summaryrefslogtreecommitdiff
path: root/tools/perf/scripts/python/stackcollapse.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/scripts/python/stackcollapse.py')
0 files changed, 0 insertions, 0 deletions
rem' style='width: 0.0%;'/> -rw-r--r--CREDITS10
-rw-r--r--Documentation/ABI/obsolete/sysfs-driver-hid-roccat-koneplus10
-rw-r--r--Documentation/ABI/removed/o2cb (renamed from Documentation/ABI/obsolete/o2cb)9
-rw-r--r--Documentation/ABI/testing/sysfs-block64
-rw-r--r--Documentation/ABI/testing/sysfs-bus-bcma31
-rw-r--r--Documentation/ABI/testing/sysfs-bus-pci9
-rw-r--r--Documentation/ABI/testing/sysfs-devices-system-cpu34
-rw-r--r--Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus19
-rw-r--r--Documentation/ABI/testing/sysfs-firmware-dmi18
-rw-r--r--Documentation/ABI/testing/sysfs-firmware-gsmi58
-rw-r--r--Documentation/ABI/testing/sysfs-firmware-log7
-rw-r--r--Documentation/ABI/testing/sysfs-kernel-fscaps8
-rw-r--r--Documentation/ABI/testing/sysfs-kernel-mm-cleancache11
-rw-r--r--Documentation/ABI/testing/sysfs-power14
-rw-r--r--Documentation/ABI/testing/sysfs-ptp98
-rw-r--r--Documentation/DocBook/.gitignore1
-rw-r--r--Documentation/DocBook/Makefile2
-rw-r--r--Documentation/DocBook/device-drivers.tmpl6
-rw-r--r--Documentation/DocBook/dvb/dvbapi.xml8
-rw-r--r--Documentation/DocBook/dvb/dvbproperty.xml408
-rw-r--r--Documentation/DocBook/dvb/frontend.h.xml20
-rw-r--r--Documentation/DocBook/genericirq.tmpl82
-rw-r--r--Documentation/DocBook/media-entities.tmpl9
-rw-r--r--Documentation/DocBook/v4l/media-controller.xml6
-rw-r--r--Documentation/DocBook/v4l/pixfmt-m420.xml147
-rw-r--r--Documentation/DocBook/v4l/pixfmt-y10b.xml43
-rw-r--r--Documentation/DocBook/v4l/pixfmt.xml3
-rw-r--r--Documentation/DocBook/v4l/subdev-formats.xml46
-rw-r--r--Documentation/DocBook/v4l/videodev2.h.xml4
-rw-r--r--Documentation/HOWTO2
-rw-r--r--Documentation/IRQ-affinity.txt17
-rw-r--r--Documentation/RCU/00-INDEX2
-rw-r--r--Documentation/RCU/stallwarn.txt23
-rw-r--r--Documentation/RCU/trace.txt278
-rw-r--r--Documentation/SubmittingPatches9
-rw-r--r--Documentation/accounting/getdelays.c38
-rw-r--r--Documentation/atomic_ops.txt2
-rw-r--r--Documentation/blockdev/cciss.txt15
-rw-r--r--Documentation/cachetlb.txt2
-rw-r--r--Documentation/cgroups/cgroups.txt41
-rw-r--r--Documentation/devicetree/bindings/crypto/fsl-sec4.txt397
-rwxr-xr-xDocumentation/devicetree/bindings/net/can/fsl-flexcan.txt61
-rw-r--r--Documentation/devicetree/bindings/net/fsl-tsec-phy.txt54
-rw-r--r--Documentation/devicetree/bindings/powerpc/fsl/ifc.txt76
-rw-r--r--Documentation/devicetree/bindings/powerpc/fsl/mpic-timer.txt38
-rw-r--r--Documentation/devicetree/bindings/powerpc/fsl/mpic.txt2
-rw-r--r--Documentation/devicetree/bindings/powerpc/nintendo/wii.txt2
-rw-r--r--Documentation/dontdiff58
-rw-r--r--Documentation/driver-model/bus.txt19
-rw-r--r--Documentation/driver-model/class.txt17
-rw-r--r--Documentation/driver-model/device.txt91
-rw-r--r--Documentation/driver-model/driver.txt18
-rw-r--r--Documentation/feature-removal-schedule.txt64
-rw-r--r--Documentation/filesystems/9p.txt29
-rw-r--r--Documentation/filesystems/configfs/configfs_example_explicit.c6
-rw-r--r--Documentation/filesystems/configfs/configfs_example_macros.c6
-rw-r--r--Documentation/filesystems/ext4.txt4
-rw-r--r--Documentation/filesystems/ocfs2.txt8
-rw-r--r--Documentation/filesystems/proc.txt12
-rw-r--r--Documentation/filesystems/ubifs.txt26
-rw-r--r--Documentation/filesystems/xfs.txt6
-rw-r--r--Documentation/hid/hiddev.txt (renamed from Documentation/usb/hiddev.txt)0
-rw-r--r--Documentation/hid/hidraw.txt119
-rw-r--r--Documentation/hwmon/adm127560
-rw-r--r--Documentation/hwmon/coretemp21
-rw-r--r--Documentation/hwmon/emc6w20142
-rw-r--r--Documentation/hwmon/f71882fg4
-rw-r--r--Documentation/hwmon/fam15h_power37
-rw-r--r--Documentation/hwmon/k10temp3
-rw-r--r--Documentation/hwmon/max1606598
-rw-r--r--Documentation/hwmon/max664221
-rw-r--r--Documentation/hwmon/max665021
-rw-r--r--Documentation/hwmon/pkgtemp36
-rw-r--r--Documentation/hwmon/sht1574
-rw-r--r--Documentation/hwmon/ucd9000110
-rw-r--r--Documentation/hwmon/ucd9200112
-rw-r--r--Documentation/i2c/busses/i2c-i8011
-rw-r--r--Documentation/i2c/writing-clients2
-rw-r--r--Documentation/input/elantech.txt123
-rw-r--r--Documentation/input/rotary-encoder.txt13
-rw-r--r--Documentation/ioctl/ioctl-number.txt3
-rw-r--r--Documentation/ja_JP/HOWTO129
-rw-r--r--Documentation/kbuild/kbuild.txt13
-rw-r--r--Documentation/kbuild/kconfig-language.txt32
-rw-r--r--Documentation/kbuild/kconfig.txt5
-rw-r--r--Documentation/kbuild/makefiles.txt53
-rw-r--r--Documentation/kernel-parameters.txt13
-rw-r--r--Documentation/lockstat.txt2
-rw-r--r--Documentation/mmc/00-INDEX2
-rw-r--r--Documentation/mmc/mmc-dev-attrs.txt10
-rw-r--r--Documentation/mmc/mmc-dev-parts.txt27
-rw-r--r--Documentation/networking/batman-adv.txt11
-rw-r--r--Documentation/networking/bonding.txt45
-rw-r--r--Documentation/networking/igb.txt13
-rw-r--r--Documentation/power/devices.txt14
-rw-r--r--Documentation/power/notifiers.txt51
-rw-r--r--Documentation/power/regulator/machine.txt4
-rw-r--r--Documentation/pti/pti_intel_mid.txt99
-rw-r--r--Documentation/ptp/ptp.txt89
-rw-r--r--Documentation/ptp/testptp.c381
-rw-r--r--Documentation/ptp/testptp.mk33
-rw-r--r--Documentation/scsi/LICENSE.qla2xxx292
-rw-r--r--Documentation/sound/alsa/ALSA-Configuration.txt7
-rw-r--r--Documentation/sound/alsa/HD-Audio-Models.txt2
-rw-r--r--Documentation/stable_api_nonsense.txt2
-rw-r--r--Documentation/sysctl/fs.txt7
-rw-r--r--Documentation/sysctl/kernel.txt3
-rw-r--r--Documentation/sysctl/net.txt11
-rw-r--r--Documentation/sysctl/vm.txt4
-rw-r--r--Documentation/timers/timers-howto.txt2
-rw-r--r--Documentation/trace/kprobetrace.txt1
-rw-r--r--Documentation/usb/callbacks.txt8
-rw-r--r--Documentation/usb/linux-cdc-acm.inf4
-rw-r--r--Documentation/usb/linux.inf6
-rw-r--r--Documentation/vgaarbiter.txt20
-rw-r--r--Documentation/video4linux/CARDLIST.em28xx2
-rw-r--r--Documentation/video4linux/Zoran1
-rw-r--r--Documentation/video4linux/gspca.txt1
-rw-r--r--Documentation/video4linux/uvcvideo.txt239
-rw-r--r--Documentation/virtual/kvm/api.txt34
-rw-r--r--Documentation/virtual/uml/UserModeLinux-HOWTO.txt10
-rw-r--r--Documentation/vm/cleancache.txt278
-rw-r--r--Documentation/vm/locking2
-rw-r--r--Documentation/x86/x86_64/boot-options.txt2
-rw-r--r--Documentation/zh_CN/email-clients.txt210
-rw-r--r--MAINTAINERS134
-rw-r--r--Makefile68
-rw-r--r--arch/Kconfig6
-rw-r--r--arch/alpha/Kconfig8
-rw-r--r--arch/alpha/include/asm/gpio.h55
-rw-r--r--arch/alpha/include/asm/smp.h2
-rw-r--r--arch/alpha/kernel/process.c2
-rw-r--r--arch/alpha/kernel/setup.c2
-rw-r--r--arch/alpha/kernel/smp.c10
-rw-r--r--arch/alpha/kernel/sys_dp264.c2
-rw-r--r--arch/alpha/kernel/sys_titan.c13
-rw-r--r--arch/alpha/kernel/vmlinux.lds.S3
-rw-r--r--arch/alpha/mm/init.c2
-rw-r--r--arch/alpha/mm/numa.c1
-rw-r--r--arch/arm/Kconfig89
-rw-r--r--arch/arm/Kconfig.debug7
-rw-r--r--arch/arm/Makefile7
-rw-r--r--arch/arm/boot/compressed/Makefile17
-rw-r--r--arch/arm/boot/compressed/decompress.c4
-rw-r--r--arch/arm/boot/compressed/head.S46
-rw-r--r--arch/arm/boot/compressed/misc.c24
-rw-r--r--arch/arm/common/gic.c84
-rw-r--r--arch/arm/common/sa1111.c8
-rw-r--r--arch/arm/common/timer-sp.c82
-rw-r--r--arch/arm/common/vic.c69
-rw-r--r--arch/arm/configs/dove_defconfig12
-rw-r--r--arch/arm/configs/mx1_defconfig1
-rw-r--r--arch/arm/configs/mx51_defconfig2
-rw-r--r--arch/arm/configs/mxs_defconfig129
-rw-r--r--arch/arm/configs/ns9xxx_defconfig56
-rw-r--r--arch/arm/configs/omap2plus_defconfig83
-rw-r--r--arch/arm/configs/realview-smp_defconfig2
-rw-r--r--arch/arm/configs/realview_defconfig2
-rw-r--r--arch/arm/configs/spear300_defconfig51
-rw-r--r--arch/arm/configs/spear320_defconfig52
-rw-r--r--arch/arm/configs/spear3xx_defconfig (renamed from arch/arm/configs/spear310_defconfig)5
-rw-r--r--arch/arm/configs/spear6xx_defconfig (renamed from arch/arm/configs/spear600_defconfig)2
-rw-r--r--arch/arm/configs/stmp378x_defconfig128
-rw-r--r--arch/arm/configs/stmp37xx_defconfig108
-rw-r--r--arch/arm/configs/versatile_defconfig2
-rw-r--r--arch/arm/include/asm/bitops.h46
-rw-r--r--arch/arm/include/asm/dma.h4
-rw-r--r--arch/arm/include/asm/elf.h1
-rw-r--r--arch/arm/include/asm/futex.h137
-rw-r--r--arch/arm/include/asm/hardware/timer-sp.h4
-rw-r--r--arch/arm/include/asm/i8253.h15
-rw-r--r--arch/arm/include/asm/mach/time.h1
-rw-r--r--arch/arm/include/asm/memory.h10
-rw-r--r--arch/arm/include/asm/ptrace.h6
-rw-r--r--arch/arm/include/asm/sizes.h42
-rw-r--r--arch/arm/include/asm/smp.h12
-rw-r--r--arch/arm/include/asm/spinlock.h2
-rw-r--r--arch/arm/include/asm/tlb.h53
-rw-r--r--arch/arm/kernel/leds.c28
-rw-r--r--arch/arm/kernel/perf_event.c5
-rw-r--r--arch/arm/kernel/ptrace.c348
-rw-r--r--arch/arm/kernel/setup.c13
-rw-r--r--arch/arm/kernel/smp.c12
-rw-r--r--arch/arm/kernel/time.c35
-rw-r--r--arch/arm/kernel/traps.c1
-rw-r--r--arch/arm/kernel/vmlinux.lds.S2
-rw-r--r--arch/arm/mach-at91/at91cap9_devices.c2
-rw-r--r--arch/arm/mach-at91/at91sam9g45_devices.c2
-rw-r--r--arch/arm/mach-at91/at91sam9rl_devices.c2
-rw-r--r--arch/arm/mach-bcmring/arch.c1
-rw-r--r--arch/arm/mach-bcmring/core.c227
-rw-r--r--arch/arm/mach-bcmring/core.h1
-rw-r--r--arch/arm/mach-davinci/cpufreq.c4
-rw-r--r--arch/arm/mach-davinci/include/mach/memory.h18
-rw-r--r--arch/arm/mach-davinci/include/mach/uncompress.h5
-rw-r--r--arch/arm/mach-davinci/irq.c93
-rw-r--r--arch/arm/mach-dove/common.c616
-rw-r--r--arch/arm/mach-dove/mpp.c134
-rw-r--r--arch/arm/mach-dove/mpp.h362
-rw-r--r--arch/arm/mach-ep93xx/gpio.c24
-rw-r--r--arch/arm/mach-exynos4/Kconfig1
-rw-r--r--arch/arm/mach-exynos4/Makefile2
-rw-r--r--arch/arm/mach-exynos4/cpu.c7
-rw-r--r--arch/arm/mach-exynos4/include/mach/map.h4
-rw-r--r--arch/arm/mach-exynos4/include/mach/regs-pmu.h3
-rw-r--r--arch/arm/mach-exynos4/include/mach/regs-usb-phy.h64
-rw-r--r--arch/arm/mach-exynos4/include/mach/smp.h19
-rw-r--r--arch/arm/mach-exynos4/irq-combiner.c6
-rw-r--r--arch/arm/mach-exynos4/mach-nuri.c16
-rw-r--r--arch/arm/mach-exynos4/platsmp.c5
-rw-r--r--arch/arm/mach-exynos4/pm.c45
-rw-r--r--arch/arm/mach-exynos4/usb-phy.c136
-rw-r--r--arch/arm/mach-footbridge/Kconfig2
-rw-r--r--arch/arm/mach-footbridge/isa-timer.c45
-rw-r--r--arch/arm/mach-gemini/include/mach/uncompress.h2
-rw-r--r--arch/arm/mach-h720x/include/mach/memory.h3
-rw-r--r--arch/arm/mach-imx/Kconfig286
-rw-r--r--arch/arm/mach-imx/Makefile38
-rw-r--r--arch/arm/mach-imx/Makefile.boot4
-rw-r--r--arch/arm/mach-imx/cache-l2x0.c56
-rw-r--r--arch/arm/mach-imx/clock-imx31.c (renamed from arch/arm/mach-mx3/clock-imx31.c)3
-rw-r--r--arch/arm/mach-imx/clock-imx35.c (renamed from arch/arm/mach-mx3/clock-imx35.c)1
-rw-r--r--arch/arm/mach-imx/cpu-imx31.c (renamed from arch/arm/mach-mx3/cpu.c)38
-rw-r--r--arch/arm/mach-imx/cpu-imx35.c44
-rw-r--r--arch/arm/mach-imx/crmregs-imx31.h (renamed from arch/arm/mach-mx3/crm_regs.h)0
-rw-r--r--arch/arm/mach-imx/devices-imx1.h8
-rw-r--r--arch/arm/mach-imx/devices-imx21.h22
-rw-r--r--arch/arm/mach-imx/devices-imx25.h35
-rw-r--r--arch/arm/mach-imx/devices-imx27.h30
-rw-r--r--arch/arm/mach-imx/devices-imx31.h (renamed from arch/arm/mach-mx3/devices-imx31.h)36
-rw-r--r--arch/arm/mach-imx/devices-imx35.h (renamed from arch/arm/mach-mx3/devices-imx35.h)37
-rw-r--r--arch/arm/mach-imx/ehci-imx31.c (renamed from arch/arm/mach-mx3/ehci-imx31.c)1
-rw-r--r--arch/arm/mach-imx/ehci-imx35.c (renamed from arch/arm/mach-mx3/ehci-imx35.c)1
-rw-r--r--arch/arm/mach-imx/eukrea_mbimx27-baseboard.c1
-rw-r--r--arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c17
-rw-r--r--arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c (renamed from arch/arm/mach-mx3/eukrea_mbimxsd-baseboard.c)29
-rw-r--r--arch/arm/mach-imx/iomux-imx31.c (renamed from arch/arm/mach-mx3/iomux-imx31.c)0
-rw-r--r--arch/arm/mach-imx/mach-apf9328.c144
-rw-r--r--arch/arm/mach-imx/mach-armadillo5x0.c (renamed from arch/arm/mach-mx3/mach-armadillo5x0.c)29
-rw-r--r--arch/arm/mach-imx/mach-bug.c (renamed from arch/arm/mach-mx3/mach-bug.c)1
-rw-r--r--arch/arm/mach-imx/mach-cpuimx27.c1
-rw-r--r--arch/arm/mach-imx/mach-cpuimx35.c (renamed from arch/arm/mach-mx3/mach-cpuimx35.c)2
-rw-r--r--arch/arm/mach-imx/mach-eukrea_cpuimx25.c2
-rw-r--r--arch/arm/mach-imx/mach-imx27_visstrim_m10.c14
-rw-r--r--arch/arm/mach-imx/mach-kzm_arm11_01.c (renamed from arch/arm/mach-mx3/mach-kzm_arm11_01.c)1
-rw-r--r--arch/arm/mach-imx/mach-mx1ads.c1
-rw-r--r--arch/arm/mach-imx/mach-mx21ads.c1
-rw-r--r--arch/arm/mach-imx/mach-mx25_3ds.c13
-rw-r--r--arch/arm/mach-imx/mach-mx27ads.c1
-rw-r--r--arch/arm/mach-imx/mach-mx31_3ds.c (renamed from arch/arm/mach-mx3/mach-mx31_3ds.c)50
-rw-r--r--arch/arm/mach-imx/mach-mx31ads.c (renamed from arch/arm/mach-mx3/mach-mx31ads.c)1
-rw-r--r--arch/arm/mach-imx/mach-mx31lilly.c (renamed from arch/arm/mach-mx3/mach-mx31lilly.c)1
-rw-r--r--arch/arm/mach-imx/mach-mx31lite.c (renamed from arch/arm/mach-mx3/mach-mx31lite.c)1
-rw-r--r--arch/arm/mach-imx/mach-mx31moboard.c (renamed from arch/arm/mach-mx3/mach-mx31moboard.c)75
-rw-r--r--arch/arm/mach-imx/mach-mx35_3ds.c (renamed from arch/arm/mach-mx3/mach-mx35_3ds.c)1
-rw-r--r--arch/arm/mach-imx/mach-mxt_td60.c1
-rw-r--r--arch/arm/mach-imx/mach-pca100.c1
-rw-r--r--arch/arm/mach-imx/mach-pcm037.c (renamed from arch/arm/mach-mx3/mach-pcm037.c)65
-rw-r--r--arch/arm/mach-imx/mach-pcm037_eet.c (renamed from arch/arm/mach-mx3/mach-pcm037_eet.c)17
-rw-r--r--arch/arm/mach-imx/mach-pcm038.c1
-rw-r--r--arch/arm/mach-imx/mach-pcm043.c (renamed from arch/arm/mach-mx3/mach-pcm043.c)17
-rw-r--r--arch/arm/mach-imx/mach-qong.c (renamed from arch/arm/mach-mx3/mach-qong.c)15
-rw-r--r--arch/arm/mach-imx/mach-vpr200.c (renamed from arch/arm/mach-mx3/mach-vpr200.c)25
-rw-r--r--arch/arm/mach-imx/mm-imx31.c66
-rw-r--r--arch/arm/mach-imx/mm-imx35.c63
-rw-r--r--arch/arm/mach-imx/mx31lilly-db.c (renamed from arch/arm/mach-mx3/mx31lilly-db.c)13
-rw-r--r--arch/arm/mach-imx/mx31lite-db.c (renamed from arch/arm/mach-mx3/mx31lite-db.c)3
-rw-r--r--arch/arm/mach-imx/mx31moboard-devboard.c (renamed from arch/arm/mach-mx3/mx31moboard-devboard.c)1
-rw-r--r--arch/arm/mach-imx/mx31moboard-marxbot.c (renamed from arch/arm/mach-mx3/mx31moboard-marxbot.c)2
-rw-r--r--arch/arm/mach-imx/mx31moboard-smartbot.c (renamed from arch/arm/mach-mx3/mx31moboard-smartbot.c)1
-rw-r--r--arch/arm/mach-imx/pcm037.h (renamed from arch/arm/mach-mx3/pcm037.h)0
-rw-r--r--arch/arm/mach-integrator/Kconfig1
-rw-r--r--arch/arm/mach-integrator/integrator_ap.c60
-rw-r--r--arch/arm/mach-integrator/integrator_cp.c24
-rw-r--r--arch/arm/mach-iop32x/include/mach/uncompress.h2
-rw-r--r--arch/arm/mach-iop33x/include/mach/uncompress.h2
-rw-r--r--arch/arm/mach-ixp4xx/common-pci.c23
-rw-r--r--arch/arm/mach-ixp4xx/common.c16
-rw-r--r--arch/arm/mach-ixp4xx/include/mach/ixp46x_ts.h78
-rw-r--r--arch/arm/mach-ixp4xx/include/mach/memory.h12
-rw-r--r--arch/arm/mach-ixp4xx/include/mach/uncompress.h2
-rw-r--r--arch/arm/mach-kirkwood/common.c601
-rw-r--r--arch/arm/mach-kirkwood/include/mach/irqs.h1
-rw-r--r--arch/arm/mach-kirkwood/mpp.c58
-rw-r--r--arch/arm/mach-kirkwood/mpp.h6
-rw-r--r--arch/arm/mach-loki/common.c190
-rw-r--r--arch/arm/mach-lpc32xx/timer.c17
-rw-r--r--arch/arm/mach-mmp/include/mach/uncompress.h2
-rw-r--r--arch/arm/mach-msm/gpio-v2.c10
-rw-r--r--arch/arm/mach-msm/include/mach/msm_iomap.h2
-rw-r--r--arch/arm/mach-msm/platsmp.c4
-rw-r--r--arch/arm/mach-mv78xx0/common.c570
-rw-r--r--arch/arm/mach-mv78xx0/mpp.c58
-rw-r--r--arch/arm/mach-mv78xx0/mpp.h6
-rw-r--r--arch/arm/mach-mx3/Kconfig257
-rw-r--r--arch/arm/mach-mx3/Makefile26
-rw-r--r--arch/arm/mach-mx3/Makefile.boot3
-rw-r--r--arch/arm/mach-mx3/devices.c115
-rw-r--r--arch/arm/mach-mx3/devices.h4
-rw-r--r--arch/arm/mach-mx3/mm.c141
-rw-r--r--arch/arm/mach-mx5/Kconfig58
-rw-r--r--arch/arm/mach-mx5/board-cpuimx51.c2
-rw-r--r--arch/arm/mach-mx5/board-cpuimx51sd.c2
-rw-r--r--arch/arm/mach-mx5/board-mx50_rdp.c1
-rw-r--r--arch/arm/mach-mx5/board-mx51_babbage.c18
-rw-r--r--arch/arm/mach-mx5/board-mx51_efikamx.c5
-rw-r--r--arch/arm/mach-mx5/board-mx51_efikasb.c5
-rw-r--r--arch/arm/mach-mx5/board-mx53_evk.c2
-rw-r--r--arch/arm/mach-mx5/board-mx53_loco.c2
-rw-r--r--arch/arm/mach-mx5/board-mx53_smd.c30
-rw-r--r--arch/arm/mach-mx5/clock-mx51-mx53.c1
-rw-r--r--arch/arm/mach-mx5/cpu.c23
-rw-r--r--arch/arm/mach-mx5/devices-imx50.h6
-rw-r--r--arch/arm/mach-mx5/devices-imx51.h25
-rw-r--r--arch/arm/mach-mx5/devices-imx53.h13
-rw-r--r--arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c2
-rw-r--r--arch/arm/mach-mx5/eukrea_mbimxsd-baseboard.c16
-rw-r--r--arch/arm/mach-mx5/mx51_efika.c3
-rw-r--r--arch/arm/mach-mxc91231/Kconfig11
-rw-r--r--arch/arm/mach-mxc91231/Makefile2
-rw-r--r--arch/arm/mach-mxc91231/Makefile.boot3
-rw-r--r--arch/arm/mach-mxc91231/clock.c640
-rw-r--r--arch/arm/mach-mxc91231/crm_regs.h394
-rw-r--r--arch/arm/mach-mxc91231/devices.c251
-rw-r--r--arch/arm/mach-mxc91231/devices.h13
-rw-r--r--arch/arm/mach-mxc91231/iomux.c177
-rw-r--r--arch/arm/mach-mxc91231/magx-zn5.c62
-rw-r--r--arch/arm/mach-mxc91231/mm.c62
-rw-r--r--arch/arm/mach-mxc91231/system.c51
-rw-r--r--arch/arm/mach-mxs/Kconfig12
-rw-r--r--arch/arm/mach-mxs/Makefile1
-rw-r--r--arch/arm/mach-mxs/clock-mx23.c2
-rw-r--r--arch/arm/mach-mxs/devices-mx28.h2
-rw-r--r--arch/arm/mach-mxs/devices/platform-mxs-i2c.c5
-rw-r--r--arch/arm/mach-mxs/include/mach/devices-common.h5
-rw-r--r--arch/arm/mach-mxs/include/mach/mx23.h2
-rw-r--r--arch/arm/mach-mxs/include/mach/uncompress.h2
-rw-r--r--arch/arm/mach-mxs/mach-mx23evk.c2
-rw-r--r--arch/arm/mach-mxs/mach-mx28evk.c4
-rw-r--r--arch/arm/mach-mxs/mach-stmp378x_devb.c120
-rw-r--r--arch/arm/mach-mxs/timer.c20
-rw-r--r--arch/arm/mach-netx/time.c16
-rw-r--r--arch/arm/mach-ns9xxx/Kconfig40
-rw-r--r--arch/arm/mach-ns9xxx/Makefile12
-rw-r--r--arch/arm/mach-ns9xxx/Makefile.boot2
-rw-r--r--arch/arm/mach-ns9xxx/board-a9m9750dev.c156
-rw-r--r--arch/arm/mach-ns9xxx/board-a9m9750dev.h15
-rw-r--r--arch/arm/mach-ns9xxx/board-jscc9p9360.c17
-rw-r--r--arch/arm/mach-ns9xxx/board-jscc9p9360.h13
-rw-r--r--arch/arm/mach-ns9xxx/clock.c215
-rw-r--r--arch/arm/mach-ns9xxx/clock.h35
-rw-r--r--arch/arm/mach-ns9xxx/generic.c19
-rw-r--r--arch/arm/mach-ns9xxx/generic.h16
-rw-r--r--arch/arm/mach-ns9xxx/gpio-ns9360.c118
-rw-r--r--arch/arm/mach-ns9xxx/gpio-ns9360.h13
-rw-r--r--arch/arm/mach-ns9xxx/gpio.c147
-rw-r--r--arch/arm/mach-ns9xxx/include/mach/board.h40
-rw-r--r--arch/arm/mach-ns9xxx/include/mach/debug-macro.S21
-rw-r--r--arch/arm/mach-ns9xxx/include/mach/entry-macro.S28
-rw-r--r--arch/arm/mach-ns9xxx/include/mach/gpio.h47
-rw-r--r--arch/arm/mach-ns9xxx/include/mach/hardware.h77
-rw-r--r--arch/arm/mach-ns9xxx/include/mach/io.h20
-rw-r--r--arch/arm/mach-ns9xxx/include/mach/irqs.h86
-rw-r--r--arch/arm/mach-ns9xxx/include/mach/memory.h24
-rw-r--r--arch/arm/mach-ns9xxx/include/mach/module.h55
-rw-r--r--arch/arm/mach-ns9xxx/include/mach/processor-ns9360.h32
-rw-r--r--arch/arm/mach-ns9xxx/include/mach/processor.h42
-rw-r--r--arch/arm/mach-ns9xxx/include/mach/regs-bbu.h45
-rw-r--r--arch/arm/mach-ns9xxx/include/mach/regs-board-a9m9750dev.h24
-rw-r--r--arch/arm/mach-ns9xxx/include/mach/regs-mem.h135
-rw-r--r--arch/arm/mach-ns9xxx/include/mach/regs-sys-common.h31
-rw-r--r--arch/arm/mach-ns9xxx/include/mach/regs-sys-ns9360.h148
-rw-r--r--arch/arm/mach-ns9xxx/include/mach/system.h35
-rw-r--r--arch/arm/mach-ns9xxx/include/mach/timex.h20
-rw-r--r--arch/arm/mach-ns9xxx/include/mach/uncompress.h164
-rw-r--r--arch/arm/mach-ns9xxx/include/mach/vmalloc.h16
-rw-r--r--arch/arm/mach-ns9xxx/irq.c74
-rw-r--r--arch/arm/mach-ns9xxx/mach-cc9p9360dev.c43
-rw-r--r--arch/arm/mach-ns9xxx/mach-cc9p9360js.c31
-rw-r--r--arch/arm/mach-ns9xxx/plat-serial8250.c70
-rw-r--r--arch/arm/mach-ns9xxx/processor-ns9360.c53
-rw-r--r--arch/arm/mach-ns9xxx/time-ns9360.c181
-rw-r--r--arch/arm/mach-nuc93x/include/mach/uncompress.h2
-rw-r--r--arch/arm/mach-omap1/flash.c2
-rw-r--r--arch/arm/mach-omap1/pm_bus.c69
-rw-r--r--arch/arm/mach-omap1/time.c69
-rw-r--r--arch/arm/mach-omap2/Kconfig1
-rw-r--r--arch/arm/mach-omap2/Makefile10
-rw-r--r--arch/arm/mach-omap2/board-2430sdp.c27
-rw-r--r--arch/arm/mach-omap2/board-3430sdp.c155
-rw-r--r--arch/arm/mach-omap2/board-4430sdp.c125
-rw-r--r--arch/arm/mach-omap2/board-am3517crane.c10
-rw-r--r--arch/arm/mach-omap2/board-am3517evm.c60
-rw-r--r--arch/arm/mach-omap2/board-apollon.c29
-rw-r--r--arch/arm/mach-omap2/board-cm-t35.c240
-rw-r--r--arch/arm/mach-omap2/board-cm-t3517.c9
-rw-r--r--arch/arm/mach-omap2/board-devkit8000.c135
-rw-r--r--arch/arm/mach-omap2/board-igep0020.c453
-rw-r--r--arch/arm/mach-omap2/board-igep0030.c458
-rw-r--r--arch/arm/mach-omap2/board-ldp.c138
-rw-r--r--arch/arm/mach-omap2/board-n8x0.c28
-rw-r--r--arch/arm/mach-omap2/board-omap3beagle.c198
-rw-r--r--arch/arm/mach-omap2/board-omap3evm.c246
-rw-r--r--arch/arm/mach-omap2/board-omap3logic.c14
-rw-r--r--arch/arm/mach-omap2/board-omap3pandora.c92
-rw-r--r--arch/arm/mach-omap2/board-omap3stalker.c137
-rw-r--r--arch/arm/mach-omap2/board-omap3touchbook.c121
-rw-r--r--arch/arm/mach-omap2/board-omap4panda.c83
-rw-r--r--arch/arm/mach-omap2/board-overo.c269
-rw-r--r--arch/arm/mach-omap2/board-rm680.c21
-rw-r--r--arch/arm/mach-omap2/board-rx51-peripherals.c71
-rw-r--r--arch/arm/mach-omap2/board-rx51-video.c7
-rw-r--r--arch/arm/mach-omap2/board-rx51.c18
-rw-r--r--arch/arm/mach-omap2/board-zoom-debugboard.c65
-rw-r--r--arch/arm/mach-omap2/board-zoom-display.c33
-rw-r--r--arch/arm/mach-omap2/board-zoom-peripherals.c29
-rw-r--r--arch/arm/mach-omap2/common-board-devices.c163
-rw-r--r--arch/arm/mach-omap2/common-board-devices.h35
-rw-r--r--arch/arm/mach-omap2/control.h2
-rw-r--r--arch/arm/mach-omap2/cpuidle34xx.c436
-rw-r--r--arch/arm/mach-omap2/display.c77
-rw-r--r--arch/arm/mach-omap2/gpmc-smc91x.c11
-rw-r--r--arch/arm/mach-omap2/gpmc-smsc911x.c44
-rw-r--r--arch/arm/mach-omap2/include/mach/board-zoom.h2
-rw-r--r--arch/arm/mach-omap2/include/mach/omap4-common.h7
-rw-r--r--arch/arm/mach-omap2/irq.c97
-rw-r--r--arch/arm/mach-omap2/omap-smp.c5
-rw-r--r--arch/arm/mach-omap2/omap_l3_noc.c51
-rw-r--r--arch/arm/mach-omap2/omap_l3_smx.c42
-rw-r--r--arch/arm/mach-omap2/omap_phy_internal.c9
-rw-r--r--arch/arm/mach-omap2/pm.h17
-rw-r--r--arch/arm/mach-omap2/pm34xx.c14
-rw-r--r--arch/arm/mach-omap2/pm44xx.c2
-rw-r--r--arch/arm/mach-omap2/pm_bus.c85
-rw-r--r--arch/arm/mach-omap2/smartreflex.c23
-rw-r--r--arch/arm/mach-omap2/usb-musb.c22
-rw-r--r--arch/arm/mach-omap2/usb-tusb6010.c3
-rw-r--r--arch/arm/mach-omap2/voltage.c1
-rw-r--r--arch/arm/mach-orion5x/common.c478
-rw-r--r--arch/arm/mach-orion5x/d2net-setup.c44
-rw-r--r--arch/arm/mach-orion5x/db88f5281-setup.c44
-rw-r--r--arch/arm/mach-orion5x/dns323-setup.c132
-rw-r--r--arch/arm/mach-orion5x/edmini_v2-setup.c44
-rw-r--r--arch/arm/mach-orion5x/kurobox_pro-setup.c44
-rw-r--r--arch/arm/mach-orion5x/ls-chl-setup.c44
-rw-r--r--arch/arm/mach-orion5x/ls_hgl-setup.c44
-rw-r--r--arch/arm/mach-orion5x/lsmini-setup.c44
-rw-r--r--arch/arm/mach-orion5x/mpp.c150
-rw-r--r--arch/arm/mach-orion5x/mpp.h191
-rw-r--r--arch/arm/mach-orion5x/mss2-setup.c44
-rw-r--r--arch/arm/mach-orion5x/mv2120-setup.c44
-rw-r--r--arch/arm/mach-orion5x/net2big-setup.c44
-rw-r--r--arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c44
-rw-r--r--arch/arm/mach-orion5x/rd88f5181l-ge-setup.c44
-rw-r--r--arch/arm/mach-orion5x/rd88f5182-setup.c44
-rw-r--r--arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c1
-rw-r--r--arch/arm/mach-orion5x/terastation_pro2-setup.c44
-rw-r--r--arch/arm/mach-orion5x/ts209-setup.c44
-rw-r--r--arch/arm/mach-orion5x/ts409-setup.c44
-rw-r--r--arch/arm/mach-orion5x/ts78xx-setup.c44
-rw-r--r--arch/arm/mach-orion5x/wnr854t-setup.c44
-rw-r--r--arch/arm/mach-orion5x/wrt350n-v2-setup.c44
-rw-r--r--arch/arm/mach-pxa/balloon3.c1
-rw-r--r--arch/arm/mach-pxa/clock-pxa2xx.c18
-rw-r--r--arch/arm/mach-pxa/clock-pxa3xx.c17
-rw-r--r--arch/arm/mach-pxa/clock.h7
-rw-r--r--arch/arm/mach-pxa/cm-x270.c1
-rw-r--r--arch/arm/mach-pxa/cm-x2xx-pci.c27
-rw-r--r--arch/arm/mach-pxa/cm-x2xx.c23
-rw-r--r--arch/arm/mach-pxa/colibri-evalboard.c1
-rw-r--r--arch/arm/mach-pxa/colibri-pxa270-income.c1
-rw-r--r--arch/arm/mach-pxa/colibri-pxa270.c1
-rw-r--r--arch/arm/mach-pxa/generic.h8
-rw-r--r--arch/arm/mach-pxa/hx4700.c2
-rw-r--r--arch/arm/mach-pxa/include/mach/memory.h10
-rw-r--r--arch/arm/mach-pxa/include/mach/uncompress.h6
-rw-r--r--arch/arm/mach-pxa/irq.c17
-rw-r--r--arch/arm/mach-pxa/lpd270.c20
-rw-r--r--arch/arm/mach-pxa/lubbock.c21
-rw-r--r--arch/arm/mach-pxa/magician.c2
-rw-r--r--arch/arm/mach-pxa/mainstone.c22
-rw-r--r--arch/arm/mach-pxa/mfp-pxa2xx.c12
-rw-r--r--arch/arm/mach-pxa/mfp-pxa3xx.c21
-rw-r--r--arch/arm/mach-pxa/mioa701.c43
-rw-r--r--arch/arm/mach-pxa/palmld.c1
-rw-r--r--arch/arm/mach-pxa/palmtreo.c1
-rw-r--r--arch/arm/mach-pxa/palmz72.c24
-rw-r--r--arch/arm/mach-pxa/pxa25x.c25
-rw-r--r--arch/arm/mach-pxa/pxa27x.c25
-rw-r--r--arch/arm/mach-pxa/pxa3xx.c25
-rw-r--r--arch/arm/mach-pxa/pxa95x.c20
-rw-r--r--arch/arm/mach-pxa/raumfeld.c1
-rw-r--r--arch/arm/mach-pxa/smemc.c29
-rw-r--r--arch/arm/mach-pxa/time.c17
-rw-r--r--arch/arm/mach-pxa/trizeps4.c1
-rw-r--r--arch/arm/mach-pxa/viper.c12
-rw-r--r--arch/arm/mach-pxa/vpac270.c1
-rw-r--r--arch/arm/mach-realview/core.c63
-rw-r--r--arch/arm/mach-realview/include/mach/memory.h9
-rw-r--r--arch/arm/mach-realview/include/mach/smp.h14
-rw-r--r--arch/arm/mach-realview/platsmp.c3
-rw-r--r--arch/arm/mach-rpc/include/mach/uncompress.h12
-rw-r--r--arch/arm/mach-s3c2410/include/mach/map.h4
-rw-r--r--arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h25
-rw-r--r--arch/arm/mach-s3c2410/irq.c30
-rw-r--r--arch/arm/mach-s3c2410/mach-bast.c17
-rw-r--r--arch/arm/mach-s3c2410/nor-simtec.c2
-rw-r--r--arch/arm/mach-s3c2410/pm.c13
-rw-r--r--arch/arm/mach-s3c2410/s3c2410.c5
-rw-r--r--arch/arm/mach-s3c2412/irq.c2
-rw-r--r--arch/arm/mach-s3c2412/mach-jive.c19
-rw-r--r--arch/arm/mach-s3c2412/pm.c27
-rw-r--r--arch/arm/mach-s3c2412/s3c2412.c4
-rw-r--r--arch/arm/mach-s3c2416/irq.c2
-rw-r--r--arch/arm/mach-s3c2416/mach-smdk2416.c27
-rw-r--r--arch/arm/mach-s3c2416/pm.c27
-rw-r--r--arch/arm/mach-s3c2416/s3c2416.c5
-rw-r--r--arch/arm/mach-s3c2440/mach-osiris.c18
-rw-r--r--arch/arm/mach-s3c2440/s3c2440.c8
-rw-r--r--arch/arm/mach-s3c2440/s3c2442.c6
-rw-r--r--arch/arm/mach-s3c2440/s3c244x-irq.c4
-rw-r--r--arch/arm/mach-s3c2440/s3c244x.c62
-rw-r--r--arch/arm/mach-s3c64xx/irq-pm.c18
-rw-r--r--arch/arm/mach-s3c64xx/irq.c7
-rw-r--r--arch/arm/mach-s5p64x0/include/mach/uncompress.h6
-rw-r--r--arch/arm/mach-s5pv210/pm.c25
-rw-r--r--arch/arm/mach-sa1100/include/mach/memory.h12
-rw-r--r--arch/arm/mach-sa1100/irq.c19
-rw-r--r--arch/arm/mach-sa1100/time.c24
-rw-r--r--arch/arm/mach-shark/include/mach/memory.h20
-rw-r--r--arch/arm/mach-shmobile/Makefile5
-rw-r--r--arch/arm/mach-shmobile/board-ag5evm.c118
-rw-r--r--arch/arm/mach-shmobile/board-ap4evb.c30
-rw-r--r--arch/arm/mach-shmobile/board-g4evm.c2
-rw-r--r--arch/arm/mach-shmobile/board-mackerel.c272
-rw-r--r--arch/arm/mach-shmobile/clock-sh7372.c21
-rw-r--r--arch/arm/mach-shmobile/clock-sh73a0.c19
-rw-r--r--arch/arm/mach-shmobile/cpuidle.c92
-rw-r--r--arch/arm/mach-shmobile/headsmp.S2
-rw-r--r--arch/arm/mach-shmobile/include/mach/common.h7
-rw-r--r--arch/arm/mach-shmobile/include/mach/head-ap4evb.txt3
-rw-r--r--arch/arm/mach-shmobile/include/mach/head-mackerel.txt3
-rw-r--r--arch/arm/mach-shmobile/include/mach/sh7372.h1
-rw-r--r--arch/arm/mach-shmobile/include/mach/sh73a0.h30
-rw-r--r--arch/arm/mach-shmobile/include/mach/smp.h16
-rw-r--r--arch/arm/mach-shmobile/intc-sh7372.c46
-rw-r--r--arch/arm/mach-shmobile/platsmp.c3
-rw-r--r--arch/arm/mach-shmobile/pm-sh7372.c108
-rw-r--r--arch/arm/mach-shmobile/pm_runtime.c145
-rw-r--r--arch/arm/mach-shmobile/setup-sh7367.c223
-rw-r--r--arch/arm/mach-shmobile/setup-sh7372.c217
-rw-r--r--arch/arm/mach-shmobile/setup-sh7377.c239
-rw-r--r--arch/arm/mach-shmobile/setup-sh73a0.c244
-rw-r--r--arch/arm/mach-shmobile/sleep-sh7372.S260
-rw-r--r--arch/arm/mach-shmobile/smp-sh73a0.c9
-rw-r--r--arch/arm/mach-shmobile/suspend.c47
-rw-r--r--arch/arm/mach-spear3xx/Kconfig30
-rw-r--r--arch/arm/mach-spear3xx/Kconfig30017
-rw-r--r--arch/arm/mach-spear3xx/Kconfig31017
-rw-r--r--arch/arm/mach-spear3xx/Kconfig32017
-rw-r--r--arch/arm/mach-spear3xx/clock.c74
-rw-r--r--arch/arm/mach-spear3xx/include/mach/generic.h205
-rw-r--r--arch/arm/mach-spear3xx/include/mach/irqs.h206
-rw-r--r--arch/arm/mach-spear3xx/include/mach/spear300.h26
-rw-r--r--arch/arm/mach-spear3xx/include/mach/spear310.h44
-rw-r--r--arch/arm/mach-spear3xx/include/mach/spear320.h48
-rw-r--r--arch/arm/mach-spear3xx/spear300.c163
-rw-r--r--arch/arm/mach-spear3xx/spear300_evb.c32
-rw-r--r--arch/arm/mach-spear3xx/spear310.c149
-rw-r--r--arch/arm/mach-spear3xx/spear310_evb.c45
-rw-r--r--arch/arm/mach-spear3xx/spear320.c251
-rw-r--r--arch/arm/mach-spear3xx/spear320_evb.c40
-rw-r--r--arch/arm/mach-spear3xx/spear3xx.c132
-rw-r--r--arch/arm/mach-spear6xx/Kconfig15
-rw-r--r--arch/arm/mach-spear6xx/Kconfig60017
-rw-r--r--arch/arm/mach-spear6xx/clock.c4
-rw-r--r--arch/arm/mach-spear6xx/include/mach/generic.h2
-rw-r--r--arch/arm/mach-spear6xx/spear6xx.c2
-rw-r--r--arch/arm/mach-stmp378x/Makefile2
-rw-r--r--arch/arm/mach-stmp378x/Makefile.boot3
-rw-r--r--arch/arm/mach-stmp378x/include/mach/entry-macro.S35
-rw-r--r--arch/arm/mach-stmp378x/include/mach/irqs.h95
-rw-r--r--arch/arm/mach-stmp378x/include/mach/pins.h151
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-apbh.h101
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-apbx.h119
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-audioin.h63
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-audioout.h104
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-bch.h56
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-clkctrl.h88
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-dcp.h87
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-digctl.h38
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-dram.h27
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-dri.h45
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-ecc8.h39
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-emi.h25
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-gpmi.h78
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-i2c.h55
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-icoll.h45
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-ir.h23
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-lcdif.h195
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-lradc.h99
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-ocotp.h40
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-pinctrl.h90
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-power.h63
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-pwm.h53
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-pxp.h140
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-rtc.h59
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-spdif.h49
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-ssp.h102
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-sydma.h23
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-timrot.h68
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-tvenc.h67
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-uartapp.h87
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-uartdbg.h268
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-usbctrl.h40
-rw-r--r--arch/arm/mach-stmp378x/include/mach/regs-usbphy.h37
-rw-r--r--arch/arm/mach-stmp378x/stmp378x.c299
-rw-r--r--arch/arm/mach-stmp378x/stmp378x.h25
-rw-r--r--arch/arm/mach-stmp378x/stmp378x_devb.c332
-rw-r--r--arch/arm/mach-stmp37xx/Makefile2
-rw-r--r--arch/arm/mach-stmp37xx/Makefile.boot3
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/entry-macro.S37
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/irqs.h99
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/pins.h147
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/regs-apbh.h97
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/regs-apbx.h113
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/regs-audioin.h61
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/regs-audioout.h111
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/regs-clkctrl.h72
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/regs-digctl.h24
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/regs-ecc8.h37
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/regs-gpmi.h63
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/regs-i2c.h55
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/regs-icoll.h43
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/regs-lcdif.h89
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/regs-lradc.h97
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/regs-pinctrl.h88
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/regs-power.h56
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/regs-pwm.h51
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/regs-rtc.h57
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/regs-ssp.h101
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/regs-timrot.h49
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/regs-uartapp.h85
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/regs-uartdbg.h268
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/regs-usbctl.h22
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/regs-usbctrl.h22
-rw-r--r--arch/arm/mach-stmp37xx/include/mach/regs-usbphy.h37
-rw-r--r--arch/arm/mach-stmp37xx/stmp37xx.c219
-rw-r--r--arch/arm/mach-stmp37xx/stmp37xx.h24
-rw-r--r--arch/arm/mach-stmp37xx/stmp37xx_devb.c99
-rw-r--r--arch/arm/mach-tcc8k/time.c16
-rw-r--r--arch/arm/mach-tegra/Kconfig3
-rw-r--r--arch/arm/mach-tegra/Makefile2
-rw-r--r--arch/arm/mach-tegra/board-harmony.c7
-rw-r--r--arch/arm/mach-tegra/gpio.c9
-rw-r--r--arch/arm/mach-tegra/include/mach/kbc.h4
-rw-r--r--arch/arm/mach-tegra/include/mach/legacy_irq.h35
-rw-r--r--arch/arm/mach-tegra/include/mach/sdhci.h1
-rw-r--r--arch/arm/mach-tegra/include/mach/smp.h14
-rw-r--r--arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h (renamed from arch/arm/mach-tegra/include/mach/harmony_audio.h)5
-rw-r--r--arch/arm/mach-tegra/irq.c174
-rw-r--r--arch/arm/mach-tegra/legacy_irq.c215
-rw-r--r--arch/arm/mach-tegra/platsmp.c3
-rw-r--r--arch/arm/mach-tegra/tegra2_clocks.c2
-rw-r--r--arch/arm/mach-tegra/timer.c16
-rw-r--r--arch/arm/mach-u300/timer.c18
-rw-r--r--arch/arm/mach-ux500/Kconfig3
-rw-r--r--arch/arm/mach-ux500/Makefile4
-rw-r--r--arch/arm/mach-ux500/board-mop500.c14
-rw-r--r--arch/arm/mach-ux500/cpu-db5500.c2
-rw-r--r--arch/arm/mach-ux500/cpu-db8500.c7
-rw-r--r--arch/arm/mach-ux500/cpu.c7
-rw-r--r--arch/arm/mach-ux500/cpufreq.c211
-rw-r--r--arch/arm/mach-ux500/include/mach/db5500-regs.h20
-rw-r--r--arch/arm/mach-ux500/include/mach/db8500-regs.h37
-rw-r--r--arch/arm/mach-ux500/include/mach/hardware.h1
-rw-r--r--arch/arm/mach-ux500/include/mach/id.h20
-rw-r--r--arch/arm/mach-ux500/include/mach/irqs-board-mop500.h5
-rw-r--r--arch/arm/mach-ux500/include/mach/irqs-board-u5500.h21
-rw-r--r--arch/arm/mach-ux500/include/mach/irqs-db5500.h27
-rw-r--r--arch/arm/mach-ux500/include/mach/irqs-db8500.h54
-rw-r--r--arch/arm/mach-ux500/include/mach/irqs.h46
-rw-r--r--arch/arm/mach-ux500/include/mach/prcmu-defs.h30
-rw-r--r--arch/arm/mach-ux500/include/mach/prcmu.h28
-rw-r--r--arch/arm/mach-ux500/include/mach/smp.h24
-rw-r--r--arch/arm/mach-ux500/include/mach/uncompress.h2
-rw-r--r--arch/arm/mach-ux500/mbox-db5500.c6
-rw-r--r--arch/arm/mach-ux500/platsmp.c8
-rw-r--r--arch/arm/mach-ux500/prcmu.c394
-rw-r--r--arch/arm/mach-versatile/core.c44
-rw-r--r--arch/arm/mach-vexpress/ct-ca9x4.c19
-rw-r--r--arch/arm/mach-vexpress/include/mach/smp.h13
-rw-r--r--arch/arm/mach-vexpress/v2m.c39
-rw-r--r--arch/arm/mach-w90x900/include/mach/uncompress.h2
-rw-r--r--arch/arm/mach-w90x900/time.c17
-rw-r--r--arch/arm/mm/flush.c7
-rw-r--r--arch/arm/mm/init.c25
-rw-r--r--arch/arm/mm/mmu.c2
-rw-r--r--arch/arm/mm/proc-v6.S34
-rw-r--r--arch/arm/plat-iop/time.c1
-rw-r--r--arch/arm/plat-mxc/Kconfig28
-rw-r--r--arch/arm/plat-mxc/cpufreq.c4
-rw-r--r--arch/arm/plat-mxc/devices/Kconfig7
-rw-r--r--arch/arm/plat-mxc/devices/Makefile2
-rw-r--r--arch/arm/plat-mxc/devices/platform-ipu-core.c129
-rw-r--r--arch/arm/plat-mxc/devices/platform-mxc_rtc.c40
-rw-r--r--arch/arm/plat-mxc/devices/platform-spi_imx.c2
-rw-r--r--arch/arm/plat-mxc/epit.c18
-rw-r--r--arch/arm/plat-mxc/include/mach/common.h8
-rw-r--r--arch/arm/plat-mxc/include/mach/debug-macro.S7
-rw-r--r--arch/arm/plat-mxc/include/mach/devices-common.h27
-rw-r--r--arch/arm/plat-mxc/include/mach/hardware.h17
-rw-r--r--arch/arm/plat-mxc/include/mach/io.h23
-rw-r--r--arch/arm/plat-mxc/include/mach/iomux-mx25.h3
-rw-r--r--arch/arm/plat-mxc/include/mach/iomux-mxc91231.h283
-rw-r--r--arch/arm/plat-mxc/include/mach/irqs.h2
-rw-r--r--arch/arm/plat-mxc/include/mach/memory.h3
-rw-r--r--arch/arm/plat-mxc/include/mach/mx27.h4
-rw-r--r--arch/arm/plat-mxc/include/mach/mx53.h13
-rw-r--r--arch/arm/plat-mxc/include/mach/mxc.h22
-rw-r--r--arch/arm/plat-mxc/include/mach/mxc91231.h256
-rw-r--r--arch/arm/plat-mxc/include/mach/system.h6
-rw-r--r--arch/arm/plat-mxc/include/mach/timex.h2
-rw-r--r--arch/arm/plat-mxc/include/mach/uncompress.h2
-rw-r--r--arch/arm/plat-mxc/system.c6
-rw-r--r--arch/arm/plat-mxc/time.c40
-rw-r--r--arch/arm/plat-nomadik/Kconfig1
-rw-r--r--arch/arm/plat-nomadik/gpio.c12
-rw-r--r--arch/arm/plat-nomadik/include/plat/i2c.h8
-rw-r--r--arch/arm/plat-nomadik/timer.c31
-rw-r--r--arch/arm/plat-omap/Kconfig2
-rw-r--r--arch/arm/plat-omap/gpio.c42
-rw-r--r--arch/arm/plat-omap/include/plat/flash.h2
-rw-r--r--arch/arm/plat-omap/include/plat/gpmc-smsc911x.h4
-rw-r--r--arch/arm/plat-omap/include/plat/smp.h36
-rw-r--r--arch/arm/plat-omap/include/plat/uncompress.h5
-rw-r--r--arch/arm/plat-omap/include/plat/usb.h2
-rw-r--r--arch/arm/plat-omap/omap_device.c23
-rw-r--r--arch/arm/plat-orion/Makefile2
-rw-r--r--arch/arm/plat-orion/common.c957
-rw-r--r--arch/arm/plat-orion/gpio.c112
-rw-r--r--arch/arm/plat-orion/include/plat/common.h117
-rw-r--r--arch/arm/plat-orion/include/plat/gpio.h1
-rw-r--r--arch/arm/plat-orion/include/plat/mpp.h34
-rw-r--r--arch/arm/plat-orion/irq.c49
-rw-r--r--arch/arm/plat-orion/mpp.c78
-rw-r--r--arch/arm/plat-orion/time.c21
-rw-r--r--arch/arm/plat-pxa/gpio.c17
-rw-r--r--arch/arm/plat-pxa/mfp.c1
-rw-r--r--arch/arm/plat-s3c24xx/devs.c41
-rw-r--r--arch/arm/plat-s3c24xx/dma.c68
-rw-r--r--arch/arm/plat-s3c24xx/include/plat/udc.h17
-rw-r--r--arch/arm/plat-s3c24xx/irq-pm.c7
-rw-r--r--arch/arm/plat-s5p/Kconfig5
-rw-r--r--arch/arm/plat-s5p/Makefile1
-rw-r--r--arch/arm/plat-s5p/dev-ehci.c57
-rw-r--r--arch/arm/plat-s5p/include/plat/ehci.h21
-rw-r--r--arch/arm/plat-s5p/include/plat/map-s5p.h2
-rw-r--r--arch/arm/plat-s5p/include/plat/usb-phy.h22
-rw-r--r--arch/arm/plat-s5p/irq-gpioint.c116
-rw-r--r--arch/arm/plat-s5p/irq-pm.c7
-rw-r--r--arch/arm/plat-s5p/irq.c6
-rw-r--r--arch/arm/plat-s5p/s5p-time.c58
-rw-r--r--arch/arm/plat-samsung/Kconfig1
-rw-r--r--arch/arm/plat-samsung/include/plat/cpu.h6
-rw-r--r--arch/arm/plat-samsung/include/plat/devs.h3
-rw-r--r--arch/arm/plat-samsung/include/plat/irq-vic-timer.h2
-rw-r--r--arch/arm/plat-samsung/include/plat/pm.h6
-rw-r--r--arch/arm/plat-samsung/include/plat/uncompress.h4
-rw-r--r--arch/arm/plat-samsung/irq-uart.c83
-rw-r--r--arch/arm/plat-samsung/irq-vic-timer.c69
-rw-r--r--arch/arm/plat-spear/clock.c5
-rw-r--r--arch/arm/plat-spear/include/plat/clock.h1
-rw-r--r--arch/arm/plat-spear/time.c16
-rw-r--r--arch/arm/plat-stmp3xxx/Kconfig37
-rw-r--r--arch/arm/plat-stmp3xxx/Makefile5
-rw-r--r--arch/arm/plat-stmp3xxx/clock.c1134
-rw-r--r--arch/arm/plat-stmp3xxx/clock.h61
-rw-r--r--arch/arm/plat-stmp3xxx/core.c128
-rw-r--r--arch/arm/plat-stmp3xxx/devices.c389
-rw-r--r--arch/arm/plat-stmp3xxx/dma.c464
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/clkdev.h18
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/cputype.h33
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/debug-macro.S39
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/dma.h153
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/gpio.h28
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/gpmi.h12
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/hardware.h32
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/io.h25
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/memory.h22
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/mmc.h14
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/pinmux.h157
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/pins.h30
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/platform.h68
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/stmp3xxx.h54
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/system.h49
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/timex.h20
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/uncompress.h53
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/vmalloc.h12
-rw-r--r--arch/arm/plat-stmp3xxx/irq.c50
-rw-r--r--arch/arm/plat-stmp3xxx/pinmux.c550
-rw-r--r--arch/arm/plat-stmp3xxx/timer.c186
-rw-r--r--arch/arm/plat-versatile/platsmp.c3
-rw-r--r--arch/arm/tools/mach-types142
-rw-r--r--arch/arm/vfp/vfpmodule.c19
-rw-r--r--arch/avr32/include/asm/bitops.h15
-rw-r--r--arch/avr32/mach-at32ap/intc.c38
-rw-r--r--arch/avr32/mm/init.c2
-rw-r--r--arch/blackfin/Kconfig5
-rw-r--r--arch/blackfin/Kconfig.debug11
-rw-r--r--arch/blackfin/configs/BF527-EZKIT-V2_defconfig12
-rw-r--r--arch/blackfin/configs/BF527-EZKIT_defconfig14
-rw-r--r--arch/blackfin/configs/BF533-STAMP_defconfig2
-rw-r--r--arch/blackfin/configs/BF537-STAMP_defconfig2
-rw-r--r--arch/blackfin/include/asm/bfin-global.h10
-rw-r--r--arch/blackfin/include/asm/bfin_pfmon.h44
-rw-r--r--arch/blackfin/include/asm/bfin_sport.h4
-rw-r--r--arch/blackfin/include/asm/cacheflush.h23
-rw-r--r--arch/blackfin/include/asm/cpu.h3
-rw-r--r--arch/blackfin/include/asm/def_LPBlackfin.h12
-rw-r--r--arch/blackfin/include/asm/irq_handler.h25
-rw-r--r--arch/blackfin/include/asm/kgdb.h7
-rw-r--r--arch/blackfin/include/asm/perf_event.h1
-rw-r--r--arch/blackfin/include/asm/ptrace.h7
-rw-r--r--arch/blackfin/include/mach-common/irq.h57
-rw-r--r--arch/blackfin/kernel/Makefile3
-rw-r--r--arch/blackfin/kernel/bfin_dma_5xx.c5
-rw-r--r--arch/blackfin/kernel/bfin_gpio.c34
-rw-r--r--arch/blackfin/kernel/bfin_ksyms.c1
-rw-r--r--arch/blackfin/kernel/debug-mmrs.c1860
-rw-r--r--arch/blackfin/kernel/ipipe.c1
-rw-r--r--arch/blackfin/kernel/irqchip.c1
-rw-r--r--arch/blackfin/kernel/nmi.c38
-rw-r--r--arch/blackfin/kernel/perf_event.c498
-rw-r--r--arch/blackfin/kernel/process.c6
-rw-r--r--arch/blackfin/kernel/reboot.c65
-rw-r--r--arch/blackfin/kernel/setup.c54
-rw-r--r--arch/blackfin/kernel/time-ts.c35
-rw-r--r--arch/blackfin/kernel/vmlinux.lds.S10
-rw-r--r--arch/blackfin/mach-bf518/include/mach/anomaly.h4
-rw-r--r--arch/blackfin/mach-bf518/include/mach/cdefBF512.h16
-rw-r--r--arch/blackfin/mach-bf518/include/mach/defBF512.h8
-rw-r--r--arch/blackfin/mach-bf518/include/mach/irq.h262
-rw-r--r--arch/blackfin/mach-bf527/boards/ezkit.c74
-rw-r--r--arch/blackfin/mach-bf527/include/mach/anomaly.h8
-rw-r--r--arch/blackfin/mach-bf527/include/mach/cdefBF522.h16
-rw-r--r--arch/blackfin/mach-bf527/include/mach/defBF522.h8
-rw-r--r--arch/blackfin/mach-bf527/include/mach/irq.h266
-rw-r--r--arch/blackfin/mach-bf533/include/mach/anomaly.h11
-rw-r--r--arch/blackfin/mach-bf533/include/mach/irq.h168
-rw-r--r--arch/blackfin/mach-bf537/boards/stamp.c106
-rw-r--r--arch/blackfin/mach-bf537/include/mach/anomaly.h10
-rw-r--r--arch/blackfin/mach-bf537/include/mach/irq.h365
-rw-r--r--arch/blackfin/mach-bf537/ints-priority.c163
-rw-r--r--arch/blackfin/mach-bf538/include/mach/anomaly.h9
-rw-r--r--arch/blackfin/mach-bf538/include/mach/irq.h89
-rw-r--r--arch/blackfin/mach-bf548/boards/ezkit.c116
-rw-r--r--arch/blackfin/mach-bf548/include/mach/anomaly.h8
-rw-r--r--arch/blackfin/mach-bf548/include/mach/irq.h89
-rw-r--r--arch/blackfin/mach-bf561/boards/ezkit.c10
-rw-r--r--arch/blackfin/mach-bf561/include/mach/anomaly.h15
-rw-r--r--arch/blackfin/mach-bf561/include/mach/irq.h505
-rw-r--r--arch/blackfin/mach-bf561/smp.c17
-rw-r--r--arch/blackfin/mach-common/dpmc.c10
-rw-r--r--arch/blackfin/mach-common/ints-priority.c476
-rw-r--r--arch/blackfin/mach-common/smp.c31
-rw-r--r--arch/blackfin/mm/sram-alloc.c43
-rw-r--r--arch/cris/Kconfig4
-rw-r--r--arch/cris/arch-v32/kernel/irq.c4
-rw-r--r--arch/cris/arch-v32/kernel/smp.c46
-rw-r--r--arch/cris/arch-v32/mach-fs/Makefile2
-rw-r--r--arch/cris/kernel/vmlinux.lds.S2
-rw-r--r--arch/cris/mm/init.c2
-rw-r--r--arch/frv/Kconfig8
-rw-r--r--arch/frv/kernel/vmlinux.lds.S2
-rw-r--r--arch/frv/mm/init.c2
-rw-r--r--arch/h8300/Kconfig8
-rw-r--r--arch/ia64/Kconfig4
-rw-r--r--arch/ia64/hp/common/sba_iommu.c3
-rw-r--r--arch/ia64/include/asm/tlb.h66
-rw-r--r--arch/ia64/kernel/cpufreq/acpi-cpufreq.c44
-rw-r--r--arch/ia64/kernel/cyclone.c6
-rw-r--r--arch/ia64/kernel/irq_ia64.c2
-rw-r--r--arch/ia64/kernel/time.c11
-rw-r--r--arch/ia64/kernel/vmlinux.lds.S1
-rw-r--r--arch/ia64/kvm/vti.h26
-rw-r--r--arch/ia64/mm/contig.c10
-rw-r--r--arch/ia64/mm/discontig.c10
-rw-r--r--arch/ia64/mm/fault.c1
-rw-r--r--arch/ia64/mm/init.c2
-rw-r--r--arch/ia64/oprofile/backtrace.c2
-rw-r--r--arch/ia64/sn/kernel/sn2/timer.c6
-rw-r--r--arch/ia64/xen/irq_xen.c10
-rw-r--r--arch/m32r/Kconfig8
-rw-r--r--arch/m32r/Kconfig.debug9
-rw-r--r--arch/m32r/include/asm/smp.h6
-rw-r--r--arch/m32r/kernel/smp.c68
-rw-r--r--arch/m32r/kernel/smpboot.c48
-rw-r--r--arch/m32r/kernel/vmlinux.lds.S3
-rw-r--r--arch/m32r/mm/discontig.c1
-rw-r--r--arch/m32r/mm/init.c2
-rw-r--r--arch/m68k/Kconfig1
-rw-r--r--arch/m68k/Kconfig.nommu4
-rw-r--r--arch/m68k/atari/atakeyb.c9
-rw-r--r--arch/m68k/atari/stdma.c2
-rw-r--r--arch/m68k/include/asm/MC68EZ328.h2
-rw-r--r--arch/m68k/include/asm/MC68VZ328.h2
-rw-r--r--arch/m68k/include/asm/atarikb.h2
-rw-r--r--arch/m68k/include/asm/bitops_mm.h95
-rw-r--r--arch/m68k/include/asm/bitops_no.h22
-rw-r--r--arch/m68k/include/asm/io_no.h8
-rw-r--r--arch/m68k/include/asm/unistd.h46
-rw-r--r--arch/m68k/kernel/Makefile_mm2
-rw-r--r--arch/m68k/kernel/asm-offsets.c106
-rw-r--r--arch/m68k/kernel/asm-offsets_mm.c100
-rw-r--r--arch/m68k/kernel/asm-offsets_no.c76
-rw-r--r--arch/m68k/kernel/entry_mm.S348
-rw-r--r--arch/m68k/kernel/entry_no.S1
-rw-r--r--arch/m68k/kernel/irq.c28
-rw-r--r--arch/m68k/kernel/m68k_ksyms.c36
-rw-r--r--arch/m68k/kernel/m68k_ksyms_mm.c16
-rw-r--r--arch/m68k/kernel/m68k_ksyms_no.c78
-rw-r--r--arch/m68k/kernel/process_no.c2
-rw-r--r--arch/m68k/kernel/sys_m68k.c581
-rw-r--r--arch/m68k/kernel/sys_m68k_mm.c546
-rw-r--r--arch/m68k/kernel/sys_m68k_no.c94
-rw-r--r--arch/m68k/kernel/syscalltable.S196
-rw-r--r--arch/m68k/kernel/vmlinux-std.lds2
-rw-r--r--arch/m68k/kernel/vmlinux-sun3.lds1
-rw-r--r--arch/m68k/lib/Makefile13
-rw-r--r--arch/m68k/lib/Makefile_mm6
-rw-r--r--arch/m68k/lib/Makefile_no7
-rw-r--r--arch/m68k/lib/checksum.c5
-rw-r--r--arch/m68k/lib/checksum_no.c3
-rw-r--r--arch/m68k/lib/memcpy.c128
-rw-r--r--arch/m68k/lib/memmove.c2
-rw-r--r--arch/m68k/lib/memset.c114
-rw-r--r--arch/m68k/lib/muldi3.c99
-rw-r--r--arch/m68k/lib/muldi3_mm.c63
-rw-r--r--arch/m68k/lib/muldi3_no.c86
-rw-r--r--arch/m68k/lib/string.c223
-rw-r--r--arch/m68k/mm/Makefile14
-rw-r--r--arch/m68k/mm/Makefile_mm8
-rw-r--r--arch/m68k/mm/Makefile_no5
-rw-r--r--arch/m68k/mm/init_mm.c2
-rw-r--r--arch/m68k/mm/init_no.c51
-rw-r--r--arch/m68k/mm/kmap.c368
-rw-r--r--arch/m68k/mm/kmap_mm.c367
-rw-r--r--arch/m68k/mm/kmap_no.c45
-rw-r--r--arch/m68k/platform/68328/entry.S7
-rw-r--r--arch/m68k/platform/68360/entry.S7
-rw-r--r--arch/m68k/platform/coldfire/dma.c3
-rw-r--r--arch/m68k/platform/coldfire/entry.S11
-rw-r--r--arch/m68k/platform/coldfire/head.S1
-rw-r--r--arch/microblaze/Kconfig6
-rw-r--r--arch/microblaze/kernel/timer.c6
-rw-r--r--arch/microblaze/mm/init.c2
-rw-r--r--arch/mips/Kbuild.platforms1
-rw-r--r--arch/mips/Kconfig70
-rw-r--r--arch/mips/Kconfig.debug9
-rw-r--r--arch/mips/Makefile12
-rw-r--r--arch/mips/alchemy/common/dbdma.c123
-rw-r--r--arch/mips/alchemy/common/dma.c46
-rw-r--r--arch/mips/alchemy/common/irq.c345
-rw-r--r--arch/mips/alchemy/common/platform.c250
-rw-r--r--arch/mips/alchemy/common/setup.c4
-rw-r--r--arch/mips/alchemy/common/time.c3
-rw-r--r--arch/mips/alchemy/devboards/db1200/setup.c7
-rw-r--r--arch/mips/alchemy/devboards/pb1000/board_setup.c2
-rw-r--r--arch/mips/alchemy/devboards/pb1500/board_setup.c2
-rw-r--r--arch/mips/alchemy/devboards/prom.c2
-rw-r--r--arch/mips/alchemy/gpr/board_setup.c14
-rw-r--r--arch/mips/alchemy/gpr/init.c2
-rw-r--r--arch/mips/alchemy/mtx-1/board_setup.c2
-rw-r--r--arch/mips/alchemy/mtx-1/init.c2
-rw-r--r--arch/mips/alchemy/mtx-1/platform.c4
-rw-r--r--arch/mips/alchemy/xxs1500/board_setup.c11
-rw-r--r--arch/mips/alchemy/xxs1500/init.c2
-rw-r--r--arch/mips/ath79/Kconfig5
-rw-r--r--arch/mips/bcm47xx/nvram.c3
-rw-r--r--arch/mips/bcm47xx/setup.c130
-rw-r--r--arch/mips/bcm63xx/boards/board_bcm963xx.c16
-rw-r--r--arch/mips/boot/compressed/uart-alchemy.c2
-rw-r--r--arch/mips/cavium-octeon/csrc-octeon.c3
-rw-r--r--arch/mips/cavium-octeon/setup.c7
-rw-r--r--arch/mips/cavium-octeon/smp.c17
-rw-r--r--arch/mips/configs/bcm47xx_defconfig1
-rw-r--r--arch/mips/configs/lemote2f_defconfig6
-rw-r--r--arch/mips/configs/malta_defconfig2
-rw-r--r--arch/mips/configs/mtx1_defconfig4
-rw-r--r--arch/mips/configs/nlm_xlr_defconfig574
-rw-r--r--arch/mips/fw/arc/cmdline.c2
-rw-r--r--arch/mips/fw/arc/env.c2
-rw-r--r--arch/mips/fw/arc/identify.c2
-rw-r--r--arch/mips/fw/arc/init.c2
-rw-r--r--arch/mips/fw/arc/misc.c2
-rw-r--r--arch/mips/fw/arc/salone.c2
-rw-r--r--arch/mips/fw/arc/time.c2
-rw-r--r--arch/mips/fw/arc/tree.c2
-rw-r--r--arch/mips/include/asm/asmmacro-32.h2
-rw-r--r--arch/mips/include/asm/asmmacro-64.h2
-rw-r--r--arch/mips/include/asm/cpu.h29
-rw-r--r--arch/mips/include/asm/i8253.h5
-rw-r--r--arch/mips/include/asm/jump_label.h22
-rw-r--r--arch/mips/include/asm/mach-au1x00/au1000.h334
-rw-r--r--arch/mips/include/asm/mach-au1x00/au1000_dma.h4
-rw-r--r--arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h8
-rw-r--r--arch/mips/include/asm/mach-au1x00/gpio-au1000.h122
-rw-r--r--arch/mips/include/asm/mach-bcm47xx/nvram.h12
-rw-r--r--arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h5
-rw-r--r--arch/mips/include/asm/mach-lantiq/lantiq.h63
-rw-r--r--arch/mips/include/asm/mach-lantiq/lantiq_platform.h53
-rw-r--r--arch/mips/include/asm/mach-lantiq/war.h24
-rw-r--r--arch/mips/include/asm/mach-lantiq/xway/irq.h18
-rw-r--r--arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h66
-rw-r--r--arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h141
-rw-r--r--arch/mips/include/asm/mach-lantiq/xway/xway_dma.h60
-rw-r--r--arch/mips/include/asm/mach-netlogic/cpu-feature-overrides.h47
-rw-r--r--arch/mips/include/asm/mach-netlogic/irq.h14
-rw-r--r--arch/mips/include/asm/mach-netlogic/war.h26
-rw-r--r--arch/mips/include/asm/module.h2
-rw-r--r--arch/mips/include/asm/netlogic/interrupt.h45
-rw-r--r--arch/mips/include/asm/netlogic/mips-extns.h76
-rw-r--r--arch/mips/include/asm/netlogic/psb-bootinfo.h109
-rw-r--r--arch/mips/include/asm/netlogic/xlr/gpio.h73
-rw-r--r--arch/mips/include/asm/netlogic/xlr/iomap.h131
-rw-r--r--arch/mips/include/asm/netlogic/xlr/pic.h231
-rw-r--r--arch/mips/include/asm/netlogic/xlr/xlr.h75
-rw-r--r--arch/mips/include/asm/ptrace.h3
-rw-r--r--arch/mips/include/asm/r4kcache.h2
-rw-r--r--arch/mips/include/asm/sgialib.h2
-rw-r--r--arch/mips/include/asm/sgiarcs.h2
-rw-r--r--arch/mips/include/asm/thread_info.h3
-rw-r--r--arch/mips/include/asm/time.h6
-rw-r--r--arch/mips/jz4740/setup.c32
-rw-r--r--arch/mips/jz4740/time.c3
-rw-r--r--arch/mips/kernel/Makefile1
-rw-r--r--arch/mips/kernel/cevt-txx9.c3
-rw-r--r--arch/mips/kernel/cpu-probe.c83
-rw-r--r--arch/mips/kernel/csrc-bcm1480.c3
-rw-r--r--arch/mips/kernel/csrc-ioasic.c4
-rw-r--r--arch/mips/kernel/csrc-powertv.c35
-rw-r--r--arch/mips/kernel/csrc-r4k.c4
-rw-r--r--arch/mips/kernel/csrc-sb1250.c3
-rw-r--r--arch/mips/kernel/entry.S7
-rw-r--r--arch/mips/kernel/i8253.c78
-rw-r--r--arch/mips/kernel/octeon_switch.S2
-rw-r--r--arch/mips/kernel/ptrace.c43
-rw-r--r--arch/mips/kernel/r2300_fpu.S2
-rw-r--r--arch/mips/kernel/r2300_switch.S2
-rw-r--r--arch/mips/kernel/r4k_fpu.S2
-rw-r--r--arch/mips/kernel/r4k_switch.S2
-rw-r--r--arch/mips/kernel/r6000_fpu.S2
-rw-r--r--arch/mips/kernel/scall32-o32.S3
-rw-r--r--arch/mips/kernel/scall64-64.S3
-rw-r--r--arch/mips/kernel/scall64-n32.S3
-rw-r--r--arch/mips/kernel/scall64-o32.S3
-rw-r--r--arch/mips/kernel/smtc.c2
-rw-r--r--arch/mips/kernel/syscall.c120
-rw-r--r--arch/mips/kernel/vmlinux.lds.S4
-rw-r--r--arch/mips/lantiq/Kconfig23
-rw-r--r--arch/mips/lantiq/Makefile11
-rw-r--r--arch/mips/lantiq/Platform8
-rw-r--r--arch/mips/lantiq/clk.c140
-rw-r--r--arch/mips/lantiq/clk.h18
-rw-r--r--arch/mips/lantiq/devices.c122
-rw-r--r--arch/mips/lantiq/devices.h23
-rw-r--r--arch/mips/lantiq/early_printk.c33
-rw-r--r--arch/mips/lantiq/irq.c326
-rw-r--r--arch/mips/lantiq/machtypes.h20
-rw-r--r--arch/mips/lantiq/prom.c71
-rw-r--r--arch/mips/lantiq/prom.h25
-rw-r--r--arch/mips/lantiq/setup.c66
-rw-r--r--arch/mips/lantiq/xway/Kconfig23
-rw-r--r--arch/mips/lantiq/xway/Makefile7
-rw-r--r--arch/mips/lantiq/xway/clk-ase.c48
-rw-r--r--arch/mips/lantiq/xway/clk-xway.c223
-rw-r--r--arch/mips/lantiq/xway/devices.c121
-rw-r--r--arch/mips/lantiq/xway/devices.h20
-rw-r--r--arch/mips/lantiq/xway/dma.c253
-rw-r--r--arch/mips/lantiq/xway/ebu.c53
-rw-r--r--arch/mips/lantiq/xway/gpio.c195
-rw-r--r--arch/mips/lantiq/xway/gpio_ebu.c126
-rw-r--r--arch/mips/lantiq/xway/gpio_stp.c157
-rw-r--r--arch/mips/lantiq/xway/mach-easy50601.c57
-rw-r--r--arch/mips/lantiq/xway/mach-easy50712.c74
-rw-r--r--arch/mips/lantiq/xway/pmu.c70
-rw-r--r--arch/mips/lantiq/xway/prom-ase.c39
-rw-r--r--arch/mips/lantiq/xway/prom-xway.c54
-rw-r--r--arch/mips/lantiq/xway/reset.c91
-rw-r--r--arch/mips/lantiq/xway/setup-ase.c19
-rw-r--r--arch/mips/lantiq/xway/setup-xway.c20
-rw-r--r--arch/mips/lib/Makefile1
-rw-r--r--arch/mips/loongson/common/cs5536/cs5536_mfgpt.c5
-rw-r--r--arch/mips/mm/Makefile4
-rw-r--r--arch/mips/mm/c-r3k.c2
-rw-r--r--arch/mips/mm/c-r4k.c3
-rw-r--r--arch/mips/mm/c-tx39.c2
-rw-r--r--arch/mips/mm/init.c2
-rw-r--r--arch/mips/mm/mmap.c122
-rw-r--r--arch/mips/mm/sc-ip22.c2
-rw-r--r--arch/mips/mm/sc-r5k.c2
-rw-r--r--arch/mips/mm/tlb-r3k.c2
-rw-r--r--arch/mips/mm/tlb-r4k.c2
-rw-r--r--arch/mips/mm/tlb-r8k.c2
-rw-r--r--arch/mips/mm/tlbex.c1
-rw-r--r--arch/mips/mti-malta/malta-int.c2
-rw-r--r--arch/mips/netlogic/Kconfig5
-rw-r--r--arch/mips/netlogic/xlr/Makefile5
-rw-r--r--arch/mips/netlogic/xlr/irq.c300
-rw-r--r--arch/mips/netlogic/xlr/platform.c98
-rw-r--r--arch/mips/netlogic/xlr/setup.c188
-rw-r--r--arch/mips/netlogic/xlr/smp.c225
-rw-r--r--arch/mips/netlogic/xlr/smpboot.S94
-rw-r--r--arch/mips/netlogic/xlr/time.c51
-rw-r--r--arch/mips/netlogic/xlr/xlr_console.c46
-rw-r--r--arch/mips/pci/Makefile2
-rw-r--r--arch/mips/pci/ops-lantiq.c116
-rw-r--r--arch/mips/pci/pci-lantiq.c297
-rw-r--r--arch/mips/pci/pci-lantiq.h18
-rw-r--r--arch/mips/pci/pci-xlr.c214
-rw-r--r--arch/mips/pmc-sierra/yosemite/smp.c4
-rw-r--r--arch/mips/sgi-ip22/ip22-hpc.c2
-rw-r--r--arch/mips/sgi-ip22/ip22-int.c2
-rw-r--r--arch/mips/sgi-ip22/ip22-mc.c2
-rw-r--r--arch/mips/sgi-ip22/ip22-setup.c2
-rw-r--r--arch/mips/sgi-ip27/ip27-irq.c2
-rw-r--r--arch/mips/sgi-ip27/ip27-timer.c16
-rw-r--r--arch/mips/sibyte/bcm1480/smp.c7
-rw-r--r--arch/mips/sibyte/sb1250/smp.c7
-rw-r--r--arch/mips/txx9/generic/setup_tx4939.c21
-rw-r--r--arch/mn10300/Kconfig3
-rw-r--r--arch/mn10300/configs/asb2364_defconfig1
-rw-r--r--arch/mn10300/kernel/irq.c16
-rw-r--r--arch/mn10300/kernel/smp.c80
-rw-r--r--arch/mn10300/kernel/vmlinux.lds.S2
-rw-r--r--arch/mn10300/mm/cache-smp.c8
-rw-r--r--arch/mn10300/mm/init.c2
-rw-r--r--arch/mn10300/mm/tlb-smp.c32
-rw-r--r--arch/parisc/Kconfig8
-rw-r--r--arch/parisc/include/asm/cacheflush.h5
-rw-r--r--arch/parisc/include/asm/pgtable.h9
-rw-r--r--arch/parisc/include/asm/smp.h9
-rw-r--r--arch/parisc/include/asm/unistd.h10
-rw-r--r--arch/parisc/kernel/cache.c13
-rw-r--r--arch/parisc/kernel/entry.S3
-rw-r--r--arch/parisc/kernel/head.S5
-rw-r--r--arch/parisc/kernel/module.c10
-rw-r--r--arch/parisc/kernel/pacache.S6
-rw-r--r--arch/parisc/kernel/smp.c5
-rw-r--r--arch/parisc/kernel/sys_parisc32.c8
-rw-r--r--arch/parisc/kernel/syscall_table.S6
-rw-r--r--arch/parisc/kernel/vmlinux.lds.S6
-rw-r--r--arch/parisc/mm/init.c264
-rw-r--r--arch/powerpc/Kconfig16
-rw-r--r--arch/powerpc/Kconfig.debug26
-rw-r--r--arch/powerpc/boot/Makefile6
-rw-r--r--arch/powerpc/boot/crt0.S116
-rw-r--r--arch/powerpc/boot/dts/canyonlands.dts18
-rw-r--r--arch/powerpc/boot/dts/katmai.dts18
-rw-r--r--arch/powerpc/boot/dts/kilauea.dts28
-rw-r--r--arch/powerpc/boot/dts/mpc8313erdb.dts13
-rw-r--r--arch/powerpc/boot/dts/mpc8572ds.dts13
-rw-r--r--arch/powerpc/boot/dts/p1020rdb.dts332
-rw-r--r--arch/powerpc/boot/dts/p1020rdb_camp_core0.dts213
-rw-r--r--arch/powerpc/boot/dts/p1020rdb_camp_core1.dts148
-rw-r--r--arch/powerpc/boot/dts/p1020si.dtsi377
-rw-r--r--arch/powerpc/boot/dts/p1022ds.dts106
-rw-r--r--arch/powerpc/boot/dts/p2020ds.dts385
-rw-r--r--arch/powerpc/boot/dts/p2020rdb.dts389
-rw-r--r--arch/powerpc/boot/dts/p2020rdb_camp_core0.dts245
-rw-r--r--arch/powerpc/boot/dts/p2020rdb_camp_core1.dts150
-rw-r--r--arch/powerpc/boot/dts/p2020si.dtsi382
-rw-r--r--arch/powerpc/boot/dts/p4080ds.dts86
-rw-r--r--arch/powerpc/boot/dts/redwood.dts20
-rw-r--r--arch/powerpc/boot/epapr.c66
-rwxr-xr-xarch/powerpc/boot/wrapper19
-rw-r--r--arch/powerpc/boot/zImage.coff.lds.S6
-rw-r--r--arch/powerpc/boot/zImage.lds.S57
-rw-r--r--arch/powerpc/configs/83xx/mpc8313_rdb_defconfig1
-rw-r--r--arch/powerpc/configs/83xx/mpc8315_rdb_defconfig1
-rw-r--r--arch/powerpc/configs/85xx/mpc8540_ads_defconfig1
-rw-r--r--arch/powerpc/configs/85xx/mpc8560_ads_defconfig1
-rw-r--r--arch/powerpc/configs/85xx/mpc85xx_cds_defconfig1
-rw-r--r--arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig1
-rw-r--r--arch/powerpc/configs/c2k_defconfig4
-rw-r--r--arch/powerpc/configs/e55xx_smp_defconfig39
-rw-r--r--arch/powerpc/configs/mpc85xx_defconfig1
-rw-r--r--arch/powerpc/configs/mpc85xx_smp_defconfig1
-rw-r--r--arch/powerpc/configs/mpc86xx_defconfig1
-rw-r--r--arch/powerpc/configs/pmac32_defconfig4
-rw-r--r--arch/powerpc/configs/ppc6xx_defconfig5
-rw-r--r--arch/powerpc/configs/ps3_defconfig4
-rw-r--r--arch/powerpc/configs/pseries_defconfig9
-rw-r--r--arch/powerpc/include/asm/cputable.h55
-rw-r--r--arch/powerpc/include/asm/cputhreads.h12
-rw-r--r--arch/powerpc/include/asm/dbell.h3
-rw-r--r--arch/powerpc/include/asm/emulated_ops.h4
-rw-r--r--arch/powerpc/include/asm/exception-64s.h113
-rw-r--r--arch/powerpc/include/asm/feature-fixups.h15
-rw-r--r--arch/powerpc/include/asm/firmware.h3
-rw-r--r--arch/powerpc/include/asm/fsl_lbc.h2
-rw-r--r--arch/powerpc/include/asm/ftrace.h14
-rw-r--r--arch/powerpc/include/asm/hvcall.h14
-rw-r--r--arch/powerpc/include/asm/io-workarounds.h (renamed from arch/powerpc/platforms/cell/io-workarounds.h)1
-rw-r--r--arch/powerpc/include/asm/io.h33
-rw-r--r--arch/powerpc/include/asm/io_event_irq.h54
-rw-r--r--arch/powerpc/include/asm/irq.h18
-rw-r--r--arch/powerpc/include/asm/kexec.h2
-rw-r--r--arch/powerpc/include/asm/kvm.h184
-rw-r--r--arch/powerpc/include/asm/kvm_44x.h1
-rw-r--r--arch/powerpc/include/asm/kvm_asm.h1
-rw-r--r--arch/powerpc/include/asm/kvm_book3s_asm.h1
-rw-r--r--arch/powerpc/include/asm/kvm_e500.h2
-rw-r--r--arch/powerpc/include/asm/kvm_host.h5
-rw-r--r--arch/powerpc/include/asm/kvm_ppc.h9
-rw-r--r--arch/powerpc/include/asm/lppaca.h2
-rw-r--r--arch/powerpc/include/asm/machdep.h22
-rw-r--r--arch/powerpc/include/asm/mmu-book3e.h20
-rw-r--r--arch/powerpc/include/asm/mmu-hash64.h6
-rw-r--r--arch/powerpc/include/asm/mmu.h52
-rw-r--r--arch/powerpc/include/asm/mmu_context.h12
-rw-r--r--arch/powerpc/include/asm/mpic.h8
-rw-r--r--arch/powerpc/include/asm/pSeries_reconfig.h5
-rw-r--r--arch/powerpc/include/asm/paca.h11
-rw-r--r--arch/powerpc/include/asm/page_64.h21
-rw-r--r--arch/powerpc/include/asm/pgalloc.h21
-rw-r--r--arch/powerpc/include/asm/pgtable-ppc64.h13
-rw-r--r--arch/powerpc/include/asm/ppc-opcode.h35
-rw-r--r--arch/powerpc/include/asm/ppc_asm.h1
-rw-r--r--arch/powerpc/include/asm/processor.h4
-rw-r--r--arch/powerpc/include/asm/pte-hash64-64k.h2
-rw-r--r--arch/powerpc/include/asm/reg.h104
-rw-r--r--arch/powerpc/include/asm/reg_a2.h165
-rw-r--r--arch/powerpc/include/asm/reg_booke.h10
-rw-r--r--arch/powerpc/include/asm/rio.h5
-rw-r--r--arch/powerpc/include/asm/rtas.h45
-rw-r--r--arch/powerpc/include/asm/scom.h156
-rw-r--r--arch/powerpc/include/asm/smp.h36
-rw-r--r--arch/powerpc/include/asm/syscall.h5
-rw-r--r--arch/powerpc/include/asm/systbl.h1
-rw-r--r--arch/powerpc/include/asm/system.h2
-rw-r--r--arch/powerpc/include/asm/thread_info.h9
-rw-r--r--arch/powerpc/include/asm/tlbflush.h2
-rw-r--r--arch/powerpc/include/asm/udbg.h1
-rw-r--r--arch/powerpc/include/asm/unistd.h3
-rw-r--r--arch/powerpc/include/asm/wsp.h14
-rw-r--r--arch/powerpc/include/asm/xics.h142
-rw-r--r--arch/powerpc/kernel/Makefile7
-rw-r--r--arch/powerpc/kernel/asm-offsets.c2
-rw-r--r--arch/powerpc/kernel/cpu_setup_a2.S114
-rw-r--r--arch/powerpc/kernel/cpu_setup_fsl_booke.S3
-rw-r--r--arch/powerpc/kernel/cpu_setup_power7.S91
-rw-r--r--arch/powerpc/kernel/cputable.c66
-rw-r--r--arch/powerpc/kernel/crash.c91
-rw-r--r--arch/powerpc/kernel/dbell.c65
-rw-r--r--arch/powerpc/kernel/entry_64.S27
-rw-r--r--arch/powerpc/kernel/exceptions-64e.S202
-rw-r--r--arch/powerpc/kernel/exceptions-64s.S216
-rw-r--r--arch/powerpc/kernel/ftrace.c8
-rw-r--r--arch/powerpc/kernel/head_32.S22
-rw-r--r--arch/powerpc/kernel/head_64.S49
-rw-r--r--arch/powerpc/kernel/idle_power7.S97
-rw-r--r--arch/powerpc/kernel/io-workarounds.c (renamed from arch/powerpc/platforms/cell/io-workarounds.c)31
-rw-r--r--arch/powerpc/kernel/irq.c212
-rw-r--r--arch/powerpc/kernel/kgdb.c4
-rw-r--r--arch/powerpc/kernel/lparcfg.c53
-rw-r--r--arch/powerpc/kernel/misc_32.S11
-rw-r--r--arch/powerpc/kernel/misc_64.S13
-rw-r--r--arch/powerpc/kernel/paca.c30
-rw-r--r--arch/powerpc/kernel/pci_dn.c3
-rw-r--r--arch/powerpc/kernel/ppc_ksyms.c5
-rw-r--r--arch/powerpc/kernel/process.c43
-rw-r--r--arch/powerpc/kernel/prom.c64
-rw-r--r--arch/powerpc/kernel/prom_init.c30
-rw-r--r--arch/powerpc/kernel/ptrace.c10
-rw-r--r--arch/powerpc/kernel/rtas.c4
-rw-r--r--arch/powerpc/kernel/setup-common.c22
-rw-r--r--arch/powerpc/kernel/setup_32.c1
-rw-r--r--arch/powerpc/kernel/setup_64.c44
-rw-r--r--arch/powerpc/kernel/signal_64.c4
-rw-r--r--arch/powerpc/kernel/smp.c138
-rw-r--r--arch/powerpc/kernel/sysfs.c38
-rw-r--r--arch/powerpc/kernel/traps.c42
-rw-r--r--arch/powerpc/kernel/udbg.c2
-rw-r--r--arch/powerpc/kernel/udbg_16550.c51
-rw-r--r--arch/powerpc/kernel/vector.S2
-rw-r--r--arch/powerpc/kernel/vmlinux.lds.S2
-rw-r--r--arch/powerpc/kvm/44x.c10
-rw-r--r--arch/powerpc/kvm/44x_emulate.c2
-rw-r--r--arch/powerpc/kvm/book3s.c2
-rw-r--r--arch/powerpc/kvm/book3s_rmhandlers.S13
-rw-r--r--arch/powerpc/kvm/book3s_segment.S12
-rw-r--r--arch/powerpc/kvm/booke.c154
-rw-r--r--arch/powerpc/kvm/booke_interrupts.S1
-rw-r--r--arch/powerpc/kvm/e500.c76
-rw-r--r--arch/powerpc/kvm/e500_emulate.c7
-rw-r--r--arch/powerpc/kvm/e500_tlb.c13
-rw-r--r--arch/powerpc/kvm/emulate.c15
-rw-r--r--arch/powerpc/kvm/powerpc.c21
-rw-r--r--arch/powerpc/kvm/timing.c31
-rw-r--r--arch/powerpc/lib/alloc.c8
-rw-r--r--arch/powerpc/lib/copypage_64.S7
-rw-r--r--arch/powerpc/lib/devres.c6
-rw-r--r--arch/powerpc/lib/sstep.c62
-rw-r--r--arch/powerpc/mm/hash_low_64.S8
-rw-r--r--arch/powerpc/mm/hash_native_64.c18
-rw-r--r--arch/powerpc/mm/hash_utils_64.c62
-rw-r--r--arch/powerpc/mm/hugetlbpage.c2
-rw-r--r--arch/powerpc/mm/mmu_context_hash64.c214
-rw-r--r--arch/powerpc/mm/mmu_context_nohash.c18
-rw-r--r--arch/powerpc/mm/numa.c17
-rw-r--r--arch/powerpc/mm/pgtable.c104
-rw-r--r--arch/powerpc/mm/pgtable_32.c12
-rw-r--r--arch/powerpc/mm/pgtable_64.c15
-rw-r--r--arch/powerpc/mm/slb.c10
-rw-r--r--arch/powerpc/mm/slb_low.S8
-rw-r--r--arch/powerpc/mm/stab.c2
-rw-r--r--arch/powerpc/mm/tlb_hash32.c3
-rw-r--r--arch/powerpc/mm/tlb_hash64.c5
-rw-r--r--arch/powerpc/mm/tlb_nohash.c3
-rw-r--r--arch/powerpc/oprofile/op_model_power4.c24
-rw-r--r--arch/powerpc/platforms/40x/Kconfig2
-rw-r--r--arch/powerpc/platforms/44x/Kconfig6
-rw-r--r--arch/powerpc/platforms/44x/iss4xx.c6
-rw-r--r--arch/powerpc/platforms/512x/mpc5121_ads_cpld.c10
-rw-r--r--arch/powerpc/platforms/52xx/media5200.c4
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_pic.c83
-rw-r--r--arch/powerpc/platforms/82xx/pq2ads-pci-pic.c12
-rw-r--r--arch/powerpc/platforms/85xx/smp.c12
-rw-r--r--arch/powerpc/platforms/85xx/socrates_fpga_pic.c26
-rw-r--r--arch/powerpc/platforms/86xx/gef_pic.c10
-rw-r--r--arch/powerpc/platforms/86xx/mpc8610_hpcd.c99
-rw-r--r--arch/powerpc/platforms/86xx/mpc86xx_smp.c6
-rw-r--r--arch/powerpc/platforms/8xx/m8xx_setup.c2
-rw-r--r--arch/powerpc/platforms/Kconfig31
-rw-r--r--arch/powerpc/platforms/Kconfig.cputype24
-rw-r--r--arch/powerpc/platforms/Makefile1
-rw-r--r--arch/powerpc/platforms/cell/Kconfig4
-rw-r--r--arch/powerpc/platforms/cell/Makefile9
-rw-r--r--arch/powerpc/platforms/cell/axon_msi.c3
-rw-r--r--arch/powerpc/platforms/cell/beat_interrupt.c27
-rw-r--r--arch/powerpc/platforms/cell/beat_interrupt.h3
-rw-r--r--arch/powerpc/platforms/cell/beat_smp.c124
-rw-r--r--arch/powerpc/platforms/cell/cbe_regs.c11
-rw-r--r--arch/powerpc/platforms/cell/celleb_pci.c25
-rw-r--r--arch/powerpc/platforms/cell/celleb_pci.h3
-rw-r--r--arch/powerpc/platforms/cell/celleb_setup.c4
-rw-r--r--arch/powerpc/platforms/cell/interrupt.c43
-rw-r--r--arch/powerpc/platforms/cell/interrupt.h2
-rw-r--r--arch/powerpc/platforms/cell/qpace_setup.c1
-rw-r--r--arch/powerpc/platforms/cell/setup.c4
-rw-r--r--arch/powerpc/platforms/cell/smp.c37
-rw-r--r--arch/powerpc/platforms/cell/spider-pci.c3
-rw-r--r--arch/powerpc/platforms/cell/spider-pic.c21
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c28
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c2
-rw-r--r--arch/powerpc/platforms/chrp/smp.c4
-rw-r--r--arch/powerpc/platforms/embedded6xx/flipper-pic.c15
-rw-r--r--arch/powerpc/platforms/embedded6xx/hlwd-pic.c15
-rw-r--r--arch/powerpc/platforms/iseries/Kconfig4
-rw-r--r--arch/powerpc/platforms/iseries/exception.S62
-rw-r--r--arch/powerpc/platforms/iseries/irq.c13
-rw-r--r--arch/powerpc/platforms/iseries/setup.c9
-rw-r--r--arch/powerpc/platforms/iseries/smp.c45
-rw-r--r--arch/powerpc/platforms/iseries/smp.h6
-rw-r--r--arch/powerpc/platforms/powermac/Kconfig11
-rw-r--r--arch/powerpc/platforms/powermac/pic.c67
-rw-r--r--arch/powerpc/platforms/powermac/pic.h11
-rw-r--r--arch/powerpc/platforms/powermac/pmac.h1
-rw-r--r--arch/powerpc/platforms/powermac/smp.c97
-rw-r--r--arch/powerpc/platforms/ps3/interrupt.c8
-rw-r--r--arch/powerpc/platforms/ps3/smp.c22
-rw-r--r--arch/powerpc/platforms/ps3/spu.c4
-rw-r--r--arch/powerpc/platforms/pseries/Kconfig23
-rw-r--r--arch/powerpc/platforms/pseries/Makefile2
-rw-r--r--arch/powerpc/platforms/pseries/dtl.c20
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c82
-rw-r--r--arch/powerpc/platforms/pseries/eeh_driver.c22
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-cpu.c5
-rw-r--r--arch/powerpc/platforms/pseries/io_event_irq.c231
-rw-r--r--arch/powerpc/platforms/pseries/iommu.c117
-rw-r--r--arch/powerpc/platforms/pseries/kexec.c5
-rw-r--r--arch/powerpc/platforms/pseries/lpar.c48
-rw-r--r--arch/powerpc/platforms/pseries/plpar_wrappers.h27
-rw-r--r--arch/powerpc/platforms/pseries/ras.c6
-rw-r--r--arch/powerpc/platforms/pseries/setup.c50
-rw-r--r--arch/powerpc/platforms/pseries/smp.c24
-rw-r--r--arch/powerpc/platforms/pseries/xics.c949
-rw-r--r--arch/powerpc/platforms/pseries/xics.h23
-rw-r--r--arch/powerpc/platforms/wsp/Kconfig28
-rw-r--r--arch/powerpc/platforms/wsp/Makefile6
-rw-r--r--arch/powerpc/platforms/wsp/ics.c712
-rw-r--r--arch/powerpc/platforms/wsp/ics.h20
-rw-r--r--arch/powerpc/platforms/wsp/opb_pic.c332
-rw-r--r--arch/powerpc/platforms/wsp/psr2.c95
-rw-r--r--arch/powerpc/platforms/wsp/scom_smp.c427
-rw-r--r--arch/powerpc/platforms/wsp/scom_wsp.c77
-rw-r--r--arch/powerpc/platforms/wsp/setup.c36
-rw-r--r--arch/powerpc/platforms/wsp/smp.c88
-rw-r--r--arch/powerpc/platforms/wsp/wsp.h17
-rw-r--r--arch/powerpc/sysdev/Kconfig17
-rw-r--r--arch/powerpc/sysdev/Makefile7
-rw-r--r--arch/powerpc/sysdev/axonram.c2
-rw-r--r--arch/powerpc/sysdev/cpm1.c8
-rw-r--r--arch/powerpc/sysdev/cpm2_pic.c10
-rw-r--r--arch/powerpc/sysdev/fsl_85xx_cache_sram.c4
-rw-r--r--arch/powerpc/sysdev/fsl_lbc.c9
-rw-r--r--arch/powerpc/sysdev/fsl_msi.c10
-rw-r--r--arch/powerpc/sysdev/fsl_rio.c100
-rw-r--r--arch/powerpc/sysdev/i8259.c13
-rw-r--r--arch/powerpc/sysdev/ipic.c52
-rw-r--r--arch/powerpc/sysdev/mmio_nvram.c2
-rw-r--r--arch/powerpc/sysdev/mpc8xx_pic.c10
-rw-r--r--arch/powerpc/sysdev/mpc8xxx_gpio.c12
-rw-r--r--arch/powerpc/sysdev/mpic.c257
-rw-r--r--arch/powerpc/sysdev/mv64x60_pic.c14
-rw-r--r--arch/powerpc/sysdev/ppc4xx_msi.c276
-rw-r--r--arch/powerpc/sysdev/qe_lib/qe_ic.c6
-rw-r--r--arch/powerpc/sysdev/scom.c192
-rw-r--r--arch/powerpc/sysdev/uic.c12
-rw-r--r--arch/powerpc/sysdev/xics/Kconfig13
-rw-r--r--arch/powerpc/sysdev/xics/Makefile6
-rw-r--r--arch/powerpc/sysdev/xics/icp-hv.c164
-rw-r--r--arch/powerpc/sysdev/xics/icp-native.c293
-rw-r--r--arch/powerpc/sysdev/xics/ics-rtas.c240
-rw-r--r--arch/powerpc/sysdev/xics/xics-common.c443
-rw-r--r--arch/powerpc/sysdev/xilinx_intc.c8
-rw-r--r--arch/powerpc/xmon/xmon.c38
-rw-r--r--arch/s390/Kconfig14
-rw-r--r--arch/s390/appldata/appldata_base.c2
-rw-r--r--arch/s390/appldata/appldata_mem.c2
-rw-r--r--arch/s390/crypto/Makefile1
-rw-r--r--arch/s390/crypto/aes_s390.c383
-rw-r--r--arch/s390/crypto/crypt_s390.h112
-rw-r--r--arch/s390/crypto/des_check_key.c132
-rw-r--r--arch/s390/crypto/des_s390.c370
-rw-r--r--arch/s390/crypto/ghash_s390.c162
-rw-r--r--arch/s390/crypto/prng.c2
-rw-r--r--arch/s390/crypto/sha1_s390.c2
-rw-r--r--arch/s390/crypto/sha256_s390.c2
-rw-r--r--arch/s390/crypto/sha512_s390.c2
-rw-r--r--arch/s390/hypfs/hypfs.h2
-rw-r--r--arch/s390/include/asm/bitops.h45
-rw-r--r--arch/s390/include/asm/cacheflush.h1
-rw-r--r--arch/s390/include/asm/cmpxchg.h1
-rw-r--r--arch/s390/include/asm/delay.h8
-rw-r--r--arch/s390/include/asm/elf.h12
-rw-r--r--arch/s390/include/asm/ftrace.h4
-rw-r--r--arch/s390/include/asm/hugetlb.h17
-rw-r--r--arch/s390/include/asm/irq.h9
-rw-r--r--arch/s390/include/asm/jump_label.h37
-rw-r--r--arch/s390/include/asm/lowcore.h4
-rw-r--r--arch/s390/include/asm/mmu.h9
-rw-r--r--arch/s390/include/asm/mmu_context.h6
-rw-r--r--arch/s390/include/asm/page.h60
-rw-r--r--arch/s390/include/asm/percpu.h68
-rw-r--r--arch/s390/include/asm/pgalloc.h57
-rw-r--r--arch/s390/include/asm/pgtable.h607
-rw-r--r--arch/s390/include/asm/processor.h1
-rw-r--r--arch/s390/include/asm/s390_ext.h17
-rw-r--r--arch/s390/include/asm/tlb.h62
-rw-r--r--arch/s390/include/asm/tlbflush.h13
-rw-r--r--arch/s390/include/asm/topology.h4
-rw-r--r--arch/s390/include/asm/uaccess.h11
-rw-r--r--arch/s390/include/asm/unistd.h1
-rw-r--r--arch/s390/kernel/Makefile8
-rw-r--r--arch/s390/kernel/asm-offsets.c4
-rw-r--r--arch/s390/kernel/dis.c2
-rw-r--r--arch/s390/kernel/entry.S1
-rw-r--r--arch/s390/kernel/entry64.S1
-rw-r--r--arch/s390/kernel/irq.c138
-rw-r--r--arch/s390/kernel/jump_label.c59
-rw-r--r--arch/s390/kernel/process.c19
-rw-r--r--arch/s390/kernel/s390_ext.c108
-rw-r--r--arch/s390/kernel/setup.c31
-rw-r--r--arch/s390/kernel/smp.c37
-rw-r--r--arch/s390/kernel/time.c5
-rw-r--r--arch/s390/kernel/topology.c17
-rw-r--r--arch/s390/kernel/traps.c1
-rw-r--r--arch/s390/kernel/vdso32/Makefile3
-rw-r--r--arch/s390/kernel/vdso64/Makefile3
-rw-r--r--arch/s390/kernel/vmlinux.lds.S2
-rw-r--r--arch/s390/kernel/vtime.c2
-rw-r--r--arch/s390/lib/delay.c15
-rw-r--r--arch/s390/mm/extmem.c6
-rw-r--r--arch/s390/mm/fault.c249
-rw-r--r--arch/s390/mm/hugetlbpage.c10
-rw-r--r--arch/s390/mm/init.c5
-rw-r--r--arch/s390/mm/pageattr.c7
-rw-r--r--arch/s390/mm/pgtable.c69
-rw-r--r--arch/s390/mm/vmem.c14
-rw-r--r--arch/s390/oprofile/hwsampler.c25
-rw-r--r--arch/score/Kconfig3
-rw-r--r--arch/score/Kconfig.debug9
-rw-r--r--arch/score/mm/init.c2
-rw-r--r--arch/sh/Kconfig8
-rw-r--r--arch/sh/Kconfig.debug9
-rw-r--r--arch/sh/boards/mach-ecovec24/setup.c18
-rw-r--r--arch/sh/configs/apsh4ad0a_defconfig2
-rw-r--r--arch/sh/configs/ecovec24_defconfig2
-rw-r--r--arch/sh/configs/sdk7786_defconfig2
-rw-r--r--arch/sh/configs/se7206_defconfig1
-rw-r--r--arch/sh/configs/sh7757lcr_defconfig2
-rw-r--r--arch/sh/configs/shx3_defconfig1
-rw-r--r--arch/sh/configs/urquell_defconfig1
-rw-r--r--arch/sh/drivers/pci/fixups-se7751.c2
-rw-r--r--arch/sh/include/asm/kgdb.h1
-rw-r--r--arch/sh/include/asm/ptrace.h6
-rw-r--r--arch/sh/include/asm/stacktrace.h3
-rw-r--r--arch/sh/include/asm/tlb.h28
-rw-r--r--arch/sh/include/asm/unistd_32.h3
-rw-r--r--arch/sh/include/asm/unistd_64.h3
-rw-r--r--arch/sh/kernel/cpu/Makefile4
-rw-r--r--arch/sh/kernel/cpu/sh4/sq.c1
-rw-r--r--arch/sh/kernel/cpu/shmobile/pm_runtime.c39
-rw-r--r--arch/sh/kernel/dumpstack.c15
-rw-r--r--arch/sh/kernel/module.c2
-rw-r--r--arch/sh/kernel/perf_callchain.c12
-rw-r--r--arch/sh/kernel/smp.c2
-rw-r--r--arch/sh/kernel/stacktrace.c13
-rw-r--r--arch/sh/kernel/syscalls_32.S1
-rw-r--r--arch/sh/kernel/syscalls_64.S1
-rw-r--r--arch/sh/kernel/traps_32.c1
-rw-r--r--arch/sh/kernel/vmlinux.lds.S2
-rw-r--r--arch/sh/mm/init.c1
-rw-r--r--arch/sh/oprofile/backtrace.c13
-rw-r--r--arch/sparc/Kconfig15
-rw-r--r--arch/sparc/Kconfig.debug9
-rw-r--r--arch/sparc/include/asm/cpudata_32.h5
-rw-r--r--arch/sparc/include/asm/floppy_32.h40
-rw-r--r--arch/sparc/include/asm/io.h13
-rw-r--r--arch/sparc/include/asm/irq_32.h6
-rw-r--r--arch/sparc/include/asm/jump_label.h25
-rw-r--r--arch/sparc/include/asm/leon.h41
-rw-r--r--arch/sparc/include/asm/pcic.h12
-rw-r--r--arch/sparc/include/asm/pgalloc_64.h3
-rw-r--r--arch/sparc/include/asm/pgtable_32.h6
-rw-r--r--arch/sparc/include/asm/pgtable_64.h18
-rw-r--r--arch/sparc/include/asm/setup.h12
-rw-r--r--arch/sparc/include/asm/smp_32.h37
-rw-r--r--arch/sparc/include/asm/smp_64.h4
-rw-r--r--arch/sparc/include/asm/spinlock_32.h1
-rw-r--r--arch/sparc/include/asm/system_32.h5
-rw-r--r--arch/sparc/include/asm/system_64.h4
-rw-r--r--arch/sparc/include/asm/tlb_64.h91
-rw-r--r--arch/sparc/include/asm/tlbflush_64.h12
-rw-r--r--arch/sparc/include/asm/topology_64.h6
-rw-r--r--arch/sparc/include/asm/unistd.h3
-rw-r--r--arch/sparc/include/asm/winmacro.h9
-rw-r--r--arch/sparc/kernel/Makefile4
-rw-r--r--arch/sparc/kernel/cpu.c139
-rw-r--r--arch/sparc/kernel/cpumap.c4
-rw-r--r--arch/sparc/kernel/devices.c4
-rw-r--r--arch/sparc/kernel/ds.c14
-rw-r--r--arch/sparc/kernel/entry.S41
-rw-r--r--arch/sparc/kernel/head_32.S51
-rw-r--r--arch/sparc/kernel/ioport.c42
-rw-r--r--arch/sparc/kernel/irq.h51
-rw-r--r--arch/sparc/kernel/irq_32.c513
-rw-r--r--arch/sparc/kernel/irq_64.c6
-rw-r--r--arch/sparc/kernel/kernel.h5
-rw-r--r--arch/sparc/kernel/leon_kernel.c365
-rw-r--r--arch/sparc/kernel/leon_smp.c148
-rw-r--r--arch/sparc/kernel/mdesc.c2
-rw-r--r--arch/sparc/kernel/of_device_64.c3
-rw-r--r--arch/sparc/kernel/pci_msi.c3
-rw-r--r--arch/sparc/kernel/pcic.c83
-rw-r--r--arch/sparc/kernel/perf_event.c1
-rw-r--r--arch/sparc/kernel/process_32.c12
-rw-r--r--arch/sparc/kernel/prom_32.c1
-rw-r--r--arch/sparc/kernel/setup_32.c89
-rw-r--r--arch/sparc/kernel/setup_64.c78
-rw-r--r--arch/sparc/kernel/smp_32.c105
-rw-r--r--arch/sparc/kernel/smp_64.c59
-rw-r--r--arch/sparc/kernel/sun4c_irq.c150
-rw-r--r--arch/sparc/kernel/sun4d_irq.c494
-rw-r--r--arch/sparc/kernel/sun4d_smp.c93
-rw-r--r--arch/sparc/kernel/sun4m_irq.c179
-rw-r--r--arch/sparc/kernel/sun4m_smp.c51
-rw-r--r--arch/sparc/kernel/sysfs.c3
-rw-r--r--arch/sparc/kernel/systbls_32.S2
-rw-r--r--arch/sparc/kernel/systbls_64.S4
-rw-r--r--arch/sparc/kernel/time_32.c10
-rw-r--r--arch/sparc/kernel/us2e_cpufreq.c4
-rw-r--r--arch/sparc/kernel/us3_cpufreq.c4
-rw-r--r--arch/sparc/kernel/vmlinux.lds.S2
-rw-r--r--arch/sparc/lib/Makefile1
-rw-r--r--arch/sparc/lib/rwsem_32.S204
-rw-r--r--arch/sparc/mm/init_32.c4
-rw-r--r--arch/sparc/mm/init_64.c14
-rw-r--r--arch/sparc/mm/tlb.c43
-rw-r--r--arch/sparc/mm/tsb.c15
-rw-r--r--arch/tile/Kconfig9
-rw-r--r--arch/tile/Kconfig.debug9
-rw-r--r--arch/tile/configs/tile_defconfig71
-rw-r--r--arch/tile/configs/tilegx_defconfig1833
-rw-r--r--arch/tile/configs/tilepro_defconfig1163
-rw-r--r--arch/tile/include/arch/chip_tilegx.h258
-rw-r--r--arch/tile/include/arch/icache.h11
-rw-r--r--arch/tile/include/arch/interrupts_64.h276
-rw-r--r--arch/tile/include/arch/spr_def.h13
-rw-r--r--arch/tile/include/arch/spr_def_64.h173
-rw-r--r--arch/tile/include/asm/atomic.h49
-rw-r--r--arch/tile/include/asm/atomic_32.h10
-rw-r--r--arch/tile/include/asm/atomic_64.h156
-rw-r--r--arch/tile/include/asm/backtrace.h82
-rw-r--r--arch/tile/include/asm/bitops.h1
-rw-r--r--arch/tile/include/asm/bitops_32.h1
-rw-r--r--arch/tile/include/asm/bitops_64.h105
-rw-r--r--arch/tile/include/asm/cacheflush.h18
-rw-r--r--arch/tile/include/asm/compat.h4
-rw-r--r--arch/tile/include/asm/dma-mapping.h3
-rw-r--r--arch/tile/include/asm/fb.h1
-rw-r--r--arch/tile/include/asm/io.h18
-rw-r--r--arch/tile/include/asm/irq.h2
-rw-r--r--arch/tile/include/asm/mmu_context.h4
-rw-r--r--arch/tile/include/asm/opcode-tile_32.h7
-rw-r--r--arch/tile/include/asm/opcode-tile_64.h1500
-rw-r--r--arch/tile/include/asm/opcode_constants_64.h1043
-rw-r--r--arch/tile/include/asm/page.h18
-rw-r--r--arch/tile/include/asm/parport.h1
-rw-r--r--arch/tile/include/asm/pci.h3
-rw-r--r--arch/tile/include/asm/pgtable_64.h175
-rw-r--r--arch/tile/include/asm/processor.h9
-rw-r--r--arch/tile/include/asm/serial.h1
-rw-r--r--arch/tile/include/asm/signal.h4
-rw-r--r--arch/tile/include/asm/spinlock_64.h161
-rw-r--r--arch/tile/include/asm/stat.h2
-rw-r--r--arch/tile/include/asm/swab.h6
-rw-r--r--arch/tile/include/asm/thread_info.h5
-rw-r--r--arch/tile/include/asm/topology.h75
-rw-r--r--arch/tile/include/asm/traps.h4
-rw-r--r--arch/tile/include/asm/unistd.h2
-rw-r--r--arch/tile/include/asm/vga.h (renamed from arch/tile/include/hv/pagesize.h)35
-rw-r--r--arch/tile/include/hv/hypervisor.h12
-rw-r--r--arch/tile/kernel/backtrace.c103
-rw-r--r--arch/tile/kernel/compat.c13
-rw-r--r--arch/tile/kernel/compat_signal.c4
-rw-r--r--arch/tile/kernel/futex_64.S55
-rw-r--r--arch/tile/kernel/hardwall.c6
-rw-r--r--arch/tile/kernel/head_64.S269
-rw-r--r--arch/tile/kernel/intvec_32.S175
-rw-r--r--arch/tile/kernel/intvec_64.S1231
-rw-r--r--arch/tile/kernel/module.c8
-rw-r--r--arch/tile/kernel/pci-dma.c2
-rw-r--r--arch/tile/kernel/pci.c206
-rw-r--r--arch/tile/kernel/process.c52
-rw-r--r--arch/tile/kernel/regs_64.S145
-rw-r--r--arch/tile/kernel/setup.c6
-rw-r--r--arch/tile/kernel/signal.c128
-rw-r--r--arch/tile/kernel/single_step.c12
-rw-r--r--arch/tile/kernel/smp.c6
-rw-r--r--arch/tile/kernel/stack.c14
-rw-r--r--arch/tile/kernel/sys.c9
-rw-r--r--arch/tile/kernel/tile-desc_32.c11
-rw-r--r--arch/tile/kernel/tile-desc_64.c2200
-rw-r--r--arch/tile/kernel/time.c2
-rw-r--r--arch/tile/kernel/tlb.c12
-rw-r--r--arch/tile/kernel/traps.c1
-rw-r--r--arch/tile/kernel/vmlinux.lds.S2
-rw-r--r--arch/tile/lib/atomic_asm_32.S2
-rw-r--r--arch/tile/lib/cacheflush.c18
-rw-r--r--arch/tile/lib/memchr_64.c71
-rw-r--r--arch/tile/lib/memcpy_64.c220
-rw-r--r--arch/tile/lib/memcpy_user_64.c86
-rw-r--r--arch/tile/lib/memset_64.c145
-rw-r--r--arch/tile/lib/spinlock_64.c104
-rw-r--r--arch/tile/lib/strchr_64.c67
-rw-r--r--arch/tile/lib/strlen_64.c38
-rw-r--r--arch/tile/lib/usercopy_64.S196
-rw-r--r--arch/tile/mm/fault.c30
-rw-r--r--arch/tile/mm/init.c2
-rw-r--r--arch/tile/mm/migrate_64.S187
-rw-r--r--arch/um/Kconfig.debug16
-rw-r--r--arch/um/Kconfig.x865
-rw-r--r--arch/um/drivers/Makefile4
-rw-r--r--arch/um/drivers/mcast.h24
-rw-r--r--arch/um/drivers/mcast_kern.c120
-rw-r--r--arch/um/drivers/mcast_user.c165
-rw-r--r--arch/um/drivers/mmapper_kern.c2
-rw-r--r--arch/um/drivers/umcast.h27
-rw-r--r--arch/um/drivers/umcast_kern.c188
-rw-r--r--arch/um/drivers/umcast_user.c186
-rw-r--r--arch/um/drivers/xterm.c2
-rw-r--r--arch/um/include/asm/common.lds.S2
-rw-r--r--arch/um/include/asm/processor-generic.h2
-rw-r--r--arch/um/include/asm/smp.h1
-rw-r--r--arch/um/include/asm/tlb.h29
-rw-r--r--arch/um/include/shared/os.h7
-rw-r--r--arch/um/kernel/Makefile1
-rw-r--r--arch/um/kernel/early_printk.c33
-rw-r--r--arch/um/kernel/smp.c5
-rw-r--r--arch/um/kernel/trap.c24
-rw-r--r--arch/um/os-Linux/main.c3
-rw-r--r--arch/um/os-Linux/process.c1
-rw-r--r--arch/um/os-Linux/util.c5
-rw-r--r--arch/unicore32/Kconfig.debug7
-rw-r--r--arch/unicore32/kernel/irq.c23
-rw-r--r--arch/unicore32/kernel/traps.c1
-rw-r--r--arch/unicore32/mm/init.c2
-rw-r--r--arch/unicore32/mm/mmu.c2
-rw-r--r--arch/x86/Kbuild1
-rw-r--r--arch/x86/Kconfig66
-rw-r--r--arch/x86/Kconfig.cpu16
-rw-r--r--arch/x86/Kconfig.debug20
-rw-r--r--arch/x86/Makefile_32.cpu2
-rw-r--r--arch/x86/configs/i386_defconfig1
-rw-r--r--arch/x86/configs/x86_64_defconfig1
-rw-r--r--arch/x86/crypto/Makefile4
-rw-r--r--arch/x86/crypto/aesni-intel_glue.c9
-rw-r--r--arch/x86/crypto/fpu.c10
-rw-r--r--arch/x86/ia32/ia32entry.S1
-rw-r--r--arch/x86/include/asm/acpi.h2
-rw-r--r--arch/x86/include/asm/alternative-asm.h9
-rw-r--r--arch/x86/include/asm/alternative.h9
-rw-r--r--arch/x86/include/asm/amd_iommu_proto.h13
-rw-r--r--arch/x86/include/asm/amd_iommu_types.h28
-rw-r--r--arch/x86/include/asm/amd_nb.h1
-rw-r--r--arch/x86/include/asm/apic.h38
-rw-r--r--arch/x86/include/asm/bios_ebda.h28
-rw-r--r--arch/x86/include/asm/cpufeature.h15
-rw-r--r--arch/x86/include/asm/dma.h12
-rw-r--r--arch/x86/include/asm/efi.h1
-rw-r--r--arch/x86/include/asm/ftrace.h7
-rw-r--r--arch/x86/include/asm/i8253.h2
-rw-r--r--arch/x86/include/asm/io.h24
-rw-r--r--arch/x86/include/asm/io_apic.h28
-rw-r--r--arch/x86/include/asm/jump_label.h27
-rw-r--r--arch/x86/include/asm/kgdb.h1
-rw-r--r--arch/x86/include/asm/kvm_emulate.h193
-rw-r--r--arch/x86/include/asm/kvm_host.h55
-rw-r--r--arch/x86/include/asm/linkage.h5
-rw-r--r--arch/x86/include/asm/mce.h2
-rw-r--r--arch/x86/include/asm/mmzone_32.h20
-rw-r--r--arch/x86/include/asm/mmzone_64.h23
-rw-r--r--arch/x86/include/asm/module.h2
-rw-r--r--arch/x86/include/asm/msr-index.h1
-rw-r--r--arch/x86/include/asm/nops.h146
-rw-r--r--arch/x86/include/asm/numa.h32
-rw-r--r--arch/x86/include/asm/numa_32.h10
-rw-r--r--arch/x86/include/asm/numa_64.h36
-rw-r--r--arch/x86/include/asm/numaq.h7
-rw-r--r--arch/x86/include/asm/olpc_ofw.h9
-rw-r--r--arch/x86/include/asm/pci.h2
-rw-r--r--arch/x86/include/asm/percpu.h34
-rw-r--r--arch/x86/include/asm/probe_roms.h8
-rw-r--r--arch/x86/include/asm/processor-flags.h1
-rw-r--r--arch/x86/include/asm/ptrace.h18
-rw-r--r--arch/x86/include/asm/setup.h4
-rw-r--r--arch/x86/include/asm/srat.h39
-rw-r--r--arch/x86/include/asm/stacktrace.h3
-rw-r--r--arch/x86/include/asm/system.h85
-rw-r--r--arch/x86/include/asm/topology.h8
-rw-r--r--arch/x86/include/asm/tsc.h4
-rw-r--r--arch/x86/include/asm/uaccess.h3
-rw-r--r--arch/x86/include/asm/uaccess_32.h1
-rw-r--r--arch/x86/include/asm/uaccess_64.h1
-rw-r--r--arch/x86/include/asm/unistd_32.h3
-rw-r--r--arch/x86/include/asm/unistd_64.h2
-rw-r--r--arch/x86/include/asm/vdso.h14
-rw-r--r--arch/x86/include/asm/vgtod.h2
-rw-r--r--arch/x86/include/asm/vsyscall.h12
-rw-r--r--arch/x86/include/asm/vvar.h52
-rw-r--r--arch/x86/include/asm/x2apic.h62
-rw-r--r--arch/x86/include/asm/xen/hypercall.h7
-rw-r--r--arch/x86/include/asm/xen/page.h5
-rw-r--r--arch/x86/include/asm/xen/pci.h16
-rw-r--r--arch/x86/kernel/Makefile12
-rw-r--r--arch/x86/kernel/acpi/boot.c8
-rw-r--r--arch/x86/kernel/acpi/sleep.c5
-rw-r--r--arch/x86/kernel/alternative.c203
-rw-r--r--arch/x86/kernel/amd_gart_64.c (renamed from arch/x86/kernel/pci-gart_64.c)0
-rw-r--r--arch/x86/kernel/amd_iommu.c527
-rw-r--r--arch/x86/kernel/amd_iommu_init.c48
-rw-r--r--arch/x86/kernel/apb_timer.c10
-rw-r--r--arch/x86/kernel/aperture_64.c34
-rw-r--r--arch/x86/kernel/apic/Makefile17
-rw-r--r--arch/x86/kernel/apic/apic.c117
-rw-r--r--arch/x86/kernel/apic/apic_flat_64.c26
-rw-r--r--arch/x86/kernel/apic/apic_noop.c9
-rw-r--r--arch/x86/kernel/apic/bigsmp_32.c13
-rw-r--r--arch/x86/kernel/apic/es7000_32.c17
-rw-r--r--arch/x86/kernel/apic/hw_nmi.c4
-rw-r--r--arch/x86/kernel/apic/io_apic.c309
-rw-r--r--arch/x86/kernel/apic/numaq_32.c40
-rw-r--r--arch/x86/kernel/apic/probe_32.c118
-rw-r--r--arch/x86/kernel/apic/probe_64.c61
-rw-r--r--arch/x86/kernel/apic/summit_32.c5
-rw-r--r--arch/x86/kernel/apic/x2apic_cluster.c222
-rw-r--r--arch/x86/kernel/apic/x2apic_phys.c115
-rw-r--r--arch/x86/kernel/apic/x2apic_uv_x.c13
-rw-r--r--arch/x86/kernel/apm_32.c4
-rw-r--r--arch/x86/kernel/cpu/Makefile1
-rw-r--r--arch/x86/kernel/cpu/amd.c9
-rw-r--r--arch/x86/kernel/cpu/common.c26
-rw-r--r--arch/x86/kernel/cpu/cpufreq/Makefile21
-rw-r--r--arch/x86/kernel/cpu/intel.c29
-rw-r--r--arch/x86/kernel/cpu/intel_cacheinfo.c20
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce.c25
-rw-r--r--arch/x86/kernel/cpu/mcheck/therm_throt.c10
-rw-r--r--arch/x86/kernel/cpu/perf_event.c28
-rw-r--r--arch/x86/kernel/cpu/perf_event_amd.c14
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel.c37
-rw-r--r--arch/x86/kernel/cpu/perf_event_p4.c7
-rw-r--r--arch/x86/kernel/devicetree.c6
-rw-r--r--arch/x86/kernel/dumpstack.c17
-rw-r--r--arch/x86/kernel/ftrace.c4
-rw-r--r--arch/x86/kernel/head32.c1
-rw-r--r--arch/x86/kernel/hpet.c72
-rw-r--r--arch/x86/kernel/i8253.c86
-rw-r--r--arch/x86/kernel/irq.c5
-rw-r--r--arch/x86/kernel/jump_label.c5
-rw-r--r--arch/x86/kernel/kvmclock.c6
-rw-r--r--arch/x86/kernel/module.c1
-rw-r--r--arch/x86/kernel/mpparse.c8
-rw-r--r--arch/x86/kernel/pci-dma.c64
-rw-r--r--arch/x86/kernel/pci-iommu_table.c18
-rw-r--r--arch/x86/kernel/probe_roms.c (renamed from arch/x86/kernel/probe_roms_32.c)101
-rw-r--r--arch/x86/kernel/process.c4
-rw-r--r--arch/x86/kernel/ptrace.c4
-rw-r--r--arch/x86/kernel/reboot.c24
-rw-r--r--arch/x86/kernel/setup.c9
-rw-r--r--arch/x86/kernel/signal.c14
-rw-r--r--arch/x86/kernel/smp.c5
-rw-r--r--arch/x86/kernel/smpboot.c4
-rw-r--r--arch/x86/kernel/stacktrace.c13
-rw-r--r--arch/x86/kernel/syscall_table_32.S1
-rw-r--r--arch/x86/kernel/tboot.c1
-rw-r--r--arch/x86/kernel/test_nx.c2
-rw-r--r--arch/x86/kernel/time.c2
-rw-r--r--arch/x86/kernel/tsc.c19
-rw-r--r--arch/x86/kernel/vmlinux.lds.S43
-rw-r--r--arch/x86/kernel/vread_tsc_64.c36
-rw-r--r--arch/x86/kernel/vsyscall_64.c48
-rw-r--r--arch/x86/kernel/x86_init.c2
-rw-r--r--arch/x86/kvm/emulate.c1754
-rw-r--r--arch/x86/kvm/i8254.h2
-rw-r--r--arch/x86/kvm/irq.h2
-rw-r--r--arch/x86/kvm/mmu.c19
-rw-r--r--arch/x86/kvm/paging_tmpl.h83
-rw-r--r--arch/x86/kvm/svm.c585
-rw-r--r--arch/x86/kvm/vmx.c228
-rw-r--r--arch/x86/kvm/x86.c570
-rw-r--r--arch/x86/kvm/x86.h2
-rw-r--r--arch/x86/lguest/boot.c4
-rw-r--r--arch/x86/lib/clear_page_64.S33
-rw-r--r--arch/x86/lib/copy_user_64.S69
-rw-r--r--arch/x86/lib/memcpy_64.S47
-rw-r--r--arch/x86/lib/memmove_64.S29
-rw-r--r--arch/x86/lib/memset_64.S54
-rw-r--r--arch/x86/mm/Makefile4
-rw-r--r--arch/x86/mm/amdtopology.c (renamed from arch/x86/mm/amdtopology_64.c)21
-rw-r--r--arch/x86/mm/fault.c13
-rw-r--r--arch/x86/mm/hugetlbpage.c4
-rw-r--r--arch/x86/mm/init.c2
-rw-r--r--arch/x86/mm/init_32.c3
-rw-r--r--arch/x86/mm/init_64.c10
-rw-r--r--arch/x86/mm/ioremap.c14
-rw-r--r--arch/x86/mm/numa.c550
-rw-r--r--arch/x86/mm/numa_32.c398
-rw-r--r--arch/x86/mm/numa_64.c644
-rw-r--r--arch/x86/mm/numa_emulation.c16
-rw-r--r--arch/x86/mm/numa_internal.h8
-rw-r--r--arch/x86/mm/pf_in.c14
-rw-r--r--arch/x86/mm/srat.c (renamed from arch/x86/mm/srat_64.c)82
-rw-r--r--arch/x86/mm/srat_32.c288
-rw-r--r--arch/x86/net/Makefile4
-rw-r--r--arch/x86/net/bpf_jit.S140
-rw-r--r--arch/x86/net/bpf_jit_comp.c654
-rw-r--r--arch/x86/oprofile/backtrace.c13
-rw-r--r--arch/x86/pci/direct.c17
-rw-r--r--arch/x86/pci/irq.c4
-rw-r--r--arch/x86/pci/mmconfig-shared.c10
-rw-r--r--arch/x86/pci/xen.c96
-rw-r--r--arch/x86/platform/efi/efi.c78
-rw-r--r--arch/x86/platform/efi/efi_64.c34
-rw-r--r--arch/x86/platform/mrst/mrst.c4
-rw-r--r--arch/x86/platform/olpc/Makefile4
-rw-r--r--arch/x86/platform/olpc/olpc.c51
-rw-r--r--arch/x86/platform/olpc/olpc_dt.c19
-rw-r--r--arch/x86/platform/uv/uv_time.c6
-rw-r--r--arch/x86/vdso/Makefile17
-rw-r--r--arch/x86/vdso/vclock_gettime.c74
-rw-r--r--arch/x86/vdso/vdso.lds.S9
-rw-r--r--arch/x86/vdso/vextern.h16
-rw-r--r--arch/x86/vdso/vgetcpu.c3
-rw-r--r--arch/x86/vdso/vma.c27
-rw-r--r--arch/x86/vdso/vvar.c12
-rw-r--r--arch/x86/xen/enlighten.c20
-rw-r--r--arch/x86/xen/irq.c2
-rw-r--r--arch/x86/xen/mmu.c320
-rw-r--r--arch/x86/xen/mmu.h37
-rw-r--r--arch/x86/xen/p2m.c43
-rw-r--r--arch/x86/xen/pci-swiotlb-xen.c2
-rw-r--r--arch/x86/xen/setup.c10
-rw-r--r--arch/x86/xen/smp.c13
-rw-r--r--arch/x86/xen/time.c14
-rw-r--r--arch/x86/xen/xen-ops.h2
-rw-r--r--arch/xtensa/Kconfig6
-rw-r--r--arch/xtensa/configs/s6105_defconfig1
-rw-r--r--arch/xtensa/include/asm/page.h4
-rw-r--r--arch/xtensa/kernel/vmlinux.lds.S2
-rw-r--r--arch/xtensa/mm/mmu.c2
-rw-r--r--arch/xtensa/mm/pgtable.c72
-rw-r--r--block/blk-cgroup.c218
-rw-r--r--block/blk-cgroup.h40
-rw-r--r--block/blk-core.c37
-rw-r--r--block/blk-exec.c2
-rw-r--r--block/blk-flush.c16
-rw-r--r--block/blk-ioc.c3
-rw-r--r--block/blk-lib.c82
-rw-r--r--block/blk-settings.c9
-rw-r--r--block/blk-sysfs.c3
-rw-r--r--block/blk-throttle.c313
-rw-r--r--block/blk.h23
-rw-r--r--block/cfq-iosched.c232
-rw-r--r--block/elevator.c11
-rw-r--r--block/genhd.c2
-rw-r--r--crypto/Kconfig6
-rw-r--r--crypto/tcrypt.c4
-rw-r--r--crypto/testmgr.c16
-rw-r--r--crypto/testmgr.h60
-rw-r--r--drivers/Kconfig7
-rw-r--r--drivers/Makefile9
-rw-r--r--drivers/acpi/Kconfig11
-rw-r--r--drivers/acpi/Makefile1
-rw-r--r--drivers/acpi/acpica/utresrc.c2
-rw-r--r--drivers/acpi/apei/Kconfig1
-rw-r--r--drivers/acpi/apei/einj.c8
-rw-r--r--drivers/acpi/apei/erst.c61
-rw-r--r--drivers/acpi/atomicio.c4
-rw-r--r--drivers/acpi/pci_root.c14
-rw-r--r--drivers/acpi/processor_perflib.c6
-rw-r--r--drivers/acpi/processor_throttling.c32
-rw-r--r--drivers/acpi/video.c2
-rw-r--r--drivers/ata/acard-ahci.c2
-rw-r--r--drivers/ata/libata-core.c10
-rw-r--r--drivers/ata/libata-eh.c2
-rw-r--r--drivers/ata/libata-pmp.c10
-rw-r--r--drivers/ata/libata-scsi.c15
-rw-r--r--drivers/ata/libata-sff.c9
-rw-r--r--drivers/ata/pata_at91.c297
-rw-r--r--drivers/ata/pata_cmd64x.c42
-rw-r--r--drivers/ata/pata_pcmcia.c2
-rw-r--r--drivers/ata/pata_triflex.c23
-rw-r--r--drivers/atm/eni.c5
-rw-r--r--drivers/atm/he.c4
-rw-r--r--drivers/atm/idt77252.c52
-rw-r--r--drivers/atm/iphase.c14
-rw-r--r--drivers/atm/solos-pci.c3
-rw-r--r--drivers/base/Kconfig7
-rw-r--r--drivers/base/base.h2
-rw-r--r--drivers/base/core.c7
-rw-r--r--drivers/base/dd.c18
-rw-r--r--drivers/base/firmware_class.c5
-rw-r--r--drivers/base/memory.c38
-rw-r--r--drivers/base/node.c14
-rw-r--r--drivers/base/platform.c176
-rw-r--r--drivers/base/power/Makefile4
-rw-r--r--drivers/base/power/clock_ops.c431
-rw-r--r--drivers/base/power/generic_ops.c39
-rw-r--r--drivers/base/power/main.c82
-rw-r--r--drivers/base/power/runtime.c29
-rw-r--r--drivers/base/power/sysfs.c4
-rw-r--r--drivers/base/power/wakeup.c1
-rw-r--r--drivers/base/sys.c202
-rw-r--r--drivers/bcma/Kconfig33
-rw-r--r--drivers/bcma/Makefile7
-rw-r--r--drivers/bcma/README19
-rw-r--r--drivers/bcma/TODO3
-rw-r--r--drivers/bcma/bcma_private.h28
-rw-r--r--drivers/bcma/core.c51
-rw-r--r--drivers/bcma/driver_chipcommon.c89
-rw-r--r--drivers/bcma/driver_chipcommon_pmu.c134
-rw-r--r--drivers/bcma/driver_pci.c163
-rw-r--r--drivers/bcma/host_pci.c198
-rw-r--r--drivers/bcma/main.c247
-rw-r--r--drivers/bcma/scan.c360
-rw-r--r--drivers/bcma/scan.h56
-rw-r--r--drivers/block/Kconfig21
-rw-r--r--drivers/block/Makefile1
-rw-r--r--drivers/block/brd.c42
-rw-r--r--drivers/block/cciss.c571
-rw-r--r--drivers/block/cciss.h11
-rw-r--r--drivers/block/cciss_cmd.h11
-rw-r--r--drivers/block/cciss_scsi.c41
-rw-r--r--drivers/block/cciss_scsi.h4
-rw-r--r--drivers/block/drbd/drbd_actlog.c2
-rw-r--r--drivers/block/drbd/drbd_bitmap.c6
-rw-r--r--drivers/block/drbd/drbd_int.h20
-rw-r--r--drivers/block/drbd/drbd_main.c37
-rw-r--r--drivers/block/drbd/drbd_nl.c127
-rw-r--r--drivers/block/drbd/drbd_receiver.c68
-rw-r--r--drivers/block/drbd/drbd_req.c20
-rw-r--r--drivers/block/drbd/drbd_req.h5
-rw-r--r--drivers/block/drbd/drbd_worker.c98
-rw-r--r--drivers/block/loop.c28
-rw-r--r--drivers/block/paride/pcd.c2
-rw-r--r--drivers/block/rbd.c27
-rw-r--r--drivers/block/xen-blkback/Makefile3
-rw-r--r--drivers/block/xen-blkback/blkback.c824
-rw-r--r--drivers/block/xen-blkback/common.h233
-rw-r--r--drivers/block/xen-blkback/xenbus.c768
-rw-r--r--drivers/block/xen-blkfront.c51
-rw-r--r--drivers/bluetooth/Kconfig4
-rw-r--r--drivers/bluetooth/ath3k.c4
-rw-r--r--drivers/bluetooth/bluecard_cs.c2
-rw-r--r--drivers/bluetooth/bt3c_cs.c2
-rw-r--r--drivers/bluetooth/btmrvl_sdio.c124
-rw-r--r--drivers/bluetooth/btmrvl_sdio.h68
-rw-r--r--drivers/bluetooth/btuart_cs.c2
-rw-r--r--drivers/bluetooth/btusb.c1
-rw-r--r--drivers/bluetooth/dtl1_cs.c2
-rw-r--r--drivers/bluetooth/hci_ath.c7
-rw-r--r--drivers/bluetooth/hci_h4.c7
-rw-r--r--drivers/bluetooth/hci_ldisc.c17
-rw-r--r--drivers/cdrom/viocd.c4
-rw-r--r--drivers/char/Kconfig2
-rw-r--r--drivers/char/agp/intel-agp.c3
-rw-r--r--drivers/char/agp/intel-agp.h8
-rw-r--r--drivers/char/agp/intel-gtt.c10
-rw-r--r--drivers/char/agp/uninorth-agp.c2
-rw-r--r--drivers/char/apm-emulation.c5
-rw-r--r--drivers/char/bsr.c2
-rw-r--r--drivers/char/hpet.c6
-rw-r--r--drivers/char/hw_random/Kconfig2
-rw-r--r--drivers/char/hw_random/amd-rng.c9
-rw-r--r--drivers/char/i8k.c166
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c138
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c88
-rw-r--r--drivers/char/mem.c42
-rw-r--r--drivers/char/mspec.c5
-rw-r--r--drivers/char/pcmcia/cm4000_cs.c2
-rw-r--r--drivers/char/pcmcia/cm4040_cs.c2
-rw-r--r--drivers/char/pcmcia/synclink_cs.c2
-rw-r--r--drivers/char/ppdev.c1
-rw-r--r--drivers/char/raw.c34
-rw-r--r--drivers/clocksource/Kconfig5
-rw-r--r--drivers/clocksource/Makefile2
-rw-r--r--drivers/clocksource/cyclone.c10
-rw-r--r--drivers/clocksource/i8253.c88
-rw-r--r--drivers/clocksource/mmio.c73
-rw-r--r--drivers/clocksource/sh_cmt.c31
-rw-r--r--drivers/clocksource/sh_tmu.c31
-rw-r--r--drivers/cpufreq/Kconfig23
-rw-r--r--drivers/cpufreq/Kconfig.x86 (renamed from arch/x86/kernel/cpu/cpufreq/Kconfig)17
-rw-r--r--drivers/cpufreq/Makefile28
-rw-r--r--drivers/cpufreq/acpi-cpufreq.c (renamed from arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c)45
-rw-r--r--drivers/cpufreq/cpufreq-nforce2.c (renamed from arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c)6
-rw-r--r--drivers/cpufreq/cpufreq.c215
-rw-r--r--drivers/cpufreq/cpufreq_performance.c5
-rw-r--r--drivers/cpufreq/cpufreq_powersave.c5
-rw-r--r--drivers/cpufreq/cpufreq_stats.c24
-rw-r--r--drivers/cpufreq/cpufreq_userspace.c13
-rw-r--r--drivers/cpufreq/db8500-cpufreq.c169
-rw-r--r--drivers/cpufreq/e_powersaver.c (renamed from arch/x86/kernel/cpu/cpufreq/e_powersaver.c)0
-rw-r--r--drivers/cpufreq/elanfreq.c (renamed from arch/x86/kernel/cpu/cpufreq/elanfreq.c)0
-rw-r--r--drivers/cpufreq/freq_table.c19
-rw-r--r--drivers/cpufreq/gx-suspmod.c (renamed from arch/x86/kernel/cpu/cpufreq/gx-suspmod.c)21
-rw-r--r--drivers/cpufreq/longhaul.c (renamed from arch/x86/kernel/cpu/cpufreq/longhaul.c)11
-rw-r--r--drivers/cpufreq/longhaul.h (renamed from arch/x86/kernel/cpu/cpufreq/longhaul.h)0
-rw-r--r--drivers/cpufreq/longrun.c (renamed from arch/x86/kernel/cpu/cpufreq/longrun.c)17
-rw-r--r--drivers/cpufreq/mperf.c (renamed from arch/x86/kernel/cpu/cpufreq/mperf.c)0
-rw-r--r--drivers/cpufreq/mperf.h (renamed from arch/x86/kernel/cpu/cpufreq/mperf.h)0
-rw-r--r--drivers/cpufreq/p4-clockmod.c (renamed from arch/x86/kernel/cpu/cpufreq/p4-clockmod.c)10
-rw-r--r--drivers/cpufreq/pcc-cpufreq.c (renamed from arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c)51
-rw-r--r--drivers/cpufreq/powernow-k6.c (renamed from arch/x86/kernel/cpu/cpufreq/powernow-k6.c)0
-rw-r--r--drivers/cpufreq/powernow-k7.c (renamed from arch/x86/kernel/cpu/cpufreq/powernow-k7.c)33
-rw-r--r--drivers/cpufreq/powernow-k7.h (renamed from arch/x86/kernel/cpu/cpufreq/powernow-k7.h)0
-rw-r--r--drivers/cpufreq/powernow-k8.c (renamed from arch/x86/kernel/cpu/cpufreq/powernow-k8.c)100
-rw-r--r--drivers/cpufreq/powernow-k8.h (renamed from arch/x86/kernel/cpu/cpufreq/powernow-k8.h)2
-rw-r--r--drivers/cpufreq/sc520_freq.c (renamed from arch/x86/kernel/cpu/cpufreq/sc520_freq.c)6
-rw-r--r--drivers/cpufreq/speedstep-centrino.c (renamed from arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c)23
-rw-r--r--drivers/cpufreq/speedstep-ich.c (renamed from arch/x86/kernel/cpu/cpufreq/speedstep-ich.c)28
-rw-r--r--drivers/cpufreq/speedstep-lib.c (renamed from arch/x86/kernel/cpu/cpufreq/speedstep-lib.c)43
-rw-r--r--drivers/cpufreq/speedstep-lib.h (renamed from arch/x86/kernel/cpu/cpufreq/speedstep-lib.h)0
-rw-r--r--drivers/cpufreq/speedstep-smi.c (renamed from arch/x86/kernel/cpu/cpufreq/speedstep-smi.c)41
-rw-r--r--drivers/crypto/Kconfig67
-rw-r--r--drivers/crypto/Makefile2
-rw-r--r--drivers/crypto/caam/Kconfig72
-rw-r--r--drivers/crypto/caam/Makefile8
-rw-r--r--drivers/crypto/caam/caamalg.c1268
-rw-r--r--drivers/crypto/caam/compat.h35
-rw-r--r--drivers/crypto/caam/ctrl.c269
-rw-r--r--drivers/crypto/caam/desc.h1605
-rw-r--r--drivers/crypto/caam/desc_constr.h205
-rw-r--r--drivers/crypto/caam/error.c248
-rw-r--r--drivers/crypto/caam/error.h11
-rw-r--r--drivers/crypto/caam/intern.h113
-rw-r--r--drivers/crypto/caam/jr.c517
-rw-r--r--drivers/crypto/caam/jr.h21
-rw-r--r--drivers/crypto/caam/regs.h663
-rw-r--r--drivers/crypto/mv_cesa.c97
-rw-r--r--drivers/crypto/omap-sham.c78
-rw-r--r--drivers/crypto/padlock-sha.c269
-rw-r--r--drivers/crypto/picoxcell_crypto.c64
-rw-r--r--drivers/crypto/s5p-sss.c701
-rw-r--r--drivers/dma/dmatest.c6
-rw-r--r--drivers/dma/dw_dmac.c2
-rw-r--r--drivers/dma/ioat/dma.c1
-rw-r--r--drivers/dma/ioat/dma_v2.c1
-rw-r--r--drivers/dma/ioat/dma_v3.c1
-rw-r--r--drivers/dma/shdma.c230
-rw-r--r--drivers/dma/shdma.h3
-rw-r--r--drivers/dma/timb_dma.c3
-rw-r--r--drivers/edac/amd76x_edac.c2
-rw-r--r--drivers/edac/amd8111_edac.c2
-rw-r--r--drivers/edac/amd8131_edac.c2
-rw-r--r--drivers/edac/cpc925_edac.c2
-rw-r--r--drivers/edac/e752x_edac.c2
-rw-r--r--drivers/edac/e7xxx_edac.c2
-rw-r--r--drivers/edac/edac_core.h12
-rw-r--r--drivers/edac/edac_device.c24
-rw-r--r--drivers/edac/edac_mc.c16
-rw-r--r--drivers/edac/edac_module.c2
-rw-r--r--drivers/edac/edac_pci.c21
-rw-r--r--drivers/edac/i3200_edac.c13
-rw-r--r--drivers/edac/i5000_edac.c2
-rw-r--r--drivers/edac/i5400_edac.c2
-rw-r--r--drivers/edac/i7300_edac.c2
-rw-r--r--drivers/edac/i7core_edac.c2
-rw-r--r--drivers/edac/i82860_edac.c2
-rw-r--r--drivers/edac/i82875p_edac.c2
-rw-r--r--drivers/edac/i82975x_edac.c2
-rw-r--r--drivers/edac/mpc85xx_edac.h2
-rw-r--r--drivers/edac/mv64x60_edac.h2
-rw-r--r--drivers/edac/ppc4xx_edac.c2
-rw-r--r--drivers/edac/r82600_edac.c2
-rw-r--r--drivers/firewire/core-card.c27
-rw-r--r--drivers/firewire/core-cdev.c7
-rw-r--r--drivers/firewire/core-device.c31
-rw-r--r--drivers/firewire/core-iso.c27
-rw-r--r--drivers/firewire/core-transaction.c19
-rw-r--r--drivers/firewire/core.h2
-rw-r--r--drivers/firewire/net.c4
-rw-r--r--drivers/firewire/ohci.c64
-rw-r--r--drivers/firewire/sbp2.c37
-rw-r--r--drivers/firmware/Kconfig2
-rw-r--r--drivers/firmware/Makefile2
-rw-r--r--drivers/firmware/edd.c22
-rw-r--r--drivers/firmware/efivars.c23
-rw-r--r--drivers/firmware/google/Kconfig31
-rw-r--r--drivers/firmware/google/Makefile3
-rw-r--r--drivers/firmware/google/gsmi.c940
-rw-r--r--drivers/firmware/google/memconsole.c166
-rw-r--r--drivers/firmware/iscsi_ibft.c4
-rw-r--r--drivers/firmware/iscsi_ibft_find.c51
-rw-r--r--drivers/gpio/Kconfig30
-rw-r--r--drivers/gpio/Makefile8
-rw-r--r--drivers/gpio/ab8500-gpio.c7
-rw-r--r--drivers/gpio/basic_mmio_gpio.c517
-rw-r--r--drivers/gpio/gpiolib.c19
-rw-r--r--drivers/gpio/janz-ttl.c3
-rw-r--r--drivers/gpio/langwell_gpio.c2
-rw-r--r--drivers/gpio/ml_ioh_gpio.c3
-rw-r--r--drivers/gpio/pca953x.c2
-rw-r--r--drivers/gpio/rdc321x-gpio.c3
-rw-r--r--drivers/gpio/timbgpio.c6
-rw-r--r--drivers/gpio/tps65910-gpio.c100
-rw-r--r--drivers/gpio/vx855_gpio.c1
-rw-r--r--drivers/gpu/drm/drm_edid.c61
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c207
-rw-r--r--drivers/gpu/drm/drm_irq.c9
-rw-r--r--drivers/gpu/drm/drm_modes.c156
-rw-r--r--drivers/gpu/drm/drm_stub.c21
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c131
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c60
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c68
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h113
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c45
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c35
-rw-r--r--drivers/gpu/drm/i915/i915_gem_tiling.c2
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c311
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h35
-rw-r--r--drivers/gpu/drm/i915/i915_suspend.c3
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c6
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c24
-rw-r--r--drivers/gpu/drm/i915/intel_display.c2303
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h19
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.c88
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.h35
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c10
-rw-r--r--drivers/gpu/drm/i915/intel_tv.c13
-rw-r--r--drivers/gpu/drm/nouveau/Kconfig2
-rw-r--r--drivers/gpu/drm/nouveau/Makefile2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_acpi.c108
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.c7
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.h1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_channel.c20
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c8
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.c25
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h208
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_grctx.h10
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mem.c66
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_object.c118
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_perf.c92
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_pm.c21
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_reg.h14
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c212
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_vm.h3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_volt.c10
-rw-r--r--drivers/gpu/drm/nouveau/nv04_crtc.c9
-rw-r--r--drivers/gpu/drm/nouveau/nv04_graph.c383
-rw-r--r--drivers/gpu/drm/nouveau/nv04_instmem.c3
-rw-r--r--drivers/gpu/drm/nouveau/nv10_graph.c212
-rw-r--r--drivers/gpu/drm/nouveau/nv20_graph.c510
-rw-r--r--drivers/gpu/drm/nouveau/nv40_fifo.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv40_graph.c323
-rw-r--r--drivers/gpu/drm/nouveau/nv40_mpeg.c311
-rw-r--r--drivers/gpu/drm/nouveau/nv50_calc.c68
-rw-r--r--drivers/gpu/drm/nouveau/nv50_crtc.c13
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c18
-rw-r--r--drivers/gpu/drm/nouveau/nv50_graph.c442
-rw-r--r--drivers/gpu/drm/nouveau/nv50_grctx.c10
-rw-r--r--drivers/gpu/drm/nouveau/nv50_mpeg.c256
-rw-r--r--drivers/gpu/drm/nouveau/nv50_pm.c15
-rw-r--r--drivers/gpu/drm/nouveau/nv50_vm.c12
-rw-r--r--drivers/gpu/drm/nouveau/nv84_crypt.c135
-rw-r--r--drivers/gpu/drm/nouveau/nva3_copy.c226
-rw-r--r--drivers/gpu/drm/nouveau/nva3_copy.fuc870
-rw-r--r--drivers/gpu/drm/nouveau/nva3_copy.fuc.h534
-rw-r--r--drivers/gpu/drm/nouveau/nva3_pm.c169
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_copy.c243
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_copy.fuc.h527
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_fifo.c142
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_graph.c600
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_graph.h29
-rw-r--r--drivers/gpu/drm/nouveau/nvc0_grctx.c20
-rw-r--r--drivers/gpu/drm/radeon/atom.c4
-rw-r--r--drivers/gpu/drm/radeon/atombios.h22
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c132
-rw-r--r--drivers/gpu/drm/radeon/atombios_dp.c1046
-rw-r--r--drivers/gpu/drm/radeon/evergreen.c14
-rw-r--r--drivers/gpu/drm/radeon/evergreend.h2
-rw-r--r--drivers/gpu/drm/radeon/ni.c8
-rw-r--r--drivers/gpu/drm/radeon/nid.h4
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_combios.c117
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c607
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c3
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c10
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c3
-rw-r--r--drivers/gpu/drm/radeon/radeon_encoders.c252
-rw-r--r--drivers/gpu/drm/radeon/radeon_fence.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_i2c.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h19
-rw-r--r--drivers/gpu/drm/radeon/radeon_ring.c2
-rw-r--r--drivers/gpu/drm/ttm/ttm_object.c2
-rw-r--r--drivers/gpu/drm/ttm/ttm_page_alloc.c4
-rw-r--r--drivers/gpu/vga/vga_switcheroo.c6
-rw-r--r--drivers/gpu/vga/vgaarb.c113
-rw-r--r--drivers/hid/Kconfig42
-rw-r--r--drivers/hid/Makefile4
-rw-r--r--drivers/hid/hid-3m-pct.c305
-rw-r--r--drivers/hid/hid-cando.c276
-rw-r--r--drivers/hid/hid-core.c35
-rw-r--r--drivers/hid/hid-ids.h53
-rw-r--r--drivers/hid/hid-input.c60
-rw-r--r--drivers/hid/hid-lg.c2
-rw-r--r--drivers/hid/hid-lgff.c3
-rw-r--r--drivers/hid/hid-magicmouse.c10
-rw-r--r--drivers/hid/hid-mosart.c296
-rw-r--r--drivers/hid/hid-multitouch.c264
-rw-r--r--drivers/hid/hid-picolcd.c4
-rw-r--r--drivers/hid/hid-roccat-koneplus.c82
-rw-r--r--drivers/hid/hid-roccat-koneplus.h11
-rw-r--r--drivers/hid/hid-sony.c2
-rw-r--r--drivers/hid/hid-stantum.c286
-rw-r--r--drivers/hid/hidraw.c30
-rw-r--r--drivers/hid/usbhid/hid-quirks.c2
-rw-r--r--drivers/hid/usbhid/hiddev.c34
-rw-r--r--drivers/hwmon/Kconfig108
-rw-r--r--drivers/hwmon/Makefile9
-rw-r--r--drivers/hwmon/abituguru.c3
-rw-r--r--drivers/hwmon/abituguru3.c13
-rw-r--r--drivers/hwmon/acpi_power_meter.c (renamed from drivers/acpi/power_meter.c)0
-rw-r--r--drivers/hwmon/adcxx.c16
-rw-r--r--drivers/hwmon/adm1275.c121
-rw-r--r--drivers/hwmon/coretemp.c742
-rw-r--r--drivers/hwmon/emc6w201.c539
-rw-r--r--drivers/hwmon/f71882fg.c115
-rw-r--r--drivers/hwmon/fam15h_power.c229
-rw-r--r--drivers/hwmon/ibmaem.c10
-rw-r--r--drivers/hwmon/it87.c31
-rw-r--r--drivers/hwmon/jc42.c2
-rw-r--r--drivers/hwmon/k10temp.c11
-rw-r--r--drivers/hwmon/k8temp.c8
-rw-r--r--drivers/hwmon/lm70.c10
-rw-r--r--drivers/hwmon/max16065.c717
-rw-r--r--drivers/hwmon/max34440.c6
-rw-r--r--drivers/hwmon/max6642.c356
-rw-r--r--drivers/hwmon/max6650.c78
-rw-r--r--drivers/hwmon/max8688.c4
-rw-r--r--drivers/hwmon/pkgtemp.c444
-rw-r--r--drivers/hwmon/pmbus.h10
-rw-r--r--drivers/hwmon/pmbus_core.c971
-rw-r--r--drivers/hwmon/sch5627.c46
-rw-r--r--drivers/hwmon/sht15.c747
-rw-r--r--drivers/hwmon/ucd9000.c278
-rw-r--r--drivers/hwmon/ucd9200.c210
-rw-r--r--drivers/hwmon/ultra45_env.c4
-rw-r--r--drivers/i2c/busses/Kconfig12
-rw-r--r--drivers/i2c/busses/i2c-eg20t.c2
-rw-r--r--drivers/i2c/busses/i2c-gpio.c2
-rw-r--r--drivers/i2c/busses/i2c-i801.c60
-rw-r--r--drivers/i2c/busses/i2c-nomadik.c276
-rw-r--r--drivers/i2c/busses/i2c-ocores.c3
-rw-r--r--drivers/i2c/busses/i2c-parport-light.c10
-rw-r--r--drivers/i2c/busses/i2c-parport.c30
-rw-r--r--drivers/i2c/busses/i2c-parport.h74
-rw-r--r--drivers/i2c/busses/i2c-sh_mobile.c20
-rw-r--r--drivers/i2c/busses/i2c-tegra.c39
-rw-r--r--drivers/i2c/busses/i2c-xiic.c3
-rw-r--r--drivers/ide/ide-acpi.c4
-rw-r--r--drivers/ide/ide-cd.c3
-rw-r--r--drivers/ide/ide-cs.c2
-rw-r--r--drivers/ide/ide-floppy.c2
-rw-r--r--drivers/ide/ide-scan-pci.c2
-rw-r--r--drivers/ide/pmac.c4
-rw-r--r--drivers/ieee802154/fakehard.c10
-rw-r--r--drivers/infiniband/Kconfig1
-rw-r--r--drivers/infiniband/core/Makefile2
-rw-r--r--drivers/infiniband/core/addr.c9
-rw-r--r--drivers/infiniband/core/cm.c8
-rw-r--r--drivers/infiniband/core/cma.c505
-rw-r--r--drivers/infiniband/core/device.c25
-rw-r--r--drivers/infiniband/core/iwcm.c2
-rw-r--r--drivers/infiniband/core/mad.c7
-rw-r--r--drivers/infiniband/core/netlink.c190
-rw-r--r--drivers/infiniband/core/ucma.c42
-rw-r--r--drivers/infiniband/core/user_mad.c7
-rw-r--r--drivers/infiniband/core/uverbs_main.c8
-rw-r--r--drivers/infiniband/hw/amso1100/c2.c1
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_cm.c29
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.h2
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_qp.c6
-rw-r--r--drivers/infiniband/hw/cxgb4/cm.c49
-rw-r--r--drivers/infiniband/hw/cxgb4/device.c115
-rw-r--r--drivers/infiniband/hw/cxgb4/iw_cxgb4.h34
-rw-r--r--drivers/infiniband/hw/cxgb4/provider.c2
-rw-r--r--drivers/infiniband/hw/cxgb4/qp.c3
-rw-r--r--drivers/infiniband/hw/cxgb4/t4.h5
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c9
-rw-r--r--drivers/infiniband/hw/nes/nes.c4
-rw-r--r--drivers/infiniband/hw/nes/nes_cm.c16
-rw-r--r--drivers/infiniband/hw/nes/nes_hw.c5
-rw-r--r--drivers/infiniband/hw/nes/nes_hw.h1
-rw-r--r--drivers/infiniband/hw/nes/nes_nic.c59
-rw-r--r--drivers/infiniband/hw/nes/nes_verbs.c2
-rw-r--r--drivers/infiniband/hw/qib/Kconfig2
-rw-r--r--drivers/infiniband/hw/qib/qib_iba7322.c3
-rw-r--r--drivers/infiniband/hw/qib/qib_pcie.c5
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h1
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c11
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ethtool.c28
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c2
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c24
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c2
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c4
-rw-r--r--drivers/input/evdev.c19
-rw-r--r--drivers/input/input-compat.h2
-rw-r--r--drivers/input/input-polldev.c56
-rw-r--r--drivers/input/input.c1
-rw-r--r--drivers/input/joydev.c1
-rw-r--r--drivers/input/keyboard/Kconfig33
-rw-r--r--drivers/input/keyboard/Makefile3
-rw-r--r--drivers/input/keyboard/adp5589-keys.c771
-rw-r--r--drivers/input/keyboard/atakbd.c5
-rw-r--r--drivers/input/keyboard/gpio_keys.c11
-rw-r--r--drivers/input/keyboard/mpr121_touchkey.c339
-rw-r--r--drivers/input/keyboard/omap-keypad.c6
-rw-r--r--drivers/input/keyboard/pmic8xxx-keypad.c799
-rw-r--r--drivers/input/keyboard/qt1070.c1
-rw-r--r--drivers/input/keyboard/sh_keysc.c53
-rw-r--r--drivers/input/keyboard/tegra-kbc.c60
-rw-r--r--drivers/input/misc/Kconfig11
-rw-r--r--drivers/input/misc/Makefile1
-rw-r--r--drivers/input/misc/ad714x.c129
-rw-r--r--drivers/input/misc/ati_remote2.c9
-rw-r--r--drivers/input/misc/pmic8xxx-pwrkey.c231
-rw-r--r--drivers/input/misc/rotary_encoder.c119
-rw-r--r--drivers/input/misc/twl4030-pwrbutton.c2
-rw-r--r--drivers/input/misc/twl4030-vibra.c3
-rw-r--r--drivers/input/mouse/atarimouse.c15
-rw-r--r--drivers/input/mouse/elantech.c72
-rw-r--r--drivers/input/mouse/elantech.h6
-rw-r--r--drivers/input/mousedev.c1
-rw-r--r--drivers/input/serio/serport.c10
-rw-r--r--drivers/input/touchscreen/Kconfig12
-rw-r--r--drivers/input/touchscreen/Makefile1
-rw-r--r--drivers/input/touchscreen/ads7846.c26
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c92
-rw-r--r--drivers/input/touchscreen/atmel_tsadcc.c2
-rw-r--r--drivers/input/touchscreen/h3600_ts_input.c8
-rw-r--r--drivers/input/touchscreen/max11801_ts.c272
-rw-r--r--drivers/input/touchscreen/tsc2007.c26
-rw-r--r--drivers/isdn/capi/Kconfig15
-rw-r--r--drivers/isdn/capi/Makefile1
-rw-r--r--drivers/isdn/capi/capi.c139
-rw-r--r--drivers/isdn/capi/capifs.c239
-rw-r--r--drivers/isdn/capi/capifs.h28
-rw-r--r--drivers/isdn/gigaset/bas-gigaset.c5
-rw-r--r--drivers/isdn/gigaset/ev-layer.c26
-rw-r--r--drivers/isdn/gigaset/ser-gigaset.c8
-rw-r--r--drivers/isdn/hardware/avm/avm_cs.c2
-rw-r--r--drivers/isdn/hardware/eicon/debug.c3
-rw-r--r--drivers/isdn/hardware/eicon/divasfunc.c5
-rw-r--r--drivers/isdn/hardware/eicon/message.c23
-rw-r--r--drivers/isdn/hardware/mISDN/hfcpci.c6
-rw-r--r--drivers/isdn/hardware/mISDN/hfcsusb.c5
-rw-r--r--drivers/isdn/hardware/mISDN/netjet.c6
-rw-r--r--drivers/isdn/hisax/arcofi.c4
-rw-r--r--drivers/isdn/hisax/avma1_cs.c2
-rw-r--r--drivers/isdn/hisax/elsa_cs.c4
-rw-r--r--drivers/isdn/hisax/elsa_ser.c3
-rw-r--r--drivers/isdn/hisax/hfc_usb.c6
-rw-r--r--drivers/isdn/hisax/ipacx.c4
-rw-r--r--drivers/isdn/hisax/jade.c3
-rw-r--r--drivers/isdn/hisax/l3dss1.c4
-rw-r--r--drivers/isdn/hisax/l3ni1.c4
-rw-r--r--drivers/isdn/hisax/sedlbauer_cs.c2
-rw-r--r--drivers/isdn/hisax/st5481.h1
-rw-r--r--drivers/isdn/hisax/st5481_init.c6
-rw-r--r--drivers/isdn/hisax/teles_cs.c4
-rw-r--r--drivers/isdn/hysdn/hysdn_proclog.c11
-rw-r--r--drivers/isdn/i4l/isdn_common.c11
-rw-r--r--drivers/isdn/i4l/isdn_net.c2
-rw-r--r--drivers/isdn/i4l/isdn_tty.c2
-rw-r--r--drivers/isdn/mISDN/layer2.c20
-rw-r--r--drivers/isdn/mISDN/socket.c3
-rw-r--r--drivers/leds/Kconfig34
-rw-r--r--drivers/leds/Makefile3
-rw-r--r--drivers/leds/led-class.c3
-rw-r--r--drivers/leds/leds-88pm860x.c7
-rw-r--r--drivers/leds/leds-asic3.c165
-rw-r--r--drivers/leds/leds-gpio-register.c42
-rw-r--r--drivers/leds/leds-h1940.c170
-rw-r--r--drivers/leds/leds-lm3530.c73
-rw-r--r--drivers/leds/leds-mc13783.c9
-rw-r--r--drivers/leds/leds-pca9532.c191
-rw-r--r--drivers/leds/leds.h7
-rw-r--r--drivers/leds/ledtrig-timer.c3
-rw-r--r--drivers/macintosh/therm_pm72.c4
-rw-r--r--drivers/macintosh/via-pmu.c56
-rw-r--r--drivers/md/bitmap.c10
-rw-r--r--drivers/md/md.c23
-rw-r--r--drivers/md/multipath.c60
-rw-r--r--drivers/md/multipath.h1
-rw-r--r--drivers/md/raid1.c506
-rw-r--r--drivers/md/raid1.h4
-rw-r--r--drivers/md/raid10.c424
-rw-r--r--drivers/md/raid5.c43
-rw-r--r--drivers/media/common/saa7146_core.c7
-rw-r--r--drivers/media/common/tuners/Kconfig8
-rw-r--r--drivers/media/common/tuners/Makefile1
-rw-r--r--drivers/media/common/tuners/mxl5005s.c2
-rw-r--r--drivers/media/common/tuners/tda18212.c265
-rw-r--r--drivers/media/common/tuners/tda18212.h48
-rw-r--r--drivers/media/common/tuners/tda18212_priv.h44
-rw-r--r--drivers/media/common/tuners/tda18271-fe.c4
-rw-r--r--drivers/media/common/tuners/xc5000.c32
-rw-r--r--drivers/media/dvb/b2c2/flexcop-pci.c4
-rw-r--r--drivers/media/dvb/bt8xx/bt878.c2
-rw-r--r--drivers/media/dvb/dm1105/dm1105.c272
-rw-r--r--drivers/media/dvb/dvb-core/dvb_demux.c117
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c365
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.h3
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig5
-rw-r--r--drivers/media/dvb/dvb-usb/a800.c17
-rw-r--r--drivers/media/dvb/dvb-usb/anysee.c620
-rw-r--r--drivers/media/dvb/dvb-usb/anysee.h23
-rw-r--r--drivers/media/dvb/dvb-usb/au6610.c22
-rw-r--r--drivers/media/dvb/dvb-usb/ce6230.c11
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700.h5
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_core.c220
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_devices.c8
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-common.c2
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-dvb.c31
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h1
-rw-r--r--drivers/media/dvb/dvb-usb/dw2102.c12
-rw-r--r--drivers/media/dvb/dvb-usb/ec168.c18
-rw-r--r--drivers/media/dvb/dvb-usb/friio.c23
-rw-r--r--drivers/media/dvb/dvb-usb/lmedm04.c260
-rw-r--r--drivers/media/dvb/dvb-usb/lmedm04.h5
-rw-r--r--drivers/media/dvb/dvb-usb/m920x.c49
-rw-r--r--drivers/media/dvb/dvb-usb/nova-t-usb2.c2
-rw-r--r--drivers/media/dvb/dvb-usb/opera1.c33
-rw-r--r--drivers/media/dvb/dvb-usb/vp702x-fe.c80
-rw-r--r--drivers/media/dvb/dvb-usb/vp702x.c213
-rw-r--r--drivers/media/dvb/dvb-usb/vp702x.h7
-rw-r--r--drivers/media/dvb/dvb-usb/vp7045.c47
-rw-r--r--drivers/media/dvb/firewire/firedtv-avc.c15
-rw-r--r--drivers/media/dvb/firewire/firedtv-fw.c1
-rw-r--r--drivers/media/dvb/frontends/Kconfig19
-rw-r--r--drivers/media/dvb/frontends/Makefile6
-rw-r--r--drivers/media/dvb/frontends/bsbe1-d01a.h146
-rw-r--r--drivers/media/dvb/frontends/bsru6.h2
-rw-r--r--drivers/media/dvb/frontends/cx24116.c21
-rw-r--r--drivers/media/dvb/frontends/cx24116.h3
-rw-r--r--drivers/media/dvb/frontends/cxd2820r.h118
-rw-r--r--drivers/media/dvb/frontends/cxd2820r_c.c338
-rw-r--r--drivers/media/dvb/frontends/cxd2820r_core.c915
-rw-r--r--drivers/media/dvb/frontends/cxd2820r_priv.h166
-rw-r--r--drivers/media/dvb/frontends/cxd2820r_t.c449
-rw-r--r--drivers/media/dvb/frontends/cxd2820r_t2.c423
-rw-r--r--drivers/media/dvb/frontends/dib0070.c40
-rw-r--r--drivers/media/dvb/frontends/dib0090.c71
-rw-r--r--drivers/media/dvb/frontends/dib7000m.c49
-rw-r--r--drivers/media/dvb/frontends/dib7000p.c72
-rw-r--r--drivers/media/dvb/frontends/dib8000.c126
-rw-r--r--drivers/media/dvb/frontends/dib9000.c176
-rw-r--r--drivers/media/dvb/frontends/dibx000_common.c109
-rw-r--r--drivers/media/dvb/frontends/dibx000_common.h5
-rw-r--r--drivers/media/dvb/frontends/drx397xD.c1511
-rw-r--r--drivers/media/dvb/frontends/drx397xD.h130
-rw-r--r--drivers/media/dvb/frontends/drx397xD_fw.h40
-rw-r--r--drivers/media/dvb/frontends/drxd.h61
-rw-r--r--drivers/media/dvb/frontends/drxd_firm.c929
-rw-r--r--drivers/media/dvb/frontends/drxd_firm.h115
-rw-r--r--drivers/media/dvb/frontends/drxd_hard.c3001
-rw-r--r--drivers/media/dvb/frontends/drxd_map_firm.h1013
-rw-r--r--drivers/media/dvb/frontends/eds1547.h2
-rw-r--r--drivers/media/dvb/frontends/ix2505v.c10
-rw-r--r--drivers/media/dvb/frontends/stb0899_algo.c2
-rw-r--r--drivers/media/dvb/frontends/stv0288.c2
-rw-r--r--drivers/media/dvb/frontends/stv0299.c10
-rw-r--r--drivers/media/dvb/frontends/tda8261.c1
-rw-r--r--drivers/media/dvb/frontends/z0194a.h2
-rw-r--r--drivers/media/dvb/mantis/hopper_cards.c2
-rw-r--r--drivers/media/dvb/mantis/mantis_cards.c2
-rw-r--r--drivers/media/dvb/mantis/mantis_pci.c5
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1033.c2
-rw-r--r--drivers/media/dvb/pt1/pt1.c5
-rw-r--r--drivers/media/dvb/siano/smsusb.c3
-rw-r--r--drivers/media/dvb/ttpci/Kconfig2
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c21
-rw-r--r--drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c60
-rw-r--r--drivers/media/radio/Kconfig15
-rw-r--r--drivers/media/radio/Makefile1
-rw-r--r--drivers/media/radio/radio-maestro.c452
-rw-r--r--drivers/media/radio/radio-maxiradio.c3
-rw-r--r--drivers/media/radio/radio-timb.c3
-rw-r--r--drivers/media/radio/radio-wl1273.c4
-rw-r--r--drivers/media/radio/si470x/radio-si470x-common.c60
-rw-r--r--drivers/media/radio/si470x/radio-si470x-i2c.c63
-rw-r--r--drivers/media/radio/si470x/radio-si470x.h4
-rw-r--r--drivers/media/radio/wl128x/fmdrv.h2
-rw-r--r--drivers/media/radio/wl128x/fmdrv_v4l2.c2
-rw-r--r--drivers/media/rc/Kconfig23
-rw-r--r--drivers/media/rc/Makefile2
-rw-r--r--drivers/media/rc/fintek-cir.c684
-rw-r--r--drivers/media/rc/fintek-cir.h243
-rw-r--r--drivers/media/rc/imon.c36
-rw-r--r--drivers/media/rc/ite-cir.c60
-rw-r--r--drivers/media/rc/keymaps/Makefile1
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-cardbus.c2
-rw-r--r--drivers/media/rc/keymaps/rc-imon-mce.c2
-rw-r--r--drivers/media/rc/keymaps/rc-imon-pad.c6
-rw-r--r--drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c2
-rw-r--r--drivers/media/rc/keymaps/rc-lme2510.c134
-rw-r--r--drivers/media/rc/keymaps/rc-rc6-mce.c4
-rw-r--r--drivers/media/rc/keymaps/rc-tivo.c98
-rw-r--r--drivers/media/rc/keymaps/rc-winfast.c4
-rw-r--r--drivers/media/rc/mceusb.c34
-rw-r--r--drivers/media/rc/nuvoton-cir.c75
-rw-r--r--drivers/media/rc/nuvoton-cir.h17
-rw-r--r--drivers/media/rc/rc-loopback.c6
-rw-r--r--drivers/media/rc/rc-main.c54
-rw-r--r--drivers/media/rc/redrat3.c1344
-rw-r--r--drivers/media/rc/winbond-cir.c447
-rw-r--r--drivers/media/video/Kconfig153
-rw-r--r--drivers/media/video/Makefile3
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c2
-rw-r--r--drivers/media/video/cpia2/cpia2_v4l.c6
-rw-r--r--drivers/media/video/cx18/Kconfig4
-rw-r--r--drivers/media/video/cx18/cx18-cards.c18
-rw-r--r--drivers/media/video/cx18/cx18-cards.h2
-rw-r--r--drivers/media/video/cx18/cx18-driver.c27
-rw-r--r--drivers/media/video/cx18/cx18-driver.h25
-rw-r--r--drivers/media/video/cx18/cx18-fileops.c70
-rw-r--r--drivers/media/video/cx18/cx18-fileops.h2
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.c144
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.c58
-rw-r--r--drivers/media/video/cx18/cx18-streams.c177
-rw-r--r--drivers/media/video/cx18/cx18-version.h2
-rw-r--r--drivers/media/video/cx18/cx23418.h6
-rw-r--r--drivers/media/video/cx231xx/cx231xx-avcore.c2
-rw-r--r--drivers/media/video/cx231xx/cx231xx-cards.c67
-rw-r--r--drivers/media/video/cx231xx/cx231xx-dvb.c1
-rw-r--r--drivers/media/video/cx231xx/cx231xx.h2
-rw-r--r--drivers/media/video/cx23885/cx23885-cards.c1
-rw-r--r--drivers/media/video/cx23885/cx23885-core.c2
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c41
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c2
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c42
-rw-r--r--drivers/media/video/cx88/cx88-video.c7
-rw-r--r--drivers/media/video/cx88/cx88.h11
-rw-r--r--drivers/media/video/em28xx/Kconfig2
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c49
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c9
-rw-r--r--drivers/media/video/em28xx/em28xx-dvb.c160
-rw-r--r--drivers/media/video/em28xx/em28xx-i2c.c2
-rw-r--r--drivers/media/video/em28xx/em28xx-reg.h1
-rw-r--r--drivers/media/video/em28xx/em28xx.h3
-rw-r--r--drivers/media/video/fsl-viu.c56
-rw-r--r--drivers/media/video/gspca/Kconfig9
-rw-r--r--drivers/media/video/gspca/Makefile2
-rw-r--r--drivers/media/video/gspca/cpia1.c6
-rw-r--r--drivers/media/video/gspca/gl860/gl860.c15
-rw-r--r--drivers/media/video/gspca/gspca.c4
-rw-r--r--drivers/media/video/gspca/gspca.h6
-rw-r--r--drivers/media/video/gspca/jeilinj.c581
-rw-r--r--drivers/media/video/gspca/kinect.c429
-rw-r--r--drivers/media/video/gspca/spca508.c5
-rw-r--r--drivers/media/video/gspca/stk014.c15
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c2
-rw-r--r--drivers/media/video/gspca/sunplus.c99
-rw-r--r--drivers/media/video/gspca/t613.c17
-rw-r--r--drivers/media/video/gspca/zc3xx.c47
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c4
-rw-r--r--drivers/media/video/m5mols/Kconfig5
-rw-r--r--drivers/media/video/m5mols/Makefile3
-rw-r--r--drivers/media/video/m5mols/m5mols.h296
-rw-r--r--drivers/media/video/m5mols/m5mols_capture.c191
-rw-r--r--drivers/media/video/m5mols/m5mols_controls.c299
-rw-r--r--drivers/media/video/m5mols/m5mols_core.c1004
-rw-r--r--drivers/media/video/m5mols/m5mols_reg.h399
-rw-r--r--drivers/media/video/msp3400-driver.c2
-rw-r--r--drivers/media/video/mt9m111.c14
-rw-r--r--drivers/media/video/mt9v022.c2
-rw-r--r--drivers/media/video/mt9v032.c773
-rw-r--r--drivers/media/video/mx3_camera.c60
-rw-r--r--drivers/media/video/omap/omap_vout.c2
-rw-r--r--drivers/media/video/omap/omap_voutdef.h2
-rw-r--r--drivers/media/video/omap1_camera.c43
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-std.c10
-rw-r--r--drivers/media/video/pwc/pwc-if.c2
-rw-r--r--drivers/media/video/pwc/pwc-v4l.c23
-rw-r--r--drivers/media/video/pxa_camera.c8
-rw-r--r--drivers/media/video/s2255drv.c27
-rw-r--r--drivers/media/video/s5p-fimc/Makefile6
-rw-r--r--drivers/media/video/s5p-fimc/mipi-csis.c724
-rw-r--r--drivers/media/video/s5p-fimc/mipi-csis.h22
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c125
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c2
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c34
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c8
-rw-r--r--drivers/media/video/saa7134/saa7134.h3
-rw-r--r--drivers/media/video/saa7164/saa7164-core.c2
-rw-r--r--drivers/media/video/saa7164/saa7164-encoder.c2
-rw-r--r--drivers/media/video/saa7164/saa7164-vbi.c2
-rw-r--r--drivers/media/video/sh_mobile_ceu_camera.c148
-rw-r--r--drivers/media/video/soc_camera.c29
-rw-r--r--drivers/media/video/soc_mediabus.c265
-rw-r--r--drivers/media/video/timblogiw.c3
-rw-r--r--drivers/media/video/tveeprom.c32
-rw-r--r--drivers/media/video/usbvision/usbvision-cards.c33
-rw-r--r--drivers/media/video/usbvision/usbvision-cards.h2
-rw-r--r--drivers/media/video/usbvision/usbvision-core.c165
-rw-r--r--drivers/media/video/usbvision/usbvision-i2c.c2
-rw-r--r--drivers/media/video/usbvision/usbvision-video.c8
-rw-r--r--drivers/media/video/usbvision/usbvision.h6
-rw-r--r--drivers/media/video/uvc/Makefile3
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c367
-rw-r--r--drivers/media/video/uvc/uvc_driver.c94
-rw-r--r--drivers/media/video/uvc/uvc_entity.c118
-rw-r--r--drivers/media/video/uvc/uvc_queue.c34
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c68
-rw-r--r--drivers/media/video/uvc/uvcvideo.h84
-rw-r--r--drivers/media/video/v4l2-dev.c18
-rw-r--r--drivers/media/video/via-camera.c1
-rw-r--r--drivers/media/video/zoran/zoran_card.c10
-rw-r--r--drivers/message/fusion/mptbase.c22
-rw-r--r--drivers/message/fusion/mptbase.h4
-rw-r--r--drivers/message/fusion/mptsas.c4
-rw-r--r--drivers/message/fusion/mptscsih.c13
-rw-r--r--drivers/message/fusion/mptspi.c22
-rw-r--r--drivers/message/i2o/README.ioctl2
-rw-r--r--drivers/message/i2o/i2o_scsi.c4
-rw-r--r--drivers/mfd/88pm860x-core.c155
-rw-r--r--drivers/mfd/Kconfig115
-rw-r--r--drivers/mfd/Makefile8
-rw-r--r--drivers/mfd/ab3100-core.c6
-rw-r--r--drivers/mfd/ab3550-core.c6
-rw-r--r--drivers/mfd/ab8500-core.c32
-rw-r--r--drivers/mfd/ab8500-gpadc.c34
-rw-r--r--drivers/mfd/ab8500-i2c.c3
-rw-r--r--drivers/mfd/asic3.c83
-rw-r--r--drivers/mfd/davinci_voicecodec.c6
-rw-r--r--drivers/mfd/db5500-prcmu-regs.h (renamed from arch/arm/mach-ux500/include/mach/prcmu-regs.h)27
-rw-r--r--drivers/mfd/db5500-prcmu.c448
-rw-r--r--drivers/mfd/db8500-prcmu-regs.h166
-rw-r--r--drivers/mfd/db8500-prcmu.c2069
-rw-r--r--drivers/mfd/htc-pasic3.c5
-rw-r--r--drivers/mfd/janz-cmodio.c3
-rw-r--r--drivers/mfd/max8925-core.c2
-rw-r--r--drivers/mfd/mc13xxx-core.c12
-rw-r--r--drivers/mfd/mfd-core.c7
-rw-r--r--drivers/mfd/omap-usb-host.c152
-rw-r--r--drivers/mfd/pm8921-core.c212
-rw-r--r--drivers/mfd/pm8xxx-irq.c371
-rw-r--r--drivers/mfd/rdc321x-southbridge.c6
-rw-r--r--drivers/mfd/t7l66xb.c6
-rw-r--r--drivers/mfd/tc6387xb.c3
-rw-r--r--drivers/mfd/tc6393xb.c10
-rw-r--r--drivers/mfd/timberdale.c81
-rw-r--r--drivers/mfd/tps6105x.c3
-rw-r--r--drivers/mfd/tps6586x.c4
-rw-r--r--drivers/mfd/tps65910-irq.c218
-rw-r--r--drivers/mfd/tps65910.c229
-rw-r--r--drivers/mfd/tps65911-comparator.c188
-rw-r--r--drivers/mfd/twl-core.c252
-rw-r--r--drivers/mfd/twl4030-codec.c10
-rw-r--r--drivers/mfd/twl4030-power.c6
-rw-r--r--drivers/mfd/twl6030-irq.c4
-rw-r--r--drivers/mfd/wl1273-core.c7
-rw-r--r--drivers/mfd/wm831x-core.c13
-rw-r--r--drivers/mfd/wm831x-irq.c27
-rw-r--r--drivers/mfd/wm8400-core.c3
-rw-r--r--drivers/misc/Kconfig26
-rw-r--r--drivers/misc/Makefile2
-rw-r--r--drivers/misc/bh1780gli.c8
-rw-r--r--drivers/misc/carma/Kconfig17
-rw-r--r--drivers/misc/carma/Makefile2
-rw-r--r--drivers/misc/carma/carma-fpga-program.c1141
-rw-r--r--drivers/misc/carma/carma-fpga.c1433
-rw-r--r--drivers/misc/cs5535-mfgpt.c4
-rw-r--r--drivers/misc/ibmasm/ibmasmfs.c2
-rw-r--r--drivers/misc/kgdbts.c29
-rw-r--r--drivers/misc/pch_phub.c153
-rw-r--r--drivers/misc/pti.c980
-rw-r--r--drivers/misc/sgi-gru/grufault.c1
-rw-r--r--drivers/misc/sgi-gru/grumain.c1
-rw-r--r--drivers/misc/spear13xx_pcie_gadget.c4
-rw-r--r--drivers/misc/ti-st/Kconfig2
-rw-r--r--drivers/misc/ti-st/st_core.c29
-rw-r--r--drivers/misc/ti-st/st_kim.c1
-rw-r--r--drivers/mmc/card/block.c712
-rw-r--r--drivers/mmc/card/mmc_test.c116
-rw-r--r--drivers/mmc/card/queue.c8
-rw-r--r--drivers/mmc/core/bus.c11
-rw-r--r--drivers/mmc/core/core.c111
-rw-r--r--drivers/mmc/core/core.h7
-rw-r--r--drivers/mmc/core/host.c4
-rw-r--r--drivers/mmc/core/mmc.c186
-rw-r--r--drivers/mmc/core/mmc_ops.c80
-rw-r--r--drivers/mmc/core/mmc_ops.h1
-rw-r--r--drivers/mmc/core/quirks.c89
-rw-r--r--drivers/mmc/core/sd.c405
-rw-r--r--drivers/mmc/core/sd.h2
-rw-r--r--drivers/mmc/core/sd_ops.c51
-rw-r--r--drivers/mmc/core/sdio.c24
-rw-r--r--drivers/mmc/core/sdio_irq.c33
-rw-r--r--drivers/mmc/core/sdio_ops.c18
-rw-r--r--drivers/mmc/host/Kconfig33
-rw-r--r--drivers/mmc/host/Makefile1
-rw-r--r--drivers/mmc/host/atmel-mci.c2
-rw-r--r--drivers/mmc/host/dw_mmc.c6
-rw-r--r--drivers/mmc/host/mmci.c6
-rw-r--r--drivers/mmc/host/mmci.h41
-rw-r--r--drivers/mmc/host/sdhci-pci.c49
-rw-r--r--drivers/mmc/host/sdhci-pxa.c48
-rw-r--r--drivers/mmc/host/sdhci-tegra.c2
-rw-r--r--drivers/mmc/host/sdhci.c854
-rw-r--r--drivers/mmc/host/sdhci.h59
-rw-r--r--drivers/mmc/host/sdricoh_cs.c2
-rw-r--r--drivers/mmc/host/sh_mmcif.c126
-rw-r--r--drivers/mmc/host/sh_mobile_sdhi.c50
-rw-r--r--drivers/mmc/host/tmio_mmc.c34
-rw-r--r--drivers/mmc/host/tmio_mmc.h16
-rw-r--r--drivers/mmc/host/tmio_mmc_dma.c21
-rw-r--r--drivers/mmc/host/tmio_mmc_pio.c184
-rw-r--r--drivers/mmc/host/vub300.c2506
-rw-r--r--drivers/mtd/Kconfig3
-rw-r--r--drivers/mtd/maps/Kconfig7
-rw-r--r--drivers/mtd/maps/Makefile2
-rw-r--r--drivers/mtd/maps/integrator-flash.c309
-rw-r--r--drivers/mtd/maps/lantiq-flash.c251
-rw-r--r--drivers/mtd/maps/pcmciamtd.c2
-rw-r--r--drivers/mtd/maps/physmap.c28
-rw-r--r--drivers/mtd/maps/pismo.c40
-rw-r--r--drivers/mtd/nand/au1550nd.c3
-rw-r--r--drivers/mtd/nand/tmio_nand.c2
-rw-r--r--drivers/mtd/ubi/cdev.c14
-rw-r--r--drivers/mtd/ubi/debug.c21
-rw-r--r--drivers/mtd/ubi/debug.h161
-rw-r--r--drivers/mtd/ubi/io.c6
-rw-r--r--drivers/mtd/ubi/scan.c2
-rw-r--r--drivers/mtd/ubi/ubi-media.h6
-rw-r--r--drivers/mtd/ubi/ubi.h4
-rw-r--r--drivers/mtd/ubi/wl.c3
-rw-r--r--drivers/net/3c509.c16
-rw-r--r--drivers/net/3c59x.c4
-rw-r--r--drivers/net/8139cp.c46
-rw-r--r--drivers/net/Kconfig7
-rw-r--r--drivers/net/Makefile2
-rw-r--r--drivers/net/acenic.c13
-rw-r--r--drivers/net/arm/etherh.c5
-rw-r--r--drivers/net/arm/ixp4xx_eth.c195
-rw-r--r--drivers/net/arm/ks8695net.c7
-rw-r--r--drivers/net/atarilance.c2
-rw-r--r--drivers/net/atl1c/atl1c_ethtool.c17
-rw-r--r--drivers/net/atl1c/atl1c_main.c27
-rw-r--r--drivers/net/atl1e/atl1e_ethtool.c7
-rw-r--r--drivers/net/atl1e/atl1e_main.c14
-rw-r--r--drivers/net/atlx/atl1.c34
-rw-r--r--drivers/net/atlx/atl2.c18
-rw-r--r--drivers/net/b44.c13
-rw-r--r--drivers/net/bcm63xx_enet.c7
-rw-r--r--drivers/net/benet/be.h74
-rw-r--r--drivers/net/benet/be_cmds.c344
-rw-r--r--drivers/net/benet/be_cmds.h457
-rw-r--r--drivers/net/benet/be_ethtool.c227
-rw-r--r--drivers/net/benet/be_hw.h4
-rw-r--r--drivers/net/benet/be_main.c638
-rw-r--r--drivers/net/bna/bfa_ioc.c13
-rw-r--r--drivers/net/bna/bna_ctrl.c21
-rw-r--r--drivers/net/bna/bna_txrx.c7
-rw-r--r--drivers/net/bna/bnad.c23
-rw-r--r--drivers/net/bna/bnad.h2
-rw-r--r--drivers/net/bna/bnad_ethtool.c70
-rw-r--r--drivers/net/bnx2.c184
-rw-r--r--drivers/net/bnx2.h3
-rw-r--r--drivers/net/bnx2x/bnx2x.h35
-rw-r--r--drivers/net/bnx2x/bnx2x_cmn.c648
-rw-r--r--drivers/net/bnx2x/bnx2x_cmn.h456
-rw-r--r--drivers/net/bnx2x/bnx2x_dcb.c202
-rw-r--r--drivers/net/bnx2x/bnx2x_dcb.h16
-rw-r--r--drivers/net/bnx2x/bnx2x_ethtool.c167
-rw-r--r--drivers/net/bnx2x/bnx2x_fw_defs.h2
-rw-r--r--drivers/net/bnx2x/bnx2x_fw_file_hdr.h2
-rw-r--r--drivers/net/bnx2x/bnx2x_hsi.h4
-rw-r--r--drivers/net/bnx2x/bnx2x_init.h2
-rw-r--r--drivers/net/bnx2x/bnx2x_init_ops.h2
-rw-r--r--drivers/net/bnx2x/bnx2x_link.c14
-rw-r--r--drivers/net/bnx2x/bnx2x_main.c435
-rw-r--r--drivers/net/bnx2x/bnx2x_reg.h2
-rw-r--r--drivers/net/bnx2x/bnx2x_stats.c2
-rw-r--r--drivers/net/bnx2x/bnx2x_stats.h2
-rw-r--r--drivers/net/bonding/Makefile3
-rw-r--r--drivers/net/bonding/bond_3ad.c43
-rw-r--r--drivers/net/bonding/bond_3ad.h4
-rw-r--r--drivers/net/bonding/bond_alb.c61
-rw-r--r--drivers/net/bonding/bond_alb.h1
-rw-r--r--drivers/net/bonding/bond_main.c562
-rw-r--r--drivers/net/bonding/bond_procfs.c2
-rw-r--r--drivers/net/bonding/bond_sysfs.c100
-rw-r--r--drivers/net/bonding/bonding.h56
-rw-r--r--drivers/net/caif/caif_serial.c6
-rw-r--r--drivers/net/can/janz-ican3.c3
-rw-r--r--drivers/net/can/pch_can.c2
-rw-r--r--drivers/net/can/slcan.c9
-rw-r--r--drivers/net/can/softing/softing_cs.c2
-rw-r--r--drivers/net/can/softing/softing_main.c2
-rw-r--r--drivers/net/cassini.c37
-rw-r--r--drivers/net/chelsio/common.h5
-rw-r--r--drivers/net/chelsio/cxgb2.c59
-rw-r--r--drivers/net/chelsio/sge.c14
-rw-r--r--drivers/net/chelsio/tp.c5
-rw-r--r--drivers/net/chelsio/tp.h1
-rw-r--r--drivers/net/cnic.c63
-rw-r--r--drivers/net/cnic.h1
-rw-r--r--drivers/net/cnic_if.h6
-rw-r--r--drivers/net/cris/eth_v10.c4
-rw-r--r--drivers/net/cxgb3/adapter.h7
-rw-r--r--drivers/net/cxgb3/common.h1
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c117
-rw-r--r--drivers/net/cxgb3/sge.c8
-rw-r--r--drivers/net/cxgb4/cxgb4.h6
-rw-r--r--drivers/net/cxgb4/cxgb4_main.c103
-rw-r--r--drivers/net/cxgb4/sge.c5
-rw-r--r--drivers/net/cxgb4vf/adapter.h6
-rw-r--r--drivers/net/cxgb4vf/cxgb4vf_main.c73
-rw-r--r--drivers/net/cxgb4vf/sge.c5
-rw-r--r--drivers/net/depca.c35
-rw-r--r--drivers/net/dl2k.c29
-rw-r--r--drivers/net/dm9000.c57
-rw-r--r--drivers/net/dummy.c4
-rw-r--r--drivers/net/e100.c78
-rw-r--r--drivers/net/e1000/e1000.h5
-rw-r--r--drivers/net/e1000/e1000_ethtool.c60
-rw-r--r--drivers/net/e1000/e1000_main.c43
-rw-r--r--drivers/net/e1000e/82571.c22
-rw-r--r--drivers/net/e1000e/e1000.h12
-rw-r--r--drivers/net/e1000e/es2lan.c5
-rw-r--r--drivers/net/e1000e/ethtool.c154
-rw-r--r--drivers/net/e1000e/hw.h1
-rw-r--r--drivers/net/e1000e/ich8lan.c16
-rw-r--r--drivers/net/e1000e/lib.c18
-rw-r--r--drivers/net/e1000e/netdev.c216
-rw-r--r--drivers/net/e1000e/phy.c4
-rw-r--r--drivers/net/eepro.c2
-rw-r--r--drivers/net/ehea/ehea_ethtool.c46
-rw-r--r--drivers/net/ehea/ehea_main.c7
-rw-r--r--drivers/net/ehea/ehea_qmr.h1
-rw-r--r--drivers/net/enc28j60.c5
-rw-r--r--drivers/net/enic/Makefile2
-rw-r--r--drivers/net/enic/enic.h5
-rw-r--r--drivers/net/enic/enic_dev.c62
-rw-r--r--drivers/net/enic/enic_dev.h7
-rw-r--r--drivers/net/enic/enic_main.c275
-rw-r--r--drivers/net/enic/enic_pp.c264
-rw-r--r--drivers/net/enic/enic_pp.h27
-rw-r--r--drivers/net/enic/enic_res.c4
-rw-r--r--drivers/net/enic/vnic_dev.c97
-rw-r--r--drivers/net/enic/vnic_dev.h6
-rw-r--r--drivers/net/enic/vnic_devcmd.h57
-rw-r--r--drivers/net/enic/vnic_vic.c5
-rw-r--r--drivers/net/enic/vnic_vic.h13
-rw-r--r--drivers/net/ewrk3.c58
-rw-r--r--drivers/net/forcedeth.c114
-rw-r--r--drivers/net/fs_enet/fs_enet-main.c2
-rw-r--r--drivers/net/gianfar.c16
-rw-r--r--drivers/net/gianfar.h20
-rw-r--r--drivers/net/gianfar_ethtool.c110
-rw-r--r--drivers/net/gianfar_ptp.c588
-rw-r--r--drivers/net/greth.c46
-rw-r--r--drivers/net/greth.h4
-rw-r--r--drivers/net/hamachi.c78
-rw-r--r--drivers/net/hamradio/6pack.c8
-rw-r--r--drivers/net/hamradio/baycom_epp.c2
-rw-r--r--drivers/net/hamradio/baycom_par.c2
-rw-r--r--drivers/net/hamradio/baycom_ser_fdx.c2
-rw-r--r--drivers/net/hamradio/baycom_ser_hdx.c2
-rw-r--r--drivers/net/hamradio/bpqether.c4
-rw-r--r--drivers/net/hamradio/hdlcdrv.c2
-rw-r--r--drivers/net/hamradio/mkiss.c11
-rw-r--r--drivers/net/hp100.c12
-rw-r--r--drivers/net/ibm_newemac/core.c17
-rw-r--r--drivers/net/ibmlana.c7
-rw-r--r--drivers/net/ibmveth.c98
-rw-r--r--drivers/net/ifb.c4
-rw-r--r--drivers/net/igb/e1000_82575.c11
-rw-r--r--drivers/net/igb/igb.h2
-rw-r--r--drivers/net/igb/igb_ethtool.c48
-rw-r--r--drivers/net/igb/igb_main.c91
-rw-r--r--drivers/net/igbvf/ethtool.c14
-rw-r--r--drivers/net/igbvf/netdev.c1
-rw-r--r--drivers/net/ioc3-eth.c32
-rw-r--r--drivers/net/irda/ali-ircc.c2
-rw-r--r--drivers/net/irda/bfin_sir.c59
-rw-r--r--drivers/net/irda/bfin_sir.h63
-rw-r--r--drivers/net/irda/irtty-sir.c16
-rw-r--r--drivers/net/irda/smsc-ircc2.c44
-rw-r--r--drivers/net/ixgb/ixgb.h3
-rw-r--r--drivers/net/ixgb/ixgb_ethtool.c53
-rw-r--r--drivers/net/ixgb/ixgb_main.c1
-rw-r--r--drivers/net/ixgbe/ixgbe.h111
-rw-r--r--drivers/net/ixgbe/ixgbe_82598.c61
-rw-r--r--drivers/net/ixgbe/ixgbe_82599.c178
-rw-r--r--drivers/net/ixgbe/ixgbe_common.c532
-rw-r--r--drivers/net/ixgbe/ixgbe_common.h12
-rw-r--r--drivers/net/ixgbe/ixgbe_dcb_82598.c2
-rw-r--r--drivers/net/ixgbe/ixgbe_dcb_82599.c77
-rw-r--r--drivers/net/ixgbe/ixgbe_dcb_82599.h2
-rw-r--r--drivers/net/ixgbe/ixgbe_dcb_nl.c109
-rw-r--r--drivers/net/ixgbe/ixgbe_ethtool.c191
-rw-r--r--drivers/net/ixgbe/ixgbe_fcoe.c4
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c1045
-rw-r--r--drivers/net/ixgbe/ixgbe_mbx.h4
-rw-r--r--drivers/net/ixgbe/ixgbe_phy.c20
-rw-r--r--drivers/net/ixgbe/ixgbe_sriov.c100
-rw-r--r--drivers/net/ixgbe/ixgbe_type.h218
-rw-r--r--drivers/net/ixgbe/ixgbe_x540.c317
-rw-r--r--drivers/net/ixgbevf/ethtool.c8
-rw-r--r--drivers/net/ixgbevf/ixgbevf_main.c31
-rw-r--r--drivers/net/ixgbevf/mbx.h1
-rw-r--r--drivers/net/ixgbevf/vf.c34
-rw-r--r--drivers/net/ixgbevf/vf.h1
-rw-r--r--drivers/net/jme.c80
-rw-r--r--drivers/net/jme.h2
-rw-r--r--drivers/net/ks8842.c3
-rw-r--r--drivers/net/ksz884x.c82
-rw-r--r--drivers/net/lantiq_etop.c805
-rw-r--r--drivers/net/loopback.c3
-rw-r--r--drivers/net/macb.c13
-rw-r--r--drivers/net/macvlan.c50
-rw-r--r--drivers/net/mdio.c23
-rw-r--r--drivers/net/mii.c31
-rw-r--r--drivers/net/mlx4/en_ethtool.c49
-rw-r--r--drivers/net/mlx4/en_netdev.c26
-rw-r--r--drivers/net/mlx4/en_rx.c2
-rw-r--r--drivers/net/mlx4/mlx4_en.h1
-rw-r--r--drivers/net/mv643xx_eth.c34
-rw-r--r--drivers/net/myri10ge/myri10ge.c69
-rw-r--r--drivers/net/natsemi.c11
-rw-r--r--drivers/net/ne3210.c15
-rw-r--r--drivers/net/netconsole.c108
-rw-r--r--drivers/net/netxen/netxen_nic.h2
-rw-r--r--drivers/net/netxen/netxen_nic_ethtool.c117
-rw-r--r--drivers/net/netxen/netxen_nic_init.c3
-rw-r--r--drivers/net/netxen/netxen_nic_main.c55
-rw-r--r--drivers/net/niu.c63
-rw-r--r--drivers/net/niu.h1
-rw-r--r--drivers/net/ns83820.c8
-rw-r--r--drivers/net/pasemi_mac.c1
-rw-r--r--drivers/net/pch_gbe/pch_gbe.h4
-rw-r--r--drivers/net/pch_gbe/pch_gbe_ethtool.c65
-rw-r--r--drivers/net/pch_gbe/pch_gbe_main.c49
-rw-r--r--drivers/net/pch_gbe/pch_gbe_param.c16
-rw-r--r--drivers/net/pch_gbe/pch_gbe_phy.c4
-rw-r--r--drivers/net/pcmcia/3c574_cs.c2
-rw-r--r--drivers/net/pcmcia/3c589_cs.c2
-rw-r--r--drivers/net/pcmcia/axnet_cs.c2
-rw-r--r--drivers/net/pcmcia/com20020_cs.c2
-rw-r--r--drivers/net/pcmcia/fmvj18x_cs.c2
-rw-r--r--drivers/net/pcmcia/ibmtr_cs.c2
-rw-r--r--drivers/net/pcmcia/nmclan_cs.c2
-rw-r--r--drivers/net/pcmcia/pcnet_cs.c2
-rw-r--r--drivers/net/pcmcia/smc91c92_cs.c8
-rw-r--r--drivers/net/pcmcia/xirc2ps_cs.c2
-rw-r--r--drivers/net/pcnet32.c90
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/dp83640.c1100
-rw-r--r--drivers/net/phy/dp83640_reg.h267
-rw-r--r--drivers/net/phy/phy.c12
-rw-r--r--drivers/net/ppp_async.c6
-rw-r--r--drivers/net/ppp_synctty.c6
-rw-r--r--drivers/net/pptp.c10
-rw-r--r--drivers/net/ps3_gelic_net.c34
-rw-r--r--drivers/net/ps3_gelic_net.h3
-rw-r--r--drivers/net/ps3_gelic_wireless.c4
-rw-r--r--drivers/net/qla3xxx.c5
-rw-r--r--drivers/net/qlcnic/qlcnic.h416
-rw-r--r--drivers/net/qlcnic/qlcnic_ctx.c250
-rw-r--r--drivers/net/qlcnic/qlcnic_ethtool.c417
-rw-r--r--drivers/net/qlcnic/qlcnic_hdr.h40
-rw-r--r--drivers/net/qlcnic/qlcnic_hw.c578
-rw-r--r--drivers/net/qlcnic/qlcnic_init.c66
-rw-r--r--drivers/net/qlcnic/qlcnic_main.c634
-rw-r--r--drivers/net/qlge/qlge.h2
-rw-r--r--drivers/net/qlge/qlge_ethtool.c74
-rw-r--r--drivers/net/qlge/qlge_main.c26
-rw-r--r--drivers/net/r8169.c1007
-rw-r--r--drivers/net/rionet.c4
-rw-r--r--drivers/net/s2io.c200
-rw-r--r--drivers/net/s2io.h13
-rw-r--r--drivers/net/sb1250-mac.c1
-rw-r--r--drivers/net/sc92031.c8
-rw-r--r--drivers/net/sfc/efx.c49
-rw-r--r--drivers/net/sfc/efx.h2
-rw-r--r--drivers/net/sfc/ethtool.c118
-rw-r--r--drivers/net/sfc/falcon.c4
-rw-r--r--drivers/net/sfc/falcon_xmac.c2
-rw-r--r--drivers/net/sfc/mac.h4
-rw-r--r--drivers/net/sfc/mcdi_mac.c2
-rw-r--r--drivers/net/sfc/mcdi_phy.c8
-rw-r--r--drivers/net/sfc/mdio_10g.c6
-rw-r--r--drivers/net/sfc/mdio_10g.h2
-rw-r--r--drivers/net/sfc/net_driver.h24
-rw-r--r--drivers/net/sfc/nic.c6
-rw-r--r--drivers/net/sfc/nic.h6
-rw-r--r--drivers/net/sfc/phy.h8
-rw-r--r--drivers/net/sfc/qt202x_phy.c2
-rw-r--r--drivers/net/sfc/rx.c4
-rw-r--r--drivers/net/sfc/selftest.c11
-rw-r--r--drivers/net/sfc/siena.c2
-rw-r--r--drivers/net/sfc/tenxpress.c4
-rw-r--r--drivers/net/sfc/tx.c9
-rw-r--r--drivers/net/sfc/txc43128_phy.c2
-rw-r--r--drivers/net/sgiseeq.c2
-rw-r--r--drivers/net/sgiseeq.h2
-rw-r--r--drivers/net/skge.c94
-rw-r--r--drivers/net/skge.h1
-rw-r--r--drivers/net/sky2.c195
-rw-r--r--drivers/net/sky2.h1
-rw-r--r--drivers/net/slip.c11
-rw-r--r--drivers/net/smc-mca.c6
-rw-r--r--drivers/net/smc911x.c4
-rw-r--r--drivers/net/smc91x.c4
-rw-r--r--drivers/net/smsc911x.c448
-rw-r--r--drivers/net/smsc911x.h22
-rw-r--r--drivers/net/spider_net.c15
-rw-r--r--drivers/net/spider_net.h7
-rw-r--r--drivers/net/spider_net_ethtool.c23
-rw-r--r--drivers/net/stmmac/dwmac1000_core.c5
-rw-r--r--drivers/net/stmmac/stmmac.h1
-rw-r--r--drivers/net/stmmac/stmmac_ethtool.c33
-rw-r--r--drivers/net/stmmac/stmmac_main.c87
-rw-r--r--drivers/net/sungem.c18
-rw-r--r--drivers/net/sunhme.c25
-rw-r--r--drivers/net/tc35815.c1
-rw-r--r--drivers/net/tehuti.c28
-rw-r--r--drivers/net/tg3.c3566
-rw-r--r--drivers/net/tg3.h281
-rw-r--r--drivers/net/tile/tilepro.c10
-rw-r--r--drivers/net/tokenring/madgemc.c2
-rw-r--r--drivers/net/tokenring/olympic.c57
-rw-r--r--drivers/net/tulip/21142.c14
-rw-r--r--drivers/net/tulip/Makefile2
-rw-r--r--drivers/net/tulip/de2104x.c183
-rw-r--r--drivers/net/tulip/de4x5.c4
-rw-r--r--drivers/net/tulip/dmfe.c9
-rw-r--r--drivers/net/tulip/eeprom.c4
-rw-r--r--drivers/net/tulip/interrupt.c48
-rw-r--r--drivers/net/tulip/media.c49
-rw-r--r--drivers/net/tulip/pnic.c22
-rw-r--r--drivers/net/tulip/pnic2.c16
-rw-r--r--drivers/net/tulip/timer.c47
-rw-r--r--drivers/net/tulip/tulip.h8
-rw-r--r--drivers/net/tulip/tulip_core.c50
-rw-r--r--drivers/net/tulip/uli526x.c71
-rw-r--r--drivers/net/tulip/winbond-840.c81
-rw-r--r--drivers/net/tulip/xircom_cb.c268
-rw-r--r--drivers/net/tun.c69
-rw-r--r--drivers/net/typhoon.c58
-rw-r--r--drivers/net/ucc_geth_ethtool.c3
-rw-r--r--drivers/net/usb/Kconfig2
-rw-r--r--drivers/net/usb/asix.c28
-rw-r--r--drivers/net/usb/catc.c2
-rw-r--r--drivers/net/usb/cdc_ncm.c84
-rw-r--r--drivers/net/usb/dm9601.c6
-rw-r--r--drivers/net/usb/plusb.c32
-rw-r--r--drivers/net/usb/rndis_host.c39
-rw-r--r--drivers/net/usb/rtl8150.c11
-rw-r--r--drivers/net/usb/smsc75xx.c131
-rw-r--r--drivers/net/usb/smsc95xx.c90
-rw-r--r--drivers/net/usb/usbnet.c8
-rw-r--r--drivers/net/veth.c48
-rw-r--r--drivers/net/via-rhine.c242
-rw-r--r--drivers/net/via-velocity.c28
-rw-r--r--drivers/net/via-velocity.h2
-rw-r--r--drivers/net/virtio_net.c46
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c43
-rw-r--r--drivers/net/vmxnet3/vmxnet3_ethtool.c73
-rw-r--r--drivers/net/vmxnet3/vmxnet3_int.h11
-rw-r--r--drivers/net/vxge/vxge-config.c48
-rw-r--r--drivers/net/vxge/vxge-config.h70
-rw-r--r--drivers/net/vxge/vxge-ethtool.c104
-rw-r--r--drivers/net/vxge/vxge-main.c144
-rw-r--r--drivers/net/vxge/vxge-main.h14
-rw-r--r--drivers/net/vxge/vxge-traffic.c1
-rw-r--r--drivers/net/vxge/vxge-traffic.h2
-rw-r--r--drivers/net/vxge/vxge-version.h4
-rw-r--r--drivers/net/wan/dlci.c4
-rw-r--r--drivers/net/wan/hdlc_fr.c9
-rw-r--r--drivers/net/wan/lapbether.c4
-rw-r--r--drivers/net/wan/pc300_drv.c5
-rw-r--r--drivers/net/wan/x25_asy.c7
-rw-r--r--drivers/net/wireless/Kconfig1
-rw-r--r--drivers/net/wireless/Makefile2
-rw-r--r--drivers/net/wireless/airo.c60
-rw-r--r--drivers/net/wireless/airo_cs.c2
-rw-r--r--drivers/net/wireless/ath/Kconfig1
-rw-r--r--drivers/net/wireless/ath/Makefile1
-rw-r--r--drivers/net/wireless/ath/ar9170/Kconfig20
-rw-r--r--drivers/net/wireless/ath/ar9170/Makefile3
-rw-r--r--drivers/net/wireless/ath/ar9170/ar9170.h258
-rw-r--r--drivers/net/wireless/ath/ar9170/cmd.c127
-rw-r--r--drivers/net/wireless/ath/ar9170/cmd.h92
-rw-r--r--drivers/net/wireless/ath/ar9170/eeprom.h179
-rw-r--r--drivers/net/wireless/ath/ar9170/hw.h430
-rw-r--r--drivers/net/wireless/ath/ar9170/led.c181
-rw-r--r--drivers/net/wireless/ath/ar9170/mac.c519
-rw-r--r--drivers/net/wireless/ath/ar9170/main.c2190
-rw-r--r--drivers/net/wireless/ath/ar9170/phy.c1719
-rw-r--r--drivers/net/wireless/ath/ar9170/usb.c1008
-rw-r--r--drivers/net/wireless/ath/ar9170/usb.h82
-rw-r--r--drivers/net/wireless/ath/ath.h10
-rw-r--r--drivers/net/wireless/ath/ath5k/ahb.c28
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h31
-rw-r--r--drivers/net/wireless/ath/ath5k/attach.c7
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c73
-rw-r--r--drivers/net/wireless/ath/ath5k/base.h7
-rw-r--r--drivers/net/wireless/ath/ath5k/caps.c3
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.c65
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.h17
-rw-r--r--drivers/net/wireless/ath/ath5k/desc.c158
-rw-r--r--drivers/net/wireless/ath/ath5k/eeprom.c158
-rw-r--r--drivers/net/wireless/ath/ath5k/mac80211-ops.c9
-rw-r--r--drivers/net/wireless/ath/ath5k/pci.c32
-rw-r--r--drivers/net/wireless/ath/ath5k/pcu.c35
-rw-r--r--drivers/net/wireless/ath/ath5k/qcu.c4
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c5
-rw-r--r--drivers/net/wireless/ath/ath9k/Kconfig21
-rw-r--r--drivers/net/wireless/ath/ath9k/Makefile6
-rw-r--r--drivers/net/wireless/ath/ath9k/ahb.c20
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.c8
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/ar5008_initvals.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/ar5008_phy.c47
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9001_initvals.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_calib.c45
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_hw.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_initvals.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_mac.c36
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_phy.c46
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_phy.h8
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h180
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_calib.c389
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_eeprom.c135
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_eeprom.h16
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_hw.c191
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_mac.c37
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_mac.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_paprd.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.c101
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.h49
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9340_initvals.h1525
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9485_initvals.h937
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h36
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c270
-rw-r--r--drivers/net/wireless/ath/ath9k/btcoex.c102
-rw-r--r--drivers/net/wireless/ath/ath9k/btcoex.h22
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.c23
-rw-r--r--drivers/net/wireless/ath/ath9k/calib.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/common.c35
-rw-r--r--drivers/net/wireless/ath/ath9k/common.h10
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c149
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h13
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.h8
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_4k.c28
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_9287.c36
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_def.c13
-rw-r--r--drivers/net/wireless/ath/ath9k/gpio.c35
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.c336
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.h12
-rw-r--r--drivers/net/wireless/ath/ath9k/htc.h315
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_beacon.c335
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_debug.c960
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_gpio.c218
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c160
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c490
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_txrx.c784
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_hst.c52
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_hst.h27
-rw-r--r--drivers/net/wireless/ath/ath9k/hw-ops.h19
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c386
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h105
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c57
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.c137
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c370
-rw-r--r--drivers/net/wireless/ath/ath9k/pci.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/phy.h20
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.c17
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c230
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h137
-rw-r--r--drivers/net/wireless/ath/ath9k/wmi.c128
-rw-r--r--drivers/net/wireless/ath/ath9k/wmi.h84
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c176
-rw-r--r--drivers/net/wireless/ath/carl9170/carl9170.h6
-rw-r--r--drivers/net/wireless/ath/carl9170/fw.c19
-rw-r--r--drivers/net/wireless/ath/carl9170/main.c104
-rw-r--r--drivers/net/wireless/ath/carl9170/tx.c164
-rw-r--r--drivers/net/wireless/ath/hw.c10
-rw-r--r--drivers/net/wireless/ath/key.c38
-rw-r--r--drivers/net/wireless/ath/regd.c8
-rw-r--r--drivers/net/wireless/ath/regd_common.h2
-rw-r--r--drivers/net/wireless/atmel_cs.c4
-rw-r--r--drivers/net/wireless/b43/b43.h28
-rw-r--r--drivers/net/wireless/b43/dma.c37
-rw-r--r--drivers/net/wireless/b43/leds.c4
-rw-r--r--drivers/net/wireless/b43/lo.c4
-rw-r--r--drivers/net/wireless/b43/main.c259
-rw-r--r--drivers/net/wireless/b43/main.h1
-rw-r--r--drivers/net/wireless/b43/pcmcia.c2
-rw-r--r--drivers/net/wireless/b43/phy_a.c16
-rw-r--r--drivers/net/wireless/b43/phy_common.c8
-rw-r--r--drivers/net/wireless/b43/phy_g.c48
-rw-r--r--drivers/net/wireless/b43/phy_lp.c22
-rw-r--r--drivers/net/wireless/b43/phy_n.c44
-rw-r--r--drivers/net/wireless/b43/pio.c30
-rw-r--r--drivers/net/wireless/b43/rfkill.c6
-rw-r--r--drivers/net/wireless/b43/sdio.c4
-rw-r--r--drivers/net/wireless/b43/sysfs.c4
-rw-r--r--drivers/net/wireless/b43/tables_lpphy.c4
-rw-r--r--drivers/net/wireless/b43/wa.c4
-rw-r--r--drivers/net/wireless/b43/xmit.c2
-rw-r--r--drivers/net/wireless/b43legacy/main.c52
-rw-r--r--drivers/net/wireless/hostap/hostap_cs.c2
-rw-r--r--drivers/net/wireless/hostap/hostap_main.c7
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c2
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-4965-calib.c4
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-4965-lib.c3
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-4965-rs.c3
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-core.c20
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-core.h1
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-dev.h4
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-hcmd.c4
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-helpers.h6
-rw-r--r--drivers/net/wireless/iwlegacy/iwl-tx.c52
-rw-r--r--drivers/net/wireless/iwlegacy/iwl3945-base.c22
-rw-r--r--drivers/net/wireless/iwlegacy/iwl4965-base.c47
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig10
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c65
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-2000.c178
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000-hw.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c115
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000-hw.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c151
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-calib.c65
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-calib.h8
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c1073
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h70
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c45
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c59
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-hw.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-ict.c4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-led.c73
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-lib.c183
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c117
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.h31
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rxon.c279
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-sta.c8
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tt.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tt.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tx.c257
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-ucode.c352
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c1415
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.h126
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h817
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c270
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h131
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-csr.h43
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c1074
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h415
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-devtrace.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-devtrace.h60
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.c113
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.h195
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fh.h42
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-hcmd.c34
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-helpers.h39
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-io.c294
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-io.h498
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.c52
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.c19
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h358
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c375
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-spectrum.h92
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c30
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sv-open.c640
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-testmode.h185
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c440
-rw-r--r--drivers/net/wireless/iwmc3200wifi/rx.c7
-rw-r--r--drivers/net/wireless/libertas/cfg.c61
-rw-r--r--drivers/net/wireless/libertas/cmd.c285
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c46
-rw-r--r--drivers/net/wireless/libertas/debugfs.c41
-rw-r--r--drivers/net/wireless/libertas/decl.h8
-rw-r--r--drivers/net/wireless/libertas/defs.h120
-rw-r--r--drivers/net/wireless/libertas/dev.h20
-rw-r--r--drivers/net/wireless/libertas/ethtool.c3
-rw-r--r--drivers/net/wireless/libertas/host.h33
-rw-r--r--drivers/net/wireless/libertas/if_cs.c94
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c37
-rw-r--r--drivers/net/wireless/libertas/if_spi.c282
-rw-r--r--drivers/net/wireless/libertas/if_spi.h68
-rw-r--r--drivers/net/wireless/libertas/if_usb.c157
-rw-r--r--drivers/net/wireless/libertas/if_usb.h14
-rw-r--r--drivers/net/wireless/libertas/main.c171
-rw-r--r--drivers/net/wireless/libertas/mesh.c218
-rw-r--r--drivers/net/wireless/libertas/mesh.h6
-rw-r--r--drivers/net/wireless/libertas/rx.c41
-rw-r--r--drivers/net/wireless/libertas/tx.c34
-rw-r--r--drivers/net/wireless/libertas/types.h18
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c11
-rw-r--r--drivers/net/wireless/mwifiex/11n.c744
-rw-r--r--drivers/net/wireless/mwifiex/11n.h161
-rw-r--r--drivers/net/wireless/mwifiex/11n_aggr.c302
-rw-r--r--drivers/net/wireless/mwifiex/11n_aggr.h32
-rw-r--r--drivers/net/wireless/mwifiex/11n_rxreorder.c616
-rw-r--r--drivers/net/wireless/mwifiex/11n_rxreorder.h65
-rw-r--r--drivers/net/wireless/mwifiex/Kconfig21
-rw-r--r--drivers/net/wireless/mwifiex/Makefile41
-rw-r--r--drivers/net/wireless/mwifiex/README204
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c1417
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.h31
-rw-r--r--drivers/net/wireless/mwifiex/cfp.c360
-rw-r--r--drivers/net/wireless/mwifiex/cmdevt.c1414
-rw-r--r--drivers/net/wireless/mwifiex/debugfs.c770
-rw-r--r--drivers/net/wireless/mwifiex/decl.h129
-rw-r--r--drivers/net/wireless/mwifiex/fw.h1187
-rw-r--r--drivers/net/wireless/mwifiex/init.c645
-rw-r--r--drivers/net/wireless/mwifiex/ioctl.h331
-rw-r--r--drivers/net/wireless/mwifiex/join.c1423
-rw-r--r--drivers/net/wireless/mwifiex/main.c1055
-rw-r--r--drivers/net/wireless/mwifiex/main.h1009
-rw-r--r--drivers/net/wireless/mwifiex/scan.c3025
-rw-r--r--drivers/net/wireless/mwifiex/sdio.c1754
-rw-r--r--drivers/net/wireless/mwifiex/sdio.h305
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmd.c1219
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmdresp.c972
-rw-r--r--drivers/net/wireless/mwifiex/sta_event.c406
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c1593
-rw-r--r--drivers/net/wireless/mwifiex/sta_rx.c200
-rw-r--r--drivers/net/wireless/mwifiex/sta_tx.c198
-rw-r--r--drivers/net/wireless/mwifiex/txrx.c202
-rw-r--r--drivers/net/wireless/mwifiex/util.c202
-rw-r--r--drivers/net/wireless/mwifiex/util.h32
-rw-r--r--drivers/net/wireless/mwifiex/wmm.c1264
-rw-r--r--drivers/net/wireless/mwifiex/wmm.h110
-rw-r--r--drivers/net/wireless/mwl8k.c875
-rw-r--r--drivers/net/wireless/orinoco/orinoco_cs.c2
-rw-r--r--drivers/net/wireless/orinoco/spectrum_cs.c2
-rw-r--r--drivers/net/wireless/p54/eeprom.c2
-rw-r--r--drivers/net/wireless/p54/fwio.c31
-rw-r--r--drivers/net/wireless/p54/lmac.h1
-rw-r--r--drivers/net/wireless/p54/main.c31
-rw-r--r--drivers/net/wireless/p54/p54.h2
-rw-r--r--drivers/net/wireless/p54/p54pci.c3
-rw-r--r--drivers/net/wireless/p54/p54usb.c1
-rw-r--r--drivers/net/wireless/ray_cs.c2
-rw-r--r--drivers/net/wireless/rndis_wlan.c3
-rw-r--r--drivers/net/wireless/rt2x00/Kconfig37
-rw-r--r--drivers/net/wireless/rt2x00/Makefile1
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c35
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c34
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c91
-rw-r--r--drivers/net/wireless/rt2x00/rt2800.h108
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c369
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.h1
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c267
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c632
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h122
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00config.c108
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00crypto.c4
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00debug.c43
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c139
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00firmware.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00ht.c133
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00lib.h57
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00link.c61
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c95
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.c19
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.h17
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c177
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.h34
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c129
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.h33
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c70
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c192
-rw-r--r--drivers/net/wireless/rtlwifi/Kconfig15
-rw-r--r--drivers/net/wireless/rtlwifi/Makefile1
-rw-r--r--drivers/net/wireless/rtlwifi/base.c733
-rw-r--r--drivers/net/wireless/rtlwifi/base.h60
-rw-r--r--drivers/net/wireless/rtlwifi/cam.c106
-rw-r--r--drivers/net/wireless/rtlwifi/cam.h5
-rw-r--r--drivers/net/wireless/rtlwifi/core.c418
-rw-r--r--drivers/net/wireless/rtlwifi/core.h1
-rw-r--r--drivers/net/wireless/rtlwifi/efuse.c234
-rw-r--r--drivers/net/wireless/rtlwifi/efuse.h5
-rw-r--r--drivers/net/wireless/rtlwifi/pci.c609
-rw-r--r--drivers/net/wireless/rtlwifi/pci.h19
-rw-r--r--drivers/net/wireless/rtlwifi/ps.c261
-rw-r--r--drivers/net/wireless/rtlwifi/ps.h9
-rw-r--r--drivers/net/wireless/rtlwifi/rc.c212
-rw-r--r--drivers/net/wireless/rtlwifi/rc.h9
-rw-r--r--drivers/net/wireless/rtlwifi/regd.c97
-rw-r--r--drivers/net/wireless/rtlwifi/regd.h2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c525
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c115
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h4
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c126
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h76
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/def.h27
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/dm.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/dm.h1
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/hw.c513
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/hw.h34
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/led.c19
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/led.h3
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/phy.c166
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/phy.h56
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/reg.h58
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/rf.c28
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/rf.h17
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/sw.c122
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/sw.h14
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/trx.c180
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/trx.h11
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/hw.c13
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/hw.h5
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/phy.c14
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/phy.h14
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/rf.c4
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/rf.h4
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/sw.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/trx.c50
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/trx.h5
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/Makefile15
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/def.h598
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/dm.c733
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/dm.h164
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/fw.c654
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/fw.h375
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/hw.c2512
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/hw.h79
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/led.c149
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/led.h37
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/phy.c1740
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/phy.h101
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/reg.h1188
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/rf.c546
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/rf.h43
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/sw.c423
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/sw.h (renamed from drivers/net/wireless/iwlwifi/iwl-agn-led.h)19
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/table.c634
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/table.h49
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/trx.c976
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/trx.h45
-rw-r--r--drivers/net/wireless/rtlwifi/usb.c19
-rw-r--r--drivers/net/wireless/rtlwifi/usb.h2
-rw-r--r--drivers/net/wireless/rtlwifi/wifi.h173
-rw-r--r--drivers/net/wireless/wl1251/cmd.h4
-rw-r--r--drivers/net/wireless/wl1251/event.c6
-rw-r--r--drivers/net/wireless/wl1251/main.c22
-rw-r--r--drivers/net/wireless/wl1251/ps.c23
-rw-r--r--drivers/net/wireless/wl1251/ps.h2
-rw-r--r--drivers/net/wireless/wl1251/wl1251.h9
-rw-r--r--drivers/net/wireless/wl12xx/Kconfig2
-rw-r--r--drivers/net/wireless/wl12xx/acx.c201
-rw-r--r--drivers/net/wireless/wl12xx/acx.h102
-rw-r--r--drivers/net/wireless/wl12xx/boot.c283
-rw-r--r--drivers/net/wireless/wl12xx/boot.h52
-rw-r--r--drivers/net/wireless/wl12xx/cmd.c113
-rw-r--r--drivers/net/wireless/wl12xx/cmd.h34
-rw-r--r--drivers/net/wireless/wl12xx/conf.h116
-rw-r--r--drivers/net/wireless/wl12xx/debugfs.c242
-rw-r--r--drivers/net/wireless/wl12xx/event.c34
-rw-r--r--drivers/net/wireless/wl12xx/event.h5
-rw-r--r--drivers/net/wireless/wl12xx/ini.h98
-rw-r--r--drivers/net/wireless/wl12xx/init.c149
-rw-r--r--drivers/net/wireless/wl12xx/init.h3
-rw-r--r--drivers/net/wireless/wl12xx/io.c11
-rw-r--r--drivers/net/wireless/wl12xx/io.h3
-rw-r--r--drivers/net/wireless/wl12xx/main.c827
-rw-r--r--drivers/net/wireless/wl12xx/ps.c33
-rw-r--r--drivers/net/wireless/wl12xx/ps.h2
-rw-r--r--drivers/net/wireless/wl12xx/reg.h15
-rw-r--r--drivers/net/wireless/wl12xx/rx.c80
-rw-r--r--drivers/net/wireless/wl12xx/scan.c260
-rw-r--r--drivers/net/wireless/wl12xx/scan.h114
-rw-r--r--drivers/net/wireless/wl12xx/sdio.c95
-rw-r--r--drivers/net/wireless/wl12xx/sdio_test.c20
-rw-r--r--drivers/net/wireless/wl12xx/spi.c17
-rw-r--r--drivers/net/wireless/wl12xx/testmode.c6
-rw-r--r--drivers/net/wireless/wl12xx/tx.c245
-rw-r--r--drivers/net/wireless/wl12xx/tx.h62
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx.h78
-rw-r--r--drivers/net/wireless/wl3501_cs.c2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c262
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.h533
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf.h2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_al2230.c198
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_al7230b.c240
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_rf2959.c78
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_uw2453.c86
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c4
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.h2
-rw-r--r--drivers/net/xen-netback/common.h7
-rw-r--r--drivers/net/xen-netback/interface.c84
-rw-r--r--drivers/net/xen-netback/xenbus.c2
-rw-r--r--drivers/net/xen-netfront.c108
-rw-r--r--drivers/of/irq.c2
-rw-r--r--drivers/parport/parport_cs.c2
-rw-r--r--drivers/parport/parport_ip32.c1
-rw-r--r--drivers/parport/parport_pc.c2
-rw-r--r--drivers/pci/access.c18
-rw-r--r--drivers/pci/bus.c6
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c7
-rw-r--r--drivers/pci/hotplug/pcihp_slot.c45
-rw-r--r--drivers/pci/intel-iommu.c1
-rw-r--r--drivers/pci/iov.c1
-rw-r--r--drivers/pci/pci-sysfs.c62
-rw-r--r--drivers/pci/pci.c444
-rw-r--r--drivers/pci/pci.h40
-rw-r--r--drivers/pci/pcie/aer/aer_inject.c2
-rw-r--r--drivers/pci/pcie/aer/aerdrv.h9
-rw-r--r--drivers/pci/pcie/aspm.c21
-rw-r--r--drivers/pci/probe.c43
-rw-r--r--drivers/pci/quirks.c21
-rw-r--r--drivers/pci/remove.c2
-rw-r--r--drivers/pci/setup-bus.c125
-rw-r--r--drivers/pcmcia/ds.c6
-rw-r--r--drivers/pcmcia/sa1100_generic.c2
-rw-r--r--drivers/platform/x86/Kconfig9
-rw-r--r--drivers/platform/x86/Makefile1
-rw-r--r--drivers/platform/x86/ibm_rtl.c13
-rw-r--r--drivers/platform/x86/intel_ips.c13
-rw-r--r--drivers/platform/x86/mxm-wmi.c111
-rw-r--r--drivers/power/Kconfig16
-rw-r--r--drivers/power/Makefile2
-rw-r--r--drivers/power/bq27x00_battery.c11
-rw-r--r--drivers/power/ds2760_battery.c6
-rw-r--r--drivers/power/ds2780_battery.c853
-rw-r--r--drivers/power/gpio-charger.c15
-rw-r--r--drivers/power/intel_mid_battery.c2
-rw-r--r--drivers/power/isp1704_charger.c22
-rw-r--r--drivers/power/max8903_charger.c391
-rw-r--r--drivers/power/max8925_power.c10
-rw-r--r--drivers/power/test_power.c276
-rw-r--r--drivers/power/z2_battery.c20
-rw-r--r--drivers/ptp/Kconfig75
-rw-r--r--drivers/ptp/Makefile7
-rw-r--r--drivers/ptp/ptp_chardev.c159
-rw-r--r--drivers/ptp/ptp_clock.c343
-rw-r--r--drivers/ptp/ptp_ixp46x.c332
-rw-r--r--drivers/ptp/ptp_private.h92
-rw-r--r--drivers/ptp/ptp_sysfs.c230
-rw-r--r--drivers/regulator/88pm8607.c30
-rw-r--r--drivers/regulator/Kconfig13
-rw-r--r--drivers/regulator/Makefile2
-rw-r--r--drivers/regulator/ab3100.c3
-rw-r--r--drivers/regulator/core.c93
-rw-r--r--drivers/regulator/db8500-prcmu.c558
-rw-r--r--drivers/regulator/max8925-regulator.c11
-rw-r--r--drivers/regulator/max8997.c13
-rw-r--r--drivers/regulator/max8998.c26
-rw-r--r--drivers/regulator/mc13783-regulator.c9
-rw-r--r--drivers/regulator/mc13892-regulator.c25
-rw-r--r--drivers/regulator/mc13xxx-regulator-core.c2
-rw-r--r--drivers/regulator/tps6105x-regulator.c5
-rw-r--r--drivers/regulator/tps65023-regulator.c3
-rw-r--r--drivers/regulator/tps6507x-regulator.c3
-rw-r--r--drivers/regulator/tps65910-regulator.c993
-rw-r--r--drivers/regulator/twl-regulator.c564
-rw-r--r--drivers/regulator/wm831x-dcdc.c2
-rw-r--r--drivers/regulator/wm8400-regulator.c12
-rw-r--r--drivers/rtc/Kconfig66
-rw-r--r--drivers/rtc/Makefile7
-rw-r--r--drivers/rtc/class.c23
-rw-r--r--drivers/rtc/rtc-88pm860x.c427
-rw-r--r--drivers/rtc/rtc-em3027.c161
-rw-r--r--drivers/rtc/rtc-m41t93.c225
-rw-r--r--drivers/rtc/rtc-mrst.c4
-rw-r--r--drivers/rtc/rtc-mxc.c6
-rw-r--r--drivers/rtc/rtc-pcf50633.c23
-rw-r--r--drivers/rtc/rtc-rv3029c2.c454
-rw-r--r--drivers/rtc/rtc-spear.c534
-rw-r--r--drivers/rtc/rtc-tile.c162
-rw-r--r--drivers/rtc/rtc-vt8500.c366
-rw-r--r--drivers/s390/block/dasd_alias.c4
-rw-r--r--drivers/s390/block/dasd_diag.c6
-rw-r--r--drivers/s390/block/dasd_eckd.c11
-rw-r--r--drivers/s390/char/Kconfig12
-rw-r--r--drivers/s390/char/Makefile3
-rw-r--r--drivers/s390/char/monwriter.c4
-rw-r--r--drivers/s390/char/raw3270.c2
-rw-r--r--drivers/s390/char/sclp.c7
-rw-r--r--drivers/s390/char/sclp.h24
-rw-r--r--drivers/s390/char/sclp_config.c14
-rw-r--r--drivers/s390/char/sclp_ocf.c145
-rw-r--r--drivers/s390/char/sclp_sdias.c3
-rw-r--r--drivers/s390/char/sclp_tty.c122
-rw-r--r--drivers/s390/char/tape_3590.c11
-rw-r--r--drivers/s390/char/tape_block.c444
-rw-r--r--drivers/s390/char/tape_std.c3
-rw-r--r--drivers/s390/cio/chsc.c35
-rw-r--r--drivers/s390/cio/device_fsm.c8
-rw-r--r--drivers/s390/cio/device_ops.c3
-rw-r--r--drivers/s390/cio/qdio_main.c2
-rw-r--r--drivers/s390/crypto/ap_bus.c8
-rw-r--r--drivers/s390/kvm/kvm_virtio.c3
-rw-r--r--drivers/s390/net/claw.c22
-rw-r--r--drivers/s390/net/ctcm_main.c2
-rw-r--r--drivers/s390/net/ctcm_mpc.c13
-rw-r--r--drivers/s390/net/lcs.c10
-rw-r--r--drivers/s390/net/netiucv.c2
-rw-r--r--drivers/s390/net/qeth_core.h26
-rw-r--r--drivers/s390/net/qeth_core_main.c150
-rw-r--r--drivers/s390/net/qeth_core_mpc.h17
-rw-r--r--drivers/s390/net/qeth_core_sys.c61
-rw-r--r--drivers/s390/net/qeth_l2_main.c21
-rw-r--r--drivers/s390/net/qeth_l3.h2
-rw-r--r--drivers/s390/net/qeth_l3_main.c261
-rw-r--r--drivers/s390/net/qeth_l3_sys.c103
-rw-r--r--drivers/scsi/aacraid/linit.c3
-rw-r--r--drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c2
-rw-r--r--drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h2
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c138
-rw-r--r--drivers/scsi/be2iscsi/be.h10
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.c11
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.h10
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.c13
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.h13
-rw-r--r--drivers/scsi/be2iscsi/be_main.c55
-rw-r--r--drivers/scsi/be2iscsi/be_main.h15
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.c17
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.h13
-rw-r--r--drivers/scsi/bfa/bfad.c61
-rw-r--r--drivers/scsi/bfa/bfad_debugfs.c33
-rw-r--r--drivers/scsi/bfa/bfad_im.h25
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc.h2
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_fcoe.c46
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_hwi.c3
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_io.c6
-rw-r--r--drivers/scsi/constants.c3
-rw-r--r--drivers/scsi/cxgbi/libcxgbi.c10
-rw-r--r--drivers/scsi/dc395x.c193
-rw-r--r--drivers/scsi/device_handler/scsi_dh_alua.c2
-rw-r--r--drivers/scsi/device_handler/scsi_dh_rdac.c72
-rw-r--r--drivers/scsi/dpt_i2o.c6
-rw-r--r--drivers/scsi/eata.c66
-rw-r--r--drivers/scsi/eata_pio.c19
-rw-r--r--drivers/scsi/esp_scsi.c8
-rw-r--r--drivers/scsi/fcoe/fcoe.c213
-rw-r--r--drivers/scsi/fcoe/fcoe_ctlr.c6
-rw-r--r--drivers/scsi/fcoe/fcoe_transport.c56
-rw-r--r--drivers/scsi/hpsa.c496
-rw-r--r--drivers/scsi/hpsa.h15
-rw-r--r--drivers/scsi/hpsa_cmd.h11
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c3
-rw-r--r--drivers/scsi/in2000.c31
-rw-r--r--drivers/scsi/ipr.c158
-rw-r--r--drivers/scsi/ipr.h22
-rw-r--r--drivers/scsi/libfc/fc_fcp.c57
-rw-r--r--drivers/scsi/libfc/fc_lport.c1
-rw-r--r--drivers/scsi/lpfc/lpfc.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c2
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.c61
-rw-r--r--drivers/scsi/lpfc/lpfc_bsg.h130
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.c931
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.h48
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c44
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c6
-rw-r--r--drivers/scsi/lpfc/lpfc_hw.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_hw4.h18
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c19
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c2
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c14
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c34
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/megaraid.c20
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.c37
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c13
-rw-r--r--drivers/scsi/mesh.c3
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c42
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.h49
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.c5
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.h1
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_scsih.c617
-rw-r--r--drivers/scsi/mvsas/Kconfig1
-rw-r--r--drivers/scsi/mvsas/Makefile1
-rw-r--r--drivers/scsi/mvsas/mv_64xx.c1
-rw-r--r--drivers/scsi/mvsas/mv_64xx.h1
-rw-r--r--drivers/scsi/mvsas/mv_94xx.c1
-rw-r--r--drivers/scsi/mvsas/mv_94xx.h1
-rw-r--r--drivers/scsi/mvsas/mv_chips.h1
-rw-r--r--drivers/scsi/mvsas/mv_defs.h3
-rw-r--r--drivers/scsi/mvsas/mv_init.c67
-rw-r--r--drivers/scsi/mvsas/mv_sas.c383
-rw-r--r--drivers/scsi/mvsas/mv_sas.h8
-rw-r--r--drivers/scsi/ncr53c8xx.c2
-rw-r--r--drivers/scsi/nsp32_debug.c2
-rw-r--r--drivers/scsi/pcmcia/aha152x_stub.c2
-rw-r--r--drivers/scsi/pcmcia/fdomain_stub.c2
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c2
-rw-r--r--drivers/scsi/pcmcia/nsp_debug.c2
-rw-r--r--drivers/scsi/pcmcia/qlogic_stub.c2
-rw-r--r--drivers/scsi/pcmcia/sym53c500_cs.c2
-rw-r--r--drivers/scsi/pm8001/pm8001_init.c2
-rw-r--r--drivers/scsi/pmcraid.c9
-rw-r--r--drivers/scsi/pmcraid.h1
-rw-r--r--drivers/scsi/qla1280.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c23
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.h2
-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.h10
-rw-r--r--drivers/scsi/qla2xxx/qla_dfs.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_fw.h5
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h18
-rw-r--r--drivers/scsi/qla2xxx/qla_gs.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c54
-rw-r--r--drivers/scsi/qla2xxx/qla_inline.h21
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c47
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c151
-rw-r--r--drivers/scsi/qla2xxx/qla_mid.c6
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.c97
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c85
-rw-r--r--drivers/scsi/qla2xxx/qla_settings.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h6
-rw-r--r--drivers/scsi/qla4xxx/ql4_mbx.c2
-rw-r--r--drivers/scsi/qla4xxx/ql4_nx.c21
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c5
-rw-r--r--drivers/scsi/scsi_error.c6
-rw-r--r--drivers/scsi/scsi_proc.c58
-rw-r--r--drivers/scsi/scsi_tgt_lib.c6
-rw-r--r--drivers/scsi/scsi_transport_fc.c11
-rw-r--r--drivers/scsi/sgiwd93.c2
-rw-r--r--drivers/scsi/sr.c2
-rw-r--r--drivers/scsi/tmscsim.c22
-rw-r--r--drivers/scsi/u14-34f.c61
-rw-r--r--drivers/scsi/wd33c93.c52
-rw-r--r--drivers/sh/clk/cpg.c2
-rw-r--r--drivers/sh/intc/virq.c5
-rw-r--r--drivers/spi/Kconfig4
-rw-r--r--drivers/spi/amba-pl022.c35
-rw-r--r--drivers/spi/atmel_spi.c2
-rw-r--r--drivers/spi/coldfire_qspi.c1
-rw-r--r--drivers/spi/dw_spi.c202
-rw-r--r--drivers/spi/dw_spi.h2
-rw-r--r--drivers/spi/spi.c4
-rw-r--r--drivers/spi/spi_nuc900.c2
-rw-r--r--drivers/spi/spi_s3c24xx.c2
-rw-r--r--drivers/spi/spi_sh.c2
-rw-r--r--drivers/spi/spi_tegra.c2
-rw-r--r--drivers/spi/xilinx_spi.c3
-rw-r--r--drivers/ssb/driver_chipcommon.c68
-rw-r--r--drivers/ssb/driver_chipcommon_pmu.c2
-rw-r--r--drivers/ssb/driver_pcicore.c255
-rw-r--r--drivers/ssb/main.c54
-rw-r--r--drivers/ssb/pci.c16
-rw-r--r--drivers/ssb/scan.c7
-rw-r--r--drivers/ssb/sprom.c43
-rw-r--r--drivers/ssb/ssb_private.h3
-rw-r--r--drivers/staging/Kconfig8
-rw-r--r--drivers/staging/Makefile9
-rw-r--r--drivers/staging/ath6kl/Kconfig6
-rw-r--r--drivers/staging/ath6kl/Makefile39
-rw-r--r--drivers/staging/ath6kl/bmi/include/bmi_internal.h3
-rw-r--r--drivers/staging/ath6kl/bmi/src/bmi.c8
-rw-r--r--drivers/staging/ath6kl/hif/sdio/linux_sdio/include/hif_internal.h1
-rw-r--r--drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif.c382
-rw-r--r--drivers/staging/ath6kl/hif/sdio/linux_sdio/src/hif_scatter.c10
-rw-r--r--drivers/staging/ath6kl/htc2/AR6000/ar6k.c5
-rw-r--r--drivers/staging/ath6kl/htc2/AR6000/ar6k.h3
-rw-r--r--drivers/staging/ath6kl/htc2/AR6000/ar6k_events.c3
-rw-r--r--drivers/staging/ath6kl/htc2/AR6000/ar6k_gmbox.c1
-rw-r--r--drivers/staging/ath6kl/htc2/AR6000/ar6k_gmbox_hciuart.c3
-rw-r--r--drivers/staging/ath6kl/htc2/htc.c10
-rw-r--r--drivers/staging/ath6kl/htc2/htc_internal.h9
-rw-r--r--drivers/staging/ath6kl/htc2/htc_recv.c6
-rw-r--r--drivers/staging/ath6kl/htc2/htc_send.c5
-rw-r--r--drivers/staging/ath6kl/include/a_config.h22
-rw-r--r--drivers/staging/ath6kl/include/a_debug.h29
-rw-r--r--drivers/staging/ath6kl/include/a_drv.h22
-rw-r--r--drivers/staging/ath6kl/include/a_drv_api.h28
-rw-r--r--drivers/staging/ath6kl/include/a_osapi.h29
-rw-r--r--drivers/staging/ath6kl/include/a_types.h58
-rw-r--r--drivers/staging/ath6kl/include/ar6000_api.h22
-rw-r--r--drivers/staging/ath6kl/include/athendpack.h52
-rw-r--r--drivers/staging/ath6kl/include/athstartpack.h55
-rw-r--r--drivers/staging/ath6kl/include/bmi.h1
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/AR6002_regdump.h60
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw2.0/hw/analog_intf_reg.h64
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw2.0/hw/analog_reg.h1932
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw2.0/hw/apb_map.h13
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw2.0/hw/gpio_reg.h977
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw2.0/hw/mbox_host_reg.h386
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw2.0/hw/mbox_reg.h481
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw2.0/hw/rtc_reg.h1163
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw2.0/hw/si_reg.h186
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw2.0/hw/uart_reg.h327
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw2.0/hw/vmc_reg.h76
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/analog_intf_ares_reg.h3291
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/analog_intf_athr_wlan_reg.h3674
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/analog_intf_reg.h37
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/apb_map.h8
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/bb_lc_reg.h7076
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/efuse_reg.h108
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/gpio_athr_wlan_reg.h1253
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/gpio_reg.h1094
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/mac_dma_reg.h605
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/mac_pcu_reg.h3065
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/mbox_host_reg.h13
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/mbox_reg.h8
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/mbox_wlan_host_reg.h51
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/mbox_wlan_reg.h49
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/rdma_reg.h564
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/rtc_reg.h788
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/rtc_wlan_reg.h1903
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/si_reg.h209
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/uart_reg.h220
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/umbox_reg.h37
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/umbox_wlan_reg.h322
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/vmc_reg.h167
-rw-r--r--drivers/staging/ath6kl/include/common/AR6002/hw4.0/hw/vmc_wlan_reg.h195
-rw-r--r--drivers/staging/ath6kl/include/common/a_hci.h682
-rw-r--r--drivers/staging/ath6kl/include/common/bmi_msg.h8
-rw-r--r--drivers/staging/ath6kl/include/common/btcoexGpio.h86
-rw-r--r--drivers/staging/ath6kl/include/common/dbglog.h8
-rw-r--r--drivers/staging/ath6kl/include/common/dset_internal.h63
-rw-r--r--drivers/staging/ath6kl/include/common/dsetid.h134
-rw-r--r--drivers/staging/ath6kl/include/common/epping_test.h9
-rw-r--r--drivers/staging/ath6kl/include/common/gmboxif.h8
-rw-r--r--drivers/staging/ath6kl/include/common/gpio.h45
-rw-r--r--drivers/staging/ath6kl/include/common/gpio_reg.h9
-rw-r--r--drivers/staging/ath6kl/include/common/htc.h9
-rw-r--r--drivers/staging/ath6kl/include/common/ini_dset.h82
-rw-r--r--drivers/staging/ath6kl/include/common/regDb.h29
-rw-r--r--drivers/staging/ath6kl/include/common/regdump.h59
-rw-r--r--drivers/staging/ath6kl/include/common/regulatory/reg_dbschema.h237
-rw-r--r--drivers/staging/ath6kl/include/common/regulatory/reg_dbvalues.h504
-rw-r--r--drivers/staging/ath6kl/include/common/targaddrs.h234
-rw-r--r--drivers/staging/ath6kl/include/common/wlan_dset.h33
-rw-r--r--drivers/staging/ath6kl/include/common/wmi.h135
-rw-r--r--drivers/staging/ath6kl/include/common/wmi_thin.h347
-rw-r--r--drivers/staging/ath6kl/include/common/wmix.h8
-rw-r--r--drivers/staging/ath6kl/include/common_drv.h4
-rw-r--r--drivers/staging/ath6kl/include/gpio_api.h59
-rw-r--r--drivers/staging/ath6kl/include/hif.h3
-rw-r--r--drivers/staging/ath6kl/include/target_reg_table.h244
-rw-r--r--drivers/staging/ath6kl/miscdrv/ar3kconfig.c23
-rw-r--r--drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsconfig.c22
-rw-r--r--drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.c28
-rw-r--r--drivers/staging/ath6kl/miscdrv/ar3kps/ar3kpsparser.h6
-rw-r--r--drivers/staging/ath6kl/miscdrv/common_drv.c126
-rw-r--r--drivers/staging/ath6kl/miscdrv/credit_dist.c1
-rw-r--r--drivers/staging/ath6kl/os/linux/ar6000_android.c388
-rw-r--r--drivers/staging/ath6kl/os/linux/ar6000_drv.c793
-rw-r--r--drivers/staging/ath6kl/os/linux/ar6000_pm.c77
-rw-r--r--drivers/staging/ath6kl/os/linux/ar6k_pal.c479
-rw-r--r--drivers/staging/ath6kl/os/linux/cfg80211.c342
-rw-r--r--drivers/staging/ath6kl/os/linux/eeprom.c574
-rw-r--r--drivers/staging/ath6kl/os/linux/export_hci_transport.c1
-rw-r--r--drivers/staging/ath6kl/os/linux/hci_bridge.c5
-rw-r--r--drivers/staging/ath6kl/os/linux/include/ar6000_drv.h152
-rw-r--r--drivers/staging/ath6kl/os/linux/include/ar6xapi_linux.h8
-rw-r--r--drivers/staging/ath6kl/os/linux/include/athdrv_linux.h4
-rw-r--r--drivers/staging/ath6kl/os/linux/include/athtypes_linux.h51
-rw-r--r--drivers/staging/ath6kl/os/linux/include/config_linux.h7
-rw-r--r--drivers/staging/ath6kl/os/linux/include/osapi_linux.h49
-rw-r--r--drivers/staging/ath6kl/os/linux/include/wlan_config.h10
-rw-r--r--drivers/staging/ath6kl/os/linux/include/wmi_filter_linux.h2
-rw-r--r--drivers/staging/ath6kl/os/linux/ioctl.c4767
-rw-r--r--drivers/staging/ath6kl/os/linux/netbuf.c1
-rw-r--r--drivers/staging/ath6kl/os/linux/wireless_ext.c2723
-rw-r--r--drivers/staging/ath6kl/reorder/rcv_aggr.c15
-rw-r--r--drivers/staging/ath6kl/wlan/include/ieee80211.h4
-rw-r--r--drivers/staging/ath6kl/wlan/src/wlan_node.c11
-rw-r--r--drivers/staging/ath6kl/wlan/src/wlan_recv_beacon.c1
-rw-r--r--drivers/staging/ath6kl/wlan/src/wlan_utils.c1
-rw-r--r--drivers/staging/ath6kl/wmi/wmi.c248
-rw-r--r--drivers/staging/brcm80211/Kconfig21
-rw-r--r--drivers/staging/brcm80211/Makefile1
-rw-r--r--drivers/staging/brcm80211/README102
-rw-r--r--drivers/staging/brcm80211/TODO56
-rw-r--r--drivers/staging/brcm80211/brcmfmac/Makefile13
-rw-r--r--drivers/staging/brcm80211/brcmfmac/README35
-rw-r--r--drivers/staging/brcm80211/brcmfmac/bcmchip.h (renamed from drivers/staging/brcm80211/util/siutils_priv.h)33
-rw-r--r--drivers/staging/brcm80211/brcmfmac/bcmsdh.c38
-rw-r--r--drivers/staging/brcm80211/brcmfmac/bcmsdh_linux.c10
-rw-r--r--drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc.c55
-rw-r--r--drivers/staging/brcm80211/brcmfmac/bcmsdh_sdmmc_linux.c7
-rw-r--r--drivers/staging/brcm80211/brcmfmac/bcmutils.c1
-rw-r--r--drivers/staging/brcm80211/brcmfmac/bcmwifi.c1
-rw-r--r--drivers/staging/brcm80211/brcmfmac/dhd.h32
-rw-r--r--drivers/staging/brcm80211/brcmfmac/dhd_cdc.c16
-rw-r--r--drivers/staging/brcm80211/brcmfmac/dhd_common.c50
-rw-r--r--drivers/staging/brcm80211/brcmfmac/dhd_linux.c121
-rw-r--r--drivers/staging/brcm80211/brcmfmac/dhd_sdio.c1132
-rw-r--r--drivers/staging/brcm80211/brcmfmac/hndpmu.c1
-rw-r--r--drivers/staging/brcm80211/brcmfmac/sbutils.c1
-rw-r--r--drivers/staging/brcm80211/brcmfmac/siutils.c1
-rw-r--r--drivers/staging/brcm80211/brcmfmac/wl_cfg80211.c1626
-rw-r--r--drivers/staging/brcm80211/brcmfmac/wl_cfg80211.h75
-rw-r--r--drivers/staging/brcm80211/brcmfmac/wl_iw.c161
-rw-r--r--drivers/staging/brcm80211/brcmsmac/Makefile22
-rw-r--r--drivers/staging/brcm80211/brcmsmac/aiutils.c (renamed from drivers/staging/brcm80211/util/siutils.c)1564
-rw-r--r--drivers/staging/brcm80211/brcmsmac/aiutils.h546
-rw-r--r--drivers/staging/brcm80211/brcmsmac/bcmotp.c (renamed from drivers/staging/brcm80211/util/bcmotp.c)127
-rw-r--r--drivers/staging/brcm80211/brcmsmac/bcmsrom.c714
-rw-r--r--drivers/staging/brcm80211/brcmsmac/bcmsrom_tbl.h (renamed from drivers/staging/brcm80211/util/bcmsrom_tbl.h)70
-rw-r--r--drivers/staging/brcm80211/brcmsmac/d11.h2
-rw-r--r--drivers/staging/brcm80211/brcmsmac/hnddma.c (renamed from drivers/staging/brcm80211/util/hnddma.c)110
-rw-r--r--drivers/staging/brcm80211/brcmsmac/nicpci.c (renamed from drivers/staging/brcm80211/util/nicpci.c)77
-rw-r--r--drivers/staging/brcm80211/brcmsmac/nvram.c (renamed from drivers/staging/brcm80211/util/nvram/nvram_ro.c)94
-rw-r--r--drivers/staging/brcm80211/brcmsmac/phy/wlc_phy_cmn.c182
-rw-r--r--drivers/staging/brcm80211/brcmsmac/phy/wlc_phy_hal.h5
-rw-r--r--drivers/staging/brcm80211/brcmsmac/phy/wlc_phy_int.h4
-rw-r--r--drivers/staging/brcm80211/brcmsmac/phy/wlc_phy_lcn.c51
-rw-r--r--drivers/staging/brcm80211/brcmsmac/phy/wlc_phy_n.c173
-rw-r--r--drivers/staging/brcm80211/brcmsmac/phy/wlc_phy_qmath.c296
-rw-r--r--drivers/staging/brcm80211/brcmsmac/phy/wlc_phy_qmath.h (renamed from drivers/staging/brcm80211/include/qmath.h)38
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wl_dbg.h24
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wl_export.h1
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wl_mac80211.c469
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wl_mac80211.h5
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wlc_alloc.c74
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wlc_alloc.h2
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wlc_ampdu.c362
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wlc_ampdu.h3
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wlc_antsel.c15
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wlc_bmac.c692
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wlc_bmac.h6
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wlc_bsscfg.h3
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wlc_channel.c73
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wlc_key.h10
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wlc_main.c1869
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wlc_main.h41
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wlc_phy_shim.c9
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wlc_pmu.c (renamed from drivers/staging/brcm80211/util/hndpmu.c)2616
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wlc_pmu.h (renamed from drivers/staging/brcm80211/include/hndpmu.h)54
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wlc_pub.h52
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wlc_rate.c20
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wlc_rate.h15
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wlc_scb.h2
-rw-r--r--drivers/staging/brcm80211/brcmsmac/wlc_stf.c62
-rw-r--r--drivers/staging/brcm80211/include/aidmp.h6
-rw-r--r--drivers/staging/brcm80211/include/bcmdefs.h12
-rw-r--r--drivers/staging/brcm80211/include/bcmdevs.h72
-rw-r--r--drivers/staging/brcm80211/include/bcmnvram.h29
-rw-r--r--drivers/staging/brcm80211/include/bcmsdpcm.h3
-rw-r--r--drivers/staging/brcm80211/include/bcmsrom_fmt.h2
-rw-r--r--drivers/staging/brcm80211/include/bcmutils.h189
-rw-r--r--drivers/staging/brcm80211/include/bcmwifi.h6
-rw-r--r--drivers/staging/brcm80211/include/hnddma.h19
-rw-r--r--drivers/staging/brcm80211/include/pci_core.h (renamed from drivers/staging/brcm80211/util/pci_core.h)0
-rw-r--r--drivers/staging/brcm80211/include/pcicfg.h510
-rw-r--r--drivers/staging/brcm80211/include/sbchipc.h6
-rw-r--r--drivers/staging/brcm80211/include/siutils.h361
-rw-r--r--drivers/staging/brcm80211/include/wlioctl.h349
-rw-r--r--drivers/staging/brcm80211/util/Makefile29
-rw-r--r--drivers/staging/brcm80211/util/aiutils.c705
-rw-r--r--drivers/staging/brcm80211/util/bcmsrom.c2088
-rw-r--r--drivers/staging/brcm80211/util/bcmutils.c484
-rw-r--r--drivers/staging/brcm80211/util/bcmwifi.c13
-rw-r--r--drivers/staging/brcm80211/util/qmath.c681
-rw-r--r--drivers/staging/brcm80211/util/sbpcmcia.h217
-rw-r--r--drivers/staging/brcm80211/util/sbsocram.h175
-rw-r--r--drivers/staging/brcm80211/util/sbutils.c476
-rw-r--r--drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c16
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_common.c61
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_common.h17
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_eeprom.c36
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci16xx.c10
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c27
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c24
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9118.c4
-rw-r--r--drivers/staging/comedi/drivers/adv_pci_dio.c3
-rw-r--r--drivers/staging/comedi/drivers/cb_das16_cs.c2
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidda.c2
-rw-r--r--drivers/staging/comedi/drivers/cb_pcimdas.c2
-rw-r--r--drivers/staging/comedi/drivers/das08_cs.c2
-rw-r--r--drivers/staging/comedi/drivers/jr3_pci.c27
-rw-r--r--drivers/staging/comedi/drivers/ni_660x.c2
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_700.c2
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_dio24.c2
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc_cs.c2
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_common.c6
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_cs.c2
-rw-r--r--drivers/staging/comedi/drivers/ni_tio.c6
-rw-r--r--drivers/staging/comedi/drivers/pcl724.c2
-rw-r--r--drivers/staging/comedi/drivers/pcl818.c2
-rw-r--r--drivers/staging/comedi/drivers/pcm3724.c2
-rw-r--r--drivers/staging/comedi/drivers/quatech_daqp_cs.c2
-rw-r--r--drivers/staging/comedi/drivers/usbdux.c2
-rw-r--r--drivers/staging/comedi/drivers/vmk80xx.c343
-rw-r--r--drivers/staging/cptm1217/clearpad_tm1217.c5
-rw-r--r--drivers/staging/crystalhd/bc_dts_types.h1
-rw-r--r--drivers/staging/crystalhd/crystalhd_misc.c4
-rw-r--r--drivers/staging/cx25821/cx25821-video.c3
-rw-r--r--drivers/staging/easycap/easycap_main.c479
-rw-r--r--drivers/staging/echo/echo.c26
-rw-r--r--drivers/staging/ft1000/ft1000-pcmcia/ft1000_cs.c2
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_hw.c158
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_usb.h19
-rw-r--r--drivers/staging/generic_serial/rio/rioinit.c2
-rw-r--r--drivers/staging/gma500/Makefile15
-rw-r--r--drivers/staging/gma500/mrst.h217
-rw-r--r--drivers/staging/gma500/mrst_crtc.c619
-rw-r--r--drivers/staging/gma500/mrst_lvds.c371
-rw-r--r--drivers/staging/gma500/psb_2d.c9
-rw-r--r--drivers/staging/gma500/psb_bl.c118
-rw-r--r--drivers/staging/gma500/psb_buffer.c450
-rw-r--r--drivers/staging/gma500/psb_drm.h122
-rw-r--r--drivers/staging/gma500/psb_drv.c765
-rw-r--r--drivers/staging/gma500/psb_drv.h462
-rw-r--r--drivers/staging/gma500/psb_fb.c365
-rw-r--r--drivers/staging/gma500/psb_fb.h16
-rw-r--r--drivers/staging/gma500/psb_fence.c122
-rw-r--r--drivers/staging/gma500/psb_gem.c320
-rw-r--r--drivers/staging/gma500/psb_gtt.c1263
-rw-r--r--drivers/staging/gma500/psb_gtt.h84
-rw-r--r--drivers/staging/gma500/psb_intel_display.c147
-rw-r--r--drivers/staging/gma500/psb_intel_drv.h13
-rw-r--r--drivers/staging/gma500/psb_intel_lvds.c50
-rw-r--r--drivers/staging/gma500/psb_intel_sdvo.c4
-rw-r--r--drivers/staging/gma500/psb_irq.c178
-rw-r--r--drivers/staging/gma500/psb_lid.c (renamed from drivers/staging/gma500/psb_reset.c)0
-rw-r--r--drivers/staging/gma500/psb_mmu.c61
-rw-r--r--drivers/staging/gma500/psb_powermgmt.c755
-rw-r--r--drivers/staging/gma500/psb_powermgmt.h55
-rw-r--r--drivers/staging/gma500/psb_pvr_glue.c73
-rw-r--r--drivers/staging/gma500/psb_pvr_glue.h25
-rw-r--r--drivers/staging/gma500/psb_sgx.c238
-rw-r--r--drivers/staging/gma500/psb_sgx.h32
-rw-r--r--drivers/staging/gma500/psb_ttm_fence.c605
-rw-r--r--drivers/staging/gma500/psb_ttm_fence_api.h272
-rw-r--r--drivers/staging/gma500/psb_ttm_fence_driver.h302
-rw-r--r--drivers/staging/gma500/psb_ttm_fence_user.c237
-rw-r--r--drivers/staging/gma500/psb_ttm_fence_user.h140
-rw-r--r--drivers/staging/gma500/psb_ttm_glue.c349
-rw-r--r--drivers/staging/gma500/psb_ttm_placement_user.c628
-rw-r--r--drivers/staging/gma500/psb_ttm_placement_user.h252
-rw-r--r--drivers/staging/gma500/psb_ttm_userobj_api.h85
-rw-r--r--drivers/staging/hv/Kconfig4
-rw-r--r--drivers/staging/hv/Makefile2
-rw-r--r--drivers/staging/hv/blkvsc.c102
-rw-r--r--drivers/staging/hv/blkvsc_drv.c1465
-rw-r--r--drivers/staging/hv/channel.c230
-rw-r--r--drivers/staging/hv/channel.h112
-rw-r--r--drivers/staging/hv/channel_mgmt.c201
-rw-r--r--drivers/staging/hv/channel_mgmt.h320
-rw-r--r--drivers/staging/hv/connection.c108
-rw-r--r--drivers/staging/hv/hv.c111
-rw-r--r--drivers/staging/hv/hv.h140
-rw-r--r--drivers/staging/hv/hv_api.h910
-rw-r--r--drivers/staging/hv/hv_kvp.c20
-rw-r--r--drivers/staging/hv/hv_mouse.c502
-rw-r--r--drivers/staging/hv/hv_timesource.c3
-rw-r--r--drivers/staging/hv/hv_util.c81
-rw-r--r--drivers/staging/hv/hyperv.h944
-rw-r--r--drivers/staging/hv/hyperv_net.h (renamed from drivers/staging/hv/rndis.h)422
-rw-r--r--drivers/staging/hv/hyperv_storage.h (renamed from drivers/staging/hv/vstorage.h)144
-rw-r--r--drivers/staging/hv/hyperv_vmbus.h631
-rw-r--r--drivers/staging/hv/logging.h98
-rw-r--r--drivers/staging/hv/netvsc.c901
-rw-r--r--drivers/staging/hv/netvsc.h332
-rw-r--r--drivers/staging/hv/netvsc_api.h116
-rw-r--r--drivers/staging/hv/netvsc_drv.c193
-rw-r--r--drivers/staging/hv/ring_buffer.c526
-rw-r--r--drivers/staging/hv/ring_buffer.h102
-rw-r--r--drivers/staging/hv/rndis_filter.c187
-rw-r--r--drivers/staging/hv/rndis_filter.h55
-rw-r--r--drivers/staging/hv/storvsc.c547
-rw-r--r--drivers/staging/hv/storvsc_api.h110
-rw-r--r--drivers/staging/hv/storvsc_drv.c967
-rw-r--r--drivers/staging/hv/utils.h120
-rw-r--r--drivers/staging/hv/version_info.h48
-rw-r--r--drivers/staging/hv/vmbus.h51
-rw-r--r--drivers/staging/hv/vmbus_api.h139
-rw-r--r--drivers/staging/hv/vmbus_channel_interface.h89
-rw-r--r--drivers/staging/hv/vmbus_drv.c1090
-rw-r--r--drivers/staging/hv/vmbus_packet_format.h161
-rw-r--r--drivers/staging/hv/vmbus_private.h134
-rw-r--r--drivers/staging/iio/Documentation/device.txt78
-rw-r--r--drivers/staging/iio/Documentation/generic_buffer.c95
-rw-r--r--drivers/staging/iio/Documentation/iio_utils.h20
-rw-r--r--drivers/staging/iio/Documentation/overview.txt19
-rw-r--r--drivers/staging/iio/Documentation/ring.txt44
-rw-r--r--drivers/staging/iio/Documentation/sysfs-bus-iio13
-rw-r--r--drivers/staging/iio/Documentation/sysfs-bus-iio-light13
-rw-r--r--drivers/staging/iio/Documentation/sysfs-bus-iio-light-tsl258320
-rw-r--r--drivers/staging/iio/Documentation/trigger.txt16
-rw-r--r--drivers/staging/iio/Documentation/userspace.txt12
-rw-r--r--drivers/staging/iio/Kconfig15
-rw-r--r--drivers/staging/iio/accel/adis16201.h9
-rw-r--r--drivers/staging/iio/accel/adis16201_core.c489
-rw-r--r--drivers/staging/iio/accel/adis16201_ring.c146
-rw-r--r--drivers/staging/iio/accel/adis16201_trigger.c82
-rw-r--r--drivers/staging/iio/accel/adis16203.h18
-rw-r--r--drivers/staging/iio/accel/adis16203_core.c411
-rw-r--r--drivers/staging/iio/accel/adis16203_ring.c123
-rw-r--r--drivers/staging/iio/accel/adis16203_trigger.c83
-rw-r--r--drivers/staging/iio/accel/adis16204.h18
-rw-r--r--drivers/staging/iio/accel/adis16204_core.c434
-rw-r--r--drivers/staging/iio/accel/adis16204_ring.c126
-rw-r--r--drivers/staging/iio/accel/adis16204_trigger.c83
-rw-r--r--drivers/staging/iio/accel/adis16209.h6
-rw-r--r--drivers/staging/iio/accel/adis16209_core.c468
-rw-r--r--drivers/staging/iio/accel/adis16209_ring.c143
-rw-r--r--drivers/staging/iio/accel/adis16209_trigger.c77
-rw-r--r--drivers/staging/iio/accel/adis16220_core.c13
-rw-r--r--drivers/staging/iio/accel/adis16240.h7
-rw-r--r--drivers/staging/iio/accel/adis16240_core.c390
-rw-r--r--drivers/staging/iio/accel/adis16240_ring.c131
-rw-r--r--drivers/staging/iio/accel/adis16240_trigger.c78
-rw-r--r--drivers/staging/iio/accel/kxsd9.c14
-rw-r--r--drivers/staging/iio/accel/lis3l02dq.h46
-rw-r--r--drivers/staging/iio/accel/lis3l02dq_core.c844
-rw-r--r--drivers/staging/iio/accel/lis3l02dq_ring.c504
-rw-r--r--drivers/staging/iio/accel/sca3000.h76
-rw-r--r--drivers/staging/iio/accel/sca3000_core.c955
-rw-r--r--drivers/staging/iio/accel/sca3000_ring.c269
-rw-r--r--drivers/staging/iio/adc/Kconfig60
-rw-r--r--drivers/staging/iio/adc/Makefile1
-rw-r--r--drivers/staging/iio/adc/ad7150.c178
-rw-r--r--drivers/staging/iio/adc/ad7152.c33
-rw-r--r--drivers/staging/iio/adc/ad7291.c502
-rw-r--r--drivers/staging/iio/adc/ad7298.h12
-rw-r--r--drivers/staging/iio/adc/ad7298_core.c242
-rw-r--r--drivers/staging/iio/adc/ad7298_ring.c134
-rw-r--r--drivers/staging/iio/adc/ad7314.c35
-rw-r--r--drivers/staging/iio/adc/ad7476.h7
-rw-r--r--drivers/staging/iio/adc/ad7476_core.c173
-rw-r--r--drivers/staging/iio/adc/ad7476_ring.c127
-rw-r--r--drivers/staging/iio/adc/ad7606.h20
-rw-r--r--drivers/staging/iio/adc/ad7606_core.c300
-rw-r--r--drivers/staging/iio/adc/ad7606_par.c30
-rw-r--r--drivers/staging/iio/adc/ad7606_ring.c152
-rw-r--r--drivers/staging/iio/adc/ad7606_spi.c24
-rw-r--r--drivers/staging/iio/adc/ad7745.c121
-rw-r--r--drivers/staging/iio/adc/ad7780.c301
-rw-r--r--drivers/staging/iio/adc/ad7780.h30
-rw-r--r--drivers/staging/iio/adc/ad7816.c111
-rw-r--r--drivers/staging/iio/adc/ad7887.h17
-rw-r--r--drivers/staging/iio/adc/ad7887_core.c200
-rw-r--r--drivers/staging/iio/adc/ad7887_ring.c156
-rw-r--r--drivers/staging/iio/adc/ad799x.h33
-rw-r--r--drivers/staging/iio/adc/ad799x_core.c859
-rw-r--r--drivers/staging/iio/adc/ad799x_ring.c93
-rw-r--r--drivers/staging/iio/adc/adt7310.c206
-rw-r--r--drivers/staging/iio/adc/adt7410.c201
-rw-r--r--drivers/staging/iio/adc/adt75.c180
-rw-r--r--drivers/staging/iio/adc/max1363.h93
-rw-r--r--drivers/staging/iio/adc/max1363_core.c1945
-rw-r--r--drivers/staging/iio/adc/max1363_ring.c109
-rw-r--r--drivers/staging/iio/addac/adt7316.c502
-rw-r--r--drivers/staging/iio/chrdev.h44
-rw-r--r--drivers/staging/iio/dac/Kconfig21
-rw-r--r--drivers/staging/iio/dac/Makefile2
-rw-r--r--drivers/staging/iio/dac/ad5446.c30
-rw-r--r--drivers/staging/iio/dac/ad5446.h1
-rw-r--r--drivers/staging/iio/dac/ad5504.c404
-rw-r--r--drivers/staging/iio/dac/ad5504.h70
-rw-r--r--drivers/staging/iio/dac/ad5624r_spi.c23
-rw-r--r--drivers/staging/iio/dac/ad5791.c444
-rw-r--r--drivers/staging/iio/dac/ad5791.h116
-rw-r--r--drivers/staging/iio/dac/max517.c17
-rw-r--r--drivers/staging/iio/dds/Kconfig4
-rw-r--r--drivers/staging/iio/dds/ad5930.c14
-rw-r--r--drivers/staging/iio/dds/ad9832.c23
-rw-r--r--drivers/staging/iio/dds/ad9834.c54
-rw-r--r--drivers/staging/iio/dds/ad9834.h8
-rw-r--r--drivers/staging/iio/dds/ad9850.c12
-rw-r--r--drivers/staging/iio/dds/ad9852.c12
-rw-r--r--drivers/staging/iio/dds/ad9910.c12
-rw-r--r--drivers/staging/iio/dds/ad9951.c12
-rw-r--r--drivers/staging/iio/gyro/Kconfig10
-rw-r--r--drivers/staging/iio/gyro/Makefile3
-rw-r--r--drivers/staging/iio/gyro/adis16060_core.c10
-rw-r--r--drivers/staging/iio/gyro/adis16080_core.c13
-rw-r--r--drivers/staging/iio/gyro/adis16130_core.c14
-rw-r--r--drivers/staging/iio/gyro/adis16260.h7
-rw-r--r--drivers/staging/iio/gyro/adis16260_core.c477
-rw-r--r--drivers/staging/iio/gyro/adis16260_ring.c124
-rw-r--r--drivers/staging/iio/gyro/adis16260_trigger.c85
-rw-r--r--drivers/staging/iio/gyro/adxrs450.h58
-rw-r--r--drivers/staging/iio/gyro/adxrs450_core.c455
-rw-r--r--drivers/staging/iio/gyro/gyro.h3
-rw-r--r--drivers/staging/iio/iio.h356
-rw-r--r--drivers/staging/iio/imu/Kconfig26
-rw-r--r--drivers/staging/iio/imu/Makefile8
-rw-r--r--drivers/staging/iio/imu/adis16300.h184
-rw-r--r--drivers/staging/iio/imu/adis16300_core.c756
-rw-r--r--drivers/staging/iio/imu/adis16300_ring.c238
-rw-r--r--drivers/staging/iio/imu/adis16300_trigger.c125
-rw-r--r--drivers/staging/iio/imu/adis16350.h177
-rw-r--r--drivers/staging/iio/imu/adis16350_core.c757
-rw-r--r--drivers/staging/iio/imu/adis16350_ring.c236
-rw-r--r--drivers/staging/iio/imu/adis16350_trigger.c125
-rw-r--r--drivers/staging/iio/imu/adis16400.h38
-rw-r--r--drivers/staging/iio/imu/adis16400_core.c731
-rw-r--r--drivers/staging/iio/imu/adis16400_ring.c235
-rw-r--r--drivers/staging/iio/imu/adis16400_trigger.c100
-rw-r--r--drivers/staging/iio/industrialio-core.c943
-rw-r--r--drivers/staging/iio/industrialio-ring.c587
-rw-r--r--drivers/staging/iio/industrialio-trigger.c299
-rw-r--r--drivers/staging/iio/kfifo_buf.c63
-rw-r--r--drivers/staging/iio/kfifo_buf.h40
-rw-r--r--drivers/staging/iio/light/Kconfig28
-rw-r--r--drivers/staging/iio/light/Makefile1
-rw-r--r--drivers/staging/iio/light/isl29018.c23
-rw-r--r--drivers/staging/iio/light/tsl2563.c427
-rw-r--r--drivers/staging/iio/light/tsl2583.c964
-rw-r--r--drivers/staging/iio/magnetometer/ak8975.c130
-rw-r--r--drivers/staging/iio/magnetometer/hmc5843.c10
-rw-r--r--drivers/staging/iio/meter/ade7753.c14
-rw-r--r--drivers/staging/iio/meter/ade7754.c14
-rw-r--r--drivers/staging/iio/meter/ade7758.h71
-rw-r--r--drivers/staging/iio/meter/ade7758_core.c366
-rw-r--r--drivers/staging/iio/meter/ade7758_ring.c281
-rw-r--r--drivers/staging/iio/meter/ade7758_trigger.c95
-rw-r--r--drivers/staging/iio/meter/ade7759.c15
-rw-r--r--drivers/staging/iio/meter/ade7854.c10
-rw-r--r--drivers/staging/iio/resolver/ad2s120x.c13
-rw-r--r--drivers/staging/iio/resolver/ad2s1210.c12
-rw-r--r--drivers/staging/iio/resolver/ad2s90.c12
-rw-r--r--drivers/staging/iio/ring_generic.h293
-rw-r--r--drivers/staging/iio/ring_sw.c205
-rw-r--r--drivers/staging/iio/ring_sw.h196
-rw-r--r--drivers/staging/iio/sysfs.h184
-rw-r--r--drivers/staging/iio/trigger.h116
-rw-r--r--drivers/staging/iio/trigger/Kconfig1
-rw-r--r--drivers/staging/iio/trigger/iio-trig-bfin-timer.c22
-rw-r--r--drivers/staging/iio/trigger/iio-trig-gpio.c25
-rw-r--r--drivers/staging/iio/trigger/iio-trig-periodic-rtc.c24
-rw-r--r--drivers/staging/iio/trigger/iio-trig-sysfs.c169
-rw-r--r--drivers/staging/intel_sst/intel_sst.c129
-rw-r--r--drivers/staging/intel_sst/intel_sst.h33
-rw-r--r--drivers/staging/intel_sst/intel_sst_app_interface.c45
-rw-r--r--drivers/staging/intel_sst/intel_sst_common.h9
-rw-r--r--drivers/staging/intel_sst/intel_sst_drv_interface.c25
-rw-r--r--drivers/staging/intel_sst/intel_sst_dsp.c14
-rw-r--r--drivers/staging/intel_sst/intel_sst_fw_ipc.h7
-rw-r--r--drivers/staging/intel_sst/intel_sst_ioctl.h8
-rw-r--r--drivers/staging/intel_sst/intel_sst_ipc.c74
-rw-r--r--drivers/staging/intel_sst/intel_sst_pvt.c2
-rw-r--r--drivers/staging/intel_sst/intel_sst_stream.c15
-rw-r--r--drivers/staging/intel_sst/intel_sst_stream_encoded.c8
-rw-r--r--drivers/staging/intel_sst/intelmid.c475
-rw-r--r--drivers/staging/intel_sst/intelmid.h38
-rw-r--r--drivers/staging/intel_sst/intelmid_adc_control.h193
-rw-r--r--drivers/staging/intel_sst/intelmid_ctrl.c304
-rw-r--r--drivers/staging/intel_sst/intelmid_msic_control.c833
-rw-r--r--drivers/staging/intel_sst/intelmid_pvt.c1
-rw-r--r--drivers/staging/intel_sst/intelmid_snd_control.h9
-rw-r--r--drivers/staging/intel_sst/intelmid_v0_control.c109
-rw-r--r--drivers/staging/intel_sst/intelmid_v1_control.c141
-rw-r--r--drivers/staging/intel_sst/intelmid_v2_control.c219
-rw-r--r--drivers/staging/intel_sst/jack.h10
-rw-r--r--drivers/staging/keucr/common.h2
-rw-r--r--drivers/staging/keucr/init.c3
-rw-r--r--drivers/staging/keucr/init.h10
-rw-r--r--drivers/staging/keucr/ms.c698
-rw-r--r--drivers/staging/keucr/ms.h338
-rw-r--r--drivers/staging/keucr/msscsi.c250
-rw-r--r--drivers/staging/keucr/scsiglue.c192
-rw-r--r--drivers/staging/keucr/smcommon.h2
-rw-r--r--drivers/staging/keucr/smil.h309
-rw-r--r--drivers/staging/keucr/smilecc.c314
-rw-r--r--drivers/staging/keucr/smilmain.c144
-rw-r--r--drivers/staging/keucr/smilsub.c66
-rw-r--r--drivers/staging/keucr/smscsi.c2
-rw-r--r--drivers/staging/keucr/transport.c531
-rw-r--r--drivers/staging/keucr/transport.h84
-rw-r--r--drivers/staging/keucr/usb.c95
-rw-r--r--drivers/staging/line6/driver.c2
-rw-r--r--drivers/staging/lirc/lirc_parallel.c27
-rw-r--r--drivers/staging/lirc/lirc_sasem.c13
-rw-r--r--drivers/staging/lirc/lirc_serial.c2
-rw-r--r--drivers/staging/lirc/lirc_sir.c30
-rw-r--r--drivers/staging/mei/Kconfig28
-rw-r--r--drivers/staging/mei/Makefile11
-rw-r--r--drivers/staging/mei/TODO17
-rw-r--r--drivers/staging/mei/hw.h333
-rw-r--r--drivers/staging/mei/init.c770
-rw-r--r--drivers/staging/mei/interface.c447
-rw-r--r--drivers/staging/mei/interface.h62
-rw-r--r--drivers/staging/mei/interrupt.c1624
-rw-r--r--drivers/staging/mei/iorw.c604
-rw-r--r--drivers/staging/mei/main.c1349
-rw-r--r--drivers/staging/mei/mei.h105
-rw-r--r--drivers/staging/mei/mei.txt189
-rw-r--r--drivers/staging/mei/mei_dev.h422
-rw-r--r--drivers/staging/mei/mei_version.h31
-rw-r--r--drivers/staging/mei/wd.c183
-rw-r--r--drivers/staging/nvec/Kconfig27
-rw-r--r--drivers/staging/nvec/Makefile4
-rw-r--r--drivers/staging/nvec/README14
-rw-r--r--drivers/staging/nvec/TODO8
-rw-r--r--drivers/staging/nvec/nvec-keytable.h266
-rw-r--r--drivers/staging/nvec/nvec.c468
-rw-r--r--drivers/staging/nvec/nvec.h110
-rw-r--r--drivers/staging/nvec/nvec_kbd.c122
-rw-r--r--drivers/staging/nvec/nvec_power.c418
-rw-r--r--drivers/staging/nvec/nvec_ps2.c103
-rw-r--r--drivers/staging/octeon/ethernet-mdio.c2
-rw-r--r--drivers/staging/olpc_dcon/olpc_dcon_xo_1.c2
-rw-r--r--drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c22
-rw-r--r--drivers/staging/pohmelfs/inode.c1
-rw-r--r--drivers/staging/rt2860/Kconfig10
-rw-r--r--drivers/staging/rt2860/Makefile52
-rw-r--r--drivers/staging/rt2860/TODO16
-rw-r--r--drivers/staging/rt2860/ap.h68
-rw-r--r--drivers/staging/rt2860/chip/mac_pci.h355
-rw-r--r--drivers/staging/rt2860/chip/mac_usb.h345
-rw-r--r--drivers/staging/rt2860/chip/rt2860.h54
-rw-r--r--drivers/staging/rt2860/chip/rt2870.h46
-rw-r--r--drivers/staging/rt2860/chip/rt3070.h67
-rw-r--r--drivers/staging/rt2860/chip/rt3090.h72
-rw-r--r--drivers/staging/rt2860/chip/rt30xx.h47
-rw-r--r--drivers/staging/rt2860/chip/rtmp_mac.h1308
-rw-r--r--drivers/staging/rt2860/chip/rtmp_phy.h516
-rw-r--r--drivers/staging/rt2860/chips/rt3070.c169
-rw-r--r--drivers/staging/rt2860/chips/rt3090.c121
-rw-r--r--drivers/staging/rt2860/chips/rt30xx.c516
-rw-r--r--drivers/staging/rt2860/chlist.h113
-rw-r--r--drivers/staging/rt2860/common/action.c606
-rw-r--r--drivers/staging/rt2860/common/action.h56
-rw-r--r--drivers/staging/rt2860/common/ba_action.c1650
-rw-r--r--drivers/staging/rt2860/common/cmm_aes.c1311
-rw-r--r--drivers/staging/rt2860/common/cmm_asic.c2565
-rw-r--r--drivers/staging/rt2860/common/cmm_cfg.c258
-rw-r--r--drivers/staging/rt2860/common/cmm_data.c2361
-rw-r--r--drivers/staging/rt2860/common/cmm_data_pci.c1096
-rw-r--r--drivers/staging/rt2860/common/cmm_data_usb.c951
-rw-r--r--drivers/staging/rt2860/common/cmm_info.c955
-rw-r--r--drivers/staging/rt2860/common/cmm_mac_pci.c1661
-rw-r--r--drivers/staging/rt2860/common/cmm_mac_usb.c1162
-rw-r--r--drivers/staging/rt2860/common/cmm_sanity.c1205
-rw-r--r--drivers/staging/rt2860/common/cmm_sync.c718
-rw-r--r--drivers/staging/rt2860/common/cmm_tkip.c833
-rw-r--r--drivers/staging/rt2860/common/cmm_wep.c473
-rw-r--r--drivers/staging/rt2860/common/cmm_wpa.c3010
-rw-r--r--drivers/staging/rt2860/common/crypt_hmac.c187
-rw-r--r--drivers/staging/rt2860/common/crypt_md5.c339
-rw-r--r--drivers/staging/rt2860/common/crypt_sha2.c269
-rw-r--r--drivers/staging/rt2860/common/dfs.c68
-rw-r--r--drivers/staging/rt2860/common/ee_efuse.c351
-rw-r--r--drivers/staging/rt2860/common/ee_prom.c197
-rw-r--r--drivers/staging/rt2860/common/eeprom.c91
-rw-r--r--drivers/staging/rt2860/common/mlme.c6068
-rw-r--r--drivers/staging/rt2860/common/rt_channel.c1705
-rw-r--r--drivers/staging/rt2860/common/rt_rf.c187
-rw-r--r--drivers/staging/rt2860/common/rtmp_init.c3536
-rw-r--r--drivers/staging/rt2860/common/rtmp_mcu.c336
-rw-r--r--drivers/staging/rt2860/common/rtmp_timer.c302
-rw-r--r--drivers/staging/rt2860/common/spectrum.c2205
-rw-r--r--drivers/staging/rt2860/crypt_hmac.h65
-rw-r--r--drivers/staging/rt2860/crypt_md5.h73
-rw-r--r--drivers/staging/rt2860/crypt_sha2.h73
-rw-r--r--drivers/staging/rt2860/dfs.h39
-rw-r--r--drivers/staging/rt2860/eeprom.h67
-rw-r--r--drivers/staging/rt2860/iface/rtmp_pci.h80
-rw-r--r--drivers/staging/rt2860/iface/rtmp_usb.h196
-rw-r--r--drivers/staging/rt2860/mlme.h1050
-rw-r--r--drivers/staging/rt2860/oid.h779
-rw-r--r--drivers/staging/rt2860/pci_main_dev.c1192
-rw-r--r--drivers/staging/rt2860/rt_config.h71
-rw-r--r--drivers/staging/rt2860/rt_linux.c1367
-rw-r--r--drivers/staging/rt2860/rt_linux.h835
-rw-r--r--drivers/staging/rt2860/rt_main_dev.c736
-rw-r--r--drivers/staging/rt2860/rt_pci_rbus.c837
-rw-r--r--drivers/staging/rt2860/rt_usb.c794
-rw-r--r--drivers/staging/rt2860/rtmp.h4332
-rw-r--r--drivers/staging/rt2860/rtmp_chip.h258
-rw-r--r--drivers/staging/rt2860/rtmp_ckipmic.h63
-rw-r--r--drivers/staging/rt2860/rtmp_def.h1427
-rw-r--r--drivers/staging/rt2860/rtmp_dot11.h100
-rw-r--r--drivers/staging/rt2860/rtmp_iface.h75
-rw-r--r--drivers/staging/rt2860/rtmp_mcu.h49
-rw-r--r--drivers/staging/rt2860/rtmp_os.h90
-rw-r--r--drivers/staging/rt2860/rtmp_timer.h148
-rw-r--r--drivers/staging/rt2860/rtmp_type.h89
-rw-r--r--drivers/staging/rt2860/rtusb_io.h185
-rw-r--r--drivers/staging/rt2860/spectrum.h189
-rw-r--r--drivers/staging/rt2860/spectrum_def.h202
-rw-r--r--drivers/staging/rt2860/sta/assoc.c1602
-rw-r--r--drivers/staging/rt2860/sta/auth.c517
-rw-r--r--drivers/staging/rt2860/sta/auth_rsp.c142
-rw-r--r--drivers/staging/rt2860/sta/connect.c2613
-rw-r--r--drivers/staging/rt2860/sta/rtmp_data.c2552
-rw-r--r--drivers/staging/rt2860/sta/sanity.c362
-rw-r--r--drivers/staging/rt2860/sta/sync.c1968
-rw-r--r--drivers/staging/rt2860/sta/wpa.c374
-rw-r--r--drivers/staging/rt2860/sta_ioctl.c2912
-rw-r--r--drivers/staging/rt2860/usb_main_dev.c927
-rw-r--r--drivers/staging/rt2860/wpa.h390
-rw-r--r--drivers/staging/rt2870/Kconfig9
-rw-r--r--drivers/staging/rt2870/Makefile55
-rw-r--r--drivers/staging/rt2870/TODO17
-rw-r--r--drivers/staging/rt2870/aironet.h1
-rw-r--r--drivers/staging/rt2870/ap.h1
-rw-r--r--drivers/staging/rt2870/chips/rt3070.c1
-rw-r--r--drivers/staging/rt2870/chips/rt30xx.c1
-rw-r--r--drivers/staging/rt2870/chlist.h1
-rw-r--r--drivers/staging/rt2870/common/acction.c1
-rw-r--r--drivers/staging/rt2870/common/action.c1
-rw-r--r--drivers/staging/rt2870/common/action.h1
-rw-r--r--drivers/staging/rt2870/common/ba_action.c1
-rw-r--r--drivers/staging/rt2870/common/cmm_aes.c1
-rw-r--r--drivers/staging/rt2870/common/cmm_asic.c1
-rw-r--r--drivers/staging/rt2870/common/cmm_cfg.c1
-rw-r--r--drivers/staging/rt2870/common/cmm_data.c1
-rw-r--r--drivers/staging/rt2870/common/cmm_data_usb.c1
-rw-r--r--drivers/staging/rt2870/common/cmm_info.c1
-rw-r--r--drivers/staging/rt2870/common/cmm_mac_usb.c1
-rw-r--r--drivers/staging/rt2870/common/cmm_profile.c1
-rw-r--r--drivers/staging/rt2870/common/cmm_sanity.c1
-rw-r--r--drivers/staging/rt2870/common/cmm_sync.c1
-rw-r--r--drivers/staging/rt2870/common/cmm_tkip.c1
-rw-r--r--drivers/staging/rt2870/common/cmm_wep.c1
-rw-r--r--drivers/staging/rt2870/common/cmm_wpa.c1
-rw-r--r--drivers/staging/rt2870/common/crypt_hmac.c1
-rw-r--r--drivers/staging/rt2870/common/crypt_md5.c1
-rw-r--r--drivers/staging/rt2870/common/crypt_sha2.c1
-rw-r--r--drivers/staging/rt2870/common/dfs.c1
-rw-r--r--drivers/staging/rt2870/common/ee_efuse.c1
-rw-r--r--drivers/staging/rt2870/common/eeprom.c1
-rw-r--r--drivers/staging/rt2870/common/md5.c1
-rw-r--r--drivers/staging/rt2870/common/mlme.c1
-rw-r--r--drivers/staging/rt2870/common/rt_channel.c1
-rw-r--r--drivers/staging/rt2870/common/rt_rf.c1
-rw-r--r--drivers/staging/rt2870/common/rtmp_init.c1
-rw-r--r--drivers/staging/rt2870/common/rtmp_mcu.c1
-rw-r--r--drivers/staging/rt2870/common/rtmp_timer.c1
-rw-r--r--drivers/staging/rt2870/common/rtmp_tkip.c1
-rw-r--r--drivers/staging/rt2870/common/rtmp_wep.c1
-rw-r--r--drivers/staging/rt2870/common/rtusb_bulk.c1232
-rw-r--r--drivers/staging/rt2870/common/rtusb_data.c262
-rw-r--r--drivers/staging/rt2870/common/rtusb_io.c2104
-rw-r--r--drivers/staging/rt2870/common/spectrum.c1
-rw-r--r--drivers/staging/rt2870/dfs.h1
-rw-r--r--drivers/staging/rt2870/md5.h1
-rw-r--r--drivers/staging/rt2870/mlme.h1
-rw-r--r--drivers/staging/rt2870/oid.h1
-rw-r--r--drivers/staging/rt2870/rt28xx.h1
-rw-r--r--drivers/staging/rt2870/rt_config.h1
-rw-r--r--drivers/staging/rt2870/rt_linux.c1
-rw-r--r--drivers/staging/rt2870/rt_linux.h1
-rw-r--r--drivers/staging/rt2870/rt_main_dev.c1
-rw-r--r--drivers/staging/rt2870/rt_profile.c1
-rw-r--r--drivers/staging/rt2870/rt_usb.c1
-rw-r--r--drivers/staging/rt2870/rtmp.h1
-rw-r--r--drivers/staging/rt2870/rtmp_ckipmic.h1
-rw-r--r--drivers/staging/rt2870/rtmp_def.h1
-rw-r--r--drivers/staging/rt2870/rtmp_type.h1
-rw-r--r--drivers/staging/rt2870/spectrum.h1
-rw-r--r--drivers/staging/rt2870/spectrum_def.h1
-rw-r--r--drivers/staging/rt2870/sta/aironet.c1
-rw-r--r--drivers/staging/rt2870/sta/assoc.c1
-rw-r--r--drivers/staging/rt2870/sta/auth.c1
-rw-r--r--drivers/staging/rt2870/sta/auth_rsp.c1
-rw-r--r--drivers/staging/rt2870/sta/connect.c1
-rw-r--r--drivers/staging/rt2870/sta/rtmp_data.c1
-rw-r--r--drivers/staging/rt2870/sta/sanity.c1
-rw-r--r--drivers/staging/rt2870/sta/sync.c1
-rw-r--r--drivers/staging/rt2870/sta/wpa.c1
-rw-r--r--drivers/staging/rt2870/sta_ioctl.c1
-rw-r--r--drivers/staging/rt2870/usb_main_dev.c1
-rw-r--r--drivers/staging/rt2870/wpa.h1
-rw-r--r--drivers/staging/rtl8712/ieee80211.h26
-rw-r--r--drivers/staging/rtl8712/if_ether.h4
-rw-r--r--drivers/staging/rtl8712/ip.h34
-rw-r--r--drivers/staging/rtl8712/mlme_osdep.h4
-rw-r--r--drivers/staging/rtl8712/osdep_service.h3
-rw-r--r--drivers/staging/rtl8712/recv_osdep.h4
-rw-r--r--drivers/staging/rtl8712/rtl8712_event.h25
-rw-r--r--drivers/staging/rtl8712/rtl8712_hal.h100
-rw-r--r--drivers/staging/rtl8712/rtl8712_led.c2
-rw-r--r--drivers/staging/rtl8712/rtl8712_recv.c2
-rw-r--r--drivers/staging/rtl8712/rtl8712_recv.h2
-rw-r--r--drivers/staging/rtl8712/rtl8712_xmit.h11
-rw-r--r--drivers/staging/rtl8712/rtl871x_cmd.c7
-rw-r--r--drivers/staging/rtl8712/rtl871x_cmd.h26
-rw-r--r--drivers/staging/rtl8712/rtl871x_event.h12
-rw-r--r--drivers/staging/rtl8712/rtl871x_io.c6
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_linux.c9
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_rtl.c2
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_set.c5
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_set.h16
-rw-r--r--drivers/staging/rtl8712/rtl871x_mp.c8
-rw-r--r--drivers/staging/rtl8712/rtl871x_mp_ioctl.h10
-rw-r--r--drivers/staging/rtl8712/rtl871x_recv.c16
-rw-r--r--drivers/staging/rtl8712/rtl871x_recv.h4
-rw-r--r--drivers/staging/rtl8712/rtl871x_rf.h2
-rw-r--r--drivers/staging/rtl8712/rtl871x_security.h51
-rw-r--r--drivers/staging/rtl8712/rtl871x_xmit.c3
-rw-r--r--drivers/staging/rtl8712/rtl871x_xmit.h3
-rw-r--r--drivers/staging/rtl8712/wifi.h63
-rw-r--r--drivers/staging/rtl8712/wlan_bssdef.h212
-rw-r--r--drivers/staging/rts_pstor/ms.c52
-rw-r--r--drivers/staging/rts_pstor/rtsx.c4
-rw-r--r--drivers/staging/rts_pstor/rtsx.h3
-rw-r--r--drivers/staging/rts_pstor/sd.c1
-rw-r--r--drivers/staging/rts_pstor/spi.c34
-rw-r--r--drivers/staging/rts_pstor/xd.c4
-rw-r--r--drivers/staging/sbe-2t3e3/dc.c33
-rw-r--r--drivers/staging/sep/sep_driver.c9
-rw-r--r--drivers/staging/sm7xx/TODO2
-rw-r--r--drivers/staging/sm7xx/smtcfb.c215
-rw-r--r--drivers/staging/sm7xx/smtcfb.h7
-rw-r--r--drivers/staging/tm6000/CARDLIST16
-rw-r--r--drivers/staging/tm6000/tm6000-alsa.c3
-rw-r--r--drivers/staging/tm6000/tm6000-cards.c381
-rw-r--r--drivers/staging/tm6000/tm6000-core.c109
-rw-r--r--drivers/staging/tm6000/tm6000-i2c.c33
-rw-r--r--drivers/staging/tm6000/tm6000-stds.c923
-rw-r--r--drivers/staging/tm6000/tm6000-usb-isoc.h2
-rw-r--r--drivers/staging/tm6000/tm6000-video.c212
-rw-r--r--drivers/staging/tm6000/tm6000.h46
-rw-r--r--drivers/staging/tty/istallion.c2
-rw-r--r--drivers/staging/usbip/Kconfig52
-rw-r--r--drivers/staging/usbip/Makefile15
-rw-r--r--drivers/staging/usbip/stub.h33
-rw-r--r--drivers/staging/usbip/stub_dev.c97
-rw-r--r--drivers/staging/usbip/stub_main.c51
-rw-r--r--drivers/staging/usbip/stub_rx.c68
-rw-r--r--drivers/staging/usbip/stub_tx.c81
-rw-r--r--drivers/staging/usbip/usbip_common.c333
-rw-r--r--drivers/staging/usbip/usbip_common.h139
-rw-r--r--drivers/staging/usbip/usbip_event.c20
-rw-r--r--drivers/staging/usbip/userspace/AUTHORS2
-rw-r--r--drivers/staging/usbip/userspace/COPYING340
-rw-r--r--drivers/staging/usbip/userspace/INSTALL237
-rw-r--r--drivers/staging/usbip/userspace/Makefile.am11
-rw-r--r--drivers/staging/usbip/userspace/README215
-rwxr-xr-xdrivers/staging/usbip/userspace/autogen.sh9
-rwxr-xr-xdrivers/staging/usbip/userspace/cleanup.sh10
-rw-r--r--drivers/staging/usbip/userspace/configure.ac114
-rw-r--r--drivers/staging/usbip/userspace/doc/usbip.871
-rw-r--r--drivers/staging/usbip/userspace/doc/usbip_bind_driver.842
-rw-r--r--drivers/staging/usbip/userspace/doc/usbipd.862
-rw-r--r--drivers/staging/usbip/userspace/libsrc/Makefile.am7
-rw-r--r--drivers/staging/usbip/userspace/libsrc/names.c793
-rw-r--r--drivers/staging/usbip/userspace/libsrc/names.h57
-rw-r--r--drivers/staging/usbip/userspace/libsrc/stub_driver.c391
-rw-r--r--drivers/staging/usbip/userspace/libsrc/stub_driver.h36
-rw-r--r--drivers/staging/usbip/userspace/libsrc/usbip.h19
-rw-r--r--drivers/staging/usbip/userspace/libsrc/usbip_common.c282
-rw-r--r--drivers/staging/usbip/userspace/libsrc/usbip_common.h149
-rw-r--r--drivers/staging/usbip/userspace/libsrc/vhci_driver.c506
-rw-r--r--drivers/staging/usbip/userspace/libsrc/vhci_driver.h61
-rw-r--r--drivers/staging/usbip/userspace/src/Makefile.am10
-rw-r--r--drivers/staging/usbip/userspace/src/bind-driver.c643
-rw-r--r--drivers/staging/usbip/userspace/src/usbip.c723
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_network.c251
-rw-r--r--drivers/staging/usbip/userspace/src/usbip_network.h198
-rw-r--r--drivers/staging/usbip/userspace/src/usbipd.c570
-rw-r--r--drivers/staging/usbip/userspace/src/utils.c255
-rw-r--r--drivers/staging/usbip/userspace/src/utils.h38
-rw-r--r--drivers/staging/usbip/userspace/usb.ids13209
-rw-r--r--drivers/staging/usbip/vhci.h38
-rw-r--r--drivers/staging/usbip/vhci_hcd.c284
-rw-r--r--drivers/staging/usbip/vhci_rx.c74
-rw-r--r--drivers/staging/usbip/vhci_sysfs.c33
-rw-r--r--drivers/staging/usbip/vhci_tx.c44
-rw-r--r--drivers/staging/vt6655/bssdb.c8
-rw-r--r--drivers/staging/vt6655/device.h2
-rw-r--r--drivers/staging/vt6655/device_main.c14
-rw-r--r--drivers/staging/vt6655/dpc.c10
-rw-r--r--drivers/staging/vt6655/ioctl.c44
-rw-r--r--drivers/staging/vt6655/power.c2
-rw-r--r--drivers/staging/vt6655/rxtx.c4
-rw-r--r--drivers/staging/vt6655/wcmd.c14
-rw-r--r--drivers/staging/vt6655/wmgr.c46
-rw-r--r--drivers/staging/vt6655/wpactl.c10
-rw-r--r--drivers/staging/vt6656/bssdb.c8
-rw-r--r--drivers/staging/vt6656/dpc.c10
-rw-r--r--drivers/staging/vt6656/ioctl.c44
-rw-r--r--drivers/staging/vt6656/main_usb.c7
-rw-r--r--drivers/staging/vt6656/rxtx.c4
-rw-r--r--drivers/staging/vt6656/wcmd.c8
-rw-r--r--drivers/staging/vt6656/wmgr.c48
-rw-r--r--drivers/staging/vt6656/wpactl.c10
-rw-r--r--drivers/staging/westbridge/astoria/arch/arm/mach-omap2/cyashalomap_kernel.c2
-rw-r--r--drivers/staging/westbridge/astoria/block/cyasblkdev_block.c2
-rw-r--r--drivers/staging/winbond/mto.c10
-rw-r--r--drivers/staging/winbond/phy_calibration.c8
-rw-r--r--drivers/staging/winbond/wb35tx.c3
-rw-r--r--drivers/staging/wlags49_h2/wl_cs.c2
-rw-r--r--drivers/staging/wlan-ng/cfg80211.c2
-rw-r--r--drivers/staging/xgifb/XGI_main.h792
-rw-r--r--drivers/staging/xgifb/XGI_main_26.c1259
-rw-r--r--drivers/staging/xgifb/XGIfb.h142
-rw-r--r--drivers/staging/xgifb/vb_def.h1269
-rw-r--r--drivers/staging/xgifb/vb_ext.c138
-rw-r--r--drivers/staging/xgifb/vb_ext.h25
-rw-r--r--drivers/staging/xgifb/vb_init.c527
-rw-r--r--drivers/staging/xgifb/vb_init.h7
-rw-r--r--drivers/staging/xgifb/vb_setmode.c1885
-rw-r--r--drivers/staging/xgifb/vb_setmode.h97
-rw-r--r--drivers/staging/xgifb/vb_struct.h823
-rw-r--r--drivers/staging/xgifb/vb_table.h8147
-rw-r--r--drivers/staging/xgifb/vb_util.c2
-rw-r--r--drivers/staging/xgifb/vgatypes.h113
-rw-r--r--drivers/staging/zcache/zcache.c5
-rw-r--r--drivers/target/Kconfig1
-rw-r--r--drivers/target/Makefile2
-rw-r--r--drivers/target/target_core_alua.c4
-rw-r--r--drivers/target/target_core_transport.c2
-rw-r--r--drivers/target/tcm_fc/Kconfig5
-rw-r--r--drivers/target/tcm_fc/Makefile15
-rw-r--r--drivers/target/tcm_fc/tcm_fc.h215
-rw-r--r--drivers/target/tcm_fc/tfc_cmd.c696
-rw-r--r--drivers/target/tcm_fc/tfc_conf.c677
-rw-r--r--drivers/target/tcm_fc/tfc_io.c374
-rw-r--r--drivers/target/tcm_fc/tfc_sess.c541
-rw-r--r--drivers/telephony/ixj_pcmcia.c2
-rw-r--r--drivers/tty/Kconfig31
-rw-r--r--drivers/tty/Makefile2
-rw-r--r--drivers/tty/amiserial.c2
-rw-r--r--drivers/tty/cyclades.c8
-rw-r--r--drivers/tty/ipwireless/Makefile2
-rw-r--r--drivers/tty/ipwireless/main.c2
-rw-r--r--drivers/tty/moxa.c18
-rw-r--r--drivers/tty/n_gsm.c43
-rw-r--r--drivers/tty/n_hdlc.c18
-rw-r--r--drivers/tty/n_r3964.c10
-rw-r--r--drivers/tty/n_tracerouter.c243
-rw-r--r--drivers/tty/n_tracesink.c238
-rw-r--r--drivers/tty/n_tracesink.h36
-rw-r--r--drivers/tty/n_tty.c61
-rw-r--r--drivers/tty/nozomi.c32
-rw-r--r--drivers/tty/pty.c35
-rw-r--r--drivers/tty/rocket.c47
-rw-r--r--drivers/tty/serial/21285.c2
-rw-r--r--drivers/tty/serial/68328serial.c2
-rw-r--r--drivers/tty/serial/8250.c44
-rw-r--r--drivers/tty/serial/8250.h3
-rw-r--r--drivers/tty/serial/8250_accent.c2
-rw-r--r--drivers/tty/serial/8250_boca.c2
-rw-r--r--drivers/tty/serial/8250_exar_st16c554.c2
-rw-r--r--drivers/tty/serial/8250_fourport.c2
-rw-r--r--drivers/tty/serial/8250_hub6.c2
-rw-r--r--drivers/tty/serial/8250_mca.c2
-rw-r--r--drivers/tty/serial/8250_pci.c53
-rw-r--r--drivers/tty/serial/8250_pnp.c2
-rw-r--r--drivers/tty/serial/Kconfig35
-rw-r--r--drivers/tty/serial/Makefile2
-rw-r--r--drivers/tty/serial/altera_uart.c26
-rw-r--r--drivers/tty/serial/amba-pl010.c2
-rw-r--r--drivers/tty/serial/amba-pl011.c2
-rw-r--r--drivers/tty/serial/atmel_serial.c2
-rw-r--r--drivers/tty/serial/bfin_sport_uart.c3
-rw-r--r--drivers/tty/serial/clps711x.c2
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart.h2
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_core.c2
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_cpm1.c2
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_cpm1.h2
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_cpm2.c2
-rw-r--r--drivers/tty/serial/cpm_uart/cpm_uart_cpm2.h2
-rw-r--r--drivers/tty/serial/ifx6x60.c2
-rw-r--r--drivers/tty/serial/imx.c2
-rw-r--r--drivers/tty/serial/lantiq.c756
-rw-r--r--drivers/tty/serial/m32r_sio.c3
-rw-r--r--drivers/tty/serial/mfd.c4
-rw-r--r--drivers/tty/serial/mrst_max3110.c2
-rw-r--r--drivers/tty/serial/msm_serial.c2
-rw-r--r--drivers/tty/serial/msm_serial.h2
-rw-r--r--drivers/tty/serial/msm_smd_tty.c3
-rw-r--r--drivers/tty/serial/netx-serial.c2
-rw-r--r--drivers/tty/serial/pch_uart.c9
-rw-r--r--drivers/tty/serial/pmac_zilog.c2
-rw-r--r--drivers/tty/serial/pxa.c2
-rw-r--r--drivers/tty/serial/s3c2400.c3
-rw-r--r--drivers/tty/serial/s3c2410.c3
-rw-r--r--drivers/tty/serial/s3c2412.c3
-rw-r--r--drivers/tty/serial/s3c2440.c3
-rw-r--r--drivers/tty/serial/s3c24a0.c3
-rw-r--r--drivers/tty/serial/s3c6400.c3
-rw-r--r--drivers/tty/serial/s5pv210.c3
-rw-r--r--drivers/tty/serial/sa1100.c2
-rw-r--r--drivers/tty/serial/samsung.c3
-rw-r--r--drivers/tty/serial/samsung.h3
-rw-r--r--drivers/tty/serial/sb1250-duart.c2
-rw-r--r--drivers/tty/serial/serial_core.c90
-rw-r--r--drivers/tty/serial/serial_cs.c2
-rw-r--r--drivers/tty/serial/serial_ks8695.c2
-rw-r--r--drivers/tty/serial/serial_txx9.c2
-rw-r--r--drivers/tty/serial/sh-sci.c18
-rw-r--r--drivers/tty/serial/sh-sci.h16
-rw-r--r--drivers/tty/serial/vt8500_serial.c2
-rw-r--r--drivers/tty/serial/xilinx_uartps.c1113
-rw-r--r--drivers/tty/synclink.c2
-rw-r--r--drivers/tty/tty_buffer.c15
-rw-r--r--drivers/tty/tty_io.c53
-rw-r--r--drivers/tty/tty_ioctl.c4
-rw-r--r--drivers/tty/tty_ldisc.c13
-rw-r--r--drivers/tty/tty_mutex.c3
-rw-r--r--drivers/tty/vt/keyboard.c2
-rw-r--r--drivers/tty/vt/selection.c5
-rw-r--r--drivers/tty/vt/vc_screen.c2
-rw-r--r--drivers/tty/vt/vt.c13
-rw-r--r--drivers/tty/vt/vt_ioctl.c25
-rw-r--r--drivers/uio/uio.c16
-rw-r--r--drivers/uio/uio_netx.c19
-rw-r--r--drivers/uio/uio_pdrv_genirq.c4
-rw-r--r--drivers/usb/Kconfig4
-rw-r--r--drivers/usb/Makefile6
-rw-r--r--drivers/usb/class/cdc-acm.c479
-rw-r--r--drivers/usb/class/cdc-acm.h24
-rw-r--r--drivers/usb/class/cdc-wdm.c14
-rw-r--r--drivers/usb/core/config.c2
-rw-r--r--drivers/usb/core/devices.c22
-rw-r--r--drivers/usb/core/file.c8
-rw-r--r--drivers/usb/core/hcd.c6
-rw-r--r--drivers/usb/core/hub.c131
-rw-r--r--drivers/usb/core/sysfs.c13
-rw-r--r--drivers/usb/core/usb.c3
-rw-r--r--drivers/usb/core/usb.h2
-rw-r--r--drivers/usb/early/ehci-dbgp.c5
-rw-r--r--drivers/usb/gadget/Kconfig35
-rw-r--r--drivers/usb/gadget/Makefile1
-rw-r--r--drivers/usb/gadget/at91_udc.c2
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.c2
-rw-r--r--drivers/usb/gadget/ci13xxx_udc.c75
-rw-r--r--drivers/usb/gadget/composite.c62
-rw-r--r--drivers/usb/gadget/dbgp.c14
-rw-r--r--drivers/usb/gadget/dummy_hcd.c21
-rw-r--r--drivers/usb/gadget/f_audio.c2
-rw-r--r--drivers/usb/gadget/f_mass_storage.c68
-rw-r--r--drivers/usb/gadget/f_rndis.c3
-rw-r--r--drivers/usb/gadget/file_storage.c55
-rw-r--r--drivers/usb/gadget/fsl_qe_udc.h2
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c438
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.h6
-rw-r--r--drivers/usb/gadget/gadget_chips.h17
-rw-r--r--drivers/usb/gadget/goku_udc.c1
-rw-r--r--drivers/usb/gadget/imx_udc.c1
-rw-r--r--drivers/usb/gadget/omap_udc.c1
-rw-r--r--drivers/usb/gadget/printer.c2
-rw-r--r--drivers/usb/gadget/pxa25x_udc.c1
-rw-r--r--drivers/usb/gadget/pxa27x_udc.c1
-rw-r--r--drivers/usb/gadget/s3c-hsotg.c235
-rw-r--r--drivers/usb/gadget/s3c-hsudc.c1349
-rw-r--r--drivers/usb/gadget/storage_common.c18
-rw-r--r--drivers/usb/host/Kconfig57
-rw-r--r--drivers/usb/host/ehci-ath79.c202
-rw-r--r--drivers/usb/host/ehci-atmel.c2
-rw-r--r--drivers/usb/host/ehci-au1xxx.c12
-rw-r--r--drivers/usb/host/ehci-cns3xxx.c2
-rw-r--r--drivers/usb/host/ehci-dbg.c2
-rw-r--r--drivers/usb/host/ehci-fsl.c221
-rw-r--r--drivers/usb/host/ehci-fsl.h4
-rw-r--r--drivers/usb/host/ehci-grlib.c242
-rw-r--r--drivers/usb/host/ehci-hcd.c21
-rw-r--r--drivers/usb/host/ehci-hub.c10
-rw-r--r--drivers/usb/host/ehci-ixp4xx.c2
-rw-r--r--drivers/usb/host/ehci-msm.c2
-rw-r--r--drivers/usb/host/ehci-mxc.c2
-rw-r--r--drivers/usb/host/ehci-octeon.c2
-rw-r--r--drivers/usb/host/ehci-omap.c2
-rw-r--r--drivers/usb/host/ehci-orion.c2
-rw-r--r--drivers/usb/host/ehci-pci.c2
-rw-r--r--drivers/usb/host/ehci-pmcmsp.c2
-rw-r--r--drivers/usb/host/ehci-ppc-of.c2
-rw-r--r--drivers/usb/host/ehci-ps3.c2
-rw-r--r--drivers/usb/host/ehci-q.c5
-rw-r--r--drivers/usb/host/ehci-s5p.c202
-rw-r--r--drivers/usb/host/ehci-sched.c22
-rw-r--r--drivers/usb/host/ehci-sh.c2
-rw-r--r--drivers/usb/host/ehci-spear.c2
-rw-r--r--drivers/usb/host/ehci-tegra.c74
-rw-r--r--drivers/usb/host/ehci-vt8500.c3
-rw-r--r--drivers/usb/host/ehci-w90x900.c2
-rw-r--r--drivers/usb/host/ehci-xilinx-of.c2
-rw-r--r--drivers/usb/host/ehci.h13
-rw-r--r--drivers/usb/host/imx21-dbg.c2
-rw-r--r--drivers/usb/host/isp116x-hcd.c1
-rw-r--r--drivers/usb/host/isp1362-hcd.c1
-rw-r--r--drivers/usb/host/isp1760-hcd.c1638
-rw-r--r--drivers/usb/host/isp1760-hcd.h78
-rw-r--r--drivers/usb/host/octeon2-common.c45
-rw-r--r--drivers/usb/host/ohci-ath79.c151
-rw-r--r--drivers/usb/host/ohci-hcd.c9
-rw-r--r--drivers/usb/host/ohci-pci.c12
-rw-r--r--drivers/usb/host/ohci-s3c2410.c58
-rw-r--r--drivers/usb/host/oxu210hp-hcd.c6
-rw-r--r--drivers/usb/host/pci-quirks.c151
-rw-r--r--drivers/usb/host/sl811-hcd.c9
-rw-r--r--drivers/usb/host/sl811_cs.c2
-rw-r--r--drivers/usb/host/u132-hcd.c3
-rw-r--r--drivers/usb/host/uhci-debug.c88
-rw-r--r--drivers/usb/host/uhci-grlib.c208
-rw-r--r--drivers/usb/host/uhci-hcd.c465
-rw-r--r--drivers/usb/host/uhci-hcd.h248
-rw-r--r--drivers/usb/host/uhci-hub.c41
-rw-r--r--drivers/usb/host/uhci-pci.c301
-rw-r--r--drivers/usb/host/uhci-q.c131
-rw-r--r--drivers/usb/host/xhci-dbg.c51
-rw-r--r--drivers/usb/host/xhci-hub.c231
-rw-r--r--drivers/usb/host/xhci-mem.c144
-rw-r--r--drivers/usb/host/xhci-pci.c1
-rw-r--r--drivers/usb/host/xhci-ring.c509
-rw-r--r--drivers/usb/host/xhci.c145
-rw-r--r--drivers/usb/host/xhci.h145
-rw-r--r--drivers/usb/misc/ftdi-elan.c3
-rw-r--r--drivers/usb/misc/ldusb.c52
-rw-r--r--drivers/usb/misc/usbtest.c133
-rw-r--r--drivers/usb/musb/Kconfig35
-rw-r--r--drivers/usb/musb/Makefile7
-rw-r--r--drivers/usb/musb/am35x.c17
-rw-r--r--drivers/usb/musb/blackfin.c16
-rw-r--r--drivers/usb/musb/cppi_dma.c34
-rw-r--r--drivers/usb/musb/da8xx.c21
-rw-r--r--drivers/usb/musb/davinci.c13
-rw-r--r--drivers/usb/musb/musb_core.c151
-rw-r--r--drivers/usb/musb/musb_debug.h14
-rw-r--r--drivers/usb/musb/musb_gadget.c178
-rw-r--r--drivers/usb/musb/musb_gadget_ep0.c22
-rw-r--r--drivers/usb/musb/musb_host.c157
-rw-r--r--drivers/usb/musb/musb_virthub.c25
-rw-r--r--drivers/usb/musb/musbhsdma.c11
-rw-r--r--drivers/usb/musb/omap2430.c25
-rw-r--r--drivers/usb/musb/tusb6010.c62
-rw-r--r--drivers/usb/musb/tusb6010_omap.c32
-rw-r--r--drivers/usb/musb/ux500_dma.c422
-rw-r--r--drivers/usb/otg/Kconfig8
-rw-r--r--drivers/usb/otg/Makefile2
-rw-r--r--drivers/usb/otg/fsl_otg.c1169
-rw-r--r--drivers/usb/otg/fsl_otg.h406
-rw-r--r--drivers/usb/otg/gpio_vbus.c14
-rw-r--r--drivers/usb/otg/isp1301_omap.c26
-rw-r--r--drivers/usb/otg/langwell_otg.c40
-rw-r--r--drivers/usb/otg/msm_otg.c671
-rw-r--r--drivers/usb/otg/otg.c35
-rw-r--r--drivers/usb/otg/otg_fsm.c349
-rw-r--r--drivers/usb/otg/otg_fsm.h154
-rw-r--r--drivers/usb/otg/twl4030-usb.c9
-rw-r--r--drivers/usb/otg/twl6030-usb.c27
-rw-r--r--drivers/usb/renesas_usbhs/Kconfig16
-rw-r--r--drivers/usb/renesas_usbhs/Makefile9
-rw-r--r--drivers/usb/renesas_usbhs/common.c437
-rw-r--r--drivers/usb/renesas_usbhs/common.h230
-rw-r--r--drivers/usb/renesas_usbhs/mod.c328
-rw-r--r--drivers/usb/renesas_usbhs/mod.h137
-rw-r--r--drivers/usb/renesas_usbhs/mod_gadget.c1384
-rw-r--r--drivers/usb/renesas_usbhs/pipe.c874
-rw-r--r--drivers/usb/renesas_usbhs/pipe.h104
-rw-r--r--drivers/usb/serial/Kconfig9
-rw-r--r--drivers/usb/serial/Makefile1
-rw-r--r--drivers/usb/serial/cp210x.c6
-rw-r--r--drivers/usb/serial/ftdi_sio.c1
-rw-r--r--drivers/usb/serial/ftdi_sio_ids.h5
-rw-r--r--drivers/usb/serial/garmin_gps.c20
-rw-r--r--drivers/usb/serial/moto_modem.c1
-rw-r--r--drivers/usb/serial/opticon.c7
-rw-r--r--drivers/usb/serial/option.c10
-rw-r--r--drivers/usb/serial/sam-ba.c206
-rw-r--r--drivers/usb/storage/ene_ub6250.c4
-rw-r--r--drivers/usb/storage/isd200.c1
-rw-r--r--drivers/usb/storage/unusual_realtek.h10
-rw-r--r--drivers/usb/storage/usb.c9
-rw-r--r--drivers/video/Kconfig58
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/amifb.c27
-rw-r--r--drivers/video/atafb.c2
-rw-r--r--drivers/video/backlight/88pm860x_bl.c7
-rw-r--r--drivers/video/backlight/adp5520_bl.c6
-rw-r--r--drivers/video/backlight/ltv350qv.c2
-rw-r--r--drivers/video/console/newport_con.c2
-rw-r--r--drivers/video/da8xx-fb.c4
-rw-r--r--drivers/video/efifb.c4
-rw-r--r--drivers/video/imxfb.c28
-rw-r--r--drivers/video/mb862xx/Makefile5
-rw-r--r--drivers/video/mb862xx/mb862xx-i2c.c178
-rw-r--r--drivers/video/mb862xx/mb862xx_reg.h58
-rw-r--r--drivers/video/mb862xx/mb862xxfb.h36
-rw-r--r--drivers/video/mb862xx/mb862xxfbdrv.c (renamed from drivers/video/mb862xx/mb862xxfb.c)153
-rw-r--r--drivers/video/msm/mddi.c2
-rw-r--r--drivers/video/mxsfb.c2
-rw-r--r--drivers/video/omap/Makefile1
-rw-r--r--drivers/video/omap/dispc.c4
-rw-r--r--drivers/video/omap/lcd_omap2evm.c192
-rw-r--r--drivers/video/omap/omapfb_main.c2
-rw-r--r--drivers/video/omap/rfbi.c2
-rw-r--r--drivers/video/omap2/Makefile4
-rw-r--r--drivers/video/omap2/displays/Kconfig9
-rw-r--r--drivers/video/omap2/displays/panel-acx565akm.c2
-rw-r--r--drivers/video/omap2/displays/panel-generic-dpi.c57
-rw-r--r--drivers/video/omap2/displays/panel-lgphilips-lb035q02.c2
-rw-r--r--drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c2
-rw-r--r--drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c6
-rw-r--r--drivers/video/omap2/displays/panel-taal.c536
-rw-r--r--drivers/video/omap2/displays/panel-tpo-td043mtea1.c10
-rw-r--r--drivers/video/omap2/dss/Kconfig33
-rw-r--r--drivers/video/omap2/dss/core.c15
-rw-r--r--drivers/video/omap2/dss/dispc.c1552
-rw-r--r--drivers/video/omap2/dss/dispc.h691
-rw-r--r--drivers/video/omap2/dss/display.c46
-rw-r--r--drivers/video/omap2/dss/dpi.c113
-rw-r--r--drivers/video/omap2/dss/dsi.c2367
-rw-r--r--drivers/video/omap2/dss/dss.c118
-rw-r--r--drivers/video/omap2/dss/dss.h98
-rw-r--r--drivers/video/omap2/dss/dss_features.c105
-rw-r--r--drivers/video/omap2/dss/dss_features.h39
-rw-r--r--drivers/video/omap2/dss/hdmi.c461
-rw-r--r--drivers/video/omap2/dss/hdmi.h222
-rw-r--r--drivers/video/omap2/dss/hdmi_omap4_panel.c2
-rw-r--r--drivers/video/omap2/dss/manager.c14
-rw-r--r--drivers/video/omap2/dss/overlay.c43
-rw-r--r--drivers/video/omap2/dss/rfbi.c176
-rw-r--r--drivers/video/omap2/dss/sdi.c2
-rw-r--r--drivers/video/omap2/dss/venc.c23
-rw-r--r--drivers/video/omap2/omapfb/omapfb-ioctl.c14
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c231
-rw-r--r--drivers/video/omap2/omapfb/omapfb-sysfs.c23
-rw-r--r--drivers/video/omap2/omapfb/omapfb.h8
-rw-r--r--drivers/video/s3c-fb.c121
-rw-r--r--drivers/video/s3c2410fb.c8
-rw-r--r--drivers/video/s3fb.c209
-rw-r--r--drivers/video/savage/savagefb-i2c.c2
-rw-r--r--drivers/video/savage/savagefb.h8
-rw-r--r--drivers/video/savage/savagefb_driver.c15
-rw-r--r--drivers/video/sh7760fb.c6
-rw-r--r--drivers/video/sh_mobile_hdmi.c10
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c126
-rw-r--r--drivers/video/sh_mobile_lcdcfb.h1
-rw-r--r--drivers/video/sh_mobile_meram.c567
-rw-r--r--drivers/video/sh_mobile_meram.h41
-rw-r--r--drivers/video/sm501fb.c24
-rw-r--r--drivers/video/tmiofb.c12
-rw-r--r--drivers/video/udlfb.c21
-rw-r--r--drivers/video/via/Makefile2
-rw-r--r--drivers/video/via/chip.h6
-rw-r--r--drivers/video/via/dvi.c160
-rw-r--r--drivers/video/via/dvi.h2
-rw-r--r--drivers/video/via/global.c4
-rw-r--r--drivers/video/via/global.h2
-rw-r--r--drivers/video/via/hw.c630
-rw-r--r--drivers/video/via/hw.h15
-rw-r--r--drivers/video/via/lcd.c23
-rw-r--r--drivers/video/via/lcd.h2
-rw-r--r--drivers/video/via/share.h17
-rw-r--r--drivers/video/via/via-core.c9
-rw-r--r--drivers/video/via/via-gpio.c49
-rw-r--r--drivers/video/via/via_clock.c349
-rw-r--r--drivers/video/via/via_clock.h76
-rw-r--r--drivers/video/via/viafbdev.c62
-rw-r--r--drivers/video/via/viafbdev.h4
-rw-r--r--drivers/video/via/viamode.c46
-rw-r--r--drivers/video/via/viamode.h9
-rw-r--r--drivers/w1/masters/Kconfig2
-rw-r--r--drivers/w1/masters/ds1wm.c333
-rw-r--r--drivers/w1/slaves/Kconfig20
-rw-r--r--drivers/w1/slaves/Makefile2
-rw-r--r--drivers/w1/slaves/w1_ds2408.c402
-rw-r--r--drivers/w1/slaves/w1_ds2780.c217
-rw-r--r--drivers/w1/slaves/w1_ds2780.h129
-rw-r--r--drivers/w1/w1.c12
-rw-r--r--drivers/w1/w1.h6
-rw-r--r--drivers/w1/w1_family.h2
-rw-r--r--drivers/w1/w1_io.c26
-rw-r--r--drivers/w1/w1_netlink.c5
-rw-r--r--drivers/watchdog/Kconfig6
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/bcm63xx_wdt.c2
-rw-r--r--drivers/watchdog/lantiq_wdt.c261
-rw-r--r--drivers/watchdog/mtx-1_wdt.c21
-rw-r--r--drivers/watchdog/rdc321x_wdt.c3
-rw-r--r--drivers/xen/Makefile25
-rw-r--r--drivers/xen/balloon.c25
-rw-r--r--drivers/xen/events.c152
-rw-r--r--drivers/xen/evtchn.c2
-rw-r--r--drivers/xen/gntalloc.c14
-rw-r--r--drivers/xen/gntdev.c16
-rw-r--r--drivers/xen/grant-table.c31
-rw-r--r--drivers/xen/manage.c8
-rw-r--r--drivers/xen/swiotlb-xen.c2
-rw-r--r--drivers/xen/sys-hypervisor.c2
-rw-r--r--drivers/xen/tmem.c264
-rw-r--r--firmware/Makefile6
-rw-r--r--firmware/WHENCE9
-rw-r--r--firmware/bnx2x/bnx2x-e1-6.2.5.0.fw.ihex9483
-rw-r--r--firmware/bnx2x/bnx2x-e1-6.2.9.0.fw.ihex9484
-rw-r--r--firmware/bnx2x/bnx2x-e1h-6.2.5.0.fw.ihex13181
-rw-r--r--firmware/bnx2x/bnx2x-e1h-6.2.9.0.fw.ihex13192
-rw-r--r--firmware/bnx2x/bnx2x-e2-6.2.5.0.fw.ihex15456
-rw-r--r--firmware/bnx2x/bnx2x-e2-6.2.9.0.fw.ihex15473
-rw-r--r--fs/9p/Kconfig5
-rw-r--r--fs/9p/vfs_inode.c4
-rw-r--r--fs/9p/vfs_inode_dotl.c11
-rw-r--r--fs/Kconfig19
-rw-r--r--fs/affs/namei.c5
-rw-r--r--fs/afs/dir.c5
-rw-r--r--fs/autofs4/root.c2
-rw-r--r--fs/bfs/dir.c3
-rw-r--r--fs/binfmt_flat.c8
-rw-r--r--fs/block_dev.c34
-rw-r--r--fs/btrfs/extent_io.c10
-rw-r--r--fs/btrfs/relocation.c2
-rw-r--r--fs/btrfs/super.c2
-rw-r--r--fs/buffer.c64
-rw-r--r--fs/ceph/addr.c5
-rw-r--r--fs/ceph/caps.c61
-rw-r--r--fs/ceph/dir.c7
-rw-r--r--fs/ceph/export.c25
-rw-r--r--fs/ceph/mds_client.c7
-rw-r--r--fs/ceph/mds_client.h1
-rw-r--r--fs/cifs/Kconfig15
-rw-r--r--fs/cifs/Makefile2
-rw-r--r--fs/cifs/README15
-rw-r--r--fs/cifs/cache.c6
-rw-r--r--fs/cifs/cifs_debug.c28
-rw-r--r--fs/cifs/cifs_dfs_ref.c2
-rw-r--r--fs/cifs/cifs_fs_sb.h7
-rw-r--r--fs/cifs/cifs_spnego.c2
-rw-r--r--fs/cifs/cifs_spnego.h2
-rw-r--r--fs/cifs/cifs_unicode.h3
-rw-r--r--fs/cifs/cifsacl.c490
-rw-r--r--fs/cifs/cifsacl.h25
-rw-r--r--fs/cifs/cifsencrypt.c26
-rw-r--r--fs/cifs/cifsfs.c338
-rw-r--r--fs/cifs/cifsfs.h20
-rw-r--r--fs/cifs/cifsglob.h139
-rw-r--r--fs/cifs/cifspdu.h37
-rw-r--r--fs/cifs/cifsproto.h237
-rw-r--r--fs/cifs/cifssmb.c838
-rw-r--r--fs/cifs/connect.c860
-rw-r--r--fs/cifs/dir.c33
-rw-r--r--fs/cifs/export.c4
-rw-r--r--fs/cifs/file.c543
-rw-r--r--fs/cifs/fscache.c6
-rw-r--r--fs/cifs/fscache.h8
-rw-r--r--fs/cifs/inode.c221
-rw-r--r--fs/cifs/ioctl.c2
-rw-r--r--fs/cifs/link.c46
-rw-r--r--fs/cifs/misc.c44
-rw-r--r--fs/cifs/netmisc.c9
-rw-r--r--fs/cifs/readdir.c8
-rw-r--r--fs/cifs/sess.c51
-rw-r--r--fs/cifs/smbdes.c418
-rw-r--r--fs/cifs/smbencrypt.c124
-rw-r--r--fs/cifs/transport.c264
-rw-r--r--fs/cifs/xattr.c28
-rw-r--r--fs/coda/dir.c5
-rw-r--r--fs/compat.c235
-rw-r--r--fs/configfs/dir.c2
-rw-r--r--fs/dcache.c9
-rw-r--r--fs/debugfs/file.c19
-rw-r--r--fs/dlm/config.c9
-rw-r--r--fs/dlm/config.h1
-rw-r--r--fs/dlm/dlm_internal.h3
-rw-r--r--fs/dlm/lock.c182
-rw-r--r--fs/dlm/lock.h1
-rw-r--r--fs/dlm/lockspace.c6
-rw-r--r--fs/dlm/main.c2
-rw-r--r--fs/dlm/plock.c65
-rw-r--r--fs/dlm/user.c1
-rw-r--r--fs/drop_caches.c5
-rw-r--r--fs/ecryptfs/inode.c5
-rw-r--r--fs/exec.c178
-rw-r--r--fs/ext2/super.c3
-rw-r--r--fs/ext3/namei.c80
-rw-r--r--fs/ext3/super.c2
-rw-r--r--fs/ext4/Makefile3
-rw-r--r--fs/ext4/balloc.c146
-rw-r--r--fs/ext4/ext4.h127
-rw-r--r--fs/ext4/ext4_jbd2.c14
-rw-r--r--fs/ext4/ext4_jbd2.h5
-rw-r--r--fs/ext4/extents.c1410
-rw-r--r--fs/ext4/file.c1
-rw-r--r--fs/ext4/fsync.c25
-rw-r--r--fs/ext4/inode.c114
-rw-r--r--fs/ext4/mballoc.c459
-rw-r--r--fs/ext4/mballoc.h6
-rw-r--r--fs/ext4/migrate.c2
-rw-r--r--fs/ext4/mmp.c351
-rw-r--r--fs/ext4/move_extent.c3
-rw-r--r--fs/ext4/namei.c82
-rw-r--r--fs/ext4/page-io.c39
-rw-r--r--fs/ext4/super.c206
-rw-r--r--fs/ext4/xattr.c4
-rw-r--r--fs/fat/cache.c7
-rw-r--r--fs/fat/dir.c32
-rw-r--r--fs/fat/fat.h15
-rw-r--r--fs/fat/fatent.c4
-rw-r--r--fs/fat/inode.c74
-rw-r--r--fs/fat/misc.c44
-rw-r--r--fs/fat/namei_msdos.c9
-rw-r--r--fs/fat/namei_vfat.c9
-rw-r--r--fs/freevxfs/vxfs_inode.c2
-rw-r--r--fs/fscache/operation.c10
-rw-r--r--fs/fscache/page.c13
-rw-r--r--fs/fuse/dir.c6
-rw-r--r--fs/gfs2/Makefile4
-rw-r--r--fs/gfs2/aops.c8
-rw-r--r--fs/gfs2/bmap.c2
-rw-r--r--fs/gfs2/dir.c197
-rw-r--r--fs/gfs2/dir.h4
-rw-r--r--fs/gfs2/export.c2
-rw-r--r--fs/gfs2/file.c46
-rw-r--r--fs/gfs2/glock.c99
-rw-r--r--fs/gfs2/glock.h3
-rw-r--r--fs/gfs2/glops.c172
-rw-r--r--fs/gfs2/glops.h2
-rw-r--r--fs/gfs2/incore.h8
-rw-r--r--fs/gfs2/inode.c1510
-rw-r--r--fs/gfs2/inode.h8
-rw-r--r--fs/gfs2/log.c208
-rw-r--r--fs/gfs2/log.h2
-rw-r--r--fs/gfs2/lops.c39
-rw-r--r--fs/gfs2/main.c3
-rw-r--r--fs/gfs2/meta_io.c2
-rw-r--r--fs/gfs2/meta_io.h2
-rw-r--r--fs/gfs2/ops_fstype.c32
-rw-r--r--fs/gfs2/ops_inode.c1344
-rw-r--r--fs/gfs2/quota.c12
-rw-r--r--fs/gfs2/quota.h4
-rw-r--r--fs/gfs2/rgrp.c24
-rw-r--r--fs/gfs2/super.c138
-rw-r--r--fs/gfs2/sys.c6
-rw-r--r--fs/gfs2/trace_gfs2.h38
-rw-r--r--fs/hfs/dir.c6
-rw-r--r--fs/hfsplus/dir.c8
-rw-r--r--fs/hostfs/hostfs_kern.c5
-rw-r--r--fs/hpfs/namei.c9
-rw-r--r--fs/hugetlbfs/inode.c7
-rw-r--r--fs/inode.c10
-rw-r--r--fs/jbd/commit.c15
-rw-r--r--fs/jbd/journal.c16
-rw-r--r--fs/jbd/transaction.c3
-rw-r--r--fs/jbd2/commit.c28
-rw-r--r--fs/jbd2/journal.c58
-rw-r--r--fs/jbd2/transaction.c22
-rw-r--r--fs/jffs2/dir.c5
-rw-r--r--fs/jfs/namei.c5
-rw-r--r--fs/logfs/dev_bdev.c1
-rw-r--r--fs/logfs/dir.c5
-rw-r--r--fs/logfs/readwrite.c2
-rw-r--r--fs/mbcache.c10
-rw-r--r--fs/minix/namei.c5
-rw-r--r--fs/mpage.c7
-rw-r--r--fs/namei.c382
-rw-r--r--fs/namespace.c2
-rw-r--r--fs/ncpfs/dir.c5
-rw-r--r--fs/ncpfs/inode.c4
-rw-r--r--fs/ncpfs/mmap.c2
-rw-r--r--fs/nfs/dir.c5
-rw-r--r--fs/nfs/internal.h2
-rw-r--r--fs/nfsd/stats.c2
-rw-r--r--fs/nilfs2/alloc.c12
-rw-r--r--fs/nilfs2/bmap.c4
-rw-r--r--fs/nilfs2/btnode.c19
-rw-r--r--fs/nilfs2/btnode.h4
-rw-r--r--fs/nilfs2/btree.c38
-rw-r--r--fs/nilfs2/cpfile.c24
-rw-r--r--fs/nilfs2/dat.c4
-rw-r--r--fs/nilfs2/file.c1
-rw-r--r--fs/nilfs2/gcinode.c25
-rw-r--r--fs/nilfs2/ifile.c4
-rw-r--r--fs/nilfs2/inode.c23
-rw-r--r--fs/nilfs2/ioctl.c61
-rw-r--r--fs/nilfs2/mdt.c8
-rw-r--r--fs/nilfs2/mdt.h9
-rw-r--r--fs/nilfs2/namei.c5
-rw-r--r--fs/nilfs2/nilfs.h7
-rw-r--r--fs/nilfs2/page.c79
-rw-r--r--fs/nilfs2/page.h7
-rw-r--r--fs/nilfs2/recovery.c12
-rw-r--r--fs/nilfs2/segbuf.c17
-rw-r--r--fs/nilfs2/segment.c190
-rw-r--r--fs/nilfs2/segment.h2
-rw-r--r--fs/nilfs2/sufile.c274
-rw-r--r--fs/nilfs2/sufile.h4
-rw-r--r--fs/nilfs2/super.c131
-rw-r--r--fs/nilfs2/the_nilfs.c24
-rw-r--r--fs/nilfs2/the_nilfs.h2
-rw-r--r--fs/ocfs2/Makefile1
-rw-r--r--fs/ocfs2/alloc.c166
-rw-r--r--fs/ocfs2/alloc.h1
-rw-r--r--fs/ocfs2/cluster/sys.c9
-rw-r--r--fs/ocfs2/dlm/dlmcommon.h14
-rw-r--r--fs/ocfs2/dlm/dlmdebug.c6
-rw-r--r--fs/ocfs2/dlm/dlmdomain.c94
-rw-r--r--fs/ocfs2/dlm/dlmmaster.c255
-rw-r--r--fs/ocfs2/dlm/dlmrecovery.c1
-rw-r--r--fs/ocfs2/dlmfs/dlmfs.c2
-rw-r--r--fs/ocfs2/file.c1
-rw-r--r--fs/ocfs2/ioctl.c492
-rw-r--r--fs/ocfs2/move_extents.c1152
-rw-r--r--fs/ocfs2/move_extents.h22
-rw-r--r--fs/ocfs2/ocfs2_ioctl.h68
-rw-r--r--fs/ocfs2/ocfs2_trace.h25
-rw-r--r--fs/ocfs2/refcounttree.c60
-rw-r--r--fs/ocfs2/refcounttree.h11
-rw-r--r--fs/ocfs2/super.c4
-rw-r--r--fs/omfs/dir.c11
-rw-r--r--fs/partitions/check.c10
-rw-r--r--fs/partitions/efi.c9
-rw-r--r--fs/partitions/ldm.c7
-rw-r--r--fs/proc/Makefile1
-rw-r--r--fs/proc/array.c4
-rw-r--r--fs/proc/base.c103
-rw-r--r--fs/proc/generic.c1
-rw-r--r--fs/proc/inode.c7
-rw-r--r--fs/proc/internal.h26
-rw-r--r--fs/proc/namespaces.c198
-rw-r--r--fs/proc/stat.c6
-rw-r--r--fs/proc/task_mmu.c233
-rw-r--r--fs/proc/vmcore.c52
-rw-r--r--fs/pstore/platform.c12
-rw-r--r--fs/quota/dquot.c5
-rw-r--r--fs/reiserfs/namei.c5
-rw-r--r--fs/reiserfs/xattr.c1
-rw-r--r--fs/splice.c33
-rw-r--r--fs/squashfs/Kconfig4
-rw-r--r--fs/squashfs/block.c2
-rw-r--r--fs/squashfs/cache.c33
-rw-r--r--fs/squashfs/decompressor.c2
-rw-r--r--fs/squashfs/decompressor.h2
-rw-r--r--fs/squashfs/dir.c2
-rw-r--r--fs/squashfs/export.c42
-rw-r--r--fs/squashfs/file.c2
-rw-r--r--fs/squashfs/fragment.c37
-rw-r--r--fs/squashfs/id.c42
-rw-r--r--fs/squashfs/inode.c2
-rw-r--r--fs/squashfs/namei.c2
-rw-r--r--fs/squashfs/squashfs.h10
-rw-r--r--fs/squashfs/squashfs_fs.h2
-rw-r--r--fs/squashfs/squashfs_fs_i.h2
-rw-r--r--fs/squashfs/squashfs_fs_sb.h2
-rw-r--r--fs/squashfs/super.c112
-rw-r--r--fs/squashfs/symlink.c2
-rw-r--r--fs/squashfs/xattr.c2
-rw-r--r--fs/squashfs/xattr.h3
-rw-r--r--fs/squashfs/xattr_id.c47
-rw-r--r--fs/squashfs/xz_wrapper.c2
-rw-r--r--fs/squashfs/zlib_wrapper.c2
-rw-r--r--fs/super.c6
-rw-r--r--fs/sysfs/file.c12
-rw-r--r--fs/sysfs/group.c6
-rw-r--r--fs/sysv/namei.c5
-rw-r--r--fs/timerfd.c102
-rw-r--r--fs/ubifs/budget.c104
-rw-r--r--fs/ubifs/commit.c2
-rw-r--r--fs/ubifs/debug.c167
-rw-r--r--fs/ubifs/debug.h178
-rw-r--r--fs/ubifs/dir.c9
-rw-r--r--fs/ubifs/file.c28
-rw-r--r--fs/ubifs/find.c10
-rw-r--r--fs/ubifs/gc.c71
-rw-r--r--fs/ubifs/io.c33
-rw-r--r--fs/ubifs/journal.c29
-rw-r--r--fs/ubifs/log.c28
-rw-r--r--fs/ubifs/lprops.c115
-rw-r--r--fs/ubifs/lpt_commit.c55
-rw-r--r--fs/ubifs/master.c8
-rw-r--r--fs/ubifs/misc.h17
-rw-r--r--fs/ubifs/orphan.c3
-rw-r--r--fs/ubifs/recovery.c354
-rw-r--r--fs/ubifs/replay.c468
-rw-r--r--fs/ubifs/sb.c153
-rw-r--r--fs/ubifs/super.c46
-rw-r--r--fs/ubifs/tnc.c10
-rw-r--r--fs/ubifs/tnc_commit.c18
-rw-r--r--fs/ubifs/ubifs-media.h30
-rw-r--r--fs/ubifs/ubifs.h86
-rw-r--r--fs/ubifs/xattr.c8
-rw-r--r--fs/udf/namei.c5
-rw-r--r--fs/ufs/balloc.c9
-rw-r--r--fs/ufs/inode.c2
-rw-r--r--fs/ufs/namei.c5
-rw-r--r--fs/ufs/truncate.c2
-rw-r--r--fs/xfs/linux-2.6/xfs_buf.c26
-rw-r--r--fs/xfs/linux-2.6/xfs_buf.h1
-rw-r--r--fs/xfs/linux-2.6/xfs_discard.c29
-rw-r--r--fs/xfs/linux-2.6/xfs_discard.h2
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl32.c3
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl32.h1
-rw-r--r--fs/xfs/linux-2.6/xfs_linux.h1
-rw-r--r--fs/xfs/linux-2.6/xfs_message.c20
-rw-r--r--fs/xfs/linux-2.6/xfs_message.h7
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c22
-rw-r--r--fs/xfs/linux-2.6/xfs_sync.c15
-rw-r--r--fs/xfs/linux-2.6/xfs_trace.h76
-rw-r--r--fs/xfs/quota/xfs_qm.c6
-rw-r--r--fs/xfs/xfs_ag.h4
-rw-r--r--fs/xfs/xfs_alloc.c871
-rw-r--r--fs/xfs/xfs_alloc.h18
-rw-r--r--fs/xfs/xfs_alloc_btree.c16
-rw-r--r--fs/xfs/xfs_bmap.c549
-rw-r--r--fs/xfs/xfs_bmap.h2
-rw-r--r--fs/xfs/xfs_dfrag.c6
-rw-r--r--fs/xfs/xfs_inode.c19
-rw-r--r--fs/xfs/xfs_inode.h1
-rw-r--r--fs/xfs/xfs_inode_item.c1
-rw-r--r--fs/xfs/xfs_log.c15
-rw-r--r--fs/xfs/xfs_log.h2
-rw-r--r--fs/xfs/xfs_log_cil.c16
-rw-r--r--fs/xfs/xfs_log_priv.h2
-rw-r--r--fs/xfs/xfs_log_recover.c75
-rw-r--r--fs/xfs/xfs_mount.c4
-rw-r--r--fs/xfs/xfs_mount.h1
-rw-r--r--fs/xfs/xfs_trans.c6
-rw-r--r--fs/xfs/xfs_types.h2
-rw-r--r--include/asm-generic/audit_change_attr.h4
-rw-r--r--include/asm-generic/audit_dir_write.h14
-rw-r--r--include/asm-generic/audit_read.h5
-rw-r--r--include/asm-generic/audit_write.h2
-rw-r--r--include/asm-generic/bitops/find.h4
-rw-r--r--include/asm-generic/bitops/le.h7
-rw-r--r--include/asm-generic/bug.h37
-rw-r--r--include/asm-generic/cacheflush.h5
-rw-r--r--include/asm-generic/pgtable.h12
-rw-r--r--include/asm-generic/ptrace.h74
-rw-r--r--include/asm-generic/resource.h2
-rw-r--r--include/asm-generic/tlb.h156
-rw-r--r--include/asm-generic/unistd.h221
-rw-r--r--include/asm-generic/vmlinux.lds.h95
-rw-r--r--include/asm-generic/xor.h2
-rw-r--r--include/drm/drmP.h49
-rw-r--r--include/drm/drm_crtc.h6
-rw-r--r--include/drm/drm_dp_helper.h5
-rw-r--r--include/drm/drm_edid.h25
-rw-r--r--include/drm/drm_fb_helper.h16
-rw-r--r--include/linux/Kbuild3
-rw-r--r--include/linux/alarmtimer.h40
-rw-r--r--include/linux/ath9k_platform.h7
-rw-r--r--include/linux/basic_mmio_gpio.h56
-rw-r--r--include/linux/bcma/bcma.h224
-rw-r--r--include/linux/bcma/bcma_driver_chipcommon.h302
-rw-r--r--include/linux/bcma/bcma_driver_pci.h89
-rw-r--r--include/linux/bcma/bcma_regs.h34
-rw-r--r--include/linux/binfmts.h4
-rw-r--r--include/linux/bitmap.h5
-rw-r--r--include/linux/bitops.h4
-rw-r--r--include/linux/blk_types.h2
-rw-r--r--include/linux/blkdev.h15
-rw-r--r--include/linux/bootmem.h25
-rw-r--r--include/linux/bsearch.h9
-rw-r--r--include/linux/buffer_head.h16
-rw-r--r--include/linux/c2port.h3
-rw-r--r--include/linux/can/core.h4
-rw-r--r--include/linux/capability.h12
-rw-r--r--include/linux/ceph/ceph_fs.h1
-rw-r--r--include/linux/cgroup.h13
-rw-r--r--include/linux/cgroup_subsys.h6
-rw-r--r--include/linux/cleancache.h122
-rw-r--r--include/linux/clockchips.h56
-rw-r--r--include/linux/clocksource.h42
-rw-r--r--include/linux/compat.h236
-rw-r--r--include/linux/compiler-gcc.h4
-rw-r--r--include/linux/compiler-gcc4.h2
-rw-r--r--include/linux/cpufreq.h52
-rw-r--r--include/linux/cpumask.h15
-rw-r--r--include/linux/crash_dump.h5
-rw-r--r--include/linux/device.h171
-rw-r--r--include/linux/dlm_plock.h6
-rw-r--r--include/linux/drbd.h10
-rw-r--r--include/linux/drbd_tag_magic.h2
-rw-r--r--include/linux/dvb/frontend.h20
-rw-r--r--include/linux/dvb/version.h2
-rw-r--r--include/linux/dynamic_debug.h2
-rw-r--r--include/linux/elf.h1
-rw-r--r--include/linux/ethtool.h317
-rw-r--r--include/linux/filter.h83
-rw-r--r--include/linux/firewire.h6
-rw-r--r--include/linux/flex_array.h2
-rw-r--r--include/linux/fs.h12
-rw-r--r--include/linux/fscache-cache.h12
-rw-r--r--include/linux/fsl_devices.h16
-rw-r--r--include/linux/ftrace.h35
-rw-r--r--include/linux/genalloc.h25
-rw-r--r--include/linux/genhd.h2
-rw-r--r--include/linux/gfp.h9
-rw-r--r--include/linux/gpio_keys.h8
-rw-r--r--include/linux/hrtimer.h33
-rw-r--r--include/linux/huge_mm.h8
-rw-r--r--include/linux/hugetlb.h7
-rw-r--r--include/linux/hugetlb_inline.h2
-rw-r--r--include/linux/i2c.h2
-rw-r--r--include/linux/i2c/i2c-sh_mobile.h10
-rw-r--r--include/linux/i2c/mpr121_touchkey.h20
-rw-r--r--include/linux/i2c/tsc2007.h7
-rw-r--r--include/linux/i2c/twl.h54
-rw-r--r--include/linux/ide.h2
-rw-r--r--include/linux/ieee80211.h20
-rw-r--r--include/linux/if_ether.h1
-rw-r--r--include/linux/if_link.h1
-rw-r--r--include/linux/if_vlan.h16
-rw-r--r--include/linux/init.h14
-rw-r--r--include/linux/init_task.h17
-rw-r--r--include/linux/input/ad714x.h3
-rw-r--r--include/linux/input/adp5589.h213
-rw-r--r--include/linux/input/pmic8xxx-keypad.h52
-rw-r--r--include/linux/input/pmic8xxx-pwrkey.h31
-rw-r--r--include/linux/interrupt.h1
-rw-r--r--include/linux/ipmi_smi.h2
-rw-r--r--include/linux/irq.h179
-rw-r--r--include/linux/irqdesc.h11
-rw-r--r--include/linux/jbd2.h8
-rw-r--r--include/linux/jump_label.h89
-rw-r--r--include/linux/jump_label_ref.h44
-rw-r--r--include/linux/kernel.h40
-rw-r--r--include/linux/key.h13
-rw-r--r--include/linux/kmod.h4
-rw-r--r--include/linux/kvm.h6
-rw-r--r--include/linux/kvm_host.h31
-rw-r--r--include/linux/leds-pca9532.h3
-rw-r--r--include/linux/leds-regulator.h2
-rw-r--r--include/linux/leds.h2
-rw-r--r--include/linux/libata.h1
-rw-r--r--include/linux/linkage.h4
-rw-r--r--include/linux/list.h35
-rw-r--r--include/linux/lockdep.h3
-rw-r--r--include/linux/lru_cache.h12
-rw-r--r--include/linux/lsm_audit.h11
-rw-r--r--include/linux/memblock.h9
-rw-r--r--include/linux/memcontrol.h24
-rw-r--r--include/linux/mempolicy.h7
-rw-r--r--include/linux/mfd/88pm860x.h6
-rw-r--r--include/linux/mfd/abx500.h8
-rw-r--r--include/linux/mfd/asic3.h23
-rw-r--r--include/linux/mfd/core.h23
-rw-r--r--include/linux/mfd/db5500-prcmu.h45
-rw-r--r--include/linux/mfd/db8500-prcmu.h978
-rw-r--r--include/linux/mfd/max8997-private.h4
-rw-r--r--include/linux/mfd/pm8xxx/core.h81
-rw-r--r--include/linux/mfd/pm8xxx/irq.h59
-rw-r--r--include/linux/mfd/pm8xxx/pm8921.h (renamed from arch/arm/mach-msm/include/mach/smp.h)24
-rw-r--r--include/linux/mfd/tmio.h17
-rw-r--r--include/linux/mfd/tps65910.h800
-rw-r--r--include/linux/mfd/twl4030-codec.h2
-rw-r--r--include/linux/mfd/wm831x/core.h26
-rw-r--r--include/linux/mfd/wm831x/pdata.h4
-rw-r--r--include/linux/mfd/wm8994/pdata.h49
-rw-r--r--include/linux/mm.h137
-rw-r--r--include/linux/mm_types.h25
-rw-r--r--include/linux/mmc/Kbuild1
-rw-r--r--include/linux/mmc/card.h189
-rw-r--r--include/linux/mmc/core.h5
-rw-r--r--include/linux/mmc/host.h49
-rw-r--r--include/linux/mmc/ioctl.h54
-rw-r--r--include/linux/mmc/mmc.h18
-rw-r--r--include/linux/mmc/sd.h9
-rw-r--r--include/linux/mmc/sdhci.h15
-rw-r--r--include/linux/mmc/sh_mobile_sdhi.h4
-rw-r--r--include/linux/mmu_notifier.h2
-rw-r--r--include/linux/mmzone.h14
-rw-r--r--include/linux/mod_devicetable.h17
-rw-r--r--include/linux/module.h37
-rw-r--r--include/linux/moduleparam.h7
-rw-r--r--include/linux/mroute.h1
-rw-r--r--include/linux/mtd/physmap.h4
-rw-r--r--include/linux/mtd/ubi.h4
-rw-r--r--include/linux/mutex.h11
-rw-r--r--include/linux/mxm-wmi.h33
-rw-r--r--include/linux/net.h1
-rw-r--r--include/linux/netdevice.h46
-rw-r--r--include/linux/netfilter/ipset/ip_set_getport.h2
-rw-r--r--include/linux/netfilter/x_tables.h96
-rw-r--r--include/linux/netlink.h1
-rw-r--r--include/linux/nilfs2_fs.h4
-rw-r--r--include/linux/nl80211.h371
-rw-r--r--include/linux/nmi.h7
-rw-r--r--include/linux/notifier.h3
-rw-r--r--include/linux/nsproxy.h9
-rw-r--r--include/linux/of_irq.h1
-rw-r--r--include/linux/oom.h2
-rw-r--r--include/linux/page-flags.h2
-rw-r--r--include/linux/pagemap.h15
-rw-r--r--include/linux/pci-aspm.h1
-rw-r--r--include/linux/pci-ats.h52
-rw-r--r--include/linux/pci.h56
-rw-r--r--include/linux/pci_ids.h4
-rw-r--r--include/linux/pci_regs.h17
-rw-r--r--include/linux/percpu_counter.h6
-rw-r--r--include/linux/perf_event.h121
-rw-r--r--include/linux/pid.h2
-rw-r--r--include/linux/pkt_sched.h15
-rw-r--r--include/linux/platform_device.h63
-rw-r--r--include/linux/pm.h39
-rw-r--r--include/linux/pm_runtime.h42
-rw-r--r--include/linux/posix-clock.h2
-rw-r--r--include/linux/posix-timers.h3
-rw-r--r--include/linux/power/isp1704_charger.h (renamed from arch/arm/mach-stmp378x/include/mach/regs-saif.h)18
-rw-r--r--include/linux/power/max8903_charger.h57
-rw-r--r--include/linux/printk.h7
-rw-r--r--include/linux/proc_fs.h40
-rw-r--r--include/linux/pstore.h4
-rw-r--r--include/linux/pti.h42
-rw-r--r--include/linux/ptp_classify.h7
-rw-r--r--include/linux/ptp_clock.h84
-rw-r--r--include/linux/ptp_clock_kernel.h139
-rw-r--r--include/linux/rbtree.h8
-rw-r--r--include/linux/rculist.h16
-rw-r--r--include/linux/rcupdate.h70
-rw-r--r--include/linux/rcutiny.h8
-rw-r--r--include/linux/rcutree.h13
-rw-r--r--include/linux/regulator/db8500-prcmu.h45
-rw-r--r--include/linux/regulator/machine.h7
-rw-r--r--include/linux/rfkill-gpio.h43
-rw-r--r--include/linux/rfkill-regulator.h48
-rw-r--r--include/linux/rmap.h29
-rw-r--r--include/linux/rotary_encoder.h1
-rw-r--r--include/linux/rtc.h8
-rw-r--r--include/linux/sched.h151
-rw-r--r--include/linux/seqlock.h7
-rw-r--r--include/linux/serial_core.h6
-rw-r--r--include/linux/serial_reg.h2
-rw-r--r--include/linux/shmem_fs.h8
-rw-r--r--include/linux/sht15.h18
-rw-r--r--include/linux/signal.h15
-rw-r--r--include/linux/skbuff.h10
-rw-r--r--include/linux/slub_def.h8
-rw-r--r--include/linux/smp.h10
-rw-r--r--include/linux/smsc911x.h1
-rw-r--r--include/linux/socket.h2
-rw-r--r--include/linux/spi/ads7846.h3
-rw-r--r--include/linux/spi/spi.h8
-rw-r--r--include/linux/spinlock_up.h2
-rw-r--r--include/linux/ssb/ssb.h7
-rw-r--r--include/linux/ssb/ssb_driver_chipcommon.h11
-rw-r--r--include/linux/ssb/ssb_regs.h2
-rw-r--r--include/linux/stmmac.h2
-rw-r--r--include/linux/string.h1
-rw-r--r--include/linux/swap.h3
-rw-r--r--include/linux/syscalls.h3
-rw-r--r--include/linux/sysdev.h11
-rw-r--r--include/linux/sysfs.h5
-rw-r--r--include/linux/thread_info.h2
-rw-r--r--include/linux/ti_wilink_st.h3
-rw-r--r--include/linux/time.h3
-rw-r--r--include/linux/timerfd.h3
-rw-r--r--include/linux/timerqueue.h2
-rw-r--r--include/linux/tipc.h2
-rw-r--r--include/linux/tracehook.h27
-rw-r--r--include/linux/tracepoint.h22
-rw-r--r--include/linux/tty.h4
-rw-r--r--include/linux/tty_ldisc.h9
-rw-r--r--include/linux/usb.h6
-rw-r--r--include/linux/usb/ch9.h2
-rw-r--r--include/linux/usb/composite.h16
-rw-r--r--include/linux/usb/ehci_def.h15
-rw-r--r--include/linux/usb/gadget.h4
-rw-r--r--include/linux/usb/msm_hsusb.h79
-rw-r--r--include/linux/usb/msm_hsusb_hw.h2
-rw-r--r--include/linux/usb/otg.h6
-rw-r--r--include/linux/usb/renesas_usbhs.h156
-rw-r--r--include/linux/usb/rndis_host.h2
-rw-r--r--include/linux/uvcvideo.h69
-rw-r--r--include/linux/v4l2-mediabus.h3
-rw-r--r--include/linux/videodev2.h4
-rw-r--r--include/linux/vm_event_item.h64
-rw-r--r--include/linux/vmstat.h69
-rw-r--r--include/linux/wl12xx.h29
-rw-r--r--include/linux/xattr.h8
-rw-r--r--include/media/m5mols.h35
-rw-r--r--include/media/mt9v032.h12
-rw-r--r--include/media/rc-core.h7
-rw-r--r--include/media/rc-map.h1
-rw-r--r--include/media/soc_camera.h15
-rw-r--r--include/media/soc_camera_platform.h50
-rw-r--r--include/media/soc_mediabus.h25
-rw-r--r--include/media/v4l2-dev.h2
-rw-r--r--include/media/videobuf-dvb.h4
-rw-r--r--include/mtd/ubi-user.h40
-rw-r--r--include/net/9p/9p.h13
-rw-r--r--include/net/9p/client.h2
-rw-r--r--include/net/9p/transport.h3
-rw-r--r--include/net/addrconf.h25
-rw-r--r--include/net/af_rxrpc.h3
-rw-r--r--include/net/af_unix.h2
-rw-r--r--include/net/atmclip.h2
-rw-r--r--include/net/bluetooth/hci.h51
-rw-r--r--include/net/bluetooth/hci_core.h42
-rw-r--r--include/net/bluetooth/l2cap.h182
-rw-r--r--include/net/bluetooth/mgmt.h57
-rw-r--r--include/net/caif/caif_dev.h50
-rw-r--r--include/net/caif/caif_layer.h36
-rw-r--r--include/net/caif/cfcnfg.h71
-rw-r--r--include/net/caif/cfctrl.h15
-rw-r--r--include/net/caif/cffrml.h7
-rw-r--r--include/net/caif/cfmuxl.h2
-rw-r--r--include/net/caif/cfpkt.h76
-rw-r--r--include/net/caif/cfsrvl.h32
-rw-r--r--include/net/cfg80211.h317
-rw-r--r--include/net/compat.h2
-rw-r--r--include/net/dst.h15
-rw-r--r--include/net/flow.h25
-rw-r--r--include/net/garp.h2
-rw-r--r--include/net/genetlink.h2
-rw-r--r--include/net/if_inet6.h11
-rw-r--r--include/net/inet6_connection_sock.h2
-rw-r--r--include/net/inet_connection_sock.h6
-rw-r--r--include/net/inet_sock.h26
-rw-r--r--include/net/inetpeer.h2
-rw-r--r--include/net/ip.h29
-rw-r--r--include/net/ip6_fib.h13
-rw-r--r--include/net/ip6_route.h26
-rw-r--r--include/net/ip_fib.h9
-rw-r--r--include/net/ip_vs.h14
-rw-r--r--include/net/ipv6.h30
-rw-r--r--include/net/ipx.h2
-rw-r--r--include/net/mac80211.h100
-rw-r--r--include/net/ndisc.h9
-rw-r--r--include/net/net_namespace.h1
-rw-r--r--include/net/netevent.h2
-rw-r--r--include/net/netfilter/nf_conntrack.h2
-rw-r--r--include/net/netfilter/nf_conntrack_tuple.h4
-rw-r--r--include/net/netfilter/nf_nat.h4
-rw-r--r--include/net/netlink.h2
-rw-r--r--include/net/netns/ipv4.h2
-rw-r--r--include/net/phonet/pn_dev.h2
-rw-r--r--include/net/ping.h55
-rw-r--r--include/net/rawv6.h4
-rw-r--r--include/net/route.h163
-rw-r--r--include/net/sctp/command.h1
-rw-r--r--include/net/sctp/constants.h18
-rw-r--r--include/net/sctp/sctp.h3
-rw-r--r--include/net/sctp/sm.h5
-rw-r--r--include/net/sctp/structs.h21
-rw-r--r--include/net/sctp/ulpevent.h3
-rw-r--r--include/net/sctp/user.h33
-rw-r--r--include/net/snmp.h14
-rw-r--r--include/net/sock.h54
-rw-r--r--include/net/transp_v6.h4
-rw-r--r--include/net/wimax.h5
-rw-r--r--include/net/xfrm.h15
-rw-r--r--include/pcmcia/ds.h2
-rw-r--r--include/rdma/Kbuild5
-rw-r--r--include/rdma/ib_addr.h13
-rw-r--r--include/rdma/ib_user_cm.h1
-rw-r--r--include/rdma/iw_cm.h11
-rw-r--r--include/rdma/rdma_cm.h29
-rw-r--r--include/rdma/rdma_netlink.h92
-rw-r--r--include/rdma/rdma_user_cm.h5
-rw-r--r--include/sound/ak4641.h26
-rw-r--r--include/sound/control.h1
-rw-r--r--include/sound/max98095.h54
-rw-r--r--include/sound/soc-dapm.h80
-rw-r--r--include/sound/soc.h32
-rw-r--r--include/sound/tea575x-tuner.h26
-rw-r--r--include/sound/tlv320dac33-plat.h2
-rw-r--r--include/sound/tpa6130a2-plat.h2
-rw-r--r--include/sound/wm8915.h55
-rw-r--r--include/sound/wm8962.h22
-rw-r--r--include/trace/events/gpio.h56
-rw-r--r--include/trace/events/irq.h3
-rw-r--r--include/video/newport.h2
-rw-r--r--include/video/omap-panel-generic-dpi.h (renamed from arch/arm/plat-omap/include/plat/panel-generic-dpi.h)8
-rw-r--r--include/video/omap-panel-nokia-dsi.h (renamed from arch/arm/plat-omap/include/plat/nokia-dsi-panel.h)14
-rw-r--r--include/video/omapdss.h (renamed from arch/arm/plat-omap/include/plat/display.h)114
-rw-r--r--include/video/sh_mobile_lcdc.h3
-rw-r--r--include/video/sh_mobile_meram.h68
-rw-r--r--include/xen/events.h9
-rw-r--r--include/xen/interface/io/blkif.h13
-rw-r--r--include/xen/interface/xen.h22
-rw-r--r--init/Kconfig37
-rw-r--r--init/calibrate.c75
-rw-r--r--init/main.c5
-rw-r--r--ipc/namespace.c37
-rw-r--r--ipc/shm.c2
-rw-r--r--kernel/Kconfig.locks2
-rw-r--r--kernel/Makefile7
-rw-r--r--kernel/auditsc.c27
-rw-r--r--kernel/capability.c4
-rw-r--r--kernel/cgroup.c614
-rw-r--r--kernel/cgroup_freezer.c26
-rw-r--r--kernel/compat.c55
-rw-r--r--kernel/cpuset.c105
-rw-r--r--kernel/cred.c6
-rw-r--r--kernel/events/Makefile6
-rw-r--r--kernel/events/core.c (renamed from kernel/perf_event.c)64
-rw-r--r--kernel/events/hw_breakpoint.c (renamed from kernel/hw_breakpoint.c)0
-rw-r--r--kernel/exit.c110
-rw-r--r--kernel/extable.c18
-rw-r--r--kernel/fork.c115
-rw-r--r--kernel/freezer.c4
-rw-r--r--kernel/hrtimer.c164
-rw-r--r--kernel/hung_task.c2
-rw-r--r--kernel/irq/Kconfig4
-rw-r--r--kernel/irq/Makefile1
-rw-r--r--kernel/irq/chip.c3
-rw-r--r--kernel/irq/debug.h1
-rw-r--r--kernel/irq/generic-chip.c354
-rw-r--r--kernel/irq/irqdesc.c22
-rw-r--r--kernel/irq/manage.c3
-rw-r--r--kernel/irq/proc.c55
-rw-r--r--kernel/irq/settings.h17
-rw-r--r--kernel/jump_label.c539
-rw-r--r--kernel/kexec.c9
-rw-r--r--kernel/kmod.c116
-rw-r--r--kernel/ksysfs.c10
-rw-r--r--kernel/lockdep.c206
-rw-r--r--kernel/module.c109
-rw-r--r--kernel/mutex-debug.c2
-rw-r--r--kernel/mutex-debug.h2
-rw-r--r--kernel/mutex.c34
-rw-r--r--kernel/mutex.h2
-rw-r--r--kernel/ns_cgroup.c118
-rw-r--r--kernel/nsproxy.c46
-rw-r--r--kernel/params.c23
-rw-r--r--kernel/pm_qos_params.c2
-rw-r--r--kernel/posix-cpu-timers.c4
-rw-r--r--kernel/posix-timers.c27
-rw-r--r--kernel/power/Kconfig10
-rw-r--r--kernel/power/hibernate.c58
-rw-r--r--kernel/power/main.c1
-rw-r--r--kernel/power/power.h4
-rw-r--r--kernel/power/snapshot.c33
-rw-r--r--kernel/power/suspend.c10
-rw-r--r--kernel/printk.c87
-rw-r--r--kernel/profile.c22
-rw-r--r--kernel/ptrace.c120
-rw-r--r--kernel/rcupdate.c32
-rw-r--r--kernel/rcutiny.c46
-rw-r--r--kernel/rcutiny_plugin.h203
-rw-r--r--kernel/rcutorture.c26
-rw-r--r--kernel/rcutree.c527
-rw-r--r--kernel/rcutree.h104
-rw-r--r--kernel/rcutree_plugin.h568
-rw-r--r--kernel/rcutree_trace.c180
-rw-r--r--kernel/sched.c1731
-rw-r--r--kernel/sched_debug.c6
-rw-r--r--kernel/sched_fair.c178
-rw-r--r--kernel/sched_features.h6
-rw-r--r--kernel/sched_idletask.c2
-rw-r--r--kernel/sched_rt.c83
-rw-r--r--kernel/sched_stoptask.c5
-rw-r--r--kernel/signal.c684
-rw-r--r--kernel/softirq.c2
-rw-r--r--kernel/sys.c5
-rw-r--r--kernel/sys_ni.c9
-rw-r--r--kernel/sysctl.c20
-rw-r--r--kernel/time/Makefile2
-rw-r--r--kernel/time/alarmtimer.c702
-rw-r--r--kernel/time/clockevents.c64
-rw-r--r--kernel/time/clocksource.c38
-rw-r--r--kernel/time/tick-broadcast.c16
-rw-r--r--kernel/time/timekeeping.c73
-rw-r--r--kernel/trace/ftrace.c1261
-rw-r--r--kernel/trace/trace.c15
-rw-r--r--kernel/trace/trace.h2
-rw-r--r--kernel/trace/trace_functions.c2
-rw-r--r--kernel/trace/trace_irqsoff.c1
-rw-r--r--kernel/trace/trace_kprobe.c1
-rw-r--r--kernel/trace/trace_output.c3
-rw-r--r--kernel/trace/trace_printk.c120
-rw-r--r--kernel/trace/trace_sched_wakeup.c1
-rw-r--r--kernel/trace/trace_selftest.c214
-rw-r--r--kernel/trace/trace_selftest_dynamic.c6
-rw-r--r--kernel/trace/trace_stack.c1
-rw-r--r--kernel/tracepoint.c23
-rw-r--r--kernel/utsname.c39
-rw-r--r--kernel/watchdog.c52
-rw-r--r--kernel/workqueue.c4
-rw-r--r--lib/Kconfig10
-rw-r--r--lib/Kconfig.debug74
-rw-r--r--lib/Makefile9
-rw-r--r--lib/audit.c2
-rw-r--r--lib/bitmap.c109
-rw-r--r--lib/bsearch.c53
-rw-r--r--lib/dma-debug.c18
-rw-r--r--lib/find_last_bit.c4
-rw-r--r--lib/find_next_bit.c18
-rw-r--r--lib/flex_array.c65
-rw-r--r--lib/genalloc.c45
-rw-r--r--lib/kstrtox.c26
-rw-r--r--lib/lru_cache.c2
-rw-r--r--lib/show_mem.c2
-rw-r--r--lib/string.c29
-rw-r--r--lib/vsprintf.c11
-rw-r--r--mm/Kconfig23
-rw-r--r--mm/Makefile1
-rw-r--r--mm/backing-dev.c4
-rw-r--r--mm/cleancache.c244
-rw-r--r--mm/filemap.c83
-rw-r--r--mm/filemap_xip.c4
-rw-r--r--mm/fremap.c6
-rw-r--r--mm/huge_memory.c25
-rw-r--r--mm/hugetlb.c20
-rw-r--r--mm/init-mm.c1
-rw-r--r--mm/internal.h4
-rw-r--r--mm/kmemleak.c7
-rw-r--r--mm/ksm.c7
-rw-r--r--mm/memcontrol.c377
-rw-r--r--mm/memory-failure.c21
-rw-r--r--mm/memory.c444
-rw-r--r--mm/memory_hotplug.c21
-rw-r--r--mm/mempolicy.c164
-rw-r--r--mm/migrate.c17
-rw-r--r--mm/mlock.c8
-rw-r--r--mm/mmap.c129
-rw-r--r--mm/mremap.c5
-rw-r--r--mm/nobootmem.c23
-rw-r--r--mm/nommu.c108
-rw-r--r--mm/oom_kill.c36
-rw-r--r--mm/page_alloc.c128
-rw-r--r--mm/page_cgroup.c28
-rw-r--r--mm/percpu.c6
-rw-r--r--mm/prio_tree.c1
-rw-r--r--mm/readahead.c2
-rw-r--r--mm/rmap.c183
-rw-r--r--mm/shmem.c334
-rw-r--r--mm/slab.c1
-rw-r--r--mm/slub.c169
-rw-r--r--mm/swap.c52
-rw-r--r--mm/swapfile.c6
-rw-r--r--mm/truncate.c6
-rw-r--r--mm/util.c24
-rw-r--r--mm/vmalloc.c19
-rw-r--r--mm/vmscan.c185
-rw-r--r--mm/vmstat.c264
-rw-r--r--net/802/garp.c6
-rw-r--r--net/802/psnap.c1
-rw-r--r--net/8021q/vlan.c38
-rw-r--r--net/8021q/vlan.h7
-rw-r--r--net/8021q/vlan_core.c85
-rw-r--r--net/8021q/vlan_dev.c225
-rw-r--r--net/9p/Kconfig8
-rw-r--r--net/9p/client.c39
-rw-r--r--net/9p/mod.c4
-rw-r--r--net/9p/trans_fd.c9
-rw-r--r--net/9p/trans_rdma.c5
-rw-r--r--net/9p/util.c2
-rw-r--r--net/Kconfig14
-rw-r--r--net/atm/lec.c6
-rw-r--r--net/atm/mpc.c2
-rw-r--r--net/atm/proc.c4
-rw-r--r--net/ax25/af_ax25.c16
-rw-r--r--net/ax25/ax25_iface.c3
-rw-r--r--net/batman-adv/aggregation.c31
-rw-r--r--net/batman-adv/aggregation.h4
-rw-r--r--net/batman-adv/bat_debugfs.c4
-rw-r--r--net/batman-adv/bat_sysfs.c16
-rw-r--r--net/batman-adv/gateway_client.c306
-rw-r--r--net/batman-adv/gateway_client.h2
-rw-r--r--net/batman-adv/hard-interface.c107
-rw-r--r--net/batman-adv/hard-interface.h18
-rw-r--r--net/batman-adv/icmp_socket.c37
-rw-r--r--net/batman-adv/main.c20
-rw-r--r--net/batman-adv/main.h44
-rw-r--r--net/batman-adv/originator.c90
-rw-r--r--net/batman-adv/originator.h1
-rw-r--r--net/batman-adv/packet.h5
-rw-r--r--net/batman-adv/routing.c572
-rw-r--r--net/batman-adv/routing.h6
-rw-r--r--net/batman-adv/send.c72
-rw-r--r--net/batman-adv/send.h2
-rw-r--r--net/batman-adv/soft-interface.c473
-rw-r--r--net/batman-adv/translation-table.c474
-rw-r--r--net/batman-adv/translation-table.h24
-rw-r--r--net/batman-adv/types.h56
-rw-r--r--net/batman-adv/unicast.c20
-rw-r--r--net/batman-adv/vis.c146
-rw-r--r--net/bluetooth/bnep/bnep.h148
-rw-r--r--net/bluetooth/bnep/core.c71
-rw-r--r--net/bluetooth/bnep/sock.c2
-rw-r--r--net/bluetooth/cmtp/capi.c6
-rw-r--r--net/bluetooth/cmtp/cmtp.h11
-rw-r--r--net/bluetooth/cmtp/core.c28
-rw-r--r--net/bluetooth/cmtp/sock.c2
-rw-r--r--net/bluetooth/hci_conn.c95
-rw-r--r--net/bluetooth/hci_core.c154
-rw-r--r--net/bluetooth/hci_event.c267
-rw-r--r--net/bluetooth/hci_sysfs.c71
-rw-r--r--net/bluetooth/hidp/core.c96
-rw-r--r--net/bluetooth/hidp/hidp.h8
-rw-r--r--net/bluetooth/hidp/sock.c7
-rw-r--r--net/bluetooth/l2cap_core.c1966
-rw-r--r--net/bluetooth/l2cap_sock.c330
-rw-r--r--net/bluetooth/mgmt.c612
-rw-r--r--net/bluetooth/rfcomm/core.c23
-rw-r--r--net/bluetooth/rfcomm/sock.c5
-rw-r--r--net/bridge/br.c1
-rw-r--r--net/bridge/br_device.c100
-rw-r--r--net/bridge/br_fdb.c311
-rw-r--r--net/bridge/br_if.c107
-rw-r--r--net/bridge/br_input.c5
-rw-r--r--net/bridge/br_ioctl.c40
-rw-r--r--net/bridge/br_multicast.c12
-rw-r--r--net/bridge/br_netfilter.c10
-rw-r--r--net/bridge/br_netlink.c60
-rw-r--r--net/bridge/br_notify.c11
-rw-r--r--net/bridge/br_private.h22
-rw-r--r--net/bridge/br_private_stp.h13
-rw-r--r--net/bridge/br_stp.c48
-rw-r--r--net/bridge/br_stp_if.c21
-rw-r--r--net/bridge/br_sysfs_br.c39
-rw-r--r--net/bridge/br_sysfs_if.c26
-rw-r--r--net/caif/Makefile2
-rw-r--r--net/caif/caif_config_util.c99
-rw-r--r--net/caif/caif_dev.c392
-rw-r--r--net/caif/caif_socket.c117
-rw-r--r--net/caif/cfcnfg.c531
-rw-r--r--net/caif/cfctrl.c234
-rw-r--r--net/caif/cfdgml.c7
-rw-r--r--net/caif/cffrml.c60
-rw-r--r--net/caif/cfmuxl.c197
-rw-r--r--net/caif/cfpkt_skbuff.c205
-rw-r--r--net/caif/cfrfml.c4
-rw-r--r--net/caif/cfserl.c7
-rw-r--r--net/caif/cfsrvl.c40
-rw-r--r--net/caif/cfutill.c7
-rw-r--r--net/caif/cfveil.c11
-rw-r--r--net/caif/cfvidl.c5
-rw-r--r--net/caif/chnl_net.c45
-rw-r--r--net/can/af_can.c67
-rw-r--r--net/can/bcm.c8
-rw-r--r--net/can/raw.c2
-rw-r--r--net/ceph/messenger.c82
-rw-r--r--net/ceph/osd_client.c19
-rw-r--r--net/ceph/osdmap.c13
-rw-r--r--net/compat.c16
-rw-r--r--net/core/dev.c203
-rw-r--r--net/core/dev_addr_lists.c12
-rw-r--r--net/core/drop_monitor.c12
-rw-r--r--net/core/dst.c57
-rw-r--r--net/core/ethtool.c196
-rw-r--r--net/core/fib_rules.c4
-rw-r--r--net/core/filter.c69
-rw-r--r--net/core/gen_estimator.c9
-rw-r--r--net/core/net-sysfs.c60
-rw-r--r--net/core/net_namespace.c87
-rw-r--r--net/core/netpoll.c28
-rw-r--r--net/core/pktgen.c222
-rw-r--r--net/core/rtnetlink.c25
-rw-r--r--net/core/skbuff.c4
-rw-r--r--net/core/sysctl_net_core.c9
-rw-r--r--net/core/utils.c24
-rw-r--r--net/dccp/ipv4.c53
-rw-r--r--net/dccp/ipv6.c10
-rw-r--r--net/dccp/output.c4
-rw-r--r--net/decnet/dn_dev.c17
-rw-r--r--net/decnet/dn_route.c15
-rw-r--r--net/decnet/dn_table.c4
-rw-r--r--net/dns_resolver/dns_key.c10
-rw-r--r--net/dsa/slave.c1
-rw-r--r--net/econet/af_econet.c8
-rw-r--r--net/ipv4/Makefile2
-rw-r--r--net/ipv4/af_inet.c53
-rw-r--r--net/ipv4/ah4.c7
-rw-r--r--net/ipv4/cipso_ipv4.c113
-rw-r--r--net/ipv4/datagram.c22
-rw-r--r--net/ipv4/devinet.c4
-rw-r--r--net/ipv4/esp4.c7
-rw-r--r--net/ipv4/fib_frontend.c16
-rw-r--r--net/ipv4/fib_semantics.c12
-rw-r--r--net/ipv4/fib_trie.c118
-rw-r--r--net/ipv4/icmp.c133
-rw-r--r--net/ipv4/igmp.c64
-rw-r--r--net/ipv4/inet_connection_sock.c61
-rw-r--r--net/ipv4/inet_diag.c2
-rw-r--r--net/ipv4/inet_lro.c4
-rw-r--r--net/ipv4/ip_forward.c2
-rw-r--r--net/ipv4/ip_fragment.c58
-rw-r--r--net/ipv4/ip_gre.c70
-rw-r--r--net/ipv4/ip_input.c4
-rw-r--r--net/ipv4/ip_options.c57
-rw-r--r--net/ipv4/ip_output.c158
-rw-r--r--net/ipv4/ip_sockglue.c37
-rw-r--r--net/ipv4/ipcomp.c4
-rw-r--r--net/ipv4/ipconfig.c35
-rw-r--r--net/ipv4/ipip.c36
-rw-r--r--net/ipv4/ipmr.c39
-rw-r--r--net/ipv4/netfilter/arp_tables.c18
-rw-r--r--net/ipv4/netfilter/ip_tables.c28
-rw-r--r--net/ipv4/netfilter/nf_nat_helper.c2
-rw-r--r--net/ipv4/ping.c932
-rw-r--r--net/ipv4/raw.c94
-rw-r--r--net/ipv4/route.c386
-rw-r--r--net/ipv4/syncookies.c22
-rw-r--r--net/ipv4/sysctl_net_ipv4.c68
-rw-r--r--net/ipv4/tcp.c7
-rw-r--r--net/ipv4/tcp_ipv4.c104
-rw-r--r--net/ipv4/tcp_output.c2
-rw-r--r--net/ipv4/udp.c80
-rw-r--r--net/ipv4/xfrm4_policy.c38
-rw-r--r--net/ipv4/xfrm4_state.c2
-rw-r--r--net/ipv6/addrconf.c58
-rw-r--r--net/ipv6/af_inet6.c2
-rw-r--r--net/ipv6/anycast.c16
-rw-r--r--net/ipv6/esp6.c5
-rw-r--r--net/ipv6/icmp.c8
-rw-r--r--net/ipv6/inet6_connection_sock.c2
-rw-r--r--net/ipv6/ip6_fib.c20
-rw-r--r--net/ipv6/ip6_input.c6
-rw-r--r--net/ipv6/ip6_output.c50
-rw-r--r--net/ipv6/ip6_tunnel.c46
-rw-r--r--net/ipv6/ip6mr.c4
-rw-r--r--net/ipv6/ipcomp6.c5
-rw-r--r--net/ipv6/mcast.c44
-rw-r--r--net/ipv6/mip6.c8
-rw-r--r--net/ipv6/ndisc.c51
-rw-r--r--net/ipv6/netfilter.c10
-rw-r--r--net/ipv6/netfilter/ip6_tables.c21
-rw-r--r--net/ipv6/netfilter/ip6table_mangle.c3
-rw-r--r--net/ipv6/proc.c40
-rw-r--r--net/ipv6/raw.c20
-rw-r--r--net/ipv6/reassembly.c4
-rw-r--r--net/ipv6/route.c158
-rw-r--r--net/ipv6/sit.c47
-rw-r--r--net/ipv6/syncookies.c13
-rw-r--r--net/ipv6/tcp_ipv6.c56
-rw-r--r--net/ipv6/udp.c24
-rw-r--r--net/ipv6/xfrm6_mode_beet.c2
-rw-r--r--net/ipv6/xfrm6_mode_tunnel.c6
-rw-r--r--net/ipv6/xfrm6_policy.c2
-rw-r--r--net/ipv6/xfrm6_tunnel.c12
-rw-r--r--net/irda/ircomm/ircomm_core.c6
-rw-r--r--net/irda/ircomm/ircomm_lmp.c5
-rw-r--r--net/irda/ircomm/ircomm_tty.c14
-rw-r--r--net/irda/irlan/irlan_filter.c4
-rw-r--r--net/irda/irlan/irlan_provider.c3
-rw-r--r--net/irda/irlap_event.c3
-rw-r--r--net/irda/irproc.c5
-rw-r--r--net/iucv/af_iucv.c9
-rw-r--r--net/iucv/iucv.c79
-rw-r--r--net/key/af_key.c4
-rw-r--r--net/l2tp/l2tp_core.c28
-rw-r--r--net/l2tp/l2tp_ip.c52
-rw-r--r--net/l2tp/l2tp_netlink.c3
-rw-r--r--net/mac80211/Kconfig1
-rw-r--r--net/mac80211/aes_ccm.c6
-rw-r--r--net/mac80211/agg-rx.c3
-rw-r--r--net/mac80211/agg-tx.c67
-rw-r--r--net/mac80211/cfg.c188
-rw-r--r--net/mac80211/debugfs.c91
-rw-r--r--net/mac80211/debugfs_key.c21
-rw-r--r--net/mac80211/debugfs_sta.c26
-rw-r--r--net/mac80211/driver-ops.h87
-rw-r--r--net/mac80211/driver-trace.h275
-rw-r--r--net/mac80211/ht.c27
-rw-r--r--net/mac80211/ibss.c21
-rw-r--r--net/mac80211/ieee80211_i.h51
-rw-r--r--net/mac80211/iface.c11
-rw-r--r--net/mac80211/key.c51
-rw-r--r--net/mac80211/key.h4
-rw-r--r--net/mac80211/main.c85
-rw-r--r--net/mac80211/mesh.c62
-rw-r--r--net/mac80211/mesh.h16
-rw-r--r--net/mac80211/mesh_hwmp.c42
-rw-r--r--net/mac80211/mesh_pathtbl.c308
-rw-r--r--net/mac80211/mesh_plink.c112
-rw-r--r--net/mac80211/mlme.c48
-rw-r--r--net/mac80211/pm.c29
-rw-r--r--net/mac80211/rc80211_minstrel.c4
-rw-r--r--net/mac80211/rc80211_minstrel_ht.c27
-rw-r--r--net/mac80211/rx.c94
-rw-r--r--net/mac80211/scan.c127
-rw-r--r--net/mac80211/sta_info.c52
-rw-r--r--net/mac80211/sta_info.h56
-rw-r--r--net/mac80211/status.c19
-rw-r--r--net/mac80211/tkip.c4
-rw-r--r--net/mac80211/tkip.h4
-rw-r--r--net/mac80211/tx.c27
-rw-r--r--net/mac80211/util.c21
-rw-r--r--net/mac80211/wep.c34
-rw-r--r--net/mac80211/wep.h4
-rw-r--r--net/mac80211/work.c16
-rw-r--r--net/mac80211/wpa.c62
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_ip.c2
-rw-r--r--net/netfilter/ipset/ip_set_getport.c16
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipport.c2
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportip.c2
-rw-r--r--net/netfilter/ipset/ip_set_hash_ipportnet.c2
-rw-r--r--net/netfilter/ipset/ip_set_hash_netport.c2
-rw-r--r--net/netfilter/ipvs/ip_vs_core.c24
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c3
-rw-r--r--net/netfilter/ipvs/ip_vs_xmit.c97
-rw-r--r--net/netfilter/nf_conntrack_extend.c8
-rw-r--r--net/netfilter/nf_conntrack_sip.c16
-rw-r--r--net/netfilter/nf_conntrack_standalone.c2
-rw-r--r--net/netfilter/nfnetlink_log.c2
-rw-r--r--net/netfilter/x_tables.c9
-rw-r--r--net/netfilter/xt_osf.c11
-rw-r--r--net/netlabel/netlabel_addrlist.h8
-rw-r--r--net/netlabel/netlabel_cipso_v4.c4
-rw-r--r--net/netlabel/netlabel_unlabeled.c42
-rw-r--r--net/netlink/af_netlink.c10
-rw-r--r--net/netrom/af_netrom.c12
-rw-r--r--net/packet/af_packet.c4
-rw-r--r--net/phonet/pn_dev.c16
-rw-r--r--net/phonet/pn_netlink.c4
-rw-r--r--net/phonet/socket.c47
-rw-r--r--net/rds/ib.c2
-rw-r--r--net/rds/ib_cm.c2
-rw-r--r--net/rds/iw.c2
-rw-r--r--net/rds/iw_cm.c2
-rw-r--r--net/rds/rdma_transport.c3
-rw-r--r--net/rfkill/Kconfig20
-rw-r--r--net/rfkill/Makefile2
-rw-r--r--net/rfkill/core.c2
-rw-r--r--net/rfkill/rfkill-gpio.c227
-rw-r--r--net/rfkill/rfkill-regulator.c164
-rw-r--r--net/rose/af_rose.c16
-rw-r--r--net/rxrpc/ar-ack.c2
-rw-r--r--net/rxrpc/ar-connevent.c3
-rw-r--r--net/rxrpc/ar-error.c5
-rw-r--r--net/rxrpc/ar-peer.c6
-rw-r--r--net/rxrpc/ar-transport.c3
-rw-r--r--net/sched/Kconfig12
-rw-r--r--net/sched/Makefile1
-rw-r--r--net/sched/act_api.c7
-rw-r--r--net/sched/act_police.c8
-rw-r--r--net/sched/sch_api.c2
-rw-r--r--net/sched/sch_generic.c17
-rw-r--r--net/sched/sch_qfq.c1137
-rw-r--r--net/sched/sch_sfq.c24
-rw-r--r--net/sctp/associola.c16
-rw-r--r--net/sctp/bind_addr.c12
-rw-r--r--net/sctp/debug.c1
-rw-r--r--net/sctp/endpointola.c20
-rw-r--r--net/sctp/input.c19
-rw-r--r--net/sctp/ipv6.c187
-rw-r--r--net/sctp/outqueue.c19
-rw-r--r--net/sctp/proc.c4
-rw-r--r--net/sctp/protocol.c80
-rw-r--r--net/sctp/sm_make_chunk.c62
-rw-r--r--net/sctp/sm_sideeffect.c9
-rw-r--r--net/sctp/sm_statefuns.c89
-rw-r--r--net/sctp/sm_statetable.c78
-rw-r--r--net/sctp/socket.c95
-rw-r--r--net/sctp/transport.c27
-rw-r--r--net/sctp/ulpevent.c30
-rw-r--r--net/socket.c230
-rw-r--r--net/sunrpc/addr.c2
-rw-r--r--net/sunrpc/auth.c4
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma_transport.c5
-rw-r--r--net/sunrpc/xprtrdma/verbs.c2
-rw-r--r--net/tipc/addr.h7
-rw-r--r--net/tipc/bcast.c22
-rw-r--r--net/tipc/bearer.c45
-rw-r--r--net/tipc/core.c3
-rw-r--r--net/tipc/discover.c150
-rw-r--r--net/tipc/discover.h11
-rw-r--r--net/tipc/link.c104
-rw-r--r--net/tipc/link.h1
-rw-r--r--net/tipc/msg.c25
-rw-r--r--net/tipc/msg.h161
-rw-r--r--net/tipc/port.c55
-rw-r--r--net/tipc/port.h14
-rw-r--r--net/tipc/socket.c27
-rw-r--r--net/tipc/subscr.c4
-rw-r--r--net/unix/af_unix.c2
-rw-r--r--net/wireless/core.c106
-rw-r--r--net/wireless/core.h38
-rw-r--r--net/wireless/lib80211_crypt_wep.c3
-rw-r--r--net/wireless/mesh.c23
-rw-r--r--net/wireless/mlme.c19
-rw-r--r--net/wireless/nl80211.c794
-rw-r--r--net/wireless/nl80211.h11
-rw-r--r--net/wireless/reg.c74
-rw-r--r--net/wireless/scan.c77
-rw-r--r--net/wireless/sme.c19
-rw-r--r--net/wireless/sysfs.c2
-rw-r--r--net/wireless/util.c128
-rw-r--r--net/xfrm/xfrm_policy.c3
-rw-r--r--net/xfrm/xfrm_state.c12
-rw-r--r--samples/Kconfig6
-rw-r--r--samples/Makefile2
-rw-r--r--samples/hidraw/Makefile10
-rw-r--r--samples/hidraw/hid-example.c178
-rw-r--r--scripts/.gitignore1
-rw-r--r--scripts/Kbuild.include12
-rw-r--r--scripts/Makefile7
-rw-r--r--scripts/Makefile.asm-generic23
-rw-r--r--scripts/Makefile.build86
-rw-r--r--scripts/Makefile.headersinst10
-rw-r--r--scripts/Makefile.lib2
-rw-r--r--scripts/basic/.gitignore2
-rw-r--r--scripts/basic/Makefile3
-rwxr-xr-xscripts/checkpatch.pl13
-rwxr-xr-xscripts/checkstack.pl2
-rwxr-xr-xscripts/checkversion.pl1
-rw-r--r--scripts/docproc.c (renamed from scripts/basic/docproc.c)0
-rw-r--r--scripts/export_report.pl26
-rw-r--r--scripts/gen_initramfs_list.sh27
-rw-r--r--scripts/kallsyms.c2
-rw-r--r--scripts/kconfig/Makefile38
-rw-r--r--scripts/kconfig/confdata.c20
-rw-r--r--scripts/kconfig/expr.h4
-rw-r--r--scripts/kconfig/gconf.c12
-rw-r--r--scripts/kconfig/lex.zconf.c_shipped33
-rw-r--r--scripts/kconfig/nconf.c14
-rw-r--r--scripts/kconfig/qconf.cc5
-rw-r--r--scripts/kconfig/zconf.l33
-rwxr-xr-xscripts/mkcompile_h30
-rw-r--r--scripts/mod/file2alias.c22
-rw-r--r--scripts/mod/modpost.c16
-rw-r--r--scripts/mod/modpost.h27
-rw-r--r--scripts/module-common.lds11
-rw-r--r--scripts/package/Makefile4
-rwxr-xr-xscripts/package/mkspec19
-rwxr-xr-xscripts/patch-kernel2
-rw-r--r--scripts/recordmcount.c168
-rw-r--r--scripts/recordmcount.h174
-rwxr-xr-xscripts/recordmcount.pl5
-rw-r--r--security/Kconfig1
-rw-r--r--security/commoncap.c13
-rw-r--r--security/device_cgroup.c3
-rw-r--r--security/keys/internal.h4
-rw-r--r--security/keys/keyctl.c6
-rw-r--r--security/keys/keyring.c37
-rw-r--r--security/keys/proc.c2
-rw-r--r--security/keys/process_keys.c13
-rw-r--r--security/keys/request_key.c3
-rw-r--r--security/keys/request_key_auth.c3
-rw-r--r--security/keys/user_defined.c20
-rw-r--r--security/lsm_audit.c59
-rw-r--r--security/selinux/avc.c29
-rw-r--r--security/selinux/hooks.c92
-rw-r--r--security/selinux/include/avc.h1
-rw-r--r--security/selinux/include/security.h9
-rw-r--r--security/selinux/netif.c18
-rw-r--r--security/selinux/netnode.c1
-rw-r--r--security/selinux/selinuxfs.c46
-rw-r--r--security/selinux/ss/policydb.c244
-rw-r--r--security/selinux/ss/policydb.h12
-rw-r--r--security/selinux/ss/services.c75
-rw-r--r--security/smack/smack.h11
-rw-r--r--security/smack/smack_lsm.c48
-rw-r--r--security/tomoyo/common.c17
-rw-r--r--security/tomoyo/file.c1
-rw-r--r--security/tomoyo/memory.c1
-rw-r--r--security/tomoyo/mount.c1
-rw-r--r--security/tomoyo/util.c2
-rw-r--r--sound/core/control.c67
-rw-r--r--sound/core/init.c5
-rw-r--r--sound/core/oss/linear.c3
-rw-r--r--sound/core/pcm_lib.c31
-rw-r--r--sound/core/pcm_native.c21
-rw-r--r--sound/core/seq/seq_queue.c2
-rw-r--r--sound/firewire/Kconfig11
-rw-r--r--sound/firewire/Makefile2
-rw-r--r--sound/firewire/amdtp.c1
-rw-r--r--sound/firewire/cmp.c3
-rw-r--r--sound/firewire/isight.c755
-rw-r--r--sound/firewire/iso-resources.c17
-rw-r--r--sound/firewire/iso-resources.h1
-rw-r--r--sound/firewire/packets-buffer.c2
-rw-r--r--sound/i2c/other/Makefile2
-rw-r--r--sound/i2c/other/tea575x-tuner.c153
-rw-r--r--sound/oss/Kconfig4
-rw-r--r--sound/oss/Makefile1
-rw-r--r--sound/oss/ac97_codec.c1203
-rw-r--r--sound/oss/au1550_ac97.c2147
-rw-r--r--sound/pci/Kconfig27
-rw-r--r--sound/pci/Makefile1
-rw-r--r--sound/pci/asihpi/asihpi.c328
-rw-r--r--sound/pci/asihpi/hpi6000.c39
-rw-r--r--sound/pci/asihpi/hpi6205.c95
-rw-r--r--sound/pci/asihpi/hpi_internal.h19
-rw-r--r--sound/pci/asihpi/hpicmn.c10
-rw-r--r--sound/pci/asihpi/hpicmn.h2
-rw-r--r--sound/pci/asihpi/hpifunc.c27
-rw-r--r--sound/pci/asihpi/hpimsgx.c31
-rw-r--r--sound/pci/asihpi/hpioctl.c63
-rw-r--r--sound/pci/au88x0/au8810.h2
-rw-r--r--sound/pci/au88x0/au8820.h2
-rw-r--r--sound/pci/au88x0/au8830.h2
-rw-r--r--sound/pci/au88x0/au88x0_pcm.c13
-rw-r--r--sound/pci/emu10k1/emufx.c5
-rw-r--r--sound/pci/emu10k1/emumixer.c10
-rw-r--r--sound/pci/es1968.c78
-rw-r--r--sound/pci/fm801.c371
-rw-r--r--sound/pci/hda/hda_codec.c99
-rw-r--r--sound/pci/hda/hda_codec.h4
-rw-r--r--sound/pci/hda/hda_eld.c21
-rw-r--r--sound/pci/hda/hda_intel.c194
-rw-r--r--sound/pci/hda/hda_local.h16
-rw-r--r--sound/pci/hda/patch_analog.c346
-rw-r--r--sound/pci/hda/patch_ca0110.c16
-rw-r--r--sound/pci/hda/patch_cirrus.c52
-rw-r--r--sound/pci/hda/patch_cmedia.c40
-rw-r--r--sound/pci/hda/patch_conexant.c1097
-rw-r--r--sound/pci/hda/patch_hdmi.c156
-rw-r--r--sound/pci/hda/patch_realtek.c3681
-rw-r--r--sound/pci/hda/patch_si3054.c11
-rw-r--r--sound/pci/hda/patch_sigmatel.c431
-rw-r--r--sound/pci/hda/patch_via.c1526
-rw-r--r--sound/pci/intel8x0m.c4
-rw-r--r--sound/pci/lola/Makefile4
-rw-r--r--sound/pci/lola/lola.c791
-rw-r--r--sound/pci/lola/lola.h527
-rw-r--r--sound/pci/lola/lola_clock.c323
-rw-r--r--sound/pci/lola/lola_mixer.c839
-rw-r--r--sound/pci/lola/lola_pcm.c706
-rw-r--r--sound/pci/lola/lola_proc.c222
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf.c2
-rw-r--r--sound/pcmcia/vx/vxpocket.c2
-rw-r--r--sound/ppc/tumbler.c2
-rw-r--r--sound/soc/atmel/sam9g20_wm8731.c4
-rw-r--r--sound/soc/au1x/db1200.c2
-rw-r--r--sound/soc/blackfin/bf5xx-ac97-pcm.c13
-rw-r--r--sound/soc/blackfin/bf5xx-ac97.c166
-rw-r--r--sound/soc/blackfin/bf5xx-ad1836.c42
-rw-r--r--sound/soc/blackfin/bf5xx-ad193x.c56
-rw-r--r--sound/soc/blackfin/bf5xx-ad1980.c45
-rw-r--r--sound/soc/blackfin/bf5xx-ad73311.c42
-rw-r--r--sound/soc/blackfin/bf5xx-i2s-pcm.c23
-rw-r--r--sound/soc/blackfin/bf5xx-i2s.c172
-rw-r--r--sound/soc/blackfin/bf5xx-sport.c159
-rw-r--r--sound/soc/blackfin/bf5xx-sport.h16
-rw-r--r--sound/soc/blackfin/bf5xx-ssm2602.c42
-rw-r--r--sound/soc/blackfin/bf5xx-tdm-pcm.c23
-rw-r--r--sound/soc/blackfin/bf5xx-tdm.c110
-rw-r--r--sound/soc/codecs/88pm860x-codec.c2
-rw-r--r--sound/soc/codecs/Kconfig20
-rw-r--r--sound/soc/codecs/Makefile10
-rw-r--r--sound/soc/codecs/ad193x.c23
-rw-r--r--sound/soc/codecs/ad1980.c2
-rw-r--r--sound/soc/codecs/ad73311.c2
-rw-r--r--sound/soc/codecs/ak4535.c19
-rw-r--r--sound/soc/codecs/ak4641.c664
-rw-r--r--sound/soc/codecs/ak4641.h47
-rw-r--r--sound/soc/codecs/ak4671.c18
-rw-r--r--sound/soc/codecs/cq93vc.c3
-rw-r--r--sound/soc/codecs/cx20442.c26
-rw-r--r--sound/soc/codecs/dmic.c26
-rw-r--r--sound/soc/codecs/jz4740.c18
-rw-r--r--sound/soc/codecs/max98088.c87
-rw-r--r--sound/soc/codecs/max98088.h13
-rw-r--r--sound/soc/codecs/max98095.c2396
-rw-r--r--sound/soc/codecs/max98095.h299
-rw-r--r--sound/soc/codecs/sn95031.c17
-rw-r--r--sound/soc/codecs/spdif_transciever.c8
-rw-r--r--sound/soc/codecs/ssm2602.c464
-rw-r--r--sound/soc/codecs/ssm2602.h6
-rw-r--r--sound/soc/codecs/tlv320aic23.c19
-rw-r--r--sound/soc/codecs/tlv320aic3x.c3
-rw-r--r--sound/soc/codecs/tlv320dac33.c17
-rw-r--r--sound/soc/codecs/tlv320dac33.h2
-rw-r--r--sound/soc/codecs/tpa6130a2.c4
-rw-r--r--sound/soc/codecs/tpa6130a2.h2
-rw-r--r--sound/soc/codecs/twl4030.c6
-rw-r--r--sound/soc/codecs/twl6040.c6
-rw-r--r--sound/soc/codecs/wl1273.c3
-rw-r--r--sound/soc/codecs/wm1250-ev1.c108
-rw-r--r--sound/soc/codecs/wm8400.c2
-rw-r--r--sound/soc/codecs/wm8711.c18
-rw-r--r--sound/soc/codecs/wm8728.c18
-rw-r--r--sound/soc/codecs/wm8731.c24
-rw-r--r--sound/soc/codecs/wm8903.c44
-rw-r--r--sound/soc/codecs/wm8915.c2930
-rw-r--r--sound/soc/codecs/wm8915.h3717
-rw-r--r--sound/soc/codecs/wm8958-dsp2.c1051
-rw-r--r--sound/soc/codecs/wm8962.c63
-rw-r--r--sound/soc/codecs/wm8993.c3
-rw-r--r--sound/soc/codecs/wm8994.c395
-rw-r--r--sound/soc/codecs/wm8994.h97
-rw-r--r--sound/soc/codecs/wm8995.c4
-rw-r--r--sound/soc/codecs/wm9705.c18
-rw-r--r--sound/soc/codecs/wm9712.c18
-rw-r--r--sound/soc/codecs/wm9713.c19
-rw-r--r--sound/soc/codecs/wm_hubs.c24
-rw-r--r--sound/soc/davinci/davinci-mcasp.c2
-rw-r--r--sound/soc/davinci/davinci-vcif.c2
-rw-r--r--sound/soc/imx/imx-ssi.c6
-rw-r--r--sound/soc/jz4740/qi_lb60.c46
-rw-r--r--sound/soc/mid-x86/sst_platform.c4
-rw-r--r--sound/soc/omap/Kconfig8
-rw-r--r--sound/soc/omap/Makefile1
-rw-r--r--sound/soc/omap/omap-mcbsp.c6
-rw-r--r--sound/soc/omap/omap-mcbsp.h2
-rw-r--r--sound/soc/omap/omap-pcm.c7
-rw-r--r--sound/soc/omap/omap-pcm.h2
-rw-r--r--sound/soc/omap/omap2evm.c139
-rw-r--r--sound/soc/omap/rx51.c2
-rw-r--r--sound/soc/pxa/Kconfig9
-rw-r--r--sound/soc/pxa/Makefile2
-rw-r--r--sound/soc/pxa/corgi.c2
-rw-r--r--sound/soc/pxa/hx4700.c255
-rw-r--r--sound/soc/pxa/poodle.c2
-rw-r--r--sound/soc/pxa/raumfeld.c92
-rw-r--r--sound/soc/pxa/spitz.c41
-rw-r--r--sound/soc/samsung/Kconfig15
-rw-r--r--sound/soc/samsung/Makefile4
-rw-r--r--sound/soc/samsung/goni_wm8994.c1
-rw-r--r--sound/soc/samsung/neo1973_wm8753.c1
-rw-r--r--sound/soc/samsung/smdk_wm8580pcm.c206
-rw-r--r--sound/soc/samsung/speyside.c332
-rw-r--r--sound/soc/sh/fsi.c188
-rw-r--r--sound/soc/soc-cache.c612
-rw-r--r--sound/soc/soc-core.c199
-rw-r--r--sound/soc/soc-dapm.c613
-rw-r--r--sound/soc/soc-jack.c2
-rw-r--r--sound/soc/soc-utils.c53
-rw-r--r--sound/soc/tegra/Kconfig38
-rw-r--r--sound/soc/tegra/Makefile14
-rw-r--r--sound/soc/tegra/harmony.c394
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.c9
-rw-r--r--sound/soc/tegra/tegra_asoc_utils.h2
-rw-r--r--sound/soc/tegra/tegra_i2s.c2
-rw-r--r--sound/soc/tegra/tegra_wm8903.c475
-rw-r--r--sound/soc/tegra/trimslice.c228
-rw-r--r--sound/usb/6fire/control.c105
-rw-r--r--sound/usb/6fire/control.h17
-rw-r--r--sound/usb/6fire/firmware.c73
-rw-r--r--sound/usb/6fire/pcm.c97
-rw-r--r--sound/usb/Kconfig10
-rw-r--r--sound/usb/card.c17
-rw-r--r--sound/usb/clock.c11
-rw-r--r--sound/usb/debug.h2
-rw-r--r--sound/usb/format.c1
-rw-r--r--sound/usb/mixer.c42
-rw-r--r--sound/usb/mixer.h14
-rw-r--r--sound/usb/mixer_quirks.c82
-rw-r--r--sound/usb/quirks-table.h51
-rw-r--r--sound/usb/quirks.c19
-rw-r--r--sound/usb/usbaudio.h1
-rw-r--r--tools/perf/Documentation/perf-script-perl.txt1
-rw-r--r--tools/perf/Documentation/perf-script-python.txt1
-rw-r--r--tools/perf/Documentation/perf-script.txt52
-rw-r--r--tools/perf/Makefile107
-rw-r--r--tools/perf/builtin-script.c296
-rw-r--r--tools/perf/builtin-stat.c573
-rw-r--r--tools/perf/builtin-test.c9
-rw-r--r--tools/perf/builtin-top.c7
-rw-r--r--tools/perf/config/feature-tests.mak (renamed from tools/perf/feature-tests.mak)16
-rw-r--r--tools/perf/config/utilities.mak188
-rw-r--r--tools/perf/util/event.c46
-rw-r--r--tools/perf/util/event.h12
-rw-r--r--tools/perf/util/evlist.c31
-rw-r--r--tools/perf/util/evlist.h3
-rw-r--r--tools/perf/util/evsel.c32
-rw-r--r--tools/perf/util/header.c31
-rw-r--r--tools/perf/util/header.h2
-rw-r--r--tools/perf/util/include/asm/alternative-asm.h8
-rw-r--r--tools/perf/util/include/linux/list.h4
-rw-r--r--tools/perf/util/parse-events.c123
-rw-r--r--tools/perf/util/probe-finder.c73
-rw-r--r--tools/perf/util/probe-finder.h2
-rw-r--r--tools/perf/util/python.c16
-rw-r--r--tools/perf/util/session.c62
-rw-r--r--tools/perf/util/session.h5
-rw-r--r--tools/perf/util/symbol.c629
-rw-r--r--tools/perf/util/symbol.h78
-rw-r--r--tools/perf/util/trace-event-parse.c1
-rw-r--r--tools/perf/util/ui/browsers/annotate.c1
-rw-r--r--tools/power/x86/turbostat/turbostat.c2
-rwxr-xr-xtools/testing/ktest/ktest.pl156
-rw-r--r--tools/testing/ktest/sample.conf93
-rw-r--r--usr/gen_init_cpio.c53
-rw-r--r--virt/kvm/assigned-dev.c18
-rw-r--r--virt/kvm/ioapic.c2
-rw-r--r--virt/kvm/kvm_main.c26
6512 files changed, 427322 insertions, 355914 deletions
diff --git a/.gitignore b/.gitignore
index 5d56a3fd0de6..9dacde0a4b2d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -57,6 +57,7 @@ modules.builtin
include/config
include/linux/version.h
include/generated
+arch/*/include/generated
# stgit generated dirs
patches-*
diff --git a/.mailmap b/.mailmap
index 5a6dd592eedc..353ad5607156 100644
--- a/.mailmap
+++ b/.mailmap
@@ -32,6 +32,7 @@ Brian Avery <b.avery@hp.com>
Brian King <brking@us.ibm.com>
Christoph Hellwig <hch@lst.de>
Corey Minyard <minyard@acm.org>
+Damian Hobson-Garcia <dhobsong@igel.co.jp>
David Brownell <david-b@pacbell.net>
David Woodhouse <dwmw2@shinybook.infradead.org>
Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
diff --git a/CREDITS b/CREDITS
index dca6abcead6b..a7ea8e343836 100644
--- a/CREDITS
+++ b/CREDITS
@@ -328,7 +328,7 @@ S: Haifa, Israel
N: Johannes Berg
E: johannes@sipsolutions.net
W: http://johannes.sipsolutions.net/
-P: 1024D/9AB78CA5 AD02 0176 4E29 C137 1DF6 08D2 FC44 CF86 9AB7 8CA5
+P: 4096R/7BF9099A C0EB C440 F6DA 091C 884D 8532 E0F3 73F3 7BF9 099A
D: powerpc & 802.11 hacker
N: Stephen R. van den Berg (AKA BuGless)
@@ -2943,6 +2943,10 @@ S: Kasarmikatu 11 A4
S: 70110 Kuopio
S: Finland
+N: Tobias Ringström
+E: tori@unhappy.mine.nu
+D: Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver
+
N: Luca Risolia
E: luca.risolia@studio.unibo.it
P: 1024D/FCE635A4 88E8 F32F 7244 68BA 3958 5D40 99DA 5D2A FCE6 35A4
@@ -3913,6 +3917,10 @@ S: Flandernstrasse 101
S: D-73732 Esslingen
S: Germany
+N: Roman Zippel
+E: zippel@linux-m68k.org
+D: AFFS and HFS filesystems, m68k maintainer, new kernel configuration in 2.5
+
N: Leonard N. Zubkoff
W: http://www.dandelion.com/Linux/
D: BusLogic SCSI driver
diff --git a/Documentation/ABI/obsolete/sysfs-driver-hid-roccat-koneplus b/Documentation/ABI/obsolete/sysfs-driver-hid-roccat-koneplus
new file mode 100644
index 000000000000..c2a270b45b03
--- /dev/null
+++ b/Documentation/ABI/obsolete/sysfs-driver-hid-roccat-koneplus
@@ -0,0 +1,10 @@
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/startup_profile
+Date: October 2010
+Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
+Description: The integer value of this attribute ranges from 0-4.
+ When read, this attribute returns the number of the actual
+ profile. This value is persistent, so its equivalent to the
+ profile that's active when the mouse is powered on next time.
+ When written, this file sets the number of the startup profile
+ and the mouse activates this profile immediately.
+ Please use actual_profile, it does the same thing.
diff --git a/Documentation/ABI/obsolete/o2cb b/Documentation/ABI/removed/o2cb
index 9c49d8e6c0cc..7f5daa465093 100644
--- a/Documentation/ABI/obsolete/o2cb
+++ b/Documentation/ABI/removed/o2cb
@@ -1,11 +1,10 @@
What: /sys/o2cb symlink
-Date: Dec 2005
-KernelVersion: 2.6.16
+Date: May 2011
+KernelVersion: 2.6.40
Contact: ocfs2-devel@oss.oracle.com
-Description: This is a symlink: /sys/o2cb to /sys/fs/o2cb. The symlink will
- be removed when new versions of ocfs2-tools which know to look
+Description: This is a symlink: /sys/o2cb to /sys/fs/o2cb. The symlink is
+ removed when new versions of ocfs2-tools which know to look
in /sys/fs/o2cb are sufficiently prevalent. Don't code new
software to look here, it should try /sys/fs/o2cb instead.
- See Documentation/ABI/stable/o2cb for more information on usage.
Users: ocfs2-tools. It's sufficient to mail proposed changes to
ocfs2-devel@oss.oracle.com.
diff --git a/Documentation/ABI/testing/sysfs-block b/Documentation/ABI/testing/sysfs-block
index 4873c759d535..c1eb41cb9876 100644
--- a/Documentation/ABI/testing/sysfs-block
+++ b/Documentation/ABI/testing/sysfs-block
@@ -142,3 +142,67 @@ Description:
with the previous I/O request are enabled. When set to 2,
all merge tries are disabled. The default value is 0 -
which enables all types of merge tries.
+
+What: /sys/block/<disk>/discard_alignment
+Date: May 2011
+Contact: Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+ Devices that support discard functionality may
+ internally allocate space in units that are bigger than
+ the exported logical block size. The discard_alignment
+ parameter indicates how many bytes the beginning of the
+ device is offset from the internal allocation unit's
+ natural alignment.
+
+What: /sys/block/<disk>/<partition>/discard_alignment
+Date: May 2011
+Contact: Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+ Devices that support discard functionality may
+ internally allocate space in units that are bigger than
+ the exported logical block size. The discard_alignment
+ parameter indicates how many bytes the beginning of the
+ partition is offset from the internal allocation unit's
+ natural alignment.
+
+What: /sys/block/<disk>/queue/discard_granularity
+Date: May 2011
+Contact: Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+ Devices that support discard functionality may
+ internally allocate space using units that are bigger
+ than the logical block size. The discard_granularity
+ parameter indicates the size of the internal allocation
+ unit in bytes if reported by the device. Otherwise the
+ discard_granularity will be set to match the device's
+ physical block size. A discard_granularity of 0 means
+ that the device does not support discard functionality.
+
+What: /sys/block/<disk>/queue/discard_max_bytes
+Date: May 2011
+Contact: Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+ Devices that support discard functionality may have
+ internal limits on the number of bytes that can be
+ trimmed or unmapped in a single operation. Some storage
+ protocols also have inherent limits on the number of
+ blocks that can be described in a single command. The
+ discard_max_bytes parameter is set by the device driver
+ to the maximum number of bytes that can be discarded in
+ a single operation. Discard requests issued to the
+ device must not exceed this limit. A discard_max_bytes
+ value of 0 means that the device does not support
+ discard functionality.
+
+What: /sys/block/<disk>/queue/discard_zeroes_data
+Date: May 2011
+Contact: Martin K. Petersen <martin.petersen@oracle.com>
+Description:
+ Devices that support discard functionality may return
+ stale or random data when a previously discarded block
+ is read back. This can cause problems if the filesystem
+ expects discarded blocks to be explicitly cleared. If a
+ device reports that it deterministically returns zeroes
+ when a discarded area is read the discard_zeroes_data
+ parameter will be set to one. Otherwise it will be 0 and
+ the result of reading a discarded area is undefined.
diff --git a/Documentation/ABI/testing/sysfs-bus-bcma b/Documentation/ABI/testing/sysfs-bus-bcma
new file mode 100644
index 000000000000..06b62badddd1
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-bcma
@@ -0,0 +1,31 @@
+What: /sys/bus/bcma/devices/.../manuf
+Date: May 2011
+KernelVersion: 2.6.40
+Contact: Rafał Miłecki <zajec5@gmail.com>
+Description:
+ Each BCMA core has it's manufacturer id. See
+ include/linux/bcma/bcma.h for possible values.
+
+What: /sys/bus/bcma/devices/.../id
+Date: May 2011
+KernelVersion: 2.6.40
+Contact: Rafał Miłecki <zajec5@gmail.com>
+Description:
+ There are a few types of BCMA cores, they can be identified by
+ id field.
+
+What: /sys/bus/bcma/devices/.../rev
+Date: May 2011
+KernelVersion: 2.6.40
+Contact: Rafał Miłecki <zajec5@gmail.com>
+Description:
+ BCMA cores of the same type can still slightly differ depending
+ on their revision. Use it for detailed programming.
+
+What: /sys/bus/bcma/devices/.../class
+Date: May 2011
+KernelVersion: 2.6.40
+Contact: Rafał Miłecki <zajec5@gmail.com>
+Description:
+ Each BCMA core is identified by few fields, including class it
+ belongs to. See include/linux/bcma/bcma.h for possible values.
diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci
index 36bf454ba855..349ecf26ce10 100644
--- a/Documentation/ABI/testing/sysfs-bus-pci
+++ b/Documentation/ABI/testing/sysfs-bus-pci
@@ -74,6 +74,15 @@ Description:
hot-remove the PCI device and any of its children.
Depends on CONFIG_HOTPLUG.
+What: /sys/bus/pci/devices/.../pci_bus/.../rescan
+Date: May 2011
+Contact: Linux PCI developers <linux-pci@vger.kernel.org>
+Description:
+ Writing a non-zero value to this attribute will
+ force a rescan of the bus and all child buses,
+ and re-discover devices removed earlier from this
+ part of the device tree. Depends on CONFIG_HOTPLUG.
+
What: /sys/bus/pci/devices/.../rescan
Date: January 2009
Contact: Linux PCI developers <linux-pci@vger.kernel.org>
diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu
index 7564e88bfa43..e7be75b96e4b 100644
--- a/Documentation/ABI/testing/sysfs-devices-system-cpu
+++ b/Documentation/ABI/testing/sysfs-devices-system-cpu
@@ -183,21 +183,21 @@ Description: Discover and change clock speed of CPUs
to learn how to control the knobs.
-What: /sys/devices/system/cpu/cpu*/cache/index*/cache_disable_X
-Date: August 2008
+What: /sys/devices/system/cpu/cpu*/cache/index3/cache_disable_{0,1}
+Date: August 2008
KernelVersion: 2.6.27
-Contact: mark.langsdorf@amd.com
-Description: These files exist in every cpu's cache index directories.
- There are currently 2 cache_disable_# files in each
- directory. Reading from these files on a supported
- processor will return that cache disable index value
- for that processor and node. Writing to one of these
- files will cause the specificed cache index to be disabled.
-
- 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://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
+Contact: discuss@x86-64.org
+Description: Disable L3 cache indices
+
+ These files exist in every CPU's cache/index3 directory. Each
+ cache_disable_{0,1} file corresponds to one disable slot which
+ can be used to disable a cache index. Reading from these files
+ on a processor with this functionality will return the currently
+ disabled index for that node. There is one L3 structure per
+ node, or per internal node on MCM machines. Writing a valid
+ index to one of these files will cause the specificed cache
+ index to be disabled.
+
+ All AMD processors with L3 caches provide this functionality.
+ For details, see BKDGs at
+ http://developer.amd.com/documentation/guides/Pages/default.aspx
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus b/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus
index 326e05452da7..c1b53b8bc2ae 100644
--- a/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus
+++ b/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus
@@ -1,9 +1,12 @@
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/actual_profile
Date: October 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
-Description: When read, this file returns the number of the actual profile in
- range 0-4.
- This file is readonly.
+Description: The integer value of this attribute ranges from 0-4.
+ When read, this attribute returns the number of the actual
+ profile. This value is persistent, so its equivalent to the
+ profile that's active when the mouse is powered on next time.
+ When written, this file sets the number of the startup profile
+ and the mouse activates this profile immediately.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/firmware_version
@@ -89,16 +92,6 @@ Description: The mouse has a tracking- and a distance-control-unit. These
This file is writeonly.
Users: http://roccat.sourceforge.net
-What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/startup_profile
-Date: October 2010
-Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
-Description: The integer value of this attribute ranges from 0-4.
- When read, this attribute returns the number of the profile
- that's active when the mouse is powered on.
- When written, this file sets the number of the startup profile
- and the mouse activates this profile immediately.
-Users: http://roccat.sourceforge.net
-
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/koneplus/roccatkoneplus<minor>/tcu
Date: October 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
diff --git a/Documentation/ABI/testing/sysfs-firmware-dmi b/Documentation/ABI/testing/sysfs-firmware-dmi
index ba9da9503c23..c78f9ab01e56 100644
--- a/Documentation/ABI/testing/sysfs-firmware-dmi
+++ b/Documentation/ABI/testing/sysfs-firmware-dmi
@@ -14,14 +14,15 @@ Description:
DMI is structured as a large table of entries, where
each entry has a common header indicating the type and
- length of the entry, as well as 'handle' that is
- supposed to be unique amongst all entries.
+ length of the entry, as well as a firmware-provided
+ 'handle' that is supposed to be unique amongst all
+ entries.
Some entries are required by the specification, but many
others are optional. In general though, users should
never expect to find a specific entry type on their
system unless they know for certain what their firmware
- is doing. Machine to machine will vary.
+ is doing. Machine to machine experiences will vary.
Multiple entries of the same type are allowed. In order
to handle these duplicate entry types, each entry is
@@ -67,25 +68,24 @@ Description:
and the two terminating nul characters.
type : The type of the entry. This value is the same
as found in the directory name. It indicates
- how the rest of the entry should be
- interpreted.
+ how the rest of the entry should be interpreted.
instance: The instance ordinal of the entry for the
given type. This value is the same as found
in the parent directory name.
- position: The position of the entry within the entirety
- of the entirety.
+ position: The ordinal position (zero-based) of the entry
+ within the entirety of the DMI entry table.
=== Entry Specialization ===
Some entry types may have other information available in
- sysfs.
+ sysfs. Not all types are specialized.
--- Type 15 - System Event Log ---
This entry allows the firmware to export a log of
events the system has taken. This information is
typically backed by nvram, but the implementation
- details are abstracted by this table. This entries data
+ details are abstracted by this table. This entry's data
is exported in the directory:
/sys/firmware/dmi/entries/15-0/system_event_log
diff --git a/Documentation/ABI/testing/sysfs-firmware-gsmi b/Documentation/ABI/testing/sysfs-firmware-gsmi
new file mode 100644
index 000000000000..0faa0aaf4b6a
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-firmware-gsmi
@@ -0,0 +1,58 @@
+What: /sys/firmware/gsmi
+Date: March 2011
+Contact: Mike Waychison <mikew@google.com>
+Description:
+ Some servers used internally at Google have firmware
+ that provides callback functionality via explicit SMI
+ triggers. Some of the callbacks are similar to those
+ provided by the EFI runtime services page, but due to
+ historical reasons this different entry-point has been
+ used.
+
+ The gsmi driver implements the kernel's abstraction for
+ these firmware callbacks. Currently, this functionality
+ is limited to handling the system event log and getting
+ access to EFI-style variables stored in nvram.
+
+ Layout:
+
+ /sys/firmware/gsmi/vars:
+
+ This directory has the same layout (and
+ underlying implementation as /sys/firmware/efi/vars.
+ See Documentation/ABI/*/sysfs-firmware-efi-vars
+ for more information on how to interact with
+ this structure.
+
+ /sys/firmware/gsmi/append_to_eventlog - write-only:
+
+ This file takes a binary blob and passes it onto
+ the firmware to be timestamped and appended to
+ the system eventlog. The binary format is
+ interpreted by the firmware and may change from
+ platform to platform. The only kernel-enforced
+ requirement is that the blob be prefixed with a
+ 32bit host-endian type used as part of the
+ firmware call.
+
+ /sys/firmware/gsmi/clear_config - write-only:
+
+ Writing any value to this file will cause the
+ entire firmware configuration to be reset to
+ "factory defaults". Callers should assume that
+ a reboot is required for the configuration to be
+ cleared.
+
+ /sys/firmware/gsmi/clear_eventlog - write-only:
+
+ This file is used to clear out a portion/the
+ whole of the system event log. Values written
+ should be values between 1 and 100 inclusive (in
+ ASCII) representing the fraction of the log to
+ clear. Not all platforms support fractional
+ clearing though, and this writes to this file
+ will error out if the firmware doesn't like your
+ submitted fraction.
+
+ Callers should assume that a reboot is needed
+ for this operation to complete.
diff --git a/Documentation/ABI/testing/sysfs-firmware-log b/Documentation/ABI/testing/sysfs-firmware-log
new file mode 100644
index 000000000000..9b58e7c5365f
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-firmware-log
@@ -0,0 +1,7 @@
+What: /sys/firmware/log
+Date: February 2011
+Contact: Mike Waychison <mikew@google.com>
+Description:
+ The /sys/firmware/log is a binary file that represents a
+ read-only copy of the firmware's log if one is
+ available.
diff --git a/Documentation/ABI/testing/sysfs-kernel-fscaps b/Documentation/ABI/testing/sysfs-kernel-fscaps
new file mode 100644
index 000000000000..50a3033b5e15
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-kernel-fscaps
@@ -0,0 +1,8 @@
+What: /sys/kernel/fscaps
+Date: February 2011
+KernelVersion: 2.6.38
+Contact: Ludwig Nussel <ludwig.nussel@suse.de>
+Description
+ Shows whether file system capabilities are honored
+ when executing a binary
+
diff --git a/Documentation/ABI/testing/sysfs-kernel-mm-cleancache b/Documentation/ABI/testing/sysfs-kernel-mm-cleancache
new file mode 100644
index 000000000000..662ae646ea12
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-kernel-mm-cleancache
@@ -0,0 +1,11 @@
+What: /sys/kernel/mm/cleancache/
+Date: April 2011
+Contact: Dan Magenheimer <dan.magenheimer@oracle.com>
+Description:
+ /sys/kernel/mm/cleancache/ contains a number of files which
+ record a count of various cleancache operations
+ (sum across all filesystems):
+ succ_gets
+ failed_gets
+ puts
+ flushes
diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power
index 194ca446ac28..b464d12761ba 100644
--- a/Documentation/ABI/testing/sysfs-power
+++ b/Documentation/ABI/testing/sysfs-power
@@ -158,3 +158,17 @@ Description:
successful, will make the kernel abort a subsequent transition
to a sleep state if any wakeup events are reported after the
write has returned.
+
+What: /sys/power/reserved_size
+Date: May 2011
+Contact: Rafael J. Wysocki <rjw@sisk.pl>
+Description:
+ The /sys/power/reserved_size file allows user space to control
+ the amount of memory reserved for allocations made by device
+ drivers during the "device freeze" stage of hibernation. It can
+ be written a string representing a non-negative integer that
+ will be used as the amount of memory to reserve for allocations
+ made by device drivers' "freeze" callbacks, in bytes.
+
+ Reading from this file will display the current value, which is
+ set to 1 MB by default.
diff --git a/Documentation/ABI/testing/sysfs-ptp b/Documentation/ABI/testing/sysfs-ptp
new file mode 100644
index 000000000000..d40d2b550502
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-ptp
@@ -0,0 +1,98 @@
+What: /sys/class/ptp/
+Date: September 2010
+Contact: Richard Cochran <richardcochran@gmail.com>
+Description:
+ This directory contains files and directories
+ providing a standardized interface to the ancillary
+ features of PTP hardware clocks.
+
+What: /sys/class/ptp/ptpN/
+Date: September 2010
+Contact: Richard Cochran <richardcochran@gmail.com>
+Description:
+ This directory contains the attributes of the Nth PTP
+ hardware clock registered into the PTP class driver
+ subsystem.
+
+What: /sys/class/ptp/ptpN/clock_name
+Date: September 2010
+Contact: Richard Cochran <richardcochran@gmail.com>
+Description:
+ This file contains the name of the PTP hardware clock
+ as a human readable string.
+
+What: /sys/class/ptp/ptpN/max_adjustment
+Date: September 2010
+Contact: Richard Cochran <richardcochran@gmail.com>
+Description:
+ This file contains the PTP hardware clock's maximum
+ frequency adjustment value (a positive integer) in
+ parts per billion.
+
+What: /sys/class/ptp/ptpN/n_alarms
+Date: September 2010
+Contact: Richard Cochran <richardcochran@gmail.com>
+Description:
+ This file contains the number of periodic or one shot
+ alarms offer by the PTP hardware clock.
+
+What: /sys/class/ptp/ptpN/n_external_timestamps
+Date: September 2010
+Contact: Richard Cochran <richardcochran@gmail.com>
+Description:
+ This file contains the number of external timestamp
+ channels offered by the PTP hardware clock.
+
+What: /sys/class/ptp/ptpN/n_periodic_outputs
+Date: September 2010
+Contact: Richard Cochran <richardcochran@gmail.com>
+Description:
+ This file contains the number of programmable periodic
+ output channels offered by the PTP hardware clock.
+
+What: /sys/class/ptp/ptpN/pps_avaiable
+Date: September 2010
+Contact: Richard Cochran <richardcochran@gmail.com>
+Description:
+ This file indicates whether the PTP hardware clock
+ supports a Pulse Per Second to the host CPU. Reading
+ "1" means that the PPS is supported, while "0" means
+ not supported.
+
+What: /sys/class/ptp/ptpN/extts_enable
+Date: September 2010
+Contact: Richard Cochran <richardcochran@gmail.com>
+Description:
+ This write-only file enables or disables external
+ timestamps. To enable external timestamps, write the
+ channel index followed by a "1" into the file.
+ To disable external timestamps, write the channel
+ index followed by a "0" into the file.
+
+What: /sys/class/ptp/ptpN/fifo
+Date: September 2010
+Contact: Richard Cochran <richardcochran@gmail.com>
+Description:
+ This file provides timestamps on external events, in
+ the form of three integers: channel index, seconds,
+ and nanoseconds.
+
+What: /sys/class/ptp/ptpN/period
+Date: September 2010
+Contact: Richard Cochran <richardcochran@gmail.com>
+Description:
+ This write-only file enables or disables periodic
+ outputs. To enable a periodic output, write five
+ integers into the file: channel index, start time
+ seconds, start time nanoseconds, period seconds, and
+ period nanoseconds. To disable a periodic output, set
+ all the seconds and nanoseconds values to zero.
+
+What: /sys/class/ptp/ptpN/pps_enable
+Date: September 2010
+Contact: Richard Cochran <richardcochran@gmail.com>
+Description:
+ This write-only file enables or disables delivery of
+ PPS events to the Linux PPS subsystem. To enable PPS
+ events, write a "1" into the file. To disable events,
+ write a "0" into the file.
diff --git a/Documentation/DocBook/.gitignore b/Documentation/DocBook/.gitignore
index c6def352fe39..679034cbd686 100644
--- a/Documentation/DocBook/.gitignore
+++ b/Documentation/DocBook/.gitignore
@@ -8,3 +8,4 @@
*.dvi
*.log
*.out
+media/
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index 8436b018c289..3cebfa0d1611 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -73,7 +73,7 @@ installmandocs: mandocs
###
#External programs used
KERNELDOC = $(srctree)/scripts/kernel-doc
-DOCPROC = $(objtree)/scripts/basic/docproc
+DOCPROC = $(objtree)/scripts/docproc
XMLTOFLAGS = -m $(srctree)/Documentation/DocBook/stylesheet.xsl
XMLTOFLAGS += --skip-validation
diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl
index 36f63d4a0a06..b638e50cf8f6 100644
--- a/Documentation/DocBook/device-drivers.tmpl
+++ b/Documentation/DocBook/device-drivers.tmpl
@@ -96,10 +96,10 @@ X!Iinclude/linux/kobject.h
<chapter id="devdrivers">
<title>Device drivers infrastructure</title>
+ <sect1><title>The Basic Device Driver-Model Structures </title>
+!Iinclude/linux/device.h
+ </sect1>
<sect1><title>Device Drivers Base</title>
-<!--
-X!Iinclude/linux/device.h
--->
!Edrivers/base/driver.c
!Edrivers/base/core.c
!Edrivers/base/class.c
diff --git a/Documentation/DocBook/dvb/dvbapi.xml b/Documentation/DocBook/dvb/dvbapi.xml
index ad8678d48916..9fad86ce7f5e 100644
--- a/Documentation/DocBook/dvb/dvbapi.xml
+++ b/Documentation/DocBook/dvb/dvbapi.xml
@@ -35,6 +35,14 @@
<revhistory>
<!-- Put document revisions here, newest first. -->
<revision>
+ <revnumber>2.0.4</revnumber>
+ <date>2011-05-06</date>
+ <authorinitials>mcc</authorinitials>
+ <revremark>
+ Add more information about DVB APIv5, better describing the frontend GET/SET props ioctl's.
+ </revremark>
+</revision>
+<revision>
<revnumber>2.0.3</revnumber>
<date>2010-07-03</date>
<authorinitials>mcc</authorinitials>
diff --git a/Documentation/DocBook/dvb/dvbproperty.xml b/Documentation/DocBook/dvb/dvbproperty.xml
index 97f397e2fb3a..b5365f61d69b 100644
--- a/Documentation/DocBook/dvb/dvbproperty.xml
+++ b/Documentation/DocBook/dvb/dvbproperty.xml
@@ -1,6 +1,330 @@
-<section id="FE_GET_PROPERTY">
+<section id="FE_GET_SET_PROPERTY">
<title>FE_GET_PROPERTY/FE_SET_PROPERTY</title>
+<programlisting>
+/* Reserved fields should be set to 0 */
+struct dtv_property {
+ __u32 cmd;
+ union {
+ __u32 data;
+ struct {
+ __u8 data[32];
+ __u32 len;
+ __u32 reserved1[3];
+ void *reserved2;
+ } buffer;
+ } u;
+ int result;
+} __attribute__ ((packed));
+
+/* num of properties cannot exceed DTV_IOCTL_MAX_MSGS per ioctl */
+#define DTV_IOCTL_MAX_MSGS 64
+
+struct dtv_properties {
+ __u32 num;
+ struct dtv_property *props;
+};
+</programlisting>
+
+<section id="FE_GET_PROPERTY">
+<title>FE_GET_PROPERTY</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call returns one or more frontend properties. This call only
+ requires read-only access to the device.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link>,
+ dtv_properties &#x22C6;props);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int num</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link> for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct dtv_property *props</para>
+</entry><entry
+ align="char">
+<para>Points to the location where the front-end property commands are stored.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>ERRORS</para>
+<informaltable><tgroup cols="2"><tbody><row>
+ <entry align="char"><para>EINVAL</para></entry>
+ <entry align="char"><para>Invalid parameter(s) received or number of parameters out of the range.</para></entry>
+ </row><row>
+ <entry align="char"><para>ENOMEM</para></entry>
+ <entry align="char"><para>Out of memory.</para></entry>
+ </row><row>
+ <entry align="char"><para>EFAULT</para></entry>
+ <entry align="char"><para>Failure while copying data from/to userspace.</para></entry>
+ </row><row>
+ <entry align="char"><para>EOPNOTSUPP</para></entry>
+ <entry align="char"><para>Property type not supported.</para></entry>
+ </row></tbody></tgroup></informaltable>
+</section>
+
+<section id="FE_SET_PROPERTY">
+<title>FE_SET_PROPERTY</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call sets one or more frontend properties. This call only
+ requires read-only access to the device.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request = <link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link>,
+ dtv_properties &#x22C6;props);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int num</para>
+</entry><entry
+ align="char">
+<para>Equals <link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link> for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct dtv_property *props</para>
+</entry><entry
+ align="char">
+<para>Points to the location where the front-end property commands are stored.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>ERRORS
+</para>
+<informaltable><tgroup cols="2"><tbody><row>
+ <entry align="char"><para>EINVAL</para></entry>
+ <entry align="char"><para>Invalid parameter(s) received or number of parameters out of the range.</para></entry>
+ </row><row>
+ <entry align="char"><para>ENOMEM</para></entry>
+ <entry align="char"><para>Out of memory.</para></entry>
+ </row><row>
+ <entry align="char"><para>EFAULT</para></entry>
+ <entry align="char"><para>Failure while copying data from/to userspace.</para></entry>
+ </row><row>
+ <entry align="char"><para>EOPNOTSUPP</para></entry>
+ <entry align="char"><para>Property type not supported.</para></entry>
+ </row></tbody></tgroup></informaltable>
+</section>
+
+<section>
+ <title>Property types</title>
+<para>
+On <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link>/<link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link>,
+the actual action is determined by the dtv_property cmd/data pairs. With one single ioctl, is possible to
+get/set up to 64 properties. The actual meaning of each property is described on the next sections.
+</para>
+
+<para>The available frontend property types are:</para>
+<programlisting>
+#define DTV_UNDEFINED 0
+#define DTV_TUNE 1
+#define DTV_CLEAR 2
+#define DTV_FREQUENCY 3
+#define DTV_MODULATION 4
+#define DTV_BANDWIDTH_HZ 5
+#define DTV_INVERSION 6
+#define DTV_DISEQC_MASTER 7
+#define DTV_SYMBOL_RATE 8
+#define DTV_INNER_FEC 9
+#define DTV_VOLTAGE 10
+#define DTV_TONE 11
+#define DTV_PILOT 12
+#define DTV_ROLLOFF 13
+#define DTV_DISEQC_SLAVE_REPLY 14
+#define DTV_FE_CAPABILITY_COUNT 15
+#define DTV_FE_CAPABILITY 16
+#define DTV_DELIVERY_SYSTEM 17
+#define DTV_ISDBT_PARTIAL_RECEPTION 18
+#define DTV_ISDBT_SOUND_BROADCASTING 19
+#define DTV_ISDBT_SB_SUBCHANNEL_ID 20
+#define DTV_ISDBT_SB_SEGMENT_IDX 21
+#define DTV_ISDBT_SB_SEGMENT_COUNT 22
+#define DTV_ISDBT_LAYERA_FEC 23
+#define DTV_ISDBT_LAYERA_MODULATION 24
+#define DTV_ISDBT_LAYERA_SEGMENT_COUNT 25
+#define DTV_ISDBT_LAYERA_TIME_INTERLEAVING 26
+#define DTV_ISDBT_LAYERB_FEC 27
+#define DTV_ISDBT_LAYERB_MODULATION 28
+#define DTV_ISDBT_LAYERB_SEGMENT_COUNT 29
+#define DTV_ISDBT_LAYERB_TIME_INTERLEAVING 30
+#define DTV_ISDBT_LAYERC_FEC 31
+#define DTV_ISDBT_LAYERC_MODULATION 32
+#define DTV_ISDBT_LAYERC_SEGMENT_COUNT 33
+#define DTV_ISDBT_LAYERC_TIME_INTERLEAVING 34
+#define DTV_API_VERSION 35
+#define DTV_CODE_RATE_HP 36
+#define DTV_CODE_RATE_LP 37
+#define DTV_GUARD_INTERVAL 38
+#define DTV_TRANSMISSION_MODE 39
+#define DTV_HIERARCHY 40
+#define DTV_ISDBT_LAYER_ENABLED 41
+#define DTV_ISDBS_TS_ID 42
+</programlisting>
+</section>
+
+<section id="fe_property_common">
+ <title>Parameters that are common to all Digital TV standards</title>
+ <section id="DTV_FREQUENCY">
+ <title><constant>DTV_FREQUENCY</constant></title>
+
+ <para>Central frequency of the channel, in HZ.</para>
+
+ <para>Notes:</para>
+ <para>1)For ISDB-T, the channels are usually transmitted with an offset of 143kHz.
+ E.g. a valid frequncy could be 474143 kHz. The stepping is bound to the bandwidth of
+ the channel which is 6MHz.</para>
+
+ <para>2)As in ISDB-Tsb the channel consists of only one or three segments the
+ frequency step is 429kHz, 3*429 respectively. As for ISDB-T the
+ central frequency of the channel is expected.</para>
+ </section>
+
+ <section id="DTV_BANDWIDTH_HZ">
+ <title><constant>DTV_BANDWIDTH_HZ</constant></title>
+
+ <para>Bandwidth for the channel, in HZ.</para>
+
+ <para>Possible values:
+ <constant>1712000</constant>,
+ <constant>5000000</constant>,
+ <constant>6000000</constant>,
+ <constant>7000000</constant>,
+ <constant>8000000</constant>,
+ <constant>10000000</constant>.
+ </para>
+
+ <para>Notes:</para>
+
+ <para>1) For ISDB-T it should be always 6000000Hz (6MHz)</para>
+ <para>2) For ISDB-Tsb it can vary depending on the number of connected segments</para>
+ <para>3) Bandwidth doesn't apply for DVB-C transmissions, as the bandwidth
+ for DVB-C depends on the symbol rate</para>
+ <para>4) Bandwidth in ISDB-T is fixed (6MHz) or can be easily derived from
+ other parameters (DTV_ISDBT_SB_SEGMENT_IDX,
+ DTV_ISDBT_SB_SEGMENT_COUNT).</para>
+ <para>5) DVB-T supports 6, 7 and 8MHz.</para>
+ <para>6) In addition, DVB-T2 supports 1.172, 5 and 10MHz.</para>
+ </section>
+
+ <section id="DTV_DELIVERY_SYSTEM">
+ <title><constant>DTV_DELIVERY_SYSTEM</constant></title>
+
+ <para>Specifies the type of Delivery system</para>
+
+ <para>Possible values: </para>
+<programlisting>
+typedef enum fe_delivery_system {
+ SYS_UNDEFINED,
+ SYS_DVBC_ANNEX_AC,
+ SYS_DVBC_ANNEX_B,
+ SYS_DVBT,
+ SYS_DSS,
+ SYS_DVBS,
+ SYS_DVBS2,
+ SYS_DVBH,
+ SYS_ISDBT,
+ SYS_ISDBS,
+ SYS_ISDBC,
+ SYS_ATSC,
+ SYS_ATSCMH,
+ SYS_DMBTH,
+ SYS_CMMB,
+ SYS_DAB,
+ SYS_DVBT2,
+} fe_delivery_system_t;
+</programlisting>
+
+ </section>
+
+ <section id="DTV_TRANSMISSION_MODE">
+ <title><constant>DTV_TRANSMISSION_MODE</constant></title>
+
+ <para>Specifies the number of carriers used by the standard</para>
+
+ <para>Possible values are:</para>
+<programlisting>
+typedef enum fe_transmit_mode {
+ TRANSMISSION_MODE_2K,
+ TRANSMISSION_MODE_8K,
+ TRANSMISSION_MODE_AUTO,
+ TRANSMISSION_MODE_4K,
+ TRANSMISSION_MODE_1K,
+ TRANSMISSION_MODE_16K,
+ TRANSMISSION_MODE_32K,
+} fe_transmit_mode_t;
+</programlisting>
+
+ <para>Notes:</para>
+ <para>1) ISDB-T supports three carrier/symbol-size: 8K, 4K, 2K. It is called
+ 'mode' in the standard: Mode 1 is 2K, mode 2 is 4K, mode 3 is 8K</para>
+
+ <para>2) If <constant>DTV_TRANSMISSION_MODE</constant> is set the <constant>TRANSMISSION_MODE_AUTO</constant> the
+ hardware will try to find the correct FFT-size (if capable) and will
+ use TMCC to fill in the missing parameters.</para>
+ <para>3) DVB-T specifies 2K and 8K as valid sizes.</para>
+ <para>4) DVB-T2 specifies 1K, 2K, 4K, 8K, 16K and 32K.</para>
+ </section>
+
+ <section id="DTV_GUARD_INTERVAL">
+ <title><constant>DTV_GUARD_INTERVAL</constant></title>
+
+ <para>Possible values are:</para>
+<programlisting>
+typedef enum fe_guard_interval {
+ GUARD_INTERVAL_1_32,
+ GUARD_INTERVAL_1_16,
+ GUARD_INTERVAL_1_8,
+ GUARD_INTERVAL_1_4,
+ GUARD_INTERVAL_AUTO,
+ GUARD_INTERVAL_1_128,
+ GUARD_INTERVAL_19_128,
+ GUARD_INTERVAL_19_256,
+} fe_guard_interval_t;
+</programlisting>
+
+ <para>Notes:</para>
+ <para>1) If <constant>DTV_GUARD_INTERVAL</constant> is set the <constant>GUARD_INTERVAL_AUTO</constant> the hardware will
+ try to find the correct guard interval (if capable) and will use TMCC to fill
+ in the missing parameters.</para>
+ <para>2) Intervals 1/128, 19/128 and 19/256 are used only for DVB-T2 at present</para>
+ </section>
+</section>
+
<section id="isdbt">
<title>ISDB-T frontend</title>
<para>This section describes shortly what are the possible parameters in the Linux
@@ -32,73 +356,6 @@
<para>Parameters used by ISDB-T and ISDB-Tsb.</para>
- <section id="isdbt-parms">
- <title>Parameters that are common with DVB-T and ATSC</title>
-
- <section id="isdbt-freq">
- <title><constant>DTV_FREQUENCY</constant></title>
-
- <para>Central frequency of the channel.</para>
-
- <para>For ISDB-T the channels are usually transmitted with an offset of 143kHz. E.g. a
- valid frequncy could be 474143 kHz. The stepping is bound to the bandwidth of
- the channel which is 6MHz.</para>
-
- <para>As in ISDB-Tsb the channel consists of only one or three segments the
- frequency step is 429kHz, 3*429 respectively. As for ISDB-T the
- central frequency of the channel is expected.</para>
- </section>
-
- <section id="isdbt-bw">
- <title><constant>DTV_BANDWIDTH_HZ</constant> (optional)</title>
-
- <para>Possible values:</para>
-
- <para>For ISDB-T it should be always 6000000Hz (6MHz)</para>
- <para>For ISDB-Tsb it can vary depending on the number of connected segments</para>
-
- <para>Note: Hardware specific values might be given here, but standard
- applications should not bother to set a value to this field as
- standard demods are ignoring it anyway.</para>
-
- <para>Bandwidth in ISDB-T is fixed (6MHz) or can be easily derived from
- other parameters (DTV_ISDBT_SB_SEGMENT_IDX,
- DTV_ISDBT_SB_SEGMENT_COUNT).</para>
- </section>
-
- <section id="isdbt-delivery-sys">
- <title><constant>DTV_DELIVERY_SYSTEM</constant></title>
-
- <para>Possible values: <constant>SYS_ISDBT</constant></para>
- </section>
-
- <section id="isdbt-tx-mode">
- <title><constant>DTV_TRANSMISSION_MODE</constant></title>
-
- <para>ISDB-T supports three carrier/symbol-size: 8K, 4K, 2K. It is called
- 'mode' in the standard: Mode 1 is 2K, mode 2 is 4K, mode 3 is 8K</para>
-
- <para>Possible values: <constant>TRANSMISSION_MODE_2K</constant>, <constant>TRANSMISSION_MODE_8K</constant>,
- <constant>TRANSMISSION_MODE_AUTO</constant>, <constant>TRANSMISSION_MODE_4K</constant></para>
-
- <para>If <constant>DTV_TRANSMISSION_MODE</constant> is set the <constant>TRANSMISSION_MODE_AUTO</constant> the
- hardware will try to find the correct FFT-size (if capable) and will
- use TMCC to fill in the missing parameters.</para>
-
- <para><constant>TRANSMISSION_MODE_4K</constant> is added at the same time as the other new parameters.</para>
- </section>
-
- <section id="isdbt-guard-interval">
- <title><constant>DTV_GUARD_INTERVAL</constant></title>
-
- <para>Possible values: <constant>GUARD_INTERVAL_1_32</constant>, <constant>GUARD_INTERVAL_1_16</constant>, <constant>GUARD_INTERVAL_1_8</constant>,
- <constant>GUARD_INTERVAL_1_4</constant>, <constant>GUARD_INTERVAL_AUTO</constant></para>
-
- <para>If <constant>DTV_GUARD_INTERVAL</constant> is set the <constant>GUARD_INTERVAL_AUTO</constant> the hardware will
- try to find the correct guard interval (if capable) and will use TMCC to fill
- in the missing parameters.</para>
- </section>
- </section>
<section id="isdbt-new-parms">
<title>ISDB-T only parameters</title>
@@ -314,5 +571,20 @@
</section>
</section>
</section>
+ <section id="dvbt2-params">
+ <title>DVB-T2 parameters</title>
+
+ <para>This section covers parameters that apply only to the DVB-T2 delivery method. DVB-T2
+ support is currently in the early stages development so expect this section to grow
+ and become more detailed with time.</para>
+
+ <section id="dvbt2-plp-id">
+ <title><constant>DTV_DVBT2_PLP_ID</constant></title>
+
+ <para>DVB-T2 supports Physical Layer Pipes (PLP) to allow transmission of
+ many data types via a single multiplex. The API will soon support this
+ at which point this section will be expanded.</para>
+ </section>
+ </section>
</section>
</section>
diff --git a/Documentation/DocBook/dvb/frontend.h.xml b/Documentation/DocBook/dvb/frontend.h.xml
index d08e0d401418..d792f789ad3b 100644
--- a/Documentation/DocBook/dvb/frontend.h.xml
+++ b/Documentation/DocBook/dvb/frontend.h.xml
@@ -176,14 +176,20 @@ typedef enum fe_transmit_mode {
TRANSMISSION_MODE_2K,
TRANSMISSION_MODE_8K,
TRANSMISSION_MODE_AUTO,
- TRANSMISSION_MODE_4K
+ TRANSMISSION_MODE_4K,
+ TRANSMISSION_MODE_1K,
+ TRANSMISSION_MODE_16K,
+ TRANSMISSION_MODE_32K,
} fe_transmit_mode_t;
typedef enum fe_bandwidth {
BANDWIDTH_8_MHZ,
BANDWIDTH_7_MHZ,
BANDWIDTH_6_MHZ,
- BANDWIDTH_AUTO
+ BANDWIDTH_AUTO,
+ BANDWIDTH_5_MHZ,
+ BANDWIDTH_10_MHZ,
+ BANDWIDTH_1_712_MHZ,
} fe_bandwidth_t;
@@ -192,7 +198,10 @@ typedef enum fe_guard_interval {
GUARD_INTERVAL_1_16,
GUARD_INTERVAL_1_8,
GUARD_INTERVAL_1_4,
- GUARD_INTERVAL_AUTO
+ GUARD_INTERVAL_AUTO,
+ GUARD_INTERVAL_1_128,
+ GUARD_INTERVAL_19_128,
+ GUARD_INTERVAL_19_256,
} fe_guard_interval_t;
@@ -306,7 +315,9 @@ struct dvb_frontend_event {
#define DTV_ISDBS_TS_ID 42
-#define DTV_MAX_COMMAND DTV_ISDBS_TS_ID
+#define DTV_DVBT2_PLP_ID 43
+
+#define DTV_MAX_COMMAND DTV_DVBT2_PLP_ID
typedef enum fe_pilot {
PILOT_ON,
@@ -338,6 +349,7 @@ typedef enum fe_delivery_system {
SYS_DMBTH,
SYS_CMMB,
SYS_DAB,
+ SYS_DVBT2,
} fe_delivery_system_t;
struct dtv_cmds_h {
diff --git a/Documentation/DocBook/genericirq.tmpl b/Documentation/DocBook/genericirq.tmpl
index fb10fd08c05c..b3422341d65c 100644
--- a/Documentation/DocBook/genericirq.tmpl
+++ b/Documentation/DocBook/genericirq.tmpl
@@ -191,8 +191,8 @@
<para>
Whenever an interrupt triggers, the lowlevel arch code calls into
the generic interrupt code by calling desc->handle_irq().
- This highlevel IRQ handling function only uses desc->chip primitives
- referenced by the assigned chip descriptor structure.
+ This highlevel IRQ handling function only uses desc->irq_data.chip
+ primitives referenced by the assigned chip descriptor structure.
</para>
</sect1>
<sect1 id="Highlevel_Driver_API">
@@ -206,11 +206,11 @@
<listitem><para>enable_irq()</para></listitem>
<listitem><para>disable_irq_nosync() (SMP only)</para></listitem>
<listitem><para>synchronize_irq() (SMP only)</para></listitem>
- <listitem><para>set_irq_type()</para></listitem>
- <listitem><para>set_irq_wake()</para></listitem>
- <listitem><para>set_irq_data()</para></listitem>
- <listitem><para>set_irq_chip()</para></listitem>
- <listitem><para>set_irq_chip_data()</para></listitem>
+ <listitem><para>irq_set_irq_type()</para></listitem>
+ <listitem><para>irq_set_irq_wake()</para></listitem>
+ <listitem><para>irq_set_handler_data()</para></listitem>
+ <listitem><para>irq_set_chip()</para></listitem>
+ <listitem><para>irq_set_chip_data()</para></listitem>
</itemizedlist>
See the autogenerated function documentation for details.
</para>
@@ -225,6 +225,8 @@
<listitem><para>handle_fasteoi_irq</para></listitem>
<listitem><para>handle_simple_irq</para></listitem>
<listitem><para>handle_percpu_irq</para></listitem>
+ <listitem><para>handle_edge_eoi_irq</para></listitem>
+ <listitem><para>handle_bad_irq</para></listitem>
</itemizedlist>
The interrupt flow handlers (either predefined or architecture
specific) are assigned to specific interrupts by the architecture
@@ -241,13 +243,13 @@
<programlisting>
default_enable(struct irq_data *data)
{
- desc->chip->irq_unmask(data);
+ desc->irq_data.chip->irq_unmask(data);
}
default_disable(struct irq_data *data)
{
if (!delay_disable(data))
- desc->chip->irq_mask(data);
+ desc->irq_data.chip->irq_mask(data);
}
default_ack(struct irq_data *data)
@@ -284,9 +286,9 @@ noop(struct irq_data *data))
<para>
The following control flow is implemented (simplified excerpt):
<programlisting>
-desc->chip->irq_mask();
-handle_IRQ_event(desc->action);
-desc->chip->irq_unmask();
+desc->irq_data.chip->irq_mask_ack();
+handle_irq_event(desc->action);
+desc->irq_data.chip->irq_unmask();
</programlisting>
</para>
</sect3>
@@ -300,8 +302,8 @@ desc->chip->irq_unmask();
<para>
The following control flow is implemented (simplified excerpt):
<programlisting>
-handle_IRQ_event(desc->action);
-desc->chip->irq_eoi();
+handle_irq_event(desc->action);
+desc->irq_data.chip->irq_eoi();
</programlisting>
</para>
</sect3>
@@ -315,17 +317,17 @@ desc->chip->irq_eoi();
The following control flow is implemented (simplified excerpt):
<programlisting>
if (desc->status &amp; running) {
- desc->chip->irq_mask();
+ desc->irq_data.chip->irq_mask_ack();
desc->status |= pending | masked;
return;
}
-desc->chip->irq_ack();
+desc->irq_data.chip->irq_ack();
desc->status |= running;
do {
if (desc->status &amp; masked)
- desc->chip->irq_unmask();
+ desc->irq_data.chip->irq_unmask();
desc->status &amp;= ~pending;
- handle_IRQ_event(desc->action);
+ handle_irq_event(desc->action);
} while (status &amp; pending);
desc->status &amp;= ~running;
</programlisting>
@@ -344,7 +346,7 @@ desc->status &amp;= ~running;
<para>
The following control flow is implemented (simplified excerpt):
<programlisting>
-handle_IRQ_event(desc->action);
+handle_irq_event(desc->action);
</programlisting>
</para>
</sect3>
@@ -362,12 +364,29 @@ handle_IRQ_event(desc->action);
<para>
The following control flow is implemented (simplified excerpt):
<programlisting>
-handle_IRQ_event(desc->action);
-if (desc->chip->irq_eoi)
- desc->chip->irq_eoi();
+if (desc->irq_data.chip->irq_ack)
+ desc->irq_data.chip->irq_ack();
+handle_irq_event(desc->action);
+if (desc->irq_data.chip->irq_eoi)
+ desc->irq_data.chip->irq_eoi();
</programlisting>
</para>
</sect3>
+ <sect3 id="EOI_Edge_IRQ_flow_handler">
+ <title>EOI Edge IRQ flow handler</title>
+ <para>
+ handle_edge_eoi_irq provides an abnomination of the edge
+ handler which is solely used to tame a badly wreckaged
+ irq controller on powerpc/cell.
+ </para>
+ </sect3>
+ <sect3 id="BAD_IRQ_flow_handler">
+ <title>Bad IRQ flow handler</title>
+ <para>
+ handle_bad_irq is used for spurious interrupts which
+ have no real handler assigned..
+ </para>
+ </sect3>
</sect2>
<sect2 id="Quirks_and_optimizations">
<title>Quirks and optimizations</title>
@@ -410,6 +429,7 @@ if (desc->chip->irq_eoi)
<listitem><para>irq_mask_ack() - Optional, recommended for performance</para></listitem>
<listitem><para>irq_mask()</para></listitem>
<listitem><para>irq_unmask()</para></listitem>
+ <listitem><para>irq_eoi() - Optional, required for eoi flow handlers</para></listitem>
<listitem><para>irq_retrigger() - Optional</para></listitem>
<listitem><para>irq_set_type() - Optional</para></listitem>
<listitem><para>irq_set_wake() - Optional</para></listitem>
@@ -424,32 +444,24 @@ if (desc->chip->irq_eoi)
<chapter id="doirq">
<title>__do_IRQ entry point</title>
<para>
- The original implementation __do_IRQ() is an alternative entry
- point for all types of interrupts.
+ The original implementation __do_IRQ() was an alternative entry
+ point for all types of interrupts. It not longer exists.
</para>
<para>
This handler turned out to be not suitable for all
interrupt hardware and was therefore reimplemented with split
- functionality for egde/level/simple/percpu interrupts. This is not
+ functionality for edge/level/simple/percpu interrupts. This is not
only a functional optimization. It also shortens code paths for
interrupts.
</para>
- <para>
- To make use of the split implementation, replace the call to
- __do_IRQ by a call to desc->handle_irq() and associate
- the appropriate handler function to desc->handle_irq().
- In most cases the generic handler implementations should
- be sufficient.
- </para>
</chapter>
<chapter id="locking">
<title>Locking on SMP</title>
<para>
The locking of chip registers is up to the architecture that
- defines the chip primitives. There is a chip->lock field that can be used
- for serialization, but the generic layer does not touch it. The per-irq
- structure is protected via desc->lock, by the generic layer.
+ defines the chip primitives. The per-irq structure is
+ protected via desc->lock, by the generic layer.
</para>
</chapter>
<chapter id="structs">
diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl
index fea63b45471a..e5fe09430fd9 100644
--- a/Documentation/DocBook/media-entities.tmpl
+++ b/Documentation/DocBook/media-entities.tmpl
@@ -270,6 +270,7 @@
<!ENTITY sub-write SYSTEM "v4l/func-write.xml">
<!ENTITY sub-io SYSTEM "v4l/io.xml">
<!ENTITY sub-grey SYSTEM "v4l/pixfmt-grey.xml">
+<!ENTITY sub-m420 SYSTEM "v4l/pixfmt-m420.xml">
<!ENTITY sub-nv12 SYSTEM "v4l/pixfmt-nv12.xml">
<!ENTITY sub-nv12m SYSTEM "v4l/pixfmt-nv12m.xml">
<!ENTITY sub-nv12mt SYSTEM "v4l/pixfmt-nv12mt.xml">
@@ -292,9 +293,11 @@
<!ENTITY sub-yuyv SYSTEM "v4l/pixfmt-yuyv.xml">
<!ENTITY sub-yvyu SYSTEM "v4l/pixfmt-yvyu.xml">
<!ENTITY sub-srggb10 SYSTEM "v4l/pixfmt-srggb10.xml">
+<!ENTITY sub-srggb12 SYSTEM "v4l/pixfmt-srggb12.xml">
<!ENTITY sub-srggb8 SYSTEM "v4l/pixfmt-srggb8.xml">
<!ENTITY sub-y10 SYSTEM "v4l/pixfmt-y10.xml">
<!ENTITY sub-y12 SYSTEM "v4l/pixfmt-y12.xml">
+<!ENTITY sub-y10b SYSTEM "v4l/pixfmt-y10b.xml">
<!ENTITY sub-pixfmt SYSTEM "v4l/pixfmt.xml">
<!ENTITY sub-cropcap SYSTEM "v4l/vidioc-cropcap.xml">
<!ENTITY sub-dbg-g-register SYSTEM "v4l/vidioc-dbg-g-register.xml">
@@ -371,9 +374,9 @@
<!ENTITY sub-media-indices SYSTEM "media-indices.tmpl">
<!ENTITY sub-media-controller SYSTEM "v4l/media-controller.xml">
-<!ENTITY sub-media-open SYSTEM "v4l/media-func-open.xml">
-<!ENTITY sub-media-close SYSTEM "v4l/media-func-close.xml">
-<!ENTITY sub-media-ioctl SYSTEM "v4l/media-func-ioctl.xml">
+<!ENTITY sub-media-func-open SYSTEM "v4l/media-func-open.xml">
+<!ENTITY sub-media-func-close SYSTEM "v4l/media-func-close.xml">
+<!ENTITY sub-media-func-ioctl SYSTEM "v4l/media-func-ioctl.xml">
<!ENTITY sub-media-ioc-device-info SYSTEM "v4l/media-ioc-device-info.xml">
<!ENTITY sub-media-ioc-enum-entities SYSTEM "v4l/media-ioc-enum-entities.xml">
<!ENTITY sub-media-ioc-enum-links SYSTEM "v4l/media-ioc-enum-links.xml">
diff --git a/Documentation/DocBook/v4l/media-controller.xml b/Documentation/DocBook/v4l/media-controller.xml
index 2dc25e1d4089..873ac3a621f0 100644
--- a/Documentation/DocBook/v4l/media-controller.xml
+++ b/Documentation/DocBook/v4l/media-controller.xml
@@ -78,9 +78,9 @@
<appendix id="media-user-func">
<title>Function Reference</title>
<!-- Keep this alphabetically sorted. -->
- &sub-media-open;
- &sub-media-close;
- &sub-media-ioctl;
+ &sub-media-func-open;
+ &sub-media-func-close;
+ &sub-media-func-ioctl;
<!-- All ioctls go here. -->
&sub-media-ioc-device-info;
&sub-media-ioc-enum-entities;
diff --git a/Documentation/DocBook/v4l/pixfmt-m420.xml b/Documentation/DocBook/v4l/pixfmt-m420.xml
new file mode 100644
index 000000000000..ce4bc019e5c0
--- /dev/null
+++ b/Documentation/DocBook/v4l/pixfmt-m420.xml
@@ -0,0 +1,147 @@
+ <refentry id="V4L2-PIX-FMT-M420">
+ <refmeta>
+ <refentrytitle>V4L2_PIX_FMT_M420 ('M420')</refentrytitle>
+ &manvol;
+ </refmeta>
+ <refnamediv>
+ <refname><constant>V4L2_PIX_FMT_M420</constant></refname>
+ <refpurpose>Format with &frac12; horizontal and vertical chroma
+ resolution, also known as YUV 4:2:0. Hybrid plane line-interleaved
+ layout.</refpurpose>
+ </refnamediv>
+ <refsect1>
+ <title>Description</title>
+
+ <para>M420 is a YUV format with &frac12; horizontal and vertical chroma
+ subsampling (YUV 4:2:0). Pixels are organized as interleaved luma and
+ chroma planes. Two lines of luma data are followed by one line of chroma
+ data.</para>
+ <para>The luma plane has one byte per pixel. The chroma plane contains
+ interleaved CbCr pixels subsampled by &frac12; in the horizontal and
+ vertical directions. Each CbCr pair belongs to four pixels. For example,
+Cb<subscript>0</subscript>/Cr<subscript>0</subscript> belongs to
+Y'<subscript>00</subscript>, Y'<subscript>01</subscript>,
+Y'<subscript>10</subscript>, Y'<subscript>11</subscript>.</para>
+
+ <para>All line lengths are identical: if the Y lines include pad bytes
+ so do the CbCr lines.</para>
+
+ <example>
+ <title><constant>V4L2_PIX_FMT_M420</constant> 4 &times; 4
+pixel image</title>
+
+ <formalpara>
+ <title>Byte Order.</title>
+ <para>Each cell is one byte.
+ <informaltable frame="none">
+ <tgroup cols="5" align="center">
+ <colspec align="left" colwidth="2*" />
+ <tbody valign="top">
+ <row>
+ <entry>start&nbsp;+&nbsp;0:</entry>
+ <entry>Y'<subscript>00</subscript></entry>
+ <entry>Y'<subscript>01</subscript></entry>
+ <entry>Y'<subscript>02</subscript></entry>
+ <entry>Y'<subscript>03</subscript></entry>
+ </row>
+ <row>
+ <entry>start&nbsp;+&nbsp;4:</entry>
+ <entry>Y'<subscript>10</subscript></entry>
+ <entry>Y'<subscript>11</subscript></entry>
+ <entry>Y'<subscript>12</subscript></entry>
+ <entry>Y'<subscript>13</subscript></entry>
+ </row>
+ <row>
+ <entry>start&nbsp;+&nbsp;8:</entry>
+ <entry>Cb<subscript>00</subscript></entry>
+ <entry>Cr<subscript>00</subscript></entry>
+ <entry>Cb<subscript>01</subscript></entry>
+ <entry>Cr<subscript>01</subscript></entry>
+ </row>
+ <row>
+ <entry>start&nbsp;+&nbsp;16:</entry>
+ <entry>Y'<subscript>20</subscript></entry>
+ <entry>Y'<subscript>21</subscript></entry>
+ <entry>Y'<subscript>22</subscript></entry>
+ <entry>Y'<subscript>23</subscript></entry>
+ </row>
+ <row>
+ <entry>start&nbsp;+&nbsp;20:</entry>
+ <entry>Y'<subscript>30</subscript></entry>
+ <entry>Y'<subscript>31</subscript></entry>
+ <entry>Y'<subscript>32</subscript></entry>
+ <entry>Y'<subscript>33</subscript></entry>
+ </row>
+ <row>
+ <entry>start&nbsp;+&nbsp;24:</entry>
+ <entry>Cb<subscript>10</subscript></entry>
+ <entry>Cr<subscript>10</subscript></entry>
+ <entry>Cb<subscript>11</subscript></entry>
+ <entry>Cr<subscript>11</subscript></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </para>
+ </formalpara>
+
+ <formalpara>
+ <title>Color Sample Location.</title>
+ <para>
+ <informaltable frame="none">
+ <tgroup cols="7" align="center">
+ <tbody valign="top">
+ <row>
+ <entry></entry>
+ <entry>0</entry><entry></entry><entry>1</entry><entry></entry>
+ <entry>2</entry><entry></entry><entry>3</entry>
+ </row>
+ <row>
+ <entry>0</entry>
+ <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+ <entry>Y</entry><entry></entry><entry>Y</entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry><entry>C</entry><entry></entry><entry></entry>
+ <entry></entry><entry>C</entry><entry></entry>
+ </row>
+ <row>
+ <entry>1</entry>
+ <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+ <entry>Y</entry><entry></entry><entry>Y</entry>
+ </row>
+ <row>
+ <entry></entry>
+ </row>
+ <row>
+ <entry>2</entry>
+ <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+ <entry>Y</entry><entry></entry><entry>Y</entry>
+ </row>
+ <row>
+ <entry></entry>
+ <entry></entry><entry>C</entry><entry></entry><entry></entry>
+ <entry></entry><entry>C</entry><entry></entry>
+ </row>
+ <row>
+ <entry>3</entry>
+ <entry>Y</entry><entry></entry><entry>Y</entry><entry></entry>
+ <entry>Y</entry><entry></entry><entry>Y</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </para>
+ </formalpara>
+ </example>
+ </refsect1>
+ </refentry>
+
+ <!--
+Local Variables:
+mode: sgml
+sgml-parent-document: "pixfmt.sgml"
+indent-tabs-mode: nil
+End:
+ -->
diff --git a/Documentation/DocBook/v4l/pixfmt-y10b.xml b/Documentation/DocBook/v4l/pixfmt-y10b.xml
new file mode 100644
index 000000000000..adb0ad808c93
--- /dev/null
+++ b/Documentation/DocBook/v4l/pixfmt-y10b.xml
@@ -0,0 +1,43 @@
+<refentry id="V4L2-PIX-FMT-Y10BPACK">
+ <refmeta>
+ <refentrytitle>V4L2_PIX_FMT_Y10BPACK ('Y10B')</refentrytitle>
+ &manvol;
+ </refmeta>
+ <refnamediv>
+ <refname><constant>V4L2_PIX_FMT_Y10BPACK</constant></refname>
+ <refpurpose>Grey-scale image as a bit-packed array</refpurpose>
+ </refnamediv>
+ <refsect1>
+ <title>Description</title>
+
+ <para>This is a packed grey-scale image format with a depth of 10 bits per
+ pixel. Pixels are stored in a bit-packed array of 10bit bits per pixel,
+ with no padding between them and with the most significant bits coming
+ first from the left.</para>
+
+ <example>
+ <title><constant>V4L2_PIX_FMT_Y10BPACK</constant> 4 pixel data stream taking 5 bytes</title>
+
+ <formalpara>
+ <title>Bit-packed representation</title>
+ <para>pixels cross the byte boundary and have a ratio of 5 bytes for each 4
+ pixels.
+ <informaltable frame="all">
+ <tgroup cols="5" align="center">
+ <colspec align="left" colwidth="2*" />
+ <tbody valign="top">
+ <row>
+ <entry>Y'<subscript>00[9:2]</subscript></entry>
+ <entry>Y'<subscript>00[1:0]</subscript>Y'<subscript>01[9:4]</subscript></entry>
+ <entry>Y'<subscript>01[3:0]</subscript>Y'<subscript>02[9:6]</subscript></entry>
+ <entry>Y'<subscript>02[5:0]</subscript>Y'<subscript>03[9:8]</subscript></entry>
+ <entry>Y'<subscript>03[7:0]</subscript></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </para>
+ </formalpara>
+ </example>
+ </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/v4l/pixfmt.xml b/Documentation/DocBook/v4l/pixfmt.xml
index 40af4beb48b9..deb660207f94 100644
--- a/Documentation/DocBook/v4l/pixfmt.xml
+++ b/Documentation/DocBook/v4l/pixfmt.xml
@@ -673,6 +673,7 @@ access the palette, this must be done with ioctls of the Linux framebuffer API.<
&sub-srggb8;
&sub-sbggr16;
&sub-srggb10;
+ &sub-srggb12;
</section>
<section id="yuv-formats">
@@ -697,6 +698,7 @@ information.</para>
&sub-grey;
&sub-y10;
&sub-y12;
+ &sub-y10b;
&sub-y16;
&sub-yuyv;
&sub-uyvy;
@@ -712,6 +714,7 @@ information.</para>
&sub-nv12m;
&sub-nv12mt;
&sub-nv16;
+ &sub-m420;
</section>
<section>
diff --git a/Documentation/DocBook/v4l/subdev-formats.xml b/Documentation/DocBook/v4l/subdev-formats.xml
index d7ccd25edcc1..8d3409d2c632 100644
--- a/Documentation/DocBook/v4l/subdev-formats.xml
+++ b/Documentation/DocBook/v4l/subdev-formats.xml
@@ -2522,5 +2522,51 @@
</tgroup>
</table>
</section>
+
+ <section>
+ <title>JPEG Compressed Formats</title>
+
+ <para>Those data formats consist of an ordered sequence of 8-bit bytes
+ obtained from JPEG compression process. Additionally to the
+ <constant>_JPEG</constant> prefix the format code is made of
+ the following information.
+ <itemizedlist>
+ <listitem><para>The number of bus samples per entropy encoded byte.</para></listitem>
+ <listitem><para>The bus width.</para></listitem>
+ </itemizedlist>
+ </para>
+
+ <para>For instance, for a JPEG baseline process and an 8-bit bus width
+ the format will be named <constant>V4L2_MBUS_FMT_JPEG_1X8</constant>.
+ </para>
+
+ <para>The following table lists existing JPEG compressed formats.</para>
+
+ <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-jpeg">
+ <title>JPEG Formats</title>
+ <tgroup cols="3">
+ <colspec colname="id" align="left" />
+ <colspec colname="code" align="left"/>
+ <colspec colname="remarks" align="left"/>
+ <thead>
+ <row>
+ <entry>Identifier</entry>
+ <entry>Code</entry>
+ <entry>Remarks</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row id="V4L2-MBUS-FMT-JPEG-1X8">
+ <entry>V4L2_MBUS_FMT_JPEG_1X8</entry>
+ <entry>0x4001</entry>
+ <entry>Besides of its usage for the parallel bus this format is
+ recommended for transmission of JPEG data over MIPI CSI bus
+ using the User Defined 8-bit Data types.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </section>
</section>
</section>
diff --git a/Documentation/DocBook/v4l/videodev2.h.xml b/Documentation/DocBook/v4l/videodev2.h.xml
index 2b796a2ee98a..c50536a4f596 100644
--- a/Documentation/DocBook/v4l/videodev2.h.xml
+++ b/Documentation/DocBook/v4l/videodev2.h.xml
@@ -311,6 +311,9 @@ struct <link linkend="v4l2-pix-format">v4l2_pix_format</link> {
#define <link linkend="V4L2-PIX-FMT-Y10">V4L2_PIX_FMT_Y10</link> v4l2_fourcc('Y', '1', '0', ' ') /* 10 Greyscale */
#define <link linkend="V4L2-PIX-FMT-Y16">V4L2_PIX_FMT_Y16</link> v4l2_fourcc('Y', '1', '6', ' ') /* 16 Greyscale */
+/* Grey bit-packed formats */
+#define <link linkend="V4L2-PIX-FMT-Y10BPACK">V4L2_PIX_FMT_Y10BPACK</link> v4l2_fourcc('Y', '1', '0', 'B') /* 10 Greyscale bit-packed */
+
/* Palette formats */
#define <link linkend="V4L2-PIX-FMT-PAL8">V4L2_PIX_FMT_PAL8</link> v4l2_fourcc('P', 'A', 'L', '8') /* 8 8-bit palette */
@@ -333,6 +336,7 @@ struct <link linkend="v4l2-pix-format">v4l2_pix_format</link> {
#define <link linkend="V4L2-PIX-FMT-YUV420">V4L2_PIX_FMT_YUV420</link> v4l2_fourcc('Y', 'U', '1', '2') /* 12 YUV 4:2:0 */
#define <link linkend="V4L2-PIX-FMT-HI240">V4L2_PIX_FMT_HI240</link> v4l2_fourcc('H', 'I', '2', '4') /* 8 8-bit color */
#define <link linkend="V4L2-PIX-FMT-HM12">V4L2_PIX_FMT_HM12</link> v4l2_fourcc('H', 'M', '1', '2') /* 8 YUV 4:2:0 16x16 macroblocks */
+#define <link linkend="V4L2-PIX-FMT-M420">V4L2_PIX_FMT_M420</link> v4l2_fourcc('M', '4', '2', '0') /* 12 YUV 4:2:0 2 lines y, 1 line uv interleaved */
/* two planes -- one Y, one Cr + Cb interleaved */
#define <link linkend="V4L2-PIX-FMT-NV12">V4L2_PIX_FMT_NV12</link> v4l2_fourcc('N', 'V', '1', '2') /* 12 Y/CbCr 4:2:0 */
diff --git a/Documentation/HOWTO b/Documentation/HOWTO
index 365bda9a0d94..81bc1a9ab9d8 100644
--- a/Documentation/HOWTO
+++ b/Documentation/HOWTO
@@ -209,7 +209,7 @@ tools. One such tool that is particularly recommended is the Linux
Cross-Reference project, which is able to present source code in a
self-referential, indexed webpage format. An excellent up-to-date
repository of the kernel code may be found at:
- http://users.sosdg.org/~qiyong/lxr/
+ http://lxr.linux.no/+trees
The development process
diff --git a/Documentation/IRQ-affinity.txt b/Documentation/IRQ-affinity.txt
index b4a615b78403..7890fae18529 100644
--- a/Documentation/IRQ-affinity.txt
+++ b/Documentation/IRQ-affinity.txt
@@ -4,10 +4,11 @@ ChangeLog:
SMP IRQ affinity
-/proc/irq/IRQ#/smp_affinity specifies which target CPUs are permitted
-for a given IRQ source. It's a bitmask of allowed CPUs. It's not allowed
-to turn off all CPUs, and if an IRQ controller does not support IRQ
-affinity then the value will not change from the default 0xffffffff.
+/proc/irq/IRQ#/smp_affinity and /proc/irq/IRQ#/smp_affinity_list specify
+which target CPUs are permitted for a given IRQ source. It's a bitmask
+(smp_affinity) or cpu list (smp_affinity_list) of allowed CPUs. It's not
+allowed to turn off all CPUs, and if an IRQ controller does not support
+IRQ affinity then the value will not change from the default of all cpus.
/proc/irq/default_smp_affinity specifies default affinity mask that applies
to all non-active IRQs. Once IRQ is allocated/activated its affinity bitmask
@@ -54,3 +55,11 @@ round-trip min/avg/max = 0.1/0.5/585.4 ms
This time around IRQ44 was delivered only to the last four processors.
i.e counters for the CPU0-3 did not change.
+Here is an example of limiting that same irq (44) to cpus 1024 to 1031:
+
+[root@moon 44]# echo 1024-1031 > smp_affinity
+[root@moon 44]# cat smp_affinity
+1024-1031
+
+Note that to do this with a bitmask would require 32 bitmasks of zero
+to follow the pertinent one.
diff --git a/Documentation/RCU/00-INDEX b/Documentation/RCU/00-INDEX
index 71b6f500ddb9..1d7a885761f5 100644
--- a/Documentation/RCU/00-INDEX
+++ b/Documentation/RCU/00-INDEX
@@ -21,7 +21,7 @@ rcu.txt
RTFP.txt
- List of RCU papers (bibliography) going back to 1980.
stallwarn.txt
- - RCU CPU stall warnings (CONFIG_RCU_CPU_STALL_DETECTOR)
+ - RCU CPU stall warnings (module parameter rcu_cpu_stall_suppress)
torture.txt
- RCU Torture Test Operation (CONFIG_RCU_TORTURE_TEST)
trace.txt
diff --git a/Documentation/RCU/stallwarn.txt b/Documentation/RCU/stallwarn.txt
index 862c08ef1fde..4e959208f736 100644
--- a/Documentation/RCU/stallwarn.txt
+++ b/Documentation/RCU/stallwarn.txt
@@ -1,22 +1,25 @@
Using RCU's CPU Stall Detector
-The CONFIG_RCU_CPU_STALL_DETECTOR kernel config parameter enables
-RCU's CPU stall detector, which detects conditions that unduly delay
-RCU grace periods. The stall detector's idea of what constitutes
-"unduly delayed" is controlled by a set of C preprocessor macros:
+The rcu_cpu_stall_suppress module parameter enables RCU's CPU stall
+detector, which detects conditions that unduly delay RCU grace periods.
+This module parameter enables CPU stall detection by default, but
+may be overridden via boot-time parameter or at runtime via sysfs.
+The stall detector's idea of what constitutes "unduly delayed" is
+controlled by a set of kernel configuration variables and cpp macros:
-RCU_SECONDS_TILL_STALL_CHECK
+CONFIG_RCU_CPU_STALL_TIMEOUT
- This macro defines the period of time that RCU will wait from
- the beginning of a grace period until it issues an RCU CPU
- stall warning. This time period is normally ten seconds.
+ This kernel configuration parameter defines the period of time
+ that RCU will wait from the beginning of a grace period until it
+ issues an RCU CPU stall warning. This time period is normally
+ ten seconds.
RCU_SECONDS_TILL_STALL_RECHECK
This macro defines the period of time that RCU will wait after
issuing a stall warning until it issues another stall warning
- for the same stall. This time period is normally set to thirty
- seconds.
+ for the same stall. This time period is normally set to three
+ times the check interval plus thirty seconds.
RCU_STALL_RAT_DELAY
diff --git a/Documentation/RCU/trace.txt b/Documentation/RCU/trace.txt
index 6a8c73f55b80..c078ad48f7a1 100644
--- a/Documentation/RCU/trace.txt
+++ b/Documentation/RCU/trace.txt
@@ -10,34 +10,46 @@ for rcutree and next for rcutiny.
CONFIG_TREE_RCU and CONFIG_TREE_PREEMPT_RCU debugfs Files and Formats
-These implementations of RCU provides five debugfs files under the
-top-level directory RCU: rcu/rcudata (which displays fields in struct
-rcu_data), rcu/rcudata.csv (which is a .csv spreadsheet version of
-rcu/rcudata), rcu/rcugp (which displays grace-period counters),
-rcu/rcuhier (which displays the struct rcu_node hierarchy), and
-rcu/rcu_pending (which displays counts of the reasons that the
-rcu_pending() function decided that there was core RCU work to do).
+These implementations of RCU provides several debugfs files under the
+top-level directory "rcu":
+
+rcu/rcudata:
+ Displays fields in struct rcu_data.
+rcu/rcudata.csv:
+ Comma-separated values spreadsheet version of rcudata.
+rcu/rcugp:
+ Displays grace-period counters.
+rcu/rcuhier:
+ Displays the struct rcu_node hierarchy.
+rcu/rcu_pending:
+ Displays counts of the reasons rcu_pending() decided that RCU had
+ work to do.
+rcu/rcutorture:
+ Displays rcutorture test progress.
+rcu/rcuboost:
+ Displays RCU boosting statistics. Only present if
+ CONFIG_RCU_BOOST=y.
The output of "cat rcu/rcudata" looks as follows:
rcu_sched:
- 0 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=10951/1 dn=0 df=1101 of=0 ri=36 ql=0 b=10
- 1 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=16117/1 dn=0 df=1015 of=0 ri=0 ql=0 b=10
- 2 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=1445/1 dn=0 df=1839 of=0 ri=0 ql=0 b=10
- 3 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=6681/1 dn=0 df=1545 of=0 ri=0 ql=0 b=10
- 4 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=1003/1 dn=0 df=1992 of=0 ri=0 ql=0 b=10
- 5 c=17829 g=17830 pq=1 pqc=17829 qp=1 dt=3887/1 dn=0 df=3331 of=0 ri=4 ql=2 b=10
- 6 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=859/1 dn=0 df=3224 of=0 ri=0 ql=0 b=10
- 7 c=17829 g=17830 pq=0 pqc=17829 qp=1 dt=3761/1 dn=0 df=1818 of=0 ri=0 ql=2 b=10
+ 0 c=20972 g=20973 pq=1 pqc=20972 qp=0 dt=545/1/0 df=50 of=0 ri=0 ql=163 qs=NRW. kt=0/W/0 ktl=ebc3 b=10 ci=153737 co=0 ca=0
+ 1 c=20972 g=20973 pq=1 pqc=20972 qp=0 dt=967/1/0 df=58 of=0 ri=0 ql=634 qs=NRW. kt=0/W/1 ktl=58c b=10 ci=191037 co=0 ca=0
+ 2 c=20972 g=20973 pq=1 pqc=20972 qp=0 dt=1081/1/0 df=175 of=0 ri=0 ql=74 qs=N.W. kt=0/W/2 ktl=da94 b=10 ci=75991 co=0 ca=0
+ 3 c=20942 g=20943 pq=1 pqc=20942 qp=1 dt=1846/0/0 df=404 of=0 ri=0 ql=0 qs=.... kt=0/W/3 ktl=d1cd b=10 ci=72261 co=0 ca=0
+ 4 c=20972 g=20973 pq=1 pqc=20972 qp=0 dt=369/1/0 df=83 of=0 ri=0 ql=48 qs=N.W. kt=0/W/4 ktl=e0e7 b=10 ci=128365 co=0 ca=0
+ 5 c=20972 g=20973 pq=1 pqc=20972 qp=0 dt=381/1/0 df=64 of=0 ri=0 ql=169 qs=NRW. kt=0/W/5 ktl=fb2f b=10 ci=164360 co=0 ca=0
+ 6 c=20972 g=20973 pq=1 pqc=20972 qp=0 dt=1037/1/0 df=183 of=0 ri=0 ql=62 qs=N.W. kt=0/W/6 ktl=d2ad b=10 ci=65663 co=0 ca=0
+ 7 c=20897 g=20897 pq=1 pqc=20896 qp=0 dt=1572/0/0 df=382 of=0 ri=0 ql=0 qs=.... kt=0/W/7 ktl=cf15 b=10 ci=75006 co=0 ca=0
rcu_bh:
- 0 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=10951/1 dn=0 df=0 of=0 ri=0 ql=0 b=10
- 1 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=16117/1 dn=0 df=13 of=0 ri=0 ql=0 b=10
- 2 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=1445/1 dn=0 df=15 of=0 ri=0 ql=0 b=10
- 3 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=6681/1 dn=0 df=9 of=0 ri=0 ql=0 b=10
- 4 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=1003/1 dn=0 df=15 of=0 ri=0 ql=0 b=10
- 5 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=3887/1 dn=0 df=15 of=0 ri=0 ql=0 b=10
- 6 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=859/1 dn=0 df=15 of=0 ri=0 ql=0 b=10
- 7 c=-275 g=-275 pq=1 pqc=-275 qp=0 dt=3761/1 dn=0 df=15 of=0 ri=0 ql=0 b=10
+ 0 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=545/1/0 df=6 of=0 ri=1 ql=0 qs=.... kt=0/W/0 ktl=ebc3 b=10 ci=0 co=0 ca=0
+ 1 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=967/1/0 df=3 of=0 ri=1 ql=0 qs=.... kt=0/W/1 ktl=58c b=10 ci=151 co=0 ca=0
+ 2 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=1081/1/0 df=6 of=0 ri=1 ql=0 qs=.... kt=0/W/2 ktl=da94 b=10 ci=0 co=0 ca=0
+ 3 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=1846/0/0 df=8 of=0 ri=1 ql=0 qs=.... kt=0/W/3 ktl=d1cd b=10 ci=0 co=0 ca=0
+ 4 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=369/1/0 df=6 of=0 ri=1 ql=0 qs=.... kt=0/W/4 ktl=e0e7 b=10 ci=0 co=0 ca=0
+ 5 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=381/1/0 df=4 of=0 ri=1 ql=0 qs=.... kt=0/W/5 ktl=fb2f b=10 ci=0 co=0 ca=0
+ 6 c=1480 g=1480 pq=1 pqc=1479 qp=0 dt=1037/1/0 df=6 of=0 ri=1 ql=0 qs=.... kt=0/W/6 ktl=d2ad b=10 ci=0 co=0 ca=0
+ 7 c=1474 g=1474 pq=1 pqc=1473 qp=0 dt=1572/0/0 df=8 of=0 ri=1 ql=0 qs=.... kt=0/W/7 ktl=cf15 b=10 ci=0 co=0 ca=0
The first section lists the rcu_data structures for rcu_sched, the second
for rcu_bh. Note that CONFIG_TREE_PREEMPT_RCU kernels will have an
@@ -52,17 +64,18 @@ o The number at the beginning of each line is the CPU number.
substantially larger than the number of actual CPUs.
o "c" is the count of grace periods that this CPU believes have
- completed. CPUs in dynticks idle mode may lag quite a ways
- behind, for example, CPU 4 under "rcu_sched" above, which has
- slept through the past 25 RCU grace periods. It is not unusual
- to see CPUs lagging by thousands of grace periods.
+ completed. Offlined CPUs and CPUs in dynticks idle mode may
+ lag quite a ways behind, for example, CPU 6 under "rcu_sched"
+ above, which has been offline through not quite 40,000 RCU grace
+ periods. It is not unusual to see CPUs lagging by thousands of
+ grace periods.
o "g" is the count of grace periods that this CPU believes have
- started. Again, CPUs in dynticks idle mode may lag behind.
- If the "c" and "g" values are equal, this CPU has already
- reported a quiescent state for the last RCU grace period that
- it is aware of, otherwise, the CPU believes that it owes RCU a
- quiescent state.
+ started. Again, offlined CPUs and CPUs in dynticks idle mode
+ may lag behind. If the "c" and "g" values are equal, this CPU
+ has already reported a quiescent state for the last RCU grace
+ period that it is aware of, otherwise, the CPU believes that it
+ owes RCU a quiescent state.
o "pq" indicates that this CPU has passed through a quiescent state
for the current grace period. It is possible for "pq" to be
@@ -81,7 +94,8 @@ o "pqc" indicates which grace period the last-observed quiescent
the next grace period!
o "qp" indicates that RCU still expects a quiescent state from
- this CPU.
+ this CPU. Offlined CPUs and CPUs in dyntick idle mode might
+ well have qp=1, which is OK: RCU is still ignoring them.
o "dt" is the current value of the dyntick counter that is incremented
when entering or leaving dynticks idle state, either by the
@@ -108,7 +122,7 @@ o "df" is the number of times that some other CPU has forced a
o "of" is the number of times that some other CPU has forced a
quiescent state on behalf of this CPU due to this CPU being
- offline. In a perfect world, this might neve happen, but it
+ offline. In a perfect world, this might never happen, but it
turns out that offlining and onlining a CPU can take several grace
periods, and so there is likely to be an extended period of time
when RCU believes that the CPU is online when it really is not.
@@ -125,6 +139,62 @@ o "ql" is the number of RCU callbacks currently residing on
of what state they are in (new, waiting for grace period to
start, waiting for grace period to end, ready to invoke).
+o "qs" gives an indication of the state of the callback queue
+ with four characters:
+
+ "N" Indicates that there are callbacks queued that are not
+ ready to be handled by the next grace period, and thus
+ will be handled by the grace period following the next
+ one.
+
+ "R" Indicates that there are callbacks queued that are
+ ready to be handled by the next grace period.
+
+ "W" Indicates that there are callbacks queued that are
+ waiting on the current grace period.
+
+ "D" Indicates that there are callbacks queued that have
+ already been handled by a prior grace period, and are
+ thus waiting to be invoked. Note that callbacks in
+ the process of being invoked are not counted here.
+ Callbacks in the process of being invoked are those
+ that have been removed from the rcu_data structures
+ queues by rcu_do_batch(), but which have not yet been
+ invoked.
+
+ If there are no callbacks in a given one of the above states,
+ the corresponding character is replaced by ".".
+
+o "kt" is the per-CPU kernel-thread state. The digit preceding
+ the first slash is zero if there is no work pending and 1
+ otherwise. The character between the first pair of slashes is
+ as follows:
+
+ "S" The kernel thread is stopped, in other words, all
+ CPUs corresponding to this rcu_node structure are
+ offline.
+
+ "R" The kernel thread is running.
+
+ "W" The kernel thread is waiting because there is no work
+ for it to do.
+
+ "O" The kernel thread is waiting because it has been
+ forced off of its designated CPU or because its
+ ->cpus_allowed mask permits it to run on other than
+ its designated CPU.
+
+ "Y" The kernel thread is yielding to avoid hogging CPU.
+
+ "?" Unknown value, indicates a bug.
+
+ The number after the final slash is the CPU that the kthread
+ is actually running on.
+
+o "ktl" is the low-order 16 bits (in hexadecimal) of the count of
+ the number of times that this CPU's per-CPU kthread has gone
+ through its loop servicing invoke_rcu_cpu_kthread() requests.
+
o "b" is the batch limit for this CPU. If more than this number
of RCU callbacks is ready to invoke, then the remainder will
be deferred.
@@ -174,14 +244,14 @@ o "gpnum" is the number of grace periods that have started. It is
The output of "cat rcu/rcuhier" looks as follows, with very long lines:
c=6902 g=6903 s=2 jfq=3 j=72c7 nfqs=13142/nfqsng=0(13142) fqlh=6
-1/1 .>. 0:127 ^0
-3/3 .>. 0:35 ^0 0/0 .>. 36:71 ^1 0/0 .>. 72:107 ^2 0/0 .>. 108:127 ^3
-3/3f .>. 0:5 ^0 2/3 .>. 6:11 ^1 0/0 .>. 12:17 ^2 0/0 .>. 18:23 ^3 0/0 .>. 24:29 ^4 0/0 .>. 30:35 ^5 0/0 .>. 36:41 ^0 0/0 .>. 42:47 ^1 0/0 .>. 48:53 ^2 0/0 .>. 54:59 ^3 0/0 .>. 60:65 ^4 0/0 .>. 66:71 ^5 0/0 .>. 72:77 ^0 0/0 .>. 78:83 ^1 0/0 .>. 84:89 ^2 0/0 .>. 90:95 ^3 0/0 .>. 96:101 ^4 0/0 .>. 102:107 ^5 0/0 .>. 108:113 ^0 0/0 .>. 114:119 ^1 0/0 .>. 120:125 ^2 0/0 .>. 126:127 ^3
+1/1 ..>. 0:127 ^0
+3/3 ..>. 0:35 ^0 0/0 ..>. 36:71 ^1 0/0 ..>. 72:107 ^2 0/0 ..>. 108:127 ^3
+3/3f ..>. 0:5 ^0 2/3 ..>. 6:11 ^1 0/0 ..>. 12:17 ^2 0/0 ..>. 18:23 ^3 0/0 ..>. 24:29 ^4 0/0 ..>. 30:35 ^5 0/0 ..>. 36:41 ^0 0/0 ..>. 42:47 ^1 0/0 ..>. 48:53 ^2 0/0 ..>. 54:59 ^3 0/0 ..>. 60:65 ^4 0/0 ..>. 66:71 ^5 0/0 ..>. 72:77 ^0 0/0 ..>. 78:83 ^1 0/0 ..>. 84:89 ^2 0/0 ..>. 90:95 ^3 0/0 ..>. 96:101 ^4 0/0 ..>. 102:107 ^5 0/0 ..>. 108:113 ^0 0/0 ..>. 114:119 ^1 0/0 ..>. 120:125 ^2 0/0 ..>. 126:127 ^3
rcu_bh:
c=-226 g=-226 s=1 jfq=-5701 j=72c7 nfqs=88/nfqsng=0(88) fqlh=0
-0/1 .>. 0:127 ^0
-0/3 .>. 0:35 ^0 0/0 .>. 36:71 ^1 0/0 .>. 72:107 ^2 0/0 .>. 108:127 ^3
-0/3f .>. 0:5 ^0 0/3 .>. 6:11 ^1 0/0 .>. 12:17 ^2 0/0 .>. 18:23 ^3 0/0 .>. 24:29 ^4 0/0 .>. 30:35 ^5 0/0 .>. 36:41 ^0 0/0 .>. 42:47 ^1 0/0 .>. 48:53 ^2 0/0 .>. 54:59 ^3 0/0 .>. 60:65 ^4 0/0 .>. 66:71 ^5 0/0 .>. 72:77 ^0 0/0 .>. 78:83 ^1 0/0 .>. 84:89 ^2 0/0 .>. 90:95 ^3 0/0 .>. 96:101 ^4 0/0 .>. 102:107 ^5 0/0 .>. 108:113 ^0 0/0 .>. 114:119 ^1 0/0 .>. 120:125 ^2 0/0 .>. 126:127 ^3
+0/1 ..>. 0:127 ^0
+0/3 ..>. 0:35 ^0 0/0 ..>. 36:71 ^1 0/0 ..>. 72:107 ^2 0/0 ..>. 108:127 ^3
+0/3f ..>. 0:5 ^0 0/3 ..>. 6:11 ^1 0/0 ..>. 12:17 ^2 0/0 ..>. 18:23 ^3 0/0 ..>. 24:29 ^4 0/0 ..>. 30:35 ^5 0/0 ..>. 36:41 ^0 0/0 ..>. 42:47 ^1 0/0 ..>. 48:53 ^2 0/0 ..>. 54:59 ^3 0/0 ..>. 60:65 ^4 0/0 ..>. 66:71 ^5 0/0 ..>. 72:77 ^0 0/0 ..>. 78:83 ^1 0/0 ..>. 84:89 ^2 0/0 ..>. 90:95 ^3 0/0 ..>. 96:101 ^4 0/0 ..>. 102:107 ^5 0/0 ..>. 108:113 ^0 0/0 ..>. 114:119 ^1 0/0 ..>. 120:125 ^2 0/0 ..>. 126:127 ^3
This is once again split into "rcu_sched" and "rcu_bh" portions,
and CONFIG_TREE_PREEMPT_RCU kernels will again have an additional
@@ -240,13 +310,20 @@ o Each element of the form "1/1 0:127 ^0" represents one struct
current grace period.
o The characters separated by the ">" indicate the state
- of the blocked-tasks lists. A "T" preceding the ">"
+ of the blocked-tasks lists. A "G" preceding the ">"
indicates that at least one task blocked in an RCU
read-side critical section blocks the current grace
- period, while a "." preceding the ">" indicates otherwise.
- The character following the ">" indicates similarly for
- the next grace period. A "T" should appear in this
- field only for rcu-preempt.
+ period, while a "E" preceding the ">" indicates that
+ at least one task blocked in an RCU read-side critical
+ section blocks the current expedited grace period.
+ A "T" character following the ">" indicates that at
+ least one task is blocked within an RCU read-side
+ critical section, regardless of whether any current
+ grace period (expedited or normal) is inconvenienced.
+ A "." character appears if the corresponding condition
+ does not hold, so that "..>." indicates that no tasks
+ are blocked. In contrast, "GE>T" indicates maximal
+ inconvenience from blocked tasks.
o The numbers separated by the ":" are the range of CPUs
served by this struct rcu_node. This can be helpful
@@ -328,6 +405,113 @@ o "nn" is the number of times that this CPU needed nothing. Alert
is due to short-circuit evaluation in rcu_pending().
+The output of "cat rcu/rcutorture" looks as follows:
+
+rcutorture test sequence: 0 (test in progress)
+rcutorture update version number: 615
+
+The first line shows the number of rcutorture tests that have completed
+since boot. If a test is currently running, the "(test in progress)"
+string will appear as shown above. The second line shows the number of
+update cycles that the current test has started, or zero if there is
+no test in progress.
+
+
+The output of "cat rcu/rcuboost" looks as follows:
+
+0:5 tasks=.... kt=W ntb=0 neb=0 nnb=0 j=2f95 bt=300f
+ balk: nt=0 egt=989 bt=0 nb=0 ny=0 nos=16
+6:7 tasks=.... kt=W ntb=0 neb=0 nnb=0 j=2f95 bt=300f
+ balk: nt=0 egt=225 bt=0 nb=0 ny=0 nos=6
+
+This information is output only for rcu_preempt. Each two-line entry
+corresponds to a leaf rcu_node strcuture. The fields are as follows:
+
+o "n:m" is the CPU-number range for the corresponding two-line
+ entry. In the sample output above, the first entry covers
+ CPUs zero through five and the second entry covers CPUs 6
+ and 7.
+
+o "tasks=TNEB" gives the state of the various segments of the
+ rnp->blocked_tasks list:
+
+ "T" This indicates that there are some tasks that blocked
+ while running on one of the corresponding CPUs while
+ in an RCU read-side critical section.
+
+ "N" This indicates that some of the blocked tasks are preventing
+ the current normal (non-expedited) grace period from
+ completing.
+
+ "E" This indicates that some of the blocked tasks are preventing
+ the current expedited grace period from completing.
+
+ "B" This indicates that some of the blocked tasks are in
+ need of RCU priority boosting.
+
+ Each character is replaced with "." if the corresponding
+ condition does not hold.
+
+o "kt" is the state of the RCU priority-boosting kernel
+ thread associated with the corresponding rcu_node structure.
+ The state can be one of the following:
+
+ "S" The kernel thread is stopped, in other words, all
+ CPUs corresponding to this rcu_node structure are
+ offline.
+
+ "R" The kernel thread is running.
+
+ "W" The kernel thread is waiting because there is no work
+ for it to do.
+
+ "Y" The kernel thread is yielding to avoid hogging CPU.
+
+ "?" Unknown value, indicates a bug.
+
+o "ntb" is the number of tasks boosted.
+
+o "neb" is the number of tasks boosted in order to complete an
+ expedited grace period.
+
+o "nnb" is the number of tasks boosted in order to complete a
+ normal (non-expedited) grace period. When boosting a task
+ that was blocking both an expedited and a normal grace period,
+ it is counted against the expedited total above.
+
+o "j" is the low-order 16 bits of the jiffies counter in
+ hexadecimal.
+
+o "bt" is the low-order 16 bits of the value that the jiffies
+ counter will have when we next start boosting, assuming that
+ the current grace period does not end beforehand. This is
+ also in hexadecimal.
+
+o "balk: nt" counts the number of times we didn't boost (in
+ other words, we balked) even though it was time to boost because
+ there were no blocked tasks to boost. This situation occurs
+ when there is one blocked task on one rcu_node structure and
+ none on some other rcu_node structure.
+
+o "egt" counts the number of times we balked because although
+ there were blocked tasks, none of them were blocking the
+ current grace period, whether expedited or otherwise.
+
+o "bt" counts the number of times we balked because boosting
+ had already been initiated for the current grace period.
+
+o "nb" counts the number of times we balked because there
+ was at least one task blocking the current non-expedited grace
+ period that never had blocked. If it is already running, it
+ just won't help to boost its priority!
+
+o "ny" counts the number of times we balked because it was
+ not yet time to start boosting.
+
+o "nos" counts the number of times we balked for other
+ reasons, e.g., the grace period ended first.
+
+
CONFIG_TINY_RCU and CONFIG_TINY_PREEMPT_RCU debugfs Files and Formats
These implementations of RCU provides a single debugfs file under the
@@ -394,9 +578,9 @@ o "neb" is the number of expedited grace periods that have had
o "nnb" is the number of normal grace periods that have had
to resort to RCU priority boosting since boot.
-o "j" is the low-order 12 bits of the jiffies counter in hexadecimal.
+o "j" is the low-order 16 bits of the jiffies counter in hexadecimal.
-o "bt" is the low-order 12 bits of the value that the jiffies counter
+o "bt" is the low-order 16 bits of the value that the jiffies counter
will have at the next time that boosting is scheduled to begin.
o In the line beginning with "normal balk", the fields are as follows:
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index e439cd0d3375..569f3532e138 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -714,10 +714,11 @@ Jeff Garzik, "Linux kernel patch submission format".
<http://linux.yyz.us/patch-format.html>
Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer".
- <http://www.kroah.com/log/2005/03/31/>
- <http://www.kroah.com/log/2005/07/08/>
- <http://www.kroah.com/log/2005/10/19/>
- <http://www.kroah.com/log/2006/01/11/>
+ <http://www.kroah.com/log/linux/maintainer.html>
+ <http://www.kroah.com/log/linux/maintainer-02.html>
+ <http://www.kroah.com/log/linux/maintainer-03.html>
+ <http://www.kroah.com/log/linux/maintainer-04.html>
+ <http://www.kroah.com/log/linux/maintainer-05.html>
NO!!!! No more huge patch bombs to linux-kernel@vger.kernel.org people!
<http://marc.theaimsgroup.com/?l=linux-kernel&m=112112749912944&w=2>
diff --git a/Documentation/accounting/getdelays.c b/Documentation/accounting/getdelays.c
index e9c77788a39d..f6318f6d7baf 100644
--- a/Documentation/accounting/getdelays.c
+++ b/Documentation/accounting/getdelays.c
@@ -177,6 +177,8 @@ static int get_family_id(int sd)
rc = send_cmd(sd, GENL_ID_CTRL, getpid(), CTRL_CMD_GETFAMILY,
CTRL_ATTR_FAMILY_NAME, (void *)name,
strlen(TASKSTATS_GENL_NAME)+1);
+ if (rc < 0)
+ return 0; /* sendto() failure? */
rep_len = recv(sd, &ans, sizeof(ans), 0);
if (ans.n.nlmsg_type == NLMSG_ERROR ||
@@ -191,30 +193,37 @@ static int get_family_id(int sd)
return id;
}
+#define average_ms(t, c) (t / 1000000ULL / (c ? c : 1))
+
static void print_delayacct(struct taskstats *t)
{
- printf("\n\nCPU %15s%15s%15s%15s\n"
- " %15llu%15llu%15llu%15llu\n"
- "IO %15s%15s\n"
- " %15llu%15llu\n"
- "SWAP %15s%15s\n"
- " %15llu%15llu\n"
- "RECLAIM %12s%15s\n"
- " %15llu%15llu\n",
- "count", "real total", "virtual total", "delay total",
+ printf("\n\nCPU %15s%15s%15s%15s%15s\n"
+ " %15llu%15llu%15llu%15llu%15.3fms\n"
+ "IO %15s%15s%15s\n"
+ " %15llu%15llu%15llums\n"
+ "SWAP %15s%15s%15s\n"
+ " %15llu%15llu%15llums\n"
+ "RECLAIM %12s%15s%15s\n"
+ " %15llu%15llu%15llums\n",
+ "count", "real total", "virtual total",
+ "delay total", "delay average",
(unsigned long long)t->cpu_count,
(unsigned long long)t->cpu_run_real_total,
(unsigned long long)t->cpu_run_virtual_total,
(unsigned long long)t->cpu_delay_total,
- "count", "delay total",
+ average_ms((double)t->cpu_delay_total, t->cpu_count),
+ "count", "delay total", "delay average",
(unsigned long long)t->blkio_count,
(unsigned long long)t->blkio_delay_total,
- "count", "delay total",
+ average_ms(t->blkio_delay_total, t->blkio_count),
+ "count", "delay total", "delay average",
(unsigned long long)t->swapin_count,
(unsigned long long)t->swapin_delay_total,
- "count", "delay total",
+ average_ms(t->swapin_delay_total, t->swapin_count),
+ "count", "delay total", "delay average",
(unsigned long long)t->freepages_count,
- (unsigned long long)t->freepages_delay_total);
+ (unsigned long long)t->freepages_delay_total,
+ average_ms(t->freepages_delay_total, t->freepages_count));
}
static void task_context_switch_counts(struct taskstats *t)
@@ -433,8 +442,6 @@ int main(int argc, char *argv[])
}
do {
- int i;
-
rep_len = recv(nl_sd, &msg, sizeof(msg), 0);
PRINTF("received %d bytes\n", rep_len);
@@ -459,7 +466,6 @@ int main(int argc, char *argv[])
na = (struct nlattr *) GENLMSG_DATA(&msg);
len = 0;
- i = 0;
while (len < rep_len) {
len += NLA_ALIGN(na->nla_len);
switch (na->nla_type) {
diff --git a/Documentation/atomic_ops.txt b/Documentation/atomic_ops.txt
index ac4d47187122..3bd585b44927 100644
--- a/Documentation/atomic_ops.txt
+++ b/Documentation/atomic_ops.txt
@@ -12,7 +12,7 @@ Also, it should be made opaque such that any kind of cast to a normal
C integer type will fail. Something like the following should
suffice:
- typedef struct { volatile int counter; } atomic_t;
+ typedef struct { int counter; } atomic_t;
Historically, counter has been declared volatile. This is now discouraged.
See Documentation/volatile-considered-harmful.txt for the complete rationale.
diff --git a/Documentation/blockdev/cciss.txt b/Documentation/blockdev/cciss.txt
index 89698e8df7d4..c00c6a5ab21f 100644
--- a/Documentation/blockdev/cciss.txt
+++ b/Documentation/blockdev/cciss.txt
@@ -169,3 +169,18 @@ is issued which positions the tape to a known position. Typically you
must rewind the tape (by issuing "mt -f /dev/st0 rewind" for example)
before i/o can proceed again to a tape drive which was reset.
+There is a cciss_tape_cmds module parameter which can be used to make cciss
+allocate more commands for use by tape drives. Ordinarily only a few commands
+(6) are allocated for tape drives because tape drives are slow and
+infrequently used and the primary purpose of Smart Array controllers is to
+act as a RAID controller for disk drives, so the vast majority of commands
+are allocated for disk devices. However, if you have more than a few tape
+drives attached to a smart array, the default number of commands may not be
+enought (for example, if you have 8 tape drives, you could only rewind 6
+at one time with the default number of commands.) The cciss_tape_cmds module
+parameter allows more commands (up to 16 more) to be allocated for use by
+tape drives. For example:
+
+ insmod cciss.ko cciss_tape_cmds=16
+
+Or, as a kernel boot parameter passed in via grub: cciss.cciss_tape_cmds=8
diff --git a/Documentation/cachetlb.txt b/Documentation/cachetlb.txt
index 9164ae3b83bc..9b728dc17535 100644
--- a/Documentation/cachetlb.txt
+++ b/Documentation/cachetlb.txt
@@ -16,7 +16,7 @@ on all processors in the system. Don't let this scare you into
thinking SMP cache/tlb flushing must be so inefficient, this is in
fact an area where many optimizations are possible. For example,
if it can be proven that a user address space has never executed
-on a cpu (see vma->cpu_vm_mask), one need not perform a flush
+on a cpu (see mm_cpumask()), one need not perform a flush
for this address space on that cpu.
First, the TLB flushing interfaces, since they are the simplest. The
diff --git a/Documentation/cgroups/cgroups.txt b/Documentation/cgroups/cgroups.txt
index aedf1bd02fdd..0ed99f08f1f3 100644
--- a/Documentation/cgroups/cgroups.txt
+++ b/Documentation/cgroups/cgroups.txt
@@ -236,7 +236,8 @@ containing the following files describing that cgroup:
- cgroup.procs: list of tgids in the cgroup. This list is not
guaranteed to be sorted or free of duplicate tgids, and userspace
should sort/uniquify the list if this property is required.
- This is a read-only file, for now.
+ Writing a thread group id into this file moves all threads in that
+ group into this cgroup.
- notify_on_release flag: run the release agent on exit?
- release_agent: the path to use for release notifications (this file
exists in the top cgroup only)
@@ -430,6 +431,12 @@ You can attach the current shell task by echoing 0:
# echo 0 > tasks
+You can use the cgroup.procs file instead of the tasks file to move all
+threads in a threadgroup at once. Echoing the pid of any task in a
+threadgroup to cgroup.procs causes all tasks in that threadgroup to be
+be attached to the cgroup. Writing 0 to cgroup.procs moves all tasks
+in the writing task's threadgroup.
+
Note: Since every task is always a member of exactly one cgroup in each
mounted hierarchy, to remove a task from its current cgroup you must
move it into a new cgroup (possibly the root cgroup) by writing to the
@@ -575,7 +582,7 @@ rmdir() will fail with it. From this behavior, pre_destroy() can be
called multiple times against a cgroup.
int can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
- struct task_struct *task, bool threadgroup)
+ struct task_struct *task)
(cgroup_mutex held by caller)
Called prior to moving a task into a cgroup; if the subsystem
@@ -584,9 +591,14 @@ task is passed, then a successful result indicates that *any*
unspecified task can be moved into the cgroup. Note that this isn't
called on a fork. If this method returns 0 (success) then this should
remain valid while the caller holds cgroup_mutex and it is ensured that either
-attach() or cancel_attach() will be called in future. If threadgroup is
-true, then a successful result indicates that all threads in the given
-thread's threadgroup can be moved together.
+attach() or cancel_attach() will be called in future.
+
+int can_attach_task(struct cgroup *cgrp, struct task_struct *tsk);
+(cgroup_mutex held by caller)
+
+As can_attach, but for operations that must be run once per task to be
+attached (possibly many when using cgroup_attach_proc). Called after
+can_attach.
void cancel_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
struct task_struct *task, bool threadgroup)
@@ -598,15 +610,24 @@ function, so that the subsystem can implement a rollback. If not, not necessary.
This will be called only about subsystems whose can_attach() operation have
succeeded.
+void pre_attach(struct cgroup *cgrp);
+(cgroup_mutex held by caller)
+
+For any non-per-thread attachment work that needs to happen before
+attach_task. Needed by cpuset.
+
void attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
- struct cgroup *old_cgrp, struct task_struct *task,
- bool threadgroup)
+ struct cgroup *old_cgrp, struct task_struct *task)
(cgroup_mutex held by caller)
Called after the task has been attached to the cgroup, to allow any
post-attachment activity that requires memory allocations or blocking.
-If threadgroup is true, the subsystem should take care of all threads
-in the specified thread's threadgroup. Currently does not support any
+
+void attach_task(struct cgroup *cgrp, struct task_struct *tsk);
+(cgroup_mutex held by caller)
+
+As attach, but for operations that must be run once per task to be attached,
+like can_attach_task. Called before attach. Currently does not support any
subsystem that might need the old_cgrp for every thread in the group.
void fork(struct cgroup_subsy *ss, struct task_struct *task)
@@ -630,7 +651,7 @@ always handled well.
void post_clone(struct cgroup_subsys *ss, struct cgroup *cgrp)
(cgroup_mutex held by caller)
-Called at the end of cgroup_clone() to do any parameter
+Called during cgroup_create() to do any parameter
initialization which might be required before a task could attach. For
example in cpusets, no task may attach before 'cpus' and 'mems' are set
up.
diff --git a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt
new file mode 100644
index 000000000000..bf57ecd5d73a
--- /dev/null
+++ b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt
@@ -0,0 +1,397 @@
+=====================================================================
+SEC 4 Device Tree Binding
+Copyright (C) 2008-2011 Freescale Semiconductor Inc.
+
+ CONTENTS
+ -Overview
+ -SEC 4 Node
+ -Job Ring Node
+ -Run Time Integrity Check (RTIC) Node
+ -Run Time Integrity Check (RTIC) Memory Node
+ -Secure Non-Volatile Storage (SNVS) Node
+ -Full Example
+
+NOTE: the SEC 4 is also known as Freescale's Cryptographic Accelerator
+Accelerator and Assurance Module (CAAM).
+
+=====================================================================
+Overview
+
+DESCRIPTION
+
+SEC 4 h/w can process requests from 2 types of sources.
+1. DPAA Queue Interface (HW interface between Queue Manager & SEC 4).
+2. Job Rings (HW interface between cores & SEC 4 registers).
+
+High Speed Data Path Configuration:
+
+HW interface between QM & SEC 4 and also BM & SEC 4, on DPAA-enabled parts
+such as the P4080. The number of simultaneous dequeues the QI can make is
+equal to the number of Descriptor Controller (DECO) engines in a particular
+SEC version. E.g., the SEC 4.0 in the P4080 has 5 DECOs and can thus
+dequeue from 5 subportals simultaneously.
+
+Job Ring Data Path Configuration:
+
+Each JR is located on a separate 4k page, they may (or may not) be made visible
+in the memory partition devoted to a particular core. The P4080 has 4 JRs, so
+up to 4 JRs can be configured; and all 4 JRs process requests in parallel.
+
+=====================================================================
+SEC 4 Node
+
+Description
+
+ Node defines the base address of the SEC 4 block.
+ This block specifies the address range of all global
+ configuration registers for the SEC 4 block. It
+ also receives interrupts from the Run Time Integrity Check
+ (RTIC) function within the SEC 4 block.
+
+PROPERTIES
+
+ - compatible
+ Usage: required
+ Value type: <string>
+ Definition: Must include "fsl,sec-v4.0"
+
+ - #address-cells
+ Usage: required
+ Value type: <u32>
+ Definition: A standard property. Defines the number of cells
+ for representing physical addresses in child nodes.
+
+ - #size-cells
+ Usage: required
+ Value type: <u32>
+ Definition: A standard property. Defines the number of cells
+ for representing the size of physical addresses in
+ child nodes.
+
+ - reg
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: A standard property. Specifies the physical
+ address and length of the SEC4 configuration registers.
+ registers
+
+ - ranges
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: A standard property. Specifies the physical address
+ range of the SEC 4.0 register space (-SNVS not included). A
+ triplet that includes the child address, parent address, &
+ length.
+
+ - interrupts
+ Usage: required
+ Value type: <prop_encoded-array>
+ Definition: Specifies the interrupts generated by this
+ device. The value of the interrupts property
+ consists of one interrupt specifier. The format
+ of the specifier is defined by the binding document
+ describing the node's interrupt parent.
+
+ - interrupt-parent
+ Usage: (required if interrupt property is defined)
+ Value type: <phandle>
+ Definition: A single <phandle> value that points
+ to the interrupt parent to which the child domain
+ is being mapped.
+
+ Note: All other standard properties (see the ePAPR) are allowed
+ but are optional.
+
+
+EXAMPLE
+ crypto@300000 {
+ compatible = "fsl,sec-v4.0";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x300000 0x10000>;
+ ranges = <0 0x300000 0x10000>;
+ interrupt-parent = <&mpic>;
+ interrupts = <92 2>;
+ };
+
+=====================================================================
+Job Ring (JR) Node
+
+ Child of the crypto node defines data processing interface to SEC 4
+ across the peripheral bus for purposes of processing
+ cryptographic descriptors. The specified address
+ range can be made visible to one (or more) cores.
+ The interrupt defined for this node is controlled within
+ the address range of this node.
+
+ - compatible
+ Usage: required
+ Value type: <string>
+ Definition: Must include "fsl,sec-v4.0-job-ring"
+
+ - reg
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Specifies a two JR parameters: an offset from
+ the parent physical address and the length the JR registers.
+
+ - fsl,liodn
+ Usage: optional-but-recommended
+ Value type: <prop-encoded-array>
+ Definition:
+ Specifies the LIODN to be used in conjunction with
+ the ppid-to-liodn table that specifies the PPID to LIODN mapping.
+ Needed if the PAMU is used. Value is a 12 bit value
+ where value is a LIODN ID for this JR. This property is
+ normally set by boot firmware.
+
+ - interrupts
+ Usage: required
+ Value type: <prop_encoded-array>
+ Definition: Specifies the interrupts generated by this
+ device. The value of the interrupts property
+ consists of one interrupt specifier. The format
+ of the specifier is defined by the binding document
+ describing the node's interrupt parent.
+
+ - interrupt-parent
+ Usage: (required if interrupt property is defined)
+ Value type: <phandle>
+ Definition: A single <phandle> value that points
+ to the interrupt parent to which the child domain
+ is being mapped.
+
+EXAMPLE
+ jr@1000 {
+ compatible = "fsl,sec-v4.0-job-ring";
+ reg = <0x1000 0x1000>;
+ fsl,liodn = <0x081>;
+ interrupt-parent = <&mpic>;
+ interrupts = <88 2>;
+ };
+
+
+=====================================================================
+Run Time Integrity Check (RTIC) Node
+
+ Child node of the crypto node. Defines a register space that
+ contains up to 5 sets of addresses and their lengths (sizes) that
+ will be checked at run time. After an initial hash result is
+ calculated, these addresses are checked by HW to monitor any
+ change. If any memory is modified, a Security Violation is
+ triggered (see SNVS definition).
+
+
+ - compatible
+ Usage: required
+ Value type: <string>
+ Definition: Must include "fsl,sec-v4.0-rtic".
+
+ - #address-cells
+ Usage: required
+ Value type: <u32>
+ Definition: A standard property. Defines the number of cells
+ for representing physical addresses in child nodes. Must
+ have a value of 1.
+
+ - #size-cells
+ Usage: required
+ Value type: <u32>
+ Definition: A standard property. Defines the number of cells
+ for representing the size of physical addresses in
+ child nodes. Must have a value of 1.
+
+ - reg
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: A standard property. Specifies a two parameters:
+ an offset from the parent physical address and the length
+ the SEC4 registers.
+
+ - ranges
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: A standard property. Specifies the physical address
+ range of the SEC 4 register space (-SNVS not included). A
+ triplet that includes the child address, parent address, &
+ length.
+
+EXAMPLE
+ rtic@6000 {
+ compatible = "fsl,sec-v4.0-rtic";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x6000 0x100>;
+ ranges = <0x0 0x6100 0xe00>;
+ };
+
+=====================================================================
+Run Time Integrity Check (RTIC) Memory Node
+ A child node that defines individual RTIC memory regions that are used to
+ perform run-time integrity check of memory areas that should not modified.
+ The node defines a register that contains the memory address &
+ length (combined) and a second register that contains the hash result
+ in big endian format.
+
+ - compatible
+ Usage: required
+ Value type: <string>
+ Definition: Must include "fsl,sec-v4.0-rtic-memory".
+
+ - reg
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: A standard property. Specifies two parameters:
+ an offset from the parent physical address and the length:
+
+ 1. The location of the RTIC memory address & length registers.
+ 2. The location RTIC hash result.
+
+ - fsl,rtic-region
+ Usage: optional-but-recommended
+ Value type: <prop-encoded-array>
+ Definition:
+ Specifies the HW address (36 bit address) for this region
+ followed by the length of the HW partition to be checked;
+ the address is represented as a 64 bit quantity followed
+ by a 32 bit length.
+
+ - fsl,liodn
+ Usage: optional-but-recommended
+ Value type: <prop-encoded-array>
+ Definition:
+ Specifies the LIODN to be used in conjunction with
+ the ppid-to-liodn table that specifies the PPID to LIODN
+ mapping. Needed if the PAMU is used. Value is a 12 bit value
+ where value is a LIODN ID for this RTIC memory region. This
+ property is normally set by boot firmware.
+
+EXAMPLE
+ rtic-a@0 {
+ compatible = "fsl,sec-v4.0-rtic-memory";
+ reg = <0x00 0x20 0x100 0x80>;
+ fsl,liodn = <0x03c>;
+ fsl,rtic-region = <0x12345678 0x12345678 0x12345678>;
+ };
+
+=====================================================================
+Secure Non-Volatile Storage (SNVS) Node
+
+ Node defines address range and the associated
+ interrupt for the SNVS function. This function
+ monitors security state information & reports
+ security violations.
+
+ - compatible
+ Usage: required
+ Value type: <string>
+ Definition: Must include "fsl,sec-v4.0-mon".
+
+ - reg
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: A standard property. Specifies the physical
+ address and length of the SEC4 configuration
+ registers.
+
+ - interrupts
+ Usage: required
+ Value type: <prop_encoded-array>
+ Definition: Specifies the interrupts generated by this
+ device. The value of the interrupts property
+ consists of one interrupt specifier. The format
+ of the specifier is defined by the binding document
+ describing the node's interrupt parent.
+
+ - interrupt-parent
+ Usage: (required if interrupt property is defined)
+ Value type: <phandle>
+ Definition: A single <phandle> value that points
+ to the interrupt parent to which the child domain
+ is being mapped.
+
+EXAMPLE
+ sec_mon@314000 {
+ compatible = "fsl,sec-v4.0-mon";
+ reg = <0x314000 0x1000>;
+ interrupt-parent = <&mpic>;
+ interrupts = <93 2>;
+ };
+
+=====================================================================
+FULL EXAMPLE
+
+ crypto: crypto@300000 {
+ compatible = "fsl,sec-v4.0";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x300000 0x10000>;
+ ranges = <0 0x300000 0x10000>;
+ interrupt-parent = <&mpic>;
+ interrupts = <92 2>;
+
+ sec_jr0: jr@1000 {
+ compatible = "fsl,sec-v4.0-job-ring";
+ reg = <0x1000 0x1000>;
+ interrupt-parent = <&mpic>;
+ interrupts = <88 2>;
+ };
+
+ sec_jr1: jr@2000 {
+ compatible = "fsl,sec-v4.0-job-ring";
+ reg = <0x2000 0x1000>;
+ interrupt-parent = <&mpic>;
+ interrupts = <89 2>;
+ };
+
+ sec_jr2: jr@3000 {
+ compatible = "fsl,sec-v4.0-job-ring";
+ reg = <0x3000 0x1000>;
+ interrupt-parent = <&mpic>;
+ interrupts = <90 2>;
+ };
+
+ sec_jr3: jr@4000 {
+ compatible = "fsl,sec-v4.0-job-ring";
+ reg = <0x4000 0x1000>;
+ interrupt-parent = <&mpic>;
+ interrupts = <91 2>;
+ };
+
+ rtic@6000 {
+ compatible = "fsl,sec-v4.0-rtic";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x6000 0x100>;
+ ranges = <0x0 0x6100 0xe00>;
+
+ rtic_a: rtic-a@0 {
+ compatible = "fsl,sec-v4.0-rtic-memory";
+ reg = <0x00 0x20 0x100 0x80>;
+ };
+
+ rtic_b: rtic-b@20 {
+ compatible = "fsl,sec-v4.0-rtic-memory";
+ reg = <0x20 0x20 0x200 0x80>;
+ };
+
+ rtic_c: rtic-c@40 {
+ compatible = "fsl,sec-v4.0-rtic-memory";
+ reg = <0x40 0x20 0x300 0x80>;
+ };
+
+ rtic_d: rtic-d@60 {
+ compatible = "fsl,sec-v4.0-rtic-memory";
+ reg = <0x60 0x20 0x500 0x80>;
+ };
+ };
+ };
+
+ sec_mon: sec_mon@314000 {
+ compatible = "fsl,sec-v4.0-mon";
+ reg = <0x314000 0x1000>;
+ interrupt-parent = <&mpic>;
+ interrupts = <93 2>;
+ };
+
+=====================================================================
diff --git a/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
new file mode 100755
index 000000000000..1a729f089866
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/can/fsl-flexcan.txt
@@ -0,0 +1,61 @@
+CAN Device Tree Bindings
+------------------------
+2011 Freescale Semiconductor, Inc.
+
+fsl,flexcan-v1.0 nodes
+-----------------------
+In addition to the required compatible-, reg- and interrupt-properties, you can
+also specify which clock source shall be used for the controller.
+
+CPI Clock- Can Protocol Interface Clock
+ This CLK_SRC bit of CTRL(control register) selects the clock source to
+ the CAN Protocol Interface(CPI) to be either the peripheral clock
+ (driven by the PLL) or the crystal oscillator clock. The selected clock
+ is the one fed to the prescaler to generate the Serial Clock (Sclock).
+ The PRESDIV field of CTRL(control register) controls a prescaler that
+ generates the Serial Clock (Sclock), whose period defines the
+ time quantum used to compose the CAN waveform.
+
+Can Engine Clock Source
+ There are two sources for CAN clock
+ - Platform Clock It represents the bus clock
+ - Oscillator Clock
+
+ Peripheral Clock (PLL)
+ --------------
+ |
+ --------- -------------
+ | |CPI Clock | Prescaler | Sclock
+ | |---------------->| (1.. 256) |------------>
+ --------- -------------
+ | |
+ -------------- ---------------------CLK_SRC
+ Oscillator Clock
+
+- fsl,flexcan-clock-source : CAN Engine Clock Source.This property selects
+ the peripheral clock. PLL clock is fed to the
+ prescaler to generate the Serial Clock (Sclock).
+ Valid values are "oscillator" and "platform"
+ "oscillator": CAN engine clock source is oscillator clock.
+ "platform" The CAN engine clock source is the bus clock
+ (platform clock).
+
+- fsl,flexcan-clock-divider : for the reference and system clock, an additional
+ clock divider can be specified.
+- clock-frequency: frequency required to calculate the bitrate for FlexCAN.
+
+Note:
+ - v1.0 of flexcan-v1.0 represent the IP block version for P1010 SOC.
+ - P1010 does not have oscillator as the Clock Source.So the default
+ Clock Source is platform clock.
+Examples:
+
+ can0@1c000 {
+ compatible = "fsl,flexcan-v1.0";
+ reg = <0x1c000 0x1000>;
+ interrupts = <48 0x2>;
+ interrupt-parent = <&mpic>;
+ fsl,flexcan-clock-source = "platform";
+ fsl,flexcan-clock-divider = <2>;
+ clock-frequency = <fixed by u-boot>;
+ };
diff --git a/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt b/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
index edb7ae19e868..2c6be0377f55 100644
--- a/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
+++ b/Documentation/devicetree/bindings/net/fsl-tsec-phy.txt
@@ -74,3 +74,57 @@ Example:
interrupt-parent = <&mpic>;
phy-handle = <&phy0>
};
+
+* Gianfar PTP clock nodes
+
+General Properties:
+
+ - compatible Should be "fsl,etsec-ptp"
+ - reg Offset and length of the register set for the device
+ - interrupts There should be at least two interrupts. Some devices
+ have as many as four PTP related interrupts.
+
+Clock Properties:
+
+ - fsl,tclk-period Timer reference clock period in nanoseconds.
+ - fsl,tmr-prsc Prescaler, divides the output clock.
+ - fsl,tmr-add Frequency compensation value.
+ - fsl,tmr-fiper1 Fixed interval period pulse generator.
+ - fsl,tmr-fiper2 Fixed interval period pulse generator.
+ - fsl,max-adj Maximum frequency adjustment in parts per billion.
+
+ These properties set the operational parameters for the PTP
+ clock. You must choose these carefully for the clock to work right.
+ Here is how to figure good values:
+
+ TimerOsc = system clock MHz
+ tclk_period = desired clock period nanoseconds
+ NominalFreq = 1000 / tclk_period MHz
+ FreqDivRatio = TimerOsc / NominalFreq (must be greater that 1.0)
+ tmr_add = ceil(2^32 / FreqDivRatio)
+ OutputClock = NominalFreq / tmr_prsc MHz
+ PulseWidth = 1 / OutputClock microseconds
+ FiperFreq1 = desired frequency in Hz
+ FiperDiv1 = 1000000 * OutputClock / FiperFreq1
+ tmr_fiper1 = tmr_prsc * tclk_period * FiperDiv1 - tclk_period
+ max_adj = 1000000000 * (FreqDivRatio - 1.0) - 1
+
+ The calculation for tmr_fiper2 is the same as for tmr_fiper1. The
+ driver expects that tmr_fiper1 will be correctly set to produce a 1
+ Pulse Per Second (PPS) signal, since this will be offered to the PPS
+ subsystem to synchronize the Linux clock.
+
+Example:
+
+ ptp_clock@24E00 {
+ compatible = "fsl,etsec-ptp";
+ reg = <0x24E00 0xB0>;
+ interrupts = <12 0x8 13 0x8>;
+ interrupt-parent = < &ipic >;
+ fsl,tclk-period = <10>;
+ fsl,tmr-prsc = <100>;
+ fsl,tmr-add = <0x999999A4>;
+ fsl,tmr-fiper1 = <0x3B9AC9F6>;
+ fsl,tmr-fiper2 = <0x00018696>;
+ fsl,max-adj = <659999998>;
+ };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt b/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt
new file mode 100644
index 000000000000..939a26d541f6
--- /dev/null
+++ b/Documentation/devicetree/bindings/powerpc/fsl/ifc.txt
@@ -0,0 +1,76 @@
+Integrated Flash Controller
+
+Properties:
+- name : Should be ifc
+- compatible : should contain "fsl,ifc". The version of the integrated
+ flash controller can be found in the IFC_REV register at
+ offset zero.
+
+- #address-cells : Should be either two or three. The first cell is the
+ chipselect number, and the remaining cells are the
+ offset into the chipselect.
+- #size-cells : Either one or two, depending on how large each chipselect
+ can be.
+- reg : Offset and length of the register set for the device
+- interrupts : IFC has two interrupts. The first one is the "common"
+ interrupt(CM_EVTER_STAT), and second is the NAND interrupt
+ (NAND_EVTER_STAT).
+
+- ranges : Each range corresponds to a single chipselect, and covers
+ the entire access window as configured.
+
+Child device nodes describe the devices connected to IFC such as NOR (e.g.
+cfi-flash) and NAND (fsl,ifc-nand). There might be board specific devices
+like FPGAs, CPLDs, etc.
+
+Example:
+
+ ifc@ffe1e000 {
+ compatible = "fsl,ifc", "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ reg = <0x0 0xffe1e000 0 0x2000>;
+ interrupts = <16 2 19 2>;
+
+ /* NOR, NAND Flashes and CPLD on board */
+ ranges = <0x0 0x0 0x0 0xee000000 0x02000000
+ 0x1 0x0 0x0 0xffa00000 0x00010000
+ 0x3 0x0 0x0 0xffb00000 0x00020000>;
+
+ flash@0,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "cfi-flash";
+ reg = <0x0 0x0 0x2000000>;
+ bank-width = <2>;
+ device-width = <1>;
+
+ partition@0 {
+ /* 32MB for user data */
+ reg = <0x0 0x02000000>;
+ label = "NOR Data";
+ };
+ };
+
+ flash@1,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,ifc-nand";
+ reg = <0x1 0x0 0x10000>;
+
+ partition@0 {
+ /* This location must not be altered */
+ /* 1MB for u-boot Bootloader Image */
+ reg = <0x0 0x00100000>;
+ label = "NAND U-Boot Image";
+ read-only;
+ };
+ };
+
+ cpld@3,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,p1010rdb-cpld";
+ reg = <0x3 0x0 0x000001f>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mpic-timer.txt b/Documentation/devicetree/bindings/powerpc/fsl/mpic-timer.txt
new file mode 100644
index 000000000000..df41958140e8
--- /dev/null
+++ b/Documentation/devicetree/bindings/powerpc/fsl/mpic-timer.txt
@@ -0,0 +1,38 @@
+* Freescale MPIC timers
+
+Required properties:
+- compatible: "fsl,mpic-global-timer"
+
+- reg : Contains two regions. The first is the main timer register bank
+ (GTCCRxx, GTBCRxx, GTVPRxx, GTDRxx). The second is the timer control
+ register (TCRx) for the group.
+
+- fsl,available-ranges: use <start count> style section to define which
+ timer interrupts can be used. This property is optional; without this,
+ all timers within the group can be used.
+
+- interrupts: one interrupt per timer in the group, in order, starting
+ with timer zero. If timer-available-ranges is present, only the
+ interrupts that correspond to available timers shall be present.
+
+Example:
+ /* Note that this requires #interrupt-cells to be 4 */
+ timer0: timer@41100 {
+ compatible = "fsl,mpic-global-timer";
+ reg = <0x41100 0x100 0x41300 4>;
+
+ /* Another AMP partition is using timers 0 and 1 */
+ fsl,available-ranges = <2 2>;
+
+ interrupts = <2 0 3 0
+ 3 0 3 0>;
+ };
+
+ timer1: timer@42100 {
+ compatible = "fsl,mpic-global-timer";
+ reg = <0x42100 0x100 0x42300 4>;
+ interrupts = <4 0 3 0
+ 5 0 3 0
+ 6 0 3 0
+ 7 0 3 0>;
+ };
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt b/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt
index 4f6145859aab..2cf38bd841fd 100644
--- a/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt
+++ b/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt
@@ -190,7 +190,7 @@ EXAMPLE 4
*/
timer0: timer@41100 {
compatible = "fsl,mpic-global-timer";
- reg = <0x41100 0x100>;
+ reg = <0x41100 0x100 0x41300 4>;
interrupts = <0 0 3 0
1 0 3 0
2 0 3 0
diff --git a/Documentation/devicetree/bindings/powerpc/nintendo/wii.txt b/Documentation/devicetree/bindings/powerpc/nintendo/wii.txt
index a7e155a023b8..36afa322b04b 100644
--- a/Documentation/devicetree/bindings/powerpc/nintendo/wii.txt
+++ b/Documentation/devicetree/bindings/powerpc/nintendo/wii.txt
@@ -127,7 +127,7 @@ Nintendo Wii device tree
- reg : should contain the SDHCI registers location and length
- interrupts : should contain the SDHCI interrupt
-1.j) The Inter-Processsor Communication (IPC) node
+1.j) The Inter-Processor Communication (IPC) node
Represent the Inter-Processor Communication interface. This interface
enables communications between the Broadway and the Starlet processors.
diff --git a/Documentation/dontdiff b/Documentation/dontdiff
index 470d3dba1a69..dfa6fc6e4b28 100644
--- a/Documentation/dontdiff
+++ b/Documentation/dontdiff
@@ -1,6 +1,8 @@
*.a
*.aux
*.bin
+*.bz2
+*.cis
*.cpio
*.csp
*.dsp
@@ -8,6 +10,8 @@
*.elf
*.eps
*.fw
+*.gcno
+*.gcov
*.gen.S
*.gif
*.grep
@@ -19,14 +23,20 @@
*.ko
*.log
*.lst
+*.lzma
+*.lzo
+*.mo
*.moc
*.mod.c
*.o
*.o.*
+*.order
*.orig
*.out
+*.patch
*.pdf
*.png
+*.pot
*.ps
*.rej
*.s
@@ -39,16 +49,22 @@
*.tex
*.ver
*.xml
+*.xz
*_MODULES
*_vga16.c
*~
+\#*#
*.9
-*.9.gz
.*
+.*.d
.mm
53c700_d.h
CVS
ChangeSet
+GPATH
+GRTAGS
+GSYMS
+GTAGS
Image
Kerntypes
Module.markers
@@ -57,15 +73,14 @@ PENDING
SCCS
System.map*
TAGS
+aconf
+af_names.h
aic7*reg.h*
aic7*reg_print.c*
aic7*seq.h*
aicasm
aicdb.h*
-altivec1.c
-altivec2.c
-altivec4.c
-altivec8.c
+altivec*.c
asm-offsets.h
asm_offsets.h
autoconf.h*
@@ -80,6 +95,7 @@ btfixupprep
build
bvmlinux
bzImage*
+capability_names.h
capflags.c
classlist.h*
comp*.log
@@ -88,7 +104,8 @@ conf
config
config-*
config_data.h*
-config_data.gz*
+config.mak
+config.mak.autogen
conmakehash
consolemap_deftbl.c*
cpustr.h
@@ -96,7 +113,9 @@ crc32table.h*
cscope.*
defkeymap.c
devlist.h*
+dnotify_test
docproc
+dslm
elf2ecoff
elfconfig.h*
evergreen_reg_safe.h
@@ -105,6 +124,7 @@ flask.h
fore200e_mkfirm
fore200e_pca_fw.c*
gconf
+gconf.glade.h
gen-devlist
gen_crc32table
gen_init_cpio
@@ -112,11 +132,12 @@ generated
genheaders
genksyms
*_gray256.c
+hpet_example
+hugepage-mmap
+hugepage-shm
ihex2fw
ikconfig.h*
inat-tables.c
-initramfs_data.cpio
-initramfs_data.cpio.gz
initramfs_list
int16.c
int1.c
@@ -133,15 +154,19 @@ kxgettext
lkc_defs.h
lex.c
lex.*.c
+linux
logo_*.c
logo_*_clut224.c
logo_*_mono.c
lxdialog
+mach
mach-types
mach-types.h
machtypes.h
map
+map_hugetlb
maui_boot.h
+media
mconf
miboot*
mk_elfconfig
@@ -150,23 +175,29 @@ mkbugboot
mkcpustr
mkdep
mkprep
+mkregtable
mktables
mktree
modpost
modules.builtin
modules.order
modversions.h*
+nconf
ncscope.*
offset.h
offsets.h
oui.c*
+page-types
parse.c
parse.h
patches*
pca200e.bin
pca200e_ecd.bin2
-piggy.gz
+perf.data
+perf.data.old
+perf-archive
piggyback
+piggy.gzip
piggy.S
pnmtologo
ppc_defs.h*
@@ -177,10 +208,9 @@ r200_reg_safe.h
r300_reg_safe.h
r420_reg_safe.h
r600_reg_safe.h
-raid6altivec*.c
-raid6int*.c
-raid6tables.c
+recordmcount
relocs
+rlim_names.h
rn50_reg_safe.h
rs600_reg_safe.h
rv515_reg_safe.h
@@ -194,6 +224,7 @@ split-include
syscalltab.h
tables.c
tags
+test_get_len
tftpboot.img
timeconst.h
times.h*
@@ -210,10 +241,13 @@ vdso32.so.dbg
vdso64.lds
vdso64.so.dbg
version.h*
+vmImage
vmlinux
vmlinux-*
vmlinux.aout
+vmlinux.bin.all
vmlinux.lds
+vmlinuz
voffset.h
vsyscall.lds
vsyscall_32.lds
diff --git a/Documentation/driver-model/bus.txt b/Documentation/driver-model/bus.txt
index 5001b7511626..6754b2df8aa1 100644
--- a/Documentation/driver-model/bus.txt
+++ b/Documentation/driver-model/bus.txt
@@ -3,24 +3,7 @@ Bus Types
Definition
~~~~~~~~~~
-
-struct bus_type {
- char * name;
-
- struct subsystem subsys;
- struct kset drivers;
- struct kset devices;
-
- struct bus_attribute * bus_attrs;
- struct device_attribute * dev_attrs;
- struct driver_attribute * drv_attrs;
-
- int (*match)(struct device * dev, struct device_driver * drv);
- int (*hotplug) (struct device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size);
- int (*suspend)(struct device * dev, pm_message_t state);
- int (*resume)(struct device * dev);
-};
+See the kerneldoc for the struct bus_type.
int bus_register(struct bus_type * bus);
diff --git a/Documentation/driver-model/class.txt b/Documentation/driver-model/class.txt
index 548505f14aa4..1fefc480a80b 100644
--- a/Documentation/driver-model/class.txt
+++ b/Documentation/driver-model/class.txt
@@ -27,22 +27,7 @@ The device class structure looks like:
typedef int (*devclass_add)(struct device *);
typedef void (*devclass_remove)(struct device *);
-struct device_class {
- char * name;
- rwlock_t lock;
- u32 devnum;
- struct list_head node;
-
- struct list_head drivers;
- struct list_head intf_list;
-
- struct driver_dir_entry dir;
- struct driver_dir_entry device_dir;
- struct driver_dir_entry driver_dir;
-
- devclass_add add_device;
- devclass_remove remove_device;
-};
+See the kerneldoc for the struct class.
A typical device class definition would look like:
diff --git a/Documentation/driver-model/device.txt b/Documentation/driver-model/device.txt
index a124f3126b0d..b2ff42685bcb 100644
--- a/Documentation/driver-model/device.txt
+++ b/Documentation/driver-model/device.txt
@@ -2,96 +2,7 @@
The Basic Device Structure
~~~~~~~~~~~~~~~~~~~~~~~~~~
-struct device {
- struct list_head g_list;
- struct list_head node;
- struct list_head bus_list;
- struct list_head driver_list;
- struct list_head intf_list;
- struct list_head children;
- struct device * parent;
-
- char name[DEVICE_NAME_SIZE];
- char bus_id[BUS_ID_SIZE];
-
- spinlock_t lock;
- atomic_t refcount;
-
- struct bus_type * bus;
- struct driver_dir_entry dir;
-
- u32 class_num;
-
- struct device_driver *driver;
- void *driver_data;
- void *platform_data;
-
- u32 current_state;
- unsigned char *saved_state;
-
- void (*release)(struct device * dev);
-};
-
-Fields
-~~~~~~
-g_list: Node in the global device list.
-
-node: Node in device's parent's children list.
-
-bus_list: Node in device's bus's devices list.
-
-driver_list: Node in device's driver's devices list.
-
-intf_list: List of intf_data. There is one structure allocated for
- each interface that the device supports.
-
-children: List of child devices.
-
-parent: *** FIXME ***
-
-name: ASCII description of device.
- Example: " 3Com Corporation 3c905 100BaseTX [Boomerang]"
-
-bus_id: ASCII representation of device's bus position. This
- field should be a name unique across all devices on the
- bus type the device belongs to.
-
- Example: PCI bus_ids are in the form of
- <bus number>:<slot number>.<function number>
- This name is unique across all PCI devices in the system.
-
-lock: Spinlock for the device.
-
-refcount: Reference count on the device.
-
-bus: Pointer to struct bus_type that device belongs to.
-
-dir: Device's sysfs directory.
-
-class_num: Class-enumerated value of the device.
-
-driver: Pointer to struct device_driver that controls the device.
-
-driver_data: Driver-specific data.
-
-platform_data: Platform data specific to the device.
-
- Example: for devices on custom boards, as typical of embedded
- and SOC based hardware, Linux often uses platform_data to point
- to board-specific structures describing devices and how they
- are wired. That can include what ports are available, chip
- variants, which GPIO pins act in what additional roles, and so
- on. This shrinks the "Board Support Packages" (BSPs) and
- minimizes board-specific #ifdefs in drivers.
-
-current_state: Current power state of the device.
-
-saved_state: Pointer to saved state of the device. This is usable by
- the device driver controlling the device.
-
-release: Callback to free the device after all references have
- gone away. This should be set by the allocator of the
- device (i.e. the bus driver that discovered the device).
+See the kerneldoc for the struct device.
Programming Interface
diff --git a/Documentation/driver-model/driver.txt b/Documentation/driver-model/driver.txt
index d2cd6fb8ba9e..4421135826a2 100644
--- a/Documentation/driver-model/driver.txt
+++ b/Documentation/driver-model/driver.txt
@@ -1,23 +1,7 @@
Device Drivers
-struct device_driver {
- char * name;
- struct bus_type * bus;
-
- struct completion unloaded;
- struct kobject kobj;
- list_t devices;
-
- struct module *owner;
-
- int (*probe) (struct device * dev);
- int (*remove) (struct device * dev);
-
- int (*suspend) (struct device * dev, pm_message_t state);
- int (*resume) (struct device * dev);
-};
-
+See the kerneldoc for the struct device_driver.
Allocation
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 492e81df2968..ff31b1cc50aa 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -35,17 +35,6 @@ Who: Luis R. Rodriguez <lrodriguez@atheros.com>
---------------------------
-What: AR9170USB
-When: 2.6.40
-
-Why: This driver is deprecated and the firmware is no longer
- maintained. The replacement driver "carl9170" has been
- around for a while, so the devices are still supported.
-
-Who: Christian Lamparter <chunkeey@googlemail.com>
-
----------------------------
-
What: IRQF_SAMPLE_RANDOM
Check: IRQF_SAMPLE_RANDOM
When: July 2009
@@ -226,7 +215,7 @@ Who: Zhang Rui <rui.zhang@intel.com>
What: CONFIG_ACPI_PROCFS_POWER
When: 2.6.39
Why: sysfs I/F for ACPI power devices, including AC and Battery,
- has been working in upstream kenrel since 2.6.24, Sep 2007.
+ has been working in upstream kernel since 2.6.24, Sep 2007.
In 2.6.37, we make the sysfs I/F always built in and this option
disabled by default.
Remove this option and the ACPI power procfs interface in 2.6.39.
@@ -273,16 +262,6 @@ Who: Michael Buesch <mb@bu3sch.de>
---------------------------
-What: /sys/o2cb symlink
-When: January 2010
-Why: /sys/fs/o2cb is the proper location for this information - /sys/o2cb
- exists as a symlink for backwards compatibility for old versions of
- ocfs2-tools. 2 years should be sufficient time to phase in new versions
- which know to look in /sys/fs/o2cb.
-Who: ocfs2-devel@oss.oracle.com
-
----------------------------
-
What: Ability for non root users to shm_get hugetlb pages based on mlock
resource limits
When: 2.6.31
@@ -405,16 +384,6 @@ Who: anybody or Florian Mickler <florian@mickler.org>
----------------------------
-What: capifs
-When: February 2011
-Files: drivers/isdn/capi/capifs.*
-Why: udev fully replaces this special file system that only contains CAPI
- NCCI TTY device nodes. User space (pppdcapiplugin) works without
- noticing the difference.
-Who: Jan Kiszka <jan.kiszka@web.de>
-
-----------------------------
-
What: KVM paravirt mmu host support
When: January 2011
Why: The paravirt mmu host support is slower than non-paravirt mmu, both
@@ -460,14 +429,6 @@ Who: Thomas Gleixner <tglx@linutronix.de>
----------------------------
-What: The acpi_sleep=s4_nonvs command line option
-When: 2.6.37
-Files: arch/x86/kernel/acpi/sleep.c
-Why: superseded by acpi_sleep=nonvs
-Who: Rafael J. Wysocki <rjw@sisk.pl>
-
-----------------------------
-
What: PCI DMA unmap state API
When: August 2012
Why: PCI DMA unmap state API (include/linux/pci-dma.h) was replaced
@@ -580,3 +541,26 @@ Why: These legacy callbacks should no longer be used as i2c-core offers
Who: Jean Delvare <khali@linux-fr.org>
----------------------------
+
+What: Support for UVCIOC_CTRL_ADD in the uvcvideo driver
+When: 2.6.42
+Why: The information passed to the driver by this ioctl is now queried
+ dynamically from the device.
+Who: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+
+----------------------------
+
+What: Support for UVCIOC_CTRL_MAP_OLD in the uvcvideo driver
+When: 2.6.42
+Why: Used only by applications compiled against older driver versions.
+ Superseded by UVCIOC_CTRL_MAP which supports V4L2 menu controls.
+Who: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+
+----------------------------
+
+What: Support for UVCIOC_CTRL_GET and UVCIOC_CTRL_SET in the uvcvideo driver
+When: 2.6.42
+Why: Superseded by the UVCIOC_CTRL_QUERY ioctl.
+Who: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+
+----------------------------
diff --git a/Documentation/filesystems/9p.txt b/Documentation/filesystems/9p.txt
index b22abba78fed..13de64c7f0ab 100644
--- a/Documentation/filesystems/9p.txt
+++ b/Documentation/filesystems/9p.txt
@@ -25,6 +25,8 @@ Other applications are described in the following papers:
http://xcpu.org/papers/cellfs-talk.pdf
* PROSE I/O: Using 9p to enable Application Partitions
http://plan9.escet.urjc.es/iwp9/cready/PROSE_iwp9_2006.pdf
+ * VirtFS: A Virtualization Aware File System pass-through
+ http://goo.gl/3WPDg
USAGE
=====
@@ -130,31 +132,20 @@ OPTIONS
RESOURCES
=========
-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*'
+Protocol specifications are maintained on github:
+http://ericvh.github.com/9p-rfc/
-The -A specifies an unauthenticated export. The 564 is the port # (you may
-have to choose a higher port number if running as a normal user). The '#U*'
-specifies exporting the root of the Linux name space. You may specify a
-subset of the namespace by extending the path: '#U*'/tmp would just export
-/tmp. For more information, see the Inferno manual pages covering styxlisten
-and export.
+9p client and server implementations are listed on
+http://9p.cat-v.org/implementations
-A Linux version of the 9p server is now maintained under the npfs project
-on sourceforge (http://sourceforge.net/projects/npfs). The currently
-maintained version is the single-threaded version of the server (named spfs)
-available from the same SVN repository.
+A 9p2000.L server is being developed by LLNL and can be found
+at http://code.google.com/p/diod/
There are user and developer mailing lists available through the v9fs project
on sourceforge (http://sourceforge.net/projects/v9fs).
-A stand-alone version of the module (which should build for any 2.6 kernel)
-is available via (http://github.com/ericvh/9p-sac/tree/master)
-
-News and other information is maintained on SWiK (http://swik.net/v9fs)
-and the Wiki (http://sf.net/apps/mediawiki/v9fs/index.php).
+News and other information is maintained on a Wiki.
+(http://sf.net/apps/mediawiki/v9fs/index.php).
Bug reports may be issued through the kernel.org bugzilla
(http://bugzilla.kernel.org)
diff --git a/Documentation/filesystems/configfs/configfs_example_explicit.c b/Documentation/filesystems/configfs/configfs_example_explicit.c
index fd53869f5633..1420233dfa55 100644
--- a/Documentation/filesystems/configfs/configfs_example_explicit.c
+++ b/Documentation/filesystems/configfs/configfs_example_explicit.c
@@ -464,9 +464,8 @@ static int __init configfs_example_init(void)
return 0;
out_unregister:
- for (; i >= 0; i--) {
+ for (i--; i >= 0; i--)
configfs_unregister_subsystem(example_subsys[i]);
- }
return ret;
}
@@ -475,9 +474,8 @@ static void __exit configfs_example_exit(void)
{
int i;
- for (i = 0; example_subsys[i]; i++) {
+ for (i = 0; example_subsys[i]; i++)
configfs_unregister_subsystem(example_subsys[i]);
- }
}
module_init(configfs_example_init);
diff --git a/Documentation/filesystems/configfs/configfs_example_macros.c b/Documentation/filesystems/configfs/configfs_example_macros.c
index d8e30a0378aa..327dfbc640a9 100644
--- a/Documentation/filesystems/configfs/configfs_example_macros.c
+++ b/Documentation/filesystems/configfs/configfs_example_macros.c
@@ -427,9 +427,8 @@ static int __init configfs_example_init(void)
return 0;
out_unregister:
- for (; i >= 0; i--) {
+ for (i--; i >= 0; i--)
configfs_unregister_subsystem(example_subsys[i]);
- }
return ret;
}
@@ -438,9 +437,8 @@ static void __exit configfs_example_exit(void)
{
int i;
- for (i = 0; example_subsys[i]; i++) {
+ for (i = 0; example_subsys[i]; i++)
configfs_unregister_subsystem(example_subsys[i]);
- }
}
module_init(configfs_example_init);
diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt
index c79ec58fd7f6..3ae9bc94352a 100644
--- a/Documentation/filesystems/ext4.txt
+++ b/Documentation/filesystems/ext4.txt
@@ -226,10 +226,6 @@ acl Enables POSIX Access Control Lists support.
noacl This option disables POSIX Access Control List
support.
-reservation
-
-noreservation
-
bsddf (*) Make 'df' act like BSD.
minixdf Make 'df' act like Minix.
diff --git a/Documentation/filesystems/ocfs2.txt b/Documentation/filesystems/ocfs2.txt
index 9ed920a8cd79..7618a287aa41 100644
--- a/Documentation/filesystems/ocfs2.txt
+++ b/Documentation/filesystems/ocfs2.txt
@@ -46,9 +46,15 @@ errors=panic Panic and halt the machine if an error occurs.
intr (*) Allow signals to interrupt cluster operations.
nointr Do not allow signals to interrupt cluster
operations.
+noatime Do not update access time.
+relatime(*) Update atime if the previous atime is older than
+ mtime or ctime
+strictatime Always update atime, but the minimum update interval
+ is specified by atime_quantum.
atime_quantum=60(*) OCFS2 will not update atime unless this number
of seconds has passed since the last update.
- Set to zero to always update atime.
+ Set to zero to always update atime. This option need
+ work with strictatime.
data=ordered (*) All data are forced directly out to the main file
system prior to its metadata being committed to the
journal.
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index b0b814d75ca1..f48178024067 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -574,6 +574,12 @@ The contents of each smp_affinity file is the same by default:
> cat /proc/irq/0/smp_affinity
ffffffff
+There is an alternate interface, smp_affinity_list which allows specifying
+a cpu range instead of a bitmask:
+
+ > cat /proc/irq/0/smp_affinity_list
+ 1024-1031
+
The default_smp_affinity mask applies to all non-active IRQs, which are the
IRQs which have not yet been allocated/activated, and hence which lack a
/proc/irq/[0-9]* directory.
@@ -583,12 +589,13 @@ reports itself as being attached. This hardware locality information does not
include information about any possible driver locality preference.
prof_cpu_mask specifies which CPUs are to be profiled by the system wide
-profiler. Default value is ffffffff (all cpus).
+profiler. Default value is ffffffff (all cpus if there are only 32 of them).
The way IRQs are routed is handled by the IO-APIC, and it's Round Robin
between all the CPUs which are allowed to handle it. As usual the kernel has
more info than you and does a better job than you, so the defaults are the
-best choice for almost everyone.
+best choice for almost everyone. [Note this applies only to those IO-APIC's
+that support "Round Robin" interrupt distribution.]
There are three more important subdirectories in /proc: net, scsi, and sys.
The general rule is that the contents, or even the existence of these
@@ -836,7 +843,6 @@ Provides counts of softirq handlers serviced since boot time, for each cpu.
TASKLET: 0 0 0 290
SCHED: 27035 26983 26971 26746
HRTIMER: 0 0 0 0
- RCU: 1678 1769 2178 2250
1.3 IDE devices in /proc/ide
diff --git a/Documentation/filesystems/ubifs.txt b/Documentation/filesystems/ubifs.txt
index d7b13b01e980..8e4fab639d9c 100644
--- a/Documentation/filesystems/ubifs.txt
+++ b/Documentation/filesystems/ubifs.txt
@@ -115,28 +115,8 @@ ubi.mtd=0 root=ubi0:rootfs rootfstype=ubifs
Module Parameters for Debugging
===============================
-When UBIFS has been compiled with debugging enabled, there are 3 module
+When UBIFS has been compiled with debugging enabled, there are 2 module
parameters that are available to control aspects of testing and debugging.
-The parameters are unsigned integers where each bit controls an option.
-The parameters are:
-
-debug_msgs Selects which debug messages to display, as follows:
-
- Message Type Flag value
-
- General messages 1
- Journal messages 2
- Mount messages 4
- Commit messages 8
- LEB search messages 16
- Budgeting messages 32
- Garbage collection messages 64
- Tree Node Cache (TNC) messages 128
- LEB properties (lprops) messages 256
- Input/output messages 512
- Log messages 1024
- Scan messages 2048
- Recovery messages 4096
debug_chks Selects extra checks that UBIFS can do while running:
@@ -154,11 +134,9 @@ debug_tsts Selects a mode of testing, as follows:
Test mode Flag value
- Force in-the-gaps method 2
Failure mode for recovery testing 4
-For example, set debug_msgs to 5 to display General messages and Mount
-messages.
+For example, set debug_chks to 3 to enable general and TNC checks.
References
diff --git a/Documentation/filesystems/xfs.txt b/Documentation/filesystems/xfs.txt
index 7bff3e4f35df..3fc0c31a6f5d 100644
--- a/Documentation/filesystems/xfs.txt
+++ b/Documentation/filesystems/xfs.txt
@@ -39,6 +39,12 @@ When mounting an XFS filesystem, the following options are accepted.
drive level write caching to be enabled, for devices that
support write barriers.
+ discard
+ Issue command to let the block device reclaim space freed by the
+ filesystem. This is useful for SSD devices, thinly provisioned
+ LUNs and virtual machine images, but may have a performance
+ impact. This option is incompatible with the nodelaylog option.
+
dmapi
Enable the DMAPI (Data Management API) event callouts.
Use with the "mtpt" option.
diff --git a/Documentation/usb/hiddev.txt b/Documentation/hid/hiddev.txt
index 6e8c9f1d2f22..6e8c9f1d2f22 100644
--- a/Documentation/usb/hiddev.txt
+++ b/Documentation/hid/hiddev.txt
diff --git a/Documentation/hid/hidraw.txt b/Documentation/hid/hidraw.txt
new file mode 100644
index 000000000000..029e6cb9a7e8
--- /dev/null
+++ b/Documentation/hid/hidraw.txt
@@ -0,0 +1,119 @@
+ HIDRAW - Raw Access to USB and Bluetooth Human Interface Devices
+ ==================================================================
+
+The hidraw driver provides a raw interface to USB and Bluetooth Human
+Interface Devices (HIDs). It differs from hiddev in that reports sent and
+received are not parsed by the HID parser, but are sent to and received from
+the device unmodified.
+
+Hidraw should be used if the userspace application knows exactly how to
+communicate with the hardware device, and is able to construct the HID
+reports manually. This is often the case when making userspace drivers for
+custom HID devices.
+
+Hidraw is also useful for communicating with non-conformant HID devices
+which send and receive data in a way that is inconsistent with their report
+descriptors. Because hiddev parses reports which are sent and received
+through it, checking them against the device's report descriptor, such
+communication with these non-conformant devices is impossible using hiddev.
+Hidraw is the only alternative, short of writing a custom kernel driver, for
+these non-conformant devices.
+
+A benefit of hidraw is that its use by userspace applications is independent
+of the underlying hardware type. Currently, Hidraw is implemented for USB
+and Bluetooth. In the future, as new hardware bus types are developed which
+use the HID specification, hidraw will be expanded to add support for these
+new bus types.
+
+Hidraw uses a dynamic major number, meaning that udev should be relied on to
+create hidraw device nodes. Udev will typically create the device nodes
+directly under /dev (eg: /dev/hidraw0). As this location is distribution-
+and udev rule-dependent, applications should use libudev to locate hidraw
+devices attached to the system. There is a tutorial on libudev with a
+working example at:
+ http://www.signal11.us/oss/udev/
+
+The HIDRAW API
+---------------
+
+read()
+-------
+read() will read a queued report received from the HID device. On USB
+devices, the reports read using read() are the reports sent from the device
+on the INTERRUPT IN endpoint. By default, read() will block until there is
+a report available to be read. read() can be made non-blocking, by passing
+the O_NONBLOCK flag to open(), or by setting the O_NONBLOCK flag using
+fcntl().
+
+On a device which uses numbered reports, the first byte of the returned data
+will be the report number; the report data follows, beginning in the second
+byte. For devices which do not use numbered reports, the report data
+will begin at the first byte.
+
+write()
+--------
+The write() function will write a report to the device. For USB devices, if
+the device has an INTERRUPT OUT endpoint, the report will be sent on that
+endpoint. If it does not, the report will be sent over the control endpoint,
+using a SET_REPORT transfer.
+
+The first byte of the buffer passed to write() should be set to the report
+number. If the device does not use numbered reports, the first byte should
+be set to 0. The report data itself should begin at the second byte.
+
+ioctl()
+--------
+Hidraw supports the following ioctls:
+
+HIDIOCGRDESCSIZE: Get Report Descriptor Size
+This ioctl will get the size of the device's report descriptor.
+
+HIDIOCGRDESC: Get Report Descriptor
+This ioctl returns the device's report descriptor using a
+hidraw_report_descriptor struct. Make sure to set the size field of the
+hidraw_report_descriptor struct to the size returned from HIDIOCGRDESCSIZE.
+
+HIDIOCGRAWINFO: Get Raw Info
+This ioctl will return a hidraw_devinfo struct containing the bus type, the
+vendor ID (VID), and product ID (PID) of the device. The bus type can be one
+of:
+ BUS_USB
+ BUS_HIL
+ BUS_BLUETOOTH
+ BUS_VIRTUAL
+which are defined in linux/input.h.
+
+HIDIOCGRAWNAME(len): Get Raw Name
+This ioctl returns a string containing the vendor and product strings of
+the device. The returned string is Unicode, UTF-8 encoded.
+
+HIDIOCGRAWPHYS(len): Get Physical Address
+This ioctl returns a string representing the physical address of the device.
+For USB devices, the string contains the physical path to the device (the
+USB controller, hubs, ports, etc). For Bluetooth devices, the string
+contains the hardware (MAC) address of the device.
+
+HIDIOCSFEATURE(len): Send a Feature Report
+This ioctl will send a feature report to the device. Per the HID
+specification, feature reports are always sent using the control endpoint.
+Set the first byte of the supplied buffer to the report number. For devices
+which do not use numbered reports, set the first byte to 0. The report data
+begins in the second byte. Make sure to set len accordingly, to one more
+than the length of the report (to account for the report number).
+
+HIDIOCGFEATURE(len): Get a Feature Report
+This ioctl will request a feature report from the device using the control
+endpoint. The first byte of the supplied buffer should be set to the report
+number of the requested report. For devices which do not use numbered
+reports, set the first byte to 0. The report will be returned starting at
+the first byte of the buffer (ie: the report number is not returned).
+
+Example
+---------
+In samples/, find hid-example.c, which shows examples of read(), write(),
+and all the ioctls for hidraw. The code may be used by anyone for any
+purpose, and can serve as a starting point for developing applications using
+hidraw.
+
+Document by:
+ Alan Ott <alan@signal11.us>, Signal 11 Software
diff --git a/Documentation/hwmon/adm1275 b/Documentation/hwmon/adm1275
new file mode 100644
index 000000000000..6a3a6476cf20
--- /dev/null
+++ b/Documentation/hwmon/adm1275
@@ -0,0 +1,60 @@
+Kernel driver adm1275
+=====================
+
+Supported chips:
+ * Analog Devices ADM1275
+ Prefix: 'adm1275'
+ Addresses scanned: -
+ Datasheet: www.analog.com/static/imported-files/data_sheets/ADM1275.pdf
+
+Author: Guenter Roeck <guenter.roeck@ericsson.com>
+
+
+Description
+-----------
+
+This driver supports hardware montoring for Analog Devices ADM1275 Hot-Swap
+Controller and Digital Power Monitor.
+
+The ADM1275 is a hot-swap controller that allows a circuit board to be removed
+from or inserted into a live backplane. It also features current and voltage
+readback via an integrated 12-bit analog-to-digital converter (ADC), accessed
+using a PMBus. interface.
+
+The driver is a client driver to the core PMBus driver. Please see
+Documentation/hwmon/pmbus for details on PMBus client drivers.
+
+
+Usage Notes
+-----------
+
+This driver does not auto-detect devices. You will have to instantiate the
+devices explicitly. Please see Documentation/i2c/instantiating-devices for
+details.
+
+
+Platform data support
+---------------------
+
+The driver supports standard PMBus driver platform data. Please see
+Documentation/hwmon/pmbus for details.
+
+
+Sysfs entries
+-------------
+
+The following attributes are supported. Limits are read-write; all other
+attributes are read-only.
+
+in1_label "vin1" or "vout1" depending on chip variant and
+ configuration.
+in1_input Measured voltage. From READ_VOUT register.
+in1_min Minumum Voltage. From VOUT_UV_WARN_LIMIT register.
+in1_max Maximum voltage. From VOUT_OV_WARN_LIMIT register.
+in1_min_alarm Voltage low alarm. From VOLTAGE_UV_WARNING status.
+in1_max_alarm Voltage high alarm. From VOLTAGE_OV_WARNING status.
+
+curr1_label "iout1"
+curr1_input Measured current. From READ_IOUT register.
+curr1_max Maximum current. From IOUT_OC_WARN_LIMIT register.
+curr1_max_alarm Current high alarm. From IOUT_OC_WARN_LIMIT register.
diff --git a/Documentation/hwmon/coretemp b/Documentation/hwmon/coretemp
index 25568f844804..f85e913a3401 100644
--- a/Documentation/hwmon/coretemp
+++ b/Documentation/hwmon/coretemp
@@ -15,8 +15,13 @@ Author: Rudolf Marek
Description
-----------
+This driver permits reading the DTS (Digital Temperature Sensor) embedded
+inside Intel CPUs. This driver can read both the per-core and per-package
+temperature using the appropriate sensors. The per-package sensor is new;
+as of now, it is present only in the SandyBridge platform. The driver will
+show the temperature of all cores inside a package under a single device
+directory inside hwmon.
-This driver permits reading temperature sensor embedded inside Intel Core CPU.
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.
@@ -27,13 +32,15 @@ mechanism will perform actions to forcibly cool down the processor. 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 - Core temperature (in millidegrees Celsius).
-temp1_max - All cooling devices should be turned on (on Core2).
-temp1_crit - Maximum junction temperature (in millidegrees Celsius).
-temp1_crit_alarm - Set when Out-of-spec bit is set, never clears.
+All Sysfs entries are named with their core_id (represented here by 'X').
+tempX_input - Core temperature (in millidegrees Celsius).
+tempX_max - All cooling devices should be turned on (on Core2).
+tempX_crit - Maximum junction temperature (in millidegrees Celsius).
+tempX_crit_alarm - Set when Out-of-spec bit is set, never clears.
Correct CPU operation is no longer guaranteed.
-temp1_label - Contains string "Core X", where X is processor
- number.
+tempX_label - Contains string "Core X", where X is processor
+ number. For Package temp, this will be "Physical id Y",
+ where Y is the package number.
The TjMax temperature is set to 85 degrees C if undocumented model specific
register (UMSR) 0xee has bit 30 set. If not the TjMax is 100 degrees C as
diff --git a/Documentation/hwmon/emc6w201 b/Documentation/hwmon/emc6w201
new file mode 100644
index 000000000000..32f355aaf56b
--- /dev/null
+++ b/Documentation/hwmon/emc6w201
@@ -0,0 +1,42 @@
+Kernel driver emc6w201
+======================
+
+Supported chips:
+ * SMSC EMC6W201
+ Prefix: 'emc6w201'
+ Addresses scanned: I2C 0x2c, 0x2d, 0x2e
+ Datasheet: Not public
+
+Author: Jean Delvare <khali@linux-fr.org>
+
+
+Description
+-----------
+
+From the datasheet:
+
+"The EMC6W201 is an environmental monitoring device with automatic fan
+control capability and enhanced system acoustics for noise suppression.
+This ACPI compliant device provides hardware monitoring for up to six
+voltages (including its own VCC) and five external thermal sensors,
+measures the speed of up to five fans, and controls the speed of
+multiple DC fans using three Pulse Width Modulator (PWM) outputs. Note
+that it is possible to control more than three fans by connecting two
+fans to one PWM output. The EMC6W201 will be available in a 36-pin
+QFN package."
+
+The device is functionally close to the EMC6D100 series, but is
+register-incompatible.
+
+The driver currently only supports the monitoring of the voltages,
+temperatures and fan speeds. Limits can be changed. Alarms are not
+supported, and neither is fan speed control.
+
+
+Known Systems With EMC6W201
+---------------------------
+
+The EMC6W201 is a rare device, only found on a few systems, made in
+2005 and 2006. Known systems with this device:
+* Dell Precision 670 workstation
+* Gigabyte 2CEWH mainboard
diff --git a/Documentation/hwmon/f71882fg b/Documentation/hwmon/f71882fg
index df02245d1419..84d2623810f3 100644
--- a/Documentation/hwmon/f71882fg
+++ b/Documentation/hwmon/f71882fg
@@ -6,6 +6,10 @@ Supported chips:
Prefix: 'f71808e'
Addresses scanned: none, address read from Super I/O config space
Datasheet: Not public
+ * Fintek F71808A
+ Prefix: 'f71808a'
+ Addresses scanned: none, address read from Super I/O config space
+ Datasheet: Not public
* Fintek F71858FG
Prefix: 'f71858fg'
Addresses scanned: none, address read from Super I/O config space
diff --git a/Documentation/hwmon/fam15h_power b/Documentation/hwmon/fam15h_power
new file mode 100644
index 000000000000..a92918e0bd69
--- /dev/null
+++ b/Documentation/hwmon/fam15h_power
@@ -0,0 +1,37 @@
+Kernel driver fam15h_power
+==========================
+
+Supported chips:
+* AMD Family 15h Processors
+
+ Prefix: 'fam15h_power'
+ Addresses scanned: PCI space
+ Datasheets:
+ BIOS and Kernel Developer's Guide (BKDG) For AMD Family 15h Processors
+ (not yet published)
+
+Author: Andreas Herrmann <andreas.herrmann3@amd.com>
+
+Description
+-----------
+
+This driver permits reading of registers providing power information
+of AMD Family 15h processors.
+
+For AMD Family 15h processors the following power values can be
+calculated using different processor northbridge function registers:
+
+* BasePwrWatts: Specifies in watts the maximum amount of power
+ consumed by the processor for NB and logic external to the core.
+* ProcessorPwrWatts: Specifies in watts the maximum amount of power
+ the processor can support.
+* CurrPwrWatts: Specifies in watts the current amount of power being
+ consumed by the processor.
+
+This driver provides ProcessorPwrWatts and CurrPwrWatts:
+* power1_crit (ProcessorPwrWatts)
+* power1_input (CurrPwrWatts)
+
+On multi-node processors the calculated value is for the entire
+package and not for a single node. Thus the driver creates sysfs
+attributes only for internal node0 of a multi-node processor.
diff --git a/Documentation/hwmon/k10temp b/Documentation/hwmon/k10temp
index d2b56a4fd1f5..0393c89277c0 100644
--- a/Documentation/hwmon/k10temp
+++ b/Documentation/hwmon/k10temp
@@ -11,6 +11,7 @@ Supported chips:
Socket S1G2: Athlon (X2), Sempron (X2), Turion X2 (Ultra)
* AMD Family 12h processors: "Llano"
* AMD Family 14h processors: "Brazos" (C/E/G-Series)
+* AMD Family 15h processors: "Bulldozer"
Prefix: 'k10temp'
Addresses scanned: PCI space
@@ -40,7 +41,7 @@ Description
-----------
This driver permits reading of the internal temperature sensor of AMD
-Family 10h/11h/12h/14h processors.
+Family 10h/11h/12h/14h/15h processors.
All these processors have a sensor, but on those for Socket F or AM2+,
the sensor may return inconsistent values (erratum 319). The driver
diff --git a/Documentation/hwmon/max16065 b/Documentation/hwmon/max16065
new file mode 100644
index 000000000000..44b4f61e04f9
--- /dev/null
+++ b/Documentation/hwmon/max16065
@@ -0,0 +1,98 @@
+Kernel driver max16065
+======================
+
+Supported chips:
+ * Maxim MAX16065, MAX16066
+ Prefixes: 'max16065', 'max16066'
+ Addresses scanned: -
+ Datasheet:
+ http://datasheets.maxim-ic.com/en/ds/MAX16065-MAX16066.pdf
+ * Maxim MAX16067
+ Prefix: 'max16067'
+ Addresses scanned: -
+ Datasheet:
+ http://datasheets.maxim-ic.com/en/ds/MAX16067.pdf
+ * Maxim MAX16068
+ Prefix: 'max16068'
+ Addresses scanned: -
+ Datasheet:
+ http://datasheets.maxim-ic.com/en/ds/MAX16068.pdf
+ * Maxim MAX16070/MAX16071
+ Prefixes: 'max16070', 'max16071'
+ Addresses scanned: -
+ Datasheet:
+ http://datasheets.maxim-ic.com/en/ds/MAX16070-MAX16071.pdf
+
+
+Author: Guenter Roeck <guenter.roeck@ericsson.com>
+
+
+Description
+-----------
+
+[From datasheets] The MAX16065/MAX16066 flash-configurable system managers
+monitor and sequence multiple system voltages. The MAX16065/MAX16066 can also
+accurately monitor (+/-2.5%) one current channel using a dedicated high-side
+current-sense amplifier. The MAX16065 manages up to twelve system voltages
+simultaneously, and the MAX16066 manages up to eight supply voltages.
+
+The MAX16067 flash-configurable system manager monitors and sequences multiple
+system voltages. The MAX16067 manages up to six system voltages simultaneously.
+
+The MAX16068 flash-configurable system manager monitors and manages up to six
+system voltages simultaneously.
+
+The MAX16070/MAX16071 flash-configurable system monitors supervise multiple
+system voltages. The MAX16070/MAX16071 can also accurately monitor (+/-2.5%)
+one current channel using a dedicated high-side current-sense amplifier. The
+MAX16070 monitors up to twelve system voltages simultaneously, and the MAX16071
+monitors up to eight supply voltages.
+
+Each monitored channel has its own low and high critical limits. MAX16065,
+MAX16066, MAX16070, and MAX16071 support an additional limit which is
+configurable as either low or high secondary limit. MAX16065, MAX16066,
+MAX16070, and MAX16071 also support supply current monitoring.
+
+
+Usage Notes
+-----------
+
+This driver does not probe for devices, since there is no register which
+can be safely used to identify the chip. You will have to instantiate
+the devices explicitly. Please see Documentation/i2c/instantiating-devices for
+details.
+
+
+Sysfs entries
+-------------
+
+in[0-11]_input Input voltage measurements.
+
+in12_input Voltage on CSP (Current Sense Positive) pin.
+ Only if the chip supports current sensing and if
+ current sensing is enabled.
+
+in[0-11]_min Low warning limit.
+ Supported on MAX16065, MAX16066, MAX16070, and MAX16071
+ only.
+
+in[0-11]_max High warning limit.
+ Supported on MAX16065, MAX16066, MAX16070, and MAX16071
+ only.
+
+ Either low or high warning limits are supported
+ (depending on chip configuration), but not both.
+
+in[0-11]_lcrit Low critical limit.
+
+in[0-11]_crit High critical limit.
+
+in[0-11]_alarm Input voltage alarm.
+
+curr1_input Current sense input; only if the chip supports current
+ sensing and if current sensing is enabled.
+ Displayed current assumes 0.001 Ohm current sense
+ resistor.
+
+curr1_alarm Overcurrent alarm; only if the chip supports current
+ sensing and if current sensing is enabled.
diff --git a/Documentation/hwmon/max6642 b/Documentation/hwmon/max6642
new file mode 100644
index 000000000000..afbd3e4942e2
--- /dev/null
+++ b/Documentation/hwmon/max6642
@@ -0,0 +1,21 @@
+Kernel driver max6642
+=====================
+
+Supported chips:
+ * Maxim MAX6642
+ Prefix: 'max6642'
+ Addresses scanned: I2C 0x48-0x4f
+ Datasheet: Publicly available at the Maxim website
+ http://datasheets.maxim-ic.com/en/ds/MAX6642.pdf
+
+Authors:
+ Per Dalen <per.dalen@appeartv.com>
+
+Description
+-----------
+
+The MAX6642 is a digital temperature sensor. It senses its own temperature as
+well as the temperature on one external diode.
+
+All temperature values are given in degrees Celsius. Resolution
+is 0.25 degree for the local temperature and for the remote temperature.
diff --git a/Documentation/hwmon/max6650 b/Documentation/hwmon/max6650
index c565650fcfc6..58d9644a2bde 100644
--- a/Documentation/hwmon/max6650
+++ b/Documentation/hwmon/max6650
@@ -2,9 +2,13 @@ Kernel driver max6650
=====================
Supported chips:
- * Maxim 6650 / 6651
+ * Maxim MAX6650
Prefix: 'max6650'
- Addresses scanned: I2C 0x1b, 0x1f, 0x48, 0x4b
+ Addresses scanned: none
+ Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf
+ * Maxim MAX6651
+ Prefix: 'max6651'
+ Addresses scanned: none
Datasheet: http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf
Authors:
@@ -15,10 +19,10 @@ Authors:
Description
-----------
-This driver implements support for the Maxim 6650/6651
+This driver implements support for the Maxim MAX6650 and MAX6651.
-The 2 devices are very similar, but the Maxim 6550 has a reduced feature
-set, e.g. only one fan-input, instead of 4 for the 6651.
+The 2 devices are very similar, but the MAX6550 has a reduced feature
+set, e.g. only one fan-input, instead of 4 for the MAX6651.
The driver is not able to distinguish between the 2 devices.
@@ -36,6 +40,13 @@ fan1_div rw sets the speed range the inputs can handle. Legal
values are 1, 2, 4, and 8. Use lower values for
faster fans.
+Usage notes
+-----------
+
+This driver does not auto-detect devices. You will have to instantiate the
+devices explicitly. Please see Documentation/i2c/instantiating-devices for
+details.
+
Module parameters
-----------------
diff --git a/Documentation/hwmon/pkgtemp b/Documentation/hwmon/pkgtemp
deleted file mode 100644
index c8e1fb0fadd3..000000000000
--- a/Documentation/hwmon/pkgtemp
+++ /dev/null
@@ -1,36 +0,0 @@
-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/sht15 b/Documentation/hwmon/sht15
new file mode 100644
index 000000000000..02850bdfac18
--- /dev/null
+++ b/Documentation/hwmon/sht15
@@ -0,0 +1,74 @@
+Kernel driver sht15
+===================
+
+Authors:
+ * Wouter Horre
+ * Jonathan Cameron
+ * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
+ * Jerome Oufella <jerome.oufella@savoirfairelinux.com>
+
+Supported chips:
+ * Sensirion SHT10
+ Prefix: 'sht10'
+
+ * Sensirion SHT11
+ Prefix: 'sht11'
+
+ * Sensirion SHT15
+ Prefix: 'sht15'
+
+ * Sensirion SHT71
+ Prefix: 'sht71'
+
+ * Sensirion SHT75
+ Prefix: 'sht75'
+
+Datasheet: Publicly available at the Sensirion website
+http://www.sensirion.ch/en/pdf/product_information/Datasheet-humidity-sensor-SHT1x.pdf
+
+Description
+-----------
+
+The SHT10, SHT11, SHT15, SHT71, and SHT75 are humidity and temperature
+sensors.
+
+The devices communicate using two GPIO lines.
+
+Supported resolutions for the measurements are 14 bits for temperature and 12
+bits for humidity, or 12 bits for temperature and 8 bits for humidity.
+
+The humidity calibration coefficients are programmed into an OTP memory on the
+chip. These coefficients are used to internally calibrate the signals from the
+sensors. Disabling the reload of those coefficients allows saving 10ms for each
+measurement and decrease power consumption, while loosing on precision.
+
+Some options may be set directly in the sht15_platform_data structure
+or via sysfs attributes.
+
+Notes:
+ * The regulator supply name is set to "vcc".
+ * If a CRC validation fails, a soft reset command is sent, which resets
+ status register to its hardware default value, but the driver will try to
+ restore the previous device configuration.
+
+Platform data
+-------------
+
+* checksum:
+ set it to true to enable CRC validation of the readings (default to false).
+* no_otp_reload:
+ flag to indicate not to reload from OTP (default to false).
+* low_resolution:
+ flag to indicate the temp/humidity resolution to use (default to false).
+
+Sysfs interface
+---------------
+
+* temp1_input: temperature input
+* humidity1_input: humidity input
+* heater_enable: write 1 in this attribute to enable the on-chip heater,
+ 0 to disable it. Be careful not to enable the heater
+ for too long.
+* temp1_fault: if 1, this means that the voltage is low (below 2.47V) and
+ measurement may be invalid.
+* humidity1_fault: same as temp1_fault.
diff --git a/Documentation/hwmon/ucd9000 b/Documentation/hwmon/ucd9000
new file mode 100644
index 000000000000..40ca6db50c48
--- /dev/null
+++ b/Documentation/hwmon/ucd9000
@@ -0,0 +1,110 @@
+Kernel driver ucd9000
+=====================
+
+Supported chips:
+ * TI UCD90120, UCD90124, UCD9090, and UCD90910
+ Prefixes: 'ucd90120', 'ucd90124', 'ucd9090', 'ucd90910'
+ Addresses scanned: -
+ Datasheets:
+ http://focus.ti.com/lit/ds/symlink/ucd90120.pdf
+ http://focus.ti.com/lit/ds/symlink/ucd90124.pdf
+ http://focus.ti.com/lit/ds/symlink/ucd9090.pdf
+ http://focus.ti.com/lit/ds/symlink/ucd90910.pdf
+
+Author: Guenter Roeck <guenter.roeck@ericsson.com>
+
+
+Description
+-----------
+
+From datasheets:
+
+The UCD90120 Power Supply Sequencer and System Health Monitor monitors and
+sequences up to 12 independent voltage rails. The device integrates a 12-bit
+ADC with a 2.5V internal reference for monitoring up to 13 power supply voltage,
+current, or temperature inputs.
+
+The UCD90124 is a 12-rail PMBus/I2C addressable power-supply sequencer and
+system-health monitor. The device integrates a 12-bit ADC for monitoring up to
+13 power-supply voltage, current, or temperature inputs. Twenty-six GPIO pins
+can be used for power supply enables, power-on reset signals, external
+interrupts, cascading, or other system functions. Twelve of these pins offer PWM
+functionality. Using these pins, the UCD90124 offers support for fan control,
+margining, and general-purpose PWM functions.
+
+The UCD9090 is a 10-rail PMBus/I2C addressable power-supply sequencer and
+monitor. The device integrates a 12-bit ADC for monitoring up to 10 power-supply
+voltage inputs. Twenty-three GPIO pins can be used for power supply enables,
+power-on reset signals, external interrupts, cascading, or other system
+functions. Ten of these pins offer PWM functionality. Using these pins, the
+UCD9090 offers support for margining, and general-purpose PWM functions.
+
+The UCD90910 is a ten-rail I2C / PMBus addressable power-supply sequencer and
+system-health monitor. The device integrates a 12-bit ADC for monitoring up to
+13 power-supply voltage, current, or temperature inputs.
+
+This driver is a client driver to the core PMBus driver. Please see
+Documentation/hwmon/pmbus for details on PMBus client drivers.
+
+
+Usage Notes
+-----------
+
+This driver does not auto-detect devices. You will have to instantiate the
+devices explicitly. Please see Documentation/i2c/instantiating-devices for
+details.
+
+
+Platform data support
+---------------------
+
+The driver supports standard PMBus driver platform data. Please see
+Documentation/hwmon/pmbus for details.
+
+
+Sysfs entries
+-------------
+
+The following attributes are supported. Limits are read-write; all other
+attributes are read-only.
+
+in[1-12]_label "vout[1-12]".
+in[1-12]_input Measured voltage. From READ_VOUT register.
+in[1-12]_min Minumum Voltage. From VOUT_UV_WARN_LIMIT register.
+in[1-12]_max Maximum voltage. From VOUT_OV_WARN_LIMIT register.
+in[1-12]_lcrit Critical minumum Voltage. VOUT_UV_FAULT_LIMIT register.
+in[1-12]_crit Critical maximum voltage. From VOUT_OV_FAULT_LIMIT register.
+in[1-12]_min_alarm Voltage low alarm. From VOLTAGE_UV_WARNING status.
+in[1-12]_max_alarm Voltage high alarm. From VOLTAGE_OV_WARNING status.
+in[1-12]_lcrit_alarm Voltage critical low alarm. From VOLTAGE_UV_FAULT status.
+in[1-12]_crit_alarm Voltage critical high alarm. From VOLTAGE_OV_FAULT status.
+
+curr[1-12]_label "iout[1-12]".
+curr[1-12]_input Measured current. From READ_IOUT register.
+curr[1-12]_max Maximum current. From IOUT_OC_WARN_LIMIT register.
+curr[1-12]_lcrit Critical minumum output current. From IOUT_UC_FAULT_LIMIT
+ register.
+curr[1-12]_crit Critical maximum current. From IOUT_OC_FAULT_LIMIT register.
+curr[1-12]_max_alarm Current high alarm. From IOUT_OC_WARNING status.
+curr[1-12]_crit_alarm Current critical high alarm. From IOUT_OC_FAULT status.
+
+ For each attribute index, either voltage or current is
+ reported, but not both. If voltage or current is
+ reported depends on the chip configuration.
+
+temp[1-2]_input Measured temperatures. From READ_TEMPERATURE_1 and
+ READ_TEMPERATURE_2 registers.
+temp[1-2]_max Maximum temperature. From OT_WARN_LIMIT register.
+temp[1-2]_crit Critical high temperature. From OT_FAULT_LIMIT register.
+temp[1-2]_max_alarm Temperature high alarm.
+temp[1-2]_crit_alarm Temperature critical high alarm.
+
+fan[1-4]_input Fan RPM.
+fan[1-4]_alarm Fan alarm.
+fan[1-4]_fault Fan fault.
+
+ Fan attributes are only available on chips supporting
+ fan control (UCD90124, UCD90910). Attribute files are
+ created only for enabled fans.
+ Note that even though UCD90910 supports up to 10 fans,
+ only up to four fans are currently supported.
diff --git a/Documentation/hwmon/ucd9200 b/Documentation/hwmon/ucd9200
new file mode 100644
index 000000000000..3c58607f72fe
--- /dev/null
+++ b/Documentation/hwmon/ucd9200
@@ -0,0 +1,112 @@
+Kernel driver ucd9200
+=====================
+
+Supported chips:
+ * TI UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, and UCD9248
+ Prefixes: 'ucd9220', 'ucd9222', 'ucd9224', 'ucd9240', 'ucd9244', 'ucd9246',
+ 'ucd9248'
+ Addresses scanned: -
+ Datasheets:
+ http://focus.ti.com/lit/ds/symlink/ucd9220.pdf
+ http://focus.ti.com/lit/ds/symlink/ucd9222.pdf
+ http://focus.ti.com/lit/ds/symlink/ucd9224.pdf
+ http://focus.ti.com/lit/ds/symlink/ucd9240.pdf
+ http://focus.ti.com/lit/ds/symlink/ucd9244.pdf
+ http://focus.ti.com/lit/ds/symlink/ucd9246.pdf
+ http://focus.ti.com/lit/ds/symlink/ucd9248.pdf
+
+Author: Guenter Roeck <guenter.roeck@ericsson.com>
+
+
+Description
+-----------
+
+[From datasheets] UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, and
+UCD9248 are multi-rail, multi-phase synchronous buck digital PWM controllers
+designed for non-isolated DC/DC power applications. The devices integrate
+dedicated circuitry for DC/DC loop management with flash memory and a serial
+interface to support configuration, monitoring and management.
+
+This driver is a client driver to the core PMBus driver. Please see
+Documentation/hwmon/pmbus for details on PMBus client drivers.
+
+
+Usage Notes
+-----------
+
+This driver does not auto-detect devices. You will have to instantiate the
+devices explicitly. Please see Documentation/i2c/instantiating-devices for
+details.
+
+
+Platform data support
+---------------------
+
+The driver supports standard PMBus driver platform data. Please see
+Documentation/hwmon/pmbus for details.
+
+
+Sysfs entries
+-------------
+
+The following attributes are supported. Limits are read-write; all other
+attributes are read-only.
+
+in1_label "vin".
+in1_input Measured voltage. From READ_VIN register.
+in1_min Minumum Voltage. From VIN_UV_WARN_LIMIT register.
+in1_max Maximum voltage. From VIN_OV_WARN_LIMIT register.
+in1_lcrit Critical minumum Voltage. VIN_UV_FAULT_LIMIT register.
+in1_crit Critical maximum voltage. From VIN_OV_FAULT_LIMIT register.
+in1_min_alarm Voltage low alarm. From VIN_UV_WARNING status.
+in1_max_alarm Voltage high alarm. From VIN_OV_WARNING status.
+in1_lcrit_alarm Voltage critical low alarm. From VIN_UV_FAULT status.
+in1_crit_alarm Voltage critical high alarm. From VIN_OV_FAULT status.
+
+in[2-5]_label "vout[1-4]".
+in[2-5]_input Measured voltage. From READ_VOUT register.
+in[2-5]_min Minumum Voltage. From VOUT_UV_WARN_LIMIT register.
+in[2-5]_max Maximum voltage. From VOUT_OV_WARN_LIMIT register.
+in[2-5]_lcrit Critical minumum Voltage. VOUT_UV_FAULT_LIMIT register.
+in[2-5]_crit Critical maximum voltage. From VOUT_OV_FAULT_LIMIT register.
+in[2-5]_min_alarm Voltage low alarm. From VOLTAGE_UV_WARNING status.
+in[2-5]_max_alarm Voltage high alarm. From VOLTAGE_OV_WARNING status.
+in[2-5]_lcrit_alarm Voltage critical low alarm. From VOLTAGE_UV_FAULT status.
+in[2-5]_crit_alarm Voltage critical high alarm. From VOLTAGE_OV_FAULT status.
+
+curr1_label "iin".
+curr1_input Measured current. From READ_IIN register.
+
+curr[2-5]_label "iout[1-4]".
+curr[2-5]_input Measured current. From READ_IOUT register.
+curr[2-5]_max Maximum current. From IOUT_OC_WARN_LIMIT register.
+curr[2-5]_lcrit Critical minumum output current. From IOUT_UC_FAULT_LIMIT
+ register.
+curr[2-5]_crit Critical maximum current. From IOUT_OC_FAULT_LIMIT register.
+curr[2-5]_max_alarm Current high alarm. From IOUT_OC_WARNING status.
+curr[2-5]_crit_alarm Current critical high alarm. From IOUT_OC_FAULT status.
+
+power1_input Measured input power. From READ_PIN register.
+power1_label "pin"
+
+power[2-5]_input Measured output power. From READ_POUT register.
+power[2-5]_label "pout[1-4]"
+
+ The number of output voltage, current, and power
+ attribute sets is determined by the number of enabled
+ rails. See chip datasheets for details.
+
+temp[1-5]_input Measured temperatures. From READ_TEMPERATURE_1 and
+ READ_TEMPERATURE_2 registers.
+ temp1 is the chip internal temperature. temp[2-5] are
+ rail temperatures. temp[2-5] attributes are only
+ created for enabled rails. See chip datasheets for
+ details.
+temp[1-5]_max Maximum temperature. From OT_WARN_LIMIT register.
+temp[1-5]_crit Critical high temperature. From OT_FAULT_LIMIT register.
+temp[1-5]_max_alarm Temperature high alarm.
+temp[1-5]_crit_alarm Temperature critical high alarm.
+
+fan1_input Fan RPM. ucd9240 only.
+fan1_alarm Fan alarm. ucd9240 only.
+fan1_fault Fan fault. ucd9240 only.
diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801
index 6df69765ccb7..2871fd500349 100644
--- a/Documentation/i2c/busses/i2c-i801
+++ b/Documentation/i2c/busses/i2c-i801
@@ -19,6 +19,7 @@ Supported adapters:
* Intel 6 Series (PCH)
* Intel Patsburg (PCH)
* Intel DH89xxCC (PCH)
+ * Intel Panther Point (PCH)
Datasheets: Publicly available at the Intel website
On Intel Patsburg and later chipsets, both the normal host SMBus controller
diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients
index 5ebf5af1d716..5aa53374ea2a 100644
--- a/Documentation/i2c/writing-clients
+++ b/Documentation/i2c/writing-clients
@@ -38,7 +38,7 @@ static struct i2c_driver foo_driver = {
.name = "foo",
},
- .id_table = foo_ids,
+ .id_table = foo_idtable,
.probe = foo_probe,
.remove = foo_remove,
/* if device autodetection is needed: */
diff --git a/Documentation/input/elantech.txt b/Documentation/input/elantech.txt
index 56941ae1f5db..db798af5ef98 100644
--- a/Documentation/input/elantech.txt
+++ b/Documentation/input/elantech.txt
@@ -34,7 +34,8 @@ Contents
Currently the Linux Elantech touchpad driver is aware of two different
hardware versions unimaginatively called version 1 and version 2. Version 1
is found in "older" laptops and uses 4 bytes per packet. Version 2 seems to
-be introduced with the EeePC and uses 6 bytes per packet.
+be introduced with the EeePC and uses 6 bytes per packet, and provides
+additional features such as position of two fingers, and width of the touch.
The driver tries to support both hardware versions and should be compatible
with the Xorg Synaptics touchpad driver and its graphical configuration
@@ -94,18 +95,44 @@ Currently the Linux Elantech touchpad driver provides two extra knobs under
can check these bits and reject any packet that appears corrupted. Using
this knob you can bypass that check.
- It is not known yet whether hardware version 2 provides the same parity
- bits. Hence checking is disabled by default. Currently even turning it on
- will do nothing.
-
+ Hardware version 2 does not provide the same parity bits. Only some basic
+ data consistency checking can be done. For now checking is disabled by
+ default. Currently even turning it on will do nothing.
/////////////////////////////////////////////////////////////////////////////
+3. Differentiating hardware versions
+ =================================
+
+To detect the hardware version, read the version number as param[0].param[1].param[2]
+
+ 4 bytes version: (after the arrow is the name given in the Dell-provided driver)
+ 02.00.22 => EF013
+ 02.06.00 => EF019
+In the wild, there appear to be more versions, such as 00.01.64, 01.00.21,
+02.00.00, 02.00.04, 02.00.06.
+
+ 6 bytes:
+ 02.00.30 => EF113
+ 02.08.00 => EF023
+ 02.08.XX => EF123
+ 02.0B.00 => EF215
+ 04.01.XX => Scroll_EF051
+ 04.02.XX => EF051
+In the wild, there appear to be more versions, such as 04.03.01, 04.04.11. There
+appears to be almost no difference, except for EF113, which does not report
+pressure/width and has different data consistency checks.
+
+Probably all the versions with param[0] <= 01 can be considered as
+4 bytes/firmware 1. The versions < 02.08.00, with the exception of 02.00.30, as
+4 bytes/firmware 2. Everything >= 02.08.00 can be considered as 6 bytes.
+
+/////////////////////////////////////////////////////////////////////////////
-3. Hardware version 1
+4. Hardware version 1
==================
-3.1 Registers
+4.1 Registers
~~~~~~~~~
By echoing a hexadecimal value to a register it contents can be altered.
@@ -168,7 +195,7 @@ For example:
smart edge activation area width?
-3.2 Native relative mode 4 byte packet format
+4.2 Native relative mode 4 byte packet format
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
byte 0:
@@ -226,9 +253,13 @@ byte 3:
positive = down
-3.3 Native absolute mode 4 byte packet format
+4.3 Native absolute mode 4 byte packet format
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+EF013 and EF019 have a special behaviour (due to a bug in the firmware?), and
+when 1 finger is touching, the first 2 position reports must be discarded.
+This counting is reset whenever a different number of fingers is reported.
+
byte 0:
firmware version 1.x:
@@ -279,11 +310,11 @@ byte 3:
/////////////////////////////////////////////////////////////////////////////
-4. Hardware version 2
+5. Hardware version 2
==================
-4.1 Registers
+5.1 Registers
~~~~~~~~~
By echoing a hexadecimal value to a register it contents can be altered.
@@ -316,16 +347,41 @@ For example:
0x7f = never i.e. tap again to release)
-4.2 Native absolute mode 6 byte packet format
+5.2 Native absolute mode 6 byte packet format
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-4.2.1 One finger touch
+5.2.1 Parity checking and packet re-synchronization
+There is no parity checking, however some consistency checks can be performed.
+
+For instance for EF113:
+ SA1= packet[0];
+ A1 = packet[1];
+ B1 = packet[2];
+ SB1= packet[3];
+ C1 = packet[4];
+ D1 = packet[5];
+ if( (((SA1 & 0x3C) != 0x3C) && ((SA1 & 0xC0) != 0x80)) || // check Byte 1
+ (((SA1 & 0x0C) != 0x0C) && ((SA1 & 0xC0) == 0x80)) || // check Byte 1 (one finger pressed)
+ (((SA1 & 0xC0) != 0x80) && (( A1 & 0xF0) != 0x00)) || // check Byte 2
+ (((SB1 & 0x3E) != 0x38) && ((SA1 & 0xC0) != 0x80)) || // check Byte 4
+ (((SB1 & 0x0E) != 0x08) && ((SA1 & 0xC0) == 0x80)) || // check Byte 4 (one finger pressed)
+ (((SA1 & 0xC0) != 0x80) && (( C1 & 0xF0) != 0x00)) ) // check Byte 5
+ // error detected
+
+For all the other ones, there are just a few constant bits:
+ if( ((packet[0] & 0x0C) != 0x04) ||
+ ((packet[3] & 0x0f) != 0x02) )
+ // error detected
+
+
+In case an error is detected, all the packets are shifted by one (and packet[0] is discarded).
+
+5.2.1 One/Three finger touch
~~~~~~~~~~~~~~~~
byte 0:
bit 7 6 5 4 3 2 1 0
- n1 n0 . . . . R L
+ n1 n0 w3 w2 . . R L
L, R = 1 when Left, Right mouse button pressed
n1..n0 = numbers of fingers on touchpad
@@ -333,24 +389,40 @@ byte 0:
byte 1:
bit 7 6 5 4 3 2 1 0
- . . . . . x10 x9 x8
+ p7 p6 p5 p4 . x10 x9 x8
byte 2:
bit 7 6 5 4 3 2 1 0
- x7 x6 x5 x4 x4 x2 x1 x0
+ x7 x6 x5 x4 x3 x2 x1 x0
x10..x0 = absolute x value (horizontal)
byte 3:
bit 7 6 5 4 3 2 1 0
- . . . . . . . .
+ n4 vf w1 w0 . . . b2
+
+ n4 = set if more than 3 fingers (only in 3 fingers mode)
+ vf = a kind of flag ? (only on EF123, 0 when finger is over one
+ of the buttons, 1 otherwise)
+ w3..w0 = width of the finger touch (not EF113)
+ b2 (on EF113 only, 0 otherwise), b2.R.L indicates one button pressed:
+ 0 = none
+ 1 = Left
+ 2 = Right
+ 3 = Middle (Left and Right)
+ 4 = Forward
+ 5 = Back
+ 6 = Another one
+ 7 = Another one
byte 4:
bit 7 6 5 4 3 2 1 0
- . . . . . . y9 y8
+ p3 p1 p2 p0 . . y9 y8
+
+ p7..p0 = pressure (not EF113)
byte 5:
@@ -363,6 +435,11 @@ byte 5:
4.2.2 Two finger touch
~~~~~~~~~~~~~~~~
+Note that the two pairs of coordinates are not exactly the coordinates of the
+two fingers, but only the pair of the lower-left and upper-right coordinates.
+So the actual fingers might be situated on the other diagonal of the square
+defined by these two points.
+
byte 0:
bit 7 6 5 4 3 2 1 0
@@ -376,14 +453,14 @@ byte 1:
bit 7 6 5 4 3 2 1 0
ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0
- ax8..ax0 = first finger absolute x value
+ ax8..ax0 = lower-left finger absolute x value
byte 2:
bit 7 6 5 4 3 2 1 0
ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0
- ay8..ay0 = first finger absolute y value
+ ay8..ay0 = lower-left finger absolute y value
byte 3:
@@ -395,11 +472,11 @@ byte 4:
bit 7 6 5 4 3 2 1 0
bx7 bx6 bx5 bx4 bx3 bx2 bx1 bx0
- bx8..bx0 = second finger absolute x value
+ bx8..bx0 = upper-right finger absolute x value
byte 5:
bit 7 6 5 4 3 2 1 0
by7 by8 by5 by4 by3 by2 by1 by0
- by8..by0 = second finger absolute y value
+ by8..by0 = upper-right finger absolute y value
diff --git a/Documentation/input/rotary-encoder.txt b/Documentation/input/rotary-encoder.txt
index 943e8f6f2b15..92e68bce13a4 100644
--- a/Documentation/input/rotary-encoder.txt
+++ b/Documentation/input/rotary-encoder.txt
@@ -9,6 +9,9 @@ peripherals with two wires. The outputs are phase-shifted by 90 degrees
and by triggering on falling and rising edges, the turn direction can
be determined.
+Some encoders have both outputs low in stable states, whereas others also have
+a stable state with both outputs high (half-period mode).
+
The phase diagram of these two outputs look like this:
_____ _____ _____
@@ -26,6 +29,8 @@ The phase diagram of these two outputs look like this:
|<-------->|
one step
+ |<-->|
+ one step (half-period mode)
For more information, please see
http://en.wikipedia.org/wiki/Rotary_encoder
@@ -34,6 +39,13 @@ For more information, please see
1. Events / state machine
-------------------------
+In half-period mode, state a) and c) above are used to determine the
+rotational direction based on the last stable state. Events are reported in
+states b) and d) given that the new stable state is different from the last
+(i.e. the rotation was not reversed half-way).
+
+Otherwise, the following apply:
+
a) Rising edge on channel A, channel B in low state
This state is used to recognize a clockwise turn
@@ -96,6 +108,7 @@ static struct rotary_encoder_platform_data my_rotary_encoder_info = {
.gpio_b = GPIO_ROTARY_B,
.inverted_a = 0,
.inverted_b = 0,
+ .half_period = false,
};
static struct platform_device rotary_encoder_device = {
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index a0a5d82b6b0b..3a46e360496d 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -166,7 +166,6 @@ Code Seq#(hex) Include File Comments
'T' all arch/x86/include/asm/ioctls.h conflict!
'T' C0-DF linux/if_tun.h conflict!
'U' all sound/asound.h conflict!
-'U' 00-0F drivers/media/video/uvc/uvcvideo.h conflict!
'U' 00-CF linux/uinput.h conflict!
'U' 00-EF linux/usbdevice_fs.h
'U' C0-CF drivers/bluetooth/hci_uart.h
@@ -259,6 +258,7 @@ Code Seq#(hex) Include File Comments
't' 80-8F linux/isdn_ppp.h
't' 90 linux/toshiba.h
'u' 00-1F linux/smb_fs.h gone
+'u' 20-3F linux/uvcvideo.h USB video class host driver
'v' 00-1F linux/ext2_fs.h conflict!
'v' 00-1F linux/fs.h conflict!
'v' 00-0F linux/sonypi.h conflict!
@@ -304,6 +304,7 @@ Code Seq#(hex) Include File Comments
0xB0 all RATIO devices in development:
<mailto:vgo@ratio.de>
0xB1 00-1F PPPoX <mailto:mostrows@styx.uwaterloo.ca>
+0xB3 00 linux/mmc/ioctl.h
0xC0 00-0F linux/usb/iowarrior.h
0xCB 00-1F CBM serial IEC bus in development:
<mailto:michael.klein@puffin.lb.shuttle.de>
diff --git a/Documentation/ja_JP/HOWTO b/Documentation/ja_JP/HOWTO
index b63301a03811..050d37fe6d40 100644
--- a/Documentation/ja_JP/HOWTO
+++ b/Documentation/ja_JP/HOWTO
@@ -11,14 +11,14 @@ for non English (read: Japanese) speakers and is not intended as a
fork. So if you have any comments or updates for this file, please try
to update the original English file first.
-Last Updated: 2008/10/24
+Last Updated: 2011/03/31
==================================
ã“れã¯ã€
-linux-2.6.28/Documentation/HOWTO
+linux-2.6.38/Documentation/HOWTO
ã®å’Œè¨³ã§ã™ã€‚
翻訳団体: JF プロジェクト < http://www.linux.or.jp/JF/ >
-翻訳日: 2008/10/24
+翻訳日: 2011/3/28
翻訳者: Tsugikazu Shibata <tshibata at ab dot jp dot nec dot com>
校正者: æ¾å€‰ã•ã‚“ <nbh--mats at nifty dot com>
å°æž— é›…å…¸ã•ã‚“ (Masanori Kobayasi) <zap03216 at nifty dot ne dot jp>
@@ -256,8 +256,8 @@ Linux カーãƒãƒ«ã®é–‹ç™ºãƒ—ロセスã¯ç¾åœ¨å¹¾ã¤ã‹ã®ç•°ãªã‚‹ãƒ¡ã‚¤ãƒ³ã‚
- メイン㮠2.6.x カーãƒãƒ«ãƒ„リー
- 2.6.x.y -stable カーãƒãƒ«ãƒ„リー
- 2.6.x -git カーãƒãƒ«ãƒ‘ッãƒ
- - 2.6.x -mm カーãƒãƒ«ãƒ‘ッãƒ
- サブシステム毎ã®ã‚«ãƒ¼ãƒãƒ«ãƒ„リーã¨ãƒ‘ッãƒ
+ - çµ±åˆãƒ†ã‚¹ãƒˆã®ãŸã‚ã® 2.6.x -next カーãƒãƒ«ãƒ„リー
2.6.x カーãƒãƒ«ãƒ„リー
-----------------
@@ -268,9 +268,9 @@ Linux カーãƒãƒ«ã®é–‹ç™ºãƒ—ロセスã¯ç¾åœ¨å¹¾ã¤ã‹ã®ç•°ãªã‚‹ãƒ¡ã‚¤ãƒ³ã‚
- æ–°ã—ã„カーãƒãƒ«ãŒãƒªãƒªãƒ¼ã‚¹ã•れãŸç›´å¾Œã«ã€2週間ã®ç‰¹åˆ¥æœŸé–“ãŒè¨­ã‘られã€
ã“ã®æœŸé–“中ã«ã€ãƒ¡ãƒ³ãƒ†ãƒŠé”㯠Linus ã«å¤§ããªå·®åˆ†ã‚’é€ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚
- ã“ã®ã‚ˆã†ãªå·®åˆ†ã¯é€šå¸¸ -mm カーãƒãƒ«ã«æ•°é€±é–“å«ã¾ã‚Œã¦ããŸãƒ‘ッãƒã§ã™ã€‚
+ ã“ã®ã‚ˆã†ãªå·®åˆ†ã¯é€šå¸¸ -next カーãƒãƒ«ã«æ•°é€±é–“å«ã¾ã‚Œã¦ããŸãƒ‘ッãƒã§ã™ã€‚
大ããªå¤‰æ›´ã¯ git(カーãƒãƒ«ã®ã‚½ãƒ¼ã‚¹ç®¡ç†ãƒ„ールã€è©³ç´°ã¯
- http://git.or.cz/ å‚ç…§) を使ã£ã¦é€ã‚‹ã®ãŒå¥½ã¾ã—ã„やり方ã§ã™ãŒã€ãƒ‘ッ
+ http://git-scm.com/ å‚ç…§) を使ã£ã¦é€ã‚‹ã®ãŒå¥½ã¾ã—ã„やり方ã§ã™ãŒã€ãƒ‘ッ
ãƒãƒ•ァイルã®å½¢å¼ã®ã¾ã¾é€ã‚‹ã®ã§ã‚‚å分ã§ã™ã€‚
- 2週間後ã€-rc1 カーãƒãƒ«ãŒãƒªãƒªãƒ¼ã‚¹ã•れã€ã“ã®å¾Œã«ã¯ã‚«ãƒ¼ãƒãƒ«å…¨ä½“ã®å®‰å®š
@@ -333,86 +333,44 @@ git リãƒã‚¸ãƒˆãƒªã§ç®¡ç†ã•れã¦ã„ã‚‹Linus ã®ã‚«ãƒ¼ãƒãƒ«ãƒ„ãƒªãƒ¼ã®æ¯Žæ
れ㯠-rc カーãƒãƒ«ã¨æ¯”ã¹ã¦ã€ãƒ‘ッãƒãŒå¤§ä¸ˆå¤«ã‹ã©ã†ã‹ã‚‚確èªã—ãªã„ã§è‡ªå‹•çš„
ã«ç”Ÿæˆã•れるã®ã§ã€ã‚ˆã‚Šå®Ÿé¨“çš„ã§ã™ã€‚
-2.6.x -mm カーãƒãƒ«ãƒ‘ッãƒ
-------------------------
-
-Andrew Morton ã«ã‚ˆã£ã¦ãƒªãƒªãƒ¼ã‚¹ã•れる実験的ãªã‚«ãƒ¼ãƒãƒ«ãƒ‘ッãƒç¾¤ã§ã™ã€‚
-Andrew ã¯å€‹åˆ¥ã®ã‚µãƒ–システムカーãƒãƒ«ãƒ„リーã¨ãƒ‘ッãƒã‚’å…¨ã¦é›†ã‚ã¦ãã¦
-linux-kernel メーリングリストã§åŽé›†ã•れãŸå¤šæ•°ã®ãƒ‘ッãƒã¨åŒæ™‚ã«ä¸€ã¤ã«ã¾
-ã¨ã‚ã¾ã™ã€‚
-ã“ã®ãƒ„ãƒªãƒ¼ã¯æ–°æ©Ÿèƒ½ã¨ãƒ‘ッãƒãŒæ¤œè¨¼ã•れる場ã¨ãªã‚Šã¾ã™ã€‚ã‚る期間ã®é–“パッãƒ
-㌠-mm ã«å…¥ã£ã¦ä¾¡å€¤ã‚’証明ã•れãŸã‚‰ã€Andrew やサブシステムメンテナãŒã€
-メインラインã¸å…¥ã‚Œã‚‹ã‚ˆã†ã« Linus ã«ãƒ—ッシュã—ã¾ã™ã€‚
-
-メインカーãƒãƒ«ãƒ„リーã«å«ã‚ã‚‹ãŸã‚ã« Linus ã«é€ã‚‹å‰ã«ã€ã™ã¹ã¦ã®æ–°ã—ã„パッ
-ãƒãŒ -mm ツリーã§ãƒ†ã‚¹ãƒˆã•れるã“ã¨ãŒå¼·ã推奨ã•れã¦ã„ã¾ã™ã€‚マージウィン
-ドウãŒé–‹ãå‰ã« -mm ツリーã«ç¾ã‚Œãªã‹ã£ãŸãƒ‘ッãƒã¯ãƒ¡ã‚¤ãƒ³ãƒ©ã‚¤ãƒ³ã«ãƒžãƒ¼ã‚¸ã•
-れるã“ã¨ã¯å›°é›£ã«ãªã‚Šã¾ã™ã€‚
-
-ã“れらã®ã‚«ãƒ¼ãƒãƒ«ã¯å®‰å®šã—ã¦å‹•作ã™ã¹ãシステムã¨ã—ã¦ä½¿ã†ã®ã«ã¯é©åˆ‡ã§ã¯ã‚
-りã¾ã›ã‚“ã—ã€ã‚«ãƒ¼ãƒãƒ«ãƒ–ランãƒã®ä¸­ã§ã‚‚ã‚‚ã£ã¨ã‚‚動作ã«ãƒªã‚¹ã‚¯ãŒé«˜ã„ã‚‚ã®ã§ã™ã€‚
-
-ã‚‚ã—ã‚ãªãŸãŒã€ã‚«ãƒ¼ãƒãƒ«é–‹ç™ºãƒ—ãƒ­ã‚»ã‚¹ã®æ”¯æ´ã‚’ã—ãŸã„ã¨æ€ã£ã¦ã„ã‚‹ã®ã§ã‚れã°ã€
-ã©ã†ãžã“れらã®ã‚«ãƒ¼ãƒãƒ«ãƒªãƒªãƒ¼ã‚¹ã‚’テストã«ä½¿ã£ã¦ã¿ã¦ã€ãã—ã¦ã‚‚ã—å•題ãŒã‚
-れã°ã€ã¾ãŸã‚‚ã—å…¨ã¦ãŒæ­£ã—ã動作ã—ãŸã¨ã—ã¦ã‚‚ã€linux-kernel メーリングリ
-ストã«ãƒ•ィードãƒãƒƒã‚¯ã‚’æä¾›ã—ã¦ãã ã•ã„。
-
-ã™ã¹ã¦ã®ä»–ã®å®Ÿé¨“的パッãƒã«åŠ ãˆã¦ã€ã“れらã®ã‚«ãƒ¼ãƒãƒ«ã¯é€šå¸¸ãƒªãƒªãƒ¼ã‚¹æ™‚点ã§
-メインライン㮠-git カーãƒãƒ«ã«å«ã¾ã‚Œã‚‹å…¨ã¦ã®å¤‰æ›´ã‚‚å«ã‚“ã§ã„ã¾ã™ã€‚
-
--mm カーãƒãƒ«ã¯æ±ºã¾ã£ãŸã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã§ã¯ãƒªãƒªãƒ¼ã‚¹ã•れã¾ã›ã‚“ã€ã—ã‹ã—通常幾
-ã¤ã‹ã® -mm カーãƒãƒ« (1 ã‹ã‚‰ 3 ãŒæ™®é€šï¼‰ãŒå„-rc カーãƒãƒ«ã®é–“ã«ãƒªãƒªãƒ¼ã‚¹ã•
-れã¾ã™ã€‚
-
サブシステム毎ã®ã‚«ãƒ¼ãƒãƒ«ãƒ„リーã¨ãƒ‘ッãƒ
-------------------------------------------
-カーãƒãƒ«ã®æ§˜ã€…ãªé ˜åŸŸã§ä½•ãŒèµ·ãã¦ã„ã‚‹ã‹ã‚’見られるよã†ã«ã™ã‚‹ãŸã‚ã€å¤šãã®
-カーãƒãƒ«ã‚µãƒ–システム開発者ã¯å½¼ã‚‰ã®é–‹ç™ºãƒ„リーを公開ã—ã¦ã„ã¾ã™ã€‚ã“れらã®
-ツリーã¯èª¬æ˜Žã—ãŸã‚ˆã†ã« -mm カーãƒãƒ«ãƒªãƒªãƒ¼ã‚¹ã«å…¥ã‚Œè¾¼ã¾ã‚Œã¾ã™ã€‚
-
-以下ã¯ã•ã¾ã–ã¾ãªã‚«ãƒ¼ãƒãƒ«ãƒ„リーã®ä¸­ã®ã„ãã¤ã‹ã®ãƒªã‚¹ãƒˆ-
-
- git ツリー-
- - Kbuild ã®é–‹ç™ºãƒ„リーã€Sam Ravnborg <sam@ravnborg.org>
- git.kernel.org:/pub/scm/linux/kernel/git/sam/kbuild.git
-
- - ACPI ã®é–‹ç™ºãƒ„リー〠Len Brown <len.brown@intel.com>
- git.kernel.org:/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.git
-
- - Block ã®é–‹ç™ºãƒ„リーã€Jens Axboe <axboe@suse.de>
- git.kernel.org:/pub/scm/linux/kernel/git/axboe/linux-2.6-block.git
-
- - DRM ã®é–‹ç™ºãƒ„リーã€Dave Airlie <airlied@linux.ie>
- git.kernel.org:/pub/scm/linux/kernel/git/airlied/drm-2.6.git
-
- - ia64 ã®é–‹ç™ºãƒ„リーã€Tony Luck <tony.luck@intel.com>
- git.kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git
-
- - infiniband, Roland Dreier <rolandd@cisco.com>
- git.kernel.org:/pub/scm/linux/kernel/git/roland/infiniband.git
-
- - libata, Jeff Garzik <jgarzik@pobox.com>
- git.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev.git
-
- - ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãƒ‰ãƒ©ã‚¤ãƒ, Jeff Garzik <jgarzik@pobox.com>
- git.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git
-
- - pcmcia, Dominik Brodowski <linux@dominikbrodowski.net>
- git.kernel.org:/pub/scm/linux/kernel/git/brodo/pcmcia-2.6.git
-
- - SCSI, James Bottomley <James.Bottomley@hansenpartnership.com>
- git.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git
-
- - x86, Ingo Molnar <mingo@elte.hu>
- git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86.git
-
- quilt ツリー-
- - USB, ドライãƒã‚³ã‚¢ã¨ I2C, Greg Kroah-Hartman <gregkh@suse.de>
- kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
+ãれãžã‚Œã®ã‚«ãƒ¼ãƒãƒ«ã‚µãƒ–システムã®ãƒ¡ãƒ³ãƒ†ãƒŠé”㯠--- ãã—ã¦å¤šãã®ã‚«ãƒ¼ãƒãƒ«
+サブシステムã®é–‹ç™ºè€…é”ã‚‚ --- å„è‡ªã®æœ€æ–°ã®é–‹ç™ºçжæ³ã‚’ソースリãƒã‚¸ãƒˆãƒªã«
+公開ã—ã¦ã„ã¾ã™ã€‚ãã®ãŸã‚ã€è‡ªåˆ†ã¨ã¯ç•°ãªã‚‹é ˜åŸŸã®ã‚«ãƒ¼ãƒãƒ«ã§ä½•ãŒèµ·ãã¦ã„ã‚‹
+ã‹ã‚’ä»–ã®äººãŒè¦‹ã‚‰ã‚Œã‚‹ã‚ˆã†ã«ãªã£ã¦ã„ã¾ã™ã€‚é–‹ç™ºãŒæ—©ã進んã§ã„る領域ã§ã¯ã€
+開発者ã¯è‡ªèº«ã®æŠ•稿ãŒã©ã®ã‚µãƒ–システムカーãƒãƒ«ãƒ„リーを元ã«ã—ã¦ã„ã‚‹ã‹è³ªå•
+ã•れるã®ã§ã€ãã®æŠ•ç¨¿ã¨ã™ã§ã«é€²è¡Œä¸­ã®ä»–ã®ä½œæ¥­ã¨ã®è¡çªãŒé¿ã‘られã¾ã™ã€‚
+
+大部分ã®ã“れらã®ãƒªãƒã‚¸ãƒˆãƒªã¯ git ツリーã§ã™ã€‚ã—ã‹ã—ãã®ä»–ã® SCM ã‚„
+quilt シリーズã¨ã—ã¦å…¬é–‹ã•れã¦ã„るパッãƒã‚­ãƒ¥ãƒ¼ã‚‚使ã‚れã¦ã„ã¾ã™ã€‚ã“れら
+ã®ã‚µãƒ–システムリãƒã‚¸ãƒˆãƒªã®ã‚¢ãƒ‰ãƒ¬ã‚¹ã¯ MAINTAINERS ファイルã«ãƒªã‚¹ãƒˆã•れ
+ã¦ã„ã¾ã™ã€‚ã“れらã®å¤šã㯠http://git.kernel.org/ ã§å‚ç…§ã™ã‚‹ã“ã¨ãŒã§ãã¾
+ã™ã€‚
- ãã®ä»–ã®ã‚«ãƒ¼ãƒãƒ«ãƒ„リー㯠http://git.kernel.org/ 㨠MAINTAINERS ファ
- イルã«ä¸€è¦§è¡¨ãŒã‚りã¾ã™ã€‚
+ææ¡ˆã•れãŸãƒ‘ッãƒãŒã“ã®ã‚ˆã†ãªã‚µãƒ–システムツリーã«ã‚³ãƒŸãƒƒãƒˆã•れるå‰ã«ã€ãƒ¡ãƒ¼
+リングリストã§äº‹å‰ã«ãƒ¬ãƒ“ューã«ã‹ã‘られã¾ã™ï¼ˆä»¥ä¸‹ã®å¯¾å¿œã™ã‚‹ã‚»ã‚¯ã‚·ãƒ§ãƒ³ã‚’
+å‚照)。ã„ãã¤ã‹ã®ã‚«ãƒ¼ãƒãƒ«ã‚µãƒ–システムã§ã¯ã€ã“ã®ãƒ¬ãƒ“ュー㯠patchwork
+ã¨ã„ã†ãƒ„ールã«ã‚ˆã£ã¦è¿½è·¡ã•れã¾ã™ã€‚Patchwork 㯠web インターフェイスã«
+よã£ã¦ãƒ‘ãƒƒãƒæŠ•ç¨¿ã®è¡¨ç¤ºã€ãƒ‘ッãƒã¸ã®ã‚³ãƒ¡ãƒ³ãƒˆä»˜ã‘や改訂ãªã©ãŒã§ãã€ãã—ã¦
+メンテナã¯ãƒ‘ッãƒã«å¯¾ã—ã¦ã€ãƒ¬ãƒ“ュー中ã€å—付済ã¿ã€æ‹’å¦ã¨ã„ã†ã‚ˆã†ãªãƒžãƒ¼ã‚¯
+ã‚’ã¤ã‘ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚大部分ã®ã“れら㮠patchwork ã®ã‚µã‚¤ãƒˆã¯
+http://patchwork.kernel.org/ ã§ãƒªã‚¹ãƒˆã•れã¦ã„ã¾ã™ã€‚
+
+çµ±åˆãƒ†ã‚¹ãƒˆã®ãŸã‚ã® 2.6.x -next カーãƒãƒ«ãƒ„リー
+---------------------------------------------
+
+ã‚µãƒ–ã‚·ã‚¹ãƒ†ãƒ ãƒ„ãƒªãƒ¼ã®æ›´æ–°å†…容ãŒãƒ¡ã‚¤ãƒ³ãƒ©ã‚¤ãƒ³ã® 2.6.x ツリーã«ãƒžãƒ¼ã‚¸ã•れ
+ã‚‹å‰ã«ã€ãれらã¯çµ±åˆãƒ†ã‚¹ãƒˆã•れる必è¦ãŒã‚りã¾ã™ã€‚ã“ã®ç›®çš„ã®ãŸã‚ã€å®Ÿè³ªçš„
+ã«å…¨ã‚µãƒ–システムツリーã‹ã‚‰ã»ã¼æ¯Žæ—¥ãƒ—ルã•れã¦ã§ãる特別ãªãƒ†ã‚¹ãƒˆç”¨ã®ãƒª
+ãƒã‚¸ãƒˆãƒªãŒå­˜åœ¨ã—ã¾ã™-
+ http://git.kernel.org/?p=linux/kernel/git/sfr/linux-next.git
+ http://linux.f-seidel.de/linux-next/pmwiki/
+
+ã“ã®ã‚„り方ã«ã‚ˆã£ã¦ã€-next カーãƒãƒ«ã¯æ¬¡ã®ãƒžãƒ¼ã‚¸æ©Ÿä¼šã§ã©ã‚“ãªã‚‚ã®ãŒãƒ¡ã‚¤ãƒ³
+ラインカーãƒãƒ«ã«ãƒžãƒ¼ã‚¸ã•れるã‹ã€ãŠãŠã¾ã‹ãªã®å±•望をæä¾›ã—ã¾ã™ã€‚-next
+カーãƒãƒ«ã®å®Ÿè¡Œãƒ†ã‚¹ãƒˆã‚’行ã†å†’険好ããªãƒ†ã‚¹ã‚¿ãƒ¼ã¯å¤§ã„ã«æ­“迎ã•れã¾ã™
ãƒã‚°ãƒ¬ãƒãƒ¼ãƒˆ
-------------
@@ -673,10 +631,9 @@ Linux カーãƒãƒ«ã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ã¯ã€ä¸€åº¦ã«å¤§é‡ã®ã‚³ãƒ¼ãƒ‰ã®å¡Šã‚’å–
ã˜ã¨ã“ã‚ã‹ã‚‰ã‚¹ã‚¿ãƒ¼ãƒˆã—ãŸã®ã§ã™ã‹ã‚‰ã€‚
Paolo Ciarrocchi ã«æ„Ÿè¬ã€å½¼ã¯å½¼ã®æ›¸ã„㟠"Development Process"
-(http://linux.tar.bz/articles/2.6-development_process)セクショ
-ンをã“ã®ãƒ†ã‚­ã‚¹ãƒˆã®åŽŸåž‹ã«ã™ã‚‹ã“ã¨ã‚’許å¯ã—ã¦ãれã¾ã—ãŸã€‚
-Rundy Dunlap 㨠Gerrit Huizenga ã¯ãƒ¡ãƒ¼ãƒªãƒ³ã‚°ãƒªã‚¹ãƒˆã§ã‚„ã‚‹ã¹ãã“ã¨ã¨ã‚„ã£
-ã¦ã¯ã„ã‘ãªã„ã“ã¨ã®ãƒªã‚¹ãƒˆã‚’æä¾›ã—ã¦ãれã¾ã—ãŸã€‚
+(http://lwn.net/Articles/94386/) セクションをã“ã®ãƒ†ã‚­ã‚¹ãƒˆã®åŽŸåž‹ã«ã™ã‚‹
+ã“ã¨ã‚’許å¯ã—ã¦ãれã¾ã—ãŸã€‚Rundy Dunlap 㨠Gerrit Huizenga ã¯ãƒ¡ãƒ¼ãƒªãƒ³ã‚°
+リストã§ã‚„ã‚‹ã¹ãã“ã¨ã¨ã‚„ã£ã¦ã¯ã„ã‘ãªã„ã“ã¨ã®ãƒªã‚¹ãƒˆã‚’æä¾›ã—ã¦ãれã¾ã—ãŸã€‚
以下ã®äººã€…ã®ãƒ¬ãƒ“ューã€ã‚³ãƒ¡ãƒ³ãƒˆã€è²¢çŒ®ã«æ„Ÿè¬ã€‚
Pat Mochel, Hanna Linder, Randy Dunlap, Kay Sievers,
Vojtech Pavlik, Jan Kara, Josh Boyer, Kees Cook, Andrew Morton, Andi
diff --git a/Documentation/kbuild/kbuild.txt b/Documentation/kbuild/kbuild.txt
index 7c2a89ba674c..68e32bb6bd80 100644
--- a/Documentation/kbuild/kbuild.txt
+++ b/Documentation/kbuild/kbuild.txt
@@ -201,3 +201,16 @@ KBUILD_ENABLE_EXTRA_GCC_CHECKS
--------------------------------------------------
If enabled over the make command line with "W=1", it turns on additional
gcc -W... options for more extensive build-time checking.
+
+KBUILD_BUILD_TIMESTAMP
+--------------------------------------------------
+Setting this to a date string overrides the timestamp used in the
+UTS_VERSION definition (uname -v in the running kernel). The value has to
+be a string that can be passed to date -d. The default value
+is the output of the date command at one point during build.
+
+KBUILD_BUILD_USER, KBUILD_BUILD_HOST
+--------------------------------------------------
+These two variables allow to override the user@host string displayed during
+boot and in /proc/version. The default value is the output of the commands
+whoami and host, respectively.
diff --git a/Documentation/kbuild/kconfig-language.txt b/Documentation/kbuild/kconfig-language.txt
index b507d61fd41c..44e2649fbb29 100644
--- a/Documentation/kbuild/kconfig-language.txt
+++ b/Documentation/kbuild/kconfig-language.txt
@@ -113,6 +113,13 @@ applicable everywhere (see syntax).
That will limit the usefulness but on the other hand avoid
the illegal configurations all over.
+- limiting menu display: "visible if" <expr>
+ This attribute is only applicable to menu blocks, if the condition is
+ false, the menu block is not displayed to the user (the symbols
+ contained there can still be selected by other symbols, though). It is
+ similar to a conditional "prompt" attribude for individual menu
+ entries. Default value of "visible" is true.
+
- numerical ranges: "range" <symbol> <symbol> ["if" <expr>]
This allows to limit the range of possible input values for int
and hex symbols. The user can only input a value which is larger than
@@ -303,7 +310,8 @@ menu:
"endmenu"
This defines a menu block, see "Menu structure" above for more
-information. The only possible options are dependencies.
+information. The only possible options are dependencies and "visible"
+attributes.
if:
@@ -381,3 +389,25 @@ config FOO
limits FOO to module (=m) or disabled (=n).
+Kconfig symbol existence
+~~~~~~~~~~~~~~~~~~~~~~~~
+The following two methods produce the same kconfig symbol dependencies
+but differ greatly in kconfig symbol existence (production) in the
+generated config file.
+
+case 1:
+
+config FOO
+ tristate "about foo"
+ depends on BAR
+
+vs. case 2:
+
+if BAR
+config FOO
+ tristate "about foo"
+endif
+
+In case 1, the symbol FOO will always exist in the config file (given
+no other dependencies). In case 2, the symbol FOO will only exist in
+the config file if BAR is enabled.
diff --git a/Documentation/kbuild/kconfig.txt b/Documentation/kbuild/kconfig.txt
index cca46b1a0f6c..c313d71324b4 100644
--- a/Documentation/kbuild/kconfig.txt
+++ b/Documentation/kbuild/kconfig.txt
@@ -48,11 +48,6 @@ KCONFIG_OVERWRITECONFIG
If you set KCONFIG_OVERWRITECONFIG in the environment, Kconfig will not
break symlinks when .config is a symlink to somewhere else.
-KCONFIG_NOTIMESTAMP
---------------------------------------------------
-If this environment variable exists and is non-null, the timestamp line
-in generated .config files is omitted.
-
______________________________________________________________________
Environment variables for '{allyes/allmod/allno/rand}config'
diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt
index 5d145bb443c0..47435e56c5da 100644
--- a/Documentation/kbuild/makefiles.txt
+++ b/Documentation/kbuild/makefiles.txt
@@ -40,11 +40,13 @@ This document describes the Linux kernel Makefiles.
--- 6.6 Commands useful for building a boot image
--- 6.7 Custom kbuild commands
--- 6.8 Preprocessing linker scripts
+ --- 6.9 Generic header files
=== 7 Kbuild syntax for exported headers
--- 7.1 header-y
--- 7.2 objhdr-y
--- 7.3 destination-y
+ --- 7.4 generic-y
=== 8 Kbuild Variables
=== 9 Makefile language
@@ -499,6 +501,18 @@ more details, with real examples.
gcc >= 3.00. For gcc < 3.00, -malign-functions=4 is used.
Note: cc-option-align uses KBUILD_CFLAGS for $(CC) options
+ cc-disable-warning
+ cc-disable-warning checks if gcc supports a given warning and returns
+ the commandline switch to disable it. This special function is needed,
+ because gcc 4.4 and later accept any unknown -Wno-* option and only
+ warn about it if there is another warning in the source file.
+
+ Example:
+ KBUILD_CFLAGS += $(call cc-disable-warning, unused-but-set-variable)
+
+ In the above example, -Wno-unused-but-set-variable will be added to
+ KBUILD_CFLAGS only if gcc really accepts it.
+
cc-version
cc-version returns a numerical version of the $(CC) compiler version.
The format is <major><minor> where both are two digits. So for example
@@ -955,6 +969,11 @@ When kbuild executes, the following steps are followed (roughly):
used when linking modules. This is often a linker script.
From commandline LDFLAGS_MODULE shall be used (see kbuild.txt).
+ KBUILD_ARFLAGS Options for $(AR) when creating archives
+
+ $(KBUILD_ARFLAGS) set by the top level Makefile to "D" (deterministic
+ mode) if this option is supported by $(AR).
+
--- 6.2 Add prerequisites to archprepare:
The archprepare: rule is used to list prerequisites that need to be
@@ -1209,6 +1228,14 @@ When kbuild executes, the following steps are followed (roughly):
The kbuild infrastructure for *lds file are used in several
architecture-specific files.
+--- 6.9 Generic header files
+
+ The directory include/asm-generic contains the header files
+ that may be shared between individual architectures.
+ The recommended approach how to use a generic header file is
+ to list the file in the Kbuild file.
+ See "7.4 generic-y" for further info on syntax etc.
+
=== 7 Kbuild syntax for exported headers
The kernel include a set of headers that is exported to userspace.
@@ -1265,6 +1292,32 @@ See subsequent chapter for the syntax of the Kbuild file.
In the example above all exported headers in the Kbuild file
will be located in the directory "include/linux" when exported.
+ --- 7.4 generic-y
+
+ If an architecture uses a verbatim copy of a header from
+ include/asm-generic then this is listed in the file
+ arch/$(ARCH)/include/asm/Kbuild like this:
+
+ Example:
+ #arch/x86/include/asm/Kbuild
+ generic-y += termios.h
+ generic-y += rtc.h
+
+ During the prepare phase of the build a wrapper include
+ file is generated in the directory:
+
+ arch/$(ARCH)/include/generated/asm
+
+ When a header is exported where the architecture uses
+ the generic header a similar wrapper is generated as part
+ of the set of exported headers in the directory:
+
+ usr/include/asm
+
+ The generated wrapper will in both cases look like the following:
+
+ Example: termios.h
+ #include <asm-generic/termios.h>
=== 8 Kbuild Variables
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index cc85a9278190..5438a2d7907f 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -245,7 +245,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
acpi_sleep= [HW,ACPI] Sleep options
Format: { s3_bios, s3_mode, s3_beep, s4_nohwsig,
- old_ordering, s4_nonvs, sci_force_enable }
+ old_ordering, nonvs, sci_force_enable }
See Documentation/power/video.txt for information on
s3_bios and s3_mode.
s3_beep is for debugging; it makes the PC's speaker beep
@@ -1664,6 +1664,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
noexec=on: enable non-executable mappings (default)
noexec=off: disable non-executable mappings
+ nosmep [X86]
+ Disable SMEP (Supervisor Mode Execution Protection)
+ even if it is supported by processor.
+
noexec32 [X86-64]
This affects only 32-bit executables.
noexec32=on: enable non-executable mappings (default)
@@ -1773,9 +1777,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
nosoftlockup [KNL] Disable the soft-lockup detector.
- noswapaccount [KNL] Disable accounting of swap in memory resource
- controller. (See Documentation/cgroups/memory.txt)
-
nosync [HW,M68K] Disables sync negotiation for all devices.
notsc [BUGS=X86-32] Disable Time Stamp Counter
@@ -2581,6 +2582,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
bytes of sense data);
c = FIX_CAPACITY (decrease the reported
device capacity by one sector);
+ d = NO_READ_DISC_INFO (don't use
+ READ_DISC_INFO command);
+ e = NO_READ_CAPACITY_16 (don't use
+ READ_CAPACITY_16 command);
h = CAPACITY_HEURISTICS (decrease the
reported device capacity by one
sector if the number is odd);
diff --git a/Documentation/lockstat.txt b/Documentation/lockstat.txt
index 65f4c795015d..9c0a80d17a23 100644
--- a/Documentation/lockstat.txt
+++ b/Documentation/lockstat.txt
@@ -136,7 +136,7 @@ View the top contending locks:
dcache_lock: 1037 1161 0.38 45.32 774.51 6611 243371 0.15 306.48 77387.24
&inode->i_mutex: 161 286 18446744073709 62882.54 1244614.55 3653 20598 18446744073709 62318.60 1693822.74
&zone->lru_lock: 94 94 0.53 7.33 92.10 4366 32690 0.29 59.81 16350.06
- &inode->i_data.i_mmap_lock: 79 79 0.40 3.77 53.03 11779 87755 0.28 116.93 29898.44
+ &inode->i_data.i_mmap_mutex: 79 79 0.40 3.77 53.03 11779 87755 0.28 116.93 29898.44
&q->__queue_lock: 48 50 0.52 31.62 86.31 774 13131 0.17 113.08 12277.52
&rq->rq_lock_key: 43 47 0.74 68.50 170.63 3706 33929 0.22 107.99 17460.62
&rq->rq_lock_key#2: 39 46 0.75 6.68 49.03 2979 32292 0.17 125.17 17137.63
diff --git a/Documentation/mmc/00-INDEX b/Documentation/mmc/00-INDEX
index fca586f5b853..93dd7a714075 100644
--- a/Documentation/mmc/00-INDEX
+++ b/Documentation/mmc/00-INDEX
@@ -2,3 +2,5 @@
- this file
mmc-dev-attrs.txt
- info on SD and MMC device attributes
+mmc-dev-parts.txt
+ - info on SD and MMC device partitions
diff --git a/Documentation/mmc/mmc-dev-attrs.txt b/Documentation/mmc/mmc-dev-attrs.txt
index ff2bd685bced..8898a95b41e5 100644
--- a/Documentation/mmc/mmc-dev-attrs.txt
+++ b/Documentation/mmc/mmc-dev-attrs.txt
@@ -1,3 +1,13 @@
+SD and MMC Block Device Attributes
+==================================
+
+These attributes are defined for the block devices associated with the
+SD or MMC device.
+
+The following attributes are read/write.
+
+ force_ro Enforce read-only access even if write protect switch is off.
+
SD and MMC Device Attributes
============================
diff --git a/Documentation/mmc/mmc-dev-parts.txt b/Documentation/mmc/mmc-dev-parts.txt
new file mode 100644
index 000000000000..2db28b8e662f
--- /dev/null
+++ b/Documentation/mmc/mmc-dev-parts.txt
@@ -0,0 +1,27 @@
+SD and MMC Device Partitions
+============================
+
+Device partitions are additional logical block devices present on the
+SD/MMC device.
+
+As of this writing, MMC boot partitions as supported and exposed as
+/dev/mmcblkXboot0 and /dev/mmcblkXboot1, where X is the index of the
+parent /dev/mmcblkX.
+
+MMC Boot Partitions
+===================
+
+Read and write access is provided to the two MMC boot partitions. Due to
+the sensitive nature of the boot partition contents, which often store
+a bootloader or bootloader configuration tables crucial to booting the
+platform, write access is disabled by default to reduce the chance of
+accidental bricking.
+
+To enable write access to /dev/mmcblkXbootY, disable the forced read-only
+access with:
+
+echo 0 > /sys/block/mmcblkXbootY/force_ro
+
+To re-enable read-only access:
+
+echo 1 > /sys/block/mmcblkXbootY/force_ro
diff --git a/Documentation/networking/batman-adv.txt b/Documentation/networking/batman-adv.txt
index ee496eb2f4a6..88d4afbdef98 100644
--- a/Documentation/networking/batman-adv.txt
+++ b/Documentation/networking/batman-adv.txt
@@ -1,4 +1,4 @@
-[state: 27-01-2011]
+[state: 17-04-2011]
BATMAN-ADV
----------
@@ -19,6 +19,7 @@ duce the overhead to a minimum. It does not depend on any (other)
network driver, and can be used on wifi as well as ethernet lan,
vpn, etc ... (anything with ethernet-style layer 2).
+
CONFIGURATION
-------------
@@ -160,13 +161,13 @@ face. Each entry can/has to have the following values:
-> "TQ mac value" - src mac's link quality towards mac address
of a neighbor originator's interface which
is being used for routing
--> "HNA mac" - HNA announced by source mac
+-> "TT mac" - TT announced by source mac
-> "PRIMARY" - this is a primary interface
-> "SEC mac" - secondary mac address of source
(requires preceding PRIMARY)
The TQ value has a range from 4 to 255 with 255 being the best.
-The HNA entries are showing which hosts are connected to the mesh
+The TT entries are showing which hosts are connected to the mesh
via bat0 or being bridged into the mesh network. The PRIMARY/SEC
values are only applied on primary interfaces
@@ -199,7 +200,7 @@ abled during run time. Following log_levels are defined:
0 - All debug output disabled
1 - Enable messages related to routing / flooding / broadcasting
-2 - Enable route or hna added / changed / deleted
+2 - Enable route or tt entry added / changed / deleted
3 - Enable all messages
The debug output can be changed at runtime using the file
@@ -207,7 +208,7 @@ The debug output can be changed at runtime using the file
# echo 2 > /sys/class/net/bat0/mesh/log_level
-will enable debug messages for when routes or HNAs change.
+will enable debug messages for when routes or TTs change.
BATCTL
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index e27202bb8d75..675612ff41ae 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -1,7 +1,7 @@
Linux Ethernet Bonding Driver HOWTO
- Latest update: 23 September 2009
+ Latest update: 27 April 2011
Initial release : Thomas Davis <tadavis at lbl.gov>
Corrections, HA extensions : 2000/10/03-15 :
@@ -585,25 +585,23 @@ mode
chosen.
num_grat_arp
-
- Specifies the number of gratuitous ARPs to be issued after a
- failover event. One gratuitous ARP is issued immediately after
- the failover, subsequent ARPs are sent at a rate of one per link
- monitor interval (arp_interval or miimon, whichever is active).
-
- The valid range is 0 - 255; the default value is 1. This option
- affects only the active-backup mode. This option was added for
- bonding version 3.3.0.
-
num_unsol_na
- Specifies the number of unsolicited IPv6 Neighbor Advertisements
- to be issued after a failover event. One unsolicited NA is issued
- immediately after the failover.
+ Specify the number of peer notifications (gratuitous ARPs and
+ unsolicited IPv6 Neighbor Advertisements) to be issued after a
+ failover event. As soon as the link is up on the new slave
+ (possibly immediately) a peer notification is sent on the
+ bonding device and each VLAN sub-device. This is repeated at
+ each link monitor interval (arp_interval or miimon, whichever
+ is active) if the number is greater than 1.
- The valid range is 0 - 255; the default value is 1. This option
- affects only the active-backup mode. This option was added for
- bonding version 3.4.0.
+ The valid range is 0 - 255; the default value is 1. These options
+ affect only the active-backup mode. These options were added for
+ bonding versions 3.3.0 and 3.4.0 respectively.
+
+ From Linux 2.6.40 and bonding version 3.7.1, these notifications
+ are generated by the ipv4 and ipv6 code and the numbers of
+ repetitions cannot be set independently.
primary
@@ -772,8 +770,17 @@ resend_igmp
a failover event. One membership report is issued immediately after
the failover, subsequent packets are sent in each 200ms interval.
- The valid range is 0 - 255; the default value is 1. This option
- was added for bonding version 3.7.0.
+ The valid range is 0 - 255; the default value is 1. A value of 0
+ prevents the IGMP membership report from being issued in response
+ to the failover event.
+
+ This option is useful for bonding modes balance-rr (0), active-backup
+ (1), balance-tlb (5) and balance-alb (6), in which a failover can
+ switch the IGMP traffic from one slave to another. Therefore a fresh
+ IGMP report must be issued to cause the switch to forward the incoming
+ IGMP traffic over the newly selected slave.
+
+ This option was added for bonding version 3.7.0.
3. Configuring Bonding Devices
==============================
diff --git a/Documentation/networking/igb.txt b/Documentation/networking/igb.txt
index 98953c0d5342..9a2a037194a5 100644
--- a/Documentation/networking/igb.txt
+++ b/Documentation/networking/igb.txt
@@ -93,6 +93,19 @@ Additional Configurations
REQUIREMENTS: MSI-X support is required for Multiqueue. If MSI-X is not
found, the system will fallback to MSI or to Legacy interrupts.
+ MAC and VLAN anti-spoofing feature
+ ----------------------------------
+ When a malicious driver attempts to send a spoofed packet, it is dropped by
+ the hardware and not transmitted. An interrupt is sent to the PF driver
+ notifying it of the spoof attempt.
+
+ When a spoofed packet is detected the PF driver will send the following
+ message to the system log (displayed by the "dmesg" command):
+
+ Spoof event(s) detected on VF(n)
+
+ Where n=the VF that attempted to do the spoofing.
+
Support
=======
diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt
index 1971bcf48a60..88880839ece4 100644
--- a/Documentation/power/devices.txt
+++ b/Documentation/power/devices.txt
@@ -279,11 +279,15 @@ When the system goes into the standby or memory sleep state, the phases are:
time.) Unlike the other suspend-related phases, during the prepare
phase the device tree is traversed top-down.
- The prepare phase uses only a bus callback. After the callback method
- returns, no new children may be registered below the device. The method
- may also prepare the device or driver in some way for the upcoming
- system power transition, but it should not put the device into a
- low-power state.
+ In addition to that, if device drivers need to allocate additional
+ memory to be able to hadle device suspend correctly, that should be
+ done in the prepare phase.
+
+ After the prepare callback method returns, no new children may be
+ registered below the device. The method may also prepare the device or
+ driver in some way for the upcoming system power transition (for
+ example, by allocating additional memory required for this purpose), but
+ it should not put the device into a low-power state.
2. The suspend methods should quiesce the device to stop it from performing
I/O. They also may save the device registers and put it into the
diff --git a/Documentation/power/notifiers.txt b/Documentation/power/notifiers.txt
index cf980709122a..c2a4a346c0d9 100644
--- a/Documentation/power/notifiers.txt
+++ b/Documentation/power/notifiers.txt
@@ -1,46 +1,41 @@
Suspend notifiers
- (C) 2007 Rafael J. Wysocki <rjw@sisk.pl>, GPL
-
-There are some operations that device drivers may want to carry out in their
-.suspend() routines, but shouldn't, because they can cause the hibernation or
-suspend to fail. For example, a driver may want to allocate a substantial amount
-of memory (like 50 MB) in .suspend(), but that shouldn't be done after the
-swsusp's memory shrinker has run.
-
-Also, there may be some operations, that subsystems want to carry out before a
-hibernation/suspend or after a restore/resume, requiring the system to be fully
-functional, so the drivers' .suspend() and .resume() routines are not suitable
-for this purpose. For example, device drivers may want to upload firmware to
-their devices after a restore from a hibernation image, but they cannot do it by
-calling request_firmware() from their .resume() routines (user land processes
-are frozen at this point). The solution may be to load the firmware into
-memory before processes are frozen and upload it from there in the .resume()
-routine. Of course, a hibernation notifier may be used for this purpose.
-
-The subsystems that have such needs can register suspend notifiers that will be
-called upon the following events by the suspend core:
+ (C) 2007-2011 Rafael J. Wysocki <rjw@sisk.pl>, GPL
+
+There are some operations that subsystems or drivers may want to carry out
+before hibernation/suspend or after restore/resume, but they require the system
+to be fully functional, so the drivers' and subsystems' .suspend() and .resume()
+or even .prepare() and .complete() callbacks are not suitable for this purpose.
+For example, device drivers may want to upload firmware to their devices after
+resume/restore, but they cannot do it by calling request_firmware() from their
+.resume() or .complete() routines (user land processes are frozen at these
+points). The solution may be to load the firmware into memory before processes
+are frozen and upload it from there in the .resume() routine.
+A suspend/hibernation notifier may be used for this purpose.
+
+The subsystems or drivers having such needs can register suspend notifiers that
+will be called upon the following events by the PM core:
PM_HIBERNATION_PREPARE The system is going to hibernate or suspend, tasks will
be frozen immediately.
PM_POST_HIBERNATION The system memory state has been restored from a
- hibernation image or an error occurred during the
- hibernation. Device drivers' .resume() callbacks have
+ hibernation image or an error occurred during
+ hibernation. Device drivers' restore callbacks have
been executed and tasks have been thawed.
PM_RESTORE_PREPARE The system is going to restore a hibernation image.
- If all goes well the restored kernel will issue a
+ If all goes well, the restored kernel will issue a
PM_POST_HIBERNATION notification.
-PM_POST_RESTORE An error occurred during the hibernation restore.
- Device drivers' .resume() callbacks have been executed
+PM_POST_RESTORE An error occurred during restore from hibernation.
+ Device drivers' restore callbacks have been executed
and tasks have been thawed.
-PM_SUSPEND_PREPARE The system is preparing for a suspend.
+PM_SUSPEND_PREPARE The system is preparing for suspend.
PM_POST_SUSPEND The system has just resumed or an error occurred during
- the suspend. Device drivers' .resume() callbacks have
- been executed and tasks have been thawed.
+ suspend. Device drivers' resume callbacks have been
+ executed and tasks have been thawed.
It is generally assumed that whatever the notifiers do for
PM_HIBERNATION_PREPARE, should be undone for PM_POST_HIBERNATION. Analogously,
diff --git a/Documentation/power/regulator/machine.txt b/Documentation/power/regulator/machine.txt
index bdec39b9bd75..b42419b52e44 100644
--- a/Documentation/power/regulator/machine.txt
+++ b/Documentation/power/regulator/machine.txt
@@ -53,11 +53,11 @@ static struct regulator_init_data regulator1_data = {
Regulator-1 supplies power to Regulator-2. This relationship must be registered
with the core so that Regulator-1 is also enabled when Consumer A enables its
-supply (Regulator-2). The supply regulator is set by the supply_regulator_dev
+supply (Regulator-2). The supply regulator is set by the supply_regulator
field below:-
static struct regulator_init_data regulator2_data = {
- .supply_regulator_dev = &platform_regulator1_device.dev,
+ .supply_regulator = "regulator_name",
.constraints = {
.min_uV = 1800000,
.max_uV = 2000000,
diff --git a/Documentation/pti/pti_intel_mid.txt b/Documentation/pti/pti_intel_mid.txt
new file mode 100644
index 000000000000..e7a5b6d1f7a9
--- /dev/null
+++ b/Documentation/pti/pti_intel_mid.txt
@@ -0,0 +1,99 @@
+The Intel MID PTI project is HW implemented in Intel Atom
+system-on-a-chip designs based on the Parallel Trace
+Interface for MIPI P1149.7 cJTAG standard. The kernel solution
+for this platform involves the following files:
+
+./include/linux/pti.h
+./drivers/.../n_tracesink.h
+./drivers/.../n_tracerouter.c
+./drivers/.../n_tracesink.c
+./drivers/.../pti.c
+
+pti.c is the driver that enables various debugging features
+popular on platforms from certain mobile manufacturers.
+n_tracerouter.c and n_tracesink.c allow extra system information to
+be collected and routed to the pti driver, such as trace
+debugging data from a modem. Although n_tracerouter
+and n_tracesink are a part of the complete PTI solution,
+these two line disciplines can work separately from
+pti.c and route any data stream from one /dev/tty node
+to another /dev/tty node via kernel-space. This provides
+a stable, reliable connection that will not break unless
+the user-space application shuts down (plus avoids
+kernel->user->kernel context switch overheads of routing
+data).
+
+An example debugging usage for this driver system:
+ *Hook /dev/ttyPTI0 to syslogd. Opening this port will also start
+ a console device to further capture debugging messages to PTI.
+ *Hook /dev/ttyPTI1 to modem debugging data to write to PTI HW.
+ This is where n_tracerouter and n_tracesink are used.
+ *Hook /dev/pti to a user-level debugging application for writing
+ to PTI HW.
+ *Use mipi_* Kernel Driver API in other device drivers for
+ debugging to PTI by first requesting a PTI write address via
+ mipi_request_masterchannel(1).
+
+Below is example pseudo-code on how a 'privileged' application
+can hook up n_tracerouter and n_tracesink to any tty on
+a system. 'Privileged' means the application has enough
+privileges to successfully manipulate the ldisc drivers
+but is not just blindly executing as 'root'. Keep in mind
+the use of ioctl(,TIOCSETD,) is not specific to the n_tracerouter
+and n_tracesink line discpline drivers but is a generic
+operation for a program to use a line discpline driver
+on a tty port other than the default n_tty.
+
+/////////// To hook up n_tracerouter and n_tracesink /////////
+
+// Note that n_tracerouter depends on n_tracesink.
+#include <errno.h>
+#define ONE_TTY "/dev/ttyOne"
+#define TWO_TTY "/dev/ttyTwo"
+
+// needed global to hand onto ldisc connection
+static int g_fd_source = -1;
+static int g_fd_sink = -1;
+
+// these two vars used to grab LDISC values from loaded ldisc drivers
+// in OS. Look at /proc/tty/ldiscs to get the right numbers from
+// the ldiscs loaded in the system.
+int source_ldisc_num, sink_ldisc_num = -1;
+int retval;
+
+g_fd_source = open(ONE_TTY, O_RDWR); // must be R/W
+g_fd_sink = open(TWO_TTY, O_RDWR); // must be R/W
+
+if (g_fd_source <= 0) || (g_fd_sink <= 0) {
+ // doubt you'll want to use these exact error lines of code
+ printf("Error on open(). errno: %d\n",errno);
+ return errno;
+}
+
+retval = ioctl(g_fd_sink, TIOCSETD, &sink_ldisc_num);
+if (retval < 0) {
+ printf("Error on ioctl(). errno: %d\n", errno);
+ return errno;
+}
+
+retval = ioctl(g_fd_source, TIOCSETD, &source_ldisc_num);
+if (retval < 0) {
+ printf("Error on ioctl(). errno: %d\n", errno);
+ return errno;
+}
+
+/////////// To disconnect n_tracerouter and n_tracesink ////////
+
+// First make sure data through the ldiscs has stopped.
+
+// Second, disconnect ldiscs. This provides a
+// little cleaner shutdown on tty stack.
+sink_ldisc_num = 0;
+source_ldisc_num = 0;
+ioctl(g_fd_uart, TIOCSETD, &sink_ldisc_num);
+ioctl(g_fd_gadget, TIOCSETD, &source_ldisc_num);
+
+// Three, program closes connection, and cleanup:
+close(g_fd_uart);
+close(g_fd_gadget);
+g_fd_uart = g_fd_gadget = NULL;
diff --git a/Documentation/ptp/ptp.txt b/Documentation/ptp/ptp.txt
new file mode 100644
index 000000000000..ae8fef86b832
--- /dev/null
+++ b/Documentation/ptp/ptp.txt
@@ -0,0 +1,89 @@
+
+* PTP hardware clock infrastructure for Linux
+
+ This patch set introduces support for IEEE 1588 PTP clocks in
+ Linux. Together with the SO_TIMESTAMPING socket options, this
+ presents a standardized method for developing PTP user space
+ programs, synchronizing Linux with external clocks, and using the
+ ancillary features of PTP hardware clocks.
+
+ A new class driver exports a kernel interface for specific clock
+ drivers and a user space interface. The infrastructure supports a
+ complete set of PTP hardware clock functionality.
+
+ + Basic clock operations
+ - Set time
+ - Get time
+ - Shift the clock by a given offset atomically
+ - Adjust clock frequency
+
+ + Ancillary clock features
+ - One short or periodic alarms, with signal delivery to user program
+ - Time stamp external events
+ - Period output signals configurable from user space
+ - Synchronization of the Linux system time via the PPS subsystem
+
+** PTP hardware clock kernel API
+
+ A PTP clock driver registers itself with the class driver. The
+ class driver handles all of the dealings with user space. The
+ author of a clock driver need only implement the details of
+ programming the clock hardware. The clock driver notifies the class
+ driver of asynchronous events (alarms and external time stamps) via
+ a simple message passing interface.
+
+ The class driver supports multiple PTP clock drivers. In normal use
+ cases, only one PTP clock is needed. However, for testing and
+ development, it can be useful to have more than one clock in a
+ single system, in order to allow performance comparisons.
+
+** PTP hardware clock user space API
+
+ The class driver also creates a character device for each
+ registered clock. User space can use an open file descriptor from
+ the character device as a POSIX clock id and may call
+ clock_gettime, clock_settime, and clock_adjtime. These calls
+ implement the basic clock operations.
+
+ User space programs may control the clock using standardized
+ ioctls. A program may query, enable, configure, and disable the
+ ancillary clock features. User space can receive time stamped
+ events via blocking read() and poll(). One shot and periodic
+ signals may be configured via the POSIX timer_settime() system
+ call.
+
+** Writing clock drivers
+
+ Clock drivers include include/linux/ptp_clock_kernel.h and register
+ themselves by presenting a 'struct ptp_clock_info' to the
+ registration method. Clock drivers must implement all of the
+ functions in the interface. If a clock does not offer a particular
+ ancillary feature, then the driver should just return -EOPNOTSUPP
+ from those functions.
+
+ Drivers must ensure that all of the methods in interface are
+ reentrant. Since most hardware implementations treat the time value
+ as a 64 bit integer accessed as two 32 bit registers, drivers
+ should use spin_lock_irqsave/spin_unlock_irqrestore to protect
+ against concurrent access. This locking cannot be accomplished in
+ class driver, since the lock may also be needed by the clock
+ driver's interrupt service routine.
+
+** Supported hardware
+
+ + Freescale eTSEC gianfar
+ - 2 Time stamp external triggers, programmable polarity (opt. interrupt)
+ - 2 Alarm registers (optional interrupt)
+ - 3 Periodic signals (optional interrupt)
+
+ + National DP83640
+ - 6 GPIOs programmable as inputs or outputs
+ - 6 GPIOs with dedicated functions (LED/JTAG/clock) can also be
+ used as general inputs or outputs
+ - GPIO inputs can time stamp external triggers
+ - GPIO outputs can produce periodic signals
+ - 1 interrupt pin
+
+ + Intel IXP465
+ - Auxiliary Slave/Master Mode Snapshot (optional interrupt)
+ - Target Time (optional interrupt)
diff --git a/Documentation/ptp/testptp.c b/Documentation/ptp/testptp.c
new file mode 100644
index 000000000000..f59ded066108
--- /dev/null
+++ b/Documentation/ptp/testptp.c
@@ -0,0 +1,381 @@
+/*
+ * PTP 1588 clock support - User space test program
+ *
+ * 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 <errno.h>
+#include <fcntl.h>
+#include <math.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/timex.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/ptp_clock.h>
+
+#define DEVICE "/dev/ptp0"
+
+#ifndef ADJ_SETOFFSET
+#define ADJ_SETOFFSET 0x0100
+#endif
+
+#ifndef CLOCK_INVALID
+#define CLOCK_INVALID -1
+#endif
+
+/* When glibc offers the syscall, this will go away. */
+#include <sys/syscall.h>
+static int clock_adjtime(clockid_t id, struct timex *tx)
+{
+ return syscall(__NR_clock_adjtime, id, tx);
+}
+
+static clockid_t get_clockid(int fd)
+{
+#define CLOCKFD 3
+#define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD)
+
+ return FD_TO_CLOCKID(fd);
+}
+
+static void handle_alarm(int s)
+{
+ printf("received signal %d\n", s);
+}
+
+static int install_handler(int signum, void (*handler)(int))
+{
+ struct sigaction action;
+ sigset_t mask;
+
+ /* Unblock the signal. */
+ sigemptyset(&mask);
+ sigaddset(&mask, signum);
+ sigprocmask(SIG_UNBLOCK, &mask, NULL);
+
+ /* Install the signal handler. */
+ action.sa_handler = handler;
+ action.sa_flags = 0;
+ sigemptyset(&action.sa_mask);
+ sigaction(signum, &action, NULL);
+
+ return 0;
+}
+
+static long ppb_to_scaled_ppm(int ppb)
+{
+ /*
+ * The 'freq' field in the 'struct timex' is in parts per
+ * million, but with a 16 bit binary fractional field.
+ * Instead of calculating either one of
+ *
+ * scaled_ppm = (ppb / 1000) << 16 [1]
+ * scaled_ppm = (ppb << 16) / 1000 [2]
+ *
+ * we simply use double precision math, in order to avoid the
+ * truncation in [1] and the possible overflow in [2].
+ */
+ return (long) (ppb * 65.536);
+}
+
+static void usage(char *progname)
+{
+ fprintf(stderr,
+ "usage: %s [options]\n"
+ " -a val request a one-shot alarm after 'val' seconds\n"
+ " -A val request a periodic alarm every 'val' seconds\n"
+ " -c query the ptp clock's capabilities\n"
+ " -d name device to open\n"
+ " -e val read 'val' external time stamp events\n"
+ " -f val adjust the ptp clock frequency by 'val' ppb\n"
+ " -g get the ptp clock time\n"
+ " -h prints this message\n"
+ " -p val enable output with a period of 'val' nanoseconds\n"
+ " -P val enable or disable (val=1|0) the system clock PPS\n"
+ " -s set the ptp clock time from the system time\n"
+ " -S set the system time from the ptp clock time\n"
+ " -t val shift the ptp clock time by 'val' seconds\n",
+ progname);
+}
+
+int main(int argc, char *argv[])
+{
+ struct ptp_clock_caps caps;
+ struct ptp_extts_event event;
+ struct ptp_extts_request extts_request;
+ struct ptp_perout_request perout_request;
+ struct timespec ts;
+ struct timex tx;
+
+ static timer_t timerid;
+ struct itimerspec timeout;
+ struct sigevent sigevent;
+
+ char *progname;
+ int c, cnt, fd;
+
+ char *device = DEVICE;
+ clockid_t clkid;
+ int adjfreq = 0x7fffffff;
+ int adjtime = 0;
+ int capabilities = 0;
+ int extts = 0;
+ int gettime = 0;
+ int oneshot = 0;
+ int periodic = 0;
+ int perout = -1;
+ int pps = -1;
+ int settime = 0;
+
+ progname = strrchr(argv[0], '/');
+ progname = progname ? 1+progname : argv[0];
+ while (EOF != (c = getopt(argc, argv, "a:A:cd:e:f:ghp:P:sSt:v"))) {
+ switch (c) {
+ case 'a':
+ oneshot = atoi(optarg);
+ break;
+ case 'A':
+ periodic = atoi(optarg);
+ break;
+ case 'c':
+ capabilities = 1;
+ break;
+ case 'd':
+ device = optarg;
+ break;
+ case 'e':
+ extts = atoi(optarg);
+ break;
+ case 'f':
+ adjfreq = atoi(optarg);
+ break;
+ case 'g':
+ gettime = 1;
+ break;
+ case 'p':
+ perout = atoi(optarg);
+ break;
+ case 'P':
+ pps = atoi(optarg);
+ break;
+ case 's':
+ settime = 1;
+ break;
+ case 'S':
+ settime = 2;
+ break;
+ case 't':
+ adjtime = atoi(optarg);
+ break;
+ case 'h':
+ usage(progname);
+ return 0;
+ case '?':
+ default:
+ usage(progname);
+ return -1;
+ }
+ }
+
+ fd = open(device, O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr, "opening %s: %s\n", device, strerror(errno));
+ return -1;
+ }
+
+ clkid = get_clockid(fd);
+ if (CLOCK_INVALID == clkid) {
+ fprintf(stderr, "failed to read clock id\n");
+ return -1;
+ }
+
+ if (capabilities) {
+ if (ioctl(fd, PTP_CLOCK_GETCAPS, &caps)) {
+ perror("PTP_CLOCK_GETCAPS");
+ } else {
+ printf("capabilities:\n"
+ " %d maximum frequency adjustment (ppb)\n"
+ " %d programmable alarms\n"
+ " %d external time stamp channels\n"
+ " %d programmable periodic signals\n"
+ " %d pulse per second\n",
+ caps.max_adj,
+ caps.n_alarm,
+ caps.n_ext_ts,
+ caps.n_per_out,
+ caps.pps);
+ }
+ }
+
+ if (0x7fffffff != adjfreq) {
+ memset(&tx, 0, sizeof(tx));
+ tx.modes = ADJ_FREQUENCY;
+ tx.freq = ppb_to_scaled_ppm(adjfreq);
+ if (clock_adjtime(clkid, &tx)) {
+ perror("clock_adjtime");
+ } else {
+ puts("frequency adjustment okay");
+ }
+ }
+
+ if (adjtime) {
+ memset(&tx, 0, sizeof(tx));
+ tx.modes = ADJ_SETOFFSET;
+ tx.time.tv_sec = adjtime;
+ tx.time.tv_usec = 0;
+ if (clock_adjtime(clkid, &tx) < 0) {
+ perror("clock_adjtime");
+ } else {
+ puts("time shift okay");
+ }
+ }
+
+ if (gettime) {
+ if (clock_gettime(clkid, &ts)) {
+ perror("clock_gettime");
+ } else {
+ printf("clock time: %ld.%09ld or %s",
+ ts.tv_sec, ts.tv_nsec, ctime(&ts.tv_sec));
+ }
+ }
+
+ if (settime == 1) {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ if (clock_settime(clkid, &ts)) {
+ perror("clock_settime");
+ } else {
+ puts("set time okay");
+ }
+ }
+
+ if (settime == 2) {
+ clock_gettime(clkid, &ts);
+ if (clock_settime(CLOCK_REALTIME, &ts)) {
+ perror("clock_settime");
+ } else {
+ puts("set time okay");
+ }
+ }
+
+ if (extts) {
+ memset(&extts_request, 0, sizeof(extts_request));
+ extts_request.index = 0;
+ extts_request.flags = PTP_ENABLE_FEATURE;
+ if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
+ perror("PTP_EXTTS_REQUEST");
+ extts = 0;
+ } else {
+ puts("external time stamp request okay");
+ }
+ for (; extts; extts--) {
+ cnt = read(fd, &event, sizeof(event));
+ if (cnt != sizeof(event)) {
+ perror("read");
+ break;
+ }
+ printf("event index %u at %lld.%09u\n", event.index,
+ event.t.sec, event.t.nsec);
+ fflush(stdout);
+ }
+ /* Disable the feature again. */
+ extts_request.flags = 0;
+ if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
+ perror("PTP_EXTTS_REQUEST");
+ }
+ }
+
+ if (oneshot) {
+ install_handler(SIGALRM, handle_alarm);
+ /* Create a timer. */
+ sigevent.sigev_notify = SIGEV_SIGNAL;
+ sigevent.sigev_signo = SIGALRM;
+ if (timer_create(clkid, &sigevent, &timerid)) {
+ perror("timer_create");
+ return -1;
+ }
+ /* Start the timer. */
+ memset(&timeout, 0, sizeof(timeout));
+ timeout.it_value.tv_sec = oneshot;
+ if (timer_settime(timerid, 0, &timeout, NULL)) {
+ perror("timer_settime");
+ return -1;
+ }
+ pause();
+ timer_delete(timerid);
+ }
+
+ if (periodic) {
+ install_handler(SIGALRM, handle_alarm);
+ /* Create a timer. */
+ sigevent.sigev_notify = SIGEV_SIGNAL;
+ sigevent.sigev_signo = SIGALRM;
+ if (timer_create(clkid, &sigevent, &timerid)) {
+ perror("timer_create");
+ return -1;
+ }
+ /* Start the timer. */
+ memset(&timeout, 0, sizeof(timeout));
+ timeout.it_interval.tv_sec = periodic;
+ timeout.it_value.tv_sec = periodic;
+ if (timer_settime(timerid, 0, &timeout, NULL)) {
+ perror("timer_settime");
+ return -1;
+ }
+ while (1) {
+ pause();
+ }
+ timer_delete(timerid);
+ }
+
+ if (perout >= 0) {
+ if (clock_gettime(clkid, &ts)) {
+ perror("clock_gettime");
+ return -1;
+ }
+ memset(&perout_request, 0, sizeof(perout_request));
+ perout_request.index = 0;
+ perout_request.start.sec = ts.tv_sec + 2;
+ perout_request.start.nsec = 0;
+ perout_request.period.sec = 0;
+ perout_request.period.nsec = perout;
+ if (ioctl(fd, PTP_PEROUT_REQUEST, &perout_request)) {
+ perror("PTP_PEROUT_REQUEST");
+ } else {
+ puts("periodic output request okay");
+ }
+ }
+
+ if (pps != -1) {
+ int enable = pps ? 1 : 0;
+ if (ioctl(fd, PTP_ENABLE_PPS, enable)) {
+ perror("PTP_ENABLE_PPS");
+ } else {
+ puts("pps for system time request okay");
+ }
+ }
+
+ close(fd);
+ return 0;
+}
diff --git a/Documentation/ptp/testptp.mk b/Documentation/ptp/testptp.mk
new file mode 100644
index 000000000000..4ef2d9755421
--- /dev/null
+++ b/Documentation/ptp/testptp.mk
@@ -0,0 +1,33 @@
+# PTP 1588 clock support - User space test program
+#
+# 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.
+
+CC = $(CROSS_COMPILE)gcc
+INC = -I$(KBUILD_OUTPUT)/usr/include
+CFLAGS = -Wall $(INC)
+LDLIBS = -lrt
+PROGS = testptp
+
+all: $(PROGS)
+
+testptp: testptp.o
+
+clean:
+ rm -f testptp.o
+
+distclean: clean
+ rm -f $(PROGS)
diff --git a/Documentation/scsi/LICENSE.qla2xxx b/Documentation/scsi/LICENSE.qla2xxx
index 9e15b4f9cd28..19e7cd4bba66 100644
--- a/Documentation/scsi/LICENSE.qla2xxx
+++ b/Documentation/scsi/LICENSE.qla2xxx
@@ -1,11 +1,11 @@
-Copyright (c) 2003-2005 QLogic Corporation
-QLogic Linux Fibre Channel HBA Driver
+Copyright (c) 2003-2011 QLogic Corporation
+QLogic Linux/ESX Fibre Channel HBA Driver
-This program includes a device driver for Linux 2.6 that may be
+This program includes a device driver for Linux 2.6/ESX that may be
distributed with QLogic hardware specific firmware binary file.
You may modify and redistribute the device driver code under the
-GNU General Public License as published by the Free Software
-Foundation (version 2 or a later version).
+GNU General Public License (a copy of which is attached hereto as
+Exhibit A) published by the Free Software Foundation (version 2).
You may redistribute the hardware specific firmware binary file
under the following terms:
@@ -43,3 +43,285 @@ OTHERWISE IN ANY INTELLECTUAL PROPERTY RIGHTS (PATENT, COPYRIGHT,
TRADE SECRET, MASK WORK, OR OTHER PROPRIETARY RIGHT) EMBODIED IN
ANY OTHER QLOGIC HARDWARE OR SOFTWARE EITHER SOLELY OR IN
COMBINATION WITH THIS PROGRAM.
+
+
+EXHIBIT A
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index 9822afb6313c..89757012c7ff 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -1230,6 +1230,13 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
This module supports multiple cards.
The driver requires the firmware loader support on kernel.
+ Module snd-lola
+ ---------------
+
+ Module for Digigram Lola PCI-e boards
+
+ This module supports multiple cards.
+
Module snd-lx6464es
-------------------
diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt
index 0caf77e59be4..d70c93bdcadf 100644
--- a/Documentation/sound/alsa/HD-Audio-Models.txt
+++ b/Documentation/sound/alsa/HD-Audio-Models.txt
@@ -94,7 +94,7 @@ ALC662/663/272
3stack-dig 3-stack (2-channel) with SPDIF
3stack-6ch 3-stack (6-channel)
3stack-6ch-dig 3-stack (6-channel) with SPDIF
- 6stack-dig 6-stack with SPDIF
+ 5stack-dig 5-stack with SPDIF
lenovo-101e Lenovo laptop
eeepc-p701 ASUS Eeepc P701
eeepc-ep20 ASUS Eeepc EP20
diff --git a/Documentation/stable_api_nonsense.txt b/Documentation/stable_api_nonsense.txt
index 847b342b7b20..db3be892afb2 100644
--- a/Documentation/stable_api_nonsense.txt
+++ b/Documentation/stable_api_nonsense.txt
@@ -122,7 +122,7 @@ operating system to suffer.
In both of these instances, all developers agreed that these were
important changes that needed to be made, and they were made, with
-relatively little pain. If Linux had to ensure that it preserve a
+relatively little pain. If Linux had to ensure that it will preserve a
stable source interface, a new interface would have been created, and
the older, broken one would have had to be maintained over time, leading
to extra work for the USB developers. Since all Linux USB developers do
diff --git a/Documentation/sysctl/fs.txt b/Documentation/sysctl/fs.txt
index 4af0614147ef..88fd7f5c8dcd 100644
--- a/Documentation/sysctl/fs.txt
+++ b/Documentation/sysctl/fs.txt
@@ -231,13 +231,6 @@ its creation).
This directory contains configuration options for the epoll(7) interface.
-max_user_instances
-------------------
-
-This is the maximum number of epoll file descriptors that a single user can
-have open at a given time. The default value is 128, and should be enough
-for normal users.
-
max_user_watches
----------------
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
index 36f007514db3..5e7cb39ad195 100644
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -161,7 +161,8 @@ core_pattern is used to specify a core dumpfile pattern name.
%s signal number
%t UNIX time of dump
%h hostname
- %e executable filename
+ %e executable filename (may be shortened)
+ %E executable path
%<OTHER> both are dropped
. If the first character of the pattern is a '|', the kernel will treat
the rest of the pattern as a command to run. The core dump will be
diff --git a/Documentation/sysctl/net.txt b/Documentation/sysctl/net.txt
index cbd05ffc606b..3201a7097e4d 100644
--- a/Documentation/sysctl/net.txt
+++ b/Documentation/sysctl/net.txt
@@ -32,6 +32,17 @@ Table : Subdirectories in /proc/sys/net
1. /proc/sys/net/core - Network core options
-------------------------------------------------------
+bpf_jit_enable
+--------------
+
+This enables Berkeley Packet Filter Just in Time compiler.
+Currently supported on x86_64 architecture, bpf_jit provides a framework
+to speed packet filtering, the one used by tcpdump/libpcap for example.
+Values :
+ 0 - disable the JIT (default value)
+ 1 - enable the JIT
+ 2 - enable the JIT and ask the compiler to emit traces on kernel log.
+
rmem_default
------------
diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt
index 30289fab86eb..96f0ee825bed 100644
--- a/Documentation/sysctl/vm.txt
+++ b/Documentation/sysctl/vm.txt
@@ -481,10 +481,10 @@ the DMA zone.
Type(A) is called as "Node" order. Type (B) is "Zone" order.
"Node order" orders the zonelists by node, then by zone within each node.
-Specify "[Nn]ode" for zone order
+Specify "[Nn]ode" for node order
"Zone Order" orders the zonelists by zone type, then by node within each
-zone. Specify "[Zz]one"for zode order.
+zone. Specify "[Zz]one" for zone order.
Specify "[Dd]efault" to request automatic configuration. Autoconfiguration
will select "node" order in following case.
diff --git a/Documentation/timers/timers-howto.txt b/Documentation/timers/timers-howto.txt
index c9ef29d2ede3..038f8c77a076 100644
--- a/Documentation/timers/timers-howto.txt
+++ b/Documentation/timers/timers-howto.txt
@@ -24,7 +24,7 @@ ATOMIC CONTEXT:
ndelay(unsigned long nsecs)
udelay(unsigned long usecs)
- mdelay(unsgined long msecs)
+ mdelay(unsigned long msecs)
udelay is the generally preferred API; ndelay-level
precision may not actually exist on many non-PC devices.
diff --git a/Documentation/trace/kprobetrace.txt b/Documentation/trace/kprobetrace.txt
index 6d27ab8d6e9f..c83bd6b4e6e8 100644
--- a/Documentation/trace/kprobetrace.txt
+++ b/Documentation/trace/kprobetrace.txt
@@ -120,7 +120,6 @@ format:
field:unsigned char common_flags; offset:2; size:1; signed:0;
field:unsigned char common_preempt_count; offset:3; size:1;signed:0;
field:int common_pid; offset:4; size:4; signed:1;
- field:int common_lock_depth; offset:8; size:4; signed:1;
field:unsigned long __probe_ip; offset:12; size:4; signed:0;
field:int __probe_nargs; offset:16; size:4; signed:1;
diff --git a/Documentation/usb/callbacks.txt b/Documentation/usb/callbacks.txt
index bfb36b34b79e..9e85846bdb98 100644
--- a/Documentation/usb/callbacks.txt
+++ b/Documentation/usb/callbacks.txt
@@ -95,9 +95,11 @@ pre_reset
int (*pre_reset)(struct usb_interface *intf);
-Another driver or user space is triggering a reset on the device which
-contains the interface passed as an argument. Cease IO and save any
-device state you need to restore.
+A driver or user space is triggering a reset on the device which
+contains the interface passed as an argument. Cease IO, wait for all
+outstanding URBs to complete, and save any device state you need to
+restore. No more URBs may be submitted until the post_reset method
+is called.
If you need to allocate memory here, use GFP_NOIO or GFP_ATOMIC, if you
are in atomic context.
diff --git a/Documentation/usb/linux-cdc-acm.inf b/Documentation/usb/linux-cdc-acm.inf
index 612e7220fb29..37a02ce54841 100644
--- a/Documentation/usb/linux-cdc-acm.inf
+++ b/Documentation/usb/linux-cdc-acm.inf
@@ -90,10 +90,10 @@ ServiceBinary=%12%\USBSER.sys
[SourceDisksFiles]
[SourceDisksNames]
[DeviceList]
-%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_0525&PID_A4AB&MI_02
+%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_1D6B&PID_0104&MI_02
[DeviceList.NTamd64]
-%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_0525&PID_A4AB&MI_02
+%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_1D6B&PID_0104&MI_02
;------------------------------------------------------------------------------
diff --git a/Documentation/usb/linux.inf b/Documentation/usb/linux.inf
index 4dee95851224..4ffa715b0ae8 100644
--- a/Documentation/usb/linux.inf
+++ b/Documentation/usb/linux.inf
@@ -18,15 +18,15 @@ DriverVer = 06/21/2006,6.0.6000.16384
; Decoration for x86 architecture
[LinuxDevices.NTx86]
-%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2, USB\VID_0525&PID_a4ab&MI_00
+%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2, USB\VID_1d6b&PID_0104&MI_00
; Decoration for x64 architecture
[LinuxDevices.NTamd64]
-%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2, USB\VID_0525&PID_a4ab&MI_00
+%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2, USB\VID_1d6b&PID_0104&MI_00
; Decoration for ia64 architecture
[LinuxDevices.NTia64]
-%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2, USB\VID_0525&PID_a4ab&MI_00
+%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2, USB\VID_1d6b&PID_0104&MI_00
;@@@ This is the common setting for setup
[ControlFlags]
diff --git a/Documentation/vgaarbiter.txt b/Documentation/vgaarbiter.txt
index 43a9b0694fdd..b7d401e0eae9 100644
--- a/Documentation/vgaarbiter.txt
+++ b/Documentation/vgaarbiter.txt
@@ -14,11 +14,10 @@ the legacy VGA arbitration task (besides other bus management tasks) when more
than one legacy device co-exists on the same machine. But the problem happens
when these devices are trying to be accessed by different userspace clients
(e.g. two server in parallel). Their address assignments conflict. Moreover,
-ideally, being an userspace application, it is not the role of the the X
-server to control bus resources. Therefore an arbitration scheme outside of
-the X server is needed to control the sharing of these resources. This
-document introduces the operation of the VGA arbiter implemented for Linux
-kernel.
+ideally, being a userspace application, it is not the role of the X server to
+control bus resources. Therefore an arbitration scheme outside of the X server
+is needed to control the sharing of these resources. This document introduces
+the operation of the VGA arbiter implemented for the Linux kernel.
----------------------------------------------------------------------------
@@ -39,7 +38,7 @@ I.1 vgaarb
The vgaarb is a module of the Linux Kernel. When it is initially loaded, it
scans all PCI devices and adds the VGA ones inside the arbitration. The
arbiter then enables/disables the decoding on different devices of the VGA
-legacy instructions. Device which do not want/need to use the arbiter may
+legacy instructions. Devices which do not want/need to use the arbiter may
explicitly tell it by calling vga_set_legacy_decoding().
The kernel exports a char device interface (/dev/vga_arbiter) to the clients,
@@ -95,8 +94,8 @@ In the case of devices hot-{un,}plugged, there is a hook - pci_notify() - to
notify them being added/removed in the system and automatically added/removed
in the arbiter.
-There's also a in-kernel API of the arbiter in the case of DRM, vgacon and
-others which may use the arbiter.
+There is also an in-kernel API of the arbiter in case DRM, vgacon, or other
+drivers want to use it.
I.2 libpciaccess
@@ -117,9 +116,8 @@ Besides it, in pci_system were added:
struct pci_device *vga_default_dev;
-The vga_count is usually need to keep informed how many cards are being
-arbitrated, so for instance if there's only one then it can totally escape the
-scheme.
+The vga_count is used to track how many cards are being arbitrated, so for
+instance, if there is only one card, then it can completely escape arbitration.
These functions below acquire VGA resources for the given card and mark those
diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx
index 31b485723bc5..9aae449440dc 100644
--- a/Documentation/video4linux/CARDLIST.em28xx
+++ b/Documentation/video4linux/CARDLIST.em28xx
@@ -54,7 +54,7 @@
53 -> Pinnacle Hybrid Pro (em2881)
54 -> Kworld VS-DVB-T 323UR (em2882) [eb1a:e323]
55 -> Terratec Cinnergy Hybrid T USB XS (em2882) (em2882) [0ccd:005e,0ccd:0042]
- 56 -> Pinnacle Hybrid Pro (2) (em2882) [2304:0226]
+ 56 -> Pinnacle Hybrid Pro (330e) (em2882) [2304:0226]
57 -> Kworld PlusTV HD Hybrid 330 (em2883) [eb1a:a316]
58 -> Compro VideoMate ForYou/Stereo (em2820/em2840) [185b:2041]
60 -> Hauppauge WinTV HVR 850 (em2883) [2040:651f]
diff --git a/Documentation/video4linux/Zoran b/Documentation/video4linux/Zoran
index c40e3bab08fa..9ed629d4874b 100644
--- a/Documentation/video4linux/Zoran
+++ b/Documentation/video4linux/Zoran
@@ -130,7 +130,6 @@ Card number: 4
Note: No module for the mse3000 is available yet
Note: No module for the vpx3224 is available yet
-Note: use encoder=X or decoder=X for non-default i2c chips
===========================
diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt
index 5c542e60f51d..5bfa9a777d26 100644
--- a/Documentation/video4linux/gspca.txt
+++ b/Documentation/video4linux/gspca.txt
@@ -275,6 +275,7 @@ pac7302 093a:2629 Genious iSlim 300
pac7302 093a:262a Webcam 300k
pac7302 093a:262c Philips SPC 230 NC
jeilinj 0979:0280 Sakar 57379
+jeilinj 0979:0280 Sportscam DV15
zc3xx 0ac8:0302 Z-star Vimicro zc0302
vc032x 0ac8:0321 Vimicro generic vc0321
vc032x 0ac8:0323 Vimicro Vc0323
diff --git a/Documentation/video4linux/uvcvideo.txt b/Documentation/video4linux/uvcvideo.txt
new file mode 100644
index 000000000000..848d620dcc5c
--- /dev/null
+++ b/Documentation/video4linux/uvcvideo.txt
@@ -0,0 +1,239 @@
+Linux USB Video Class (UVC) driver
+==================================
+
+This file documents some driver-specific aspects of the UVC driver, such as
+driver-specific ioctls and implementation notes.
+
+Questions and remarks can be sent to the Linux UVC development mailing list at
+linux-uvc-devel@lists.berlios.de.
+
+
+Extension Unit (XU) support
+---------------------------
+
+1. Introduction
+
+The UVC specification allows for vendor-specific extensions through extension
+units (XUs). The Linux UVC driver supports extension unit controls (XU controls)
+through two separate mechanisms:
+
+ - through mappings of XU controls to V4L2 controls
+ - through a driver-specific ioctl interface
+
+The first one allows generic V4L2 applications to use XU controls by mapping
+certain XU controls onto V4L2 controls, which then show up during ordinary
+control enumeration.
+
+The second mechanism requires uvcvideo-specific knowledge for the application to
+access XU controls but exposes the entire UVC XU concept to user space for
+maximum flexibility.
+
+Both mechanisms complement each other and are described in more detail below.
+
+
+2. Control mappings
+
+The UVC driver provides an API for user space applications to define so-called
+control mappings at runtime. These allow for individual XU controls or byte
+ranges thereof to be mapped to new V4L2 controls. Such controls appear and
+function exactly like normal V4L2 controls (i.e. the stock controls, such as
+brightness, contrast, etc.). However, reading or writing of such a V4L2 controls
+triggers a read or write of the associated XU control.
+
+The ioctl used to create these control mappings is called UVCIOC_CTRL_MAP.
+Previous driver versions (before 0.2.0) required another ioctl to be used
+beforehand (UVCIOC_CTRL_ADD) to pass XU control information to the UVC driver.
+This is no longer necessary as newer uvcvideo versions query the information
+directly from the device.
+
+For details on the UVCIOC_CTRL_MAP ioctl please refer to the section titled
+"IOCTL reference" below.
+
+
+3. Driver specific XU control interface
+
+For applications that need to access XU controls directly, e.g. for testing
+purposes, firmware upload, or accessing binary controls, a second mechanism to
+access XU controls is provided in the form of a driver-specific ioctl, namely
+UVCIOC_CTRL_QUERY.
+
+A call to this ioctl allows applications to send queries to the UVC driver that
+directly map to the low-level UVC control requests.
+
+In order to make such a request the UVC unit ID of the control's extension unit
+and the control selector need to be known. This information either needs to be
+hardcoded in the application or queried using other ways such as by parsing the
+UVC descriptor or, if available, using the media controller API to enumerate a
+device's entities.
+
+Unless the control size is already known it is necessary to first make a
+UVC_GET_LEN requests in order to be able to allocate a sufficiently large buffer
+and set the buffer size to the correct value. Similarly, to find out whether
+UVC_GET_CUR or UVC_SET_CUR are valid requests for a given control, a
+UVC_GET_INFO request should be made. The bits 0 (GET supported) and 1 (SET
+supported) of the resulting byte indicate which requests are valid.
+
+With the addition of the UVCIOC_CTRL_QUERY ioctl the UVCIOC_CTRL_GET and
+UVCIOC_CTRL_SET ioctls have become obsolete since their functionality is a
+subset of the former ioctl. For the time being they are still supported but
+application developers are encouraged to use UVCIOC_CTRL_QUERY instead.
+
+For details on the UVCIOC_CTRL_QUERY ioctl please refer to the section titled
+"IOCTL reference" below.
+
+
+4. Security
+
+The API doesn't currently provide a fine-grained access control facility. The
+UVCIOC_CTRL_ADD and UVCIOC_CTRL_MAP ioctls require super user permissions.
+
+Suggestions on how to improve this are welcome.
+
+
+5. Debugging
+
+In order to debug problems related to XU controls or controls in general it is
+recommended to enable the UVC_TRACE_CONTROL bit in the module parameter 'trace'.
+This causes extra output to be written into the system log.
+
+
+6. IOCTL reference
+
+---- UVCIOC_CTRL_MAP - Map a UVC control to a V4L2 control ----
+
+Argument: struct uvc_xu_control_mapping
+
+Description:
+ This ioctl creates a mapping between a UVC control or part of a UVC
+ control and a V4L2 control. Once mappings are defined, userspace
+ applications can access vendor-defined UVC control through the V4L2
+ control API.
+
+ To create a mapping, applications fill the uvc_xu_control_mapping
+ structure with information about an existing UVC control defined with
+ UVCIOC_CTRL_ADD and a new V4L2 control.
+
+ A UVC control can be mapped to several V4L2 controls. For instance,
+ a UVC pan/tilt control could be mapped to separate pan and tilt V4L2
+ controls. The UVC control is divided into non overlapping fields using
+ the 'size' and 'offset' fields and are then independantly mapped to
+ V4L2 control.
+
+ For signed integer V4L2 controls the data_type field should be set to
+ UVC_CTRL_DATA_TYPE_SIGNED. Other values are currently ignored.
+
+Return value:
+ On success 0 is returned. On error -1 is returned and errno is set
+ appropriately.
+
+ ENOMEM
+ Not enough memory to perform the operation.
+ EPERM
+ Insufficient privileges (super user privileges are required).
+ EINVAL
+ No such UVC control.
+ EOVERFLOW
+ The requested offset and size would overflow the UVC control.
+ EEXIST
+ Mapping already exists.
+
+Data types:
+ * struct uvc_xu_control_mapping
+
+ __u32 id V4L2 control identifier
+ __u8 name[32] V4L2 control name
+ __u8 entity[16] UVC extension unit GUID
+ __u8 selector UVC control selector
+ __u8 size V4L2 control size (in bits)
+ __u8 offset V4L2 control offset (in bits)
+ enum v4l2_ctrl_type
+ v4l2_type V4L2 control type
+ enum uvc_control_data_type
+ data_type UVC control data type
+ struct uvc_menu_info
+ *menu_info Array of menu entries (for menu controls only)
+ __u32 menu_count Number of menu entries (for menu controls only)
+
+ * struct uvc_menu_info
+
+ __u32 value Menu entry value used by the device
+ __u8 name[32] Menu entry name
+
+
+ * enum uvc_control_data_type
+
+ UVC_CTRL_DATA_TYPE_RAW Raw control (byte array)
+ UVC_CTRL_DATA_TYPE_SIGNED Signed integer
+ UVC_CTRL_DATA_TYPE_UNSIGNED Unsigned integer
+ UVC_CTRL_DATA_TYPE_BOOLEAN Boolean
+ UVC_CTRL_DATA_TYPE_ENUM Enumeration
+ UVC_CTRL_DATA_TYPE_BITMASK Bitmask
+
+
+---- UVCIOC_CTRL_QUERY - Query a UVC XU control ----
+
+Argument: struct uvc_xu_control_query
+
+Description:
+ This ioctl queries a UVC XU control identified by its extension unit ID
+ and control selector.
+
+ There are a number of different queries available that closely
+ correspond to the low-level control requests described in the UVC
+ specification. These requests are:
+
+ UVC_GET_CUR
+ Obtain the current value of the control.
+ UVC_GET_MIN
+ Obtain the minimum value of the control.
+ UVC_GET_MAX
+ Obtain the maximum value of the control.
+ UVC_GET_DEF
+ Obtain the default value of the control.
+ UVC_GET_RES
+ Query the resolution of the control, i.e. the step size of the
+ allowed control values.
+ UVC_GET_LEN
+ Query the size of the control in bytes.
+ UVC_GET_INFO
+ Query the control information bitmap, which indicates whether
+ get/set requests are supported.
+ UVC_SET_CUR
+ Update the value of the control.
+
+ Applications must set the 'size' field to the correct length for the
+ control. Exceptions are the UVC_GET_LEN and UVC_GET_INFO queries, for
+ which the size must be set to 2 and 1, respectively. The 'data' field
+ must point to a valid writable buffer big enough to hold the indicated
+ number of data bytes.
+
+ Data is copied directly from the device without any driver-side
+ processing. Applications are responsible for data buffer formatting,
+ including little-endian/big-endian conversion. This is particularly
+ important for the result of the UVC_GET_LEN requests, which is always
+ returned as a little-endian 16-bit integer by the device.
+
+Return value:
+ On success 0 is returned. On error -1 is returned and errno is set
+ appropriately.
+
+ ENOENT
+ The device does not support the given control or the specified
+ extension unit could not be found.
+ ENOBUFS
+ The specified buffer size is incorrect (too big or too small).
+ EINVAL
+ An invalid request code was passed.
+ EBADRQC
+ The given request is not supported by the given control.
+ EFAULT
+ The data pointer references an inaccessible memory area.
+
+Data types:
+ * struct uvc_xu_control_query
+
+ __u8 unit Extension unit ID
+ __u8 selector Control selector
+ __u8 query Request code to send to the device
+ __u16 size Control data size (in bytes)
+ __u8 *data Control value
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 9bef4e4cec50..42542eb802ca 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -175,7 +175,10 @@ Parameters: vcpu id (apic id on x86)
Returns: vcpu fd on success, -1 on error
This API adds a vcpu to a virtual machine. The vcpu id is a small integer
-in the range [0, max_vcpus).
+in the range [0, max_vcpus). You can use KVM_CAP_NR_VCPUS of the
+KVM_CHECK_EXTENSION ioctl() to determine the value for max_vcpus at run-time.
+If the KVM_CAP_NR_VCPUS does not exist, you should assume that max_vcpus is 4
+cpus max.
4.8 KVM_GET_DIRTY_LOG (vm ioctl)
@@ -261,7 +264,7 @@ See KVM_GET_REGS for the data structure.
4.13 KVM_GET_SREGS
Capability: basic
-Architectures: x86
+Architectures: x86, ppc
Type: vcpu ioctl
Parameters: struct kvm_sregs (out)
Returns: 0 on success, -1 on error
@@ -279,6 +282,8 @@ struct kvm_sregs {
__u64 interrupt_bitmap[(KVM_NR_INTERRUPTS + 63) / 64];
};
+/* ppc -- see arch/powerpc/include/asm/kvm.h */
+
interrupt_bitmap is a bitmap of pending external interrupts. At most
one bit may be set. This interrupt has been acknowledged by the APIC
but not yet injected into the cpu core.
@@ -286,7 +291,7 @@ but not yet injected into the cpu core.
4.14 KVM_SET_SREGS
Capability: basic
-Architectures: x86
+Architectures: x86, ppc
Type: vcpu ioctl
Parameters: struct kvm_sregs (in)
Returns: 0 on success, -1 on error
@@ -1263,6 +1268,29 @@ struct kvm_assigned_msix_entry {
__u16 padding[3];
};
+4.54 KVM_SET_TSC_KHZ
+
+Capability: KVM_CAP_TSC_CONTROL
+Architectures: x86
+Type: vcpu ioctl
+Parameters: virtual tsc_khz
+Returns: 0 on success, -1 on error
+
+Specifies the tsc frequency for the virtual machine. The unit of the
+frequency is KHz.
+
+4.55 KVM_GET_TSC_KHZ
+
+Capability: KVM_CAP_GET_TSC_KHZ
+Architectures: x86
+Type: vcpu ioctl
+Parameters: none
+Returns: virtual tsc-khz on success, negative value on error
+
+Returns the tsc frequency of the guest. The unit of the return value is
+KHz. If the host has unstable tsc this ioctl returns -EIO instead as an
+error.
+
5. The kvm_run structure
Application code obtains a pointer to the kvm_run structure by
diff --git a/Documentation/virtual/uml/UserModeLinux-HOWTO.txt b/Documentation/virtual/uml/UserModeLinux-HOWTO.txt
index 9b7e1904db1c..5d0fc8bfcdb9 100644
--- a/Documentation/virtual/uml/UserModeLinux-HOWTO.txt
+++ b/Documentation/virtual/uml/UserModeLinux-HOWTO.txt
@@ -1182,6 +1182,16 @@
forge.net/> and explains these in detail, as well as
some other issues.
+ There is also a related point-to-point only "ucast" transport.
+ This is useful when your network does not support multicast, and
+ all network connections are simple point to point links.
+
+ The full set of command line options for this transport are
+
+
+ ethn=ucast,ethernet address,remote address,listen port,remote port
+
+
66..66.. TTUUNN//TTAAPP wwiitthh tthhee uummll__nneett hheellppeerr
diff --git a/Documentation/vm/cleancache.txt b/Documentation/vm/cleancache.txt
new file mode 100644
index 000000000000..36c367c73084
--- /dev/null
+++ b/Documentation/vm/cleancache.txt
@@ -0,0 +1,278 @@
+MOTIVATION
+
+Cleancache is a new optional feature provided by the VFS layer that
+potentially dramatically increases page cache effectiveness for
+many workloads in many environments at a negligible cost.
+
+Cleancache can be thought of as a page-granularity victim cache for clean
+pages that the kernel's pageframe replacement algorithm (PFRA) would like
+to keep around, but can't since there isn't enough memory. So when the
+PFRA "evicts" a page, it first attempts to use cleancache code to
+put the data contained in that page into "transcendent memory", memory
+that is not directly accessible or addressable by the kernel and is
+of unknown and possibly time-varying size.
+
+Later, when a cleancache-enabled filesystem wishes to access a page
+in a file on disk, it first checks cleancache to see if it already
+contains it; if it does, the page of data is copied into the kernel
+and a disk access is avoided.
+
+Transcendent memory "drivers" for cleancache are currently implemented
+in Xen (using hypervisor memory) and zcache (using in-kernel compressed
+memory) and other implementations are in development.
+
+FAQs are included below.
+
+IMPLEMENTATION OVERVIEW
+
+A cleancache "backend" that provides transcendent memory registers itself
+to the kernel's cleancache "frontend" by calling cleancache_register_ops,
+passing a pointer to a cleancache_ops structure with funcs set appropriately.
+Note that cleancache_register_ops returns the previous settings so that
+chaining can be performed if desired. The functions provided must conform to
+certain semantics as follows:
+
+Most important, cleancache is "ephemeral". Pages which are copied into
+cleancache have an indefinite lifetime which is completely unknowable
+by the kernel and so may or may not still be in cleancache at any later time.
+Thus, as its name implies, cleancache is not suitable for dirty pages.
+Cleancache has complete discretion over what pages to preserve and what
+pages to discard and when.
+
+Mounting a cleancache-enabled filesystem should call "init_fs" to obtain a
+pool id which, if positive, must be saved in the filesystem's superblock;
+a negative return value indicates failure. A "put_page" will copy a
+(presumably about-to-be-evicted) page into cleancache and associate it with
+the pool id, a file key, and a page index into the file. (The combination
+of a pool id, a file key, and an index is sometimes called a "handle".)
+A "get_page" will copy the page, if found, from cleancache into kernel memory.
+A "flush_page" will ensure the page no longer is present in cleancache;
+a "flush_inode" will flush all pages associated with the specified file;
+and, when a filesystem is unmounted, a "flush_fs" will flush all pages in
+all files specified by the given pool id and also surrender the pool id.
+
+An "init_shared_fs", like init_fs, obtains a pool id but tells cleancache
+to treat the pool as shared using a 128-bit UUID as a key. On systems
+that may run multiple kernels (such as hard partitioned or virtualized
+systems) that may share a clustered filesystem, and where cleancache
+may be shared among those kernels, calls to init_shared_fs that specify the
+same UUID will receive the same pool id, thus allowing the pages to
+be shared. Note that any security requirements must be imposed outside
+of the kernel (e.g. by "tools" that control cleancache). Or a
+cleancache implementation can simply disable shared_init by always
+returning a negative value.
+
+If a get_page is successful on a non-shared pool, the page is flushed (thus
+making cleancache an "exclusive" cache). On a shared pool, the page
+is NOT flushed on a successful get_page so that it remains accessible to
+other sharers. The kernel is responsible for ensuring coherency between
+cleancache (shared or not), the page cache, and the filesystem, using
+cleancache flush operations as required.
+
+Note that cleancache must enforce put-put-get coherency and get-get
+coherency. For the former, if two puts are made to the same handle but
+with different data, say AAA by the first put and BBB by the second, a
+subsequent get can never return the stale data (AAA). For get-get coherency,
+if a get for a given handle fails, subsequent gets for that handle will
+never succeed unless preceded by a successful put with that handle.
+
+Last, cleancache provides no SMP serialization guarantees; if two
+different Linux threads are simultaneously putting and flushing a page
+with the same handle, the results are indeterminate. Callers must
+lock the page to ensure serial behavior.
+
+CLEANCACHE PERFORMANCE METRICS
+
+Cleancache monitoring is done by sysfs files in the
+/sys/kernel/mm/cleancache directory. The effectiveness of cleancache
+can be measured (across all filesystems) with:
+
+succ_gets - number of gets that were successful
+failed_gets - number of gets that failed
+puts - number of puts attempted (all "succeed")
+flushes - number of flushes attempted
+
+A backend implementatation may provide additional metrics.
+
+FAQ
+
+1) Where's the value? (Andrew Morton)
+
+Cleancache provides a significant performance benefit to many workloads
+in many environments with negligible overhead by improving the
+effectiveness of the pagecache. Clean pagecache pages are
+saved in transcendent memory (RAM that is otherwise not directly
+addressable to the kernel); fetching those pages later avoids "refaults"
+and thus disk reads.
+
+Cleancache (and its sister code "frontswap") provide interfaces for
+this transcendent memory (aka "tmem"), which conceptually lies between
+fast kernel-directly-addressable RAM and slower DMA/asynchronous devices.
+Disallowing direct kernel or userland reads/writes to tmem
+is ideal when data is transformed to a different form and size (such
+as with compression) or secretly moved (as might be useful for write-
+balancing for some RAM-like devices). Evicted page-cache pages (and
+swap pages) are a great use for this kind of slower-than-RAM-but-much-
+faster-than-disk transcendent memory, and the cleancache (and frontswap)
+"page-object-oriented" specification provides a nice way to read and
+write -- and indirectly "name" -- the pages.
+
+In the virtual case, the whole point of virtualization is to statistically
+multiplex physical resources across the varying demands of multiple
+virtual machines. This is really hard to do with RAM and efforts to
+do it well with no kernel change have essentially failed (except in some
+well-publicized special-case workloads). Cleancache -- and frontswap --
+with a fairly small impact on the kernel, provide a huge amount
+of flexibility for more dynamic, flexible RAM multiplexing.
+Specifically, the Xen Transcendent Memory backend allows otherwise
+"fallow" hypervisor-owned RAM to not only be "time-shared" between multiple
+virtual machines, but the pages can be compressed and deduplicated to
+optimize RAM utilization. And when guest OS's are induced to surrender
+underutilized RAM (e.g. with "self-ballooning"), page cache pages
+are the first to go, and cleancache allows those pages to be
+saved and reclaimed if overall host system memory conditions allow.
+
+And the identical interface used for cleancache can be used in
+physical systems as well. The zcache driver acts as a memory-hungry
+device that stores pages of data in a compressed state. And
+the proposed "RAMster" driver shares RAM across multiple physical
+systems.
+
+2) Why does cleancache have its sticky fingers so deep inside the
+ filesystems and VFS? (Andrew Morton and Christoph Hellwig)
+
+The core hooks for cleancache in VFS are in most cases a single line
+and the minimum set are placed precisely where needed to maintain
+coherency (via cleancache_flush operations) between cleancache,
+the page cache, and disk. All hooks compile into nothingness if
+cleancache is config'ed off and turn into a function-pointer-
+compare-to-NULL if config'ed on but no backend claims the ops
+functions, or to a compare-struct-element-to-negative if a
+backend claims the ops functions but a filesystem doesn't enable
+cleancache.
+
+Some filesystems are built entirely on top of VFS and the hooks
+in VFS are sufficient, so don't require an "init_fs" hook; the
+initial implementation of cleancache didn't provide this hook.
+But for some filesystems (such as btrfs), the VFS hooks are
+incomplete and one or more hooks in fs-specific code are required.
+And for some other filesystems, such as tmpfs, cleancache may
+be counterproductive. So it seemed prudent to require a filesystem
+to "opt in" to use cleancache, which requires adding a hook in
+each filesystem. Not all filesystems are supported by cleancache
+only because they haven't been tested. The existing set should
+be sufficient to validate the concept, the opt-in approach means
+that untested filesystems are not affected, and the hooks in the
+existing filesystems should make it very easy to add more
+filesystems in the future.
+
+The total impact of the hooks to existing fs and mm files is only
+about 40 lines added (not counting comments and blank lines).
+
+3) Why not make cleancache asynchronous and batched so it can
+ more easily interface with real devices with DMA instead
+ of copying each individual page? (Minchan Kim)
+
+The one-page-at-a-time copy semantics simplifies the implementation
+on both the frontend and backend and also allows the backend to
+do fancy things on-the-fly like page compression and
+page deduplication. And since the data is "gone" (copied into/out
+of the pageframe) before the cleancache get/put call returns,
+a great deal of race conditions and potential coherency issues
+are avoided. While the interface seems odd for a "real device"
+or for real kernel-addressable RAM, it makes perfect sense for
+transcendent memory.
+
+4) Why is non-shared cleancache "exclusive"? And where is the
+ page "flushed" after a "get"? (Minchan Kim)
+
+The main reason is to free up space in transcendent memory and
+to avoid unnecessary cleancache_flush calls. If you want inclusive,
+the page can be "put" immediately following the "get". If
+put-after-get for inclusive becomes common, the interface could
+be easily extended to add a "get_no_flush" call.
+
+The flush is done by the cleancache backend implementation.
+
+5) What's the performance impact?
+
+Performance analysis has been presented at OLS'09 and LCA'10.
+Briefly, performance gains can be significant on most workloads,
+especially when memory pressure is high (e.g. when RAM is
+overcommitted in a virtual workload); and because the hooks are
+invoked primarily in place of or in addition to a disk read/write,
+overhead is negligible even in worst case workloads. Basically
+cleancache replaces I/O with memory-copy-CPU-overhead; on older
+single-core systems with slow memory-copy speeds, cleancache
+has little value, but in newer multicore machines, especially
+consolidated/virtualized machines, it has great value.
+
+6) How do I add cleancache support for filesystem X? (Boaz Harrash)
+
+Filesystems that are well-behaved and conform to certain
+restrictions can utilize cleancache simply by making a call to
+cleancache_init_fs at mount time. Unusual, misbehaving, or
+poorly layered filesystems must either add additional hooks
+and/or undergo extensive additional testing... or should just
+not enable the optional cleancache.
+
+Some points for a filesystem to consider:
+
+- The FS should be block-device-based (e.g. a ram-based FS such
+ as tmpfs should not enable cleancache)
+- To ensure coherency/correctness, the FS must ensure that all
+ file removal or truncation operations either go through VFS or
+ add hooks to do the equivalent cleancache "flush" operations
+- To ensure coherency/correctness, either inode numbers must
+ be unique across the lifetime of the on-disk file OR the
+ FS must provide an "encode_fh" function.
+- The FS must call the VFS superblock alloc and deactivate routines
+ or add hooks to do the equivalent cleancache calls done there.
+- To maximize performance, all pages fetched from the FS should
+ go through the do_mpag_readpage routine or the FS should add
+ hooks to do the equivalent (cf. btrfs)
+- Currently, the FS blocksize must be the same as PAGESIZE. This
+ is not an architectural restriction, but no backends currently
+ support anything different.
+- A clustered FS should invoke the "shared_init_fs" cleancache
+ hook to get best performance for some backends.
+
+7) Why not use the KVA of the inode as the key? (Christoph Hellwig)
+
+If cleancache would use the inode virtual address instead of
+inode/filehandle, the pool id could be eliminated. But, this
+won't work because cleancache retains pagecache data pages
+persistently even when the inode has been pruned from the
+inode unused list, and only flushes the data page if the file
+gets removed/truncated. So if cleancache used the inode kva,
+there would be potential coherency issues if/when the inode
+kva is reused for a different file. Alternately, if cleancache
+flushed the pages when the inode kva was freed, much of the value
+of cleancache would be lost because the cache of pages in cleanache
+is potentially much larger than the kernel pagecache and is most
+useful if the pages survive inode cache removal.
+
+8) Why is a global variable required?
+
+The cleancache_enabled flag is checked in all of the frequently-used
+cleancache hooks. The alternative is a function call to check a static
+variable. Since cleancache is enabled dynamically at runtime, systems
+that don't enable cleancache would suffer thousands (possibly
+tens-of-thousands) of unnecessary function calls per second. So the
+global variable allows cleancache to be enabled by default at compile
+time, but have insignificant performance impact when cleancache remains
+disabled at runtime.
+
+9) Does cleanache work with KVM?
+
+The memory model of KVM is sufficiently different that a cleancache
+backend may have less value for KVM. This remains to be tested,
+especially in an overcommitted system.
+
+10) Does cleancache work in userspace? It sounds useful for
+ memory hungry caches like web browsers. (Jamie Lokier)
+
+No plans yet, though we agree it sounds useful, at least for
+apps that bypass the page cache (e.g. O_DIRECT).
+
+Last updated: Dan Magenheimer, April 13 2011
diff --git a/Documentation/vm/locking b/Documentation/vm/locking
index 25fadb448760..f61228bd6395 100644
--- a/Documentation/vm/locking
+++ b/Documentation/vm/locking
@@ -66,7 +66,7 @@ in some cases it is not really needed. Eg, vm_start is modified by
expand_stack(), it is hard to come up with a destructive scenario without
having the vmlist protection in this case.
-The page_table_lock nests with the inode i_mmap_lock and the kmem cache
+The page_table_lock nests with the inode i_mmap_mutex and the kmem cache
c_spinlock spinlocks. This is okay, since the kmem code asks for pages after
dropping c_spinlock. The page_table_lock also nests with pagecache_lock and
pagemap_lru_lock spinlocks, and no code asks for memory with these locks
diff --git a/Documentation/x86/x86_64/boot-options.txt b/Documentation/x86/x86_64/boot-options.txt
index 092e596a1301..c54b4f503e2a 100644
--- a/Documentation/x86/x86_64/boot-options.txt
+++ b/Documentation/x86/x86_64/boot-options.txt
@@ -206,7 +206,7 @@ IOMMU (input/output memory management unit)
(e.g. because you have < 3 GB memory).
Kernel boot message: "PCI-DMA: Disabling IOMMU"
- 2. <arch/x86_64/kernel/pci-gart.c>: AMD GART based hardware IOMMU.
+ 2. <arch/x86/kernel/amd_gart_64.c>: AMD GART based hardware IOMMU.
Kernel boot message: "PCI-DMA: using GART IOMMU"
3. <arch/x86_64/kernel/pci-swiotlb.c> : Software IOMMU implementation. Used
diff --git a/Documentation/zh_CN/email-clients.txt b/Documentation/zh_CN/email-clients.txt
new file mode 100644
index 000000000000..5d65e323d060
--- /dev/null
+++ b/Documentation/zh_CN/email-clients.txt
@@ -0,0 +1,210 @@
+锘?Chinese translated version of Documentation/email-clients.txt
+
+If you have any comment or update to the content, please contact the
+original document maintainer directly. However, if you have a problem
+communicating in English you can also ask the Chinese maintainer for
+help. Contact the Chinese maintainer if this translation is outdated
+or if there is a problem with the translation.
+
+Chinese maintainer: Harry Wei <harryxiyou@gmail.com>
+---------------------------------------------------------------------
+Documentation/email-clients.txt ???涓????缈�?
+
+æ¿¡??????å® ??ç’烘????å­˜?版???????????瀹癸??璇风?å­˜?ヨ??绯诲?????妗g??ç¼å­˜?よ?????æ¿¡????æµ£?浣跨?ㄨ?辨??
+浜ゆ???????ä¼´?剧??ç’‡?é”›?æ¶”????浠ュ??æ¶“???????ç¼å­˜?よ??å§¹???┿??æ¿¡???????缈æ˜????å­˜?é¢???????舵?????缈?
+ç’‡?瀛???ã„©??棰?é”›?璇疯??绯讳腑??????ç¼å­˜?よ?????
+
+æ¶“???????ç¼å­˜?よ??é”›? ç’æƒ§??濞? Harry Wei <harryxiyou@gmail.com>
+æ¶“???????缈æ˜?????é”›? ç’æƒ§??濞? Harry Wei <harryxiyou@gmail.com>
+涓?????????¤?????锛? Yinglin Luan <synmyth@gmail.com>
+ Xiaochen Wang <wangxiaochen0@gmail.com>
+ yaxinsn <yaxinsn@163.com>
+
+浠ヤ??涓烘?f??
+---------------------------------------------------------------------
+
+Linux???浠跺?㈡?风?????缃?淇℃??
+======================================================================
+
+?????????缃?
+----------------------------------------------------------------------
+Linux?????歌ˉ涓???????æ©????浠惰?????浜ょ??é”›????濂芥??ç›ãƒ¤??æµ£?æ¶“æ´ª??浠朵????????宓?????????????浜?ç¼å­˜?よ??
+??ユ?堕??浠讹??浣???????浠�????瀹规?煎??�璇ユ??"text/plain"?????惰??锛????浠朵????????涓?璧???????锛?
+???涓鸿??æµ¼?浣胯ˉ涓????寮???ã„©?ã„¥????ㄨ??ç’鸿??绋?æ¶“???????寰???ä¼´?俱??
+
+??ㄦ?ュ?????Linux?????歌ˉ涓???????æµ è·º?㈡?风????ã„¥?????ç›ãƒ¤????è·º??璇ュ??浜?????????????æ¿®???舵?????渚?æ¿¡?é”›?
+æµ ?æµ ?æ¶“???芥?ç‘°?????????????ã‚…?惰〃绗???????绌烘?ç¡·???????虫????ㄦ??æ¶“?ç›????寮?æ¾¶å­˜?????ç¼?ç俱??
+
+æ¶“?ç‘•????æ©?"format=flowed"妯″????????ç›ãƒ¤?????æ©???蜂??寮?璧蜂?????棰????浠ュ?????瀹崇?????ç›????
+
+æ¶“?ç‘•?ç’â•€????????æµ è·º?㈡?风??æ©?ç›??????ㄦ?㈣?????æ©???蜂??æµ¼???æ‘??æµ£????ç›ãƒ¤?????
+
+???æµ è·º?㈡?风??æ¶“???芥?ç‘°???????????瀛?ç»—????缂??????ç‘°?????ç‘•??????????ç›ãƒ¤???????芥??ASCII??????UTF-8缂??????ç‘°??é”›?
+æ¿¡????æµ£?浣跨??UTF-8缂??????ç‘°???????????浠讹????d??æµ£?ç?æµ¼???åž®??æ¶“?浜??????è—‰????????瀛?ç»—???????棰????
+
+???浠跺?㈡?风??�璇ュ舰???骞朵??淇???? References: ?????? In-Reply-To: ???棰?锛???d??
+???浠惰??棰?çå˜??æµ¼?æ¶“???????
+
+æ¾¶???å‰??甯?(?????????ç’寸??甯?)???甯é•????界?ㄤ??ç›ãƒ¤??é”›????æ¶“å“„?惰〃绗?æµ¼?æž????涓虹┖??笺??浣跨??xclipboard, xclip
+??????xcutselæ¶”?ç’稿??浠ワ??æµ£???????濂芥??ç’‡?æ¶“?æ¶“?????????åž®??浣跨?ã„¥????å‰??甯????
+
+æ¶“?ç‘•???ㄤ娇???PGP/GPG缃æ’????????浠朵腑??????ç›ãƒ¤?????æ©???蜂??浣垮??寰?æ¾¶???????æ¶“???借?诲??????????ㄤ??æµ£????ç›ãƒ¤?????
+锛?�涓????棰?�璇ユ?????浠ヤ慨澶????锛?
+
+??ã„§???????æ??æµ è·º??ç›ã„¥?????ç›ãƒ¤??æ¶”????é”›?ç¼????宸åž?????æ¶“?æ¶“?ç›ãƒ¤?????æ¶“?æ¶“???????涓绘??é”›?æ·‡?瀛???ユ?è·º?扮??
+???浠讹??ç?ç›ãƒ¤?????'patch'??戒护???æ¶“?é”›?æ¿¡??????????浜?é”›????ç¼??????æ??æµ è·º??ç›ã„¥????????
+
+
+涓?浜????浠跺?㈡?风?????绀?
+----------------------------------------------------------------------
+æ©????ç¼???è½°??浜?ç’‡?ç¼????MUA???缃????绀猴?????浠ョ?ㄤ??ç¼?Linux?????稿?????ç›ãƒ¤?????æ©?浜?骞朵???????虫??
+?????????�浠跺?????缃???�????
+
+璇存??锛?
+TUI = 浠ユ?????涓哄?虹???????ㄦ?锋?ュ??
+GUI = ??惧舰?????㈢?ㄦ?锋?ュ??
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Alpine (TUI)
+
+???缃????椤癸??
+???"Sending Preferences"??ã„¥??é”›?
+
+- "Do Not Send Flowed Text"蹇?椤诲?????
+- "Strip Whitespace Before Sending"蹇?椤诲?抽??
+
+褰???????浠舵?讹????????�璇ユ?惧?ㄨˉ涓?浼???虹?扮????版?癸????跺?????涓?CTRL-R�??????锛?浣挎??瀹????
+ç›ãƒ¤?????æµ è·º????ュ?ä¼´??浠朵腑???
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Evolution (GUI)
+
+æ¶“?浜?寮????????????????浣跨?ã„¥????????ç›ãƒ¤??
+
+褰??????╅??浠堕??椤癸??Preformat
+ 浠?Format->Heading->Preformatted (Ctrl-7)??????宸ュ?锋??
+
+??跺??浣跨??锛?
+ Insert->Text File... (Alt-n x)?????ヨˉ涓????浠躲??
+
+浣?�???浠?"diff -Nru old.c new.c | xclip"锛???????Preformat锛???跺??浣跨?ㄤ腑??撮??��绮?甯????
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Kmail (GUI)
+
+æ¶“?浜?寮????????????????浣跨?ã„¥????????ç›ãƒ¤?????
+
+榛?ç’よ?剧疆涓?æ¶“?HTML??ç…Ž??????????????é”›?æ¶“?ç‘•??????ã„¥?????
+
+褰?æ¶”????æ¶“?ç????æµ å‰????è·º??é”›???ã„©??椤逛?????æ¶“?ç‘•??????â•„????ㄦ?㈣????????æ¶“????缂虹?ç‘°æ°¨???æµ£???ã„©??浠朵腑æˆ???ョ??浠讳????????
+??戒??æµ¼?çš??????ㄦ?㈣??é”›????å§ã‚„??蹇?椤诲?ã„¥?????ç›ãƒ¤??æ¶”?????????ㄦ?㈣????????ç» ?????????è§„??ç辨???????ㄨ????ㄦ?㈣????ヤ功??????浠讹??
+??跺?????瀹?淇?瀛?涓鸿??绋裤??涓????浣???ㄨ??绋夸腑???娆℃??寮?瀹?锛?瀹?宸茬????ㄩ?ㄨ????ㄦ?㈣??浜?锛???d??浣???????浠惰?界?舵病???
+?????╄????ㄦ?㈣??锛?浣????�涓?浼?澶�诲凡???????????ㄦ?㈣?????
+
+??ã„©??æµ å‰??æ´????é”›??????ヨˉ涓?æ¶”????é”›???å¥??甯哥?ã„§??ç›ãƒ¤??瀹????ç»—?é”›?æ¶“?æ¶“?æ©?瀛????(---)???
+
+??è·º?????"Message"????????$??é”›??????â•‚????ユ??浠讹????ョ????????æµ£????ç›ãƒ¤?????浠躲??æ©????æ¶“?æ¶“?棰?æ¾¶???????椤癸??æµ£????æµ ?
+???�瀹????缃?浣???????浠跺缓绔?宸ュ?锋????????锛?�???浠ュ甫涓?"insert file"??炬?????
+
+æµ£????浠ュ????ã„¥?ä¼´??æ©?GPG???ç’ä¼´??浠讹??æµ£???????宓?ç›ãƒ¤?????濂戒??ç‘•?浣跨??GPG???ç’æ¿??æµ ????æµ£?æ¶“å“„??宓??????????绛惧??ç›ãƒ¤??é”›?
+褰?浠?GPG涓???????7浣?缂??????朵??浣夸??浠?????????�?澶???????
+
+æ¿¡????æµ£????ç‘•?浠ラ??æµ å‰??褰㈠????????ç›ãƒ¤??é”›???d??çåž?抽????ç‘°?婚??浠讹????è·º?????æ¶“?çž???Ñ??ç»????"Suggest automatic
+display"é”›?æ©???å³°??宓????浠舵?æ‘?è§„??ç’â•„?æ˜???????般??
+
+褰?æµ£?ç‘•?æ·‡?瀛?ç?ç‘•?????????????宓???????ç›ãƒ¤??é”›?æµ£????浠ヤ??娑???????ç›ã„§????奸????â•?????ç›ãƒ¤????????浠讹????è·º????冲?婚?????
+"save as"???æµ£????浠ヤ娇??ㄤ??æ¶“?娌℃????å­˜?圭????????ç›ãƒ¤????????浠讹??æ¿¡????瀹????浠ユ?g‘???褰㈠??ç¼???????褰?æµ£?å§ï½‡????ã„¥??
+???宸辩??�??d??涓?瀵????锛???f?舵病??????椤瑰??浠ヤ??瀛????浠?--宸茬?????涓?涓?�??风??bug�姹???ュ?�?kmail???bugzilla
+骞朵??甯????æ©?ç?æµ¼?çš?æ¾¶??????????浠舵??浠ュ?????瀵规??æ¶“???ㄦ?å³°??璇诲???????????çš?æ·‡?瀛????é”›????浠ュ?????æµ£???虫?????æµ è·º????è·º?æ¿?朵????版?癸??
+浣?涓?寰?涓????浠?浠????????????逛负�????????翠?????璇汇??
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Lotus Notes (GUI)
+
+涓?瑕?浣跨?ㄥ?????
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Mutt (TUI)
+
+寰?澶?Linux寮????浜哄??浣跨??mutt瀹㈡?风??锛????浠ヨ?????瀹????瀹?宸ヤ????????甯告??浜????
+
+Mutt涓????甯?缂?�???锛????浠ヤ??绠′??浣跨?ㄤ??涔?缂?�??ㄩ?戒??�璇ュ甫????????ㄦ??�???澶у????扮??�??ㄩ?藉甫???
+涓?涓?"insert file"???椤癸??瀹????浠ラ??�涓???瑰?????浠跺??瀹圭????瑰???????ユ??浠躲??
+
+'vim'浣?涓?mutt???缂?�???锛?
+ set editor="vi"
+
+ 濡????浣跨??xclip锛???�ヤ互涓???戒护
+ :set paste
+ ???涓????涔??????????shift-insert??????浣跨??
+ :r filename
+
+æ¿¡??????å® ?????ç›ãƒ¤??æµ£?æ¶“å“„??宓??????????
+(a)ttach宸ヤ?????寰?濂斤??涓?甯????"set paste"???
+
+???缃????椤癸??
+瀹?æ´?璇ヤ互榛?ç’よ?剧疆???褰㈠??宸ヤ?????
+??惰??é”›????"send_charset"ç’剧疆涓?"us-ascii::utf-8"æ¶”????æ¶“?æ¶“?æ¶“???????涓绘?????
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Pine (TUI)
+
+Pine�??绘??涓?浜?绌烘?煎????????棰?锛?浣????�浜???�ㄥ??璇ラ?借??淇?澶?浜????
+
+æ¿¡???????浠ワ??璇蜂娇???alpine(pine???ç¼Ñ„?胯??)
+
+???缃????椤癸??
+- ???�????????????瑕?娑???ゆ??绋???????
+- "no-strip-whitespace-before-send"???椤逛????????瑕???????
+
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Sylpheed (GUI)
+
+- ???宓??????????浠ュ??濂界??宸ヤ??锛???????浣跨?ㄩ??浠讹?????
+- ???ç’é•娇??ã„¥????ã„§??缂?æˆ???ã„£??
+- 瀵逛?????褰?�澶???堕??甯告?????
+- 濡???????�non-SSL�??ワ?????娉?浣跨??TLS SMTP?????????
+- ??ㄧ?????�??d腑???涓?涓?寰??????ㄧ??ruler bar???
+- ç¼???æ¿?????æ¶“?娣诲????æ¿??çå˜??æµ¼?å§ï½‡â€˜???浜?瑙f?剧ãš??????
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Thunderbird (GUI)
+
+榛?ç’ゆ????å…¸??é”›?thunderbird寰?瀹规??????????????é”›?æµ£????æ©????æ¶“?浜???è§„?????浠ュ己??è·º?????寰???æ‘ソ???
+
+- ??ㄧ?ㄦ?峰????疯?剧疆???锛?�??????瀵诲??锛?涓?瑕???????"Compose messages in HTML format"???
+
+- 缂?æˆ?æµ£????Thunderbird???缃?ç’剧疆??ヤ娇瀹?æ¶“?ç‘•????ç›?浣跨??é”›?user_pref("mailnews.wraplength", 0);
+
+- 缂?æˆ?æµ£????Thunderbird???缃?ç’剧疆锛?浣垮??æ¶“?ç‘•?浣跨??"format=flowed"??ç…Ž??é”›?user_pref("mailnews.
+ send_plaintext_flowed", false);
+
+- æµ£????ç‘•?æµ£?Thunderbird???æ¶“æ´ª???????ç…Ž????ç‘°??é”›?
+ æ¿¡????榛?ç’ゆ????å…¸??æµ£?æ¶”??????????HTML??ç…Ž??é”›???d?????寰???俱??æµ ?æµ ?æµ ????棰???????æ¶“????妗?æ¶“???????"Preformat"??ç…Ž?????
+ æ¿¡????榛?ç’ゆ????å…¸??æµ£?æ¶”??????????????????ç…Ž??é”›?æµ£?æ¶“?寰????瀹???逛负HTML??ç…Ž??é”›?æµ ?æµ ?æµ£?æ¶“è½°??娆℃?Ñ…??é”›???ヤ功?????扮??娑????é”›?
+ ??è·º??寮哄?朵娇瀹??????版???????ç…Ž??é”›???????瀹?çå˜?????ç›????ç‘•?瀹???æ¿??é”›???ã„¥??淇$????炬??æ¶“?浣跨??shift?????ヤ娇瀹????æ¶“?HTML
+ ??煎??锛???跺?????棰???????涓????妗?涓???????"Preformat"??煎?????
+
+- ???ç’é•娇??ã„¥????ã„§??缂?æˆ????é”›?
+ ???瀵?Thunderbird???ç›ãƒ¤?????ç» ?????????è§„??ç辨??浣跨?ㄤ??æ¶“?"external editor"??â•??é”›???è·º??浣跨?ㄤ????????娆㈢??
+ $EDITOR??ヨ?诲???????????骞惰ˉ涓???版?????æ¶“????ç‘•?瀹???æ¿??é”›????浠ヤ??æžè—‰è‹Ÿæ¶“?瀹?ç‘?æ©?æ¶“???â•??é”›???è·º??娣诲??æ¶“?æ¶“?浣跨?ã„¥?????
+ ??????View->Toolbars->Customize...??????褰?æµ£?æ¶”????淇℃???????è·º??æµ ?æµ ???ç‘°?诲??çåž??浠ヤ?????
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+TkRat (GUI)
+
+???浠ヤ娇??ㄥ?????浣跨??"Insert file..."??????澶???ㄧ??缂?�??ㄣ??
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Gmail (Web GUI)
+
+æ¶“?ç‘•?浣跨?ã„¥????????ç›ãƒ¤?????
+
+Gmail缃?椤�㈡?风???????ㄥ?版????惰〃绗?�???涓虹┖??笺??
+
+??界?跺?惰〃绗?�???涓虹┖??奸??棰????浠ヨ??澶???ㄧ??�??ㄨВ??筹???????跺??�浼?浣跨?ㄥ??�??㈣?????姣?�??????涓?78涓?瀛?绗????
+
+???涓?涓????棰????Gmail�浼????浠讳??涓????ASCII???瀛?绗????淇℃????逛负base64缂???????瀹????涓?瑗垮????????娆ф床浜虹?????瀛????
+
+ ###
diff --git a/MAINTAINERS b/MAINTAINERS
index ec947424f702..a6562ba1dc35 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -287,35 +287,35 @@ F: sound/pci/ad1889.*
AD525X ANALOG DEVICES DIGITAL POTENTIOMETERS DRIVER
M: Michael Hennerich <michael.hennerich@analog.com>
-L: device-driver-devel@blackfin.uclinux.org
+L: device-drivers-devel@blackfin.uclinux.org
W: http://wiki.analog.com/AD5254
S: Supported
F: drivers/misc/ad525x_dpot.c
AD5398 CURRENT REGULATOR DRIVER (AD5398/AD5821)
M: Michael Hennerich <michael.hennerich@analog.com>
-L: device-driver-devel@blackfin.uclinux.org
+L: device-drivers-devel@blackfin.uclinux.org
W: http://wiki.analog.com/AD5398
S: Supported
F: drivers/regulator/ad5398.c
AD714X CAPACITANCE TOUCH SENSOR DRIVER (AD7142/3/7/8/7A)
M: Michael Hennerich <michael.hennerich@analog.com>
-L: device-driver-devel@blackfin.uclinux.org
+L: device-drivers-devel@blackfin.uclinux.org
W: http://wiki.analog.com/AD7142
S: Supported
F: drivers/input/misc/ad714x.c
AD7877 TOUCHSCREEN DRIVER
M: Michael Hennerich <michael.hennerich@analog.com>
-L: device-driver-devel@blackfin.uclinux.org
+L: device-drivers-devel@blackfin.uclinux.org
W: http://wiki.analog.com/AD7877
S: Supported
F: drivers/input/touchscreen/ad7877.c
AD7879 TOUCHSCREEN DRIVER (AD7879/AD7889)
M: Michael Hennerich <michael.hennerich@analog.com>
-L: device-driver-devel@blackfin.uclinux.org
+L: device-drivers-devel@blackfin.uclinux.org
W: http://wiki.analog.com/AD7879
S: Supported
F: drivers/input/touchscreen/ad7879.c
@@ -341,7 +341,7 @@ F: drivers/net/wireless/adm8211.*
ADP5520 BACKLIGHT DRIVER WITH IO EXPANDER (ADP5520/ADP5501)
M: Michael Hennerich <michael.hennerich@analog.com>
-L: device-driver-devel@blackfin.uclinux.org
+L: device-drivers-devel@blackfin.uclinux.org
W: http://wiki.analog.com/ADP5520
S: Supported
F: drivers/mfd/adp5520.c
@@ -352,7 +352,7 @@ F: drivers/input/keyboard/adp5520-keys.c
ADP5588 QWERTY KEYPAD AND IO EXPANDER DRIVER (ADP5588/ADP5587)
M: Michael Hennerich <michael.hennerich@analog.com>
-L: device-driver-devel@blackfin.uclinux.org
+L: device-drivers-devel@blackfin.uclinux.org
W: http://wiki.analog.com/ADP5588
S: Supported
F: drivers/input/keyboard/adp5588-keys.c
@@ -360,7 +360,7 @@ F: drivers/gpio/adp5588-gpio.c
ADP8860 BACKLIGHT DRIVER (ADP8860/ADP8861/ADP8863)
M: Michael Hennerich <michael.hennerich@analog.com>
-L: device-driver-devel@blackfin.uclinux.org
+L: device-drivers-devel@blackfin.uclinux.org
W: http://wiki.analog.com/ADP8860
S: Supported
F: drivers/video/backlight/adp8860_bl.c
@@ -387,7 +387,7 @@ F: drivers/hwmon/adt7475.c
ADXL34X THREE-AXIS DIGITAL ACCELEROMETER DRIVER (ADXL345/ADXL346)
M: Michael Hennerich <michael.hennerich@analog.com>
-L: device-driver-devel@blackfin.uclinux.org
+L: device-drivers-devel@blackfin.uclinux.org
W: http://wiki.analog.com/ADXL345
S: Supported
F: drivers/input/misc/adxl34x.c
@@ -405,8 +405,8 @@ S: Maintained
F: sound/oss/aedsp16.c
AFFS FILE SYSTEM
-M: Roman Zippel <zippel@linux-m68k.org>
-S: Maintained
+L: linux-fsdevel@vger.kernel.org
+S: Orphan
F: Documentation/filesystems/affs.txt
F: fs/affs/
@@ -483,6 +483,13 @@ F: drivers/tty/serial/altera_jtaguart.c
F: include/linux/altera_uart.h
F: include/linux/altera_jtaguart.h
+AMD FAM15H PROCESSOR POWER MONITORING DRIVER
+M: Andreas Herrmann <andreas.herrmann3@amd.com>
+L: lm-sensors@lm-sensors.org
+S: Maintained
+F: Documentation/hwmon/fam15h_power
+F: drivers/hwmon/fam15h_power.c
+
AMD GEODE CS5536 USB DEVICE CONTROLLER DRIVER
M: Thomas Dahlmann <dahlmann.thomas@arcor.de>
L: linux-geode@lists.infradead.org (moderated for non-subscribers)
@@ -526,7 +533,7 @@ S: Maintained
F: drivers/infiniband/hw/amso1100/
ANALOG DEVICES INC ASOC CODEC DRIVERS
-L: device-driver-devel@blackfin.uclinux.org
+L: device-drivers-devel@blackfin.uclinux.org
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
W: http://wiki.analog.com/
S: Supported
@@ -548,10 +555,11 @@ S: Maintained
F: sound/aoa/
APM DRIVER
-L: linux-laptop@vger.kernel.org
-S: Orphan
+M: Jiri Kosina <jkosina@suse.cz>
+S: Odd fixes
F: arch/x86/kernel/apm_32.c
F: include/linux/apm_bios.h
+F: drivers/char/apm-emulation.c
APPLE BCM5974 MULTITOUCH DRIVER
M: Henrik Rydberg <rydberg@euromail.se>
@@ -729,7 +737,7 @@ ARM/EZX SMARTPHONES (A780, A910, A1200, E680, ROKR E2 and ROKR E6)
M: Daniel Ribeiro <drwyrm@gmail.com>
M: Stefan Schmidt <stefan@openezx.org>
M: Harald Welte <laforge@openezx.org>
-L: openezx-devel@lists.openezx.org (subscribers-only)
+L: openezx-devel@lists.openezx.org (moderated for non-subscribers)
W: http://www.openezx.org/
S: Maintained
T: topgit git://git.openezx.org/openezx.git
@@ -923,6 +931,8 @@ F: drivers/mmc/host/msm_sdcc.h
F: drivers/tty/serial/msm_serial.h
F: drivers/tty/serial/msm_serial.c
F: drivers/platform/msm/
+F: drivers/*/pm8???-*
+F: include/linux/mfd/pm8xxx/
T: git git://codeaurora.org/quic/kernel/davidb/linux-msm.git
S: Maintained
@@ -1232,13 +1242,6 @@ W: http://wireless.kernel.org/en/users/Drivers/ath9k
S: Supported
F: drivers/net/wireless/ath/ath9k/
-ATHEROS AR9170 WIRELESS DRIVER
-M: Christian Lamparter <chunkeey@web.de>
-L: linux-wireless@vger.kernel.org
-W: http://wireless.kernel.org/en/users/Drivers/ar9170
-S: Obsolete
-F: drivers/net/wireless/ath/ar9170/
-
CARL9170 LINUX COMMUNITY WIRELESS DRIVER
M: Christian Lamparter <chunkeey@googlemail.com>
L: linux-wireless@vger.kernel.org
@@ -2040,9 +2043,8 @@ F: net/ax25/ax25_timer.c
F: net/ax25/sysctl_net_ax25.c
DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER
-M: Tobias Ringstrom <tori@unhappy.mine.nu>
L: netdev@vger.kernel.org
-S: Maintained
+S: Orphan
F: Documentation/networking/dmfe.txt
F: drivers/net/tulip/dmfe.c
@@ -2251,10 +2253,10 @@ F: drivers/gpu/drm/
F: include/drm/
INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
-M: Chris Wilson <chris@chris-wilson.co.uk>
+M: Keith Packard <keithp@keithp.com>
L: intel-gfx@lists.freedesktop.org (subscribers-only)
L: dri-devel@lists.freedesktop.org
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/ickle/drm-intel.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/keithp/linux-2.6.git
S: Supported
F: drivers/gpu/drm/i915
F: include/drm/i915*
@@ -2582,6 +2584,13 @@ S: Maintained
F: drivers/hwmon/f75375s.c
F: include/linux/f75375s.h
+FIREWIRE AUDIO DRIVERS
+M: Clemens Ladisch <clemens@ladisch.de>
+L: alsa-devel@alsa-project.org (moderated for non-subscribers)
+T: git git://git.alsa-project.org/alsa-kernel.git
+S: Maintained
+F: sound/firewire/
+
FIREWIRE SUBSYSTEM
M: Stefan Richter <stefanr@s5r6.in-berlin.de>
L: linux1394-devel@lists.sourceforge.net
@@ -2946,8 +2955,8 @@ F: drivers/block/cciss*
F: include/linux/cciss_ioctl.h
HFS FILESYSTEM
-M: Roman Zippel <zippel@linux-m68k.org>
-S: Maintained
+L: linux-fsdevel@vger.kernel.org
+S: Orphan
F: Documentation/filesystems/hfs.txt
F: fs/hfs/
@@ -3363,6 +3372,12 @@ F: Documentation/wimax/README.i2400m
F: drivers/net/wimax/i2400m/
F: include/linux/wimax/i2400m.h
+INTEL WIRELESS 3945ABG/BG, 4965AGN (iwlegacy)
+M: Stanislaw Gruszka <sgruszka@redhat.com>
+L: linux-wireless@vger.kernel.org
+S: Supported
+F: drivers/net/wireless/iwlegacy/
+
INTEL WIRELESS WIFI LINK (iwlwifi)
M: Wey-Yi Guy <wey-yi.w.guy@intel.com>
M: Intel Linux Wireless <ilw@linux.intel.com>
@@ -3566,9 +3581,16 @@ M: Andrew Morton <akpm@linux-foundation.org>
M: Jan Kara <jack@suse.cz>
L: linux-ext4@vger.kernel.org
S: Maintained
-F: fs/jbd*/
-F: include/linux/ext*jbd*.h
-F: include/linux/jbd*.h
+F: fs/jbd/
+F: include/linux/ext3_jbd.h
+F: include/linux/jbd.h
+
+JOURNALLING LAYER FOR BLOCK DEVICES (JBD2)
+M: "Theodore Ts'o" <tytso@mit.edu>
+L: linux-ext4@vger.kernel.org
+S: Maintained
+F: fs/jbd2/
+F: include/linux/jbd2.h
JSM Neo PCI based serial card
M: Breno Leitao <leitao@linux.vnet.ibm.com>
@@ -3591,10 +3613,9 @@ F: Documentation/hwmon/k8temp
F: drivers/hwmon/k8temp.c
KCONFIG
-M: Roman Zippel <zippel@linux-m68k.org>
+M: Michal Marek <mmarek@suse.cz>
L: linux-kbuild@vger.kernel.org
-Q: http://patchwork.kernel.org/project/linux-kbuild/list/
-S: Maintained
+S: Odd Fixes
F: Documentation/kbuild/kconfig-language.txt
F: scripts/kconfig/
@@ -3898,7 +3919,6 @@ F: drivers/*/*/*pasemi*
LINUX SECURITY MODULE (LSM) FRAMEWORK
M: Chris Wright <chrisw@sous-sol.org>
L: linux-security-module@vger.kernel.org
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/chrisw/lsm-2.6.git
S: Supported
LIS3LV02D ACCELEROMETER DRIVER
@@ -4001,7 +4021,6 @@ F: arch/m32r/
M68K ARCHITECTURE
M: Geert Uytterhoeven <geert@linux-m68k.org>
-M: Roman Zippel <zippel@linux-m68k.org>
L: linux-m68k@lists.linux-m68k.org
W: http://www.linux-m68k.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k.git
@@ -4135,6 +4154,7 @@ M: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
L: linux-mm@kvack.org
S: Maintained
F: mm/memcontrol.c
+F: mm/page_cgroup.c
MEMORY TECHNOLOGY DEVICES (MTD)
M: David Woodhouse <dwmw2@infradead.org>
@@ -4254,7 +4274,7 @@ F: include/linux/isicom.h
MUSB MULTIPOINT HIGH SPEED DUAL-ROLE CONTROLLER
M: Felipe Balbi <balbi@ti.com>
L: linux-usb@vger.kernel.org
-T: git git://gitorious.org/usb/usb.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
S: Maintained
F: drivers/usb/musb/
@@ -4271,6 +4291,13 @@ M: Tim Hockin <thockin@hockin.org>
S: Maintained
F: drivers/net/natsemi.c
+NATIVE INSTRUMENTS USB SOUND INTERFACE DRIVER
+M: Daniel Mack <zonque@gmail.com>
+S: Maintained
+L: alsa-devel@alsa-project.org
+W: http://www.native-instruments.com
+F: sound/usb/caiaq/
+
NCP FILESYSTEM
M: Petr Vandrovec <petr@vandrovec.name>
S: Odd Fixes
@@ -4386,6 +4413,7 @@ S: Maintained
F: net/ipv4/
F: net/ipv6/
F: include/net/ip*
+F: arch/x86/net/*
NETWORKING [LABELED] (NetLabel, CIPSO, Labeled IPsec, SECMARK)
M: Paul Moore <paul.moore@hp.com>
@@ -4581,6 +4609,7 @@ M: Felipe Balbi <balbi@ti.com>
M: David Brownell <dbrownell@users.sourceforge.net>
L: linux-usb@vger.kernel.org
L: linux-omap@vger.kernel.org
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
S: Maintained
F: drivers/usb/*/*omap*
F: arch/arm/*omap*/usb*
@@ -5432,6 +5461,7 @@ F: include/linux/timex.h
F: kernel/time/clocksource.c
F: kernel/time/time*.c
F: kernel/time/ntp.c
+F: drivers/clocksource
TLG2300 VIDEO4LINUX-2 DRIVER
M: Huang Shijie <shijie8@gmail.com>
@@ -5583,10 +5613,11 @@ M: James Morris <jmorris@namei.org>
M: Eric Paris <eparis@parisplace.org>
L: selinux@tycho.nsa.gov (subscribers-only, general discussion)
W: http://selinuxproject.org
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6.git
+T: git git://git.infradead.org/users/eparis/selinux.git
S: Supported
F: include/linux/selinux*
F: security/selinux/
+F: scripts/selinux/
APPARMOR SECURITY MODULE
M: John Johansen <john.johansen@canonical.com>
@@ -5612,9 +5643,9 @@ F: include/linux/ata.h
F: include/linux/libata.h
SERVER ENGINES 10Gbps iSCSI - BladeEngine 2 DRIVER
-M: Jayamohan Kallickal <jayamohank@serverengines.com>
+M: Jayamohan Kallickal <jayamohan.kallickal@emulex.com>
L: linux-scsi@vger.kernel.org
-W: http://www.serverengines.com
+W: http://www.emulex.com
S: Supported
F: drivers/scsi/be2iscsi/
@@ -5832,6 +5863,13 @@ S: Maintained
F: drivers/ssb/
F: include/linux/ssb/
+BROADCOM SPECIFIC AMBA DRIVER (BCMA)
+M: Rafał Miłecki <zajec5@gmail.com>
+L: linux-wireless@vger.kernel.org
+S: Maintained
+F: drivers/bcma/
+F: include/linux/bcma/
+
SONY VAIO CONTROL DEVICE DRIVER
M: Mattia Dongili <malattia@linux.it>
L: platform-driver-x86@vger.kernel.org
@@ -5861,7 +5899,7 @@ F: include/sound/
F: sound/
SOUND - SOC LAYER / DYNAMIC AUDIO POWER MANAGEMENT (ASoC)
-M: Liam Girdwood <lrg@slimlogic.co.uk>
+M: Liam Girdwood <lrg@ti.com>
M: Mark Brown <broonie@opensource.wolfsonmicro.com>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6.git
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
@@ -5970,7 +6008,7 @@ F: Documentation/filesystems/spufs.txt
F: arch/powerpc/platforms/cell/spufs/
SQUASHFS FILE SYSTEM
-M: Phillip Lougher <phillip@lougher.demon.co.uk>
+M: Phillip Lougher <phillip@squashfs.org.uk>
L: squashfs-devel@lists.sourceforge.net (subscribers-only)
W: http://squashfs.org.uk
S: Maintained
@@ -6112,7 +6150,7 @@ F: drivers/mmc/host/tifm_sd.c
F: include/linux/tifm.h
TI TWL4030 SERIES SOC CODEC DRIVER
-M: Peter Ujfalusi <peter.ujfalusi@nokia.com>
+M: Peter Ujfalusi <peter.ujfalusi@ti.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Maintained
F: sound/soc/codecs/twl4030*
@@ -6215,6 +6253,7 @@ TRIVIAL PATCHES
M: Jiri Kosina <trivial@kernel.org>
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial.git
S: Maintained
+K: ^Subject:.*(?i)trivial
TTY LAYER
M: Greg Kroah-Hartman <gregkh@suse.de>
@@ -6756,7 +6795,7 @@ F: drivers/scsi/vmw_pvscsi.c
F: drivers/scsi/vmw_pvscsi.h
VOLTAGE AND CURRENT REGULATOR FRAMEWORK
-M: Liam Girdwood <lrg@slimlogic.co.uk>
+M: Liam Girdwood <lrg@ti.com>
M: Mark Brown <broonie@opensource.wolfsonmicro.com>
W: http://opensource.wolfsonmicro.com/node/15
W: http://www.slimlogic.co.uk/?p=48
@@ -6778,6 +6817,13 @@ L: lm-sensors@lm-sensors.org
S: Maintained
F: drivers/hwmon/vt8231.c
+VUB300 USB to SDIO/SD/MMC bridge chip
+M: Tony Olech <tony.olech@elandigitalsystems.com>
+L: linux-mmc@vger.kernel.org
+L: linux-usb@vger.kernel.org
+S: Supported
+F: drivers/mmc/host/vub300.c
+
W1 DALLAS'S 1-WIRE BUS
M: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
S: Maintained
diff --git a/Makefile b/Makefile
index 123d858dae03..529d93fa2430 100644
--- a/Makefile
+++ b/Makefile
@@ -103,7 +103,7 @@ ifeq ("$(origin O)", "command line")
endif
ifeq ("$(origin W)", "command line")
- export KBUILD_ENABLE_EXTRA_GCC_CHECKS := 1
+ export KBUILD_ENABLE_EXTRA_GCC_CHECKS := $(W)
endif
# That's our default target when none is given on the command line
@@ -220,6 +220,14 @@ ifeq ($(ARCH),sh64)
SRCARCH := sh
endif
+# Additional ARCH settings for tile
+ifeq ($(ARCH),tilepro)
+ SRCARCH := tile
+endif
+ifeq ($(ARCH),tilegx)
+ SRCARCH := tile
+endif
+
# Where to locate arch specific headers
hdr-arch := $(SRCARCH)
@@ -349,7 +357,8 @@ CFLAGS_GCOV = -fprofile-arcs -ftest-coverage
# Use LINUXINCLUDE when you must reference the include/ directory.
# Needed to be compatible with the O= option
-LINUXINCLUDE := -I$(srctree)/arch/$(hdr-arch)/include -Iinclude \
+LINUXINCLUDE := -I$(srctree)/arch/$(hdr-arch)/include \
+ -Iarch/$(hdr-arch)/include/generated -Iinclude \
$(if $(KBUILD_SRC), -I$(srctree)/include) \
-include include/generated/autoconf.h
@@ -382,6 +391,7 @@ 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
+export KBUILD_ARFLAGS
# When compiling out-of-tree modules, put MODVERDIR in the module
# tree rather than in the kernel tree. The kernel tree might
@@ -416,6 +426,12 @@ ifneq ($(KBUILD_SRC),)
$(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
endif
+# Support for using generic headers in asm-generic
+PHONY += asm-generic
+asm-generic:
+ $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.asm-generic \
+ obj=arch/$(SRCARCH)/include/generated/asm
+
# To make sure we do not include .config for any of the *config targets
# catch them early, and hand them over to scripts/kconfig/Makefile
# It is allowed to specify more targets when calling make, including
@@ -559,6 +575,10 @@ ifndef CONFIG_CC_STACKPROTECTOR
KBUILD_CFLAGS += $(call cc-option, -fno-stack-protector)
endif
+# This warning generated too much noise in a regular build.
+# Use make W=1 to enable this warning (see scripts/Makefile.build)
+KBUILD_CFLAGS += $(call cc-disable-warning, unused-but-set-variable)
+
ifdef CONFIG_FRAME_POINTER
KBUILD_CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls
else
@@ -604,7 +624,7 @@ CHECKFLAGS += $(NOSTDINC_FLAGS)
KBUILD_CFLAGS += $(call cc-option,-Wdeclaration-after-statement,)
# disable pointer signed / unsigned warnings in gcc 4.0
-KBUILD_CFLAGS += $(call cc-option,-Wno-pointer-sign,)
+KBUILD_CFLAGS += $(call cc-disable-warning, pointer-sign)
# disable invalid "can't wrap" optimizations for signed / pointers
KBUILD_CFLAGS += $(call cc-option,-fno-strict-overflow)
@@ -612,6 +632,9 @@ KBUILD_CFLAGS += $(call cc-option,-fno-strict-overflow)
# conserve stack if available
KBUILD_CFLAGS += $(call cc-option,-fconserve-stack)
+# use the deterministic mode of AR if available
+KBUILD_ARFLAGS := $(call ar-option,D)
+
# check for 'asm goto'
ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC)), y)
KBUILD_CFLAGS += -DCC_HAVE_ASM_GOTO
@@ -797,15 +820,17 @@ ifdef CONFIG_KALLSYMS
# o The correct .tmp_kallsyms2.o is linked into the final vmlinux.
# o Verify that the System.map from vmlinux matches the map from
# .tmp_vmlinux2, just in case we did not generate kallsyms correctly.
-# o If CONFIG_KALLSYMS_EXTRA_PASS is set, do an extra pass using
+# o If 'make KALLSYMS_EXTRA_PASS=1" was used, do an extra pass using
# .tmp_vmlinux3 and .tmp_kallsyms3.o. This is only meant as a
# temporary bypass to allow the kernel to be built while the
# maintainers work out what went wrong with kallsyms.
-ifdef CONFIG_KALLSYMS_EXTRA_PASS
-last_kallsyms := 3
-else
last_kallsyms := 2
+
+ifdef KALLSYMS_EXTRA_PASS
+ifneq ($(KALLSYMS_EXTRA_PASS),0)
+last_kallsyms := 3
+endif
endif
kallsyms.o := .tmp_kallsyms$(last_kallsyms).o
@@ -816,7 +841,8 @@ define verify_kallsyms
$(cmd_sysmap) .tmp_vmlinux$(last_kallsyms) .tmp_System.map
$(Q)cmp -s System.map .tmp_System.map || \
(echo Inconsistent kallsyms data; \
- echo Try setting CONFIG_KALLSYMS_EXTRA_PASS; \
+ echo This is a bug - please report about it; \
+ echo Try "make KALLSYMS_EXTRA_PASS=1" as a workaround; \
rm .tmp_kallsyms* ; /bin/false )
endef
@@ -947,7 +973,7 @@ ifneq ($(KBUILD_SRC),)
endif
# prepare2 creates a makefile if using a separate output directory
-prepare2: prepare3 outputmakefile
+prepare2: prepare3 outputmakefile asm-generic
prepare1: prepare2 include/linux/version.h include/generated/utsrelease.h \
include/config/auto.conf
@@ -991,7 +1017,8 @@ include/generated/utsrelease.h: include/config/kernel.release FORCE
PHONY += headerdep
headerdep:
- $(Q)find include/ -name '*.h' | xargs --max-args 1 scripts/headerdep.pl
+ $(Q)find $(srctree)/include/ -name '*.h' | xargs --max-args 1 \
+ $(srctree)/scripts/headerdep.pl -I$(srctree)/include
# ---------------------------------------------------------------------------
@@ -1021,7 +1048,7 @@ hdr-inst := -rR -f $(srctree)/scripts/Makefile.headersinst obj
hdr-dst = $(if $(KBUILD_HEADERS), dst=include/asm-$(hdr-arch), dst=include/asm)
PHONY += __headers
-__headers: include/linux/version.h scripts_basic FORCE
+__headers: include/linux/version.h scripts_basic asm-generic FORCE
$(Q)$(MAKE) $(build)=scripts build_unifdef
PHONY += headers_install_all
@@ -1136,7 +1163,8 @@ CLEAN_FILES += vmlinux System.map \
.tmp_kallsyms* .tmp_version .tmp_vmlinux* .tmp_System.map
# Directories & files removed with 'make mrproper'
-MRPROPER_DIRS += include/config usr/include include/generated
+MRPROPER_DIRS += include/config usr/include include/generated \
+ arch/*/include/generated
MRPROPER_FILES += .config .config.old .version .old_version \
include/linux/version.h \
Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS
@@ -1267,7 +1295,12 @@ help:
@echo ' make O=dir [targets] Locate all output files in "dir", including .config'
@echo ' make C=1 [targets] Check all c source with $$CHECK (sparse by default)'
@echo ' make C=2 [targets] Force check of all c source with $$CHECK'
- @echo ' make W=1 [targets] Enable extra gcc checks'
+ @echo ' make W=n [targets] Enable extra gcc checks, n=1,2,3 where'
+ @echo ' 1: warnings which may be relevant and do not occur too often'
+ @echo ' 2: warnings which occur quite often but may still be relevant'
+ @echo ' 3: more obscure warnings, can most likely be ignored'
+ @echo ' Multiple levels can be combined with W=12 or W=123'
+ @echo ' make RECORDMCOUNT_WARN=1 [targets] Warn about ignored mcount sections'
@echo ''
@echo 'Execute "make" or "make all" to build all targets marked with [*] '
@echo 'For further info see the ./README file'
@@ -1290,6 +1323,7 @@ $(help-board-dirs): help-%:
# Documentation targets
# ---------------------------------------------------------------------------
%docs: scripts_basic FORCE
+ $(Q)$(MAKE) $(build)=scripts build_docproc
$(Q)$(MAKE) $(build)=Documentation/DocBook $@
else # KBUILD_EXTMOD
@@ -1374,7 +1408,7 @@ endif # KBUILD_EXTMOD
clean: $(clean-dirs)
$(call cmd,rmdirs)
$(call cmd,rmfiles)
- @find $(or $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \
+ @find $(if $(KBUILD_EXTMOD), $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \
\( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
-o -name '*.symtypes' -o -name 'modules.order' \
@@ -1392,13 +1426,15 @@ tags TAGS cscope gtags: FORCE
# Scripts to check various things for consistency
# ---------------------------------------------------------------------------
+PHONY += includecheck versioncheck coccicheck namespacecheck export_report
+
includecheck:
- find * $(RCS_FIND_IGNORE) \
+ find $(srctree)/* $(RCS_FIND_IGNORE) \
-name '*.[hcS]' -type f -print | sort \
| xargs $(PERL) -w $(srctree)/scripts/checkincludes.pl
versioncheck:
- find * $(RCS_FIND_IGNORE) \
+ find $(srctree)/* $(RCS_FIND_IGNORE) \
-name '*.[hcS]' -type f -print | sort \
| xargs $(PERL) -w $(srctree)/scripts/checkversion.pl
diff --git a/arch/Kconfig b/arch/Kconfig
index f78c2be4242b..26b0e2397a57 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -144,9 +144,6 @@ config HAVE_CLK
config HAVE_DMA_API_DEBUG
bool
-config HAVE_DEFAULT_NO_SPIN_MUTEXES
- bool
-
config HAVE_HW_BREAKPOINT
bool
depends on PERF_EVENTS
@@ -178,4 +175,7 @@ config HAVE_ARCH_JUMP_LABEL
config HAVE_ARCH_MUTEX_CPU_RELAX
bool
+config HAVE_RCU_TABLE_FREE
+ bool
+
source "kernel/gcov/Kconfig"
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 9808998cc073..60219bf94198 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -12,6 +12,7 @@ config ALPHA
select GENERIC_IRQ_PROBE
select AUTO_IRQ_AFFINITY if SMP
select GENERIC_IRQ_SHOW
+ select ARCH_WANT_OPTIONAL_GPIOLIB
help
The Alpha is a 64-bit general-purpose processor designed and
marketed by the Digital Equipment Corporation of blessed memory,
@@ -40,10 +41,6 @@ config ARCH_HAS_ILOG2_U64
bool
default n
-config GENERIC_FIND_NEXT_BIT
- bool
- default y
-
config GENERIC_CALIBRATE_DELAY
bool
default y
@@ -51,6 +48,9 @@ config GENERIC_CALIBRATE_DELAY
config GENERIC_CMOS_UPDATE
def_bool y
+config GENERIC_GPIO
+ def_bool y
+
config ZONE_DMA
bool
default y
diff --git a/arch/alpha/include/asm/gpio.h b/arch/alpha/include/asm/gpio.h
new file mode 100644
index 000000000000..7dc6a6343c06
--- /dev/null
+++ b/arch/alpha/include/asm/gpio.h
@@ -0,0 +1,55 @@
+/*
+ * Generic GPIO API implementation for Alpha.
+ *
+ * A stright copy of that for PowerPC which was:
+ *
+ * Copyright (c) 2007-2008 MontaVista Software, Inc.
+ *
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _ASM_ALPHA_GPIO_H
+#define _ASM_ALPHA_GPIO_H
+
+#include <linux/errno.h>
+#include <asm-generic/gpio.h>
+
+#ifdef CONFIG_GPIOLIB
+
+/*
+ * We don't (yet) implement inlined/rapid versions for on-chip gpios.
+ * Just call gpiolib.
+ */
+static inline int gpio_get_value(unsigned int gpio)
+{
+ return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned int gpio, int value)
+{
+ __gpio_set_value(gpio, value);
+}
+
+static inline int gpio_cansleep(unsigned int gpio)
+{
+ return __gpio_cansleep(gpio);
+}
+
+static inline int gpio_to_irq(unsigned int gpio)
+{
+ return __gpio_to_irq(gpio);
+}
+
+static inline int irq_to_gpio(unsigned int irq)
+{
+ return -EINVAL;
+}
+
+#endif /* CONFIG_GPIOLIB */
+
+#endif /* _ASM_ALPHA_GPIO_H */
diff --git a/arch/alpha/include/asm/smp.h b/arch/alpha/include/asm/smp.h
index 3f390e8cc0b3..c46e714aa3e0 100644
--- a/arch/alpha/include/asm/smp.h
+++ b/arch/alpha/include/asm/smp.h
@@ -39,8 +39,6 @@ struct cpuinfo_alpha {
extern struct cpuinfo_alpha cpu_data[NR_CPUS];
-#define PROC_CHANGE_PENALTY 20
-
#define hard_smp_processor_id() __hard_smp_processor_id()
#define raw_smp_processor_id() (current_thread_info()->cpu)
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index 3ec35066f1dc..838eac128409 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -121,7 +121,7 @@ common_shutdown_1(void *generic_ptr)
/* Wait for the secondaries to halt. */
set_cpu_present(boot_cpuid, false);
set_cpu_possible(boot_cpuid, false);
- while (cpus_weight(cpu_present_map))
+ while (cpumask_weight(cpu_present_mask))
barrier();
#endif
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
index edbddcbd5bc6..cc0fd862cf26 100644
--- a/arch/alpha/kernel/setup.c
+++ b/arch/alpha/kernel/setup.c
@@ -1257,7 +1257,7 @@ show_cpuinfo(struct seq_file *f, void *slot)
#ifdef CONFIG_SMP
seq_printf(f, "cpus active\t\t: %u\n"
"cpu active mask\t\t: %016lx\n",
- num_online_cpus(), cpus_addr(cpu_possible_map)[0]);
+ num_online_cpus(), cpumask_bits(cpu_possible_mask)[0]);
#endif
show_cache_size (f, "L1 Icache", alpha_l1i_cacheshape);
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index 42aa078a5e4d..d739703608fc 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -451,7 +451,7 @@ setup_smp(void)
}
printk(KERN_INFO "SMP: %d CPUs probed -- cpu_present_map = %lx\n",
- smp_num_probed, cpu_present_map.bits[0]);
+ smp_num_probed, cpumask_bits(cpu_present_mask)[0]);
}
/*
@@ -585,8 +585,7 @@ handle_ipi(struct pt_regs *regs)
switch (which) {
case IPI_RESCHEDULE:
- /* Reschedule callback. Everything to be done
- is done by the interrupt return path. */
+ scheduler_ipi();
break;
case IPI_CALL_FUNC:
@@ -630,8 +629,9 @@ smp_send_reschedule(int cpu)
void
smp_send_stop(void)
{
- cpumask_t to_whom = cpu_possible_map;
- cpu_clear(smp_processor_id(), to_whom);
+ cpumask_t to_whom;
+ cpumask_copy(&to_whom, cpu_possible_mask);
+ cpumask_clear_cpu(smp_processor_id(), &to_whom);
#ifdef DEBUG_IPI_MSG
if (hard_smp_processor_id() != boot_cpu_id)
printk(KERN_WARNING "smp_send_stop: Not on boot cpu.\n");
diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c
index 5ac00fd4cd0c..f8856829c22a 100644
--- a/arch/alpha/kernel/sys_dp264.c
+++ b/arch/alpha/kernel/sys_dp264.c
@@ -140,7 +140,7 @@ cpu_set_irq_affinity(unsigned int irq, cpumask_t affinity)
for (cpu = 0; cpu < 4; cpu++) {
unsigned long aff = cpu_irq_affinity[cpu];
- if (cpu_isset(cpu, affinity))
+ if (cpumask_test_cpu(cpu, &affinity))
aff |= 1UL << irq;
else
aff &= ~(1UL << irq);
diff --git a/arch/alpha/kernel/sys_titan.c b/arch/alpha/kernel/sys_titan.c
index fea0e4620994..6994407e242a 100644
--- a/arch/alpha/kernel/sys_titan.c
+++ b/arch/alpha/kernel/sys_titan.c
@@ -65,10 +65,11 @@ titan_update_irq_hw(unsigned long mask)
register int bcpu = boot_cpuid;
#ifdef CONFIG_SMP
- cpumask_t cpm = cpu_present_map;
+ cpumask_t cpm;
volatile unsigned long *dim0, *dim1, *dim2, *dim3;
unsigned long mask0, mask1, mask2, mask3, dummy;
+ cpumask_copy(&cpm, cpu_present_mask);
mask &= ~isa_enable;
mask0 = mask & titan_cpu_irq_affinity[0];
mask1 = mask & titan_cpu_irq_affinity[1];
@@ -84,10 +85,10 @@ titan_update_irq_hw(unsigned long mask)
dim1 = &cchip->dim1.csr;
dim2 = &cchip->dim2.csr;
dim3 = &cchip->dim3.csr;
- if (!cpu_isset(0, cpm)) dim0 = &dummy;
- if (!cpu_isset(1, cpm)) dim1 = &dummy;
- if (!cpu_isset(2, cpm)) dim2 = &dummy;
- if (!cpu_isset(3, cpm)) dim3 = &dummy;
+ if (!cpumask_test_cpu(0, &cpm)) dim0 = &dummy;
+ if (!cpumask_test_cpu(1, &cpm)) dim1 = &dummy;
+ if (!cpumask_test_cpu(2, &cpm)) dim2 = &dummy;
+ if (!cpumask_test_cpu(3, &cpm)) dim3 = &dummy;
*dim0 = mask0;
*dim1 = mask1;
@@ -137,7 +138,7 @@ titan_cpu_set_irq_affinity(unsigned int irq, cpumask_t affinity)
int cpu;
for (cpu = 0; cpu < 4; cpu++) {
- if (cpu_isset(cpu, affinity))
+ if (cpumask_test_cpu(cpu, &affinity))
titan_cpu_irq_affinity[cpu] |= 1UL << irq;
else
titan_cpu_irq_affinity[cpu] &= ~(1UL << irq);
diff --git a/arch/alpha/kernel/vmlinux.lds.S b/arch/alpha/kernel/vmlinux.lds.S
index 433be2a24f31..f937ad123852 100644
--- a/arch/alpha/kernel/vmlinux.lds.S
+++ b/arch/alpha/kernel/vmlinux.lds.S
@@ -39,13 +39,14 @@ SECTIONS
__init_begin = ALIGN(PAGE_SIZE);
INIT_TEXT_SECTION(PAGE_SIZE)
INIT_DATA_SECTION(16)
- PERCPU(L1_CACHE_BYTES, PAGE_SIZE)
+ PERCPU_SECTION(L1_CACHE_BYTES)
/* Align to THREAD_SIZE rather than PAGE_SIZE here so any padding page
needed for the THREAD_SIZE aligned init_task gets freed after init */
. = ALIGN(THREAD_SIZE);
__init_end = .;
/* Freed after init ends here */
+ _sdata = .; /* Start of rw data section */
_data = .;
RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE)
diff --git a/arch/alpha/mm/init.c b/arch/alpha/mm/init.c
index 86425ab53bf5..69d0c5761e2f 100644
--- a/arch/alpha/mm/init.c
+++ b/arch/alpha/mm/init.c
@@ -32,8 +32,6 @@
#include <asm/console.h>
#include <asm/tlb.h>
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
extern void die_if_kernel(char *,struct pt_regs *,long);
static struct pcb_struct original_pcb;
diff --git a/arch/alpha/mm/numa.c b/arch/alpha/mm/numa.c
index 7b2c56d8f930..3973ae395772 100644
--- a/arch/alpha/mm/numa.c
+++ b/arch/alpha/mm/numa.c
@@ -313,6 +313,7 @@ void __init paging_init(void)
zones_size[ZONE_DMA] = dma_local_pfn;
zones_size[ZONE_NORMAL] = (end_pfn - start_pfn) - dma_local_pfn;
}
+ node_set_state(nid, N_NORMAL_MEMORY);
free_area_init_node(nid, zones_size, start_pfn, NULL);
}
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 377a7a595b08..7275009686e6 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -197,15 +197,21 @@ config ARM_PATCH_PHYS_VIRT
depends on !XIP_KERNEL && MMU
depends on !ARCH_REALVIEW || !SPARSEMEM
help
- Patch phys-to-virt translation functions at runtime according to
- the position of the kernel in system memory.
+ Patch phys-to-virt and virt-to-phys translation functions at
+ boot and module load time according to the position of the
+ kernel in system memory.
- This can only be used with non-XIP with MMU kernels where
- the base of physical memory is at a 16MB boundary.
+ This can only be used with non-XIP MMU kernels where the base
+ of physical memory is at a 16MB boundary, or theoretically 64K
+ for the MSM machine class.
config ARM_PATCH_PHYS_VIRT_16BIT
def_bool y
depends on ARM_PATCH_PHYS_VIRT && ARCH_MSM
+ help
+ This option extends the physical to virtual translation patching
+ to allow physical memory down to a theoretical minimum of 64K
+ boundaries.
source "init/Kconfig"
@@ -297,6 +303,7 @@ config ARCH_BCMRING
depends on MMU
select CPU_V6
select ARM_AMBA
+ select ARM_TIMER_SP804
select CLKDEV_LOOKUP
select GENERIC_CLOCKEVENTS
select ARCH_WANT_OPTIONAL_GPIOLIB
@@ -366,6 +373,7 @@ config ARCH_MXC
select GENERIC_CLOCKEVENTS
select ARCH_REQUIRE_GPIOLIB
select CLKDEV_LOOKUP
+ select CLKSRC_MMIO
select HAVE_SCHED_CLOCK
help
Support for Freescale MXC/iMX-based family of processors
@@ -375,21 +383,13 @@ config ARCH_MXS
select GENERIC_CLOCKEVENTS
select ARCH_REQUIRE_GPIOLIB
select CLKDEV_LOOKUP
+ select CLKSRC_MMIO
help
Support for Freescale MXS-based family of processors
-config ARCH_STMP3XXX
- bool "Freescale STMP3xxx"
- select CPU_ARM926T
- select CLKDEV_LOOKUP
- select ARCH_REQUIRE_GPIOLIB
- select GENERIC_CLOCKEVENTS
- select USB_ARCH_HAS_EHCI
- help
- Support for systems based on the Freescale 3xxx CPUs.
-
config ARCH_NETX
bool "Hilscher NetX based"
+ select CLKSRC_MMIO
select CPU_ARM926T
select ARM_VIC
select GENERIC_CLOCKEVENTS
@@ -457,6 +457,7 @@ config ARCH_IXP2000
config ARCH_IXP4XX
bool "IXP4xx-based"
depends on MMU
+ select CLKSRC_MMIO
select CPU_XSCALE
select GENERIC_GPIO
select GENERIC_CLOCKEVENTS
@@ -468,7 +469,7 @@ config ARCH_IXP4XX
config ARCH_DOVE
bool "Marvell Dove"
- select CPU_V6K
+ select CPU_V7
select PCI
select ARCH_REQUIRE_GPIOLIB
select GENERIC_CLOCKEVENTS
@@ -497,6 +498,7 @@ config ARCH_LOKI
config ARCH_LPC32XX
bool "NXP LPC32XX"
+ select CLKSRC_MMIO
select CPU_ARM926T
select ARCH_REQUIRE_GPIOLIB
select HAVE_IDE
@@ -554,23 +556,12 @@ config ARCH_KS8695
Support for Micrel/Kendin KS8695 "Centaur" (ARM922T) based
System-on-Chip devices.
-config ARCH_NS9XXX
- bool "NetSilicon NS9xxx"
- select CPU_ARM926T
- select GENERIC_GPIO
- select GENERIC_CLOCKEVENTS
- select HAVE_CLK
- help
- Say Y here if you intend to run this kernel on a NetSilicon NS9xxx
- System.
-
- <http://www.digi.com/products/microprocessors/index.jsp>
-
config ARCH_W90X900
bool "Nuvoton W90X900 CPU"
select CPU_ARM926T
select ARCH_REQUIRE_GPIOLIB
select CLKDEV_LOOKUP
+ select CLKSRC_MMIO
select GENERIC_CLOCKEVENTS
help
Support for Nuvoton (Winbond logic dept.) ARM9 processor,
@@ -592,6 +583,7 @@ config ARCH_NUC93X
config ARCH_TEGRA
bool "NVIDIA Tegra"
select CLKDEV_LOOKUP
+ select CLKSRC_MMIO
select GENERIC_TIME
select GENERIC_CLOCKEVENTS
select GENERIC_GPIO
@@ -617,6 +609,7 @@ config ARCH_PXA
select ARCH_MTD_XIP
select ARCH_HAS_CPUFREQ
select CLKDEV_LOOKUP
+ select CLKSRC_MMIO
select ARCH_REQUIRE_GPIOLIB
select GENERIC_CLOCKEVENTS
select HAVE_SCHED_CLOCK
@@ -667,6 +660,7 @@ config ARCH_RPC
config ARCH_SA1100
bool "SA1100-based"
+ select CLKSRC_MMIO
select CPU_SA1100
select ISA
select ARCH_SPARSEMEM_ENABLE
@@ -803,6 +797,7 @@ config ARCH_SHARK
config ARCH_TCC_926
bool "Telechips TCC ARM926-based systems"
+ select CLKSRC_MMIO
select CPU_ARM926T
select HAVE_CLK
select CLKDEV_LOOKUP
@@ -813,6 +808,7 @@ config ARCH_TCC_926
config ARCH_U300
bool "ST-Ericsson U300 Series"
depends on MMU
+ select CLKSRC_MMIO
select CPU_ARM926T
select HAVE_SCHED_CLOCK
select HAVE_TCM
@@ -854,6 +850,7 @@ config ARCH_DAVINCI
select HAVE_IDE
select CLKDEV_LOOKUP
select GENERIC_ALLOCATOR
+ select GENERIC_IRQ_CHIP
select ARCH_HAS_HOLES_MEMORYMODEL
help
Support for TI's DaVinci platform.
@@ -874,6 +871,7 @@ config PLAT_SPEAR
select ARM_AMBA
select ARCH_REQUIRE_GPIOLIB
select CLKDEV_LOOKUP
+ select CLKSRC_MMIO
select GENERIC_CLOCKEVENTS
select HAVE_CLK
help
@@ -951,8 +949,6 @@ source "arch/arm/mach-netx/Kconfig"
source "arch/arm/mach-nomadik/Kconfig"
source "arch/arm/plat-nomadik/Kconfig"
-source "arch/arm/mach-ns9xxx/Kconfig"
-
source "arch/arm/mach-nuc93x/Kconfig"
source "arch/arm/plat-omap/Kconfig"
@@ -1005,8 +1001,6 @@ source "arch/arm/mach-exynos4/Kconfig"
source "arch/arm/mach-shmobile/Kconfig"
-source "arch/arm/plat-stmp3xxx/Kconfig"
-
source "arch/arm/mach-tegra/Kconfig"
source "arch/arm/mach-u300/Kconfig"
@@ -1033,6 +1027,8 @@ config PLAT_IOP
config PLAT_ORION
bool
+ select CLKSRC_MMIO
+ select GENERIC_IRQ_CHIP
select HAVE_SCHED_CLOCK
config PLAT_PXA
@@ -1043,6 +1039,7 @@ config PLAT_VERSATILE
config ARM_TIMER_SP804
bool
+ select CLKSRC_MMIO
source arch/arm/mm/Kconfig
@@ -1318,8 +1315,7 @@ menu "Kernel Features"
source "kernel/time/Kconfig"
config SMP
- bool "Symmetric Multi-Processing (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ bool "Symmetric Multi-Processing"
depends on CPU_V6K || CPU_V7
depends on GENERIC_CLOCKEVENTS
depends on REALVIEW_EB_ARM11MP || REALVIEW_EB_A9MP || \
@@ -1521,8 +1517,8 @@ config ARCH_SELECT_MEMORY_MODEL
def_bool ARCH_SPARSEMEM_ENABLE
config HIGHMEM
- bool "High Memory Support (EXPERIMENTAL)"
- depends on MMU && EXPERIMENTAL
+ bool "High Memory Support"
+ depends on MMU
help
The address space of ARM processors is only 4 Gigabytes large
and it has to accommodate user address space, kernel address
@@ -1742,16 +1738,31 @@ config CMDLINE
time by entering them here. As a minimum, you should specify the
memory size and the root device (e.g., mem=64M root=/dev/nfs).
+choice
+ prompt "Kernel command line type" if CMDLINE != ""
+ default CMDLINE_FROM_BOOTLOADER
+
+config CMDLINE_FROM_BOOTLOADER
+ bool "Use bootloader kernel arguments if available"
+ help
+ Uses the command-line options passed by the boot loader. If
+ the boot loader doesn't provide any, the default kernel command
+ string provided in CMDLINE will be used.
+
+config CMDLINE_EXTEND
+ bool "Extend bootloader kernel arguments"
+ help
+ The command-line arguments provided by the boot loader will be
+ appended to the default kernel command string.
+
config CMDLINE_FORCE
bool "Always use the default kernel command string"
- depends on CMDLINE != ""
help
Always use the default kernel command string, even if the boot
loader passes other arguments to the kernel.
This is useful if you cannot or don't want to change the
command-line options your boot loader passes to the kernel.
-
- If unsure, say N.
+endchoice
config XIP_KERNEL
bool "Kernel Execute-In-Place from ROM"
@@ -2010,7 +2021,7 @@ menu "Power management options"
source "kernel/power/Kconfig"
config ARCH_SUSPEND_POSSIBLE
- depends on !ARCH_S5P64X0 && !ARCH_S5P6442
+ depends on !ARCH_S5P64X0 && !ARCH_S5P6442 && !ARCH_S5PC100
depends on CPU_ARM920T || CPU_ARM926T || CPU_SA1100 || \
CPU_V6 || CPU_V6K || CPU_V7 || CPU_XSC3 || CPU_XSCALE
def_bool y
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 03d01d783e3b..81cbe40c159c 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -63,13 +63,6 @@ config DEBUG_USER
8 - SIGSEGV faults
16 - SIGBUS faults
-config DEBUG_STACK_USAGE
- bool "Enable stack utilization instrumentation"
- depends on DEBUG_KERNEL
- help
- Enables the display of the minimum amount of free stack which each
- task has ever had available in the sysrq-T output.
-
# These options are only for real kernel hackers who want to get their hands dirty.
config DEBUG_LL
bool "Kernel low-level debugging functions"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index c7d321a3d95d..25750bcb3397 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -158,13 +158,11 @@ machine-$(CONFIG_ARCH_MV78XX0) := mv78xx0
machine-$(CONFIG_ARCH_MX1) := imx
machine-$(CONFIG_ARCH_MX2) := imx
machine-$(CONFIG_ARCH_MX25) := imx
-machine-$(CONFIG_ARCH_MX3) := mx3
+machine-$(CONFIG_ARCH_MX3) := imx
machine-$(CONFIG_ARCH_MX5) := mx5
-machine-$(CONFIG_ARCH_MXC91231) := mxc91231
machine-$(CONFIG_ARCH_MXS) := mxs
machine-$(CONFIG_ARCH_NETX) := netx
machine-$(CONFIG_ARCH_NOMADIK) := nomadik
-machine-$(CONFIG_ARCH_NS9XXX) := ns9xxx
machine-$(CONFIG_ARCH_OMAP1) := omap1
machine-$(CONFIG_ARCH_OMAP2) := omap2
machine-$(CONFIG_ARCH_OMAP3) := omap2
@@ -185,8 +183,6 @@ machine-$(CONFIG_ARCH_EXYNOS4) := exynos4
machine-$(CONFIG_ARCH_SA1100) := sa1100
machine-$(CONFIG_ARCH_SHARK) := shark
machine-$(CONFIG_ARCH_SHMOBILE) := shmobile
-machine-$(CONFIG_ARCH_STMP378X) := stmp378x
-machine-$(CONFIG_ARCH_STMP37XX) := stmp37xx
machine-$(CONFIG_ARCH_TCC8K) := tcc8k
machine-$(CONFIG_ARCH_TEGRA) := tegra
machine-$(CONFIG_ARCH_U300) := u300
@@ -207,7 +203,6 @@ machine-$(CONFIG_MACH_SPEAR600) := spear6xx
plat-$(CONFIG_ARCH_MXC) := mxc
plat-$(CONFIG_ARCH_OMAP) := omap
plat-$(CONFIG_ARCH_S3C64XX) := samsung
-plat-$(CONFIG_ARCH_STMP3XXX) := stmp3xxx
plat-$(CONFIG_ARCH_TCC_926) := tcc
plat-$(CONFIG_PLAT_IOP) := iop
plat-$(CONFIG_PLAT_NOMADIK) := nomadik
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index 0c6852d93506..23aad0722303 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -98,8 +98,6 @@ endif
ccflags-y := -fpic -fno-builtin
asflags-y := -Wa,-march=all
-# Provide size of uncompressed kernel to the decompressor via a linker symbol.
-LDFLAGS_vmlinux = --defsym _image_size=$(shell stat -c "%s" $(obj)/../Image)
# Supply ZRELADDR to the decompressor via a linker symbol.
ifneq ($(CONFIG_AUTO_ZRELADDR),y)
LDFLAGS_vmlinux += --defsym zreladdr=$(ZRELADDR)
@@ -122,10 +120,23 @@ lib1funcs = $(obj)/lib1funcs.o
$(obj)/lib1funcs.S: $(srctree)/arch/$(SRCARCH)/lib/lib1funcs.S FORCE
$(call cmd,shipped)
+# We need to prevent any GOTOFF relocs being used with references
+# to symbols in the .bss section since we cannot relocate them
+# independently from the rest at run time. This can be achieved by
+# ensuring that no private .bss symbols exist, as global symbols
+# always have a GOT entry which is what we need.
+# The .data section is already discarded by the linker script so no need
+# to bother about it here.
+check_for_bad_syms = \
+bad_syms=$$($(CROSS_COMPILE)nm $@ | sed -n 's/^.\{8\} [bc] \(.*\)/\1/p') && \
+[ -z "$$bad_syms" ] || \
+ ( echo "following symbols must have non local/private scope:" >&2; \
+ echo "$$bad_syms" >&2; rm -f $@; false )
+
$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \
$(addprefix $(obj)/, $(OBJS)) $(lib1funcs) FORCE
$(call if_changed,ld)
- @:
+ @$(check_for_bad_syms)
$(obj)/piggy.$(suffix_y): $(obj)/../Image FORCE
$(call if_changed,$(suffix_y))
diff --git a/arch/arm/boot/compressed/decompress.c b/arch/arm/boot/compressed/decompress.c
index 4c72a97bc3e1..07be5a2f8302 100644
--- a/arch/arm/boot/compressed/decompress.c
+++ b/arch/arm/boot/compressed/decompress.c
@@ -44,7 +44,7 @@ extern void error(char *);
#include "../../../../lib/decompress_unlzma.c"
#endif
-void do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x))
+int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x))
{
- decompress(input, len, NULL, NULL, output, NULL, error);
+ return decompress(input, len, NULL, NULL, output, NULL, error);
}
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index 49f5b2eaaa87..f9da41921c52 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -179,7 +179,7 @@ not_angel:
bl cache_on
restart: adr r0, LC0
- ldmia r0, {r1, r2, r3, r6, r9, r11, r12}
+ ldmia r0, {r1, r2, r3, r6, r10, r11, r12}
ldr sp, [r0, #28]
/*
@@ -188,6 +188,20 @@ restart: adr r0, LC0
*/
sub r0, r0, r1 @ calculate the delta offset
add r6, r6, r0 @ _edata
+ add r10, r10, r0 @ inflated kernel size location
+
+ /*
+ * The kernel build system appends the size of the
+ * decompressed kernel at the end of the compressed data
+ * in little-endian form.
+ */
+ ldrb r9, [r10, #0]
+ ldrb lr, [r10, #1]
+ orr r9, r9, lr, lsl #8
+ ldrb lr, [r10, #2]
+ ldrb r10, [r10, #3]
+ orr r9, r9, lr, lsl #16
+ orr r9, r9, r10, lsl #24
#ifndef CONFIG_ZBOOT_ROM
/* malloc space is above the relocated stack (64k max) */
@@ -347,10 +361,10 @@ LC0: .word LC0 @ r1
.word __bss_start @ r2
.word _end @ r3
.word _edata @ r6
- .word _image_size @ r9
+ .word input_data_end - 4 @ r10 (inflated size location)
.word _got_start @ r11
.word _got_end @ ip
- .word user_stack_end @ sp
+ .word .L_user_stack_end @ sp
.size LC0, . - LC0
#ifdef CONFIG_ARCH_RPC
@@ -459,7 +473,11 @@ __setup_mmu: sub r3, r4, #16384 @ Page directory size
orr r1, r1, #3 << 10
add r2, r3, #16384
1: cmp r1, r9 @ if virt > start of RAM
+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
+ orrhs r1, r1, #0x08 @ set cacheable
+#else
orrhs r1, r1, #0x0c @ set cacheable, bufferable
+#endif
cmp r1, r10 @ if virt > end of RAM
bichs r1, r1, #0x0c @ clear cacheable, bufferable
str r1, [r0], #4 @ 1:1 mapping
@@ -484,6 +502,12 @@ __setup_mmu: sub r3, r4, #16384 @ Page directory size
mov pc, lr
ENDPROC(__setup_mmu)
+__arm926ejs_mmu_cache_on:
+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
+ mov r0, #4 @ put dcache in WT mode
+ mcr p15, 7, r0, c15, c0, 0
+#endif
+
__armv4_mmu_cache_on:
mov r12, lr
#ifdef CONFIG_MMU
@@ -665,6 +689,12 @@ proc_types:
W(b) __armv4_mpu_cache_off
W(b) __armv4_mpu_cache_flush
+ .word 0x41069260 @ ARM926EJ-S (v5TEJ)
+ .word 0xff0ffff0
+ b __arm926ejs_mmu_cache_on
+ b __armv4_mmu_cache_off
+ b __armv5tej_mmu_cache_flush
+
.word 0x00007000 @ ARM7 IDs
.word 0x0000f000
mov pc, lr
@@ -747,12 +777,6 @@ proc_types:
W(b) __armv4_mmu_cache_off
W(b) __armv6_mmu_cache_flush
- .word 0x560f5810 @ Marvell PJ4 ARMv6
- .word 0xff0ffff0
- W(b) __armv4_mmu_cache_on
- W(b) __armv4_mmu_cache_off
- W(b) __armv6_mmu_cache_flush
-
.word 0x000f0000 @ new CPU Id
.word 0x000f0000
W(b) __armv7_mmu_cache_on
@@ -1078,5 +1102,5 @@ reloc_code_end:
.align
.section ".stack", "aw", %nobits
-user_stack: .space 4096
-user_stack_end:
+.L_user_stack: .space 4096
+.L_user_stack_end:
diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c
index 2df38263124c..832d37236c59 100644
--- a/arch/arm/boot/compressed/misc.c
+++ b/arch/arm/boot/compressed/misc.c
@@ -26,8 +26,6 @@ unsigned int __machine_arch_type;
#include <linux/linkage.h>
#include <asm/string.h>
-#include <asm/unaligned.h>
-
static void putstr(const char *ptr);
extern void error(char *x);
@@ -139,13 +137,12 @@ void *memcpy(void *__dest, __const void *__src, size_t __n)
}
/*
- * gzip delarations
+ * gzip declarations
*/
extern char input_data[];
extern char input_data_end[];
unsigned char *output_data;
-unsigned long output_ptr;
unsigned long free_mem_ptr;
unsigned long free_mem_end_ptr;
@@ -170,15 +167,15 @@ asmlinkage void __div0(void)
error("Attempting division by 0!");
}
-extern void do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x));
+extern int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x));
-unsigned long
+void
decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p,
unsigned long free_mem_ptr_end_p,
int arch_id)
{
- unsigned char *tmp;
+ int ret;
output_data = (unsigned char *)output_start;
free_mem_ptr = free_mem_ptr_p;
@@ -187,12 +184,11 @@ decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p,
arch_decomp_setup();
- tmp = (unsigned char *) (((unsigned long)input_data_end) - 4);
- output_ptr = get_unaligned_le32(tmp);
-
putstr("Uncompressing Linux...");
- do_decompress(input_data, input_data_end - input_data,
- output_data, error);
- putstr(" done, booting the kernel.\n");
- return output_ptr;
+ ret = do_decompress(input_data, input_data_end - input_data,
+ output_data, error);
+ if (ret)
+ error("decompressor returned an error");
+ else
+ putstr(" done, booting the kernel.\n");
}
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index f70ec7dadebb..4ddd0a6ac7ff 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -49,7 +49,7 @@ struct gic_chip_data {
* Default make them NULL.
*/
struct irq_chip gic_arch_extn = {
- .irq_ack = NULL,
+ .irq_eoi = NULL,
.irq_mask = NULL,
.irq_unmask = NULL,
.irq_retrigger = NULL,
@@ -84,21 +84,12 @@ static inline unsigned int gic_irq(struct irq_data *d)
/*
* Routines to acknowledge, disable and enable interrupts
*/
-static void gic_ack_irq(struct irq_data *d)
-{
- spin_lock(&irq_controller_lock);
- if (gic_arch_extn.irq_ack)
- gic_arch_extn.irq_ack(d);
- writel(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
- spin_unlock(&irq_controller_lock);
-}
-
static void gic_mask_irq(struct irq_data *d)
{
u32 mask = 1 << (d->irq % 32);
spin_lock(&irq_controller_lock);
- writel(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4);
+ writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4);
if (gic_arch_extn.irq_mask)
gic_arch_extn.irq_mask(d);
spin_unlock(&irq_controller_lock);
@@ -111,10 +102,21 @@ static void gic_unmask_irq(struct irq_data *d)
spin_lock(&irq_controller_lock);
if (gic_arch_extn.irq_unmask)
gic_arch_extn.irq_unmask(d);
- writel(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
+ writel_relaxed(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
spin_unlock(&irq_controller_lock);
}
+static void gic_eoi_irq(struct irq_data *d)
+{
+ if (gic_arch_extn.irq_eoi) {
+ spin_lock(&irq_controller_lock);
+ gic_arch_extn.irq_eoi(d);
+ spin_unlock(&irq_controller_lock);
+ }
+
+ writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
+}
+
static int gic_set_type(struct irq_data *d, unsigned int type)
{
void __iomem *base = gic_dist_base(d);
@@ -138,7 +140,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
if (gic_arch_extn.irq_set_type)
gic_arch_extn.irq_set_type(d, type);
- val = readl(base + GIC_DIST_CONFIG + confoff);
+ val = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
if (type == IRQ_TYPE_LEVEL_HIGH)
val &= ~confmask;
else if (type == IRQ_TYPE_EDGE_RISING)
@@ -148,15 +150,15 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
* As recommended by the spec, disable the interrupt before changing
* the configuration
*/
- if (readl(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) {
- writel(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff);
+ if (readl_relaxed(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) {
+ writel_relaxed(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff);
enabled = true;
}
- writel(val, base + GIC_DIST_CONFIG + confoff);
+ writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
if (enabled)
- writel(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);
+ writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);
spin_unlock(&irq_controller_lock);
@@ -188,8 +190,8 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
spin_lock(&irq_controller_lock);
d->node = cpu;
- val = readl(reg) & ~mask;
- writel(val | bit, reg);
+ val = readl_relaxed(reg) & ~mask;
+ writel_relaxed(val | bit, reg);
spin_unlock(&irq_controller_lock);
return 0;
@@ -218,11 +220,10 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
unsigned int cascade_irq, gic_irq;
unsigned long status;
- /* primary controller ack'ing */
- chip->irq_ack(&desc->irq_data);
+ chained_irq_enter(chip, desc);
spin_lock(&irq_controller_lock);
- status = readl(chip_data->cpu_base + GIC_CPU_INTACK);
+ status = readl_relaxed(chip_data->cpu_base + GIC_CPU_INTACK);
spin_unlock(&irq_controller_lock);
gic_irq = (status & 0x3ff);
@@ -236,15 +237,14 @@ static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
generic_handle_irq(cascade_irq);
out:
- /* primary controller unmasking */
- chip->irq_unmask(&desc->irq_data);
+ chained_irq_exit(chip, desc);
}
static struct irq_chip gic_chip = {
.name = "GIC",
- .irq_ack = gic_ack_irq,
.irq_mask = gic_mask_irq,
.irq_unmask = gic_unmask_irq,
+ .irq_eoi = gic_eoi_irq,
.irq_set_type = gic_set_type,
.irq_retrigger = gic_retrigger,
#ifdef CONFIG_SMP
@@ -272,13 +272,13 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
cpumask |= cpumask << 8;
cpumask |= cpumask << 16;
- writel(0, base + GIC_DIST_CTRL);
+ writel_relaxed(0, base + GIC_DIST_CTRL);
/*
* Find out how many interrupts are supported.
* The GIC only supports up to 1020 interrupt sources.
*/
- gic_irqs = readl(base + GIC_DIST_CTR) & 0x1f;
+ gic_irqs = readl_relaxed(base + GIC_DIST_CTR) & 0x1f;
gic_irqs = (gic_irqs + 1) * 32;
if (gic_irqs > 1020)
gic_irqs = 1020;
@@ -287,26 +287,26 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
* Set all global interrupts to be level triggered, active low.
*/
for (i = 32; i < gic_irqs; i += 16)
- writel(0, base + GIC_DIST_CONFIG + i * 4 / 16);
+ writel_relaxed(0, base + GIC_DIST_CONFIG + i * 4 / 16);
/*
* Set all global interrupts to this CPU only.
*/
for (i = 32; i < gic_irqs; i += 4)
- writel(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
+ writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
/*
* Set priority on all global interrupts.
*/
for (i = 32; i < gic_irqs; i += 4)
- writel(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
+ writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
/*
* Disable all interrupts. Leave the PPI and SGIs alone
* as these enables are banked registers.
*/
for (i = 32; i < gic_irqs; i += 32)
- writel(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
+ writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
/*
* Limit number of interrupts registered to the platform maximum
@@ -319,12 +319,12 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
* Setup the Linux IRQ subsystem.
*/
for (i = irq_start; i < irq_limit; i++) {
- irq_set_chip_and_handler(i, &gic_chip, handle_level_irq);
+ irq_set_chip_and_handler(i, &gic_chip, handle_fasteoi_irq);
irq_set_chip_data(i, gic);
set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
}
- writel(1, base + GIC_DIST_CTRL);
+ writel_relaxed(1, base + GIC_DIST_CTRL);
}
static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
@@ -337,17 +337,17 @@ static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
* Deal with the banked PPI and SGI interrupts - disable all
* PPI interrupts, ensure all SGI interrupts are enabled.
*/
- writel(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR);
- writel(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET);
+ writel_relaxed(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR);
+ writel_relaxed(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET);
/*
* Set priority on PPI and SGI interrupts
*/
for (i = 0; i < 32; i += 4)
- writel(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
+ writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
- writel(0xf0, base + GIC_CPU_PRIMASK);
- writel(1, base + GIC_CPU_CTRL);
+ writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
+ writel_relaxed(1, base + GIC_CPU_CTRL);
}
void __init gic_init(unsigned int gic_nr, unsigned int irq_start,
@@ -391,7 +391,13 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
{
unsigned long map = *cpus_addr(*mask);
+ /*
+ * Ensure that stores to Normal memory are visible to the
+ * other CPUs before issuing the IPI.
+ */
+ dsb();
+
/* this always happens on GIC0 */
- writel(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT);
+ writel_relaxed(map << 16 | irq, gic_data[0].dist_base + GIC_DIST_SOFTINT);
}
#endif
diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index a12b33c0dc42..9c49a46a2b7a 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -185,14 +185,6 @@ static struct sa1111_dev_info sa1111_devices[] = {
},
};
-void __init sa1111_adjust_zones(unsigned long *size, unsigned long *holes)
-{
- unsigned int sz = SZ_1M >> PAGE_SHIFT;
-
- size[1] = size[0] - sz;
- size[0] = sz;
-}
-
/*
* SA1111 interrupt support. Since clearing an IRQ while there are
* active IRQs causes the interrupt output to pulse, the upper levels
diff --git a/arch/arm/common/timer-sp.c b/arch/arm/common/timer-sp.c
index 6ef3342153b9..41df47875122 100644
--- a/arch/arm/common/timer-sp.c
+++ b/arch/arm/common/timer-sp.c
@@ -18,53 +18,67 @@
* 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/clk.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
+#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <asm/hardware/arm_timer.h>
-/*
- * These timers are currently always setup to be clocked at 1MHz.
- */
-#define TIMER_FREQ_KHZ (1000)
-#define TIMER_RELOAD (TIMER_FREQ_KHZ * 1000 / HZ)
+static long __init sp804_get_clock_rate(const char *name)
+{
+ struct clk *clk;
+ long rate;
+ int err;
+
+ clk = clk_get_sys("sp804", name);
+ if (IS_ERR(clk)) {
+ pr_err("sp804: %s clock not found: %d\n", name,
+ (int)PTR_ERR(clk));
+ return PTR_ERR(clk);
+ }
-static void __iomem *clksrc_base;
+ err = clk_enable(clk);
+ if (err) {
+ pr_err("sp804: %s clock failed to enable: %d\n", name, err);
+ clk_put(clk);
+ return err;
+ }
-static cycle_t sp804_read(struct clocksource *cs)
-{
- return ~readl(clksrc_base + TIMER_VALUE);
-}
+ rate = clk_get_rate(clk);
+ if (rate < 0) {
+ pr_err("sp804: %s clock failed to get rate: %ld\n", name, rate);
+ clk_disable(clk);
+ clk_put(clk);
+ }
-static struct clocksource clocksource_sp804 = {
- .name = "timer3",
- .rating = 200,
- .read = sp804_read,
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
+ return rate;
+}
-void __init sp804_clocksource_init(void __iomem *base)
+void __init sp804_clocksource_init(void __iomem *base, const char *name)
{
- struct clocksource *cs = &clocksource_sp804;
+ long rate = sp804_get_clock_rate(name);
- clksrc_base = base;
+ if (rate < 0)
+ return;
/* setup timer 0 as free-running clocksource */
- writel(0, clksrc_base + TIMER_CTRL);
- writel(0xffffffff, clksrc_base + TIMER_LOAD);
- writel(0xffffffff, clksrc_base + TIMER_VALUE);
+ writel(0, base + TIMER_CTRL);
+ writel(0xffffffff, base + TIMER_LOAD);
+ writel(0xffffffff, base + TIMER_VALUE);
writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC,
- clksrc_base + TIMER_CTRL);
+ base + TIMER_CTRL);
- clocksource_register_khz(cs, TIMER_FREQ_KHZ);
+ clocksource_mmio_init(base + TIMER_VALUE, name,
+ rate, 200, 32, clocksource_mmio_readl_down);
}
static void __iomem *clkevt_base;
+static unsigned long clkevt_reload;
/*
* IRQ handler for the timer
@@ -90,7 +104,7 @@ static void sp804_set_mode(enum clock_event_mode mode,
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
- writel(TIMER_RELOAD, clkevt_base + TIMER_LOAD);
+ writel(clkevt_reload, clkevt_base + TIMER_LOAD);
ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
break;
@@ -120,7 +134,6 @@ static int sp804_set_next_event(unsigned long next,
}
static struct clock_event_device sp804_clockevent = {
- .name = "timer0",
.shift = 32,
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.set_mode = sp804_set_mode,
@@ -136,17 +149,24 @@ static struct irqaction sp804_timer_irq = {
.dev_id = &sp804_clockevent,
};
-void __init sp804_clockevents_init(void __iomem *base, unsigned int timer_irq)
+void __init sp804_clockevents_init(void __iomem *base, unsigned int irq,
+ const char *name)
{
struct clock_event_device *evt = &sp804_clockevent;
+ long rate = sp804_get_clock_rate(name);
+
+ if (rate < 0)
+ return;
clkevt_base = base;
+ clkevt_reload = DIV_ROUND_CLOSEST(rate, HZ);
- evt->irq = timer_irq;
- evt->mult = div_sc(TIMER_FREQ_KHZ, NSEC_PER_MSEC, evt->shift);
+ evt->name = name;
+ evt->irq = irq;
+ evt->mult = div_sc(rate, NSEC_PER_SEC, evt->shift);
evt->max_delta_ns = clockevent_delta2ns(0xffffffff, evt);
evt->min_delta_ns = clockevent_delta2ns(0xf, evt);
- setup_irq(timer_irq, &sp804_timer_irq);
+ setup_irq(irq, &sp804_timer_irq);
clockevents_register_device(evt);
}
diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
index 113085a77123..7aa4262ada7a 100644
--- a/arch/arm/common/vic.c
+++ b/arch/arm/common/vic.c
@@ -22,17 +22,16 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/io.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/device.h>
#include <linux/amba/bus.h>
#include <asm/mach/irq.h>
#include <asm/hardware/vic.h>
-#if defined(CONFIG_PM)
+#ifdef CONFIG_PM
/**
* struct vic_device - VIC PM device
- * @sysdev: The system device which is registered.
* @irq: The IRQ number for the base of the VIC.
* @base: The register base for the VIC.
* @resume_sources: A bitmask of interrupts for resume.
@@ -43,8 +42,6 @@
* @protect: Save for VIC_PROTECT.
*/
struct vic_device {
- struct sys_device sysdev;
-
void __iomem *base;
int irq;
u32 resume_sources;
@@ -59,11 +56,6 @@ struct vic_device {
static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
static int vic_id;
-
-static inline struct vic_device *to_vic(struct sys_device *sys)
-{
- return container_of(sys, struct vic_device, sysdev);
-}
#endif /* CONFIG_PM */
/**
@@ -85,10 +77,9 @@ static void vic_init2(void __iomem *base)
writel(32, base + VIC_PL190_DEF_VECT_ADDR);
}
-#if defined(CONFIG_PM)
-static int vic_class_resume(struct sys_device *dev)
+#ifdef CONFIG_PM
+static void resume_one_vic(struct vic_device *vic)
{
- struct vic_device *vic = to_vic(dev);
void __iomem *base = vic->base;
printk(KERN_DEBUG "%s: resuming vic at %p\n", __func__, base);
@@ -107,13 +98,18 @@ static int vic_class_resume(struct sys_device *dev)
writel(vic->soft_int, base + VIC_INT_SOFT);
writel(~vic->soft_int, base + VIC_INT_SOFT_CLEAR);
+}
- return 0;
+static void vic_resume(void)
+{
+ int id;
+
+ for (id = vic_id - 1; id >= 0; id--)
+ resume_one_vic(vic_devices + id);
}
-static int vic_class_suspend(struct sys_device *dev, pm_message_t state)
+static void suspend_one_vic(struct vic_device *vic)
{
- struct vic_device *vic = to_vic(dev);
void __iomem *base = vic->base;
printk(KERN_DEBUG "%s: suspending vic at %p\n", __func__, base);
@@ -128,14 +124,21 @@ static int vic_class_suspend(struct sys_device *dev, pm_message_t state)
writel(vic->resume_irqs, base + VIC_INT_ENABLE);
writel(~vic->resume_irqs, base + VIC_INT_ENABLE_CLEAR);
+}
+
+static int vic_suspend(void)
+{
+ int id;
+
+ for (id = 0; id < vic_id; id++)
+ suspend_one_vic(vic_devices + id);
return 0;
}
-struct sysdev_class vic_class = {
- .name = "vic",
- .suspend = vic_class_suspend,
- .resume = vic_class_resume,
+struct syscore_ops vic_syscore_ops = {
+ .suspend = vic_suspend,
+ .resume = vic_resume,
};
/**
@@ -147,30 +150,8 @@ struct sysdev_class vic_class = {
*/
static int __init vic_pm_init(void)
{
- struct vic_device *dev = vic_devices;
- int err;
- int id;
-
- if (vic_id == 0)
- return 0;
-
- err = sysdev_class_register(&vic_class);
- if (err) {
- printk(KERN_ERR "%s: cannot register class\n", __func__);
- return err;
- }
-
- for (id = 0; id < vic_id; id++, dev++) {
- dev->sysdev.id = id;
- dev->sysdev.cls = &vic_class;
-
- err = sysdev_register(&dev->sysdev);
- if (err) {
- printk(KERN_ERR "%s: failed to register device\n",
- __func__);
- return err;
- }
- }
+ if (vic_id > 0)
+ register_syscore_ops(&vic_syscore_ops);
return 0;
}
diff --git a/arch/arm/configs/dove_defconfig b/arch/arm/configs/dove_defconfig
index 54bf5eec8016..40db34cf2771 100644
--- a/arch/arm/configs/dove_defconfig
+++ b/arch/arm/configs/dove_defconfig
@@ -8,8 +8,6 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
CONFIG_ARCH_DOVE=y
CONFIG_MACH_DOVE_DB=y
-CONFIG_CPU_V6=y
-CONFIG_CPU_32v6K=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_AEABI=y
@@ -44,7 +42,6 @@ CONFIG_MTD_UBI=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=1
-# CONFIG_MISC_DEVICES is not set
# CONFIG_SCSI_PROC_FS is not set
CONFIG_BLK_DEV_SD=y
# CONFIG_SCSI_LOWLEVEL is not set
@@ -59,12 +56,12 @@ CONFIG_INPUT_EVDEV=y
# CONFIG_KEYBOARD_ATKBD is not set
# CONFIG_MOUSE_PS2 is not set
# CONFIG_SERIO is not set
+CONFIG_LEGACY_PTY_COUNT=16
# CONFIG_DEVKMEM is not set
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_SERIAL_8250_PCI is not set
CONFIG_SERIAL_8250_RUNTIME_UARTS=2
-CONFIG_LEGACY_PTY_COUNT=16
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
@@ -72,12 +69,10 @@ CONFIG_I2C_MV64XXX=y
CONFIG_SPI=y
CONFIG_SPI_ORION=y
# CONFIG_HWMON is not set
-# CONFIG_VGA_CONSOLE is not set
CONFIG_USB=y
CONFIG_USB_DEVICEFS=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
-CONFIG_USB_EHCI_TT_NEWSCHED=y
CONFIG_USB_STORAGE=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_MV=y
@@ -86,7 +81,6 @@ CONFIG_MV_XOR=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
# CONFIG_EXT3_FS_XATTR is not set
-CONFIG_INOTIFY=y
CONFIG_ISO9660_FS=y
CONFIG_JOLIET=y
CONFIG_UDF_FS=m
@@ -110,23 +104,19 @@ CONFIG_DEBUG_KERNEL=y
CONFIG_TIMER_STATS=y
# CONFIG_DEBUG_BUGVERBOSE is not set
CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_SYSCTL_SYSCALL_CHECK=y
CONFIG_DEBUG_USER=y
CONFIG_DEBUG_ERRORS=y
CONFIG_CRYPTO_NULL=y
-CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_MD4=y
-CONFIG_CRYPTO_MD5=y
CONFIG_CRYPTO_SHA1=y
CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_SHA512=y
CONFIG_CRYPTO_AES=y
CONFIG_CRYPTO_BLOWFISH=y
-CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_TEA=y
CONFIG_CRYPTO_TWOFISH=y
CONFIG_CRYPTO_DEFLATE=y
diff --git a/arch/arm/configs/mx1_defconfig b/arch/arm/configs/mx1_defconfig
index b39b5ced8a10..c9436d0bf593 100644
--- a/arch/arm/configs/mx1_defconfig
+++ b/arch/arm/configs/mx1_defconfig
@@ -15,6 +15,7 @@ CONFIG_ARCH_MXC=y
CONFIG_ARCH_MX1=y
CONFIG_ARCH_MX1ADS=y
CONFIG_MACH_SCB9328=y
+CONFIG_MACH_APF9328=y
CONFIG_MXC_IRQ_PRIOR=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
diff --git a/arch/arm/configs/mx51_defconfig b/arch/arm/configs/mx51_defconfig
index e3c903281f70..0ace16cba9b5 100644
--- a/arch/arm/configs/mx51_defconfig
+++ b/arch/arm/configs/mx51_defconfig
@@ -13,7 +13,7 @@ CONFIG_MODULE_SRCVERSION_ALL=y
# CONFIG_LBDAF is not set
# CONFIG_BLK_DEV_BSG is not set
CONFIG_ARCH_MXC=y
-CONFIG_ARCH_MX5=y
+CONFIG_ARCH_MX51=y
CONFIG_MACH_MX51_BABBAGE=y
CONFIG_MACH_MX51_3DS=y
CONFIG_MACH_EUKREA_CPUIMX51=y
diff --git a/arch/arm/configs/mxs_defconfig b/arch/arm/configs/mxs_defconfig
new file mode 100644
index 000000000000..2bf224310fb4
--- /dev/null
+++ b/arch/arm/configs/mxs_defconfig
@@ -0,0 +1,129 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_SYSVIPC=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=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_NET_NS is not set
+CONFIG_PERF_EVENTS=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_BLK_DEV_INTEGRITY=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_ARCH_MXS=y
+CONFIG_MACH_STMP378X_DEVB=y
+CONFIG_MACH_TX28=y
+# CONFIG_ARM_THUMB is not set
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT_VOLUNTARY=y
+CONFIG_AEABI=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
+CONFIG_AUTO_ZRELADDR=y
+CONFIG_FPE_NWFPE=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_SYN_COOKIES=y
+# 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 is not set
+# CONFIG_IPV6 is not set
+CONFIG_CAN=m
+CONFIG_CAN_RAW=m
+CONFIG_CAN_BCM=m
+CONFIG_CAN_DEV=m
+CONFIG_CAN_FLEXCAN=m
+# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+# CONFIG_BLK_DEV is not set
+CONFIG_NETDEVICES=y
+CONFIG_NET_ETHERNET=y
+CONFIG_ENC28J60=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_EVDEV=m
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_TSC2007=m
+# CONFIG_SERIO is not set
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=m
+# CONFIG_I2C_COMPAT is not set
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_MXS=m
+CONFIG_SPI=y
+CONFIG_SPI_GPIO=m
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+# CONFIG_HWMON is not set
+# CONFIG_MFD_SUPPORT is not set
+CONFIG_DISPLAY_SUPPORT=m
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_MMC=y
+CONFIG_MMC_MXS=y
+CONFIG_RTC_CLASS=m
+CONFIG_RTC_DRV_DS1307=m
+CONFIG_DMADEVICES=y
+CONFIG_MXS_DMA=y
+CONFIG_EXT3_FS=y
+# CONFIG_DNOTIFY is not set
+CONFIG_FSCACHE=m
+CONFIG_FSCACHE_STATS=y
+CONFIG_CACHEFILES=m
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_PRINTK_TIME=y
+CONFIG_FRAME_WARN=2048
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_TIMER_STATS=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+CONFIG_DEBUG_INFO=y
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_STRICT_DEVMEM=y
+CONFIG_DEBUG_USER=y
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC7=m
diff --git a/arch/arm/configs/ns9xxx_defconfig b/arch/arm/configs/ns9xxx_defconfig
deleted file mode 100644
index 1f528a002983..000000000000
--- a/arch/arm/configs/ns9xxx_defconfig
+++ /dev/null
@@ -1,56 +0,0 @@
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_NS9XXX=y
-CONFIG_MACH_CC9P9360DEV=y
-CONFIG_MACH_CC9P9360JS=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_FPE_NWFPE=y
-CONFIG_NET=y
-CONFIG_PACKET=m
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_SYN_COOKIES=y
-CONFIG_MTD=m
-CONFIG_MTD_CONCAT=m
-CONFIG_MTD_CHAR=m
-CONFIG_MTD_BLOCK=m
-CONFIG_MTD_CFI=m
-CONFIG_MTD_JEDECPROBE=m
-CONFIG_MTD_CFI_AMDSTD=m
-CONFIG_MTD_PHYSMAP=m
-CONFIG_BLK_DEV_LOOP=m
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-# CONFIG_SERIO_SERPORT is not set
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=m
-CONFIG_I2C_GPIO=m
-# CONFIG_HWMON is not set
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=m
-CONFIG_LEDS_GPIO=m
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_LEDS_TRIGGER_TIMER=m
-CONFIG_LEDS_TRIGGER_HEARTBEAT=m
-CONFIG_RTC_CLASS=m
-CONFIG_EXT2_FS=m
-CONFIG_TMPFS=y
-CONFIG_JFFS2_FS=m
-CONFIG_NFS_FS=y
-CONFIG_ROOT_NFS=y
-# CONFIG_ENABLE_MUST_CHECK is not set
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig
index 076db52ff672..d5f00d7eb075 100644
--- a/arch/arm/configs/omap2plus_defconfig
+++ b/arch/arm/configs/omap2plus_defconfig
@@ -21,58 +21,22 @@ CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
# CONFIG_BLK_DEV_BSG is not set
CONFIG_ARCH_OMAP=y
-CONFIG_ARCH_OMAP2=y
-CONFIG_ARCH_OMAP3=y
-CONFIG_ARCH_OMAP4=y
CONFIG_OMAP_RESET_CLOCKS=y
CONFIG_OMAP_MUX_DEBUG=y
-CONFIG_OMAP_32K_TIMER=y
-CONFIG_MACH_OMAP_GENERIC=y
-CONFIG_ARCH_OMAP2420=y
-CONFIG_ARCH_OMAP2430=y
-CONFIG_ARCH_OMAP3430=y
-CONFIG_MACH_OMAP_H4=y
-CONFIG_MACH_OMAP_APOLLON=y
-CONFIG_MACH_OMAP_2430SDP=y
-CONFIG_MACH_OMAP3_BEAGLE=y
-CONFIG_MACH_DEVKIT8000=y
-CONFIG_MACH_OMAP_LDP=y
-CONFIG_MACH_OVERO=y
-CONFIG_MACH_OMAP3EVM=y
-CONFIG_MACH_OMAP3517EVM=y
-CONFIG_MACH_OMAP3_PANDORA=y
-CONFIG_MACH_OMAP3_TOUCHBOOK=y
-CONFIG_MACH_OMAP_3430SDP=y
-CONFIG_MACH_NOKIA_N8X0=y
-CONFIG_MACH_NOKIA_RX51=y
-CONFIG_MACH_OMAP_ZOOM2=y
-CONFIG_MACH_OMAP_ZOOM3=y
-CONFIG_MACH_CM_T35=y
-CONFIG_MACH_IGEP0020=y
-CONFIG_MACH_SBC3530=y
-CONFIG_MACH_OMAP_3630SDP=y
-CONFIG_MACH_OMAP_4430SDP=y
CONFIG_ARM_THUMBEE=y
-CONFIG_ARM_L1_CACHE_SHIFT=5
CONFIG_ARM_ERRATA_411920=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_SMP=y
CONFIG_NR_CPUS=2
-# CONFIG_LOCAL_TIMERS is not set
-CONFIG_AEABI=y
CONFIG_LEDS=y
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_CMDLINE="root=/dev/mmcblk0p2 rootwait console=ttyO2,115200"
CONFIG_KEXEC=y
CONFIG_FPE_NWFPE=y
-CONFIG_VFP=y
-CONFIG_NEON=y
CONFIG_BINFMT_MISC=y
-CONFIG_PM=y
CONFIG_PM_DEBUG=y
-CONFIG_PM_RUNTIME=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@@ -89,14 +53,6 @@ CONFIG_IP_PNP_RARP=y
# CONFIG_IPV6 is not set
CONFIG_NETFILTER=y
CONFIG_BT=m
-CONFIG_BT_L2CAP=m
-CONFIG_BT_SCO=m
-CONFIG_BT_RFCOMM=y
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=m
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
-CONFIG_BT_HIDP=m
CONFIG_BT_HCIUART=m
CONFIG_BT_HCIUART_H4=y
CONFIG_BT_HCIUART_BCSP=y
@@ -107,11 +63,9 @@ CONFIG_CFG80211=m
CONFIG_MAC80211=m
CONFIG_MAC80211_RC_PID=y
CONFIG_MAC80211_RC_DEFAULT_PID=y
-CONFIG_MAC80211_LEDS=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_CONNECTOR=y
CONFIG_MTD=y
-CONFIG_MTD_CONCAT=y
CONFIG_MTD_CMDLINE_PARTS=y
CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
@@ -127,7 +81,6 @@ CONFIG_MTD_UBI=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=16384
-CONFIG_EEPROM_LEGACY=y
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_SCSI_MULTI_LUN=y
@@ -158,19 +111,15 @@ CONFIG_TOUCHSCREEN_ADS7846=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_TWL4030_PWRBUTTON=y
CONFIG_VT_HW_CONSOLE_BINDING=y
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_8250_NR_UARTS=32
CONFIG_SERIAL_8250_EXTENDED=y
CONFIG_SERIAL_8250_MANY_PORTS=y
CONFIG_SERIAL_8250_SHARE_IRQ=y
CONFIG_SERIAL_8250_DETECT_IRQ=y
CONFIG_SERIAL_8250_RSA=y
-# CONFIG_LEGACY_PTYS is not set
CONFIG_HW_RANDOM=y
-CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_OMAP=y
CONFIG_SPI=y
CONFIG_SPI_OMAP24XX=y
CONFIG_DEBUG_GPIO=y
@@ -181,10 +130,6 @@ CONFIG_POWER_SUPPLY=y
CONFIG_WATCHDOG=y
CONFIG_OMAP_WATCHDOG=y
CONFIG_TWL4030_WATCHDOG=y
-CONFIG_MENELAUS=y
-CONFIG_TWL4030_CORE=y
-CONFIG_TWL4030_POWER=y
-CONFIG_REGULATOR=y
CONFIG_REGULATOR_TWL4030=y
CONFIG_REGULATOR_TPS65023=y
CONFIG_REGULATOR_TPS6507X=y
@@ -208,7 +153,6 @@ CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_LCD_CLASS_DEVICE=y
CONFIG_LCD_PLATFORM=y
CONFIG_DISPLAY_SUPPORT=y
-# CONFIG_VGA_CONSOLE is not set
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
CONFIG_FONTS=y
@@ -217,25 +161,20 @@ CONFIG_FONT_8x16=y
CONFIG_LOGO=y
CONFIG_SOUND=m
CONFIG_SND=m
-CONFIG_SND_MIXER_OSS=y
-CONFIG_SND_PCM_OSS=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
CONFIG_SND_VERBOSE_PRINTK=y
CONFIG_SND_DEBUG=y
-CONFIG_SND_USB_AUDIO=y
-CONFIG_SND_SOC=y
-CONFIG_SND_OMAP_SOC=y
-CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=y
+CONFIG_SND_USB_AUDIO=m
+CONFIG_SND_SOC=m
+CONFIG_SND_OMAP_SOC=m
+CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=m
CONFIG_USB=y
CONFIG_USB_DEBUG=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_DEVICEFS=y
CONFIG_USB_SUSPEND=y
-# CONFIG_USB_OTG_WHITELIST is not set
CONFIG_USB_MON=y
-# CONFIG_USB_MUSB_HDRC is not set
-# CONFIG_USB_MUSB_OTG is not set
-# CONFIG_USB_GADGET_MUSB_HDRC is not set
-CONFIG_USB_MUSB_DEBUG=y
CONFIG_USB_WDM=y
CONFIG_USB_STORAGE=y
CONFIG_USB_LIBUSUAL=y
@@ -250,18 +189,12 @@ CONFIG_MMC_UNSAFE_RESUME=y
CONFIG_SDIO_UART=y
CONFIG_MMC_OMAP=y
CONFIG_MMC_OMAP_HS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_GPIO=y
-CONFIG_LEDS_TRIGGER_TIMER=y
-CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_TWL92330=y
CONFIG_RTC_DRV_TWL4030=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
# CONFIG_EXT3_FS_XATTR is not set
-CONFIG_INOTIFY=y
CONFIG_QUOTA=y
CONFIG_QFMT_V2=y
CONFIG_MSDOS_FS=y
@@ -285,12 +218,10 @@ CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
CONFIG_SCHEDSTATS=y
CONFIG_TIMER_STATS=y
CONFIG_PROVE_LOCKING=y
-# CONFIG_LOCK_STAT is not set
CONFIG_DEBUG_SPINLOCK_SLEEP=y
# CONFIG_DEBUG_BUGVERBOSE is not set
CONFIG_DEBUG_INFO=y
diff --git a/arch/arm/configs/realview-smp_defconfig b/arch/arm/configs/realview-smp_defconfig
index 5ca7a61f7c01..abe61bf379d2 100644
--- a/arch/arm/configs/realview-smp_defconfig
+++ b/arch/arm/configs/realview-smp_defconfig
@@ -38,7 +38,7 @@ CONFIG_MTD_BLOCK=y
CONFIG_MTD_CFI=y
CONFIG_MTD_CFI_INTELEXT=y
CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_ARM_INTEGRATOR=y
+CONFIG_MTD_PHYSMAP=y
CONFIG_ARM_CHARLCD=y
CONFIG_NETDEVICES=y
CONFIG_SMSC_PHY=y
diff --git a/arch/arm/configs/realview_defconfig b/arch/arm/configs/realview_defconfig
index fcaa60328051..7079cbe898a8 100644
--- a/arch/arm/configs/realview_defconfig
+++ b/arch/arm/configs/realview_defconfig
@@ -37,7 +37,7 @@ CONFIG_MTD_BLOCK=y
CONFIG_MTD_CFI=y
CONFIG_MTD_CFI_INTELEXT=y
CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_ARM_INTEGRATOR=y
+CONFIG_MTD_PHYSMAP=y
CONFIG_ARM_CHARLCD=y
CONFIG_NETDEVICES=y
CONFIG_SMSC_PHY=y
diff --git a/arch/arm/configs/spear300_defconfig b/arch/arm/configs/spear300_defconfig
deleted file mode 100644
index cf29f3e56922..000000000000
--- a/arch/arm/configs/spear300_defconfig
+++ /dev/null
@@ -1,51 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_KALLSYMS_EXTRA_PASS=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_PLAT_SPEAR=y
-CONFIG_BINFMT_MISC=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=16384
-CONFIG_INPUT_FF_MEMLESS=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_SERIAL_AMBA_PL011=y
-CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_HW_RANDOM is not set
-CONFIG_RAW_DRIVER=y
-CONFIG_MAX_RAW_DEVS=8192
-CONFIG_GPIO_SYSFS=y
-CONFIG_GPIO_PL061=y
-# CONFIG_HWMON is not set
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT2_FS_SECURITY=y
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_SECURITY=y
-CONFIG_AUTOFS4_FS=m
-CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
-CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
-CONFIG_TMPFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_NLS=y
-CONFIG_NLS_DEFAULT="utf8"
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ASCII=m
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
-CONFIG_DEBUG_INFO=y
-# CONFIG_CRC32 is not set
diff --git a/arch/arm/configs/spear320_defconfig b/arch/arm/configs/spear320_defconfig
deleted file mode 100644
index 842f7f3c512a..000000000000
--- a/arch/arm/configs/spear320_defconfig
+++ /dev/null
@@ -1,52 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_KALLSYMS_EXTRA_PASS=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_PLAT_SPEAR=y
-CONFIG_MACH_SPEAR320=y
-CONFIG_BINFMT_MISC=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=16384
-CONFIG_INPUT_FF_MEMLESS=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_SERIAL_AMBA_PL011=y
-CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_HW_RANDOM is not set
-CONFIG_RAW_DRIVER=y
-CONFIG_MAX_RAW_DEVS=8192
-CONFIG_GPIO_SYSFS=y
-CONFIG_GPIO_PL061=y
-# CONFIG_HWMON is not set
-# CONFIG_VGA_CONSOLE is not set
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT2_FS_SECURITY=y
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_SECURITY=y
-CONFIG_AUTOFS4_FS=m
-CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
-CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
-CONFIG_TMPFS=y
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_NLS=y
-CONFIG_NLS_DEFAULT="utf8"
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ASCII=m
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_SPINLOCK=y
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
-CONFIG_DEBUG_INFO=y
-# CONFIG_CRC32 is not set
diff --git a/arch/arm/configs/spear310_defconfig b/arch/arm/configs/spear3xx_defconfig
index 824e44418b18..fea7e1f026a3 100644
--- a/arch/arm/configs/spear310_defconfig
+++ b/arch/arm/configs/spear3xx_defconfig
@@ -7,7 +7,9 @@ CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
CONFIG_PLAT_SPEAR=y
-CONFIG_MACH_SPEAR310=y
+CONFIG_BOARD_SPEAR300_EVB=y
+CONFIG_BOARD_SPEAR310_EVB=y
+CONFIG_BOARD_SPEAR320_EVB=y
CONFIG_BINFMT_MISC=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_BLK_DEV_RAM=y
@@ -25,7 +27,6 @@ CONFIG_MAX_RAW_DEVS=8192
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_PL061=y
# CONFIG_HWMON is not set
-# CONFIG_VGA_CONSOLE is not set
# CONFIG_HID_SUPPORT is not set
# CONFIG_USB_SUPPORT is not set
CONFIG_EXT2_FS=y
diff --git a/arch/arm/configs/spear600_defconfig b/arch/arm/configs/spear6xx_defconfig
index 6777c11f63e7..cef2e836afd2 100644
--- a/arch/arm/configs/spear600_defconfig
+++ b/arch/arm/configs/spear6xx_defconfig
@@ -8,6 +8,7 @@ CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
CONFIG_PLAT_SPEAR=y
CONFIG_ARCH_SPEAR6XX=y
+CONFIG_BOARD_SPEAR600_EVB=y
CONFIG_BINFMT_MISC=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_BLK_DEV_RAM=y
@@ -22,7 +23,6 @@ CONFIG_MAX_RAW_DEVS=8192
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_PL061=y
# CONFIG_HWMON is not set
-# CONFIG_VGA_CONSOLE is not set
# CONFIG_HID_SUPPORT is not set
# CONFIG_USB_SUPPORT is not set
CONFIG_EXT2_FS=y
diff --git a/arch/arm/configs/stmp378x_defconfig b/arch/arm/configs/stmp378x_defconfig
deleted file mode 100644
index 1079c2b6eb3a..000000000000
--- a/arch/arm/configs/stmp378x_defconfig
+++ /dev/null
@@ -1,128 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOCALVERSION="-default"
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_EXPERT=y
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_STMP3XXX=y
-CONFIG_ARCH_STMP378X=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_PREEMPT=y
-CONFIG_AEABI=y
-CONFIG_HIGHMEM=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=ttySDBG0,115200 mem=32M"
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_IP_MULTIPLE_TABLES=y
-CONFIG_IP_ROUTE_MULTIPATH=y
-CONFIG_IP_ROUTE_VERBOSE=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_MROUTE=y
-CONFIG_IP_PIMSM_V1=y
-CONFIG_IP_PIMSM_V2=y
-CONFIG_SYN_COOKIES=y
-# CONFIG_INET_LRO is not set
-# CONFIG_IPV6 is not set
-CONFIG_NET_SCHED=y
-# CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-# CONFIG_STANDALONE is not set
-CONFIG_MTD=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_UBI=y
-CONFIG_MTD_UBI_GLUEBI=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_CRYPTOLOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=4
-CONFIG_BLK_DEV_RAM_SIZE=6144
-# CONFIG_MISC_DEVICES is not set
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_SG=y
-# CONFIG_SCSI_LOWLEVEL is not set
-CONFIG_INPUT_POLLDEV=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=320
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=240
-CONFIG_INPUT_EVDEV=y
-# CONFIG_KEYBOARD_ATKBD is not set
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_INPUT_MISC=y
-# CONFIG_SERIO_SERPORT is not set
-CONFIG_VT_HW_CONSOLE_BINDING=y
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_HW_RANDOM=y
-CONFIG_DEBUG_GPIO=y
-CONFIG_GPIO_SYSFS=y
-# CONFIG_HWMON is not set
-CONFIG_FB=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_LCD_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_LOGO=y
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-# CONFIG_DNOTIFY is not set
-CONFIG_TMPFS=y
-CONFIG_CONFIGFS_FS=m
-# CONFIG_MISC_FILESYSTEMS is not set
-# CONFIG_NETWORK_FILESYSTEMS is not set
-# CONFIG_ENABLE_MUST_CHECK is not set
-CONFIG_STRIP_ASM_SYMS=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_SHIRQ=y
-# CONFIG_SCHED_DEBUG is not set
-CONFIG_DEBUG_OBJECTS=y
-CONFIG_DEBUG_OBJECTS_SELFTEST=y
-CONFIG_DEBUG_OBJECTS_FREE=y
-CONFIG_DEBUG_OBJECTS_TIMERS=y
-CONFIG_DEBUG_SLAB=y
-CONFIG_DEBUG_SLAB_LEAK=y
-CONFIG_DEBUG_RT_MUTEXES=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
-CONFIG_DEBUG_KOBJECT=y
-# CONFIG_DEBUG_BUGVERBOSE is not set
-CONFIG_DEBUG_INFO=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_BOOT_TRACER=y
-CONFIG_STACK_TRACER=y
-CONFIG_BLK_DEV_IO_TRACE=y
-CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
-CONFIG_SECURITY=y
-CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_ECB=y
-CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_SHA1=m
-CONFIG_CRYPTO_AES=m
-CONFIG_CRYPTO_DES=y
-CONFIG_CRYPTO_DEFLATE=y
-CONFIG_CRYPTO_LZO=y
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
-CONFIG_CRC_CCITT=m
-CONFIG_CRC16=y
diff --git a/arch/arm/configs/stmp37xx_defconfig b/arch/arm/configs/stmp37xx_defconfig
deleted file mode 100644
index 564a5cc44085..000000000000
--- a/arch/arm/configs/stmp37xx_defconfig
+++ /dev/null
@@ -1,108 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOCALVERSION="-default"
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_EXPERT=y
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_ARCH_STMP3XXX=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_PREEMPT=y
-CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=ttySDBG0,115200 mem=32M lcd_panel=lms350 rdinit=/bin/sh ignore_loglevel"
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_IP_MULTIPLE_TABLES=y
-CONFIG_IP_ROUTE_MULTIPATH=y
-CONFIG_IP_ROUTE_VERBOSE=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_MROUTE=y
-CONFIG_IP_PIMSM_V1=y
-CONFIG_IP_PIMSM_V2=y
-CONFIG_SYN_COOKIES=y
-# CONFIG_INET_LRO is not set
-# CONFIG_IPV6 is not set
-CONFIG_NET_SCHED=y
-# CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-# CONFIG_STANDALONE is not set
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_CRYPTOLOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=4
-CONFIG_BLK_DEV_RAM_SIZE=6144
-# CONFIG_MISC_DEVICES is not set
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_SG=y
-# CONFIG_SCSI_LOWLEVEL is not set
-CONFIG_INPUT_POLLDEV=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=320
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=240
-CONFIG_INPUT_EVDEV=y
-# CONFIG_KEYBOARD_ATKBD is not set
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_INPUT_MISC=y
-# CONFIG_SERIO_SERPORT is not set
-CONFIG_VT_HW_CONSOLE_BINDING=y
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_HW_RANDOM=y
-CONFIG_DEBUG_GPIO=y
-CONFIG_GPIO_SYSFS=y
-# CONFIG_HWMON is not set
-CONFIG_FB=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_LCD_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_LOGO=y
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-# CONFIG_DNOTIFY is not set
-CONFIG_TMPFS=y
-CONFIG_CONFIGFS_FS=m
-# CONFIG_MISC_FILESYSTEMS is not set
-# CONFIG_NETWORK_FILESYSTEMS is not set
-# CONFIG_ENABLE_MUST_CHECK is not set
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_SYSCTL_SYSCALL_CHECK=y
-CONFIG_BOOT_TRACER=y
-CONFIG_STACK_TRACER=y
-CONFIG_BLK_DEV_IO_TRACE=y
-CONFIG_DEBUG_LL=y
-CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
-CONFIG_SECURITY=y
-CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_ECB=y
-CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_SHA1=m
-CONFIG_CRYPTO_AES=m
-CONFIG_CRYPTO_DES=y
-CONFIG_CRYPTO_DEFLATE=y
-CONFIG_CRYPTO_LZO=y
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
-CONFIG_CRC_CCITT=m
-CONFIG_CRC16=y
diff --git a/arch/arm/configs/versatile_defconfig b/arch/arm/configs/versatile_defconfig
index 0ce710f47500..cdd4d2bd3962 100644
--- a/arch/arm/configs/versatile_defconfig
+++ b/arch/arm/configs/versatile_defconfig
@@ -32,7 +32,7 @@ CONFIG_MTD_BLOCK=y
CONFIG_MTD_CFI=y
CONFIG_MTD_CFI_ADV_OPTIONS=y
CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_ARM_INTEGRATOR=y
+CONFIG_MTD_PHYSMAP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_EEPROM_LEGACY=m
CONFIG_NETDEVICES=y
diff --git a/arch/arm/include/asm/bitops.h b/arch/arm/include/asm/bitops.h
index 6b7403fd8f54..b4892a06442c 100644
--- a/arch/arm/include/asm/bitops.h
+++ b/arch/arm/include/asm/bitops.h
@@ -203,8 +203,6 @@ extern int _find_next_bit_be(const unsigned long *p, int size, int offset);
#define find_first_bit(p,sz) _find_first_bit_le(p,sz)
#define find_next_bit(p,sz,off) _find_next_bit_le(p,sz,off)
-#define WORD_BITOFF_TO_LE(x) ((x))
-
#else
/*
* These are the big endian, atomic definitions.
@@ -214,8 +212,6 @@ extern int _find_next_bit_be(const unsigned long *p, int size, int offset);
#define find_first_bit(p,sz) _find_first_bit_be(p,sz)
#define find_next_bit(p,sz,off) _find_next_bit_be(p,sz,off)
-#define WORD_BITOFF_TO_LE(x) ((x) ^ 0x18)
-
#endif
#if __LINUX_ARM_ARCH__ < 5
@@ -287,55 +283,29 @@ static inline int fls(int x)
#include <asm-generic/bitops/hweight.h>
#include <asm-generic/bitops/lock.h>
-static inline void __set_bit_le(int nr, void *addr)
-{
- __set_bit(WORD_BITOFF_TO_LE(nr), addr);
-}
-
-static inline void __clear_bit_le(int nr, void *addr)
-{
- __clear_bit(WORD_BITOFF_TO_LE(nr), addr);
-}
-
-static inline int __test_and_set_bit_le(int nr, void *addr)
-{
- return __test_and_set_bit(WORD_BITOFF_TO_LE(nr), addr);
-}
-
-static inline int test_and_set_bit_le(int nr, void *addr)
-{
- return test_and_set_bit(WORD_BITOFF_TO_LE(nr), addr);
-}
-
-static inline int __test_and_clear_bit_le(int nr, void *addr)
-{
- return __test_and_clear_bit(WORD_BITOFF_TO_LE(nr), addr);
-}
-
-static inline int test_and_clear_bit_le(int nr, void *addr)
-{
- return test_and_clear_bit(WORD_BITOFF_TO_LE(nr), addr);
-}
-
-static inline int test_bit_le(int nr, const void *addr)
-{
- return test_bit(WORD_BITOFF_TO_LE(nr), addr);
-}
+#ifdef __ARMEB__
static inline int find_first_zero_bit_le(const void *p, unsigned size)
{
return _find_first_zero_bit_le(p, size);
}
+#define find_first_zero_bit_le find_first_zero_bit_le
static inline int find_next_zero_bit_le(const void *p, int size, int offset)
{
return _find_next_zero_bit_le(p, size, offset);
}
+#define find_next_zero_bit_le find_next_zero_bit_le
static inline int find_next_bit_le(const void *p, int size, int offset)
{
return _find_next_bit_le(p, size, offset);
}
+#define find_next_bit_le find_next_bit_le
+
+#endif
+
+#include <asm-generic/bitops/le.h>
/*
* Ext2 is defined to use little-endian byte ordering.
diff --git a/arch/arm/include/asm/dma.h b/arch/arm/include/asm/dma.h
index ca51143f97f1..42005542932b 100644
--- a/arch/arm/include/asm/dma.h
+++ b/arch/arm/include/asm/dma.h
@@ -6,8 +6,10 @@
/*
* This is the maximum virtual address which can be DMA'd from.
*/
-#ifndef MAX_DMA_ADDRESS
+#ifndef ARM_DMA_ZONE_SIZE
#define MAX_DMA_ADDRESS 0xffffffff
+#else
+#define MAX_DMA_ADDRESS (PAGE_OFFSET + ARM_DMA_ZONE_SIZE)
#endif
#ifdef CONFIG_ISA_DMA_API
diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h
index c3cd8755e648..0e9ce8d9686e 100644
--- a/arch/arm/include/asm/elf.h
+++ b/arch/arm/include/asm/elf.h
@@ -108,6 +108,7 @@ struct task_struct;
int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs);
#define ELF_CORE_COPY_TASK_REGS dump_task_regs
+#define CORE_DUMP_USE_REGSET
#define ELF_EXEC_PAGESIZE 4096
/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h
index 199a6b6de7f4..8c73900da9ed 100644
--- a/arch/arm/include/asm/futex.h
+++ b/arch/arm/include/asm/futex.h
@@ -3,16 +3,74 @@
#ifdef __KERNEL__
+#if defined(CONFIG_CPU_USE_DOMAINS) && defined(CONFIG_SMP)
+/* ARM doesn't provide unprivileged exclusive memory accessors */
+#include <asm-generic/futex.h>
+#else
+
+#include <linux/futex.h>
+#include <linux/uaccess.h>
+#include <asm/errno.h>
+
+#define __futex_atomic_ex_table(err_reg) \
+ "3:\n" \
+ " .pushsection __ex_table,\"a\"\n" \
+ " .align 3\n" \
+ " .long 1b, 4f, 2b, 4f\n" \
+ " .popsection\n" \
+ " .pushsection .fixup,\"ax\"\n" \
+ "4: mov %0, " err_reg "\n" \
+ " b 3b\n" \
+ " .popsection"
+
#ifdef CONFIG_SMP
-#include <asm-generic/futex.h>
+#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
+ smp_mb(); \
+ __asm__ __volatile__( \
+ "1: ldrex %1, [%2]\n" \
+ " " insn "\n" \
+ "2: strex %1, %0, [%2]\n" \
+ " teq %1, #0\n" \
+ " bne 1b\n" \
+ " mov %0, #0\n" \
+ __futex_atomic_ex_table("%4") \
+ : "=&r" (ret), "=&r" (oldval) \
+ : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \
+ : "cc", "memory")
+
+static inline int
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
+{
+ int ret;
+ u32 val;
+
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
+ return -EFAULT;
+
+ smp_mb();
+ __asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
+ "1: ldrex %1, [%4]\n"
+ " teq %1, %2\n"
+ " ite eq @ explicit IT needed for the 2b label\n"
+ "2: strexeq %0, %3, [%4]\n"
+ " movne %0, #0\n"
+ " teq %0, #0\n"
+ " bne 1b\n"
+ __futex_atomic_ex_table("%5")
+ : "=&r" (ret), "=&r" (val)
+ : "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT)
+ : "cc", "memory");
+ smp_mb();
+
+ *uval = val;
+ return ret;
+}
#else /* !SMP, we can work around lack of atomic ops by disabling preemption */
-#include <linux/futex.h>
#include <linux/preempt.h>
-#include <linux/uaccess.h>
-#include <asm/errno.h>
#include <asm/domain.h>
#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
@@ -21,20 +79,38 @@
" " insn "\n" \
"2: " T(str) " %0, [%2]\n" \
" mov %0, #0\n" \
- "3:\n" \
- " .pushsection __ex_table,\"a\"\n" \
- " .align 3\n" \
- " .long 1b, 4f, 2b, 4f\n" \
- " .popsection\n" \
- " .pushsection .fixup,\"ax\"\n" \
- "4: mov %0, %4\n" \
- " b 3b\n" \
- " .popsection" \
+ __futex_atomic_ex_table("%4") \
: "=&r" (ret), "=&r" (oldval) \
: "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \
: "cc", "memory")
static inline int
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
+{
+ int ret = 0;
+ u32 val;
+
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
+ return -EFAULT;
+
+ __asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
+ "1: " T(ldr) " %1, [%4]\n"
+ " teq %1, %2\n"
+ " it eq @ explicit IT needed for the 2b label\n"
+ "2: " T(streq) " %3, [%4]\n"
+ __futex_atomic_ex_table("%5")
+ : "+r" (ret), "=&r" (val)
+ : "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT)
+ : "cc", "memory");
+
+ *uval = val;
+ return ret;
+}
+
+#endif /* !SMP */
+
+static inline int
futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
int op = (encoded_op >> 28) & 7;
@@ -87,39 +163,6 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
return ret;
}
-static inline int
-futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
- u32 oldval, u32 newval)
-{
- int ret = 0;
- u32 val;
-
- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
- return -EFAULT;
-
- __asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n"
- "1: " T(ldr) " %1, [%4]\n"
- " teq %1, %2\n"
- " it eq @ explicit IT needed for the 2b label\n"
- "2: " T(streq) " %3, [%4]\n"
- "3:\n"
- " .pushsection __ex_table,\"a\"\n"
- " .align 3\n"
- " .long 1b, 4f, 2b, 4f\n"
- " .popsection\n"
- " .pushsection .fixup,\"ax\"\n"
- "4: mov %0, %5\n"
- " b 3b\n"
- " .popsection"
- : "+r" (ret), "=&r" (val)
- : "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT)
- : "cc", "memory");
-
- *uval = val;
- return ret;
-}
-
-#endif /* !SMP */
-
+#endif /* !(CPU_USE_DOMAINS && SMP) */
#endif /* __KERNEL__ */
#endif /* _ASM_ARM_FUTEX_H */
diff --git a/arch/arm/include/asm/hardware/timer-sp.h b/arch/arm/include/asm/hardware/timer-sp.h
index 21e75e30d497..4384d81eee79 100644
--- a/arch/arm/include/asm/hardware/timer-sp.h
+++ b/arch/arm/include/asm/hardware/timer-sp.h
@@ -1,2 +1,2 @@
-void sp804_clocksource_init(void __iomem *);
-void sp804_clockevents_init(void __iomem *, unsigned int);
+void sp804_clocksource_init(void __iomem *, const char *);
+void sp804_clockevents_init(void __iomem *, unsigned int, const char *);
diff --git a/arch/arm/include/asm/i8253.h b/arch/arm/include/asm/i8253.h
new file mode 100644
index 000000000000..70656b69d5ce
--- /dev/null
+++ b/arch/arm/include/asm/i8253.h
@@ -0,0 +1,15 @@
+#ifndef __ASMARM_I8253_H
+#define __ASMARM_I8253_H
+
+/* i8253A PIT registers */
+#define PIT_MODE 0x43
+#define PIT_CH0 0x40
+
+#define PIT_LATCH ((PIT_TICK_RATE + HZ / 2) / HZ)
+
+extern raw_spinlock_t i8253_lock;
+
+#define outb_pit outb_p
+#define inb_pit inb_p
+
+#endif
diff --git a/arch/arm/include/asm/mach/time.h b/arch/arm/include/asm/mach/time.h
index 883f6be5117a..d5adaae5ee2c 100644
--- a/arch/arm/include/asm/mach/time.h
+++ b/arch/arm/include/asm/mach/time.h
@@ -34,7 +34,6 @@
* timer interrupt which may be pending.
*/
struct sys_timer {
- struct sys_device dev;
void (*init)(void);
void (*suspend)(void);
void (*resume)(void);
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index 431077c5a867..af44a8fb3480 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -209,14 +209,10 @@ static inline unsigned long __phys_to_virt(unsigned long x)
* allocations. This must be the smallest DMA mask in the system,
* so a successful GFP_DMA allocation will always satisfy this.
*/
-#ifndef ISA_DMA_THRESHOLD
+#ifndef ARM_DMA_ZONE_SIZE
#define ISA_DMA_THRESHOLD (0xffffffffULL)
-#endif
-
-#ifndef arch_adjust_zones
-#define arch_adjust_zones(size,holes) do { } while (0)
-#elif !defined(CONFIG_ZONE_DMA)
-#error "custom arch_adjust_zones() requires CONFIG_ZONE_DMA"
+#else
+#define ISA_DMA_THRESHOLD (PHYS_OFFSET + ARM_DMA_ZONE_SIZE - 1)
#endif
/*
diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
index a8ff22b2a391..312d10877bd7 100644
--- a/arch/arm/include/asm/ptrace.h
+++ b/arch/arm/include/asm/ptrace.h
@@ -128,6 +128,12 @@ struct pt_regs {
#define ARM_r0 uregs[0]
#define ARM_ORIG_r0 uregs[17]
+/*
+ * The size of the user-visible VFP state as seen by PTRACE_GET/SETVFPREGS
+ * and core dumps.
+ */
+#define ARM_VFPREGS_SIZE ( 32 * 8 /*fpregs*/ + 4 /*fpscr*/ )
+
#ifdef __KERNEL__
#define user_mode(regs) \
diff --git a/arch/arm/include/asm/sizes.h b/arch/arm/include/asm/sizes.h
index 316bb2b2be3d..154b89b81d3e 100644
--- a/arch/arm/include/asm/sizes.h
+++ b/arch/arm/include/asm/sizes.h
@@ -16,44 +16,6 @@
/* Size definitions
* Copyright (C) ARM Limited 1998. All rights reserved.
*/
+#include <asm-generic/sizes.h>
-#ifndef __sizes_h
-#define __sizes_h 1
-
-/* handy sizes */
-#define SZ_16 0x00000010
-#define SZ_32 0x00000020
-#define SZ_64 0x00000040
-#define SZ_128 0x00000080
-#define SZ_256 0x00000100
-#define SZ_512 0x00000200
-
-#define SZ_1K 0x00000400
-#define SZ_2K 0x00000800
-#define SZ_4K 0x00001000
-#define SZ_8K 0x00002000
-#define SZ_16K 0x00004000
-#define SZ_32K 0x00008000
-#define SZ_64K 0x00010000
-#define SZ_128K 0x00020000
-#define SZ_256K 0x00040000
-#define SZ_512K 0x00080000
-
-#define SZ_1M 0x00100000
-#define SZ_2M 0x00200000
-#define SZ_4M 0x00400000
-#define SZ_8M 0x00800000
-#define SZ_16M 0x01000000
-#define SZ_32M 0x02000000
-#define SZ_48M 0x03000000
-#define SZ_64M 0x04000000
-#define SZ_128M 0x08000000
-#define SZ_256M 0x10000000
-#define SZ_512M 0x20000000
-
-#define SZ_1G 0x40000000
-#define SZ_2G 0x80000000
-
-#endif
-
-/* END */
+#define SZ_48M (SZ_32M + SZ_16M)
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 96ed521f2408..d2b514fd76f4 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -14,20 +14,12 @@
#include <linux/cpumask.h>
#include <linux/thread_info.h>
-#include <mach/smp.h>
-
#ifndef CONFIG_SMP
# error "<asm/smp.h> included in non-SMP build"
#endif
#define raw_smp_processor_id() (current_thread_info()->cpu)
-/*
- * at the moment, there's not a big penalty for changing CPUs
- * (the >big< penalty is running SMP in the first place)
- */
-#define PROC_CHANGE_PENALTY 15
-
struct seq_file;
/*
@@ -47,9 +39,9 @@ extern void smp_init_cpus(void);
/*
- * Raise an IPI cross call on CPUs in callmap.
+ * Provide a function to raise an IPI cross call on CPUs in callmap.
*/
-extern void smp_cross_call(const struct cpumask *mask, int ipi);
+extern void set_smp_cross_call(void (*)(const struct cpumask *, unsigned int));
/*
* Boot a secondary CPU, and assign it the specified idle task.
diff --git a/arch/arm/include/asm/spinlock.h b/arch/arm/include/asm/spinlock.h
index fdd3820edff8..65fa3c88095c 100644
--- a/arch/arm/include/asm/spinlock.h
+++ b/arch/arm/include/asm/spinlock.h
@@ -5,6 +5,8 @@
#error SMP not supported on pre-ARMv6 CPUs
#endif
+#include <asm/processor.h>
+
/*
* sev and wfe are ARMv6K extensions. Uniprocessor ARMv6 may not have the K
* extensions, so when running on UP, we have to patch these instructions away.
diff --git a/arch/arm/include/asm/tlb.h b/arch/arm/include/asm/tlb.h
index 82dfe5d0c41e..265f908c4a6e 100644
--- a/arch/arm/include/asm/tlb.h
+++ b/arch/arm/include/asm/tlb.h
@@ -41,12 +41,12 @@
*/
#if defined(CONFIG_SMP) || defined(CONFIG_CPU_32v7)
#define tlb_fast_mode(tlb) 0
-#define FREE_PTE_NR 500
#else
#define tlb_fast_mode(tlb) 1
-#define FREE_PTE_NR 0
#endif
+#define MMU_GATHER_BUNDLE 8
+
/*
* TLB handling. This allows us to remove pages from the page
* tables, and efficiently handle the TLB issues.
@@ -58,7 +58,9 @@ struct mmu_gather {
unsigned long range_start;
unsigned long range_end;
unsigned int nr;
- struct page *pages[FREE_PTE_NR];
+ unsigned int max;
+ struct page **pages;
+ struct page *local[MMU_GATHER_BUNDLE];
};
DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
@@ -97,26 +99,37 @@ static inline void tlb_add_flush(struct mmu_gather *tlb, unsigned long addr)
}
}
+static inline void __tlb_alloc_page(struct mmu_gather *tlb)
+{
+ unsigned long addr = __get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0);
+
+ if (addr) {
+ tlb->pages = (void *)addr;
+ tlb->max = PAGE_SIZE / sizeof(struct page *);
+ }
+}
+
static inline void tlb_flush_mmu(struct mmu_gather *tlb)
{
tlb_flush(tlb);
if (!tlb_fast_mode(tlb)) {
free_pages_and_swap_cache(tlb->pages, tlb->nr);
tlb->nr = 0;
+ if (tlb->pages == tlb->local)
+ __tlb_alloc_page(tlb);
}
}
-static inline struct mmu_gather *
-tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
+static inline void
+tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned int fullmm)
{
- struct mmu_gather *tlb = &get_cpu_var(mmu_gathers);
-
tlb->mm = mm;
- tlb->fullmm = full_mm_flush;
+ tlb->fullmm = fullmm;
tlb->vma = NULL;
+ tlb->max = ARRAY_SIZE(tlb->local);
+ tlb->pages = tlb->local;
tlb->nr = 0;
-
- return tlb;
+ __tlb_alloc_page(tlb);
}
static inline void
@@ -127,7 +140,8 @@ tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
/* keep the page table cache within bounds */
check_pgt_cache();
- put_cpu_var(mmu_gathers);
+ if (tlb->pages != tlb->local)
+ free_pages((unsigned long)tlb->pages, 0);
}
/*
@@ -162,15 +176,22 @@ tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
tlb_flush(tlb);
}
-static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)
{
if (tlb_fast_mode(tlb)) {
free_page_and_swap_cache(page);
- } else {
- tlb->pages[tlb->nr++] = page;
- if (tlb->nr >= FREE_PTE_NR)
- tlb_flush_mmu(tlb);
+ return 1; /* avoid calling tlb_flush_mmu */
}
+
+ tlb->pages[tlb->nr++] = page;
+ VM_BUG_ON(tlb->nr > tlb->max);
+ return tlb->max - tlb->nr;
+}
+
+static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+ if (!__tlb_remove_page(tlb, page))
+ tlb_flush_mmu(tlb);
}
static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
diff --git a/arch/arm/kernel/leds.c b/arch/arm/kernel/leds.c
index 31a316c1777b..0f107dcb0347 100644
--- a/arch/arm/kernel/leds.c
+++ b/arch/arm/kernel/leds.c
@@ -10,6 +10,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <asm/leds.h>
@@ -69,36 +70,37 @@ static ssize_t leds_store(struct sys_device *dev,
static SYSDEV_ATTR(event, 0200, NULL, leds_store);
-static int leds_suspend(struct sys_device *dev, pm_message_t state)
+static struct sysdev_class leds_sysclass = {
+ .name = "leds",
+};
+
+static struct sys_device leds_device = {
+ .id = 0,
+ .cls = &leds_sysclass,
+};
+
+static int leds_suspend(void)
{
leds_event(led_stop);
return 0;
}
-static int leds_resume(struct sys_device *dev)
+static void leds_resume(void)
{
leds_event(led_start);
- return 0;
}
-static int leds_shutdown(struct sys_device *dev)
+static void leds_shutdown(void)
{
leds_event(led_halted);
- return 0;
}
-static struct sysdev_class leds_sysclass = {
- .name = "leds",
+static struct syscore_ops leds_syscore_ops = {
.shutdown = leds_shutdown,
.suspend = leds_suspend,
.resume = leds_resume,
};
-static struct sys_device leds_device = {
- .id = 0,
- .cls = &leds_sysclass,
-};
-
static int __init leds_init(void)
{
int ret;
@@ -107,6 +109,8 @@ static int __init leds_init(void)
ret = sysdev_register(&leds_device);
if (ret == 0)
ret = sysdev_create_file(&leds_device, &attr_event);
+ if (ret == 0)
+ register_syscore_ops(&leds_syscore_ops);
return ret;
}
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 139e3c827369..d53c0abc4dd3 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -560,11 +560,6 @@ static int armpmu_event_init(struct perf_event *event)
event->destroy = hw_perf_event_destroy;
if (!atomic_inc_not_zero(&active_events)) {
- if (atomic_read(&active_events) > armpmu->num_events) {
- atomic_dec(&active_events);
- return -ENOSPC;
- }
-
mutex_lock(&pmu_reserve_mutex);
if (atomic_read(&active_events) == 0) {
err = armpmu_reserve_hardware();
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index 8182f45ca493..97260060bf26 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -21,6 +21,7 @@
#include <linux/uaccess.h>
#include <linux/perf_event.h>
#include <linux/hw_breakpoint.h>
+#include <linux/regset.h>
#include <asm/pgtable.h>
#include <asm/system.h>
@@ -308,58 +309,6 @@ static int ptrace_write_user(struct task_struct *tsk, unsigned long off,
return put_user_reg(tsk, off >> 2, val);
}
-/*
- * Get all user integer registers.
- */
-static int ptrace_getregs(struct task_struct *tsk, void __user *uregs)
-{
- struct pt_regs *regs = task_pt_regs(tsk);
-
- return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0;
-}
-
-/*
- * Set all user integer registers.
- */
-static int ptrace_setregs(struct task_struct *tsk, void __user *uregs)
-{
- struct pt_regs newregs;
- int ret;
-
- ret = -EFAULT;
- if (copy_from_user(&newregs, uregs, sizeof(struct pt_regs)) == 0) {
- struct pt_regs *regs = task_pt_regs(tsk);
-
- ret = -EINVAL;
- if (valid_user_regs(&newregs)) {
- *regs = newregs;
- ret = 0;
- }
- }
-
- return ret;
-}
-
-/*
- * Get the child FPU state.
- */
-static int ptrace_getfpregs(struct task_struct *tsk, void __user *ufp)
-{
- return copy_to_user(ufp, &task_thread_info(tsk)->fpstate,
- sizeof(struct user_fp)) ? -EFAULT : 0;
-}
-
-/*
- * Set the child FPU state.
- */
-static int ptrace_setfpregs(struct task_struct *tsk, void __user *ufp)
-{
- struct thread_info *thread = task_thread_info(tsk);
- thread->used_cp[1] = thread->used_cp[2] = 1;
- return copy_from_user(&thread->fpstate, ufp,
- sizeof(struct user_fp)) ? -EFAULT : 0;
-}
-
#ifdef CONFIG_IWMMXT
/*
@@ -418,56 +367,6 @@ static int ptrace_setcrunchregs(struct task_struct *tsk, void __user *ufp)
}
#endif
-#ifdef CONFIG_VFP
-/*
- * Get the child VFP state.
- */
-static int ptrace_getvfpregs(struct task_struct *tsk, void __user *data)
-{
- struct thread_info *thread = task_thread_info(tsk);
- union vfp_state *vfp = &thread->vfpstate;
- struct user_vfp __user *ufp = data;
-
- vfp_sync_hwstate(thread);
-
- /* copy the floating point registers */
- if (copy_to_user(&ufp->fpregs, &vfp->hard.fpregs,
- sizeof(vfp->hard.fpregs)))
- return -EFAULT;
-
- /* copy the status and control register */
- if (put_user(vfp->hard.fpscr, &ufp->fpscr))
- return -EFAULT;
-
- return 0;
-}
-
-/*
- * Set the child VFP state.
- */
-static int ptrace_setvfpregs(struct task_struct *tsk, void __user *data)
-{
- struct thread_info *thread = task_thread_info(tsk);
- union vfp_state *vfp = &thread->vfpstate;
- struct user_vfp __user *ufp = data;
-
- vfp_sync_hwstate(thread);
-
- /* copy the floating point registers */
- if (copy_from_user(&vfp->hard.fpregs, &ufp->fpregs,
- sizeof(vfp->hard.fpregs)))
- return -EFAULT;
-
- /* copy the status and control register */
- if (get_user(vfp->hard.fpscr, &ufp->fpscr))
- return -EFAULT;
-
- vfp_flush_hwstate(thread);
-
- return 0;
-}
-#endif
-
#ifdef CONFIG_HAVE_HW_BREAKPOINT
/*
* Convert a virtual register number into an index for a thread_info
@@ -694,6 +593,219 @@ out:
}
#endif
+/* regset get/set implementations */
+
+static int gpr_get(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ struct pt_regs *regs = task_pt_regs(target);
+
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ regs,
+ 0, sizeof(*regs));
+}
+
+static int gpr_set(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ int ret;
+ struct pt_regs newregs;
+
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &newregs,
+ 0, sizeof(newregs));
+ if (ret)
+ return ret;
+
+ if (!valid_user_regs(&newregs))
+ return -EINVAL;
+
+ *task_pt_regs(target) = newregs;
+ return 0;
+}
+
+static int fpa_get(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &task_thread_info(target)->fpstate,
+ 0, sizeof(struct user_fp));
+}
+
+static int fpa_set(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ struct thread_info *thread = task_thread_info(target);
+
+ thread->used_cp[1] = thread->used_cp[2] = 1;
+
+ return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &thread->fpstate,
+ 0, sizeof(struct user_fp));
+}
+
+#ifdef CONFIG_VFP
+/*
+ * VFP register get/set implementations.
+ *
+ * With respect to the kernel, struct user_fp is divided into three chunks:
+ * 16 or 32 real VFP registers (d0-d15 or d0-31)
+ * These are transferred to/from the real registers in the task's
+ * vfp_hard_struct. The number of registers depends on the kernel
+ * configuration.
+ *
+ * 16 or 0 fake VFP registers (d16-d31 or empty)
+ * i.e., the user_vfp structure has space for 32 registers even if
+ * the kernel doesn't have them all.
+ *
+ * vfp_get() reads this chunk as zero where applicable
+ * vfp_set() ignores this chunk
+ *
+ * 1 word for the FPSCR
+ *
+ * The bounds-checking logic built into user_regset_copyout and friends
+ * means that we can make a simple sequence of calls to map the relevant data
+ * to/from the specified slice of the user regset structure.
+ */
+static int vfp_get(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ int ret;
+ struct thread_info *thread = task_thread_info(target);
+ struct vfp_hard_struct const *vfp = &thread->vfpstate.hard;
+ const size_t user_fpregs_offset = offsetof(struct user_vfp, fpregs);
+ const size_t user_fpscr_offset = offsetof(struct user_vfp, fpscr);
+
+ vfp_sync_hwstate(thread);
+
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &vfp->fpregs,
+ user_fpregs_offset,
+ user_fpregs_offset + sizeof(vfp->fpregs));
+ if (ret)
+ return ret;
+
+ ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+ user_fpregs_offset + sizeof(vfp->fpregs),
+ user_fpscr_offset);
+ if (ret)
+ return ret;
+
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &vfp->fpscr,
+ user_fpscr_offset,
+ user_fpscr_offset + sizeof(vfp->fpscr));
+}
+
+/*
+ * For vfp_set() a read-modify-write is done on the VFP registers,
+ * in order to avoid writing back a half-modified set of registers on
+ * failure.
+ */
+static int vfp_set(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ int ret;
+ struct thread_info *thread = task_thread_info(target);
+ struct vfp_hard_struct new_vfp = thread->vfpstate.hard;
+ const size_t user_fpregs_offset = offsetof(struct user_vfp, fpregs);
+ const size_t user_fpscr_offset = offsetof(struct user_vfp, fpscr);
+
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &new_vfp.fpregs,
+ user_fpregs_offset,
+ user_fpregs_offset + sizeof(new_vfp.fpregs));
+ if (ret)
+ return ret;
+
+ ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ user_fpregs_offset + sizeof(new_vfp.fpregs),
+ user_fpscr_offset);
+ if (ret)
+ return ret;
+
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+ &new_vfp.fpscr,
+ user_fpscr_offset,
+ user_fpscr_offset + sizeof(new_vfp.fpscr));
+ if (ret)
+ return ret;
+
+ vfp_sync_hwstate(thread);
+ thread->vfpstate.hard = new_vfp;
+ vfp_flush_hwstate(thread);
+
+ return 0;
+}
+#endif /* CONFIG_VFP */
+
+enum arm_regset {
+ REGSET_GPR,
+ REGSET_FPR,
+#ifdef CONFIG_VFP
+ REGSET_VFP,
+#endif
+};
+
+static const struct user_regset arm_regsets[] = {
+ [REGSET_GPR] = {
+ .core_note_type = NT_PRSTATUS,
+ .n = ELF_NGREG,
+ .size = sizeof(u32),
+ .align = sizeof(u32),
+ .get = gpr_get,
+ .set = gpr_set
+ },
+ [REGSET_FPR] = {
+ /*
+ * For the FPA regs in fpstate, the real fields are a mixture
+ * of sizes, so pretend that the registers are word-sized:
+ */
+ .core_note_type = NT_PRFPREG,
+ .n = sizeof(struct user_fp) / sizeof(u32),
+ .size = sizeof(u32),
+ .align = sizeof(u32),
+ .get = fpa_get,
+ .set = fpa_set
+ },
+#ifdef CONFIG_VFP
+ [REGSET_VFP] = {
+ /*
+ * Pretend that the VFP regs are word-sized, since the FPSCR is
+ * a single word dangling at the end of struct user_vfp:
+ */
+ .core_note_type = NT_ARM_VFP,
+ .n = ARM_VFPREGS_SIZE / sizeof(u32),
+ .size = sizeof(u32),
+ .align = sizeof(u32),
+ .get = vfp_get,
+ .set = vfp_set
+ },
+#endif /* CONFIG_VFP */
+};
+
+static const struct user_regset_view user_arm_view = {
+ .name = "arm", .e_machine = ELF_ARCH, .ei_osabi = ELF_OSABI,
+ .regsets = arm_regsets, .n = ARRAY_SIZE(arm_regsets)
+};
+
+const struct user_regset_view *task_user_regset_view(struct task_struct *task)
+{
+ return &user_arm_view;
+}
+
long arch_ptrace(struct task_struct *child, long request,
unsigned long addr, unsigned long data)
{
@@ -710,19 +822,31 @@ long arch_ptrace(struct task_struct *child, long request,
break;
case PTRACE_GETREGS:
- ret = ptrace_getregs(child, datap);
+ ret = copy_regset_to_user(child,
+ &user_arm_view, REGSET_GPR,
+ 0, sizeof(struct pt_regs),
+ datap);
break;
case PTRACE_SETREGS:
- ret = ptrace_setregs(child, datap);
+ ret = copy_regset_from_user(child,
+ &user_arm_view, REGSET_GPR,
+ 0, sizeof(struct pt_regs),
+ datap);
break;
case PTRACE_GETFPREGS:
- ret = ptrace_getfpregs(child, datap);
+ ret = copy_regset_to_user(child,
+ &user_arm_view, REGSET_FPR,
+ 0, sizeof(union fp_state),
+ datap);
break;
-
+
case PTRACE_SETFPREGS:
- ret = ptrace_setfpregs(child, datap);
+ ret = copy_regset_from_user(child,
+ &user_arm_view, REGSET_FPR,
+ 0, sizeof(union fp_state),
+ datap);
break;
#ifdef CONFIG_IWMMXT
@@ -757,11 +881,17 @@ long arch_ptrace(struct task_struct *child, long request,
#ifdef CONFIG_VFP
case PTRACE_GETVFPREGS:
- ret = ptrace_getvfpregs(child, datap);
+ ret = copy_regset_to_user(child,
+ &user_arm_view, REGSET_VFP,
+ 0, ARM_VFPREGS_SIZE,
+ datap);
break;
case PTRACE_SETVFPREGS:
- ret = ptrace_setvfpregs(child, datap);
+ ret = copy_regset_from_user(child,
+ &user_arm_view, REGSET_VFP,
+ 0, ARM_VFPREGS_SIZE,
+ datap);
break;
#endif
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 006c1e884eaf..6dce209a623b 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -672,11 +672,16 @@ __tagtable(ATAG_REVISION, parse_tag_revision);
static int __init parse_tag_cmdline(const struct tag *tag)
{
-#ifndef CONFIG_CMDLINE_FORCE
- strlcpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE);
-#else
+#if defined(CONFIG_CMDLINE_EXTEND)
+ strlcat(default_command_line, " ", COMMAND_LINE_SIZE);
+ strlcat(default_command_line, tag->u.cmdline.cmdline,
+ COMMAND_LINE_SIZE);
+#elif defined(CONFIG_CMDLINE_FORCE)
pr_warning("Ignoring tag cmdline (using the default kernel command line)\n");
-#endif /* CONFIG_CMDLINE_FORCE */
+#else
+ strlcpy(default_command_line, tag->u.cmdline.cmdline,
+ COMMAND_LINE_SIZE);
+#endif
return 0;
}
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index f29b8a29b174..d439a8f4c078 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -376,6 +376,13 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
}
}
+static void (*smp_cross_call)(const struct cpumask *, unsigned int);
+
+void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int))
+{
+ smp_cross_call = fn;
+}
+
void arch_send_call_function_ipi_mask(const struct cpumask *mask)
{
smp_cross_call(mask, IPI_CALL_FUNC);
@@ -560,10 +567,7 @@ asmlinkage void __exception_irq_entry do_IPI(int ipinr, struct pt_regs *regs)
break;
case IPI_RESCHEDULE:
- /*
- * nothing more to do - eveything is
- * done on the interrupt return path
- */
+ scheduler_ipi();
break;
case IPI_CALL_FUNC:
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index 1ff46cabc7ef..cb634c3e28e9 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -21,7 +21,7 @@
#include <linux/timex.h>
#include <linux/errno.h>
#include <linux/profile.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/timer.h>
#include <linux/irq.h>
@@ -115,48 +115,37 @@ void timer_tick(void)
#endif
#if defined(CONFIG_PM) && !defined(CONFIG_GENERIC_CLOCKEVENTS)
-static int timer_suspend(struct sys_device *dev, pm_message_t state)
+static int timer_suspend(void)
{
- struct sys_timer *timer = container_of(dev, struct sys_timer, dev);
-
- if (timer->suspend != NULL)
- timer->suspend();
+ if (system_timer->suspend)
+ system_timer->suspend();
return 0;
}
-static int timer_resume(struct sys_device *dev)
+static void timer_resume(void)
{
- struct sys_timer *timer = container_of(dev, struct sys_timer, dev);
-
- if (timer->resume != NULL)
- timer->resume();
-
- return 0;
+ if (system_timer->resume)
+ system_timer->resume();
}
#else
#define timer_suspend NULL
#define timer_resume NULL
#endif
-static struct sysdev_class timer_sysclass = {
- .name = "timer",
+static struct syscore_ops timer_syscore_ops = {
.suspend = timer_suspend,
.resume = timer_resume,
};
-static int __init timer_init_sysfs(void)
+static int __init timer_init_syscore_ops(void)
{
- int ret = sysdev_class_register(&timer_sysclass);
- if (ret == 0) {
- system_timer->dev.cls = &timer_sysclass;
- ret = sysdev_register(&system_timer->dev);
- }
+ register_syscore_ops(&timer_syscore_ops);
- return ret;
+ return 0;
}
-device_initcall(timer_init_sysfs);
+device_initcall(timer_init_syscore_ops);
void __init time_init(void)
{
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 3b54ad19d489..d52eec268b47 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -234,7 +234,6 @@ static int __die(const char *str, int err, struct thread_info *thread, struct pt
printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP "\n",
str, err, ++die_counter);
- sysfs_printk_last_file();
/* trap and error numbers are mostly meaningless on ARM */
ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, SIGSEGV);
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index b4348e62ef06..e5287f21badc 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -82,7 +82,7 @@ SECTIONS
#endif
}
- PERCPU(32, PAGE_SIZE)
+ PERCPU_SECTION(32)
#ifndef CONFIG_XIP_KERNEL
. = ALIGN(PAGE_SIZE);
diff --git a/arch/arm/mach-at91/at91cap9_devices.c b/arch/arm/mach-at91/at91cap9_devices.c
index 9ffbf3a2dfea..21020ceb2f3a 100644
--- a/arch/arm/mach-at91/at91cap9_devices.c
+++ b/arch/arm/mach-at91/at91cap9_devices.c
@@ -171,7 +171,7 @@ void __init at91_add_device_usba(struct usba_platform_data *data)
*/
usba_udc_data.pdata.vbus_pin = -EINVAL;
usba_udc_data.pdata.num_ep = ARRAY_SIZE(usba_udc_ep);
- memcpy(usba_udc_data.ep, usba_udc_ep, sizeof(usba_udc_ep));;
+ memcpy(usba_udc_data.ep, usba_udc_ep, sizeof(usba_udc_ep));
if (data && data->vbus_pin > 0) {
at91_set_gpio_input(data->vbus_pin, 0);
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
index 1e8f275c17f6..5e9f8a4c38df 100644
--- a/arch/arm/mach-at91/at91sam9g45_devices.c
+++ b/arch/arm/mach-at91/at91sam9g45_devices.c
@@ -256,7 +256,7 @@ void __init at91_add_device_usba(struct usba_platform_data *data)
{
usba_udc_data.pdata.vbus_pin = -EINVAL;
usba_udc_data.pdata.num_ep = ARRAY_SIZE(usba_udc_ep);
- memcpy(usba_udc_data.ep, usba_udc_ep, sizeof(usba_udc_ep));;
+ memcpy(usba_udc_data.ep, usba_udc_ep, sizeof(usba_udc_ep));
if (data && data->vbus_pin > 0) {
at91_set_gpio_input(data->vbus_pin, 0);
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
index 53aaa94df75a..c49262bddd85 100644
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
@@ -145,7 +145,7 @@ void __init at91_add_device_usba(struct usba_platform_data *data)
*/
usba_udc_data.pdata.vbus_pin = -EINVAL;
usba_udc_data.pdata.num_ep = ARRAY_SIZE(usba_udc_ep);
- memcpy(usba_udc_data.ep, usba_udc_ep, sizeof(usba_udc_ep));;
+ memcpy(usba_udc_data.ep, usba_udc_ep, sizeof(usba_udc_ep));
if (data && data->vbus_pin > 0) {
at91_set_gpio_input(data->vbus_pin, 0);
diff --git a/arch/arm/mach-bcmring/arch.c b/arch/arm/mach-bcmring/arch.c
index 73eb066d2329..a604b9ebb501 100644
--- a/arch/arm/mach-bcmring/arch.c
+++ b/arch/arm/mach-bcmring/arch.c
@@ -169,6 +169,7 @@ MACHINE_START(BCMRING, "BCMRING")
/* Maintainer: Broadcom Corporation */
.fixup = bcmring_fixup,
.map_io = bcmring_map_io,
+ .init_early = bcmring_init_early,
.init_irq = bcmring_init_irq,
.timer = &bcmring_timer,
.init_machine = bcmring_init_machine
diff --git a/arch/arm/mach-bcmring/core.c b/arch/arm/mach-bcmring/core.c
index 8fc2035759fb..43eadbcc29ed 100644
--- a/arch/arm/mach-bcmring/core.c
+++ b/arch/arm/mach-bcmring/core.c
@@ -28,8 +28,6 @@
#include <linux/sysdev.h>
#include <linux/interrupt.h>
#include <linux/amba/bus.h>
-#include <linux/clocksource.h>
-#include <linux/clockchips.h>
#include <linux/clkdev.h>
#include <mach/csp/mm_addr.h>
@@ -37,6 +35,7 @@
#include <linux/io.h>
#include <asm/irq.h>
#include <asm/hardware/arm_timer.h>
+#include <asm/hardware/timer-sp.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -97,6 +96,35 @@ static struct clk dummy_apb_pclk = {
.mode = CLK_MODE_XTAL,
};
+/* Timer 0 - 25 MHz, Timer3 at bus clock rate, typically 150-166 MHz */
+#if defined(CONFIG_ARCH_FPGA11107)
+/* fpga cpu/bus are currently 30 times slower so scale frequency as well to */
+/* slow down Linux's sense of time */
+#define TIMER0_FREQUENCY_MHZ (tmrHw_LOW_FREQUENCY_MHZ * 30)
+#define TIMER1_FREQUENCY_MHZ (tmrHw_LOW_FREQUENCY_MHZ * 30)
+#define TIMER3_FREQUENCY_MHZ (tmrHw_HIGH_FREQUENCY_MHZ * 30)
+#define TIMER3_FREQUENCY_KHZ (tmrHw_HIGH_FREQUENCY_HZ / 1000 * 30)
+#else
+#define TIMER0_FREQUENCY_MHZ tmrHw_LOW_FREQUENCY_MHZ
+#define TIMER1_FREQUENCY_MHZ tmrHw_LOW_FREQUENCY_MHZ
+#define TIMER3_FREQUENCY_MHZ tmrHw_HIGH_FREQUENCY_MHZ
+#define TIMER3_FREQUENCY_KHZ (tmrHw_HIGH_FREQUENCY_HZ / 1000)
+#endif
+
+static struct clk sp804_timer012_clk = {
+ .name = "sp804-timer-0,1,2",
+ .type = CLK_TYPE_PRIMARY,
+ .mode = CLK_MODE_XTAL,
+ .rate_hz = TIMER1_FREQUENCY_MHZ * 1000000,
+};
+
+static struct clk sp804_timer3_clk = {
+ .name = "sp804-timer-3",
+ .type = CLK_TYPE_PRIMARY,
+ .mode = CLK_MODE_XTAL,
+ .rate_hz = TIMER3_FREQUENCY_KHZ * 1000,
+};
+
static struct clk_lookup lookups[] = {
{ /* Bus clock */
.con_id = "apb_pclk",
@@ -107,6 +135,18 @@ static struct clk_lookup lookups[] = {
}, { /* UART1 */
.dev_id = "uartb",
.clk = &uart_clk,
+ }, { /* SP804 timer 0 */
+ .dev_id = "sp804",
+ .con_id = "timer0",
+ .clk = &sp804_timer012_clk,
+ }, { /* SP804 timer 1 */
+ .dev_id = "sp804",
+ .con_id = "timer1",
+ .clk = &sp804_timer012_clk,
+ }, { /* SP804 timer 3 */
+ .dev_id = "sp804",
+ .con_id = "timer3",
+ .clk = &sp804_timer3_clk,
}
};
@@ -151,8 +191,6 @@ void __init bcmring_amba_init(void)
chipcHw_busInterfaceClockEnable(bus_clock);
- clkdev_add_table(lookups, ARRAY_SIZE(lookups));
-
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
struct amba_device *d = amba_devs[i];
amba_device_register(d, &iomem_resource);
@@ -162,170 +200,18 @@ void __init bcmring_amba_init(void)
/*
* Where is the timer (VA)?
*/
-#define TIMER0_VA_BASE MM_IO_BASE_TMR
-#define TIMER1_VA_BASE (MM_IO_BASE_TMR + 0x20)
-#define TIMER2_VA_BASE (MM_IO_BASE_TMR + 0x40)
-#define TIMER3_VA_BASE (MM_IO_BASE_TMR + 0x60)
-
-/* Timer 0 - 25 MHz, Timer3 at bus clock rate, typically 150-166 MHz */
-#if defined(CONFIG_ARCH_FPGA11107)
-/* fpga cpu/bus are currently 30 times slower so scale frequency as well to */
-/* slow down Linux's sense of time */
-#define TIMER0_FREQUENCY_MHZ (tmrHw_LOW_FREQUENCY_MHZ * 30)
-#define TIMER1_FREQUENCY_MHZ (tmrHw_LOW_FREQUENCY_MHZ * 30)
-#define TIMER3_FREQUENCY_MHZ (tmrHw_HIGH_FREQUENCY_MHZ * 30)
-#define TIMER3_FREQUENCY_KHZ (tmrHw_HIGH_FREQUENCY_HZ / 1000 * 30)
-#else
-#define TIMER0_FREQUENCY_MHZ tmrHw_LOW_FREQUENCY_MHZ
-#define TIMER1_FREQUENCY_MHZ tmrHw_LOW_FREQUENCY_MHZ
-#define TIMER3_FREQUENCY_MHZ tmrHw_HIGH_FREQUENCY_MHZ
-#define TIMER3_FREQUENCY_KHZ (tmrHw_HIGH_FREQUENCY_HZ / 1000)
-#endif
-
-#define TICKS_PER_uSEC TIMER0_FREQUENCY_MHZ
-
-/*
- * These are useconds NOT ticks.
- *
- */
-#define mSEC_1 1000
-#define mSEC_5 (mSEC_1 * 5)
-#define mSEC_10 (mSEC_1 * 10)
-#define mSEC_25 (mSEC_1 * 25)
-#define SEC_1 (mSEC_1 * 1000)
-
-/*
- * How long is the timer interval?
- */
-#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10)
-#if TIMER_INTERVAL >= 0x100000
-#define TIMER_RELOAD (TIMER_INTERVAL >> 8)
-#define TIMER_DIVISOR (TIMER_CTRL_DIV256)
-#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC)
-#elif TIMER_INTERVAL >= 0x10000
-#define TIMER_RELOAD (TIMER_INTERVAL >> 4) /* Divide by 16 */
-#define TIMER_DIVISOR (TIMER_CTRL_DIV16)
-#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC)
-#else
-#define TIMER_RELOAD (TIMER_INTERVAL)
-#define TIMER_DIVISOR (TIMER_CTRL_DIV1)
-#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC)
-#endif
-
-static void timer_set_mode(enum clock_event_mode mode,
- struct clock_event_device *clk)
-{
- unsigned long ctrl;
-
- switch (mode) {
- case CLOCK_EVT_MODE_PERIODIC:
- writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD);
-
- ctrl = TIMER_CTRL_PERIODIC;
- ctrl |=
- TIMER_DIVISOR | TIMER_CTRL_32BIT | TIMER_CTRL_IE |
- TIMER_CTRL_ENABLE;
- break;
- case CLOCK_EVT_MODE_ONESHOT:
- /* period set, and timer enabled in 'next_event' hook */
- ctrl = TIMER_CTRL_ONESHOT;
- ctrl |= TIMER_DIVISOR | TIMER_CTRL_32BIT | TIMER_CTRL_IE;
- break;
- case CLOCK_EVT_MODE_UNUSED:
- case CLOCK_EVT_MODE_SHUTDOWN:
- default:
- ctrl = 0;
- }
-
- writel(ctrl, TIMER0_VA_BASE + TIMER_CTRL);
-}
-
-static int timer_set_next_event(unsigned long evt,
- struct clock_event_device *unused)
-{
- unsigned long ctrl = readl(TIMER0_VA_BASE + TIMER_CTRL);
-
- writel(evt, TIMER0_VA_BASE + TIMER_LOAD);
- writel(ctrl | TIMER_CTRL_ENABLE, TIMER0_VA_BASE + TIMER_CTRL);
-
- return 0;
-}
-
-static struct clock_event_device timer0_clockevent = {
- .name = "timer0",
- .shift = 32,
- .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
- .set_mode = timer_set_mode,
- .set_next_event = timer_set_next_event,
-};
-
-/*
- * IRQ handler for the timer
- */
-static irqreturn_t bcmring_timer_interrupt(int irq, void *dev_id)
-{
- struct clock_event_device *evt = &timer0_clockevent;
-
- writel(1, TIMER0_VA_BASE + TIMER_INTCLR);
-
- evt->event_handler(evt);
-
- return IRQ_HANDLED;
-}
-
-static struct irqaction bcmring_timer_irq = {
- .name = "bcmring Timer Tick",
- .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
- .handler = bcmring_timer_interrupt,
-};
-
-static cycle_t bcmring_get_cycles_timer1(struct clocksource *cs)
-{
- return ~readl(TIMER1_VA_BASE + TIMER_VALUE);
-}
-
-static cycle_t bcmring_get_cycles_timer3(struct clocksource *cs)
-{
- return ~readl(TIMER3_VA_BASE + TIMER_VALUE);
-}
-
-static struct clocksource clocksource_bcmring_timer1 = {
- .name = "timer1",
- .rating = 200,
- .read = bcmring_get_cycles_timer1,
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-static struct clocksource clocksource_bcmring_timer3 = {
- .name = "timer3",
- .rating = 100,
- .read = bcmring_get_cycles_timer3,
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
+#define TIMER0_VA_BASE ((void __iomem *)MM_IO_BASE_TMR)
+#define TIMER1_VA_BASE ((void __iomem *)(MM_IO_BASE_TMR + 0x20))
+#define TIMER2_VA_BASE ((void __iomem *)(MM_IO_BASE_TMR + 0x40))
+#define TIMER3_VA_BASE ((void __iomem *)(MM_IO_BASE_TMR + 0x60))
static int __init bcmring_clocksource_init(void)
{
/* setup timer1 as free-running clocksource */
- writel(0, TIMER1_VA_BASE + TIMER_CTRL);
- writel(0xffffffff, TIMER1_VA_BASE + TIMER_LOAD);
- writel(0xffffffff, TIMER1_VA_BASE + TIMER_VALUE);
- writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC,
- TIMER1_VA_BASE + TIMER_CTRL);
-
- clocksource_register_khz(&clocksource_bcmring_timer1,
- TIMER1_FREQUENCY_MHZ * 1000);
+ sp804_clocksource_init(TIMER1_VA_BASE, "timer1");
/* setup timer3 as free-running clocksource */
- writel(0, TIMER3_VA_BASE + TIMER_CTRL);
- writel(0xffffffff, TIMER3_VA_BASE + TIMER_LOAD);
- writel(0xffffffff, TIMER3_VA_BASE + TIMER_VALUE);
- writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC,
- TIMER3_VA_BASE + TIMER_CTRL);
-
- clocksource_register_khz(&clocksource_bcmring_timer3,
- TIMER3_FREQUENCY_KHZ);
+ sp804_clocksource_init(TIMER3_VA_BASE, "timer3");
return 0;
}
@@ -347,21 +233,16 @@ void __init bcmring_init_timer(void)
/*
* Make irqs happen for the system timer
*/
- setup_irq(IRQ_TIMER0, &bcmring_timer_irq);
-
bcmring_clocksource_init();
- timer0_clockevent.mult =
- div_sc(1000000, NSEC_PER_SEC, timer0_clockevent.shift);
- timer0_clockevent.max_delta_ns =
- clockevent_delta2ns(0xffffffff, &timer0_clockevent);
- timer0_clockevent.min_delta_ns =
- clockevent_delta2ns(0xf, &timer0_clockevent);
-
- timer0_clockevent.cpumask = cpumask_of(0);
- clockevents_register_device(&timer0_clockevent);
+ sp804_clockevents_register(TIMER0_VA_BASE, IRQ_TIMER0, "timer0");
}
struct sys_timer bcmring_timer = {
.init = bcmring_init_timer,
};
+
+void __init bcmring_init_early(void)
+{
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
+}
diff --git a/arch/arm/mach-bcmring/core.h b/arch/arm/mach-bcmring/core.h
index b197ba48e36e..e0e02c48f9b1 100644
--- a/arch/arm/mach-bcmring/core.h
+++ b/arch/arm/mach-bcmring/core.h
@@ -25,6 +25,7 @@
void __init bcmring_amba_init(void);
void __init bcmring_map_io(void);
void __init bcmring_init_irq(void);
+void __init bcmring_init_early(void);
extern struct sys_timer bcmring_timer;
#endif
diff --git a/arch/arm/mach-davinci/cpufreq.c b/arch/arm/mach-davinci/cpufreq.c
index 0a95be1512bb..41669ecc1f91 100644
--- a/arch/arm/mach-davinci/cpufreq.c
+++ b/arch/arm/mach-davinci/cpufreq.c
@@ -94,9 +94,7 @@ static int davinci_target(struct cpufreq_policy *policy,
if (freqs.old == freqs.new)
return ret;
- cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER,
- dev_driver_string(cpufreq.dev),
- "transition: %u --> %u\n", freqs.old, freqs.new);
+ dev_dbg(&cpufreq.dev, "transition: %u --> %u\n", freqs.old, freqs.new);
ret = cpufreq_frequency_table_target(policy, pdata->freq_table,
freqs.new, relation, &idx);
diff --git a/arch/arm/mach-davinci/include/mach/memory.h b/arch/arm/mach-davinci/include/mach/memory.h
index 78822723f382..491249ef209c 100644
--- a/arch/arm/mach-davinci/include/mach/memory.h
+++ b/arch/arm/mach-davinci/include/mach/memory.h
@@ -41,27 +41,11 @@
*/
#define CONSISTENT_DMA_SIZE (14<<20)
-#ifndef __ASSEMBLY__
/*
* Restrict DMA-able region to workaround silicon bug. The bug
* restricts buffers available for DMA to video hardware to be
* below 128M
*/
-static inline void
-__arch_adjust_zones(unsigned long *size, unsigned long *holes)
-{
- unsigned int sz = (128<<20) >> PAGE_SHIFT;
-
- size[1] = size[0] - sz;
- size[0] = sz;
-}
-
-#define arch_adjust_zones(zone_size, holes) \
- if ((meminfo.bank[0].size >> 20) > 128) __arch_adjust_zones(zone_size, holes)
-
-#define ISA_DMA_THRESHOLD (PHYS_OFFSET + (128<<20) - 1)
-#define MAX_DMA_ADDRESS (PAGE_OFFSET + (128<<20))
-
-#endif
+#define ARM_DMA_ZONE_SIZE SZ_128M
#endif /* __ASM_ARCH_MEMORY_H */
diff --git a/arch/arm/mach-davinci/include/mach/uncompress.h b/arch/arm/mach-davinci/include/mach/uncompress.h
index 47723e8d75a4..78d80683cdc2 100644
--- a/arch/arm/mach-davinci/include/mach/uncompress.h
+++ b/arch/arm/mach-davinci/include/mach/uncompress.h
@@ -25,8 +25,7 @@
#include <mach/serial.h>
-static u32 *uart;
-static u32 *uart_info = (u32 *)(DAVINCI_UART_INFO);
+u32 *uart;
/* PORT_16C550A, in polled non-fifo mode */
static void putc(char c)
@@ -44,6 +43,8 @@ static inline void flush(void)
static inline void set_uart_info(u32 phys, void * __iomem virt)
{
+ u32 *uart_info = (u32 *)(DAVINCI_UART_INFO);
+
uart = (u32 *)phys;
uart_info[0] = phys;
uart_info[1] = (u32)virt;
diff --git a/arch/arm/mach-davinci/irq.c b/arch/arm/mach-davinci/irq.c
index e6269a6e0014..bfe68ec4e1a6 100644
--- a/arch/arm/mach-davinci/irq.c
+++ b/arch/arm/mach-davinci/irq.c
@@ -29,8 +29,6 @@
#include <mach/common.h>
#include <asm/mach/irq.h>
-#define IRQ_BIT(irq) ((irq) & 0x1f)
-
#define FIQ_REG0_OFFSET 0x0000
#define FIQ_REG1_OFFSET 0x0004
#define IRQ_REG0_OFFSET 0x0008
@@ -42,78 +40,33 @@
#define IRQ_INTPRI0_REG_OFFSET 0x0030
#define IRQ_INTPRI7_REG_OFFSET 0x004C
-static inline unsigned int davinci_irq_readl(int offset)
-{
- return __raw_readl(davinci_intc_base + offset);
-}
-
static inline void davinci_irq_writel(unsigned long value, int offset)
{
__raw_writel(value, davinci_intc_base + offset);
}
-/* Disable interrupt */
-static void davinci_mask_irq(struct irq_data *d)
+static __init void
+davinci_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num)
{
- unsigned int mask;
- u32 l;
-
- mask = 1 << IRQ_BIT(d->irq);
-
- if (d->irq > 31) {
- l = davinci_irq_readl(IRQ_ENT_REG1_OFFSET);
- l &= ~mask;
- davinci_irq_writel(l, IRQ_ENT_REG1_OFFSET);
- } else {
- l = davinci_irq_readl(IRQ_ENT_REG0_OFFSET);
- l &= ~mask;
- davinci_irq_writel(l, IRQ_ENT_REG0_OFFSET);
- }
-}
-
-/* Enable interrupt */
-static void davinci_unmask_irq(struct irq_data *d)
-{
- unsigned int mask;
- u32 l;
-
- mask = 1 << IRQ_BIT(d->irq);
-
- if (d->irq > 31) {
- l = davinci_irq_readl(IRQ_ENT_REG1_OFFSET);
- l |= mask;
- davinci_irq_writel(l, IRQ_ENT_REG1_OFFSET);
- } else {
- l = davinci_irq_readl(IRQ_ENT_REG0_OFFSET);
- l |= mask;
- davinci_irq_writel(l, IRQ_ENT_REG0_OFFSET);
- }
+ struct irq_chip_generic *gc;
+ struct irq_chip_type *ct;
+
+ gc = irq_alloc_generic_chip("AINTC", 1, irq_start, base, handle_edge_irq);
+ ct = gc->chip_types;
+ ct->chip.irq_ack = irq_gc_ack;
+ ct->chip.irq_mask = irq_gc_mask_clr_bit;
+ ct->chip.irq_unmask = irq_gc_mask_set_bit;
+
+ ct->regs.ack = IRQ_REG0_OFFSET;
+ ct->regs.mask = IRQ_ENT_REG0_OFFSET;
+ irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
+ IRQ_NOREQUEST | IRQ_NOPROBE, 0);
}
-/* EOI interrupt */
-static void davinci_ack_irq(struct irq_data *d)
-{
- unsigned int mask;
-
- mask = 1 << IRQ_BIT(d->irq);
-
- if (d->irq > 31)
- davinci_irq_writel(mask, IRQ_REG1_OFFSET);
- else
- davinci_irq_writel(mask, IRQ_REG0_OFFSET);
-}
-
-static struct irq_chip davinci_irq_chip_0 = {
- .name = "AINTC",
- .irq_ack = davinci_ack_irq,
- .irq_mask = davinci_mask_irq,
- .irq_unmask = davinci_unmask_irq,
-};
-
/* ARM Interrupt Controller Initialization */
void __init davinci_irq_init(void)
{
- unsigned i;
+ unsigned i, j;
const u8 *davinci_def_priorities = davinci_soc_info.intc_irq_prios;
davinci_intc_type = DAVINCI_INTC_TYPE_AINTC;
@@ -144,7 +97,6 @@ void __init davinci_irq_init(void)
davinci_irq_writel(~0x0, IRQ_REG1_OFFSET);
for (i = IRQ_INTPRI0_REG_OFFSET; i <= IRQ_INTPRI7_REG_OFFSET; i += 4) {
- unsigned j;
u32 pri;
for (j = 0, pri = 0; j < 32; j += 4, davinci_def_priorities++)
@@ -152,13 +104,8 @@ void __init davinci_irq_init(void)
davinci_irq_writel(pri, i);
}
- /* set up genirq dispatch for ARM INTC */
- for (i = 0; i < davinci_soc_info.intc_irq_num; i++) {
- irq_set_chip(i, &davinci_irq_chip_0);
- set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
- if (i != IRQ_TINT1_TINT34)
- irq_set_handler(i, handle_edge_irq);
- else
- irq_set_handler(i, handle_level_irq);
- }
+ for (i = 0, j = 0; i < davinci_soc_info.intc_irq_num; i += 32, j += 0x04)
+ davinci_alloc_gc(davinci_intc_base + j, i, 32);
+
+ irq_set_handler(IRQ_TINT1_TINT34, handle_level_irq);
}
diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c
index e06a88f1f81d..5ed51b84c1b2 100644
--- a/arch/arm/mach-dove/common.c
+++ b/arch/arm/mach-dove/common.c
@@ -16,10 +16,8 @@
#include <linux/serial_8250.h>
#include <linux/clk.h>
#include <linux/mbus.h>
-#include <linux/mv643xx_eth.h>
-#include <linux/mv643xx_i2c.h>
#include <linux/ata_platform.h>
-#include <linux/spi/orion_spi.h>
+#include <linux/serial_8250.h>
#include <linux/gpio.h>
#include <asm/page.h>
#include <asm/setup.h>
@@ -32,11 +30,12 @@
#include <mach/bridge-regs.h>
#include <asm/mach/arch.h>
#include <linux/irq.h>
-#include <plat/mv_xor.h>
-#include <plat/ehci-orion.h>
#include <plat/time.h>
+#include <plat/common.h>
#include "common.h"
+static int get_tclk(void);
+
/*****************************************************************************
* I/O Address Mapping
****************************************************************************/
@@ -70,463 +69,106 @@ void __init dove_map_io(void)
}
/*****************************************************************************
- * EHCI
- ****************************************************************************/
-static struct orion_ehci_data dove_ehci_data = {
- .dram = &dove_mbus_dram_info,
- .phy_version = EHCI_PHY_NA,
-};
-
-static u64 ehci_dmamask = DMA_BIT_MASK(32);
-
-/*****************************************************************************
* EHCI0
****************************************************************************/
-static struct resource dove_ehci0_resources[] = {
- {
- .start = DOVE_USB0_PHYS_BASE,
- .end = DOVE_USB0_PHYS_BASE + SZ_4K - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_DOVE_USB0,
- .end = IRQ_DOVE_USB0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device dove_ehci0 = {
- .name = "orion-ehci",
- .id = 0,
- .dev = {
- .dma_mask = &ehci_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &dove_ehci_data,
- },
- .resource = dove_ehci0_resources,
- .num_resources = ARRAY_SIZE(dove_ehci0_resources),
-};
-
void __init dove_ehci0_init(void)
{
- platform_device_register(&dove_ehci0);
+ orion_ehci_init(&dove_mbus_dram_info,
+ DOVE_USB0_PHYS_BASE, IRQ_DOVE_USB0);
}
/*****************************************************************************
* EHCI1
****************************************************************************/
-static struct resource dove_ehci1_resources[] = {
- {
- .start = DOVE_USB1_PHYS_BASE,
- .end = DOVE_USB1_PHYS_BASE + SZ_4K - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_DOVE_USB1,
- .end = IRQ_DOVE_USB1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device dove_ehci1 = {
- .name = "orion-ehci",
- .id = 1,
- .dev = {
- .dma_mask = &ehci_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &dove_ehci_data,
- },
- .resource = dove_ehci1_resources,
- .num_resources = ARRAY_SIZE(dove_ehci1_resources),
-};
-
void __init dove_ehci1_init(void)
{
- platform_device_register(&dove_ehci1);
+ orion_ehci_1_init(&dove_mbus_dram_info,
+ DOVE_USB1_PHYS_BASE, IRQ_DOVE_USB1);
}
/*****************************************************************************
* GE00
****************************************************************************/
-struct mv643xx_eth_shared_platform_data dove_ge00_shared_data = {
- .t_clk = 0,
- .dram = &dove_mbus_dram_info,
-};
-
-static struct resource dove_ge00_shared_resources[] = {
- {
- .name = "ge00 base",
- .start = DOVE_GE00_PHYS_BASE + 0x2000,
- .end = DOVE_GE00_PHYS_BASE + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device dove_ge00_shared = {
- .name = MV643XX_ETH_SHARED_NAME,
- .id = 0,
- .dev = {
- .platform_data = &dove_ge00_shared_data,
- },
- .num_resources = 1,
- .resource = dove_ge00_shared_resources,
-};
-
-static struct resource dove_ge00_resources[] = {
- {
- .name = "ge00 irq",
- .start = IRQ_DOVE_GE00_SUM,
- .end = IRQ_DOVE_GE00_SUM,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device dove_ge00 = {
- .name = MV643XX_ETH_NAME,
- .id = 0,
- .num_resources = 1,
- .resource = dove_ge00_resources,
- .dev = {
- .coherent_dma_mask = 0xffffffff,
- },
-};
-
void __init dove_ge00_init(struct mv643xx_eth_platform_data *eth_data)
{
- eth_data->shared = &dove_ge00_shared;
- dove_ge00.dev.platform_data = eth_data;
-
- platform_device_register(&dove_ge00_shared);
- platform_device_register(&dove_ge00);
+ orion_ge00_init(eth_data, &dove_mbus_dram_info,
+ DOVE_GE00_PHYS_BASE, IRQ_DOVE_GE00_SUM,
+ 0, get_tclk());
}
/*****************************************************************************
* SoC RTC
****************************************************************************/
-static struct resource dove_rtc_resource[] = {
- {
- .start = DOVE_RTC_PHYS_BASE,
- .end = DOVE_RTC_PHYS_BASE + 32 - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_DOVE_RTC,
- .flags = IORESOURCE_IRQ,
- }
-};
-
void __init dove_rtc_init(void)
{
- platform_device_register_simple("rtc-mv", -1, dove_rtc_resource, 2);
+ orion_rtc_init(DOVE_RTC_PHYS_BASE, IRQ_DOVE_RTC);
}
/*****************************************************************************
* SATA
****************************************************************************/
-static struct resource dove_sata_resources[] = {
- {
- .name = "sata base",
- .start = DOVE_SATA_PHYS_BASE,
- .end = DOVE_SATA_PHYS_BASE + 0x5000 - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .name = "sata irq",
- .start = IRQ_DOVE_SATA,
- .end = IRQ_DOVE_SATA,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device dove_sata = {
- .name = "sata_mv",
- .id = 0,
- .dev = {
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .num_resources = ARRAY_SIZE(dove_sata_resources),
- .resource = dove_sata_resources,
-};
-
void __init dove_sata_init(struct mv_sata_platform_data *sata_data)
{
- sata_data->dram = &dove_mbus_dram_info;
- dove_sata.dev.platform_data = sata_data;
- platform_device_register(&dove_sata);
+ orion_sata_init(sata_data, &dove_mbus_dram_info,
+ DOVE_SATA_PHYS_BASE, IRQ_DOVE_SATA);
+
}
/*****************************************************************************
* UART0
****************************************************************************/
-static struct plat_serial8250_port dove_uart0_data[] = {
- {
- .mapbase = DOVE_UART0_PHYS_BASE,
- .membase = (char *)DOVE_UART0_VIRT_BASE,
- .irq = IRQ_DOVE_UART_0,
- .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = 0,
- }, {
- },
-};
-
-static struct resource dove_uart0_resources[] = {
- {
- .start = DOVE_UART0_PHYS_BASE,
- .end = DOVE_UART0_PHYS_BASE + SZ_256 - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_DOVE_UART_0,
- .end = IRQ_DOVE_UART_0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device dove_uart0 = {
- .name = "serial8250",
- .id = 0,
- .dev = {
- .platform_data = dove_uart0_data,
- },
- .resource = dove_uart0_resources,
- .num_resources = ARRAY_SIZE(dove_uart0_resources),
-};
-
void __init dove_uart0_init(void)
{
- platform_device_register(&dove_uart0);
+ orion_uart0_init(DOVE_UART0_VIRT_BASE, DOVE_UART0_PHYS_BASE,
+ IRQ_DOVE_UART_0, get_tclk());
}
/*****************************************************************************
* UART1
****************************************************************************/
-static struct plat_serial8250_port dove_uart1_data[] = {
- {
- .mapbase = DOVE_UART1_PHYS_BASE,
- .membase = (char *)DOVE_UART1_VIRT_BASE,
- .irq = IRQ_DOVE_UART_1,
- .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = 0,
- }, {
- },
-};
-
-static struct resource dove_uart1_resources[] = {
- {
- .start = DOVE_UART1_PHYS_BASE,
- .end = DOVE_UART1_PHYS_BASE + SZ_256 - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_DOVE_UART_1,
- .end = IRQ_DOVE_UART_1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device dove_uart1 = {
- .name = "serial8250",
- .id = 1,
- .dev = {
- .platform_data = dove_uart1_data,
- },
- .resource = dove_uart1_resources,
- .num_resources = ARRAY_SIZE(dove_uart1_resources),
-};
-
void __init dove_uart1_init(void)
{
- platform_device_register(&dove_uart1);
+ orion_uart1_init(DOVE_UART1_VIRT_BASE, DOVE_UART1_PHYS_BASE,
+ IRQ_DOVE_UART_1, get_tclk());
}
/*****************************************************************************
* UART2
****************************************************************************/
-static struct plat_serial8250_port dove_uart2_data[] = {
- {
- .mapbase = DOVE_UART2_PHYS_BASE,
- .membase = (char *)DOVE_UART2_VIRT_BASE,
- .irq = IRQ_DOVE_UART_2,
- .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = 0,
- }, {
- },
-};
-
-static struct resource dove_uart2_resources[] = {
- {
- .start = DOVE_UART2_PHYS_BASE,
- .end = DOVE_UART2_PHYS_BASE + SZ_256 - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_DOVE_UART_2,
- .end = IRQ_DOVE_UART_2,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device dove_uart2 = {
- .name = "serial8250",
- .id = 2,
- .dev = {
- .platform_data = dove_uart2_data,
- },
- .resource = dove_uart2_resources,
- .num_resources = ARRAY_SIZE(dove_uart2_resources),
-};
-
void __init dove_uart2_init(void)
{
- platform_device_register(&dove_uart2);
+ orion_uart2_init(DOVE_UART2_VIRT_BASE, DOVE_UART2_PHYS_BASE,
+ IRQ_DOVE_UART_2, get_tclk());
}
/*****************************************************************************
* UART3
****************************************************************************/
-static struct plat_serial8250_port dove_uart3_data[] = {
- {
- .mapbase = DOVE_UART3_PHYS_BASE,
- .membase = (char *)DOVE_UART3_VIRT_BASE,
- .irq = IRQ_DOVE_UART_3,
- .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = 0,
- }, {
- },
-};
-
-static struct resource dove_uart3_resources[] = {
- {
- .start = DOVE_UART3_PHYS_BASE,
- .end = DOVE_UART3_PHYS_BASE + SZ_256 - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_DOVE_UART_3,
- .end = IRQ_DOVE_UART_3,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device dove_uart3 = {
- .name = "serial8250",
- .id = 3,
- .dev = {
- .platform_data = dove_uart3_data,
- },
- .resource = dove_uart3_resources,
- .num_resources = ARRAY_SIZE(dove_uart3_resources),
-};
-
void __init dove_uart3_init(void)
{
- platform_device_register(&dove_uart3);
+ orion_uart3_init(DOVE_UART3_VIRT_BASE, DOVE_UART3_PHYS_BASE,
+ IRQ_DOVE_UART_3, get_tclk());
}
/*****************************************************************************
- * SPI0
+ * SPI
****************************************************************************/
-static struct orion_spi_info dove_spi0_data = {
- .tclk = 0,
-};
-
-static struct resource dove_spi0_resources[] = {
- {
- .start = DOVE_SPI0_PHYS_BASE,
- .end = DOVE_SPI0_PHYS_BASE + SZ_512 - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_DOVE_SPI0,
- .end = IRQ_DOVE_SPI0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device dove_spi0 = {
- .name = "orion_spi",
- .id = 0,
- .resource = dove_spi0_resources,
- .dev = {
- .platform_data = &dove_spi0_data,
- },
- .num_resources = ARRAY_SIZE(dove_spi0_resources),
-};
-
void __init dove_spi0_init(void)
{
- platform_device_register(&dove_spi0);
+ orion_spi_init(DOVE_SPI0_PHYS_BASE, get_tclk());
}
-/*****************************************************************************
- * SPI1
- ****************************************************************************/
-static struct orion_spi_info dove_spi1_data = {
- .tclk = 0,
-};
-
-static struct resource dove_spi1_resources[] = {
- {
- .start = DOVE_SPI1_PHYS_BASE,
- .end = DOVE_SPI1_PHYS_BASE + SZ_512 - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_DOVE_SPI1,
- .end = IRQ_DOVE_SPI1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device dove_spi1 = {
- .name = "orion_spi",
- .id = 1,
- .resource = dove_spi1_resources,
- .dev = {
- .platform_data = &dove_spi1_data,
- },
- .num_resources = ARRAY_SIZE(dove_spi1_resources),
-};
-
void __init dove_spi1_init(void)
{
- platform_device_register(&dove_spi1);
+ orion_spi_init(DOVE_SPI1_PHYS_BASE, get_tclk());
}
/*****************************************************************************
* I2C
****************************************************************************/
-static struct mv64xxx_i2c_pdata dove_i2c_data = {
- .freq_m = 10, /* assumes 166 MHz TCLK gets 94.3kHz */
- .freq_n = 3,
- .timeout = 1000, /* Default timeout of 1 second */
-};
-
-static struct resource dove_i2c_resources[] = {
- {
- .name = "i2c base",
- .start = DOVE_I2C_PHYS_BASE,
- .end = DOVE_I2C_PHYS_BASE + 0x20 - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .name = "i2c irq",
- .start = IRQ_DOVE_I2C,
- .end = IRQ_DOVE_I2C,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device dove_i2c = {
- .name = MV64XXX_I2C_CTLR_NAME,
- .id = 0,
- .num_resources = ARRAY_SIZE(dove_i2c_resources),
- .resource = dove_i2c_resources,
- .dev = {
- .platform_data = &dove_i2c_data,
- },
-};
-
void __init dove_i2c_init(void)
{
- platform_device_register(&dove_i2c);
+ orion_i2c_init(DOVE_I2C_PHYS_BASE, IRQ_DOVE_I2C, 10);
}
/*****************************************************************************
@@ -554,208 +196,22 @@ struct sys_timer dove_timer = {
};
/*****************************************************************************
- * XOR
- ****************************************************************************/
-static struct mv_xor_platform_shared_data dove_xor_shared_data = {
- .dram = &dove_mbus_dram_info,
-};
-
-/*****************************************************************************
* XOR 0
****************************************************************************/
-static u64 dove_xor0_dmamask = DMA_BIT_MASK(32);
-
-static struct resource dove_xor0_shared_resources[] = {
- {
- .name = "xor 0 low",
- .start = DOVE_XOR0_PHYS_BASE,
- .end = DOVE_XOR0_PHYS_BASE + 0xff,
- .flags = IORESOURCE_MEM,
- }, {
- .name = "xor 0 high",
- .start = DOVE_XOR0_HIGH_PHYS_BASE,
- .end = DOVE_XOR0_HIGH_PHYS_BASE + 0xff,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device dove_xor0_shared = {
- .name = MV_XOR_SHARED_NAME,
- .id = 0,
- .dev = {
- .platform_data = &dove_xor_shared_data,
- },
- .num_resources = ARRAY_SIZE(dove_xor0_shared_resources),
- .resource = dove_xor0_shared_resources,
-};
-
-static struct resource dove_xor00_resources[] = {
- [0] = {
- .start = IRQ_DOVE_XOR_00,
- .end = IRQ_DOVE_XOR_00,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct mv_xor_platform_data dove_xor00_data = {
- .shared = &dove_xor0_shared,
- .hw_id = 0,
- .pool_size = PAGE_SIZE,
-};
-
-static struct platform_device dove_xor00_channel = {
- .name = MV_XOR_NAME,
- .id = 0,
- .num_resources = ARRAY_SIZE(dove_xor00_resources),
- .resource = dove_xor00_resources,
- .dev = {
- .dma_mask = &dove_xor0_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(64),
- .platform_data = &dove_xor00_data,
- },
-};
-
-static struct resource dove_xor01_resources[] = {
- [0] = {
- .start = IRQ_DOVE_XOR_01,
- .end = IRQ_DOVE_XOR_01,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct mv_xor_platform_data dove_xor01_data = {
- .shared = &dove_xor0_shared,
- .hw_id = 1,
- .pool_size = PAGE_SIZE,
-};
-
-static struct platform_device dove_xor01_channel = {
- .name = MV_XOR_NAME,
- .id = 1,
- .num_resources = ARRAY_SIZE(dove_xor01_resources),
- .resource = dove_xor01_resources,
- .dev = {
- .dma_mask = &dove_xor0_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(64),
- .platform_data = &dove_xor01_data,
- },
-};
-
void __init dove_xor0_init(void)
{
- platform_device_register(&dove_xor0_shared);
-
- /*
- * two engines can't do memset simultaneously, this limitation
- * satisfied by removing memset support from one of the engines.
- */
- dma_cap_set(DMA_MEMCPY, dove_xor00_data.cap_mask);
- dma_cap_set(DMA_XOR, dove_xor00_data.cap_mask);
- platform_device_register(&dove_xor00_channel);
-
- dma_cap_set(DMA_MEMCPY, dove_xor01_data.cap_mask);
- dma_cap_set(DMA_MEMSET, dove_xor01_data.cap_mask);
- dma_cap_set(DMA_XOR, dove_xor01_data.cap_mask);
- platform_device_register(&dove_xor01_channel);
+ orion_xor0_init(&dove_mbus_dram_info,
+ DOVE_XOR0_PHYS_BASE, DOVE_XOR0_HIGH_PHYS_BASE,
+ IRQ_DOVE_XOR_00, IRQ_DOVE_XOR_01);
}
/*****************************************************************************
* XOR 1
****************************************************************************/
-static u64 dove_xor1_dmamask = DMA_BIT_MASK(32);
-
-static struct resource dove_xor1_shared_resources[] = {
- {
- .name = "xor 0 low",
- .start = DOVE_XOR1_PHYS_BASE,
- .end = DOVE_XOR1_PHYS_BASE + 0xff,
- .flags = IORESOURCE_MEM,
- }, {
- .name = "xor 0 high",
- .start = DOVE_XOR1_HIGH_PHYS_BASE,
- .end = DOVE_XOR1_HIGH_PHYS_BASE + 0xff,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device dove_xor1_shared = {
- .name = MV_XOR_SHARED_NAME,
- .id = 1,
- .dev = {
- .platform_data = &dove_xor_shared_data,
- },
- .num_resources = ARRAY_SIZE(dove_xor1_shared_resources),
- .resource = dove_xor1_shared_resources,
-};
-
-static struct resource dove_xor10_resources[] = {
- [0] = {
- .start = IRQ_DOVE_XOR_10,
- .end = IRQ_DOVE_XOR_10,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct mv_xor_platform_data dove_xor10_data = {
- .shared = &dove_xor1_shared,
- .hw_id = 0,
- .pool_size = PAGE_SIZE,
-};
-
-static struct platform_device dove_xor10_channel = {
- .name = MV_XOR_NAME,
- .id = 2,
- .num_resources = ARRAY_SIZE(dove_xor10_resources),
- .resource = dove_xor10_resources,
- .dev = {
- .dma_mask = &dove_xor1_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(64),
- .platform_data = &dove_xor10_data,
- },
-};
-
-static struct resource dove_xor11_resources[] = {
- [0] = {
- .start = IRQ_DOVE_XOR_11,
- .end = IRQ_DOVE_XOR_11,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct mv_xor_platform_data dove_xor11_data = {
- .shared = &dove_xor1_shared,
- .hw_id = 1,
- .pool_size = PAGE_SIZE,
-};
-
-static struct platform_device dove_xor11_channel = {
- .name = MV_XOR_NAME,
- .id = 3,
- .num_resources = ARRAY_SIZE(dove_xor11_resources),
- .resource = dove_xor11_resources,
- .dev = {
- .dma_mask = &dove_xor1_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(64),
- .platform_data = &dove_xor11_data,
- },
-};
-
void __init dove_xor1_init(void)
{
- platform_device_register(&dove_xor1_shared);
-
- /*
- * two engines can't do memset simultaneously, this limitation
- * satisfied by removing memset support from one of the engines.
- */
- dma_cap_set(DMA_MEMCPY, dove_xor10_data.cap_mask);
- dma_cap_set(DMA_XOR, dove_xor10_data.cap_mask);
- platform_device_register(&dove_xor10_channel);
-
- dma_cap_set(DMA_MEMCPY, dove_xor11_data.cap_mask);
- dma_cap_set(DMA_MEMSET, dove_xor11_data.cap_mask);
- dma_cap_set(DMA_XOR, dove_xor11_data.cap_mask);
- platform_device_register(&dove_xor11_channel);
+ orion_xor1_init(DOVE_XOR1_PHYS_BASE, DOVE_XOR1_HIGH_PHYS_BASE,
+ IRQ_DOVE_XOR_10, IRQ_DOVE_XOR_11);
}
/*****************************************************************************
@@ -833,14 +289,6 @@ void __init dove_init(void)
#endif
dove_setup_cpu_mbus();
- dove_ge00_shared_data.t_clk = tclk;
- dove_uart0_data[0].uartclk = tclk;
- dove_uart1_data[0].uartclk = tclk;
- dove_uart2_data[0].uartclk = tclk;
- dove_uart3_data[0].uartclk = tclk;
- dove_spi0_data.tclk = tclk;
- dove_spi1_data.tclk = tclk;
-
/* internal devices that every board has */
dove_rtc_init();
dove_xor0_init();
diff --git a/arch/arm/mach-dove/mpp.c b/arch/arm/mach-dove/mpp.c
index c66c76346904..51e0e411c9cb 100644
--- a/arch/arm/mach-dove/mpp.c
+++ b/arch/arm/mach-dove/mpp.c
@@ -11,24 +11,17 @@
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <linux/io.h>
-
+#include <plat/mpp.h>
#include <mach/dove.h>
-
#include "mpp.h"
-#define MPP_NR_REGS 4
-#define MPP_CTRL(i) ((i) == 3 ? \
- DOVE_MPP_CTRL4_VIRT_BASE : \
- DOVE_MPP_VIRT_BASE + (i) * 4)
-#define PMU_SIG_REGS 2
-#define PMU_SIG_CTRL(i) (DOVE_PMU_SIG_CTRL + (i) * 4)
-
struct dove_mpp_grp {
int start;
int end;
};
-static struct dove_mpp_grp dove_mpp_grp[] = {
+/* Map a group to a range of GPIO pins in that group */
+static const struct dove_mpp_grp dove_mpp_grp[] = {
[MPP_24_39] = {
.start = 24,
.end = 39,
@@ -38,8 +31,8 @@ static struct dove_mpp_grp dove_mpp_grp[] = {
.end = 45,
},
[MPP_46_51] = {
- .start = 40,
- .end = 45,
+ .start = 46,
+ .end = 51,
},
[MPP_58_61] = {
.start = 58,
@@ -51,6 +44,8 @@ static struct dove_mpp_grp dove_mpp_grp[] = {
},
};
+/* Enable gpio for a range of pins. mode should be a combination of
+ GPIO_OUTPUT_OK | GPIO_INPUT_OK */
static void dove_mpp_gpio_mode(int start, int end, int gpio_mode)
{
int i;
@@ -59,24 +54,17 @@ static void dove_mpp_gpio_mode(int start, int end, int gpio_mode)
orion_gpio_set_valid(i, gpio_mode);
}
+/* Dump all the extra MPP registers. The platform code will dump the
+ registers for pins 0-23. */
static void dove_mpp_dump_regs(void)
{
-#ifdef DEBUG
- int i;
+ pr_debug("PMU_CTRL4_CTRL: %08x\n",
+ readl(DOVE_MPP_CTRL4_VIRT_BASE));
- pr_debug("MPP_CTRL regs:");
- for (i = 0; i < MPP_NR_REGS; i++)
- printk(" %08x", readl(MPP_CTRL(i)));
- printk("\n");
+ pr_debug("PMU_MPP_GENERAL_CTRL: %08x\n",
+ readl(DOVE_PMU_MPP_GENERAL_CTRL));
- pr_debug("PMU_SIG_CTRL regs:");
- for (i = 0; i < PMU_SIG_REGS; i++)
- printk(" %08x", readl(PMU_SIG_CTRL(i)));
- printk("\n");
-
- pr_debug("PMU_MPP_GENERAL_CTRL: %08x\n", readl(DOVE_PMU_MPP_GENERAL_CTRL));
pr_debug("MPP_GENERAL: %08x\n", readl(DOVE_MPP_GENERAL_VIRT_BASE));
-#endif
}
static void dove_mpp_cfg_nfc(int sel)
@@ -92,7 +80,7 @@ static void dove_mpp_cfg_nfc(int sel)
static void dove_mpp_cfg_au1(int sel)
{
- u32 mpp_ctrl4 = readl(DOVE_MPP_CTRL4_VIRT_BASE);
+ u32 mpp_ctrl4 = readl(DOVE_MPP_CTRL4_VIRT_BASE);
u32 ssp_ctrl1 = readl(DOVE_SSP_CTRL_STATUS_1);
u32 mpp_gen_ctrl = readl(DOVE_MPP_GENERAL_VIRT_BASE);
u32 global_cfg_2 = readl(DOVE_GLOBAL_CONFIG_2);
@@ -128,82 +116,46 @@ static void dove_mpp_cfg_au1(int sel)
writel(global_cfg_2, DOVE_GLOBAL_CONFIG_2);
}
-static void dove_mpp_conf_grp(int num, int sel, u32 *mpp_ctrl)
-{
- int start = dove_mpp_grp[num].start;
- int end = dove_mpp_grp[num].end;
- int gpio_mode = sel ? GPIO_OUTPUT_OK | GPIO_INPUT_OK : 0;
-
- *mpp_ctrl &= ~(0x1 << num);
- *mpp_ctrl |= sel << num;
-
- dove_mpp_gpio_mode(start, end, gpio_mode);
-}
-
-void __init dove_mpp_conf(unsigned int *mpp_list)
+/* Configure the group registers, enabling GPIO if sel indicates the
+ pin is to be used for GPIO */
+static void dove_mpp_conf_grp(unsigned int *mpp_grp_list)
{
- u32 mpp_ctrl[MPP_NR_REGS];
- u32 pmu_mpp_ctrl = 0;
- u32 pmu_sig_ctrl[PMU_SIG_REGS];
- int i;
-
- for (i = 0; i < MPP_NR_REGS; i++)
- mpp_ctrl[i] = readl(MPP_CTRL(i));
-
- for (i = 0; i < PMU_SIG_REGS; i++)
- pmu_sig_ctrl[i] = readl(PMU_SIG_CTRL(i));
-
- pmu_mpp_ctrl = readl(DOVE_PMU_MPP_GENERAL_CTRL);
+ u32 mpp_ctrl4 = readl(DOVE_MPP_CTRL4_VIRT_BASE);
+ int gpio_mode;
- dove_mpp_dump_regs();
-
- for ( ; *mpp_list != MPP_END; mpp_list++) {
- unsigned int num = MPP_NUM(*mpp_list);
- unsigned int sel = MPP_SEL(*mpp_list);
- int shift, gpio_mode;
-
- if (num > MPP_MAX) {
- pr_err("dove: invalid MPP number (%u)\n", num);
- continue;
- }
-
- if (*mpp_list & MPP_NFC_MASK) {
- dove_mpp_cfg_nfc(sel);
- continue;
- }
+ for ( ; *mpp_grp_list; mpp_grp_list++) {
+ unsigned int num = MPP_NUM(*mpp_grp_list);
+ unsigned int sel = MPP_SEL(*mpp_grp_list);
- if (*mpp_list & MPP_AU1_MASK) {
- dove_mpp_cfg_au1(sel);
+ if (num > MPP_GRP_MAX) {
+ pr_err("dove: invalid MPP GRP number (%u)\n", num);
continue;
}
- if (*mpp_list & MPP_GRP_MASK) {
- dove_mpp_conf_grp(num, sel, &mpp_ctrl[3]);
- continue;
- }
-
- shift = (num & 7) << 2;
- if (*mpp_list & MPP_PMU_MASK) {
- pmu_mpp_ctrl |= (0x1 << num);
- pmu_sig_ctrl[num / 8] &= ~(0xf << shift);
- pmu_sig_ctrl[num / 8] |= 0xf << shift;
- gpio_mode = 0;
- } else {
- mpp_ctrl[num / 8] &= ~(0xf << shift);
- mpp_ctrl[num / 8] |= sel << shift;
- gpio_mode = GPIO_OUTPUT_OK | GPIO_INPUT_OK;
- }
+ mpp_ctrl4 &= ~(0x1 << num);
+ mpp_ctrl4 |= sel << num;
- orion_gpio_set_valid(num, gpio_mode);
+ gpio_mode = sel ? GPIO_OUTPUT_OK | GPIO_INPUT_OK : 0;
+ dove_mpp_gpio_mode(dove_mpp_grp[num].start,
+ dove_mpp_grp[num].end, gpio_mode);
}
+ writel(mpp_ctrl4, DOVE_MPP_CTRL4_VIRT_BASE);
+}
- for (i = 0; i < MPP_NR_REGS; i++)
- writel(mpp_ctrl[i], MPP_CTRL(i));
+/* Configure the various MPP pins on Dove */
+void __init dove_mpp_conf(unsigned int *mpp_list,
+ unsigned int *mpp_grp_list,
+ unsigned int grp_au1_52_57,
+ unsigned int grp_nfc_64_71)
+{
+ dove_mpp_dump_regs();
- for (i = 0; i < PMU_SIG_REGS; i++)
- writel(pmu_sig_ctrl[i], PMU_SIG_CTRL(i));
+ /* Use platform code for pins 0-23 */
+ orion_mpp_conf(mpp_list, 0, MPP_MAX, DOVE_MPP_VIRT_BASE);
- writel(pmu_mpp_ctrl, DOVE_PMU_MPP_GENERAL_CTRL);
+ dove_mpp_conf_grp(mpp_grp_list);
+ dove_mpp_cfg_au1(grp_au1_52_57);
+ dove_mpp_cfg_nfc(grp_nfc_64_71);
dove_mpp_dump_regs();
}
diff --git a/arch/arm/mach-dove/mpp.h b/arch/arm/mach-dove/mpp.h
index 2a43ce413b15..fbec7c52bfac 100644
--- a/arch/arm/mach-dove/mpp.h
+++ b/arch/arm/mach-dove/mpp.h
@@ -1,178 +1,150 @@
#ifndef __ARCH_DOVE_MPP_CODED_H
#define __ARCH_DOVE_MPP_CODED_H
-#define MPP(_num, _mode, _pmu, _grp, _au1, _nfc) ( \
-/* MPP/group number */ ((_num) & 0xff) | \
-/* MPP select value */ (((_mode) & 0xf) << 8) | \
-/* MPP PMU */ ((!!(_pmu)) << 12) | \
-/* group flag */ ((!!(_grp)) << 13) | \
-/* AU1 flag */ ((!!(_au1)) << 14) | \
-/* NFCE flag */ ((!!(_nfc)) << 15))
-
-#define MPP_MAX 71
-
-#define MPP_NUM(x) ((x) & 0xff)
-#define MPP_SEL(x) (((x) >> 8) & 0xf)
-
-#define MPP_PMU_MASK MPP(0, 0x0, 1, 0, 0, 0)
-#define MPP_GRP_MASK MPP(0, 0x0, 0, 1, 0, 0)
-#define MPP_AU1_MASK MPP(0, 0x0, 0, 0, 1, 0)
-#define MPP_NFC_MASK MPP(0, 0x0, 0, 0, 0, 1)
-
-#define MPP_END MPP(0xff, 0xf, 1, 1, 1, 1)
-
-#define MPP_PMU_DRIVE_0 0x1
-#define MPP_PMU_DRIVE_1 0x2
-#define MPP_PMU_SDI 0x3
-#define MPP_PMU_CPU_PWRDWN 0x4
-#define MPP_PMU_STBY_PWRDWN 0x5
-#define MPP_PMU_CORE_PWR_GOOD 0x8
-#define MPP_PMU_BAT_FAULT 0xa
-#define MPP_PMU_EXT0_WU 0xb
-#define MPP_PMU_EXT1_WU 0xc
-#define MPP_PMU_EXT2_WU 0xd
-#define MPP_PMU_BLINK 0xe
-#define MPP_PMU(_num, _mode) MPP((_num), MPP_PMU_##_mode, 1, 0, 0, 0)
-
-#define MPP_PIN(_num, _mode) MPP((_num), (_mode), 0, 0, 0, 0)
-#define MPP_GRP(_grp, _mode) MPP((_grp), (_mode), 0, 1, 0, 0)
-#define MPP_GRP_AU1(_mode) MPP(0, (_mode), 0, 0, 1, 0)
-#define MPP_GRP_NFC(_mode) MPP(0, (_mode), 0, 0, 0, 1)
-
-#define MPP0_GPIO0 MPP_PIN(0, 0x0)
-#define MPP0_UA2_RTSn MPP_PIN(0, 0x2)
-#define MPP0_SDIO0_CD MPP_PIN(0, 0x3)
-#define MPP0_LCD0_PWM MPP_PIN(0, 0xf)
-
-#define MPP1_GPIO1 MPP_PIN(1, 0x0)
-#define MPP1_UA2_CTSn MPP_PIN(1, 0x2)
-#define MPP1_SDIO0_WP MPP_PIN(1, 0x3)
-#define MPP1_LCD1_PWM MPP_PIN(1, 0xf)
-
-#define MPP2_GPIO2 MPP_PIN(2, 0x0)
-#define MPP2_SATA_PRESENT MPP_PIN(2, 0x1)
-#define MPP2_UA2_TXD MPP_PIN(2, 0x2)
-#define MPP2_SDIO0_BUS_POWER MPP_PIN(2, 0x3)
-#define MPP2_UA_RTSn1 MPP_PIN(2, 0x4)
-
-#define MPP3_GPIO3 MPP_PIN(3, 0x0)
-#define MPP3_SATA_ACT MPP_PIN(3, 0x1)
-#define MPP3_UA2_RXD MPP_PIN(3, 0x2)
-#define MPP3_SDIO0_LED_CTRL MPP_PIN(3, 0x3)
-#define MPP3_UA_CTSn1 MPP_PIN(3, 0x4)
-#define MPP3_SPI_LCD_CS1 MPP_PIN(3, 0xf)
-
-#define MPP4_GPIO4 MPP_PIN(4, 0x0)
-#define MPP4_UA3_RTSn MPP_PIN(4, 0x2)
-#define MPP4_SDIO1_CD MPP_PIN(4, 0x3)
-#define MPP4_SPI_1_MISO MPP_PIN(4, 0x4)
-
-#define MPP5_GPIO5 MPP_PIN(5, 0x0)
-#define MPP5_UA3_CTSn MPP_PIN(5, 0x2)
-#define MPP5_SDIO1_WP MPP_PIN(5, 0x3)
-#define MPP5_SPI_1_CS MPP_PIN(5, 0x4)
-
-#define MPP6_GPIO6 MPP_PIN(6, 0x0)
-#define MPP6_UA3_TXD MPP_PIN(6, 0x2)
-#define MPP6_SDIO1_BUS_POWER MPP_PIN(6, 0x3)
-#define MPP6_SPI_1_MOSI MPP_PIN(6, 0x4)
-
-#define MPP7_GPIO7 MPP_PIN(7, 0x0)
-#define MPP7_UA3_RXD MPP_PIN(7, 0x2)
-#define MPP7_SDIO1_LED_CTRL MPP_PIN(7, 0x3)
-#define MPP7_SPI_1_SCK MPP_PIN(7, 0x4)
-
-#define MPP8_GPIO8 MPP_PIN(8, 0x0)
-#define MPP8_WD_RST_OUT MPP_PIN(8, 0x1)
-
-#define MPP9_GPIO9 MPP_PIN(9, 0x0)
-#define MPP9_PEX1_CLKREQn MPP_PIN(9, 0x5)
-
-#define MPP10_GPIO10 MPP_PIN(10, 0x0)
-#define MPP10_SSP_SCLK MPP_PIN(10, 0x5)
-
-#define MPP11_GPIO11 MPP_PIN(11, 0x0)
-#define MPP11_SATA_PRESENT MPP_PIN(11, 0x1)
-#define MPP11_SATA_ACT MPP_PIN(11, 0x2)
-#define MPP11_SDIO0_LED_CTRL MPP_PIN(11, 0x3)
-#define MPP11_SDIO1_LED_CTRL MPP_PIN(11, 0x4)
-#define MPP11_PEX0_CLKREQn MPP_PIN(11, 0x5)
-
-#define MPP12_GPIO12 MPP_PIN(12, 0x0)
-#define MPP12_SATA_ACT MPP_PIN(12, 0x1)
-#define MPP12_UA2_RTSn MPP_PIN(12, 0x2)
-#define MPP12_AD0_I2S_EXT_MCLK MPP_PIN(12, 0x3)
-#define MPP12_SDIO1_CD MPP_PIN(12, 0x4)
-
-#define MPP13_GPIO13 MPP_PIN(13, 0x0)
-#define MPP13_UA2_CTSn MPP_PIN(13, 0x2)
-#define MPP13_AD1_I2S_EXT_MCLK MPP_PIN(13, 0x3)
-#define MPP13_SDIO1WP MPP_PIN(13, 0x4)
-#define MPP13_SSP_EXTCLK MPP_PIN(13, 0x5)
-
-#define MPP14_GPIO14 MPP_PIN(14, 0x0)
-#define MPP14_UA2_TXD MPP_PIN(14, 0x2)
-#define MPP14_SDIO1_BUS_POWER MPP_PIN(14, 0x4)
-#define MPP14_SSP_RXD MPP_PIN(14, 0x5)
-
-#define MPP15_GPIO15 MPP_PIN(15, 0x0)
-#define MPP15_UA2_RXD MPP_PIN(15, 0x2)
-#define MPP15_SDIO1_LED_CTRL MPP_PIN(15, 0x4)
-#define MPP15_SSP_SFRM MPP_PIN(15, 0x5)
-
-#define MPP16_GPIO16 MPP_PIN(16, 0x0)
-#define MPP16_UA3_RTSn MPP_PIN(16, 0x2)
-#define MPP16_SDIO0_CD MPP_PIN(16, 0x3)
-#define MPP16_SPI_LCD_CS1 MPP_PIN(16, 0x4)
-#define MPP16_AC97_SDATA_IN1 MPP_PIN(16, 0x5)
-
-#define MPP17_GPIO17 MPP_PIN(17, 0x0)
-#define MPP17_AC97_SYSCLK_OUT MPP_PIN(17, 0x1)
-#define MPP17_UA3_CTSn MPP_PIN(17, 0x2)
-#define MPP17_SDIO0_WP MPP_PIN(17, 0x3)
-#define MPP17_TW_SDA2 MPP_PIN(17, 0x4)
-#define MPP17_AC97_SDATA_IN2 MPP_PIN(17, 0x5)
-
-#define MPP18_GPIO18 MPP_PIN(18, 0x0)
-#define MPP18_UA3_TXD MPP_PIN(18, 0x2)
-#define MPP18_SDIO0_BUS_POWER MPP_PIN(18, 0x3)
-#define MPP18_LCD0_PWM MPP_PIN(18, 0x4)
-#define MPP18_AC_SDATA_IN3 MPP_PIN(18, 0x5)
-
-#define MPP19_GPIO19 MPP_PIN(19, 0x0)
-#define MPP19_UA3_RXD MPP_PIN(19, 0x2)
-#define MPP19_SDIO0_LED_CTRL MPP_PIN(19, 0x3)
-#define MPP19_TW_SCK2 MPP_PIN(19, 0x4)
-
-#define MPP20_GPIO20 MPP_PIN(20, 0x0)
-#define MPP20_AC97_SYSCLK_OUT MPP_PIN(20, 0x1)
-#define MPP20_SPI_LCD_MISO MPP_PIN(20, 0x2)
-#define MPP20_SDIO1_CD MPP_PIN(20, 0x3)
-#define MPP20_SDIO0_CD MPP_PIN(20, 0x5)
-#define MPP20_SPI_1_MISO MPP_PIN(20, 0x6)
-
-#define MPP21_GPIO21 MPP_PIN(21, 0x0)
-#define MPP21_UA1_RTSn MPP_PIN(21, 0x1)
-#define MPP21_SPI_LCD_CS0 MPP_PIN(21, 0x2)
-#define MPP21_SDIO1_WP MPP_PIN(21, 0x3)
-#define MPP21_SSP_SFRM MPP_PIN(21, 0x4)
-#define MPP21_SDIO0_WP MPP_PIN(21, 0x5)
-#define MPP21_SPI_1_CS MPP_PIN(21, 0x6)
-
-#define MPP22_GPIO22 MPP_PIN(22, 0x0)
-#define MPP22_UA1_CTSn MPP_PIN(22, 0x1)
-#define MPP22_SPI_LCD_MOSI MPP_PIN(22, 0x2)
-#define MPP22_SDIO1_BUS_POWER MPP_PIN(22, 0x3)
-#define MPP22_SSP_TXD MPP_PIN(22, 0x4)
-#define MPP22_SDIO0_BUS_POWER MPP_PIN(22, 0x5)
-#define MPP22_SPI_1_MOSI MPP_PIN(22, 0x6)
-
-#define MPP23_GPIO23 MPP_PIN(23, 0x0)
-#define MPP23_SPI_LCD_SCK MPP_PIN(23, 0x2)
-#define MPP23_SDIO1_LED_CTRL MPP_PIN(23, 0x3)
-#define MPP23_SSP_SCLK MPP_PIN(23, 0x4)
-#define MPP23_SDIO0_LED_CTRL MPP_PIN(23, 0x5)
-#define MPP23_SPI_1_SCK MPP_PIN(23, 0x6)
+#define MPP(_num, _sel, _in, _out) ( \
+ /* MPP number */ ((_num) & 0xff) | \
+ /* MPP select value */ (((_sel) & 0xf) << 8) | \
+ /* may be input signal */ ((!!(_in)) << 12) | \
+ /* may be output signal */ ((!!(_out)) << 13))
+
+#define MPP0_GPIO0 MPP(0, 0x0, 1, 1)
+#define MPP0_UA2_RTSn MPP(0, 0x2, 0, 0)
+#define MPP0_SDIO0_CD MPP(0, 0x3, 0, 0)
+#define MPP0_LCD0_PWM MPP(0, 0xf, 0, 0)
+
+#define MPP1_GPIO1 MPP(1, 0x0, 1, 1)
+#define MPP1_UA2_CTSn MPP(1, 0x2, 0, 0)
+#define MPP1_SDIO0_WP MPP(1, 0x3, 0, 0)
+#define MPP1_LCD1_PWM MPP(1, 0xf, 0, 0)
+
+#define MPP2_GPIO2 MPP(2, 0x0, 1, 1)
+#define MPP2_SATA_PRESENT MPP(2, 0x1, 0, 0)
+#define MPP2_UA2_TXD MPP(2, 0x2, 0, 0)
+#define MPP2_SDIO0_BUS_POWER MPP(2, 0x3, 0, 0)
+#define MPP2_UA_RTSn1 MPP(2, 0x4, 0, 0)
+
+#define MPP3_GPIO3 MPP(3, 0x0, 1, 1)
+#define MPP3_SATA_ACT MPP(3, 0x1, 0, 0)
+#define MPP3_UA2_RXD MPP(3, 0x2, 0, 0)
+#define MPP3_SDIO0_LED_CTRL MPP(3, 0x3, 0, 0)
+#define MPP3_UA_CTSn1 MPP(3, 0x4, 0, 0)
+#define MPP3_SPI_LCD_CS1 MPP(3, 0xf, 0, 0)
+
+#define MPP4_GPIO4 MPP(4, 0x0, 1, 1)
+#define MPP4_UA3_RTSn MPP(4, 0x2, 0, 0)
+#define MPP4_SDIO1_CD MPP(4, 0x3, 0, 0)
+#define MPP4_SPI_1_MISO MPP(4, 0x4, 0, 0)
+
+#define MPP5_GPIO5 MPP(5, 0x0, 1, 1)
+#define MPP5_UA3_CTSn MPP(5, 0x2, 0, 0)
+#define MPP5_SDIO1_WP MPP(5, 0x3, 0, 0)
+#define MPP5_SPI_1_CS MPP(5, 0x4, 0, 0)
+
+#define MPP6_GPIO6 MPP(6, 0x0, 1, 1)
+#define MPP6_UA3_TXD MPP(6, 0x2, 0, 0)
+#define MPP6_SDIO1_BUS_POWER MPP(6, 0x3, 0, 0)
+#define MPP6_SPI_1_MOSI MPP(6, 0x4, 0, 0)
+
+#define MPP7_GPIO7 MPP(7, 0x0, 1, 1)
+#define MPP7_UA3_RXD MPP(7, 0x2, 0, 0)
+#define MPP7_SDIO1_LED_CTRL MPP(7, 0x3, 0, 0)
+#define MPP7_SPI_1_SCK MPP(7, 0x4, 0, 0)
+
+#define MPP8_GPIO8 MPP(8, 0x0, 1, 1)
+#define MPP8_WD_RST_OUT MPP(8, 0x1, 0, 0)
+
+#define MPP9_GPIO9 MPP(9, 0x0, 1, 1)
+#define MPP9_PEX1_CLKREQn MPP(9, 0x5, 0, 0)
+
+#define MPP10_GPIO10 MPP(10, 0x0, 1, 1)
+#define MPP10_SSP_SCLK MPP(10, 0x5, 0, 0)
+
+#define MPP11_GPIO11 MPP(11, 0x0, 1, 1)
+#define MPP11_SATA_PRESENT MPP(11, 0x1, 0, 0)
+#define MPP11_SATA_ACT MPP(11, 0x2, 0, 0)
+#define MPP11_SDIO0_LED_CTRL MPP(11, 0x3, 0, 0)
+#define MPP11_SDIO1_LED_CTRL MPP(11, 0x4, 0, 0)
+#define MPP11_PEX0_CLKREQn MPP(11, 0x5, 0, 0)
+
+#define MPP12_GPIO12 MPP(12, 0x0, 1, 1)
+#define MPP12_SATA_ACT MPP(12, 0x1, 0, 0)
+#define MPP12_UA2_RTSn MPP(12, 0x2, 0, 0)
+#define MPP12_AD0_I2S_EXT_MCLK MPP(12, 0x3, 0, 0)
+#define MPP12_SDIO1_CD MPP(12, 0x4, 0, 0)
+
+#define MPP13_GPIO13 MPP(13, 0x0, 1, 1)
+#define MPP13_UA2_CTSn MPP(13, 0x2, 0, 0)
+#define MPP13_AD1_I2S_EXT_MCLK MPP(13, 0x3, 0, 0)
+#define MPP13_SDIO1WP MPP(13, 0x4, 0, 0)
+#define MPP13_SSP_EXTCLK MPP(13, 0x5, 0, 0)
+
+#define MPP14_GPIO14 MPP(14, 0x0, 1, 1)
+#define MPP14_UA2_TXD MPP(14, 0x2, 0, 0)
+#define MPP14_SDIO1_BUS_POWER MPP(14, 0x4, 0, 0)
+#define MPP14_SSP_RXD MPP(14, 0x5, 0, 0)
+
+#define MPP15_GPIO15 MPP(15, 0x0, 1, 1)
+#define MPP15_UA2_RXD MPP(15, 0x2, 0, 0)
+#define MPP15_SDIO1_LED_CTRL MPP(15, 0x4, 0, 0)
+#define MPP15_SSP_SFRM MPP(15, 0x5, 0, 0)
+
+#define MPP16_GPIO16 MPP(16, 0x0, 1, 1)
+#define MPP16_UA3_RTSn MPP(16, 0x2, 0, 0)
+#define MPP16_SDIO0_CD MPP(16, 0x3, 0, 0)
+#define MPP16_SPI_LCD_CS1 MPP(16, 0x4, 0, 0)
+#define MPP16_AC97_SDATA_IN1 MPP(16, 0x5, 0, 0)
+
+#define MPP17_GPIO17 MPP(17, 0x0, 1, 1)
+#define MPP17_AC97_SYSCLK_OUT MPP(17, 0x1, 0, 0)
+#define MPP17_UA3_CTSn MPP(17, 0x2, 0, 0)
+#define MPP17_SDIO0_WP MPP(17, 0x3, 0, 0)
+#define MPP17_TW_SDA2 MPP(17, 0x4, 0, 0)
+#define MPP17_AC97_SDATA_IN2 MPP(17, 0x5, 0, 0)
+
+#define MPP18_GPIO18 MPP(18, 0x0, 1, 1)
+#define MPP18_UA3_TXD MPP(18, 0x2, 0, 0)
+#define MPP18_SDIO0_BUS_POWER MPP(18, 0x3, 0, 0)
+#define MPP18_LCD0_PWM MPP(18, 0x4, 0, 0)
+#define MPP18_AC_SDATA_IN3 MPP(18, 0x5, 0, 0)
+
+#define MPP19_GPIO19 MPP(19, 0x0, 1, 1)
+#define MPP19_UA3_RXD MPP(19, 0x2, 0, 0)
+#define MPP19_SDIO0_LED_CTRL MPP(19, 0x3, 0, 0)
+#define MPP19_TW_SCK2 MPP(19, 0x4, 0, 0)
+
+#define MPP20_GPIO20 MPP(20, 0x0, 1, 1)
+#define MPP20_AC97_SYSCLK_OUT MPP(20, 0x1, 0, 0)
+#define MPP20_SPI_LCD_MISO MPP(20, 0x2, 0, 0)
+#define MPP20_SDIO1_CD MPP(20, 0x3, 0, 0)
+#define MPP20_SDIO0_CD MPP(20, 0x5, 0, 0)
+#define MPP20_SPI_1_MISO MPP(20, 0x6, 0, 0)
+
+#define MPP21_GPIO21 MPP(21, 0x0, 1, 1)
+#define MPP21_UA1_RTSn MPP(21, 0x1, 0, 0)
+#define MPP21_SPI_LCD_CS0 MPP(21, 0x2, 0, 0)
+#define MPP21_SDIO1_WP MPP(21, 0x3, 0, 0)
+#define MPP21_SSP_SFRM MPP(21, 0x4, 0, 0)
+#define MPP21_SDIO0_WP MPP(21, 0x5, 0, 0)
+#define MPP21_SPI_1_CS MPP(21, 0x6, 0, 0)
+
+#define MPP22_GPIO22 MPP(22, 0x0, 1, 1)
+#define MPP22_UA1_CTSn MPP(22, 0x1, 0, 0)
+#define MPP22_SPI_LCD_MOSI MPP(22, 0x2, 0, 0)
+#define MPP22_SDIO1_BUS_POWER MPP(22, 0x3, 0, 0)
+#define MPP22_SSP_TXD MPP(22, 0x4, 0, 0)
+#define MPP22_SDIO0_BUS_POWER MPP(22, 0x5, 0, 0)
+#define MPP22_SPI_1_MOSI MPP(22, 0x6, 0, 0)
+
+#define MPP23_GPIO23 MPP(23, 0x0, 1, 1)
+#define MPP23_SPI_LCD_SCK MPP(23, 0x2, 0, 0)
+#define MPP23_SDIO1_LED_CTRL MPP(23, 0x3, 0, 0)
+#define MPP23_SSP_SCLK MPP(23, 0x4, 0, 0)
+#define MPP23_SDIO0_LED_CTRL MPP(23, 0x5, 0, 0)
+#define MPP23_SPI_1_SCK MPP(23, 0x6, 0, 0)
+
+#define MPP_MAX 23
+
+#define MPP_GRP(_grp, _mode) MPP((_grp), (_mode), 0, 0)
/* for MPP groups _num is a group index */
enum dove_mpp_grp_idx {
@@ -181,40 +153,44 @@ enum dove_mpp_grp_idx {
MPP_46_51 = 1,
MPP_58_61 = 5,
MPP_62_63 = 4,
+ MPP_GRP_MAX = 5,
};
-#define MPP24_39_GPIO MPP_GRP(MPP_24_39, 0x1)
-#define MPP24_39_CAM MPP_GRP(MPP_24_39, 0x0)
+#define MPP_GRP_24_39_GPIO MPP_GRP(MPP_24_39, 0x1)
+#define MPP_GRP_24_39_CAM MPP_GRP(MPP_24_39, 0x0)
-#define MPP40_45_GPIO MPP_GRP(MPP_40_45, 0x1)
-#define MPP40_45_SD0 MPP_GRP(MPP_40_45, 0x0)
+#define MPP_GRP_40_45_GPIO MPP_GRP(MPP_40_45, 0x1)
+#define MPP_GRP_40_45_SD0 MPP_GRP(MPP_40_45, 0x0)
-#define MPP46_51_GPIO MPP_GRP(MPP_46_51, 0x1)
-#define MPP46_51_SD1 MPP_GRP(MPP_46_51, 0x0)
+#define MPP_GRP_46_51_GPIO MPP_GRP(MPP_46_51, 0x1)
+#define MPP_GRP_46_51_SD1 MPP_GRP(MPP_46_51, 0x0)
-#define MPP58_61_GPIO MPP_GRP(MPP_58_61, 0x1)
-#define MPP58_61_SPI MPP_GRP(MPP_58_61, 0x0)
+#define MPP_GRP_58_61_GPIO MPP_GRP(MPP_58_61, 0x1)
+#define MPP_GRP_58_61_SPI MPP_GRP(MPP_58_61, 0x0)
-#define MPP62_63_GPIO MPP_GRP(MPP_62_63, 0x1)
-#define MPP62_63_UA1 MPP_GRP(MPP_62_63, 0x0)
+#define MPP_GRP_62_63_GPIO MPP_GRP(MPP_62_63, 0x1)
+#define MPP_GRP_62_63_UA1 MPP_GRP(MPP_62_63, 0x0)
/* The MPP[64:71] control differs from other groups */
-#define MPP64_71_GPO MPP_GRP_NFC(0x1)
-#define MPP64_71_NFC MPP_GRP_NFC(0x0)
+#define MPP_GRP_NFC_64_71_GPO 0x1
+#define MPP_GRP_NFC_64_71_NFC 0x0
/*
* The MPP[52:57] functionality is encoded by 4 bits in different
* registers. The _num field in this case encodes those bits in
* correspodence with Table 135 of 88AP510 Functional specification
*/
-#define MPP52_57_AU1 MPP_GRP_AU1(0x0)
-#define MPP52_57_AU1_GPIO57 MPP_GRP_AU1(0x2)
-#define MPP52_57_GPIO MPP_GRP_AU1(0xa)
-#define MPP52_57_TW_GPIO MPP_GRP_AU1(0xb)
-#define MPP52_57_AU1_SSP MPP_GRP_AU1(0xc)
-#define MPP52_57_SSP_GPIO MPP_GRP_AU1(0xe)
-#define MPP52_57_SSP_TW MPP_GRP_AU1(0xf)
-
-void dove_mpp_conf(unsigned int *mpp_list);
+#define MPP_GRP_AU1_52_57_AU1 0x0
+#define MPP_GRP_AU1_52_57_AU1_GPIO57 0x2
+#define MPP_GRP_AU1_52_57_GPIO 0xa
+#define MPP_GRP_AU1_52_57_TW_GPIO 0xb
+#define MPP_GRP_AU1_52_57_AU1_SSP 0xc
+#define MPP_GRP_AU1_52_57_SSP_GPIO 0xe
+#define MPP_GRP_AU1_52_57_SSP_TW 0xf
+
+void dove_mpp_conf(unsigned int *mpp_list,
+ unsigned int *mpp_grp_list,
+ unsigned int grp_au1_52_57,
+ unsigned int grp_nfc_64_71);
#endif /* __ARCH_DOVE_MPP_CODED_H */
diff --git a/arch/arm/mach-ep93xx/gpio.c b/arch/arm/mach-ep93xx/gpio.c
index a5a9ff70b198..415dce37b88c 100644
--- a/arch/arm/mach-ep93xx/gpio.c
+++ b/arch/arm/mach-ep93xx/gpio.c
@@ -356,29 +356,6 @@ static int ep93xx_gpio_set_debounce(struct gpio_chip *chip,
return 0;
}
-static void ep93xx_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
-{
- struct ep93xx_gpio_chip *ep93xx_chip = to_ep93xx_gpio_chip(chip);
- u8 data_reg, data_dir_reg;
- int gpio, i;
-
- data_reg = __raw_readb(ep93xx_chip->data_reg);
- data_dir_reg = __raw_readb(ep93xx_chip->data_dir_reg);
-
- gpio = ep93xx_chip->chip.base;
- for (i = 0; i < chip->ngpio; i++, gpio++) {
- int is_out = data_dir_reg & (1 << i);
- int irq = gpio_to_irq(gpio);
-
- seq_printf(s, " %s%d gpio-%-3d (%-12s) %s %s %s\n",
- chip->label, i, gpio,
- gpiochip_is_requested(chip, i) ? : "",
- is_out ? "out" : "in ",
- (data_reg & (1<< i)) ? "hi" : "lo",
- (!is_out && irq>= 0) ? "(interrupt)" : "");
- }
-}
-
#define EP93XX_GPIO_BANK(name, dr, ddr, base_gpio) \
{ \
.chip = { \
@@ -387,7 +364,6 @@ static void ep93xx_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
.direction_output = ep93xx_gpio_direction_output, \
.get = ep93xx_gpio_get, \
.set = ep93xx_gpio_set, \
- .dbg_show = ep93xx_gpio_dbg_show, \
.base = base_gpio, \
.ngpio = 8, \
}, \
diff --git a/arch/arm/mach-exynos4/Kconfig b/arch/arm/mach-exynos4/Kconfig
index e849f67be47d..805196207ce8 100644
--- a/arch/arm/mach-exynos4/Kconfig
+++ b/arch/arm/mach-exynos4/Kconfig
@@ -170,6 +170,7 @@ config MACH_NURI
select S3C_DEV_HSMMC3
select S3C_DEV_I2C1
select S3C_DEV_I2C5
+ select S5P_DEV_USB_EHCI
select EXYNOS4_SETUP_I2C1
select EXYNOS4_SETUP_I2C5
select EXYNOS4_SETUP_SDHCI
diff --git a/arch/arm/mach-exynos4/Makefile b/arch/arm/mach-exynos4/Makefile
index 9be104f63c0b..777897551e42 100644
--- a/arch/arm/mach-exynos4/Makefile
+++ b/arch/arm/mach-exynos4/Makefile
@@ -54,3 +54,5 @@ obj-$(CONFIG_EXYNOS4_SETUP_I2C7) += setup-i2c7.o
obj-$(CONFIG_EXYNOS4_SETUP_KEYPAD) += setup-keypad.o
obj-$(CONFIG_EXYNOS4_SETUP_SDHCI) += setup-sdhci.o
obj-$(CONFIG_EXYNOS4_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
+
+obj-$(CONFIG_USB_SUPPORT) += usb-phy.o
diff --git a/arch/arm/mach-exynos4/cpu.c b/arch/arm/mach-exynos4/cpu.c
index 793011391943..08813a6f66b1 100644
--- a/arch/arm/mach-exynos4/cpu.c
+++ b/arch/arm/mach-exynos4/cpu.c
@@ -97,7 +97,12 @@ static struct map_desc exynos4_iodesc[] __initdata = {
.pfn = __phys_to_pfn(EXYNOS4_PA_SROMC),
.length = SZ_4K,
.type = MT_DEVICE,
- },
+ }, {
+ .virtual = (unsigned long)S5P_VA_USB_HSPHY,
+ .pfn = __phys_to_pfn(EXYNOS4_PA_HSPHY),
+ .length = SZ_4K,
+ .type = MT_DEVICE,
+ }
};
static void exynos4_idle(void)
diff --git a/arch/arm/mach-exynos4/include/mach/map.h b/arch/arm/mach-exynos4/include/mach/map.h
index 6330b73b9ea7..0009e77a05fc 100644
--- a/arch/arm/mach-exynos4/include/mach/map.h
+++ b/arch/arm/mach-exynos4/include/mach/map.h
@@ -101,6 +101,9 @@
#define EXYNOS4_PA_SROMC 0x12570000
+#define EXYNOS4_PA_EHCI 0x12580000
+#define EXYNOS4_PA_HSPHY 0x125B0000
+
#define EXYNOS4_PA_UART 0x13800000
#define EXYNOS4_PA_IIC(x) (0x13860000 + ((x) * 0x10000))
@@ -143,6 +146,7 @@
#define S5P_PA_SROMC EXYNOS4_PA_SROMC
#define S5P_PA_SYSCON EXYNOS4_PA_SYSCON
#define S5P_PA_TIMER EXYNOS4_PA_TIMER
+#define S5P_PA_EHCI EXYNOS4_PA_EHCI
#define SAMSUNG_PA_KEYPAD EXYNOS4_PA_KEYPAD
diff --git a/arch/arm/mach-exynos4/include/mach/regs-pmu.h b/arch/arm/mach-exynos4/include/mach/regs-pmu.h
index 62b0014d05e0..a9643371f8e7 100644
--- a/arch/arm/mach-exynos4/include/mach/regs-pmu.h
+++ b/arch/arm/mach-exynos4/include/mach/regs-pmu.h
@@ -33,6 +33,9 @@
#define S5P_EINT_WAKEUP_MASK S5P_PMUREG(0x0604)
#define S5P_WAKEUP_MASK S5P_PMUREG(0x0608)
+#define S5P_USBHOST_PHY_CONTROL S5P_PMUREG(0x0708)
+#define S5P_USBHOST_PHY_ENABLE (1 << 0)
+
#define S5P_MIPI_DPHY_CONTROL(n) S5P_PMUREG(0x0710 + (n) * 4)
#define S5P_MIPI_DPHY_ENABLE (1 << 0)
#define S5P_MIPI_DPHY_SRESETN (1 << 1)
diff --git a/arch/arm/mach-exynos4/include/mach/regs-usb-phy.h b/arch/arm/mach-exynos4/include/mach/regs-usb-phy.h
new file mode 100644
index 000000000000..703118d5173c
--- /dev/null
+++ b/arch/arm/mach-exynos4/include/mach/regs-usb-phy.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 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_S5P_REGS_USB_PHY_H
+#define __PLAT_S5P_REGS_USB_PHY_H
+
+#define EXYNOS4_HSOTG_PHYREG(x) ((x) + S5P_VA_USB_HSPHY)
+
+#define EXYNOS4_PHYPWR EXYNOS4_HSOTG_PHYREG(0x00)
+#define PHY1_HSIC_NORMAL_MASK (0xf << 9)
+#define PHY1_HSIC1_SLEEP (1 << 12)
+#define PHY1_HSIC1_FORCE_SUSPEND (1 << 11)
+#define PHY1_HSIC0_SLEEP (1 << 10)
+#define PHY1_HSIC0_FORCE_SUSPEND (1 << 9)
+
+#define PHY1_STD_NORMAL_MASK (0x7 << 6)
+#define PHY1_STD_SLEEP (1 << 8)
+#define PHY1_STD_ANALOG_POWERDOWN (1 << 7)
+#define PHY1_STD_FORCE_SUSPEND (1 << 6)
+
+#define PHY0_NORMAL_MASK (0x39 << 0)
+#define PHY0_SLEEP (1 << 5)
+#define PHY0_OTG_DISABLE (1 << 4)
+#define PHY0_ANALOG_POWERDOWN (1 << 3)
+#define PHY0_FORCE_SUSPEND (1 << 0)
+
+#define EXYNOS4_PHYCLK EXYNOS4_HSOTG_PHYREG(0x04)
+#define PHY1_COMMON_ON_N (1 << 7)
+#define PHY0_COMMON_ON_N (1 << 4)
+#define PHY0_ID_PULLUP (1 << 2)
+#define CLKSEL_MASK (0x3 << 0)
+#define CLKSEL_SHIFT (0)
+#define CLKSEL_48M (0x0 << 0)
+#define CLKSEL_12M (0x2 << 0)
+#define CLKSEL_24M (0x3 << 0)
+
+#define EXYNOS4_RSTCON EXYNOS4_HSOTG_PHYREG(0x08)
+#define HOST_LINK_PORT_SWRST_MASK (0xf << 6)
+#define HOST_LINK_PORT2_SWRST (1 << 9)
+#define HOST_LINK_PORT1_SWRST (1 << 8)
+#define HOST_LINK_PORT0_SWRST (1 << 7)
+#define HOST_LINK_ALL_SWRST (1 << 6)
+
+#define PHY1_SWRST_MASK (0x7 << 3)
+#define PHY1_HSIC_SWRST (1 << 5)
+#define PHY1_STD_SWRST (1 << 4)
+#define PHY1_ALL_SWRST (1 << 3)
+
+#define PHY0_SWRST_MASK (0x7 << 0)
+#define PHY0_PHYLINK_SWRST (1 << 2)
+#define PHY0_HLINK_SWRST (1 << 1)
+#define PHY0_SWRST (1 << 0)
+
+#define EXYNOS4_PHY1CON EXYNOS4_HSOTG_PHYREG(0x34)
+#define FPENABLEN (1 << 0)
+
+#endif /* __PLAT_S5P_REGS_USB_PHY_H */
diff --git a/arch/arm/mach-exynos4/include/mach/smp.h b/arch/arm/mach-exynos4/include/mach/smp.h
deleted file mode 100644
index a463dcebcfd3..000000000000
--- a/arch/arm/mach-exynos4/include/mach/smp.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/* linux/arch/arm/mach-exynos4/include/mach/smp.h
- *
- * Cloned from arch/arm/mach-realview/include/mach/smp.h
-*/
-
-#ifndef ASM_ARCH_SMP_H
-#define ASM_ARCH_SMP_H __FILE__
-
-#include <asm/hardware/gic.h>
-
-/*
- * We use IRQ1 as the IPI
- */
-static inline void smp_cross_call(const struct cpumask *mask, int ipi)
-{
- gic_raise_softirq(mask, ipi);
-}
-
-#endif
diff --git a/arch/arm/mach-exynos4/irq-combiner.c b/arch/arm/mach-exynos4/irq-combiner.c
index f488b66d6806..5a2758ab055e 100644
--- a/arch/arm/mach-exynos4/irq-combiner.c
+++ b/arch/arm/mach-exynos4/irq-combiner.c
@@ -59,8 +59,7 @@ static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
unsigned int cascade_irq, combiner_irq;
unsigned long status;
- /* primary controller ack'ing */
- chip->irq_ack(&desc->irq_data);
+ chained_irq_enter(chip, desc);
spin_lock(&irq_controller_lock);
status = __raw_readl(chip_data->base + COMBINER_INT_STATUS);
@@ -79,8 +78,7 @@ static void combiner_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
generic_handle_irq(cascade_irq);
out:
- /* primary controller unmasking */
- chip->irq_unmask(&desc->irq_data);
+ chained_irq_exit(chip, desc);
}
static struct irq_chip combiner_chip = {
diff --git a/arch/arm/mach-exynos4/mach-nuri.c b/arch/arm/mach-exynos4/mach-nuri.c
index b79ad010d194..bb5d12f43af8 100644
--- a/arch/arm/mach-exynos4/mach-nuri.c
+++ b/arch/arm/mach-exynos4/mach-nuri.c
@@ -30,6 +30,8 @@
#include <plat/cpu.h>
#include <plat/devs.h>
#include <plat/sdhci.h>
+#include <plat/ehci.h>
+#include <plat/clock.h>
#include <mach/map.h>
@@ -262,6 +264,16 @@ static struct i2c_board_info i2c5_devs[] __initdata = {
/* max8997, To be updated */
};
+/* USB EHCI */
+static struct s5p_ehci_platdata nuri_ehci_pdata;
+
+static void __init nuri_ehci_init(void)
+{
+ struct s5p_ehci_platdata *pdata = &nuri_ehci_pdata;
+
+ s5p_ehci_set_platdata(pdata);
+}
+
static struct platform_device *nuri_devices[] __initdata = {
/* Samsung Platform Devices */
&emmc_fixed_voltage,
@@ -270,6 +282,7 @@ static struct platform_device *nuri_devices[] __initdata = {
&s3c_device_hsmmc3,
&s3c_device_wdt,
&s3c_device_timer[0],
+ &s5p_device_ehci,
/* NURI Devices */
&nuri_gpio_keys,
@@ -291,6 +304,9 @@ static void __init nuri_machine_init(void)
i2c_register_board_info(1, i2c1_devs, ARRAY_SIZE(i2c1_devs));
i2c_register_board_info(5, i2c5_devs, ARRAY_SIZE(i2c5_devs));
+ nuri_ehci_init();
+ clk_xusbxti.rate = 24000000;
+
/* Last */
platform_add_devices(nuri_devices, ARRAY_SIZE(nuri_devices));
}
diff --git a/arch/arm/mach-exynos4/platsmp.c b/arch/arm/mach-exynos4/platsmp.c
index 6d35878ec1aa..c5e65a02be8d 100644
--- a/arch/arm/mach-exynos4/platsmp.c
+++ b/arch/arm/mach-exynos4/platsmp.c
@@ -22,6 +22,7 @@
#include <linux/io.h>
#include <asm/cacheflush.h>
+#include <asm/hardware/gic.h>
#include <asm/smp_scu.h>
#include <asm/unified.h>
@@ -104,7 +105,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
* the boot monitor to read the system wide flags register,
* and branch to the address found there.
*/
- smp_cross_call(cpumask_of(cpu), 1);
+ gic_raise_softirq(cpumask_of(cpu), 1);
timeout = jiffies + (1 * HZ);
while (time_before(jiffies, timeout)) {
@@ -147,6 +148,8 @@ void __init smp_init_cpus(void)
for (i = 0; i < ncores; i++)
set_cpu_possible(i, true);
+
+ set_smp_cross_call(gic_raise_softirq);
}
void __init platform_smp_prepare_cpus(unsigned int max_cpus)
diff --git a/arch/arm/mach-exynos4/pm.c b/arch/arm/mach-exynos4/pm.c
index 10d917d9e3ad..8755ca8dd48d 100644
--- a/arch/arm/mach-exynos4/pm.c
+++ b/arch/arm/mach-exynos4/pm.c
@@ -16,6 +16,7 @@
#include <linux/init.h>
#include <linux/suspend.h>
+#include <linux/syscore_ops.h>
#include <linux/io.h>
#include <asm/cacheflush.h>
@@ -372,7 +373,27 @@ void exynos4_scu_enable(void __iomem *scu_base)
flush_cache_all();
}
-static int exynos4_pm_resume(struct sys_device *dev)
+static struct sysdev_driver exynos4_pm_driver = {
+ .add = exynos4_pm_add,
+};
+
+static __init int exynos4_pm_drvinit(void)
+{
+ unsigned int tmp;
+
+ s3c_pm_init();
+
+ /* All wakeup disable */
+
+ tmp = __raw_readl(S5P_WAKEUP_MASK);
+ tmp |= ((0xFF << 8) | (0x1F << 1));
+ __raw_writel(tmp, S5P_WAKEUP_MASK);
+
+ return sysdev_driver_register(&exynos4_sysclass, &exynos4_pm_driver);
+}
+arch_initcall(exynos4_pm_drvinit);
+
+static void exynos4_pm_resume(void)
{
/* For release retention */
@@ -394,27 +415,15 @@ static int exynos4_pm_resume(struct sys_device *dev)
/* enable L2X0*/
writel_relaxed(1, S5P_VA_L2CC + L2X0_CTRL);
#endif
-
- return 0;
}
-static struct sysdev_driver exynos4_pm_driver = {
- .add = exynos4_pm_add,
+static struct syscore_ops exynos4_pm_syscore_ops = {
.resume = exynos4_pm_resume,
};
-static __init int exynos4_pm_drvinit(void)
+static __init int exynos4_pm_syscore_init(void)
{
- unsigned int tmp;
-
- s3c_pm_init();
-
- /* All wakeup disable */
-
- tmp = __raw_readl(S5P_WAKEUP_MASK);
- tmp |= ((0xFF << 8) | (0x1F << 1));
- __raw_writel(tmp, S5P_WAKEUP_MASK);
-
- return sysdev_driver_register(&exynos4_sysclass, &exynos4_pm_driver);
+ register_syscore_ops(&exynos4_pm_syscore_ops);
+ return 0;
}
-arch_initcall(exynos4_pm_drvinit);
+arch_initcall(exynos4_pm_syscore_init);
diff --git a/arch/arm/mach-exynos4/usb-phy.c b/arch/arm/mach-exynos4/usb-phy.c
new file mode 100644
index 000000000000..0883c1b824b9
--- /dev/null
+++ b/arch/arm/mach-exynos4/usb-phy.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2011 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/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <mach/regs-pmu.h>
+#include <mach/regs-usb-phy.h>
+#include <plat/cpu.h>
+#include <plat/usb-phy.h>
+
+static int exynos4_usb_phy1_init(struct platform_device *pdev)
+{
+ struct clk *otg_clk;
+ struct clk *xusbxti_clk;
+ u32 phyclk;
+ u32 rstcon;
+ int err;
+
+ otg_clk = clk_get(&pdev->dev, "otg");
+ if (IS_ERR(otg_clk)) {
+ dev_err(&pdev->dev, "Failed to get otg clock\n");
+ return PTR_ERR(otg_clk);
+ }
+
+ err = clk_enable(otg_clk);
+ if (err) {
+ clk_put(otg_clk);
+ return err;
+ }
+
+ writel(readl(S5P_USBHOST_PHY_CONTROL) | S5P_USBHOST_PHY_ENABLE,
+ S5P_USBHOST_PHY_CONTROL);
+
+ /* set clock frequency for PLL */
+ phyclk = readl(EXYNOS4_PHYCLK) & ~CLKSEL_MASK;
+
+ xusbxti_clk = clk_get(&pdev->dev, "xusbxti");
+ if (xusbxti_clk && !IS_ERR(xusbxti_clk)) {
+ switch (clk_get_rate(xusbxti_clk)) {
+ case 12 * MHZ:
+ phyclk |= CLKSEL_12M;
+ break;
+ case 24 * MHZ:
+ phyclk |= CLKSEL_24M;
+ break;
+ default:
+ case 48 * MHZ:
+ /* default reference clock */
+ break;
+ }
+ clk_put(xusbxti_clk);
+ }
+
+ writel(phyclk, EXYNOS4_PHYCLK);
+
+ /* floating prevention logic: disable */
+ writel((readl(EXYNOS4_PHY1CON) | FPENABLEN), EXYNOS4_PHY1CON);
+
+ /* set to normal HSIC 0 and 1 of PHY1 */
+ writel((readl(EXYNOS4_PHYPWR) & ~PHY1_HSIC_NORMAL_MASK),
+ EXYNOS4_PHYPWR);
+
+ /* set to normal standard USB of PHY1 */
+ writel((readl(EXYNOS4_PHYPWR) & ~PHY1_STD_NORMAL_MASK), EXYNOS4_PHYPWR);
+
+ /* reset all ports of both PHY and Link */
+ rstcon = readl(EXYNOS4_RSTCON) | HOST_LINK_PORT_SWRST_MASK |
+ PHY1_SWRST_MASK;
+ writel(rstcon, EXYNOS4_RSTCON);
+ udelay(10);
+
+ rstcon &= ~(HOST_LINK_PORT_SWRST_MASK | PHY1_SWRST_MASK);
+ writel(rstcon, EXYNOS4_RSTCON);
+ udelay(50);
+
+ clk_disable(otg_clk);
+ clk_put(otg_clk);
+
+ return 0;
+}
+
+static int exynos4_usb_phy1_exit(struct platform_device *pdev)
+{
+ struct clk *otg_clk;
+ int err;
+
+ otg_clk = clk_get(&pdev->dev, "otg");
+ if (IS_ERR(otg_clk)) {
+ dev_err(&pdev->dev, "Failed to get otg clock\n");
+ return PTR_ERR(otg_clk);
+ }
+
+ err = clk_enable(otg_clk);
+ if (err) {
+ clk_put(otg_clk);
+ return err;
+ }
+
+ writel((readl(EXYNOS4_PHYPWR) | PHY1_STD_ANALOG_POWERDOWN),
+ EXYNOS4_PHYPWR);
+
+ writel(readl(S5P_USBHOST_PHY_CONTROL) & ~S5P_USBHOST_PHY_ENABLE,
+ S5P_USBHOST_PHY_CONTROL);
+
+ clk_disable(otg_clk);
+ clk_put(otg_clk);
+
+ return 0;
+}
+
+int s5p_usb_phy_init(struct platform_device *pdev, int type)
+{
+ if (type == S5P_USB_PHY_HOST)
+ return exynos4_usb_phy1_init(pdev);
+
+ return -EINVAL;
+}
+
+int s5p_usb_phy_exit(struct platform_device *pdev, int type)
+{
+ if (type == S5P_USB_PHY_HOST)
+ return exynos4_usb_phy1_exit(pdev);
+
+ return -EINVAL;
+}
diff --git a/arch/arm/mach-footbridge/Kconfig b/arch/arm/mach-footbridge/Kconfig
index bdd257921cfb..46adca068f2c 100644
--- a/arch/arm/mach-footbridge/Kconfig
+++ b/arch/arm/mach-footbridge/Kconfig
@@ -4,6 +4,7 @@ menu "Footbridge Implementations"
config ARCH_CATS
bool "CATS"
+ select CLKSRC_I8253
select FOOTBRIDGE_HOST
select ISA
select ISA_DMA
@@ -59,6 +60,7 @@ config ARCH_EBSA285_HOST
config ARCH_NETWINDER
bool "NetWinder"
+ select CLKSRC_I8253
select FOOTBRIDGE_HOST
select ISA
select ISA_DMA
diff --git a/arch/arm/mach-footbridge/isa-timer.c b/arch/arm/mach-footbridge/isa-timer.c
index 441c6ce0d555..7020f1a3feca 100644
--- a/arch/arm/mach-footbridge/isa-timer.c
+++ b/arch/arm/mach-footbridge/isa-timer.c
@@ -10,53 +10,16 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
+#include <linux/spinlock.h>
#include <linux/timex.h>
#include <asm/irq.h>
-
+#include <asm/i8253.h>
#include <asm/mach/time.h>
#include "common.h"
-#define PIT_MODE 0x43
-#define PIT_CH0 0x40
-
-#define PIT_LATCH ((PIT_TICK_RATE + HZ / 2) / HZ)
-
-static cycle_t pit_read(struct clocksource *cs)
-{
- unsigned long flags;
- static int old_count;
- static u32 old_jifs;
- int count;
- u32 jifs;
-
- raw_local_irq_save(flags);
-
- jifs = jiffies;
- outb_p(0x00, PIT_MODE); /* latch the count */
- count = inb_p(PIT_CH0); /* read the latched count */
- count |= inb_p(PIT_CH0) << 8;
-
- if (count > old_count && jifs == old_jifs)
- count = old_count;
-
- old_count = count;
- old_jifs = jifs;
-
- raw_local_irq_restore(flags);
-
- count = (PIT_LATCH - 1) - count;
-
- return (cycle_t)(jifs * PIT_LATCH) + count;
-}
-
-static struct clocksource pit_cs = {
- .name = "pit",
- .rating = 110,
- .read = pit_read,
- .mask = CLOCKSOURCE_MASK(32),
-};
+DEFINE_RAW_SPINLOCK(i8253_lock);
static void pit_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
@@ -121,7 +84,7 @@ static void __init isa_timer_init(void)
pit_ce.max_delta_ns = clockevent_delta2ns(0x7fff, &pit_ce);
pit_ce.min_delta_ns = clockevent_delta2ns(0x000f, &pit_ce);
- clocksource_register_hz(&pit_cs, PIT_TICK_RATE);
+ clocksource_i8253_init();
setup_irq(pit_ce.irq, &pit_timer_irq);
clockevents_register_device(&pit_ce);
diff --git a/arch/arm/mach-gemini/include/mach/uncompress.h b/arch/arm/mach-gemini/include/mach/uncompress.h
index 5483f61a8061..0efa26247235 100644
--- a/arch/arm/mach-gemini/include/mach/uncompress.h
+++ b/arch/arm/mach-gemini/include/mach/uncompress.h
@@ -16,7 +16,7 @@
#include <linux/serial_reg.h>
#include <mach/hardware.h>
-static volatile unsigned long *UART = (unsigned long *)GEMINI_UART_BASE;
+static volatile unsigned long * const UART = (unsigned long *)GEMINI_UART_BASE;
/*
* The following code assumes the serial port has already been
diff --git a/arch/arm/mach-h720x/include/mach/memory.h b/arch/arm/mach-h720x/include/mach/memory.h
index 9d3687651462..b0b3baec9acf 100644
--- a/arch/arm/mach-h720x/include/mach/memory.h
+++ b/arch/arm/mach-h720x/include/mach/memory.h
@@ -13,7 +13,6 @@
* There should not be more than (0xd0000000 - 0xc0000000)
* bytes of RAM.
*/
-#define ISA_DMA_THRESHOLD (PHYS_OFFSET + SZ_256M - 1)
-#define MAX_DMA_ADDRESS (PAGE_OFFSET + SZ_256M)
+#define ARM_DMA_ZONE_SIZE SZ_256M
#endif
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 56b930a13443..59c97a331136 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -1,5 +1,15 @@
config IMX_HAVE_DMA_V1
bool
+#
+# ARCH_MX31 and ARCH_MX35 are left for compatibility
+# Some usages assume that having one of them implies not having (e.g.) ARCH_MX2.
+# To easily distinguish good and reviewed from unreviewed usages new (and IMHO
+# more sensible) names are used: SOC_IMX31 and SOC_IMX35
+config ARCH_MX31
+ bool
+
+config ARCH_MX35
+ bool
config SOC_IMX1
bool
@@ -31,6 +41,24 @@ config SOC_IMX27
select IMX_HAVE_IOMUX_V1
select MXC_AVIC
+config SOC_IMX31
+ bool
+ select CPU_V6
+ select IMX_HAVE_PLATFORM_MXC_RNGA
+ select ARCH_MXC_AUDMUX_V2
+ select ARCH_MX31
+ select MXC_AVIC
+
+config SOC_IMX35
+ bool
+ select CPU_V6
+ select ARCH_MXC_IOMUX_V3
+ select ARCH_MXC_AUDMUX_V2
+ select HAVE_EPIT
+ select ARCH_MX35
+ select MXC_AVIC
+
+
if ARCH_MX1
comment "MX1 platforms:"
@@ -40,6 +68,7 @@ config MACH_MXLADS
config ARCH_MX1ADS
bool "MX1ADS platform"
select MACH_MXLADS
+ select SOC_IMX1
select IMX_HAVE_PLATFORM_IMX_I2C
select IMX_HAVE_PLATFORM_IMX_UART
help
@@ -51,6 +80,13 @@ config MACH_SCB9328
help
Say Y here if you are using a Synertronixx scb9328 board
+config MACH_APF9328
+ bool "APF9328"
+ select SOC_IMX1
+ select IMX_HAVE_PLATFORM_IMX_UART
+ help
+ Say Yes here if you are using the Armadeus APF9328 development board
+
endif
if ARCH_MX2
@@ -129,6 +165,7 @@ choice
config MACH_EUKREA_MBIMXSD25_BASEBOARD
bool "Eukrea MBIMXSD development board"
+ select IMX_HAVE_PLATFORM_GPIO_KEYS
select IMX_HAVE_PLATFORM_IMX_SSI
help
This adds board specific devices that can be found on Eukrea's
@@ -254,6 +291,7 @@ config MACH_MX27_3DS
config MACH_IMX27_VISSTRIM_M10
bool "Vista Silicon i.MX27 Visstrim_m10"
select SOC_IMX27
+ select IMX_HAVE_PLATFORM_GPIO_KEYS
select IMX_HAVE_PLATFORM_IMX_I2C
select IMX_HAVE_PLATFORM_IMX_SSI
select IMX_HAVE_PLATFORM_IMX_UART
@@ -314,3 +352,251 @@ config MACH_IMX27IPCAM
configurations for the board and its peripherals.
endif
+
+if ARCH_MX3
+
+comment "MX31 platforms:"
+
+config MACH_MX31ADS
+ bool "Support MX31ADS platforms"
+ select SOC_IMX31
+ select IMX_HAVE_PLATFORM_IMX_I2C
+ select IMX_HAVE_PLATFORM_IMX_SSI
+ select IMX_HAVE_PLATFORM_IMX_UART
+ default y
+ help
+ Include support for MX31ADS platform. This includes specific
+ configurations for the board and its peripherals.
+
+config MACH_MX31ADS_WM1133_EV1
+ bool "Support Wolfson Microelectronics 1133-EV1 module"
+ depends on MACH_MX31ADS
+ depends on MFD_WM8350_I2C
+ depends on REGULATOR_WM8350
+ select MFD_WM8350_CONFIG_MODE_0
+ select MFD_WM8352_CONFIG_MODE_0
+ help
+ Include support for the Wolfson Microelectronics 1133-EV1 PMU
+ and audio module for the MX31ADS platform.
+
+config MACH_MX31LILLY
+ bool "Support MX31 LILLY-1131 platforms (INCO startec)"
+ select SOC_IMX31
+ select IMX_HAVE_PLATFORM_IMX_UART
+ select IMX_HAVE_PLATFORM_IPU_CORE
+ select IMX_HAVE_PLATFORM_MXC_EHCI
+ select IMX_HAVE_PLATFORM_MXC_MMC
+ select IMX_HAVE_PLATFORM_SPI_IMX
+ select MXC_ULPI if USB_ULPI
+ help
+ Include support for mx31 based LILLY1131 modules. This includes
+ specific configurations for the board and its peripherals.
+
+config MACH_MX31LITE
+ bool "Support MX31 LITEKIT (LogicPD)"
+ select SOC_IMX31
+ select MXC_ULPI if USB_ULPI
+ select IMX_HAVE_PLATFORM_IMX2_WDT
+ select IMX_HAVE_PLATFORM_IMX_UART
+ select IMX_HAVE_PLATFORM_MXC_EHCI
+ select IMX_HAVE_PLATFORM_MXC_MMC
+ select IMX_HAVE_PLATFORM_MXC_NAND
+ select IMX_HAVE_PLATFORM_MXC_RTC
+ select IMX_HAVE_PLATFORM_SPI_IMX
+ help
+ Include support for MX31 LITEKIT platform. This includes specific
+ configurations for the board and its peripherals.
+
+config MACH_PCM037
+ bool "Support Phytec pcm037 (i.MX31) platforms"
+ select SOC_IMX31
+ select IMX_HAVE_PLATFORM_FSL_USB2_UDC
+ select IMX_HAVE_PLATFORM_IMX2_WDT
+ select IMX_HAVE_PLATFORM_IMX_I2C
+ select IMX_HAVE_PLATFORM_IMX_UART
+ select IMX_HAVE_PLATFORM_IPU_CORE
+ select IMX_HAVE_PLATFORM_MXC_EHCI
+ select IMX_HAVE_PLATFORM_MXC_MMC
+ select IMX_HAVE_PLATFORM_MXC_NAND
+ select IMX_HAVE_PLATFORM_MXC_W1
+ select MXC_ULPI if USB_ULPI
+ help
+ Include support for Phytec pcm037 platform. This includes
+ specific configurations for the board and its peripherals.
+
+config MACH_PCM037_EET
+ bool "Support pcm037 EET board extensions"
+ depends on MACH_PCM037
+ select IMX_HAVE_PLATFORM_GPIO_KEYS
+ select IMX_HAVE_PLATFORM_SPI_IMX
+ help
+ Add support for PCM037 EET baseboard extensions. If you are using the
+ OLED display with EET, use "video=mx3fb:CMEL-OLED" kernel
+ command-line parameter.
+
+config MACH_MX31_3DS
+ bool "Support MX31PDK (3DS)"
+ select SOC_IMX31
+ select MXC_DEBUG_BOARD
+ select IMX_HAVE_PLATFORM_FSL_USB2_UDC
+ select IMX_HAVE_PLATFORM_IMX2_WDT
+ select IMX_HAVE_PLATFORM_IMX_I2C
+ select IMX_HAVE_PLATFORM_IMX_KEYPAD
+ select IMX_HAVE_PLATFORM_IMX_UART
+ select IMX_HAVE_PLATFORM_IPU_CORE
+ select IMX_HAVE_PLATFORM_MXC_EHCI
+ select IMX_HAVE_PLATFORM_MXC_NAND
+ select IMX_HAVE_PLATFORM_SPI_IMX
+ select MXC_ULPI if USB_ULPI
+ help
+ Include support for MX31PDK (3DS) platform. This includes specific
+ configurations for the board and its peripherals.
+
+config MACH_MX31_3DS_MXC_NAND_USE_BBT
+ bool "Make the MXC NAND driver use the in flash Bad Block Table"
+ depends on MACH_MX31_3DS
+ depends on MTD_NAND_MXC
+ help
+ Enable this if you want that the MXC NAND driver uses the in flash
+ Bad Block Table to know what blocks are bad instead of scanning the
+ entire flash looking for bad block markers.
+
+config MACH_MX31MOBOARD
+ bool "Support mx31moboard platforms (EPFL Mobots group)"
+ select SOC_IMX31
+ select IMX_HAVE_PLATFORM_FSL_USB2_UDC
+ select IMX_HAVE_PLATFORM_IMX_I2C
+ select IMX_HAVE_PLATFORM_IMX_UART
+ select IMX_HAVE_PLATFORM_IPU_CORE
+ select IMX_HAVE_PLATFORM_MXC_EHCI
+ select IMX_HAVE_PLATFORM_MXC_MMC
+ select IMX_HAVE_PLATFORM_SPI_IMX
+ select MXC_ULPI if USB_ULPI
+ help
+ Include support for mx31moboard platform. This includes specific
+ configurations for the board and its peripherals.
+
+config MACH_QONG
+ bool "Support Dave/DENX QongEVB-LITE platform"
+ select SOC_IMX31
+ select IMX_HAVE_PLATFORM_IMX_UART
+ help
+ Include support for Dave/DENX QongEVB-LITE platform. This includes
+ specific configurations for the board and its peripherals.
+
+config MACH_ARMADILLO5X0
+ bool "Support Atmark Armadillo-500 Development Base Board"
+ select SOC_IMX31
+ select IMX_HAVE_PLATFORM_GPIO_KEYS
+ select IMX_HAVE_PLATFORM_IMX_I2C
+ select IMX_HAVE_PLATFORM_IMX_UART
+ select IMX_HAVE_PLATFORM_IPU_CORE
+ select IMX_HAVE_PLATFORM_MXC_EHCI
+ select IMX_HAVE_PLATFORM_MXC_MMC
+ select IMX_HAVE_PLATFORM_MXC_NAND
+ select MXC_ULPI if USB_ULPI
+ help
+ Include support for Atmark Armadillo-500 platform. This includes
+ specific configurations for the board and its peripherals.
+
+config MACH_KZM_ARM11_01
+ bool "Support KZM-ARM11-01(Kyoto Microcomputer)"
+ select SOC_IMX31
+ select IMX_HAVE_PLATFORM_IMX_UART
+ help
+ Include support for KZM-ARM11-01. This includes specific
+ configurations for the board and its peripherals.
+
+config MACH_BUG
+ bool "Support Buglabs BUGBase platform"
+ select SOC_IMX31
+ select IMX_HAVE_PLATFORM_IMX_UART
+ default y
+ help
+ Include support for BUGBase 1.3 platform. This includes specific
+ configurations for the board and its peripherals.
+
+comment "MX35 platforms:"
+
+config MACH_PCM043
+ bool "Support Phytec pcm043 (i.MX35) platforms"
+ select SOC_IMX35
+ select IMX_HAVE_PLATFORM_FLEXCAN
+ select IMX_HAVE_PLATFORM_FSL_USB2_UDC
+ select IMX_HAVE_PLATFORM_IMX2_WDT
+ select IMX_HAVE_PLATFORM_IMX_I2C
+ select IMX_HAVE_PLATFORM_IMX_SSI
+ select IMX_HAVE_PLATFORM_IMX_UART
+ select IMX_HAVE_PLATFORM_IPU_CORE
+ select IMX_HAVE_PLATFORM_MXC_EHCI
+ select IMX_HAVE_PLATFORM_MXC_NAND
+ select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
+ select MXC_ULPI if USB_ULPI
+ help
+ Include support for Phytec pcm043 platform. This includes
+ specific configurations for the board and its peripherals.
+
+config MACH_MX35_3DS
+ bool "Support MX35PDK platform"
+ select SOC_IMX35
+ select MXC_DEBUG_BOARD
+ select IMX_HAVE_PLATFORM_FSL_USB2_UDC
+ select IMX_HAVE_PLATFORM_IMX2_WDT
+ select IMX_HAVE_PLATFORM_IMX_I2C
+ select IMX_HAVE_PLATFORM_IMX_UART
+ select IMX_HAVE_PLATFORM_MXC_EHCI
+ select IMX_HAVE_PLATFORM_MXC_NAND
+ select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
+ help
+ Include support for MX35PDK platform. This includes specific
+ configurations for the board and its peripherals.
+
+config MACH_EUKREA_CPUIMX35
+ bool "Support Eukrea CPUIMX35 Platform"
+ select SOC_IMX35
+ select IMX_HAVE_PLATFORM_FLEXCAN
+ select IMX_HAVE_PLATFORM_FSL_USB2_UDC
+ select IMX_HAVE_PLATFORM_IMX2_WDT
+ select IMX_HAVE_PLATFORM_IMX_I2C
+ select IMX_HAVE_PLATFORM_IMX_UART
+ select IMX_HAVE_PLATFORM_MXC_EHCI
+ select IMX_HAVE_PLATFORM_MXC_NAND
+ select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
+ select MXC_ULPI if USB_ULPI
+ help
+ Include support for Eukrea CPUIMX35 platform. This includes
+ specific configurations for the board and its peripherals.
+
+choice
+ prompt "Baseboard"
+ depends on MACH_EUKREA_CPUIMX35
+ default MACH_EUKREA_MBIMXSD35_BASEBOARD
+
+config MACH_EUKREA_MBIMXSD35_BASEBOARD
+ bool "Eukrea MBIMXSD development board"
+ select IMX_HAVE_PLATFORM_GPIO_KEYS
+ select IMX_HAVE_PLATFORM_IMX_SSI
+ select IMX_HAVE_PLATFORM_IPU_CORE
+ help
+ This adds board specific devices that can be found on Eukrea's
+ MBIMXSD evaluation board.
+
+endchoice
+
+config MACH_VPR200
+ bool "Support VPR200 platform"
+ select SOC_IMX35
+ select IMX_HAVE_PLATFORM_FSL_USB2_UDC
+ select IMX_HAVE_PLATFORM_GPIO_KEYS
+ select IMX_HAVE_PLATFORM_IMX2_WDT
+ select IMX_HAVE_PLATFORM_IMX_UART
+ select IMX_HAVE_PLATFORM_IMX_I2C
+ select IMX_HAVE_PLATFORM_IPU_CORE
+ select IMX_HAVE_PLATFORM_MXC_EHCI
+ select IMX_HAVE_PLATFORM_MXC_NAND
+ select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
+ help
+ Include support for VPR200 platform. This includes specific
+ configurations for the board and its peripherals.
+
+endif
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index b85794d27991..e9eb36dad888 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -1,9 +1,3 @@
-#
-# Makefile for the linux kernel.
-#
-
-# Object file lists.
-
obj-$(CONFIG_IMX_HAVE_DMA_V1) += dma-v1.o
obj-$(CONFIG_ARCH_MX1) += clock-imx1.o mm-imx1.o
@@ -14,18 +8,27 @@ obj-$(CONFIG_ARCH_MX25) += clock-imx25.o mm-imx25.o ehci-imx25.o
obj-$(CONFIG_MACH_MX27) += cpu-imx27.o pm-imx27.o
obj-$(CONFIG_MACH_MX27) += clock-imx27.o mm-imx27.o ehci-imx27.o
+obj-$(CONFIG_SOC_IMX31) += mm-imx31.o cpu-imx31.o clock-imx31.o iomux-imx31.o ehci-imx31.o
+obj-$(CONFIG_SOC_IMX35) += mm-imx35.o cpu-imx35.o clock-imx35.o ehci-imx35.o
+obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o
+
# Support for CMOS sensor interface
-obj-$(CONFIG_MX1_VIDEO) += mx1-camera-fiq.o mx1-camera-fiq-ksym.o
+obj-$(CONFIG_MX1_VIDEO) += mx1-camera-fiq.o mx1-camera-fiq-ksym.o
+# i.MX1 based machines
obj-$(CONFIG_ARCH_MX1ADS) += mach-mx1ads.o
obj-$(CONFIG_MACH_SCB9328) += mach-scb9328.o
+obj-$(CONFIG_MACH_APF9328) += mach-apf9328.o
+# i.MX21 based machines
obj-$(CONFIG_MACH_MX21ADS) += mach-mx21ads.o
+# i.MX25 based machines
obj-$(CONFIG_MACH_MX25_3DS) += mach-mx25_3ds.o
obj-$(CONFIG_MACH_EUKREA_CPUIMX25) += mach-eukrea_cpuimx25.o
obj-$(CONFIG_MACH_EUKREA_MBIMXSD25_BASEBOARD) += eukrea_mbimxsd25-baseboard.o
+# i.MX27 based machines
obj-$(CONFIG_MACH_MX27ADS) += mach-mx27ads.o
obj-$(CONFIG_MACH_PCM038) += mach-pcm038.o
obj-$(CONFIG_MACH_PCM970_BASEBOARD) += pcm970-baseboard.o
@@ -37,3 +40,24 @@ obj-$(CONFIG_MACH_EUKREA_MBIMX27_BASEBOARD) += eukrea_mbimx27-baseboard.o
obj-$(CONFIG_MACH_PCA100) += mach-pca100.o
obj-$(CONFIG_MACH_MXT_TD60) += mach-mxt_td60.o
obj-$(CONFIG_MACH_IMX27IPCAM) += mach-imx27ipcam.o
+
+# i.MX31 based machines
+obj-$(CONFIG_MACH_MX31ADS) += mach-mx31ads.o
+obj-$(CONFIG_MACH_MX31LILLY) += mach-mx31lilly.o mx31lilly-db.o
+obj-$(CONFIG_MACH_MX31LITE) += mach-mx31lite.o mx31lite-db.o
+obj-$(CONFIG_MACH_PCM037) += mach-pcm037.o
+obj-$(CONFIG_MACH_PCM037_EET) += mach-pcm037_eet.o
+obj-$(CONFIG_MACH_MX31_3DS) += mach-mx31_3ds.o
+obj-$(CONFIG_MACH_MX31MOBOARD) += mach-mx31moboard.o mx31moboard-devboard.o \
+ mx31moboard-marxbot.o mx31moboard-smartbot.o
+obj-$(CONFIG_MACH_QONG) += mach-qong.o
+obj-$(CONFIG_MACH_ARMADILLO5X0) += mach-armadillo5x0.o
+obj-$(CONFIG_MACH_KZM_ARM11_01) += mach-kzm_arm11_01.o
+obj-$(CONFIG_MACH_BUG) += mach-bug.o
+
+# i.MX35 based machines
+obj-$(CONFIG_MACH_PCM043) += mach-pcm043.o
+obj-$(CONFIG_MACH_MX35_3DS) += mach-mx35_3ds.o
+obj-$(CONFIG_MACH_EUKREA_CPUIMX35) += mach-cpuimx35.o
+obj-$(CONFIG_MACH_EUKREA_MBIMXSD35_BASEBOARD) += eukrea_mbimxsd35-baseboard.o
+obj-$(CONFIG_MACH_VPR200) += mach-vpr200.o
diff --git a/arch/arm/mach-imx/Makefile.boot b/arch/arm/mach-imx/Makefile.boot
index 3953d60bff0b..ebee18b3884c 100644
--- a/arch/arm/mach-imx/Makefile.boot
+++ b/arch/arm/mach-imx/Makefile.boot
@@ -13,3 +13,7 @@ initrd_phys-$(CONFIG_ARCH_MX25) := 0x80800000
zreladdr-$(CONFIG_MACH_MX27) := 0xA0008000
params_phys-$(CONFIG_MACH_MX27) := 0xA0000100
initrd_phys-$(CONFIG_MACH_MX27) := 0xA0800000
+
+zreladdr-$(CONFIG_ARCH_MX3) := 0x80008000
+params_phys-$(CONFIG_ARCH_MX3) := 0x80000100
+initrd_phys-$(CONFIG_ARCH_MX3) := 0x80800000
diff --git a/arch/arm/mach-imx/cache-l2x0.c b/arch/arm/mach-imx/cache-l2x0.c
new file mode 100644
index 000000000000..69d1322add3c
--- /dev/null
+++ b/arch/arm/mach-imx/cache-l2x0.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2009-2010 Pengutronix
+ * Sascha Hauer <s.hauer@pengutronix.de>
+ * Juergen Beisert <j.beisert@pengutronix.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/init.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+
+#include <asm/hardware/cache-l2x0.h>
+
+#include <mach/hardware.h>
+
+static int mxc_init_l2x0(void)
+{
+ void __iomem *l2x0_base;
+ void __iomem *clkctl_base;
+
+ if (!cpu_is_mx31() && !cpu_is_mx35())
+ return 0;
+
+/*
+ * First of all, we must repair broken chip settings. There are some
+ * i.MX35 CPUs in the wild, comming with bogus L2 cache settings. These
+ * misconfigured CPUs will run amok immediately when the L2 cache gets enabled.
+ * Workaraound is to setup the correct register setting prior enabling the
+ * L2 cache. This should not hurt already working CPUs, as they are using the
+ * same value.
+ */
+#define L2_MEM_VAL 0x10
+
+ clkctl_base = ioremap(MX35_CLKCTL_BASE_ADDR, 4096);
+ if (clkctl_base != NULL) {
+ writel(0x00000515, clkctl_base + L2_MEM_VAL);
+ iounmap(clkctl_base);
+ } else {
+ pr_err("L2 cache: Cannot fix timing. Trying to continue without\n");
+ }
+
+ l2x0_base = ioremap(MX3x_L2CC_BASE_ADDR, 4096);
+ if (IS_ERR(l2x0_base)) {
+ printk(KERN_ERR "remapping L2 cache area failed with %ld\n",
+ PTR_ERR(l2x0_base));
+ return 0;
+ }
+
+ l2x0_init(l2x0_base, 0x00030024, 0x00000000);
+
+ return 0;
+}
+arch_initcall(mxc_init_l2x0);
diff --git a/arch/arm/mach-mx3/clock-imx31.c b/arch/arm/mach-imx/clock-imx31.c
index d423cac8cab7..25f343fca2b9 100644
--- a/arch/arm/mach-mx3/clock-imx31.c
+++ b/arch/arm/mach-imx/clock-imx31.c
@@ -32,7 +32,7 @@
#include <mach/mx31.h>
#include <mach/common.h>
-#include "crm_regs.h"
+#include "crmregs-imx31.h"
#define PRE_DIV_MIN_FREQ 10000000 /* Minimum Frequency after Predivider */
@@ -627,4 +627,3 @@ int __init mx31_clocks_init(unsigned long fref)
return 0;
}
-
diff --git a/arch/arm/mach-mx3/clock-imx35.c b/arch/arm/mach-imx/clock-imx35.c
index 448a038cd1ec..5a4cc1ea405b 100644
--- a/arch/arm/mach-mx3/clock-imx35.c
+++ b/arch/arm/mach-imx/clock-imx35.c
@@ -547,4 +547,3 @@ int __init mx35_clocks_init()
return 0;
}
-
diff --git a/arch/arm/mach-mx3/cpu.c b/arch/arm/mach-imx/cpu-imx31.c
index d1d339576fdf..a3780700a882 100644
--- a/arch/arm/mach-mx3/cpu.c
+++ b/arch/arm/mach-imx/cpu-imx31.c
@@ -1,5 +1,5 @@
/*
- * MX3 CPU type detection
+ * MX31 CPU type detection
*
* Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
*
@@ -17,14 +17,12 @@
unsigned int mx31_cpu_rev;
EXPORT_SYMBOL(mx31_cpu_rev);
-struct mx3_cpu_type {
+static struct {
u8 srev;
const char *name;
const char *v;
unsigned int rev;
-};
-
-static struct mx3_cpu_type mx31_cpu_type[] __initdata = {
+} mx31_cpu_type[] __initdata = {
{ .srev = 0x00, .name = "i.MX31(L)", .v = "1.0", .rev = IMX_CHIP_REVISION_1_0 },
{ .srev = 0x10, .name = "i.MX31", .v = "1.1", .rev = IMX_CHIP_REVISION_1_1 },
{ .srev = 0x11, .name = "i.MX31L", .v = "1.1", .rev = IMX_CHIP_REVISION_1_1 },
@@ -57,33 +55,3 @@ void __init mx31_read_cpu_rev(void)
printk(KERN_WARNING "Unknown CPU identifier. srev = %02x\n", srev);
}
-
-unsigned int mx35_cpu_rev;
-EXPORT_SYMBOL(mx35_cpu_rev);
-
-void __init mx35_read_cpu_rev(void)
-{
- u32 rev;
- char *srev;
-
- rev = __raw_readl(MX35_IO_ADDRESS(MX35_IIM_BASE_ADDR + MXC_IIMSREV));
- switch (rev) {
- case 0x00:
- mx35_cpu_rev = IMX_CHIP_REVISION_1_0;
- srev = "1.0";
- break;
- case 0x10:
- mx35_cpu_rev = IMX_CHIP_REVISION_2_0;
- srev = "2.0";
- break;
- case 0x11:
- mx35_cpu_rev = IMX_CHIP_REVISION_2_1;
- srev = "2.1";
- break;
- default:
- mx35_cpu_rev = IMX_CHIP_REVISION_UNKNOWN;
- srev = "unknown";
- }
-
- printk(KERN_INFO "CPU identified as i.MX35, silicon rev %s\n", srev);
-}
diff --git a/arch/arm/mach-imx/cpu-imx35.c b/arch/arm/mach-imx/cpu-imx35.c
new file mode 100644
index 000000000000..6637cd819ecb
--- /dev/null
+++ b/arch/arm/mach-imx/cpu-imx35.c
@@ -0,0 +1,44 @@
+/*
+ * MX35 CPU type detection
+ *
+ * Copyright (c) 2009 Daniel Mack <daniel@caiaq.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/io.h>
+#include <mach/hardware.h>
+#include <mach/iim.h>
+
+unsigned int mx35_cpu_rev;
+EXPORT_SYMBOL(mx35_cpu_rev);
+
+void __init mx35_read_cpu_rev(void)
+{
+ u32 rev;
+ char *srev;
+
+ rev = __raw_readl(MX35_IO_ADDRESS(MX35_IIM_BASE_ADDR + MXC_IIMSREV));
+ switch (rev) {
+ case 0x00:
+ mx35_cpu_rev = IMX_CHIP_REVISION_1_0;
+ srev = "1.0";
+ break;
+ case 0x10:
+ mx35_cpu_rev = IMX_CHIP_REVISION_2_0;
+ srev = "2.0";
+ break;
+ case 0x11:
+ mx35_cpu_rev = IMX_CHIP_REVISION_2_1;
+ srev = "2.1";
+ break;
+ default:
+ mx35_cpu_rev = IMX_CHIP_REVISION_UNKNOWN;
+ srev = "unknown";
+ }
+
+ printk(KERN_INFO "CPU identified as i.MX35, silicon rev %s\n", srev);
+}
diff --git a/arch/arm/mach-mx3/crm_regs.h b/arch/arm/mach-imx/crmregs-imx31.h
index 37a8a07beda3..37a8a07beda3 100644
--- a/arch/arm/mach-mx3/crm_regs.h
+++ b/arch/arm/mach-imx/crmregs-imx31.h
diff --git a/arch/arm/mach-imx/devices-imx1.h b/arch/arm/mach-imx/devices-imx1.h
index da593657ff3f..3aad1e70de96 100644
--- a/arch/arm/mach-imx/devices-imx1.h
+++ b/arch/arm/mach-imx/devices-imx1.h
@@ -9,21 +9,21 @@
#include <mach/mx1.h>
#include <mach/devices-common.h>
-extern const struct imx_imx_fb_data imx1_imx_fb_data __initconst;
+extern const struct imx_imx_fb_data imx1_imx_fb_data;
#define imx1_add_imx_fb(pdata) \
imx_add_imx_fb(&imx1_imx_fb_data, pdata)
-extern const struct imx_imx_i2c_data imx1_imx_i2c_data __initconst;
+extern const struct imx_imx_i2c_data imx1_imx_i2c_data;
#define imx1_add_imx_i2c(pdata) \
imx_add_imx_i2c(&imx1_imx_i2c_data, pdata)
-extern const struct imx_imx_uart_3irq_data imx1_imx_uart_data[] __initconst;
+extern const struct imx_imx_uart_3irq_data imx1_imx_uart_data[];
#define imx1_add_imx_uart(id, pdata) \
imx_add_imx_uart_3irq(&imx1_imx_uart_data[id], pdata)
#define imx1_add_imx_uart0(pdata) imx1_add_imx_uart(0, pdata)
#define imx1_add_imx_uart1(pdata) imx1_add_imx_uart(1, pdata)
-extern const struct imx_spi_imx_data imx1_cspi_data[] __initconst;
+extern const struct imx_spi_imx_data imx1_cspi_data[];
#define imx1_add_cspi(id, pdata) \
imx_add_spi_imx(&imx1_cspi_data[id], pdata)
diff --git a/arch/arm/mach-imx/devices-imx21.h b/arch/arm/mach-imx/devices-imx21.h
index 16744d2d9b81..2628e0c474dc 100644
--- a/arch/arm/mach-imx/devices-imx21.h
+++ b/arch/arm/mach-imx/devices-imx21.h
@@ -9,31 +9,31 @@
#include <mach/mx21.h>
#include <mach/devices-common.h>
-extern const struct imx_imx21_hcd_data imx21_imx21_hcd_data __initconst;
+extern const struct imx_imx21_hcd_data imx21_imx21_hcd_data;
#define imx21_add_imx21_hcd(pdata) \
imx_add_imx21_hcd(&imx21_imx21_hcd_data, pdata)
-extern const struct imx_imx2_wdt_data imx21_imx2_wdt_data __initconst;
+extern const struct imx_imx2_wdt_data imx21_imx2_wdt_data;
#define imx21_add_imx2_wdt(pdata) \
imx_add_imx2_wdt(&imx21_imx2_wdt_data)
-extern const struct imx_imx_fb_data imx21_imx_fb_data __initconst;
+extern const struct imx_imx_fb_data imx21_imx_fb_data;
#define imx21_add_imx_fb(pdata) \
imx_add_imx_fb(&imx21_imx_fb_data, pdata)
-extern const struct imx_imx_i2c_data imx21_imx_i2c_data __initconst;
+extern const struct imx_imx_i2c_data imx21_imx_i2c_data;
#define imx21_add_imx_i2c(pdata) \
imx_add_imx_i2c(&imx21_imx_i2c_data, pdata)
-extern const struct imx_imx_keypad_data imx21_imx_keypad_data __initconst;
+extern const struct imx_imx_keypad_data imx21_imx_keypad_data;
#define imx21_add_imx_keypad(pdata) \
imx_add_imx_keypad(&imx21_imx_keypad_data, pdata)
-extern const struct imx_imx_ssi_data imx21_imx_ssi_data[] __initconst;
+extern const struct imx_imx_ssi_data imx21_imx_ssi_data[];
#define imx21_add_imx_ssi(id, pdata) \
imx_add_imx_ssi(&imx21_imx_ssi_data[id], pdata)
-extern const struct imx_imx_uart_1irq_data imx21_imx_uart_data[] __initconst;
+extern const struct imx_imx_uart_1irq_data imx21_imx_uart_data[];
#define imx21_add_imx_uart(id, pdata) \
imx_add_imx_uart_1irq(&imx21_imx_uart_data[id], pdata)
#define imx21_add_imx_uart0(pdata) imx21_add_imx_uart(0, pdata)
@@ -41,19 +41,19 @@ extern const struct imx_imx_uart_1irq_data imx21_imx_uart_data[] __initconst;
#define imx21_add_imx_uart2(pdata) imx21_add_imx_uart(2, pdata)
#define imx21_add_imx_uart3(pdata) imx21_add_imx_uart(3, pdata)
-extern const struct imx_mxc_mmc_data imx21_mxc_mmc_data[] __initconst;
+extern const struct imx_mxc_mmc_data imx21_mxc_mmc_data[];
#define imx21_add_mxc_mmc(id, pdata) \
imx_add_mxc_mmc(&imx21_mxc_mmc_data[id], pdata)
-extern const struct imx_mxc_nand_data imx21_mxc_nand_data __initconst;
+extern const struct imx_mxc_nand_data imx21_mxc_nand_data;
#define imx21_add_mxc_nand(pdata) \
imx_add_mxc_nand(&imx21_mxc_nand_data, pdata)
-extern const struct imx_mxc_w1_data imx21_mxc_w1_data __initconst;
+extern const struct imx_mxc_w1_data imx21_mxc_w1_data;
#define imx21_add_mxc_w1(pdata) \
imx_add_mxc_w1(&imx21_mxc_w1_data)
-extern const struct imx_spi_imx_data imx21_cspi_data[] __initconst;
+extern const struct imx_spi_imx_data imx21_cspi_data[];
#define imx21_add_cspi(id, pdata) \
imx_add_spi_imx(&imx21_cspi_data[id], pdata)
#define imx21_add_spi_imx0(pdata) imx21_add_cspi(0, pdata)
diff --git a/arch/arm/mach-imx/devices-imx25.h b/arch/arm/mach-imx/devices-imx25.h
index b591d72f6037..efa0761c508d 100644
--- a/arch/arm/mach-imx/devices-imx25.h
+++ b/arch/arm/mach-imx/devices-imx25.h
@@ -9,48 +9,48 @@
#include <mach/mx25.h>
#include <mach/devices-common.h>
-extern const struct imx_fec_data imx25_fec_data __initconst;
+extern const struct imx_fec_data imx25_fec_data;
#define imx25_add_fec(pdata) \
imx_add_fec(&imx25_fec_data, pdata)
-extern const struct imx_flexcan_data imx25_flexcan_data[] __initconst;
+extern const struct imx_flexcan_data imx25_flexcan_data[];
#define imx25_add_flexcan(id, pdata) \
imx_add_flexcan(&imx25_flexcan_data[id], pdata)
#define imx25_add_flexcan0(pdata) imx25_add_flexcan(0, pdata)
#define imx25_add_flexcan1(pdata) imx25_add_flexcan(1, pdata)
-extern const struct imx_fsl_usb2_udc_data imx25_fsl_usb2_udc_data __initconst;
+extern const struct imx_fsl_usb2_udc_data imx25_fsl_usb2_udc_data;
#define imx25_add_fsl_usb2_udc(pdata) \
imx_add_fsl_usb2_udc(&imx25_fsl_usb2_udc_data, pdata)
-extern struct imx_imxdi_rtc_data imx25_imxdi_rtc_data __initconst;
+extern struct imx_imxdi_rtc_data imx25_imxdi_rtc_data;
#define imx25_add_imxdi_rtc(pdata) \
imx_add_imxdi_rtc(&imx25_imxdi_rtc_data)
-extern const struct imx_imx2_wdt_data imx25_imx2_wdt_data __initconst;
+extern const struct imx_imx2_wdt_data imx25_imx2_wdt_data;
#define imx25_add_imx2_wdt(pdata) \
imx_add_imx2_wdt(&imx25_imx2_wdt_data)
-extern const struct imx_imx_fb_data imx25_imx_fb_data __initconst;
+extern const struct imx_imx_fb_data imx25_imx_fb_data;
#define imx25_add_imx_fb(pdata) \
imx_add_imx_fb(&imx25_imx_fb_data, pdata)
-extern const struct imx_imx_i2c_data imx25_imx_i2c_data[] __initconst;
+extern const struct imx_imx_i2c_data imx25_imx_i2c_data[];
#define imx25_add_imx_i2c(id, pdata) \
imx_add_imx_i2c(&imx25_imx_i2c_data[id], pdata)
#define imx25_add_imx_i2c0(pdata) imx25_add_imx_i2c(0, pdata)
#define imx25_add_imx_i2c1(pdata) imx25_add_imx_i2c(1, pdata)
#define imx25_add_imx_i2c2(pdata) imx25_add_imx_i2c(2, pdata)
-extern const struct imx_imx_keypad_data imx25_imx_keypad_data __initconst;
+extern const struct imx_imx_keypad_data imx25_imx_keypad_data;
#define imx25_add_imx_keypad(pdata) \
imx_add_imx_keypad(&imx25_imx_keypad_data, pdata)
-extern const struct imx_imx_ssi_data imx25_imx_ssi_data[] __initconst;
+extern const struct imx_imx_ssi_data imx25_imx_ssi_data[];
#define imx25_add_imx_ssi(id, pdata) \
imx_add_imx_ssi(&imx25_imx_ssi_data[id], pdata)
-extern const struct imx_imx_uart_1irq_data imx25_imx_uart_data[] __initconst;
+extern const struct imx_imx_uart_1irq_data imx25_imx_uart_data[];
#define imx25_add_imx_uart(id, pdata) \
imx_add_imx_uart_1irq(&imx25_imx_uart_data[id], pdata)
#define imx25_add_imx_uart0(pdata) imx25_add_imx_uart(0, pdata)
@@ -59,33 +59,32 @@ extern const struct imx_imx_uart_1irq_data imx25_imx_uart_data[] __initconst;
#define imx25_add_imx_uart3(pdata) imx25_add_imx_uart(3, pdata)
#define imx25_add_imx_uart4(pdata) imx25_add_imx_uart(4, pdata)
-extern const struct imx_mx2_camera_data imx25_mx2_camera_data __initconst;
+extern const struct imx_mx2_camera_data imx25_mx2_camera_data;
#define imx25_add_mx2_camera(pdata) \
imx_add_mx2_camera(&imx25_mx2_camera_data, pdata)
-extern const struct imx_mxc_ehci_data imx25_mxc_ehci_otg_data __initconst;
+extern const struct imx_mxc_ehci_data imx25_mxc_ehci_otg_data;
#define imx25_add_mxc_ehci_otg(pdata) \
imx_add_mxc_ehci(&imx25_mxc_ehci_otg_data, pdata)
-extern const struct imx_mxc_ehci_data imx25_mxc_ehci_hs_data __initconst;
+extern const struct imx_mxc_ehci_data imx25_mxc_ehci_hs_data;
#define imx25_add_mxc_ehci_hs(pdata) \
imx_add_mxc_ehci(&imx25_mxc_ehci_hs_data, pdata)
-extern const struct imx_mxc_nand_data imx25_mxc_nand_data __initconst;
+extern const struct imx_mxc_nand_data imx25_mxc_nand_data;
#define imx25_add_mxc_nand(pdata) \
imx_add_mxc_nand(&imx25_mxc_nand_data, pdata)
-extern const struct imx_sdhci_esdhc_imx_data
-imx25_sdhci_esdhc_imx_data[] __initconst;
+extern const struct imx_sdhci_esdhc_imx_data imx25_sdhci_esdhc_imx_data[];
#define imx25_add_sdhci_esdhc_imx(id, pdata) \
imx_add_sdhci_esdhc_imx(&imx25_sdhci_esdhc_imx_data[id], pdata)
-extern const struct imx_spi_imx_data imx25_cspi_data[] __initconst;
+extern const struct imx_spi_imx_data imx25_cspi_data[];
#define imx25_add_spi_imx(id, pdata) \
imx_add_spi_imx(&imx25_cspi_data[id], pdata)
#define imx25_add_spi_imx0(pdata) imx25_add_spi_imx(0, pdata)
#define imx25_add_spi_imx1(pdata) imx25_add_spi_imx(1, pdata)
#define imx25_add_spi_imx2(pdata) imx25_add_spi_imx(2, pdata)
-extern struct imx_mxc_pwm_data imx25_mxc_pwm_data[] __initconst;
+extern struct imx_mxc_pwm_data imx25_mxc_pwm_data[];
#define imx25_add_mxc_pwm(id) \
imx_add_mxc_pwm(&imx25_mxc_pwm_data[id])
diff --git a/arch/arm/mach-imx/devices-imx27.h b/arch/arm/mach-imx/devices-imx27.h
index f1272d4b5a33..7f97a3cdd41d 100644
--- a/arch/arm/mach-imx/devices-imx27.h
+++ b/arch/arm/mach-imx/devices-imx27.h
@@ -9,35 +9,35 @@
#include <mach/mx27.h>
#include <mach/devices-common.h>
-extern const struct imx_fec_data imx27_fec_data __initconst;
+extern const struct imx_fec_data imx27_fec_data;
#define imx27_add_fec(pdata) \
imx_add_fec(&imx27_fec_data, pdata)
-extern const struct imx_fsl_usb2_udc_data imx27_fsl_usb2_udc_data __initconst;
+extern const struct imx_fsl_usb2_udc_data imx27_fsl_usb2_udc_data;
#define imx27_add_fsl_usb2_udc(pdata) \
imx_add_fsl_usb2_udc(&imx27_fsl_usb2_udc_data, pdata)
-extern const struct imx_imx2_wdt_data imx27_imx2_wdt_data __initconst;
+extern const struct imx_imx2_wdt_data imx27_imx2_wdt_data;
#define imx27_add_imx2_wdt(pdata) \
imx_add_imx2_wdt(&imx27_imx2_wdt_data)
-extern const struct imx_imx_fb_data imx27_imx_fb_data __initconst;
+extern const struct imx_imx_fb_data imx27_imx_fb_data;
#define imx27_add_imx_fb(pdata) \
imx_add_imx_fb(&imx27_imx_fb_data, pdata)
-extern const struct imx_imx_i2c_data imx27_imx_i2c_data[] __initconst;
+extern const struct imx_imx_i2c_data imx27_imx_i2c_data[];
#define imx27_add_imx_i2c(id, pdata) \
imx_add_imx_i2c(&imx27_imx_i2c_data[id], pdata)
-extern const struct imx_imx_keypad_data imx27_imx_keypad_data __initconst;
+extern const struct imx_imx_keypad_data imx27_imx_keypad_data;
#define imx27_add_imx_keypad(pdata) \
imx_add_imx_keypad(&imx27_imx_keypad_data, pdata)
-extern const struct imx_imx_ssi_data imx27_imx_ssi_data[] __initconst;
+extern const struct imx_imx_ssi_data imx27_imx_ssi_data[];
#define imx27_add_imx_ssi(id, pdata) \
imx_add_imx_ssi(&imx27_imx_ssi_data[id], pdata)
-extern const struct imx_imx_uart_1irq_data imx27_imx_uart_data[] __initconst;
+extern const struct imx_imx_uart_1irq_data imx27_imx_uart_data[];
#define imx27_add_imx_uart(id, pdata) \
imx_add_imx_uart_1irq(&imx27_imx_uart_data[id], pdata)
#define imx27_add_imx_uart0(pdata) imx27_add_imx_uart(0, pdata)
@@ -47,30 +47,30 @@ extern const struct imx_imx_uart_1irq_data imx27_imx_uart_data[] __initconst;
#define imx27_add_imx_uart4(pdata) imx27_add_imx_uart(4, pdata)
#define imx27_add_imx_uart5(pdata) imx27_add_imx_uart(5, pdata)
-extern const struct imx_mx2_camera_data imx27_mx2_camera_data __initconst;
+extern const struct imx_mx2_camera_data imx27_mx2_camera_data;
#define imx27_add_mx2_camera(pdata) \
imx_add_mx2_camera(&imx27_mx2_camera_data, pdata)
-extern const struct imx_mxc_ehci_data imx27_mxc_ehci_otg_data __initconst;
+extern const struct imx_mxc_ehci_data imx27_mxc_ehci_otg_data;
#define imx27_add_mxc_ehci_otg(pdata) \
imx_add_mxc_ehci(&imx27_mxc_ehci_otg_data, pdata)
-extern const struct imx_mxc_ehci_data imx27_mxc_ehci_hs_data[] __initconst;
+extern const struct imx_mxc_ehci_data imx27_mxc_ehci_hs_data[];
#define imx27_add_mxc_ehci_hs(id, pdata) \
imx_add_mxc_ehci(&imx27_mxc_ehci_hs_data[id - 1], pdata)
-extern const struct imx_mxc_mmc_data imx27_mxc_mmc_data[] __initconst;
+extern const struct imx_mxc_mmc_data imx27_mxc_mmc_data[];
#define imx27_add_mxc_mmc(id, pdata) \
imx_add_mxc_mmc(&imx27_mxc_mmc_data[id], pdata)
-extern const struct imx_mxc_nand_data imx27_mxc_nand_data __initconst;
+extern const struct imx_mxc_nand_data imx27_mxc_nand_data;
#define imx27_add_mxc_nand(pdata) \
imx_add_mxc_nand(&imx27_mxc_nand_data, pdata)
-extern const struct imx_mxc_w1_data imx27_mxc_w1_data __initconst;
+extern const struct imx_mxc_w1_data imx27_mxc_w1_data;
#define imx27_add_mxc_w1(pdata) \
imx_add_mxc_w1(&imx27_mxc_w1_data)
-extern const struct imx_spi_imx_data imx27_cspi_data[] __initconst;
+extern const struct imx_spi_imx_data imx27_cspi_data[];
#define imx27_add_cspi(id, pdata) \
imx_add_spi_imx(&imx27_cspi_data[id], pdata)
#define imx27_add_spi_imx0(pdata) imx27_add_cspi(0, pdata)
diff --git a/arch/arm/mach-mx3/devices-imx31.h b/arch/arm/mach-imx/devices-imx31.h
index 40f4e848a671..dbe940d9c53a 100644
--- a/arch/arm/mach-mx3/devices-imx31.h
+++ b/arch/arm/mach-imx/devices-imx31.h
@@ -9,30 +9,30 @@
#include <mach/mx31.h>
#include <mach/devices-common.h>
-extern const struct imx_fsl_usb2_udc_data imx31_fsl_usb2_udc_data __initconst;
+extern const struct imx_fsl_usb2_udc_data imx31_fsl_usb2_udc_data;
#define imx31_add_fsl_usb2_udc(pdata) \
imx_add_fsl_usb2_udc(&imx31_fsl_usb2_udc_data, pdata)
-extern const struct imx_imx2_wdt_data imx31_imx2_wdt_data __initconst;
+extern const struct imx_imx2_wdt_data imx31_imx2_wdt_data;
#define imx31_add_imx2_wdt(pdata) \
imx_add_imx2_wdt(&imx31_imx2_wdt_data)
-extern const struct imx_imx_i2c_data imx31_imx_i2c_data[] __initconst;
+extern const struct imx_imx_i2c_data imx31_imx_i2c_data[];
#define imx31_add_imx_i2c(id, pdata) \
imx_add_imx_i2c(&imx31_imx_i2c_data[id], pdata)
#define imx31_add_imx_i2c0(pdata) imx31_add_imx_i2c(0, pdata)
#define imx31_add_imx_i2c1(pdata) imx31_add_imx_i2c(1, pdata)
#define imx31_add_imx_i2c2(pdata) imx31_add_imx_i2c(2, pdata)
-extern const struct imx_imx_keypad_data imx31_imx_keypad_data __initconst;
+extern const struct imx_imx_keypad_data imx31_imx_keypad_data;
#define imx31_add_imx_keypad(pdata) \
imx_add_imx_keypad(&imx31_imx_keypad_data, pdata)
-extern const struct imx_imx_ssi_data imx31_imx_ssi_data[] __initconst;
+extern const struct imx_imx_ssi_data imx31_imx_ssi_data[];
#define imx31_add_imx_ssi(id, pdata) \
imx_add_imx_ssi(&imx31_imx_ssi_data[id], pdata)
-extern const struct imx_imx_uart_1irq_data imx31_imx_uart_data[] __initconst;
+extern const struct imx_imx_uart_1irq_data imx31_imx_uart_data[];
#define imx31_add_imx_uart(id, pdata) \
imx_add_imx_uart_1irq(&imx31_imx_uart_data[id], pdata)
#define imx31_add_imx_uart0(pdata) imx31_add_imx_uart(0, pdata)
@@ -41,26 +41,38 @@ extern const struct imx_imx_uart_1irq_data imx31_imx_uart_data[] __initconst;
#define imx31_add_imx_uart3(pdata) imx31_add_imx_uart(3, pdata)
#define imx31_add_imx_uart4(pdata) imx31_add_imx_uart(4, pdata)
-extern const struct imx_mxc_ehci_data imx31_mxc_ehci_otg_data __initconst;
+extern const struct imx_ipu_core_data imx31_ipu_core_data;
+#define imx31_add_ipu_core(pdata) \
+ imx_add_ipu_core(&imx31_ipu_core_data, pdata)
+#define imx31_alloc_mx3_camera(pdata) \
+ imx_alloc_mx3_camera(&imx31_ipu_core_data, pdata)
+#define imx31_add_mx3_sdc_fb(pdata) \
+ imx_add_mx3_sdc_fb(&imx31_ipu_core_data, pdata)
+
+extern const struct imx_mxc_ehci_data imx31_mxc_ehci_otg_data;
#define imx31_add_mxc_ehci_otg(pdata) \
imx_add_mxc_ehci(&imx31_mxc_ehci_otg_data, pdata)
-extern const struct imx_mxc_ehci_data imx31_mxc_ehci_hs_data[] __initconst;
+extern const struct imx_mxc_ehci_data imx31_mxc_ehci_hs_data[];
#define imx31_add_mxc_ehci_hs(id, pdata) \
imx_add_mxc_ehci(&imx31_mxc_ehci_hs_data[id - 1], pdata)
-extern const struct imx_mxc_mmc_data imx31_mxc_mmc_data[] __initconst;
+extern const struct imx_mxc_mmc_data imx31_mxc_mmc_data[];
#define imx31_add_mxc_mmc(id, pdata) \
imx_add_mxc_mmc(&imx31_mxc_mmc_data[id], pdata)
-extern const struct imx_mxc_nand_data imx31_mxc_nand_data __initconst;
+extern const struct imx_mxc_nand_data imx31_mxc_nand_data;
#define imx31_add_mxc_nand(pdata) \
imx_add_mxc_nand(&imx31_mxc_nand_data, pdata)
-extern const struct imx_mxc_w1_data imx31_mxc_w1_data __initconst;
+extern const struct imx_mxc_rtc_data imx31_mxc_rtc_data;
+#define imx31_add_mxc_rtc(pdata) \
+ imx_add_mxc_rtc(&imx31_mxc_rtc_data)
+
+extern const struct imx_mxc_w1_data imx31_mxc_w1_data;
#define imx31_add_mxc_w1(pdata) \
imx_add_mxc_w1(&imx31_mxc_w1_data)
-extern const struct imx_spi_imx_data imx31_cspi_data[] __initconst;
+extern const struct imx_spi_imx_data imx31_cspi_data[];
#define imx31_add_cspi(id, pdata) \
imx_add_spi_imx(&imx31_cspi_data[id], pdata)
#define imx31_add_spi_imx0(pdata) imx31_add_cspi(0, pdata)
diff --git a/arch/arm/mach-mx3/devices-imx35.h b/arch/arm/mach-imx/devices-imx35.h
index d545d86cc202..234cbd3c18af 100644
--- a/arch/arm/mach-mx3/devices-imx35.h
+++ b/arch/arm/mach-imx/devices-imx35.h
@@ -9,67 +9,74 @@
#include <mach/mx35.h>
#include <mach/devices-common.h>
-extern const struct imx_fec_data imx35_fec_data __initconst;
+extern const struct imx_fec_data imx35_fec_data;
#define imx35_add_fec(pdata) \
imx_add_fec(&imx35_fec_data, pdata)
-extern const struct imx_fsl_usb2_udc_data imx35_fsl_usb2_udc_data __initconst;
+extern const struct imx_fsl_usb2_udc_data imx35_fsl_usb2_udc_data;
#define imx35_add_fsl_usb2_udc(pdata) \
imx_add_fsl_usb2_udc(&imx35_fsl_usb2_udc_data, pdata)
-extern const struct imx_flexcan_data imx35_flexcan_data[] __initconst;
+extern const struct imx_flexcan_data imx35_flexcan_data[];
#define imx35_add_flexcan(id, pdata) \
imx_add_flexcan(&imx35_flexcan_data[id], pdata)
#define imx35_add_flexcan0(pdata) imx35_add_flexcan(0, pdata)
#define imx35_add_flexcan1(pdata) imx35_add_flexcan(1, pdata)
-extern const struct imx_imx2_wdt_data imx35_imx2_wdt_data __initconst;
+extern const struct imx_imx2_wdt_data imx35_imx2_wdt_data;
#define imx35_add_imx2_wdt(pdata) \
imx_add_imx2_wdt(&imx35_imx2_wdt_data)
-extern const struct imx_imx_i2c_data imx35_imx_i2c_data[] __initconst;
+extern const struct imx_imx_i2c_data imx35_imx_i2c_data[];
#define imx35_add_imx_i2c(id, pdata) \
imx_add_imx_i2c(&imx35_imx_i2c_data[id], pdata)
#define imx35_add_imx_i2c0(pdata) imx35_add_imx_i2c(0, pdata)
#define imx35_add_imx_i2c1(pdata) imx35_add_imx_i2c(1, pdata)
#define imx35_add_imx_i2c2(pdata) imx35_add_imx_i2c(2, pdata)
-extern const struct imx_imx_keypad_data imx35_imx_keypad_data __initconst;
+extern const struct imx_imx_keypad_data imx35_imx_keypad_data;
#define imx35_add_imx_keypad(pdata) \
imx_add_imx_keypad(&imx35_imx_keypad_data, pdata)
-extern const struct imx_imx_ssi_data imx35_imx_ssi_data[] __initconst;
+extern const struct imx_imx_ssi_data imx35_imx_ssi_data[];
#define imx35_add_imx_ssi(id, pdata) \
imx_add_imx_ssi(&imx35_imx_ssi_data[id], pdata)
-extern const struct imx_imx_uart_1irq_data imx35_imx_uart_data[] __initconst;
+extern const struct imx_imx_uart_1irq_data imx35_imx_uart_data[];
#define imx35_add_imx_uart(id, pdata) \
imx_add_imx_uart_1irq(&imx35_imx_uart_data[id], pdata)
#define imx35_add_imx_uart0(pdata) imx35_add_imx_uart(0, pdata)
#define imx35_add_imx_uart1(pdata) imx35_add_imx_uart(1, pdata)
#define imx35_add_imx_uart2(pdata) imx35_add_imx_uart(2, pdata)
-extern const struct imx_mxc_ehci_data imx35_mxc_ehci_otg_data __initconst;
+extern const struct imx_ipu_core_data imx35_ipu_core_data;
+#define imx35_add_ipu_core(pdata) \
+ imx_add_ipu_core(&imx35_ipu_core_data, pdata)
+#define imx35_alloc_mx3_camera(pdata) \
+ imx_alloc_mx3_camera(&imx35_ipu_core_data, pdata)
+#define imx35_add_mx3_sdc_fb(pdata) \
+ imx_add_mx3_sdc_fb(&imx35_ipu_core_data, pdata)
+
+extern const struct imx_mxc_ehci_data imx35_mxc_ehci_otg_data;
#define imx35_add_mxc_ehci_otg(pdata) \
imx_add_mxc_ehci(&imx35_mxc_ehci_otg_data, pdata)
-extern const struct imx_mxc_ehci_data imx35_mxc_ehci_hs_data __initconst;
+extern const struct imx_mxc_ehci_data imx35_mxc_ehci_hs_data;
#define imx35_add_mxc_ehci_hs(pdata) \
imx_add_mxc_ehci(&imx35_mxc_ehci_hs_data, pdata)
-extern const struct imx_mxc_nand_data imx35_mxc_nand_data __initconst;
+extern const struct imx_mxc_nand_data imx35_mxc_nand_data;
#define imx35_add_mxc_nand(pdata) \
imx_add_mxc_nand(&imx35_mxc_nand_data, pdata)
-extern const struct imx_mxc_w1_data imx35_mxc_w1_data __initconst;
+extern const struct imx_mxc_w1_data imx35_mxc_w1_data;
#define imx35_add_mxc_w1(pdata) \
imx_add_mxc_w1(&imx35_mxc_w1_data)
-extern const struct imx_sdhci_esdhc_imx_data
-imx35_sdhci_esdhc_imx_data[] __initconst;
+extern const struct imx_sdhci_esdhc_imx_data imx35_sdhci_esdhc_imx_data[];
#define imx35_add_sdhci_esdhc_imx(id, pdata) \
imx_add_sdhci_esdhc_imx(&imx35_sdhci_esdhc_imx_data[id], pdata)
-extern const struct imx_spi_imx_data imx35_cspi_data[] __initconst;
+extern const struct imx_spi_imx_data imx35_cspi_data[];
#define imx35_add_cspi(id, pdata) \
imx_add_spi_imx(&imx35_cspi_data[id], pdata)
#define imx35_add_spi_imx0(pdata) imx35_add_cspi(0, pdata)
diff --git a/arch/arm/mach-mx3/ehci-imx31.c b/arch/arm/mach-imx/ehci-imx31.c
index 314a983ac614..faad0f15ac7f 100644
--- a/arch/arm/mach-mx3/ehci-imx31.c
+++ b/arch/arm/mach-imx/ehci-imx31.c
@@ -80,4 +80,3 @@ int mx31_initialize_usb_hw(int port, unsigned int flags)
return 0;
}
-
diff --git a/arch/arm/mach-mx3/ehci-imx35.c b/arch/arm/mach-imx/ehci-imx35.c
index 33983a478c6b..001ec3971f5d 100644
--- a/arch/arm/mach-mx3/ehci-imx35.c
+++ b/arch/arm/mach-imx/ehci-imx35.c
@@ -77,4 +77,3 @@ int mx35_initialize_usb_hw(int port, unsigned int flags)
return 0;
}
-
diff --git a/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c b/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c
index fa5288018ba7..5911281da5f5 100644
--- a/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c
+++ b/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c
@@ -32,7 +32,6 @@
#include <mach/common.h>
#include <mach/iomux-mx27.h>
#include <mach/hardware.h>
-#include <mach/spi.h>
#include <mach/audmux.h>
#include "devices-imx27.h"
diff --git a/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c b/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c
index 6269053505f7..f9ef04acdab1 100644
--- a/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c
+++ b/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c
@@ -22,7 +22,6 @@
#include <linux/gpio.h>
#include <linux/leds.h>
#include <linux/platform_device.h>
-#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <video/platform_lcd.h>
@@ -32,9 +31,7 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <mach/mx25.h>
-#include <mach/imx-uart.h>
#include <mach/audmux.h>
-#include <mach/esdhc.h>
#include "devices-imx25.h"
@@ -208,23 +205,14 @@ static struct gpio_keys_button eukrea_mbimxsd_gpio_buttons[] = {
},
};
-static struct gpio_keys_platform_data eukrea_mbimxsd_button_data = {
+static const struct gpio_keys_platform_data
+ eukrea_mbimxsd_button_data __initconst = {
.buttons = eukrea_mbimxsd_gpio_buttons,
.nbuttons = ARRAY_SIZE(eukrea_mbimxsd_gpio_buttons),
};
-static struct platform_device eukrea_mbimxsd_button_device = {
- .name = "gpio-keys",
- .id = -1,
- .num_resources = 0,
- .dev = {
- .platform_data = &eukrea_mbimxsd_button_data,
- }
-};
-
static struct platform_device *platform_devices[] __initdata = {
&eukrea_mbimxsd_leds_gpio,
- &eukrea_mbimxsd_button_device,
&eukrea_mbimxsd_lcd_powerdev,
};
@@ -299,4 +287,5 @@ void __init eukrea_mbimxsd25_baseboard_init(void)
ARRAY_SIZE(eukrea_mbimxsd_i2c_devices));
platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+ imx_add_gpio_keys(&eukrea_mbimxsd_button_data);
}
diff --git a/arch/arm/mach-mx3/eukrea_mbimxsd-baseboard.c b/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c
index 2e288b38b4ad..4909ea05855a 100644
--- a/arch/arm/mach-mx3/eukrea_mbimxsd-baseboard.c
+++ b/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c
@@ -26,7 +26,6 @@
#include <linux/interrupt.h>
#include <linux/leds.h>
#include <linux/platform_device.h>
-#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <video/platform_lcd.h>
#include <linux/i2c.h>
@@ -38,15 +37,10 @@
#include <mach/hardware.h>
#include <mach/common.h>
-#include <mach/imx-uart.h>
#include <mach/iomux-mx35.h>
-#include <mach/ipu.h>
-#include <mach/mx3fb.h>
#include <mach/audmux.h>
-#include <mach/esdhc.h>
#include "devices-imx35.h"
-#include "devices.h"
static const struct fb_videomode fb_modedb[] = {
{
@@ -101,12 +95,11 @@ static const struct fb_videomode fb_modedb[] = {
},
};
-static struct ipu_platform_data mx3_ipu_data = {
+static const struct ipu_platform_data mx3_ipu_data __initconst = {
.irq_base = MXC_IPU_IRQ_START,
};
-static struct mx3fb_platform_data mx3fb_pdata = {
- .dma_dev = &mx3_ipu.dev,
+static struct mx3fb_platform_data mx3fb_pdata __initdata = {
.name = "CMO-QVGA",
.mode = fb_modedb,
.num_modes = ARRAY_SIZE(fb_modedb),
@@ -223,23 +216,14 @@ static struct gpio_keys_button eukrea_mbimxsd_gpio_buttons[] = {
},
};
-static struct gpio_keys_platform_data eukrea_mbimxsd_button_data = {
+static const struct gpio_keys_platform_data
+ eukrea_mbimxsd_button_data __initconst = {
.buttons = eukrea_mbimxsd_gpio_buttons,
.nbuttons = ARRAY_SIZE(eukrea_mbimxsd_gpio_buttons),
};
-static struct platform_device eukrea_mbimxsd_button_device = {
- .name = "gpio-keys",
- .id = -1,
- .num_resources = 0,
- .dev = {
- .platform_data = &eukrea_mbimxsd_button_data,
- }
-};
-
static struct platform_device *platform_devices[] __initdata = {
&eukrea_mbimxsd_leds_gpio,
- &eukrea_mbimxsd_button_device,
&eukrea_mbimxsd_lcd_powerdev,
};
@@ -292,8 +276,8 @@ void __init eukrea_mbimxsd35_baseboard_init(void)
#endif
imx35_add_imx_uart1(&uart_pdata);
- mxc_register_device(&mx3_ipu, &mx3_ipu_data);
- mxc_register_device(&mx3_fb, &mx3fb_pdata);
+ imx35_add_ipu_core(&mx3_ipu_data);
+ imx35_add_mx3_sdc_fb(&mx3fb_pdata);
imx35_add_imx_ssi(0, &eukrea_mbimxsd_ssi_pdata);
@@ -315,4 +299,5 @@ void __init eukrea_mbimxsd35_baseboard_init(void)
ARRAY_SIZE(eukrea_mbimxsd_i2c_devices));
platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+ imx_add_gpio_keys(&eukrea_mbimxsd_button_data);
}
diff --git a/arch/arm/mach-mx3/iomux-imx31.c b/arch/arm/mach-imx/iomux-imx31.c
index cf8f8099ebd7..cf8f8099ebd7 100644
--- a/arch/arm/mach-mx3/iomux-imx31.c
+++ b/arch/arm/mach-imx/iomux-imx31.c
diff --git a/arch/arm/mach-imx/mach-apf9328.c b/arch/arm/mach-imx/mach-apf9328.c
new file mode 100644
index 000000000000..15e45c84e371
--- /dev/null
+++ b/arch/arm/mach-imx/mach-apf9328.c
@@ -0,0 +1,144 @@
+/*
+ * linux/arch/arm/mach-imx/mach-apf9328.c
+ *
+ * Copyright (c) 2005-2011 ARMadeus systems <support@armadeus.com>
+ *
+ * This work is based on mach-scb9328.c which is:
+ * Copyright (c) 2004 Sascha Hauer <saschahauer@web.de>
+ * Copyright (c) 2006-2008 Juergen Beisert <jbeisert@netscape.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+#include <linux/dm9000.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+#include <mach/common.h>
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/iomux-mx1.h>
+
+#include "devices-imx1.h"
+
+static const int apf9328_pins[] __initconst = {
+ /* UART1 */
+ PC9_PF_UART1_CTS,
+ PC10_PF_UART1_RTS,
+ PC11_PF_UART1_TXD,
+ PC12_PF_UART1_RXD,
+ /* UART2 */
+ PB28_PF_UART2_CTS,
+ PB29_PF_UART2_RTS,
+ PB30_PF_UART2_TXD,
+ PB31_PF_UART2_RXD,
+};
+
+/*
+ * The APF9328 can have up to 32MB NOR Flash
+ */
+static struct resource flash_resource = {
+ .start = MX1_CS0_PHYS,
+ .end = MX1_CS0_PHYS + SZ_32M - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct physmap_flash_data apf9328_flash_data = {
+ .width = 2,
+};
+
+static struct platform_device apf9328_flash_device = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &apf9328_flash_data,
+ },
+ .resource = &flash_resource,
+ .num_resources = 1,
+};
+
+/*
+ * APF9328 has a DM9000 Ethernet controller
+ */
+static struct dm9000_plat_data dm9000_setup = {
+ .flags = DM9000_PLATF_16BITONLY
+};
+
+static struct resource dm9000_resources[] = {
+ {
+ .start = MX1_CS4_PHYS + 0x00C00000,
+ .end = MX1_CS4_PHYS + 0x00C00001,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = MX1_CS4_PHYS + 0x00C00002,
+ .end = MX1_CS4_PHYS + 0x00C00003,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = IRQ_GPIOB(14),
+ .end = IRQ_GPIOB(14),
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+ },
+};
+
+static struct platform_device dm9000x_device = {
+ .name = "dm9000",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(dm9000_resources),
+ .resource = dm9000_resources,
+ .dev = {
+ .platform_data = &dm9000_setup,
+ }
+};
+
+/* --- SERIAL RESSOURCE --- */
+static const struct imxuart_platform_data uart0_pdata __initconst = {
+ .flags = 0,
+};
+
+static const struct imxuart_platform_data uart1_pdata __initconst = {
+ .flags = IMXUART_HAVE_RTSCTS,
+};
+
+static struct platform_device *devices[] __initdata = {
+ &apf9328_flash_device,
+ &dm9000x_device,
+};
+
+static void __init apf9328_init(void)
+{
+ mxc_gpio_setup_multiple_pins(apf9328_pins,
+ ARRAY_SIZE(apf9328_pins),
+ "APF9328");
+
+ imx1_add_imx_uart0(&uart0_pdata);
+ imx1_add_imx_uart1(&uart1_pdata);
+
+ platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
+static void __init apf9328_timer_init(void)
+{
+ mx1_clocks_init(32768);
+}
+
+static struct sys_timer apf9328_timer = {
+ .init = apf9328_timer_init,
+};
+
+MACHINE_START(APF9328, "Armadeus APF9328")
+ /* Maintainer: Gwenhael Goavec-Merou, ARMadeus Systems */
+ .map_io = mx1_map_io,
+ .init_early = imx1_init_early,
+ .init_irq = mx1_init_irq,
+ .timer = &apf9328_timer,
+ .init_machine = apf9328_init,
+MACHINE_END
diff --git a/arch/arm/mach-mx3/mach-armadillo5x0.c b/arch/arm/mach-imx/mach-armadillo5x0.c
index 226829bf7c25..ffb40ff619b1 100644
--- a/arch/arm/mach-mx3/mach-armadillo5x0.c
+++ b/arch/arm/mach-imx/mach-armadillo5x0.c
@@ -34,7 +34,6 @@
#include <linux/mtd/physmap.h>
#include <linux/io.h>
#include <linux/input.h>
-#include <linux/gpio_keys.h>
#include <linux/i2c.h>
#include <linux/usb/otg.h>
#include <linux/usb/ulpi.h>
@@ -49,13 +48,10 @@
#include <mach/common.h>
#include <mach/iomux-mx3.h>
-#include <mach/ipu.h>
-#include <mach/mx3fb.h>
#include <mach/ulpi.h>
#include "devices-imx31.h"
-#include "devices.h"
-#include "crm_regs.h"
+#include "crmregs-imx31.h"
static int armadillo5x0_pins[] = {
/* UART1 */
@@ -280,20 +276,12 @@ static struct gpio_keys_button armadillo5x0_buttons[] = {
}
};
-static struct gpio_keys_platform_data armadillo5x0_button_data = {
+static const struct gpio_keys_platform_data
+ armadillo5x0_button_data __initconst = {
.buttons = armadillo5x0_buttons,
.nbuttons = ARRAY_SIZE(armadillo5x0_buttons),
};
-static struct platform_device armadillo5x0_button_device = {
- .name = "gpio-keys",
- .id = -1,
- .num_resources = 0,
- .dev = {
- .platform_data = &armadillo5x0_button_data,
- }
-};
-
/*
* NAND Flash
*/
@@ -383,12 +371,11 @@ static const struct fb_videomode fb_modedb[] = {
},
};
-static struct ipu_platform_data mx3_ipu_data = {
+static const struct ipu_platform_data mx3_ipu_data __initconst = {
.irq_base = MXC_IPU_IRQ_START,
};
-static struct mx3fb_platform_data mx3fb_pdata = {
- .dma_dev = &mx3_ipu.dev,
+static struct mx3fb_platform_data mx3fb_pdata __initdata = {
.name = "CRT-VGA",
.mode = fb_modedb,
.num_modes = ARRAY_SIZE(fb_modedb),
@@ -496,7 +483,6 @@ static const struct imxuart_platform_data uart_pdata __initconst = {
static struct platform_device *devices[] __initdata = {
&armadillo5x0_smc911x_device,
- &armadillo5x0_button_device,
};
/*
@@ -508,6 +494,7 @@ static void __init armadillo5x0_init(void)
ARRAY_SIZE(armadillo5x0_pins), "armadillo5x0");
platform_add_devices(devices, ARRAY_SIZE(devices));
+ imx_add_gpio_keys(&armadillo5x0_button_data);
imx31_add_imx_i2c1(NULL);
/* Register UART */
@@ -521,8 +508,8 @@ static void __init armadillo5x0_init(void)
imx31_add_mxc_mmc(0, &sdhc_pdata);
/* Register FB */
- mxc_register_device(&mx3_ipu, &mx3_ipu_data);
- mxc_register_device(&mx3_fb, &mx3fb_pdata);
+ imx31_add_ipu_core(&mx3_ipu_data);
+ imx31_add_mx3_sdc_fb(&mx3fb_pdata);
/* Register NOR Flash */
mxc_register_device(&armadillo5x0_nor_flash,
diff --git a/arch/arm/mach-mx3/mach-bug.c b/arch/arm/mach-imx/mach-bug.c
index d137d7078ee9..42e4f078a19c 100644
--- a/arch/arm/mach-mx3/mach-bug.c
+++ b/arch/arm/mach-imx/mach-bug.c
@@ -20,7 +20,6 @@
#include <linux/platform_device.h>
#include <mach/iomux-mx3.h>
-#include <mach/imx-uart.h>
#include <mach/hardware.h>
#include <mach/common.h>
diff --git a/arch/arm/mach-imx/mach-cpuimx27.c b/arch/arm/mach-imx/mach-cpuimx27.c
index 759299bb035b..46a2e41d43d2 100644
--- a/arch/arm/mach-imx/mach-cpuimx27.c
+++ b/arch/arm/mach-imx/mach-cpuimx27.c
@@ -38,7 +38,6 @@
#include <mach/common.h>
#include <mach/hardware.h>
#include <mach/iomux-mx27.h>
-#include <mach/mxc_nand.h>
#include <mach/ulpi.h>
#include "devices-imx27.h"
diff --git a/arch/arm/mach-mx3/mach-cpuimx35.c b/arch/arm/mach-imx/mach-cpuimx35.c
index ec63d998f647..3f8ef825fa6f 100644
--- a/arch/arm/mach-mx3/mach-cpuimx35.c
+++ b/arch/arm/mach-imx/mach-cpuimx35.c
@@ -41,10 +41,8 @@
#include <mach/hardware.h>
#include <mach/common.h>
#include <mach/iomux-mx35.h>
-#include <mach/mxc_nand.h>
#include "devices-imx35.h"
-#include "devices.h"
static const struct imxuart_platform_data uart_pdata __initconst = {
.flags = IMXUART_HAVE_RTSCTS,
diff --git a/arch/arm/mach-imx/mach-eukrea_cpuimx25.c b/arch/arm/mach-imx/mach-eukrea_cpuimx25.c
index 9da8d18eeb00..148cff2819b9 100644
--- a/arch/arm/mach-imx/mach-eukrea_cpuimx25.c
+++ b/arch/arm/mach-imx/mach-eukrea_cpuimx25.c
@@ -36,8 +36,6 @@
#include <asm/mach/map.h>
#include <mach/common.h>
#include <mach/mx25.h>
-#include <mach/mxc_nand.h>
-#include <mach/imxfb.h>
#include <mach/iomux-mx25.h>
#include "devices-imx25.h"
diff --git a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
index d7e0d219726a..7ae43b1ec517 100644
--- a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
+++ b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c
@@ -27,7 +27,6 @@
#include <linux/mtd/physmap.h>
#include <linux/i2c.h>
#include <linux/i2c/pca953x.h>
-#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/gpio.h>
#include <linux/delay.h>
@@ -130,19 +129,12 @@ static struct gpio_keys_button visstrim_gpio_keys[] = {
}
};
-static struct gpio_keys_platform_data visstrim_gpio_keys_platform_data = {
+static const struct gpio_keys_platform_data
+ visstrim_gpio_keys_platform_data __initconst = {
.buttons = visstrim_gpio_keys,
.nbuttons = ARRAY_SIZE(visstrim_gpio_keys),
};
-static struct platform_device visstrim_gpio_keys_device = {
- .name = "gpio-keys",
- .id = -1,
- .dev = {
- .platform_data = &visstrim_gpio_keys_platform_data,
- },
-};
-
/* Visstrim_SM10 has a microSD slot connected to sdhc1 */
static int visstrim_m10_sdhc1_init(struct device *dev,
irq_handler_t detect_irq, void *data)
@@ -186,7 +178,6 @@ static struct platform_device visstrim_m10_nor_mtd_device = {
};
static struct platform_device *platform_devices[] __initdata = {
- &visstrim_gpio_keys_device,
&visstrim_m10_nor_mtd_device,
};
@@ -255,6 +246,7 @@ static void __init visstrim_m10_board_init(void)
imx27_add_mxc_mmc(0, &visstrim_m10_sdhc_pdata);
imx27_add_mxc_ehci_otg(&visstrim_m10_usbotg_pdata);
imx27_add_fec(NULL);
+ imx_add_gpio_keys(&visstrim_gpio_keys_platform_data);
platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
}
diff --git a/arch/arm/mach-mx3/mach-kzm_arm11_01.c b/arch/arm/mach-imx/mach-kzm_arm11_01.c
index d35621d62b4d..1ecae20cf4e3 100644
--- a/arch/arm/mach-mx3/mach-kzm_arm11_01.c
+++ b/arch/arm/mach-imx/mach-kzm_arm11_01.c
@@ -39,7 +39,6 @@
#include <mach/iomux-mx3.h>
#include "devices-imx31.h"
-#include "devices.h"
#define KZM_ARM11_IO_ADDRESS(x) (IOMEM( \
IMX_IO_P2V_MODULE(x, MX31_CS4) ?: \
diff --git a/arch/arm/mach-imx/mach-mx1ads.c b/arch/arm/mach-imx/mach-mx1ads.c
index 47cf56ac6d5b..38ec5cbbda9b 100644
--- a/arch/arm/mach-imx/mach-mx1ads.c
+++ b/arch/arm/mach-imx/mach-mx1ads.c
@@ -25,7 +25,6 @@
#include <mach/common.h>
#include <mach/hardware.h>
-#include <mach/i2c.h>
#include <mach/iomux-mx1.h>
#include <mach/irqs.h>
diff --git a/arch/arm/mach-imx/mach-mx21ads.c b/arch/arm/mach-imx/mach-mx21ads.c
index fa52a1086eae..74ac88978ddd 100644
--- a/arch/arm/mach-imx/mach-mx21ads.c
+++ b/arch/arm/mach-imx/mach-mx21ads.c
@@ -25,7 +25,6 @@
#include <asm/mach/time.h>
#include <asm/mach/map.h>
#include <mach/iomux-mx21.h>
-#include <mach/mxc_nand.h>
#include "devices-imx21.h"
diff --git a/arch/arm/mach-imx/mach-mx25_3ds.c b/arch/arm/mach-imx/mach-mx25_3ds.c
index 06da438282aa..58ea3fdf0911 100644
--- a/arch/arm/mach-imx/mach-mx25_3ds.c
+++ b/arch/arm/mach-imx/mach-mx25_3ds.c
@@ -29,7 +29,6 @@
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
-#include <linux/input/matrix_keypad.h>
#include <linux/usb/otg.h>
#include <mach/hardware.h>
@@ -103,6 +102,8 @@ static iomux_v3_cfg_t mx25pdk_pads[] = {
MX25_PAD_SD1_DATA1__SD1_DATA1,
MX25_PAD_SD1_DATA2__SD1_DATA2,
MX25_PAD_SD1_DATA3__SD1_DATA3,
+ MX25_PAD_A14__GPIO_2_0, /* WriteProtect */
+ MX25_PAD_A15__GPIO_2_1, /* CardDetect */
/* I2C1 */
MX25_PAD_I2C1_CLK__I2C1_CLK,
@@ -208,6 +209,14 @@ static const struct imxi2c_platform_data mx25_3ds_i2c0_data __initconst = {
.bitrate = 100000,
};
+#define SD1_GPIO_WP IMX_GPIO_NR(2, 0)
+#define SD1_GPIO_CD IMX_GPIO_NR(2, 1)
+
+static const struct esdhc_platform_data mx25pdk_esdhc_pdata __initconst = {
+ .wp_gpio = SD1_GPIO_WP,
+ .cd_gpio = SD1_GPIO_CD,
+};
+
static void __init mx25pdk_init(void)
{
mxc_iomux_v3_setup_multiple_pads(mx25pdk_pads,
@@ -225,7 +234,7 @@ static void __init mx25pdk_init(void)
imx25_add_fec(&mx25_fec_pdata);
imx25_add_imx_keypad(&mx25pdk_keymap_data);
- imx25_add_sdhci_esdhc_imx(0, NULL);
+ imx25_add_sdhci_esdhc_imx(0, &mx25pdk_esdhc_pdata);
imx25_add_imx_i2c0(&mx25_3ds_i2c0_data);
}
diff --git a/arch/arm/mach-imx/mach-mx27ads.c b/arch/arm/mach-imx/mach-mx27ads.c
index 367d1e4384c7..1db79506f5e4 100644
--- a/arch/arm/mach-imx/mach-mx27ads.c
+++ b/arch/arm/mach-imx/mach-mx27ads.c
@@ -29,7 +29,6 @@
#include <asm/mach/map.h>
#include <mach/gpio.h>
#include <mach/iomux-mx27.h>
-#include <mach/mxc_nand.h>
#include "devices-imx27.h"
diff --git a/arch/arm/mach-mx3/mach-mx31_3ds.c b/arch/arm/mach-imx/mach-mx31_3ds.c
index 034be624d35c..9b982449cb52 100644
--- a/arch/arm/mach-mx3/mach-mx31_3ds.c
+++ b/arch/arm/mach-imx/mach-mx31_3ds.c
@@ -39,13 +39,8 @@
#include <mach/iomux-mx3.h>
#include <mach/3ds_debugboard.h>
#include <mach/ulpi.h>
-#include <mach/mmc.h>
-#include <mach/ipu.h>
-#include <mach/mx3fb.h>
-#include <mach/mx3_camera.h>
#include "devices-imx31.h"
-#include "devices.h"
/* CPLD IRQ line for external uart, external ethernet etc */
#define EXPIO_PARENT_INT IOMUX_TO_IRQ(MX31_PIN_GPIO1_1)
@@ -178,22 +173,37 @@ static struct gpio mx31_3ds_camera_gpios[] = {
{ MX31_3DS_GPIO_CAMERA_RST, GPIOF_OUT_INIT_HIGH, "camera-reset" },
};
-static int __init mx31_3ds_camera_alloc_dma(void)
+static const struct mx3_camera_pdata mx31_3ds_camera_pdata __initconst = {
+ .flags = MX3_CAMERA_DATAWIDTH_10,
+ .mclk_10khz = 2600,
+};
+
+static int __init mx31_3ds_init_camera(void)
{
- int dma;
+ int dma, ret = -ENOMEM;
+ struct platform_device *pdev =
+ imx31_alloc_mx3_camera(&mx31_3ds_camera_pdata);
+
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
if (!mx3_camera_base)
- return -ENOMEM;
+ goto err;
- dma = dma_declare_coherent_memory(&mx3_camera.dev,
+ dma = dma_declare_coherent_memory(&pdev->dev,
mx3_camera_base, mx3_camera_base,
MX31_3DS_CAMERA_BUF_SIZE,
DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE);
if (!(dma & DMA_MEMORY_MAP))
- return -ENOMEM;
+ goto err;
- return 0;
+ ret = platform_device_add(pdev);
+ if (ret)
+err:
+ platform_device_put(pdev);
+
+ return ret;
}
static int mx31_3ds_camera_power(struct device *dev, int on)
@@ -241,12 +251,6 @@ static struct platform_device mx31_3ds_ov2640 = {
},
};
-struct mx3_camera_pdata mx31_3ds_camera_pdata = {
- .dma_dev = &mx3_ipu.dev,
- .flags = MX3_CAMERA_DATAWIDTH_10,
- .mclk_10khz = 2600,
-};
-
/*
* FB support
*/
@@ -273,8 +277,7 @@ static struct ipu_platform_data mx3_ipu_data = {
.irq_base = MXC_IPU_IRQ_START,
};
-static struct mx3fb_platform_data mx3fb_pdata = {
- .dma_dev = &mx3_ipu.dev,
+static struct mx3fb_platform_data mx3fb_pdata __initdata = {
.name = "Epson-VGA",
.mode = fb_modedb,
.num_modes = ARRAY_SIZE(fb_modedb),
@@ -723,8 +726,8 @@ static void __init mx31_3ds_init(void)
imx31_add_mxc_mmc(0, &sdhc1_pdata);
imx31_add_spi_imx0(&spi0_pdata);
- mxc_register_device(&mx3_ipu, &mx3_ipu_data);
- mxc_register_device(&mx3_fb, &mx3fb_pdata);
+ imx31_add_ipu_core(&mx3_ipu_data);
+ imx31_add_mx3_sdc_fb(&mx3fb_pdata);
/* CSI */
/* Camera power: default - off */
@@ -735,10 +738,7 @@ static void __init mx31_3ds_init(void)
iclink_ov2640.power = NULL;
}
- if (!mx31_3ds_camera_alloc_dma())
- mxc_register_device(&mx3_camera, &mx31_3ds_camera_pdata);
- else
- pr_err("Failed to allocate dma memory for camera");
+ mx31_3ds_init_camera();
}
static void __init mx31_3ds_timer_init(void)
diff --git a/arch/arm/mach-mx3/mach-mx31ads.c b/arch/arm/mach-imx/mach-mx31ads.c
index 3d095d69bc68..f4dee0254634 100644
--- a/arch/arm/mach-mx3/mach-mx31ads.c
+++ b/arch/arm/mach-imx/mach-mx31ads.c
@@ -38,7 +38,6 @@
#endif
#include "devices-imx31.h"
-#include "devices.h"
/* PBC Board interrupt status register */
#define PBC_INTSTATUS 0x000016
diff --git a/arch/arm/mach-mx3/mach-mx31lilly.c b/arch/arm/mach-imx/mach-mx31lilly.c
index ed95745163b8..410e676ae087 100644
--- a/arch/arm/mach-mx3/mach-mx31lilly.c
+++ b/arch/arm/mach-imx/mach-mx31lilly.c
@@ -46,7 +46,6 @@
#include <mach/ulpi.h>
#include "devices-imx31.h"
-#include "devices.h"
/*
* This file contains module-specific initialization routines for LILLY-1131.
diff --git a/arch/arm/mach-mx3/mach-mx31lite.c b/arch/arm/mach-imx/mach-mx31lite.c
index 24a21a384bf1..ac9b4cad320e 100644
--- a/arch/arm/mach-mx3/mach-mx31lite.c
+++ b/arch/arm/mach-imx/mach-mx31lite.c
@@ -44,7 +44,6 @@
#include <mach/ulpi.h>
#include "devices-imx31.h"
-#include "devices.h"
/*
* This file contains the module-specific initialization routines.
diff --git a/arch/arm/mach-mx3/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c
index 3a021b01161d..eaa51e49ca95 100644
--- a/arch/arm/mach-mx3/mach-mx31moboard.c
+++ b/arch/arm/mach-imx/mach-mx31moboard.c
@@ -27,6 +27,7 @@
#include <linux/mfd/mc13783.h>
#include <linux/spi/spi.h>
#include <linux/types.h>
+#include <linux/memblock.h>
#include <linux/usb/otg.h>
#include <linux/usb/ulpi.h>
@@ -39,13 +40,9 @@
#include <mach/common.h>
#include <mach/hardware.h>
#include <mach/iomux-mx3.h>
-#include <mach/ipu.h>
-#include <mach/mx3_camera.h>
-#include <mach/spi.h>
#include <mach/ulpi.h>
#include "devices-imx31.h"
-#include "devices.h"
static unsigned int moboard_pins[] = {
/* UART0 */
@@ -102,7 +99,7 @@ static unsigned int moboard_pins[] = {
};
static struct physmap_flash_data mx31moboard_flash_data = {
- .width = 2,
+ .width = 2,
};
static struct resource mx31moboard_flash_resource = {
@@ -194,8 +191,8 @@ static struct regulator_init_data sdhc_vreg_data = {
static struct regulator_consumer_supply cam_consumers[] = {
{
- .dev = &mx3_camera.dev,
- .supply = "cam_vcc",
+ .dev_name = "mx3_camera.0",
+ .supply = "cam_vcc",
},
};
@@ -430,9 +427,9 @@ static int __init moboard_usbh2_init(void)
static struct gpio_led mx31moboard_leds[] = {
{
- .name = "coreboard-led-0:red:running",
+ .name = "coreboard-led-0:red:running",
.default_trigger = "heartbeat",
- .gpio = IOMUX_TO_GPIO(MX31_PIN_SVEN0),
+ .gpio = IOMUX_TO_GPIO(MX31_PIN_SVEN0),
}, {
.name = "coreboard-led-1:red",
.gpio = IOMUX_TO_GPIO(MX31_PIN_STX0),
@@ -446,7 +443,7 @@ static struct gpio_led mx31moboard_leds[] = {
};
static struct gpio_led_platform_data mx31moboard_led_pdata = {
- .num_leds = ARRAY_SIZE(mx31moboard_leds),
+ .num_leds = ARRAY_SIZE(mx31moboard_leds),
.leds = mx31moboard_leds,
};
@@ -458,7 +455,7 @@ static struct platform_device mx31moboard_leds_device = {
},
};
-static struct ipu_platform_data mx3_ipu_data = {
+static const struct ipu_platform_data mx3_ipu_data __initconst = {
.irq_base = MXC_IPU_IRQ_START,
};
@@ -467,37 +464,39 @@ static struct platform_device *devices[] __initdata = {
&mx31moboard_leds_device,
};
-static struct mx3_camera_pdata camera_pdata = {
- .dma_dev = &mx3_ipu.dev,
+static struct mx3_camera_pdata camera_pdata __initdata = {
.flags = MX3_CAMERA_DATAWIDTH_8 | MX3_CAMERA_DATAWIDTH_10,
.mclk_10khz = 4800,
};
-#define CAMERA_BUF_SIZE (4*1024*1024)
+static phys_addr_t mx3_camera_base __initdata;
+#define MX3_CAMERA_BUF_SIZE SZ_4M
-static int __init mx31moboard_cam_alloc_dma(const size_t buf_size)
+static int __init mx31moboard_init_cam(void)
{
- dma_addr_t dma_handle;
- void *buf;
- int dma;
-
- if (buf_size < 2 * 1024 * 1024)
- return -EINVAL;
+ int dma, ret = -ENOMEM;
+ struct platform_device *pdev;
- buf = dma_alloc_coherent(NULL, buf_size, &dma_handle, GFP_KERNEL);
- if (!buf) {
- pr_err("%s: cannot allocate camera buffer-memory\n", __func__);
- return -ENOMEM;
- }
+ imx31_add_ipu_core(&mx3_ipu_data);
- memset(buf, 0, buf_size);
+ pdev = imx31_alloc_mx3_camera(&camera_pdata);
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
- dma = dma_declare_coherent_memory(&mx3_camera.dev,
- dma_handle, dma_handle, buf_size,
+ dma = dma_declare_coherent_memory(&pdev->dev,
+ mx3_camera_base, mx3_camera_base,
+ MX3_CAMERA_BUF_SIZE,
DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE);
+ if (!(dma & DMA_MEMORY_MAP))
+ goto err;
+
+ ret = platform_device_add(pdev);
+ if (ret)
+err:
+ platform_device_put(pdev);
+
+ return ret;
- /* The way we call dma_declare_coherent_memory only a malloc can fail */
- return dma & DMA_MEMORY_MAP ? 0 : -ENOMEM;
}
static int mx31moboard_baseboard;
@@ -529,9 +528,7 @@ static void __init mx31moboard_init(void)
imx31_add_mxc_mmc(0, &sdhc1_pdata);
- mxc_register_device(&mx3_ipu, &mx3_ipu_data);
- if (!mx31moboard_cam_alloc_dma(CAMERA_BUF_SIZE))
- mxc_register_device(&mx3_camera, &camera_pdata);
+ mx31moboard_init_cam();
usb_xcvr_reset();
@@ -565,9 +562,19 @@ struct sys_timer mx31moboard_timer = {
.init = mx31moboard_timer_init,
};
+static void __init mx31moboard_reserve(void)
+{
+ /* reserve 4 MiB for mx3-camera */
+ mx3_camera_base = memblock_alloc(MX3_CAMERA_BUF_SIZE,
+ MX3_CAMERA_BUF_SIZE);
+ memblock_free(mx3_camera_base, MX3_CAMERA_BUF_SIZE);
+ memblock_remove(mx3_camera_base, MX3_CAMERA_BUF_SIZE);
+}
+
MACHINE_START(MX31MOBOARD, "EPFL Mobots mx31moboard")
/* Maintainer: Valentin Longchamp, EPFL Mobots group */
.boot_params = MX3x_PHYS_OFFSET + 0x100,
+ .reserve = mx31moboard_reserve,
.map_io = mx31_map_io,
.init_early = imx31_init_early,
.init_irq = mx31_init_irq,
diff --git a/arch/arm/mach-mx3/mach-mx35_3ds.c b/arch/arm/mach-imx/mach-mx35_3ds.c
index ff5fe231b8d6..882880ac1bbc 100644
--- a/arch/arm/mach-mx3/mach-mx35_3ds.c
+++ b/arch/arm/mach-imx/mach-mx35_3ds.c
@@ -42,7 +42,6 @@
#include <mach/3ds_debugboard.h>
#include "devices-imx35.h"
-#include "devices.h"
#define EXPIO_PARENT_INT (MXC_INTERNAL_IRQS + GPIO_PORTA + 1)
diff --git a/arch/arm/mach-imx/mach-mxt_td60.c b/arch/arm/mach-imx/mach-mxt_td60.c
index 69787c30c320..2774541511e7 100644
--- a/arch/arm/mach-imx/mach-mxt_td60.c
+++ b/arch/arm/mach-imx/mach-mxt_td60.c
@@ -29,7 +29,6 @@
#include <asm/mach/map.h>
#include <linux/gpio.h>
#include <mach/iomux-mx27.h>
-#include <mach/mxc_nand.h>
#include <linux/i2c/pca953x.h>
#include "devices-imx27.h"
diff --git a/arch/arm/mach-imx/mach-pca100.c b/arch/arm/mach-imx/mach-pca100.c
index 63e182556778..bbddc5a11c43 100644
--- a/arch/arm/mach-imx/mach-pca100.c
+++ b/arch/arm/mach-imx/mach-pca100.c
@@ -37,7 +37,6 @@
#include <mach/iomux-mx27.h>
#include <asm/mach/time.h>
#include <mach/audmux.h>
-#include <mach/mxc_nand.h>
#include <mach/irqs.h>
#include <mach/ulpi.h>
diff --git a/arch/arm/mach-mx3/mach-pcm037.c b/arch/arm/mach-imx/mach-pcm037.c
index f07d3bded674..89c213b81295 100644
--- a/arch/arm/mach-mx3/mach-pcm037.c
+++ b/arch/arm/mach-imx/mach-pcm037.c
@@ -31,6 +31,7 @@
#include <linux/usb/otg.h>
#include <linux/usb/ulpi.h>
#include <linux/gfp.h>
+#include <linux/memblock.h>
#include <media/soc_camera.h>
@@ -41,13 +42,9 @@
#include <mach/common.h>
#include <mach/hardware.h>
#include <mach/iomux-mx3.h>
-#include <mach/ipu.h>
-#include <mach/mx3_camera.h>
-#include <mach/mx3fb.h>
#include <mach/ulpi.h>
#include "devices-imx31.h"
-#include "devices.h"
#include "pcm037.h"
static enum pcm037_board_variant pcm037_instance = PCM037_PCM970;
@@ -404,35 +401,35 @@ static const struct imxmmc_platform_data sdhc_pdata __initconst = {
.exit = pcm970_sdhc1_exit,
};
-struct mx3_camera_pdata camera_pdata = {
- .dma_dev = &mx3_ipu.dev,
+struct mx3_camera_pdata camera_pdata __initdata = {
.flags = MX3_CAMERA_DATAWIDTH_8 | MX3_CAMERA_DATAWIDTH_10,
.mclk_10khz = 2000,
};
-static int __init pcm037_camera_alloc_dma(const size_t buf_size)
-{
- dma_addr_t dma_handle;
- void *buf;
- int dma;
-
- if (buf_size < 2 * 1024 * 1024)
- return -EINVAL;
+static phys_addr_t mx3_camera_base __initdata;
+#define MX3_CAMERA_BUF_SIZE SZ_4M
- buf = dma_alloc_coherent(NULL, buf_size, &dma_handle, GFP_KERNEL);
- if (!buf) {
- pr_err("%s: cannot allocate camera buffer-memory\n", __func__);
- return -ENOMEM;
- }
+static int __init pcm037_init_camera(void)
+{
+ int dma, ret = -ENOMEM;
+ struct platform_device *pdev = imx31_alloc_mx3_camera(&camera_pdata);
- memset(buf, 0, buf_size);
+ if (IS_ERR(pdev))
+ return PTR_ERR(pdev);
- dma = dma_declare_coherent_memory(&mx3_camera.dev,
- dma_handle, dma_handle, buf_size,
+ dma = dma_declare_coherent_memory(&pdev->dev,
+ mx3_camera_base, mx3_camera_base,
+ MX3_CAMERA_BUF_SIZE,
DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE);
+ if (!(dma & DMA_MEMORY_MAP))
+ goto err;
+
+ ret = platform_device_add(pdev);
+ if (ret)
+err:
+ platform_device_put(pdev);
- /* The way we call dma_declare_coherent_memory only a malloc can fail */
- return dma & DMA_MEMORY_MAP ? 0 : -ENOMEM;
+ return ret;
}
static struct platform_device *devices[] __initdata = {
@@ -442,7 +439,7 @@ static struct platform_device *devices[] __initdata = {
&pcm037_mt9v022,
};
-static struct ipu_platform_data mx3_ipu_data = {
+static const struct ipu_platform_data mx3_ipu_data __initconst = {
.irq_base = MXC_IPU_IRQ_START,
};
@@ -500,7 +497,6 @@ static const struct fb_videomode fb_modedb[] = {
};
static struct mx3fb_platform_data mx3fb_pdata = {
- .dma_dev = &mx3_ipu.dev,
.name = "Sharp-LQ035Q7DH06-QVGA",
.mode = fb_modedb,
.num_modes = ARRAY_SIZE(fb_modedb),
@@ -638,8 +634,8 @@ static void __init pcm037_init(void)
imx31_add_mxc_nand(&pcm037_nand_board_info);
imx31_add_mxc_mmc(0, &sdhc_pdata);
- mxc_register_device(&mx3_ipu, &mx3_ipu_data);
- mxc_register_device(&mx3_fb, &mx3fb_pdata);
+ imx31_add_ipu_core(&mx3_ipu_data);
+ imx31_add_mx3_sdc_fb(&mx3fb_pdata);
/* CSI */
/* Camera power: default - off */
@@ -649,8 +645,7 @@ static void __init pcm037_init(void)
else
iclink_mt9t031.power = NULL;
- if (!pcm037_camera_alloc_dma(4 * 1024 * 1024))
- mxc_register_device(&mx3_camera, &camera_pdata);
+ pcm037_init_camera();
platform_device_register(&pcm970_sja1000);
@@ -680,9 +675,19 @@ struct sys_timer pcm037_timer = {
.init = pcm037_timer_init,
};
+static void __init pcm037_reserve(void)
+{
+ /* reserve 4 MiB for mx3-camera */
+ mx3_camera_base = memblock_alloc(MX3_CAMERA_BUF_SIZE,
+ MX3_CAMERA_BUF_SIZE);
+ memblock_free(mx3_camera_base, MX3_CAMERA_BUF_SIZE);
+ memblock_remove(mx3_camera_base, MX3_CAMERA_BUF_SIZE);
+}
+
MACHINE_START(PCM037, "Phytec Phycore pcm037")
/* Maintainer: Pengutronix */
.boot_params = MX3x_PHYS_OFFSET + 0x100,
+ .reserve = pcm037_reserve,
.map_io = mx31_map_io,
.init_early = imx31_init_early,
.init_irq = mx31_init_irq,
diff --git a/arch/arm/mach-mx3/mach-pcm037_eet.c b/arch/arm/mach-imx/mach-pcm037_eet.c
index df6fb07d037e..1b7606bef8f4 100644
--- a/arch/arm/mach-mx3/mach-pcm037_eet.c
+++ b/arch/arm/mach-imx/mach-pcm037_eet.c
@@ -7,19 +7,16 @@
* published by the Free Software Foundation.
*/
#include <linux/gpio.h>
-#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <mach/common.h>
#include <mach/iomux-mx3.h>
-#include <mach/spi.h>
#include <asm/mach-types.h>
#include "pcm037.h"
-#include "devices.h"
#include "devices-imx31.h"
static unsigned int pcm037_eet_pins[] = {
@@ -156,20 +153,13 @@ static struct gpio_keys_button pcm037_gpio_keys[] = {
},
};
-static struct gpio_keys_platform_data pcm037_gpio_keys_platform_data = {
+static const struct gpio_keys_platform_data
+ pcm037_gpio_keys_platform_data __initconst = {
.buttons = pcm037_gpio_keys,
.nbuttons = ARRAY_SIZE(pcm037_gpio_keys),
.rep = 0, /* No auto-repeat */
};
-static struct platform_device pcm037_gpio_keys_device = {
- .name = "gpio-keys",
- .id = -1,
- .dev = {
- .platform_data = &pcm037_gpio_keys_platform_data,
- },
-};
-
static int __init eet_init_devices(void)
{
if (!machine_is_pcm037() || pcm037_variant() != PCM037_EET)
@@ -182,9 +172,8 @@ static int __init eet_init_devices(void)
spi_register_board_info(pcm037_spi_dev, ARRAY_SIZE(pcm037_spi_dev));
imx31_add_spi_imx0(&pcm037_spi1_pdata);
- platform_device_register(&pcm037_gpio_keys_device);
+ imx_add_gpio_keys(&pcm037_gpio_keys_platform_data);
return 0;
}
-
late_initcall(eet_init_devices);
diff --git a/arch/arm/mach-imx/mach-pcm038.c b/arch/arm/mach-imx/mach-pcm038.c
index 4cbce6d0fef1..853bb871c7ed 100644
--- a/arch/arm/mach-imx/mach-pcm038.c
+++ b/arch/arm/mach-imx/mach-pcm038.c
@@ -36,7 +36,6 @@
#include <mach/common.h>
#include <mach/hardware.h>
#include <mach/iomux-mx27.h>
-#include <mach/mxc_nand.h>
#include <mach/ulpi.h>
#include "devices-imx27.h"
diff --git a/arch/arm/mach-mx3/mach-pcm043.c b/arch/arm/mach-imx/mach-pcm043.c
index 036ba1a4704b..026441628dfa 100644
--- a/arch/arm/mach-mx3/mach-pcm043.c
+++ b/arch/arm/mach-imx/mach-pcm043.c
@@ -36,14 +36,10 @@
#include <mach/hardware.h>
#include <mach/common.h>
#include <mach/iomux-mx35.h>
-#include <mach/ipu.h>
-#include <mach/mx3fb.h>
#include <mach/ulpi.h>
#include <mach/audmux.h>
-#include <mach/esdhc.h>
#include "devices-imx35.h"
-#include "devices.h"
static const struct fb_videomode fb_modedb[] = {
{
@@ -81,12 +77,11 @@ static const struct fb_videomode fb_modedb[] = {
},
};
-static struct ipu_platform_data mx3_ipu_data = {
+static const struct ipu_platform_data mx3_ipu_data __initconst = {
.irq_base = MXC_IPU_IRQ_START,
};
-static struct mx3fb_platform_data mx3fb_pdata = {
- .dma_dev = &mx3_ipu.dev,
+static struct mx3fb_platform_data mx3fb_pdata __initdata = {
.name = "Sharp-LQ035Q7",
.mode = fb_modedb,
.num_modes = ARRAY_SIZE(fb_modedb),
@@ -127,12 +122,12 @@ static struct at24_platform_data board_eeprom = {
};
static struct i2c_board_info pcm043_i2c_devices[] = {
- {
+ {
I2C_BOARD_INFO("at24", 0x52), /* E0=0, E1=1, E2=0 */
.platform_data = &board_eeprom,
}, {
I2C_BOARD_INFO("pcf8563", 0x51),
- }
+ },
};
static struct platform_device *devices[] __initdata = {
@@ -390,8 +385,8 @@ static void __init pcm043_init(void)
imx35_add_imx_i2c0(&pcm043_i2c0_data);
- mxc_register_device(&mx3_ipu, &mx3_ipu_data);
- mxc_register_device(&mx3_fb, &mx3fb_pdata);
+ imx35_add_ipu_core(&mx3_ipu_data);
+ imx35_add_mx3_sdc_fb(&mx3fb_pdata);
if (otg_mode_host) {
otg_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS |
diff --git a/arch/arm/mach-mx3/mach-qong.c b/arch/arm/mach-imx/mach-qong.c
index 17f758b77623..c16328715939 100644
--- a/arch/arm/mach-mx3/mach-qong.c
+++ b/arch/arm/mach-imx/mach-qong.c
@@ -33,24 +33,23 @@
#include <mach/iomux-mx3.h>
#include "devices-imx31.h"
-#include "devices.h"
/* FPGA defines */
#define QONG_FPGA_VERSION(major, minor, rev) \
(((major & 0xF) << 12) | ((minor & 0xF) << 8) | (rev & 0xFF))
-#define QONG_FPGA_BASEADDR MX31_CS1_BASE_ADDR
-#define QONG_FPGA_PERIPH_SIZE (1 << 24)
+#define QONG_FPGA_BASEADDR MX31_CS1_BASE_ADDR
+#define QONG_FPGA_PERIPH_SIZE (1 << 24)
#define QONG_FPGA_CTRL_BASEADDR QONG_FPGA_BASEADDR
-#define QONG_FPGA_CTRL_SIZE 0x10
+#define QONG_FPGA_CTRL_SIZE 0x10
/* FPGA control registers */
#define QONG_FPGA_CTRL_VERSION 0x00
#define QONG_DNET_ID 1
#define QONG_DNET_BASEADDR \
(QONG_FPGA_BASEADDR + QONG_DNET_ID * QONG_FPGA_PERIPH_SIZE)
-#define QONG_DNET_SIZE 0x00001000
+#define QONG_DNET_SIZE 0x00001000
#define QONG_FPGA_IRQ IOMUX_TO_IRQ(MX31_PIN_DTR_DCE1)
@@ -166,15 +165,15 @@ static struct platform_nand_data qong_nand_data = {
.options = 0,
},
.ctrl = {
- .cmd_ctrl = qong_nand_cmd_ctrl,
+ .cmd_ctrl = qong_nand_cmd_ctrl,
.dev_ready = qong_nand_device_ready,
.select_chip = qong_nand_select_chip,
}
};
static struct resource qong_nand_resource = {
- .start = MX31_CS3_BASE_ADDR,
- .end = MX31_CS3_BASE_ADDR + SZ_32M - 1,
+ .start = MX31_CS3_BASE_ADDR,
+ .end = MX31_CS3_BASE_ADDR + SZ_32M - 1,
.flags = IORESOURCE_MEM,
};
diff --git a/arch/arm/mach-mx3/mach-vpr200.c b/arch/arm/mach-imx/mach-vpr200.c
index 47a69cbc31a8..d74e3473d236 100644
--- a/arch/arm/mach-mx3/mach-vpr200.c
+++ b/arch/arm/mach-imx/mach-vpr200.c
@@ -32,16 +32,12 @@
#include <mach/common.h>
#include <mach/iomux-mx35.h>
#include <mach/irqs.h>
-#include <mach/ipu.h>
-#include <mach/mx3fb.h>
#include <linux/i2c.h>
#include <linux/i2c/at24.h>
#include <linux/mfd/mc13xxx.h>
-#include <linux/gpio_keys.h>
#include "devices-imx35.h"
-#include "devices.h"
#define GPIO_LCDPWR IMX_GPIO_NR(1, 2)
#define GPIO_PMIC_INT IMX_GPIO_NR(2, 0)
@@ -91,12 +87,11 @@ static const struct fb_videomode fb_modedb[] = {
}
};
-static struct ipu_platform_data mx3_ipu_data = {
+static const struct ipu_platform_data mx3_ipu_data __initconst = {
.irq_base = MXC_IPU_IRQ_START,
};
-static struct mx3fb_platform_data mx3fb_pdata = {
- .dma_dev = &mx3_ipu.dev,
+static struct mx3fb_platform_data mx3fb_pdata __initdata = {
.name = "PT0708048",
.mode = fb_modedb,
.num_modes = ARRAY_SIZE(fb_modedb),
@@ -141,18 +136,12 @@ static struct gpio_keys_button vpr200_gpio_keys_table[] = {
{KEY_F9, GPIO_BUTTON8, 1, "vpr-keys: F9", 1, VPR_KEY_DEBOUNCE},
};
-static struct gpio_keys_platform_data vpr200_gpio_keys_data = {
+static const struct gpio_keys_platform_data
+ vpr200_gpio_keys_data __initconst = {
.buttons = vpr200_gpio_keys_table,
.nbuttons = ARRAY_SIZE(vpr200_gpio_keys_table),
};
-static struct platform_device vpr200_device_gpiokeys = {
- .name = "gpio-keys",
- .dev = {
- .platform_data = &vpr200_gpio_keys_data,
- }
-};
-
static struct mc13xxx_platform_data vpr200_pmic = {
.flags = MC13XXX_USE_ADC | MC13XXX_USE_TOUCHSCREEN,
};
@@ -271,7 +260,6 @@ static const struct mxc_usbh_platform_data usb_host_pdata __initconst = {
static struct platform_device *devices[] __initdata = {
&vpr200_flash,
- &vpr200_device_gpiokeys,
};
/*
@@ -283,6 +271,7 @@ static void __init vpr200_board_init(void)
imx35_add_fec(NULL);
imx35_add_imx2_wdt(NULL);
+ imx_add_gpio_keys(&vpr200_gpio_keys_data);
platform_add_devices(devices, ARRAY_SIZE(devices));
@@ -299,8 +288,8 @@ static void __init vpr200_board_init(void)
imx35_add_imx_uart0(NULL);
imx35_add_imx_uart2(NULL);
- mxc_register_device(&mx3_ipu, &mx3_ipu_data);
- mxc_register_device(&mx3_fb, &mx3fb_pdata);
+ imx35_add_ipu_core(&mx3_ipu_data);
+ imx35_add_mx3_sdc_fb(&mx3fb_pdata);
imx35_add_fsl_usb2_udc(&otg_device_pdata);
imx35_add_mxc_ehci_hs(&usb_host_pdata);
diff --git a/arch/arm/mach-imx/mm-imx31.c b/arch/arm/mach-imx/mm-imx31.c
new file mode 100644
index 000000000000..86b9b45864d2
--- /dev/null
+++ b/arch/arm/mach-imx/mm-imx31.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 1999,2000 Arm Limited
+ * Copyright (C) 2000 Deep Blue Solutions Ltd
+ * Copyright (C) 2002 Shane Nay (shane@minirl.com)
+ * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * - add MX31 specific definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/err.h>
+
+#include <asm/pgtable.h>
+#include <asm/mach/map.h>
+
+#include <mach/common.h>
+#include <mach/hardware.h>
+#include <mach/iomux-v3.h>
+#include <mach/gpio.h>
+#include <mach/irqs.h>
+
+static struct map_desc mx31_io_desc[] __initdata = {
+ imx_map_entry(MX31, X_MEMC, MT_DEVICE),
+ imx_map_entry(MX31, AVIC, MT_DEVICE_NONSHARED),
+ imx_map_entry(MX31, AIPS1, MT_DEVICE_NONSHARED),
+ imx_map_entry(MX31, AIPS2, MT_DEVICE_NONSHARED),
+ imx_map_entry(MX31, SPBA0, MT_DEVICE_NONSHARED),
+};
+
+/*
+ * This function initializes the memory map. It is called during the
+ * system startup to create static physical to virtual memory mappings
+ * for the IO modules.
+ */
+void __init mx31_map_io(void)
+{
+ iotable_init(mx31_io_desc, ARRAY_SIZE(mx31_io_desc));
+}
+
+void __init imx31_init_early(void)
+{
+ mxc_set_cpu_type(MXC_CPU_MX31);
+ mxc_arch_reset_init(MX31_IO_ADDRESS(MX31_WDOG_BASE_ADDR));
+}
+
+static struct mxc_gpio_port imx31_gpio_ports[] = {
+ DEFINE_IMX_GPIO_PORT_IRQ(MX31, 0, 1, MX31_INT_GPIO1),
+ DEFINE_IMX_GPIO_PORT_IRQ(MX31, 1, 2, MX31_INT_GPIO2),
+ DEFINE_IMX_GPIO_PORT_IRQ(MX31, 2, 3, MX31_INT_GPIO3),
+};
+
+void __init mx31_init_irq(void)
+{
+ mxc_init_irq(MX31_IO_ADDRESS(MX31_AVIC_BASE_ADDR));
+ mxc_gpio_init(imx31_gpio_ports, ARRAY_SIZE(imx31_gpio_ports));
+}
diff --git a/arch/arm/mach-imx/mm-imx35.c b/arch/arm/mach-imx/mm-imx35.c
new file mode 100644
index 000000000000..c880e6d1ae55
--- /dev/null
+++ b/arch/arm/mach-imx/mm-imx35.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 1999,2000 Arm Limited
+ * Copyright (C) 2000 Deep Blue Solutions Ltd
+ * Copyright (C) 2002 Shane Nay (shane@minirl.com)
+ * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ * - add MX31 specific definitions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/err.h>
+
+#include <asm/pgtable.h>
+#include <asm/mach/map.h>
+#include <asm/hardware/cache-l2x0.h>
+
+#include <mach/common.h>
+#include <mach/hardware.h>
+#include <mach/iomux-v3.h>
+#include <mach/gpio.h>
+#include <mach/irqs.h>
+
+static struct map_desc mx35_io_desc[] __initdata = {
+ imx_map_entry(MX35, X_MEMC, MT_DEVICE),
+ imx_map_entry(MX35, AVIC, MT_DEVICE_NONSHARED),
+ imx_map_entry(MX35, AIPS1, MT_DEVICE_NONSHARED),
+ imx_map_entry(MX35, AIPS2, MT_DEVICE_NONSHARED),
+ imx_map_entry(MX35, SPBA0, MT_DEVICE_NONSHARED),
+};
+
+void __init mx35_map_io(void)
+{
+ iotable_init(mx35_io_desc, ARRAY_SIZE(mx35_io_desc));
+}
+
+void __init imx35_init_early(void)
+{
+ mxc_set_cpu_type(MXC_CPU_MX35);
+ mxc_iomux_v3_init(MX35_IO_ADDRESS(MX35_IOMUXC_BASE_ADDR));
+ mxc_arch_reset_init(MX35_IO_ADDRESS(MX35_WDOG_BASE_ADDR));
+}
+
+static struct mxc_gpio_port imx35_gpio_ports[] = {
+ DEFINE_IMX_GPIO_PORT_IRQ(MX35, 0, 1, MX35_INT_GPIO1),
+ DEFINE_IMX_GPIO_PORT_IRQ(MX35, 1, 2, MX35_INT_GPIO2),
+ DEFINE_IMX_GPIO_PORT_IRQ(MX35, 2, 3, MX35_INT_GPIO3),
+};
+
+void __init mx35_init_irq(void)
+{
+ mxc_init_irq(MX35_IO_ADDRESS(MX35_AVIC_BASE_ADDR));
+ mxc_gpio_init(imx35_gpio_ports, ARRAY_SIZE(imx35_gpio_ports));
+}
diff --git a/arch/arm/mach-mx3/mx31lilly-db.c b/arch/arm/mach-imx/mx31lilly-db.c
index 8f1a38ebf5c8..7d26f766a4ee 100644
--- a/arch/arm/mach-mx3/mx31lilly-db.c
+++ b/arch/arm/mach-imx/mx31lilly-db.c
@@ -34,11 +34,8 @@
#include <mach/common.h>
#include <mach/iomux-mx3.h>
#include <mach/board-mx31lilly.h>
-#include <mach/mx3fb.h>
-#include <mach/ipu.h>
#include "devices-imx31.h"
-#include "devices.h"
/*
* This file contains board-specific initialization routines for the
@@ -164,13 +161,13 @@ static const struct imxmmc_platform_data mmc_pdata __initconst = {
};
/* Framebuffer support */
-static struct ipu_platform_data ipu_data __initdata = {
+static const struct ipu_platform_data ipu_data __initconst = {
.irq_base = MXC_IPU_IRQ_START,
};
static const struct fb_videomode fb_modedb = {
/* 640x480 TFT panel (IPS-056T) */
- .name = "CRT-VGA",
+ .name = "CRT-VGA",
.refresh = 64,
.xres = 640,
.yres = 480,
@@ -187,7 +184,6 @@ static const struct fb_videomode fb_modedb = {
};
static struct mx3fb_platform_data fb_pdata __initdata = {
- .dma_dev = &mx3_ipu.dev,
.name = "CRT-VGA",
.mode = &fb_modedb,
.num_modes = 1,
@@ -202,8 +198,8 @@ static void __init mx31lilly_init_fb(void)
return;
}
- mxc_register_device(&mx3_ipu, &ipu_data);
- mxc_register_device(&mx3_fb, &fb_pdata);
+ imx31_add_ipu_core(&ipu_data);
+ imx31_add_mx3_sdc_fb(&fb_pdata);
gpio_direction_output(LCD_VCC_EN_GPIO, 1);
}
@@ -218,4 +214,3 @@ void __init mx31lilly_db_init(void)
imx31_add_mxc_mmc(0, &mmc_pdata);
mx31lilly_init_fb();
}
-
diff --git a/arch/arm/mach-mx3/mx31lite-db.c b/arch/arm/mach-imx/mx31lite-db.c
index 3124ea837ac7..5aa053edc17c 100644
--- a/arch/arm/mach-mx3/mx31lite-db.c
+++ b/arch/arm/mach-imx/mx31lite-db.c
@@ -37,7 +37,6 @@
#include <mach/board-mx31lite.h>
#include "devices-imx31.h"
-#include "devices.h"
/*
* This file contains board-specific initialization routines for the
@@ -200,5 +199,5 @@ void __init mx31lite_db_init(void)
imx31_add_spi_imx0(&spi0_pdata);
platform_device_register(&litekit_led_device);
imx31_add_imx2_wdt(NULL);
- mxc_register_device(&imx_rtc_device0, NULL);
+ imx31_add_mxc_rtc(NULL);
}
diff --git a/arch/arm/mach-mx3/mx31moboard-devboard.c b/arch/arm/mach-imx/mx31moboard-devboard.c
index 6410b9c48a02..0aa25364360d 100644
--- a/arch/arm/mach-mx3/mx31moboard-devboard.c
+++ b/arch/arm/mach-imx/mx31moboard-devboard.c
@@ -28,7 +28,6 @@
#include <mach/ulpi.h>
#include "devices-imx31.h"
-#include "devices.h"
static unsigned int devboard_pins[] = {
/* UART1 */
diff --git a/arch/arm/mach-mx3/mx31moboard-marxbot.c b/arch/arm/mach-imx/mx31moboard-marxbot.c
index 57f7b00cb709..bb639cbda4e5 100644
--- a/arch/arm/mach-mx3/mx31moboard-marxbot.c
+++ b/arch/arm/mach-imx/mx31moboard-marxbot.c
@@ -26,14 +26,12 @@
#include <mach/common.h>
#include <mach/hardware.h>
-#include <mach/imx-uart.h>
#include <mach/iomux-mx3.h>
#include <mach/ulpi.h>
#include <media/soc_camera.h>
#include "devices-imx31.h"
-#include "devices.h"
static unsigned int marxbot_pins[] = {
/* SDHC2 */
diff --git a/arch/arm/mach-mx3/mx31moboard-smartbot.c b/arch/arm/mach-imx/mx31moboard-smartbot.c
index 35f806e737c1..fabb801e7994 100644
--- a/arch/arm/mach-mx3/mx31moboard-smartbot.c
+++ b/arch/arm/mach-imx/mx31moboard-smartbot.c
@@ -32,7 +32,6 @@
#include <media/soc_camera.h>
#include "devices-imx31.h"
-#include "devices.h"
static unsigned int smartbot_pins[] = {
/* UART1 */
diff --git a/arch/arm/mach-mx3/pcm037.h b/arch/arm/mach-imx/pcm037.h
index d6929721a5fd..d6929721a5fd 100644
--- a/arch/arm/mach-mx3/pcm037.h
+++ b/arch/arm/mach-imx/pcm037.h
diff --git a/arch/arm/mach-integrator/Kconfig b/arch/arm/mach-integrator/Kconfig
index d701d32a07f1..dfd18f3b50e8 100644
--- a/arch/arm/mach-integrator/Kconfig
+++ b/arch/arm/mach-integrator/Kconfig
@@ -4,6 +4,7 @@ menu "Integrator Options"
config ARCH_INTEGRATOR_AP
bool "Support Integrator/AP and Integrator/PP2 platforms"
+ select CLKSRC_MMIO
select MIGHT_HAVE_PCI
help
Include support for the ARM(R) Integrator/AP and
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
index 980803ff348c..2fbbdd5eac35 100644
--- a/arch/arm/mach-integrator/integrator_ap.c
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -24,13 +24,14 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/string.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/amba/bus.h>
#include <linux/amba/kmi.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/mtd/physmap.h>
#include <mach/hardware.h>
#include <mach/platform.h>
@@ -43,7 +44,6 @@
#include <mach/lm.h>
#include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
#include <asm/mach/irq.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
@@ -180,13 +180,13 @@ static void __init ap_init_irq(void)
#ifdef CONFIG_PM
static unsigned long ic_irq_enable;
-static int irq_suspend(struct sys_device *dev, pm_message_t state)
+static int irq_suspend(void)
{
ic_irq_enable = readl(VA_IC_BASE + IRQ_ENABLE);
return 0;
}
-static int irq_resume(struct sys_device *dev)
+static void irq_resume(void)
{
/* disable all irq sources */
writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR);
@@ -194,33 +194,25 @@ static int irq_resume(struct sys_device *dev)
writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR);
writel(ic_irq_enable, VA_IC_BASE + IRQ_ENABLE_SET);
- return 0;
}
#else
#define irq_suspend NULL
#define irq_resume NULL
#endif
-static struct sysdev_class irq_class = {
- .name = "irq",
+static struct syscore_ops irq_syscore_ops = {
.suspend = irq_suspend,
.resume = irq_resume,
};
-static struct sys_device irq_device = {
- .id = 0,
- .cls = &irq_class,
-};
-
-static int __init irq_init_sysfs(void)
+static int __init irq_syscore_init(void)
{
- int ret = sysdev_class_register(&irq_class);
- if (ret == 0)
- ret = sysdev_register(&irq_device);
- return ret;
+ register_syscore_ops(&irq_syscore_ops);
+
+ return 0;
}
-device_initcall(irq_init_sysfs);
+device_initcall(irq_syscore_init);
/*
* Flash handling.
@@ -230,7 +222,7 @@ device_initcall(irq_init_sysfs);
#define EBI_CSR1 (VA_EBI_BASE + INTEGRATOR_EBI_CSR1_OFFSET)
#define EBI_LOCK (VA_EBI_BASE + INTEGRATOR_EBI_LOCK_OFFSET)
-static int ap_flash_init(void)
+static int ap_flash_init(struct platform_device *dev)
{
u32 tmp;
@@ -247,7 +239,7 @@ static int ap_flash_init(void)
return 0;
}
-static void ap_flash_exit(void)
+static void ap_flash_exit(struct platform_device *dev)
{
u32 tmp;
@@ -263,15 +255,14 @@ static void ap_flash_exit(void)
}
}
-static void ap_flash_set_vpp(int on)
+static void ap_flash_set_vpp(struct platform_device *pdev, int on)
{
void __iomem *reg = on ? SC_CTRLS : SC_CTRLC;
writel(INTEGRATOR_SC_CTRL_nFLVPPEN, reg);
}
-static struct flash_platform_data ap_flash_data = {
- .map_name = "cfi_probe",
+static struct physmap_flash_data ap_flash_data = {
.width = 4,
.init = ap_flash_init,
.exit = ap_flash_exit,
@@ -285,7 +276,7 @@ static struct resource cfi_flash_resource = {
};
static struct platform_device cfi_flash_device = {
- .name = "armflash",
+ .name = "physmap-flash",
.id = 0,
.dev = {
.platform_data = &ap_flash_data,
@@ -343,25 +334,9 @@ static void __init ap_init(void)
static unsigned long timer_reload;
-static void __iomem * const clksrc_base = (void __iomem *)TIMER2_VA_BASE;
-
-static cycle_t timersp_read(struct clocksource *cs)
-{
- return ~(readl(clksrc_base + TIMER_VALUE) & 0xffff);
-}
-
-static struct clocksource clocksource_timersp = {
- .name = "timer2",
- .rating = 200,
- .read = timersp_read,
- .mask = CLOCKSOURCE_MASK(16),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
static void integrator_clocksource_init(u32 khz)
{
- struct clocksource *cs = &clocksource_timersp;
- void __iomem *base = clksrc_base;
+ void __iomem *base = (void __iomem *)TIMER2_VA_BASE;
u32 ctrl = TIMER_CTRL_ENABLE;
if (khz >= 1500) {
@@ -372,7 +347,8 @@ static void integrator_clocksource_init(u32 khz)
writel(ctrl, base + TIMER_CTRL);
writel(0xffff, base + TIMER_LOAD);
- clocksource_register_khz(cs, khz);
+ clocksource_mmio_init(base + TIMER_VALUE, "timer2",
+ khz * 1000, 200, 16, clocksource_mmio_readl_down);
}
static void __iomem * const clkevt_base = (void __iomem *)TIMER1_VA_BASE;
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
index 9e3ce26023e8..4eb03ab5cb46 100644
--- a/arch/arm/mach-integrator/integrator_cp.c
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -22,6 +22,7 @@
#include <linux/io.h>
#include <linux/gfp.h>
#include <linux/clkdev.h>
+#include <linux/mtd/physmap.h>
#include <mach/hardware.h>
#include <mach/platform.h>
@@ -35,7 +36,6 @@
#include <mach/lm.h>
#include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
#include <asm/mach/irq.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
@@ -229,17 +229,24 @@ static struct clk cp_auxclk = {
.vcoreg = CM_AUXOSC,
};
+static struct clk sp804_clk = {
+ .rate = 1000000,
+};
+
static struct clk_lookup cp_lookups[] = {
{ /* CLCD */
.dev_id = "mb:c0",
.clk = &cp_auxclk,
+ }, { /* SP804 timers */
+ .dev_id = "sp804",
+ .clk = &sp804_clk,
},
};
/*
* Flash handling.
*/
-static int intcp_flash_init(void)
+static int intcp_flash_init(struct platform_device *dev)
{
u32 val;
@@ -250,7 +257,7 @@ static int intcp_flash_init(void)
return 0;
}
-static void intcp_flash_exit(void)
+static void intcp_flash_exit(struct platform_device *dev)
{
u32 val;
@@ -259,7 +266,7 @@ static void intcp_flash_exit(void)
writel(val, INTCP_VA_CTRL_BASE + INTCP_FLASHPROG);
}
-static void intcp_flash_set_vpp(int on)
+static void intcp_flash_set_vpp(struct platform_device *pdev, int on)
{
u32 val;
@@ -271,8 +278,7 @@ static void intcp_flash_set_vpp(int on)
writel(val, INTCP_VA_CTRL_BASE + INTCP_FLASHPROG);
}
-static struct flash_platform_data intcp_flash_data = {
- .map_name = "cfi_probe",
+static struct physmap_flash_data intcp_flash_data = {
.width = 4,
.init = intcp_flash_init,
.exit = intcp_flash_exit,
@@ -286,7 +292,7 @@ static struct resource intcp_flash_resource = {
};
static struct platform_device intcp_flash_device = {
- .name = "armflash",
+ .name = "physmap-flash",
.id = 0,
.dev = {
.platform_data = &intcp_flash_data,
@@ -476,8 +482,8 @@ static void __init intcp_timer_init(void)
writel(0, TIMER1_VA_BASE + TIMER_CTRL);
writel(0, TIMER2_VA_BASE + TIMER_CTRL);
- sp804_clocksource_init(TIMER2_VA_BASE);
- sp804_clockevents_init(TIMER1_VA_BASE, IRQ_TIMERINT1);
+ sp804_clocksource_init(TIMER2_VA_BASE, "timer2");
+ sp804_clockevents_init(TIMER1_VA_BASE, IRQ_TIMERINT1, "timer1");
}
static struct sys_timer cp_timer = {
diff --git a/arch/arm/mach-iop32x/include/mach/uncompress.h b/arch/arm/mach-iop32x/include/mach/uncompress.h
index b247551b6f5a..4fd715496f45 100644
--- a/arch/arm/mach-iop32x/include/mach/uncompress.h
+++ b/arch/arm/mach-iop32x/include/mach/uncompress.h
@@ -7,7 +7,7 @@
#include <linux/serial_reg.h>
#include <mach/hardware.h>
-static volatile u8 *uart_base;
+volatile u8 *uart_base;
#define TX_DONE (UART_LSR_TEMT | UART_LSR_THRE)
diff --git a/arch/arm/mach-iop33x/include/mach/uncompress.h b/arch/arm/mach-iop33x/include/mach/uncompress.h
index b42423f63302..f99bb848c5a1 100644
--- a/arch/arm/mach-iop33x/include/mach/uncompress.h
+++ b/arch/arm/mach-iop33x/include/mach/uncompress.h
@@ -7,7 +7,7 @@
#include <linux/serial_reg.h>
#include <mach/hardware.h>
-static volatile u32 *uart_base;
+volatile u32 *uart_base;
#define TX_DONE (UART_LSR_TEMT | UART_LSR_THRE)
diff --git a/arch/arm/mach-ixp4xx/common-pci.c b/arch/arm/mach-ixp4xx/common-pci.c
index a54b3db80366..e9a589395723 100644
--- a/arch/arm/mach-ixp4xx/common-pci.c
+++ b/arch/arm/mach-ixp4xx/common-pci.c
@@ -342,29 +342,6 @@ int dma_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size)
return (dev->bus == &pci_bus_type ) && ((dma_addr + size) >= SZ_64M);
}
-/*
- * Only first 64MB of memory can be accessed via PCI.
- * We use GFP_DMA to allocate safe buffers to do map/unmap.
- * This is really ugly and we need a better way of specifying
- * DMA-capable regions of memory.
- */
-void __init ixp4xx_adjust_zones(unsigned long *zone_size,
- unsigned long *zhole_size)
-{
- unsigned int sz = SZ_64M >> PAGE_SHIFT;
-
- /*
- * Only adjust if > 64M on current system
- */
- if (zone_size[0] <= sz)
- return;
-
- zone_size[1] = zone_size[0] - sz;
- zone_size[0] = sz;
- zhole_size[1] = zhole_size[0];
- zhole_size[0] = 0;
-}
-
void __init ixp4xx_pci_preinit(void)
{
unsigned long cpuid = read_cpuid_id();
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index ed19bc314318..74ed81a3cb1a 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -419,26 +419,14 @@ static void notrace ixp4xx_update_sched_clock(void)
/*
* clocksource
*/
-static cycle_t ixp4xx_get_cycles(struct clocksource *cs)
-{
- return *IXP4XX_OSTS;
-}
-
-static struct clocksource clocksource_ixp4xx = {
- .name = "OSTS",
- .rating = 200,
- .read = ixp4xx_get_cycles,
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
unsigned long ixp4xx_timer_freq = IXP4XX_TIMER_FREQ;
EXPORT_SYMBOL(ixp4xx_timer_freq);
static void __init ixp4xx_clocksource_init(void)
{
init_sched_clock(&cd, ixp4xx_update_sched_clock, 32, ixp4xx_timer_freq);
- clocksource_register_hz(&clocksource_ixp4xx, ixp4xx_timer_freq);
+ clocksource_mmio_init(&IXP4XX_OSTS, "OSTS", ixp4xx_timer_freq, 200, 32,
+ clocksource_mmio_readl_up);
}
/*
diff --git a/arch/arm/mach-ixp4xx/include/mach/ixp46x_ts.h b/arch/arm/mach-ixp4xx/include/mach/ixp46x_ts.h
new file mode 100644
index 000000000000..292d55ed2113
--- /dev/null
+++ b/arch/arm/mach-ixp4xx/include/mach/ixp46x_ts.h
@@ -0,0 +1,78 @@
+/*
+ * PTP 1588 clock using the IXP46X
+ *
+ * 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 _IXP46X_TS_H_
+#define _IXP46X_TS_H_
+
+#define DEFAULT_ADDEND 0xF0000029
+#define TICKS_NS_SHIFT 4
+
+struct ixp46x_channel_ctl {
+ u32 ch_control; /* 0x40 Time Synchronization Channel Control */
+ u32 ch_event; /* 0x44 Time Synchronization Channel Event */
+ u32 tx_snap_lo; /* 0x48 Transmit Snapshot Low Register */
+ u32 tx_snap_hi; /* 0x4C Transmit Snapshot High Register */
+ u32 rx_snap_lo; /* 0x50 Receive Snapshot Low Register */
+ u32 rx_snap_hi; /* 0x54 Receive Snapshot High Register */
+ u32 src_uuid_lo; /* 0x58 Source UUID0 Low Register */
+ u32 src_uuid_hi; /* 0x5C Sequence Identifier/Source UUID0 High */
+};
+
+struct ixp46x_ts_regs {
+ u32 control; /* 0x00 Time Sync Control Register */
+ u32 event; /* 0x04 Time Sync Event Register */
+ u32 addend; /* 0x08 Time Sync Addend Register */
+ u32 accum; /* 0x0C Time Sync Accumulator Register */
+ u32 test; /* 0x10 Time Sync Test Register */
+ u32 unused; /* 0x14 */
+ u32 rsystime_lo; /* 0x18 RawSystemTime_Low Register */
+ u32 rsystime_hi; /* 0x1C RawSystemTime_High Register */
+ u32 systime_lo; /* 0x20 SystemTime_Low Register */
+ u32 systime_hi; /* 0x24 SystemTime_High Register */
+ u32 trgt_lo; /* 0x28 TargetTime_Low Register */
+ u32 trgt_hi; /* 0x2C TargetTime_High Register */
+ u32 asms_lo; /* 0x30 Auxiliary Slave Mode Snapshot Low */
+ u32 asms_hi; /* 0x34 Auxiliary Slave Mode Snapshot High */
+ u32 amms_lo; /* 0x38 Auxiliary Master Mode Snapshot Low */
+ u32 amms_hi; /* 0x3C Auxiliary Master Mode Snapshot High */
+
+ struct ixp46x_channel_ctl channel[3];
+};
+
+/* 0x00 Time Sync Control Register Bits */
+#define TSCR_AMM (1<<3)
+#define TSCR_ASM (1<<2)
+#define TSCR_TTM (1<<1)
+#define TSCR_RST (1<<0)
+
+/* 0x04 Time Sync Event Register Bits */
+#define TSER_SNM (1<<3)
+#define TSER_SNS (1<<2)
+#define TTIPEND (1<<1)
+
+/* 0x40 Time Synchronization Channel Control Register Bits */
+#define MASTER_MODE (1<<0)
+#define TIMESTAMP_ALL (1<<1)
+
+/* 0x44 Time Synchronization Channel Event Register Bits */
+#define TX_SNAPSHOT_LOCKED (1<<0)
+#define RX_SNAPSHOT_LOCKED (1<<1)
+
+#endif
diff --git a/arch/arm/mach-ixp4xx/include/mach/memory.h b/arch/arm/mach-ixp4xx/include/mach/memory.h
index 6d388c9d0e20..34e79404671a 100644
--- a/arch/arm/mach-ixp4xx/include/mach/memory.h
+++ b/arch/arm/mach-ixp4xx/include/mach/memory.h
@@ -14,16 +14,8 @@
*/
#define PLAT_PHYS_OFFSET UL(0x00000000)
-#if !defined(__ASSEMBLY__) && defined(CONFIG_PCI)
-
-void ixp4xx_adjust_zones(unsigned long *size, unsigned long *holes);
-
-#define arch_adjust_zones(size, holes) \
- ixp4xx_adjust_zones(size, holes)
-
-#define ISA_DMA_THRESHOLD (SZ_64M - 1)
-#define MAX_DMA_ADDRESS (PAGE_OFFSET + SZ_64M)
-
+#ifdef CONFIG_PCI
+#define ARM_DMA_ZONE_SIZE SZ_64M
#endif
#endif
diff --git a/arch/arm/mach-ixp4xx/include/mach/uncompress.h b/arch/arm/mach-ixp4xx/include/mach/uncompress.h
index 2db0078a8cf2..219d7c1dcdba 100644
--- a/arch/arm/mach-ixp4xx/include/mach/uncompress.h
+++ b/arch/arm/mach-ixp4xx/include/mach/uncompress.h
@@ -19,7 +19,7 @@
#define TX_DONE (UART_LSR_TEMT|UART_LSR_THRE)
-static volatile u32* uart_base;
+volatile u32* uart_base;
static inline void putc(int c)
{
diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c
index 20e71df3e3bb..f3248cfbe51d 100644
--- a/arch/arm/mach-kirkwood/common.c
+++ b/arch/arm/mach-kirkwood/common.c
@@ -13,11 +13,9 @@
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
#include <linux/mbus.h>
-#include <linux/mv643xx_eth.h>
-#include <linux/mv643xx_i2c.h>
#include <linux/ata_platform.h>
#include <linux/mtd/nand.h>
-#include <linux/spi/orion_spi.h>
+#include <linux/dma-mapping.h>
#include <net/dsa.h>
#include <asm/page.h>
#include <asm/timex.h>
@@ -28,11 +26,9 @@
#include <mach/bridge-regs.h>
#include <plat/audio.h>
#include <plat/cache-feroceon-l2.h>
-#include <plat/ehci-orion.h>
#include <plat/mvsdio.h>
-#include <plat/mv_xor.h>
#include <plat/orion_nand.h>
-#include <plat/orion_wdt.h>
+#include <plat/common.h>
#include <plat/time.h>
#include "common.h"
@@ -69,210 +65,52 @@ void __init kirkwood_map_io(void)
* registered. Some reserved bits must be set to 1.
*/
unsigned int kirkwood_clk_ctrl = CGC_DUNIT | CGC_RESERVED;
-
-
-/*****************************************************************************
- * EHCI
- ****************************************************************************/
-static struct orion_ehci_data kirkwood_ehci_data = {
- .dram = &kirkwood_mbus_dram_info,
- .phy_version = EHCI_PHY_NA,
-};
-
-static u64 ehci_dmamask = 0xffffffffUL;
/*****************************************************************************
* EHCI0
****************************************************************************/
-static struct resource kirkwood_ehci_resources[] = {
- {
- .start = USB_PHYS_BASE,
- .end = USB_PHYS_BASE + 0x0fff,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_KIRKWOOD_USB,
- .end = IRQ_KIRKWOOD_USB,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device kirkwood_ehci = {
- .name = "orion-ehci",
- .id = 0,
- .dev = {
- .dma_mask = &ehci_dmamask,
- .coherent_dma_mask = 0xffffffff,
- .platform_data = &kirkwood_ehci_data,
- },
- .resource = kirkwood_ehci_resources,
- .num_resources = ARRAY_SIZE(kirkwood_ehci_resources),
-};
-
void __init kirkwood_ehci_init(void)
{
kirkwood_clk_ctrl |= CGC_USB0;
- platform_device_register(&kirkwood_ehci);
+ orion_ehci_init(&kirkwood_mbus_dram_info,
+ USB_PHYS_BASE, IRQ_KIRKWOOD_USB);
}
/*****************************************************************************
* GE00
****************************************************************************/
-struct mv643xx_eth_shared_platform_data kirkwood_ge00_shared_data = {
- .dram = &kirkwood_mbus_dram_info,
-};
-
-static struct resource kirkwood_ge00_shared_resources[] = {
- {
- .name = "ge00 base",
- .start = GE00_PHYS_BASE + 0x2000,
- .end = GE00_PHYS_BASE + 0x3fff,
- .flags = IORESOURCE_MEM,
- }, {
- .name = "ge00 err irq",
- .start = IRQ_KIRKWOOD_GE00_ERR,
- .end = IRQ_KIRKWOOD_GE00_ERR,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device kirkwood_ge00_shared = {
- .name = MV643XX_ETH_SHARED_NAME,
- .id = 0,
- .dev = {
- .platform_data = &kirkwood_ge00_shared_data,
- },
- .num_resources = ARRAY_SIZE(kirkwood_ge00_shared_resources),
- .resource = kirkwood_ge00_shared_resources,
-};
-
-static struct resource kirkwood_ge00_resources[] = {
- {
- .name = "ge00 irq",
- .start = IRQ_KIRKWOOD_GE00_SUM,
- .end = IRQ_KIRKWOOD_GE00_SUM,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device kirkwood_ge00 = {
- .name = MV643XX_ETH_NAME,
- .id = 0,
- .num_resources = 1,
- .resource = kirkwood_ge00_resources,
- .dev = {
- .coherent_dma_mask = 0xffffffff,
- },
-};
-
void __init kirkwood_ge00_init(struct mv643xx_eth_platform_data *eth_data)
{
kirkwood_clk_ctrl |= CGC_GE0;
- eth_data->shared = &kirkwood_ge00_shared;
- kirkwood_ge00.dev.platform_data = eth_data;
- platform_device_register(&kirkwood_ge00_shared);
- platform_device_register(&kirkwood_ge00);
+ orion_ge00_init(eth_data, &kirkwood_mbus_dram_info,
+ GE00_PHYS_BASE, IRQ_KIRKWOOD_GE00_SUM,
+ IRQ_KIRKWOOD_GE00_ERR, kirkwood_tclk);
}
/*****************************************************************************
* GE01
****************************************************************************/
-struct mv643xx_eth_shared_platform_data kirkwood_ge01_shared_data = {
- .dram = &kirkwood_mbus_dram_info,
- .shared_smi = &kirkwood_ge00_shared,
-};
-
-static struct resource kirkwood_ge01_shared_resources[] = {
- {
- .name = "ge01 base",
- .start = GE01_PHYS_BASE + 0x2000,
- .end = GE01_PHYS_BASE + 0x3fff,
- .flags = IORESOURCE_MEM,
- }, {
- .name = "ge01 err irq",
- .start = IRQ_KIRKWOOD_GE01_ERR,
- .end = IRQ_KIRKWOOD_GE01_ERR,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device kirkwood_ge01_shared = {
- .name = MV643XX_ETH_SHARED_NAME,
- .id = 1,
- .dev = {
- .platform_data = &kirkwood_ge01_shared_data,
- },
- .num_resources = ARRAY_SIZE(kirkwood_ge01_shared_resources),
- .resource = kirkwood_ge01_shared_resources,
-};
-
-static struct resource kirkwood_ge01_resources[] = {
- {
- .name = "ge01 irq",
- .start = IRQ_KIRKWOOD_GE01_SUM,
- .end = IRQ_KIRKWOOD_GE01_SUM,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device kirkwood_ge01 = {
- .name = MV643XX_ETH_NAME,
- .id = 1,
- .num_resources = 1,
- .resource = kirkwood_ge01_resources,
- .dev = {
- .coherent_dma_mask = 0xffffffff,
- },
-};
-
void __init kirkwood_ge01_init(struct mv643xx_eth_platform_data *eth_data)
{
+
kirkwood_clk_ctrl |= CGC_GE1;
- eth_data->shared = &kirkwood_ge01_shared;
- kirkwood_ge01.dev.platform_data = eth_data;
- platform_device_register(&kirkwood_ge01_shared);
- platform_device_register(&kirkwood_ge01);
+ orion_ge01_init(eth_data, &kirkwood_mbus_dram_info,
+ GE01_PHYS_BASE, IRQ_KIRKWOOD_GE01_SUM,
+ IRQ_KIRKWOOD_GE01_ERR, kirkwood_tclk);
}
/*****************************************************************************
* Ethernet switch
****************************************************************************/
-static struct resource kirkwood_switch_resources[] = {
- {
- .start = 0,
- .end = 0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device kirkwood_switch_device = {
- .name = "dsa",
- .id = 0,
- .num_resources = 0,
- .resource = kirkwood_switch_resources,
-};
-
void __init kirkwood_ge00_switch_init(struct dsa_platform_data *d, int irq)
{
- int i;
-
- if (irq != NO_IRQ) {
- kirkwood_switch_resources[0].start = irq;
- kirkwood_switch_resources[0].end = irq;
- kirkwood_switch_device.num_resources = 1;
- }
-
- d->netdev = &kirkwood_ge00.dev;
- for (i = 0; i < d->nr_chips; i++)
- d->chip[i].mii_bus = &kirkwood_ge00_shared.dev;
- kirkwood_switch_device.dev.platform_data = d;
-
- platform_device_register(&kirkwood_switch_device);
+ orion_ge00_switch_init(d, irq);
}
@@ -325,53 +163,23 @@ void __init kirkwood_nand_init_rnb(struct mtd_partition *parts, int nr_parts,
/*****************************************************************************
* SoC RTC
****************************************************************************/
-static struct resource kirkwood_rtc_resource = {
- .start = RTC_PHYS_BASE,
- .end = RTC_PHYS_BASE + SZ_16 - 1,
- .flags = IORESOURCE_MEM,
-};
-
static void __init kirkwood_rtc_init(void)
{
- platform_device_register_simple("rtc-mv", -1, &kirkwood_rtc_resource, 1);
+ orion_rtc_init(RTC_PHYS_BASE, IRQ_KIRKWOOD_RTC);
}
/*****************************************************************************
* SATA
****************************************************************************/
-static struct resource kirkwood_sata_resources[] = {
- {
- .name = "sata base",
- .start = SATA_PHYS_BASE,
- .end = SATA_PHYS_BASE + 0x5000 - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .name = "sata irq",
- .start = IRQ_KIRKWOOD_SATA,
- .end = IRQ_KIRKWOOD_SATA,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device kirkwood_sata = {
- .name = "sata_mv",
- .id = 0,
- .dev = {
- .coherent_dma_mask = 0xffffffff,
- },
- .num_resources = ARRAY_SIZE(kirkwood_sata_resources),
- .resource = kirkwood_sata_resources,
-};
-
void __init kirkwood_sata_init(struct mv_sata_platform_data *sata_data)
{
kirkwood_clk_ctrl |= CGC_SATA0;
if (sata_data->n_ports > 1)
kirkwood_clk_ctrl |= CGC_SATA1;
- sata_data->dram = &kirkwood_mbus_dram_info;
- kirkwood_sata.dev.platform_data = sata_data;
- platform_device_register(&kirkwood_sata);
+
+ orion_sata_init(sata_data, &kirkwood_mbus_dram_info,
+ SATA_PHYS_BASE, IRQ_KIRKWOOD_SATA);
}
@@ -391,14 +199,14 @@ static struct resource mvsdio_resources[] = {
},
};
-static u64 mvsdio_dmamask = 0xffffffffUL;
+static u64 mvsdio_dmamask = DMA_BIT_MASK(32);
static struct platform_device kirkwood_sdio = {
.name = "mvsdio",
.id = -1,
.dev = {
.dma_mask = &mvsdio_dmamask,
- .coherent_dma_mask = 0xffffffff,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
},
.num_resources = ARRAY_SIZE(mvsdio_resources),
.resource = mvsdio_resources,
@@ -423,424 +231,84 @@ void __init kirkwood_sdio_init(struct mvsdio_platform_data *mvsdio_data)
/*****************************************************************************
* SPI
****************************************************************************/
-static struct orion_spi_info kirkwood_spi_plat_data = {
-};
-
-static struct resource kirkwood_spi_resources[] = {
- {
- .start = SPI_PHYS_BASE,
- .end = SPI_PHYS_BASE + SZ_512 - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device kirkwood_spi = {
- .name = "orion_spi",
- .id = 0,
- .resource = kirkwood_spi_resources,
- .dev = {
- .platform_data = &kirkwood_spi_plat_data,
- },
- .num_resources = ARRAY_SIZE(kirkwood_spi_resources),
-};
-
void __init kirkwood_spi_init()
{
kirkwood_clk_ctrl |= CGC_RUNIT;
- platform_device_register(&kirkwood_spi);
+ orion_spi_init(SPI_PHYS_BASE, kirkwood_tclk);
}
/*****************************************************************************
* I2C
****************************************************************************/
-static struct mv64xxx_i2c_pdata kirkwood_i2c_pdata = {
- .freq_m = 8, /* assumes 166 MHz TCLK */
- .freq_n = 3,
- .timeout = 1000, /* Default timeout of 1 second */
-};
-
-static struct resource kirkwood_i2c_resources[] = {
- {
- .start = I2C_PHYS_BASE,
- .end = I2C_PHYS_BASE + 0x1f,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_KIRKWOOD_TWSI,
- .end = IRQ_KIRKWOOD_TWSI,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device kirkwood_i2c = {
- .name = MV64XXX_I2C_CTLR_NAME,
- .id = 0,
- .num_resources = ARRAY_SIZE(kirkwood_i2c_resources),
- .resource = kirkwood_i2c_resources,
- .dev = {
- .platform_data = &kirkwood_i2c_pdata,
- },
-};
-
void __init kirkwood_i2c_init(void)
{
- platform_device_register(&kirkwood_i2c);
+ orion_i2c_init(I2C_PHYS_BASE, IRQ_KIRKWOOD_TWSI, 8);
}
/*****************************************************************************
* UART0
****************************************************************************/
-static struct plat_serial8250_port kirkwood_uart0_data[] = {
- {
- .mapbase = UART0_PHYS_BASE,
- .membase = (char *)UART0_VIRT_BASE,
- .irq = IRQ_KIRKWOOD_UART_0,
- .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = 0,
- }, {
- },
-};
-
-static struct resource kirkwood_uart0_resources[] = {
- {
- .start = UART0_PHYS_BASE,
- .end = UART0_PHYS_BASE + 0xff,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_KIRKWOOD_UART_0,
- .end = IRQ_KIRKWOOD_UART_0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device kirkwood_uart0 = {
- .name = "serial8250",
- .id = 0,
- .dev = {
- .platform_data = kirkwood_uart0_data,
- },
- .resource = kirkwood_uart0_resources,
- .num_resources = ARRAY_SIZE(kirkwood_uart0_resources),
-};
void __init kirkwood_uart0_init(void)
{
- platform_device_register(&kirkwood_uart0);
+ orion_uart0_init(UART0_VIRT_BASE, UART0_PHYS_BASE,
+ IRQ_KIRKWOOD_UART_0, kirkwood_tclk);
}
/*****************************************************************************
* UART1
****************************************************************************/
-static struct plat_serial8250_port kirkwood_uart1_data[] = {
- {
- .mapbase = UART1_PHYS_BASE,
- .membase = (char *)UART1_VIRT_BASE,
- .irq = IRQ_KIRKWOOD_UART_1,
- .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = 0,
- }, {
- },
-};
-
-static struct resource kirkwood_uart1_resources[] = {
- {
- .start = UART1_PHYS_BASE,
- .end = UART1_PHYS_BASE + 0xff,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_KIRKWOOD_UART_1,
- .end = IRQ_KIRKWOOD_UART_1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device kirkwood_uart1 = {
- .name = "serial8250",
- .id = 1,
- .dev = {
- .platform_data = kirkwood_uart1_data,
- },
- .resource = kirkwood_uart1_resources,
- .num_resources = ARRAY_SIZE(kirkwood_uart1_resources),
-};
-
void __init kirkwood_uart1_init(void)
{
- platform_device_register(&kirkwood_uart1);
+ orion_uart1_init(UART1_VIRT_BASE, UART1_PHYS_BASE,
+ IRQ_KIRKWOOD_UART_1, kirkwood_tclk);
}
-
/*****************************************************************************
* Cryptographic Engines and Security Accelerator (CESA)
****************************************************************************/
-
-static struct resource kirkwood_crypto_res[] = {
- {
- .name = "regs",
- .start = CRYPTO_PHYS_BASE,
- .end = CRYPTO_PHYS_BASE + 0xffff,
- .flags = IORESOURCE_MEM,
- }, {
- .name = "sram",
- .start = KIRKWOOD_SRAM_PHYS_BASE,
- .end = KIRKWOOD_SRAM_PHYS_BASE + KIRKWOOD_SRAM_SIZE - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .name = "crypto interrupt",
- .start = IRQ_KIRKWOOD_CRYPTO,
- .end = IRQ_KIRKWOOD_CRYPTO,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device kirkwood_crypto_device = {
- .name = "mv_crypto",
- .id = -1,
- .num_resources = ARRAY_SIZE(kirkwood_crypto_res),
- .resource = kirkwood_crypto_res,
-};
-
void __init kirkwood_crypto_init(void)
{
kirkwood_clk_ctrl |= CGC_CRYPTO;
- platform_device_register(&kirkwood_crypto_device);
+ orion_crypto_init(CRYPTO_PHYS_BASE, KIRKWOOD_SRAM_PHYS_BASE,
+ KIRKWOOD_SRAM_SIZE, IRQ_KIRKWOOD_CRYPTO);
}
/*****************************************************************************
- * XOR
- ****************************************************************************/
-static struct mv_xor_platform_shared_data kirkwood_xor_shared_data = {
- .dram = &kirkwood_mbus_dram_info,
-};
-
-static u64 kirkwood_xor_dmamask = DMA_BIT_MASK(32);
-
-
-/*****************************************************************************
* XOR0
****************************************************************************/
-static struct resource kirkwood_xor0_shared_resources[] = {
- {
- .name = "xor 0 low",
- .start = XOR0_PHYS_BASE,
- .end = XOR0_PHYS_BASE + 0xff,
- .flags = IORESOURCE_MEM,
- }, {
- .name = "xor 0 high",
- .start = XOR0_HIGH_PHYS_BASE,
- .end = XOR0_HIGH_PHYS_BASE + 0xff,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device kirkwood_xor0_shared = {
- .name = MV_XOR_SHARED_NAME,
- .id = 0,
- .dev = {
- .platform_data = &kirkwood_xor_shared_data,
- },
- .num_resources = ARRAY_SIZE(kirkwood_xor0_shared_resources),
- .resource = kirkwood_xor0_shared_resources,
-};
-
-static struct resource kirkwood_xor00_resources[] = {
- [0] = {
- .start = IRQ_KIRKWOOD_XOR_00,
- .end = IRQ_KIRKWOOD_XOR_00,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct mv_xor_platform_data kirkwood_xor00_data = {
- .shared = &kirkwood_xor0_shared,
- .hw_id = 0,
- .pool_size = PAGE_SIZE,
-};
-
-static struct platform_device kirkwood_xor00_channel = {
- .name = MV_XOR_NAME,
- .id = 0,
- .num_resources = ARRAY_SIZE(kirkwood_xor00_resources),
- .resource = kirkwood_xor00_resources,
- .dev = {
- .dma_mask = &kirkwood_xor_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(64),
- .platform_data = &kirkwood_xor00_data,
- },
-};
-
-static struct resource kirkwood_xor01_resources[] = {
- [0] = {
- .start = IRQ_KIRKWOOD_XOR_01,
- .end = IRQ_KIRKWOOD_XOR_01,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct mv_xor_platform_data kirkwood_xor01_data = {
- .shared = &kirkwood_xor0_shared,
- .hw_id = 1,
- .pool_size = PAGE_SIZE,
-};
-
-static struct platform_device kirkwood_xor01_channel = {
- .name = MV_XOR_NAME,
- .id = 1,
- .num_resources = ARRAY_SIZE(kirkwood_xor01_resources),
- .resource = kirkwood_xor01_resources,
- .dev = {
- .dma_mask = &kirkwood_xor_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(64),
- .platform_data = &kirkwood_xor01_data,
- },
-};
-
static void __init kirkwood_xor0_init(void)
{
kirkwood_clk_ctrl |= CGC_XOR0;
- platform_device_register(&kirkwood_xor0_shared);
- /*
- * two engines can't do memset simultaneously, this limitation
- * satisfied by removing memset support from one of the engines.
- */
- dma_cap_set(DMA_MEMCPY, kirkwood_xor00_data.cap_mask);
- dma_cap_set(DMA_XOR, kirkwood_xor00_data.cap_mask);
- platform_device_register(&kirkwood_xor00_channel);
-
- dma_cap_set(DMA_MEMCPY, kirkwood_xor01_data.cap_mask);
- dma_cap_set(DMA_MEMSET, kirkwood_xor01_data.cap_mask);
- dma_cap_set(DMA_XOR, kirkwood_xor01_data.cap_mask);
- platform_device_register(&kirkwood_xor01_channel);
+ orion_xor0_init(&kirkwood_mbus_dram_info,
+ XOR0_PHYS_BASE, XOR0_HIGH_PHYS_BASE,
+ IRQ_KIRKWOOD_XOR_00, IRQ_KIRKWOOD_XOR_01);
}
/*****************************************************************************
* XOR1
****************************************************************************/
-static struct resource kirkwood_xor1_shared_resources[] = {
- {
- .name = "xor 1 low",
- .start = XOR1_PHYS_BASE,
- .end = XOR1_PHYS_BASE + 0xff,
- .flags = IORESOURCE_MEM,
- }, {
- .name = "xor 1 high",
- .start = XOR1_HIGH_PHYS_BASE,
- .end = XOR1_HIGH_PHYS_BASE + 0xff,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device kirkwood_xor1_shared = {
- .name = MV_XOR_SHARED_NAME,
- .id = 1,
- .dev = {
- .platform_data = &kirkwood_xor_shared_data,
- },
- .num_resources = ARRAY_SIZE(kirkwood_xor1_shared_resources),
- .resource = kirkwood_xor1_shared_resources,
-};
-
-static struct resource kirkwood_xor10_resources[] = {
- [0] = {
- .start = IRQ_KIRKWOOD_XOR_10,
- .end = IRQ_KIRKWOOD_XOR_10,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct mv_xor_platform_data kirkwood_xor10_data = {
- .shared = &kirkwood_xor1_shared,
- .hw_id = 0,
- .pool_size = PAGE_SIZE,
-};
-
-static struct platform_device kirkwood_xor10_channel = {
- .name = MV_XOR_NAME,
- .id = 2,
- .num_resources = ARRAY_SIZE(kirkwood_xor10_resources),
- .resource = kirkwood_xor10_resources,
- .dev = {
- .dma_mask = &kirkwood_xor_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(64),
- .platform_data = &kirkwood_xor10_data,
- },
-};
-
-static struct resource kirkwood_xor11_resources[] = {
- [0] = {
- .start = IRQ_KIRKWOOD_XOR_11,
- .end = IRQ_KIRKWOOD_XOR_11,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct mv_xor_platform_data kirkwood_xor11_data = {
- .shared = &kirkwood_xor1_shared,
- .hw_id = 1,
- .pool_size = PAGE_SIZE,
-};
-
-static struct platform_device kirkwood_xor11_channel = {
- .name = MV_XOR_NAME,
- .id = 3,
- .num_resources = ARRAY_SIZE(kirkwood_xor11_resources),
- .resource = kirkwood_xor11_resources,
- .dev = {
- .dma_mask = &kirkwood_xor_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(64),
- .platform_data = &kirkwood_xor11_data,
- },
-};
-
static void __init kirkwood_xor1_init(void)
{
kirkwood_clk_ctrl |= CGC_XOR1;
- platform_device_register(&kirkwood_xor1_shared);
- /*
- * two engines can't do memset simultaneously, this limitation
- * satisfied by removing memset support from one of the engines.
- */
- dma_cap_set(DMA_MEMCPY, kirkwood_xor10_data.cap_mask);
- dma_cap_set(DMA_XOR, kirkwood_xor10_data.cap_mask);
- platform_device_register(&kirkwood_xor10_channel);
-
- dma_cap_set(DMA_MEMCPY, kirkwood_xor11_data.cap_mask);
- dma_cap_set(DMA_MEMSET, kirkwood_xor11_data.cap_mask);
- dma_cap_set(DMA_XOR, kirkwood_xor11_data.cap_mask);
- platform_device_register(&kirkwood_xor11_channel);
+ orion_xor1_init(XOR1_PHYS_BASE, XOR1_HIGH_PHYS_BASE,
+ IRQ_KIRKWOOD_XOR_10, IRQ_KIRKWOOD_XOR_11);
}
/*****************************************************************************
* Watchdog
****************************************************************************/
-static struct orion_wdt_platform_data kirkwood_wdt_data = {
- .tclk = 0,
-};
-
-static struct platform_device kirkwood_wdt_device = {
- .name = "orion_wdt",
- .id = -1,
- .dev = {
- .platform_data = &kirkwood_wdt_data,
- },
- .num_resources = 0,
-};
-
static void __init kirkwood_wdt_init(void)
{
- kirkwood_wdt_data.tclk = kirkwood_tclk;
- platform_device_register(&kirkwood_wdt_device);
+ orion_wdt_init(kirkwood_tclk);
}
@@ -984,11 +452,6 @@ void __init kirkwood_init(void)
{
printk(KERN_INFO "Kirkwood: %s, TCLK=%d.\n",
kirkwood_id(), kirkwood_tclk);
- kirkwood_ge00_shared_data.t_clk = kirkwood_tclk;
- kirkwood_ge01_shared_data.t_clk = kirkwood_tclk;
- 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;
/*
diff --git a/arch/arm/mach-kirkwood/include/mach/irqs.h b/arch/arm/mach-kirkwood/include/mach/irqs.h
index 9da2eb59180b..2bf8161e3b51 100644
--- a/arch/arm/mach-kirkwood/include/mach/irqs.h
+++ b/arch/arm/mach-kirkwood/include/mach/irqs.h
@@ -51,6 +51,7 @@
#define IRQ_KIRKWOOD_GPIO_HIGH_16_23 41
#define IRQ_KIRKWOOD_GE00_ERR 46
#define IRQ_KIRKWOOD_GE01_ERR 47
+#define IRQ_KIRKWOOD_RTC 53
/*
* KIRKWOOD General Purpose Pins
diff --git a/arch/arm/mach-kirkwood/mpp.c b/arch/arm/mach-kirkwood/mpp.c
index 7ce201848067..b0a7d979a8ed 100644
--- a/arch/arm/mach-kirkwood/mpp.c
+++ b/arch/arm/mach-kirkwood/mpp.c
@@ -14,6 +14,7 @@
#include <linux/io.h>
#include <asm/gpio.h>
#include <mach/hardware.h>
+#include <plat/mpp.h>
#include "common.h"
#include "mpp.h"
@@ -36,61 +37,8 @@ static unsigned int __init kirkwood_variant(void)
return 0;
}
-#define MPP_CTRL(i) (DEV_BUS_VIRT_BASE + (i) * 4)
-#define MPP_NR_REGS (1 + MPP_MAX/8)
-
void __init kirkwood_mpp_conf(unsigned int *mpp_list)
{
- u32 mpp_ctrl[MPP_NR_REGS];
- unsigned int variant_mask;
- int i;
-
- variant_mask = kirkwood_variant();
- if (!variant_mask)
- return;
-
- printk(KERN_DEBUG "initial MPP regs:");
- for (i = 0; i < MPP_NR_REGS; i++) {
- mpp_ctrl[i] = readl(MPP_CTRL(i));
- printk(" %08x", mpp_ctrl[i]);
- }
- printk("\n");
-
- for ( ; *mpp_list; mpp_list++) {
- unsigned int num = MPP_NUM(*mpp_list);
- unsigned int sel = MPP_SEL(*mpp_list);
- int shift, gpio_mode;
-
- if (num > MPP_MAX) {
- printk(KERN_ERR "kirkwood_mpp_conf: invalid MPP "
- "number (%u)\n", num);
- continue;
- }
- if (!(*mpp_list & variant_mask)) {
- printk(KERN_WARNING
- "kirkwood_mpp_conf: requested MPP%u config "
- "unavailable on this hardware\n", num);
- continue;
- }
-
- shift = (num & 7) << 2;
- mpp_ctrl[num / 8] &= ~(0xf << shift);
- mpp_ctrl[num / 8] |= sel << shift;
-
- gpio_mode = 0;
- if (*mpp_list & MPP_INPUT_MASK)
- gpio_mode |= GPIO_INPUT_OK;
- if (*mpp_list & MPP_OUTPUT_MASK)
- gpio_mode |= GPIO_OUTPUT_OK;
- if (sel != 0)
- gpio_mode = 0;
- orion_gpio_set_valid(num, gpio_mode);
- }
-
- printk(KERN_DEBUG " final MPP regs:");
- for (i = 0; i < MPP_NR_REGS; i++) {
- writel(mpp_ctrl[i], MPP_CTRL(i));
- printk(" %08x", mpp_ctrl[i]);
- }
- printk("\n");
+ orion_mpp_conf(mpp_list, kirkwood_variant(),
+ MPP_MAX, DEV_BUS_VIRT_BASE);
}
diff --git a/arch/arm/mach-kirkwood/mpp.h b/arch/arm/mach-kirkwood/mpp.h
index 9b0a94d85c3e..ac787957e2d9 100644
--- a/arch/arm/mach-kirkwood/mpp.h
+++ b/arch/arm/mach-kirkwood/mpp.h
@@ -22,14 +22,8 @@
/* available on F6281 */ ((!!(_F6281)) << 17) | \
/* available on F6282 */ ((!!(_F6282)) << 18))
-#define MPP_NUM(x) ((x) & 0xff)
-#define MPP_SEL(x) (((x) >> 8) & 0xf)
-
/* num sel i o 6180 6190 6192 6281 6282 */
-#define MPP_INPUT_MASK MPP( 0, 0x0, 1, 0, 0, 0, 0, 0, 0 )
-#define MPP_OUTPUT_MASK MPP( 0, 0x0, 0, 1, 0, 0, 0, 0, 0 )
-
#define MPP_F6180_MASK MPP( 0, 0x0, 0, 0, 1, 0, 0, 0, 0 )
#define MPP_F6190_MASK MPP( 0, 0x0, 0, 0, 0, 1, 0, 0, 0 )
#define MPP_F6192_MASK MPP( 0, 0x0, 0, 0, 0, 0, 1, 0, 0 )
diff --git a/arch/arm/mach-loki/common.c b/arch/arm/mach-loki/common.c
index e41e909cf8f4..5f02664db812 100644
--- a/arch/arm/mach-loki/common.c
+++ b/arch/arm/mach-loki/common.c
@@ -13,7 +13,7 @@
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
#include <linux/mbus.h>
-#include <linux/mv643xx_eth.h>
+#include <linux/dma-mapping.h>
#include <asm/page.h>
#include <asm/timex.h>
#include <asm/mach/map.h>
@@ -22,6 +22,7 @@
#include <mach/loki.h>
#include <plat/orion_nand.h>
#include <plat/time.h>
+#include <plat/common.h>
#include "common.h"
/*****************************************************************************
@@ -43,116 +44,28 @@ void __init loki_map_io(void)
/*****************************************************************************
- * GE0
+ * GE00
****************************************************************************/
-struct mv643xx_eth_shared_platform_data loki_ge0_shared_data = {
- .t_clk = LOKI_TCLK,
- .dram = &loki_mbus_dram_info,
-};
-
-static struct resource loki_ge0_shared_resources[] = {
- {
- .name = "ge0 base",
- .start = GE0_PHYS_BASE + 0x2000,
- .end = GE0_PHYS_BASE + 0x3fff,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device loki_ge0_shared = {
- .name = MV643XX_ETH_SHARED_NAME,
- .id = 0,
- .dev = {
- .platform_data = &loki_ge0_shared_data,
- },
- .num_resources = 1,
- .resource = loki_ge0_shared_resources,
-};
-
-static struct resource loki_ge0_resources[] = {
- {
- .name = "ge0 irq",
- .start = IRQ_LOKI_GBE_A_INT,
- .end = IRQ_LOKI_GBE_A_INT,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device loki_ge0 = {
- .name = MV643XX_ETH_NAME,
- .id = 0,
- .num_resources = 1,
- .resource = loki_ge0_resources,
- .dev = {
- .coherent_dma_mask = 0xffffffff,
- },
-};
-
void __init loki_ge0_init(struct mv643xx_eth_platform_data *eth_data)
{
- eth_data->shared = &loki_ge0_shared;
- loki_ge0.dev.platform_data = eth_data;
-
writel(0x00079220, GE0_VIRT_BASE + 0x20b0);
- platform_device_register(&loki_ge0_shared);
- platform_device_register(&loki_ge0);
+
+ orion_ge00_init(eth_data, &loki_mbus_dram_info,
+ GE0_PHYS_BASE, IRQ_LOKI_GBE_A_INT,
+ 0, LOKI_TCLK);
}
/*****************************************************************************
- * GE1
+ * GE01
****************************************************************************/
-struct mv643xx_eth_shared_platform_data loki_ge1_shared_data = {
- .t_clk = LOKI_TCLK,
- .dram = &loki_mbus_dram_info,
-};
-
-static struct resource loki_ge1_shared_resources[] = {
- {
- .name = "ge1 base",
- .start = GE1_PHYS_BASE + 0x2000,
- .end = GE1_PHYS_BASE + 0x3fff,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device loki_ge1_shared = {
- .name = MV643XX_ETH_SHARED_NAME,
- .id = 1,
- .dev = {
- .platform_data = &loki_ge1_shared_data,
- },
- .num_resources = 1,
- .resource = loki_ge1_shared_resources,
-};
-
-static struct resource loki_ge1_resources[] = {
- {
- .name = "ge1 irq",
- .start = IRQ_LOKI_GBE_B_INT,
- .end = IRQ_LOKI_GBE_B_INT,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device loki_ge1 = {
- .name = MV643XX_ETH_NAME,
- .id = 1,
- .num_resources = 1,
- .resource = loki_ge1_resources,
- .dev = {
- .coherent_dma_mask = 0xffffffff,
- },
-};
-
void __init loki_ge1_init(struct mv643xx_eth_platform_data *eth_data)
{
- eth_data->shared = &loki_ge1_shared;
- loki_ge1.dev.platform_data = eth_data;
-
writel(0x00079220, GE1_VIRT_BASE + 0x20b0);
- platform_device_register(&loki_ge1_shared);
- platform_device_register(&loki_ge1);
+
+ orion_ge01_init(eth_data, &loki_mbus_dram_info,
+ GE1_PHYS_BASE, IRQ_LOKI_GBE_B_INT,
+ 0, LOKI_TCLK);
}
@@ -187,7 +100,7 @@ static struct platform_device loki_sas = {
.name = "mvsas",
.id = 0,
.dev = {
- .coherent_dma_mask = 0xffffffff,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
},
.num_resources = ARRAY_SIZE(loki_sas_resources),
.resource = loki_sas_resources,
@@ -203,88 +116,19 @@ void __init loki_sas_init(void)
/*****************************************************************************
* UART0
****************************************************************************/
-static struct plat_serial8250_port loki_uart0_data[] = {
- {
- .mapbase = UART0_PHYS_BASE,
- .membase = (char *)UART0_VIRT_BASE,
- .irq = IRQ_LOKI_UART0,
- .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = LOKI_TCLK,
- }, {
- },
-};
-
-static struct resource loki_uart0_resources[] = {
- {
- .start = UART0_PHYS_BASE,
- .end = UART0_PHYS_BASE + 0xff,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_LOKI_UART0,
- .end = IRQ_LOKI_UART0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device loki_uart0 = {
- .name = "serial8250",
- .id = 0,
- .dev = {
- .platform_data = loki_uart0_data,
- },
- .resource = loki_uart0_resources,
- .num_resources = ARRAY_SIZE(loki_uart0_resources),
-};
-
void __init loki_uart0_init(void)
{
- platform_device_register(&loki_uart0);
+ orion_uart0_init(UART0_VIRT_BASE, UART0_PHYS_BASE,
+ IRQ_LOKI_UART0, LOKI_TCLK);
}
-
/*****************************************************************************
* UART1
****************************************************************************/
-static struct plat_serial8250_port loki_uart1_data[] = {
- {
- .mapbase = UART1_PHYS_BASE,
- .membase = (char *)UART1_VIRT_BASE,
- .irq = IRQ_LOKI_UART1,
- .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = LOKI_TCLK,
- }, {
- },
-};
-
-static struct resource loki_uart1_resources[] = {
- {
- .start = UART1_PHYS_BASE,
- .end = UART1_PHYS_BASE + 0xff,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_LOKI_UART1,
- .end = IRQ_LOKI_UART1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device loki_uart1 = {
- .name = "serial8250",
- .id = 1,
- .dev = {
- .platform_data = loki_uart1_data,
- },
- .resource = loki_uart1_resources,
- .num_resources = ARRAY_SIZE(loki_uart1_resources),
-};
-
void __init loki_uart1_init(void)
{
- platform_device_register(&loki_uart1);
+ orion_uart1_init(UART1_VIRT_BASE, UART1_PHYS_BASE,
+ IRQ_LOKI_UART1, LOKI_TCLK);
}
diff --git a/arch/arm/mach-lpc32xx/timer.c b/arch/arm/mach-lpc32xx/timer.c
index 6162ac308c20..b42c909bbeeb 100644
--- a/arch/arm/mach-lpc32xx/timer.c
+++ b/arch/arm/mach-lpc32xx/timer.c
@@ -31,19 +31,6 @@
#include <mach/platform.h>
#include "common.h"
-static cycle_t lpc32xx_clksrc_read(struct clocksource *cs)
-{
- return (cycle_t)__raw_readl(LCP32XX_TIMER_TC(LPC32XX_TIMER1_BASE));
-}
-
-static struct clocksource lpc32xx_clksrc = {
- .name = "lpc32xx_clksrc",
- .rating = 300,
- .read = lpc32xx_clksrc_read,
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
static int lpc32xx_clkevt_next_event(unsigned long delta,
struct clock_event_device *dev)
{
@@ -170,7 +157,9 @@ static void __init lpc32xx_timer_init(void)
__raw_writel(0, LCP32XX_TIMER_MCR(LPC32XX_TIMER1_BASE));
__raw_writel(LCP32XX_TIMER_CNTR_TCR_EN,
LCP32XX_TIMER_TCR(LPC32XX_TIMER1_BASE));
- clocksource_register_hz(&lpc32xx_clksrc, clkrate);
+
+ clocksource_mmio_init(LCP32XX_TIMER_TC(LPC32XX_TIMER1_BASE),
+ "lpc32xx_clksrc", clkrate, 300, 32, clocksource_mmio_readl_up);
}
struct sys_timer lpc32xx_timer = {
diff --git a/arch/arm/mach-mmp/include/mach/uncompress.h b/arch/arm/mach-mmp/include/mach/uncompress.h
index 85bd8a2d84b5..d6daeb7e4ef1 100644
--- a/arch/arm/mach-mmp/include/mach/uncompress.h
+++ b/arch/arm/mach-mmp/include/mach/uncompress.h
@@ -14,7 +14,7 @@
#define UART2_BASE (APB_PHYS_BASE + 0x17000)
#define UART3_BASE (APB_PHYS_BASE + 0x18000)
-static volatile unsigned long *UART;
+volatile unsigned long *UART;
static inline void putc(char c)
{
diff --git a/arch/arm/mach-msm/gpio-v2.c b/arch/arm/mach-msm/gpio-v2.c
index 56a964e52ad3..cc9c4fd7cccc 100644
--- a/arch/arm/mach-msm/gpio-v2.c
+++ b/arch/arm/mach-msm/gpio-v2.c
@@ -27,6 +27,9 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
+
+#include <asm/mach/irq.h>
+
#include <mach/msm_iomap.h>
#include "gpiomux.h"
@@ -309,8 +312,10 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type)
*/
static void msm_summary_irq_handler(unsigned int irq, struct irq_desc *desc)
{
- struct irq_data *data = irq_desc_get_irq_data(desc);
unsigned long i;
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+
+ chained_irq_enter(chip, desc);
for (i = find_first_bit(msm_gpio.enabled_irqs, NR_GPIO_IRQS);
i < NR_GPIO_IRQS;
@@ -319,7 +324,8 @@ static void msm_summary_irq_handler(unsigned int irq, struct irq_desc *desc)
generic_handle_irq(msm_gpio_to_irq(&msm_gpio.gpio_chip,
i));
}
- data->chip->irq_ack(data);
+
+ chained_irq_exit(chip, desc);
}
static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
diff --git a/arch/arm/mach-msm/include/mach/msm_iomap.h b/arch/arm/mach-msm/include/mach/msm_iomap.h
index c98c7591f3b8..2f494b6a9d0a 100644
--- a/arch/arm/mach-msm/include/mach/msm_iomap.h
+++ b/arch/arm/mach-msm/include/mach/msm_iomap.h
@@ -55,7 +55,7 @@
#include "msm_iomap-8960.h"
-/* Virtual addressses shared across all MSM targets. */
+/* Virtual addresses shared across all MSM targets. */
#define MSM_CSR_BASE IOMEM(0xE0001000)
#define MSM_QGIC_DIST_BASE IOMEM(0xF0000000)
#define MSM_QGIC_CPU_BASE IOMEM(0xF0001000)
diff --git a/arch/arm/mach-msm/platsmp.c b/arch/arm/mach-msm/platsmp.c
index 0f427bc94447..2034098cf015 100644
--- a/arch/arm/mach-msm/platsmp.c
+++ b/arch/arm/mach-msm/platsmp.c
@@ -119,7 +119,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
* the boot monitor to read the system wide flags register,
* and branch to the address found there.
*/
- smp_cross_call(cpumask_of(cpu), 1);
+ gic_raise_softirq(cpumask_of(cpu), 1);
timeout = jiffies + (1 * HZ);
while (time_before(jiffies, timeout)) {
@@ -151,6 +151,8 @@ void __init smp_init_cpus(void)
for (i = 0; i < NR_CPUS; i++)
set_cpu_possible(i, true);
+
+ set_smp_cross_call(gic_raise_softirq);
}
void __init platform_smp_prepare_cpus(unsigned int max_cpus)
diff --git a/arch/arm/mach-mv78xx0/common.c b/arch/arm/mach-mv78xx0/common.c
index 44fb4e55be0d..23d3980ef59d 100644
--- a/arch/arm/mach-mv78xx0/common.c
+++ b/arch/arm/mach-mv78xx0/common.c
@@ -13,8 +13,6 @@
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
#include <linux/mbus.h>
-#include <linux/mv643xx_eth.h>
-#include <linux/mv643xx_i2c.h>
#include <linux/ata_platform.h>
#include <linux/ethtool.h>
#include <asm/mach/map.h>
@@ -22,11 +20,12 @@
#include <mach/mv78xx0.h>
#include <mach/bridge-regs.h>
#include <plat/cache-feroceon-l2.h>
-#include <plat/ehci-orion.h>
#include <plat/orion_nand.h>
#include <plat/time.h>
+#include <plat/common.h>
#include "common.h"
+static int get_tclk(void);
/*****************************************************************************
* Common bits
@@ -168,285 +167,62 @@ void __init mv78xx0_map_io(void)
/*****************************************************************************
* EHCI
****************************************************************************/
-static struct orion_ehci_data mv78xx0_ehci_data = {
- .dram = &mv78xx0_mbus_dram_info,
- .phy_version = EHCI_PHY_NA,
-};
-
-static u64 ehci_dmamask = 0xffffffffUL;
-
-
-/*****************************************************************************
- * EHCI0
- ****************************************************************************/
-static struct resource mv78xx0_ehci0_resources[] = {
- {
- .start = USB0_PHYS_BASE,
- .end = USB0_PHYS_BASE + 0x0fff,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_MV78XX0_USB_0,
- .end = IRQ_MV78XX0_USB_0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device mv78xx0_ehci0 = {
- .name = "orion-ehci",
- .id = 0,
- .dev = {
- .dma_mask = &ehci_dmamask,
- .coherent_dma_mask = 0xffffffff,
- .platform_data = &mv78xx0_ehci_data,
- },
- .resource = mv78xx0_ehci0_resources,
- .num_resources = ARRAY_SIZE(mv78xx0_ehci0_resources),
-};
-
void __init mv78xx0_ehci0_init(void)
{
- platform_device_register(&mv78xx0_ehci0);
+ orion_ehci_init(&mv78xx0_mbus_dram_info,
+ USB0_PHYS_BASE, IRQ_MV78XX0_USB_0);
}
/*****************************************************************************
* EHCI1
****************************************************************************/
-static struct resource mv78xx0_ehci1_resources[] = {
- {
- .start = USB1_PHYS_BASE,
- .end = USB1_PHYS_BASE + 0x0fff,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_MV78XX0_USB_1,
- .end = IRQ_MV78XX0_USB_1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device mv78xx0_ehci1 = {
- .name = "orion-ehci",
- .id = 1,
- .dev = {
- .dma_mask = &ehci_dmamask,
- .coherent_dma_mask = 0xffffffff,
- .platform_data = &mv78xx0_ehci_data,
- },
- .resource = mv78xx0_ehci1_resources,
- .num_resources = ARRAY_SIZE(mv78xx0_ehci1_resources),
-};
-
void __init mv78xx0_ehci1_init(void)
{
- platform_device_register(&mv78xx0_ehci1);
+ orion_ehci_1_init(&mv78xx0_mbus_dram_info,
+ USB1_PHYS_BASE, IRQ_MV78XX0_USB_1);
}
/*****************************************************************************
* EHCI2
****************************************************************************/
-static struct resource mv78xx0_ehci2_resources[] = {
- {
- .start = USB2_PHYS_BASE,
- .end = USB2_PHYS_BASE + 0x0fff,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_MV78XX0_USB_2,
- .end = IRQ_MV78XX0_USB_2,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device mv78xx0_ehci2 = {
- .name = "orion-ehci",
- .id = 2,
- .dev = {
- .dma_mask = &ehci_dmamask,
- .coherent_dma_mask = 0xffffffff,
- .platform_data = &mv78xx0_ehci_data,
- },
- .resource = mv78xx0_ehci2_resources,
- .num_resources = ARRAY_SIZE(mv78xx0_ehci2_resources),
-};
-
void __init mv78xx0_ehci2_init(void)
{
- platform_device_register(&mv78xx0_ehci2);
+ orion_ehci_2_init(&mv78xx0_mbus_dram_info,
+ USB2_PHYS_BASE, IRQ_MV78XX0_USB_2);
}
/*****************************************************************************
* GE00
****************************************************************************/
-struct mv643xx_eth_shared_platform_data mv78xx0_ge00_shared_data = {
- .t_clk = 0,
- .dram = &mv78xx0_mbus_dram_info,
-};
-
-static struct resource mv78xx0_ge00_shared_resources[] = {
- {
- .name = "ge00 base",
- .start = GE00_PHYS_BASE + 0x2000,
- .end = GE00_PHYS_BASE + 0x3fff,
- .flags = IORESOURCE_MEM,
- }, {
- .name = "ge err irq",
- .start = IRQ_MV78XX0_GE_ERR,
- .end = IRQ_MV78XX0_GE_ERR,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device mv78xx0_ge00_shared = {
- .name = MV643XX_ETH_SHARED_NAME,
- .id = 0,
- .dev = {
- .platform_data = &mv78xx0_ge00_shared_data,
- },
- .num_resources = ARRAY_SIZE(mv78xx0_ge00_shared_resources),
- .resource = mv78xx0_ge00_shared_resources,
-};
-
-static struct resource mv78xx0_ge00_resources[] = {
- {
- .name = "ge00 irq",
- .start = IRQ_MV78XX0_GE00_SUM,
- .end = IRQ_MV78XX0_GE00_SUM,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device mv78xx0_ge00 = {
- .name = MV643XX_ETH_NAME,
- .id = 0,
- .num_resources = 1,
- .resource = mv78xx0_ge00_resources,
- .dev = {
- .coherent_dma_mask = 0xffffffff,
- },
-};
-
void __init mv78xx0_ge00_init(struct mv643xx_eth_platform_data *eth_data)
{
- eth_data->shared = &mv78xx0_ge00_shared;
- mv78xx0_ge00.dev.platform_data = eth_data;
-
- platform_device_register(&mv78xx0_ge00_shared);
- platform_device_register(&mv78xx0_ge00);
+ orion_ge00_init(eth_data, &mv78xx0_mbus_dram_info,
+ GE00_PHYS_BASE, IRQ_MV78XX0_GE00_SUM,
+ IRQ_MV78XX0_GE_ERR, get_tclk());
}
/*****************************************************************************
* GE01
****************************************************************************/
-struct mv643xx_eth_shared_platform_data mv78xx0_ge01_shared_data = {
- .t_clk = 0,
- .dram = &mv78xx0_mbus_dram_info,
- .shared_smi = &mv78xx0_ge00_shared,
-};
-
-static struct resource mv78xx0_ge01_shared_resources[] = {
- {
- .name = "ge01 base",
- .start = GE01_PHYS_BASE + 0x2000,
- .end = GE01_PHYS_BASE + 0x3fff,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device mv78xx0_ge01_shared = {
- .name = MV643XX_ETH_SHARED_NAME,
- .id = 1,
- .dev = {
- .platform_data = &mv78xx0_ge01_shared_data,
- },
- .num_resources = 1,
- .resource = mv78xx0_ge01_shared_resources,
-};
-
-static struct resource mv78xx0_ge01_resources[] = {
- {
- .name = "ge01 irq",
- .start = IRQ_MV78XX0_GE01_SUM,
- .end = IRQ_MV78XX0_GE01_SUM,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device mv78xx0_ge01 = {
- .name = MV643XX_ETH_NAME,
- .id = 1,
- .num_resources = 1,
- .resource = mv78xx0_ge01_resources,
- .dev = {
- .coherent_dma_mask = 0xffffffff,
- },
-};
-
void __init mv78xx0_ge01_init(struct mv643xx_eth_platform_data *eth_data)
{
- eth_data->shared = &mv78xx0_ge01_shared;
- mv78xx0_ge01.dev.platform_data = eth_data;
-
- platform_device_register(&mv78xx0_ge01_shared);
- platform_device_register(&mv78xx0_ge01);
+ orion_ge01_init(eth_data, &mv78xx0_mbus_dram_info,
+ GE01_PHYS_BASE, IRQ_MV78XX0_GE01_SUM,
+ NO_IRQ, get_tclk());
}
/*****************************************************************************
* GE10
****************************************************************************/
-struct mv643xx_eth_shared_platform_data mv78xx0_ge10_shared_data = {
- .t_clk = 0,
- .dram = &mv78xx0_mbus_dram_info,
- .shared_smi = &mv78xx0_ge00_shared,
-};
-
-static struct resource mv78xx0_ge10_shared_resources[] = {
- {
- .name = "ge10 base",
- .start = GE10_PHYS_BASE + 0x2000,
- .end = GE10_PHYS_BASE + 0x3fff,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device mv78xx0_ge10_shared = {
- .name = MV643XX_ETH_SHARED_NAME,
- .id = 2,
- .dev = {
- .platform_data = &mv78xx0_ge10_shared_data,
- },
- .num_resources = 1,
- .resource = mv78xx0_ge10_shared_resources,
-};
-
-static struct resource mv78xx0_ge10_resources[] = {
- {
- .name = "ge10 irq",
- .start = IRQ_MV78XX0_GE10_SUM,
- .end = IRQ_MV78XX0_GE10_SUM,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device mv78xx0_ge10 = {
- .name = MV643XX_ETH_NAME,
- .id = 2,
- .num_resources = 1,
- .resource = mv78xx0_ge10_resources,
- .dev = {
- .coherent_dma_mask = 0xffffffff,
- },
-};
-
void __init mv78xx0_ge10_init(struct mv643xx_eth_platform_data *eth_data)
{
u32 dev, rev;
- eth_data->shared = &mv78xx0_ge10_shared;
- mv78xx0_ge10.dev.platform_data = eth_data;
-
/*
* On the Z0, ge10 and ge11 are internally connected back
* to back, and not brought out.
@@ -458,65 +234,19 @@ void __init mv78xx0_ge10_init(struct mv643xx_eth_platform_data *eth_data)
eth_data->duplex = DUPLEX_FULL;
}
- platform_device_register(&mv78xx0_ge10_shared);
- platform_device_register(&mv78xx0_ge10);
+ orion_ge10_init(eth_data, &mv78xx0_mbus_dram_info,
+ GE10_PHYS_BASE, IRQ_MV78XX0_GE10_SUM,
+ NO_IRQ, get_tclk());
}
/*****************************************************************************
* GE11
****************************************************************************/
-struct mv643xx_eth_shared_platform_data mv78xx0_ge11_shared_data = {
- .t_clk = 0,
- .dram = &mv78xx0_mbus_dram_info,
- .shared_smi = &mv78xx0_ge00_shared,
-};
-
-static struct resource mv78xx0_ge11_shared_resources[] = {
- {
- .name = "ge11 base",
- .start = GE11_PHYS_BASE + 0x2000,
- .end = GE11_PHYS_BASE + 0x3fff,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device mv78xx0_ge11_shared = {
- .name = MV643XX_ETH_SHARED_NAME,
- .id = 3,
- .dev = {
- .platform_data = &mv78xx0_ge11_shared_data,
- },
- .num_resources = 1,
- .resource = mv78xx0_ge11_shared_resources,
-};
-
-static struct resource mv78xx0_ge11_resources[] = {
- {
- .name = "ge11 irq",
- .start = IRQ_MV78XX0_GE11_SUM,
- .end = IRQ_MV78XX0_GE11_SUM,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device mv78xx0_ge11 = {
- .name = MV643XX_ETH_NAME,
- .id = 3,
- .num_resources = 1,
- .resource = mv78xx0_ge11_resources,
- .dev = {
- .coherent_dma_mask = 0xffffffff,
- },
-};
-
void __init mv78xx0_ge11_init(struct mv643xx_eth_platform_data *eth_data)
{
u32 dev, rev;
- eth_data->shared = &mv78xx0_ge11_shared;
- mv78xx0_ge11.dev.platform_data = eth_data;
-
/*
* On the Z0, ge10 and ge11 are internally connected back
* to back, and not brought out.
@@ -528,293 +258,68 @@ void __init mv78xx0_ge11_init(struct mv643xx_eth_platform_data *eth_data)
eth_data->duplex = DUPLEX_FULL;
}
- platform_device_register(&mv78xx0_ge11_shared);
- platform_device_register(&mv78xx0_ge11);
+ orion_ge11_init(eth_data, &mv78xx0_mbus_dram_info,
+ GE11_PHYS_BASE, IRQ_MV78XX0_GE11_SUM,
+ NO_IRQ, get_tclk());
}
/*****************************************************************************
- * I2C bus 0
- ****************************************************************************/
-
-static struct mv64xxx_i2c_pdata mv78xx0_i2c_0_pdata = {
- .freq_m = 8, /* assumes 166 MHz TCLK */
- .freq_n = 3,
- .timeout = 1000, /* Default timeout of 1 second */
-};
-
-static struct resource mv78xx0_i2c_0_resources[] = {
- {
- .start = I2C_0_PHYS_BASE,
- .end = I2C_0_PHYS_BASE + 0x1f,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_MV78XX0_I2C_0,
- .end = IRQ_MV78XX0_I2C_0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-
-static struct platform_device mv78xx0_i2c_0 = {
- .name = MV64XXX_I2C_CTLR_NAME,
- .id = 0,
- .num_resources = ARRAY_SIZE(mv78xx0_i2c_0_resources),
- .resource = mv78xx0_i2c_0_resources,
- .dev = {
- .platform_data = &mv78xx0_i2c_0_pdata,
- },
-};
-
-/*****************************************************************************
- * I2C bus 1
+ * I2C
****************************************************************************/
-
-static struct mv64xxx_i2c_pdata mv78xx0_i2c_1_pdata = {
- .freq_m = 8, /* assumes 166 MHz TCLK */
- .freq_n = 3,
- .timeout = 1000, /* Default timeout of 1 second */
-};
-
-static struct resource mv78xx0_i2c_1_resources[] = {
- {
- .start = I2C_1_PHYS_BASE,
- .end = I2C_1_PHYS_BASE + 0x1f,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_MV78XX0_I2C_1,
- .end = IRQ_MV78XX0_I2C_1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-
-static struct platform_device mv78xx0_i2c_1 = {
- .name = MV64XXX_I2C_CTLR_NAME,
- .id = 1,
- .num_resources = ARRAY_SIZE(mv78xx0_i2c_1_resources),
- .resource = mv78xx0_i2c_1_resources,
- .dev = {
- .platform_data = &mv78xx0_i2c_1_pdata,
- },
-};
-
void __init mv78xx0_i2c_init(void)
{
- platform_device_register(&mv78xx0_i2c_0);
- platform_device_register(&mv78xx0_i2c_1);
+ orion_i2c_init(I2C_0_PHYS_BASE, IRQ_MV78XX0_I2C_0, 8);
+ orion_i2c_1_init(I2C_1_PHYS_BASE, IRQ_MV78XX0_I2C_1, 8);
}
/*****************************************************************************
* SATA
****************************************************************************/
-static struct resource mv78xx0_sata_resources[] = {
- {
- .name = "sata base",
- .start = SATA_PHYS_BASE,
- .end = SATA_PHYS_BASE + 0x5000 - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .name = "sata irq",
- .start = IRQ_MV78XX0_SATA,
- .end = IRQ_MV78XX0_SATA,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device mv78xx0_sata = {
- .name = "sata_mv",
- .id = 0,
- .dev = {
- .coherent_dma_mask = 0xffffffff,
- },
- .num_resources = ARRAY_SIZE(mv78xx0_sata_resources),
- .resource = mv78xx0_sata_resources,
-};
-
void __init mv78xx0_sata_init(struct mv_sata_platform_data *sata_data)
{
- sata_data->dram = &mv78xx0_mbus_dram_info;
- mv78xx0_sata.dev.platform_data = sata_data;
- platform_device_register(&mv78xx0_sata);
+ orion_sata_init(sata_data, &mv78xx0_mbus_dram_info,
+ SATA_PHYS_BASE, IRQ_MV78XX0_SATA);
}
/*****************************************************************************
* UART0
****************************************************************************/
-static struct plat_serial8250_port mv78xx0_uart0_data[] = {
- {
- .mapbase = UART0_PHYS_BASE,
- .membase = (char *)UART0_VIRT_BASE,
- .irq = IRQ_MV78XX0_UART_0,
- .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = 0,
- }, {
- },
-};
-
-static struct resource mv78xx0_uart0_resources[] = {
- {
- .start = UART0_PHYS_BASE,
- .end = UART0_PHYS_BASE + 0xff,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_MV78XX0_UART_0,
- .end = IRQ_MV78XX0_UART_0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device mv78xx0_uart0 = {
- .name = "serial8250",
- .id = 0,
- .dev = {
- .platform_data = mv78xx0_uart0_data,
- },
- .resource = mv78xx0_uart0_resources,
- .num_resources = ARRAY_SIZE(mv78xx0_uart0_resources),
-};
-
void __init mv78xx0_uart0_init(void)
{
- platform_device_register(&mv78xx0_uart0);
+ orion_uart0_init(UART0_VIRT_BASE, UART0_PHYS_BASE,
+ IRQ_MV78XX0_UART_0, get_tclk());
}
/*****************************************************************************
* UART1
****************************************************************************/
-static struct plat_serial8250_port mv78xx0_uart1_data[] = {
- {
- .mapbase = UART1_PHYS_BASE,
- .membase = (char *)UART1_VIRT_BASE,
- .irq = IRQ_MV78XX0_UART_1,
- .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = 0,
- }, {
- },
-};
-
-static struct resource mv78xx0_uart1_resources[] = {
- {
- .start = UART1_PHYS_BASE,
- .end = UART1_PHYS_BASE + 0xff,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_MV78XX0_UART_1,
- .end = IRQ_MV78XX0_UART_1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device mv78xx0_uart1 = {
- .name = "serial8250",
- .id = 1,
- .dev = {
- .platform_data = mv78xx0_uart1_data,
- },
- .resource = mv78xx0_uart1_resources,
- .num_resources = ARRAY_SIZE(mv78xx0_uart1_resources),
-};
-
void __init mv78xx0_uart1_init(void)
{
- platform_device_register(&mv78xx0_uart1);
+ orion_uart1_init(UART1_VIRT_BASE, UART1_PHYS_BASE,
+ IRQ_MV78XX0_UART_1, get_tclk());
}
/*****************************************************************************
* UART2
****************************************************************************/
-static struct plat_serial8250_port mv78xx0_uart2_data[] = {
- {
- .mapbase = UART2_PHYS_BASE,
- .membase = (char *)UART2_VIRT_BASE,
- .irq = IRQ_MV78XX0_UART_2,
- .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = 0,
- }, {
- },
-};
-
-static struct resource mv78xx0_uart2_resources[] = {
- {
- .start = UART2_PHYS_BASE,
- .end = UART2_PHYS_BASE + 0xff,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_MV78XX0_UART_2,
- .end = IRQ_MV78XX0_UART_2,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device mv78xx0_uart2 = {
- .name = "serial8250",
- .id = 2,
- .dev = {
- .platform_data = mv78xx0_uart2_data,
- },
- .resource = mv78xx0_uart2_resources,
- .num_resources = ARRAY_SIZE(mv78xx0_uart2_resources),
-};
-
void __init mv78xx0_uart2_init(void)
{
- platform_device_register(&mv78xx0_uart2);
+ orion_uart2_init(UART2_VIRT_BASE, UART2_PHYS_BASE,
+ IRQ_MV78XX0_UART_2, get_tclk());
}
-
/*****************************************************************************
* UART3
****************************************************************************/
-static struct plat_serial8250_port mv78xx0_uart3_data[] = {
- {
- .mapbase = UART3_PHYS_BASE,
- .membase = (char *)UART3_VIRT_BASE,
- .irq = IRQ_MV78XX0_UART_3,
- .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = 0,
- }, {
- },
-};
-
-static struct resource mv78xx0_uart3_resources[] = {
- {
- .start = UART3_PHYS_BASE,
- .end = UART3_PHYS_BASE + 0xff,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_MV78XX0_UART_3,
- .end = IRQ_MV78XX0_UART_3,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device mv78xx0_uart3 = {
- .name = "serial8250",
- .id = 3,
- .dev = {
- .platform_data = mv78xx0_uart3_data,
- },
- .resource = mv78xx0_uart3_resources,
- .num_resources = ARRAY_SIZE(mv78xx0_uart3_resources),
-};
-
void __init mv78xx0_uart3_init(void)
{
- platform_device_register(&mv78xx0_uart3);
+ orion_uart3_init(UART3_VIRT_BASE, UART3_PHYS_BASE,
+ IRQ_MV78XX0_UART_3, get_tclk());
}
-
/*****************************************************************************
* Time handling
****************************************************************************/
@@ -895,13 +400,4 @@ void __init mv78xx0_init(void)
#ifdef CONFIG_CACHE_FEROCEON_L2
feroceon_l2_init(is_l2_writethrough());
#endif
-
- mv78xx0_ge00_shared_data.t_clk = tclk;
- mv78xx0_ge01_shared_data.t_clk = tclk;
- mv78xx0_ge10_shared_data.t_clk = tclk;
- mv78xx0_ge11_shared_data.t_clk = tclk;
- mv78xx0_uart0_data[0].uartclk = tclk;
- mv78xx0_uart1_data[0].uartclk = tclk;
- mv78xx0_uart2_data[0].uartclk = tclk;
- mv78xx0_uart3_data[0].uartclk = tclk;
}
diff --git a/arch/arm/mach-mv78xx0/mpp.c b/arch/arm/mach-mv78xx0/mpp.c
index 65b72c454cb0..59b7686b9209 100644
--- a/arch/arm/mach-mv78xx0/mpp.c
+++ b/arch/arm/mach-mv78xx0/mpp.c
@@ -12,6 +12,7 @@
#include <linux/init.h>
#include <linux/mbus.h>
#include <linux/io.h>
+#include <plat/mpp.h>
#include <asm/gpio.h>
#include <mach/hardware.h>
#include "common.h"
@@ -31,61 +32,8 @@ static unsigned int __init mv78xx0_variant(void)
return 0;
}
-#define MPP_CTRL(i) (DEV_BUS_VIRT_BASE + (i) * 4)
-#define MPP_NR_REGS (1 + MPP_MAX/8)
-
void __init mv78xx0_mpp_conf(unsigned int *mpp_list)
{
- u32 mpp_ctrl[MPP_NR_REGS];
- unsigned int variant_mask;
- int i;
-
- variant_mask = mv78xx0_variant();
- if (!variant_mask)
- return;
-
- printk(KERN_DEBUG "initial MPP regs:");
- for (i = 0; i < MPP_NR_REGS; i++) {
- mpp_ctrl[i] = readl(MPP_CTRL(i));
- printk(" %08x", mpp_ctrl[i]);
- }
- printk("\n");
-
- for ( ; *mpp_list; mpp_list++) {
- unsigned int num = MPP_NUM(*mpp_list);
- unsigned int sel = MPP_SEL(*mpp_list);
- int shift, gpio_mode;
-
- if (num > MPP_MAX) {
- printk(KERN_ERR "mv78xx0_mpp_conf: invalid MPP "
- "number (%u)\n", num);
- continue;
- }
- if (!(*mpp_list & variant_mask)) {
- printk(KERN_WARNING
- "mv78xx0_mpp_conf: requested MPP%u config "
- "unavailable on this hardware\n", num);
- continue;
- }
-
- shift = (num & 7) << 2;
- mpp_ctrl[num / 8] &= ~(0xf << shift);
- mpp_ctrl[num / 8] |= sel << shift;
-
- gpio_mode = 0;
- if (*mpp_list & MPP_INPUT_MASK)
- gpio_mode |= GPIO_INPUT_OK;
- if (*mpp_list & MPP_OUTPUT_MASK)
- gpio_mode |= GPIO_OUTPUT_OK;
- if (sel != 0)
- gpio_mode = 0;
- orion_gpio_set_valid(num, gpio_mode);
- }
-
- printk(KERN_DEBUG " final MPP regs:");
- for (i = 0; i < MPP_NR_REGS; i++) {
- writel(mpp_ctrl[i], MPP_CTRL(i));
- printk(" %08x", mpp_ctrl[i]);
- }
- printk("\n");
+ orion_mpp_conf(mpp_list, mv78xx0_variant(),
+ MPP_MAX, DEV_BUS_VIRT_BASE);
}
diff --git a/arch/arm/mach-mv78xx0/mpp.h b/arch/arm/mach-mv78xx0/mpp.h
index 80840b781eaa..b61b50927123 100644
--- a/arch/arm/mach-mv78xx0/mpp.h
+++ b/arch/arm/mach-mv78xx0/mpp.h
@@ -19,14 +19,8 @@
/* may be output signal */ ((!!(_out)) << 13) | \
/* available on A0 */ ((!!(_78100_A0)) << 14))
-#define MPP_NUM(x) ((x) & 0xff)
-#define MPP_SEL(x) (((x) >> 8) & 0xf)
-
/* num sel i o 78100_A0 */
-#define MPP_INPUT_MASK MPP(0, 0x0, 1, 0, 0)
-#define MPP_OUTPUT_MASK MPP(0, 0x0, 0, 1, 0)
-
#define MPP_78100_A0_MASK MPP(0, 0x0, 0, 0, 1)
#define MPP0_GPIO MPP(0, 0x0, 1, 1, 1)
diff --git a/arch/arm/mach-mx3/Kconfig b/arch/arm/mach-mx3/Kconfig
deleted file mode 100644
index 340809a7d233..000000000000
--- a/arch/arm/mach-mx3/Kconfig
+++ /dev/null
@@ -1,257 +0,0 @@
-if ARCH_MX3
-
-# ARCH_MX31 and ARCH_MX35 are left for compatibility
-# Some usages assume that having one of them implies not having (e.g.) ARCH_MX2.
-# To easily distinguish good and reviewed from unreviewed usages new (and IMHO
-# more sensible) names are used: SOC_IMX31 and SOC_IMX35
-config ARCH_MX31
- bool
-
-config ARCH_MX35
- bool
-
-config SOC_IMX31
- bool
- select IMX_HAVE_PLATFORM_MXC_RNGA
- select ARCH_MXC_AUDMUX_V2
- select ARCH_MX31
- select MXC_AVIC
-
-config SOC_IMX35
- bool
- select ARCH_MXC_IOMUX_V3
- select ARCH_MXC_AUDMUX_V2
- select HAVE_EPIT
- select ARCH_MX35
- select MXC_AVIC
-
-comment "MX3 platforms:"
-
-config MACH_MX31ADS
- bool "Support MX31ADS platforms"
- select SOC_IMX31
- select IMX_HAVE_PLATFORM_IMX_I2C
- select IMX_HAVE_PLATFORM_IMX_SSI
- select IMX_HAVE_PLATFORM_IMX_UART
- default y
- help
- Include support for MX31ADS platform. This includes specific
- configurations for the board and its peripherals.
-
-config MACH_MX31ADS_WM1133_EV1
- bool "Support Wolfson Microelectronics 1133-EV1 module"
- depends on MACH_MX31ADS
- depends on MFD_WM8350_I2C
- depends on REGULATOR_WM8350
- select MFD_WM8350_CONFIG_MODE_0
- select MFD_WM8352_CONFIG_MODE_0
- help
- Include support for the Wolfson Microelectronics 1133-EV1 PMU
- and audio module for the MX31ADS platform.
-
-config MACH_PCM037
- bool "Support Phytec pcm037 (i.MX31) platforms"
- select SOC_IMX31
- select IMX_HAVE_PLATFORM_FSL_USB2_UDC
- select IMX_HAVE_PLATFORM_IMX2_WDT
- select IMX_HAVE_PLATFORM_IMX_I2C
- select IMX_HAVE_PLATFORM_IMX_UART
- select IMX_HAVE_PLATFORM_MXC_EHCI
- select IMX_HAVE_PLATFORM_MXC_MMC
- select IMX_HAVE_PLATFORM_MXC_NAND
- select IMX_HAVE_PLATFORM_MXC_W1
- select MXC_ULPI if USB_ULPI
- help
- Include support for Phytec pcm037 platform. This includes
- specific configurations for the board and its peripherals.
-
-config MACH_PCM037_EET
- bool "Support pcm037 EET board extensions"
- depends on MACH_PCM037
- select IMX_HAVE_PLATFORM_SPI_IMX
- help
- Add support for PCM037 EET baseboard extensions. If you are using the
- OLED display with EET, use "video=mx3fb:CMEL-OLED" kernel
- command-line parameter.
-
-config MACH_MX31LITE
- bool "Support MX31 LITEKIT (LogicPD)"
- select SOC_IMX31
- select MXC_ULPI if USB_ULPI
- select IMX_HAVE_PLATFORM_IMX2_WDT
- select IMX_HAVE_PLATFORM_IMX_UART
- select IMX_HAVE_PLATFORM_MXC_EHCI
- select IMX_HAVE_PLATFORM_MXC_MMC
- select IMX_HAVE_PLATFORM_MXC_NAND
- select IMX_HAVE_PLATFORM_SPI_IMX
- help
- Include support for MX31 LITEKIT platform. This includes specific
- configurations for the board and its peripherals.
-
-config MACH_MX31_3DS
- bool "Support MX31PDK (3DS)"
- select SOC_IMX31
- select MXC_DEBUG_BOARD
- select IMX_HAVE_PLATFORM_FSL_USB2_UDC
- select IMX_HAVE_PLATFORM_IMX2_WDT
- select IMX_HAVE_PLATFORM_IMX_I2C
- select IMX_HAVE_PLATFORM_IMX_KEYPAD
- select IMX_HAVE_PLATFORM_IMX_UART
- select IMX_HAVE_PLATFORM_MXC_EHCI
- select IMX_HAVE_PLATFORM_MXC_NAND
- select IMX_HAVE_PLATFORM_SPI_IMX
- select MXC_ULPI if USB_ULPI
- help
- Include support for MX31PDK (3DS) platform. This includes specific
- configurations for the board and its peripherals.
-
-config MACH_MX31_3DS_MXC_NAND_USE_BBT
- bool "Make the MXC NAND driver use the in flash Bad Block Table"
- depends on MACH_MX31_3DS
- depends on MTD_NAND_MXC
- help
- Enable this if you want that the MXC NAND driver uses the in flash
- Bad Block Table to know what blocks are bad instead of scanning the
- entire flash looking for bad block markers.
-
-config MACH_MX31MOBOARD
- bool "Support mx31moboard platforms (EPFL Mobots group)"
- select SOC_IMX31
- select IMX_HAVE_PLATFORM_FSL_USB2_UDC
- select IMX_HAVE_PLATFORM_IMX_I2C
- select IMX_HAVE_PLATFORM_IMX_UART
- select IMX_HAVE_PLATFORM_MXC_EHCI
- select IMX_HAVE_PLATFORM_MXC_MMC
- select IMX_HAVE_PLATFORM_SPI_IMX
- select MXC_ULPI if USB_ULPI
- help
- Include support for mx31moboard platform. This includes specific
- configurations for the board and its peripherals.
-
-config MACH_MX31LILLY
- bool "Support MX31 LILLY-1131 platforms (INCO startec)"
- select SOC_IMX31
- select IMX_HAVE_PLATFORM_IMX_UART
- select IMX_HAVE_PLATFORM_MXC_EHCI
- select IMX_HAVE_PLATFORM_MXC_MMC
- select IMX_HAVE_PLATFORM_SPI_IMX
- select MXC_ULPI if USB_ULPI
- help
- Include support for mx31 based LILLY1131 modules. This includes
- specific configurations for the board and its peripherals.
-
-config MACH_QONG
- bool "Support Dave/DENX QongEVB-LITE platform"
- select SOC_IMX31
- select IMX_HAVE_PLATFORM_IMX_UART
- help
- Include support for Dave/DENX QongEVB-LITE platform. This includes
- specific configurations for the board and its peripherals.
-
-config MACH_PCM043
- bool "Support Phytec pcm043 (i.MX35) platforms"
- select SOC_IMX35
- select IMX_HAVE_PLATFORM_FLEXCAN
- select IMX_HAVE_PLATFORM_FSL_USB2_UDC
- select IMX_HAVE_PLATFORM_IMX2_WDT
- select IMX_HAVE_PLATFORM_IMX_I2C
- select IMX_HAVE_PLATFORM_IMX_SSI
- select IMX_HAVE_PLATFORM_IMX_UART
- select IMX_HAVE_PLATFORM_MXC_EHCI
- select IMX_HAVE_PLATFORM_MXC_NAND
- select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
- select MXC_ULPI if USB_ULPI
- help
- Include support for Phytec pcm043 platform. This includes
- specific configurations for the board and its peripherals.
-
-config MACH_ARMADILLO5X0
- bool "Support Atmark Armadillo-500 Development Base Board"
- select SOC_IMX31
- select IMX_HAVE_PLATFORM_IMX_I2C
- select IMX_HAVE_PLATFORM_IMX_UART
- select IMX_HAVE_PLATFORM_MXC_EHCI
- select IMX_HAVE_PLATFORM_MXC_MMC
- select IMX_HAVE_PLATFORM_MXC_NAND
- select MXC_ULPI if USB_ULPI
- help
- Include support for Atmark Armadillo-500 platform. This includes
- specific configurations for the board and its peripherals.
-
-config MACH_MX35_3DS
- bool "Support MX35PDK platform"
- select SOC_IMX35
- select MXC_DEBUG_BOARD
- select IMX_HAVE_PLATFORM_FSL_USB2_UDC
- select IMX_HAVE_PLATFORM_IMX2_WDT
- select IMX_HAVE_PLATFORM_IMX_I2C
- select IMX_HAVE_PLATFORM_IMX_UART
- select IMX_HAVE_PLATFORM_MXC_EHCI
- select IMX_HAVE_PLATFORM_MXC_NAND
- select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
- help
- Include support for MX35PDK platform. This includes specific
- configurations for the board and its peripherals.
-
-config MACH_KZM_ARM11_01
- bool "Support KZM-ARM11-01(Kyoto Microcomputer)"
- select SOC_IMX31
- select IMX_HAVE_PLATFORM_IMX_UART
- help
- Include support for KZM-ARM11-01. This includes specific
- configurations for the board and its peripherals.
-
-config MACH_BUG
- bool "Support Buglabs BUGBase platform"
- select SOC_IMX31
- select IMX_HAVE_PLATFORM_IMX_UART
- default y
- help
- Include support for BUGBase 1.3 platform. This includes specific
- configurations for the board and its peripherals.
-
-config MACH_EUKREA_CPUIMX35
- bool "Support Eukrea CPUIMX35 Platform"
- select SOC_IMX35
- select IMX_HAVE_PLATFORM_FLEXCAN
- select IMX_HAVE_PLATFORM_FSL_USB2_UDC
- select IMX_HAVE_PLATFORM_IMX2_WDT
- select IMX_HAVE_PLATFORM_IMX_I2C
- select IMX_HAVE_PLATFORM_IMX_UART
- select IMX_HAVE_PLATFORM_MXC_EHCI
- select IMX_HAVE_PLATFORM_MXC_NAND
- select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
- select MXC_ULPI if USB_ULPI
- help
- Include support for Eukrea CPUIMX35 platform. This includes
- specific configurations for the board and its peripherals.
-
-choice
- prompt "Baseboard"
- depends on MACH_EUKREA_CPUIMX35
- default MACH_EUKREA_MBIMXSD35_BASEBOARD
-
-config MACH_EUKREA_MBIMXSD35_BASEBOARD
- bool "Eukrea MBIMXSD development board"
- select IMX_HAVE_PLATFORM_IMX_SSI
- help
- This adds board specific devices that can be found on Eukrea's
- MBIMXSD evaluation board.
-
-endchoice
-
-config MACH_VPR200
- bool "Support VPR200 platform"
- select SOC_IMX35
- select IMX_HAVE_PLATFORM_FSL_USB2_UDC
- select IMX_HAVE_PLATFORM_IMX2_WDT
- select IMX_HAVE_PLATFORM_IMX_UART
- select IMX_HAVE_PLATFORM_IMX_I2C
- select IMX_HAVE_PLATFORM_MXC_EHCI
- select IMX_HAVE_PLATFORM_MXC_NAND
- select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
- help
- Include support for VPR200 platform. This includes specific
- configurations for the board and its peripherals.
-
-endif
diff --git a/arch/arm/mach-mx3/Makefile b/arch/arm/mach-mx3/Makefile
deleted file mode 100644
index a54faf2cf5fa..000000000000
--- a/arch/arm/mach-mx3/Makefile
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-
-# Object file lists.
-
-obj-y := mm.o devices.o cpu.o
-obj-$(CONFIG_SOC_IMX31) += clock-imx31.o iomux-imx31.o ehci-imx31.o
-obj-$(CONFIG_SOC_IMX35) += clock-imx35.o ehci-imx35.o
-obj-$(CONFIG_MACH_MX31ADS) += mach-mx31ads.o
-obj-$(CONFIG_MACH_MX31LILLY) += mach-mx31lilly.o mx31lilly-db.o
-obj-$(CONFIG_MACH_MX31LITE) += mach-mx31lite.o mx31lite-db.o
-obj-$(CONFIG_MACH_PCM037) += mach-pcm037.o
-obj-$(CONFIG_MACH_PCM037_EET) += mach-pcm037_eet.o
-obj-$(CONFIG_MACH_MX31_3DS) += mach-mx31_3ds.o
-obj-$(CONFIG_MACH_MX31MOBOARD) += mach-mx31moboard.o mx31moboard-devboard.o \
- mx31moboard-marxbot.o mx31moboard-smartbot.o
-obj-$(CONFIG_MACH_QONG) += mach-qong.o
-obj-$(CONFIG_MACH_PCM043) += mach-pcm043.o
-obj-$(CONFIG_MACH_ARMADILLO5X0) += mach-armadillo5x0.o
-obj-$(CONFIG_MACH_MX35_3DS) += mach-mx35_3ds.o
-obj-$(CONFIG_MACH_KZM_ARM11_01) += mach-kzm_arm11_01.o
-obj-$(CONFIG_MACH_BUG) += mach-bug.o
-obj-$(CONFIG_MACH_EUKREA_CPUIMX35) += mach-cpuimx35.o
-obj-$(CONFIG_MACH_EUKREA_MBIMXSD35_BASEBOARD) += eukrea_mbimxsd-baseboard.o
-obj-$(CONFIG_MACH_VPR200) += mach-vpr200.o
diff --git a/arch/arm/mach-mx3/Makefile.boot b/arch/arm/mach-mx3/Makefile.boot
deleted file mode 100644
index e1dd366f836b..000000000000
--- a/arch/arm/mach-mx3/Makefile.boot
+++ /dev/null
@@ -1,3 +0,0 @@
- zreladdr-y := 0x80008000
-params_phys-y := 0x80000100
-initrd_phys-y := 0x80800000
diff --git a/arch/arm/mach-mx3/devices.c b/arch/arm/mach-mx3/devices.c
deleted file mode 100644
index b6672db788fb..000000000000
--- a/arch/arm/mach-mx3/devices.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright 2006-2007 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Sascha Hauer, kernel@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.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include <linux/dma-mapping.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/serial.h>
-#include <linux/gpio.h>
-#include <mach/hardware.h>
-#include <mach/irqs.h>
-#include <mach/common.h>
-#include <mach/mx3_camera.h>
-
-#include "devices.h"
-
-/* i.MX31 Image Processing Unit */
-
-/* The resource order is important! */
-static struct resource mx3_ipu_rsrc[] = {
- {
- .start = MX3x_IPU_CTRL_BASE_ADDR,
- .end = MX3x_IPU_CTRL_BASE_ADDR + 0x5F,
- .flags = IORESOURCE_MEM,
- }, {
- .start = MX3x_IPU_CTRL_BASE_ADDR + 0x88,
- .end = MX3x_IPU_CTRL_BASE_ADDR + 0xB3,
- .flags = IORESOURCE_MEM,
- }, {
- .start = MX3x_INT_IPU_SYN,
- .end = MX3x_INT_IPU_SYN,
- .flags = IORESOURCE_IRQ,
- }, {
- .start = MX3x_INT_IPU_ERR,
- .end = MX3x_INT_IPU_ERR,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-struct platform_device mx3_ipu = {
- .name = "ipu-core",
- .id = -1,
- .num_resources = ARRAY_SIZE(mx3_ipu_rsrc),
- .resource = mx3_ipu_rsrc,
-};
-
-static struct resource fb_resources[] = {
- {
- .start = MX3x_IPU_CTRL_BASE_ADDR + 0xB4,
- .end = MX3x_IPU_CTRL_BASE_ADDR + 0x1BF,
- .flags = IORESOURCE_MEM,
- },
-};
-
-struct platform_device mx3_fb = {
- .name = "mx3_sdc_fb",
- .id = -1,
- .num_resources = ARRAY_SIZE(fb_resources),
- .resource = fb_resources,
- .dev = {
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
-};
-
-static struct resource camera_resources[] = {
- {
- .start = MX3x_IPU_CTRL_BASE_ADDR + 0x60,
- .end = MX3x_IPU_CTRL_BASE_ADDR + 0x87,
- .flags = IORESOURCE_MEM,
- },
-};
-
-struct platform_device mx3_camera = {
- .name = "mx3-camera",
- .id = 0,
- .num_resources = ARRAY_SIZE(camera_resources),
- .resource = camera_resources,
- .dev = {
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
-};
-
-static struct resource imx_rtc_resources[] = {
- {
- .start = MX31_RTC_BASE_ADDR,
- .end = MX31_RTC_BASE_ADDR + 0x3fff,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = MX31_INT_RTC,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-struct platform_device imx_rtc_device0 = {
- .name = "mxc_rtc",
- .id = -1,
- .num_resources = ARRAY_SIZE(imx_rtc_resources),
- .resource = imx_rtc_resources,
-};
diff --git a/arch/arm/mach-mx3/devices.h b/arch/arm/mach-mx3/devices.h
deleted file mode 100644
index 121962c568d1..000000000000
--- a/arch/arm/mach-mx3/devices.h
+++ /dev/null
@@ -1,4 +0,0 @@
-extern struct platform_device mx3_ipu;
-extern struct platform_device mx3_fb;
-extern struct platform_device mx3_camera;
-extern struct platform_device imx_rtc_device0;
diff --git a/arch/arm/mach-mx3/mm.c b/arch/arm/mach-mx3/mm.c
deleted file mode 100644
index 54d7174b4202..000000000000
--- a/arch/arm/mach-mx3/mm.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 1999,2000 Arm Limited
- * Copyright (C) 2000 Deep Blue Solutions Ltd
- * Copyright (C) 2002 Shane Nay (shane@minirl.com)
- * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
- * - add MX31 specific definitions
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/err.h>
-
-#include <asm/pgtable.h>
-#include <asm/mach/map.h>
-#include <asm/hardware/cache-l2x0.h>
-
-#include <mach/common.h>
-#include <mach/hardware.h>
-#include <mach/iomux-v3.h>
-#include <mach/gpio.h>
-#include <mach/irqs.h>
-
-#ifdef CONFIG_SOC_IMX31
-static struct map_desc mx31_io_desc[] __initdata = {
- imx_map_entry(MX31, X_MEMC, MT_DEVICE),
- imx_map_entry(MX31, AVIC, MT_DEVICE_NONSHARED),
- imx_map_entry(MX31, AIPS1, MT_DEVICE_NONSHARED),
- imx_map_entry(MX31, AIPS2, MT_DEVICE_NONSHARED),
- imx_map_entry(MX31, SPBA0, MT_DEVICE_NONSHARED),
-};
-
-/*
- * This function initializes the memory map. It is called during the
- * system startup to create static physical to virtual memory mappings
- * for the IO modules.
- */
-void __init mx31_map_io(void)
-{
- iotable_init(mx31_io_desc, ARRAY_SIZE(mx31_io_desc));
-}
-
-void __init imx31_init_early(void)
-{
- mxc_set_cpu_type(MXC_CPU_MX31);
- mxc_arch_reset_init(MX31_IO_ADDRESS(MX31_WDOG_BASE_ADDR));
-}
-
-static struct mxc_gpio_port imx31_gpio_ports[] = {
- DEFINE_IMX_GPIO_PORT_IRQ(MX31, 0, 1, MX31_INT_GPIO1),
- DEFINE_IMX_GPIO_PORT_IRQ(MX31, 1, 2, MX31_INT_GPIO2),
- DEFINE_IMX_GPIO_PORT_IRQ(MX31, 2, 3, MX31_INT_GPIO3),
-};
-
-void __init mx31_init_irq(void)
-{
- mxc_init_irq(MX31_IO_ADDRESS(MX31_AVIC_BASE_ADDR));
- mxc_gpio_init(imx31_gpio_ports, ARRAY_SIZE(imx31_gpio_ports));
-}
-#endif /* ifdef CONFIG_SOC_IMX31 */
-
-#ifdef CONFIG_SOC_IMX35
-static struct map_desc mx35_io_desc[] __initdata = {
- imx_map_entry(MX35, X_MEMC, MT_DEVICE),
- imx_map_entry(MX35, AVIC, MT_DEVICE_NONSHARED),
- imx_map_entry(MX35, AIPS1, MT_DEVICE_NONSHARED),
- imx_map_entry(MX35, AIPS2, MT_DEVICE_NONSHARED),
- imx_map_entry(MX35, SPBA0, MT_DEVICE_NONSHARED),
-};
-
-void __init mx35_map_io(void)
-{
- iotable_init(mx35_io_desc, ARRAY_SIZE(mx35_io_desc));
-}
-
-void __init imx35_init_early(void)
-{
- mxc_set_cpu_type(MXC_CPU_MX35);
- mxc_iomux_v3_init(MX35_IO_ADDRESS(MX35_IOMUXC_BASE_ADDR));
- mxc_arch_reset_init(MX35_IO_ADDRESS(MX35_WDOG_BASE_ADDR));
-}
-
-static struct mxc_gpio_port imx35_gpio_ports[] = {
- DEFINE_IMX_GPIO_PORT_IRQ(MX35, 0, 1, MX35_INT_GPIO1),
- DEFINE_IMX_GPIO_PORT_IRQ(MX35, 1, 2, MX35_INT_GPIO2),
- DEFINE_IMX_GPIO_PORT_IRQ(MX35, 2, 3, MX35_INT_GPIO3),
-};
-
-void __init mx35_init_irq(void)
-{
- mxc_init_irq(MX35_IO_ADDRESS(MX35_AVIC_BASE_ADDR));
- mxc_gpio_init(imx35_gpio_ports, ARRAY_SIZE(imx35_gpio_ports));
-}
-#endif /* ifdef CONFIG_SOC_IMX35 */
-
-#ifdef CONFIG_CACHE_L2X0
-static int mxc_init_l2x0(void)
-{
- void __iomem *l2x0_base;
- void __iomem *clkctl_base;
-/*
- * First of all, we must repair broken chip settings. There are some
- * i.MX35 CPUs in the wild, comming with bogus L2 cache settings. These
- * misconfigured CPUs will run amok immediately when the L2 cache gets enabled.
- * Workaraound is to setup the correct register setting prior enabling the
- * L2 cache. This should not hurt already working CPUs, as they are using the
- * same value
- */
-#define L2_MEM_VAL 0x10
-
- clkctl_base = ioremap(MX35_CLKCTL_BASE_ADDR, 4096);
- if (clkctl_base != NULL) {
- writel(0x00000515, clkctl_base + L2_MEM_VAL);
- iounmap(clkctl_base);
- } else {
- pr_err("L2 cache: Cannot fix timing. Trying to continue without\n");
- }
-
- l2x0_base = ioremap(MX3x_L2CC_BASE_ADDR, 4096);
- if (IS_ERR(l2x0_base)) {
- printk(KERN_ERR "remapping L2 cache area failed with %ld\n",
- PTR_ERR(l2x0_base));
- return 0;
- }
-
- l2x0_init(l2x0_base, 0x00030024, 0x00000000);
-
- return 0;
-}
-
-arch_initcall(mxc_init_l2x0);
-#endif
diff --git a/arch/arm/mach-mx5/Kconfig b/arch/arm/mach-mx5/Kconfig
index 159340da9191..799fbc40e53c 100644
--- a/arch/arm/mach-mx5/Kconfig
+++ b/arch/arm/mach-mx5/Kconfig
@@ -1,11 +1,11 @@
-if ARCH_MX5
-# ARCH_MX50/51/53 are left to mark places where prevent multi-soc in single
+if ARCH_MX503 || ARCH_MX51
+# ARCH_MX5/50/53 are left to mark places where prevent multi-soc in single
# image. So for most time, SOC_IMX50/51/53 should be used.
-config ARCH_MX50
+config ARCH_MX5
bool
-config ARCH_MX51
+config ARCH_MX50
bool
config ARCH_MX53
@@ -13,27 +13,54 @@ config ARCH_MX53
config SOC_IMX50
bool
+ select CPU_V7
+ select ARM_L1_CACHE_SHIFT_6
select MXC_TZIC
select ARCH_MXC_IOMUX_V3
select ARCH_MXC_AUDMUX_V2
select ARCH_HAS_CPUFREQ
+ select ARCH_MX5
select ARCH_MX50
config SOC_IMX51
bool
+ select CPU_V7
+ select ARM_L1_CACHE_SHIFT_6
select MXC_TZIC
select ARCH_MXC_IOMUX_V3
select ARCH_MXC_AUDMUX_V2
select ARCH_HAS_CPUFREQ
- select ARCH_MX51
+ select ARCH_MX5
config SOC_IMX53
bool
+ select CPU_V7
+ select ARM_L1_CACHE_SHIFT_6
select MXC_TZIC
select ARCH_MXC_IOMUX_V3
+ select ARCH_MX5
select ARCH_MX53
-comment "MX5 platforms:"
+if ARCH_MX50_SUPPORTED
+#comment "i.MX50 machines:"
+
+config MACH_MX50_RDP
+ bool "Support MX50 reference design platform"
+ depends on BROKEN
+ select SOC_IMX50
+ select IMX_HAVE_PLATFORM_IMX_I2C
+ select IMX_HAVE_PLATFORM_IMX_UART
+ select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
+ select IMX_HAVE_PLATFORM_SPI_IMX
+ select IMX_HAVE_PLATFORM_FEC
+ help
+ Include support for MX50 reference design platform (RDP) board. This
+ includes specific configurations for the board and its peripherals.
+
+endif # ARCH_MX50_SUPPORTED
+
+if ARCH_MX51
+comment "i.MX51 machines:"
config MACH_MX51_BABBAGE
bool "Support MX51 BABBAGE platforms"
@@ -136,6 +163,11 @@ config MACH_MX51_EFIKASB
Include support for Genesi Efika Smartbook. This includes specific
configurations for the board and its peripherals.
+endif # ARCH_MX51
+
+if ARCH_MX53_SUPPORTED
+comment "i.MX53 machines:"
+
config MACH_MX53_EVK
bool "Support MX53 EVK platforms"
select SOC_IMX53
@@ -154,6 +186,7 @@ config MACH_MX53_SMD
select IMX_HAVE_PLATFORM_IMX2_WDT
select IMX_HAVE_PLATFORM_IMX_I2C
select IMX_HAVE_PLATFORM_IMX_UART
+ select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
help
Include support for MX53 SMD platform. This includes specific
configurations for the board and its peripherals.
@@ -170,17 +203,6 @@ config MACH_MX53_LOCO
Include support for MX53 LOCO platform. This includes specific
configurations for the board and its peripherals.
-config MACH_MX50_RDP
- bool "Support MX50 reference design platform"
- depends on BROKEN
- select SOC_IMX50
- select IMX_HAVE_PLATFORM_IMX_I2C
- select IMX_HAVE_PLATFORM_IMX_UART
- select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
- select IMX_HAVE_PLATFORM_SPI_IMX
- select IMX_HAVE_PLATFORM_FEC
- help
- Include support for MX50 reference design platform (RDP) board. This
- includes specific configurations for the board and its peripherals.
+endif # ARCH_MX53_SUPPORTED
endif
diff --git a/arch/arm/mach-mx5/board-cpuimx51.c b/arch/arm/mach-mx5/board-cpuimx51.c
index d0296a94c475..4efa02ee1639 100644
--- a/arch/arm/mach-mx5/board-cpuimx51.c
+++ b/arch/arm/mach-mx5/board-cpuimx51.c
@@ -23,13 +23,11 @@
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
-#include <linux/fsl_devices.h>
#include <mach/eukrea-baseboards.h>
#include <mach/common.h>
#include <mach/hardware.h>
#include <mach/iomux-mx51.h>
-#include <mach/mxc_ehci.h>
#include <asm/irq.h>
#include <asm/setup.h>
diff --git a/arch/arm/mach-mx5/board-cpuimx51sd.c b/arch/arm/mach-mx5/board-cpuimx51sd.c
index 29b180823bf5..5ef25a596143 100644
--- a/arch/arm/mach-mx5/board-cpuimx51sd.c
+++ b/arch/arm/mach-mx5/board-cpuimx51sd.c
@@ -23,7 +23,6 @@
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
-#include <linux/fsl_devices.h>
#include <linux/i2c-gpio.h>
#include <linux/spi/spi.h>
#include <linux/can/platform/mcp251x.h>
@@ -32,7 +31,6 @@
#include <mach/common.h>
#include <mach/hardware.h>
#include <mach/iomux-mx51.h>
-#include <mach/mxc_ehci.h>
#include <asm/irq.h>
#include <asm/setup.h>
diff --git a/arch/arm/mach-mx5/board-mx50_rdp.c b/arch/arm/mach-mx5/board-mx50_rdp.c
index dedf7f2d6d0f..11210e1ae42a 100644
--- a/arch/arm/mach-mx5/board-mx50_rdp.c
+++ b/arch/arm/mach-mx5/board-mx50_rdp.c
@@ -23,7 +23,6 @@
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/io.h>
-#include <linux/fsl_devices.h>
#include <mach/common.h>
#include <mach/hardware.h>
diff --git a/arch/arm/mach-mx5/board-mx51_babbage.c b/arch/arm/mach-mx5/board-mx51_babbage.c
index bea4e4135f9d..c7b3fabf50f9 100644
--- a/arch/arm/mach-mx5/board-mx51_babbage.c
+++ b/arch/arm/mach-mx5/board-mx51_babbage.c
@@ -16,9 +16,6 @@
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/io.h>
-#include <linux/fsl_devices.h>
-#include <linux/fec.h>
-#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/spi/flash.h>
#include <linux/spi/spi.h>
@@ -26,7 +23,6 @@
#include <mach/common.h>
#include <mach/hardware.h>
#include <mach/iomux-mx51.h>
-#include <mach/mxc_ehci.h>
#include <asm/irq.h>
#include <asm/setup.h>
@@ -208,18 +204,16 @@ static inline void babbage_usbhub_reset(void)
{
int ret;
- /* Bring USB hub out of reset */
- ret = gpio_request(BABBAGE_USB_HUB_RESET, "GPIO1_7");
+ /* Reset USB hub */
+ ret = gpio_request_one(BABBAGE_USB_HUB_RESET,
+ GPIOF_OUT_INIT_LOW, "GPIO1_7");
if (ret) {
printk(KERN_ERR"failed to get GPIO_USB_HUB_RESET: %d\n", ret);
return;
}
- gpio_direction_output(BABBAGE_USB_HUB_RESET, 0);
- /* USB HUB RESET - De-assert USB HUB RESET_N */
- msleep(1);
- gpio_set_value(BABBAGE_USB_HUB_RESET, 0);
- msleep(1);
+ msleep(2);
+ /* Deassert reset */
gpio_set_value(BABBAGE_USB_HUB_RESET, 1);
}
@@ -361,7 +355,7 @@ static void __init mx51_babbage_init(void)
/* Set the PAD settings for the pwr key. */
mxc_iomux_v3_setup_pad(power_key);
- imx51_add_gpio_keys(&imx_button_data);
+ imx_add_gpio_keys(&imx_button_data);
imx51_add_imx_i2c(0, &babbage_i2c_data);
imx51_add_imx_i2c(1, &babbage_i2c_data);
diff --git a/arch/arm/mach-mx5/board-mx51_efikamx.c b/arch/arm/mach-mx5/board-mx51_efikamx.c
index acab1911cb3c..6e362315291b 100644
--- a/arch/arm/mach-mx5/board-mx51_efikamx.c
+++ b/arch/arm/mach-mx5/board-mx51_efikamx.c
@@ -22,7 +22,6 @@
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/io.h>
-#include <linux/fsl_devices.h>
#include <linux/spi/flash.h>
#include <linux/spi/spi.h>
#include <linux/mfd/mc13892.h>
@@ -32,8 +31,6 @@
#include <mach/common.h>
#include <mach/hardware.h>
#include <mach/iomux-mx51.h>
-#include <mach/i2c.h>
-#include <mach/mxc_ehci.h>
#include <asm/irq.h>
#include <asm/setup.h>
@@ -252,7 +249,7 @@ static void __init mx51_efikamx_init(void)
}
platform_device_register(&mx51_efikamx_leds_device);
- imx51_add_gpio_keys(&mx51_efikamx_powerkey_data);
+ imx_add_gpio_keys(&mx51_efikamx_powerkey_data);
if (system_rev == 0x11) {
gpio_request(EFIKAMX_RESET1_1, "reset");
diff --git a/arch/arm/mach-mx5/board-mx51_efikasb.c b/arch/arm/mach-mx5/board-mx51_efikasb.c
index db04ce8462dc..474fc6e4c6df 100644
--- a/arch/arm/mach-mx5/board-mx51_efikasb.c
+++ b/arch/arm/mach-mx5/board-mx51_efikasb.c
@@ -22,7 +22,6 @@
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/io.h>
-#include <linux/fsl_devices.h>
#include <linux/spi/flash.h>
#include <linux/spi/spi.h>
#include <linux/mfd/mc13892.h>
@@ -35,8 +34,6 @@
#include <mach/common.h>
#include <mach/hardware.h>
#include <mach/iomux-mx51.h>
-#include <mach/i2c.h>
-#include <mach/mxc_ehci.h>
#include <asm/irq.h>
#include <asm/setup.h>
@@ -260,7 +257,7 @@ static void __init efikasb_board_init(void)
imx51_add_sdhci_esdhc_imx(1, NULL);
platform_device_register(&mx51_efikasb_leds_device);
- imx51_add_gpio_keys(&mx51_efikasb_keys_data);
+ imx_add_gpio_keys(&mx51_efikasb_keys_data);
}
diff --git a/arch/arm/mach-mx5/board-mx53_evk.c b/arch/arm/mach-mx5/board-mx53_evk.c
index 2af3f43f74db..f87d571882c6 100644
--- a/arch/arm/mach-mx5/board-mx53_evk.c
+++ b/arch/arm/mach-mx5/board-mx53_evk.c
@@ -21,7 +21,6 @@
#include <linux/init.h>
#include <linux/clk.h>
-#include <linux/fec.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/spi/flash.h>
@@ -31,7 +30,6 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
-#include <mach/imx-uart.h>
#include <mach/iomux-mx53.h>
#define MX53_EVK_FEC_PHY_RST IMX_GPIO_NR(7, 6)
diff --git a/arch/arm/mach-mx5/board-mx53_loco.c b/arch/arm/mach-mx5/board-mx53_loco.c
index 6206b1191fe8..1b947e8c9c0c 100644
--- a/arch/arm/mach-mx5/board-mx53_loco.c
+++ b/arch/arm/mach-mx5/board-mx53_loco.c
@@ -20,13 +20,11 @@
#include <linux/init.h>
#include <linux/clk.h>
-#include <linux/fec.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <mach/common.h>
#include <mach/hardware.h>
-#include <mach/imx-uart.h>
#include <mach/iomux-mx53.h>
#include <asm/mach-types.h>
diff --git a/arch/arm/mach-mx5/board-mx53_smd.c b/arch/arm/mach-mx5/board-mx53_smd.c
index 31e173267edf..817c08938f55 100644
--- a/arch/arm/mach-mx5/board-mx53_smd.c
+++ b/arch/arm/mach-mx5/board-mx53_smd.c
@@ -20,13 +20,11 @@
#include <linux/init.h>
#include <linux/clk.h>
-#include <linux/fec.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <mach/common.h>
#include <mach/hardware.h>
-#include <mach/imx-uart.h>
#include <mach/iomux-mx53.h>
#include <asm/mach-types.h>
@@ -52,6 +50,31 @@ static iomux_v3_cfg_t mx53_smd_pads[] = {
/* I2C1 */
MX53_PAD_CSI0_DAT8__I2C1_SDA,
MX53_PAD_CSI0_DAT9__I2C1_SCL,
+ /* SD1 */
+ MX53_PAD_SD1_CMD__ESDHC1_CMD,
+ MX53_PAD_SD1_CLK__ESDHC1_CLK,
+ MX53_PAD_SD1_DATA0__ESDHC1_DAT0,
+ MX53_PAD_SD1_DATA1__ESDHC1_DAT1,
+ MX53_PAD_SD1_DATA2__ESDHC1_DAT2,
+ MX53_PAD_SD1_DATA3__ESDHC1_DAT3,
+ /* SD2 */
+ MX53_PAD_SD2_CMD__ESDHC2_CMD,
+ MX53_PAD_SD2_CLK__ESDHC2_CLK,
+ MX53_PAD_SD2_DATA0__ESDHC2_DAT0,
+ MX53_PAD_SD2_DATA1__ESDHC2_DAT1,
+ MX53_PAD_SD2_DATA2__ESDHC2_DAT2,
+ MX53_PAD_SD2_DATA3__ESDHC2_DAT3,
+ /* SD3 */
+ MX53_PAD_PATA_DATA8__ESDHC3_DAT0,
+ MX53_PAD_PATA_DATA9__ESDHC3_DAT1,
+ MX53_PAD_PATA_DATA10__ESDHC3_DAT2,
+ MX53_PAD_PATA_DATA11__ESDHC3_DAT3,
+ MX53_PAD_PATA_DATA0__ESDHC3_DAT4,
+ MX53_PAD_PATA_DATA1__ESDHC3_DAT5,
+ MX53_PAD_PATA_DATA2__ESDHC3_DAT6,
+ MX53_PAD_PATA_DATA3__ESDHC3_DAT7,
+ MX53_PAD_PATA_IORDY__ESDHC3_CLK,
+ MX53_PAD_PATA_RESET_B__ESDHC3_CMD,
};
static const struct imxuart_platform_data mx53_smd_uart_data __initconst = {
@@ -97,6 +120,9 @@ static void __init mx53_smd_board_init(void)
imx53_add_fec(&mx53_smd_fec_data);
imx53_add_imx2_wdt(0, NULL);
imx53_add_imx_i2c(0, &mx53_smd_i2c_data);
+ imx53_add_sdhci_esdhc_imx(0, NULL);
+ imx53_add_sdhci_esdhc_imx(1, NULL);
+ imx53_add_sdhci_esdhc_imx(2, NULL);
}
static void __init mx53_smd_timer_init(void)
diff --git a/arch/arm/mach-mx5/clock-mx51-mx53.c b/arch/arm/mach-mx5/clock-mx51-mx53.c
index fdbc05ed5513..6b89c1bf4eb2 100644
--- a/arch/arm/mach-mx5/clock-mx51-mx53.c
+++ b/arch/arm/mach-mx5/clock-mx51-mx53.c
@@ -1563,6 +1563,7 @@ int __init mx53_clocks_init(unsigned long ckil, unsigned long osc,
clk_enable(&iim_clk);
mx53_revision();
clk_disable(&iim_clk);
+ mx53_display_revision();
/* Set SDHC parents to be PLL2 */
clk_set_parent(&esdhc1_clk, &pll2_sw_clk);
diff --git a/arch/arm/mach-mx5/cpu.c b/arch/arm/mach-mx5/cpu.c
index 472bdfab2e55..86f87da59c64 100644
--- a/arch/arm/mach-mx5/cpu.c
+++ b/arch/arm/mach-mx5/cpu.c
@@ -166,6 +166,29 @@ int mx50_revision(void)
}
EXPORT_SYMBOL(mx50_revision);
+void mx53_display_revision(void)
+{
+ int rev;
+ char *srev;
+ rev = mx53_revision();
+
+ switch (rev) {
+ case IMX_CHIP_REVISION_1_0:
+ srev = IMX_CHIP_REVISION_1_0_STRING;
+ break;
+ case IMX_CHIP_REVISION_2_0:
+ srev = IMX_CHIP_REVISION_2_0_STRING;
+ break;
+ case IMX_CHIP_REVISION_2_1:
+ srev = IMX_CHIP_REVISION_2_1_STRING;
+ break;
+ default:
+ srev = IMX_CHIP_REVISION_UNKNOWN_STRING;
+ }
+ printk(KERN_INFO "CPU identified as i.MX53, silicon rev %s\n", srev);
+}
+EXPORT_SYMBOL(mx53_display_revision);
+
static int __init post_cpu_init(void)
{
unsigned int reg;
diff --git a/arch/arm/mach-mx5/devices-imx50.h b/arch/arm/mach-mx5/devices-imx50.h
index c9e42823c7e3..7216667eaafc 100644
--- a/arch/arm/mach-mx5/devices-imx50.h
+++ b/arch/arm/mach-mx5/devices-imx50.h
@@ -21,14 +21,14 @@
#include <mach/mx50.h>
#include <mach/devices-common.h>
-extern const struct imx_imx_uart_1irq_data imx50_imx_uart_data[] __initconst;
+extern const struct imx_imx_uart_1irq_data imx50_imx_uart_data[];
#define imx50_add_imx_uart(id, pdata) \
imx_add_imx_uart_1irq(&imx50_imx_uart_data[id], pdata)
-extern const struct imx_fec_data imx50_fec_data __initconst;
+extern const struct imx_fec_data imx50_fec_data;
#define imx50_add_fec(pdata) \
imx_add_fec(&imx50_fec_data, pdata)
-extern const struct imx_imx_i2c_data imx50_imx_i2c_data[] __initconst;
+extern const struct imx_imx_i2c_data imx50_imx_i2c_data[];
#define imx50_add_imx_i2c(id, pdata) \
imx_add_imx_i2c(&imx50_imx_i2c_data[id], pdata)
diff --git a/arch/arm/mach-mx5/devices-imx51.h b/arch/arm/mach-mx5/devices-imx51.h
index 7fff485e5603..e11bc0e0ec49 100644
--- a/arch/arm/mach-mx5/devices-imx51.h
+++ b/arch/arm/mach-mx5/devices-imx51.h
@@ -9,49 +9,46 @@
#include <mach/mx51.h>
#include <mach/devices-common.h>
-extern const struct imx_fec_data imx51_fec_data __initconst;
+extern const struct imx_fec_data imx51_fec_data;
#define imx51_add_fec(pdata) \
imx_add_fec(&imx51_fec_data, pdata)
-#define imx51_add_gpio_keys(pdata) imx_add_gpio_keys(pdata)
-
-extern const struct imx_imx_i2c_data imx51_imx_i2c_data[] __initconst;
+extern const struct imx_imx_i2c_data imx51_imx_i2c_data[];
#define imx51_add_imx_i2c(id, pdata) \
imx_add_imx_i2c(&imx51_imx_i2c_data[id], pdata)
-extern const struct imx_imx_ssi_data imx51_imx_ssi_data[] __initconst;
+extern const struct imx_imx_ssi_data imx51_imx_ssi_data[];
#define imx51_add_imx_ssi(id, pdata) \
imx_add_imx_ssi(&imx51_imx_ssi_data[id], pdata)
-extern const struct imx_imx_uart_1irq_data imx51_imx_uart_data[] __initconst;
+extern const struct imx_imx_uart_1irq_data imx51_imx_uart_data[];
#define imx51_add_imx_uart(id, pdata) \
imx_add_imx_uart_1irq(&imx51_imx_uart_data[id], pdata)
-extern const struct imx_mxc_nand_data imx51_mxc_nand_data __initconst;
+extern const struct imx_mxc_nand_data imx51_mxc_nand_data;
#define imx51_add_mxc_nand(pdata) \
imx_add_mxc_nand(&imx51_mxc_nand_data, pdata)
-extern const struct imx_sdhci_esdhc_imx_data
-imx51_sdhci_esdhc_imx_data[] __initconst;
+extern const struct imx_sdhci_esdhc_imx_data imx51_sdhci_esdhc_imx_data[];
#define imx51_add_sdhci_esdhc_imx(id, pdata) \
imx_add_sdhci_esdhc_imx(&imx51_sdhci_esdhc_imx_data[id], pdata)
-extern const struct imx_spi_imx_data imx51_cspi_data __initconst;
+extern const struct imx_spi_imx_data imx51_cspi_data;
#define imx51_add_cspi(pdata) \
imx_add_spi_imx(&imx51_cspi_data, pdata)
-extern const struct imx_spi_imx_data imx51_ecspi_data[] __initconst;
+extern const struct imx_spi_imx_data imx51_ecspi_data[];
#define imx51_add_ecspi(id, pdata) \
imx_add_spi_imx(&imx51_ecspi_data[id], pdata)
-extern const struct imx_imx2_wdt_data imx51_imx2_wdt_data[] __initconst;
+extern const struct imx_imx2_wdt_data imx51_imx2_wdt_data[];
#define imx51_add_imx2_wdt(id, pdata) \
imx_add_imx2_wdt(&imx51_imx2_wdt_data[id])
-extern const struct imx_mxc_pwm_data imx51_mxc_pwm_data[] __initconst;
+extern const struct imx_mxc_pwm_data imx51_mxc_pwm_data[];
#define imx51_add_mxc_pwm(id) \
imx_add_mxc_pwm(&imx51_mxc_pwm_data[id])
-extern const struct imx_imx_keypad_data imx51_imx_keypad_data __initconst;
+extern const struct imx_imx_keypad_data imx51_imx_keypad_data;
#define imx51_add_imx_keypad(pdata) \
imx_add_imx_keypad(&imx51_imx_keypad_data, pdata)
diff --git a/arch/arm/mach-mx5/devices-imx53.h b/arch/arm/mach-mx5/devices-imx53.h
index 9251008dad1f..48f4c8cc42f5 100644
--- a/arch/arm/mach-mx5/devices-imx53.h
+++ b/arch/arm/mach-mx5/devices-imx53.h
@@ -8,28 +8,27 @@
#include <mach/mx53.h>
#include <mach/devices-common.h>
-extern const struct imx_fec_data imx53_fec_data __initconst;
+extern const struct imx_fec_data imx53_fec_data;
#define imx53_add_fec(pdata) \
imx_add_fec(&imx53_fec_data, pdata)
-extern const struct imx_imx_uart_1irq_data imx53_imx_uart_data[] __initconst;
+extern const struct imx_imx_uart_1irq_data imx53_imx_uart_data[];
#define imx53_add_imx_uart(id, pdata) \
imx_add_imx_uart_1irq(&imx53_imx_uart_data[id], pdata)
-extern const struct imx_imx_i2c_data imx53_imx_i2c_data[] __initconst;
+extern const struct imx_imx_i2c_data imx53_imx_i2c_data[];
#define imx53_add_imx_i2c(id, pdata) \
imx_add_imx_i2c(&imx53_imx_i2c_data[id], pdata)
-extern const struct imx_sdhci_esdhc_imx_data
-imx53_sdhci_esdhc_imx_data[] __initconst;
+extern const struct imx_sdhci_esdhc_imx_data imx53_sdhci_esdhc_imx_data[];
#define imx53_add_sdhci_esdhc_imx(id, pdata) \
imx_add_sdhci_esdhc_imx(&imx53_sdhci_esdhc_imx_data[id], pdata)
-extern const struct imx_spi_imx_data imx53_ecspi_data[] __initconst;
+extern const struct imx_spi_imx_data imx53_ecspi_data[];
#define imx53_add_ecspi(id, pdata) \
imx_add_spi_imx(&imx53_ecspi_data[id], pdata)
-extern const struct imx_imx2_wdt_data imx53_imx2_wdt_data[] __initconst;
+extern const struct imx_imx2_wdt_data imx53_imx2_wdt_data[];
#define imx53_add_imx2_wdt(id, pdata) \
imx_add_imx2_wdt(&imx53_imx2_wdt_data[id])
diff --git a/arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c b/arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c
index 4a8550529b04..97292d20f1f3 100644
--- a/arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c
+++ b/arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c
@@ -18,13 +18,11 @@
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
-#include <linux/fsl_devices.h>
#include <linux/i2c/tsc2007.h>
#include <linux/leds.h>
#include <mach/common.h>
#include <mach/hardware.h>
-#include <mach/imx-uart.h>
#include <mach/iomux-mx51.h>
#include <asm/mach/arch.h>
diff --git a/arch/arm/mach-mx5/eukrea_mbimxsd-baseboard.c b/arch/arm/mach-mx5/eukrea_mbimxsd-baseboard.c
index e6c1119c20ae..31c871ec46a6 100644
--- a/arch/arm/mach-mx5/eukrea_mbimxsd-baseboard.c
+++ b/arch/arm/mach-mx5/eukrea_mbimxsd-baseboard.c
@@ -27,7 +27,6 @@
#include <linux/irq.h>
#include <linux/leds.h>
#include <linux/platform_device.h>
-#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/i2c.h>
@@ -38,7 +37,6 @@
#include <mach/hardware.h>
#include <mach/common.h>
-#include <mach/imx-uart.h>
#include <mach/iomux-mx51.h>
#include <mach/audmux.h>
@@ -108,23 +106,14 @@ static struct gpio_keys_button eukrea_mbimxsd_gpio_buttons[] = {
},
};
-static struct gpio_keys_platform_data eukrea_mbimxsd_button_data = {
+static const struct gpio_keys_platform_data
+ eukrea_mbimxsd_button_data __initconst = {
.buttons = eukrea_mbimxsd_gpio_buttons,
.nbuttons = ARRAY_SIZE(eukrea_mbimxsd_gpio_buttons),
};
-static struct platform_device eukrea_mbimxsd_button_device = {
- .name = "gpio-keys",
- .id = -1,
- .num_resources = 0,
- .dev = {
- .platform_data = &eukrea_mbimxsd_button_data,
- }
-};
-
static struct platform_device *platform_devices[] __initdata = {
&eukrea_mbimxsd_leds_gpio,
- &eukrea_mbimxsd_button_device,
};
static const struct imxuart_platform_data uart_pdata __initconst = {
@@ -166,4 +155,5 @@ void __init eukrea_mbimxsd51_baseboard_init(void)
ARRAY_SIZE(eukrea_mbimxsd_i2c_devices));
platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+ imx_add_gpio_keys(&eukrea_mbimxsd_button_data);
}
diff --git a/arch/arm/mach-mx5/mx51_efika.c b/arch/arm/mach-mx5/mx51_efika.c
index d0c7075937cf..56739c23aca7 100644
--- a/arch/arm/mach-mx5/mx51_efika.c
+++ b/arch/arm/mach-mx5/mx51_efika.c
@@ -20,7 +20,6 @@
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/io.h>
-#include <linux/fsl_devices.h>
#include <linux/spi/flash.h>
#include <linux/spi/spi.h>
#include <linux/mfd/mc13892.h>
@@ -30,8 +29,6 @@
#include <mach/common.h>
#include <mach/hardware.h>
#include <mach/iomux-mx51.h>
-#include <mach/i2c.h>
-#include <mach/mxc_ehci.h>
#include <linux/usb/otg.h>
#include <linux/usb/ulpi.h>
diff --git a/arch/arm/mach-mxc91231/Kconfig b/arch/arm/mach-mxc91231/Kconfig
deleted file mode 100644
index 8e5fa38ebb67..000000000000
--- a/arch/arm/mach-mxc91231/Kconfig
+++ /dev/null
@@ -1,11 +0,0 @@
-if ARCH_MXC91231
-
-comment "MXC91231 platforms:"
-
-config MACH_MAGX_ZN5
- bool "Support Motorola Zn5 GSM phone"
- default n
- help
- Include support for Motorola Zn5 GSM phone.
-
-endif
diff --git a/arch/arm/mach-mxc91231/Makefile b/arch/arm/mach-mxc91231/Makefile
deleted file mode 100644
index 011d5e197125..000000000000
--- a/arch/arm/mach-mxc91231/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-obj-y := mm.o clock.o devices.o system.o iomux.o
-obj-$(CONFIG_MACH_MAGX_ZN5) += magx-zn5.o
diff --git a/arch/arm/mach-mxc91231/Makefile.boot b/arch/arm/mach-mxc91231/Makefile.boot
deleted file mode 100644
index 9939a19d99a1..000000000000
--- a/arch/arm/mach-mxc91231/Makefile.boot
+++ /dev/null
@@ -1,3 +0,0 @@
- zreladdr-y := 0x90008000
-params_phys-y := 0x90000100
-initrd_phys-y := 0x90800000
diff --git a/arch/arm/mach-mxc91231/clock.c b/arch/arm/mach-mxc91231/clock.c
deleted file mode 100644
index 9fab505f1eb1..000000000000
--- a/arch/arm/mach-mxc91231/clock.c
+++ /dev/null
@@ -1,640 +0,0 @@
-#include <linux/clk.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/clkdev.h>
-
-#include <mach/clock.h>
-#include <mach/hardware.h>
-#include <mach/common.h>
-
-#include <asm/bug.h>
-#include <asm/div64.h>
-
-#include "crm_regs.h"
-
-#define CRM_SMALL_DIVIDER(base, name) \
- crm_small_divider(base, \
- base ## _ ## name ## _OFFSET, \
- base ## _ ## name ## _MASK)
-#define CRM_1DIVIDER(base, name) \
- crm_divider(base, \
- base ## _ ## name ## _OFFSET, \
- base ## _ ## name ## _MASK, 1)
-#define CRM_16DIVIDER(base, name) \
- crm_divider(base, \
- base ## _ ## name ## _OFFSET, \
- base ## _ ## name ## _MASK, 16)
-
-static u32 crm_small_divider(void __iomem *reg, u8 offset, u32 mask)
-{
- static const u32 crm_small_dividers[] = {
- 2, 3, 4, 5, 6, 8, 10, 12
- };
- u8 idx;
-
- idx = (__raw_readl(reg) & mask) >> offset;
- if (idx > 7)
- return 1;
-
- return crm_small_dividers[idx];
-}
-
-static u32 crm_divider(void __iomem *reg, u8 offset, u32 mask, u32 z)
-{
- u32 div;
- div = (__raw_readl(reg) & mask) >> offset;
- return div ? div : z;
-}
-
-static int _clk_1bit_enable(struct clk *clk)
-{
- u32 reg;
-
- reg = __raw_readl(clk->enable_reg);
- reg |= 1 << clk->enable_shift;
- __raw_writel(reg, clk->enable_reg);
-
- return 0;
-}
-
-static void _clk_1bit_disable(struct clk *clk)
-{
- u32 reg;
-
- reg = __raw_readl(clk->enable_reg);
- reg &= ~(1 << clk->enable_shift);
- __raw_writel(reg, clk->enable_reg);
-}
-
-static int _clk_3bit_enable(struct clk *clk)
-{
- u32 reg;
-
- reg = __raw_readl(clk->enable_reg);
- reg |= 0x7 << clk->enable_shift;
- __raw_writel(reg, clk->enable_reg);
-
- return 0;
-}
-
-static void _clk_3bit_disable(struct clk *clk)
-{
- u32 reg;
-
- reg = __raw_readl(clk->enable_reg);
- reg &= ~(0x7 << clk->enable_shift);
- __raw_writel(reg, clk->enable_reg);
-}
-
-static unsigned long ckih_rate;
-
-static unsigned long clk_ckih_get_rate(struct clk *clk)
-{
- return ckih_rate;
-}
-
-static struct clk ckih_clk = {
- .get_rate = clk_ckih_get_rate,
-};
-
-static unsigned long clk_ckih_x2_get_rate(struct clk *clk)
-{
- return 2 * clk_get_rate(clk->parent);
-}
-
-static struct clk ckih_x2_clk = {
- .parent = &ckih_clk,
- .get_rate = clk_ckih_x2_get_rate,
-};
-
-static unsigned long clk_ckil_get_rate(struct clk *clk)
-{
- return CKIL_CLK_FREQ;
-}
-
-static struct clk ckil_clk = {
- .get_rate = clk_ckil_get_rate,
-};
-
-/* plls stuff */
-static struct clk mcu_pll_clk;
-static struct clk dsp_pll_clk;
-static struct clk usb_pll_clk;
-
-static struct clk *pll_clk(u8 sel)
-{
- switch (sel) {
- case 0:
- return &mcu_pll_clk;
- case 1:
- return &dsp_pll_clk;
- case 2:
- return &usb_pll_clk;
- }
- BUG();
-}
-
-static void __iomem *pll_base(struct clk *clk)
-{
- if (clk == &mcu_pll_clk)
- return MXC_PLL0_BASE;
- else if (clk == &dsp_pll_clk)
- return MXC_PLL1_BASE;
- else if (clk == &usb_pll_clk)
- return MXC_PLL2_BASE;
- BUG();
-}
-
-static unsigned long clk_pll_get_rate(struct clk *clk)
-{
- const void __iomem *pllbase;
- unsigned long dp_op, dp_mfd, dp_mfn, pll_hfsm, ref_clk, mfi;
- long mfn, mfn_abs, mfd, pdf;
- s64 temp;
- pllbase = pll_base(clk);
-
- pll_hfsm = __raw_readl(pllbase + MXC_PLL_DP_CTL) & MXC_PLL_DP_CTL_HFSM;
- if (pll_hfsm == 0) {
- dp_op = __raw_readl(pllbase + MXC_PLL_DP_OP);
- dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_MFD);
- dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_MFN);
- } else {
- dp_op = __raw_readl(pllbase + MXC_PLL_DP_HFS_OP);
- dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_HFS_MFD);
- dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_HFS_MFN);
- }
-
- pdf = dp_op & MXC_PLL_DP_OP_PDF_MASK;
- mfi = (dp_op >> MXC_PLL_DP_OP_MFI_OFFSET) & MXC_PLL_DP_OP_PDF_MASK;
- mfi = (mfi <= 5) ? 5 : mfi;
- mfd = dp_mfd & MXC_PLL_DP_MFD_MASK;
- mfn = dp_mfn & MXC_PLL_DP_MFN_MASK;
- mfn = (mfn <= 0x4000000) ? mfn : (mfn - 0x10000000);
-
- if (mfn < 0)
- mfn_abs = -mfn;
- else
- mfn_abs = mfn;
-
-/* XXX: actually this asumes that ckih is fed to pll, but spec says
- * that ckih_x2 is also possible. need to check this out.
- */
- ref_clk = clk_get_rate(&ckih_clk);
-
- ref_clk *= 2;
- ref_clk /= pdf + 1;
-
- temp = (u64) ref_clk * mfn_abs;
- do_div(temp, mfd);
- if (mfn < 0)
- temp = -temp;
- temp += ref_clk * mfi;
-
- return temp;
-}
-
-static int clk_pll_enable(struct clk *clk)
-{
- void __iomem *ctl;
- u32 reg;
-
- ctl = pll_base(clk);
- reg = __raw_readl(ctl);
- reg |= (MXC_PLL_DP_CTL_RST | MXC_PLL_DP_CTL_UPEN);
- __raw_writel(reg, ctl);
- do {
- reg = __raw_readl(ctl);
- } while ((reg & MXC_PLL_DP_CTL_LRF) != MXC_PLL_DP_CTL_LRF);
- return 0;
-}
-
-static void clk_pll_disable(struct clk *clk)
-{
- void __iomem *ctl;
- u32 reg;
-
- ctl = pll_base(clk);
- reg = __raw_readl(ctl);
- reg &= ~(MXC_PLL_DP_CTL_RST | MXC_PLL_DP_CTL_UPEN);
- __raw_writel(reg, ctl);
-}
-
-static struct clk mcu_pll_clk = {
- .parent = &ckih_clk,
- .get_rate = clk_pll_get_rate,
- .enable = clk_pll_enable,
- .disable = clk_pll_disable,
-};
-
-static struct clk dsp_pll_clk = {
- .parent = &ckih_clk,
- .get_rate = clk_pll_get_rate,
- .enable = clk_pll_enable,
- .disable = clk_pll_disable,
-};
-
-static struct clk usb_pll_clk = {
- .parent = &ckih_clk,
- .get_rate = clk_pll_get_rate,
- .enable = clk_pll_enable,
- .disable = clk_pll_disable,
-};
-/* plls stuff end */
-
-/* ap_ref_clk stuff */
-static struct clk ap_ref_clk;
-
-static unsigned long clk_ap_ref_get_rate(struct clk *clk)
-{
- u32 ascsr, acsr;
- u8 ap_pat_ref_div_2, ap_isel, acs, ads;
-
- ascsr = __raw_readl(MXC_CRMAP_ASCSR);
- acsr = __raw_readl(MXC_CRMAP_ACSR);
-
- /* 0 for ckih, 1 for ckih*2 */
- ap_isel = ascsr & MXC_CRMAP_ASCSR_APISEL;
- /* reg divider */
- ap_pat_ref_div_2 = (ascsr >> MXC_CRMAP_ASCSR_AP_PATDIV2_OFFSET) & 0x1;
- /* undocumented, 1 for disabling divider */
- ads = (acsr >> MXC_CRMAP_ACSR_ADS_OFFSET) & 0x1;
- /* 0 for pat_ref, 1 for divider out */
- acs = acsr & MXC_CRMAP_ACSR_ACS;
-
- if (acs & !ads)
- /* use divided clock */
- return clk_get_rate(clk->parent) / (ap_pat_ref_div_2 ? 2 : 1);
-
- return clk_get_rate(clk->parent) * (ap_isel ? 2 : 1);
-}
-
-static struct clk ap_ref_clk = {
- .parent = &ckih_clk,
- .get_rate = clk_ap_ref_get_rate,
-};
-/* ap_ref_clk stuff end */
-
-/* ap_pre_dfs_clk stuff */
-static struct clk ap_pre_dfs_clk;
-
-static unsigned long clk_ap_pre_dfs_get_rate(struct clk *clk)
-{
- u32 acsr, ascsr;
-
- acsr = __raw_readl(MXC_CRMAP_ACSR);
- ascsr = __raw_readl(MXC_CRMAP_ASCSR);
-
- if (acsr & MXC_CRMAP_ACSR_ACS) {
- u8 sel;
- sel = (ascsr & MXC_CRMAP_ASCSR_APSEL_MASK) >>
- MXC_CRMAP_ASCSR_APSEL_OFFSET;
- return clk_get_rate(pll_clk(sel)) /
- CRM_SMALL_DIVIDER(MXC_CRMAP_ACDR, ARMDIV);
- }
- return clk_get_rate(&ap_ref_clk);
-}
-
-static struct clk ap_pre_dfs_clk = {
- .get_rate = clk_ap_pre_dfs_get_rate,
-};
-/* ap_pre_dfs_clk stuff end */
-
-/* usb_clk stuff */
-static struct clk usb_clk;
-
-static struct clk *clk_usb_parent(struct clk *clk)
-{
- u32 acsr, ascsr;
-
- acsr = __raw_readl(MXC_CRMAP_ACSR);
- ascsr = __raw_readl(MXC_CRMAP_ASCSR);
-
- if (acsr & MXC_CRMAP_ACSR_ACS) {
- u8 sel;
- sel = (ascsr & MXC_CRMAP_ASCSR_USBSEL_MASK) >>
- MXC_CRMAP_ASCSR_USBSEL_OFFSET;
- return pll_clk(sel);
- }
- return &ap_ref_clk;
-}
-
-static unsigned long clk_usb_get_rate(struct clk *clk)
-{
- return clk_get_rate(clk->parent) /
- CRM_SMALL_DIVIDER(MXC_CRMAP_ACDER2, USBDIV);
-}
-
-static struct clk usb_clk = {
- .enable_reg = MXC_CRMAP_ACDER2,
- .enable_shift = MXC_CRMAP_ACDER2_USBEN_OFFSET,
- .get_rate = clk_usb_get_rate,
- .enable = _clk_1bit_enable,
- .disable = _clk_1bit_disable,
-};
-/* usb_clk stuff end */
-
-static unsigned long clk_ipg_get_rate(struct clk *clk)
-{
- return clk_get_rate(clk->parent) / CRM_16DIVIDER(MXC_CRMAP_ACDR, IPDIV);
-}
-
-static unsigned long clk_ahb_get_rate(struct clk *clk)
-{
- return clk_get_rate(clk->parent) /
- CRM_16DIVIDER(MXC_CRMAP_ACDR, AHBDIV);
-}
-
-static struct clk ipg_clk = {
- .parent = &ap_pre_dfs_clk,
- .get_rate = clk_ipg_get_rate,
-};
-
-static struct clk ahb_clk = {
- .parent = &ap_pre_dfs_clk,
- .get_rate = clk_ahb_get_rate,
-};
-
-/* perclk_clk stuff */
-static struct clk perclk_clk;
-
-static unsigned long clk_perclk_get_rate(struct clk *clk)
-{
- u32 acder2;
-
- acder2 = __raw_readl(MXC_CRMAP_ACDER2);
- if (acder2 & MXC_CRMAP_ACDER2_BAUD_ISEL_MASK)
- return 2 * clk_get_rate(clk->parent);
-
- return clk_get_rate(clk->parent);
-}
-
-static struct clk perclk_clk = {
- .parent = &ckih_clk,
- .get_rate = clk_perclk_get_rate,
-};
-/* perclk_clk stuff end */
-
-/* uart_clk stuff */
-static struct clk uart_clk[];
-
-static unsigned long clk_uart_get_rate(struct clk *clk)
-{
- u32 div;
-
- switch (clk->id) {
- case 0:
- case 1:
- div = CRM_SMALL_DIVIDER(MXC_CRMAP_ACDER2, BAUDDIV);
- break;
- case 2:
- div = CRM_SMALL_DIVIDER(MXC_CRMAP_APRA, UART3DIV);
- break;
- default:
- BUG();
- }
- return clk_get_rate(clk->parent) / div;
-}
-
-static struct clk uart_clk[] = {
- {
- .id = 0,
- .parent = &perclk_clk,
- .enable_reg = MXC_CRMAP_APRA,
- .enable_shift = MXC_CRMAP_APRA_UART1EN_OFFSET,
- .get_rate = clk_uart_get_rate,
- .enable = _clk_1bit_enable,
- .disable = _clk_1bit_disable,
- }, {
- .id = 1,
- .parent = &perclk_clk,
- .enable_reg = MXC_CRMAP_APRA,
- .enable_shift = MXC_CRMAP_APRA_UART2EN_OFFSET,
- .get_rate = clk_uart_get_rate,
- .enable = _clk_1bit_enable,
- .disable = _clk_1bit_disable,
- }, {
- .id = 2,
- .parent = &perclk_clk,
- .enable_reg = MXC_CRMAP_APRA,
- .enable_shift = MXC_CRMAP_APRA_UART3EN_OFFSET,
- .get_rate = clk_uart_get_rate,
- .enable = _clk_1bit_enable,
- .disable = _clk_1bit_disable,
- },
-};
-/* uart_clk stuff end */
-
-/* sdhc_clk stuff */
-static struct clk nfc_clk;
-
-static unsigned long clk_nfc_get_rate(struct clk *clk)
-{
- return clk_get_rate(clk->parent) /
- CRM_1DIVIDER(MXC_CRMAP_ACDER2, NFCDIV);
-}
-
-static struct clk nfc_clk = {
- .parent = &ahb_clk,
- .enable_reg = MXC_CRMAP_ACDER2,
- .enable_shift = MXC_CRMAP_ACDER2_NFCEN_OFFSET,
- .get_rate = clk_nfc_get_rate,
- .enable = _clk_1bit_enable,
- .disable = _clk_1bit_disable,
-};
-/* sdhc_clk stuff end */
-
-/* sdhc_clk stuff */
-static struct clk sdhc_clk[];
-
-static struct clk *clk_sdhc_parent(struct clk *clk)
-{
- u32 aprb;
- u8 sel;
- u32 mask;
- int offset;
-
- aprb = __raw_readl(MXC_CRMAP_APRB);
-
- switch (clk->id) {
- case 0:
- mask = MXC_CRMAP_APRB_SDHC1_ISEL_MASK;
- offset = MXC_CRMAP_APRB_SDHC1_ISEL_OFFSET;
- break;
- case 1:
- mask = MXC_CRMAP_APRB_SDHC2_ISEL_MASK;
- offset = MXC_CRMAP_APRB_SDHC2_ISEL_OFFSET;
- break;
- default:
- BUG();
- }
- sel = (aprb & mask) >> offset;
-
- switch (sel) {
- case 0:
- return &ckih_clk;
- case 1:
- return &ckih_x2_clk;
- }
- return &usb_clk;
-}
-
-static unsigned long clk_sdhc_get_rate(struct clk *clk)
-{
- u32 div;
-
- switch (clk->id) {
- case 0:
- div = CRM_SMALL_DIVIDER(MXC_CRMAP_APRB, SDHC1_DIV);
- break;
- case 1:
- div = CRM_SMALL_DIVIDER(MXC_CRMAP_APRB, SDHC2_DIV);
- break;
- default:
- BUG();
- }
-
- return clk_get_rate(clk->parent) / div;
-}
-
-static int clk_sdhc_enable(struct clk *clk)
-{
- u32 amlpmre1, aprb;
-
- amlpmre1 = __raw_readl(MXC_CRMAP_AMLPMRE1);
- aprb = __raw_readl(MXC_CRMAP_APRB);
- switch (clk->id) {
- case 0:
- amlpmre1 |= (0x7 << MXC_CRMAP_AMLPMRE1_MLPME4_OFFSET);
- aprb |= (0x1 << MXC_CRMAP_APRB_SDHC1EN_OFFSET);
- break;
- case 1:
- amlpmre1 |= (0x7 << MXC_CRMAP_AMLPMRE1_MLPME5_OFFSET);
- aprb |= (0x1 << MXC_CRMAP_APRB_SDHC2EN_OFFSET);
- break;
- }
- __raw_writel(amlpmre1, MXC_CRMAP_AMLPMRE1);
- __raw_writel(aprb, MXC_CRMAP_APRB);
- return 0;
-}
-
-static void clk_sdhc_disable(struct clk *clk)
-{
- u32 amlpmre1, aprb;
-
- amlpmre1 = __raw_readl(MXC_CRMAP_AMLPMRE1);
- aprb = __raw_readl(MXC_CRMAP_APRB);
- switch (clk->id) {
- case 0:
- amlpmre1 &= ~(0x7 << MXC_CRMAP_AMLPMRE1_MLPME4_OFFSET);
- aprb &= ~(0x1 << MXC_CRMAP_APRB_SDHC1EN_OFFSET);
- break;
- case 1:
- amlpmre1 &= ~(0x7 << MXC_CRMAP_AMLPMRE1_MLPME5_OFFSET);
- aprb &= ~(0x1 << MXC_CRMAP_APRB_SDHC2EN_OFFSET);
- break;
- }
- __raw_writel(amlpmre1, MXC_CRMAP_AMLPMRE1);
- __raw_writel(aprb, MXC_CRMAP_APRB);
-}
-
-static struct clk sdhc_clk[] = {
- {
- .id = 0,
- .get_rate = clk_sdhc_get_rate,
- .enable = clk_sdhc_enable,
- .disable = clk_sdhc_disable,
- }, {
- .id = 1,
- .get_rate = clk_sdhc_get_rate,
- .enable = clk_sdhc_enable,
- .disable = clk_sdhc_disable,
- },
-};
-/* sdhc_clk stuff end */
-
-/* wdog_clk stuff */
-static struct clk wdog_clk[] = {
- {
- .id = 0,
- .parent = &ipg_clk,
- .enable_reg = MXC_CRMAP_AMLPMRD,
- .enable_shift = MXC_CRMAP_AMLPMRD_MLPMD7_OFFSET,
- .enable = _clk_3bit_enable,
- .disable = _clk_3bit_disable,
- }, {
- .id = 1,
- .parent = &ipg_clk,
- .enable_reg = MXC_CRMAP_AMLPMRD,
- .enable_shift = MXC_CRMAP_AMLPMRD_MLPMD3_OFFSET,
- .enable = _clk_3bit_enable,
- .disable = _clk_3bit_disable,
- },
-};
-/* wdog_clk stuff end */
-
-/* gpt_clk stuff */
-static struct clk gpt_clk = {
- .parent = &ipg_clk,
- .enable_reg = MXC_CRMAP_AMLPMRC,
- .enable_shift = MXC_CRMAP_AMLPMRC_MLPMC4_OFFSET,
- .enable = _clk_3bit_enable,
- .disable = _clk_3bit_disable,
-};
-/* gpt_clk stuff end */
-
-/* cspi_clk stuff */
-static struct clk cspi_clk[] = {
- {
- .id = 0,
- .parent = &ipg_clk,
- .enable_reg = MXC_CRMAP_AMLPMRE2,
- .enable_shift = MXC_CRMAP_AMLPMRE2_MLPME0_OFFSET,
- .enable = _clk_3bit_enable,
- .disable = _clk_3bit_disable,
- }, {
- .id = 1,
- .parent = &ipg_clk,
- .enable_reg = MXC_CRMAP_AMLPMRE1,
- .enable_shift = MXC_CRMAP_AMLPMRE1_MLPME6_OFFSET,
- .enable = _clk_3bit_enable,
- .disable = _clk_3bit_disable,
- },
-};
-/* cspi_clk stuff end */
-
-#define _REGISTER_CLOCK(d, n, c) \
- { \
- .dev_id = d, \
- .con_id = n, \
- .clk = &c, \
- },
-
-static struct clk_lookup lookups[] = {
- _REGISTER_CLOCK("imx-uart.0", NULL, uart_clk[0])
- _REGISTER_CLOCK("imx-uart.1", NULL, uart_clk[1])
- _REGISTER_CLOCK("imx-uart.2", NULL, uart_clk[2])
- _REGISTER_CLOCK("mxc-mmc.0", NULL, sdhc_clk[0])
- _REGISTER_CLOCK("mxc-mmc.1", NULL, sdhc_clk[1])
- _REGISTER_CLOCK("mxc-wdt.0", NULL, wdog_clk[0])
- _REGISTER_CLOCK("spi_imx.0", NULL, cspi_clk[0])
- _REGISTER_CLOCK("spi_imx.1", NULL, cspi_clk[1])
-};
-
-int __init mxc91231_clocks_init(unsigned long fref)
-{
- void __iomem *gpt_base;
-
- ckih_rate = fref;
-
- usb_clk.parent = clk_usb_parent(&usb_clk);
- sdhc_clk[0].parent = clk_sdhc_parent(&sdhc_clk[0]);
- sdhc_clk[1].parent = clk_sdhc_parent(&sdhc_clk[1]);
-
- clkdev_add_table(lookups, ARRAY_SIZE(lookups));
-
- gpt_base = MXC91231_IO_ADDRESS(MXC91231_GPT1_BASE_ADDR);
- mxc_timer_init(&gpt_clk, gpt_base, MXC91231_INT_GPT);
-
- return 0;
-}
diff --git a/arch/arm/mach-mxc91231/crm_regs.h b/arch/arm/mach-mxc91231/crm_regs.h
deleted file mode 100644
index b989baccd675..000000000000
--- a/arch/arm/mach-mxc91231/crm_regs.h
+++ /dev/null
@@ -1,394 +0,0 @@
-/*
- * Copyright 2006 Freescale Semiconductor, Inc.
- * Copyright 2006-2007 Motorola, 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.
- */
-
-#ifndef _ARCH_ARM_MACH_MXC91231_CRM_REGS_H_
-#define _ARCH_ARM_MACH_MXC91231_CRM_REGS_H_
-
-#define CKIL_CLK_FREQ 32768
-
-#define MXC_CRM_AP_BASE MXC91231_IO_ADDRESS(MXC91231_CRM_AP_BASE_ADDR)
-#define MXC_CRM_COM_BASE MXC91231_IO_ADDRESS(MXC91231_CRM_COM_BASE_ADDR)
-#define MXC_DSM_BASE MXC91231_IO_ADDRESS(MXC91231_DSM_BASE_ADDR)
-#define MXC_PLL0_BASE MXC91231_IO_ADDRESS(MXC91231_PLL0_BASE_ADDR)
-#define MXC_PLL1_BASE MXC91231_IO_ADDRESS(MXC91231_PLL1_BASE_ADDR)
-#define MXC_PLL2_BASE MXC91231_IO_ADDRESS(MXC91231_PLL2_BASE_ADDR)
-#define MXC_CLKCTL_BASE MXC91231_IO_ADDRESS(MXC91231_CLKCTL_BASE_ADDR)
-
-/* PLL Register Offsets */
-#define MXC_PLL_DP_CTL 0x00
-#define MXC_PLL_DP_CONFIG 0x04
-#define MXC_PLL_DP_OP 0x08
-#define MXC_PLL_DP_MFD 0x0C
-#define MXC_PLL_DP_MFN 0x10
-#define MXC_PLL_DP_HFS_OP 0x1C
-#define MXC_PLL_DP_HFS_MFD 0x20
-#define MXC_PLL_DP_HFS_MFN 0x24
-
-/* PLL Register Bit definitions */
-#define MXC_PLL_DP_CTL_DPDCK0_2_EN 0x1000
-#define MXC_PLL_DP_CTL_ADE 0x800
-#define MXC_PLL_DP_CTL_REF_CLK_DIV 0x400
-#define MXC_PLL_DP_CTL_HFSM 0x80
-#define MXC_PLL_DP_CTL_PRE 0x40
-#define MXC_PLL_DP_CTL_UPEN 0x20
-#define MXC_PLL_DP_CTL_RST 0x10
-#define MXC_PLL_DP_CTL_RCP 0x8
-#define MXC_PLL_DP_CTL_PLM 0x4
-#define MXC_PLL_DP_CTL_BRM0 0x2
-#define MXC_PLL_DP_CTL_LRF 0x1
-
-#define MXC_PLL_DP_OP_MFI_OFFSET 4
-#define MXC_PLL_DP_OP_MFI_MASK 0xF
-#define MXC_PLL_DP_OP_PDF_OFFSET 0
-#define MXC_PLL_DP_OP_PDF_MASK 0xF
-
-#define MXC_PLL_DP_MFD_OFFSET 0
-#define MXC_PLL_DP_MFD_MASK 0x7FFFFFF
-
-#define MXC_PLL_DP_MFN_OFFSET 0
-#define MXC_PLL_DP_MFN_MASK 0x7FFFFFF
-
-/* CRM AP Register Offsets */
-#define MXC_CRMAP_ASCSR (MXC_CRM_AP_BASE + 0x00)
-#define MXC_CRMAP_ACDR (MXC_CRM_AP_BASE + 0x04)
-#define MXC_CRMAP_ACDER1 (MXC_CRM_AP_BASE + 0x08)
-#define MXC_CRMAP_ACDER2 (MXC_CRM_AP_BASE + 0x0C)
-#define MXC_CRMAP_ACGCR (MXC_CRM_AP_BASE + 0x10)
-#define MXC_CRMAP_ACCGCR (MXC_CRM_AP_BASE + 0x14)
-#define MXC_CRMAP_AMLPMRA (MXC_CRM_AP_BASE + 0x18)
-#define MXC_CRMAP_AMLPMRB (MXC_CRM_AP_BASE + 0x1C)
-#define MXC_CRMAP_AMLPMRC (MXC_CRM_AP_BASE + 0x20)
-#define MXC_CRMAP_AMLPMRD (MXC_CRM_AP_BASE + 0x24)
-#define MXC_CRMAP_AMLPMRE1 (MXC_CRM_AP_BASE + 0x28)
-#define MXC_CRMAP_AMLPMRE2 (MXC_CRM_AP_BASE + 0x2C)
-#define MXC_CRMAP_AMLPMRF (MXC_CRM_AP_BASE + 0x30)
-#define MXC_CRMAP_AMLPMRG (MXC_CRM_AP_BASE + 0x34)
-#define MXC_CRMAP_APGCR (MXC_CRM_AP_BASE + 0x38)
-#define MXC_CRMAP_ACSR (MXC_CRM_AP_BASE + 0x3C)
-#define MXC_CRMAP_ADCR (MXC_CRM_AP_BASE + 0x40)
-#define MXC_CRMAP_ACR (MXC_CRM_AP_BASE + 0x44)
-#define MXC_CRMAP_AMCR (MXC_CRM_AP_BASE + 0x48)
-#define MXC_CRMAP_APCR (MXC_CRM_AP_BASE + 0x4C)
-#define MXC_CRMAP_AMORA (MXC_CRM_AP_BASE + 0x50)
-#define MXC_CRMAP_AMORB (MXC_CRM_AP_BASE + 0x54)
-#define MXC_CRMAP_AGPR (MXC_CRM_AP_BASE + 0x58)
-#define MXC_CRMAP_APRA (MXC_CRM_AP_BASE + 0x5C)
-#define MXC_CRMAP_APRB (MXC_CRM_AP_BASE + 0x60)
-#define MXC_CRMAP_APOR (MXC_CRM_AP_BASE + 0x64)
-#define MXC_CRMAP_ADFMR (MXC_CRM_AP_BASE + 0x68)
-
-/* CRM AP Register Bit definitions */
-#define MXC_CRMAP_ASCSR_CRS 0x10000
-#define MXC_CRMAP_ASCSR_AP_PATDIV2_OFFSET 15
-#define MXC_CRMAP_ASCSR_AP_PATREF_DIV2 0x8000
-#define MXC_CRMAP_ASCSR_USBSEL_OFFSET 13
-#define MXC_CRMAP_ASCSR_USBSEL_MASK (0x3 << 13)
-#define MXC_CRMAP_ASCSR_CSISEL_OFFSET 11
-#define MXC_CRMAP_ASCSR_CSISEL_MASK (0x3 << 11)
-#define MXC_CRMAP_ASCSR_SSI2SEL_OFFSET 7
-#define MXC_CRMAP_ASCSR_SSI2SEL_MASK (0x3 << 7)
-#define MXC_CRMAP_ASCSR_SSI1SEL_OFFSET 5
-#define MXC_CRMAP_ASCSR_SSI1SEL_MASK (0x3 << 5)
-#define MXC_CRMAP_ASCSR_APSEL_OFFSET 3
-#define MXC_CRMAP_ASCSR_APSEL_MASK (0x3 << 3)
-#define MXC_CRMAP_ASCSR_AP_PATDIV1_OFFSET 2
-#define MXC_CRMAP_ASCSR_AP_PATREF_DIV1 0x4
-#define MXC_CRMAP_ASCSR_APISEL 0x1
-
-#define MXC_CRMAP_ACDR_ARMDIV_OFFSET 8
-#define MXC_CRMAP_ACDR_ARMDIV_MASK (0xF << 8)
-#define MXC_CRMAP_ACDR_AHBDIV_OFFSET 4
-#define MXC_CRMAP_ACDR_AHBDIV_MASK (0xF << 4)
-#define MXC_CRMAP_ACDR_IPDIV_OFFSET 0
-#define MXC_CRMAP_ACDR_IPDIV_MASK 0xF
-
-#define MXC_CRMAP_ACDER1_CSIEN_OFFSET 30
-#define MXC_CRMAP_ACDER1_CSIDIV_OFFSET 24
-#define MXC_CRMAP_ACDER1_CSIDIV_MASK (0x3F << 24)
-#define MXC_CRMAP_ACDER1_SSI2EN_OFFSET 14
-#define MXC_CRMAP_ACDER1_SSI2DIV_OFFSET 8
-#define MXC_CRMAP_ACDER1_SSI2DIV_MASK (0x3F << 8)
-#define MXC_CRMAP_ACDER1_SSI1EN_OFFSET 6
-#define MXC_CRMAP_ACDER1_SSI1DIV_OFFSET 0
-#define MXC_CRMAP_ACDER1_SSI1DIV_MASK 0x3F
-
-#define MXC_CRMAP_ACDER2_CRCT_CLK_DIV_OFFSET 24
-#define MXC_CRMAP_ACDER2_CRCT_CLK_DIV_MASK (0x7 << 24)
-#define MXC_CRMAP_ACDER2_NFCEN_OFFSET 20
-#define MXC_CRMAP_ACDER2_NFCDIV_OFFSET 16
-#define MXC_CRMAP_ACDER2_NFCDIV_MASK (0xF << 16)
-#define MXC_CRMAP_ACDER2_USBEN_OFFSET 12
-#define MXC_CRMAP_ACDER2_USBDIV_OFFSET 8
-#define MXC_CRMAP_ACDER2_USBDIV_MASK (0xF << 8)
-#define MXC_CRMAP_ACDER2_BAUD_ISEL_OFFSET 5
-#define MXC_CRMAP_ACDER2_BAUD_ISEL_MASK (0x3 << 5)
-#define MXC_CRMAP_ACDER2_BAUDDIV_OFFSET 0
-#define MXC_CRMAP_ACDER2_BAUDDIV_MASK 0xF
-
-#define MXC_CRMAP_AMLPMRA_MLPMA7_OFFSET 22
-#define MXC_CRMAP_AMLPMRA_MLPMA7_MASK (0x7 << 22)
-#define MXC_CRMAP_AMLPMRA_MLPMA6_OFFSET 19
-#define MXC_CRMAP_AMLPMRA_MLPMA6_MASK (0x7 << 19)
-#define MXC_CRMAP_AMLPMRA_MLPMA4_OFFSET 12
-#define MXC_CRMAP_AMLPMRA_MLPMA4_MASK (0x7 << 12)
-#define MXC_CRMAP_AMLPMRA_MLPMA3_OFFSET 9
-#define MXC_CRMAP_AMLPMRA_MLPMA3_MASK (0x7 << 9)
-#define MXC_CRMAP_AMLPMRA_MLPMA2_OFFSET 6
-#define MXC_CRMAP_AMLPMRA_MLPMA2_MASK (0x7 << 6)
-#define MXC_CRMAP_AMLPMRA_MLPMA1_OFFSET 3
-#define MXC_CRMAP_AMLPMRA_MLPMA1_MASK (0x7 << 3)
-
-#define MXC_CRMAP_AMLPMRB_MLPMB0_OFFSET 0
-#define MXC_CRMAP_AMLPMRB_MLPMB0_MASK 0x7
-
-#define MXC_CRMAP_AMLPMRC_MLPMC9_OFFSET 28
-#define MXC_CRMAP_AMLPMRC_MLPMC9_MASK (0x7 << 28)
-#define MXC_CRMAP_AMLPMRC_MLPMC7_OFFSET 22
-#define MXC_CRMAP_AMLPMRC_MLPMC7_MASK (0x7 << 22)
-#define MXC_CRMAP_AMLPMRC_MLPMC5_OFFSET 16
-#define MXC_CRMAP_AMLPMRC_MLPMC5_MASK (0x7 << 16)
-#define MXC_CRMAP_AMLPMRC_MLPMC4_OFFSET 12
-#define MXC_CRMAP_AMLPMRC_MLPMC4_MASK (0x7 << 12)
-#define MXC_CRMAP_AMLPMRC_MLPMC3_OFFSET 9
-#define MXC_CRMAP_AMLPMRC_MLPMC3_MASK (0x7 << 9)
-#define MXC_CRMAP_AMLPMRC_MLPMC2_OFFSET 6
-#define MXC_CRMAP_AMLPMRC_MLPMC2_MASK (0x7 << 6)
-#define MXC_CRMAP_AMLPMRC_MLPMC1_OFFSET 3
-#define MXC_CRMAP_AMLPMRC_MLPMC1_MASK (0x7 << 3)
-#define MXC_CRMAP_AMLPMRC_MLPMC0_OFFSET 0
-#define MXC_CRMAP_AMLPMRC_MLPMC0_MASK 0x7
-
-#define MXC_CRMAP_AMLPMRD_MLPMD7_OFFSET 22
-#define MXC_CRMAP_AMLPMRD_MLPMD7_MASK (0x7 << 22)
-#define MXC_CRMAP_AMLPMRD_MLPMD4_OFFSET 12
-#define MXC_CRMAP_AMLPMRD_MLPMD4_MASK (0x7 << 12)
-#define MXC_CRMAP_AMLPMRD_MLPMD3_OFFSET 9
-#define MXC_CRMAP_AMLPMRD_MLPMD3_MASK (0x7 << 9)
-#define MXC_CRMAP_AMLPMRD_MLPMD2_OFFSET 6
-#define MXC_CRMAP_AMLPMRD_MLPMD2_MASK (0x7 << 6)
-#define MXC_CRMAP_AMLPMRD_MLPMD0_OFFSET 0
-#define MXC_CRMAP_AMLPMRD_MLPMD0_MASK 0x7
-
-#define MXC_CRMAP_AMLPMRE1_MLPME9_OFFSET 28
-#define MXC_CRMAP_AMLPMRE1_MLPME9_MASK (0x7 << 28)
-#define MXC_CRMAP_AMLPMRE1_MLPME8_OFFSET 25
-#define MXC_CRMAP_AMLPMRE1_MLPME8_MASK (0x7 << 25)
-#define MXC_CRMAP_AMLPMRE1_MLPME7_OFFSET 22
-#define MXC_CRMAP_AMLPMRE1_MLPME7_MASK (0x7 << 22)
-#define MXC_CRMAP_AMLPMRE1_MLPME6_OFFSET 19
-#define MXC_CRMAP_AMLPMRE1_MLPME6_MASK (0x7 << 19)
-#define MXC_CRMAP_AMLPMRE1_MLPME5_OFFSET 16
-#define MXC_CRMAP_AMLPMRE1_MLPME5_MASK (0x7 << 16)
-#define MXC_CRMAP_AMLPMRE1_MLPME4_OFFSET 12
-#define MXC_CRMAP_AMLPMRE1_MLPME4_MASK (0x7 << 12)
-#define MXC_CRMAP_AMLPMRE1_MLPME3_OFFSET 9
-#define MXC_CRMAP_AMLPMRE1_MLPME3_MASK (0x7 << 9)
-#define MXC_CRMAP_AMLPMRE1_MLPME2_OFFSET 6
-#define MXC_CRMAP_AMLPMRE1_MLPME2_MASK (0x7 << 6)
-#define MXC_CRMAP_AMLPMRE1_MLPME1_OFFSET 3
-#define MXC_CRMAP_AMLPMRE1_MLPME1_MASK (0x7 << 3)
-#define MXC_CRMAP_AMLPMRE1_MLPME0_OFFSET 0
-#define MXC_CRMAP_AMLPMRE1_MLPME0_MASK 0x7
-
-#define MXC_CRMAP_AMLPMRE2_MLPME0_OFFSET 0
-#define MXC_CRMAP_AMLPMRE2_MLPME0_MASK 0x7
-
-#define MXC_CRMAP_AMLPMRF_MLPMF6_OFFSET 19
-#define MXC_CRMAP_AMLPMRF_MLPMF6_MASK (0x7 << 19)
-#define MXC_CRMAP_AMLPMRF_MLPMF5_OFFSET 16
-#define MXC_CRMAP_AMLPMRF_MLPMF5_MASK (0x7 << 16)
-#define MXC_CRMAP_AMLPMRF_MLPMF3_OFFSET 9
-#define MXC_CRMAP_AMLPMRF_MLPMF3_MASK (0x7 << 9)
-#define MXC_CRMAP_AMLPMRF_MLPMF2_OFFSET 6
-#define MXC_CRMAP_AMLPMRF_MLPMF2_MASK (0x7 << 6)
-#define MXC_CRMAP_AMLPMRF_MLPMF1_OFFSET 3
-#define MXC_CRMAP_AMLPMRF_MLPMF1_MASK (0x7 << 3)
-#define MXC_CRMAP_AMLPMRF_MLPMF0_OFFSET 0
-#define MXC_CRMAP_AMLPMRF_MLPMF0_MASK (0x7 << 0)
-
-#define MXC_CRMAP_AMLPMRG_MLPMG9_OFFSET 28
-#define MXC_CRMAP_AMLPMRG_MLPMG9_MASK (0x7 << 28)
-#define MXC_CRMAP_AMLPMRG_MLPMG7_OFFSET 22
-#define MXC_CRMAP_AMLPMRG_MLPMG7_MASK (0x7 << 22)
-#define MXC_CRMAP_AMLPMRG_MLPMG6_OFFSET 19
-#define MXC_CRMAP_AMLPMRG_MLPMG6_MASK (0x7 << 19)
-#define MXC_CRMAP_AMLPMRG_MLPMG5_OFFSET 16
-#define MXC_CRMAP_AMLPMRG_MLPMG5_MASK (0x7 << 16)
-#define MXC_CRMAP_AMLPMRG_MLPMG4_OFFSET 12
-#define MXC_CRMAP_AMLPMRG_MLPMG4_MASK (0x7 << 12)
-#define MXC_CRMAP_AMLPMRG_MLPMG3_OFFSET 9
-#define MXC_CRMAP_AMLPMRG_MLPMG3_MASK (0x7 << 9)
-#define MXC_CRMAP_AMLPMRG_MLPMG2_OFFSET 6
-#define MXC_CRMAP_AMLPMRG_MLPMG2_MASK (0x7 << 6)
-#define MXC_CRMAP_AMLPMRG_MLPMG1_OFFSET 3
-#define MXC_CRMAP_AMLPMRG_MLPMG1_MASK (0x7 << 3)
-#define MXC_CRMAP_AMLPMRG_MLPMG0_OFFSET 0
-#define MXC_CRMAP_AMLPMRG_MLPMG0_MASK 0x7
-
-#define MXC_CRMAP_AGPR_IPUPAD_OFFSET 20
-#define MXC_CRMAP_AGPR_IPUPAD_MASK (0x7 << 20)
-
-#define MXC_CRMAP_APRA_EL1TEN_OFFSET 29
-#define MXC_CRMAP_APRA_SIMEN_OFFSET 24
-#define MXC_CRMAP_APRA_UART3DIV_OFFSET 17
-#define MXC_CRMAP_APRA_UART3DIV_MASK (0xF << 17)
-#define MXC_CRMAP_APRA_UART3EN_OFFSET 16
-#define MXC_CRMAP_APRA_SAHARA_DIV2_CLKEN_OFFSET 14
-#define MXC_CRMAP_APRA_MQSPIEN_OFFSET 13
-#define MXC_CRMAP_APRA_UART2EN_OFFSET 8
-#define MXC_CRMAP_APRA_UART1EN_OFFSET 0
-
-#define MXC_CRMAP_APRB_SDHC2_ISEL_OFFSET 13
-#define MXC_CRMAP_APRB_SDHC2_ISEL_MASK (0x7 << 13)
-#define MXC_CRMAP_APRB_SDHC2_DIV_OFFSET 9
-#define MXC_CRMAP_APRB_SDHC2_DIV_MASK (0xF << 9)
-#define MXC_CRMAP_APRB_SDHC2EN_OFFSET 8
-#define MXC_CRMAP_APRB_SDHC1_ISEL_OFFSET 5
-#define MXC_CRMAP_APRB_SDHC1_ISEL_MASK (0x7 << 5)
-#define MXC_CRMAP_APRB_SDHC1_DIV_OFFSET 1
-#define MXC_CRMAP_APRB_SDHC1_DIV_MASK (0xF << 1)
-#define MXC_CRMAP_APRB_SDHC1EN_OFFSET 0
-
-#define MXC_CRMAP_ACSR_ADS_OFFSET 8
-#define MXC_CRMAP_ACSR_ADS (0x1 << 8)
-#define MXC_CRMAP_ACSR_ACS 0x1
-
-#define MXC_CRMAP_ADCR_LFDF_0 (0x0 << 8)
-#define MXC_CRMAP_ADCR_LFDF_2 (0x1 << 8)
-#define MXC_CRMAP_ADCR_LFDF_4 (0x2 << 8)
-#define MXC_CRMAP_ADCR_LFDF_8 (0x3 << 8)
-#define MXC_CRMAP_ADCR_LFDF_OFFSET 8
-#define MXC_CRMAP_ADCR_LFDF_MASK (0x3 << 8)
-#define MXC_CRMAP_ADCR_ALT_PLL 0x80
-#define MXC_CRMAP_ADCR_DFS_DIVEN 0x20
-#define MXC_CRMAP_ADCR_DIV_BYP 0x2
-#define MXC_CRMAP_ADCR_VSTAT 0x8
-#define MXC_CRMAP_ADCR_TSTAT 0x10
-#define MXC_CRMAP_ADCR_DVFS_VCTRL 0x10
-#define MXC_CRMAP_ADCR_CLK_ON 0x40
-
-#define MXC_CRMAP_ADFMR_FC_OFFSET 16
-#define MXC_CRMAP_ADFMR_FC_MASK (0x1F << 16)
-#define MXC_CRMAP_ADFMR_MF_OFFSET 1
-#define MXC_CRMAP_ADFMR_MF_MASK (0x3FF << 1)
-#define MXC_CRMAP_ADFMR_DFM_CLK_READY 0x1
-#define MXC_CRMAP_ADFMR_DFM_PWR_DOWN 0x8000
-
-#define MXC_CRMAP_ACR_CKOHS_HIGH (1 << 18)
-#define MXC_CRMAP_ACR_CKOS_HIGH (1 << 16)
-#define MXC_CRMAP_ACR_CKOHS_MASK (0x7 << 12)
-#define MXC_CRMAP_ACR_CKOHD (1 << 11)
-#define MXC_CRMAP_ACR_CKOHDIV_MASK (0xF << 8)
-#define MXC_CRMAP_ACR_CKOHDIV_OFFSET 8
-#define MXC_CRMAP_ACR_CKOD (1 << 7)
-#define MXC_CRMAP_ACR_CKOS_MASK (0x7 << 4)
-
-/* AP Warm reset */
-#define MXC_CRMAP_AMCR_SW_AP (1 << 14)
-
-/* Bit definitions of ACGCR in CRM_AP for tree level clock gating */
-#define MXC_CRMAP_ACGCR_ACG0_STOP_WAIT 0x00000001
-#define MXC_CRMAP_ACGCR_ACG0_STOP 0x00000003
-#define MXC_CRMAP_ACGCR_ACG0_RUN 0x00000007
-#define MXC_CRMAP_ACGCR_ACG0_DISABLED 0x00000000
-
-#define MXC_CRMAP_ACGCR_ACG1_STOP_WAIT 0x00000008
-#define MXC_CRMAP_ACGCR_ACG1_STOP 0x00000018
-#define MXC_CRMAP_ACGCR_ACG1_RUN 0x00000038
-#define MXC_CRMAP_ACGCR_ACG1_DISABLED 0x00000000
-
-#define MXC_CRMAP_ACGCR_ACG2_STOP_WAIT 0x00000040
-#define MXC_CRMAP_ACGCR_ACG2_STOP 0x000000C0
-#define MXC_CRMAP_ACGCR_ACG2_RUN 0x000001C0
-#define MXC_CRMAP_ACGCR_ACG2_DISABLED 0x00000000
-
-#define MXC_CRMAP_ACGCR_ACG3_STOP_WAIT 0x00000200
-#define MXC_CRMAP_ACGCR_ACG3_STOP 0x00000600
-#define MXC_CRMAP_ACGCR_ACG3_RUN 0x00000E00
-#define MXC_CRMAP_ACGCR_ACG3_DISABLED 0x00000000
-
-#define MXC_CRMAP_ACGCR_ACG4_STOP_WAIT 0x00001000
-#define MXC_CRMAP_ACGCR_ACG4_STOP 0x00003000
-#define MXC_CRMAP_ACGCR_ACG4_RUN 0x00007000
-#define MXC_CRMAP_ACGCR_ACG4_DISABLED 0x00000000
-
-#define MXC_CRMAP_ACGCR_ACG5_STOP_WAIT 0x00010000
-#define MXC_CRMAP_ACGCR_ACG5_STOP 0x00030000
-#define MXC_CRMAP_ACGCR_ACG5_RUN 0x00070000
-#define MXC_CRMAP_ACGCR_ACG5_DISABLED 0x00000000
-
-#define MXC_CRMAP_ACGCR_ACG6_STOP_WAIT 0x00080000
-#define MXC_CRMAP_ACGCR_ACG6_STOP 0x00180000
-#define MXC_CRMAP_ACGCR_ACG6_RUN 0x00380000
-#define MXC_CRMAP_ACGCR_ACG6_DISABLED 0x00000000
-
-#define NUM_GATE_CTRL 6
-
-/* CRM COM Register Offsets */
-#define MXC_CRMCOM_CSCR (MXC_CRM_COM_BASE + 0x0C)
-#define MXC_CRMCOM_CCCR (MXC_CRM_COM_BASE + 0x10)
-
-/* CRM COM Bit Definitions */
-#define MXC_CRMCOM_CSCR_PPD1 0x08000000
-#define MXC_CRMCOM_CSCR_CKOHSEL (1 << 18)
-#define MXC_CRMCOM_CSCR_CKOSEL (1 << 17)
-#define MXC_CRMCOM_CCCR_CC_DIV_OFFSET 8
-#define MXC_CRMCOM_CCCR_CC_DIV_MASK (0x1F << 8)
-#define MXC_CRMCOM_CCCR_CC_SEL_OFFSET 0
-#define MXC_CRMCOM_CCCR_CC_SEL_MASK 0x3
-
-/* DSM Register Offsets */
-#define MXC_DSM_SLEEP_TIME (MXC_DSM_BASE + 0x0c)
-#define MXC_DSM_CONTROL0 (MXC_DSM_BASE + 0x20)
-#define MXC_DSM_CONTROL1 (MXC_DSM_BASE + 0x24)
-#define MXC_DSM_CTREN (MXC_DSM_BASE + 0x28)
-#define MXC_DSM_WARM_PER (MXC_DSM_BASE + 0x40)
-#define MXC_DSM_LOCK_PER (MXC_DSM_BASE + 0x44)
-#define MXC_DSM_MGPER (MXC_DSM_BASE + 0x4c)
-#define MXC_DSM_CRM_CONTROL (MXC_DSM_BASE + 0x50)
-
-/* Bit definitions of various registers in DSM */
-#define MXC_DSM_CRM_CTRL_DVFS_BYP 0x00000008
-#define MXC_DSM_CRM_CTRL_DVFS_VCTRL 0x00000004
-#define MXC_DSM_CRM_CTRL_LPMD1 0x00000002
-#define MXC_DSM_CRM_CTRL_LPMD0 0x00000001
-#define MXC_DSM_CRM_CTRL_LPMD_STOP_MODE 0x00000000
-#define MXC_DSM_CRM_CTRL_LPMD_WAIT_MODE 0x00000001
-#define MXC_DSM_CRM_CTRL_LPMD_RUN_MODE 0x00000003
-#define MXC_DSM_CONTROL0_STBY_COMMIT_EN 0x00000200
-#define MXC_DSM_CONTROL0_MSTR_EN 0x00000001
-#define MXC_DSM_CONTROL0_RESTART 0x00000010
-/* Counter Block reset */
-#define MXC_DSM_CONTROL1_CB_RST 0x00000002
-/* State Machine reset */
-#define MXC_DSM_CONTROL1_SM_RST 0x00000004
-/* Bit needed to reset counter block */
-#define MXC_CONTROL1_RST_CNT32 0x00000008
-#define MXC_DSM_CONTROL1_RST_CNT32_EN 0x00000800
-#define MXC_DSM_CONTROL1_SLEEP 0x00000100
-#define MXC_DSM_CONTROL1_WAKEUP_DISABLE 0x00004000
-#define MXC_DSM_CTREN_CNT32 0x00000001
-
-/* Magic Fix enable bit */
-#define MXC_DSM_MGPER_EN_MGFX 0x80000000
-#define MXC_DSM_MGPER_PER_MASK 0x000003FF
-#define MXC_DSM_MGPER_PER(n) (MXC_DSM_MGPER_PER_MASK & n)
-
-/* Address offsets of the CLKCTL registers */
-#define MXC_CLKCTL_GP_CTRL (MXC_CLKCTL_BASE + 0x00)
-#define MXC_CLKCTL_GP_SER (MXC_CLKCTL_BASE + 0x04)
-#define MXC_CLKCTL_GP_CER (MXC_CLKCTL_BASE + 0x08)
-
-#endif /* _ARCH_ARM_MACH_MXC91231_CRM_REGS_H_ */
diff --git a/arch/arm/mach-mxc91231/devices.c b/arch/arm/mach-mxc91231/devices.c
deleted file mode 100644
index 027af4f0d18a..000000000000
--- a/arch/arm/mach-mxc91231/devices.c
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright 2006-2007 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Sascha Hauer, kernel@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.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You 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/platform_device.h>
-#include <linux/serial.h>
-#include <linux/gpio.h>
-#include <mach/hardware.h>
-#include <mach/irqs.h>
-#include <mach/imx-uart.h>
-
-static struct resource uart0[] = {
- {
- .start = MXC91231_UART1_BASE_ADDR,
- .end = MXC91231_UART1_BASE_ADDR + 0x0B5,
- .flags = IORESOURCE_MEM,
- }, {
- .start = MXC91231_INT_UART1_RX,
- .end = MXC91231_INT_UART1_RX,
- .flags = IORESOURCE_IRQ,
- }, {
- .start = MXC91231_INT_UART1_TX,
- .end = MXC91231_INT_UART1_TX,
- .flags = IORESOURCE_IRQ,
- }, {
- .start = MXC91231_INT_UART1_MINT,
- .end = MXC91231_INT_UART1_MINT,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-struct platform_device mxc_uart_device0 = {
- .name = "imx-uart",
- .id = 0,
- .resource = uart0,
- .num_resources = ARRAY_SIZE(uart0),
-};
-
-static struct resource uart1[] = {
- {
- .start = MXC91231_UART2_BASE_ADDR,
- .end = MXC91231_UART2_BASE_ADDR + 0x0B5,
- .flags = IORESOURCE_MEM,
- }, {
- .start = MXC91231_INT_UART2_RX,
- .end = MXC91231_INT_UART2_RX,
- .flags = IORESOURCE_IRQ,
- }, {
- .start = MXC91231_INT_UART2_TX,
- .end = MXC91231_INT_UART2_TX,
- .flags = IORESOURCE_IRQ,
- }, {
- .start = MXC91231_INT_UART2_MINT,
- .end = MXC91231_INT_UART2_MINT,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-struct platform_device mxc_uart_device1 = {
- .name = "imx-uart",
- .id = 1,
- .resource = uart1,
- .num_resources = ARRAY_SIZE(uart1),
-};
-
-static struct resource uart2[] = {
- {
- .start = MXC91231_UART3_BASE_ADDR,
- .end = MXC91231_UART3_BASE_ADDR + 0x0B5,
- .flags = IORESOURCE_MEM,
- }, {
- .start = MXC91231_INT_UART3_RX,
- .end = MXC91231_INT_UART3_RX,
- .flags = IORESOURCE_IRQ,
- }, {
- .start = MXC91231_INT_UART3_TX,
- .end = MXC91231_INT_UART3_TX,
- .flags = IORESOURCE_IRQ,
- }, {
- .start = MXC91231_INT_UART3_MINT,
- .end = MXC91231_INT_UART3_MINT,
- .flags = IORESOURCE_IRQ,
-
- },
-};
-
-struct platform_device mxc_uart_device2 = {
- .name = "imx-uart",
- .id = 2,
- .resource = uart2,
- .num_resources = ARRAY_SIZE(uart2),
-};
-
-/* GPIO port description */
-static struct mxc_gpio_port mxc_gpio_ports[] = {
- [0] = {
- .chip.label = "gpio-0",
- .base = MXC91231_IO_ADDRESS(MXC91231_GPIO1_AP_BASE_ADDR),
- .irq = MXC91231_INT_GPIO1,
- .virtual_irq_start = MXC_GPIO_IRQ_START,
- },
- [1] = {
- .chip.label = "gpio-1",
- .base = MXC91231_IO_ADDRESS(MXC91231_GPIO2_AP_BASE_ADDR),
- .irq = MXC91231_INT_GPIO2,
- .virtual_irq_start = MXC_GPIO_IRQ_START + 32,
- },
- [2] = {
- .chip.label = "gpio-2",
- .base = MXC91231_IO_ADDRESS(MXC91231_GPIO3_AP_BASE_ADDR),
- .irq = MXC91231_INT_GPIO3,
- .virtual_irq_start = MXC_GPIO_IRQ_START + 64,
- },
- [3] = {
- .chip.label = "gpio-3",
- .base = MXC91231_IO_ADDRESS(MXC91231_GPIO4_SH_BASE_ADDR),
- .irq = MXC91231_INT_GPIO4,
- .virtual_irq_start = MXC_GPIO_IRQ_START + 96,
- },
-};
-
-int __init mxc91231_register_gpios(void)
-{
- return mxc_gpio_init(mxc_gpio_ports, ARRAY_SIZE(mxc_gpio_ports));
-}
-
-static struct resource mxc_nand_resources[] = {
- {
- .start = MXC91231_NFC_BASE_ADDR,
- .end = MXC91231_NFC_BASE_ADDR + 0xfff,
- .flags = IORESOURCE_MEM
- }, {
- .start = MXC91231_INT_NANDFC,
- .end = MXC91231_INT_NANDFC,
- .flags = IORESOURCE_IRQ
- },
-};
-
-struct platform_device mxc_nand_device = {
- .name = "mxc_nand",
- .id = 0,
- .num_resources = ARRAY_SIZE(mxc_nand_resources),
- .resource = mxc_nand_resources,
-};
-
-static struct resource mxc_sdhc0_resources[] = {
- {
- .start = MXC91231_MMC_SDHC1_BASE_ADDR,
- .end = MXC91231_MMC_SDHC1_BASE_ADDR + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = MXC91231_INT_MMC_SDHC1,
- .end = MXC91231_INT_MMC_SDHC1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct resource mxc_sdhc1_resources[] = {
- {
- .start = MXC91231_MMC_SDHC2_BASE_ADDR,
- .end = MXC91231_MMC_SDHC2_BASE_ADDR + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = MXC91231_INT_MMC_SDHC2,
- .end = MXC91231_INT_MMC_SDHC2,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-struct platform_device mxc_sdhc_device0 = {
- .name = "mxc-mmc",
- .id = 0,
- .num_resources = ARRAY_SIZE(mxc_sdhc0_resources),
- .resource = mxc_sdhc0_resources,
-};
-
-struct platform_device mxc_sdhc_device1 = {
- .name = "mxc-mmc",
- .id = 1,
- .num_resources = ARRAY_SIZE(mxc_sdhc1_resources),
- .resource = mxc_sdhc1_resources,
-};
-
-static struct resource mxc_cspi0_resources[] = {
- {
- .start = MXC91231_CSPI1_BASE_ADDR,
- .end = MXC91231_CSPI1_BASE_ADDR + 0x20,
- .flags = IORESOURCE_MEM,
- }, {
- .start = MXC91231_INT_CSPI1,
- .end = MXC91231_INT_CSPI1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-struct platform_device mxc_cspi_device0 = {
- .name = "spi_imx",
- .id = 0,
- .num_resources = ARRAY_SIZE(mxc_cspi0_resources),
- .resource = mxc_cspi0_resources,
-};
-
-static struct resource mxc_cspi1_resources[] = {
- {
- .start = MXC91231_CSPI2_BASE_ADDR,
- .end = MXC91231_CSPI2_BASE_ADDR + 0x20,
- .flags = IORESOURCE_MEM,
- }, {
- .start = MXC91231_INT_CSPI2,
- .end = MXC91231_INT_CSPI2,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-struct platform_device mxc_cspi_device1 = {
- .name = "spi_imx",
- .id = 1,
- .num_resources = ARRAY_SIZE(mxc_cspi1_resources),
- .resource = mxc_cspi1_resources,
-};
-
-static struct resource mxc_wdog0_resources[] = {
- {
- .start = MXC91231_WDOG1_BASE_ADDR,
- .end = MXC91231_WDOG1_BASE_ADDR + 0x10,
- .flags = IORESOURCE_MEM,
- },
-};
-
-struct platform_device mxc_wdog_device0 = {
- .name = "mxc-wdt",
- .id = 0,
- .num_resources = ARRAY_SIZE(mxc_wdog0_resources),
- .resource = mxc_wdog0_resources,
-};
diff --git a/arch/arm/mach-mxc91231/devices.h b/arch/arm/mach-mxc91231/devices.h
deleted file mode 100644
index 72a2136ce27d..000000000000
--- a/arch/arm/mach-mxc91231/devices.h
+++ /dev/null
@@ -1,13 +0,0 @@
-extern struct platform_device mxc_uart_device0;
-extern struct platform_device mxc_uart_device1;
-extern struct platform_device mxc_uart_device2;
-
-extern struct platform_device mxc_nand_device;
-
-extern struct platform_device mxc_sdhc_device0;
-extern struct platform_device mxc_sdhc_device1;
-
-extern struct platform_device mxc_cspi_device0;
-extern struct platform_device mxc_cspi_device1;
-
-extern struct platform_device mxc_wdog_device0;
diff --git a/arch/arm/mach-mxc91231/iomux.c b/arch/arm/mach-mxc91231/iomux.c
deleted file mode 100644
index 66fc41cbf2ca..000000000000
--- a/arch/arm/mach-mxc91231/iomux.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright (C) 2008 by Sascha Hauer <kernel@pengutronix.de>
- * Copyright (C) 2009 by Valentin Longchamp <valentin.longchamp@epfl.ch>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA.
- */
-
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <mach/hardware.h>
-#include <mach/gpio.h>
-#include <mach/iomux-mxc91231.h>
-
-/*
- * IOMUX register (base) addresses
- */
-#define IOMUX_AP_BASE MXC91231_IO_ADDRESS(MXC91231_IOMUX_AP_BASE_ADDR)
-#define IOMUX_COM_BASE MXC91231_IO_ADDRESS(MXC91231_IOMUX_COM_BASE_ADDR)
-#define IOMUXSW_AP_MUX_CTL (IOMUX_AP_BASE + 0x000)
-#define IOMUXSW_SP_MUX_CTL (IOMUX_COM_BASE + 0x000)
-#define IOMUXSW_PAD_CTL (IOMUX_COM_BASE + 0x200)
-
-#define IOMUXINT_OBS1 (IOMUX_AP_BASE + 0x600)
-#define IOMUXINT_OBS2 (IOMUX_AP_BASE + 0x004)
-
-static DEFINE_SPINLOCK(gpio_mux_lock);
-
-#define NB_PORTS ((PIN_MAX + 32) / 32)
-#define PIN_GLOBAL_NUM(pin) \
- (((pin & MUX_SIDE_MASK) >> MUX_SIDE_SHIFT)*PIN_AP_MAX + \
- ((pin & MUX_REG_MASK) >> MUX_REG_SHIFT)*4 + \
- ((pin & MUX_FIELD_MASK) >> MUX_FIELD_SHIFT))
-
-unsigned long mxc_pin_alloc_map[NB_PORTS * 32 / BITS_PER_LONG];
-/*
- * set the mode for a IOMUX pin.
- */
-int mxc_iomux_mode(unsigned int pin_mode)
-{
- u32 side, field, l, mode, ret = 0;
- void __iomem *reg;
-
- side = (pin_mode & MUX_SIDE_MASK) >> MUX_SIDE_SHIFT;
- switch (side) {
- case MUX_SIDE_AP:
- reg = IOMUXSW_AP_MUX_CTL;
- break;
- case MUX_SIDE_SP:
- reg = IOMUXSW_SP_MUX_CTL;
- break;
- default:
- return -EINVAL;
- }
- reg += ((pin_mode & MUX_REG_MASK) >> MUX_REG_SHIFT) * 4;
- field = (pin_mode & MUX_FIELD_MASK) >> MUX_FIELD_SHIFT;
- mode = (pin_mode & MUX_MODE_MASK) >> MUX_MODE_SHIFT;
-
- spin_lock(&gpio_mux_lock);
-
- l = __raw_readl(reg);
- l &= ~(0xff << (field * 8));
- l |= mode << (field * 8);
- __raw_writel(l, reg);
-
- spin_unlock(&gpio_mux_lock);
-
- return ret;
-}
-EXPORT_SYMBOL(mxc_iomux_mode);
-
-/*
- * This function configures the pad value for a IOMUX pin.
- */
-void mxc_iomux_set_pad(enum iomux_pins pin, u32 config)
-{
- u32 padgrp, field, l;
- void __iomem *reg;
-
- padgrp = (pin & MUX_PADGRP_MASK) >> MUX_PADGRP_SHIFT;
- reg = IOMUXSW_PAD_CTL + (pin + 2) / 3 * 4;
- field = (pin + 2) % 3;
-
- pr_debug("%s: reg offset = 0x%x, field = %d\n",
- __func__, (pin + 2) / 3, field);
-
- spin_lock(&gpio_mux_lock);
-
- l = __raw_readl(reg);
- l &= ~(0x1ff << (field * 10));
- l |= config << (field * 10);
- __raw_writel(l, reg);
-
- spin_unlock(&gpio_mux_lock);
-}
-EXPORT_SYMBOL(mxc_iomux_set_pad);
-
-/*
- * allocs a single pin:
- * - reserves the pin so that it is not claimed by another driver
- * - setups the iomux according to the configuration
- */
-int mxc_iomux_alloc_pin(unsigned int pin_mode, const char *label)
-{
- unsigned pad = PIN_GLOBAL_NUM(pin_mode);
- if (pad >= (PIN_MAX + 1)) {
- printk(KERN_ERR "mxc_iomux: Attempt to request nonexistant pin %u for \"%s\"\n",
- pad, label ? label : "?");
- return -EINVAL;
- }
-
- if (test_and_set_bit(pad, mxc_pin_alloc_map)) {
- printk(KERN_ERR "mxc_iomux: pin %u already used. Allocation for \"%s\" failed\n",
- pad, label ? label : "?");
- return -EBUSY;
- }
- mxc_iomux_mode(pin_mode);
-
- return 0;
-}
-EXPORT_SYMBOL(mxc_iomux_alloc_pin);
-
-int mxc_iomux_setup_multiple_pins(const unsigned int *pin_list, unsigned count,
- const char *label)
-{
- const unsigned int *p = pin_list;
- int i;
- int ret = -EINVAL;
-
- for (i = 0; i < count; i++) {
- ret = mxc_iomux_alloc_pin(*p, label);
- if (ret)
- goto setup_error;
- p++;
- }
- return 0;
-
-setup_error:
- mxc_iomux_release_multiple_pins(pin_list, i);
- return ret;
-}
-EXPORT_SYMBOL(mxc_iomux_setup_multiple_pins);
-
-void mxc_iomux_release_pin(unsigned int pin_mode)
-{
- unsigned pad = PIN_GLOBAL_NUM(pin_mode);
-
- if (pad < (PIN_MAX + 1))
- clear_bit(pad, mxc_pin_alloc_map);
-}
-EXPORT_SYMBOL(mxc_iomux_release_pin);
-
-void mxc_iomux_release_multiple_pins(const unsigned int *pin_list, int count)
-{
- const unsigned int *p = pin_list;
- int i;
-
- for (i = 0; i < count; i++) {
- mxc_iomux_release_pin(*p);
- p++;
- }
-}
-EXPORT_SYMBOL(mxc_iomux_release_multiple_pins);
diff --git a/arch/arm/mach-mxc91231/magx-zn5.c b/arch/arm/mach-mxc91231/magx-zn5.c
deleted file mode 100644
index f31a45e5a0b8..000000000000
--- a/arch/arm/mach-mxc91231/magx-zn5.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2009 Dmitriy Taychenachev <dimichxp@gmail.com>
- *
- * This file is released under the GPLv2 or later.
- */
-
-#include <linux/irq.h>
-#include <linux/init.h>
-#include <linux/device.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/time.h>
-#include <asm/mach/arch.h>
-
-#include <mach/common.h>
-#include <mach/hardware.h>
-#include <mach/iomux-mxc91231.h>
-#include <mach/mmc.h>
-#include <mach/imx-uart.h>
-
-#include "devices.h"
-
-static struct imxuart_platform_data uart_pdata = {
-};
-
-static struct imxmmc_platform_data sdhc_pdata = {
-};
-
-static void __init zn5_init(void)
-{
- pm_power_off = mxc91231_power_off;
-
- mxc_iomux_alloc_pin(MXC91231_PIN_SP_USB_DAT_VP__RXD2, "uart2-rx");
- mxc_iomux_alloc_pin(MXC91231_PIN_SP_USB_SE0_VM__TXD2, "uart2-tx");
-
- mxc_register_device(&mxc_uart_device1, &uart_pdata);
- mxc_register_device(&mxc_uart_device0, &uart_pdata);
-
- mxc_register_device(&mxc_sdhc_device0, &sdhc_pdata);
-
- mxc_register_device(&mxc_wdog_device0, NULL);
-
- return;
-}
-
-static void __init zn5_timer_init(void)
-{
- mxc91231_clocks_init(26000000); /* 26mhz ckih */
-}
-
-struct sys_timer zn5_timer = {
- .init = zn5_timer_init,
-};
-
-MACHINE_START(MAGX_ZN5, "Motorola Zn5")
- .boot_params = MXC91231_PHYS_OFFSET + 0x100,
- .map_io = mxc91231_map_io,
- .init_early = mxc91231_init_early,
- .init_irq = mxc91231_init_irq,
- .timer = &zn5_timer,
- .init_machine = zn5_init,
-MACHINE_END
diff --git a/arch/arm/mach-mxc91231/mm.c b/arch/arm/mach-mxc91231/mm.c
deleted file mode 100644
index a77f6daf6a26..000000000000
--- a/arch/arm/mach-mxc91231/mm.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 1999,2000 Arm Limited
- * Copyright (C) 2000 Deep Blue Solutions Ltd
- * Copyright (C) 2002 Shane Nay (shane@minirl.com)
- * Copyright 2004-2005 Freescale Semiconductor, Inc. All Rights Reserved.
- * - add MXC specific definitions
- * Copyright 2006 Motorola, 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.
- */
-
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <mach/hardware.h>
-#include <mach/common.h>
-#include <asm/pgtable.h>
-#include <asm/mach/map.h>
-
-/*
- * This structure defines the MXC memory map.
- */
-static struct map_desc mxc91231_io_desc[] __initdata = {
- imx_map_entry(MXC91231, L2CC, MT_DEVICE),
- imx_map_entry(MXC91231, X_MEMC, MT_DEVICE),
- imx_map_entry(MXC91231, ROMP, MT_DEVICE),
- imx_map_entry(MXC91231, AVIC, MT_DEVICE),
- imx_map_entry(MXC91231, AIPS1, MT_DEVICE),
- imx_map_entry(MXC91231, SPBA0, MT_DEVICE),
- imx_map_entry(MXC91231, SPBA1, MT_DEVICE),
- imx_map_entry(MXC91231, AIPS2, MT_DEVICE),
-};
-
-/*
- * This function initializes the memory map. It is called during the
- * system startup to create static physical to virtual memory map for
- * the IO modules.
- */
-void __init mxc91231_map_io(void)
-{
- iotable_init(mxc91231_io_desc, ARRAY_SIZE(mxc91231_io_desc));
-}
-
-void __init mxc91231_init_early(void)
-{
- mxc_set_cpu_type(MXC_CPU_MXC91231);
-}
-
-int mxc91231_register_gpios(void);
-
-void __init mxc91231_init_irq(void)
-{
- mxc91231_register_gpios();
- mxc_init_irq(MXC91231_IO_ADDRESS(MXC91231_AVIC_BASE_ADDR));
-}
diff --git a/arch/arm/mach-mxc91231/system.c b/arch/arm/mach-mxc91231/system.c
deleted file mode 100644
index 736f7efd874a..000000000000
--- a/arch/arm/mach-mxc91231/system.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2009 Dmitriy Taychenachev <dimichxp@gmail.com>
- *
- * This file is released under the GPLv2 or later.
- */
-
-#include <linux/delay.h>
-#include <linux/io.h>
-
-#include <asm/proc-fns.h>
-#include <mach/hardware.h>
-
-#include "crm_regs.h"
-
-#define WDOG_WCR MXC91231_IO_ADDRESS(MXC91231_WDOG1_BASE_ADDR)
-#define WDOG_WCR_OUT_ENABLE (1 << 6)
-#define WDOG_WCR_ASSERT (1 << 5)
-
-void mxc91231_power_off(void)
-{
- u16 wcr;
-
- wcr = __raw_readw(WDOG_WCR);
- wcr |= WDOG_WCR_OUT_ENABLE;
- wcr &= ~WDOG_WCR_ASSERT;
- __raw_writew(wcr, WDOG_WCR);
-}
-
-void mxc91231_arch_reset(char mode, const char *cmd)
-{
- u32 amcr;
-
- /* Reset the AP using CRM */
- amcr = __raw_readl(MXC_CRMAP_AMCR);
- amcr &= ~MXC_CRMAP_AMCR_SW_AP;
- __raw_writel(amcr, MXC_CRMAP_AMCR);
-
- mdelay(10);
- cpu_reset(0);
-}
-
-void mxc91231_prepare_idle(void)
-{
- u32 crm_ctl;
-
- /* Go to WAIT mode after WFI */
- crm_ctl = __raw_readl(MXC_DSM_CRM_CONTROL);
- crm_ctl &= ~(MXC_DSM_CRM_CTRL_LPMD0 | MXC_DSM_CRM_CTRL_LPMD1);
- crm_ctl |= MXC_DSM_CRM_CTRL_LPMD_WAIT_MODE;
- __raw_writel(crm_ctl, MXC_DSM_CRM_CONTROL);
-}
diff --git a/arch/arm/mach-mxs/Kconfig b/arch/arm/mach-mxs/Kconfig
index 4522fbb235d5..f114960622e0 100644
--- a/arch/arm/mach-mxs/Kconfig
+++ b/arch/arm/mach-mxs/Kconfig
@@ -17,6 +17,16 @@ config SOC_IMX28
comment "MXS platforms:"
+config MACH_STMP378X_DEVB
+ bool "Support STMP378x_devb Platform"
+ select SOC_IMX23
+ select MXS_HAVE_AMBA_DUART
+ select MXS_HAVE_PLATFORM_AUART
+ select MXS_HAVE_PLATFORM_MXS_MMC
+ help
+ Include support for STMP378x-devb platform. This includes specific
+ configurations for the board and its peripherals.
+
config MACH_MX23EVK
bool "Support MX23EVK Platform"
select SOC_IMX23
@@ -24,7 +34,6 @@ config MACH_MX23EVK
select MXS_HAVE_PLATFORM_AUART
select MXS_HAVE_PLATFORM_MXS_MMC
select MXS_HAVE_PLATFORM_MXSFB
- default y
help
Include support for MX23EVK platform. This includes specific
configurations for the board and its peripherals.
@@ -39,7 +48,6 @@ config MACH_MX28EVK
select MXS_HAVE_PLATFORM_MXS_MMC
select MXS_HAVE_PLATFORM_MXSFB
select MXS_OCOTP
- default y
help
Include support for MX28EVK platform. This includes specific
configurations for the board and its peripherals.
diff --git a/arch/arm/mach-mxs/Makefile b/arch/arm/mach-mxs/Makefile
index 2f1f6141ca71..58e892376bf2 100644
--- a/arch/arm/mach-mxs/Makefile
+++ b/arch/arm/mach-mxs/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_PM) += pm.o
obj-$(CONFIG_SOC_IMX23) += clock-mx23.o mm-mx23.o
obj-$(CONFIG_SOC_IMX28) += clock-mx28.o mm-mx28.o
+obj-$(CONFIG_MACH_STMP378X_DEVB) += mach-stmp378x_devb.o
obj-$(CONFIG_MACH_MX23EVK) += mach-mx23evk.o
obj-$(CONFIG_MACH_MX28EVK) += mach-mx28evk.o
obj-$(CONFIG_MODULE_TX28) += module-tx28.o
diff --git a/arch/arm/mach-mxs/clock-mx23.c b/arch/arm/mach-mxs/clock-mx23.c
index c3577ea789ac..0163b6d83773 100644
--- a/arch/arm/mach-mxs/clock-mx23.c
+++ b/arch/arm/mach-mxs/clock-mx23.c
@@ -446,6 +446,8 @@ static struct clk_lookup lookups[] = {
_REGISTER_CLOCK("rtc", NULL, rtc_clk)
_REGISTER_CLOCK("mxs-dma-apbh", NULL, hbus_clk)
_REGISTER_CLOCK("mxs-dma-apbx", NULL, xbus_clk)
+ _REGISTER_CLOCK("mxs-mmc.0", NULL, ssp_clk)
+ _REGISTER_CLOCK("mxs-mmc.1", NULL, ssp_clk)
_REGISTER_CLOCK(NULL, "usb", usb_clk)
_REGISTER_CLOCK(NULL, "audio", audio_clk)
_REGISTER_CLOCK("mxs-pwm.0", NULL, pwm_clk)
diff --git a/arch/arm/mach-mxs/devices-mx28.h b/arch/arm/mach-mxs/devices-mx28.h
index c473eddce8cf..79b94523954a 100644
--- a/arch/arm/mach-mxs/devices-mx28.h
+++ b/arch/arm/mach-mxs/devices-mx28.h
@@ -34,7 +34,7 @@ extern const struct mxs_flexcan_data mx28_flexcan_data[] __initconst;
#define mx28_add_flexcan0(pdata) mx28_add_flexcan(0, pdata)
#define mx28_add_flexcan1(pdata) mx28_add_flexcan(1, pdata)
-extern const struct mxs_i2c_data mx28_mxs_i2c_data[] __initconst;
+extern const struct mxs_mxs_i2c_data mx28_mxs_i2c_data[] __initconst;
#define mx28_add_mxs_i2c(id) mxs_add_mxs_i2c(&mx28_mxs_i2c_data[id])
extern const struct mxs_mxs_mmc_data mx28_mxs_mmc_data[] __initconst;
diff --git a/arch/arm/mach-mxs/devices/platform-mxs-i2c.c b/arch/arm/mach-mxs/devices/platform-mxs-i2c.c
index eab3a06836d6..79222ec8ede1 100644
--- a/arch/arm/mach-mxs/devices/platform-mxs-i2c.c
+++ b/arch/arm/mach-mxs/devices/platform-mxs-i2c.c
@@ -22,13 +22,14 @@
[_id] = mxs_i2c_data_entry_single(soc, _id)
#ifdef CONFIG_SOC_IMX28
-const struct mxs_i2c_data mx28_mxs_i2c_data[] __initconst = {
+const struct mxs_mxs_i2c_data mx28_mxs_i2c_data[] __initconst = {
mxs_i2c_data_entry(MX28, 0),
mxs_i2c_data_entry(MX28, 1),
};
#endif
-struct platform_device *__init mxs_add_mxs_i2c(const struct mxs_i2c_data *data)
+struct platform_device *__init mxs_add_mxs_i2c(
+ const struct mxs_mxs_i2c_data *data)
{
struct resource res[] = {
{
diff --git a/arch/arm/mach-mxs/include/mach/devices-common.h b/arch/arm/mach-mxs/include/mach/devices-common.h
index c5137f14c364..7a37469ed5bf 100644
--- a/arch/arm/mach-mxs/include/mach/devices-common.h
+++ b/arch/arm/mach-mxs/include/mach/devices-common.h
@@ -65,13 +65,14 @@ struct platform_device *__init mxs_add_flexcan(
const struct flexcan_platform_data *pdata);
/* i2c */
-struct mxs_i2c_data {
+struct mxs_mxs_i2c_data {
int id;
resource_size_t iobase;
resource_size_t errirq;
resource_size_t dmairq;
};
-struct platform_device * __init mxs_add_mxs_i2c(const struct mxs_i2c_data *data);
+struct platform_device * __init mxs_add_mxs_i2c(
+ const struct mxs_mxs_i2c_data *data);
/* mmc */
#include <mach/mmc.h>
diff --git a/arch/arm/mach-mxs/include/mach/mx23.h b/arch/arm/mach-mxs/include/mach/mx23.h
index c0a18c23084a..599094bc99de 100644
--- a/arch/arm/mach-mxs/include/mach/mx23.h
+++ b/arch/arm/mach-mxs/include/mach/mx23.h
@@ -57,7 +57,7 @@
#define MX23_AUDIOIN_BASE_ADDR (MX23_IO_BASE_ADDR + 0x04c000)
#define MX23_LRADC_BASE_ADDR (MX23_IO_BASE_ADDR + 0x050000)
#define MX23_SPDIF_BASE_ADDR (MX23_IO_BASE_ADDR + 0x054000)
-#define MX23_I2C0_BASE_ADDR (MX23_IO_BASE_ADDR + 0x058000)
+#define MX23_I2C_BASE_ADDR (MX23_IO_BASE_ADDR + 0x058000)
#define MX23_RTC_BASE_ADDR (MX23_IO_BASE_ADDR + 0x05c000)
#define MX23_PWM_BASE_ADDR (MX23_IO_BASE_ADDR + 0x064000)
#define MX23_TIMROT_BASE_ADDR (MX23_IO_BASE_ADDR + 0x068000)
diff --git a/arch/arm/mach-mxs/include/mach/uncompress.h b/arch/arm/mach-mxs/include/mach/uncompress.h
index f12a1732d8b8..7f8bf6539646 100644
--- a/arch/arm/mach-mxs/include/mach/uncompress.h
+++ b/arch/arm/mach-mxs/include/mach/uncompress.h
@@ -20,7 +20,7 @@
#include <asm/mach-types.h>
-static unsigned long mxs_duart_base;
+unsigned long mxs_duart_base;
#define MXS_DUART(x) (*(volatile unsigned long *)(mxs_duart_base + (x)))
diff --git a/arch/arm/mach-mxs/mach-mx23evk.c b/arch/arm/mach-mxs/mach-mx23evk.c
index 214e5b641bbc..3c2de33803ab 100644
--- a/arch/arm/mach-mxs/mach-mx23evk.c
+++ b/arch/arm/mach-mxs/mach-mx23evk.c
@@ -148,7 +148,7 @@ static void __init mx23evk_init(void)
mx23_add_auart0();
/* power on mmc slot by writing 0 to the gpio */
- ret = gpio_request_one(MX23EVK_MMC0_SLOT_POWER, GPIOF_DIR_OUT,
+ ret = gpio_request_one(MX23EVK_MMC0_SLOT_POWER, GPIOF_OUT_INIT_LOW,
"mmc0-slot-power");
if (ret)
pr_warn("failed to request gpio mmc0-slot-power: %d\n", ret);
diff --git a/arch/arm/mach-mxs/mach-mx28evk.c b/arch/arm/mach-mxs/mach-mx28evk.c
index bb329b9a2608..eacdc6b0e70a 100644
--- a/arch/arm/mach-mxs/mach-mx28evk.c
+++ b/arch/arm/mach-mxs/mach-mx28evk.c
@@ -375,13 +375,13 @@ static void __init mx28evk_init(void)
mx28_add_mxsfb(&mx28evk_mxsfb_pdata);
/* power on mmc slot by writing 0 to the gpio */
- ret = gpio_request_one(MX28EVK_MMC0_SLOT_POWER, GPIOF_DIR_OUT,
+ ret = gpio_request_one(MX28EVK_MMC0_SLOT_POWER, GPIOF_OUT_INIT_LOW,
"mmc0-slot-power");
if (ret)
pr_warn("failed to request gpio mmc0-slot-power: %d\n", ret);
mx28_add_mxs_mmc(0, &mx28evk_mmc_pdata[0]);
- ret = gpio_request_one(MX28EVK_MMC1_SLOT_POWER, GPIOF_DIR_OUT,
+ ret = gpio_request_one(MX28EVK_MMC1_SLOT_POWER, GPIOF_OUT_INIT_LOW,
"mmc1-slot-power");
if (ret)
pr_warn("failed to request gpio mmc1-slot-power: %d\n", ret);
diff --git a/arch/arm/mach-mxs/mach-stmp378x_devb.c b/arch/arm/mach-mxs/mach-stmp378x_devb.c
new file mode 100644
index 000000000000..7f38d82b69af
--- /dev/null
+++ b/arch/arm/mach-mxs/mach-stmp378x_devb.c
@@ -0,0 +1,120 @@
+/*
+ * board setup for STMP378x-Development-Board
+ *
+ * based on mx23evk board setup and information gained form the original
+ * plat-stmp based board setup, now converted to mach-mxs.
+ *
+ * Copyright 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2011 Wolfram Sang, Pengutronix e.K.
+ *
+ * This program is free software; 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/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/spi/spi.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+
+#include <mach/common.h>
+#include <mach/iomux-mx23.h>
+
+#include "devices-mx23.h"
+
+#define STMP378X_DEVB_MMC0_WRITE_PROTECT MXS_GPIO_NR(1, 30)
+#define STMP378X_DEVB_MMC0_SLOT_POWER MXS_GPIO_NR(1, 29)
+
+#define STMP378X_DEVB_PAD_AUART (MXS_PAD_4MA | MXS_PAD_1V8 | MXS_PAD_NOPULL)
+
+static const iomux_cfg_t stmp378x_dvb_pads[] __initconst = {
+ /* duart (extended setup missing in old boardcode, too */
+ MX23_PAD_PWM0__DUART_RX,
+ MX23_PAD_PWM1__DUART_TX,
+
+ /* auart */
+ MX23_PAD_AUART1_RX__AUART1_RX | STMP378X_DEVB_PAD_AUART,
+ MX23_PAD_AUART1_TX__AUART1_TX | STMP378X_DEVB_PAD_AUART,
+ MX23_PAD_AUART1_CTS__AUART1_CTS | STMP378X_DEVB_PAD_AUART,
+ MX23_PAD_AUART1_RTS__AUART1_RTS | STMP378X_DEVB_PAD_AUART,
+
+ /* mmc */
+ MX23_PAD_SSP1_DATA0__SSP1_DATA0 |
+ (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+ MX23_PAD_SSP1_DATA1__SSP1_DATA1 |
+ (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+ MX23_PAD_SSP1_DATA2__SSP1_DATA2 |
+ (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+ MX23_PAD_SSP1_DATA3__SSP1_DATA3 |
+ (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+ MX23_PAD_SSP1_CMD__SSP1_CMD |
+ (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
+ MX23_PAD_SSP1_DETECT__SSP1_DETECT |
+ (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_NOPULL),
+ MX23_PAD_SSP1_SCK__SSP1_SCK |
+ (MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_NOPULL),
+ MX23_PAD_PWM4__GPIO_1_30 | MXS_PAD_CTRL, /* write protect */
+ MX23_PAD_PWM3__GPIO_1_29 | MXS_PAD_CTRL, /* power enable */
+};
+
+static struct mxs_mmc_platform_data stmp378x_dvb_mmc_pdata __initdata = {
+ .wp_gpio = STMP378X_DEVB_MMC0_WRITE_PROTECT,
+};
+
+static struct spi_board_info spi_board_info[] __initdata = {
+#if defined(CONFIG_ENC28J60) || defined(CONFIG_ENC28J60_MODULE)
+ {
+ .modalias = "enc28j60",
+ .max_speed_hz = 6 * 1000 * 1000,
+ .bus_num = 1,
+ .chip_select = 0,
+ .platform_data = NULL,
+ },
+#endif
+};
+
+static void __init stmp378x_dvb_init(void)
+{
+ int ret;
+
+ mxs_iomux_setup_multiple_pads(stmp378x_dvb_pads,
+ ARRAY_SIZE(stmp378x_dvb_pads));
+
+ mx23_add_duart();
+ mx23_add_auart0();
+
+ /* power on mmc slot */
+ ret = gpio_request_one(STMP378X_DEVB_MMC0_SLOT_POWER,
+ GPIOF_OUT_INIT_LOW, "mmc0-slot-power");
+ if (ret)
+ pr_warn("could not power mmc (%d)\n", ret);
+
+ mx23_add_mxs_mmc(0, &stmp378x_dvb_mmc_pdata);
+
+ spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+}
+
+static void __init stmp378x_dvb_timer_init(void)
+{
+ mx23_clocks_init();
+}
+
+static struct sys_timer stmp378x_dvb_timer = {
+ .init = stmp378x_dvb_timer_init,
+};
+
+MACHINE_START(STMP378X, "STMP378X")
+ .map_io = mx23_map_io,
+ .init_irq = mx23_init_irq,
+ .init_machine = stmp378x_dvb_init,
+ .timer = &stmp378x_dvb_timer,
+MACHINE_END
diff --git a/arch/arm/mach-mxs/timer.c b/arch/arm/mach-mxs/timer.c
index 13647f301860..cace0d2e5a55 100644
--- a/arch/arm/mach-mxs/timer.c
+++ b/arch/arm/mach-mxs/timer.c
@@ -101,11 +101,6 @@ static cycle_t timrotv1_get_cycles(struct clocksource *cs)
& 0xffff0000) >> 16);
}
-static cycle_t timrotv2_get_cycles(struct clocksource *cs)
-{
- return ~__raw_readl(mxs_timrot_base + HW_TIMROT_RUNNING_COUNTn(1));
-}
-
static int timrotv1_set_next_event(unsigned long evt,
struct clock_event_device *dev)
{
@@ -230,8 +225,8 @@ static int __init mxs_clockevent_init(struct clk *timer_clk)
static struct clocksource clocksource_mxs = {
.name = "mxs_timer",
.rating = 200,
- .read = timrotv2_get_cycles,
- .mask = CLOCKSOURCE_MASK(32),
+ .read = timrotv1_get_cycles,
+ .mask = CLOCKSOURCE_MASK(16),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
@@ -239,12 +234,11 @@ static int __init mxs_clocksource_init(struct clk *timer_clk)
{
unsigned int c = clk_get_rate(timer_clk);
- if (timrot_is_v1()) {
- clocksource_mxs.read = timrotv1_get_cycles;
- clocksource_mxs.mask = CLOCKSOURCE_MASK(16);
- }
-
- clocksource_register_hz(&clocksource_mxs, c);
+ if (timrot_is_v1())
+ clocksource_register_hz(&clocksource_mxs, c);
+ else
+ clocksource_mmio_init(mxs_timrot_base + HW_TIMROT_RUNNING_COUNTn(1),
+ "mxs_timer", c, 200, 32, clocksource_mmio_readl_down);
return 0;
}
diff --git a/arch/arm/mach-netx/time.c b/arch/arm/mach-netx/time.c
index f12f22d09b6c..e24c141ba489 100644
--- a/arch/arm/mach-netx/time.c
+++ b/arch/arm/mach-netx/time.c
@@ -104,19 +104,6 @@ static struct irqaction netx_timer_irq = {
.handler = netx_timer_interrupt,
};
-cycle_t netx_get_cycles(struct clocksource *cs)
-{
- return readl(NETX_GPIO_COUNTER_CURRENT(TIMER_CLOCKSOURCE));
-}
-
-static struct clocksource clocksource_netx = {
- .name = "netx_timer",
- .rating = 200,
- .read = netx_get_cycles,
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
/*
* Set up timer interrupt
*/
@@ -150,7 +137,8 @@ static void __init netx_timer_init(void)
writel(NETX_GPIO_COUNTER_CTRL_RUN,
NETX_GPIO_COUNTER_CTRL(TIMER_CLOCKSOURCE));
- clocksource_register_hz(&clocksource_netx, CLOCK_TICK_RATE);
+ clocksource_mmio_init(NETX_GPIO_COUNTER_CURRENT(TIMER_CLOCKSOURCE),
+ "netx_timer", CLOCK_TICK_RATE, 200, 32, clocksource_mmio_readl_up);
netx_clockevent.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC,
netx_clockevent.shift);
diff --git a/arch/arm/mach-ns9xxx/Kconfig b/arch/arm/mach-ns9xxx/Kconfig
deleted file mode 100644
index dd0cd5ac4b8b..000000000000
--- a/arch/arm/mach-ns9xxx/Kconfig
+++ /dev/null
@@ -1,40 +0,0 @@
-if ARCH_NS9XXX
-
-menu "NS9xxx Implementations"
-
-config NS9XXX_HAVE_SERIAL8250
- bool
-
-config PROCESSOR_NS9360
- bool
-
-config MODULE_CC9P9360
- bool
- select PROCESSOR_NS9360
-
-config BOARD_A9M9750DEV
- select NS9XXX_HAVE_SERIAL8250
- bool
-
-config BOARD_JSCC9P9360
- bool
-
-config MACH_CC9P9360DEV
- bool "ConnectCore 9P 9360 on an A9M9750 Devboard"
- select MODULE_CC9P9360
- select BOARD_A9M9750DEV
- help
- Say Y here if you are using the Digi ConnectCore 9P 9360
- on an A9M9750 Development Board.
-
-config MACH_CC9P9360JS
- bool "ConnectCore 9P 9360 on a JSCC9P9360 Devboard"
- select MODULE_CC9P9360
- select BOARD_JSCC9P9360
- help
- Say Y here if you are using the Digi ConnectCore 9P 9360
- on an JSCC9P9360 Development Board.
-
-endmenu
-
-endif
diff --git a/arch/arm/mach-ns9xxx/Makefile b/arch/arm/mach-ns9xxx/Makefile
deleted file mode 100644
index 41efaf9ad50b..000000000000
--- a/arch/arm/mach-ns9xxx/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-obj-y := clock.o generic.o gpio.o irq.o
-
-obj-$(CONFIG_MACH_CC9P9360DEV) += mach-cc9p9360dev.o
-obj-$(CONFIG_MACH_CC9P9360JS) += mach-cc9p9360js.o
-
-obj-$(CONFIG_PROCESSOR_NS9360) += gpio-ns9360.o processor-ns9360.o time-ns9360.o
-
-obj-$(CONFIG_BOARD_A9M9750DEV) += board-a9m9750dev.o
-obj-$(CONFIG_BOARD_JSCC9P9360) += board-jscc9p9360.o
-
-# platform devices
-obj-$(CONFIG_NS9XXX_HAVE_SERIAL8250) += plat-serial8250.o
diff --git a/arch/arm/mach-ns9xxx/Makefile.boot b/arch/arm/mach-ns9xxx/Makefile.boot
deleted file mode 100644
index 54654919229b..000000000000
--- a/arch/arm/mach-ns9xxx/Makefile.boot
+++ /dev/null
@@ -1,2 +0,0 @@
-zreladdr-y := 0x8000
-params_phys-y := 0x100
diff --git a/arch/arm/mach-ns9xxx/board-a9m9750dev.c b/arch/arm/mach-ns9xxx/board-a9m9750dev.c
deleted file mode 100644
index e27687d53504..000000000000
--- a/arch/arm/mach-ns9xxx/board-a9m9750dev.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/board-a9m9750dev.c
- *
- * Copyright (C) 2006,2007 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#include <linux/irq.h>
-
-#include <asm/mach/map.h>
-#include <asm/gpio.h>
-
-#include <mach/board.h>
-#include <mach/processor-ns9360.h>
-#include <mach/regs-sys-ns9360.h>
-#include <mach/regs-mem.h>
-#include <mach/regs-bbu.h>
-#include <mach/regs-board-a9m9750dev.h>
-
-#include "board-a9m9750dev.h"
-
-static struct map_desc board_a9m9750dev_io_desc[] __initdata = {
- { /* FPGA on CS0 */
- .virtual = io_p2v(NS9XXX_CSxSTAT_PHYS(0)),
- .pfn = __phys_to_pfn(NS9XXX_CSxSTAT_PHYS(0)),
- .length = NS9XXX_CS0STAT_LENGTH,
- .type = MT_DEVICE,
- },
-};
-
-void __init board_a9m9750dev_map_io(void)
-{
- iotable_init(board_a9m9750dev_io_desc,
- ARRAY_SIZE(board_a9m9750dev_io_desc));
-}
-
-static void a9m9750dev_fpga_ack_irq(struct irq_data *d)
-{
- /* nothing */
-}
-
-static void a9m9750dev_fpga_mask_irq(struct irq_data *d)
-{
- u8 ier;
-
- ier = __raw_readb(FPGA_IER);
-
- ier &= ~(1 << (d->irq - FPGA_IRQ(0)));
-
- __raw_writeb(ier, FPGA_IER);
-}
-
-static void a9m9750dev_fpga_maskack_irq(struct irq_data *d)
-{
- a9m9750dev_fpga_mask_irq(d);
- a9m9750dev_fpga_ack_irq(d);
-}
-
-static void a9m9750dev_fpga_unmask_irq(struct irq_data *d)
-{
- u8 ier;
-
- ier = __raw_readb(FPGA_IER);
-
- ier |= 1 << (d->irq - FPGA_IRQ(0));
-
- __raw_writeb(ier, FPGA_IER);
-}
-
-static struct irq_chip a9m9750dev_fpga_chip = {
- .irq_ack = a9m9750dev_fpga_ack_irq,
- .irq_mask = a9m9750dev_fpga_mask_irq,
- .irq_mask_ack = a9m9750dev_fpga_maskack_irq,
- .irq_unmask = a9m9750dev_fpga_unmask_irq,
-};
-
-static void a9m9750dev_fpga_demux_handler(unsigned int irq,
- struct irq_desc *desc)
-{
- u8 stat = __raw_readb(FPGA_ISR);
-
- desc->irq_data.chip->irq_mask_ack(&desc->irq_data);
-
- while (stat != 0) {
- int irqno = fls(stat) - 1;
-
- stat &= ~(1 << irqno);
-
- generic_handle_irq(FPGA_IRQ(irqno));
- }
-
- desc->irq_data.chip->irq_unmask(&desc->irq_data);
-}
-
-void __init board_a9m9750dev_init_irq(void)
-{
- u32 eic;
- int i;
-
- if (gpio_request(11, "board a9m9750dev extirq2") == 0)
- ns9360_gpio_configure(11, 0, 1);
- else
- printk(KERN_ERR "%s: cannot get gpio 11 for IRQ_NS9XXX_EXT2\n",
- __func__);
-
- for (i = FPGA_IRQ(0); i <= FPGA_IRQ(7); ++i) {
- irq_set_chip_and_handler(i, &a9m9750dev_fpga_chip,
- handle_level_irq);
- set_irq_flags(i, IRQF_VALID);
- }
-
- /* IRQ_NS9XXX_EXT2: level sensitive + active low */
- eic = __raw_readl(SYS_EIC(2));
- REGSET(eic, SYS_EIC, PLTY, AL);
- REGSET(eic, SYS_EIC, LVEDG, LEVEL);
- __raw_writel(eic, SYS_EIC(2));
-
- irq_set_chained_handler(IRQ_NS9XXX_EXT2,
- a9m9750dev_fpga_demux_handler);
-}
-
-void __init board_a9m9750dev_init_machine(void)
-{
- u32 reg;
-
- /* setup static CS0: memory base ... */
- reg = __raw_readl(SYS_SMCSSMB(0));
- REGSETIM(reg, SYS_SMCSSMB, CSxB, NS9XXX_CSxSTAT_PHYS(0) >> 12);
- __raw_writel(reg, SYS_SMCSSMB(0));
-
- /* ... and mask */
- reg = __raw_readl(SYS_SMCSSMM(0));
- REGSETIM(reg, SYS_SMCSSMM, CSxM, 0xfffff);
- REGSET(reg, SYS_SMCSSMM, CSEx, EN);
- __raw_writel(reg, SYS_SMCSSMM(0));
-
- /* setup static CS0: memory configuration */
- reg = __raw_readl(MEM_SMC(0));
- REGSET(reg, MEM_SMC, PSMC, OFF);
- REGSET(reg, MEM_SMC, BSMC, OFF);
- REGSET(reg, MEM_SMC, EW, OFF);
- REGSET(reg, MEM_SMC, PB, 1);
- REGSET(reg, MEM_SMC, PC, AL);
- REGSET(reg, MEM_SMC, PM, DIS);
- REGSET(reg, MEM_SMC, MW, 8);
- __raw_writel(reg, MEM_SMC(0));
-
- /* setup static CS0: timing */
- __raw_writel(0x2, MEM_SMWED(0));
- __raw_writel(0x2, MEM_SMOED(0));
- __raw_writel(0x6, MEM_SMRD(0));
- __raw_writel(0x6, MEM_SMWD(0));
-}
diff --git a/arch/arm/mach-ns9xxx/board-a9m9750dev.h b/arch/arm/mach-ns9xxx/board-a9m9750dev.h
deleted file mode 100644
index edc75abbc5dd..000000000000
--- a/arch/arm/mach-ns9xxx/board-a9m9750dev.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/board-a9m9750dev.h
- *
- * Copyright (C) 2006 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#include <linux/init.h>
-
-void __init board_a9m9750dev_map_io(void);
-void __init board_a9m9750dev_init_machine(void);
-void __init board_a9m9750dev_init_irq(void);
diff --git a/arch/arm/mach-ns9xxx/board-jscc9p9360.c b/arch/arm/mach-ns9xxx/board-jscc9p9360.c
deleted file mode 100644
index 4bd3eec04bfe..000000000000
--- a/arch/arm/mach-ns9xxx/board-jscc9p9360.c
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/board-jscc9p9360.c
- *
- * Copyright (C) 2006,2007 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#include "board-jscc9p9360.h"
-
-void __init board_jscc9p9360_init_machine(void)
-{
- /* TODO: reserve GPIOs for push buttons, etc pp */
-}
-
diff --git a/arch/arm/mach-ns9xxx/board-jscc9p9360.h b/arch/arm/mach-ns9xxx/board-jscc9p9360.h
deleted file mode 100644
index 1a81a074df45..000000000000
--- a/arch/arm/mach-ns9xxx/board-jscc9p9360.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/board-jscc9p9360.h
- *
- * Copyright (C) 2006 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#include <linux/init.h>
-
-void __init board_jscc9p9360_init_machine(void);
diff --git a/arch/arm/mach-ns9xxx/clock.c b/arch/arm/mach-ns9xxx/clock.c
deleted file mode 100644
index cf81cbc57544..000000000000
--- a/arch/arm/mach-ns9xxx/clock.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/clock.c
- *
- * Copyright (C) 2007 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/list.h>
-#include <linux/clk.h>
-#include <linux/string.h>
-#include <linux/platform_device.h>
-#include <linux/semaphore.h>
-
-#include "clock.h"
-
-static LIST_HEAD(clocks);
-static DEFINE_SPINLOCK(clk_lock);
-
-struct clk *clk_get(struct device *dev, const char *id)
-{
- struct clk *p, *ret = NULL, *retgen = NULL;
- unsigned long flags;
- int idno;
-
- if (dev == NULL || dev->bus != &platform_bus_type)
- idno = -1;
- else
- idno = to_platform_device(dev)->id;
-
- spin_lock_irqsave(&clk_lock, flags);
- list_for_each_entry(p, &clocks, node) {
- if (strcmp(id, p->name) == 0) {
- if (p->id == idno) {
- if (!try_module_get(p->owner))
- continue;
- ret = p;
- break;
- } else if (p->id == -1)
- /* remember match with id == -1 in case there is
- * no clock for idno */
- retgen = p;
- }
- }
-
- if (!ret && retgen && try_module_get(retgen->owner))
- ret = retgen;
-
- if (ret)
- ++ret->refcount;
-
- spin_unlock_irqrestore(&clk_lock, flags);
-
- return ret ? ret : ERR_PTR(-ENOENT);
-}
-EXPORT_SYMBOL(clk_get);
-
-void clk_put(struct clk *clk)
-{
- module_put(clk->owner);
- --clk->refcount;
-}
-EXPORT_SYMBOL(clk_put);
-
-static int clk_enable_unlocked(struct clk *clk)
-{
- int ret = 0;
- if (clk->parent) {
- ret = clk_enable_unlocked(clk->parent);
- if (ret)
- return ret;
- }
-
- if (clk->usage++ == 0 && clk->endisable)
- ret = clk->endisable(clk, 1);
-
- return ret;
-}
-
-int clk_enable(struct clk *clk)
-{
- int ret;
- unsigned long flags;
-
- spin_lock_irqsave(&clk_lock, flags);
-
- ret = clk_enable_unlocked(clk);
-
- spin_unlock_irqrestore(&clk_lock, flags);
-
- return ret;
-}
-EXPORT_SYMBOL(clk_enable);
-
-static void clk_disable_unlocked(struct clk *clk)
-{
- if (--clk->usage == 0 && clk->endisable)
- clk->endisable(clk, 0);
-
- if (clk->parent)
- clk_disable_unlocked(clk->parent);
-}
-
-void clk_disable(struct clk *clk)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&clk_lock, flags);
-
- clk_disable_unlocked(clk);
-
- spin_unlock_irqrestore(&clk_lock, flags);
-}
-EXPORT_SYMBOL(clk_disable);
-
-unsigned long clk_get_rate(struct clk *clk)
-{
- if (clk->get_rate)
- return clk->get_rate(clk);
-
- if (clk->rate)
- return clk->rate;
-
- if (clk->parent)
- return clk_get_rate(clk->parent);
-
- return 0;
-}
-EXPORT_SYMBOL(clk_get_rate);
-
-int clk_register(struct clk *clk)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&clk_lock, flags);
-
- list_add(&clk->node, &clocks);
-
- if (clk->parent)
- ++clk->parent->refcount;
-
- spin_unlock_irqrestore(&clk_lock, flags);
-
- return 0;
-}
-
-int clk_unregister(struct clk *clk)
-{
- int ret = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&clk_lock, flags);
-
- if (clk->usage || clk->refcount)
- ret = -EBUSY;
- else
- list_del(&clk->node);
-
- if (clk->parent)
- --clk->parent->refcount;
-
- spin_unlock_irqrestore(&clk_lock, flags);
-
- return ret;
-}
-
-#if defined CONFIG_DEBUG_FS
-
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-
-static int clk_debugfs_show(struct seq_file *s, void *null)
-{
- unsigned long flags;
- struct clk *p;
-
- spin_lock_irqsave(&clk_lock, flags);
-
- list_for_each_entry(p, &clocks, node)
- seq_printf(s, "%s.%d: usage=%lu refcount=%lu rate=%lu\n",
- p->name, p->id, p->usage, p->refcount,
- p->usage ? clk_get_rate(p) : 0);
-
- spin_unlock_irqrestore(&clk_lock, flags);
-
- return 0;
-}
-
-static int clk_debugfs_open(struct inode *inode, struct file *file)
-{
- return single_open(file, clk_debugfs_show, NULL);
-}
-
-static const struct file_operations clk_debugfs_operations = {
- .open = clk_debugfs_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int __init clk_debugfs_init(void)
-{
- struct dentry *dentry;
-
- dentry = debugfs_create_file("clk", S_IFREG | S_IRUGO, NULL, NULL,
- &clk_debugfs_operations);
- return IS_ERR(dentry) ? PTR_ERR(dentry) : 0;
-}
-subsys_initcall(clk_debugfs_init);
-
-#endif /* if defined CONFIG_DEBUG_FS */
diff --git a/arch/arm/mach-ns9xxx/clock.h b/arch/arm/mach-ns9xxx/clock.h
deleted file mode 100644
index b86c30dd79eb..000000000000
--- a/arch/arm/mach-ns9xxx/clock.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/clock.h
- *
- * Copyright (C) 2007 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#ifndef __NS9XXX_CLOCK_H
-#define __NS9XXX_CLOCK_H
-
-#include <linux/list.h>
-
-struct clk {
- struct module *owner;
- const char *name;
- int id;
-
- struct clk *parent;
-
- unsigned long rate;
- int (*endisable)(struct clk *, int enable);
- unsigned long (*get_rate)(struct clk *);
-
- struct list_head node;
- unsigned long refcount;
- unsigned long usage;
-};
-
-int clk_register(struct clk *clk);
-int clk_unregister(struct clk *clk);
-
-#endif /* ifndef __NS9XXX_CLOCK_H */
diff --git a/arch/arm/mach-ns9xxx/generic.c b/arch/arm/mach-ns9xxx/generic.c
deleted file mode 100644
index 1e0f467879cc..000000000000
--- a/arch/arm/mach-ns9xxx/generic.c
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/generic.c
- *
- * Copyright (C) 2006,2007 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <asm/memory.h>
-
-#include "generic.h"
-
-void __init ns9xxx_init_machine(void)
-{
-}
diff --git a/arch/arm/mach-ns9xxx/generic.h b/arch/arm/mach-ns9xxx/generic.h
deleted file mode 100644
index 82493191aad6..000000000000
--- a/arch/arm/mach-ns9xxx/generic.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/generic.h
- *
- * Copyright (C) 2006,2007 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#include <linux/time.h>
-#include <asm/mach/time.h>
-#include <linux/init.h>
-
-void __init ns9xxx_init_irq(void);
-void __init ns9xxx_init_machine(void);
diff --git a/arch/arm/mach-ns9xxx/gpio-ns9360.c b/arch/arm/mach-ns9xxx/gpio-ns9360.c
deleted file mode 100644
index 377330c1b250..000000000000
--- a/arch/arm/mach-ns9xxx/gpio-ns9360.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/gpio-ns9360.c
- *
- * Copyright (C) 2006,2007 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#include <linux/bug.h>
-#include <linux/errno.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-#include <mach/regs-bbu.h>
-#include <mach/processor-ns9360.h>
-
-#include "gpio-ns9360.h"
-
-static inline int ns9360_valid_gpio(unsigned gpio)
-{
- return gpio <= 72;
-}
-
-static inline void __iomem *ns9360_gpio_get_gconfaddr(unsigned gpio)
-{
- if (gpio < 56)
- return BBU_GCONFb1(gpio / 8);
- else
- /*
- * this could be optimised away on
- * ns9750 only builds, but it isn't ...
- */
- return BBU_GCONFb2((gpio - 56) / 8);
-}
-
-static inline void __iomem *ns9360_gpio_get_gctrladdr(unsigned gpio)
-{
- if (gpio < 32)
- return BBU_GCTRL1;
- else if (gpio < 64)
- return BBU_GCTRL2;
- else
- /* this could be optimised away on ns9750 only builds */
- return BBU_GCTRL3;
-}
-
-static inline void __iomem *ns9360_gpio_get_gstataddr(unsigned gpio)
-{
- if (gpio < 32)
- return BBU_GSTAT1;
- else if (gpio < 64)
- return BBU_GSTAT2;
- else
- /* this could be optimised away on ns9750 only builds */
- return BBU_GSTAT3;
-}
-
-/*
- * each gpio can serve for 4 different purposes [0..3]. These are called
- * "functions" and passed in the parameter func. Functions 0-2 are always some
- * special things, function 3 is GPIO. If func == 3 dir specifies input or
- * output, and with inv you can enable an inverter (independent of func).
- */
-int __ns9360_gpio_configure(unsigned gpio, int dir, int inv, int func)
-{
- void __iomem *conf = ns9360_gpio_get_gconfaddr(gpio);
- u32 confval;
-
- confval = __raw_readl(conf);
- REGSETIM_IDX(confval, BBU_GCONFx, DIR, gpio & 7, dir);
- REGSETIM_IDX(confval, BBU_GCONFx, INV, gpio & 7, inv);
- REGSETIM_IDX(confval, BBU_GCONFx, FUNC, gpio & 7, func);
- __raw_writel(confval, conf);
-
- return 0;
-}
-
-int ns9360_gpio_configure(unsigned gpio, int inv, int func)
-{
- if (likely(ns9360_valid_gpio(gpio))) {
- if (func == 3) {
- printk(KERN_WARNING "use gpio_direction_input "
- "or gpio_direction_output\n");
- return -EINVAL;
- } else
- return __ns9360_gpio_configure(gpio, 0, inv, func);
- } else
- return -EINVAL;
-}
-EXPORT_SYMBOL(ns9360_gpio_configure);
-
-int ns9360_gpio_get_value(unsigned gpio)
-{
- void __iomem *stat = ns9360_gpio_get_gstataddr(gpio);
- int ret;
-
- ret = 1 & (__raw_readl(stat) >> (gpio & 31));
-
- return ret;
-}
-
-void ns9360_gpio_set_value(unsigned gpio, int value)
-{
- void __iomem *ctrl = ns9360_gpio_get_gctrladdr(gpio);
- u32 ctrlval;
-
- ctrlval = __raw_readl(ctrl);
-
- if (value)
- ctrlval |= 1 << (gpio & 31);
- else
- ctrlval &= ~(1 << (gpio & 31));
-
- __raw_writel(ctrlval, ctrl);
-}
diff --git a/arch/arm/mach-ns9xxx/gpio-ns9360.h b/arch/arm/mach-ns9xxx/gpio-ns9360.h
deleted file mode 100644
index 131cd1715caa..000000000000
--- a/arch/arm/mach-ns9xxx/gpio-ns9360.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/gpio-ns9360.h
- *
- * Copyright (C) 2006,2007 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-int __ns9360_gpio_configure(unsigned gpio, int dir, int inv, int func);
-int ns9360_gpio_get_value(unsigned gpio);
-void ns9360_gpio_set_value(unsigned gpio, int value);
diff --git a/arch/arm/mach-ns9xxx/gpio.c b/arch/arm/mach-ns9xxx/gpio.c
deleted file mode 100644
index 5503ca09c4ae..000000000000
--- a/arch/arm/mach-ns9xxx/gpio.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/gpio.c
- *
- * Copyright (C) 2006,2007 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#include <linux/kernel.h>
-#include <linux/compiler.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/module.h>
-#include <linux/bitops.h>
-
-#include <mach/gpio.h>
-#include <mach/processor.h>
-#include <mach/processor-ns9360.h>
-#include <asm/bug.h>
-#include <asm/types.h>
-
-#include "gpio-ns9360.h"
-
-#if defined(CONFIG_PROCESSOR_NS9360)
-#define GPIO_MAX 72
-#elif defined(CONFIG_PROCESSOR_NS9750)
-#define GPIO_MAX 49
-#endif
-
-/* protects BBU_GCONFx and BBU_GCTRLx */
-static spinlock_t gpio_lock = __SPIN_LOCK_UNLOCKED(gpio_lock);
-
-/* only access gpiores with atomic ops */
-static DECLARE_BITMAP(gpiores, GPIO_MAX + 1);
-
-static inline int ns9xxx_valid_gpio(unsigned gpio)
-{
-#if defined(CONFIG_PROCESSOR_NS9360)
- if (processor_is_ns9360())
- return gpio <= 72;
- else
-#endif
-#if defined(CONFIG_PROCESSOR_NS9750)
- if (processor_is_ns9750())
- return gpio <= 49;
- else
-#endif
- {
- BUG();
- return 0;
- }
-}
-
-int gpio_request(unsigned gpio, const char *label)
-{
- if (likely(ns9xxx_valid_gpio(gpio)))
- return test_and_set_bit(gpio, gpiores) ? -EBUSY : 0;
- else
- return -EINVAL;
-}
-EXPORT_SYMBOL(gpio_request);
-
-void gpio_free(unsigned gpio)
-{
- might_sleep();
- clear_bit(gpio, gpiores);
- return;
-}
-EXPORT_SYMBOL(gpio_free);
-
-int gpio_direction_input(unsigned gpio)
-{
- if (likely(ns9xxx_valid_gpio(gpio))) {
- int ret = -EINVAL;
- unsigned long flags;
-
- spin_lock_irqsave(&gpio_lock, flags);
-#if defined(CONFIG_PROCESSOR_NS9360)
- if (processor_is_ns9360())
- ret = __ns9360_gpio_configure(gpio, 0, 0, 3);
- else
-#endif
- BUG();
-
- spin_unlock_irqrestore(&gpio_lock, flags);
-
- return ret;
-
- } else
- return -EINVAL;
-}
-EXPORT_SYMBOL(gpio_direction_input);
-
-int gpio_direction_output(unsigned gpio, int value)
-{
- if (likely(ns9xxx_valid_gpio(gpio))) {
- int ret = -EINVAL;
- unsigned long flags;
-
- gpio_set_value(gpio, value);
-
- spin_lock_irqsave(&gpio_lock, flags);
-#if defined(CONFIG_PROCESSOR_NS9360)
- if (processor_is_ns9360())
- ret = __ns9360_gpio_configure(gpio, 1, 0, 3);
- else
-#endif
- BUG();
-
- spin_unlock_irqrestore(&gpio_lock, flags);
-
- return ret;
- } else
- return -EINVAL;
-}
-EXPORT_SYMBOL(gpio_direction_output);
-
-int gpio_get_value(unsigned gpio)
-{
-#if defined(CONFIG_PROCESSOR_NS9360)
- if (processor_is_ns9360())
- return ns9360_gpio_get_value(gpio);
- else
-#endif
- {
- BUG();
- return -EINVAL;
- }
-}
-EXPORT_SYMBOL(gpio_get_value);
-
-void gpio_set_value(unsigned gpio, int value)
-{
- unsigned long flags;
- spin_lock_irqsave(&gpio_lock, flags);
-#if defined(CONFIG_PROCESSOR_NS9360)
- if (processor_is_ns9360())
- ns9360_gpio_set_value(gpio, value);
- else
-#endif
- BUG();
-
- spin_unlock_irqrestore(&gpio_lock, flags);
-}
-EXPORT_SYMBOL(gpio_set_value);
diff --git a/arch/arm/mach-ns9xxx/include/mach/board.h b/arch/arm/mach-ns9xxx/include/mach/board.h
deleted file mode 100644
index 19ca6de46a45..000000000000
--- a/arch/arm/mach-ns9xxx/include/mach/board.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/include/mach/board.h
- *
- * Copyright (C) 2006,2007 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#ifndef __ASM_ARCH_BOARD_H
-#define __ASM_ARCH_BOARD_H
-
-#include <asm/mach-types.h>
-
-#define board_is_a9m9750dev() (0 \
- || machine_is_cc9p9750dev() \
- )
-
-#define board_is_a9mvali() (0 \
- || machine_is_cc9p9750val() \
- )
-
-#define board_is_jscc9p9210() (0 \
- || machine_is_cc9p9210js() \
- )
-
-#define board_is_jscc9p9215() (0 \
- || machine_is_cc9p9215js() \
- )
-
-#define board_is_jscc9p9360() (0 \
- || machine_is_cc9p9360js() \
- )
-
-#define board_is_uncbas() (0 \
- || machine_is_cc7ucamry() \
- )
-
-#endif /* ifndef __ASM_ARCH_BOARD_H */
diff --git a/arch/arm/mach-ns9xxx/include/mach/debug-macro.S b/arch/arm/mach-ns9xxx/include/mach/debug-macro.S
deleted file mode 100644
index 5a2acbdc3d67..000000000000
--- a/arch/arm/mach-ns9xxx/include/mach/debug-macro.S
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/include/mach/debug-macro.S
- * Copyright (C) 2006 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#include <mach/hardware.h>
-#include <asm/memory.h>
-
-#include <mach/regs-board-a9m9750dev.h>
-
- .macro addruart, rp, rv
- ldr \rp, =NS9XXX_CSxSTAT_PHYS(0)
- ldr \rv, =io_p2v(NS9XXX_CSxSTAT_PHYS(0))
- .endm
-
-#define UART_SHIFT 2
-#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/mach-ns9xxx/include/mach/entry-macro.S b/arch/arm/mach-ns9xxx/include/mach/entry-macro.S
deleted file mode 100644
index 71ca0319b547..000000000000
--- a/arch/arm/mach-ns9xxx/include/mach/entry-macro.S
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/include/mach/entry-macro.S
- *
- * Copyright (C) 2006,2007 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#include <mach/hardware.h>
-#include <mach/regs-sys-common.h>
-
- .macro get_irqnr_preamble, base, tmp
- ldr \base, =SYS_ISRADDR
- .endm
-
- .macro arch_ret_to_user, tmp1, tmp2
- .endm
-
- .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
- ldr \irqstat, [\base, #(SYS_ISA - SYS_ISRADDR)]
- cmp \irqstat, #0
- ldrne \irqnr, [\base]
- .endm
-
- .macro disable_fiq
- .endm
diff --git a/arch/arm/mach-ns9xxx/include/mach/gpio.h b/arch/arm/mach-ns9xxx/include/mach/gpio.h
deleted file mode 100644
index 5eb349032579..000000000000
--- a/arch/arm/mach-ns9xxx/include/mach/gpio.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/include/mach/gpio.h
- *
- * Copyright (C) 2007 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
-*/
-#ifndef __ASM_ARCH_GPIO_H
-#define __ASM_ARCH_GPIO_H
-
-#include <asm/errno.h>
-
-int gpio_request(unsigned gpio, const char *label);
-
-void gpio_free(unsigned gpio);
-
-int ns9xxx_gpio_configure(unsigned gpio, int inv, int func);
-
-int gpio_direction_input(unsigned gpio);
-
-int gpio_direction_output(unsigned gpio, int value);
-
-int gpio_get_value(unsigned gpio);
-
-void gpio_set_value(unsigned gpio, int value);
-
-/*
- * ns9xxx can use gpio pins to trigger an irq, but it's not generic
- * enough to be supported by the gpio_to_irq/irq_to_gpio interface
- */
-static inline int gpio_to_irq(unsigned gpio)
-{
- return -EINVAL;
-}
-
-static inline int irq_to_gpio(unsigned irq)
-{
- return -EINVAL;
-}
-
-/* get the cansleep() stubs */
-#include <asm-generic/gpio.h>
-
-#endif /* ifndef __ASM_ARCH_GPIO_H */
diff --git a/arch/arm/mach-ns9xxx/include/mach/hardware.h b/arch/arm/mach-ns9xxx/include/mach/hardware.h
deleted file mode 100644
index 76631128e11c..000000000000
--- a/arch/arm/mach-ns9xxx/include/mach/hardware.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/include/mach/hardware.h
- *
- * Copyright (C) 2006 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#ifndef __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
-
-/*
- * NetSilicon NS9xxx internal mapping:
- *
- * physical <--> virtual
- * 0x90000000 - 0x906fffff <--> 0xf9000000 - 0xf96fffff
- * 0xa0100000 - 0xa0afffff <--> 0xfa100000 - 0xfaafffff
- */
-#define io_p2v(x) (0xf0000000 \
- + (((x) & 0xf0000000) >> 4) \
- + ((x) & 0x00ffffff))
-
-#define io_v2p(x) ((((x) & 0x0f000000) << 4) \
- + ((x) & 0x00ffffff))
-
-#define __REGSHIFT(mask) ((mask) & (-(mask)))
-
-#define __REGBIT(bit) ((u32)1 << (bit))
-#define __REGBITS(hbit, lbit) ((((u32)1 << ((hbit) - (lbit) + 1)) - 1) << (lbit))
-#define __REGVAL(mask, value) (((value) * __REGSHIFT(mask)) & (mask))
-
-#ifndef __ASSEMBLY__
-
-# define __REG(x) ((void __iomem __force *)io_p2v((x)))
-# define __REG2(x, y) ((void __iomem __force *)(io_p2v((x)) + 4 * (y)))
-
-# define __REGSET(var, field, value) \
- ((var) = (((var) & ~((field) & ~(value))) | (value)))
-
-# define REGSET(var, reg, field, value) \
- __REGSET(var, reg ## _ ## field, reg ## _ ## field ## _ ## value)
-
-# define REGSET_IDX(var, reg, field, idx, value) \
- __REGSET(var, reg ## _ ## field((idx)), reg ## _ ## field ## _ ## value((idx)))
-
-# define REGSETIM(var, reg, field, value) \
- __REGSET(var, reg ## _ ## field, __REGVAL(reg ## _ ## field, (value)))
-
-# define REGSETIM_IDX(var, reg, field, idx, value) \
- __REGSET(var, reg ## _ ## field((idx)), __REGVAL(reg ## _ ## field((idx)), (value)))
-
-# define __REGGET(var, field) \
- (((var) & (field)))
-
-# define REGGET(var, reg, field) \
- __REGGET(var, reg ## _ ## field)
-
-# define REGGET_IDX(var, reg, field, idx) \
- __REGGET(var, reg ## _ ## field((idx)))
-
-# define REGGETIM(var, reg, field) \
- __REGGET(var, reg ## _ ## field) / __REGSHIFT(reg ## _ ## field)
-
-# define REGGETIM_IDX(var, reg, field, idx) \
- __REGGET(var, reg ## _ ## field((idx))) / \
- __REGSHIFT(reg ## _ ## field((idx)))
-
-#else
-
-# define __REG(x) io_p2v(x)
-# define __REG2(x, y) io_p2v((x) + 4 * (y))
-
-#endif
-
-#endif /* ifndef __ASM_ARCH_HARDWARE_H */
diff --git a/arch/arm/mach-ns9xxx/include/mach/io.h b/arch/arm/mach-ns9xxx/include/mach/io.h
deleted file mode 100644
index f08451d2e1bc..000000000000
--- a/arch/arm/mach-ns9xxx/include/mach/io.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/include/mach/io.h
- *
- * Copyright (C) 2006 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#ifndef __ASM_ARCH_IO_H
-#define __ASM_ARCH_IO_H
-
-#define IO_SPACE_LIMIT 0xffffffff /* XXX */
-
-#define __io(a) __typesafe_io(a)
-#define __mem_pci(a) (a)
-#define __mem_isa(a) (IO_BASE + (a))
-
-#endif /* ifndef __ASM_ARCH_IO_H */
diff --git a/arch/arm/mach-ns9xxx/include/mach/irqs.h b/arch/arm/mach-ns9xxx/include/mach/irqs.h
deleted file mode 100644
index 13483949e210..000000000000
--- a/arch/arm/mach-ns9xxx/include/mach/irqs.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/include/mach/irqs.h
- *
- * Copyright (C) 2006,2007 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#ifndef __ASM_ARCH_IRQS_H
-#define __ASM_ARCH_IRQS_H
-
-/* NetSilicon 9360 */
-#define IRQ_NS9XXX_WATCHDOG 0
-#define IRQ_NS9XXX_AHBBUSERR 1
-#define IRQ_NS9360_BBUSAGG 2
-/* irq 3 is reserved for NS9360 */
-#define IRQ_NS9XXX_ETHRX 4
-#define IRQ_NS9XXX_ETHTX 5
-#define IRQ_NS9XXX_ETHPHY 6
-#define IRQ_NS9360_LCD 7
-#define IRQ_NS9360_SERBRX 8
-#define IRQ_NS9360_SERBTX 9
-#define IRQ_NS9360_SERARX 10
-#define IRQ_NS9360_SERATX 11
-#define IRQ_NS9360_SERCRX 12
-#define IRQ_NS9360_SERCTX 13
-#define IRQ_NS9360_I2C 14
-#define IRQ_NS9360_BBUSDMA 15
-#define IRQ_NS9360_TIMER0 16
-#define IRQ_NS9360_TIMER1 17
-#define IRQ_NS9360_TIMER2 18
-#define IRQ_NS9360_TIMER3 19
-#define IRQ_NS9360_TIMER4 20
-#define IRQ_NS9360_TIMER5 21
-#define IRQ_NS9360_TIMER6 22
-#define IRQ_NS9360_TIMER7 23
-#define IRQ_NS9360_RTC 24
-#define IRQ_NS9360_USBHOST 25
-#define IRQ_NS9360_USBDEVICE 26
-#define IRQ_NS9360_IEEE1284 27
-#define IRQ_NS9XXX_EXT0 28
-#define IRQ_NS9XXX_EXT1 29
-#define IRQ_NS9XXX_EXT2 30
-#define IRQ_NS9XXX_EXT3 31
-
-#define BBUS_IRQ(irq) (32 + irq)
-
-#define IRQ_BBUS_DMA BBUS_IRQ(0)
-#define IRQ_BBUS_SERBRX BBUS_IRQ(2)
-#define IRQ_BBUS_SERBTX BBUS_IRQ(3)
-#define IRQ_BBUS_SERARX BBUS_IRQ(4)
-#define IRQ_BBUS_SERATX BBUS_IRQ(5)
-#define IRQ_BBUS_SERCRX BBUS_IRQ(6)
-#define IRQ_BBUS_SERCTX BBUS_IRQ(7)
-#define IRQ_BBUS_SERDRX BBUS_IRQ(8)
-#define IRQ_BBUS_SERDTX BBUS_IRQ(9)
-#define IRQ_BBUS_I2C BBUS_IRQ(10)
-#define IRQ_BBUS_1284 BBUS_IRQ(11)
-#define IRQ_BBUS_UTIL BBUS_IRQ(12)
-#define IRQ_BBUS_RTC BBUS_IRQ(13)
-#define IRQ_BBUS_USBHST BBUS_IRQ(14)
-#define IRQ_BBUS_USBDEV BBUS_IRQ(15)
-#define IRQ_BBUS_AHBDMA1 BBUS_IRQ(24)
-#define IRQ_BBUS_AHBDMA2 BBUS_IRQ(25)
-
-/*
- * these Interrupts are specific for the a9m9750dev board.
- * They are generated by an FPGA that interrupts the CPU on
- * IRQ_NS9360_EXT2
- */
-#define FPGA_IRQ(irq) (64 + irq)
-
-#define IRQ_FPGA_UARTA FPGA_IRQ(0)
-#define IRQ_FPGA_UARTB FPGA_IRQ(1)
-#define IRQ_FPGA_UARTC FPGA_IRQ(2)
-#define IRQ_FPGA_UARTD FPGA_IRQ(3)
-#define IRQ_FPGA_TOUCH FPGA_IRQ(4)
-#define IRQ_FPGA_CF FPGA_IRQ(5)
-#define IRQ_FPGA_CAN0 FPGA_IRQ(6)
-#define IRQ_FPGA_CAN1 FPGA_IRQ(7)
-
-#define NR_IRQS 72
-
-#endif /* __ASM_ARCH_IRQS_H */
diff --git a/arch/arm/mach-ns9xxx/include/mach/memory.h b/arch/arm/mach-ns9xxx/include/mach/memory.h
deleted file mode 100644
index 5c65aee6e7a9..000000000000
--- a/arch/arm/mach-ns9xxx/include/mach/memory.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/include/mach/memory.h
- *
- * Copyright (C) 2006 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
-*/
-#ifndef __ASM_ARCH_MEMORY_H
-#define __ASM_ARCH_MEMORY_H
-
-/* x in [0..3] */
-#define NS9XXX_CSxSTAT_PHYS(x) UL(((x) + 4) << 28)
-
-#define NS9XXX_CS0STAT_LENGTH UL(0x1000)
-#define NS9XXX_CS1STAT_LENGTH UL(0x1000)
-#define NS9XXX_CS2STAT_LENGTH UL(0x1000)
-#define NS9XXX_CS3STAT_LENGTH UL(0x1000)
-
-#define PLAT_PHYS_OFFSET UL(0x00000000)
-
-#endif
diff --git a/arch/arm/mach-ns9xxx/include/mach/module.h b/arch/arm/mach-ns9xxx/include/mach/module.h
deleted file mode 100644
index 628e9752589b..000000000000
--- a/arch/arm/mach-ns9xxx/include/mach/module.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/include/mach/module.h
- *
- * Copyright (C) 2007 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#ifndef __ASM_ARCH_MODULE_H
-#define __ASM_ARCH_MODULE_H
-
-#include <asm/mach-types.h>
-
-#define module_is_cc7ucamry() (0 \
- || machine_is_cc7ucamry() \
- )
-
-#define module_is_cc9c() (0 \
- )
-
-#define module_is_cc9p9210() (0 \
- || machine_is_cc9p9210() \
- || machine_is_cc9p9210js() \
- )
-
-#define module_is_cc9p9215() (0 \
- || machine_is_cc9p9215() \
- || machine_is_cc9p9215js() \
- )
-
-#define module_is_cc9p9360() (0 \
- || machine_is_cc9p9360dev() \
- || machine_is_cc9p9360js() \
- )
-
-#define module_is_cc9p9750() (0 \
- || machine_is_a9m9750() \
- || machine_is_cc9p9750js() \
- || machine_is_cc9p9750val() \
- )
-
-#define module_is_ccw9c() (0 \
- )
-
-#define module_is_inc20otter() (0 \
- || machine_is_inc20otter() \
- )
-
-#define module_is_otter() (0 \
- || machine_is_otter() \
- )
-
-#endif /* ifndef __ASM_ARCH_MODULE_H */
diff --git a/arch/arm/mach-ns9xxx/include/mach/processor-ns9360.h b/arch/arm/mach-ns9xxx/include/mach/processor-ns9360.h
deleted file mode 100644
index f41deda5129e..000000000000
--- a/arch/arm/mach-ns9xxx/include/mach/processor-ns9360.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/include/mach/processor-ns9360.h
- *
- * Copyright (C) 2007 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#ifndef __ASM_ARCH_PROCESSORNS9360_H
-#define __ASM_ARCH_PROCESSORNS9360_H
-
-#include <linux/init.h>
-
-void ns9360_reset(char mode);
-
-unsigned long ns9360_systemclock(void) __attribute__((const));
-
-static inline unsigned long ns9360_cpuclock(void) __attribute__((const));
-static inline unsigned long ns9360_cpuclock(void)
-{
- return ns9360_systemclock() / 2;
-}
-
-void __init ns9360_map_io(void);
-
-extern struct sys_timer ns9360_timer;
-
-int ns9360_gpio_configure(unsigned gpio, int inv, int func);
-
-#endif /* ifndef __ASM_ARCH_PROCESSORNS9360_H */
diff --git a/arch/arm/mach-ns9xxx/include/mach/processor.h b/arch/arm/mach-ns9xxx/include/mach/processor.h
deleted file mode 100644
index 9f77f746a386..000000000000
--- a/arch/arm/mach-ns9xxx/include/mach/processor.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/include/mach/processor.h
- *
- * Copyright (C) 2006,2007 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#ifndef __ASM_ARCH_PROCESSOR_H
-#define __ASM_ARCH_PROCESSOR_H
-
-#include <mach/module.h>
-
-#define processor_is_ns9210() (0 \
- || module_is_cc7ucamry() \
- || module_is_cc9p9210() \
- || module_is_inc20otter() \
- || module_is_otter() \
- )
-
-#define processor_is_ns9215() (0 \
- || module_is_cc9p9215() \
- )
-
-#define processor_is_ns9360() (0 \
- || module_is_cc9p9360() \
- || module_is_cc9c() \
- || module_is_ccw9c() \
- )
-
-#define processor_is_ns9750() (0 \
- || module_is_cc9p9750() \
- )
-
-#define processor_is_ns921x() (0 \
- || processor_is_ns9210() \
- || processor_is_ns9215() \
- )
-
-#endif /* ifndef __ASM_ARCH_PROCESSOR_H */
diff --git a/arch/arm/mach-ns9xxx/include/mach/regs-bbu.h b/arch/arm/mach-ns9xxx/include/mach/regs-bbu.h
deleted file mode 100644
index af227c058fb9..000000000000
--- a/arch/arm/mach-ns9xxx/include/mach/regs-bbu.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/include/mach/regs-bbu.h
- *
- * Copyright (C) 2006 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#ifndef __ASM_ARCH_REGSBBU_H
-#define __ASM_ARCH_REGSBBU_H
-
-#include <mach/hardware.h>
-
-/* BBus Utility */
-
-/* GPIO Configuration Registers block 1 */
-/* NOTE: the HRM starts counting at 1 for the GPIO registers, here the start is
- * at 0 for each block. That is, BBU_GCONFb1(0) is GPIO Configuration Register
- * #1, BBU_GCONFb2(0) is GPIO Configuration Register #8. */
-#define BBU_GCONFb1(x) __REG2(0x90600010, (x))
-#define BBU_GCONFb2(x) __REG2(0x90600100, (x))
-
-#define BBU_GCONFx_DIR(m) __REGBIT(3 + (((m) & 7) << 2))
-#define BBU_GCONFx_DIR_INPUT(m) __REGVAL(BBU_GCONFx_DIR(m), 0)
-#define BBU_GCONFx_DIR_OUTPUT(m) __REGVAL(BBU_GCONFx_DIR(m), 1)
-#define BBU_GCONFx_INV(m) __REGBIT(2 + (((m) & 7) << 2))
-#define BBU_GCONFx_INV_NO(m) __REGVAL(BBU_GCONFx_INV(m), 0)
-#define BBU_GCONFx_INV_YES(m) __REGVAL(BBU_GCONFx_INV(m), 1)
-#define BBU_GCONFx_FUNC(m) __REGBITS(1 + (((m) & 7) << 2), ((m) & 7) << 2)
-#define BBU_GCONFx_FUNC_0(m) __REGVAL(BBU_GCONFx_FUNC(m), 0)
-#define BBU_GCONFx_FUNC_1(m) __REGVAL(BBU_GCONFx_FUNC(m), 1)
-#define BBU_GCONFx_FUNC_2(m) __REGVAL(BBU_GCONFx_FUNC(m), 2)
-#define BBU_GCONFx_FUNC_3(m) __REGVAL(BBU_GCONFx_FUNC(m), 3)
-
-#define BBU_GCTRL1 __REG(0x90600030)
-#define BBU_GCTRL2 __REG(0x90600034)
-#define BBU_GCTRL3 __REG(0x90600120)
-
-#define BBU_GSTAT1 __REG(0x90600040)
-#define BBU_GSTAT2 __REG(0x90600044)
-#define BBU_GSTAT3 __REG(0x90600130)
-
-#endif /* ifndef __ASM_ARCH_REGSBBU_H */
diff --git a/arch/arm/mach-ns9xxx/include/mach/regs-board-a9m9750dev.h b/arch/arm/mach-ns9xxx/include/mach/regs-board-a9m9750dev.h
deleted file mode 100644
index cd1593693f56..000000000000
--- a/arch/arm/mach-ns9xxx/include/mach/regs-board-a9m9750dev.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/include/mach/regs-board-a9m9750dev.h
- *
- * Copyright (C) 2006 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#ifndef __ASM_ARCH_REGSBOARDA9M9750_H
-#define __ASM_ARCH_REGSBOARDA9M9750_H
-
-#include <mach/hardware.h>
-
-#define FPGA_UARTA_BASE io_p2v(NS9XXX_CSxSTAT_PHYS(0))
-#define FPGA_UARTB_BASE io_p2v(NS9XXX_CSxSTAT_PHYS(0) + 0x08)
-#define FPGA_UARTC_BASE io_p2v(NS9XXX_CSxSTAT_PHYS(0) + 0x10)
-#define FPGA_UARTD_BASE io_p2v(NS9XXX_CSxSTAT_PHYS(0) + 0x18)
-
-#define FPGA_IER __REG(NS9XXX_CSxSTAT_PHYS(0) + 0x50)
-#define FPGA_ISR __REG(NS9XXX_CSxSTAT_PHYS(0) + 0x60)
-
-#endif /* ifndef __ASM_ARCH_REGSBOARDA9M9750_H */
diff --git a/arch/arm/mach-ns9xxx/include/mach/regs-mem.h b/arch/arm/mach-ns9xxx/include/mach/regs-mem.h
deleted file mode 100644
index f1625bf8cdce..000000000000
--- a/arch/arm/mach-ns9xxx/include/mach/regs-mem.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/include/mach/regs-mem.h
- *
- * Copyright (C) 2006 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#ifndef __ASM_ARCH_REGSMEM_H
-#define __ASM_ARCH_REGSMEM_H
-
-#include <mach/hardware.h>
-
-/* Memory Module */
-
-/* Control register */
-#define MEM_CTRL __REG(0xa0700000)
-
-/* Status register */
-#define MEM_STAT __REG(0xa0700004)
-
-/* Configuration register */
-#define MEM_CONF __REG(0xa0700008)
-
-/* Dynamic Memory Control register */
-#define MEM_DMCTRL __REG(0xa0700020)
-
-/* Dynamic Memory Refresh Timer */
-#define MEM_DMRT __REG(0xa0700024)
-
-/* Dynamic Memory Read Configuration register */
-#define MEM_DMRC __REG(0xa0700028)
-
-/* Dynamic Memory Precharge Command Period (tRP) */
-#define MEM_DMPCP __REG(0xa0700030)
-
-/* Dynamic Memory Active to Precharge Command Period (tRAS) */
-#define MEM_DMAPCP __REG(0xa0700034)
-
-/* Dynamic Memory Self-Refresh Exit Time (tSREX) */
-#define MEM_DMSRET __REG(0xa0700038)
-
-/* Dynamic Memory Last Data Out to Active Time (tAPR) */
-#define MEM_DMLDOAT __REG(0xa070003c)
-
-/* Dynamic Memory Data-in to Active Command Time (tDAL or TAPW) */
-#define MEM_DMDIACT __REG(0xa0700040)
-
-/* Dynamic Memory Write Recovery Time (tWR, tDPL, tRWL, tRDL) */
-#define MEM_DMWRT __REG(0xa0700044)
-
-/* Dynamic Memory Active to Active Command Period (tRC) */
-#define MEM_DMAACP __REG(0xa0700048)
-
-/* Dynamic Memory Auto Refresh Period, and Auto Refresh to Active Command Period (tRFC) */
-#define MEM_DMARP __REG(0xa070004c)
-
-/* Dynamic Memory Exit Self-Refresh to Active Command (tXSR) */
-#define MEM_DMESRAC __REG(0xa0700050)
-
-/* Dynamic Memory Active Bank A to Active B Time (tRRD) */
-#define MEM_DMABAABT __REG(0xa0700054)
-
-/* Dynamic Memory Load Mode register to Active Command Time (tMRD) */
-#define MEM_DMLMACT __REG(0xa0700058)
-
-/* Static Memory Extended Wait */
-#define MEM_SMEW __REG(0xa0700080)
-
-/* Dynamic Memory Configuration Register x */
-#define MEM_DMCONF(x) __REG2(0xa0700100, (x) << 3)
-
-/* Dynamic Memory RAS and CAS Delay x */
-#define MEM_DMRCD(x) __REG2(0xa0700104, (x) << 3)
-
-/* Static Memory Configuration Register x */
-#define MEM_SMC(x) __REG2(0xa0700200, (x) << 3)
-
-/* Static Memory Configuration Register x: Write protect */
-#define MEM_SMC_PSMC __REGBIT(20)
-#define MEM_SMC_PSMC_OFF __REGVAL(MEM_SMC_PSMC, 0)
-#define MEM_SMC_PSMC_ON __REGVAL(MEM_SMC_PSMC, 1)
-
-/* Static Memory Configuration Register x: Buffer enable */
-#define MEM_SMC_BSMC __REGBIT(19)
-#define MEM_SMC_BSMC_OFF __REGVAL(MEM_SMC_BSMC, 0)
-#define MEM_SMC_BSMC_ON __REGVAL(MEM_SMC_BSMC, 1)
-
-/* Static Memory Configuration Register x: Extended Wait */
-#define MEM_SMC_EW __REGBIT(8)
-#define MEM_SMC_EW_OFF __REGVAL(MEM_SMC_EW, 0)
-#define MEM_SMC_EW_ON __REGVAL(MEM_SMC_EW, 1)
-
-/* Static Memory Configuration Register x: Byte lane state */
-#define MEM_SMC_PB __REGBIT(7)
-#define MEM_SMC_PB_0 __REGVAL(MEM_SMC_PB, 0)
-#define MEM_SMC_PB_1 __REGVAL(MEM_SMC_PB, 1)
-
-/* Static Memory Configuration Register x: Chip select polarity */
-#define MEM_SMC_PC __REGBIT(6)
-#define MEM_SMC_PC_AL __REGVAL(MEM_SMC_PC, 0)
-#define MEM_SMC_PC_AH __REGVAL(MEM_SMC_PC, 1)
-
-/* static memory configuration register x: page mode*/
-#define MEM_SMC_PM __REGBIT(3)
-#define MEM_SMC_PM_DIS __REGVAL(MEM_SMC_PM, 0)
-#define MEM_SMC_PM_ASYNC __REGVAL(MEM_SMC_PM, 1)
-
-/* static memory configuration register x: Memory width */
-#define MEM_SMC_MW __REGBITS(1, 0)
-#define MEM_SMC_MW_8 __REGVAL(MEM_SMC_MW, 0)
-#define MEM_SMC_MW_16 __REGVAL(MEM_SMC_MW, 1)
-#define MEM_SMC_MW_32 __REGVAL(MEM_SMC_MW, 2)
-
-/* Static Memory Write Enable Delay x */
-#define MEM_SMWED(x) __REG2(0xa0700204, (x) << 3)
-
-/* Static Memory Output Enable Delay x */
-#define MEM_SMOED(x) __REG2(0xa0700208, (x) << 3)
-
-/* Static Memory Read Delay x */
-#define MEM_SMRD(x) __REG2(0xa070020c, (x) << 3)
-
-/* Static Memory Page Mode Read Delay 0 */
-#define MEM_SMPMRD(x) __REG2(0xa0700210, (x) << 3)
-
-/* Static Memory Write Delay */
-#define MEM_SMWD(x) __REG2(0xa0700214, (x) << 3)
-
-/* Static Memory Turn Round Delay x */
-#define MEM_SWT(x) __REG2(0xa0700218, (x) << 3)
-
-#endif /* ifndef __ASM_ARCH_REGSMEM_H */
diff --git a/arch/arm/mach-ns9xxx/include/mach/regs-sys-common.h b/arch/arm/mach-ns9xxx/include/mach/regs-sys-common.h
deleted file mode 100644
index 14f91dfd5736..000000000000
--- a/arch/arm/mach-ns9xxx/include/mach/regs-sys-common.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/include/mach/regs-sys-common.h
- *
- * Copyright (C) 2007 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-
-#ifndef __ASM_ARCH_REGSSYSCOMMON_H
-#define __ASM_ARCH_REGSSYSCOMMON_H
-#include <mach/hardware.h>
-
-/* Interrupt Vector Address Register Level x */
-#define SYS_IVA(x) __REG2(0xa09000c4, (x))
-
-/* Interrupt Configuration registers */
-#define SYS_IC(x) __REG2(0xa0900144, (x))
-
-/* ISRADDR */
-#define SYS_ISRADDR __REG(0xa0900164)
-
-/* Interrupt Status Active */
-#define SYS_ISA __REG(0xa0900168)
-
-/* Interrupt Status Raw */
-#define SYS_ISR __REG(0xa090016c)
-
-#endif /* ifndef __ASM_ARCH_REGSSYSCOMMON_H */
diff --git a/arch/arm/mach-ns9xxx/include/mach/regs-sys-ns9360.h b/arch/arm/mach-ns9xxx/include/mach/regs-sys-ns9360.h
deleted file mode 100644
index 8ff254d9901c..000000000000
--- a/arch/arm/mach-ns9xxx/include/mach/regs-sys-ns9360.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/include/mach/regs-sys-ns9360.h
- *
- * Copyright (C) 2006,2007 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#ifndef __ASM_ARCH_REGSSYSNS9360_H
-#define __ASM_ARCH_REGSSYSNS9360_H
-
-#include <mach/hardware.h>
-
-/* System Control Module */
-
-/* AHB Arbiter Gen Configuration */
-#define SYS_AHBAGENCONF __REG(0xa0900000)
-
-/* BRC */
-#define SYS_BRC(x) __REG2(0xa0900004, (x))
-
-/* Timer x Reload Count register */
-#define SYS_TRC(x) __REG2(0xa0900044, (x))
-
-/* Timer x Read register */
-#define SYS_TR(x) __REG2(0xa0900084, (x))
-
-/* Timer Interrupt Status register */
-#define SYS_TIS __REG(0xa0900170)
-
-/* PLL Configuration register */
-#define SYS_PLL __REG(0xa0900188)
-
-/* PLL FS status */
-#define SYS_PLL_FS __REGBITS(24, 23)
-
-/* PLL ND status */
-#define SYS_PLL_ND __REGBITS(20, 16)
-
-/* PLL Configuration register: PLL SW change */
-#define SYS_PLL_SWC __REGBIT(15)
-#define SYS_PLL_SWC_NO __REGVAL(SYS_PLL_SWC, 0)
-#define SYS_PLL_SWC_YES __REGVAL(SYS_PLL_SWC, 1)
-
-/* Timer x Control register */
-#define SYS_TC(x) __REG2(0xa0900190, (x))
-
-/* Timer x Control register: Timer enable */
-#define SYS_TCx_TEN __REGBIT(15)
-#define SYS_TCx_TEN_DIS __REGVAL(SYS_TCx_TEN, 0)
-#define SYS_TCx_TEN_EN __REGVAL(SYS_TCx_TEN, 1)
-
-/* Timer x Control register: CPU debug mode */
-#define SYS_TCx_TDBG __REGBIT(10)
-#define SYS_TCx_TDBG_CONT __REGVAL(SYS_TCx_TDBG, 0)
-#define SYS_TCx_TDBG_STOP __REGVAL(SYS_TCx_TDBG, 1)
-
-/* Timer x Control register: Interrupt clear */
-#define SYS_TCx_INTC __REGBIT(9)
-#define SYS_TCx_INTC_UNSET __REGVAL(SYS_TCx_INTC, 0)
-#define SYS_TCx_INTC_SET __REGVAL(SYS_TCx_INTC, 1)
-
-/* Timer x Control register: Timer clock select */
-#define SYS_TCx_TLCS __REGBITS(8, 6)
-#define SYS_TCx_TLCS_CPU __REGVAL(SYS_TCx_TLCS, 0) /* CPU clock */
-#define SYS_TCx_TLCS_DIV2 __REGVAL(SYS_TCx_TLCS, 1) /* CPU clock / 2 */
-#define SYS_TCx_TLCS_DIV4 __REGVAL(SYS_TCx_TLCS, 2) /* CPU clock / 4 */
-#define SYS_TCx_TLCS_DIV8 __REGVAL(SYS_TCx_TLCS, 3) /* CPU clock / 8 */
-#define SYS_TCx_TLCS_DIV16 __REGVAL(SYS_TCx_TLCS, 4) /* CPU clock / 16 */
-#define SYS_TCx_TLCS_DIV32 __REGVAL(SYS_TCx_TLCS, 5) /* CPU clock / 32 */
-#define SYS_TCx_TLCS_DIV64 __REGVAL(SYS_TCx_TLCS, 6) /* CPU clock / 64 */
-#define SYS_TCx_TLCS_EXT __REGVAL(SYS_TCx_TLCS, 7)
-
-/* Timer x Control register: Timer mode */
-#define SYS_TCx_TM __REGBITS(5, 4)
-#define SYS_TCx_TM_IEE __REGVAL(SYS_TCx_TM, 0) /* Internal timer or external event */
-#define SYS_TCx_TM_ELL __REGVAL(SYS_TCx_TM, 1) /* External low-level, gated timer */
-#define SYS_TCx_TM_EHL __REGVAL(SYS_TCx_TM, 2) /* External high-level, gated timer */
-#define SYS_TCx_TM_CONCAT __REGVAL(SYS_TCx_TM, 3) /* Concatenate the lower timer. */
-
-/* Timer x Control register: Interrupt select */
-#define SYS_TCx_INTS __REGBIT(3)
-#define SYS_TCx_INTS_DIS __REGVAL(SYS_TCx_INTS, 0)
-#define SYS_TCx_INTS_EN __REGVAL(SYS_TCx_INTS, 1)
-
-/* Timer x Control register: Up/down select */
-#define SYS_TCx_UDS __REGBIT(2)
-#define SYS_TCx_UDS_UP __REGVAL(SYS_TCx_UDS, 0)
-#define SYS_TCx_UDS_DOWN __REGVAL(SYS_TCx_UDS, 1)
-
-/* Timer x Control register: 32- or 16-bit timer */
-#define SYS_TCx_TSZ __REGBIT(1)
-#define SYS_TCx_TSZ_16 __REGVAL(SYS_TCx_TSZ, 0)
-#define SYS_TCx_TSZ_32 __REGVAL(SYS_TCx_TSZ, 1)
-
-/* Timer x Control register: Reload enable */
-#define SYS_TCx_REN __REGBIT(0)
-#define SYS_TCx_REN_DIS __REGVAL(SYS_TCx_REN, 0)
-#define SYS_TCx_REN_EN __REGVAL(SYS_TCx_REN, 1)
-
-/* System Memory Chip Select x Dynamic Memory Base */
-#define SYS_SMCSDMB(x) __REG2(0xa09001d0, (x) << 1)
-
-/* System Memory Chip Select x Dynamic Memory Mask */
-#define SYS_SMCSDMM(x) __REG2(0xa09001d4, (x) << 1)
-
-/* System Memory Chip Select x Static Memory Base */
-#define SYS_SMCSSMB(x) __REG2(0xa09001f0, (x) << 1)
-
-/* System Memory Chip Select x Static Memory Base: Chip select x base */
-#define SYS_SMCSSMB_CSxB __REGBITS(31, 12)
-
-/* System Memory Chip Select x Static Memory Mask */
-#define SYS_SMCSSMM(x) __REG2(0xa09001f4, (x) << 1)
-
-/* System Memory Chip Select x Static Memory Mask: Chip select x mask */
-#define SYS_SMCSSMM_CSxM __REGBITS(31, 12)
-
-/* System Memory Chip Select x Static Memory Mask: Chip select x enable */
-#define SYS_SMCSSMM_CSEx __REGBIT(0)
-#define SYS_SMCSSMM_CSEx_DIS __REGVAL(SYS_SMCSSMM_CSEx, 0)
-#define SYS_SMCSSMM_CSEx_EN __REGVAL(SYS_SMCSSMM_CSEx, 1)
-
-/* General purpose, user-defined ID register */
-#define SYS_GENID __REG(0xa0900210)
-
-/* External Interrupt x Control register */
-#define SYS_EIC(x) __REG2(0xa0900214, (x))
-
-/* External Interrupt x Control register: Status */
-#define SYS_EIC_STS __REGBIT(3)
-
-/* External Interrupt x Control register: Clear */
-#define SYS_EIC_CLR __REGBIT(2)
-
-/* External Interrupt x Control register: Polarity */
-#define SYS_EIC_PLTY __REGBIT(1)
-#define SYS_EIC_PLTY_AH __REGVAL(SYS_EIC_PLTY, 0)
-#define SYS_EIC_PLTY_AL __REGVAL(SYS_EIC_PLTY, 1)
-
-/* External Interrupt x Control register: Level edge */
-#define SYS_EIC_LVEDG __REGBIT(0)
-#define SYS_EIC_LVEDG_LEVEL __REGVAL(SYS_EIC_LVEDG, 0)
-#define SYS_EIC_LVEDG_EDGE __REGVAL(SYS_EIC_LVEDG, 1)
-
-#endif /* ifndef __ASM_ARCH_REGSSYSNS9360_H */
diff --git a/arch/arm/mach-ns9xxx/include/mach/system.h b/arch/arm/mach-ns9xxx/include/mach/system.h
deleted file mode 100644
index 1561588ca364..000000000000
--- a/arch/arm/mach-ns9xxx/include/mach/system.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/include/mach/system.h
- *
- * Copyright (C) 2006,2007 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-#include <asm/proc-fns.h>
-#include <mach/processor.h>
-#include <mach/processor-ns9360.h>
-
-static inline void arch_idle(void)
-{
- cpu_do_idle();
-}
-
-static inline void arch_reset(char mode, const char *cmd)
-{
-#ifdef CONFIG_PROCESSOR_NS9360
- if (processor_is_ns9360())
- ns9360_reset(mode);
- else
-#endif
- BUG();
-
- BUG();
-}
-
-#endif /* ifndef __ASM_ARCH_SYSTEM_H */
diff --git a/arch/arm/mach-ns9xxx/include/mach/timex.h b/arch/arm/mach-ns9xxx/include/mach/timex.h
deleted file mode 100644
index 734a8d8bd578..000000000000
--- a/arch/arm/mach-ns9xxx/include/mach/timex.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/include/mach/timex.h
- *
- * Copyright (C) 2005-2006 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#ifndef __ASM_ARCH_TIMEX_H
-#define __ASM_ARCH_TIMEX_H
-
-/*
- * value for CLOCK_TICK_RATE stolen from arch/arm/mach-s3c2410/include/mach/timex.h.
- * See there for an explanation.
- */
-#define CLOCK_TICK_RATE 12000000
-
-#endif /* ifndef __ASM_ARCH_TIMEX_H */
diff --git a/arch/arm/mach-ns9xxx/include/mach/uncompress.h b/arch/arm/mach-ns9xxx/include/mach/uncompress.h
deleted file mode 100644
index 770a68c46e81..000000000000
--- a/arch/arm/mach-ns9xxx/include/mach/uncompress.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/include/mach/uncompress.h
- *
- * Copyright (C) 2006 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#ifndef __ASM_ARCH_UNCOMPRESS_H
-#define __ASM_ARCH_UNCOMPRESS_H
-
-#include <linux/io.h>
-
-#define __REG(x) ((void __iomem __force *)(x))
-
-static void putc_dummy(char c, void __iomem *base)
-{
- /* nothing */
-}
-
-static int timeout;
-
-static void putc_ns9360(char c, void __iomem *base)
-{
- do {
- if (timeout)
- --timeout;
-
- if (__raw_readl(base + 8) & (1 << 3)) {
- __raw_writeb(c, base + 16);
- timeout = 0x10000;
- break;
- }
- } while (timeout);
-}
-
-static void putc_a9m9750dev(char c, void __iomem *base)
-{
- do {
- if (timeout)
- --timeout;
-
- if (__raw_readb(base + 5) & (1 << 5)) {
- __raw_writeb(c, base);
- timeout = 0x10000;
- break;
- }
- } while (timeout);
-
-}
-
-static void putc_ns921x(char c, void __iomem *base)
-{
- do {
- if (timeout)
- --timeout;
-
- if (!(__raw_readl(base) & (1 << 11))) {
- __raw_writeb(c, base + 0x0028);
- timeout = 0x10000;
- break;
- }
- } while (timeout);
-}
-
-#define MSCS __REG(0xA0900184)
-
-#define NS9360_UARTA __REG(0x90200040)
-#define NS9360_UARTB __REG(0x90200000)
-#define NS9360_UARTC __REG(0x90300000)
-#define NS9360_UARTD __REG(0x90300040)
-
-#define NS9360_UART_ENABLED(base) \
- (__raw_readl(NS9360_UARTA) & (1 << 31))
-
-#define A9M9750DEV_UARTA __REG(0x40000000)
-
-#define NS921XSYS_CLOCK __REG(0xa090017c)
-#define NS921X_UARTA __REG(0x90010000)
-#define NS921X_UARTB __REG(0x90018000)
-#define NS921X_UARTC __REG(0x90020000)
-#define NS921X_UARTD __REG(0x90028000)
-
-#define NS921X_UART_ENABLED(base) \
- (__raw_readl((base) + 0x1000) & (1 << 29))
-
-static void autodetect(void (**putc)(char, void __iomem *), void __iomem **base)
-{
- timeout = 0x10000;
- if (((__raw_readl(MSCS) >> 16) & 0xfe) == 0x00) {
- /* ns9360 or ns9750 */
- if (NS9360_UART_ENABLED(NS9360_UARTA)) {
- *putc = putc_ns9360;
- *base = NS9360_UARTA;
- return;
- } else if (NS9360_UART_ENABLED(NS9360_UARTB)) {
- *putc = putc_ns9360;
- *base = NS9360_UARTB;
- return;
- } else if (NS9360_UART_ENABLED(NS9360_UARTC)) {
- *putc = putc_ns9360;
- *base = NS9360_UARTC;
- return;
- } else if (NS9360_UART_ENABLED(NS9360_UARTD)) {
- *putc = putc_ns9360;
- *base = NS9360_UARTD;
- return;
- } else if (__raw_readl(__REG(0xa09001f4)) == 0xfffff001) {
- *putc = putc_a9m9750dev;
- *base = A9M9750DEV_UARTA;
- return;
- }
- } else if (((__raw_readl(MSCS) >> 16) & 0xfe) == 0x02) {
- /* ns921x */
- u32 clock = __raw_readl(NS921XSYS_CLOCK);
-
- if ((clock & (1 << 1)) &&
- NS921X_UART_ENABLED(NS921X_UARTA)) {
- *putc = putc_ns921x;
- *base = NS921X_UARTA;
- return;
- } else if ((clock & (1 << 2)) &&
- NS921X_UART_ENABLED(NS921X_UARTB)) {
- *putc = putc_ns921x;
- *base = NS921X_UARTB;
- return;
- } else if ((clock & (1 << 3)) &&
- NS921X_UART_ENABLED(NS921X_UARTC)) {
- *putc = putc_ns921x;
- *base = NS921X_UARTC;
- return;
- } else if ((clock & (1 << 4)) &&
- NS921X_UART_ENABLED(NS921X_UARTD)) {
- *putc = putc_ns921x;
- *base = NS921X_UARTD;
- return;
- }
- }
-
- *putc = putc_dummy;
-}
-
-void (*myputc)(char, void __iomem *);
-void __iomem *base;
-
-static void putc(char c)
-{
- myputc(c, base);
-}
-
-static void arch_decomp_setup(void)
-{
- autodetect(&myputc, &base);
-}
-#define arch_decomp_wdog()
-
-static void flush(void)
-{
- /* nothing */
-}
-
-#endif /* ifndef __ASM_ARCH_UNCOMPRESS_H */
diff --git a/arch/arm/mach-ns9xxx/include/mach/vmalloc.h b/arch/arm/mach-ns9xxx/include/mach/vmalloc.h
deleted file mode 100644
index c8651974c4b0..000000000000
--- a/arch/arm/mach-ns9xxx/include/mach/vmalloc.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/include/mach/vmalloc.h
- *
- * Copyright (C) 2006 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#ifndef __ASM_ARCH_VMALLOC_H
-#define __ASM_ARCH_VMALLOC_H
-
-#define VMALLOC_END (0xf0000000UL)
-
-#endif /* ifndef __ASM_ARCH_VMALLOC_H */
diff --git a/arch/arm/mach-ns9xxx/irq.c b/arch/arm/mach-ns9xxx/irq.c
deleted file mode 100644
index 37ab0a2b83ad..000000000000
--- a/arch/arm/mach-ns9xxx/irq.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/irq.c
- *
- * Copyright (C) 2006,2007 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#include <linux/interrupt.h>
-#include <linux/kernel_stat.h>
-#include <linux/io.h>
-#include <asm/mach/irq.h>
-#include <mach/regs-sys-common.h>
-#include <mach/irqs.h>
-#include <mach/board.h>
-
-#include "generic.h"
-
-/* simple interrupt prio table: prio(x) < prio(y) <=> x < y */
-#define irq2prio(i) (i)
-#define prio2irq(p) (p)
-
-static void ns9xxx_mask_irq(struct irq_data *d)
-{
- /* XXX: better use cpp symbols */
- int prio = irq2prio(d->irq);
- u32 ic = __raw_readl(SYS_IC(prio / 4));
- ic &= ~(1 << (7 + 8 * (3 - (prio & 3))));
- __raw_writel(ic, SYS_IC(prio / 4));
-}
-
-static void ns9xxx_eoi_irq(struct irq_data *d)
-{
- __raw_writel(0, SYS_ISRADDR);
-}
-
-static void ns9xxx_unmask_irq(struct irq_data *d)
-{
- /* XXX: better use cpp symbols */
- int prio = irq2prio(d->irq);
- u32 ic = __raw_readl(SYS_IC(prio / 4));
- ic |= 1 << (7 + 8 * (3 - (prio & 3)));
- __raw_writel(ic, SYS_IC(prio / 4));
-}
-
-static struct irq_chip ns9xxx_chip = {
- .irq_eoi = ns9xxx_eoi_irq,
- .irq_mask = ns9xxx_mask_irq,
- .irq_unmask = ns9xxx_unmask_irq,
-};
-
-void __init ns9xxx_init_irq(void)
-{
- int i;
-
- /* disable all IRQs */
- for (i = 0; i < 8; ++i)
- __raw_writel(prio2irq(4 * i) << 24 |
- prio2irq(4 * i + 1) << 16 |
- prio2irq(4 * i + 2) << 8 |
- prio2irq(4 * i + 3),
- SYS_IC(i));
-
- for (i = 0; i < 32; ++i)
- __raw_writel(prio2irq(i), SYS_IVA(i));
-
- for (i = 0; i <= 31; ++i) {
- irq_set_chip_and_handler(i, &ns9xxx_chip, handle_fasteoi_irq);
- set_irq_flags(i, IRQF_VALID);
- irq_set_status_flags(i, IRQ_LEVEL);
- }
-}
diff --git a/arch/arm/mach-ns9xxx/mach-cc9p9360dev.c b/arch/arm/mach-ns9xxx/mach-cc9p9360dev.c
deleted file mode 100644
index 2858417d8d8a..000000000000
--- a/arch/arm/mach-ns9xxx/mach-cc9p9360dev.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/mach-cc9p9360dev.c
- *
- * Copyright (C) 2006,2007 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#include <asm/mach/arch.h>
-#include <asm/mach-types.h>
-
-#include <mach/processor-ns9360.h>
-
-#include "board-a9m9750dev.h"
-#include "generic.h"
-
-static void __init mach_cc9p9360dev_map_io(void)
-{
- ns9360_map_io();
- board_a9m9750dev_map_io();
-}
-
-static void __init mach_cc9p9360dev_init_irq(void)
-{
- ns9xxx_init_irq();
- board_a9m9750dev_init_irq();
-}
-
-static void __init mach_cc9p9360dev_init_machine(void)
-{
- ns9xxx_init_machine();
- board_a9m9750dev_init_machine();
-}
-
-MACHINE_START(CC9P9360DEV, "Digi ConnectCore 9P 9360 on an A9M9750 Devboard")
- .map_io = mach_cc9p9360dev_map_io,
- .init_irq = mach_cc9p9360dev_init_irq,
- .init_machine = mach_cc9p9360dev_init_machine,
- .timer = &ns9360_timer,
- .boot_params = 0x100,
-MACHINE_END
diff --git a/arch/arm/mach-ns9xxx/mach-cc9p9360js.c b/arch/arm/mach-ns9xxx/mach-cc9p9360js.c
deleted file mode 100644
index 729f68da4293..000000000000
--- a/arch/arm/mach-ns9xxx/mach-cc9p9360js.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/mach-cc9p9360js.c
- *
- * Copyright (C) 2006,2007 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#include <asm/mach/arch.h>
-#include <asm/mach-types.h>
-
-#include <mach/processor-ns9360.h>
-
-#include "board-jscc9p9360.h"
-#include "generic.h"
-
-static void __init mach_cc9p9360js_init_machine(void)
-{
- ns9xxx_init_machine();
- board_jscc9p9360_init_machine();
-}
-
-MACHINE_START(CC9P9360JS, "Digi ConnectCore 9P 9360 on an JSCC9P9360 Devboard")
- .map_io = ns9360_map_io,
- .init_irq = ns9xxx_init_irq,
- .init_machine = mach_cc9p9360js_init_machine,
- .timer = &ns9360_timer,
- .boot_params = 0x100,
-MACHINE_END
diff --git a/arch/arm/mach-ns9xxx/plat-serial8250.c b/arch/arm/mach-ns9xxx/plat-serial8250.c
deleted file mode 100644
index 463e92465fda..000000000000
--- a/arch/arm/mach-ns9xxx/plat-serial8250.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/plat-serial8250.c
- *
- * Copyright (C) 2008 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#include <linux/platform_device.h>
-#include <linux/serial_8250.h>
-#include <linux/slab.h>
-
-#include <mach/regs-board-a9m9750dev.h>
-#include <mach/board.h>
-
-#define DRIVER_NAME "serial8250"
-
-static int __init ns9xxx_plat_serial8250_init(void)
-{
- struct plat_serial8250_port *pdata;
- struct platform_device *pdev;
- int ret = -ENOMEM;
- int i;
-
- if (!board_is_a9m9750dev())
- return -ENODEV;
-
- pdev = platform_device_alloc(DRIVER_NAME, 0);
- if (!pdev)
- goto err;
-
- pdata = kzalloc(5 * sizeof(*pdata), GFP_KERNEL);
- if (!pdata)
- goto err;
-
- pdev->dev.platform_data = pdata;
-
- pdata[0].iobase = FPGA_UARTA_BASE;
- pdata[1].iobase = FPGA_UARTB_BASE;
- pdata[2].iobase = FPGA_UARTC_BASE;
- pdata[3].iobase = FPGA_UARTD_BASE;
-
- for (i = 0; i < 4; ++i) {
- pdata[i].membase = (void __iomem *)pdata[i].iobase;
- pdata[i].mapbase = pdata[i].iobase;
- pdata[i].iotype = UPIO_MEM;
- pdata[i].uartclk = 18432000;
- pdata[i].flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
- }
-
- pdata[0].irq = IRQ_FPGA_UARTA;
- pdata[1].irq = IRQ_FPGA_UARTB;
- pdata[2].irq = IRQ_FPGA_UARTC;
- pdata[3].irq = IRQ_FPGA_UARTD;
-
- ret = platform_device_add(pdev);
- if (ret) {
-err:
- platform_device_put(pdev);
-
- printk(KERN_WARNING "Could not add %s (errno=%d)\n",
- DRIVER_NAME, ret);
- }
-
- return 0;
-}
-
-arch_initcall(ns9xxx_plat_serial8250_init);
diff --git a/arch/arm/mach-ns9xxx/processor-ns9360.c b/arch/arm/mach-ns9xxx/processor-ns9360.c
deleted file mode 100644
index aed1999d24fc..000000000000
--- a/arch/arm/mach-ns9xxx/processor-ns9360.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/processor-ns9360.c
- *
- * Copyright (C) 2007 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#include <linux/io.h>
-#include <linux/kernel.h>
-
-#include <asm/page.h>
-#include <asm/mach/map.h>
-#include <mach/processor-ns9360.h>
-#include <mach/regs-sys-ns9360.h>
-
-void ns9360_reset(char mode)
-{
- u32 reg;
-
- reg = __raw_readl(SYS_PLL) >> 16;
- REGSET(reg, SYS_PLL, SWC, YES);
- __raw_writel(reg, SYS_PLL);
-}
-
-#define CRYSTAL 29491200 /* Hz */
-unsigned long ns9360_systemclock(void)
-{
- u32 pll = __raw_readl(SYS_PLL);
- return CRYSTAL * (REGGETIM(pll, SYS_PLL, ND) + 1)
- >> REGGETIM(pll, SYS_PLL, FS);
-}
-
-static struct map_desc ns9360_io_desc[] __initdata = {
- { /* BBus */
- .virtual = io_p2v(0x90000000),
- .pfn = __phys_to_pfn(0x90000000),
- .length = 0x00700000,
- .type = MT_DEVICE,
- }, { /* AHB */
- .virtual = io_p2v(0xa0100000),
- .pfn = __phys_to_pfn(0xa0100000),
- .length = 0x00900000,
- .type = MT_DEVICE,
- },
-};
-
-void __init ns9360_map_io(void)
-{
- iotable_init(ns9360_io_desc, ARRAY_SIZE(ns9360_io_desc));
-}
diff --git a/arch/arm/mach-ns9xxx/time-ns9360.c b/arch/arm/mach-ns9xxx/time-ns9360.c
deleted file mode 100644
index 9ca32f55728b..000000000000
--- a/arch/arm/mach-ns9xxx/time-ns9360.c
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * arch/arm/mach-ns9xxx/time-ns9360.c
- *
- * Copyright (C) 2006,2007 by Digi International Inc.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-#include <linux/jiffies.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/stringify.h>
-#include <linux/clocksource.h>
-#include <linux/clockchips.h>
-
-#include <mach/processor-ns9360.h>
-#include <mach/regs-sys-ns9360.h>
-#include <mach/irqs.h>
-#include <mach/system.h>
-#include "generic.h"
-
-#define TIMER_CLOCKSOURCE 0
-#define TIMER_CLOCKEVENT 1
-static u32 latch;
-
-static cycle_t ns9360_clocksource_read(struct clocksource *cs)
-{
- return __raw_readl(SYS_TR(TIMER_CLOCKSOURCE));
-}
-
-static struct clocksource ns9360_clocksource = {
- .name = "ns9360-timer" __stringify(TIMER_CLOCKSOURCE),
- .rating = 300,
- .read = ns9360_clocksource_read,
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-static void ns9360_clockevent_setmode(enum clock_event_mode mode,
- struct clock_event_device *clk)
-{
- u32 tc = __raw_readl(SYS_TC(TIMER_CLOCKEVENT));
-
- switch (mode) {
- case CLOCK_EVT_MODE_PERIODIC:
- __raw_writel(latch, SYS_TRC(TIMER_CLOCKEVENT));
- REGSET(tc, SYS_TCx, REN, EN);
- REGSET(tc, SYS_TCx, INTS, EN);
- REGSET(tc, SYS_TCx, TEN, EN);
- break;
-
- case CLOCK_EVT_MODE_ONESHOT:
- REGSET(tc, SYS_TCx, REN, DIS);
- REGSET(tc, SYS_TCx, INTS, EN);
-
- /* fall through */
-
- case CLOCK_EVT_MODE_UNUSED:
- case CLOCK_EVT_MODE_SHUTDOWN:
- case CLOCK_EVT_MODE_RESUME:
- default:
- REGSET(tc, SYS_TCx, TEN, DIS);
- break;
- }
-
- __raw_writel(tc, SYS_TC(TIMER_CLOCKEVENT));
-}
-
-static int ns9360_clockevent_setnextevent(unsigned long evt,
- struct clock_event_device *clk)
-{
- u32 tc = __raw_readl(SYS_TC(TIMER_CLOCKEVENT));
-
- if (REGGET(tc, SYS_TCx, TEN)) {
- REGSET(tc, SYS_TCx, TEN, DIS);
- __raw_writel(tc, SYS_TC(TIMER_CLOCKEVENT));
- }
-
- REGSET(tc, SYS_TCx, TEN, EN);
-
- __raw_writel(evt, SYS_TRC(TIMER_CLOCKEVENT));
-
- __raw_writel(tc, SYS_TC(TIMER_CLOCKEVENT));
-
- return 0;
-}
-
-static struct clock_event_device ns9360_clockevent_device = {
- .name = "ns9360-timer" __stringify(TIMER_CLOCKEVENT),
- .shift = 20,
- .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
- .set_mode = ns9360_clockevent_setmode,
- .set_next_event = ns9360_clockevent_setnextevent,
-};
-
-static irqreturn_t ns9360_clockevent_handler(int irq, void *dev_id)
-{
- int timerno = irq - IRQ_NS9360_TIMER0;
- u32 tc;
-
- struct clock_event_device *evt = &ns9360_clockevent_device;
-
- /* clear irq */
- tc = __raw_readl(SYS_TC(timerno));
- if (REGGET(tc, SYS_TCx, REN) == SYS_TCx_REN_DIS) {
- REGSET(tc, SYS_TCx, TEN, DIS);
- __raw_writel(tc, SYS_TC(timerno));
- }
- REGSET(tc, SYS_TCx, INTC, SET);
- __raw_writel(tc, SYS_TC(timerno));
- REGSET(tc, SYS_TCx, INTC, UNSET);
- __raw_writel(tc, SYS_TC(timerno));
-
- evt->event_handler(evt);
-
- return IRQ_HANDLED;
-}
-
-static struct irqaction ns9360_clockevent_action = {
- .name = "ns9360-timer" __stringify(TIMER_CLOCKEVENT),
- .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
- .handler = ns9360_clockevent_handler,
-};
-
-static void __init ns9360_timer_init(void)
-{
- int tc;
-
- tc = __raw_readl(SYS_TC(TIMER_CLOCKSOURCE));
- if (REGGET(tc, SYS_TCx, TEN)) {
- REGSET(tc, SYS_TCx, TEN, DIS);
- __raw_writel(tc, SYS_TC(TIMER_CLOCKSOURCE));
- }
-
- __raw_writel(0, SYS_TRC(TIMER_CLOCKSOURCE));
-
- REGSET(tc, SYS_TCx, TEN, EN);
- REGSET(tc, SYS_TCx, TDBG, STOP);
- REGSET(tc, SYS_TCx, TLCS, CPU);
- REGSET(tc, SYS_TCx, TM, IEE);
- REGSET(tc, SYS_TCx, INTS, DIS);
- REGSET(tc, SYS_TCx, UDS, UP);
- REGSET(tc, SYS_TCx, TSZ, 32);
- REGSET(tc, SYS_TCx, REN, EN);
-
- __raw_writel(tc, SYS_TC(TIMER_CLOCKSOURCE));
-
- clocksource_register_hz(&ns9360_clocksource, ns9360_cpuclock());
-
- latch = SH_DIV(ns9360_cpuclock(), HZ, 0);
-
- tc = __raw_readl(SYS_TC(TIMER_CLOCKEVENT));
- REGSET(tc, SYS_TCx, TEN, DIS);
- REGSET(tc, SYS_TCx, TDBG, STOP);
- REGSET(tc, SYS_TCx, TLCS, CPU);
- REGSET(tc, SYS_TCx, TM, IEE);
- REGSET(tc, SYS_TCx, INTS, DIS);
- REGSET(tc, SYS_TCx, UDS, DOWN);
- REGSET(tc, SYS_TCx, TSZ, 32);
- REGSET(tc, SYS_TCx, REN, EN);
- __raw_writel(tc, SYS_TC(TIMER_CLOCKEVENT));
-
- ns9360_clockevent_device.mult = div_sc(ns9360_cpuclock(),
- NSEC_PER_SEC, ns9360_clockevent_device.shift);
- ns9360_clockevent_device.max_delta_ns =
- clockevent_delta2ns(-1, &ns9360_clockevent_device);
- ns9360_clockevent_device.min_delta_ns =
- clockevent_delta2ns(1, &ns9360_clockevent_device);
-
- ns9360_clockevent_device.cpumask = cpumask_of(0);
- clockevents_register_device(&ns9360_clockevent_device);
-
- setup_irq(IRQ_NS9360_TIMER0 + TIMER_CLOCKEVENT,
- &ns9360_clockevent_action);
-}
-
-struct sys_timer ns9360_timer = {
- .init = ns9360_timer_init,
-};
diff --git a/arch/arm/mach-nuc93x/include/mach/uncompress.h b/arch/arm/mach-nuc93x/include/mach/uncompress.h
index 73082cd61e84..381cb9baadd5 100644
--- a/arch/arm/mach-nuc93x/include/mach/uncompress.h
+++ b/arch/arm/mach-nuc93x/include/mach/uncompress.h
@@ -27,7 +27,7 @@
#define arch_decomp_wdog()
#define TX_DONE (UART_LSR_TEMT | UART_LSR_THRE)
-static u32 * uart_base = (u32 *)UART0_PA;
+static u32 * const uart_base = (u32 *)UART0_PA;
static void putc(int ch)
{
diff --git a/arch/arm/mach-omap1/flash.c b/arch/arm/mach-omap1/flash.c
index acd161666408..1749cb37dda0 100644
--- a/arch/arm/mach-omap1/flash.c
+++ b/arch/arm/mach-omap1/flash.c
@@ -13,7 +13,7 @@
#include <plat/tc.h>
#include <plat/flash.h>
-void omap1_set_vpp(struct map_info *map, int enable)
+void omap1_set_vpp(struct platform_device *pdev, int enable)
{
static int count;
u32 l;
diff --git a/arch/arm/mach-omap1/pm_bus.c b/arch/arm/mach-omap1/pm_bus.c
index 6588c22b8a64..fe31d933f0ed 100644
--- a/arch/arm/mach-omap1/pm_bus.c
+++ b/arch/arm/mach-omap1/pm_bus.c
@@ -24,75 +24,50 @@
#ifdef CONFIG_PM_RUNTIME
static int omap1_pm_runtime_suspend(struct device *dev)
{
- struct clk *iclk, *fclk;
- int ret = 0;
+ int ret;
dev_dbg(dev, "%s\n", __func__);
ret = pm_generic_runtime_suspend(dev);
+ if (ret)
+ return ret;
- fclk = clk_get(dev, "fck");
- if (!IS_ERR(fclk)) {
- clk_disable(fclk);
- clk_put(fclk);
- }
-
- iclk = clk_get(dev, "ick");
- if (!IS_ERR(iclk)) {
- clk_disable(iclk);
- clk_put(iclk);
+ ret = pm_runtime_clk_suspend(dev);
+ if (ret) {
+ pm_generic_runtime_resume(dev);
+ return ret;
}
return 0;
-};
+}
static int omap1_pm_runtime_resume(struct device *dev)
{
- struct clk *iclk, *fclk;
-
dev_dbg(dev, "%s\n", __func__);
- iclk = clk_get(dev, "ick");
- if (!IS_ERR(iclk)) {
- clk_enable(iclk);
- clk_put(iclk);
- }
+ pm_runtime_clk_resume(dev);
+ return pm_generic_runtime_resume(dev);
+}
- fclk = clk_get(dev, "fck");
- if (!IS_ERR(fclk)) {
- clk_enable(fclk);
- clk_put(fclk);
- }
+static struct dev_power_domain default_power_domain = {
+ .ops = {
+ .runtime_suspend = omap1_pm_runtime_suspend,
+ .runtime_resume = omap1_pm_runtime_resume,
+ USE_PLATFORM_PM_SLEEP_OPS
+ },
+};
- return pm_generic_runtime_resume(dev);
+static struct pm_clk_notifier_block platform_bus_notifier = {
+ .pwr_domain = &default_power_domain,
+ .con_ids = { "ick", "fck", NULL, },
};
static int __init omap1_pm_runtime_init(void)
{
- const struct dev_pm_ops *pm;
- struct dev_pm_ops *omap_pm;
-
if (!cpu_class_is_omap1())
return -ENODEV;
- pm = platform_bus_get_pm_ops();
- if (!pm) {
- pr_err("%s: unable to get dev_pm_ops from platform_bus\n",
- __func__);
- return -ENODEV;
- }
-
- omap_pm = kmemdup(pm, sizeof(struct dev_pm_ops), GFP_KERNEL);
- if (!omap_pm) {
- pr_err("%s: unable to alloc memory for new dev_pm_ops\n",
- __func__);
- return -ENOMEM;
- }
-
- omap_pm->runtime_suspend = omap1_pm_runtime_suspend;
- omap_pm->runtime_resume = omap1_pm_runtime_resume;
-
- platform_bus_set_pm_ops(omap_pm);
+ pm_runtime_clk_add_notifier(&platform_bus_type, &platform_bus_notifier);
return 0;
}
diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c
index 6885d2fac183..03e1e1062ad4 100644
--- a/arch/arm/mach-omap1/time.c
+++ b/arch/arm/mach-omap1/time.c
@@ -68,49 +68,50 @@ typedef struct {
} omap_mpu_timer_regs_t;
#define omap_mpu_timer_base(n) \
-((volatile omap_mpu_timer_regs_t*)OMAP1_IO_ADDRESS(OMAP_MPU_TIMER_BASE + \
+((omap_mpu_timer_regs_t __iomem *)OMAP1_IO_ADDRESS(OMAP_MPU_TIMER_BASE + \
(n)*OMAP_MPU_TIMER_OFFSET))
static inline unsigned long notrace omap_mpu_timer_read(int nr)
{
- volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
- return timer->read_tim;
+ omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
+ return readl(&timer->read_tim);
}
static inline void omap_mpu_set_autoreset(int nr)
{
- volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+ omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
- timer->cntl = timer->cntl | MPU_TIMER_AR;
+ writel(readl(&timer->cntl) | MPU_TIMER_AR, &timer->cntl);
}
static inline void omap_mpu_remove_autoreset(int nr)
{
- volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+ omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
- timer->cntl = timer->cntl & ~MPU_TIMER_AR;
+ writel(readl(&timer->cntl) & ~MPU_TIMER_AR, &timer->cntl);
}
static inline void omap_mpu_timer_start(int nr, unsigned long load_val,
int autoreset)
{
- volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
- unsigned int timerflags = (MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_ST);
+ omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
+ unsigned int timerflags = MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_ST;
- if (autoreset) timerflags |= MPU_TIMER_AR;
+ if (autoreset)
+ timerflags |= MPU_TIMER_AR;
- timer->cntl = MPU_TIMER_CLOCK_ENABLE;
+ writel(MPU_TIMER_CLOCK_ENABLE, &timer->cntl);
udelay(1);
- timer->load_tim = load_val;
+ writel(load_val, &timer->load_tim);
udelay(1);
- timer->cntl = timerflags;
+ writel(timerflags, &timer->cntl);
}
static inline void omap_mpu_timer_stop(int nr)
{
- volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr);
+ omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
- timer->cntl &= ~MPU_TIMER_ST;
+ writel(readl(&timer->cntl) & ~MPU_TIMER_ST, &timer->cntl);
}
/*
@@ -189,38 +190,11 @@ static __init void omap_init_mpu_timer(unsigned long rate)
* ---------------------------------------------------------------------------
*/
-static unsigned long omap_mpu_timer2_overflows;
-
-static irqreturn_t omap_mpu_timer2_interrupt(int irq, void *dev_id)
-{
- omap_mpu_timer2_overflows++;
- return IRQ_HANDLED;
-}
-
-static struct irqaction omap_mpu_timer2_irq = {
- .name = "mpu_timer2",
- .flags = IRQF_DISABLED,
- .handler = omap_mpu_timer2_interrupt,
-};
-
-static cycle_t mpu_read(struct clocksource *cs)
-{
- return ~omap_mpu_timer_read(1);
-}
-
-static struct clocksource clocksource_mpu = {
- .name = "mpu_timer2",
- .rating = 300,
- .read = mpu_read,
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
static DEFINE_CLOCK_DATA(cd);
static inline unsigned long long notrace _omap_mpu_sched_clock(void)
{
- u32 cyc = mpu_read(&clocksource_mpu);
+ u32 cyc = ~omap_mpu_timer_read(1);
return cyc_to_sched_clock(&cd, cyc, (u32)~0);
}
@@ -238,21 +212,22 @@ static unsigned long long notrace omap_mpu_sched_clock(void)
static void notrace mpu_update_sched_clock(void)
{
- u32 cyc = mpu_read(&clocksource_mpu);
+ u32 cyc = ~omap_mpu_timer_read(1);
update_sched_clock(&cd, cyc, (u32)~0);
}
static void __init omap_init_clocksource(unsigned long rate)
{
+ omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(1);
static char err[] __initdata = KERN_ERR
"%s: can't register clocksource!\n";
- setup_irq(INT_TIMER2, &omap_mpu_timer2_irq);
omap_mpu_timer_start(1, ~0, 1);
init_sched_clock(&cd, mpu_update_sched_clock, 32, rate);
- if (clocksource_register_hz(&clocksource_mpu, rate))
- printk(err, clocksource_mpu.name);
+ if (clocksource_mmio_init(&timer->read_tim, "mpu_timer2", rate,
+ 300, 32, clocksource_mmio_readl_down))
+ printk(err, "mpu_timer2");
}
static void __init omap_mpu_timer_init(void)
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index b997a35830fc..19d5891c48e3 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -288,6 +288,7 @@ config MACH_IGEP0030
depends on ARCH_OMAP3
default y
select OMAP_PACKAGE_CBB
+ select MACH_IGEP0020
config MACH_SBC3530
bool "OMAP3 SBC STALKER board"
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 512b15204450..b14807794401 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -59,10 +59,10 @@ endif
# Power Management
ifeq ($(CONFIG_PM),y)
obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o
-obj-$(CONFIG_ARCH_OMAP2) += sleep24xx.o pm_bus.o
+obj-$(CONFIG_ARCH_OMAP2) += sleep24xx.o
obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o \
- cpuidle34xx.o pm_bus.o
-obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o pm_bus.o
+ cpuidle34xx.o
+obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o
obj-$(CONFIG_PM_DEBUG) += pm-debug.o
obj-$(CONFIG_OMAP_SMARTREFLEX) += sr_device.o smartreflex.o
obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS3) += smartreflex-class3.o
@@ -229,8 +229,6 @@ obj-$(CONFIG_MACH_CM_T35) += board-cm-t35.o \
obj-$(CONFIG_MACH_CM_T3517) += board-cm-t3517.o
obj-$(CONFIG_MACH_IGEP0020) += board-igep0020.o \
hsmmc.o
-obj-$(CONFIG_MACH_IGEP0030) += board-igep0030.o \
- hsmmc.o
obj-$(CONFIG_MACH_OMAP3_TOUCHBOOK) += board-omap3touchbook.o \
hsmmc.o
obj-$(CONFIG_MACH_OMAP_4430SDP) += board-4430sdp.o \
@@ -270,3 +268,5 @@ obj-$(CONFIG_ARCH_OMAP4) += hwspinlock.o
disp-$(CONFIG_OMAP2_DSS) := display.o
obj-y += $(disp-m) $(disp-y)
+
+obj-y += common-board-devices.o
diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c
index 1fa6bb896f41..d54969be0a54 100644
--- a/arch/arm/mach-omap2/board-2430sdp.c
+++ b/arch/arm/mach-omap2/board-2430sdp.c
@@ -41,6 +41,7 @@
#include "mux.h"
#include "hsmmc.h"
+#include "common-board-devices.h"
#define SDP2430_CS0_BASE 0x04000000
#define SECONDARY_LCD_GPIO 147
@@ -180,15 +181,6 @@ static struct twl4030_platform_data sdp2430_twldata = {
.vmmc1 = &sdp2430_vmmc1,
};
-static struct i2c_board_info __initdata sdp2430_i2c_boardinfo[] = {
- {
- I2C_BOARD_INFO("twl4030", 0x48),
- .flags = I2C_CLIENT_WAKE,
- .irq = INT_24XX_SYS_NIRQ,
- .platform_data = &sdp2430_twldata,
- },
-};
-
static struct i2c_board_info __initdata sdp2430_i2c1_boardinfo[] = {
{
I2C_BOARD_INFO("isp1301_omap", 0x2D),
@@ -201,8 +193,7 @@ static int __init omap2430_i2c_init(void)
{
omap_register_i2c_bus(1, 100, sdp2430_i2c1_boardinfo,
ARRAY_SIZE(sdp2430_i2c1_boardinfo));
- omap_register_i2c_bus(2, 2600, sdp2430_i2c_boardinfo,
- ARRAY_SIZE(sdp2430_i2c_boardinfo));
+ omap2_pmic_init("twl4030", &sdp2430_twldata);
return 0;
}
@@ -217,11 +208,6 @@ static struct omap2_hsmmc_info mmc[] __initdata = {
{} /* Terminator */
};
-static struct omap_musb_board_data musb_board_data = {
- .interface_type = MUSB_INTERFACE_ULPI,
- .mode = MUSB_OTG,
- .power = 100,
-};
static struct omap_usb_config sdp2430_usb_config __initdata = {
.otg = 1,
#ifdef CONFIG_USB_GADGET_OMAP
@@ -240,8 +226,6 @@ static struct omap_board_mux board_mux[] __initdata = {
static void __init omap_2430sdp_init(void)
{
- int ret;
-
omap2430_mux_init(board_mux, OMAP_PACKAGE_ZAC);
omap_board_config = sdp2430_config;
@@ -255,14 +239,13 @@ static void __init omap_2430sdp_init(void)
omap2_usbfs_init(&sdp2430_usb_config);
omap_mux_init_signal("usb0hs_stp", OMAP_PULL_ENA | OMAP_PULL_UP);
- usb_musb_init(&musb_board_data);
+ usb_musb_init(NULL);
board_smc91x_init();
/* Turn off secondary LCD backlight */
- ret = gpio_request(SECONDARY_LCD_GPIO, "Secondary LCD backlight");
- if (ret == 0)
- gpio_direction_output(SECONDARY_LCD_GPIO, 0);
+ gpio_request_one(SECONDARY_LCD_GPIO, GPIOF_OUT_INIT_LOW,
+ "Secondary LCD backlight");
}
static void __init omap_2430sdp_map_io(void)
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index 9afd087cc29c..ae2963a98041 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -19,7 +19,6 @@
#include <linux/input.h>
#include <linux/input/matrix_keypad.h>
#include <linux/spi/spi.h>
-#include <linux/spi/ads7846.h>
#include <linux/i2c/twl.h>
#include <linux/regulator/machine.h>
#include <linux/io.h>
@@ -37,8 +36,8 @@
#include <plat/common.h>
#include <plat/dma.h>
#include <plat/gpmc.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
#include <plat/gpmc-smc91x.h>
@@ -48,6 +47,7 @@
#include "hsmmc.h"
#include "pm.h"
#include "control.h"
+#include "common-board-devices.h"
#define CONFIG_DISABLE_HFCLK 1
@@ -59,24 +59,6 @@
#define TWL4030_MSECURE_GPIO 22
-/* FIXME: These values need to be updated based on more profiling on 3430sdp*/
-static struct cpuidle_params omap3_cpuidle_params_table[] = {
- /* C1 */
- {1, 2, 2, 5},
- /* C2 */
- {1, 10, 10, 30},
- /* C3 */
- {1, 50, 50, 300},
- /* C4 */
- {1, 1500, 1800, 4000},
- /* C5 */
- {1, 2500, 7500, 12000},
- /* C6 */
- {1, 3000, 8500, 15000},
- /* C7 */
- {1, 10000, 30000, 300000},
-};
-
static uint32_t board_keymap[] = {
KEY(0, 0, KEY_LEFT),
KEY(0, 1, KEY_RIGHT),
@@ -123,63 +105,14 @@ static struct twl4030_keypad_data sdp3430_kp_data = {
.rep = 1,
};
-static int ts_gpio; /* Needed for ads7846_get_pendown_state */
-
-/**
- * @brief ads7846_dev_init : Requests & sets GPIO line for pen-irq
- *
- * @return - void. If request gpio fails then Flag KERN_ERR.
- */
-static void ads7846_dev_init(void)
-{
- if (gpio_request(ts_gpio, "ADS7846 pendown") < 0) {
- printk(KERN_ERR "can't get ads746 pen down GPIO\n");
- return;
- }
-
- gpio_direction_input(ts_gpio);
- gpio_set_debounce(ts_gpio, 310);
-}
-
-static int ads7846_get_pendown_state(void)
-{
- return !gpio_get_value(ts_gpio);
-}
-
-static struct ads7846_platform_data tsc2046_config __initdata = {
- .get_pendown_state = ads7846_get_pendown_state,
- .keep_vref_on = 1,
- .wakeup = true,
-};
-
-
-static struct omap2_mcspi_device_config tsc2046_mcspi_config = {
- .turbo_mode = 0,
- .single_channel = 1, /* 0: slave, 1: master */
-};
-
-static struct spi_board_info sdp3430_spi_board_info[] __initdata = {
- [0] = {
- /*
- * TSC2046 operates at a max freqency of 2MHz, so
- * operate slightly below at 1.5MHz
- */
- .modalias = "ads7846",
- .bus_num = 1,
- .chip_select = 0,
- .max_speed_hz = 1500000,
- .controller_data = &tsc2046_mcspi_config,
- .irq = 0,
- .platform_data = &tsc2046_config,
- },
-};
-
-
#define SDP3430_LCD_PANEL_BACKLIGHT_GPIO 8
#define SDP3430_LCD_PANEL_ENABLE_GPIO 5
-static unsigned backlight_gpio;
-static unsigned enable_gpio;
+static struct gpio sdp3430_dss_gpios[] __initdata = {
+ {SDP3430_LCD_PANEL_ENABLE_GPIO, GPIOF_OUT_INIT_LOW, "LCD reset" },
+ {SDP3430_LCD_PANEL_BACKLIGHT_GPIO, GPIOF_OUT_INIT_LOW, "LCD Backlight"},
+};
+
static int lcd_enabled;
static int dvi_enabled;
@@ -187,29 +120,11 @@ static void __init sdp3430_display_init(void)
{
int r;
- enable_gpio = SDP3430_LCD_PANEL_ENABLE_GPIO;
- backlight_gpio = SDP3430_LCD_PANEL_BACKLIGHT_GPIO;
-
- r = gpio_request(enable_gpio, "LCD reset");
- if (r) {
- printk(KERN_ERR "failed to get LCD reset GPIO\n");
- goto err0;
- }
-
- r = gpio_request(backlight_gpio, "LCD Backlight");
- if (r) {
- printk(KERN_ERR "failed to get LCD backlight GPIO\n");
- goto err1;
- }
-
- gpio_direction_output(enable_gpio, 0);
- gpio_direction_output(backlight_gpio, 0);
+ r = gpio_request_array(sdp3430_dss_gpios,
+ ARRAY_SIZE(sdp3430_dss_gpios));
+ if (r)
+ printk(KERN_ERR "failed to get LCD control GPIOs\n");
- return;
-err1:
- gpio_free(enable_gpio);
-err0:
- return;
}
static int sdp3430_panel_enable_lcd(struct omap_dss_device *dssdev)
@@ -219,8 +134,8 @@ static int sdp3430_panel_enable_lcd(struct omap_dss_device *dssdev)
return -EINVAL;
}
- gpio_direction_output(enable_gpio, 1);
- gpio_direction_output(backlight_gpio, 1);
+ gpio_direction_output(SDP3430_LCD_PANEL_ENABLE_GPIO, 1);
+ gpio_direction_output(SDP3430_LCD_PANEL_BACKLIGHT_GPIO, 1);
lcd_enabled = 1;
@@ -231,8 +146,8 @@ static void sdp3430_panel_disable_lcd(struct omap_dss_device *dssdev)
{
lcd_enabled = 0;
- gpio_direction_output(enable_gpio, 0);
- gpio_direction_output(backlight_gpio, 0);
+ gpio_direction_output(SDP3430_LCD_PANEL_ENABLE_GPIO, 0);
+ gpio_direction_output(SDP3430_LCD_PANEL_BACKLIGHT_GPIO, 0);
}
static int sdp3430_panel_enable_dvi(struct omap_dss_device *dssdev)
@@ -360,12 +275,10 @@ static int sdp3430_twl_gpio_setup(struct device *dev,
omap2_hsmmc_init(mmc);
/* gpio + 7 is "sub_lcd_en_bkl" (output/PWM1) */
- gpio_request(gpio + 7, "sub_lcd_en_bkl");
- gpio_direction_output(gpio + 7, 0);
+ gpio_request_one(gpio + 7, GPIOF_OUT_INIT_LOW, "sub_lcd_en_bkl");
/* gpio + 15 is "sub_lcd_nRST" (output) */
- gpio_request(gpio + 15, "sub_lcd_nRST");
- gpio_direction_output(gpio + 15, 0);
+ gpio_request_one(gpio + 15, GPIOF_OUT_INIT_LOW, "sub_lcd_nRST");
return 0;
}
@@ -580,20 +493,10 @@ static struct twl4030_platform_data sdp3430_twldata = {
.vpll2 = &sdp3430_vpll2,
};
-static struct i2c_board_info __initdata sdp3430_i2c_boardinfo[] = {
- {
- I2C_BOARD_INFO("twl4030", 0x48),
- .flags = I2C_CLIENT_WAKE,
- .irq = INT_34XX_SYS_NIRQ,
- .platform_data = &sdp3430_twldata,
- },
-};
-
static int __init omap3430_i2c_init(void)
{
/* i2c1 for PMIC only */
- omap_register_i2c_bus(1, 2600, sdp3430_i2c_boardinfo,
- ARRAY_SIZE(sdp3430_i2c_boardinfo));
+ omap3_pmic_init("twl4030", &sdp3430_twldata);
/* i2c2 on camera connector (for sensor control) and optional isp1301 */
omap_register_i2c_bus(2, 400, NULL, 0);
/* i2c3 on display connector (for DVI, tfp410) */
@@ -872,30 +775,22 @@ static struct flash_partitions sdp_flash_partitions[] = {
},
};
-static struct omap_musb_board_data musb_board_data = {
- .interface_type = MUSB_INTERFACE_ULPI,
- .mode = MUSB_OTG,
- .power = 100,
-};
-
static void __init omap_3430sdp_init(void)
{
+ int gpio_pendown;
+
omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
omap_board_config = sdp3430_config;
omap_board_config_size = ARRAY_SIZE(sdp3430_config);
- omap3_pm_init_cpuidle(omap3_cpuidle_params_table);
omap3430_i2c_init();
omap_display_init(&sdp3430_dss_data);
if (omap_rev() > OMAP3430_REV_ES1_0)
- ts_gpio = SDP3430_TS_GPIO_IRQ_SDPV2;
+ gpio_pendown = SDP3430_TS_GPIO_IRQ_SDPV2;
else
- ts_gpio = SDP3430_TS_GPIO_IRQ_SDPV1;
- sdp3430_spi_board_info[0].irq = gpio_to_irq(ts_gpio);
- spi_register_board_info(sdp3430_spi_board_info,
- ARRAY_SIZE(sdp3430_spi_board_info));
- ads7846_dev_init();
+ gpio_pendown = SDP3430_TS_GPIO_IRQ_SDPV1;
+ omap_ads7846_init(1, gpio_pendown, 310, NULL);
board_serial_init();
- usb_musb_init(&musb_board_data);
+ usb_musb_init(NULL);
board_smc91x_init();
board_flash_init(sdp_flash_partitions, chip_sel_3430, 0);
sdp3430_display_init();
diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c
index 56702c5e577f..73fa90bb6953 100644
--- a/arch/arm/mach-omap2/board-4430sdp.c
+++ b/arch/arm/mach-omap2/board-4430sdp.c
@@ -36,12 +36,13 @@
#include <plat/usb.h>
#include <plat/mmc.h>
#include <plat/omap4-keypad.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
#include "mux.h"
#include "hsmmc.h"
#include "timer-gp.h"
#include "control.h"
+#include "common-board-devices.h"
#define ETH_KS8851_IRQ 34
#define ETH_KS8851_POWER_ON 48
@@ -251,58 +252,22 @@ static struct spi_board_info sdp4430_spi_board_info[] __initdata = {
},
};
+static struct gpio sdp4430_eth_gpios[] __initdata = {
+ { ETH_KS8851_POWER_ON, GPIOF_OUT_INIT_HIGH, "eth_power" },
+ { ETH_KS8851_QUART, GPIOF_OUT_INIT_HIGH, "quart" },
+ { ETH_KS8851_IRQ, GPIOF_IN, "eth_irq" },
+};
+
static int omap_ethernet_init(void)
{
int status;
/* Request of GPIO lines */
+ status = gpio_request_array(sdp4430_eth_gpios,
+ ARRAY_SIZE(sdp4430_eth_gpios));
+ if (status)
+ pr_err("Cannot request ETH GPIOs\n");
- status = gpio_request(ETH_KS8851_POWER_ON, "eth_power");
- if (status) {
- pr_err("Cannot request GPIO %d\n", ETH_KS8851_POWER_ON);
- return status;
- }
-
- status = gpio_request(ETH_KS8851_QUART, "quart");
- if (status) {
- pr_err("Cannot request GPIO %d\n", ETH_KS8851_QUART);
- goto error1;
- }
-
- status = gpio_request(ETH_KS8851_IRQ, "eth_irq");
- if (status) {
- pr_err("Cannot request GPIO %d\n", ETH_KS8851_IRQ);
- goto error2;
- }
-
- /* Configuration of requested GPIO lines */
-
- status = gpio_direction_output(ETH_KS8851_POWER_ON, 1);
- if (status) {
- pr_err("Cannot set output GPIO %d\n", ETH_KS8851_IRQ);
- goto error3;
- }
-
- status = gpio_direction_output(ETH_KS8851_QUART, 1);
- if (status) {
- pr_err("Cannot set output GPIO %d\n", ETH_KS8851_QUART);
- goto error3;
- }
-
- status = gpio_direction_input(ETH_KS8851_IRQ);
- if (status) {
- pr_err("Cannot set input GPIO %d\n", ETH_KS8851_IRQ);
- goto error3;
- }
-
- return 0;
-
-error3:
- gpio_free(ETH_KS8851_IRQ);
-error2:
- gpio_free(ETH_KS8851_QUART);
-error1:
- gpio_free(ETH_KS8851_POWER_ON);
return status;
}
@@ -575,14 +540,6 @@ static struct twl4030_platform_data sdp4430_twldata = {
.usb = &omap4_usbphy_data
};
-static struct i2c_board_info __initdata sdp4430_i2c_boardinfo[] = {
- {
- I2C_BOARD_INFO("twl6030", 0x48),
- .flags = I2C_CLIENT_WAKE,
- .irq = OMAP44XX_IRQ_SYS_1N,
- .platform_data = &sdp4430_twldata,
- },
-};
static struct i2c_board_info __initdata sdp4430_i2c_3_boardinfo[] = {
{
I2C_BOARD_INFO("tmp105", 0x48),
@@ -598,12 +555,7 @@ static struct i2c_board_info __initdata sdp4430_i2c_4_boardinfo[] = {
};
static int __init omap4_i2c_init(void)
{
- /*
- * Phoenix Audio IC needs I2C1 to
- * start with 400 KHz or less
- */
- omap_register_i2c_bus(1, 400, sdp4430_i2c_boardinfo,
- ARRAY_SIZE(sdp4430_i2c_boardinfo));
+ omap4_pmic_init("twl6030", &sdp4430_twldata);
omap_register_i2c_bus(2, 400, NULL, 0);
omap_register_i2c_bus(3, 400, sdp4430_i2c_3_boardinfo,
ARRAY_SIZE(sdp4430_i2c_3_boardinfo));
@@ -614,21 +566,13 @@ static int __init omap4_i2c_init(void)
static void __init omap_sfh7741prox_init(void)
{
- int error;
+ int error;
- error = gpio_request(OMAP4_SFH7741_ENABLE_GPIO, "sfh7741");
- if (error < 0) {
+ error = gpio_request_one(OMAP4_SFH7741_ENABLE_GPIO,
+ GPIOF_OUT_INIT_LOW, "sfh7741");
+ if (error < 0)
pr_err("%s:failed to request GPIO %d, error %d\n",
__func__, OMAP4_SFH7741_ENABLE_GPIO, error);
- return;
- }
-
- error = gpio_direction_output(OMAP4_SFH7741_ENABLE_GPIO , 0);
- if (error < 0) {
- pr_err("%s: GPIO configuration failed: GPIO %d,error %d\n",
- __func__, OMAP4_SFH7741_ENABLE_GPIO, error);
- gpio_free(OMAP4_SFH7741_ENABLE_GPIO);
- }
}
static void sdp4430_hdmi_mux_init(void)
@@ -645,27 +589,19 @@ static void sdp4430_hdmi_mux_init(void)
OMAP_PIN_INPUT_PULLUP);
}
+static struct gpio sdp4430_hdmi_gpios[] = {
+ { HDMI_GPIO_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_hpd" },
+ { HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" },
+};
+
static int sdp4430_panel_enable_hdmi(struct omap_dss_device *dssdev)
{
int status;
- status = gpio_request_one(HDMI_GPIO_HPD, GPIOF_OUT_INIT_HIGH,
- "hdmi_gpio_hpd");
- if (status) {
- pr_err("Cannot request GPIO %d\n", HDMI_GPIO_HPD);
- return status;
- }
- status = gpio_request_one(HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH,
- "hdmi_gpio_ls_oe");
- if (status) {
- pr_err("Cannot request GPIO %d\n", HDMI_GPIO_LS_OE);
- goto error1;
- }
-
- return 0;
-
-error1:
- gpio_free(HDMI_GPIO_HPD);
+ status = gpio_request_array(sdp4430_hdmi_gpios,
+ ARRAY_SIZE(sdp4430_hdmi_gpios));
+ if (status)
+ pr_err("%s: Cannot request HDMI GPIOs\n", __func__);
return status;
}
@@ -680,6 +616,15 @@ static struct omap_dss_device sdp4430_hdmi_device = {
.name = "hdmi",
.driver_name = "hdmi_panel",
.type = OMAP_DISPLAY_TYPE_HDMI,
+ .clocks = {
+ .dispc = {
+ .dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK,
+ },
+ .hdmi = {
+ .regn = 15,
+ .regm2 = 1,
+ },
+ },
.platform_enable = sdp4430_panel_enable_hdmi,
.platform_disable = sdp4430_panel_disable_hdmi,
.channel = OMAP_DSS_CHANNEL_DIGIT,
diff --git a/arch/arm/mach-omap2/board-am3517crane.c b/arch/arm/mach-omap2/board-am3517crane.c
index a890d244fec6..5e438a77cd72 100644
--- a/arch/arm/mach-omap2/board-am3517crane.c
+++ b/arch/arm/mach-omap2/board-am3517crane.c
@@ -89,19 +89,13 @@ static void __init am3517_crane_init(void)
return;
}
- ret = gpio_request(GPIO_USB_POWER, "usb_ehci_enable");
+ ret = gpio_request_one(GPIO_USB_POWER, GPIOF_OUT_INIT_HIGH,
+ "usb_ehci_enable");
if (ret < 0) {
pr_err("Can not request GPIO %d\n", GPIO_USB_POWER);
return;
}
- ret = gpio_direction_output(GPIO_USB_POWER, 1);
- if (ret < 0) {
- gpio_free(GPIO_USB_POWER);
- pr_err("Unable to initialize EHCI power\n");
- return;
- }
-
usbhs_init(&usbhs_bdata);
}
diff --git a/arch/arm/mach-omap2/board-am3517evm.c b/arch/arm/mach-omap2/board-am3517evm.c
index ce7d5e6e4150..63af4171c043 100644
--- a/arch/arm/mach-omap2/board-am3517evm.c
+++ b/arch/arm/mach-omap2/board-am3517evm.c
@@ -34,8 +34,8 @@
#include <plat/board.h>
#include <plat/common.h>
#include <plat/usb.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
#include "mux.h"
#include "control.h"
@@ -174,19 +174,14 @@ static void __init am3517_evm_rtc_init(void)
int r;
omap_mux_init_gpio(GPIO_RTCS35390A_IRQ, OMAP_PIN_INPUT_PULLUP);
- r = gpio_request(GPIO_RTCS35390A_IRQ, "rtcs35390a-irq");
+
+ r = gpio_request_one(GPIO_RTCS35390A_IRQ, GPIOF_IN, "rtcs35390a-irq");
if (r < 0) {
printk(KERN_WARNING "failed to request GPIO#%d\n",
GPIO_RTCS35390A_IRQ);
return;
}
- r = gpio_direction_input(GPIO_RTCS35390A_IRQ);
- if (r < 0) {
- printk(KERN_WARNING "GPIO#%d cannot be configured as input\n",
- GPIO_RTCS35390A_IRQ);
- gpio_free(GPIO_RTCS35390A_IRQ);
- return;
- }
+
am3517evm_i2c1_boardinfo[0].irq = gpio_to_irq(GPIO_RTCS35390A_IRQ);
}
@@ -242,6 +237,15 @@ static int dvi_enabled;
#if defined(CONFIG_PANEL_SHARP_LQ043T1DG01) || \
defined(CONFIG_PANEL_SHARP_LQ043T1DG01_MODULE)
+static struct gpio am3517_evm_dss_gpios[] __initdata = {
+ /* GPIO 182 = LCD Backlight Power */
+ { LCD_PANEL_BKLIGHT_PWR, GPIOF_OUT_INIT_HIGH, "lcd_backlight_pwr" },
+ /* GPIO 181 = LCD Panel PWM */
+ { LCD_PANEL_PWM, GPIOF_OUT_INIT_HIGH, "lcd bl enable" },
+ /* GPIO 176 = LCD Panel Power enable pin */
+ { LCD_PANEL_PWR, GPIOF_OUT_INIT_HIGH, "dvi enable" },
+};
+
static void __init am3517_evm_display_init(void)
{
int r;
@@ -249,41 +253,15 @@ static void __init am3517_evm_display_init(void)
omap_mux_init_gpio(LCD_PANEL_PWR, OMAP_PIN_INPUT_PULLUP);
omap_mux_init_gpio(LCD_PANEL_BKLIGHT_PWR, OMAP_PIN_INPUT_PULLDOWN);
omap_mux_init_gpio(LCD_PANEL_PWM, OMAP_PIN_INPUT_PULLDOWN);
- /*
- * Enable GPIO 182 = LCD Backlight Power
- */
- r = gpio_request(LCD_PANEL_BKLIGHT_PWR, "lcd_backlight_pwr");
+
+ r = gpio_request_array(am3517_evm_dss_gpios,
+ ARRAY_SIZE(am3517_evm_dss_gpios));
if (r) {
- printk(KERN_ERR "failed to get lcd_backlight_pwr\n");
+ printk(KERN_ERR "failed to get DSS panel control GPIOs\n");
return;
}
- gpio_direction_output(LCD_PANEL_BKLIGHT_PWR, 1);
- /*
- * Enable GPIO 181 = LCD Panel PWM
- */
- r = gpio_request(LCD_PANEL_PWM, "lcd_pwm");
- if (r) {
- printk(KERN_ERR "failed to get lcd_pwm\n");
- goto err_1;
- }
- gpio_direction_output(LCD_PANEL_PWM, 1);
- /*
- * Enable GPIO 176 = LCD Panel Power enable pin
- */
- r = gpio_request(LCD_PANEL_PWR, "lcd_panel_pwr");
- if (r) {
- printk(KERN_ERR "failed to get lcd_panel_pwr\n");
- goto err_2;
- }
- gpio_direction_output(LCD_PANEL_PWR, 1);
printk(KERN_INFO "Display initialized successfully\n");
- return;
-
-err_2:
- gpio_free(LCD_PANEL_PWM);
-err_1:
- gpio_free(LCD_PANEL_BKLIGHT_PWR);
}
#else
static void __init am3517_evm_display_init(void) {}
@@ -396,7 +374,7 @@ static struct omap_musb_board_data musb_board_data = {
.power = 500,
.set_phy_power = am35x_musb_phy_power,
.clear_irq = am35x_musb_clear_irq,
- .set_mode = am35x_musb_set_mode,
+ .set_mode = am35x_set_mode,
.reset = am35x_musb_reset,
};
diff --git a/arch/arm/mach-omap2/board-apollon.c b/arch/arm/mach-omap2/board-apollon.c
index f4f8374a0298..f3beb8eeef77 100644
--- a/arch/arm/mach-omap2/board-apollon.c
+++ b/arch/arm/mach-omap2/board-apollon.c
@@ -202,6 +202,7 @@ static inline void __init apollon_init_smc91x(void)
unsigned int rate;
struct clk *gpmc_fck;
int eth_cs;
+ int err;
gpmc_fck = clk_get(NULL, "gpmc_fck"); /* Always on ENABLE_ON_INIT */
if (IS_ERR(gpmc_fck)) {
@@ -245,15 +246,13 @@ static inline void __init apollon_init_smc91x(void)
apollon_smc91x_resources[0].end = base + 0x30f;
udelay(100);
- omap_mux_init_gpio(74, 0);
- if (gpio_request(APOLLON_ETHR_GPIO_IRQ, "SMC91x irq") < 0) {
+ omap_mux_init_gpio(APOLLON_ETHR_GPIO_IRQ, 0);
+ err = gpio_request_one(APOLLON_ETHR_GPIO_IRQ, GPIOF_IN, "SMC91x irq");
+ if (err) {
printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n",
APOLLON_ETHR_GPIO_IRQ);
gpmc_cs_free(APOLLON_ETH_CS);
- goto out;
}
- gpio_direction_input(APOLLON_ETHR_GPIO_IRQ);
-
out:
clk_disable(gpmc_fck);
clk_put(gpmc_fck);
@@ -280,20 +279,19 @@ static void __init omap_apollon_init_early(void)
omap2_init_common_devices(NULL, NULL);
}
+static struct gpio apollon_gpio_leds[] __initdata = {
+ { LED0_GPIO13, GPIOF_OUT_INIT_LOW, "LED0" }, /* LED0 - AA10 */
+ { LED1_GPIO14, GPIOF_OUT_INIT_LOW, "LED1" }, /* LED1 - AA6 */
+ { LED2_GPIO15, GPIOF_OUT_INIT_LOW, "LED2" }, /* LED2 - AA4 */
+};
+
static void __init apollon_led_init(void)
{
- /* LED0 - AA10 */
omap_mux_init_signal("vlynq_clk.gpio_13", 0);
- gpio_request(LED0_GPIO13, "LED0");
- gpio_direction_output(LED0_GPIO13, 0);
- /* LED1 - AA6 */
omap_mux_init_signal("vlynq_rx1.gpio_14", 0);
- gpio_request(LED1_GPIO14, "LED1");
- gpio_direction_output(LED1_GPIO14, 0);
- /* LED2 - AA4 */
omap_mux_init_signal("vlynq_rx0.gpio_15", 0);
- gpio_request(LED2_GPIO15, "LED2");
- gpio_direction_output(LED2_GPIO15, 0);
+
+ gpio_request_array(apollon_gpio_leds, ARRAY_SIZE(apollon_gpio_leds));
}
static void __init apollon_usb_init(void)
@@ -301,8 +299,7 @@ static void __init apollon_usb_init(void)
/* USB device */
/* DEVICE_SUSPEND */
omap_mux_init_signal("mcbsp2_clkx.gpio_12", 0);
- gpio_request(12, "USB suspend");
- gpio_direction_output(12, 0);
+ gpio_request_one(12, GPIOF_OUT_INIT_LOW, "USB suspend");
omap2_usbfs_init(&apollon_usb_config);
}
diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c
index 02a12b41c0ff..c63115bc1536 100644
--- a/arch/arm/mach-omap2/board-cm-t35.c
+++ b/arch/arm/mach-omap2/board-cm-t35.c
@@ -45,8 +45,8 @@
#include <plat/nand.h>
#include <plat/gpmc.h>
#include <plat/usb.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
#include <plat/mcspi.h>
#include <mach/hardware.h>
@@ -54,6 +54,7 @@
#include "mux.h"
#include "sdram-micron-mt46h32m32lf-6.h"
#include "hsmmc.h"
+#include "common-board-devices.h"
#define CM_T35_GPIO_PENDOWN 57
@@ -66,86 +67,28 @@
#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
#include <linux/smsc911x.h>
+#include <plat/gpmc-smsc911x.h>
-static struct smsc911x_platform_config cm_t35_smsc911x_config = {
- .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
- .irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
- .flags = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS,
- .phy_interface = PHY_INTERFACE_MODE_MII,
-};
-
-static struct resource cm_t35_smsc911x_resources[] = {
- {
- .flags = IORESOURCE_MEM,
- },
- {
- .start = OMAP_GPIO_IRQ(CM_T35_SMSC911X_GPIO),
- .end = OMAP_GPIO_IRQ(CM_T35_SMSC911X_GPIO),
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
- },
-};
-
-static struct platform_device cm_t35_smsc911x_device = {
- .name = "smsc911x",
+static struct omap_smsc911x_platform_data cm_t35_smsc911x_cfg = {
.id = 0,
- .num_resources = ARRAY_SIZE(cm_t35_smsc911x_resources),
- .resource = cm_t35_smsc911x_resources,
- .dev = {
- .platform_data = &cm_t35_smsc911x_config,
- },
-};
-
-static struct resource sb_t35_smsc911x_resources[] = {
- {
- .flags = IORESOURCE_MEM,
- },
- {
- .start = OMAP_GPIO_IRQ(SB_T35_SMSC911X_GPIO),
- .end = OMAP_GPIO_IRQ(SB_T35_SMSC911X_GPIO),
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
- },
+ .cs = CM_T35_SMSC911X_CS,
+ .gpio_irq = CM_T35_SMSC911X_GPIO,
+ .gpio_reset = -EINVAL,
+ .flags = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS,
};
-static struct platform_device sb_t35_smsc911x_device = {
- .name = "smsc911x",
+static struct omap_smsc911x_platform_data sb_t35_smsc911x_cfg = {
.id = 1,
- .num_resources = ARRAY_SIZE(sb_t35_smsc911x_resources),
- .resource = sb_t35_smsc911x_resources,
- .dev = {
- .platform_data = &cm_t35_smsc911x_config,
- },
+ .cs = SB_T35_SMSC911X_CS,
+ .gpio_irq = SB_T35_SMSC911X_GPIO,
+ .gpio_reset = -EINVAL,
+ .flags = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS,
};
-static void __init cm_t35_init_smsc911x(struct platform_device *dev,
- int cs, int irq_gpio)
-{
- unsigned long cs_mem_base;
-
- if (gpmc_cs_request(cs, SZ_16M, &cs_mem_base) < 0) {
- pr_err("CM-T35: Failed request for GPMC mem for smsc911x\n");
- return;
- }
-
- dev->resource[0].start = cs_mem_base + 0x0;
- dev->resource[0].end = cs_mem_base + 0xff;
-
- if ((gpio_request(irq_gpio, "ETH IRQ") == 0) &&
- (gpio_direction_input(irq_gpio) == 0)) {
- gpio_export(irq_gpio, 0);
- } else {
- pr_err("CM-T35: could not obtain gpio for SMSC911X IRQ\n");
- return;
- }
-
- platform_device_register(dev);
-}
-
static void __init cm_t35_init_ethernet(void)
{
- cm_t35_init_smsc911x(&cm_t35_smsc911x_device,
- CM_T35_SMSC911X_CS, CM_T35_SMSC911X_GPIO);
- cm_t35_init_smsc911x(&sb_t35_smsc911x_device,
- SB_T35_SMSC911X_CS, SB_T35_SMSC911X_GPIO);
+ gpmc_smsc911x_init(&cm_t35_smsc911x_cfg);
+ gpmc_smsc911x_init(&sb_t35_smsc911x_cfg);
}
#else
static inline void __init cm_t35_init_ethernet(void) { return; }
@@ -235,69 +178,10 @@ static void __init cm_t35_init_nand(void)
static inline void cm_t35_init_nand(void) {}
#endif
-#if defined(CONFIG_TOUCHSCREEN_ADS7846) || \
- defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
-#include <linux/spi/ads7846.h>
-
-static struct omap2_mcspi_device_config ads7846_mcspi_config = {
- .turbo_mode = 0,
- .single_channel = 1, /* 0: slave, 1: master */
-};
-
-static int ads7846_get_pendown_state(void)
-{
- return !gpio_get_value(CM_T35_GPIO_PENDOWN);
-}
-
-static struct ads7846_platform_data ads7846_config = {
- .x_max = 0x0fff,
- .y_max = 0x0fff,
- .x_plate_ohms = 180,
- .pressure_max = 255,
- .debounce_max = 10,
- .debounce_tol = 3,
- .debounce_rep = 1,
- .get_pendown_state = ads7846_get_pendown_state,
- .keep_vref_on = 1,
-};
-
-static struct spi_board_info cm_t35_spi_board_info[] __initdata = {
- {
- .modalias = "ads7846",
- .bus_num = 1,
- .chip_select = 0,
- .max_speed_hz = 1500000,
- .controller_data = &ads7846_mcspi_config,
- .irq = OMAP_GPIO_IRQ(CM_T35_GPIO_PENDOWN),
- .platform_data = &ads7846_config,
- },
-};
-
-static void __init cm_t35_init_ads7846(void)
-{
- if ((gpio_request(CM_T35_GPIO_PENDOWN, "ADS7846_PENDOWN") == 0) &&
- (gpio_direction_input(CM_T35_GPIO_PENDOWN) == 0)) {
- gpio_export(CM_T35_GPIO_PENDOWN, 0);
- } else {
- pr_err("CM-T35: could not obtain gpio for ADS7846_PENDOWN\n");
- return;
- }
-
- spi_register_board_info(cm_t35_spi_board_info,
- ARRAY_SIZE(cm_t35_spi_board_info));
-}
-#else
-static inline void cm_t35_init_ads7846(void) {}
-#endif
-
#define CM_T35_LCD_EN_GPIO 157
#define CM_T35_LCD_BL_GPIO 58
#define CM_T35_DVI_EN_GPIO 54
-static int lcd_bl_gpio;
-static int lcd_en_gpio;
-static int dvi_en_gpio;
-
static int lcd_enabled;
static int dvi_enabled;
@@ -308,8 +192,8 @@ static int cm_t35_panel_enable_lcd(struct omap_dss_device *dssdev)
return -EINVAL;
}
- gpio_set_value(lcd_en_gpio, 1);
- gpio_set_value(lcd_bl_gpio, 1);
+ gpio_set_value(CM_T35_LCD_EN_GPIO, 1);
+ gpio_set_value(CM_T35_LCD_BL_GPIO, 1);
lcd_enabled = 1;
@@ -320,8 +204,8 @@ static void cm_t35_panel_disable_lcd(struct omap_dss_device *dssdev)
{
lcd_enabled = 0;
- gpio_set_value(lcd_bl_gpio, 0);
- gpio_set_value(lcd_en_gpio, 0);
+ gpio_set_value(CM_T35_LCD_BL_GPIO, 0);
+ gpio_set_value(CM_T35_LCD_EN_GPIO, 0);
}
static int cm_t35_panel_enable_dvi(struct omap_dss_device *dssdev)
@@ -331,7 +215,7 @@ static int cm_t35_panel_enable_dvi(struct omap_dss_device *dssdev)
return -EINVAL;
}
- gpio_set_value(dvi_en_gpio, 0);
+ gpio_set_value(CM_T35_DVI_EN_GPIO, 0);
dvi_enabled = 1;
return 0;
@@ -339,7 +223,7 @@ static int cm_t35_panel_enable_dvi(struct omap_dss_device *dssdev)
static void cm_t35_panel_disable_dvi(struct omap_dss_device *dssdev)
{
- gpio_set_value(dvi_en_gpio, 1);
+ gpio_set_value(CM_T35_DVI_EN_GPIO, 1);
dvi_enabled = 0;
}
@@ -421,62 +305,38 @@ static struct spi_board_info cm_t35_lcd_spi_board_info[] __initdata = {
},
};
+static struct gpio cm_t35_dss_gpios[] __initdata = {
+ { CM_T35_LCD_EN_GPIO, GPIOF_OUT_INIT_LOW, "lcd enable" },
+ { CM_T35_LCD_BL_GPIO, GPIOF_OUT_INIT_LOW, "lcd bl enable" },
+ { CM_T35_DVI_EN_GPIO, GPIOF_OUT_INIT_HIGH, "dvi enable" },
+};
+
static void __init cm_t35_init_display(void)
{
int err;
- lcd_en_gpio = CM_T35_LCD_EN_GPIO;
- lcd_bl_gpio = CM_T35_LCD_BL_GPIO;
- dvi_en_gpio = CM_T35_DVI_EN_GPIO;
-
spi_register_board_info(cm_t35_lcd_spi_board_info,
ARRAY_SIZE(cm_t35_lcd_spi_board_info));
- err = gpio_request(lcd_en_gpio, "LCD RST");
- if (err) {
- pr_err("CM-T35: failed to get LCD reset GPIO\n");
- goto out;
- }
-
- err = gpio_request(lcd_bl_gpio, "LCD BL");
+ err = gpio_request_array(cm_t35_dss_gpios,
+ ARRAY_SIZE(cm_t35_dss_gpios));
if (err) {
- pr_err("CM-T35: failed to get LCD backlight control GPIO\n");
- goto err_lcd_bl;
- }
-
- err = gpio_request(dvi_en_gpio, "DVI EN");
- if (err) {
- pr_err("CM-T35: failed to get DVI reset GPIO\n");
- goto err_dvi_en;
+ pr_err("CM-T35: failed to request DSS control GPIOs\n");
+ return;
}
- gpio_export(lcd_en_gpio, 0);
- gpio_export(lcd_bl_gpio, 0);
- gpio_export(dvi_en_gpio, 0);
- gpio_direction_output(lcd_en_gpio, 0);
- gpio_direction_output(lcd_bl_gpio, 0);
- gpio_direction_output(dvi_en_gpio, 1);
+ gpio_export(CM_T35_LCD_EN_GPIO, 0);
+ gpio_export(CM_T35_LCD_BL_GPIO, 0);
+ gpio_export(CM_T35_DVI_EN_GPIO, 0);
msleep(50);
- gpio_set_value(lcd_en_gpio, 1);
+ gpio_set_value(CM_T35_LCD_EN_GPIO, 1);
err = omap_display_init(&cm_t35_dss_data);
if (err) {
pr_err("CM-T35: failed to register DSS device\n");
- goto err_dev_reg;
+ gpio_free_array(cm_t35_dss_gpios, ARRAY_SIZE(cm_t35_dss_gpios));
}
-
- return;
-
-err_dev_reg:
- gpio_free(dvi_en_gpio);
-err_dvi_en:
- gpio_free(lcd_bl_gpio);
-err_lcd_bl:
- gpio_free(lcd_en_gpio);
-out:
-
- return;
}
static struct regulator_consumer_supply cm_t35_vmmc1_supply = {
@@ -609,10 +469,8 @@ static int cm_t35_twl_gpio_setup(struct device *dev, unsigned gpio,
{
int wlan_rst = gpio + 2;
- if ((gpio_request(wlan_rst, "WLAN RST") == 0) &&
- (gpio_direction_output(wlan_rst, 1) == 0)) {
+ if (gpio_request_one(wlan_rst, GPIOF_OUT_INIT_HIGH, "WLAN RST") == 0) {
gpio_export(wlan_rst, 0);
-
udelay(10);
gpio_set_value(wlan_rst, 0);
udelay(10);
@@ -653,19 +511,9 @@ static struct twl4030_platform_data cm_t35_twldata = {
.vpll2 = &cm_t35_vpll2,
};
-static struct i2c_board_info __initdata cm_t35_i2c_boardinfo[] = {
- {
- I2C_BOARD_INFO("tps65930", 0x48),
- .flags = I2C_CLIENT_WAKE,
- .irq = INT_34XX_SYS_NIRQ,
- .platform_data = &cm_t35_twldata,
- },
-};
-
static void __init cm_t35_init_i2c(void)
{
- omap_register_i2c_bus(1, 2600, cm_t35_i2c_boardinfo,
- ARRAY_SIZE(cm_t35_i2c_boardinfo));
+ omap3_pmic_init("tps65930", &cm_t35_twldata);
}
static void __init cm_t35_init_early(void)
@@ -775,12 +623,6 @@ static struct omap_board_mux board_mux[] __initdata = {
};
#endif
-static struct omap_musb_board_data musb_board_data = {
- .interface_type = MUSB_INTERFACE_ULPI,
- .mode = MUSB_OTG,
- .power = 100,
-};
-
static struct omap_board_config_kernel cm_t35_config[] __initdata = {
};
@@ -792,12 +634,12 @@ static void __init cm_t35_init(void)
omap_serial_init();
cm_t35_init_i2c();
cm_t35_init_nand();
- cm_t35_init_ads7846();
+ omap_ads7846_init(1, CM_T35_GPIO_PENDOWN, 0, NULL);
cm_t35_init_ethernet();
cm_t35_init_led();
cm_t35_init_display();
- usb_musb_init(&musb_board_data);
+ usb_musb_init(NULL);
usbhs_init(&usbhs_bdata);
}
diff --git a/arch/arm/mach-omap2/board-cm-t3517.c b/arch/arm/mach-omap2/board-cm-t3517.c
index a27e3eee8292..08f08e812492 100644
--- a/arch/arm/mach-omap2/board-cm-t3517.c
+++ b/arch/arm/mach-omap2/board-cm-t3517.c
@@ -148,14 +148,13 @@ static void __init cm_t3517_init_rtc(void)
{
int err;
- err = gpio_request(RTC_CS_EN_GPIO, "rtc cs en");
+ err = gpio_request_one(RTC_CS_EN_GPIO, GPIOF_OUT_INIT_HIGH,
+ "rtc cs en");
if (err) {
pr_err("CM-T3517: rtc cs en gpio request failed: %d\n", err);
return;
}
- gpio_direction_output(RTC_CS_EN_GPIO, 1);
-
platform_device_register(&cm_t3517_rtc_device);
}
#else
@@ -182,11 +181,11 @@ static int cm_t3517_init_usbh(void)
{
int err;
- err = gpio_request(USB_HUB_RESET_GPIO, "usb hub rst");
+ err = gpio_request_one(USB_HUB_RESET_GPIO, GPIOF_OUT_INIT_LOW,
+ "usb hub rst");
if (err) {
pr_err("CM-T3517: usb hub rst gpio request failed: %d\n", err);
} else {
- gpio_direction_output(USB_HUB_RESET_GPIO, 0);
udelay(10);
gpio_set_value(USB_HUB_RESET_GPIO, 1);
msleep(1);
diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c
index 65f9fde2c567..cf520d7dd614 100644
--- a/arch/arm/mach-omap2/board-devkit8000.c
+++ b/arch/arm/mach-omap2/board-devkit8000.c
@@ -45,13 +45,12 @@
#include <plat/gpmc.h>
#include <plat/nand.h>
#include <plat/usb.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
#include <plat/mcspi.h>
#include <linux/input/matrix_keypad.h>
#include <linux/spi/spi.h>
-#include <linux/spi/ads7846.h>
#include <linux/dm9000.h>
#include <linux/interrupt.h>
@@ -60,6 +59,7 @@
#include "mux.h"
#include "hsmmc.h"
#include "timer-gp.h"
+#include "common-board-devices.h"
#define NAND_BLOCK_SIZE SZ_128K
@@ -97,13 +97,6 @@ static struct mtd_partition devkit8000_nand_partitions[] = {
},
};
-static struct omap_nand_platform_data devkit8000_nand_data = {
- .options = NAND_BUSWIDTH_16,
- .parts = devkit8000_nand_partitions,
- .nr_parts = ARRAY_SIZE(devkit8000_nand_partitions),
- .dma_channel = -1, /* disable DMA in OMAP NAND driver */
-};
-
static struct omap2_hsmmc_info mmc[] = {
{
.mmc = 1,
@@ -249,7 +242,7 @@ static int devkit8000_twl_gpio_setup(struct device *dev,
/* TWL4030_GPIO_MAX + 0 is "LCD_PWREN" (out, active high) */
devkit8000_lcd_device.reset_gpio = gpio + TWL4030_GPIO_MAX + 0;
ret = gpio_request_one(devkit8000_lcd_device.reset_gpio,
- GPIOF_DIR_OUT | GPIOF_INIT_LOW, "LCD_PWREN");
+ GPIOF_OUT_INIT_LOW, "LCD_PWREN");
if (ret < 0) {
devkit8000_lcd_device.reset_gpio = -EINVAL;
printk(KERN_ERR "Failed to request GPIO for LCD_PWRN\n");
@@ -258,7 +251,7 @@ static int devkit8000_twl_gpio_setup(struct device *dev,
/* gpio + 7 is "DVI_PD" (out, active low) */
devkit8000_dvi_device.reset_gpio = gpio + 7;
ret = gpio_request_one(devkit8000_dvi_device.reset_gpio,
- GPIOF_DIR_OUT | GPIOF_INIT_LOW, "DVI PowerDown");
+ GPIOF_OUT_INIT_LOW, "DVI PowerDown");
if (ret < 0) {
devkit8000_dvi_device.reset_gpio = -EINVAL;
printk(KERN_ERR "Failed to request GPIO for DVI PowerDown\n");
@@ -366,19 +359,9 @@ static struct twl4030_platform_data devkit8000_twldata = {
.keypad = &devkit8000_kp_data,
};
-static struct i2c_board_info __initdata devkit8000_i2c_boardinfo[] = {
- {
- I2C_BOARD_INFO("tps65930", 0x48),
- .flags = I2C_CLIENT_WAKE,
- .irq = INT_34XX_SYS_NIRQ,
- .platform_data = &devkit8000_twldata,
- },
-};
-
static int __init devkit8000_i2c_init(void)
{
- omap_register_i2c_bus(1, 2600, devkit8000_i2c_boardinfo,
- ARRAY_SIZE(devkit8000_i2c_boardinfo));
+ omap3_pmic_init("tps65930", &devkit8000_twldata);
/* Bus 3 is attached to the DVI port where devices like the pico DLP
* projector don't work reliably with 400kHz */
omap_register_i2c_bus(3, 400, NULL, 0);
@@ -463,56 +446,6 @@ static void __init devkit8000_init_irq(void)
#endif
}
-static void __init devkit8000_ads7846_init(void)
-{
- int gpio = OMAP3_DEVKIT_TS_GPIO;
- int ret;
-
- ret = gpio_request(gpio, "ads7846_pen_down");
- if (ret < 0) {
- printk(KERN_ERR "Failed to request GPIO %d for "
- "ads7846 pen down IRQ\n", gpio);
- return;
- }
-
- gpio_direction_input(gpio);
-}
-
-static int ads7846_get_pendown_state(void)
-{
- return !gpio_get_value(OMAP3_DEVKIT_TS_GPIO);
-}
-
-static struct ads7846_platform_data ads7846_config = {
- .x_max = 0x0fff,
- .y_max = 0x0fff,
- .x_plate_ohms = 180,
- .pressure_max = 255,
- .debounce_max = 10,
- .debounce_tol = 5,
- .debounce_rep = 1,
- .get_pendown_state = ads7846_get_pendown_state,
- .keep_vref_on = 1,
- .settle_delay_usecs = 150,
-};
-
-static struct omap2_mcspi_device_config ads7846_mcspi_config = {
- .turbo_mode = 0,
- .single_channel = 1, /* 0: slave, 1: master */
-};
-
-static struct spi_board_info devkit8000_spi_board_info[] __initdata = {
- {
- .modalias = "ads7846",
- .bus_num = 2,
- .chip_select = 0,
- .max_speed_hz = 1500000,
- .controller_data = &ads7846_mcspi_config,
- .irq = OMAP_GPIO_IRQ(OMAP3_DEVKIT_TS_GPIO),
- .platform_data = &ads7846_config,
- }
-};
-
#define OMAP_DM9000_BASE 0x2c000000
static struct resource omap_dm9000_resources[] = {
@@ -550,14 +483,14 @@ static void __init omap_dm9000_init(void)
{
unsigned char *eth_addr = omap_dm9000_platdata.dev_addr;
struct omap_die_id odi;
+ int ret;
- if (gpio_request(OMAP_DM9000_GPIO_IRQ, "dm9000 irq") < 0) {
+ ret = gpio_request_one(OMAP_DM9000_GPIO_IRQ, GPIOF_IN, "dm9000 irq");
+ if (ret < 0) {
printk(KERN_ERR "Failed to request GPIO%d for dm9000 IRQ\n",
OMAP_DM9000_GPIO_IRQ);
return;
- }
-
- gpio_direction_input(OMAP_DM9000_GPIO_IRQ);
+ }
/* init the mac address using DIE id */
omap_get_die_id(&odi);
@@ -576,45 +509,6 @@ static struct platform_device *devkit8000_devices[] __initdata = {
&omap_dm9000_dev,
};
-static void __init devkit8000_flash_init(void)
-{
- u8 cs = 0;
- u8 nandcs = GPMC_CS_NUM + 1;
-
- /* find out the chip-select on which NAND exists */
- while (cs < GPMC_CS_NUM) {
- u32 ret = 0;
- ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
-
- if ((ret & 0xC00) == 0x800) {
- printk(KERN_INFO "Found NAND on CS%d\n", cs);
- if (nandcs > GPMC_CS_NUM)
- nandcs = cs;
- }
- cs++;
- }
-
- if (nandcs > GPMC_CS_NUM) {
- printk(KERN_INFO "NAND: Unable to find configuration "
- "in GPMC\n ");
- return;
- }
-
- if (nandcs < GPMC_CS_NUM) {
- devkit8000_nand_data.cs = nandcs;
-
- printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
- if (gpmc_nand_init(&devkit8000_nand_data) < 0)
- printk(KERN_ERR "Unable to register NAND device\n");
- }
-}
-
-static struct omap_musb_board_data musb_board_data = {
- .interface_type = MUSB_INTERFACE_ULPI,
- .mode = MUSB_OTG,
- .power = 100,
-};
-
static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
@@ -795,14 +689,13 @@ static void __init devkit8000_init(void)
ARRAY_SIZE(devkit8000_devices));
omap_display_init(&devkit8000_dss_data);
- spi_register_board_info(devkit8000_spi_board_info,
- ARRAY_SIZE(devkit8000_spi_board_info));
- devkit8000_ads7846_init();
+ omap_ads7846_init(2, OMAP3_DEVKIT_TS_GPIO, 0, NULL);
- usb_musb_init(&musb_board_data);
+ usb_musb_init(NULL);
usbhs_init(&usbhs_bdata);
- devkit8000_flash_init();
+ omap_nand_flash_init(NAND_BUSWIDTH_16, devkit8000_nand_partitions,
+ ARRAY_SIZE(devkit8000_nand_partitions));
/* Ensure SDRC pins are mux'd for self-refresh */
omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c
index 34cf982b9679..0c1bfca3f731 100644
--- a/arch/arm/mach-omap2/board-igep0020.c
+++ b/arch/arm/mach-omap2/board-igep0020.c
@@ -31,13 +31,14 @@
#include <plat/common.h>
#include <plat/gpmc.h>
#include <plat/usb.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
#include <plat/onenand.h>
#include "mux.h"
#include "hsmmc.h"
#include "sdram-numonyx-m65kxxxxam.h"
+#include "common-board-devices.h"
#define IGEP2_SMSC911X_CS 5
#define IGEP2_SMSC911X_GPIO 176
@@ -54,6 +55,11 @@
#define IGEP2_RC_GPIO_WIFI_NRESET 139
#define IGEP2_RC_GPIO_BT_NRESET 137
+#define IGEP3_GPIO_LED0_GREEN 54
+#define IGEP3_GPIO_LED0_RED 53
+#define IGEP3_GPIO_LED1_RED 16
+#define IGEP3_GPIO_USBH_NRESET 183
+
/*
* IGEP2 Hardware Revision Table
*
@@ -68,6 +74,7 @@
#define IGEP2_BOARD_HWREV_B 0
#define IGEP2_BOARD_HWREV_C 1
+#define IGEP3_BOARD_HWREV 2
static u8 hwrev;
@@ -75,24 +82,29 @@ static void __init igep2_get_revision(void)
{
u8 ret;
+ if (machine_is_igep0030()) {
+ hwrev = IGEP3_BOARD_HWREV;
+ return;
+ }
+
omap_mux_init_gpio(IGEP2_GPIO_LED1_RED, OMAP_PIN_INPUT);
- if ((gpio_request(IGEP2_GPIO_LED1_RED, "GPIO_HW0_REV") == 0) &&
- (gpio_direction_input(IGEP2_GPIO_LED1_RED) == 0)) {
- ret = gpio_get_value(IGEP2_GPIO_LED1_RED);
- if (ret == 0) {
- pr_info("IGEP2: Hardware Revision C (B-NON compatible)\n");
- hwrev = IGEP2_BOARD_HWREV_C;
- } else if (ret == 1) {
- pr_info("IGEP2: Hardware Revision B/C (B compatible)\n");
- hwrev = IGEP2_BOARD_HWREV_B;
- } else {
- pr_err("IGEP2: Unknown Hardware Revision\n");
- hwrev = -1;
- }
- } else {
+ if (gpio_request_one(IGEP2_GPIO_LED1_RED, GPIOF_IN, "GPIO_HW0_REV")) {
pr_warning("IGEP2: Could not obtain gpio GPIO_HW0_REV\n");
pr_err("IGEP2: Unknown Hardware Revision\n");
+ return;
+ }
+
+ ret = gpio_get_value(IGEP2_GPIO_LED1_RED);
+ if (ret == 0) {
+ pr_info("IGEP2: Hardware Revision C (B-NON compatible)\n");
+ hwrev = IGEP2_BOARD_HWREV_C;
+ } else if (ret == 1) {
+ pr_info("IGEP2: Hardware Revision B/C (B compatible)\n");
+ hwrev = IGEP2_BOARD_HWREV_B;
+ } else {
+ pr_err("IGEP2: Unknown Hardware Revision\n");
+ hwrev = -1;
}
gpio_free(IGEP2_GPIO_LED1_RED);
@@ -111,7 +123,7 @@ static void __init igep2_get_revision(void)
* So MTD regards it as 4KiB page size and 256KiB block size 64*(2*2048)
*/
-static struct mtd_partition igep2_onenand_partitions[] = {
+static struct mtd_partition igep_onenand_partitions[] = {
{
.name = "X-Loader",
.offset = 0,
@@ -139,21 +151,21 @@ static struct mtd_partition igep2_onenand_partitions[] = {
},
};
-static struct omap_onenand_platform_data igep2_onenand_data = {
- .parts = igep2_onenand_partitions,
- .nr_parts = ARRAY_SIZE(igep2_onenand_partitions),
+static struct omap_onenand_platform_data igep_onenand_data = {
+ .parts = igep_onenand_partitions,
+ .nr_parts = ARRAY_SIZE(igep_onenand_partitions),
.dma_channel = -1, /* disable DMA in OMAP OneNAND driver */
};
-static struct platform_device igep2_onenand_device = {
+static struct platform_device igep_onenand_device = {
.name = "omap2-onenand",
.id = -1,
.dev = {
- .platform_data = &igep2_onenand_data,
+ .platform_data = &igep_onenand_data,
},
};
-static void __init igep2_flash_init(void)
+static void __init igep_flash_init(void)
{
u8 cs = 0;
u8 onenandcs = GPMC_CS_NUM + 1;
@@ -165,7 +177,7 @@ static void __init igep2_flash_init(void)
/* Check if NAND/oneNAND is configured */
if ((ret & 0xC00) == 0x800)
/* NAND found */
- pr_err("IGEP2: Unsupported NAND found\n");
+ pr_err("IGEP: Unsupported NAND found\n");
else {
ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
if ((ret & 0x3F) == (ONENAND_MAP >> 24))
@@ -175,85 +187,46 @@ static void __init igep2_flash_init(void)
}
if (onenandcs > GPMC_CS_NUM) {
- pr_err("IGEP2: Unable to find configuration in GPMC\n");
+ pr_err("IGEP: Unable to find configuration in GPMC\n");
return;
}
- igep2_onenand_data.cs = onenandcs;
+ igep_onenand_data.cs = onenandcs;
- if (platform_device_register(&igep2_onenand_device) < 0)
- pr_err("IGEP2: Unable to register OneNAND device\n");
+ if (platform_device_register(&igep_onenand_device) < 0)
+ pr_err("IGEP: Unable to register OneNAND device\n");
}
#else
-static void __init igep2_flash_init(void) {}
+static void __init igep_flash_init(void) {}
#endif
#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
#include <linux/smsc911x.h>
+#include <plat/gpmc-smsc911x.h>
-static struct smsc911x_platform_config igep2_smsc911x_config = {
- .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
- .irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
- .flags = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS ,
- .phy_interface = PHY_INTERFACE_MODE_MII,
-};
-
-static struct resource igep2_smsc911x_resources[] = {
- {
- .flags = IORESOURCE_MEM,
- },
- {
- .start = OMAP_GPIO_IRQ(IGEP2_SMSC911X_GPIO),
- .end = OMAP_GPIO_IRQ(IGEP2_SMSC911X_GPIO),
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
- },
-};
-
-static struct platform_device igep2_smsc911x_device = {
- .name = "smsc911x",
- .id = 0,
- .num_resources = ARRAY_SIZE(igep2_smsc911x_resources),
- .resource = igep2_smsc911x_resources,
- .dev = {
- .platform_data = &igep2_smsc911x_config,
- },
+static struct omap_smsc911x_platform_data smsc911x_cfg = {
+ .cs = IGEP2_SMSC911X_CS,
+ .gpio_irq = IGEP2_SMSC911X_GPIO,
+ .gpio_reset = -EINVAL,
+ .flags = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS,
};
static inline void __init igep2_init_smsc911x(void)
{
- unsigned long cs_mem_base;
-
- if (gpmc_cs_request(IGEP2_SMSC911X_CS, SZ_16M, &cs_mem_base) < 0) {
- pr_err("IGEP v2: Failed request for GPMC mem for smsc911x\n");
- gpmc_cs_free(IGEP2_SMSC911X_CS);
- return;
- }
-
- igep2_smsc911x_resources[0].start = cs_mem_base + 0x0;
- igep2_smsc911x_resources[0].end = cs_mem_base + 0xff;
-
- if ((gpio_request(IGEP2_SMSC911X_GPIO, "SMSC911X IRQ") == 0) &&
- (gpio_direction_input(IGEP2_SMSC911X_GPIO) == 0)) {
- gpio_export(IGEP2_SMSC911X_GPIO, 0);
- } else {
- pr_err("IGEP v2: Could not obtain gpio for for SMSC911X IRQ\n");
- return;
- }
-
- platform_device_register(&igep2_smsc911x_device);
+ gpmc_smsc911x_init(&smsc911x_cfg);
}
#else
static inline void __init igep2_init_smsc911x(void) { }
#endif
-static struct regulator_consumer_supply igep2_vmmc1_supply =
+static struct regulator_consumer_supply igep_vmmc1_supply =
REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0");
/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
-static struct regulator_init_data igep2_vmmc1 = {
+static struct regulator_init_data igep_vmmc1 = {
.constraints = {
.min_uV = 1850000,
.max_uV = 3150000,
@@ -264,13 +237,13 @@ static struct regulator_init_data igep2_vmmc1 = {
| REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = 1,
- .consumer_supplies = &igep2_vmmc1_supply,
+ .consumer_supplies = &igep_vmmc1_supply,
};
-static struct regulator_consumer_supply igep2_vio_supply =
+static struct regulator_consumer_supply igep_vio_supply =
REGULATOR_SUPPLY("vmmc_aux", "omap_hsmmc.1");
-static struct regulator_init_data igep2_vio = {
+static struct regulator_init_data igep_vio = {
.constraints = {
.min_uV = 1800000,
.max_uV = 1800000,
@@ -282,34 +255,34 @@ static struct regulator_init_data igep2_vio = {
| REGULATOR_CHANGE_STATUS,
},
.num_consumer_supplies = 1,
- .consumer_supplies = &igep2_vio_supply,
+ .consumer_supplies = &igep_vio_supply,
};
-static struct regulator_consumer_supply igep2_vmmc2_supply =
+static struct regulator_consumer_supply igep_vmmc2_supply =
REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1");
-static struct regulator_init_data igep2_vmmc2 = {
+static struct regulator_init_data igep_vmmc2 = {
.constraints = {
.valid_modes_mask = REGULATOR_MODE_NORMAL,
.always_on = 1,
},
.num_consumer_supplies = 1,
- .consumer_supplies = &igep2_vmmc2_supply,
+ .consumer_supplies = &igep_vmmc2_supply,
};
-static struct fixed_voltage_config igep2_vwlan = {
+static struct fixed_voltage_config igep_vwlan = {
.supply_name = "vwlan",
.microvolts = 3300000,
.gpio = -EINVAL,
.enabled_at_boot = 1,
- .init_data = &igep2_vmmc2,
+ .init_data = &igep_vmmc2,
};
-static struct platform_device igep2_vwlan_device = {
+static struct platform_device igep_vwlan_device = {
.name = "reg-fixed-voltage",
.id = 0,
.dev = {
- .platform_data = &igep2_vwlan,
+ .platform_data = &igep_vwlan,
},
};
@@ -334,20 +307,17 @@ static struct omap2_hsmmc_info mmc[] = {
#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
#include <linux/leds.h>
-static struct gpio_led igep2_gpio_leds[] = {
+static struct gpio_led igep_gpio_leds[] = {
[0] = {
.name = "gpio-led:red:d0",
- .gpio = IGEP2_GPIO_LED0_RED,
.default_trigger = "default-off"
},
[1] = {
.name = "gpio-led:green:d0",
- .gpio = IGEP2_GPIO_LED0_GREEN,
.default_trigger = "default-off",
},
[2] = {
.name = "gpio-led:red:d1",
- .gpio = IGEP2_GPIO_LED1_RED,
.default_trigger = "default-off",
},
[3] = {
@@ -358,94 +328,119 @@ static struct gpio_led igep2_gpio_leds[] = {
},
};
-static struct gpio_led_platform_data igep2_led_pdata = {
- .leds = igep2_gpio_leds,
- .num_leds = ARRAY_SIZE(igep2_gpio_leds),
+static struct gpio_led_platform_data igep_led_pdata = {
+ .leds = igep_gpio_leds,
+ .num_leds = ARRAY_SIZE(igep_gpio_leds),
};
-static struct platform_device igep2_led_device = {
+static struct platform_device igep_led_device = {
.name = "leds-gpio",
.id = -1,
.dev = {
- .platform_data = &igep2_led_pdata,
+ .platform_data = &igep_led_pdata,
},
};
-static void __init igep2_leds_init(void)
+static void __init igep_leds_init(void)
{
- platform_device_register(&igep2_led_device);
+ if (machine_is_igep0020()) {
+ igep_gpio_leds[0].gpio = IGEP2_GPIO_LED0_RED;
+ igep_gpio_leds[1].gpio = IGEP2_GPIO_LED0_GREEN;
+ igep_gpio_leds[2].gpio = IGEP2_GPIO_LED1_RED;
+ } else {
+ igep_gpio_leds[0].gpio = IGEP3_GPIO_LED0_RED;
+ igep_gpio_leds[1].gpio = IGEP3_GPIO_LED0_GREEN;
+ igep_gpio_leds[2].gpio = IGEP3_GPIO_LED1_RED;
+ }
+
+ platform_device_register(&igep_led_device);
}
#else
-static inline void igep2_leds_init(void)
+static struct gpio igep_gpio_leds[] __initdata = {
+ { -EINVAL, GPIOF_OUT_INIT_LOW, "gpio-led:red:d0" },
+ { -EINVAL, GPIOF_OUT_INIT_LOW, "gpio-led:green:d0" },
+ { -EINVAL, GPIOF_OUT_INIT_LOW, "gpio-led:red:d1" },
+};
+
+static inline void igep_leds_init(void)
{
- if ((gpio_request(IGEP2_GPIO_LED0_RED, "gpio-led:red:d0") == 0) &&
- (gpio_direction_output(IGEP2_GPIO_LED0_RED, 0) == 0))
- gpio_export(IGEP2_GPIO_LED0_RED, 0);
- else
- pr_warning("IGEP v2: Could not obtain gpio GPIO_LED0_RED\n");
+ int i;
- if ((gpio_request(IGEP2_GPIO_LED0_GREEN, "gpio-led:green:d0") == 0) &&
- (gpio_direction_output(IGEP2_GPIO_LED0_GREEN, 0) == 0))
- gpio_export(IGEP2_GPIO_LED0_GREEN, 0);
- else
- pr_warning("IGEP v2: Could not obtain gpio GPIO_LED0_GREEN\n");
+ if (machine_is_igep0020()) {
+ igep_gpio_leds[0].gpio = IGEP2_GPIO_LED0_RED;
+ igep_gpio_leds[1].gpio = IGEP2_GPIO_LED0_GREEN;
+ igep_gpio_leds[2].gpio = IGEP2_GPIO_LED1_RED;
+ } else {
+ igep_gpio_leds[0].gpio = IGEP3_GPIO_LED0_RED;
+ igep_gpio_leds[1].gpio = IGEP3_GPIO_LED0_GREEN;
+ igep_gpio_leds[2].gpio = IGEP3_GPIO_LED1_RED;
+ }
- if ((gpio_request(IGEP2_GPIO_LED1_RED, "gpio-led:red:d1") == 0) &&
- (gpio_direction_output(IGEP2_GPIO_LED1_RED, 0) == 0))
- gpio_export(IGEP2_GPIO_LED1_RED, 0);
- else
- pr_warning("IGEP v2: Could not obtain gpio GPIO_LED1_RED\n");
+ if (gpio_request_array(igep_gpio_leds, ARRAY_SIZE(igep_gpio_leds))) {
+ pr_warning("IGEP v2: Could not obtain leds gpios\n");
+ return;
+ }
+ for (i = 0; i < ARRAY_SIZE(igep_gpio_leds); i++)
+ gpio_export(igep_gpio_leds[i].gpio, 0);
}
#endif
-static int igep2_twl_gpio_setup(struct device *dev,
+static struct gpio igep2_twl_gpios[] = {
+ { -EINVAL, GPIOF_IN, "GPIO_EHCI_NOC" },
+ { -EINVAL, GPIOF_OUT_INIT_LOW, "GPIO_USBH_CPEN" },
+};
+
+static int igep_twl_gpio_setup(struct device *dev,
unsigned gpio, unsigned ngpio)
{
+ int ret;
+
/* gpio + 0 is "mmc0_cd" (input/IRQ) */
mmc[0].gpio_cd = gpio + 0;
omap2_hsmmc_init(mmc);
- /*
- * REVISIT: need ehci-omap hooks for external VBUS
- * power switch and overcurrent detect
- */
- if ((gpio_request(gpio + 1, "GPIO_EHCI_NOC") < 0) ||
- (gpio_direction_input(gpio + 1) < 0))
- pr_err("IGEP2: Could not obtain gpio for EHCI NOC");
-
- /*
- * TWL4030_GPIO_MAX + 0 == ledA, GPIO_USBH_CPEN
- * (out, active low)
- */
- if ((gpio_request(gpio + TWL4030_GPIO_MAX, "GPIO_USBH_CPEN") < 0) ||
- (gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0) < 0))
- pr_err("IGEP2: Could not obtain gpio for USBH_CPEN");
-
/* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */
#if !defined(CONFIG_LEDS_GPIO) && !defined(CONFIG_LEDS_GPIO_MODULE)
- if ((gpio_request(gpio+TWL4030_GPIO_MAX+1, "gpio-led:green:d1") == 0)
- && (gpio_direction_output(gpio + TWL4030_GPIO_MAX + 1, 1) == 0))
+ ret = gpio_request_one(gpio + TWL4030_GPIO_MAX + 1, GPIOF_OUT_INIT_HIGH,
+ "gpio-led:green:d1");
+ if (ret == 0)
gpio_export(gpio + TWL4030_GPIO_MAX + 1, 0);
else
- pr_warning("IGEP v2: Could not obtain gpio GPIO_LED1_GREEN\n");
+ pr_warning("IGEP: Could not obtain gpio GPIO_LED1_GREEN\n");
#else
- igep2_gpio_leds[3].gpio = gpio + TWL4030_GPIO_MAX + 1;
+ igep_gpio_leds[3].gpio = gpio + TWL4030_GPIO_MAX + 1;
#endif
+ if (machine_is_igep0030())
+ return 0;
+
+ /*
+ * REVISIT: need ehci-omap hooks for external VBUS
+ * power switch and overcurrent detect
+ */
+ igep2_twl_gpios[0].gpio = gpio + 1;
+
+ /* TWL4030_GPIO_MAX + 0 == ledA, GPIO_USBH_CPEN (out, active low) */
+ igep2_twl_gpios[1].gpio = gpio + TWL4030_GPIO_MAX;
+
+ ret = gpio_request_array(igep2_twl_gpios, ARRAY_SIZE(igep2_twl_gpios));
+ if (ret < 0)
+ pr_err("IGEP2: Could not obtain gpio for USBH_CPEN");
+
return 0;
};
-static struct twl4030_gpio_platform_data igep2_twl4030_gpio_pdata = {
+static struct twl4030_gpio_platform_data igep_twl4030_gpio_pdata = {
.gpio_base = OMAP_MAX_GPIO_LINES,
.irq_base = TWL4030_GPIO_IRQ_BASE,
.irq_end = TWL4030_GPIO_IRQ_END,
.use_leds = true,
- .setup = igep2_twl_gpio_setup,
+ .setup = igep_twl_gpio_setup,
};
-static struct twl4030_usb_data igep2_usb_data = {
+static struct twl4030_usb_data igep_usb_data = {
.usb_mode = T2_USB_MODE_ULPI,
};
@@ -507,16 +502,17 @@ static struct regulator_init_data igep2_vpll2 = {
static void __init igep2_display_init(void)
{
- if (gpio_request(IGEP2_GPIO_DVI_PUP, "GPIO_DVI_PUP") &&
- gpio_direction_output(IGEP2_GPIO_DVI_PUP, 1))
+ int err = gpio_request_one(IGEP2_GPIO_DVI_PUP, GPIOF_OUT_INIT_HIGH,
+ "GPIO_DVI_PUP");
+ if (err)
pr_err("IGEP v2: Could not obtain gpio GPIO_DVI_PUP\n");
}
-static struct platform_device *igep2_devices[] __initdata = {
- &igep2_vwlan_device,
+static struct platform_device *igep_devices[] __initdata = {
+ &igep_vwlan_device,
};
-static void __init igep2_init_early(void)
+static void __init igep_init_early(void)
{
omap2_init_common_infrastructure();
omap2_init_common_devices(m65kxxxxam_sdrc_params,
@@ -561,27 +557,15 @@ static struct twl4030_keypad_data igep2_keypad_pdata = {
.rep = 1,
};
-static struct twl4030_platform_data igep2_twldata = {
+static struct twl4030_platform_data igep_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */
- .usb = &igep2_usb_data,
- .codec = &igep2_codec_data,
- .gpio = &igep2_twl4030_gpio_pdata,
- .keypad = &igep2_keypad_pdata,
- .vmmc1 = &igep2_vmmc1,
- .vpll2 = &igep2_vpll2,
- .vio = &igep2_vio,
-};
-
-static struct i2c_board_info __initdata igep2_i2c1_boardinfo[] = {
- {
- I2C_BOARD_INFO("twl4030", 0x48),
- .flags = I2C_CLIENT_WAKE,
- .irq = INT_34XX_SYS_NIRQ,
- .platform_data = &igep2_twldata,
- },
+ .usb = &igep_usb_data,
+ .gpio = &igep_twl4030_gpio_pdata,
+ .vmmc1 = &igep_vmmc1,
+ .vio = &igep_vio,
};
static struct i2c_board_info __initdata igep2_i2c3_boardinfo[] = {
@@ -590,32 +574,29 @@ static struct i2c_board_info __initdata igep2_i2c3_boardinfo[] = {
},
};
-static void __init igep2_i2c_init(void)
+static void __init igep_i2c_init(void)
{
int ret;
- ret = omap_register_i2c_bus(1, 2600, igep2_i2c1_boardinfo,
- ARRAY_SIZE(igep2_i2c1_boardinfo));
- if (ret)
- pr_warning("IGEP2: Could not register I2C1 bus (%d)\n", ret);
+ if (machine_is_igep0020()) {
+ /*
+ * Bus 3 is attached to the DVI port where devices like the
+ * pico DLP projector don't work reliably with 400kHz
+ */
+ ret = omap_register_i2c_bus(3, 100, igep2_i2c3_boardinfo,
+ ARRAY_SIZE(igep2_i2c3_boardinfo));
+ if (ret)
+ pr_warning("IGEP2: Could not register I2C3 bus (%d)\n", ret);
+
+ igep_twldata.codec = &igep2_codec_data;
+ igep_twldata.keypad = &igep2_keypad_pdata;
+ igep_twldata.vpll2 = &igep2_vpll2;
+ }
- /*
- * Bus 3 is attached to the DVI port where devices like the pico DLP
- * projector don't work reliably with 400kHz
- */
- ret = omap_register_i2c_bus(3, 100, igep2_i2c3_boardinfo,
- ARRAY_SIZE(igep2_i2c3_boardinfo));
- if (ret)
- pr_warning("IGEP2: Could not register I2C3 bus (%d)\n", ret);
+ omap3_pmic_init("twl4030", &igep_twldata);
}
-static struct omap_musb_board_data musb_board_data = {
- .interface_type = MUSB_INTERFACE_ULPI,
- .mode = MUSB_OTG,
- .power = 100,
-};
-
-static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
+static const struct usbhs_omap_board_data igep2_usbhs_bdata __initconst = {
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
.port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED,
.port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
@@ -626,6 +607,17 @@ static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
.reset_gpio_port[2] = -EINVAL,
};
+static const struct usbhs_omap_board_data igep3_usbhs_bdata __initconst = {
+ .port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED,
+ .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
+ .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
+
+ .phy_reset = true,
+ .reset_gpio_port[0] = -EINVAL,
+ .reset_gpio_port[1] = IGEP3_GPIO_USBH_NRESET,
+ .reset_gpio_port[2] = -EINVAL,
+};
+
#ifdef CONFIG_OMAP_MUX
static struct omap_board_mux board_mux[] __initdata = {
{ .reg_offset = OMAP_MUX_TERMINATOR },
@@ -633,82 +625,95 @@ static struct omap_board_mux board_mux[] __initdata = {
#endif
#if defined(CONFIG_LIBERTAS_SDIO) || defined(CONFIG_LIBERTAS_SDIO_MODULE)
+static struct gpio igep_wlan_bt_gpios[] __initdata = {
+ { -EINVAL, GPIOF_OUT_INIT_HIGH, "GPIO_WIFI_NPD" },
+ { -EINVAL, GPIOF_OUT_INIT_HIGH, "GPIO_WIFI_NRESET" },
+ { -EINVAL, GPIOF_OUT_INIT_HIGH, "GPIO_BT_NRESET" },
+};
-static void __init igep2_wlan_bt_init(void)
+static void __init igep_wlan_bt_init(void)
{
- unsigned npd, wreset, btreset;
+ int err;
/* GPIO's for WLAN-BT combo depends on hardware revision */
if (hwrev == IGEP2_BOARD_HWREV_B) {
- npd = IGEP2_RB_GPIO_WIFI_NPD;
- wreset = IGEP2_RB_GPIO_WIFI_NRESET;
- btreset = IGEP2_RB_GPIO_BT_NRESET;
- } else if (hwrev == IGEP2_BOARD_HWREV_C) {
- npd = IGEP2_RC_GPIO_WIFI_NPD;
- wreset = IGEP2_RC_GPIO_WIFI_NRESET;
- btreset = IGEP2_RC_GPIO_BT_NRESET;
+ igep_wlan_bt_gpios[0].gpio = IGEP2_RB_GPIO_WIFI_NPD;
+ igep_wlan_bt_gpios[1].gpio = IGEP2_RB_GPIO_WIFI_NRESET;
+ igep_wlan_bt_gpios[2].gpio = IGEP2_RB_GPIO_BT_NRESET;
+ } else if (hwrev == IGEP2_BOARD_HWREV_C || machine_is_igep0030()) {
+ igep_wlan_bt_gpios[0].gpio = IGEP2_RC_GPIO_WIFI_NPD;
+ igep_wlan_bt_gpios[1].gpio = IGEP2_RC_GPIO_WIFI_NRESET;
+ igep_wlan_bt_gpios[2].gpio = IGEP2_RC_GPIO_BT_NRESET;
} else
return;
- /* Set GPIO's for WLAN-BT combo module */
- if ((gpio_request(npd, "GPIO_WIFI_NPD") == 0) &&
- (gpio_direction_output(npd, 1) == 0)) {
- gpio_export(npd, 0);
- } else
- pr_warning("IGEP2: Could not obtain gpio GPIO_WIFI_NPD\n");
-
- if ((gpio_request(wreset, "GPIO_WIFI_NRESET") == 0) &&
- (gpio_direction_output(wreset, 1) == 0)) {
- gpio_export(wreset, 0);
- gpio_set_value(wreset, 0);
- udelay(10);
- gpio_set_value(wreset, 1);
- } else
- pr_warning("IGEP2: Could not obtain gpio GPIO_WIFI_NRESET\n");
+ err = gpio_request_array(igep_wlan_bt_gpios,
+ ARRAY_SIZE(igep_wlan_bt_gpios));
+ if (err) {
+ pr_warning("IGEP2: Could not obtain WIFI/BT gpios\n");
+ return;
+ }
+
+ gpio_export(igep_wlan_bt_gpios[0].gpio, 0);
+ gpio_export(igep_wlan_bt_gpios[1].gpio, 0);
+ gpio_export(igep_wlan_bt_gpios[2].gpio, 0);
+
+ gpio_set_value(igep_wlan_bt_gpios[1].gpio, 0);
+ udelay(10);
+ gpio_set_value(igep_wlan_bt_gpios[1].gpio, 1);
- if ((gpio_request(btreset, "GPIO_BT_NRESET") == 0) &&
- (gpio_direction_output(btreset, 1) == 0)) {
- gpio_export(btreset, 0);
- } else
- pr_warning("IGEP2: Could not obtain gpio GPIO_BT_NRESET\n");
}
#else
-static inline void __init igep2_wlan_bt_init(void) { }
+static inline void __init igep_wlan_bt_init(void) { }
#endif
-static void __init igep2_init(void)
+static void __init igep_init(void)
{
omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
/* Get IGEP2 hardware revision */
igep2_get_revision();
/* Register I2C busses and drivers */
- igep2_i2c_init();
- platform_add_devices(igep2_devices, ARRAY_SIZE(igep2_devices));
- omap_display_init(&igep2_dss_data);
+ igep_i2c_init();
+ platform_add_devices(igep_devices, ARRAY_SIZE(igep_devices));
omap_serial_init();
- usb_musb_init(&musb_board_data);
- usbhs_init(&usbhs_bdata);
+ usb_musb_init(NULL);
- igep2_flash_init();
- igep2_leds_init();
- igep2_display_init();
- igep2_init_smsc911x();
+ igep_flash_init();
+ igep_leds_init();
/*
* WLAN-BT combo module from MuRata which has a Marvell WLAN
* (88W8686) + CSR Bluetooth chipset. Uses SDIO interface.
*/
- igep2_wlan_bt_init();
+ igep_wlan_bt_init();
+ if (machine_is_igep0020()) {
+ omap_display_init(&igep2_dss_data);
+ igep2_display_init();
+ igep2_init_smsc911x();
+ usbhs_init(&igep2_usbhs_bdata);
+ } else {
+ usbhs_init(&igep3_usbhs_bdata);
+ }
}
MACHINE_START(IGEP0020, "IGEP v2 board")
.boot_params = 0x80000100,
.reserve = omap_reserve,
.map_io = omap3_map_io,
- .init_early = igep2_init_early,
+ .init_early = igep_init_early,
+ .init_irq = omap_init_irq,
+ .init_machine = igep_init,
+ .timer = &omap_timer,
+MACHINE_END
+
+MACHINE_START(IGEP0030, "IGEP OMAP3 module")
+ .boot_params = 0x80000100,
+ .reserve = omap_reserve,
+ .map_io = omap3_map_io,
+ .init_early = igep_init_early,
.init_irq = omap_init_irq,
- .init_machine = igep2_init,
+ .init_machine = igep_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-igep0030.c b/arch/arm/mach-omap2/board-igep0030.c
deleted file mode 100644
index 2cf86c3cb1a3..000000000000
--- a/arch/arm/mach-omap2/board-igep0030.c
+++ /dev/null
@@ -1,458 +0,0 @@
-/*
- * Copyright (C) 2010 - ISEE 2007 SL
- *
- * Modified from mach-omap2/board-generic.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/interrupt.h>
-
-#include <linux/regulator/machine.h>
-#include <linux/regulator/fixed.h>
-#include <linux/i2c/twl.h>
-#include <linux/mmc/host.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-#include <plat/board.h>
-#include <plat/common.h>
-#include <plat/gpmc.h>
-#include <plat/usb.h>
-#include <plat/onenand.h>
-
-#include "mux.h"
-#include "hsmmc.h"
-#include "sdram-numonyx-m65kxxxxam.h"
-
-#define IGEP3_GPIO_LED0_GREEN 54
-#define IGEP3_GPIO_LED0_RED 53
-#define IGEP3_GPIO_LED1_RED 16
-
-#define IGEP3_GPIO_WIFI_NPD 138
-#define IGEP3_GPIO_WIFI_NRESET 139
-#define IGEP3_GPIO_BT_NRESET 137
-
-#define IGEP3_GPIO_USBH_NRESET 183
-
-
-#if defined(CONFIG_MTD_ONENAND_OMAP2) || \
- defined(CONFIG_MTD_ONENAND_OMAP2_MODULE)
-
-#define ONENAND_MAP 0x20000000
-
-/*
- * x2 Flash built-in COMBO POP MEMORY
- * Since the device is equipped with two DataRAMs, and two-plane NAND
- * Flash memory array, these two component enables simultaneous program
- * of 4KiB. Plane1 has only even blocks such as block0, block2, block4
- * while Plane2 has only odd blocks such as block1, block3, block5.
- * So MTD regards it as 4KiB page size and 256KiB block size 64*(2*2048)
- */
-
-static struct mtd_partition igep3_onenand_partitions[] = {
- {
- .name = "X-Loader",
- .offset = 0,
- .size = 2 * (64*(2*2048))
- },
- {
- .name = "U-Boot",
- .offset = MTDPART_OFS_APPEND,
- .size = 6 * (64*(2*2048)),
- },
- {
- .name = "Environment",
- .offset = MTDPART_OFS_APPEND,
- .size = 2 * (64*(2*2048)),
- },
- {
- .name = "Kernel",
- .offset = MTDPART_OFS_APPEND,
- .size = 12 * (64*(2*2048)),
- },
- {
- .name = "File System",
- .offset = MTDPART_OFS_APPEND,
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-static struct omap_onenand_platform_data igep3_onenand_pdata = {
- .parts = igep3_onenand_partitions,
- .nr_parts = ARRAY_SIZE(igep3_onenand_partitions),
- .onenand_setup = NULL,
- .dma_channel = -1, /* disable DMA in OMAP OneNAND driver */
-};
-
-static struct platform_device igep3_onenand_device = {
- .name = "omap2-onenand",
- .id = -1,
- .dev = {
- .platform_data = &igep3_onenand_pdata,
- },
-};
-
-static void __init igep3_flash_init(void)
-{
- u8 cs = 0;
- u8 onenandcs = GPMC_CS_NUM + 1;
-
- for (cs = 0; cs < GPMC_CS_NUM; cs++) {
- u32 ret;
- ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
-
- /* Check if NAND/oneNAND is configured */
- if ((ret & 0xC00) == 0x800)
- /* NAND found */
- pr_err("IGEP3: Unsupported NAND found\n");
- else {
- ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
-
- if ((ret & 0x3F) == (ONENAND_MAP >> 24))
- /* OneNAND found */
- onenandcs = cs;
- }
- }
-
- if (onenandcs > GPMC_CS_NUM) {
- pr_err("IGEP3: Unable to find configuration in GPMC\n");
- return;
- }
-
- igep3_onenand_pdata.cs = onenandcs;
-
- if (platform_device_register(&igep3_onenand_device) < 0)
- pr_err("IGEP3: Unable to register OneNAND device\n");
-}
-
-#else
-static void __init igep3_flash_init(void) {}
-#endif
-
-static struct regulator_consumer_supply igep3_vmmc1_supply =
- REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0");
-
-/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
-static struct regulator_init_data igep3_vmmc1 = {
- .constraints = {
- .min_uV = 1850000,
- .max_uV = 3150000,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
- | REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = 1,
- .consumer_supplies = &igep3_vmmc1_supply,
-};
-
-static struct regulator_consumer_supply igep3_vio_supply =
- REGULATOR_SUPPLY("vmmc_aux", "omap_hsmmc.1");
-
-static struct regulator_init_data igep3_vio = {
- .constraints = {
- .min_uV = 1800000,
- .max_uV = 1800000,
- .apply_uV = 1,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
- | REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = 1,
- .consumer_supplies = &igep3_vio_supply,
-};
-
-static struct regulator_consumer_supply igep3_vmmc2_supply =
- REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1");
-
-static struct regulator_init_data igep3_vmmc2 = {
- .constraints = {
- .valid_modes_mask = REGULATOR_MODE_NORMAL,
- .always_on = 1,
- },
- .num_consumer_supplies = 1,
- .consumer_supplies = &igep3_vmmc2_supply,
-};
-
-static struct fixed_voltage_config igep3_vwlan = {
- .supply_name = "vwlan",
- .microvolts = 3300000,
- .gpio = -EINVAL,
- .enabled_at_boot = 1,
- .init_data = &igep3_vmmc2,
-};
-
-static struct platform_device igep3_vwlan_device = {
- .name = "reg-fixed-voltage",
- .id = 0,
- .dev = {
- .platform_data = &igep3_vwlan,
- },
-};
-
-static struct omap2_hsmmc_info mmc[] = {
- [0] = {
- .mmc = 1,
- .caps = MMC_CAP_4_BIT_DATA,
- .gpio_cd = -EINVAL,
- .gpio_wp = -EINVAL,
- },
-#if defined(CONFIG_LIBERTAS_SDIO) || defined(CONFIG_LIBERTAS_SDIO_MODULE)
- [1] = {
- .mmc = 2,
- .caps = MMC_CAP_4_BIT_DATA,
- .gpio_cd = -EINVAL,
- .gpio_wp = -EINVAL,
- },
-#endif
- {} /* Terminator */
-};
-
-#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
-#include <linux/leds.h>
-
-static struct gpio_led igep3_gpio_leds[] = {
- [0] = {
- .name = "gpio-led:red:d0",
- .gpio = IGEP3_GPIO_LED0_RED,
- .default_trigger = "default-off"
- },
- [1] = {
- .name = "gpio-led:green:d0",
- .gpio = IGEP3_GPIO_LED0_GREEN,
- .default_trigger = "default-off",
- },
- [2] = {
- .name = "gpio-led:red:d1",
- .gpio = IGEP3_GPIO_LED1_RED,
- .default_trigger = "default-off",
- },
- [3] = {
- .name = "gpio-led:green:d1",
- .default_trigger = "heartbeat",
- .gpio = -EINVAL, /* gets replaced */
- },
-};
-
-static struct gpio_led_platform_data igep3_led_pdata = {
- .leds = igep3_gpio_leds,
- .num_leds = ARRAY_SIZE(igep3_gpio_leds),
-};
-
-static struct platform_device igep3_led_device = {
- .name = "leds-gpio",
- .id = -1,
- .dev = {
- .platform_data = &igep3_led_pdata,
- },
-};
-
-static void __init igep3_leds_init(void)
-{
- platform_device_register(&igep3_led_device);
-}
-
-#else
-static inline void igep3_leds_init(void)
-{
- if ((gpio_request(IGEP3_GPIO_LED0_RED, "gpio-led:red:d0") == 0) &&
- (gpio_direction_output(IGEP3_GPIO_LED0_RED, 1) == 0)) {
- gpio_export(IGEP3_GPIO_LED0_RED, 0);
- gpio_set_value(IGEP3_GPIO_LED0_RED, 1);
- } else
- pr_warning("IGEP3: Could not obtain gpio GPIO_LED0_RED\n");
-
- if ((gpio_request(IGEP3_GPIO_LED0_GREEN, "gpio-led:green:d0") == 0) &&
- (gpio_direction_output(IGEP3_GPIO_LED0_GREEN, 1) == 0)) {
- gpio_export(IGEP3_GPIO_LED0_GREEN, 0);
- gpio_set_value(IGEP3_GPIO_LED0_GREEN, 1);
- } else
- pr_warning("IGEP3: Could not obtain gpio GPIO_LED0_GREEN\n");
-
- if ((gpio_request(IGEP3_GPIO_LED1_RED, "gpio-led:red:d1") == 0) &&
- (gpio_direction_output(IGEP3_GPIO_LED1_RED, 1) == 0)) {
- gpio_export(IGEP3_GPIO_LED1_RED, 0);
- gpio_set_value(IGEP3_GPIO_LED1_RED, 1);
- } else
- pr_warning("IGEP3: Could not obtain gpio GPIO_LED1_RED\n");
-}
-#endif
-
-static int igep3_twl4030_gpio_setup(struct device *dev,
- unsigned gpio, unsigned ngpio)
-{
- /* gpio + 0 is "mmc0_cd" (input/IRQ) */
- mmc[0].gpio_cd = gpio + 0;
- omap2_hsmmc_init(mmc);
-
- /* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */
-#if !defined(CONFIG_LEDS_GPIO) && !defined(CONFIG_LEDS_GPIO_MODULE)
- if ((gpio_request(gpio+TWL4030_GPIO_MAX+1, "gpio-led:green:d1") == 0)
- && (gpio_direction_output(gpio + TWL4030_GPIO_MAX + 1, 1) == 0)) {
- gpio_export(gpio + TWL4030_GPIO_MAX + 1, 0);
- gpio_set_value(gpio + TWL4030_GPIO_MAX + 1, 0);
- } else
- pr_warning("IGEP3: Could not obtain gpio GPIO_LED1_GREEN\n");
-#else
- igep3_gpio_leds[3].gpio = gpio + TWL4030_GPIO_MAX + 1;
-#endif
-
- return 0;
-};
-
-static struct twl4030_gpio_platform_data igep3_twl4030_gpio_pdata = {
- .gpio_base = OMAP_MAX_GPIO_LINES,
- .irq_base = TWL4030_GPIO_IRQ_BASE,
- .irq_end = TWL4030_GPIO_IRQ_END,
- .use_leds = true,
- .setup = igep3_twl4030_gpio_setup,
-};
-
-static struct twl4030_usb_data igep3_twl4030_usb_data = {
- .usb_mode = T2_USB_MODE_ULPI,
-};
-
-static struct platform_device *igep3_devices[] __initdata = {
- &igep3_vwlan_device,
-};
-
-static void __init igep3_init_early(void)
-{
- omap2_init_common_infrastructure();
- omap2_init_common_devices(m65kxxxxam_sdrc_params,
- m65kxxxxam_sdrc_params);
-}
-
-static struct twl4030_platform_data igep3_twl4030_pdata = {
- .irq_base = TWL4030_IRQ_BASE,
- .irq_end = TWL4030_IRQ_END,
-
- /* platform_data for children goes here */
- .usb = &igep3_twl4030_usb_data,
- .gpio = &igep3_twl4030_gpio_pdata,
- .vmmc1 = &igep3_vmmc1,
- .vio = &igep3_vio,
-};
-
-static struct i2c_board_info __initdata igep3_i2c_boardinfo[] = {
- {
- I2C_BOARD_INFO("twl4030", 0x48),
- .flags = I2C_CLIENT_WAKE,
- .irq = INT_34XX_SYS_NIRQ,
- .platform_data = &igep3_twl4030_pdata,
- },
-};
-
-static int __init igep3_i2c_init(void)
-{
- omap_register_i2c_bus(1, 2600, igep3_i2c_boardinfo,
- ARRAY_SIZE(igep3_i2c_boardinfo));
-
- return 0;
-}
-
-static struct omap_musb_board_data musb_board_data = {
- .interface_type = MUSB_INTERFACE_ULPI,
- .mode = MUSB_OTG,
- .power = 100,
-};
-
-#if defined(CONFIG_LIBERTAS_SDIO) || defined(CONFIG_LIBERTAS_SDIO_MODULE)
-
-static void __init igep3_wifi_bt_init(void)
-{
- /* Configure MUX values for W-LAN + Bluetooth GPIO's */
- omap_mux_init_gpio(IGEP3_GPIO_WIFI_NPD, OMAP_PIN_OUTPUT);
- omap_mux_init_gpio(IGEP3_GPIO_WIFI_NRESET, OMAP_PIN_OUTPUT);
- omap_mux_init_gpio(IGEP3_GPIO_BT_NRESET, OMAP_PIN_OUTPUT);
-
- /* Set GPIO's for W-LAN + Bluetooth combo module */
- if ((gpio_request(IGEP3_GPIO_WIFI_NPD, "GPIO_WIFI_NPD") == 0) &&
- (gpio_direction_output(IGEP3_GPIO_WIFI_NPD, 1) == 0)) {
- gpio_export(IGEP3_GPIO_WIFI_NPD, 0);
- } else
- pr_warning("IGEP3: Could not obtain gpio GPIO_WIFI_NPD\n");
-
- if ((gpio_request(IGEP3_GPIO_WIFI_NRESET, "GPIO_WIFI_NRESET") == 0) &&
- (gpio_direction_output(IGEP3_GPIO_WIFI_NRESET, 1) == 0)) {
- gpio_export(IGEP3_GPIO_WIFI_NRESET, 0);
- gpio_set_value(IGEP3_GPIO_WIFI_NRESET, 0);
- udelay(10);
- gpio_set_value(IGEP3_GPIO_WIFI_NRESET, 1);
- } else
- pr_warning("IGEP3: Could not obtain gpio GPIO_WIFI_NRESET\n");
-
- if ((gpio_request(IGEP3_GPIO_BT_NRESET, "GPIO_BT_NRESET") == 0) &&
- (gpio_direction_output(IGEP3_GPIO_BT_NRESET, 1) == 0)) {
- gpio_export(IGEP3_GPIO_BT_NRESET, 0);
- } else
- pr_warning("IGEP3: Could not obtain gpio GPIO_BT_NRESET\n");
-}
-#else
-void __init igep3_wifi_bt_init(void) {}
-#endif
-
-static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
- .port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED,
- .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
- .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED,
-
- .phy_reset = true,
- .reset_gpio_port[0] = -EINVAL,
- .reset_gpio_port[1] = IGEP3_GPIO_USBH_NRESET,
- .reset_gpio_port[2] = -EINVAL,
-};
-
-#ifdef CONFIG_OMAP_MUX
-static struct omap_board_mux board_mux[] __initdata = {
- OMAP3_MUX(I2C2_SDA, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
- { .reg_offset = OMAP_MUX_TERMINATOR },
-};
-#endif
-
-static void __init igep3_init(void)
-{
- omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
-
- /* Register I2C busses and drivers */
- igep3_i2c_init();
- platform_add_devices(igep3_devices, ARRAY_SIZE(igep3_devices));
- omap_serial_init();
- usb_musb_init(&musb_board_data);
- usbhs_init(&usbhs_bdata);
-
- igep3_flash_init();
- igep3_leds_init();
-
- /*
- * WLAN-BT combo module from MuRata which has a Marvell WLAN
- * (88W8686) + CSR Bluetooth chipset. Uses SDIO interface.
- */
- igep3_wifi_bt_init();
-
-}
-
-MACHINE_START(IGEP0030, "IGEP OMAP3 module")
- .boot_params = 0x80000100,
- .reserve = omap_reserve,
- .map_io = omap3_map_io,
- .init_early = igep3_init_early,
- .init_irq = omap_init_irq,
- .init_machine = igep3_init,
- .timer = &omap_timer,
-MACHINE_END
diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c
index e2ba77957a8c..f7d6038075f0 100644
--- a/arch/arm/mach-omap2/board-ldp.c
+++ b/arch/arm/mach-omap2/board-ldp.c
@@ -22,7 +22,6 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/spi/spi.h>
-#include <linux/spi/ads7846.h>
#include <linux/regulator/machine.h>
#include <linux/i2c/twl.h>
#include <linux/io.h>
@@ -43,47 +42,19 @@
#include <asm/delay.h>
#include <plat/usb.h>
+#include <plat/gpmc-smsc911x.h>
#include "board-flash.h"
#include "mux.h"
#include "hsmmc.h"
#include "control.h"
+#include "common-board-devices.h"
#define LDP_SMSC911X_CS 1
#define LDP_SMSC911X_GPIO 152
#define DEBUG_BASE 0x08000000
#define LDP_ETHR_START DEBUG_BASE
-static struct resource ldp_smsc911x_resources[] = {
- [0] = {
- .start = LDP_ETHR_START,
- .end = LDP_ETHR_START + SZ_4K,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = 0,
- .end = 0,
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
- },
-};
-
-static struct smsc911x_platform_config ldp_smsc911x_config = {
- .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
- .irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
- .flags = SMSC911X_USE_32BIT,
- .phy_interface = PHY_INTERFACE_MODE_MII,
-};
-
-static struct platform_device ldp_smsc911x_device = {
- .name = "smsc911x",
- .id = -1,
- .num_resources = ARRAY_SIZE(ldp_smsc911x_resources),
- .resource = ldp_smsc911x_resources,
- .dev = {
- .platform_data = &ldp_smsc911x_config,
- },
-};
-
static uint32_t board_keymap[] = {
KEY(0, 0, KEY_1),
KEY(1, 0, KEY_2),
@@ -197,82 +168,16 @@ static struct platform_device ldp_gpio_keys_device = {
},
};
-static int ts_gpio;
-
-/**
- * @brief ads7846_dev_init : Requests & sets GPIO line for pen-irq
- *
- * @return - void. If request gpio fails then Flag KERN_ERR.
- */
-static void ads7846_dev_init(void)
-{
- if (gpio_request(ts_gpio, "ads7846 irq") < 0) {
- printk(KERN_ERR "can't get ads746 pen down GPIO\n");
- return;
- }
-
- gpio_direction_input(ts_gpio);
- gpio_set_debounce(ts_gpio, 310);
-}
-
-static int ads7846_get_pendown_state(void)
-{
- return !gpio_get_value(ts_gpio);
-}
-
-static struct ads7846_platform_data tsc2046_config __initdata = {
- .get_pendown_state = ads7846_get_pendown_state,
- .keep_vref_on = 1,
-};
-
-static struct omap2_mcspi_device_config tsc2046_mcspi_config = {
- .turbo_mode = 0,
- .single_channel = 1, /* 0: slave, 1: master */
-};
-
-static struct spi_board_info ldp_spi_board_info[] __initdata = {
- [0] = {
- /*
- * TSC2046 operates at a max freqency of 2MHz, so
- * operate slightly below at 1.5MHz
- */
- .modalias = "ads7846",
- .bus_num = 1,
- .chip_select = 0,
- .max_speed_hz = 1500000,
- .controller_data = &tsc2046_mcspi_config,
- .irq = 0,
- .platform_data = &tsc2046_config,
- },
+static struct omap_smsc911x_platform_data smsc911x_cfg = {
+ .cs = LDP_SMSC911X_CS,
+ .gpio_irq = LDP_SMSC911X_GPIO,
+ .gpio_reset = -EINVAL,
+ .flags = SMSC911X_USE_32BIT,
};
static inline void __init ldp_init_smsc911x(void)
{
- int eth_cs;
- unsigned long cs_mem_base;
- int eth_gpio = 0;
-
- eth_cs = LDP_SMSC911X_CS;
-
- if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
- printk(KERN_ERR "Failed to request GPMC mem for smsc911x\n");
- return;
- }
-
- ldp_smsc911x_resources[0].start = cs_mem_base + 0x0;
- ldp_smsc911x_resources[0].end = cs_mem_base + 0xff;
- udelay(100);
-
- eth_gpio = LDP_SMSC911X_GPIO;
-
- ldp_smsc911x_resources[1].start = OMAP_GPIO_IRQ(eth_gpio);
-
- if (gpio_request(eth_gpio, "smsc911x irq") < 0) {
- printk(KERN_ERR "Failed to request GPIO%d for smsc911x IRQ\n",
- eth_gpio);
- return;
- }
- gpio_direction_input(eth_gpio);
+ gpmc_smsc911x_init(&smsc911x_cfg);
}
static struct platform_device ldp_lcd_device = {
@@ -360,19 +265,9 @@ static struct twl4030_platform_data ldp_twldata = {
.keypad = &ldp_kp_twl4030_data,
};
-static struct i2c_board_info __initdata ldp_i2c_boardinfo[] = {
- {
- I2C_BOARD_INFO("twl4030", 0x48),
- .flags = I2C_CLIENT_WAKE,
- .irq = INT_34XX_SYS_NIRQ,
- .platform_data = &ldp_twldata,
- },
-};
-
static int __init omap_i2c_init(void)
{
- omap_register_i2c_bus(1, 2600, ldp_i2c_boardinfo,
- ARRAY_SIZE(ldp_i2c_boardinfo));
+ omap3_pmic_init("twl4030", &ldp_twldata);
omap_register_i2c_bus(2, 400, NULL, 0);
omap_register_i2c_bus(3, 400, NULL, 0);
return 0;
@@ -389,7 +284,6 @@ static struct omap2_hsmmc_info mmc[] __initdata = {
};
static struct platform_device *ldp_devices[] __initdata = {
- &ldp_smsc911x_device,
&ldp_lcd_device,
&ldp_gpio_keys_device,
};
@@ -400,12 +294,6 @@ static struct omap_board_mux board_mux[] __initdata = {
};
#endif
-static struct omap_musb_board_data musb_board_data = {
- .interface_type = MUSB_INTERFACE_ULPI,
- .mode = MUSB_OTG,
- .power = 100,
-};
-
static struct mtd_partition ldp_nand_partitions[] = {
/* All the partition sizes are listed in terms of NAND block size */
{
@@ -446,13 +334,9 @@ static void __init omap_ldp_init(void)
ldp_init_smsc911x();
omap_i2c_init();
platform_add_devices(ldp_devices, ARRAY_SIZE(ldp_devices));
- ts_gpio = 54;
- ldp_spi_board_info[0].irq = gpio_to_irq(ts_gpio);
- spi_register_board_info(ldp_spi_board_info,
- ARRAY_SIZE(ldp_spi_board_info));
- ads7846_dev_init();
+ omap_ads7846_init(1, 54, 310, NULL);
omap_serial_init();
- usb_musb_init(&musb_board_data);
+ usb_musb_init(NULL);
board_nand_init(ldp_nand_partitions,
ARRAY_SIZE(ldp_nand_partitions), ZOOM_NAND_CS, 0);
diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c
index e710cd9e079b..8d74318ed495 100644
--- a/arch/arm/mach-omap2/board-n8x0.c
+++ b/arch/arm/mach-omap2/board-n8x0.c
@@ -106,14 +106,13 @@ static void __init n8x0_usb_init(void)
static char announce[] __initdata = KERN_INFO "TUSB 6010\n";
/* PM companion chip power control pin */
- ret = gpio_request(TUSB6010_GPIO_ENABLE, "TUSB6010 enable");
+ ret = gpio_request_one(TUSB6010_GPIO_ENABLE, GPIOF_OUT_INIT_LOW,
+ "TUSB6010 enable");
if (ret != 0) {
printk(KERN_ERR "Could not get TUSB power GPIO%i\n",
TUSB6010_GPIO_ENABLE);
return;
}
- gpio_direction_output(TUSB6010_GPIO_ENABLE, 0);
-
tusb_set_power(0);
ret = tusb6010_setup_interface(&tusb_data, TUSB6010_REFCLK_19, 2,
@@ -494,8 +493,12 @@ static struct omap_mmc_platform_data mmc1_data = {
static struct omap_mmc_platform_data *mmc_data[OMAP24XX_NR_MMC];
-static void __init n8x0_mmc_init(void)
+static struct gpio n810_emmc_gpios[] __initdata = {
+ { N810_EMMC_VSD_GPIO, GPIOF_OUT_INIT_LOW, "MMC slot 2 Vddf" },
+ { N810_EMMC_VIO_GPIO, GPIOF_OUT_INIT_LOW, "MMC slot 2 Vdd" },
+};
+static void __init n8x0_mmc_init(void)
{
int err;
@@ -512,27 +515,18 @@ static void __init n8x0_mmc_init(void)
mmc1_data.slots[1].ban_openended = 1;
}
- err = gpio_request(N8X0_SLOT_SWITCH_GPIO, "MMC slot switch");
+ err = gpio_request_one(N8X0_SLOT_SWITCH_GPIO, GPIOF_OUT_INIT_LOW,
+ "MMC slot switch");
if (err)
return;
- gpio_direction_output(N8X0_SLOT_SWITCH_GPIO, 0);
-
if (machine_is_nokia_n810()) {
- err = gpio_request(N810_EMMC_VSD_GPIO, "MMC slot 2 Vddf");
- if (err) {
- gpio_free(N8X0_SLOT_SWITCH_GPIO);
- return;
- }
- gpio_direction_output(N810_EMMC_VSD_GPIO, 0);
-
- err = gpio_request(N810_EMMC_VIO_GPIO, "MMC slot 2 Vdd");
+ err = gpio_request_array(n810_emmc_gpios,
+ ARRAY_SIZE(n810_emmc_gpios));
if (err) {
gpio_free(N8X0_SLOT_SWITCH_GPIO);
- gpio_free(N810_EMMC_VSD_GPIO);
return;
}
- gpio_direction_output(N810_EMMC_VIO_GPIO, 0);
}
mmc_data[0] = &mmc1_data;
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 33007fd4a083..be71426359f2 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -41,8 +41,8 @@
#include <plat/board.h>
#include <plat/common.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
#include <plat/gpmc.h>
#include <plat/nand.h>
#include <plat/usb.h>
@@ -52,6 +52,7 @@
#include "hsmmc.h"
#include "timer-gp.h"
#include "pm.h"
+#include "common-board-devices.h"
#define NAND_BLOCK_SIZE SZ_128K
@@ -79,6 +80,12 @@ static u8 omap3_beagle_get_rev(void)
return omap3_beagle_version;
}
+static struct gpio omap3_beagle_rev_gpios[] __initdata = {
+ { 171, GPIOF_IN, "rev_id_0" },
+ { 172, GPIOF_IN, "rev_id_1" },
+ { 173, GPIOF_IN, "rev_id_2" },
+};
+
static void __init omap3_beagle_init_rev(void)
{
int ret;
@@ -88,21 +95,13 @@ static void __init omap3_beagle_init_rev(void)
omap_mux_init_gpio(172, OMAP_PIN_INPUT_PULLUP);
omap_mux_init_gpio(173, OMAP_PIN_INPUT_PULLUP);
- ret = gpio_request(171, "rev_id_0");
- if (ret < 0)
- goto fail0;
-
- ret = gpio_request(172, "rev_id_1");
- if (ret < 0)
- goto fail1;
-
- ret = gpio_request(173, "rev_id_2");
- if (ret < 0)
- goto fail2;
-
- gpio_direction_input(171);
- gpio_direction_input(172);
- gpio_direction_input(173);
+ ret = gpio_request_array(omap3_beagle_rev_gpios,
+ ARRAY_SIZE(omap3_beagle_rev_gpios));
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to get revision detection GPIO pins\n");
+ omap3_beagle_version = OMAP3BEAGLE_BOARD_UNKN;
+ return;
+ }
beagle_rev = gpio_get_value(171) | (gpio_get_value(172) << 1)
| (gpio_get_value(173) << 2);
@@ -128,18 +127,6 @@ static void __init omap3_beagle_init_rev(void)
printk(KERN_INFO "OMAP3 Beagle Rev: unknown %hd\n", beagle_rev);
omap3_beagle_version = OMAP3BEAGLE_BOARD_UNKN;
}
-
- return;
-
-fail2:
- gpio_free(172);
-fail1:
- gpio_free(171);
-fail0:
- printk(KERN_ERR "Unable to get revision detection GPIO pins\n");
- omap3_beagle_version = OMAP3BEAGLE_BOARD_UNKN;
-
- return;
}
static struct mtd_partition omap3beagle_nand_partitions[] = {
@@ -173,15 +160,6 @@ static struct mtd_partition omap3beagle_nand_partitions[] = {
},
};
-static struct omap_nand_platform_data omap3beagle_nand_data = {
- .options = NAND_BUSWIDTH_16,
- .parts = omap3beagle_nand_partitions,
- .nr_parts = ARRAY_SIZE(omap3beagle_nand_partitions),
- .dma_channel = -1, /* disable DMA in OMAP NAND driver */
- .nand_setup = NULL,
- .dev_ready = NULL,
-};
-
/* DSS */
static int beagle_enable_dvi(struct omap_dss_device *dssdev)
@@ -243,13 +221,10 @@ static void __init beagle_display_init(void)
{
int r;
- r = gpio_request(beagle_dvi_device.reset_gpio, "DVI reset");
- if (r < 0) {
+ r = gpio_request_one(beagle_dvi_device.reset_gpio, GPIOF_OUT_INIT_LOW,
+ "DVI reset");
+ if (r < 0)
printk(KERN_ERR "Unable to get DVI reset GPIO\n");
- return;
- }
-
- gpio_direction_output(beagle_dvi_device.reset_gpio, 0);
}
#include "sdram-micron-mt46h32m32lf-6.h"
@@ -276,7 +251,7 @@ static struct gpio_led gpio_leds[];
static int beagle_twl_gpio_setup(struct device *dev,
unsigned gpio, unsigned ngpio)
{
- int r;
+ int r, usb_pwr_level;
if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
mmc[0].gpio_wp = -EINVAL;
@@ -295,66 +270,46 @@ static int beagle_twl_gpio_setup(struct device *dev,
beagle_vmmc1_supply.dev = mmc[0].dev;
beagle_vsim_supply.dev = mmc[0].dev;
- /* REVISIT: need ehci-omap hooks for external VBUS
- * power switch and overcurrent detect
- */
- if (omap3_beagle_get_rev() != OMAP3BEAGLE_BOARD_XM) {
- r = gpio_request(gpio + 1, "EHCI_nOC");
- if (!r) {
- r = gpio_direction_input(gpio + 1);
- if (r)
- gpio_free(gpio + 1);
- }
- if (r)
- pr_err("%s: unable to configure EHCI_nOC\n", __func__);
- }
-
/*
* TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, XM active
* high / others active low)
- */
- gpio_request(gpio + TWL4030_GPIO_MAX, "nEN_USB_PWR");
- if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM)
- gpio_direction_output(gpio + TWL4030_GPIO_MAX, 1);
- else
- gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0);
-
- /* DVI reset GPIO is different between beagle revisions */
- if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM)
- beagle_dvi_device.reset_gpio = 129;
- else
- beagle_dvi_device.reset_gpio = 170;
-
- /* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
- gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
-
- /*
- * gpio + 1 on Xm controls the TFP410's enable line (active low)
- * gpio + 2 control varies depending on the board rev as follows:
- * P7/P8 revisions(prototype): Camera EN
- * A2+ revisions (production): LDO (supplies DVI, serial, led blocks)
+ * DVI reset GPIO is different between beagle revisions
*/
if (omap3_beagle_get_rev() == OMAP3BEAGLE_BOARD_XM) {
- r = gpio_request(gpio + 1, "nDVI_PWR_EN");
- if (!r) {
- r = gpio_direction_output(gpio + 1, 0);
- if (r)
- gpio_free(gpio + 1);
- }
+ usb_pwr_level = GPIOF_OUT_INIT_HIGH;
+ beagle_dvi_device.reset_gpio = 129;
+ /*
+ * gpio + 1 on Xm controls the TFP410's enable line (active low)
+ * gpio + 2 control varies depending on the board rev as below:
+ * P7/P8 revisions(prototype): Camera EN
+ * A2+ revisions (production): LDO (DVI, serial, led blocks)
+ */
+ r = gpio_request_one(gpio + 1, GPIOF_OUT_INIT_LOW,
+ "nDVI_PWR_EN");
if (r)
pr_err("%s: unable to configure nDVI_PWR_EN\n",
__func__);
- r = gpio_request(gpio + 2, "DVI_LDO_EN");
- if (!r) {
- r = gpio_direction_output(gpio + 2, 1);
- if (r)
- gpio_free(gpio + 2);
- }
+ r = gpio_request_one(gpio + 2, GPIOF_OUT_INIT_HIGH,
+ "DVI_LDO_EN");
if (r)
pr_err("%s: unable to configure DVI_LDO_EN\n",
__func__);
+ } else {
+ usb_pwr_level = GPIOF_OUT_INIT_LOW;
+ beagle_dvi_device.reset_gpio = 170;
+ /*
+ * REVISIT: need ehci-omap hooks for external VBUS
+ * power switch and overcurrent detect
+ */
+ if (gpio_request_one(gpio + 1, GPIOF_IN, "EHCI_nOC"))
+ pr_err("%s: unable to configure EHCI_nOC\n", __func__);
}
+ gpio_request_one(gpio + TWL4030_GPIO_MAX, usb_pwr_level, "nEN_USB_PWR");
+
+ /* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
+ gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
+
return 0;
}
@@ -453,15 +408,6 @@ static struct twl4030_platform_data beagle_twldata = {
.vpll2 = &beagle_vpll2,
};
-static struct i2c_board_info __initdata beagle_i2c_boardinfo[] = {
- {
- I2C_BOARD_INFO("twl4030", 0x48),
- .flags = I2C_CLIENT_WAKE,
- .irq = INT_34XX_SYS_NIRQ,
- .platform_data = &beagle_twldata,
- },
-};
-
static struct i2c_board_info __initdata beagle_i2c_eeprom[] = {
{
I2C_BOARD_INFO("eeprom", 0x50),
@@ -470,8 +416,7 @@ static struct i2c_board_info __initdata beagle_i2c_eeprom[] = {
static int __init omap3_beagle_i2c_init(void)
{
- omap_register_i2c_bus(1, 2600, beagle_i2c_boardinfo,
- ARRAY_SIZE(beagle_i2c_boardinfo));
+ omap3_pmic_init("twl4030", &beagle_twldata);
/* Bus 3 is attached to the DVI port where devices like the pico DLP
* projector don't work reliably with 400kHz */
omap_register_i2c_bus(3, 100, beagle_i2c_eeprom, ARRAY_SIZE(beagle_i2c_eeprom));
@@ -551,39 +496,6 @@ static struct platform_device *omap3_beagle_devices[] __initdata = {
&keys_gpio,
};
-static void __init omap3beagle_flash_init(void)
-{
- u8 cs = 0;
- u8 nandcs = GPMC_CS_NUM + 1;
-
- /* find out the chip-select on which NAND exists */
- while (cs < GPMC_CS_NUM) {
- u32 ret = 0;
- ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
-
- if ((ret & 0xC00) == 0x800) {
- printk(KERN_INFO "Found NAND on CS%d\n", cs);
- if (nandcs > GPMC_CS_NUM)
- nandcs = cs;
- }
- cs++;
- }
-
- if (nandcs > GPMC_CS_NUM) {
- printk(KERN_INFO "NAND: Unable to find configuration "
- "in GPMC\n ");
- return;
- }
-
- if (nandcs < GPMC_CS_NUM) {
- omap3beagle_nand_data.cs = nandcs;
-
- printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
- if (gpmc_nand_init(&omap3beagle_nand_data) < 0)
- printk(KERN_ERR "Unable to register NAND device\n");
- }
-}
-
static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
@@ -602,12 +514,6 @@ static struct omap_board_mux board_mux[] __initdata = {
};
#endif
-static struct omap_musb_board_data musb_board_data = {
- .interface_type = MUSB_INTERFACE_ULPI,
- .mode = MUSB_OTG,
- .power = 100,
-};
-
static void __init beagle_opp_init(void)
{
int r = 0;
@@ -665,13 +571,13 @@ static void __init omap3_beagle_init(void)
omap_serial_init();
omap_mux_init_gpio(170, OMAP_PIN_INPUT);
- gpio_request(170, "DVI_nPD");
/* REVISIT leave DVI powered down until it's needed ... */
- gpio_direction_output(170, true);
+ gpio_request_one(170, GPIOF_OUT_INIT_HIGH, "DVI_nPD");
- usb_musb_init(&musb_board_data);
+ usb_musb_init(NULL);
usbhs_init(&usbhs_bdata);
- omap3beagle_flash_init();
+ omap_nand_flash_init(NAND_BUSWIDTH_16, omap3beagle_nand_partitions,
+ ARRAY_SIZE(omap3beagle_nand_partitions));
/* Ensure SDRC pins are mux'd for self-refresh */
omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index 5a1a916e5cc8..b4d43464a303 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -44,12 +44,13 @@
#include <plat/usb.h>
#include <plat/common.h>
#include <plat/mcspi.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
#include "mux.h"
#include "sdram-micron-mt46h32m32lf-6.h"
#include "hsmmc.h"
+#include "common-board-devices.h"
#define OMAP3_EVM_TS_GPIO 175
#define OMAP3_EVM_EHCI_VBUS 22
@@ -101,49 +102,20 @@ static void __init omap3_evm_get_revision(void)
}
#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
-static struct resource omap3evm_smsc911x_resources[] = {
- [0] = {
- .start = OMAP3EVM_ETHR_START,
- .end = (OMAP3EVM_ETHR_START + OMAP3EVM_ETHR_SIZE - 1),
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = OMAP_GPIO_IRQ(OMAP3EVM_ETHR_GPIO_IRQ),
- .end = OMAP_GPIO_IRQ(OMAP3EVM_ETHR_GPIO_IRQ),
- .flags = (IORESOURCE_IRQ | IRQF_TRIGGER_LOW),
- },
-};
+#include <plat/gpmc-smsc911x.h>
-static struct smsc911x_platform_config smsc911x_config = {
- .phy_interface = PHY_INTERFACE_MODE_MII,
- .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
- .irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
- .flags = (SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS),
-};
-
-static struct platform_device omap3evm_smsc911x_device = {
- .name = "smsc911x",
- .id = -1,
- .num_resources = ARRAY_SIZE(omap3evm_smsc911x_resources),
- .resource = &omap3evm_smsc911x_resources[0],
- .dev = {
- .platform_data = &smsc911x_config,
- },
+static struct omap_smsc911x_platform_data smsc911x_cfg = {
+ .cs = OMAP3EVM_SMSC911X_CS,
+ .gpio_irq = OMAP3EVM_ETHR_GPIO_IRQ,
+ .gpio_reset = -EINVAL,
+ .flags = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS,
};
static inline void __init omap3evm_init_smsc911x(void)
{
- int eth_cs, eth_rst;
struct clk *l3ck;
unsigned int rate;
- if (get_omap3_evm_rev() == OMAP3EVM_BOARD_GEN_1)
- eth_rst = OMAP3EVM_GEN1_ETHR_GPIO_RST;
- else
- eth_rst = OMAP3EVM_GEN2_ETHR_GPIO_RST;
-
- eth_cs = OMAP3EVM_SMSC911X_CS;
-
l3ck = clk_get(NULL, "l3_ck");
if (IS_ERR(l3ck))
rate = 100000000;
@@ -152,33 +124,13 @@ static inline void __init omap3evm_init_smsc911x(void)
/* Configure ethernet controller reset gpio */
if (cpu_is_omap3430()) {
- if (gpio_request(eth_rst, "SMSC911x gpio") < 0) {
- pr_err(KERN_ERR "Failed to request %d for smsc911x\n",
- eth_rst);
- return;
- }
-
- if (gpio_direction_output(eth_rst, 1) < 0) {
- pr_err(KERN_ERR "Failed to set direction of %d for" \
- " smsc911x\n", eth_rst);
- return;
- }
- /* reset pulse to ethernet controller*/
- usleep_range(150, 220);
- gpio_set_value(eth_rst, 0);
- usleep_range(150, 220);
- gpio_set_value(eth_rst, 1);
- usleep_range(1, 2);
- }
-
- if (gpio_request(OMAP3EVM_ETHR_GPIO_IRQ, "SMSC911x irq") < 0) {
- printk(KERN_ERR "Failed to request GPIO%d for smsc911x IRQ\n",
- OMAP3EVM_ETHR_GPIO_IRQ);
- return;
+ if (get_omap3_evm_rev() == OMAP3EVM_BOARD_GEN_1)
+ smsc911x_cfg.gpio_reset = OMAP3EVM_GEN1_ETHR_GPIO_RST;
+ else
+ smsc911x_cfg.gpio_reset = OMAP3EVM_GEN2_ETHR_GPIO_RST;
}
- gpio_direction_input(OMAP3EVM_ETHR_GPIO_IRQ);
- platform_device_register(&omap3evm_smsc911x_device);
+ gpmc_smsc911x_init(&smsc911x_cfg);
}
#else
@@ -197,6 +149,15 @@ static inline void __init omap3evm_init_smsc911x(void) { return; }
#define OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO 210
#define OMAP3EVM_DVI_PANEL_EN_GPIO 199
+static struct gpio omap3_evm_dss_gpios[] __initdata = {
+ { OMAP3EVM_LCD_PANEL_RESB, GPIOF_OUT_INIT_HIGH, "lcd_panel_resb" },
+ { OMAP3EVM_LCD_PANEL_INI, GPIOF_OUT_INIT_HIGH, "lcd_panel_ini" },
+ { OMAP3EVM_LCD_PANEL_QVGA, GPIOF_OUT_INIT_LOW, "lcd_panel_qvga" },
+ { OMAP3EVM_LCD_PANEL_LR, GPIOF_OUT_INIT_HIGH, "lcd_panel_lr" },
+ { OMAP3EVM_LCD_PANEL_UD, GPIOF_OUT_INIT_HIGH, "lcd_panel_ud" },
+ { OMAP3EVM_LCD_PANEL_ENVDD, GPIOF_OUT_INIT_LOW, "lcd_panel_envdd" },
+};
+
static int lcd_enabled;
static int dvi_enabled;
@@ -204,61 +165,10 @@ static void __init omap3_evm_display_init(void)
{
int r;
- r = gpio_request(OMAP3EVM_LCD_PANEL_RESB, "lcd_panel_resb");
- if (r) {
- printk(KERN_ERR "failed to get lcd_panel_resb\n");
- return;
- }
- gpio_direction_output(OMAP3EVM_LCD_PANEL_RESB, 1);
-
- r = gpio_request(OMAP3EVM_LCD_PANEL_INI, "lcd_panel_ini");
- if (r) {
- printk(KERN_ERR "failed to get lcd_panel_ini\n");
- goto err_1;
- }
- gpio_direction_output(OMAP3EVM_LCD_PANEL_INI, 1);
-
- r = gpio_request(OMAP3EVM_LCD_PANEL_QVGA, "lcd_panel_qvga");
- if (r) {
- printk(KERN_ERR "failed to get lcd_panel_qvga\n");
- goto err_2;
- }
- gpio_direction_output(OMAP3EVM_LCD_PANEL_QVGA, 0);
-
- r = gpio_request(OMAP3EVM_LCD_PANEL_LR, "lcd_panel_lr");
- if (r) {
- printk(KERN_ERR "failed to get lcd_panel_lr\n");
- goto err_3;
- }
- gpio_direction_output(OMAP3EVM_LCD_PANEL_LR, 1);
-
- r = gpio_request(OMAP3EVM_LCD_PANEL_UD, "lcd_panel_ud");
- if (r) {
- printk(KERN_ERR "failed to get lcd_panel_ud\n");
- goto err_4;
- }
- gpio_direction_output(OMAP3EVM_LCD_PANEL_UD, 1);
-
- r = gpio_request(OMAP3EVM_LCD_PANEL_ENVDD, "lcd_panel_envdd");
- if (r) {
- printk(KERN_ERR "failed to get lcd_panel_envdd\n");
- goto err_5;
- }
- gpio_direction_output(OMAP3EVM_LCD_PANEL_ENVDD, 0);
-
- return;
-
-err_5:
- gpio_free(OMAP3EVM_LCD_PANEL_UD);
-err_4:
- gpio_free(OMAP3EVM_LCD_PANEL_LR);
-err_3:
- gpio_free(OMAP3EVM_LCD_PANEL_QVGA);
-err_2:
- gpio_free(OMAP3EVM_LCD_PANEL_INI);
-err_1:
- gpio_free(OMAP3EVM_LCD_PANEL_RESB);
-
+ r = gpio_request_array(omap3_evm_dss_gpios,
+ ARRAY_SIZE(omap3_evm_dss_gpios));
+ if (r)
+ printk(KERN_ERR "failed to get lcd_panel_* gpios\n");
}
static int omap3_evm_enable_lcd(struct omap_dss_device *dssdev)
@@ -448,7 +358,7 @@ static struct platform_device leds_gpio = {
static int omap3evm_twl_gpio_setup(struct device *dev,
unsigned gpio, unsigned ngpio)
{
- int r;
+ int r, lcd_bl_en;
/* gpio + 0 is "mmc0_cd" (input/IRQ) */
omap_mux_init_gpio(63, OMAP_PIN_INPUT);
@@ -465,16 +375,14 @@ static int omap3evm_twl_gpio_setup(struct device *dev,
*/
/* TWL4030_GPIO_MAX + 0 == ledA, LCD Backlight control */
- r = gpio_request(gpio + TWL4030_GPIO_MAX, "EN_LCD_BKL");
- if (!r)
- r = gpio_direction_output(gpio + TWL4030_GPIO_MAX,
- (get_omap3_evm_rev() >= OMAP3EVM_BOARD_GEN_2) ? 1 : 0);
+ lcd_bl_en = get_omap3_evm_rev() >= OMAP3EVM_BOARD_GEN_2 ?
+ GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
+ r = gpio_request_one(gpio + TWL4030_GPIO_MAX, lcd_bl_en, "EN_LCD_BKL");
if (r)
printk(KERN_ERR "failed to get/set lcd_bkl gpio\n");
/* gpio + 7 == DVI Enable */
- gpio_request(gpio + 7, "EN_DVI");
- gpio_direction_output(gpio + 7, 0);
+ gpio_request_one(gpio + 7, GPIOF_OUT_INIT_LOW, "EN_DVI");
/* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */
gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
@@ -652,78 +560,18 @@ static struct twl4030_platform_data omap3evm_twldata = {
.vdac = &omap3_evm_vdac,
.vpll2 = &omap3_evm_vpll2,
.vio = &omap3evm_vio,
-};
-
-static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = {
- {
- I2C_BOARD_INFO("twl4030", 0x48),
- .flags = I2C_CLIENT_WAKE,
- .irq = INT_34XX_SYS_NIRQ,
- .platform_data = &omap3evm_twldata,
- },
+ .vmmc1 = &omap3evm_vmmc1,
+ .vsim = &omap3evm_vsim,
};
static int __init omap3_evm_i2c_init(void)
{
- /*
- * REVISIT: These entries can be set in omap3evm_twl_data
- * after a merge with MFD tree
- */
- omap3evm_twldata.vmmc1 = &omap3evm_vmmc1;
- omap3evm_twldata.vsim = &omap3evm_vsim;
-
- omap_register_i2c_bus(1, 2600, omap3evm_i2c_boardinfo,
- ARRAY_SIZE(omap3evm_i2c_boardinfo));
+ omap3_pmic_init("twl4030", &omap3evm_twldata);
omap_register_i2c_bus(2, 400, NULL, 0);
omap_register_i2c_bus(3, 400, NULL, 0);
return 0;
}
-static void ads7846_dev_init(void)
-{
- if (gpio_request(OMAP3_EVM_TS_GPIO, "ADS7846 pendown") < 0)
- printk(KERN_ERR "can't get ads7846 pen down GPIO\n");
-
- gpio_direction_input(OMAP3_EVM_TS_GPIO);
- gpio_set_debounce(OMAP3_EVM_TS_GPIO, 310);
-}
-
-static int ads7846_get_pendown_state(void)
-{
- return !gpio_get_value(OMAP3_EVM_TS_GPIO);
-}
-
-static struct ads7846_platform_data ads7846_config = {
- .x_max = 0x0fff,
- .y_max = 0x0fff,
- .x_plate_ohms = 180,
- .pressure_max = 255,
- .debounce_max = 10,
- .debounce_tol = 3,
- .debounce_rep = 1,
- .get_pendown_state = ads7846_get_pendown_state,
- .keep_vref_on = 1,
- .settle_delay_usecs = 150,
- .wakeup = true,
-};
-
-static struct omap2_mcspi_device_config ads7846_mcspi_config = {
- .turbo_mode = 0,
- .single_channel = 1, /* 0: slave, 1: master */
-};
-
-static struct spi_board_info omap3evm_spi_board_info[] = {
- [0] = {
- .modalias = "ads7846",
- .bus_num = 1,
- .chip_select = 0,
- .max_speed_hz = 1500000,
- .controller_data = &ads7846_mcspi_config,
- .irq = OMAP_GPIO_IRQ(OMAP3_EVM_TS_GPIO),
- .platform_data = &ads7846_config,
- },
-};
-
static struct omap_board_config_kernel omap3_evm_config[] __initdata = {
};
@@ -825,6 +673,11 @@ static struct omap_musb_board_data musb_board_data = {
.power = 100,
};
+static struct gpio omap3_evm_ehci_gpios[] __initdata = {
+ { OMAP3_EVM_EHCI_VBUS, GPIOF_OUT_INIT_HIGH, "enable EHCI VBUS" },
+ { OMAP3_EVM_EHCI_SELECT, GPIOF_OUT_INIT_LOW, "select EHCI port" },
+};
+
static void __init omap3_evm_init(void)
{
omap3_evm_get_revision();
@@ -841,9 +694,6 @@ static void __init omap3_evm_init(void)
omap_display_init(&omap3_evm_dss_data);
- spi_register_board_info(omap3evm_spi_board_info,
- ARRAY_SIZE(omap3evm_spi_board_info));
-
omap_serial_init();
/* OMAP3EVM uses ISP1504 phy and so register nop transceiver */
@@ -851,16 +701,12 @@ static void __init omap3_evm_init(void)
if (get_omap3_evm_rev() >= OMAP3EVM_BOARD_GEN_2) {
/* enable EHCI VBUS using GPIO22 */
- omap_mux_init_gpio(22, OMAP_PIN_INPUT_PULLUP);
- gpio_request(OMAP3_EVM_EHCI_VBUS, "enable EHCI VBUS");
- gpio_direction_output(OMAP3_EVM_EHCI_VBUS, 0);
- gpio_set_value(OMAP3_EVM_EHCI_VBUS, 1);
-
+ omap_mux_init_gpio(OMAP3_EVM_EHCI_VBUS, OMAP_PIN_INPUT_PULLUP);
/* Select EHCI port on main board */
- omap_mux_init_gpio(61, OMAP_PIN_INPUT_PULLUP);
- gpio_request(OMAP3_EVM_EHCI_SELECT, "select EHCI port");
- gpio_direction_output(OMAP3_EVM_EHCI_SELECT, 0);
- gpio_set_value(OMAP3_EVM_EHCI_SELECT, 0);
+ omap_mux_init_gpio(OMAP3_EVM_EHCI_SELECT,
+ OMAP_PIN_INPUT_PULLUP);
+ gpio_request_array(omap3_evm_ehci_gpios,
+ ARRAY_SIZE(omap3_evm_ehci_gpios));
/* setup EHCI phy reset config */
omap_mux_init_gpio(21, OMAP_PIN_INPUT_PULLUP);
@@ -876,7 +722,7 @@ static void __init omap3_evm_init(void)
}
usb_musb_init(&musb_board_data);
usbhs_init(&usbhs_bdata);
- ads7846_dev_init();
+ omap_ads7846_init(1, OMAP3_EVM_TS_GPIO, 310, NULL);
omap3evm_init_smsc911x();
omap3_evm_display_init();
diff --git a/arch/arm/mach-omap2/board-omap3logic.c b/arch/arm/mach-omap2/board-omap3logic.c
index b726943d7c93..60d9be49dbab 100644
--- a/arch/arm/mach-omap2/board-omap3logic.c
+++ b/arch/arm/mach-omap2/board-omap3logic.c
@@ -37,6 +37,7 @@
#include "hsmmc.h"
#include "timer-gp.h"
#include "control.h"
+#include "common-board-devices.h"
#include <plat/mux.h>
#include <plat/board.h>
@@ -93,19 +94,9 @@ static struct twl4030_platform_data omap3logic_twldata = {
.vmmc1 = &omap3logic_vmmc1,
};
-static struct i2c_board_info __initdata omap3logic_i2c_boardinfo[] = {
- {
- I2C_BOARD_INFO("twl4030", 0x48),
- .flags = I2C_CLIENT_WAKE,
- .irq = INT_34XX_SYS_NIRQ,
- .platform_data = &omap3logic_twldata,
- },
-};
-
static int __init omap3logic_i2c_init(void)
{
- omap_register_i2c_bus(1, 2600, omap3logic_i2c_boardinfo,
- ARRAY_SIZE(omap3logic_i2c_boardinfo));
+ omap3_pmic_init("twl4030", &omap3logic_twldata);
return 0;
}
@@ -147,7 +138,6 @@ static struct omap_smsc911x_platform_data __initdata board_smsc911x_data = {
.cs = OMAP3LOGIC_SMSC911X_CS,
.gpio_irq = -EINVAL,
.gpio_reset = -EINVAL,
- .flags = IORESOURCE_IRQ_LOWLEVEL,
};
/* TODO/FIXME (comment by Peter Barada, LogicPD):
diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c
index 07dba888f450..1d10736c6d3c 100644
--- a/arch/arm/mach-omap2/board-omap3pandora.c
+++ b/arch/arm/mach-omap2/board-omap3pandora.c
@@ -22,7 +22,6 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
-#include <linux/spi/ads7846.h>
#include <linux/regulator/machine.h>
#include <linux/i2c/twl.h>
#include <linux/wl12xx.h>
@@ -46,12 +45,13 @@
#include <mach/hardware.h>
#include <plat/mcspi.h>
#include <plat/usb.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
#include <plat/nand.h>
#include "mux.h"
#include "sdram-micron-mt46h32m32lf-6.h"
#include "hsmmc.h"
+#include "common-board-devices.h"
#define PANDORA_WIFI_IRQ_GPIO 21
#define PANDORA_WIFI_NRESET_GPIO 23
@@ -305,24 +305,13 @@ static int omap3pandora_twl_gpio_setup(struct device *dev,
/* gpio + 13 drives 32kHz buffer for wifi module */
gpio_32khz = gpio + 13;
- ret = gpio_request(gpio_32khz, "wifi 32kHz");
+ ret = gpio_request_one(gpio_32khz, GPIOF_OUT_INIT_HIGH, "wifi 32kHz");
if (ret < 0) {
pr_err("Cannot get GPIO line %d, ret=%d\n", gpio_32khz, ret);
- goto fail;
- }
-
- ret = gpio_direction_output(gpio_32khz, 1);
- if (ret < 0) {
- pr_err("Cannot set GPIO line %d, ret=%d\n", gpio_32khz, ret);
- goto fail_direction;
+ return -ENODEV;
}
return 0;
-
-fail_direction:
- gpio_free(gpio_32khz);
-fail:
- return -ENODEV;
}
static struct twl4030_gpio_platform_data omap3pandora_gpio_data = {
@@ -544,15 +533,6 @@ static struct twl4030_platform_data omap3pandora_twldata = {
.bci = &pandora_bci_data,
};
-static struct i2c_board_info __initdata omap3pandora_i2c_boardinfo[] = {
- {
- I2C_BOARD_INFO("tps65950", 0x48),
- .flags = I2C_CLIENT_WAKE,
- .irq = INT_34XX_SYS_NIRQ,
- .platform_data = &omap3pandora_twldata,
- },
-};
-
static struct i2c_board_info __initdata omap3pandora_i2c3_boardinfo[] = {
{
I2C_BOARD_INFO("bq27500", 0x55),
@@ -562,61 +542,15 @@ static struct i2c_board_info __initdata omap3pandora_i2c3_boardinfo[] = {
static int __init omap3pandora_i2c_init(void)
{
- omap_register_i2c_bus(1, 2600, omap3pandora_i2c_boardinfo,
- ARRAY_SIZE(omap3pandora_i2c_boardinfo));
+ omap3_pmic_init("tps65950", &omap3pandora_twldata);
/* i2c2 pins are not connected */
omap_register_i2c_bus(3, 100, omap3pandora_i2c3_boardinfo,
ARRAY_SIZE(omap3pandora_i2c3_boardinfo));
return 0;
}
-static void __init omap3pandora_ads7846_init(void)
-{
- int gpio = OMAP3_PANDORA_TS_GPIO;
- int ret;
-
- ret = gpio_request(gpio, "ads7846_pen_down");
- if (ret < 0) {
- printk(KERN_ERR "Failed to request GPIO %d for "
- "ads7846 pen down IRQ\n", gpio);
- return;
- }
-
- gpio_direction_input(gpio);
-}
-
-static int ads7846_get_pendown_state(void)
-{
- return !gpio_get_value(OMAP3_PANDORA_TS_GPIO);
-}
-
-static struct ads7846_platform_data ads7846_config = {
- .x_max = 0x0fff,
- .y_max = 0x0fff,
- .x_plate_ohms = 180,
- .pressure_max = 255,
- .debounce_max = 10,
- .debounce_tol = 3,
- .debounce_rep = 1,
- .get_pendown_state = ads7846_get_pendown_state,
- .keep_vref_on = 1,
-};
-
-static struct omap2_mcspi_device_config ads7846_mcspi_config = {
- .turbo_mode = 0,
- .single_channel = 1, /* 0: slave, 1: master */
-};
-
static struct spi_board_info omap3pandora_spi_board_info[] __initdata = {
{
- .modalias = "ads7846",
- .bus_num = 1,
- .chip_select = 0,
- .max_speed_hz = 1500000,
- .controller_data = &ads7846_mcspi_config,
- .irq = OMAP_GPIO_IRQ(OMAP3_PANDORA_TS_GPIO),
- .platform_data = &ads7846_config,
- }, {
.modalias = "tpo_td043mtea1_panel_spi",
.bus_num = 1,
.chip_select = 1,
@@ -639,14 +573,10 @@ static void __init pandora_wl1251_init(void)
memset(&pandora_wl1251_pdata, 0, sizeof(pandora_wl1251_pdata));
- ret = gpio_request(PANDORA_WIFI_IRQ_GPIO, "wl1251 irq");
+ ret = gpio_request_one(PANDORA_WIFI_IRQ_GPIO, GPIOF_IN, "wl1251 irq");
if (ret < 0)
goto fail;
- ret = gpio_direction_input(PANDORA_WIFI_IRQ_GPIO);
- if (ret < 0)
- goto fail_irq;
-
pandora_wl1251_pdata.irq = gpio_to_irq(PANDORA_WIFI_IRQ_GPIO);
if (pandora_wl1251_pdata.irq < 0)
goto fail_irq;
@@ -688,12 +618,6 @@ static struct omap_board_mux board_mux[] __initdata = {
};
#endif
-static struct omap_musb_board_data musb_board_data = {
- .interface_type = MUSB_INTERFACE_ULPI,
- .mode = MUSB_OTG,
- .power = 100,
-};
-
static void __init omap3pandora_init(void)
{
omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
@@ -705,9 +629,9 @@ static void __init omap3pandora_init(void)
omap_serial_init();
spi_register_board_info(omap3pandora_spi_board_info,
ARRAY_SIZE(omap3pandora_spi_board_info));
- omap3pandora_ads7846_init();
+ omap_ads7846_init(1, OMAP3_PANDORA_TS_GPIO, 0, NULL);
usbhs_init(&usbhs_bdata);
- usb_musb_init(&musb_board_data);
+ usb_musb_init(NULL);
gpmc_nand_init(&pandora_nand_data);
/* Ensure SDRC pins are mux'd for self-refresh */
diff --git a/arch/arm/mach-omap2/board-omap3stalker.c b/arch/arm/mach-omap2/board-omap3stalker.c
index a6e0b9161c99..0c108a212ea2 100644
--- a/arch/arm/mach-omap2/board-omap3stalker.c
+++ b/arch/arm/mach-omap2/board-omap3stalker.c
@@ -39,13 +39,12 @@
#include <plat/gpmc.h>
#include <plat/nand.h>
#include <plat/usb.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
#include <plat/mcspi.h>
#include <linux/input/matrix_keypad.h>
#include <linux/spi/spi.h>
-#include <linux/spi/ads7846.h>
#include <linux/interrupt.h>
#include <linux/smsc911x.h>
#include <linux/i2c/at24.h>
@@ -54,52 +53,28 @@
#include "mux.h"
#include "hsmmc.h"
#include "timer-gp.h"
+#include "common-board-devices.h"
#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
+#include <plat/gpmc-smsc911x.h>
+
#define OMAP3STALKER_ETHR_START 0x2c000000
#define OMAP3STALKER_ETHR_SIZE 1024
#define OMAP3STALKER_ETHR_GPIO_IRQ 19
#define OMAP3STALKER_SMC911X_CS 5
-static struct resource omap3stalker_smsc911x_resources[] = {
- [0] = {
- .start = OMAP3STALKER_ETHR_START,
- .end =
- (OMAP3STALKER_ETHR_START + OMAP3STALKER_ETHR_SIZE - 1),
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = OMAP_GPIO_IRQ(OMAP3STALKER_ETHR_GPIO_IRQ),
- .end = OMAP_GPIO_IRQ(OMAP3STALKER_ETHR_GPIO_IRQ),
- .flags = (IORESOURCE_IRQ | IRQF_TRIGGER_LOW),
- },
-};
-
-static struct smsc911x_platform_config smsc911x_config = {
- .phy_interface = PHY_INTERFACE_MODE_MII,
- .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
- .irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+static struct omap_smsc911x_platform_data smsc911x_cfg = {
+ .cs = OMAP3STALKER_SMC911X_CS,
+ .gpio_irq = OMAP3STALKER_ETHR_GPIO_IRQ,
+ .gpio_reset = -EINVAL,
.flags = (SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS),
};
-static struct platform_device omap3stalker_smsc911x_device = {
- .name = "smsc911x",
- .id = -1,
- .num_resources = ARRAY_SIZE(omap3stalker_smsc911x_resources),
- .resource = &omap3stalker_smsc911x_resources[0],
- .dev = {
- .platform_data = &smsc911x_config,
- },
-};
-
static inline void __init omap3stalker_init_eth(void)
{
- int eth_cs;
struct clk *l3ck;
unsigned int rate;
- eth_cs = OMAP3STALKER_SMC911X_CS;
-
l3ck = clk_get(NULL, "l3_ck");
if (IS_ERR(l3ck))
rate = 100000000;
@@ -107,16 +82,7 @@ static inline void __init omap3stalker_init_eth(void)
rate = clk_get_rate(l3ck);
omap_mux_init_gpio(19, OMAP_PIN_INPUT_PULLUP);
- if (gpio_request(OMAP3STALKER_ETHR_GPIO_IRQ, "SMC911x irq") < 0) {
- printk(KERN_ERR
- "Failed to request GPIO%d for smc911x IRQ\n",
- OMAP3STALKER_ETHR_GPIO_IRQ);
- return;
- }
-
- gpio_direction_input(OMAP3STALKER_ETHR_GPIO_IRQ);
-
- platform_device_register(&omap3stalker_smsc911x_device);
+ gpmc_smsc911x_init(&smsc911x_cfg);
}
#else
@@ -365,12 +331,11 @@ omap3stalker_twl_gpio_setup(struct device *dev,
*/
/* TWL4030_GPIO_MAX + 0 == ledA, LCD Backlight control */
- gpio_request(gpio + TWL4030_GPIO_MAX, "EN_LCD_BKL");
- gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0);
+ gpio_request_one(gpio + TWL4030_GPIO_MAX, GPIOF_OUT_INIT_LOW,
+ "EN_LCD_BKL");
/* gpio + 7 == DVI Enable */
- gpio_request(gpio + 7, "EN_DVI");
- gpio_direction_output(gpio + 7, 0);
+ gpio_request_one(gpio + 7, GPIOF_OUT_INIT_LOW, "EN_DVI");
/* TWL4030_GPIO_MAX + 1 == ledB (out, mmc0) */
gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
@@ -489,15 +454,8 @@ static struct twl4030_platform_data omap3stalker_twldata = {
.codec = &omap3stalker_codec_data,
.vdac = &omap3_stalker_vdac,
.vpll2 = &omap3_stalker_vpll2,
-};
-
-static struct i2c_board_info __initdata omap3stalker_i2c_boardinfo[] = {
- {
- I2C_BOARD_INFO("twl4030", 0x48),
- .flags = I2C_CLIENT_WAKE,
- .irq = INT_34XX_SYS_NIRQ,
- .platform_data = &omap3stalker_twldata,
- },
+ .vmmc1 = &omap3stalker_vmmc1,
+ .vsim = &omap3stalker_vsim,
};
static struct at24_platform_data fram_info = {
@@ -516,15 +474,7 @@ static struct i2c_board_info __initdata omap3stalker_i2c_boardinfo3[] = {
static int __init omap3_stalker_i2c_init(void)
{
- /*
- * REVISIT: These entries can be set in omap3evm_twl_data
- * after a merge with MFD tree
- */
- omap3stalker_twldata.vmmc1 = &omap3stalker_vmmc1;
- omap3stalker_twldata.vsim = &omap3stalker_vsim;
-
- omap_register_i2c_bus(1, 2600, omap3stalker_i2c_boardinfo,
- ARRAY_SIZE(omap3stalker_i2c_boardinfo));
+ omap3_pmic_init("twl4030", &omap3stalker_twldata);
omap_register_i2c_bus(2, 400, NULL, 0);
omap_register_i2c_bus(3, 400, omap3stalker_i2c_boardinfo3,
ARRAY_SIZE(omap3stalker_i2c_boardinfo3));
@@ -532,49 +482,6 @@ static int __init omap3_stalker_i2c_init(void)
}
#define OMAP3_STALKER_TS_GPIO 175
-static void ads7846_dev_init(void)
-{
- if (gpio_request(OMAP3_STALKER_TS_GPIO, "ADS7846 pendown") < 0)
- printk(KERN_ERR "can't get ads7846 pen down GPIO\n");
-
- gpio_direction_input(OMAP3_STALKER_TS_GPIO);
- gpio_set_debounce(OMAP3_STALKER_TS_GPIO, 310);
-}
-
-static int ads7846_get_pendown_state(void)
-{
- return !gpio_get_value(OMAP3_STALKER_TS_GPIO);
-}
-
-static struct ads7846_platform_data ads7846_config = {
- .x_max = 0x0fff,
- .y_max = 0x0fff,
- .x_plate_ohms = 180,
- .pressure_max = 255,
- .debounce_max = 10,
- .debounce_tol = 3,
- .debounce_rep = 1,
- .get_pendown_state = ads7846_get_pendown_state,
- .keep_vref_on = 1,
- .settle_delay_usecs = 150,
-};
-
-static struct omap2_mcspi_device_config ads7846_mcspi_config = {
- .turbo_mode = 0,
- .single_channel = 1, /* 0: slave, 1: master */
-};
-
-static struct spi_board_info omap3stalker_spi_board_info[] = {
- [0] = {
- .modalias = "ads7846",
- .bus_num = 1,
- .chip_select = 0,
- .max_speed_hz = 1500000,
- .controller_data = &ads7846_mcspi_config,
- .irq = OMAP_GPIO_IRQ(OMAP3_STALKER_TS_GPIO),
- .platform_data = &ads7846_config,
- },
-};
static struct omap_board_config_kernel omap3_stalker_config[] __initdata = {
};
@@ -618,12 +525,6 @@ static struct omap_board_mux board_mux[] __initdata = {
};
#endif
-static struct omap_musb_board_data musb_board_data = {
- .interface_type = MUSB_INTERFACE_ULPI,
- .mode = MUSB_OTG,
- .power = 100,
-};
-
static void __init omap3_stalker_init(void)
{
omap3_mux_init(board_mux, OMAP_PACKAGE_CUS);
@@ -636,13 +537,11 @@ static void __init omap3_stalker_init(void)
ARRAY_SIZE(omap3_stalker_devices));
omap_display_init(&omap3_stalker_dss_data);
- spi_register_board_info(omap3stalker_spi_board_info,
- ARRAY_SIZE(omap3stalker_spi_board_info));
omap_serial_init();
- usb_musb_init(&musb_board_data);
+ usb_musb_init(NULL);
usbhs_init(&usbhs_bdata);
- ads7846_dev_init();
+ omap_ads7846_init(1, OMAP3_STALKER_TS_GPIO, 310, NULL);
omap_mux_init_gpio(21, OMAP_PIN_OUTPUT);
omap_mux_init_gpio(18, OMAP_PIN_INPUT_PULLUP);
diff --git a/arch/arm/mach-omap2/board-omap3touchbook.c b/arch/arm/mach-omap2/board-omap3touchbook.c
index 127cb1752bdd..82872d7d313b 100644
--- a/arch/arm/mach-omap2/board-omap3touchbook.c
+++ b/arch/arm/mach-omap2/board-omap3touchbook.c
@@ -52,6 +52,7 @@
#include "mux.h"
#include "hsmmc.h"
#include "timer-gp.h"
+#include "common-board-devices.h"
#include <asm/setup.h>
@@ -95,15 +96,6 @@ static struct mtd_partition omap3touchbook_nand_partitions[] = {
},
};
-static struct omap_nand_platform_data omap3touchbook_nand_data = {
- .options = NAND_BUSWIDTH_16,
- .parts = omap3touchbook_nand_partitions,
- .nr_parts = ARRAY_SIZE(omap3touchbook_nand_partitions),
- .dma_channel = -1, /* disable DMA in OMAP NAND driver */
- .nand_setup = NULL,
- .dev_ready = NULL,
-};
-
#include "sdram-micron-mt46h32m32lf-6.h"
static struct omap2_hsmmc_info mmc[] = {
@@ -154,13 +146,11 @@ static int touchbook_twl_gpio_setup(struct device *dev,
/* REVISIT: need ehci-omap hooks for external VBUS
* power switch and overcurrent detect
*/
-
- gpio_request(gpio + 1, "EHCI_nOC");
- gpio_direction_input(gpio + 1);
+ gpio_request_one(gpio + 1, GPIOF_IN, "EHCI_nOC");
/* TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, active low) */
- gpio_request(gpio + TWL4030_GPIO_MAX, "nEN_USB_PWR");
- gpio_direction_output(gpio + TWL4030_GPIO_MAX, 0);
+ gpio_request_one(gpio + TWL4030_GPIO_MAX, GPIOF_OUT_INIT_LOW,
+ "nEN_USB_PWR");
/* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */
gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1;
@@ -273,15 +263,6 @@ static struct twl4030_platform_data touchbook_twldata = {
.vpll2 = &touchbook_vpll2,
};
-static struct i2c_board_info __initdata touchbook_i2c_boardinfo[] = {
- {
- I2C_BOARD_INFO("twl4030", 0x48),
- .flags = I2C_CLIENT_WAKE,
- .irq = INT_34XX_SYS_NIRQ,
- .platform_data = &touchbook_twldata,
- },
-};
-
static struct i2c_board_info __initdata touchBook_i2c_boardinfo[] = {
{
I2C_BOARD_INFO("bq27200", 0x55),
@@ -291,8 +272,7 @@ static struct i2c_board_info __initdata touchBook_i2c_boardinfo[] = {
static int __init omap3_touchbook_i2c_init(void)
{
/* Standard TouchBook bus */
- omap_register_i2c_bus(1, 2600, touchbook_i2c_boardinfo,
- ARRAY_SIZE(touchbook_i2c_boardinfo));
+ omap3_pmic_init("twl4030", &touchbook_twldata);
/* Additional TouchBook bus */
omap_register_i2c_bus(3, 100, touchBook_i2c_boardinfo,
@@ -301,19 +281,7 @@ static int __init omap3_touchbook_i2c_init(void)
return 0;
}
-static void __init omap3_ads7846_init(void)
-{
- if (gpio_request(OMAP3_TS_GPIO, "ads7846_pen_down")) {
- printk(KERN_ERR "Failed to request GPIO %d for "
- "ads7846 pen down IRQ\n", OMAP3_TS_GPIO);
- return;
- }
-
- gpio_direction_input(OMAP3_TS_GPIO);
- gpio_set_debounce(OMAP3_TS_GPIO, 310);
-}
-
-static struct ads7846_platform_data ads7846_config = {
+static struct ads7846_platform_data ads7846_pdata = {
.x_min = 100,
.y_min = 265,
.x_max = 3950,
@@ -327,23 +295,6 @@ static struct ads7846_platform_data ads7846_config = {
.keep_vref_on = 1,
};
-static struct omap2_mcspi_device_config ads7846_mcspi_config = {
- .turbo_mode = 0,
- .single_channel = 1, /* 0: slave, 1: master */
-};
-
-static struct spi_board_info omap3_ads7846_spi_board_info[] __initdata = {
- {
- .modalias = "ads7846",
- .bus_num = 4,
- .chip_select = 0,
- .max_speed_hz = 1500000,
- .controller_data = &ads7846_mcspi_config,
- .irq = OMAP_GPIO_IRQ(OMAP3_TS_GPIO),
- .platform_data = &ads7846_config,
- }
-};
-
static struct gpio_led gpio_leds[] = {
{
.name = "touchbook::usr0",
@@ -434,39 +385,6 @@ static struct platform_device *omap3_touchbook_devices[] __initdata = {
&keys_gpio,
};
-static void __init omap3touchbook_flash_init(void)
-{
- u8 cs = 0;
- u8 nandcs = GPMC_CS_NUM + 1;
-
- /* find out the chip-select on which NAND exists */
- while (cs < GPMC_CS_NUM) {
- u32 ret = 0;
- ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
-
- if ((ret & 0xC00) == 0x800) {
- printk(KERN_INFO "Found NAND on CS%d\n", cs);
- if (nandcs > GPMC_CS_NUM)
- nandcs = cs;
- }
- cs++;
- }
-
- if (nandcs > GPMC_CS_NUM) {
- printk(KERN_INFO "NAND: Unable to find configuration "
- "in GPMC\n ");
- return;
- }
-
- if (nandcs < GPMC_CS_NUM) {
- omap3touchbook_nand_data.cs = nandcs;
-
- printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
- if (gpmc_nand_init(&omap3touchbook_nand_data) < 0)
- printk(KERN_ERR "Unable to register NAND device\n");
- }
-}
-
static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
.port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
@@ -481,15 +399,10 @@ static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
static void omap3_touchbook_poweroff(void)
{
- int r;
+ int pwr_off = TB_KILL_POWER_GPIO;
- r = gpio_request(TB_KILL_POWER_GPIO, "DVI reset");
- if (r < 0) {
+ if (gpio_request_one(pwr_off, GPIOF_OUT_INIT_LOW, "DVI reset") < 0)
printk(KERN_ERR "Unable to get kill power GPIO\n");
- return;
- }
-
- gpio_direction_output(TB_KILL_POWER_GPIO, 0);
}
static int __init early_touchbook_revision(char *p)
@@ -501,12 +414,6 @@ static int __init early_touchbook_revision(char *p)
}
early_param("tbr", early_touchbook_revision);
-static struct omap_musb_board_data musb_board_data = {
- .interface_type = MUSB_INTERFACE_ULPI,
- .mode = MUSB_OTG,
- .power = 100,
-};
-
static void __init omap3_touchbook_init(void)
{
omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
@@ -521,17 +428,15 @@ static void __init omap3_touchbook_init(void)
omap_serial_init();
omap_mux_init_gpio(170, OMAP_PIN_INPUT);
- gpio_request(176, "DVI_nPD");
/* REVISIT leave DVI powered down until it's needed ... */
- gpio_direction_output(176, true);
+ gpio_request_one(176, GPIOF_OUT_INIT_HIGH, "DVI_nPD");
/* Touchscreen and accelerometer */
- spi_register_board_info(omap3_ads7846_spi_board_info,
- ARRAY_SIZE(omap3_ads7846_spi_board_info));
- omap3_ads7846_init();
- usb_musb_init(&musb_board_data);
+ omap_ads7846_init(4, OMAP3_TS_GPIO, 310, &ads7846_pdata);
+ usb_musb_init(NULL);
usbhs_init(&usbhs_bdata);
- omap3touchbook_flash_init();
+ omap_nand_flash_init(NAND_BUSWIDTH_16, omap3touchbook_nand_partitions,
+ ARRAY_SIZE(omap3touchbook_nand_partitions));
/* Ensure SDRC pins are mux'd for self-refresh */
omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c
index f3a7b1011914..90485fced973 100644
--- a/arch/arm/mach-omap2/board-omap4panda.c
+++ b/arch/arm/mach-omap2/board-omap4panda.c
@@ -34,18 +34,19 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
#include <plat/board.h>
#include <plat/common.h>
#include <plat/usb.h>
#include <plat/mmc.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omap-panel-generic-dpi.h>
#include "timer-gp.h"
#include "hsmmc.h"
#include "control.h"
#include "mux.h"
+#include "common-board-devices.h"
#define GPIO_HUB_POWER 1
#define GPIO_HUB_NRESET 62
@@ -111,6 +112,11 @@ static const struct usbhs_omap_board_data usbhs_bdata __initconst = {
.reset_gpio_port[2] = -EINVAL
};
+static struct gpio panda_ehci_gpios[] __initdata = {
+ { GPIO_HUB_POWER, GPIOF_OUT_INIT_LOW, "hub_power" },
+ { GPIO_HUB_NRESET, GPIOF_OUT_INIT_LOW, "hub_nreset" },
+};
+
static void __init omap4_ehci_init(void)
{
int ret;
@@ -120,44 +126,27 @@ static void __init omap4_ehci_init(void)
phy_ref_clk = clk_get(NULL, "auxclk3_ck");
if (IS_ERR(phy_ref_clk)) {
pr_err("Cannot request auxclk3\n");
- goto error1;
+ return;
}
clk_set_rate(phy_ref_clk, 19200000);
clk_enable(phy_ref_clk);
- /* disable the power to the usb hub prior to init */
- ret = gpio_request(GPIO_HUB_POWER, "hub_power");
+ /* disable the power to the usb hub prior to init and reset phy+hub */
+ ret = gpio_request_array(panda_ehci_gpios,
+ ARRAY_SIZE(panda_ehci_gpios));
if (ret) {
- pr_err("Cannot request GPIO %d\n", GPIO_HUB_POWER);
- goto error1;
+ pr_err("Unable to initialize EHCI power/reset\n");
+ return;
}
- gpio_export(GPIO_HUB_POWER, 0);
- gpio_direction_output(GPIO_HUB_POWER, 0);
- gpio_set_value(GPIO_HUB_POWER, 0);
- /* reset phy+hub */
- ret = gpio_request(GPIO_HUB_NRESET, "hub_nreset");
- if (ret) {
- pr_err("Cannot request GPIO %d\n", GPIO_HUB_NRESET);
- goto error2;
- }
+ gpio_export(GPIO_HUB_POWER, 0);
gpio_export(GPIO_HUB_NRESET, 0);
- gpio_direction_output(GPIO_HUB_NRESET, 0);
- gpio_set_value(GPIO_HUB_NRESET, 0);
gpio_set_value(GPIO_HUB_NRESET, 1);
usbhs_init(&usbhs_bdata);
/* enable power to hub */
gpio_set_value(GPIO_HUB_POWER, 1);
- return;
-
-error2:
- gpio_free(GPIO_HUB_POWER);
-error1:
- pr_err("Unable to initialize EHCI power/reset\n");
- return;
-
}
static struct omap_musb_board_data musb_board_data = {
@@ -408,15 +397,6 @@ static struct twl4030_platform_data omap4_panda_twldata = {
.usb = &omap4_usbphy_data,
};
-static struct i2c_board_info __initdata omap4_panda_i2c_boardinfo[] = {
- {
- I2C_BOARD_INFO("twl6030", 0x48),
- .flags = I2C_CLIENT_WAKE,
- .irq = OMAP44XX_IRQ_SYS_1N,
- .platform_data = &omap4_panda_twldata,
- },
-};
-
/*
* Display monitor features are burnt in their EEPROM as EDID data. The EEPROM
* is connected as I2C slave device, and can be accessed at address 0x50
@@ -429,12 +409,7 @@ static struct i2c_board_info __initdata panda_i2c_eeprom[] = {
static int __init omap4_panda_i2c_init(void)
{
- /*
- * Phoenix Audio IC needs I2C1 to
- * start with 400 KHz or less
- */
- omap_register_i2c_bus(1, 400, omap4_panda_i2c_boardinfo,
- ARRAY_SIZE(omap4_panda_i2c_boardinfo));
+ omap4_pmic_init("twl6030", &omap4_panda_twldata);
omap_register_i2c_bus(2, 400, NULL, 0);
/*
* Bus 3 is attached to the DVI port where devices like the pico DLP
@@ -651,27 +626,19 @@ static void omap4_panda_hdmi_mux_init(void)
OMAP_PIN_INPUT_PULLUP);
}
+static struct gpio panda_hdmi_gpios[] = {
+ { HDMI_GPIO_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_hpd" },
+ { HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" },
+};
+
static int omap4_panda_panel_enable_hdmi(struct omap_dss_device *dssdev)
{
int status;
- status = gpio_request_one(HDMI_GPIO_HPD, GPIOF_OUT_INIT_HIGH,
- "hdmi_gpio_hpd");
- if (status) {
- pr_err("Cannot request GPIO %d\n", HDMI_GPIO_HPD);
- return status;
- }
- status = gpio_request_one(HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH,
- "hdmi_gpio_ls_oe");
- if (status) {
- pr_err("Cannot request GPIO %d\n", HDMI_GPIO_LS_OE);
- goto error1;
- }
-
- return 0;
-
-error1:
- gpio_free(HDMI_GPIO_HPD);
+ status = gpio_request_array(panda_hdmi_gpios,
+ ARRAY_SIZE(panda_hdmi_gpios));
+ if (status)
+ pr_err("Cannot request HDMI GPIOs\n");
return status;
}
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index 59ca33326b8c..1555918e3ffa 100644
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -43,8 +43,8 @@
#include <plat/board.h>
#include <plat/common.h>
-#include <plat/display.h>
-#include <plat/panel-generic-dpi.h>
+#include <video/omapdss.h>
+#include <video/omap-panel-generic-dpi.h>
#include <mach/gpio.h>
#include <plat/gpmc.h>
#include <mach/hardware.h>
@@ -56,6 +56,7 @@
#include "mux.h"
#include "sdram-micron-mt46h32m32lf-6.h"
#include "hsmmc.h"
+#include "common-board-devices.h"
#define OVERO_GPIO_BT_XGATE 15
#define OVERO_GPIO_W2W_NRESET 16
@@ -74,30 +75,6 @@
#if defined(CONFIG_TOUCHSCREEN_ADS7846) || \
defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
-#include <linux/spi/ads7846.h>
-
-static struct omap2_mcspi_device_config ads7846_mcspi_config = {
- .turbo_mode = 0,
- .single_channel = 1, /* 0: slave, 1: master */
-};
-
-static int ads7846_get_pendown_state(void)
-{
- return !gpio_get_value(OVERO_GPIO_PENDOWN);
-}
-
-static struct ads7846_platform_data ads7846_config = {
- .x_max = 0x0fff,
- .y_max = 0x0fff,
- .x_plate_ohms = 180,
- .pressure_max = 255,
- .debounce_max = 10,
- .debounce_tol = 3,
- .debounce_rep = 1,
- .get_pendown_state = ads7846_get_pendown_state,
- .keep_vref_on = 1,
-};
-
/* fixed regulator for ads7846 */
static struct regulator_consumer_supply ads7846_supply =
REGULATOR_SUPPLY("vcc", "spi1.0");
@@ -128,14 +105,7 @@ static struct platform_device vads7846_device = {
static void __init overo_ads7846_init(void)
{
- if ((gpio_request(OVERO_GPIO_PENDOWN, "ADS7846_PENDOWN") == 0) &&
- (gpio_direction_input(OVERO_GPIO_PENDOWN) == 0)) {
- gpio_export(OVERO_GPIO_PENDOWN, 0);
- } else {
- printk(KERN_ERR "could not obtain gpio for ADS7846_PENDOWN\n");
- return;
- }
-
+ omap_ads7846_init(1, OVERO_GPIO_PENDOWN, 0, NULL);
platform_device_register(&vads7846_device);
}
@@ -146,106 +116,28 @@ static inline void __init overo_ads7846_init(void) { return; }
#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
#include <linux/smsc911x.h>
+#include <plat/gpmc-smsc911x.h>
-static struct resource overo_smsc911x_resources[] = {
- {
- .name = "smsc911x-memory",
- .flags = IORESOURCE_MEM,
- },
- {
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
- },
-};
-
-static struct resource overo_smsc911x2_resources[] = {
- {
- .name = "smsc911x2-memory",
- .flags = IORESOURCE_MEM,
- },
- {
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
- },
-};
-
-static struct smsc911x_platform_config overo_smsc911x_config = {
- .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
- .irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
- .flags = SMSC911X_USE_32BIT ,
- .phy_interface = PHY_INTERFACE_MODE_MII,
-};
-
-static struct platform_device overo_smsc911x_device = {
- .name = "smsc911x",
+static struct omap_smsc911x_platform_data smsc911x_cfg = {
.id = 0,
- .num_resources = ARRAY_SIZE(overo_smsc911x_resources),
- .resource = overo_smsc911x_resources,
- .dev = {
- .platform_data = &overo_smsc911x_config,
- },
+ .cs = OVERO_SMSC911X_CS,
+ .gpio_irq = OVERO_SMSC911X_GPIO,
+ .gpio_reset = -EINVAL,
+ .flags = SMSC911X_USE_32BIT,
};
-static struct platform_device overo_smsc911x2_device = {
- .name = "smsc911x",
+static struct omap_smsc911x_platform_data smsc911x2_cfg = {
.id = 1,
- .num_resources = ARRAY_SIZE(overo_smsc911x2_resources),
- .resource = overo_smsc911x2_resources,
- .dev = {
- .platform_data = &overo_smsc911x_config,
- },
+ .cs = OVERO_SMSC911X2_CS,
+ .gpio_irq = OVERO_SMSC911X2_GPIO,
+ .gpio_reset = -EINVAL,
+ .flags = SMSC911X_USE_32BIT,
};
-static struct platform_device *smsc911x_devices[] = {
- &overo_smsc911x_device,
- &overo_smsc911x2_device,
-};
-
-static inline void __init overo_init_smsc911x(void)
+static void __init overo_init_smsc911x(void)
{
- unsigned long cs_mem_base, cs_mem_base2;
-
- /* set up first smsc911x chip */
-
- if (gpmc_cs_request(OVERO_SMSC911X_CS, SZ_16M, &cs_mem_base) < 0) {
- printk(KERN_ERR "Failed request for GPMC mem for smsc911x\n");
- return;
- }
-
- overo_smsc911x_resources[0].start = cs_mem_base + 0x0;
- overo_smsc911x_resources[0].end = cs_mem_base + 0xff;
-
- if ((gpio_request(OVERO_SMSC911X_GPIO, "SMSC911X IRQ") == 0) &&
- (gpio_direction_input(OVERO_SMSC911X_GPIO) == 0)) {
- gpio_export(OVERO_SMSC911X_GPIO, 0);
- } else {
- printk(KERN_ERR "could not obtain gpio for SMSC911X IRQ\n");
- return;
- }
-
- overo_smsc911x_resources[1].start = OMAP_GPIO_IRQ(OVERO_SMSC911X_GPIO);
- overo_smsc911x_resources[1].end = 0;
-
- /* set up second smsc911x chip */
-
- if (gpmc_cs_request(OVERO_SMSC911X2_CS, SZ_16M, &cs_mem_base2) < 0) {
- printk(KERN_ERR "Failed request for GPMC mem for smsc911x2\n");
- return;
- }
-
- overo_smsc911x2_resources[0].start = cs_mem_base2 + 0x0;
- overo_smsc911x2_resources[0].end = cs_mem_base2 + 0xff;
-
- if ((gpio_request(OVERO_SMSC911X2_GPIO, "SMSC911X2 IRQ") == 0) &&
- (gpio_direction_input(OVERO_SMSC911X2_GPIO) == 0)) {
- gpio_export(OVERO_SMSC911X2_GPIO, 0);
- } else {
- printk(KERN_ERR "could not obtain gpio for SMSC911X2 IRQ\n");
- return;
- }
-
- overo_smsc911x2_resources[1].start = OMAP_GPIO_IRQ(OVERO_SMSC911X2_GPIO);
- overo_smsc911x2_resources[1].end = 0;
-
- platform_add_devices(smsc911x_devices, ARRAY_SIZE(smsc911x_devices));
+ gpmc_smsc911x_init(&smsc911x_cfg);
+ gpmc_smsc911x_init(&smsc911x2_cfg);
}
#else
@@ -259,21 +151,20 @@ static int dvi_enabled;
#define OVERO_GPIO_LCD_EN 144
#define OVERO_GPIO_LCD_BL 145
+static struct gpio overo_dss_gpios[] __initdata = {
+ { OVERO_GPIO_LCD_EN, GPIOF_OUT_INIT_HIGH, "OVERO_GPIO_LCD_EN" },
+ { OVERO_GPIO_LCD_BL, GPIOF_OUT_INIT_HIGH, "OVERO_GPIO_LCD_BL" },
+};
+
static void __init overo_display_init(void)
{
- if ((gpio_request(OVERO_GPIO_LCD_EN, "OVERO_GPIO_LCD_EN") == 0) &&
- (gpio_direction_output(OVERO_GPIO_LCD_EN, 1) == 0))
- gpio_export(OVERO_GPIO_LCD_EN, 0);
- else
- printk(KERN_ERR "could not obtain gpio for "
- "OVERO_GPIO_LCD_EN\n");
+ if (gpio_request_array(overo_dss_gpios, ARRAY_SIZE(overo_dss_gpios))) {
+ printk(KERN_ERR "could not obtain DSS control GPIOs\n");
+ return;
+ }
- if ((gpio_request(OVERO_GPIO_LCD_BL, "OVERO_GPIO_LCD_BL") == 0) &&
- (gpio_direction_output(OVERO_GPIO_LCD_BL, 1) == 0))
- gpio_export(OVERO_GPIO_LCD_BL, 0);
- else
- printk(KERN_ERR "could not obtain gpio for "
- "OVERO_GPIO_LCD_BL\n");
+ gpio_export(OVERO_GPIO_LCD_EN, 0);
+ gpio_export(OVERO_GPIO_LCD_BL, 0);
}
static int overo_panel_enable_dvi(struct omap_dss_device *dssdev)
@@ -412,45 +303,6 @@ static struct mtd_partition overo_nand_partitions[] = {
},
};
-static struct omap_nand_platform_data overo_nand_data = {
- .parts = overo_nand_partitions,
- .nr_parts = ARRAY_SIZE(overo_nand_partitions),
- .dma_channel = -1, /* disable DMA in OMAP NAND driver */
-};
-
-static void __init overo_flash_init(void)
-{
- u8 cs = 0;
- u8 nandcs = GPMC_CS_NUM + 1;
-
- /* find out the chip-select on which NAND exists */
- while (cs < GPMC_CS_NUM) {
- u32 ret = 0;
- ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
-
- if ((ret & 0xC00) == 0x800) {
- printk(KERN_INFO "Found NAND on CS%d\n", cs);
- if (nandcs > GPMC_CS_NUM)
- nandcs = cs;
- }
- cs++;
- }
-
- if (nandcs > GPMC_CS_NUM) {
- printk(KERN_INFO "NAND: Unable to find configuration "
- "in GPMC\n ");
- return;
- }
-
- if (nandcs < GPMC_CS_NUM) {
- overo_nand_data.cs = nandcs;
-
- printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
- if (gpmc_nand_init(&overo_nand_data) < 0)
- printk(KERN_ERR "Unable to register NAND device\n");
- }
-}
-
static struct omap2_hsmmc_info mmc[] = {
{
.mmc = 1,
@@ -648,37 +500,15 @@ static struct twl4030_platform_data overo_twldata = {
.vpll2 = &overo_vpll2,
};
-static struct i2c_board_info __initdata overo_i2c_boardinfo[] = {
- {
- I2C_BOARD_INFO("tps65950", 0x48),
- .flags = I2C_CLIENT_WAKE,
- .irq = INT_34XX_SYS_NIRQ,
- .platform_data = &overo_twldata,
- },
-};
-
static int __init overo_i2c_init(void)
{
- omap_register_i2c_bus(1, 2600, overo_i2c_boardinfo,
- ARRAY_SIZE(overo_i2c_boardinfo));
+ omap3_pmic_init("tps65950", &overo_twldata);
/* i2c2 pins are used for gpio */
omap_register_i2c_bus(3, 400, NULL, 0);
return 0;
}
static struct spi_board_info overo_spi_board_info[] __initdata = {
-#if defined(CONFIG_TOUCHSCREEN_ADS7846) || \
- defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
- {
- .modalias = "ads7846",
- .bus_num = 1,
- .chip_select = 0,
- .max_speed_hz = 1500000,
- .controller_data = &ads7846_mcspi_config,
- .irq = OMAP_GPIO_IRQ(OVERO_GPIO_PENDOWN),
- .platform_data = &ads7846_config,
- },
-#endif
#if defined(CONFIG_PANEL_LGPHILIPS_LB035Q02) || \
defined(CONFIG_PANEL_LGPHILIPS_LB035Q02_MODULE)
{
@@ -722,20 +552,22 @@ static struct omap_board_mux board_mux[] __initdata = {
};
#endif
-static struct omap_musb_board_data musb_board_data = {
- .interface_type = MUSB_INTERFACE_ULPI,
- .mode = MUSB_OTG,
- .power = 100,
+static struct gpio overo_bt_gpios[] __initdata = {
+ { OVERO_GPIO_BT_XGATE, GPIOF_OUT_INIT_LOW, "lcd enable" },
+ { OVERO_GPIO_BT_NRESET, GPIOF_OUT_INIT_HIGH, "lcd bl enable" },
};
static void __init overo_init(void)
{
+ int ret;
+
omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
overo_i2c_init();
omap_display_init(&overo_dss_data);
omap_serial_init();
- overo_flash_init();
- usb_musb_init(&musb_board_data);
+ omap_nand_flash_init(0, overo_nand_partitions,
+ ARRAY_SIZE(overo_nand_partitions));
+ usb_musb_init(NULL);
usbhs_init(&usbhs_bdata);
overo_spi_init();
overo_ads7846_init();
@@ -748,9 +580,9 @@ static void __init overo_init(void)
omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
- if ((gpio_request(OVERO_GPIO_W2W_NRESET,
- "OVERO_GPIO_W2W_NRESET") == 0) &&
- (gpio_direction_output(OVERO_GPIO_W2W_NRESET, 1) == 0)) {
+ ret = gpio_request_one(OVERO_GPIO_W2W_NRESET, GPIOF_OUT_INIT_HIGH,
+ "OVERO_GPIO_W2W_NRESET");
+ if (ret == 0) {
gpio_export(OVERO_GPIO_W2W_NRESET, 0);
gpio_set_value(OVERO_GPIO_W2W_NRESET, 0);
udelay(10);
@@ -760,25 +592,20 @@ static void __init overo_init(void)
"OVERO_GPIO_W2W_NRESET\n");
}
- if ((gpio_request(OVERO_GPIO_BT_XGATE, "OVERO_GPIO_BT_XGATE") == 0) &&
- (gpio_direction_output(OVERO_GPIO_BT_XGATE, 0) == 0))
+ ret = gpio_request_array(overo_bt_gpios, ARRAY_SIZE(overo_bt_gpios));
+ if (ret) {
+ pr_err("%s: could not obtain BT gpios\n", __func__);
+ } else {
gpio_export(OVERO_GPIO_BT_XGATE, 0);
- else
- printk(KERN_ERR "could not obtain gpio for OVERO_GPIO_BT_XGATE\n");
-
- if ((gpio_request(OVERO_GPIO_BT_NRESET, "OVERO_GPIO_BT_NRESET") == 0) &&
- (gpio_direction_output(OVERO_GPIO_BT_NRESET, 1) == 0)) {
gpio_export(OVERO_GPIO_BT_NRESET, 0);
gpio_set_value(OVERO_GPIO_BT_NRESET, 0);
mdelay(6);
gpio_set_value(OVERO_GPIO_BT_NRESET, 1);
- } else {
- printk(KERN_ERR "could not obtain gpio for "
- "OVERO_GPIO_BT_NRESET\n");
}
- if ((gpio_request(OVERO_GPIO_USBH_CPEN, "OVERO_GPIO_USBH_CPEN") == 0) &&
- (gpio_direction_output(OVERO_GPIO_USBH_CPEN, 1) == 0))
+ ret = gpio_request_one(OVERO_GPIO_USBH_CPEN, GPIOF_OUT_INIT_HIGH,
+ "OVERO_GPIO_USBH_CPEN");
+ if (ret == 0)
gpio_export(OVERO_GPIO_USBH_CPEN, 0);
else
printk(KERN_ERR "could not obtain gpio for "
diff --git a/arch/arm/mach-omap2/board-rm680.c b/arch/arm/mach-omap2/board-rm680.c
index 2af8b05e786d..42d10b12da3c 100644
--- a/arch/arm/mach-omap2/board-rm680.c
+++ b/arch/arm/mach-omap2/board-rm680.c
@@ -31,6 +31,7 @@
#include "mux.h"
#include "hsmmc.h"
#include "sdram-nokia.h"
+#include "common-board-devices.h"
static struct regulator_consumer_supply rm680_vemmc_consumers[] = {
REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1"),
@@ -90,19 +91,9 @@ static struct twl4030_platform_data rm680_twl_data = {
/* add rest of the children here */
};
-static struct i2c_board_info __initdata rm680_twl_i2c_board_info[] = {
- {
- I2C_BOARD_INFO("twl5031", 0x48),
- .flags = I2C_CLIENT_WAKE,
- .irq = INT_34XX_SYS_NIRQ,
- .platform_data = &rm680_twl_data,
- },
-};
-
static void __init rm680_i2c_init(void)
{
- omap_register_i2c_bus(1, 2900, rm680_twl_i2c_board_info,
- ARRAY_SIZE(rm680_twl_i2c_board_info));
+ omap_pmic_init(1, 2900, "twl5031", INT_34XX_SYS_NIRQ, &rm680_twl_data);
omap_register_i2c_bus(2, 400, NULL, 0);
omap_register_i2c_bus(3, 400, NULL, 0);
}
@@ -153,17 +144,11 @@ static struct omap_board_mux board_mux[] __initdata = {
};
#endif
-static struct omap_musb_board_data rm680_musb_data = {
- .interface_type = MUSB_INTERFACE_ULPI,
- .mode = MUSB_PERIPHERAL,
- .power = 100,
-};
-
static void __init rm680_init(void)
{
omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
omap_serial_init();
- usb_musb_init(&rm680_musb_data);
+ usb_musb_init(NULL);
rm680_peripherals_init();
}
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index bbcb6775a6a3..f6247e71a194 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -23,6 +23,7 @@
#include <linux/gpio.h>
#include <linux/gpio_keys.h>
#include <linux/mmc/host.h>
+#include <linux/power/isp1704_charger.h>
#include <plat/mcspi.h>
#include <plat/board.h>
@@ -43,6 +44,7 @@
#include "mux.h"
#include "hsmmc.h"
+#include "common-board-devices.h"
#define SYSTEM_REV_B_USES_VAUX3 0x1699
#define SYSTEM_REV_S_USES_VAUX3 0x8
@@ -52,6 +54,8 @@
#define RX51_FMTX_RESET_GPIO 163
#define RX51_FMTX_IRQ 53
+#define RX51_USB_TRANSCEIVER_RST_GPIO 67
+
/* list all spi devices here */
enum {
RX51_SPI_WL1251,
@@ -110,10 +114,30 @@ static struct spi_board_info rx51_peripherals_spi_board_info[] __initdata = {
},
};
+static void rx51_charger_set_power(bool on)
+{
+ gpio_set_value(RX51_USB_TRANSCEIVER_RST_GPIO, on);
+}
+
+static struct isp1704_charger_data rx51_charger_data = {
+ .set_power = rx51_charger_set_power,
+};
+
static struct platform_device rx51_charger_device = {
- .name = "isp1704_charger",
+ .name = "isp1704_charger",
+ .dev = {
+ .platform_data = &rx51_charger_data,
+ },
};
+static void __init rx51_charger_init(void)
+{
+ WARN_ON(gpio_request_one(RX51_USB_TRANSCEIVER_RST_GPIO,
+ GPIOF_OUT_INIT_LOW, "isp1704_reset"));
+
+ platform_device_register(&rx51_charger_device);
+}
+
#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
#define RX51_GPIO_CAMERA_LENS_COVER 110
@@ -557,10 +581,8 @@ static __init void rx51_init_si4713(void)
static int rx51_twlgpio_setup(struct device *dev, unsigned gpio, unsigned n)
{
/* FIXME this gpio setup is just a placeholder for now */
- gpio_request(gpio + 6, "backlight_pwm");
- gpio_direction_output(gpio + 6, 0);
- gpio_request(gpio + 7, "speaker_en");
- gpio_direction_output(gpio + 7, 1);
+ gpio_request_one(gpio + 6, GPIOF_OUT_INIT_LOW, "backlight_pwm");
+ gpio_request_one(gpio + 7, GPIOF_OUT_INIT_HIGH, "speaker_en");
return 0;
}
@@ -730,7 +752,7 @@ static struct twl4030_resconfig twl4030_rconfig[] __initdata = {
{ .resource = RES_RESET, .devgroup = -1,
.type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
},
- { .resource = RES_Main_Ref, .devgroup = -1,
+ { .resource = RES_MAIN_REF, .devgroup = -1,
.type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1
},
{ 0, 0},
@@ -777,15 +799,6 @@ static struct tpa6130a2_platform_data rx51_tpa6130a2_data __initdata_or_module =
.power_gpio = 98,
};
-static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_1[] = {
- {
- I2C_BOARD_INFO("twl5030", 0x48),
- .flags = I2C_CLIENT_WAKE,
- .irq = INT_34XX_SYS_NIRQ,
- .platform_data = &rx51_twldata,
- },
-};
-
/* Audio setup data */
static struct aic3x_setup_data rx51_aic34_setup = {
.gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
@@ -833,8 +846,7 @@ static int __init rx51_i2c_init(void)
rx51_twldata.vaux3 = &rx51_vaux3_cam;
}
rx51_twldata.vmmc2 = &rx51_vmmc2;
- omap_register_i2c_bus(1, 2200, rx51_peripherals_i2c_board_info_1,
- ARRAY_SIZE(rx51_peripherals_i2c_board_info_1));
+ omap_pmic_init(1, 2200, "twl5030", INT_34XX_SYS_NIRQ, &rx51_twldata);
omap_register_i2c_bus(2, 100, rx51_peripherals_i2c_board_info_2,
ARRAY_SIZE(rx51_peripherals_i2c_board_info_2));
omap_register_i2c_bus(3, 400, NULL, 0);
@@ -921,26 +933,20 @@ static void rx51_wl1251_set_power(bool enable)
gpio_set_value(RX51_WL1251_POWER_GPIO, enable);
}
+static struct gpio rx51_wl1251_gpios[] __initdata = {
+ { RX51_WL1251_POWER_GPIO, GPIOF_OUT_INIT_LOW, "wl1251 power" },
+ { RX51_WL1251_IRQ_GPIO, GPIOF_IN, "wl1251 irq" },
+};
+
static void __init rx51_init_wl1251(void)
{
int irq, ret;
- ret = gpio_request(RX51_WL1251_POWER_GPIO, "wl1251 power");
+ ret = gpio_request_array(rx51_wl1251_gpios,
+ ARRAY_SIZE(rx51_wl1251_gpios));
if (ret < 0)
goto error;
- ret = gpio_direction_output(RX51_WL1251_POWER_GPIO, 0);
- if (ret < 0)
- goto err_power;
-
- ret = gpio_request(RX51_WL1251_IRQ_GPIO, "wl1251 irq");
- if (ret < 0)
- goto err_power;
-
- ret = gpio_direction_input(RX51_WL1251_IRQ_GPIO);
- if (ret < 0)
- goto err_irq;
-
irq = gpio_to_irq(RX51_WL1251_IRQ_GPIO);
if (irq < 0)
goto err_irq;
@@ -952,10 +958,7 @@ static void __init rx51_init_wl1251(void)
err_irq:
gpio_free(RX51_WL1251_IRQ_GPIO);
-
-err_power:
gpio_free(RX51_WL1251_POWER_GPIO);
-
error:
printk(KERN_ERR "wl1251 board initialisation failed\n");
wl1251_pdata.set_power = NULL;
@@ -981,6 +984,6 @@ void __init rx51_peripherals_init(void)
if (partition)
omap2_hsmmc_init(mmc);
- platform_device_register(&rx51_charger_device);
+ rx51_charger_init();
}
diff --git a/arch/arm/mach-omap2/board-rx51-video.c b/arch/arm/mach-omap2/board-rx51-video.c
index 89a66db8b77d..2c1289bd5e6a 100644
--- a/arch/arm/mach-omap2/board-rx51-video.c
+++ b/arch/arm/mach-omap2/board-rx51-video.c
@@ -15,7 +15,7 @@
#include <linux/spi/spi.h>
#include <linux/mm.h>
#include <asm/mach-types.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
#include <plat/vram.h>
#include <plat/mcspi.h>
@@ -76,13 +76,12 @@ static int __init rx51_video_init(void)
return 0;
}
- if (gpio_request(RX51_LCD_RESET_GPIO, "LCD ACX565AKM reset")) {
+ if (gpio_request_one(RX51_LCD_RESET_GPIO, GPIOF_OUT_INIT_HIGH,
+ "LCD ACX565AKM reset")) {
pr_err("%s failed to get LCD Reset GPIO\n", __func__);
return 0;
}
- gpio_direction_output(RX51_LCD_RESET_GPIO, 1);
-
omap_display_init(&rx51_dss_board_info);
return 0;
}
diff --git a/arch/arm/mach-omap2/board-rx51.c b/arch/arm/mach-omap2/board-rx51.c
index f8ba20a14e62..fec4cac8fa0a 100644
--- a/arch/arm/mach-omap2/board-rx51.c
+++ b/arch/arm/mach-omap2/board-rx51.c
@@ -58,21 +58,25 @@ static struct platform_device leds_gpio = {
},
};
+/*
+ * cpuidle C-states definition override from the default values.
+ * The 'exit_latency' field is the sum of sleep and wake-up latencies.
+ */
static struct cpuidle_params rx51_cpuidle_params[] = {
/* C1 */
- {1, 110, 162, 5},
+ {110 + 162, 5 , 1},
/* C2 */
- {1, 106, 180, 309},
+ {106 + 180, 309, 1},
/* C3 */
- {0, 107, 410, 46057},
+ {107 + 410, 46057, 0},
/* C4 */
- {0, 121, 3374, 46057},
+ {121 + 3374, 46057, 0},
/* C5 */
- {1, 855, 1146, 46057},
+ {855 + 1146, 46057, 1},
/* C6 */
- {0, 7580, 4134, 484329},
+ {7580 + 4134, 484329, 0},
/* C7 */
- {1, 7505, 15274, 484329},
+ {7505 + 15274, 484329, 1},
};
static struct omap_lcd_config rx51_lcd_config = {
diff --git a/arch/arm/mach-omap2/board-zoom-debugboard.c b/arch/arm/mach-omap2/board-zoom-debugboard.c
index 007ebdc6c993..6402e781c458 100644
--- a/arch/arm/mach-omap2/board-zoom-debugboard.c
+++ b/arch/arm/mach-omap2/board-zoom-debugboard.c
@@ -15,6 +15,7 @@
#include <linux/interrupt.h>
#include <plat/gpmc.h>
+#include <plat/gpmc-smsc911x.h>
#include <mach/board-zoom.h>
@@ -26,60 +27,16 @@
#define DEBUG_BASE 0x08000000
#define ZOOM_ETHR_START DEBUG_BASE
-static struct resource zoom_smsc911x_resources[] = {
- [0] = {
- .start = ZOOM_ETHR_START,
- .end = ZOOM_ETHR_START + SZ_4K,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
- },
-};
-
-static struct smsc911x_platform_config zoom_smsc911x_config = {
- .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
- .irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+static struct omap_smsc911x_platform_data zoom_smsc911x_cfg = {
+ .cs = ZOOM_SMSC911X_CS,
+ .gpio_irq = ZOOM_SMSC911X_GPIO,
+ .gpio_reset = -EINVAL,
.flags = SMSC911X_USE_32BIT,
- .phy_interface = PHY_INTERFACE_MODE_MII,
-};
-
-static struct platform_device zoom_smsc911x_device = {
- .name = "smsc911x",
- .id = -1,
- .num_resources = ARRAY_SIZE(zoom_smsc911x_resources),
- .resource = zoom_smsc911x_resources,
- .dev = {
- .platform_data = &zoom_smsc911x_config,
- },
};
static inline void __init zoom_init_smsc911x(void)
{
- int eth_cs;
- unsigned long cs_mem_base;
- int eth_gpio = 0;
-
- eth_cs = ZOOM_SMSC911X_CS;
-
- if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
- printk(KERN_ERR "Failed to request GPMC mem for smsc911x\n");
- return;
- }
-
- zoom_smsc911x_resources[0].start = cs_mem_base + 0x0;
- zoom_smsc911x_resources[0].end = cs_mem_base + 0xff;
-
- eth_gpio = ZOOM_SMSC911X_GPIO;
-
- zoom_smsc911x_resources[1].start = OMAP_GPIO_IRQ(eth_gpio);
-
- if (gpio_request(eth_gpio, "smsc911x irq") < 0) {
- printk(KERN_ERR "Failed to request GPIO%d for smsc911x IRQ\n",
- eth_gpio);
- return;
- }
- gpio_direction_input(eth_gpio);
+ gpmc_smsc911x_init(&zoom_smsc911x_cfg);
}
static struct plat_serial8250_port serial_platform_data[] = {
@@ -120,12 +77,9 @@ static inline void __init zoom_init_quaduart(void)
quart_gpio = ZOOM_QUADUART_GPIO;
- if (gpio_request(quart_gpio, "TL16CP754C GPIO") < 0) {
+ if (gpio_request_one(quart_gpio, GPIOF_IN, "TL16CP754C GPIO") < 0)
printk(KERN_ERR "Failed to request GPIO%d for TL16CP754C\n",
quart_gpio);
- return;
- }
- gpio_direction_input(quart_gpio);
}
static inline int omap_zoom_debugboard_detect(void)
@@ -135,12 +89,12 @@ static inline int omap_zoom_debugboard_detect(void)
debug_board_detect = ZOOM_SMSC911X_GPIO;
- if (gpio_request(debug_board_detect, "Zoom debug board detect") < 0) {
+ if (gpio_request_one(debug_board_detect, GPIOF_IN,
+ "Zoom debug board detect") < 0) {
printk(KERN_ERR "Failed to request GPIO%d for Zoom debug"
"board detect\n", debug_board_detect);
return 0;
}
- gpio_direction_input(debug_board_detect);
if (!gpio_get_value(debug_board_detect)) {
ret = 0;
@@ -150,7 +104,6 @@ static inline int omap_zoom_debugboard_detect(void)
}
static struct platform_device *zoom_devices[] __initdata = {
- &zoom_smsc911x_device,
&zoom_debugboard_serial_device,
};
diff --git a/arch/arm/mach-omap2/board-zoom-display.c b/arch/arm/mach-omap2/board-zoom-display.c
index 37b84c2b850f..c7c6beb1ec24 100644
--- a/arch/arm/mach-omap2/board-zoom-display.c
+++ b/arch/arm/mach-omap2/board-zoom-display.c
@@ -15,40 +15,25 @@
#include <linux/i2c/twl.h>
#include <linux/spi/spi.h>
#include <plat/mcspi.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
#define LCD_PANEL_RESET_GPIO_PROD 96
#define LCD_PANEL_RESET_GPIO_PILOT 55
#define LCD_PANEL_QVGA_GPIO 56
+static struct gpio zoom_lcd_gpios[] __initdata = {
+ { -EINVAL, GPIOF_OUT_INIT_HIGH, "lcd reset" },
+ { LCD_PANEL_QVGA_GPIO, GPIOF_OUT_INIT_HIGH, "lcd qvga" },
+};
+
static void zoom_lcd_panel_init(void)
{
- int ret;
- unsigned char lcd_panel_reset_gpio;
-
- lcd_panel_reset_gpio = (omap_rev() > OMAP3430_REV_ES3_0) ?
+ zoom_lcd_gpios[0].gpio = (omap_rev() > OMAP3430_REV_ES3_0) ?
LCD_PANEL_RESET_GPIO_PROD :
LCD_PANEL_RESET_GPIO_PILOT;
- ret = gpio_request(lcd_panel_reset_gpio, "lcd reset");
- if (ret) {
- pr_err("Failed to get LCD reset GPIO (gpio%d).\n",
- lcd_panel_reset_gpio);
- return;
- }
- gpio_direction_output(lcd_panel_reset_gpio, 1);
-
- ret = gpio_request(LCD_PANEL_QVGA_GPIO, "lcd qvga");
- if (ret) {
- pr_err("Failed to get LCD_PANEL_QVGA_GPIO (gpio%d).\n",
- LCD_PANEL_QVGA_GPIO);
- goto err0;
- }
- gpio_direction_output(LCD_PANEL_QVGA_GPIO, 1);
-
- return;
-err0:
- gpio_free(lcd_panel_reset_gpio);
+ if (gpio_request_array(zoom_lcd_gpios, ARRAY_SIZE(zoom_lcd_gpios)))
+ pr_err("%s: Failed to get LCD GPIOs.\n", __func__);
}
static int zoom_panel_enable_lcd(struct omap_dss_device *dssdev)
diff --git a/arch/arm/mach-omap2/board-zoom-peripherals.c b/arch/arm/mach-omap2/board-zoom-peripherals.c
index 8dee7549fbdf..118c6f53c5eb 100644
--- a/arch/arm/mach-omap2/board-zoom-peripherals.c
+++ b/arch/arm/mach-omap2/board-zoom-peripherals.c
@@ -31,6 +31,7 @@
#include "mux.h"
#include "hsmmc.h"
+#include "common-board-devices.h"
#define OMAP_ZOOM_WLAN_PMENA_GPIO (101)
#define OMAP_ZOOM_WLAN_IRQ_GPIO (162)
@@ -276,13 +277,11 @@ static int zoom_twl_gpio_setup(struct device *dev,
zoom_vsim_supply.dev = mmc[0].dev;
zoom_vmmc2_supply.dev = mmc[1].dev;
- ret = gpio_request(LCD_PANEL_ENABLE_GPIO, "lcd enable");
- if (ret) {
+ ret = gpio_request_one(LCD_PANEL_ENABLE_GPIO, GPIOF_OUT_INIT_LOW,
+ "lcd enable");
+ if (ret)
pr_err("Failed to get LCD_PANEL_ENABLE_GPIO (gpio%d).\n",
LCD_PANEL_ENABLE_GPIO);
- return ret;
- }
- gpio_direction_output(LCD_PANEL_ENABLE_GPIO, 0);
return ret;
}
@@ -349,15 +348,6 @@ static struct twl4030_platform_data zoom_twldata = {
.vdac = &zoom_vdac,
};
-static struct i2c_board_info __initdata zoom_i2c_boardinfo[] = {
- {
- I2C_BOARD_INFO("twl5030", 0x48),
- .flags = I2C_CLIENT_WAKE,
- .irq = INT_34XX_SYS_NIRQ,
- .platform_data = &zoom_twldata,
- },
-};
-
static int __init omap_i2c_init(void)
{
if (machine_is_omap_zoom2()) {
@@ -365,19 +355,12 @@ static int __init omap_i2c_init(void)
zoom_audio_data.hs_extmute = 1;
zoom_audio_data.set_hs_extmute = zoom2_set_hs_extmute;
}
- omap_register_i2c_bus(1, 2400, zoom_i2c_boardinfo,
- ARRAY_SIZE(zoom_i2c_boardinfo));
+ omap_pmic_init(1, 2400, "twl5030", INT_34XX_SYS_NIRQ, &zoom_twldata);
omap_register_i2c_bus(2, 400, NULL, 0);
omap_register_i2c_bus(3, 400, NULL, 0);
return 0;
}
-static struct omap_musb_board_data musb_board_data = {
- .interface_type = MUSB_INTERFACE_ULPI,
- .mode = MUSB_OTG,
- .power = 100,
-};
-
static void enable_board_wakeup_source(void)
{
/* T2 interrupt line (keypad) */
@@ -392,7 +375,7 @@ void __init zoom_peripherals_init(void)
omap_i2c_init();
platform_device_register(&omap_vwlan_device);
- usb_musb_init(&musb_board_data);
+ usb_musb_init(NULL);
enable_board_wakeup_source();
omap_serial_init();
}
diff --git a/arch/arm/mach-omap2/common-board-devices.c b/arch/arm/mach-omap2/common-board-devices.c
new file mode 100644
index 000000000000..e94903b2c65b
--- /dev/null
+++ b/arch/arm/mach-omap2/common-board-devices.c
@@ -0,0 +1,163 @@
+/*
+ * common-board-devices.c
+ *
+ * Copyright (C) 2011 CompuLab, Ltd.
+ * Author: Mike Rapoport <mike@compulab.co.il>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You 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/i2c.h>
+#include <linux/i2c/twl.h>
+
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+
+#include <plat/i2c.h>
+#include <plat/mcspi.h>
+#include <plat/nand.h>
+
+#include "common-board-devices.h"
+
+static struct i2c_board_info __initdata pmic_i2c_board_info = {
+ .addr = 0x48,
+ .flags = I2C_CLIENT_WAKE,
+};
+
+void __init omap_pmic_init(int bus, u32 clkrate,
+ const char *pmic_type, int pmic_irq,
+ struct twl4030_platform_data *pmic_data)
+{
+ strncpy(pmic_i2c_board_info.type, pmic_type,
+ sizeof(pmic_i2c_board_info.type));
+ pmic_i2c_board_info.irq = pmic_irq;
+ pmic_i2c_board_info.platform_data = pmic_data;
+
+ omap_register_i2c_bus(bus, clkrate, &pmic_i2c_board_info, 1);
+}
+
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) || \
+ defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+static struct omap2_mcspi_device_config ads7846_mcspi_config = {
+ .turbo_mode = 0,
+ .single_channel = 1, /* 0: slave, 1: master */
+};
+
+static struct ads7846_platform_data ads7846_config = {
+ .x_max = 0x0fff,
+ .y_max = 0x0fff,
+ .x_plate_ohms = 180,
+ .pressure_max = 255,
+ .debounce_max = 10,
+ .debounce_tol = 3,
+ .debounce_rep = 1,
+ .gpio_pendown = -EINVAL,
+ .keep_vref_on = 1,
+};
+
+static struct spi_board_info ads7846_spi_board_info __initdata = {
+ .modalias = "ads7846",
+ .bus_num = -EINVAL,
+ .chip_select = 0,
+ .max_speed_hz = 1500000,
+ .controller_data = &ads7846_mcspi_config,
+ .irq = -EINVAL,
+ .platform_data = &ads7846_config,
+};
+
+void __init omap_ads7846_init(int bus_num, int gpio_pendown, int gpio_debounce,
+ struct ads7846_platform_data *board_pdata)
+{
+ struct spi_board_info *spi_bi = &ads7846_spi_board_info;
+ int err;
+
+ err = gpio_request(gpio_pendown, "TS PenDown");
+ if (err) {
+ pr_err("Could not obtain gpio for TS PenDown: %d\n", err);
+ return;
+ }
+
+ gpio_direction_input(gpio_pendown);
+ gpio_export(gpio_pendown, 0);
+
+ if (gpio_debounce)
+ gpio_set_debounce(gpio_pendown, gpio_debounce);
+
+ ads7846_config.gpio_pendown = gpio_pendown;
+
+ spi_bi->bus_num = bus_num;
+ spi_bi->irq = OMAP_GPIO_IRQ(gpio_pendown);
+
+ if (board_pdata)
+ spi_bi->platform_data = board_pdata;
+
+ spi_register_board_info(&ads7846_spi_board_info, 1);
+}
+#else
+void __init omap_ads7846_init(int bus_num, int gpio_pendown, int gpio_debounce,
+ struct ads7846_platform_data *board_pdata)
+{
+}
+#endif
+
+#if defined(CONFIG_MTD_NAND_OMAP2) || defined(CONFIG_MTD_NAND_OMAP2_MODULE)
+static struct omap_nand_platform_data nand_data = {
+ .dma_channel = -1, /* disable DMA in OMAP NAND driver */
+};
+
+void __init omap_nand_flash_init(int options, struct mtd_partition *parts,
+ int nr_parts)
+{
+ u8 cs = 0;
+ u8 nandcs = GPMC_CS_NUM + 1;
+
+ /* find out the chip-select on which NAND exists */
+ while (cs < GPMC_CS_NUM) {
+ u32 ret = 0;
+ ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1);
+
+ if ((ret & 0xC00) == 0x800) {
+ printk(KERN_INFO "Found NAND on CS%d\n", cs);
+ if (nandcs > GPMC_CS_NUM)
+ nandcs = cs;
+ }
+ cs++;
+ }
+
+ if (nandcs > GPMC_CS_NUM) {
+ printk(KERN_INFO "NAND: Unable to find configuration "
+ "in GPMC\n ");
+ return;
+ }
+
+ if (nandcs < GPMC_CS_NUM) {
+ nand_data.cs = nandcs;
+ nand_data.parts = parts;
+ nand_data.nr_parts = nr_parts;
+ nand_data.options = options;
+
+ printk(KERN_INFO "Registering NAND on CS%d\n", nandcs);
+ if (gpmc_nand_init(&nand_data) < 0)
+ printk(KERN_ERR "Unable to register NAND device\n");
+ }
+}
+#else
+void __init omap_nand_flash_init(int options, struct mtd_partition *parts,
+ int nr_parts)
+{
+}
+#endif
diff --git a/arch/arm/mach-omap2/common-board-devices.h b/arch/arm/mach-omap2/common-board-devices.h
new file mode 100644
index 000000000000..eb80b3b0ef47
--- /dev/null
+++ b/arch/arm/mach-omap2/common-board-devices.h
@@ -0,0 +1,35 @@
+#ifndef __OMAP_COMMON_BOARD_DEVICES__
+#define __OMAP_COMMON_BOARD_DEVICES__
+
+struct twl4030_platform_data;
+struct mtd_partition;
+
+void omap_pmic_init(int bus, u32 clkrate, const char *pmic_type, int pmic_irq,
+ struct twl4030_platform_data *pmic_data);
+
+static inline void omap2_pmic_init(const char *pmic_type,
+ struct twl4030_platform_data *pmic_data)
+{
+ omap_pmic_init(2, 2600, pmic_type, INT_24XX_SYS_NIRQ, pmic_data);
+}
+
+static inline void omap3_pmic_init(const char *pmic_type,
+ struct twl4030_platform_data *pmic_data)
+{
+ omap_pmic_init(1, 2600, pmic_type, INT_34XX_SYS_NIRQ, pmic_data);
+}
+
+static inline void omap4_pmic_init(const char *pmic_type,
+ struct twl4030_platform_data *pmic_data)
+{
+ /* Phoenix Audio IC needs I2C1 to start with 400 KHz or less */
+ omap_pmic_init(1, 400, pmic_type, OMAP44XX_IRQ_SYS_1N, pmic_data);
+}
+
+struct ads7846_platform_data;
+
+void omap_ads7846_init(int bus_num, int gpio_pendown, int gpio_debounce,
+ struct ads7846_platform_data *board_pdata);
+void omap_nand_flash_init(int opts, struct mtd_partition *parts, int n_parts);
+
+#endif /* __OMAP_COMMON_BOARD_DEVICES__ */
diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h
index c2804c1c4efd..a016c8b59e00 100644
--- a/arch/arm/mach-omap2/control.h
+++ b/arch/arm/mach-omap2/control.h
@@ -236,7 +236,7 @@
#define OMAP343X_CONTROL_WKUP_DEBOBS3 (OMAP343X_CONTROL_GENERAL_WKUP + 0x014)
#define OMAP343X_CONTROL_WKUP_DEBOBS4 (OMAP343X_CONTROL_GENERAL_WKUP + 0x018)
-/* 36xx-only RTA - Retention till Accesss control registers and bits */
+/* 36xx-only RTA - Retention till Access control registers and bits */
#define OMAP36XX_CONTROL_MEM_RTA_CTRL 0x40C
#define OMAP36XX_RTA_DISABLE 0x0
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index 1c240eff3918..4bf6e6e8b100 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -36,36 +36,6 @@
#ifdef CONFIG_CPU_IDLE
-#define OMAP3_MAX_STATES 7
-#define OMAP3_STATE_C1 0 /* C1 - MPU WFI + Core active */
-#define OMAP3_STATE_C2 1 /* C2 - MPU WFI + Core inactive */
-#define OMAP3_STATE_C3 2 /* C3 - MPU CSWR + Core inactive */
-#define OMAP3_STATE_C4 3 /* C4 - MPU OFF + Core iactive */
-#define OMAP3_STATE_C5 4 /* C5 - MPU RET + Core RET */
-#define OMAP3_STATE_C6 5 /* C6 - MPU OFF + Core RET */
-#define OMAP3_STATE_C7 6 /* C7 - MPU OFF + Core OFF */
-
-#define OMAP3_STATE_MAX OMAP3_STATE_C7
-
-#define CPUIDLE_FLAG_CHECK_BM 0x10000 /* use omap3_enter_idle_bm() */
-
-struct omap3_processor_cx {
- u8 valid;
- u8 type;
- u32 sleep_latency;
- u32 wakeup_latency;
- u32 mpu_state;
- u32 core_state;
- u32 threshold;
- u32 flags;
- const char *desc;
-};
-
-struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES];
-struct omap3_processor_cx current_cx_state;
-struct powerdomain *mpu_pd, *core_pd, *per_pd;
-struct powerdomain *cam_pd;
-
/*
* The latencies/thresholds for various C states have
* to be configured from the respective board files.
@@ -75,27 +45,31 @@ struct powerdomain *cam_pd;
*/
static struct cpuidle_params cpuidle_params_table[] = {
/* C1 */
- {1, 2, 2, 5},
+ {2 + 2, 5, 1},
/* C2 */
- {1, 10, 10, 30},
+ {10 + 10, 30, 1},
/* C3 */
- {1, 50, 50, 300},
+ {50 + 50, 300, 1},
/* C4 */
- {1, 1500, 1800, 4000},
+ {1500 + 1800, 4000, 1},
/* C5 */
- {1, 2500, 7500, 12000},
+ {2500 + 7500, 12000, 1},
/* C6 */
- {1, 3000, 8500, 15000},
+ {3000 + 8500, 15000, 1},
/* C7 */
- {1, 10000, 30000, 300000},
+ {10000 + 30000, 300000, 1},
};
+#define OMAP3_NUM_STATES ARRAY_SIZE(cpuidle_params_table)
-static int omap3_idle_bm_check(void)
-{
- if (!omap3_can_sleep())
- return 1;
- return 0;
-}
+/* Mach specific information to be recorded in the C-state driver_data */
+struct omap3_idle_statedata {
+ u32 mpu_state;
+ u32 core_state;
+ u8 valid;
+};
+struct omap3_idle_statedata omap3_idle_data[OMAP3_NUM_STATES];
+
+struct powerdomain *mpu_pd, *core_pd, *per_pd, *cam_pd;
static int _cpuidle_allow_idle(struct powerdomain *pwrdm,
struct clockdomain *clkdm)
@@ -122,12 +96,10 @@ static int _cpuidle_deny_idle(struct powerdomain *pwrdm,
static int omap3_enter_idle(struct cpuidle_device *dev,
struct cpuidle_state *state)
{
- struct omap3_processor_cx *cx = cpuidle_get_statedata(state);
+ struct omap3_idle_statedata *cx = cpuidle_get_statedata(state);
struct timespec ts_preidle, ts_postidle, ts_idle;
u32 mpu_state = cx->mpu_state, core_state = cx->core_state;
- current_cx_state = *cx;
-
/* Used to keep track of the total time in idle */
getnstimeofday(&ts_preidle);
@@ -140,7 +112,8 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
if (omap_irq_pending() || need_resched())
goto return_sleep_time;
- if (cx->type == OMAP3_STATE_C1) {
+ /* Deny idle for C1 */
+ if (state == &dev->states[0]) {
pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle);
pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle);
}
@@ -148,7 +121,8 @@ static int omap3_enter_idle(struct cpuidle_device *dev,
/* Execute ARM wfi */
omap_sram_idle();
- if (cx->type == OMAP3_STATE_C1) {
+ /* Re-allow idle for C1 */
+ if (state == &dev->states[0]) {
pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle);
pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle);
}
@@ -164,41 +138,53 @@ return_sleep_time:
}
/**
- * next_valid_state - Find next valid c-state
+ * next_valid_state - Find next valid C-state
* @dev: cpuidle device
- * @state: Currently selected c-state
+ * @state: Currently selected C-state
*
* If the current state is valid, it is returned back to the caller.
* Else, this function searches for a lower c-state which is still
- * valid (as defined in omap3_power_states[]).
+ * valid.
+ *
+ * A state is valid if the 'valid' field is enabled and
+ * if it satisfies the enable_off_mode condition.
*/
static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
- struct cpuidle_state *curr)
+ struct cpuidle_state *curr)
{
struct cpuidle_state *next = NULL;
- struct omap3_processor_cx *cx;
+ struct omap3_idle_statedata *cx = cpuidle_get_statedata(curr);
+ u32 mpu_deepest_state = PWRDM_POWER_RET;
+ u32 core_deepest_state = PWRDM_POWER_RET;
- cx = (struct omap3_processor_cx *)cpuidle_get_statedata(curr);
+ if (enable_off_mode) {
+ mpu_deepest_state = PWRDM_POWER_OFF;
+ /*
+ * Erratum i583: valable for ES rev < Es1.2 on 3630.
+ * CORE OFF mode is not supported in a stable form, restrict
+ * instead the CORE state to RET.
+ */
+ if (!IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583))
+ core_deepest_state = PWRDM_POWER_OFF;
+ }
/* Check if current state is valid */
- if (cx->valid) {
+ if ((cx->valid) &&
+ (cx->mpu_state >= mpu_deepest_state) &&
+ (cx->core_state >= core_deepest_state)) {
return curr;
} else {
- u8 idx = OMAP3_STATE_MAX;
+ int idx = OMAP3_NUM_STATES - 1;
- /*
- * Reach the current state starting at highest C-state
- */
- for (; idx >= OMAP3_STATE_C1; idx--) {
+ /* Reach the current state starting at highest C-state */
+ for (; idx >= 0; idx--) {
if (&dev->states[idx] == curr) {
next = &dev->states[idx];
break;
}
}
- /*
- * Should never hit this condition.
- */
+ /* Should never hit this condition */
WARN_ON(next == NULL);
/*
@@ -206,17 +192,17 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
* Start search from the next (lower) state.
*/
idx--;
- for (; idx >= OMAP3_STATE_C1; idx--) {
- struct omap3_processor_cx *cx;
-
+ for (; idx >= 0; idx--) {
cx = cpuidle_get_statedata(&dev->states[idx]);
- if (cx->valid) {
+ if ((cx->valid) &&
+ (cx->mpu_state >= mpu_deepest_state) &&
+ (cx->core_state >= core_deepest_state)) {
next = &dev->states[idx];
break;
}
}
/*
- * C1 and C2 are always valid.
+ * C1 is always valid.
* So, no need to check for 'next==NULL' outside this loop.
*/
}
@@ -229,36 +215,22 @@ static struct cpuidle_state *next_valid_state(struct cpuidle_device *dev,
* @dev: cpuidle device
* @state: The target state to be programmed
*
- * Used for C states with CPUIDLE_FLAG_CHECK_BM flag set. This
- * function checks for any pending activity and then programs the
- * device to the specified or a safer state.
+ * This function checks for any pending activity and then programs
+ * the device to the specified or a safer state.
*/
static int omap3_enter_idle_bm(struct cpuidle_device *dev,
struct cpuidle_state *state)
{
- struct cpuidle_state *new_state = next_valid_state(dev, state);
- u32 core_next_state, per_next_state = 0, per_saved_state = 0;
- u32 cam_state;
- struct omap3_processor_cx *cx;
+ struct cpuidle_state *new_state;
+ u32 core_next_state, per_next_state = 0, per_saved_state = 0, cam_state;
+ struct omap3_idle_statedata *cx;
int ret;
- if ((state->flags & CPUIDLE_FLAG_CHECK_BM) && omap3_idle_bm_check()) {
- BUG_ON(!dev->safe_state);
+ if (!omap3_can_sleep()) {
new_state = dev->safe_state;
goto select_state;
}
- cx = cpuidle_get_statedata(state);
- core_next_state = cx->core_state;
-
- /*
- * FIXME: we currently manage device-specific idle states
- * for PER and CORE in combination with CPU-specific
- * idle states. This is wrong, and device-specific
- * idle management needs to be separated out into
- * its own code.
- */
-
/*
* Prevent idle completely if CAM is active.
* CAM does not have wakeup capability in OMAP3.
@@ -270,9 +242,19 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
}
/*
+ * FIXME: we currently manage device-specific idle states
+ * for PER and CORE in combination with CPU-specific
+ * idle states. This is wrong, and device-specific
+ * idle management needs to be separated out into
+ * its own code.
+ */
+
+ /*
* Prevent PER off if CORE is not in retention or off as this
* would disable PER wakeups completely.
*/
+ cx = cpuidle_get_statedata(state);
+ core_next_state = cx->core_state;
per_next_state = per_saved_state = pwrdm_read_next_pwrst(per_pd);
if ((per_next_state == PWRDM_POWER_OFF) &&
(core_next_state > PWRDM_POWER_RET))
@@ -282,6 +264,8 @@ static int omap3_enter_idle_bm(struct cpuidle_device *dev,
if (per_next_state != per_saved_state)
pwrdm_set_next_pwrst(per_pd, per_next_state);
+ new_state = next_valid_state(dev, state);
+
select_state:
dev->last_state = new_state;
ret = omap3_enter_idle(dev, new_state);
@@ -295,31 +279,6 @@ select_state:
DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev);
-/**
- * omap3_cpuidle_update_states() - Update the cpuidle states
- * @mpu_deepest_state: Enable states up to and including this for mpu domain
- * @core_deepest_state: Enable states up to and including this for core domain
- *
- * This goes through the list of states available and enables and disables the
- * validity of C states based on deepest state that can be achieved for the
- * variable domain
- */
-void omap3_cpuidle_update_states(u32 mpu_deepest_state, u32 core_deepest_state)
-{
- int i;
-
- for (i = OMAP3_STATE_C1; i < OMAP3_MAX_STATES; i++) {
- struct omap3_processor_cx *cx = &omap3_power_states[i];
-
- if ((cx->mpu_state >= mpu_deepest_state) &&
- (cx->core_state >= core_deepest_state)) {
- cx->valid = 1;
- } else {
- cx->valid = 0;
- }
- }
-}
-
void omap3_pm_init_cpuidle(struct cpuidle_params *cpuidle_board_params)
{
int i;
@@ -327,212 +286,109 @@ void omap3_pm_init_cpuidle(struct cpuidle_params *cpuidle_board_params)
if (!cpuidle_board_params)
return;
- for (i = OMAP3_STATE_C1; i < OMAP3_MAX_STATES; i++) {
- cpuidle_params_table[i].valid =
- cpuidle_board_params[i].valid;
- cpuidle_params_table[i].sleep_latency =
- cpuidle_board_params[i].sleep_latency;
- cpuidle_params_table[i].wake_latency =
- cpuidle_board_params[i].wake_latency;
- cpuidle_params_table[i].threshold =
- cpuidle_board_params[i].threshold;
+ for (i = 0; i < OMAP3_NUM_STATES; i++) {
+ cpuidle_params_table[i].valid = cpuidle_board_params[i].valid;
+ cpuidle_params_table[i].exit_latency =
+ cpuidle_board_params[i].exit_latency;
+ cpuidle_params_table[i].target_residency =
+ cpuidle_board_params[i].target_residency;
}
return;
}
-/* omap3_init_power_states - Initialises the OMAP3 specific C states.
- *
- * Below is the desciption of each C state.
- * C1 . MPU WFI + Core active
- * C2 . MPU WFI + Core inactive
- * C3 . MPU CSWR + Core inactive
- * C4 . MPU OFF + Core inactive
- * C5 . MPU CSWR + Core CSWR
- * C6 . MPU OFF + Core CSWR
- * C7 . MPU OFF + Core OFF
- */
-void omap_init_power_states(void)
-{
- /* C1 . MPU WFI + Core active */
- omap3_power_states[OMAP3_STATE_C1].valid =
- cpuidle_params_table[OMAP3_STATE_C1].valid;
- omap3_power_states[OMAP3_STATE_C1].type = OMAP3_STATE_C1;
- omap3_power_states[OMAP3_STATE_C1].sleep_latency =
- cpuidle_params_table[OMAP3_STATE_C1].sleep_latency;
- omap3_power_states[OMAP3_STATE_C1].wakeup_latency =
- cpuidle_params_table[OMAP3_STATE_C1].wake_latency;
- omap3_power_states[OMAP3_STATE_C1].threshold =
- cpuidle_params_table[OMAP3_STATE_C1].threshold;
- omap3_power_states[OMAP3_STATE_C1].mpu_state = PWRDM_POWER_ON;
- omap3_power_states[OMAP3_STATE_C1].core_state = PWRDM_POWER_ON;
- omap3_power_states[OMAP3_STATE_C1].flags = CPUIDLE_FLAG_TIME_VALID;
- omap3_power_states[OMAP3_STATE_C1].desc = "MPU ON + CORE ON";
-
- /* C2 . MPU WFI + Core inactive */
- omap3_power_states[OMAP3_STATE_C2].valid =
- cpuidle_params_table[OMAP3_STATE_C2].valid;
- omap3_power_states[OMAP3_STATE_C2].type = OMAP3_STATE_C2;
- omap3_power_states[OMAP3_STATE_C2].sleep_latency =
- cpuidle_params_table[OMAP3_STATE_C2].sleep_latency;
- omap3_power_states[OMAP3_STATE_C2].wakeup_latency =
- cpuidle_params_table[OMAP3_STATE_C2].wake_latency;
- omap3_power_states[OMAP3_STATE_C2].threshold =
- cpuidle_params_table[OMAP3_STATE_C2].threshold;
- omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_ON;
- omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_ON;
- omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID |
- CPUIDLE_FLAG_CHECK_BM;
- omap3_power_states[OMAP3_STATE_C2].desc = "MPU ON + CORE ON";
-
- /* C3 . MPU CSWR + Core inactive */
- omap3_power_states[OMAP3_STATE_C3].valid =
- cpuidle_params_table[OMAP3_STATE_C3].valid;
- omap3_power_states[OMAP3_STATE_C3].type = OMAP3_STATE_C3;
- omap3_power_states[OMAP3_STATE_C3].sleep_latency =
- cpuidle_params_table[OMAP3_STATE_C3].sleep_latency;
- omap3_power_states[OMAP3_STATE_C3].wakeup_latency =
- cpuidle_params_table[OMAP3_STATE_C3].wake_latency;
- omap3_power_states[OMAP3_STATE_C3].threshold =
- cpuidle_params_table[OMAP3_STATE_C3].threshold;
- omap3_power_states[OMAP3_STATE_C3].mpu_state = PWRDM_POWER_RET;
- omap3_power_states[OMAP3_STATE_C3].core_state = PWRDM_POWER_ON;
- omap3_power_states[OMAP3_STATE_C3].flags = CPUIDLE_FLAG_TIME_VALID |
- CPUIDLE_FLAG_CHECK_BM;
- omap3_power_states[OMAP3_STATE_C3].desc = "MPU RET + CORE ON";
-
- /* C4 . MPU OFF + Core inactive */
- omap3_power_states[OMAP3_STATE_C4].valid =
- cpuidle_params_table[OMAP3_STATE_C4].valid;
- omap3_power_states[OMAP3_STATE_C4].type = OMAP3_STATE_C4;
- omap3_power_states[OMAP3_STATE_C4].sleep_latency =
- cpuidle_params_table[OMAP3_STATE_C4].sleep_latency;
- omap3_power_states[OMAP3_STATE_C4].wakeup_latency =
- cpuidle_params_table[OMAP3_STATE_C4].wake_latency;
- omap3_power_states[OMAP3_STATE_C4].threshold =
- cpuidle_params_table[OMAP3_STATE_C4].threshold;
- omap3_power_states[OMAP3_STATE_C4].mpu_state = PWRDM_POWER_OFF;
- omap3_power_states[OMAP3_STATE_C4].core_state = PWRDM_POWER_ON;
- omap3_power_states[OMAP3_STATE_C4].flags = CPUIDLE_FLAG_TIME_VALID |
- CPUIDLE_FLAG_CHECK_BM;
- omap3_power_states[OMAP3_STATE_C4].desc = "MPU OFF + CORE ON";
-
- /* C5 . MPU CSWR + Core CSWR*/
- omap3_power_states[OMAP3_STATE_C5].valid =
- cpuidle_params_table[OMAP3_STATE_C5].valid;
- omap3_power_states[OMAP3_STATE_C5].type = OMAP3_STATE_C5;
- omap3_power_states[OMAP3_STATE_C5].sleep_latency =
- cpuidle_params_table[OMAP3_STATE_C5].sleep_latency;
- omap3_power_states[OMAP3_STATE_C5].wakeup_latency =
- cpuidle_params_table[OMAP3_STATE_C5].wake_latency;
- omap3_power_states[OMAP3_STATE_C5].threshold =
- cpuidle_params_table[OMAP3_STATE_C5].threshold;
- omap3_power_states[OMAP3_STATE_C5].mpu_state = PWRDM_POWER_RET;
- omap3_power_states[OMAP3_STATE_C5].core_state = PWRDM_POWER_RET;
- omap3_power_states[OMAP3_STATE_C5].flags = CPUIDLE_FLAG_TIME_VALID |
- CPUIDLE_FLAG_CHECK_BM;
- omap3_power_states[OMAP3_STATE_C5].desc = "MPU RET + CORE RET";
-
- /* C6 . MPU OFF + Core CSWR */
- omap3_power_states[OMAP3_STATE_C6].valid =
- cpuidle_params_table[OMAP3_STATE_C6].valid;
- omap3_power_states[OMAP3_STATE_C6].type = OMAP3_STATE_C6;
- omap3_power_states[OMAP3_STATE_C6].sleep_latency =
- cpuidle_params_table[OMAP3_STATE_C6].sleep_latency;
- omap3_power_states[OMAP3_STATE_C6].wakeup_latency =
- cpuidle_params_table[OMAP3_STATE_C6].wake_latency;
- omap3_power_states[OMAP3_STATE_C6].threshold =
- cpuidle_params_table[OMAP3_STATE_C6].threshold;
- omap3_power_states[OMAP3_STATE_C6].mpu_state = PWRDM_POWER_OFF;
- omap3_power_states[OMAP3_STATE_C6].core_state = PWRDM_POWER_RET;
- omap3_power_states[OMAP3_STATE_C6].flags = CPUIDLE_FLAG_TIME_VALID |
- CPUIDLE_FLAG_CHECK_BM;
- omap3_power_states[OMAP3_STATE_C6].desc = "MPU OFF + CORE RET";
-
- /* C7 . MPU OFF + Core OFF */
- omap3_power_states[OMAP3_STATE_C7].valid =
- cpuidle_params_table[OMAP3_STATE_C7].valid;
- omap3_power_states[OMAP3_STATE_C7].type = OMAP3_STATE_C7;
- omap3_power_states[OMAP3_STATE_C7].sleep_latency =
- cpuidle_params_table[OMAP3_STATE_C7].sleep_latency;
- omap3_power_states[OMAP3_STATE_C7].wakeup_latency =
- cpuidle_params_table[OMAP3_STATE_C7].wake_latency;
- omap3_power_states[OMAP3_STATE_C7].threshold =
- cpuidle_params_table[OMAP3_STATE_C7].threshold;
- omap3_power_states[OMAP3_STATE_C7].mpu_state = PWRDM_POWER_OFF;
- omap3_power_states[OMAP3_STATE_C7].core_state = PWRDM_POWER_OFF;
- omap3_power_states[OMAP3_STATE_C7].flags = CPUIDLE_FLAG_TIME_VALID |
- CPUIDLE_FLAG_CHECK_BM;
- omap3_power_states[OMAP3_STATE_C7].desc = "MPU OFF + CORE OFF";
-
- /*
- * Erratum i583: implementation for ES rev < Es1.2 on 3630. We cannot
- * enable OFF mode in a stable form for previous revisions.
- * we disable C7 state as a result.
- */
- if (IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583)) {
- omap3_power_states[OMAP3_STATE_C7].valid = 0;
- cpuidle_params_table[OMAP3_STATE_C7].valid = 0;
- pr_warn("%s: core off state C7 disabled due to i583\n",
- __func__);
- }
-}
-
struct cpuidle_driver omap3_idle_driver = {
.name = "omap3_idle",
.owner = THIS_MODULE,
};
+/* Helper to fill the C-state common data and register the driver_data */
+static inline struct omap3_idle_statedata *_fill_cstate(
+ struct cpuidle_device *dev,
+ int idx, const char *descr)
+{
+ struct omap3_idle_statedata *cx = &omap3_idle_data[idx];
+ struct cpuidle_state *state = &dev->states[idx];
+
+ state->exit_latency = cpuidle_params_table[idx].exit_latency;
+ state->target_residency = cpuidle_params_table[idx].target_residency;
+ state->flags = CPUIDLE_FLAG_TIME_VALID;
+ state->enter = omap3_enter_idle_bm;
+ cx->valid = cpuidle_params_table[idx].valid;
+ sprintf(state->name, "C%d", idx + 1);
+ strncpy(state->desc, descr, CPUIDLE_DESC_LEN);
+ cpuidle_set_statedata(state, cx);
+
+ return cx;
+}
+
/**
* omap3_idle_init - Init routine for OMAP3 idle
*
- * Registers the OMAP3 specific cpuidle driver with the cpuidle
+ * Registers the OMAP3 specific cpuidle driver to the cpuidle
* framework with the valid set of states.
*/
int __init omap3_idle_init(void)
{
- int i, count = 0;
- struct omap3_processor_cx *cx;
- struct cpuidle_state *state;
struct cpuidle_device *dev;
+ struct omap3_idle_statedata *cx;
mpu_pd = pwrdm_lookup("mpu_pwrdm");
core_pd = pwrdm_lookup("core_pwrdm");
per_pd = pwrdm_lookup("per_pwrdm");
cam_pd = pwrdm_lookup("cam_pwrdm");
- omap_init_power_states();
cpuidle_register_driver(&omap3_idle_driver);
-
dev = &per_cpu(omap3_idle_dev, smp_processor_id());
- for (i = OMAP3_STATE_C1; i < OMAP3_MAX_STATES; i++) {
- cx = &omap3_power_states[i];
- state = &dev->states[count];
-
- if (!cx->valid)
- continue;
- cpuidle_set_statedata(state, cx);
- state->exit_latency = cx->sleep_latency + cx->wakeup_latency;
- state->target_residency = cx->threshold;
- state->flags = cx->flags;
- state->enter = (state->flags & CPUIDLE_FLAG_CHECK_BM) ?
- omap3_enter_idle_bm : omap3_enter_idle;
- if (cx->type == OMAP3_STATE_C1)
- dev->safe_state = state;
- sprintf(state->name, "C%d", count+1);
- strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN);
- count++;
- }
+ /* C1 . MPU WFI + Core active */
+ cx = _fill_cstate(dev, 0, "MPU ON + CORE ON");
+ (&dev->states[0])->enter = omap3_enter_idle;
+ dev->safe_state = &dev->states[0];
+ cx->valid = 1; /* C1 is always valid */
+ cx->mpu_state = PWRDM_POWER_ON;
+ cx->core_state = PWRDM_POWER_ON;
- if (!count)
- return -EINVAL;
- dev->state_count = count;
+ /* C2 . MPU WFI + Core inactive */
+ cx = _fill_cstate(dev, 1, "MPU ON + CORE ON");
+ cx->mpu_state = PWRDM_POWER_ON;
+ cx->core_state = PWRDM_POWER_ON;
+
+ /* C3 . MPU CSWR + Core inactive */
+ cx = _fill_cstate(dev, 2, "MPU RET + CORE ON");
+ cx->mpu_state = PWRDM_POWER_RET;
+ cx->core_state = PWRDM_POWER_ON;
- if (enable_off_mode)
- omap3_cpuidle_update_states(PWRDM_POWER_OFF, PWRDM_POWER_OFF);
- else
- omap3_cpuidle_update_states(PWRDM_POWER_RET, PWRDM_POWER_RET);
+ /* C4 . MPU OFF + Core inactive */
+ cx = _fill_cstate(dev, 3, "MPU OFF + CORE ON");
+ cx->mpu_state = PWRDM_POWER_OFF;
+ cx->core_state = PWRDM_POWER_ON;
+
+ /* C5 . MPU RET + Core RET */
+ cx = _fill_cstate(dev, 4, "MPU RET + CORE RET");
+ cx->mpu_state = PWRDM_POWER_RET;
+ cx->core_state = PWRDM_POWER_RET;
+
+ /* C6 . MPU OFF + Core RET */
+ cx = _fill_cstate(dev, 5, "MPU OFF + CORE RET");
+ cx->mpu_state = PWRDM_POWER_OFF;
+ cx->core_state = PWRDM_POWER_RET;
+
+ /* C7 . MPU OFF + Core OFF */
+ cx = _fill_cstate(dev, 6, "MPU OFF + CORE OFF");
+ /*
+ * Erratum i583: implementation for ES rev < Es1.2 on 3630. We cannot
+ * enable OFF mode in a stable form for previous revisions.
+ * We disable C7 state as a result.
+ */
+ if (IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583)) {
+ cx->valid = 0;
+ pr_warn("%s: core off state C7 disabled due to i583\n",
+ __func__);
+ }
+ cx->mpu_state = PWRDM_POWER_OFF;
+ cx->core_state = PWRDM_POWER_OFF;
+ dev->state_count = OMAP3_NUM_STATES;
if (cpuidle_register_device(dev)) {
printk(KERN_ERR "%s: CPUidle register device failed\n",
__func__);
diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c
index 256d23fb79ab..543fcb8b518c 100644
--- a/arch/arm/mach-omap2/display.c
+++ b/arch/arm/mach-omap2/display.c
@@ -22,7 +22,7 @@
#include <linux/clk.h>
#include <linux/err.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
#include <plat/omap_hwmod.h>
#include <plat/omap_device.h>
@@ -56,37 +56,58 @@ static bool opt_clock_available(const char *clk_role)
return false;
}
+struct omap_dss_hwmod_data {
+ const char *oh_name;
+ const char *dev_name;
+ const int id;
+};
+
+static const struct omap_dss_hwmod_data omap2_dss_hwmod_data[] __initdata = {
+ { "dss_core", "omapdss_dss", -1 },
+ { "dss_dispc", "omapdss_dispc", -1 },
+ { "dss_rfbi", "omapdss_rfbi", -1 },
+ { "dss_venc", "omapdss_venc", -1 },
+};
+
+static const struct omap_dss_hwmod_data omap3_dss_hwmod_data[] __initdata = {
+ { "dss_core", "omapdss_dss", -1 },
+ { "dss_dispc", "omapdss_dispc", -1 },
+ { "dss_rfbi", "omapdss_rfbi", -1 },
+ { "dss_venc", "omapdss_venc", -1 },
+ { "dss_dsi1", "omapdss_dsi1", -1 },
+};
+
+static const struct omap_dss_hwmod_data omap4_dss_hwmod_data[] __initdata = {
+ { "dss_core", "omapdss_dss", -1 },
+ { "dss_dispc", "omapdss_dispc", -1 },
+ { "dss_rfbi", "omapdss_rfbi", -1 },
+ { "dss_venc", "omapdss_venc", -1 },
+ { "dss_dsi1", "omapdss_dsi1", -1 },
+ { "dss_dsi2", "omapdss_dsi2", -1 },
+ { "dss_hdmi", "omapdss_hdmi", -1 },
+};
+
int __init omap_display_init(struct omap_dss_board_info *board_data)
{
int r = 0;
struct omap_hwmod *oh;
struct omap_device *od;
- int i;
+ int i, oh_count;
struct omap_display_platform_data pdata;
-
- /*
- * omap: valid DSS hwmod names
- * omap2,3,4: dss_core, dss_dispc, dss_rfbi, dss_venc
- * omap3,4: dss_dsi1
- * omap4: dss_dsi2, dss_hdmi
- */
- char *oh_name[] = { "dss_core", "dss_dispc", "dss_rfbi", "dss_venc",
- "dss_dsi1", "dss_dsi2", "dss_hdmi" };
- char *dev_name[] = { "omapdss_dss", "omapdss_dispc", "omapdss_rfbi",
- "omapdss_venc", "omapdss_dsi1", "omapdss_dsi2",
- "omapdss_hdmi" };
- int oh_count;
+ const struct omap_dss_hwmod_data *curr_dss_hwmod;
memset(&pdata, 0, sizeof(pdata));
- if (cpu_is_omap24xx())
- oh_count = ARRAY_SIZE(oh_name) - 3;
- /* last 3 hwmod dev in oh_name are not available for omap2 */
- else if (cpu_is_omap44xx())
- oh_count = ARRAY_SIZE(oh_name);
- else
- oh_count = ARRAY_SIZE(oh_name) - 2;
- /* last 2 hwmod dev in oh_name are not available for omap3 */
+ if (cpu_is_omap24xx()) {
+ curr_dss_hwmod = omap2_dss_hwmod_data;
+ oh_count = ARRAY_SIZE(omap2_dss_hwmod_data);
+ } else if (cpu_is_omap34xx()) {
+ curr_dss_hwmod = omap3_dss_hwmod_data;
+ oh_count = ARRAY_SIZE(omap3_dss_hwmod_data);
+ } else {
+ curr_dss_hwmod = omap4_dss_hwmod_data;
+ oh_count = ARRAY_SIZE(omap4_dss_hwmod_data);
+ }
/* opt_clks are always associated with dss hwmod */
oh_core = omap_hwmod_lookup("dss_core");
@@ -100,19 +121,21 @@ int __init omap_display_init(struct omap_dss_board_info *board_data)
pdata.opt_clock_available = opt_clock_available;
for (i = 0; i < oh_count; i++) {
- oh = omap_hwmod_lookup(oh_name[i]);
+ oh = omap_hwmod_lookup(curr_dss_hwmod[i].oh_name);
if (!oh) {
- pr_err("Could not look up %s\n", oh_name[i]);
+ pr_err("Could not look up %s\n",
+ curr_dss_hwmod[i].oh_name);
return -ENODEV;
}
- od = omap_device_build(dev_name[i], -1, oh, &pdata,
+ od = omap_device_build(curr_dss_hwmod[i].dev_name,
+ curr_dss_hwmod[i].id, oh, &pdata,
sizeof(struct omap_display_platform_data),
omap_dss_latency,
ARRAY_SIZE(omap_dss_latency), 0);
if (WARN((IS_ERR(od)), "Could not build omap_device for %s\n",
- oh_name[i]))
+ curr_dss_hwmod[i].oh_name))
return -ENODEV;
}
omap_display_device.dev.platform_data = board_data;
diff --git a/arch/arm/mach-omap2/gpmc-smc91x.c b/arch/arm/mach-omap2/gpmc-smc91x.c
index 877c6f5807b7..ba10c24f3d8d 100644
--- a/arch/arm/mach-omap2/gpmc-smc91x.c
+++ b/arch/arm/mach-omap2/gpmc-smc91x.c
@@ -147,25 +147,24 @@ void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data)
goto free1;
}
- if (gpio_request(gpmc_cfg->gpio_irq, "SMC91X irq") < 0)
+ if (gpio_request_one(gpmc_cfg->gpio_irq, GPIOF_IN, "SMC91X irq") < 0)
goto free1;
- gpio_direction_input(gpmc_cfg->gpio_irq);
gpmc_smc91x_resources[1].start = gpio_to_irq(gpmc_cfg->gpio_irq);
if (gpmc_cfg->gpio_pwrdwn) {
- ret = gpio_request(gpmc_cfg->gpio_pwrdwn, "SMC91X powerdown");
+ ret = gpio_request_one(gpmc_cfg->gpio_pwrdwn,
+ GPIOF_OUT_INIT_LOW, "SMC91X powerdown");
if (ret)
goto free2;
- gpio_direction_output(gpmc_cfg->gpio_pwrdwn, 0);
}
if (gpmc_cfg->gpio_reset) {
- ret = gpio_request(gpmc_cfg->gpio_reset, "SMC91X reset");
+ ret = gpio_request_one(gpmc_cfg->gpio_reset,
+ GPIOF_OUT_INIT_LOW, "SMC91X reset");
if (ret)
goto free3;
- gpio_direction_output(gpmc_cfg->gpio_reset, 0);
gpio_set_value(gpmc_cfg->gpio_reset, 1);
msleep(100);
gpio_set_value(gpmc_cfg->gpio_reset, 0);
diff --git a/arch/arm/mach-omap2/gpmc-smsc911x.c b/arch/arm/mach-omap2/gpmc-smsc911x.c
index 703f150dd01d..997033129d26 100644
--- a/arch/arm/mach-omap2/gpmc-smsc911x.c
+++ b/arch/arm/mach-omap2/gpmc-smsc911x.c
@@ -10,6 +10,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/kernel.h>
#include <linux/platform_device.h>
@@ -30,7 +31,7 @@ static struct resource gpmc_smsc911x_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .flags = IORESOURCE_IRQ,
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
},
};
@@ -41,16 +42,6 @@ static struct smsc911x_platform_config gpmc_smsc911x_config = {
.flags = SMSC911X_USE_16BIT,
};
-static struct platform_device gpmc_smsc911x_device = {
- .name = "smsc911x",
- .id = -1,
- .num_resources = ARRAY_SIZE(gpmc_smsc911x_resources),
- .resource = gpmc_smsc911x_resources,
- .dev = {
- .platform_data = &gpmc_smsc911x_config,
- },
-};
-
/*
* Initialize smsc911x device connected to the GPMC. Note that we
* assume that pin multiplexing is done in the board-*.c file,
@@ -58,46 +49,49 @@ static struct platform_device gpmc_smsc911x_device = {
*/
void __init gpmc_smsc911x_init(struct omap_smsc911x_platform_data *board_data)
{
+ struct platform_device *pdev;
unsigned long cs_mem_base;
int ret;
gpmc_cfg = board_data;
if (gpmc_cs_request(gpmc_cfg->cs, SZ_16M, &cs_mem_base) < 0) {
- printk(KERN_ERR "Failed to request GPMC mem for smsc911x\n");
+ pr_err("Failed to request GPMC mem region\n");
return;
}
gpmc_smsc911x_resources[0].start = cs_mem_base + 0x0;
gpmc_smsc911x_resources[0].end = cs_mem_base + 0xff;
- if (gpio_request(gpmc_cfg->gpio_irq, "smsc911x irq") < 0) {
- printk(KERN_ERR "Failed to request GPIO%d for smsc911x IRQ\n",
- gpmc_cfg->gpio_irq);
+ if (gpio_request_one(gpmc_cfg->gpio_irq, GPIOF_IN, "smsc911x irq")) {
+ pr_err("Failed to request IRQ GPIO%d\n", gpmc_cfg->gpio_irq);
goto free1;
}
- gpio_direction_input(gpmc_cfg->gpio_irq);
gpmc_smsc911x_resources[1].start = gpio_to_irq(gpmc_cfg->gpio_irq);
- gpmc_smsc911x_resources[1].flags |=
- (gpmc_cfg->flags & IRQF_TRIGGER_MASK);
if (gpio_is_valid(gpmc_cfg->gpio_reset)) {
- ret = gpio_request(gpmc_cfg->gpio_reset, "smsc911x reset");
+ ret = gpio_request_one(gpmc_cfg->gpio_reset,
+ GPIOF_OUT_INIT_HIGH, "smsc911x reset");
if (ret) {
- printk(KERN_ERR "Failed to request GPIO%d for smsc911x reset\n",
- gpmc_cfg->gpio_reset);
+ pr_err("Failed to request reset GPIO%d\n",
+ gpmc_cfg->gpio_reset);
goto free2;
}
- gpio_direction_output(gpmc_cfg->gpio_reset, 1);
gpio_set_value(gpmc_cfg->gpio_reset, 0);
msleep(100);
gpio_set_value(gpmc_cfg->gpio_reset, 1);
}
- if (platform_device_register(&gpmc_smsc911x_device) < 0) {
- printk(KERN_ERR "Unable to register smsc911x device\n");
+ if (gpmc_cfg->flags)
+ gpmc_smsc911x_config.flags = gpmc_cfg->flags;
+
+ pdev = platform_device_register_resndata(NULL, "smsc911x", gpmc_cfg->id,
+ gpmc_smsc911x_resources, ARRAY_SIZE(gpmc_smsc911x_resources),
+ &gpmc_smsc911x_config, sizeof(gpmc_smsc911x_config));
+ if (!pdev) {
+ pr_err("Unable to register platform device\n");
gpio_free(gpmc_cfg->gpio_reset);
goto free2;
}
@@ -109,5 +103,5 @@ free2:
free1:
gpmc_cs_free(gpmc_cfg->cs);
- printk(KERN_ERR "Could not initialize smsc911x\n");
+ pr_err("Could not initialize smsc911x device\n");
}
diff --git a/arch/arm/mach-omap2/include/mach/board-zoom.h b/arch/arm/mach-omap2/include/mach/board-zoom.h
index d20bd9c1a106..775fdc3b000b 100644
--- a/arch/arm/mach-omap2/include/mach/board-zoom.h
+++ b/arch/arm/mach-omap2/include/mach/board-zoom.h
@@ -1,7 +1,7 @@
/*
* Defines for zoom boards
*/
-#include <plat/display.h>
+#include <video/omapdss.h>
#define ZOOM_NAND_CS 0
diff --git a/arch/arm/mach-omap2/include/mach/omap4-common.h b/arch/arm/mach-omap2/include/mach/omap4-common.h
index de441c05a6a6..e4bd87619734 100644
--- a/arch/arm/mach-omap2/include/mach/omap4-common.h
+++ b/arch/arm/mach-omap2/include/mach/omap4-common.h
@@ -33,4 +33,11 @@ extern void __iomem *gic_dist_base_addr;
extern void __init gic_init_irq(void);
extern void omap_smc1(u32 fn, u32 arg);
+#ifdef CONFIG_SMP
+/* Needed for secondary core boot */
+extern void omap_secondary_startup(void);
+extern u32 omap_modify_auxcoreboot0(u32 set_mask, u32 clear_mask);
+extern void omap_auxcoreboot_addr(u32 cpu_addr);
+extern u32 omap_read_auxcoreboot0(void);
+#endif
#endif
diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
index 237e4530abf2..3af2b7a1045e 100644
--- a/arch/arm/mach-omap2/irq.c
+++ b/arch/arm/mach-omap2/irq.c
@@ -73,83 +73,18 @@ static u32 intc_bank_read_reg(struct omap_irq_bank *bank, u16 reg)
return __raw_readl(bank->base_reg + reg);
}
-static int previous_irq;
-
-/*
- * On 34xx we can get occasional spurious interrupts if the ack from
- * an interrupt handler does not get posted before we unmask. Warn about
- * the interrupt handlers that need to flush posted writes.
- */
-static int omap_check_spurious(unsigned int irq)
-{
- u32 sir, spurious;
-
- sir = intc_bank_read_reg(&irq_banks[0], INTC_SIR);
- spurious = sir >> 7;
-
- if (spurious) {
- printk(KERN_WARNING "Spurious irq %i: 0x%08x, please flush "
- "posted write for irq %i\n",
- irq, sir, previous_irq);
- return spurious;
- }
-
- return 0;
-}
-
/* XXX: FIQ and additional INTC support (only MPU at the moment) */
static void omap_ack_irq(struct irq_data *d)
{
intc_bank_write_reg(0x1, &irq_banks[0], INTC_CONTROL);
}
-static void omap_mask_irq(struct irq_data *d)
-{
- unsigned int irq = d->irq;
- int offset = irq & (~(IRQ_BITS_PER_REG - 1));
-
- if (cpu_is_omap34xx() && !cpu_is_ti816x()) {
- int spurious = 0;
-
- /*
- * INT_34XX_GPT12_IRQ is also the spurious irq. Maybe because
- * it is the highest irq number?
- */
- if (irq == INT_34XX_GPT12_IRQ)
- spurious = omap_check_spurious(irq);
-
- if (!spurious)
- previous_irq = irq;
- }
-
- irq &= (IRQ_BITS_PER_REG - 1);
-
- intc_bank_write_reg(1 << irq, &irq_banks[0], INTC_MIR_SET0 + offset);
-}
-
-static void omap_unmask_irq(struct irq_data *d)
-{
- unsigned int irq = d->irq;
- int offset = irq & (~(IRQ_BITS_PER_REG - 1));
-
- irq &= (IRQ_BITS_PER_REG - 1);
-
- intc_bank_write_reg(1 << irq, &irq_banks[0], INTC_MIR_CLEAR0 + offset);
-}
-
static void omap_mask_ack_irq(struct irq_data *d)
{
- omap_mask_irq(d);
+ irq_gc_mask_disable_reg(d);
omap_ack_irq(d);
}
-static struct irq_chip omap_irq_chip = {
- .name = "INTC",
- .irq_ack = omap_mask_ack_irq,
- .irq_mask = omap_mask_irq,
- .irq_unmask = omap_unmask_irq,
-};
-
static void __init omap_irq_bank_init_one(struct omap_irq_bank *bank)
{
unsigned long tmp;
@@ -186,11 +121,31 @@ int omap_irq_pending(void)
return 0;
}
+static __init void
+omap_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num)
+{
+ struct irq_chip_generic *gc;
+ struct irq_chip_type *ct;
+
+ gc = irq_alloc_generic_chip("INTC", 1, irq_start, base,
+ handle_level_irq);
+ ct = gc->chip_types;
+ ct->chip.irq_ack = omap_mask_ack_irq;
+ ct->chip.irq_mask = irq_gc_mask_disable_reg;
+ ct->chip.irq_unmask = irq_gc_unmask_enable_reg;
+
+ ct->regs.ack = INTC_CONTROL;
+ ct->regs.enable = INTC_MIR_CLEAR0;
+ ct->regs.disable = INTC_MIR_SET0;
+ irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
+ IRQ_NOREQUEST | IRQ_NOPROBE, 0);
+}
+
void __init omap_init_irq(void)
{
unsigned long nr_of_irqs = 0;
unsigned int nr_banks = 0;
- int i;
+ int i, j;
for (i = 0; i < ARRAY_SIZE(irq_banks); i++) {
unsigned long base = 0;
@@ -215,17 +170,15 @@ void __init omap_init_irq(void)
omap_irq_bank_init_one(bank);
+ for (i = 0, j = 0; i < bank->nr_irqs; i += 32, j += 0x20)
+ omap_alloc_gc(bank->base_reg + j, i, 32);
+
nr_of_irqs += bank->nr_irqs;
nr_banks++;
}
printk(KERN_INFO "Total of %ld interrupts on %d active controller%s\n",
nr_of_irqs, nr_banks, nr_banks > 1 ? "s" : "");
-
- for (i = 0; i < nr_of_irqs; i++) {
- irq_set_chip_and_handler(i, &omap_irq_chip, handle_level_irq);
- set_irq_flags(i, IRQF_VALID);
- }
}
#ifdef CONFIG_ARCH_OMAP3
diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c
index b66cfe8bc464..ecfe93c4b585 100644
--- a/arch/arm/mach-omap2/omap-smp.c
+++ b/arch/arm/mach-omap2/omap-smp.c
@@ -21,6 +21,7 @@
#include <linux/io.h>
#include <asm/cacheflush.h>
+#include <asm/hardware/gic.h>
#include <asm/smp_scu.h>
#include <mach/hardware.h>
#include <mach/omap4-common.h>
@@ -63,7 +64,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
omap_modify_auxcoreboot0(0x200, 0xfffffdff);
flush_cache_all();
smp_wmb();
- smp_cross_call(cpumask_of(cpu), 1);
+ gic_raise_softirq(cpumask_of(cpu), 1);
/*
* Now the secondary core is starting up let it run its
@@ -118,6 +119,8 @@ void __init smp_init_cpus(void)
for (i = 0; i < ncores; i++)
set_cpu_possible(i, true);
+
+ set_smp_cross_call(gic_raise_softirq);
}
void __init platform_smp_prepare_cpus(unsigned int max_cpus)
diff --git a/arch/arm/mach-omap2/omap_l3_noc.c b/arch/arm/mach-omap2/omap_l3_noc.c
index 82632c24076f..7b9f1909ddb2 100644
--- a/arch/arm/mach-omap2/omap_l3_noc.c
+++ b/arch/arm/mach-omap2/omap_l3_noc.c
@@ -63,10 +63,7 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3)
char *source_name;
/* Get the Type of interrupt */
- if (irq == l3->app_irq)
- inttype = L3_APPLICATION_ERROR;
- else
- inttype = L3_DEBUG_ERROR;
+ inttype = irq == l3->app_irq ? L3_APPLICATION_ERROR : L3_DEBUG_ERROR;
for (i = 0; i < L3_MODULES; i++) {
/*
@@ -84,10 +81,10 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3)
err_src = j;
/* Read the stderrlog_main_source from clk domain */
- std_err_main_addr = base + (*(l3_targ[i] + err_src));
- std_err_main = readl(std_err_main_addr);
+ std_err_main_addr = base + *(l3_targ[i] + err_src);
+ std_err_main = readl(std_err_main_addr);
- switch ((std_err_main & CUSTOM_ERROR)) {
+ switch (std_err_main & CUSTOM_ERROR) {
case STANDARD_ERROR:
source_name =
l3_targ_stderrlog_main_name[i][err_src];
@@ -132,49 +129,49 @@ static int __init omap4_l3_probe(struct platform_device *pdev)
l3 = kzalloc(sizeof(*l3), GFP_KERNEL);
if (!l3)
- ret = -ENOMEM;
+ return -ENOMEM;
platform_set_drvdata(pdev, l3);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "couldn't find resource 0\n");
ret = -ENODEV;
- goto err1;
+ goto err0;
}
l3->l3_base[0] = ioremap(res->start, resource_size(res));
- if (!(l3->l3_base[0])) {
+ if (!l3->l3_base[0]) {
dev_err(&pdev->dev, "ioremap failed\n");
ret = -ENOMEM;
- goto err2;
+ goto err0;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res) {
dev_err(&pdev->dev, "couldn't find resource 1\n");
ret = -ENODEV;
- goto err3;
+ goto err1;
}
l3->l3_base[1] = ioremap(res->start, resource_size(res));
- if (!(l3->l3_base[1])) {
+ if (!l3->l3_base[1]) {
dev_err(&pdev->dev, "ioremap failed\n");
ret = -ENOMEM;
- goto err4;
+ goto err1;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
if (!res) {
dev_err(&pdev->dev, "couldn't find resource 2\n");
ret = -ENODEV;
- goto err5;
+ goto err2;
}
l3->l3_base[2] = ioremap(res->start, resource_size(res));
- if (!(l3->l3_base[2])) {
+ if (!l3->l3_base[2]) {
dev_err(&pdev->dev, "ioremap failed\n");
ret = -ENOMEM;
- goto err6;
+ goto err2;
}
/*
@@ -187,7 +184,7 @@ static int __init omap4_l3_probe(struct platform_device *pdev)
if (ret) {
pr_crit("L3: request_irq failed to register for 0x%x\n",
OMAP44XX_IRQ_L3_DBG);
- goto err7;
+ goto err3;
}
l3->debug_irq = irq;
@@ -198,24 +195,22 @@ static int __init omap4_l3_probe(struct platform_device *pdev)
if (ret) {
pr_crit("L3: request_irq failed to register for 0x%x\n",
OMAP44XX_IRQ_L3_APP);
- goto err8;
+ goto err4;
}
l3->app_irq = irq;
- goto err0;
-err8:
-err7:
- iounmap(l3->l3_base[2]);
-err6:
-err5:
- iounmap(l3->l3_base[1]);
+ return 0;
+
err4:
+ free_irq(l3->debug_irq, l3);
err3:
- iounmap(l3->l3_base[0]);
+ iounmap(l3->l3_base[2]);
err2:
+ iounmap(l3->l3_base[1]);
err1:
- kfree(l3);
+ iounmap(l3->l3_base[0]);
err0:
+ kfree(l3);
return ret;
}
diff --git a/arch/arm/mach-omap2/omap_l3_smx.c b/arch/arm/mach-omap2/omap_l3_smx.c
index 4321e7938929..873c0e33b512 100644
--- a/arch/arm/mach-omap2/omap_l3_smx.c
+++ b/arch/arm/mach-omap2/omap_l3_smx.c
@@ -155,7 +155,7 @@ static irqreturn_t omap3_l3_block_irq(struct omap3_l3 *l3,
u8 multi = error & L3_ERROR_LOG_MULTI;
u32 address = omap3_l3_decode_addr(error_addr);
- WARN(true, "%s Error seen by %s %s at address %x\n",
+ WARN(true, "%s seen by %s %s at address %x\n",
omap3_l3_code_string(code),
omap3_l3_initiator_string(initid),
multi ? "Multiple Errors" : "",
@@ -167,21 +167,15 @@ static irqreturn_t omap3_l3_block_irq(struct omap3_l3 *l3,
static irqreturn_t omap3_l3_app_irq(int irq, void *_l3)
{
struct omap3_l3 *l3 = _l3;
-
u64 status, clear;
u64 error;
u64 error_addr;
u64 err_source = 0;
void __iomem *base;
int int_type;
-
irqreturn_t ret = IRQ_NONE;
- if (irq == l3->app_irq)
- int_type = L3_APPLICATION_ERROR;
- else
- int_type = L3_DEBUG_ERROR;
-
+ int_type = irq == l3->app_irq ? L3_APPLICATION_ERROR : L3_DEBUG_ERROR;
if (!int_type) {
status = omap3_l3_readll(l3->rt, L3_SI_FLAG_STATUS_0);
/*
@@ -202,7 +196,6 @@ static irqreturn_t omap3_l3_app_irq(int irq, void *_l3)
base = l3->rt + *(omap3_l3_bases[int_type] + err_source);
error = omap3_l3_readll(base, L3_ERROR_LOG);
-
if (error) {
error_addr = omap3_l3_readll(base, L3_ERROR_LOG_ADDR);
@@ -210,9 +203,8 @@ static irqreturn_t omap3_l3_app_irq(int irq, void *_l3)
}
/* Clear the status register */
- clear = ((L3_AGENT_STATUS_CLEAR_IA << int_type) |
- (L3_AGENT_STATUS_CLEAR_TA));
-
+ clear = (L3_AGENT_STATUS_CLEAR_IA << int_type) |
+ L3_AGENT_STATUS_CLEAR_TA;
omap3_l3_writell(base, L3_AGENT_STATUS, clear);
/* clear the error log register */
@@ -228,10 +220,8 @@ static int __init omap3_l3_probe(struct platform_device *pdev)
int ret;
l3 = kzalloc(sizeof(*l3), GFP_KERNEL);
- if (!l3) {
- ret = -ENOMEM;
- goto err0;
- }
+ if (!l3)
+ return -ENOMEM;
platform_set_drvdata(pdev, l3);
@@ -239,13 +229,13 @@ static int __init omap3_l3_probe(struct platform_device *pdev)
if (!res) {
dev_err(&pdev->dev, "couldn't find resource\n");
ret = -ENODEV;
- goto err1;
+ goto err0;
}
l3->rt = ioremap(res->start, resource_size(res));
- if (!(l3->rt)) {
+ if (!l3->rt) {
dev_err(&pdev->dev, "ioremap failed\n");
ret = -ENOMEM;
- goto err2;
+ goto err0;
}
l3->debug_irq = platform_get_irq(pdev, 0);
@@ -254,28 +244,26 @@ static int __init omap3_l3_probe(struct platform_device *pdev)
"l3-debug-irq", l3);
if (ret) {
dev_err(&pdev->dev, "couldn't request debug irq\n");
- goto err3;
+ goto err1;
}
l3->app_irq = platform_get_irq(pdev, 1);
ret = request_irq(l3->app_irq, omap3_l3_app_irq,
IRQF_DISABLED | IRQF_TRIGGER_RISING,
"l3-app-irq", l3);
-
if (ret) {
dev_err(&pdev->dev, "couldn't request app irq\n");
- goto err4;
+ goto err2;
}
- goto err0;
+ return 0;
-err4:
-err3:
- iounmap(l3->rt);
err2:
+ free_irq(l3->debug_irq, l3);
err1:
- kfree(l3);
+ iounmap(l3->rt);
err0:
+ kfree(l3);
return ret;
}
diff --git a/arch/arm/mach-omap2/omap_phy_internal.c b/arch/arm/mach-omap2/omap_phy_internal.c
index 05f6abc96b0d..f47813edd951 100644
--- a/arch/arm/mach-omap2/omap_phy_internal.c
+++ b/arch/arm/mach-omap2/omap_phy_internal.c
@@ -50,13 +50,16 @@ int omap4430_phy_init(struct device *dev)
{
ctrl_base = ioremap(OMAP443X_SCM_BASE, SZ_1K);
if (!ctrl_base) {
- dev_err(dev, "control module ioremap failed\n");
+ pr_err("control module ioremap failed\n");
return -ENOMEM;
}
/* Power down the phy */
__raw_writel(PHY_PD, ctrl_base + CONTROL_DEV_CONF);
- phyclk = clk_get(dev, "ocp2scp_usb_phy_ick");
+ if (!dev)
+ return 0;
+
+ phyclk = clk_get(dev, "ocp2scp_usb_phy_ick");
if (IS_ERR(phyclk)) {
dev_err(dev, "cannot clk_get ocp2scp_usb_phy_ick\n");
iounmap(ctrl_base);
@@ -228,7 +231,7 @@ void am35x_musb_clear_irq(void)
regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
}
-void am35x_musb_set_mode(u8 musb_mode)
+void am35x_set_mode(u8 musb_mode)
{
u32 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 797bfd12b643..45bcfce77352 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -36,11 +36,16 @@ static inline int omap4_opp_init(void)
}
#endif
+/*
+ * cpuidle mach specific parameters
+ *
+ * The board code can override the default C-states definition using
+ * omap3_pm_init_cpuidle
+ */
struct cpuidle_params {
- u8 valid;
- u32 sleep_latency;
- u32 wake_latency;
- u32 threshold;
+ u32 exit_latency; /* exit_latency = sleep + wake-up latencies */
+ u32 target_residency;
+ u8 valid; /* validates the C-state */
};
#if defined(CONFIG_PM) && defined(CONFIG_CPU_IDLE)
@@ -73,10 +78,6 @@ extern u32 sleep_while_idle;
#define sleep_while_idle 0
#endif
-#if defined(CONFIG_CPU_IDLE)
-extern void omap3_cpuidle_update_states(u32, u32);
-#endif
-
#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
extern void pm_dbg_update_time(struct powerdomain *pwrdm, int prev);
extern int pm_dbg_regset_save(int reg_set);
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 0c5e3a46a3ad..c155c9d1c82c 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -779,18 +779,6 @@ void omap3_pm_off_mode_enable(int enable)
else
state = PWRDM_POWER_RET;
-#ifdef CONFIG_CPU_IDLE
- /*
- * Erratum i583: implementation for ES rev < Es1.2 on 3630. We cannot
- * enable OFF mode in a stable form for previous revisions, restrict
- * instead to RET
- */
- if (IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583))
- omap3_cpuidle_update_states(state, PWRDM_POWER_RET);
- else
- omap3_cpuidle_update_states(state, state);
-#endif
-
list_for_each_entry(pwrst, &pwrst_list, node) {
if (IS_PM34XX_ERRATUM(PM_SDRC_WAKEUP_ERRATUM_i583) &&
pwrst->pwrdm == core_pwrdm &&
@@ -895,8 +883,6 @@ static int __init omap3_pm_init(void)
pm_errata_configure();
- printk(KERN_ERR "Power Management for TI OMAP3.\n");
-
/* XXX prcm_setup_regs needs to be before enabling hw
* supervised mode for powerdomains */
prcm_setup_regs();
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index 76cfff2db514..59a870be8390 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -105,13 +105,11 @@ static int __init omap4_pm_init(void)
pr_err("Power Management for TI OMAP4.\n");
-#ifdef CONFIG_PM
ret = pwrdm_for_each(pwrdms_setup, NULL);
if (ret) {
pr_err("Failed to setup powerdomains\n");
goto err2;
}
-#endif
#ifdef CONFIG_SUSPEND
suspend_set_ops(&omap_pm_ops);
diff --git a/arch/arm/mach-omap2/pm_bus.c b/arch/arm/mach-omap2/pm_bus.c
deleted file mode 100644
index 5acd2ab298b1..000000000000
--- a/arch/arm/mach-omap2/pm_bus.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Runtime PM support code for OMAP
- *
- * Author: Kevin Hilman, Deep Root Systems, LLC
- *
- * Copyright (C) 2010 Texas Instruments, 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/kernel.h>
-#include <linux/io.h>
-#include <linux/pm_runtime.h>
-#include <linux/platform_device.h>
-#include <linux/mutex.h>
-
-#include <plat/omap_device.h>
-#include <plat/omap-pm.h>
-
-#ifdef CONFIG_PM_RUNTIME
-static int omap_pm_runtime_suspend(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- int r, ret = 0;
-
- dev_dbg(dev, "%s\n", __func__);
-
- ret = pm_generic_runtime_suspend(dev);
-
- if (!ret && dev->parent == &omap_device_parent) {
- r = omap_device_idle(pdev);
- WARN_ON(r);
- }
-
- return ret;
-};
-
-static int omap_pm_runtime_resume(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- int r;
-
- dev_dbg(dev, "%s\n", __func__);
-
- if (dev->parent == &omap_device_parent) {
- r = omap_device_enable(pdev);
- WARN_ON(r);
- }
-
- return pm_generic_runtime_resume(dev);
-};
-#else
-#define omap_pm_runtime_suspend NULL
-#define omap_pm_runtime_resume NULL
-#endif /* CONFIG_PM_RUNTIME */
-
-static int __init omap_pm_runtime_init(void)
-{
- const struct dev_pm_ops *pm;
- struct dev_pm_ops *omap_pm;
-
- pm = platform_bus_get_pm_ops();
- if (!pm) {
- pr_err("%s: unable to get dev_pm_ops from platform_bus\n",
- __func__);
- return -ENODEV;
- }
-
- omap_pm = kmemdup(pm, sizeof(struct dev_pm_ops), GFP_KERNEL);
- if (!omap_pm) {
- pr_err("%s: unable to alloc memory for new dev_pm_ops\n",
- __func__);
- return -ENOMEM;
- }
-
- omap_pm->runtime_suspend = omap_pm_runtime_suspend;
- omap_pm->runtime_resume = omap_pm_runtime_resume;
-
- platform_bus_set_pm_ops(omap_pm);
-
- return 0;
-}
-core_initcall(omap_pm_runtime_init);
diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index 13e24f913dd4..fb7dc52394a8 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -847,6 +847,14 @@ static int __init omap_sr_probe(struct platform_device *pdev)
goto err_free_devinfo;
}
+ mem = request_mem_region(mem->start, resource_size(mem),
+ dev_name(&pdev->dev));
+ if (!mem) {
+ dev_err(&pdev->dev, "%s: no mem region\n", __func__);
+ ret = -EBUSY;
+ goto err_free_devinfo;
+ }
+
irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
pm_runtime_enable(&pdev->dev);
@@ -883,7 +891,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
ret = sr_late_init(sr_info);
if (ret) {
pr_warning("%s: Error in SR late init\n", __func__);
- goto err_release_region;
+ return ret;
}
}
@@ -896,7 +904,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
vdd_dbg_dir = omap_voltage_get_dbgdir(sr_info->voltdm);
if (!vdd_dbg_dir) {
ret = -EINVAL;
- goto err_release_region;
+ goto err_iounmap;
}
sr_info->dbg_dir = debugfs_create_dir("smartreflex", vdd_dbg_dir);
@@ -904,7 +912,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "%s: Unable to create debugfs directory\n",
__func__);
ret = PTR_ERR(sr_info->dbg_dir);
- goto err_release_region;
+ goto err_iounmap;
}
(void) debugfs_create_file("autocomp", S_IRUGO | S_IWUSR,
@@ -921,7 +929,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "%s: Unable to create debugfs directory"
"for n-values\n", __func__);
ret = PTR_ERR(nvalue_dir);
- goto err_release_region;
+ goto err_debugfs;
}
omap_voltage_get_volttable(sr_info->voltdm, &volt_data);
@@ -931,7 +939,7 @@ static int __init omap_sr_probe(struct platform_device *pdev)
"entries for n-values\n",
__func__, sr_info->voltdm->name);
ret = -ENODATA;
- goto err_release_region;
+ goto err_debugfs;
}
for (i = 0; i < sr_info->nvalue_count; i++) {
@@ -945,6 +953,11 @@ static int __init omap_sr_probe(struct platform_device *pdev)
return ret;
+err_debugfs:
+ debugfs_remove_recursive(sr_info->dbg_dir);
+err_iounmap:
+ list_del(&sr_info->node);
+ iounmap(sr_info->base);
err_release_region:
release_mem_region(mem->start, resource_size(mem));
err_free_devinfo:
diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c
index 35559f77e2de..c7ed540d868d 100644
--- a/arch/arm/mach-omap2/usb-musb.c
+++ b/arch/arm/mach-omap2/usb-musb.c
@@ -108,7 +108,13 @@ static void usb_musb_mux_init(struct omap_musb_board_data *board_data)
}
}
-void __init usb_musb_init(struct omap_musb_board_data *board_data)
+static struct omap_musb_board_data musb_default_board_data = {
+ .interface_type = MUSB_INTERFACE_ULPI,
+ .mode = MUSB_OTG,
+ .power = 100,
+};
+
+void __init usb_musb_init(struct omap_musb_board_data *musb_board_data)
{
struct omap_hwmod *oh;
struct omap_device *od;
@@ -116,11 +122,12 @@ void __init usb_musb_init(struct omap_musb_board_data *board_data)
struct device *dev;
int bus_id = -1;
const char *oh_name, *name;
+ struct omap_musb_board_data *board_data;
- if (cpu_is_omap3517() || cpu_is_omap3505()) {
- } else if (cpu_is_omap44xx()) {
- usb_musb_mux_init(board_data);
- }
+ if (musb_board_data)
+ board_data = musb_board_data;
+ else
+ board_data = &musb_default_board_data;
/*
* REVISIT: This line can be removed once all the platforms using
@@ -164,10 +171,15 @@ void __init usb_musb_init(struct omap_musb_board_data *board_data)
dev->dma_mask = &musb_dmamask;
dev->coherent_dma_mask = musb_dmamask;
put_device(dev);
+
+ if (cpu_is_omap44xx())
+ omap4430_phy_init(dev);
}
#else
void __init usb_musb_init(struct omap_musb_board_data *board_data)
{
+ if (cpu_is_omap44xx())
+ omap4430_phy_init(NULL);
}
#endif /* CONFIG_USB_MUSB_SOC */
diff --git a/arch/arm/mach-omap2/usb-tusb6010.c b/arch/arm/mach-omap2/usb-tusb6010.c
index 8a3c05f3c1d6..8dd26b765b7d 100644
--- a/arch/arm/mach-omap2/usb-tusb6010.c
+++ b/arch/arm/mach-omap2/usb-tusb6010.c
@@ -293,12 +293,11 @@ tusb6010_setup_interface(struct musb_hdrc_platform_data *data,
);
/* IRQ */
- status = gpio_request(irq, "TUSB6010 irq");
+ status = gpio_request_one(irq, GPIOF_IN, "TUSB6010 irq");
if (status < 0) {
printk(error, 3, status);
return status;
}
- gpio_direction_input(irq);
tusb_resources[2].start = irq + IH_GPIO_BASE;
/* set up memory timings ... can speed them up later */
diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
index 0c1552d9d995..9ef3789ded4b 100644
--- a/arch/arm/mach-omap2/voltage.c
+++ b/arch/arm/mach-omap2/voltage.c
@@ -148,7 +148,6 @@ static int vp_volt_debug_get(void *data, u64 *val)
}
vsel = vdd->read_reg(prm_mod_offs, vdd->vp_data->voltage);
- pr_notice("curr_vsel = %x\n", vsel);
if (!vdd->pmic_info->vsel_to_uv) {
pr_warning("PMIC function to convert vsel to voltage"
diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c
index 986c3bf4e6b8..0ab531d047fc 100644
--- a/arch/arm/mach-orion5x/common.c
+++ b/arch/arm/mach-orion5x/common.c
@@ -13,12 +13,11 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
#include <linux/serial_8250.h>
#include <linux/mbus.h>
-#include <linux/mv643xx_eth.h>
#include <linux/mv643xx_i2c.h>
#include <linux/ata_platform.h>
-#include <linux/spi/orion_spi.h>
#include <net/dsa.h>
#include <asm/page.h>
#include <asm/setup.h>
@@ -29,11 +28,9 @@
#include <mach/bridge-regs.h>
#include <mach/hardware.h>
#include <mach/orion5x.h>
-#include <plat/ehci-orion.h>
-#include <plat/mv_xor.h>
#include <plat/orion_nand.h>
-#include <plat/orion_wdt.h>
#include <plat/time.h>
+#include <plat/common.h>
#include "common.h"
/*****************************************************************************
@@ -70,530 +67,124 @@ void __init orion5x_map_io(void)
/*****************************************************************************
- * EHCI
- ****************************************************************************/
-static struct orion_ehci_data orion5x_ehci_data = {
- .dram = &orion5x_mbus_dram_info,
- .phy_version = EHCI_PHY_ORION,
-};
-
-static u64 ehci_dmamask = 0xffffffffUL;
-
-
-/*****************************************************************************
* EHCI0
****************************************************************************/
-static struct resource orion5x_ehci0_resources[] = {
- {
- .start = ORION5X_USB0_PHYS_BASE,
- .end = ORION5X_USB0_PHYS_BASE + SZ_4K - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_ORION5X_USB0_CTRL,
- .end = IRQ_ORION5X_USB0_CTRL,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device orion5x_ehci0 = {
- .name = "orion-ehci",
- .id = 0,
- .dev = {
- .dma_mask = &ehci_dmamask,
- .coherent_dma_mask = 0xffffffff,
- .platform_data = &orion5x_ehci_data,
- },
- .resource = orion5x_ehci0_resources,
- .num_resources = ARRAY_SIZE(orion5x_ehci0_resources),
-};
-
void __init orion5x_ehci0_init(void)
{
- platform_device_register(&orion5x_ehci0);
+ orion_ehci_init(&orion5x_mbus_dram_info,
+ ORION5X_USB0_PHYS_BASE, IRQ_ORION5X_USB0_CTRL);
}
/*****************************************************************************
* EHCI1
****************************************************************************/
-static struct resource orion5x_ehci1_resources[] = {
- {
- .start = ORION5X_USB1_PHYS_BASE,
- .end = ORION5X_USB1_PHYS_BASE + SZ_4K - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_ORION5X_USB1_CTRL,
- .end = IRQ_ORION5X_USB1_CTRL,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device orion5x_ehci1 = {
- .name = "orion-ehci",
- .id = 1,
- .dev = {
- .dma_mask = &ehci_dmamask,
- .coherent_dma_mask = 0xffffffff,
- .platform_data = &orion5x_ehci_data,
- },
- .resource = orion5x_ehci1_resources,
- .num_resources = ARRAY_SIZE(orion5x_ehci1_resources),
-};
-
void __init orion5x_ehci1_init(void)
{
- platform_device_register(&orion5x_ehci1);
+ orion_ehci_1_init(&orion5x_mbus_dram_info,
+ ORION5X_USB1_PHYS_BASE, IRQ_ORION5X_USB1_CTRL);
}
/*****************************************************************************
- * GigE
+ * GE00
****************************************************************************/
-struct mv643xx_eth_shared_platform_data orion5x_eth_shared_data = {
- .dram = &orion5x_mbus_dram_info,
-};
-
-static struct resource orion5x_eth_shared_resources[] = {
- {
- .start = ORION5X_ETH_PHYS_BASE + 0x2000,
- .end = ORION5X_ETH_PHYS_BASE + 0x3fff,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_ORION5X_ETH_ERR,
- .end = IRQ_ORION5X_ETH_ERR,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device orion5x_eth_shared = {
- .name = MV643XX_ETH_SHARED_NAME,
- .id = 0,
- .dev = {
- .platform_data = &orion5x_eth_shared_data,
- },
- .num_resources = ARRAY_SIZE(orion5x_eth_shared_resources),
- .resource = orion5x_eth_shared_resources,
-};
-
-static struct resource orion5x_eth_resources[] = {
- {
- .name = "eth irq",
- .start = IRQ_ORION5X_ETH_SUM,
- .end = IRQ_ORION5X_ETH_SUM,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device orion5x_eth = {
- .name = MV643XX_ETH_NAME,
- .id = 0,
- .num_resources = 1,
- .resource = orion5x_eth_resources,
- .dev = {
- .coherent_dma_mask = 0xffffffff,
- },
-};
-
void __init orion5x_eth_init(struct mv643xx_eth_platform_data *eth_data)
{
- eth_data->shared = &orion5x_eth_shared;
- orion5x_eth.dev.platform_data = eth_data;
-
- platform_device_register(&orion5x_eth_shared);
- platform_device_register(&orion5x_eth);
+ orion_ge00_init(eth_data, &orion5x_mbus_dram_info,
+ ORION5X_ETH_PHYS_BASE, IRQ_ORION5X_ETH_SUM,
+ IRQ_ORION5X_ETH_ERR, orion5x_tclk);
}
/*****************************************************************************
* Ethernet switch
****************************************************************************/
-static struct resource orion5x_switch_resources[] = {
- {
- .start = 0,
- .end = 0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device orion5x_switch_device = {
- .name = "dsa",
- .id = 0,
- .num_resources = 0,
- .resource = orion5x_switch_resources,
-};
-
void __init orion5x_eth_switch_init(struct dsa_platform_data *d, int irq)
{
- int i;
-
- if (irq != NO_IRQ) {
- orion5x_switch_resources[0].start = irq;
- orion5x_switch_resources[0].end = irq;
- orion5x_switch_device.num_resources = 1;
- }
-
- d->netdev = &orion5x_eth.dev;
- for (i = 0; i < d->nr_chips; i++)
- d->chip[i].mii_bus = &orion5x_eth_shared.dev;
- orion5x_switch_device.dev.platform_data = d;
-
- platform_device_register(&orion5x_switch_device);
+ orion_ge00_switch_init(d, irq);
}
/*****************************************************************************
* I2C
****************************************************************************/
-static struct mv64xxx_i2c_pdata orion5x_i2c_pdata = {
- .freq_m = 8, /* assumes 166 MHz TCLK */
- .freq_n = 3,
- .timeout = 1000, /* Default timeout of 1 second */
-};
-
-static struct resource orion5x_i2c_resources[] = {
- {
- .start = I2C_PHYS_BASE,
- .end = I2C_PHYS_BASE + 0x1f,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_ORION5X_I2C,
- .end = IRQ_ORION5X_I2C,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device orion5x_i2c = {
- .name = MV64XXX_I2C_CTLR_NAME,
- .id = 0,
- .num_resources = ARRAY_SIZE(orion5x_i2c_resources),
- .resource = orion5x_i2c_resources,
- .dev = {
- .platform_data = &orion5x_i2c_pdata,
- },
-};
-
void __init orion5x_i2c_init(void)
{
- platform_device_register(&orion5x_i2c);
+ orion_i2c_init(I2C_PHYS_BASE, IRQ_ORION5X_I2C, 8);
+
}
/*****************************************************************************
* SATA
****************************************************************************/
-static struct resource orion5x_sata_resources[] = {
- {
- .name = "sata base",
- .start = ORION5X_SATA_PHYS_BASE,
- .end = ORION5X_SATA_PHYS_BASE + 0x5000 - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .name = "sata irq",
- .start = IRQ_ORION5X_SATA,
- .end = IRQ_ORION5X_SATA,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device orion5x_sata = {
- .name = "sata_mv",
- .id = 0,
- .dev = {
- .coherent_dma_mask = 0xffffffff,
- },
- .num_resources = ARRAY_SIZE(orion5x_sata_resources),
- .resource = orion5x_sata_resources,
-};
-
void __init orion5x_sata_init(struct mv_sata_platform_data *sata_data)
{
- sata_data->dram = &orion5x_mbus_dram_info;
- orion5x_sata.dev.platform_data = sata_data;
- platform_device_register(&orion5x_sata);
+ orion_sata_init(sata_data, &orion5x_mbus_dram_info,
+ ORION5X_SATA_PHYS_BASE, IRQ_ORION5X_SATA);
}
/*****************************************************************************
* SPI
****************************************************************************/
-static struct orion_spi_info orion5x_spi_plat_data = {
- .tclk = 0,
- .enable_clock_fix = 1,
-};
-
-static struct resource orion5x_spi_resources[] = {
- {
- .name = "spi base",
- .start = SPI_PHYS_BASE,
- .end = SPI_PHYS_BASE + 0x1f,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device orion5x_spi = {
- .name = "orion_spi",
- .id = 0,
- .dev = {
- .platform_data = &orion5x_spi_plat_data,
- },
- .num_resources = ARRAY_SIZE(orion5x_spi_resources),
- .resource = orion5x_spi_resources,
-};
-
void __init orion5x_spi_init()
{
- platform_device_register(&orion5x_spi);
+ orion_spi_init(SPI_PHYS_BASE, orion5x_tclk);
}
/*****************************************************************************
* UART0
****************************************************************************/
-static struct plat_serial8250_port orion5x_uart0_data[] = {
- {
- .mapbase = UART0_PHYS_BASE,
- .membase = (char *)UART0_VIRT_BASE,
- .irq = IRQ_ORION5X_UART0,
- .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = 0,
- }, {
- },
-};
-
-static struct resource orion5x_uart0_resources[] = {
- {
- .start = UART0_PHYS_BASE,
- .end = UART0_PHYS_BASE + 0xff,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_ORION5X_UART0,
- .end = IRQ_ORION5X_UART0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device orion5x_uart0 = {
- .name = "serial8250",
- .id = PLAT8250_DEV_PLATFORM,
- .dev = {
- .platform_data = orion5x_uart0_data,
- },
- .resource = orion5x_uart0_resources,
- .num_resources = ARRAY_SIZE(orion5x_uart0_resources),
-};
-
void __init orion5x_uart0_init(void)
{
- platform_device_register(&orion5x_uart0);
+ orion_uart0_init(UART0_VIRT_BASE, UART0_PHYS_BASE,
+ IRQ_ORION5X_UART0, orion5x_tclk);
}
-
/*****************************************************************************
* UART1
****************************************************************************/
-static struct plat_serial8250_port orion5x_uart1_data[] = {
- {
- .mapbase = UART1_PHYS_BASE,
- .membase = (char *)UART1_VIRT_BASE,
- .irq = IRQ_ORION5X_UART1,
- .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = 0,
- }, {
- },
-};
-
-static struct resource orion5x_uart1_resources[] = {
- {
- .start = UART1_PHYS_BASE,
- .end = UART1_PHYS_BASE + 0xff,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_ORION5X_UART1,
- .end = IRQ_ORION5X_UART1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device orion5x_uart1 = {
- .name = "serial8250",
- .id = PLAT8250_DEV_PLATFORM1,
- .dev = {
- .platform_data = orion5x_uart1_data,
- },
- .resource = orion5x_uart1_resources,
- .num_resources = ARRAY_SIZE(orion5x_uart1_resources),
-};
-
void __init orion5x_uart1_init(void)
{
- platform_device_register(&orion5x_uart1);
+ orion_uart1_init(UART1_VIRT_BASE, UART1_PHYS_BASE,
+ IRQ_ORION5X_UART1, orion5x_tclk);
}
-
/*****************************************************************************
* XOR engine
****************************************************************************/
-struct mv_xor_platform_shared_data orion5x_xor_shared_data = {
- .dram = &orion5x_mbus_dram_info,
-};
-
-static struct resource orion5x_xor_shared_resources[] = {
- {
- .name = "xor low",
- .start = ORION5X_XOR_PHYS_BASE,
- .end = ORION5X_XOR_PHYS_BASE + 0xff,
- .flags = IORESOURCE_MEM,
- }, {
- .name = "xor high",
- .start = ORION5X_XOR_PHYS_BASE + 0x200,
- .end = ORION5X_XOR_PHYS_BASE + 0x2ff,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device orion5x_xor_shared = {
- .name = MV_XOR_SHARED_NAME,
- .id = 0,
- .dev = {
- .platform_data = &orion5x_xor_shared_data,
- },
- .num_resources = ARRAY_SIZE(orion5x_xor_shared_resources),
- .resource = orion5x_xor_shared_resources,
-};
-
-static u64 orion5x_xor_dmamask = DMA_BIT_MASK(32);
-
-static struct resource orion5x_xor0_resources[] = {
- [0] = {
- .start = IRQ_ORION5X_XOR0,
- .end = IRQ_ORION5X_XOR0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct mv_xor_platform_data orion5x_xor0_data = {
- .shared = &orion5x_xor_shared,
- .hw_id = 0,
- .pool_size = PAGE_SIZE,
-};
-
-static struct platform_device orion5x_xor0_channel = {
- .name = MV_XOR_NAME,
- .id = 0,
- .num_resources = ARRAY_SIZE(orion5x_xor0_resources),
- .resource = orion5x_xor0_resources,
- .dev = {
- .dma_mask = &orion5x_xor_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(64),
- .platform_data = &orion5x_xor0_data,
- },
-};
-
-static struct resource orion5x_xor1_resources[] = {
- [0] = {
- .start = IRQ_ORION5X_XOR1,
- .end = IRQ_ORION5X_XOR1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct mv_xor_platform_data orion5x_xor1_data = {
- .shared = &orion5x_xor_shared,
- .hw_id = 1,
- .pool_size = PAGE_SIZE,
-};
-
-static struct platform_device orion5x_xor1_channel = {
- .name = MV_XOR_NAME,
- .id = 1,
- .num_resources = ARRAY_SIZE(orion5x_xor1_resources),
- .resource = orion5x_xor1_resources,
- .dev = {
- .dma_mask = &orion5x_xor_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(64),
- .platform_data = &orion5x_xor1_data,
- },
-};
-
void __init orion5x_xor_init(void)
{
- platform_device_register(&orion5x_xor_shared);
-
- /*
- * two engines can't do memset simultaneously, this limitation
- * satisfied by removing memset support from one of the engines.
- */
- dma_cap_set(DMA_MEMCPY, orion5x_xor0_data.cap_mask);
- dma_cap_set(DMA_XOR, orion5x_xor0_data.cap_mask);
- platform_device_register(&orion5x_xor0_channel);
-
- dma_cap_set(DMA_MEMCPY, orion5x_xor1_data.cap_mask);
- dma_cap_set(DMA_MEMSET, orion5x_xor1_data.cap_mask);
- dma_cap_set(DMA_XOR, orion5x_xor1_data.cap_mask);
- platform_device_register(&orion5x_xor1_channel);
+ orion_xor0_init(&orion5x_mbus_dram_info,
+ ORION5X_XOR_PHYS_BASE,
+ ORION5X_XOR_PHYS_BASE + 0x200,
+ IRQ_ORION5X_XOR0, IRQ_ORION5X_XOR1);
}
-static struct resource orion5x_crypto_res[] = {
- {
- .name = "regs",
- .start = ORION5X_CRYPTO_PHYS_BASE,
- .end = ORION5X_CRYPTO_PHYS_BASE + 0xffff,
- .flags = IORESOURCE_MEM,
- }, {
- .name = "sram",
- .start = ORION5X_SRAM_PHYS_BASE,
- .end = ORION5X_SRAM_PHYS_BASE + SZ_8K - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .name = "crypto interrupt",
- .start = IRQ_ORION5X_CESA,
- .end = IRQ_ORION5X_CESA,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device orion5x_crypto_device = {
- .name = "mv_crypto",
- .id = -1,
- .num_resources = ARRAY_SIZE(orion5x_crypto_res),
- .resource = orion5x_crypto_res,
-};
-
-static int __init orion5x_crypto_init(void)
+/*****************************************************************************
+ * Cryptographic Engines and Security Accelerator (CESA)
+ ****************************************************************************/
+static void __init orion5x_crypto_init(void)
{
int ret;
ret = orion5x_setup_sram_win();
if (ret)
- return ret;
+ return;
- return platform_device_register(&orion5x_crypto_device);
+ orion_crypto_init(ORION5X_CRYPTO_PHYS_BASE, ORION5X_SRAM_PHYS_BASE,
+ SZ_8K, IRQ_ORION5X_CESA);
}
/*****************************************************************************
* Watchdog
****************************************************************************/
-static struct orion_wdt_platform_data orion5x_wdt_data = {
- .tclk = 0,
-};
-
-static struct platform_device orion5x_wdt_device = {
- .name = "orion_wdt",
- .id = -1,
- .dev = {
- .platform_data = &orion5x_wdt_data,
- },
- .num_resources = 0,
-};
-
void __init orion5x_wdt_init(void)
{
- orion5x_wdt_data.tclk = orion5x_tclk;
- platform_device_register(&orion5x_wdt_device);
+ orion_wdt_init(orion5x_tclk);
}
@@ -685,11 +276,6 @@ void __init orion5x_init(void)
orion5x_id(&dev, &rev, &dev_name);
printk(KERN_INFO "Orion ID: %s. TCLK=%d.\n", dev_name, orion5x_tclk);
- orion5x_eth_shared_data.t_clk = orion5x_tclk;
- orion5x_spi_plat_data.tclk = orion5x_tclk;
- orion5x_uart0_data[0].uartclk = orion5x_tclk;
- orion5x_uart1_data[0].uartclk = orion5x_tclk;
-
/*
* Setup Orion address map
*/
diff --git a/arch/arm/mach-orion5x/d2net-setup.c b/arch/arm/mach-orion5x/d2net-setup.c
index 425807579303..19cf5bf99f1b 100644
--- a/arch/arm/mach-orion5x/d2net-setup.c
+++ b/arch/arm/mach-orion5x/d2net-setup.c
@@ -267,28 +267,28 @@ static struct platform_device d2net_gpio_buttons = {
* General Setup
****************************************************************************/
-static struct orion5x_mpp_mode d2net_mpp_modes[] __initdata = {
- { 0, MPP_GPIO }, /* Board ID (bit 0) */
- { 1, MPP_GPIO }, /* Board ID (bit 1) */
- { 2, MPP_GPIO }, /* Board ID (bit 2) */
- { 3, MPP_GPIO }, /* SATA 0 power */
- { 4, MPP_UNUSED },
- { 5, MPP_GPIO }, /* Fan fail detection */
- { 6, MPP_GPIO }, /* Red front LED */
- { 7, MPP_UNUSED },
- { 8, MPP_GPIO }, /* Rear power switch (on|auto) */
- { 9, MPP_GPIO }, /* Rear power switch (auto|off) */
- { 10, MPP_UNUSED },
- { 11, MPP_UNUSED },
- { 12, MPP_GPIO }, /* SATA 1 power */
- { 13, MPP_UNUSED },
- { 14, MPP_SATA_LED }, /* SATA 0 active */
- { 15, MPP_SATA_LED }, /* SATA 1 active */
- { 16, MPP_GPIO }, /* Blue front LED blink control */
- { 17, MPP_UNUSED },
- { 18, MPP_GPIO }, /* Front button (0 = Released, 1 = Pushed ) */
- { 19, MPP_UNUSED },
- { -1 }
+static unsigned int d2net_mpp_modes[] __initdata = {
+ MPP0_GPIO, /* Board ID (bit 0) */
+ MPP1_GPIO, /* Board ID (bit 1) */
+ MPP2_GPIO, /* Board ID (bit 2) */
+ MPP3_GPIO, /* SATA 0 power */
+ MPP4_UNUSED,
+ MPP5_GPIO, /* Fan fail detection */
+ MPP6_GPIO, /* Red front LED */
+ MPP7_UNUSED,
+ MPP8_GPIO, /* Rear power switch (on|auto) */
+ MPP9_GPIO, /* Rear power switch (auto|off) */
+ MPP10_UNUSED,
+ MPP11_UNUSED,
+ MPP12_GPIO, /* SATA 1 power */
+ MPP13_UNUSED,
+ MPP14_SATA_LED, /* SATA 0 active */
+ MPP15_SATA_LED, /* SATA 1 active */
+ MPP16_GPIO, /* Blue front LED blink control */
+ MPP17_UNUSED,
+ MPP18_GPIO, /* Front button (0 = Released, 1 = Pushed ) */
+ MPP19_UNUSED,
+ 0,
/* 22: USB port 1 fuse (0 = Fail, 1 = Ok) */
/* 23: Blue front LED off */
/* 24: Inhibit board power off (0 = Disabled, 1 = Enabled) */
diff --git a/arch/arm/mach-orion5x/db88f5281-setup.c b/arch/arm/mach-orion5x/db88f5281-setup.c
index b7d4591214e0..f95d3cb01cbf 100644
--- a/arch/arm/mach-orion5x/db88f5281-setup.c
+++ b/arch/arm/mach-orion5x/db88f5281-setup.c
@@ -298,28 +298,28 @@ static struct i2c_board_info __initdata db88f5281_i2c_rtc = {
/*****************************************************************************
* General Setup
****************************************************************************/
-static struct orion5x_mpp_mode db88f5281_mpp_modes[] __initdata = {
- { 0, MPP_GPIO }, /* USB Over Current */
- { 1, MPP_GPIO }, /* USB Vbat input */
- { 2, MPP_PCI_ARB }, /* PCI_REQn[2] */
- { 3, MPP_PCI_ARB }, /* PCI_GNTn[2] */
- { 4, MPP_PCI_ARB }, /* PCI_REQn[3] */
- { 5, MPP_PCI_ARB }, /* PCI_GNTn[3] */
- { 6, MPP_GPIO }, /* JP0, CON17.2 */
- { 7, MPP_GPIO }, /* JP1, CON17.1 */
- { 8, MPP_GPIO }, /* JP2, CON11.2 */
- { 9, MPP_GPIO }, /* JP3, CON11.3 */
- { 10, MPP_GPIO }, /* RTC int */
- { 11, MPP_GPIO }, /* Baud Rate Generator */
- { 12, MPP_GPIO }, /* PCI int 1 */
- { 13, MPP_GPIO }, /* PCI int 2 */
- { 14, MPP_NAND }, /* NAND_REn[2] */
- { 15, MPP_NAND }, /* NAND_WEn[2] */
- { 16, MPP_UART }, /* UART1_RX */
- { 17, MPP_UART }, /* UART1_TX */
- { 18, MPP_UART }, /* UART1_CTSn */
- { 19, MPP_UART }, /* UART1_RTSn */
- { -1 },
+static unsigned int db88f5281_mpp_modes[] __initdata = {
+ MPP0_GPIO, /* USB Over Current */
+ MPP1_GPIO, /* USB Vbat input */
+ MPP2_PCI_ARB, /* PCI_REQn[2] */
+ MPP3_PCI_ARB, /* PCI_GNTn[2] */
+ MPP4_PCI_ARB, /* PCI_REQn[3] */
+ MPP5_PCI_ARB, /* PCI_GNTn[3] */
+ MPP6_GPIO, /* JP0, CON17.2 */
+ MPP7_GPIO, /* JP1, CON17.1 */
+ MPP8_GPIO, /* JP2, CON11.2 */
+ MPP9_GPIO, /* JP3, CON11.3 */
+ MPP10_GPIO, /* RTC int */
+ MPP11_GPIO, /* Baud Rate Generator */
+ MPP12_GPIO, /* PCI int 1 */
+ MPP13_GPIO, /* PCI int 2 */
+ MPP14_NAND, /* NAND_REn[2] */
+ MPP15_NAND, /* NAND_WEn[2] */
+ MPP16_UART, /* UART1_RX */
+ MPP17_UART, /* UART1_TX */
+ MPP18_UART, /* UART1_CTSn */
+ MPP19_UART, /* UART1_RTSn */
+ 0,
};
static void __init db88f5281_init(void)
diff --git a/arch/arm/mach-orion5x/dns323-setup.c b/arch/arm/mach-orion5x/dns323-setup.c
index 90ab022eabeb..855e0e77d563 100644
--- a/arch/arm/mach-orion5x/dns323-setup.c
+++ b/arch/arm/mach-orion5x/dns323-setup.c
@@ -385,76 +385,76 @@ static struct mv_sata_platform_data dns323_sata_data = {
/****************************************************************************
* General Setup
*/
-static struct orion5x_mpp_mode dns323a_mpp_modes[] __initdata = {
- { 0, MPP_PCIE_RST_OUTn },
- { 1, MPP_GPIO }, /* right amber LED (sata ch0) */
- { 2, MPP_GPIO }, /* left amber LED (sata ch1) */
- { 3, MPP_UNUSED },
- { 4, MPP_GPIO }, /* power button LED */
- { 5, MPP_GPIO }, /* power button LED */
- { 6, MPP_GPIO }, /* GMT G751-2f overtemp */
- { 7, MPP_GPIO }, /* M41T80 nIRQ/OUT/SQW */
- { 8, MPP_GPIO }, /* triggers power off */
- { 9, MPP_GPIO }, /* power button switch */
- { 10, MPP_GPIO }, /* reset button switch */
- { 11, MPP_UNUSED },
- { 12, MPP_UNUSED },
- { 13, MPP_UNUSED },
- { 14, MPP_UNUSED },
- { 15, MPP_UNUSED },
- { 16, MPP_UNUSED },
- { 17, MPP_UNUSED },
- { 18, MPP_UNUSED },
- { 19, MPP_UNUSED },
- { -1 },
+static unsigned int dns323a_mpp_modes[] __initdata = {
+ MPP0_PCIE_RST_OUTn,
+ MPP1_GPIO, /* right amber LED (sata ch0) */
+ MPP2_GPIO, /* left amber LED (sata ch1) */
+ MPP3_UNUSED,
+ MPP4_GPIO, /* power button LED */
+ MPP5_GPIO, /* power button LED */
+ MPP6_GPIO, /* GMT G751-2f overtemp */
+ MPP7_GPIO, /* M41T80 nIRQ/OUT/SQW */
+ MPP8_GPIO, /* triggers power off */
+ MPP9_GPIO, /* power button switch */
+ MPP10_GPIO, /* reset button switch */
+ MPP11_UNUSED,
+ MPP12_UNUSED,
+ MPP13_UNUSED,
+ MPP14_UNUSED,
+ MPP15_UNUSED,
+ MPP16_UNUSED,
+ MPP17_UNUSED,
+ MPP18_UNUSED,
+ MPP19_UNUSED,
+ 0,
};
-static struct orion5x_mpp_mode dns323b_mpp_modes[] __initdata = {
- { 0, MPP_UNUSED },
- { 1, MPP_GPIO }, /* right amber LED (sata ch0) */
- { 2, MPP_GPIO }, /* left amber LED (sata ch1) */
- { 3, MPP_GPIO }, /* system up flag */
- { 4, MPP_GPIO }, /* power button LED */
- { 5, MPP_GPIO }, /* power button LED */
- { 6, MPP_GPIO }, /* GMT G751-2f overtemp */
- { 7, MPP_GPIO }, /* M41T80 nIRQ/OUT/SQW */
- { 8, MPP_GPIO }, /* triggers power off */
- { 9, MPP_GPIO }, /* power button switch */
- { 10, MPP_GPIO }, /* reset button switch */
- { 11, MPP_UNUSED },
- { 12, MPP_SATA_LED },
- { 13, MPP_SATA_LED },
- { 14, MPP_SATA_LED },
- { 15, MPP_SATA_LED },
- { 16, MPP_UNUSED },
- { 17, MPP_UNUSED },
- { 18, MPP_UNUSED },
- { 19, MPP_UNUSED },
- { -1 },
+static unsigned int dns323b_mpp_modes[] __initdata = {
+ MPP0_UNUSED,
+ MPP1_GPIO, /* right amber LED (sata ch0) */
+ MPP2_GPIO, /* left amber LED (sata ch1) */
+ MPP3_GPIO, /* system up flag */
+ MPP4_GPIO, /* power button LED */
+ MPP5_GPIO, /* power button LED */
+ MPP6_GPIO, /* GMT G751-2f overtemp */
+ MPP7_GPIO, /* M41T80 nIRQ/OUT/SQW */
+ MPP8_GPIO, /* triggers power off */
+ MPP9_GPIO, /* power button switch */
+ MPP10_GPIO, /* reset button switch */
+ MPP11_UNUSED,
+ MPP12_SATA_LED,
+ MPP13_SATA_LED,
+ MPP14_SATA_LED,
+ MPP15_SATA_LED,
+ MPP16_UNUSED,
+ MPP17_UNUSED,
+ MPP18_UNUSED,
+ MPP19_UNUSED,
+ 0,
};
-static struct orion5x_mpp_mode dns323c_mpp_modes[] __initdata = {
- { 0, MPP_GPIO }, /* ? input */
- { 1, MPP_GPIO }, /* input power switch (0 = pressed) */
- { 2, MPP_GPIO }, /* output power off */
- { 3, MPP_UNUSED }, /* ? output */
- { 4, MPP_UNUSED }, /* ? output */
- { 5, MPP_UNUSED }, /* ? output */
- { 6, MPP_UNUSED }, /* ? output */
- { 7, MPP_UNUSED }, /* ? output */
- { 8, MPP_GPIO }, /* i/o right amber LED */
- { 9, MPP_GPIO }, /* i/o left amber LED */
- { 10, MPP_GPIO }, /* input */
- { 11, MPP_UNUSED },
- { 12, MPP_SATA_LED },
- { 13, MPP_SATA_LED },
- { 14, MPP_SATA_LED },
- { 15, MPP_SATA_LED },
- { 16, MPP_UNUSED },
- { 17, MPP_GPIO }, /* power button LED */
- { 18, MPP_GPIO }, /* fan speed bit 0 */
- { 19, MPP_GPIO }, /* fan speed bit 1 */
- { -1 },
+static unsigned int dns323c_mpp_modes[] __initdata = {
+ MPP0_GPIO, /* ? input */
+ MPP1_GPIO, /* input power switch (0 = pressed) */
+ MPP2_GPIO, /* output power off */
+ MPP3_UNUSED, /* ? output */
+ MPP4_UNUSED, /* ? output */
+ MPP5_UNUSED, /* ? output */
+ MPP6_UNUSED, /* ? output */
+ MPP7_UNUSED, /* ? output */
+ MPP8_GPIO, /* i/o right amber LED */
+ MPP9_GPIO, /* i/o left amber LED */
+ MPP10_GPIO, /* input */
+ MPP11_UNUSED,
+ MPP12_SATA_LED,
+ MPP13_SATA_LED,
+ MPP14_SATA_LED,
+ MPP15_SATA_LED,
+ MPP16_UNUSED,
+ MPP17_GPIO, /* power button LED */
+ MPP18_GPIO, /* fan speed bit 0 */
+ MPP19_GPIO, /* fan speed bit 1 */
+ 0,
};
/* Rev C1 Fan speed notes:
diff --git a/arch/arm/mach-orion5x/edmini_v2-setup.c b/arch/arm/mach-orion5x/edmini_v2-setup.c
index d037a90c216c..b67cff0d4cfe 100644
--- a/arch/arm/mach-orion5x/edmini_v2-setup.c
+++ b/arch/arm/mach-orion5x/edmini_v2-setup.c
@@ -180,31 +180,31 @@ static struct platform_device edmini_v2_gpio_buttons = {
/*****************************************************************************
* General Setup
****************************************************************************/
-static struct orion5x_mpp_mode edminiv2_mpp_modes[] __initdata = {
- { 0, MPP_UNUSED },
- { 1, MPP_UNUSED },
- { 2, MPP_UNUSED },
- { 3, MPP_GPIO }, /* RTC interrupt */
- { 4, MPP_UNUSED },
- { 5, MPP_UNUSED },
- { 6, MPP_UNUSED },
- { 7, MPP_UNUSED },
- { 8, MPP_UNUSED },
- { 9, MPP_UNUSED },
- { 10, MPP_UNUSED },
- { 11, MPP_UNUSED },
- { 12, MPP_SATA_LED }, /* SATA 0 presence */
- { 13, MPP_SATA_LED }, /* SATA 1 presence */
- { 14, MPP_SATA_LED }, /* SATA 0 active */
- { 15, MPP_SATA_LED }, /* SATA 1 active */
+static unsigned int edminiv2_mpp_modes[] __initdata = {
+ MPP0_UNUSED,
+ MPP1_UNUSED,
+ MPP2_UNUSED,
+ MPP3_GPIO, /* RTC interrupt */
+ MPP4_UNUSED,
+ MPP5_UNUSED,
+ MPP6_UNUSED,
+ MPP7_UNUSED,
+ MPP8_UNUSED,
+ MPP9_UNUSED,
+ MPP10_UNUSED,
+ MPP11_UNUSED,
+ MPP12_SATA_LED, /* SATA 0 presence */
+ MPP13_SATA_LED, /* SATA 1 presence */
+ MPP14_SATA_LED, /* SATA 0 active */
+ MPP15_SATA_LED, /* SATA 1 active */
/* 16: Power LED control (0 = On, 1 = Off) */
- { 16, MPP_GPIO },
+ MPP16_GPIO,
/* 17: Power LED control select (0 = CPLD, 1 = GPIO16) */
- { 17, MPP_GPIO },
+ MPP17_GPIO,
/* 18: Power button status (0 = Released, 1 = Pressed) */
- { 18, MPP_GPIO },
- { 19, MPP_UNUSED },
- { -1 }
+ MPP18_GPIO,
+ MPP19_UNUSED,
+ 0,
};
static void __init edmini_v2_init(void)
diff --git a/arch/arm/mach-orion5x/kurobox_pro-setup.c b/arch/arm/mach-orion5x/kurobox_pro-setup.c
index 47497c76162a..c0eb6462633f 100644
--- a/arch/arm/mach-orion5x/kurobox_pro-setup.c
+++ b/arch/arm/mach-orion5x/kurobox_pro-setup.c
@@ -315,28 +315,28 @@ static void kurobox_pro_power_off(void)
/*****************************************************************************
* General Setup
****************************************************************************/
-static struct orion5x_mpp_mode kurobox_pro_mpp_modes[] __initdata = {
- { 0, MPP_UNUSED },
- { 1, MPP_UNUSED },
- { 2, MPP_GPIO }, /* GPIO Micon */
- { 3, MPP_GPIO }, /* GPIO Rtc */
- { 4, MPP_UNUSED },
- { 5, MPP_UNUSED },
- { 6, MPP_NAND }, /* NAND Flash REn */
- { 7, MPP_NAND }, /* NAND Flash WEn */
- { 8, MPP_UNUSED },
- { 9, MPP_UNUSED },
- { 10, MPP_UNUSED },
- { 11, MPP_UNUSED },
- { 12, MPP_SATA_LED }, /* SATA 0 presence */
- { 13, MPP_SATA_LED }, /* SATA 1 presence */
- { 14, MPP_SATA_LED }, /* SATA 0 active */
- { 15, MPP_SATA_LED }, /* SATA 1 active */
- { 16, MPP_UART }, /* UART1 RXD */
- { 17, MPP_UART }, /* UART1 TXD */
- { 18, MPP_UART }, /* UART1 CTSn */
- { 19, MPP_UART }, /* UART1 RTSn */
- { -1 },
+static unsigned int kurobox_pro_mpp_modes[] __initdata = {
+ MPP0_UNUSED,
+ MPP1_UNUSED,
+ MPP2_GPIO, /* GPIO Micon */
+ MPP3_GPIO, /* GPIO Rtc */
+ MPP4_UNUSED,
+ MPP5_UNUSED,
+ MPP6_NAND, /* NAND Flash REn */
+ MPP7_NAND, /* NAND Flash WEn */
+ MPP8_UNUSED,
+ MPP9_UNUSED,
+ MPP10_UNUSED,
+ MPP11_UNUSED,
+ MPP12_SATA_LED, /* SATA 0 presence */
+ MPP13_SATA_LED, /* SATA 1 presence */
+ MPP14_SATA_LED, /* SATA 0 active */
+ MPP15_SATA_LED, /* SATA 1 active */
+ MPP16_UART, /* UART1 RXD */
+ MPP17_UART, /* UART1 TXD */
+ MPP18_UART, /* UART1 CTSn */
+ MPP19_UART, /* UART1 RTSn */
+ 0,
};
static void __init kurobox_pro_init(void)
diff --git a/arch/arm/mach-orion5x/ls-chl-setup.c b/arch/arm/mach-orion5x/ls-chl-setup.c
index 6ae12aa6d759..5065803ca82a 100644
--- a/arch/arm/mach-orion5x/ls-chl-setup.c
+++ b/arch/arm/mach-orion5x/ls-chl-setup.c
@@ -251,28 +251,28 @@ static struct platform_device lschl_fan_device = {
* GPIO Data
****************************************************************************/
-static struct orion5x_mpp_mode lschl_mpp_modes[] __initdata = {
- { 0, MPP_GPIO }, /* LED POWER */
- { 1, MPP_GPIO }, /* HDD POWER */
- { 2, MPP_GPIO }, /* LED ALARM */
- { 3, MPP_GPIO }, /* LED INFO */
- { 4, MPP_UNUSED },
- { 5, MPP_UNUSED },
- { 6, MPP_GPIO }, /* FAN LOCK */
- { 7, MPP_GPIO }, /* SW INIT */
- { 8, MPP_GPIO }, /* SW POWER */
- { 9, MPP_GPIO }, /* USB POWER */
- { 10, MPP_GPIO }, /* SW AUTO POWER */
- { 11, MPP_UNUSED },
- { 12, MPP_UNUSED },
- { 13, MPP_UNUSED },
- { 14, MPP_GPIO }, /* FAN HIGH */
- { 15, MPP_GPIO }, /* SW FUNC */
- { 16, MPP_GPIO }, /* FAN LOW */
- { 17, MPP_GPIO }, /* LED FUNC */
- { 18, MPP_UNUSED },
- { 19, MPP_UNUSED },
- { -1 },
+static unsigned int lschl_mpp_modes[] __initdata = {
+ MPP0_GPIO, /* LED POWER */
+ MPP1_GPIO, /* HDD POWER */
+ MPP2_GPIO, /* LED ALARM */
+ MPP3_GPIO, /* LED INFO */
+ MPP4_UNUSED,
+ MPP5_UNUSED,
+ MPP6_GPIO, /* FAN LOCK */
+ MPP7_GPIO, /* SW INIT */
+ MPP8_GPIO, /* SW POWER */
+ MPP9_GPIO, /* USB POWER */
+ MPP10_GPIO, /* SW AUTO POWER */
+ MPP11_UNUSED,
+ MPP12_UNUSED,
+ MPP13_UNUSED,
+ MPP14_GPIO, /* FAN HIGH */
+ MPP15_GPIO, /* SW FUNC */
+ MPP16_GPIO, /* FAN LOW */
+ MPP17_GPIO, /* LED FUNC */
+ MPP18_UNUSED,
+ MPP19_UNUSED,
+ 0,
};
static void __init lschl_init(void)
diff --git a/arch/arm/mach-orion5x/ls_hgl-setup.c b/arch/arm/mach-orion5x/ls_hgl-setup.c
index 7adafd79cf98..8503d0a42d41 100644
--- a/arch/arm/mach-orion5x/ls_hgl-setup.c
+++ b/arch/arm/mach-orion5x/ls_hgl-setup.c
@@ -200,28 +200,28 @@ static void ls_hgl_power_off(void)
#define LS_HGL_GPIO_HDD_POWER 1
-static struct orion5x_mpp_mode ls_hgl_mpp_modes[] __initdata = {
- { 0, MPP_GPIO }, /* LED_PWR */
- { 1, MPP_GPIO }, /* HDD_PWR */
- { 2, MPP_GPIO }, /* LED_ALARM */
- { 3, MPP_GPIO }, /* LED_INFO */
- { 4, MPP_UNUSED },
- { 5, MPP_UNUSED },
- { 6, MPP_GPIO }, /* FAN_LCK */
- { 7, MPP_GPIO }, /* INIT */
- { 8, MPP_GPIO }, /* POWER */
- { 9, MPP_GPIO }, /* USB_PWR */
- { 10, MPP_GPIO }, /* AUTO_POWER */
- { 11, MPP_UNUSED }, /* LED_ETH (dummy) */
- { 12, MPP_UNUSED },
- { 13, MPP_UNUSED },
- { 14, MPP_UNUSED },
- { 15, MPP_GPIO }, /* FUNC */
- { 16, MPP_UNUSED },
- { 17, MPP_GPIO }, /* LED_FUNC */
- { 18, MPP_UNUSED },
- { 19, MPP_UNUSED },
- { -1 },
+static unsigned int ls_hgl_mpp_modes[] __initdata = {
+ MPP0_GPIO, /* LED_PWR */
+ MPP1_GPIO, /* HDD_PWR */
+ MPP2_GPIO, /* LED_ALARM */
+ MPP3_GPIO, /* LED_INFO */
+ MPP4_UNUSED,
+ MPP5_UNUSED,
+ MPP6_GPIO, /* FAN_LCK */
+ MPP7_GPIO, /* INIT */
+ MPP8_GPIO, /* POWER */
+ MPP9_GPIO, /* USB_PWR */
+ MPP10_GPIO, /* AUTO_POWER */
+ MPP11_UNUSED, /* LED_ETH (dummy) */
+ MPP12_UNUSED,
+ MPP13_UNUSED,
+ MPP14_UNUSED,
+ MPP15_GPIO, /* FUNC */
+ MPP16_UNUSED,
+ MPP17_GPIO, /* LED_FUNC */
+ MPP18_UNUSED,
+ MPP19_UNUSED,
+ 0,
};
static void __init ls_hgl_init(void)
diff --git a/arch/arm/mach-orion5x/lsmini-setup.c b/arch/arm/mach-orion5x/lsmini-setup.c
index 869958f5c394..9c82723c05c0 100644
--- a/arch/arm/mach-orion5x/lsmini-setup.c
+++ b/arch/arm/mach-orion5x/lsmini-setup.c
@@ -201,28 +201,28 @@ static void lsmini_power_off(void)
#define LSMINI_GPIO_HDD_POWER0 1
#define LSMINI_GPIO_HDD_POWER1 19
-static struct orion5x_mpp_mode lsmini_mpp_modes[] __initdata = {
- { 0, MPP_UNUSED }, /* LED_RESERVE1 (unused) */
- { 1, MPP_GPIO }, /* HDD_PWR */
- { 2, MPP_GPIO }, /* LED_ALARM */
- { 3, MPP_GPIO }, /* LED_INFO */
- { 4, MPP_UNUSED },
- { 5, MPP_UNUSED },
- { 6, MPP_UNUSED },
- { 7, MPP_UNUSED },
- { 8, MPP_UNUSED },
- { 9, MPP_GPIO }, /* LED_FUNC */
- { 10, MPP_UNUSED },
- { 11, MPP_UNUSED }, /* LED_ETH (dummy) */
- { 12, MPP_UNUSED },
- { 13, MPP_UNUSED },
- { 14, MPP_GPIO }, /* LED_PWR */
- { 15, MPP_GPIO }, /* FUNC */
- { 16, MPP_GPIO }, /* USB_PWR */
- { 17, MPP_GPIO }, /* AUTO_POWER */
- { 18, MPP_GPIO }, /* POWER */
- { 19, MPP_GPIO }, /* HDD_PWR1 */
- { -1 },
+static unsigned int lsmini_mpp_modes[] __initdata = {
+ MPP0_UNUSED, /* LED_RESERVE1 (unused) */
+ MPP1_GPIO, /* HDD_PWR */
+ MPP2_GPIO, /* LED_ALARM */
+ MPP3_GPIO, /* LED_INFO */
+ MPP4_UNUSED,
+ MPP5_UNUSED,
+ MPP6_UNUSED,
+ MPP7_UNUSED,
+ MPP8_UNUSED,
+ MPP9_GPIO, /* LED_FUNC */
+ MPP10_UNUSED,
+ MPP11_UNUSED, /* LED_ETH (dummy) */
+ MPP12_UNUSED,
+ MPP13_UNUSED,
+ MPP14_GPIO, /* LED_PWR */
+ MPP15_GPIO, /* FUNC */
+ MPP16_GPIO, /* USB_PWR */
+ MPP17_GPIO, /* AUTO_POWER */
+ MPP18_GPIO, /* POWER */
+ MPP19_GPIO, /* HDD_PWR1 */
+ 0,
};
static void __init lsmini_init(void)
diff --git a/arch/arm/mach-orion5x/mpp.c b/arch/arm/mach-orion5x/mpp.c
index 2288207726e4..f12c41b98d46 100644
--- a/arch/arm/mach-orion5x/mpp.c
+++ b/arch/arm/mach-orion5x/mpp.c
@@ -12,154 +12,34 @@
#include <linux/init.h>
#include <linux/mbus.h>
#include <linux/io.h>
-#include <asm/gpio.h>
#include <mach/hardware.h>
-#include "common.h"
+#include <plat/mpp.h>
#include "mpp.h"
+#include "common.h"
-static int is_5181l(void)
-{
- u32 dev;
- u32 rev;
-
- orion5x_pcie_id(&dev, &rev);
-
- return !!(dev == MV88F5181_DEV_ID && rev >= MV88F5181L_REV_A0);
-}
-
-static int is_5182(void)
+static unsigned int __init orion5x_variant(void)
{
u32 dev;
u32 rev;
orion5x_pcie_id(&dev, &rev);
- return !!(dev == MV88F5182_DEV_ID);
-}
+ if (dev == MV88F5181_DEV_ID && rev >= MV88F5181L_REV_A0)
+ return MPP_F5181_MASK;
-static int is_5281(void)
-{
- u32 dev;
- u32 rev;
+ if (dev == MV88F5182_DEV_ID)
+ return MPP_F5182_MASK;
- orion5x_pcie_id(&dev, &rev);
+ if (dev == MV88F5281_DEV_ID)
+ return MPP_F5281_MASK;
- return !!(dev == MV88F5281_DEV_ID);
+ printk(KERN_ERR "MPP setup: unknown orion5x variant "
+ "(dev %#x rev %#x)\n", dev, rev);
+ return 0;
}
-static int __init determine_type_encoding(int mpp, enum orion5x_mpp_type type)
+void __init orion5x_mpp_conf(unsigned int *mpp_list)
{
- switch (type) {
- case MPP_UNUSED:
- case MPP_GPIO:
- if (mpp == 0)
- return 3;
- if (mpp >= 1 && mpp <= 15)
- return 0;
- if (mpp >= 16 && mpp <= 19) {
- if (is_5182())
- return 5;
- if (type == MPP_UNUSED)
- return 0;
- }
- return -1;
-
- case MPP_PCIE_RST_OUTn:
- if (mpp == 0)
- return 0;
- return -1;
-
- case MPP_PCI_ARB:
- if (mpp >= 0 && mpp <= 7)
- return 2;
- return -1;
-
- case MPP_PCI_PMEn:
- if (mpp == 2)
- return 3;
- return -1;
-
- case MPP_GIGE:
- if (mpp >= 8 && mpp <= 19)
- return 1;
- return -1;
-
- case MPP_NAND:
- if (is_5182() || is_5281()) {
- if (mpp >= 4 && mpp <= 7)
- return 4;
- if (mpp >= 12 && mpp <= 17)
- return 4;
- }
- return -1;
-
- case MPP_PCI_CLK:
- if (is_5181l() && mpp >= 6 && mpp <= 7)
- return 5;
- return -1;
-
- case MPP_SATA_LED:
- if (is_5182()) {
- if (mpp >= 4 && mpp <= 7)
- return 5;
- if (mpp >= 12 && mpp <= 15)
- return 5;
- }
- return -1;
-
- case MPP_UART:
- if (mpp >= 16 && mpp <= 19)
- return 0;
- return -1;
- }
-
- printk(KERN_INFO "unknown MPP type %d\n", type);
-
- return -1;
-}
-
-void __init orion5x_mpp_conf(struct orion5x_mpp_mode *mode)
-{
- u32 mpp_0_7_ctrl = readl(MPP_0_7_CTRL);
- u32 mpp_8_15_ctrl = readl(MPP_8_15_CTRL);
- u32 mpp_16_19_ctrl = readl(MPP_16_19_CTRL);
-
- for ( ; mode->mpp >= 0; mode++) {
- u32 *reg;
- int num_type;
- int shift;
-
- if (mode->mpp >= 0 && mode->mpp <= 7)
- reg = &mpp_0_7_ctrl;
- else if (mode->mpp >= 8 && mode->mpp <= 15)
- reg = &mpp_8_15_ctrl;
- else if (mode->mpp >= 16 && mode->mpp <= 19)
- reg = &mpp_16_19_ctrl;
- else {
- printk(KERN_ERR "orion5x_mpp_conf: invalid MPP "
- "(%d)\n", mode->mpp);
- continue;
- }
-
- num_type = determine_type_encoding(mode->mpp, mode->type);
- if (num_type < 0) {
- printk(KERN_ERR "orion5x_mpp_conf: invalid MPP "
- "combination (%d, %d)\n", mode->mpp,
- mode->type);
- continue;
- }
-
- shift = (mode->mpp & 7) << 2;
- *reg &= ~(0xf << shift);
- *reg |= (num_type & 0xf) << shift;
-
- if (mode->type == MPP_UNUSED && (mode->mpp < 16 || is_5182()))
- orion_gpio_set_unused(mode->mpp);
-
- orion_gpio_set_valid(mode->mpp, !!(mode->type == MPP_GPIO));
- }
-
- writel(mpp_0_7_ctrl, MPP_0_7_CTRL);
- writel(mpp_8_15_ctrl, MPP_8_15_CTRL);
- writel(mpp_16_19_ctrl, MPP_16_19_CTRL);
+ orion_mpp_conf(mpp_list, orion5x_variant(),
+ MPP_MAX, ORION5X_DEV_BUS_VIRT_BASE);
}
diff --git a/arch/arm/mach-orion5x/mpp.h b/arch/arm/mach-orion5x/mpp.h
index 290e610dc012..eac68978a2c2 100644
--- a/arch/arm/mach-orion5x/mpp.h
+++ b/arch/arm/mach-orion5x/mpp.h
@@ -1,74 +1,129 @@
#ifndef __ARCH_ORION5X_MPP_H
#define __ARCH_ORION5X_MPP_H
-enum orion5x_mpp_type {
- /*
- * This MPP is unused.
- */
- MPP_UNUSED,
-
- /*
- * This MPP pin is used as a generic GPIO pin. Valid for
- * MPPs 0-15 and device bus data pins 16-31. On 5182, also
- * valid for MPPs 16-19.
- */
- MPP_GPIO,
-
- /*
- * This MPP is used as PCIe_RST_OUTn pin. Valid for
- * MPP 0 only.
- */
- MPP_PCIE_RST_OUTn,
-
- /*
- * This MPP is used as PCI arbiter pin (REQn/GNTn).
- * Valid for MPPs 0-7 only.
- */
- MPP_PCI_ARB,
-
- /*
- * This MPP is used as PCI_PMEn pin. Valid for MPP 2 only.
- */
- MPP_PCI_PMEn,
-
- /*
- * This MPP is used as GigE half-duplex (COL, CRS) or GMII
- * (RXERR, CRS, TXERR, TXD[7:4], RXD[7:4]) pin. Valid for
- * MPPs 8-19 only.
- */
- MPP_GIGE,
-
- /*
- * This MPP is used as NAND REn/WEn pin. Valid for MPPs
- * 4-7 and 12-17 only, and only on the 5181l/5182/5281.
- */
- MPP_NAND,
-
- /*
- * This MPP is used as a PCI clock output pin. Valid for
- * MPPs 6-7 only, and only on the 5181l.
- */
- MPP_PCI_CLK,
-
- /*
- * This MPP is used as a SATA presence/activity LED.
- * Valid for MPPs 4-7 and 12-15 only, and only on the 5182.
- */
- MPP_SATA_LED,
-
- /*
- * This MPP is used as UART1 RXD/TXD/CTSn/RTSn pin.
- * Valid for MPPs 16-19 only.
- */
- MPP_UART,
-};
-
-struct orion5x_mpp_mode {
- int mpp;
- enum orion5x_mpp_type type;
-};
-
-void orion5x_mpp_conf(struct orion5x_mpp_mode *mode);
+#define MPP(_num, _sel, _in, _out, _F5181l, _F5182, _F5281) ( \
+ /* MPP number */ ((_num) & 0xff) | \
+ /* MPP select value */ (((_sel) & 0xf) << 8) | \
+ /* may be input signal */ ((!!(_in)) << 12) | \
+ /* may be output signal */ ((!!(_out)) << 13) | \
+ /* available on F5181l */ ((!!(_F5181l)) << 14) | \
+ /* available on F5182 */ ((!!(_F5182)) << 15) | \
+ /* available on F5281 */ ((!!(_F5281)) << 16))
+ /* num sel i o 5181 5182 5281 */
+
+#define MPP_F5181_MASK MPP(0, 0x0, 0, 0, 1, 0, 0)
+#define MPP_F5182_MASK MPP(0, 0x0, 0, 0, 0, 1, 0)
+#define MPP_F5281_MASK MPP(0, 0x0, 0, 0, 0, 0, 1)
+
+#define MPP0_UNUSED MPP(0, 0x3, 0, 0, 1, 1, 1)
+#define MPP0_GPIO MPP(0, 0x3, 1, 1, 1, 1, 1)
+#define MPP0_PCIE_RST_OUTn MPP(0, 0x0, 0, 0, 1, 1, 1)
+#define MPP0_PCI_ARB MPP(0, 0x2, 0, 0, 1, 1, 1)
+
+#define MPP1_UNUSED MPP(1, 0x0, 0, 0, 1, 1, 1)
+#define MPP1_GPIO MPP(1, 0x0, 1, 1, 1, 1, 1)
+#define MPP1_PCI_ARB MPP(1, 0x2, 0, 0, 1, 1, 1)
+
+#define MPP2_UNUSED MPP(2, 0x0, 0, 0, 1, 1, 1)
+#define MPP2_GPIO MPP(2, 0x0, 1, 1, 1, 1, 1)
+#define MPP2_PCI_ARB MPP(2, 0x2, 0, 0, 1, 1, 1)
+#define MPP2_PCI_PMEn MPP(2, 0x3, 0, 0, 1, 1, 1)
+
+#define MPP3_UNUSED MPP(3, 0x0, 0, 0, 1, 1, 1)
+#define MPP3_GPIO MPP(3, 0x0, 1, 1, 1, 1, 1)
+#define MPP3_PCI_ARB MPP(3, 0x2, 0, 0, 1, 1, 1)
+
+#define MPP4_UNUSED MPP(4, 0x0, 0, 0, 1, 1, 1)
+#define MPP4_GPIO MPP(4, 0x0, 1, 1, 1, 1, 1)
+#define MPP4_PCI_ARB MPP(4, 0x2, 0, 0, 1, 1, 1)
+#define MPP4_NAND MPP(4, 0x4, 0, 0, 0, 1, 1)
+#define MPP4_SATA_LED MPP(4, 0x5, 0, 0, 0, 1, 0)
+
+#define MPP5_UNUSED MPP(5, 0x0, 0, 0, 1, 1, 1)
+#define MPP5_GPIO MPP(5, 0x0, 1, 1, 1, 1, 1)
+#define MPP5_PCI_ARB MPP(5, 0x2, 0, 0, 1, 1, 1)
+#define MPP5_NAND MPP(5, 0x4, 0, 0, 0, 1, 1)
+#define MPP5_SATA_LED MPP(5, 0x5, 0, 0, 0, 1, 0)
+
+#define MPP6_UNUSED MPP(6, 0x0, 0, 0, 1, 1, 1)
+#define MPP6_GPIO MPP(6, 0x0, 1, 1, 1, 1, 1)
+#define MPP6_PCI_ARB MPP(6, 0x2, 0, 0, 1, 1, 1)
+#define MPP6_NAND MPP(6, 0x4, 0, 0, 0, 1, 1)
+#define MPP6_PCI_CLK MPP(6, 0x5, 0, 0, 1, 0, 0)
+#define MPP6_SATA_LED MPP(6, 0x5, 0, 0, 0, 1, 0)
+
+#define MPP7_UNUSED MPP(7, 0x0, 0, 0, 1, 1, 1)
+#define MPP7_GPIO MPP(7, 0x0, 1, 1, 1, 1, 1)
+#define MPP7_PCI_ARB MPP(7, 0x2, 0, 0, 1, 1, 1)
+#define MPP7_NAND MPP(7, 0x4, 0, 0, 0, 1, 1)
+#define MPP7_PCI_CLK MPP(7, 0x5, 0, 0, 1, 0, 0)
+#define MPP7_SATA_LED MPP(7, 0x5, 0, 0, 0, 1, 0)
+
+#define MPP8_UNUSED MPP(8, 0x0, 0, 0, 1, 1, 1)
+#define MPP8_GPIO MPP(8, 0x0, 1, 1, 1, 1, 1)
+#define MPP8_GIGE MPP(8, 0x1, 0, 0, 1, 1, 1)
+
+#define MPP9_UNUSED MPP(9, 0x0, 0, 0, 1, 1, 1)
+#define MPP9_GPIO MPP(9, 0x0, 0, 0, 1, 1, 1)
+#define MPP9_GIGE MPP(9, 0x1, 1, 1, 1, 1, 1)
+
+#define MPP10_UNUSED MPP(10, 0x0, 0, 0, 1, 1, 1)
+#define MPP10_GPIO MPP(10, 0x0, 1, 1, 1, 1, 1)
+#define MPP10_GIGE MPP(10, 0x1, 0, 0, 1, 1, 1)
+
+#define MPP11_UNUSED MPP(11, 0x0, 0, 0, 1, 1, 1)
+#define MPP11_GPIO MPP(11, 0x0, 1, 1, 1, 1, 1)
+#define MPP11_GIGE MPP(11, 0x1, 0, 0, 1, 1, 1)
+
+#define MPP12_UNUSED MPP(12, 0x0, 0, 0, 1, 1, 1)
+#define MPP12_GPIO MPP(12, 0x0, 1, 1, 1, 1, 1)
+#define MPP12_GIGE MPP(12, 0x1, 0, 0, 1, 1, 1)
+#define MPP12_NAND MPP(12, 0x4, 0, 0, 0, 1, 1)
+#define MPP12_SATA_LED MPP(12, 0x5, 0, 0, 0, 1, 0)
+
+#define MPP13_UNUSED MPP(13, 0x0, 0, 0, 1, 1, 1)
+#define MPP13_GPIO MPP(13, 0x0, 1, 1, 1, 1, 1)
+#define MPP13_GIGE MPP(13, 0x1, 0, 0, 1, 1, 1)
+#define MPP13_NAND MPP(13, 0x4, 0, 0, 0, 1, 1)
+#define MPP13_SATA_LED MPP(13, 0x5, 0, 0, 0, 1, 0)
+
+#define MPP14_UNUSED MPP(14, 0x0, 0, 0, 1, 1, 1)
+#define MPP14_GPIO MPP(14, 0x0, 1, 1, 1, 1, 1)
+#define MPP14_GIGE MPP(14, 0x1, 0, 0, 1, 1, 1)
+#define MPP14_NAND MPP(14, 0x4, 0, 0, 0, 1, 1)
+#define MPP14_SATA_LED MPP(14, 0x5, 0, 0, 0, 1, 0)
+
+#define MPP15_UNUSED MPP(15, 0x0, 0, 0, 1, 1, 1)
+#define MPP15_GPIO MPP(15, 0x0, 1, 1, 1, 1, 1)
+#define MPP15_GIGE MPP(15, 0x1, 0, 0, 1, 1, 1)
+#define MPP15_NAND MPP(15, 0x4, 0, 0, 0, 1, 1)
+#define MPP15_SATA_LED MPP(15, 0x5, 0, 0, 0, 1, 0)
+
+#define MPP16_UNUSED MPP(16, 0x0, 0, 0, 1, 1, 1)
+#define MPP16_GPIO MPP(16, 0x5, 1, 1, 0, 1, 0)
+#define MPP16_GIGE MPP(16, 0x1, 0, 0, 1, 1, 1)
+#define MPP16_NAND MPP(16, 0x4, 0, 0, 0, 1, 1)
+#define MPP16_UART MPP(16, 0x0, 0, 0, 0, 1, 1)
+
+#define MPP17_UNUSED MPP(17, 0x0, 0, 0, 1, 1, 1)
+#define MPP17_GPIO MPP(17, 0x5, 1, 1, 0, 1, 0)
+#define MPP17_GIGE MPP(17, 0x1, 0, 0, 1, 1, 1)
+#define MPP17_NAND MPP(17, 0x4, 0, 0, 0, 1, 1)
+#define MPP17_UART MPP(17, 0x0, 0, 0, 0, 1, 1)
+
+#define MPP18_UNUSED MPP(18, 0x0, 0, 0, 1, 1, 1)
+#define MPP18_GPIO MPP(18, 0x5, 1, 1, 0, 1, 0)
+#define MPP18_GIGE MPP(18, 0x1, 0, 0, 1, 1, 1)
+#define MPP18_UART MPP(18, 0x0, 0, 0, 0, 1, 1)
+
+#define MPP19_UNUSED MPP(19, 0x0, 0, 0, 1, 1, 1)
+#define MPP19_GPIO MPP(19, 0x5, 1, 1, 0, 1, 0)
+#define MPP19_GIGE MPP(19, 0x1, 0, 0, 1, 1, 1)
+#define MPP19_UART MPP(19, 0x0, 0, 0, 0, 1, 1)
+
+#define MPP_MAX 19
+
+void orion5x_mpp_conf(unsigned int *mpp_list);
#endif
diff --git a/arch/arm/mach-orion5x/mss2-setup.c b/arch/arm/mach-orion5x/mss2-setup.c
index b43b208153cb..59263b73d1e4 100644
--- a/arch/arm/mach-orion5x/mss2-setup.c
+++ b/arch/arm/mach-orion5x/mss2-setup.c
@@ -193,28 +193,28 @@ static void mss2_power_off(void)
/****************************************************************************
* General Setup
****************************************************************************/
-static struct orion5x_mpp_mode mss2_mpp_modes[] __initdata = {
- { 0, MPP_GPIO }, /* Power LED */
- { 1, MPP_GPIO }, /* Error LED */
- { 2, MPP_UNUSED },
- { 3, MPP_GPIO }, /* RTC interrupt */
- { 4, MPP_GPIO }, /* HDD ind. (Single/Dual)*/
- { 5, MPP_GPIO }, /* HD0 5V control */
- { 6, MPP_GPIO }, /* HD0 12V control */
- { 7, MPP_GPIO }, /* HD1 5V control */
- { 8, MPP_GPIO }, /* HD1 12V control */
- { 9, MPP_UNUSED },
- { 10, MPP_GPIO }, /* Fan control */
- { 11, MPP_GPIO }, /* Power button */
- { 12, MPP_GPIO }, /* Reset button */
- { 13, MPP_UNUSED },
- { 14, MPP_SATA_LED }, /* SATA 0 active */
- { 15, MPP_SATA_LED }, /* SATA 1 active */
- { 16, MPP_UNUSED },
- { 17, MPP_UNUSED },
- { 18, MPP_UNUSED },
- { 19, MPP_UNUSED },
- { -1 },
+static unsigned int mss2_mpp_modes[] __initdata = {
+ MPP0_GPIO, /* Power LED */
+ MPP1_GPIO, /* Error LED */
+ MPP2_UNUSED,
+ MPP3_GPIO, /* RTC interrupt */
+ MPP4_GPIO, /* HDD ind. (Single/Dual)*/
+ MPP5_GPIO, /* HD0 5V control */
+ MPP6_GPIO, /* HD0 12V control */
+ MPP7_GPIO, /* HD1 5V control */
+ MPP8_GPIO, /* HD1 12V control */
+ MPP9_UNUSED,
+ MPP10_GPIO, /* Fan control */
+ MPP11_GPIO, /* Power button */
+ MPP12_GPIO, /* Reset button */
+ MPP13_UNUSED,
+ MPP14_SATA_LED, /* SATA 0 active */
+ MPP15_SATA_LED, /* SATA 1 active */
+ MPP16_UNUSED,
+ MPP17_UNUSED,
+ MPP18_UNUSED,
+ MPP19_UNUSED,
+ 0,
};
static void __init mss2_init(void)
diff --git a/arch/arm/mach-orion5x/mv2120-setup.c b/arch/arm/mach-orion5x/mv2120-setup.c
index c55d071707f5..63ff10c3c464 100644
--- a/arch/arm/mach-orion5x/mv2120-setup.c
+++ b/arch/arm/mach-orion5x/mv2120-setup.c
@@ -108,28 +108,28 @@ static struct platform_device mv2120_button_device = {
/****************************************************************************
* General Setup
****************************************************************************/
-static struct orion5x_mpp_mode mv2120_mpp_modes[] __initdata = {
- { 0, MPP_GPIO }, /* Sys status LED */
- { 1, MPP_GPIO }, /* Sys error LED */
- { 2, MPP_GPIO }, /* OverTemp interrupt */
- { 3, MPP_GPIO }, /* RTC interrupt */
- { 4, MPP_GPIO }, /* V_LED 5V */
- { 5, MPP_GPIO }, /* V_LED 3.3V */
- { 6, MPP_UNUSED },
- { 7, MPP_UNUSED },
- { 8, MPP_GPIO }, /* SATA 0 fail LED */
- { 9, MPP_GPIO }, /* SATA 1 fail LED */
- { 10, MPP_UNUSED },
- { 11, MPP_UNUSED },
- { 12, MPP_SATA_LED }, /* SATA 0 presence */
- { 13, MPP_SATA_LED }, /* SATA 1 presence */
- { 14, MPP_SATA_LED }, /* SATA 0 active */
- { 15, MPP_SATA_LED }, /* SATA 1 active */
- { 16, MPP_UNUSED },
- { 17, MPP_GPIO }, /* Reset button */
- { 18, MPP_GPIO }, /* Power button */
- { 19, MPP_GPIO }, /* Power off */
- { -1 },
+static unsigned int mv2120_mpp_modes[] __initdata = {
+ MPP0_GPIO, /* Sys status LED */
+ MPP1_GPIO, /* Sys error LED */
+ MPP2_GPIO, /* OverTemp interrupt */
+ MPP3_GPIO, /* RTC interrupt */
+ MPP4_GPIO, /* V_LED 5V */
+ MPP5_GPIO, /* V_LED 3.3V */
+ MPP6_UNUSED,
+ MPP7_UNUSED,
+ MPP8_GPIO, /* SATA 0 fail LED */
+ MPP9_GPIO, /* SATA 1 fail LED */
+ MPP10_UNUSED,
+ MPP11_UNUSED,
+ MPP12_SATA_LED, /* SATA 0 presence */
+ MPP13_SATA_LED, /* SATA 1 presence */
+ MPP14_SATA_LED, /* SATA 0 active */
+ MPP15_SATA_LED, /* SATA 1 active */
+ MPP16_UNUSED,
+ MPP17_GPIO, /* Reset button */
+ MPP18_GPIO, /* Power button */
+ MPP19_GPIO, /* Power off */
+ 0,
};
static struct i2c_board_info __initdata mv2120_i2c_rtc = {
diff --git a/arch/arm/mach-orion5x/net2big-setup.c b/arch/arm/mach-orion5x/net2big-setup.c
index a5930f83958b..e43b39cc7fe9 100644
--- a/arch/arm/mach-orion5x/net2big-setup.c
+++ b/arch/arm/mach-orion5x/net2big-setup.c
@@ -339,28 +339,28 @@ static struct platform_device net2big_gpio_buttons = {
* General Setup
****************************************************************************/
-static struct orion5x_mpp_mode net2big_mpp_modes[] __initdata = {
- { 0, MPP_GPIO }, /* Raid mode (bit 0) */
- { 1, MPP_GPIO }, /* USB port 2 fuse (0 = Fail, 1 = Ok) */
- { 2, MPP_GPIO }, /* Raid mode (bit 1) */
- { 3, MPP_GPIO }, /* Board ID (bit 0) */
- { 4, MPP_GPIO }, /* Fan activity (0 = Off, 1 = On) */
- { 5, MPP_GPIO }, /* Fan fail detection */
- { 6, MPP_GPIO }, /* Red front LED (0 = Off, 1 = On) */
- { 7, MPP_GPIO }, /* Disable initial blinking on front LED */
- { 8, MPP_GPIO }, /* Rear power switch (on|auto) */
- { 9, MPP_GPIO }, /* Rear power switch (auto|off) */
- { 10, MPP_GPIO }, /* SATA 1 red LED (0 = Off, 1 = On) */
- { 11, MPP_GPIO }, /* SATA 0 red LED (0 = Off, 1 = On) */
- { 12, MPP_GPIO }, /* Board ID (bit 1) */
- { 13, MPP_GPIO }, /* SATA 1 blue LED blink control */
- { 14, MPP_SATA_LED },
- { 15, MPP_SATA_LED },
- { 16, MPP_GPIO }, /* Blue front LED control */
- { 17, MPP_GPIO }, /* SATA 0 blue LED blink control */
- { 18, MPP_GPIO }, /* Front button (0 = Released, 1 = Pushed ) */
- { 19, MPP_GPIO }, /* SATA{0,1} power On/Off request */
- { -1 }
+static unsigned int net2big_mpp_modes[] __initdata = {
+ MPP0_GPIO, /* Raid mode (bit 0) */
+ MPP1_GPIO, /* USB port 2 fuse (0 = Fail, 1 = Ok) */
+ MPP2_GPIO, /* Raid mode (bit 1) */
+ MPP3_GPIO, /* Board ID (bit 0) */
+ MPP4_GPIO, /* Fan activity (0 = Off, 1 = On) */
+ MPP5_GPIO, /* Fan fail detection */
+ MPP6_GPIO, /* Red front LED (0 = Off, 1 = On) */
+ MPP7_GPIO, /* Disable initial blinking on front LED */
+ MPP8_GPIO, /* Rear power switch (on|auto) */
+ MPP9_GPIO, /* Rear power switch (auto|off) */
+ MPP10_GPIO, /* SATA 1 red LED (0 = Off, 1 = On) */
+ MPP11_GPIO, /* SATA 0 red LED (0 = Off, 1 = On) */
+ MPP12_GPIO, /* Board ID (bit 1) */
+ MPP13_GPIO, /* SATA 1 blue LED blink control */
+ MPP14_SATA_LED,
+ MPP15_SATA_LED,
+ MPP16_GPIO, /* Blue front LED control */
+ MPP17_GPIO, /* SATA 0 blue LED blink control */
+ MPP18_GPIO, /* Front button (0 = Released, 1 = Pushed ) */
+ MPP19_GPIO, /* SATA{0,1} power On/Off request */
+ 0,
/* 22: USB port 1 fuse (0 = Fail, 1 = Ok) */
/* 23: SATA 0 power status */
/* 24: Board power off */
diff --git a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
index 34310ab56e29..9eec7c2375e9 100644
--- a/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
@@ -64,28 +64,28 @@ static struct platform_device rd88f5181l_fxo_nor_boot_flash = {
/*****************************************************************************
* General Setup
****************************************************************************/
-static struct orion5x_mpp_mode rd88f5181l_fxo_mpp_modes[] __initdata = {
- { 0, MPP_GPIO }, /* LED1 CardBus LED (front panel) */
- { 1, MPP_GPIO }, /* PCI_intA */
- { 2, MPP_GPIO }, /* Hard Reset / Factory Init*/
- { 3, MPP_GPIO }, /* FXS or DAA select */
- { 4, MPP_GPIO }, /* LED6 - phone LED (front panel) */
- { 5, MPP_GPIO }, /* LED5 - phone LED (front panel) */
- { 6, MPP_PCI_CLK }, /* CPU PCI refclk */
- { 7, MPP_PCI_CLK }, /* PCI/PCIe refclk */
- { 8, MPP_GPIO }, /* CardBus reset */
- { 9, MPP_GPIO }, /* GE_RXERR */
- { 10, MPP_GPIO }, /* LED2 MiniPCI LED (front panel) */
- { 11, MPP_GPIO }, /* Lifeline control */
- { 12, MPP_GIGE }, /* GE_TXD[4] */
- { 13, MPP_GIGE }, /* GE_TXD[5] */
- { 14, MPP_GIGE }, /* GE_TXD[6] */
- { 15, MPP_GIGE }, /* GE_TXD[7] */
- { 16, MPP_GIGE }, /* GE_RXD[4] */
- { 17, MPP_GIGE }, /* GE_RXD[5] */
- { 18, MPP_GIGE }, /* GE_RXD[6] */
- { 19, MPP_GIGE }, /* GE_RXD[7] */
- { -1 },
+static unsigned int rd88f5181l_fxo_mpp_modes[] __initdata = {
+ MPP0_GPIO, /* LED1 CardBus LED (front panel) */
+ MPP1_GPIO, /* PCI_intA */
+ MPP2_GPIO, /* Hard Reset / Factory Init*/
+ MPP3_GPIO, /* FXS or DAA select */
+ MPP4_GPIO, /* LED6 - phone LED (front panel) */
+ MPP5_GPIO, /* LED5 - phone LED (front panel) */
+ MPP6_PCI_CLK, /* CPU PCI refclk */
+ MPP7_PCI_CLK, /* PCI/PCIe refclk */
+ MPP8_GPIO, /* CardBus reset */
+ MPP9_GPIO, /* GE_RXERR */
+ MPP10_GPIO, /* LED2 MiniPCI LED (front panel) */
+ MPP11_GPIO, /* Lifeline control */
+ MPP12_GIGE, /* GE_TXD[4] */
+ MPP13_GIGE, /* GE_TXD[5] */
+ MPP14_GIGE, /* GE_TXD[6] */
+ MPP15_GIGE, /* GE_TXD[7] */
+ MPP16_GIGE, /* GE_RXD[4] */
+ MPP17_GIGE, /* GE_RXD[5] */
+ MPP18_GIGE, /* GE_RXD[6] */
+ MPP19_GIGE, /* GE_RXD[7] */
+ 0,
};
static struct mv643xx_eth_platform_data rd88f5181l_fxo_eth_data = {
diff --git a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
index c1f79fa014ed..0cc90bbfd326 100644
--- a/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
@@ -65,28 +65,28 @@ static struct platform_device rd88f5181l_ge_nor_boot_flash = {
/*****************************************************************************
* General Setup
****************************************************************************/
-static struct orion5x_mpp_mode rd88f5181l_ge_mpp_modes[] __initdata = {
- { 0, MPP_GPIO }, /* LED1 */
- { 1, MPP_GPIO }, /* LED5 */
- { 2, MPP_GPIO }, /* LED4 */
- { 3, MPP_GPIO }, /* LED3 */
- { 4, MPP_GPIO }, /* PCI_intA */
- { 5, MPP_GPIO }, /* RTC interrupt */
- { 6, MPP_PCI_CLK }, /* CPU PCI refclk */
- { 7, MPP_PCI_CLK }, /* PCI/PCIe refclk */
- { 8, MPP_GPIO }, /* 88e6131 interrupt */
- { 9, MPP_GPIO }, /* GE_RXERR */
- { 10, MPP_GPIO }, /* PCI_intB */
- { 11, MPP_GPIO }, /* LED2 */
- { 12, MPP_GIGE }, /* GE_TXD[4] */
- { 13, MPP_GIGE }, /* GE_TXD[5] */
- { 14, MPP_GIGE }, /* GE_TXD[6] */
- { 15, MPP_GIGE }, /* GE_TXD[7] */
- { 16, MPP_GIGE }, /* GE_RXD[4] */
- { 17, MPP_GIGE }, /* GE_RXD[5] */
- { 18, MPP_GIGE }, /* GE_RXD[6] */
- { 19, MPP_GIGE }, /* GE_RXD[7] */
- { -1 },
+static unsigned int rd88f5181l_ge_mpp_modes[] __initdata = {
+ MPP0_GPIO, /* LED1 */
+ MPP1_GPIO, /* LED5 */
+ MPP2_GPIO, /* LED4 */
+ MPP3_GPIO, /* LED3 */
+ MPP4_GPIO, /* PCI_intA */
+ MPP5_GPIO, /* RTC interrupt */
+ MPP6_PCI_CLK, /* CPU PCI refclk */
+ MPP7_PCI_CLK, /* PCI/PCIe refclk */
+ MPP8_GPIO, /* 88e6131 interrupt */
+ MPP9_GPIO, /* GE_RXERR */
+ MPP10_GPIO, /* PCI_intB */
+ MPP11_GPIO, /* LED2 */
+ MPP12_GIGE, /* GE_TXD[4] */
+ MPP13_GIGE, /* GE_TXD[5] */
+ MPP14_GIGE, /* GE_TXD[6] */
+ MPP15_GIGE, /* GE_TXD[7] */
+ MPP16_GIGE, /* GE_RXD[4] */
+ MPP17_GIGE, /* GE_RXD[5] */
+ MPP18_GIGE, /* GE_RXD[6] */
+ MPP19_GIGE, /* GE_RXD[7] */
+ 0,
};
static struct mv643xx_eth_platform_data rd88f5181l_ge_eth_data = {
diff --git a/arch/arm/mach-orion5x/rd88f5182-setup.c b/arch/arm/mach-orion5x/rd88f5182-setup.c
index 4fc46772a087..48da39b9bdb0 100644
--- a/arch/arm/mach-orion5x/rd88f5182-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5182-setup.c
@@ -241,28 +241,28 @@ static struct mv_sata_platform_data rd88f5182_sata_data = {
/*****************************************************************************
* General Setup
****************************************************************************/
-static struct orion5x_mpp_mode rd88f5182_mpp_modes[] __initdata = {
- { 0, MPP_GPIO }, /* Debug Led */
- { 1, MPP_GPIO }, /* Reset Switch */
- { 2, MPP_UNUSED },
- { 3, MPP_GPIO }, /* RTC Int */
- { 4, MPP_GPIO },
- { 5, MPP_GPIO },
- { 6, MPP_GPIO }, /* PCI_intA */
- { 7, MPP_GPIO }, /* PCI_intB */
- { 8, MPP_UNUSED },
- { 9, MPP_UNUSED },
- { 10, MPP_UNUSED },
- { 11, MPP_UNUSED },
- { 12, MPP_SATA_LED }, /* SATA 0 presence */
- { 13, MPP_SATA_LED }, /* SATA 1 presence */
- { 14, MPP_SATA_LED }, /* SATA 0 active */
- { 15, MPP_SATA_LED }, /* SATA 1 active */
- { 16, MPP_UNUSED },
- { 17, MPP_UNUSED },
- { 18, MPP_UNUSED },
- { 19, MPP_UNUSED },
- { -1 },
+static unsigned int rd88f5182_mpp_modes[] __initdata = {
+ MPP0_GPIO, /* Debug Led */
+ MPP1_GPIO, /* Reset Switch */
+ MPP2_UNUSED,
+ MPP3_GPIO, /* RTC Int */
+ MPP4_GPIO,
+ MPP5_GPIO,
+ MPP6_GPIO, /* PCI_intA */
+ MPP7_GPIO, /* PCI_intB */
+ MPP8_UNUSED,
+ MPP9_UNUSED,
+ MPP10_UNUSED,
+ MPP11_UNUSED,
+ MPP12_SATA_LED, /* SATA 0 presence */
+ MPP13_SATA_LED, /* SATA 1 presence */
+ MPP14_SATA_LED, /* SATA 0 active */
+ MPP15_SATA_LED, /* SATA 1 active */
+ MPP16_UNUSED,
+ MPP17_UNUSED,
+ MPP18_UNUSED,
+ MPP19_UNUSED,
+ 0,
};
static void __init rd88f5182_init(void)
diff --git a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
index b080c6966d10..ad2eba9286ad 100644
--- a/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
+++ b/arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
@@ -27,7 +27,6 @@
#include <asm/mach/pci.h>
#include <mach/orion5x.h>
#include "common.h"
-#include "mpp.h"
static struct mv643xx_eth_platform_data rd88f6183ap_ge_eth_data = {
.phy_addr = -1,
diff --git a/arch/arm/mach-orion5x/terastation_pro2-setup.c b/arch/arm/mach-orion5x/terastation_pro2-setup.c
index 616004143912..29ce826c3c21 100644
--- a/arch/arm/mach-orion5x/terastation_pro2-setup.c
+++ b/arch/arm/mach-orion5x/terastation_pro2-setup.c
@@ -295,28 +295,28 @@ static void tsp2_power_off(void)
/*****************************************************************************
* General Setup
****************************************************************************/
-static struct orion5x_mpp_mode tsp2_mpp_modes[] __initdata = {
- { 0, MPP_PCIE_RST_OUTn },
- { 1, MPP_UNUSED },
- { 2, MPP_UNUSED },
- { 3, MPP_UNUSED },
- { 4, MPP_NAND }, /* BOOT NAND Flash REn */
- { 5, MPP_NAND }, /* BOOT NAND Flash WEn */
- { 6, MPP_NAND }, /* BOOT NAND Flash HREn[0] */
- { 7, MPP_NAND }, /* BOOT NAND Flash WEn[0] */
- { 8, MPP_GPIO }, /* MICON int */
- { 9, MPP_GPIO }, /* RTC int */
- { 10, MPP_UNUSED },
- { 11, MPP_GPIO }, /* PCI Int A */
- { 12, MPP_UNUSED },
- { 13, MPP_GPIO }, /* UPS on UART0 enable */
- { 14, MPP_GPIO }, /* UPS low battery detection */
- { 15, MPP_UNUSED },
- { 16, MPP_UART }, /* UART1 RXD */
- { 17, MPP_UART }, /* UART1 TXD */
- { 18, MPP_UART }, /* UART1 CTSn */
- { 19, MPP_UART }, /* UART1 RTSn */
- { -1 },
+static unsigned int tsp2_mpp_modes[] __initdata = {
+ MPP0_PCIE_RST_OUTn,
+ MPP1_UNUSED,
+ MPP2_UNUSED,
+ MPP3_UNUSED,
+ MPP4_NAND, /* BOOT NAND Flash REn */
+ MPP5_NAND, /* BOOT NAND Flash WEn */
+ MPP6_NAND, /* BOOT NAND Flash HREn[0] */
+ MPP7_NAND, /* BOOT NAND Flash WEn[0] */
+ MPP8_GPIO, /* MICON int */
+ MPP9_GPIO, /* RTC int */
+ MPP10_UNUSED,
+ MPP11_GPIO, /* PCI Int A */
+ MPP12_UNUSED,
+ MPP13_GPIO, /* UPS on UART0 enable */
+ MPP14_GPIO, /* UPS low battery detection */
+ MPP15_UNUSED,
+ MPP16_UART, /* UART1 RXD */
+ MPP17_UART, /* UART1 TXD */
+ MPP18_UART, /* UART1 CTSn */
+ MPP19_UART, /* UART1 RTSn */
+ 0,
};
static void __init tsp2_init(void)
diff --git a/arch/arm/mach-orion5x/ts209-setup.c b/arch/arm/mach-orion5x/ts209-setup.c
index e6d64494d3de..47162fd5f044 100644
--- a/arch/arm/mach-orion5x/ts209-setup.c
+++ b/arch/arm/mach-orion5x/ts209-setup.c
@@ -244,28 +244,28 @@ static struct mv_sata_platform_data qnap_ts209_sata_data = {
* General Setup
****************************************************************************/
-static struct orion5x_mpp_mode ts209_mpp_modes[] __initdata = {
- { 0, MPP_UNUSED },
- { 1, MPP_GPIO }, /* USB copy button */
- { 2, MPP_GPIO }, /* Load defaults button */
- { 3, MPP_GPIO }, /* GPIO RTC */
- { 4, MPP_UNUSED },
- { 5, MPP_UNUSED },
- { 6, MPP_GPIO }, /* PCI Int A */
- { 7, MPP_GPIO }, /* PCI Int B */
- { 8, MPP_UNUSED },
- { 9, MPP_UNUSED },
- { 10, MPP_UNUSED },
- { 11, MPP_UNUSED },
- { 12, MPP_SATA_LED }, /* SATA 0 presence */
- { 13, MPP_SATA_LED }, /* SATA 1 presence */
- { 14, MPP_SATA_LED }, /* SATA 0 active */
- { 15, MPP_SATA_LED }, /* SATA 1 active */
- { 16, MPP_UART }, /* UART1 RXD */
- { 17, MPP_UART }, /* UART1 TXD */
- { 18, MPP_GPIO }, /* SW_RST */
- { 19, MPP_UNUSED },
- { -1 },
+static unsigned int ts209_mpp_modes[] __initdata = {
+ MPP0_UNUSED,
+ MPP1_GPIO, /* USB copy button */
+ MPP2_GPIO, /* Load defaults button */
+ MPP3_GPIO, /* GPIO RTC */
+ MPP4_UNUSED,
+ MPP5_UNUSED,
+ MPP6_GPIO, /* PCI Int A */
+ MPP7_GPIO, /* PCI Int B */
+ MPP8_UNUSED,
+ MPP9_UNUSED,
+ MPP10_UNUSED,
+ MPP11_UNUSED,
+ MPP12_SATA_LED, /* SATA 0 presence */
+ MPP13_SATA_LED, /* SATA 1 presence */
+ MPP14_SATA_LED, /* SATA 0 active */
+ MPP15_SATA_LED, /* SATA 1 active */
+ MPP16_UART, /* UART1 RXD */
+ MPP17_UART, /* UART1 TXD */
+ MPP18_GPIO, /* SW_RST */
+ MPP19_UNUSED,
+ 0,
};
static void __init qnap_ts209_init(void)
diff --git a/arch/arm/mach-orion5x/ts409-setup.c b/arch/arm/mach-orion5x/ts409-setup.c
index 9eac8192d923..5aacc7ac5cf4 100644
--- a/arch/arm/mach-orion5x/ts409-setup.c
+++ b/arch/arm/mach-orion5x/ts409-setup.c
@@ -242,28 +242,28 @@ static struct platform_device qnap_ts409_button_device = {
/*****************************************************************************
* General Setup
****************************************************************************/
-static struct orion5x_mpp_mode ts409_mpp_modes[] __initdata = {
- { 0, MPP_UNUSED },
- { 1, MPP_UNUSED },
- { 2, MPP_UNUSED },
- { 3, MPP_UNUSED },
- { 4, MPP_GPIO }, /* HDD 1 status */
- { 5, MPP_GPIO }, /* HDD 2 status */
- { 6, MPP_GPIO }, /* HDD 3 status */
- { 7, MPP_GPIO }, /* HDD 4 status */
- { 8, MPP_UNUSED },
- { 9, MPP_UNUSED },
- { 10, MPP_GPIO }, /* RTC int */
- { 11, MPP_UNUSED },
- { 12, MPP_UNUSED },
- { 13, MPP_UNUSED },
- { 14, MPP_GPIO }, /* SW_RST */
- { 15, MPP_GPIO }, /* USB copy button */
- { 16, MPP_UART }, /* UART1 RXD */
- { 17, MPP_UART }, /* UART1 TXD */
- { 18, MPP_UNUSED },
- { 19, MPP_UNUSED },
- { -1 },
+static unsigned int ts409_mpp_modes[] __initdata = {
+ MPP0_UNUSED,
+ MPP1_UNUSED,
+ MPP2_UNUSED,
+ MPP3_UNUSED,
+ MPP4_GPIO, /* HDD 1 status */
+ MPP5_GPIO, /* HDD 2 status */
+ MPP6_GPIO, /* HDD 3 status */
+ MPP7_GPIO, /* HDD 4 status */
+ MPP8_UNUSED,
+ MPP9_UNUSED,
+ MPP10_GPIO, /* RTC int */
+ MPP11_UNUSED,
+ MPP12_UNUSED,
+ MPP13_UNUSED,
+ MPP14_GPIO, /* SW_RST */
+ MPP15_GPIO, /* USB copy button */
+ MPP16_UART, /* UART1 RXD */
+ MPP17_UART, /* UART1 TXD */
+ MPP18_UNUSED,
+ MPP19_UNUSED,
+ 0,
};
static void __init qnap_ts409_init(void)
diff --git a/arch/arm/mach-orion5x/ts78xx-setup.c b/arch/arm/mach-orion5x/ts78xx-setup.c
index edb1dd2d1611..6b7b54116f30 100644
--- a/arch/arm/mach-orion5x/ts78xx-setup.c
+++ b/arch/arm/mach-orion5x/ts78xx-setup.c
@@ -557,27 +557,27 @@ static struct kobj_attribute ts78xx_fpga_attr =
/*****************************************************************************
* General Setup
****************************************************************************/
-static struct orion5x_mpp_mode ts78xx_mpp_modes[] __initdata = {
- { 0, MPP_UNUSED },
- { 1, MPP_GPIO }, /* JTAG Clock */
- { 2, MPP_GPIO }, /* JTAG Data In */
- { 3, MPP_GPIO }, /* Lat ECP2 256 FPGA - PB2B */
- { 4, MPP_GPIO }, /* JTAG Data Out */
- { 5, MPP_GPIO }, /* JTAG TMS */
- { 6, MPP_GPIO }, /* Lat ECP2 256 FPGA - PB31A_CLK4+ */
- { 7, MPP_GPIO }, /* Lat ECP2 256 FPGA - PB22B */
- { 8, MPP_UNUSED },
- { 9, MPP_UNUSED },
- { 10, MPP_UNUSED },
- { 11, MPP_UNUSED },
- { 12, MPP_UNUSED },
- { 13, MPP_UNUSED },
- { 14, MPP_UNUSED },
- { 15, MPP_UNUSED },
- { 16, MPP_UART },
- { 17, MPP_UART },
- { 18, MPP_UART },
- { 19, MPP_UART },
+static unsigned int ts78xx_mpp_modes[] __initdata = {
+ MPP0_UNUSED,
+ MPP1_GPIO, /* JTAG Clock */
+ MPP2_GPIO, /* JTAG Data In */
+ MPP3_GPIO, /* Lat ECP2 256 FPGA - PB2B */
+ MPP4_GPIO, /* JTAG Data Out */
+ MPP5_GPIO, /* JTAG TMS */
+ MPP6_GPIO, /* Lat ECP2 256 FPGA - PB31A_CLK4+ */
+ MPP7_GPIO, /* Lat ECP2 256 FPGA - PB22B */
+ MPP8_UNUSED,
+ MPP9_UNUSED,
+ MPP10_UNUSED,
+ MPP11_UNUSED,
+ MPP12_UNUSED,
+ MPP13_UNUSED,
+ MPP14_UNUSED,
+ MPP15_UNUSED,
+ MPP16_UART,
+ MPP17_UART,
+ MPP18_UART,
+ MPP19_UART,
/*
* MPP[20] PCI Clock Out 1
* MPP[21] PCI Clock Out 0
@@ -586,7 +586,7 @@ static struct orion5x_mpp_mode ts78xx_mpp_modes[] __initdata = {
* MPP[24] Unused
* MPP[25] Unused
*/
- { -1 },
+ 0,
};
static void __init ts78xx_init(void)
diff --git a/arch/arm/mach-orion5x/wnr854t-setup.c b/arch/arm/mach-orion5x/wnr854t-setup.c
index 4e5216be0745..444a1c7fdfd6 100644
--- a/arch/arm/mach-orion5x/wnr854t-setup.c
+++ b/arch/arm/mach-orion5x/wnr854t-setup.c
@@ -24,28 +24,28 @@
#include "common.h"
#include "mpp.h"
-static struct orion5x_mpp_mode wnr854t_mpp_modes[] __initdata = {
- { 0, MPP_GPIO }, /* Power LED green (0=on) */
- { 1, MPP_GPIO }, /* Reset Button (0=off) */
- { 2, MPP_GPIO }, /* Power LED blink (0=off) */
- { 3, MPP_GPIO }, /* WAN Status LED amber (0=off) */
- { 4, MPP_GPIO }, /* PCI int */
- { 5, MPP_GPIO }, /* ??? */
- { 6, MPP_GPIO }, /* ??? */
- { 7, MPP_GPIO }, /* ??? */
- { 8, MPP_UNUSED }, /* ??? */
- { 9, MPP_GIGE }, /* GE_RXERR */
- { 10, MPP_UNUSED }, /* ??? */
- { 11, MPP_UNUSED }, /* ??? */
- { 12, MPP_GIGE }, /* GE_TXD[4] */
- { 13, MPP_GIGE }, /* GE_TXD[5] */
- { 14, MPP_GIGE }, /* GE_TXD[6] */
- { 15, MPP_GIGE }, /* GE_TXD[7] */
- { 16, MPP_GIGE }, /* GE_RXD[4] */
- { 17, MPP_GIGE }, /* GE_RXD[5] */
- { 18, MPP_GIGE }, /* GE_RXD[6] */
- { 19, MPP_GIGE }, /* GE_RXD[7] */
- { -1 },
+static unsigned int wnr854t_mpp_modes[] __initdata = {
+ MPP0_GPIO, /* Power LED green (0=on) */
+ MPP1_GPIO, /* Reset Button (0=off) */
+ MPP2_GPIO, /* Power LED blink (0=off) */
+ MPP3_GPIO, /* WAN Status LED amber (0=off) */
+ MPP4_GPIO, /* PCI int */
+ MPP5_GPIO, /* ??? */
+ MPP6_GPIO, /* ??? */
+ MPP7_GPIO, /* ??? */
+ MPP8_UNUSED, /* ??? */
+ MPP9_GIGE, /* GE_RXERR */
+ MPP10_UNUSED, /* ??? */
+ MPP11_UNUSED, /* ??? */
+ MPP12_GIGE, /* GE_TXD[4] */
+ MPP13_GIGE, /* GE_TXD[5] */
+ MPP14_GIGE, /* GE_TXD[6] */
+ MPP15_GIGE, /* GE_TXD[7] */
+ MPP16_GIGE, /* GE_RXD[4] */
+ MPP17_GIGE, /* GE_RXD[5] */
+ MPP18_GIGE, /* GE_RXD[6] */
+ MPP19_GIGE, /* GE_RXD[7] */
+ 0,
};
/*
diff --git a/arch/arm/mach-orion5x/wrt350n-v2-setup.c b/arch/arm/mach-orion5x/wrt350n-v2-setup.c
index fab79d09cc5c..d1952be0ae1c 100644
--- a/arch/arm/mach-orion5x/wrt350n-v2-setup.c
+++ b/arch/arm/mach-orion5x/wrt350n-v2-setup.c
@@ -101,28 +101,28 @@ static struct platform_device wrt350n_v2_button_device = {
/*
* General setup
*/
-static struct orion5x_mpp_mode wrt350n_v2_mpp_modes[] __initdata = {
- { 0, MPP_GPIO }, /* Power LED green (0=on) */
- { 1, MPP_GPIO }, /* Security LED (0=on) */
- { 2, MPP_GPIO }, /* Internal Button (0=on) */
- { 3, MPP_GPIO }, /* Reset Button (0=on) */
- { 4, MPP_GPIO }, /* PCI int */
- { 5, MPP_GPIO }, /* Power LED orange (0=on) */
- { 6, MPP_GPIO }, /* USB LED (0=on) */
- { 7, MPP_GPIO }, /* Wireless LED (0=on) */
- { 8, MPP_UNUSED }, /* ??? */
- { 9, MPP_GIGE }, /* GE_RXERR */
- { 10, MPP_UNUSED }, /* ??? */
- { 11, MPP_UNUSED }, /* ??? */
- { 12, MPP_GIGE }, /* GE_TXD[4] */
- { 13, MPP_GIGE }, /* GE_TXD[5] */
- { 14, MPP_GIGE }, /* GE_TXD[6] */
- { 15, MPP_GIGE }, /* GE_TXD[7] */
- { 16, MPP_GIGE }, /* GE_RXD[4] */
- { 17, MPP_GIGE }, /* GE_RXD[5] */
- { 18, MPP_GIGE }, /* GE_RXD[6] */
- { 19, MPP_GIGE }, /* GE_RXD[7] */
- { -1 },
+static unsigned int wrt350n_v2_mpp_modes[] __initdata = {
+ MPP0_GPIO, /* Power LED green (0=on) */
+ MPP1_GPIO, /* Security LED (0=on) */
+ MPP2_GPIO, /* Internal Button (0=on) */
+ MPP3_GPIO, /* Reset Button (0=on) */
+ MPP4_GPIO, /* PCI int */
+ MPP5_GPIO, /* Power LED orange (0=on) */
+ MPP6_GPIO, /* USB LED (0=on) */
+ MPP7_GPIO, /* Wireless LED (0=on) */
+ MPP8_UNUSED, /* ??? */
+ MPP9_GIGE, /* GE_RXERR */
+ MPP10_UNUSED, /* ??? */
+ MPP11_UNUSED, /* ??? */
+ MPP12_GIGE, /* GE_TXD[4] */
+ MPP13_GIGE, /* GE_TXD[5] */
+ MPP14_GIGE, /* GE_TXD[6] */
+ MPP15_GIGE, /* GE_TXD[7] */
+ MPP16_GIGE, /* GE_RXD[4] */
+ MPP17_GIGE, /* GE_RXD[5] */
+ MPP18_GIGE, /* GE_RXD[6] */
+ MPP19_GIGE, /* GE_RXD[7] */
+ 0,
};
/*
diff --git a/arch/arm/mach-pxa/balloon3.c b/arch/arm/mach-pxa/balloon3.c
index bfbecec6d05f..810a982a66f8 100644
--- a/arch/arm/mach-pxa/balloon3.c
+++ b/arch/arm/mach-pxa/balloon3.c
@@ -15,7 +15,6 @@
#include <linux/init.h>
#include <linux/platform_device.h>
-#include <linux/sysdev.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/bitops.h>
diff --git a/arch/arm/mach-pxa/clock-pxa2xx.c b/arch/arm/mach-pxa/clock-pxa2xx.c
index 1ce090448493..1d5859d9a0e3 100644
--- a/arch/arm/mach-pxa/clock-pxa2xx.c
+++ b/arch/arm/mach-pxa/clock-pxa2xx.c
@@ -9,7 +9,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <mach/pxa2xx-regs.h>
@@ -33,32 +33,22 @@ const struct clkops clk_pxa2xx_cken_ops = {
#ifdef CONFIG_PM
static uint32_t saved_cken;
-static int pxa2xx_clock_suspend(struct sys_device *d, pm_message_t state)
+static int pxa2xx_clock_suspend(void)
{
saved_cken = CKEN;
return 0;
}
-static int pxa2xx_clock_resume(struct sys_device *d)
+static void pxa2xx_clock_resume(void)
{
CKEN = saved_cken;
- return 0;
}
#else
#define pxa2xx_clock_suspend NULL
#define pxa2xx_clock_resume NULL
#endif
-struct sysdev_class pxa2xx_clock_sysclass = {
- .name = "pxa2xx-clock",
+struct syscore_ops pxa2xx_clock_syscore_ops = {
.suspend = pxa2xx_clock_suspend,
.resume = pxa2xx_clock_resume,
};
-
-static int __init pxa2xx_clock_init(void)
-{
- if (cpu_is_pxa2xx())
- return sysdev_class_register(&pxa2xx_clock_sysclass);
- return 0;
-}
-postcore_initcall(pxa2xx_clock_init);
diff --git a/arch/arm/mach-pxa/clock-pxa3xx.c b/arch/arm/mach-pxa/clock-pxa3xx.c
index 3f864cd0bd28..2a37a9a8f621 100644
--- a/arch/arm/mach-pxa/clock-pxa3xx.c
+++ b/arch/arm/mach-pxa/clock-pxa3xx.c
@@ -10,6 +10,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/syscore_ops.h>
#include <mach/smemc.h>
#include <mach/pxa3xx-regs.h>
@@ -182,7 +183,7 @@ const struct clkops clk_pxa3xx_pout_ops = {
static uint32_t cken[2];
static uint32_t accr;
-static int pxa3xx_clock_suspend(struct sys_device *d, pm_message_t state)
+static int pxa3xx_clock_suspend(void)
{
cken[0] = CKENA;
cken[1] = CKENB;
@@ -190,28 +191,18 @@ static int pxa3xx_clock_suspend(struct sys_device *d, pm_message_t state)
return 0;
}
-static int pxa3xx_clock_resume(struct sys_device *d)
+static void pxa3xx_clock_resume(void)
{
ACCR = accr;
CKENA = cken[0];
CKENB = cken[1];
- return 0;
}
#else
#define pxa3xx_clock_suspend NULL
#define pxa3xx_clock_resume NULL
#endif
-struct sysdev_class pxa3xx_clock_sysclass = {
- .name = "pxa3xx-clock",
+struct syscore_ops pxa3xx_clock_syscore_ops = {
.suspend = pxa3xx_clock_suspend,
.resume = pxa3xx_clock_resume,
};
-
-static int __init pxa3xx_clock_init(void)
-{
- if (cpu_is_pxa3xx() || cpu_is_pxa95x())
- return sysdev_class_register(&pxa3xx_clock_sysclass);
- return 0;
-}
-postcore_initcall(pxa3xx_clock_init);
diff --git a/arch/arm/mach-pxa/clock.h b/arch/arm/mach-pxa/clock.h
index f9f349a21b54..1f2fb9c43f06 100644
--- a/arch/arm/mach-pxa/clock.h
+++ b/arch/arm/mach-pxa/clock.h
@@ -1,5 +1,5 @@
#include <linux/clkdev.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
struct clkops {
void (*enable)(struct clk *);
@@ -54,7 +54,7 @@ extern const struct clkops clk_pxa2xx_cken_ops;
void clk_pxa2xx_cken_enable(struct clk *clk);
void clk_pxa2xx_cken_disable(struct clk *clk);
-extern struct sysdev_class pxa2xx_clock_sysclass;
+extern struct syscore_ops pxa2xx_clock_syscore_ops;
#if defined(CONFIG_PXA3xx) || defined(CONFIG_PXA95x)
#define DEFINE_PXA3_CKEN(_name, _cken, _rate, _delay) \
@@ -74,5 +74,6 @@ extern const struct clkops clk_pxa3xx_smemc_ops;
extern void clk_pxa3xx_cken_enable(struct clk *);
extern void clk_pxa3xx_cken_disable(struct clk *);
-extern struct sysdev_class pxa3xx_clock_sysclass;
+extern struct syscore_ops pxa3xx_clock_syscore_ops;
+
#endif
diff --git a/arch/arm/mach-pxa/cm-x270.c b/arch/arm/mach-pxa/cm-x270.c
index b88d601a8090..13518a705399 100644
--- a/arch/arm/mach-pxa/cm-x270.c
+++ b/arch/arm/mach-pxa/cm-x270.c
@@ -10,7 +10,6 @@
*/
#include <linux/platform_device.h>
-#include <linux/sysdev.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/delay.h>
diff --git a/arch/arm/mach-pxa/cm-x2xx-pci.c b/arch/arm/mach-pxa/cm-x2xx-pci.c
index 8b1a30959fae..1afc0fb7d6d5 100644
--- a/arch/arm/mach-pxa/cm-x2xx-pci.c
+++ b/arch/arm/mach-pxa/cm-x2xx-pci.c
@@ -29,33 +29,6 @@
unsigned long it8152_base_address;
static int cmx2xx_it8152_irq_gpio;
-/*
- * Only first 64MB of memory can be accessed via PCI.
- * We use GFP_DMA to allocate safe buffers to do map/unmap.
- * This is really ugly and we need a better way of specifying
- * DMA-capable regions of memory.
- */
-void __init cmx2xx_pci_adjust_zones(unsigned long *zone_size,
- unsigned long *zhole_size)
-{
- unsigned int sz = SZ_64M >> PAGE_SHIFT;
-
- if (machine_is_armcore()) {
- pr_info("Adjusting zones for CM-X2XX\n");
-
- /*
- * Only adjust if > 64M on current system
- */
- if (zone_size[0] <= sz)
- return;
-
- zone_size[1] = zone_size[0] - sz;
- zone_size[0] = sz;
- zhole_size[1] = zhole_size[0];
- zhole_size[0] = 0;
- }
-}
-
static void cmx2xx_it8152_irq_demux(unsigned int irq, struct irq_desc *desc)
{
/* clear our parent irq */
diff --git a/arch/arm/mach-pxa/cm-x2xx.c b/arch/arm/mach-pxa/cm-x2xx.c
index 8225e2e58c6e..a10996782476 100644
--- a/arch/arm/mach-pxa/cm-x2xx.c
+++ b/arch/arm/mach-pxa/cm-x2xx.c
@@ -10,7 +10,7 @@
*/
#include <linux/platform_device.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/irq.h>
#include <linux/gpio.h>
@@ -388,7 +388,7 @@ static inline void cmx2xx_init_display(void) {}
#ifdef CONFIG_PM
static unsigned long sleep_save_msc[10];
-static int cmx2xx_suspend(struct sys_device *dev, pm_message_t state)
+static int cmx2xx_suspend(void)
{
cmx2xx_pci_suspend();
@@ -412,7 +412,7 @@ static int cmx2xx_suspend(struct sys_device *dev, pm_message_t state)
return 0;
}
-static int cmx2xx_resume(struct sys_device *dev)
+static void cmx2xx_resume(void)
{
cmx2xx_pci_resume();
@@ -420,27 +420,18 @@ static int cmx2xx_resume(struct sys_device *dev)
__raw_writel(sleep_save_msc[0], MSC0);
__raw_writel(sleep_save_msc[1], MSC1);
__raw_writel(sleep_save_msc[2], MSC2);
-
- return 0;
}
-static struct sysdev_class cmx2xx_pm_sysclass = {
- .name = "pm",
+static struct syscore_ops cmx2xx_pm_syscore_ops = {
.resume = cmx2xx_resume,
.suspend = cmx2xx_suspend,
};
-static struct sys_device cmx2xx_pm_device = {
- .cls = &cmx2xx_pm_sysclass,
-};
-
static int __init cmx2xx_pm_init(void)
{
- int error;
- error = sysdev_class_register(&cmx2xx_pm_sysclass);
- if (error == 0)
- error = sysdev_register(&cmx2xx_pm_device);
- return error;
+ register_syscore_ops(&cmx2xx_pm_syscore_ops);
+
+ return 0;
}
#else
static int __init cmx2xx_pm_init(void) { return 0; }
diff --git a/arch/arm/mach-pxa/colibri-evalboard.c b/arch/arm/mach-pxa/colibri-evalboard.c
index 81c3c433e2d6..d28e802e2448 100644
--- a/arch/arm/mach-pxa/colibri-evalboard.c
+++ b/arch/arm/mach-pxa/colibri-evalboard.c
@@ -13,7 +13,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
-#include <linux/sysdev.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <asm/mach-types.h>
diff --git a/arch/arm/mach-pxa/colibri-pxa270-income.c b/arch/arm/mach-pxa/colibri-pxa270-income.c
index 44c1b77ece67..80538b8806ed 100644
--- a/arch/arm/mach-pxa/colibri-pxa270-income.c
+++ b/arch/arm/mach-pxa/colibri-pxa270-income.c
@@ -22,7 +22,6 @@
#include <linux/platform_device.h>
#include <linux/pwm_backlight.h>
#include <linux/i2c/pxa-i2c.h>
-#include <linux/sysdev.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
diff --git a/arch/arm/mach-pxa/colibri-pxa270.c b/arch/arm/mach-pxa/colibri-pxa270.c
index 6fc5d328ba7f..7545a48ed88b 100644
--- a/arch/arm/mach-pxa/colibri-pxa270.c
+++ b/arch/arm/mach-pxa/colibri-pxa270.c
@@ -17,7 +17,6 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
#include <linux/platform_device.h>
-#include <linux/sysdev.h>
#include <linux/ucb1400.h>
#include <asm/mach/arch.h>
diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h
index a079d8baa45a..e6c9344a95ae 100644
--- a/arch/arm/mach-pxa/generic.h
+++ b/arch/arm/mach-pxa/generic.h
@@ -61,10 +61,10 @@ extern unsigned pxa3xx_get_clk_frequency_khz(int);
#define pxa3xx_get_clk_frequency_khz(x) (0)
#endif
-extern struct sysdev_class pxa_irq_sysclass;
-extern struct sysdev_class pxa_gpio_sysclass;
-extern struct sysdev_class pxa2xx_mfp_sysclass;
-extern struct sysdev_class pxa3xx_mfp_sysclass;
+extern struct syscore_ops pxa_irq_syscore_ops;
+extern struct syscore_ops pxa_gpio_syscore_ops;
+extern struct syscore_ops pxa2xx_mfp_syscore_ops;
+extern struct syscore_ops pxa3xx_mfp_syscore_ops;
void __init pxa_set_ffuart_info(void *info);
void __init pxa_set_btuart_info(void *info);
diff --git a/arch/arm/mach-pxa/hx4700.c b/arch/arm/mach-pxa/hx4700.c
index 9cdcca597924..f941a495a4a8 100644
--- a/arch/arm/mach-pxa/hx4700.c
+++ b/arch/arm/mach-pxa/hx4700.c
@@ -735,7 +735,7 @@ static struct platform_device bq24022 = {
* StrataFlash
*/
-static void hx4700_set_vpp(struct map_info *map, int vpp)
+static void hx4700_set_vpp(struct platform_device *pdev, int vpp)
{
gpio_set_value(GPIO91_HX4700_FLASH_VPEN, vpp);
}
diff --git a/arch/arm/mach-pxa/include/mach/memory.h b/arch/arm/mach-pxa/include/mach/memory.h
index 7f68724dcc27..07734f37f8fd 100644
--- a/arch/arm/mach-pxa/include/mach/memory.h
+++ b/arch/arm/mach-pxa/include/mach/memory.h
@@ -17,14 +17,8 @@
*/
#define PLAT_PHYS_OFFSET UL(0xa0000000)
-#if !defined(__ASSEMBLY__) && defined(CONFIG_MACH_ARMCORE) && defined(CONFIG_PCI)
-void cmx2xx_pci_adjust_zones(unsigned long *size, unsigned long *holes);
-
-#define arch_adjust_zones(size, holes) \
- cmx2xx_pci_adjust_zones(size, holes)
-
-#define ISA_DMA_THRESHOLD (PHYS_OFFSET + SZ_64M - 1)
-#define MAX_DMA_ADDRESS (PAGE_OFFSET + SZ_64M)
+#if defined(CONFIG_MACH_ARMCORE) && defined(CONFIG_PCI)
+#define ARM_DMA_ZONE_SIZE SZ_64M
#endif
#endif
diff --git a/arch/arm/mach-pxa/include/mach/uncompress.h b/arch/arm/mach-pxa/include/mach/uncompress.h
index 759b851ec985..5519a34b667f 100644
--- a/arch/arm/mach-pxa/include/mach/uncompress.h
+++ b/arch/arm/mach-pxa/include/mach/uncompress.h
@@ -16,9 +16,9 @@
#define BTUART_BASE (0x40200000)
#define STUART_BASE (0x40700000)
-static unsigned long uart_base;
-static unsigned int uart_shift;
-static unsigned int uart_is_pxa;
+unsigned long uart_base;
+unsigned int uart_shift;
+unsigned int uart_is_pxa;
static inline unsigned char uart_read(int offset)
{
diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
index 6251e3f5c62c..32ed551bf9c5 100644
--- a/arch/arm/mach-pxa/irq.c
+++ b/arch/arm/mach-pxa/irq.c
@@ -15,7 +15,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/io.h>
#include <linux/irq.h>
@@ -183,7 +183,7 @@ void __init pxa_init_irq(int irq_nr, set_wake_t fn)
static unsigned long saved_icmr[MAX_INTERNAL_IRQS/32];
static unsigned long saved_ipr[MAX_INTERNAL_IRQS];
-static int pxa_irq_suspend(struct sys_device *dev, pm_message_t state)
+static int pxa_irq_suspend(void)
{
int i;
@@ -202,7 +202,7 @@ static int pxa_irq_suspend(struct sys_device *dev, pm_message_t state)
return 0;
}
-static int pxa_irq_resume(struct sys_device *dev)
+static void pxa_irq_resume(void)
{
int i;
@@ -218,22 +218,13 @@ static int pxa_irq_resume(struct sys_device *dev)
__raw_writel(saved_ipr[i], IRQ_BASE + IPR(i));
__raw_writel(1, IRQ_BASE + ICCR);
- return 0;
}
#else
#define pxa_irq_suspend NULL
#define pxa_irq_resume NULL
#endif
-struct sysdev_class pxa_irq_sysclass = {
- .name = "irq",
+struct syscore_ops pxa_irq_syscore_ops = {
.suspend = pxa_irq_suspend,
.resume = pxa_irq_resume,
};
-
-static int __init pxa_irq_init(void)
-{
- return sysdev_class_register(&pxa_irq_sysclass);
-}
-
-core_initcall(pxa_irq_init);
diff --git a/arch/arm/mach-pxa/lpd270.c b/arch/arm/mach-pxa/lpd270.c
index f5de541725b1..6cf8180bf5bd 100644
--- a/arch/arm/mach-pxa/lpd270.c
+++ b/arch/arm/mach-pxa/lpd270.c
@@ -15,7 +15,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/bitops.h>
@@ -159,30 +159,22 @@ static void __init lpd270_init_irq(void)
#ifdef CONFIG_PM
-static int lpd270_irq_resume(struct sys_device *dev)
+static void lpd270_irq_resume(void)
{
__raw_writew(lpd270_irq_enabled, LPD270_INT_MASK);
- return 0;
}
-static struct sysdev_class lpd270_irq_sysclass = {
- .name = "cpld_irq",
+static struct syscore_ops lpd270_irq_syscore_ops = {
.resume = lpd270_irq_resume,
};
-static struct sys_device lpd270_irq_device = {
- .cls = &lpd270_irq_sysclass,
-};
-
static int __init lpd270_irq_device_init(void)
{
- int ret = -ENODEV;
if (machine_is_logicpd_pxa270()) {
- ret = sysdev_class_register(&lpd270_irq_sysclass);
- if (ret == 0)
- ret = sysdev_register(&lpd270_irq_device);
+ register_syscore_ops(&lpd270_irq_syscore_ops);
+ return 0;
}
- return ret;
+ return -ENODEV;
}
device_initcall(lpd270_irq_device_init);
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
index 3ede978c83d9..e10ddb827147 100644
--- a/arch/arm/mach-pxa/lubbock.c
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -15,7 +15,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/major.h>
#include <linux/fb.h>
#include <linux/interrupt.h>
@@ -176,31 +176,22 @@ static void __init lubbock_init_irq(void)
#ifdef CONFIG_PM
-static int lubbock_irq_resume(struct sys_device *dev)
+static void lubbock_irq_resume(void)
{
LUB_IRQ_MASK_EN = lubbock_irq_enabled;
- return 0;
}
-static struct sysdev_class lubbock_irq_sysclass = {
- .name = "cpld_irq",
+static struct syscore_ops lubbock_irq_syscore_ops = {
.resume = lubbock_irq_resume,
};
-static struct sys_device lubbock_irq_device = {
- .cls = &lubbock_irq_sysclass,
-};
-
static int __init lubbock_irq_device_init(void)
{
- int ret = -ENODEV;
-
if (machine_is_lubbock()) {
- ret = sysdev_class_register(&lubbock_irq_sysclass);
- if (ret == 0)
- ret = sysdev_register(&lubbock_irq_device);
+ register_syscore_ops(&lubbock_irq_syscore_ops);
+ return 0;
}
- return ret;
+ return -ENODEV;
}
device_initcall(lubbock_irq_device_init);
diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c
index 9984ef70bd79..e1920572948a 100644
--- a/arch/arm/mach-pxa/magician.c
+++ b/arch/arm/mach-pxa/magician.c
@@ -662,7 +662,7 @@ static struct pxaohci_platform_data magician_ohci_info = {
* StrataFlash
*/
-static void magician_set_vpp(struct map_info *map, int vpp)
+static void magician_set_vpp(struct platform_device *pdev, int vpp)
{
gpio_set_value(EGPIO_MAGICIAN_FLASH_VPP, vpp);
}
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
index 95163baca29e..3479e2b3b511 100644
--- a/arch/arm/mach-pxa/mainstone.c
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -15,7 +15,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/bitops.h>
@@ -185,31 +185,21 @@ static void __init mainstone_init_irq(void)
#ifdef CONFIG_PM
-static int mainstone_irq_resume(struct sys_device *dev)
+static void mainstone_irq_resume(void)
{
MST_INTMSKENA = mainstone_irq_enabled;
- return 0;
}
-static struct sysdev_class mainstone_irq_sysclass = {
- .name = "cpld_irq",
+static struct syscore_ops mainstone_irq_syscore_ops = {
.resume = mainstone_irq_resume,
};
-static struct sys_device mainstone_irq_device = {
- .cls = &mainstone_irq_sysclass,
-};
-
static int __init mainstone_irq_device_init(void)
{
- int ret = -ENODEV;
+ if (machine_is_mainstone())
+ register_syscore_ops(&mainstone_irq_syscore_ops);
- if (machine_is_mainstone()) {
- ret = sysdev_class_register(&mainstone_irq_sysclass);
- if (ret == 0)
- ret = sysdev_register(&mainstone_irq_device);
- }
- return ret;
+ return 0;
}
device_initcall(mainstone_irq_device_init);
diff --git a/arch/arm/mach-pxa/mfp-pxa2xx.c b/arch/arm/mach-pxa/mfp-pxa2xx.c
index 1d1419b73457..87ae3129f4f7 100644
--- a/arch/arm/mach-pxa/mfp-pxa2xx.c
+++ b/arch/arm/mach-pxa/mfp-pxa2xx.c
@@ -16,7 +16,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <mach/gpio.h>
#include <mach/pxa2xx-regs.h>
@@ -338,7 +338,7 @@ static unsigned long saved_gafr[2][4];
static unsigned long saved_gpdr[4];
static unsigned long saved_pgsr[4];
-static int pxa2xx_mfp_suspend(struct sys_device *d, pm_message_t state)
+static int pxa2xx_mfp_suspend(void)
{
int i;
@@ -365,7 +365,7 @@ static int pxa2xx_mfp_suspend(struct sys_device *d, pm_message_t state)
return 0;
}
-static int pxa2xx_mfp_resume(struct sys_device *d)
+static void pxa2xx_mfp_resume(void)
{
int i;
@@ -376,15 +376,13 @@ static int pxa2xx_mfp_resume(struct sys_device *d)
PGSR(i) = saved_pgsr[i];
}
PSSR = PSSR_RDH | PSSR_PH;
- return 0;
}
#else
#define pxa2xx_mfp_suspend NULL
#define pxa2xx_mfp_resume NULL
#endif
-struct sysdev_class pxa2xx_mfp_sysclass = {
- .name = "mfp",
+struct syscore_ops pxa2xx_mfp_syscore_ops = {
.suspend = pxa2xx_mfp_suspend,
.resume = pxa2xx_mfp_resume,
};
@@ -409,6 +407,6 @@ static int __init pxa2xx_mfp_init(void)
for (i = 0; i <= gpio_to_bank(pxa_last_gpio); i++)
gpdr_lpm[i] = GPDR(i * 32);
- return sysdev_class_register(&pxa2xx_mfp_sysclass);
+ return 0;
}
postcore_initcall(pxa2xx_mfp_init);
diff --git a/arch/arm/mach-pxa/mfp-pxa3xx.c b/arch/arm/mach-pxa/mfp-pxa3xx.c
index 7a270eecd480..89863a01ecd7 100644
--- a/arch/arm/mach-pxa/mfp-pxa3xx.c
+++ b/arch/arm/mach-pxa/mfp-pxa3xx.c
@@ -17,7 +17,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <mach/hardware.h>
#include <mach/mfp-pxa3xx.h>
@@ -31,13 +31,13 @@
* a pull-down mode if they're an active low chip select, and we're
* just entering standby.
*/
-static int pxa3xx_mfp_suspend(struct sys_device *d, pm_message_t state)
+static int pxa3xx_mfp_suspend(void)
{
mfp_config_lpm();
return 0;
}
-static int pxa3xx_mfp_resume(struct sys_device *d)
+static void pxa3xx_mfp_resume(void)
{
mfp_config_run();
@@ -47,24 +47,13 @@ static int pxa3xx_mfp_resume(struct sys_device *d)
* preserve them here in case they will be referenced later
*/
ASCR &= ~(ASCR_RDH | ASCR_D1S | ASCR_D2S | ASCR_D3S);
- return 0;
}
#else
#define pxa3xx_mfp_suspend NULL
#define pxa3xx_mfp_resume NULL
#endif
-struct sysdev_class pxa3xx_mfp_sysclass = {
- .name = "mfp",
+struct syscore_ops pxa3xx_mfp_syscore_ops = {
.suspend = pxa3xx_mfp_suspend,
- .resume = pxa3xx_mfp_resume,
+ .resume = pxa3xx_mfp_resume,
};
-
-static int __init mfp_init_devicefs(void)
-{
- if (cpu_is_pxa3xx())
- return sysdev_class_register(&pxa3xx_mfp_sysclass);
-
- return 0;
-}
-postcore_initcall(mfp_init_devicefs);
diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c
index 23925db8ff74..e3470137c934 100644
--- a/arch/arm/mach-pxa/mioa701.c
+++ b/arch/arm/mach-pxa/mioa701.c
@@ -22,7 +22,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/gpio_keys.h>
@@ -488,7 +488,7 @@ static void install_bootstrap(void)
}
-static int mioa701_sys_suspend(struct sys_device *sysdev, pm_message_t state)
+static int mioa701_sys_suspend(void)
{
int i = 0, is_bt_on;
u32 *mem_resume_vector = phys_to_virt(RESUME_VECTOR_ADDR);
@@ -514,7 +514,7 @@ static int mioa701_sys_suspend(struct sys_device *sysdev, pm_message_t state)
return 0;
}
-static int mioa701_sys_resume(struct sys_device *sysdev)
+static void mioa701_sys_resume(void)
{
int i = 0;
u32 *mem_resume_vector = phys_to_virt(RESUME_VECTOR_ADDR);
@@ -527,43 +527,18 @@ static int mioa701_sys_resume(struct sys_device *sysdev)
*mem_resume_enabler = save_buffer[i++];
*mem_resume_bt = save_buffer[i++];
*mem_resume_unknown = save_buffer[i++];
-
- return 0;
}
-static struct sysdev_class mioa701_sysclass = {
- .name = "mioa701",
-};
-
-static struct sys_device sysdev_bootstrap = {
- .cls = &mioa701_sysclass,
-};
-
-static struct sysdev_driver driver_bootstrap = {
- .suspend = &mioa701_sys_suspend,
- .resume = &mioa701_sys_resume,
+static struct syscore_ops mioa701_syscore_ops = {
+ .suspend = mioa701_sys_suspend,
+ .resume = mioa701_sys_resume,
};
static int __init bootstrap_init(void)
{
- int rc;
int save_size = mioa701_bootstrap_lg + (sizeof(u32) * 3);
- rc = sysdev_class_register(&mioa701_sysclass);
- if (rc) {
- printk(KERN_ERR "Failed registering mioa701 sys class\n");
- return -ENODEV;
- }
- rc = sysdev_register(&sysdev_bootstrap);
- if (rc) {
- printk(KERN_ERR "Failed registering mioa701 sys device\n");
- return -ENODEV;
- }
- rc = sysdev_driver_register(&mioa701_sysclass, &driver_bootstrap);
- if (rc) {
- printk(KERN_ERR "Failed registering PMU sys driver\n");
- return -ENODEV;
- }
+ register_syscore_ops(&mioa701_syscore_ops);
save_buffer = kmalloc(save_size, GFP_KERNEL);
if (!save_buffer)
@@ -576,9 +551,7 @@ static int __init bootstrap_init(void)
static void bootstrap_exit(void)
{
kfree(save_buffer);
- sysdev_driver_unregister(&mioa701_sysclass, &driver_bootstrap);
- sysdev_unregister(&sysdev_bootstrap);
- sysdev_class_unregister(&mioa701_sysclass);
+ unregister_syscore_ops(&mioa701_syscore_ops);
printk(KERN_CRIT "Unregistering mioa701 suspend will hang next"
"resume !!!\n");
diff --git a/arch/arm/mach-pxa/palmld.c b/arch/arm/mach-pxa/palmld.c
index a6f898cbfac9..4061ecddee70 100644
--- a/arch/arm/mach-pxa/palmld.c
+++ b/arch/arm/mach-pxa/palmld.c
@@ -24,7 +24,6 @@
#include <linux/gpio.h>
#include <linux/wm97xx.h>
#include <linux/power_supply.h>
-#include <linux/sysdev.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
diff --git a/arch/arm/mach-pxa/palmtreo.c b/arch/arm/mach-pxa/palmtreo.c
index 8aadad55fbe4..20d1b18b1733 100644
--- a/arch/arm/mach-pxa/palmtreo.c
+++ b/arch/arm/mach-pxa/palmtreo.c
@@ -25,7 +25,6 @@
#include <linux/pwm_backlight.h>
#include <linux/gpio.h>
#include <linux/power_supply.h>
-#include <linux/sysdev.h>
#include <linux/w1-gpio.h>
#include <asm/mach-types.h>
diff --git a/arch/arm/mach-pxa/palmz72.c b/arch/arm/mach-pxa/palmz72.c
index 3b8a4f37dbbe..65f24f0b77e8 100644
--- a/arch/arm/mach-pxa/palmz72.c
+++ b/arch/arm/mach-pxa/palmz72.c
@@ -19,7 +19,7 @@
*/
#include <linux/platform_device.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/gpio_keys.h>
@@ -233,9 +233,9 @@ static struct palmz72_resume_info palmz72_resume_info = {
static unsigned long store_ptr;
-/* sys_device for Palm Zire 72 PM */
+/* syscore_ops for Palm Zire 72 PM */
-static int palmz72_pm_suspend(struct sys_device *dev, pm_message_t msg)
+static int palmz72_pm_suspend(void)
{
/* setup the resume_info struct for the original bootloader */
palmz72_resume_info.resume_addr = (u32) cpu_resume;
@@ -249,31 +249,23 @@ static int palmz72_pm_suspend(struct sys_device *dev, pm_message_t msg)
return 0;
}
-static int palmz72_pm_resume(struct sys_device *dev)
+static void palmz72_pm_resume(void)
{
*PALMZ72_SAVE_DWORD = store_ptr;
- return 0;
}
-static struct sysdev_class palmz72_pm_sysclass = {
- .name = "palmz72_pm",
+static struct syscore_ops palmz72_pm_syscore_ops = {
.suspend = palmz72_pm_suspend,
.resume = palmz72_pm_resume,
};
-static struct sys_device palmz72_pm_device = {
- .cls = &palmz72_pm_sysclass,
-};
-
static int __init palmz72_pm_init(void)
{
- int ret = -ENODEV;
if (machine_is_palmz72()) {
- ret = sysdev_class_register(&palmz72_pm_sysclass);
- if (ret == 0)
- ret = sysdev_register(&palmz72_pm_device);
+ register_syscore_ops(&palmz72_pm_syscore_ops);
+ return 0;
}
- return ret;
+ return -ENODEV;
}
device_initcall(palmz72_pm_init);
diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
index a4af8c52d7ee..fed363cec9c6 100644
--- a/arch/arm/mach-pxa/pxa25x.c
+++ b/arch/arm/mach-pxa/pxa25x.c
@@ -21,7 +21,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/suspend.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/irq.h>
#include <asm/mach/map.h>
@@ -350,21 +350,9 @@ static struct platform_device *pxa25x_devices[] __initdata = {
&pxa_device_asoc_platform,
};
-static struct sys_device pxa25x_sysdev[] = {
- {
- .cls = &pxa_irq_sysclass,
- }, {
- .cls = &pxa2xx_mfp_sysclass,
- }, {
- .cls = &pxa_gpio_sysclass,
- }, {
- .cls = &pxa2xx_clock_sysclass,
- }
-};
-
static int __init pxa25x_init(void)
{
- int i, ret = 0;
+ int ret = 0;
if (cpu_is_pxa25x()) {
@@ -377,11 +365,10 @@ static int __init pxa25x_init(void)
pxa25x_init_pm();
- for (i = 0; i < ARRAY_SIZE(pxa25x_sysdev); i++) {
- ret = sysdev_register(&pxa25x_sysdev[i]);
- if (ret)
- pr_err("failed to register sysdev[%d]\n", i);
- }
+ register_syscore_ops(&pxa_irq_syscore_ops);
+ register_syscore_ops(&pxa2xx_mfp_syscore_ops);
+ register_syscore_ops(&pxa_gpio_syscore_ops);
+ register_syscore_ops(&pxa2xx_clock_syscore_ops);
ret = platform_add_devices(pxa25x_devices,
ARRAY_SIZE(pxa25x_devices));
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index 909756eaf4b7..2fecbec58d88 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -16,7 +16,7 @@
#include <linux/init.h>
#include <linux/suspend.h>
#include <linux/platform_device.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/i2c/pxa-i2c.h>
@@ -428,21 +428,9 @@ static struct platform_device *devices[] __initdata = {
&pxa27x_device_pwm1,
};
-static struct sys_device pxa27x_sysdev[] = {
- {
- .cls = &pxa_irq_sysclass,
- }, {
- .cls = &pxa2xx_mfp_sysclass,
- }, {
- .cls = &pxa_gpio_sysclass,
- }, {
- .cls = &pxa2xx_clock_sysclass,
- }
-};
-
static int __init pxa27x_init(void)
{
- int i, ret = 0;
+ int ret = 0;
if (cpu_is_pxa27x()) {
@@ -455,11 +443,10 @@ static int __init pxa27x_init(void)
pxa27x_init_pm();
- for (i = 0; i < ARRAY_SIZE(pxa27x_sysdev); i++) {
- ret = sysdev_register(&pxa27x_sysdev[i]);
- if (ret)
- pr_err("failed to register sysdev[%d]\n", i);
- }
+ register_syscore_ops(&pxa_irq_syscore_ops);
+ register_syscore_ops(&pxa2xx_mfp_syscore_ops);
+ register_syscore_ops(&pxa_gpio_syscore_ops);
+ register_syscore_ops(&pxa2xx_clock_syscore_ops);
ret = platform_add_devices(devices, ARRAY_SIZE(devices));
}
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index 8dd107391157..8521d7d6f1da 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -20,7 +20,7 @@
#include <linux/platform_device.h>
#include <linux/irq.h>
#include <linux/io.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/i2c/pxa-i2c.h>
#include <asm/mach/map.h>
@@ -427,21 +427,9 @@ static struct platform_device *devices[] __initdata = {
&pxa27x_device_pwm1,
};
-static struct sys_device pxa3xx_sysdev[] = {
- {
- .cls = &pxa_irq_sysclass,
- }, {
- .cls = &pxa3xx_mfp_sysclass,
- }, {
- .cls = &pxa_gpio_sysclass,
- }, {
- .cls = &pxa3xx_clock_sysclass,
- }
-};
-
static int __init pxa3xx_init(void)
{
- int i, ret = 0;
+ int ret = 0;
if (cpu_is_pxa3xx()) {
@@ -462,11 +450,10 @@ static int __init pxa3xx_init(void)
pxa3xx_init_pm();
- for (i = 0; i < ARRAY_SIZE(pxa3xx_sysdev); i++) {
- ret = sysdev_register(&pxa3xx_sysdev[i]);
- if (ret)
- pr_err("failed to register sysdev[%d]\n", i);
- }
+ register_syscore_ops(&pxa_irq_syscore_ops);
+ register_syscore_ops(&pxa3xx_mfp_syscore_ops);
+ register_syscore_ops(&pxa_gpio_syscore_ops);
+ register_syscore_ops(&pxa3xx_clock_syscore_ops);
ret = platform_add_devices(devices, ARRAY_SIZE(devices));
}
diff --git a/arch/arm/mach-pxa/pxa95x.c b/arch/arm/mach-pxa/pxa95x.c
index 23b229bd06e9..ecc82a330fad 100644
--- a/arch/arm/mach-pxa/pxa95x.c
+++ b/arch/arm/mach-pxa/pxa95x.c
@@ -18,7 +18,7 @@
#include <linux/i2c/pxa-i2c.h>
#include <linux/irq.h>
#include <linux/io.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <mach/hardware.h>
#include <mach/gpio.h>
@@ -260,16 +260,6 @@ static struct platform_device *devices[] __initdata = {
&pxa27x_device_pwm1,
};
-static struct sys_device pxa95x_sysdev[] = {
- {
- .cls = &pxa_irq_sysclass,
- }, {
- .cls = &pxa_gpio_sysclass,
- }, {
- .cls = &pxa3xx_clock_sysclass,
- }
-};
-
static int __init pxa95x_init(void)
{
int ret = 0, i;
@@ -293,11 +283,9 @@ static int __init pxa95x_init(void)
if ((ret = pxa_init_dma(IRQ_DMA, 32)))
return ret;
- for (i = 0; i < ARRAY_SIZE(pxa95x_sysdev); i++) {
- ret = sysdev_register(&pxa95x_sysdev[i]);
- if (ret)
- pr_err("failed to register sysdev[%d]\n", i);
- }
+ register_syscore_ops(&pxa_irq_syscore_ops);
+ register_syscore_ops(&pxa_gpio_syscore_ops);
+ register_syscore_ops(&pxa3xx_clock_syscore_ops);
ret = platform_add_devices(devices, ARRAY_SIZE(devices));
}
diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c
index cd1861351f75..d130f77b6d11 100644
--- a/arch/arm/mach-pxa/raumfeld.c
+++ b/arch/arm/mach-pxa/raumfeld.c
@@ -18,7 +18,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/sysdev.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
diff --git a/arch/arm/mach-pxa/smemc.c b/arch/arm/mach-pxa/smemc.c
index 232b7316ec08..79923058d10f 100644
--- a/arch/arm/mach-pxa/smemc.c
+++ b/arch/arm/mach-pxa/smemc.c
@@ -6,7 +6,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <mach/hardware.h>
#include <mach/smemc.h>
@@ -16,7 +16,7 @@ static unsigned long msc[2];
static unsigned long sxcnfg, memclkcfg;
static unsigned long csadrcfg[4];
-static int pxa3xx_smemc_suspend(struct sys_device *dev, pm_message_t state)
+static int pxa3xx_smemc_suspend(void)
{
msc[0] = __raw_readl(MSC0);
msc[1] = __raw_readl(MSC1);
@@ -30,7 +30,7 @@ static int pxa3xx_smemc_suspend(struct sys_device *dev, pm_message_t state)
return 0;
}
-static int pxa3xx_smemc_resume(struct sys_device *dev)
+static void pxa3xx_smemc_resume(void)
{
__raw_writel(msc[0], MSC0);
__raw_writel(msc[1], MSC1);
@@ -40,34 +40,19 @@ static int pxa3xx_smemc_resume(struct sys_device *dev)
__raw_writel(csadrcfg[1], CSADRCFG1);
__raw_writel(csadrcfg[2], CSADRCFG2);
__raw_writel(csadrcfg[3], CSADRCFG3);
-
- return 0;
}
-static struct sysdev_class smemc_sysclass = {
- .name = "smemc",
+static struct syscore_ops smemc_syscore_ops = {
.suspend = pxa3xx_smemc_suspend,
.resume = pxa3xx_smemc_resume,
};
-static struct sys_device smemc_sysdev = {
- .id = 0,
- .cls = &smemc_sysclass,
-};
-
static int __init smemc_init(void)
{
- int ret = 0;
+ if (cpu_is_pxa3xx())
+ register_syscore_ops(&smemc_syscore_ops);
- if (cpu_is_pxa3xx()) {
- ret = sysdev_class_register(&smemc_sysclass);
- if (ret)
- return ret;
-
- ret = sysdev_register(&smemc_sysdev);
- }
-
- return ret;
+ return 0;
}
subsys_initcall(smemc_init);
#endif
diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
index 428da3ff33a5..de684701449c 100644
--- a/arch/arm/mach-pxa/time.c
+++ b/arch/arm/mach-pxa/time.c
@@ -105,19 +105,6 @@ static struct clock_event_device ckevt_pxa_osmr0 = {
.set_mode = pxa_osmr0_set_mode,
};
-static cycle_t pxa_read_oscr(struct clocksource *cs)
-{
- return OSCR;
-}
-
-static struct clocksource cksrc_pxa_oscr0 = {
- .name = "oscr0",
- .rating = 200,
- .read = pxa_read_oscr,
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
static struct irqaction pxa_ost0_irq = {
.name = "ost0",
.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
@@ -134,7 +121,6 @@ static void __init pxa_timer_init(void)
init_sched_clock(&cd, pxa_update_sched_clock, 32, clock_tick_rate);
- clocksource_calc_mult_shift(&cksrc_pxa_oscr0, clock_tick_rate, 4);
clockevents_calc_mult_shift(&ckevt_pxa_osmr0, clock_tick_rate, 4);
ckevt_pxa_osmr0.max_delta_ns =
clockevent_delta2ns(0x7fffffff, &ckevt_pxa_osmr0);
@@ -144,7 +130,8 @@ static void __init pxa_timer_init(void)
setup_irq(IRQ_OST0, &pxa_ost0_irq);
- clocksource_register_hz(&cksrc_pxa_oscr0, clock_tick_rate);
+ clocksource_mmio_init(&OSCR, "oscr0", clock_tick_rate, 200, 32,
+ clocksource_mmio_readl_up);
clockevents_register_device(&ckevt_pxa_osmr0);
}
diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c
index b9cfbebdfe9c..687417a93698 100644
--- a/arch/arm/mach-pxa/trizeps4.c
+++ b/arch/arm/mach-pxa/trizeps4.c
@@ -15,7 +15,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
-#include <linux/sysdev.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/bitops.h>
diff --git a/arch/arm/mach-pxa/viper.c b/arch/arm/mach-pxa/viper.c
index b523f119e0f0..903218eab56d 100644
--- a/arch/arm/mach-pxa/viper.c
+++ b/arch/arm/mach-pxa/viper.c
@@ -44,6 +44,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
+#include <linux/syscore_ops.h>
#include <mach/pxa25x.h>
#include <mach/audio.h>
@@ -130,20 +131,19 @@ static u8 viper_hw_version(void)
return v1;
}
-/* CPU sysdev */
-static int viper_cpu_suspend(struct sys_device *sysdev, pm_message_t state)
+/* CPU system core operations. */
+static int viper_cpu_suspend(void)
{
viper_icr_set_bit(VIPER_ICR_R_DIS);
return 0;
}
-static int viper_cpu_resume(struct sys_device *sysdev)
+static void viper_cpu_resume(void)
{
viper_icr_clear_bit(VIPER_ICR_R_DIS);
- return 0;
}
-static struct sysdev_driver viper_cpu_sysdev_driver = {
+static struct syscore_ops viper_cpu_syscore_ops = {
.suspend = viper_cpu_suspend,
.resume = viper_cpu_resume,
};
@@ -945,7 +945,7 @@ static void __init viper_init(void)
viper_init_vcore_gpios();
viper_init_cpufreq();
- sysdev_driver_register(&cpu_sysdev_class, &viper_cpu_sysdev_driver);
+ register_syscore_ops(&viper_cpu_syscore_ops);
if (version) {
pr_info("viper: hardware v%di%d detected. "
diff --git a/arch/arm/mach-pxa/vpac270.c b/arch/arm/mach-pxa/vpac270.c
index f71d377c8640..67bd41488bf8 100644
--- a/arch/arm/mach-pxa/vpac270.c
+++ b/arch/arm/mach-pxa/vpac270.c
@@ -16,7 +16,6 @@
#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/gpio.h>
-#include <linux/sysdev.h>
#include <linux/usb/gpio_vbus.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index 75dbc8791d05..5c23450d2d1d 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -31,6 +31,7 @@
#include <linux/amba/mmci.h>
#include <linux/gfp.h>
#include <linux/clkdev.h>
+#include <linux/mtd/physmap.h>
#include <asm/system.h>
#include <mach/hardware.h>
@@ -41,7 +42,6 @@
#include <asm/hardware/icst.h>
#include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
#include <asm/mach/irq.h>
#include <asm/mach/map.h>
@@ -56,48 +56,9 @@
#include "core.h"
-#ifdef CONFIG_ZONE_DMA
-/*
- * Adjust the zones if there are restrictions for DMA access.
- */
-void __init realview_adjust_zones(unsigned long *size, unsigned long *hole)
-{
- unsigned long dma_size = SZ_256M >> PAGE_SHIFT;
-
- if (!machine_is_realview_pbx() || size[0] <= dma_size)
- return;
-
- size[ZONE_NORMAL] = size[0] - dma_size;
- size[ZONE_DMA] = dma_size;
- hole[ZONE_NORMAL] = hole[0];
- hole[ZONE_DMA] = 0;
-}
-#endif
-
-
#define REALVIEW_FLASHCTRL (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_FLASH_OFFSET)
-static int realview_flash_init(void)
-{
- u32 val;
-
- val = __raw_readl(REALVIEW_FLASHCTRL);
- val &= ~REALVIEW_FLASHPROG_FLVPPEN;
- __raw_writel(val, REALVIEW_FLASHCTRL);
-
- return 0;
-}
-
-static void realview_flash_exit(void)
-{
- u32 val;
-
- val = __raw_readl(REALVIEW_FLASHCTRL);
- val &= ~REALVIEW_FLASHPROG_FLVPPEN;
- __raw_writel(val, REALVIEW_FLASHCTRL);
-}
-
-static void realview_flash_set_vpp(int on)
+static void realview_flash_set_vpp(struct platform_device *pdev, int on)
{
u32 val;
@@ -109,16 +70,13 @@ static void realview_flash_set_vpp(int on)
__raw_writel(val, REALVIEW_FLASHCTRL);
}
-static struct flash_platform_data realview_flash_data = {
- .map_name = "cfi_probe",
+static struct physmap_flash_data realview_flash_data = {
.width = 4,
- .init = realview_flash_init,
- .exit = realview_flash_exit,
.set_vpp = realview_flash_set_vpp,
};
struct platform_device realview_flash_device = {
- .name = "armflash",
+ .name = "physmap-flash",
.id = 0,
.dev = {
.platform_data = &realview_flash_data,
@@ -315,6 +273,10 @@ static struct clk ref24_clk = {
.rate = 24000000,
};
+static struct clk sp804_clk = {
+ .rate = 1000000,
+};
+
static struct clk dummy_apb_pclk;
static struct clk_lookup lookups[] = {
@@ -357,7 +319,10 @@ static struct clk_lookup lookups[] = {
}, { /* SSP */
.dev_id = "dev:ssp0",
.clk = &ref24_clk,
- }
+ }, { /* SP804 timers */
+ .dev_id = "sp804",
+ .clk = &sp804_clk,
+ },
};
void __init realview_init_early(void)
@@ -545,8 +510,8 @@ void __init realview_timer_init(unsigned int timer_irq)
writel(0, timer2_va_base + TIMER_CTRL);
writel(0, timer3_va_base + TIMER_CTRL);
- sp804_clocksource_init(timer3_va_base);
- sp804_clockevents_init(timer0_va_base, timer_irq);
+ sp804_clocksource_init(timer3_va_base, "timer3");
+ sp804_clockevents_init(timer0_va_base, timer_irq, "timer0");
}
/*
diff --git a/arch/arm/mach-realview/include/mach/memory.h b/arch/arm/mach-realview/include/mach/memory.h
index e05fc2c4c080..1759fa673eea 100644
--- a/arch/arm/mach-realview/include/mach/memory.h
+++ b/arch/arm/mach-realview/include/mach/memory.h
@@ -29,13 +29,8 @@
#define PLAT_PHYS_OFFSET UL(0x00000000)
#endif
-#if !defined(__ASSEMBLY__) && defined(CONFIG_ZONE_DMA)
-extern void realview_adjust_zones(unsigned long *size, unsigned long *hole);
-#define arch_adjust_zones(size, hole) \
- realview_adjust_zones(size, hole)
-
-#define ISA_DMA_THRESHOLD (PHYS_OFFSET + SZ_256M - 1)
-#define MAX_DMA_ADDRESS (PAGE_OFFSET + SZ_256M)
+#ifdef CONFIG_ZONE_DMA
+#define ARM_DMA_ZONE_SIZE SZ_256M
#endif
#ifdef CONFIG_SPARSEMEM
diff --git a/arch/arm/mach-realview/include/mach/smp.h b/arch/arm/mach-realview/include/mach/smp.h
deleted file mode 100644
index c8221b38ee7c..000000000000
--- a/arch/arm/mach-realview/include/mach/smp.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef ASMARM_ARCH_SMP_H
-#define ASMARM_ARCH_SMP_H
-
-#include <asm/hardware/gic.h>
-
-/*
- * We use IRQ1 as the IPI
- */
-static inline void smp_cross_call(const struct cpumask *mask, int ipi)
-{
- gic_raise_softirq(mask, ipi);
-}
-
-#endif
diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c
index 23919229e12d..963bf0d8119a 100644
--- a/arch/arm/mach-realview/platsmp.c
+++ b/arch/arm/mach-realview/platsmp.c
@@ -14,6 +14,7 @@
#include <linux/io.h>
#include <mach/hardware.h>
+#include <asm/hardware/gic.h>
#include <asm/mach-types.h>
#include <asm/smp_scu.h>
#include <asm/unified.h>
@@ -61,6 +62,8 @@ void __init smp_init_cpus(void)
for (i = 0; i < ncores; i++)
set_cpu_possible(i, true);
+
+ set_smp_cross_call(gic_raise_softirq);
}
void __init platform_smp_prepare_cpus(unsigned int max_cpus)
diff --git a/arch/arm/mach-rpc/include/mach/uncompress.h b/arch/arm/mach-rpc/include/mach/uncompress.h
index 8c9e2c7161c6..9cd9bcdad6cc 100644
--- a/arch/arm/mach-rpc/include/mach/uncompress.h
+++ b/arch/arm/mach-rpc/include/mach/uncompress.h
@@ -66,12 +66,12 @@ extern __attribute__((pure)) struct param_struct *params(void);
#define params (params())
#ifndef STANDALONE_DEBUG
-static unsigned long video_num_cols;
-static unsigned long video_num_rows;
-static unsigned long video_x;
-static unsigned long video_y;
-static unsigned char bytes_per_char_v;
-static int white;
+unsigned long video_num_cols;
+unsigned long video_num_rows;
+unsigned long video_x;
+unsigned long video_y;
+unsigned char bytes_per_char_v;
+int white;
/*
* This does not append a newline
diff --git a/arch/arm/mach-s3c2410/include/mach/map.h b/arch/arm/mach-s3c2410/include/mach/map.h
index 25bbf5a942dd..425552d84b60 100644
--- a/arch/arm/mach-s3c2410/include/mach/map.h
+++ b/arch/arm/mach-s3c2410/include/mach/map.h
@@ -21,6 +21,10 @@
/* USB host controller */
#define S3C2410_PA_USBHOST (0x49000000)
+/* S3C2416/S3C2443/S3C2450 High-Speed USB Gadget */
+#define S3C2416_PA_HSUDC (0x49800000)
+#define S3C2416_SZ_HSUDC (SZ_4K)
+
/* DMA controller */
#define S3C2410_PA_DMA (0x4B000000)
#define S3C24XX_SZ_DMA SZ_1M
diff --git a/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h b/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h
index 44494a56e68b..5e06c7265835 100644
--- a/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h
+++ b/arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h
@@ -37,6 +37,10 @@
#define S3C2443_SYSID S3C2443_CLKREG(0x5C)
#define S3C2443_PWRCFG S3C2443_CLKREG(0x60)
#define S3C2443_RSTCON S3C2443_CLKREG(0x64)
+#define S3C2443_PHYCTRL S3C2443_CLKREG(0x80)
+#define S3C2443_PHYPWR S3C2443_CLKREG(0x84)
+#define S3C2443_URSTCON S3C2443_CLKREG(0x88)
+#define S3C2443_UCLKCON S3C2443_CLKREG(0x8C)
#define S3C2443_SWRST_RESET (0x533c2443)
@@ -121,6 +125,27 @@
#define S3C2443_PWRCFG_SLEEP (1<<15)
+#define S3C2443_PWRCFG_USBPHY (1 << 4)
+
+#define S3C2443_URSTCON_FUNCRST (1 << 2)
+#define S3C2443_URSTCON_PHYRST (1 << 0)
+
+#define S3C2443_PHYCTRL_CLKSEL (1 << 3)
+#define S3C2443_PHYCTRL_EXTCLK (1 << 2)
+#define S3C2443_PHYCTRL_PLLSEL (1 << 1)
+#define S3C2443_PHYCTRL_DSPORT (1 << 0)
+
+#define S3C2443_PHYPWR_COMMON_ON (1 << 31)
+#define S3C2443_PHYPWR_ANALOG_PD (1 << 4)
+#define S3C2443_PHYPWR_PLL_REFCLK (1 << 3)
+#define S3C2443_PHYPWR_XO_ON (1 << 2)
+#define S3C2443_PHYPWR_PLL_PWRDN (1 << 1)
+#define S3C2443_PHYPWR_FSUSPEND (1 << 0)
+
+#define S3C2443_UCLKCON_DETECT_VBUS (1 << 31)
+#define S3C2443_UCLKCON_FUNC_CLKEN (1 << 2)
+#define S3C2443_UCLKCON_TCLKEN (1 << 0)
+
#include <asm/div64.h>
static inline unsigned int
diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c
index 5e2f35332056..2854129f8cc7 100644
--- a/arch/arm/mach-s3c2410/irq.c
+++ b/arch/arm/mach-s3c2410/irq.c
@@ -23,38 +23,12 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <plat/cpu.h>
#include <plat/pm.h>
-static int s3c2410_irq_add(struct sys_device *sysdev)
-{
- return 0;
-}
-
-static struct sysdev_driver s3c2410_irq_driver = {
- .add = s3c2410_irq_add,
+struct syscore_ops s3c24xx_irq_syscore_ops = {
.suspend = s3c24xx_irq_suspend,
.resume = s3c24xx_irq_resume,
};
-
-static int __init s3c2410_irq_init(void)
-{
- return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_irq_driver);
-}
-
-arch_initcall(s3c2410_irq_init);
-
-static struct sysdev_driver s3c2410a_irq_driver = {
- .add = s3c2410_irq_add,
- .suspend = s3c24xx_irq_suspend,
- .resume = s3c24xx_irq_resume,
-};
-
-static int __init s3c2410a_irq_init(void)
-{
- return sysdev_driver_register(&s3c2410a_sysclass, &s3c2410a_irq_driver);
-}
-
-arch_initcall(s3c2410a_irq_init);
diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c
index 2970ea9f7c2b..1e2d536adda9 100644
--- a/arch/arm/mach-s3c2410/mach-bast.c
+++ b/arch/arm/mach-s3c2410/mach-bast.c
@@ -17,7 +17,7 @@
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/gpio.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <linux/dm9000.h>
@@ -214,17 +214,16 @@ static struct s3c2410_uartcfg bast_uartcfgs[] __initdata = {
/* NAND Flash on BAST board */
#ifdef CONFIG_PM
-static int bast_pm_suspend(struct sys_device *sd, pm_message_t state)
+static int bast_pm_suspend(void)
{
/* ensure that an nRESET is not generated on resume. */
gpio_direction_output(S3C2410_GPA(21), 1);
return 0;
}
-static int bast_pm_resume(struct sys_device *sd)
+static void bast_pm_resume(void)
{
s3c_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPA21_nRSTOUT);
- return 0;
}
#else
@@ -232,16 +231,11 @@ static int bast_pm_resume(struct sys_device *sd)
#define bast_pm_resume NULL
#endif
-static struct sysdev_class bast_pm_sysclass = {
- .name = "mach-bast",
+static struct syscore_ops bast_pm_syscore_ops = {
.suspend = bast_pm_suspend,
.resume = bast_pm_resume,
};
-static struct sys_device bast_pm_sysdev = {
- .cls = &bast_pm_sysclass,
-};
-
static int smartmedia_map[] = { 0 };
static int chip0_map[] = { 1 };
static int chip1_map[] = { 2 };
@@ -642,8 +636,7 @@ static void __init bast_map_io(void)
static void __init bast_init(void)
{
- sysdev_class_register(&bast_pm_sysclass);
- sysdev_register(&bast_pm_sysdev);
+ register_syscore_ops(&bast_pm_syscore_ops);
s3c_i2c0_set_platdata(&bast_i2c_info);
s3c_nand_set_platdata(&bast_nand_info);
diff --git a/arch/arm/mach-s3c2410/nor-simtec.c b/arch/arm/mach-s3c2410/nor-simtec.c
index 598d130633dc..ad9f750f1e55 100644
--- a/arch/arm/mach-s3c2410/nor-simtec.c
+++ b/arch/arm/mach-s3c2410/nor-simtec.c
@@ -32,7 +32,7 @@
#include "nor-simtec.h"
-static void simtec_nor_vpp(struct map_info *map, int vpp)
+static void simtec_nor_vpp(struct platform_device *pdev, int vpp)
{
unsigned int val;
unsigned long flags;
diff --git a/arch/arm/mach-s3c2410/pm.c b/arch/arm/mach-s3c2410/pm.c
index 725636fc4dc3..4728f9aa7df1 100644
--- a/arch/arm/mach-s3c2410/pm.c
+++ b/arch/arm/mach-s3c2410/pm.c
@@ -25,6 +25,7 @@
#include <linux/errno.h>
#include <linux/time.h>
#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/gpio.h>
#include <linux/io.h>
@@ -92,7 +93,7 @@ static void s3c2410_pm_prepare(void)
}
}
-static int s3c2410_pm_resume(struct sys_device *dev)
+static void s3c2410_pm_resume(void)
{
unsigned long tmp;
@@ -104,10 +105,12 @@ static int s3c2410_pm_resume(struct sys_device *dev)
if ( machine_is_aml_m5900() )
s3c2410_gpio_setpin(S3C2410_GPF(2), 0);
-
- return 0;
}
+struct syscore_ops s3c2410_pm_syscore_ops = {
+ .resume = s3c2410_pm_resume,
+};
+
static int s3c2410_pm_add(struct sys_device *dev)
{
pm_cpu_prep = s3c2410_pm_prepare;
@@ -119,7 +122,6 @@ static int s3c2410_pm_add(struct sys_device *dev)
#if defined(CONFIG_CPU_S3C2410)
static struct sysdev_driver s3c2410_pm_driver = {
.add = s3c2410_pm_add,
- .resume = s3c2410_pm_resume,
};
/* register ourselves */
@@ -133,7 +135,6 @@ arch_initcall(s3c2410_pm_drvinit);
static struct sysdev_driver s3c2410a_pm_driver = {
.add = s3c2410_pm_add,
- .resume = s3c2410_pm_resume,
};
static int __init s3c2410a_pm_drvinit(void)
@@ -147,7 +148,6 @@ arch_initcall(s3c2410a_pm_drvinit);
#if defined(CONFIG_CPU_S3C2440)
static struct sysdev_driver s3c2440_pm_driver = {
.add = s3c2410_pm_add,
- .resume = s3c2410_pm_resume,
};
static int __init s3c2440_pm_drvinit(void)
@@ -161,7 +161,6 @@ arch_initcall(s3c2440_pm_drvinit);
#if defined(CONFIG_CPU_S3C2442)
static struct sysdev_driver s3c2442_pm_driver = {
.add = s3c2410_pm_add,
- .resume = s3c2410_pm_resume,
};
static int __init s3c2442_pm_drvinit(void)
diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c
index adc90a3c5890..f1d3bd8f6f17 100644
--- a/arch/arm/mach-s3c2410/s3c2410.c
+++ b/arch/arm/mach-s3c2410/s3c2410.c
@@ -19,6 +19,7 @@
#include <linux/gpio.h>
#include <linux/clk.h>
#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <linux/io.h>
@@ -40,6 +41,7 @@
#include <plat/devs.h>
#include <plat/clock.h>
#include <plat/pll.h>
+#include <plat/pm.h>
#include <plat/gpio-core.h>
#include <plat/gpio-cfg.h>
@@ -168,6 +170,9 @@ int __init s3c2410_init(void)
{
printk("S3C2410: Initialising architecture\n");
+ register_syscore_ops(&s3c2410_pm_syscore_ops);
+ register_syscore_ops(&s3c24xx_irq_syscore_ops);
+
return sysdev_register(&s3c2410_sysdev);
}
diff --git a/arch/arm/mach-s3c2412/irq.c b/arch/arm/mach-s3c2412/irq.c
index f3355d2ec634..1a1aa220972b 100644
--- a/arch/arm/mach-s3c2412/irq.c
+++ b/arch/arm/mach-s3c2412/irq.c
@@ -202,8 +202,6 @@ static int s3c2412_irq_add(struct sys_device *sysdev)
static struct sysdev_driver s3c2412_irq_driver = {
.add = s3c2412_irq_add,
- .suspend = s3c24xx_irq_suspend,
- .resume = s3c24xx_irq_resume,
};
static int s3c2412_irq_init(void)
diff --git a/arch/arm/mach-s3c2412/mach-jive.c b/arch/arm/mach-s3c2412/mach-jive.c
index 923e01bdf017..85dcaeb9e62f 100644
--- a/arch/arm/mach-s3c2412/mach-jive.c
+++ b/arch/arm/mach-s3c2412/mach-jive.c
@@ -17,7 +17,7 @@
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/gpio.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
@@ -486,7 +486,7 @@ static struct s3c2410_udc_mach_info jive_udc_cfg __initdata = {
/* Jive power management device */
#ifdef CONFIG_PM
-static int jive_pm_suspend(struct sys_device *sd, pm_message_t state)
+static int jive_pm_suspend(void)
{
/* Write the magic value u-boot uses to check for resume into
* the INFORM0 register, and ensure INFORM1 is set to the
@@ -498,10 +498,9 @@ static int jive_pm_suspend(struct sys_device *sd, pm_message_t state)
return 0;
}
-static int jive_pm_resume(struct sys_device *sd)
+static void jive_pm_resume(void)
{
__raw_writel(0x0, S3C2412_INFORM0);
- return 0;
}
#else
@@ -509,16 +508,11 @@ static int jive_pm_resume(struct sys_device *sd)
#define jive_pm_resume NULL
#endif
-static struct sysdev_class jive_pm_sysclass = {
- .name = "jive-pm",
+static struct syscore_ops jive_pm_syscore_ops = {
.suspend = jive_pm_suspend,
.resume = jive_pm_resume,
};
-static struct sys_device jive_pm_sysdev = {
- .cls = &jive_pm_sysclass,
-};
-
static void __init jive_map_io(void)
{
s3c24xx_init_io(jive_iodesc, ARRAY_SIZE(jive_iodesc));
@@ -536,10 +530,9 @@ static void jive_power_off(void)
static void __init jive_machine_init(void)
{
- /* register system devices for managing low level suspend */
+ /* register system core operations for managing low level suspend */
- sysdev_class_register(&jive_pm_sysclass);
- sysdev_register(&jive_pm_sysdev);
+ register_syscore_ops(&jive_pm_syscore_ops);
/* write our sleep configurations for the IO. Pull down all unused
* IO, ensure that we have turned off all peripherals we do not
diff --git a/arch/arm/mach-s3c2412/pm.c b/arch/arm/mach-s3c2412/pm.c
index a7417c479ffe..752b13a7b3db 100644
--- a/arch/arm/mach-s3c2412/pm.c
+++ b/arch/arm/mach-s3c2412/pm.c
@@ -17,6 +17,7 @@
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/platform_device.h>
#include <linux/io.h>
@@ -86,13 +87,24 @@ static struct sleep_save s3c2412_sleep[] = {
SAVE_ITEM(S3C2413_GPJSLPCON),
};
-static int s3c2412_pm_suspend(struct sys_device *dev, pm_message_t state)
+static struct sysdev_driver s3c2412_pm_driver = {
+ .add = s3c2412_pm_add,
+};
+
+static __init int s3c2412_pm_init(void)
+{
+ return sysdev_driver_register(&s3c2412_sysclass, &s3c2412_pm_driver);
+}
+
+arch_initcall(s3c2412_pm_init);
+
+static int s3c2412_pm_suspend(void)
{
s3c_pm_do_save(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
return 0;
}
-static int s3c2412_pm_resume(struct sys_device *dev)
+static void s3c2412_pm_resume(void)
{
unsigned long tmp;
@@ -102,18 +114,9 @@ static int s3c2412_pm_resume(struct sys_device *dev)
__raw_writel(tmp, S3C2412_PWRCFG);
s3c_pm_do_restore(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
- return 0;
}
-static struct sysdev_driver s3c2412_pm_driver = {
- .add = s3c2412_pm_add,
+struct syscore_ops s3c2412_pm_syscore_ops = {
.suspend = s3c2412_pm_suspend,
.resume = s3c2412_pm_resume,
};
-
-static __init int s3c2412_pm_init(void)
-{
- return sysdev_driver_register(&s3c2412_sysclass, &s3c2412_pm_driver);
-}
-
-arch_initcall(s3c2412_pm_init);
diff --git a/arch/arm/mach-s3c2412/s3c2412.c b/arch/arm/mach-s3c2412/s3c2412.c
index 4c6df51ddf33..ef0958d3e5c6 100644
--- a/arch/arm/mach-s3c2412/s3c2412.c
+++ b/arch/arm/mach-s3c2412/s3c2412.c
@@ -19,6 +19,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <linux/io.h>
@@ -244,5 +245,8 @@ int __init s3c2412_init(void)
{
printk("S3C2412: Initialising architecture\n");
+ register_syscore_ops(&s3c2412_pm_syscore_ops);
+ register_syscore_ops(&s3c24xx_irq_syscore_ops);
+
return sysdev_register(&s3c2412_sysdev);
}
diff --git a/arch/arm/mach-s3c2416/irq.c b/arch/arm/mach-s3c2416/irq.c
index 77b38f2381c1..28ad20d42445 100644
--- a/arch/arm/mach-s3c2416/irq.c
+++ b/arch/arm/mach-s3c2416/irq.c
@@ -236,8 +236,6 @@ static int __init s3c2416_irq_add(struct sys_device *sysdev)
static struct sysdev_driver s3c2416_irq_driver = {
.add = s3c2416_irq_add,
- .suspend = s3c24xx_irq_suspend,
- .resume = s3c24xx_irq_resume,
};
static int __init s3c2416_irq_init(void)
diff --git a/arch/arm/mach-s3c2416/mach-smdk2416.c b/arch/arm/mach-s3c2416/mach-smdk2416.c
index 3f83177246c7..ac27ebb31c9b 100644
--- a/arch/arm/mach-s3c2416/mach-smdk2416.c
+++ b/arch/arm/mach-s3c2416/mach-smdk2416.c
@@ -23,6 +23,7 @@
#include <linux/mtd/partitions.h>
#include <linux/gpio.h>
#include <linux/fb.h>
+#include <linux/delay.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -35,6 +36,7 @@
#include <plat/regs-serial.h>
#include <mach/regs-gpio.h>
#include <mach/regs-lcd.h>
+#include <mach/regs-s3c2443-clock.h>
#include <mach/idle.h>
#include <mach/leds-gpio.h>
@@ -47,6 +49,7 @@
#include <plat/cpu.h>
#include <plat/nand.h>
#include <plat/sdhci.h>
+#include <plat/udc.h>
#include <plat/regs-fb-v4.h>
#include <plat/fb.h>
@@ -121,6 +124,27 @@ static struct s3c2410_uartcfg smdk2416_uartcfgs[] __initdata = {
}
};
+void smdk2416_hsudc_gpio_init(void)
+{
+ s3c_gpio_setpull(S3C2410_GPH(14), S3C_GPIO_PULL_UP);
+ s3c_gpio_setpull(S3C2410_GPF(2), S3C_GPIO_PULL_NONE);
+ s3c_gpio_cfgpin(S3C2410_GPH(14), S3C_GPIO_SFN(1));
+ s3c2410_modify_misccr(S3C2416_MISCCR_SEL_SUSPND, 0);
+}
+
+void smdk2416_hsudc_gpio_uninit(void)
+{
+ s3c2410_modify_misccr(S3C2416_MISCCR_SEL_SUSPND, 1);
+ s3c_gpio_setpull(S3C2410_GPH(14), S3C_GPIO_PULL_NONE);
+ s3c_gpio_cfgpin(S3C2410_GPH(14), S3C_GPIO_SFN(0));
+}
+
+struct s3c24xx_hsudc_platdata smdk2416_hsudc_platdata = {
+ .epnum = 9,
+ .gpio_init = smdk2416_hsudc_gpio_init,
+ .gpio_uninit = smdk2416_hsudc_gpio_uninit,
+};
+
struct s3c_fb_pd_win smdk2416_fb_win[] = {
[0] = {
/* think this is the same as the smdk6410 */
@@ -186,6 +210,7 @@ static struct platform_device *smdk2416_devices[] __initdata = {
&s3c_device_i2c0,
&s3c_device_hsmmc0,
&s3c_device_hsmmc1,
+ &s3c_device_usb_hsudc,
};
static void __init smdk2416_map_io(void)
@@ -203,6 +228,8 @@ static void __init smdk2416_machine_init(void)
s3c_sdhci0_set_platdata(&smdk2416_hsmmc0_pdata);
s3c_sdhci1_set_platdata(&smdk2416_hsmmc1_pdata);
+ s3c24xx_hsudc_set_platdata(&smdk2416_hsudc_platdata);
+
gpio_request(S3C2410_GPB(4), "USBHost Power");
gpio_direction_output(S3C2410_GPB(4), 1);
diff --git a/arch/arm/mach-s3c2416/pm.c b/arch/arm/mach-s3c2416/pm.c
index 4a04205b04d5..41db2b21e213 100644
--- a/arch/arm/mach-s3c2416/pm.c
+++ b/arch/arm/mach-s3c2416/pm.c
@@ -11,6 +11,7 @@
*/
#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/io.h>
#include <asm/cacheflush.h>
@@ -55,30 +56,26 @@ static int s3c2416_pm_add(struct sys_device *sysdev)
return 0;
}
-static int s3c2416_pm_suspend(struct sys_device *dev, pm_message_t state)
+static struct sysdev_driver s3c2416_pm_driver = {
+ .add = s3c2416_pm_add,
+};
+
+static __init int s3c2416_pm_init(void)
{
- return 0;
+ return sysdev_driver_register(&s3c2416_sysclass, &s3c2416_pm_driver);
}
-static int s3c2416_pm_resume(struct sys_device *dev)
+arch_initcall(s3c2416_pm_init);
+
+
+static void s3c2416_pm_resume(void)
{
/* unset the return-from-sleep amd inform flags */
__raw_writel(0x0, S3C2443_PWRMODE);
__raw_writel(0x0, S3C2412_INFORM0);
__raw_writel(0x0, S3C2412_INFORM1);
-
- return 0;
}
-static struct sysdev_driver s3c2416_pm_driver = {
- .add = s3c2416_pm_add,
- .suspend = s3c2416_pm_suspend,
+struct syscore_ops s3c2416_pm_syscore_ops = {
.resume = s3c2416_pm_resume,
};
-
-static __init int s3c2416_pm_init(void)
-{
- return sysdev_driver_register(&s3c2416_sysclass, &s3c2416_pm_driver);
-}
-
-arch_initcall(s3c2416_pm_init);
diff --git a/arch/arm/mach-s3c2416/s3c2416.c b/arch/arm/mach-s3c2416/s3c2416.c
index ba7fd8737434..494ce913dc95 100644
--- a/arch/arm/mach-s3c2416/s3c2416.c
+++ b/arch/arm/mach-s3c2416/s3c2416.c
@@ -32,6 +32,7 @@
#include <linux/platform_device.h>
#include <linux/serial_core.h>
#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/clk.h>
#include <linux/io.h>
@@ -54,6 +55,7 @@
#include <plat/devs.h>
#include <plat/cpu.h>
#include <plat/sdhci.h>
+#include <plat/pm.h>
#include <plat/iic-core.h>
#include <plat/fb-core.h>
@@ -95,6 +97,9 @@ int __init s3c2416_init(void)
s3c_fb_setname("s3c2443-fb");
+ register_syscore_ops(&s3c2416_pm_syscore_ops);
+ register_syscore_ops(&s3c24xx_irq_syscore_ops);
+
return sysdev_register(&s3c2416_sysdev);
}
diff --git a/arch/arm/mach-s3c2440/mach-osiris.c b/arch/arm/mach-s3c2440/mach-osiris.c
index 14dc67897757..d88536393310 100644
--- a/arch/arm/mach-s3c2440/mach-osiris.c
+++ b/arch/arm/mach-s3c2440/mach-osiris.c
@@ -17,7 +17,7 @@
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/device.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/serial_core.h>
#include <linux/clk.h>
#include <linux/i2c.h>
@@ -284,7 +284,7 @@ static struct platform_device osiris_pcmcia = {
#ifdef CONFIG_PM
static unsigned char pm_osiris_ctrl0;
-static int osiris_pm_suspend(struct sys_device *sd, pm_message_t state)
+static int osiris_pm_suspend(void)
{
unsigned int tmp;
@@ -304,7 +304,7 @@ static int osiris_pm_suspend(struct sys_device *sd, pm_message_t state)
return 0;
}
-static int osiris_pm_resume(struct sys_device *sd)
+static void osiris_pm_resume(void)
{
if (pm_osiris_ctrl0 & OSIRIS_CTRL0_FIX8)
__raw_writeb(OSIRIS_CTRL1_FIX8, OSIRIS_VA_CTRL1);
@@ -312,8 +312,6 @@ static int osiris_pm_resume(struct sys_device *sd)
__raw_writeb(pm_osiris_ctrl0, OSIRIS_VA_CTRL0);
s3c_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPA21_nRSTOUT);
-
- return 0;
}
#else
@@ -321,16 +319,11 @@ static int osiris_pm_resume(struct sys_device *sd)
#define osiris_pm_resume NULL
#endif
-static struct sysdev_class osiris_pm_sysclass = {
- .name = "mach-osiris",
+static struct syscore_ops osiris_pm_syscore_ops = {
.suspend = osiris_pm_suspend,
.resume = osiris_pm_resume,
};
-static struct sys_device osiris_pm_sysdev = {
- .cls = &osiris_pm_sysclass,
-};
-
/* Link for DVS driver to TPS65011 */
static void osiris_tps_release(struct device *dev)
@@ -439,8 +432,7 @@ static void __init osiris_map_io(void)
static void __init osiris_init(void)
{
- sysdev_class_register(&osiris_pm_sysclass);
- sysdev_register(&osiris_pm_sysdev);
+ register_syscore_ops(&osiris_pm_syscore_ops);
s3c_i2c0_set_platdata(NULL);
s3c_nand_set_platdata(&osiris_nand_info);
diff --git a/arch/arm/mach-s3c2440/s3c2440.c b/arch/arm/mach-s3c2440/s3c2440.c
index f7663f731ea0..ce99ff72838d 100644
--- a/arch/arm/mach-s3c2440/s3c2440.c
+++ b/arch/arm/mach-s3c2440/s3c2440.c
@@ -19,6 +19,7 @@
#include <linux/platform_device.h>
#include <linux/serial_core.h>
#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/gpio.h>
#include <linux/clk.h>
#include <linux/io.h>
@@ -33,6 +34,7 @@
#include <plat/devs.h>
#include <plat/cpu.h>
#include <plat/s3c244x.h>
+#include <plat/pm.h>
#include <plat/gpio-core.h>
#include <plat/gpio-cfg.h>
@@ -51,6 +53,12 @@ int __init s3c2440_init(void)
s3c_device_wdt.resource[1].start = IRQ_S3C2440_WDT;
s3c_device_wdt.resource[1].end = IRQ_S3C2440_WDT;
+ /* register suspend/resume handlers */
+
+ register_syscore_ops(&s3c2410_pm_syscore_ops);
+ register_syscore_ops(&s3c244x_pm_syscore_ops);
+ register_syscore_ops(&s3c24xx_irq_syscore_ops);
+
/* register our system device for everything else */
return sysdev_register(&s3c2440_sysdev);
diff --git a/arch/arm/mach-s3c2440/s3c2442.c b/arch/arm/mach-s3c2440/s3c2442.c
index ecf813546554..6224bad4d604 100644
--- a/arch/arm/mach-s3c2440/s3c2442.c
+++ b/arch/arm/mach-s3c2440/s3c2442.c
@@ -29,6 +29,7 @@
#include <linux/err.h>
#include <linux/device.h>
#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/mutex.h>
@@ -45,6 +46,7 @@
#include <plat/clock.h>
#include <plat/cpu.h>
#include <plat/s3c244x.h>
+#include <plat/pm.h>
#include <plat/gpio-core.h>
#include <plat/gpio-cfg.h>
@@ -167,6 +169,10 @@ int __init s3c2442_init(void)
{
printk("S3C2442: Initialising architecture\n");
+ register_syscore_ops(&s3c2410_pm_syscore_ops);
+ register_syscore_ops(&s3c244x_pm_syscore_ops);
+ register_syscore_ops(&s3c24xx_irq_syscore_ops);
+
return sysdev_register(&s3c2442_sysdev);
}
diff --git a/arch/arm/mach-s3c2440/s3c244x-irq.c b/arch/arm/mach-s3c2440/s3c244x-irq.c
index de07c2feaa32..c63e8f26d901 100644
--- a/arch/arm/mach-s3c2440/s3c244x-irq.c
+++ b/arch/arm/mach-s3c2440/s3c244x-irq.c
@@ -116,8 +116,6 @@ static int s3c244x_irq_add(struct sys_device *sysdev)
static struct sysdev_driver s3c2440_irq_driver = {
.add = s3c244x_irq_add,
- .suspend = s3c24xx_irq_suspend,
- .resume = s3c24xx_irq_resume,
};
static int s3c2440_irq_init(void)
@@ -129,8 +127,6 @@ arch_initcall(s3c2440_irq_init);
static struct sysdev_driver s3c2442_irq_driver = {
.add = s3c244x_irq_add,
- .suspend = s3c24xx_irq_suspend,
- .resume = s3c24xx_irq_resume,
};
diff --git a/arch/arm/mach-s3c2440/s3c244x.c b/arch/arm/mach-s3c2440/s3c244x.c
index 90c1707b9c95..7e8a23d2098a 100644
--- a/arch/arm/mach-s3c2440/s3c244x.c
+++ b/arch/arm/mach-s3c2440/s3c244x.c
@@ -19,6 +19,7 @@
#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/clk.h>
#include <linux/io.h>
@@ -134,45 +135,14 @@ void __init s3c244x_init_clocks(int xtal)
s3c2410_baseclk_add();
}
-#ifdef CONFIG_PM
-
-static struct sleep_save s3c244x_sleep[] = {
- SAVE_ITEM(S3C2440_DSC0),
- SAVE_ITEM(S3C2440_DSC1),
- SAVE_ITEM(S3C2440_GPJDAT),
- SAVE_ITEM(S3C2440_GPJCON),
- SAVE_ITEM(S3C2440_GPJUP)
-};
-
-static int s3c244x_suspend(struct sys_device *dev, pm_message_t state)
-{
- s3c_pm_do_save(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep));
- return 0;
-}
-
-static int s3c244x_resume(struct sys_device *dev)
-{
- s3c_pm_do_restore(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep));
- return 0;
-}
-
-#else
-#define s3c244x_suspend NULL
-#define s3c244x_resume NULL
-#endif
-
/* Since the S3C2442 and S3C2440 share items, put both sysclasses here */
struct sysdev_class s3c2440_sysclass = {
.name = "s3c2440-core",
- .suspend = s3c244x_suspend,
- .resume = s3c244x_resume
};
struct sysdev_class s3c2442_sysclass = {
.name = "s3c2442-core",
- .suspend = s3c244x_suspend,
- .resume = s3c244x_resume
};
/* need to register class before we actually register the device, and
@@ -194,3 +164,33 @@ static int __init s3c2442_core_init(void)
}
core_initcall(s3c2442_core_init);
+
+
+#ifdef CONFIG_PM
+static struct sleep_save s3c244x_sleep[] = {
+ SAVE_ITEM(S3C2440_DSC0),
+ SAVE_ITEM(S3C2440_DSC1),
+ SAVE_ITEM(S3C2440_GPJDAT),
+ SAVE_ITEM(S3C2440_GPJCON),
+ SAVE_ITEM(S3C2440_GPJUP)
+};
+
+static int s3c244x_suspend(void)
+{
+ s3c_pm_do_save(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep));
+ return 0;
+}
+
+static void s3c244x_resume(void)
+{
+ s3c_pm_do_restore(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep));
+}
+#else
+#define s3c244x_suspend NULL
+#define s3c244x_resume NULL
+#endif
+
+struct syscore_ops s3c244x_pm_syscore_ops = {
+ .suspend = s3c244x_suspend,
+ .resume = s3c244x_resume,
+};
diff --git a/arch/arm/mach-s3c64xx/irq-pm.c b/arch/arm/mach-s3c64xx/irq-pm.c
index da1bec64b9da..8bec61e242c7 100644
--- a/arch/arm/mach-s3c64xx/irq-pm.c
+++ b/arch/arm/mach-s3c64xx/irq-pm.c
@@ -13,7 +13,7 @@
*/
#include <linux/kernel.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/interrupt.h>
#include <linux/serial_core.h>
#include <linux/irq.h>
@@ -54,7 +54,7 @@ static struct irq_grp_save {
static u32 irq_uart_mask[CONFIG_SERIAL_SAMSUNG_UARTS];
-static int s3c64xx_irq_pm_suspend(struct sys_device *dev, pm_message_t state)
+static int s3c64xx_irq_pm_suspend(void)
{
struct irq_grp_save *grp = eint_grp_save;
int i;
@@ -75,7 +75,7 @@ static int s3c64xx_irq_pm_suspend(struct sys_device *dev, pm_message_t state)
return 0;
}
-static int s3c64xx_irq_pm_resume(struct sys_device *dev)
+static void s3c64xx_irq_pm_resume(void)
{
struct irq_grp_save *grp = eint_grp_save;
int i;
@@ -94,18 +94,18 @@ static int s3c64xx_irq_pm_resume(struct sys_device *dev)
}
S3C_PMDBG("%s: IRQ configuration restored\n", __func__);
- return 0;
}
-static struct sysdev_driver s3c64xx_irq_driver = {
+struct syscore_ops s3c64xx_irq_syscore_ops = {
.suspend = s3c64xx_irq_pm_suspend,
.resume = s3c64xx_irq_pm_resume,
};
-static int __init s3c64xx_irq_pm_init(void)
+static __init int s3c64xx_syscore_init(void)
{
- return sysdev_driver_register(&s3c64xx_sysclass, &s3c64xx_irq_driver);
-}
+ register_syscore_ops(&s3c64xx_irq_syscore_ops);
-arch_initcall(s3c64xx_irq_pm_init);
+ return 0;
+}
+core_initcall(s3c64xx_syscore_init);
diff --git a/arch/arm/mach-s3c64xx/irq.c b/arch/arm/mach-s3c64xx/irq.c
index 67a145d440f3..97660c8141ae 100644
--- a/arch/arm/mach-s3c64xx/irq.c
+++ b/arch/arm/mach-s3c64xx/irq.c
@@ -58,12 +58,7 @@ void __init s3c64xx_init_irq(u32 vic0_valid, u32 vic1_valid)
vic_init(VA_VIC1, IRQ_VIC1_BASE, vic1_valid, 0);
/* add the timer sub-irqs */
-
- s3c_init_vic_timer_irq(IRQ_TIMER0_VIC, IRQ_TIMER0);
- s3c_init_vic_timer_irq(IRQ_TIMER1_VIC, IRQ_TIMER1);
- s3c_init_vic_timer_irq(IRQ_TIMER2_VIC, IRQ_TIMER2);
- s3c_init_vic_timer_irq(IRQ_TIMER3_VIC, IRQ_TIMER3);
- s3c_init_vic_timer_irq(IRQ_TIMER4_VIC, IRQ_TIMER4);
+ s3c_init_vic_timer_irq(5, IRQ_TIMER0);
s3c_init_uart_irqs(uart_irqs, ARRAY_SIZE(uart_irqs));
}
diff --git a/arch/arm/mach-s5p64x0/include/mach/uncompress.h b/arch/arm/mach-s5p64x0/include/mach/uncompress.h
index c65b229aab23..1608faf870ff 100644
--- a/arch/arm/mach-s5p64x0/include/mach/uncompress.h
+++ b/arch/arm/mach-s5p64x0/include/mach/uncompress.h
@@ -24,8 +24,8 @@ typedef unsigned int upf_t; /* cannot include linux/serial_core.h */
/* uart setup */
-static unsigned int fifo_mask;
-static unsigned int fifo_max;
+unsigned int fifo_mask;
+unsigned int fifo_max;
/* forward declerations */
@@ -43,7 +43,7 @@ static void arch_detect_cpu(void);
/* how many bytes we allow into the FIFO at a time in FIFO mode */
#define FIFO_MAX (14)
-static unsigned long uart_base;
+unsigned long uart_base;
static __inline__ void get_uart_base(void)
{
diff --git a/arch/arm/mach-s5pv210/pm.c b/arch/arm/mach-s5pv210/pm.c
index 549d7924fd4c..24febae3d4c0 100644
--- a/arch/arm/mach-s5pv210/pm.c
+++ b/arch/arm/mach-s5pv210/pm.c
@@ -16,6 +16,7 @@
#include <linux/init.h>
#include <linux/suspend.h>
+#include <linux/syscore_ops.h>
#include <linux/io.h>
#include <plat/cpu.h>
@@ -140,7 +141,17 @@ static int s5pv210_pm_add(struct sys_device *sysdev)
return 0;
}
-static int s5pv210_pm_resume(struct sys_device *dev)
+static struct sysdev_driver s5pv210_pm_driver = {
+ .add = s5pv210_pm_add,
+};
+
+static __init int s5pv210_pm_drvinit(void)
+{
+ return sysdev_driver_register(&s5pv210_sysclass, &s5pv210_pm_driver);
+}
+arch_initcall(s5pv210_pm_drvinit);
+
+static void s5pv210_pm_resume(void)
{
u32 tmp;
@@ -150,17 +161,15 @@ static int s5pv210_pm_resume(struct sys_device *dev)
__raw_writel(tmp , S5P_OTHERS);
s3c_pm_do_restore_core(s5pv210_core_save, ARRAY_SIZE(s5pv210_core_save));
-
- return 0;
}
-static struct sysdev_driver s5pv210_pm_driver = {
- .add = s5pv210_pm_add,
+static struct syscore_ops s5pv210_pm_syscore_ops = {
.resume = s5pv210_pm_resume,
};
-static __init int s5pv210_pm_drvinit(void)
+static __init int s5pv210_pm_syscore_init(void)
{
- return sysdev_driver_register(&s5pv210_sysclass, &s5pv210_pm_driver);
+ register_syscore_ops(&s5pv210_pm_syscore_ops);
+ return 0;
}
-arch_initcall(s5pv210_pm_drvinit);
+arch_initcall(s5pv210_pm_syscore_init);
diff --git a/arch/arm/mach-sa1100/include/mach/memory.h b/arch/arm/mach-sa1100/include/mach/memory.h
index a44da6a2916c..cff31ee246b7 100644
--- a/arch/arm/mach-sa1100/include/mach/memory.h
+++ b/arch/arm/mach-sa1100/include/mach/memory.h
@@ -14,18 +14,8 @@
*/
#define PLAT_PHYS_OFFSET UL(0xc0000000)
-#ifndef __ASSEMBLY__
-
#ifdef CONFIG_SA1111
-void sa1111_adjust_zones(unsigned long *size, unsigned long *holes);
-
-#define arch_adjust_zones(size, holes) \
- sa1111_adjust_zones(size, holes)
-
-#define ISA_DMA_THRESHOLD (PHYS_OFFSET + SZ_1M - 1)
-#define MAX_DMA_ADDRESS (PAGE_OFFSET + SZ_1M)
-
-#endif
+#define ARM_DMA_ZONE_SIZE SZ_1M
#endif
/*
diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c
index 423ddb3d65e9..dfbf824a69fa 100644
--- a/arch/arm/mach-sa1100/irq.c
+++ b/arch/arm/mach-sa1100/irq.c
@@ -14,7 +14,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/ioport.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <mach/hardware.h>
#include <asm/mach/irq.h>
@@ -234,7 +234,7 @@ static struct sa1100irq_state {
unsigned int iccr;
} sa1100irq_state;
-static int sa1100irq_suspend(struct sys_device *dev, pm_message_t state)
+static int sa1100irq_suspend(void)
{
struct sa1100irq_state *st = &sa1100irq_state;
@@ -264,7 +264,7 @@ static int sa1100irq_suspend(struct sys_device *dev, pm_message_t state)
return 0;
}
-static int sa1100irq_resume(struct sys_device *dev)
+static void sa1100irq_resume(void)
{
struct sa1100irq_state *st = &sa1100irq_state;
@@ -277,24 +277,17 @@ static int sa1100irq_resume(struct sys_device *dev)
ICMR = st->icmr;
}
- return 0;
}
-static struct sysdev_class sa1100irq_sysclass = {
- .name = "sa11x0-irq",
+static struct syscore_ops sa1100irq_syscore_ops = {
.suspend = sa1100irq_suspend,
.resume = sa1100irq_resume,
};
-static struct sys_device sa1100irq_device = {
- .id = 0,
- .cls = &sa1100irq_sysclass,
-};
-
static int __init sa1100irq_init_devicefs(void)
{
- sysdev_class_register(&sa1100irq_sysclass);
- return sysdev_register(&sa1100irq_device);
+ register_syscore_ops(&sa1100irq_syscore_ops);
+ return 0;
}
device_initcall(sa1100irq_init_devicefs);
diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c
index ae4f3d80416f..fa6602491d54 100644
--- a/arch/arm/mach-sa1100/time.c
+++ b/arch/arm/mach-sa1100/time.c
@@ -92,25 +92,11 @@ sa1100_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *c)
static struct clock_event_device ckevt_sa1100_osmr0 = {
.name = "osmr0",
.features = CLOCK_EVT_FEAT_ONESHOT,
- .shift = 32,
.rating = 200,
.set_next_event = sa1100_osmr0_set_next_event,
.set_mode = sa1100_osmr0_set_mode,
};
-static cycle_t sa1100_read_oscr(struct clocksource *s)
-{
- return OSCR;
-}
-
-static struct clocksource cksrc_sa1100_oscr = {
- .name = "oscr",
- .rating = 200,
- .read = sa1100_read_oscr,
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
static struct irqaction sa1100_timer_irq = {
.name = "ost0",
.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
@@ -120,14 +106,13 @@ static struct irqaction sa1100_timer_irq = {
static void __init sa1100_timer_init(void)
{
- OIER = 0; /* disable any timer interrupts */
- OSSR = 0xf; /* clear status on all timers */
+ OIER = 0;
+ OSSR = OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3;
init_fixed_sched_clock(&cd, sa1100_update_sched_clock, 32,
3686400, SC_MULT, SC_SHIFT);
- ckevt_sa1100_osmr0.mult =
- div_sc(3686400, NSEC_PER_SEC, ckevt_sa1100_osmr0.shift);
+ clockevents_calc_mult_shift(&ckevt_sa1100_osmr0, 3686400, 4);
ckevt_sa1100_osmr0.max_delta_ns =
clockevent_delta2ns(0x7fffffff, &ckevt_sa1100_osmr0);
ckevt_sa1100_osmr0.min_delta_ns =
@@ -136,7 +121,8 @@ static void __init sa1100_timer_init(void)
setup_irq(IRQ_OST0, &sa1100_timer_irq);
- clocksource_register_hz(&cksrc_sa1100_oscr, CLOCK_TICK_RATE);
+ clocksource_mmio_init(&OSCR, "oscr", CLOCK_TICK_RATE, 200, 32,
+ clocksource_mmio_readl_up);
clockevents_register_device(&ckevt_sa1100_osmr0);
}
diff --git a/arch/arm/mach-shark/include/mach/memory.h b/arch/arm/mach-shark/include/mach/memory.h
index 9afb17000008..4c0831f83b0c 100644
--- a/arch/arm/mach-shark/include/mach/memory.h
+++ b/arch/arm/mach-shark/include/mach/memory.h
@@ -17,25 +17,7 @@
*/
#define PLAT_PHYS_OFFSET UL(0x08000000)
-#ifndef __ASSEMBLY__
-
-static inline void __arch_adjust_zones(unsigned long *zone_size, unsigned long *zhole_size)
-{
- /* Only the first 4 MB (=1024 Pages) are usable for DMA */
- /* See dev / -> .properties in OpenFirmware. */
- zone_size[1] = zone_size[0] - 1024;
- zone_size[0] = 1024;
- zhole_size[1] = zhole_size[0];
- zhole_size[0] = 0;
-}
-
-#define arch_adjust_zones(size, holes) \
- __arch_adjust_zones(size, holes)
-
-#define ISA_DMA_THRESHOLD (PHYS_OFFSET + SZ_4M - 1)
-#define MAX_DMA_ADDRESS (PAGE_OFFSET + SZ_4M)
-
-#endif
+#define ARM_DMA_ZONE_SIZE SZ_4M
/*
* Cache flushing area
diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile
index e2507f66f9d5..612b27000c3e 100644
--- a/arch/arm/mach-shmobile/Makefile
+++ b/arch/arm/mach-shmobile/Makefile
@@ -30,6 +30,11 @@ obj-$(CONFIG_ARCH_SH7377) += entry-intc.o
obj-$(CONFIG_ARCH_SH7372) += entry-intc.o
obj-$(CONFIG_ARCH_SH73A0) += entry-gic.o
+# PM objects
+obj-$(CONFIG_SUSPEND) += suspend.o
+obj-$(CONFIG_CPU_IDLE) += cpuidle.o
+obj-$(CONFIG_ARCH_SH7372) += pm-sh7372.o sleep-sh7372.o
+
# Board objects
obj-$(CONFIG_MACH_G3EVM) += board-g3evm.o
obj-$(CONFIG_MACH_G4EVM) += board-g4evm.o
diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c
index 3e6f0aab460b..c95258c274c1 100644
--- a/arch/arm/mach-shmobile/board-ag5evm.c
+++ b/arch/arm/mach-shmobile/board-ag5evm.c
@@ -34,6 +34,8 @@
#include <linux/input/sh_keysc.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sh_mmcif.h>
+#include <linux/mmc/sh_mobile_sdhi.h>
+#include <linux/mfd/tmio.h>
#include <linux/sh_clk.h>
#include <video/sh_mobile_lcdc.h>
#include <video/sh_mipi_dsi.h>
@@ -156,10 +158,19 @@ static struct resource sh_mmcif_resources[] = {
},
};
+static struct sh_mmcif_dma sh_mmcif_dma = {
+ .chan_priv_rx = {
+ .slave_id = SHDMA_SLAVE_MMCIF_RX,
+ },
+ .chan_priv_tx = {
+ .slave_id = SHDMA_SLAVE_MMCIF_TX,
+ },
+};
static struct sh_mmcif_plat_data sh_mmcif_platdata = {
.sup_pclk = 0,
.ocr = MMC_VDD_165_195,
.caps = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE,
+ .dma = &sh_mmcif_dma,
};
static struct platform_device mmc_device = {
@@ -296,11 +307,13 @@ static struct platform_device lcdc0_device = {
/* MIPI-DSI */
static struct resource mipidsi0_resources[] = {
[0] = {
+ .name = "DSI0",
.start = 0xfeab0000,
.end = 0xfeab3fff,
.flags = IORESOURCE_MEM,
},
[1] = {
+ .name = "DSI0",
.start = 0xfeab4000,
.end = 0xfeab7fff,
.flags = IORESOURCE_MEM,
@@ -325,6 +338,89 @@ static struct platform_device mipidsi0_device = {
},
};
+static struct sh_mobile_sdhi_info sdhi0_info = {
+ .dma_slave_tx = SHDMA_SLAVE_SDHI0_TX,
+ .dma_slave_rx = SHDMA_SLAVE_SDHI0_RX,
+ .tmio_caps = MMC_CAP_SD_HIGHSPEED,
+ .tmio_ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
+};
+
+static struct resource sdhi0_resources[] = {
+ [0] = {
+ .name = "SDHI0",
+ .start = 0xee100000,
+ .end = 0xee1000ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = gic_spi(83),
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = gic_spi(84),
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ .start = gic_spi(85),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device sdhi0_device = {
+ .name = "sh_mobile_sdhi",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(sdhi0_resources),
+ .resource = sdhi0_resources,
+ .dev = {
+ .platform_data = &sdhi0_info,
+ },
+};
+
+void ag5evm_sdhi1_set_pwr(struct platform_device *pdev, int state)
+{
+ gpio_set_value(GPIO_PORT114, state);
+}
+
+static struct sh_mobile_sdhi_info sh_sdhi1_platdata = {
+ .dma_slave_tx = SHDMA_SLAVE_SDHI1_TX,
+ .dma_slave_rx = SHDMA_SLAVE_SDHI1_RX,
+ .tmio_flags = TMIO_MMC_WRPROTECT_DISABLE,
+ .tmio_caps = MMC_CAP_NONREMOVABLE,
+ .tmio_ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
+ .set_pwr = ag5evm_sdhi1_set_pwr,
+};
+
+static struct resource sdhi1_resources[] = {
+ [0] = {
+ .name = "SDHI1",
+ .start = 0xee120000,
+ .end = 0xee1200ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = gic_spi(87),
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = gic_spi(88),
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ .start = gic_spi(89),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device sdhi1_device = {
+ .name = "sh_mobile_sdhi",
+ .id = 1,
+ .dev = {
+ .platform_data = &sh_sdhi1_platdata,
+ },
+ .num_resources = ARRAY_SIZE(sdhi1_resources),
+ .resource = sdhi1_resources,
+};
+
static struct platform_device *ag5evm_devices[] __initdata = {
&eth_device,
&keysc_device,
@@ -333,6 +429,8 @@ static struct platform_device *ag5evm_devices[] __initdata = {
&irda_device,
&lcdc0_device,
&mipidsi0_device,
+ &sdhi0_device,
+ &sdhi1_device,
};
static struct map_desc ag5evm_io_desc[] __initdata = {
@@ -454,6 +552,26 @@ static void __init ag5evm_init(void)
/* MIPI-DSI clock setup */
__raw_writel(0x2a809010, DSI0PHYCR);
+ /* enable SDHI0 on CN15 [SD I/F] */
+ gpio_request(GPIO_FN_SDHICD0, NULL);
+ gpio_request(GPIO_FN_SDHIWP0, NULL);
+ gpio_request(GPIO_FN_SDHICMD0, NULL);
+ gpio_request(GPIO_FN_SDHICLK0, NULL);
+ gpio_request(GPIO_FN_SDHID0_3, NULL);
+ gpio_request(GPIO_FN_SDHID0_2, NULL);
+ gpio_request(GPIO_FN_SDHID0_1, NULL);
+ gpio_request(GPIO_FN_SDHID0_0, NULL);
+
+ /* enable SDHI1 on CN4 [WLAN I/F] */
+ gpio_request(GPIO_FN_SDHICLK1, NULL);
+ gpio_request(GPIO_FN_SDHICMD1_PU, NULL);
+ gpio_request(GPIO_FN_SDHID1_3_PU, NULL);
+ gpio_request(GPIO_FN_SDHID1_2_PU, NULL);
+ gpio_request(GPIO_FN_SDHID1_1_PU, NULL);
+ gpio_request(GPIO_FN_SDHID1_0_PU, NULL);
+ gpio_request(GPIO_PORT114, "sdhi1_power");
+ gpio_direction_output(GPIO_PORT114, 0);
+
#ifdef CONFIG_CACHE_L2X0
/* Shared attribute override enable, 64K*8way */
l2x0_init(__io(0xf0100000), 0x00460000, 0xc2000fff);
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c
index 1e35fa976d64..08acb6ec8139 100644
--- a/arch/arm/mach-shmobile/board-ap4evb.c
+++ b/arch/arm/mach-shmobile/board-ap4evb.c
@@ -316,8 +316,16 @@ static struct resource sdhi0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = evt2irq(0x0e00) /* SDHI0 */,
- .flags = IORESOURCE_IRQ,
+ .start = evt2irq(0x0e00) /* SDHI0_SDHI0I0 */,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = evt2irq(0x0e20) /* SDHI0_SDHI0I1 */,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ .start = evt2irq(0x0e40) /* SDHI0_SDHI0I2 */,
+ .flags = IORESOURCE_IRQ,
},
};
@@ -349,8 +357,16 @@ static struct resource sdhi1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = evt2irq(0x0e80),
- .flags = IORESOURCE_IRQ,
+ .start = evt2irq(0x0e80), /* SDHI1_SDHI1I0 */
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = evt2irq(0x0ea0), /* SDHI1_SDHI1I1 */
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ .start = evt2irq(0x0ec0), /* SDHI1_SDHI1I2 */
+ .flags = IORESOURCE_IRQ,
},
};
@@ -980,11 +996,6 @@ static void __init hdmi_init_pm_clock(void)
goto out;
}
- ret = clk_enable(&sh7372_pllc2_clk);
- if (ret < 0) {
- pr_err("Cannot enable pllc2 clock\n");
- goto out;
- }
pr_debug("PLLC2 set frequency %lu\n", rate);
ret = clk_set_parent(hdmi_ick, &sh7372_pllc2_clk);
@@ -1343,6 +1354,7 @@ static void __init ap4evb_init(void)
hdmi_init_pm_clock();
fsi_init_pm_clock();
+ sh7372_pm_init();
}
static void __init ap4evb_timer_init(void)
diff --git a/arch/arm/mach-shmobile/board-g4evm.c b/arch/arm/mach-shmobile/board-g4evm.c
index c87a7b7c5832..8e3c5559f27f 100644
--- a/arch/arm/mach-shmobile/board-g4evm.c
+++ b/arch/arm/mach-shmobile/board-g4evm.c
@@ -205,7 +205,7 @@ static struct resource sdhi0_resources[] = {
[0] = {
.name = "SDHI0",
.start = 0xe6d50000,
- .end = 0xe6d50nff,
+ .end = 0xe6d500ff,
.flags = IORESOURCE_MEM,
},
[1] = {
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index 7da2ca24229d..448ddbe43335 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -43,6 +43,7 @@
#include <linux/sh_intc.h>
#include <linux/tca6416_keypad.h>
#include <linux/usb/r8a66597.h>
+#include <linux/usb/renesas_usbhs.h>
#include <video/sh_mobile_hdmi.h>
#include <video/sh_mobile_lcdc.h>
@@ -143,7 +144,30 @@
* open | external VBUS | Function
*
* *1
- * CN31 is used as Host in Linux.
+ * CN31 is used as
+ * CONFIG_USB_R8A66597_HCD Host
+ * CONFIG_USB_RENESAS_USBHS Function
+ *
+ * CAUTION
+ *
+ * renesas_usbhs driver can use external interrupt mode
+ * (which come from USB-PHY) or autonomy mode (it use own interrupt)
+ * for detecting connection/disconnection when Function.
+ * USB will be power OFF while it has been disconnecting
+ * if external interrupt mode, and it is always power ON if autonomy mode,
+ *
+ * mackerel can not use external interrupt (IRQ7-PORT167) mode on "USB0",
+ * because Touchscreen is using IRQ7-PORT40.
+ * It is impossible to use IRQ7 demux on this board.
+ *
+ * We can use external interrupt mode USB-Function on "USB1".
+ * USB1 can become Host by r8a66597, and become Function by renesas_usbhs.
+ * But don't select both drivers in same time.
+ * These uses same IRQ number for request_irq(), and aren't supporting
+ * IRQF_SHARD / IORESOURCE_IRQ_SHAREABLE.
+ *
+ * Actually these are old/new version of USB driver.
+ * This mean its register will be broken if it supports SHARD IRQ,
*/
/*
@@ -185,6 +209,7 @@
* FIXME !!
*
* gpio_no_direction
+ * gpio_pull_down
* are quick_hack.
*
* current gpio frame work doesn't have
@@ -196,6 +221,16 @@ static void __init gpio_no_direction(u32 addr)
__raw_writeb(0x00, addr);
}
+static void __init gpio_pull_down(u32 addr)
+{
+ u8 data = __raw_readb(addr);
+
+ data &= 0x0F;
+ data |= 0xA0;
+
+ __raw_writeb(data, addr);
+}
+
/* MTD */
static struct mtd_partition nor_flash_partitions[] = {
{
@@ -458,12 +493,6 @@ static void __init hdmi_init_pm_clock(void)
goto out;
}
- ret = clk_enable(&sh7372_pllc2_clk);
- if (ret < 0) {
- pr_err("Cannot enable pllc2 clock\n");
- goto out;
- }
-
pr_debug("PLLC2 set frequency %lu\n", rate);
ret = clk_set_parent(hdmi_ick, &sh7372_pllc2_clk);
@@ -515,6 +544,157 @@ static struct platform_device usb1_host_device = {
.resource = usb1_host_resources,
};
+/* USB1 (Function) */
+#define USB_PHY_MODE (1 << 4)
+#define USB_PHY_INT_EN ((1 << 3) | (1 << 2))
+#define USB_PHY_ON (1 << 1)
+#define USB_PHY_OFF (1 << 0)
+#define USB_PHY_INT_CLR (USB_PHY_ON | USB_PHY_OFF)
+
+struct usbhs_private {
+ unsigned int irq;
+ unsigned int usbphyaddr;
+ unsigned int usbcrcaddr;
+ struct renesas_usbhs_platform_info info;
+};
+
+#define usbhs_get_priv(pdev) \
+ container_of(renesas_usbhs_get_info(pdev), \
+ struct usbhs_private, info)
+
+#define usbhs_is_connected(priv) \
+ (!((1 << 7) & __raw_readw(priv->usbcrcaddr)))
+
+static int usbhs1_get_id(struct platform_device *pdev)
+{
+ return USBHS_GADGET;
+}
+
+static int usbhs1_get_vbus(struct platform_device *pdev)
+{
+ return usbhs_is_connected(usbhs_get_priv(pdev));
+}
+
+static irqreturn_t usbhs1_interrupt(int irq, void *data)
+{
+ struct platform_device *pdev = data;
+ struct usbhs_private *priv = usbhs_get_priv(pdev);
+
+ dev_dbg(&pdev->dev, "%s\n", __func__);
+
+ renesas_usbhs_call_notify_hotplug(pdev);
+
+ /* clear status */
+ __raw_writew(__raw_readw(priv->usbphyaddr) | USB_PHY_INT_CLR,
+ priv->usbphyaddr);
+
+ return IRQ_HANDLED;
+}
+
+static int usbhs1_hardware_init(struct platform_device *pdev)
+{
+ struct usbhs_private *priv = usbhs_get_priv(pdev);
+ int ret;
+
+ irq_set_irq_type(priv->irq, IRQ_TYPE_LEVEL_HIGH);
+
+ /* clear interrupt status */
+ __raw_writew(USB_PHY_MODE | USB_PHY_INT_CLR, priv->usbphyaddr);
+
+ ret = request_irq(priv->irq, usbhs1_interrupt, 0,
+ dev_name(&pdev->dev), pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "request_irq err\n");
+ return ret;
+ }
+
+ /* enable USB phy interrupt */
+ __raw_writew(USB_PHY_MODE | USB_PHY_INT_EN, priv->usbphyaddr);
+
+ return 0;
+}
+
+static void usbhs1_hardware_exit(struct platform_device *pdev)
+{
+ struct usbhs_private *priv = usbhs_get_priv(pdev);
+
+ /* clear interrupt status */
+ __raw_writew(USB_PHY_MODE | USB_PHY_INT_CLR, priv->usbphyaddr);
+
+ free_irq(priv->irq, pdev);
+}
+
+static void usbhs1_phy_reset(struct platform_device *pdev)
+{
+ struct usbhs_private *priv = usbhs_get_priv(pdev);
+
+ /* init phy */
+ __raw_writew(0x8a0a, priv->usbcrcaddr);
+}
+
+static u32 usbhs1_pipe_cfg[] = {
+ USB_ENDPOINT_XFER_CONTROL,
+ USB_ENDPOINT_XFER_ISOC,
+ USB_ENDPOINT_XFER_ISOC,
+ USB_ENDPOINT_XFER_BULK,
+ USB_ENDPOINT_XFER_BULK,
+ USB_ENDPOINT_XFER_BULK,
+ USB_ENDPOINT_XFER_INT,
+ USB_ENDPOINT_XFER_INT,
+ USB_ENDPOINT_XFER_INT,
+ USB_ENDPOINT_XFER_BULK,
+ USB_ENDPOINT_XFER_BULK,
+ USB_ENDPOINT_XFER_BULK,
+ USB_ENDPOINT_XFER_BULK,
+ USB_ENDPOINT_XFER_BULK,
+ USB_ENDPOINT_XFER_BULK,
+ USB_ENDPOINT_XFER_BULK,
+};
+
+static struct usbhs_private usbhs1_private = {
+ .irq = evt2irq(0x0300), /* IRQ8 */
+ .usbphyaddr = 0xE60581E2, /* USBPHY1INTAP */
+ .usbcrcaddr = 0xE6058130, /* USBCR4 */
+ .info = {
+ .platform_callback = {
+ .hardware_init = usbhs1_hardware_init,
+ .hardware_exit = usbhs1_hardware_exit,
+ .phy_reset = usbhs1_phy_reset,
+ .get_id = usbhs1_get_id,
+ .get_vbus = usbhs1_get_vbus,
+ },
+ .driver_param = {
+ .buswait_bwait = 4,
+ .pipe_type = usbhs1_pipe_cfg,
+ .pipe_size = ARRAY_SIZE(usbhs1_pipe_cfg),
+ },
+ },
+};
+
+static struct resource usbhs1_resources[] = {
+ [0] = {
+ .name = "USBHS",
+ .start = 0xE68B0000,
+ .end = 0xE68B00E6 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = evt2irq(0x1ce0) /* USB1_USB1I0 */,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device usbhs1_device = {
+ .name = "renesas_usbhs",
+ .id = 1,
+ .dev = {
+ .platform_data = &usbhs1_private.info,
+ },
+ .num_resources = ARRAY_SIZE(usbhs1_resources),
+ .resource = usbhs1_resources,
+};
+
+
/* LED */
static struct gpio_led mackerel_leds[] = {
{
@@ -690,7 +870,15 @@ static struct resource sdhi0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = evt2irq(0x0e00) /* SDHI0 */,
+ .start = evt2irq(0x0e00) /* SDHI0_SDHI0I0 */,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = evt2irq(0x0e20) /* SDHI0_SDHI0I1 */,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ .start = evt2irq(0x0e40) /* SDHI0_SDHI0I2 */,
.flags = IORESOURCE_IRQ,
},
};
@@ -705,7 +893,7 @@ static struct platform_device sdhi0_device = {
},
};
-#if !defined(CONFIG_MMC_SH_MMCIF)
+#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
/* SDHI1 */
static struct sh_mobile_sdhi_info sdhi1_info = {
.dma_slave_tx = SHDMA_SLAVE_SDHI1_TX,
@@ -725,7 +913,15 @@ static struct resource sdhi1_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = evt2irq(0x0e80),
+ .start = evt2irq(0x0e80), /* SDHI1_SDHI1I0 */
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = evt2irq(0x0ea0), /* SDHI1_SDHI1I1 */
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ .start = evt2irq(0x0ec0), /* SDHI1_SDHI1I2 */
.flags = IORESOURCE_IRQ,
},
};
@@ -768,7 +964,15 @@ static struct resource sdhi2_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = evt2irq(0x1200),
+ .start = evt2irq(0x1200), /* SDHI2_SDHI2I0 */
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ .start = evt2irq(0x1220), /* SDHI2_SDHI2I1 */
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ .start = evt2irq(0x1240), /* SDHI2_SDHI2I2 */
.flags = IORESOURCE_IRQ,
},
};
@@ -803,6 +1007,15 @@ static struct resource sh_mmcif_resources[] = {
},
};
+static struct sh_mmcif_dma sh_mmcif_dma = {
+ .chan_priv_rx = {
+ .slave_id = SHDMA_SLAVE_MMCIF_RX,
+ },
+ .chan_priv_tx = {
+ .slave_id = SHDMA_SLAVE_MMCIF_TX,
+ },
+};
+
static struct sh_mmcif_plat_data sh_mmcif_plat = {
.sup_pclk = 0,
.ocr = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34,
@@ -810,6 +1023,7 @@ static struct sh_mmcif_plat_data sh_mmcif_plat = {
MMC_CAP_8_BIT_DATA |
MMC_CAP_NEEDS_POLL,
.get_cd = slot_cn7_get_cd,
+ .dma = &sh_mmcif_dma,
};
static struct platform_device sh_mmcif_device = {
@@ -858,37 +1072,23 @@ static struct soc_camera_link camera_link = {
.priv = &camera_info,
};
-static void dummy_release(struct device *dev)
+static struct platform_device *camera_device;
+
+static void mackerel_camera_release(struct device *dev)
{
+ soc_camera_platform_release(&camera_device);
}
-static struct platform_device camera_device = {
- .name = "soc_camera_platform",
- .dev = {
- .platform_data = &camera_info,
- .release = dummy_release,
- },
-};
-
static int mackerel_camera_add(struct soc_camera_link *icl,
struct device *dev)
{
- if (icl != &camera_link)
- return -ENODEV;
-
- camera_info.dev = dev;
-
- return platform_device_register(&camera_device);
+ return soc_camera_platform_add(icl, dev, &camera_device, &camera_link,
+ mackerel_camera_release, 0);
}
static void mackerel_camera_del(struct soc_camera_link *icl)
{
- if (icl != &camera_link)
- return;
-
- platform_device_unregister(&camera_device);
- memset(&camera_device.dev.kobj, 0,
- sizeof(camera_device.dev.kobj));
+ soc_camera_platform_del(icl, camera_device, &camera_link);
}
static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
@@ -935,12 +1135,13 @@ static struct platform_device *mackerel_devices[] __initdata = {
&smc911x_device,
&lcdc_device,
&usb1_host_device,
+ &usbhs1_device,
&leds_device,
&fsi_device,
&fsi_ak4643_device,
&fsi_hdmi_device,
&sdhi0_device,
-#if !defined(CONFIG_MMC_SH_MMCIF)
+#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
&sdhi1_device,
#endif
&sdhi2_device,
@@ -1030,6 +1231,7 @@ static void __init mackerel_map_io(void)
#define GPIO_PORT9CR 0xE6051009
#define GPIO_PORT10CR 0xE605100A
+#define GPIO_PORT168CR 0xE60520A8
#define SRCR4 0xe61580bc
#define USCCR1 0xE6058144
static void __init mackerel_init(void)
@@ -1088,6 +1290,7 @@ static void __init mackerel_init(void)
gpio_request(GPIO_FN_OVCN_1_114, NULL);
gpio_request(GPIO_FN_EXTLP_1, NULL);
gpio_request(GPIO_FN_OVCN2_1, NULL);
+ gpio_pull_down(GPIO_PORT168CR);
/* setup USB phy */
__raw_writew(0x8a0a, 0xE6058130); /* USBCR4 */
@@ -1140,7 +1343,7 @@ static void __init mackerel_init(void)
gpio_request(GPIO_FN_SDHID0_1, NULL);
gpio_request(GPIO_FN_SDHID0_0, NULL);
-#if !defined(CONFIG_MMC_SH_MMCIF)
+#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
/* enable SDHI1 */
gpio_request(GPIO_FN_SDHICMD1, NULL);
gpio_request(GPIO_FN_SDHICLK1, NULL);
@@ -1216,6 +1419,7 @@ static void __init mackerel_init(void)
platform_add_devices(mackerel_devices, ARRAY_SIZE(mackerel_devices));
hdmi_init_pm_clock();
+ sh7372_pm_init();
}
static void __init mackerel_timer_init(void)
diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c
index e9731b5a73ed..d17eb66f4ac2 100644
--- a/arch/arm/mach-shmobile/clock-sh7372.c
+++ b/arch/arm/mach-shmobile/clock-sh7372.c
@@ -44,6 +44,11 @@
#define DSI1PCKCR 0xe6150098
#define PLLC01CR 0xe6150028
#define PLLC2CR 0xe615002c
+#define RMSTPCR0 0xe6150110
+#define RMSTPCR1 0xe6150114
+#define RMSTPCR2 0xe6150118
+#define RMSTPCR3 0xe615011c
+#define RMSTPCR4 0xe6150120
#define SMSTPCR0 0xe6150130
#define SMSTPCR1 0xe6150134
#define SMSTPCR2 0xe6150138
@@ -421,9 +426,6 @@ static unsigned long fsidiv_recalc(struct clk *clk)
value = __raw_readl(clk->mapping->base);
- if ((value & 0x3) != 0x3)
- return 0;
-
value >>= 16;
if (value < 2)
return 0;
@@ -504,7 +506,7 @@ static struct clk *late_main_clks[] = {
enum { MSTP001,
MSTP131, MSTP130,
MSTP129, MSTP128, MSTP127, MSTP126, MSTP125,
- MSTP118, MSTP117, MSTP116,
+ MSTP118, MSTP117, MSTP116, MSTP113,
MSTP106, MSTP101, MSTP100,
MSTP223,
MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
@@ -527,6 +529,7 @@ static struct clk mstp_clks[MSTP_NR] = {
[MSTP118] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 18, 0), /* DSITX */
[MSTP117] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 17, 0), /* LCDC1 */
[MSTP116] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 16, 0), /* IIC0 */
+ [MSTP113] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 13, 0), /* MERAM */
[MSTP106] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 6, 0), /* JPU */
[MSTP101] = MSTP(&div4_clks[DIV4_M1], SMSTPCR1, 1, 0), /* VPU */
[MSTP100] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 0, 0), /* LCDC0 */
@@ -617,6 +620,7 @@ static struct clk_lookup lookups[] = {
CLKDEV_DEV_ID("sh-mipi-dsi.0", &mstp_clks[MSTP118]), /* DSITX0 */
CLKDEV_DEV_ID("sh_mobile_lcdc_fb.1", &mstp_clks[MSTP117]), /* LCDC1 */
CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* IIC0 */
+ CLKDEV_DEV_ID("sh_mobile_meram.0", &mstp_clks[MSTP113]), /* MERAM */
CLKDEV_DEV_ID("uio_pdrv_genirq.5", &mstp_clks[MSTP106]), /* JPU */
CLKDEV_DEV_ID("uio_pdrv_genirq.0", &mstp_clks[MSTP101]), /* VPU */
CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[MSTP100]), /* LCDC0 */
@@ -634,6 +638,7 @@ static struct clk_lookup lookups[] = {
CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */
CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP322]), /* USB0 */
CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[MSTP322]), /* USB0 */
+ CLKDEV_DEV_ID("renesas_usbhs.0", &mstp_clks[MSTP322]), /* USB0 */
CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */
CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */
CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMC */
@@ -644,6 +649,7 @@ static struct clk_lookup lookups[] = {
CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* IIC4 */
CLKDEV_DEV_ID("r8a66597_hcd.1", &mstp_clks[MSTP406]), /* USB1 */
CLKDEV_DEV_ID("r8a66597_udc.1", &mstp_clks[MSTP406]), /* USB1 */
+ CLKDEV_DEV_ID("renesas_usbhs.1", &mstp_clks[MSTP406]), /* USB1 */
CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */
CLKDEV_ICK_ID("ick", "sh-mobile-hdmi", &div6_reparent_clks[DIV6_HDMI]),
@@ -655,6 +661,13 @@ void __init sh7372_clock_init(void)
{
int k, ret = 0;
+ /* make sure MSTP bits on the RT/SH4AL-DSP side are off */
+ __raw_writel(0xe4ef8087, RMSTPCR0);
+ __raw_writel(0xffffffff, RMSTPCR1);
+ __raw_writel(0x37c7f7ff, RMSTPCR2);
+ __raw_writel(0xffffffff, RMSTPCR3);
+ __raw_writel(0xffe0fffd, RMSTPCR4);
+
for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
ret = clk_register(main_clks[k]);
diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c
index 7e58904c1c8c..bcacb1e8cf85 100644
--- a/arch/arm/mach-shmobile/clock-sh73a0.c
+++ b/arch/arm/mach-shmobile/clock-sh73a0.c
@@ -266,7 +266,8 @@ enum { MSTP001,
MSTP129, MSTP128, MSTP127, MSTP126, MSTP125, MSTP118, MSTP116, MSTP100,
MSTP219,
MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
- MSTP331, MSTP329, MSTP325, MSTP323, MSTP312,
+ MSTP331, MSTP329, MSTP325, MSTP323, MSTP318,
+ MSTP314, MSTP313, MSTP312, MSTP311,
MSTP411, MSTP410, MSTP403,
MSTP_NR };
@@ -295,7 +296,11 @@ static struct clk mstp_clks[MSTP_NR] = {
[MSTP329] = MSTP(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */
[MSTP325] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 25, 0), /* IrDA */
[MSTP323] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 23, 0), /* IIC1 */
+ [MSTP318] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 18, 0), /* SY-DMAC */
+ [MSTP314] = MSTP(&div6_clks[DIV6_SDHI0], SMSTPCR3, 14, 0), /* SDHI0 */
+ [MSTP313] = MSTP(&div6_clks[DIV6_SDHI1], SMSTPCR3, 13, 0), /* SDHI1 */
[MSTP312] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 12, 0), /* MMCIF0 */
+ [MSTP311] = MSTP(&div6_clks[DIV6_SDHI2], SMSTPCR3, 11, 0), /* SDHI2 */
[MSTP411] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 11, 0), /* IIC3 */
[MSTP410] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 10, 0), /* IIC4 */
[MSTP403] = MSTP(&r_clk, SMSTPCR4, 3, 0), /* KEYSC */
@@ -313,6 +318,9 @@ static struct clk_lookup lookups[] = {
CLKDEV_CON_ID("vck1_clk", &div6_clks[DIV6_VCK1]),
CLKDEV_CON_ID("vck2_clk", &div6_clks[DIV6_VCK2]),
CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]),
+ CLKDEV_CON_ID("sdhi0_clk", &div6_clks[DIV6_SDHI0]),
+ CLKDEV_CON_ID("sdhi1_clk", &div6_clks[DIV6_SDHI1]),
+ CLKDEV_CON_ID("sdhi2_clk", &div6_clks[DIV6_SDHI2]),
CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSIT]),
CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSIT]),
CLKDEV_ICK_ID("dsi0p_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSI0P]),
@@ -341,7 +349,11 @@ static struct clk_lookup lookups[] = {
CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), /* CMT10 */
CLKDEV_DEV_ID("sh_irda.0", &mstp_clks[MSTP325]), /* IrDA */
CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* I2C1 */
+ CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[MSTP318]), /* SY-DMAC */
+ CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */
+ CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */
CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMCIF0 */
+ CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP311]), /* SDHI2 */
CLKDEV_DEV_ID("i2c-sh_mobile.3", &mstp_clks[MSTP411]), /* I2C3 */
CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* I2C4 */
CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */
@@ -351,6 +363,11 @@ void __init sh73a0_clock_init(void)
{
int k, ret = 0;
+ /* Set SDHI clocks to a known state */
+ __raw_writel(0x108, SD0CKCR);
+ __raw_writel(0x108, SD1CKCR);
+ __raw_writel(0x108, SD2CKCR);
+
/* detect main clock parent */
switch ((__raw_readl(CKSCR) >> 24) & 0x03) {
case 0:
diff --git a/arch/arm/mach-shmobile/cpuidle.c b/arch/arm/mach-shmobile/cpuidle.c
new file mode 100644
index 000000000000..2e44f11f592e
--- /dev/null
+++ b/arch/arm/mach-shmobile/cpuidle.c
@@ -0,0 +1,92 @@
+/*
+ * CPUIdle support code for SH-Mobile ARM
+ *
+ * Copyright (C) 2011 Magnus Damm
+ *
+ * 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/pm.h>
+#include <linux/cpuidle.h>
+#include <linux/suspend.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+static void shmobile_enter_wfi(void)
+{
+ cpu_do_idle();
+}
+
+void (*shmobile_cpuidle_modes[CPUIDLE_STATE_MAX])(void) = {
+ shmobile_enter_wfi, /* regular sleep mode */
+};
+
+static int shmobile_cpuidle_enter(struct cpuidle_device *dev,
+ struct cpuidle_state *state)
+{
+ ktime_t before, after;
+ int requested_state = state - &dev->states[0];
+
+ dev->last_state = &dev->states[requested_state];
+ before = ktime_get();
+
+ local_irq_disable();
+ local_fiq_disable();
+
+ shmobile_cpuidle_modes[requested_state]();
+
+ local_irq_enable();
+ local_fiq_enable();
+
+ after = ktime_get();
+ return ktime_to_ns(ktime_sub(after, before)) >> 10;
+}
+
+static struct cpuidle_device shmobile_cpuidle_dev;
+static struct cpuidle_driver shmobile_cpuidle_driver = {
+ .name = "shmobile_cpuidle",
+ .owner = THIS_MODULE,
+};
+
+void (*shmobile_cpuidle_setup)(struct cpuidle_device *dev);
+
+static int shmobile_cpuidle_init(void)
+{
+ struct cpuidle_device *dev = &shmobile_cpuidle_dev;
+ struct cpuidle_state *state;
+ int i;
+
+ cpuidle_register_driver(&shmobile_cpuidle_driver);
+
+ for (i = 0; i < CPUIDLE_STATE_MAX; i++) {
+ dev->states[i].name[0] = '\0';
+ dev->states[i].desc[0] = '\0';
+ dev->states[i].enter = shmobile_cpuidle_enter;
+ }
+
+ i = CPUIDLE_DRIVER_STATE_START;
+
+ state = &dev->states[i++];
+ snprintf(state->name, CPUIDLE_NAME_LEN, "C1");
+ strncpy(state->desc, "WFI", CPUIDLE_DESC_LEN);
+ state->exit_latency = 1;
+ state->target_residency = 1 * 2;
+ state->power_usage = 3;
+ state->flags = 0;
+ state->flags |= CPUIDLE_FLAG_TIME_VALID;
+
+ dev->safe_state = state;
+ dev->state_count = i;
+
+ if (shmobile_cpuidle_setup)
+ shmobile_cpuidle_setup(dev);
+
+ cpuidle_register_device(dev);
+
+ return 0;
+}
+late_initcall(shmobile_cpuidle_init);
diff --git a/arch/arm/mach-shmobile/headsmp.S b/arch/arm/mach-shmobile/headsmp.S
index d4cec6b4c7d9..26079d933d91 100644
--- a/arch/arm/mach-shmobile/headsmp.S
+++ b/arch/arm/mach-shmobile/headsmp.S
@@ -24,4 +24,4 @@
.align 12
ENTRY(shmobile_secondary_vector)
ldr pc, 1f
-1: .long secondary_startup - PAGE_OFFSET + PHYS_OFFSET
+1: .long secondary_startup - PAGE_OFFSET + PLAT_PHYS_OFFSET
diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h
index 013ac0ee8256..06aecb31d9c7 100644
--- a/arch/arm/mach-shmobile/include/mach/common.h
+++ b/arch/arm/mach-shmobile/include/mach/common.h
@@ -8,6 +8,10 @@ struct clk;
extern int clk_init(void);
extern void shmobile_handle_irq_intc(struct pt_regs *);
extern void shmobile_handle_irq_gic(struct pt_regs *);
+extern struct platform_suspend_ops shmobile_suspend_ops;
+struct cpuidle_device;
+extern void (*shmobile_cpuidle_modes[])(void);
+extern void (*shmobile_cpuidle_setup)(struct cpuidle_device *dev);
extern void sh7367_init_irq(void);
extern void sh7367_add_early_devices(void);
@@ -30,6 +34,9 @@ extern void sh7372_add_early_devices(void);
extern void sh7372_add_standard_devices(void);
extern void sh7372_clock_init(void);
extern void sh7372_pinmux_init(void);
+extern void sh7372_pm_init(void);
+extern void sh7372_cpu_suspend(void);
+extern void sh7372_cpu_resume(void);
extern struct clk sh7372_extal1_clk;
extern struct clk sh7372_extal2_clk;
diff --git a/arch/arm/mach-shmobile/include/mach/head-ap4evb.txt b/arch/arm/mach-shmobile/include/mach/head-ap4evb.txt
index 3029aba38688..9f134dfeffdc 100644
--- a/arch/arm/mach-shmobile/include/mach/head-ap4evb.txt
+++ b/arch/arm/mach-shmobile/include/mach/head-ap4evb.txt
@@ -87,8 +87,7 @@ WAIT 1, 0xFE40009C
ED 0xFE400354, 0x01AD8002
LIST "SCIF0 - Serial port for earlyprintk"
-EB 0xE6053098, 0x11
EB 0xE6053098, 0xe1
EW 0xE6C40000, 0x0000
EB 0xE6C40004, 0x19
-EW 0xE6C40008, 0x3000
+EW 0xE6C40008, 0x0030
diff --git a/arch/arm/mach-shmobile/include/mach/head-mackerel.txt b/arch/arm/mach-shmobile/include/mach/head-mackerel.txt
index 3029aba38688..9f134dfeffdc 100644
--- a/arch/arm/mach-shmobile/include/mach/head-mackerel.txt
+++ b/arch/arm/mach-shmobile/include/mach/head-mackerel.txt
@@ -87,8 +87,7 @@ WAIT 1, 0xFE40009C
ED 0xFE400354, 0x01AD8002
LIST "SCIF0 - Serial port for earlyprintk"
-EB 0xE6053098, 0x11
EB 0xE6053098, 0xe1
EW 0xE6C40000, 0x0000
EB 0xE6C40004, 0x19
-EW 0xE6C40008, 0x3000
+EW 0xE6C40008, 0x0030
diff --git a/arch/arm/mach-shmobile/include/mach/sh7372.h b/arch/arm/mach-shmobile/include/mach/sh7372.h
index 5736efcca60c..df20d7670172 100644
--- a/arch/arm/mach-shmobile/include/mach/sh7372.h
+++ b/arch/arm/mach-shmobile/include/mach/sh7372.h
@@ -435,6 +435,7 @@ enum {
/* DMA slave IDs */
enum {
+ SHDMA_SLAVE_INVALID,
SHDMA_SLAVE_SCIF0_TX,
SHDMA_SLAVE_SCIF0_RX,
SHDMA_SLAVE_SCIF1_TX,
diff --git a/arch/arm/mach-shmobile/include/mach/sh73a0.h b/arch/arm/mach-shmobile/include/mach/sh73a0.h
index ceb2cdc92bf9..216c3d695ef1 100644
--- a/arch/arm/mach-shmobile/include/mach/sh73a0.h
+++ b/arch/arm/mach-shmobile/include/mach/sh73a0.h
@@ -463,5 +463,35 @@ enum {
GPIO_FN_FSIAIBT_PU,
GPIO_FN_FSIAISLD_PU,
};
+/* DMA slave IDs */
+enum {
+ SHDMA_SLAVE_INVALID,
+ SHDMA_SLAVE_SCIF0_TX,
+ SHDMA_SLAVE_SCIF0_RX,
+ SHDMA_SLAVE_SCIF1_TX,
+ SHDMA_SLAVE_SCIF1_RX,
+ SHDMA_SLAVE_SCIF2_TX,
+ SHDMA_SLAVE_SCIF2_RX,
+ SHDMA_SLAVE_SCIF3_TX,
+ SHDMA_SLAVE_SCIF3_RX,
+ SHDMA_SLAVE_SCIF4_TX,
+ SHDMA_SLAVE_SCIF4_RX,
+ SHDMA_SLAVE_SCIF5_TX,
+ SHDMA_SLAVE_SCIF5_RX,
+ SHDMA_SLAVE_SCIF6_TX,
+ SHDMA_SLAVE_SCIF6_RX,
+ SHDMA_SLAVE_SCIF7_TX,
+ SHDMA_SLAVE_SCIF7_RX,
+ SHDMA_SLAVE_SCIF8_TX,
+ SHDMA_SLAVE_SCIF8_RX,
+ SHDMA_SLAVE_SDHI0_TX,
+ SHDMA_SLAVE_SDHI0_RX,
+ SHDMA_SLAVE_SDHI1_TX,
+ SHDMA_SLAVE_SDHI1_RX,
+ SHDMA_SLAVE_SDHI2_TX,
+ SHDMA_SLAVE_SDHI2_RX,
+ SHDMA_SLAVE_MMCIF_TX,
+ SHDMA_SLAVE_MMCIF_RX,
+};
#endif /* __ASM_SH73A0_H__ */
diff --git a/arch/arm/mach-shmobile/include/mach/smp.h b/arch/arm/mach-shmobile/include/mach/smp.h
deleted file mode 100644
index 50db94e927ad..000000000000
--- a/arch/arm/mach-shmobile/include/mach/smp.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef __MACH_SMP_H
-#define __MACH_SMP_H
-
-#include <asm/hardware/gic.h>
-
-/*
- * We use IRQ1 as the IPI
- */
-static inline void smp_cross_call(const struct cpumask *mask, int ipi)
-{
-#if defined(CONFIG_ARM_GIC)
- gic_raise_softirq(mask, ipi);
-#endif
-}
-
-#endif
diff --git a/arch/arm/mach-shmobile/intc-sh7372.c b/arch/arm/mach-shmobile/intc-sh7372.c
index 7a4960f9c1e3..3b28743c77eb 100644
--- a/arch/arm/mach-shmobile/intc-sh7372.c
+++ b/arch/arm/mach-shmobile/intc-sh7372.c
@@ -27,8 +27,6 @@
enum {
UNUSED_INTCA = 0,
- ENABLED,
- DISABLED,
/* interrupt sources INTCA */
IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A,
@@ -49,14 +47,14 @@ enum {
MSIOF2, MSIOF1,
SCIFA4, SCIFA5, SCIFB,
FLCTL_FLSTEI, FLCTL_FLTENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I,
- SDHI0,
- SDHI1,
+ SDHI0_SDHI0I0, SDHI0_SDHI0I1, SDHI0_SDHI0I2, SDHI0_SDHI0I3,
+ SDHI1_SDHI1I0, SDHI1_SDHI1I1, SDHI1_SDHI1I2,
IRREM,
IRDA,
TPU0,
TTI20,
DDM,
- SDHI2,
+ SDHI2_SDHI2I0, SDHI2_SDHI2I1, SDHI2_SDHI2I2, SDHI2_SDHI2I3,
RWDT0,
DMAC1_1_DEI0, DMAC1_1_DEI1, DMAC1_1_DEI2, DMAC1_1_DEI3,
DMAC1_2_DEI4, DMAC1_2_DEI5, DMAC1_2_DADERR,
@@ -84,7 +82,7 @@ enum {
/* interrupt groups INTCA */
DMAC1_1, DMAC1_2, DMAC2_1, DMAC2_2, DMAC3_1, DMAC3_2, SHWYSTAT,
- AP_ARM1, AP_ARM2, SPU2, FLCTL, IIC1
+ AP_ARM1, AP_ARM2, SPU2, FLCTL, IIC1, SDHI0, SDHI1, SDHI2
};
static struct intc_vect intca_vectors[] __initdata = {
@@ -125,17 +123,17 @@ static struct intc_vect intca_vectors[] __initdata = {
INTC_VECT(SCIFB, 0x0d60),
INTC_VECT(FLCTL_FLSTEI, 0x0d80), INTC_VECT(FLCTL_FLTENDI, 0x0da0),
INTC_VECT(FLCTL_FLTREQ0I, 0x0dc0), INTC_VECT(FLCTL_FLTREQ1I, 0x0de0),
- INTC_VECT(SDHI0, 0x0e00), INTC_VECT(SDHI0, 0x0e20),
- INTC_VECT(SDHI0, 0x0e40), INTC_VECT(SDHI0, 0x0e60),
- INTC_VECT(SDHI1, 0x0e80), INTC_VECT(SDHI1, 0x0ea0),
- INTC_VECT(SDHI1, 0x0ec0),
+ INTC_VECT(SDHI0_SDHI0I0, 0x0e00), INTC_VECT(SDHI0_SDHI0I1, 0x0e20),
+ INTC_VECT(SDHI0_SDHI0I2, 0x0e40), INTC_VECT(SDHI0_SDHI0I3, 0x0e60),
+ INTC_VECT(SDHI1_SDHI1I0, 0x0e80), INTC_VECT(SDHI1_SDHI1I1, 0x0ea0),
+ INTC_VECT(SDHI1_SDHI1I2, 0x0ec0),
INTC_VECT(IRREM, 0x0f60),
INTC_VECT(IRDA, 0x0480),
INTC_VECT(TPU0, 0x04a0),
INTC_VECT(TTI20, 0x1100),
INTC_VECT(DDM, 0x1140),
- INTC_VECT(SDHI2, 0x1200), INTC_VECT(SDHI2, 0x1220),
- INTC_VECT(SDHI2, 0x1240), INTC_VECT(SDHI2, 0x1260),
+ INTC_VECT(SDHI2_SDHI2I0, 0x1200), INTC_VECT(SDHI2_SDHI2I1, 0x1220),
+ INTC_VECT(SDHI2_SDHI2I2, 0x1240), INTC_VECT(SDHI2_SDHI2I3, 0x1260),
INTC_VECT(RWDT0, 0x1280),
INTC_VECT(DMAC1_1_DEI0, 0x2000), INTC_VECT(DMAC1_1_DEI1, 0x2020),
INTC_VECT(DMAC1_1_DEI2, 0x2040), INTC_VECT(DMAC1_1_DEI3, 0x2060),
@@ -195,6 +193,12 @@ static struct intc_group intca_groups[] __initdata = {
INTC_GROUP(FLCTL, FLCTL_FLSTEI, FLCTL_FLTENDI,
FLCTL_FLTREQ0I, FLCTL_FLTREQ1I),
INTC_GROUP(IIC1, IIC1_ALI1, IIC1_TACKI1, IIC1_WAITI1, IIC1_DTEI1),
+ INTC_GROUP(SDHI0, SDHI0_SDHI0I0, SDHI0_SDHI0I1,
+ SDHI0_SDHI0I2, SDHI0_SDHI0I3),
+ INTC_GROUP(SDHI1, SDHI1_SDHI1I0, SDHI1_SDHI1I1,
+ SDHI1_SDHI1I2),
+ INTC_GROUP(SDHI2, SDHI2_SDHI2I0, SDHI2_SDHI2I1,
+ SDHI2_SDHI2I2, SDHI2_SDHI2I3),
INTC_GROUP(SHWYSTAT, SHWYSTAT_RT, SHWYSTAT_HS, SHWYSTAT_COM),
};
@@ -230,10 +234,10 @@ static struct intc_mask_reg intca_mask_registers[] __initdata = {
{ SCIFB, SCIFA5, SCIFA4, MSIOF1,
0, 0, MSIOF2, 0 } },
{ 0xe694009c, 0xe69400dc, 8, /* IMR7A / IMCR7A */
- { DISABLED, ENABLED, ENABLED, ENABLED,
+ { SDHI0_SDHI0I3, SDHI0_SDHI0I2, SDHI0_SDHI0I1, SDHI0_SDHI0I0,
FLCTL_FLTREQ1I, FLCTL_FLTREQ0I, FLCTL_FLTENDI, FLCTL_FLSTEI } },
{ 0xe69400a0, 0xe69400e0, 8, /* IMR8A / IMCR8A */
- { 0, ENABLED, ENABLED, ENABLED,
+ { 0, SDHI1_SDHI1I2, SDHI1_SDHI1I1, SDHI1_SDHI1I0,
TTI20, USBHSDMAC0_USHDMI, 0, 0 } },
{ 0xe69400a4, 0xe69400e4, 8, /* IMR9A / IMCR9A */
{ CMT1_CMT13, CMT1_CMT12, CMT1_CMT11, CMT1_CMT10,
@@ -248,7 +252,7 @@ static struct intc_mask_reg intca_mask_registers[] __initdata = {
{ 0, 0, TPU0, 0,
0, 0, 0, 0 } },
{ 0xe69400b4, 0xe69400f4, 8, /* IMR13A / IMCR13A */
- { DISABLED, DISABLED, ENABLED, ENABLED,
+ { SDHI2_SDHI2I3, SDHI2_SDHI2I2, SDHI2_SDHI2I1, SDHI2_SDHI2I0,
0, CMT3, 0, RWDT0 } },
{ 0xe6950080, 0xe69500c0, 8, /* IMR0A3 / IMCR0A3 */
{ SHWYSTAT_RT, SHWYSTAT_HS, SHWYSTAT_COM, 0,
@@ -354,14 +358,10 @@ static struct intc_mask_reg intca_ack_registers[] __initdata = {
{ IRQ24A, IRQ25A, IRQ26A, IRQ27A, IRQ28A, IRQ29A, IRQ30A, IRQ31A } },
};
-static struct intc_desc intca_desc __initdata = {
- .name = "sh7372-intca",
- .force_enable = ENABLED,
- .force_disable = DISABLED,
- .hw = INTC_HW_DESC(intca_vectors, intca_groups,
- intca_mask_registers, intca_prio_registers,
- intca_sense_registers, intca_ack_registers),
-};
+static DECLARE_INTC_DESC_ACK(intca_desc, "sh7372-intca",
+ intca_vectors, intca_groups,
+ intca_mask_registers, intca_prio_registers,
+ intca_sense_registers, intca_ack_registers);
enum {
UNUSED_INTCS = 0,
diff --git a/arch/arm/mach-shmobile/platsmp.c b/arch/arm/mach-shmobile/platsmp.c
index 65e879bab4dc..f3888feb1c68 100644
--- a/arch/arm/mach-shmobile/platsmp.c
+++ b/arch/arm/mach-shmobile/platsmp.c
@@ -16,6 +16,7 @@
#include <linux/device.h>
#include <linux/smp.h>
#include <linux/io.h>
+#include <asm/hardware/gic.h>
#include <asm/localtimer.h>
#include <asm/mach-types.h>
#include <mach/common.h>
@@ -57,6 +58,8 @@ void __init smp_init_cpus(void)
for (i = 0; i < ncores; i++)
set_cpu_possible(i, true);
+
+ set_smp_cross_call(gic_raise_softirq);
}
void __init platform_smp_prepare_cpus(unsigned int max_cpus)
diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c
new file mode 100644
index 000000000000..8e4aadf14c9f
--- /dev/null
+++ b/arch/arm/mach-shmobile/pm-sh7372.c
@@ -0,0 +1,108 @@
+/*
+ * sh7372 Power management support
+ *
+ * Copyright (C) 2011 Magnus Damm
+ *
+ * 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/pm.h>
+#include <linux/suspend.h>
+#include <linux/cpuidle.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/tlbflush.h>
+#include <mach/common.h>
+
+#define SMFRAM 0xe6a70000
+#define SYSTBCR 0xe6150024
+#define SBAR 0xe6180020
+#define APARMBAREA 0xe6f10020
+
+static void sh7372_enter_core_standby(void)
+{
+ void __iomem *smfram = (void __iomem *)SMFRAM;
+
+ __raw_writel(0, APARMBAREA); /* translate 4k */
+ __raw_writel(__pa(sh7372_cpu_resume), SBAR); /* set reset vector */
+ __raw_writel(0x10, SYSTBCR); /* enable core standby */
+
+ __raw_writel(0, smfram + 0x3c); /* clear page table address */
+
+ sh7372_cpu_suspend();
+ cpu_init();
+
+ /* if page table address is non-NULL then we have been powered down */
+ if (__raw_readl(smfram + 0x3c)) {
+ __raw_writel(__raw_readl(smfram + 0x40),
+ __va(__raw_readl(smfram + 0x3c)));
+
+ flush_tlb_all();
+ set_cr(__raw_readl(smfram + 0x38));
+ }
+
+ __raw_writel(0, SYSTBCR); /* disable core standby */
+ __raw_writel(0, SBAR); /* disable reset vector translation */
+}
+
+#ifdef CONFIG_CPU_IDLE
+static void sh7372_cpuidle_setup(struct cpuidle_device *dev)
+{
+ struct cpuidle_state *state;
+ int i = dev->state_count;
+
+ state = &dev->states[i];
+ snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
+ strncpy(state->desc, "Core Standby Mode", CPUIDLE_DESC_LEN);
+ state->exit_latency = 10;
+ state->target_residency = 20 + 10;
+ state->power_usage = 1; /* perhaps not */
+ state->flags = 0;
+ state->flags |= CPUIDLE_FLAG_TIME_VALID;
+ shmobile_cpuidle_modes[i] = sh7372_enter_core_standby;
+
+ dev->state_count = i + 1;
+}
+
+static void sh7372_cpuidle_init(void)
+{
+ shmobile_cpuidle_setup = sh7372_cpuidle_setup;
+}
+#else
+static void sh7372_cpuidle_init(void) {}
+#endif
+
+#ifdef CONFIG_SUSPEND
+static int sh7372_enter_suspend(suspend_state_t suspend_state)
+{
+ sh7372_enter_core_standby();
+ return 0;
+}
+
+static void sh7372_suspend_init(void)
+{
+ shmobile_suspend_ops.enter = sh7372_enter_suspend;
+}
+#else
+static void sh7372_suspend_init(void) {}
+#endif
+
+#define DBGREG1 0xe6100020
+#define DBGREG9 0xe6100040
+
+void __init sh7372_pm_init(void)
+{
+ /* enable DBG hardware block to kick SYSC */
+ __raw_writel(0x0000a500, DBGREG9);
+ __raw_writel(0x0000a501, DBGREG9);
+ __raw_writel(0x00000000, DBGREG1);
+
+ sh7372_suspend_init();
+ sh7372_cpuidle_init();
+}
diff --git a/arch/arm/mach-shmobile/pm_runtime.c b/arch/arm/mach-shmobile/pm_runtime.c
index 94912d3944d3..2d1b67a59e4a 100644
--- a/arch/arm/mach-shmobile/pm_runtime.c
+++ b/arch/arm/mach-shmobile/pm_runtime.c
@@ -18,152 +18,41 @@
#include <linux/clk.h>
#include <linux/sh_clk.h>
#include <linux/bitmap.h>
+#include <linux/slab.h>
#ifdef CONFIG_PM_RUNTIME
-#define BIT_ONCE 0
-#define BIT_ACTIVE 1
-#define BIT_CLK_ENABLED 2
-struct pm_runtime_data {
- unsigned long flags;
- struct clk *clk;
-};
-
-static void __devres_release(struct device *dev, void *res)
-{
- struct pm_runtime_data *prd = res;
-
- dev_dbg(dev, "__devres_release()\n");
-
- if (test_bit(BIT_CLK_ENABLED, &prd->flags))
- clk_disable(prd->clk);
-
- if (test_bit(BIT_ACTIVE, &prd->flags))
- clk_put(prd->clk);
-}
-
-static struct pm_runtime_data *__to_prd(struct device *dev)
-{
- return devres_find(dev, __devres_release, NULL, NULL);
-}
-
-static void platform_pm_runtime_init(struct device *dev,
- struct pm_runtime_data *prd)
-{
- if (prd && !test_and_set_bit(BIT_ONCE, &prd->flags)) {
- prd->clk = clk_get(dev, NULL);
- if (!IS_ERR(prd->clk)) {
- set_bit(BIT_ACTIVE, &prd->flags);
- dev_info(dev, "clocks managed by runtime pm\n");
- }
- }
-}
-
-static void platform_pm_runtime_bug(struct device *dev,
- struct pm_runtime_data *prd)
-{
- if (prd && !test_and_set_bit(BIT_ONCE, &prd->flags))
- dev_err(dev, "runtime pm suspend before resume\n");
-}
-
-int platform_pm_runtime_suspend(struct device *dev)
-{
- struct pm_runtime_data *prd = __to_prd(dev);
-
- dev_dbg(dev, "platform_pm_runtime_suspend()\n");
-
- platform_pm_runtime_bug(dev, prd);
-
- if (prd && test_bit(BIT_ACTIVE, &prd->flags)) {
- clk_disable(prd->clk);
- clear_bit(BIT_CLK_ENABLED, &prd->flags);
- }
-
- return 0;
-}
-
-int platform_pm_runtime_resume(struct device *dev)
-{
- struct pm_runtime_data *prd = __to_prd(dev);
-
- dev_dbg(dev, "platform_pm_runtime_resume()\n");
-
- platform_pm_runtime_init(dev, prd);
-
- if (prd && test_bit(BIT_ACTIVE, &prd->flags)) {
- clk_enable(prd->clk);
- set_bit(BIT_CLK_ENABLED, &prd->flags);
- }
-
- return 0;
-}
-
-int platform_pm_runtime_idle(struct device *dev)
+static int default_platform_runtime_idle(struct device *dev)
{
/* suspend synchronously to disable clocks immediately */
return pm_runtime_suspend(dev);
}
-static int platform_bus_notify(struct notifier_block *nb,
- unsigned long action, void *data)
-{
- struct device *dev = data;
- struct pm_runtime_data *prd;
-
- dev_dbg(dev, "platform_bus_notify() %ld !\n", action);
-
- if (action == BUS_NOTIFY_BIND_DRIVER) {
- prd = devres_alloc(__devres_release, sizeof(*prd), GFP_KERNEL);
- if (prd)
- devres_add(dev, prd);
- else
- dev_err(dev, "unable to alloc memory for runtime pm\n");
- }
-
- return 0;
-}
-
-#else /* CONFIG_PM_RUNTIME */
-
-static int platform_bus_notify(struct notifier_block *nb,
- unsigned long action, void *data)
-{
- struct device *dev = data;
- struct clk *clk;
+static struct dev_power_domain default_power_domain = {
+ .ops = {
+ .runtime_suspend = pm_runtime_clk_suspend,
+ .runtime_resume = pm_runtime_clk_resume,
+ .runtime_idle = default_platform_runtime_idle,
+ USE_PLATFORM_PM_SLEEP_OPS
+ },
+};
- dev_dbg(dev, "platform_bus_notify() %ld !\n", action);
+#define DEFAULT_PWR_DOMAIN_PTR (&default_power_domain)
- switch (action) {
- case BUS_NOTIFY_BIND_DRIVER:
- clk = clk_get(dev, NULL);
- if (!IS_ERR(clk)) {
- clk_enable(clk);
- clk_put(clk);
- dev_info(dev, "runtime pm disabled, clock forced on\n");
- }
- break;
- case BUS_NOTIFY_UNBOUND_DRIVER:
- clk = clk_get(dev, NULL);
- if (!IS_ERR(clk)) {
- clk_disable(clk);
- clk_put(clk);
- dev_info(dev, "runtime pm disabled, clock forced off\n");
- }
- break;
- }
+#else
- return 0;
-}
+#define DEFAULT_PWR_DOMAIN_PTR NULL
#endif /* CONFIG_PM_RUNTIME */
-static struct notifier_block platform_bus_notifier = {
- .notifier_call = platform_bus_notify
+static struct pm_clk_notifier_block platform_bus_notifier = {
+ .pwr_domain = DEFAULT_PWR_DOMAIN_PTR,
+ .con_ids = { NULL, },
};
static int __init sh_pm_runtime_init(void)
{
- bus_register_notifier(&platform_bus_type, &platform_bus_notifier);
+ pm_runtime_clk_add_notifier(&platform_bus_type, &platform_bus_notifier);
return 0;
}
core_initcall(sh_pm_runtime_init);
diff --git a/arch/arm/mach-shmobile/setup-sh7367.c b/arch/arm/mach-shmobile/setup-sh7367.c
index ce28141662da..2c10190dbb55 100644
--- a/arch/arm/mach-shmobile/setup-sh7367.c
+++ b/arch/arm/mach-shmobile/setup-sh7367.c
@@ -22,6 +22,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
+#include <linux/uio_driver.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/io.h>
@@ -195,6 +196,214 @@ static struct platform_device cmt10_device = {
.num_resources = ARRAY_SIZE(cmt10_resources),
};
+/* VPU */
+static struct uio_info vpu_platform_data = {
+ .name = "VPU5",
+ .version = "0",
+ .irq = intcs_evt2irq(0x980),
+};
+
+static struct resource vpu_resources[] = {
+ [0] = {
+ .name = "VPU",
+ .start = 0xfe900000,
+ .end = 0xfe902807,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device vpu_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 0,
+ .dev = {
+ .platform_data = &vpu_platform_data,
+ },
+ .resource = vpu_resources,
+ .num_resources = ARRAY_SIZE(vpu_resources),
+};
+
+/* VEU0 */
+static struct uio_info veu0_platform_data = {
+ .name = "VEU0",
+ .version = "0",
+ .irq = intcs_evt2irq(0x700),
+};
+
+static struct resource veu0_resources[] = {
+ [0] = {
+ .name = "VEU0",
+ .start = 0xfe920000,
+ .end = 0xfe9200b7,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device veu0_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 1,
+ .dev = {
+ .platform_data = &veu0_platform_data,
+ },
+ .resource = veu0_resources,
+ .num_resources = ARRAY_SIZE(veu0_resources),
+};
+
+/* VEU1 */
+static struct uio_info veu1_platform_data = {
+ .name = "VEU1",
+ .version = "0",
+ .irq = intcs_evt2irq(0x720),
+};
+
+static struct resource veu1_resources[] = {
+ [0] = {
+ .name = "VEU1",
+ .start = 0xfe924000,
+ .end = 0xfe9240b7,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device veu1_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 2,
+ .dev = {
+ .platform_data = &veu1_platform_data,
+ },
+ .resource = veu1_resources,
+ .num_resources = ARRAY_SIZE(veu1_resources),
+};
+
+/* VEU2 */
+static struct uio_info veu2_platform_data = {
+ .name = "VEU2",
+ .version = "0",
+ .irq = intcs_evt2irq(0x740),
+};
+
+static struct resource veu2_resources[] = {
+ [0] = {
+ .name = "VEU2",
+ .start = 0xfe928000,
+ .end = 0xfe9280b7,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device veu2_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 3,
+ .dev = {
+ .platform_data = &veu2_platform_data,
+ },
+ .resource = veu2_resources,
+ .num_resources = ARRAY_SIZE(veu2_resources),
+};
+
+/* VEU3 */
+static struct uio_info veu3_platform_data = {
+ .name = "VEU3",
+ .version = "0",
+ .irq = intcs_evt2irq(0x760),
+};
+
+static struct resource veu3_resources[] = {
+ [0] = {
+ .name = "VEU3",
+ .start = 0xfe92c000,
+ .end = 0xfe92c0b7,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device veu3_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 4,
+ .dev = {
+ .platform_data = &veu3_platform_data,
+ },
+ .resource = veu3_resources,
+ .num_resources = ARRAY_SIZE(veu3_resources),
+};
+
+/* VEU2H */
+static struct uio_info veu2h_platform_data = {
+ .name = "VEU2H",
+ .version = "0",
+ .irq = intcs_evt2irq(0x520),
+};
+
+static struct resource veu2h_resources[] = {
+ [0] = {
+ .name = "VEU2H",
+ .start = 0xfe93c000,
+ .end = 0xfe93c27b,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device veu2h_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 5,
+ .dev = {
+ .platform_data = &veu2h_platform_data,
+ },
+ .resource = veu2h_resources,
+ .num_resources = ARRAY_SIZE(veu2h_resources),
+};
+
+/* JPU */
+static struct uio_info jpu_platform_data = {
+ .name = "JPU",
+ .version = "0",
+ .irq = intcs_evt2irq(0x560),
+};
+
+static struct resource jpu_resources[] = {
+ [0] = {
+ .name = "JPU",
+ .start = 0xfe980000,
+ .end = 0xfe9902d3,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device jpu_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 6,
+ .dev = {
+ .platform_data = &jpu_platform_data,
+ },
+ .resource = jpu_resources,
+ .num_resources = ARRAY_SIZE(jpu_resources),
+};
+
+/* SPU1 */
+static struct uio_info spu1_platform_data = {
+ .name = "SPU1",
+ .version = "0",
+ .irq = evt2irq(0xfc0),
+};
+
+static struct resource spu1_resources[] = {
+ [0] = {
+ .name = "SPU1",
+ .start = 0xfe300000,
+ .end = 0xfe3fffff,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device spu1_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 7,
+ .dev = {
+ .platform_data = &spu1_platform_data,
+ },
+ .resource = spu1_resources,
+ .num_resources = ARRAY_SIZE(spu1_resources),
+};
+
static struct platform_device *sh7367_early_devices[] __initdata = {
&scif0_device,
&scif1_device,
@@ -206,10 +415,24 @@ static struct platform_device *sh7367_early_devices[] __initdata = {
&cmt10_device,
};
+static struct platform_device *sh7367_devices[] __initdata = {
+ &vpu_device,
+ &veu0_device,
+ &veu1_device,
+ &veu2_device,
+ &veu3_device,
+ &veu2h_device,
+ &jpu_device,
+ &spu1_device,
+};
+
void __init sh7367_add_standard_devices(void)
{
platform_add_devices(sh7367_early_devices,
ARRAY_SIZE(sh7367_early_devices));
+
+ platform_add_devices(sh7367_devices,
+ ARRAY_SIZE(sh7367_devices));
}
#define SYMSTPCR2 0xe6158048
diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c
index ff0494f3d00c..cd807eea69e2 100644
--- a/arch/arm/mach-shmobile/setup-sh7372.c
+++ b/arch/arm/mach-shmobile/setup-sh7372.c
@@ -22,6 +22,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
+#include <linux/uio_driver.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/io.h>
@@ -601,6 +602,214 @@ static struct platform_device dma2_device = {
},
};
+/* VPU */
+static struct uio_info vpu_platform_data = {
+ .name = "VPU5HG",
+ .version = "0",
+ .irq = intcs_evt2irq(0x980),
+};
+
+static struct resource vpu_resources[] = {
+ [0] = {
+ .name = "VPU",
+ .start = 0xfe900000,
+ .end = 0xfe900157,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device vpu_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 0,
+ .dev = {
+ .platform_data = &vpu_platform_data,
+ },
+ .resource = vpu_resources,
+ .num_resources = ARRAY_SIZE(vpu_resources),
+};
+
+/* VEU0 */
+static struct uio_info veu0_platform_data = {
+ .name = "VEU0",
+ .version = "0",
+ .irq = intcs_evt2irq(0x700),
+};
+
+static struct resource veu0_resources[] = {
+ [0] = {
+ .name = "VEU0",
+ .start = 0xfe920000,
+ .end = 0xfe9200cb,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device veu0_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 1,
+ .dev = {
+ .platform_data = &veu0_platform_data,
+ },
+ .resource = veu0_resources,
+ .num_resources = ARRAY_SIZE(veu0_resources),
+};
+
+/* VEU1 */
+static struct uio_info veu1_platform_data = {
+ .name = "VEU1",
+ .version = "0",
+ .irq = intcs_evt2irq(0x720),
+};
+
+static struct resource veu1_resources[] = {
+ [0] = {
+ .name = "VEU1",
+ .start = 0xfe924000,
+ .end = 0xfe9240cb,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device veu1_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 2,
+ .dev = {
+ .platform_data = &veu1_platform_data,
+ },
+ .resource = veu1_resources,
+ .num_resources = ARRAY_SIZE(veu1_resources),
+};
+
+/* VEU2 */
+static struct uio_info veu2_platform_data = {
+ .name = "VEU2",
+ .version = "0",
+ .irq = intcs_evt2irq(0x740),
+};
+
+static struct resource veu2_resources[] = {
+ [0] = {
+ .name = "VEU2",
+ .start = 0xfe928000,
+ .end = 0xfe928307,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device veu2_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 3,
+ .dev = {
+ .platform_data = &veu2_platform_data,
+ },
+ .resource = veu2_resources,
+ .num_resources = ARRAY_SIZE(veu2_resources),
+};
+
+/* VEU3 */
+static struct uio_info veu3_platform_data = {
+ .name = "VEU3",
+ .version = "0",
+ .irq = intcs_evt2irq(0x760),
+};
+
+static struct resource veu3_resources[] = {
+ [0] = {
+ .name = "VEU3",
+ .start = 0xfe92c000,
+ .end = 0xfe92c307,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device veu3_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 4,
+ .dev = {
+ .platform_data = &veu3_platform_data,
+ },
+ .resource = veu3_resources,
+ .num_resources = ARRAY_SIZE(veu3_resources),
+};
+
+/* JPU */
+static struct uio_info jpu_platform_data = {
+ .name = "JPU",
+ .version = "0",
+ .irq = intcs_evt2irq(0x560),
+};
+
+static struct resource jpu_resources[] = {
+ [0] = {
+ .name = "JPU",
+ .start = 0xfe980000,
+ .end = 0xfe9902d3,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device jpu_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 5,
+ .dev = {
+ .platform_data = &jpu_platform_data,
+ },
+ .resource = jpu_resources,
+ .num_resources = ARRAY_SIZE(jpu_resources),
+};
+
+/* SPU2DSP0 */
+static struct uio_info spu0_platform_data = {
+ .name = "SPU2DSP0",
+ .version = "0",
+ .irq = evt2irq(0x1800),
+};
+
+static struct resource spu0_resources[] = {
+ [0] = {
+ .name = "SPU2DSP0",
+ .start = 0xfe200000,
+ .end = 0xfe2fffff,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device spu0_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 6,
+ .dev = {
+ .platform_data = &spu0_platform_data,
+ },
+ .resource = spu0_resources,
+ .num_resources = ARRAY_SIZE(spu0_resources),
+};
+
+/* SPU2DSP1 */
+static struct uio_info spu1_platform_data = {
+ .name = "SPU2DSP1",
+ .version = "0",
+ .irq = evt2irq(0x1820),
+};
+
+static struct resource spu1_resources[] = {
+ [0] = {
+ .name = "SPU2DSP1",
+ .start = 0xfe300000,
+ .end = 0xfe3fffff,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device spu1_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 7,
+ .dev = {
+ .platform_data = &spu1_platform_data,
+ },
+ .resource = spu1_resources,
+ .num_resources = ARRAY_SIZE(spu1_resources),
+};
+
static struct platform_device *sh7372_early_devices[] __initdata = {
&scif0_device,
&scif1_device,
@@ -620,6 +829,14 @@ static struct platform_device *sh7372_late_devices[] __initdata = {
&dma0_device,
&dma1_device,
&dma2_device,
+ &vpu_device,
+ &veu0_device,
+ &veu1_device,
+ &veu2_device,
+ &veu3_device,
+ &jpu_device,
+ &spu0_device,
+ &spu1_device,
};
void __init sh7372_add_standard_devices(void)
diff --git a/arch/arm/mach-shmobile/setup-sh7377.c b/arch/arm/mach-shmobile/setup-sh7377.c
index 8099b0b8a934..bb405b8e459b 100644
--- a/arch/arm/mach-shmobile/setup-sh7377.c
+++ b/arch/arm/mach-shmobile/setup-sh7377.c
@@ -22,6 +22,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
+#include <linux/uio_driver.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/io.h>
@@ -38,7 +39,7 @@ static struct plat_sci_port scif0_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE,
.scbrr_algo_id = SCBRR_ALGO_4,
- .type = PORT_SCIF,
+ .type = PORT_SCIFA,
.irqs = { evt2irq(0xc00), evt2irq(0xc00),
evt2irq(0xc00), evt2irq(0xc00) },
};
@@ -57,7 +58,7 @@ static struct plat_sci_port scif1_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE,
.scbrr_algo_id = SCBRR_ALGO_4,
- .type = PORT_SCIF,
+ .type = PORT_SCIFA,
.irqs = { evt2irq(0xc20), evt2irq(0xc20),
evt2irq(0xc20), evt2irq(0xc20) },
};
@@ -76,7 +77,7 @@ static struct plat_sci_port scif2_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE,
.scbrr_algo_id = SCBRR_ALGO_4,
- .type = PORT_SCIF,
+ .type = PORT_SCIFA,
.irqs = { evt2irq(0xc40), evt2irq(0xc40),
evt2irq(0xc40), evt2irq(0xc40) },
};
@@ -95,7 +96,7 @@ static struct plat_sci_port scif3_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE,
.scbrr_algo_id = SCBRR_ALGO_4,
- .type = PORT_SCIF,
+ .type = PORT_SCIFA,
.irqs = { evt2irq(0xc60), evt2irq(0xc60),
evt2irq(0xc60), evt2irq(0xc60) },
};
@@ -114,7 +115,7 @@ static struct plat_sci_port scif4_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE,
.scbrr_algo_id = SCBRR_ALGO_4,
- .type = PORT_SCIF,
+ .type = PORT_SCIFA,
.irqs = { evt2irq(0xd20), evt2irq(0xd20),
evt2irq(0xd20), evt2irq(0xd20) },
};
@@ -133,7 +134,7 @@ static struct plat_sci_port scif5_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE,
.scbrr_algo_id = SCBRR_ALGO_4,
- .type = PORT_SCIF,
+ .type = PORT_SCIFA,
.irqs = { evt2irq(0xd40), evt2irq(0xd40),
evt2irq(0xd40), evt2irq(0xd40) },
};
@@ -152,7 +153,7 @@ static struct plat_sci_port scif6_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE,
.scbrr_algo_id = SCBRR_ALGO_4,
- .type = PORT_SCIF,
+ .type = PORT_SCIFA,
.irqs = { intcs_evt2irq(0x1a80), intcs_evt2irq(0x1a80),
intcs_evt2irq(0x1a80), intcs_evt2irq(0x1a80) },
};
@@ -171,7 +172,7 @@ static struct plat_sci_port scif7_platform_data = {
.flags = UPF_BOOT_AUTOCONF,
.scscr = SCSCR_RE | SCSCR_TE,
.scbrr_algo_id = SCBRR_ALGO_4,
- .type = PORT_SCIF,
+ .type = PORT_SCIFB,
.irqs = { evt2irq(0xd60), evt2irq(0xd60),
evt2irq(0xd60), evt2irq(0xd60) },
};
@@ -215,6 +216,214 @@ static struct platform_device cmt10_device = {
.num_resources = ARRAY_SIZE(cmt10_resources),
};
+/* VPU */
+static struct uio_info vpu_platform_data = {
+ .name = "VPU5HG",
+ .version = "0",
+ .irq = intcs_evt2irq(0x980),
+};
+
+static struct resource vpu_resources[] = {
+ [0] = {
+ .name = "VPU",
+ .start = 0xfe900000,
+ .end = 0xfe900157,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device vpu_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 0,
+ .dev = {
+ .platform_data = &vpu_platform_data,
+ },
+ .resource = vpu_resources,
+ .num_resources = ARRAY_SIZE(vpu_resources),
+};
+
+/* VEU0 */
+static struct uio_info veu0_platform_data = {
+ .name = "VEU0",
+ .version = "0",
+ .irq = intcs_evt2irq(0x700),
+};
+
+static struct resource veu0_resources[] = {
+ [0] = {
+ .name = "VEU0",
+ .start = 0xfe920000,
+ .end = 0xfe9200cb,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device veu0_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 1,
+ .dev = {
+ .platform_data = &veu0_platform_data,
+ },
+ .resource = veu0_resources,
+ .num_resources = ARRAY_SIZE(veu0_resources),
+};
+
+/* VEU1 */
+static struct uio_info veu1_platform_data = {
+ .name = "VEU1",
+ .version = "0",
+ .irq = intcs_evt2irq(0x720),
+};
+
+static struct resource veu1_resources[] = {
+ [0] = {
+ .name = "VEU1",
+ .start = 0xfe924000,
+ .end = 0xfe9240cb,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device veu1_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 2,
+ .dev = {
+ .platform_data = &veu1_platform_data,
+ },
+ .resource = veu1_resources,
+ .num_resources = ARRAY_SIZE(veu1_resources),
+};
+
+/* VEU2 */
+static struct uio_info veu2_platform_data = {
+ .name = "VEU2",
+ .version = "0",
+ .irq = intcs_evt2irq(0x740),
+};
+
+static struct resource veu2_resources[] = {
+ [0] = {
+ .name = "VEU2",
+ .start = 0xfe928000,
+ .end = 0xfe928307,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device veu2_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 3,
+ .dev = {
+ .platform_data = &veu2_platform_data,
+ },
+ .resource = veu2_resources,
+ .num_resources = ARRAY_SIZE(veu2_resources),
+};
+
+/* VEU3 */
+static struct uio_info veu3_platform_data = {
+ .name = "VEU3",
+ .version = "0",
+ .irq = intcs_evt2irq(0x760),
+};
+
+static struct resource veu3_resources[] = {
+ [0] = {
+ .name = "VEU3",
+ .start = 0xfe92c000,
+ .end = 0xfe92c307,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device veu3_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 4,
+ .dev = {
+ .platform_data = &veu3_platform_data,
+ },
+ .resource = veu3_resources,
+ .num_resources = ARRAY_SIZE(veu3_resources),
+};
+
+/* JPU */
+static struct uio_info jpu_platform_data = {
+ .name = "JPU",
+ .version = "0",
+ .irq = intcs_evt2irq(0x560),
+};
+
+static struct resource jpu_resources[] = {
+ [0] = {
+ .name = "JPU",
+ .start = 0xfe980000,
+ .end = 0xfe9902d3,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device jpu_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 5,
+ .dev = {
+ .platform_data = &jpu_platform_data,
+ },
+ .resource = jpu_resources,
+ .num_resources = ARRAY_SIZE(jpu_resources),
+};
+
+/* SPU2DSP0 */
+static struct uio_info spu0_platform_data = {
+ .name = "SPU2DSP0",
+ .version = "0",
+ .irq = evt2irq(0x1800),
+};
+
+static struct resource spu0_resources[] = {
+ [0] = {
+ .name = "SPU2DSP0",
+ .start = 0xfe200000,
+ .end = 0xfe2fffff,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device spu0_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 6,
+ .dev = {
+ .platform_data = &spu0_platform_data,
+ },
+ .resource = spu0_resources,
+ .num_resources = ARRAY_SIZE(spu0_resources),
+};
+
+/* SPU2DSP1 */
+static struct uio_info spu1_platform_data = {
+ .name = "SPU2DSP1",
+ .version = "0",
+ .irq = evt2irq(0x1820),
+};
+
+static struct resource spu1_resources[] = {
+ [0] = {
+ .name = "SPU2DSP1",
+ .start = 0xfe300000,
+ .end = 0xfe3fffff,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device spu1_device = {
+ .name = "uio_pdrv_genirq",
+ .id = 7,
+ .dev = {
+ .platform_data = &spu1_platform_data,
+ },
+ .resource = spu1_resources,
+ .num_resources = ARRAY_SIZE(spu1_resources),
+};
+
static struct platform_device *sh7377_early_devices[] __initdata = {
&scif0_device,
&scif1_device,
@@ -227,10 +436,24 @@ static struct platform_device *sh7377_early_devices[] __initdata = {
&cmt10_device,
};
+static struct platform_device *sh7377_devices[] __initdata = {
+ &vpu_device,
+ &veu0_device,
+ &veu1_device,
+ &veu2_device,
+ &veu3_device,
+ &jpu_device,
+ &spu0_device,
+ &spu1_device,
+};
+
void __init sh7377_add_standard_devices(void)
{
platform_add_devices(sh7377_early_devices,
ARRAY_SIZE(sh7377_early_devices));
+
+ platform_add_devices(sh7377_devices,
+ ARRAY_SIZE(sh7377_devices));
}
#define SMSTPCR3 0xe615013c
diff --git a/arch/arm/mach-shmobile/setup-sh73a0.c b/arch/arm/mach-shmobile/setup-sh73a0.c
index 685c40a2f5e6..e46821c0a62e 100644
--- a/arch/arm/mach-shmobile/setup-sh73a0.c
+++ b/arch/arm/mach-shmobile/setup-sh73a0.c
@@ -27,9 +27,11 @@
#include <linux/input.h>
#include <linux/io.h>
#include <linux/serial_sci.h>
+#include <linux/sh_dma.h>
#include <linux/sh_intc.h>
#include <linux/sh_timer.h>
#include <mach/hardware.h>
+#include <mach/sh73a0.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -392,6 +394,242 @@ static struct platform_device i2c4_device = {
.num_resources = ARRAY_SIZE(i2c4_resources),
};
+/* Transmit sizes and respective CHCR register values */
+enum {
+ XMIT_SZ_8BIT = 0,
+ XMIT_SZ_16BIT = 1,
+ XMIT_SZ_32BIT = 2,
+ XMIT_SZ_64BIT = 7,
+ XMIT_SZ_128BIT = 3,
+ XMIT_SZ_256BIT = 4,
+ XMIT_SZ_512BIT = 5,
+};
+
+/* log2(size / 8) - used to calculate number of transfers */
+#define TS_SHIFT { \
+ [XMIT_SZ_8BIT] = 0, \
+ [XMIT_SZ_16BIT] = 1, \
+ [XMIT_SZ_32BIT] = 2, \
+ [XMIT_SZ_64BIT] = 3, \
+ [XMIT_SZ_128BIT] = 4, \
+ [XMIT_SZ_256BIT] = 5, \
+ [XMIT_SZ_512BIT] = 6, \
+}
+
+#define TS_INDEX2VAL(i) ((((i) & 3) << 3) | (((i) & 0xc) << (20 - 2)))
+#define CHCR_TX(xmit_sz) (DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL((xmit_sz)))
+#define CHCR_RX(xmit_sz) (DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL((xmit_sz)))
+
+static const struct sh_dmae_slave_config sh73a0_dmae_slaves[] = {
+ {
+ .slave_id = SHDMA_SLAVE_SCIF0_TX,
+ .addr = 0xe6c40020,
+ .chcr = CHCR_TX(XMIT_SZ_8BIT),
+ .mid_rid = 0x21,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF0_RX,
+ .addr = 0xe6c40024,
+ .chcr = CHCR_RX(XMIT_SZ_8BIT),
+ .mid_rid = 0x22,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF1_TX,
+ .addr = 0xe6c50020,
+ .chcr = CHCR_TX(XMIT_SZ_8BIT),
+ .mid_rid = 0x25,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF1_RX,
+ .addr = 0xe6c50024,
+ .chcr = CHCR_RX(XMIT_SZ_8BIT),
+ .mid_rid = 0x26,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF2_TX,
+ .addr = 0xe6c60020,
+ .chcr = CHCR_TX(XMIT_SZ_8BIT),
+ .mid_rid = 0x29,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF2_RX,
+ .addr = 0xe6c60024,
+ .chcr = CHCR_RX(XMIT_SZ_8BIT),
+ .mid_rid = 0x2a,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF3_TX,
+ .addr = 0xe6c70020,
+ .chcr = CHCR_TX(XMIT_SZ_8BIT),
+ .mid_rid = 0x2d,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF3_RX,
+ .addr = 0xe6c70024,
+ .chcr = CHCR_RX(XMIT_SZ_8BIT),
+ .mid_rid = 0x2e,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF4_TX,
+ .addr = 0xe6c80020,
+ .chcr = CHCR_TX(XMIT_SZ_8BIT),
+ .mid_rid = 0x39,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF4_RX,
+ .addr = 0xe6c80024,
+ .chcr = CHCR_RX(XMIT_SZ_8BIT),
+ .mid_rid = 0x3a,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF5_TX,
+ .addr = 0xe6cb0020,
+ .chcr = CHCR_TX(XMIT_SZ_8BIT),
+ .mid_rid = 0x35,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF5_RX,
+ .addr = 0xe6cb0024,
+ .chcr = CHCR_RX(XMIT_SZ_8BIT),
+ .mid_rid = 0x36,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF6_TX,
+ .addr = 0xe6cc0020,
+ .chcr = CHCR_TX(XMIT_SZ_8BIT),
+ .mid_rid = 0x1d,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF6_RX,
+ .addr = 0xe6cc0024,
+ .chcr = CHCR_RX(XMIT_SZ_8BIT),
+ .mid_rid = 0x1e,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF7_TX,
+ .addr = 0xe6cd0020,
+ .chcr = CHCR_TX(XMIT_SZ_8BIT),
+ .mid_rid = 0x19,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF7_RX,
+ .addr = 0xe6cd0024,
+ .chcr = CHCR_RX(XMIT_SZ_8BIT),
+ .mid_rid = 0x1a,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF8_TX,
+ .addr = 0xe6c30040,
+ .chcr = CHCR_TX(XMIT_SZ_8BIT),
+ .mid_rid = 0x3d,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF8_RX,
+ .addr = 0xe6c30060,
+ .chcr = CHCR_RX(XMIT_SZ_8BIT),
+ .mid_rid = 0x3e,
+ }, {
+ .slave_id = SHDMA_SLAVE_SDHI0_TX,
+ .addr = 0xee100030,
+ .chcr = CHCR_TX(XMIT_SZ_16BIT),
+ .mid_rid = 0xc1,
+ }, {
+ .slave_id = SHDMA_SLAVE_SDHI0_RX,
+ .addr = 0xee100030,
+ .chcr = CHCR_RX(XMIT_SZ_16BIT),
+ .mid_rid = 0xc2,
+ }, {
+ .slave_id = SHDMA_SLAVE_SDHI1_TX,
+ .addr = 0xee120030,
+ .chcr = CHCR_TX(XMIT_SZ_16BIT),
+ .mid_rid = 0xc9,
+ }, {
+ .slave_id = SHDMA_SLAVE_SDHI1_RX,
+ .addr = 0xee120030,
+ .chcr = CHCR_RX(XMIT_SZ_16BIT),
+ .mid_rid = 0xca,
+ }, {
+ .slave_id = SHDMA_SLAVE_SDHI2_TX,
+ .addr = 0xee140030,
+ .chcr = CHCR_TX(XMIT_SZ_16BIT),
+ .mid_rid = 0xcd,
+ }, {
+ .slave_id = SHDMA_SLAVE_SDHI2_RX,
+ .addr = 0xee140030,
+ .chcr = CHCR_RX(XMIT_SZ_16BIT),
+ .mid_rid = 0xce,
+ }, {
+ .slave_id = SHDMA_SLAVE_MMCIF_TX,
+ .addr = 0xe6bd0034,
+ .chcr = CHCR_TX(XMIT_SZ_32BIT),
+ .mid_rid = 0xd1,
+ }, {
+ .slave_id = SHDMA_SLAVE_MMCIF_RX,
+ .addr = 0xe6bd0034,
+ .chcr = CHCR_RX(XMIT_SZ_32BIT),
+ .mid_rid = 0xd2,
+ },
+};
+
+#define DMAE_CHANNEL(_offset) \
+ { \
+ .offset = _offset - 0x20, \
+ .dmars = _offset - 0x20 + 0x40, \
+ }
+
+static const struct sh_dmae_channel sh73a0_dmae_channels[] = {
+ DMAE_CHANNEL(0x8000),
+ DMAE_CHANNEL(0x8080),
+ DMAE_CHANNEL(0x8100),
+ DMAE_CHANNEL(0x8180),
+ DMAE_CHANNEL(0x8200),
+ DMAE_CHANNEL(0x8280),
+ DMAE_CHANNEL(0x8300),
+ DMAE_CHANNEL(0x8380),
+ DMAE_CHANNEL(0x8400),
+ DMAE_CHANNEL(0x8480),
+ DMAE_CHANNEL(0x8500),
+ DMAE_CHANNEL(0x8580),
+ DMAE_CHANNEL(0x8600),
+ DMAE_CHANNEL(0x8680),
+ DMAE_CHANNEL(0x8700),
+ DMAE_CHANNEL(0x8780),
+ DMAE_CHANNEL(0x8800),
+ DMAE_CHANNEL(0x8880),
+ DMAE_CHANNEL(0x8900),
+ DMAE_CHANNEL(0x8980),
+};
+
+static const unsigned int ts_shift[] = TS_SHIFT;
+
+static struct sh_dmae_pdata sh73a0_dmae_platform_data = {
+ .slave = sh73a0_dmae_slaves,
+ .slave_num = ARRAY_SIZE(sh73a0_dmae_slaves),
+ .channel = sh73a0_dmae_channels,
+ .channel_num = ARRAY_SIZE(sh73a0_dmae_channels),
+ .ts_low_shift = 3,
+ .ts_low_mask = 0x18,
+ .ts_high_shift = (20 - 2), /* 2 bits for shifted low TS */
+ .ts_high_mask = 0x00300000,
+ .ts_shift = ts_shift,
+ .ts_shift_num = ARRAY_SIZE(ts_shift),
+ .dmaor_init = DMAOR_DME,
+};
+
+static struct resource sh73a0_dmae_resources[] = {
+ {
+ /* Registers including DMAOR and channels including DMARSx */
+ .start = 0xfe000020,
+ .end = 0xfe008a00 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ /* DMA error IRQ */
+ .start = gic_spi(129),
+ .end = gic_spi(129),
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ /* IRQ for channels 0-19 */
+ .start = gic_spi(109),
+ .end = gic_spi(128),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device dma0_device = {
+ .name = "sh-dma-engine",
+ .id = 0,
+ .resource = sh73a0_dmae_resources,
+ .num_resources = ARRAY_SIZE(sh73a0_dmae_resources),
+ .dev = {
+ .platform_data = &sh73a0_dmae_platform_data,
+ },
+};
+
static struct platform_device *sh73a0_early_devices[] __initdata = {
&scif0_device,
&scif1_device,
@@ -413,10 +651,16 @@ static struct platform_device *sh73a0_late_devices[] __initdata = {
&i2c2_device,
&i2c3_device,
&i2c4_device,
+ &dma0_device,
};
+#define SRCR2 0xe61580b0
+
void __init sh73a0_add_standard_devices(void)
{
+ /* Clear software reset bit on SY-DMAC module */
+ __raw_writel(__raw_readl(SRCR2) & ~(1 << 18), SRCR2);
+
platform_add_devices(sh73a0_early_devices,
ARRAY_SIZE(sh73a0_early_devices));
platform_add_devices(sh73a0_late_devices,
diff --git a/arch/arm/mach-shmobile/sleep-sh7372.S b/arch/arm/mach-shmobile/sleep-sh7372.S
new file mode 100644
index 000000000000..d37d3ca4d18f
--- /dev/null
+++ b/arch/arm/mach-shmobile/sleep-sh7372.S
@@ -0,0 +1,260 @@
+/*
+ * sh7372 lowlevel sleep code for "Core Standby Mode"
+ *
+ * Copyright (C) 2011 Magnus Damm
+ *
+ * In "Core Standby Mode" the ARM core is off, but L2 cache is still on
+ *
+ * Based on mach-omap2/sleep34xx.S
+ *
+ * (C) Copyright 2007 Texas Instruments
+ * Karthik Dasu <karthik-dp@ti.com>
+ *
+ * (C) Copyright 2004 Texas Instruments, <www.ti.com>
+ * Richard Woodruff <r-woodruff2@ti.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/linkage.h>
+#include <asm/assembler.h>
+
+#define SMFRAM 0xe6a70000
+
+ .align
+kernel_flush:
+ .word v7_flush_dcache_all
+
+ .align 3
+ENTRY(sh7372_cpu_suspend)
+ stmfd sp!, {r0-r12, lr} @ save registers on stack
+
+ ldr r8, =SMFRAM
+
+ mov r4, sp @ Store sp
+ mrs r5, spsr @ Store spsr
+ mov r6, lr @ Store lr
+ stmia r8!, {r4-r6}
+
+ mrc p15, 0, r4, c1, c0, 2 @ Coprocessor access control register
+ mrc p15, 0, r5, c2, c0, 0 @ TTBR0
+ mrc p15, 0, r6, c2, c0, 1 @ TTBR1
+ mrc p15, 0, r7, c2, c0, 2 @ TTBCR
+ stmia r8!, {r4-r7}
+
+ mrc p15, 0, r4, c3, c0, 0 @ Domain access Control Register
+ mrc p15, 0, r5, c10, c2, 0 @ PRRR
+ mrc p15, 0, r6, c10, c2, 1 @ NMRR
+ stmia r8!,{r4-r6}
+
+ mrc p15, 0, r4, c13, c0, 1 @ Context ID
+ mrc p15, 0, r5, c13, c0, 2 @ User r/w thread and process ID
+ mrc p15, 0, r6, c12, c0, 0 @ Secure or NS vector base address
+ mrs r7, cpsr @ Store current cpsr
+ stmia r8!, {r4-r7}
+
+ mrc p15, 0, r4, c1, c0, 0 @ save control register
+ stmia r8!, {r4}
+
+ /*
+ * jump out to kernel flush routine
+ * - reuse that code is better
+ * - it executes in a cached space so is faster than refetch per-block
+ * - should be faster and will change with kernel
+ * - 'might' have to copy address, load and jump to it
+ * Flush all data from the L1 data cache before disabling
+ * SCTLR.C bit.
+ */
+ ldr r1, kernel_flush
+ mov lr, pc
+ bx r1
+
+ /*
+ * Clear the SCTLR.C bit to prevent further data cache
+ * allocation. Clearing SCTLR.C would make all the data accesses
+ * strongly ordered and would not hit the cache.
+ */
+ mrc p15, 0, r0, c1, c0, 0
+ bic r0, r0, #(1 << 2) @ Disable the C bit
+ mcr p15, 0, r0, c1, c0, 0
+ isb
+
+ /*
+ * Invalidate L1 data cache. Even though only invalidate is
+ * necessary exported flush API is used here. Doing clean
+ * on already clean cache would be almost NOP.
+ */
+ ldr r1, kernel_flush
+ blx r1
+ /*
+ * The kernel doesn't interwork: v7_flush_dcache_all in particluar will
+ * always return in Thumb state when CONFIG_THUMB2_KERNEL is enabled.
+ * This sequence switches back to ARM. Note that .align may insert a
+ * nop: bx pc needs to be word-aligned in order to work.
+ */
+ THUMB( .thumb )
+ THUMB( .align )
+ THUMB( bx pc )
+ THUMB( nop )
+ .arm
+
+ /* Data memory barrier and Data sync barrier */
+ dsb
+ dmb
+
+/*
+ * ===================================
+ * == WFI instruction => Enter idle ==
+ * ===================================
+ */
+ wfi @ wait for interrupt
+
+/*
+ * ===================================
+ * == Resume path for non-OFF modes ==
+ * ===================================
+ */
+ mrc p15, 0, r0, c1, c0, 0
+ tst r0, #(1 << 2) @ Check C bit enabled?
+ orreq r0, r0, #(1 << 2) @ Enable the C bit if cleared
+ mcreq p15, 0, r0, c1, c0, 0
+ isb
+
+/*
+ * ===================================
+ * == Exit point from non-OFF modes ==
+ * ===================================
+ */
+ ldmfd sp!, {r0-r12, pc} @ restore regs and return
+
+ .pool
+
+ .align 12
+ .text
+ .global sh7372_cpu_resume
+sh7372_cpu_resume:
+
+ mov r1, #0
+ /*
+ * Invalidate all instruction caches to PoU
+ * and flush branch target cache
+ */
+ mcr p15, 0, r1, c7, c5, 0
+
+ ldr r3, =SMFRAM
+
+ ldmia r3!, {r4-r6}
+ mov sp, r4 @ Restore sp
+ msr spsr_cxsf, r5 @ Restore spsr
+ mov lr, r6 @ Restore lr
+
+ ldmia r3!, {r4-r7}
+ mcr p15, 0, r4, c1, c0, 2 @ Coprocessor access Control Register
+ mcr p15, 0, r5, c2, c0, 0 @ TTBR0
+ mcr p15, 0, r6, c2, c0, 1 @ TTBR1
+ mcr p15, 0, r7, c2, c0, 2 @ TTBCR
+
+ ldmia r3!,{r4-r6}
+ mcr p15, 0, r4, c3, c0, 0 @ Domain access Control Register
+ mcr p15, 0, r5, c10, c2, 0 @ PRRR
+ mcr p15, 0, r6, c10, c2, 1 @ NMRR
+
+ ldmia r3!,{r4-r7}
+ mcr p15, 0, r4, c13, c0, 1 @ Context ID
+ mcr p15, 0, r5, c13, c0, 2 @ User r/w thread and process ID
+ mrc p15, 0, r6, c12, c0, 0 @ Secure or NS vector base address
+ msr cpsr, r7 @ store cpsr
+
+ /* Starting to enable MMU here */
+ mrc p15, 0, r7, c2, c0, 2 @ Read TTBRControl
+ /* Extract N (0:2) bits and decide whether to use TTBR0 or TTBR1 */
+ and r7, #0x7
+ cmp r7, #0x0
+ beq usettbr0
+ttbr_error:
+ /*
+ * More work needs to be done to support N[0:2] value other than 0
+ * So looping here so that the error can be detected
+ */
+ b ttbr_error
+
+ .align
+cache_pred_disable_mask:
+ .word 0xFFFFE7FB
+ttbrbit_mask:
+ .word 0xFFFFC000
+table_index_mask:
+ .word 0xFFF00000
+table_entry:
+ .word 0x00000C02
+usettbr0:
+
+ mrc p15, 0, r2, c2, c0, 0
+ ldr r5, ttbrbit_mask
+ and r2, r5
+ mov r4, pc
+ ldr r5, table_index_mask
+ and r4, r5 @ r4 = 31 to 20 bits of pc
+ /* Extract the value to be written to table entry */
+ ldr r6, table_entry
+ /* r6 has the value to be written to table entry */
+ add r6, r6, r4
+ /* Getting the address of table entry to modify */
+ lsr r4, #18
+ /* r2 has the location which needs to be modified */
+ add r2, r4
+ ldr r4, [r2]
+ str r6, [r2] /* modify the table entry */
+
+ mov r7, r6
+ mov r5, r2
+ mov r6, r4
+ /* r5 = original page table address */
+ /* r6 = original page table data */
+
+ mov r0, #0
+ mcr p15, 0, r0, c7, c5, 4 @ Flush prefetch buffer
+ mcr p15, 0, r0, c7, c5, 6 @ Invalidate branch predictor array
+ mcr p15, 0, r0, c8, c5, 0 @ Invalidate instruction TLB
+ mcr p15, 0, r0, c8, c6, 0 @ Invalidate data TLB
+
+ /*
+ * Restore control register. This enables the MMU.
+ * The caches and prediction are not enabled here, they
+ * will be enabled after restoring the MMU table entry.
+ */
+ ldmia r3!, {r4}
+ stmia r3!, {r5} /* save original page table address */
+ stmia r3!, {r6} /* save original page table data */
+ stmia r3!, {r7} /* save modified page table data */
+
+ ldr r2, cache_pred_disable_mask
+ and r4, r2
+ mcr p15, 0, r4, c1, c0, 0
+ dsb
+ isb
+
+ ldr r0, =restoremmu_on
+ bx r0
+
+/*
+ * ==============================
+ * == Exit point from OFF mode ==
+ * ==============================
+ */
+restoremmu_on:
+
+ ldmfd sp!, {r0-r12, pc} @ restore regs and return
diff --git a/arch/arm/mach-shmobile/smp-sh73a0.c b/arch/arm/mach-shmobile/smp-sh73a0.c
index a156d2108df1..3ffdbc92ba82 100644
--- a/arch/arm/mach-shmobile/smp-sh73a0.c
+++ b/arch/arm/mach-shmobile/smp-sh73a0.c
@@ -59,6 +59,11 @@ unsigned int __init sh73a0_get_core_count(void)
{
void __iomem *scu_base = scu_base_addr();
+#ifdef CONFIG_HAVE_ARM_TWD
+ /* twd_base needs to be initialized before percpu_timer_setup() */
+ twd_base = (void __iomem *)0xf0000600;
+#endif
+
return scu_get_core_count(scu_base);
}
@@ -82,10 +87,6 @@ int __cpuinit sh73a0_boot_secondary(unsigned int cpu)
void __init sh73a0_smp_prepare_cpus(void)
{
-#ifdef CONFIG_HAVE_ARM_TWD
- twd_base = (void __iomem *)0xf0000600;
-#endif
-
scu_enable(scu_base_addr());
/* Map the reset vector (in headsmp.S) */
diff --git a/arch/arm/mach-shmobile/suspend.c b/arch/arm/mach-shmobile/suspend.c
new file mode 100644
index 000000000000..c1febe13f709
--- /dev/null
+++ b/arch/arm/mach-shmobile/suspend.c
@@ -0,0 +1,47 @@
+/*
+ * Suspend-to-RAM support code for SH-Mobile ARM
+ *
+ * Copyright (C) 2011 Magnus Damm
+ *
+ * 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/pm.h>
+#include <linux/suspend.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+static int shmobile_suspend_default_enter(suspend_state_t suspend_state)
+{
+ cpu_do_idle();
+ return 0;
+}
+
+static int shmobile_suspend_begin(suspend_state_t state)
+{
+ disable_hlt();
+ return 0;
+}
+
+static void shmobile_suspend_end(void)
+{
+ enable_hlt();
+}
+
+struct platform_suspend_ops shmobile_suspend_ops = {
+ .begin = shmobile_suspend_begin,
+ .end = shmobile_suspend_end,
+ .enter = shmobile_suspend_default_enter,
+ .valid = suspend_valid_only_mem,
+};
+
+static int __init shmobile_suspend_init(void)
+{
+ suspend_set_ops(&shmobile_suspend_ops);
+ return 0;
+}
+late_initcall(shmobile_suspend_init);
diff --git a/arch/arm/mach-spear3xx/Kconfig b/arch/arm/mach-spear3xx/Kconfig
index 20d1317cc486..2cee6b0de371 100644
--- a/arch/arm/mach-spear3xx/Kconfig
+++ b/arch/arm/mach-spear3xx/Kconfig
@@ -4,9 +4,26 @@
if ARCH_SPEAR3XX
-choice
- prompt "SPEAr3XX Family"
- default MACH_SPEAR300
+menu "SPEAr3xx Implementations"
+config BOARD_SPEAR300_EVB
+ bool "SPEAr300 Evaluation Board"
+ select MACH_SPEAR300
+ help
+ Supports ST SPEAr300 Evaluation Board
+
+config BOARD_SPEAR310_EVB
+ bool "SPEAr310 Evaluation Board"
+ select MACH_SPEAR310
+ help
+ Supports ST SPEAr310 Evaluation Board
+
+config BOARD_SPEAR320_EVB
+ bool "SPEAr320 Evaluation Board"
+ select MACH_SPEAR320
+ help
+ Supports ST SPEAr320 Evaluation Board
+
+endmenu
config MACH_SPEAR300
bool "SPEAr300"
@@ -23,11 +40,4 @@ config MACH_SPEAR320
help
Supports ST SPEAr320 Machine
-endchoice
-
-# Adding SPEAr3XX machine specific configuration files
-source "arch/arm/mach-spear3xx/Kconfig300"
-source "arch/arm/mach-spear3xx/Kconfig310"
-source "arch/arm/mach-spear3xx/Kconfig320"
-
endif #ARCH_SPEAR3XX
diff --git a/arch/arm/mach-spear3xx/Kconfig300 b/arch/arm/mach-spear3xx/Kconfig300
deleted file mode 100644
index c519a05b4ab4..000000000000
--- a/arch/arm/mach-spear3xx/Kconfig300
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# SPEAr300 machine configuration file
-#
-
-if MACH_SPEAR300
-
-choice
- prompt "SPEAr300 Boards"
- default BOARD_SPEAR300_EVB
-
-config BOARD_SPEAR300_EVB
- bool "SPEAr300 Evaluation Board"
- help
- Supports ST SPEAr300 Evaluation Board
-endchoice
-
-endif #MACH_SPEAR300
diff --git a/arch/arm/mach-spear3xx/Kconfig310 b/arch/arm/mach-spear3xx/Kconfig310
deleted file mode 100644
index 60e7442d75bd..000000000000
--- a/arch/arm/mach-spear3xx/Kconfig310
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# SPEAr310 machine configuration file
-#
-
-if MACH_SPEAR310
-
-choice
- prompt "SPEAr310 Boards"
- default BOARD_SPEAR310_EVB
-
-config BOARD_SPEAR310_EVB
- bool "SPEAr310 Evaluation Board"
- help
- Supports ST SPEAr310 Evaluation Board
-endchoice
-
-endif #MACH_SPEAR310
diff --git a/arch/arm/mach-spear3xx/Kconfig320 b/arch/arm/mach-spear3xx/Kconfig320
deleted file mode 100644
index 1c1d438399b8..000000000000
--- a/arch/arm/mach-spear3xx/Kconfig320
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# SPEAr320 machine configuration file
-#
-
-if MACH_SPEAR320
-
-choice
- prompt "SPEAr320 Boards"
- default BOARD_SPEAR320_EVB
-
-config BOARD_SPEAR320_EVB
- bool "SPEAr320 Evaluation Board"
- help
- Supports ST SPEAr320 Evaluation Board
-endchoice
-
-endif #MACH_SPEAR320
diff --git a/arch/arm/mach-spear3xx/clock.c b/arch/arm/mach-spear3xx/clock.c
index 98bc7edc95a6..f67860cd649f 100644
--- a/arch/arm/mach-spear3xx/clock.c
+++ b/arch/arm/mach-spear3xx/clock.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
+#include <asm/mach-types.h>
#include <plat/clock.h>
#include <mach/misc_regs.h>
@@ -688,56 +689,71 @@ static struct clk_lookup spear_clk_lookups[] = {
{ .dev_id = "adc", .clk = &adc_clk},
{ .dev_id = "ssp-pl022.0", .clk = &ssp0_clk},
{ .dev_id = "gpio", .clk = &gpio_clk},
-#if defined(CONFIG_MACH_SPEAR310) || defined(CONFIG_MACH_SPEAR320)
- { .dev_id = "physmap-flash", .clk = &emi_clk},
-#endif
-#if defined(CONFIG_MACH_SPEAR300) || defined(CONFIG_MACH_SPEAR310) || \
- defined(CONFIG_MACH_SPEAR320)
- { .con_id = "fsmc", .clk = &fsmc_clk},
-#endif
-
-/* common clocks to spear310 and spear320 */
-#if defined(CONFIG_MACH_SPEAR310) || defined(CONFIG_MACH_SPEAR320)
- { .dev_id = "uart1", .clk = &uart1_clk},
- { .dev_id = "uart2", .clk = &uart2_clk},
-#endif
-
- /* common clock to spear300 and spear320 */
-#if defined(CONFIG_MACH_SPEAR300) || defined(CONFIG_MACH_SPEAR320)
- { .dev_id = "clcd", .clk = &clcd_clk},
- { .dev_id = "sdhci", .clk = &sdhci_clk},
-#endif /* CONFIG_MACH_SPEAR300 || CONFIG_MACH_SPEAR320 */
+};
- /* spear300 machine specific clock structures */
+/* array of all spear 300 clock lookups */
#ifdef CONFIG_MACH_SPEAR300
+static struct clk_lookup spear300_clk_lookups[] = {
+ { .dev_id = "clcd", .clk = &clcd_clk},
+ { .con_id = "fsmc", .clk = &fsmc_clk},
{ .dev_id = "gpio1", .clk = &gpio1_clk},
{ .dev_id = "keyboard", .clk = &kbd_clk},
+ { .dev_id = "sdhci", .clk = &sdhci_clk},
+};
#endif
- /* spear310 machine specific clock structures */
+/* array of all spear 310 clock lookups */
#ifdef CONFIG_MACH_SPEAR310
+static struct clk_lookup spear310_clk_lookups[] = {
+ { .con_id = "fsmc", .clk = &fsmc_clk},
+ { .con_id = "emi", .clk = &emi_clk},
+ { .dev_id = "uart1", .clk = &uart1_clk},
+ { .dev_id = "uart2", .clk = &uart2_clk},
{ .dev_id = "uart3", .clk = &uart3_clk},
{ .dev_id = "uart4", .clk = &uart4_clk},
{ .dev_id = "uart5", .clk = &uart5_clk},
-
+};
#endif
- /* spear320 machine specific clock structures */
+
+/* array of all spear 320 clock lookups */
#ifdef CONFIG_MACH_SPEAR320
+static struct clk_lookup spear320_clk_lookups[] = {
+ { .dev_id = "clcd", .clk = &clcd_clk},
+ { .con_id = "fsmc", .clk = &fsmc_clk},
+ { .dev_id = "i2c_designware.1", .clk = &i2c1_clk},
+ { .con_id = "emi", .clk = &emi_clk},
+ { .dev_id = "pwm", .clk = &pwm_clk},
+ { .dev_id = "sdhci", .clk = &sdhci_clk},
{ .dev_id = "c_can_platform.0", .clk = &can0_clk},
{ .dev_id = "c_can_platform.1", .clk = &can1_clk},
- { .dev_id = "i2c_designware.1", .clk = &i2c1_clk},
{ .dev_id = "ssp-pl022.1", .clk = &ssp1_clk},
{ .dev_id = "ssp-pl022.2", .clk = &ssp2_clk},
- { .dev_id = "pwm", .clk = &pwm_clk},
-#endif
+ { .dev_id = "uart1", .clk = &uart1_clk},
+ { .dev_id = "uart2", .clk = &uart2_clk},
};
+#endif
-void __init clk_init(void)
+void __init spear3xx_clk_init(void)
{
- int i;
+ int i, cnt;
+ struct clk_lookup *lookups;
+
+ if (machine_is_spear300()) {
+ cnt = ARRAY_SIZE(spear300_clk_lookups);
+ lookups = spear300_clk_lookups;
+ } else if (machine_is_spear310()) {
+ cnt = ARRAY_SIZE(spear310_clk_lookups);
+ lookups = spear310_clk_lookups;
+ } else {
+ cnt = ARRAY_SIZE(spear320_clk_lookups);
+ lookups = spear320_clk_lookups;
+ }
for (i = 0; i < ARRAY_SIZE(spear_clk_lookups); i++)
clk_register(&spear_clk_lookups[i]);
- recalc_root_clocks();
+ for (i = 0; i < cnt; i++)
+ clk_register(&lookups[i]);
+
+ clk_init();
}
diff --git a/arch/arm/mach-spear3xx/include/mach/generic.h b/arch/arm/mach-spear3xx/include/mach/generic.h
index 8e30636909ef..b8f31c3935f7 100644
--- a/arch/arm/mach-spear3xx/include/mach/generic.h
+++ b/arch/arm/mach-spear3xx/include/mach/generic.h
@@ -27,16 +27,16 @@
* Following GPT channels will be used as clock source and clockevent
*/
#define SPEAR_GPT0_BASE SPEAR3XX_ML1_TMR_BASE
-#define SPEAR_GPT0_CHAN0_IRQ IRQ_CPU_GPT1_1
-#define SPEAR_GPT0_CHAN1_IRQ IRQ_CPU_GPT1_2
+#define SPEAR_GPT0_CHAN0_IRQ SPEAR3XX_IRQ_CPU_GPT1_1
+#define SPEAR_GPT0_CHAN1_IRQ SPEAR3XX_IRQ_CPU_GPT1_2
/* Add spear3xx family device structure declarations here */
-extern struct amba_device gpio_device;
-extern struct amba_device uart_device;
+extern struct amba_device spear3xx_gpio_device;
+extern struct amba_device spear3xx_uart_device;
extern struct sys_timer spear3xx_timer;
/* Add spear3xx family function declarations here */
-void __init clk_init(void);
+void __init spear3xx_clk_init(void);
void __init spear_setup_timer(void);
void __init spear3xx_map_io(void);
void __init spear3xx_init_irq(void);
@@ -60,81 +60,80 @@ void __init spear3xx_init(void);
#define PMX_TIMER_1_2_MASK (1 << 0)
/* pad mux devices */
-extern struct pmx_dev pmx_firda;
-extern struct pmx_dev pmx_i2c;
-extern struct pmx_dev pmx_ssp_cs;
-extern struct pmx_dev pmx_ssp;
-extern struct pmx_dev pmx_mii;
-extern struct pmx_dev pmx_gpio_pin0;
-extern struct pmx_dev pmx_gpio_pin1;
-extern struct pmx_dev pmx_gpio_pin2;
-extern struct pmx_dev pmx_gpio_pin3;
-extern struct pmx_dev pmx_gpio_pin4;
-extern struct pmx_dev pmx_gpio_pin5;
-extern struct pmx_dev pmx_uart0_modem;
-extern struct pmx_dev pmx_uart0;
-extern struct pmx_dev pmx_timer_3_4;
-extern struct pmx_dev pmx_timer_1_2;
+extern struct pmx_dev spear3xx_pmx_firda;
+extern struct pmx_dev spear3xx_pmx_i2c;
+extern struct pmx_dev spear3xx_pmx_ssp_cs;
+extern struct pmx_dev spear3xx_pmx_ssp;
+extern struct pmx_dev spear3xx_pmx_mii;
+extern struct pmx_dev spear3xx_pmx_gpio_pin0;
+extern struct pmx_dev spear3xx_pmx_gpio_pin1;
+extern struct pmx_dev spear3xx_pmx_gpio_pin2;
+extern struct pmx_dev spear3xx_pmx_gpio_pin3;
+extern struct pmx_dev spear3xx_pmx_gpio_pin4;
+extern struct pmx_dev spear3xx_pmx_gpio_pin5;
+extern struct pmx_dev spear3xx_pmx_uart0_modem;
+extern struct pmx_dev spear3xx_pmx_uart0;
+extern struct pmx_dev spear3xx_pmx_timer_3_4;
+extern struct pmx_dev spear3xx_pmx_timer_1_2;
#if defined(CONFIG_MACH_SPEAR310) || defined(CONFIG_MACH_SPEAR320)
/* padmux plgpio devices */
-extern struct pmx_dev pmx_plgpio_0_1;
-extern struct pmx_dev pmx_plgpio_2_3;
-extern struct pmx_dev pmx_plgpio_4_5;
-extern struct pmx_dev pmx_plgpio_6_9;
-extern struct pmx_dev pmx_plgpio_10_27;
-extern struct pmx_dev pmx_plgpio_28;
-extern struct pmx_dev pmx_plgpio_29;
-extern struct pmx_dev pmx_plgpio_30;
-extern struct pmx_dev pmx_plgpio_31;
-extern struct pmx_dev pmx_plgpio_32;
-extern struct pmx_dev pmx_plgpio_33;
-extern struct pmx_dev pmx_plgpio_34_36;
-extern struct pmx_dev pmx_plgpio_37_42;
-extern struct pmx_dev pmx_plgpio_43_44_47_48;
-extern struct pmx_dev pmx_plgpio_45_46_49_50;
+extern struct pmx_dev spear3xx_pmx_plgpio_0_1;
+extern struct pmx_dev spear3xx_pmx_plgpio_2_3;
+extern struct pmx_dev spear3xx_pmx_plgpio_4_5;
+extern struct pmx_dev spear3xx_pmx_plgpio_6_9;
+extern struct pmx_dev spear3xx_pmx_plgpio_10_27;
+extern struct pmx_dev spear3xx_pmx_plgpio_28;
+extern struct pmx_dev spear3xx_pmx_plgpio_29;
+extern struct pmx_dev spear3xx_pmx_plgpio_30;
+extern struct pmx_dev spear3xx_pmx_plgpio_31;
+extern struct pmx_dev spear3xx_pmx_plgpio_32;
+extern struct pmx_dev spear3xx_pmx_plgpio_33;
+extern struct pmx_dev spear3xx_pmx_plgpio_34_36;
+extern struct pmx_dev spear3xx_pmx_plgpio_37_42;
+extern struct pmx_dev spear3xx_pmx_plgpio_43_44_47_48;
+extern struct pmx_dev spear3xx_pmx_plgpio_45_46_49_50;
#endif
-extern struct pmx_driver pmx_driver;
-
/* spear300 declarations */
#ifdef CONFIG_MACH_SPEAR300
/* Add spear300 machine device structure declarations here */
-extern struct amba_device gpio1_device;
+extern struct amba_device spear300_gpio1_device;
/* pad mux modes */
-extern struct pmx_mode nand_mode;
-extern struct pmx_mode nor_mode;
-extern struct pmx_mode photo_frame_mode;
-extern struct pmx_mode lend_ip_phone_mode;
-extern struct pmx_mode hend_ip_phone_mode;
-extern struct pmx_mode lend_wifi_phone_mode;
-extern struct pmx_mode hend_wifi_phone_mode;
-extern struct pmx_mode ata_pabx_wi2s_mode;
-extern struct pmx_mode ata_pabx_i2s_mode;
-extern struct pmx_mode caml_lcdw_mode;
-extern struct pmx_mode camu_lcd_mode;
-extern struct pmx_mode camu_wlcd_mode;
-extern struct pmx_mode caml_lcd_mode;
+extern struct pmx_mode spear300_nand_mode;
+extern struct pmx_mode spear300_nor_mode;
+extern struct pmx_mode spear300_photo_frame_mode;
+extern struct pmx_mode spear300_lend_ip_phone_mode;
+extern struct pmx_mode spear300_hend_ip_phone_mode;
+extern struct pmx_mode spear300_lend_wifi_phone_mode;
+extern struct pmx_mode spear300_hend_wifi_phone_mode;
+extern struct pmx_mode spear300_ata_pabx_wi2s_mode;
+extern struct pmx_mode spear300_ata_pabx_i2s_mode;
+extern struct pmx_mode spear300_caml_lcdw_mode;
+extern struct pmx_mode spear300_camu_lcd_mode;
+extern struct pmx_mode spear300_camu_wlcd_mode;
+extern struct pmx_mode spear300_caml_lcd_mode;
/* pad mux devices */
-extern struct pmx_dev pmx_fsmc_2_chips;
-extern struct pmx_dev pmx_fsmc_4_chips;
-extern struct pmx_dev pmx_keyboard;
-extern struct pmx_dev pmx_clcd;
-extern struct pmx_dev pmx_telecom_gpio;
-extern struct pmx_dev pmx_telecom_tdm;
-extern struct pmx_dev pmx_telecom_spi_cs_i2c_clk;
-extern struct pmx_dev pmx_telecom_camera;
-extern struct pmx_dev pmx_telecom_dac;
-extern struct pmx_dev pmx_telecom_i2s;
-extern struct pmx_dev pmx_telecom_boot_pins;
-extern struct pmx_dev pmx_telecom_sdhci_4bit;
-extern struct pmx_dev pmx_telecom_sdhci_8bit;
-extern struct pmx_dev pmx_gpio1;
+extern struct pmx_dev spear300_pmx_fsmc_2_chips;
+extern struct pmx_dev spear300_pmx_fsmc_4_chips;
+extern struct pmx_dev spear300_pmx_keyboard;
+extern struct pmx_dev spear300_pmx_clcd;
+extern struct pmx_dev spear300_pmx_telecom_gpio;
+extern struct pmx_dev spear300_pmx_telecom_tdm;
+extern struct pmx_dev spear300_pmx_telecom_spi_cs_i2c_clk;
+extern struct pmx_dev spear300_pmx_telecom_camera;
+extern struct pmx_dev spear300_pmx_telecom_dac;
+extern struct pmx_dev spear300_pmx_telecom_i2s;
+extern struct pmx_dev spear300_pmx_telecom_boot_pins;
+extern struct pmx_dev spear300_pmx_telecom_sdhci_4bit;
+extern struct pmx_dev spear300_pmx_telecom_sdhci_8bit;
+extern struct pmx_dev spear300_pmx_gpio1;
/* Add spear300 machine function declarations here */
-void __init spear300_init(void);
+void __init spear300_init(struct pmx_mode *pmx_mode, struct pmx_dev **pmx_devs,
+ u8 pmx_dev_count);
#endif /* CONFIG_MACH_SPEAR300 */
@@ -143,17 +142,18 @@ void __init spear300_init(void);
/* Add spear310 machine device structure declarations here */
/* pad mux devices */
-extern struct pmx_dev pmx_emi_cs_0_1_4_5;
-extern struct pmx_dev pmx_emi_cs_2_3;
-extern struct pmx_dev pmx_uart1;
-extern struct pmx_dev pmx_uart2;
-extern struct pmx_dev pmx_uart3_4_5;
-extern struct pmx_dev pmx_fsmc;
-extern struct pmx_dev pmx_rs485_0_1;
-extern struct pmx_dev pmx_tdm0;
+extern struct pmx_dev spear310_pmx_emi_cs_0_1_4_5;
+extern struct pmx_dev spear310_pmx_emi_cs_2_3;
+extern struct pmx_dev spear310_pmx_uart1;
+extern struct pmx_dev spear310_pmx_uart2;
+extern struct pmx_dev spear310_pmx_uart3_4_5;
+extern struct pmx_dev spear310_pmx_fsmc;
+extern struct pmx_dev spear310_pmx_rs485_0_1;
+extern struct pmx_dev spear310_pmx_tdm0;
/* Add spear310 machine function declarations here */
-void __init spear310_init(void);
+void __init spear310_init(struct pmx_mode *pmx_mode, struct pmx_dev **pmx_devs,
+ u8 pmx_dev_count);
#endif /* CONFIG_MACH_SPEAR310 */
@@ -162,37 +162,38 @@ void __init spear310_init(void);
/* Add spear320 machine device structure declarations here */
/* pad mux modes */
-extern struct pmx_mode auto_net_smii_mode;
-extern struct pmx_mode auto_net_mii_mode;
-extern struct pmx_mode auto_exp_mode;
-extern struct pmx_mode small_printers_mode;
+extern struct pmx_mode spear320_auto_net_smii_mode;
+extern struct pmx_mode spear320_auto_net_mii_mode;
+extern struct pmx_mode spear320_auto_exp_mode;
+extern struct pmx_mode spear320_small_printers_mode;
/* pad mux devices */
-extern struct pmx_dev pmx_clcd;
-extern struct pmx_dev pmx_emi;
-extern struct pmx_dev pmx_fsmc;
-extern struct pmx_dev pmx_spp;
-extern struct pmx_dev pmx_sdhci;
-extern struct pmx_dev pmx_i2s;
-extern struct pmx_dev pmx_uart1;
-extern struct pmx_dev pmx_uart1_modem;
-extern struct pmx_dev pmx_uart2;
-extern struct pmx_dev pmx_touchscreen;
-extern struct pmx_dev pmx_can;
-extern struct pmx_dev pmx_sdhci_led;
-extern struct pmx_dev pmx_pwm0;
-extern struct pmx_dev pmx_pwm1;
-extern struct pmx_dev pmx_pwm2;
-extern struct pmx_dev pmx_pwm3;
-extern struct pmx_dev pmx_ssp1;
-extern struct pmx_dev pmx_ssp2;
-extern struct pmx_dev pmx_mii1;
-extern struct pmx_dev pmx_smii0;
-extern struct pmx_dev pmx_smii1;
-extern struct pmx_dev pmx_i2c1;
+extern struct pmx_dev spear320_pmx_clcd;
+extern struct pmx_dev spear320_pmx_emi;
+extern struct pmx_dev spear320_pmx_fsmc;
+extern struct pmx_dev spear320_pmx_spp;
+extern struct pmx_dev spear320_pmx_sdhci;
+extern struct pmx_dev spear320_pmx_i2s;
+extern struct pmx_dev spear320_pmx_uart1;
+extern struct pmx_dev spear320_pmx_uart1_modem;
+extern struct pmx_dev spear320_pmx_uart2;
+extern struct pmx_dev spear320_pmx_touchscreen;
+extern struct pmx_dev spear320_pmx_can;
+extern struct pmx_dev spear320_pmx_sdhci_led;
+extern struct pmx_dev spear320_pmx_pwm0;
+extern struct pmx_dev spear320_pmx_pwm1;
+extern struct pmx_dev spear320_pmx_pwm2;
+extern struct pmx_dev spear320_pmx_pwm3;
+extern struct pmx_dev spear320_pmx_ssp1;
+extern struct pmx_dev spear320_pmx_ssp2;
+extern struct pmx_dev spear320_pmx_mii1;
+extern struct pmx_dev spear320_pmx_smii0;
+extern struct pmx_dev spear320_pmx_smii1;
+extern struct pmx_dev spear320_pmx_i2c1;
/* Add spear320 machine function declarations here */
-void __init spear320_init(void);
+void __init spear320_init(struct pmx_mode *pmx_mode, struct pmx_dev **pmx_devs,
+ u8 pmx_dev_count);
#endif /* CONFIG_MACH_SPEAR320 */
diff --git a/arch/arm/mach-spear3xx/include/mach/irqs.h b/arch/arm/mach-spear3xx/include/mach/irqs.h
index a1a7f481866d..6e265442808e 100644
--- a/arch/arm/mach-spear3xx/include/mach/irqs.h
+++ b/arch/arm/mach-spear3xx/include/mach/irqs.h
@@ -15,138 +15,140 @@
#define __MACH_IRQS_H
/* SPEAr3xx IRQ definitions */
-#define IRQ_HW_ACCEL_MOD_0 0
-#define IRQ_INTRCOMM_RAS_ARM 1
-#define IRQ_CPU_GPT1_1 2
-#define IRQ_CPU_GPT1_2 3
-#define IRQ_BASIC_GPT1_1 4
-#define IRQ_BASIC_GPT1_2 5
-#define IRQ_BASIC_GPT2_1 6
-#define IRQ_BASIC_GPT2_2 7
-#define IRQ_BASIC_DMA 8
-#define IRQ_BASIC_SMI 9
-#define IRQ_BASIC_RTC 10
-#define IRQ_BASIC_GPIO 11
-#define IRQ_BASIC_WDT 12
-#define IRQ_DDR_CONTROLLER 13
-#define IRQ_SYS_ERROR 14
-#define IRQ_WAKEUP_RCV 15
-#define IRQ_JPEG 16
-#define IRQ_IRDA 17
-#define IRQ_ADC 18
-#define IRQ_UART 19
-#define IRQ_SSP 20
-#define IRQ_I2C 21
-#define IRQ_MAC_1 22
-#define IRQ_MAC_2 23
-#define IRQ_USB_DEV 24
-#define IRQ_USB_H_OHCI_0 25
-#define IRQ_USB_H_EHCI_0 26
-#define IRQ_USB_H_EHCI_1 IRQ_USB_H_EHCI_0
-#define IRQ_USB_H_OHCI_1 27
-#define IRQ_GEN_RAS_1 28
-#define IRQ_GEN_RAS_2 29
-#define IRQ_GEN_RAS_3 30
-#define IRQ_HW_ACCEL_MOD_1 31
-#define IRQ_VIC_END 32
-
-#define VIRQ_START IRQ_VIC_END
+#define SPEAR3XX_IRQ_HW_ACCEL_MOD_0 0
+#define SPEAR3XX_IRQ_INTRCOMM_RAS_ARM 1
+#define SPEAR3XX_IRQ_CPU_GPT1_1 2
+#define SPEAR3XX_IRQ_CPU_GPT1_2 3
+#define SPEAR3XX_IRQ_BASIC_GPT1_1 4
+#define SPEAR3XX_IRQ_BASIC_GPT1_2 5
+#define SPEAR3XX_IRQ_BASIC_GPT2_1 6
+#define SPEAR3XX_IRQ_BASIC_GPT2_2 7
+#define SPEAR3XX_IRQ_BASIC_DMA 8
+#define SPEAR3XX_IRQ_BASIC_SMI 9
+#define SPEAR3XX_IRQ_BASIC_RTC 10
+#define SPEAR3XX_IRQ_BASIC_GPIO 11
+#define SPEAR3XX_IRQ_BASIC_WDT 12
+#define SPEAR3XX_IRQ_DDR_CONTROLLER 13
+#define SPEAR3XX_IRQ_SYS_ERROR 14
+#define SPEAR3XX_IRQ_WAKEUP_RCV 15
+#define SPEAR3XX_IRQ_JPEG 16
+#define SPEAR3XX_IRQ_IRDA 17
+#define SPEAR3XX_IRQ_ADC 18
+#define SPEAR3XX_IRQ_UART 19
+#define SPEAR3XX_IRQ_SSP 20
+#define SPEAR3XX_IRQ_I2C 21
+#define SPEAR3XX_IRQ_MAC_1 22
+#define SPEAR3XX_IRQ_MAC_2 23
+#define SPEAR3XX_IRQ_USB_DEV 24
+#define SPEAR3XX_IRQ_USB_H_OHCI_0 25
+#define SPEAR3XX_IRQ_USB_H_EHCI_0 26
+#define SPEAR3XX_IRQ_USB_H_EHCI_1 SPEAR3XX_IRQ_USB_H_EHCI_0
+#define SPEAR3XX_IRQ_USB_H_OHCI_1 27
+#define SPEAR3XX_IRQ_GEN_RAS_1 28
+#define SPEAR3XX_IRQ_GEN_RAS_2 29
+#define SPEAR3XX_IRQ_GEN_RAS_3 30
+#define SPEAR3XX_IRQ_HW_ACCEL_MOD_1 31
+#define SPEAR3XX_IRQ_VIC_END 32
+
+#define SPEAR3XX_VIRQ_START SPEAR3XX_IRQ_VIC_END
/* SPEAr300 Virtual irq definitions */
-#ifdef CONFIG_MACH_SPEAR300
/* IRQs sharing IRQ_GEN_RAS_1 */
-#define VIRQ_IT_PERS_S (VIRQ_START + 0)
-#define VIRQ_IT_CHANGE_S (VIRQ_START + 1)
-#define VIRQ_I2S (VIRQ_START + 2)
-#define VIRQ_TDM (VIRQ_START + 3)
-#define VIRQ_CAMERA_L (VIRQ_START + 4)
-#define VIRQ_CAMERA_F (VIRQ_START + 5)
-#define VIRQ_CAMERA_V (VIRQ_START + 6)
-#define VIRQ_KEYBOARD (VIRQ_START + 7)
-#define VIRQ_GPIO1 (VIRQ_START + 8)
+#define SPEAR300_VIRQ_IT_PERS_S (SPEAR3XX_VIRQ_START + 0)
+#define SPEAR300_VIRQ_IT_CHANGE_S (SPEAR3XX_VIRQ_START + 1)
+#define SPEAR300_VIRQ_I2S (SPEAR3XX_VIRQ_START + 2)
+#define SPEAR300_VIRQ_TDM (SPEAR3XX_VIRQ_START + 3)
+#define SPEAR300_VIRQ_CAMERA_L (SPEAR3XX_VIRQ_START + 4)
+#define SPEAR300_VIRQ_CAMERA_F (SPEAR3XX_VIRQ_START + 5)
+#define SPEAR300_VIRQ_CAMERA_V (SPEAR3XX_VIRQ_START + 6)
+#define SPEAR300_VIRQ_KEYBOARD (SPEAR3XX_VIRQ_START + 7)
+#define SPEAR300_VIRQ_GPIO1 (SPEAR3XX_VIRQ_START + 8)
/* IRQs sharing IRQ_GEN_RAS_3 */
-#define IRQ_CLCD IRQ_GEN_RAS_3
+#define SPEAR300_IRQ_CLCD SPEAR3XX_IRQ_GEN_RAS_3
/* IRQs sharing IRQ_INTRCOMM_RAS_ARM */
-#define IRQ_SDHCI IRQ_INTRCOMM_RAS_ARM
-
-/* GPIO pins virtual irqs */
-#define SPEAR_GPIO_INT_BASE (VIRQ_START + 9)
-#define SPEAR_GPIO1_INT_BASE (SPEAR_GPIO_INT_BASE + 8)
-#define SPEAR_GPIO_INT_END (SPEAR_GPIO1_INT_BASE + 8)
+#define SPEAR300_IRQ_SDHCI SPEAR3XX_IRQ_INTRCOMM_RAS_ARM
/* SPEAr310 Virtual irq definitions */
-#elif defined(CONFIG_MACH_SPEAR310)
/* IRQs sharing IRQ_GEN_RAS_1 */
-#define VIRQ_SMII0 (VIRQ_START + 0)
-#define VIRQ_SMII1 (VIRQ_START + 1)
-#define VIRQ_SMII2 (VIRQ_START + 2)
-#define VIRQ_SMII3 (VIRQ_START + 3)
-#define VIRQ_WAKEUP_SMII0 (VIRQ_START + 4)
-#define VIRQ_WAKEUP_SMII1 (VIRQ_START + 5)
-#define VIRQ_WAKEUP_SMII2 (VIRQ_START + 6)
-#define VIRQ_WAKEUP_SMII3 (VIRQ_START + 7)
+#define SPEAR310_VIRQ_SMII0 (SPEAR3XX_VIRQ_START + 0)
+#define SPEAR310_VIRQ_SMII1 (SPEAR3XX_VIRQ_START + 1)
+#define SPEAR310_VIRQ_SMII2 (SPEAR3XX_VIRQ_START + 2)
+#define SPEAR310_VIRQ_SMII3 (SPEAR3XX_VIRQ_START + 3)
+#define SPEAR310_VIRQ_WAKEUP_SMII0 (SPEAR3XX_VIRQ_START + 4)
+#define SPEAR310_VIRQ_WAKEUP_SMII1 (SPEAR3XX_VIRQ_START + 5)
+#define SPEAR310_VIRQ_WAKEUP_SMII2 (SPEAR3XX_VIRQ_START + 6)
+#define SPEAR310_VIRQ_WAKEUP_SMII3 (SPEAR3XX_VIRQ_START + 7)
/* IRQs sharing IRQ_GEN_RAS_2 */
-#define VIRQ_UART1 (VIRQ_START + 8)
-#define VIRQ_UART2 (VIRQ_START + 9)
-#define VIRQ_UART3 (VIRQ_START + 10)
-#define VIRQ_UART4 (VIRQ_START + 11)
-#define VIRQ_UART5 (VIRQ_START + 12)
+#define SPEAR310_VIRQ_UART1 (SPEAR3XX_VIRQ_START + 8)
+#define SPEAR310_VIRQ_UART2 (SPEAR3XX_VIRQ_START + 9)
+#define SPEAR310_VIRQ_UART3 (SPEAR3XX_VIRQ_START + 10)
+#define SPEAR310_VIRQ_UART4 (SPEAR3XX_VIRQ_START + 11)
+#define SPEAR310_VIRQ_UART5 (SPEAR3XX_VIRQ_START + 12)
/* IRQs sharing IRQ_GEN_RAS_3 */
-#define VIRQ_EMI (VIRQ_START + 13)
-#define VIRQ_PLGPIO (VIRQ_START + 14)
+#define SPEAR310_VIRQ_EMI (SPEAR3XX_VIRQ_START + 13)
+#define SPEAR310_VIRQ_PLGPIO (SPEAR3XX_VIRQ_START + 14)
/* IRQs sharing IRQ_INTRCOMM_RAS_ARM */
-#define VIRQ_TDM_HDLC (VIRQ_START + 15)
-#define VIRQ_RS485_0 (VIRQ_START + 16)
-#define VIRQ_RS485_1 (VIRQ_START + 17)
-
-/* GPIO pins virtual irqs */
-#define SPEAR_GPIO_INT_BASE (VIRQ_START + 18)
+#define SPEAR310_VIRQ_TDM_HDLC (SPEAR3XX_VIRQ_START + 15)
+#define SPEAR310_VIRQ_RS485_0 (SPEAR3XX_VIRQ_START + 16)
+#define SPEAR310_VIRQ_RS485_1 (SPEAR3XX_VIRQ_START + 17)
/* SPEAr320 Virtual irq definitions */
-#else
/* IRQs sharing IRQ_GEN_RAS_1 */
-#define VIRQ_EMI (VIRQ_START + 0)
-#define VIRQ_CLCD (VIRQ_START + 1)
-#define VIRQ_SPP (VIRQ_START + 2)
+#define SPEAR320_VIRQ_EMI (SPEAR3XX_VIRQ_START + 0)
+#define SPEAR320_VIRQ_CLCD (SPEAR3XX_VIRQ_START + 1)
+#define SPEAR320_VIRQ_SPP (SPEAR3XX_VIRQ_START + 2)
/* IRQs sharing IRQ_GEN_RAS_2 */
-#define IRQ_SDHCI IRQ_GEN_RAS_2
+#define SPEAR320_IRQ_SDHCI SPEAR3XX_IRQ_GEN_RAS_2
/* IRQs sharing IRQ_GEN_RAS_3 */
-#define VIRQ_PLGPIO (VIRQ_START + 3)
-#define VIRQ_I2S_PLAY (VIRQ_START + 4)
-#define VIRQ_I2S_REC (VIRQ_START + 5)
+#define SPEAR320_VIRQ_PLGPIO (SPEAR3XX_VIRQ_START + 3)
+#define SPEAR320_VIRQ_I2S_PLAY (SPEAR3XX_VIRQ_START + 4)
+#define SPEAR320_VIRQ_I2S_REC (SPEAR3XX_VIRQ_START + 5)
/* IRQs sharing IRQ_INTRCOMM_RAS_ARM */
-#define VIRQ_CANU (VIRQ_START + 6)
-#define VIRQ_CANL (VIRQ_START + 7)
-#define VIRQ_UART1 (VIRQ_START + 8)
-#define VIRQ_UART2 (VIRQ_START + 9)
-#define VIRQ_SSP1 (VIRQ_START + 10)
-#define VIRQ_SSP2 (VIRQ_START + 11)
-#define VIRQ_SMII0 (VIRQ_START + 12)
-#define VIRQ_MII1_SMII1 (VIRQ_START + 13)
-#define VIRQ_WAKEUP_SMII0 (VIRQ_START + 14)
-#define VIRQ_WAKEUP_MII1_SMII1 (VIRQ_START + 15)
-#define VIRQ_I2C (VIRQ_START + 16)
-
-/* GPIO pins virtual irqs */
-#define SPEAR_GPIO_INT_BASE (VIRQ_START + 17)
+#define SPEAR320_VIRQ_CANU (SPEAR3XX_VIRQ_START + 6)
+#define SPEAR320_VIRQ_CANL (SPEAR3XX_VIRQ_START + 7)
+#define SPEAR320_VIRQ_UART1 (SPEAR3XX_VIRQ_START + 8)
+#define SPEAR320_VIRQ_UART2 (SPEAR3XX_VIRQ_START + 9)
+#define SPEAR320_VIRQ_SSP1 (SPEAR3XX_VIRQ_START + 10)
+#define SPEAR320_VIRQ_SSP2 (SPEAR3XX_VIRQ_START + 11)
+#define SPEAR320_VIRQ_SMII0 (SPEAR3XX_VIRQ_START + 12)
+#define SPEAR320_VIRQ_MII1_SMII1 (SPEAR3XX_VIRQ_START + 13)
+#define SPEAR320_VIRQ_WAKEUP_SMII0 (SPEAR3XX_VIRQ_START + 14)
+#define SPEAR320_VIRQ_WAKEUP_MII1_SMII1 (SPEAR3XX_VIRQ_START + 15)
+#define SPEAR320_VIRQ_I2C1 (SPEAR3XX_VIRQ_START + 16)
+/*
+ * GPIO pins virtual irqs
+ * Use the lowest number for the GPIO virtual IRQs base on which subarchs
+ * we have compiled in
+ */
+#if defined(CONFIG_MACH_SPEAR310)
+#define SPEAR3XX_GPIO_INT_BASE (SPEAR3XX_VIRQ_START + 18)
+#elif defined(CONFIG_MACH_SPEAR320)
+#define SPEAR3XX_GPIO_INT_BASE (SPEAR3XX_VIRQ_START + 17)
+#else
+#define SPEAR3XX_GPIO_INT_BASE (SPEAR3XX_VIRQ_START + 9)
#endif
-/* PLGPIO Virtual IRQs */
+#define SPEAR300_GPIO1_INT_BASE (SPEAR3XX_GPIO_INT_BASE + 8)
+#define SPEAR3XX_PLGPIO_COUNT 102
+
#if defined(CONFIG_MACH_SPEAR310) || defined(CONFIG_MACH_SPEAR320)
-#define SPEAR_PLGPIO_INT_BASE (SPEAR_GPIO_INT_BASE + 8)
-#define SPEAR_GPIO_INT_END (SPEAR_PLGPIO_INT_BASE + 102)
+#define SPEAR3XX_PLGPIO_INT_BASE (SPEAR3XX_GPIO_INT_BASE + 8)
+#define SPEAR3XX_GPIO_INT_END (SPEAR3XX_PLGPIO_INT_BASE + \
+ SPEAR3XX_PLGPIO_COUNT)
+#else
+#define SPEAR3XX_GPIO_INT_END (SPEAR300_GPIO1_INT_BASE + 8)
#endif
-#define VIRQ_END SPEAR_GPIO_INT_END
-#define NR_IRQS VIRQ_END
+#define SPEAR3XX_VIRQ_END SPEAR3XX_GPIO_INT_END
+#define NR_IRQS SPEAR3XX_VIRQ_END
#endif /* __MACH_IRQS_H */
diff --git a/arch/arm/mach-spear3xx/include/mach/spear300.h b/arch/arm/mach-spear3xx/include/mach/spear300.h
index c723515f8853..3b6ea0729040 100644
--- a/arch/arm/mach-spear3xx/include/mach/spear300.h
+++ b/arch/arm/mach-spear3xx/include/mach/spear300.h
@@ -20,19 +20,19 @@
#define SPEAR300_TELECOM_BASE UL(0x50000000)
/* Interrupt registers offsets and masks */
-#define INT_ENB_MASK_REG 0x54
-#define INT_STS_MASK_REG 0x58
-#define IT_PERS_S_IRQ_MASK (1 << 0)
-#define IT_CHANGE_S_IRQ_MASK (1 << 1)
-#define I2S_IRQ_MASK (1 << 2)
-#define TDM_IRQ_MASK (1 << 3)
-#define CAMERA_L_IRQ_MASK (1 << 4)
-#define CAMERA_F_IRQ_MASK (1 << 5)
-#define CAMERA_V_IRQ_MASK (1 << 6)
-#define KEYBOARD_IRQ_MASK (1 << 7)
-#define GPIO1_IRQ_MASK (1 << 8)
-
-#define SHIRQ_RAS1_MASK 0x1FF
+#define SPEAR300_INT_ENB_MASK_REG 0x54
+#define SPEAR300_INT_STS_MASK_REG 0x58
+#define SPEAR300_IT_PERS_S_IRQ_MASK (1 << 0)
+#define SPEAR300_IT_CHANGE_S_IRQ_MASK (1 << 1)
+#define SPEAR300_I2S_IRQ_MASK (1 << 2)
+#define SPEAR300_TDM_IRQ_MASK (1 << 3)
+#define SPEAR300_CAMERA_L_IRQ_MASK (1 << 4)
+#define SPEAR300_CAMERA_F_IRQ_MASK (1 << 5)
+#define SPEAR300_CAMERA_V_IRQ_MASK (1 << 6)
+#define SPEAR300_KEYBOARD_IRQ_MASK (1 << 7)
+#define SPEAR300_GPIO1_IRQ_MASK (1 << 8)
+
+#define SPEAR300_SHIRQ_RAS1_MASK 0x1FF
#define SPEAR300_CLCD_BASE UL(0x60000000)
#define SPEAR300_SDHCI_BASE UL(0x70000000)
diff --git a/arch/arm/mach-spear3xx/include/mach/spear310.h b/arch/arm/mach-spear3xx/include/mach/spear310.h
index 1e853479b8cd..1567d0da725f 100644
--- a/arch/arm/mach-spear3xx/include/mach/spear310.h
+++ b/arch/arm/mach-spear3xx/include/mach/spear310.h
@@ -29,29 +29,29 @@
#define SPEAR310_SOC_CONFIG_BASE UL(0xB4000000)
/* Interrupt registers offsets and masks */
-#define INT_STS_MASK_REG 0x04
-#define SMII0_IRQ_MASK (1 << 0)
-#define SMII1_IRQ_MASK (1 << 1)
-#define SMII2_IRQ_MASK (1 << 2)
-#define SMII3_IRQ_MASK (1 << 3)
-#define WAKEUP_SMII0_IRQ_MASK (1 << 4)
-#define WAKEUP_SMII1_IRQ_MASK (1 << 5)
-#define WAKEUP_SMII2_IRQ_MASK (1 << 6)
-#define WAKEUP_SMII3_IRQ_MASK (1 << 7)
-#define UART1_IRQ_MASK (1 << 8)
-#define UART2_IRQ_MASK (1 << 9)
-#define UART3_IRQ_MASK (1 << 10)
-#define UART4_IRQ_MASK (1 << 11)
-#define UART5_IRQ_MASK (1 << 12)
-#define EMI_IRQ_MASK (1 << 13)
-#define TDM_HDLC_IRQ_MASK (1 << 14)
-#define RS485_0_IRQ_MASK (1 << 15)
-#define RS485_1_IRQ_MASK (1 << 16)
+#define SPEAR310_INT_STS_MASK_REG 0x04
+#define SPEAR310_SMII0_IRQ_MASK (1 << 0)
+#define SPEAR310_SMII1_IRQ_MASK (1 << 1)
+#define SPEAR310_SMII2_IRQ_MASK (1 << 2)
+#define SPEAR310_SMII3_IRQ_MASK (1 << 3)
+#define SPEAR310_WAKEUP_SMII0_IRQ_MASK (1 << 4)
+#define SPEAR310_WAKEUP_SMII1_IRQ_MASK (1 << 5)
+#define SPEAR310_WAKEUP_SMII2_IRQ_MASK (1 << 6)
+#define SPEAR310_WAKEUP_SMII3_IRQ_MASK (1 << 7)
+#define SPEAR310_UART1_IRQ_MASK (1 << 8)
+#define SPEAR310_UART2_IRQ_MASK (1 << 9)
+#define SPEAR310_UART3_IRQ_MASK (1 << 10)
+#define SPEAR310_UART4_IRQ_MASK (1 << 11)
+#define SPEAR310_UART5_IRQ_MASK (1 << 12)
+#define SPEAR310_EMI_IRQ_MASK (1 << 13)
+#define SPEAR310_TDM_HDLC_IRQ_MASK (1 << 14)
+#define SPEAR310_RS485_0_IRQ_MASK (1 << 15)
+#define SPEAR310_RS485_1_IRQ_MASK (1 << 16)
-#define SHIRQ_RAS1_MASK 0x000FF
-#define SHIRQ_RAS2_MASK 0x01F00
-#define SHIRQ_RAS3_MASK 0x02000
-#define SHIRQ_INTRCOMM_RAS_MASK 0x1C000
+#define SPEAR310_SHIRQ_RAS1_MASK 0x000FF
+#define SPEAR310_SHIRQ_RAS2_MASK 0x01F00
+#define SPEAR310_SHIRQ_RAS3_MASK 0x02000
+#define SPEAR310_SHIRQ_INTRCOMM_RAS_MASK 0x1C000
#endif /* __MACH_SPEAR310_H */
diff --git a/arch/arm/mach-spear3xx/include/mach/spear320.h b/arch/arm/mach-spear3xx/include/mach/spear320.h
index 940f0d85d959..8cfa83fa1296 100644
--- a/arch/arm/mach-spear3xx/include/mach/spear320.h
+++ b/arch/arm/mach-spear3xx/include/mach/spear320.h
@@ -36,31 +36,31 @@
#define SPEAR320_SOC_CONFIG_BASE UL(0xB3000000)
/* Interrupt registers offsets and masks */
-#define INT_STS_MASK_REG 0x04
-#define INT_CLR_MASK_REG 0x04
-#define INT_ENB_MASK_REG 0x08
-#define GPIO_IRQ_MASK (1 << 0)
-#define I2S_PLAY_IRQ_MASK (1 << 1)
-#define I2S_REC_IRQ_MASK (1 << 2)
-#define EMI_IRQ_MASK (1 << 7)
-#define CLCD_IRQ_MASK (1 << 8)
-#define SPP_IRQ_MASK (1 << 9)
-#define SDHCI_IRQ_MASK (1 << 10)
-#define CAN_U_IRQ_MASK (1 << 11)
-#define CAN_L_IRQ_MASK (1 << 12)
-#define UART1_IRQ_MASK (1 << 13)
-#define UART2_IRQ_MASK (1 << 14)
-#define SSP1_IRQ_MASK (1 << 15)
-#define SSP2_IRQ_MASK (1 << 16)
-#define SMII0_IRQ_MASK (1 << 17)
-#define MII1_SMII1_IRQ_MASK (1 << 18)
-#define WAKEUP_SMII0_IRQ_MASK (1 << 19)
-#define WAKEUP_MII1_SMII1_IRQ_MASK (1 << 20)
-#define I2C1_IRQ_MASK (1 << 21)
+#define SPEAR320_INT_STS_MASK_REG 0x04
+#define SPEAR320_INT_CLR_MASK_REG 0x04
+#define SPEAR320_INT_ENB_MASK_REG 0x08
+#define SPEAR320_GPIO_IRQ_MASK (1 << 0)
+#define SPEAR320_I2S_PLAY_IRQ_MASK (1 << 1)
+#define SPEAR320_I2S_REC_IRQ_MASK (1 << 2)
+#define SPEAR320_EMI_IRQ_MASK (1 << 7)
+#define SPEAR320_CLCD_IRQ_MASK (1 << 8)
+#define SPEAR320_SPP_IRQ_MASK (1 << 9)
+#define SPEAR320_SDHCI_IRQ_MASK (1 << 10)
+#define SPEAR320_CAN_U_IRQ_MASK (1 << 11)
+#define SPEAR320_CAN_L_IRQ_MASK (1 << 12)
+#define SPEAR320_UART1_IRQ_MASK (1 << 13)
+#define SPEAR320_UART2_IRQ_MASK (1 << 14)
+#define SPEAR320_SSP1_IRQ_MASK (1 << 15)
+#define SPEAR320_SSP2_IRQ_MASK (1 << 16)
+#define SPEAR320_SMII0_IRQ_MASK (1 << 17)
+#define SPEAR320_MII1_SMII1_IRQ_MASK (1 << 18)
+#define SPEAR320_WAKEUP_SMII0_IRQ_MASK (1 << 19)
+#define SPEAR320_WAKEUP_MII1_SMII1_IRQ_MASK (1 << 20)
+#define SPEAR320_I2C1_IRQ_MASK (1 << 21)
-#define SHIRQ_RAS1_MASK 0x000380
-#define SHIRQ_RAS3_MASK 0x000007
-#define SHIRQ_INTRCOMM_RAS_MASK 0x3FF800
+#define SPEAR320_SHIRQ_RAS1_MASK 0x000380
+#define SPEAR320_SHIRQ_RAS3_MASK 0x000007
+#define SPEAR320_SHIRQ_INTRCOMM_RAS_MASK 0x3FF800
#endif /* __MACH_SPEAR320_H */
diff --git a/arch/arm/mach-spear3xx/spear300.c b/arch/arm/mach-spear3xx/spear300.c
index 2697e65adf86..a5e46b4ade20 100644
--- a/arch/arm/mach-spear3xx/spear300.c
+++ b/arch/arm/mach-spear3xx/spear300.c
@@ -40,86 +40,86 @@
#define CAML_LCD_MODE (1 << 12)
#define ALL_MODES 0x1FFF
-struct pmx_mode nand_mode = {
+struct pmx_mode spear300_nand_mode = {
.id = NAND_MODE,
.name = "nand mode",
.mask = 0x00,
};
-struct pmx_mode nor_mode = {
+struct pmx_mode spear300_nor_mode = {
.id = NOR_MODE,
.name = "nor mode",
.mask = 0x01,
};
-struct pmx_mode photo_frame_mode = {
+struct pmx_mode spear300_photo_frame_mode = {
.id = PHOTO_FRAME_MODE,
.name = "photo frame mode",
.mask = 0x02,
};
-struct pmx_mode lend_ip_phone_mode = {
+struct pmx_mode spear300_lend_ip_phone_mode = {
.id = LEND_IP_PHONE_MODE,
.name = "lend ip phone mode",
.mask = 0x03,
};
-struct pmx_mode hend_ip_phone_mode = {
+struct pmx_mode spear300_hend_ip_phone_mode = {
.id = HEND_IP_PHONE_MODE,
.name = "hend ip phone mode",
.mask = 0x04,
};
-struct pmx_mode lend_wifi_phone_mode = {
+struct pmx_mode spear300_lend_wifi_phone_mode = {
.id = LEND_WIFI_PHONE_MODE,
.name = "lend wifi phone mode",
.mask = 0x05,
};
-struct pmx_mode hend_wifi_phone_mode = {
+struct pmx_mode spear300_hend_wifi_phone_mode = {
.id = HEND_WIFI_PHONE_MODE,
.name = "hend wifi phone mode",
.mask = 0x06,
};
-struct pmx_mode ata_pabx_wi2s_mode = {
+struct pmx_mode spear300_ata_pabx_wi2s_mode = {
.id = ATA_PABX_WI2S_MODE,
.name = "ata pabx wi2s mode",
.mask = 0x07,
};
-struct pmx_mode ata_pabx_i2s_mode = {
+struct pmx_mode spear300_ata_pabx_i2s_mode = {
.id = ATA_PABX_I2S_MODE,
.name = "ata pabx i2s mode",
.mask = 0x08,
};
-struct pmx_mode caml_lcdw_mode = {
+struct pmx_mode spear300_caml_lcdw_mode = {
.id = CAML_LCDW_MODE,
.name = "caml lcdw mode",
.mask = 0x0C,
};
-struct pmx_mode camu_lcd_mode = {
+struct pmx_mode spear300_camu_lcd_mode = {
.id = CAMU_LCD_MODE,
.name = "camu lcd mode",
.mask = 0x0D,
};
-struct pmx_mode camu_wlcd_mode = {
+struct pmx_mode spear300_camu_wlcd_mode = {
.id = CAMU_WLCD_MODE,
.name = "camu wlcd mode",
.mask = 0x0E,
};
-struct pmx_mode caml_lcd_mode = {
+struct pmx_mode spear300_caml_lcd_mode = {
.id = CAML_LCD_MODE,
.name = "caml lcd mode",
.mask = 0x0F,
};
/* devices */
-struct pmx_dev_mode pmx_fsmc_2_chips_modes[] = {
+static struct pmx_dev_mode pmx_fsmc_2_chips_modes[] = {
{
.ids = NAND_MODE | NOR_MODE | PHOTO_FRAME_MODE |
ATA_PABX_WI2S_MODE | ATA_PABX_I2S_MODE,
@@ -127,14 +127,14 @@ struct pmx_dev_mode pmx_fsmc_2_chips_modes[] = {
},
};
-struct pmx_dev pmx_fsmc_2_chips = {
+struct pmx_dev spear300_pmx_fsmc_2_chips = {
.name = "fsmc_2_chips",
.modes = pmx_fsmc_2_chips_modes,
.mode_count = ARRAY_SIZE(pmx_fsmc_2_chips_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_fsmc_4_chips_modes[] = {
+static struct pmx_dev_mode pmx_fsmc_4_chips_modes[] = {
{
.ids = NAND_MODE | NOR_MODE | PHOTO_FRAME_MODE |
ATA_PABX_WI2S_MODE | ATA_PABX_I2S_MODE,
@@ -142,14 +142,14 @@ struct pmx_dev_mode pmx_fsmc_4_chips_modes[] = {
},
};
-struct pmx_dev pmx_fsmc_4_chips = {
+struct pmx_dev spear300_pmx_fsmc_4_chips = {
.name = "fsmc_4_chips",
.modes = pmx_fsmc_4_chips_modes,
.mode_count = ARRAY_SIZE(pmx_fsmc_4_chips_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_keyboard_modes[] = {
+static struct pmx_dev_mode pmx_keyboard_modes[] = {
{
.ids = LEND_IP_PHONE_MODE | HEND_IP_PHONE_MODE |
LEND_WIFI_PHONE_MODE | HEND_WIFI_PHONE_MODE |
@@ -159,14 +159,14 @@ struct pmx_dev_mode pmx_keyboard_modes[] = {
},
};
-struct pmx_dev pmx_keyboard = {
+struct pmx_dev spear300_pmx_keyboard = {
.name = "keyboard",
.modes = pmx_keyboard_modes,
.mode_count = ARRAY_SIZE(pmx_keyboard_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_clcd_modes[] = {
+static struct pmx_dev_mode pmx_clcd_modes[] = {
{
.ids = PHOTO_FRAME_MODE,
.mask = PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK ,
@@ -177,14 +177,14 @@ struct pmx_dev_mode pmx_clcd_modes[] = {
},
};
-struct pmx_dev pmx_clcd = {
+struct pmx_dev spear300_pmx_clcd = {
.name = "clcd",
.modes = pmx_clcd_modes,
.mode_count = ARRAY_SIZE(pmx_clcd_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_telecom_gpio_modes[] = {
+static struct pmx_dev_mode pmx_telecom_gpio_modes[] = {
{
.ids = PHOTO_FRAME_MODE | CAMU_LCD_MODE | CAML_LCD_MODE,
.mask = PMX_MII_MASK,
@@ -204,14 +204,14 @@ struct pmx_dev_mode pmx_telecom_gpio_modes[] = {
},
};
-struct pmx_dev pmx_telecom_gpio = {
+struct pmx_dev spear300_pmx_telecom_gpio = {
.name = "telecom_gpio",
.modes = pmx_telecom_gpio_modes,
.mode_count = ARRAY_SIZE(pmx_telecom_gpio_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_telecom_tdm_modes[] = {
+static struct pmx_dev_mode pmx_telecom_tdm_modes[] = {
{
.ids = PHOTO_FRAME_MODE | LEND_IP_PHONE_MODE |
HEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE
@@ -222,14 +222,14 @@ struct pmx_dev_mode pmx_telecom_tdm_modes[] = {
},
};
-struct pmx_dev pmx_telecom_tdm = {
+struct pmx_dev spear300_pmx_telecom_tdm = {
.name = "telecom_tdm",
.modes = pmx_telecom_tdm_modes,
.mode_count = ARRAY_SIZE(pmx_telecom_tdm_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_telecom_spi_cs_i2c_clk_modes[] = {
+static struct pmx_dev_mode pmx_telecom_spi_cs_i2c_clk_modes[] = {
{
.ids = LEND_IP_PHONE_MODE | HEND_IP_PHONE_MODE |
LEND_WIFI_PHONE_MODE | HEND_WIFI_PHONE_MODE
@@ -239,14 +239,14 @@ struct pmx_dev_mode pmx_telecom_spi_cs_i2c_clk_modes[] = {
},
};
-struct pmx_dev pmx_telecom_spi_cs_i2c_clk = {
+struct pmx_dev spear300_pmx_telecom_spi_cs_i2c_clk = {
.name = "telecom_spi_cs_i2c_clk",
.modes = pmx_telecom_spi_cs_i2c_clk_modes,
.mode_count = ARRAY_SIZE(pmx_telecom_spi_cs_i2c_clk_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_telecom_camera_modes[] = {
+static struct pmx_dev_mode pmx_telecom_camera_modes[] = {
{
.ids = CAML_LCDW_MODE | CAML_LCD_MODE,
.mask = PMX_MII_MASK,
@@ -256,14 +256,14 @@ struct pmx_dev_mode pmx_telecom_camera_modes[] = {
},
};
-struct pmx_dev pmx_telecom_camera = {
+struct pmx_dev spear300_pmx_telecom_camera = {
.name = "telecom_camera",
.modes = pmx_telecom_camera_modes,
.mode_count = ARRAY_SIZE(pmx_telecom_camera_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_telecom_dac_modes[] = {
+static struct pmx_dev_mode pmx_telecom_dac_modes[] = {
{
.ids = ATA_PABX_I2S_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE
| CAMU_WLCD_MODE | CAML_LCD_MODE,
@@ -271,14 +271,14 @@ struct pmx_dev_mode pmx_telecom_dac_modes[] = {
},
};
-struct pmx_dev pmx_telecom_dac = {
+struct pmx_dev spear300_pmx_telecom_dac = {
.name = "telecom_dac",
.modes = pmx_telecom_dac_modes,
.mode_count = ARRAY_SIZE(pmx_telecom_dac_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_telecom_i2s_modes[] = {
+static struct pmx_dev_mode pmx_telecom_i2s_modes[] = {
{
.ids = LEND_IP_PHONE_MODE | HEND_IP_PHONE_MODE
| LEND_WIFI_PHONE_MODE | HEND_WIFI_PHONE_MODE |
@@ -288,14 +288,14 @@ struct pmx_dev_mode pmx_telecom_i2s_modes[] = {
},
};
-struct pmx_dev pmx_telecom_i2s = {
+struct pmx_dev spear300_pmx_telecom_i2s = {
.name = "telecom_i2s",
.modes = pmx_telecom_i2s_modes,
.mode_count = ARRAY_SIZE(pmx_telecom_i2s_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_telecom_boot_pins_modes[] = {
+static struct pmx_dev_mode pmx_telecom_boot_pins_modes[] = {
{
.ids = NAND_MODE | NOR_MODE,
.mask = PMX_UART0_MODEM_MASK | PMX_TIMER_1_2_MASK |
@@ -303,14 +303,14 @@ struct pmx_dev_mode pmx_telecom_boot_pins_modes[] = {
},
};
-struct pmx_dev pmx_telecom_boot_pins = {
+struct pmx_dev spear300_pmx_telecom_boot_pins = {
.name = "telecom_boot_pins",
.modes = pmx_telecom_boot_pins_modes,
.mode_count = ARRAY_SIZE(pmx_telecom_boot_pins_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_telecom_sdhci_4bit_modes[] = {
+static struct pmx_dev_mode pmx_telecom_sdhci_4bit_modes[] = {
{
.ids = PHOTO_FRAME_MODE | LEND_IP_PHONE_MODE |
HEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE |
@@ -323,14 +323,14 @@ struct pmx_dev_mode pmx_telecom_sdhci_4bit_modes[] = {
},
};
-struct pmx_dev pmx_telecom_sdhci_4bit = {
+struct pmx_dev spear300_pmx_telecom_sdhci_4bit = {
.name = "telecom_sdhci_4bit",
.modes = pmx_telecom_sdhci_4bit_modes,
.mode_count = ARRAY_SIZE(pmx_telecom_sdhci_4bit_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_telecom_sdhci_8bit_modes[] = {
+static struct pmx_dev_mode pmx_telecom_sdhci_8bit_modes[] = {
{
.ids = PHOTO_FRAME_MODE | LEND_IP_PHONE_MODE |
HEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE |
@@ -342,14 +342,14 @@ struct pmx_dev_mode pmx_telecom_sdhci_8bit_modes[] = {
},
};
-struct pmx_dev pmx_telecom_sdhci_8bit = {
+struct pmx_dev spear300_pmx_telecom_sdhci_8bit = {
.name = "telecom_sdhci_8bit",
.modes = pmx_telecom_sdhci_8bit_modes,
.mode_count = ARRAY_SIZE(pmx_telecom_sdhci_8bit_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_gpio1_modes[] = {
+static struct pmx_dev_mode pmx_gpio1_modes[] = {
{
.ids = PHOTO_FRAME_MODE,
.mask = PMX_UART0_MODEM_MASK | PMX_TIMER_1_2_MASK |
@@ -357,7 +357,7 @@ struct pmx_dev_mode pmx_gpio1_modes[] = {
},
};
-struct pmx_dev pmx_gpio1 = {
+struct pmx_dev spear300_pmx_gpio1 = {
.name = "arm gpio1",
.modes = pmx_gpio1_modes,
.mode_count = ARRAY_SIZE(pmx_gpio1_modes),
@@ -365,60 +365,60 @@ struct pmx_dev pmx_gpio1 = {
};
/* pmx driver structure */
-struct pmx_driver pmx_driver = {
+static struct pmx_driver pmx_driver = {
.mode_reg = {.offset = MODE_CONFIG_REG, .mask = 0x0000000f},
.mux_reg = {.offset = PAD_MUX_CONFIG_REG, .mask = 0x00007fff},
};
/* spear3xx shared irq */
-struct shirq_dev_config shirq_ras1_config[] = {
+static struct shirq_dev_config shirq_ras1_config[] = {
{
- .virq = VIRQ_IT_PERS_S,
- .enb_mask = IT_PERS_S_IRQ_MASK,
- .status_mask = IT_PERS_S_IRQ_MASK,
+ .virq = SPEAR300_VIRQ_IT_PERS_S,
+ .enb_mask = SPEAR300_IT_PERS_S_IRQ_MASK,
+ .status_mask = SPEAR300_IT_PERS_S_IRQ_MASK,
}, {
- .virq = VIRQ_IT_CHANGE_S,
- .enb_mask = IT_CHANGE_S_IRQ_MASK,
- .status_mask = IT_CHANGE_S_IRQ_MASK,
+ .virq = SPEAR300_VIRQ_IT_CHANGE_S,
+ .enb_mask = SPEAR300_IT_CHANGE_S_IRQ_MASK,
+ .status_mask = SPEAR300_IT_CHANGE_S_IRQ_MASK,
}, {
- .virq = VIRQ_I2S,
- .enb_mask = I2S_IRQ_MASK,
- .status_mask = I2S_IRQ_MASK,
+ .virq = SPEAR300_VIRQ_I2S,
+ .enb_mask = SPEAR300_I2S_IRQ_MASK,
+ .status_mask = SPEAR300_I2S_IRQ_MASK,
}, {
- .virq = VIRQ_TDM,
- .enb_mask = TDM_IRQ_MASK,
- .status_mask = TDM_IRQ_MASK,
+ .virq = SPEAR300_VIRQ_TDM,
+ .enb_mask = SPEAR300_TDM_IRQ_MASK,
+ .status_mask = SPEAR300_TDM_IRQ_MASK,
}, {
- .virq = VIRQ_CAMERA_L,
- .enb_mask = CAMERA_L_IRQ_MASK,
- .status_mask = CAMERA_L_IRQ_MASK,
+ .virq = SPEAR300_VIRQ_CAMERA_L,
+ .enb_mask = SPEAR300_CAMERA_L_IRQ_MASK,
+ .status_mask = SPEAR300_CAMERA_L_IRQ_MASK,
}, {
- .virq = VIRQ_CAMERA_F,
- .enb_mask = CAMERA_F_IRQ_MASK,
- .status_mask = CAMERA_F_IRQ_MASK,
+ .virq = SPEAR300_VIRQ_CAMERA_F,
+ .enb_mask = SPEAR300_CAMERA_F_IRQ_MASK,
+ .status_mask = SPEAR300_CAMERA_F_IRQ_MASK,
}, {
- .virq = VIRQ_CAMERA_V,
- .enb_mask = CAMERA_V_IRQ_MASK,
- .status_mask = CAMERA_V_IRQ_MASK,
+ .virq = SPEAR300_VIRQ_CAMERA_V,
+ .enb_mask = SPEAR300_CAMERA_V_IRQ_MASK,
+ .status_mask = SPEAR300_CAMERA_V_IRQ_MASK,
}, {
- .virq = VIRQ_KEYBOARD,
- .enb_mask = KEYBOARD_IRQ_MASK,
- .status_mask = KEYBOARD_IRQ_MASK,
+ .virq = SPEAR300_VIRQ_KEYBOARD,
+ .enb_mask = SPEAR300_KEYBOARD_IRQ_MASK,
+ .status_mask = SPEAR300_KEYBOARD_IRQ_MASK,
}, {
- .virq = VIRQ_GPIO1,
- .enb_mask = GPIO1_IRQ_MASK,
- .status_mask = GPIO1_IRQ_MASK,
+ .virq = SPEAR300_VIRQ_GPIO1,
+ .enb_mask = SPEAR300_GPIO1_IRQ_MASK,
+ .status_mask = SPEAR300_GPIO1_IRQ_MASK,
},
};
-struct spear_shirq shirq_ras1 = {
- .irq = IRQ_GEN_RAS_1,
+static struct spear_shirq shirq_ras1 = {
+ .irq = SPEAR3XX_IRQ_GEN_RAS_1,
.dev_config = shirq_ras1_config,
.dev_count = ARRAY_SIZE(shirq_ras1_config),
.regs = {
- .enb_reg = INT_ENB_MASK_REG,
- .status_reg = INT_STS_MASK_REG,
- .status_reg_mask = SHIRQ_RAS1_MASK,
+ .enb_reg = SPEAR300_INT_ENB_MASK_REG,
+ .status_reg = SPEAR300_INT_STS_MASK_REG,
+ .status_reg_mask = SPEAR300_SHIRQ_RAS1_MASK,
.clear_reg = -1,
},
};
@@ -427,10 +427,10 @@ struct spear_shirq shirq_ras1 = {
/* arm gpio1 device registration */
static struct pl061_platform_data gpio1_plat_data = {
.gpio_base = 8,
- .irq_base = SPEAR_GPIO1_INT_BASE,
+ .irq_base = SPEAR300_GPIO1_INT_BASE,
};
-struct amba_device gpio1_device = {
+struct amba_device spear300_gpio1_device = {
.dev = {
.init_name = "gpio1",
.platform_data = &gpio1_plat_data,
@@ -440,11 +440,12 @@ struct amba_device gpio1_device = {
.end = SPEAR300_GPIO_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
- .irq = {VIRQ_GPIO1, NO_IRQ},
+ .irq = {SPEAR300_VIRQ_GPIO1, NO_IRQ},
};
/* spear300 routines */
-void __init spear300_init(void)
+void __init spear300_init(struct pmx_mode *pmx_mode, struct pmx_dev **pmx_devs,
+ u8 pmx_dev_count)
{
int ret = 0;
@@ -460,6 +461,10 @@ void __init spear300_init(void)
}
/* pmx initialization */
+ pmx_driver.mode = pmx_mode;
+ pmx_driver.devs = pmx_devs;
+ pmx_driver.devs_count = pmx_dev_count;
+
pmx_driver.base = ioremap(SPEAR300_SOC_CONFIG_BASE, SZ_4K);
if (pmx_driver.base) {
ret = pmx_register(&pmx_driver);
diff --git a/arch/arm/mach-spear3xx/spear300_evb.c b/arch/arm/mach-spear3xx/spear300_evb.c
index 42d2253ef540..69006f694220 100644
--- a/arch/arm/mach-spear3xx/spear300_evb.c
+++ b/arch/arm/mach-spear3xx/spear300_evb.c
@@ -19,26 +19,26 @@
/* padmux devices to enable */
static struct pmx_dev *pmx_devs[] = {
/* spear3xx specific devices */
- &pmx_i2c,
- &pmx_ssp_cs,
- &pmx_ssp,
- &pmx_mii,
- &pmx_uart0,
+ &spear3xx_pmx_i2c,
+ &spear3xx_pmx_ssp_cs,
+ &spear3xx_pmx_ssp,
+ &spear3xx_pmx_mii,
+ &spear3xx_pmx_uart0,
/* spear300 specific devices */
- &pmx_fsmc_2_chips,
- &pmx_clcd,
- &pmx_telecom_sdhci_4bit,
- &pmx_gpio1,
+ &spear300_pmx_fsmc_2_chips,
+ &spear300_pmx_clcd,
+ &spear300_pmx_telecom_sdhci_4bit,
+ &spear300_pmx_gpio1,
};
static struct amba_device *amba_devs[] __initdata = {
/* spear3xx specific devices */
- &gpio_device,
- &uart_device,
+ &spear3xx_gpio_device,
+ &spear3xx_uart_device,
/* spear300 specific devices */
- &gpio1_device,
+ &spear300_gpio1_device,
};
static struct platform_device *plat_devs[] __initdata = {
@@ -51,13 +51,9 @@ static void __init spear300_evb_init(void)
{
unsigned int i;
- /* padmux initialization, must be done before spear300_init */
- pmx_driver.mode = &photo_frame_mode;
- pmx_driver.devs = pmx_devs;
- pmx_driver.devs_count = ARRAY_SIZE(pmx_devs);
-
/* call spear300 machine init function */
- spear300_init();
+ spear300_init(&spear300_photo_frame_mode, pmx_devs,
+ ARRAY_SIZE(pmx_devs));
/* Add Platform Devices */
platform_add_devices(plat_devs, ARRAY_SIZE(plat_devs));
diff --git a/arch/arm/mach-spear3xx/spear310.c b/arch/arm/mach-spear3xx/spear310.c
index 5c0a67b60c2a..9004cf9f01bf 100644
--- a/arch/arm/mach-spear3xx/spear310.c
+++ b/arch/arm/mach-spear3xx/spear310.c
@@ -22,112 +22,112 @@
#define PAD_MUX_CONFIG_REG 0x08
/* devices */
-struct pmx_dev_mode pmx_emi_cs_0_1_4_5_modes[] = {
+static struct pmx_dev_mode pmx_emi_cs_0_1_4_5_modes[] = {
{
.ids = 0x00,
.mask = PMX_TIMER_3_4_MASK,
},
};
-struct pmx_dev pmx_emi_cs_0_1_4_5 = {
+struct pmx_dev spear310_pmx_emi_cs_0_1_4_5 = {
.name = "emi_cs_0_1_4_5",
.modes = pmx_emi_cs_0_1_4_5_modes,
.mode_count = ARRAY_SIZE(pmx_emi_cs_0_1_4_5_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_emi_cs_2_3_modes[] = {
+static struct pmx_dev_mode pmx_emi_cs_2_3_modes[] = {
{
.ids = 0x00,
.mask = PMX_TIMER_1_2_MASK,
},
};
-struct pmx_dev pmx_emi_cs_2_3 = {
+struct pmx_dev spear310_pmx_emi_cs_2_3 = {
.name = "emi_cs_2_3",
.modes = pmx_emi_cs_2_3_modes,
.mode_count = ARRAY_SIZE(pmx_emi_cs_2_3_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_uart1_modes[] = {
+static struct pmx_dev_mode pmx_uart1_modes[] = {
{
.ids = 0x00,
.mask = PMX_FIRDA_MASK,
},
};
-struct pmx_dev pmx_uart1 = {
+struct pmx_dev spear310_pmx_uart1 = {
.name = "uart1",
.modes = pmx_uart1_modes,
.mode_count = ARRAY_SIZE(pmx_uart1_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_uart2_modes[] = {
+static struct pmx_dev_mode pmx_uart2_modes[] = {
{
.ids = 0x00,
.mask = PMX_TIMER_1_2_MASK,
},
};
-struct pmx_dev pmx_uart2 = {
+struct pmx_dev spear310_pmx_uart2 = {
.name = "uart2",
.modes = pmx_uart2_modes,
.mode_count = ARRAY_SIZE(pmx_uart2_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_uart3_4_5_modes[] = {
+static struct pmx_dev_mode pmx_uart3_4_5_modes[] = {
{
.ids = 0x00,
.mask = PMX_UART0_MODEM_MASK,
},
};
-struct pmx_dev pmx_uart3_4_5 = {
+struct pmx_dev spear310_pmx_uart3_4_5 = {
.name = "uart3_4_5",
.modes = pmx_uart3_4_5_modes,
.mode_count = ARRAY_SIZE(pmx_uart3_4_5_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_fsmc_modes[] = {
+static struct pmx_dev_mode pmx_fsmc_modes[] = {
{
.ids = 0x00,
.mask = PMX_SSP_CS_MASK,
},
};
-struct pmx_dev pmx_fsmc = {
+struct pmx_dev spear310_pmx_fsmc = {
.name = "fsmc",
.modes = pmx_fsmc_modes,
.mode_count = ARRAY_SIZE(pmx_fsmc_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_rs485_0_1_modes[] = {
+static struct pmx_dev_mode pmx_rs485_0_1_modes[] = {
{
.ids = 0x00,
.mask = PMX_MII_MASK,
},
};
-struct pmx_dev pmx_rs485_0_1 = {
+struct pmx_dev spear310_pmx_rs485_0_1 = {
.name = "rs485_0_1",
.modes = pmx_rs485_0_1_modes,
.mode_count = ARRAY_SIZE(pmx_rs485_0_1_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_tdm0_modes[] = {
+static struct pmx_dev_mode pmx_tdm0_modes[] = {
{
.ids = 0x00,
.mask = PMX_MII_MASK,
},
};
-struct pmx_dev pmx_tdm0 = {
+struct pmx_dev spear310_pmx_tdm0 = {
.name = "tdm0",
.modes = pmx_tdm0_modes,
.mode_count = ARRAY_SIZE(pmx_tdm0_modes),
@@ -135,122 +135,122 @@ struct pmx_dev pmx_tdm0 = {
};
/* pmx driver structure */
-struct pmx_driver pmx_driver = {
+static struct pmx_driver pmx_driver = {
.mux_reg = {.offset = PAD_MUX_CONFIG_REG, .mask = 0x00007fff},
};
/* spear3xx shared irq */
-struct shirq_dev_config shirq_ras1_config[] = {
+static struct shirq_dev_config shirq_ras1_config[] = {
{
- .virq = VIRQ_SMII0,
- .status_mask = SMII0_IRQ_MASK,
+ .virq = SPEAR310_VIRQ_SMII0,
+ .status_mask = SPEAR310_SMII0_IRQ_MASK,
}, {
- .virq = VIRQ_SMII1,
- .status_mask = SMII1_IRQ_MASK,
+ .virq = SPEAR310_VIRQ_SMII1,
+ .status_mask = SPEAR310_SMII1_IRQ_MASK,
}, {
- .virq = VIRQ_SMII2,
- .status_mask = SMII2_IRQ_MASK,
+ .virq = SPEAR310_VIRQ_SMII2,
+ .status_mask = SPEAR310_SMII2_IRQ_MASK,
}, {
- .virq = VIRQ_SMII3,
- .status_mask = SMII3_IRQ_MASK,
+ .virq = SPEAR310_VIRQ_SMII3,
+ .status_mask = SPEAR310_SMII3_IRQ_MASK,
}, {
- .virq = VIRQ_WAKEUP_SMII0,
- .status_mask = WAKEUP_SMII0_IRQ_MASK,
+ .virq = SPEAR310_VIRQ_WAKEUP_SMII0,
+ .status_mask = SPEAR310_WAKEUP_SMII0_IRQ_MASK,
}, {
- .virq = VIRQ_WAKEUP_SMII1,
- .status_mask = WAKEUP_SMII1_IRQ_MASK,
+ .virq = SPEAR310_VIRQ_WAKEUP_SMII1,
+ .status_mask = SPEAR310_WAKEUP_SMII1_IRQ_MASK,
}, {
- .virq = VIRQ_WAKEUP_SMII2,
- .status_mask = WAKEUP_SMII2_IRQ_MASK,
+ .virq = SPEAR310_VIRQ_WAKEUP_SMII2,
+ .status_mask = SPEAR310_WAKEUP_SMII2_IRQ_MASK,
}, {
- .virq = VIRQ_WAKEUP_SMII3,
- .status_mask = WAKEUP_SMII3_IRQ_MASK,
+ .virq = SPEAR310_VIRQ_WAKEUP_SMII3,
+ .status_mask = SPEAR310_WAKEUP_SMII3_IRQ_MASK,
},
};
-struct spear_shirq shirq_ras1 = {
- .irq = IRQ_GEN_RAS_1,
+static struct spear_shirq shirq_ras1 = {
+ .irq = SPEAR3XX_IRQ_GEN_RAS_1,
.dev_config = shirq_ras1_config,
.dev_count = ARRAY_SIZE(shirq_ras1_config),
.regs = {
.enb_reg = -1,
- .status_reg = INT_STS_MASK_REG,
- .status_reg_mask = SHIRQ_RAS1_MASK,
+ .status_reg = SPEAR310_INT_STS_MASK_REG,
+ .status_reg_mask = SPEAR310_SHIRQ_RAS1_MASK,
.clear_reg = -1,
},
};
-struct shirq_dev_config shirq_ras2_config[] = {
+static struct shirq_dev_config shirq_ras2_config[] = {
{
- .virq = VIRQ_UART1,
- .status_mask = UART1_IRQ_MASK,
+ .virq = SPEAR310_VIRQ_UART1,
+ .status_mask = SPEAR310_UART1_IRQ_MASK,
}, {
- .virq = VIRQ_UART2,
- .status_mask = UART2_IRQ_MASK,
+ .virq = SPEAR310_VIRQ_UART2,
+ .status_mask = SPEAR310_UART2_IRQ_MASK,
}, {
- .virq = VIRQ_UART3,
- .status_mask = UART3_IRQ_MASK,
+ .virq = SPEAR310_VIRQ_UART3,
+ .status_mask = SPEAR310_UART3_IRQ_MASK,
}, {
- .virq = VIRQ_UART4,
- .status_mask = UART4_IRQ_MASK,
+ .virq = SPEAR310_VIRQ_UART4,
+ .status_mask = SPEAR310_UART4_IRQ_MASK,
}, {
- .virq = VIRQ_UART5,
- .status_mask = UART5_IRQ_MASK,
+ .virq = SPEAR310_VIRQ_UART5,
+ .status_mask = SPEAR310_UART5_IRQ_MASK,
},
};
-struct spear_shirq shirq_ras2 = {
- .irq = IRQ_GEN_RAS_2,
+static struct spear_shirq shirq_ras2 = {
+ .irq = SPEAR3XX_IRQ_GEN_RAS_2,
.dev_config = shirq_ras2_config,
.dev_count = ARRAY_SIZE(shirq_ras2_config),
.regs = {
.enb_reg = -1,
- .status_reg = INT_STS_MASK_REG,
- .status_reg_mask = SHIRQ_RAS2_MASK,
+ .status_reg = SPEAR310_INT_STS_MASK_REG,
+ .status_reg_mask = SPEAR310_SHIRQ_RAS2_MASK,
.clear_reg = -1,
},
};
-struct shirq_dev_config shirq_ras3_config[] = {
+static struct shirq_dev_config shirq_ras3_config[] = {
{
- .virq = VIRQ_EMI,
- .status_mask = EMI_IRQ_MASK,
+ .virq = SPEAR310_VIRQ_EMI,
+ .status_mask = SPEAR310_EMI_IRQ_MASK,
},
};
-struct spear_shirq shirq_ras3 = {
- .irq = IRQ_GEN_RAS_3,
+static struct spear_shirq shirq_ras3 = {
+ .irq = SPEAR3XX_IRQ_GEN_RAS_3,
.dev_config = shirq_ras3_config,
.dev_count = ARRAY_SIZE(shirq_ras3_config),
.regs = {
.enb_reg = -1,
- .status_reg = INT_STS_MASK_REG,
- .status_reg_mask = SHIRQ_RAS3_MASK,
+ .status_reg = SPEAR310_INT_STS_MASK_REG,
+ .status_reg_mask = SPEAR310_SHIRQ_RAS3_MASK,
.clear_reg = -1,
},
};
-struct shirq_dev_config shirq_intrcomm_ras_config[] = {
+static struct shirq_dev_config shirq_intrcomm_ras_config[] = {
{
- .virq = VIRQ_TDM_HDLC,
- .status_mask = TDM_HDLC_IRQ_MASK,
+ .virq = SPEAR310_VIRQ_TDM_HDLC,
+ .status_mask = SPEAR310_TDM_HDLC_IRQ_MASK,
}, {
- .virq = VIRQ_RS485_0,
- .status_mask = RS485_0_IRQ_MASK,
+ .virq = SPEAR310_VIRQ_RS485_0,
+ .status_mask = SPEAR310_RS485_0_IRQ_MASK,
}, {
- .virq = VIRQ_RS485_1,
- .status_mask = RS485_1_IRQ_MASK,
+ .virq = SPEAR310_VIRQ_RS485_1,
+ .status_mask = SPEAR310_RS485_1_IRQ_MASK,
},
};
-struct spear_shirq shirq_intrcomm_ras = {
- .irq = IRQ_INTRCOMM_RAS_ARM,
+static struct spear_shirq shirq_intrcomm_ras = {
+ .irq = SPEAR3XX_IRQ_INTRCOMM_RAS_ARM,
.dev_config = shirq_intrcomm_ras_config,
.dev_count = ARRAY_SIZE(shirq_intrcomm_ras_config),
.regs = {
.enb_reg = -1,
- .status_reg = INT_STS_MASK_REG,
- .status_reg_mask = SHIRQ_INTRCOMM_RAS_MASK,
+ .status_reg = SPEAR310_INT_STS_MASK_REG,
+ .status_reg_mask = SPEAR310_SHIRQ_INTRCOMM_RAS_MASK,
.clear_reg = -1,
},
};
@@ -258,7 +258,8 @@ struct spear_shirq shirq_intrcomm_ras = {
/* Add spear310 specific devices here */
/* spear310 routines */
-void __init spear310_init(void)
+void __init spear310_init(struct pmx_mode *pmx_mode, struct pmx_dev **pmx_devs,
+ u8 pmx_dev_count)
{
void __iomem *base;
int ret = 0;
@@ -296,6 +297,10 @@ void __init spear310_init(void)
/* pmx initialization */
pmx_driver.base = base;
+ pmx_driver.mode = pmx_mode;
+ pmx_driver.devs = pmx_devs;
+ pmx_driver.devs_count = pmx_dev_count;
+
ret = pmx_register(&pmx_driver);
if (ret)
printk(KERN_ERR "padmux: registeration failed. err no: %d\n",
diff --git a/arch/arm/mach-spear3xx/spear310_evb.c b/arch/arm/mach-spear3xx/spear310_evb.c
index 2d7f333bd67b..c8684ce1f9b3 100644
--- a/arch/arm/mach-spear3xx/spear310_evb.c
+++ b/arch/arm/mach-spear3xx/spear310_evb.c
@@ -19,31 +19,31 @@
/* padmux devices to enable */
static struct pmx_dev *pmx_devs[] = {
/* spear3xx specific devices */
- &pmx_i2c,
- &pmx_ssp,
- &pmx_gpio_pin0,
- &pmx_gpio_pin1,
- &pmx_gpio_pin2,
- &pmx_gpio_pin3,
- &pmx_gpio_pin4,
- &pmx_gpio_pin5,
- &pmx_uart0,
+ &spear3xx_pmx_i2c,
+ &spear3xx_pmx_ssp,
+ &spear3xx_pmx_gpio_pin0,
+ &spear3xx_pmx_gpio_pin1,
+ &spear3xx_pmx_gpio_pin2,
+ &spear3xx_pmx_gpio_pin3,
+ &spear3xx_pmx_gpio_pin4,
+ &spear3xx_pmx_gpio_pin5,
+ &spear3xx_pmx_uart0,
/* spear310 specific devices */
- &pmx_emi_cs_0_1_4_5,
- &pmx_emi_cs_2_3,
- &pmx_uart1,
- &pmx_uart2,
- &pmx_uart3_4_5,
- &pmx_fsmc,
- &pmx_rs485_0_1,
- &pmx_tdm0,
+ &spear310_pmx_emi_cs_0_1_4_5,
+ &spear310_pmx_emi_cs_2_3,
+ &spear310_pmx_uart1,
+ &spear310_pmx_uart2,
+ &spear310_pmx_uart3_4_5,
+ &spear310_pmx_fsmc,
+ &spear310_pmx_rs485_0_1,
+ &spear310_pmx_tdm0,
};
static struct amba_device *amba_devs[] __initdata = {
/* spear3xx specific devices */
- &gpio_device,
- &uart_device,
+ &spear3xx_gpio_device,
+ &spear3xx_uart_device,
/* spear310 specific devices */
};
@@ -58,13 +58,8 @@ static void __init spear310_evb_init(void)
{
unsigned int i;
- /* padmux initialization, must be done before spear310_init */
- pmx_driver.mode = NULL;
- pmx_driver.devs = pmx_devs;
- pmx_driver.devs_count = ARRAY_SIZE(pmx_devs);
-
/* call spear310 machine init function */
- spear310_init();
+ spear310_init(NULL, pmx_devs, ARRAY_SIZE(pmx_devs));
/* Add Platform Devices */
platform_add_devices(plat_devs, ARRAY_SIZE(plat_devs));
diff --git a/arch/arm/mach-spear3xx/spear320.c b/arch/arm/mach-spear3xx/spear320.c
index 741c1f414cbd..ee29bef43074 100644
--- a/arch/arm/mach-spear3xx/spear320.c
+++ b/arch/arm/mach-spear3xx/spear320.c
@@ -29,88 +29,88 @@
#define SMALL_PRINTERS_MODE (1 << 3)
#define ALL_MODES 0xF
-struct pmx_mode auto_net_smii_mode = {
+struct pmx_mode spear320_auto_net_smii_mode = {
.id = AUTO_NET_SMII_MODE,
.name = "Automation Networking SMII Mode",
.mask = 0x00,
};
-struct pmx_mode auto_net_mii_mode = {
+struct pmx_mode spear320_auto_net_mii_mode = {
.id = AUTO_NET_MII_MODE,
.name = "Automation Networking MII Mode",
.mask = 0x01,
};
-struct pmx_mode auto_exp_mode = {
+struct pmx_mode spear320_auto_exp_mode = {
.id = AUTO_EXP_MODE,
.name = "Automation Expanded Mode",
.mask = 0x02,
};
-struct pmx_mode small_printers_mode = {
+struct pmx_mode spear320_small_printers_mode = {
.id = SMALL_PRINTERS_MODE,
.name = "Small Printers Mode",
.mask = 0x03,
};
/* devices */
-struct pmx_dev_mode pmx_clcd_modes[] = {
+static struct pmx_dev_mode pmx_clcd_modes[] = {
{
.ids = AUTO_NET_SMII_MODE,
.mask = 0x0,
},
};
-struct pmx_dev pmx_clcd = {
+struct pmx_dev spear320_pmx_clcd = {
.name = "clcd",
.modes = pmx_clcd_modes,
.mode_count = ARRAY_SIZE(pmx_clcd_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_emi_modes[] = {
+static struct pmx_dev_mode pmx_emi_modes[] = {
{
.ids = AUTO_EXP_MODE,
.mask = PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK,
},
};
-struct pmx_dev pmx_emi = {
+struct pmx_dev spear320_pmx_emi = {
.name = "emi",
.modes = pmx_emi_modes,
.mode_count = ARRAY_SIZE(pmx_emi_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_fsmc_modes[] = {
+static struct pmx_dev_mode pmx_fsmc_modes[] = {
{
.ids = ALL_MODES,
.mask = 0x0,
},
};
-struct pmx_dev pmx_fsmc = {
+struct pmx_dev spear320_pmx_fsmc = {
.name = "fsmc",
.modes = pmx_fsmc_modes,
.mode_count = ARRAY_SIZE(pmx_fsmc_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_spp_modes[] = {
+static struct pmx_dev_mode pmx_spp_modes[] = {
{
.ids = SMALL_PRINTERS_MODE,
.mask = 0x0,
},
};
-struct pmx_dev pmx_spp = {
+struct pmx_dev spear320_pmx_spp = {
.name = "spp",
.modes = pmx_spp_modes,
.mode_count = ARRAY_SIZE(pmx_spp_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_sdhci_modes[] = {
+static struct pmx_dev_mode pmx_sdhci_modes[] = {
{
.ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE |
SMALL_PRINTERS_MODE,
@@ -118,42 +118,42 @@ struct pmx_dev_mode pmx_sdhci_modes[] = {
},
};
-struct pmx_dev pmx_sdhci = {
+struct pmx_dev spear320_pmx_sdhci = {
.name = "sdhci",
.modes = pmx_sdhci_modes,
.mode_count = ARRAY_SIZE(pmx_sdhci_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_i2s_modes[] = {
+static struct pmx_dev_mode pmx_i2s_modes[] = {
{
.ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE,
.mask = PMX_UART0_MODEM_MASK,
},
};
-struct pmx_dev pmx_i2s = {
+struct pmx_dev spear320_pmx_i2s = {
.name = "i2s",
.modes = pmx_i2s_modes,
.mode_count = ARRAY_SIZE(pmx_i2s_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_uart1_modes[] = {
+static struct pmx_dev_mode pmx_uart1_modes[] = {
{
.ids = ALL_MODES,
.mask = PMX_GPIO_PIN0_MASK | PMX_GPIO_PIN1_MASK,
},
};
-struct pmx_dev pmx_uart1 = {
+struct pmx_dev spear320_pmx_uart1 = {
.name = "uart1",
.modes = pmx_uart1_modes,
.mode_count = ARRAY_SIZE(pmx_uart1_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_uart1_modem_modes[] = {
+static struct pmx_dev_mode pmx_uart1_modem_modes[] = {
{
.ids = AUTO_EXP_MODE,
.mask = PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK |
@@ -165,42 +165,42 @@ struct pmx_dev_mode pmx_uart1_modem_modes[] = {
},
};
-struct pmx_dev pmx_uart1_modem = {
+struct pmx_dev spear320_pmx_uart1_modem = {
.name = "uart1_modem",
.modes = pmx_uart1_modem_modes,
.mode_count = ARRAY_SIZE(pmx_uart1_modem_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_uart2_modes[] = {
+static struct pmx_dev_mode pmx_uart2_modes[] = {
{
.ids = ALL_MODES,
.mask = PMX_FIRDA_MASK,
},
};
-struct pmx_dev pmx_uart2 = {
+struct pmx_dev spear320_pmx_uart2 = {
.name = "uart2",
.modes = pmx_uart2_modes,
.mode_count = ARRAY_SIZE(pmx_uart2_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_touchscreen_modes[] = {
+static struct pmx_dev_mode pmx_touchscreen_modes[] = {
{
.ids = AUTO_NET_SMII_MODE,
.mask = PMX_SSP_CS_MASK,
},
};
-struct pmx_dev pmx_touchscreen = {
+struct pmx_dev spear320_pmx_touchscreen = {
.name = "touchscreen",
.modes = pmx_touchscreen_modes,
.mode_count = ARRAY_SIZE(pmx_touchscreen_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_can_modes[] = {
+static struct pmx_dev_mode pmx_can_modes[] = {
{
.ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | AUTO_EXP_MODE,
.mask = PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK |
@@ -208,28 +208,28 @@ struct pmx_dev_mode pmx_can_modes[] = {
},
};
-struct pmx_dev pmx_can = {
+struct pmx_dev spear320_pmx_can = {
.name = "can",
.modes = pmx_can_modes,
.mode_count = ARRAY_SIZE(pmx_can_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_sdhci_led_modes[] = {
+static struct pmx_dev_mode pmx_sdhci_led_modes[] = {
{
.ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE,
.mask = PMX_SSP_CS_MASK,
},
};
-struct pmx_dev pmx_sdhci_led = {
+struct pmx_dev spear320_pmx_sdhci_led = {
.name = "sdhci_led",
.modes = pmx_sdhci_led_modes,
.mode_count = ARRAY_SIZE(pmx_sdhci_led_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_pwm0_modes[] = {
+static struct pmx_dev_mode pmx_pwm0_modes[] = {
{
.ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE,
.mask = PMX_UART0_MODEM_MASK,
@@ -239,14 +239,14 @@ struct pmx_dev_mode pmx_pwm0_modes[] = {
},
};
-struct pmx_dev pmx_pwm0 = {
+struct pmx_dev spear320_pmx_pwm0 = {
.name = "pwm0",
.modes = pmx_pwm0_modes,
.mode_count = ARRAY_SIZE(pmx_pwm0_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_pwm1_modes[] = {
+static struct pmx_dev_mode pmx_pwm1_modes[] = {
{
.ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE,
.mask = PMX_UART0_MODEM_MASK,
@@ -256,14 +256,14 @@ struct pmx_dev_mode pmx_pwm1_modes[] = {
},
};
-struct pmx_dev pmx_pwm1 = {
+struct pmx_dev spear320_pmx_pwm1 = {
.name = "pwm1",
.modes = pmx_pwm1_modes,
.mode_count = ARRAY_SIZE(pmx_pwm1_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_pwm2_modes[] = {
+static struct pmx_dev_mode pmx_pwm2_modes[] = {
{
.ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE,
.mask = PMX_SSP_CS_MASK,
@@ -273,105 +273,105 @@ struct pmx_dev_mode pmx_pwm2_modes[] = {
},
};
-struct pmx_dev pmx_pwm2 = {
+struct pmx_dev spear320_pmx_pwm2 = {
.name = "pwm2",
.modes = pmx_pwm2_modes,
.mode_count = ARRAY_SIZE(pmx_pwm2_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_pwm3_modes[] = {
+static struct pmx_dev_mode pmx_pwm3_modes[] = {
{
.ids = AUTO_EXP_MODE | SMALL_PRINTERS_MODE | AUTO_NET_SMII_MODE,
.mask = PMX_MII_MASK,
},
};
-struct pmx_dev pmx_pwm3 = {
+struct pmx_dev spear320_pmx_pwm3 = {
.name = "pwm3",
.modes = pmx_pwm3_modes,
.mode_count = ARRAY_SIZE(pmx_pwm3_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_ssp1_modes[] = {
+static struct pmx_dev_mode pmx_ssp1_modes[] = {
{
.ids = SMALL_PRINTERS_MODE | AUTO_NET_SMII_MODE,
.mask = PMX_MII_MASK,
},
};
-struct pmx_dev pmx_ssp1 = {
+struct pmx_dev spear320_pmx_ssp1 = {
.name = "ssp1",
.modes = pmx_ssp1_modes,
.mode_count = ARRAY_SIZE(pmx_ssp1_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_ssp2_modes[] = {
+static struct pmx_dev_mode pmx_ssp2_modes[] = {
{
.ids = AUTO_NET_SMII_MODE,
.mask = PMX_MII_MASK,
},
};
-struct pmx_dev pmx_ssp2 = {
+struct pmx_dev spear320_pmx_ssp2 = {
.name = "ssp2",
.modes = pmx_ssp2_modes,
.mode_count = ARRAY_SIZE(pmx_ssp2_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_mii1_modes[] = {
+static struct pmx_dev_mode pmx_mii1_modes[] = {
{
.ids = AUTO_NET_MII_MODE,
.mask = 0x0,
},
};
-struct pmx_dev pmx_mii1 = {
+struct pmx_dev spear320_pmx_mii1 = {
.name = "mii1",
.modes = pmx_mii1_modes,
.mode_count = ARRAY_SIZE(pmx_mii1_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_smii0_modes[] = {
+static struct pmx_dev_mode pmx_smii0_modes[] = {
{
.ids = AUTO_NET_SMII_MODE | AUTO_EXP_MODE | SMALL_PRINTERS_MODE,
.mask = PMX_MII_MASK,
},
};
-struct pmx_dev pmx_smii0 = {
+struct pmx_dev spear320_pmx_smii0 = {
.name = "smii0",
.modes = pmx_smii0_modes,
.mode_count = ARRAY_SIZE(pmx_smii0_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_smii1_modes[] = {
+static struct pmx_dev_mode pmx_smii1_modes[] = {
{
.ids = AUTO_NET_SMII_MODE | SMALL_PRINTERS_MODE,
.mask = PMX_MII_MASK,
},
};
-struct pmx_dev pmx_smii1 = {
+struct pmx_dev spear320_pmx_smii1 = {
.name = "smii1",
.modes = pmx_smii1_modes,
.mode_count = ARRAY_SIZE(pmx_smii1_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_i2c1_modes[] = {
+static struct pmx_dev_mode pmx_i2c1_modes[] = {
{
.ids = AUTO_EXP_MODE,
.mask = 0x0,
},
};
-struct pmx_dev pmx_i2c1 = {
+struct pmx_dev spear320_pmx_i2c1 = {
.name = "i2c1",
.modes = pmx_i2c1_modes,
.mode_count = ARRAY_SIZE(pmx_i2c1_modes),
@@ -379,131 +379,131 @@ struct pmx_dev pmx_i2c1 = {
};
/* pmx driver structure */
-struct pmx_driver pmx_driver = {
+static struct pmx_driver pmx_driver = {
.mode_reg = {.offset = MODE_CONFIG_REG, .mask = 0x00000007},
.mux_reg = {.offset = PAD_MUX_CONFIG_REG, .mask = 0x00007fff},
};
/* spear3xx shared irq */
-struct shirq_dev_config shirq_ras1_config[] = {
+static struct shirq_dev_config shirq_ras1_config[] = {
{
- .virq = VIRQ_EMI,
- .status_mask = EMI_IRQ_MASK,
- .clear_mask = EMI_IRQ_MASK,
+ .virq = SPEAR320_VIRQ_EMI,
+ .status_mask = SPEAR320_EMI_IRQ_MASK,
+ .clear_mask = SPEAR320_EMI_IRQ_MASK,
}, {
- .virq = VIRQ_CLCD,
- .status_mask = CLCD_IRQ_MASK,
- .clear_mask = CLCD_IRQ_MASK,
+ .virq = SPEAR320_VIRQ_CLCD,
+ .status_mask = SPEAR320_CLCD_IRQ_MASK,
+ .clear_mask = SPEAR320_CLCD_IRQ_MASK,
}, {
- .virq = VIRQ_SPP,
- .status_mask = SPP_IRQ_MASK,
- .clear_mask = SPP_IRQ_MASK,
+ .virq = SPEAR320_VIRQ_SPP,
+ .status_mask = SPEAR320_SPP_IRQ_MASK,
+ .clear_mask = SPEAR320_SPP_IRQ_MASK,
},
};
-struct spear_shirq shirq_ras1 = {
- .irq = IRQ_GEN_RAS_1,
+static struct spear_shirq shirq_ras1 = {
+ .irq = SPEAR3XX_IRQ_GEN_RAS_1,
.dev_config = shirq_ras1_config,
.dev_count = ARRAY_SIZE(shirq_ras1_config),
.regs = {
.enb_reg = -1,
- .status_reg = INT_STS_MASK_REG,
- .status_reg_mask = SHIRQ_RAS1_MASK,
- .clear_reg = INT_CLR_MASK_REG,
+ .status_reg = SPEAR320_INT_STS_MASK_REG,
+ .status_reg_mask = SPEAR320_SHIRQ_RAS1_MASK,
+ .clear_reg = SPEAR320_INT_CLR_MASK_REG,
.reset_to_clear = 1,
},
};
-struct shirq_dev_config shirq_ras3_config[] = {
+static struct shirq_dev_config shirq_ras3_config[] = {
{
- .virq = VIRQ_PLGPIO,
- .enb_mask = GPIO_IRQ_MASK,
- .status_mask = GPIO_IRQ_MASK,
- .clear_mask = GPIO_IRQ_MASK,
+ .virq = SPEAR320_VIRQ_PLGPIO,
+ .enb_mask = SPEAR320_GPIO_IRQ_MASK,
+ .status_mask = SPEAR320_GPIO_IRQ_MASK,
+ .clear_mask = SPEAR320_GPIO_IRQ_MASK,
}, {
- .virq = VIRQ_I2S_PLAY,
- .enb_mask = I2S_PLAY_IRQ_MASK,
- .status_mask = I2S_PLAY_IRQ_MASK,
- .clear_mask = I2S_PLAY_IRQ_MASK,
+ .virq = SPEAR320_VIRQ_I2S_PLAY,
+ .enb_mask = SPEAR320_I2S_PLAY_IRQ_MASK,
+ .status_mask = SPEAR320_I2S_PLAY_IRQ_MASK,
+ .clear_mask = SPEAR320_I2S_PLAY_IRQ_MASK,
}, {
- .virq = VIRQ_I2S_REC,
- .enb_mask = I2S_REC_IRQ_MASK,
- .status_mask = I2S_REC_IRQ_MASK,
- .clear_mask = I2S_REC_IRQ_MASK,
+ .virq = SPEAR320_VIRQ_I2S_REC,
+ .enb_mask = SPEAR320_I2S_REC_IRQ_MASK,
+ .status_mask = SPEAR320_I2S_REC_IRQ_MASK,
+ .clear_mask = SPEAR320_I2S_REC_IRQ_MASK,
},
};
-struct spear_shirq shirq_ras3 = {
- .irq = IRQ_GEN_RAS_3,
+static struct spear_shirq shirq_ras3 = {
+ .irq = SPEAR3XX_IRQ_GEN_RAS_3,
.dev_config = shirq_ras3_config,
.dev_count = ARRAY_SIZE(shirq_ras3_config),
.regs = {
- .enb_reg = INT_ENB_MASK_REG,
+ .enb_reg = SPEAR320_INT_ENB_MASK_REG,
.reset_to_enb = 1,
- .status_reg = INT_STS_MASK_REG,
- .status_reg_mask = SHIRQ_RAS3_MASK,
- .clear_reg = INT_CLR_MASK_REG,
+ .status_reg = SPEAR320_INT_STS_MASK_REG,
+ .status_reg_mask = SPEAR320_SHIRQ_RAS3_MASK,
+ .clear_reg = SPEAR320_INT_CLR_MASK_REG,
.reset_to_clear = 1,
},
};
-struct shirq_dev_config shirq_intrcomm_ras_config[] = {
+static struct shirq_dev_config shirq_intrcomm_ras_config[] = {
{
- .virq = VIRQ_CANU,
- .status_mask = CAN_U_IRQ_MASK,
- .clear_mask = CAN_U_IRQ_MASK,
+ .virq = SPEAR320_VIRQ_CANU,
+ .status_mask = SPEAR320_CAN_U_IRQ_MASK,
+ .clear_mask = SPEAR320_CAN_U_IRQ_MASK,
}, {
- .virq = VIRQ_CANL,
- .status_mask = CAN_L_IRQ_MASK,
- .clear_mask = CAN_L_IRQ_MASK,
+ .virq = SPEAR320_VIRQ_CANL,
+ .status_mask = SPEAR320_CAN_L_IRQ_MASK,
+ .clear_mask = SPEAR320_CAN_L_IRQ_MASK,
}, {
- .virq = VIRQ_UART1,
- .status_mask = UART1_IRQ_MASK,
- .clear_mask = UART1_IRQ_MASK,
+ .virq = SPEAR320_VIRQ_UART1,
+ .status_mask = SPEAR320_UART1_IRQ_MASK,
+ .clear_mask = SPEAR320_UART1_IRQ_MASK,
}, {
- .virq = VIRQ_UART2,
- .status_mask = UART2_IRQ_MASK,
- .clear_mask = UART2_IRQ_MASK,
+ .virq = SPEAR320_VIRQ_UART2,
+ .status_mask = SPEAR320_UART2_IRQ_MASK,
+ .clear_mask = SPEAR320_UART2_IRQ_MASK,
}, {
- .virq = VIRQ_SSP1,
- .status_mask = SSP1_IRQ_MASK,
- .clear_mask = SSP1_IRQ_MASK,
+ .virq = SPEAR320_VIRQ_SSP1,
+ .status_mask = SPEAR320_SSP1_IRQ_MASK,
+ .clear_mask = SPEAR320_SSP1_IRQ_MASK,
}, {
- .virq = VIRQ_SSP2,
- .status_mask = SSP2_IRQ_MASK,
- .clear_mask = SSP2_IRQ_MASK,
+ .virq = SPEAR320_VIRQ_SSP2,
+ .status_mask = SPEAR320_SSP2_IRQ_MASK,
+ .clear_mask = SPEAR320_SSP2_IRQ_MASK,
}, {
- .virq = VIRQ_SMII0,
- .status_mask = SMII0_IRQ_MASK,
- .clear_mask = SMII0_IRQ_MASK,
+ .virq = SPEAR320_VIRQ_SMII0,
+ .status_mask = SPEAR320_SMII0_IRQ_MASK,
+ .clear_mask = SPEAR320_SMII0_IRQ_MASK,
}, {
- .virq = VIRQ_MII1_SMII1,
- .status_mask = MII1_SMII1_IRQ_MASK,
- .clear_mask = MII1_SMII1_IRQ_MASK,
+ .virq = SPEAR320_VIRQ_MII1_SMII1,
+ .status_mask = SPEAR320_MII1_SMII1_IRQ_MASK,
+ .clear_mask = SPEAR320_MII1_SMII1_IRQ_MASK,
}, {
- .virq = VIRQ_WAKEUP_SMII0,
- .status_mask = WAKEUP_SMII0_IRQ_MASK,
- .clear_mask = WAKEUP_SMII0_IRQ_MASK,
+ .virq = SPEAR320_VIRQ_WAKEUP_SMII0,
+ .status_mask = SPEAR320_WAKEUP_SMII0_IRQ_MASK,
+ .clear_mask = SPEAR320_WAKEUP_SMII0_IRQ_MASK,
}, {
- .virq = VIRQ_WAKEUP_MII1_SMII1,
- .status_mask = WAKEUP_MII1_SMII1_IRQ_MASK,
- .clear_mask = WAKEUP_MII1_SMII1_IRQ_MASK,
+ .virq = SPEAR320_VIRQ_WAKEUP_MII1_SMII1,
+ .status_mask = SPEAR320_WAKEUP_MII1_SMII1_IRQ_MASK,
+ .clear_mask = SPEAR320_WAKEUP_MII1_SMII1_IRQ_MASK,
}, {
- .virq = VIRQ_I2C,
- .status_mask = I2C1_IRQ_MASK,
- .clear_mask = I2C1_IRQ_MASK,
+ .virq = SPEAR320_VIRQ_I2C1,
+ .status_mask = SPEAR320_I2C1_IRQ_MASK,
+ .clear_mask = SPEAR320_I2C1_IRQ_MASK,
},
};
-struct spear_shirq shirq_intrcomm_ras = {
- .irq = IRQ_INTRCOMM_RAS_ARM,
+static struct spear_shirq shirq_intrcomm_ras = {
+ .irq = SPEAR3XX_IRQ_INTRCOMM_RAS_ARM,
.dev_config = shirq_intrcomm_ras_config,
.dev_count = ARRAY_SIZE(shirq_intrcomm_ras_config),
.regs = {
.enb_reg = -1,
- .status_reg = INT_STS_MASK_REG,
- .status_reg_mask = SHIRQ_INTRCOMM_RAS_MASK,
- .clear_reg = INT_CLR_MASK_REG,
+ .status_reg = SPEAR320_INT_STS_MASK_REG,
+ .status_reg_mask = SPEAR320_SHIRQ_INTRCOMM_RAS_MASK,
+ .clear_reg = SPEAR320_INT_CLR_MASK_REG,
.reset_to_clear = 1,
},
};
@@ -511,7 +511,8 @@ struct spear_shirq shirq_intrcomm_ras = {
/* Add spear320 specific devices here */
/* spear320 routines */
-void __init spear320_init(void)
+void __init spear320_init(struct pmx_mode *pmx_mode, struct pmx_dev **pmx_devs,
+ u8 pmx_dev_count)
{
void __iomem *base;
int ret = 0;
@@ -543,6 +544,10 @@ void __init spear320_init(void)
/* pmx initialization */
pmx_driver.base = base;
+ pmx_driver.mode = pmx_mode;
+ pmx_driver.devs = pmx_devs;
+ pmx_driver.devs_count = pmx_dev_count;
+
ret = pmx_register(&pmx_driver);
if (ret)
printk(KERN_ERR "padmux: registeration failed. err no: %d\n",
diff --git a/arch/arm/mach-spear3xx/spear320_evb.c b/arch/arm/mach-spear3xx/spear320_evb.c
index 8213e4b66c14..a12b353940d6 100644
--- a/arch/arm/mach-spear3xx/spear320_evb.c
+++ b/arch/arm/mach-spear3xx/spear320_evb.c
@@ -19,28 +19,28 @@
/* padmux devices to enable */
static struct pmx_dev *pmx_devs[] = {
/* spear3xx specific devices */
- &pmx_i2c,
- &pmx_ssp,
- &pmx_mii,
- &pmx_uart0,
+ &spear3xx_pmx_i2c,
+ &spear3xx_pmx_ssp,
+ &spear3xx_pmx_mii,
+ &spear3xx_pmx_uart0,
/* spear320 specific devices */
- &pmx_fsmc,
- &pmx_sdhci,
- &pmx_i2s,
- &pmx_uart1,
- &pmx_uart2,
- &pmx_can,
- &pmx_pwm0,
- &pmx_pwm1,
- &pmx_pwm2,
- &pmx_mii1,
+ &spear320_pmx_fsmc,
+ &spear320_pmx_sdhci,
+ &spear320_pmx_i2s,
+ &spear320_pmx_uart1,
+ &spear320_pmx_uart2,
+ &spear320_pmx_can,
+ &spear320_pmx_pwm0,
+ &spear320_pmx_pwm1,
+ &spear320_pmx_pwm2,
+ &spear320_pmx_mii1,
};
static struct amba_device *amba_devs[] __initdata = {
/* spear3xx specific devices */
- &gpio_device,
- &uart_device,
+ &spear3xx_gpio_device,
+ &spear3xx_uart_device,
/* spear320 specific devices */
};
@@ -55,13 +55,9 @@ static void __init spear320_evb_init(void)
{
unsigned int i;
- /* padmux initialization, must be done before spear320_init */
- pmx_driver.mode = &auto_net_mii_mode;
- pmx_driver.devs = pmx_devs;
- pmx_driver.devs_count = ARRAY_SIZE(pmx_devs);
-
/* call spear320 machine init function */
- spear320_init();
+ spear320_init(&spear320_auto_net_mii_mode, pmx_devs,
+ ARRAY_SIZE(pmx_devs));
/* Add Platform Devices */
platform_add_devices(plat_devs, ARRAY_SIZE(plat_devs));
diff --git a/arch/arm/mach-spear3xx/spear3xx.c b/arch/arm/mach-spear3xx/spear3xx.c
index d3ba8ca1bc59..10af45da86a0 100644
--- a/arch/arm/mach-spear3xx/spear3xx.c
+++ b/arch/arm/mach-spear3xx/spear3xx.c
@@ -25,10 +25,10 @@
/* gpio device registration */
static struct pl061_platform_data gpio_plat_data = {
.gpio_base = 0,
- .irq_base = SPEAR_GPIO_INT_BASE,
+ .irq_base = SPEAR3XX_GPIO_INT_BASE,
};
-struct amba_device gpio_device = {
+struct amba_device spear3xx_gpio_device = {
.dev = {
.init_name = "gpio",
.platform_data = &gpio_plat_data,
@@ -38,11 +38,11 @@ struct amba_device gpio_device = {
.end = SPEAR3XX_ICM3_GPIO_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
- .irq = {IRQ_BASIC_GPIO, NO_IRQ},
+ .irq = {SPEAR3XX_IRQ_BASIC_GPIO, NO_IRQ},
};
/* uart device registration */
-struct amba_device uart_device = {
+struct amba_device spear3xx_uart_device = {
.dev = {
.init_name = "uart",
},
@@ -51,7 +51,7 @@ struct amba_device uart_device = {
.end = SPEAR3XX_ICM1_UART_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
- .irq = {IRQ_UART, NO_IRQ},
+ .irq = {SPEAR3XX_IRQ_UART, NO_IRQ},
};
/* Do spear3xx familiy common initialization part here */
@@ -97,215 +97,215 @@ void __init spear3xx_map_io(void)
iotable_init(spear3xx_io_desc, ARRAY_SIZE(spear3xx_io_desc));
/* This will initialize clock framework */
- clk_init();
+ spear3xx_clk_init();
}
/* pad multiplexing support */
/* devices */
-struct pmx_dev_mode pmx_firda_modes[] = {
+static struct pmx_dev_mode pmx_firda_modes[] = {
{
.ids = 0xffffffff,
.mask = PMX_FIRDA_MASK,
},
};
-struct pmx_dev pmx_firda = {
+struct pmx_dev spear3xx_pmx_firda = {
.name = "firda",
.modes = pmx_firda_modes,
.mode_count = ARRAY_SIZE(pmx_firda_modes),
.enb_on_reset = 0,
};
-struct pmx_dev_mode pmx_i2c_modes[] = {
+static struct pmx_dev_mode pmx_i2c_modes[] = {
{
.ids = 0xffffffff,
.mask = PMX_I2C_MASK,
},
};
-struct pmx_dev pmx_i2c = {
+struct pmx_dev spear3xx_pmx_i2c = {
.name = "i2c",
.modes = pmx_i2c_modes,
.mode_count = ARRAY_SIZE(pmx_i2c_modes),
.enb_on_reset = 0,
};
-struct pmx_dev_mode pmx_ssp_cs_modes[] = {
+static struct pmx_dev_mode pmx_ssp_cs_modes[] = {
{
.ids = 0xffffffff,
.mask = PMX_SSP_CS_MASK,
},
};
-struct pmx_dev pmx_ssp_cs = {
+struct pmx_dev spear3xx_pmx_ssp_cs = {
.name = "ssp_chip_selects",
.modes = pmx_ssp_cs_modes,
.mode_count = ARRAY_SIZE(pmx_ssp_cs_modes),
.enb_on_reset = 0,
};
-struct pmx_dev_mode pmx_ssp_modes[] = {
+static struct pmx_dev_mode pmx_ssp_modes[] = {
{
.ids = 0xffffffff,
.mask = PMX_SSP_MASK,
},
};
-struct pmx_dev pmx_ssp = {
+struct pmx_dev spear3xx_pmx_ssp = {
.name = "ssp",
.modes = pmx_ssp_modes,
.mode_count = ARRAY_SIZE(pmx_ssp_modes),
.enb_on_reset = 0,
};
-struct pmx_dev_mode pmx_mii_modes[] = {
+static struct pmx_dev_mode pmx_mii_modes[] = {
{
.ids = 0xffffffff,
.mask = PMX_MII_MASK,
},
};
-struct pmx_dev pmx_mii = {
+struct pmx_dev spear3xx_pmx_mii = {
.name = "mii",
.modes = pmx_mii_modes,
.mode_count = ARRAY_SIZE(pmx_mii_modes),
.enb_on_reset = 0,
};
-struct pmx_dev_mode pmx_gpio_pin0_modes[] = {
+static struct pmx_dev_mode pmx_gpio_pin0_modes[] = {
{
.ids = 0xffffffff,
.mask = PMX_GPIO_PIN0_MASK,
},
};
-struct pmx_dev pmx_gpio_pin0 = {
+struct pmx_dev spear3xx_pmx_gpio_pin0 = {
.name = "gpio_pin0",
.modes = pmx_gpio_pin0_modes,
.mode_count = ARRAY_SIZE(pmx_gpio_pin0_modes),
.enb_on_reset = 0,
};
-struct pmx_dev_mode pmx_gpio_pin1_modes[] = {
+static struct pmx_dev_mode pmx_gpio_pin1_modes[] = {
{
.ids = 0xffffffff,
.mask = PMX_GPIO_PIN1_MASK,
},
};
-struct pmx_dev pmx_gpio_pin1 = {
+struct pmx_dev spear3xx_pmx_gpio_pin1 = {
.name = "gpio_pin1",
.modes = pmx_gpio_pin1_modes,
.mode_count = ARRAY_SIZE(pmx_gpio_pin1_modes),
.enb_on_reset = 0,
};
-struct pmx_dev_mode pmx_gpio_pin2_modes[] = {
+static struct pmx_dev_mode pmx_gpio_pin2_modes[] = {
{
.ids = 0xffffffff,
.mask = PMX_GPIO_PIN2_MASK,
},
};
-struct pmx_dev pmx_gpio_pin2 = {
+struct pmx_dev spear3xx_pmx_gpio_pin2 = {
.name = "gpio_pin2",
.modes = pmx_gpio_pin2_modes,
.mode_count = ARRAY_SIZE(pmx_gpio_pin2_modes),
.enb_on_reset = 0,
};
-struct pmx_dev_mode pmx_gpio_pin3_modes[] = {
+static struct pmx_dev_mode pmx_gpio_pin3_modes[] = {
{
.ids = 0xffffffff,
.mask = PMX_GPIO_PIN3_MASK,
},
};
-struct pmx_dev pmx_gpio_pin3 = {
+struct pmx_dev spear3xx_pmx_gpio_pin3 = {
.name = "gpio_pin3",
.modes = pmx_gpio_pin3_modes,
.mode_count = ARRAY_SIZE(pmx_gpio_pin3_modes),
.enb_on_reset = 0,
};
-struct pmx_dev_mode pmx_gpio_pin4_modes[] = {
+static struct pmx_dev_mode pmx_gpio_pin4_modes[] = {
{
.ids = 0xffffffff,
.mask = PMX_GPIO_PIN4_MASK,
},
};
-struct pmx_dev pmx_gpio_pin4 = {
+struct pmx_dev spear3xx_pmx_gpio_pin4 = {
.name = "gpio_pin4",
.modes = pmx_gpio_pin4_modes,
.mode_count = ARRAY_SIZE(pmx_gpio_pin4_modes),
.enb_on_reset = 0,
};
-struct pmx_dev_mode pmx_gpio_pin5_modes[] = {
+static struct pmx_dev_mode pmx_gpio_pin5_modes[] = {
{
.ids = 0xffffffff,
.mask = PMX_GPIO_PIN5_MASK,
},
};
-struct pmx_dev pmx_gpio_pin5 = {
+struct pmx_dev spear3xx_pmx_gpio_pin5 = {
.name = "gpio_pin5",
.modes = pmx_gpio_pin5_modes,
.mode_count = ARRAY_SIZE(pmx_gpio_pin5_modes),
.enb_on_reset = 0,
};
-struct pmx_dev_mode pmx_uart0_modem_modes[] = {
+static struct pmx_dev_mode pmx_uart0_modem_modes[] = {
{
.ids = 0xffffffff,
.mask = PMX_UART0_MODEM_MASK,
},
};
-struct pmx_dev pmx_uart0_modem = {
+struct pmx_dev spear3xx_pmx_uart0_modem = {
.name = "uart0_modem",
.modes = pmx_uart0_modem_modes,
.mode_count = ARRAY_SIZE(pmx_uart0_modem_modes),
.enb_on_reset = 0,
};
-struct pmx_dev_mode pmx_uart0_modes[] = {
+static struct pmx_dev_mode pmx_uart0_modes[] = {
{
.ids = 0xffffffff,
.mask = PMX_UART0_MASK,
},
};
-struct pmx_dev pmx_uart0 = {
+struct pmx_dev spear3xx_pmx_uart0 = {
.name = "uart0",
.modes = pmx_uart0_modes,
.mode_count = ARRAY_SIZE(pmx_uart0_modes),
.enb_on_reset = 0,
};
-struct pmx_dev_mode pmx_timer_3_4_modes[] = {
+static struct pmx_dev_mode pmx_timer_3_4_modes[] = {
{
.ids = 0xffffffff,
.mask = PMX_TIMER_3_4_MASK,
},
};
-struct pmx_dev pmx_timer_3_4 = {
+struct pmx_dev spear3xx_pmx_timer_3_4 = {
.name = "timer_3_4",
.modes = pmx_timer_3_4_modes,
.mode_count = ARRAY_SIZE(pmx_timer_3_4_modes),
.enb_on_reset = 0,
};
-struct pmx_dev_mode pmx_timer_1_2_modes[] = {
+static struct pmx_dev_mode pmx_timer_1_2_modes[] = {
{
.ids = 0xffffffff,
.mask = PMX_TIMER_1_2_MASK,
},
};
-struct pmx_dev pmx_timer_1_2 = {
+struct pmx_dev spear3xx_pmx_timer_1_2 = {
.name = "timer_1_2",
.modes = pmx_timer_1_2_modes,
.mode_count = ARRAY_SIZE(pmx_timer_1_2_modes),
@@ -314,210 +314,210 @@ struct pmx_dev pmx_timer_1_2 = {
#if defined(CONFIG_MACH_SPEAR310) || defined(CONFIG_MACH_SPEAR320)
/* plgpios devices */
-struct pmx_dev_mode pmx_plgpio_0_1_modes[] = {
+static struct pmx_dev_mode pmx_plgpio_0_1_modes[] = {
{
.ids = 0x00,
.mask = PMX_FIRDA_MASK,
},
};
-struct pmx_dev pmx_plgpio_0_1 = {
+struct pmx_dev spear3xx_pmx_plgpio_0_1 = {
.name = "plgpio 0 and 1",
.modes = pmx_plgpio_0_1_modes,
.mode_count = ARRAY_SIZE(pmx_plgpio_0_1_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_plgpio_2_3_modes[] = {
+static struct pmx_dev_mode pmx_plgpio_2_3_modes[] = {
{
.ids = 0x00,
.mask = PMX_UART0_MASK,
},
};
-struct pmx_dev pmx_plgpio_2_3 = {
+struct pmx_dev spear3xx_pmx_plgpio_2_3 = {
.name = "plgpio 2 and 3",
.modes = pmx_plgpio_2_3_modes,
.mode_count = ARRAY_SIZE(pmx_plgpio_2_3_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_plgpio_4_5_modes[] = {
+static struct pmx_dev_mode pmx_plgpio_4_5_modes[] = {
{
.ids = 0x00,
.mask = PMX_I2C_MASK,
},
};
-struct pmx_dev pmx_plgpio_4_5 = {
+struct pmx_dev spear3xx_pmx_plgpio_4_5 = {
.name = "plgpio 4 and 5",
.modes = pmx_plgpio_4_5_modes,
.mode_count = ARRAY_SIZE(pmx_plgpio_4_5_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_plgpio_6_9_modes[] = {
+static struct pmx_dev_mode pmx_plgpio_6_9_modes[] = {
{
.ids = 0x00,
.mask = PMX_SSP_MASK,
},
};
-struct pmx_dev pmx_plgpio_6_9 = {
+struct pmx_dev spear3xx_pmx_plgpio_6_9 = {
.name = "plgpio 6 to 9",
.modes = pmx_plgpio_6_9_modes,
.mode_count = ARRAY_SIZE(pmx_plgpio_6_9_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_plgpio_10_27_modes[] = {
+static struct pmx_dev_mode pmx_plgpio_10_27_modes[] = {
{
.ids = 0x00,
.mask = PMX_MII_MASK,
},
};
-struct pmx_dev pmx_plgpio_10_27 = {
+struct pmx_dev spear3xx_pmx_plgpio_10_27 = {
.name = "plgpio 10 to 27",
.modes = pmx_plgpio_10_27_modes,
.mode_count = ARRAY_SIZE(pmx_plgpio_10_27_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_plgpio_28_modes[] = {
+static struct pmx_dev_mode pmx_plgpio_28_modes[] = {
{
.ids = 0x00,
.mask = PMX_GPIO_PIN0_MASK,
},
};
-struct pmx_dev pmx_plgpio_28 = {
+struct pmx_dev spear3xx_pmx_plgpio_28 = {
.name = "plgpio 28",
.modes = pmx_plgpio_28_modes,
.mode_count = ARRAY_SIZE(pmx_plgpio_28_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_plgpio_29_modes[] = {
+static struct pmx_dev_mode pmx_plgpio_29_modes[] = {
{
.ids = 0x00,
.mask = PMX_GPIO_PIN1_MASK,
},
};
-struct pmx_dev pmx_plgpio_29 = {
+struct pmx_dev spear3xx_pmx_plgpio_29 = {
.name = "plgpio 29",
.modes = pmx_plgpio_29_modes,
.mode_count = ARRAY_SIZE(pmx_plgpio_29_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_plgpio_30_modes[] = {
+static struct pmx_dev_mode pmx_plgpio_30_modes[] = {
{
.ids = 0x00,
.mask = PMX_GPIO_PIN2_MASK,
},
};
-struct pmx_dev pmx_plgpio_30 = {
+struct pmx_dev spear3xx_pmx_plgpio_30 = {
.name = "plgpio 30",
.modes = pmx_plgpio_30_modes,
.mode_count = ARRAY_SIZE(pmx_plgpio_30_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_plgpio_31_modes[] = {
+static struct pmx_dev_mode pmx_plgpio_31_modes[] = {
{
.ids = 0x00,
.mask = PMX_GPIO_PIN3_MASK,
},
};
-struct pmx_dev pmx_plgpio_31 = {
+struct pmx_dev spear3xx_pmx_plgpio_31 = {
.name = "plgpio 31",
.modes = pmx_plgpio_31_modes,
.mode_count = ARRAY_SIZE(pmx_plgpio_31_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_plgpio_32_modes[] = {
+static struct pmx_dev_mode pmx_plgpio_32_modes[] = {
{
.ids = 0x00,
.mask = PMX_GPIO_PIN4_MASK,
},
};
-struct pmx_dev pmx_plgpio_32 = {
+struct pmx_dev spear3xx_pmx_plgpio_32 = {
.name = "plgpio 32",
.modes = pmx_plgpio_32_modes,
.mode_count = ARRAY_SIZE(pmx_plgpio_32_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_plgpio_33_modes[] = {
+static struct pmx_dev_mode pmx_plgpio_33_modes[] = {
{
.ids = 0x00,
.mask = PMX_GPIO_PIN5_MASK,
},
};
-struct pmx_dev pmx_plgpio_33 = {
+struct pmx_dev spear3xx_pmx_plgpio_33 = {
.name = "plgpio 33",
.modes = pmx_plgpio_33_modes,
.mode_count = ARRAY_SIZE(pmx_plgpio_33_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_plgpio_34_36_modes[] = {
+static struct pmx_dev_mode pmx_plgpio_34_36_modes[] = {
{
.ids = 0x00,
.mask = PMX_SSP_CS_MASK,
},
};
-struct pmx_dev pmx_plgpio_34_36 = {
+struct pmx_dev spear3xx_pmx_plgpio_34_36 = {
.name = "plgpio 34 to 36",
.modes = pmx_plgpio_34_36_modes,
.mode_count = ARRAY_SIZE(pmx_plgpio_34_36_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_plgpio_37_42_modes[] = {
+static struct pmx_dev_mode pmx_plgpio_37_42_modes[] = {
{
.ids = 0x00,
.mask = PMX_UART0_MODEM_MASK,
},
};
-struct pmx_dev pmx_plgpio_37_42 = {
+struct pmx_dev spear3xx_pmx_plgpio_37_42 = {
.name = "plgpio 37 to 42",
.modes = pmx_plgpio_37_42_modes,
.mode_count = ARRAY_SIZE(pmx_plgpio_37_42_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_plgpio_43_44_47_48_modes[] = {
+static struct pmx_dev_mode pmx_plgpio_43_44_47_48_modes[] = {
{
.ids = 0x00,
.mask = PMX_TIMER_1_2_MASK,
},
};
-struct pmx_dev pmx_plgpio_43_44_47_48 = {
+struct pmx_dev spear3xx_pmx_plgpio_43_44_47_48 = {
.name = "plgpio 43, 44, 47 and 48",
.modes = pmx_plgpio_43_44_47_48_modes,
.mode_count = ARRAY_SIZE(pmx_plgpio_43_44_47_48_modes),
.enb_on_reset = 1,
};
-struct pmx_dev_mode pmx_plgpio_45_46_49_50_modes[] = {
+static struct pmx_dev_mode pmx_plgpio_45_46_49_50_modes[] = {
{
.ids = 0x00,
.mask = PMX_TIMER_3_4_MASK,
},
};
-struct pmx_dev pmx_plgpio_45_46_49_50 = {
+struct pmx_dev spear3xx_pmx_plgpio_45_46_49_50 = {
.name = "plgpio 45, 46, 49 and 50",
.modes = pmx_plgpio_45_46_49_50_modes,
.mode_count = ARRAY_SIZE(pmx_plgpio_45_46_49_50_modes),
diff --git a/arch/arm/mach-spear6xx/Kconfig b/arch/arm/mach-spear6xx/Kconfig
index bddba034f862..ff4ae5ba00f1 100644
--- a/arch/arm/mach-spear6xx/Kconfig
+++ b/arch/arm/mach-spear6xx/Kconfig
@@ -4,17 +4,18 @@
if ARCH_SPEAR6XX
-choice
- prompt "SPEAr6XX Family"
- default MACH_SPEAR600
+menu "SPEAr6xx Implementations"
+config BOARD_SPEAR600_EVB
+ bool "SPEAr600 Evaluation Board"
+ select MACH_SPEAR600
+ help
+ Supports ST SPEAr600 Evaluation Board
+
+endmenu
config MACH_SPEAR600
bool "SPEAr600"
help
Supports ST SPEAr600 Machine
-endchoice
-
-# Adding SPEAr6XX machine specific configuration files
-source "arch/arm/mach-spear6xx/Kconfig600"
endif #ARCH_SPEAR6XX
diff --git a/arch/arm/mach-spear6xx/Kconfig600 b/arch/arm/mach-spear6xx/Kconfig600
deleted file mode 100644
index 9e19f65eb78e..000000000000
--- a/arch/arm/mach-spear6xx/Kconfig600
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# SPEAr600 machine configuration file
-#
-
-if MACH_SPEAR600
-
-choice
- prompt "SPEAr600 Boards"
- default BOARD_SPEAR600_EVB
-
-config BOARD_SPEAR600_EVB
- bool "SPEAr600 Evaluation Board"
- help
- Supports ST SPEAr600 Evaluation Board
-endchoice
-
-endif #MACH_SPEAR600
diff --git a/arch/arm/mach-spear6xx/clock.c b/arch/arm/mach-spear6xx/clock.c
index 88b748b5be80..ac70e0d88fef 100644
--- a/arch/arm/mach-spear6xx/clock.c
+++ b/arch/arm/mach-spear6xx/clock.c
@@ -671,12 +671,12 @@ static struct clk_lookup spear_clk_lookups[] = {
{ .dev_id = "gpio2", .clk = &gpio2_clk},
};
-void __init clk_init(void)
+void __init spear6xx_clk_init(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(spear_clk_lookups); i++)
clk_register(&spear_clk_lookups[i]);
- recalc_root_clocks();
+ clk_init();
}
diff --git a/arch/arm/mach-spear6xx/include/mach/generic.h b/arch/arm/mach-spear6xx/include/mach/generic.h
index 94cf4a648b57..183f0238c5e2 100644
--- a/arch/arm/mach-spear6xx/include/mach/generic.h
+++ b/arch/arm/mach-spear6xx/include/mach/generic.h
@@ -39,7 +39,7 @@ void __init spear6xx_map_io(void);
void __init spear6xx_init_irq(void);
void __init spear6xx_init(void);
void __init spear600_init(void);
-void __init clk_init(void);
+void __init spear6xx_clk_init(void);
/* Add spear600 machine device structure declarations here */
diff --git a/arch/arm/mach-spear6xx/spear6xx.c b/arch/arm/mach-spear6xx/spear6xx.c
index 981812961ac7..e0f6628c8b2c 100644
--- a/arch/arm/mach-spear6xx/spear6xx.c
+++ b/arch/arm/mach-spear6xx/spear6xx.c
@@ -148,7 +148,7 @@ void __init spear6xx_map_io(void)
iotable_init(spear6xx_io_desc, ARRAY_SIZE(spear6xx_io_desc));
/* This will initialize clock framework */
- clk_init();
+ spear6xx_clk_init();
}
static void __init spear6xx_timer_init(void)
diff --git a/arch/arm/mach-stmp378x/Makefile b/arch/arm/mach-stmp378x/Makefile
deleted file mode 100644
index d156f76b379f..000000000000
--- a/arch/arm/mach-stmp378x/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-obj-$(CONFIG_ARCH_STMP378X) += stmp378x.o
-obj-$(CONFIG_MACH_STMP378X) += stmp378x_devb.o
diff --git a/arch/arm/mach-stmp378x/Makefile.boot b/arch/arm/mach-stmp378x/Makefile.boot
deleted file mode 100644
index 1568ad404d59..000000000000
--- a/arch/arm/mach-stmp378x/Makefile.boot
+++ /dev/null
@@ -1,3 +0,0 @@
- zreladdr-y := 0x40008000
-params_phys-y := 0x40000100
-initrd_phys-y := 0x40800000
diff --git a/arch/arm/mach-stmp378x/include/mach/entry-macro.S b/arch/arm/mach-stmp378x/include/mach/entry-macro.S
deleted file mode 100644
index 731a92286da2..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/entry-macro.S
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Low-level IRQ helper macros for Freescale STMP378X
- *
- * Embedded Alley Solutions, Inc <source@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-
- .macro disable_fiq
- .endm
-
- .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
-
- mov \base, #0xf0000000 @ vm address of IRQ controller
- ldr \irqnr, [\base, #0x70] @ HW_ICOLL_STAT
- cmp \irqnr, #0x7f
- moveqs \irqnr, #0 @ Zero flag set for no IRQ
-
- .endm
-
- .macro get_irqnr_preamble, base, tmp
- .endm
-
- .macro arch_ret_to_user, tmp1, tmp2
- .endm
diff --git a/arch/arm/mach-stmp378x/include/mach/irqs.h b/arch/arm/mach-stmp378x/include/mach/irqs.h
deleted file mode 100644
index cc59673becdd..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/irqs.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Freescale STMP378X interrupts
- *
- * Copyright (C) 2005 Sigmatel Inc
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-
-#define IRQ_DEBUG_UART 0
-#define IRQ_COMMS_RX 1
-#define IRQ_COMMS_TX 1
-#define IRQ_SSP2_ERROR 2
-#define IRQ_VDD5V 3
-#define IRQ_HEADPHONE_SHORT 4
-#define IRQ_DAC_DMA 5
-#define IRQ_DAC_ERROR 6
-#define IRQ_ADC_DMA 7
-#define IRQ_ADC_ERROR 8
-#define IRQ_SPDIF_DMA 9
-#define IRQ_SAIF2_DMA 9
-#define IRQ_SPDIF_ERROR 10
-#define IRQ_SAIF1_IRQ 10
-#define IRQ_SAIF2_IRQ 10
-#define IRQ_USB_CTRL 11
-#define IRQ_USB_WAKEUP 12
-#define IRQ_GPMI_DMA 13
-#define IRQ_SSP1_DMA 14
-#define IRQ_SSP_ERROR 15
-#define IRQ_GPIO0 16
-#define IRQ_GPIO1 17
-#define IRQ_GPIO2 18
-#define IRQ_SAIF1_DMA 19
-#define IRQ_SSP2_DMA 20
-#define IRQ_ECC8_IRQ 21
-#define IRQ_RTC_ALARM 22
-#define IRQ_UARTAPP_TX_DMA 23
-#define IRQ_UARTAPP_INTERNAL 24
-#define IRQ_UARTAPP_RX_DMA 25
-#define IRQ_I2C_DMA 26
-#define IRQ_I2C_ERROR 27
-#define IRQ_TIMER0 28
-#define IRQ_TIMER1 29
-#define IRQ_TIMER2 30
-#define IRQ_TIMER3 31
-#define IRQ_BATT_BRNOUT 32
-#define IRQ_VDDD_BRNOUT 33
-#define IRQ_VDDIO_BRNOUT 34
-#define IRQ_VDD18_BRNOUT 35
-#define IRQ_TOUCH_DETECT 36
-#define IRQ_LRADC_CH0 37
-#define IRQ_LRADC_CH1 38
-#define IRQ_LRADC_CH2 39
-#define IRQ_LRADC_CH3 40
-#define IRQ_LRADC_CH4 41
-#define IRQ_LRADC_CH5 42
-#define IRQ_LRADC_CH6 43
-#define IRQ_LRADC_CH7 44
-#define IRQ_LCDIF_DMA 45
-#define IRQ_LCDIF_ERROR 46
-#define IRQ_DIGCTL_DEBUG_TRAP 47
-#define IRQ_RTC_1MSEC 48
-#define IRQ_DRI_DMA 49
-#define IRQ_DRI_ATTENTION 50
-#define IRQ_GPMI_ATTENTION 51
-#define IRQ_IR 52
-#define IRQ_DCP_VMI 53
-#define IRQ_DCP 54
-#define IRQ_BCH 56
-#define IRQ_PXP 57
-#define IRQ_UARTAPP2_TX_DMA 58
-#define IRQ_UARTAPP2_INTERNAL 59
-#define IRQ_UARTAPP2_RX_DMA 60
-#define IRQ_VDAC_DETECT 61
-#define IRQ_VDD5V_DROOP 64
-#define IRQ_DCDC4P2_BO 65
-
-
-#define NR_REAL_IRQS 128
-#define NR_IRQS (NR_REAL_IRQS + 32 * 3)
-
-/* All interrupts are FIQ capable */
-#define FIQ_START IRQ_DEBUG_UART
-
-/* Hard disk IRQ is a GPMI attention IRQ */
-#define IRQ_HARDDISK IRQ_GPMI_ATTENTION
diff --git a/arch/arm/mach-stmp378x/include/mach/pins.h b/arch/arm/mach-stmp378x/include/mach/pins.h
deleted file mode 100644
index 93f952d35969..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/pins.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Freescale STMP378X SoC pin multiplexing
- *
- * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#ifndef __ASM_ARCH_PINS_H
-#define __ASM_ARCH_PINS_H
-
-/*
- * Define all STMP378x pins, a pin name corresponds to a STMP378x hardware
- * interface this pin belongs to.
- */
-
-/* Bank 0 */
-#define PINID_GPMI_D00 STMP3XXX_PINID(0, 0)
-#define PINID_GPMI_D01 STMP3XXX_PINID(0, 1)
-#define PINID_GPMI_D02 STMP3XXX_PINID(0, 2)
-#define PINID_GPMI_D03 STMP3XXX_PINID(0, 3)
-#define PINID_GPMI_D04 STMP3XXX_PINID(0, 4)
-#define PINID_GPMI_D05 STMP3XXX_PINID(0, 5)
-#define PINID_GPMI_D06 STMP3XXX_PINID(0, 6)
-#define PINID_GPMI_D07 STMP3XXX_PINID(0, 7)
-#define PINID_GPMI_D08 STMP3XXX_PINID(0, 8)
-#define PINID_GPMI_D09 STMP3XXX_PINID(0, 9)
-#define PINID_GPMI_D10 STMP3XXX_PINID(0, 10)
-#define PINID_GPMI_D11 STMP3XXX_PINID(0, 11)
-#define PINID_GPMI_D12 STMP3XXX_PINID(0, 12)
-#define PINID_GPMI_D13 STMP3XXX_PINID(0, 13)
-#define PINID_GPMI_D14 STMP3XXX_PINID(0, 14)
-#define PINID_GPMI_D15 STMP3XXX_PINID(0, 15)
-#define PINID_GPMI_CLE STMP3XXX_PINID(0, 16)
-#define PINID_GPMI_ALE STMP3XXX_PINID(0, 17)
-#define PINID_GMPI_CE2N STMP3XXX_PINID(0, 18)
-#define PINID_GPMI_RDY0 STMP3XXX_PINID(0, 19)
-#define PINID_GPMI_RDY1 STMP3XXX_PINID(0, 20)
-#define PINID_GPMI_RDY2 STMP3XXX_PINID(0, 21)
-#define PINID_GPMI_RDY3 STMP3XXX_PINID(0, 22)
-#define PINID_GPMI_WPN STMP3XXX_PINID(0, 23)
-#define PINID_GPMI_WRN STMP3XXX_PINID(0, 24)
-#define PINID_GPMI_RDN STMP3XXX_PINID(0, 25)
-#define PINID_AUART1_CTS STMP3XXX_PINID(0, 26)
-#define PINID_AUART1_RTS STMP3XXX_PINID(0, 27)
-#define PINID_AUART1_RX STMP3XXX_PINID(0, 28)
-#define PINID_AUART1_TX STMP3XXX_PINID(0, 29)
-#define PINID_I2C_SCL STMP3XXX_PINID(0, 30)
-#define PINID_I2C_SDA STMP3XXX_PINID(0, 31)
-
-/* Bank 1 */
-#define PINID_LCD_D00 STMP3XXX_PINID(1, 0)
-#define PINID_LCD_D01 STMP3XXX_PINID(1, 1)
-#define PINID_LCD_D02 STMP3XXX_PINID(1, 2)
-#define PINID_LCD_D03 STMP3XXX_PINID(1, 3)
-#define PINID_LCD_D04 STMP3XXX_PINID(1, 4)
-#define PINID_LCD_D05 STMP3XXX_PINID(1, 5)
-#define PINID_LCD_D06 STMP3XXX_PINID(1, 6)
-#define PINID_LCD_D07 STMP3XXX_PINID(1, 7)
-#define PINID_LCD_D08 STMP3XXX_PINID(1, 8)
-#define PINID_LCD_D09 STMP3XXX_PINID(1, 9)
-#define PINID_LCD_D10 STMP3XXX_PINID(1, 10)
-#define PINID_LCD_D11 STMP3XXX_PINID(1, 11)
-#define PINID_LCD_D12 STMP3XXX_PINID(1, 12)
-#define PINID_LCD_D13 STMP3XXX_PINID(1, 13)
-#define PINID_LCD_D14 STMP3XXX_PINID(1, 14)
-#define PINID_LCD_D15 STMP3XXX_PINID(1, 15)
-#define PINID_LCD_D16 STMP3XXX_PINID(1, 16)
-#define PINID_LCD_D17 STMP3XXX_PINID(1, 17)
-#define PINID_LCD_RESET STMP3XXX_PINID(1, 18)
-#define PINID_LCD_RS STMP3XXX_PINID(1, 19)
-#define PINID_LCD_WR STMP3XXX_PINID(1, 20)
-#define PINID_LCD_CS STMP3XXX_PINID(1, 21)
-#define PINID_LCD_DOTCK STMP3XXX_PINID(1, 22)
-#define PINID_LCD_ENABLE STMP3XXX_PINID(1, 23)
-#define PINID_LCD_HSYNC STMP3XXX_PINID(1, 24)
-#define PINID_LCD_VSYNC STMP3XXX_PINID(1, 25)
-#define PINID_PWM0 STMP3XXX_PINID(1, 26)
-#define PINID_PWM1 STMP3XXX_PINID(1, 27)
-#define PINID_PWM2 STMP3XXX_PINID(1, 28)
-#define PINID_PWM3 STMP3XXX_PINID(1, 29)
-#define PINID_PWM4 STMP3XXX_PINID(1, 30)
-
-/* Bank 2 */
-#define PINID_SSP1_CMD STMP3XXX_PINID(2, 0)
-#define PINID_SSP1_DETECT STMP3XXX_PINID(2, 1)
-#define PINID_SSP1_DATA0 STMP3XXX_PINID(2, 2)
-#define PINID_SSP1_DATA1 STMP3XXX_PINID(2, 3)
-#define PINID_SSP1_DATA2 STMP3XXX_PINID(2, 4)
-#define PINID_SSP1_DATA3 STMP3XXX_PINID(2, 5)
-#define PINID_SSP1_SCK STMP3XXX_PINID(2, 6)
-#define PINID_ROTARYA STMP3XXX_PINID(2, 7)
-#define PINID_ROTARYB STMP3XXX_PINID(2, 8)
-#define PINID_EMI_A00 STMP3XXX_PINID(2, 9)
-#define PINID_EMI_A01 STMP3XXX_PINID(2, 10)
-#define PINID_EMI_A02 STMP3XXX_PINID(2, 11)
-#define PINID_EMI_A03 STMP3XXX_PINID(2, 12)
-#define PINID_EMI_A04 STMP3XXX_PINID(2, 13)
-#define PINID_EMI_A05 STMP3XXX_PINID(2, 14)
-#define PINID_EMI_A06 STMP3XXX_PINID(2, 15)
-#define PINID_EMI_A07 STMP3XXX_PINID(2, 16)
-#define PINID_EMI_A08 STMP3XXX_PINID(2, 17)
-#define PINID_EMI_A09 STMP3XXX_PINID(2, 18)
-#define PINID_EMI_A10 STMP3XXX_PINID(2, 19)
-#define PINID_EMI_A11 STMP3XXX_PINID(2, 20)
-#define PINID_EMI_A12 STMP3XXX_PINID(2, 21)
-#define PINID_EMI_BA0 STMP3XXX_PINID(2, 22)
-#define PINID_EMI_BA1 STMP3XXX_PINID(2, 23)
-#define PINID_EMI_CASN STMP3XXX_PINID(2, 24)
-#define PINID_EMI_CE0N STMP3XXX_PINID(2, 25)
-#define PINID_EMI_CE1N STMP3XXX_PINID(2, 26)
-#define PINID_GPMI_CE1N STMP3XXX_PINID(2, 27)
-#define PINID_GPMI_CE0N STMP3XXX_PINID(2, 28)
-#define PINID_EMI_CKE STMP3XXX_PINID(2, 29)
-#define PINID_EMI_RASN STMP3XXX_PINID(2, 30)
-#define PINID_EMI_WEN STMP3XXX_PINID(2, 31)
-
-/* Bank 3 */
-#define PINID_EMI_D00 STMP3XXX_PINID(3, 0)
-#define PINID_EMI_D01 STMP3XXX_PINID(3, 1)
-#define PINID_EMI_D02 STMP3XXX_PINID(3, 2)
-#define PINID_EMI_D03 STMP3XXX_PINID(3, 3)
-#define PINID_EMI_D04 STMP3XXX_PINID(3, 4)
-#define PINID_EMI_D05 STMP3XXX_PINID(3, 5)
-#define PINID_EMI_D06 STMP3XXX_PINID(3, 6)
-#define PINID_EMI_D07 STMP3XXX_PINID(3, 7)
-#define PINID_EMI_D08 STMP3XXX_PINID(3, 8)
-#define PINID_EMI_D09 STMP3XXX_PINID(3, 9)
-#define PINID_EMI_D10 STMP3XXX_PINID(3, 10)
-#define PINID_EMI_D11 STMP3XXX_PINID(3, 11)
-#define PINID_EMI_D12 STMP3XXX_PINID(3, 12)
-#define PINID_EMI_D13 STMP3XXX_PINID(3, 13)
-#define PINID_EMI_D14 STMP3XXX_PINID(3, 14)
-#define PINID_EMI_D15 STMP3XXX_PINID(3, 15)
-#define PINID_EMI_DQM0 STMP3XXX_PINID(3, 16)
-#define PINID_EMI_DQM1 STMP3XXX_PINID(3, 17)
-#define PINID_EMI_DQS0 STMP3XXX_PINID(3, 18)
-#define PINID_EMI_DQS1 STMP3XXX_PINID(3, 19)
-#define PINID_EMI_CLK STMP3XXX_PINID(3, 20)
-#define PINID_EMI_CLKN STMP3XXX_PINID(3, 21)
-
-#endif /* __ASM_ARCH_PINS_H */
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-apbh.h b/arch/arm/mach-stmp378x/include/mach/regs-apbh.h
deleted file mode 100644
index dbcf85b6ac2a..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-apbh.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * stmp378x: APBH register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef _MACH_REGS_APBH
-#define _MACH_REGS_APBH
-
-#define REGS_APBH_BASE (STMP3XXX_REGS_BASE + 0x4000)
-#define REGS_APBH_PHYS 0x80004000
-#define REGS_APBH_SIZE 0x2000
-
-#define HW_APBH_CTRL0 0x0
-#define BM_APBH_CTRL0_RESET_CHANNEL 0x00FF0000
-#define BP_APBH_CTRL0_RESET_CHANNEL 16
-#define BM_APBH_CTRL0_CLKGATE 0x40000000
-#define BM_APBH_CTRL0_SFTRST 0x80000000
-
-#define HW_APBH_CTRL1 0x10
-#define BM_APBH_CTRL1_CH0_CMDCMPLT_IRQ 0x00000001
-#define BP_APBH_CTRL1_CH0_CMDCMPLT_IRQ 0
-
-#define HW_APBH_CTRL2 0x20
-
-#define HW_APBH_DEVSEL 0x30
-
-#define HW_APBH_CH0_NXTCMDAR (0x50 + 0 * 0x70)
-#define HW_APBH_CH1_NXTCMDAR (0x50 + 1 * 0x70)
-#define HW_APBH_CH2_NXTCMDAR (0x50 + 2 * 0x70)
-#define HW_APBH_CH3_NXTCMDAR (0x50 + 3 * 0x70)
-#define HW_APBH_CH4_NXTCMDAR (0x50 + 4 * 0x70)
-#define HW_APBH_CH5_NXTCMDAR (0x50 + 5 * 0x70)
-#define HW_APBH_CH6_NXTCMDAR (0x50 + 6 * 0x70)
-#define HW_APBH_CH7_NXTCMDAR (0x50 + 7 * 0x70)
-#define HW_APBH_CH8_NXTCMDAR (0x50 + 8 * 0x70)
-#define HW_APBH_CH9_NXTCMDAR (0x50 + 9 * 0x70)
-#define HW_APBH_CH10_NXTCMDAR (0x50 + 10 * 0x70)
-#define HW_APBH_CH11_NXTCMDAR (0x50 + 11 * 0x70)
-#define HW_APBH_CH12_NXTCMDAR (0x50 + 12 * 0x70)
-#define HW_APBH_CH13_NXTCMDAR (0x50 + 13 * 0x70)
-#define HW_APBH_CH14_NXTCMDAR (0x50 + 14 * 0x70)
-#define HW_APBH_CH15_NXTCMDAR (0x50 + 15 * 0x70)
-
-#define HW_APBH_CHn_NXTCMDAR 0x50
-
-#define BV_APBH_CHn_CMD_COMMAND__NO_DMA_XFER 0
-#define BV_APBH_CHn_CMD_COMMAND__DMA_WRITE 1
-#define BV_APBH_CHn_CMD_COMMAND__DMA_READ 2
-#define BV_APBH_CHn_CMD_COMMAND__DMA_SENSE 3
-#define BM_APBH_CHn_CMD_COMMAND 0x00000003
-#define BP_APBH_CHn_CMD_COMMAND 0
-#define BM_APBH_CHn_CMD_CHAIN 0x00000004
-#define BM_APBH_CHn_CMD_IRQONCMPLT 0x00000008
-#define BM_APBH_CHn_CMD_NANDLOCK 0x00000010
-#define BM_APBH_CHn_CMD_NANDWAIT4READY 0x00000020
-#define BM_APBH_CHn_CMD_SEMAPHORE 0x00000040
-#define BM_APBH_CHn_CMD_WAIT4ENDCMD 0x00000080
-#define BM_APBH_CHn_CMD_CMDWORDS 0x0000F000
-#define BP_APBH_CHn_CMD_CMDWORDS 12
-#define BM_APBH_CHn_CMD_XFER_COUNT 0xFFFF0000
-#define BP_APBH_CHn_CMD_XFER_COUNT 16
-
-#define HW_APBH_CH0_SEMA (0x80 + 0 * 0x70)
-#define HW_APBH_CH1_SEMA (0x80 + 1 * 0x70)
-#define HW_APBH_CH2_SEMA (0x80 + 2 * 0x70)
-#define HW_APBH_CH3_SEMA (0x80 + 3 * 0x70)
-#define HW_APBH_CH4_SEMA (0x80 + 4 * 0x70)
-#define HW_APBH_CH5_SEMA (0x80 + 5 * 0x70)
-#define HW_APBH_CH6_SEMA (0x80 + 6 * 0x70)
-#define HW_APBH_CH7_SEMA (0x80 + 7 * 0x70)
-#define HW_APBH_CH8_SEMA (0x80 + 8 * 0x70)
-#define HW_APBH_CH9_SEMA (0x80 + 9 * 0x70)
-#define HW_APBH_CH10_SEMA (0x80 + 10 * 0x70)
-#define HW_APBH_CH11_SEMA (0x80 + 11 * 0x70)
-#define HW_APBH_CH12_SEMA (0x80 + 12 * 0x70)
-#define HW_APBH_CH13_SEMA (0x80 + 13 * 0x70)
-#define HW_APBH_CH14_SEMA (0x80 + 14 * 0x70)
-#define HW_APBH_CH15_SEMA (0x80 + 15 * 0x70)
-
-#define HW_APBH_CHn_SEMA 0x80
-#define BM_APBH_CHn_SEMA_INCREMENT_SEMA 0x000000FF
-#define BP_APBH_CHn_SEMA_INCREMENT_SEMA 0
-#define BM_APBH_CHn_SEMA_PHORE 0x00FF0000
-#define BP_APBH_CHn_SEMA_PHORE 16
-
-#endif
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-apbx.h b/arch/arm/mach-stmp378x/include/mach/regs-apbx.h
deleted file mode 100644
index 3b934a4d27f0..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-apbx.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * stmp378x: APBX register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef _MACH_REGS_APBX
-#define _MACH_REGS_APBX
-
-#define REGS_APBX_BASE (STMP3XXX_REGS_BASE + 0x24000)
-#define REGS_APBX_PHYS 0x80024000
-#define REGS_APBX_SIZE 0x2000
-
-#define HW_APBX_CTRL0 0x0
-#define BM_APBX_CTRL0_CLKGATE 0x40000000
-#define BM_APBX_CTRL0_SFTRST 0x80000000
-
-#define HW_APBX_CTRL1 0x10
-
-#define HW_APBX_CTRL2 0x20
-
-#define HW_APBX_CHANNEL_CTRL 0x30
-#define BM_APBX_CHANNEL_CTRL_RESET_CHANNEL 0xFFFF0000
-#define BP_APBX_CHANNEL_CTRL_RESET_CHANNEL 16
-
-#define HW_APBX_DEVSEL 0x40
-
-#define HW_APBX_CH0_NXTCMDAR (0x110 + 0 * 0x70)
-#define HW_APBX_CH1_NXTCMDAR (0x110 + 1 * 0x70)
-#define HW_APBX_CH2_NXTCMDAR (0x110 + 2 * 0x70)
-#define HW_APBX_CH3_NXTCMDAR (0x110 + 3 * 0x70)
-#define HW_APBX_CH4_NXTCMDAR (0x110 + 4 * 0x70)
-#define HW_APBX_CH5_NXTCMDAR (0x110 + 5 * 0x70)
-#define HW_APBX_CH6_NXTCMDAR (0x110 + 6 * 0x70)
-#define HW_APBX_CH7_NXTCMDAR (0x110 + 7 * 0x70)
-#define HW_APBX_CH8_NXTCMDAR (0x110 + 8 * 0x70)
-#define HW_APBX_CH9_NXTCMDAR (0x110 + 9 * 0x70)
-#define HW_APBX_CH10_NXTCMDAR (0x110 + 10 * 0x70)
-#define HW_APBX_CH11_NXTCMDAR (0x110 + 11 * 0x70)
-#define HW_APBX_CH12_NXTCMDAR (0x110 + 12 * 0x70)
-#define HW_APBX_CH13_NXTCMDAR (0x110 + 13 * 0x70)
-#define HW_APBX_CH14_NXTCMDAR (0x110 + 14 * 0x70)
-#define HW_APBX_CH15_NXTCMDAR (0x110 + 15 * 0x70)
-
-#define HW_APBX_CHn_NXTCMDAR 0x110
-#define BM_APBX_CHn_CMD_COMMAND 0x00000003
-#define BP_APBX_CHn_CMD_COMMAND 0
-#define BV_APBX_CHn_CMD_COMMAND__NO_DMA_XFER 0
-#define BV_APBX_CHn_CMD_COMMAND__DMA_WRITE 1
-#define BV_APBX_CHn_CMD_COMMAND__DMA_READ 2
-#define BV_APBX_CHn_CMD_COMMAND__DMA_SENSE 3
-#define BM_APBX_CHn_CMD_CHAIN 0x00000004
-#define BM_APBX_CHn_CMD_IRQONCMPLT 0x00000008
-#define BM_APBX_CHn_CMD_SEMAPHORE 0x00000040
-#define BM_APBX_CHn_CMD_WAIT4ENDCMD 0x00000080
-#define BM_APBX_CHn_CMD_HALTONTERMINATE 0x00000100
-#define BM_APBX_CHn_CMD_CMDWORDS 0x0000F000
-#define BP_APBX_CHn_CMD_CMDWORDS 12
-#define BM_APBX_CHn_CMD_XFER_COUNT 0xFFFF0000
-#define BP_APBX_CHn_CMD_XFER_COUNT 16
-
-#define HW_APBX_CH0_BAR (0x130 + 0 * 0x70)
-#define HW_APBX_CH1_BAR (0x130 + 1 * 0x70)
-#define HW_APBX_CH2_BAR (0x130 + 2 * 0x70)
-#define HW_APBX_CH3_BAR (0x130 + 3 * 0x70)
-#define HW_APBX_CH4_BAR (0x130 + 4 * 0x70)
-#define HW_APBX_CH5_BAR (0x130 + 5 * 0x70)
-#define HW_APBX_CH6_BAR (0x130 + 6 * 0x70)
-#define HW_APBX_CH7_BAR (0x130 + 7 * 0x70)
-#define HW_APBX_CH8_BAR (0x130 + 8 * 0x70)
-#define HW_APBX_CH9_BAR (0x130 + 9 * 0x70)
-#define HW_APBX_CH10_BAR (0x130 + 10 * 0x70)
-#define HW_APBX_CH11_BAR (0x130 + 11 * 0x70)
-#define HW_APBX_CH12_BAR (0x130 + 12 * 0x70)
-#define HW_APBX_CH13_BAR (0x130 + 13 * 0x70)
-#define HW_APBX_CH14_BAR (0x130 + 14 * 0x70)
-#define HW_APBX_CH15_BAR (0x130 + 15 * 0x70)
-
-#define HW_APBX_CHn_BAR 0x130
-
-#define HW_APBX_CH0_SEMA (0x140 + 0 * 0x70)
-#define HW_APBX_CH1_SEMA (0x140 + 1 * 0x70)
-#define HW_APBX_CH2_SEMA (0x140 + 2 * 0x70)
-#define HW_APBX_CH3_SEMA (0x140 + 3 * 0x70)
-#define HW_APBX_CH4_SEMA (0x140 + 4 * 0x70)
-#define HW_APBX_CH5_SEMA (0x140 + 5 * 0x70)
-#define HW_APBX_CH6_SEMA (0x140 + 6 * 0x70)
-#define HW_APBX_CH7_SEMA (0x140 + 7 * 0x70)
-#define HW_APBX_CH8_SEMA (0x140 + 8 * 0x70)
-#define HW_APBX_CH9_SEMA (0x140 + 9 * 0x70)
-#define HW_APBX_CH10_SEMA (0x140 + 10 * 0x70)
-#define HW_APBX_CH11_SEMA (0x140 + 11 * 0x70)
-#define HW_APBX_CH12_SEMA (0x140 + 12 * 0x70)
-#define HW_APBX_CH13_SEMA (0x140 + 13 * 0x70)
-#define HW_APBX_CH14_SEMA (0x140 + 14 * 0x70)
-#define HW_APBX_CH15_SEMA (0x140 + 15 * 0x70)
-
-#define HW_APBX_CHn_SEMA 0x140
-#define BM_APBX_CHn_SEMA_INCREMENT_SEMA 0x000000FF
-#define BP_APBX_CHn_SEMA_INCREMENT_SEMA 0
-#define BM_APBX_CHn_SEMA_PHORE 0x00FF0000
-#define BP_APBX_CHn_SEMA_PHORE 16
-
-#endif
-
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-audioin.h b/arch/arm/mach-stmp378x/include/mach/regs-audioin.h
deleted file mode 100644
index 641ac6126f83..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-audioin.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * stmp378x: AUDIOIN register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_AUDIOIN_BASE (STMP3XXX_REGS_BASE + 0x4C000)
-#define REGS_AUDIOIN_PHYS 0x8004C000
-#define REGS_AUDIOIN_SIZE 0x2000
-
-#define HW_AUDIOIN_CTRL 0x0
-#define BM_AUDIOIN_CTRL_RUN 0x00000001
-#define BP_AUDIOIN_CTRL_RUN 0
-#define BM_AUDIOIN_CTRL_FIFO_ERROR_IRQ_EN 0x00000002
-#define BM_AUDIOIN_CTRL_FIFO_OVERFLOW_IRQ 0x00000004
-#define BM_AUDIOIN_CTRL_FIFO_UNDERFLOW_IRQ 0x00000008
-#define BM_AUDIOIN_CTRL_WORD_LENGTH 0x00000020
-#define BM_AUDIOIN_CTRL_CLKGATE 0x40000000
-#define BM_AUDIOIN_CTRL_SFTRST 0x80000000
-
-#define HW_AUDIOIN_STAT 0x10
-
-#define HW_AUDIOIN_ADCSRR 0x20
-
-#define HW_AUDIOIN_ADCVOLUME 0x30
-#define BM_AUDIOIN_ADCVOLUME_VOLUME_RIGHT 0x000000FF
-#define BP_AUDIOIN_ADCVOLUME_VOLUME_RIGHT 0
-#define BM_AUDIOIN_ADCVOLUME_VOLUME_LEFT 0x00FF0000
-#define BP_AUDIOIN_ADCVOLUME_VOLUME_LEFT 16
-
-#define HW_AUDIOIN_ADCDEBUG 0x40
-
-#define HW_AUDIOIN_ADCVOL 0x50
-#define BM_AUDIOIN_ADCVOL_GAIN_RIGHT 0x0000000F
-#define BP_AUDIOIN_ADCVOL_GAIN_RIGHT 0
-#define BM_AUDIOIN_ADCVOL_SELECT_RIGHT 0x00000030
-#define BP_AUDIOIN_ADCVOL_SELECT_RIGHT 4
-#define BM_AUDIOIN_ADCVOL_GAIN_LEFT 0x00000F00
-#define BP_AUDIOIN_ADCVOL_GAIN_LEFT 8
-#define BM_AUDIOIN_ADCVOL_SELECT_LEFT 0x00003000
-#define BP_AUDIOIN_ADCVOL_SELECT_LEFT 12
-#define BM_AUDIOIN_ADCVOL_MUTE 0x01000000
-
-#define HW_AUDIOIN_MICLINE 0x60
-
-#define HW_AUDIOIN_ANACLKCTRL 0x70
-#define BM_AUDIOIN_ANACLKCTRL_CLKGATE 0x80000000
-
-#define HW_AUDIOIN_DATA 0x80
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-audioout.h b/arch/arm/mach-stmp378x/include/mach/regs-audioout.h
deleted file mode 100644
index f533e23694a0..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-audioout.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * stmp378x: AUDIOOUT register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_AUDIOOUT_BASE (STMP3XXX_REGS_BASE + 0x48000)
-#define REGS_AUDIOOUT_PHYS 0x80048000
-#define REGS_AUDIOOUT_SIZE 0x2000
-
-#define HW_AUDIOOUT_CTRL 0x0
-#define BM_AUDIOOUT_CTRL_RUN 0x00000001
-#define BP_AUDIOOUT_CTRL_RUN 0
-#define BM_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN 0x00000002
-#define BM_AUDIOOUT_CTRL_FIFO_OVERFLOW_IRQ 0x00000004
-#define BM_AUDIOOUT_CTRL_FIFO_UNDERFLOW_IRQ 0x00000008
-#define BM_AUDIOOUT_CTRL_WORD_LENGTH 0x00000040
-#define BM_AUDIOOUT_CTRL_CLKGATE 0x40000000
-#define BM_AUDIOOUT_CTRL_SFTRST 0x80000000
-
-#define HW_AUDIOOUT_STAT 0x10
-
-#define HW_AUDIOOUT_DACSRR 0x20
-#define BM_AUDIOOUT_DACSRR_SRC_FRAC 0x00001FFF
-#define BP_AUDIOOUT_DACSRR_SRC_FRAC 0
-#define BM_AUDIOOUT_DACSRR_SRC_INT 0x001F0000
-#define BP_AUDIOOUT_DACSRR_SRC_INT 16
-#define BM_AUDIOOUT_DACSRR_SRC_HOLD 0x07000000
-#define BP_AUDIOOUT_DACSRR_SRC_HOLD 24
-#define BM_AUDIOOUT_DACSRR_BASEMULT 0x70000000
-#define BP_AUDIOOUT_DACSRR_BASEMULT 28
-
-#define HW_AUDIOOUT_DACVOLUME 0x30
-#define BM_AUDIOOUT_DACVOLUME_MUTE_RIGHT 0x00000100
-#define BM_AUDIOOUT_DACVOLUME_MUTE_LEFT 0x01000000
-#define BM_AUDIOOUT_DACVOLUME_EN_ZCD 0x02000000
-
-#define HW_AUDIOOUT_DACDEBUG 0x40
-
-#define HW_AUDIOOUT_HPVOL 0x50
-#define BM_AUDIOOUT_HPVOL_MUTE 0x01000000
-#define BM_AUDIOOUT_HPVOL_EN_MSTR_ZCD 0x02000000
-
-#define HW_AUDIOOUT_PWRDN 0x70
-#define BM_AUDIOOUT_PWRDN_HEADPHONE 0x00000001
-#define BP_AUDIOOUT_PWRDN_HEADPHONE 0
-#define BM_AUDIOOUT_PWRDN_CAPLESS 0x00000010
-#define BM_AUDIOOUT_PWRDN_ADC 0x00000100
-#define BM_AUDIOOUT_PWRDN_DAC 0x00001000
-#define BM_AUDIOOUT_PWRDN_RIGHT_ADC 0x00010000
-#define BM_AUDIOOUT_PWRDN_SPEAKER 0x01000000
-
-#define HW_AUDIOOUT_REFCTRL 0x80
-#define BM_AUDIOOUT_REFCTRL_VAG_VAL 0x000000F0
-#define BP_AUDIOOUT_REFCTRL_VAG_VAL 4
-#define BM_AUDIOOUT_REFCTRL_ADC_REFVAL 0x00000F00
-#define BP_AUDIOOUT_REFCTRL_ADC_REFVAL 8
-#define BM_AUDIOOUT_REFCTRL_ADJ_VAG 0x00001000
-#define BM_AUDIOOUT_REFCTRL_ADJ_ADC 0x00002000
-#define BM_AUDIOOUT_REFCTRL_BIAS_CTRL 0x00030000
-#define BP_AUDIOOUT_REFCTRL_BIAS_CTRL 16
-#define BM_AUDIOOUT_REFCTRL_LOW_PWR 0x00080000
-#define BM_AUDIOOUT_REFCTRL_VBG_ADJ 0x00700000
-#define BP_AUDIOOUT_REFCTRL_VBG_ADJ 20
-#define BM_AUDIOOUT_REFCTRL_XTAL_BGR_BIAS 0x01000000
-#define BM_AUDIOOUT_REFCTRL_RAISE_REF 0x02000000
-
-#define HW_AUDIOOUT_ANACTRL 0x90
-#define BM_AUDIOOUT_ANACTRL_HP_CLASSAB 0x00000010
-#define BM_AUDIOOUT_ANACTRL_HP_HOLD_GND 0x00000020
-
-#define HW_AUDIOOUT_TEST 0xA0
-#define BM_AUDIOOUT_TEST_HP_I1_ADJ 0x00C00000
-#define BP_AUDIOOUT_TEST_HP_I1_ADJ 22
-
-#define HW_AUDIOOUT_BISTCTRL 0xB0
-
-#define HW_AUDIOOUT_BISTSTAT0 0xC0
-
-#define HW_AUDIOOUT_BISTSTAT1 0xD0
-
-#define HW_AUDIOOUT_ANACLKCTRL 0xE0
-#define BM_AUDIOOUT_ANACLKCTRL_CLKGATE 0x80000000
-
-#define HW_AUDIOOUT_DATA 0xF0
-
-#define HW_AUDIOOUT_SPEAKERCTRL 0x100
-#define BM_AUDIOOUT_SPEAKERCTRL_MUTE 0x01000000
-
-#define HW_AUDIOOUT_VERSION 0x200
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-bch.h b/arch/arm/mach-stmp378x/include/mach/regs-bch.h
deleted file mode 100644
index 532d24650717..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-bch.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * stmp378x: BCH register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_BCH_BASE (STMP3XXX_REGS_BASE + 0xA000)
-#define REGS_BCH_PHYS 0x8000A000
-#define REGS_BCH_SIZE 0x2000
-
-#define HW_BCH_CTRL 0x0
-#define BM_BCH_CTRL_COMPLETE_IRQ 0x00000001
-#define BP_BCH_CTRL_COMPLETE_IRQ 0
-#define BM_BCH_CTRL_COMPLETE_IRQ_EN 0x00000100
-
-#define HW_BCH_STATUS0 0x10
-#define BM_BCH_STATUS0_UNCORRECTABLE 0x00000004
-#define BM_BCH_STATUS0_CORRECTED 0x00000008
-#define BM_BCH_STATUS0_STATUS_BLK0 0x0000FF00
-#define BP_BCH_STATUS0_STATUS_BLK0 8
-#define BM_BCH_STATUS0_COMPLETED_CE 0x000F0000
-#define BP_BCH_STATUS0_COMPLETED_CE 16
-
-#define HW_BCH_LAYOUTSELECT 0x70
-
-#define HW_BCH_FLASH0LAYOUT0 0x80
-#define BM_BCH_FLASH0LAYOUT0_DATA0_SIZE 0x00000FFF
-#define BP_BCH_FLASH0LAYOUT0_DATA0_SIZE 0
-#define BM_BCH_FLASH0LAYOUT0_ECC0 0x0000F000
-#define BP_BCH_FLASH0LAYOUT0_ECC0 12
-#define BM_BCH_FLASH0LAYOUT0_META_SIZE 0x00FF0000
-#define BP_BCH_FLASH0LAYOUT0_META_SIZE 16
-#define BM_BCH_FLASH0LAYOUT0_NBLOCKS 0xFF000000
-#define BP_BCH_FLASH0LAYOUT0_NBLOCKS 24
-#define BM_BCH_FLASH0LAYOUT1_DATAN_SIZE 0x00000FFF
-#define BP_BCH_FLASH0LAYOUT1_DATAN_SIZE 0
-#define BM_BCH_FLASH0LAYOUT1_ECCN 0x0000F000
-#define BP_BCH_FLASH0LAYOUT1_ECCN 12
-#define BM_BCH_FLASH0LAYOUT1_PAGE_SIZE 0xFFFF0000
-#define BP_BCH_FLASH0LAYOUT1_PAGE_SIZE 16
-
-#define HW_BCH_BLOCKNAME 0x150
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-clkctrl.h b/arch/arm/mach-stmp378x/include/mach/regs-clkctrl.h
deleted file mode 100644
index 7c546afd57a3..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-clkctrl.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * stmp378x: CLKCTRL register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef _MACH_REGS_CLKCTRL
-#define _MACH_REGS_CLKCTRL
-
-#define REGS_CLKCTRL_BASE (STMP3XXX_REGS_BASE + 0x40000)
-#define REGS_CLKCTRL_PHYS 0x80040000
-#define REGS_CLKCTRL_SIZE 0x2000
-
-#define HW_CLKCTRL_PLLCTRL0 0x0
-#define BM_CLKCTRL_PLLCTRL0_EN_USB_CLKS 0x00040000
-
-#define HW_CLKCTRL_CPU 0x20
-#define BM_CLKCTRL_CPU_DIV_CPU 0x0000003F
-#define BP_CLKCTRL_CPU_DIV_CPU 0
-
-#define HW_CLKCTRL_HBUS 0x30
-#define BM_CLKCTRL_HBUS_DIV 0x0000001F
-#define BP_CLKCTRL_HBUS_DIV 0
-#define BM_CLKCTRL_HBUS_DIV_FRAC_EN 0x00000020
-
-#define HW_CLKCTRL_XBUS 0x40
-
-#define HW_CLKCTRL_XTAL 0x50
-#define BM_CLKCTRL_XTAL_DRI_CLK24M_GATE 0x10000000
-
-#define HW_CLKCTRL_PIX 0x60
-#define BM_CLKCTRL_PIX_DIV 0x00000FFF
-#define BP_CLKCTRL_PIX_DIV 0
-#define BM_CLKCTRL_PIX_CLKGATE 0x80000000
-
-#define HW_CLKCTRL_SSP 0x70
-
-#define HW_CLKCTRL_GPMI 0x80
-
-#define HW_CLKCTRL_SPDIF 0x90
-
-#define HW_CLKCTRL_EMI 0xA0
-#define BM_CLKCTRL_EMI_DIV_EMI 0x0000003F
-#define BP_CLKCTRL_EMI_DIV_EMI 0
-#define BM_CLKCTRL_EMI_DCC_RESYNC_ENABLE 0x00010000
-#define BM_CLKCTRL_EMI_BUSY_DCC_RESYNC 0x00020000
-#define BM_CLKCTRL_EMI_BUSY_REF_EMI 0x10000000
-#define BM_CLKCTRL_EMI_BUSY_REF_XTAL 0x20000000
-
-#define HW_CLKCTRL_IR 0xB0
-
-#define HW_CLKCTRL_SAIF 0xC0
-
-#define HW_CLKCTRL_TV 0xD0
-
-#define HW_CLKCTRL_ETM 0xE0
-
-#define HW_CLKCTRL_FRAC 0xF0
-#define BM_CLKCTRL_FRAC_EMIFRAC 0x00003F00
-#define BP_CLKCTRL_FRAC_EMIFRAC 8
-#define BM_CLKCTRL_FRAC_PIXFRAC 0x003F0000
-#define BP_CLKCTRL_FRAC_PIXFRAC 16
-#define BM_CLKCTRL_FRAC_CLKGATEPIX 0x00800000
-
-#define HW_CLKCTRL_FRAC1 0x100
-
-#define HW_CLKCTRL_CLKSEQ 0x110
-#define BM_CLKCTRL_CLKSEQ_BYPASS_PIX 0x00000002
-
-#define HW_CLKCTRL_RESET 0x120
-#define BM_CLKCTRL_RESET_DIG 0x00000001
-#define BP_CLKCTRL_RESET_DIG 0
-
-#endif
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-dcp.h b/arch/arm/mach-stmp378x/include/mach/regs-dcp.h
deleted file mode 100644
index fdedd00c0e28..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-dcp.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * stmp378x: DCP register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_DCP_BASE (STMP3XXX_REGS_BASE + 0x28000)
-#define REGS_DCP_PHYS 0x80028000
-#define REGS_DCP_SIZE 0x2000
-
-#define HW_DCP_CTRL 0x0
-#define BM_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE 0x000000FF
-#define BP_DCP_CTRL_CHANNEL_INTERRUPT_ENABLE 0
-#define BM_DCP_CTRL_ENABLE_CONTEXT_CACHING 0x00400000
-#define BM_DCP_CTRL_GATHER_RESIDUAL_WRITES 0x00800000
-#define BM_DCP_CTRL_CLKGATE 0x40000000
-#define BM_DCP_CTRL_SFTRST 0x80000000
-
-#define HW_DCP_STAT 0x10
-#define BM_DCP_STAT_IRQ 0x0000000F
-#define BP_DCP_STAT_IRQ 0
-
-#define HW_DCP_CHANNELCTRL 0x20
-#define BM_DCP_CHANNELCTRL_ENABLE_CHANNEL 0x000000FF
-#define BP_DCP_CHANNELCTRL_ENABLE_CHANNEL 0
-
-#define HW_DCP_CONTEXT 0x50
-#define BM_DCP_PACKET1_INTERRUPT 0x00000001
-#define BP_DCP_PACKET1_INTERRUPT 0
-#define BM_DCP_PACKET1_DECR_SEMAPHORE 0x00000002
-#define BM_DCP_PACKET1_CHAIN 0x00000004
-#define BM_DCP_PACKET1_CHAIN_CONTIGUOUS 0x00000008
-#define BM_DCP_PACKET1_ENABLE_CIPHER 0x00000020
-#define BM_DCP_PACKET1_ENABLE_HASH 0x00000040
-#define BM_DCP_PACKET1_CIPHER_ENCRYPT 0x00000100
-#define BM_DCP_PACKET1_CIPHER_INIT 0x00000200
-#define BM_DCP_PACKET1_OTP_KEY 0x00000400
-#define BM_DCP_PACKET1_PAYLOAD_KEY 0x00000800
-#define BM_DCP_PACKET1_HASH_INIT 0x00001000
-#define BM_DCP_PACKET1_HASH_TERM 0x00002000
-#define BM_DCP_PACKET2_CIPHER_SELECT 0x0000000F
-#define BP_DCP_PACKET2_CIPHER_SELECT 0
-#define BM_DCP_PACKET2_CIPHER_MODE 0x000000F0
-#define BP_DCP_PACKET2_CIPHER_MODE 4
-#define BM_DCP_PACKET2_KEY_SELECT 0x0000FF00
-#define BP_DCP_PACKET2_KEY_SELECT 8
-#define BM_DCP_PACKET2_HASH_SELECT 0x000F0000
-#define BP_DCP_PACKET2_HASH_SELECT 16
-#define BM_DCP_PACKET2_CIPHER_CFG 0xFF000000
-#define BP_DCP_PACKET2_CIPHER_CFG 24
-
-#define HW_DCP_CH0CMDPTR (0x100 + 0 * 0x40)
-#define HW_DCP_CH1CMDPTR (0x100 + 1 * 0x40)
-#define HW_DCP_CH2CMDPTR (0x100 + 2 * 0x40)
-#define HW_DCP_CH3CMDPTR (0x100 + 3 * 0x40)
-
-#define HW_DCP_CHnCMDPTR 0x100
-
-#define HW_DCP_CH0SEMA (0x110 + 0 * 0x40)
-#define HW_DCP_CH1SEMA (0x110 + 1 * 0x40)
-#define HW_DCP_CH2SEMA (0x110 + 2 * 0x40)
-#define HW_DCP_CH3SEMA (0x110 + 3 * 0x40)
-
-#define HW_DCP_CHnSEMA 0x110
-#define BM_DCP_CHnSEMA_INCREMENT 0x000000FF
-#define BP_DCP_CHnSEMA_INCREMENT 0
-
-#define HW_DCP_CH0STAT (0x120 + 0 * 0x40)
-#define HW_DCP_CH1STAT (0x120 + 1 * 0x40)
-#define HW_DCP_CH2STAT (0x120 + 2 * 0x40)
-#define HW_DCP_CH3STAT (0x120 + 3 * 0x40)
-
-#define HW_DCP_CHnSTAT 0x120
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-digctl.h b/arch/arm/mach-stmp378x/include/mach/regs-digctl.h
deleted file mode 100644
index 5293005523b3..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-digctl.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * stmp378x: DIGCTL register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_DIGCTL_BASE (STMP3XXX_REGS_BASE + 0x1C000)
-#define REGS_DIGCTL_PHYS 0x8001C000
-#define REGS_DIGCTL_SIZE 0x2000
-
-#define HW_DIGCTL_CTRL 0x0
-#define BM_DIGCTL_CTRL_USB_CLKGATE 0x00000004
-
-#define HW_DIGCTL_ARMCACHE 0x2B0
-#define BM_DIGCTL_ARMCACHE_ITAG_SS 0x00000003
-#define BP_DIGCTL_ARMCACHE_ITAG_SS 0
-#define BM_DIGCTL_ARMCACHE_DTAG_SS 0x00000030
-#define BP_DIGCTL_ARMCACHE_DTAG_SS 4
-#define BM_DIGCTL_ARMCACHE_CACHE_SS 0x00000300
-#define BP_DIGCTL_ARMCACHE_CACHE_SS 8
-#define BM_DIGCTL_ARMCACHE_DRTY_SS 0x00003000
-#define BP_DIGCTL_ARMCACHE_DRTY_SS 12
-#define BM_DIGCTL_ARMCACHE_VALID_SS 0x00030000
-#define BP_DIGCTL_ARMCACHE_VALID_SS 16
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-dram.h b/arch/arm/mach-stmp378x/include/mach/regs-dram.h
deleted file mode 100644
index 02851431677c..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-dram.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * stmp378x: DRAM register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_DRAM_BASE (STMP3XXX_REGS_BASE + 0xE0000)
-#define REGS_DRAM_PHYS 0x800E0000
-#define REGS_DRAM_SIZE 0x2000
-
-#define HW_DRAM_CTL06 0x18
-
-#define HW_DRAM_CTL08 0x20
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-dri.h b/arch/arm/mach-stmp378x/include/mach/regs-dri.h
deleted file mode 100644
index da25f7e397e5..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-dri.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * stmp378x: DRI register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_DRI_BASE (STMP3XXX_REGS_BASE + 0x74000)
-#define REGS_DRI_PHYS 0x80074000
-#define REGS_DRI_SIZE 0x2000
-
-#define HW_DRI_CTRL 0x0
-#define BM_DRI_CTRL_RUN 0x00000001
-#define BP_DRI_CTRL_RUN 0
-#define BM_DRI_CTRL_ATTENTION_IRQ 0x00000002
-#define BM_DRI_CTRL_PILOT_SYNC_LOSS_IRQ 0x00000004
-#define BM_DRI_CTRL_OVERFLOW_IRQ 0x00000008
-#define BM_DRI_CTRL_ATTENTION_IRQ_EN 0x00000200
-#define BM_DRI_CTRL_PILOT_SYNC_LOSS_IRQ_EN 0x00000400
-#define BM_DRI_CTRL_OVERFLOW_IRQ_EN 0x00000800
-#define BM_DRI_CTRL_REACQUIRE_PHASE 0x00008000
-#define BM_DRI_CTRL_STOP_ON_PILOT_ERROR 0x02000000
-#define BM_DRI_CTRL_STOP_ON_OFLOW_ERROR 0x04000000
-#define BM_DRI_CTRL_ENABLE_INPUTS 0x20000000
-#define BM_DRI_CTRL_CLKGATE 0x40000000
-#define BM_DRI_CTRL_SFTRST 0x80000000
-
-#define HW_DRI_TIMING 0x10
-#define BM_DRI_TIMING_GAP_DETECTION_INTERVAL 0x000000FF
-#define BP_DRI_TIMING_GAP_DETECTION_INTERVAL 0
-#define BM_DRI_TIMING_PILOT_REP_RATE 0x000F0000
-#define BP_DRI_TIMING_PILOT_REP_RATE 16
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-ecc8.h b/arch/arm/mach-stmp378x/include/mach/regs-ecc8.h
deleted file mode 100644
index cc353bec331b..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-ecc8.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * stmp378x: ECC8 register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_ECC8_BASE (STMP3XXX_REGS_BASE + 0x8000)
-#define REGS_ECC8_PHYS 0x80008000
-#define REGS_ECC8_SIZE 0x2000
-
-#define HW_ECC8_CTRL 0x0
-#define BM_ECC8_CTRL_COMPLETE_IRQ 0x00000001
-#define BP_ECC8_CTRL_COMPLETE_IRQ 0
-#define BM_ECC8_CTRL_COMPLETE_IRQ_EN 0x00000100
-#define BM_ECC8_CTRL_AHBM_SFTRST 0x20000000
-
-#define HW_ECC8_STATUS0 0x10
-#define BM_ECC8_STATUS0_UNCORRECTABLE 0x00000004
-#define BM_ECC8_STATUS0_CORRECTED 0x00000008
-#define BM_ECC8_STATUS0_STATUS_AUX 0x00000F00
-#define BP_ECC8_STATUS0_STATUS_AUX 8
-#define BM_ECC8_STATUS0_COMPLETED_CE 0x000F0000
-#define BP_ECC8_STATUS0_COMPLETED_CE 16
-
-#define HW_ECC8_STATUS1 0x20
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-emi.h b/arch/arm/mach-stmp378x/include/mach/regs-emi.h
deleted file mode 100644
index 98773fc33d7b..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-emi.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * stmp378x: EMI register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_EMI_BASE (STMP3XXX_REGS_BASE + 0x20000)
-#define REGS_EMI_PHYS 0x80020000
-#define REGS_EMI_SIZE 0x2000
-
-#define HW_EMI_STAT 0x10
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-gpmi.h b/arch/arm/mach-stmp378x/include/mach/regs-gpmi.h
deleted file mode 100644
index 2cc8bbe91687..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-gpmi.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * stmp378x: GPMI register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_GPMI_BASE (STMP3XXX_REGS_BASE + 0xC000)
-#define REGS_GPMI_PHYS 0x8000C000
-#define REGS_GPMI_SIZE 0x2000
-
-#define HW_GPMI_CTRL0 0x0
-#define BM_GPMI_CTRL0_XFER_COUNT 0x0000FFFF
-#define BP_GPMI_CTRL0_XFER_COUNT 0
-#define BM_GPMI_CTRL0_CS 0x00300000
-#define BP_GPMI_CTRL0_CS 20
-#define BM_GPMI_CTRL0_LOCK_CS 0x00400000
-#define BM_GPMI_CTRL0_WORD_LENGTH 0x00800000
-#define BM_GPMI_CTRL0_ADDRESS 0x000E0000
-#define BP_GPMI_CTRL0_ADDRESS 17
-#define BV_GPMI_CTRL0_ADDRESS__NAND_DATA 0x0
-#define BV_GPMI_CTRL0_ADDRESS__NAND_CLE 0x1
-#define BV_GPMI_CTRL0_ADDRESS__NAND_ALE 0x2
-#define BM_GPMI_CTRL0_ADDRESS_INCREMENT 0x00010000
-#define BM_GPMI_CTRL0_COMMAND_MODE 0x03000000
-#define BP_GPMI_CTRL0_COMMAND_MODE 24
-#define BV_GPMI_CTRL0_COMMAND_MODE__WRITE 0x0
-#define BV_GPMI_CTRL0_COMMAND_MODE__READ 0x1
-#define BV_GPMI_CTRL0_COMMAND_MODE__READ_AND_COMPARE 0x2
-#define BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY 0x3
-#define BM_GPMI_CTRL0_RUN 0x20000000
-#define BM_GPMI_CTRL0_CLKGATE 0x40000000
-#define BM_GPMI_CTRL0_SFTRST 0x80000000
-#define BM_GPMI_ECCCTRL_BUFFER_MASK 0x000001FF
-#define BP_GPMI_ECCCTRL_BUFFER_MASK 0
-#define BM_GPMI_ECCCTRL_ENABLE_ECC 0x00001000
-#define BM_GPMI_ECCCTRL_ECC_CMD 0x00006000
-#define BP_GPMI_ECCCTRL_ECC_CMD 13
-#define BV_GPMI_ECCCTRL_ECC_CMD__DECODE_4_BIT 0
-#define BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_4_BIT 1
-#define BV_GPMI_ECCCTRL_ECC_CMD__DECODE_8_BIT 2
-#define BV_GPMI_ECCCTRL_ECC_CMD__ENCODE_8_BIT 3
-
-#define HW_GPMI_CTRL1 0x60
-#define BM_GPMI_CTRL1_GPMI_MODE 0x00000001
-#define BP_GPMI_CTRL1_GPMI_MODE 0
-#define BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY 0x00000004
-#define BM_GPMI_CTRL1_DEV_RESET 0x00000008
-#define BM_GPMI_CTRL1_TIMEOUT_IRQ 0x00000200
-#define BM_GPMI_CTRL1_DEV_IRQ 0x00000400
-#define BM_GPMI_CTRL1_RDN_DELAY 0x0000F000
-#define BP_GPMI_CTRL1_RDN_DELAY 12
-#define BM_GPMI_CTRL1_BCH_MODE 0x00040000
-
-#define HW_GPMI_TIMING0 0x70
-#define BM_GPMI_TIMING0_DATA_SETUP 0x000000FF
-#define BP_GPMI_TIMING0_DATA_SETUP 0
-#define BM_GPMI_TIMING0_DATA_HOLD 0x0000FF00
-#define BP_GPMI_TIMING0_DATA_HOLD 8
-#define BM_GPMI_TIMING0_ADDRESS_SETUP 0x00FF0000
-#define BP_GPMI_TIMING0_ADDRESS_SETUP 16
-
-#define HW_GPMI_TIMING1 0x80
-#define BM_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT 0xFFFF0000
-#define BP_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT 16
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-i2c.h b/arch/arm/mach-stmp378x/include/mach/regs-i2c.h
deleted file mode 100644
index 13a234c99433..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-i2c.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * stmp378x: I2C register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_I2C_BASE (STMP3XXX_REGS_BASE + 0x58000)
-#define REGS_I2C_PHYS 0x80058000
-#define REGS_I2C_SIZE 0x2000
-
-#define HW_I2C_CTRL0 0x0
-#define BM_I2C_CTRL0_XFER_COUNT 0x0000FFFF
-#define BP_I2C_CTRL0_XFER_COUNT 0
-#define BM_I2C_CTRL0_DIRECTION 0x00010000
-#define BM_I2C_CTRL0_MASTER_MODE 0x00020000
-#define BM_I2C_CTRL0_PRE_SEND_START 0x00080000
-#define BM_I2C_CTRL0_POST_SEND_STOP 0x00100000
-#define BM_I2C_CTRL0_RETAIN_CLOCK 0x00200000
-#define BM_I2C_CTRL0_SEND_NAK_ON_LAST 0x02000000
-#define BM_I2C_CTRL0_CLKGATE 0x40000000
-#define BM_I2C_CTRL0_SFTRST 0x80000000
-
-#define HW_I2C_TIMING0 0x10
-
-#define HW_I2C_TIMING1 0x20
-
-#define HW_I2C_TIMING2 0x30
-
-#define HW_I2C_CTRL1 0x40
-#define BM_I2C_CTRL1_SLAVE_IRQ 0x00000001
-#define BP_I2C_CTRL1_SLAVE_IRQ 0
-#define BM_I2C_CTRL1_SLAVE_STOP_IRQ 0x00000002
-#define BM_I2C_CTRL1_MASTER_LOSS_IRQ 0x00000004
-#define BM_I2C_CTRL1_EARLY_TERM_IRQ 0x00000008
-#define BM_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ 0x00000010
-#define BM_I2C_CTRL1_NO_SLAVE_ACK_IRQ 0x00000020
-#define BM_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ 0x00000040
-#define BM_I2C_CTRL1_BUS_FREE_IRQ 0x00000080
-#define BM_I2C_CTRL1_CLR_GOT_A_NAK 0x10000000
-
-#define HW_I2C_VERSION 0x90
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-icoll.h b/arch/arm/mach-stmp378x/include/mach/regs-icoll.h
deleted file mode 100644
index f996e80f40e7..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-icoll.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * stmp378x: ICOLL register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef _MACH_REGS_ICOLL
-#define _MACH_REGS_ICOLL
-
-#define REGS_ICOLL_BASE (STMP3XXX_REGS_BASE + 0x0)
-#define REGS_ICOLL_PHYS 0x80000000
-#define REGS_ICOLL_SIZE 0x2000
-
-#define HW_ICOLL_VECTOR 0x0
-
-#define HW_ICOLL_LEVELACK 0x10
-#define BM_ICOLL_LEVELACK_IRQLEVELACK 0x0000000F
-#define BP_ICOLL_LEVELACK_IRQLEVELACK 0
-
-#define HW_ICOLL_CTRL 0x20
-#define BM_ICOLL_CTRL_CLKGATE 0x40000000
-#define BM_ICOLL_CTRL_SFTRST 0x80000000
-
-#define HW_ICOLL_STAT 0x70
-
-#define HW_ICOLL_INTERRUPTn 0x120
-
-#define HW_ICOLL_INTERRUPTn 0x120
-#define BM_ICOLL_INTERRUPTn_ENABLE 0x00000004
-
-#endif
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-ir.h b/arch/arm/mach-stmp378x/include/mach/regs-ir.h
deleted file mode 100644
index a5b4ef10fab8..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-ir.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * stmp378x: IR register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_IR_BASE (STMP3XXX_REGS_BASE + 0x78000)
-#define REGS_IR_PHYS 0x80078000
-#define REGS_IR_SIZE 0x2000
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-lcdif.h b/arch/arm/mach-stmp378x/include/mach/regs-lcdif.h
deleted file mode 100644
index 9cdbef4badc3..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-lcdif.h
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * stmp378x: LCDIF register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_LCDIF_BASE (STMP3XXX_REGS_BASE + 0x30000)
-#define REGS_LCDIF_PHYS 0x80030000
-#define REGS_LCDIF_SIZE 0x2000
-
-#define HW_LCDIF_CTRL 0x0
-#define BM_LCDIF_CTRL_RUN 0x00000001
-#define BP_LCDIF_CTRL_RUN 0
-#define BM_LCDIF_CTRL_LCDIF_MASTER 0x00000020
-#define BM_LCDIF_CTRL_RGB_TO_YCBCR422_CSC 0x00000080
-#define BM_LCDIF_CTRL_WORD_LENGTH 0x00000300
-#define BP_LCDIF_CTRL_WORD_LENGTH 8
-#define BM_LCDIF_CTRL_LCD_DATABUS_WIDTH 0x00000C00
-#define BP_LCDIF_CTRL_LCD_DATABUS_WIDTH 10
-#define BM_LCDIF_CTRL_INPUT_DATA_SWIZZLE 0x0000C000
-#define BP_LCDIF_CTRL_INPUT_DATA_SWIZZLE 14
-#define BM_LCDIF_CTRL_DATA_SELECT 0x00010000
-#define BM_LCDIF_CTRL_DOTCLK_MODE 0x00020000
-#define BM_LCDIF_CTRL_VSYNC_MODE 0x00040000
-#define BM_LCDIF_CTRL_BYPASS_COUNT 0x00080000
-#define BM_LCDIF_CTRL_DVI_MODE 0x00100000
-#define BM_LCDIF_CTRL_SHIFT_NUM_BITS 0x03E00000
-#define BP_LCDIF_CTRL_SHIFT_NUM_BITS 21
-#define BM_LCDIF_CTRL_DATA_SHIFT_DIR 0x04000000
-#define BM_LCDIF_CTRL_WAIT_FOR_VSYNC_EDGE 0x08000000
-#define BM_LCDIF_CTRL_CLKGATE 0x40000000
-#define BM_LCDIF_CTRL_SFTRST 0x80000000
-
-#define HW_LCDIF_CTRL1 0x10
-#define BM_LCDIF_CTRL1_RESET 0x00000001
-#define BP_LCDIF_CTRL1_RESET 0
-#define BM_LCDIF_CTRL1_MODE86 0x00000002
-#define BM_LCDIF_CTRL1_BUSY_ENABLE 0x00000004
-#define BM_LCDIF_CTRL1_VSYNC_EDGE_IRQ 0x00000100
-#define BM_LCDIF_CTRL1_CUR_FRAME_DONE_IRQ 0x00000200
-#define BM_LCDIF_CTRL1_UNDERFLOW_IRQ 0x00000400
-#define BM_LCDIF_CTRL1_OVERFLOW_IRQ 0x00000800
-#define BM_LCDIF_CTRL1_VSYNC_EDGE_IRQ_EN 0x00001000
-#define BM_LCDIF_CTRL1_BYTE_PACKING_FORMAT 0x000F0000
-#define BP_LCDIF_CTRL1_BYTE_PACKING_FORMAT 16
-#define BM_LCDIF_CTRL1_INTERLACE_FIELDS 0x00800000
-#define BM_LCDIF_CTRL1_RECOVER_ON_UNDERFLOW 0x01000000
-
-#define HW_LCDIF_TRANSFER_COUNT 0x20
-#define BM_LCDIF_TRANSFER_COUNT_H_COUNT 0x0000FFFF
-#define BP_LCDIF_TRANSFER_COUNT_H_COUNT 0
-#define BM_LCDIF_TRANSFER_COUNT_V_COUNT 0xFFFF0000
-#define BP_LCDIF_TRANSFER_COUNT_V_COUNT 16
-
-#define HW_LCDIF_CUR_BUF 0x30
-
-#define HW_LCDIF_NEXT_BUF 0x40
-
-#define HW_LCDIF_TIMING 0x60
-
-#define HW_LCDIF_VDCTRL0 0x70
-#define BM_LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH 0x0003FFFF
-#define BP_LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH 0
-#define BM_LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT 0x00100000
-#define BM_LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT 0x00200000
-#define BM_LCDIF_VDCTRL0_ENABLE_POL 0x01000000
-#define BM_LCDIF_VDCTRL0_DOTCLK_POL 0x02000000
-#define BM_LCDIF_VDCTRL0_HSYNC_POL 0x04000000
-#define BM_LCDIF_VDCTRL0_VSYNC_POL 0x08000000
-#define BM_LCDIF_VDCTRL0_ENABLE_PRESENT 0x10000000
-#define BM_LCDIF_VDCTRL0_VSYNC_OEB 0x20000000
-
-#define HW_LCDIF_VDCTRL1 0x80
-#define BM_LCDIF_VDCTRL1_VSYNC_PERIOD 0xFFFFFFFF
-#define BP_LCDIF_VDCTRL1_VSYNC_PERIOD 0
-
-#define HW_LCDIF_VDCTRL2 0x90
-#define BM_LCDIF_VDCTRL2_HSYNC_PERIOD 0x0003FFFF
-#define BP_LCDIF_VDCTRL2_HSYNC_PERIOD 0
-#define BM_LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH 0xFF000000
-#define BP_LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH 24
-
-#define HW_LCDIF_VDCTRL3 0xA0
-#define BM_LCDIF_VDCTRL3_VERTICAL_WAIT_CNT 0x0000FFFF
-#define BP_LCDIF_VDCTRL3_VERTICAL_WAIT_CNT 0
-#define BM_LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT 0x0FFF0000
-#define BP_LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT 16
-
-#define HW_LCDIF_VDCTRL4 0xB0
-#define BM_LCDIF_VDCTRL4_DOTCLK_H_VALID_DATA_CNT 0x0003FFFF
-#define BP_LCDIF_VDCTRL4_DOTCLK_H_VALID_DATA_CNT 0
-#define BM_LCDIF_VDCTRL4_SYNC_SIGNALS_ON 0x00040000
-
-#define HW_LCDIF_DVICTRL0 0xC0
-#define BM_LCDIF_DVICTRL0_V_LINES_CNT 0x000003FF
-#define BP_LCDIF_DVICTRL0_V_LINES_CNT 0
-#define BM_LCDIF_DVICTRL0_H_BLANKING_CNT 0x000FFC00
-#define BP_LCDIF_DVICTRL0_H_BLANKING_CNT 10
-#define BM_LCDIF_DVICTRL0_H_ACTIVE_CNT 0x7FF00000
-#define BP_LCDIF_DVICTRL0_H_ACTIVE_CNT 20
-
-#define HW_LCDIF_DVICTRL1 0xD0
-#define BM_LCDIF_DVICTRL1_F2_START_LINE 0x000003FF
-#define BP_LCDIF_DVICTRL1_F2_START_LINE 0
-#define BM_LCDIF_DVICTRL1_F1_END_LINE 0x000FFC00
-#define BP_LCDIF_DVICTRL1_F1_END_LINE 10
-#define BM_LCDIF_DVICTRL1_F1_START_LINE 0x3FF00000
-#define BP_LCDIF_DVICTRL1_F1_START_LINE 20
-
-#define HW_LCDIF_DVICTRL2 0xE0
-#define BM_LCDIF_DVICTRL2_V1_BLANK_END_LINE 0x000003FF
-#define BP_LCDIF_DVICTRL2_V1_BLANK_END_LINE 0
-#define BM_LCDIF_DVICTRL2_V1_BLANK_START_LINE 0x000FFC00
-#define BP_LCDIF_DVICTRL2_V1_BLANK_START_LINE 10
-#define BM_LCDIF_DVICTRL2_F2_END_LINE 0x3FF00000
-#define BP_LCDIF_DVICTRL2_F2_END_LINE 20
-
-#define HW_LCDIF_DVICTRL3 0xF0
-#define BM_LCDIF_DVICTRL3_V2_BLANK_END_LINE 0x000003FF
-#define BP_LCDIF_DVICTRL3_V2_BLANK_END_LINE 0
-#define BM_LCDIF_DVICTRL3_V2_BLANK_START_LINE 0x03FF0000
-#define BP_LCDIF_DVICTRL3_V2_BLANK_START_LINE 16
-
-#define HW_LCDIF_DVICTRL4 0x100
-#define BM_LCDIF_DVICTRL4_H_FILL_CNT 0x000000FF
-#define BP_LCDIF_DVICTRL4_H_FILL_CNT 0
-#define BM_LCDIF_DVICTRL4_CR_FILL_VALUE 0x0000FF00
-#define BP_LCDIF_DVICTRL4_CR_FILL_VALUE 8
-#define BM_LCDIF_DVICTRL4_CB_FILL_VALUE 0x00FF0000
-#define BP_LCDIF_DVICTRL4_CB_FILL_VALUE 16
-#define BM_LCDIF_DVICTRL4_Y_FILL_VALUE 0xFF000000
-#define BP_LCDIF_DVICTRL4_Y_FILL_VALUE 24
-
-#define HW_LCDIF_CSC_COEFF0 0x110
-#define BM_LCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER 0x00000003
-#define BP_LCDIF_CSC_COEFF0_CSC_SUBSAMPLE_FILTER 0
-#define BM_LCDIF_CSC_COEFF0_C0 0x03FF0000
-#define BP_LCDIF_CSC_COEFF0_C0 16
-
-#define HW_LCDIF_CSC_COEFF1 0x120
-#define BM_LCDIF_CSC_COEFF1_C1 0x000003FF
-#define BP_LCDIF_CSC_COEFF1_C1 0
-#define BM_LCDIF_CSC_COEFF1_C2 0x03FF0000
-#define BP_LCDIF_CSC_COEFF1_C2 16
-
-#define HW_LCDIF_CSC_COEFF2 0x130
-#define BM_LCDIF_CSC_COEFF2_C3 0x000003FF
-#define BP_LCDIF_CSC_COEFF2_C3 0
-#define BM_LCDIF_CSC_COEFF2_C4 0x03FF0000
-#define BP_LCDIF_CSC_COEFF2_C4 16
-
-#define HW_LCDIF_CSC_COEFF3 0x140
-#define BM_LCDIF_CSC_COEFF3_C5 0x000003FF
-#define BP_LCDIF_CSC_COEFF3_C5 0
-#define BM_LCDIF_CSC_COEFF3_C6 0x03FF0000
-#define BP_LCDIF_CSC_COEFF3_C6 16
-
-#define HW_LCDIF_CSC_COEFF4 0x150
-#define BM_LCDIF_CSC_COEFF4_C7 0x000003FF
-#define BP_LCDIF_CSC_COEFF4_C7 0
-#define BM_LCDIF_CSC_COEFF4_C8 0x03FF0000
-#define BP_LCDIF_CSC_COEFF4_C8 16
-
-#define HW_LCDIF_CSC_OFFSET 0x160
-#define BM_LCDIF_CSC_OFFSET_Y_OFFSET 0x000001FF
-#define BP_LCDIF_CSC_OFFSET_Y_OFFSET 0
-#define BM_LCDIF_CSC_OFFSET_CBCR_OFFSET 0x01FF0000
-#define BP_LCDIF_CSC_OFFSET_CBCR_OFFSET 16
-
-#define HW_LCDIF_CSC_LIMIT 0x170
-#define BM_LCDIF_CSC_LIMIT_Y_MAX 0x000000FF
-#define BP_LCDIF_CSC_LIMIT_Y_MAX 0
-#define BM_LCDIF_CSC_LIMIT_Y_MIN 0x0000FF00
-#define BP_LCDIF_CSC_LIMIT_Y_MIN 8
-#define BM_LCDIF_CSC_LIMIT_CBCR_MAX 0x00FF0000
-#define BP_LCDIF_CSC_LIMIT_CBCR_MAX 16
-#define BM_LCDIF_CSC_LIMIT_CBCR_MIN 0xFF000000
-#define BP_LCDIF_CSC_LIMIT_CBCR_MIN 24
-
-#define HW_LCDIF_STAT 0x1D0
-#define BM_LCDIF_STAT_TXFIFO_EMPTY 0x04000000
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-lradc.h b/arch/arm/mach-stmp378x/include/mach/regs-lradc.h
deleted file mode 100644
index cb8cb06f8277..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-lradc.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * stmp378x: LRADC register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_LRADC_BASE (STMP3XXX_REGS_BASE + 0x50000)
-#define REGS_LRADC_PHYS 0x80050000
-#define REGS_LRADC_SIZE 0x2000
-
-#define HW_LRADC_CTRL0 0x0
-#define BM_LRADC_CTRL0_SCHEDULE 0x000000FF
-#define BP_LRADC_CTRL0_SCHEDULE 0
-#define BM_LRADC_CTRL0_XPLUS_ENABLE 0x00010000
-#define BM_LRADC_CTRL0_YPLUS_ENABLE 0x00020000
-#define BM_LRADC_CTRL0_XMINUS_ENABLE 0x00040000
-#define BM_LRADC_CTRL0_YMINUS_ENABLE 0x00080000
-#define BM_LRADC_CTRL0_TOUCH_DETECT_ENABLE 0x00100000
-#define BM_LRADC_CTRL0_ONCHIP_GROUNDREF 0x00200000
-#define BM_LRADC_CTRL0_CLKGATE 0x40000000
-#define BM_LRADC_CTRL0_SFTRST 0x80000000
-
-#define HW_LRADC_CTRL1 0x10
-#define BM_LRADC_CTRL1_LRADC0_IRQ 0x00000001
-#define BP_LRADC_CTRL1_LRADC0_IRQ 0
-#define BM_LRADC_CTRL1_LRADC5_IRQ 0x00000020
-#define BM_LRADC_CTRL1_LRADC6_IRQ 0x00000040
-#define BM_LRADC_CTRL1_TOUCH_DETECT_IRQ 0x00000100
-#define BM_LRADC_CTRL1_LRADC0_IRQ_EN 0x00010000
-#define BM_LRADC_CTRL1_LRADC5_IRQ_EN 0x00200000
-#define BM_LRADC_CTRL1_TOUCH_DETECT_IRQ_EN 0x01000000
-
-#define HW_LRADC_CTRL2 0x20
-#define BM_LRADC_CTRL2_BL_BRIGHTNESS 0x001F0000
-#define BP_LRADC_CTRL2_BL_BRIGHTNESS 16
-#define BM_LRADC_CTRL2_BL_MUX_SELECT 0x00200000
-#define BM_LRADC_CTRL2_BL_ENABLE 0x00400000
-#define BM_LRADC_CTRL2_DIVIDE_BY_TWO 0xFF000000
-#define BP_LRADC_CTRL2_DIVIDE_BY_TWO 24
-
-#define HW_LRADC_CTRL3 0x30
-#define BM_LRADC_CTRL3_CYCLE_TIME 0x00000300
-#define BP_LRADC_CTRL3_CYCLE_TIME 8
-
-#define HW_LRADC_STATUS 0x40
-#define BM_LRADC_STATUS_TOUCH_DETECT_RAW 0x00000001
-#define BP_LRADC_STATUS_TOUCH_DETECT_RAW 0
-
-#define HW_LRADC_CH0 (0x50 + 0 * 0x10)
-#define HW_LRADC_CH1 (0x50 + 1 * 0x10)
-#define HW_LRADC_CH2 (0x50 + 2 * 0x10)
-#define HW_LRADC_CH3 (0x50 + 3 * 0x10)
-#define HW_LRADC_CH4 (0x50 + 4 * 0x10)
-#define HW_LRADC_CH5 (0x50 + 5 * 0x10)
-#define HW_LRADC_CH6 (0x50 + 6 * 0x10)
-#define HW_LRADC_CH7 (0x50 + 7 * 0x10)
-
-#define HW_LRADC_CHn 0x50
-#define BM_LRADC_CHn_VALUE 0x0003FFFF
-#define BP_LRADC_CHn_VALUE 0
-#define BM_LRADC_CHn_NUM_SAMPLES 0x1F000000
-#define BP_LRADC_CHn_NUM_SAMPLES 24
-#define BM_LRADC_CHn_ACCUMULATE 0x20000000
-
-#define HW_LRADC_DELAY0 (0xD0 + 0 * 0x10)
-#define HW_LRADC_DELAY1 (0xD0 + 1 * 0x10)
-#define HW_LRADC_DELAY2 (0xD0 + 2 * 0x10)
-#define HW_LRADC_DELAY3 (0xD0 + 3 * 0x10)
-
-#define HW_LRADC_DELAYn 0xD0
-#define BM_LRADC_DELAYn_DELAY 0x000007FF
-#define BP_LRADC_DELAYn_DELAY 0
-#define BM_LRADC_DELAYn_LOOP_COUNT 0x0000F800
-#define BP_LRADC_DELAYn_LOOP_COUNT 11
-#define BM_LRADC_DELAYn_TRIGGER_DELAYS 0x000F0000
-#define BP_LRADC_DELAYn_TRIGGER_DELAYS 16
-#define BM_LRADC_DELAYn_KICK 0x00100000
-#define BM_LRADC_DELAYn_TRIGGER_LRADCS 0xFF000000
-#define BP_LRADC_DELAYn_TRIGGER_LRADCS 24
-
-#define HW_LRADC_CTRL4 0x140
-#define BM_LRADC_CTRL4_LRADC6SELECT 0x0F000000
-#define BP_LRADC_CTRL4_LRADC6SELECT 24
-#define BM_LRADC_CTRL4_LRADC7SELECT 0xF0000000
-#define BP_LRADC_CTRL4_LRADC7SELECT 28
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-ocotp.h b/arch/arm/mach-stmp378x/include/mach/regs-ocotp.h
deleted file mode 100644
index f0af64d9937e..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-ocotp.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * stmp378x: OCOTP register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_OCOTP_BASE (STMP3XXX_REGS_BASE + 0x2C000)
-#define REGS_OCOTP_PHYS 0x8002C000
-#define REGS_OCOTP_SIZE 0x2000
-
-#define HW_OCOTP_CTRL 0x0
-#define BM_OCOTP_CTRL_BUSY 0x00000100
-#define BM_OCOTP_CTRL_ERROR 0x00000200
-#define BM_OCOTP_CTRL_RD_BANK_OPEN 0x00001000
-#define BM_OCOTP_CTRL_RELOAD_SHADOWS 0x00002000
-#define BM_OCOTP_CTRL_WR_UNLOCK 0xFFFF0000
-#define BP_OCOTP_CTRL_WR_UNLOCK 16
-
-#define HW_OCOTP_DATA 0x10
-
-#define HW_OCOTP_CUST0 (0x20 + 0 * 0x10)
-#define HW_OCOTP_CUST1 (0x20 + 1 * 0x10)
-#define HW_OCOTP_CUST2 (0x20 + 2 * 0x10)
-#define HW_OCOTP_CUST3 (0x20 + 3 * 0x10)
-
-#define HW_OCOTP_CUSTn 0x20
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-pinctrl.h b/arch/arm/mach-stmp378x/include/mach/regs-pinctrl.h
deleted file mode 100644
index 50d90ea1b136..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-pinctrl.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * stmp378x: PINCTRL register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef _MACH_REGS_PINCTRL
-#define _MACH_REGS_PINCTRL
-
-#define REGS_PINCTRL_BASE (STMP3XXX_REGS_BASE + 0x18000)
-#define REGS_PINCTRL_PHYS 0x80018000
-#define REGS_PINCTRL_SIZE 0x2000
-
-#define HW_PINCTRL_MUXSEL0 0x100
-#define HW_PINCTRL_MUXSEL1 0x110
-#define HW_PINCTRL_MUXSEL2 0x120
-#define HW_PINCTRL_MUXSEL3 0x130
-#define HW_PINCTRL_MUXSEL4 0x140
-#define HW_PINCTRL_MUXSEL5 0x150
-#define HW_PINCTRL_MUXSEL6 0x160
-#define HW_PINCTRL_MUXSEL7 0x170
-
-#define HW_PINCTRL_DRIVE0 0x200
-#define HW_PINCTRL_DRIVE1 0x210
-#define HW_PINCTRL_DRIVE2 0x220
-#define HW_PINCTRL_DRIVE3 0x230
-#define HW_PINCTRL_DRIVE4 0x240
-#define HW_PINCTRL_DRIVE5 0x250
-#define HW_PINCTRL_DRIVE6 0x260
-#define HW_PINCTRL_DRIVE7 0x270
-#define HW_PINCTRL_DRIVE8 0x280
-#define HW_PINCTRL_DRIVE9 0x290
-#define HW_PINCTRL_DRIVE10 0x2A0
-#define HW_PINCTRL_DRIVE11 0x2B0
-#define HW_PINCTRL_DRIVE12 0x2C0
-#define HW_PINCTRL_DRIVE13 0x2D0
-#define HW_PINCTRL_DRIVE14 0x2E0
-
-#define HW_PINCTRL_PULL0 0x400
-#define HW_PINCTRL_PULL1 0x410
-#define HW_PINCTRL_PULL2 0x420
-#define HW_PINCTRL_PULL3 0x430
-
-#define HW_PINCTRL_DOUT0 0x500
-#define HW_PINCTRL_DOUT1 0x510
-#define HW_PINCTRL_DOUT2 0x520
-
-#define HW_PINCTRL_DIN0 0x600
-#define HW_PINCTRL_DIN1 0x610
-#define HW_PINCTRL_DIN2 0x620
-
-#define HW_PINCTRL_DOE0 0x700
-#define HW_PINCTRL_DOE1 0x710
-#define HW_PINCTRL_DOE2 0x720
-
-#define HW_PINCTRL_PIN2IRQ0 0x800
-#define HW_PINCTRL_PIN2IRQ1 0x810
-#define HW_PINCTRL_PIN2IRQ2 0x820
-
-#define HW_PINCTRL_IRQEN0 0x900
-#define HW_PINCTRL_IRQEN1 0x910
-#define HW_PINCTRL_IRQEN2 0x920
-
-#define HW_PINCTRL_IRQLEVEL0 0xA00
-#define HW_PINCTRL_IRQLEVEL1 0xA10
-#define HW_PINCTRL_IRQLEVEL2 0xA20
-
-#define HW_PINCTRL_IRQPOL0 0xB00
-#define HW_PINCTRL_IRQPOL1 0xB10
-#define HW_PINCTRL_IRQPOL2 0xB20
-
-#define HW_PINCTRL_IRQSTAT0 0xC00
-#define HW_PINCTRL_IRQSTAT1 0xC10
-#define HW_PINCTRL_IRQSTAT2 0xC20
-
-#endif
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-power.h b/arch/arm/mach-stmp378x/include/mach/regs-power.h
deleted file mode 100644
index e454c830f076..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-power.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * stmp378x: POWER register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef _MACH_REGS_POWER
-#define _MACH_REGS_POWER
-
-#define REGS_POWER_BASE (STMP3XXX_REGS_BASE + 0x44000)
-#define REGS_POWER_PHYS 0x80044000
-#define REGS_POWER_SIZE 0x2000
-
-#define HW_POWER_CTRL 0x0
-#define BM_POWER_CTRL_ENIRQ_VDD5V_GT_VDDIO 0x00000001
-#define BP_POWER_CTRL_ENIRQ_VDD5V_GT_VDDIO 0
-#define BM_POWER_CTRL_ENIRQ_PSWITCH 0x00020000
-#define BM_POWER_CTRL_PSWITCH_IRQ 0x00100000
-#define BM_POWER_CTRL_CLKGATE 0x40000000
-
-#define HW_POWER_5VCTRL 0x10
-#define BM_POWER_5VCTRL_ENABLE_LINREG_ILIMIT 0x00000040
-
-#define HW_POWER_MINPWR 0x20
-
-#define HW_POWER_CHARGE 0x30
-
-#define HW_POWER_VDDDCTRL 0x40
-
-#define HW_POWER_VDDACTRL 0x50
-
-#define HW_POWER_VDDIOCTRL 0x60
-#define BM_POWER_VDDIOCTRL_TRG 0x0000001F
-#define BP_POWER_VDDIOCTRL_TRG 0
-
-#define HW_POWER_STS 0xC0
-#define BM_POWER_STS_VBUSVALID 0x00000002
-#define BM_POWER_STS_BVALID 0x00000004
-#define BM_POWER_STS_AVALID 0x00000008
-#define BM_POWER_STS_DC_OK 0x00000200
-
-#define HW_POWER_RESET 0x100
-
-#define HW_POWER_DEBUG 0x110
-#define BM_POWER_DEBUG_BVALIDPIOLOCK 0x00000002
-#define BM_POWER_DEBUG_AVALIDPIOLOCK 0x00000004
-#define BM_POWER_DEBUG_VBUSVALIDPIOLOCK 0x00000008
-
-#endif
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-pwm.h b/arch/arm/mach-stmp378x/include/mach/regs-pwm.h
deleted file mode 100644
index 0d0f9e56ec77..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-pwm.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * stmp378x: PWM register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_PWM_BASE (STMP3XXX_REGS_BASE + 0x64000)
-#define REGS_PWM_PHYS 0x80064000
-#define REGS_PWM_SIZE 0x2000
-
-#define HW_PWM_CTRL 0x0
-#define BM_PWM_CTRL_PWM2_ENABLE 0x00000004
-#define BM_PWM_CTRL_PWM2_ANA_CTRL_ENABLE 0x00000020
-
-#define HW_PWM_ACTIVE0 (0x10 + 0 * 0x20)
-#define HW_PWM_ACTIVE1 (0x10 + 1 * 0x20)
-#define HW_PWM_ACTIVE2 (0x10 + 2 * 0x20)
-#define HW_PWM_ACTIVE3 (0x10 + 3 * 0x20)
-
-#define HW_PWM_ACTIVEn 0x10
-#define BM_PWM_ACTIVEn_ACTIVE 0x0000FFFF
-#define BP_PWM_ACTIVEn_ACTIVE 0
-#define BM_PWM_ACTIVEn_INACTIVE 0xFFFF0000
-#define BP_PWM_ACTIVEn_INACTIVE 16
-
-#define HW_PWM_PERIOD0 (0x20 + 0 * 0x20)
-#define HW_PWM_PERIOD1 (0x20 + 1 * 0x20)
-#define HW_PWM_PERIOD2 (0x20 + 2 * 0x20)
-#define HW_PWM_PERIOD3 (0x20 + 3 * 0x20)
-
-#define HW_PWM_PERIODn 0x20
-#define BM_PWM_PERIODn_PERIOD 0x0000FFFF
-#define BP_PWM_PERIODn_PERIOD 0
-#define BM_PWM_PERIODn_ACTIVE_STATE 0x00030000
-#define BP_PWM_PERIODn_ACTIVE_STATE 16
-#define BM_PWM_PERIODn_INACTIVE_STATE 0x000C0000
-#define BP_PWM_PERIODn_INACTIVE_STATE 18
-#define BM_PWM_PERIODn_CDIV 0x00700000
-#define BP_PWM_PERIODn_CDIV 20
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-pxp.h b/arch/arm/mach-stmp378x/include/mach/regs-pxp.h
deleted file mode 100644
index 54d297896de8..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-pxp.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * stmp378x: PXP register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_PXP_BASE (STMP3XXX_REGS_BASE + 0x2A000)
-#define REGS_PXP_PHYS 0x8002A000
-#define REGS_PXP_SIZE 0x2000
-
-#define HW_PXP_CTRL 0x0
-#define BM_PXP_CTRL_ENABLE 0x00000001
-#define BP_PXP_CTRL_ENABLE 0
-#define BM_PXP_CTRL_IRQ_ENABLE 0x00000002
-#define BM_PXP_CTRL_OUTPUT_RGB_FORMAT 0x000000F0
-#define BP_PXP_CTRL_OUTPUT_RGB_FORMAT 4
-#define BM_PXP_CTRL_ROTATE 0x00000300
-#define BP_PXP_CTRL_ROTATE 8
-#define BM_PXP_CTRL_HFLIP 0x00000400
-#define BM_PXP_CTRL_VFLIP 0x00000800
-#define BM_PXP_CTRL_S0_FORMAT 0x0000F000
-#define BP_PXP_CTRL_S0_FORMAT 12
-#define BM_PXP_CTRL_SCALE 0x00040000
-#define BM_PXP_CTRL_CROP 0x00080000
-
-#define HW_PXP_STAT 0x10
-#define BM_PXP_STAT_IRQ 0x00000001
-#define BP_PXP_STAT_IRQ 0
-
-#define HW_PXP_RGBBUF 0x20
-
-#define HW_PXP_RGBSIZE 0x40
-#define BM_PXP_RGBSIZE_HEIGHT 0x00000FFF
-#define BP_PXP_RGBSIZE_HEIGHT 0
-#define BM_PXP_RGBSIZE_WIDTH 0x00FFF000
-#define BP_PXP_RGBSIZE_WIDTH 12
-
-#define HW_PXP_S0BUF 0x50
-
-#define HW_PXP_S0UBUF 0x60
-
-#define HW_PXP_S0VBUF 0x70
-
-#define HW_PXP_S0PARAM 0x80
-#define BM_PXP_S0PARAM_HEIGHT 0x000000FF
-#define BP_PXP_S0PARAM_HEIGHT 0
-#define BM_PXP_S0PARAM_WIDTH 0x0000FF00
-#define BP_PXP_S0PARAM_WIDTH 8
-#define BM_PXP_S0PARAM_YBASE 0x00FF0000
-#define BP_PXP_S0PARAM_YBASE 16
-#define BM_PXP_S0PARAM_XBASE 0xFF000000
-#define BP_PXP_S0PARAM_XBASE 24
-
-#define HW_PXP_S0BACKGROUND 0x90
-
-#define HW_PXP_S0CROP 0xA0
-#define BM_PXP_S0CROP_HEIGHT 0x000000FF
-#define BP_PXP_S0CROP_HEIGHT 0
-#define BM_PXP_S0CROP_WIDTH 0x0000FF00
-#define BP_PXP_S0CROP_WIDTH 8
-#define BM_PXP_S0CROP_YBASE 0x00FF0000
-#define BP_PXP_S0CROP_YBASE 16
-#define BM_PXP_S0CROP_XBASE 0xFF000000
-#define BP_PXP_S0CROP_XBASE 24
-
-#define HW_PXP_S0SCALE 0xB0
-#define BM_PXP_S0SCALE_XSCALE 0x00003FFF
-#define BP_PXP_S0SCALE_XSCALE 0
-#define BM_PXP_S0SCALE_YSCALE 0x3FFF0000
-#define BP_PXP_S0SCALE_YSCALE 16
-
-#define HW_PXP_CSCCOEFF0 0xD0
-
-#define HW_PXP_CSCCOEFF1 0xE0
-
-#define HW_PXP_CSCCOEFF2 0xF0
-
-#define HW_PXP_S0COLORKEYLOW 0x180
-
-#define HW_PXP_S0COLORKEYHIGH 0x190
-
-#define HW_PXP_OL0 (0x200 + 0 * 0x40)
-#define HW_PXP_OL1 (0x200 + 1 * 0x40)
-#define HW_PXP_OL2 (0x200 + 2 * 0x40)
-#define HW_PXP_OL3 (0x200 + 3 * 0x40)
-#define HW_PXP_OL4 (0x200 + 4 * 0x40)
-#define HW_PXP_OL5 (0x200 + 5 * 0x40)
-#define HW_PXP_OL6 (0x200 + 6 * 0x40)
-#define HW_PXP_OL7 (0x200 + 7 * 0x40)
-
-#define HW_PXP_OLn 0x200
-
-#define HW_PXP_OL0SIZE (0x210 + 0 * 0x40)
-#define HW_PXP_OL1SIZE (0x210 + 1 * 0x40)
-#define HW_PXP_OL2SIZE (0x210 + 2 * 0x40)
-#define HW_PXP_OL3SIZE (0x210 + 3 * 0x40)
-#define HW_PXP_OL4SIZE (0x210 + 4 * 0x40)
-#define HW_PXP_OL5SIZE (0x210 + 5 * 0x40)
-#define HW_PXP_OL6SIZE (0x210 + 6 * 0x40)
-#define HW_PXP_OL7SIZE (0x210 + 7 * 0x40)
-
-#define HW_PXP_OLnSIZE 0x210
-#define BM_PXP_OLnSIZE_HEIGHT 0x000000FF
-#define BP_PXP_OLnSIZE_HEIGHT 0
-#define BM_PXP_OLnSIZE_WIDTH 0x0000FF00
-#define BP_PXP_OLnSIZE_WIDTH 8
-
-#define HW_PXP_OL0PARAM (0x220 + 0 * 0x40)
-#define HW_PXP_OL1PARAM (0x220 + 1 * 0x40)
-#define HW_PXP_OL2PARAM (0x220 + 2 * 0x40)
-#define HW_PXP_OL3PARAM (0x220 + 3 * 0x40)
-#define HW_PXP_OL4PARAM (0x220 + 4 * 0x40)
-#define HW_PXP_OL5PARAM (0x220 + 5 * 0x40)
-#define HW_PXP_OL6PARAM (0x220 + 6 * 0x40)
-#define HW_PXP_OL7PARAM (0x220 + 7 * 0x40)
-
-#define HW_PXP_OLnPARAM 0x220
-#define BM_PXP_OLnPARAM_ENABLE 0x00000001
-#define BP_PXP_OLnPARAM_ENABLE 0
-#define BM_PXP_OLnPARAM_ALPHA_CNTL 0x00000006
-#define BP_PXP_OLnPARAM_ALPHA_CNTL 1
-#define BM_PXP_OLnPARAM_ENABLE_COLORKEY 0x00000008
-#define BM_PXP_OLnPARAM_FORMAT 0x000000F0
-#define BP_PXP_OLnPARAM_FORMAT 4
-#define BM_PXP_OLnPARAM_ALPHA 0x0000FF00
-#define BP_PXP_OLnPARAM_ALPHA 8
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-rtc.h b/arch/arm/mach-stmp378x/include/mach/regs-rtc.h
deleted file mode 100644
index b8dbd6742d98..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-rtc.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * stmp378x: RTC register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_RTC_BASE (STMP3XXX_REGS_BASE + 0x5C000)
-#define REGS_RTC_PHYS 0x8005C000
-#define REGS_RTC_SIZE 0x2000
-
-#define HW_RTC_CTRL 0x0
-#define BM_RTC_CTRL_ALARM_IRQ_EN 0x00000001
-#define BP_RTC_CTRL_ALARM_IRQ_EN 0
-#define BM_RTC_CTRL_ONEMSEC_IRQ_EN 0x00000002
-#define BM_RTC_CTRL_ALARM_IRQ 0x00000004
-#define BM_RTC_CTRL_ONEMSEC_IRQ 0x00000008
-#define BM_RTC_CTRL_WATCHDOGEN 0x00000010
-
-#define HW_RTC_STAT 0x10
-#define BM_RTC_STAT_NEW_REGS 0x0000FF00
-#define BP_RTC_STAT_NEW_REGS 8
-#define BM_RTC_STAT_STALE_REGS 0x00FF0000
-#define BP_RTC_STAT_STALE_REGS 16
-#define BM_RTC_STAT_RTC_PRESENT 0x80000000
-
-#define HW_RTC_SECONDS 0x30
-
-#define HW_RTC_ALARM 0x40
-
-#define HW_RTC_WATCHDOG 0x50
-
-#define HW_RTC_PERSISTENT0 0x60
-#define BM_RTC_PERSISTENT0_ALARM_WAKE_EN 0x00000002
-#define BM_RTC_PERSISTENT0_ALARM_EN 0x00000004
-#define BM_RTC_PERSISTENT0_XTAL24MHZ_PWRUP 0x00000010
-#define BM_RTC_PERSISTENT0_XTAL32KHZ_PWRUP 0x00000020
-#define BM_RTC_PERSISTENT0_ALARM_WAKE 0x00000080
-#define BM_RTC_PERSISTENT0_SPARE_ANALOG 0xFFFC0000
-#define BP_RTC_PERSISTENT0_SPARE_ANALOG 18
-
-#define HW_RTC_PERSISTENT1 0x70
-#define BM_RTC_PERSISTENT1_GENERAL 0xFFFFFFFF
-#define BP_RTC_PERSISTENT1_GENERAL 0
-
-#define HW_RTC_VERSION 0xD0
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-spdif.h b/arch/arm/mach-stmp378x/include/mach/regs-spdif.h
deleted file mode 100644
index 801539848c28..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-spdif.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * stmp378x: SPDIF register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_SPDIF_BASE (STMP3XXX_REGS_BASE + 0x54000)
-#define REGS_SPDIF_PHYS 0x80054000
-#define REGS_SPDIF_SIZE 0x2000
-
-#define HW_SPDIF_CTRL 0x0
-#define BM_SPDIF_CTRL_RUN 0x00000001
-#define BP_SPDIF_CTRL_RUN 0
-#define BM_SPDIF_CTRL_FIFO_ERROR_IRQ_EN 0x00000002
-#define BM_SPDIF_CTRL_FIFO_OVERFLOW_IRQ 0x00000004
-#define BM_SPDIF_CTRL_FIFO_UNDERFLOW_IRQ 0x00000008
-#define BM_SPDIF_CTRL_WORD_LENGTH 0x00000010
-#define BM_SPDIF_CTRL_CLKGATE 0x40000000
-#define BM_SPDIF_CTRL_SFTRST 0x80000000
-
-#define HW_SPDIF_STAT 0x10
-
-#define HW_SPDIF_FRAMECTRL 0x20
-
-#define HW_SPDIF_SRR 0x30
-#define BM_SPDIF_SRR_RATE 0x000FFFFF
-#define BP_SPDIF_SRR_RATE 0
-#define BM_SPDIF_SRR_BASEMULT 0x70000000
-#define BP_SPDIF_SRR_BASEMULT 28
-
-#define HW_SPDIF_DEBUG 0x40
-
-#define HW_SPDIF_DATA 0x50
-
-#define HW_SPDIF_VERSION 0x60
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-ssp.h b/arch/arm/mach-stmp378x/include/mach/regs-ssp.h
deleted file mode 100644
index 28aacf0f58ed..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-ssp.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * stmp378x: SSP register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_SSP1_BASE (STMP3XXX_REGS_BASE + 0x10000)
-#define REGS_SSP1_PHYS 0x80010000
-#define REGS_SSP2_BASE (STMP3XXX_REGS_BASE + 0x34000)
-#define REGS_SSP2_PHYS 0x80034000
-#define REGS_SSP_SIZE 0x2000
-
-#define HW_SSP_CTRL0 0x0
-#define BM_SSP_CTRL0_XFER_COUNT 0x0000FFFF
-#define BP_SSP_CTRL0_XFER_COUNT 0
-#define BM_SSP_CTRL0_ENABLE 0x00010000
-#define BM_SSP_CTRL0_GET_RESP 0x00020000
-#define BM_SSP_CTRL0_LONG_RESP 0x00080000
-#define BM_SSP_CTRL0_WAIT_FOR_CMD 0x00100000
-#define BM_SSP_CTRL0_WAIT_FOR_IRQ 0x00200000
-#define BM_SSP_CTRL0_BUS_WIDTH 0x00C00000
-#define BP_SSP_CTRL0_BUS_WIDTH 22
-#define BM_SSP_CTRL0_DATA_XFER 0x01000000
-#define BM_SSP_CTRL0_READ 0x02000000
-#define BM_SSP_CTRL0_IGNORE_CRC 0x04000000
-#define BM_SSP_CTRL0_LOCK_CS 0x08000000
-#define BM_SSP_CTRL0_RUN 0x20000000
-#define BM_SSP_CTRL0_CLKGATE 0x40000000
-#define BM_SSP_CTRL0_SFTRST 0x80000000
-
-#define HW_SSP_CMD0 0x10
-#define BM_SSP_CMD0_CMD 0x000000FF
-#define BP_SSP_CMD0_CMD 0
-#define BM_SSP_CMD0_BLOCK_COUNT 0x0000FF00
-#define BP_SSP_CMD0_BLOCK_COUNT 8
-#define BM_SSP_CMD0_BLOCK_SIZE 0x000F0000
-#define BP_SSP_CMD0_BLOCK_SIZE 16
-#define BM_SSP_CMD0_APPEND_8CYC 0x00100000
-#define BM_SSP_CMD1_CMD_ARG 0xFFFFFFFF
-#define BP_SSP_CMD1_CMD_ARG 0
-
-#define HW_SSP_TIMING 0x50
-#define BM_SSP_TIMING_CLOCK_RATE 0x000000FF
-#define BP_SSP_TIMING_CLOCK_RATE 0
-#define BM_SSP_TIMING_CLOCK_DIVIDE 0x0000FF00
-#define BP_SSP_TIMING_CLOCK_DIVIDE 8
-#define BM_SSP_TIMING_TIMEOUT 0xFFFF0000
-#define BP_SSP_TIMING_TIMEOUT 16
-
-#define HW_SSP_CTRL1 0x60
-#define BM_SSP_CTRL1_SSP_MODE 0x0000000F
-#define BP_SSP_CTRL1_SSP_MODE 0
-#define BM_SSP_CTRL1_WORD_LENGTH 0x000000F0
-#define BP_SSP_CTRL1_WORD_LENGTH 4
-#define BM_SSP_CTRL1_POLARITY 0x00000200
-#define BM_SSP_CTRL1_PHASE 0x00000400
-#define BM_SSP_CTRL1_DMA_ENABLE 0x00002000
-#define BM_SSP_CTRL1_FIFO_OVERRUN_IRQ 0x00008000
-#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN 0x00010000
-#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ 0x00020000
-#define BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ 0x00200000
-#define BM_SSP_CTRL1_DATA_CRC_IRQ_EN 0x00400000
-#define BM_SSP_CTRL1_DATA_CRC_IRQ 0x00800000
-#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN 0x01000000
-#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ 0x02000000
-#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN 0x04000000
-#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ 0x08000000
-#define BM_SSP_CTRL1_RESP_ERR_IRQ_EN 0x10000000
-#define BM_SSP_CTRL1_RESP_ERR_IRQ 0x20000000
-#define BM_SSP_CTRL1_SDIO_IRQ 0x80000000
-
-#define HW_SSP_DATA 0x70
-
-#define HW_SSP_SDRESP0 0x80
-
-#define HW_SSP_SDRESP1 0x90
-
-#define HW_SSP_SDRESP2 0xA0
-
-#define HW_SSP_SDRESP3 0xB0
-
-#define HW_SSP_STATUS 0xC0
-#define BM_SSP_STATUS_FIFO_EMPTY 0x00000020
-#define BM_SSP_STATUS_TIMEOUT 0x00001000
-#define BM_SSP_STATUS_RESP_TIMEOUT 0x00004000
-#define BM_SSP_STATUS_RESP_ERR 0x00008000
-#define BM_SSP_STATUS_RESP_CRC_ERR 0x00010000
-#define BM_SSP_STATUS_CARD_DETECT 0x10000000
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-sydma.h b/arch/arm/mach-stmp378x/include/mach/regs-sydma.h
deleted file mode 100644
index 08343a8b5566..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-sydma.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * stmp378x: SYDMA register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_SYDMA_BASE (STMP3XXX_REGS_BASE + 0x26000)
-#define REGS_SYDMA_PHYS 0x80026000
-#define REGS_SYDMA_SIZE 0x2000
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-timrot.h b/arch/arm/mach-stmp378x/include/mach/regs-timrot.h
deleted file mode 100644
index b5527957c67f..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-timrot.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * stmp378x: TIMROT register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef _MACH_REGS_TIMROT
-#define _MACH_REGS_TIMROT
-
-#define REGS_TIMROT_BASE (STMP3XXX_REGS_BASE + 0x68000)
-#define REGS_TIMROT_PHYS 0x80068000
-#define REGS_TIMROT_SIZE 0x2000
-
-#define HW_TIMROT_ROTCTRL 0x0
-#define BM_TIMROT_ROTCTRL_SELECT_A 0x00000007
-#define BP_TIMROT_ROTCTRL_SELECT_A 0
-#define BM_TIMROT_ROTCTRL_SELECT_B 0x00000070
-#define BP_TIMROT_ROTCTRL_SELECT_B 4
-#define BM_TIMROT_ROTCTRL_POLARITY_A 0x00000100
-#define BM_TIMROT_ROTCTRL_POLARITY_B 0x00000200
-#define BM_TIMROT_ROTCTRL_OVERSAMPLE 0x00000C00
-#define BP_TIMROT_ROTCTRL_OVERSAMPLE 10
-#define BM_TIMROT_ROTCTRL_RELATIVE 0x00001000
-#define BM_TIMROT_ROTCTRL_DIVIDER 0x003F0000
-#define BP_TIMROT_ROTCTRL_DIVIDER 16
-#define BM_TIMROT_ROTCTRL_ROTARY_PRESENT 0x20000000
-#define BM_TIMROT_ROTCTRL_CLKGATE 0x40000000
-#define BM_TIMROT_ROTCTRL_SFTRST 0x80000000
-
-#define HW_TIMROT_ROTCOUNT 0x10
-#define BM_TIMROT_ROTCOUNT_UPDOWN 0x0000FFFF
-#define BP_TIMROT_ROTCOUNT_UPDOWN 0
-
-#define HW_TIMROT_TIMCTRL0 (0x20 + 0 * 0x20)
-#define HW_TIMROT_TIMCTRL1 (0x20 + 1 * 0x20)
-#define HW_TIMROT_TIMCTRL2 (0x20 + 2 * 0x20)
-
-#define HW_TIMROT_TIMCTRLn 0x20
-#define BM_TIMROT_TIMCTRLn_SELECT 0x0000000F
-#define BP_TIMROT_TIMCTRLn_SELECT 0
-#define BM_TIMROT_TIMCTRLn_PRESCALE 0x00000030
-#define BP_TIMROT_TIMCTRLn_PRESCALE 4
-#define BM_TIMROT_TIMCTRLn_RELOAD 0x00000040
-#define BM_TIMROT_TIMCTRLn_UPDATE 0x00000080
-#define BM_TIMROT_TIMCTRLn_IRQ_EN 0x00004000
-#define BM_TIMROT_TIMCTRLn_IRQ 0x00008000
-
-#define HW_TIMROT_TIMCOUNT0 (0x30 + 0 * 0x20)
-#define HW_TIMROT_TIMCOUNT1 (0x30 + 1 * 0x20)
-#define HW_TIMROT_TIMCOUNT2 (0x30 + 2 * 0x20)
-
-#define HW_TIMROT_TIMCOUNTn 0x30
-
-#endif
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-tvenc.h b/arch/arm/mach-stmp378x/include/mach/regs-tvenc.h
deleted file mode 100644
index 7f895cb34350..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-tvenc.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * stmp378x: TVENC register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_TVENC_BASE (STMP3XXX_REGS_BASE + 0x38000)
-#define REGS_TVENC_PHYS 0x80038000
-#define REGS_TVENC_SIZE 0x2000
-
-#define HW_TVENC_CTRL 0x0
-#define BM_TVENC_CTRL_CLKGATE 0x40000000
-#define BM_TVENC_CTRL_SFTRST 0x80000000
-
-#define HW_TVENC_CONFIG 0x10
-#define BM_TVENC_CONFIG_ENCD_MODE 0x00000007
-#define BP_TVENC_CONFIG_ENCD_MODE 0
-#define BM_TVENC_CONFIG_SYNC_MODE 0x00000070
-#define BP_TVENC_CONFIG_SYNC_MODE 4
-#define BM_TVENC_CONFIG_FSYNC_PHS 0x00000200
-#define BM_TVENC_CONFIG_CGAIN 0x0000C000
-#define BP_TVENC_CONFIG_CGAIN 14
-#define BM_TVENC_CONFIG_YGAIN_SEL 0x00030000
-#define BP_TVENC_CONFIG_YGAIN_SEL 16
-#define BM_TVENC_CONFIG_PAL_SHAPE 0x00100000
-
-#define HW_TVENC_SYNCOFFSET 0x30
-
-#define HW_TVENC_COLORSUB0 0xC0
-
-#define HW_TVENC_COLORBURST 0x140
-#define BM_TVENC_COLORBURST_PBA 0x00FF0000
-#define BP_TVENC_COLORBURST_PBA 16
-#define BM_TVENC_COLORBURST_NBA 0xFF000000
-#define BP_TVENC_COLORBURST_NBA 24
-
-#define HW_TVENC_MACROVISION0 0x150
-
-#define HW_TVENC_MACROVISION1 0x160
-
-#define HW_TVENC_MACROVISION2 0x170
-
-#define HW_TVENC_MACROVISION3 0x180
-
-#define HW_TVENC_MACROVISION4 0x190
-
-#define HW_TVENC_DACCTRL 0x1A0
-#define BM_TVENC_DACCTRL_RVAL 0x00000070
-#define BP_TVENC_DACCTRL_RVAL 4
-#define BM_TVENC_DACCTRL_DUMP_TOVDD1 0x00000100
-#define BM_TVENC_DACCTRL_PWRUP1 0x00001000
-#define BM_TVENC_DACCTRL_GAINUP 0x00040000
-#define BM_TVENC_DACCTRL_GAINDN 0x00080000
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-uartapp.h b/arch/arm/mach-stmp378x/include/mach/regs-uartapp.h
deleted file mode 100644
index a251e68bb3a1..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-uartapp.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * stmp378x: UARTAPP register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_UARTAPP1_BASE (STMP3XXX_REGS_BASE + 0x6C000)
-#define REGS_UARTAPP1_PHYS 0x8006C000
-#define REGS_UARTAPP2_BASE (STMP3XXX_REGS_BASE + 0x6E000)
-#define REGS_UARTAPP2_PHYS 0x8006E000
-#define REGS_UARTAPP_SIZE 0x2000
-
-#define HW_UARTAPP_CTRL0 0x0
-#define BM_UARTAPP_CTRL0_XFER_COUNT 0x0000FFFF
-#define BP_UARTAPP_CTRL0_XFER_COUNT 0
-#define BM_UARTAPP_CTRL0_RXTIMEOUT 0x07FF0000
-#define BP_UARTAPP_CTRL0_RXTIMEOUT 16
-#define BM_UARTAPP_CTRL0_RXTO_ENABLE 0x08000000
-#define BM_UARTAPP_CTRL0_RUN 0x20000000
-#define BM_UARTAPP_CTRL0_SFTRST 0x80000000
-#define BM_UARTAPP_CTRL1_XFER_COUNT 0x0000FFFF
-#define BP_UARTAPP_CTRL1_XFER_COUNT 0
-#define BM_UARTAPP_CTRL1_RUN 0x10000000
-
-#define HW_UARTAPP_CTRL2 0x20
-#define BM_UARTAPP_CTRL2_UARTEN 0x00000001
-#define BP_UARTAPP_CTRL2_UARTEN 0
-#define BM_UARTAPP_CTRL2_TXE 0x00000100
-#define BM_UARTAPP_CTRL2_RXE 0x00000200
-#define BM_UARTAPP_CTRL2_RTS 0x00000800
-#define BM_UARTAPP_CTRL2_RTSEN 0x00004000
-#define BM_UARTAPP_CTRL2_CTSEN 0x00008000
-#define BM_UARTAPP_CTRL2_RXDMAE 0x01000000
-#define BM_UARTAPP_CTRL2_TXDMAE 0x02000000
-#define BM_UARTAPP_CTRL2_DMAONERR 0x04000000
-
-#define HW_UARTAPP_LINECTRL 0x30
-#define BM_UARTAPP_LINECTRL_BRK 0x00000001
-#define BP_UARTAPP_LINECTRL_BRK 0
-#define BM_UARTAPP_LINECTRL_PEN 0x00000002
-#define BM_UARTAPP_LINECTRL_EPS 0x00000004
-#define BM_UARTAPP_LINECTRL_STP2 0x00000008
-#define BM_UARTAPP_LINECTRL_FEN 0x00000010
-#define BM_UARTAPP_LINECTRL_WLEN 0x00000060
-#define BP_UARTAPP_LINECTRL_WLEN 5
-#define BM_UARTAPP_LINECTRL_SPS 0x00000080
-#define BM_UARTAPP_LINECTRL_BAUD_DIVFRAC 0x00003F00
-#define BP_UARTAPP_LINECTRL_BAUD_DIVFRAC 8
-#define BM_UARTAPP_LINECTRL_BAUD_DIVINT 0xFFFF0000
-#define BP_UARTAPP_LINECTRL_BAUD_DIVINT 16
-
-#define HW_UARTAPP_INTR 0x50
-#define BM_UARTAPP_INTR_CTSMIS 0x00000002
-#define BM_UARTAPP_INTR_RTIS 0x00000040
-#define BM_UARTAPP_INTR_CTSMIEN 0x00020000
-#define BM_UARTAPP_INTR_RXIEN 0x00100000
-#define BM_UARTAPP_INTR_RTIEN 0x00400000
-
-#define HW_UARTAPP_DATA 0x60
-
-#define HW_UARTAPP_STAT 0x70
-#define BM_UARTAPP_STAT_RXCOUNT 0x0000FFFF
-#define BP_UARTAPP_STAT_RXCOUNT 0
-#define BM_UARTAPP_STAT_FERR 0x00010000
-#define BM_UARTAPP_STAT_PERR 0x00020000
-#define BM_UARTAPP_STAT_BERR 0x00040000
-#define BM_UARTAPP_STAT_OERR 0x00080000
-#define BM_UARTAPP_STAT_RXFE 0x01000000
-#define BM_UARTAPP_STAT_TXFF 0x02000000
-#define BM_UARTAPP_STAT_TXFE 0x08000000
-#define BM_UARTAPP_STAT_CTS 0x10000000
-
-#define HW_UARTAPP_VERSION 0x90
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-uartdbg.h b/arch/arm/mach-stmp378x/include/mach/regs-uartdbg.h
deleted file mode 100644
index b810deb552a9..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-uartdbg.h
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * stmp378x: UARTDBG register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_UARTDBG_BASE (STMP3XXX_REGS_BASE + 0x70000)
-#define REGS_UARTDBG_PHYS 0x80070000
-#define REGS_UARTDBG_SIZE 0x2000
-
-#define HW_UARTDBGDR 0x00000000
-#define BP_UARTDBGDR_UNAVAILABLE 16
-#define BM_UARTDBGDR_UNAVAILABLE 0xFFFF0000
-#define BF_UARTDBGDR_UNAVAILABLE(v) \
- (((v) << 16) & BM_UARTDBGDR_UNAVAILABLE)
-#define BP_UARTDBGDR_RESERVED 12
-#define BM_UARTDBGDR_RESERVED 0x0000F000
-#define BF_UARTDBGDR_RESERVED(v) \
- (((v) << 12) & BM_UARTDBGDR_RESERVED)
-#define BM_UARTDBGDR_OE 0x00000800
-#define BM_UARTDBGDR_BE 0x00000400
-#define BM_UARTDBGDR_PE 0x00000200
-#define BM_UARTDBGDR_FE 0x00000100
-#define BP_UARTDBGDR_DATA 0
-#define BM_UARTDBGDR_DATA 0x000000FF
-#define BF_UARTDBGDR_DATA(v) \
- (((v) << 0) & BM_UARTDBGDR_DATA)
-#define HW_UARTDBGRSR_ECR 0x00000004
-#define BP_UARTDBGRSR_ECR_UNAVAILABLE 8
-#define BM_UARTDBGRSR_ECR_UNAVAILABLE 0xFFFFFF00
-#define BF_UARTDBGRSR_ECR_UNAVAILABLE(v) \
- (((v) << 8) & BM_UARTDBGRSR_ECR_UNAVAILABLE)
-#define BP_UARTDBGRSR_ECR_EC 4
-#define BM_UARTDBGRSR_ECR_EC 0x000000F0
-#define BF_UARTDBGRSR_ECR_EC(v) \
- (((v) << 4) & BM_UARTDBGRSR_ECR_EC)
-#define BM_UARTDBGRSR_ECR_OE 0x00000008
-#define BM_UARTDBGRSR_ECR_BE 0x00000004
-#define BM_UARTDBGRSR_ECR_PE 0x00000002
-#define BM_UARTDBGRSR_ECR_FE 0x00000001
-#define HW_UARTDBGFR 0x00000018
-#define BP_UARTDBGFR_UNAVAILABLE 16
-#define BM_UARTDBGFR_UNAVAILABLE 0xFFFF0000
-#define BF_UARTDBGFR_UNAVAILABLE(v) \
- (((v) << 16) & BM_UARTDBGFR_UNAVAILABLE)
-#define BP_UARTDBGFR_RESERVED 9
-#define BM_UARTDBGFR_RESERVED 0x0000FE00
-#define BF_UARTDBGFR_RESERVED(v) \
- (((v) << 9) & BM_UARTDBGFR_RESERVED)
-#define BM_UARTDBGFR_RI 0x00000100
-#define BM_UARTDBGFR_TXFE 0x00000080
-#define BM_UARTDBGFR_RXFF 0x00000040
-#define BM_UARTDBGFR_TXFF 0x00000020
-#define BM_UARTDBGFR_RXFE 0x00000010
-#define BM_UARTDBGFR_BUSY 0x00000008
-#define BM_UARTDBGFR_DCD 0x00000004
-#define BM_UARTDBGFR_DSR 0x00000002
-#define BM_UARTDBGFR_CTS 0x00000001
-#define HW_UARTDBGILPR 0x00000020
-#define BP_UARTDBGILPR_UNAVAILABLE 8
-#define BM_UARTDBGILPR_UNAVAILABLE 0xFFFFFF00
-#define BF_UARTDBGILPR_UNAVAILABLE(v) \
- (((v) << 8) & BM_UARTDBGILPR_UNAVAILABLE)
-#define BP_UARTDBGILPR_ILPDVSR 0
-#define BM_UARTDBGILPR_ILPDVSR 0x000000FF
-#define BF_UARTDBGILPR_ILPDVSR(v) \
- (((v) << 0) & BM_UARTDBGILPR_ILPDVSR)
-#define HW_UARTDBGIBRD 0x00000024
-#define BP_UARTDBGIBRD_UNAVAILABLE 16
-#define BM_UARTDBGIBRD_UNAVAILABLE 0xFFFF0000
-#define BF_UARTDBGIBRD_UNAVAILABLE(v) \
- (((v) << 16) & BM_UARTDBGIBRD_UNAVAILABLE)
-#define BP_UARTDBGIBRD_BAUD_DIVINT 0
-#define BM_UARTDBGIBRD_BAUD_DIVINT 0x0000FFFF
-#define BF_UARTDBGIBRD_BAUD_DIVINT(v) \
- (((v) << 0) & BM_UARTDBGIBRD_BAUD_DIVINT)
-#define HW_UARTDBGFBRD 0x00000028
-#define BP_UARTDBGFBRD_UNAVAILABLE 8
-#define BM_UARTDBGFBRD_UNAVAILABLE 0xFFFFFF00
-#define BF_UARTDBGFBRD_UNAVAILABLE(v) \
- (((v) << 8) & BM_UARTDBGFBRD_UNAVAILABLE)
-#define BP_UARTDBGFBRD_RESERVED 6
-#define BM_UARTDBGFBRD_RESERVED 0x000000C0
-#define BF_UARTDBGFBRD_RESERVED(v) \
- (((v) << 6) & BM_UARTDBGFBRD_RESERVED)
-#define BP_UARTDBGFBRD_BAUD_DIVFRAC 0
-#define BM_UARTDBGFBRD_BAUD_DIVFRAC 0x0000003F
-#define BF_UARTDBGFBRD_BAUD_DIVFRAC(v) \
- (((v) << 0) & BM_UARTDBGFBRD_BAUD_DIVFRAC)
-#define HW_UARTDBGLCR_H 0x0000002c
-#define BP_UARTDBGLCR_H_UNAVAILABLE 16
-#define BM_UARTDBGLCR_H_UNAVAILABLE 0xFFFF0000
-#define BF_UARTDBGLCR_H_UNAVAILABLE(v) \
- (((v) << 16) & BM_UARTDBGLCR_H_UNAVAILABLE)
-#define BP_UARTDBGLCR_H_RESERVED 8
-#define BM_UARTDBGLCR_H_RESERVED 0x0000FF00
-#define BF_UARTDBGLCR_H_RESERVED(v) \
- (((v) << 8) & BM_UARTDBGLCR_H_RESERVED)
-#define BM_UARTDBGLCR_H_SPS 0x00000080
-#define BP_UARTDBGLCR_H_WLEN 5
-#define BM_UARTDBGLCR_H_WLEN 0x00000060
-#define BF_UARTDBGLCR_H_WLEN(v) \
- (((v) << 5) & BM_UARTDBGLCR_H_WLEN)
-#define BM_UARTDBGLCR_H_FEN 0x00000010
-#define BM_UARTDBGLCR_H_STP2 0x00000008
-#define BM_UARTDBGLCR_H_EPS 0x00000004
-#define BM_UARTDBGLCR_H_PEN 0x00000002
-#define BM_UARTDBGLCR_H_BRK 0x00000001
-#define HW_UARTDBGCR 0x00000030
-#define BP_UARTDBGCR_UNAVAILABLE 16
-#define BM_UARTDBGCR_UNAVAILABLE 0xFFFF0000
-#define BF_UARTDBGCR_UNAVAILABLE(v) \
- (((v) << 16) & BM_UARTDBGCR_UNAVAILABLE)
-#define BM_UARTDBGCR_CTSEN 0x00008000
-#define BM_UARTDBGCR_RTSEN 0x00004000
-#define BM_UARTDBGCR_OUT2 0x00002000
-#define BM_UARTDBGCR_OUT1 0x00001000
-#define BM_UARTDBGCR_RTS 0x00000800
-#define BM_UARTDBGCR_DTR 0x00000400
-#define BM_UARTDBGCR_RXE 0x00000200
-#define BM_UARTDBGCR_TXE 0x00000100
-#define BM_UARTDBGCR_LBE 0x00000080
-#define BP_UARTDBGCR_RESERVED 3
-#define BM_UARTDBGCR_RESERVED 0x00000078
-#define BF_UARTDBGCR_RESERVED(v) \
- (((v) << 3) & BM_UARTDBGCR_RESERVED)
-#define BM_UARTDBGCR_SIRLP 0x00000004
-#define BM_UARTDBGCR_SIREN 0x00000002
-#define BM_UARTDBGCR_UARTEN 0x00000001
-#define HW_UARTDBGIFLS 0x00000034
-#define BP_UARTDBGIFLS_UNAVAILABLE 16
-#define BM_UARTDBGIFLS_UNAVAILABLE 0xFFFF0000
-#define BF_UARTDBGIFLS_UNAVAILABLE(v) \
- (((v) << 16) & BM_UARTDBGIFLS_UNAVAILABLE)
-#define BP_UARTDBGIFLS_RESERVED 6
-#define BM_UARTDBGIFLS_RESERVED 0x0000FFC0
-#define BF_UARTDBGIFLS_RESERVED(v) \
- (((v) << 6) & BM_UARTDBGIFLS_RESERVED)
-#define BP_UARTDBGIFLS_RXIFLSEL 3
-#define BM_UARTDBGIFLS_RXIFLSEL 0x00000038
-#define BF_UARTDBGIFLS_RXIFLSEL(v) \
- (((v) << 3) & BM_UARTDBGIFLS_RXIFLSEL)
-#define BV_UARTDBGIFLS_RXIFLSEL__NOT_EMPTY 0x0
-#define BV_UARTDBGIFLS_RXIFLSEL__ONE_QUARTER 0x1
-#define BV_UARTDBGIFLS_RXIFLSEL__ONE_HALF 0x2
-#define BV_UARTDBGIFLS_RXIFLSEL__THREE_QUARTERS 0x3
-#define BV_UARTDBGIFLS_RXIFLSEL__SEVEN_EIGHTHS 0x4
-#define BV_UARTDBGIFLS_RXIFLSEL__INVALID5 0x5
-#define BV_UARTDBGIFLS_RXIFLSEL__INVALID6 0x6
-#define BV_UARTDBGIFLS_RXIFLSEL__INVALID7 0x7
-#define BP_UARTDBGIFLS_TXIFLSEL 0
-#define BM_UARTDBGIFLS_TXIFLSEL 0x00000007
-#define BF_UARTDBGIFLS_TXIFLSEL(v) \
- (((v) << 0) & BM_UARTDBGIFLS_TXIFLSEL)
-#define BV_UARTDBGIFLS_TXIFLSEL__EMPTY 0x0
-#define BV_UARTDBGIFLS_TXIFLSEL__ONE_QUARTER 0x1
-#define BV_UARTDBGIFLS_TXIFLSEL__ONE_HALF 0x2
-#define BV_UARTDBGIFLS_TXIFLSEL__THREE_QUARTERS 0x3
-#define BV_UARTDBGIFLS_TXIFLSEL__SEVEN_EIGHTHS 0x4
-#define BV_UARTDBGIFLS_TXIFLSEL__INVALID5 0x5
-#define BV_UARTDBGIFLS_TXIFLSEL__INVALID6 0x6
-#define BV_UARTDBGIFLS_TXIFLSEL__INVALID7 0x7
-#define HW_UARTDBGIMSC 0x00000038
-#define BP_UARTDBGIMSC_UNAVAILABLE 16
-#define BM_UARTDBGIMSC_UNAVAILABLE 0xFFFF0000
-#define BF_UARTDBGIMSC_UNAVAILABLE(v) \
- (((v) << 16) & BM_UARTDBGIMSC_UNAVAILABLE)
-#define BP_UARTDBGIMSC_RESERVED 11
-#define BM_UARTDBGIMSC_RESERVED 0x0000F800
-#define BF_UARTDBGIMSC_RESERVED(v) \
- (((v) << 11) & BM_UARTDBGIMSC_RESERVED)
-#define BM_UARTDBGIMSC_OEIM 0x00000400
-#define BM_UARTDBGIMSC_BEIM 0x00000200
-#define BM_UARTDBGIMSC_PEIM 0x00000100
-#define BM_UARTDBGIMSC_FEIM 0x00000080
-#define BM_UARTDBGIMSC_RTIM 0x00000040
-#define BM_UARTDBGIMSC_TXIM 0x00000020
-#define BM_UARTDBGIMSC_RXIM 0x00000010
-#define BM_UARTDBGIMSC_DSRMIM 0x00000008
-#define BM_UARTDBGIMSC_DCDMIM 0x00000004
-#define BM_UARTDBGIMSC_CTSMIM 0x00000002
-#define BM_UARTDBGIMSC_RIMIM 0x00000001
-#define HW_UARTDBGRIS 0x0000003c
-#define BP_UARTDBGRIS_UNAVAILABLE 16
-#define BM_UARTDBGRIS_UNAVAILABLE 0xFFFF0000
-#define BF_UARTDBGRIS_UNAVAILABLE(v) \
- (((v) << 16) & BM_UARTDBGRIS_UNAVAILABLE)
-#define BP_UARTDBGRIS_RESERVED 11
-#define BM_UARTDBGRIS_RESERVED 0x0000F800
-#define BF_UARTDBGRIS_RESERVED(v) \
- (((v) << 11) & BM_UARTDBGRIS_RESERVED)
-#define BM_UARTDBGRIS_OERIS 0x00000400
-#define BM_UARTDBGRIS_BERIS 0x00000200
-#define BM_UARTDBGRIS_PERIS 0x00000100
-#define BM_UARTDBGRIS_FERIS 0x00000080
-#define BM_UARTDBGRIS_RTRIS 0x00000040
-#define BM_UARTDBGRIS_TXRIS 0x00000020
-#define BM_UARTDBGRIS_RXRIS 0x00000010
-#define BM_UARTDBGRIS_DSRRMIS 0x00000008
-#define BM_UARTDBGRIS_DCDRMIS 0x00000004
-#define BM_UARTDBGRIS_CTSRMIS 0x00000002
-#define BM_UARTDBGRIS_RIRMIS 0x00000001
-#define HW_UARTDBGMIS 0x00000040
-#define BP_UARTDBGMIS_UNAVAILABLE 16
-#define BM_UARTDBGMIS_UNAVAILABLE 0xFFFF0000
-#define BF_UARTDBGMIS_UNAVAILABLE(v) \
- (((v) << 16) & BM_UARTDBGMIS_UNAVAILABLE)
-#define BP_UARTDBGMIS_RESERVED 11
-#define BM_UARTDBGMIS_RESERVED 0x0000F800
-#define BF_UARTDBGMIS_RESERVED(v) \
- (((v) << 11) & BM_UARTDBGMIS_RESERVED)
-#define BM_UARTDBGMIS_OEMIS 0x00000400
-#define BM_UARTDBGMIS_BEMIS 0x00000200
-#define BM_UARTDBGMIS_PEMIS 0x00000100
-#define BM_UARTDBGMIS_FEMIS 0x00000080
-#define BM_UARTDBGMIS_RTMIS 0x00000040
-#define BM_UARTDBGMIS_TXMIS 0x00000020
-#define BM_UARTDBGMIS_RXMIS 0x00000010
-#define BM_UARTDBGMIS_DSRMMIS 0x00000008
-#define BM_UARTDBGMIS_DCDMMIS 0x00000004
-#define BM_UARTDBGMIS_CTSMMIS 0x00000002
-#define BM_UARTDBGMIS_RIMMIS 0x00000001
-#define HW_UARTDBGICR 0x00000044
-#define BP_UARTDBGICR_UNAVAILABLE 16
-#define BM_UARTDBGICR_UNAVAILABLE 0xFFFF0000
-#define BF_UARTDBGICR_UNAVAILABLE(v) \
- (((v) << 16) & BM_UARTDBGICR_UNAVAILABLE)
-#define BP_UARTDBGICR_RESERVED 11
-#define BM_UARTDBGICR_RESERVED 0x0000F800
-#define BF_UARTDBGICR_RESERVED(v) \
- (((v) << 11) & BM_UARTDBGICR_RESERVED)
-#define BM_UARTDBGICR_OEIC 0x00000400
-#define BM_UARTDBGICR_BEIC 0x00000200
-#define BM_UARTDBGICR_PEIC 0x00000100
-#define BM_UARTDBGICR_FEIC 0x00000080
-#define BM_UARTDBGICR_RTIC 0x00000040
-#define BM_UARTDBGICR_TXIC 0x00000020
-#define BM_UARTDBGICR_RXIC 0x00000010
-#define BM_UARTDBGICR_DSRMIC 0x00000008
-#define BM_UARTDBGICR_DCDMIC 0x00000004
-#define BM_UARTDBGICR_CTSMIC 0x00000002
-#define BM_UARTDBGICR_RIMIC 0x00000001
-#define HW_UARTDBGDMACR 0x00000048
-#define BP_UARTDBGDMACR_UNAVAILABLE 16
-#define BM_UARTDBGDMACR_UNAVAILABLE 0xFFFF0000
-#define BF_UARTDBGDMACR_UNAVAILABLE(v) \
- (((v) << 16) & BM_UARTDBGDMACR_UNAVAILABLE)
-#define BP_UARTDBGDMACR_RESERVED 3
-#define BM_UARTDBGDMACR_RESERVED 0x0000FFF8
-#define BF_UARTDBGDMACR_RESERVED(v) \
- (((v) << 3) & BM_UARTDBGDMACR_RESERVED)
-#define BM_UARTDBGDMACR_DMAONERR 0x00000004
-#define BM_UARTDBGDMACR_TXDMAE 0x00000002
-#define BM_UARTDBGDMACR_RXDMAE 0x00000001
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-usbctrl.h b/arch/arm/mach-stmp378x/include/mach/regs-usbctrl.h
deleted file mode 100644
index 25112c1aa608..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-usbctrl.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * stmp378x: USBCTRL register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_USBCTRL_BASE (STMP3XXX_REGS_BASE + 0x80000)
-#define REGS_USBCTRL_PHYS 0x80080000
-#define REGS_USBCTRL_SIZE 0x2000
-
-#define HW_USBCTRL_USBCMD 0x140
-#define BM_USBCTRL_USBCMD_RS 0x00000001
-#define BP_USBCTRL_USBCMD_RS 0
-#define BM_USBCTRL_USBCMD_RST 0x00000002
-
-#define HW_USBCTRL_USBINTR 0x148
-#define BM_USBCTRL_USBINTR_UE 0x00000001
-#define BP_USBCTRL_USBINTR_UE 0
-
-#define HW_USBCTRL_PORTSC1 0x184
-#define BM_USBCTRL_PORTSC1_PHCD 0x00800000
-
-#define HW_USBCTRL_OTGSC 0x1A4
-#define BM_USBCTRL_OTGSC_ID 0x00000100
-#define BM_USBCTRL_OTGSC_IDIS 0x00010000
-#define BM_USBCTRL_OTGSC_IDIE 0x01000000
diff --git a/arch/arm/mach-stmp378x/include/mach/regs-usbphy.h b/arch/arm/mach-stmp378x/include/mach/regs-usbphy.h
deleted file mode 100644
index 11f3b732dc92..000000000000
--- a/arch/arm/mach-stmp378x/include/mach/regs-usbphy.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * stmp378x: USBPHY register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_USBPHY_BASE (STMP3XXX_REGS_BASE + 0x7C000)
-#define REGS_USBPHY_PHYS 0x8007C000
-#define REGS_USBPHY_SIZE 0x2000
-
-#define HW_USBPHY_PWD 0x0
-
-#define HW_USBPHY_CTRL 0x30
-#define BM_USBPHY_CTRL_ENHOSTDISCONDETECT 0x00000002
-#define BM_USBPHY_CTRL_ENDEVPLUGINDETECT 0x00000010
-#define BM_USBPHY_CTRL_ENOTGIDDETECT 0x00000080
-#define BM_USBPHY_CTRL_ENIRQDEVPLUGIN 0x00000800
-#define BM_USBPHY_CTRL_CLKGATE 0x40000000
-#define BM_USBPHY_CTRL_SFTRST 0x80000000
-
-#define HW_USBPHY_STATUS 0x40
-#define BM_USBPHY_STATUS_DEVPLUGIN_STATUS 0x00000040
-#define BM_USBPHY_STATUS_OTGID_STATUS 0x00000100
diff --git a/arch/arm/mach-stmp378x/stmp378x.c b/arch/arm/mach-stmp378x/stmp378x.c
deleted file mode 100644
index c2f9fe04c112..000000000000
--- a/arch/arm/mach-stmp378x/stmp378x.c
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * Freescale STMP378X platform support
- *
- * Embedded Alley Solutions, Inc <source@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/irq.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/dma.h>
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/map.h>
-#include <asm/mach/time.h>
-
-#include <mach/pins.h>
-#include <mach/pinmux.h>
-#include <mach/dma.h>
-#include <mach/hardware.h>
-#include <mach/system.h>
-#include <mach/platform.h>
-#include <mach/stmp3xxx.h>
-#include <mach/regs-icoll.h>
-#include <mach/regs-apbh.h>
-#include <mach/regs-apbx.h>
-#include <mach/regs-pxp.h>
-#include <mach/regs-i2c.h>
-
-#include "stmp378x.h"
-/*
- * IRQ handling
- */
-static void stmp378x_ack_irq(struct irq_data *d)
-{
- /* Tell ICOLL to release IRQ line */
- __raw_writel(0, REGS_ICOLL_BASE + HW_ICOLL_VECTOR);
-
- /* ACK current interrupt */
- __raw_writel(0x01 /* BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0 */,
- REGS_ICOLL_BASE + HW_ICOLL_LEVELACK);
-
- /* Barrier */
- (void)__raw_readl(REGS_ICOLL_BASE + HW_ICOLL_STAT);
-}
-
-static void stmp378x_mask_irq(struct irq_data *d)
-{
- /* IRQ disable */
- stmp3xxx_clearl(BM_ICOLL_INTERRUPTn_ENABLE,
- REGS_ICOLL_BASE + HW_ICOLL_INTERRUPTn + d->irq * 0x10);
-}
-
-static void stmp378x_unmask_irq(struct irq_data *d)
-{
- /* IRQ enable */
- stmp3xxx_setl(BM_ICOLL_INTERRUPTn_ENABLE,
- REGS_ICOLL_BASE + HW_ICOLL_INTERRUPTn + d->irq * 0x10);
-}
-
-static struct irq_chip stmp378x_chip = {
- .irq_ack = stmp378x_ack_irq,
- .irq_mask = stmp378x_mask_irq,
- .irq_unmask = stmp378x_unmask_irq,
-};
-
-void __init stmp378x_init_irq(void)
-{
- stmp3xxx_init_irq(&stmp378x_chip);
-}
-
-/*
- * DMA interrupt handling
- */
-void stmp3xxx_arch_dma_enable_interrupt(int channel)
-{
- void __iomem *c1, *c2;
-
- switch (STMP3XXX_DMA_BUS(channel)) {
- case STMP3XXX_BUS_APBH:
- c1 = REGS_APBH_BASE + HW_APBH_CTRL1;
- c2 = REGS_APBH_BASE + HW_APBH_CTRL2;
- break;
-
- case STMP3XXX_BUS_APBX:
- c1 = REGS_APBX_BASE + HW_APBX_CTRL1;
- c2 = REGS_APBX_BASE + HW_APBX_CTRL2;
- break;
-
- default:
- return;
- }
- stmp3xxx_setl(1 << (16 + STMP3XXX_DMA_CHANNEL(channel)), c1);
- stmp3xxx_setl(1 << (16 + STMP3XXX_DMA_CHANNEL(channel)), c2);
-}
-EXPORT_SYMBOL(stmp3xxx_arch_dma_enable_interrupt);
-
-void stmp3xxx_arch_dma_clear_interrupt(int channel)
-{
- void __iomem *c1, *c2;
-
- switch (STMP3XXX_DMA_BUS(channel)) {
- case STMP3XXX_BUS_APBH:
- c1 = REGS_APBH_BASE + HW_APBH_CTRL1;
- c2 = REGS_APBH_BASE + HW_APBH_CTRL2;
- break;
-
- case STMP3XXX_BUS_APBX:
- c1 = REGS_APBX_BASE + HW_APBX_CTRL1;
- c2 = REGS_APBX_BASE + HW_APBX_CTRL2;
- break;
-
- default:
- return;
- }
- stmp3xxx_clearl(1 << STMP3XXX_DMA_CHANNEL(channel), c1);
- stmp3xxx_clearl(1 << STMP3XXX_DMA_CHANNEL(channel), c2);
-}
-EXPORT_SYMBOL(stmp3xxx_arch_dma_clear_interrupt);
-
-int stmp3xxx_arch_dma_is_interrupt(int channel)
-{
- int r = 0;
-
- switch (STMP3XXX_DMA_BUS(channel)) {
- case STMP3XXX_BUS_APBH:
- r = __raw_readl(REGS_APBH_BASE + HW_APBH_CTRL1) &
- (1 << STMP3XXX_DMA_CHANNEL(channel));
- break;
-
- case STMP3XXX_BUS_APBX:
- r = __raw_readl(REGS_APBX_BASE + HW_APBX_CTRL1) &
- (1 << STMP3XXX_DMA_CHANNEL(channel));
- break;
- }
- return r;
-}
-EXPORT_SYMBOL(stmp3xxx_arch_dma_is_interrupt);
-
-void stmp3xxx_arch_dma_reset_channel(int channel)
-{
- unsigned chbit = 1 << STMP3XXX_DMA_CHANNEL(channel);
- void __iomem *c0;
- u32 mask;
-
- switch (STMP3XXX_DMA_BUS(channel)) {
- case STMP3XXX_BUS_APBH:
- c0 = REGS_APBH_BASE + HW_APBH_CTRL0;
- mask = chbit << BP_APBH_CTRL0_RESET_CHANNEL;
- break;
- case STMP3XXX_BUS_APBX:
- c0 = REGS_APBX_BASE + HW_APBX_CHANNEL_CTRL;
- mask = chbit << BP_APBX_CHANNEL_CTRL_RESET_CHANNEL;
- break;
- default:
- return;
- }
-
- /* Reset channel and wait for it to complete */
- stmp3xxx_setl(mask, c0);
- while (__raw_readl(c0) & mask)
- cpu_relax();
-}
-EXPORT_SYMBOL(stmp3xxx_arch_dma_reset_channel);
-
-void stmp3xxx_arch_dma_freeze(int channel)
-{
- unsigned chbit = 1 << STMP3XXX_DMA_CHANNEL(channel);
- u32 mask = 1 << chbit;
-
- switch (STMP3XXX_DMA_BUS(channel)) {
- case STMP3XXX_BUS_APBH:
- stmp3xxx_setl(mask, REGS_APBH_BASE + HW_APBH_CTRL0);
- break;
- case STMP3XXX_BUS_APBX:
- stmp3xxx_setl(mask, REGS_APBX_BASE + HW_APBX_CHANNEL_CTRL);
- break;
- }
-}
-EXPORT_SYMBOL(stmp3xxx_arch_dma_freeze);
-
-void stmp3xxx_arch_dma_unfreeze(int channel)
-{
- unsigned chbit = 1 << STMP3XXX_DMA_CHANNEL(channel);
- u32 mask = 1 << chbit;
-
- switch (STMP3XXX_DMA_BUS(channel)) {
- case STMP3XXX_BUS_APBH:
- stmp3xxx_clearl(mask, REGS_APBH_BASE + HW_APBH_CTRL0);
- break;
- case STMP3XXX_BUS_APBX:
- stmp3xxx_clearl(mask, REGS_APBX_BASE + HW_APBX_CHANNEL_CTRL);
- break;
- }
-}
-EXPORT_SYMBOL(stmp3xxx_arch_dma_unfreeze);
-
-/*
- * The registers are all very closely mapped, so we might as well map them all
- * with a single mapping
- *
- * Logical Physical
- * f0000000 80000000 On-chip registers
- * f1000000 00000000 32k on-chip SRAM
- */
-
-static struct map_desc stmp378x_io_desc[] __initdata = {
- {
- .virtual = (u32)STMP3XXX_REGS_BASE,
- .pfn = __phys_to_pfn(STMP3XXX_REGS_PHBASE),
- .length = STMP3XXX_REGS_SIZE,
- .type = MT_DEVICE,
- },
- {
- .virtual = (u32)STMP3XXX_OCRAM_BASE,
- .pfn = __phys_to_pfn(STMP3XXX_OCRAM_PHBASE),
- .length = STMP3XXX_OCRAM_SIZE,
- .type = MT_DEVICE,
- },
-};
-
-
-static u64 common_dmamask = DMA_BIT_MASK(32);
-
-/*
- * devices that are present only on stmp378x, not on all 3xxx boards:
- * PxP
- * I2C
- */
-static struct resource pxp_resource[] = {
- {
- .flags = IORESOURCE_MEM,
- .start = REGS_PXP_PHYS,
- .end = REGS_PXP_PHYS + REGS_PXP_SIZE,
- }, {
- .flags = IORESOURCE_IRQ,
- .start = IRQ_PXP,
- .end = IRQ_PXP,
- },
-};
-
-struct platform_device stmp378x_pxp = {
- .name = "stmp3xxx-pxp",
- .id = -1,
- .dev = {
- .dma_mask = &common_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .num_resources = ARRAY_SIZE(pxp_resource),
- .resource = pxp_resource,
-};
-
-static struct resource i2c_resources[] = {
- {
- .flags = IORESOURCE_IRQ,
- .start = IRQ_I2C_ERROR,
- .end = IRQ_I2C_ERROR,
- }, {
- .flags = IORESOURCE_MEM,
- .start = REGS_I2C_PHYS,
- .end = REGS_I2C_PHYS + REGS_I2C_SIZE,
- }, {
- .flags = IORESOURCE_DMA,
- .start = STMP3XXX_DMA(3, STMP3XXX_BUS_APBX),
- .end = STMP3XXX_DMA(3, STMP3XXX_BUS_APBX),
- },
-};
-
-struct platform_device stmp378x_i2c = {
- .name = "i2c_stmp3xxx",
- .id = 0,
- .dev = {
- .dma_mask = &common_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = i2c_resources,
- .num_resources = ARRAY_SIZE(i2c_resources),
-};
-
-void __init stmp378x_map_io(void)
-{
- iotable_init(stmp378x_io_desc, ARRAY_SIZE(stmp378x_io_desc));
-}
diff --git a/arch/arm/mach-stmp378x/stmp378x.h b/arch/arm/mach-stmp378x/stmp378x.h
deleted file mode 100644
index 0dc15b3c891f..000000000000
--- a/arch/arm/mach-stmp378x/stmp378x.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Freescale STMP37XX/STMP378X internal functions and data declarations
- *
- * Embedded Alley Solutions, Inc <source@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#ifndef __MACH_STMP378X_H
-#define __MACH_STMP378X_H
-
-void stmp378x_map_io(void);
-void stmp378x_init_irq(void);
-
-extern struct platform_device stmp378x_pxp, stmp378x_i2c;
-#endif /* __MACH_STMP378X_COMMON_H */
diff --git a/arch/arm/mach-stmp378x/stmp378x_devb.c b/arch/arm/mach-stmp378x/stmp378x_devb.c
deleted file mode 100644
index 06158848afd9..000000000000
--- a/arch/arm/mach-stmp378x/stmp378x_devb.c
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * Freescale STMP378X development board support
- *
- * Embedded Alley Solutions, Inc <source@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/spi/spi.h>
-
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-#include <mach/pins.h>
-#include <mach/pinmux.h>
-#include <mach/platform.h>
-#include <mach/stmp3xxx.h>
-#include <mach/mmc.h>
-#include <mach/gpmi.h>
-
-#include "stmp378x.h"
-
-static struct platform_device *devices[] = {
- &stmp3xxx_dbguart,
- &stmp3xxx_appuart,
- &stmp3xxx_watchdog,
- &stmp3xxx_touchscreen,
- &stmp3xxx_rtc,
- &stmp3xxx_keyboard,
- &stmp3xxx_framebuffer,
- &stmp3xxx_backlight,
- &stmp3xxx_rotdec,
- &stmp3xxx_persistent,
- &stmp3xxx_dcp_bootstream,
- &stmp3xxx_dcp,
- &stmp3xxx_battery,
- &stmp378x_pxp,
- &stmp378x_i2c,
-};
-
-static struct pin_desc i2c_pins_desc[] = {
- { PINID_I2C_SCL, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
- { PINID_I2C_SDA, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
-};
-
-static struct pin_group i2c_pins = {
- .pins = i2c_pins_desc,
- .nr_pins = ARRAY_SIZE(i2c_pins_desc),
-};
-
-static struct pin_desc dbguart_pins_0[] = {
- { PINID_PWM0, PIN_FUN3, },
- { PINID_PWM1, PIN_FUN3, },
-};
-
-static struct pin_group dbguart_pins[] = {
- [0] = {
- .pins = dbguart_pins_0,
- .nr_pins = ARRAY_SIZE(dbguart_pins_0),
- },
-};
-
-static int dbguart_pins_control(int id, int request)
-{
- int r = 0;
-
- if (request)
- r = stmp3xxx_request_pin_group(&dbguart_pins[id], "debug uart");
- else
- stmp3xxx_release_pin_group(&dbguart_pins[id], "debug uart");
- return r;
-}
-
-static struct pin_desc appuart_pins_0[] = {
- { PINID_AUART1_CTS, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
- { PINID_AUART1_RTS, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
- { PINID_AUART1_RX, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
- { PINID_AUART1_TX, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
-};
-
-static struct pin_desc appuart_pins_1[] = {
-#if 0 /* enable these when second appuart will be connected */
- { PINID_AUART2_CTS, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
- { PINID_AUART2_RTS, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
- { PINID_AUART2_RX, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
- { PINID_AUART2_TX, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
-#endif
-};
-
-static struct pin_desc mmc_pins_desc[] = {
- { PINID_SSP1_DATA0, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 },
- { PINID_SSP1_DATA1, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 },
- { PINID_SSP1_DATA2, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 },
- { PINID_SSP1_DATA3, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 },
- { PINID_SSP1_CMD, PIN_FUN1, PIN_8MA, PIN_3_3V, 1 },
- { PINID_SSP1_SCK, PIN_FUN1, PIN_8MA, PIN_3_3V, 0 },
- { PINID_SSP1_DETECT, PIN_FUN1, PIN_8MA, PIN_3_3V, 0 },
-};
-
-static struct pin_group mmc_pins = {
- .pins = mmc_pins_desc,
- .nr_pins = ARRAY_SIZE(mmc_pins_desc),
-};
-
-static int stmp3xxxmmc_get_wp(void)
-{
- return gpio_get_value(PINID_PWM4);
-}
-
-static int stmp3xxxmmc_hw_init_ssp1(void)
-{
- int ret;
-
- ret = stmp3xxx_request_pin_group(&mmc_pins, "mmc");
- if (ret)
- goto out;
-
- /* Configure write protect GPIO pin */
- ret = gpio_request(PINID_PWM4, "mmc wp");
- if (ret)
- goto out_wp;
-
- gpio_direction_input(PINID_PWM4);
-
- /* Configure POWER pin as gpio to drive power to MMC slot */
- ret = gpio_request(PINID_PWM3, "mmc power");
- if (ret)
- goto out_power;
-
- gpio_direction_output(PINID_PWM3, 0);
- mdelay(100);
-
- return 0;
-
-out_power:
- gpio_free(PINID_PWM4);
-out_wp:
- stmp3xxx_release_pin_group(&mmc_pins, "mmc");
-out:
- return ret;
-}
-
-static void stmp3xxxmmc_hw_release_ssp1(void)
-{
- gpio_free(PINID_PWM3);
- gpio_free(PINID_PWM4);
- stmp3xxx_release_pin_group(&mmc_pins, "mmc");
-}
-
-static void stmp3xxxmmc_cmd_pullup_ssp1(int enable)
-{
- stmp3xxx_pin_pullup(PINID_SSP1_CMD, enable, "mmc");
-}
-
-static unsigned long
-stmp3xxxmmc_setclock_ssp1(void __iomem *base, unsigned long hz)
-{
- struct clk *ssp, *parent;
- char *p;
- long r;
-
- ssp = clk_get(NULL, "ssp");
-
- /* using SSP1, no timeout, clock rate 1 */
- writel(BF(2, SSP_TIMING_CLOCK_DIVIDE) |
- BF(0xFFFF, SSP_TIMING_TIMEOUT),
- base + HW_SSP_TIMING);
-
- p = (hz > 1000000) ? "io" : "osc_24M";
- parent = clk_get(NULL, p);
- clk_set_parent(ssp, parent);
- r = clk_set_rate(ssp, 2 * hz / 1000);
- clk_put(parent);
- clk_put(ssp);
-
- return hz;
-}
-
-static struct stmp3xxxmmc_platform_data mmc_data = {
- .hw_init = stmp3xxxmmc_hw_init_ssp1,
- .hw_release = stmp3xxxmmc_hw_release_ssp1,
- .get_wp = stmp3xxxmmc_get_wp,
- .cmd_pullup = stmp3xxxmmc_cmd_pullup_ssp1,
- .setclock = stmp3xxxmmc_setclock_ssp1,
-};
-
-
-static struct pin_group appuart_pins[] = {
- [0] = {
- .pins = appuart_pins_0,
- .nr_pins = ARRAY_SIZE(appuart_pins_0),
- },
- [1] = {
- .pins = appuart_pins_1,
- .nr_pins = ARRAY_SIZE(appuart_pins_1),
- },
-};
-
-static struct pin_desc ssp1_pins_desc[] = {
- { PINID_SSP1_SCK, PIN_FUN1, PIN_8MA, PIN_3_3V, 0, },
- { PINID_SSP1_CMD, PIN_FUN1, PIN_4MA, PIN_3_3V, 0, },
- { PINID_SSP1_DATA0, PIN_FUN1, PIN_4MA, PIN_3_3V, 0, },
- { PINID_SSP1_DATA3, PIN_FUN1, PIN_4MA, PIN_3_3V, 0, },
-};
-
-static struct pin_desc ssp2_pins_desc[] = {
- { PINID_GPMI_WRN, PIN_FUN3, PIN_8MA, PIN_3_3V, 0, },
- { PINID_GPMI_RDY1, PIN_FUN3, PIN_4MA, PIN_3_3V, 0, },
- { PINID_GPMI_D00, PIN_FUN3, PIN_4MA, PIN_3_3V, 0, },
- { PINID_GPMI_D03, PIN_FUN3, PIN_4MA, PIN_3_3V, 0, },
-};
-
-static struct pin_group ssp1_pins = {
- .pins = ssp1_pins_desc,
- .nr_pins = ARRAY_SIZE(ssp1_pins_desc),
-};
-
-static struct pin_group ssp2_pins = {
- .pins = ssp1_pins_desc,
- .nr_pins = ARRAY_SIZE(ssp2_pins_desc),
-};
-
-static struct pin_desc gpmi_pins_desc[] = {
- { PINID_GPMI_CE0N, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
- { PINID_GPMI_CE1N, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
- { PINID_GMPI_CE2N, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
- { PINID_GPMI_CLE, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
- { PINID_GPMI_ALE, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
- { PINID_GPMI_WPN, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 },
- { PINID_GPMI_RDY1, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
- { PINID_GPMI_D00, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
- { PINID_GPMI_D01, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
- { PINID_GPMI_D02, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
- { PINID_GPMI_D03, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
- { PINID_GPMI_D04, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
- { PINID_GPMI_D05, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
- { PINID_GPMI_D06, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
- { PINID_GPMI_D07, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
- { PINID_GPMI_RDY0, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
- { PINID_GPMI_RDY2, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
- { PINID_GPMI_RDY3, PIN_FUN1, PIN_4MA, PIN_3_3V, 0 },
- { PINID_GPMI_WRN, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 },
- { PINID_GPMI_RDN, PIN_FUN1, PIN_12MA, PIN_3_3V, 0 },
-};
-
-static struct pin_group gpmi_pins = {
- .pins = gpmi_pins_desc,
- .nr_pins = ARRAY_SIZE(gpmi_pins_desc),
-};
-
-static struct mtd_partition gpmi_partitions[] = {
- [0] = {
- .name = "boot",
- .size = 10 * SZ_1M,
- .offset = 0,
- },
- [1] = {
- .name = "data",
- .size = MTDPART_SIZ_FULL,
- .offset = MTDPART_OFS_APPEND,
- },
-};
-
-static struct gpmi_platform_data gpmi_data = {
- .pins = &gpmi_pins,
- .nr_parts = ARRAY_SIZE(gpmi_partitions),
- .parts = gpmi_partitions,
- .part_types = { "cmdline", NULL },
-};
-
-static struct spi_board_info spi_board_info[] __initdata = {
-#if defined(CONFIG_ENC28J60) || defined(CONFIG_ENC28J60_MODULE)
- {
- .modalias = "enc28j60",
- .max_speed_hz = 6 * 1000 * 1000,
- .bus_num = 1,
- .chip_select = 0,
- .platform_data = NULL,
- },
-#endif
-};
-
-static void __init stmp378x_devb_init(void)
-{
- stmp3xxx_pinmux_init(NR_REAL_IRQS);
-
- /* init stmp3xxx platform */
- stmp3xxx_init();
-
- stmp3xxx_dbguart.dev.platform_data = dbguart_pins_control;
- stmp3xxx_appuart.dev.platform_data = appuart_pins;
- stmp3xxx_mmc.dev.platform_data = &mmc_data;
- stmp3xxx_gpmi.dev.platform_data = &gpmi_data;
- stmp3xxx_spi1.dev.platform_data = &ssp1_pins;
- stmp3xxx_spi2.dev.platform_data = &ssp2_pins;
- stmp378x_i2c.dev.platform_data = &i2c_pins;
-
- /* register spi devices */
- spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
-
- /* add board's devices */
- platform_add_devices(devices, ARRAY_SIZE(devices));
-
- /* add devices selected by command line ssp1= and ssp2= options */
- stmp3xxx_ssp1_device_register();
- stmp3xxx_ssp2_device_register();
-}
-
-MACHINE_START(STMP378X, "STMP378X")
- .boot_params = 0x40000100,
- .map_io = stmp378x_map_io,
- .init_irq = stmp378x_init_irq,
- .timer = &stmp3xxx_timer,
- .init_machine = stmp378x_devb_init,
-MACHINE_END
diff --git a/arch/arm/mach-stmp37xx/Makefile b/arch/arm/mach-stmp37xx/Makefile
deleted file mode 100644
index 57deffd09fbf..000000000000
--- a/arch/arm/mach-stmp37xx/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-obj-$(CONFIG_ARCH_STMP37XX) += stmp37xx.o
-obj-$(CONFIG_MACH_STMP37XX) += stmp37xx_devb.o
diff --git a/arch/arm/mach-stmp37xx/Makefile.boot b/arch/arm/mach-stmp37xx/Makefile.boot
deleted file mode 100644
index 1568ad404d59..000000000000
--- a/arch/arm/mach-stmp37xx/Makefile.boot
+++ /dev/null
@@ -1,3 +0,0 @@
- zreladdr-y := 0x40008000
-params_phys-y := 0x40000100
-initrd_phys-y := 0x40800000
diff --git a/arch/arm/mach-stmp37xx/include/mach/entry-macro.S b/arch/arm/mach-stmp37xx/include/mach/entry-macro.S
deleted file mode 100644
index fed2787b6c34..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/entry-macro.S
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Low-level IRQ helper macros for Freescale STMP37XX
- *
- * Embedded Alley Solutions, Inc <source@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-
- .macro disable_fiq
- .endm
-
- .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
-
- mov \base, #0xf0000000 @ vm address of IRQ controller
- ldr \irqnr, [\base, #0x30] @ HW_ICOLL_STAT
- cmp \irqnr, #0x3f
- movne \irqstat, #0 @ Ack this IRQ
- strne \irqstat, [\base, #0x00]@ HW_ICOLL_VECTOR
- moveqs \irqnr, #0 @ Zero flag set for no IRQ
-
- .endm
-
- .macro get_irqnr_preamble, base, tmp
- .endm
-
- .macro arch_ret_to_user, tmp1, tmp2
- .endm
diff --git a/arch/arm/mach-stmp37xx/include/mach/irqs.h b/arch/arm/mach-stmp37xx/include/mach/irqs.h
deleted file mode 100644
index 98f12938550d..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/irqs.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Freescale STMP37XX interrupts
- *
- * Copyright (C) 2005 Sigmatel Inc
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#ifndef _ASM_ARCH_IRQS_H
-#define _ASM_ARCH_IRQS_H
-
-#define IRQ_DEBUG_UART 0
-#define IRQ_COMMS_RX 1
-#define IRQ_COMMS_TX 1
-#define IRQ_SSP2_ERROR 2
-#define IRQ_VDD5V 3
-#define IRQ_HEADPHONE_SHORT 4
-#define IRQ_DAC_DMA 5
-#define IRQ_DAC_ERROR 6
-#define IRQ_ADC_DMA 7
-#define IRQ_ADC_ERROR 8
-#define IRQ_SPDIF_DMA 9
-#define IRQ_SAIF2_DMA 9
-#define IRQ_SPDIF_ERROR 10
-#define IRQ_SAIF1_IRQ 10
-#define IRQ_SAIF2_IRQ 10
-#define IRQ_USB_CTRL 11
-#define IRQ_USB_WAKEUP 12
-#define IRQ_GPMI_DMA 13
-#define IRQ_SSP1_DMA 14
-#define IRQ_SSP_ERROR 15
-#define IRQ_GPIO0 16
-#define IRQ_GPIO1 17
-#define IRQ_GPIO2 18
-#define IRQ_SAIF1_DMA 19
-#define IRQ_SSP2_DMA 20
-#define IRQ_ECC8_IRQ 21
-#define IRQ_RTC_ALARM 22
-#define IRQ_UARTAPP_TX_DMA 23
-#define IRQ_UARTAPP_INTERNAL 24
-#define IRQ_UARTAPP_RX_DMA 25
-#define IRQ_I2C_DMA 26
-#define IRQ_I2C_ERROR 27
-#define IRQ_TIMER0 28
-#define IRQ_TIMER1 29
-#define IRQ_TIMER2 30
-#define IRQ_TIMER3 31
-#define IRQ_BATT_BRNOUT 32
-#define IRQ_VDDD_BRNOUT 33
-#define IRQ_VDDIO_BRNOUT 34
-#define IRQ_VDD18_BRNOUT 35
-#define IRQ_TOUCH_DETECT 36
-#define IRQ_LRADC_CH0 37
-#define IRQ_LRADC_CH1 38
-#define IRQ_LRADC_CH2 39
-#define IRQ_LRADC_CH3 40
-#define IRQ_LRADC_CH4 41
-#define IRQ_LRADC_CH5 42
-#define IRQ_LRADC_CH6 43
-#define IRQ_LRADC_CH7 44
-#define IRQ_LCDIF_DMA 45
-#define IRQ_LCDIF_ERROR 46
-#define IRQ_DIGCTL_DEBUG_TRAP 47
-#define IRQ_RTC_1MSEC 48
-#define IRQ_DRI_DMA 49
-#define IRQ_DRI_ATTENTION 50
-#define IRQ_GPMI_ATTENTION 51
-#define IRQ_IR 52
-#define IRQ_DCP_VMI 53
-#define IRQ_DCP 54
-#define IRQ_RESERVED_55 55
-#define IRQ_RESERVED_56 56
-#define IRQ_RESERVED_57 57
-#define IRQ_RESERVED_58 58
-#define IRQ_RESERVED_59 59
-#define SW_IRQ_60 60
-#define SW_IRQ_61 61
-#define SW_IRQ_62 62
-#define SW_IRQ_63 63
-
-#define NR_REAL_IRQS 64
-#define NR_IRQS (NR_REAL_IRQS + 32 * 3)
-
-/* TIMER and BRNOUT are FIQ capable */
-#define FIQ_START IRQ_TIMER0
-
-/* Hard disk IRQ is a GPMI attention IRQ */
-#define IRQ_HARDDISK IRQ_GPMI_ATTENTION
-
-#endif /* _ASM_ARCH_IRQS_H */
diff --git a/arch/arm/mach-stmp37xx/include/mach/pins.h b/arch/arm/mach-stmp37xx/include/mach/pins.h
deleted file mode 100644
index d56de0c471d8..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/pins.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Freescale STMP37XX SoC pin multiplexing
- *
- * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#ifndef __ASM_ARCH_PINS_H
-#define __ASM_ARCH_PINS_H
-
-/*
- * Define all STMP37XX pins, a pin name corresponds to a STMP37xx hardware
- * interface this pin belongs to.
- */
-
-/* Bank 0 */
-#define PINID_GPMI_D00 STMP3XXX_PINID(0, 0)
-#define PINID_GPMI_D01 STMP3XXX_PINID(0, 1)
-#define PINID_GPMI_D02 STMP3XXX_PINID(0, 2)
-#define PINID_GPMI_D03 STMP3XXX_PINID(0, 3)
-#define PINID_GPMI_D04 STMP3XXX_PINID(0, 4)
-#define PINID_GPMI_D05 STMP3XXX_PINID(0, 5)
-#define PINID_GPMI_D06 STMP3XXX_PINID(0, 6)
-#define PINID_GPMI_D07 STMP3XXX_PINID(0, 7)
-#define PINID_GPMI_D08 STMP3XXX_PINID(0, 8)
-#define PINID_GPMI_D09 STMP3XXX_PINID(0, 9)
-#define PINID_GPMI_D10 STMP3XXX_PINID(0, 10)
-#define PINID_GPMI_D11 STMP3XXX_PINID(0, 11)
-#define PINID_GPMI_D12 STMP3XXX_PINID(0, 12)
-#define PINID_GPMI_D13 STMP3XXX_PINID(0, 13)
-#define PINID_GPMI_D14 STMP3XXX_PINID(0, 14)
-#define PINID_GPMI_D15 STMP3XXX_PINID(0, 15)
-#define PINID_GPMI_A0 STMP3XXX_PINID(0, 16)
-#define PINID_GPMI_A1 STMP3XXX_PINID(0, 17)
-#define PINID_GPMI_A2 STMP3XXX_PINID(0, 18)
-#define PINID_GPMI_RDY0 STMP3XXX_PINID(0, 19)
-#define PINID_GPMI_RDY2 STMP3XXX_PINID(0, 20)
-#define PINID_GPMI_RDY3 STMP3XXX_PINID(0, 21)
-#define PINID_GPMI_RESETN STMP3XXX_PINID(0, 22)
-#define PINID_GPMI_IRQ STMP3XXX_PINID(0, 23)
-#define PINID_GPMI_WRN STMP3XXX_PINID(0, 24)
-#define PINID_GPMI_RDN STMP3XXX_PINID(0, 25)
-#define PINID_UART2_CTS STMP3XXX_PINID(0, 26)
-#define PINID_UART2_RTS STMP3XXX_PINID(0, 27)
-#define PINID_UART2_RX STMP3XXX_PINID(0, 28)
-#define PINID_UART2_TX STMP3XXX_PINID(0, 29)
-
-/* Bank 1 */
-#define PINID_LCD_D00 STMP3XXX_PINID(1, 0)
-#define PINID_LCD_D01 STMP3XXX_PINID(1, 1)
-#define PINID_LCD_D02 STMP3XXX_PINID(1, 2)
-#define PINID_LCD_D03 STMP3XXX_PINID(1, 3)
-#define PINID_LCD_D04 STMP3XXX_PINID(1, 4)
-#define PINID_LCD_D05 STMP3XXX_PINID(1, 5)
-#define PINID_LCD_D06 STMP3XXX_PINID(1, 6)
-#define PINID_LCD_D07 STMP3XXX_PINID(1, 7)
-#define PINID_LCD_D08 STMP3XXX_PINID(1, 8)
-#define PINID_LCD_D09 STMP3XXX_PINID(1, 9)
-#define PINID_LCD_D10 STMP3XXX_PINID(1, 10)
-#define PINID_LCD_D11 STMP3XXX_PINID(1, 11)
-#define PINID_LCD_D12 STMP3XXX_PINID(1, 12)
-#define PINID_LCD_D13 STMP3XXX_PINID(1, 13)
-#define PINID_LCD_D14 STMP3XXX_PINID(1, 14)
-#define PINID_LCD_D15 STMP3XXX_PINID(1, 15)
-#define PINID_LCD_RESET STMP3XXX_PINID(1, 16)
-#define PINID_LCD_RS STMP3XXX_PINID(1, 17)
-#define PINID_LCD_WR_RWN STMP3XXX_PINID(1, 18)
-#define PINID_LCD_RD_E STMP3XXX_PINID(1, 19)
-#define PINID_LCD_CS STMP3XXX_PINID(1, 20)
-#define PINID_LCD_BUSY STMP3XXX_PINID(1, 21)
-#define PINID_SSP1_CMD STMP3XXX_PINID(1, 22)
-#define PINID_SSP1_SCK STMP3XXX_PINID(1, 23)
-#define PINID_SSP1_DATA0 STMP3XXX_PINID(1, 24)
-#define PINID_SSP1_DATA1 STMP3XXX_PINID(1, 25)
-#define PINID_SSP1_DATA2 STMP3XXX_PINID(1, 26)
-#define PINID_SSP1_DATA3 STMP3XXX_PINID(1, 27)
-#define PINID_SSP1_DETECT STMP3XXX_PINID(1, 28)
-
-/* Bank 2 */
-#define PINID_PWM0 STMP3XXX_PINID(2, 0)
-#define PINID_PWM1 STMP3XXX_PINID(2, 1)
-#define PINID_PWM2 STMP3XXX_PINID(2, 2)
-#define PINID_PWM3 STMP3XXX_PINID(2, 3)
-#define PINID_PWM4 STMP3XXX_PINID(2, 4)
-#define PINID_I2C_SCL STMP3XXX_PINID(2, 5)
-#define PINID_I2C_SDA STMP3XXX_PINID(2, 6)
-#define PINID_ROTTARYA STMP3XXX_PINID(2, 7)
-#define PINID_ROTTARYB STMP3XXX_PINID(2, 8)
-#define PINID_EMI_CKE STMP3XXX_PINID(2, 9)
-#define PINID_EMI_RASN STMP3XXX_PINID(2, 10)
-#define PINID_EMI_CASN STMP3XXX_PINID(2, 11)
-#define PINID_EMI_CE0N STMP3XXX_PINID(2, 12)
-#define PINID_EMI_CE1N STMP3XXX_PINID(2, 13)
-#define PINID_EMI_CE2N STMP3XXX_PINID(2, 14)
-#define PINID_EMI_CE3N STMP3XXX_PINID(2, 15)
-#define PINID_EMI_A00 STMP3XXX_PINID(2, 16)
-#define PINID_EMI_A01 STMP3XXX_PINID(2, 17)
-#define PINID_EMI_A02 STMP3XXX_PINID(2, 18)
-#define PINID_EMI_A03 STMP3XXX_PINID(2, 19)
-#define PINID_EMI_A04 STMP3XXX_PINID(2, 20)
-#define PINID_EMI_A05 STMP3XXX_PINID(2, 21)
-#define PINID_EMI_A06 STMP3XXX_PINID(2, 22)
-#define PINID_EMI_A07 STMP3XXX_PINID(2, 23)
-#define PINID_EMI_A08 STMP3XXX_PINID(2, 24)
-#define PINID_EMI_A09 STMP3XXX_PINID(2, 25)
-#define PINID_EMI_A10 STMP3XXX_PINID(2, 26)
-#define PINID_EMI_A11 STMP3XXX_PINID(2, 27)
-#define PINID_EMI_A12 STMP3XXX_PINID(2, 28)
-#define PINID_EMI_A13 STMP3XXX_PINID(2, 29)
-#define PINID_EMI_A14 STMP3XXX_PINID(2, 30)
-#define PINID_EMI_WEN STMP3XXX_PINID(2, 31)
-
-/* Bank 3 */
-#define PINID_EMI_D00 STMP3XXX_PINID(3, 0)
-#define PINID_EMI_D01 STMP3XXX_PINID(3, 1)
-#define PINID_EMI_D02 STMP3XXX_PINID(3, 2)
-#define PINID_EMI_D03 STMP3XXX_PINID(3, 3)
-#define PINID_EMI_D04 STMP3XXX_PINID(3, 4)
-#define PINID_EMI_D05 STMP3XXX_PINID(3, 5)
-#define PINID_EMI_D06 STMP3XXX_PINID(3, 6)
-#define PINID_EMI_D07 STMP3XXX_PINID(3, 7)
-#define PINID_EMI_D08 STMP3XXX_PINID(3, 8)
-#define PINID_EMI_D09 STMP3XXX_PINID(3, 9)
-#define PINID_EMI_D10 STMP3XXX_PINID(3, 10)
-#define PINID_EMI_D11 STMP3XXX_PINID(3, 11)
-#define PINID_EMI_D12 STMP3XXX_PINID(3, 12)
-#define PINID_EMI_D13 STMP3XXX_PINID(3, 13)
-#define PINID_EMI_D14 STMP3XXX_PINID(3, 14)
-#define PINID_EMI_D15 STMP3XXX_PINID(3, 15)
-#define PINID_EMI_DQS0 STMP3XXX_PINID(3, 16)
-#define PINID_EMI_DQS1 STMP3XXX_PINID(3, 17)
-#define PINID_EMI_DQM0 STMP3XXX_PINID(3, 18)
-#define PINID_EMI_DQM1 STMP3XXX_PINID(3, 19)
-#define PINID_EMI_CLK STMP3XXX_PINID(3, 20)
-#define PINID_EMI_CLKN STMP3XXX_PINID(3, 21)
-
-#endif /* __ASM_ARCH_PINS_H */
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-apbh.h b/arch/arm/mach-stmp37xx/include/mach/regs-apbh.h
deleted file mode 100644
index a323aa9a21f2..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/regs-apbh.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * stmp37xx: APBH register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef _MACH_REGS_APBH
-#define _MACH_REGS_APBH
-
-#define REGS_APBH_BASE (STMP3XXX_REGS_BASE + 0x4000)
-
-#define HW_APBH_CTRL0 0x0
-#define BM_APBH_CTRL0_RESET_CHANNEL 0x00FF0000
-#define BP_APBH_CTRL0_RESET_CHANNEL 16
-#define BM_APBH_CTRL0_CLKGATE 0x40000000
-#define BM_APBH_CTRL0_SFTRST 0x80000000
-
-#define HW_APBH_CTRL1 0x10
-#define BM_APBH_CTRL1_CH0_CMDCMPLT_IRQ 0x00000001
-#define BP_APBH_CTRL1_CH0_CMDCMPLT_IRQ 0
-
-#define HW_APBH_DEVSEL 0x20
-
-#define HW_APBH_CH0_NXTCMDAR (0x50 + 0 * 0x70)
-#define HW_APBH_CH1_NXTCMDAR (0x50 + 1 * 0x70)
-#define HW_APBH_CH2_NXTCMDAR (0x50 + 2 * 0x70)
-#define HW_APBH_CH3_NXTCMDAR (0x50 + 3 * 0x70)
-#define HW_APBH_CH4_NXTCMDAR (0x50 + 4 * 0x70)
-#define HW_APBH_CH5_NXTCMDAR (0x50 + 5 * 0x70)
-#define HW_APBH_CH6_NXTCMDAR (0x50 + 6 * 0x70)
-#define HW_APBH_CH7_NXTCMDAR (0x50 + 7 * 0x70)
-#define HW_APBH_CH8_NXTCMDAR (0x50 + 8 * 0x70)
-#define HW_APBH_CH9_NXTCMDAR (0x50 + 9 * 0x70)
-#define HW_APBH_CH10_NXTCMDAR (0x50 + 10 * 0x70)
-#define HW_APBH_CH11_NXTCMDAR (0x50 + 11 * 0x70)
-#define HW_APBH_CH12_NXTCMDAR (0x50 + 12 * 0x70)
-#define HW_APBH_CH13_NXTCMDAR (0x50 + 13 * 0x70)
-#define HW_APBH_CH14_NXTCMDAR (0x50 + 14 * 0x70)
-#define HW_APBH_CH15_NXTCMDAR (0x50 + 15 * 0x70)
-
-#define HW_APBH_CHn_NXTCMDAR 0x50
-
-#define BM_APBH_CHn_CMD_MODE 0x00000003
-#define BP_APBH_CHn_CMD_MODE 0x00000001
-#define BV_APBH_CHn_CMD_MODE_NOOP 0
-#define BV_APBH_CHn_CMD_MODE_WRITE 1
-#define BV_APBH_CHn_CMD_MODE_READ 2
-#define BV_APBH_CHn_CMD_MODE_SENSE 3
-#define BM_APBH_CHn_CMD_CHAIN 0x00000004
-#define BM_APBH_CHn_CMD_IRQONCMPLT 0x00000008
-#define BM_APBH_CHn_CMD_NANDLOCK 0x00000010
-#define BM_APBH_CHn_CMD_NANDWAIT4READY 0x00000020
-#define BM_APBH_CHn_CMD_SEMAPHORE 0x00000040
-#define BM_APBH_CHn_CMD_WAIT4ENDCMD 0x00000080
-#define BM_APBH_CHn_CMD_CMDWORDS 0x0000F000
-#define BP_APBH_CHn_CMD_CMDWORDS 12
-#define BM_APBH_CHn_CMD_XFER_COUNT 0xFFFF0000
-#define BP_APBH_CHn_CMD_XFER_COUNT 16
-
-#define HW_APBH_CH0_SEMA (0x80 + 0 * 0x70)
-#define HW_APBH_CH1_SEMA (0x80 + 1 * 0x70)
-#define HW_APBH_CH2_SEMA (0x80 + 2 * 0x70)
-#define HW_APBH_CH3_SEMA (0x80 + 3 * 0x70)
-#define HW_APBH_CH4_SEMA (0x80 + 4 * 0x70)
-#define HW_APBH_CH5_SEMA (0x80 + 5 * 0x70)
-#define HW_APBH_CH6_SEMA (0x80 + 6 * 0x70)
-#define HW_APBH_CH7_SEMA (0x80 + 7 * 0x70)
-#define HW_APBH_CH8_SEMA (0x80 + 8 * 0x70)
-#define HW_APBH_CH9_SEMA (0x80 + 9 * 0x70)
-#define HW_APBH_CH10_SEMA (0x80 + 10 * 0x70)
-#define HW_APBH_CH11_SEMA (0x80 + 11 * 0x70)
-#define HW_APBH_CH12_SEMA (0x80 + 12 * 0x70)
-#define HW_APBH_CH13_SEMA (0x80 + 13 * 0x70)
-#define HW_APBH_CH14_SEMA (0x80 + 14 * 0x70)
-#define HW_APBH_CH15_SEMA (0x80 + 15 * 0x70)
-
-#define HW_APBH_CHn_SEMA 0x80
-#define BM_APBH_CHn_SEMA_INCREMENT_SEMA 0x000000FF
-#define BP_APBH_CHn_SEMA_INCREMENT_SEMA 0
-#define BM_APBH_CHn_SEMA_PHORE 0x00FF0000
-#define BP_APBH_CHn_SEMA_PHORE 16
-
-#endif
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-apbx.h b/arch/arm/mach-stmp37xx/include/mach/regs-apbx.h
deleted file mode 100644
index 6d080cd5b702..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/regs-apbx.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * stmp37xx: APBX register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef _MACH_REGS_APBX
-#define _MACH_REGS_APBX
-
-#define REGS_APBX_BASE (STMP3XXX_REGS_BASE + 0x24000)
-
-#define HW_APBX_CTRL0 0x0
-#define BM_APBX_CTRL0_RESET_CHANNEL 0x00FF0000
-#define BP_APBX_CTRL0_RESET_CHANNEL 16
-#define BM_APBX_CTRL0_CLKGATE 0x40000000
-#define BM_APBX_CTRL0_SFTRST 0x80000000
-
-#define HW_APBX_CTRL1 0x10
-
-#define HW_APBX_DEVSEL 0x20
-
-#define HW_APBX_CH0_NXTCMDAR (0x50 + 0 * 0x70)
-#define HW_APBX_CH1_NXTCMDAR (0x50 + 1 * 0x70)
-#define HW_APBX_CH2_NXTCMDAR (0x50 + 2 * 0x70)
-#define HW_APBX_CH3_NXTCMDAR (0x50 + 3 * 0x70)
-#define HW_APBX_CH4_NXTCMDAR (0x50 + 4 * 0x70)
-#define HW_APBX_CH5_NXTCMDAR (0x50 + 5 * 0x70)
-#define HW_APBX_CH6_NXTCMDAR (0x50 + 6 * 0x70)
-#define HW_APBX_CH7_NXTCMDAR (0x50 + 7 * 0x70)
-#define HW_APBX_CH8_NXTCMDAR (0x50 + 8 * 0x70)
-#define HW_APBX_CH9_NXTCMDAR (0x50 + 9 * 0x70)
-#define HW_APBX_CH10_NXTCMDAR (0x50 + 10 * 0x70)
-#define HW_APBX_CH11_NXTCMDAR (0x50 + 11 * 0x70)
-#define HW_APBX_CH12_NXTCMDAR (0x50 + 12 * 0x70)
-#define HW_APBX_CH13_NXTCMDAR (0x50 + 13 * 0x70)
-#define HW_APBX_CH14_NXTCMDAR (0x50 + 14 * 0x70)
-#define HW_APBX_CH15_NXTCMDAR (0x50 + 15 * 0x70)
-
-#define HW_APBX_CHn_NXTCMDAR 0x50
-#define BM_APBX_CHn_CMD_MODE 0x00000003
-#define BP_APBX_CHn_CMD_MODE 0x00000001
-#define BV_APBX_CHn_CMD_MODE_NOOP 0
-#define BV_APBX_CHn_CMD_MODE_WRITE 1
-#define BV_APBX_CHn_CMD_MODE_READ 2
-#define BV_APBX_CHn_CMD_MODE_SENSE 3
-#define BM_APBX_CHn_CMD_COMMAND 0x00000003
-#define BP_APBX_CHn_CMD_COMMAND 0
-#define BM_APBX_CHn_CMD_CHAIN 0x00000004
-#define BM_APBX_CHn_CMD_IRQONCMPLT 0x00000008
-#define BM_APBX_CHn_CMD_SEMAPHORE 0x00000040
-#define BM_APBX_CHn_CMD_WAIT4ENDCMD 0x00000080
-#define BM_APBX_CHn_CMD_CMDWORDS 0x0000F000
-#define BP_APBX_CHn_CMD_CMDWORDS 12
-#define BM_APBX_CHn_CMD_XFER_COUNT 0xFFFF0000
-#define BP_APBX_CHn_CMD_XFER_COUNT 16
-
-#define HW_APBX_CH0_BAR (0x70 + 0 * 0x70)
-#define HW_APBX_CH1_BAR (0x70 + 1 * 0x70)
-#define HW_APBX_CH2_BAR (0x70 + 2 * 0x70)
-#define HW_APBX_CH3_BAR (0x70 + 3 * 0x70)
-#define HW_APBX_CH4_BAR (0x70 + 4 * 0x70)
-#define HW_APBX_CH5_BAR (0x70 + 5 * 0x70)
-#define HW_APBX_CH6_BAR (0x70 + 6 * 0x70)
-#define HW_APBX_CH7_BAR (0x70 + 7 * 0x70)
-#define HW_APBX_CH8_BAR (0x70 + 8 * 0x70)
-#define HW_APBX_CH9_BAR (0x70 + 9 * 0x70)
-#define HW_APBX_CH10_BAR (0x70 + 10 * 0x70)
-#define HW_APBX_CH11_BAR (0x70 + 11 * 0x70)
-#define HW_APBX_CH12_BAR (0x70 + 12 * 0x70)
-#define HW_APBX_CH13_BAR (0x70 + 13 * 0x70)
-#define HW_APBX_CH14_BAR (0x70 + 14 * 0x70)
-#define HW_APBX_CH15_BAR (0x70 + 15 * 0x70)
-
-#define HW_APBX_CHn_BAR 0x70
-
-#define HW_APBX_CH0_SEMA (0x80 + 0 * 0x70)
-#define HW_APBX_CH1_SEMA (0x80 + 1 * 0x70)
-#define HW_APBX_CH2_SEMA (0x80 + 2 * 0x70)
-#define HW_APBX_CH3_SEMA (0x80 + 3 * 0x70)
-#define HW_APBX_CH4_SEMA (0x80 + 4 * 0x70)
-#define HW_APBX_CH5_SEMA (0x80 + 5 * 0x70)
-#define HW_APBX_CH6_SEMA (0x80 + 6 * 0x70)
-#define HW_APBX_CH7_SEMA (0x80 + 7 * 0x70)
-#define HW_APBX_CH8_SEMA (0x80 + 8 * 0x70)
-#define HW_APBX_CH9_SEMA (0x80 + 9 * 0x70)
-#define HW_APBX_CH10_SEMA (0x80 + 10 * 0x70)
-#define HW_APBX_CH11_SEMA (0x80 + 11 * 0x70)
-#define HW_APBX_CH12_SEMA (0x80 + 12 * 0x70)
-#define HW_APBX_CH13_SEMA (0x80 + 13 * 0x70)
-#define HW_APBX_CH14_SEMA (0x80 + 14 * 0x70)
-#define HW_APBX_CH15_SEMA (0x80 + 15 * 0x70)
-
-#define HW_APBX_CHn_SEMA 0x80
-#define BM_APBX_CHn_SEMA_INCREMENT_SEMA 0x000000FF
-#define BP_APBX_CHn_SEMA_INCREMENT_SEMA 0
-#define BM_APBX_CHn_SEMA_PHORE 0x00FF0000
-#define BP_APBX_CHn_SEMA_PHORE 16
-
-#endif
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-audioin.h b/arch/arm/mach-stmp37xx/include/mach/regs-audioin.h
deleted file mode 100644
index 3b511f947a53..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/regs-audioin.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * stmp37xx: AUDIOIN register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_AUDIOIN_BASE (STMP3XXX_REGS_BASE + 0x4C000)
-
-#define HW_AUDIOIN_CTRL 0x0
-#define BM_AUDIOIN_CTRL_RUN 0x00000001
-#define BP_AUDIOIN_CTRL_RUN 0
-#define BM_AUDIOIN_CTRL_FIFO_ERROR_IRQ_EN 0x00000002
-#define BM_AUDIOIN_CTRL_FIFO_OVERFLOW_IRQ 0x00000004
-#define BM_AUDIOIN_CTRL_FIFO_UNDERFLOW_IRQ 0x00000008
-#define BM_AUDIOIN_CTRL_WORD_LENGTH 0x00000020
-#define BM_AUDIOIN_CTRL_CLKGATE 0x40000000
-#define BM_AUDIOIN_CTRL_SFTRST 0x80000000
-
-#define HW_AUDIOIN_STAT 0x10
-
-#define HW_AUDIOIN_ADCSRR 0x20
-
-#define HW_AUDIOIN_ADCVOLUME 0x30
-#define BM_AUDIOIN_ADCVOLUME_VOLUME_RIGHT 0x000000FF
-#define BP_AUDIOIN_ADCVOLUME_VOLUME_RIGHT 0
-#define BM_AUDIOIN_ADCVOLUME_VOLUME_LEFT 0x00FF0000
-#define BP_AUDIOIN_ADCVOLUME_VOLUME_LEFT 16
-
-#define HW_AUDIOIN_ADCDEBUG 0x40
-
-#define HW_AUDIOIN_ADCVOL 0x50
-#define BM_AUDIOIN_ADCVOL_GAIN_RIGHT 0x0000000F
-#define BP_AUDIOIN_ADCVOL_GAIN_RIGHT 0
-#define BM_AUDIOIN_ADCVOL_SELECT_RIGHT 0x00000030
-#define BP_AUDIOIN_ADCVOL_SELECT_RIGHT 4
-#define BM_AUDIOIN_ADCVOL_GAIN_LEFT 0x00000F00
-#define BP_AUDIOIN_ADCVOL_GAIN_LEFT 8
-#define BM_AUDIOIN_ADCVOL_SELECT_LEFT 0x00003000
-#define BP_AUDIOIN_ADCVOL_SELECT_LEFT 12
-#define BM_AUDIOIN_ADCVOL_MUTE 0x01000000
-
-#define HW_AUDIOIN_MICLINE 0x60
-
-#define HW_AUDIOIN_ANACLKCTRL 0x70
-#define BM_AUDIOIN_ANACLKCTRL_CLKGATE 0x80000000
-
-#define HW_AUDIOIN_DATA 0x80
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-audioout.h b/arch/arm/mach-stmp37xx/include/mach/regs-audioout.h
deleted file mode 100644
index ca1942b8a3e9..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/regs-audioout.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * stmp37xx: AUDIOOUT register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_AUDIOOUT_BASE (STMP3XXX_REGS_BASE + 0x48000)
-
-#define HW_AUDIOOUT_CTRL 0x0
-#define BM_AUDIOOUT_CTRL_RUN 0x00000001
-#define BP_AUDIOOUT_CTRL_RUN 0
-#define BM_AUDIOOUT_CTRL_FIFO_ERROR_IRQ_EN 0x00000002
-#define BM_AUDIOOUT_CTRL_FIFO_OVERFLOW_IRQ 0x00000004
-#define BM_AUDIOOUT_CTRL_FIFO_UNDERFLOW_IRQ 0x00000008
-#define BM_AUDIOOUT_CTRL_WORD_LENGTH 0x00000040
-#define BM_AUDIOOUT_CTRL_CLKGATE 0x40000000
-#define BM_AUDIOOUT_CTRL_SFTRST 0x80000000
-
-#define HW_AUDIOOUT_STAT 0x10
-
-#define HW_AUDIOOUT_DACSRR 0x20
-#define BM_AUDIOOUT_DACSRR_SRC_FRAC 0x00001FFF
-#define BP_AUDIOOUT_DACSRR_SRC_FRAC 0
-#define BM_AUDIOOUT_DACSRR_SRC_INT 0x001F0000
-#define BP_AUDIOOUT_DACSRR_SRC_INT 16
-#define BM_AUDIOOUT_DACSRR_SRC_HOLD 0x07000000
-#define BP_AUDIOOUT_DACSRR_SRC_HOLD 24
-#define BM_AUDIOOUT_DACSRR_BASEMULT 0x70000000
-#define BP_AUDIOOUT_DACSRR_BASEMULT 28
-
-#define HW_AUDIOOUT_DACVOLUME 0x30
-#define BM_AUDIOOUT_DACVOLUME_MUTE_RIGHT 0x00000100
-#define BM_AUDIOOUT_DACVOLUME_MUTE_LEFT 0x01000000
-#define BM_AUDIOOUT_DACVOLUME_EN_ZCD 0x02000000
-
-#define HW_AUDIOOUT_DACDEBUG 0x40
-
-#define HW_AUDIOOUT_HPVOL 0x50
-#define BM_AUDIOOUT_HPVOL_MUTE 0x01000000
-#define BM_AUDIOOUT_HPVOL_EN_MSTR_ZCD 0x02000000
-
-#define HW_AUDIOOUT_PWRDN 0x70
-#define BM_AUDIOOUT_PWRDN_HEADPHONE 0x00000001
-#define BP_AUDIOOUT_PWRDN_HEADPHONE 0
-#define BM_AUDIOOUT_PWRDN_CAPLESS 0x00000010
-#define BM_AUDIOOUT_PWRDN_ADC 0x00000100
-#define BM_AUDIOOUT_PWRDN_DAC 0x00001000
-#define BM_AUDIOOUT_PWRDN_RIGHT_ADC 0x00010000
-#define BM_AUDIOOUT_PWRDN_LINEOUT 0x01000000
-
-#define HW_AUDIOOUT_REFCTRL 0x80
-#define BM_AUDIOOUT_REFCTRL_VAG_VAL 0x000000F0
-#define BP_AUDIOOUT_REFCTRL_VAG_VAL 4
-#define BM_AUDIOOUT_REFCTRL_ADC_REFVAL 0x00000F00
-#define BP_AUDIOOUT_REFCTRL_ADC_REFVAL 8
-#define BM_AUDIOOUT_REFCTRL_ADJ_VAG 0x00001000
-#define BM_AUDIOOUT_REFCTRL_ADJ_ADC 0x00002000
-#define BM_AUDIOOUT_REFCTRL_BIAS_CTRL 0x00030000
-#define BP_AUDIOOUT_REFCTRL_BIAS_CTRL 16
-#define BM_AUDIOOUT_REFCTRL_LOW_PWR 0x00080000
-#define BM_AUDIOOUT_REFCTRL_VBG_ADJ 0x00700000
-#define BP_AUDIOOUT_REFCTRL_VBG_ADJ 20
-#define BM_AUDIOOUT_REFCTRL_XTAL_BGR_BIAS 0x01000000
-#define BM_AUDIOOUT_REFCTRL_RAISE_REF 0x02000000
-
-#define HW_AUDIOOUT_ANACTRL 0x90
-#define BM_AUDIOOUT_ANACTRL_HP_CLASSAB 0x00000010
-#define BM_AUDIOOUT_ANACTRL_HP_HOLD_GND 0x00000020
-
-#define HW_AUDIOOUT_TEST 0xA0
-#define BM_AUDIOOUT_TEST_HP_I1_ADJ 0x00C00000
-#define BP_AUDIOOUT_TEST_HP_I1_ADJ 22
-
-#define HW_AUDIOOUT_BISTCTRL 0xB0
-
-#define HW_AUDIOOUT_BISTSTAT0 0xC0
-
-#define HW_AUDIOOUT_BISTSTAT1 0xD0
-
-#define HW_AUDIOOUT_ANACLKCTRL 0xE0
-#define BM_AUDIOOUT_ANACLKCTRL_CLKGATE 0x80000000
-
-#define HW_AUDIOOUT_DATA 0xF0
-
-#define HW_AUDIOOUT_LINEOUTCTRL 0x100
-#define BM_AUDIOOUT_LINEOUTCTRL_VOL_RIGHT 0x0000001F
-#define BP_AUDIOOUT_LINEOUTCTRL_VOL_RIGHT 0
-#define BM_AUDIOOUT_LINEOUTCTRL_VOL_LEFT 0x00001F00
-#define BP_AUDIOOUT_LINEOUTCTRL_VOL_LEFT 8
-#define BM_AUDIOOUT_LINEOUTCTRL_CHARGE_CAP 0x00007000
-#define BP_AUDIOOUT_LINEOUTCTRL_CHARGE_CAP 12
-#define BM_AUDIOOUT_LINEOUTCTRL_VAG_CTRL 0x00F00000
-#define BP_AUDIOOUT_LINEOUTCTRL_VAG_CTRL 20
-#define BM_AUDIOOUT_LINEOUTCTRL_MUTE 0x01000000
-#define BM_AUDIOOUT_LINEOUTCTRL_EN_ZCD 0x02000000
-
-#define HW_AUDIOOUT_VERSION 0x200
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-clkctrl.h b/arch/arm/mach-stmp37xx/include/mach/regs-clkctrl.h
deleted file mode 100644
index 47f5c92fdaf6..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/regs-clkctrl.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * stmp37xx: CLKCTRL register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef _MACH_REGS_CLKCTRL
-#define _MACH_REGS_CLKCTRL
-
-#define REGS_CLKCTRL_BASE (STMP3XXX_REGS_BASE + 0x40000)
-
-#define HW_CLKCTRL_PLLCTRL0 0x0
-#define BM_CLKCTRL_PLLCTRL0_EN_USB_CLKS 0x00040000
-
-#define HW_CLKCTRL_CPU 0x20
-#define BM_CLKCTRL_CPU_DIV_CPU 0x0000003F
-#define BP_CLKCTRL_CPU_DIV_CPU 0
-
-#define HW_CLKCTRL_HBUS 0x30
-#define BM_CLKCTRL_HBUS_DIV 0x0000001F
-#define BP_CLKCTRL_HBUS_DIV 0
-
-#define HW_CLKCTRL_XBUS 0x40
-
-#define HW_CLKCTRL_XTAL 0x50
-
-#define HW_CLKCTRL_PIX 0x60
-#define BM_CLKCTRL_PIX_DIV 0x00007FFF
-#define BP_CLKCTRL_PIX_DIV 0
-#define BM_CLKCTRL_PIX_CLKGATE 0x80000000
-
-#define HW_CLKCTRL_SSP 0x70
-
-#define HW_CLKCTRL_GPMI 0x80
-
-#define HW_CLKCTRL_SPDIF 0x90
-
-#define HW_CLKCTRL_EMI 0xA0
-
-#define HW_CLKCTRL_IR 0xB0
-
-#define HW_CLKCTRL_SAIF 0xC0
-
-#define HW_CLKCTRL_FRAC 0xD0
-#define BM_CLKCTRL_FRAC_EMIFRAC 0x00003F00
-#define BP_CLKCTRL_FRAC_EMIFRAC 8
-#define BM_CLKCTRL_FRAC_PIXFRAC 0x003F0000
-#define BP_CLKCTRL_FRAC_PIXFRAC 16
-#define BM_CLKCTRL_FRAC_CLKGATEPIX 0x00800000
-
-#define HW_CLKCTRL_CLKSEQ 0xE0
-#define BM_CLKCTRL_CLKSEQ_BYPASS_PIX 0x00000002
-
-#define HW_CLKCTRL_RESET 0xF0
-#define BM_CLKCTRL_RESET_DIG 0x00000001
-#define BP_CLKCTRL_RESET_DIG 0
-
-#endif
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-digctl.h b/arch/arm/mach-stmp37xx/include/mach/regs-digctl.h
deleted file mode 100644
index ba1bbe265c20..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/regs-digctl.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * stmp37xx: DIGCTL register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_DIGCTL_BASE (STMP3XXX_REGS_BASE + 0x1C000)
-
-#define HW_DIGCTL_CTRL 0x0
-#define BM_DIGCTL_CTRL_USB_CLKGATE 0x00000004
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-ecc8.h b/arch/arm/mach-stmp37xx/include/mach/regs-ecc8.h
deleted file mode 100644
index 3b6d990a3af5..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/regs-ecc8.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * stmp37xx: ECC8 register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_ECC8_BASE (STMP3XXX_REGS_BASE + 0x8000)
-
-#define HW_ECC8_CTRL 0x0
-#define BM_ECC8_CTRL_COMPLETE_IRQ 0x00000001
-#define BP_ECC8_CTRL_COMPLETE_IRQ 0
-#define BM_ECC8_CTRL_COMPLETE_IRQ_EN 0x00000100
-#define BM_ECC8_CTRL_AHBM_SFTRST 0x20000000
-
-#define HW_ECC8_STATUS0 0x10
-#define BM_ECC8_STATUS0_UNCORRECTABLE 0x00000004
-#define BM_ECC8_STATUS0_CORRECTED 0x00000008
-#define BM_ECC8_STATUS0_STATUS_AUX 0x00000F00
-#define BP_ECC8_STATUS0_STATUS_AUX 8
-#define BM_ECC8_STATUS0_COMPLETED_CE 0x000F0000
-#define BP_ECC8_STATUS0_COMPLETED_CE 16
-
-#define HW_ECC8_STATUS1 0x20
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-gpmi.h b/arch/arm/mach-stmp37xx/include/mach/regs-gpmi.h
deleted file mode 100644
index f2b304f54490..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/regs-gpmi.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * stmp37xx: GPMI register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_GPMI_BASE (STMP3XXX_REGS_BASE + 0xC000)
-#define REGS_GPMI_PHYS 0x8000C000
-#define REGS_GPMI_SIZE 0x2000
-
-#define HW_GPMI_CTRL0 0x0
-#define BM_GPMI_CTRL0_XFER_COUNT 0x0000FFFF
-#define BP_GPMI_CTRL0_XFER_COUNT 0
-#define BM_GPMI_CTRL0_CS 0x00300000
-#define BP_GPMI_CTRL0_CS 20
-#define BM_GPMI_CTRL0_LOCK_CS 0x00400000
-#define BM_GPMI_CTRL0_WORD_LENGTH 0x00800000
-#define BM_GPMI_CTRL0_COMMAND_MODE 0x03000000
-#define BP_GPMI_CTRL0_COMMAND_MODE 24
-#define BV_GPMI_CTRL0_COMMAND_MODE__WRITE 0x0
-#define BV_GPMI_CTRL0_COMMAND_MODE__READ 0x1
-#define BV_GPMI_CTRL0_COMMAND_MODE__READ_AND_COMPARE 0x2
-#define BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY 0x3
-#define BM_GPMI_CTRL0_RUN 0x20000000
-#define BM_GPMI_CTRL0_CLKGATE 0x40000000
-#define BM_GPMI_CTRL0_SFTRST 0x80000000
-#define BM_GPMI_ECCCTRL_ENABLE_ECC 0x00001000
-#define BM_GPMI_ECCCTRL_ECC_CMD 0x00006000
-#define BP_GPMI_ECCCTRL_ECC_CMD 13
-
-#define HW_GPMI_CTRL1 0x60
-#define BM_GPMI_CTRL1_GPMI_MODE 0x00000003
-#define BP_GPMI_CTRL1_GPMI_MODE 0
-#define BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY 0x00000004
-#define BM_GPMI_CTRL1_DEV_RESET 0x00000008
-#define BM_GPMI_CTRL1_TIMEOUT_IRQ 0x00000200
-#define BM_GPMI_CTRL1_DEV_IRQ 0x00000400
-#define BM_GPMI_CTRL1_DSAMPLE_TIME 0x00007000
-#define BP_GPMI_CTRL1_DSAMPLE_TIME 12
-
-#define HW_GPMI_TIMING0 0x70
-#define BM_GPMI_TIMING0_DATA_SETUP 0x000000FF
-#define BP_GPMI_TIMING0_DATA_SETUP 0
-#define BM_GPMI_TIMING0_DATA_HOLD 0x0000FF00
-#define BP_GPMI_TIMING0_DATA_HOLD 8
-
-#define HW_GPMI_TIMING1 0x80
-#define BM_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT 0xFFFF0000
-#define BP_GPMI_TIMING1_DEVICE_BUSY_TIMEOUT 16
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-i2c.h b/arch/arm/mach-stmp37xx/include/mach/regs-i2c.h
deleted file mode 100644
index 35882a9b8bc5..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/regs-i2c.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * stmp37xx: I2C register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_I2C_BASE (STMP3XXX_REGS_BASE + 0x58000)
-#define REGS_I2C_PHYS 0x80058000
-#define REGS_I2C_SIZE 0x2000
-
-#define HW_I2C_CTRL0 0x0
-#define BM_I2C_CTRL0_XFER_COUNT 0x0000FFFF
-#define BP_I2C_CTRL0_XFER_COUNT 0
-#define BM_I2C_CTRL0_DIRECTION 0x00010000
-#define BM_I2C_CTRL0_MASTER_MODE 0x00020000
-#define BM_I2C_CTRL0_PRE_SEND_START 0x00080000
-#define BM_I2C_CTRL0_POST_SEND_STOP 0x00100000
-#define BM_I2C_CTRL0_RETAIN_CLOCK 0x00200000
-#define BM_I2C_CTRL0_SEND_NAK_ON_LAST 0x02000000
-#define BM_I2C_CTRL0_CLKGATE 0x40000000
-#define BM_I2C_CTRL0_SFTRST 0x80000000
-
-#define HW_I2C_TIMING0 0x10
-
-#define HW_I2C_TIMING1 0x20
-
-#define HW_I2C_TIMING2 0x30
-
-#define HW_I2C_CTRL1 0x40
-#define BM_I2C_CTRL1_SLAVE_IRQ 0x00000001
-#define BP_I2C_CTRL1_SLAVE_IRQ 0
-#define BM_I2C_CTRL1_SLAVE_STOP_IRQ 0x00000002
-#define BM_I2C_CTRL1_MASTER_LOSS_IRQ 0x00000004
-#define BM_I2C_CTRL1_EARLY_TERM_IRQ 0x00000008
-#define BM_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ 0x00000010
-#define BM_I2C_CTRL1_NO_SLAVE_ACK_IRQ 0x00000020
-#define BM_I2C_CTRL1_DATA_ENGINE_CMPLT_IRQ 0x00000040
-#define BM_I2C_CTRL1_BUS_FREE_IRQ 0x00000080
-#define BM_I2C_CTRL1_CLR_GOT_A_NAK 0x10000000
-
-#define HW_I2C_VERSION 0x90
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-icoll.h b/arch/arm/mach-stmp37xx/include/mach/regs-icoll.h
deleted file mode 100644
index 3b7c92239e20..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/regs-icoll.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * stmp37xx: ICOLL register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef _MACH_REGS_ICOLL
-#define _MACH_REGS_ICOLL
-
-#define REGS_ICOLL_BASE (STMP3XXX_REGS_BASE + 0x0)
-
-#define HW_ICOLL_VECTOR 0x0
-
-#define HW_ICOLL_LEVELACK 0x10
-
-#define HW_ICOLL_CTRL 0x20
-#define BM_ICOLL_CTRL_CLKGATE 0x40000000
-#define BM_ICOLL_CTRL_SFTRST 0x80000000
-
-#define HW_ICOLL_STAT 0x30
-
-#define HW_ICOLL_PRIORITY0 (0x60 + 0 * 0x10)
-#define HW_ICOLL_PRIORITY1 (0x60 + 1 * 0x10)
-#define HW_ICOLL_PRIORITY2 (0x60 + 2 * 0x10)
-#define HW_ICOLL_PRIORITY3 (0x60 + 3 * 0x10)
-
-#define HW_ICOLL_PRIORITYn 0x60
-
-#endif
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-lcdif.h b/arch/arm/mach-stmp37xx/include/mach/regs-lcdif.h
deleted file mode 100644
index 72514e8b0737..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/regs-lcdif.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * stmp37xx: LCDIF register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_LCDIF_BASE (STMP3XXX_REGS_BASE + 0x30000)
-#define REGS_LCDIF_PHYS 0x80030000
-#define REGS_LCDIF_SIZE 0x2000
-
-#define HW_LCDIF_CTRL 0x0
-#define BM_LCDIF_CTRL_COUNT 0x0000FFFF
-#define BP_LCDIF_CTRL_COUNT 0
-#define BM_LCDIF_CTRL_RUN 0x00010000
-#define BM_LCDIF_CTRL_WORD_LENGTH 0x00020000
-#define BM_LCDIF_CTRL_DATA_SELECT 0x00040000
-#define BM_LCDIF_CTRL_DOTCLK_MODE 0x00080000
-#define BM_LCDIF_CTRL_VSYNC_MODE 0x00100000
-#define BM_LCDIF_CTRL_DATA_SWIZZLE 0x00600000
-#define BP_LCDIF_CTRL_DATA_SWIZZLE 21
-#define BM_LCDIF_CTRL_BYPASS_COUNT 0x00800000
-#define BM_LCDIF_CTRL_SHIFT_NUM_BITS 0x06000000
-#define BP_LCDIF_CTRL_SHIFT_NUM_BITS 25
-#define BM_LCDIF_CTRL_DATA_SHIFT_DIR 0x08000000
-#define BM_LCDIF_CTRL_WAIT_FOR_VSYNC_EDGE 0x10000000
-#define BM_LCDIF_CTRL_CLKGATE 0x40000000
-#define BM_LCDIF_CTRL_SFTRST 0x80000000
-
-#define HW_LCDIF_CTRL1 0x10
-#define BM_LCDIF_CTRL1_RESET 0x00000001
-#define BP_LCDIF_CTRL1_RESET 0
-#define BM_LCDIF_CTRL1_MODE86 0x00000002
-#define BM_LCDIF_CTRL1_BUSY_ENABLE 0x00000004
-#define BM_LCDIF_CTRL1_VSYNC_EDGE_IRQ 0x00000100
-#define BM_LCDIF_CTRL1_CUR_FRAME_DONE_IRQ 0x00000200
-#define BM_LCDIF_CTRL1_UNDERFLOW_IRQ 0x00000400
-#define BM_LCDIF_CTRL1_OVERFLOW_IRQ 0x00000800
-#define BM_LCDIF_CTRL1_VSYNC_EDGE_IRQ_EN 0x00001000
-#define BM_LCDIF_CTRL1_BYTE_PACKING_FORMAT 0x000F0000
-#define BP_LCDIF_CTRL1_BYTE_PACKING_FORMAT 16
-
-#define HW_LCDIF_TIMING 0x20
-
-#define HW_LCDIF_VDCTRL0 0x30
-#define BM_LCDIF_VDCTRL0_VALID_DATA_CNT 0x000003FF
-#define BP_LCDIF_VDCTRL0_VALID_DATA_CNT 0
-#define BM_LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT 0x00100000
-#define BM_LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT 0x00200000
-#define BM_LCDIF_VDCTRL0_ENABLE_POL 0x01000000
-#define BM_LCDIF_VDCTRL0_DOTCLK_POL 0x02000000
-#define BM_LCDIF_VDCTRL0_HSYNC_POL 0x04000000
-#define BM_LCDIF_VDCTRL0_VSYNC_POL 0x08000000
-#define BM_LCDIF_VDCTRL0_ENABLE_PRESENT 0x10000000
-#define BM_LCDIF_VDCTRL0_VSYNC_OEB 0x20000000
-
-#define HW_LCDIF_VDCTRL1 0x40
-#define BM_LCDIF_VDCTRL1_VSYNC_PERIOD 0x000FFFFF
-#define BP_LCDIF_VDCTRL1_VSYNC_PERIOD 0
-#define BM_LCDIF_VDCTRL1_VSYNC_PULSE_WIDTH 0xFFF00000
-#define BP_LCDIF_VDCTRL1_VSYNC_PULSE_WIDTH 20
-
-#define HW_LCDIF_VDCTRL2 0x50
-#define BM_LCDIF_VDCTRL2_VALID_DATA_CNT 0x000007FF
-#define BP_LCDIF_VDCTRL2_VALID_DATA_CNT 0
-#define BM_LCDIF_VDCTRL2_HSYNC_PERIOD 0x007FF800
-#define BP_LCDIF_VDCTRL2_HSYNC_PERIOD 11
-#define BM_LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH 0xFF800000
-#define BP_LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH 23
-
-#define HW_LCDIF_VDCTRL3 0x60
-#define BM_LCDIF_VDCTRL3_VERTICAL_WAIT_CNT 0x000001FF
-#define BP_LCDIF_VDCTRL3_VERTICAL_WAIT_CNT 0
-#define BM_LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT 0x00FFF000
-#define BP_LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT 12
-#define BM_LCDIF_VDCTRL3_SYNC_SIGNALS_ON 0x01000000
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-lradc.h b/arch/arm/mach-stmp37xx/include/mach/regs-lradc.h
deleted file mode 100644
index cc7b4702d1cd..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/regs-lradc.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * stmp37xx: LRADC register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_LRADC_BASE (STMP3XXX_REGS_BASE + 0x50000)
-
-#define HW_LRADC_CTRL0 0x0
-#define BM_LRADC_CTRL0_SCHEDULE 0x000000FF
-#define BP_LRADC_CTRL0_SCHEDULE 0
-#define BM_LRADC_CTRL0_XPLUS_ENABLE 0x00010000
-#define BM_LRADC_CTRL0_YPLUS_ENABLE 0x00020000
-#define BM_LRADC_CTRL0_XMINUS_ENABLE 0x00040000
-#define BM_LRADC_CTRL0_YMINUS_ENABLE 0x00080000
-#define BM_LRADC_CTRL0_TOUCH_DETECT_ENABLE 0x00100000
-#define BM_LRADC_CTRL0_ONCHIP_GROUNDREF 0x00200000
-#define BM_LRADC_CTRL0_CLKGATE 0x40000000
-#define BM_LRADC_CTRL0_SFTRST 0x80000000
-
-#define HW_LRADC_CTRL1 0x10
-#define BM_LRADC_CTRL1_LRADC0_IRQ 0x00000001
-#define BP_LRADC_CTRL1_LRADC0_IRQ 0
-#define BM_LRADC_CTRL1_LRADC5_IRQ 0x00000020
-#define BM_LRADC_CTRL1_LRADC6_IRQ 0x00000040
-#define BM_LRADC_CTRL1_TOUCH_DETECT_IRQ 0x00000100
-#define BM_LRADC_CTRL1_LRADC0_IRQ_EN 0x00010000
-#define BM_LRADC_CTRL1_LRADC5_IRQ_EN 0x00200000
-#define BM_LRADC_CTRL1_TOUCH_DETECT_IRQ_EN 0x01000000
-
-#define HW_LRADC_CTRL2 0x20
-#define BM_LRADC_CTRL2_BL_BRIGHTNESS 0x001F0000
-#define BP_LRADC_CTRL2_BL_BRIGHTNESS 16
-#define BM_LRADC_CTRL2_BL_MUX_SELECT 0x00200000
-#define BM_LRADC_CTRL2_BL_ENABLE 0x00400000
-#define BM_LRADC_CTRL2_DIVIDE_BY_TWO 0xFF000000
-#define BP_LRADC_CTRL2_DIVIDE_BY_TWO 24
-
-#define HW_LRADC_CTRL3 0x30
-#define BM_LRADC_CTRL3_CYCLE_TIME 0x00000300
-#define BP_LRADC_CTRL3_CYCLE_TIME 8
-
-#define HW_LRADC_STATUS 0x40
-#define BM_LRADC_STATUS_TOUCH_DETECT_RAW 0x00000001
-#define BP_LRADC_STATUS_TOUCH_DETECT_RAW 0
-
-#define HW_LRADC_CH0 (0x50 + 0 * 0x10)
-#define HW_LRADC_CH1 (0x50 + 1 * 0x10)
-#define HW_LRADC_CH2 (0x50 + 2 * 0x10)
-#define HW_LRADC_CH3 (0x50 + 3 * 0x10)
-#define HW_LRADC_CH4 (0x50 + 4 * 0x10)
-#define HW_LRADC_CH5 (0x50 + 5 * 0x10)
-#define HW_LRADC_CH6 (0x50 + 6 * 0x10)
-#define HW_LRADC_CH7 (0x50 + 7 * 0x10)
-
-#define HW_LRADC_CHn 0x50
-#define BM_LRADC_CHn_VALUE 0x0003FFFF
-#define BP_LRADC_CHn_VALUE 0
-#define BM_LRADC_CHn_NUM_SAMPLES 0x1F000000
-#define BP_LRADC_CHn_NUM_SAMPLES 24
-#define BM_LRADC_CHn_ACCUMULATE 0x20000000
-
-#define HW_LRADC_DELAY0 (0xD0 + 0 * 0x10)
-#define HW_LRADC_DELAY1 (0xD0 + 1 * 0x10)
-#define HW_LRADC_DELAY2 (0xD0 + 2 * 0x10)
-#define HW_LRADC_DELAY3 (0xD0 + 3 * 0x10)
-
-#define HW_LRADC_DELAYn 0xD0
-#define BM_LRADC_DELAYn_DELAY 0x000007FF
-#define BP_LRADC_DELAYn_DELAY 0
-#define BM_LRADC_DELAYn_LOOP_COUNT 0x0000F800
-#define BP_LRADC_DELAYn_LOOP_COUNT 11
-#define BM_LRADC_DELAYn_TRIGGER_DELAYS 0x000F0000
-#define BP_LRADC_DELAYn_TRIGGER_DELAYS 16
-#define BM_LRADC_DELAYn_KICK 0x00100000
-#define BM_LRADC_DELAYn_TRIGGER_LRADCS 0xFF000000
-#define BP_LRADC_DELAYn_TRIGGER_LRADCS 24
-
-#define HW_LRADC_CTRL4 0x140
-#define BM_LRADC_CTRL4_LRADC6SELECT 0x0F000000
-#define BP_LRADC_CTRL4_LRADC6SELECT 24
-#define BM_LRADC_CTRL4_LRADC7SELECT 0xF0000000
-#define BP_LRADC_CTRL4_LRADC7SELECT 28
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-pinctrl.h b/arch/arm/mach-stmp37xx/include/mach/regs-pinctrl.h
deleted file mode 100644
index d5efce2388c7..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/regs-pinctrl.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * stmp37xx: PINCTRL register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef _MACH_REGS_PINCTRL
-#define _MACH_REGS_PINCTRL
-
-#define REGS_PINCTRL_BASE (STMP3XXX_REGS_BASE + 0x18000)
-
-#define HW_PINCTRL_MUXSEL0 0x100
-#define HW_PINCTRL_MUXSEL1 0x110
-#define HW_PINCTRL_MUXSEL2 0x120
-#define HW_PINCTRL_MUXSEL3 0x130
-#define HW_PINCTRL_MUXSEL4 0x140
-#define HW_PINCTRL_MUXSEL5 0x150
-#define HW_PINCTRL_MUXSEL6 0x160
-#define HW_PINCTRL_MUXSEL7 0x170
-
-#define HW_PINCTRL_DRIVE0 0x200
-#define HW_PINCTRL_DRIVE1 0x210
-#define HW_PINCTRL_DRIVE2 0x220
-#define HW_PINCTRL_DRIVE3 0x230
-#define HW_PINCTRL_DRIVE4 0x240
-#define HW_PINCTRL_DRIVE5 0x250
-#define HW_PINCTRL_DRIVE6 0x260
-#define HW_PINCTRL_DRIVE7 0x270
-#define HW_PINCTRL_DRIVE8 0x280
-#define HW_PINCTRL_DRIVE9 0x290
-#define HW_PINCTRL_DRIVE10 0x2A0
-#define HW_PINCTRL_DRIVE11 0x2B0
-#define HW_PINCTRL_DRIVE12 0x2C0
-#define HW_PINCTRL_DRIVE13 0x2D0
-#define HW_PINCTRL_DRIVE14 0x2E0
-
-#define HW_PINCTRL_PULL0 0x300
-#define HW_PINCTRL_PULL1 0x310
-#define HW_PINCTRL_PULL2 0x320
-#define HW_PINCTRL_PULL3 0x330
-
-#define HW_PINCTRL_DOUT0 0x400
-#define HW_PINCTRL_DOUT1 0x410
-#define HW_PINCTRL_DOUT2 0x420
-
-#define HW_PINCTRL_DIN0 0x500
-#define HW_PINCTRL_DIN1 0x510
-#define HW_PINCTRL_DIN2 0x520
-
-#define HW_PINCTRL_DOE0 0x600
-#define HW_PINCTRL_DOE1 0x610
-#define HW_PINCTRL_DOE2 0x620
-
-#define HW_PINCTRL_PIN2IRQ0 0x700
-#define HW_PINCTRL_PIN2IRQ1 0x710
-#define HW_PINCTRL_PIN2IRQ2 0x720
-
-#define HW_PINCTRL_IRQEN0 0x800
-#define HW_PINCTRL_IRQEN1 0x810
-#define HW_PINCTRL_IRQEN2 0x820
-
-#define HW_PINCTRL_IRQLEVEL0 0x900
-#define HW_PINCTRL_IRQLEVEL1 0x910
-#define HW_PINCTRL_IRQLEVEL2 0x920
-
-#define HW_PINCTRL_IRQPOL0 0xA00
-#define HW_PINCTRL_IRQPOL1 0xA10
-#define HW_PINCTRL_IRQPOL2 0xA20
-
-#define HW_PINCTRL_IRQSTAT0 0xB00
-#define HW_PINCTRL_IRQSTAT1 0xB10
-#define HW_PINCTRL_IRQSTAT2 0xB20
-
-#endif
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-power.h b/arch/arm/mach-stmp37xx/include/mach/regs-power.h
deleted file mode 100644
index 0e733d74a229..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/regs-power.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * stmp37xx: POWER register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef _MACH_REGS_POWER
-#define _MACH_REGS_POWER
-
-#define REGS_POWER_BASE (STMP3XXX_REGS_BASE + 0x44000)
-
-#define HW_POWER_CTRL 0x0
-#define BM_POWER_CTRL_CLKGATE 0x40000000
-
-#define HW_POWER_5VCTRL 0x10
-
-#define HW_POWER_MINPWR 0x20
-
-#define HW_POWER_CHARGE 0x30
-
-#define HW_POWER_VDDDCTRL 0x40
-
-#define HW_POWER_VDDACTRL 0x50
-
-#define HW_POWER_VDDIOCTRL 0x60
-#define BM_POWER_VDDIOCTRL_TRG 0x0000001F
-#define BP_POWER_VDDIOCTRL_TRG 0
-
-#define HW_POWER_STS 0xB0
-#define BM_POWER_STS_VBUSVALID 0x00000002
-#define BM_POWER_STS_BVALID 0x00000004
-#define BM_POWER_STS_AVALID 0x00000008
-#define BM_POWER_STS_DC_OK 0x00000100
-
-#define HW_POWER_RESET 0xE0
-
-#define HW_POWER_DEBUG 0xF0
-#define BM_POWER_DEBUG_BVALIDPIOLOCK 0x00000002
-#define BM_POWER_DEBUG_AVALIDPIOLOCK 0x00000004
-#define BM_POWER_DEBUG_VBUSVALIDPIOLOCK 0x00000008
-
-#endif
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-pwm.h b/arch/arm/mach-stmp37xx/include/mach/regs-pwm.h
deleted file mode 100644
index 15966a1b62e0..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/regs-pwm.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * stmp37xx: PWM register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_PWM_BASE (STMP3XXX_REGS_BASE + 0x64000)
-
-#define HW_PWM_CTRL 0x0
-#define BM_PWM_CTRL_PWM2_ENABLE 0x00000004
-#define BM_PWM_CTRL_PWM2_ANA_CTRL_ENABLE 0x00000020
-
-#define HW_PWM_ACTIVE0 (0x10 + 0 * 0x20)
-#define HW_PWM_ACTIVE1 (0x10 + 1 * 0x20)
-#define HW_PWM_ACTIVE2 (0x10 + 2 * 0x20)
-#define HW_PWM_ACTIVE3 (0x10 + 3 * 0x20)
-
-#define HW_PWM_ACTIVEn 0x10
-#define BM_PWM_ACTIVEn_ACTIVE 0x0000FFFF
-#define BP_PWM_ACTIVEn_ACTIVE 0
-#define BM_PWM_ACTIVEn_INACTIVE 0xFFFF0000
-#define BP_PWM_ACTIVEn_INACTIVE 16
-
-#define HW_PWM_PERIOD0 (0x20 + 0 * 0x20)
-#define HW_PWM_PERIOD1 (0x20 + 1 * 0x20)
-#define HW_PWM_PERIOD2 (0x20 + 2 * 0x20)
-#define HW_PWM_PERIOD3 (0x20 + 3 * 0x20)
-
-#define HW_PWM_PERIODn 0x20
-#define BM_PWM_PERIODn_PERIOD 0x0000FFFF
-#define BP_PWM_PERIODn_PERIOD 0
-#define BM_PWM_PERIODn_ACTIVE_STATE 0x00030000
-#define BP_PWM_PERIODn_ACTIVE_STATE 16
-#define BM_PWM_PERIODn_INACTIVE_STATE 0x000C0000
-#define BP_PWM_PERIODn_INACTIVE_STATE 18
-#define BM_PWM_PERIODn_CDIV 0x00700000
-#define BP_PWM_PERIODn_CDIV 20
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-rtc.h b/arch/arm/mach-stmp37xx/include/mach/regs-rtc.h
deleted file mode 100644
index fac40edc38a1..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/regs-rtc.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * stmp37xx: RTC register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_RTC_BASE (STMP3XXX_REGS_BASE + 0x5C000)
-#define REGS_RTC_PHYS 0x8005C000
-#define REGS_RTC_SIZE 0x2000
-
-#define HW_RTC_CTRL 0x0
-#define BM_RTC_CTRL_ALARM_IRQ_EN 0x00000001
-#define BP_RTC_CTRL_ALARM_IRQ_EN 0
-#define BM_RTC_CTRL_ONEMSEC_IRQ_EN 0x00000002
-#define BM_RTC_CTRL_ALARM_IRQ 0x00000004
-#define BM_RTC_CTRL_ONEMSEC_IRQ 0x00000008
-#define BM_RTC_CTRL_WATCHDOGEN 0x00000010
-
-#define HW_RTC_STAT 0x10
-#define BM_RTC_STAT_NEW_REGS 0x0000FF00
-#define BP_RTC_STAT_NEW_REGS 8
-#define BM_RTC_STAT_STALE_REGS 0x00FF0000
-#define BP_RTC_STAT_STALE_REGS 16
-#define BM_RTC_STAT_RTC_PRESENT 0x80000000
-
-#define HW_RTC_SECONDS 0x30
-
-#define HW_RTC_ALARM 0x40
-
-#define HW_RTC_WATCHDOG 0x50
-
-#define HW_RTC_PERSISTENT0 0x60
-#define BM_RTC_PERSISTENT0_ALARM_WAKE_EN 0x00000002
-#define BM_RTC_PERSISTENT0_ALARM_EN 0x00000004
-#define BM_RTC_PERSISTENT0_XTAL24MHZ_PWRUP 0x00000010
-#define BM_RTC_PERSISTENT0_XTAL32KHZ_PWRUP 0x00000020
-#define BM_RTC_PERSISTENT0_ALARM_WAKE 0x00000080
-#define BM_RTC_PERSISTENT0_SPARE_ANALOG 0xFFFC0000
-#define BP_RTC_PERSISTENT0_SPARE_ANALOG 18
-
-#define HW_RTC_PERSISTENT1 0x70
-
-#define HW_RTC_VERSION 0xD0
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-ssp.h b/arch/arm/mach-stmp37xx/include/mach/regs-ssp.h
deleted file mode 100644
index cbde891a06c2..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/regs-ssp.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * stmp37xx: SSP register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_SSP_BASE (STMP3XXX_REGS_BASE + 0x10000)
-#define REGS_SSP1_PHYS 0x80010000
-#define REGS_SSP2_PHYS 0x80034000
-#define REGS_SSP_SIZE 0x2000
-
-#define HW_SSP_CTRL0 0x0
-#define BM_SSP_CTRL0_XFER_COUNT 0x0000FFFF
-#define BP_SSP_CTRL0_XFER_COUNT 0
-#define BM_SSP_CTRL0_ENABLE 0x00010000
-#define BM_SSP_CTRL0_GET_RESP 0x00020000
-#define BM_SSP_CTRL0_LONG_RESP 0x00080000
-#define BM_SSP_CTRL0_WAIT_FOR_CMD 0x00100000
-#define BM_SSP_CTRL0_WAIT_FOR_IRQ 0x00200000
-#define BM_SSP_CTRL0_BUS_WIDTH 0x00C00000
-#define BP_SSP_CTRL0_BUS_WIDTH 22
-#define BM_SSP_CTRL0_DATA_XFER 0x01000000
-#define BM_SSP_CTRL0_READ 0x02000000
-#define BM_SSP_CTRL0_IGNORE_CRC 0x04000000
-#define BM_SSP_CTRL0_LOCK_CS 0x08000000
-#define BM_SSP_CTRL0_RUN 0x20000000
-#define BM_SSP_CTRL0_CLKGATE 0x40000000
-#define BM_SSP_CTRL0_SFTRST 0x80000000
-
-#define HW_SSP_CMD0 0x10
-#define BM_SSP_CMD0_CMD 0x000000FF
-#define BP_SSP_CMD0_CMD 0
-#define BM_SSP_CMD0_BLOCK_COUNT 0x0000FF00
-#define BP_SSP_CMD0_BLOCK_COUNT 8
-#define BM_SSP_CMD0_BLOCK_SIZE 0x000F0000
-#define BP_SSP_CMD0_BLOCK_SIZE 16
-#define BM_SSP_CMD0_APPEND_8CYC 0x00100000
-#define BM_SSP_CMD1_CMD_ARG 0xFFFFFFFF
-#define BP_SSP_CMD1_CMD_ARG 0
-
-#define HW_SSP_TIMING 0x50
-#define BM_SSP_TIMING_CLOCK_RATE 0x000000FF
-#define BP_SSP_TIMING_CLOCK_RATE 0
-#define BM_SSP_TIMING_CLOCK_DIVIDE 0x0000FF00
-#define BP_SSP_TIMING_CLOCK_DIVIDE 8
-#define BM_SSP_TIMING_TIMEOUT 0xFFFF0000
-#define BP_SSP_TIMING_TIMEOUT 16
-
-#define HW_SSP_CTRL1 0x60
-#define BM_SSP_CTRL1_SSP_MODE 0x0000000F
-#define BP_SSP_CTRL1_SSP_MODE 0
-#define BM_SSP_CTRL1_WORD_LENGTH 0x000000F0
-#define BP_SSP_CTRL1_WORD_LENGTH 4
-#define BM_SSP_CTRL1_POLARITY 0x00000200
-#define BM_SSP_CTRL1_PHASE 0x00000400
-#define BM_SSP_CTRL1_DMA_ENABLE 0x00002000
-#define BM_SSP_CTRL1_FIFO_OVERRUN_IRQ 0x00008000
-#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ_EN 0x00010000
-#define BM_SSP_CTRL1_RECV_TIMEOUT_IRQ 0x00020000
-#define BM_SSP_CTRL1_FIFO_UNDERRUN_IRQ 0x00200000
-#define BM_SSP_CTRL1_DATA_CRC_IRQ_EN 0x00400000
-#define BM_SSP_CTRL1_DATA_CRC_IRQ 0x00800000
-#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ_EN 0x01000000
-#define BM_SSP_CTRL1_DATA_TIMEOUT_IRQ 0x02000000
-#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ_EN 0x04000000
-#define BM_SSP_CTRL1_RESP_TIMEOUT_IRQ 0x08000000
-#define BM_SSP_CTRL1_RESP_ERR_IRQ_EN 0x10000000
-#define BM_SSP_CTRL1_RESP_ERR_IRQ 0x20000000
-#define BM_SSP_CTRL1_SDIO_IRQ 0x80000000
-
-#define HW_SSP_DATA 0x70
-
-#define HW_SSP_SDRESP0 0x80
-
-#define HW_SSP_SDRESP1 0x90
-
-#define HW_SSP_SDRESP2 0xA0
-
-#define HW_SSP_SDRESP3 0xB0
-
-#define HW_SSP_STATUS 0xC0
-#define BM_SSP_STATUS_FIFO_EMPTY 0x00000020
-#define BM_SSP_STATUS_TIMEOUT 0x00001000
-#define BM_SSP_STATUS_RESP_TIMEOUT 0x00004000
-#define BM_SSP_STATUS_RESP_ERR 0x00008000
-#define BM_SSP_STATUS_RESP_CRC_ERR 0x00010000
-#define BM_SSP_STATUS_CARD_DETECT 0x10000000
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-timrot.h b/arch/arm/mach-stmp37xx/include/mach/regs-timrot.h
deleted file mode 100644
index 4af0f6edfa78..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/regs-timrot.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * stmp37xx: TIMROT register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef _MACH_REGS_TIMROT
-#define _MACH_REGS_TIMROT
-
-#define REGS_TIMROT_BASE (STMP3XXX_REGS_BASE + 0x68000)
-
-#define HW_TIMROT_ROTCTRL 0x0
-#define BM_TIMROT_ROTCTRL_CLKGATE 0x40000000
-#define BM_TIMROT_ROTCTRL_SFTRST 0x80000000
-
-#define HW_TIMROT_TIMCTRL0 (0x20 + 0 * 0x20)
-#define HW_TIMROT_TIMCTRL1 (0x20 + 1 * 0x20)
-#define HW_TIMROT_TIMCTRL2 (0x20 + 2 * 0x20)
-
-#define HW_TIMROT_TIMCTRLn 0x20
-#define BM_TIMROT_TIMCTRLn_SELECT 0x0000000F
-#define BP_TIMROT_TIMCTRLn_SELECT 0
-#define BM_TIMROT_TIMCTRLn_PRESCALE 0x00000030
-#define BP_TIMROT_TIMCTRLn_PRESCALE 4
-#define BM_TIMROT_TIMCTRLn_RELOAD 0x00000040
-#define BM_TIMROT_TIMCTRLn_UPDATE 0x00000080
-#define BM_TIMROT_TIMCTRLn_IRQ_EN 0x00004000
-#define BM_TIMROT_TIMCTRLn_IRQ 0x00008000
-
-#define HW_TIMROT_TIMCOUNT0 (0x30 + 0 * 0x20)
-#define HW_TIMROT_TIMCOUNT1 (0x30 + 1 * 0x20)
-#define HW_TIMROT_TIMCOUNT2 (0x30 + 2 * 0x20)
-
-#define HW_TIMROT_TIMCOUNTn 0x30
-#endif
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-uartapp.h b/arch/arm/mach-stmp37xx/include/mach/regs-uartapp.h
deleted file mode 100644
index 0594275d860c..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/regs-uartapp.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * stmp37xx: UARTAPP register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_UARTAPP_BASE (STMP3XXX_REGS_BASE + 0x6C000)
-#define REGS_UARTAPP1_PHYS 0x8006C000
-#define REGS_UARTAPP_SIZE 0x2000
-
-#define HW_UARTAPP_CTRL0 0x0
-#define BM_UARTAPP_CTRL0_XFER_COUNT 0x0000FFFF
-#define BP_UARTAPP_CTRL0_XFER_COUNT 0
-#define BM_UARTAPP_CTRL0_RXTIMEOUT 0x07FF0000
-#define BP_UARTAPP_CTRL0_RXTIMEOUT 16
-#define BM_UARTAPP_CTRL0_RXTO_ENABLE 0x08000000
-#define BM_UARTAPP_CTRL0_RUN 0x20000000
-#define BM_UARTAPP_CTRL0_SFTRST 0x80000000
-#define BM_UARTAPP_CTRL1_XFER_COUNT 0x0000FFFF
-#define BP_UARTAPP_CTRL1_XFER_COUNT 0
-#define BM_UARTAPP_CTRL1_RUN 0x10000000
-
-#define HW_UARTAPP_CTRL2 0x20
-#define BM_UARTAPP_CTRL2_UARTEN 0x00000001
-#define BP_UARTAPP_CTRL2_UARTEN 0
-#define BM_UARTAPP_CTRL2_TXE 0x00000100
-#define BM_UARTAPP_CTRL2_RXE 0x00000200
-#define BM_UARTAPP_CTRL2_RTS 0x00000800
-#define BM_UARTAPP_CTRL2_RTSEN 0x00004000
-#define BM_UARTAPP_CTRL2_CTSEN 0x00008000
-#define BM_UARTAPP_CTRL2_RXDMAE 0x01000000
-#define BM_UARTAPP_CTRL2_TXDMAE 0x02000000
-#define BM_UARTAPP_CTRL2_DMAONERR 0x04000000
-
-#define HW_UARTAPP_LINECTRL 0x30
-#define BM_UARTAPP_LINECTRL_BRK 0x00000001
-#define BP_UARTAPP_LINECTRL_BRK 0
-#define BM_UARTAPP_LINECTRL_PEN 0x00000002
-#define BM_UARTAPP_LINECTRL_EPS 0x00000004
-#define BM_UARTAPP_LINECTRL_STP2 0x00000008
-#define BM_UARTAPP_LINECTRL_FEN 0x00000010
-#define BM_UARTAPP_LINECTRL_WLEN 0x00000060
-#define BP_UARTAPP_LINECTRL_WLEN 5
-#define BM_UARTAPP_LINECTRL_SPS 0x00000080
-#define BM_UARTAPP_LINECTRL_BAUD_DIVFRAC 0x00003F00
-#define BP_UARTAPP_LINECTRL_BAUD_DIVFRAC 8
-#define BM_UARTAPP_LINECTRL_BAUD_DIVINT 0xFFFF0000
-#define BP_UARTAPP_LINECTRL_BAUD_DIVINT 16
-
-#define HW_UARTAPP_INTR 0x50
-#define BM_UARTAPP_INTR_CTSMIS 0x00000002
-#define BM_UARTAPP_INTR_RTIS 0x00000040
-#define BM_UARTAPP_INTR_CTSMIEN 0x00020000
-#define BM_UARTAPP_INTR_RXIEN 0x00100000
-#define BM_UARTAPP_INTR_RTIEN 0x00400000
-
-#define HW_UARTAPP_DATA 0x60
-
-#define HW_UARTAPP_STAT 0x70
-#define BM_UARTAPP_STAT_RXCOUNT 0x0000FFFF
-#define BP_UARTAPP_STAT_RXCOUNT 0
-#define BM_UARTAPP_STAT_FERR 0x00010000
-#define BM_UARTAPP_STAT_PERR 0x00020000
-#define BM_UARTAPP_STAT_BERR 0x00040000
-#define BM_UARTAPP_STAT_OERR 0x00080000
-#define BM_UARTAPP_STAT_RXFE 0x01000000
-#define BM_UARTAPP_STAT_TXFF 0x02000000
-#define BM_UARTAPP_STAT_TXFE 0x08000000
-#define BM_UARTAPP_STAT_CTS 0x10000000
-
-#define HW_UARTAPP_VERSION 0x90
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-uartdbg.h b/arch/arm/mach-stmp37xx/include/mach/regs-uartdbg.h
deleted file mode 100644
index b810deb552a9..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/regs-uartdbg.h
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * stmp378x: UARTDBG register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_UARTDBG_BASE (STMP3XXX_REGS_BASE + 0x70000)
-#define REGS_UARTDBG_PHYS 0x80070000
-#define REGS_UARTDBG_SIZE 0x2000
-
-#define HW_UARTDBGDR 0x00000000
-#define BP_UARTDBGDR_UNAVAILABLE 16
-#define BM_UARTDBGDR_UNAVAILABLE 0xFFFF0000
-#define BF_UARTDBGDR_UNAVAILABLE(v) \
- (((v) << 16) & BM_UARTDBGDR_UNAVAILABLE)
-#define BP_UARTDBGDR_RESERVED 12
-#define BM_UARTDBGDR_RESERVED 0x0000F000
-#define BF_UARTDBGDR_RESERVED(v) \
- (((v) << 12) & BM_UARTDBGDR_RESERVED)
-#define BM_UARTDBGDR_OE 0x00000800
-#define BM_UARTDBGDR_BE 0x00000400
-#define BM_UARTDBGDR_PE 0x00000200
-#define BM_UARTDBGDR_FE 0x00000100
-#define BP_UARTDBGDR_DATA 0
-#define BM_UARTDBGDR_DATA 0x000000FF
-#define BF_UARTDBGDR_DATA(v) \
- (((v) << 0) & BM_UARTDBGDR_DATA)
-#define HW_UARTDBGRSR_ECR 0x00000004
-#define BP_UARTDBGRSR_ECR_UNAVAILABLE 8
-#define BM_UARTDBGRSR_ECR_UNAVAILABLE 0xFFFFFF00
-#define BF_UARTDBGRSR_ECR_UNAVAILABLE(v) \
- (((v) << 8) & BM_UARTDBGRSR_ECR_UNAVAILABLE)
-#define BP_UARTDBGRSR_ECR_EC 4
-#define BM_UARTDBGRSR_ECR_EC 0x000000F0
-#define BF_UARTDBGRSR_ECR_EC(v) \
- (((v) << 4) & BM_UARTDBGRSR_ECR_EC)
-#define BM_UARTDBGRSR_ECR_OE 0x00000008
-#define BM_UARTDBGRSR_ECR_BE 0x00000004
-#define BM_UARTDBGRSR_ECR_PE 0x00000002
-#define BM_UARTDBGRSR_ECR_FE 0x00000001
-#define HW_UARTDBGFR 0x00000018
-#define BP_UARTDBGFR_UNAVAILABLE 16
-#define BM_UARTDBGFR_UNAVAILABLE 0xFFFF0000
-#define BF_UARTDBGFR_UNAVAILABLE(v) \
- (((v) << 16) & BM_UARTDBGFR_UNAVAILABLE)
-#define BP_UARTDBGFR_RESERVED 9
-#define BM_UARTDBGFR_RESERVED 0x0000FE00
-#define BF_UARTDBGFR_RESERVED(v) \
- (((v) << 9) & BM_UARTDBGFR_RESERVED)
-#define BM_UARTDBGFR_RI 0x00000100
-#define BM_UARTDBGFR_TXFE 0x00000080
-#define BM_UARTDBGFR_RXFF 0x00000040
-#define BM_UARTDBGFR_TXFF 0x00000020
-#define BM_UARTDBGFR_RXFE 0x00000010
-#define BM_UARTDBGFR_BUSY 0x00000008
-#define BM_UARTDBGFR_DCD 0x00000004
-#define BM_UARTDBGFR_DSR 0x00000002
-#define BM_UARTDBGFR_CTS 0x00000001
-#define HW_UARTDBGILPR 0x00000020
-#define BP_UARTDBGILPR_UNAVAILABLE 8
-#define BM_UARTDBGILPR_UNAVAILABLE 0xFFFFFF00
-#define BF_UARTDBGILPR_UNAVAILABLE(v) \
- (((v) << 8) & BM_UARTDBGILPR_UNAVAILABLE)
-#define BP_UARTDBGILPR_ILPDVSR 0
-#define BM_UARTDBGILPR_ILPDVSR 0x000000FF
-#define BF_UARTDBGILPR_ILPDVSR(v) \
- (((v) << 0) & BM_UARTDBGILPR_ILPDVSR)
-#define HW_UARTDBGIBRD 0x00000024
-#define BP_UARTDBGIBRD_UNAVAILABLE 16
-#define BM_UARTDBGIBRD_UNAVAILABLE 0xFFFF0000
-#define BF_UARTDBGIBRD_UNAVAILABLE(v) \
- (((v) << 16) & BM_UARTDBGIBRD_UNAVAILABLE)
-#define BP_UARTDBGIBRD_BAUD_DIVINT 0
-#define BM_UARTDBGIBRD_BAUD_DIVINT 0x0000FFFF
-#define BF_UARTDBGIBRD_BAUD_DIVINT(v) \
- (((v) << 0) & BM_UARTDBGIBRD_BAUD_DIVINT)
-#define HW_UARTDBGFBRD 0x00000028
-#define BP_UARTDBGFBRD_UNAVAILABLE 8
-#define BM_UARTDBGFBRD_UNAVAILABLE 0xFFFFFF00
-#define BF_UARTDBGFBRD_UNAVAILABLE(v) \
- (((v) << 8) & BM_UARTDBGFBRD_UNAVAILABLE)
-#define BP_UARTDBGFBRD_RESERVED 6
-#define BM_UARTDBGFBRD_RESERVED 0x000000C0
-#define BF_UARTDBGFBRD_RESERVED(v) \
- (((v) << 6) & BM_UARTDBGFBRD_RESERVED)
-#define BP_UARTDBGFBRD_BAUD_DIVFRAC 0
-#define BM_UARTDBGFBRD_BAUD_DIVFRAC 0x0000003F
-#define BF_UARTDBGFBRD_BAUD_DIVFRAC(v) \
- (((v) << 0) & BM_UARTDBGFBRD_BAUD_DIVFRAC)
-#define HW_UARTDBGLCR_H 0x0000002c
-#define BP_UARTDBGLCR_H_UNAVAILABLE 16
-#define BM_UARTDBGLCR_H_UNAVAILABLE 0xFFFF0000
-#define BF_UARTDBGLCR_H_UNAVAILABLE(v) \
- (((v) << 16) & BM_UARTDBGLCR_H_UNAVAILABLE)
-#define BP_UARTDBGLCR_H_RESERVED 8
-#define BM_UARTDBGLCR_H_RESERVED 0x0000FF00
-#define BF_UARTDBGLCR_H_RESERVED(v) \
- (((v) << 8) & BM_UARTDBGLCR_H_RESERVED)
-#define BM_UARTDBGLCR_H_SPS 0x00000080
-#define BP_UARTDBGLCR_H_WLEN 5
-#define BM_UARTDBGLCR_H_WLEN 0x00000060
-#define BF_UARTDBGLCR_H_WLEN(v) \
- (((v) << 5) & BM_UARTDBGLCR_H_WLEN)
-#define BM_UARTDBGLCR_H_FEN 0x00000010
-#define BM_UARTDBGLCR_H_STP2 0x00000008
-#define BM_UARTDBGLCR_H_EPS 0x00000004
-#define BM_UARTDBGLCR_H_PEN 0x00000002
-#define BM_UARTDBGLCR_H_BRK 0x00000001
-#define HW_UARTDBGCR 0x00000030
-#define BP_UARTDBGCR_UNAVAILABLE 16
-#define BM_UARTDBGCR_UNAVAILABLE 0xFFFF0000
-#define BF_UARTDBGCR_UNAVAILABLE(v) \
- (((v) << 16) & BM_UARTDBGCR_UNAVAILABLE)
-#define BM_UARTDBGCR_CTSEN 0x00008000
-#define BM_UARTDBGCR_RTSEN 0x00004000
-#define BM_UARTDBGCR_OUT2 0x00002000
-#define BM_UARTDBGCR_OUT1 0x00001000
-#define BM_UARTDBGCR_RTS 0x00000800
-#define BM_UARTDBGCR_DTR 0x00000400
-#define BM_UARTDBGCR_RXE 0x00000200
-#define BM_UARTDBGCR_TXE 0x00000100
-#define BM_UARTDBGCR_LBE 0x00000080
-#define BP_UARTDBGCR_RESERVED 3
-#define BM_UARTDBGCR_RESERVED 0x00000078
-#define BF_UARTDBGCR_RESERVED(v) \
- (((v) << 3) & BM_UARTDBGCR_RESERVED)
-#define BM_UARTDBGCR_SIRLP 0x00000004
-#define BM_UARTDBGCR_SIREN 0x00000002
-#define BM_UARTDBGCR_UARTEN 0x00000001
-#define HW_UARTDBGIFLS 0x00000034
-#define BP_UARTDBGIFLS_UNAVAILABLE 16
-#define BM_UARTDBGIFLS_UNAVAILABLE 0xFFFF0000
-#define BF_UARTDBGIFLS_UNAVAILABLE(v) \
- (((v) << 16) & BM_UARTDBGIFLS_UNAVAILABLE)
-#define BP_UARTDBGIFLS_RESERVED 6
-#define BM_UARTDBGIFLS_RESERVED 0x0000FFC0
-#define BF_UARTDBGIFLS_RESERVED(v) \
- (((v) << 6) & BM_UARTDBGIFLS_RESERVED)
-#define BP_UARTDBGIFLS_RXIFLSEL 3
-#define BM_UARTDBGIFLS_RXIFLSEL 0x00000038
-#define BF_UARTDBGIFLS_RXIFLSEL(v) \
- (((v) << 3) & BM_UARTDBGIFLS_RXIFLSEL)
-#define BV_UARTDBGIFLS_RXIFLSEL__NOT_EMPTY 0x0
-#define BV_UARTDBGIFLS_RXIFLSEL__ONE_QUARTER 0x1
-#define BV_UARTDBGIFLS_RXIFLSEL__ONE_HALF 0x2
-#define BV_UARTDBGIFLS_RXIFLSEL__THREE_QUARTERS 0x3
-#define BV_UARTDBGIFLS_RXIFLSEL__SEVEN_EIGHTHS 0x4
-#define BV_UARTDBGIFLS_RXIFLSEL__INVALID5 0x5
-#define BV_UARTDBGIFLS_RXIFLSEL__INVALID6 0x6
-#define BV_UARTDBGIFLS_RXIFLSEL__INVALID7 0x7
-#define BP_UARTDBGIFLS_TXIFLSEL 0
-#define BM_UARTDBGIFLS_TXIFLSEL 0x00000007
-#define BF_UARTDBGIFLS_TXIFLSEL(v) \
- (((v) << 0) & BM_UARTDBGIFLS_TXIFLSEL)
-#define BV_UARTDBGIFLS_TXIFLSEL__EMPTY 0x0
-#define BV_UARTDBGIFLS_TXIFLSEL__ONE_QUARTER 0x1
-#define BV_UARTDBGIFLS_TXIFLSEL__ONE_HALF 0x2
-#define BV_UARTDBGIFLS_TXIFLSEL__THREE_QUARTERS 0x3
-#define BV_UARTDBGIFLS_TXIFLSEL__SEVEN_EIGHTHS 0x4
-#define BV_UARTDBGIFLS_TXIFLSEL__INVALID5 0x5
-#define BV_UARTDBGIFLS_TXIFLSEL__INVALID6 0x6
-#define BV_UARTDBGIFLS_TXIFLSEL__INVALID7 0x7
-#define HW_UARTDBGIMSC 0x00000038
-#define BP_UARTDBGIMSC_UNAVAILABLE 16
-#define BM_UARTDBGIMSC_UNAVAILABLE 0xFFFF0000
-#define BF_UARTDBGIMSC_UNAVAILABLE(v) \
- (((v) << 16) & BM_UARTDBGIMSC_UNAVAILABLE)
-#define BP_UARTDBGIMSC_RESERVED 11
-#define BM_UARTDBGIMSC_RESERVED 0x0000F800
-#define BF_UARTDBGIMSC_RESERVED(v) \
- (((v) << 11) & BM_UARTDBGIMSC_RESERVED)
-#define BM_UARTDBGIMSC_OEIM 0x00000400
-#define BM_UARTDBGIMSC_BEIM 0x00000200
-#define BM_UARTDBGIMSC_PEIM 0x00000100
-#define BM_UARTDBGIMSC_FEIM 0x00000080
-#define BM_UARTDBGIMSC_RTIM 0x00000040
-#define BM_UARTDBGIMSC_TXIM 0x00000020
-#define BM_UARTDBGIMSC_RXIM 0x00000010
-#define BM_UARTDBGIMSC_DSRMIM 0x00000008
-#define BM_UARTDBGIMSC_DCDMIM 0x00000004
-#define BM_UARTDBGIMSC_CTSMIM 0x00000002
-#define BM_UARTDBGIMSC_RIMIM 0x00000001
-#define HW_UARTDBGRIS 0x0000003c
-#define BP_UARTDBGRIS_UNAVAILABLE 16
-#define BM_UARTDBGRIS_UNAVAILABLE 0xFFFF0000
-#define BF_UARTDBGRIS_UNAVAILABLE(v) \
- (((v) << 16) & BM_UARTDBGRIS_UNAVAILABLE)
-#define BP_UARTDBGRIS_RESERVED 11
-#define BM_UARTDBGRIS_RESERVED 0x0000F800
-#define BF_UARTDBGRIS_RESERVED(v) \
- (((v) << 11) & BM_UARTDBGRIS_RESERVED)
-#define BM_UARTDBGRIS_OERIS 0x00000400
-#define BM_UARTDBGRIS_BERIS 0x00000200
-#define BM_UARTDBGRIS_PERIS 0x00000100
-#define BM_UARTDBGRIS_FERIS 0x00000080
-#define BM_UARTDBGRIS_RTRIS 0x00000040
-#define BM_UARTDBGRIS_TXRIS 0x00000020
-#define BM_UARTDBGRIS_RXRIS 0x00000010
-#define BM_UARTDBGRIS_DSRRMIS 0x00000008
-#define BM_UARTDBGRIS_DCDRMIS 0x00000004
-#define BM_UARTDBGRIS_CTSRMIS 0x00000002
-#define BM_UARTDBGRIS_RIRMIS 0x00000001
-#define HW_UARTDBGMIS 0x00000040
-#define BP_UARTDBGMIS_UNAVAILABLE 16
-#define BM_UARTDBGMIS_UNAVAILABLE 0xFFFF0000
-#define BF_UARTDBGMIS_UNAVAILABLE(v) \
- (((v) << 16) & BM_UARTDBGMIS_UNAVAILABLE)
-#define BP_UARTDBGMIS_RESERVED 11
-#define BM_UARTDBGMIS_RESERVED 0x0000F800
-#define BF_UARTDBGMIS_RESERVED(v) \
- (((v) << 11) & BM_UARTDBGMIS_RESERVED)
-#define BM_UARTDBGMIS_OEMIS 0x00000400
-#define BM_UARTDBGMIS_BEMIS 0x00000200
-#define BM_UARTDBGMIS_PEMIS 0x00000100
-#define BM_UARTDBGMIS_FEMIS 0x00000080
-#define BM_UARTDBGMIS_RTMIS 0x00000040
-#define BM_UARTDBGMIS_TXMIS 0x00000020
-#define BM_UARTDBGMIS_RXMIS 0x00000010
-#define BM_UARTDBGMIS_DSRMMIS 0x00000008
-#define BM_UARTDBGMIS_DCDMMIS 0x00000004
-#define BM_UARTDBGMIS_CTSMMIS 0x00000002
-#define BM_UARTDBGMIS_RIMMIS 0x00000001
-#define HW_UARTDBGICR 0x00000044
-#define BP_UARTDBGICR_UNAVAILABLE 16
-#define BM_UARTDBGICR_UNAVAILABLE 0xFFFF0000
-#define BF_UARTDBGICR_UNAVAILABLE(v) \
- (((v) << 16) & BM_UARTDBGICR_UNAVAILABLE)
-#define BP_UARTDBGICR_RESERVED 11
-#define BM_UARTDBGICR_RESERVED 0x0000F800
-#define BF_UARTDBGICR_RESERVED(v) \
- (((v) << 11) & BM_UARTDBGICR_RESERVED)
-#define BM_UARTDBGICR_OEIC 0x00000400
-#define BM_UARTDBGICR_BEIC 0x00000200
-#define BM_UARTDBGICR_PEIC 0x00000100
-#define BM_UARTDBGICR_FEIC 0x00000080
-#define BM_UARTDBGICR_RTIC 0x00000040
-#define BM_UARTDBGICR_TXIC 0x00000020
-#define BM_UARTDBGICR_RXIC 0x00000010
-#define BM_UARTDBGICR_DSRMIC 0x00000008
-#define BM_UARTDBGICR_DCDMIC 0x00000004
-#define BM_UARTDBGICR_CTSMIC 0x00000002
-#define BM_UARTDBGICR_RIMIC 0x00000001
-#define HW_UARTDBGDMACR 0x00000048
-#define BP_UARTDBGDMACR_UNAVAILABLE 16
-#define BM_UARTDBGDMACR_UNAVAILABLE 0xFFFF0000
-#define BF_UARTDBGDMACR_UNAVAILABLE(v) \
- (((v) << 16) & BM_UARTDBGDMACR_UNAVAILABLE)
-#define BP_UARTDBGDMACR_RESERVED 3
-#define BM_UARTDBGDMACR_RESERVED 0x0000FFF8
-#define BF_UARTDBGDMACR_RESERVED(v) \
- (((v) << 3) & BM_UARTDBGDMACR_RESERVED)
-#define BM_UARTDBGDMACR_DMAONERR 0x00000004
-#define BM_UARTDBGDMACR_TXDMAE 0x00000002
-#define BM_UARTDBGDMACR_RXDMAE 0x00000001
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-usbctl.h b/arch/arm/mach-stmp37xx/include/mach/regs-usbctl.h
deleted file mode 100644
index 9145e22df32c..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/regs-usbctl.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * stmp37xx: USBCTL register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_USBCTL_BASE (STMP3XXX_REGS_BASE + 0x80000)
-#define REGS_USBCTL_PHYS 0x80000
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-usbctrl.h b/arch/arm/mach-stmp37xx/include/mach/regs-usbctrl.h
deleted file mode 100644
index 1a2ae9cbdfed..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/regs-usbctrl.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * stmp37xx: USBCTRL register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_USBCTRL_BASE (STMP3XXX_REGS_BASE + 0x80000)
-#define REGS_USBCTRL_PHYS 0x80080000
diff --git a/arch/arm/mach-stmp37xx/include/mach/regs-usbphy.h b/arch/arm/mach-stmp37xx/include/mach/regs-usbphy.h
deleted file mode 100644
index b7fce0fbc560..000000000000
--- a/arch/arm/mach-stmp37xx/include/mach/regs-usbphy.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * stmp37xx: USBPHY register definitions
- *
- * Copyright (c) 2008 Freescale Semiconductor
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define REGS_USBPHY_BASE (STMP3XXX_REGS_BASE + 0x7C000)
-
-#define HW_USBPHY_PWD 0x0
-
-#define HW_USBPHY_CTRL 0x30
-#define BM_USBPHY_CTRL_ENHSPRECHARGEXMIT 0x00000001
-#define BP_USBPHY_CTRL_ENHSPRECHARGEXMIT 0
-#define BM_USBPHY_CTRL_ENHOSTDISCONDETECT 0x00000002
-#define BM_USBPHY_CTRL_ENDEVPLUGINDETECT 0x00000010
-#define BM_USBPHY_CTRL_ENOTGIDDETECT 0x00000080
-#define BM_USBPHY_CTRL_ENIRQDEVPLUGIN 0x00000800
-#define BM_USBPHY_CTRL_CLKGATE 0x40000000
-#define BM_USBPHY_CTRL_SFTRST 0x80000000
-
-#define HW_USBPHY_STATUS 0x40
-#define BM_USBPHY_STATUS_DEVPLUGIN_STATUS 0x00000040
-#define BM_USBPHY_STATUS_OTGID_STATUS 0x00000100
diff --git a/arch/arm/mach-stmp37xx/stmp37xx.c b/arch/arm/mach-stmp37xx/stmp37xx.c
deleted file mode 100644
index a9aed06ff376..000000000000
--- a/arch/arm/mach-stmp37xx/stmp37xx.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Freescale STMP37XX platform support
- *
- * Embedded Alley Solutions, Inc <source@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/map.h>
-#include <asm/mach/time.h>
-
-#include <mach/stmp3xxx.h>
-#include <mach/dma.h>
-
-#include <mach/platform.h>
-#include <mach/regs-icoll.h>
-#include <mach/regs-apbh.h>
-#include <mach/regs-apbx.h>
-#include "stmp37xx.h"
-
-/*
- * IRQ handling
- */
-static void stmp37xx_ack_irq(struct irq_data *d)
-{
- /* Disable IRQ */
- stmp3xxx_clearl(0x04 << ((d->irq % 4) * 8),
- REGS_ICOLL_BASE + HW_ICOLL_PRIORITYn + d->irq / 4 * 0x10);
-
- /* ACK current interrupt */
- __raw_writel(1, REGS_ICOLL_BASE + HW_ICOLL_LEVELACK);
-
- /* Barrier */
- (void)__raw_readl(REGS_ICOLL_BASE + HW_ICOLL_STAT);
-}
-
-static void stmp37xx_mask_irq(struct irq_data *d)
-{
- /* IRQ disable */
- stmp3xxx_clearl(0x04 << ((d->irq % 4) * 8),
- REGS_ICOLL_BASE + HW_ICOLL_PRIORITYn + d->irq / 4 * 0x10);
-}
-
-static void stmp37xx_unmask_irq(struct irq_data *d)
-{
- /* IRQ enable */
- stmp3xxx_setl(0x04 << ((d->irq % 4) * 8),
- REGS_ICOLL_BASE + HW_ICOLL_PRIORITYn + d->irq / 4 * 0x10);
-}
-
-static struct irq_chip stmp37xx_chip = {
- .irq_ack = stmp37xx_ack_irq,
- .irq_mask = stmp37xx_mask_irq,
- .irq_unmask = stmp37xx_unmask_irq,
-};
-
-void __init stmp37xx_init_irq(void)
-{
- stmp3xxx_init_irq(&stmp37xx_chip);
-}
-
-/*
- * DMA interrupt handling
- */
-void stmp3xxx_arch_dma_enable_interrupt(int channel)
-{
- switch (STMP3XXX_DMA_BUS(channel)) {
- case STMP3XXX_BUS_APBH:
- stmp3xxx_setl(1 << (8 + STMP3XXX_DMA_CHANNEL(channel)),
- REGS_APBH_BASE + HW_APBH_CTRL1);
- break;
-
- case STMP3XXX_BUS_APBX:
- stmp3xxx_setl(1 << (8 + STMP3XXX_DMA_CHANNEL(channel)),
- REGS_APBX_BASE + HW_APBX_CTRL1);
- break;
- }
-}
-EXPORT_SYMBOL(stmp3xxx_arch_dma_enable_interrupt);
-
-void stmp3xxx_arch_dma_clear_interrupt(int channel)
-{
- switch (STMP3XXX_DMA_BUS(channel)) {
- case STMP3XXX_BUS_APBH:
- stmp3xxx_clearl(1 << STMP3XXX_DMA_CHANNEL(channel),
- REGS_APBH_BASE + HW_APBH_CTRL1);
- break;
-
- case STMP3XXX_BUS_APBX:
- stmp3xxx_clearl(1 << STMP3XXX_DMA_CHANNEL(channel),
- REGS_APBX_BASE + HW_APBX_CTRL1);
- break;
- }
-}
-EXPORT_SYMBOL(stmp3xxx_arch_dma_clear_interrupt);
-
-int stmp3xxx_arch_dma_is_interrupt(int channel)
-{
- int r = 0;
-
- switch (STMP3XXX_DMA_BUS(channel)) {
- case STMP3XXX_BUS_APBH:
- r = __raw_readl(REGS_APBH_BASE + HW_APBH_CTRL1) &
- (1 << STMP3XXX_DMA_CHANNEL(channel));
- break;
-
- case STMP3XXX_BUS_APBX:
- r = __raw_readl(REGS_APBH_BASE + HW_APBH_CTRL1) &
- (1 << STMP3XXX_DMA_CHANNEL(channel));
- break;
- }
- return r;
-}
-EXPORT_SYMBOL(stmp3xxx_arch_dma_is_interrupt);
-
-void stmp3xxx_arch_dma_reset_channel(int channel)
-{
- unsigned chbit = 1 << STMP3XXX_DMA_CHANNEL(channel);
-
- switch (STMP3XXX_DMA_BUS(channel)) {
- case STMP3XXX_BUS_APBH:
- /* Reset channel and wait for it to complete */
- stmp3xxx_setl(chbit << BP_APBH_CTRL0_RESET_CHANNEL,
- REGS_APBH_BASE + HW_APBH_CTRL0);
- while (__raw_readl(REGS_APBH_BASE + HW_APBH_CTRL0) &
- (chbit << BP_APBH_CTRL0_RESET_CHANNEL))
- cpu_relax();
- break;
-
- case STMP3XXX_BUS_APBX:
- stmp3xxx_setl(chbit << BP_APBX_CTRL0_RESET_CHANNEL,
- REGS_APBX_BASE + HW_APBX_CTRL0);
- while (__raw_readl(REGS_APBX_BASE + HW_APBX_CTRL0) &
- (chbit << BP_APBX_CTRL0_RESET_CHANNEL))
- cpu_relax();
- break;
- }
-}
-EXPORT_SYMBOL(stmp3xxx_arch_dma_reset_channel);
-
-void stmp3xxx_arch_dma_freeze(int channel)
-{
- unsigned chbit = 1 << STMP3XXX_DMA_CHANNEL(channel);
-
- switch (STMP3XXX_DMA_BUS(channel)) {
- case STMP3XXX_BUS_APBH:
- stmp3xxx_setl(1 << chbit, REGS_APBH_BASE + HW_APBH_CTRL0);
- break;
- case STMP3XXX_BUS_APBX:
- stmp3xxx_setl(1 << chbit, REGS_APBH_BASE + HW_APBH_CTRL0);
- break;
- }
-}
-EXPORT_SYMBOL(stmp3xxx_arch_dma_freeze);
-
-void stmp3xxx_arch_dma_unfreeze(int channel)
-{
- unsigned chbit = 1 << STMP3XXX_DMA_CHANNEL(channel);
-
- switch (STMP3XXX_DMA_BUS(channel)) {
- case STMP3XXX_BUS_APBH:
- stmp3xxx_clearl(1 << chbit, REGS_APBH_BASE + HW_APBH_CTRL0);
- break;
- case STMP3XXX_BUS_APBX:
- stmp3xxx_clearl(1 << chbit, REGS_APBH_BASE + HW_APBH_CTRL0);
- break;
- }
-}
-EXPORT_SYMBOL(stmp3xxx_arch_dma_unfreeze);
-
-/*
- * The registers are all very closely mapped, so we might as well map them all
- * with a single mapping
- *
- * Logical Physical
- * f0000000 80000000 On-chip registers
- * f1000000 00000000 32k on-chip SRAM
- */
-static struct map_desc stmp37xx_io_desc[] __initdata = {
- {
- .virtual = (u32)STMP3XXX_REGS_BASE,
- .pfn = __phys_to_pfn(STMP3XXX_REGS_PHBASE),
- .length = SZ_1M,
- .type = MT_DEVICE
- },
- {
- .virtual = (u32)STMP3XXX_OCRAM_BASE,
- .pfn = __phys_to_pfn(STMP3XXX_OCRAM_PHBASE),
- .length = STMP3XXX_OCRAM_SIZE,
- .type = MT_DEVICE,
- },
-};
-
-void __init stmp37xx_map_io(void)
-{
- iotable_init(stmp37xx_io_desc, ARRAY_SIZE(stmp37xx_io_desc));
-}
diff --git a/arch/arm/mach-stmp37xx/stmp37xx.h b/arch/arm/mach-stmp37xx/stmp37xx.h
deleted file mode 100644
index 0b75fb796a64..000000000000
--- a/arch/arm/mach-stmp37xx/stmp37xx.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Freescale STMP37XX/STMP378X internal functions and data declarations
- *
- * Embedded Alley Solutions, Inc <source@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#ifndef __MACH_STMP37XX_H
-#define __MACH_STMP37XX_H
-
-void stmp37xx_map_io(void);
-void stmp37xx_init_irq(void);
-
-#endif /* __MACH_STMP37XX_H */
diff --git a/arch/arm/mach-stmp37xx/stmp37xx_devb.c b/arch/arm/mach-stmp37xx/stmp37xx_devb.c
deleted file mode 100644
index 311d8552d362..000000000000
--- a/arch/arm/mach-stmp37xx/stmp37xx_devb.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Freescale STMP37XX development board support
- *
- * Embedded Alley Solutions, Inc <source@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-#include <mach/stmp3xxx.h>
-#include <mach/pins.h>
-#include <mach/pinmux.h>
-#include "stmp37xx.h"
-
-/*
- * List of STMP37xx development board specific devices
- */
-static struct platform_device *stmp37xx_devb_devices[] = {
- &stmp3xxx_dbguart,
- &stmp3xxx_appuart,
-};
-
-static struct pin_desc dbguart_pins_0[] = {
- { PINID_PWM0, PIN_FUN3, },
- { PINID_PWM1, PIN_FUN3, },
-};
-
-struct pin_desc appuart_pins_0[] = {
- { PINID_UART2_CTS, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
- { PINID_UART2_RTS, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
- { PINID_UART2_RX, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
- { PINID_UART2_TX, PIN_FUN1, PIN_4MA, PIN_1_8V, 0, },
-};
-
-static struct pin_group appuart_pins[] = {
- [0] = {
- .pins = appuart_pins_0,
- .nr_pins = ARRAY_SIZE(appuart_pins_0),
- },
- /* 37xx has the only app uart */
-};
-
-static struct pin_group dbguart_pins[] = {
- [0] = {
- .pins = dbguart_pins_0,
- .nr_pins = ARRAY_SIZE(dbguart_pins_0),
- },
-};
-
-static int dbguart_pins_control(int id, int request)
-{
- int r = 0;
-
- if (request)
- r = stmp3xxx_request_pin_group(&dbguart_pins[id], "debug uart");
- else
- stmp3xxx_release_pin_group(&dbguart_pins[id], "debug uart");
- return r;
-}
-
-
-static void __init stmp37xx_devb_init(void)
-{
- stmp3xxx_pinmux_init(NR_REAL_IRQS);
-
- /* Init STMP3xxx platform */
- stmp3xxx_init();
-
- stmp3xxx_dbguart.dev.platform_data = dbguart_pins_control;
- stmp3xxx_appuart.dev.platform_data = appuart_pins;
-
- /* Add STMP37xx development board devices */
- platform_add_devices(stmp37xx_devb_devices,
- ARRAY_SIZE(stmp37xx_devb_devices));
-}
-
-MACHINE_START(STMP37XX, "STMP37XX")
- .boot_params = 0x40000100,
- .map_io = stmp37xx_map_io,
- .init_irq = stmp37xx_init_irq,
- .timer = &stmp3xxx_timer,
- .init_machine = stmp37xx_devb_init,
-MACHINE_END
diff --git a/arch/arm/mach-tcc8k/time.c b/arch/arm/mach-tcc8k/time.c
index e0a8d609afe1..a96babe83771 100644
--- a/arch/arm/mach-tcc8k/time.c
+++ b/arch/arm/mach-tcc8k/time.c
@@ -25,19 +25,6 @@
static void __iomem *timer_base;
-static cycle_t tcc_get_cycles(struct clocksource *cs)
-{
- return __raw_readl(timer_base + TC32MCNT_OFFS);
-}
-
-static struct clocksource clocksource_tcc = {
- .name = "tcc_tc32",
- .rating = 200,
- .read = tcc_get_cycles,
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
static int tcc_set_next_event(unsigned long evt,
struct clock_event_device *unused)
{
@@ -102,7 +89,8 @@ static int __init tcc_clockevent_init(struct clk *clock)
{
unsigned int c = clk_get_rate(clock);
- clocksource_register_hz(&clocksource_tcc, c);
+ clocksource_mmio_init(timer_base + TC32MCNT_OFFS, "tcc_tc32", c,
+ 200, 32, clocksource_mmio_readl_up);
clockevent_tcc.mult = div_sc(c, NSEC_PER_SEC,
clockevent_tcc.shift);
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 3cdeffc97b44..5ec1846aa1d0 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -27,12 +27,14 @@ comment "Tegra board type"
config MACH_HARMONY
bool "Harmony board"
+ select MACH_HAS_SND_SOC_TEGRA_WM8903
help
Support for nVidia Harmony development platform
config MACH_KAEN
bool "Kaen board"
select MACH_SEABOARD
+ select MACH_HAS_SND_SOC_TEGRA_WM8903
help
Support for the Kaen version of Seaboard
@@ -43,6 +45,7 @@ config MACH_PAZ00
config MACH_SEABOARD
bool "Seaboard board"
+ select MACH_HAS_SND_SOC_TEGRA_WM8903
help
Support for nVidia Seaboard development platform. It will
also be included for some of the derivative boards that
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 1afe05038c27..823c703e573c 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -1,7 +1,7 @@
obj-y += common.o
obj-y += devices.o
obj-y += io.o
-obj-y += irq.o legacy_irq.o
+obj-y += irq.o
obj-y += clock.o
obj-y += timer.o
obj-y += gpio.o
diff --git a/arch/arm/mach-tegra/board-harmony.c b/arch/arm/mach-tegra/board-harmony.c
index 75c918a86a31..30e18bc60647 100644
--- a/arch/arm/mach-tegra/board-harmony.c
+++ b/arch/arm/mach-tegra/board-harmony.c
@@ -34,7 +34,7 @@
#include <asm/mach/time.h>
#include <asm/setup.h>
-#include <mach/harmony_audio.h>
+#include <mach/tegra_wm8903_pdata.h>
#include <mach/iomap.h>
#include <mach/irqs.h>
#include <mach/sdhci.h>
@@ -67,15 +67,16 @@ static struct platform_device debug_uart = {
},
};
-static struct harmony_audio_platform_data harmony_audio_pdata = {
+static struct tegra_wm8903_platform_data harmony_audio_pdata = {
.gpio_spkr_en = TEGRA_GPIO_SPKR_EN,
.gpio_hp_det = TEGRA_GPIO_HP_DET,
+ .gpio_hp_mute = -1,
.gpio_int_mic_en = TEGRA_GPIO_INT_MIC_EN,
.gpio_ext_mic_en = TEGRA_GPIO_EXT_MIC_EN,
};
static struct platform_device harmony_audio_device = {
- .name = "tegra-snd-harmony",
+ .name = "tegra-snd-wm8903",
.id = 0,
.dev = {
.platform_data = &harmony_audio_pdata,
diff --git a/arch/arm/mach-tegra/gpio.c b/arch/arm/mach-tegra/gpio.c
index 65a1aba6823d..919d63837736 100644
--- a/arch/arm/mach-tegra/gpio.c
+++ b/arch/arm/mach-tegra/gpio.c
@@ -24,6 +24,8 @@
#include <linux/io.h>
#include <linux/gpio.h>
+#include <asm/mach/irq.h>
+
#include <mach/iomap.h>
#include <mach/suspend.h>
@@ -221,8 +223,9 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
int port;
int pin;
int unmasked = 0;
+ struct irq_chip *chip = irq_desc_get_chip(desc);
- desc->irq_data.chip->irq_ack(&desc->irq_data);
+ chained_irq_enter(chip, desc);
bank = irq_get_handler_data(irq);
@@ -241,7 +244,7 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
*/
if (lvl & (0x100 << pin)) {
unmasked = 1;
- desc->irq_data.chip->irq_unmask(&desc->irq_data);
+ chained_irq_exit(chip, desc);
}
generic_handle_irq(gpio_to_irq(gpio + pin));
@@ -249,7 +252,7 @@ static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
}
if (!unmasked)
- desc->irq_data.chip->irq_unmask(&desc->irq_data);
+ chained_irq_exit(chip, desc);
}
diff --git a/arch/arm/mach-tegra/include/mach/kbc.h b/arch/arm/mach-tegra/include/mach/kbc.h
index 04c779832c78..4f3572a1c684 100644
--- a/arch/arm/mach-tegra/include/mach/kbc.h
+++ b/arch/arm/mach-tegra/include/mach/kbc.h
@@ -50,13 +50,11 @@ struct tegra_kbc_platform_data {
unsigned int debounce_cnt;
unsigned int repeat_cnt;
- unsigned int wake_cnt; /* 0:wake on any key >1:wake on wake_cfg */
- const struct tegra_kbc_wake_key *wake_cfg;
-
struct tegra_kbc_pin_cfg pin_cfg[KBC_MAX_GPIO];
const struct matrix_keymap_data *keymap_data;
bool wakeup;
bool use_fn_map;
+ bool use_ghost_filter;
};
#endif
diff --git a/arch/arm/mach-tegra/include/mach/legacy_irq.h b/arch/arm/mach-tegra/include/mach/legacy_irq.h
deleted file mode 100644
index d898c0e3d905..000000000000
--- a/arch/arm/mach-tegra/include/mach/legacy_irq.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * arch/arm/mach-tegra/include/mach/legacy_irq.h
- *
- * Copyright (C) 2010 Google, Inc.
- * Author: Colin Cross <ccross@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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 _ARCH_ARM_MACH_TEGRA_LEGARY_IRQ_H
-#define _ARCH_ARM_MACH_TEGRA_LEGARY_IRQ_H
-
-void tegra_legacy_mask_irq(unsigned int irq);
-void tegra_legacy_unmask_irq(unsigned int irq);
-void tegra_legacy_select_fiq(unsigned int irq, bool fiq);
-void tegra_legacy_force_irq_set(unsigned int irq);
-void tegra_legacy_force_irq_clr(unsigned int irq);
-int tegra_legacy_force_irq_status(unsigned int irq);
-void tegra_legacy_select_fiq(unsigned int irq, bool fiq);
-unsigned long tegra_legacy_vfiq(int nr);
-unsigned long tegra_legacy_class(int nr);
-int tegra_legacy_irq_set_wake(int irq, int enable);
-void tegra_legacy_irq_set_lp1_wake_mask(void);
-void tegra_legacy_irq_restore_mask(void);
-void tegra_init_legacy_irq(void);
-
-#endif
diff --git a/arch/arm/mach-tegra/include/mach/sdhci.h b/arch/arm/mach-tegra/include/mach/sdhci.h
index 3ad086e859c3..4231bc7b8652 100644
--- a/arch/arm/mach-tegra/include/mach/sdhci.h
+++ b/arch/arm/mach-tegra/include/mach/sdhci.h
@@ -24,6 +24,7 @@ struct tegra_sdhci_platform_data {
int wp_gpio;
int power_gpio;
int is_8bit;
+ int pm_flags;
};
#endif
diff --git a/arch/arm/mach-tegra/include/mach/smp.h b/arch/arm/mach-tegra/include/mach/smp.h
deleted file mode 100644
index c8221b38ee7c..000000000000
--- a/arch/arm/mach-tegra/include/mach/smp.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef ASMARM_ARCH_SMP_H
-#define ASMARM_ARCH_SMP_H
-
-#include <asm/hardware/gic.h>
-
-/*
- * We use IRQ1 as the IPI
- */
-static inline void smp_cross_call(const struct cpumask *mask, int ipi)
-{
- gic_raise_softirq(mask, ipi);
-}
-
-#endif
diff --git a/arch/arm/mach-tegra/include/mach/harmony_audio.h b/arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h
index af086500ab7d..9d293344a7ff 100644
--- a/arch/arm/mach-tegra/include/mach/harmony_audio.h
+++ b/arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-tegra/include/mach/harmony_audio.h
+ * arch/arm/mach-tegra/include/mach/tegra_wm8903_pdata.h
*
* Copyright 2011 NVIDIA, Inc.
*
@@ -14,9 +14,10 @@
*
*/
-struct harmony_audio_platform_data {
+struct tegra_wm8903_platform_data {
int gpio_spkr_en;
int gpio_hp_det;
+ int gpio_hp_mute;
int gpio_int_mic_en;
int gpio_ext_mic_en;
};
diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c
index 4330d8995b27..4956c3cea731 100644
--- a/arch/arm/mach-tegra/irq.c
+++ b/arch/arm/mach-tegra/irq.c
@@ -1,8 +1,8 @@
/*
- * Copyright (C) 2010 Google, Inc.
+ * Copyright (C) 2011 Google, Inc.
*
* Author:
- * Colin Cross <ccross@google.com>
+ * Colin Cross <ccross@android.com>
*
* Copyright (C) 2010, NVIDIA Corporation
*
@@ -18,8 +18,6 @@
*/
#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/io.h>
@@ -27,134 +25,110 @@
#include <asm/hardware/gic.h>
#include <mach/iomap.h>
-#include <mach/legacy_irq.h>
-#include <mach/suspend.h>
#include "board.h"
-#define PMC_CTRL 0x0
-#define PMC_CTRL_LATCH_WAKEUPS (1 << 5)
-#define PMC_WAKE_MASK 0xc
-#define PMC_WAKE_LEVEL 0x10
-#define PMC_WAKE_STATUS 0x14
-#define PMC_SW_WAKE_STATUS 0x18
-#define PMC_DPD_SAMPLE 0x20
+#define INT_SYS_NR (INT_GPIO_BASE - INT_PRI_BASE)
+#define INT_SYS_SZ (INT_SEC_BASE - INT_PRI_BASE)
+#define PPI_NR ((INT_SYS_NR+INT_SYS_SZ-1)/INT_SYS_SZ)
+
+#define ICTLR_CPU_IEP_VFIQ 0x08
+#define ICTLR_CPU_IEP_FIR 0x14
+#define ICTLR_CPU_IEP_FIR_SET 0x18
+#define ICTLR_CPU_IEP_FIR_CLR 0x1c
+
+#define ICTLR_CPU_IER 0x20
+#define ICTLR_CPU_IER_SET 0x24
+#define ICTLR_CPU_IER_CLR 0x28
+#define ICTLR_CPU_IEP_CLASS 0x2C
+
+#define ICTLR_COP_IER 0x30
+#define ICTLR_COP_IER_SET 0x34
+#define ICTLR_COP_IER_CLR 0x38
+#define ICTLR_COP_IEP_CLASS 0x3c
+
+#define NUM_ICTLRS 4
+#define FIRST_LEGACY_IRQ 32
+
+static void __iomem *ictlr_reg_base[] = {
+ IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE),
+ IO_ADDRESS(TEGRA_SECONDARY_ICTLR_BASE),
+ IO_ADDRESS(TEGRA_TERTIARY_ICTLR_BASE),
+ IO_ADDRESS(TEGRA_QUATERNARY_ICTLR_BASE),
+};
-static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE);
+static inline void tegra_irq_write_mask(unsigned int irq, unsigned long reg)
+{
+ void __iomem *base;
+ u32 mask;
-static u32 tegra_lp0_wake_enb;
-static u32 tegra_lp0_wake_level;
-static u32 tegra_lp0_wake_level_any;
+ BUG_ON(irq < FIRST_LEGACY_IRQ ||
+ irq >= FIRST_LEGACY_IRQ + NUM_ICTLRS * 32);
-static void (*tegra_gic_mask_irq)(struct irq_data *d);
-static void (*tegra_gic_unmask_irq)(struct irq_data *d);
-static void (*tegra_gic_ack_irq)(struct irq_data *d);
+ base = ictlr_reg_base[(irq - FIRST_LEGACY_IRQ) / 32];
+ mask = BIT((irq - FIRST_LEGACY_IRQ) % 32);
-/* ensures that sufficient time is passed for a register write to
- * serialize into the 32KHz domain */
-static void pmc_32kwritel(u32 val, unsigned long offs)
-{
- writel(val, pmc + offs);
- udelay(130);
+ __raw_writel(mask, base + reg);
}
-int tegra_set_lp1_wake(int irq, int enable)
+static void tegra_mask(struct irq_data *d)
{
- return tegra_legacy_irq_set_wake(irq, enable);
+ if (d->irq < FIRST_LEGACY_IRQ)
+ return;
+
+ tegra_irq_write_mask(d->irq, ICTLR_CPU_IER_CLR);
}
-void tegra_set_lp0_wake_pads(u32 wake_enb, u32 wake_level, u32 wake_any)
+static void tegra_unmask(struct irq_data *d)
{
- u32 temp;
- u32 status;
- u32 lvl;
-
- wake_level &= wake_enb;
- wake_any &= wake_enb;
+ if (d->irq < FIRST_LEGACY_IRQ)
+ return;
- wake_level |= (tegra_lp0_wake_level & tegra_lp0_wake_enb);
- wake_any |= (tegra_lp0_wake_level_any & tegra_lp0_wake_enb);
-
- wake_enb |= tegra_lp0_wake_enb;
-
- pmc_32kwritel(0, PMC_SW_WAKE_STATUS);
- temp = readl(pmc + PMC_CTRL);
- temp |= PMC_CTRL_LATCH_WAKEUPS;
- pmc_32kwritel(temp, PMC_CTRL);
- temp &= ~PMC_CTRL_LATCH_WAKEUPS;
- pmc_32kwritel(temp, PMC_CTRL);
- status = readl(pmc + PMC_SW_WAKE_STATUS);
- lvl = readl(pmc + PMC_WAKE_LEVEL);
-
- /* flip the wakeup trigger for any-edge triggered pads
- * which are currently asserting as wakeups */
- lvl ^= status;
- lvl &= wake_any;
-
- wake_level |= lvl;
-
- writel(wake_level, pmc + PMC_WAKE_LEVEL);
- /* Enable DPD sample to trigger sampling pads data and direction
- * in which pad will be driven during lp0 mode*/
- writel(0x1, pmc + PMC_DPD_SAMPLE);
-
- writel(wake_enb, pmc + PMC_WAKE_MASK);
+ tegra_irq_write_mask(d->irq, ICTLR_CPU_IER_SET);
}
-static void tegra_mask(struct irq_data *d)
+static void tegra_ack(struct irq_data *d)
{
- tegra_gic_mask_irq(d);
- tegra_legacy_mask_irq(d->irq);
-}
+ if (d->irq < FIRST_LEGACY_IRQ)
+ return;
-static void tegra_unmask(struct irq_data *d)
-{
- tegra_gic_unmask_irq(d);
- tegra_legacy_unmask_irq(d->irq);
+ tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_CLR);
}
-static void tegra_ack(struct irq_data *d)
+static void tegra_eoi(struct irq_data *d)
{
- tegra_legacy_force_irq_clr(d->irq);
- tegra_gic_ack_irq(d);
+ if (d->irq < FIRST_LEGACY_IRQ)
+ return;
+
+ tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_CLR);
}
static int tegra_retrigger(struct irq_data *d)
{
- tegra_legacy_force_irq_set(d->irq);
+ if (d->irq < FIRST_LEGACY_IRQ)
+ return 0;
+
+ tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_SET);
+
return 1;
}
-static struct irq_chip tegra_irq = {
- .name = "PPI",
- .irq_ack = tegra_ack,
- .irq_mask = tegra_mask,
- .irq_unmask = tegra_unmask,
- .irq_retrigger = tegra_retrigger,
-};
-
void __init tegra_init_irq(void)
{
- struct irq_chip *gic;
- unsigned int i;
- int irq;
+ int i;
- tegra_init_legacy_irq();
+ for (i = 0; i < NUM_ICTLRS; i++) {
+ void __iomem *ictlr = ictlr_reg_base[i];
+ writel(~0, ictlr + ICTLR_CPU_IER_CLR);
+ writel(0, ictlr + ICTLR_CPU_IEP_CLASS);
+ }
+
+ gic_arch_extn.irq_ack = tegra_ack;
+ gic_arch_extn.irq_eoi = tegra_eoi;
+ gic_arch_extn.irq_mask = tegra_mask;
+ gic_arch_extn.irq_unmask = tegra_unmask;
+ gic_arch_extn.irq_retrigger = tegra_retrigger;
gic_init(0, 29, IO_ADDRESS(TEGRA_ARM_INT_DIST_BASE),
IO_ADDRESS(TEGRA_ARM_PERIF_BASE + 0x100));
-
- gic = irq_get_chip(29);
- tegra_gic_unmask_irq = gic->irq_unmask;
- tegra_gic_mask_irq = gic->irq_mask;
- tegra_gic_ack_irq = gic->irq_ack;
-#ifdef CONFIG_SMP
- tegra_irq.irq_set_affinity = gic->irq_set_affinity;
-#endif
-
- for (i = 0; i < INT_MAIN_NR; i++) {
- irq = INT_PRI_BASE + i;
- irq_set_chip_and_handler(irq, &tegra_irq, handle_level_irq);
- set_irq_flags(irq, IRQF_VALID);
- }
}
diff --git a/arch/arm/mach-tegra/legacy_irq.c b/arch/arm/mach-tegra/legacy_irq.c
deleted file mode 100644
index 38eb719a4f53..000000000000
--- a/arch/arm/mach-tegra/legacy_irq.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * arch/arm/mach-tegra/legacy_irq.c
- *
- * Copyright (C) 2010 Google, Inc.
- * Author: Colin Cross <ccross@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT 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/io.h>
-#include <linux/kernel.h>
-#include <mach/iomap.h>
-#include <mach/irqs.h>
-#include <mach/legacy_irq.h>
-
-#define INT_SYS_NR (INT_GPIO_BASE - INT_PRI_BASE)
-#define INT_SYS_SZ (INT_SEC_BASE - INT_PRI_BASE)
-#define PPI_NR ((INT_SYS_NR+INT_SYS_SZ-1)/INT_SYS_SZ)
-
-#define ICTLR_CPU_IEP_VFIQ 0x08
-#define ICTLR_CPU_IEP_FIR 0x14
-#define ICTLR_CPU_IEP_FIR_SET 0x18
-#define ICTLR_CPU_IEP_FIR_CLR 0x1c
-
-#define ICTLR_CPU_IER 0x20
-#define ICTLR_CPU_IER_SET 0x24
-#define ICTLR_CPU_IER_CLR 0x28
-#define ICTLR_CPU_IEP_CLASS 0x2C
-
-#define ICTLR_COP_IER 0x30
-#define ICTLR_COP_IER_SET 0x34
-#define ICTLR_COP_IER_CLR 0x38
-#define ICTLR_COP_IEP_CLASS 0x3c
-
-#define NUM_ICTLRS 4
-
-static void __iomem *ictlr_reg_base[] = {
- IO_ADDRESS(TEGRA_PRIMARY_ICTLR_BASE),
- IO_ADDRESS(TEGRA_SECONDARY_ICTLR_BASE),
- IO_ADDRESS(TEGRA_TERTIARY_ICTLR_BASE),
- IO_ADDRESS(TEGRA_QUATERNARY_ICTLR_BASE),
-};
-
-static u32 tegra_legacy_wake_mask[4];
-static u32 tegra_legacy_saved_mask[4];
-
-/* When going into deep sleep, the CPU is powered down, taking the GIC with it
- In order to wake, the wake interrupts need to be enabled in the legacy
- interrupt controller. */
-void tegra_legacy_unmask_irq(unsigned int irq)
-{
- void __iomem *base;
- pr_debug("%s: %d\n", __func__, irq);
-
- irq -= 32;
- base = ictlr_reg_base[irq>>5];
- writel(1 << (irq & 31), base + ICTLR_CPU_IER_SET);
-}
-
-void tegra_legacy_mask_irq(unsigned int irq)
-{
- void __iomem *base;
- pr_debug("%s: %d\n", __func__, irq);
-
- irq -= 32;
- base = ictlr_reg_base[irq>>5];
- writel(1 << (irq & 31), base + ICTLR_CPU_IER_CLR);
-}
-
-void tegra_legacy_force_irq_set(unsigned int irq)
-{
- void __iomem *base;
- pr_debug("%s: %d\n", __func__, irq);
-
- irq -= 32;
- base = ictlr_reg_base[irq>>5];
- writel(1 << (irq & 31), base + ICTLR_CPU_IEP_FIR_SET);
-}
-
-void tegra_legacy_force_irq_clr(unsigned int irq)
-{
- void __iomem *base;
- pr_debug("%s: %d\n", __func__, irq);
-
- irq -= 32;
- base = ictlr_reg_base[irq>>5];
- writel(1 << (irq & 31), base + ICTLR_CPU_IEP_FIR_CLR);
-}
-
-int tegra_legacy_force_irq_status(unsigned int irq)
-{
- void __iomem *base;
- pr_debug("%s: %d\n", __func__, irq);
-
- irq -= 32;
- base = ictlr_reg_base[irq>>5];
- return !!(readl(base + ICTLR_CPU_IEP_FIR) & (1 << (irq & 31)));
-}
-
-void tegra_legacy_select_fiq(unsigned int irq, bool fiq)
-{
- void __iomem *base;
- pr_debug("%s: %d\n", __func__, irq);
-
- irq -= 32;
- base = ictlr_reg_base[irq>>5];
- writel(fiq << (irq & 31), base + ICTLR_CPU_IEP_CLASS);
-}
-
-unsigned long tegra_legacy_vfiq(int nr)
-{
- void __iomem *base;
- base = ictlr_reg_base[nr];
- return readl(base + ICTLR_CPU_IEP_VFIQ);
-}
-
-unsigned long tegra_legacy_class(int nr)
-{
- void __iomem *base;
- base = ictlr_reg_base[nr];
- return readl(base + ICTLR_CPU_IEP_CLASS);
-}
-
-int tegra_legacy_irq_set_wake(int irq, int enable)
-{
- irq -= 32;
- if (enable)
- tegra_legacy_wake_mask[irq >> 5] |= 1 << (irq & 31);
- else
- tegra_legacy_wake_mask[irq >> 5] &= ~(1 << (irq & 31));
-
- return 0;
-}
-
-void tegra_legacy_irq_set_lp1_wake_mask(void)
-{
- void __iomem *base;
- int i;
-
- for (i = 0; i < NUM_ICTLRS; i++) {
- base = ictlr_reg_base[i];
- tegra_legacy_saved_mask[i] = readl(base + ICTLR_CPU_IER);
- writel(tegra_legacy_wake_mask[i], base + ICTLR_CPU_IER);
- }
-}
-
-void tegra_legacy_irq_restore_mask(void)
-{
- void __iomem *base;
- int i;
-
- for (i = 0; i < NUM_ICTLRS; i++) {
- base = ictlr_reg_base[i];
- writel(tegra_legacy_saved_mask[i], base + ICTLR_CPU_IER);
- }
-}
-
-void tegra_init_legacy_irq(void)
-{
- int i;
-
- for (i = 0; i < NUM_ICTLRS; i++) {
- void __iomem *ictlr = ictlr_reg_base[i];
- writel(~0, ictlr + ICTLR_CPU_IER_CLR);
- writel(0, ictlr + ICTLR_CPU_IEP_CLASS);
- }
-}
-
-#ifdef CONFIG_PM
-static u32 cop_ier[NUM_ICTLRS];
-static u32 cpu_ier[NUM_ICTLRS];
-static u32 cpu_iep[NUM_ICTLRS];
-
-void tegra_irq_suspend(void)
-{
- unsigned long flags;
- int i;
-
- local_irq_save(flags);
- for (i = 0; i < NUM_ICTLRS; i++) {
- void __iomem *ictlr = ictlr_reg_base[i];
- cpu_ier[i] = readl(ictlr + ICTLR_CPU_IER);
- cpu_iep[i] = readl(ictlr + ICTLR_CPU_IEP_CLASS);
- cop_ier[i] = readl(ictlr + ICTLR_COP_IER);
- writel(~0, ictlr + ICTLR_COP_IER_CLR);
- }
- local_irq_restore(flags);
-}
-
-void tegra_irq_resume(void)
-{
- unsigned long flags;
- int i;
-
- local_irq_save(flags);
- for (i = 0; i < NUM_ICTLRS; i++) {
- void __iomem *ictlr = ictlr_reg_base[i];
- writel(cpu_iep[i], ictlr + ICTLR_CPU_IEP_CLASS);
- writel(~0ul, ictlr + ICTLR_CPU_IER_CLR);
- writel(cpu_ier[i], ictlr + ICTLR_CPU_IER_SET);
- writel(0, ictlr + ICTLR_COP_IEP_CLASS);
- writel(~0ul, ictlr + ICTLR_COP_IER_CLR);
- writel(cop_ier[i], ictlr + ICTLR_COP_IER_SET);
- }
- local_irq_restore(flags);
-}
-#endif
diff --git a/arch/arm/mach-tegra/platsmp.c b/arch/arm/mach-tegra/platsmp.c
index ec1f68924edf..b8ae3c978dee 100644
--- a/arch/arm/mach-tegra/platsmp.c
+++ b/arch/arm/mach-tegra/platsmp.c
@@ -20,6 +20,7 @@
#include <linux/io.h>
#include <asm/cacheflush.h>
+#include <asm/hardware/gic.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <asm/smp_scu.h>
@@ -122,6 +123,8 @@ void __init smp_init_cpus(void)
for (i = 0; i < ncores; i++)
cpu_set(i, cpu_possible_map);
+
+ set_smp_cross_call(gic_raise_softirq);
}
void __init platform_smp_prepare_cpus(unsigned int max_cpus)
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c
index 4459470c052d..bb618075fab6 100644
--- a/arch/arm/mach-tegra/tegra2_clocks.c
+++ b/arch/arm/mach-tegra/tegra2_clocks.c
@@ -337,7 +337,7 @@ static int tegra2_super_clk_set_parent(struct clk *c, struct clk *p)
const struct clk_mux_sel *sel;
int shift;
- val = clk_readl(c->reg + SUPER_CLK_MUX);;
+ val = clk_readl(c->reg + SUPER_CLK_MUX);
BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) &&
((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE));
shift = ((val & SUPER_STATE_MASK) == SUPER_STATE_IDLE) ?
diff --git a/arch/arm/mach-tegra/timer.c b/arch/arm/mach-tegra/timer.c
index 0fcb1eb4214d..90350420c4e9 100644
--- a/arch/arm/mach-tegra/timer.c
+++ b/arch/arm/mach-tegra/timer.c
@@ -98,11 +98,6 @@ static void tegra_timer_set_mode(enum clock_event_mode mode,
}
}
-static cycle_t tegra_clocksource_read(struct clocksource *cs)
-{
- return timer_readl(TIMERUS_CNTR_1US);
-}
-
static struct clock_event_device tegra_clockevent = {
.name = "timer0",
.rating = 300,
@@ -111,14 +106,6 @@ static struct clock_event_device tegra_clockevent = {
.set_mode = tegra_timer_set_mode,
};
-static struct clocksource tegra_clocksource = {
- .name = "timer_us",
- .rating = 300,
- .read = tegra_clocksource_read,
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
static DEFINE_CLOCK_DATA(cd);
/*
@@ -234,7 +221,8 @@ static void __init tegra_init_timer(void)
init_fixed_sched_clock(&cd, tegra_update_sched_clock, 32,
1000000, SC_MULT, SC_SHIFT);
- if (clocksource_register_hz(&tegra_clocksource, 1000000)) {
+ if (clocksource_mmio_init(timer_reg_base + TIMERUS_CNTR_1US,
+ "timer_us", 1000000, 300, 32, clocksource_mmio_readl_up)) {
printk(KERN_ERR "Failed to register clocksource\n");
BUG();
}
diff --git a/arch/arm/mach-u300/timer.c b/arch/arm/mach-u300/timer.c
index 3ec58bd2d6e4..891cf44591e0 100644
--- a/arch/arm/mach-u300/timer.c
+++ b/arch/arm/mach-u300/timer.c
@@ -333,20 +333,6 @@ static struct irqaction u300_timer_irq = {
.handler = u300_timer_interrupt,
};
-/* Use general purpose timer 2 as clock source */
-static cycle_t u300_get_cycles(struct clocksource *cs)
-{
- return (cycles_t) readl(U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT2CC);
-}
-
-static struct clocksource clocksource_u300_1mhz = {
- .name = "GPT2",
- .rating = 300, /* Reasonably fast and accurate clock source */
- .read = u300_get_cycles,
- .mask = CLOCKSOURCE_MASK(32), /* 32 bits */
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
/*
* Override the global weak sched_clock symbol with this
* local implementation which uses the clocksource to get some
@@ -422,7 +408,9 @@ static void __init u300_timer_init(void)
writel(U300_TIMER_APP_EGPT2_TIMER_ENABLE,
U300_TIMER_APP_VBASE + U300_TIMER_APP_EGPT2);
- if (clocksource_register_hz(&clocksource_u300_1mhz, rate))
+ /* Use general purpose timer 2 as clock source */
+ if (clocksource_mmio_init(U300_TIMER_APP_VBASE + U300_TIMER_APP_GPT2CC,
+ "GPT2", rate, 300, 32, clocksource_mmio_readl_up))
printk(KERN_ERR "timer: failed to initialize clock "
"source %s\n", clocksource_u300_1mhz.name);
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
index 58626013aa32..54429d015954 100644
--- a/arch/arm/mach-ux500/Kconfig
+++ b/arch/arm/mach-ux500/Kconfig
@@ -12,9 +12,12 @@ menu "Ux500 SoC"
config UX500_SOC_DB5500
bool "DB5500"
+ select MFD_DB5500_PRCMU
config UX500_SOC_DB8500
bool "DB8500"
+ select MFD_DB8500_PRCMU
+ select REGULATOR_DB8500_PRCMU
endmenu
diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile
index b549a8fb4231..1694916e6822 100644
--- a/arch/arm/mach-ux500/Makefile
+++ b/arch/arm/mach-ux500/Makefile
@@ -5,7 +5,7 @@
obj-y := clock.o cpu.o devices.o devices-common.o \
id.o usb.o
obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o dma-db5500.o
-obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o prcmu.o
+obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o
obj-$(CONFIG_MACH_U8500) += board-mop500.o board-mop500-sdi.o \
board-mop500-regulators.o \
board-mop500-uib.o board-mop500-stuib.o \
@@ -17,4 +17,4 @@ obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
obj-$(CONFIG_U5500_MODEM_IRQ) += modem-irq-db5500.o
obj-$(CONFIG_U5500_MBOX) += mbox-db5500.o
-obj-$(CONFIG_CPU_FREQ) += cpufreq.o
+
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c
index 6e1907fa94f0..bb26f40493e6 100644
--- a/arch/arm/mach-ux500/board-mop500.c
+++ b/arch/arm/mach-ux500/board-mop500.c
@@ -204,7 +204,7 @@ static struct i2c_board_info __initdata mop500_i2c2_devices[] = {
},
};
-#define U8500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, _sm) \
+#define U8500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, t_out, _sm) \
static struct nmk_i2c_controller u8500_i2c##id##_data = { \
/* \
* slave data setup time, which is \
@@ -219,19 +219,21 @@ static struct nmk_i2c_controller u8500_i2c##id##_data = { \
.rft = _rft, \
/* std. mode operation */ \
.clk_freq = clk, \
+ /* Slave response timeout(ms) */\
+ .timeout = t_out, \
.sm = _sm, \
}
/*
* The board uses 4 i2c controllers, initialize all of
* them with slave data setup time of 250 ns,
- * Tx & Rx FIFO threshold values as 1 and standard
+ * Tx & Rx FIFO threshold values as 8 and standard
* mode of operation
*/
-U8500_I2C_CONTROLLER(0, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
-U8500_I2C_CONTROLLER(1, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
-U8500_I2C_CONTROLLER(2, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
-U8500_I2C_CONTROLLER(3, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
+U8500_I2C_CONTROLLER(0, 0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
+U8500_I2C_CONTROLLER(1, 0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
+U8500_I2C_CONTROLLER(2, 0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
+U8500_I2C_CONTROLLER(3, 0xe, 1, 8, 100000, 200, I2C_FREQ_MODE_FAST);
static void __init mop500_i2c_init(void)
{
diff --git a/arch/arm/mach-ux500/cpu-db5500.c b/arch/arm/mach-ux500/cpu-db5500.c
index c9dc2eff3cb2..c01bc19e3c5e 100644
--- a/arch/arm/mach-ux500/cpu-db5500.c
+++ b/arch/arm/mach-ux500/cpu-db5500.c
@@ -188,6 +188,8 @@ void __init u5500_map_io(void)
ux500_map_io();
iotable_init(u5500_io_desc, ARRAY_SIZE(u5500_io_desc));
+
+ _PRCMU_BASE = __io_address(U5500_PRCMU_BASE);
}
static int usb_db5500_rx_dma_cfg[] = {
diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c
index 516126cb357d..c3c417656bd9 100644
--- a/arch/arm/mach-ux500/cpu-db8500.c
+++ b/arch/arm/mach-ux500/cpu-db8500.c
@@ -87,6 +87,8 @@ void __init u8500_map_io(void)
iotable_init(u8500_v1_io_desc, ARRAY_SIZE(u8500_v1_io_desc));
else if (cpu_is_u8500v2())
iotable_init(u8500_v2_io_desc, ARRAY_SIZE(u8500_v2_io_desc));
+
+ _PRCMU_BASE = __io_address(U8500_PRCMU_BASE);
}
static struct resource db8500_pmu_resources[] = {
@@ -129,9 +131,14 @@ static struct platform_device db8500_pmu_device = {
.dev.platform_data = &db8500_pmu_platdata,
};
+static struct platform_device db8500_prcmu_device = {
+ .name = "db8500-prcmu",
+};
+
static struct platform_device *platform_devs[] __initdata = {
&u8500_dma40_device,
&db8500_pmu_device,
+ &db8500_prcmu_device,
};
static resource_size_t __initdata db8500_gpio_base[] = {
diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c
index 5a43107c6232..1da23bb87c16 100644
--- a/arch/arm/mach-ux500/cpu.c
+++ b/arch/arm/mach-ux500/cpu.c
@@ -8,6 +8,8 @@
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/clk.h>
+#include <linux/mfd/db8500-prcmu.h>
+#include <linux/mfd/db5500-prcmu.h>
#include <asm/cacheflush.h>
#include <asm/hardware/cache-l2x0.h>
@@ -19,10 +21,11 @@
#include <mach/hardware.h>
#include <mach/setup.h>
#include <mach/devices.h>
-#include <mach/prcmu.h>
#include "clock.h"
+void __iomem *_PRCMU_BASE;
+
#ifdef CONFIG_CACHE_L2X0
static void __iomem *l2x0_base;
#endif
@@ -47,6 +50,8 @@ void __init ux500_init_irq(void)
* Init clocks here so that they are available for system timer
* initialization.
*/
+ if (cpu_is_u5500())
+ db5500_prcmu_early_init();
if (cpu_is_u8500())
prcmu_early_init();
clk_init();
diff --git a/arch/arm/mach-ux500/cpufreq.c b/arch/arm/mach-ux500/cpufreq.c
deleted file mode 100644
index 5c5b747f134d..000000000000
--- a/arch/arm/mach-ux500/cpufreq.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * CPU frequency scaling for u8500
- * Inspired by linux/arch/arm/mach-davinci/cpufreq.c
- *
- * Copyright (C) STMicroelectronics 2009
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License Terms: GNU General Public License v2
- *
- * Author: Sundar Iyer <sundar.iyer@stericsson.com>
- * Author: Martin Persson <martin.persson@stericsson.com>
- * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
- *
- */
-
-#include <linux/platform_device.h>
-#include <linux/kernel.h>
-#include <linux/cpufreq.h>
-#include <linux/delay.h>
-
-#include <mach/hardware.h>
-#include <mach/prcmu.h>
-#include <mach/prcmu-defs.h>
-
-#define DRIVER_NAME "cpufreq-u8500"
-#define CPUFREQ_NAME "u8500"
-
-static struct device *dev;
-
-static struct cpufreq_frequency_table freq_table[] = {
- [0] = {
- .index = 0,
- .frequency = 200000,
- },
- [1] = {
- .index = 1,
- .frequency = 300000,
- },
- [2] = {
- .index = 2,
- .frequency = 600000,
- },
- [3] = {
- /* Used for CPU_OPP_MAX, if available */
- .index = 3,
- .frequency = CPUFREQ_TABLE_END,
- },
- [4] = {
- .index = 4,
- .frequency = CPUFREQ_TABLE_END,
- },
-};
-
-static enum prcmu_cpu_opp index2opp[] = {
- CPU_OPP_EXT_CLK,
- CPU_OPP_50,
- CPU_OPP_100,
- CPU_OPP_MAX
-};
-
-static int u8500_cpufreq_verify_speed(struct cpufreq_policy *policy)
-{
- return cpufreq_frequency_table_verify(policy, freq_table);
-}
-
-static int u8500_cpufreq_target(struct cpufreq_policy *policy,
- unsigned int target_freq,
- unsigned int relation)
-{
- struct cpufreq_freqs freqs;
- unsigned int index;
- int ret = 0;
-
- /*
- * Ensure desired rate is within allowed range. Some govenors
- * (ondemand) will just pass target_freq=0 to get the minimum.
- */
- if (target_freq < policy->cpuinfo.min_freq)
- target_freq = policy->cpuinfo.min_freq;
- if (target_freq > policy->cpuinfo.max_freq)
- target_freq = policy->cpuinfo.max_freq;
-
- ret = cpufreq_frequency_table_target(policy, freq_table,
- target_freq, relation, &index);
- if (ret < 0) {
- dev_err(dev, "Could not look up next frequency\n");
- return ret;
- }
-
- freqs.old = policy->cur;
- freqs.new = freq_table[index].frequency;
- freqs.cpu = policy->cpu;
-
- if (freqs.old == freqs.new) {
- dev_dbg(dev, "Current and target frequencies are equal\n");
- return 0;
- }
-
- dev_dbg(dev, "transition: %u --> %u\n", freqs.old, freqs.new);
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-
- ret = prcmu_set_cpu_opp(index2opp[index]);
- if (ret < 0) {
- dev_err(dev, "Failed to set OPP level\n");
- return ret;
- }
-
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
-
- return ret;
-}
-
-static unsigned int u8500_cpufreq_getspeed(unsigned int cpu)
-{
- int i;
-
- for (i = 0; prcmu_get_cpu_opp() != index2opp[i]; i++)
- ;
- return freq_table[i].frequency;
-}
-
-static int __cpuinit u8500_cpu_init(struct cpufreq_policy *policy)
-{
- int res;
-
- BUILD_BUG_ON(ARRAY_SIZE(index2opp) + 1 != ARRAY_SIZE(freq_table));
-
- if (cpu_is_u8500v2()) {
- freq_table[1].frequency = 400000;
- freq_table[2].frequency = 800000;
- if (prcmu_has_arm_maxopp())
- freq_table[3].frequency = 1000000;
- }
-
- /* get policy fields based on the table */
- res = cpufreq_frequency_table_cpuinfo(policy, freq_table);
- if (!res)
- cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
- else {
- dev_err(dev, "u8500-cpufreq : Failed to read policy table\n");
- return res;
- }
-
- policy->min = policy->cpuinfo.min_freq;
- policy->max = policy->cpuinfo.max_freq;
- policy->cur = u8500_cpufreq_getspeed(policy->cpu);
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
- /*
- * FIXME : Need to take time measurement across the target()
- * function with no/some/all drivers in the notification
- * list.
- */
- policy->cpuinfo.transition_latency = 200 * 1000; /* in ns */
-
- /* policy sharing between dual CPUs */
- cpumask_copy(policy->cpus, &cpu_present_map);
-
- policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
-
- return res;
-}
-
-static struct freq_attr *u8500_cpufreq_attr[] = {
- &cpufreq_freq_attr_scaling_available_freqs,
- NULL,
-};
-static int u8500_cpu_exit(struct cpufreq_policy *policy)
-{
- cpufreq_frequency_table_put_attr(policy->cpu);
- return 0;
-}
-
-static struct cpufreq_driver u8500_driver = {
- .owner = THIS_MODULE,
- .flags = CPUFREQ_STICKY,
- .verify = u8500_cpufreq_verify_speed,
- .target = u8500_cpufreq_target,
- .get = u8500_cpufreq_getspeed,
- .init = u8500_cpu_init,
- .exit = u8500_cpu_exit,
- .name = CPUFREQ_NAME,
- .attr = u8500_cpufreq_attr,
-};
-
-static int __init u8500_cpufreq_probe(struct platform_device *pdev)
-{
- dev = &pdev->dev;
- return cpufreq_register_driver(&u8500_driver);
-}
-
-static int __exit u8500_cpufreq_remove(struct platform_device *pdev)
-{
- return cpufreq_unregister_driver(&u8500_driver);
-}
-
-static struct platform_driver u8500_cpufreq_driver = {
- .driver = {
- .name = DRIVER_NAME,
- .owner = THIS_MODULE,
- },
- .remove = __exit_p(u8500_cpufreq_remove),
-};
-
-static int __init u8500_cpufreq_init(void)
-{
- return platform_driver_probe(&u8500_cpufreq_driver,
- &u8500_cpufreq_probe);
-}
-
-device_initcall(u8500_cpufreq_init);
diff --git a/arch/arm/mach-ux500/include/mach/db5500-regs.h b/arch/arm/mach-ux500/include/mach/db5500-regs.h
index bd88c1e74060..6ad983294103 100644
--- a/arch/arm/mach-ux500/include/mach/db5500-regs.h
+++ b/arch/arm/mach-ux500/include/mach/db5500-regs.h
@@ -17,6 +17,8 @@
#define U5500_GIC_DIST_BASE 0xA0411000
#define U5500_GIC_CPU_BASE 0xA0410100
#define U5500_DMA_BASE 0x90030000
+#define U5500_STM_BASE 0x90020000
+#define U5500_STM_REG_BASE (U5500_STM_BASE + 0xF000)
#define U5500_MCDE_BASE 0xA0400000
#define U5500_MODEM_BASE 0xB0000000
#define U5500_L2CC_BASE 0xA0412000
@@ -29,7 +31,9 @@
#define U5500_NAND0_BASE 0x60000000
#define U5500_NAND1_BASE 0x70000000
#define U5500_TWD_BASE 0xa0410600
+#define U5500_ICN_BASE 0xA0040000
#define U5500_B2R2_BASE 0xa0200000
+#define U5500_BOOT_ROM_BASE 0x90000000
#define U5500_FSMC_BASE (U5500_PER1_BASE + 0x0000)
#define U5500_SDI0_BASE (U5500_PER1_BASE + 0x1000)
@@ -60,6 +64,7 @@
#define U5500_MSP1_BASE (U5500_PER4_BASE + 0x9000)
#define U5500_GPIO2_BASE (U5500_PER4_BASE + 0xA000)
#define U5500_CDETECT_BASE (U5500_PER4_BASE + 0xF000)
+#define U5500_PRCMU_TCDM_BASE (U5500_PER4_BASE + 0x18000)
#define U5500_SPI0_BASE (U5500_PER5_BASE + 0x0000)
#define U5500_SPI1_BASE (U5500_PER5_BASE + 0x1000)
@@ -83,7 +88,7 @@
#define U5500_HASH0_BASE (U5500_PER6_BASE + 0x1000)
#define U5500_HASH1_BASE (U5500_PER6_BASE + 0x2000)
#define U5500_PKA_BASE (U5500_PER6_BASE + 0x4000)
-#define U5500_PKAM_BASE (U5500_PER6_BASE + 0x5000)
+#define U5500_PKAM_BASE (U5500_PER6_BASE + 0x5100)
#define U5500_MTU0_BASE (U5500_PER6_BASE + 0x6000)
#define U5500_MTU1_BASE (U5500_PER6_BASE + 0x7000)
#define U5500_CR_BASE (U5500_PER6_BASE + 0x8000)
@@ -114,8 +119,19 @@
#define U5500_MBOX2_LOCAL_START (U5500_MBOX_BASE + 0x20)
#define U5500_MBOX2_LOCAL_END (U5500_MBOX_BASE + 0x3F)
-#define U5500_ESRAM_BASE 0x40000000
+#define U5500_ACCCON_BASE_SEC (0xBFFF0000)
+#define U5500_ACCCON_BASE (0xBFFF1000)
+#define U5500_ACCCON_CPUVEC_RESET_ADDR_OFFSET (0x00000020)
+#define U5500_ACCCON_ACC_CPU_CTRL_OFFSET (0x000000BC)
+
+#define U5500_ESRAM_BASE 0x40000000
#define U5500_ESRAM_DMA_LCPA_OFFSET 0x10000
#define U5500_DMA_LCPA_BASE (U5500_ESRAM_BASE + U5500_ESRAM_DMA_LCPA_OFFSET)
+#define U5500_MCDE_SIZE 0x1000
+#define U5500_DSI_LINK_SIZE 0x1000
+#define U5500_DSI_LINK_COUNT 0x2
+#define U5500_DSI_LINK1_BASE (U5500_MCDE_BASE + U5500_MCDE_SIZE)
+#define U5500_DSI_LINK2_BASE (U5500_DSI_LINK1_BASE + U5500_DSI_LINK_SIZE)
+
#endif
diff --git a/arch/arm/mach-ux500/include/mach/db8500-regs.h b/arch/arm/mach-ux500/include/mach/db8500-regs.h
index 16647b255378..049997109cf9 100644
--- a/arch/arm/mach-ux500/include/mach/db8500-regs.h
+++ b/arch/arm/mach-ux500/include/mach/db8500-regs.h
@@ -15,8 +15,13 @@
#define U8500_ESRAM_BANK2 (U8500_ESRAM_BANK1 + U8500_ESRAM_BANK_SIZE)
#define U8500_ESRAM_BANK3 (U8500_ESRAM_BANK2 + U8500_ESRAM_BANK_SIZE)
#define U8500_ESRAM_BANK4 (U8500_ESRAM_BANK3 + U8500_ESRAM_BANK_SIZE)
-/* Use bank 4 for DMA LCPA */
-#define U8500_DMA_LCPA_BASE U8500_ESRAM_BANK4
+/*
+ * on V1 DMA uses 4KB for logical parameters position is right after the 64KB
+ * reserved for security
+ */
+#define U8500_ESRAM_DMA_LCPA_OFFSET 0x10000
+
+#define U8500_DMA_LCPA_BASE (U8500_ESRAM_BANK0 + U8500_ESRAM_DMA_LCPA_OFFSET)
#define U8500_DMA_LCPA_BASE_ED (U8500_ESRAM_BANK4 + 0x4000)
#define U8500_PER3_BASE 0x80000000
@@ -27,9 +32,12 @@
#define U8500_B2R2_BASE 0x80130000
#define U8500_HSEM_BASE 0x80140000
#define U8500_PER4_BASE 0x80150000
+#define U8500_TPIU_BASE 0x80190000
#define U8500_ICN_BASE 0x81000000
#define U8500_BOOT_ROM_BASE 0x90000000
+/* ASIC ID is at 0xbf4 offset within this region */
+#define U8500_ASIC_ID_BASE 0x9001D000
#define U8500_PER6_BASE 0xa03c0000
#define U8500_PER5_BASE 0xa03e0000
@@ -70,13 +78,15 @@
/* per6 base addresses */
#define U8500_RNG_BASE (U8500_PER6_BASE + 0x0000)
-#define U8500_PKA_BASE (U8500_PER6_BASE + 0x1000)
-#define U8500_PKAM_BASE (U8500_PER6_BASE + 0x2000)
+#define U8500_HASH0_BASE (U8500_PER6_BASE + 0x1000)
+#define U8500_HASH1_BASE (U8500_PER6_BASE + 0x2000)
+#define U8500_PKA_BASE (U8500_PER6_BASE + 0x4000)
+#define U8500_PKAM_BASE (U8500_PER6_BASE + 0x5100)
#define U8500_MTU0_BASE (U8500_PER6_BASE + 0x6000) /* v1 */
#define U8500_MTU1_BASE (U8500_PER6_BASE + 0x7000) /* v1 */
#define U8500_CR_BASE (U8500_PER6_BASE + 0x8000) /* v1 */
-#define U8500_CRYPTO0_BASE (U8500_PER6_BASE + 0xa000)
-#define U8500_CRYPTO1_BASE (U8500_PER6_BASE + 0xb000)
+#define U8500_CRYP0_BASE (U8500_PER6_BASE + 0xa000)
+#define U8500_CRYP1_BASE (U8500_PER6_BASE + 0xb000)
#define U8500_CLKRST6_BASE (U8500_PER6_BASE + 0xf000)
/* per5 base addresses */
@@ -93,7 +103,8 @@
#define U8500_DMC_BASE (U8500_PER4_BASE + 0x06000)
#define U8500_PRCMU_BASE (U8500_PER4_BASE + 0x07000)
#define U8500_PRCMU_TCDM_BASE_V1 (U8500_PER4_BASE + 0x0f000)
-#define U8500_PRCMU_TCDM_BASE (U8500_PER4_BASE + 0x68000)
+#define U8500_PRCMU_TCDM_BASE (U8500_PER4_BASE + 0x68000)
+#define U8500_PRCMU_TCPM_BASE (U8500_PER4_BASE + 0x60000)
/* per3 base addresses */
#define U8500_FSMC_BASE (U8500_PER3_BASE + 0x0000)
@@ -124,6 +135,7 @@
#define U8500_I2C1_BASE (U8500_PER1_BASE + 0x2000)
#define U8500_MSP0_BASE (U8500_PER1_BASE + 0x3000)
#define U8500_MSP1_BASE (U8500_PER1_BASE + 0x4000)
+#define U8500_MSP3_BASE (U8500_PER1_BASE + 0x5000)
#define U8500_SDI0_BASE (U8500_PER1_BASE + 0x6000)
#define U8500_I2C2_BASE (U8500_PER1_BASE + 0x8000)
#define U8500_SPI3_BASE (U8500_PER1_BASE + 0x9000)
@@ -143,4 +155,15 @@
#define U8500_GPIOBANK7_BASE (U8500_GPIO2_BASE + 0x80)
#define U8500_GPIOBANK8_BASE U8500_GPIO3_BASE
+#define U8500_MCDE_SIZE 0x1000
+#define U8500_DSI_LINK_SIZE 0x1000
+#define U8500_DSI_LINK1_BASE (U8500_MCDE_BASE + U8500_MCDE_SIZE)
+#define U8500_DSI_LINK2_BASE (U8500_DSI_LINK1_BASE + U8500_DSI_LINK_SIZE)
+#define U8500_DSI_LINK3_BASE (U8500_DSI_LINK2_BASE + U8500_DSI_LINK_SIZE)
+#define U8500_DSI_LINK_COUNT 0x3
+
+/* Modem and APE physical addresses */
+#define U8500_MODEM_BASE 0xe000000
+#define U8500_APE_BASE 0x6000000
+
#endif
diff --git a/arch/arm/mach-ux500/include/mach/hardware.h b/arch/arm/mach-ux500/include/mach/hardware.h
index bf63f2631ba0..2c6f71049f2e 100644
--- a/arch/arm/mach-ux500/include/mach/hardware.h
+++ b/arch/arm/mach-ux500/include/mach/hardware.h
@@ -35,6 +35,7 @@
#ifndef __ASSEMBLY__
#include <mach/id.h>
+extern void __iomem *_PRCMU_BASE;
#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x)
diff --git a/arch/arm/mach-ux500/include/mach/id.h b/arch/arm/mach-ux500/include/mach/id.h
index f1288d10b6ab..02b541a37ee5 100644
--- a/arch/arm/mach-ux500/include/mach/id.h
+++ b/arch/arm/mach-ux500/include/mach/id.h
@@ -75,6 +75,26 @@ static inline bool __attribute_const__ cpu_is_u8500v2(void)
return cpu_is_u8500() && ((dbx500_revision() & 0xf0) == 0xB0);
}
+static inline bool cpu_is_u8500v20(void)
+{
+ return cpu_is_u8500() && (dbx500_revision() == 0xB0);
+}
+
+static inline bool cpu_is_u8500v21(void)
+{
+ return cpu_is_u8500() && (dbx500_revision() == 0xB1);
+}
+
+static inline bool cpu_is_u8500v20_or_later(void)
+{
+ return cpu_is_u8500() && !cpu_is_u8500v10() && !cpu_is_u8500v11();
+}
+
+static inline bool ux500_is_svp(void)
+{
+ return false;
+}
+
#define ux500_unknown_soc() BUG()
#endif
diff --git a/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h b/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h
index 97ef55f84934..47969909836c 100644
--- a/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h
+++ b/arch/arm/mach-ux500/include/mach/irqs-board-mop500.h
@@ -50,6 +50,11 @@
#define MOP500_IRQ_END MOP500_NR_IRQS
+/*
+ * We may have several boards, but only one will run at a
+ * time, so the one with most IRQs will bump this ahead,
+ * but the IRQ_BOARD_START remains the same for either board.
+ */
#if MOP500_IRQ_END > IRQ_BOARD_END
#undef IRQ_BOARD_END
#define IRQ_BOARD_END MOP500_IRQ_END
diff --git a/arch/arm/mach-ux500/include/mach/irqs-board-u5500.h b/arch/arm/mach-ux500/include/mach/irqs-board-u5500.h
new file mode 100644
index 000000000000..29d972c7717b
--- /dev/null
+++ b/arch/arm/mach-ux500/include/mach/irqs-board-u5500.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __MACH_IRQS_BOARD_U5500_H
+#define __MACH_IRQS_BOARD_U5500_H
+
+#define AB5500_NR_IRQS 5
+#define IRQ_AB5500_BASE IRQ_BOARD_START
+#define IRQ_AB5500_END (IRQ_AB5500_BASE + AB5500_NR_IRQS)
+
+#define U5500_IRQ_END IRQ_AB5500_END
+
+#if IRQ_BOARD_END < U5500_IRQ_END
+#undef IRQ_BOARD_END
+#define IRQ_BOARD_END U5500_IRQ_END
+#endif
+
+#endif
diff --git a/arch/arm/mach-ux500/include/mach/irqs-db5500.h b/arch/arm/mach-ux500/include/mach/irqs-db5500.h
index bfa123dbec3b..77239776a6f2 100644
--- a/arch/arm/mach-ux500/include/mach/irqs-db5500.h
+++ b/arch/arm/mach-ux500/include/mach/irqs-db5500.h
@@ -83,4 +83,31 @@
#define IRQ_DB5500_GPIO6 (IRQ_SHPI_START + 125)
#define IRQ_DB5500_GPIO7 (IRQ_SHPI_START + 126)
+#ifdef CONFIG_UX500_SOC_DB5500
+
+/*
+ * After the GPIO ones we reserve a range of IRQ:s in which virtual
+ * IRQ:s representing modem IRQ:s can be allocated
+ */
+#define IRQ_MODEM_EVENTS_BASE IRQ_SOC_START
+#define IRQ_MODEM_EVENTS_NBR 72
+#define IRQ_MODEM_EVENTS_END (IRQ_MODEM_EVENTS_BASE + IRQ_MODEM_EVENTS_NBR)
+
+/* List of virtual IRQ:s that are allocated from the range above */
+#define MBOX_PAIR0_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 43)
+#define MBOX_PAIR1_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 45)
+#define MBOX_PAIR2_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 41)
+
+/*
+ * We may have several SoCs, but only one will run at a
+ * time, so the one with most IRQs will bump this ahead,
+ * but the IRQ_SOC_START remains the same for either SoC.
+ */
+#if IRQ_SOC_END < IRQ_MODEM_EVENTS_END
+#undef IRQ_SOC_END
+#define IRQ_SOC_END IRQ_MODEM_EVENTS_END
+#endif
+
+#endif /* CONFIG_UX500_SOC_DB5500 */
+
#endif
diff --git a/arch/arm/mach-ux500/include/mach/irqs-db8500.h b/arch/arm/mach-ux500/include/mach/irqs-db8500.h
index 8b5d9f0a1633..68bc14974608 100644
--- a/arch/arm/mach-ux500/include/mach/irqs-db8500.h
+++ b/arch/arm/mach-ux500/include/mach/irqs-db8500.h
@@ -93,4 +93,58 @@
#define IRQ_DB8500_GPIO7 (IRQ_SHPI_START + 126)
#define IRQ_DB8500_GPIO8 (IRQ_SHPI_START + 127)
+#define IRQ_CA_WAKE_REQ_ED (IRQ_SHPI_START + 71)
+#define IRQ_AC_READ_NOTIFICATION_0_ED (IRQ_SHPI_START + 66)
+#define IRQ_AC_READ_NOTIFICATION_1_ED (IRQ_SHPI_START + 64)
+#define IRQ_CA_MSG_PEND_NOTIFICATION_0_ED (IRQ_SHPI_START + 67)
+#define IRQ_CA_MSG_PEND_NOTIFICATION_1_ED (IRQ_SHPI_START + 65)
+
+#define IRQ_CA_WAKE_REQ_V1 (IRQ_SHPI_START + 83)
+#define IRQ_AC_READ_NOTIFICATION_0_V1 (IRQ_SHPI_START + 78)
+#define IRQ_AC_READ_NOTIFICATION_1_V1 (IRQ_SHPI_START + 76)
+#define IRQ_CA_MSG_PEND_NOTIFICATION_0_V1 (IRQ_SHPI_START + 79)
+#define IRQ_CA_MSG_PEND_NOTIFICATION_1_V1 (IRQ_SHPI_START + 77)
+
+#ifdef CONFIG_UX500_SOC_DB8500
+
+/* Virtual interrupts corresponding to the PRCMU wakeups. */
+#define IRQ_PRCMU_BASE IRQ_SOC_START
+#define NUM_PRCMU_WAKEUPS (IRQ_PRCMU_END - IRQ_PRCMU_BASE)
+
+#define IRQ_PRCMU_RTC (IRQ_PRCMU_BASE)
+#define IRQ_PRCMU_RTT0 (IRQ_PRCMU_BASE + 1)
+#define IRQ_PRCMU_RTT1 (IRQ_PRCMU_BASE + 2)
+#define IRQ_PRCMU_HSI0 (IRQ_PRCMU_BASE + 3)
+#define IRQ_PRCMU_HSI1 (IRQ_PRCMU_BASE + 4)
+#define IRQ_PRCMU_CA_WAKE (IRQ_PRCMU_BASE + 5)
+#define IRQ_PRCMU_USB (IRQ_PRCMU_BASE + 6)
+#define IRQ_PRCMU_ABB (IRQ_PRCMU_BASE + 7)
+#define IRQ_PRCMU_ABB_FIFO (IRQ_PRCMU_BASE + 8)
+#define IRQ_PRCMU_ARM (IRQ_PRCMU_BASE + 9)
+#define IRQ_PRCMU_MODEM_SW_RESET_REQ (IRQ_PRCMU_BASE + 10)
+#define IRQ_PRCMU_GPIO0 (IRQ_PRCMU_BASE + 11)
+#define IRQ_PRCMU_GPIO1 (IRQ_PRCMU_BASE + 12)
+#define IRQ_PRCMU_GPIO2 (IRQ_PRCMU_BASE + 13)
+#define IRQ_PRCMU_GPIO3 (IRQ_PRCMU_BASE + 14)
+#define IRQ_PRCMU_GPIO4 (IRQ_PRCMU_BASE + 15)
+#define IRQ_PRCMU_GPIO5 (IRQ_PRCMU_BASE + 16)
+#define IRQ_PRCMU_GPIO6 (IRQ_PRCMU_BASE + 17)
+#define IRQ_PRCMU_GPIO7 (IRQ_PRCMU_BASE + 18)
+#define IRQ_PRCMU_GPIO8 (IRQ_PRCMU_BASE + 19)
+#define IRQ_PRCMU_CA_SLEEP (IRQ_PRCMU_BASE + 20)
+#define IRQ_PRCMU_HOTMON_LOW (IRQ_PRCMU_BASE + 21)
+#define IRQ_PRCMU_HOTMON_HIGH (IRQ_PRCMU_BASE + 22)
+#define IRQ_PRCMU_END (IRQ_PRCMU_BASE + 23)
+
+/*
+ * We may have several SoCs, but only one will run at a
+ * time, so the one with most IRQs will bump this ahead,
+ * but the IRQ_SOC_START remains the same for either SoC.
+ */
+#if IRQ_SOC_END < IRQ_PRCMU_END
+#undef IRQ_SOC_END
+#define IRQ_SOC_END IRQ_PRCMU_END
+#endif
+
+#endif /* CONFIG_UX500_SOC_DB8500 */
#endif
diff --git a/arch/arm/mach-ux500/include/mach/irqs.h b/arch/arm/mach-ux500/include/mach/irqs.h
index ba1294c13c4d..9db68d264c5f 100644
--- a/arch/arm/mach-ux500/include/mach/irqs.h
+++ b/arch/arm/mach-ux500/include/mach/irqs.h
@@ -10,49 +10,47 @@
#ifndef ASM_ARCH_IRQS_H
#define ASM_ARCH_IRQS_H
-#include <mach/irqs-db5500.h>
-#include <mach/irqs-db8500.h>
+#include <mach/hardware.h>
-#define IRQ_LOCALTIMER 29
-#define IRQ_LOCALWDOG 30
+#define IRQ_LOCALTIMER 29
+#define IRQ_LOCALWDOG 30
/* Shared Peripheral Interrupt (SHPI) */
#define IRQ_SHPI_START 32
-/* Interrupt numbers generic for shared peripheral */
+/*
+ * MTU0 preserved for now until plat-nomadik is taught not to use it. Don't
+ * add any other IRQs here, use the irqs-dbx500.h files.
+ */
#define IRQ_MTU0 (IRQ_SHPI_START + 4)
-/* There are 128 shared peripheral interrupts assigned to
- * INTID[160:32]. The first 32 interrupts are reserved.
- */
-#define DBX500_NR_INTERNAL_IRQS 161
+#define DBX500_NR_INTERNAL_IRQS 160
/* After chip-specific IRQ numbers we have the GPIO ones */
#define NOMADIK_NR_GPIO 288
#define NOMADIK_GPIO_TO_IRQ(gpio) ((gpio) + DBX500_NR_INTERNAL_IRQS)
#define NOMADIK_IRQ_TO_GPIO(irq) ((irq) - DBX500_NR_INTERNAL_IRQS)
-#define IRQ_BOARD_START NOMADIK_GPIO_TO_IRQ(NOMADIK_NR_GPIO)
+#define IRQ_GPIO_END NOMADIK_GPIO_TO_IRQ(NOMADIK_NR_GPIO)
+
+#define IRQ_SOC_START IRQ_GPIO_END
+/* This will be overridden by SoC-specific irq headers */
+#define IRQ_SOC_END IRQ_SOC_START
+#include <mach/irqs-db5500.h>
+#include <mach/irqs-db8500.h>
+
+#define IRQ_BOARD_START IRQ_SOC_END
/* This will be overridden by board-specific irq headers */
-#define IRQ_BOARD_END IRQ_BOARD_START
+#define IRQ_BOARD_END IRQ_BOARD_START
#ifdef CONFIG_MACH_U8500
#include <mach/irqs-board-mop500.h>
#endif
-/*
- * After the board specific IRQ:s we reserve a range of IRQ:s in which virtual
- * IRQ:s representing modem IRQ:s can be allocated
- */
-#define IRQ_MODEM_EVENTS_BASE (IRQ_BOARD_END + 1)
-#define IRQ_MODEM_EVENTS_NBR 72
-#define IRQ_MODEM_EVENTS_END (IRQ_MODEM_EVENTS_BASE + IRQ_MODEM_EVENTS_NBR)
-
-/* List of virtual IRQ:s that are allocated from the range above */
-#define MBOX_PAIR0_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 43)
-#define MBOX_PAIR1_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 45)
-#define MBOX_PAIR2_VIRT_IRQ (IRQ_MODEM_EVENTS_BASE + 41)
+#ifdef CONFIG_MACH_U5500
+#include <mach/irqs-board-u5500.h>
+#endif
-#define NR_IRQS IRQ_MODEM_EVENTS_END
+#define NR_IRQS IRQ_BOARD_END
#endif /* ASM_ARCH_IRQS_H */
diff --git a/arch/arm/mach-ux500/include/mach/prcmu-defs.h b/arch/arm/mach-ux500/include/mach/prcmu-defs.h
deleted file mode 100644
index 848ba64b561f..000000000000
--- a/arch/arm/mach-ux500/include/mach/prcmu-defs.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) STMicroelectronics 2009
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Sundar Iyer <sundar.iyer@stericsson.com>
- * Author: Martin Persson <martin.persson@stericsson.com>
- *
- * License Terms: GNU General Public License v2
- *
- * PRCM Unit definitions
- */
-
-#ifndef __MACH_PRCMU_DEFS_H
-#define __MACH_PRCMU_DEFS_H
-
-enum prcmu_cpu_opp {
- CPU_OPP_INIT = 0x00,
- CPU_OPP_NO_CHANGE = 0x01,
- CPU_OPP_100 = 0x02,
- CPU_OPP_50 = 0x03,
- CPU_OPP_MAX = 0x04,
- CPU_OPP_EXT_CLK = 0x07
-};
-enum prcmu_ape_opp {
- APE_OPP_NO_CHANGE = 0x00,
- APE_OPP_100 = 0x02,
- APE_OPP_50 = 0x03,
-};
-
-#endif /* __MACH_PRCMU_DEFS_H */
diff --git a/arch/arm/mach-ux500/include/mach/prcmu.h b/arch/arm/mach-ux500/include/mach/prcmu.h
deleted file mode 100644
index c49e456162ef..000000000000
--- a/arch/arm/mach-ux500/include/mach/prcmu.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) STMicroelectronics 2009
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
- * Author: Sundar Iyer <sundar.iyer@stericsson.com>
- * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
- *
- * License Terms: GNU General Public License v2
- *
- * PRCM Unit f/w API
- */
-#ifndef __MACH_PRCMU_H
-#define __MACH_PRCMU_H
-#include <mach/prcmu-defs.h>
-
-void __init prcmu_early_init(void);
-int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
-int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
-int prcmu_set_ape_opp(enum prcmu_ape_opp opp);
-int prcmu_set_cpu_opp(enum prcmu_cpu_opp opp);
-int prcmu_set_ape_cpu_opps(enum prcmu_ape_opp ape_opp,
- enum prcmu_cpu_opp cpu_opp);
-int prcmu_get_ape_opp(void);
-int prcmu_get_cpu_opp(void);
-bool prcmu_has_arm_maxopp(void);
-
-#endif /* __MACH_PRCMU_H */
diff --git a/arch/arm/mach-ux500/include/mach/smp.h b/arch/arm/mach-ux500/include/mach/smp.h
deleted file mode 100644
index ca2b15b1b3b1..000000000000
--- a/arch/arm/mach-ux500/include/mach/smp.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * This file is based ARM realview platform.
- * Copyright (C) ARM Limited.
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-#ifndef ASMARM_ARCH_SMP_H
-#define ASMARM_ARCH_SMP_H
-
-#include <asm/hardware/gic.h>
-
-/* This is required to wakeup the secondary core */
-extern void u8500_secondary_startup(void);
-
-/*
- * We use IRQ1 as the IPI
- */
-static inline void smp_cross_call(const struct cpumask *mask, int ipi)
-{
- gic_raise_softirq(mask, ipi);
-}
-#endif
diff --git a/arch/arm/mach-ux500/include/mach/uncompress.h b/arch/arm/mach-ux500/include/mach/uncompress.h
index ab0fe1432fae..088b550c40df 100644
--- a/arch/arm/mach-ux500/include/mach/uncompress.h
+++ b/arch/arm/mach-ux500/include/mach/uncompress.h
@@ -24,7 +24,7 @@
#include <linux/amba/serial.h>
#include <mach/hardware.h>
-static u32 ux500_uart_base;
+u32 ux500_uart_base;
static void putc(const char c)
{
diff --git a/arch/arm/mach-ux500/mbox-db5500.c b/arch/arm/mach-ux500/mbox-db5500.c
index a4ffb9f4f461..2b2d51caf9d8 100644
--- a/arch/arm/mach-ux500/mbox-db5500.c
+++ b/arch/arm/mach-ux500/mbox-db5500.c
@@ -416,8 +416,7 @@ struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv)
dev_dbg(&(mbox->pdev->dev),
"Resource name: %s start: 0x%X, end: 0x%X\n",
resource->name, resource->start, resource->end);
- mbox->virtbase_peer =
- ioremap(resource->start, resource->end - resource->start);
+ mbox->virtbase_peer = ioremap(resource->start, resource_size(resource));
if (!mbox->virtbase_peer) {
dev_err(&(mbox->pdev->dev), "Unable to ioremap peer mbox\n");
mbox = NULL;
@@ -440,8 +439,7 @@ struct mbox *mbox_setup(u8 mbox_id, mbox_recv_cb_t *mbox_cb, void *priv)
dev_dbg(&(mbox->pdev->dev),
"Resource name: %s start: 0x%X, end: 0x%X\n",
resource->name, resource->start, resource->end);
- mbox->virtbase_local =
- ioremap(resource->start, resource->end - resource->start);
+ mbox->virtbase_local = ioremap(resource->start, resource_size(resource));
if (!mbox->virtbase_local) {
dev_err(&(mbox->pdev->dev), "Unable to ioremap local mbox\n");
mbox = NULL;
diff --git a/arch/arm/mach-ux500/platsmp.c b/arch/arm/mach-ux500/platsmp.c
index 4fff4d408417..0c527fe2cebb 100644
--- a/arch/arm/mach-ux500/platsmp.c
+++ b/arch/arm/mach-ux500/platsmp.c
@@ -18,10 +18,14 @@
#include <linux/io.h>
#include <asm/cacheflush.h>
+#include <asm/hardware/gic.h>
#include <asm/smp_scu.h>
#include <mach/hardware.h>
#include <mach/setup.h>
+/* This is called from headsmp.S to wakeup the secondary core */
+extern void u8500_secondary_startup(void);
+
/*
* control for which core is the next to come out of the secondary
* boot "holding pen"
@@ -94,7 +98,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
*/
write_pen_release(cpu);
- smp_cross_call(cpumask_of(cpu), 1);
+ gic_raise_softirq(cpumask_of(cpu), 1);
timeout = jiffies + (1 * HZ);
while (time_before(jiffies, timeout)) {
@@ -162,6 +166,8 @@ void __init smp_init_cpus(void)
for (i = 0; i < ncores; i++)
set_cpu_possible(i, true);
+
+ set_smp_cross_call(gic_raise_softirq);
}
void __init platform_smp_prepare_cpus(unsigned int max_cpus)
diff --git a/arch/arm/mach-ux500/prcmu.c b/arch/arm/mach-ux500/prcmu.c
deleted file mode 100644
index c522d26ef348..000000000000
--- a/arch/arm/mach-ux500/prcmu.c
+++ /dev/null
@@ -1,394 +0,0 @@
-/*
- * Copyright (C) STMicroelectronics 2009
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License Terms: GNU General Public License v2
- * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
- * Author: Sundar Iyer <sundar.iyer@stericsson.com>
- * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
- *
- * U8500 PRCM Unit interface driver
- *
- */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/mutex.h>
-#include <linux/completion.h>
-#include <linux/jiffies.h>
-#include <linux/bitops.h>
-#include <linux/interrupt.h>
-
-#include <mach/hardware.h>
-#include <mach/prcmu-regs.h>
-#include <mach/prcmu-defs.h>
-
-/* Global var to runtime determine TCDM base for v2 or v1 */
-static __iomem void *tcdm_base;
-
-#define _MBOX_HEADER (tcdm_base + 0xFE8)
-#define MBOX_HEADER_REQ_MB0 (_MBOX_HEADER + 0x0)
-
-#define REQ_MB1 (tcdm_base + 0xFD0)
-#define REQ_MB5 (tcdm_base + 0xE44)
-
-#define REQ_MB1_ARMOPP (REQ_MB1 + 0x0)
-#define REQ_MB1_APEOPP (REQ_MB1 + 0x1)
-#define REQ_MB1_BOOSTOPP (REQ_MB1 + 0x2)
-
-#define ACK_MB1 (tcdm_base + 0xE04)
-#define ACK_MB5 (tcdm_base + 0xDF4)
-
-#define ACK_MB1_CURR_ARMOPP (ACK_MB1 + 0x0)
-#define ACK_MB1_CURR_APEOPP (ACK_MB1 + 0x1)
-
-#define REQ_MB5_I2C_SLAVE_OP (REQ_MB5)
-#define REQ_MB5_I2C_HW_BITS (REQ_MB5 + 1)
-#define REQ_MB5_I2C_REG (REQ_MB5 + 2)
-#define REQ_MB5_I2C_VAL (REQ_MB5 + 3)
-
-#define ACK_MB5_I2C_STATUS (ACK_MB5 + 1)
-#define ACK_MB5_I2C_VAL (ACK_MB5 + 3)
-
-#define PRCM_AVS_VARM_MAX_OPP (tcdm_base + 0x2E4)
-#define PRCM_AVS_ISMODEENABLE 7
-#define PRCM_AVS_ISMODEENABLE_MASK (1 << PRCM_AVS_ISMODEENABLE)
-
-#define I2C_WRITE(slave) \
- (((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0))
-#define I2C_READ(slave) \
- (((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0) | BIT(0))
-#define I2C_STOP_EN BIT(3)
-
-enum mb1_h {
- MB1H_ARM_OPP = 1,
- MB1H_APE_OPP,
- MB1H_ARM_APE_OPP,
-};
-
-static struct {
- struct mutex lock;
- struct completion work;
- struct {
- u8 arm_opp;
- u8 ape_opp;
- u8 arm_status;
- u8 ape_status;
- } ack;
-} mb1_transfer;
-
-enum ack_mb5_status {
- I2C_WR_OK = 0x01,
- I2C_RD_OK = 0x02,
-};
-
-#define MBOX_BIT BIT
-#define NUM_MBOX 8
-
-static struct {
- struct mutex lock;
- struct completion work;
- bool failed;
- struct {
- u8 status;
- u8 value;
- } ack;
-} mb5_transfer;
-
-/**
- * prcmu_abb_read() - Read register value(s) from the ABB.
- * @slave: The I2C slave address.
- * @reg: The (start) register address.
- * @value: The read out value(s).
- * @size: The number of registers to read.
- *
- * Reads register value(s) from the ABB.
- * @size has to be 1 for the current firmware version.
- */
-int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
-{
- int r;
-
- if (size != 1)
- return -EINVAL;
-
- r = mutex_lock_interruptible(&mb5_transfer.lock);
- if (r)
- return r;
-
- while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
- cpu_relax();
-
- writeb(I2C_READ(slave), REQ_MB5_I2C_SLAVE_OP);
- writeb(I2C_STOP_EN, REQ_MB5_I2C_HW_BITS);
- writeb(reg, REQ_MB5_I2C_REG);
-
- writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
- if (!wait_for_completion_timeout(&mb5_transfer.work,
- msecs_to_jiffies(500))) {
- pr_err("prcmu: prcmu_abb_read timed out.\n");
- r = -EIO;
- goto unlock_and_return;
- }
- r = ((mb5_transfer.ack.status == I2C_RD_OK) ? 0 : -EIO);
- if (!r)
- *value = mb5_transfer.ack.value;
-
-unlock_and_return:
- mutex_unlock(&mb5_transfer.lock);
- return r;
-}
-EXPORT_SYMBOL(prcmu_abb_read);
-
-/**
- * prcmu_abb_write() - Write register value(s) to the ABB.
- * @slave: The I2C slave address.
- * @reg: The (start) register address.
- * @value: The value(s) to write.
- * @size: The number of registers to write.
- *
- * Reads register value(s) from the ABB.
- * @size has to be 1 for the current firmware version.
- */
-int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
-{
- int r;
-
- if (size != 1)
- return -EINVAL;
-
- r = mutex_lock_interruptible(&mb5_transfer.lock);
- if (r)
- return r;
-
-
- while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
- cpu_relax();
-
- writeb(I2C_WRITE(slave), REQ_MB5_I2C_SLAVE_OP);
- writeb(I2C_STOP_EN, REQ_MB5_I2C_HW_BITS);
- writeb(reg, REQ_MB5_I2C_REG);
- writeb(*value, REQ_MB5_I2C_VAL);
-
- writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
- if (!wait_for_completion_timeout(&mb5_transfer.work,
- msecs_to_jiffies(500))) {
- pr_err("prcmu: prcmu_abb_write timed out.\n");
- r = -EIO;
- goto unlock_and_return;
- }
- r = ((mb5_transfer.ack.status == I2C_WR_OK) ? 0 : -EIO);
-
-unlock_and_return:
- mutex_unlock(&mb5_transfer.lock);
- return r;
-}
-EXPORT_SYMBOL(prcmu_abb_write);
-
-static int set_ape_cpu_opps(u8 header, enum prcmu_ape_opp ape_opp,
- enum prcmu_cpu_opp cpu_opp)
-{
- bool do_ape;
- bool do_arm;
- int err = 0;
-
- do_ape = ((header == MB1H_APE_OPP) || (header == MB1H_ARM_APE_OPP));
- do_arm = ((header == MB1H_ARM_OPP) || (header == MB1H_ARM_APE_OPP));
-
- mutex_lock(&mb1_transfer.lock);
-
- while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
- cpu_relax();
-
- writeb(0, MBOX_HEADER_REQ_MB0);
- writeb(cpu_opp, REQ_MB1_ARMOPP);
- writeb(ape_opp, REQ_MB1_APEOPP);
- writeb(0, REQ_MB1_BOOSTOPP);
- writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
- wait_for_completion(&mb1_transfer.work);
- if ((do_ape) && (mb1_transfer.ack.ape_status != 0))
- err = -EIO;
- if ((do_arm) && (mb1_transfer.ack.arm_status != 0))
- err = -EIO;
-
- mutex_unlock(&mb1_transfer.lock);
-
- return err;
-}
-
-/**
- * prcmu_set_ape_opp() - Set the OPP of the APE.
- * @opp: The OPP to set.
- *
- * This function sets the OPP of the APE.
- */
-int prcmu_set_ape_opp(enum prcmu_ape_opp opp)
-{
- return set_ape_cpu_opps(MB1H_APE_OPP, opp, APE_OPP_NO_CHANGE);
-}
-EXPORT_SYMBOL(prcmu_set_ape_opp);
-
-/**
- * prcmu_set_cpu_opp() - Set the OPP of the CPU.
- * @opp: The OPP to set.
- *
- * This function sets the OPP of the CPU.
- */
-int prcmu_set_cpu_opp(enum prcmu_cpu_opp opp)
-{
- return set_ape_cpu_opps(MB1H_ARM_OPP, CPU_OPP_NO_CHANGE, opp);
-}
-EXPORT_SYMBOL(prcmu_set_cpu_opp);
-
-/**
- * prcmu_set_ape_cpu_opps() - Set the OPPs of the APE and the CPU.
- * @ape_opp: The APE OPP to set.
- * @cpu_opp: The CPU OPP to set.
- *
- * This function sets the OPPs of the APE and the CPU.
- */
-int prcmu_set_ape_cpu_opps(enum prcmu_ape_opp ape_opp,
- enum prcmu_cpu_opp cpu_opp)
-{
- return set_ape_cpu_opps(MB1H_ARM_APE_OPP, ape_opp, cpu_opp);
-}
-EXPORT_SYMBOL(prcmu_set_ape_cpu_opps);
-
-/**
- * prcmu_get_ape_opp() - Get the OPP of the APE.
- *
- * This function gets the OPP of the APE.
- */
-enum prcmu_ape_opp prcmu_get_ape_opp(void)
-{
- return readb(ACK_MB1_CURR_APEOPP);
-}
-EXPORT_SYMBOL(prcmu_get_ape_opp);
-
-/**
- * prcmu_get_cpu_opp() - Get the OPP of the CPU.
- *
- * This function gets the OPP of the CPU. The OPP is specified in %%.
- * PRCMU_OPP_EXT is a special OPP value, not specified in %%.
- */
-int prcmu_get_cpu_opp(void)
-{
- return readb(ACK_MB1_CURR_ARMOPP);
-}
-EXPORT_SYMBOL(prcmu_get_cpu_opp);
-
-bool prcmu_has_arm_maxopp(void)
-{
- return (readb(PRCM_AVS_VARM_MAX_OPP) & PRCM_AVS_ISMODEENABLE_MASK)
- == PRCM_AVS_ISMODEENABLE_MASK;
-}
-
-static void read_mailbox_0(void)
-{
- writel(MBOX_BIT(0), PRCM_ARM_IT1_CLEAR);
-}
-
-static void read_mailbox_1(void)
-{
- mb1_transfer.ack.arm_opp = readb(ACK_MB1_CURR_ARMOPP);
- mb1_transfer.ack.ape_opp = readb(ACK_MB1_CURR_APEOPP);
- complete(&mb1_transfer.work);
- writel(MBOX_BIT(1), PRCM_ARM_IT1_CLEAR);
-}
-
-static void read_mailbox_2(void)
-{
- writel(MBOX_BIT(2), PRCM_ARM_IT1_CLEAR);
-}
-
-static void read_mailbox_3(void)
-{
- writel(MBOX_BIT(3), PRCM_ARM_IT1_CLEAR);
-}
-
-static void read_mailbox_4(void)
-{
- writel(MBOX_BIT(4), PRCM_ARM_IT1_CLEAR);
-}
-
-static void read_mailbox_5(void)
-{
- mb5_transfer.ack.status = readb(ACK_MB5_I2C_STATUS);
- mb5_transfer.ack.value = readb(ACK_MB5_I2C_VAL);
- complete(&mb5_transfer.work);
- writel(MBOX_BIT(5), PRCM_ARM_IT1_CLEAR);
-}
-
-static void read_mailbox_6(void)
-{
- writel(MBOX_BIT(6), PRCM_ARM_IT1_CLEAR);
-}
-
-static void read_mailbox_7(void)
-{
- writel(MBOX_BIT(7), PRCM_ARM_IT1_CLEAR);
-}
-
-static void (* const read_mailbox[NUM_MBOX])(void) = {
- read_mailbox_0,
- read_mailbox_1,
- read_mailbox_2,
- read_mailbox_3,
- read_mailbox_4,
- read_mailbox_5,
- read_mailbox_6,
- read_mailbox_7
-};
-
-static irqreturn_t prcmu_irq_handler(int irq, void *data)
-{
- u32 bits;
- u8 n;
-
- bits = (readl(PRCM_ARM_IT1_VAL) & (MBOX_BIT(NUM_MBOX) - 1));
- if (unlikely(!bits))
- return IRQ_NONE;
-
- for (n = 0; bits; n++) {
- if (bits & MBOX_BIT(n)) {
- bits -= MBOX_BIT(n);
- read_mailbox[n]();
- }
- }
- return IRQ_HANDLED;
-}
-
-void __init prcmu_early_init(void)
-{
- if (cpu_is_u8500v11() || cpu_is_u8500ed()) {
- tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE_V1);
- } else if (cpu_is_u8500v2()) {
- tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE);
- } else {
- pr_err("prcmu: Unsupported chip version\n");
- BUG();
- }
-}
-
-static int __init prcmu_init(void)
-{
- if (cpu_is_u8500ed()) {
- pr_err("prcmu: Unsupported chip version\n");
- return 0;
- }
-
- mutex_init(&mb1_transfer.lock);
- init_completion(&mb1_transfer.work);
- mutex_init(&mb5_transfer.lock);
- init_completion(&mb5_transfer.work);
-
- /* Clean up the mailbox interrupts after pre-kernel code. */
- writel((MBOX_BIT(NUM_MBOX) - 1), PRCM_ARM_IT1_CLEAR);
-
- return request_irq(IRQ_DB8500_PRCMU1, prcmu_irq_handler, 0,
- "prcmu", NULL);
-}
-
-arch_initcall(prcmu_init);
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index eb7ffa0ee8b5..0c99cf076c63 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -32,6 +32,7 @@
#include <linux/io.h>
#include <linux/gfp.h>
#include <linux/clkdev.h>
+#include <linux/mtd/physmap.h>
#include <asm/system.h>
#include <asm/irq.h>
@@ -42,7 +43,6 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
#include <asm/mach/irq.h>
#include <asm/mach/time.h>
#include <asm/mach/map.h>
@@ -190,27 +190,7 @@ void __init versatile_map_io(void)
#define VERSATILE_FLASHCTRL (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_FLASH_OFFSET)
-static int versatile_flash_init(void)
-{
- u32 val;
-
- val = __raw_readl(VERSATILE_FLASHCTRL);
- val &= ~VERSATILE_FLASHPROG_FLVPPEN;
- __raw_writel(val, VERSATILE_FLASHCTRL);
-
- return 0;
-}
-
-static void versatile_flash_exit(void)
-{
- u32 val;
-
- val = __raw_readl(VERSATILE_FLASHCTRL);
- val &= ~VERSATILE_FLASHPROG_FLVPPEN;
- __raw_writel(val, VERSATILE_FLASHCTRL);
-}
-
-static void versatile_flash_set_vpp(int on)
+static void versatile_flash_set_vpp(struct platform_device *pdev, int on)
{
u32 val;
@@ -222,11 +202,8 @@ static void versatile_flash_set_vpp(int on)
__raw_writel(val, VERSATILE_FLASHCTRL);
}
-static struct flash_platform_data versatile_flash_data = {
- .map_name = "cfi_probe",
+static struct physmap_flash_data versatile_flash_data = {
.width = 4,
- .init = versatile_flash_init,
- .exit = versatile_flash_exit,
.set_vpp = versatile_flash_set_vpp,
};
@@ -237,7 +214,7 @@ static struct resource versatile_flash_resource = {
};
static struct platform_device versatile_flash_device = {
- .name = "armflash",
+ .name = "physmap-flash",
.id = 0,
.dev = {
.platform_data = &versatile_flash_data,
@@ -375,6 +352,10 @@ static struct clk ref24_clk = {
.rate = 24000000,
};
+static struct clk sp804_clk = {
+ .rate = 1000000,
+};
+
static struct clk dummy_apb_pclk;
static struct clk_lookup lookups[] = {
@@ -411,7 +392,10 @@ static struct clk_lookup lookups[] = {
}, { /* CLCD */
.dev_id = "dev:20",
.clk = &osc4_clk,
- }
+ }, { /* SP804 timers */
+ .dev_id = "sp804",
+ .clk = &sp804_clk,
+ },
};
/*
@@ -764,8 +748,8 @@ static void __init versatile_timer_init(void)
writel(0, TIMER2_VA_BASE + TIMER_CTRL);
writel(0, TIMER3_VA_BASE + TIMER_CTRL);
- sp804_clocksource_init(TIMER3_VA_BASE);
- sp804_clockevents_init(TIMER0_VA_BASE, IRQ_TIMERINT0_1);
+ sp804_clocksource_init(TIMER3_VA_BASE, "timer3");
+ sp804_clockevents_init(TIMER0_VA_BASE, IRQ_TIMERINT0_1, "timer0");
}
struct sys_timer versatile_timer = {
diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c
index ebc22e759325..765a71ff7f3b 100644
--- a/arch/arm/mach-vexpress/ct-ca9x4.c
+++ b/arch/arm/mach-vexpress/ct-ca9x4.c
@@ -71,8 +71,9 @@ static void __init ct_ca9x4_timer_init(void)
writel(0, MMIO_P2V(CT_CA9X4_TIMER0) + TIMER_CTRL);
writel(0, MMIO_P2V(CT_CA9X4_TIMER1) + TIMER_CTRL);
- sp804_clocksource_init(MMIO_P2V(CT_CA9X4_TIMER1));
- sp804_clockevents_init(MMIO_P2V(CT_CA9X4_TIMER0), IRQ_CT_CA9X4_TIMER0);
+ sp804_clocksource_init(MMIO_P2V(CT_CA9X4_TIMER1), "ct-timer1");
+ sp804_clockevents_init(MMIO_P2V(CT_CA9X4_TIMER0), IRQ_CT_CA9X4_TIMER0,
+ "ct-timer0");
}
static struct sys_timer ct_ca9x4_timer = {
@@ -141,10 +142,22 @@ static struct clk osc1_clk = {
.rate = 24000000,
};
+static struct clk ct_sp804_clk = {
+ .rate = 1000000,
+};
+
static struct clk_lookup lookups[] = {
{ /* CLCD */
.dev_id = "ct:clcd",
.clk = &osc1_clk,
+ }, { /* SP804 timers */
+ .dev_id = "sp804",
+ .con_id = "ct-timer0",
+ .clk = &ct_sp804_clk,
+ }, { /* SP804 timers */
+ .dev_id = "sp804",
+ .con_id = "ct-timer1",
+ .clk = &ct_sp804_clk,
},
};
@@ -210,6 +223,8 @@ static void ct_ca9x4_init_cpu_map(void)
for (i = 0; i < ncores; ++i)
set_cpu_possible(i, true);
+
+ set_smp_cross_call(gic_raise_softirq);
}
static void ct_ca9x4_smp_enable(unsigned int max_cpus)
diff --git a/arch/arm/mach-vexpress/include/mach/smp.h b/arch/arm/mach-vexpress/include/mach/smp.h
deleted file mode 100644
index 4c05e4a9713a..000000000000
--- a/arch/arm/mach-vexpress/include/mach/smp.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef __MACH_SMP_H
-#define __MACH_SMP_H
-
-#include <asm/hardware/gic.h>
-
-/*
- * We use IRQ1 as the IPI
- */
-static inline void smp_cross_call(const struct cpumask *mask, int ipi)
-{
- gic_raise_softirq(mask, ipi);
-}
-#endif
diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c
index ba46e8e07437..285edcd2da2a 100644
--- a/arch/arm/mach-vexpress/v2m.c
+++ b/arch/arm/mach-vexpress/v2m.c
@@ -13,11 +13,11 @@
#include <linux/sysdev.h>
#include <linux/usb/isp1760.h>
#include <linux/clkdev.h>
+#include <linux/mtd/physmap.h>
#include <asm/mach-types.h>
#include <asm/sizes.h>
#include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
#include <asm/hardware/arm_timer.h>
@@ -65,8 +65,9 @@ static void __init v2m_timer_init(void)
writel(0, MMIO_P2V(V2M_TIMER0) + TIMER_CTRL);
writel(0, MMIO_P2V(V2M_TIMER1) + TIMER_CTRL);
- sp804_clocksource_init(MMIO_P2V(V2M_TIMER1));
- sp804_clockevents_init(MMIO_P2V(V2M_TIMER0), IRQ_V2M_TIMER0);
+ sp804_clocksource_init(MMIO_P2V(V2M_TIMER1), "v2m-timer1");
+ sp804_clockevents_init(MMIO_P2V(V2M_TIMER0), IRQ_V2M_TIMER0,
+ "v2m-timer0");
}
static struct sys_timer v2m_timer = {
@@ -206,27 +207,13 @@ static struct platform_device v2m_usb_device = {
.dev.platform_data = &v2m_usb_config,
};
-static int v2m_flash_init(void)
-{
- writel(0, MMIO_P2V(V2M_SYS_FLASH));
- return 0;
-}
-
-static void v2m_flash_exit(void)
-{
- writel(0, MMIO_P2V(V2M_SYS_FLASH));
-}
-
-static void v2m_flash_set_vpp(int on)
+static void v2m_flash_set_vpp(struct platform_device *pdev, int on)
{
writel(on != 0, MMIO_P2V(V2M_SYS_FLASH));
}
-static struct flash_platform_data v2m_flash_data = {
- .map_name = "cfi_probe",
+static struct physmap_flash_data v2m_flash_data = {
.width = 4,
- .init = v2m_flash_init,
- .exit = v2m_flash_exit,
.set_vpp = v2m_flash_set_vpp,
};
@@ -243,7 +230,7 @@ static struct resource v2m_flash_resources[] = {
};
static struct platform_device v2m_flash_device = {
- .name = "armflash",
+ .name = "physmap-flash",
.id = -1,
.resource = v2m_flash_resources,
.num_resources = ARRAY_SIZE(v2m_flash_resources),
@@ -333,6 +320,10 @@ static struct clk osc2_clk = {
.rate = 24000000,
};
+static struct clk v2m_sp804_clk = {
+ .rate = 1000000,
+};
+
static struct clk dummy_apb_pclk;
static struct clk_lookup v2m_lookups[] = {
@@ -363,6 +354,14 @@ static struct clk_lookup v2m_lookups[] = {
}, { /* CLCD */
.dev_id = "mb:clcd",
.clk = &osc1_clk,
+ }, { /* SP804 timers */
+ .dev_id = "sp804",
+ .con_id = "v2m-timer0",
+ .clk = &v2m_sp804_clk,
+ }, { /* SP804 timers */
+ .dev_id = "sp804",
+ .con_id = "v2m-timer1",
+ .clk = &v2m_sp804_clk,
},
};
diff --git a/arch/arm/mach-w90x900/include/mach/uncompress.h b/arch/arm/mach-w90x900/include/mach/uncompress.h
index 56f1a74d7016..03130212ace2 100644
--- a/arch/arm/mach-w90x900/include/mach/uncompress.h
+++ b/arch/arm/mach-w90x900/include/mach/uncompress.h
@@ -27,7 +27,7 @@
#define arch_decomp_wdog()
#define TX_DONE (UART_LSR_TEMT | UART_LSR_THRE)
-static volatile u32 * uart_base = (u32 *)UART0_PA;
+static volatile u32 * const uart_base = (u32 *)UART0_PA;
static void putc(int ch)
{
diff --git a/arch/arm/mach-w90x900/time.c b/arch/arm/mach-w90x900/time.c
index 4b089cb930dc..a2c4e2d0a0d4 100644
--- a/arch/arm/mach-w90x900/time.c
+++ b/arch/arm/mach-w90x900/time.c
@@ -43,7 +43,6 @@
#define PRESCALE 0x63 /* Divider = prescale + 1 */
#define TDR_SHIFT 24
-#define TDR_MASK ((1 << TDR_SHIFT) - 1)
static unsigned int timer0_load;
@@ -143,19 +142,6 @@ static void __init nuc900_clockevents_init(void)
clockevents_register_device(&nuc900_clockevent_device);
}
-static cycle_t nuc900_get_cycles(struct clocksource *cs)
-{
- return (~__raw_readl(REG_TDR1)) & TDR_MASK;
-}
-
-static struct clocksource clocksource_nuc900 = {
- .name = "nuc900-timer1",
- .rating = 200,
- .read = nuc900_get_cycles,
- .mask = CLOCKSOURCE_MASK(TDR_SHIFT),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
static void __init nuc900_clocksource_init(void)
{
unsigned int val;
@@ -175,7 +161,8 @@ static void __init nuc900_clocksource_init(void)
val |= (COUNTEN | PERIOD | PRESCALE);
__raw_writel(val, REG_TCSR1);
- clocksource_register_hz(&clocksource_nuc900, rate);
+ clocksource_mmio_init(REG_TDR1, "nuc900-timer1", rate, 200,
+ TDR_SHIFT, clocksource_mmio_readl_down);
}
static void __init nuc900_timer_init(void)
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
index 2b269c955524..1a8d4aa821be 100644
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -253,8 +253,8 @@ void __sync_icache_dcache(pte_t pteval)
if (!test_and_set_bit(PG_dcache_clean, &page->flags))
__flush_dcache_page(mapping, page);
- /* pte_exec() already checked above for non-aliasing VIPT cache */
- if (cache_is_vipt_nonaliasing() || pte_exec(pteval))
+
+ if (pte_exec(pteval))
__flush_icache_all();
}
#endif
@@ -275,7 +275,8 @@ void __sync_icache_dcache(pte_t pteval)
* kernel cache lines for later. Otherwise, we assume we have
* aliasing mappings.
*
- * Note that we disable the lazy flush for SMP.
+ * Note that we disable the lazy flush for SMP configurations where
+ * the cache maintenance operations are not automatically broadcasted.
*/
void flush_dcache_page(struct page *page)
{
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index e591513bb53e..3f17ea146f0e 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -85,7 +85,7 @@ void show_mem(unsigned int filter)
struct meminfo * mi = &meminfo;
printk("Mem-info:\n");
- show_free_areas();
+ show_free_areas(filter);
for_each_bank (i, mi) {
struct membank *bank = &mi->bank[i];
@@ -201,6 +201,20 @@ static void __init arm_bootmem_init(unsigned long start_pfn,
}
}
+#ifdef CONFIG_ZONE_DMA
+static void __init arm_adjust_dma_zone(unsigned long *size, unsigned long *hole,
+ unsigned long dma_size)
+{
+ if (size[0] <= dma_size)
+ return;
+
+ size[ZONE_NORMAL] = size[0] - dma_size;
+ size[ZONE_DMA] = dma_size;
+ hole[ZONE_NORMAL] = hole[0];
+ hole[ZONE_DMA] = 0;
+}
+#endif
+
static void __init arm_bootmem_free(unsigned long min, unsigned long max_low,
unsigned long max_high)
{
@@ -243,11 +257,18 @@ static void __init arm_bootmem_free(unsigned long min, unsigned long max_low,
#endif
}
+#ifdef ARM_DMA_ZONE_SIZE
+#ifndef CONFIG_ZONE_DMA
+#error ARM_DMA_ZONE_SIZE set but no DMA zone to limit allocations
+#endif
+
/*
* Adjust the sizes according to any special requirements for
* this machine type.
*/
- arch_adjust_zones(zone_size, zhole_size);
+ arm_adjust_dma_zone(zone_size, zhole_size,
+ ARM_DMA_ZONE_SIZE >> PAGE_SHIFT);
+#endif
free_area_init_node(0, zone_size, min, zhole_size);
}
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 6cf76b3b68d1..08a92368d9d3 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -31,8 +31,6 @@
#include "mm.h"
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
/*
* empty_zero_page is a special page that is used for
* zero-initialized data and COW.
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
index 7c99cb4c8e4f..ab17cc0d3fa7 100644
--- a/arch/arm/mm/proc-v6.S
+++ b/arch/arm/mm/proc-v6.S
@@ -175,11 +175,6 @@ cpu_v6_name:
.asciz "ARMv6-compatible processor"
.size cpu_v6_name, . - cpu_v6_name
- .type cpu_pj4_name, #object
-cpu_pj4_name:
- .asciz "Marvell PJ4 processor"
- .size cpu_pj4_name, . - cpu_pj4_name
-
.align
__CPUINIT
@@ -305,32 +300,3 @@ __v6_proc_info:
.long v6_user_fns
.long v6_cache_fns
.size __v6_proc_info, . - __v6_proc_info
-
- .type __pj4_v6_proc_info, #object
-__pj4_v6_proc_info:
- .long 0x560f5810
- .long 0xff0ffff0
- ALT_SMP(.long \
- PMD_TYPE_SECT | \
- PMD_SECT_AP_WRITE | \
- PMD_SECT_AP_READ | \
- PMD_FLAGS_SMP)
- ALT_UP(.long \
- PMD_TYPE_SECT | \
- PMD_SECT_AP_WRITE | \
- PMD_SECT_AP_READ | \
- PMD_FLAGS_UP)
- .long PMD_TYPE_SECT | \
- PMD_SECT_XN | \
- PMD_SECT_AP_WRITE | \
- PMD_SECT_AP_READ
- b __v6_setup
- .long cpu_arch_name
- .long cpu_elf_name
- .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP|HWCAP_TLS
- .long cpu_pj4_name
- .long v6_processor_functions
- .long v6wbi_tlb_fns
- .long v6_user_fns
- .long v6_cache_fns
- .size __pj4_v6_proc_info, . - __pj4_v6_proc_info
diff --git a/arch/arm/plat-iop/time.c b/arch/arm/plat-iop/time.c
index 07f23bb42bed..7cdc5161ff2b 100644
--- a/arch/arm/plat-iop/time.c
+++ b/arch/arm/plat-iop/time.c
@@ -17,7 +17,6 @@
#include <linux/interrupt.h>
#include <linux/time.h>
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/timex.h>
#include <linux/sched.h>
#include <linux/io.h>
diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig
index b0cb4258e382..a5353fc0793f 100644
--- a/arch/arm/plat-mxc/Kconfig
+++ b/arch/arm/plat-mxc/Kconfig
@@ -4,13 +4,18 @@ source "arch/arm/plat-mxc/devices/Kconfig"
menu "Freescale MXC Implementations"
+config ARCH_MX50_SUPPORTED
+ bool
+
+config ARCH_MX53_SUPPORTED
+ bool
+
choice
prompt "Freescale CPU family:"
default ARCH_MX3
config ARCH_MX1
bool "MX1-based"
- select SOC_IMX1
help
This enables support for systems based on the Freescale i.MX1 family
@@ -26,29 +31,26 @@ config ARCH_MX25
config ARCH_MX3
bool "MX3-based"
- select CPU_V6
help
This enables support for systems based on the Freescale i.MX3 family
-config ARCH_MXC91231
- bool "MXC91231-based"
- select CPU_V6
- select MXC_AVIC
+config ARCH_MX503
+ bool "i.MX50 + i.MX53"
+ select ARCH_MX50_SUPPORTED
+ select ARCH_MX53_SUPPORTED
help
- This enables support for systems based on the Freescale MXC91231 family
+ This enables support for machines using Freescale's i.MX50 and i.MX51
+ processors.
-config ARCH_MX5
- bool "MX5-based"
- select CPU_V7
- select ARM_L1_CACHE_SHIFT_6
+config ARCH_MX51
+ bool "i.MX51"
+ select ARCH_MX51_SUPPORTED
help
This enables support for systems based on the Freescale i.MX51 family
endchoice
source "arch/arm/mach-imx/Kconfig"
-source "arch/arm/mach-mx3/Kconfig"
-source "arch/arm/mach-mxc91231/Kconfig"
source "arch/arm/mach-mx5/Kconfig"
endmenu
diff --git a/arch/arm/plat-mxc/cpufreq.c b/arch/arm/plat-mxc/cpufreq.c
index 4268a2bdf145..74aac96cda20 100644
--- a/arch/arm/plat-mxc/cpufreq.c
+++ b/arch/arm/plat-mxc/cpufreq.c
@@ -153,8 +153,8 @@ static int __init mxc_cpufreq_init(struct cpufreq_policy *policy)
ret = cpufreq_frequency_table_cpuinfo(policy, imx_freq_table);
if (ret < 0) {
- printk(KERN_ERR "%s: failed to register i.MXC CPUfreq \
- with error code %d\n", __func__, ret);
+ printk(KERN_ERR "%s: failed to register i.MXC CPUfreq with error code %d\n",
+ __func__, ret);
goto err;
}
diff --git a/arch/arm/plat-mxc/devices/Kconfig b/arch/arm/plat-mxc/devices/Kconfig
index b9ab1d58b5e7..bd294add932c 100644
--- a/arch/arm/plat-mxc/devices/Kconfig
+++ b/arch/arm/plat-mxc/devices/Kconfig
@@ -24,7 +24,6 @@ config IMX_HAVE_PLATFORM_IMXDI_RTC
config IMX_HAVE_PLATFORM_IMX_FB
bool
- select HAVE_FB_IMX
config IMX_HAVE_PLATFORM_IMX_I2C
bool
@@ -41,6 +40,9 @@ config IMX_HAVE_PLATFORM_IMX_UART
config IMX_HAVE_PLATFORM_IMX_UDC
bool
+config IMX_HAVE_PLATFORM_IPU_CORE
+ bool
+
config IMX_HAVE_PLATFORM_MX1_CAMERA
bool
@@ -63,6 +65,9 @@ config IMX_HAVE_PLATFORM_MXC_RNGA
bool
select ARCH_HAS_RNGA
+config IMX_HAVE_PLATFORM_MXC_RTC
+ bool
+
config IMX_HAVE_PLATFORM_MXC_W1
bool
diff --git a/arch/arm/plat-mxc/devices/Makefile b/arch/arm/plat-mxc/devices/Makefile
index 75cd2ece9053..ad2922acf480 100644
--- a/arch/arm/plat-mxc/devices/Makefile
+++ b/arch/arm/plat-mxc/devices/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_KEYPAD) += platform-imx-keypad.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_SSI) += platform-imx-ssi.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_UART) += platform-imx-uart.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_UDC) += platform-imx_udc.o
+obj-$(CONFIG_IMX_HAVE_PLATFORM_IPU_CORE) += platform-ipu-core.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_MX1_CAMERA) += platform-mx1-camera.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_MX2_CAMERA) += platform-mx2-camera.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_EHCI) += platform-mxc-ehci.o
@@ -19,6 +20,7 @@ obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_MMC) += platform-mxc-mmc.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_NAND) += platform-mxc_nand.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_PWM) += platform-mxc_pwm.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_RNGA) += platform-mxc_rnga.o
+obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_RTC) += platform-mxc_rtc.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_W1) += platform-mxc_w1.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX) += platform-sdhci-esdhc-imx.o
obj-$(CONFIG_IMX_HAVE_PLATFORM_SPI_IMX) += platform-spi_imx.o
diff --git a/arch/arm/plat-mxc/devices/platform-ipu-core.c b/arch/arm/plat-mxc/devices/platform-ipu-core.c
new file mode 100644
index 000000000000..edf65034aea5
--- /dev/null
+++ b/arch/arm/plat-mxc/devices/platform-ipu-core.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2011 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.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 <mach/hardware.h>
+#include <mach/devices-common.h>
+
+#define imx_ipu_core_entry_single(soc) \
+{ \
+ .iobase = soc ## _IPU_CTRL_BASE_ADDR, \
+ .synirq = soc ## _INT_IPU_SYN, \
+ .errirq = soc ## _INT_IPU_ERR, \
+}
+
+#ifdef CONFIG_SOC_IMX31
+const struct imx_ipu_core_data imx31_ipu_core_data __initconst =
+ imx_ipu_core_entry_single(MX31);
+#endif
+
+#ifdef CONFIG_SOC_IMX35
+const struct imx_ipu_core_data imx35_ipu_core_data __initconst =
+ imx_ipu_core_entry_single(MX35);
+#endif
+
+static struct platform_device *imx_ipu_coredev __initdata;
+
+struct platform_device *__init imx_add_ipu_core(
+ const struct imx_ipu_core_data *data,
+ const struct ipu_platform_data *pdata)
+{
+ /* The resource order is important! */
+ struct resource res[] = {
+ {
+ .start = data->iobase,
+ .end = data->iobase + 0x5f,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = data->iobase + 0x88,
+ .end = data->iobase + 0xb3,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = data->synirq,
+ .end = data->synirq,
+ .flags = IORESOURCE_IRQ,
+ }, {
+ .start = data->errirq,
+ .end = data->errirq,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+
+ return imx_ipu_coredev = imx_add_platform_device("ipu-core", -1,
+ res, ARRAY_SIZE(res), pdata, sizeof(*pdata));
+}
+
+struct platform_device *__init imx_alloc_mx3_camera(
+ const struct imx_ipu_core_data *data,
+ const struct mx3_camera_pdata *pdata)
+{
+ struct resource res[] = {
+ {
+ .start = data->iobase + 0x60,
+ .end = data->iobase + 0x87,
+ .flags = IORESOURCE_MEM,
+ },
+ };
+ int ret = -ENOMEM;
+ struct platform_device *pdev;
+
+ if (IS_ERR_OR_NULL(imx_ipu_coredev))
+ return ERR_PTR(-ENODEV);
+
+ pdev = platform_device_alloc("mx3-camera", 0);
+ if (!pdev)
+ goto err;
+
+ pdev->dev.dma_mask = kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL);
+ if (!pdev->dev.dma_mask)
+ goto err;
+
+ *pdev->dev.dma_mask = DMA_BIT_MASK(32);
+ pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+ ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res));
+ if (ret)
+ goto err;
+
+ if (pdata) {
+ struct mx3_camera_pdata *copied_pdata;
+
+ ret = platform_device_add_data(pdev, pdata, sizeof(*pdata));
+ if (ret) {
+err:
+ kfree(pdev->dev.dma_mask);
+ platform_device_put(pdev);
+ return ERR_PTR(-ENODEV);
+ }
+ copied_pdata = dev_get_platdata(&pdev->dev);
+ copied_pdata->dma_dev = &imx_ipu_coredev->dev;
+ }
+
+ return pdev;
+}
+
+struct platform_device *__init imx_add_mx3_sdc_fb(
+ const struct imx_ipu_core_data *data,
+ struct mx3fb_platform_data *pdata)
+{
+ struct resource res[] = {
+ {
+ .start = data->iobase + 0xb4,
+ .end = data->iobase + 0x1bf,
+ .flags = IORESOURCE_MEM,
+ },
+ };
+
+ if (IS_ERR_OR_NULL(imx_ipu_coredev))
+ return ERR_PTR(-ENODEV);
+
+ pdata->dma_dev = &imx_ipu_coredev->dev;
+
+ return imx_add_platform_device_dmamask("mx3_sdc_fb", -1,
+ res, ARRAY_SIZE(res), pdata, sizeof(*pdata),
+ DMA_BIT_MASK(32));
+}
diff --git a/arch/arm/plat-mxc/devices/platform-mxc_rtc.c b/arch/arm/plat-mxc/devices/platform-mxc_rtc.c
new file mode 100644
index 000000000000..16d0ec4df5f6
--- /dev/null
+++ b/arch/arm/plat-mxc/devices/platform-mxc_rtc.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010-2011 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.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 <mach/hardware.h>
+#include <mach/devices-common.h>
+
+#define imx_mxc_rtc_data_entry_single(soc) \
+ { \
+ .iobase = soc ## _RTC_BASE_ADDR, \
+ .irq = soc ## _INT_RTC, \
+ }
+
+#ifdef CONFIG_SOC_IMX31
+const struct imx_mxc_rtc_data imx31_mxc_rtc_data __initconst =
+ imx_mxc_rtc_data_entry_single(MX31);
+#endif /* ifdef CONFIG_SOC_IMX31 */
+
+struct platform_device *__init imx_add_mxc_rtc(
+ const struct imx_mxc_rtc_data *data)
+{
+ struct resource res[] = {
+ {
+ .start = data->iobase,
+ .end = data->iobase + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = data->irq,
+ .end = data->irq,
+ .flags = IORESOURCE_IRQ,
+ },
+ };
+
+ return imx_add_platform_device("mxc_rtc", -1,
+ res, ARRAY_SIZE(res), NULL, 0);
+}
diff --git a/arch/arm/plat-mxc/devices/platform-spi_imx.c b/arch/arm/plat-mxc/devices/platform-spi_imx.c
index f4a60ab6763b..f97eb3615b2c 100644
--- a/arch/arm/plat-mxc/devices/platform-spi_imx.c
+++ b/arch/arm/plat-mxc/devices/platform-spi_imx.c
@@ -80,7 +80,7 @@ const struct imx_spi_imx_data imx35_cspi_data[] __initconst = {
#ifdef CONFIG_SOC_IMX51
const struct imx_spi_imx_data imx51_cspi_data __initconst =
- imx_spi_imx_data_entry_single(MX51, CSPI, "imx51-cspi", 0, , SZ_4K);
+ imx_spi_imx_data_entry_single(MX51, CSPI, "imx51-cspi", 2, , SZ_4K);
const struct imx_spi_imx_data imx51_ecspi_data[] __initconst = {
#define imx51_ecspi_data_entry(_id, _hwid) \
diff --git a/arch/arm/plat-mxc/epit.c b/arch/arm/plat-mxc/epit.c
index d69d343ff61f..d3467f818c33 100644
--- a/arch/arm/plat-mxc/epit.c
+++ b/arch/arm/plat-mxc/epit.c
@@ -83,26 +83,12 @@ static void epit_irq_acknowledge(void)
__raw_writel(EPITSR_OCIF, timer_base + EPITSR);
}
-static cycle_t epit_read(struct clocksource *cs)
-{
- return 0 - __raw_readl(timer_base + EPITCNR);
-}
-
-static struct clocksource clocksource_epit = {
- .name = "epit",
- .rating = 200,
- .read = epit_read,
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
static int __init epit_clocksource_init(struct clk *timer_clk)
{
unsigned int c = clk_get_rate(timer_clk);
- clocksource_register_hz(&clocksource_epit, c);
-
- return 0;
+ return clocksource_mmio_init(timer_base + EPITCNR, "epit", c, 200, 32,
+ clocksource_mmio_readl_down);
}
/* clock event */
diff --git a/arch/arm/plat-mxc/include/mach/common.h b/arch/arm/plat-mxc/include/mach/common.h
index a22ebe11a602..da7991832af6 100644
--- a/arch/arm/plat-mxc/include/mach/common.h
+++ b/arch/arm/plat-mxc/include/mach/common.h
@@ -23,7 +23,6 @@ extern void mx35_map_io(void);
extern void mx50_map_io(void);
extern void mx51_map_io(void);
extern void mx53_map_io(void);
-extern void mxc91231_map_io(void);
extern void imx1_init_early(void);
extern void imx21_init_early(void);
extern void imx25_init_early(void);
@@ -33,7 +32,6 @@ extern void imx35_init_early(void);
extern void imx50_init_early(void);
extern void imx51_init_early(void);
extern void imx53_init_early(void);
-extern void mxc91231_init_early(void);
extern void mxc_init_irq(void __iomem *);
extern void tzic_init_irq(void __iomem *);
extern void mx1_init_irq(void);
@@ -45,7 +43,6 @@ extern void mx35_init_irq(void);
extern void mx50_init_irq(void);
extern void mx51_init_irq(void);
extern void mx53_init_irq(void);
-extern void mxc91231_init_irq(void);
extern void epit_timer_init(struct clk *timer_clk, void __iomem *base, int irq);
extern void mxc_timer_init(struct clk *timer_clk, void __iomem *, int);
extern int mx1_clocks_init(unsigned long fref);
@@ -58,14 +55,11 @@ extern int mx51_clocks_init(unsigned long ckil, unsigned long osc,
unsigned long ckih1, unsigned long ckih2);
extern int mx53_clocks_init(unsigned long ckil, unsigned long osc,
unsigned long ckih1, unsigned long ckih2);
-extern int mxc91231_clocks_init(unsigned long fref);
extern int mxc_register_gpios(void);
extern int mxc_register_device(struct platform_device *pdev, void *data);
extern void mxc_set_cpu_type(unsigned int type);
extern void mxc_arch_reset_init(void __iomem *);
-extern void mxc91231_power_off(void);
-extern void mxc91231_arch_reset(int, const char *);
-extern void mxc91231_prepare_idle(void);
extern void mx51_efikamx_reset(void);
extern int mx53_revision(void);
+extern int mx53_display_revision(void);
#endif
diff --git a/arch/arm/plat-mxc/include/mach/debug-macro.S b/arch/arm/plat-mxc/include/mach/debug-macro.S
index 3b3a37c25c56..8e8d175e5077 100644
--- a/arch/arm/plat-mxc/include/mach/debug-macro.S
+++ b/arch/arm/plat-mxc/include/mach/debug-macro.S
@@ -44,13 +44,6 @@
#define UART_PADDR MX51_UART1_BASE_ADDR
#endif
-#ifdef CONFIG_ARCH_MXC91231
-#ifdef UART_PADDR
-#error "CONFIG_DEBUG_LL is incompatible with multiple archs"
-#endif
-#define UART_PADDR MXC91231_UART2_BASE_ADDR
-#endif
-
#define UART_VADDR IMX_IO_ADDRESS(UART_PADDR)
.macro addruart, rp, rv
diff --git a/arch/arm/plat-mxc/include/mach/devices-common.h b/arch/arm/plat-mxc/include/mach/devices-common.h
index 8658c9caa650..fa8477337f91 100644
--- a/arch/arm/plat-mxc/include/mach/devices-common.h
+++ b/arch/arm/plat-mxc/include/mach/devices-common.h
@@ -166,6 +166,24 @@ struct platform_device *__init imx_add_imx_udc(
const struct imx_imx_udc_data *data,
const struct imxusb_platform_data *pdata);
+#include <mach/ipu.h>
+#include <mach/mx3fb.h>
+#include <mach/mx3_camera.h>
+struct imx_ipu_core_data {
+ resource_size_t iobase;
+ resource_size_t synirq;
+ resource_size_t errirq;
+};
+struct platform_device *__init imx_add_ipu_core(
+ const struct imx_ipu_core_data *data,
+ const struct ipu_platform_data *pdata);
+struct platform_device *__init imx_alloc_mx3_camera(
+ const struct imx_ipu_core_data *data,
+ const struct mx3_camera_pdata *pdata);
+struct platform_device *__init imx_add_mx3_sdc_fb(
+ const struct imx_ipu_core_data *data,
+ struct mx3fb_platform_data *pdata);
+
#include <mach/mx1_camera.h>
struct imx_mx1_camera_data {
resource_size_t iobase;
@@ -237,6 +255,15 @@ struct imx_mxc_pwm_data {
struct platform_device *__init imx_add_mxc_pwm(
const struct imx_mxc_pwm_data *data);
+/* mxc_rtc */
+struct imx_mxc_rtc_data {
+ resource_size_t iobase;
+ resource_size_t irq;
+};
+struct platform_device *__init imx_add_mxc_rtc(
+ const struct imx_mxc_rtc_data *data);
+
+/* mxc_w1 */
struct imx_mxc_w1_data {
resource_size_t iobase;
};
diff --git a/arch/arm/plat-mxc/include/mach/hardware.h b/arch/arm/plat-mxc/include/mach/hardware.h
index 26bb1bab4aeb..67d3e2bed065 100644
--- a/arch/arm/plat-mxc/include/mach/hardware.h
+++ b/arch/arm/plat-mxc/include/mach/hardware.h
@@ -86,15 +86,6 @@
* SPBA0 0x70000000+0x100000 -> 0xf5400000+0x100000
* AIPS1 0x73f00000+0x100000 -> 0xf5700000+0x100000
* AIPS2 0x83f00000+0x100000 -> 0xf4300000+0x100000
- * mxc91231:
- * L2CC 0x30000000+0x010000 -> 0xf4400000+0x010000
- * X_MEMC 0xb8000000+0x010000 -> 0xf4c00000+0x010000
- * ROMP 0x60000000+0x010000 -> 0xf5000000+0x010000
- * AVIC 0x68000000+0x010000 -> 0xf5800000+0x010000
- * AIPS1 0x43f00000+0x100000 -> 0xf5300000+0x100000
- * SPBA0 0x50000000+0x100000 -> 0xf5400000+0x100000
- * SPBA1 0x52000000+0x100000 -> 0xf5600000+0x100000
- * AIPS2 0x53f00000+0x100000 -> 0xf5700000+0x100000
*/
#define IMX_IO_P2V(x) ( \
0xf4000000 + \
@@ -104,6 +95,8 @@
#define IMX_IO_ADDRESS(x) IOMEM(IMX_IO_P2V(x))
+#include <mach/mxc.h>
+
#ifdef CONFIG_ARCH_MX5
#include <mach/mx50.h>
#include <mach/mx51.h>
@@ -134,12 +127,6 @@
# include <mach/mx25.h>
#endif
-#ifdef CONFIG_ARCH_MXC91231
-# include <mach/mxc91231.h>
-#endif
-
-#include <mach/mxc.h>
-
#define imx_map_entry(soc, name, _type) { \
.virtual = soc ## _IO_P2V(soc ## _ ## name ## _BASE_ADDR), \
.pfn = __phys_to_pfn(soc ## _ ## name ## _BASE_ADDR), \
diff --git a/arch/arm/plat-mxc/include/mach/io.h b/arch/arm/plat-mxc/include/mach/io.h
index b4f2de769466..4347a87d2bb0 100644
--- a/arch/arm/plat-mxc/include/mach/io.h
+++ b/arch/arm/plat-mxc/include/mach/io.h
@@ -14,19 +14,26 @@
/* Allow IO space to be anywhere in the memory */
#define IO_SPACE_LIMIT 0xffffffff
-#ifdef CONFIG_ARCH_MX3
-#define __arch_ioremap __mx3_ioremap
+#if defined(CONFIG_SOC_IMX31) || defined(CONFIG_SOC_IMX35)
+#include <mach/hardware.h>
+
+#define __arch_ioremap __imx_ioremap
#define __arch_iounmap __iounmap
+#define addr_in_module(addr, mod) \
+ ((unsigned long)(addr) - mod ## _BASE_ADDR < mod ## _SIZE)
+
static inline void __iomem *
-__mx3_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
+__imx_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
{
- if (mtype == MT_DEVICE) {
- /* Access all peripherals below 0x80000000 as nonshared device
- * but leave l2cc alone.
+ if (mtype == MT_DEVICE && (cpu_is_mx31() || cpu_is_mx35())) {
+ /*
+ * Access all peripherals below 0x80000000 as nonshared device
+ * on mx3, but leave l2cc alone. Otherwise cache corruptions
+ * can occur.
*/
- if ((phys_addr < 0x80000000) && ((phys_addr < 0x30000000) ||
- (phys_addr >= 0x30000000 + SZ_1M)))
+ if (phys_addr < 0x80000000 &&
+ !addr_in_module(phys_addr, MX3x_L2CC))
mtype = MT_DEVICE_NONSHARED;
}
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx25.h b/arch/arm/plat-mxc/include/mach/iomux-mx25.h
index d7f52c91f82e..2e5244de7ff5 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mx25.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mx25.h
@@ -89,13 +89,16 @@
#define MX25_PAD_CS0__GPIO_4_2 IOMUX_PAD(0x000, 0x04c, 0x05, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_CS1__CS1 IOMUX_PAD(0x000, 0x050, 0x00, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_CS1__NF_CE3 IOMUX_PAD(0x000, 0x050, 0x01, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_CS1__GPIO_4_3 IOMUX_PAD(0x000, 0x050, 0x05, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_CS4__CS4 IOMUX_PAD(0x264, 0x054, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_CS4__NF_CE1 IOMUX_PAD(0x264, 0x054, 0x01, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_CS4__UART5_CTS IOMUX_PAD(0x264, 0x054, 0x13, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_CS4__GPIO_3_20 IOMUX_PAD(0x264, 0x054, 0x15, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_CS5__CS5 IOMUX_PAD(0x268, 0x058, 0x10, 0, 0, NO_PAD_CTRL)
+#define MX25_PAD_CS5__NF_CE2 IOMUX_PAD(0x268, 0x058, 0x01, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_CS5__UART5_RTS IOMUX_PAD(0x268, 0x058, 0x13, 0x574, 0, NO_PAD_CTRL)
#define MX25_PAD_CS5__GPIO_3_21 IOMUX_PAD(0x268, 0x058, 0x15, 0, 0, NO_PAD_CTRL)
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mxc91231.h b/arch/arm/plat-mxc/include/mach/iomux-mxc91231.h
deleted file mode 100644
index bf28df0d58b7..000000000000
--- a/arch/arm/plat-mxc/include/mach/iomux-mxc91231.h
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright (C) 2008 by Sascha Hauer <kernel@pengutronix.de>
- * Copyright (C) 2009 by Dmitriy Taychenachev <dimichxp@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.
- */
-
-#ifndef __MACH_IOMUX_MXC91231_H__
-#define __MACH_IOMUX_MXC91231_H__
-
-/*
- * various IOMUX output functions
- */
-
-#define IOMUX_OCONFIG_GPIO (0 << 4) /* used as GPIO */
-#define IOMUX_OCONFIG_FUNC (1 << 4) /* used as function */
-#define IOMUX_OCONFIG_ALT1 (2 << 4) /* used as alternate function 1 */
-#define IOMUX_OCONFIG_ALT2 (3 << 4) /* used as alternate function 2 */
-#define IOMUX_OCONFIG_ALT3 (4 << 4) /* used as alternate function 3 */
-#define IOMUX_OCONFIG_ALT4 (5 << 4) /* used as alternate function 4 */
-#define IOMUX_OCONFIG_ALT5 (6 << 4) /* used as alternate function 5 */
-#define IOMUX_OCONFIG_ALT6 (7 << 4) /* used as alternate function 6 */
-#define IOMUX_ICONFIG_NONE 0 /* not configured for input */
-#define IOMUX_ICONFIG_GPIO 1 /* used as GPIO */
-#define IOMUX_ICONFIG_FUNC 2 /* used as function */
-#define IOMUX_ICONFIG_ALT1 4 /* used as alternate function 1 */
-#define IOMUX_ICONFIG_ALT2 8 /* used as alternate function 2 */
-
-#define IOMUX_CONFIG_GPIO (IOMUX_OCONFIG_GPIO | IOMUX_ICONFIG_GPIO)
-#define IOMUX_CONFIG_FUNC (IOMUX_OCONFIG_FUNC | IOMUX_ICONFIG_FUNC)
-#define IOMUX_CONFIG_ALT1 (IOMUX_OCONFIG_ALT1 | IOMUX_ICONFIG_ALT1)
-#define IOMUX_CONFIG_ALT2 (IOMUX_OCONFIG_ALT2 | IOMUX_ICONFIG_ALT2)
-
-/*
- * setups a single pin:
- * - reserves the pin so that it is not claimed by another driver
- * - setups the iomux according to the configuration
- * - if the pin is configured as a GPIO, we claim it through kernel gpiolib
- */
-int mxc_iomux_alloc_pin(unsigned int pin_mode, const char *label);
-/*
- * setups mutliple pins
- * convenient way to call the above function with tables
- */
-int mxc_iomux_setup_multiple_pins(const unsigned int *pin_list, unsigned count,
- const char *label);
-
-/*
- * releases a single pin:
- * - make it available for a future use by another driver
- * - frees the GPIO if the pin was configured as GPIO
- * - DOES NOT reconfigure the IOMUX in its reset state
- */
-void mxc_iomux_release_pin(unsigned int pin_mode);
-/*
- * releases multiple pins
- * convenvient way to call the above function with tables
- */
-void mxc_iomux_release_multiple_pins(const unsigned int *pin_list, int count);
-
-#define MUX_SIDE_AP (0)
-#define MUX_SIDE_SP (1)
-
-#define MUX_SIDE_SHIFT (26)
-#define MUX_SIDE_MASK (0x1 << MUX_SIDE_SHIFT)
-
-#define MUX_GPIO_PORT_SHIFT (23)
-#define MUX_GPIO_PORT_MASK (0x7 << MUX_GPIO_PORT_SHIFT)
-
-#define MUX_GPIO_PIN_SHIFT (20)
-#define MUX_GPIO_PIN_MASK (0x1f << MUX_GPIO_PIN_SHIFT)
-
-#define MUX_REG_SHIFT (15)
-#define MUX_REG_MASK (0x1f << MUX_REG_SHIFT)
-
-#define MUX_FIELD_SHIFT (13)
-#define MUX_FIELD_MASK (0x3 << MUX_FIELD_SHIFT)
-
-#define MUX_PADGRP_SHIFT (8)
-#define MUX_PADGRP_MASK (0x1f << MUX_PADGRP_SHIFT)
-
-#define MUX_PIN_MASK (0xffffff << 8)
-
-#define GPIO_PORT_MAX (3)
-
-#define IOMUX_PIN(side, gport, gpin, ctlreg, ctlfield, padgrp) \
- (((side) << MUX_SIDE_SHIFT) | \
- (gport << MUX_GPIO_PORT_SHIFT) | \
- ((gpin) << MUX_GPIO_PIN_SHIFT) | \
- ((ctlreg) << MUX_REG_SHIFT) | \
- ((ctlfield) << MUX_FIELD_SHIFT) | \
- ((padgrp) << MUX_PADGRP_SHIFT))
-
-#define MUX_MODE_OUT_SHIFT (4)
-#define MUX_MODE_IN_SHIFT (0)
-#define MUX_MODE_SHIFT (0)
-#define MUX_MODE_MASK (0xff << MUX_MODE_SHIFT)
-
-#define IOMUX_MODE(pin, mode) \
- (pin | (mode << MUX_MODE_SHIFT))
-
-enum iomux_pins {
- /* AP Side pins */
- MXC91231_PIN_AP_CLE = IOMUX_PIN(0, 0, 0, 0, 0, 24),
- MXC91231_PIN_AP_ALE = IOMUX_PIN(0, 0, 1, 0, 1, 24),
- MXC91231_PIN_AP_CE_B = IOMUX_PIN(0, 0, 2, 0, 2, 24),
- MXC91231_PIN_AP_RE_B = IOMUX_PIN(0, 0, 3, 0, 3, 24),
- MXC91231_PIN_AP_WE_B = IOMUX_PIN(0, 0, 4, 1, 0, 24),
- MXC91231_PIN_AP_WP_B = IOMUX_PIN(0, 0, 5, 1, 1, 24),
- MXC91231_PIN_AP_BSY_B = IOMUX_PIN(0, 0, 6, 1, 2, 24),
- MXC91231_PIN_AP_U1_TXD = IOMUX_PIN(0, 0, 7, 1, 3, 28),
- MXC91231_PIN_AP_U1_RXD = IOMUX_PIN(0, 0, 8, 2, 0, 28),
- MXC91231_PIN_AP_U1_RTS_B = IOMUX_PIN(0, 0, 9, 2, 1, 28),
- MXC91231_PIN_AP_U1_CTS_B = IOMUX_PIN(0, 0, 10, 2, 2, 28),
- MXC91231_PIN_AP_AD1_TXD = IOMUX_PIN(0, 0, 11, 2, 3, 9),
- MXC91231_PIN_AP_AD1_RXD = IOMUX_PIN(0, 0, 12, 3, 0, 9),
- MXC91231_PIN_AP_AD1_TXC = IOMUX_PIN(0, 0, 13, 3, 1, 9),
- MXC91231_PIN_AP_AD1_TXFS = IOMUX_PIN(0, 0, 14, 3, 2, 9),
- MXC91231_PIN_AP_AD2_TXD = IOMUX_PIN(0, 0, 15, 3, 3, 9),
- MXC91231_PIN_AP_AD2_RXD = IOMUX_PIN(0, 0, 16, 4, 0, 9),
- MXC91231_PIN_AP_AD2_TXC = IOMUX_PIN(0, 0, 17, 4, 1, 9),
- MXC91231_PIN_AP_AD2_TXFS = IOMUX_PIN(0, 0, 18, 4, 2, 9),
- MXC91231_PIN_AP_OWDAT = IOMUX_PIN(0, 0, 19, 4, 3, 28),
- MXC91231_PIN_AP_IPU_LD17 = IOMUX_PIN(0, 0, 20, 5, 0, 28),
- MXC91231_PIN_AP_IPU_D3_VSYNC = IOMUX_PIN(0, 0, 21, 5, 1, 28),
- MXC91231_PIN_AP_IPU_D3_HSYNC = IOMUX_PIN(0, 0, 22, 5, 2, 28),
- MXC91231_PIN_AP_IPU_D3_CLK = IOMUX_PIN(0, 0, 23, 5, 3, 28),
- MXC91231_PIN_AP_IPU_D3_DRDY = IOMUX_PIN(0, 0, 24, 6, 0, 28),
- MXC91231_PIN_AP_IPU_D3_CONTR = IOMUX_PIN(0, 0, 25, 6, 1, 28),
- MXC91231_PIN_AP_IPU_D0_CS = IOMUX_PIN(0, 0, 26, 6, 2, 28),
- MXC91231_PIN_AP_IPU_LD16 = IOMUX_PIN(0, 0, 27, 6, 3, 28),
- MXC91231_PIN_AP_IPU_D2_CS = IOMUX_PIN(0, 0, 28, 7, 0, 28),
- MXC91231_PIN_AP_IPU_PAR_RS = IOMUX_PIN(0, 0, 29, 7, 1, 28),
- MXC91231_PIN_AP_IPU_D3_PS = IOMUX_PIN(0, 0, 30, 7, 2, 28),
- MXC91231_PIN_AP_IPU_D3_CLS = IOMUX_PIN(0, 0, 31, 7, 3, 28),
- MXC91231_PIN_AP_IPU_RD = IOMUX_PIN(0, 1, 0, 8, 0, 28),
- MXC91231_PIN_AP_IPU_WR = IOMUX_PIN(0, 1, 1, 8, 1, 28),
- MXC91231_PIN_AP_IPU_LD0 = IOMUX_PIN(0, 7, 0, 8, 2, 28),
- MXC91231_PIN_AP_IPU_LD1 = IOMUX_PIN(0, 7, 0, 8, 3, 28),
- MXC91231_PIN_AP_IPU_LD2 = IOMUX_PIN(0, 7, 0, 9, 0, 28),
- MXC91231_PIN_AP_IPU_LD3 = IOMUX_PIN(0, 1, 2, 9, 1, 28),
- MXC91231_PIN_AP_IPU_LD4 = IOMUX_PIN(0, 1, 3, 9, 2, 28),
- MXC91231_PIN_AP_IPU_LD5 = IOMUX_PIN(0, 1, 4, 9, 3, 28),
- MXC91231_PIN_AP_IPU_LD6 = IOMUX_PIN(0, 1, 5, 10, 0, 28),
- MXC91231_PIN_AP_IPU_LD7 = IOMUX_PIN(0, 1, 6, 10, 1, 28),
- MXC91231_PIN_AP_IPU_LD8 = IOMUX_PIN(0, 1, 7, 10, 2, 28),
- MXC91231_PIN_AP_IPU_LD9 = IOMUX_PIN(0, 1, 8, 10, 3, 28),
- MXC91231_PIN_AP_IPU_LD10 = IOMUX_PIN(0, 1, 9, 11, 0, 28),
- MXC91231_PIN_AP_IPU_LD11 = IOMUX_PIN(0, 1, 10, 11, 1, 28),
- MXC91231_PIN_AP_IPU_LD12 = IOMUX_PIN(0, 1, 11, 11, 2, 28),
- MXC91231_PIN_AP_IPU_LD13 = IOMUX_PIN(0, 1, 12, 11, 3, 28),
- MXC91231_PIN_AP_IPU_LD14 = IOMUX_PIN(0, 1, 13, 12, 0, 28),
- MXC91231_PIN_AP_IPU_LD15 = IOMUX_PIN(0, 1, 14, 12, 1, 28),
- MXC91231_PIN_AP_KPROW4 = IOMUX_PIN(0, 7, 0, 12, 2, 10),
- MXC91231_PIN_AP_KPROW5 = IOMUX_PIN(0, 1, 16, 12, 3, 10),
- MXC91231_PIN_AP_GPIO_AP_B17 = IOMUX_PIN(0, 1, 17, 13, 0, 10),
- MXC91231_PIN_AP_GPIO_AP_B18 = IOMUX_PIN(0, 1, 18, 13, 1, 10),
- MXC91231_PIN_AP_KPCOL3 = IOMUX_PIN(0, 1, 19, 13, 2, 11),
- MXC91231_PIN_AP_KPCOL4 = IOMUX_PIN(0, 1, 20, 13, 3, 11),
- MXC91231_PIN_AP_KPCOL5 = IOMUX_PIN(0, 1, 21, 14, 0, 11),
- MXC91231_PIN_AP_GPIO_AP_B22 = IOMUX_PIN(0, 1, 22, 14, 1, 11),
- MXC91231_PIN_AP_GPIO_AP_B23 = IOMUX_PIN(0, 1, 23, 14, 2, 11),
- MXC91231_PIN_AP_CSI_D0 = IOMUX_PIN(0, 1, 24, 14, 3, 21),
- MXC91231_PIN_AP_CSI_D1 = IOMUX_PIN(0, 1, 25, 15, 0, 21),
- MXC91231_PIN_AP_CSI_D2 = IOMUX_PIN(0, 1, 26, 15, 1, 21),
- MXC91231_PIN_AP_CSI_D3 = IOMUX_PIN(0, 1, 27, 15, 2, 21),
- MXC91231_PIN_AP_CSI_D4 = IOMUX_PIN(0, 1, 28, 15, 3, 21),
- MXC91231_PIN_AP_CSI_D5 = IOMUX_PIN(0, 1, 29, 16, 0, 21),
- MXC91231_PIN_AP_CSI_D6 = IOMUX_PIN(0, 1, 30, 16, 1, 21),
- MXC91231_PIN_AP_CSI_D7 = IOMUX_PIN(0, 1, 31, 16, 2, 21),
- MXC91231_PIN_AP_CSI_D8 = IOMUX_PIN(0, 2, 0, 16, 3, 21),
- MXC91231_PIN_AP_CSI_D9 = IOMUX_PIN(0, 2, 1, 17, 0, 21),
- MXC91231_PIN_AP_CSI_MCLK = IOMUX_PIN(0, 2, 2, 17, 1, 21),
- MXC91231_PIN_AP_CSI_VSYNC = IOMUX_PIN(0, 2, 3, 17, 2, 21),
- MXC91231_PIN_AP_CSI_HSYNC = IOMUX_PIN(0, 2, 4, 17, 3, 21),
- MXC91231_PIN_AP_CSI_PIXCLK = IOMUX_PIN(0, 2, 5, 18, 0, 21),
- MXC91231_PIN_AP_I2CLK = IOMUX_PIN(0, 2, 6, 18, 1, 12),
- MXC91231_PIN_AP_I2DAT = IOMUX_PIN(0, 2, 7, 18, 2, 12),
- MXC91231_PIN_AP_GPIO_AP_C8 = IOMUX_PIN(0, 2, 8, 18, 3, 9),
- MXC91231_PIN_AP_GPIO_AP_C9 = IOMUX_PIN(0, 2, 9, 19, 0, 9),
- MXC91231_PIN_AP_GPIO_AP_C10 = IOMUX_PIN(0, 2, 10, 19, 1, 9),
- MXC91231_PIN_AP_GPIO_AP_C11 = IOMUX_PIN(0, 2, 11, 19, 2, 9),
- MXC91231_PIN_AP_GPIO_AP_C12 = IOMUX_PIN(0, 2, 12, 19, 3, 9),
- MXC91231_PIN_AP_GPIO_AP_C13 = IOMUX_PIN(0, 2, 13, 20, 0, 28),
- MXC91231_PIN_AP_GPIO_AP_C14 = IOMUX_PIN(0, 2, 14, 20, 1, 28),
- MXC91231_PIN_AP_GPIO_AP_C15 = IOMUX_PIN(0, 2, 15, 20, 2, 9),
- MXC91231_PIN_AP_GPIO_AP_C16 = IOMUX_PIN(0, 2, 16, 20, 3, 9),
- MXC91231_PIN_AP_GPIO_AP_C17 = IOMUX_PIN(0, 2, 17, 21, 0, 9),
- MXC91231_PIN_AP_ED_INT0 = IOMUX_PIN(0, 2, 18, 21, 1, 22),
- MXC91231_PIN_AP_ED_INT1 = IOMUX_PIN(0, 2, 19, 21, 2, 22),
- MXC91231_PIN_AP_ED_INT2 = IOMUX_PIN(0, 2, 20, 21, 3, 22),
- MXC91231_PIN_AP_ED_INT3 = IOMUX_PIN(0, 2, 21, 22, 0, 22),
- MXC91231_PIN_AP_ED_INT4 = IOMUX_PIN(0, 2, 22, 22, 1, 23),
- MXC91231_PIN_AP_ED_INT5 = IOMUX_PIN(0, 2, 23, 22, 2, 23),
- MXC91231_PIN_AP_ED_INT6 = IOMUX_PIN(0, 2, 24, 22, 3, 23),
- MXC91231_PIN_AP_ED_INT7 = IOMUX_PIN(0, 2, 25, 23, 0, 23),
- MXC91231_PIN_AP_U2_DSR_B = IOMUX_PIN(0, 2, 26, 23, 1, 28),
- MXC91231_PIN_AP_U2_RI_B = IOMUX_PIN(0, 2, 27, 23, 2, 28),
- MXC91231_PIN_AP_U2_CTS_B = IOMUX_PIN(0, 2, 28, 23, 3, 28),
- MXC91231_PIN_AP_U2_DTR_B = IOMUX_PIN(0, 2, 29, 24, 0, 28),
- MXC91231_PIN_AP_KPROW0 = IOMUX_PIN(0, 7, 0, 24, 1, 10),
- MXC91231_PIN_AP_KPROW1 = IOMUX_PIN(0, 1, 15, 24, 2, 10),
- MXC91231_PIN_AP_KPROW2 = IOMUX_PIN(0, 7, 0, 24, 3, 10),
- MXC91231_PIN_AP_KPROW3 = IOMUX_PIN(0, 7, 0, 25, 0, 10),
- MXC91231_PIN_AP_KPCOL0 = IOMUX_PIN(0, 7, 0, 25, 1, 11),
- MXC91231_PIN_AP_KPCOL1 = IOMUX_PIN(0, 7, 0, 25, 2, 11),
- MXC91231_PIN_AP_KPCOL2 = IOMUX_PIN(0, 7, 0, 25, 3, 11),
-
- /* Shared pins */
- MXC91231_PIN_SP_U3_TXD = IOMUX_PIN(1, 3, 0, 0, 0, 28),
- MXC91231_PIN_SP_U3_RXD = IOMUX_PIN(1, 3, 1, 0, 1, 28),
- MXC91231_PIN_SP_U3_RTS_B = IOMUX_PIN(1, 3, 2, 0, 2, 28),
- MXC91231_PIN_SP_U3_CTS_B = IOMUX_PIN(1, 3, 3, 0, 3, 28),
- MXC91231_PIN_SP_USB_TXOE_B = IOMUX_PIN(1, 3, 4, 1, 0, 28),
- MXC91231_PIN_SP_USB_DAT_VP = IOMUX_PIN(1, 3, 5, 1, 1, 28),
- MXC91231_PIN_SP_USB_SE0_VM = IOMUX_PIN(1, 3, 6, 1, 2, 28),
- MXC91231_PIN_SP_USB_RXD = IOMUX_PIN(1, 3, 7, 1, 3, 28),
- MXC91231_PIN_SP_UH2_TXOE_B = IOMUX_PIN(1, 3, 8, 2, 0, 28),
- MXC91231_PIN_SP_UH2_SPEED = IOMUX_PIN(1, 3, 9, 2, 1, 28),
- MXC91231_PIN_SP_UH2_SUSPEN = IOMUX_PIN(1, 3, 10, 2, 2, 28),
- MXC91231_PIN_SP_UH2_TXDP = IOMUX_PIN(1, 3, 11, 2, 3, 28),
- MXC91231_PIN_SP_UH2_RXDP = IOMUX_PIN(1, 3, 12, 3, 0, 28),
- MXC91231_PIN_SP_UH2_RXDM = IOMUX_PIN(1, 3, 13, 3, 1, 28),
- MXC91231_PIN_SP_UH2_OVR = IOMUX_PIN(1, 3, 14, 3, 2, 28),
- MXC91231_PIN_SP_UH2_PWR = IOMUX_PIN(1, 3, 15, 3, 3, 28),
- MXC91231_PIN_SP_SD1_DAT0 = IOMUX_PIN(1, 3, 16, 4, 0, 25),
- MXC91231_PIN_SP_SD1_DAT1 = IOMUX_PIN(1, 3, 17, 4, 1, 25),
- MXC91231_PIN_SP_SD1_DAT2 = IOMUX_PIN(1, 3, 18, 4, 2, 25),
- MXC91231_PIN_SP_SD1_DAT3 = IOMUX_PIN(1, 3, 19, 4, 3, 25),
- MXC91231_PIN_SP_SD1_CMD = IOMUX_PIN(1, 3, 20, 5, 0, 25),
- MXC91231_PIN_SP_SD1_CLK = IOMUX_PIN(1, 3, 21, 5, 1, 25),
- MXC91231_PIN_SP_SD2_DAT0 = IOMUX_PIN(1, 3, 22, 5, 2, 26),
- MXC91231_PIN_SP_SD2_DAT1 = IOMUX_PIN(1, 3, 23, 5, 3, 26),
- MXC91231_PIN_SP_SD2_DAT2 = IOMUX_PIN(1, 3, 24, 6, 0, 26),
- MXC91231_PIN_SP_SD2_DAT3 = IOMUX_PIN(1, 3, 25, 6, 1, 26),
- MXC91231_PIN_SP_GPIO_SP_A26 = IOMUX_PIN(1, 3, 26, 6, 2, 28),
- MXC91231_PIN_SP_SPI1_CLK = IOMUX_PIN(1, 3, 27, 6, 3, 13),
- MXC91231_PIN_SP_SPI1_MOSI = IOMUX_PIN(1, 3, 28, 7, 0, 13),
- MXC91231_PIN_SP_SPI1_MISO = IOMUX_PIN(1, 3, 29, 7, 1, 13),
- MXC91231_PIN_SP_SPI1_SS0 = IOMUX_PIN(1, 3, 30, 7, 2, 13),
- MXC91231_PIN_SP_SPI1_SS1 = IOMUX_PIN(1, 3, 31, 7, 3, 13),
- MXC91231_PIN_SP_SD2_CMD = IOMUX_PIN(1, 7, 0, 8, 0, 26),
- MXC91231_PIN_SP_SD2_CLK = IOMUX_PIN(1, 7, 0, 8, 1, 26),
- MXC91231_PIN_SP_SIM1_RST_B = IOMUX_PIN(1, 2, 30, 8, 2, 28),
- MXC91231_PIN_SP_SIM1_SVEN = IOMUX_PIN(1, 7, 0, 8, 3, 28),
- MXC91231_PIN_SP_SIM1_CLK = IOMUX_PIN(1, 7, 0, 9, 0, 28),
- MXC91231_PIN_SP_SIM1_TRXD = IOMUX_PIN(1, 7, 0, 9, 1, 28),
- MXC91231_PIN_SP_SIM1_PD = IOMUX_PIN(1, 2, 31, 9, 2, 28),
- MXC91231_PIN_SP_UH2_TXDM = IOMUX_PIN(1, 7, 0, 9, 3, 28),
- MXC91231_PIN_SP_UH2_RXD = IOMUX_PIN(1, 7, 0, 10, 0, 28),
-};
-
-#define PIN_AP_MAX (104)
-#define PIN_SP_MAX (41)
-
-#define PIN_MAX (PIN_AP_MAX + PIN_SP_MAX)
-
-/*
- * Convenience values for use with mxc_iomux_mode()
- *
- * Format here is MXC91231_PIN_(pin name)__(function)
- */
-
-#define MXC91231_PIN_SP_USB_DAT_VP__USB_DAT_VP \
- IOMUX_MODE(MXC91231_PIN_SP_USB_DAT_VP, IOMUX_CONFIG_FUNC)
-#define MXC91231_PIN_SP_USB_SE0_VM__USB_SE0_VM \
- IOMUX_MODE(MXC91231_PIN_SP_USB_SE0_VM, IOMUX_CONFIG_FUNC)
-#define MXC91231_PIN_SP_USB_DAT_VP__RXD2 \
- IOMUX_MODE(MXC91231_PIN_SP_USB_DAT_VP, IOMUX_CONFIG_ALT1)
-#define MXC91231_PIN_SP_USB_SE0_VM__TXD2 \
- IOMUX_MODE(MXC91231_PIN_SP_USB_SE0_VM, IOMUX_CONFIG_ALT1)
-
-
-#endif /* __MACH_IOMUX_MXC91231_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/irqs.h b/arch/arm/plat-mxc/include/mach/irqs.h
index a3d930d3e65d..35c89bcdf758 100644
--- a/arch/arm/plat-mxc/include/mach/irqs.h
+++ b/arch/arm/plat-mxc/include/mach/irqs.h
@@ -35,8 +35,6 @@
#define MXC_GPIO_IRQS (32 * 4)
#elif defined CONFIG_SOC_IMX51
#define MXC_GPIO_IRQS (32 * 4)
-#elif defined CONFIG_ARCH_MXC91231
-#define MXC_GPIO_IRQS (32 * 4)
#elif defined CONFIG_ARCH_MX3
#define MXC_GPIO_IRQS (32 * 3)
#endif
diff --git a/arch/arm/plat-mxc/include/mach/memory.h b/arch/arm/plat-mxc/include/mach/memory.h
index 5d51cbb98893..11be5cdbdd1a 100644
--- a/arch/arm/plat-mxc/include/mach/memory.h
+++ b/arch/arm/plat-mxc/include/mach/memory.h
@@ -19,7 +19,6 @@
#define MX50_PHYS_OFFSET UL(0x70000000)
#define MX51_PHYS_OFFSET UL(0x90000000)
#define MX53_PHYS_OFFSET UL(0x70000000)
-#define MXC91231_PHYS_OFFSET UL(0x90000000)
#if !defined(CONFIG_RUNTIME_PHYS_OFFSET)
# if defined CONFIG_ARCH_MX1
@@ -32,8 +31,6 @@
# define PLAT_PHYS_OFFSET MX27_PHYS_OFFSET
# elif defined CONFIG_ARCH_MX3
# define PLAT_PHYS_OFFSET MX3x_PHYS_OFFSET
-# elif defined CONFIG_ARCH_MXC91231
-# define PLAT_PHYS_OFFSET MXC91231_PHYS_OFFSET
# elif defined CONFIG_ARCH_MX50
# define PLAT_PHYS_OFFSET MX50_PHYS_OFFSET
# elif defined CONFIG_ARCH_MX51
diff --git a/arch/arm/plat-mxc/include/mach/mx27.h b/arch/arm/plat-mxc/include/mach/mx27.h
index cbc43ad5ef48..1dc1c522601b 100644
--- a/arch/arm/plat-mxc/include/mach/mx27.h
+++ b/arch/arm/plat-mxc/include/mach/mx27.h
@@ -60,8 +60,8 @@
#define MX27_AUDMUX_BASE_ADDR (MX27_AIPI_BASE_ADDR + 0x16000)
#define MX27_CSPI3_BASE_ADDR (MX27_AIPI_BASE_ADDR + 0x17000)
#define MX27_MSHC_BASE_ADDR (MX27_AIPI_BASE_ADDR + 0x18000)
-#define MX27_GPT5_BASE_ADDR (MX27_AIPI_BASE_ADDR + 0x19000)
-#define MX27_GPT4_BASE_ADDR (MX27_AIPI_BASE_ADDR + 0x1a000)
+#define MX27_GPT4_BASE_ADDR (MX27_AIPI_BASE_ADDR + 0x19000)
+#define MX27_GPT5_BASE_ADDR (MX27_AIPI_BASE_ADDR + 0x1a000)
#define MX27_UART5_BASE_ADDR (MX27_AIPI_BASE_ADDR + 0x1b000)
#define MX27_UART6_BASE_ADDR (MX27_AIPI_BASE_ADDR + 0x1c000)
#define MX27_I2C2_BASE_ADDR (MX27_AIPI_BASE_ADDR + 0x1d000)
diff --git a/arch/arm/plat-mxc/include/mach/mx53.h b/arch/arm/plat-mxc/include/mach/mx53.h
index ace17864575e..9d2a1ef84de2 100644
--- a/arch/arm/plat-mxc/include/mach/mx53.h
+++ b/arch/arm/plat-mxc/include/mach/mx53.h
@@ -337,17 +337,4 @@
#define MX53_INT_GPIO7_LOW 107
#define MX53_INT_GPIO7_HIGH 108
-/* silicon revisions specific to i.MX53 */
-#define MX53_CHIP_REV_1_0 0x10
-#define MX53_CHIP_REV_1_1 0x11
-#define MX53_CHIP_REV_1_2 0x12
-#define MX53_CHIP_REV_1_3 0x13
-#define MX53_CHIP_REV_2_0 0x20
-#define MX53_CHIP_REV_2_1 0x21
-#define MX53_CHIP_REV_2_2 0x22
-#define MX53_CHIP_REV_2_3 0x23
-#define MX53_CHIP_REV_3_0 0x30
-#define MX53_CHIP_REV_3_1 0x31
-#define MX53_CHIP_REV_3_2 0x32
-
#endif /* ifndef __MACH_MX53_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/mxc.h b/arch/arm/plat-mxc/include/mach/mxc.h
index 1aea818d9d31..4ac53ce97c24 100644
--- a/arch/arm/plat-mxc/include/mach/mxc.h
+++ b/arch/arm/plat-mxc/include/mach/mxc.h
@@ -35,7 +35,6 @@
#define MXC_CPU_MX50 50
#define MXC_CPU_MX51 51
#define MXC_CPU_MX53 53
-#define MXC_CPU_MXC91231 91231
#define IMX_CHIP_REVISION_1_0 0x10
#define IMX_CHIP_REVISION_1_1 0x11
@@ -177,18 +176,6 @@ extern unsigned int __mxc_cpu_type;
# define cpu_is_mx53() (0)
#endif
-#ifdef CONFIG_ARCH_MXC91231
-# ifdef mxc_cpu_type
-# undef mxc_cpu_type
-# define mxc_cpu_type __mxc_cpu_type
-# else
-# define mxc_cpu_type MXC_CPU_MXC91231
-# endif
-# define cpu_is_mxc91231() (mxc_cpu_type == MXC_CPU_MXC91231)
-#else
-# define cpu_is_mxc91231() (0)
-#endif
-
#ifndef __ASSEMBLY__
struct cpu_op {
@@ -207,14 +194,7 @@ enum mxc_cpu_pwr_mode {
extern struct cpu_op *(*get_cpu_op)(int *op);
#endif
-#if defined(CONFIG_ARCH_MX3) || defined(CONFIG_ARCH_MX2)
-/* These are deprecated, use mx[23][157]_setup_weimcs instead. */
-#define CSCR_U(n) (IO_ADDRESS(WEIM_BASE_ADDR + n * 0x10))
-#define CSCR_L(n) (IO_ADDRESS(WEIM_BASE_ADDR + n * 0x10 + 0x4))
-#define CSCR_A(n) (IO_ADDRESS(WEIM_BASE_ADDR + n * 0x10 + 0x8))
-#endif
-
-#define cpu_is_mx3() (cpu_is_mx31() || cpu_is_mx35() || cpu_is_mxc91231())
+#define cpu_is_mx3() (cpu_is_mx31() || cpu_is_mx35())
#define cpu_is_mx2() (cpu_is_mx21() || cpu_is_mx27())
#endif /* __ASM_ARCH_MXC_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/mxc91231.h b/arch/arm/plat-mxc/include/mach/mxc91231.h
deleted file mode 100644
index 765190fe6332..000000000000
--- a/arch/arm/plat-mxc/include/mach/mxc91231.h
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved.
- * - Platform specific register memory map
- *
- * Copyright 2005-2007 Motorola, 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.
- */
-#ifndef __MACH_MXC91231_H__
-#define __MACH_MXC91231_H__
-
-/*
- * L2CC
- */
-#define MXC91231_L2CC_BASE_ADDR 0x30000000
-#define MXC91231_L2CC_SIZE SZ_64K
-
-/*
- * AIPS 1
- */
-#define MXC91231_AIPS1_BASE_ADDR 0x43F00000
-#define MXC91231_AIPS1_SIZE SZ_1M
-
-#define MXC91231_AIPS1_CTRL_BASE_ADDR MXC91231_AIPS1_BASE_ADDR
-#define MXC91231_MAX_BASE_ADDR (MXC91231_AIPS1_BASE_ADDR + 0x04000)
-#define MXC91231_EVTMON_BASE_ADDR (MXC91231_AIPS1_BASE_ADDR + 0x08000)
-#define MXC91231_CLKCTL_BASE_ADDR (MXC91231_AIPS1_BASE_ADDR + 0x0C000)
-#define MXC91231_ETB_SLOT4_BASE_ADDR (MXC91231_AIPS1_BASE_ADDR + 0x10000)
-#define MXC91231_ETB_SLOT5_BASE_ADDR (MXC91231_AIPS1_BASE_ADDR + 0x14000)
-#define MXC91231_ECT_CTIO_BASE_ADDR (MXC91231_AIPS1_BASE_ADDR + 0x18000)
-#define MXC91231_I2C_BASE_ADDR (MXC91231_AIPS1_BASE_ADDR + 0x80000)
-#define MXC91231_MU_BASE_ADDR (MXC91231_AIPS1_BASE_ADDR + 0x88000)
-#define MXC91231_UART1_BASE_ADDR (MXC91231_AIPS1_BASE_ADDR + 0x90000)
-#define MXC91231_UART2_BASE_ADDR (MXC91231_AIPS1_BASE_ADDR + 0x94000)
-#define MXC91231_DSM_BASE_ADDR (MXC91231_AIPS1_BASE_ADDR + 0x98000)
-#define MXC91231_OWIRE_BASE_ADDR (MXC91231_AIPS1_BASE_ADDR + 0x9C000)
-#define MXC91231_SSI1_BASE_ADDR (MXC91231_AIPS1_BASE_ADDR + 0xA0000)
-#define MXC91231_KPP_BASE_ADDR (MXC91231_AIPS1_BASE_ADDR + 0xA8000)
-#define MXC91231_IOMUX_AP_BASE_ADDR (MXC91231_AIPS1_BASE_ADDR + 0xAC000)
-#define MXC91231_CTI_AP_BASE_ADDR (MXC91231_AIPS1_BASE_ADDR + 0xB8000)
-
-/*
- * AIPS 2
- */
-#define MXC91231_AIPS2_BASE_ADDR 0x53F00000
-#define MXC91231_AIPS2_SIZE SZ_1M
-
-#define MXC91231_GEMK_BASE_ADDR (MXC91231_AIPS2_BASE_ADDR + 0x8C000)
-#define MXC91231_GPT1_BASE_ADDR (MXC91231_AIPS2_BASE_ADDR + 0x90000)
-#define MXC91231_EPIT1_AP_BASE_ADDR (MXC91231_AIPS2_BASE_ADDR + 0x94000)
-#define MXC91231_SCC_BASE_ADDR (MXC91231_AIPS2_BASE_ADDR + 0xAC000)
-#define MXC91231_RNGA_BASE_ADDR (MXC91231_AIPS2_BASE_ADDR + 0xB0000)
-#define MXC91231_IPU_CTRL_BASE_ADDR (MXC91231_AIPS2_BASE_ADDR + 0xC0000)
-#define MXC91231_AUDMUX_BASE_ADDR (MXC91231_AIPS2_BASE_ADDR + 0xC4000)
-#define MXC91231_EDIO_BASE_ADDR (MXC91231_AIPS2_BASE_ADDR + 0xC8000)
-#define MXC91231_GPIO1_AP_BASE_ADDR (MXC91231_AIPS2_BASE_ADDR + 0xCC000)
-#define MXC91231_GPIO2_AP_BASE_ADDR (MXC91231_AIPS2_BASE_ADDR + 0xD0000)
-#define MXC91231_SDMA_BASE_ADDR (MXC91231_AIPS2_BASE_ADDR + 0xD4000)
-#define MXC91231_RTC_BASE_ADDR (MXC91231_AIPS2_BASE_ADDR + 0xD8000)
-#define MXC91231_WDOG1_BASE_ADDR (MXC91231_AIPS2_BASE_ADDR + 0xDC000)
-#define MXC91231_PWM_BASE_ADDR (MXC91231_AIPS2_BASE_ADDR + 0xE0000)
-#define MXC91231_GPIO3_AP_BASE_ADDR (MXC91231_AIPS2_BASE_ADDR + 0xE4000)
-#define MXC91231_WDOG2_BASE_ADDR (MXC91231_AIPS2_BASE_ADDR + 0xE8000)
-#define MXC91231_RTIC_BASE_ADDR (MXC91231_AIPS2_BASE_ADDR + 0xEC000)
-#define MXC91231_LPMC_BASE_ADDR (MXC91231_AIPS2_BASE_ADDR + 0xF0000)
-
-/*
- * SPBA global module 0
- */
-#define MXC91231_SPBA0_BASE_ADDR 0x50000000
-#define MXC91231_SPBA0_SIZE SZ_1M
-
-#define MXC91231_MMC_SDHC1_BASE_ADDR (MXC91231_SPBA0_BASE_ADDR + 0x04000)
-#define MXC91231_MMC_SDHC2_BASE_ADDR (MXC91231_SPBA0_BASE_ADDR + 0x08000)
-#define MXC91231_UART3_BASE_ADDR (MXC91231_SPBA0_BASE_ADDR + 0x0C000)
-#define MXC91231_CSPI2_BASE_ADDR (MXC91231_SPBA0_BASE_ADDR + 0x10000)
-#define MXC91231_SSI2_BASE_ADDR (MXC91231_SPBA0_BASE_ADDR + 0x14000)
-#define MXC91231_SIM_BASE_ADDR (MXC91231_SPBA0_BASE_ADDR + 0x18000)
-#define MXC91231_IIM_BASE_ADDR (MXC91231_SPBA0_BASE_ADDR + 0x1C000)
-#define MXC91231_CTI_SDMA_BASE_ADDR (MXC91231_SPBA0_BASE_ADDR + 0x20000)
-#define MXC91231_USBOTG_CTRL_BASE_ADDR (MXC91231_SPBA0_BASE_ADDR + 0x24000)
-#define MXC91231_USBOTG_DATA_BASE_ADDR (MXC91231_SPBA0_BASE_ADDR + 0x28000)
-#define MXC91231_CSPI1_BASE_ADDR (MXC91231_SPBA0_BASE_ADDR + 0x30000)
-#define MXC91231_SPBA_CTRL_BASE_ADDR (MXC91231_SPBA0_BASE_ADDR + 0x3C000)
-#define MXC91231_IOMUX_COM_BASE_ADDR (MXC91231_SPBA0_BASE_ADDR + 0x40000)
-#define MXC91231_CRM_COM_BASE_ADDR (MXC91231_SPBA0_BASE_ADDR + 0x44000)
-#define MXC91231_CRM_AP_BASE_ADDR (MXC91231_SPBA0_BASE_ADDR + 0x48000)
-#define MXC91231_PLL0_BASE_ADDR (MXC91231_SPBA0_BASE_ADDR + 0x4C000)
-#define MXC91231_PLL1_BASE_ADDR (MXC91231_SPBA0_BASE_ADDR + 0x50000)
-#define MXC91231_PLL2_BASE_ADDR (MXC91231_SPBA0_BASE_ADDR + 0x54000)
-#define MXC91231_GPIO4_SH_BASE_ADDR (MXC91231_SPBA0_BASE_ADDR + 0x58000)
-#define MXC91231_HAC_BASE_ADDR (MXC91231_SPBA0_BASE_ADDR + 0x5C000)
-#define MXC91231_SAHARA_BASE_ADDR (MXC91231_SPBA0_BASE_ADDR + 0x5C000)
-#define MXC91231_PLL3_BASE_ADDR (MXC91231_SPBA0_BASE_ADDR + 0x60000)
-
-/*
- * SPBA global module 1
- */
-#define MXC91231_SPBA1_BASE_ADDR 0x52000000
-#define MXC91231_SPBA1_SIZE SZ_1M
-
-#define MXC91231_MQSPI_BASE_ADDR (MXC91231_SPBA1_BASE_ADDR + 0x34000)
-#define MXC91231_EL1T_BASE_ADDR (MXC91231_SPBA1_BASE_ADDR + 0x38000)
-
-/*!
- * Defines for SPBA modules
- */
-#define MXC91231_SPBA_SDHC1 0x04
-#define MXC91231_SPBA_SDHC2 0x08
-#define MXC91231_SPBA_UART3 0x0C
-#define MXC91231_SPBA_CSPI2 0x10
-#define MXC91231_SPBA_SSI2 0x14
-#define MXC91231_SPBA_SIM 0x18
-#define MXC91231_SPBA_IIM 0x1C
-#define MXC91231_SPBA_CTI_SDMA 0x20
-#define MXC91231_SPBA_USBOTG_CTRL_REGS 0x24
-#define MXC91231_SPBA_USBOTG_DATA_REGS 0x28
-#define MXC91231_SPBA_CSPI1 0x30
-#define MXC91231_SPBA_MQSPI 0x34
-#define MXC91231_SPBA_EL1T 0x38
-#define MXC91231_SPBA_IOMUX 0x40
-#define MXC91231_SPBA_CRM_COM 0x44
-#define MXC91231_SPBA_CRM_AP 0x48
-#define MXC91231_SPBA_PLL0 0x4C
-#define MXC91231_SPBA_PLL1 0x50
-#define MXC91231_SPBA_PLL2 0x54
-#define MXC91231_SPBA_GPIO4 0x58
-#define MXC91231_SPBA_SAHARA 0x5C
-
-/*
- * ROMP and AVIC
- */
-#define MXC91231_ROMP_BASE_ADDR 0x60000000
-#define MXC91231_ROMP_SIZE SZ_64K
-
-#define MXC91231_AVIC_BASE_ADDR 0x68000000
-#define MXC91231_AVIC_SIZE SZ_64K
-
-/*
- * NAND, SDRAM, WEIM, M3IF, EMI controllers
- */
-#define MXC91231_X_MEMC_BASE_ADDR 0xB8000000
-#define MXC91231_X_MEMC_SIZE SZ_64K
-
-#define MXC91231_NFC_BASE_ADDR (MXC91231_X_MEMC_BASE_ADDR + 0x0000)
-#define MXC91231_ESDCTL_BASE_ADDR (MXC91231_X_MEMC_BASE_ADDR + 0x1000)
-#define MXC91231_WEIM_BASE_ADDR (MXC91231_X_MEMC_BASE_ADDR + 0x2000)
-#define MXC91231_M3IF_BASE_ADDR (MXC91231_X_MEMC_BASE_ADDR + 0x3000)
-#define MXC91231_EMI_CTL_BASE_ADDR (MXC91231_X_MEMC_BASE_ADDR + 0x4000)
-
-/*
- * Memory regions and CS
- * CPLD is connected on CS4
- * CS5 is TP1021 or it is not connected
- * */
-#define MXC91231_FB_RAM_BASE_ADDR 0x78000000
-#define MXC91231_FB_RAM_SIZE SZ_256K
-#define MXC91231_CSD0_BASE_ADDR 0x80000000
-#define MXC91231_CSD1_BASE_ADDR 0x90000000
-#define MXC91231_CS0_BASE_ADDR 0xA0000000
-#define MXC91231_CS1_BASE_ADDR 0xA8000000
-#define MXC91231_CS2_BASE_ADDR 0xB0000000
-#define MXC91231_CS3_BASE_ADDR 0xB2000000
-#define MXC91231_CS4_BASE_ADDR 0xB4000000
-#define MXC91231_CS5_BASE_ADDR 0xB6000000
-
-/*
- * This macro defines the physical to virtual address mapping for all the
- * peripheral modules. It is used by passing in the physical address as x
- * and returning the virtual address.
- */
-#define MXC91231_IO_P2V(x) IMX_IO_P2V(x)
-#define MXC91231_IO_ADDRESS(x) IOMEM(MXC91231_IO_P2V(x))
-
-/*
- * Interrupt numbers
- */
-#define MXC91231_INT_GPIO3 0
-#define MXC91231_INT_EL1T_CI 1
-#define MXC91231_INT_EL1T_RFCI 2
-#define MXC91231_INT_EL1T_RFI 3
-#define MXC91231_INT_EL1T_MCU 4
-#define MXC91231_INT_EL1T_IPI 5
-#define MXC91231_INT_MU_GEN 6
-#define MXC91231_INT_GPIO4 7
-#define MXC91231_INT_MMC_SDHC2 8
-#define MXC91231_INT_MMC_SDHC1 9
-#define MXC91231_INT_I2C 10
-#define MXC91231_INT_SSI2 11
-#define MXC91231_INT_SSI1 12
-#define MXC91231_INT_CSPI2 13
-#define MXC91231_INT_CSPI1 14
-#define MXC91231_INT_RTIC 15
-#define MXC91231_INT_SAHARA 15
-#define MXC91231_INT_HAC 15
-#define MXC91231_INT_UART3_RX 16
-#define MXC91231_INT_UART3_TX 17
-#define MXC91231_INT_UART3_MINT 18
-#define MXC91231_INT_ECT 19
-#define MXC91231_INT_SIM_IPB 20
-#define MXC91231_INT_SIM_DATA 21
-#define MXC91231_INT_RNGA 22
-#define MXC91231_INT_DSM_AP 23
-#define MXC91231_INT_KPP 24
-#define MXC91231_INT_RTC 25
-#define MXC91231_INT_PWM 26
-#define MXC91231_INT_GEMK_AP 27
-#define MXC91231_INT_EPIT 28
-#define MXC91231_INT_GPT 29
-#define MXC91231_INT_UART2_RX 30
-#define MXC91231_INT_UART2_TX 31
-#define MXC91231_INT_UART2_MINT 32
-#define MXC91231_INT_NANDFC 33
-#define MXC91231_INT_SDMA 34
-#define MXC91231_INT_USB_WAKEUP 35
-#define MXC91231_INT_USB_SOF 36
-#define MXC91231_INT_PMU_EVTMON 37
-#define MXC91231_INT_USB_FUNC 38
-#define MXC91231_INT_USB_DMA 39
-#define MXC91231_INT_USB_CTRL 40
-#define MXC91231_INT_IPU_ERR 41
-#define MXC91231_INT_IPU_SYN 42
-#define MXC91231_INT_UART1_RX 43
-#define MXC91231_INT_UART1_TX 44
-#define MXC91231_INT_UART1_MINT 45
-#define MXC91231_INT_IIM 46
-#define MXC91231_INT_MU_RX_OR 47
-#define MXC91231_INT_MU_TX_OR 48
-#define MXC91231_INT_SCC_SCM 49
-#define MXC91231_INT_SCC_SMN 50
-#define MXC91231_INT_GPIO2 51
-#define MXC91231_INT_GPIO1 52
-#define MXC91231_INT_MQSPI1 53
-#define MXC91231_INT_MQSPI2 54
-#define MXC91231_INT_WDOG2 55
-#define MXC91231_INT_EXT_INT7 56
-#define MXC91231_INT_EXT_INT6 57
-#define MXC91231_INT_EXT_INT5 58
-#define MXC91231_INT_EXT_INT4 59
-#define MXC91231_INT_EXT_INT3 60
-#define MXC91231_INT_EXT_INT2 61
-#define MXC91231_INT_EXT_INT1 62
-#define MXC91231_INT_EXT_INT0 63
-
-#define MXC91231_MAX_INT_LINES 63
-#define MXC91231_MAX_EXT_LINES 8
-
-#endif /* __MACH_MXC91231_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/system.h b/arch/arm/plat-mxc/include/mach/system.h
index 0417da9f710d..51f02a9d41a3 100644
--- a/arch/arm/plat-mxc/include/mach/system.h
+++ b/arch/arm/plat-mxc/include/mach/system.h
@@ -24,12 +24,6 @@ extern void mx5_cpu_lp_set(enum mxc_cpu_pwr_mode mode);
static inline void arch_idle(void)
{
-#ifdef CONFIG_ARCH_MXC91231
- if (cpu_is_mxc91231()) {
- /* Need this to set DSM low-power mode */
- mxc91231_prepare_idle();
- }
-#endif
/* fix i.MX31 errata TLSbo65953 and i.MX35 errata ENGcm09472 */
if (cpu_is_mx31() || cpu_is_mx35()) {
unsigned long reg = 0;
diff --git a/arch/arm/plat-mxc/include/mach/timex.h b/arch/arm/plat-mxc/include/mach/timex.h
index 2d9624697cc9..d61d5c74817c 100644
--- a/arch/arm/plat-mxc/include/mach/timex.h
+++ b/arch/arm/plat-mxc/include/mach/timex.h
@@ -26,8 +26,6 @@
#define CLOCK_TICK_RATE 16000000
#elif defined CONFIG_ARCH_MX5
#define CLOCK_TICK_RATE 8000000
-#elif defined CONFIG_ARCH_MXC91231
-#define CLOCK_TICK_RATE 13000000
#endif
#endif /* __ASM_ARCH_MXC_TIMEX_H__ */
diff --git a/arch/arm/plat-mxc/include/mach/uncompress.h b/arch/arm/plat-mxc/include/mach/uncompress.h
index 4864b0afd440..d85e2d1c0324 100644
--- a/arch/arm/plat-mxc/include/mach/uncompress.h
+++ b/arch/arm/plat-mxc/include/mach/uncompress.h
@@ -21,7 +21,7 @@
#include <asm/mach-types.h>
-static unsigned long uart_base;
+unsigned long uart_base;
#define UART(x) (*(volatile unsigned long *)(uart_base + (x)))
diff --git a/arch/arm/plat-mxc/system.c b/arch/arm/plat-mxc/system.c
index 3455fc0575a6..8024f2ac177c 100644
--- a/arch/arm/plat-mxc/system.c
+++ b/arch/arm/plat-mxc/system.c
@@ -37,12 +37,6 @@ void arch_reset(char mode, const char *cmd)
{
unsigned int wcr_enable;
-#ifdef CONFIG_ARCH_MXC91231
- if (cpu_is_mxc91231()) {
- mxc91231_arch_reset(mode, cmd);
- return;
- }
-#endif
#ifdef CONFIG_MACH_MX51_EFIKAMX
if (machine_is_mx51_efikamx()) {
mx51_efikamx_reset();
diff --git a/arch/arm/plat-mxc/time.c b/arch/arm/plat-mxc/time.c
index 2237ff8b434f..4b0fe285e83c 100644
--- a/arch/arm/plat-mxc/time.c
+++ b/arch/arm/plat-mxc/time.c
@@ -54,7 +54,7 @@
#define MX2_TSTAT_CAPT (1 << 1)
#define MX2_TSTAT_COMP (1 << 0)
-/* MX31, MX35, MX25, MXC91231, MX5 */
+/* MX31, MX35, MX25, MX5 */
#define V2_TCTL_WAITEN (1 << 3) /* Wait enable mode */
#define V2_TCTL_CLK_IPG (1 << 6)
#define V2_TCTL_FRR (1 << 9)
@@ -106,56 +106,32 @@ static void gpt_irq_acknowledge(void)
__raw_writel(V2_TSTAT_OF1, timer_base + V2_TSTAT);
}
-static cycle_t dummy_get_cycles(struct clocksource *cs)
-{
- return 0;
-}
-
-static cycle_t mx1_2_get_cycles(struct clocksource *cs)
-{
- return __raw_readl(timer_base + MX1_2_TCN);
-}
-
-static cycle_t v2_get_cycles(struct clocksource *cs)
-{
- return __raw_readl(timer_base + V2_TCN);
-}
-
-static struct clocksource clocksource_mxc = {
- .name = "mxc_timer1",
- .rating = 200,
- .read = dummy_get_cycles,
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
+static void __iomem *sched_clock_reg;
static DEFINE_CLOCK_DATA(cd);
unsigned long long notrace sched_clock(void)
{
- cycle_t cyc = clocksource_mxc.read(&clocksource_mxc);
+ cycle_t cyc = sched_clock_reg ? __raw_readl(sched_clock_reg) : 0;
return cyc_to_sched_clock(&cd, cyc, (u32)~0);
}
static void notrace mxc_update_sched_clock(void)
{
- cycle_t cyc = clocksource_mxc.read(&clocksource_mxc);
+ cycle_t cyc = sched_clock_reg ? __raw_readl(sched_clock_reg) : 0;
update_sched_clock(&cd, cyc, (u32)~0);
}
static int __init mxc_clocksource_init(struct clk *timer_clk)
{
unsigned int c = clk_get_rate(timer_clk);
+ void __iomem *reg = timer_base + (timer_is_v2() ? V2_TCN : MX1_2_TCN);
- if (timer_is_v2())
- clocksource_mxc.read = v2_get_cycles;
- else
- clocksource_mxc.read = mx1_2_get_cycles;
+ sched_clock_reg = reg;
init_sched_clock(&cd, mxc_update_sched_clock, 32, c);
- clocksource_register_hz(&clocksource_mxc, c);
-
- return 0;
+ return clocksource_mmio_init(reg, "mxc_timer1", c, 200, 32,
+ clocksource_mmio_readl_up);
}
/* clock event */
diff --git a/arch/arm/plat-nomadik/Kconfig b/arch/arm/plat-nomadik/Kconfig
index 187f4e84bb22..18296ee68802 100644
--- a/arch/arm/plat-nomadik/Kconfig
+++ b/arch/arm/plat-nomadik/Kconfig
@@ -5,6 +5,7 @@
config PLAT_NOMADIK
bool
depends on ARCH_NOMADIK || ARCH_U8500
+ select CLKSRC_MMIO
default y
help
Common platform code for Nomadik and other ST-Ericsson
diff --git a/arch/arm/plat-nomadik/gpio.c b/arch/arm/plat-nomadik/gpio.c
index f49748eca1a3..307b8131aa8c 100644
--- a/arch/arm/plat-nomadik/gpio.c
+++ b/arch/arm/plat-nomadik/gpio.c
@@ -23,6 +23,8 @@
#include <linux/irq.h>
#include <linux/slab.h>
+#include <asm/mach/irq.h>
+
#include <plat/pincfg.h>
#include <mach/hardware.h>
#include <mach/gpio.h>
@@ -681,13 +683,7 @@ static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc,
struct irq_chip *host_chip = irq_get_chip(irq);
unsigned int first_irq;
- if (host_chip->irq_mask_ack)
- host_chip->irq_mask_ack(&desc->irq_data);
- else {
- host_chip->irq_mask(&desc->irq_data);
- if (host_chip->irq_ack)
- host_chip->irq_ack(&desc->irq_data);
- }
+ chained_irq_enter(host_chip, desc);
nmk_chip = irq_get_handler_data(irq);
first_irq = NOMADIK_GPIO_TO_IRQ(nmk_chip->chip.base);
@@ -698,7 +694,7 @@ static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc,
status &= ~BIT(bit);
}
- host_chip->irq_unmask(&desc->irq_data);
+ chained_irq_exit(host_chip, desc);
}
static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
diff --git a/arch/arm/plat-nomadik/include/plat/i2c.h b/arch/arm/plat-nomadik/include/plat/i2c.h
index 1621db67a53d..8ba70ffc31ec 100644
--- a/arch/arm/plat-nomadik/include/plat/i2c.h
+++ b/arch/arm/plat-nomadik/include/plat/i2c.h
@@ -11,8 +11,8 @@
enum i2c_freq_mode {
I2C_FREQ_MODE_STANDARD, /* up to 100 Kb/s */
I2C_FREQ_MODE_FAST, /* up to 400 Kb/s */
+ I2C_FREQ_MODE_HIGH_SPEED, /* up to 3.4 Mb/s */
I2C_FREQ_MODE_FAST_PLUS, /* up to 1 Mb/s */
- I2C_FREQ_MODE_HIGH_SPEED /* up to 3.4 Mb/s */
};
/**
@@ -24,13 +24,15 @@ enum i2c_freq_mode {
* to the values of 14, 6, 2 for a 48 MHz i2c clk
* @tft: Tx FIFO Threshold in bytes
* @rft: Rx FIFO Threshold in bytes
+ * @timeout Slave response timeout(ms)
* @sm: speed mode
*/
struct nmk_i2c_controller {
unsigned long clk_freq;
unsigned short slsu;
- unsigned char tft;
- unsigned char rft;
+ unsigned char tft;
+ unsigned char rft;
+ int timeout;
enum i2c_freq_mode sm;
};
diff --git a/arch/arm/plat-nomadik/timer.c b/arch/arm/plat-nomadik/timer.c
index 41723402006b..ef74e157a9d5 100644
--- a/arch/arm/plat-nomadik/timer.c
+++ b/arch/arm/plat-nomadik/timer.c
@@ -26,29 +26,6 @@
void __iomem *mtu_base; /* Assigned by machine code */
/*
- * Kernel assumes that sched_clock can be called early
- * but the MTU may not yet be initialized.
- */
-static cycle_t nmdk_read_timer_dummy(struct clocksource *cs)
-{
- return 0;
-}
-
-/* clocksource: MTU decrements, so we negate the value being read. */
-static cycle_t nmdk_read_timer(struct clocksource *cs)
-{
- return -readl(mtu_base + MTU_VAL(0));
-}
-
-static struct clocksource nmdk_clksrc = {
- .name = "mtu_0",
- .rating = 200,
- .read = nmdk_read_timer_dummy,
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-/*
* Override the global weak sched_clock symbol with this
* local implementation which uses the clocksource to get some
* better resolution when scheduling the kernel.
@@ -172,12 +149,10 @@ void __init nmdk_timer_init(void)
writel(0, mtu_base + MTU_BGLR(0));
writel(cr | MTU_CRn_ENA, mtu_base + MTU_CR(0));
- /* Now the clock source is ready */
- nmdk_clksrc.read = nmdk_read_timer;
-
- if (clocksource_register_hz(&nmdk_clksrc, rate))
+ if (clocksource_mmio_init(mtu_base + MTU_VAL(0), "mtu_0",
+ rate, 200, 32, clocksource_mmio_readl_down))
pr_err("timer: failed to initialize clock source %s\n",
- nmdk_clksrc.name);
+ "mtu_0");
init_sched_clock(&cd, nomadik_update_sched_clock, 32, rate);
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index cd5f993612fd..49a4c75243fc 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -12,12 +12,14 @@ choice
config ARCH_OMAP1
bool "TI OMAP1"
select CLKDEV_LOOKUP
+ select CLKSRC_MMIO
help
"Systems based on omap7xx, omap15xx or omap16xx"
config ARCH_OMAP2PLUS
bool "TI OMAP2/3/4"
select CLKDEV_LOOKUP
+ select GENERIC_IRQ_CHIP
select OMAP_DM_TIMER
help
"Systems based on OMAP2, OMAP3 or OMAP4"
diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c
index d2adcdda23cf..efb869390199 100644
--- a/arch/arm/plat-omap/gpio.c
+++ b/arch/arm/plat-omap/gpio.c
@@ -17,7 +17,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
@@ -1137,8 +1137,9 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
struct gpio_bank *bank;
u32 retrigger = 0;
int unmasked = 0;
+ struct irq_chip *chip = irq_desc_get_chip(desc);
- desc->irq_data.chip->irq_ack(&desc->irq_data);
+ chained_irq_enter(chip, desc);
bank = irq_get_handler_data(irq);
#ifdef CONFIG_ARCH_OMAP1
@@ -1195,7 +1196,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
configured, we could unmask GPIO bank interrupt immediately */
if (!level_mask && !unmasked) {
unmasked = 1;
- desc->irq_data.chip->irq_unmask(&desc->irq_data);
+ chained_irq_exit(chip, desc);
}
isr |= retrigger;
@@ -1231,7 +1232,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
interrupt */
exit:
if (!unmasked)
- desc->irq_data.chip->irq_unmask(&desc->irq_data);
+ chained_irq_exit(chip, desc);
}
static void gpio_irq_shutdown(struct irq_data *d)
@@ -1372,9 +1373,7 @@ static const struct dev_pm_ops omap_mpuio_dev_pm_ops = {
.resume_noirq = omap_mpuio_resume_noirq,
};
-/* use platform_driver for this, now that there's no longer any
- * point to sys_device (other than not disturbing old code).
- */
+/* use platform_driver for this. */
static struct platform_driver omap_mpuio_driver = {
.driver = {
.name = "mpuio",
@@ -1745,7 +1744,7 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
}
#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS)
-static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg)
+static int omap_gpio_suspend(void)
{
int i;
@@ -1795,12 +1794,12 @@ static int omap_gpio_suspend(struct sys_device *dev, pm_message_t mesg)
return 0;
}
-static int omap_gpio_resume(struct sys_device *dev)
+static void omap_gpio_resume(void)
{
int i;
if (!cpu_class_is_omap2() && !cpu_is_omap16xx())
- return 0;
+ return;
for (i = 0; i < gpio_bank_count; i++) {
struct gpio_bank *bank = &gpio_bank[i];
@@ -1836,21 +1835,13 @@ static int omap_gpio_resume(struct sys_device *dev)
__raw_writel(bank->saved_wakeup, wake_set);
spin_unlock_irqrestore(&bank->lock, flags);
}
-
- return 0;
}
-static struct sysdev_class omap_gpio_sysclass = {
- .name = "gpio",
+static struct syscore_ops omap_gpio_syscore_ops = {
.suspend = omap_gpio_suspend,
.resume = omap_gpio_resume,
};
-static struct sys_device omap_gpio_device = {
- .id = 0,
- .cls = &omap_gpio_sysclass,
-};
-
#endif
#ifdef CONFIG_ARCH_OMAP2PLUS
@@ -2108,21 +2099,14 @@ postcore_initcall(omap_gpio_drv_reg);
static int __init omap_gpio_sysinit(void)
{
- int ret = 0;
-
mpuio_init();
#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS)
- if (cpu_is_omap16xx() || cpu_class_is_omap2()) {
- if (ret == 0) {
- ret = sysdev_class_register(&omap_gpio_sysclass);
- if (ret == 0)
- ret = sysdev_register(&omap_gpio_device);
- }
- }
+ if (cpu_is_omap16xx() || cpu_class_is_omap2())
+ register_syscore_ops(&omap_gpio_syscore_ops);
#endif
- return ret;
+ return 0;
}
arch_initcall(omap_gpio_sysinit);
diff --git a/arch/arm/plat-omap/include/plat/flash.h b/arch/arm/plat-omap/include/plat/flash.h
index 3e6327016b40..3083195123ea 100644
--- a/arch/arm/plat-omap/include/plat/flash.h
+++ b/arch/arm/plat-omap/include/plat/flash.h
@@ -11,6 +11,6 @@
#include <linux/mtd/map.h>
-extern void omap1_set_vpp(struct map_info *map, int enable);
+extern void omap1_set_vpp(struct platform_device *pdev, int enable);
#endif
diff --git a/arch/arm/plat-omap/include/plat/gpmc-smsc911x.h b/arch/arm/plat-omap/include/plat/gpmc-smsc911x.h
index 872de0bf1e6b..ea6c9c88c725 100644
--- a/arch/arm/plat-omap/include/plat/gpmc-smsc911x.h
+++ b/arch/arm/plat-omap/include/plat/gpmc-smsc911x.h
@@ -14,14 +14,14 @@
#ifndef __ASM_ARCH_OMAP_GPMC_SMSC911X_H__
struct omap_smsc911x_platform_data {
+ int id;
int cs;
int gpio_irq;
int gpio_reset;
u32 flags;
};
-#if defined(CONFIG_SMSC911X) || \
- defined(CONFIG_SMSC911X_MODULE)
+#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE)
extern void gpmc_smsc911x_init(struct omap_smsc911x_platform_data *d);
diff --git a/arch/arm/plat-omap/include/plat/smp.h b/arch/arm/plat-omap/include/plat/smp.h
deleted file mode 100644
index 7a10257909ef..000000000000
--- a/arch/arm/plat-omap/include/plat/smp.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * OMAP4 machine specific smp.h
- *
- * Copyright (C) 2009 Texas Instruments, Inc.
- *
- * Author:
- * Santosh Shilimkar <santosh.shilimkar@ti.com>
- *
- * Interface functions needed for the SMP. This file is based on arm
- * realview smp platform.
- * Copyright (c) 2003 ARM Limited.
- *
- * 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 OMAP_ARCH_SMP_H
-#define OMAP_ARCH_SMP_H
-
-#include <asm/hardware/gic.h>
-
-/* Needed for secondary core boot */
-extern void omap_secondary_startup(void);
-extern u32 omap_modify_auxcoreboot0(u32 set_mask, u32 clear_mask);
-extern void omap_auxcoreboot_addr(u32 cpu_addr);
-extern u32 omap_read_auxcoreboot0(void);
-
-/*
- * We use Soft IRQ1 as the IPI
- */
-static inline void smp_cross_call(const struct cpumask *mask, int ipi)
-{
- gic_raise_softirq(mask, ipi);
-}
-
-#endif
diff --git a/arch/arm/plat-omap/include/plat/uncompress.h b/arch/arm/plat-omap/include/plat/uncompress.h
index 30b891c4a93f..ac4b60d9aa29 100644
--- a/arch/arm/plat-omap/include/plat/uncompress.h
+++ b/arch/arm/plat-omap/include/plat/uncompress.h
@@ -27,8 +27,8 @@
#define MDR1_MODE_MASK 0x07
-static volatile u8 *uart_base;
-static int uart_shift;
+volatile u8 *uart_base;
+int uart_shift;
/*
* Store the DEBUG_LL uart number into memory.
@@ -129,7 +129,6 @@ static inline void __arch_decomp_setup(unsigned long arch_id)
DEBUG_LL_OMAP1(3, sx1);
/* omap2 based boards using UART1 */
- DEBUG_LL_OMAP2(1, omap2evm);
DEBUG_LL_OMAP2(1, omap_2430sdp);
DEBUG_LL_OMAP2(1, omap_apollon);
DEBUG_LL_OMAP2(1, omap_h4);
diff --git a/arch/arm/plat-omap/include/plat/usb.h b/arch/arm/plat-omap/include/plat/usb.h
index 02b96c8f6a17..17d3c939775c 100644
--- a/arch/arm/plat-omap/include/plat/usb.h
+++ b/arch/arm/plat-omap/include/plat/usb.h
@@ -113,7 +113,7 @@ extern int omap4430_phy_suspend(struct device *dev, int suspend);
extern void am35x_musb_reset(void);
extern void am35x_musb_phy_power(u8 on);
extern void am35x_musb_clear_irq(void);
-extern void am35x_musb_set_mode(u8 musb_mode);
+extern void am35x_set_mode(u8 musb_mode);
/*
* FIXME correct answer depends on hmc_mode,
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
index 9bbda9acb73b..a37b8eb65b76 100644
--- a/arch/arm/plat-omap/omap_device.c
+++ b/arch/arm/plat-omap/omap_device.c
@@ -536,6 +536,28 @@ int omap_early_device_register(struct omap_device *od)
return 0;
}
+static int _od_runtime_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ return omap_device_idle(pdev);
+}
+
+static int _od_runtime_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ return omap_device_enable(pdev);
+}
+
+static struct dev_power_domain omap_device_power_domain = {
+ .ops = {
+ .runtime_suspend = _od_runtime_suspend,
+ .runtime_resume = _od_runtime_resume,
+ USE_PLATFORM_PM_SLEEP_OPS
+ }
+};
+
/**
* omap_device_register - register an omap_device with one omap_hwmod
* @od: struct omap_device * to register
@@ -549,6 +571,7 @@ int omap_device_register(struct omap_device *od)
pr_debug("omap_device: %s: registering\n", od->pdev.name);
od->pdev.dev.parent = &omap_device_parent;
+ od->pdev.dev.pwr_domain = &omap_device_power_domain;
return platform_device_register(&od->pdev);
}
diff --git a/arch/arm/plat-orion/Makefile b/arch/arm/plat-orion/Makefile
index 56021a72e10c..95a5fc53b6db 100644
--- a/arch/arm/plat-orion/Makefile
+++ b/arch/arm/plat-orion/Makefile
@@ -2,7 +2,7 @@
# Makefile for the linux kernel.
#
-obj-y := irq.o pcie.o time.o
+obj-y := irq.o pcie.o time.o common.o mpp.o
obj-m :=
obj-n :=
obj- :=
diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c
new file mode 100644
index 000000000000..9e5451b3c8e3
--- /dev/null
+++ b/arch/arm/plat-orion/common.c
@@ -0,0 +1,957 @@
+/*
+ * arch/arm/plat-orion/common.c
+ *
+ * Marvell Orion SoC common setup code used by multiple mach-/common.c
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/serial_8250.h>
+#include <linux/mbus.h>
+#include <linux/ata_platform.h>
+#include <linux/mv643xx_eth.h>
+#include <linux/mv643xx_i2c.h>
+#include <net/dsa.h>
+#include <linux/spi/orion_spi.h>
+#include <plat/orion_wdt.h>
+#include <plat/mv_xor.h>
+#include <plat/ehci-orion.h>
+
+/* Fill in the resources structure and link it into the platform
+ device structure. There is always a memory region, and nearly
+ always an interrupt.*/
+static void fill_resources(struct platform_device *device,
+ struct resource *resources,
+ resource_size_t mapbase,
+ resource_size_t size,
+ unsigned int irq)
+{
+ device->resource = resources;
+ device->num_resources = 1;
+ resources[0].flags = IORESOURCE_MEM;
+ resources[0].start = mapbase;
+ resources[0].end = mapbase + size;
+
+ if (irq != NO_IRQ) {
+ device->num_resources++;
+ resources[1].flags = IORESOURCE_IRQ;
+ resources[1].start = irq;
+ resources[1].end = irq;
+ }
+}
+
+/*****************************************************************************
+ * UART
+ ****************************************************************************/
+static void __init uart_complete(
+ struct platform_device *orion_uart,
+ struct plat_serial8250_port *data,
+ struct resource *resources,
+ unsigned int membase,
+ resource_size_t mapbase,
+ unsigned int irq,
+ unsigned int uartclk)
+{
+ data->mapbase = mapbase;
+ data->membase = (void __iomem *)membase;
+ data->irq = irq;
+ data->uartclk = uartclk;
+ orion_uart->dev.platform_data = data;
+
+ fill_resources(orion_uart, resources, mapbase, 0xff, irq);
+ platform_device_register(orion_uart);
+}
+
+/*****************************************************************************
+ * UART0
+ ****************************************************************************/
+static struct plat_serial8250_port orion_uart0_data[] = {
+ {
+ .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
+ .iotype = UPIO_MEM,
+ .regshift = 2,
+ }, {
+ },
+};
+
+static struct resource orion_uart0_resources[2];
+
+static struct platform_device orion_uart0 = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+};
+
+void __init orion_uart0_init(unsigned int membase,
+ resource_size_t mapbase,
+ unsigned int irq,
+ unsigned int uartclk)
+{
+ uart_complete(&orion_uart0, orion_uart0_data, orion_uart0_resources,
+ membase, mapbase, irq, uartclk);
+}
+
+/*****************************************************************************
+ * UART1
+ ****************************************************************************/
+static struct plat_serial8250_port orion_uart1_data[] = {
+ {
+ .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
+ .iotype = UPIO_MEM,
+ .regshift = 2,
+ }, {
+ },
+};
+
+static struct resource orion_uart1_resources[2];
+
+static struct platform_device orion_uart1 = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM1,
+};
+
+void __init orion_uart1_init(unsigned int membase,
+ resource_size_t mapbase,
+ unsigned int irq,
+ unsigned int uartclk)
+{
+ uart_complete(&orion_uart1, orion_uart1_data, orion_uart1_resources,
+ membase, mapbase, irq, uartclk);
+}
+
+/*****************************************************************************
+ * UART2
+ ****************************************************************************/
+static struct plat_serial8250_port orion_uart2_data[] = {
+ {
+ .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
+ .iotype = UPIO_MEM,
+ .regshift = 2,
+ }, {
+ },
+};
+
+static struct resource orion_uart2_resources[2];
+
+static struct platform_device orion_uart2 = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM2,
+};
+
+void __init orion_uart2_init(unsigned int membase,
+ resource_size_t mapbase,
+ unsigned int irq,
+ unsigned int uartclk)
+{
+ uart_complete(&orion_uart2, orion_uart2_data, orion_uart2_resources,
+ membase, mapbase, irq, uartclk);
+}
+
+/*****************************************************************************
+ * UART3
+ ****************************************************************************/
+static struct plat_serial8250_port orion_uart3_data[] = {
+ {
+ .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
+ .iotype = UPIO_MEM,
+ .regshift = 2,
+ }, {
+ },
+};
+
+static struct resource orion_uart3_resources[2];
+
+static struct platform_device orion_uart3 = {
+ .name = "serial8250",
+ .id = 3,
+};
+
+void __init orion_uart3_init(unsigned int membase,
+ resource_size_t mapbase,
+ unsigned int irq,
+ unsigned int uartclk)
+{
+ uart_complete(&orion_uart3, orion_uart3_data, orion_uart3_resources,
+ membase, mapbase, irq, uartclk);
+}
+
+/*****************************************************************************
+ * SoC RTC
+ ****************************************************************************/
+static struct resource orion_rtc_resource[2];
+
+void __init orion_rtc_init(unsigned long mapbase,
+ unsigned long irq)
+{
+ orion_rtc_resource[0].start = mapbase;
+ orion_rtc_resource[0].end = mapbase + SZ_32 - 1;
+ orion_rtc_resource[0].flags = IORESOURCE_MEM;
+ orion_rtc_resource[1].start = irq;
+ orion_rtc_resource[1].end = irq;
+ orion_rtc_resource[1].flags = IORESOURCE_IRQ;
+
+ platform_device_register_simple("rtc-mv", -1, orion_rtc_resource, 2);
+}
+
+/*****************************************************************************
+ * GE
+ ****************************************************************************/
+static __init void ge_complete(
+ struct mv643xx_eth_shared_platform_data *orion_ge_shared_data,
+ struct mbus_dram_target_info *mbus_dram_info, int tclk,
+ struct resource *orion_ge_resource, unsigned long irq,
+ struct platform_device *orion_ge_shared,
+ struct mv643xx_eth_platform_data *eth_data,
+ struct platform_device *orion_ge)
+{
+ orion_ge_shared_data->dram = mbus_dram_info;
+ orion_ge_shared_data->t_clk = tclk;
+ orion_ge_resource->start = irq;
+ orion_ge_resource->end = irq;
+ eth_data->shared = orion_ge_shared;
+ orion_ge->dev.platform_data = eth_data;
+
+ platform_device_register(orion_ge_shared);
+ platform_device_register(orion_ge);
+}
+
+/*****************************************************************************
+ * GE00
+ ****************************************************************************/
+struct mv643xx_eth_shared_platform_data orion_ge00_shared_data;
+
+static struct resource orion_ge00_shared_resources[] = {
+ {
+ .name = "ge00 base",
+ }, {
+ .name = "ge00 err irq",
+ },
+};
+
+static struct platform_device orion_ge00_shared = {
+ .name = MV643XX_ETH_SHARED_NAME,
+ .id = 0,
+ .dev = {
+ .platform_data = &orion_ge00_shared_data,
+ },
+};
+
+static struct resource orion_ge00_resources[] = {
+ {
+ .name = "ge00 irq",
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device orion_ge00 = {
+ .name = MV643XX_ETH_NAME,
+ .id = 0,
+ .num_resources = 1,
+ .resource = orion_ge00_resources,
+ .dev = {
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data,
+ struct mbus_dram_target_info *mbus_dram_info,
+ unsigned long mapbase,
+ unsigned long irq,
+ unsigned long irq_err,
+ int tclk)
+{
+ fill_resources(&orion_ge00_shared, orion_ge00_shared_resources,
+ mapbase + 0x2000, SZ_16K - 1, irq_err);
+ ge_complete(&orion_ge00_shared_data, mbus_dram_info, tclk,
+ orion_ge00_resources, irq, &orion_ge00_shared,
+ eth_data, &orion_ge00);
+}
+
+/*****************************************************************************
+ * GE01
+ ****************************************************************************/
+struct mv643xx_eth_shared_platform_data orion_ge01_shared_data = {
+ .shared_smi = &orion_ge00_shared,
+};
+
+static struct resource orion_ge01_shared_resources[] = {
+ {
+ .name = "ge01 base",
+ }, {
+ .name = "ge01 err irq",
+ },
+};
+
+static struct platform_device orion_ge01_shared = {
+ .name = MV643XX_ETH_SHARED_NAME,
+ .id = 1,
+ .dev = {
+ .platform_data = &orion_ge01_shared_data,
+ },
+};
+
+static struct resource orion_ge01_resources[] = {
+ {
+ .name = "ge01 irq",
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device orion_ge01 = {
+ .name = MV643XX_ETH_NAME,
+ .id = 1,
+ .num_resources = 1,
+ .resource = orion_ge01_resources,
+ .dev = {
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data,
+ struct mbus_dram_target_info *mbus_dram_info,
+ unsigned long mapbase,
+ unsigned long irq,
+ unsigned long irq_err,
+ int tclk)
+{
+ fill_resources(&orion_ge01_shared, orion_ge01_shared_resources,
+ mapbase + 0x2000, SZ_16K - 1, irq_err);
+ ge_complete(&orion_ge01_shared_data, mbus_dram_info, tclk,
+ orion_ge01_resources, irq, &orion_ge01_shared,
+ eth_data, &orion_ge01);
+}
+
+/*****************************************************************************
+ * GE10
+ ****************************************************************************/
+struct mv643xx_eth_shared_platform_data orion_ge10_shared_data = {
+ .shared_smi = &orion_ge00_shared,
+};
+
+static struct resource orion_ge10_shared_resources[] = {
+ {
+ .name = "ge10 base",
+ }, {
+ .name = "ge10 err irq",
+ },
+};
+
+static struct platform_device orion_ge10_shared = {
+ .name = MV643XX_ETH_SHARED_NAME,
+ .id = 1,
+ .dev = {
+ .platform_data = &orion_ge10_shared_data,
+ },
+};
+
+static struct resource orion_ge10_resources[] = {
+ {
+ .name = "ge10 irq",
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device orion_ge10 = {
+ .name = MV643XX_ETH_NAME,
+ .id = 1,
+ .num_resources = 2,
+ .resource = orion_ge10_resources,
+ .dev = {
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+void __init orion_ge10_init(struct mv643xx_eth_platform_data *eth_data,
+ struct mbus_dram_target_info *mbus_dram_info,
+ unsigned long mapbase,
+ unsigned long irq,
+ unsigned long irq_err,
+ int tclk)
+{
+ fill_resources(&orion_ge10_shared, orion_ge10_shared_resources,
+ mapbase + 0x2000, SZ_16K - 1, irq_err);
+ ge_complete(&orion_ge10_shared_data, mbus_dram_info, tclk,
+ orion_ge10_resources, irq, &orion_ge10_shared,
+ eth_data, &orion_ge10);
+}
+
+/*****************************************************************************
+ * GE11
+ ****************************************************************************/
+struct mv643xx_eth_shared_platform_data orion_ge11_shared_data = {
+ .shared_smi = &orion_ge00_shared,
+};
+
+static struct resource orion_ge11_shared_resources[] = {
+ {
+ .name = "ge11 base",
+ }, {
+ .name = "ge11 err irq",
+ },
+};
+
+static struct platform_device orion_ge11_shared = {
+ .name = MV643XX_ETH_SHARED_NAME,
+ .id = 1,
+ .dev = {
+ .platform_data = &orion_ge11_shared_data,
+ },
+};
+
+static struct resource orion_ge11_resources[] = {
+ {
+ .name = "ge11 irq",
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device orion_ge11 = {
+ .name = MV643XX_ETH_NAME,
+ .id = 1,
+ .num_resources = 2,
+ .resource = orion_ge11_resources,
+ .dev = {
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+void __init orion_ge11_init(struct mv643xx_eth_platform_data *eth_data,
+ struct mbus_dram_target_info *mbus_dram_info,
+ unsigned long mapbase,
+ unsigned long irq,
+ unsigned long irq_err,
+ int tclk)
+{
+ fill_resources(&orion_ge11_shared, orion_ge11_shared_resources,
+ mapbase + 0x2000, SZ_16K - 1, irq_err);
+ ge_complete(&orion_ge11_shared_data, mbus_dram_info, tclk,
+ orion_ge11_resources, irq, &orion_ge11_shared,
+ eth_data, &orion_ge11);
+}
+
+/*****************************************************************************
+ * Ethernet switch
+ ****************************************************************************/
+static struct resource orion_switch_resources[] = {
+ {
+ .start = 0,
+ .end = 0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device orion_switch_device = {
+ .name = "dsa",
+ .id = 0,
+ .num_resources = 0,
+ .resource = orion_switch_resources,
+};
+
+void __init orion_ge00_switch_init(struct dsa_platform_data *d, int irq)
+{
+ int i;
+
+ if (irq != NO_IRQ) {
+ orion_switch_resources[0].start = irq;
+ orion_switch_resources[0].end = irq;
+ orion_switch_device.num_resources = 1;
+ }
+
+ d->netdev = &orion_ge00.dev;
+ for (i = 0; i < d->nr_chips; i++)
+ d->chip[i].mii_bus = &orion_ge00_shared.dev;
+ orion_switch_device.dev.platform_data = d;
+
+ platform_device_register(&orion_switch_device);
+}
+
+/*****************************************************************************
+ * I2C
+ ****************************************************************************/
+static struct mv64xxx_i2c_pdata orion_i2c_pdata = {
+ .freq_n = 3,
+ .timeout = 1000, /* Default timeout of 1 second */
+};
+
+static struct resource orion_i2c_resources[2];
+
+static struct platform_device orion_i2c = {
+ .name = MV64XXX_I2C_CTLR_NAME,
+ .id = 0,
+ .dev = {
+ .platform_data = &orion_i2c_pdata,
+ },
+};
+
+static struct mv64xxx_i2c_pdata orion_i2c_1_pdata = {
+ .freq_n = 3,
+ .timeout = 1000, /* Default timeout of 1 second */
+};
+
+static struct resource orion_i2c_1_resources[2];
+
+static struct platform_device orion_i2c_1 = {
+ .name = MV64XXX_I2C_CTLR_NAME,
+ .id = 1,
+ .dev = {
+ .platform_data = &orion_i2c_1_pdata,
+ },
+};
+
+void __init orion_i2c_init(unsigned long mapbase,
+ unsigned long irq,
+ unsigned long freq_m)
+{
+ orion_i2c_pdata.freq_m = freq_m;
+ fill_resources(&orion_i2c, orion_i2c_resources, mapbase,
+ SZ_32 - 1, irq);
+ platform_device_register(&orion_i2c);
+}
+
+void __init orion_i2c_1_init(unsigned long mapbase,
+ unsigned long irq,
+ unsigned long freq_m)
+{
+ orion_i2c_1_pdata.freq_m = freq_m;
+ fill_resources(&orion_i2c_1, orion_i2c_1_resources, mapbase,
+ SZ_32 - 1, irq);
+ platform_device_register(&orion_i2c_1);
+}
+
+/*****************************************************************************
+ * SPI
+ ****************************************************************************/
+static struct orion_spi_info orion_spi_plat_data;
+static struct resource orion_spi_resources;
+
+static struct platform_device orion_spi = {
+ .name = "orion_spi",
+ .id = 0,
+ .dev = {
+ .platform_data = &orion_spi_plat_data,
+ },
+};
+
+static struct orion_spi_info orion_spi_1_plat_data;
+static struct resource orion_spi_1_resources;
+
+static struct platform_device orion_spi_1 = {
+ .name = "orion_spi",
+ .id = 1,
+ .dev = {
+ .platform_data = &orion_spi_1_plat_data,
+ },
+};
+
+/* Note: The SPI silicon core does have interrupts. However the
+ * current Linux software driver does not use interrupts. */
+
+void __init orion_spi_init(unsigned long mapbase,
+ unsigned long tclk)
+{
+ orion_spi_plat_data.tclk = tclk;
+ fill_resources(&orion_spi, &orion_spi_resources,
+ mapbase, SZ_512 - 1, NO_IRQ);
+ platform_device_register(&orion_spi);
+}
+
+void __init orion_spi_1_init(unsigned long mapbase,
+ unsigned long tclk)
+{
+ orion_spi_1_plat_data.tclk = tclk;
+ fill_resources(&orion_spi_1, &orion_spi_1_resources,
+ mapbase, SZ_512 - 1, NO_IRQ);
+ platform_device_register(&orion_spi_1);
+}
+
+/*****************************************************************************
+ * Watchdog
+ ****************************************************************************/
+static struct orion_wdt_platform_data orion_wdt_data;
+
+static struct platform_device orion_wdt_device = {
+ .name = "orion_wdt",
+ .id = -1,
+ .dev = {
+ .platform_data = &orion_wdt_data,
+ },
+ .num_resources = 0,
+};
+
+void __init orion_wdt_init(unsigned long tclk)
+{
+ orion_wdt_data.tclk = tclk;
+ platform_device_register(&orion_wdt_device);
+}
+
+/*****************************************************************************
+ * XOR
+ ****************************************************************************/
+static struct mv_xor_platform_shared_data orion_xor_shared_data;
+
+static u64 orion_xor_dmamask = DMA_BIT_MASK(32);
+
+void __init orion_xor_init_channels(
+ struct mv_xor_platform_data *orion_xor0_data,
+ struct platform_device *orion_xor0_channel,
+ struct mv_xor_platform_data *orion_xor1_data,
+ struct platform_device *orion_xor1_channel)
+{
+ /*
+ * two engines can't do memset simultaneously, this limitation
+ * satisfied by removing memset support from one of the engines.
+ */
+ dma_cap_set(DMA_MEMCPY, orion_xor0_data->cap_mask);
+ dma_cap_set(DMA_XOR, orion_xor0_data->cap_mask);
+ platform_device_register(orion_xor0_channel);
+
+ dma_cap_set(DMA_MEMCPY, orion_xor1_data->cap_mask);
+ dma_cap_set(DMA_MEMSET, orion_xor1_data->cap_mask);
+ dma_cap_set(DMA_XOR, orion_xor1_data->cap_mask);
+ platform_device_register(orion_xor1_channel);
+}
+
+/*****************************************************************************
+ * XOR0
+ ****************************************************************************/
+static struct resource orion_xor0_shared_resources[] = {
+ {
+ .name = "xor 0 low",
+ .flags = IORESOURCE_MEM,
+ }, {
+ .name = "xor 0 high",
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device orion_xor0_shared = {
+ .name = MV_XOR_SHARED_NAME,
+ .id = 0,
+ .dev = {
+ .platform_data = &orion_xor_shared_data,
+ },
+ .num_resources = ARRAY_SIZE(orion_xor0_shared_resources),
+ .resource = orion_xor0_shared_resources,
+};
+
+static struct resource orion_xor00_resources[] = {
+ [0] = {
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct mv_xor_platform_data orion_xor00_data = {
+ .shared = &orion_xor0_shared,
+ .hw_id = 0,
+ .pool_size = PAGE_SIZE,
+};
+
+static struct platform_device orion_xor00_channel = {
+ .name = MV_XOR_NAME,
+ .id = 0,
+ .num_resources = ARRAY_SIZE(orion_xor00_resources),
+ .resource = orion_xor00_resources,
+ .dev = {
+ .dma_mask = &orion_xor_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(64),
+ .platform_data = &orion_xor00_data,
+ },
+};
+
+static struct resource orion_xor01_resources[] = {
+ [0] = {
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct mv_xor_platform_data orion_xor01_data = {
+ .shared = &orion_xor0_shared,
+ .hw_id = 1,
+ .pool_size = PAGE_SIZE,
+};
+
+static struct platform_device orion_xor01_channel = {
+ .name = MV_XOR_NAME,
+ .id = 1,
+ .num_resources = ARRAY_SIZE(orion_xor01_resources),
+ .resource = orion_xor01_resources,
+ .dev = {
+ .dma_mask = &orion_xor_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(64),
+ .platform_data = &orion_xor01_data,
+ },
+};
+
+void __init orion_xor0_init(struct mbus_dram_target_info *mbus_dram_info,
+ unsigned long mapbase_low,
+ unsigned long mapbase_high,
+ unsigned long irq_0,
+ unsigned long irq_1)
+{
+ orion_xor_shared_data.dram = mbus_dram_info;
+
+ orion_xor0_shared_resources[0].start = mapbase_low;
+ orion_xor0_shared_resources[0].end = mapbase_low + 0xff;
+ orion_xor0_shared_resources[1].start = mapbase_high;
+ orion_xor0_shared_resources[1].end = mapbase_high + 0xff;
+
+ orion_xor00_resources[0].start = irq_0;
+ orion_xor00_resources[0].end = irq_0;
+ orion_xor01_resources[0].start = irq_1;
+ orion_xor01_resources[0].end = irq_1;
+
+ platform_device_register(&orion_xor0_shared);
+
+ orion_xor_init_channels(&orion_xor00_data, &orion_xor00_channel,
+ &orion_xor01_data, &orion_xor01_channel);
+}
+
+/*****************************************************************************
+ * XOR1
+ ****************************************************************************/
+static struct resource orion_xor1_shared_resources[] = {
+ {
+ .name = "xor 1 low",
+ .flags = IORESOURCE_MEM,
+ }, {
+ .name = "xor 1 high",
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device orion_xor1_shared = {
+ .name = MV_XOR_SHARED_NAME,
+ .id = 1,
+ .dev = {
+ .platform_data = &orion_xor_shared_data,
+ },
+ .num_resources = ARRAY_SIZE(orion_xor1_shared_resources),
+ .resource = orion_xor1_shared_resources,
+};
+
+static struct resource orion_xor10_resources[] = {
+ [0] = {
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct mv_xor_platform_data orion_xor10_data = {
+ .shared = &orion_xor1_shared,
+ .hw_id = 0,
+ .pool_size = PAGE_SIZE,
+};
+
+static struct platform_device orion_xor10_channel = {
+ .name = MV_XOR_NAME,
+ .id = 2,
+ .num_resources = ARRAY_SIZE(orion_xor10_resources),
+ .resource = orion_xor10_resources,
+ .dev = {
+ .dma_mask = &orion_xor_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(64),
+ .platform_data = &orion_xor10_data,
+ },
+};
+
+static struct resource orion_xor11_resources[] = {
+ [0] = {
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct mv_xor_platform_data orion_xor11_data = {
+ .shared = &orion_xor1_shared,
+ .hw_id = 1,
+ .pool_size = PAGE_SIZE,
+};
+
+static struct platform_device orion_xor11_channel = {
+ .name = MV_XOR_NAME,
+ .id = 3,
+ .num_resources = ARRAY_SIZE(orion_xor11_resources),
+ .resource = orion_xor11_resources,
+ .dev = {
+ .dma_mask = &orion_xor_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(64),
+ .platform_data = &orion_xor11_data,
+ },
+};
+
+void __init orion_xor1_init(unsigned long mapbase_low,
+ unsigned long mapbase_high,
+ unsigned long irq_0,
+ unsigned long irq_1)
+{
+ orion_xor1_shared_resources[0].start = mapbase_low;
+ orion_xor1_shared_resources[0].end = mapbase_low + 0xff;
+ orion_xor1_shared_resources[1].start = mapbase_high;
+ orion_xor1_shared_resources[1].end = mapbase_high + 0xff;
+
+ orion_xor10_resources[0].start = irq_0;
+ orion_xor10_resources[0].end = irq_0;
+ orion_xor11_resources[0].start = irq_1;
+ orion_xor11_resources[0].end = irq_1;
+
+ platform_device_register(&orion_xor1_shared);
+
+ orion_xor_init_channels(&orion_xor10_data, &orion_xor10_channel,
+ &orion_xor11_data, &orion_xor11_channel);
+}
+
+/*****************************************************************************
+ * EHCI
+ ****************************************************************************/
+static struct orion_ehci_data orion_ehci_data = {
+ .phy_version = EHCI_PHY_NA,
+};
+
+static u64 ehci_dmamask = DMA_BIT_MASK(32);
+
+
+/*****************************************************************************
+ * EHCI0
+ ****************************************************************************/
+static struct resource orion_ehci_resources[2];
+
+static struct platform_device orion_ehci = {
+ .name = "orion-ehci",
+ .id = 0,
+ .dev = {
+ .dma_mask = &ehci_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &orion_ehci_data,
+ },
+};
+
+void __init orion_ehci_init(struct mbus_dram_target_info *mbus_dram_info,
+ unsigned long mapbase,
+ unsigned long irq)
+{
+ orion_ehci_data.dram = mbus_dram_info;
+ fill_resources(&orion_ehci, orion_ehci_resources, mapbase, SZ_4K - 1,
+ irq);
+
+ platform_device_register(&orion_ehci);
+}
+
+/*****************************************************************************
+ * EHCI1
+ ****************************************************************************/
+static struct resource orion_ehci_1_resources[2];
+
+static struct platform_device orion_ehci_1 = {
+ .name = "orion-ehci",
+ .id = 1,
+ .dev = {
+ .dma_mask = &ehci_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &orion_ehci_data,
+ },
+};
+
+void __init orion_ehci_1_init(struct mbus_dram_target_info *mbus_dram_info,
+ unsigned long mapbase,
+ unsigned long irq)
+{
+ orion_ehci_data.dram = mbus_dram_info;
+ fill_resources(&orion_ehci_1, orion_ehci_1_resources,
+ mapbase, SZ_4K - 1, irq);
+
+ platform_device_register(&orion_ehci_1);
+}
+
+/*****************************************************************************
+ * EHCI2
+ ****************************************************************************/
+static struct resource orion_ehci_2_resources[2];
+
+static struct platform_device orion_ehci_2 = {
+ .name = "orion-ehci",
+ .id = 2,
+ .dev = {
+ .dma_mask = &ehci_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ .platform_data = &orion_ehci_data,
+ },
+};
+
+void __init orion_ehci_2_init(struct mbus_dram_target_info *mbus_dram_info,
+ unsigned long mapbase,
+ unsigned long irq)
+{
+ orion_ehci_data.dram = mbus_dram_info;
+ fill_resources(&orion_ehci_2, orion_ehci_2_resources,
+ mapbase, SZ_4K - 1, irq);
+
+ platform_device_register(&orion_ehci_2);
+}
+
+/*****************************************************************************
+ * SATA
+ ****************************************************************************/
+static struct resource orion_sata_resources[2] = {
+ {
+ .name = "sata base",
+ }, {
+ .name = "sata irq",
+ },
+};
+
+static struct platform_device orion_sata = {
+ .name = "sata_mv",
+ .id = 0,
+ .dev = {
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+void __init orion_sata_init(struct mv_sata_platform_data *sata_data,
+ struct mbus_dram_target_info *mbus_dram_info,
+ unsigned long mapbase,
+ unsigned long irq)
+{
+ sata_data->dram = mbus_dram_info;
+ orion_sata.dev.platform_data = sata_data;
+ fill_resources(&orion_sata, orion_sata_resources,
+ mapbase, 0x5000 - 1, irq);
+
+ platform_device_register(&orion_sata);
+}
+
+/*****************************************************************************
+ * Cryptographic Engines and Security Accelerator (CESA)
+ ****************************************************************************/
+static struct resource orion_crypto_resources[] = {
+ {
+ .name = "regs",
+ }, {
+ .name = "crypto interrupt",
+ }, {
+ .name = "sram",
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct platform_device orion_crypto = {
+ .name = "mv_crypto",
+ .id = -1,
+};
+
+void __init orion_crypto_init(unsigned long mapbase,
+ unsigned long srambase,
+ unsigned long sram_size,
+ unsigned long irq)
+{
+ fill_resources(&orion_crypto, orion_crypto_resources,
+ mapbase, 0xffff, irq);
+ orion_crypto.num_resources = 3;
+ orion_crypto_resources[2].start = srambase;
+ orion_crypto_resources[2].end = srambase + sram_size - 1;
+
+ platform_device_register(&orion_crypto);
+}
diff --git a/arch/arm/plat-orion/gpio.c b/arch/arm/plat-orion/gpio.c
index a431a138f402..5b4fffab1eb4 100644
--- a/arch/arm/plat-orion/gpio.c
+++ b/arch/arm/plat-orion/gpio.c
@@ -321,59 +321,16 @@ EXPORT_SYMBOL(orion_gpio_set_blink);
* polarity LEVEL mask
*
****************************************************************************/
-static void gpio_irq_ack(struct irq_data *d)
-{
- struct orion_gpio_chip *ochip = irq_data_get_irq_chip_data(d);
- int type = irqd_get_trigger_type(d);
-
- if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
- int pin = d->irq - ochip->secondary_irq_base;
-
- writel(~(1 << pin), GPIO_EDGE_CAUSE(ochip));
- }
-}
-
-static void gpio_irq_mask(struct irq_data *d)
-{
- struct orion_gpio_chip *ochip = irq_data_get_irq_chip_data(d);
- int type = irqd_get_trigger_type(d);
- void __iomem *reg;
- int pin;
-
- if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
- reg = GPIO_EDGE_MASK(ochip);
- else
- reg = GPIO_LEVEL_MASK(ochip);
-
- pin = d->irq - ochip->secondary_irq_base;
-
- writel(readl(reg) & ~(1 << pin), reg);
-}
-
-static void gpio_irq_unmask(struct irq_data *d)
-{
- struct orion_gpio_chip *ochip = irq_data_get_irq_chip_data(d);
- int type = irqd_get_trigger_type(d);
- void __iomem *reg;
- int pin;
-
- if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING))
- reg = GPIO_EDGE_MASK(ochip);
- else
- reg = GPIO_LEVEL_MASK(ochip);
-
- pin = d->irq - ochip->secondary_irq_base;
-
- writel(readl(reg) | (1 << pin), reg);
-}
static int gpio_irq_set_type(struct irq_data *d, u32 type)
{
- struct orion_gpio_chip *ochip = irq_data_get_irq_chip_data(d);
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+ struct irq_chip_type *ct = irq_data_get_chip_type(d);
+ struct orion_gpio_chip *ochip = gc->private;
int pin;
u32 u;
- pin = d->irq - ochip->secondary_irq_base;
+ pin = d->irq - gc->irq_base;
u = readl(GPIO_IO_CONF(ochip)) & (1 << pin);
if (!u) {
@@ -382,18 +339,14 @@ static int gpio_irq_set_type(struct irq_data *d, u32 type)
return -EINVAL;
}
- /*
- * Set edge/level type.
- */
- if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
- __irq_set_handler_locked(d->irq, handle_edge_irq);
- } else if (type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
- __irq_set_handler_locked(d->irq, handle_level_irq);
- } else {
- printk(KERN_ERR "failed to set irq=%d (type=%d)\n",
- d->irq, type);
+ type &= IRQ_TYPE_SENSE_MASK;
+ if (type == IRQ_TYPE_NONE)
return -EINVAL;
- }
+
+ /* Check if we need to change chip and handler */
+ if (!(ct->type & type))
+ if (irq_setup_alt_chip(d, type))
+ return -EINVAL;
/*
* Configure interrupt polarity.
@@ -425,19 +378,12 @@ static int gpio_irq_set_type(struct irq_data *d, u32 type)
return 0;
}
-struct irq_chip orion_gpio_irq_chip = {
- .name = "orion_gpio_irq",
- .irq_ack = gpio_irq_ack,
- .irq_mask = gpio_irq_mask,
- .irq_unmask = gpio_irq_unmask,
- .irq_set_type = gpio_irq_set_type,
-};
-
void __init orion_gpio_init(int gpio_base, int ngpio,
u32 base, int mask_offset, int secondary_irq_base)
{
struct orion_gpio_chip *ochip;
- int i;
+ struct irq_chip_generic *gc;
+ struct irq_chip_type *ct;
if (orion_gpio_chip_count == ARRAY_SIZE(orion_gpio_chips))
return;
@@ -471,15 +417,29 @@ void __init orion_gpio_init(int gpio_base, int ngpio,
writel(0, GPIO_EDGE_MASK(ochip));
writel(0, GPIO_LEVEL_MASK(ochip));
- for (i = 0; i < ngpio; i++) {
- unsigned int irq = secondary_irq_base + i;
-
- irq_set_chip_and_handler(irq, &orion_gpio_irq_chip,
- handle_level_irq);
- irq_set_chip_data(irq, ochip);
- irq_set_status_flags(irq, IRQ_LEVEL);
- set_irq_flags(irq, IRQF_VALID);
- }
+ gc = irq_alloc_generic_chip("orion_gpio_irq", 2, secondary_irq_base,
+ ochip->base, handle_level_irq);
+ gc->private = ochip;
+
+ ct = gc->chip_types;
+ ct->regs.mask = ochip->mask_offset + GPIO_LEVEL_MASK_OFF;
+ ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW;
+ ct->chip.irq_mask = irq_gc_mask_clr_bit;
+ ct->chip.irq_unmask = irq_gc_mask_set_bit;
+ ct->chip.irq_set_type = gpio_irq_set_type;
+
+ ct++;
+ ct->regs.mask = ochip->mask_offset + GPIO_EDGE_MASK_OFF;
+ ct->regs.ack = GPIO_EDGE_CAUSE_OFF;
+ ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
+ ct->chip.irq_ack = irq_gc_ack;
+ ct->chip.irq_mask = irq_gc_mask_clr_bit;
+ ct->chip.irq_unmask = irq_gc_mask_set_bit;
+ ct->chip.irq_set_type = gpio_irq_set_type;
+ ct->handler = handle_edge_irq;
+
+ irq_setup_generic_chip(gc, IRQ_MSK(ngpio), IRQ_GC_INIT_MASK_CACHE,
+ IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE);
}
void orion_gpio_irq_handler(int pinoff)
diff --git a/arch/arm/plat-orion/include/plat/common.h b/arch/arm/plat-orion/include/plat/common.h
new file mode 100644
index 000000000000..a63c357e2ab1
--- /dev/null
+++ b/arch/arm/plat-orion/include/plat/common.h
@@ -0,0 +1,117 @@
+/*
+ * arch/arm/plat-orion/include/plat/common.h
+ *
+ * Marvell Orion SoC common setup code used by different mach-/common.c
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __PLAT_COMMON_H
+#include <linux/mv643xx_eth.h>
+
+struct dsa_platform_data;
+
+void __init orion_uart0_init(unsigned int membase,
+ resource_size_t mapbase,
+ unsigned int irq,
+ unsigned int uartclk);
+
+void __init orion_uart1_init(unsigned int membase,
+ resource_size_t mapbase,
+ unsigned int irq,
+ unsigned int uartclk);
+
+void __init orion_uart2_init(unsigned int membase,
+ resource_size_t mapbase,
+ unsigned int irq,
+ unsigned int uartclk);
+
+void __init orion_uart3_init(unsigned int membase,
+ resource_size_t mapbase,
+ unsigned int irq,
+ unsigned int uartclk);
+
+void __init orion_rtc_init(unsigned long mapbase,
+ unsigned long irq);
+
+void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data,
+ struct mbus_dram_target_info *mbus_dram_info,
+ unsigned long mapbase,
+ unsigned long irq,
+ unsigned long irq_err,
+ int tclk);
+
+void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data,
+ struct mbus_dram_target_info *mbus_dram_info,
+ unsigned long mapbase,
+ unsigned long irq,
+ unsigned long irq_err,
+ int tclk);
+
+void __init orion_ge10_init(struct mv643xx_eth_platform_data *eth_data,
+ struct mbus_dram_target_info *mbus_dram_info,
+ unsigned long mapbase,
+ unsigned long irq,
+ unsigned long irq_err,
+ int tclk);
+
+void __init orion_ge11_init(struct mv643xx_eth_platform_data *eth_data,
+ struct mbus_dram_target_info *mbus_dram_info,
+ unsigned long mapbase,
+ unsigned long irq,
+ unsigned long irq_err,
+ int tclk);
+
+void __init orion_ge00_switch_init(struct dsa_platform_data *d,
+ int irq);
+void __init orion_i2c_init(unsigned long mapbase,
+ unsigned long irq,
+ unsigned long freq_m);
+
+void __init orion_i2c_1_init(unsigned long mapbase,
+ unsigned long irq,
+ unsigned long freq_m);
+
+void __init orion_spi_init(unsigned long mapbase,
+ unsigned long tclk);
+
+void __init orion_spi_1_init(unsigned long mapbase,
+ unsigned long tclk);
+
+void __init orion_wdt_init(unsigned long tclk);
+
+void __init orion_xor0_init(struct mbus_dram_target_info *mbus_dram_info,
+ unsigned long mapbase_low,
+ unsigned long mapbase_high,
+ unsigned long irq_0,
+ unsigned long irq_1);
+
+void __init orion_xor1_init(unsigned long mapbase_low,
+ unsigned long mapbase_high,
+ unsigned long irq_0,
+ unsigned long irq_1);
+
+void __init orion_ehci_init(struct mbus_dram_target_info *mbus_dram_info,
+ unsigned long mapbase,
+ unsigned long irq);
+
+void __init orion_ehci_1_init(struct mbus_dram_target_info *mbus_dram_info,
+ unsigned long mapbase,
+ unsigned long irq);
+
+void __init orion_ehci_2_init(struct mbus_dram_target_info *mbus_dram_info,
+ unsigned long mapbase,
+ unsigned long irq);
+
+void __init orion_sata_init(struct mv_sata_platform_data *sata_data,
+ struct mbus_dram_target_info *mbus_dram_info,
+ unsigned long mapbase,
+ unsigned long irq);
+
+void __init orion_crypto_init(unsigned long mapbase,
+ unsigned long srambase,
+ unsigned long sram_size,
+ unsigned long irq);
+#endif
diff --git a/arch/arm/plat-orion/include/plat/gpio.h b/arch/arm/plat-orion/include/plat/gpio.h
index 5578b9803fc6..3075b9fdde83 100644
--- a/arch/arm/plat-orion/include/plat/gpio.h
+++ b/arch/arm/plat-orion/include/plat/gpio.h
@@ -39,7 +39,6 @@ void __init orion_gpio_init(int gpio_base, int ngpio,
/*
* GPIO interrupt handling.
*/
-extern struct irq_chip orion_gpio_irq_chip;
void orion_gpio_irq_handler(int irqoff);
diff --git a/arch/arm/plat-orion/include/plat/mpp.h b/arch/arm/plat-orion/include/plat/mpp.h
new file mode 100644
index 000000000000..723adce99f41
--- /dev/null
+++ b/arch/arm/plat-orion/include/plat/mpp.h
@@ -0,0 +1,34 @@
+/*
+ * arch/arm/plat-orion/include/plat/mpp.h
+ *
+ * Marvell Orion SoC MPP handling.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __PLAT_MPP_H
+#define __PLAT_MPP_H
+
+#define MPP_NUM(x) ((x) & 0xff)
+#define MPP_SEL(x) (((x) >> 8) & 0xf)
+
+/* This is the generic MPP macro, without any variant information.
+ Each machine architecture is expected to extend this with further
+ bit fields indicating which MPP configurations are valid for a
+ specific variant. */
+
+#define GENERIC_MPP(_num, _sel, _in, _out) ( \
+ /* MPP number */ ((_num) & 0xff) | \
+ /* MPP select value */ (((_sel) & 0xf) << 8) | \
+ /* may be input signal */ ((!!(_in)) << 12) | \
+ /* may be output signal */ ((!!(_out)) << 13))
+
+#define MPP_INPUT_MASK GENERIC_MPP(0, 0x0, 1, 0)
+#define MPP_OUTPUT_MASK GENERIC_MPP(0, 0x0, 0, 1)
+
+void __init orion_mpp_conf(unsigned int *mpp_list, unsigned int variant_mask,
+ unsigned int mpp_max, unsigned int dev_bus);
+
+#endif
diff --git a/arch/arm/plat-orion/irq.c b/arch/arm/plat-orion/irq.c
index d8d638e09f8f..2d5b9c1ef389 100644
--- a/arch/arm/plat-orion/irq.c
+++ b/arch/arm/plat-orion/irq.c
@@ -14,52 +14,21 @@
#include <linux/io.h>
#include <plat/irq.h>
-static void orion_irq_mask(struct irq_data *d)
-{
- void __iomem *maskaddr = irq_data_get_irq_chip_data(d);
- u32 mask;
-
- mask = readl(maskaddr);
- mask &= ~(1 << (d->irq & 31));
- writel(mask, maskaddr);
-}
-
-static void orion_irq_unmask(struct irq_data *d)
-{
- void __iomem *maskaddr = irq_data_get_irq_chip_data(d);
- u32 mask;
-
- mask = readl(maskaddr);
- mask |= 1 << (d->irq & 31);
- writel(mask, maskaddr);
-}
-
-static struct irq_chip orion_irq_chip = {
- .name = "orion_irq",
- .irq_mask = orion_irq_mask,
- .irq_mask_ack = orion_irq_mask,
- .irq_unmask = orion_irq_unmask,
-};
-
void __init orion_irq_init(unsigned int irq_start, void __iomem *maskaddr)
{
- unsigned int i;
+ struct irq_chip_generic *gc;
+ struct irq_chip_type *ct;
/*
* Mask all interrupts initially.
*/
writel(0, maskaddr);
- /*
- * Register IRQ sources.
- */
- for (i = 0; i < 32; i++) {
- unsigned int irq = irq_start + i;
-
- irq_set_chip_and_handler(irq, &orion_irq_chip,
- handle_level_irq);
- irq_set_chip_data(irq, maskaddr);
- irq_set_status_flags(irq, IRQ_LEVEL);
- set_irq_flags(irq, IRQF_VALID);
- }
+ gc = irq_alloc_generic_chip("orion_irq", 1, irq_start, maskaddr,
+ handle_level_irq);
+ ct = gc->chip_types;
+ ct->chip.irq_mask = irq_gc_mask_clr_bit;
+ ct->chip.irq_unmask = irq_gc_mask_set_bit;
+ irq_setup_generic_chip(gc, IRQ_MSK(32), IRQ_GC_INIT_MASK_CACHE,
+ IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE);
}
diff --git a/arch/arm/plat-orion/mpp.c b/arch/arm/plat-orion/mpp.c
new file mode 100644
index 000000000000..91553432711d
--- /dev/null
+++ b/arch/arm/plat-orion/mpp.c
@@ -0,0 +1,78 @@
+/*
+ * arch/arm/plat-orion/mpp.c
+ *
+ * MPP functions for Marvell orion SoCs
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/mbus.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <mach/hardware.h>
+#include <plat/mpp.h>
+
+/* Address of the ith MPP control register */
+static __init unsigned long mpp_ctrl_addr(unsigned int i,
+ unsigned long dev_bus)
+{
+ return dev_bus + (i) * 4;
+}
+
+
+void __init orion_mpp_conf(unsigned int *mpp_list, unsigned int variant_mask,
+ unsigned int mpp_max, unsigned int dev_bus)
+{
+ unsigned int mpp_nr_regs = (1 + mpp_max/8);
+ u32 mpp_ctrl[mpp_nr_regs];
+ int i;
+
+ printk(KERN_DEBUG "initial MPP regs:");
+ for (i = 0; i < mpp_nr_regs; i++) {
+ mpp_ctrl[i] = readl(mpp_ctrl_addr(i, dev_bus));
+ printk(" %08x", mpp_ctrl[i]);
+ }
+ printk("\n");
+
+ for ( ; *mpp_list; mpp_list++) {
+ unsigned int num = MPP_NUM(*mpp_list);
+ unsigned int sel = MPP_SEL(*mpp_list);
+ int shift, gpio_mode;
+
+ if (num > mpp_max) {
+ printk(KERN_ERR "orion_mpp_conf: invalid MPP "
+ "number (%u)\n", num);
+ continue;
+ }
+ if (variant_mask & !(*mpp_list & variant_mask)) {
+ printk(KERN_WARNING
+ "orion_mpp_conf: requested MPP%u config "
+ "unavailable on this hardware\n", num);
+ continue;
+ }
+
+ shift = (num & 7) << 2;
+ mpp_ctrl[num / 8] &= ~(0xf << shift);
+ mpp_ctrl[num / 8] |= sel << shift;
+
+ gpio_mode = 0;
+ if (*mpp_list & MPP_INPUT_MASK)
+ gpio_mode |= GPIO_INPUT_OK;
+ if (*mpp_list & MPP_OUTPUT_MASK)
+ gpio_mode |= GPIO_OUTPUT_OK;
+ if (sel != 0)
+ gpio_mode = 0;
+ orion_gpio_set_valid(num, gpio_mode);
+ }
+
+ printk(KERN_DEBUG " final MPP regs:");
+ for (i = 0; i < mpp_nr_regs; i++) {
+ writel(mpp_ctrl[i], mpp_ctrl_addr(i, dev_bus));
+ printk(" %08x", mpp_ctrl[i]);
+ }
+ printk("\n");
+}
diff --git a/arch/arm/plat-orion/time.c b/arch/arm/plat-orion/time.c
index 742b0323c57b..69a61367e4b8 100644
--- a/arch/arm/plat-orion/time.c
+++ b/arch/arm/plat-orion/time.c
@@ -81,24 +81,6 @@ static void __init setup_sched_clock(unsigned long tclk)
}
/*
- * Clocksource handling.
- */
-static cycle_t orion_clksrc_read(struct clocksource *cs)
-{
- return 0xffffffff - readl(timer_base + TIMER0_VAL_OFF);
-}
-
-static struct clocksource orion_clksrc = {
- .name = "orion_clocksource",
- .rating = 300,
- .read = orion_clksrc_read,
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-
-
-/*
* Clockevent handling.
*/
static int
@@ -247,7 +229,8 @@ orion_time_init(u32 _bridge_base, u32 _bridge_timer1_clr_mask,
writel(u & ~BRIDGE_INT_TIMER0, bridge_base + BRIDGE_MASK_OFF);
u = readl(timer_base + TIMER_CTRL_OFF);
writel(u | TIMER0_EN | TIMER0_RELOAD_EN, timer_base + TIMER_CTRL_OFF);
- clocksource_register_hz(&orion_clksrc, tclk);
+ clocksource_mmio_init(timer_base + TIMER0_VAL_OFF, "orion_clocksource",
+ tclk, 300, 32, clocksource_mmio_readl_down);
/*
* Setup clockevent timer (interrupt-driven).
diff --git a/arch/arm/plat-pxa/gpio.c b/arch/arm/plat-pxa/gpio.c
index dce088f45678..48ebb9479b61 100644
--- a/arch/arm/plat-pxa/gpio.c
+++ b/arch/arm/plat-pxa/gpio.c
@@ -15,7 +15,7 @@
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/io.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/slab.h>
#include <mach/gpio.h>
@@ -295,7 +295,7 @@ void __init pxa_init_gpio(int mux_irq, int start, int end, set_wake_t fn)
}
#ifdef CONFIG_PM
-static int pxa_gpio_suspend(struct sys_device *dev, pm_message_t state)
+static int pxa_gpio_suspend(void)
{
struct pxa_gpio_chip *c;
int gpio;
@@ -312,7 +312,7 @@ static int pxa_gpio_suspend(struct sys_device *dev, pm_message_t state)
return 0;
}
-static int pxa_gpio_resume(struct sys_device *dev)
+static void pxa_gpio_resume(void)
{
struct pxa_gpio_chip *c;
int gpio;
@@ -326,22 +326,13 @@ static int pxa_gpio_resume(struct sys_device *dev)
__raw_writel(c->saved_gfer, c->regbase + GFER_OFFSET);
__raw_writel(c->saved_gpdr, c->regbase + GPDR_OFFSET);
}
- return 0;
}
#else
#define pxa_gpio_suspend NULL
#define pxa_gpio_resume NULL
#endif
-struct sysdev_class pxa_gpio_sysclass = {
- .name = "gpio",
+struct syscore_ops pxa_gpio_syscore_ops = {
.suspend = pxa_gpio_suspend,
.resume = pxa_gpio_resume,
};
-
-static int __init pxa_gpio_init(void)
-{
- return sysdev_class_register(&pxa_gpio_sysclass);
-}
-
-core_initcall(pxa_gpio_init);
diff --git a/arch/arm/plat-pxa/mfp.c b/arch/arm/plat-pxa/mfp.c
index a9aa5ad3f4eb..be12eadcce20 100644
--- a/arch/arm/plat-pxa/mfp.c
+++ b/arch/arm/plat-pxa/mfp.c
@@ -17,7 +17,6 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
-#include <linux/sysdev.h>
#include <plat/mfp.h>
diff --git a/arch/arm/plat-s3c24xx/devs.c b/arch/arm/plat-s3c24xx/devs.c
index 268f3ed0a105..73667994518a 100644
--- a/arch/arm/plat-s3c24xx/devs.c
+++ b/arch/arm/plat-s3c24xx/devs.c
@@ -22,6 +22,7 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/dma-mapping.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -233,6 +234,46 @@ void __init s3c24xx_udc_set_platdata(struct s3c2410_udc_mach_info *pd)
}
}
+/* USB High Speed 2.0 Device (Gadget) */
+static struct resource s3c_hsudc_resource[] = {
+ [0] = {
+ .start = S3C2416_PA_HSUDC,
+ .end = S3C2416_PA_HSUDC + S3C2416_SZ_HSUDC - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_USBD,
+ .end = IRQ_USBD,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static u64 s3c_hsudc_dmamask = DMA_BIT_MASK(32);
+
+struct platform_device s3c_device_usb_hsudc = {
+ .name = "s3c-hsudc",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(s3c_hsudc_resource),
+ .resource = s3c_hsudc_resource,
+ .dev = {
+ .dma_mask = &s3c_hsudc_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
+ },
+};
+
+void __init s3c24xx_hsudc_set_platdata(struct s3c24xx_hsudc_platdata *pd)
+{
+ struct s3c24xx_hsudc_platdata *npd;
+
+ npd = kmalloc(sizeof(*npd), GFP_KERNEL);
+ if (npd) {
+ memcpy(npd, pd, sizeof(*npd));
+ s3c_device_usb_hsudc.dev.platform_data = npd;
+ } else {
+ printk(KERN_ERR "no memory for udc platform data\n");
+ }
+}
+
/* IIS */
static struct resource s3c_iis_resource[] = {
diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c
index 27ea852e3370..c10d10c56e2e 100644
--- a/arch/arm/plat-s3c24xx/dma.c
+++ b/arch/arm/plat-s3c24xx/dma.c
@@ -22,7 +22,7 @@
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/io.h>
@@ -1195,19 +1195,12 @@ int s3c2410_dma_getposition(unsigned int channel, dma_addr_t *src, dma_addr_t *d
EXPORT_SYMBOL(s3c2410_dma_getposition);
-static inline struct s3c2410_dma_chan *to_dma_chan(struct sys_device *dev)
-{
- return container_of(dev, struct s3c2410_dma_chan, dev);
-}
-
-/* system device class */
+/* system core operations */
#ifdef CONFIG_PM
-static int s3c2410_dma_suspend(struct sys_device *dev, pm_message_t state)
+static void s3c2410_dma_suspend_chan(s3c2410_dma_chan *cp)
{
- struct s3c2410_dma_chan *cp = to_dma_chan(dev);
-
printk(KERN_DEBUG "suspending dma channel %d\n", cp->number);
if (dma_rdreg(cp, S3C2410_DMA_DMASKTRIG) & S3C2410_DMASKTRIG_ON) {
@@ -1222,13 +1215,21 @@ static int s3c2410_dma_suspend(struct sys_device *dev, pm_message_t state)
s3c2410_dma_dostop(cp);
}
+}
+
+static int s3c2410_dma_suspend(void)
+{
+ struct s3c2410_dma_chan *cp = s3c2410_chans;
+ int channel;
+
+ for (channel = 0; channel < dma_channels; cp++, channel++)
+ s3c2410_dma_suspend_chan(cp);
return 0;
}
-static int s3c2410_dma_resume(struct sys_device *dev)
+static void s3c2410_dma_resume_chan(struct s3c2410_dma_chan *cp)
{
- struct s3c2410_dma_chan *cp = to_dma_chan(dev);
unsigned int no = cp->number | DMACH_LOW_LEVEL;
/* restore channel's hardware configuration */
@@ -1249,13 +1250,21 @@ static int s3c2410_dma_resume(struct sys_device *dev)
return 0;
}
+static void s3c2410_dma_resume(void)
+{
+ struct s3c2410_dma_chan *cp = s3c2410_chans + dma_channels - 1;
+ int channel;
+
+ for (channel = dma_channels - 1; channel >= 0; cp++, channel--)
+ s3c2410_dma_resume_chan(cp);
+}
+
#else
#define s3c2410_dma_suspend NULL
#define s3c2410_dma_resume NULL
#endif /* CONFIG_PM */
-struct sysdev_class dma_sysclass = {
- .name = "s3c24xx-dma",
+struct syscore_ops dma_syscore_ops = {
.suspend = s3c2410_dma_suspend,
.resume = s3c2410_dma_resume,
};
@@ -1269,39 +1278,14 @@ static void s3c2410_dma_cache_ctor(void *p)
/* initialisation code */
-static int __init s3c24xx_dma_sysclass_init(void)
+static int __init s3c24xx_dma_syscore_init(void)
{
- int ret = sysdev_class_register(&dma_sysclass);
-
- if (ret != 0)
- printk(KERN_ERR "dma sysclass registration failed\n");
-
- return ret;
-}
-
-core_initcall(s3c24xx_dma_sysclass_init);
-
-static int __init s3c24xx_dma_sysdev_register(void)
-{
- struct s3c2410_dma_chan *cp = s3c2410_chans;
- int channel, ret;
-
- for (channel = 0; channel < dma_channels; cp++, channel++) {
- cp->dev.cls = &dma_sysclass;
- cp->dev.id = channel;
- ret = sysdev_register(&cp->dev);
-
- if (ret) {
- printk(KERN_ERR "error registering dev for dma %d\n",
- channel);
- return ret;
- }
- }
+ register_syscore_ops(&dma_syscore_ops);
return 0;
}
-late_initcall(s3c24xx_dma_sysdev_register);
+late_initcall(s3c24xx_dma_syscore_init);
int __init s3c24xx_dma_init(unsigned int channels, unsigned int irq,
unsigned int stride)
diff --git a/arch/arm/plat-s3c24xx/include/plat/udc.h b/arch/arm/plat-s3c24xx/include/plat/udc.h
index 80457c6414aa..f63884242506 100644
--- a/arch/arm/plat-s3c24xx/include/plat/udc.h
+++ b/arch/arm/plat-s3c24xx/include/plat/udc.h
@@ -37,4 +37,21 @@ struct s3c2410_udc_mach_info {
extern void __init s3c24xx_udc_set_platdata(struct s3c2410_udc_mach_info *);
+/**
+ * s3c24xx_hsudc_platdata - Platform data for USB High-Speed gadget controller.
+ * @epnum: Number of endpoints to be instantiated by the controller driver.
+ * @gpio_init: Platform specific USB related GPIO initialization.
+ * @gpio_uninit: Platform specific USB releted GPIO uninitialzation.
+ *
+ * Representation of platform data for the S3C24XX USB 2.0 High Speed gadget
+ * controllers.
+ */
+struct s3c24xx_hsudc_platdata {
+ unsigned int epnum;
+ void (*gpio_init)(void);
+ void (*gpio_uninit)(void);
+};
+
+extern void __init s3c24xx_hsudc_set_platdata(struct s3c24xx_hsudc_platdata *pd);
+
#endif /* __ASM_ARM_ARCH_UDC_H */
diff --git a/arch/arm/plat-s3c24xx/irq-pm.c b/arch/arm/plat-s3c24xx/irq-pm.c
index c3624d898630..0efb2e2848c8 100644
--- a/arch/arm/plat-s3c24xx/irq-pm.c
+++ b/arch/arm/plat-s3c24xx/irq-pm.c
@@ -14,7 +14,6 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
-#include <linux/sysdev.h>
#include <linux/irq.h>
#include <plat/cpu.h>
@@ -65,7 +64,7 @@ static unsigned long save_extint[3];
static unsigned long save_eintflt[4];
static unsigned long save_eintmask;
-int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state)
+int s3c24xx_irq_suspend(void)
{
unsigned int i;
@@ -81,7 +80,7 @@ int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state)
return 0;
}
-int s3c24xx_irq_resume(struct sys_device *dev)
+void s3c24xx_irq_resume(void)
{
unsigned int i;
@@ -93,6 +92,4 @@ int s3c24xx_irq_resume(struct sys_device *dev)
s3c_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
__raw_writel(save_eintmask, S3C24XX_EINTMASK);
-
- return 0;
}
diff --git a/arch/arm/plat-s5p/Kconfig b/arch/arm/plat-s5p/Kconfig
index 849229716586..6751bcf7b888 100644
--- a/arch/arm/plat-s5p/Kconfig
+++ b/arch/arm/plat-s5p/Kconfig
@@ -85,6 +85,11 @@ config S5P_DEV_CSIS1
help
Compile in platform device definitions for MIPI-CSIS channel 1
+config S5P_DEV_USB_EHCI
+ bool
+ help
+ Compile in platform device definition for USB EHCI
+
config S5P_SETUP_MIPIPHY
bool
help
diff --git a/arch/arm/plat-s5p/Makefile b/arch/arm/plat-s5p/Makefile
index 42afff7f60be..e234cc4d49a0 100644
--- a/arch/arm/plat-s5p/Makefile
+++ b/arch/arm/plat-s5p/Makefile
@@ -33,4 +33,5 @@ obj-$(CONFIG_S5P_DEV_FIMC3) += dev-fimc3.o
obj-$(CONFIG_S5P_DEV_ONENAND) += dev-onenand.o
obj-$(CONFIG_S5P_DEV_CSIS0) += dev-csis0.o
obj-$(CONFIG_S5P_DEV_CSIS1) += dev-csis1.o
+obj-$(CONFIG_S5P_DEV_USB_EHCI) += dev-ehci.o
obj-$(CONFIG_S5P_SETUP_MIPIPHY) += setup-mipiphy.o
diff --git a/arch/arm/plat-s5p/dev-ehci.c b/arch/arm/plat-s5p/dev-ehci.c
new file mode 100644
index 000000000000..94080fff9e9b
--- /dev/null
+++ b/arch/arm/plat-s5p/dev-ehci.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 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/platform_device.h>
+#include <mach/irqs.h>
+#include <mach/map.h>
+#include <plat/devs.h>
+#include <plat/ehci.h>
+#include <plat/usb-phy.h>
+
+/* USB EHCI Host Controller registration */
+static struct resource s5p_ehci_resource[] = {
+ [0] = {
+ .start = S5P_PA_EHCI,
+ .end = S5P_PA_EHCI + SZ_256 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_USB_HOST,
+ .end = IRQ_USB_HOST,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static u64 s5p_device_ehci_dmamask = 0xffffffffUL;
+
+struct platform_device s5p_device_ehci = {
+ .name = "s5p-ehci",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(s5p_ehci_resource),
+ .resource = s5p_ehci_resource,
+ .dev = {
+ .dma_mask = &s5p_device_ehci_dmamask,
+ .coherent_dma_mask = 0xffffffffUL
+ }
+};
+
+void __init s5p_ehci_set_platdata(struct s5p_ehci_platdata *pd)
+{
+ struct s5p_ehci_platdata *npd;
+
+ npd = s3c_set_platdata(pd, sizeof(struct s5p_ehci_platdata),
+ &s5p_device_ehci);
+
+ if (!npd->phy_init)
+ npd->phy_init = s5p_usb_phy_init;
+ if (!npd->phy_exit)
+ npd->phy_exit = s5p_usb_phy_exit;
+}
diff --git a/arch/arm/plat-s5p/include/plat/ehci.h b/arch/arm/plat-s5p/include/plat/ehci.h
new file mode 100644
index 000000000000..6ae6810c7569
--- /dev/null
+++ b/arch/arm/plat-s5p/include/plat/ehci.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2011 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_S5P_EHCI_H
+#define __PLAT_S5P_EHCI_H
+
+struct s5p_ehci_platdata {
+ int (*phy_init)(struct platform_device *pdev, int type);
+ int (*phy_exit)(struct platform_device *pdev, int type);
+};
+
+extern void s5p_ehci_set_platdata(struct s5p_ehci_platdata *pd);
+
+#endif /* __PLAT_S5P_EHCI_H */
diff --git a/arch/arm/plat-s5p/include/plat/map-s5p.h b/arch/arm/plat-s5p/include/plat/map-s5p.h
index d973d39666a3..a6c3d327ce72 100644
--- a/arch/arm/plat-s5p/include/plat/map-s5p.h
+++ b/arch/arm/plat-s5p/include/plat/map-s5p.h
@@ -39,7 +39,7 @@
#define S5P_VA_TWD S5P_VA_COREPERI(0x600)
#define S5P_VA_GIC_DIST S5P_VA_COREPERI(0x1000)
-#define S3C_VA_USB_HSPHY S3C_ADDR(0x02900000)
+#define S5P_VA_USB_HSPHY S3C_ADDR(0x02900000)
#define VA_VIC(x) (S3C_VA_IRQ + ((x) * 0x10000))
#define VA_VIC0 VA_VIC(0)
diff --git a/arch/arm/plat-s5p/include/plat/usb-phy.h b/arch/arm/plat-s5p/include/plat/usb-phy.h
new file mode 100644
index 000000000000..6dd6bcfca3ce
--- /dev/null
+++ b/arch/arm/plat-s5p/include/plat/usb-phy.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2011 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_S5P_USB_PHY_H
+#define __PLAT_S5P_USB_PHY_H
+
+enum s5p_usb_phy_type {
+ S5P_USB_PHY_DEVICE,
+ S5P_USB_PHY_HOST,
+};
+
+extern int s5p_usb_phy_init(struct platform_device *pdev, int type);
+extern int s5p_usb_phy_exit(struct platform_device *pdev, int type);
+
+#endif /* __PLAT_S5P_REGS_USB_PHY_H */
diff --git a/arch/arm/plat-s5p/irq-gpioint.c b/arch/arm/plat-s5p/irq-gpioint.c
index cd6d67c8382a..135abda31c9a 100644
--- a/arch/arm/plat-s5p/irq-gpioint.c
+++ b/arch/arm/plat-s5p/irq-gpioint.c
@@ -41,72 +41,11 @@ struct s5p_gpioint_bank {
LIST_HEAD(banks);
-static int s5p_gpioint_get_offset(struct irq_data *data)
+static int s5p_gpioint_set_type(struct irq_data *d, unsigned int type)
{
- struct s3c_gpio_chip *chip = irq_data_get_irq_handler_data(data);
- return data->irq - chip->irq_base;
-}
-
-static void s5p_gpioint_ack(struct irq_data *data)
-{
- struct s3c_gpio_chip *chip = irq_data_get_irq_handler_data(data);
- int group, offset, pend_offset;
- unsigned int value;
-
- group = chip->group;
- offset = s5p_gpioint_get_offset(data);
- pend_offset = REG_OFFSET(group);
-
- value = __raw_readl(GPIO_BASE(chip) + PEND_OFFSET + pend_offset);
- value |= BIT(offset);
- __raw_writel(value, GPIO_BASE(chip) + PEND_OFFSET + pend_offset);
-}
-
-static void s5p_gpioint_mask(struct irq_data *data)
-{
- struct s3c_gpio_chip *chip = irq_data_get_irq_handler_data(data);
- int group, offset, mask_offset;
- unsigned int value;
-
- group = chip->group;
- offset = s5p_gpioint_get_offset(data);
- mask_offset = REG_OFFSET(group);
-
- value = __raw_readl(GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
- value |= BIT(offset);
- __raw_writel(value, GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
-}
-
-static void s5p_gpioint_unmask(struct irq_data *data)
-{
- struct s3c_gpio_chip *chip = irq_data_get_irq_handler_data(data);
- int group, offset, mask_offset;
- unsigned int value;
-
- group = chip->group;
- offset = s5p_gpioint_get_offset(data);
- mask_offset = REG_OFFSET(group);
-
- value = __raw_readl(GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
- value &= ~BIT(offset);
- __raw_writel(value, GPIO_BASE(chip) + MASK_OFFSET + mask_offset);
-}
-
-static void s5p_gpioint_mask_ack(struct irq_data *data)
-{
- s5p_gpioint_mask(data);
- s5p_gpioint_ack(data);
-}
-
-static int s5p_gpioint_set_type(struct irq_data *data, unsigned int type)
-{
- struct s3c_gpio_chip *chip = irq_data_get_irq_handler_data(data);
- int group, offset, con_offset;
- unsigned int value;
-
- group = chip->group;
- offset = s5p_gpioint_get_offset(data);
- con_offset = REG_OFFSET(group);
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+ struct irq_chip_type *ct = gc->chip_types;
+ unsigned int shift = (d->irq - gc->irq_base) << 2;
switch (type) {
case IRQ_TYPE_EDGE_RISING:
@@ -130,23 +69,12 @@ static int s5p_gpioint_set_type(struct irq_data *data, unsigned int type)
return -EINVAL;
}
- value = __raw_readl(GPIO_BASE(chip) + CON_OFFSET + con_offset);
- value &= ~(0x7 << (offset * 0x4));
- value |= (type << (offset * 0x4));
- __raw_writel(value, GPIO_BASE(chip) + CON_OFFSET + con_offset);
-
+ gc->type_cache &= ~(0x7 << shift);
+ gc->type_cache |= type << shift;
+ writel(gc->type_cache, gc->reg_base + ct->regs.type);
return 0;
}
-static struct irq_chip s5p_gpioint = {
- .name = "s5p_gpioint",
- .irq_ack = s5p_gpioint_ack,
- .irq_mask = s5p_gpioint_mask,
- .irq_mask_ack = s5p_gpioint_mask_ack,
- .irq_unmask = s5p_gpioint_unmask,
- .irq_set_type = s5p_gpioint_set_type,
-};
-
static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc)
{
struct s5p_gpioint_bank *bank = irq_get_handler_data(irq);
@@ -179,9 +107,10 @@ static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc)
static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip)
{
static int used_gpioint_groups = 0;
- int irq, group = chip->group;
- int i;
+ int group = chip->group;
struct s5p_gpioint_bank *bank = NULL;
+ struct irq_chip_generic *gc;
+ struct irq_chip_type *ct;
if (used_gpioint_groups >= S5P_GPIOINT_GROUP_COUNT)
return -ENOMEM;
@@ -211,19 +140,28 @@ static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip)
* chained GPIO irq has been successfully registered, allocate new gpio
* int group and assign irq nubmers
*/
-
chip->irq_base = S5P_GPIOINT_BASE +
used_gpioint_groups * S5P_GPIOINT_GROUP_SIZE;
used_gpioint_groups++;
bank->chips[group - bank->start] = chip;
- for (i = 0; i < chip->chip.ngpio; i++) {
- irq = chip->irq_base + i;
- irq_set_chip(irq, &s5p_gpioint);
- irq_set_handler_data(irq, chip);
- irq_set_handler(irq, handle_level_irq);
- set_irq_flags(irq, IRQF_VALID);
- }
+
+ gc = irq_alloc_generic_chip("s5p_gpioint", 1, chip->irq_base,
+ (void __iomem *)GPIO_BASE(chip),
+ handle_level_irq);
+ if (!gc)
+ return -ENOMEM;
+ ct = gc->chip_types;
+ ct->chip.irq_ack = irq_gc_ack;
+ ct->chip.irq_mask = irq_gc_mask_set_bit;
+ ct->chip.irq_unmask = irq_gc_mask_clr_bit;
+ ct->chip.irq_set_type = s5p_gpioint_set_type,
+ ct->regs.ack = PEND_OFFSET + REG_OFFSET(chip->group);
+ ct->regs.mask = MASK_OFFSET + REG_OFFSET(chip->group);
+ ct->regs.type = CON_OFFSET + REG_OFFSET(chip->group);
+ irq_setup_generic_chip(gc, IRQ_MSK(chip->chip.ngpio),
+ IRQ_GC_INIT_MASK_CACHE,
+ IRQ_NOREQUEST | IRQ_NOPROBE, 0);
return 0;
}
diff --git a/arch/arm/plat-s5p/irq-pm.c b/arch/arm/plat-s5p/irq-pm.c
index 5259ad458bc8..327acb3a4464 100644
--- a/arch/arm/plat-s5p/irq-pm.c
+++ b/arch/arm/plat-s5p/irq-pm.c
@@ -16,7 +16,6 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
-#include <linux/sysdev.h>
#include <plat/cpu.h>
#include <plat/irqs.h>
@@ -77,17 +76,15 @@ static struct sleep_save eint_save[] = {
SAVE_ITEM(S5P_EINT_MASK(3)),
};
-int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state)
+int s3c24xx_irq_suspend(void)
{
s3c_pm_do_save(eint_save, ARRAY_SIZE(eint_save));
return 0;
}
-int s3c24xx_irq_resume(struct sys_device *dev)
+void s3c24xx_irq_resume(void)
{
s3c_pm_do_restore(eint_save, ARRAY_SIZE(eint_save));
-
- return 0;
}
diff --git a/arch/arm/plat-s5p/irq.c b/arch/arm/plat-s5p/irq.c
index 5560b12035d1..a97c08957f49 100644
--- a/arch/arm/plat-s5p/irq.c
+++ b/arch/arm/plat-s5p/irq.c
@@ -64,11 +64,7 @@ void __init s5p_init_irq(u32 *vic, u32 num_vic)
vic_init(VA_VIC(irq), VIC_BASE(irq), vic[irq], 0);
#endif
- s3c_init_vic_timer_irq(IRQ_TIMER0_VIC, IRQ_TIMER0);
- s3c_init_vic_timer_irq(IRQ_TIMER1_VIC, IRQ_TIMER1);
- s3c_init_vic_timer_irq(IRQ_TIMER2_VIC, IRQ_TIMER2);
- s3c_init_vic_timer_irq(IRQ_TIMER3_VIC, IRQ_TIMER3);
- s3c_init_vic_timer_irq(IRQ_TIMER4_VIC, IRQ_TIMER4);
+ s3c_init_vic_timer_irq(5, IRQ_TIMER0);
s3c_init_uart_irqs(uart_irqs, ARRAY_SIZE(uart_irqs));
}
diff --git a/arch/arm/plat-s5p/s5p-time.c b/arch/arm/plat-s5p/s5p-time.c
index 8090403eec0f..899a8cc011ff 100644
--- a/arch/arm/plat-s5p/s5p-time.c
+++ b/arch/arm/plat-s5p/s5p-time.c
@@ -290,7 +290,7 @@ static void __init s5p_clockevent_init(void)
setup_irq(irq_number, &s5p_clock_event_irq);
}
-static cycle_t s5p_timer_read(struct clocksource *cs)
+static void __iomem *s5p_timer_reg(void)
{
unsigned long offset = 0;
@@ -308,10 +308,17 @@ static cycle_t s5p_timer_read(struct clocksource *cs)
default:
printk(KERN_ERR "Invalid Timer %d\n", timer_source.source_id);
- return 0;
+ return NULL;
}
- return (cycle_t) ~__raw_readl(S3C_TIMERREG(offset));
+ return S3C_TIMERREG(offset);
+}
+
+static cycle_t s5p_timer_read(struct clocksource *cs)
+{
+ void __iomem *reg = s5p_timer_reg();
+
+ return (cycle_t) (reg ? ~__raw_readl(reg) : 0);
}
/*
@@ -325,53 +332,22 @@ static DEFINE_CLOCK_DATA(cd);
unsigned long long notrace sched_clock(void)
{
- u32 cyc;
- unsigned long offset = 0;
-
- switch (timer_source.source_id) {
- case S5P_PWM0:
- case S5P_PWM1:
- case S5P_PWM2:
- case S5P_PWM3:
- offset = (timer_source.source_id * 0x0c) + 0x14;
- break;
-
- case S5P_PWM4:
- offset = 0x40;
- break;
+ void __iomem *reg = s5p_timer_reg();
- default:
- printk(KERN_ERR "Invalid Timer %d\n", timer_source.source_id);
+ if (!reg)
return 0;
- }
- cyc = ~__raw_readl(S3C_TIMERREG(offset));
- return cyc_to_sched_clock(&cd, cyc, (u32)~0);
+ return cyc_to_sched_clock(&cd, ~__raw_readl(reg), (u32)~0);
}
static void notrace s5p_update_sched_clock(void)
{
- u32 cyc;
- unsigned long offset = 0;
+ void __iomem *reg = s5p_timer_reg();
- switch (timer_source.source_id) {
- case S5P_PWM0:
- case S5P_PWM1:
- case S5P_PWM2:
- case S5P_PWM3:
- offset = (timer_source.source_id * 0x0c) + 0x14;
- break;
-
- case S5P_PWM4:
- offset = 0x40;
- break;
-
- default:
- printk(KERN_ERR "Invalid Timer %d\n", timer_source.source_id);
- }
+ if (!reg)
+ return;
- cyc = ~__raw_readl(S3C_TIMERREG(offset));
- update_sched_clock(&cd, cyc, (u32)~0);
+ update_sched_clock(&cd, ~__raw_readl(reg), (u32)~0);
}
struct clocksource time_clocksource = {
diff --git a/arch/arm/plat-samsung/Kconfig b/arch/arm/plat-samsung/Kconfig
index be72100b81b4..4d79519d19a4 100644
--- a/arch/arm/plat-samsung/Kconfig
+++ b/arch/arm/plat-samsung/Kconfig
@@ -8,6 +8,7 @@ config PLAT_SAMSUNG
bool
depends on PLAT_S3C24XX || ARCH_S3C64XX || PLAT_S5P
select NO_IOPORT
+ select GENERIC_IRQ_CHIP
default y
help
Base platform code for all Samsung SoC based systems
diff --git a/arch/arm/plat-samsung/include/plat/cpu.h b/arch/arm/plat-samsung/include/plat/cpu.h
index cedfff51c82b..3aedac0034ba 100644
--- a/arch/arm/plat-samsung/include/plat/cpu.h
+++ b/arch/arm/plat-samsung/include/plat/cpu.h
@@ -68,6 +68,12 @@ extern void s3c24xx_init_uartdevs(char *name,
struct sys_timer;
extern struct sys_timer s3c24xx_timer;
+extern struct syscore_ops s3c2410_pm_syscore_ops;
+extern struct syscore_ops s3c2412_pm_syscore_ops;
+extern struct syscore_ops s3c2416_pm_syscore_ops;
+extern struct syscore_ops s3c244x_pm_syscore_ops;
+extern struct syscore_ops s3c64xx_irq_syscore_ops;
+
/* system device classes */
extern struct sysdev_class s3c2410_sysclass;
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h
index f0da6b70fba4..39818d8da420 100644
--- a/arch/arm/plat-samsung/include/plat/devs.h
+++ b/arch/arm/plat-samsung/include/plat/devs.h
@@ -88,6 +88,7 @@ extern struct platform_device s3c64xx_device_onenand1;
extern struct platform_device s5p_device_onenand;
extern struct platform_device s3c_device_usbgadget;
+extern struct platform_device s3c_device_usb_hsudc;
extern struct platform_device s3c_device_usb_hsotg;
extern struct platform_device s5pv210_device_ac97;
@@ -142,6 +143,8 @@ extern struct platform_device s5p_device_fimc3;
extern struct platform_device s5p_device_mipi_csis0;
extern struct platform_device s5p_device_mipi_csis1;
+extern struct platform_device s5p_device_ehci;
+
extern struct platform_device exynos4_device_sysmmu;
/* s3c2440 specific devices */
diff --git a/arch/arm/plat-samsung/include/plat/irq-vic-timer.h b/arch/arm/plat-samsung/include/plat/irq-vic-timer.h
index a90b53431b5b..5b9c42fd32d7 100644
--- a/arch/arm/plat-samsung/include/plat/irq-vic-timer.h
+++ b/arch/arm/plat-samsung/include/plat/irq-vic-timer.h
@@ -10,4 +10,4 @@
* published by the Free Software Foundation.
*/
-extern void s3c_init_vic_timer_irq(unsigned int vic, unsigned int timer);
+extern void s3c_init_vic_timer_irq(unsigned int num, unsigned int timer_irq);
diff --git a/arch/arm/plat-samsung/include/plat/pm.h b/arch/arm/plat-samsung/include/plat/pm.h
index 937cc2ace517..7fb6f6be8c81 100644
--- a/arch/arm/plat-samsung/include/plat/pm.h
+++ b/arch/arm/plat-samsung/include/plat/pm.h
@@ -103,14 +103,16 @@ extern void s3c_pm_do_restore_core(struct sleep_save *ptr, int count);
#ifdef CONFIG_PM
extern int s3c_irqext_wake(struct irq_data *data, unsigned int state);
-extern int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state);
-extern int s3c24xx_irq_resume(struct sys_device *dev);
+extern int s3c24xx_irq_suspend(void);
+extern void s3c24xx_irq_resume(void);
#else
#define s3c_irqext_wake NULL
#define s3c24xx_irq_suspend NULL
#define s3c24xx_irq_resume NULL
#endif
+extern struct syscore_ops s3c24xx_irq_syscore_ops;
+
/* PM debug functions */
#ifdef CONFIG_SAMSUNG_PM_DEBUG
diff --git a/arch/arm/plat-samsung/include/plat/uncompress.h b/arch/arm/plat-samsung/include/plat/uncompress.h
index 7d6ed7263d57..ee48e12a1e72 100644
--- a/arch/arm/plat-samsung/include/plat/uncompress.h
+++ b/arch/arm/plat-samsung/include/plat/uncompress.h
@@ -18,8 +18,8 @@ typedef unsigned int upf_t; /* cannot include linux/serial_core.h */
/* uart setup */
-static unsigned int fifo_mask;
-static unsigned int fifo_max;
+unsigned int fifo_mask;
+unsigned int fifo_max;
/* forward declerations */
diff --git a/arch/arm/plat-samsung/irq-uart.c b/arch/arm/plat-samsung/irq-uart.c
index 4d4e571af553..32582c0958e3 100644
--- a/arch/arm/plat-samsung/irq-uart.c
+++ b/arch/arm/plat-samsung/irq-uart.c
@@ -27,60 +27,6 @@
/* Note, we make use of the fact that the parent IRQs, IRQ_UART[0..3]
* are consecutive when looking up the interrupt in the demux routines.
*/
-
-static inline void __iomem *s3c_irq_uart_base(struct irq_data *data)
-{
- struct s3c_uart_irq *uirq = irq_data_get_irq_chip_data(data);
- return uirq->regs;
-}
-
-static inline unsigned int s3c_irq_uart_bit(unsigned int irq)
-{
- return irq & 3;
-}
-
-static void s3c_irq_uart_mask(struct irq_data *data)
-{
- void __iomem *regs = s3c_irq_uart_base(data);
- unsigned int bit = s3c_irq_uart_bit(data->irq);
- u32 reg;
-
- reg = __raw_readl(regs + S3C64XX_UINTM);
- reg |= (1 << bit);
- __raw_writel(reg, regs + S3C64XX_UINTM);
-}
-
-static void s3c_irq_uart_maskack(struct irq_data *data)
-{
- void __iomem *regs = s3c_irq_uart_base(data);
- unsigned int bit = s3c_irq_uart_bit(data->irq);
- u32 reg;
-
- reg = __raw_readl(regs + S3C64XX_UINTM);
- reg |= (1 << bit);
- __raw_writel(reg, regs + S3C64XX_UINTM);
- __raw_writel(1 << bit, regs + S3C64XX_UINTP);
-}
-
-static void s3c_irq_uart_unmask(struct irq_data *data)
-{
- void __iomem *regs = s3c_irq_uart_base(data);
- unsigned int bit = s3c_irq_uart_bit(data->irq);
- u32 reg;
-
- reg = __raw_readl(regs + S3C64XX_UINTM);
- reg &= ~(1 << bit);
- __raw_writel(reg, regs + S3C64XX_UINTM);
-}
-
-static void s3c_irq_uart_ack(struct irq_data *data)
-{
- void __iomem *regs = s3c_irq_uart_base(data);
- unsigned int bit = s3c_irq_uart_bit(data->irq);
-
- __raw_writel(1 << bit, regs + S3C64XX_UINTP);
-}
-
static void s3c_irq_demux_uart(unsigned int irq, struct irq_desc *desc)
{
struct s3c_uart_irq *uirq = desc->irq_data.handler_data;
@@ -97,30 +43,25 @@ static void s3c_irq_demux_uart(unsigned int irq, struct irq_desc *desc)
generic_handle_irq(base + 3);
}
-static struct irq_chip s3c_irq_uart = {
- .name = "s3c-uart",
- .irq_mask = s3c_irq_uart_mask,
- .irq_unmask = s3c_irq_uart_unmask,
- .irq_mask_ack = s3c_irq_uart_maskack,
- .irq_ack = s3c_irq_uart_ack,
-};
-
static void __init s3c_init_uart_irq(struct s3c_uart_irq *uirq)
{
void __iomem *reg_base = uirq->regs;
- unsigned int irq;
- int offs;
+ struct irq_chip_generic *gc;
+ struct irq_chip_type *ct;
/* mask all interrupts at the start. */
__raw_writel(0xf, reg_base + S3C64XX_UINTM);
- for (offs = 0; offs < 3; offs++) {
- irq = uirq->base_irq + offs;
-
- irq_set_chip_and_handler(irq, &s3c_irq_uart, handle_level_irq);
- irq_set_chip_data(irq, uirq);
- set_irq_flags(irq, IRQF_VALID);
- }
+ gc = irq_alloc_generic_chip("s3c-uart", 1, uirq->base_irq, reg_base,
+ handle_level_irq);
+ ct = gc->chip_types;
+ ct->chip.irq_ack = irq_gc_ack;
+ ct->chip.irq_mask = irq_gc_mask_set_bit;
+ ct->chip.irq_unmask = irq_gc_mask_clr_bit;
+ ct->regs.ack = S3C64XX_UINTP;
+ ct->regs.mask = S3C64XX_UINTM;
+ irq_setup_generic_chip(gc, IRQ_MSK(4), IRQ_GC_INIT_MASK_CACHE,
+ IRQ_NOREQUEST | IRQ_NOPROBE, 0);
irq_set_handler_data(uirq->parent_irq, uirq);
irq_set_chained_handler(uirq->parent_irq, s3c_irq_demux_uart);
diff --git a/arch/arm/plat-samsung/irq-vic-timer.c b/arch/arm/plat-samsung/irq-vic-timer.c
index d6ad66ab9290..a607546ddbd0 100644
--- a/arch/arm/plat-samsung/irq-vic-timer.c
+++ b/arch/arm/plat-samsung/irq-vic-timer.c
@@ -28,60 +28,43 @@ static void s3c_irq_demux_vic_timer(unsigned int irq, struct irq_desc *desc)
}
/* We assume the IRQ_TIMER0..IRQ_TIMER4 range is continuous. */
-
-static void s3c_irq_timer_mask(struct irq_data *data)
-{
- u32 reg = __raw_readl(S3C64XX_TINT_CSTAT);
- u32 mask = (u32)data->chip_data;
-
- reg &= 0x1f; /* mask out pending interrupts */
- reg &= ~mask;
- __raw_writel(reg, S3C64XX_TINT_CSTAT);
-}
-
-static void s3c_irq_timer_unmask(struct irq_data *data)
+static void s3c_irq_timer_ack(struct irq_data *d)
{
- u32 reg = __raw_readl(S3C64XX_TINT_CSTAT);
- u32 mask = (u32)data->chip_data;
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+ u32 mask = (1 << 5) << (d->irq - gc->irq_base);
- reg &= 0x1f; /* mask out pending interrupts */
- reg |= mask;
- __raw_writel(reg, S3C64XX_TINT_CSTAT);
+ irq_reg_writel(mask | gc->mask_cache, gc->reg_base);
}
-static void s3c_irq_timer_ack(struct irq_data *data)
-{
- u32 reg = __raw_readl(S3C64XX_TINT_CSTAT);
- u32 mask = (u32)data->chip_data;
-
- reg &= 0x1f;
- reg |= mask << 5;
- __raw_writel(reg, S3C64XX_TINT_CSTAT);
-}
-
-static struct irq_chip s3c_irq_timer = {
- .name = "s3c-timer",
- .irq_mask = s3c_irq_timer_mask,
- .irq_unmask = s3c_irq_timer_unmask,
- .irq_ack = s3c_irq_timer_ack,
-};
-
/**
* s3c_init_vic_timer_irq() - initialise timer irq chanined off VIC.\
- * @parent_irq: The parent IRQ on the VIC for the timer.
- * @timer_irq: The IRQ to be used for the timer.
+ * @num: Number of timers to initialize
+ * @timer_irq: Base IRQ number to be used for the timers.
*
* Register the necessary IRQ chaining and support for the timer IRQs
* chained of the VIC.
*/
-void __init s3c_init_vic_timer_irq(unsigned int parent_irq,
- unsigned int timer_irq)
+void __init s3c_init_vic_timer_irq(unsigned int num, unsigned int timer_irq)
{
+ unsigned int pirq[5] = { IRQ_TIMER0_VIC, IRQ_TIMER1_VIC, IRQ_TIMER2_VIC,
+ IRQ_TIMER3_VIC, IRQ_TIMER4_VIC };
+ struct irq_chip_generic *s3c_tgc;
+ struct irq_chip_type *ct;
+ unsigned int i;
- irq_set_chained_handler(parent_irq, s3c_irq_demux_vic_timer);
- irq_set_handler_data(parent_irq, (void *)timer_irq);
+ s3c_tgc = irq_alloc_generic_chip("s3c-timer", 1, timer_irq,
+ S3C64XX_TINT_CSTAT, handle_level_irq);
+ ct = s3c_tgc->chip_types;
+ ct->chip.irq_mask = irq_gc_mask_clr_bit;
+ ct->chip.irq_unmask = irq_gc_mask_set_bit;
+ ct->chip.irq_ack = s3c_irq_timer_ack;
+ irq_setup_generic_chip(s3c_tgc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
+ IRQ_NOREQUEST | IRQ_NOPROBE, 0);
+ /* Clear the upper bits of the mask_cache*/
+ s3c_tgc->mask_cache &= 0x1f;
- irq_set_chip_and_handler(timer_irq, &s3c_irq_timer, handle_level_irq);
- irq_set_chip_data(timer_irq, (void *)(1 << (timer_irq - IRQ_TIMER0)));
- set_irq_flags(timer_irq, IRQF_VALID);
+ for (i = 0; i < num; i++, timer_irq++) {
+ irq_set_chained_handler(pirq[i], s3c_irq_demux_vic_timer);
+ irq_set_handler_data(pirq[i], (void *)timer_irq);
+ }
}
diff --git a/arch/arm/plat-spear/clock.c b/arch/arm/plat-spear/clock.c
index bdbd7ec9cb6b..6fa474cb398e 100644
--- a/arch/arm/plat-spear/clock.c
+++ b/arch/arm/plat-spear/clock.c
@@ -903,6 +903,11 @@ void recalc_root_clocks(void)
spin_unlock_irqrestore(&clocks_lock, flags);
}
+void __init clk_init(void)
+{
+ recalc_root_clocks();
+}
+
#ifdef CONFIG_DEBUG_FS
/*
* debugfs support to trace clock tree hierarchy and attributes
diff --git a/arch/arm/plat-spear/include/plat/clock.h b/arch/arm/plat-spear/include/plat/clock.h
index fcc0d0ad4a1f..0062bafef12d 100644
--- a/arch/arm/plat-spear/include/plat/clock.h
+++ b/arch/arm/plat-spear/include/plat/clock.h
@@ -224,6 +224,7 @@ struct clcd_rate_tbl {
};
/* platform specific clock functions */
+void __init clk_init(void);
void clk_register(struct clk_lookup *cl);
void recalc_root_clocks(void);
diff --git a/arch/arm/plat-spear/time.c b/arch/arm/plat-spear/time.c
index dbb6e4fff79d..0c77e4298675 100644
--- a/arch/arm/plat-spear/time.c
+++ b/arch/arm/plat-spear/time.c
@@ -70,19 +70,6 @@ static void clockevent_set_mode(enum clock_event_mode mode,
static int clockevent_next_event(unsigned long evt,
struct clock_event_device *clk_event_dev);
-static cycle_t clocksource_read_cycles(struct clocksource *cs)
-{
- return (cycle_t) readw(gpt_base + COUNT(CLKSRC));
-}
-
-static struct clocksource clksrc = {
- .name = "tmr1",
- .rating = 200, /* its a pretty decent clock */
- .read = clocksource_read_cycles,
- .mask = 0xFFFF, /* 16 bits */
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
static void spear_clocksource_init(void)
{
u32 tick_rate;
@@ -103,7 +90,8 @@ static void spear_clocksource_init(void)
writew(val, gpt_base + CR(CLKSRC));
/* register the clocksource */
- clocksource_register_hz(&clksrc, tick_rate);
+ clocksource_mmio_init(gpt_base + COUNT(CLKSRC), "tmr1", tick_rate,
+ 200, 16, clocksource_mmio_readw_up);
}
static struct clock_event_device clkevt = {
diff --git a/arch/arm/plat-stmp3xxx/Kconfig b/arch/arm/plat-stmp3xxx/Kconfig
deleted file mode 100644
index 2cf37c35951b..000000000000
--- a/arch/arm/plat-stmp3xxx/Kconfig
+++ /dev/null
@@ -1,37 +0,0 @@
-if ARCH_STMP3XXX
-
-menu "Freescale STMP3xxx implementations"
-
-choice
- prompt "Select STMP3xxx chip family"
-
-config ARCH_STMP37XX
- bool "Freescale SMTP37xx"
- select CPU_ARM926T
- ---help---
- STMP37xx refers to 3700 through 3769 chips
-
-config ARCH_STMP378X
- bool "Freescale STMP378x"
- select CPU_ARM926T
- ---help---
- STMP378x refers to 3780 through 3789 chips
-
-endchoice
-
-choice
- prompt "Select STMP3xxx board type"
-
-config MACH_STMP37XX
- depends on ARCH_STMP37XX
- bool "Freescale STMP37xx development board"
-
-config MACH_STMP378X
- depends on ARCH_STMP378X
- bool "Freescale STMP378x development board"
-
-endchoice
-
-endmenu
-
-endif
diff --git a/arch/arm/plat-stmp3xxx/Makefile b/arch/arm/plat-stmp3xxx/Makefile
deleted file mode 100644
index 31dd518f37a5..000000000000
--- a/arch/arm/plat-stmp3xxx/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-# Object file lists.
-obj-y += core.o timer.o irq.o dma.o clock.o pinmux.o devices.o
diff --git a/arch/arm/plat-stmp3xxx/clock.c b/arch/arm/plat-stmp3xxx/clock.c
deleted file mode 100644
index 2e712e17ce72..000000000000
--- a/arch/arm/plat-stmp3xxx/clock.c
+++ /dev/null
@@ -1,1134 +0,0 @@
-/*
- * Clock manipulation routines for Freescale STMP37XX/STMP378X
- *
- * Author: Vitaly Wool <vital@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#define DEBUG
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/clk.h>
-#include <linux/spinlock.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/clkdev.h>
-
-#include <asm/mach-types.h>
-#include <mach/platform.h>
-#include <mach/regs-clkctrl.h>
-
-#include "clock.h"
-
-static DEFINE_SPINLOCK(clocks_lock);
-
-static struct clk osc_24M;
-static struct clk pll_clk;
-static struct clk cpu_clk;
-static struct clk hclk;
-
-static int propagate_rate(struct clk *);
-
-static inline int clk_is_busy(struct clk *clk)
-{
- return __raw_readl(clk->busy_reg) & (1 << clk->busy_bit);
-}
-
-static inline int clk_good(struct clk *clk)
-{
- return clk && !IS_ERR(clk) && clk->ops;
-}
-
-static int std_clk_enable(struct clk *clk)
-{
- if (clk->enable_reg) {
- u32 clk_reg = __raw_readl(clk->enable_reg);
- if (clk->enable_negate)
- clk_reg &= ~(1 << clk->enable_shift);
- else
- clk_reg |= (1 << clk->enable_shift);
- __raw_writel(clk_reg, clk->enable_reg);
- if (clk->enable_wait)
- udelay(clk->enable_wait);
- return 0;
- } else
- return -EINVAL;
-}
-
-static int std_clk_disable(struct clk *clk)
-{
- if (clk->enable_reg) {
- u32 clk_reg = __raw_readl(clk->enable_reg);
- if (clk->enable_negate)
- clk_reg |= (1 << clk->enable_shift);
- else
- clk_reg &= ~(1 << clk->enable_shift);
- __raw_writel(clk_reg, clk->enable_reg);
- return 0;
- } else
- return -EINVAL;
-}
-
-static int io_set_rate(struct clk *clk, u32 rate)
-{
- u32 reg_frac, clkctrl_frac;
- int i, ret = 0, mask = 0x1f;
-
- clkctrl_frac = (clk->parent->rate * 18 + rate - 1) / rate;
-
- if (clkctrl_frac < 18 || clkctrl_frac > 35) {
- ret = -EINVAL;
- goto out;
- }
-
- reg_frac = __raw_readl(clk->scale_reg);
- reg_frac &= ~(mask << clk->scale_shift);
- __raw_writel(reg_frac | (clkctrl_frac << clk->scale_shift),
- clk->scale_reg);
- if (clk->busy_reg) {
- for (i = 10000; i; i--)
- if (!clk_is_busy(clk))
- break;
- if (!i)
- ret = -ETIMEDOUT;
- else
- ret = 0;
- }
-out:
- return ret;
-}
-
-static long io_get_rate(struct clk *clk)
-{
- long rate = clk->parent->rate * 18;
- int mask = 0x1f;
-
- rate /= (__raw_readl(clk->scale_reg) >> clk->scale_shift) & mask;
- clk->rate = rate;
-
- return rate;
-}
-
-static long per_get_rate(struct clk *clk)
-{
- long rate = clk->parent->rate;
- long div;
- const int mask = 0xff;
-
- if (clk->enable_reg &&
- !(__raw_readl(clk->enable_reg) & clk->enable_shift))
- clk->rate = 0;
- else {
- div = (__raw_readl(clk->scale_reg) >> clk->scale_shift) & mask;
- if (div)
- rate /= div;
- clk->rate = rate;
- }
-
- return clk->rate;
-}
-
-static int per_set_rate(struct clk *clk, u32 rate)
-{
- int ret = -EINVAL;
- int div = (clk->parent->rate + rate - 1) / rate;
- u32 reg_frac;
- const int mask = 0xff;
- int try = 10;
- int i = -1;
-
- if (div == 0 || div > mask)
- goto out;
-
- reg_frac = __raw_readl(clk->scale_reg);
- reg_frac &= ~(mask << clk->scale_shift);
-
- while (try--) {
- __raw_writel(reg_frac | (div << clk->scale_shift),
- clk->scale_reg);
-
- if (clk->busy_reg) {
- for (i = 10000; i; i--)
- if (!clk_is_busy(clk))
- break;
- }
- if (i)
- break;
- }
-
- if (!i)
- ret = -ETIMEDOUT;
- else
- ret = 0;
-
-out:
- if (ret != 0)
- printk(KERN_ERR "%s: error %d\n", __func__, ret);
- return ret;
-}
-
-static long lcdif_get_rate(struct clk *clk)
-{
- long rate = clk->parent->rate;
- long div;
- const int mask = 0xff;
-
- div = (__raw_readl(clk->scale_reg) >> clk->scale_shift) & mask;
- if (div) {
- rate /= div;
- div = (__raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC) &
- BM_CLKCTRL_FRAC_PIXFRAC) >> BP_CLKCTRL_FRAC_PIXFRAC;
- rate /= div;
- }
- clk->rate = rate;
-
- return rate;
-}
-
-static int lcdif_set_rate(struct clk *clk, u32 rate)
-{
- int ret = 0;
- /*
- * On 3700, we can get most timings exact by modifying ref_pix
- * and the divider, but keeping the phase timings at 1 (2
- * phases per cycle).
- *
- * ref_pix can be between 480e6*18/35=246.9MHz and 480e6*18/18=480MHz,
- * which is between 18/(18*480e6)=2.084ns and 35/(18*480e6)=4.050ns.
- *
- * ns_cycle >= 2*18e3/(18*480) = 25/6
- * ns_cycle <= 2*35e3/(18*480) = 875/108
- *
- * Multiply the ns_cycle by 'div' to lengthen it until it fits the
- * bounds. This is the divider we'll use after ref_pix.
- *
- * 6 * ns_cycle >= 25 * div
- * 108 * ns_cycle <= 875 * div
- */
- u32 ns_cycle = 1000000 / rate;
- u32 div, reg_val;
- u32 lowest_result = (u32) -1;
- u32 lowest_div = 0, lowest_fracdiv = 0;
-
- for (div = 1; div < 256; ++div) {
- u32 fracdiv;
- u32 ps_result;
- int lower_bound = 6 * ns_cycle >= 25 * div;
- int upper_bound = 108 * ns_cycle <= 875 * div;
- if (!lower_bound)
- break;
- if (!upper_bound)
- continue;
- /*
- * Found a matching div. Calculate fractional divider needed,
- * rounded up.
- */
- fracdiv = ((clk->parent->rate / 1000 * 18 / 2) *
- ns_cycle + 1000 * div - 1) /
- (1000 * div);
- if (fracdiv < 18 || fracdiv > 35) {
- ret = -EINVAL;
- goto out;
- }
- /* Calculate the actual cycle time this results in */
- ps_result = 6250 * div * fracdiv / 27;
-
- /* Use the fastest result that doesn't break ns_cycle */
- if (ps_result <= lowest_result) {
- lowest_result = ps_result;
- lowest_div = div;
- lowest_fracdiv = fracdiv;
- }
- }
-
- if (div >= 256 || lowest_result == (u32) -1) {
- ret = -EINVAL;
- goto out;
- }
- pr_debug("Programming PFD=%u,DIV=%u ref_pix=%uMHz "
- "PIXCLK=%uMHz cycle=%u.%03uns\n",
- lowest_fracdiv, lowest_div,
- 480*18/lowest_fracdiv, 480*18/lowest_fracdiv/lowest_div,
- lowest_result / 1000, lowest_result % 1000);
-
- /* Program ref_pix phase fractional divider */
- reg_val = __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC);
- reg_val &= ~BM_CLKCTRL_FRAC_PIXFRAC;
- reg_val |= BF(lowest_fracdiv, CLKCTRL_FRAC_PIXFRAC);
- __raw_writel(reg_val, REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC);
-
- /* Ungate PFD */
- stmp3xxx_clearl(BM_CLKCTRL_FRAC_CLKGATEPIX,
- REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC);
-
- /* Program pix divider */
- reg_val = __raw_readl(clk->scale_reg);
- reg_val &= ~(BM_CLKCTRL_PIX_DIV | BM_CLKCTRL_PIX_CLKGATE);
- reg_val |= BF(lowest_div, CLKCTRL_PIX_DIV);
- __raw_writel(reg_val, clk->scale_reg);
-
- /* Wait for divider update */
- if (clk->busy_reg) {
- int i;
- for (i = 10000; i; i--)
- if (!clk_is_busy(clk))
- break;
- if (!i) {
- ret = -ETIMEDOUT;
- goto out;
- }
- }
-
- /* Switch to ref_pix source */
- reg_val = __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ);
- reg_val &= ~BM_CLKCTRL_CLKSEQ_BYPASS_PIX;
- __raw_writel(reg_val, REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ);
-
-out:
- return ret;
-}
-
-
-static int cpu_set_rate(struct clk *clk, u32 rate)
-{
- u32 reg_val;
-
- if (rate < 24000)
- return -EINVAL;
- else if (rate == 24000) {
- /* switch to the 24M source */
- clk_set_parent(clk, &osc_24M);
- } else {
- int i;
- u32 clkctrl_cpu = 1;
- u32 c = clkctrl_cpu;
- u32 clkctrl_frac = 1;
- u32 val;
- for ( ; c < 0x40; c++) {
- u32 f = (pll_clk.rate*18/c + rate/2) / rate;
- int s1, s2;
-
- if (f < 18 || f > 35)
- continue;
- s1 = pll_clk.rate*18/clkctrl_frac/clkctrl_cpu - rate;
- s2 = pll_clk.rate*18/c/f - rate;
- pr_debug("%s: s1 %d, s2 %d\n", __func__, s1, s2);
- if (abs(s1) > abs(s2)) {
- clkctrl_cpu = c;
- clkctrl_frac = f;
- }
- if (s2 == 0)
- break;
- };
- pr_debug("%s: clkctrl_cpu %d, clkctrl_frac %d\n", __func__,
- clkctrl_cpu, clkctrl_frac);
- if (c == 0x40) {
- int d = pll_clk.rate*18/clkctrl_frac/clkctrl_cpu -
- rate;
- if (abs(d) > 100 ||
- clkctrl_frac < 18 || clkctrl_frac > 35)
- return -EINVAL;
- }
-
- /* 4.6.2 */
- val = __raw_readl(clk->scale_reg);
- val &= ~(0x3f << clk->scale_shift);
- val |= clkctrl_frac;
- clk_set_parent(clk, &osc_24M);
- udelay(10);
- __raw_writel(val, clk->scale_reg);
- /* ungate */
- __raw_writel(1<<7, clk->scale_reg + 8);
- /* write clkctrl_cpu */
- clk->saved_div = clkctrl_cpu;
-
- reg_val = __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU);
- reg_val &= ~0x3F;
- reg_val |= clkctrl_cpu;
- __raw_writel(reg_val, REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU);
-
- for (i = 10000; i; i--)
- if (!clk_is_busy(clk))
- break;
- if (!i) {
- printk(KERN_ERR "couldn't set up CPU divisor\n");
- return -ETIMEDOUT;
- }
- clk_set_parent(clk, &pll_clk);
- clk->saved_div = 0;
- udelay(10);
- }
- return 0;
-}
-
-static long cpu_get_rate(struct clk *clk)
-{
- long rate = clk->parent->rate * 18;
-
- rate /= (__raw_readl(clk->scale_reg) >> clk->scale_shift) & 0x3f;
- rate /= __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU) & 0x3f;
- rate = ((rate + 9) / 10) * 10;
- clk->rate = rate;
-
- return rate;
-}
-
-static long cpu_round_rate(struct clk *clk, u32 rate)
-{
- unsigned long r = 0;
-
- if (rate <= 24000)
- r = 24000;
- else {
- u32 clkctrl_cpu = 1;
- u32 clkctrl_frac;
- do {
- clkctrl_frac =
- (pll_clk.rate*18 / clkctrl_cpu + rate/2) / rate;
- if (clkctrl_frac > 35)
- continue;
- if (pll_clk.rate*18 / clkctrl_frac / clkctrl_cpu/10 ==
- rate / 10)
- break;
- } while (pll_clk.rate / 2 >= clkctrl_cpu++ * rate);
- if (pll_clk.rate / 2 < (clkctrl_cpu - 1) * rate)
- clkctrl_cpu--;
- pr_debug("%s: clkctrl_cpu %d, clkctrl_frac %d\n", __func__,
- clkctrl_cpu, clkctrl_frac);
- if (clkctrl_frac < 18)
- clkctrl_frac = 18;
- if (clkctrl_frac > 35)
- clkctrl_frac = 35;
-
- r = pll_clk.rate * 18;
- r /= clkctrl_frac;
- r /= clkctrl_cpu;
- r = 10 * ((r + 9) / 10);
- }
- return r;
-}
-
-static long emi_get_rate(struct clk *clk)
-{
- long rate = clk->parent->rate * 18;
-
- rate /= (__raw_readl(clk->scale_reg) >> clk->scale_shift) & 0x3f;
- rate /= __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_EMI) & 0x3f;
- clk->rate = rate;
-
- return rate;
-}
-
-static int clkseq_set_parent(struct clk *clk, struct clk *parent)
-{
- int ret = -EINVAL;
- int shift = 8;
-
- /* bypass? */
- if (parent == &osc_24M)
- shift = 4;
-
- if (clk->bypass_reg) {
-#ifdef CONFIG_ARCH_STMP378X
- u32 hbus_val, cpu_val;
-
- if (clk == &cpu_clk && shift == 4) {
- hbus_val = __raw_readl(REGS_CLKCTRL_BASE +
- HW_CLKCTRL_HBUS);
- cpu_val = __raw_readl(REGS_CLKCTRL_BASE +
- HW_CLKCTRL_CPU);
-
- hbus_val &= ~(BM_CLKCTRL_HBUS_DIV_FRAC_EN |
- BM_CLKCTRL_HBUS_DIV);
- clk->saved_div = cpu_val & BM_CLKCTRL_CPU_DIV_CPU;
- cpu_val &= ~BM_CLKCTRL_CPU_DIV_CPU;
- cpu_val |= 1;
-
- if (machine_is_stmp378x()) {
- __raw_writel(hbus_val,
- REGS_CLKCTRL_BASE + HW_CLKCTRL_HBUS);
- __raw_writel(cpu_val,
- REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU);
- hclk.rate = 0;
- }
- } else if (clk == &cpu_clk && shift == 8) {
- hbus_val = __raw_readl(REGS_CLKCTRL_BASE +
- HW_CLKCTRL_HBUS);
- cpu_val = __raw_readl(REGS_CLKCTRL_BASE +
- HW_CLKCTRL_CPU);
- hbus_val &= ~(BM_CLKCTRL_HBUS_DIV_FRAC_EN |
- BM_CLKCTRL_HBUS_DIV);
- hbus_val |= 2;
- cpu_val &= ~BM_CLKCTRL_CPU_DIV_CPU;
- if (clk->saved_div)
- cpu_val |= clk->saved_div;
- else
- cpu_val |= 2;
-
- if (machine_is_stmp378x()) {
- __raw_writel(hbus_val,
- REGS_CLKCTRL_BASE + HW_CLKCTRL_HBUS);
- __raw_writel(cpu_val,
- REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU);
- hclk.rate = 0;
- }
- }
-#endif
- __raw_writel(1 << clk->bypass_shift, clk->bypass_reg + shift);
-
- ret = 0;
- }
-
- return ret;
-}
-
-static int hbus_set_rate(struct clk *clk, u32 rate)
-{
- u8 div = 0;
- int is_frac = 0;
- u32 clkctrl_hbus;
- struct clk *parent = clk->parent;
-
- pr_debug("%s: rate %d, parent rate %d\n", __func__, rate,
- parent->rate);
-
- if (rate > parent->rate)
- return -EINVAL;
-
- if (((parent->rate + rate/2) / rate) * rate != parent->rate &&
- parent->rate / rate < 32) {
- pr_debug("%s: switching to fractional mode\n", __func__);
- is_frac = 1;
- }
-
- if (is_frac)
- div = (32 * rate + parent->rate / 2) / parent->rate;
- else
- div = (parent->rate + rate - 1) / rate;
- pr_debug("%s: div calculated is %d\n", __func__, div);
- if (!div || div > 0x1f)
- return -EINVAL;
-
- clk_set_parent(&cpu_clk, &osc_24M);
- udelay(10);
- clkctrl_hbus = __raw_readl(clk->scale_reg);
- clkctrl_hbus &= ~0x3f;
- clkctrl_hbus |= div;
- clkctrl_hbus |= (is_frac << 5);
-
- __raw_writel(clkctrl_hbus, clk->scale_reg);
- if (clk->busy_reg) {
- int i;
- for (i = 10000; i; i--)
- if (!clk_is_busy(clk))
- break;
- if (!i) {
- printk(KERN_ERR "couldn't set up CPU divisor\n");
- return -ETIMEDOUT;
- }
- }
- clk_set_parent(&cpu_clk, &pll_clk);
- __raw_writel(clkctrl_hbus, clk->scale_reg);
- udelay(10);
- return 0;
-}
-
-static long hbus_get_rate(struct clk *clk)
-{
- long rate = clk->parent->rate;
-
- if (__raw_readl(clk->scale_reg) & 0x20) {
- rate *= __raw_readl(clk->scale_reg) & 0x1f;
- rate /= 32;
- } else
- rate /= __raw_readl(clk->scale_reg) & 0x1f;
- clk->rate = rate;
-
- return rate;
-}
-
-static int xbus_set_rate(struct clk *clk, u32 rate)
-{
- u16 div = 0;
- u32 clkctrl_xbus;
-
- pr_debug("%s: rate %d, parent rate %d\n", __func__, rate,
- clk->parent->rate);
-
- div = (clk->parent->rate + rate - 1) / rate;
- pr_debug("%s: div calculated is %d\n", __func__, div);
- if (!div || div > 0x3ff)
- return -EINVAL;
-
- clkctrl_xbus = __raw_readl(clk->scale_reg);
- clkctrl_xbus &= ~0x3ff;
- clkctrl_xbus |= div;
- __raw_writel(clkctrl_xbus, clk->scale_reg);
- if (clk->busy_reg) {
- int i;
- for (i = 10000; i; i--)
- if (!clk_is_busy(clk))
- break;
- if (!i) {
- printk(KERN_ERR "couldn't set up xbus divisor\n");
- return -ETIMEDOUT;
- }
- }
- return 0;
-}
-
-static long xbus_get_rate(struct clk *clk)
-{
- long rate = clk->parent->rate;
-
- rate /= __raw_readl(clk->scale_reg) & 0x3ff;
- clk->rate = rate;
-
- return rate;
-}
-
-
-/* Clock ops */
-
-static struct clk_ops std_ops = {
- .enable = std_clk_enable,
- .disable = std_clk_disable,
- .get_rate = per_get_rate,
- .set_rate = per_set_rate,
- .set_parent = clkseq_set_parent,
-};
-
-static struct clk_ops min_ops = {
- .enable = std_clk_enable,
- .disable = std_clk_disable,
-};
-
-static struct clk_ops cpu_ops = {
- .enable = std_clk_enable,
- .disable = std_clk_disable,
- .get_rate = cpu_get_rate,
- .set_rate = cpu_set_rate,
- .round_rate = cpu_round_rate,
- .set_parent = clkseq_set_parent,
-};
-
-static struct clk_ops io_ops = {
- .enable = std_clk_enable,
- .disable = std_clk_disable,
- .get_rate = io_get_rate,
- .set_rate = io_set_rate,
-};
-
-static struct clk_ops hbus_ops = {
- .get_rate = hbus_get_rate,
- .set_rate = hbus_set_rate,
-};
-
-static struct clk_ops xbus_ops = {
- .get_rate = xbus_get_rate,
- .set_rate = xbus_set_rate,
-};
-
-static struct clk_ops lcdif_ops = {
- .enable = std_clk_enable,
- .disable = std_clk_disable,
- .get_rate = lcdif_get_rate,
- .set_rate = lcdif_set_rate,
- .set_parent = clkseq_set_parent,
-};
-
-static struct clk_ops emi_ops = {
- .get_rate = emi_get_rate,
-};
-
-/* List of on-chip clocks */
-
-static struct clk osc_24M = {
- .flags = FIXED_RATE | ENABLED,
- .rate = 24000,
-};
-
-static struct clk pll_clk = {
- .parent = &osc_24M,
- .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_PLLCTRL0,
- .enable_shift = 16,
- .enable_wait = 10,
- .flags = FIXED_RATE | ENABLED,
- .rate = 480000,
- .ops = &min_ops,
-};
-
-static struct clk cpu_clk = {
- .parent = &pll_clk,
- .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC,
- .scale_shift = 0,
- .bypass_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
- .bypass_shift = 7,
- .busy_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU,
- .busy_bit = 28,
- .flags = RATE_PROPAGATES | ENABLED,
- .ops = &cpu_ops,
-};
-
-static struct clk io_clk = {
- .parent = &pll_clk,
- .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC,
- .enable_shift = 31,
- .enable_negate = 1,
- .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC,
- .scale_shift = 24,
- .flags = RATE_PROPAGATES | ENABLED,
- .ops = &io_ops,
-};
-
-static struct clk hclk = {
- .parent = &cpu_clk,
- .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_HBUS,
- .bypass_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
- .bypass_shift = 7,
- .busy_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_HBUS,
- .busy_bit = 29,
- .flags = RATE_PROPAGATES | ENABLED,
- .ops = &hbus_ops,
-};
-
-static struct clk xclk = {
- .parent = &osc_24M,
- .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_XBUS,
- .busy_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_XBUS,
- .busy_bit = 31,
- .flags = RATE_PROPAGATES | ENABLED,
- .ops = &xbus_ops,
-};
-
-static struct clk uart_clk = {
- .parent = &xclk,
- .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL,
- .enable_shift = 31,
- .enable_negate = 1,
- .flags = ENABLED,
- .ops = &min_ops,
-};
-
-static struct clk audio_clk = {
- .parent = &xclk,
- .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL,
- .enable_shift = 30,
- .enable_negate = 1,
- .ops = &min_ops,
-};
-
-static struct clk pwm_clk = {
- .parent = &xclk,
- .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL,
- .enable_shift = 29,
- .enable_negate = 1,
- .ops = &min_ops,
-};
-
-static struct clk dri_clk = {
- .parent = &xclk,
- .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL,
- .enable_shift = 28,
- .enable_negate = 1,
- .ops = &min_ops,
-};
-
-static struct clk digctl_clk = {
- .parent = &xclk,
- .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL,
- .enable_shift = 27,
- .enable_negate = 1,
- .ops = &min_ops,
-};
-
-static struct clk timer_clk = {
- .parent = &xclk,
- .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL,
- .enable_shift = 26,
- .enable_negate = 1,
- .flags = ENABLED,
- .ops = &min_ops,
-};
-
-static struct clk lcdif_clk = {
- .parent = &pll_clk,
- .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_PIX,
- .busy_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_PIX,
- .busy_bit = 29,
- .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_PIX,
- .enable_shift = 31,
- .enable_negate = 1,
- .bypass_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
- .bypass_shift = 1,
- .flags = NEEDS_SET_PARENT,
- .ops = &lcdif_ops,
-};
-
-static struct clk ssp_clk = {
- .parent = &io_clk,
- .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_SSP,
- .busy_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_SSP,
- .busy_bit = 29,
- .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_SSP,
- .enable_shift = 31,
- .bypass_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
- .bypass_shift = 5,
- .enable_negate = 1,
- .flags = NEEDS_SET_PARENT,
- .ops = &std_ops,
-};
-
-static struct clk gpmi_clk = {
- .parent = &io_clk,
- .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_GPMI,
- .busy_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_GPMI,
- .busy_bit = 29,
- .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_GPMI,
- .enable_shift = 31,
- .enable_negate = 1,
- .bypass_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
- .bypass_shift = 4,
- .flags = NEEDS_SET_PARENT,
- .ops = &std_ops,
-};
-
-static struct clk spdif_clk = {
- .parent = &pll_clk,
- .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_SPDIF,
- .enable_shift = 31,
- .enable_negate = 1,
- .ops = &min_ops,
-};
-
-static struct clk emi_clk = {
- .parent = &pll_clk,
- .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_EMI,
- .enable_shift = 31,
- .enable_negate = 1,
- .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC,
- .scale_shift = 8,
- .busy_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_EMI,
- .busy_bit = 28,
- .bypass_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
- .bypass_shift = 6,
- .flags = ENABLED,
- .ops = &emi_ops,
-};
-
-static struct clk ir_clk = {
- .parent = &io_clk,
- .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_IR,
- .enable_shift = 31,
- .enable_negate = 1,
- .bypass_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
- .bypass_shift = 3,
- .ops = &min_ops,
-};
-
-static struct clk saif_clk = {
- .parent = &pll_clk,
- .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_SAIF,
- .busy_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_SAIF,
- .busy_bit = 29,
- .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_SAIF,
- .enable_shift = 31,
- .enable_negate = 1,
- .bypass_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
- .bypass_shift = 0,
- .ops = &std_ops,
-};
-
-static struct clk usb_clk = {
- .parent = &pll_clk,
- .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_PLLCTRL0,
- .enable_shift = 18,
- .enable_negate = 1,
- .ops = &min_ops,
-};
-
-/* list of all the clocks */
-static struct clk_lookup onchip_clks[] = {
- {
- .con_id = "osc_24M",
- .clk = &osc_24M,
- }, {
- .con_id = "pll",
- .clk = &pll_clk,
- }, {
- .con_id = "cpu",
- .clk = &cpu_clk,
- }, {
- .con_id = "hclk",
- .clk = &hclk,
- }, {
- .con_id = "xclk",
- .clk = &xclk,
- }, {
- .con_id = "io",
- .clk = &io_clk,
- }, {
- .con_id = "uart",
- .clk = &uart_clk,
- }, {
- .con_id = "audio",
- .clk = &audio_clk,
- }, {
- .con_id = "pwm",
- .clk = &pwm_clk,
- }, {
- .con_id = "dri",
- .clk = &dri_clk,
- }, {
- .con_id = "digctl",
- .clk = &digctl_clk,
- }, {
- .con_id = "timer",
- .clk = &timer_clk,
- }, {
- .con_id = "lcdif",
- .clk = &lcdif_clk,
- }, {
- .con_id = "ssp",
- .clk = &ssp_clk,
- }, {
- .con_id = "gpmi",
- .clk = &gpmi_clk,
- }, {
- .con_id = "spdif",
- .clk = &spdif_clk,
- }, {
- .con_id = "emi",
- .clk = &emi_clk,
- }, {
- .con_id = "ir",
- .clk = &ir_clk,
- }, {
- .con_id = "saif",
- .clk = &saif_clk,
- }, {
- .con_id = "usb",
- .clk = &usb_clk,
- },
-};
-
-static int __init propagate_rate(struct clk *clk)
-{
- struct clk_lookup *cl;
-
- for (cl = onchip_clks; cl < onchip_clks + ARRAY_SIZE(onchip_clks);
- cl++) {
- if (unlikely(!clk_good(cl->clk)))
- continue;
- if (cl->clk->parent == clk && cl->clk->ops->get_rate) {
- cl->clk->ops->get_rate(cl->clk);
- if (cl->clk->flags & RATE_PROPAGATES)
- propagate_rate(cl->clk);
- }
- }
-
- return 0;
-}
-
-/* Exported API */
-unsigned long clk_get_rate(struct clk *clk)
-{
- if (unlikely(!clk_good(clk)))
- return 0;
-
- if (clk->rate != 0)
- return clk->rate;
-
- if (clk->ops->get_rate != NULL)
- return clk->ops->get_rate(clk);
-
- return clk_get_rate(clk->parent);
-}
-EXPORT_SYMBOL(clk_get_rate);
-
-long clk_round_rate(struct clk *clk, unsigned long rate)
-{
- if (unlikely(!clk_good(clk)))
- return 0;
-
- if (clk->ops->round_rate)
- return clk->ops->round_rate(clk, rate);
-
- return 0;
-}
-EXPORT_SYMBOL(clk_round_rate);
-
-static inline int close_enough(long rate1, long rate2)
-{
- return rate1 && !((rate2 - rate1) * 1000 / rate1);
-}
-
-int clk_set_rate(struct clk *clk, unsigned long rate)
-{
- int ret = -EINVAL;
-
- if (unlikely(!clk_good(clk)))
- goto out;
-
- if (clk->flags & FIXED_RATE || !clk->ops->set_rate)
- goto out;
-
- else if (!close_enough(clk->rate, rate)) {
- ret = clk->ops->set_rate(clk, rate);
- if (ret < 0)
- goto out;
- clk->rate = rate;
- if (clk->flags & RATE_PROPAGATES)
- propagate_rate(clk);
- } else
- ret = 0;
-
-out:
- return ret;
-}
-EXPORT_SYMBOL(clk_set_rate);
-
-int clk_enable(struct clk *clk)
-{
- unsigned long clocks_flags;
-
- if (unlikely(!clk_good(clk)))
- return -EINVAL;
-
- if (clk->parent)
- clk_enable(clk->parent);
-
- spin_lock_irqsave(&clocks_lock, clocks_flags);
-
- clk->usage++;
- if (clk->ops && clk->ops->enable)
- clk->ops->enable(clk);
-
- spin_unlock_irqrestore(&clocks_lock, clocks_flags);
- return 0;
-}
-EXPORT_SYMBOL(clk_enable);
-
-static void local_clk_disable(struct clk *clk)
-{
- if (unlikely(!clk_good(clk)))
- return;
-
- if (clk->usage == 0 && clk->ops->disable)
- clk->ops->disable(clk);
-
- if (clk->parent)
- local_clk_disable(clk->parent);
-}
-
-void clk_disable(struct clk *clk)
-{
- unsigned long clocks_flags;
-
- if (unlikely(!clk_good(clk)))
- return;
-
- spin_lock_irqsave(&clocks_lock, clocks_flags);
-
- if ((--clk->usage) == 0 && clk->ops->disable)
- clk->ops->disable(clk);
-
- spin_unlock_irqrestore(&clocks_lock, clocks_flags);
- if (clk->parent)
- clk_disable(clk->parent);
-}
-EXPORT_SYMBOL(clk_disable);
-
-/* Some additional API */
-int clk_set_parent(struct clk *clk, struct clk *parent)
-{
- int ret = -ENODEV;
- unsigned long clocks_flags;
-
- if (unlikely(!clk_good(clk)))
- goto out;
-
- if (!clk->ops->set_parent)
- goto out;
-
- spin_lock_irqsave(&clocks_lock, clocks_flags);
-
- ret = clk->ops->set_parent(clk, parent);
- if (!ret) {
- /* disable if usage count is 0 */
- local_clk_disable(parent);
-
- parent->usage += clk->usage;
- clk->parent->usage -= clk->usage;
-
- /* disable if new usage count is 0 */
- local_clk_disable(clk->parent);
-
- clk->parent = parent;
- }
- spin_unlock_irqrestore(&clocks_lock, clocks_flags);
-
-out:
- return ret;
-}
-EXPORT_SYMBOL(clk_set_parent);
-
-struct clk *clk_get_parent(struct clk *clk)
-{
- if (unlikely(!clk_good(clk)))
- return NULL;
- return clk->parent;
-}
-EXPORT_SYMBOL(clk_get_parent);
-
-static int __init clk_init(void)
-{
- struct clk_lookup *cl;
- struct clk_ops *ops;
-
- spin_lock_init(&clocks_lock);
-
- for (cl = onchip_clks; cl < onchip_clks + ARRAY_SIZE(onchip_clks);
- cl++) {
- if (cl->clk->flags & ENABLED)
- clk_enable(cl->clk);
- else
- local_clk_disable(cl->clk);
-
- ops = cl->clk->ops;
-
- if ((cl->clk->flags & NEEDS_INITIALIZATION) &&
- ops && ops->set_rate)
- ops->set_rate(cl->clk, cl->clk->rate);
-
- if (cl->clk->flags & FIXED_RATE) {
- if (cl->clk->flags & RATE_PROPAGATES)
- propagate_rate(cl->clk);
- } else {
- if (ops && ops->get_rate)
- ops->get_rate(cl->clk);
- }
-
- if (cl->clk->flags & NEEDS_SET_PARENT) {
- if (ops && ops->set_parent)
- ops->set_parent(cl->clk, cl->clk->parent);
- }
- }
- clkdev_add_table(onchip_clks, ARRAY_SIZE(onchip_clks));
- return 0;
-}
-
-arch_initcall(clk_init);
diff --git a/arch/arm/plat-stmp3xxx/clock.h b/arch/arm/plat-stmp3xxx/clock.h
deleted file mode 100644
index a6611e1a3510..000000000000
--- a/arch/arm/plat-stmp3xxx/clock.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Clock control driver for Freescale STMP37XX/STMP378X - internal header file
- *
- * Author: Vitaly Wool <vital@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#ifndef __ARCH_ARM_STMX3XXX_CLOCK_H__
-#define __ARCH_ARM_STMX3XXX_CLOCK_H__
-
-#ifndef __ASSEMBLER__
-
-struct clk_ops {
- int (*enable) (struct clk *);
- int (*disable) (struct clk *);
- long (*get_rate) (struct clk *);
- long (*round_rate) (struct clk *, u32);
- int (*set_rate) (struct clk *, u32);
- int (*set_parent) (struct clk *, struct clk *);
-};
-
-struct clk {
- struct clk *parent;
- u32 rate;
- u32 flags;
- u8 scale_shift;
- u8 enable_shift;
- u8 bypass_shift;
- u8 busy_bit;
- s8 usage;
- int enable_wait;
- int enable_negate;
- u32 saved_div;
- void __iomem *enable_reg;
- void __iomem *scale_reg;
- void __iomem *bypass_reg;
- void __iomem *busy_reg;
- struct clk_ops *ops;
-};
-
-#endif /* __ASSEMBLER__ */
-
-/* Flags */
-#define RATE_PROPAGATES (1<<0)
-#define NEEDS_INITIALIZATION (1<<1)
-#define PARENT_SET_RATE (1<<2)
-#define FIXED_RATE (1<<3)
-#define ENABLED (1<<4)
-#define NEEDS_SET_PARENT (1<<5)
-
-#endif
diff --git a/arch/arm/plat-stmp3xxx/core.c b/arch/arm/plat-stmp3xxx/core.c
deleted file mode 100644
index 37b8a09148a4..000000000000
--- a/arch/arm/plat-stmp3xxx/core.c
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Freescale STMP37XX/STMP378X core routines
- *
- * Embedded Alley Solutions, Inc <source@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/io.h>
-
-#include <mach/stmp3xxx.h>
-#include <mach/platform.h>
-#include <mach/dma.h>
-#include <mach/regs-clkctrl.h>
-
-static int __stmp3xxx_reset_block(void __iomem *hwreg, int just_enable)
-{
- u32 c;
- int timeout;
-
- /* the process of software reset of IP block is done
- in several steps:
-
- - clear SFTRST and wait for block is enabled;
- - clear clock gating (CLKGATE bit);
- - set the SFTRST again and wait for block is in reset;
- - clear SFTRST and wait for reset completion.
- */
- c = __raw_readl(hwreg);
- c &= ~(1<<31); /* clear SFTRST */
- __raw_writel(c, hwreg);
- for (timeout = 1000000; timeout > 0; timeout--)
- /* still in SFTRST state ? */
- if ((__raw_readl(hwreg) & (1<<31)) == 0)
- break;
- if (timeout <= 0) {
- printk(KERN_ERR"%s(%p): timeout when enabling\n",
- __func__, hwreg);
- return -ETIME;
- }
-
- c = __raw_readl(hwreg);
- c &= ~(1<<30); /* clear CLKGATE */
- __raw_writel(c, hwreg);
-
- if (!just_enable) {
- c = __raw_readl(hwreg);
- c |= (1<<31); /* now again set SFTRST */
- __raw_writel(c, hwreg);
- for (timeout = 1000000; timeout > 0; timeout--)
- /* poll until CLKGATE set */
- if (__raw_readl(hwreg) & (1<<30))
- break;
- if (timeout <= 0) {
- printk(KERN_ERR"%s(%p): timeout when resetting\n",
- __func__, hwreg);
- return -ETIME;
- }
-
- c = __raw_readl(hwreg);
- c &= ~(1<<31); /* clear SFTRST */
- __raw_writel(c, hwreg);
- for (timeout = 1000000; timeout > 0; timeout--)
- /* still in SFTRST state ? */
- if ((__raw_readl(hwreg) & (1<<31)) == 0)
- break;
- if (timeout <= 0) {
- printk(KERN_ERR"%s(%p): timeout when enabling "
- "after reset\n", __func__, hwreg);
- return -ETIME;
- }
-
- c = __raw_readl(hwreg);
- c &= ~(1<<30); /* clear CLKGATE */
- __raw_writel(c, hwreg);
- }
- for (timeout = 1000000; timeout > 0; timeout--)
- /* still in SFTRST state ? */
- if ((__raw_readl(hwreg) & (1<<30)) == 0)
- break;
-
- if (timeout <= 0) {
- printk(KERN_ERR"%s(%p): timeout when unclockgating\n",
- __func__, hwreg);
- return -ETIME;
- }
-
- return 0;
-}
-
-int stmp3xxx_reset_block(void __iomem *hwreg, int just_enable)
-{
- int try = 10;
- int r;
-
- while (try--) {
- r = __stmp3xxx_reset_block(hwreg, just_enable);
- if (!r)
- break;
- pr_debug("%s: try %d failed\n", __func__, 10 - try);
- }
- return r;
-}
-EXPORT_SYMBOL(stmp3xxx_reset_block);
-
-struct platform_device stmp3xxx_dbguart = {
- .name = "stmp3xxx-dbguart",
- .id = -1,
-};
-
-void __init stmp3xxx_init(void)
-{
- /* Turn off auto-slow and other tricks */
- stmp3xxx_clearl(0x7f00000, REGS_CLKCTRL_BASE + HW_CLKCTRL_HBUS);
-
- stmp3xxx_dma_init();
-}
diff --git a/arch/arm/plat-stmp3xxx/devices.c b/arch/arm/plat-stmp3xxx/devices.c
deleted file mode 100644
index 68fed4b8746a..000000000000
--- a/arch/arm/plat-stmp3xxx/devices.c
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
-* Freescale STMP37XX/STMP378X platform devices
-*
-* Embedded Alley Solutions, Inc <source@embeddedalley.com>
-*
-* Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
-* Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
-*/
-
-/*
-* The code contained herein is licensed under the GNU General Public
-* License. You may obtain a copy of the GNU General Public License
-* Version 2 or later at the following locations:
-*
-* http://www.opensource.org/licenses/gpl-license.html
-* http://www.gnu.org/copyleft/gpl.html
-*/
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/dma-mapping.h>
-
-#include <mach/dma.h>
-#include <mach/platform.h>
-#include <mach/stmp3xxx.h>
-#include <mach/regs-lcdif.h>
-#include <mach/regs-uartapp.h>
-#include <mach/regs-gpmi.h>
-#include <mach/regs-usbctrl.h>
-#include <mach/regs-ssp.h>
-#include <mach/regs-rtc.h>
-
-static u64 common_dmamask = DMA_BIT_MASK(32);
-
-static struct resource appuart_resources[] = {
- {
- .start = IRQ_UARTAPP_INTERNAL,
- .end = IRQ_UARTAPP_INTERNAL,
- .flags = IORESOURCE_IRQ,
- }, {
- .start = IRQ_UARTAPP_RX_DMA,
- .end = IRQ_UARTAPP_RX_DMA,
- .flags = IORESOURCE_IRQ,
- }, {
- .start = IRQ_UARTAPP_TX_DMA,
- .end = IRQ_UARTAPP_TX_DMA,
- .flags = IORESOURCE_IRQ,
- }, {
- .start = REGS_UARTAPP1_PHYS,
- .end = REGS_UARTAPP1_PHYS + REGS_UARTAPP_SIZE,
- .flags = IORESOURCE_MEM,
- }, {
- /* Rx DMA channel */
- .start = STMP3XXX_DMA(6, STMP3XXX_BUS_APBX),
- .end = STMP3XXX_DMA(6, STMP3XXX_BUS_APBX),
- .flags = IORESOURCE_DMA,
- }, {
- /* Tx DMA channel */
- .start = STMP3XXX_DMA(7, STMP3XXX_BUS_APBX),
- .end = STMP3XXX_DMA(7, STMP3XXX_BUS_APBX),
- .flags = IORESOURCE_DMA,
- },
-};
-
-struct platform_device stmp3xxx_appuart = {
- .name = "stmp3xxx-appuart",
- .id = 0,
- .resource = appuart_resources,
- .num_resources = ARRAY_SIZE(appuart_resources),
- .dev = {
- .dma_mask = &common_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
-};
-
-struct platform_device stmp3xxx_watchdog = {
- .name = "stmp3xxx_wdt",
- .id = -1,
-};
-
-static struct resource ts_resource[] = {
- {
- .flags = IORESOURCE_IRQ,
- .start = IRQ_TOUCH_DETECT,
- .end = IRQ_TOUCH_DETECT,
- }, {
- .flags = IORESOURCE_IRQ,
- .start = IRQ_LRADC_CH5,
- .end = IRQ_LRADC_CH5,
- },
-};
-
-struct platform_device stmp3xxx_touchscreen = {
- .name = "stmp3xxx_ts",
- .id = -1,
- .resource = ts_resource,
- .num_resources = ARRAY_SIZE(ts_resource),
-};
-
-/*
-* Keypad device
-*/
-struct platform_device stmp3xxx_keyboard = {
- .name = "stmp3xxx-keyboard",
- .id = -1,
-};
-
-static struct resource gpmi_resources[] = {
- {
- .flags = IORESOURCE_MEM,
- .start = REGS_GPMI_PHYS,
- .end = REGS_GPMI_PHYS + REGS_GPMI_SIZE,
- }, {
- .flags = IORESOURCE_IRQ,
- .start = IRQ_GPMI_DMA,
- .end = IRQ_GPMI_DMA,
- }, {
- .flags = IORESOURCE_DMA,
- .start = STMP3XXX_DMA(4, STMP3XXX_BUS_APBH),
- .end = STMP3XXX_DMA(8, STMP3XXX_BUS_APBH),
- },
-};
-
-struct platform_device stmp3xxx_gpmi = {
- .name = "gpmi",
- .id = -1,
- .dev = {
- .dma_mask = &common_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = gpmi_resources,
- .num_resources = ARRAY_SIZE(gpmi_resources),
-};
-
-static struct resource mmc1_resource[] = {
- {
- .flags = IORESOURCE_MEM,
- .start = REGS_SSP1_PHYS,
- .end = REGS_SSP1_PHYS + REGS_SSP_SIZE,
- }, {
- .flags = IORESOURCE_DMA,
- .start = STMP3XXX_DMA(1, STMP3XXX_BUS_APBH),
- .end = STMP3XXX_DMA(1, STMP3XXX_BUS_APBH),
- }, {
- .flags = IORESOURCE_IRQ,
- .start = IRQ_SSP1_DMA,
- .end = IRQ_SSP1_DMA,
- }, {
- .flags = IORESOURCE_IRQ,
- .start = IRQ_SSP_ERROR,
- .end = IRQ_SSP_ERROR,
- },
-};
-
-struct platform_device stmp3xxx_mmc = {
- .name = "stmp3xxx-mmc",
- .id = 1,
- .dev = {
- .dma_mask = &common_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = mmc1_resource,
- .num_resources = ARRAY_SIZE(mmc1_resource),
-};
-
-static struct resource usb_resources[] = {
- {
- .start = REGS_USBCTRL_PHYS,
- .end = REGS_USBCTRL_PHYS + SZ_4K,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_USB_CTRL,
- .end = IRQ_USB_CTRL,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-struct platform_device stmp3xxx_udc = {
- .name = "fsl-usb2-udc",
- .id = -1,
- .dev = {
- .dma_mask = &common_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = usb_resources,
- .num_resources = ARRAY_SIZE(usb_resources),
-};
-
-struct platform_device stmp3xxx_ehci = {
- .name = "fsl-ehci",
- .id = -1,
- .dev = {
- .dma_mask = &common_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = usb_resources,
- .num_resources = ARRAY_SIZE(usb_resources),
-};
-
-static struct resource rtc_resources[] = {
- {
- .start = REGS_RTC_PHYS,
- .end = REGS_RTC_PHYS + REGS_RTC_SIZE,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_RTC_ALARM,
- .end = IRQ_RTC_ALARM,
- .flags = IORESOURCE_IRQ,
- }, {
- .start = IRQ_RTC_1MSEC,
- .end = IRQ_RTC_1MSEC,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-struct platform_device stmp3xxx_rtc = {
- .name = "stmp3xxx-rtc",
- .id = -1,
- .resource = rtc_resources,
- .num_resources = ARRAY_SIZE(rtc_resources),
-};
-
-static struct resource ssp1_resources[] = {
- {
- .start = REGS_SSP1_PHYS,
- .end = REGS_SSP1_PHYS + REGS_SSP_SIZE,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_SSP1_DMA,
- .end = IRQ_SSP1_DMA,
- .flags = IORESOURCE_IRQ,
- }, {
- .start = STMP3XXX_DMA(1, STMP3XXX_BUS_APBH),
- .end = STMP3XXX_DMA(1, STMP3XXX_BUS_APBH),
- .flags = IORESOURCE_DMA,
- },
-};
-
-static struct resource ssp2_resources[] = {
- {
- .start = REGS_SSP2_PHYS,
- .end = REGS_SSP2_PHYS + REGS_SSP_SIZE,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_SSP2_DMA,
- .end = IRQ_SSP2_DMA,
- .flags = IORESOURCE_IRQ,
- }, {
- .start = STMP3XXX_DMA(2, STMP3XXX_BUS_APBH),
- .end = STMP3XXX_DMA(2, STMP3XXX_BUS_APBH),
- .flags = IORESOURCE_DMA,
- },
-};
-
-struct platform_device stmp3xxx_spi1 = {
- .name = "stmp3xxx_ssp",
- .id = 1,
- .dev = {
- .dma_mask = &common_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = ssp1_resources,
- .num_resources = ARRAY_SIZE(ssp1_resources),
-};
-
-struct platform_device stmp3xxx_spi2 = {
- .name = "stmp3xxx_ssp",
- .id = 2,
- .dev = {
- .dma_mask = &common_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = ssp2_resources,
- .num_resources = ARRAY_SIZE(ssp2_resources),
-};
-
-static struct resource fb_resource[] = {
- {
- .flags = IORESOURCE_IRQ,
- .start = IRQ_LCDIF_DMA,
- .end = IRQ_LCDIF_DMA,
- }, {
- .flags = IORESOURCE_IRQ,
- .start = IRQ_LCDIF_ERROR,
- .end = IRQ_LCDIF_ERROR,
- }, {
- .flags = IORESOURCE_MEM,
- .start = REGS_LCDIF_PHYS,
- .end = REGS_LCDIF_PHYS + REGS_LCDIF_SIZE,
- },
-};
-
-struct platform_device stmp3xxx_framebuffer = {
- .name = "stmp3xxx-fb",
- .id = -1,
- .dev = {
- .dma_mask = &common_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .num_resources = ARRAY_SIZE(fb_resource),
- .resource = fb_resource,
-};
-
-#define CMDLINE_DEVICE_CHOOSE(name, dev1, dev2) \
- static char *cmdline_device_##name; \
- static int cmdline_device_##name##_setup(char *dev) \
- { \
- cmdline_device_##name = dev + 1; \
- return 0; \
- } \
- __setup(#name, cmdline_device_##name##_setup); \
- int stmp3xxx_##name##_device_register(void) \
- { \
- struct platform_device *d = NULL; \
- if (!cmdline_device_##name || \
- !strcmp(cmdline_device_##name, #dev1)) \
- d = &stmp3xxx_##dev1; \
- else if (!strcmp(cmdline_device_##name, #dev2)) \
- d = &stmp3xxx_##dev2; \
- else \
- printk(KERN_ERR"Unknown %s assignment '%s'.\n", \
- #name, cmdline_device_##name); \
- return d ? platform_device_register(d) : -ENOENT; \
- }
-
-CMDLINE_DEVICE_CHOOSE(ssp1, mmc, spi1)
-CMDLINE_DEVICE_CHOOSE(ssp2, gpmi, spi2)
-
-struct platform_device stmp3xxx_backlight = {
- .name = "stmp3xxx-bl",
- .id = -1,
-};
-
-struct platform_device stmp3xxx_rotdec = {
- .name = "stmp3xxx-rotdec",
- .id = -1,
-};
-
-struct platform_device stmp3xxx_persistent = {
- .name = "stmp3xxx-persistent",
- .id = -1,
-};
-
-struct platform_device stmp3xxx_dcp_bootstream = {
- .name = "stmp3xxx-dcpboot",
- .id = -1,
- .dev = {
- .dma_mask = &common_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
-};
-
-static struct resource dcp_resources[] = {
- {
- .start = IRQ_DCP_VMI,
- .end = IRQ_DCP_VMI,
- .flags = IORESOURCE_IRQ,
- }, {
- .start = IRQ_DCP,
- .end = IRQ_DCP,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-struct platform_device stmp3xxx_dcp = {
- .name = "stmp3xxx-dcp",
- .id = -1,
- .resource = dcp_resources,
- .num_resources = ARRAY_SIZE(dcp_resources),
- .dev = {
- .dma_mask = &common_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
-};
-
-static struct resource battery_resource[] = {
- {
- .flags = IORESOURCE_IRQ,
- .start = IRQ_VDD5V,
- .end = IRQ_VDD5V,
- },
-};
-
-struct platform_device stmp3xxx_battery = {
- .name = "stmp3xxx-battery",
- .resource = battery_resource,
- .num_resources = ARRAY_SIZE(battery_resource),
-};
diff --git a/arch/arm/plat-stmp3xxx/dma.c b/arch/arm/plat-stmp3xxx/dma.c
deleted file mode 100644
index b4dcf8c0477d..000000000000
--- a/arch/arm/plat-stmp3xxx/dma.c
+++ /dev/null
@@ -1,464 +0,0 @@
-/*
- * DMA helper routines for Freescale STMP37XX/STMP378X
- *
- * Author: dmitry pervushin <dpervushin@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#include <linux/gfp.h>
-#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/dmapool.h>
-#include <linux/sysdev.h>
-#include <linux/cpufreq.h>
-
-#include <asm/page.h>
-
-#include <mach/platform.h>
-#include <mach/dma.h>
-#include <mach/regs-apbx.h>
-#include <mach/regs-apbh.h>
-
-static const size_t pool_item_size = sizeof(struct stmp3xxx_dma_command);
-static const size_t pool_alignment = 8;
-static struct stmp3xxx_dma_user {
- void *pool;
- int inuse;
- const char *name;
-} channels[MAX_DMA_CHANNELS];
-
-#define IS_VALID_CHANNEL(ch) ((ch) >= 0 && (ch) < MAX_DMA_CHANNELS)
-#define IS_USED(ch) (channels[ch].inuse)
-
-int stmp3xxx_dma_request(int ch, struct device *dev, const char *name)
-{
- struct stmp3xxx_dma_user *user;
- int err = 0;
-
- user = channels + ch;
- if (!IS_VALID_CHANNEL(ch)) {
- err = -ENODEV;
- goto out;
- }
- if (IS_USED(ch)) {
- err = -EBUSY;
- goto out;
- }
- /* Create a pool to allocate dma commands from */
- user->pool = dma_pool_create(name, dev, pool_item_size,
- pool_alignment, PAGE_SIZE);
- if (user->pool == NULL) {
- err = -ENOMEM;
- goto out;
- }
- user->name = name;
- user->inuse++;
-out:
- return err;
-}
-EXPORT_SYMBOL(stmp3xxx_dma_request);
-
-int stmp3xxx_dma_release(int ch)
-{
- struct stmp3xxx_dma_user *user = channels + ch;
- int err = 0;
-
- if (!IS_VALID_CHANNEL(ch)) {
- err = -ENODEV;
- goto out;
- }
- if (!IS_USED(ch)) {
- err = -EBUSY;
- goto out;
- }
- BUG_ON(user->pool == NULL);
- dma_pool_destroy(user->pool);
- user->inuse--;
-out:
- return err;
-}
-EXPORT_SYMBOL(stmp3xxx_dma_release);
-
-int stmp3xxx_dma_read_semaphore(int channel)
-{
- int sem = -1;
-
- switch (STMP3XXX_DMA_BUS(channel)) {
- case STMP3XXX_BUS_APBH:
- sem = __raw_readl(REGS_APBH_BASE + HW_APBH_CHn_SEMA +
- STMP3XXX_DMA_CHANNEL(channel) * 0x70);
- sem &= BM_APBH_CHn_SEMA_PHORE;
- sem >>= BP_APBH_CHn_SEMA_PHORE;
- break;
-
- case STMP3XXX_BUS_APBX:
- sem = __raw_readl(REGS_APBX_BASE + HW_APBX_CHn_SEMA +
- STMP3XXX_DMA_CHANNEL(channel) * 0x70);
- sem &= BM_APBX_CHn_SEMA_PHORE;
- sem >>= BP_APBX_CHn_SEMA_PHORE;
- break;
- default:
- BUG();
- }
- return sem;
-}
-EXPORT_SYMBOL(stmp3xxx_dma_read_semaphore);
-
-int stmp3xxx_dma_allocate_command(int channel,
- struct stmp3xxx_dma_descriptor *descriptor)
-{
- struct stmp3xxx_dma_user *user = channels + channel;
- int err = 0;
-
- if (!IS_VALID_CHANNEL(channel)) {
- err = -ENODEV;
- goto out;
- }
- if (!IS_USED(channel)) {
- err = -EBUSY;
- goto out;
- }
- if (descriptor == NULL) {
- err = -EINVAL;
- goto out;
- }
-
- /* Allocate memory for a command from the buffer */
- descriptor->command =
- dma_pool_alloc(user->pool, GFP_KERNEL, &descriptor->handle);
-
- /* Check it worked */
- if (!descriptor->command) {
- err = -ENOMEM;
- goto out;
- }
-
- memset(descriptor->command, 0, pool_item_size);
-out:
- WARN_ON(err);
- return err;
-}
-EXPORT_SYMBOL(stmp3xxx_dma_allocate_command);
-
-int stmp3xxx_dma_free_command(int channel,
- struct stmp3xxx_dma_descriptor *descriptor)
-{
- int err = 0;
-
- if (!IS_VALID_CHANNEL(channel)) {
- err = -ENODEV;
- goto out;
- }
- if (!IS_USED(channel)) {
- err = -EBUSY;
- goto out;
- }
-
- /* Return the command memory to the pool */
- dma_pool_free(channels[channel].pool, descriptor->command,
- descriptor->handle);
-
- /* Initialise descriptor so we're not tempted to use it */
- descriptor->command = NULL;
- descriptor->handle = 0;
- descriptor->virtual_buf_ptr = NULL;
- descriptor->next_descr = NULL;
-
- WARN_ON(err);
-out:
- return err;
-}
-EXPORT_SYMBOL(stmp3xxx_dma_free_command);
-
-void stmp3xxx_dma_go(int channel,
- struct stmp3xxx_dma_descriptor *head, u32 semaphore)
-{
- int ch = STMP3XXX_DMA_CHANNEL(channel);
- void __iomem *c, *s;
-
- switch (STMP3XXX_DMA_BUS(channel)) {
- case STMP3XXX_BUS_APBH:
- c = REGS_APBH_BASE + HW_APBH_CHn_NXTCMDAR + 0x70 * ch;
- s = REGS_APBH_BASE + HW_APBH_CHn_SEMA + 0x70 * ch;
- break;
-
- case STMP3XXX_BUS_APBX:
- c = REGS_APBX_BASE + HW_APBX_CHn_NXTCMDAR + 0x70 * ch;
- s = REGS_APBX_BASE + HW_APBX_CHn_SEMA + 0x70 * ch;
- break;
-
- default:
- return;
- }
-
- /* Set next command */
- __raw_writel(head->handle, c);
- /* Set counting semaphore (kicks off transfer). Assumes
- peripheral has been set up correctly */
- __raw_writel(semaphore, s);
-}
-EXPORT_SYMBOL(stmp3xxx_dma_go);
-
-int stmp3xxx_dma_running(int channel)
-{
- switch (STMP3XXX_DMA_BUS(channel)) {
- case STMP3XXX_BUS_APBH:
- return (__raw_readl(REGS_APBH_BASE + HW_APBH_CHn_SEMA +
- 0x70 * STMP3XXX_DMA_CHANNEL(channel))) &
- BM_APBH_CHn_SEMA_PHORE;
-
- case STMP3XXX_BUS_APBX:
- return (__raw_readl(REGS_APBX_BASE + HW_APBX_CHn_SEMA +
- 0x70 * STMP3XXX_DMA_CHANNEL(channel))) &
- BM_APBX_CHn_SEMA_PHORE;
- default:
- BUG();
- return 0;
- }
-}
-EXPORT_SYMBOL(stmp3xxx_dma_running);
-
-/*
- * Circular dma chain management
- */
-void stmp3xxx_dma_free_chain(struct stmp37xx_circ_dma_chain *chain)
-{
- int i;
-
- for (i = 0; i < chain->total_count; i++)
- stmp3xxx_dma_free_command(
- STMP3XXX_DMA(chain->channel, chain->bus),
- &chain->chain[i]);
-}
-EXPORT_SYMBOL(stmp3xxx_dma_free_chain);
-
-int stmp3xxx_dma_make_chain(int ch, struct stmp37xx_circ_dma_chain *chain,
- struct stmp3xxx_dma_descriptor descriptors[],
- unsigned items)
-{
- int i;
- int err = 0;
-
- if (items == 0)
- return err;
-
- for (i = 0; i < items; i++) {
- err = stmp3xxx_dma_allocate_command(ch, &descriptors[i]);
- if (err) {
- WARN_ON(err);
- /*
- * Couldn't allocate the whole chain.
- * deallocate what has been allocated
- */
- if (i) {
- do {
- stmp3xxx_dma_free_command(ch,
- &descriptors
- [i]);
- } while (i-- > 0);
- }
- return err;
- }
-
- /* link them! */
- if (i > 0) {
- descriptors[i - 1].next_descr = &descriptors[i];
- descriptors[i - 1].command->next =
- descriptors[i].handle;
- }
- }
-
- /* make list circular */
- descriptors[items - 1].next_descr = &descriptors[0];
- descriptors[items - 1].command->next = descriptors[0].handle;
-
- chain->total_count = items;
- chain->chain = descriptors;
- chain->free_index = 0;
- chain->active_index = 0;
- chain->cooked_index = 0;
- chain->free_count = items;
- chain->active_count = 0;
- chain->cooked_count = 0;
- chain->bus = STMP3XXX_DMA_BUS(ch);
- chain->channel = STMP3XXX_DMA_CHANNEL(ch);
- return err;
-}
-EXPORT_SYMBOL(stmp3xxx_dma_make_chain);
-
-void stmp37xx_circ_clear_chain(struct stmp37xx_circ_dma_chain *chain)
-{
- BUG_ON(stmp3xxx_dma_running(STMP3XXX_DMA(chain->channel, chain->bus)));
- chain->free_index = 0;
- chain->active_index = 0;
- chain->cooked_index = 0;
- chain->free_count = chain->total_count;
- chain->active_count = 0;
- chain->cooked_count = 0;
-}
-EXPORT_SYMBOL(stmp37xx_circ_clear_chain);
-
-void stmp37xx_circ_advance_free(struct stmp37xx_circ_dma_chain *chain,
- unsigned count)
-{
- BUG_ON(chain->cooked_count < count);
-
- chain->cooked_count -= count;
- chain->cooked_index += count;
- chain->cooked_index %= chain->total_count;
- chain->free_count += count;
-}
-EXPORT_SYMBOL(stmp37xx_circ_advance_free);
-
-void stmp37xx_circ_advance_active(struct stmp37xx_circ_dma_chain *chain,
- unsigned count)
-{
- void __iomem *c;
- u32 mask_clr, mask;
- BUG_ON(chain->free_count < count);
-
- chain->free_count -= count;
- chain->free_index += count;
- chain->free_index %= chain->total_count;
- chain->active_count += count;
-
- switch (chain->bus) {
- case STMP3XXX_BUS_APBH:
- c = REGS_APBH_BASE + HW_APBH_CHn_SEMA + 0x70 * chain->channel;
- mask_clr = BM_APBH_CHn_SEMA_INCREMENT_SEMA;
- mask = BF(count, APBH_CHn_SEMA_INCREMENT_SEMA);
- break;
- case STMP3XXX_BUS_APBX:
- c = REGS_APBX_BASE + HW_APBX_CHn_SEMA + 0x70 * chain->channel;
- mask_clr = BM_APBX_CHn_SEMA_INCREMENT_SEMA;
- mask = BF(count, APBX_CHn_SEMA_INCREMENT_SEMA);
- break;
- default:
- BUG();
- return;
- }
-
- /* Set counting semaphore (kicks off transfer). Assumes
- peripheral has been set up correctly */
- stmp3xxx_clearl(mask_clr, c);
- stmp3xxx_setl(mask, c);
-}
-EXPORT_SYMBOL(stmp37xx_circ_advance_active);
-
-unsigned stmp37xx_circ_advance_cooked(struct stmp37xx_circ_dma_chain *chain)
-{
- unsigned cooked;
-
- cooked = chain->active_count -
- stmp3xxx_dma_read_semaphore(STMP3XXX_DMA(chain->channel, chain->bus));
-
- chain->active_count -= cooked;
- chain->active_index += cooked;
- chain->active_index %= chain->total_count;
-
- chain->cooked_count += cooked;
-
- return cooked;
-}
-EXPORT_SYMBOL(stmp37xx_circ_advance_cooked);
-
-void stmp3xxx_dma_set_alt_target(int channel, int function)
-{
-#if defined(CONFIG_ARCH_STMP37XX)
- unsigned bits = 4;
-#elif defined(CONFIG_ARCH_STMP378X)
- unsigned bits = 2;
-#else
-#error wrong arch
-#endif
- int shift = STMP3XXX_DMA_CHANNEL(channel) * bits;
- unsigned mask = (1<<bits) - 1;
- void __iomem *c;
-
- BUG_ON(function < 0 || function >= (1<<bits));
- pr_debug("%s: channel = %d, using mask %x, "
- "shift = %d\n", __func__, channel, mask, shift);
-
- switch (STMP3XXX_DMA_BUS(channel)) {
- case STMP3XXX_BUS_APBH:
- c = REGS_APBH_BASE + HW_APBH_DEVSEL;
- break;
- case STMP3XXX_BUS_APBX:
- c = REGS_APBX_BASE + HW_APBX_DEVSEL;
- break;
- default:
- BUG();
- }
- stmp3xxx_clearl(mask << shift, c);
- stmp3xxx_setl(mask << shift, c);
-}
-EXPORT_SYMBOL(stmp3xxx_dma_set_alt_target);
-
-void stmp3xxx_dma_suspend(void)
-{
- stmp3xxx_setl(BM_APBH_CTRL0_CLKGATE, REGS_APBH_BASE + HW_APBH_CTRL0);
- stmp3xxx_setl(BM_APBX_CTRL0_CLKGATE, REGS_APBX_BASE + HW_APBX_CTRL0);
-}
-
-void stmp3xxx_dma_resume(void)
-{
- stmp3xxx_clearl(BM_APBH_CTRL0_CLKGATE | BM_APBH_CTRL0_SFTRST,
- REGS_APBH_BASE + HW_APBH_CTRL0);
- stmp3xxx_clearl(BM_APBX_CTRL0_CLKGATE | BM_APBX_CTRL0_SFTRST,
- REGS_APBX_BASE + HW_APBX_CTRL0);
-}
-
-#ifdef CONFIG_CPU_FREQ
-
-struct dma_notifier_block {
- struct notifier_block nb;
- void *data;
-};
-
-static int dma_cpufreq_notifier(struct notifier_block *self,
- unsigned long phase, void *p)
-{
- switch (phase) {
- case CPUFREQ_POSTCHANGE:
- stmp3xxx_dma_resume();
- break;
-
- case CPUFREQ_PRECHANGE:
- stmp3xxx_dma_suspend();
- break;
-
- default:
- break;
- }
-
- return NOTIFY_DONE;
-}
-
-static struct dma_notifier_block dma_cpufreq_nb = {
- .nb = {
- .notifier_call = dma_cpufreq_notifier,
- },
-};
-#endif /* CONFIG_CPU_FREQ */
-
-void __init stmp3xxx_dma_init(void)
-{
- stmp3xxx_clearl(BM_APBH_CTRL0_CLKGATE | BM_APBH_CTRL0_SFTRST,
- REGS_APBH_BASE + HW_APBH_CTRL0);
- stmp3xxx_clearl(BM_APBX_CTRL0_CLKGATE | BM_APBX_CTRL0_SFTRST,
- REGS_APBX_BASE + HW_APBX_CTRL0);
-#ifdef CONFIG_CPU_FREQ
- cpufreq_register_notifier(&dma_cpufreq_nb.nb,
- CPUFREQ_TRANSITION_NOTIFIER);
-#endif /* CONFIG_CPU_FREQ */
-}
diff --git a/arch/arm/plat-stmp3xxx/include/mach/clkdev.h b/arch/arm/plat-stmp3xxx/include/mach/clkdev.h
deleted file mode 100644
index f9c39772d7c5..000000000000
--- a/arch/arm/plat-stmp3xxx/include/mach/clkdev.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#ifndef __ASM_MACH_CLKDEV_H
-#define __ASM_MACH_CLKDEV_H
-
-#define __clk_get(clk) ({ 1; })
-#define __clk_put(clk) do { } while (0)
-
-#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/cputype.h b/arch/arm/plat-stmp3xxx/include/mach/cputype.h
deleted file mode 100644
index b4e205b95f2c..000000000000
--- a/arch/arm/plat-stmp3xxx/include/mach/cputype.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Freescale STMP37XX/STMP378X CPU type detection
- *
- * Embedded Alley Solutions, Inc <source@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#ifndef __ASM_PLAT_CPU_H
-#define __ASM_PLAT_CPU_H
-
-#ifdef CONFIG_ARCH_STMP37XX
-#define cpu_is_stmp37xx() (1)
-#else
-#define cpu_is_stmp37xx() (0)
-#endif
-
-#ifdef CONFIG_ARCH_STMP378X
-#define cpu_is_stmp378x() (1)
-#else
-#define cpu_is_stmp378x() (0)
-#endif
-
-#endif /* __ASM_PLAT_CPU_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/debug-macro.S b/arch/arm/plat-stmp3xxx/include/mach/debug-macro.S
deleted file mode 100644
index d3a0985c9681..000000000000
--- a/arch/arm/plat-stmp3xxx/include/mach/debug-macro.S
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Debugging macro include header
- *
- * Embedded Alley Solutions, Inc <source@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-
- .macro addruart, rp, rv
- mov \rp, #0x00070000
- add \rv, \rp, #0xf0000000 @ virtual base
- add \rp, \rp, #0x80000000 @ physical base
- .endm
-
- .macro senduart,rd,rx
- strb \rd, [\rx, #0] @ data register at 0
- .endm
-
- .macro waituart,rd,rx
-1001: ldr \rd, [\rx, #0x18] @ UARTFLG
- tst \rd, #1 << 5 @ UARTFLGUTXFF - 1 when full
- bne 1001b
- .endm
-
- .macro busyuart,rd,rx
-1001: ldr \rd, [\rx, #0x18] @ UARTFLG
- tst \rd, #1 << 3 @ UARTFLGUBUSY - 1 when busy
- bne 1001b
- .endm
diff --git a/arch/arm/plat-stmp3xxx/include/mach/dma.h b/arch/arm/plat-stmp3xxx/include/mach/dma.h
deleted file mode 100644
index 7c58557c6766..000000000000
--- a/arch/arm/plat-stmp3xxx/include/mach/dma.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Freescale STMP37XX/STMP378X DMA helper interface
- *
- * Embedded Alley Solutions, Inc <source@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#ifndef __ASM_PLAT_STMP3XXX_DMA_H
-#define __ASM_PLAT_STMP3XXX_DMA_H
-
-#include <linux/platform_device.h>
-#include <linux/dmapool.h>
-
-#if !defined(MAX_PIO_WORDS)
-#define MAX_PIO_WORDS (15)
-#endif
-
-#define STMP3XXX_BUS_APBH 0
-#define STMP3XXX_BUS_APBX 1
-#define STMP3XXX_DMA_MAX_CHANNEL 16
-#define STMP3XXX_DMA_BUS(dma) ((dma) / 16)
-#define STMP3XXX_DMA_CHANNEL(dma) ((dma) % 16)
-#define STMP3XXX_DMA(channel, bus) ((bus) * 16 + (channel))
-#define MAX_DMA_ADDRESS 0xffffffff
-#define MAX_DMA_CHANNELS 32
-
-struct stmp3xxx_dma_command {
- u32 next;
- u32 cmd;
- union {
- u32 buf_ptr;
- u32 alternate;
- };
- u32 pio_words[MAX_PIO_WORDS];
-};
-
-struct stmp3xxx_dma_descriptor {
- struct stmp3xxx_dma_command *command;
- dma_addr_t handle;
-
- /* The virtual address of the buffer pointer */
- void *virtual_buf_ptr;
- /* The next descriptor in a the DMA chain (optional) */
- struct stmp3xxx_dma_descriptor *next_descr;
-};
-
-struct stmp37xx_circ_dma_chain {
- unsigned total_count;
- struct stmp3xxx_dma_descriptor *chain;
-
- unsigned free_index;
- unsigned free_count;
- unsigned active_index;
- unsigned active_count;
- unsigned cooked_index;
- unsigned cooked_count;
-
- int bus;
- unsigned channel;
-};
-
-static inline struct stmp3xxx_dma_descriptor
- *stmp3xxx_dma_circ_get_free_head(struct stmp37xx_circ_dma_chain *chain)
-{
- return &(chain->chain[chain->free_index]);
-}
-
-static inline struct stmp3xxx_dma_descriptor
- *stmp3xxx_dma_circ_get_cooked_head(struct stmp37xx_circ_dma_chain *chain)
-{
- return &(chain->chain[chain->cooked_index]);
-}
-
-int stmp3xxx_dma_request(int ch, struct device *dev, const char *name);
-int stmp3xxx_dma_release(int ch);
-int stmp3xxx_dma_allocate_command(int ch,
- struct stmp3xxx_dma_descriptor *descriptor);
-int stmp3xxx_dma_free_command(int ch,
- struct stmp3xxx_dma_descriptor *descriptor);
-void stmp3xxx_dma_continue(int channel, u32 semaphore);
-void stmp3xxx_dma_go(int ch, struct stmp3xxx_dma_descriptor *head,
- u32 semaphore);
-int stmp3xxx_dma_running(int ch);
-int stmp3xxx_dma_make_chain(int ch, struct stmp37xx_circ_dma_chain *chain,
- struct stmp3xxx_dma_descriptor descriptors[],
- unsigned items);
-void stmp3xxx_dma_free_chain(struct stmp37xx_circ_dma_chain *chain);
-void stmp37xx_circ_clear_chain(struct stmp37xx_circ_dma_chain *chain);
-void stmp37xx_circ_advance_free(struct stmp37xx_circ_dma_chain *chain,
- unsigned count);
-void stmp37xx_circ_advance_active(struct stmp37xx_circ_dma_chain *chain,
- unsigned count);
-unsigned stmp37xx_circ_advance_cooked(struct stmp37xx_circ_dma_chain *chain);
-int stmp3xxx_dma_read_semaphore(int ch);
-void stmp3xxx_dma_init(void);
-void stmp3xxx_dma_set_alt_target(int ch, int target);
-void stmp3xxx_dma_suspend(void);
-void stmp3xxx_dma_resume(void);
-
-/*
- * STMP37xx and STMP378x have different DMA control
- * registers layout
- */
-
-void stmp3xxx_arch_dma_freeze(int ch);
-void stmp3xxx_arch_dma_unfreeze(int ch);
-void stmp3xxx_arch_dma_reset_channel(int ch);
-void stmp3xxx_arch_dma_enable_interrupt(int ch);
-void stmp3xxx_arch_dma_clear_interrupt(int ch);
-int stmp3xxx_arch_dma_is_interrupt(int ch);
-
-static inline void stmp3xxx_dma_reset_channel(int ch)
-{
- stmp3xxx_arch_dma_reset_channel(ch);
-}
-
-
-static inline void stmp3xxx_dma_freeze(int ch)
-{
- stmp3xxx_arch_dma_freeze(ch);
-}
-
-static inline void stmp3xxx_dma_unfreeze(int ch)
-{
- stmp3xxx_arch_dma_unfreeze(ch);
-}
-
-static inline void stmp3xxx_dma_enable_interrupt(int ch)
-{
- stmp3xxx_arch_dma_enable_interrupt(ch);
-}
-
-static inline void stmp3xxx_dma_clear_interrupt(int ch)
-{
- stmp3xxx_arch_dma_clear_interrupt(ch);
-}
-
-static inline int stmp3xxx_dma_is_interrupt(int ch)
-{
- return stmp3xxx_arch_dma_is_interrupt(ch);
-}
-
-#endif /* __ASM_PLAT_STMP3XXX_DMA_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/gpio.h b/arch/arm/plat-stmp3xxx/include/mach/gpio.h
deleted file mode 100644
index a8b579256170..000000000000
--- a/arch/arm/plat-stmp3xxx/include/mach/gpio.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Freescale STMP37XX/STMP378X GPIO interface
- *
- * Embedded Alley Solutions, Inc <source@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#ifndef __ASM_PLAT_GPIO_H
-#define __ASM_PLAT_GPIO_H
-
-#define ARCH_NR_GPIOS (32 * 3)
-#define gpio_to_irq(gpio) __gpio_to_irq(gpio)
-#define gpio_get_value(gpio) __gpio_get_value(gpio)
-#define gpio_set_value(gpio, value) __gpio_set_value(gpio, value)
-
-#include <asm-generic/gpio.h>
-
-#endif /* __ASM_PLAT_GPIO_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/gpmi.h b/arch/arm/plat-stmp3xxx/include/mach/gpmi.h
deleted file mode 100644
index e166432910ad..000000000000
--- a/arch/arm/plat-stmp3xxx/include/mach/gpmi.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef __MACH_GPMI_H
-
-#include <linux/mtd/partitions.h>
-#include <mach/regs-gpmi.h>
-
-struct gpmi_platform_data {
- void *pins;
- int nr_parts;
- struct mtd_partition *parts;
- const char *part_types[];
-};
-#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/hardware.h b/arch/arm/plat-stmp3xxx/include/mach/hardware.h
deleted file mode 100644
index 47b8978405bc..000000000000
--- a/arch/arm/plat-stmp3xxx/include/mach/hardware.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * This file contains the hardware definitions of the Freescale STMP3XXX
- *
- * Copyright (C) 2005 Sigmatel Inc
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#ifndef __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
-
-/*
- * Where in virtual memory the IO devices (timers, system controllers
- * and so on)
- */
-#define IO_BASE 0xF0000000 /* VA of IO */
-#define IO_SIZE 0x00100000 /* How much? */
-#define IO_START 0x80000000 /* PA of IO */
-
-/* macro to get at IO space when running virtually */
-#define IO_ADDRESS(x) (((x) & 0x000fffff) | IO_BASE)
-
-#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/io.h b/arch/arm/plat-stmp3xxx/include/mach/io.h
deleted file mode 100644
index d08b1b7f3d1c..000000000000
--- a/arch/arm/plat-stmp3xxx/include/mach/io.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2005 Sigmatel Inc
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-#define __io(a) __typesafe_io(a)
-#define __mem_pci(a) (a)
-#define __mem_isa(a) (a)
-
-#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/memory.h b/arch/arm/plat-stmp3xxx/include/mach/memory.h
deleted file mode 100644
index 61fa54882e12..000000000000
--- a/arch/arm/plat-stmp3xxx/include/mach/memory.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#ifndef __ASM_ARCH_MEMORY_H
-#define __ASM_ARCH_MEMORY_H
-
-/*
- * Physical DRAM offset.
- */
-#define PLAT_PHYS_OFFSET UL(0x40000000)
-
-#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/mmc.h b/arch/arm/plat-stmp3xxx/include/mach/mmc.h
deleted file mode 100644
index ba81e1543761..000000000000
--- a/arch/arm/plat-stmp3xxx/include/mach/mmc.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef _MACH_MMC_H
-#define _MACH_MMC_H
-
-#include <mach/regs-ssp.h>
-
-struct stmp3xxxmmc_platform_data {
- int (*get_wp)(void);
- unsigned long (*setclock)(void __iomem *base, unsigned long);
- void (*cmd_pullup)(int);
- int (*hw_init)(void);
- void (*hw_release)(void);
-};
-
-#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/pinmux.h b/arch/arm/plat-stmp3xxx/include/mach/pinmux.h
deleted file mode 100644
index cc5af82279ad..000000000000
--- a/arch/arm/plat-stmp3xxx/include/mach/pinmux.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Freescale STMP37XX/STMP378X Pin Multiplexing
- *
- * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#ifndef __PINMUX_H
-#define __PINMUX_H
-
-#include <linux/spinlock.h>
-#include <linux/types.h>
-#include <linux/gpio.h>
-#include <asm-generic/gpio.h>
-
-/* Pin definitions */
-#include "pins.h"
-#include <mach/pins.h>
-
-/*
- * Each pin may be routed up to four different HW interfaces
- * including GPIO
- */
-enum pin_fun {
- PIN_FUN1 = 0,
- PIN_FUN2,
- PIN_FUN3,
- PIN_GPIO,
-};
-
-/*
- * Each pin may have different output drive strength in range from
- * 4mA to 20mA. The most common case is 4, 8 and 12 mA strengths.
- */
-enum pin_strength {
- PIN_4MA = 0,
- PIN_8MA,
- PIN_12MA,
- PIN_16MA,
- PIN_20MA,
-};
-
-/*
- * Each pin can be programmed for 1.8V or 3.3V
- */
-enum pin_voltage {
- PIN_1_8V = 0,
- PIN_3_3V,
-};
-
-/*
- * Structure to define a group of pins and their parameters
- */
-struct pin_desc {
- unsigned id;
- enum pin_fun fun;
- enum pin_strength strength;
- enum pin_voltage voltage;
- unsigned pullup:1;
-};
-
-struct pin_group {
- struct pin_desc *pins;
- int nr_pins;
-};
-
-/* Set pin drive strength */
-void stmp3xxx_pin_strength(unsigned id, enum pin_strength strength,
- const char *label);
-
-/* Set pin voltage */
-void stmp3xxx_pin_voltage(unsigned id, enum pin_voltage voltage,
- const char *label);
-
-/* Enable pull-up resistor for a pin */
-void stmp3xxx_pin_pullup(unsigned id, int enable, const char *label);
-
-/*
- * Request a pin ownership, only one module (identified by @label)
- * may own a pin.
- */
-int stmp3xxx_request_pin(unsigned id, enum pin_fun fun, const char *label);
-
-/* Release pin */
-void stmp3xxx_release_pin(unsigned id, const char *label);
-
-void stmp3xxx_set_pin_type(unsigned id, enum pin_fun fun);
-
-/*
- * Each bank is associated with a number of registers to control
- * pin function, drive strength, voltage and pull-up reigster. The
- * number of registers of a given type depends on the number of bits
- * describin particular pin.
- */
-#define HW_MUXSEL_NUM 2 /* registers per bank */
-#define HW_MUXSEL_PIN_LEN 2 /* bits per pin */
-#define HW_MUXSEL_PIN_NUM 16 /* pins per register */
-#define HW_MUXSEL_PINFUN_MASK 0x3 /* pin function mask */
-#define HW_MUXSEL_PINFUN_NUM 4 /* four options for a pin */
-
-#define HW_DRIVE_NUM 4 /* registers per bank */
-#define HW_DRIVE_PIN_LEN 4 /* bits per pin */
-#define HW_DRIVE_PIN_NUM 8 /* pins per register */
-#define HW_DRIVE_PINDRV_MASK 0x3 /* pin strength mask - 2 bits */
-#define HW_DRIVE_PINDRV_NUM 5 /* five possible strength values */
-#define HW_DRIVE_PINV_MASK 0x4 /* pin voltage mask - 1 bit */
-
-
-struct stmp3xxx_pinmux_bank {
- struct gpio_chip chip;
-
- /* Pins allocation map */
- unsigned long pin_map;
-
- /* Pin owner names */
- const char *pin_labels[32];
-
- /* Bank registers */
- void __iomem *hw_muxsel[HW_MUXSEL_NUM];
- void __iomem *hw_drive[HW_DRIVE_NUM];
- void __iomem *hw_pull;
-
- void __iomem *pin2irq,
- *irqlevel,
- *irqpolarity,
- *irqen,
- *irqstat;
-
- /* HW MUXSEL register function bit values */
- u8 functions[HW_MUXSEL_PINFUN_NUM];
-
- /*
- * HW DRIVE register strength bit values:
- * 0xff - requested strength is not supported for this bank
- */
- u8 strengths[HW_DRIVE_PINDRV_NUM];
-
- /* GPIO things */
- void __iomem *hw_gpio_in,
- *hw_gpio_out,
- *hw_gpio_doe;
- int irq, virq;
-};
-
-int __init stmp3xxx_pinmux_init(int virtual_irq_start);
-
-#endif /* __PINMUX_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/pins.h b/arch/arm/plat-stmp3xxx/include/mach/pins.h
deleted file mode 100644
index c573318e1caa..000000000000
--- a/arch/arm/plat-stmp3xxx/include/mach/pins.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Freescale STMP37XX/STMP378X Pin multiplexing interface definitions
- *
- * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#ifndef __ASM_PLAT_PINS_H
-#define __ASM_PLAT_PINS_H
-
-#define STMP3XXX_PINID(bank, pin) (bank * 32 + pin)
-#define STMP3XXX_PINID_TO_BANK(pinid) (pinid / 32)
-#define STMP3XXX_PINID_TO_PINNUM(pinid) (pinid % 32)
-
-/*
- * Special invalid pin identificator to show a pin doesn't exist
- */
-#define PINID_NO_PIN STMP3XXX_PINID(0xFF, 0xFF)
-
-#endif /* __ASM_PLAT_PINS_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/platform.h b/arch/arm/plat-stmp3xxx/include/mach/platform.h
deleted file mode 100644
index 7007ddaa91eb..000000000000
--- a/arch/arm/plat-stmp3xxx/include/mach/platform.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#ifndef __ASM_PLAT_PLATFORM_H
-#define __ASM_PLAT_PLATFORM_H
-
-#ifndef __ASSEMBLER__
-#include <linux/io.h>
-#endif
-#include <asm/sizes.h>
-
-/* Virtual address where registers are mapped */
-#define STMP3XXX_REGS_PHBASE 0x80000000
-#ifdef __ASSEMBLER__
-#define STMP3XXX_REGS_BASE 0xF0000000
-#else
-#define STMP3XXX_REGS_BASE (void __iomem *)0xF0000000
-#endif
-#define STMP3XXX_REGS_SIZE SZ_1M
-
-/* Virtual address where OCRAM is mapped */
-#define STMP3XXX_OCRAM_PHBASE 0x00000000
-#ifdef __ASSEMBLER__
-#define STMP3XXX_OCRAM_BASE 0xf1000000
-#else
-#define STMP3XXX_OCRAM_BASE (void __iomem *)0xf1000000
-#endif
-#define STMP3XXX_OCRAM_SIZE (32 * SZ_1K)
-
-#ifdef CONFIG_ARCH_STMP37XX
-#define IRQ_PRIORITY_REG_RD HW_ICOLL_PRIORITYn_RD
-#define IRQ_PRIORITY_REG_WR HW_ICOLL_PRIORITYn_WR
-#endif
-
-#ifdef CONFIG_ARCH_STMP378X
-#define IRQ_PRIORITY_REG_RD HW_ICOLL_INTERRUPTn_RD
-#define IRQ_PRIORITY_REG_WR HW_ICOLL_INTERRUPTn_WR
-#endif
-
-#define HW_STMP3XXX_SET 0x04
-#define HW_STMP3XXX_CLR 0x08
-#define HW_STMP3XXX_TOG 0x0c
-
-#ifndef __ASSEMBLER__
-static inline void stmp3xxx_clearl(u32 v, void __iomem *r)
-{
- __raw_writel(v, r + HW_STMP3XXX_CLR);
-}
-
-static inline void stmp3xxx_setl(u32 v, void __iomem *r)
-{
- __raw_writel(v, r + HW_STMP3XXX_SET);
-}
-#endif
-
-#define BF(value, field) (((value) << BP_##field) & BM_##field)
-
-#endif /* __ASM_ARCH_PLATFORM_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/stmp3xxx.h b/arch/arm/plat-stmp3xxx/include/mach/stmp3xxx.h
deleted file mode 100644
index 2e300feaa4cf..000000000000
--- a/arch/arm/plat-stmp3xxx/include/mach/stmp3xxx.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Freescale STMP37XX/STMP378X core structure and function declarations
- *
- * Embedded Alley Solutions, Inc <source@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#ifndef __ASM_PLAT_STMP3XXX_H
-#define __ASM_PLAT_STMP3XXX_H
-
-#include <linux/irq.h>
-
-extern struct sys_timer stmp3xxx_timer;
-
-void stmp3xxx_init_irq(struct irq_chip *chip);
-void stmp3xxx_init(void);
-int stmp3xxx_reset_block(void __iomem *hwreg, int just_enable);
-extern struct platform_device stmp3xxx_dbguart,
- stmp3xxx_appuart,
- stmp3xxx_watchdog,
- stmp3xxx_touchscreen,
- stmp3xxx_keyboard,
- stmp3xxx_gpmi,
- stmp3xxx_mmc,
- stmp3xxx_udc,
- stmp3xxx_ehci,
- stmp3xxx_rtc,
- stmp3xxx_spi1,
- stmp3xxx_spi2,
- stmp3xxx_backlight,
- stmp3xxx_rotdec,
- stmp3xxx_dcp,
- stmp3xxx_dcp_bootstream,
- stmp3xxx_persistent,
- stmp3xxx_framebuffer,
- stmp3xxx_battery;
-int stmp3xxx_ssp1_device_register(void);
-int stmp3xxx_ssp2_device_register(void);
-
-struct pin_group;
-void stmp3xxx_release_pin_group(struct pin_group *pin_group, const char *label);
-int stmp3xxx_request_pin_group(struct pin_group *pin_group, const char *label);
-
-#endif /* __ASM_PLAT_STMP3XXX_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/system.h b/arch/arm/plat-stmp3xxx/include/mach/system.h
deleted file mode 100644
index 28a988889319..000000000000
--- a/arch/arm/plat-stmp3xxx/include/mach/system.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2005 Sigmatel Inc
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#ifndef __ASM_ARCH_SYSTEM_H
-#define __ASM_ARCH_SYSTEM_H
-
-#include <asm/proc-fns.h>
-#include <mach/platform.h>
-#include <mach/regs-clkctrl.h>
-#include <mach/regs-power.h>
-
-static inline void arch_idle(void)
-{
- /*
- * This should do all the clock switching
- * and wait for interrupt tricks
- */
-
- cpu_do_idle();
-}
-
-static inline void arch_reset(char mode, const char *cmd)
-{
- /* Set BATTCHRG to default value */
- __raw_writel(0x00010000, REGS_POWER_BASE + HW_POWER_CHARGE);
-
- /* Set MINPWR to default value */
- __raw_writel(0, REGS_POWER_BASE + HW_POWER_MINPWR);
-
- /* Reset digital side of chip (but not power or RTC) */
- __raw_writel(BM_CLKCTRL_RESET_DIG,
- REGS_CLKCTRL_BASE + HW_CLKCTRL_RESET);
-
- /* Should not return */
-}
-
-#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/timex.h b/arch/arm/plat-stmp3xxx/include/mach/timex.h
deleted file mode 100644
index 3373985d7a8e..000000000000
--- a/arch/arm/plat-stmp3xxx/include/mach/timex.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 1999 ARM Limited
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-
-/*
- * System time clock is sourced from the 32k clock
- */
-#define CLOCK_TICK_RATE (32768)
diff --git a/arch/arm/plat-stmp3xxx/include/mach/uncompress.h b/arch/arm/plat-stmp3xxx/include/mach/uncompress.h
deleted file mode 100644
index f79f5ee56cd4..000000000000
--- a/arch/arm/plat-stmp3xxx/include/mach/uncompress.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#ifndef __ASM_PLAT_UNCOMPRESS_H
-#define __ASM_PLAT_UNCOMPRESS_H
-
-/*
- * Register includes are for when the MMU enabled; we need to define our
- * own stuff here for pre-MMU use
- */
-#define UARTDBG_BASE 0x80070000
-#define UART(c) (((volatile unsigned *)UARTDBG_BASE)[c])
-
-/*
- * This does not append a newline
- */
-static void putc(char c)
-{
- /* Wait for TX fifo empty */
- while ((UART(6) & (1<<7)) == 0)
- continue;
-
- /* Write byte */
- UART(0) = c;
-
- /* Wait for last bit to exit the UART */
- while (UART(6) & (1<<3))
- continue;
-}
-
-static void flush(void)
-{
-}
-
-/*
- * nothing to do
- */
-#define arch_decomp_setup()
-
-#define arch_decomp_wdog()
-
-#endif /* __ASM_PLAT_UNCOMPRESS_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/vmalloc.h b/arch/arm/plat-stmp3xxx/include/mach/vmalloc.h
deleted file mode 100644
index 943c1a29d641..000000000000
--- a/arch/arm/plat-stmp3xxx/include/mach/vmalloc.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- *
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#define VMALLOC_END 0xf0000000UL
diff --git a/arch/arm/plat-stmp3xxx/irq.c b/arch/arm/plat-stmp3xxx/irq.c
deleted file mode 100644
index 6fdf9acf82ed..000000000000
--- a/arch/arm/plat-stmp3xxx/irq.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Freescale STMP37XX/STMP378X common interrupt handling code
- *
- * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/irq.h>
-#include <linux/sysdev.h>
-
-#include <mach/stmp3xxx.h>
-#include <mach/platform.h>
-#include <mach/regs-icoll.h>
-
-void __init stmp3xxx_init_irq(struct irq_chip *chip)
-{
- unsigned int i, lv;
-
- /* Reset the interrupt controller */
- stmp3xxx_reset_block(REGS_ICOLL_BASE + HW_ICOLL_CTRL, true);
-
- /* Disable all interrupts initially */
- for (i = 0; i < NR_REAL_IRQS; i++) {
- chip->irq_mask(irq_get_irq_data(i));
- irq_set_chip_and_handler(i, chip, handle_level_irq);
- set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
- }
-
- /* Ensure vector is cleared */
- for (lv = 0; lv < 4; lv++)
- __raw_writel(1 << lv, REGS_ICOLL_BASE + HW_ICOLL_LEVELACK);
- __raw_writel(0, REGS_ICOLL_BASE + HW_ICOLL_VECTOR);
-
- /* Barrier */
- (void)__raw_readl(REGS_ICOLL_BASE + HW_ICOLL_STAT);
-}
-
diff --git a/arch/arm/plat-stmp3xxx/pinmux.c b/arch/arm/plat-stmp3xxx/pinmux.c
deleted file mode 100644
index 3def03b3217d..000000000000
--- a/arch/arm/plat-stmp3xxx/pinmux.c
+++ /dev/null
@@ -1,550 +0,0 @@
-/*
- * Freescale STMP378X/STMP378X Pin Multiplexing
- *
- * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#define DEBUG
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/sysdev.h>
-#include <linux/string.h>
-#include <linux/bitops.h>
-#include <linux/irq.h>
-
-#include <mach/hardware.h>
-#include <mach/platform.h>
-#include <mach/regs-pinctrl.h>
-#include <mach/pins.h>
-#include <mach/pinmux.h>
-
-#define NR_BANKS ARRAY_SIZE(pinmux_banks)
-static struct stmp3xxx_pinmux_bank pinmux_banks[] = {
- [0] = {
- .hw_muxsel = {
- REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL0,
- REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL1,
- },
- .hw_drive = {
- REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE0,
- REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE1,
- REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE2,
- REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE3,
- },
- .hw_pull = REGS_PINCTRL_BASE + HW_PINCTRL_PULL0,
- .functions = { 0x0, 0x1, 0x2, 0x3 },
- .strengths = { 0x0, 0x1, 0x2, 0x3, 0xff },
-
- .hw_gpio_in = REGS_PINCTRL_BASE + HW_PINCTRL_DIN0,
- .hw_gpio_out = REGS_PINCTRL_BASE + HW_PINCTRL_DOUT0,
- .hw_gpio_doe = REGS_PINCTRL_BASE + HW_PINCTRL_DOE0,
- .irq = IRQ_GPIO0,
-
- .pin2irq = REGS_PINCTRL_BASE + HW_PINCTRL_PIN2IRQ0,
- .irqstat = REGS_PINCTRL_BASE + HW_PINCTRL_IRQSTAT0,
- .irqlevel = REGS_PINCTRL_BASE + HW_PINCTRL_IRQLEVEL0,
- .irqpolarity = REGS_PINCTRL_BASE + HW_PINCTRL_IRQPOL0,
- .irqen = REGS_PINCTRL_BASE + HW_PINCTRL_IRQEN0,
- },
- [1] = {
- .hw_muxsel = {
- REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL2,
- REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL3,
- },
- .hw_drive = {
- REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE4,
- REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE5,
- REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE6,
- REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE7,
- },
- .hw_pull = REGS_PINCTRL_BASE + HW_PINCTRL_PULL1,
- .functions = { 0x0, 0x1, 0x2, 0x3 },
- .strengths = { 0x0, 0x1, 0x2, 0x3, 0xff },
-
- .hw_gpio_in = REGS_PINCTRL_BASE + HW_PINCTRL_DIN1,
- .hw_gpio_out = REGS_PINCTRL_BASE + HW_PINCTRL_DOUT1,
- .hw_gpio_doe = REGS_PINCTRL_BASE + HW_PINCTRL_DOE1,
- .irq = IRQ_GPIO1,
-
- .pin2irq = REGS_PINCTRL_BASE + HW_PINCTRL_PIN2IRQ1,
- .irqstat = REGS_PINCTRL_BASE + HW_PINCTRL_IRQSTAT1,
- .irqlevel = REGS_PINCTRL_BASE + HW_PINCTRL_IRQLEVEL1,
- .irqpolarity = REGS_PINCTRL_BASE + HW_PINCTRL_IRQPOL1,
- .irqen = REGS_PINCTRL_BASE + HW_PINCTRL_IRQEN1,
- },
- [2] = {
- .hw_muxsel = {
- REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL4,
- REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL5,
- },
- .hw_drive = {
- REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE8,
- REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE9,
- REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE10,
- REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE11,
- },
- .hw_pull = REGS_PINCTRL_BASE + HW_PINCTRL_PULL2,
- .functions = { 0x0, 0x1, 0x2, 0x3 },
- .strengths = { 0x0, 0x1, 0x2, 0x1, 0x2 },
-
- .hw_gpio_in = REGS_PINCTRL_BASE + HW_PINCTRL_DIN2,
- .hw_gpio_out = REGS_PINCTRL_BASE + HW_PINCTRL_DOUT2,
- .hw_gpio_doe = REGS_PINCTRL_BASE + HW_PINCTRL_DOE2,
- .irq = IRQ_GPIO2,
-
- .pin2irq = REGS_PINCTRL_BASE + HW_PINCTRL_PIN2IRQ2,
- .irqstat = REGS_PINCTRL_BASE + HW_PINCTRL_IRQSTAT2,
- .irqlevel = REGS_PINCTRL_BASE + HW_PINCTRL_IRQLEVEL2,
- .irqpolarity = REGS_PINCTRL_BASE + HW_PINCTRL_IRQPOL2,
- .irqen = REGS_PINCTRL_BASE + HW_PINCTRL_IRQEN2,
- },
- [3] = {
- .hw_muxsel = {
- REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL6,
- REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL7,
- },
- .hw_drive = {
- REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE12,
- REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE13,
- REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE14,
- NULL,
- },
- .hw_pull = REGS_PINCTRL_BASE + HW_PINCTRL_PULL3,
- .functions = {0x0, 0x1, 0x2, 0x3},
- .strengths = {0x0, 0x1, 0x2, 0x3, 0xff},
- },
-};
-
-static inline struct stmp3xxx_pinmux_bank *
-stmp3xxx_pinmux_bank(unsigned id, unsigned *bank, unsigned *pin)
-{
- unsigned b, p;
-
- b = STMP3XXX_PINID_TO_BANK(id);
- p = STMP3XXX_PINID_TO_PINNUM(id);
- BUG_ON(b >= NR_BANKS);
- if (bank)
- *bank = b;
- if (pin)
- *pin = p;
- return &pinmux_banks[b];
-}
-
-/* Check if requested pin is owned by caller */
-static int stmp3xxx_check_pin(unsigned id, const char *label)
-{
- unsigned pin;
- struct stmp3xxx_pinmux_bank *pm = stmp3xxx_pinmux_bank(id, NULL, &pin);
-
- if (!test_bit(pin, &pm->pin_map)) {
- printk(KERN_WARNING
- "%s: Accessing free pin %x, caller %s\n",
- __func__, id, label);
-
- return -EINVAL;
- }
-
- if (label && pm->pin_labels[pin] &&
- strcmp(label, pm->pin_labels[pin])) {
- printk(KERN_WARNING
- "%s: Wrong pin owner %x, caller %s owner %s\n",
- __func__, id, label, pm->pin_labels[pin]);
-
- return -EINVAL;
- }
- return 0;
-}
-
-void stmp3xxx_pin_strength(unsigned id, enum pin_strength strength,
- const char *label)
-{
- struct stmp3xxx_pinmux_bank *pbank;
- void __iomem *hwdrive;
- u32 shift, val;
- u32 bank, pin;
-
- pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
- pr_debug("%s: label %s bank %d pin %d strength %d\n", __func__, label,
- bank, pin, strength);
-
- hwdrive = pbank->hw_drive[pin / HW_DRIVE_PIN_NUM];
- shift = (pin % HW_DRIVE_PIN_NUM) * HW_DRIVE_PIN_LEN;
- val = pbank->strengths[strength];
- if (val == 0xff) {
- printk(KERN_WARNING
- "%s: strength is not supported for bank %d, caller %s",
- __func__, bank, label);
- return;
- }
-
- if (stmp3xxx_check_pin(id, label))
- return;
-
- pr_debug("%s: writing 0x%x to 0x%p register\n", __func__,
- val << shift, hwdrive);
- stmp3xxx_clearl(HW_DRIVE_PINDRV_MASK << shift, hwdrive);
- stmp3xxx_setl(val << shift, hwdrive);
-}
-
-void stmp3xxx_pin_voltage(unsigned id, enum pin_voltage voltage,
- const char *label)
-{
- struct stmp3xxx_pinmux_bank *pbank;
- void __iomem *hwdrive;
- u32 shift;
- u32 bank, pin;
-
- pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
- pr_debug("%s: label %s bank %d pin %d voltage %d\n", __func__, label,
- bank, pin, voltage);
-
- hwdrive = pbank->hw_drive[pin / HW_DRIVE_PIN_NUM];
- shift = (pin % HW_DRIVE_PIN_NUM) * HW_DRIVE_PIN_LEN;
-
- if (stmp3xxx_check_pin(id, label))
- return;
-
- pr_debug("%s: changing 0x%x bit in 0x%p register\n",
- __func__, HW_DRIVE_PINV_MASK << shift, hwdrive);
- if (voltage == PIN_1_8V)
- stmp3xxx_clearl(HW_DRIVE_PINV_MASK << shift, hwdrive);
- else
- stmp3xxx_setl(HW_DRIVE_PINV_MASK << shift, hwdrive);
-}
-
-void stmp3xxx_pin_pullup(unsigned id, int enable, const char *label)
-{
- struct stmp3xxx_pinmux_bank *pbank;
- void __iomem *hwpull;
- u32 bank, pin;
-
- pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
- pr_debug("%s: label %s bank %d pin %d enable %d\n", __func__, label,
- bank, pin, enable);
-
- hwpull = pbank->hw_pull;
-
- if (stmp3xxx_check_pin(id, label))
- return;
-
- pr_debug("%s: changing 0x%x bit in 0x%p register\n",
- __func__, 1 << pin, hwpull);
- if (enable)
- stmp3xxx_setl(1 << pin, hwpull);
- else
- stmp3xxx_clearl(1 << pin, hwpull);
-}
-
-int stmp3xxx_request_pin(unsigned id, enum pin_fun fun, const char *label)
-{
- struct stmp3xxx_pinmux_bank *pbank;
- u32 bank, pin;
- int ret = 0;
-
- pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
- pr_debug("%s: label %s bank %d pin %d fun %d\n", __func__, label,
- bank, pin, fun);
-
- if (test_bit(pin, &pbank->pin_map)) {
- printk(KERN_WARNING
- "%s: CONFLICT DETECTED pin %d:%d caller %s owner %s\n",
- __func__, bank, pin, label, pbank->pin_labels[pin]);
- return -EBUSY;
- }
-
- set_bit(pin, &pbank->pin_map);
- pbank->pin_labels[pin] = label;
-
- stmp3xxx_set_pin_type(id, fun);
-
- return ret;
-}
-
-void stmp3xxx_set_pin_type(unsigned id, enum pin_fun fun)
-{
- struct stmp3xxx_pinmux_bank *pbank;
- void __iomem *hwmux;
- u32 shift, val;
- u32 bank, pin;
-
- pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
-
- hwmux = pbank->hw_muxsel[pin / HW_MUXSEL_PIN_NUM];
- shift = (pin % HW_MUXSEL_PIN_NUM) * HW_MUXSEL_PIN_LEN;
-
- val = pbank->functions[fun];
- shift = (pin % HW_MUXSEL_PIN_NUM) * HW_MUXSEL_PIN_LEN;
- pr_debug("%s: writing 0x%x to 0x%p register\n",
- __func__, val << shift, hwmux);
- stmp3xxx_clearl(HW_MUXSEL_PINFUN_MASK << shift, hwmux);
- stmp3xxx_setl(val << shift, hwmux);
-}
-
-void stmp3xxx_release_pin(unsigned id, const char *label)
-{
- struct stmp3xxx_pinmux_bank *pbank;
- u32 bank, pin;
-
- pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
- pr_debug("%s: label %s bank %d pin %d\n", __func__, label, bank, pin);
-
- if (stmp3xxx_check_pin(id, label))
- return;
-
- clear_bit(pin, &pbank->pin_map);
- pbank->pin_labels[pin] = NULL;
-}
-
-int stmp3xxx_request_pin_group(struct pin_group *pin_group, const char *label)
-{
- struct pin_desc *pin;
- int p;
- int err = 0;
-
- /* Allocate and configure pins */
- for (p = 0; p < pin_group->nr_pins; p++) {
- pr_debug("%s: #%d\n", __func__, p);
- pin = &pin_group->pins[p];
-
- err = stmp3xxx_request_pin(pin->id, pin->fun, label);
- if (err)
- goto out_err;
-
- stmp3xxx_pin_strength(pin->id, pin->strength, label);
- stmp3xxx_pin_voltage(pin->id, pin->voltage, label);
- stmp3xxx_pin_pullup(pin->id, pin->pullup, label);
- }
-
- return 0;
-
-out_err:
- /* Release allocated pins in case of error */
- while (--p >= 0) {
- pr_debug("%s: releasing #%d\n", __func__, p);
- stmp3xxx_release_pin(pin_group->pins[p].id, label);
- }
- return err;
-}
-EXPORT_SYMBOL(stmp3xxx_request_pin_group);
-
-void stmp3xxx_release_pin_group(struct pin_group *pin_group, const char *label)
-{
- struct pin_desc *pin;
- int p;
-
- for (p = 0; p < pin_group->nr_pins; p++) {
- pin = &pin_group->pins[p];
- stmp3xxx_release_pin(pin->id, label);
- }
-}
-EXPORT_SYMBOL(stmp3xxx_release_pin_group);
-
-static int stmp3xxx_irq_data_to_gpio(struct irq_data *d,
- struct stmp3xxx_pinmux_bank **bank, unsigned *gpio)
-{
- struct stmp3xxx_pinmux_bank *pm;
-
- for (pm = pinmux_banks; pm < pinmux_banks + NR_BANKS; pm++)
- if (pm->virq <= d->irq && d->irq < pm->virq + 32) {
- *bank = pm;
- *gpio = d->irq - pm->virq;
- return 0;
- }
- return -ENOENT;
-}
-
-static int stmp3xxx_set_irqtype(struct irq_data *d, unsigned type)
-{
- struct stmp3xxx_pinmux_bank *pm;
- unsigned gpio;
- int l, p;
-
- stmp3xxx_irq_data_to_gpio(d, &pm, &gpio);
- switch (type) {
- case IRQ_TYPE_EDGE_RISING:
- l = 0; p = 1; break;
- case IRQ_TYPE_EDGE_FALLING:
- l = 0; p = 0; break;
- case IRQ_TYPE_LEVEL_HIGH:
- l = 1; p = 1; break;
- case IRQ_TYPE_LEVEL_LOW:
- l = 1; p = 0; break;
- default:
- pr_debug("%s: Incorrect GPIO interrupt type 0x%x\n",
- __func__, type);
- return -ENXIO;
- }
-
- if (l)
- stmp3xxx_setl(1 << gpio, pm->irqlevel);
- else
- stmp3xxx_clearl(1 << gpio, pm->irqlevel);
- if (p)
- stmp3xxx_setl(1 << gpio, pm->irqpolarity);
- else
- stmp3xxx_clearl(1 << gpio, pm->irqpolarity);
- return 0;
-}
-
-static void stmp3xxx_pin_ack_irq(struct irq_data *d)
-{
- u32 stat;
- struct stmp3xxx_pinmux_bank *pm;
- unsigned gpio;
-
- stmp3xxx_irq_data_to_gpio(d, &pm, &gpio);
- stat = __raw_readl(pm->irqstat) & (1 << gpio);
- stmp3xxx_clearl(stat, pm->irqstat);
-}
-
-static void stmp3xxx_pin_mask_irq(struct irq_data *d)
-{
- struct stmp3xxx_pinmux_bank *pm;
- unsigned gpio;
-
- stmp3xxx_irq_data_to_gpio(d, &pm, &gpio);
- stmp3xxx_clearl(1 << gpio, pm->irqen);
- stmp3xxx_clearl(1 << gpio, pm->pin2irq);
-}
-
-static void stmp3xxx_pin_unmask_irq(struct irq_data *d)
-{
- struct stmp3xxx_pinmux_bank *pm;
- unsigned gpio;
-
- stmp3xxx_irq_data_to_gpio(d, &pm, &gpio);
- stmp3xxx_setl(1 << gpio, pm->irqen);
- stmp3xxx_setl(1 << gpio, pm->pin2irq);
-}
-
-static inline
-struct stmp3xxx_pinmux_bank *to_pinmux_bank(struct gpio_chip *chip)
-{
- return container_of(chip, struct stmp3xxx_pinmux_bank, chip);
-}
-
-static int stmp3xxx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
- return pm->virq + offset;
-}
-
-static int stmp3xxx_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
- struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
- unsigned v;
-
- v = __raw_readl(pm->hw_gpio_in) & (1 << offset);
- return v ? 1 : 0;
-}
-
-static void stmp3xxx_gpio_set(struct gpio_chip *chip, unsigned offset, int v)
-{
- struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
-
- if (v)
- stmp3xxx_setl(1 << offset, pm->hw_gpio_out);
- else
- stmp3xxx_clearl(1 << offset, pm->hw_gpio_out);
-}
-
-static int stmp3xxx_gpio_output(struct gpio_chip *chip, unsigned offset, int v)
-{
- struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
-
- stmp3xxx_setl(1 << offset, pm->hw_gpio_doe);
- stmp3xxx_gpio_set(chip, offset, v);
- return 0;
-}
-
-static int stmp3xxx_gpio_input(struct gpio_chip *chip, unsigned offset)
-{
- struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
-
- stmp3xxx_clearl(1 << offset, pm->hw_gpio_doe);
- return 0;
-}
-
-static int stmp3xxx_gpio_request(struct gpio_chip *chip, unsigned offset)
-{
- return stmp3xxx_request_pin(chip->base + offset, PIN_GPIO, "gpio");
-}
-
-static void stmp3xxx_gpio_free(struct gpio_chip *chip, unsigned offset)
-{
- stmp3xxx_release_pin(chip->base + offset, "gpio");
-}
-
-static void stmp3xxx_gpio_irq(u32 irq, struct irq_desc *desc)
-{
- struct stmp3xxx_pinmux_bank *pm = irq_get_handler_data(irq);
- int gpio_irq = pm->virq;
- u32 stat = __raw_readl(pm->irqstat);
-
- while (stat) {
- if (stat & 1)
- generic_handle_irq(gpio_irq);
- gpio_irq++;
- stat >>= 1;
- }
-}
-
-static struct irq_chip gpio_irq_chip = {
- .irq_ack = stmp3xxx_pin_ack_irq,
- .irq_mask = stmp3xxx_pin_mask_irq,
- .irq_unmask = stmp3xxx_pin_unmask_irq,
- .irq_set_type = stmp3xxx_set_irqtype,
-};
-
-int __init stmp3xxx_pinmux_init(int virtual_irq_start)
-{
- int b, r = 0;
- struct stmp3xxx_pinmux_bank *pm;
- int virq;
-
- for (b = 0; b < 3; b++) {
- /* only banks 0,1,2 are allowed to GPIO */
- pm = pinmux_banks + b;
- pm->chip.base = 32 * b;
- pm->chip.ngpio = 32;
- pm->chip.owner = THIS_MODULE;
- pm->chip.can_sleep = 1;
- pm->chip.exported = 1;
- pm->chip.to_irq = stmp3xxx_gpio_to_irq;
- pm->chip.direction_input = stmp3xxx_gpio_input;
- pm->chip.direction_output = stmp3xxx_gpio_output;
- pm->chip.get = stmp3xxx_gpio_get;
- pm->chip.set = stmp3xxx_gpio_set;
- pm->chip.request = stmp3xxx_gpio_request;
- pm->chip.free = stmp3xxx_gpio_free;
- pm->virq = virtual_irq_start + b * 32;
-
- for (virq = pm->virq; virq < pm->virq; virq++) {
- gpio_irq_chip.irq_mask(irq_get_irq_data(virq));
- irq_set_chip_and_handler(virq, &gpio_irq_chip,
- handle_level_irq);
- set_irq_flags(virq, IRQF_VALID);
- }
- r = gpiochip_add(&pm->chip);
- if (r < 0)
- break;
- irq_set_chained_handler(pm->irq, stmp3xxx_gpio_irq);
- irq_set_handler_data(pm->irq, pm);
- }
- return r;
-}
-
-MODULE_AUTHOR("Vladislav Buzov");
-MODULE_LICENSE("GPL");
diff --git a/arch/arm/plat-stmp3xxx/timer.c b/arch/arm/plat-stmp3xxx/timer.c
deleted file mode 100644
index c395630a6edc..000000000000
--- a/arch/arm/plat-stmp3xxx/timer.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * System timer for Freescale STMP37XX/STMP378X
- *
- * Embedded Alley Solutions, Inc <source@embeddedalley.com>
- *
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
- */
-
-/*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
- *
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/clocksource.h>
-#include <linux/clockchips.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-
-#include <asm/mach/time.h>
-#include <mach/stmp3xxx.h>
-#include <mach/platform.h>
-#include <mach/regs-timrot.h>
-
-static irqreturn_t
-stmp3xxx_timer_interrupt(int irq, void *dev_id)
-{
- struct clock_event_device *c = dev_id;
-
- /* timer 0 */
- if (__raw_readl(REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0) &
- BM_TIMROT_TIMCTRLn_IRQ) {
- stmp3xxx_clearl(BM_TIMROT_TIMCTRLn_IRQ,
- REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0);
- c->event_handler(c);
- }
-
- /* timer 1 */
- else if (__raw_readl(REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1)
- & BM_TIMROT_TIMCTRLn_IRQ) {
- stmp3xxx_clearl(BM_TIMROT_TIMCTRLn_IRQ,
- REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1);
- stmp3xxx_clearl(BM_TIMROT_TIMCTRLn_IRQ_EN,
- REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1);
- __raw_writel(0xFFFF, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1);
- }
-
- return IRQ_HANDLED;
-}
-
-static cycle_t stmp3xxx_clock_read(struct clocksource *cs)
-{
- return ~((__raw_readl(REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1)
- & 0xFFFF0000) >> 16);
-}
-
-static int
-stmp3xxx_timrot_set_next_event(unsigned long delta,
- struct clock_event_device *dev)
-{
- /* reload the timer */
- __raw_writel(delta, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0);
- return 0;
-}
-
-static void
-stmp3xxx_timrot_set_mode(enum clock_event_mode mode,
- struct clock_event_device *dev)
-{
-}
-
-static struct clock_event_device ckevt_timrot = {
- .name = "timrot",
- .features = CLOCK_EVT_FEAT_ONESHOT,
- .shift = 32,
- .set_next_event = stmp3xxx_timrot_set_next_event,
- .set_mode = stmp3xxx_timrot_set_mode,
-};
-
-static struct clocksource cksrc_stmp3xxx = {
- .name = "cksrc_stmp3xxx",
- .rating = 250,
- .read = stmp3xxx_clock_read,
- .mask = CLOCKSOURCE_MASK(16),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
-static struct irqaction stmp3xxx_timer_irq = {
- .name = "stmp3xxx_timer",
- .flags = IRQF_DISABLED | IRQF_TIMER,
- .handler = stmp3xxx_timer_interrupt,
- .dev_id = &ckevt_timrot,
-};
-
-
-/*
- * Set up timer interrupt, and return the current time in seconds.
- */
-static void __init stmp3xxx_init_timer(void)
-{
- ckevt_timrot.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC,
- ckevt_timrot.shift);
- ckevt_timrot.min_delta_ns = clockevent_delta2ns(2, &ckevt_timrot);
- ckevt_timrot.max_delta_ns = clockevent_delta2ns(0xFFF, &ckevt_timrot);
- ckevt_timrot.cpumask = cpumask_of(0);
-
- stmp3xxx_reset_block(REGS_TIMROT_BASE, false);
-
- /* clear two timers */
- __raw_writel(0, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0);
- __raw_writel(0, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1);
-
- /* configure them */
- __raw_writel(
- (8 << BP_TIMROT_TIMCTRLn_SELECT) | /* 32 kHz */
- BM_TIMROT_TIMCTRLn_RELOAD |
- BM_TIMROT_TIMCTRLn_UPDATE |
- BM_TIMROT_TIMCTRLn_IRQ_EN,
- REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0);
- __raw_writel(
- (8 << BP_TIMROT_TIMCTRLn_SELECT) | /* 32 kHz */
- BM_TIMROT_TIMCTRLn_RELOAD |
- BM_TIMROT_TIMCTRLn_UPDATE |
- BM_TIMROT_TIMCTRLn_IRQ_EN,
- REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1);
-
- __raw_writel(CLOCK_TICK_RATE / HZ - 1,
- REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0);
- __raw_writel(0xFFFF, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1);
-
- setup_irq(IRQ_TIMER0, &stmp3xxx_timer_irq);
-
- clocksource_register_hz(&cksrc_stmp3xxx, CLOCK_TICK_RATE);
- clockevents_register_device(&ckevt_timrot);
-}
-
-#ifdef CONFIG_PM
-
-void stmp3xxx_suspend_timer(void)
-{
- stmp3xxx_clearl(BM_TIMROT_TIMCTRLn_IRQ_EN | BM_TIMROT_TIMCTRLn_IRQ,
- REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0);
- stmp3xxx_setl(BM_TIMROT_ROTCTRL_CLKGATE,
- REGS_TIMROT_BASE + HW_TIMROT_ROTCTRL);
-}
-
-void stmp3xxx_resume_timer(void)
-{
- stmp3xxx_clearl(BM_TIMROT_ROTCTRL_SFTRST | BM_TIMROT_ROTCTRL_CLKGATE,
- REGS_TIMROT_BASE + HW_TIMROT_ROTCTRL);
- __raw_writel(
- 8 << BP_TIMROT_TIMCTRLn_SELECT | /* 32 kHz */
- BM_TIMROT_TIMCTRLn_RELOAD |
- BM_TIMROT_TIMCTRLn_UPDATE |
- BM_TIMROT_TIMCTRLn_IRQ_EN,
- REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0);
- __raw_writel(
- 8 << BP_TIMROT_TIMCTRLn_SELECT | /* 32 kHz */
- BM_TIMROT_TIMCTRLn_RELOAD |
- BM_TIMROT_TIMCTRLn_UPDATE |
- BM_TIMROT_TIMCTRLn_IRQ_EN,
- REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1);
- __raw_writel(CLOCK_TICK_RATE / HZ - 1,
- REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0);
- __raw_writel(0xFFFF, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1);
-}
-
-#else
-
-#define stmp3xxx_suspend_timer NULL
-#define stmp3xxx_resume_timer NULL
-
-#endif /* CONFIG_PM */
-
-struct sys_timer stmp3xxx_timer = {
- .init = stmp3xxx_init_timer,
- .suspend = stmp3xxx_suspend_timer,
- .resume = stmp3xxx_resume_timer,
-};
diff --git a/arch/arm/plat-versatile/platsmp.c b/arch/arm/plat-versatile/platsmp.c
index ba3d471d4bcf..51ecfea09b27 100644
--- a/arch/arm/plat-versatile/platsmp.c
+++ b/arch/arm/plat-versatile/platsmp.c
@@ -16,6 +16,7 @@
#include <linux/smp.h>
#include <asm/cacheflush.h>
+#include <asm/hardware/gic.h>
/*
* control for which core is the next to come out of the secondary
@@ -83,7 +84,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
* the boot monitor to read the system wide flags register,
* and branch to the address found there.
*/
- smp_cross_call(cpumask_of(cpu), 1);
+ gic_raise_softirq(cpumask_of(cpu), 1);
timeout = jiffies + (1 * HZ);
while (time_before(jiffies, timeout)) {
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index 7ca41f0a09b1..3b3776d0a1a7 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -17,7 +17,7 @@
# XXX: the last 12 months. If your entry is missing please email rmk at
# XXX: <linux@arm.linux.org.uk>
#
-# Last update: Sun Mar 20 18:06:11 2011
+# Last update: Sat May 7 08:48:24 2011
#
# machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number
#
@@ -377,6 +377,8 @@ davinci_da850_evm MACH_DAVINCI_DA850_EVM DAVINCI_DA850_EVM 2157
at91sam9g10ek MACH_AT91SAM9G10EK AT91SAM9G10EK 2159
omap_4430sdp MACH_OMAP_4430SDP OMAP_4430SDP 2160
magx_zn5 MACH_MAGX_ZN5 MAGX_ZN5 2162
+btmavb101 MACH_BTMAVB101 BTMAVB101 2172
+btmawb101 MACH_BTMAWB101 BTMAWB101 2173
omap3_torpedo MACH_OMAP3_TORPEDO OMAP3_TORPEDO 2178
anw6410 MACH_ANW6410 ANW6410 2183
imx27_visstrim_m10 MACH_IMX27_VISSTRIM_M10 IMX27_VISSTRIM_M10 2187
@@ -400,6 +402,7 @@ d2net MACH_D2NET D2NET 2282
bigdisk MACH_BIGDISK BIGDISK 2283
at91sam9g20ek_2mmc MACH_AT91SAM9G20EK_2MMC AT91SAM9G20EK_2MMC 2288
bcmring MACH_BCMRING BCMRING 2289
+dp6xx MACH_DP6XX DP6XX 2302
mahimahi MACH_MAHIMAHI MAHIMAHI 2304
smdk6442 MACH_SMDK6442 SMDK6442 2324
openrd_base MACH_OPENRD_BASE OPENRD_BASE 2325
@@ -424,6 +427,7 @@ smdkv210 MACH_SMDKV210 SMDKV210 2456
omap_zoom3 MACH_OMAP_ZOOM3 OMAP_ZOOM3 2464
omap_3630sdp MACH_OMAP_3630SDP OMAP_3630SDP 2465
smartq7 MACH_SMARTQ7 SMARTQ7 2479
+watson_efm_plugin MACH_WATSON_EFM_PLUGIN WATSON_EFM_PLUGIN 2491
g4evm MACH_G4EVM G4EVM 2493
omapl138_hawkboard MACH_OMAPL138_HAWKBOARD OMAPL138_HAWKBOARD 2495
ts41x MACH_TS41X TS41X 2502
@@ -433,6 +437,8 @@ mx28evk MACH_MX28EVK MX28EVK 2531
smartq5 MACH_SMARTQ5 SMARTQ5 2534
davinci_dm6467tevm MACH_DAVINCI_DM6467TEVM DAVINCI_DM6467TEVM 2548
mxt_td60 MACH_MXT_TD60 MXT_TD60 2550
+riot_bei2 MACH_RIOT_BEI2 RIOT_BEI2 2576
+riot_x37 MACH_RIOT_X37 RIOT_X37 2578
capc7117 MACH_CAPC7117 CAPC7117 2612
icontrol MACH_ICONTROL ICONTROL 2624
qsd8x50a_st1_5 MACH_QSD8X50A_ST1_5 QSD8X50A_ST1_5 2627
@@ -445,6 +451,7 @@ spear320 MACH_SPEAR320 SPEAR320 2661
aquila MACH_AQUILA AQUILA 2676
sheeva_esata MACH_ESATA_SHEEVAPLUG ESATA_SHEEVAPLUG 2678
msm7x30_surf MACH_MSM7X30_SURF MSM7X30_SURF 2679
+ea2478devkit MACH_EA2478DEVKIT EA2478DEVKIT 2683
terastation_wxl MACH_TERASTATION_WXL TERASTATION_WXL 2697
msm7x25_surf MACH_MSM7X25_SURF MSM7X25_SURF 2703
msm7x25_ffa MACH_MSM7X25_FFA MSM7X25_FFA 2704
@@ -463,75 +470,16 @@ wbd222 MACH_WBD222 WBD222 2753
msm8x60_surf MACH_MSM8X60_SURF MSM8X60_SURF 2755
msm8x60_sim MACH_MSM8X60_SIM MSM8X60_SIM 2756
tcc8000_sdk MACH_TCC8000_SDK TCC8000_SDK 2758
-ap420 MACH_AP420 AP420 2765
-davinci_dm365_fc MACH_DAVINCI_DM365_FC DAVINCI_DM365_FC 2767
-msm8x55_surf MACH_MSM8X55_SURF MSM8X55_SURF 2768
-msm8x55_ffa MACH_MSM8X55_FFA MSM8X55_FFA 2769
-esl_vamana MACH_ESL_VAMANA ESL_VAMANA 2770
-sbc35 MACH_SBC35 SBC35 2771
-mpx6446 MACH_MPX6446 MPX6446 2772
-oreo_controller MACH_OREO_CONTROLLER OREO_CONTROLLER 2773
-kopin_models MACH_KOPIN_MODELS KOPIN_MODELS 2774
-ttc_vision2 MACH_TTC_VISION2 TTC_VISION2 2775
+nanos MACH_NANOS NANOS 2759
+stamp9g45 MACH_STAMP9G45 STAMP9G45 2761
cns3420vb MACH_CNS3420VB CNS3420VB 2776
-olympus MACH_OLYMPUS OLYMPUS 2778
-vortex MACH_VORTEX VORTEX 2779
-s5pc200 MACH_S5PC200 S5PC200 2780
-ecucore_9263 MACH_ECUCORE_9263 ECUCORE_9263 2781
-smdkc200 MACH_SMDKC200 SMDKC200 2782
-emsiso_sx27 MACH_EMSISO_SX27 EMSISO_SX27 2783
-apx_som9g45_ek MACH_APX_SOM9G45_EK APX_SOM9G45_EK 2784
-songshan MACH_SONGSHAN SONGSHAN 2785
-tianshan MACH_TIANSHAN TIANSHAN 2786
-vpx500 MACH_VPX500 VPX500 2787
-am3517sam MACH_AM3517SAM AM3517SAM 2788
-skat91_sim508 MACH_SKAT91_SIM508 SKAT91_SIM508 2789
-skat91_s3e MACH_SKAT91_S3E SKAT91_S3E 2790
omap4_panda MACH_OMAP4_PANDA OMAP4_PANDA 2791
-df7220 MACH_DF7220 DF7220 2792
-nemini MACH_NEMINI NEMINI 2793
-t8200 MACH_T8200 T8200 2794
-apf51 MACH_APF51 APF51 2795
-dr_rc_unit MACH_DR_RC_UNIT DR_RC_UNIT 2796
-bordeaux MACH_BORDEAUX BORDEAUX 2797
-catania_b MACH_CATANIA_B CATANIA_B 2798
-mx51_ocean MACH_MX51_OCEAN MX51_OCEAN 2799
ti8168evm MACH_TI8168EVM TI8168EVM 2800
-neocoreomap MACH_NEOCOREOMAP NEOCOREOMAP 2801
-withings_wbp MACH_WITHINGS_WBP WITHINGS_WBP 2802
-dbps MACH_DBPS DBPS 2803
-pcbfp0001 MACH_PCBFP0001 PCBFP0001 2805
-speedy MACH_SPEEDY SPEEDY 2806
-chrysaor MACH_CHRYSAOR CHRYSAOR 2807
-tango MACH_TANGO TANGO 2808
-synology_dsx11 MACH_SYNOLOGY_DSX11 SYNOLOGY_DSX11 2809
-hanlin_v3ext MACH_HANLIN_V3EXT HANLIN_V3EXT 2810
-hanlin_v5 MACH_HANLIN_V5 HANLIN_V5 2811
-hanlin_v3plus MACH_HANLIN_V3PLUS HANLIN_V3PLUS 2812
-iriver_story MACH_IRIVER_STORY IRIVER_STORY 2813
-irex_iliad MACH_IREX_ILIAD IREX_ILIAD 2814
-irex_dr1000 MACH_IREX_DR1000 IREX_DR1000 2815
teton_bga MACH_TETON_BGA TETON_BGA 2816
-snapper9g45 MACH_SNAPPER9G45 SNAPPER9G45 2817
-tam3517 MACH_TAM3517 TAM3517 2818
-pdc100 MACH_PDC100 PDC100 2819
eukrea_cpuimx25sd MACH_EUKREA_CPUIMX25 EUKREA_CPUIMX25 2820
eukrea_cpuimx35sd MACH_EUKREA_CPUIMX35 EUKREA_CPUIMX35 2821
eukrea_cpuimx51sd MACH_EUKREA_CPUIMX51SD EUKREA_CPUIMX51SD 2822
eukrea_cpuimx51 MACH_EUKREA_CPUIMX51 EUKREA_CPUIMX51 2823
-p565 MACH_P565 P565 2824
-acer_a4 MACH_ACER_A4 ACER_A4 2825
-davinci_dm368_bip MACH_DAVINCI_DM368_BIP DAVINCI_DM368_BIP 2826
-eshare MACH_ESHARE ESHARE 2827
-wlbargn MACH_WLBARGN WLBARGN 2829
-bm170 MACH_BM170 BM170 2830
-netspace_mini_v2 MACH_NETSPACE_MINI_V2 NETSPACE_MINI_V2 2831
-netspace_plug_v2 MACH_NETSPACE_PLUG_V2 NETSPACE_PLUG_V2 2832
-siemens_l1 MACH_SIEMENS_L1 SIEMENS_L1 2833
-elv_lcu1 MACH_ELV_LCU1 ELV_LCU1 2834
-mcu1 MACH_MCU1 MCU1 2835
-omap3_tao3530 MACH_OMAP3_TAO3530 OMAP3_TAO3530 2836
-omap3_pcutouch MACH_OMAP3_PCUTOUCH OMAP3_PCUTOUCH 2837
smdkc210 MACH_SMDKC210 SMDKC210 2838
omap3_braillo MACH_OMAP3_BRAILLO OMAP3_BRAILLO 2839
spyplug MACH_SPYPLUG SPYPLUG 2840
@@ -973,9 +921,7 @@ isc3 MACH_ISC3 ISC3 3291
rascal MACH_RASCAL RASCAL 3292
hrefv60 MACH_HREFV60 HREFV60 3293
tpt_2_0 MACH_TPT_2_0 TPT_2_0 3294
-pyramid_td MACH_PYRAMID_TD PYRAMID_TD 3295
splendor MACH_SPLENDOR SPLENDOR 3296
-guf_planet MACH_GUF_PLANET GUF_PLANET 3297
msm8x60_qt MACH_MSM8X60_QT MSM8X60_QT 3298
htc_hd_mini MACH_HTC_HD_MINI HTC_HD_MINI 3299
athene MACH_ATHENE ATHENE 3300
@@ -1099,3 +1045,71 @@ ecuv5 MACH_ECUV5 ECUV5 3421
hsgx6d MACH_HSGX6D HSGX6D 3422
dawad7 MACH_DAWAD7 DAWAD7 3423
sam9repeater MACH_SAM9REPEATER SAM9REPEATER 3424
+gt_i5700 MACH_GT_I5700 GT_I5700 3425
+ctera_plug_c2 MACH_CTERA_PLUG_C2 CTERA_PLUG_C2 3426
+marvelct MACH_MARVELCT MARVELCT 3427
+ag11005 MACH_AG11005 AG11005 3428
+vangogh MACH_VANGOGH VANGOGH 3430
+matrix505 MACH_MATRIX505 MATRIX505 3431
+oce_nigma MACH_OCE_NIGMA OCE_NIGMA 3432
+t55 MACH_T55 T55 3433
+bio3k MACH_BIO3K BIO3K 3434
+expressct MACH_EXPRESSCT EXPRESSCT 3435
+cardhu MACH_CARDHU CARDHU 3436
+aruba MACH_ARUBA ARUBA 3437
+bonaire MACH_BONAIRE BONAIRE 3438
+nuc700evb MACH_NUC700EVB NUC700EVB 3439
+nuc710evb MACH_NUC710EVB NUC710EVB 3440
+nuc740evb MACH_NUC740EVB NUC740EVB 3441
+nuc745evb MACH_NUC745EVB NUC745EVB 3442
+transcede MACH_TRANSCEDE TRANSCEDE 3443
+mora MACH_MORA MORA 3444
+nda_evm MACH_NDA_EVM NDA_EVM 3445
+timu MACH_TIMU TIMU 3446
+expressh MACH_EXPRESSH EXPRESSH 3447
+veridis_a300 MACH_VERIDIS_A300 VERIDIS_A300 3448
+dm368_leopard MACH_DM368_LEOPARD DM368_LEOPARD 3449
+omap_mcop MACH_OMAP_MCOP OMAP_MCOP 3450
+tritip MACH_TRITIP TRITIP 3451
+sm1k MACH_SM1K SM1K 3452
+monch MACH_MONCH MONCH 3453
+curacao MACH_CURACAO CURACAO 3454
+origen MACH_ORIGEN ORIGEN 3455
+epc10 MACH_EPC10 EPC10 3456
+sgh_i740 MACH_SGH_I740 SGH_I740 3457
+tuna MACH_TUNA TUNA 3458
+mx51_tulip MACH_MX51_TULIP MX51_TULIP 3459
+mx51_aster7 MACH_MX51_ASTER7 MX51_ASTER7 3460
+acro37xbrd MACH_ACRO37XBRD ACRO37XBRD 3461
+elke MACH_ELKE ELKE 3462
+sbc6000x MACH_SBC6000X SBC6000X 3463
+r1801e MACH_R1801E R1801E 3464
+h1600 MACH_H1600 H1600 3465
+mini210 MACH_MINI210 MINI210 3466
+mini8168 MACH_MINI8168 MINI8168 3467
+pc7308 MACH_PC7308 PC7308 3468
+kmm2m01 MACH_KMM2M01 KMM2M01 3470
+mx51erebus MACH_MX51EREBUS MX51EREBUS 3471
+wm8650refboard MACH_WM8650REFBOARD WM8650REFBOARD 3472
+tuxrail MACH_TUXRAIL TUXRAIL 3473
+arthur MACH_ARTHUR ARTHUR 3474
+doorboy MACH_DOORBOY DOORBOY 3475
+xarina MACH_XARINA XARINA 3476
+roverx7 MACH_ROVERX7 ROVERX7 3477
+sdvr MACH_SDVR SDVR 3478
+acer_maya MACH_ACER_MAYA ACER_MAYA 3479
+pico MACH_PICO PICO 3480
+cwmx233 MACH_CWMX233 CWMX233 3481
+cwam1808 MACH_CWAM1808 CWAM1808 3482
+cwdm365 MACH_CWDM365 CWDM365 3483
+mx51_moray MACH_MX51_MORAY MX51_MORAY 3484
+thales_cbc MACH_THALES_CBC THALES_CBC 3485
+bluepoint MACH_BLUEPOINT BLUEPOINT 3486
+dir665 MACH_DIR665 DIR665 3487
+acmerover1 MACH_ACMEROVER1 ACMEROVER1 3488
+shooter_ct MACH_SHOOTER_CT SHOOTER_CT 3489
+bliss MACH_BLISS BLISS 3490
+blissc MACH_BLISSC BLISSC 3491
+thales_adc MACH_THALES_ADC THALES_ADC 3492
+ubisys_p9d_evp MACH_UBISYS_P9D_EVP UBISYS_P9D_EVP 3493
+atdgp318 MACH_ATDGP318 ATDGP318 3494
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index f74695075e64..f25e7ec89416 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -398,9 +398,9 @@ static void vfp_enable(void *unused)
}
#ifdef CONFIG_PM
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
-static int vfp_pm_suspend(struct sys_device *dev, pm_message_t state)
+static int vfp_pm_suspend(void)
{
struct thread_info *ti = current_thread_info();
u32 fpexc = fmrx(FPEXC);
@@ -420,34 +420,25 @@ static int vfp_pm_suspend(struct sys_device *dev, pm_message_t state)
return 0;
}
-static int vfp_pm_resume(struct sys_device *dev)
+static void vfp_pm_resume(void)
{
/* ensure we have access to the vfp */
vfp_enable(NULL);
/* and disable it to ensure the next usage restores the state */
fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
-
- return 0;
}
-static struct sysdev_class vfp_pm_sysclass = {
- .name = "vfp",
+static struct syscore_ops vfp_pm_syscore_ops = {
.suspend = vfp_pm_suspend,
.resume = vfp_pm_resume,
};
-static struct sys_device vfp_pm_sysdev = {
- .cls = &vfp_pm_sysclass,
-};
-
static void vfp_pm_init(void)
{
- sysdev_class_register(&vfp_pm_sysclass);
- sysdev_register(&vfp_pm_sysdev);
+ register_syscore_ops(&vfp_pm_syscore_ops);
}
-
#else
static inline void vfp_pm_init(void) { }
#endif /* CONFIG_PM */
diff --git a/arch/avr32/include/asm/bitops.h b/arch/avr32/include/asm/bitops.h
index 72444d97f80c..b70c19bab63a 100644
--- a/arch/avr32/include/asm/bitops.h
+++ b/arch/avr32/include/asm/bitops.h
@@ -270,14 +270,21 @@ static inline int __fls(unsigned long word)
unsigned long find_first_zero_bit(const unsigned long *addr,
unsigned long size);
+#define find_first_zero_bit find_first_zero_bit
+
unsigned long find_next_zero_bit(const unsigned long *addr,
unsigned long size,
unsigned long offset);
+#define find_next_zero_bit find_next_zero_bit
+
unsigned long find_first_bit(const unsigned long *addr,
unsigned long size);
+#define find_first_bit find_first_bit
+
unsigned long find_next_bit(const unsigned long *addr,
unsigned long size,
unsigned long offset);
+#define find_next_bit find_next_bit
/*
* ffs: find first bit set. This is defined the same way as
@@ -299,6 +306,14 @@ static inline int ffs(unsigned long word)
#include <asm-generic/bitops/hweight.h>
#include <asm-generic/bitops/lock.h>
+extern unsigned long find_next_zero_bit_le(const void *addr,
+ unsigned long size, unsigned long offset);
+#define find_next_zero_bit_le find_next_zero_bit_le
+
+extern unsigned long find_next_bit_le(const void *addr,
+ unsigned long size, unsigned long offset);
+#define find_next_bit_le find_next_bit_le
+
#include <asm-generic/bitops/le.h>
#include <asm-generic/bitops/ext2-atomic.h>
diff --git a/arch/avr32/mach-at32ap/intc.c b/arch/avr32/mach-at32ap/intc.c
index 21ce35f33aa5..3e3646186c9f 100644
--- a/arch/avr32/mach-at32ap/intc.c
+++ b/arch/avr32/mach-at32ap/intc.c
@@ -12,7 +12,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <asm/io.h>
@@ -21,7 +21,6 @@
struct intc {
void __iomem *regs;
struct irq_chip chip;
- struct sys_device sysdev;
#ifdef CONFIG_PM
unsigned long suspend_ipr;
unsigned long saved_ipr[64];
@@ -146,9 +145,8 @@ void intc_set_suspend_handler(unsigned long offset)
intc0.suspend_ipr = offset;
}
-static int intc_suspend(struct sys_device *sdev, pm_message_t state)
+static int intc_suspend(void)
{
- struct intc *intc = container_of(sdev, struct intc, sysdev);
int i;
if (unlikely(!irqs_disabled())) {
@@ -156,28 +154,25 @@ static int intc_suspend(struct sys_device *sdev, pm_message_t state)
return -EINVAL;
}
- if (unlikely(!intc->suspend_ipr)) {
+ if (unlikely(!intc0.suspend_ipr)) {
pr_err("intc_suspend: suspend_ipr not initialized\n");
return -EINVAL;
}
for (i = 0; i < 64; i++) {
- intc->saved_ipr[i] = intc_readl(intc, INTPR0 + 4 * i);
- intc_writel(intc, INTPR0 + 4 * i, intc->suspend_ipr);
+ intc0.saved_ipr[i] = intc_readl(&intc0, INTPR0 + 4 * i);
+ intc_writel(&intc0, INTPR0 + 4 * i, intc0.suspend_ipr);
}
return 0;
}
-static int intc_resume(struct sys_device *sdev)
+static int intc_resume(void)
{
- struct intc *intc = container_of(sdev, struct intc, sysdev);
int i;
- WARN_ON(!irqs_disabled());
-
for (i = 0; i < 64; i++)
- intc_writel(intc, INTPR0 + 4 * i, intc->saved_ipr[i]);
+ intc_writel(&intc0, INTPR0 + 4 * i, intc0.saved_ipr[i]);
return 0;
}
@@ -186,27 +181,18 @@ static int intc_resume(struct sys_device *sdev)
#define intc_resume NULL
#endif
-static struct sysdev_class intc_class = {
- .name = "intc",
+static struct syscore_ops intc_syscore_ops = {
.suspend = intc_suspend,
.resume = intc_resume,
};
-static int __init intc_init_sysdev(void)
+static int __init intc_init_syscore(void)
{
- int ret;
-
- ret = sysdev_class_register(&intc_class);
- if (ret)
- return ret;
+ register_syscore_ops(&intc_syscore_ops);
- intc0.sysdev.id = 0;
- intc0.sysdev.cls = &intc_class;
- ret = sysdev_register(&intc0.sysdev);
-
- return ret;
+ return 0;
}
-device_initcall(intc_init_sysdev);
+device_initcall(intc_init_syscore);
unsigned long intc_get_pending(unsigned int group)
{
diff --git a/arch/avr32/mm/init.c b/arch/avr32/mm/init.c
index a7314d44b17b..2798c2d4a1cf 100644
--- a/arch/avr32/mm/init.c
+++ b/arch/avr32/mm/init.c
@@ -25,8 +25,6 @@
#include <asm/setup.h>
#include <asm/sections.h>
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned_data;
struct page *empty_zero_page;
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index 8addb1220b4f..d619b17c4413 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -24,11 +24,13 @@ config BLACKFIN
select HAVE_FUNCTION_TRACER
select HAVE_FUNCTION_TRACE_MCOUNT_TEST
select HAVE_IDE
+ select HAVE_IRQ_WORK
select HAVE_KERNEL_GZIP if RAMKERNEL
select HAVE_KERNEL_BZIP2 if RAMKERNEL
select HAVE_KERNEL_LZMA if RAMKERNEL
select HAVE_KERNEL_LZO if RAMKERNEL
select HAVE_OPROFILE
+ select HAVE_PERF_EVENTS
select ARCH_WANT_OPTIONAL_GPIOLIB
select HAVE_GENERIC_HARDIRQS
select GENERIC_ATOMIC64
@@ -45,9 +47,6 @@ config GENERIC_BUG
config ZONE_DMA
def_bool y
-config GENERIC_FIND_NEXT_BIT
- def_bool y
-
config GENERIC_GPIO
def_bool y
diff --git a/arch/blackfin/Kconfig.debug b/arch/blackfin/Kconfig.debug
index 2641731f24cd..e2a3d4c8ab9a 100644
--- a/arch/blackfin/Kconfig.debug
+++ b/arch/blackfin/Kconfig.debug
@@ -9,15 +9,6 @@ config DEBUG_STACKOVERFLOW
This option will cause messages to be printed if free stack space
drops below a certain limit.
-config DEBUG_STACK_USAGE
- bool "Enable stack utilization instrumentation"
- depends on DEBUG_KERNEL
- help
- Enables the display of the minimum amount of free stack which each
- task has ever had available in the sysrq-T output.
-
- This option will slow down process creation somewhat.
-
config DEBUG_VERBOSE
bool "Verbose fault messages"
default y
@@ -32,7 +23,7 @@ config DEBUG_VERBOSE
Most people should say N here.
config DEBUG_MMRS
- bool "Generate Blackfin MMR tree"
+ tristate "Generate Blackfin MMR tree"
select DEBUG_FS
help
Create a tree of Blackfin MMRs via the debugfs tree. If
diff --git a/arch/blackfin/configs/BF527-EZKIT-V2_defconfig b/arch/blackfin/configs/BF527-EZKIT-V2_defconfig
index 95cf2ba9de17..8465b3e6b862 100644
--- a/arch/blackfin/configs/BF527-EZKIT-V2_defconfig
+++ b/arch/blackfin/configs/BF527-EZKIT-V2_defconfig
@@ -121,13 +121,11 @@ CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_VGA16 is not set
# CONFIG_LOGO_LINUX_CLUT224 is not set
# CONFIG_LOGO_BLACKFIN_VGA16 is not set
-CONFIG_SOUND=m
-CONFIG_SND=m
-CONFIG_SND_SOC=m
-CONFIG_SND_BF5XX_I2S=m
-CONFIG_SND_BF5XX_SOC_SSM2602=m
-CONFIG_SND_BF5XX_AC97=m
-CONFIG_SND_BF5XX_SOC_AD1980=m
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_BF5XX_I2S=y
+CONFIG_SND_BF5XX_SOC_SSM2602=y
CONFIG_HID_A4TECH=y
CONFIG_HID_APPLE=y
CONFIG_HID_BELKIN=y
diff --git a/arch/blackfin/configs/BF527-EZKIT_defconfig b/arch/blackfin/configs/BF527-EZKIT_defconfig
index 8be8e33fac52..5e7321b26040 100644
--- a/arch/blackfin/configs/BF527-EZKIT_defconfig
+++ b/arch/blackfin/configs/BF527-EZKIT_defconfig
@@ -96,7 +96,7 @@ CONFIG_SERIAL_BFIN_UART1=y
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
CONFIG_I2C_CHARDEV=m
-CONFIG_I2C_BLACKFIN_TWI=m
+CONFIG_I2C_BLACKFIN_TWI=y
CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ=100
CONFIG_SPI=y
CONFIG_SPI_BFIN=y
@@ -115,13 +115,11 @@ CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_VGA16 is not set
# CONFIG_LOGO_LINUX_CLUT224 is not set
# CONFIG_LOGO_BLACKFIN_VGA16 is not set
-CONFIG_SOUND=m
-CONFIG_SND=m
-CONFIG_SND_SOC=m
-CONFIG_SND_BF5XX_I2S=m
-CONFIG_SND_BF5XX_SOC_SSM2602=m
-CONFIG_SND_BF5XX_AC97=m
-CONFIG_SND_BF5XX_SOC_AD1980=m
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SND_BF5XX_I2S=y
+CONFIG_SND_BF5XX_SOC_SSM2602=y
CONFIG_HID_A4TECH=y
CONFIG_HID_APPLE=y
CONFIG_HID_BELKIN=y
diff --git a/arch/blackfin/configs/BF533-STAMP_defconfig b/arch/blackfin/configs/BF533-STAMP_defconfig
index 0aafde6c8c2d..b90d3792ed52 100644
--- a/arch/blackfin/configs/BF533-STAMP_defconfig
+++ b/arch/blackfin/configs/BF533-STAMP_defconfig
@@ -99,8 +99,6 @@ CONFIG_SND_PCM_OSS=m
CONFIG_SND_SOC=m
CONFIG_SND_BF5XX_I2S=m
CONFIG_SND_BF5XX_SOC_AD73311=m
-CONFIG_SND_BF5XX_AC97=m
-CONFIG_SND_BF5XX_SOC_AD1980=m
# CONFIG_USB_SUPPORT is not set
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_BFIN=y
diff --git a/arch/blackfin/configs/BF537-STAMP_defconfig b/arch/blackfin/configs/BF537-STAMP_defconfig
index c9077fb58135..005362537a7b 100644
--- a/arch/blackfin/configs/BF537-STAMP_defconfig
+++ b/arch/blackfin/configs/BF537-STAMP_defconfig
@@ -110,8 +110,6 @@ CONFIG_SND_PCM_OSS=m
CONFIG_SND_SOC=m
CONFIG_SND_BF5XX_I2S=m
CONFIG_SND_BF5XX_SOC_AD73311=m
-CONFIG_SND_BF5XX_AC97=m
-CONFIG_SND_BF5XX_SOC_AD1980=m
# CONFIG_USB_SUPPORT is not set
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_BFIN=y
diff --git a/arch/blackfin/include/asm/bfin-global.h b/arch/blackfin/include/asm/bfin-global.h
index 121cc04d877d..17bcbf60bcae 100644
--- a/arch/blackfin/include/asm/bfin-global.h
+++ b/arch/blackfin/include/asm/bfin-global.h
@@ -49,16 +49,6 @@ extern void dump_bfin_trace_buffer(void);
#define dump_bfin_trace_buffer()
#endif
-/* init functions only */
-extern int init_arch_irq(void);
-extern void init_exception_vectors(void);
-extern void program_IAR(void);
-
-extern asmlinkage void lower_to_irq14(void);
-extern asmlinkage void bfin_return_from_exception(void);
-extern asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs);
-extern int bfin_internal_set_wake(unsigned int irq, unsigned int state);
-
extern void *l1_data_A_sram_alloc(size_t);
extern void *l1_data_B_sram_alloc(size_t);
extern void *l1_inst_sram_alloc(size_t);
diff --git a/arch/blackfin/include/asm/bfin_pfmon.h b/arch/blackfin/include/asm/bfin_pfmon.h
new file mode 100644
index 000000000000..accd47e2db40
--- /dev/null
+++ b/arch/blackfin/include/asm/bfin_pfmon.h
@@ -0,0 +1,44 @@
+/*
+ * Blackfin Performance Monitor definitions
+ *
+ * Copyright 2005-2011 Analog Devices Inc.
+ *
+ * Licensed under the ADI BSD license or GPL-2 (or later).
+ */
+
+#ifndef __ASM_BFIN_PFMON_H__
+#define __ASM_BFIN_PFMON_H__
+
+/* PFCTL Masks */
+#define PFMON_MASK 0xff
+#define PFCEN_MASK 0x3
+#define PFCEN_DISABLE 0x0
+#define PFCEN_ENABLE_USER 0x1
+#define PFCEN_ENABLE_SUPV 0x2
+#define PFCEN_ENABLE_ALL (PFCEN_ENABLE_USER | PFCEN_ENABLE_SUPV)
+
+#define PFPWR_P 0
+#define PEMUSW0_P 2
+#define PFCEN0_P 3
+#define PFMON0_P 5
+#define PEMUSW1_P 13
+#define PFCEN1_P 14
+#define PFMON1_P 16
+#define PFCNT0_P 24
+#define PFCNT1_P 25
+
+#define PFPWR (1 << PFPWR_P)
+#define PEMUSW(n, x) ((x) << ((n) ? PEMUSW1_P : PEMUSW0_P))
+#define PEMUSW0 PEMUSW(0, 1)
+#define PEMUSW1 PEMUSW(1, 1)
+#define PFCEN(n, x) ((x) << ((n) ? PFCEN1_P : PFCEN0_P))
+#define PFCEN0 PFCEN(0, PFCEN_MASK)
+#define PFCEN1 PFCEN(1, PFCEN_MASK)
+#define PFCNT(n, x) ((x) << ((n) ? PFCNT1_P : PFCNT0_P))
+#define PFCNT0 PFCNT(0, 1)
+#define PFCNT1 PFCNT(1, 1)
+#define PFMON(n, x) ((x) << ((n) ? PFMON1_P : PFMON0_P))
+#define PFMON0 PFMON(0, PFMON_MASK)
+#define PFMON1 PFMON(1, PFMON_MASK)
+
+#endif
diff --git a/arch/blackfin/include/asm/bfin_sport.h b/arch/blackfin/include/asm/bfin_sport.h
index d27600c262c2..f8568a31d0ab 100644
--- a/arch/blackfin/include/asm/bfin_sport.h
+++ b/arch/blackfin/include/asm/bfin_sport.h
@@ -100,6 +100,10 @@ struct sport_register {
};
#undef __BFP
+struct bfin_snd_platform_data {
+ const unsigned short *pin_req;
+};
+
#define bfin_read_sport_rx32(base) \
({ \
struct sport_register *__mmrs = (void *)base; \
diff --git a/arch/blackfin/include/asm/cacheflush.h b/arch/blackfin/include/asm/cacheflush.h
index 77135b62818e..9a5b2c572ebf 100644
--- a/arch/blackfin/include/asm/cacheflush.h
+++ b/arch/blackfin/include/asm/cacheflush.h
@@ -39,8 +39,13 @@ extern void blackfin_invalidate_entire_icache(void);
static inline void flush_icache_range(unsigned start, unsigned end)
{
-#if defined(CONFIG_BFIN_EXTMEM_WRITEBACK) || defined(CONFIG_BFIN_L2_WRITEBACK)
- blackfin_dcache_flush_range(start, end);
+#if defined(CONFIG_BFIN_EXTMEM_WRITEBACK)
+ if (end <= physical_mem_end)
+ blackfin_dcache_flush_range(start, end);
+#endif
+#if defined(CONFIG_BFIN_L2_WRITEBACK)
+ if (start >= L2_START && end <= L2_START + L2_LENGTH)
+ blackfin_dcache_flush_range(start, end);
#endif
/* Make sure all write buffers in the data side of the core
@@ -52,9 +57,17 @@ static inline void flush_icache_range(unsigned start, unsigned end)
* the pipeline.
*/
SSYNC();
-#if defined(CONFIG_BFIN_ICACHE)
- blackfin_icache_flush_range(start, end);
- flush_icache_range_others(start, end);
+#if defined(CONFIG_BFIN_EXTMEM_ICACHEABLE)
+ if (end <= physical_mem_end) {
+ blackfin_icache_flush_range(start, end);
+ flush_icache_range_others(start, end);
+ }
+#endif
+#if defined(CONFIG_BFIN_L2_ICACHEABLE)
+ if (start >= L2_START && end <= L2_START + L2_LENGTH) {
+ blackfin_icache_flush_range(start, end);
+ flush_icache_range_others(start, end);
+ }
#endif
}
diff --git a/arch/blackfin/include/asm/cpu.h b/arch/blackfin/include/asm/cpu.h
index 16883e582e3c..05043786da21 100644
--- a/arch/blackfin/include/asm/cpu.h
+++ b/arch/blackfin/include/asm/cpu.h
@@ -10,11 +10,8 @@
#include <linux/percpu.h>
-struct task_struct;
-
struct blackfin_cpudata {
struct cpu cpu;
- struct task_struct *idle;
unsigned int imemctl;
unsigned int dmemctl;
};
diff --git a/arch/blackfin/include/asm/def_LPBlackfin.h b/arch/blackfin/include/asm/def_LPBlackfin.h
index 7600fe0696af..823679011457 100644
--- a/arch/blackfin/include/asm/def_LPBlackfin.h
+++ b/arch/blackfin/include/asm/def_LPBlackfin.h
@@ -52,10 +52,10 @@
#define bfin_read(addr) \
({ \
- sizeof(*(addr)) == 1 ? bfin_read8(addr) : \
- sizeof(*(addr)) == 2 ? bfin_read16(addr) : \
- sizeof(*(addr)) == 4 ? bfin_read32(addr) : \
- ({ BUG(); 0; }); \
+ sizeof(*(addr)) == 1 ? bfin_read8(addr) : \
+ sizeof(*(addr)) == 2 ? bfin_read16(addr) : \
+ sizeof(*(addr)) == 4 ? bfin_read32(addr) : \
+ ({ BUG(); 0; }); \
})
#define bfin_write(addr, val) \
do { \
@@ -69,13 +69,13 @@ do { \
#define bfin_write_or(addr, bits) \
do { \
- void *__addr = (void *)(addr); \
+ typeof(addr) __addr = (addr); \
bfin_write(__addr, bfin_read(__addr) | (bits)); \
} while (0)
#define bfin_write_and(addr, bits) \
do { \
- void *__addr = (void *)(addr); \
+ typeof(addr) __addr = (addr); \
bfin_write(__addr, bfin_read(__addr) & (bits)); \
} while (0)
diff --git a/arch/blackfin/include/asm/irq_handler.h b/arch/blackfin/include/asm/irq_handler.h
index 7fbe42307b9a..ee73f79aef10 100644
--- a/arch/blackfin/include/asm/irq_handler.h
+++ b/arch/blackfin/include/asm/irq_handler.h
@@ -10,6 +10,16 @@
#include <linux/types.h>
#include <linux/linkage.h>
+/* init functions only */
+extern int __init init_arch_irq(void);
+extern void init_exception_vectors(void);
+extern void __init program_IAR(void);
+#ifdef init_mach_irq
+extern void __init init_mach_irq(void);
+#else
+# define init_mach_irq()
+#endif
+
/* BASE LEVEL interrupt handler routines */
asmlinkage void evt_exception(void);
asmlinkage void trap(void);
@@ -37,4 +47,19 @@ extern void return_from_exception(void);
extern int bfin_request_exception(unsigned int exception, void (*handler)(void));
extern int bfin_free_exception(unsigned int exception, void (*handler)(void));
+extern asmlinkage void lower_to_irq14(void);
+extern asmlinkage void bfin_return_from_exception(void);
+extern asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs);
+extern int bfin_internal_set_wake(unsigned int irq, unsigned int state);
+
+struct irq_data;
+extern void bfin_handle_irq(unsigned irq);
+extern void bfin_ack_noop(struct irq_data *);
+extern void bfin_internal_mask_irq(unsigned int irq);
+extern void bfin_internal_unmask_irq(unsigned int irq);
+
+struct irq_desc;
+extern void bfin_demux_mac_status_irq(unsigned int, struct irq_desc *);
+extern void bfin_demux_gpio_irq(unsigned int, struct irq_desc *);
+
#endif
diff --git a/arch/blackfin/include/asm/kgdb.h b/arch/blackfin/include/asm/kgdb.h
index 8651afe12990..aaf884591b07 100644
--- a/arch/blackfin/include/asm/kgdb.h
+++ b/arch/blackfin/include/asm/kgdb.h
@@ -103,7 +103,12 @@ static inline void arch_kgdb_breakpoint(void)
asm("EXCPT 2;");
}
#define BREAK_INSTR_SIZE 2
-#define CACHE_FLUSH_IS_SAFE 1
+#ifdef CONFIG_SMP
+# define CACHE_FLUSH_IS_SAFE 0
+#else
+# define CACHE_FLUSH_IS_SAFE 1
+#endif
+#define GDB_ADJUSTS_BREAK_OFFSET
#define HW_INST_WATCHPOINT_NUM 6
#define HW_WATCHPOINT_NUM 8
#define TYPE_INST_WATCHPOINT 0
diff --git a/arch/blackfin/include/asm/perf_event.h b/arch/blackfin/include/asm/perf_event.h
new file mode 100644
index 000000000000..3d2b1716322f
--- /dev/null
+++ b/arch/blackfin/include/asm/perf_event.h
@@ -0,0 +1 @@
+#define MAX_HWEVENTS 2
diff --git a/arch/blackfin/include/asm/ptrace.h b/arch/blackfin/include/asm/ptrace.h
index 832d7c009a2c..7854d4367c15 100644
--- a/arch/blackfin/include/asm/ptrace.h
+++ b/arch/blackfin/include/asm/ptrace.h
@@ -102,14 +102,9 @@ struct pt_regs {
/* user_mode returns true if only one bit is set in IPEND, other than the
master interrupt enable. */
#define user_mode(regs) (!(((regs)->ipend & ~0x10) & (((regs)->ipend & ~0x10) - 1)))
-#define instruction_pointer(regs) ((regs)->pc)
-#define user_stack_pointer(regs) ((regs)->usp)
-#define profile_pc(regs) instruction_pointer(regs)
extern void show_regs(struct pt_regs *);
#define arch_has_single_step() (1)
-extern void user_enable_single_step(struct task_struct *child);
-extern void user_disable_single_step(struct task_struct *child);
/* common code demands this function */
#define ptrace_disable(child) user_disable_single_step(child)
@@ -130,6 +125,8 @@ extern int is_user_addr_valid(struct task_struct *child,
((unsigned long)task_stack_page(task) + \
(THREAD_SIZE - sizeof(struct pt_regs)))
+#include <asm-generic/ptrace.h>
+
#endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */
diff --git a/arch/blackfin/include/mach-common/irq.h b/arch/blackfin/include/mach-common/irq.h
new file mode 100644
index 000000000000..cab14e911dc2
--- /dev/null
+++ b/arch/blackfin/include/mach-common/irq.h
@@ -0,0 +1,57 @@
+/*
+ * Common Blackfin IRQ definitions (i.e. the CEC)
+ *
+ * Copyright 2005-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+#ifndef _MACH_COMMON_IRQ_H_
+#define _MACH_COMMON_IRQ_H_
+
+/*
+ * Core events interrupt source definitions
+ *
+ * Event Source Event Name
+ * Emulation EMU 0 (highest priority)
+ * Reset RST 1
+ * NMI NMI 2
+ * Exception EVX 3
+ * Reserved -- 4
+ * Hardware Error IVHW 5
+ * Core Timer IVTMR 6
+ * Peripherals IVG7 7
+ * Peripherals IVG8 8
+ * Peripherals IVG9 9
+ * Peripherals IVG10 10
+ * Peripherals IVG11 11
+ * Peripherals IVG12 12
+ * Peripherals IVG13 13
+ * Softirq IVG14 14
+ * System Call IVG15 15 (lowest priority)
+ */
+
+/* The ABSTRACT IRQ definitions */
+#define IRQ_EMU 0 /* Emulation */
+#define IRQ_RST 1 /* reset */
+#define IRQ_NMI 2 /* Non Maskable */
+#define IRQ_EVX 3 /* Exception */
+#define IRQ_UNUSED 4 /* - unused interrupt */
+#define IRQ_HWERR 5 /* Hardware Error */
+#define IRQ_CORETMR 6 /* Core timer */
+
+#define BFIN_IRQ(x) ((x) + 7)
+
+#define IVG7 7
+#define IVG8 8
+#define IVG9 9
+#define IVG10 10
+#define IVG11 11
+#define IVG12 12
+#define IVG13 13
+#define IVG14 14
+#define IVG15 15
+
+#define NR_IRQS (NR_MACH_IRQS + NR_SPARE_IRQS)
+
+#endif
diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile
index ca5ccc777772..d550b24d9e9b 100644
--- a/arch/blackfin/kernel/Makefile
+++ b/arch/blackfin/kernel/Makefile
@@ -33,7 +33,10 @@ obj-$(CONFIG_EARLY_PRINTK) += shadow_console.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_DEBUG_VERBOSE) += trace.o
obj-$(CONFIG_BFIN_PSEUDODBG_INSNS) += pseudodbg.o
+obj-$(CONFIG_PERF_EVENTS) += perf_event.o
# the kgdb test puts code into L2 and without linker
# relaxation, we need to force long calls to/from it
CFLAGS_kgdb_test.o := -mlong-calls -O0
+
+obj-$(CONFIG_DEBUG_MMRS) += debug-mmrs.o
diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c
index 6ce8dce753c9..71dbaa4a48af 100644
--- a/arch/blackfin/kernel/bfin_dma_5xx.c
+++ b/arch/blackfin/kernel/bfin_dma_5xx.c
@@ -36,6 +36,11 @@ static int __init blackfin_dma_init(void)
printk(KERN_INFO "Blackfin DMA Controller\n");
+
+#if ANOMALY_05000480
+ bfin_write_DMAC_TC_PER(0x0111);
+#endif
+
for (i = 0; i < MAX_DMA_CHANNELS; i++) {
atomic_set(&dma_ch[i].chan_status, 0);
dma_ch[i].regs = dma_io_base_addr[i];
diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c
index 170cf90735ba..bcf8cf6fe412 100644
--- a/arch/blackfin/kernel/bfin_gpio.c
+++ b/arch/blackfin/kernel/bfin_gpio.c
@@ -10,10 +10,12 @@
#include <linux/module.h>
#include <linux/err.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <asm/blackfin.h>
#include <asm/gpio.h>
#include <asm/portmux.h>
#include <linux/irq.h>
+#include <asm/irq_handler.h>
#if ANOMALY_05000311 || ANOMALY_05000323
enum {
@@ -534,7 +536,7 @@ static const unsigned int sic_iwr_irqs[] = {
#if defined(BF533_FAMILY)
IRQ_PROG_INTB
#elif defined(BF537_FAMILY)
- IRQ_PROG_INTB, IRQ_PORTG_INTB, IRQ_MAC_TX
+ IRQ_PF_INTB_WATCH, IRQ_PORTG_INTB, IRQ_PH_INTB_MAC_TX
#elif defined(BF538_FAMILY)
IRQ_PORTF_INTB
#elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x)
@@ -1203,35 +1205,43 @@ void bfin_reset_boot_spi_cs(unsigned short pin)
}
#if defined(CONFIG_PROC_FS)
-static int gpio_proc_read(char *buf, char **start, off_t offset,
- int len, int *unused_i, void *unused_v)
+static int gpio_proc_show(struct seq_file *m, void *v)
{
- int c, irq, gpio, outlen = 0;
+ int c, irq, gpio;
for (c = 0; c < MAX_RESOURCES; c++) {
irq = is_reserved(gpio_irq, c, 1);
gpio = is_reserved(gpio, c, 1);
if (!check_gpio(c) && (gpio || irq))
- len = sprintf(buf, "GPIO_%d: \t%s%s \t\tGPIO %s\n", c,
+ seq_printf(m, "GPIO_%d: \t%s%s \t\tGPIO %s\n", c,
get_label(c), (gpio && irq) ? " *" : "",
get_gpio_dir(c) ? "OUTPUT" : "INPUT");
else if (is_reserved(peri, c, 1))
- len = sprintf(buf, "GPIO_%d: \t%s \t\tPeripheral\n", c, get_label(c));
+ seq_printf(m, "GPIO_%d: \t%s \t\tPeripheral\n", c, get_label(c));
else
continue;
- buf += len;
- outlen += len;
}
- return outlen;
+
+ return 0;
}
+static int gpio_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, gpio_proc_show, NULL);
+}
+
+static const struct file_operations gpio_proc_ops = {
+ .open = gpio_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static __init int gpio_register_proc(void)
{
struct proc_dir_entry *proc_gpio;
- proc_gpio = create_proc_entry("gpio", S_IRUGO, NULL);
- if (proc_gpio)
- proc_gpio->read_proc = gpio_proc_read;
+ proc_gpio = proc_create("gpio", S_IRUGO, NULL, &gpio_proc_ops);
return proc_gpio != NULL;
}
__initcall(gpio_register_proc);
diff --git a/arch/blackfin/kernel/bfin_ksyms.c b/arch/blackfin/kernel/bfin_ksyms.c
index 2c264b51566a..c446591b961d 100644
--- a/arch/blackfin/kernel/bfin_ksyms.c
+++ b/arch/blackfin/kernel/bfin_ksyms.c
@@ -11,6 +11,7 @@
#include <asm/cacheflush.h>
#include <asm/io.h>
+#include <asm/irq_handler.h>
/* Allow people to have their own Blackfin exception handler in a module */
EXPORT_SYMBOL(bfin_return_from_exception);
diff --git a/arch/blackfin/kernel/debug-mmrs.c b/arch/blackfin/kernel/debug-mmrs.c
new file mode 100644
index 000000000000..94b1d8a0256a
--- /dev/null
+++ b/arch/blackfin/kernel/debug-mmrs.c
@@ -0,0 +1,1860 @@
+/*
+ * debugfs interface to core/system MMRs
+ *
+ * Copyright 2007-2011 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
+#include <linux/debugfs.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <asm/blackfin.h>
+#include <asm/gpio.h>
+#include <asm/bfin_can.h>
+#include <asm/bfin_dma.h>
+#include <asm/bfin_ppi.h>
+#include <asm/bfin_serial.h>
+#include <asm/bfin5xx_spi.h>
+#include <asm/bfin_twi.h>
+
+/* Common code defines PORT_MUX on us, so redirect the MMR back locally */
+#ifdef BFIN_PORT_MUX
+#undef PORT_MUX
+#define PORT_MUX BFIN_PORT_MUX
+#endif
+
+#define _d(name, bits, addr, perms) debugfs_create_x##bits(name, perms, parent, (u##bits *)addr)
+#define d(name, bits, addr) _d(name, bits, addr, S_IRUSR|S_IWUSR)
+#define d_RO(name, bits, addr) _d(name, bits, addr, S_IRUSR)
+#define d_WO(name, bits, addr) _d(name, bits, addr, S_IWUSR)
+
+#define D_RO(name, bits) d_RO(#name, bits, name)
+#define D_WO(name, bits) d_WO(#name, bits, name)
+#define D32(name) d(#name, 32, name)
+#define D16(name) d(#name, 16, name)
+
+#define REGS_OFF(peri, mmr) offsetof(struct bfin_##peri##_regs, mmr)
+#define __REGS(peri, sname, rname) \
+ do { \
+ struct bfin_##peri##_regs r; \
+ void *addr = (void *)(base + REGS_OFF(peri, rname)); \
+ strcpy(_buf, sname); \
+ if (sizeof(r.rname) == 2) \
+ debugfs_create_x16(buf, S_IRUSR|S_IWUSR, parent, addr); \
+ else \
+ debugfs_create_x32(buf, S_IRUSR|S_IWUSR, parent, addr); \
+ } while (0)
+#define REGS_STR_PFX(buf, pfx, num) \
+ ({ \
+ buf + (num >= 0 ? \
+ sprintf(buf, #pfx "%i_", num) : \
+ sprintf(buf, #pfx "_")); \
+ })
+#define REGS_STR_PFX_C(buf, pfx, num) \
+ ({ \
+ buf + (num >= 0 ? \
+ sprintf(buf, #pfx "%c_", 'A' + num) : \
+ sprintf(buf, #pfx "_")); \
+ })
+
+/*
+ * Core registers (not memory mapped)
+ */
+extern u32 last_seqstat;
+
+static int debug_cclk_get(void *data, u64 *val)
+{
+ *val = get_cclk();
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_debug_cclk, debug_cclk_get, NULL, "0x%08llx\n");
+
+static int debug_sclk_get(void *data, u64 *val)
+{
+ *val = get_sclk();
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_debug_sclk, debug_sclk_get, NULL, "0x%08llx\n");
+
+#define DEFINE_SYSREG(sr, pre, post) \
+static int sysreg_##sr##_get(void *data, u64 *val) \
+{ \
+ unsigned long tmp; \
+ pre; \
+ __asm__ __volatile__("%0 = " #sr ";" : "=d"(tmp)); \
+ *val = tmp; \
+ return 0; \
+} \
+static int sysreg_##sr##_set(void *data, u64 val) \
+{ \
+ unsigned long tmp = val; \
+ __asm__ __volatile__(#sr " = %0;" : : "d"(tmp)); \
+ post; \
+ return 0; \
+} \
+DEFINE_SIMPLE_ATTRIBUTE(fops_sysreg_##sr, sysreg_##sr##_get, sysreg_##sr##_set, "0x%08llx\n")
+
+DEFINE_SYSREG(cycles, , );
+DEFINE_SYSREG(cycles2, __asm__ __volatile__("%0 = cycles;" : "=d"(tmp)), );
+DEFINE_SYSREG(emudat, , );
+DEFINE_SYSREG(seqstat, , );
+DEFINE_SYSREG(syscfg, , CSYNC());
+#define D_SYSREG(sr) debugfs_create_file(#sr, S_IRUSR|S_IWUSR, parent, NULL, &fops_sysreg_##sr)
+
+/*
+ * CAN
+ */
+#define CAN_OFF(mmr) REGS_OFF(can, mmr)
+#define __CAN(uname, lname) __REGS(can, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_can(struct dentry *parent, unsigned long base, int num)
+{
+ static struct dentry *am, *mb;
+ int i, j;
+ char buf[32], *_buf = REGS_STR_PFX(buf, CAN, num);
+
+ if (!am) {
+ am = debugfs_create_dir("am", parent);
+ mb = debugfs_create_dir("mb", parent);
+ }
+
+ __CAN(MC1, mc1);
+ __CAN(MD1, md1);
+ __CAN(TRS1, trs1);
+ __CAN(TRR1, trr1);
+ __CAN(TA1, ta1);
+ __CAN(AA1, aa1);
+ __CAN(RMP1, rmp1);
+ __CAN(RML1, rml1);
+ __CAN(MBTIF1, mbtif1);
+ __CAN(MBRIF1, mbrif1);
+ __CAN(MBIM1, mbim1);
+ __CAN(RFH1, rfh1);
+ __CAN(OPSS1, opss1);
+
+ __CAN(MC2, mc2);
+ __CAN(MD2, md2);
+ __CAN(TRS2, trs2);
+ __CAN(TRR2, trr2);
+ __CAN(TA2, ta2);
+ __CAN(AA2, aa2);
+ __CAN(RMP2, rmp2);
+ __CAN(RML2, rml2);
+ __CAN(MBTIF2, mbtif2);
+ __CAN(MBRIF2, mbrif2);
+ __CAN(MBIM2, mbim2);
+ __CAN(RFH2, rfh2);
+ __CAN(OPSS2, opss2);
+
+ __CAN(CLOCK, clock);
+ __CAN(TIMING, timing);
+ __CAN(DEBUG, debug);
+ __CAN(STATUS, status);
+ __CAN(CEC, cec);
+ __CAN(GIS, gis);
+ __CAN(GIM, gim);
+ __CAN(GIF, gif);
+ __CAN(CONTROL, control);
+ __CAN(INTR, intr);
+ __CAN(VERSION, version);
+ __CAN(MBTD, mbtd);
+ __CAN(EWR, ewr);
+ __CAN(ESR, esr);
+ /*__CAN(UCREG, ucreg); no longer exists */
+ __CAN(UCCNT, uccnt);
+ __CAN(UCRC, ucrc);
+ __CAN(UCCNF, uccnf);
+ __CAN(VERSION2, version2);
+
+ for (i = 0; i < 32; ++i) {
+ sprintf(_buf, "AM%02iL", i);
+ debugfs_create_x16(buf, S_IRUSR|S_IWUSR, am,
+ (u16 *)(base + CAN_OFF(msk[i].aml)));
+ sprintf(_buf, "AM%02iH", i);
+ debugfs_create_x16(buf, S_IRUSR|S_IWUSR, am,
+ (u16 *)(base + CAN_OFF(msk[i].amh)));
+
+ for (j = 0; j < 3; ++j) {
+ sprintf(_buf, "MB%02i_DATA%i", i, j);
+ debugfs_create_x16(buf, S_IRUSR|S_IWUSR, mb,
+ (u16 *)(base + CAN_OFF(chl[i].data[j*2])));
+ }
+ sprintf(_buf, "MB%02i_LENGTH", i);
+ debugfs_create_x16(buf, S_IRUSR|S_IWUSR, mb,
+ (u16 *)(base + CAN_OFF(chl[i].dlc)));
+ sprintf(_buf, "MB%02i_TIMESTAMP", i);
+ debugfs_create_x16(buf, S_IRUSR|S_IWUSR, mb,
+ (u16 *)(base + CAN_OFF(chl[i].tsv)));
+ sprintf(_buf, "MB%02i_ID0", i);
+ debugfs_create_x16(buf, S_IRUSR|S_IWUSR, mb,
+ (u16 *)(base + CAN_OFF(chl[i].id0)));
+ sprintf(_buf, "MB%02i_ID1", i);
+ debugfs_create_x16(buf, S_IRUSR|S_IWUSR, mb,
+ (u16 *)(base + CAN_OFF(chl[i].id1)));
+ }
+}
+#define CAN(num) bfin_debug_mmrs_can(parent, CAN##num##_MC1, num)
+
+/*
+ * DMA
+ */
+#define __DMA(uname, lname) __REGS(dma, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_dma(struct dentry *parent, unsigned long base, int num, char mdma, const char *pfx)
+{
+ char buf[32], *_buf;
+
+ if (mdma)
+ _buf = buf + sprintf(buf, "%s_%c%i_", pfx, mdma, num);
+ else
+ _buf = buf + sprintf(buf, "%s%i_", pfx, num);
+
+ __DMA(NEXT_DESC_PTR, next_desc_ptr);
+ __DMA(START_ADDR, start_addr);
+ __DMA(CONFIG, config);
+ __DMA(X_COUNT, x_count);
+ __DMA(X_MODIFY, x_modify);
+ __DMA(Y_COUNT, y_count);
+ __DMA(Y_MODIFY, y_modify);
+ __DMA(CURR_DESC_PTR, curr_desc_ptr);
+ __DMA(CURR_ADDR, curr_addr);
+ __DMA(IRQ_STATUS, irq_status);
+ __DMA(PERIPHERAL_MAP, peripheral_map);
+ __DMA(CURR_X_COUNT, curr_x_count);
+ __DMA(CURR_Y_COUNT, curr_y_count);
+}
+#define _DMA(num, base, mdma, pfx) bfin_debug_mmrs_dma(parent, base, num, mdma, pfx "DMA")
+#define DMA(num) _DMA(num, DMA##num##_NEXT_DESC_PTR, 0, "")
+#define _MDMA(num, x) \
+ do { \
+ _DMA(num, x##DMA_D##num##_CONFIG, 'D', #x); \
+ _DMA(num, x##DMA_S##num##_CONFIG, 'S', #x); \
+ } while (0)
+#define MDMA(num) _MDMA(num, M)
+#define IMDMA(num) _MDMA(num, IM)
+
+/*
+ * EPPI
+ */
+#define __EPPI(uname, lname) __REGS(eppi, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_eppi(struct dentry *parent, unsigned long base, int num)
+{
+ char buf[32], *_buf = REGS_STR_PFX(buf, EPPI, num);
+ __EPPI(STATUS, status);
+ __EPPI(HCOUNT, hcount);
+ __EPPI(HDELAY, hdelay);
+ __EPPI(VCOUNT, vcount);
+ __EPPI(VDELAY, vdelay);
+ __EPPI(FRAME, frame);
+ __EPPI(LINE, line);
+ __EPPI(CLKDIV, clkdiv);
+ __EPPI(CONTROL, control);
+ __EPPI(FS1W_HBL, fs1w_hbl);
+ __EPPI(FS1P_AVPL, fs1p_avpl);
+ __EPPI(FS2W_LVB, fs2w_lvb);
+ __EPPI(FS2P_LAVF, fs2p_lavf);
+ __EPPI(CLIP, clip);
+}
+#define EPPI(num) bfin_debug_mmrs_eppi(parent, EPPI##num##_STATUS, num)
+
+/*
+ * General Purpose Timers
+ */
+#define GPTIMER_OFF(mmr) (TIMER0_##mmr - TIMER0_CONFIG)
+#define __GPTIMER(name) \
+ do { \
+ strcpy(_buf, #name); \
+ debugfs_create_x16(buf, S_IRUSR|S_IWUSR, parent, (u16 *)(base + GPTIMER_OFF(name))); \
+ } while (0)
+static void __init __maybe_unused
+bfin_debug_mmrs_gptimer(struct dentry *parent, unsigned long base, int num)
+{
+ char buf[32], *_buf = REGS_STR_PFX(buf, TIMER, num);
+ __GPTIMER(CONFIG);
+ __GPTIMER(COUNTER);
+ __GPTIMER(PERIOD);
+ __GPTIMER(WIDTH);
+}
+#define GPTIMER(num) bfin_debug_mmrs_gptimer(parent, TIMER##num##_CONFIG, num)
+
+/*
+ * Handshake MDMA
+ */
+#define __HMDMA(uname, lname) __REGS(hmdma, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_hmdma(struct dentry *parent, unsigned long base, int num)
+{
+ char buf[32], *_buf = REGS_STR_PFX(buf, HMDMA, num);
+ __HMDMA(CONTROL, control);
+ __HMDMA(ECINIT, ecinit);
+ __HMDMA(BCINIT, bcinit);
+ __HMDMA(ECURGENT, ecurgent);
+ __HMDMA(ECOVERFLOW, ecoverflow);
+ __HMDMA(ECOUNT, ecount);
+ __HMDMA(BCOUNT, bcount);
+}
+#define HMDMA(num) bfin_debug_mmrs_hmdma(parent, HMDMA##num##_CONTROL, num)
+
+/*
+ * Port/GPIO
+ */
+#define bfin_gpio_regs gpio_port_t
+#define __PORT(uname, lname) __REGS(gpio, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_port(struct dentry *parent, unsigned long base, int num)
+{
+ char buf[32], *_buf;
+#ifdef __ADSPBF54x__
+ _buf = REGS_STR_PFX_C(buf, PORT, num);
+ __PORT(FER, port_fer);
+ __PORT(SET, data_set);
+ __PORT(CLEAR, data_clear);
+ __PORT(DIR_SET, dir_set);
+ __PORT(DIR_CLEAR, dir_clear);
+ __PORT(INEN, inen);
+ __PORT(MUX, port_mux);
+#else
+ _buf = buf + sprintf(buf, "PORT%cIO_", num);
+ __PORT(CLEAR, data_clear);
+ __PORT(SET, data_set);
+ __PORT(TOGGLE, toggle);
+ __PORT(MASKA, maska);
+ __PORT(MASKA_CLEAR, maska_clear);
+ __PORT(MASKA_SET, maska_set);
+ __PORT(MASKA_TOGGLE, maska_toggle);
+ __PORT(MASKB, maskb);
+ __PORT(MASKB_CLEAR, maskb_clear);
+ __PORT(MASKB_SET, maskb_set);
+ __PORT(MASKB_TOGGLE, maskb_toggle);
+ __PORT(DIR, dir);
+ __PORT(POLAR, polar);
+ __PORT(EDGE, edge);
+ __PORT(BOTH, both);
+ __PORT(INEN, inen);
+#endif
+ _buf[-1] = '\0';
+ d(buf, 16, base + REGS_OFF(gpio, data));
+}
+#define PORT(base, num) bfin_debug_mmrs_port(parent, base, num)
+
+/*
+ * PPI
+ */
+#define __PPI(uname, lname) __REGS(ppi, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_ppi(struct dentry *parent, unsigned long base, int num)
+{
+ char buf[32], *_buf = REGS_STR_PFX(buf, PPI, num);
+ __PPI(CONTROL, control);
+ __PPI(STATUS, status);
+ __PPI(COUNT, count);
+ __PPI(DELAY, delay);
+ __PPI(FRAME, frame);
+}
+#define PPI(num) bfin_debug_mmrs_ppi(parent, PPI##num##_STATUS, num)
+
+/*
+ * SPI
+ */
+#define __SPI(uname, lname) __REGS(spi, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_spi(struct dentry *parent, unsigned long base, int num)
+{
+ char buf[32], *_buf = REGS_STR_PFX(buf, SPI, num);
+ __SPI(CTL, ctl);
+ __SPI(FLG, flg);
+ __SPI(STAT, stat);
+ __SPI(TDBR, tdbr);
+ __SPI(RDBR, rdbr);
+ __SPI(BAUD, baud);
+ __SPI(SHADOW, shadow);
+}
+#define SPI(num) bfin_debug_mmrs_spi(parent, SPI##num##_REGBASE, num)
+
+/*
+ * SPORT
+ */
+static inline int sport_width(void *mmr)
+{
+ unsigned long lmmr = (unsigned long)mmr;
+ if ((lmmr & 0xff) == 0x10)
+ /* SPORT#_TX has 0x10 offset -> SPORT#_TCR2 has 0x04 offset */
+ lmmr -= 0xc;
+ else
+ /* SPORT#_RX has 0x18 offset -> SPORT#_RCR2 has 0x24 offset */
+ lmmr += 0xc;
+ /* extract SLEN field from control register 2 and add 1 */
+ return (bfin_read16(lmmr) & 0x1f) + 1;
+}
+static int sport_set(void *mmr, u64 val)
+{
+ unsigned long flags;
+ local_irq_save(flags);
+ if (sport_width(mmr) <= 16)
+ bfin_write16(mmr, val);
+ else
+ bfin_write32(mmr, val);
+ local_irq_restore(flags);
+ return 0;
+}
+static int sport_get(void *mmr, u64 *val)
+{
+ unsigned long flags;
+ local_irq_save(flags);
+ if (sport_width(mmr) <= 16)
+ *val = bfin_read16(mmr);
+ else
+ *val = bfin_read32(mmr);
+ local_irq_restore(flags);
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_sport, sport_get, sport_set, "0x%08llx\n");
+/*DEFINE_SIMPLE_ATTRIBUTE(fops_sport_ro, sport_get, NULL, "0x%08llx\n");*/
+DEFINE_SIMPLE_ATTRIBUTE(fops_sport_wo, NULL, sport_set, "0x%08llx\n");
+#define SPORT_OFF(mmr) (SPORT0_##mmr - SPORT0_TCR1)
+#define _D_SPORT(name, perms, fops) \
+ do { \
+ strcpy(_buf, #name); \
+ debugfs_create_file(buf, perms, parent, (void *)(base + SPORT_OFF(name)), fops); \
+ } while (0)
+#define __SPORT_RW(name) _D_SPORT(name, S_IRUSR|S_IWUSR, &fops_sport)
+#define __SPORT_RO(name) _D_SPORT(name, S_IRUSR, &fops_sport_ro)
+#define __SPORT_WO(name) _D_SPORT(name, S_IWUSR, &fops_sport_wo)
+#define __SPORT(name, bits) \
+ do { \
+ strcpy(_buf, #name); \
+ debugfs_create_x##bits(buf, S_IRUSR|S_IWUSR, parent, (u##bits *)(base + SPORT_OFF(name))); \
+ } while (0)
+static void __init __maybe_unused
+bfin_debug_mmrs_sport(struct dentry *parent, unsigned long base, int num)
+{
+ char buf[32], *_buf = REGS_STR_PFX(buf, SPORT, num);
+ __SPORT(CHNL, 16);
+ __SPORT(MCMC1, 16);
+ __SPORT(MCMC2, 16);
+ __SPORT(MRCS0, 32);
+ __SPORT(MRCS1, 32);
+ __SPORT(MRCS2, 32);
+ __SPORT(MRCS3, 32);
+ __SPORT(MTCS0, 32);
+ __SPORT(MTCS1, 32);
+ __SPORT(MTCS2, 32);
+ __SPORT(MTCS3, 32);
+ __SPORT(RCLKDIV, 16);
+ __SPORT(RCR1, 16);
+ __SPORT(RCR2, 16);
+ __SPORT(RFSDIV, 16);
+ __SPORT_RW(RX);
+ __SPORT(STAT, 16);
+ __SPORT(TCLKDIV, 16);
+ __SPORT(TCR1, 16);
+ __SPORT(TCR2, 16);
+ __SPORT(TFSDIV, 16);
+ __SPORT_WO(TX);
+}
+#define SPORT(num) bfin_debug_mmrs_sport(parent, SPORT##num##_TCR1, num)
+
+/*
+ * TWI
+ */
+#define __TWI(uname, lname) __REGS(twi, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_twi(struct dentry *parent, unsigned long base, int num)
+{
+ char buf[32], *_buf = REGS_STR_PFX(buf, TWI, num);
+ __TWI(CLKDIV, clkdiv);
+ __TWI(CONTROL, control);
+ __TWI(SLAVE_CTL, slave_ctl);
+ __TWI(SLAVE_STAT, slave_stat);
+ __TWI(SLAVE_ADDR, slave_addr);
+ __TWI(MASTER_CTL, master_ctl);
+ __TWI(MASTER_STAT, master_stat);
+ __TWI(MASTER_ADDR, master_addr);
+ __TWI(INT_STAT, int_stat);
+ __TWI(INT_MASK, int_mask);
+ __TWI(FIFO_CTL, fifo_ctl);
+ __TWI(FIFO_STAT, fifo_stat);
+ __TWI(XMT_DATA8, xmt_data8);
+ __TWI(XMT_DATA16, xmt_data16);
+ __TWI(RCV_DATA8, rcv_data8);
+ __TWI(RCV_DATA16, rcv_data16);
+}
+#define TWI(num) bfin_debug_mmrs_twi(parent, TWI##num##_CLKDIV, num)
+
+/*
+ * UART
+ */
+#define __UART(uname, lname) __REGS(uart, #uname, lname)
+static void __init __maybe_unused
+bfin_debug_mmrs_uart(struct dentry *parent, unsigned long base, int num)
+{
+ char buf[32], *_buf = REGS_STR_PFX(buf, UART, num);
+#ifdef BFIN_UART_BF54X_STYLE
+ __UART(DLL, dll);
+ __UART(DLH, dlh);
+ __UART(GCTL, gctl);
+ __UART(LCR, lcr);
+ __UART(MCR, mcr);
+ __UART(LSR, lsr);
+ __UART(MSR, msr);
+ __UART(SCR, scr);
+ __UART(IER_SET, ier_set);
+ __UART(IER_CLEAR, ier_clear);
+ __UART(THR, thr);
+ __UART(RBR, rbr);
+#else
+ __UART(DLL, dll);
+ __UART(THR, thr);
+ __UART(RBR, rbr);
+ __UART(DLH, dlh);
+ __UART(IER, ier);
+ __UART(IIR, iir);
+ __UART(LCR, lcr);
+ __UART(MCR, mcr);
+ __UART(LSR, lsr);
+ __UART(MSR, msr);
+ __UART(SCR, scr);
+ __UART(GCTL, gctl);
+#endif
+}
+#define UART(num) bfin_debug_mmrs_uart(parent, UART##num##_DLL, num)
+
+/*
+ * The actual debugfs generation
+ */
+static struct dentry *debug_mmrs_dentry;
+
+static int __init bfin_debug_mmrs_init(void)
+{
+ struct dentry *top, *parent;
+
+ pr_info("debug-mmrs: setting up Blackfin MMR debugfs\n");
+
+ top = debugfs_create_dir("blackfin", NULL);
+ if (top == NULL)
+ return -1;
+
+ parent = debugfs_create_dir("core_regs", top);
+ debugfs_create_file("cclk", S_IRUSR, parent, NULL, &fops_debug_cclk);
+ debugfs_create_file("sclk", S_IRUSR, parent, NULL, &fops_debug_sclk);
+ debugfs_create_x32("last_seqstat", S_IRUSR, parent, &last_seqstat);
+ D_SYSREG(cycles);
+ D_SYSREG(cycles2);
+ D_SYSREG(emudat);
+ D_SYSREG(seqstat);
+ D_SYSREG(syscfg);
+
+ /* Core MMRs */
+ parent = debugfs_create_dir("ctimer", top);
+ D32(TCNTL);
+ D32(TCOUNT);
+ D32(TPERIOD);
+ D32(TSCALE);
+
+ parent = debugfs_create_dir("cec", top);
+ D32(EVT0);
+ D32(EVT1);
+ D32(EVT2);
+ D32(EVT3);
+ D32(EVT4);
+ D32(EVT5);
+ D32(EVT6);
+ D32(EVT7);
+ D32(EVT8);
+ D32(EVT9);
+ D32(EVT10);
+ D32(EVT11);
+ D32(EVT12);
+ D32(EVT13);
+ D32(EVT14);
+ D32(EVT15);
+ D32(EVT_OVERRIDE);
+ D32(IMASK);
+ D32(IPEND);
+ D32(ILAT);
+ D32(IPRIO);
+
+ parent = debugfs_create_dir("debug", top);
+ D32(DBGSTAT);
+ D32(DSPID);
+
+ parent = debugfs_create_dir("mmu", top);
+ D32(SRAM_BASE_ADDRESS);
+ D32(DCPLB_ADDR0);
+ D32(DCPLB_ADDR10);
+ D32(DCPLB_ADDR11);
+ D32(DCPLB_ADDR12);
+ D32(DCPLB_ADDR13);
+ D32(DCPLB_ADDR14);
+ D32(DCPLB_ADDR15);
+ D32(DCPLB_ADDR1);
+ D32(DCPLB_ADDR2);
+ D32(DCPLB_ADDR3);
+ D32(DCPLB_ADDR4);
+ D32(DCPLB_ADDR5);
+ D32(DCPLB_ADDR6);
+ D32(DCPLB_ADDR7);
+ D32(DCPLB_ADDR8);
+ D32(DCPLB_ADDR9);
+ D32(DCPLB_DATA0);
+ D32(DCPLB_DATA10);
+ D32(DCPLB_DATA11);
+ D32(DCPLB_DATA12);
+ D32(DCPLB_DATA13);
+ D32(DCPLB_DATA14);
+ D32(DCPLB_DATA15);
+ D32(DCPLB_DATA1);
+ D32(DCPLB_DATA2);
+ D32(DCPLB_DATA3);
+ D32(DCPLB_DATA4);
+ D32(DCPLB_DATA5);
+ D32(DCPLB_DATA6);
+ D32(DCPLB_DATA7);
+ D32(DCPLB_DATA8);
+ D32(DCPLB_DATA9);
+ D32(DCPLB_FAULT_ADDR);
+ D32(DCPLB_STATUS);
+ D32(DMEM_CONTROL);
+ D32(DTEST_COMMAND);
+ D32(DTEST_DATA0);
+ D32(DTEST_DATA1);
+
+ D32(ICPLB_ADDR0);
+ D32(ICPLB_ADDR1);
+ D32(ICPLB_ADDR2);
+ D32(ICPLB_ADDR3);
+ D32(ICPLB_ADDR4);
+ D32(ICPLB_ADDR5);
+ D32(ICPLB_ADDR6);
+ D32(ICPLB_ADDR7);
+ D32(ICPLB_ADDR8);
+ D32(ICPLB_ADDR9);
+ D32(ICPLB_ADDR10);
+ D32(ICPLB_ADDR11);
+ D32(ICPLB_ADDR12);
+ D32(ICPLB_ADDR13);
+ D32(ICPLB_ADDR14);
+ D32(ICPLB_ADDR15);
+ D32(ICPLB_DATA0);
+ D32(ICPLB_DATA1);
+ D32(ICPLB_DATA2);
+ D32(ICPLB_DATA3);
+ D32(ICPLB_DATA4);
+ D32(ICPLB_DATA5);
+ D32(ICPLB_DATA6);
+ D32(ICPLB_DATA7);
+ D32(ICPLB_DATA8);
+ D32(ICPLB_DATA9);
+ D32(ICPLB_DATA10);
+ D32(ICPLB_DATA11);
+ D32(ICPLB_DATA12);
+ D32(ICPLB_DATA13);
+ D32(ICPLB_DATA14);
+ D32(ICPLB_DATA15);
+ D32(ICPLB_FAULT_ADDR);
+ D32(ICPLB_STATUS);
+ D32(IMEM_CONTROL);
+ if (!ANOMALY_05000481) {
+ D32(ITEST_COMMAND);
+ D32(ITEST_DATA0);
+ D32(ITEST_DATA1);
+ }
+
+ parent = debugfs_create_dir("perf", top);
+ D32(PFCNTR0);
+ D32(PFCNTR1);
+ D32(PFCTL);
+
+ parent = debugfs_create_dir("trace", top);
+ D32(TBUF);
+ D32(TBUFCTL);
+ D32(TBUFSTAT);
+
+ parent = debugfs_create_dir("watchpoint", top);
+ D32(WPIACTL);
+ D32(WPIA0);
+ D32(WPIA1);
+ D32(WPIA2);
+ D32(WPIA3);
+ D32(WPIA4);
+ D32(WPIA5);
+ D32(WPIACNT0);
+ D32(WPIACNT1);
+ D32(WPIACNT2);
+ D32(WPIACNT3);
+ D32(WPIACNT4);
+ D32(WPIACNT5);
+ D32(WPDACTL);
+ D32(WPDA0);
+ D32(WPDA1);
+ D32(WPDACNT0);
+ D32(WPDACNT1);
+ D32(WPSTAT);
+
+ /* System MMRs */
+#ifdef ATAPI_CONTROL
+ parent = debugfs_create_dir("atapi", top);
+ D16(ATAPI_CONTROL);
+ D16(ATAPI_DEV_ADDR);
+ D16(ATAPI_DEV_RXBUF);
+ D16(ATAPI_DEV_TXBUF);
+ D16(ATAPI_DMA_TFRCNT);
+ D16(ATAPI_INT_MASK);
+ D16(ATAPI_INT_STATUS);
+ D16(ATAPI_LINE_STATUS);
+ D16(ATAPI_MULTI_TIM_0);
+ D16(ATAPI_MULTI_TIM_1);
+ D16(ATAPI_MULTI_TIM_2);
+ D16(ATAPI_PIO_TFRCNT);
+ D16(ATAPI_PIO_TIM_0);
+ D16(ATAPI_PIO_TIM_1);
+ D16(ATAPI_REG_TIM_0);
+ D16(ATAPI_SM_STATE);
+ D16(ATAPI_STATUS);
+ D16(ATAPI_TERMINATE);
+ D16(ATAPI_UDMAOUT_TFRCNT);
+ D16(ATAPI_ULTRA_TIM_0);
+ D16(ATAPI_ULTRA_TIM_1);
+ D16(ATAPI_ULTRA_TIM_2);
+ D16(ATAPI_ULTRA_TIM_3);
+ D16(ATAPI_UMAIN_TFRCNT);
+ D16(ATAPI_XFER_LEN);
+#endif
+
+#if defined(CAN_MC1) || defined(CAN0_MC1) || defined(CAN1_MC1)
+ parent = debugfs_create_dir("can", top);
+# ifdef CAN_MC1
+ bfin_debug_mmrs_can(parent, CAN_MC1, -1);
+# endif
+# ifdef CAN0_MC1
+ CAN(0);
+# endif
+# ifdef CAN1_MC1
+ CAN(1);
+# endif
+#endif
+
+#ifdef CNT_COMMAND
+ parent = debugfs_create_dir("counter", top);
+ D16(CNT_COMMAND);
+ D16(CNT_CONFIG);
+ D32(CNT_COUNTER);
+ D16(CNT_DEBOUNCE);
+ D16(CNT_IMASK);
+ D32(CNT_MAX);
+ D32(CNT_MIN);
+ D16(CNT_STATUS);
+#endif
+
+ parent = debugfs_create_dir("dmac", top);
+#ifdef DMA_TC_CNT
+ D16(DMAC_TC_CNT);
+ D16(DMAC_TC_PER);
+#endif
+#ifdef DMAC0_TC_CNT
+ D16(DMAC0_TC_CNT);
+ D16(DMAC0_TC_PER);
+#endif
+#ifdef DMAC1_TC_CNT
+ D16(DMAC1_TC_CNT);
+ D16(DMAC1_TC_PER);
+#endif
+#ifdef DMAC1_PERIMUX
+ D16(DMAC1_PERIMUX);
+#endif
+
+#ifdef __ADSPBF561__
+ /* XXX: should rewrite the MMR map */
+# define DMA0_NEXT_DESC_PTR DMA2_0_NEXT_DESC_PTR
+# define DMA1_NEXT_DESC_PTR DMA2_1_NEXT_DESC_PTR
+# define DMA2_NEXT_DESC_PTR DMA2_2_NEXT_DESC_PTR
+# define DMA3_NEXT_DESC_PTR DMA2_3_NEXT_DESC_PTR
+# define DMA4_NEXT_DESC_PTR DMA2_4_NEXT_DESC_PTR
+# define DMA5_NEXT_DESC_PTR DMA2_5_NEXT_DESC_PTR
+# define DMA6_NEXT_DESC_PTR DMA2_6_NEXT_DESC_PTR
+# define DMA7_NEXT_DESC_PTR DMA2_7_NEXT_DESC_PTR
+# define DMA8_NEXT_DESC_PTR DMA2_8_NEXT_DESC_PTR
+# define DMA9_NEXT_DESC_PTR DMA2_9_NEXT_DESC_PTR
+# define DMA10_NEXT_DESC_PTR DMA2_10_NEXT_DESC_PTR
+# define DMA11_NEXT_DESC_PTR DMA2_11_NEXT_DESC_PTR
+# define DMA12_NEXT_DESC_PTR DMA1_0_NEXT_DESC_PTR
+# define DMA13_NEXT_DESC_PTR DMA1_1_NEXT_DESC_PTR
+# define DMA14_NEXT_DESC_PTR DMA1_2_NEXT_DESC_PTR
+# define DMA15_NEXT_DESC_PTR DMA1_3_NEXT_DESC_PTR
+# define DMA16_NEXT_DESC_PTR DMA1_4_NEXT_DESC_PTR
+# define DMA17_NEXT_DESC_PTR DMA1_5_NEXT_DESC_PTR
+# define DMA18_NEXT_DESC_PTR DMA1_6_NEXT_DESC_PTR
+# define DMA19_NEXT_DESC_PTR DMA1_7_NEXT_DESC_PTR
+# define DMA20_NEXT_DESC_PTR DMA1_8_NEXT_DESC_PTR
+# define DMA21_NEXT_DESC_PTR DMA1_9_NEXT_DESC_PTR
+# define DMA22_NEXT_DESC_PTR DMA1_10_NEXT_DESC_PTR
+# define DMA23_NEXT_DESC_PTR DMA1_11_NEXT_DESC_PTR
+#endif
+ parent = debugfs_create_dir("dma", top);
+ DMA(0);
+ DMA(1);
+ DMA(1);
+ DMA(2);
+ DMA(3);
+ DMA(4);
+ DMA(5);
+ DMA(6);
+ DMA(7);
+#ifdef DMA8_NEXT_DESC_PTR
+ DMA(8);
+ DMA(9);
+ DMA(10);
+ DMA(11);
+#endif
+#ifdef DMA12_NEXT_DESC_PTR
+ DMA(12);
+ DMA(13);
+ DMA(14);
+ DMA(15);
+ DMA(16);
+ DMA(17);
+ DMA(18);
+ DMA(19);
+#endif
+#ifdef DMA20_NEXT_DESC_PTR
+ DMA(20);
+ DMA(21);
+ DMA(22);
+ DMA(23);
+#endif
+
+ parent = debugfs_create_dir("ebiu_amc", top);
+ D32(EBIU_AMBCTL0);
+ D32(EBIU_AMBCTL1);
+ D16(EBIU_AMGCTL);
+#ifdef EBIU_MBSCTL
+ D16(EBIU_MBSCTL);
+ D32(EBIU_ARBSTAT);
+ D32(EBIU_MODE);
+ D16(EBIU_FCTL);
+#endif
+
+#ifdef EBIU_SDGCTL
+ parent = debugfs_create_dir("ebiu_sdram", top);
+# ifdef __ADSPBF561__
+ D32(EBIU_SDBCTL);
+# else
+ D16(EBIU_SDBCTL);
+# endif
+ D32(EBIU_SDGCTL);
+ D16(EBIU_SDRRC);
+ D16(EBIU_SDSTAT);
+#endif
+
+#ifdef EBIU_DDRACCT
+ parent = debugfs_create_dir("ebiu_ddr", top);
+ D32(EBIU_DDRACCT);
+ D32(EBIU_DDRARCT);
+ D32(EBIU_DDRBRC0);
+ D32(EBIU_DDRBRC1);
+ D32(EBIU_DDRBRC2);
+ D32(EBIU_DDRBRC3);
+ D32(EBIU_DDRBRC4);
+ D32(EBIU_DDRBRC5);
+ D32(EBIU_DDRBRC6);
+ D32(EBIU_DDRBRC7);
+ D32(EBIU_DDRBWC0);
+ D32(EBIU_DDRBWC1);
+ D32(EBIU_DDRBWC2);
+ D32(EBIU_DDRBWC3);
+ D32(EBIU_DDRBWC4);
+ D32(EBIU_DDRBWC5);
+ D32(EBIU_DDRBWC6);
+ D32(EBIU_DDRBWC7);
+ D32(EBIU_DDRCTL0);
+ D32(EBIU_DDRCTL1);
+ D32(EBIU_DDRCTL2);
+ D32(EBIU_DDRCTL3);
+ D32(EBIU_DDRGC0);
+ D32(EBIU_DDRGC1);
+ D32(EBIU_DDRGC2);
+ D32(EBIU_DDRGC3);
+ D32(EBIU_DDRMCCL);
+ D32(EBIU_DDRMCEN);
+ D32(EBIU_DDRQUE);
+ D32(EBIU_DDRTACT);
+ D32(EBIU_ERRADD);
+ D16(EBIU_ERRMST);
+ D16(EBIU_RSTCTL);
+#endif
+
+#ifdef EMAC_ADDRHI
+ parent = debugfs_create_dir("emac", top);
+ D32(EMAC_ADDRHI);
+ D32(EMAC_ADDRLO);
+ D32(EMAC_FLC);
+ D32(EMAC_HASHHI);
+ D32(EMAC_HASHLO);
+ D32(EMAC_MMC_CTL);
+ D32(EMAC_MMC_RIRQE);
+ D32(EMAC_MMC_RIRQS);
+ D32(EMAC_MMC_TIRQE);
+ D32(EMAC_MMC_TIRQS);
+ D32(EMAC_OPMODE);
+ D32(EMAC_RXC_ALIGN);
+ D32(EMAC_RXC_ALLFRM);
+ D32(EMAC_RXC_ALLOCT);
+ D32(EMAC_RXC_BROAD);
+ D32(EMAC_RXC_DMAOVF);
+ D32(EMAC_RXC_EQ64);
+ D32(EMAC_RXC_FCS);
+ D32(EMAC_RXC_GE1024);
+ D32(EMAC_RXC_LNERRI);
+ D32(EMAC_RXC_LNERRO);
+ D32(EMAC_RXC_LONG);
+ D32(EMAC_RXC_LT1024);
+ D32(EMAC_RXC_LT128);
+ D32(EMAC_RXC_LT256);
+ D32(EMAC_RXC_LT512);
+ D32(EMAC_RXC_MACCTL);
+ D32(EMAC_RXC_MULTI);
+ D32(EMAC_RXC_OCTET);
+ D32(EMAC_RXC_OK);
+ D32(EMAC_RXC_OPCODE);
+ D32(EMAC_RXC_PAUSE);
+ D32(EMAC_RXC_SHORT);
+ D32(EMAC_RXC_TYPED);
+ D32(EMAC_RXC_UNICST);
+ D32(EMAC_RX_IRQE);
+ D32(EMAC_RX_STAT);
+ D32(EMAC_RX_STKY);
+ D32(EMAC_STAADD);
+ D32(EMAC_STADAT);
+ D32(EMAC_SYSCTL);
+ D32(EMAC_SYSTAT);
+ D32(EMAC_TXC_1COL);
+ D32(EMAC_TXC_ABORT);
+ D32(EMAC_TXC_ALLFRM);
+ D32(EMAC_TXC_ALLOCT);
+ D32(EMAC_TXC_BROAD);
+ D32(EMAC_TXC_CRSERR);
+ D32(EMAC_TXC_DEFER);
+ D32(EMAC_TXC_DMAUND);
+ D32(EMAC_TXC_EQ64);
+ D32(EMAC_TXC_GE1024);
+ D32(EMAC_TXC_GT1COL);
+ D32(EMAC_TXC_LATECL);
+ D32(EMAC_TXC_LT1024);
+ D32(EMAC_TXC_LT128);
+ D32(EMAC_TXC_LT256);
+ D32(EMAC_TXC_LT512);
+ D32(EMAC_TXC_MACCTL);
+ D32(EMAC_TXC_MULTI);
+ D32(EMAC_TXC_OCTET);
+ D32(EMAC_TXC_OK);
+ D32(EMAC_TXC_UNICST);
+ D32(EMAC_TXC_XS_COL);
+ D32(EMAC_TXC_XS_DFR);
+ D32(EMAC_TX_IRQE);
+ D32(EMAC_TX_STAT);
+ D32(EMAC_TX_STKY);
+ D32(EMAC_VLAN1);
+ D32(EMAC_VLAN2);
+ D32(EMAC_WKUP_CTL);
+ D32(EMAC_WKUP_FFCMD);
+ D32(EMAC_WKUP_FFCRC0);
+ D32(EMAC_WKUP_FFCRC1);
+ D32(EMAC_WKUP_FFMSK0);
+ D32(EMAC_WKUP_FFMSK1);
+ D32(EMAC_WKUP_FFMSK2);
+ D32(EMAC_WKUP_FFMSK3);
+ D32(EMAC_WKUP_FFOFF);
+# ifdef EMAC_PTP_ACCR
+ D32(EMAC_PTP_ACCR);
+ D32(EMAC_PTP_ADDEND);
+ D32(EMAC_PTP_ALARMHI);
+ D32(EMAC_PTP_ALARMLO);
+ D16(EMAC_PTP_CTL);
+ D32(EMAC_PTP_FOFF);
+ D32(EMAC_PTP_FV1);
+ D32(EMAC_PTP_FV2);
+ D32(EMAC_PTP_FV3);
+ D16(EMAC_PTP_ID_OFF);
+ D32(EMAC_PTP_ID_SNAP);
+ D16(EMAC_PTP_IE);
+ D16(EMAC_PTP_ISTAT);
+ D32(EMAC_PTP_OFFSET);
+ D32(EMAC_PTP_PPS_PERIOD);
+ D32(EMAC_PTP_PPS_STARTHI);
+ D32(EMAC_PTP_PPS_STARTLO);
+ D32(EMAC_PTP_RXSNAPHI);
+ D32(EMAC_PTP_RXSNAPLO);
+ D32(EMAC_PTP_TIMEHI);
+ D32(EMAC_PTP_TIMELO);
+ D32(EMAC_PTP_TXSNAPHI);
+ D32(EMAC_PTP_TXSNAPLO);
+# endif
+#endif
+
+#if defined(EPPI0_STATUS) || defined(EPPI1_STATUS) || defined(EPPI2_STATUS)
+ parent = debugfs_create_dir("eppi", top);
+# ifdef EPPI0_STATUS
+ EPPI(0);
+# endif
+# ifdef EPPI1_STATUS
+ EPPI(1);
+# endif
+# ifdef EPPI2_STATUS
+ EPPI(2);
+# endif
+#endif
+
+ parent = debugfs_create_dir("gptimer", top);
+#ifdef TIMER_DISABLE
+ D16(TIMER_DISABLE);
+ D16(TIMER_ENABLE);
+ D32(TIMER_STATUS);
+#endif
+#ifdef TIMER_DISABLE0
+ D16(TIMER_DISABLE0);
+ D16(TIMER_ENABLE0);
+ D32(TIMER_STATUS0);
+#endif
+#ifdef TIMER_DISABLE1
+ D16(TIMER_DISABLE1);
+ D16(TIMER_ENABLE1);
+ D32(TIMER_STATUS1);
+#endif
+ /* XXX: Should convert BF561 MMR names */
+#ifdef TMRS4_DISABLE
+ D16(TMRS4_DISABLE);
+ D16(TMRS4_ENABLE);
+ D32(TMRS4_STATUS);
+ D16(TMRS8_DISABLE);
+ D16(TMRS8_ENABLE);
+ D32(TMRS8_STATUS);
+#endif
+ GPTIMER(0);
+ GPTIMER(1);
+ GPTIMER(2);
+#ifdef TIMER3_CONFIG
+ GPTIMER(3);
+ GPTIMER(4);
+ GPTIMER(5);
+ GPTIMER(6);
+ GPTIMER(7);
+#endif
+#ifdef TIMER8_CONFIG
+ GPTIMER(8);
+ GPTIMER(9);
+ GPTIMER(10);
+#endif
+#ifdef TIMER11_CONFIG
+ GPTIMER(11);
+#endif
+
+#ifdef HMDMA0_CONTROL
+ parent = debugfs_create_dir("hmdma", top);
+ HMDMA(0);
+ HMDMA(1);
+#endif
+
+#ifdef HOST_CONTROL
+ parent = debugfs_create_dir("hostdp", top);
+ D16(HOST_CONTROL);
+ D16(HOST_STATUS);
+ D16(HOST_TIMEOUT);
+#endif
+
+#ifdef IMDMA_S0_CONFIG
+ parent = debugfs_create_dir("imdma", top);
+ IMDMA(0);
+ IMDMA(1);
+#endif
+
+#ifdef KPAD_CTL
+ parent = debugfs_create_dir("keypad", top);
+ D16(KPAD_CTL);
+ D16(KPAD_PRESCALE);
+ D16(KPAD_MSEL);
+ D16(KPAD_ROWCOL);
+ D16(KPAD_STAT);
+ D16(KPAD_SOFTEVAL);
+#endif
+
+ parent = debugfs_create_dir("mdma", top);
+ MDMA(0);
+ MDMA(1);
+#ifdef MDMA_D2_CONFIG
+ MDMA(2);
+ MDMA(3);
+#endif
+
+#ifdef MXVR_CONFIG
+ parent = debugfs_create_dir("mxvr", top);
+ D16(MXVR_CONFIG);
+# ifdef MXVR_PLL_CTL_0
+ D32(MXVR_PLL_CTL_0);
+# endif
+ D32(MXVR_STATE_0);
+ D32(MXVR_STATE_1);
+ D32(MXVR_INT_STAT_0);
+ D32(MXVR_INT_STAT_1);
+ D32(MXVR_INT_EN_0);
+ D32(MXVR_INT_EN_1);
+ D16(MXVR_POSITION);
+ D16(MXVR_MAX_POSITION);
+ D16(MXVR_DELAY);
+ D16(MXVR_MAX_DELAY);
+ D32(MXVR_LADDR);
+ D16(MXVR_GADDR);
+ D32(MXVR_AADDR);
+ D32(MXVR_ALLOC_0);
+ D32(MXVR_ALLOC_1);
+ D32(MXVR_ALLOC_2);
+ D32(MXVR_ALLOC_3);
+ D32(MXVR_ALLOC_4);
+ D32(MXVR_ALLOC_5);
+ D32(MXVR_ALLOC_6);
+ D32(MXVR_ALLOC_7);
+ D32(MXVR_ALLOC_8);
+ D32(MXVR_ALLOC_9);
+ D32(MXVR_ALLOC_10);
+ D32(MXVR_ALLOC_11);
+ D32(MXVR_ALLOC_12);
+ D32(MXVR_ALLOC_13);
+ D32(MXVR_ALLOC_14);
+ D32(MXVR_SYNC_LCHAN_0);
+ D32(MXVR_SYNC_LCHAN_1);
+ D32(MXVR_SYNC_LCHAN_2);
+ D32(MXVR_SYNC_LCHAN_3);
+ D32(MXVR_SYNC_LCHAN_4);
+ D32(MXVR_SYNC_LCHAN_5);
+ D32(MXVR_SYNC_LCHAN_6);
+ D32(MXVR_SYNC_LCHAN_7);
+ D32(MXVR_DMA0_CONFIG);
+ D32(MXVR_DMA0_START_ADDR);
+ D16(MXVR_DMA0_COUNT);
+ D32(MXVR_DMA0_CURR_ADDR);
+ D16(MXVR_DMA0_CURR_COUNT);
+ D32(MXVR_DMA1_CONFIG);
+ D32(MXVR_DMA1_START_ADDR);
+ D16(MXVR_DMA1_COUNT);
+ D32(MXVR_DMA1_CURR_ADDR);
+ D16(MXVR_DMA1_CURR_COUNT);
+ D32(MXVR_DMA2_CONFIG);
+ D32(MXVR_DMA2_START_ADDR);
+ D16(MXVR_DMA2_COUNT);
+ D32(MXVR_DMA2_CURR_ADDR);
+ D16(MXVR_DMA2_CURR_COUNT);
+ D32(MXVR_DMA3_CONFIG);
+ D32(MXVR_DMA3_START_ADDR);
+ D16(MXVR_DMA3_COUNT);
+ D32(MXVR_DMA3_CURR_ADDR);
+ D16(MXVR_DMA3_CURR_COUNT);
+ D32(MXVR_DMA4_CONFIG);
+ D32(MXVR_DMA4_START_ADDR);
+ D16(MXVR_DMA4_COUNT);
+ D32(MXVR_DMA4_CURR_ADDR);
+ D16(MXVR_DMA4_CURR_COUNT);
+ D32(MXVR_DMA5_CONFIG);
+ D32(MXVR_DMA5_START_ADDR);
+ D16(MXVR_DMA5_COUNT);
+ D32(MXVR_DMA5_CURR_ADDR);
+ D16(MXVR_DMA5_CURR_COUNT);
+ D32(MXVR_DMA6_CONFIG);
+ D32(MXVR_DMA6_START_ADDR);
+ D16(MXVR_DMA6_COUNT);
+ D32(MXVR_DMA6_CURR_ADDR);
+ D16(MXVR_DMA6_CURR_COUNT);
+ D32(MXVR_DMA7_CONFIG);
+ D32(MXVR_DMA7_START_ADDR);
+ D16(MXVR_DMA7_COUNT);
+ D32(MXVR_DMA7_CURR_ADDR);
+ D16(MXVR_DMA7_CURR_COUNT);
+ D16(MXVR_AP_CTL);
+ D32(MXVR_APRB_START_ADDR);
+ D32(MXVR_APRB_CURR_ADDR);
+ D32(MXVR_APTB_START_ADDR);
+ D32(MXVR_APTB_CURR_ADDR);
+ D32(MXVR_CM_CTL);
+ D32(MXVR_CMRB_START_ADDR);
+ D32(MXVR_CMRB_CURR_ADDR);
+ D32(MXVR_CMTB_START_ADDR);
+ D32(MXVR_CMTB_CURR_ADDR);
+ D32(MXVR_RRDB_START_ADDR);
+ D32(MXVR_RRDB_CURR_ADDR);
+ D32(MXVR_PAT_DATA_0);
+ D32(MXVR_PAT_EN_0);
+ D32(MXVR_PAT_DATA_1);
+ D32(MXVR_PAT_EN_1);
+ D16(MXVR_FRAME_CNT_0);
+ D16(MXVR_FRAME_CNT_1);
+ D32(MXVR_ROUTING_0);
+ D32(MXVR_ROUTING_1);
+ D32(MXVR_ROUTING_2);
+ D32(MXVR_ROUTING_3);
+ D32(MXVR_ROUTING_4);
+ D32(MXVR_ROUTING_5);
+ D32(MXVR_ROUTING_6);
+ D32(MXVR_ROUTING_7);
+ D32(MXVR_ROUTING_8);
+ D32(MXVR_ROUTING_9);
+ D32(MXVR_ROUTING_10);
+ D32(MXVR_ROUTING_11);
+ D32(MXVR_ROUTING_12);
+ D32(MXVR_ROUTING_13);
+ D32(MXVR_ROUTING_14);
+# ifdef MXVR_PLL_CTL_1
+ D32(MXVR_PLL_CTL_1);
+# endif
+ D16(MXVR_BLOCK_CNT);
+# ifdef MXVR_CLK_CTL
+ D32(MXVR_CLK_CTL);
+# endif
+# ifdef MXVR_CDRPLL_CTL
+ D32(MXVR_CDRPLL_CTL);
+# endif
+# ifdef MXVR_FMPLL_CTL
+ D32(MXVR_FMPLL_CTL);
+# endif
+# ifdef MXVR_PIN_CTL
+ D16(MXVR_PIN_CTL);
+# endif
+# ifdef MXVR_SCLK_CNT
+ D16(MXVR_SCLK_CNT);
+# endif
+#endif
+
+#ifdef NFC_ADDR
+ parent = debugfs_create_dir("nfc", top);
+ D_WO(NFC_ADDR, 16);
+ D_WO(NFC_CMD, 16);
+ D_RO(NFC_COUNT, 16);
+ D16(NFC_CTL);
+ D_WO(NFC_DATA_RD, 16);
+ D_WO(NFC_DATA_WR, 16);
+ D_RO(NFC_ECC0, 16);
+ D_RO(NFC_ECC1, 16);
+ D_RO(NFC_ECC2, 16);
+ D_RO(NFC_ECC3, 16);
+ D16(NFC_IRQMASK);
+ D16(NFC_IRQSTAT);
+ D_WO(NFC_PGCTL, 16);
+ D_RO(NFC_READ, 16);
+ D16(NFC_RST);
+ D_RO(NFC_STAT, 16);
+#endif
+
+#ifdef OTP_CONTROL
+ parent = debugfs_create_dir("otp", top);
+ D16(OTP_CONTROL);
+ D16(OTP_BEN);
+ D16(OTP_STATUS);
+ D32(OTP_TIMING);
+ D32(OTP_DATA0);
+ D32(OTP_DATA1);
+ D32(OTP_DATA2);
+ D32(OTP_DATA3);
+#endif
+
+#ifdef PIXC_CTL
+ parent = debugfs_create_dir("pixc", top);
+ D16(PIXC_CTL);
+ D16(PIXC_PPL);
+ D16(PIXC_LPF);
+ D16(PIXC_AHSTART);
+ D16(PIXC_AHEND);
+ D16(PIXC_AVSTART);
+ D16(PIXC_AVEND);
+ D16(PIXC_ATRANSP);
+ D16(PIXC_BHSTART);
+ D16(PIXC_BHEND);
+ D16(PIXC_BVSTART);
+ D16(PIXC_BVEND);
+ D16(PIXC_BTRANSP);
+ D16(PIXC_INTRSTAT);
+ D32(PIXC_RYCON);
+ D32(PIXC_GUCON);
+ D32(PIXC_BVCON);
+ D32(PIXC_CCBIAS);
+ D32(PIXC_TC);
+#endif
+
+ parent = debugfs_create_dir("pll", top);
+ D16(PLL_CTL);
+ D16(PLL_DIV);
+ D16(PLL_LOCKCNT);
+ D16(PLL_STAT);
+ D16(VR_CTL);
+ D32(CHIPID); /* it's part of this hardware block */
+
+#if defined(PPI_STATUS) || defined(PPI0_STATUS) || defined(PPI1_STATUS)
+ parent = debugfs_create_dir("ppi", top);
+# ifdef PPI_STATUS
+ bfin_debug_mmrs_ppi(parent, PPI_STATUS, -1);
+# endif
+# ifdef PPI0_STATUS
+ PPI(0);
+# endif
+# ifdef PPI1_STATUS
+ PPI(1);
+# endif
+#endif
+
+#ifdef PWM_CTRL
+ parent = debugfs_create_dir("pwm", top);
+ D16(PWM_CTRL);
+ D16(PWM_STAT);
+ D16(PWM_TM);
+ D16(PWM_DT);
+ D16(PWM_GATE);
+ D16(PWM_CHA);
+ D16(PWM_CHB);
+ D16(PWM_CHC);
+ D16(PWM_SEG);
+ D16(PWM_SYNCWT);
+ D16(PWM_CHAL);
+ D16(PWM_CHBL);
+ D16(PWM_CHCL);
+ D16(PWM_LSI);
+ D16(PWM_STAT2);
+#endif
+
+#ifdef RSI_CONFIG
+ parent = debugfs_create_dir("rsi", top);
+ D32(RSI_ARGUMENT);
+ D16(RSI_CEATA_CONTROL);
+ D16(RSI_CLK_CONTROL);
+ D16(RSI_COMMAND);
+ D16(RSI_CONFIG);
+ D16(RSI_DATA_CNT);
+ D16(RSI_DATA_CONTROL);
+ D16(RSI_DATA_LGTH);
+ D32(RSI_DATA_TIMER);
+ D16(RSI_EMASK);
+ D16(RSI_ESTAT);
+ D32(RSI_FIFO);
+ D16(RSI_FIFO_CNT);
+ D32(RSI_MASK0);
+ D32(RSI_MASK1);
+ D16(RSI_PID0);
+ D16(RSI_PID1);
+ D16(RSI_PID2);
+ D16(RSI_PID3);
+ D16(RSI_PWR_CONTROL);
+ D16(RSI_RD_WAIT_EN);
+ D32(RSI_RESPONSE0);
+ D32(RSI_RESPONSE1);
+ D32(RSI_RESPONSE2);
+ D32(RSI_RESPONSE3);
+ D16(RSI_RESP_CMD);
+ D32(RSI_STATUS);
+ D_WO(RSI_STATUSCL, 16);
+#endif
+
+#ifdef RTC_ALARM
+ parent = debugfs_create_dir("rtc", top);
+ D32(RTC_ALARM);
+ D16(RTC_ICTL);
+ D16(RTC_ISTAT);
+ D16(RTC_PREN);
+ D32(RTC_STAT);
+ D16(RTC_SWCNT);
+#endif
+
+#ifdef SDH_CFG
+ parent = debugfs_create_dir("sdh", top);
+ D32(SDH_ARGUMENT);
+ D16(SDH_CFG);
+ D16(SDH_CLK_CTL);
+ D16(SDH_COMMAND);
+ D_RO(SDH_DATA_CNT, 16);
+ D16(SDH_DATA_CTL);
+ D16(SDH_DATA_LGTH);
+ D32(SDH_DATA_TIMER);
+ D16(SDH_E_MASK);
+ D16(SDH_E_STATUS);
+ D32(SDH_FIFO);
+ D_RO(SDH_FIFO_CNT, 16);
+ D32(SDH_MASK0);
+ D32(SDH_MASK1);
+ D_RO(SDH_PID0, 16);
+ D_RO(SDH_PID1, 16);
+ D_RO(SDH_PID2, 16);
+ D_RO(SDH_PID3, 16);
+ D_RO(SDH_PID4, 16);
+ D_RO(SDH_PID5, 16);
+ D_RO(SDH_PID6, 16);
+ D_RO(SDH_PID7, 16);
+ D16(SDH_PWR_CTL);
+ D16(SDH_RD_WAIT_EN);
+ D_RO(SDH_RESPONSE0, 32);
+ D_RO(SDH_RESPONSE1, 32);
+ D_RO(SDH_RESPONSE2, 32);
+ D_RO(SDH_RESPONSE3, 32);
+ D_RO(SDH_RESP_CMD, 16);
+ D_RO(SDH_STATUS, 32);
+ D_WO(SDH_STATUS_CLR, 16);
+#endif
+
+#ifdef SECURE_CONTROL
+ parent = debugfs_create_dir("security", top);
+ D16(SECURE_CONTROL);
+ D16(SECURE_STATUS);
+ D32(SECURE_SYSSWT);
+#endif
+
+ parent = debugfs_create_dir("sic", top);
+ D16(SWRST);
+ D16(SYSCR);
+ D16(SIC_RVECT);
+ D32(SIC_IAR0);
+ D32(SIC_IAR1);
+ D32(SIC_IAR2);
+#ifdef SIC_IAR3
+ D32(SIC_IAR3);
+#endif
+#ifdef SIC_IAR4
+ D32(SIC_IAR4);
+ D32(SIC_IAR5);
+ D32(SIC_IAR6);
+#endif
+#ifdef SIC_IAR7
+ D32(SIC_IAR7);
+#endif
+#ifdef SIC_IAR8
+ D32(SIC_IAR8);
+ D32(SIC_IAR9);
+ D32(SIC_IAR10);
+ D32(SIC_IAR11);
+#endif
+#ifdef SIC_IMASK
+ D32(SIC_IMASK);
+ D32(SIC_ISR);
+ D32(SIC_IWR);
+#endif
+#ifdef SIC_IMASK0
+ D32(SIC_IMASK0);
+ D32(SIC_IMASK1);
+ D32(SIC_ISR0);
+ D32(SIC_ISR1);
+ D32(SIC_IWR0);
+ D32(SIC_IWR1);
+#endif
+#ifdef SIC_IMASK2
+ D32(SIC_IMASK2);
+ D32(SIC_ISR2);
+ D32(SIC_IWR2);
+#endif
+#ifdef SICB_RVECT
+ D16(SICB_SWRST);
+ D16(SICB_SYSCR);
+ D16(SICB_RVECT);
+ D32(SICB_IAR0);
+ D32(SICB_IAR1);
+ D32(SICB_IAR2);
+ D32(SICB_IAR3);
+ D32(SICB_IAR4);
+ D32(SICB_IAR5);
+ D32(SICB_IAR6);
+ D32(SICB_IAR7);
+ D32(SICB_IMASK0);
+ D32(SICB_IMASK1);
+ D32(SICB_ISR0);
+ D32(SICB_ISR1);
+ D32(SICB_IWR0);
+ D32(SICB_IWR1);
+#endif
+
+ parent = debugfs_create_dir("spi", top);
+#ifdef SPI0_REGBASE
+ SPI(0);
+#endif
+#ifdef SPI1_REGBASE
+ SPI(1);
+#endif
+#ifdef SPI2_REGBASE
+ SPI(2);
+#endif
+
+ parent = debugfs_create_dir("sport", top);
+#ifdef SPORT0_STAT
+ SPORT(0);
+#endif
+#ifdef SPORT1_STAT
+ SPORT(1);
+#endif
+#ifdef SPORT2_STAT
+ SPORT(2);
+#endif
+#ifdef SPORT3_STAT
+ SPORT(3);
+#endif
+
+#if defined(TWI_CLKDIV) || defined(TWI0_CLKDIV) || defined(TWI1_CLKDIV)
+ parent = debugfs_create_dir("twi", top);
+# ifdef TWI_CLKDIV
+ bfin_debug_mmrs_twi(parent, TWI_CLKDIV, -1);
+# endif
+# ifdef TWI0_CLKDIV
+ TWI(0);
+# endif
+# ifdef TWI1_CLKDIV
+ TWI(1);
+# endif
+#endif
+
+ parent = debugfs_create_dir("uart", top);
+#ifdef BFIN_UART_DLL
+ bfin_debug_mmrs_uart(parent, BFIN_UART_DLL, -1);
+#endif
+#ifdef UART0_DLL
+ UART(0);
+#endif
+#ifdef UART1_DLL
+ UART(1);
+#endif
+#ifdef UART2_DLL
+ UART(2);
+#endif
+#ifdef UART3_DLL
+ UART(3);
+#endif
+
+#ifdef USB_FADDR
+ parent = debugfs_create_dir("usb", top);
+ D16(USB_FADDR);
+ D16(USB_POWER);
+ D16(USB_INTRTX);
+ D16(USB_INTRRX);
+ D16(USB_INTRTXE);
+ D16(USB_INTRRXE);
+ D16(USB_INTRUSB);
+ D16(USB_INTRUSBE);
+ D16(USB_FRAME);
+ D16(USB_INDEX);
+ D16(USB_TESTMODE);
+ D16(USB_GLOBINTR);
+ D16(USB_GLOBAL_CTL);
+ D16(USB_TX_MAX_PACKET);
+ D16(USB_CSR0);
+ D16(USB_TXCSR);
+ D16(USB_RX_MAX_PACKET);
+ D16(USB_RXCSR);
+ D16(USB_COUNT0);
+ D16(USB_RXCOUNT);
+ D16(USB_TXTYPE);
+ D16(USB_NAKLIMIT0);
+ D16(USB_TXINTERVAL);
+ D16(USB_RXTYPE);
+ D16(USB_RXINTERVAL);
+ D16(USB_TXCOUNT);
+ D16(USB_EP0_FIFO);
+ D16(USB_EP1_FIFO);
+ D16(USB_EP2_FIFO);
+ D16(USB_EP3_FIFO);
+ D16(USB_EP4_FIFO);
+ D16(USB_EP5_FIFO);
+ D16(USB_EP6_FIFO);
+ D16(USB_EP7_FIFO);
+ D16(USB_OTG_DEV_CTL);
+ D16(USB_OTG_VBUS_IRQ);
+ D16(USB_OTG_VBUS_MASK);
+ D16(USB_LINKINFO);
+ D16(USB_VPLEN);
+ D16(USB_HS_EOF1);
+ D16(USB_FS_EOF1);
+ D16(USB_LS_EOF1);
+ D16(USB_APHY_CNTRL);
+ D16(USB_APHY_CALIB);
+ D16(USB_APHY_CNTRL2);
+ D16(USB_PHY_TEST);
+ D16(USB_PLLOSC_CTRL);
+ D16(USB_SRP_CLKDIV);
+ D16(USB_EP_NI0_TXMAXP);
+ D16(USB_EP_NI0_TXCSR);
+ D16(USB_EP_NI0_RXMAXP);
+ D16(USB_EP_NI0_RXCSR);
+ D16(USB_EP_NI0_RXCOUNT);
+ D16(USB_EP_NI0_TXTYPE);
+ D16(USB_EP_NI0_TXINTERVAL);
+ D16(USB_EP_NI0_RXTYPE);
+ D16(USB_EP_NI0_RXINTERVAL);
+ D16(USB_EP_NI0_TXCOUNT);
+ D16(USB_EP_NI1_TXMAXP);
+ D16(USB_EP_NI1_TXCSR);
+ D16(USB_EP_NI1_RXMAXP);
+ D16(USB_EP_NI1_RXCSR);
+ D16(USB_EP_NI1_RXCOUNT);
+ D16(USB_EP_NI1_TXTYPE);
+ D16(USB_EP_NI1_TXINTERVAL);
+ D16(USB_EP_NI1_RXTYPE);
+ D16(USB_EP_NI1_RXINTERVAL);
+ D16(USB_EP_NI1_TXCOUNT);
+ D16(USB_EP_NI2_TXMAXP);
+ D16(USB_EP_NI2_TXCSR);
+ D16(USB_EP_NI2_RXMAXP);
+ D16(USB_EP_NI2_RXCSR);
+ D16(USB_EP_NI2_RXCOUNT);
+ D16(USB_EP_NI2_TXTYPE);
+ D16(USB_EP_NI2_TXINTERVAL);
+ D16(USB_EP_NI2_RXTYPE);
+ D16(USB_EP_NI2_RXINTERVAL);
+ D16(USB_EP_NI2_TXCOUNT);
+ D16(USB_EP_NI3_TXMAXP);
+ D16(USB_EP_NI3_TXCSR);
+ D16(USB_EP_NI3_RXMAXP);
+ D16(USB_EP_NI3_RXCSR);
+ D16(USB_EP_NI3_RXCOUNT);
+ D16(USB_EP_NI3_TXTYPE);
+ D16(USB_EP_NI3_TXINTERVAL);
+ D16(USB_EP_NI3_RXTYPE);
+ D16(USB_EP_NI3_RXINTERVAL);
+ D16(USB_EP_NI3_TXCOUNT);
+ D16(USB_EP_NI4_TXMAXP);
+ D16(USB_EP_NI4_TXCSR);
+ D16(USB_EP_NI4_RXMAXP);
+ D16(USB_EP_NI4_RXCSR);
+ D16(USB_EP_NI4_RXCOUNT);
+ D16(USB_EP_NI4_TXTYPE);
+ D16(USB_EP_NI4_TXINTERVAL);
+ D16(USB_EP_NI4_RXTYPE);
+ D16(USB_EP_NI4_RXINTERVAL);
+ D16(USB_EP_NI4_TXCOUNT);
+ D16(USB_EP_NI5_TXMAXP);
+ D16(USB_EP_NI5_TXCSR);
+ D16(USB_EP_NI5_RXMAXP);
+ D16(USB_EP_NI5_RXCSR);
+ D16(USB_EP_NI5_RXCOUNT);
+ D16(USB_EP_NI5_TXTYPE);
+ D16(USB_EP_NI5_TXINTERVAL);
+ D16(USB_EP_NI5_RXTYPE);
+ D16(USB_EP_NI5_RXINTERVAL);
+ D16(USB_EP_NI5_TXCOUNT);
+ D16(USB_EP_NI6_TXMAXP);
+ D16(USB_EP_NI6_TXCSR);
+ D16(USB_EP_NI6_RXMAXP);
+ D16(USB_EP_NI6_RXCSR);
+ D16(USB_EP_NI6_RXCOUNT);
+ D16(USB_EP_NI6_TXTYPE);
+ D16(USB_EP_NI6_TXINTERVAL);
+ D16(USB_EP_NI6_RXTYPE);
+ D16(USB_EP_NI6_RXINTERVAL);
+ D16(USB_EP_NI6_TXCOUNT);
+ D16(USB_EP_NI7_TXMAXP);
+ D16(USB_EP_NI7_TXCSR);
+ D16(USB_EP_NI7_RXMAXP);
+ D16(USB_EP_NI7_RXCSR);
+ D16(USB_EP_NI7_RXCOUNT);
+ D16(USB_EP_NI7_TXTYPE);
+ D16(USB_EP_NI7_TXINTERVAL);
+ D16(USB_EP_NI7_RXTYPE);
+ D16(USB_EP_NI7_RXINTERVAL);
+ D16(USB_EP_NI7_TXCOUNT);
+ D16(USB_DMA_INTERRUPT);
+ D16(USB_DMA0CONTROL);
+ D16(USB_DMA0ADDRLOW);
+ D16(USB_DMA0ADDRHIGH);
+ D16(USB_DMA0COUNTLOW);
+ D16(USB_DMA0COUNTHIGH);
+ D16(USB_DMA1CONTROL);
+ D16(USB_DMA1ADDRLOW);
+ D16(USB_DMA1ADDRHIGH);
+ D16(USB_DMA1COUNTLOW);
+ D16(USB_DMA1COUNTHIGH);
+ D16(USB_DMA2CONTROL);
+ D16(USB_DMA2ADDRLOW);
+ D16(USB_DMA2ADDRHIGH);
+ D16(USB_DMA2COUNTLOW);
+ D16(USB_DMA2COUNTHIGH);
+ D16(USB_DMA3CONTROL);
+ D16(USB_DMA3ADDRLOW);
+ D16(USB_DMA3ADDRHIGH);
+ D16(USB_DMA3COUNTLOW);
+ D16(USB_DMA3COUNTHIGH);
+ D16(USB_DMA4CONTROL);
+ D16(USB_DMA4ADDRLOW);
+ D16(USB_DMA4ADDRHIGH);
+ D16(USB_DMA4COUNTLOW);
+ D16(USB_DMA4COUNTHIGH);
+ D16(USB_DMA5CONTROL);
+ D16(USB_DMA5ADDRLOW);
+ D16(USB_DMA5ADDRHIGH);
+ D16(USB_DMA5COUNTLOW);
+ D16(USB_DMA5COUNTHIGH);
+ D16(USB_DMA6CONTROL);
+ D16(USB_DMA6ADDRLOW);
+ D16(USB_DMA6ADDRHIGH);
+ D16(USB_DMA6COUNTLOW);
+ D16(USB_DMA6COUNTHIGH);
+ D16(USB_DMA7CONTROL);
+ D16(USB_DMA7ADDRLOW);
+ D16(USB_DMA7ADDRHIGH);
+ D16(USB_DMA7COUNTLOW);
+ D16(USB_DMA7COUNTHIGH);
+#endif
+
+#ifdef WDOG_CNT
+ parent = debugfs_create_dir("watchdog", top);
+ D32(WDOG_CNT);
+ D16(WDOG_CTL);
+ D32(WDOG_STAT);
+#endif
+#ifdef WDOGA_CNT
+ parent = debugfs_create_dir("watchdog", top);
+ D32(WDOGA_CNT);
+ D16(WDOGA_CTL);
+ D32(WDOGA_STAT);
+ D32(WDOGB_CNT);
+ D16(WDOGB_CTL);
+ D32(WDOGB_STAT);
+#endif
+
+ /* BF533 glue */
+#ifdef FIO_FLAG_D
+#define PORTFIO FIO_FLAG_D
+#endif
+ /* BF561 glue */
+#ifdef FIO0_FLAG_D
+#define PORTFIO FIO0_FLAG_D
+#endif
+#ifdef FIO1_FLAG_D
+#define PORTGIO FIO1_FLAG_D
+#endif
+#ifdef FIO2_FLAG_D
+#define PORTHIO FIO2_FLAG_D
+#endif
+ parent = debugfs_create_dir("port", top);
+#ifdef PORTFIO
+ PORT(PORTFIO, 'F');
+#endif
+#ifdef PORTGIO
+ PORT(PORTGIO, 'G');
+#endif
+#ifdef PORTHIO
+ PORT(PORTHIO, 'H');
+#endif
+
+#ifdef __ADSPBF51x__
+ D16(PORTF_FER);
+ D16(PORTF_DRIVE);
+ D16(PORTF_HYSTERESIS);
+ D16(PORTF_MUX);
+
+ D16(PORTG_FER);
+ D16(PORTG_DRIVE);
+ D16(PORTG_HYSTERESIS);
+ D16(PORTG_MUX);
+
+ D16(PORTH_FER);
+ D16(PORTH_DRIVE);
+ D16(PORTH_HYSTERESIS);
+ D16(PORTH_MUX);
+
+ D16(MISCPORT_DRIVE);
+ D16(MISCPORT_HYSTERESIS);
+#endif /* BF51x */
+
+#ifdef __ADSPBF52x__
+ D16(PORTF_FER);
+ D16(PORTF_DRIVE);
+ D16(PORTF_HYSTERESIS);
+ D16(PORTF_MUX);
+ D16(PORTF_SLEW);
+
+ D16(PORTG_FER);
+ D16(PORTG_DRIVE);
+ D16(PORTG_HYSTERESIS);
+ D16(PORTG_MUX);
+ D16(PORTG_SLEW);
+
+ D16(PORTH_FER);
+ D16(PORTH_DRIVE);
+ D16(PORTH_HYSTERESIS);
+ D16(PORTH_MUX);
+ D16(PORTH_SLEW);
+
+ D16(MISCPORT_DRIVE);
+ D16(MISCPORT_HYSTERESIS);
+ D16(MISCPORT_SLEW);
+#endif /* BF52x */
+
+#ifdef BF537_FAMILY
+ D16(PORTF_FER);
+ D16(PORTG_FER);
+ D16(PORTH_FER);
+ D16(PORT_MUX);
+#endif /* BF534 BF536 BF537 */
+
+#ifdef BF538_FAMILY
+ D16(PORTCIO_FER);
+ D16(PORTCIO);
+ D16(PORTCIO_CLEAR);
+ D16(PORTCIO_SET);
+ D16(PORTCIO_TOGGLE);
+ D16(PORTCIO_DIR);
+ D16(PORTCIO_INEN);
+
+ D16(PORTDIO);
+ D16(PORTDIO_CLEAR);
+ D16(PORTDIO_DIR);
+ D16(PORTDIO_FER);
+ D16(PORTDIO_INEN);
+ D16(PORTDIO_SET);
+ D16(PORTDIO_TOGGLE);
+
+ D16(PORTEIO);
+ D16(PORTEIO_CLEAR);
+ D16(PORTEIO_DIR);
+ D16(PORTEIO_FER);
+ D16(PORTEIO_INEN);
+ D16(PORTEIO_SET);
+ D16(PORTEIO_TOGGLE);
+#endif /* BF538 BF539 */
+
+#ifdef __ADSPBF54x__
+ {
+ int num;
+ unsigned long base;
+ char *_buf, buf[32];
+
+ base = PORTA_FER;
+ for (num = 0; num < 10; ++num) {
+ PORT(base, num);
+ base += sizeof(struct bfin_gpio_regs);
+ }
+
+#define __PINT(uname, lname) __REGS(pint, #uname, lname)
+ parent = debugfs_create_dir("pint", top);
+ base = PINT0_MASK_SET;
+ for (num = 0; num < 4; ++num) {
+ _buf = REGS_STR_PFX(buf, PINT, num);
+ __PINT(MASK_SET, mask_set);
+ __PINT(MASK_CLEAR, mask_clear);
+ __PINT(IRQ, irq);
+ __PINT(ASSIGN, assign);
+ __PINT(EDGE_SET, edge_set);
+ __PINT(EDGE_CLEAR, edge_clear);
+ __PINT(INVERT_SET, invert_set);
+ __PINT(INVERT_CLEAR, invert_clear);
+ __PINT(PINSTATE, pinstate);
+ __PINT(LATCH, latch);
+ base += sizeof(struct bfin_pint_regs);
+ }
+
+ }
+#endif /* BF54x */
+
+ debug_mmrs_dentry = top;
+
+ return 0;
+}
+module_init(bfin_debug_mmrs_init);
+
+static void __exit bfin_debug_mmrs_exit(void)
+{
+ debugfs_remove_recursive(debug_mmrs_dentry);
+}
+module_exit(bfin_debug_mmrs_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/arch/blackfin/kernel/ipipe.c b/arch/blackfin/kernel/ipipe.c
index f37019c847c9..486426f8a0d7 100644
--- a/arch/blackfin/kernel/ipipe.c
+++ b/arch/blackfin/kernel/ipipe.c
@@ -33,6 +33,7 @@
#include <linux/io.h>
#include <asm/system.h>
#include <asm/atomic.h>
+#include <asm/irq_handler.h>
DEFINE_PER_CPU(struct pt_regs, __ipipe_tick_regs);
diff --git a/arch/blackfin/kernel/irqchip.c b/arch/blackfin/kernel/irqchip.c
index 1696d34f51c2..ff3d747154ac 100644
--- a/arch/blackfin/kernel/irqchip.c
+++ b/arch/blackfin/kernel/irqchip.c
@@ -11,6 +11,7 @@
#include <linux/kallsyms.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <asm/irq_handler.h>
#include <asm/trace.h>
#include <asm/pda.h>
diff --git a/arch/blackfin/kernel/nmi.c b/arch/blackfin/kernel/nmi.c
index 0b5f72f17fd0..679d0db35256 100644
--- a/arch/blackfin/kernel/nmi.c
+++ b/arch/blackfin/kernel/nmi.c
@@ -12,7 +12,7 @@
#include <linux/bitops.h>
#include <linux/hardirq.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/pm.h>
#include <linux/nmi.h>
#include <linux/smp.h>
@@ -145,16 +145,16 @@ int check_nmi_wdt_touched(void)
{
unsigned int this_cpu = smp_processor_id();
unsigned int cpu;
+ cpumask_t mask;
- cpumask_t mask = cpu_online_map;
-
+ cpumask_copy(&mask, cpu_online_mask);
if (!atomic_read(&nmi_touched[this_cpu]))
return 0;
atomic_set(&nmi_touched[this_cpu], 0);
- cpu_clear(this_cpu, mask);
- for_each_cpu_mask(cpu, mask) {
+ cpumask_clear_cpu(this_cpu, &mask);
+ for_each_cpu(cpu, &mask) {
invalidate_dcache_range((unsigned long)(&nmi_touched[cpu]),
(unsigned long)(&nmi_touched[cpu]));
if (!atomic_read(&nmi_touched[cpu]))
@@ -196,43 +196,31 @@ void touch_nmi_watchdog(void)
/* Suspend/resume support */
#ifdef CONFIG_PM
-static int nmi_wdt_suspend(struct sys_device *dev, pm_message_t state)
+static int nmi_wdt_suspend(void)
{
nmi_wdt_stop();
return 0;
}
-static int nmi_wdt_resume(struct sys_device *dev)
+static void nmi_wdt_resume(void)
{
if (nmi_active)
nmi_wdt_start();
- return 0;
}
-static struct sysdev_class nmi_sysclass = {
- .name = DRV_NAME,
+static struct syscore_ops nmi_syscore_ops = {
.resume = nmi_wdt_resume,
.suspend = nmi_wdt_suspend,
};
-static struct sys_device device_nmi_wdt = {
- .id = 0,
- .cls = &nmi_sysclass,
-};
-
-static int __init init_nmi_wdt_sysfs(void)
+static int __init init_nmi_wdt_syscore(void)
{
- int error;
-
- if (!nmi_active)
- return 0;
+ if (nmi_active)
+ register_syscore_ops(&nmi_syscore_ops);
- error = sysdev_class_register(&nmi_sysclass);
- if (!error)
- error = sysdev_register(&device_nmi_wdt);
- return error;
+ return 0;
}
-late_initcall(init_nmi_wdt_sysfs);
+late_initcall(init_nmi_wdt_syscore);
#endif /* CONFIG_PM */
diff --git a/arch/blackfin/kernel/perf_event.c b/arch/blackfin/kernel/perf_event.c
new file mode 100644
index 000000000000..04300f29c0e7
--- /dev/null
+++ b/arch/blackfin/kernel/perf_event.c
@@ -0,0 +1,498 @@
+/*
+ * Blackfin performance counters
+ *
+ * Copyright 2011 Analog Devices Inc.
+ *
+ * Ripped from SuperH version:
+ *
+ * Copyright (C) 2009 Paul Mundt
+ *
+ * Heavily based on the x86 and PowerPC implementations.
+ *
+ * x86:
+ * Copyright (C) 2008 Thomas Gleixner <tglx@linutronix.de>
+ * Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar
+ * Copyright (C) 2009 Jaswinder Singh Rajput
+ * Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter
+ * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2009 Intel Corporation, <markus.t.metzger@intel.com>
+ *
+ * ppc:
+ * Copyright 2008-2009 Paul Mackerras, IBM Corporation.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/perf_event.h>
+#include <asm/bfin_pfmon.h>
+
+/*
+ * We have two counters, and each counter can support an event type.
+ * The 'o' is PFCNTx=1 and 's' is PFCNTx=0
+ *
+ * 0x04 o pc invariant branches
+ * 0x06 o mispredicted branches
+ * 0x09 o predicted branches taken
+ * 0x0B o EXCPT insn
+ * 0x0C o CSYNC/SSYNC insn
+ * 0x0D o Insns committed
+ * 0x0E o Interrupts taken
+ * 0x0F o Misaligned address exceptions
+ * 0x80 o Code memory fetches stalled due to DMA
+ * 0x83 o 64bit insn fetches delivered
+ * 0x9A o data cache fills (bank a)
+ * 0x9B o data cache fills (bank b)
+ * 0x9C o data cache lines evicted (bank a)
+ * 0x9D o data cache lines evicted (bank b)
+ * 0x9E o data cache high priority fills
+ * 0x9F o data cache low priority fills
+ * 0x00 s loop 0 iterations
+ * 0x01 s loop 1 iterations
+ * 0x0A s CSYNC/SSYNC stalls
+ * 0x10 s DAG read/after write hazards
+ * 0x13 s RAW data hazards
+ * 0x81 s code TAG stalls
+ * 0x82 s code fill stalls
+ * 0x90 s processor to memory stalls
+ * 0x91 s data memory stalls not hidden by 0x90
+ * 0x92 s data store buffer full stalls
+ * 0x93 s data memory write buffer full stalls due to high->low priority
+ * 0x95 s data memory fill buffer stalls
+ * 0x96 s data TAG collision stalls
+ * 0x97 s data collision stalls
+ * 0x98 s data stalls
+ * 0x99 s data stalls sent to processor
+ */
+
+static const int event_map[] = {
+ /* use CYCLES cpu register */
+ [PERF_COUNT_HW_CPU_CYCLES] = -1,
+ [PERF_COUNT_HW_INSTRUCTIONS] = 0x0D,
+ [PERF_COUNT_HW_CACHE_REFERENCES] = -1,
+ [PERF_COUNT_HW_CACHE_MISSES] = 0x83,
+ [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x09,
+ [PERF_COUNT_HW_BRANCH_MISSES] = 0x06,
+ [PERF_COUNT_HW_BUS_CYCLES] = -1,
+};
+
+#define C(x) PERF_COUNT_HW_CACHE_##x
+
+static const int cache_events[PERF_COUNT_HW_CACHE_MAX]
+ [PERF_COUNT_HW_CACHE_OP_MAX]
+ [PERF_COUNT_HW_CACHE_RESULT_MAX] =
+{
+ [C(L1D)] = { /* Data bank A */
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = 0,
+ [C(RESULT_MISS) ] = 0x9A,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = 0,
+ [C(RESULT_MISS) ] = 0,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = 0,
+ [C(RESULT_MISS) ] = 0,
+ },
+ },
+
+ [C(L1I)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = 0,
+ [C(RESULT_MISS) ] = 0x83,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = -1,
+ [C(RESULT_MISS) ] = -1,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = 0,
+ [C(RESULT_MISS) ] = 0,
+ },
+ },
+
+ [C(LL)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = -1,
+ [C(RESULT_MISS) ] = -1,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = -1,
+ [C(RESULT_MISS) ] = -1,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = -1,
+ [C(RESULT_MISS) ] = -1,
+ },
+ },
+
+ [C(DTLB)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = -1,
+ [C(RESULT_MISS) ] = -1,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = -1,
+ [C(RESULT_MISS) ] = -1,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = -1,
+ [C(RESULT_MISS) ] = -1,
+ },
+ },
+
+ [C(ITLB)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = -1,
+ [C(RESULT_MISS) ] = -1,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = -1,
+ [C(RESULT_MISS) ] = -1,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = -1,
+ [C(RESULT_MISS) ] = -1,
+ },
+ },
+
+ [C(BPU)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = -1,
+ [C(RESULT_MISS) ] = -1,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = -1,
+ [C(RESULT_MISS) ] = -1,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = -1,
+ [C(RESULT_MISS) ] = -1,
+ },
+ },
+};
+
+const char *perf_pmu_name(void)
+{
+ return "bfin";
+}
+EXPORT_SYMBOL(perf_pmu_name);
+
+int perf_num_counters(void)
+{
+ return ARRAY_SIZE(event_map);
+}
+EXPORT_SYMBOL(perf_num_counters);
+
+static u64 bfin_pfmon_read(int idx)
+{
+ return bfin_read32(PFCNTR0 + (idx * 4));
+}
+
+static void bfin_pfmon_disable(struct hw_perf_event *hwc, int idx)
+{
+ bfin_write_PFCTL(bfin_read_PFCTL() & ~PFCEN(idx, PFCEN_MASK));
+}
+
+static void bfin_pfmon_enable(struct hw_perf_event *hwc, int idx)
+{
+ u32 val, mask;
+
+ val = PFPWR;
+ if (idx) {
+ mask = ~(PFCNT1 | PFMON1 | PFCEN1 | PEMUSW1);
+ /* The packed config is for event0, so shift it to event1 slots */
+ val |= (hwc->config << (PFMON1_P - PFMON0_P));
+ val |= (hwc->config & PFCNT0) << (PFCNT1_P - PFCNT0_P);
+ bfin_write_PFCNTR1(0);
+ } else {
+ mask = ~(PFCNT0 | PFMON0 | PFCEN0 | PEMUSW0);
+ val |= hwc->config;
+ bfin_write_PFCNTR0(0);
+ }
+
+ bfin_write_PFCTL((bfin_read_PFCTL() & mask) | val);
+}
+
+static void bfin_pfmon_disable_all(void)
+{
+ bfin_write_PFCTL(bfin_read_PFCTL() & ~PFPWR);
+}
+
+static void bfin_pfmon_enable_all(void)
+{
+ bfin_write_PFCTL(bfin_read_PFCTL() | PFPWR);
+}
+
+struct cpu_hw_events {
+ struct perf_event *events[MAX_HWEVENTS];
+ unsigned long used_mask[BITS_TO_LONGS(MAX_HWEVENTS)];
+};
+DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
+
+static int hw_perf_cache_event(int config, int *evp)
+{
+ unsigned long type, op, result;
+ int ev;
+
+ /* unpack config */
+ type = config & 0xff;
+ op = (config >> 8) & 0xff;
+ result = (config >> 16) & 0xff;
+
+ if (type >= PERF_COUNT_HW_CACHE_MAX ||
+ op >= PERF_COUNT_HW_CACHE_OP_MAX ||
+ result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
+ return -EINVAL;
+
+ ev = cache_events[type][op][result];
+ if (ev == 0)
+ return -EOPNOTSUPP;
+ if (ev == -1)
+ return -EINVAL;
+ *evp = ev;
+ return 0;
+}
+
+static void bfin_perf_event_update(struct perf_event *event,
+ struct hw_perf_event *hwc, int idx)
+{
+ u64 prev_raw_count, new_raw_count;
+ s64 delta;
+ int shift = 0;
+
+ /*
+ * Depending on the counter configuration, they may or may not
+ * be chained, in which case the previous counter value can be
+ * updated underneath us if the lower-half overflows.
+ *
+ * Our tactic to handle this is to first atomically read and
+ * exchange a new raw count - then add that new-prev delta
+ * count to the generic counter atomically.
+ *
+ * As there is no interrupt associated with the overflow events,
+ * this is the simplest approach for maintaining consistency.
+ */
+again:
+ prev_raw_count = local64_read(&hwc->prev_count);
+ new_raw_count = bfin_pfmon_read(idx);
+
+ if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
+ new_raw_count) != prev_raw_count)
+ goto again;
+
+ /*
+ * Now we have the new raw value and have updated the prev
+ * timestamp already. We can now calculate the elapsed delta
+ * (counter-)time and add that to the generic counter.
+ *
+ * Careful, not all hw sign-extends above the physical width
+ * of the count.
+ */
+ delta = (new_raw_count << shift) - (prev_raw_count << shift);
+ delta >>= shift;
+
+ local64_add(delta, &event->count);
+}
+
+static void bfin_pmu_stop(struct perf_event *event, int flags)
+{
+ struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+ struct hw_perf_event *hwc = &event->hw;
+ int idx = hwc->idx;
+
+ if (!(event->hw.state & PERF_HES_STOPPED)) {
+ bfin_pfmon_disable(hwc, idx);
+ cpuc->events[idx] = NULL;
+ event->hw.state |= PERF_HES_STOPPED;
+ }
+
+ if ((flags & PERF_EF_UPDATE) && !(event->hw.state & PERF_HES_UPTODATE)) {
+ bfin_perf_event_update(event, &event->hw, idx);
+ event->hw.state |= PERF_HES_UPTODATE;
+ }
+}
+
+static void bfin_pmu_start(struct perf_event *event, int flags)
+{
+ struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+ struct hw_perf_event *hwc = &event->hw;
+ int idx = hwc->idx;
+
+ if (WARN_ON_ONCE(idx == -1))
+ return;
+
+ if (flags & PERF_EF_RELOAD)
+ WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
+
+ cpuc->events[idx] = event;
+ event->hw.state = 0;
+ bfin_pfmon_enable(hwc, idx);
+}
+
+static void bfin_pmu_del(struct perf_event *event, int flags)
+{
+ struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+
+ bfin_pmu_stop(event, PERF_EF_UPDATE);
+ __clear_bit(event->hw.idx, cpuc->used_mask);
+
+ perf_event_update_userpage(event);
+}
+
+static int bfin_pmu_add(struct perf_event *event, int flags)
+{
+ struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+ struct hw_perf_event *hwc = &event->hw;
+ int idx = hwc->idx;
+ int ret = -EAGAIN;
+
+ perf_pmu_disable(event->pmu);
+
+ if (__test_and_set_bit(idx, cpuc->used_mask)) {
+ idx = find_first_zero_bit(cpuc->used_mask, MAX_HWEVENTS);
+ if (idx == MAX_HWEVENTS)
+ goto out;
+
+ __set_bit(idx, cpuc->used_mask);
+ hwc->idx = idx;
+ }
+
+ bfin_pfmon_disable(hwc, idx);
+
+ event->hw.state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+ if (flags & PERF_EF_START)
+ bfin_pmu_start(event, PERF_EF_RELOAD);
+
+ perf_event_update_userpage(event);
+ ret = 0;
+out:
+ perf_pmu_enable(event->pmu);
+ return ret;
+}
+
+static void bfin_pmu_read(struct perf_event *event)
+{
+ bfin_perf_event_update(event, &event->hw, event->hw.idx);
+}
+
+static int bfin_pmu_event_init(struct perf_event *event)
+{
+ struct perf_event_attr *attr = &event->attr;
+ struct hw_perf_event *hwc = &event->hw;
+ int config = -1;
+ int ret;
+
+ if (attr->exclude_hv || attr->exclude_idle)
+ return -EPERM;
+
+ /*
+ * All of the on-chip counters are "limited", in that they have
+ * no interrupts, and are therefore unable to do sampling without
+ * further work and timer assistance.
+ */
+ if (hwc->sample_period)
+ return -EINVAL;
+
+ ret = 0;
+ switch (attr->type) {
+ case PERF_TYPE_RAW:
+ config = PFMON(0, attr->config & PFMON_MASK) |
+ PFCNT(0, !(attr->config & 0x100));
+ break;
+ case PERF_TYPE_HW_CACHE:
+ ret = hw_perf_cache_event(attr->config, &config);
+ break;
+ case PERF_TYPE_HARDWARE:
+ if (attr->config >= ARRAY_SIZE(event_map))
+ return -EINVAL;
+
+ config = event_map[attr->config];
+ break;
+ }
+
+ if (config == -1)
+ return -EINVAL;
+
+ if (!attr->exclude_kernel)
+ config |= PFCEN(0, PFCEN_ENABLE_SUPV);
+ if (!attr->exclude_user)
+ config |= PFCEN(0, PFCEN_ENABLE_USER);
+
+ hwc->config |= config;
+
+ return ret;
+}
+
+static void bfin_pmu_enable(struct pmu *pmu)
+{
+ struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+ struct perf_event *event;
+ struct hw_perf_event *hwc;
+ int i;
+
+ for (i = 0; i < MAX_HWEVENTS; ++i) {
+ event = cpuc->events[i];
+ if (!event)
+ continue;
+ hwc = &event->hw;
+ bfin_pfmon_enable(hwc, hwc->idx);
+ }
+
+ bfin_pfmon_enable_all();
+}
+
+static void bfin_pmu_disable(struct pmu *pmu)
+{
+ bfin_pfmon_disable_all();
+}
+
+static struct pmu pmu = {
+ .pmu_enable = bfin_pmu_enable,
+ .pmu_disable = bfin_pmu_disable,
+ .event_init = bfin_pmu_event_init,
+ .add = bfin_pmu_add,
+ .del = bfin_pmu_del,
+ .start = bfin_pmu_start,
+ .stop = bfin_pmu_stop,
+ .read = bfin_pmu_read,
+};
+
+static void bfin_pmu_setup(int cpu)
+{
+ struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu);
+
+ memset(cpuhw, 0, sizeof(struct cpu_hw_events));
+}
+
+static int __cpuinit
+bfin_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (long)hcpu;
+
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_UP_PREPARE:
+ bfin_write_PFCTL(0);
+ bfin_pmu_setup(cpu);
+ break;
+
+ default:
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static int __init bfin_pmu_init(void)
+{
+ int ret;
+
+ ret = perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
+ if (!ret)
+ perf_cpu_notifier(bfin_pmu_notifier);
+
+ return ret;
+}
+early_initcall(bfin_pmu_init);
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c
index b407bc8ad918..6a660fa921b5 100644
--- a/arch/blackfin/kernel/process.c
+++ b/arch/blackfin/kernel/process.c
@@ -171,10 +171,8 @@ asmlinkage int bfin_clone(struct pt_regs *regs)
unsigned long newsp;
#ifdef __ARCH_SYNC_CORE_DCACHE
- if (current->rt.nr_cpus_allowed == num_possible_cpus()) {
- current->cpus_allowed = cpumask_of_cpu(smp_processor_id());
- current->rt.nr_cpus_allowed = 1;
- }
+ if (current->rt.nr_cpus_allowed == num_possible_cpus())
+ set_cpus_allowed_ptr(current, cpumask_of(smp_processor_id()));
#endif
/* syscall2 puts clone_flags in r0 and usp in r1 */
diff --git a/arch/blackfin/kernel/reboot.c b/arch/blackfin/kernel/reboot.c
index 53d08dee8531..488bdc51aaa5 100644
--- a/arch/blackfin/kernel/reboot.c
+++ b/arch/blackfin/kernel/reboot.c
@@ -23,6 +23,9 @@
__attribute__ ((__l1_text__, __noreturn__))
static void bfin_reset(void)
{
+ if (!ANOMALY_05000353 && !ANOMALY_05000386)
+ bfrom_SoftReset((void *)(L1_SCRATCH_START + L1_SCRATCH_LENGTH - 20));
+
/* Wait for completion of "system" events such as cache line
* line fills so that we avoid infinite stalls later on as
* much as possible. This code is in L1, so it won't trigger
@@ -30,46 +33,40 @@ static void bfin_reset(void)
*/
__builtin_bfin_ssync();
- /* The bootrom checks to see how it was reset and will
- * automatically perform a software reset for us when
- * it starts executing after the core reset.
- */
- if (ANOMALY_05000353 || ANOMALY_05000386) {
- /* Initiate System software reset. */
- bfin_write_SWRST(0x7);
+ /* Initiate System software reset. */
+ bfin_write_SWRST(0x7);
- /* Due to the way reset is handled in the hardware, we need
- * to delay for 10 SCLKS. The only reliable way to do this is
- * to calculate the CCLK/SCLK ratio and multiply 10. For now,
- * we'll assume worse case which is a 1:15 ratio.
- */
- asm(
- "LSETUP (1f, 1f) LC0 = %0\n"
- "1: nop;"
- :
- : "a" (15 * 10)
- : "LC0", "LB0", "LT0"
- );
+ /* Due to the way reset is handled in the hardware, we need
+ * to delay for 10 SCLKS. The only reliable way to do this is
+ * to calculate the CCLK/SCLK ratio and multiply 10. For now,
+ * we'll assume worse case which is a 1:15 ratio.
+ */
+ asm(
+ "LSETUP (1f, 1f) LC0 = %0\n"
+ "1: nop;"
+ :
+ : "a" (15 * 10)
+ : "LC0", "LB0", "LT0"
+ );
- /* Clear System software reset */
- bfin_write_SWRST(0);
+ /* Clear System software reset */
+ bfin_write_SWRST(0);
- /* The BF526 ROM will crash during reset */
+ /* The BF526 ROM will crash during reset */
#if defined(__ADSPBF522__) || defined(__ADSPBF524__) || defined(__ADSPBF526__)
- bfin_read_SWRST();
+ bfin_read_SWRST();
#endif
- /* Wait for the SWRST write to complete. Cannot rely on SSYNC
- * though as the System state is all reset now.
- */
- asm(
- "LSETUP (1f, 1f) LC1 = %0\n"
- "1: nop;"
- :
- : "a" (15 * 1)
- : "LC1", "LB1", "LT1"
- );
- }
+ /* Wait for the SWRST write to complete. Cannot rely on SSYNC
+ * though as the System state is all reset now.
+ */
+ asm(
+ "LSETUP (1f, 1f) LC1 = %0\n"
+ "1: nop;"
+ :
+ : "a" (15 * 1)
+ : "LC1", "LB1", "LT1"
+ );
while (1)
/* Issue core reset */
diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c
index 805c6132c779..536bd9d7e0cf 100644
--- a/arch/blackfin/kernel/setup.c
+++ b/arch/blackfin/kernel/setup.c
@@ -29,6 +29,7 @@
#include <asm/cpu.h>
#include <asm/fixed_code.h>
#include <asm/early_printk.h>
+#include <asm/irq_handler.h>
u16 _bfin_swrst;
EXPORT_SYMBOL(_bfin_swrst);
@@ -105,6 +106,8 @@ void __cpuinit bfin_setup_caches(unsigned int cpu)
bfin_dcache_init(dcplb_tbl[cpu]);
#endif
+ bfin_setup_cpudata(cpu);
+
/*
* In cache coherence emulation mode, we need to have the
* D-cache enabled before running any atomic operation which
@@ -163,7 +166,6 @@ void __cpuinit bfin_setup_cpudata(unsigned int cpu)
{
struct blackfin_cpudata *cpudata = &per_cpu(cpu_data, cpu);
- cpudata->idle = current;
cpudata->imemctl = bfin_read_IMEM_CONTROL();
cpudata->dmemctl = bfin_read_DMEM_CONTROL();
}
@@ -851,6 +853,7 @@ void __init native_machine_early_platform_add_devices(void)
void __init setup_arch(char **cmdline_p)
{
+ u32 mmr;
unsigned long sclk, cclk;
native_machine_early_platform_add_devices();
@@ -902,10 +905,10 @@ void __init setup_arch(char **cmdline_p)
bfin_write_EBIU_FCTL(CONFIG_EBIU_FCTLVAL);
#endif
#ifdef CONFIG_BFIN_HYSTERESIS_CONTROL
- bfin_write_PORTF_HYSTERISIS(HYST_PORTF_0_15);
- bfin_write_PORTG_HYSTERISIS(HYST_PORTG_0_15);
- bfin_write_PORTH_HYSTERISIS(HYST_PORTH_0_15);
- bfin_write_MISCPORT_HYSTERISIS((bfin_read_MISCPORT_HYSTERISIS() &
+ bfin_write_PORTF_HYSTERESIS(HYST_PORTF_0_15);
+ bfin_write_PORTG_HYSTERESIS(HYST_PORTG_0_15);
+ bfin_write_PORTH_HYSTERESIS(HYST_PORTH_0_15);
+ bfin_write_MISCPORT_HYSTERESIS((bfin_read_MISCPORT_HYSTERESIS() &
~HYST_NONEGPIO_MASK) | HYST_NONEGPIO);
#endif
@@ -921,17 +924,14 @@ void __init setup_arch(char **cmdline_p)
bfin_read_IMDMA_D1_IRQ_STATUS();
}
#endif
- printk(KERN_INFO "Hardware Trace ");
- if (bfin_read_TBUFCTL() & 0x1)
- printk(KERN_CONT "Active ");
- else
- printk(KERN_CONT "Off ");
- if (bfin_read_TBUFCTL() & 0x2)
- printk(KERN_CONT "and Enabled\n");
- else
- printk(KERN_CONT "and Disabled\n");
- printk(KERN_INFO "Boot Mode: %i\n", bfin_read_SYSCR() & 0xF);
+ mmr = bfin_read_TBUFCTL();
+ printk(KERN_INFO "Hardware Trace %s and %sabled\n",
+ (mmr & 0x1) ? "active" : "off",
+ (mmr & 0x2) ? "en" : "dis");
+
+ mmr = bfin_read_SYSCR();
+ printk(KERN_INFO "Boot Mode: %i\n", mmr & 0xF);
/* Newer parts mirror SWRST bits in SYSCR */
#if defined(CONFIG_BF53x) || defined(CONFIG_BF561) || \
@@ -939,7 +939,7 @@ void __init setup_arch(char **cmdline_p)
_bfin_swrst = bfin_read_SWRST();
#else
/* Clear boot mode field */
- _bfin_swrst = bfin_read_SYSCR() & ~0xf;
+ _bfin_swrst = mmr & ~0xf;
#endif
#ifdef CONFIG_DEBUG_DOUBLEFAULT_PRINT
@@ -1036,8 +1036,6 @@ void __init setup_arch(char **cmdline_p)
static int __init topology_init(void)
{
unsigned int cpu;
- /* Record CPU-private information for the boot processor. */
- bfin_setup_cpudata(0);
for_each_possible_cpu(cpu) {
register_cpu(&per_cpu(cpu_data, cpu).cpu, cpu);
@@ -1283,12 +1281,14 @@ static int show_cpuinfo(struct seq_file *m, void *v)
dsup_banks, BFIN_DSUBBANKS, BFIN_DWAYS,
BFIN_DLINES);
#ifdef __ARCH_SYNC_CORE_DCACHE
- seq_printf(m, "SMP Dcache Flushes\t: %lu\n\n", dcache_invld_count[cpu_num]);
+ seq_printf(m, "dcache flushes\t: %lu\n", dcache_invld_count[cpu_num]);
#endif
#ifdef __ARCH_SYNC_CORE_ICACHE
- seq_printf(m, "SMP Icache Flushes\t: %lu\n\n", icache_invld_count[cpu_num]);
+ seq_printf(m, "icache flushes\t: %lu\n", icache_invld_count[cpu_num]);
#endif
+ seq_printf(m, "\n");
+
if (cpu_num != num_possible_cpus() - 1)
return 0;
@@ -1312,13 +1312,11 @@ static int show_cpuinfo(struct seq_file *m, void *v)
" in data cache\n");
}
seq_printf(m, "board name\t: %s\n", bfin_board_name);
- seq_printf(m, "board memory\t: %ld kB (0x%p -> 0x%p)\n",
- physical_mem_end >> 10, (void *)0, (void *)physical_mem_end);
- seq_printf(m, "kernel memory\t: %d kB (0x%p -> 0x%p)\n",
+ seq_printf(m, "board memory\t: %ld kB (0x%08lx -> 0x%08lx)\n",
+ physical_mem_end >> 10, 0ul, physical_mem_end);
+ seq_printf(m, "kernel memory\t: %d kB (0x%08lx -> 0x%08lx)\n",
((int)memory_end - (int)_rambase) >> 10,
- (void *)_rambase,
- (void *)memory_end);
- seq_printf(m, "\n");
+ _rambase, memory_end);
return 0;
}
@@ -1326,7 +1324,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
static void *c_start(struct seq_file *m, loff_t *pos)
{
if (*pos == 0)
- *pos = first_cpu(cpu_online_map);
+ *pos = cpumask_first(cpu_online_mask);
if (*pos >= num_online_cpus())
return NULL;
@@ -1335,7 +1333,7 @@ static void *c_start(struct seq_file *m, loff_t *pos)
static void *c_next(struct seq_file *m, void *v, loff_t *pos)
{
- *pos = next_cpu(*pos, cpu_online_map);
+ *pos = cpumask_next(*pos, cpu_online_mask);
return c_start(m, pos);
}
diff --git a/arch/blackfin/kernel/time-ts.c b/arch/blackfin/kernel/time-ts.c
index cdb4beb6bc8f..9e9b60d969dc 100644
--- a/arch/blackfin/kernel/time-ts.c
+++ b/arch/blackfin/kernel/time-ts.c
@@ -23,29 +23,6 @@
#include <asm/gptimers.h>
#include <asm/nmi.h>
-/* Accelerators for sched_clock()
- * convert from cycles(64bits) => nanoseconds (64bits)
- * basic equation:
- * ns = cycles / (freq / ns_per_sec)
- * ns = cycles * (ns_per_sec / freq)
- * ns = cycles * (10^9 / (cpu_khz * 10^3))
- * ns = cycles * (10^6 / cpu_khz)
- *
- * Then we use scaling math (suggested by george@mvista.com) to get:
- * ns = cycles * (10^6 * SC / cpu_khz) / SC
- * ns = cycles * cyc2ns_scale / SC
- *
- * And since SC is a constant power of two, we can convert the div
- * into a shift.
- *
- * We can use khz divisor instead of mhz to keep a better precision, since
- * cyc2ns_scale is limited to 10^6 * 2^10, which fits in 32 bits.
- * (mathieu.desnoyers@polymtl.ca)
- *
- * -johnstul@us.ibm.com "math is hard, lets go shopping!"
- */
-
-#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
#if defined(CONFIG_CYCLES_CLOCKSOURCE)
@@ -63,7 +40,6 @@ static struct clocksource bfin_cs_cycles = {
.rating = 400,
.read = bfin_read_cycles,
.mask = CLOCKSOURCE_MASK(64),
- .shift = CYC2NS_SCALE_FACTOR,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
@@ -75,10 +51,7 @@ static inline unsigned long long bfin_cs_cycles_sched_clock(void)
static int __init bfin_cs_cycles_init(void)
{
- bfin_cs_cycles.mult = \
- clocksource_hz2mult(get_cclk(), bfin_cs_cycles.shift);
-
- if (clocksource_register(&bfin_cs_cycles))
+ if (clocksource_register_hz(&bfin_cs_cycles, get_cclk()))
panic("failed to register clocksource");
return 0;
@@ -111,7 +84,6 @@ static struct clocksource bfin_cs_gptimer0 = {
.rating = 350,
.read = bfin_read_gptimer0,
.mask = CLOCKSOURCE_MASK(32),
- .shift = CYC2NS_SCALE_FACTOR,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
@@ -125,10 +97,7 @@ static int __init bfin_cs_gptimer0_init(void)
{
setup_gptimer0();
- bfin_cs_gptimer0.mult = \
- clocksource_hz2mult(get_sclk(), bfin_cs_gptimer0.shift);
-
- if (clocksource_register(&bfin_cs_gptimer0))
+ if (clocksource_register_hz(&bfin_cs_gptimer0, get_sclk()))
panic("failed to register clocksource");
return 0;
diff --git a/arch/blackfin/kernel/vmlinux.lds.S b/arch/blackfin/kernel/vmlinux.lds.S
index 854fa49f1c3e..3ac5b66d14aa 100644
--- a/arch/blackfin/kernel/vmlinux.lds.S
+++ b/arch/blackfin/kernel/vmlinux.lds.S
@@ -136,7 +136,7 @@ SECTIONS
. = ALIGN(16);
INIT_DATA_SECTION(16)
- PERCPU(32, PAGE_SIZE)
+ PERCPU_SECTION(32)
.exit.data :
{
@@ -155,14 +155,8 @@ SECTIONS
SECURITY_INITCALL
INIT_RAM_FS
- . = ALIGN(4);
___per_cpu_load = .;
- ___per_cpu_start = .;
- *(.data.percpu.first)
- *(.data.percpu.page_aligned)
- *(.data.percpu)
- *(.data.percpu.shared_aligned)
- ___per_cpu_end = .;
+ PERCPU_INPUT(32)
EXIT_DATA
__einitdata = .;
diff --git a/arch/blackfin/mach-bf518/include/mach/anomaly.h b/arch/blackfin/mach-bf518/include/mach/anomaly.h
index 24918c5f7ea1..d2f076fbbc9e 100644
--- a/arch/blackfin/mach-bf518/include/mach/anomaly.h
+++ b/arch/blackfin/mach-bf518/include/mach/anomaly.h
@@ -5,7 +5,7 @@
* and can be replaced with that version at any time
* DO NOT EDIT THIS FILE
*
- * Copyright 2004-2010 Analog Devices Inc.
+ * Copyright 2004-2011 Analog Devices Inc.
* Licensed under the ADI BSD license.
* https://docs.blackfin.uclinux.org/doku.php?id=adi_bsd
*/
@@ -141,6 +141,7 @@
#define ANOMALY_05000364 (0)
#define ANOMALY_05000371 (0)
#define ANOMALY_05000380 (0)
+#define ANOMALY_05000383 (0)
#define ANOMALY_05000386 (0)
#define ANOMALY_05000389 (0)
#define ANOMALY_05000400 (0)
@@ -155,6 +156,7 @@
#define ANOMALY_05000467 (0)
#define ANOMALY_05000474 (0)
#define ANOMALY_05000475 (0)
+#define ANOMALY_05000480 (0)
#define ANOMALY_05000485 (0)
#endif
diff --git a/arch/blackfin/mach-bf518/include/mach/cdefBF512.h b/arch/blackfin/mach-bf518/include/mach/cdefBF512.h
index b657d37a3402..bb79627f0929 100644
--- a/arch/blackfin/mach-bf518/include/mach/cdefBF512.h
+++ b/arch/blackfin/mach-bf518/include/mach/cdefBF512.h
@@ -990,18 +990,18 @@
#define bfin_write_PORTG_SLEW(val) bfin_write16(PORTG_SLEW, val)
#define bfin_read_PORTH_SLEW() bfin_read16(PORTH_SLEW)
#define bfin_write_PORTH_SLEW(val) bfin_write16(PORTH_SLEW, val)
-#define bfin_read_PORTF_HYSTERISIS() bfin_read16(PORTF_HYSTERISIS)
-#define bfin_write_PORTF_HYSTERISIS(val) bfin_write16(PORTF_HYSTERISIS, val)
-#define bfin_read_PORTG_HYSTERISIS() bfin_read16(PORTG_HYSTERISIS)
-#define bfin_write_PORTG_HYSTERISIS(val) bfin_write16(PORTG_HYSTERISIS, val)
-#define bfin_read_PORTH_HYSTERISIS() bfin_read16(PORTH_HYSTERISIS)
-#define bfin_write_PORTH_HYSTERISIS(val) bfin_write16(PORTH_HYSTERISIS, val)
+#define bfin_read_PORTF_HYSTERESIS() bfin_read16(PORTF_HYSTERESIS)
+#define bfin_write_PORTF_HYSTERESIS(val) bfin_write16(PORTF_HYSTERESIS, val)
+#define bfin_read_PORTG_HYSTERESIS() bfin_read16(PORTG_HYSTERESIS)
+#define bfin_write_PORTG_HYSTERESIS(val) bfin_write16(PORTG_HYSTERESIS, val)
+#define bfin_read_PORTH_HYSTERESIS() bfin_read16(PORTH_HYSTERESIS)
+#define bfin_write_PORTH_HYSTERESIS(val) bfin_write16(PORTH_HYSTERESIS, val)
#define bfin_read_MISCPORT_DRIVE() bfin_read16(MISCPORT_DRIVE)
#define bfin_write_MISCPORT_DRIVE(val) bfin_write16(MISCPORT_DRIVE, val)
#define bfin_read_MISCPORT_SLEW() bfin_read16(MISCPORT_SLEW)
#define bfin_write_MISCPORT_SLEW(val) bfin_write16(MISCPORT_SLEW, val)
-#define bfin_read_MISCPORT_HYSTERISIS() bfin_read16(MISCPORT_HYSTERISIS)
-#define bfin_write_MISCPORT_HYSTERISIS(val) bfin_write16(MISCPORT_HYSTERISIS, val)
+#define bfin_read_MISCPORT_HYSTERESIS() bfin_read16(MISCPORT_HYSTERESIS)
+#define bfin_write_MISCPORT_HYSTERESIS(val) bfin_write16(MISCPORT_HYSTERESIS, val)
/* HOST Port Registers */
diff --git a/arch/blackfin/mach-bf518/include/mach/defBF512.h b/arch/blackfin/mach-bf518/include/mach/defBF512.h
index cb1172f50757..729704078cd7 100644
--- a/arch/blackfin/mach-bf518/include/mach/defBF512.h
+++ b/arch/blackfin/mach-bf518/include/mach/defBF512.h
@@ -561,12 +561,12 @@
#define PORTF_SLEW 0xFFC03230 /* Port F slew control */
#define PORTG_SLEW 0xFFC03234 /* Port G slew control */
#define PORTH_SLEW 0xFFC03238 /* Port H slew control */
-#define PORTF_HYSTERISIS 0xFFC03240 /* Port F Schmitt trigger control */
-#define PORTG_HYSTERISIS 0xFFC03244 /* Port G Schmitt trigger control */
-#define PORTH_HYSTERISIS 0xFFC03248 /* Port H Schmitt trigger control */
+#define PORTF_HYSTERESIS 0xFFC03240 /* Port F Schmitt trigger control */
+#define PORTG_HYSTERESIS 0xFFC03244 /* Port G Schmitt trigger control */
+#define PORTH_HYSTERESIS 0xFFC03248 /* Port H Schmitt trigger control */
#define MISCPORT_DRIVE 0xFFC03280 /* Misc Port drive strength control */
#define MISCPORT_SLEW 0xFFC03284 /* Misc Port slew control */
-#define MISCPORT_HYSTERISIS 0xFFC03288 /* Misc Port Schmitt trigger control */
+#define MISCPORT_HYSTERESIS 0xFFC03288 /* Misc Port Schmitt trigger control */
/***********************************************************************************
diff --git a/arch/blackfin/mach-bf518/include/mach/irq.h b/arch/blackfin/mach-bf518/include/mach/irq.h
index 435e76e31aaa..edf8efd457dc 100644
--- a/arch/blackfin/mach-bf518/include/mach/irq.h
+++ b/arch/blackfin/mach-bf518/include/mach/irq.h
@@ -7,38 +7,9 @@
#ifndef _BF518_IRQ_H_
#define _BF518_IRQ_H_
-/*
- * Interrupt source definitions
- Event Source Core Event Name
- Core Emulation **
- Events (highest priority) EMU 0
- Reset RST 1
- NMI NMI 2
- Exception EVX 3
- Reserved -- 4
- Hardware Error IVHW 5
- Core Timer IVTMR 6 *
-
- .....
-
- Software Interrupt 1 IVG14 31
- Software Interrupt 2 --
- (lowest priority) IVG15 32 *
-*/
-
-#define NR_PERI_INTS (2 * 32)
-
-/* The ABSTRACT IRQ definitions */
-/** the first seven of the following are fixed, the rest you change if you need to **/
-#define IRQ_EMU 0 /* Emulation */
-#define IRQ_RST 1 /* reset */
-#define IRQ_NMI 2 /* Non Maskable */
-#define IRQ_EVX 3 /* Exception */
-#define IRQ_UNUSED 4 /* - unused interrupt */
-#define IRQ_HWERR 5 /* Hardware Error */
-#define IRQ_CORETMR 6 /* Core timer */
-
-#define BFIN_IRQ(x) ((x) + 7)
+#include <mach-common/irq.h>
+
+#define NR_PERI_INTS (2 * 32)
#define IRQ_PLL_WAKEUP BFIN_IRQ(0) /* PLL Wakeup Interrupt */
#define IRQ_DMA0_ERROR BFIN_IRQ(1) /* DMA Error 0 (generic) */
@@ -54,23 +25,23 @@
#define IRQ_UART0_ERROR BFIN_IRQ(12) /* UART0 Status */
#define IRQ_UART1_ERROR BFIN_IRQ(13) /* UART1 Status */
#define IRQ_RTC BFIN_IRQ(14) /* RTC */
-#define IRQ_PPI BFIN_IRQ(15) /* DMA Channel 0 (PPI) */
+#define IRQ_PPI BFIN_IRQ(15) /* DMA Channel 0 (PPI) */
#define IRQ_SPORT0_RX BFIN_IRQ(16) /* DMA 3 Channel (SPORT0 RX) */
#define IRQ_SPORT0_TX BFIN_IRQ(17) /* DMA 4 Channel (SPORT0 TX) */
#define IRQ_RSI BFIN_IRQ(17) /* DMA 4 Channel (RSI) */
#define IRQ_SPORT1_RX BFIN_IRQ(18) /* DMA 5 Channel (SPORT1 RX/SPI) */
#define IRQ_SPI1 BFIN_IRQ(18) /* DMA 5 Channel (SPI1) */
#define IRQ_SPORT1_TX BFIN_IRQ(19) /* DMA 6 Channel (SPORT1 TX) */
-#define IRQ_TWI BFIN_IRQ(20) /* TWI */
-#define IRQ_SPI0 BFIN_IRQ(21) /* DMA 7 Channel (SPI0) */
-#define IRQ_UART0_RX BFIN_IRQ(22) /* DMA8 Channel (UART0 RX) */
-#define IRQ_UART0_TX BFIN_IRQ(23) /* DMA9 Channel (UART0 TX) */
-#define IRQ_UART1_RX BFIN_IRQ(24) /* DMA10 Channel (UART1 RX) */
-#define IRQ_UART1_TX BFIN_IRQ(25) /* DMA11 Channel (UART1 TX) */
-#define IRQ_OPTSEC BFIN_IRQ(26) /* OTPSEC Interrupt */
-#define IRQ_CNT BFIN_IRQ(27) /* GP Counter */
-#define IRQ_MAC_RX BFIN_IRQ(28) /* DMA1 Channel (MAC RX) */
-#define IRQ_PORTH_INTA BFIN_IRQ(29) /* Port H Interrupt A */
+#define IRQ_TWI BFIN_IRQ(20) /* TWI */
+#define IRQ_SPI0 BFIN_IRQ(21) /* DMA 7 Channel (SPI0) */
+#define IRQ_UART0_RX BFIN_IRQ(22) /* DMA8 Channel (UART0 RX) */
+#define IRQ_UART0_TX BFIN_IRQ(23) /* DMA9 Channel (UART0 TX) */
+#define IRQ_UART1_RX BFIN_IRQ(24) /* DMA10 Channel (UART1 RX) */
+#define IRQ_UART1_TX BFIN_IRQ(25) /* DMA11 Channel (UART1 TX) */
+#define IRQ_OPTSEC BFIN_IRQ(26) /* OTPSEC Interrupt */
+#define IRQ_CNT BFIN_IRQ(27) /* GP Counter */
+#define IRQ_MAC_RX BFIN_IRQ(28) /* DMA1 Channel (MAC RX) */
+#define IRQ_PORTH_INTA BFIN_IRQ(29) /* Port H Interrupt A */
#define IRQ_MAC_TX BFIN_IRQ(30) /* DMA2 Channel (MAC TX) */
#define IRQ_PORTH_INTB BFIN_IRQ(31) /* Port H Interrupt B */
#define IRQ_TIMER0 BFIN_IRQ(32) /* Timer 0 */
@@ -96,101 +67,90 @@
#define IRQ_PWM_SYNC BFIN_IRQ(54) /* PWM Sync Interrupt */
#define IRQ_PTP_STAT BFIN_IRQ(55) /* PTP Stat Interrupt */
-#define SYS_IRQS BFIN_IRQ(63) /* 70 */
-
-#define IRQ_PF0 71
-#define IRQ_PF1 72
-#define IRQ_PF2 73
-#define IRQ_PF3 74
-#define IRQ_PF4 75
-#define IRQ_PF5 76
-#define IRQ_PF6 77
-#define IRQ_PF7 78
-#define IRQ_PF8 79
-#define IRQ_PF9 80
-#define IRQ_PF10 81
-#define IRQ_PF11 82
-#define IRQ_PF12 83
-#define IRQ_PF13 84
-#define IRQ_PF14 85
-#define IRQ_PF15 86
-
-#define IRQ_PG0 87
-#define IRQ_PG1 88
-#define IRQ_PG2 89
-#define IRQ_PG3 90
-#define IRQ_PG4 91
-#define IRQ_PG5 92
-#define IRQ_PG6 93
-#define IRQ_PG7 94
-#define IRQ_PG8 95
-#define IRQ_PG9 96
-#define IRQ_PG10 97
-#define IRQ_PG11 98
-#define IRQ_PG12 99
-#define IRQ_PG13 100
-#define IRQ_PG14 101
-#define IRQ_PG15 102
-
-#define IRQ_PH0 103
-#define IRQ_PH1 104
-#define IRQ_PH2 105
-#define IRQ_PH3 106
-#define IRQ_PH4 107
-#define IRQ_PH5 108
-#define IRQ_PH6 109
-#define IRQ_PH7 110
-#define IRQ_PH8 111
-#define IRQ_PH9 112
-#define IRQ_PH10 113
-#define IRQ_PH11 114
-#define IRQ_PH12 115
-#define IRQ_PH13 116
-#define IRQ_PH14 117
-#define IRQ_PH15 118
-
-#define GPIO_IRQ_BASE IRQ_PF0
-
-#define IRQ_MAC_PHYINT 119 /* PHY_INT Interrupt */
-#define IRQ_MAC_MMCINT 120 /* MMC Counter Interrupt */
-#define IRQ_MAC_RXFSINT 121 /* RX Frame-Status Interrupt */
-#define IRQ_MAC_TXFSINT 122 /* TX Frame-Status Interrupt */
-#define IRQ_MAC_WAKEDET 123 /* Wake-Up Interrupt */
-#define IRQ_MAC_RXDMAERR 124 /* RX DMA Direction Error Interrupt */
-#define IRQ_MAC_TXDMAERR 125 /* TX DMA Direction Error Interrupt */
-#define IRQ_MAC_STMDONE 126 /* Station Mgt. Transfer Done Interrupt */
-
-#define NR_MACH_IRQS (IRQ_MAC_STMDONE + 1)
-#define NR_IRQS (NR_MACH_IRQS + NR_SPARE_IRQS)
-
-#define IVG7 7
-#define IVG8 8
-#define IVG9 9
-#define IVG10 10
-#define IVG11 11
-#define IVG12 12
-#define IVG13 13
-#define IVG14 14
-#define IVG15 15
+#define SYS_IRQS BFIN_IRQ(63) /* 70 */
+
+#define IRQ_PF0 71
+#define IRQ_PF1 72
+#define IRQ_PF2 73
+#define IRQ_PF3 74
+#define IRQ_PF4 75
+#define IRQ_PF5 76
+#define IRQ_PF6 77
+#define IRQ_PF7 78
+#define IRQ_PF8 79
+#define IRQ_PF9 80
+#define IRQ_PF10 81
+#define IRQ_PF11 82
+#define IRQ_PF12 83
+#define IRQ_PF13 84
+#define IRQ_PF14 85
+#define IRQ_PF15 86
+
+#define IRQ_PG0 87
+#define IRQ_PG1 88
+#define IRQ_PG2 89
+#define IRQ_PG3 90
+#define IRQ_PG4 91
+#define IRQ_PG5 92
+#define IRQ_PG6 93
+#define IRQ_PG7 94
+#define IRQ_PG8 95
+#define IRQ_PG9 96
+#define IRQ_PG10 97
+#define IRQ_PG11 98
+#define IRQ_PG12 99
+#define IRQ_PG13 100
+#define IRQ_PG14 101
+#define IRQ_PG15 102
+
+#define IRQ_PH0 103
+#define IRQ_PH1 104
+#define IRQ_PH2 105
+#define IRQ_PH3 106
+#define IRQ_PH4 107
+#define IRQ_PH5 108
+#define IRQ_PH6 109
+#define IRQ_PH7 110
+#define IRQ_PH8 111
+#define IRQ_PH9 112
+#define IRQ_PH10 113
+#define IRQ_PH11 114
+#define IRQ_PH12 115
+#define IRQ_PH13 116
+#define IRQ_PH14 117
+#define IRQ_PH15 118
+
+#define GPIO_IRQ_BASE IRQ_PF0
+
+#define IRQ_MAC_PHYINT 119 /* PHY_INT Interrupt */
+#define IRQ_MAC_MMCINT 120 /* MMC Counter Interrupt */
+#define IRQ_MAC_RXFSINT 121 /* RX Frame-Status Interrupt */
+#define IRQ_MAC_TXFSINT 122 /* TX Frame-Status Interrupt */
+#define IRQ_MAC_WAKEDET 123 /* Wake-Up Interrupt */
+#define IRQ_MAC_RXDMAERR 124 /* RX DMA Direction Error Interrupt */
+#define IRQ_MAC_TXDMAERR 125 /* TX DMA Direction Error Interrupt */
+#define IRQ_MAC_STMDONE 126 /* Station Mgt. Transfer Done Interrupt */
+
+#define NR_MACH_IRQS (IRQ_MAC_STMDONE + 1)
/* IAR0 BIT FIELDS */
#define IRQ_PLL_WAKEUP_POS 0
#define IRQ_DMA0_ERROR_POS 4
-#define IRQ_DMAR0_BLK_POS 8
-#define IRQ_DMAR1_BLK_POS 12
-#define IRQ_DMAR0_OVR_POS 16
-#define IRQ_DMAR1_OVR_POS 20
-#define IRQ_PPI_ERROR_POS 24
-#define IRQ_MAC_ERROR_POS 28
+#define IRQ_DMAR0_BLK_POS 8
+#define IRQ_DMAR1_BLK_POS 12
+#define IRQ_DMAR0_OVR_POS 16
+#define IRQ_DMAR1_OVR_POS 20
+#define IRQ_PPI_ERROR_POS 24
+#define IRQ_MAC_ERROR_POS 28
/* IAR1 BIT FIELDS */
#define IRQ_SPORT0_ERROR_POS 0
#define IRQ_SPORT1_ERROR_POS 4
#define IRQ_PTP_ERROR_POS 8
-#define IRQ_UART0_ERROR_POS 16
-#define IRQ_UART1_ERROR_POS 20
-#define IRQ_RTC_POS 24
-#define IRQ_PPI_POS 28
+#define IRQ_UART0_ERROR_POS 16
+#define IRQ_UART1_ERROR_POS 20
+#define IRQ_RTC_POS 24
+#define IRQ_PPI_POS 28
/* IAR2 BIT FIELDS */
#define IRQ_SPORT0_RX_POS 0
@@ -199,19 +159,19 @@
#define IRQ_SPORT1_RX_POS 8
#define IRQ_SPI1_POS 8
#define IRQ_SPORT1_TX_POS 12
-#define IRQ_TWI_POS 16
-#define IRQ_SPI0_POS 20
-#define IRQ_UART0_RX_POS 24
-#define IRQ_UART0_TX_POS 28
+#define IRQ_TWI_POS 16
+#define IRQ_SPI0_POS 20
+#define IRQ_UART0_RX_POS 24
+#define IRQ_UART0_TX_POS 28
/* IAR3 BIT FIELDS */
-#define IRQ_UART1_RX_POS 0
-#define IRQ_UART1_TX_POS 4
-#define IRQ_OPTSEC_POS 8
-#define IRQ_CNT_POS 12
-#define IRQ_MAC_RX_POS 16
+#define IRQ_UART1_RX_POS 0
+#define IRQ_UART1_TX_POS 4
+#define IRQ_OPTSEC_POS 8
+#define IRQ_CNT_POS 12
+#define IRQ_MAC_RX_POS 16
#define IRQ_PORTH_INTA_POS 20
-#define IRQ_MAC_TX_POS 24
+#define IRQ_MAC_TX_POS 24
#define IRQ_PORTH_INTB_POS 28
/* IAR4 BIT FIELDS */
@@ -227,19 +187,19 @@
/* IAR5 BIT FIELDS */
#define IRQ_PORTG_INTA_POS 0
#define IRQ_PORTG_INTB_POS 4
-#define IRQ_MEM_DMA0_POS 8
-#define IRQ_MEM_DMA1_POS 12
-#define IRQ_WATCH_POS 16
+#define IRQ_MEM_DMA0_POS 8
+#define IRQ_MEM_DMA1_POS 12
+#define IRQ_WATCH_POS 16
#define IRQ_PORTF_INTA_POS 20
#define IRQ_PORTF_INTB_POS 24
-#define IRQ_SPI0_ERROR_POS 28
+#define IRQ_SPI0_ERROR_POS 28
/* IAR6 BIT FIELDS */
-#define IRQ_SPI1_ERROR_POS 0
-#define IRQ_RSI_INT0_POS 12
-#define IRQ_RSI_INT1_POS 16
-#define IRQ_PWM_TRIP_POS 20
-#define IRQ_PWM_SYNC_POS 24
-#define IRQ_PTP_STAT_POS 28
-
-#endif /* _BF518_IRQ_H_ */
+#define IRQ_SPI1_ERROR_POS 0
+#define IRQ_RSI_INT0_POS 12
+#define IRQ_RSI_INT1_POS 16
+#define IRQ_PWM_TRIP_POS 20
+#define IRQ_PWM_SYNC_POS 24
+#define IRQ_PTP_STAT_POS 28
+
+#endif
diff --git a/arch/blackfin/mach-bf527/boards/ezkit.c b/arch/blackfin/mach-bf527/boards/ezkit.c
index 2cd2ff6f3043..e67ac7720668 100644
--- a/arch/blackfin/mach-bf527/boards/ezkit.c
+++ b/arch/blackfin/mach-bf527/boards/ezkit.c
@@ -26,6 +26,7 @@
#include <asm/portmux.h>
#include <asm/dpmc.h>
#include <linux/spi/ad7877.h>
+#include <asm/bfin_sport.h>
/*
* Name the Board for the /proc/cpuinfo
@@ -526,11 +527,69 @@ static struct bfin5xx_spi_chip spidev_chip_info = {
};
#endif
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
+ defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+
+static const u16 bfin_snd_pin[][7] = {
+ {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS,
+ P_SPORT0_DRPRI, P_SPORT0_RSCLK, 0, 0},
+ {P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS,
+ P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_TFS, 0},
+};
+
+static struct bfin_snd_platform_data bfin_snd_data[] = {
+ {
+ .pin_req = &bfin_snd_pin[0][0],
+ },
+ {
+ .pin_req = &bfin_snd_pin[1][0],
+ },
+};
+
+#define BFIN_SND_RES(x) \
+ [x] = { \
+ { \
+ .start = SPORT##x##_TCR1, \
+ .end = SPORT##x##_TCR1, \
+ .flags = IORESOURCE_MEM \
+ }, \
+ { \
+ .start = CH_SPORT##x##_RX, \
+ .end = CH_SPORT##x##_RX, \
+ .flags = IORESOURCE_DMA, \
+ }, \
+ { \
+ .start = CH_SPORT##x##_TX, \
+ .end = CH_SPORT##x##_TX, \
+ .flags = IORESOURCE_DMA, \
+ }, \
+ { \
+ .start = IRQ_SPORT##x##_ERROR, \
+ .end = IRQ_SPORT##x##_ERROR, \
+ .flags = IORESOURCE_IRQ, \
+ } \
+ }
+
+static struct resource bfin_snd_resources[][4] = {
+ BFIN_SND_RES(0),
+ BFIN_SND_RES(1),
+};
+
+static struct platform_device bfin_pcm = {
+ .name = "bfin-pcm-audio",
+ .id = -1,
+};
+#endif
+
#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
static struct platform_device bfin_i2s = {
.name = "bfin-i2s",
.id = CONFIG_SND_BF5XX_SPORT_NUM,
- /* TODO: add platform data here */
+ .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+ .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+ .dev = {
+ .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+ },
};
#endif
@@ -538,7 +597,11 @@ static struct platform_device bfin_i2s = {
static struct platform_device bfin_tdm = {
.name = "bfin-tdm",
.id = CONFIG_SND_BF5XX_SPORT_NUM,
- /* TODO: add platform data here */
+ .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+ .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+ .dev = {
+ .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+ },
};
#endif
@@ -583,7 +646,9 @@ static struct spi_board_info bfin_spi_board_info[] __initdata = {
.max_speed_hz = 3125000, /* max spi clock (SCK) speed in HZ */
.bus_num = 0,
.chip_select = 4,
+ .platform_data = "ad1836",
.controller_data = &ad1836_spi_chip_info,
+ .mode = SPI_MODE_3,
},
#endif
#if defined(CONFIG_MMC_SPI) || defined(CONFIG_MMC_SPI_MODULE)
@@ -1211,6 +1276,11 @@ static struct platform_device *stamp_devices[] __initdata = {
&ezkit_flash_device,
#endif
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
+ defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+ &bfin_pcm,
+#endif
+
#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
&bfin_i2s,
#endif
diff --git a/arch/blackfin/mach-bf527/include/mach/anomaly.h b/arch/blackfin/mach-bf527/include/mach/anomaly.h
index 9358afa05c90..e66a7e89cd3c 100644
--- a/arch/blackfin/mach-bf527/include/mach/anomaly.h
+++ b/arch/blackfin/mach-bf527/include/mach/anomaly.h
@@ -5,14 +5,14 @@
* and can be replaced with that version at any time
* DO NOT EDIT THIS FILE
*
- * Copyright 2004-2010 Analog Devices Inc.
+ * Copyright 2004-2011 Analog Devices Inc.
* Licensed under the ADI BSD license.
* https://docs.blackfin.uclinux.org/doku.php?id=adi_bsd
*/
/* This file should be up to date with:
* - Revision E, 03/15/2010; ADSP-BF526 Blackfin Processor Anomaly List
- * - Revision G, 08/25/2009; ADSP-BF527 Blackfin Processor Anomaly List
+ * - Revision H, 04/29/2010; ADSP-BF527 Blackfin Processor Anomaly List
*/
#ifndef _MACH_ANOMALY_H_
@@ -220,6 +220,8 @@
#define ANOMALY_05000483 (1)
/* PLL_CTL Change Using bfrom_SysControl() Can Result in Processor Overclocking */
#define ANOMALY_05000485 (_ANOMALY_BF526_BF527(< 2, < 3))
+/* The CODEC Zero-Cross Detect Feature is not Functional */
+#define ANOMALY_05000487 (1)
/* IFLUSH sucks at life */
#define ANOMALY_05000491 (1)
@@ -268,11 +270,13 @@
#define ANOMALY_05000323 (0)
#define ANOMALY_05000362 (1)
#define ANOMALY_05000363 (0)
+#define ANOMALY_05000383 (0)
#define ANOMALY_05000400 (0)
#define ANOMALY_05000402 (0)
#define ANOMALY_05000412 (0)
#define ANOMALY_05000447 (0)
#define ANOMALY_05000448 (0)
#define ANOMALY_05000474 (0)
+#define ANOMALY_05000480 (0)
#endif
diff --git a/arch/blackfin/mach-bf527/include/mach/cdefBF522.h b/arch/blackfin/mach-bf527/include/mach/cdefBF522.h
index 618dfcdfa91a..2c12e879aa4e 100644
--- a/arch/blackfin/mach-bf527/include/mach/cdefBF522.h
+++ b/arch/blackfin/mach-bf527/include/mach/cdefBF522.h
@@ -1007,18 +1007,18 @@
#define bfin_write_PORTG_SLEW(val) bfin_write16(PORTG_SLEW, val)
#define bfin_read_PORTH_SLEW() bfin_read16(PORTH_SLEW)
#define bfin_write_PORTH_SLEW(val) bfin_write16(PORTH_SLEW, val)
-#define bfin_read_PORTF_HYSTERISIS() bfin_read16(PORTF_HYSTERISIS)
-#define bfin_write_PORTF_HYSTERISIS(val) bfin_write16(PORTF_HYSTERISIS, val)
-#define bfin_read_PORTG_HYSTERISIS() bfin_read16(PORTG_HYSTERISIS)
-#define bfin_write_PORTG_HYSTERISIS(val) bfin_write16(PORTG_HYSTERISIS, val)
-#define bfin_read_PORTH_HYSTERISIS() bfin_read16(PORTH_HYSTERISIS)
-#define bfin_write_PORTH_HYSTERISIS(val) bfin_write16(PORTH_HYSTERISIS, val)
+#define bfin_read_PORTF_HYSTERESIS() bfin_read16(PORTF_HYSTERESIS)
+#define bfin_write_PORTF_HYSTERESIS(val) bfin_write16(PORTF_HYSTERESIS, val)
+#define bfin_read_PORTG_HYSTERESIS() bfin_read16(PORTG_HYSTERESIS)
+#define bfin_write_PORTG_HYSTERESIS(val) bfin_write16(PORTG_HYSTERESIS, val)
+#define bfin_read_PORTH_HYSTERESIS() bfin_read16(PORTH_HYSTERESIS)
+#define bfin_write_PORTH_HYSTERESIS(val) bfin_write16(PORTH_HYSTERESIS, val)
#define bfin_read_MISCPORT_DRIVE() bfin_read16(MISCPORT_DRIVE)
#define bfin_write_MISCPORT_DRIVE(val) bfin_write16(MISCPORT_DRIVE, val)
#define bfin_read_MISCPORT_SLEW() bfin_read16(MISCPORT_SLEW)
#define bfin_write_MISCPORT_SLEW(val) bfin_write16(MISCPORT_SLEW, val)
-#define bfin_read_MISCPORT_HYSTERISIS() bfin_read16(MISCPORT_HYSTERISIS)
-#define bfin_write_MISCPORT_HYSTERISIS(val) bfin_write16(MISCPORT_HYSTERISIS, val)
+#define bfin_read_MISCPORT_HYSTERESIS() bfin_read16(MISCPORT_HYSTERESIS)
+#define bfin_write_MISCPORT_HYSTERESIS(val) bfin_write16(MISCPORT_HYSTERESIS, val)
/* HOST Port Registers */
diff --git a/arch/blackfin/mach-bf527/include/mach/defBF522.h b/arch/blackfin/mach-bf527/include/mach/defBF522.h
index 84ef11e52644..37d353a19722 100644
--- a/arch/blackfin/mach-bf527/include/mach/defBF522.h
+++ b/arch/blackfin/mach-bf527/include/mach/defBF522.h
@@ -562,12 +562,12 @@
#define PORTF_SLEW 0xFFC03230 /* Port F slew control */
#define PORTG_SLEW 0xFFC03234 /* Port G slew control */
#define PORTH_SLEW 0xFFC03238 /* Port H slew control */
-#define PORTF_HYSTERISIS 0xFFC03240 /* Port F Schmitt trigger control */
-#define PORTG_HYSTERISIS 0xFFC03244 /* Port G Schmitt trigger control */
-#define PORTH_HYSTERISIS 0xFFC03248 /* Port H Schmitt trigger control */
+#define PORTF_HYSTERESIS 0xFFC03240 /* Port F Schmitt trigger control */
+#define PORTG_HYSTERESIS 0xFFC03244 /* Port G Schmitt trigger control */
+#define PORTH_HYSTERESIS 0xFFC03248 /* Port H Schmitt trigger control */
#define MISCPORT_DRIVE 0xFFC03280 /* Misc Port drive strength control */
#define MISCPORT_SLEW 0xFFC03284 /* Misc Port slew control */
-#define MISCPORT_HYSTERISIS 0xFFC03288 /* Misc Port Schmitt trigger control */
+#define MISCPORT_HYSTERESIS 0xFFC03288 /* Misc Port Schmitt trigger control */
/***********************************************************************************
diff --git a/arch/blackfin/mach-bf527/include/mach/irq.h b/arch/blackfin/mach-bf527/include/mach/irq.h
index 704d9253e41d..ed7310ff819b 100644
--- a/arch/blackfin/mach-bf527/include/mach/irq.h
+++ b/arch/blackfin/mach-bf527/include/mach/irq.h
@@ -7,38 +7,9 @@
#ifndef _BF527_IRQ_H_
#define _BF527_IRQ_H_
-/*
- * Interrupt source definitions
- Event Source Core Event Name
- Core Emulation **
- Events (highest priority) EMU 0
- Reset RST 1
- NMI NMI 2
- Exception EVX 3
- Reserved -- 4
- Hardware Error IVHW 5
- Core Timer IVTMR 6 *
-
- .....
-
- Software Interrupt 1 IVG14 31
- Software Interrupt 2 --
- (lowest priority) IVG15 32 *
-*/
-
-#define NR_PERI_INTS (2 * 32)
-
-/* The ABSTRACT IRQ definitions */
-/** the first seven of the following are fixed, the rest you change if you need to **/
-#define IRQ_EMU 0 /* Emulation */
-#define IRQ_RST 1 /* reset */
-#define IRQ_NMI 2 /* Non Maskable */
-#define IRQ_EVX 3 /* Exception */
-#define IRQ_UNUSED 4 /* - unused interrupt */
-#define IRQ_HWERR 5 /* Hardware Error */
-#define IRQ_CORETMR 6 /* Core timer */
-
-#define BFIN_IRQ(x) ((x) + 7)
+#include <mach-common/irq.h>
+
+#define NR_PERI_INTS (2 * 32)
#define IRQ_PLL_WAKEUP BFIN_IRQ(0) /* PLL Wakeup Interrupt */
#define IRQ_DMA0_ERROR BFIN_IRQ(1) /* DMA Error 0 (generic) */
@@ -53,21 +24,21 @@
#define IRQ_UART0_ERROR BFIN_IRQ(12) /* UART0 Status */
#define IRQ_UART1_ERROR BFIN_IRQ(13) /* UART1 Status */
#define IRQ_RTC BFIN_IRQ(14) /* RTC */
-#define IRQ_PPI BFIN_IRQ(15) /* DMA Channel 0 (PPI/NAND) */
+#define IRQ_PPI BFIN_IRQ(15) /* DMA Channel 0 (PPI/NAND) */
#define IRQ_SPORT0_RX BFIN_IRQ(16) /* DMA 3 Channel (SPORT0 RX) */
#define IRQ_SPORT0_TX BFIN_IRQ(17) /* DMA 4 Channel (SPORT0 TX) */
#define IRQ_SPORT1_RX BFIN_IRQ(18) /* DMA 5 Channel (SPORT1 RX) */
#define IRQ_SPORT1_TX BFIN_IRQ(19) /* DMA 6 Channel (SPORT1 TX) */
-#define IRQ_TWI BFIN_IRQ(20) /* TWI */
-#define IRQ_SPI BFIN_IRQ(21) /* DMA 7 Channel (SPI) */
-#define IRQ_UART0_RX BFIN_IRQ(22) /* DMA8 Channel (UART0 RX) */
-#define IRQ_UART0_TX BFIN_IRQ(23) /* DMA9 Channel (UART0 TX) */
-#define IRQ_UART1_RX BFIN_IRQ(24) /* DMA10 Channel (UART1 RX) */
-#define IRQ_UART1_TX BFIN_IRQ(25) /* DMA11 Channel (UART1 TX) */
-#define IRQ_OPTSEC BFIN_IRQ(26) /* OTPSEC Interrupt */
-#define IRQ_CNT BFIN_IRQ(27) /* GP Counter */
-#define IRQ_MAC_RX BFIN_IRQ(28) /* DMA1 Channel (MAC RX/HDMA) */
-#define IRQ_PORTH_INTA BFIN_IRQ(29) /* Port H Interrupt A */
+#define IRQ_TWI BFIN_IRQ(20) /* TWI */
+#define IRQ_SPI BFIN_IRQ(21) /* DMA 7 Channel (SPI) */
+#define IRQ_UART0_RX BFIN_IRQ(22) /* DMA8 Channel (UART0 RX) */
+#define IRQ_UART0_TX BFIN_IRQ(23) /* DMA9 Channel (UART0 TX) */
+#define IRQ_UART1_RX BFIN_IRQ(24) /* DMA10 Channel (UART1 RX) */
+#define IRQ_UART1_TX BFIN_IRQ(25) /* DMA11 Channel (UART1 TX) */
+#define IRQ_OPTSEC BFIN_IRQ(26) /* OTPSEC Interrupt */
+#define IRQ_CNT BFIN_IRQ(27) /* GP Counter */
+#define IRQ_MAC_RX BFIN_IRQ(28) /* DMA1 Channel (MAC RX/HDMA) */
+#define IRQ_PORTH_INTA BFIN_IRQ(29) /* Port H Interrupt A */
#define IRQ_MAC_TX BFIN_IRQ(30) /* DMA2 Channel (MAC TX/NAND) */
#define IRQ_NFC BFIN_IRQ(30) /* DMA2 Channel (MAC TX/NAND) */
#define IRQ_PORTH_INTB BFIN_IRQ(31) /* Port H Interrupt B */
@@ -96,119 +67,108 @@
#define IRQ_USB_INT2 BFIN_IRQ(54) /* USB_INT2 Interrupt */
#define IRQ_USB_DMA BFIN_IRQ(55) /* USB_DMAINT Interrupt */
-#define SYS_IRQS BFIN_IRQ(63) /* 70 */
-
-#define IRQ_PF0 71
-#define IRQ_PF1 72
-#define IRQ_PF2 73
-#define IRQ_PF3 74
-#define IRQ_PF4 75
-#define IRQ_PF5 76
-#define IRQ_PF6 77
-#define IRQ_PF7 78
-#define IRQ_PF8 79
-#define IRQ_PF9 80
-#define IRQ_PF10 81
-#define IRQ_PF11 82
-#define IRQ_PF12 83
-#define IRQ_PF13 84
-#define IRQ_PF14 85
-#define IRQ_PF15 86
-
-#define IRQ_PG0 87
-#define IRQ_PG1 88
-#define IRQ_PG2 89
-#define IRQ_PG3 90
-#define IRQ_PG4 91
-#define IRQ_PG5 92
-#define IRQ_PG6 93
-#define IRQ_PG7 94
-#define IRQ_PG8 95
-#define IRQ_PG9 96
-#define IRQ_PG10 97
-#define IRQ_PG11 98
-#define IRQ_PG12 99
-#define IRQ_PG13 100
-#define IRQ_PG14 101
-#define IRQ_PG15 102
-
-#define IRQ_PH0 103
-#define IRQ_PH1 104
-#define IRQ_PH2 105
-#define IRQ_PH3 106
-#define IRQ_PH4 107
-#define IRQ_PH5 108
-#define IRQ_PH6 109
-#define IRQ_PH7 110
-#define IRQ_PH8 111
-#define IRQ_PH9 112
-#define IRQ_PH10 113
-#define IRQ_PH11 114
-#define IRQ_PH12 115
-#define IRQ_PH13 116
-#define IRQ_PH14 117
-#define IRQ_PH15 118
-
-#define GPIO_IRQ_BASE IRQ_PF0
-
-#define IRQ_MAC_PHYINT 119 /* PHY_INT Interrupt */
-#define IRQ_MAC_MMCINT 120 /* MMC Counter Interrupt */
-#define IRQ_MAC_RXFSINT 121 /* RX Frame-Status Interrupt */
-#define IRQ_MAC_TXFSINT 122 /* TX Frame-Status Interrupt */
-#define IRQ_MAC_WAKEDET 123 /* Wake-Up Interrupt */
-#define IRQ_MAC_RXDMAERR 124 /* RX DMA Direction Error Interrupt */
-#define IRQ_MAC_TXDMAERR 125 /* TX DMA Direction Error Interrupt */
-#define IRQ_MAC_STMDONE 126 /* Station Mgt. Transfer Done Interrupt */
-
-#define NR_MACH_IRQS (IRQ_MAC_STMDONE + 1)
-#define NR_IRQS (NR_MACH_IRQS + NR_SPARE_IRQS)
-
-#define IVG7 7
-#define IVG8 8
-#define IVG9 9
-#define IVG10 10
-#define IVG11 11
-#define IVG12 12
-#define IVG13 13
-#define IVG14 14
-#define IVG15 15
+#define SYS_IRQS BFIN_IRQ(63) /* 70 */
+
+#define IRQ_PF0 71
+#define IRQ_PF1 72
+#define IRQ_PF2 73
+#define IRQ_PF3 74
+#define IRQ_PF4 75
+#define IRQ_PF5 76
+#define IRQ_PF6 77
+#define IRQ_PF7 78
+#define IRQ_PF8 79
+#define IRQ_PF9 80
+#define IRQ_PF10 81
+#define IRQ_PF11 82
+#define IRQ_PF12 83
+#define IRQ_PF13 84
+#define IRQ_PF14 85
+#define IRQ_PF15 86
+
+#define IRQ_PG0 87
+#define IRQ_PG1 88
+#define IRQ_PG2 89
+#define IRQ_PG3 90
+#define IRQ_PG4 91
+#define IRQ_PG5 92
+#define IRQ_PG6 93
+#define IRQ_PG7 94
+#define IRQ_PG8 95
+#define IRQ_PG9 96
+#define IRQ_PG10 97
+#define IRQ_PG11 98
+#define IRQ_PG12 99
+#define IRQ_PG13 100
+#define IRQ_PG14 101
+#define IRQ_PG15 102
+
+#define IRQ_PH0 103
+#define IRQ_PH1 104
+#define IRQ_PH2 105
+#define IRQ_PH3 106
+#define IRQ_PH4 107
+#define IRQ_PH5 108
+#define IRQ_PH6 109
+#define IRQ_PH7 110
+#define IRQ_PH8 111
+#define IRQ_PH9 112
+#define IRQ_PH10 113
+#define IRQ_PH11 114
+#define IRQ_PH12 115
+#define IRQ_PH13 116
+#define IRQ_PH14 117
+#define IRQ_PH15 118
+
+#define GPIO_IRQ_BASE IRQ_PF0
+
+#define IRQ_MAC_PHYINT 119 /* PHY_INT Interrupt */
+#define IRQ_MAC_MMCINT 120 /* MMC Counter Interrupt */
+#define IRQ_MAC_RXFSINT 121 /* RX Frame-Status Interrupt */
+#define IRQ_MAC_TXFSINT 122 /* TX Frame-Status Interrupt */
+#define IRQ_MAC_WAKEDET 123 /* Wake-Up Interrupt */
+#define IRQ_MAC_RXDMAERR 124 /* RX DMA Direction Error Interrupt */
+#define IRQ_MAC_TXDMAERR 125 /* TX DMA Direction Error Interrupt */
+#define IRQ_MAC_STMDONE 126 /* Station Mgt. Transfer Done Interrupt */
+
+#define NR_MACH_IRQS (IRQ_MAC_STMDONE + 1)
/* IAR0 BIT FIELDS */
#define IRQ_PLL_WAKEUP_POS 0
#define IRQ_DMA0_ERROR_POS 4
-#define IRQ_DMAR0_BLK_POS 8
-#define IRQ_DMAR1_BLK_POS 12
-#define IRQ_DMAR0_OVR_POS 16
-#define IRQ_DMAR1_OVR_POS 20
-#define IRQ_PPI_ERROR_POS 24
-#define IRQ_MAC_ERROR_POS 28
+#define IRQ_DMAR0_BLK_POS 8
+#define IRQ_DMAR1_BLK_POS 12
+#define IRQ_DMAR0_OVR_POS 16
+#define IRQ_DMAR1_OVR_POS 20
+#define IRQ_PPI_ERROR_POS 24
+#define IRQ_MAC_ERROR_POS 28
/* IAR1 BIT FIELDS */
#define IRQ_SPORT0_ERROR_POS 0
#define IRQ_SPORT1_ERROR_POS 4
-#define IRQ_UART0_ERROR_POS 16
-#define IRQ_UART1_ERROR_POS 20
-#define IRQ_RTC_POS 24
-#define IRQ_PPI_POS 28
+#define IRQ_UART0_ERROR_POS 16
+#define IRQ_UART1_ERROR_POS 20
+#define IRQ_RTC_POS 24
+#define IRQ_PPI_POS 28
/* IAR2 BIT FIELDS */
#define IRQ_SPORT0_RX_POS 0
#define IRQ_SPORT0_TX_POS 4
#define IRQ_SPORT1_RX_POS 8
#define IRQ_SPORT1_TX_POS 12
-#define IRQ_TWI_POS 16
-#define IRQ_SPI_POS 20
-#define IRQ_UART0_RX_POS 24
-#define IRQ_UART0_TX_POS 28
+#define IRQ_TWI_POS 16
+#define IRQ_SPI_POS 20
+#define IRQ_UART0_RX_POS 24
+#define IRQ_UART0_TX_POS 28
/* IAR3 BIT FIELDS */
-#define IRQ_UART1_RX_POS 0
-#define IRQ_UART1_TX_POS 4
-#define IRQ_OPTSEC_POS 8
-#define IRQ_CNT_POS 12
-#define IRQ_MAC_RX_POS 16
+#define IRQ_UART1_RX_POS 0
+#define IRQ_UART1_TX_POS 4
+#define IRQ_OPTSEC_POS 8
+#define IRQ_CNT_POS 12
+#define IRQ_MAC_RX_POS 16
#define IRQ_PORTH_INTA_POS 20
-#define IRQ_MAC_TX_POS 24
+#define IRQ_MAC_TX_POS 24
#define IRQ_PORTH_INTB_POS 28
/* IAR4 BIT FIELDS */
@@ -224,21 +184,21 @@
/* IAR5 BIT FIELDS */
#define IRQ_PORTG_INTA_POS 0
#define IRQ_PORTG_INTB_POS 4
-#define IRQ_MEM_DMA0_POS 8
-#define IRQ_MEM_DMA1_POS 12
-#define IRQ_WATCH_POS 16
+#define IRQ_MEM_DMA0_POS 8
+#define IRQ_MEM_DMA1_POS 12
+#define IRQ_WATCH_POS 16
#define IRQ_PORTF_INTA_POS 20
#define IRQ_PORTF_INTB_POS 24
-#define IRQ_SPI_ERROR_POS 28
+#define IRQ_SPI_ERROR_POS 28
/* IAR6 BIT FIELDS */
-#define IRQ_NFC_ERROR_POS 0
-#define IRQ_HDMA_ERROR_POS 4
-#define IRQ_HDMA_POS 8
-#define IRQ_USB_EINT_POS 12
-#define IRQ_USB_INT0_POS 16
-#define IRQ_USB_INT1_POS 20
-#define IRQ_USB_INT2_POS 24
-#define IRQ_USB_DMA_POS 28
-
-#endif /* _BF527_IRQ_H_ */
+#define IRQ_NFC_ERROR_POS 0
+#define IRQ_HDMA_ERROR_POS 4
+#define IRQ_HDMA_POS 8
+#define IRQ_USB_EINT_POS 12
+#define IRQ_USB_INT0_POS 16
+#define IRQ_USB_INT1_POS 20
+#define IRQ_USB_INT2_POS 24
+#define IRQ_USB_DMA_POS 28
+
+#endif
diff --git a/arch/blackfin/mach-bf533/include/mach/anomaly.h b/arch/blackfin/mach-bf533/include/mach/anomaly.h
index 78f872187918..72aa59440f82 100644
--- a/arch/blackfin/mach-bf533/include/mach/anomaly.h
+++ b/arch/blackfin/mach-bf533/include/mach/anomaly.h
@@ -5,13 +5,13 @@
* and can be replaced with that version at any time
* DO NOT EDIT THIS FILE
*
- * Copyright 2004-2010 Analog Devices Inc.
+ * Copyright 2004-2011 Analog Devices Inc.
* Licensed under the ADI BSD license.
* https://docs.blackfin.uclinux.org/doku.php?id=adi_bsd
*/
/* This file should be up to date with:
- * - Revision E, 09/18/2008; ADSP-BF531/BF532/BF533 Blackfin Processor Anomaly List
+ * - Revision F, 05/25/2010; ADSP-BF531/BF532/BF533 Blackfin Processor Anomaly List
*/
#ifndef _MACH_ANOMALY_H_
@@ -206,6 +206,10 @@
#define ANOMALY_05000443 (1)
/* False Hardware Error when RETI Points to Invalid Memory */
#define ANOMALY_05000461 (1)
+/* Synchronization Problem at Startup May Cause SPORT Transmit Channels to Misalign */
+#define ANOMALY_05000462 (1)
+/* Boot Failure When SDRAM Control Signals Toggle Coming Out Of Reset */
+#define ANOMALY_05000471 (1)
/* Interrupted 32-Bit SPORT Data Register Access Results In Underflow */
#define ANOMALY_05000473 (1)
/* Possible Lockup Condition whem Modifying PLL from External Memory */
@@ -351,12 +355,14 @@
#define ANOMALY_05000362 (1)
#define ANOMALY_05000364 (0)
#define ANOMALY_05000380 (0)
+#define ANOMALY_05000383 (0)
#define ANOMALY_05000386 (1)
#define ANOMALY_05000389 (0)
#define ANOMALY_05000412 (0)
#define ANOMALY_05000430 (0)
#define ANOMALY_05000432 (0)
#define ANOMALY_05000435 (0)
+#define ANOMALY_05000440 (0)
#define ANOMALY_05000447 (0)
#define ANOMALY_05000448 (0)
#define ANOMALY_05000456 (0)
@@ -364,6 +370,7 @@
#define ANOMALY_05000465 (0)
#define ANOMALY_05000467 (0)
#define ANOMALY_05000474 (0)
+#define ANOMALY_05000480 (0)
#define ANOMALY_05000485 (0)
#endif
diff --git a/arch/blackfin/mach-bf533/include/mach/irq.h b/arch/blackfin/mach-bf533/include/mach/irq.h
index 1f7e9765d954..709733754142 100644
--- a/arch/blackfin/mach-bf533/include/mach/irq.h
+++ b/arch/blackfin/mach-bf533/include/mach/irq.h
@@ -7,83 +7,36 @@
#ifndef _BF533_IRQ_H_
#define _BF533_IRQ_H_
-/*
- * Interrupt source definitions
- Event Source Core Event Name
-Core Emulation **
- Events (highest priority) EMU 0
- Reset RST 1
- NMI NMI 2
- Exception EVX 3
- Reserved -- 4
- Hardware Error IVHW 5
- Core Timer IVTMR 6 *
- PLL Wakeup Interrupt IVG7 7
- DMA Error (generic) IVG7 8
- PPI Error Interrupt IVG7 9
- SPORT0 Error Interrupt IVG7 10
- SPORT1 Error Interrupt IVG7 11
- SPI Error Interrupt IVG7 12
- UART Error Interrupt IVG7 13
- RTC Interrupt IVG8 14
- DMA0 Interrupt (PPI) IVG8 15
- DMA1 (SPORT0 RX) IVG9 16
- DMA2 (SPORT0 TX) IVG9 17
- DMA3 (SPORT1 RX) IVG9 18
- DMA4 (SPORT1 TX) IVG9 19
- DMA5 (PPI) IVG10 20
- DMA6 (UART RX) IVG10 21
- DMA7 (UART TX) IVG10 22
- Timer0 IVG11 23
- Timer1 IVG11 24
- Timer2 IVG11 25
- PF Interrupt A IVG12 26
- PF Interrupt B IVG12 27
- DMA8/9 Interrupt IVG13 28
- DMA10/11 Interrupt IVG13 29
- Watchdog Timer IVG13 30
+#include <mach-common/irq.h>
- Softirq IVG14 31
- System Call --
- (lowest priority) IVG15 32 *
- */
-#define SYS_IRQS 31
-#define NR_PERI_INTS 24
+#define NR_PERI_INTS 24
-/* The ABSTRACT IRQ definitions */
-/** the first seven of the following are fixed, the rest you change if you need to **/
-#define IRQ_EMU 0 /*Emulation */
-#define IRQ_RST 1 /*reset */
-#define IRQ_NMI 2 /*Non Maskable */
-#define IRQ_EVX 3 /*Exception */
-#define IRQ_UNUSED 4 /*- unused interrupt*/
-#define IRQ_HWERR 5 /*Hardware Error */
-#define IRQ_CORETMR 6 /*Core timer */
+#define IRQ_PLL_WAKEUP BFIN_IRQ(0) /* PLL Wakeup Interrupt */
+#define IRQ_DMA_ERROR BFIN_IRQ(1) /* DMA Error (general) */
+#define IRQ_PPI_ERROR BFIN_IRQ(2) /* PPI Error Interrupt */
+#define IRQ_SPORT0_ERROR BFIN_IRQ(3) /* SPORT0 Error Interrupt */
+#define IRQ_SPORT1_ERROR BFIN_IRQ(4) /* SPORT1 Error Interrupt */
+#define IRQ_SPI_ERROR BFIN_IRQ(5) /* SPI Error Interrupt */
+#define IRQ_UART0_ERROR BFIN_IRQ(6) /* UART Error Interrupt */
+#define IRQ_RTC BFIN_IRQ(7) /* RTC Interrupt */
+#define IRQ_PPI BFIN_IRQ(8) /* DMA0 Interrupt (PPI) */
+#define IRQ_SPORT0_RX BFIN_IRQ(9) /* DMA1 Interrupt (SPORT0 RX) */
+#define IRQ_SPORT0_TX BFIN_IRQ(10) /* DMA2 Interrupt (SPORT0 TX) */
+#define IRQ_SPORT1_RX BFIN_IRQ(11) /* DMA3 Interrupt (SPORT1 RX) */
+#define IRQ_SPORT1_TX BFIN_IRQ(12) /* DMA4 Interrupt (SPORT1 TX) */
+#define IRQ_SPI BFIN_IRQ(13) /* DMA5 Interrupt (SPI) */
+#define IRQ_UART0_RX BFIN_IRQ(14) /* DMA6 Interrupt (UART RX) */
+#define IRQ_UART0_TX BFIN_IRQ(15) /* DMA7 Interrupt (UART TX) */
+#define IRQ_TIMER0 BFIN_IRQ(16) /* Timer 0 */
+#define IRQ_TIMER1 BFIN_IRQ(17) /* Timer 1 */
+#define IRQ_TIMER2 BFIN_IRQ(18) /* Timer 2 */
+#define IRQ_PROG_INTA BFIN_IRQ(19) /* Programmable Flags A (8) */
+#define IRQ_PROG_INTB BFIN_IRQ(20) /* Programmable Flags B (8) */
+#define IRQ_MEM_DMA0 BFIN_IRQ(21) /* DMA8/9 Interrupt (Memory DMA Stream 0) */
+#define IRQ_MEM_DMA1 BFIN_IRQ(22) /* DMA10/11 Interrupt (Memory DMA Stream 1) */
+#define IRQ_WATCH BFIN_IRQ(23) /* Watch Dog Timer */
-#define IRQ_PLL_WAKEUP 7 /*PLL Wakeup Interrupt */
-#define IRQ_DMA_ERROR 8 /*DMA Error (general) */
-#define IRQ_PPI_ERROR 9 /*PPI Error Interrupt */
-#define IRQ_SPORT0_ERROR 10 /*SPORT0 Error Interrupt */
-#define IRQ_SPORT1_ERROR 11 /*SPORT1 Error Interrupt */
-#define IRQ_SPI_ERROR 12 /*SPI Error Interrupt */
-#define IRQ_UART0_ERROR 13 /*UART Error Interrupt */
-#define IRQ_RTC 14 /*RTC Interrupt */
-#define IRQ_PPI 15 /*DMA0 Interrupt (PPI) */
-#define IRQ_SPORT0_RX 16 /*DMA1 Interrupt (SPORT0 RX) */
-#define IRQ_SPORT0_TX 17 /*DMA2 Interrupt (SPORT0 TX) */
-#define IRQ_SPORT1_RX 18 /*DMA3 Interrupt (SPORT1 RX) */
-#define IRQ_SPORT1_TX 19 /*DMA4 Interrupt (SPORT1 TX) */
-#define IRQ_SPI 20 /*DMA5 Interrupt (SPI) */
-#define IRQ_UART0_RX 21 /*DMA6 Interrupt (UART RX) */
-#define IRQ_UART0_TX 22 /*DMA7 Interrupt (UART TX) */
-#define IRQ_TIMER0 23 /*Timer 0 */
-#define IRQ_TIMER1 24 /*Timer 1 */
-#define IRQ_TIMER2 25 /*Timer 2 */
-#define IRQ_PROG_INTA 26 /*Programmable Flags A (8) */
-#define IRQ_PROG_INTB 27 /*Programmable Flags B (8) */
-#define IRQ_MEM_DMA0 28 /*DMA8/9 Interrupt (Memory DMA Stream 0) */
-#define IRQ_MEM_DMA1 29 /*DMA10/11 Interrupt (Memory DMA Stream 1) */
-#define IRQ_WATCH 30 /*Watch Dog Timer */
+#define SYS_IRQS 31
#define IRQ_PF0 33
#define IRQ_PF1 34
@@ -105,46 +58,35 @@ Core Emulation **
#define GPIO_IRQ_BASE IRQ_PF0
#define NR_MACH_IRQS (IRQ_PF15 + 1)
-#define NR_IRQS (NR_MACH_IRQS + NR_SPARE_IRQS)
-
-#define IVG7 7
-#define IVG8 8
-#define IVG9 9
-#define IVG10 10
-#define IVG11 11
-#define IVG12 12
-#define IVG13 13
-#define IVG14 14
-#define IVG15 15
-/* IAR0 BIT FIELDS*/
-#define RTC_ERROR_POS 28
-#define UART_ERROR_POS 24
-#define SPORT1_ERROR_POS 20
-#define SPI_ERROR_POS 16
-#define SPORT0_ERROR_POS 12
-#define PPI_ERROR_POS 8
-#define DMA_ERROR_POS 4
-#define PLLWAKE_ERROR_POS 0
+/* IAR0 BIT FIELDS */
+#define RTC_ERROR_POS 28
+#define UART_ERROR_POS 24
+#define SPORT1_ERROR_POS 20
+#define SPI_ERROR_POS 16
+#define SPORT0_ERROR_POS 12
+#define PPI_ERROR_POS 8
+#define DMA_ERROR_POS 4
+#define PLLWAKE_ERROR_POS 0
-/* IAR1 BIT FIELDS*/
-#define DMA7_UARTTX_POS 28
-#define DMA6_UARTRX_POS 24
-#define DMA5_SPI_POS 20
-#define DMA4_SPORT1TX_POS 16
-#define DMA3_SPORT1RX_POS 12
-#define DMA2_SPORT0TX_POS 8
-#define DMA1_SPORT0RX_POS 4
-#define DMA0_PPI_POS 0
+/* IAR1 BIT FIELDS */
+#define DMA7_UARTTX_POS 28
+#define DMA6_UARTRX_POS 24
+#define DMA5_SPI_POS 20
+#define DMA4_SPORT1TX_POS 16
+#define DMA3_SPORT1RX_POS 12
+#define DMA2_SPORT0TX_POS 8
+#define DMA1_SPORT0RX_POS 4
+#define DMA0_PPI_POS 0
-/* IAR2 BIT FIELDS*/
-#define WDTIMER_POS 28
-#define MEMDMA1_POS 24
-#define MEMDMA0_POS 20
-#define PFB_POS 16
-#define PFA_POS 12
-#define TIMER2_POS 8
-#define TIMER1_POS 4
-#define TIMER0_POS 0
+/* IAR2 BIT FIELDS */
+#define WDTIMER_POS 28
+#define MEMDMA1_POS 24
+#define MEMDMA0_POS 20
+#define PFB_POS 16
+#define PFA_POS 12
+#define TIMER2_POS 8
+#define TIMER1_POS 4
+#define TIMER0_POS 0
-#endif /* _BF533_IRQ_H_ */
+#endif
diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c
index 3fa335405b31..e16dc4560048 100644
--- a/arch/blackfin/mach-bf537/boards/stamp.c
+++ b/arch/blackfin/mach-bf537/boards/stamp.c
@@ -35,6 +35,7 @@
#include <asm/reboot.h>
#include <asm/portmux.h>
#include <asm/dpmc.h>
+#include <asm/bfin_sport.h>
#ifdef CONFIG_REGULATOR_FIXED_VOLTAGE
#include <linux/regulator/fixed.h>
#endif
@@ -2585,27 +2586,103 @@ static struct platform_device bfin_dpmc = {
},
};
-#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
+ defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) || \
+ defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+
+#define SPORT_REQ(x) \
+ [x] = {P_SPORT##x##_TFS, P_SPORT##x##_DTPRI, P_SPORT##x##_TSCLK, \
+ P_SPORT##x##_RFS, P_SPORT##x##_DRPRI, P_SPORT##x##_RSCLK, 0}
+
+static const u16 bfin_snd_pin[][7] = {
+ SPORT_REQ(0),
+ SPORT_REQ(1),
+};
+
+static struct bfin_snd_platform_data bfin_snd_data[] = {
+ {
+ .pin_req = &bfin_snd_pin[0][0],
+ },
+ {
+ .pin_req = &bfin_snd_pin[1][0],
+ },
+};
+
+#define BFIN_SND_RES(x) \
+ [x] = { \
+ { \
+ .start = SPORT##x##_TCR1, \
+ .end = SPORT##x##_TCR1, \
+ .flags = IORESOURCE_MEM \
+ }, \
+ { \
+ .start = CH_SPORT##x##_RX, \
+ .end = CH_SPORT##x##_RX, \
+ .flags = IORESOURCE_DMA, \
+ }, \
+ { \
+ .start = CH_SPORT##x##_TX, \
+ .end = CH_SPORT##x##_TX, \
+ .flags = IORESOURCE_DMA, \
+ }, \
+ { \
+ .start = IRQ_SPORT##x##_ERROR, \
+ .end = IRQ_SPORT##x##_ERROR, \
+ .flags = IORESOURCE_IRQ, \
+ } \
+ }
+
+static struct resource bfin_snd_resources[][4] = {
+ BFIN_SND_RES(0),
+ BFIN_SND_RES(1),
+};
+
+static struct platform_device bfin_pcm = {
+ .name = "bfin-pcm-audio",
+ .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_AD73311) || defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE)
+static struct platform_device bfin_ad73311_codec_device = {
+ .name = "ad73311",
+ .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_I2S) || defined(CONFIG_SND_BF5XX_SOC_I2S_MODULE)
static struct platform_device bfin_i2s = {
.name = "bfin-i2s",
.id = CONFIG_SND_BF5XX_SPORT_NUM,
- /* TODO: add platform data here */
+ .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+ .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+ .dev = {
+ .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+ },
};
#endif
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_TDM) || defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
static struct platform_device bfin_tdm = {
.name = "bfin-tdm",
.id = CONFIG_SND_BF5XX_SPORT_NUM,
- /* TODO: add platform data here */
+ .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+ .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+ .dev = {
+ .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+ },
};
#endif
-#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AC97) || defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
static struct platform_device bfin_ac97 = {
.name = "bfin-ac97",
.id = CONFIG_SND_BF5XX_SPORT_NUM,
- /* TODO: add platform data here */
+ .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+ .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+ .dev = {
+ .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+ },
};
#endif
@@ -2796,17 +2873,28 @@ static struct platform_device *stamp_devices[] __initdata = {
&stamp_flash_device,
#endif
-#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
+ defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) || \
+ defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+ &bfin_pcm,
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_AD73311) || defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE)
+ &bfin_ad73311_codec_device,
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_I2S) || defined(CONFIG_SND_BF5XX_SOC_I2S_MODULE)
&bfin_i2s,
#endif
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_TDM) || defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
&bfin_tdm,
#endif
-#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AC97) || defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
&bfin_ac97,
#endif
+
#if defined(CONFIG_REGULATOR_AD5398) || defined(CONFIG_REGULATOR_AD5398_MODULE)
#if defined(CONFIG_REGULATOR_VIRTUAL_CONSUMER) || \
defined(CONFIG_REGULATOR_VIRTUAL_CONSUMER_MODULE)
diff --git a/arch/blackfin/mach-bf537/include/mach/anomaly.h b/arch/blackfin/mach-bf537/include/mach/anomaly.h
index 43df6afd22ad..7f8e5a9f5db6 100644
--- a/arch/blackfin/mach-bf537/include/mach/anomaly.h
+++ b/arch/blackfin/mach-bf537/include/mach/anomaly.h
@@ -5,13 +5,13 @@
* and can be replaced with that version at any time
* DO NOT EDIT THIS FILE
*
- * Copyright 2004-2010 Analog Devices Inc.
+ * Copyright 2004-2011 Analog Devices Inc.
* Licensed under the ADI BSD license.
* https://docs.blackfin.uclinux.org/doku.php?id=adi_bsd
*/
/* This file should be up to date with:
- * - Revision D, 09/18/2008; ADSP-BF534/ADSP-BF536/ADSP-BF537 Blackfin Processor Anomaly List
+ * - Revision E, 05/25/2010; ADSP-BF534/ADSP-BF536/ADSP-BF537 Blackfin Processor Anomaly List
*/
#ifndef _MACH_ANOMALY_H_
@@ -160,12 +160,16 @@
#define ANOMALY_05000443 (1)
/* False Hardware Error when RETI Points to Invalid Memory */
#define ANOMALY_05000461 (1)
+/* Synchronization Problem at Startup May Cause SPORT Transmit Channels to Misalign */
+#define ANOMALY_05000462 (1)
/* Interrupted 32-Bit SPORT Data Register Access Results In Underflow */
#define ANOMALY_05000473 (1)
/* Possible Lockup Condition whem Modifying PLL from External Memory */
#define ANOMALY_05000475 (1)
/* TESTSET Instruction Cannot Be Interrupted */
#define ANOMALY_05000477 (1)
+/* Multiple Simultaneous Urgent DMA Requests May Cause DMA System Instability */
+#define ANOMALY_05000480 (__SILICON_REVISION__ < 3)
/* Reads of ITEST_COMMAND and ITEST_DATA Registers Cause Cache Corruption */
#define ANOMALY_05000481 (1)
/* IFLUSH sucks at life */
@@ -204,6 +208,7 @@
#define ANOMALY_05000363 (0)
#define ANOMALY_05000364 (0)
#define ANOMALY_05000380 (0)
+#define ANOMALY_05000383 (0)
#define ANOMALY_05000386 (1)
#define ANOMALY_05000389 (0)
#define ANOMALY_05000400 (0)
@@ -211,6 +216,7 @@
#define ANOMALY_05000430 (0)
#define ANOMALY_05000432 (0)
#define ANOMALY_05000435 (0)
+#define ANOMALY_05000440 (0)
#define ANOMALY_05000447 (0)
#define ANOMALY_05000448 (0)
#define ANOMALY_05000456 (0)
diff --git a/arch/blackfin/mach-bf537/include/mach/irq.h b/arch/blackfin/mach-bf537/include/mach/irq.h
index 1a6d617c5fcf..b6ed8235bda4 100644
--- a/arch/blackfin/mach-bf537/include/mach/irq.h
+++ b/arch/blackfin/mach-bf537/include/mach/irq.h
@@ -7,193 +7,178 @@
#ifndef _BF537_IRQ_H_
#define _BF537_IRQ_H_
-/*
- * Interrupt source definitions
- * Event Source Core Event Name
- * Core Emulation **
- * Events (highest priority) EMU 0
- * Reset RST 1
- * NMI NMI 2
- * Exception EVX 3
- * Reserved -- 4
- * Hardware Error IVHW 5
- * Core Timer IVTMR 6
- * .....
- *
- * Softirq IVG14
- * System Call --
- * (lowest priority) IVG15
- */
-
-#define SYS_IRQS 39
-#define NR_PERI_INTS 32
-
-/* The ABSTRACT IRQ definitions */
-/** the first seven of the following are fixed, the rest you change if you need to **/
-#define IRQ_EMU 0 /*Emulation */
-#define IRQ_RST 1 /*reset */
-#define IRQ_NMI 2 /*Non Maskable */
-#define IRQ_EVX 3 /*Exception */
-#define IRQ_UNUSED 4 /*- unused interrupt*/
-#define IRQ_HWERR 5 /*Hardware Error */
-#define IRQ_CORETMR 6 /*Core timer */
-
-#define IRQ_PLL_WAKEUP 7 /*PLL Wakeup Interrupt */
-#define IRQ_DMA_ERROR 8 /*DMA Error (general) */
-#define IRQ_GENERIC_ERROR 9 /*GENERIC Error Interrupt */
-#define IRQ_RTC 10 /*RTC Interrupt */
-#define IRQ_PPI 11 /*DMA0 Interrupt (PPI) */
-#define IRQ_SPORT0_RX 12 /*DMA3 Interrupt (SPORT0 RX) */
-#define IRQ_SPORT0_TX 13 /*DMA4 Interrupt (SPORT0 TX) */
-#define IRQ_SPORT1_RX 14 /*DMA5 Interrupt (SPORT1 RX) */
-#define IRQ_SPORT1_TX 15 /*DMA6 Interrupt (SPORT1 TX) */
-#define IRQ_TWI 16 /*TWI Interrupt */
-#define IRQ_SPI 17 /*DMA7 Interrupt (SPI) */
-#define IRQ_UART0_RX 18 /*DMA8 Interrupt (UART0 RX) */
-#define IRQ_UART0_TX 19 /*DMA9 Interrupt (UART0 TX) */
-#define IRQ_UART1_RX 20 /*DMA10 Interrupt (UART1 RX) */
-#define IRQ_UART1_TX 21 /*DMA11 Interrupt (UART1 TX) */
-#define IRQ_CAN_RX 22 /*CAN Receive Interrupt */
-#define IRQ_CAN_TX 23 /*CAN Transmit Interrupt */
-#define IRQ_MAC_RX 24 /*DMA1 (Ethernet RX) Interrupt */
-#define IRQ_MAC_TX 25 /*DMA2 (Ethernet TX) Interrupt */
-#define IRQ_TIMER0 26 /*Timer 0 */
-#define IRQ_TIMER1 27 /*Timer 1 */
-#define IRQ_TIMER2 28 /*Timer 2 */
-#define IRQ_TIMER3 29 /*Timer 3 */
-#define IRQ_TIMER4 30 /*Timer 4 */
-#define IRQ_TIMER5 31 /*Timer 5 */
-#define IRQ_TIMER6 32 /*Timer 6 */
-#define IRQ_TIMER7 33 /*Timer 7 */
-#define IRQ_PROG_INTA 34 /* PF Ports F&G (PF15:0) Interrupt A */
-#define IRQ_PORTG_INTB 35 /* PF Port G (PF15:0) Interrupt B */
-#define IRQ_MEM_DMA0 36 /*(Memory DMA Stream 0) */
-#define IRQ_MEM_DMA1 37 /*(Memory DMA Stream 1) */
-#define IRQ_PROG_INTB 38 /* PF Ports F (PF15:0) Interrupt B */
-#define IRQ_WATCH 38 /*Watch Dog Timer */
-
-#define IRQ_PPI_ERROR 42 /*PPI Error Interrupt */
-#define IRQ_CAN_ERROR 43 /*CAN Error Interrupt */
-#define IRQ_MAC_ERROR 44 /*MAC Status/Error Interrupt */
-#define IRQ_SPORT0_ERROR 45 /*SPORT0 Error Interrupt */
-#define IRQ_SPORT1_ERROR 46 /*SPORT1 Error Interrupt */
-#define IRQ_SPI_ERROR 47 /*SPI Error Interrupt */
-#define IRQ_UART0_ERROR 48 /*UART Error Interrupt */
-#define IRQ_UART1_ERROR 49 /*UART Error Interrupt */
-
-#define IRQ_PF0 50
-#define IRQ_PF1 51
-#define IRQ_PF2 52
-#define IRQ_PF3 53
-#define IRQ_PF4 54
-#define IRQ_PF5 55
-#define IRQ_PF6 56
-#define IRQ_PF7 57
-#define IRQ_PF8 58
-#define IRQ_PF9 59
-#define IRQ_PF10 60
-#define IRQ_PF11 61
-#define IRQ_PF12 62
-#define IRQ_PF13 63
-#define IRQ_PF14 64
-#define IRQ_PF15 65
-
-#define IRQ_PG0 66
-#define IRQ_PG1 67
-#define IRQ_PG2 68
-#define IRQ_PG3 69
-#define IRQ_PG4 70
-#define IRQ_PG5 71
-#define IRQ_PG6 72
-#define IRQ_PG7 73
-#define IRQ_PG8 74
-#define IRQ_PG9 75
-#define IRQ_PG10 76
-#define IRQ_PG11 77
-#define IRQ_PG12 78
-#define IRQ_PG13 79
-#define IRQ_PG14 80
-#define IRQ_PG15 81
-
-#define IRQ_PH0 82
-#define IRQ_PH1 83
-#define IRQ_PH2 84
-#define IRQ_PH3 85
-#define IRQ_PH4 86
-#define IRQ_PH5 87
-#define IRQ_PH6 88
-#define IRQ_PH7 89
-#define IRQ_PH8 90
-#define IRQ_PH9 91
-#define IRQ_PH10 92
-#define IRQ_PH11 93
-#define IRQ_PH12 94
-#define IRQ_PH13 95
-#define IRQ_PH14 96
-#define IRQ_PH15 97
-
-#define GPIO_IRQ_BASE IRQ_PF0
-
-#define IRQ_MAC_PHYINT 98 /* PHY_INT Interrupt */
-#define IRQ_MAC_MMCINT 99 /* MMC Counter Interrupt */
-#define IRQ_MAC_RXFSINT 100 /* RX Frame-Status Interrupt */
-#define IRQ_MAC_TXFSINT 101 /* TX Frame-Status Interrupt */
-#define IRQ_MAC_WAKEDET 102 /* Wake-Up Interrupt */
-#define IRQ_MAC_RXDMAERR 103 /* RX DMA Direction Error Interrupt */
-#define IRQ_MAC_TXDMAERR 104 /* TX DMA Direction Error Interrupt */
-#define IRQ_MAC_STMDONE 105 /* Station Mgt. Transfer Done Interrupt */
-
-#define NR_MACH_IRQS (IRQ_MAC_STMDONE + 1)
-#define NR_IRQS (NR_MACH_IRQS + NR_SPARE_IRQS)
-
-#define IVG7 7
-#define IVG8 8
-#define IVG9 9
-#define IVG10 10
-#define IVG11 11
-#define IVG12 12
-#define IVG13 13
-#define IVG14 14
-#define IVG15 15
-
-/* IAR0 BIT FIELDS*/
-#define IRQ_PLL_WAKEUP_POS 0
-#define IRQ_DMA_ERROR_POS 4
-#define IRQ_ERROR_POS 8
-#define IRQ_RTC_POS 12
-#define IRQ_PPI_POS 16
-#define IRQ_SPORT0_RX_POS 20
-#define IRQ_SPORT0_TX_POS 24
-#define IRQ_SPORT1_RX_POS 28
-
-/* IAR1 BIT FIELDS*/
-#define IRQ_SPORT1_TX_POS 0
-#define IRQ_TWI_POS 4
-#define IRQ_SPI_POS 8
-#define IRQ_UART0_RX_POS 12
-#define IRQ_UART0_TX_POS 16
-#define IRQ_UART1_RX_POS 20
-#define IRQ_UART1_TX_POS 24
-#define IRQ_CAN_RX_POS 28
-
-/* IAR2 BIT FIELDS*/
-#define IRQ_CAN_TX_POS 0
-#define IRQ_MAC_RX_POS 4
-#define IRQ_MAC_TX_POS 8
-#define IRQ_TIMER0_POS 12
-#define IRQ_TIMER1_POS 16
-#define IRQ_TIMER2_POS 20
-#define IRQ_TIMER3_POS 24
-#define IRQ_TIMER4_POS 28
-
-/* IAR3 BIT FIELDS*/
-#define IRQ_TIMER5_POS 0
-#define IRQ_TIMER6_POS 4
-#define IRQ_TIMER7_POS 8
-#define IRQ_PROG_INTA_POS 12
-#define IRQ_PORTG_INTB_POS 16
-#define IRQ_MEM_DMA0_POS 20
-#define IRQ_MEM_DMA1_POS 24
-#define IRQ_WATCH_POS 28
-
-#endif /* _BF537_IRQ_H_ */
+#include <mach-common/irq.h>
+
+#define NR_PERI_INTS 32
+
+#define IRQ_PLL_WAKEUP BFIN_IRQ(0) /* PLL Wakeup Interrupt */
+#define IRQ_DMA_ERROR BFIN_IRQ(1) /* DMA Error (general) */
+#define IRQ_GENERIC_ERROR BFIN_IRQ(2) /* GENERIC Error Interrupt */
+#define IRQ_RTC BFIN_IRQ(3) /* RTC Interrupt */
+#define IRQ_PPI BFIN_IRQ(4) /* DMA0 Interrupt (PPI) */
+#define IRQ_SPORT0_RX BFIN_IRQ(5) /* DMA3 Interrupt (SPORT0 RX) */
+#define IRQ_SPORT0_TX BFIN_IRQ(6) /* DMA4 Interrupt (SPORT0 TX) */
+#define IRQ_SPORT1_RX BFIN_IRQ(7) /* DMA5 Interrupt (SPORT1 RX) */
+#define IRQ_SPORT1_TX BFIN_IRQ(8) /* DMA6 Interrupt (SPORT1 TX) */
+#define IRQ_TWI BFIN_IRQ(9) /* TWI Interrupt */
+#define IRQ_SPI BFIN_IRQ(10) /* DMA7 Interrupt (SPI) */
+#define IRQ_UART0_RX BFIN_IRQ(11) /* DMA8 Interrupt (UART0 RX) */
+#define IRQ_UART0_TX BFIN_IRQ(12) /* DMA9 Interrupt (UART0 TX) */
+#define IRQ_UART1_RX BFIN_IRQ(13) /* DMA10 Interrupt (UART1 RX) */
+#define IRQ_UART1_TX BFIN_IRQ(14) /* DMA11 Interrupt (UART1 TX) */
+#define IRQ_CAN_RX BFIN_IRQ(15) /* CAN Receive Interrupt */
+#define IRQ_CAN_TX BFIN_IRQ(16) /* CAN Transmit Interrupt */
+#define IRQ_PH_INTA_MAC_RX BFIN_IRQ(17) /* Port H Interrupt A & DMA1 Interrupt (Ethernet RX) */
+#define IRQ_PH_INTB_MAC_TX BFIN_IRQ(18) /* Port H Interrupt B & DMA2 Interrupt (Ethernet TX) */
+#define IRQ_TIMER0 BFIN_IRQ(19) /* Timer 0 */
+#define IRQ_TIMER1 BFIN_IRQ(20) /* Timer 1 */
+#define IRQ_TIMER2 BFIN_IRQ(21) /* Timer 2 */
+#define IRQ_TIMER3 BFIN_IRQ(22) /* Timer 3 */
+#define IRQ_TIMER4 BFIN_IRQ(23) /* Timer 4 */
+#define IRQ_TIMER5 BFIN_IRQ(24) /* Timer 5 */
+#define IRQ_TIMER6 BFIN_IRQ(25) /* Timer 6 */
+#define IRQ_TIMER7 BFIN_IRQ(26) /* Timer 7 */
+#define IRQ_PF_INTA_PG_INTA BFIN_IRQ(27) /* Ports F&G Interrupt A */
+#define IRQ_PORTG_INTB BFIN_IRQ(28) /* Port G Interrupt B */
+#define IRQ_MEM_DMA0 BFIN_IRQ(29) /* (Memory DMA Stream 0) */
+#define IRQ_MEM_DMA1 BFIN_IRQ(30) /* (Memory DMA Stream 1) */
+#define IRQ_PF_INTB_WATCH BFIN_IRQ(31) /* Watchdog & Port F Interrupt B */
+
+#define SYS_IRQS 39
+
+#define IRQ_PPI_ERROR 42 /* PPI Error Interrupt */
+#define IRQ_CAN_ERROR 43 /* CAN Error Interrupt */
+#define IRQ_MAC_ERROR 44 /* MAC Status/Error Interrupt */
+#define IRQ_SPORT0_ERROR 45 /* SPORT0 Error Interrupt */
+#define IRQ_SPORT1_ERROR 46 /* SPORT1 Error Interrupt */
+#define IRQ_SPI_ERROR 47 /* SPI Error Interrupt */
+#define IRQ_UART0_ERROR 48 /* UART Error Interrupt */
+#define IRQ_UART1_ERROR 49 /* UART Error Interrupt */
+
+#define IRQ_PF0 50
+#define IRQ_PF1 51
+#define IRQ_PF2 52
+#define IRQ_PF3 53
+#define IRQ_PF4 54
+#define IRQ_PF5 55
+#define IRQ_PF6 56
+#define IRQ_PF7 57
+#define IRQ_PF8 58
+#define IRQ_PF9 59
+#define IRQ_PF10 60
+#define IRQ_PF11 61
+#define IRQ_PF12 62
+#define IRQ_PF13 63
+#define IRQ_PF14 64
+#define IRQ_PF15 65
+
+#define IRQ_PG0 66
+#define IRQ_PG1 67
+#define IRQ_PG2 68
+#define IRQ_PG3 69
+#define IRQ_PG4 70
+#define IRQ_PG5 71
+#define IRQ_PG6 72
+#define IRQ_PG7 73
+#define IRQ_PG8 74
+#define IRQ_PG9 75
+#define IRQ_PG10 76
+#define IRQ_PG11 77
+#define IRQ_PG12 78
+#define IRQ_PG13 79
+#define IRQ_PG14 80
+#define IRQ_PG15 81
+
+#define IRQ_PH0 82
+#define IRQ_PH1 83
+#define IRQ_PH2 84
+#define IRQ_PH3 85
+#define IRQ_PH4 86
+#define IRQ_PH5 87
+#define IRQ_PH6 88
+#define IRQ_PH7 89
+#define IRQ_PH8 90
+#define IRQ_PH9 91
+#define IRQ_PH10 92
+#define IRQ_PH11 93
+#define IRQ_PH12 94
+#define IRQ_PH13 95
+#define IRQ_PH14 96
+#define IRQ_PH15 97
+
+#define GPIO_IRQ_BASE IRQ_PF0
+
+#define IRQ_MAC_PHYINT 98 /* PHY_INT Interrupt */
+#define IRQ_MAC_MMCINT 99 /* MMC Counter Interrupt */
+#define IRQ_MAC_RXFSINT 100 /* RX Frame-Status Interrupt */
+#define IRQ_MAC_TXFSINT 101 /* TX Frame-Status Interrupt */
+#define IRQ_MAC_WAKEDET 102 /* Wake-Up Interrupt */
+#define IRQ_MAC_RXDMAERR 103 /* RX DMA Direction Error Interrupt */
+#define IRQ_MAC_TXDMAERR 104 /* TX DMA Direction Error Interrupt */
+#define IRQ_MAC_STMDONE 105 /* Station Mgt. Transfer Done Interrupt */
+
+#define IRQ_MAC_RX 106 /* DMA1 Interrupt (Ethernet RX) */
+#define IRQ_PORTH_INTA 107 /* Port H Interrupt A */
+
+#if 0 /* No Interrupt B support (yet) */
+#define IRQ_MAC_TX 108 /* DMA2 Interrupt (Ethernet TX) */
+#define IRQ_PORTH_INTB 109 /* Port H Interrupt B */
+#else
+#define IRQ_MAC_TX IRQ_PH_INTB_MAC_TX
+#endif
+
+#define IRQ_PORTF_INTA 110 /* Port F Interrupt A */
+#define IRQ_PORTG_INTA 111 /* Port G Interrupt A */
+
+#if 0 /* No Interrupt B support (yet) */
+#define IRQ_WATCH 112 /* Watchdog Timer */
+#define IRQ_PORTF_INTB 113 /* Port F Interrupt B */
+#else
+#define IRQ_WATCH IRQ_PF_INTB_WATCH
+#endif
+
+#define NR_MACH_IRQS (113 + 1)
+
+/* IAR0 BIT FIELDS */
+#define IRQ_PLL_WAKEUP_POS 0
+#define IRQ_DMA_ERROR_POS 4
+#define IRQ_ERROR_POS 8
+#define IRQ_RTC_POS 12
+#define IRQ_PPI_POS 16
+#define IRQ_SPORT0_RX_POS 20
+#define IRQ_SPORT0_TX_POS 24
+#define IRQ_SPORT1_RX_POS 28
+
+/* IAR1 BIT FIELDS */
+#define IRQ_SPORT1_TX_POS 0
+#define IRQ_TWI_POS 4
+#define IRQ_SPI_POS 8
+#define IRQ_UART0_RX_POS 12
+#define IRQ_UART0_TX_POS 16
+#define IRQ_UART1_RX_POS 20
+#define IRQ_UART1_TX_POS 24
+#define IRQ_CAN_RX_POS 28
+
+/* IAR2 BIT FIELDS */
+#define IRQ_CAN_TX_POS 0
+#define IRQ_MAC_RX_POS 4
+#define IRQ_MAC_TX_POS 8
+#define IRQ_TIMER0_POS 12
+#define IRQ_TIMER1_POS 16
+#define IRQ_TIMER2_POS 20
+#define IRQ_TIMER3_POS 24
+#define IRQ_TIMER4_POS 28
+
+/* IAR3 BIT FIELDS */
+#define IRQ_TIMER5_POS 0
+#define IRQ_TIMER6_POS 4
+#define IRQ_TIMER7_POS 8
+#define IRQ_PROG_INTA_POS 12
+#define IRQ_PORTG_INTB_POS 16
+#define IRQ_MEM_DMA0_POS 20
+#define IRQ_MEM_DMA1_POS 24
+#define IRQ_WATCH_POS 28
+
+#define init_mach_irq init_mach_irq
+
+#endif
diff --git a/arch/blackfin/mach-bf537/ints-priority.c b/arch/blackfin/mach-bf537/ints-priority.c
index f6500622b35d..2137a209a22b 100644
--- a/arch/blackfin/mach-bf537/ints-priority.c
+++ b/arch/blackfin/mach-bf537/ints-priority.c
@@ -10,6 +10,13 @@
#include <linux/irq.h>
#include <asm/blackfin.h>
+#include <asm/irq_handler.h>
+#include <asm/bfin5xx_spi.h>
+#include <asm/bfin_sport.h>
+#include <asm/bfin_can.h>
+#include <asm/bfin_dma.h>
+#include <asm/dpmc.h>
+
void __init program_IAR(void)
{
/* Program the IAR0 Register with the configured priority */
@@ -51,3 +58,159 @@ void __init program_IAR(void)
SSYNC();
}
+
+#define SPI_ERR_MASK (BIT_STAT_TXCOL | BIT_STAT_RBSY | BIT_STAT_MODF | BIT_STAT_TXE) /* SPI_STAT */
+#define SPORT_ERR_MASK (ROVF | RUVF | TOVF | TUVF) /* SPORT_STAT */
+#define PPI_ERR_MASK (0xFFFF & ~FLD) /* PPI_STATUS */
+#define EMAC_ERR_MASK (PHYINT | MMCINT | RXFSINT | TXFSINT | WAKEDET | RXDMAERR | TXDMAERR | STMDONE) /* EMAC_SYSTAT */
+#define UART_ERR_MASK (0x6) /* UART_IIR */
+#define CAN_ERR_MASK (EWTIF | EWRIF | EPIF | BOIF | WUIF | UIAIF | AAIF | RMLIF | UCEIF | EXTIF | ADIF) /* CAN_GIF */
+
+static int error_int_mask;
+
+static void bf537_generic_error_mask_irq(struct irq_data *d)
+{
+ error_int_mask &= ~(1L << (d->irq - IRQ_PPI_ERROR));
+ if (!error_int_mask)
+ bfin_internal_mask_irq(IRQ_GENERIC_ERROR);
+}
+
+static void bf537_generic_error_unmask_irq(struct irq_data *d)
+{
+ bfin_internal_unmask_irq(IRQ_GENERIC_ERROR);
+ error_int_mask |= 1L << (d->irq - IRQ_PPI_ERROR);
+}
+
+static struct irq_chip bf537_generic_error_irqchip = {
+ .name = "ERROR",
+ .irq_ack = bfin_ack_noop,
+ .irq_mask_ack = bf537_generic_error_mask_irq,
+ .irq_mask = bf537_generic_error_mask_irq,
+ .irq_unmask = bf537_generic_error_unmask_irq,
+};
+
+static void bf537_demux_error_irq(unsigned int int_err_irq,
+ struct irq_desc *inta_desc)
+{
+ int irq = 0;
+
+#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
+ if (bfin_read_EMAC_SYSTAT() & EMAC_ERR_MASK)
+ irq = IRQ_MAC_ERROR;
+ else
+#endif
+ if (bfin_read_SPORT0_STAT() & SPORT_ERR_MASK)
+ irq = IRQ_SPORT0_ERROR;
+ else if (bfin_read_SPORT1_STAT() & SPORT_ERR_MASK)
+ irq = IRQ_SPORT1_ERROR;
+ else if (bfin_read_PPI_STATUS() & PPI_ERR_MASK)
+ irq = IRQ_PPI_ERROR;
+ else if (bfin_read_CAN_GIF() & CAN_ERR_MASK)
+ irq = IRQ_CAN_ERROR;
+ else if (bfin_read_SPI_STAT() & SPI_ERR_MASK)
+ irq = IRQ_SPI_ERROR;
+ else if ((bfin_read_UART0_IIR() & UART_ERR_MASK) == UART_ERR_MASK)
+ irq = IRQ_UART0_ERROR;
+ else if ((bfin_read_UART1_IIR() & UART_ERR_MASK) == UART_ERR_MASK)
+ irq = IRQ_UART1_ERROR;
+
+ if (irq) {
+ if (error_int_mask & (1L << (irq - IRQ_PPI_ERROR)))
+ bfin_handle_irq(irq);
+ else {
+
+ switch (irq) {
+ case IRQ_PPI_ERROR:
+ bfin_write_PPI_STATUS(PPI_ERR_MASK);
+ break;
+#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
+ case IRQ_MAC_ERROR:
+ bfin_write_EMAC_SYSTAT(EMAC_ERR_MASK);
+ break;
+#endif
+ case IRQ_SPORT0_ERROR:
+ bfin_write_SPORT0_STAT(SPORT_ERR_MASK);
+ break;
+
+ case IRQ_SPORT1_ERROR:
+ bfin_write_SPORT1_STAT(SPORT_ERR_MASK);
+ break;
+
+ case IRQ_CAN_ERROR:
+ bfin_write_CAN_GIS(CAN_ERR_MASK);
+ break;
+
+ case IRQ_SPI_ERROR:
+ bfin_write_SPI_STAT(SPI_ERR_MASK);
+ break;
+
+ default:
+ break;
+ }
+
+ pr_debug("IRQ %d:"
+ " MASKED PERIPHERAL ERROR INTERRUPT ASSERTED\n",
+ irq);
+ }
+ } else
+ pr_err("%s: IRQ ?: PERIPHERAL ERROR INTERRUPT ASSERTED BUT NO SOURCE FOUND\n",
+ __func__);
+
+}
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+static int mac_rx_int_mask;
+
+static void bf537_mac_rx_mask_irq(struct irq_data *d)
+{
+ mac_rx_int_mask &= ~(1L << (d->irq - IRQ_MAC_RX));
+ if (!mac_rx_int_mask)
+ bfin_internal_mask_irq(IRQ_PH_INTA_MAC_RX);
+}
+
+static void bf537_mac_rx_unmask_irq(struct irq_data *d)
+{
+ bfin_internal_unmask_irq(IRQ_PH_INTA_MAC_RX);
+ mac_rx_int_mask |= 1L << (d->irq - IRQ_MAC_RX);
+}
+
+static struct irq_chip bf537_mac_rx_irqchip = {
+ .name = "ERROR",
+ .irq_ack = bfin_ack_noop,
+ .irq_mask_ack = bf537_mac_rx_mask_irq,
+ .irq_mask = bf537_mac_rx_mask_irq,
+ .irq_unmask = bf537_mac_rx_unmask_irq,
+};
+
+static void bf537_demux_mac_rx_irq(unsigned int int_irq,
+ struct irq_desc *desc)
+{
+ if (bfin_read_DMA1_IRQ_STATUS() & (DMA_DONE | DMA_ERR))
+ bfin_handle_irq(IRQ_MAC_RX);
+ else
+ bfin_demux_gpio_irq(int_irq, desc);
+}
+#endif
+
+void __init init_mach_irq(void)
+{
+ int irq;
+
+#if defined(CONFIG_BF537) || defined(CONFIG_BF536)
+ /* Clear EMAC Interrupt Status bits so we can demux it later */
+ bfin_write_EMAC_SYSTAT(-1);
+#endif
+
+ irq_set_chained_handler(IRQ_GENERIC_ERROR, bf537_demux_error_irq);
+ for (irq = IRQ_PPI_ERROR; irq <= IRQ_UART1_ERROR; irq++)
+ irq_set_chip_and_handler(irq, &bf537_generic_error_irqchip,
+ handle_level_irq);
+
+#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
+ irq_set_chained_handler(IRQ_PH_INTA_MAC_RX, bf537_demux_mac_rx_irq);
+ irq_set_chip_and_handler(IRQ_MAC_RX, &bf537_mac_rx_irqchip, handle_level_irq);
+ irq_set_chip_and_handler(IRQ_PORTH_INTA, &bf537_mac_rx_irqchip, handle_level_irq);
+
+ irq_set_chained_handler(IRQ_MAC_ERROR, bfin_demux_mac_status_irq);
+#endif
+}
diff --git a/arch/blackfin/mach-bf538/include/mach/anomaly.h b/arch/blackfin/mach-bf538/include/mach/anomaly.h
index 8774b481c78e..55e7d0712a94 100644
--- a/arch/blackfin/mach-bf538/include/mach/anomaly.h
+++ b/arch/blackfin/mach-bf538/include/mach/anomaly.h
@@ -5,14 +5,14 @@
* and can be replaced with that version at any time
* DO NOT EDIT THIS FILE
*
- * Copyright 2004-2010 Analog Devices Inc.
+ * Copyright 2004-2011 Analog Devices Inc.
* Licensed under the ADI BSD license.
* https://docs.blackfin.uclinux.org/doku.php?id=adi_bsd
*/
/* This file should be up to date with:
- * - Revision H, 07/10/2009; ADSP-BF538/BF538F Blackfin Processor Anomaly List
- * - Revision M, 07/10/2009; ADSP-BF539/BF539F Blackfin Processor Anomaly List
+ * - Revision I, 05/25/2010; ADSP-BF538/BF538F Blackfin Processor Anomaly List
+ * - Revision N, 05/25/2010; ADSP-BF539/BF539F Blackfin Processor Anomaly List
*/
#ifndef _MACH_ANOMALY_H_
@@ -179,6 +179,7 @@
#define ANOMALY_05000363 (0)
#define ANOMALY_05000364 (0)
#define ANOMALY_05000380 (0)
+#define ANOMALY_05000383 (0)
#define ANOMALY_05000386 (1)
#define ANOMALY_05000389 (0)
#define ANOMALY_05000400 (0)
@@ -186,6 +187,7 @@
#define ANOMALY_05000430 (0)
#define ANOMALY_05000432 (0)
#define ANOMALY_05000435 (0)
+#define ANOMALY_05000440 (0)
#define ANOMALY_05000447 (0)
#define ANOMALY_05000448 (0)
#define ANOMALY_05000456 (0)
@@ -193,6 +195,7 @@
#define ANOMALY_05000465 (0)
#define ANOMALY_05000467 (0)
#define ANOMALY_05000474 (0)
+#define ANOMALY_05000480 (0)
#define ANOMALY_05000485 (0)
#endif
diff --git a/arch/blackfin/mach-bf538/include/mach/irq.h b/arch/blackfin/mach-bf538/include/mach/irq.h
index 7a479d224dc7..07ca069d37cd 100644
--- a/arch/blackfin/mach-bf538/include/mach/irq.h
+++ b/arch/blackfin/mach-bf538/include/mach/irq.h
@@ -7,38 +7,9 @@
#ifndef _BF538_IRQ_H_
#define _BF538_IRQ_H_
-/*
- * Interrupt source definitions
- Event Source Core Event Name
- Core Emulation **
- Events (highest priority) EMU 0
- Reset RST 1
- NMI NMI 2
- Exception EVX 3
- Reserved -- 4
- Hardware Error IVHW 5
- Core Timer IVTMR 6 *
-
- .....
-
- Software Interrupt 1 IVG14 31
- Software Interrupt 2 --
- (lowest priority) IVG15 32 *
-*/
-
-#define NR_PERI_INTS (2 * 32)
-
-/* The ABSTRACT IRQ definitions */
-/** the first seven of the following are fixed, the rest you change if you need to **/
-#define IRQ_EMU 0 /* Emulation */
-#define IRQ_RST 1 /* reset */
-#define IRQ_NMI 2 /* Non Maskable */
-#define IRQ_EVX 3 /* Exception */
-#define IRQ_UNUSED 4 /* - unused interrupt */
-#define IRQ_HWERR 5 /* Hardware Error */
-#define IRQ_CORETMR 6 /* Core timer */
-
-#define BFIN_IRQ(x) ((x) + 7)
+#include <mach-common/irq.h>
+
+#define NR_PERI_INTS (2 * 32)
#define IRQ_PLL_WAKEUP BFIN_IRQ(0) /* PLL Wakeup Interrupt */
#define IRQ_DMA0_ERROR BFIN_IRQ(1) /* DMA Error 0 (generic) */
@@ -91,37 +62,26 @@
#define SYS_IRQS BFIN_IRQ(63) /* 70 */
-#define IRQ_PF0 71
-#define IRQ_PF1 72
-#define IRQ_PF2 73
-#define IRQ_PF3 74
-#define IRQ_PF4 75
-#define IRQ_PF5 76
-#define IRQ_PF6 77
-#define IRQ_PF7 78
-#define IRQ_PF8 79
-#define IRQ_PF9 80
-#define IRQ_PF10 81
-#define IRQ_PF11 82
-#define IRQ_PF12 83
-#define IRQ_PF13 84
-#define IRQ_PF14 85
-#define IRQ_PF15 86
-
-#define GPIO_IRQ_BASE IRQ_PF0
-
-#define NR_MACH_IRQS (IRQ_PF15 + 1)
-#define NR_IRQS (NR_MACH_IRQS + NR_SPARE_IRQS)
-
-#define IVG7 7
-#define IVG8 8
-#define IVG9 9
-#define IVG10 10
-#define IVG11 11
-#define IVG12 12
-#define IVG13 13
-#define IVG14 14
-#define IVG15 15
+#define IRQ_PF0 71
+#define IRQ_PF1 72
+#define IRQ_PF2 73
+#define IRQ_PF3 74
+#define IRQ_PF4 75
+#define IRQ_PF5 76
+#define IRQ_PF6 77
+#define IRQ_PF7 78
+#define IRQ_PF8 79
+#define IRQ_PF9 80
+#define IRQ_PF10 81
+#define IRQ_PF11 82
+#define IRQ_PF12 83
+#define IRQ_PF13 84
+#define IRQ_PF14 85
+#define IRQ_PF15 86
+
+#define GPIO_IRQ_BASE IRQ_PF0
+
+#define NR_MACH_IRQS (IRQ_PF15 + 1)
/* IAR0 BIT FIELDS */
#define IRQ_PLL_WAKEUP_POS 0
@@ -184,4 +144,5 @@
#define IRQ_CAN_TX_POS 0
#define IRQ_MEM1_DMA0_POS 4
#define IRQ_MEM1_DMA1_POS 8
-#endif /* _BF538_IRQ_H_ */
+
+#endif
diff --git a/arch/blackfin/mach-bf548/boards/ezkit.c b/arch/blackfin/mach-bf548/boards/ezkit.c
index 93e19a54a880..311bf9970fe7 100644
--- a/arch/blackfin/mach-bf548/boards/ezkit.c
+++ b/arch/blackfin/mach-bf548/boards/ezkit.c
@@ -22,6 +22,7 @@
#include <asm/gpio.h>
#include <asm/nand.h>
#include <asm/dpmc.h>
+#include <asm/bfin_sport.h>
#include <asm/portmux.h>
#include <asm/bfin_sdh.h>
#include <mach/bf54x_keys.h>
@@ -956,7 +957,15 @@ static struct mtd_partition ezkit_partitions[] = {
.offset = MTDPART_OFS_APPEND,
}, {
.name = "file system(nor)",
- .size = MTDPART_SIZ_FULL,
+ .size = 0x1000000 - 0x80000 - 0x400000 - 0x8000 * 4,
+ .offset = MTDPART_OFS_APPEND,
+ }, {
+ .name = "config(nor)",
+ .size = 0x8000 * 3,
+ .offset = MTDPART_OFS_APPEND,
+ }, {
+ .name = "u-boot env(nor)",
+ .size = 0x8000,
.offset = MTDPART_OFS_APPEND,
}
};
@@ -1312,27 +1321,110 @@ static struct platform_device bfin_dpmc = {
},
};
-#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
+ defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) || \
+ defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+
+#define SPORT_REQ(x) \
+ [x] = {P_SPORT##x##_TFS, P_SPORT##x##_DTPRI, P_SPORT##x##_TSCLK, \
+ P_SPORT##x##_RFS, P_SPORT##x##_DRPRI, P_SPORT##x##_RSCLK, 0}
+
+static const u16 bfin_snd_pin[][7] = {
+ SPORT_REQ(0),
+ SPORT_REQ(1),
+};
+
+static struct bfin_snd_platform_data bfin_snd_data[] = {
+ {
+ .pin_req = &bfin_snd_pin[0][0],
+ },
+ {
+ .pin_req = &bfin_snd_pin[1][0],
+ },
+};
+
+#define BFIN_SND_RES(x) \
+ [x] = { \
+ { \
+ .start = SPORT##x##_TCR1, \
+ .end = SPORT##x##_TCR1, \
+ .flags = IORESOURCE_MEM \
+ }, \
+ { \
+ .start = CH_SPORT##x##_RX, \
+ .end = CH_SPORT##x##_RX, \
+ .flags = IORESOURCE_DMA, \
+ }, \
+ { \
+ .start = CH_SPORT##x##_TX, \
+ .end = CH_SPORT##x##_TX, \
+ .flags = IORESOURCE_DMA, \
+ }, \
+ { \
+ .start = IRQ_SPORT##x##_ERROR, \
+ .end = IRQ_SPORT##x##_ERROR, \
+ .flags = IORESOURCE_IRQ, \
+ } \
+ }
+
+static struct resource bfin_snd_resources[][4] = {
+ BFIN_SND_RES(0),
+ BFIN_SND_RES(1),
+};
+
+static struct platform_device bfin_pcm = {
+ .name = "bfin-pcm-audio",
+ .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_AD73311) || defined(CONFIG_SND_BF5XX_SOC_AD73311_MODULE)
+static struct platform_device bfin_ad73311_codec_device = {
+ .name = "ad73311",
+ .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_AD1980) || defined(CONFIG_SND_BF5XX_SOC_AD1980_MODULE)
+static struct platform_device bfin_ad1980_codec_device = {
+ .name = "ad1980",
+ .id = -1,
+};
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_I2S) || defined(CONFIG_SND_BF5XX_SOC_I2S_MODULE)
static struct platform_device bfin_i2s = {
.name = "bfin-i2s",
.id = CONFIG_SND_BF5XX_SPORT_NUM,
- /* TODO: add platform data here */
+ .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+ .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+ .dev = {
+ .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+ },
};
#endif
-#if defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_TDM) || defined(CONFIG_SND_BF5XX_SOC_TDM_MODULE)
static struct platform_device bfin_tdm = {
.name = "bfin-tdm",
.id = CONFIG_SND_BF5XX_SPORT_NUM,
- /* TODO: add platform data here */
+ .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+ .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+ .dev = {
+ .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+ },
};
#endif
-#if defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+#if defined(CONFIG_SND_BF5XX_SOC_AC97) || defined(CONFIG_SND_BF5XX_SOC_AC97_MODULE)
static struct platform_device bfin_ac97 = {
.name = "bfin-ac97",
.id = CONFIG_SND_BF5XX_SPORT_NUM,
- /* TODO: add platform data here */
+ .num_resources = ARRAY_SIZE(bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM]),
+ .resource = bfin_snd_resources[CONFIG_SND_BF5XX_SPORT_NUM],
+ .dev = {
+ .platform_data = &bfin_snd_data[CONFIG_SND_BF5XX_SPORT_NUM],
+ },
};
#endif
@@ -1450,6 +1542,16 @@ static struct platform_device *ezkit_devices[] __initdata = {
&ezkit_flash_device,
#endif
+#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE) || \
+ defined(CONFIG_SND_BF5XX_TDM) || defined(CONFIG_SND_BF5XX_TDM_MODULE) || \
+ defined(CONFIG_SND_BF5XX_AC97) || defined(CONFIG_SND_BF5XX_AC97_MODULE)
+ &bfin_pcm,
+#endif
+
+#if defined(CONFIG_SND_BF5XX_SOC_AD1980) || defined(CONFIG_SND_BF5XX_SOC_AD1980_MODULE)
+ &bfin_ad1980_codec_device,
+#endif
+
#if defined(CONFIG_SND_BF5XX_I2S) || defined(CONFIG_SND_BF5XX_I2S_MODULE)
&bfin_i2s,
#endif
diff --git a/arch/blackfin/mach-bf548/include/mach/anomaly.h b/arch/blackfin/mach-bf548/include/mach/anomaly.h
index ffd0537295ac..9e70785bdde3 100644
--- a/arch/blackfin/mach-bf548/include/mach/anomaly.h
+++ b/arch/blackfin/mach-bf548/include/mach/anomaly.h
@@ -5,13 +5,13 @@
* and can be replaced with that version at any time
* DO NOT EDIT THIS FILE
*
- * Copyright 2004-2010 Analog Devices Inc.
+ * Copyright 2004-2011 Analog Devices Inc.
* Licensed under the ADI BSD license.
* https://docs.blackfin.uclinux.org/doku.php?id=adi_bsd
*/
/* This file should be up to date with:
- * - Revision I, 07/23/2009; ADSP-BF542/BF544/BF547/BF548/BF549 Blackfin Processor Anomaly List
+ * - Revision J, 06/03/2010; ADSP-BF542/BF544/BF547/BF548/BF549 Blackfin Processor Anomaly List
*/
#ifndef _MACH_ANOMALY_H_
@@ -220,6 +220,8 @@
#define ANOMALY_05000481 (1)
/* Possible USB Data Corruption When Multiple Endpoints Are Accessed by the Core */
#define ANOMALY_05000483 (1)
+/* DDR Trim May Not Be Performed for Certain VLEV Values in OTP Page PBS00L */
+#define ANOMALY_05000484 (__SILICON_REVISION__ < 3)
/* PLL_CTL Change Using bfrom_SysControl() Can Result in Processor Overclocking */
#define ANOMALY_05000485 (__SILICON_REVISION__ >= 2)
/* IFLUSH sucks at life */
@@ -274,6 +276,8 @@
#define ANOMALY_05000412 (0)
#define ANOMALY_05000432 (0)
#define ANOMALY_05000435 (0)
+#define ANOMALY_05000440 (0)
#define ANOMALY_05000475 (0)
+#define ANOMALY_05000480 (0)
#endif
diff --git a/arch/blackfin/mach-bf548/include/mach/irq.h b/arch/blackfin/mach-bf548/include/mach/irq.h
index 7f87787e7738..533b8095b540 100644
--- a/arch/blackfin/mach-bf548/include/mach/irq.h
+++ b/arch/blackfin/mach-bf548/include/mach/irq.h
@@ -7,38 +7,9 @@
#ifndef _BF548_IRQ_H_
#define _BF548_IRQ_H_
-/*
- * Interrupt source definitions
- Event Source Core Event Name
-Core Emulation **
-Events (highest priority) EMU 0
- Reset RST 1
- NMI NMI 2
- Exception EVX 3
- Reserved -- 4
- Hardware Error IVHW 5
- Core Timer IVTMR 6 *
-
-.....
-
- Software Interrupt 1 IVG14 31
- Software Interrupt 2 --
- (lowest priority) IVG15 32 *
- */
-
-#define NR_PERI_INTS (32 * 3)
-
-/* The ABSTRACT IRQ definitions */
-/** the first seven of the following are fixed, the rest you change if you need to **/
-#define IRQ_EMU 0 /* Emulation */
-#define IRQ_RST 1 /* reset */
-#define IRQ_NMI 2 /* Non Maskable */
-#define IRQ_EVX 3 /* Exception */
-#define IRQ_UNUSED 4 /* - unused interrupt*/
-#define IRQ_HWERR 5 /* Hardware Error */
-#define IRQ_CORETMR 6 /* Core timer */
+#include <mach-common/irq.h>
-#define BFIN_IRQ(x) ((x) + 7)
+#define NR_PERI_INTS (3 * 32)
#define IRQ_PLL_WAKEUP BFIN_IRQ(0) /* PLL Wakeup Interrupt */
#define IRQ_DMAC0_ERROR BFIN_IRQ(1) /* DMAC0 Status Interrupt */
@@ -311,49 +282,37 @@ Events (highest priority) EMU 0
#define IRQ_PJ14 BFIN_PJ_IRQ(14) /* N/A */
#define IRQ_PJ15 BFIN_PJ_IRQ(15) /* N/A */
-#define GPIO_IRQ_BASE IRQ_PA0
+#define GPIO_IRQ_BASE IRQ_PA0
-#define NR_MACH_IRQS (IRQ_PJ15 + 1)
-#define NR_IRQS (NR_MACH_IRQS + NR_SPARE_IRQS)
+#define NR_MACH_IRQS (IRQ_PJ15 + 1)
/* For compatibility reasons with existing code */
-#define IRQ_DMAC0_ERR IRQ_DMAC0_ERROR
-#define IRQ_EPPI0_ERR IRQ_EPPI0_ERROR
+#define IRQ_DMAC0_ERR IRQ_DMAC0_ERROR
+#define IRQ_EPPI0_ERR IRQ_EPPI0_ERROR
#define IRQ_SPORT0_ERR IRQ_SPORT0_ERROR
#define IRQ_SPORT1_ERR IRQ_SPORT1_ERROR
-#define IRQ_SPI0_ERR IRQ_SPI0_ERROR
-#define IRQ_UART0_ERR IRQ_UART0_ERROR
-#define IRQ_DMAC1_ERR IRQ_DMAC1_ERROR
+#define IRQ_SPI0_ERR IRQ_SPI0_ERROR
+#define IRQ_UART0_ERR IRQ_UART0_ERROR
+#define IRQ_DMAC1_ERR IRQ_DMAC1_ERROR
#define IRQ_SPORT2_ERR IRQ_SPORT2_ERROR
#define IRQ_SPORT3_ERR IRQ_SPORT3_ERROR
-#define IRQ_SPI1_ERR IRQ_SPI1_ERROR
-#define IRQ_SPI2_ERR IRQ_SPI2_ERROR
-#define IRQ_UART1_ERR IRQ_UART1_ERROR
-#define IRQ_UART2_ERR IRQ_UART2_ERROR
-#define IRQ_CAN0_ERR IRQ_CAN0_ERROR
-#define IRQ_MXVR_ERR IRQ_MXVR_ERROR
-#define IRQ_EPPI1_ERR IRQ_EPPI1_ERROR
-#define IRQ_EPPI2_ERR IRQ_EPPI2_ERROR
-#define IRQ_UART3_ERR IRQ_UART3_ERROR
-#define IRQ_HOST_ERR IRQ_HOST_ERROR
-#define IRQ_PIXC_ERR IRQ_PIXC_ERROR
-#define IRQ_NFC_ERR IRQ_NFC_ERROR
-#define IRQ_ATAPI_ERR IRQ_ATAPI_ERROR
-#define IRQ_CAN1_ERR IRQ_CAN1_ERROR
+#define IRQ_SPI1_ERR IRQ_SPI1_ERROR
+#define IRQ_SPI2_ERR IRQ_SPI2_ERROR
+#define IRQ_UART1_ERR IRQ_UART1_ERROR
+#define IRQ_UART2_ERR IRQ_UART2_ERROR
+#define IRQ_CAN0_ERR IRQ_CAN0_ERROR
+#define IRQ_MXVR_ERR IRQ_MXVR_ERROR
+#define IRQ_EPPI1_ERR IRQ_EPPI1_ERROR
+#define IRQ_EPPI2_ERR IRQ_EPPI2_ERROR
+#define IRQ_UART3_ERR IRQ_UART3_ERROR
+#define IRQ_HOST_ERR IRQ_HOST_ERROR
+#define IRQ_PIXC_ERR IRQ_PIXC_ERROR
+#define IRQ_NFC_ERR IRQ_NFC_ERROR
+#define IRQ_ATAPI_ERR IRQ_ATAPI_ERROR
+#define IRQ_CAN1_ERR IRQ_CAN1_ERROR
#define IRQ_HS_DMA_ERR IRQ_HS_DMA_ERROR
-
-#define IVG7 7
-#define IVG8 8
-#define IVG9 9
-#define IVG10 10
-#define IVG11 11
-#define IVG12 12
-#define IVG13 13
-#define IVG14 14
-#define IVG15 15
-
/* IAR0 BIT FIELDS */
#define IRQ_PLL_WAKEUP_POS 0
#define IRQ_DMAC0_ERR_POS 4
@@ -492,4 +451,4 @@ struct bfin_pint_regs {
#endif
-#endif /* _BF548_IRQ_H_ */
+#endif
diff --git a/arch/blackfin/mach-bf561/boards/ezkit.c b/arch/blackfin/mach-bf561/boards/ezkit.c
index f667e7704197..5067984a62e7 100644
--- a/arch/blackfin/mach-bf561/boards/ezkit.c
+++ b/arch/blackfin/mach-bf561/boards/ezkit.c
@@ -247,7 +247,15 @@ static struct mtd_partition ezkit_partitions[] = {
.offset = MTDPART_OFS_APPEND,
}, {
.name = "file system(nor)",
- .size = MTDPART_SIZ_FULL,
+ .size = 0x800000 - 0x40000 - 0x1C0000 - 0x2000 * 8,
+ .offset = MTDPART_OFS_APPEND,
+ }, {
+ .name = "config(nor)",
+ .size = 0x2000 * 7,
+ .offset = MTDPART_OFS_APPEND,
+ }, {
+ .name = "u-boot env(nor)",
+ .size = 0x2000,
.offset = MTDPART_OFS_APPEND,
}
};
diff --git a/arch/blackfin/mach-bf561/include/mach/anomaly.h b/arch/blackfin/mach-bf561/include/mach/anomaly.h
index 6a3499b02097..22b5ab773027 100644
--- a/arch/blackfin/mach-bf561/include/mach/anomaly.h
+++ b/arch/blackfin/mach-bf561/include/mach/anomaly.h
@@ -5,13 +5,13 @@
* and can be replaced with that version at any time
* DO NOT EDIT THIS FILE
*
- * Copyright 2004-2010 Analog Devices Inc.
+ * Copyright 2004-2011 Analog Devices Inc.
* Licensed under the ADI BSD license.
* https://docs.blackfin.uclinux.org/doku.php?id=adi_bsd
*/
/* This file should be up to date with:
- * - Revision Q, 11/07/2008; ADSP-BF561 Blackfin Processor Anomaly List
+ * - Revision R, 05/25/2010; ADSP-BF561 Blackfin Processor Anomaly List
*/
#ifndef _MACH_ANOMALY_H_
@@ -290,12 +290,18 @@
#define ANOMALY_05000428 (__SILICON_REVISION__ > 3)
/* IFLUSH Instruction at End of Hardware Loop Causes Infinite Stall */
#define ANOMALY_05000443 (1)
+/* SCKELOW Feature Is Not Functional */
+#define ANOMALY_05000458 (1)
/* False Hardware Error when RETI Points to Invalid Memory */
#define ANOMALY_05000461 (1)
+/* Synchronization Problem at Startup May Cause SPORT Transmit Channels to Misalign */
+#define ANOMALY_05000462 (1)
+/* Boot Failure When SDRAM Control Signals Toggle Coming Out Of Reset */
+#define ANOMALY_05000471 (1)
/* Interrupted 32-Bit SPORT Data Register Access Results In Underflow */
#define ANOMALY_05000473 (1)
/* Possible Lockup Condition whem Modifying PLL from External Memory */
-#define ANOMALY_05000475 (__SILICON_REVISION__ < 4)
+#define ANOMALY_05000475 (1)
/* TESTSET Instruction Cannot Be Interrupted */
#define ANOMALY_05000477 (1)
/* Reads of ITEST_COMMAND and ITEST_DATA Registers Cause Cache Corruption */
@@ -314,12 +320,14 @@
#define ANOMALY_05000353 (1)
#define ANOMALY_05000364 (0)
#define ANOMALY_05000380 (0)
+#define ANOMALY_05000383 (0)
#define ANOMALY_05000386 (1)
#define ANOMALY_05000389 (0)
#define ANOMALY_05000400 (0)
#define ANOMALY_05000430 (0)
#define ANOMALY_05000432 (0)
#define ANOMALY_05000435 (0)
+#define ANOMALY_05000440 (0)
#define ANOMALY_05000447 (0)
#define ANOMALY_05000448 (0)
#define ANOMALY_05000456 (0)
@@ -327,6 +335,7 @@
#define ANOMALY_05000465 (0)
#define ANOMALY_05000467 (0)
#define ANOMALY_05000474 (0)
+#define ANOMALY_05000480 (0)
#define ANOMALY_05000485 (0)
#endif
diff --git a/arch/blackfin/mach-bf561/include/mach/irq.h b/arch/blackfin/mach-bf561/include/mach/irq.h
index c95566ade51b..d6998520f70f 100644
--- a/arch/blackfin/mach-bf561/include/mach/irq.h
+++ b/arch/blackfin/mach-bf561/include/mach/irq.h
@@ -7,212 +7,98 @@
#ifndef _BF561_IRQ_H_
#define _BF561_IRQ_H_
-/***********************************************************************
- * Interrupt source definitions:
- Event Source Core Event Name IRQ No
- (highest priority)
- Emulation Events EMU 0
- Reset RST 1
- NMI NMI 2
- Exception EVX 3
- Reserved -- 4
- Hardware Error IVHW 5
- Core Timer IVTMR 6 *
-
- PLL Wakeup Interrupt IVG7 7
- DMA1 Error (generic) IVG7 8
- DMA2 Error (generic) IVG7 9
- IMDMA Error (generic) IVG7 10
- PPI1 Error Interrupt IVG7 11
- PPI2 Error Interrupt IVG7 12
- SPORT0 Error Interrupt IVG7 13
- SPORT1 Error Interrupt IVG7 14
- SPI Error Interrupt IVG7 15
- UART Error Interrupt IVG7 16
- Reserved Interrupt IVG7 17
-
- DMA1 0 Interrupt(PPI1) IVG8 18
- DMA1 1 Interrupt(PPI2) IVG8 19
- DMA1 2 Interrupt IVG8 20
- DMA1 3 Interrupt IVG8 21
- DMA1 4 Interrupt IVG8 22
- DMA1 5 Interrupt IVG8 23
- DMA1 6 Interrupt IVG8 24
- DMA1 7 Interrupt IVG8 25
- DMA1 8 Interrupt IVG8 26
- DMA1 9 Interrupt IVG8 27
- DMA1 10 Interrupt IVG8 28
- DMA1 11 Interrupt IVG8 29
-
- DMA2 0 (SPORT0 RX) IVG9 30
- DMA2 1 (SPORT0 TX) IVG9 31
- DMA2 2 (SPORT1 RX) IVG9 32
- DMA2 3 (SPORT2 TX) IVG9 33
- DMA2 4 (SPI) IVG9 34
- DMA2 5 (UART RX) IVG9 35
- DMA2 6 (UART TX) IVG9 36
- DMA2 7 Interrupt IVG9 37
- DMA2 8 Interrupt IVG9 38
- DMA2 9 Interrupt IVG9 39
- DMA2 10 Interrupt IVG9 40
- DMA2 11 Interrupt IVG9 41
-
- TIMER 0 Interrupt IVG10 42
- TIMER 1 Interrupt IVG10 43
- TIMER 2 Interrupt IVG10 44
- TIMER 3 Interrupt IVG10 45
- TIMER 4 Interrupt IVG10 46
- TIMER 5 Interrupt IVG10 47
- TIMER 6 Interrupt IVG10 48
- TIMER 7 Interrupt IVG10 49
- TIMER 8 Interrupt IVG10 50
- TIMER 9 Interrupt IVG10 51
- TIMER 10 Interrupt IVG10 52
- TIMER 11 Interrupt IVG10 53
-
- Programmable Flags0 A (8) IVG11 54
- Programmable Flags0 B (8) IVG11 55
- Programmable Flags1 A (8) IVG11 56
- Programmable Flags1 B (8) IVG11 57
- Programmable Flags2 A (8) IVG11 58
- Programmable Flags2 B (8) IVG11 59
-
- MDMA1 0 write/read INT IVG8 60
- MDMA1 1 write/read INT IVG8 61
-
- MDMA2 0 write/read INT IVG9 62
- MDMA2 1 write/read INT IVG9 63
-
- IMDMA 0 write/read INT IVG12 64
- IMDMA 1 write/read INT IVG12 65
-
- Watch Dog Timer IVG13 66
-
- Reserved interrupt IVG7 67
- Reserved interrupt IVG7 68
- Supplemental interrupt 0 IVG7 69
- supplemental interrupt 1 IVG7 70
-
- Softirq IVG14
- System Call --
- (lowest priority) IVG15
-
- **********************************************************************/
-
-#define SYS_IRQS 71
-#define NR_PERI_INTS 64
-
-/*
- * The ABSTRACT IRQ definitions
- * the first seven of the following are fixed,
- * the rest you change if you need to.
- */
-/* IVG 0-6*/
-#define IRQ_EMU 0 /* Emulation */
-#define IRQ_RST 1 /* Reset */
-#define IRQ_NMI 2 /* Non Maskable Interrupt */
-#define IRQ_EVX 3 /* Exception */
-#define IRQ_UNUSED 4 /* Reserved interrupt */
-#define IRQ_HWERR 5 /* Hardware Error */
-#define IRQ_CORETMR 6 /* Core timer */
-
-#define IVG_BASE 7
-/* IVG 7 */
-#define IRQ_PLL_WAKEUP (IVG_BASE + 0) /* PLL Wakeup Interrupt */
-#define IRQ_DMA1_ERROR (IVG_BASE + 1) /* DMA1 Error (general) */
-#define IRQ_DMA_ERROR IRQ_DMA1_ERROR /* DMA1 Error (general) */
-#define IRQ_DMA2_ERROR (IVG_BASE + 2) /* DMA2 Error (general) */
-#define IRQ_IMDMA_ERROR (IVG_BASE + 3) /* IMDMA Error Interrupt */
-#define IRQ_PPI1_ERROR (IVG_BASE + 4) /* PPI1 Error Interrupt */
-#define IRQ_PPI_ERROR IRQ_PPI1_ERROR /* PPI1 Error Interrupt */
-#define IRQ_PPI2_ERROR (IVG_BASE + 5) /* PPI2 Error Interrupt */
-#define IRQ_SPORT0_ERROR (IVG_BASE + 6) /* SPORT0 Error Interrupt */
-#define IRQ_SPORT1_ERROR (IVG_BASE + 7) /* SPORT1 Error Interrupt */
-#define IRQ_SPI_ERROR (IVG_BASE + 8) /* SPI Error Interrupt */
-#define IRQ_UART_ERROR (IVG_BASE + 9) /* UART Error Interrupt */
-#define IRQ_RESERVED_ERROR (IVG_BASE + 10) /* Reversed Interrupt */
-/* IVG 8 */
-#define IRQ_DMA1_0 (IVG_BASE + 11) /* DMA1 0 Interrupt(PPI1) */
-#define IRQ_PPI IRQ_DMA1_0 /* DMA1 0 Interrupt(PPI1) */
-#define IRQ_PPI0 IRQ_DMA1_0 /* DMA1 0 Interrupt(PPI1) */
-#define IRQ_DMA1_1 (IVG_BASE + 12) /* DMA1 1 Interrupt(PPI2) */
-#define IRQ_PPI1 IRQ_DMA1_1 /* DMA1 1 Interrupt(PPI2) */
-#define IRQ_DMA1_2 (IVG_BASE + 13) /* DMA1 2 Interrupt */
-#define IRQ_DMA1_3 (IVG_BASE + 14) /* DMA1 3 Interrupt */
-#define IRQ_DMA1_4 (IVG_BASE + 15) /* DMA1 4 Interrupt */
-#define IRQ_DMA1_5 (IVG_BASE + 16) /* DMA1 5 Interrupt */
-#define IRQ_DMA1_6 (IVG_BASE + 17) /* DMA1 6 Interrupt */
-#define IRQ_DMA1_7 (IVG_BASE + 18) /* DMA1 7 Interrupt */
-#define IRQ_DMA1_8 (IVG_BASE + 19) /* DMA1 8 Interrupt */
-#define IRQ_DMA1_9 (IVG_BASE + 20) /* DMA1 9 Interrupt */
-#define IRQ_DMA1_10 (IVG_BASE + 21) /* DMA1 10 Interrupt */
-#define IRQ_DMA1_11 (IVG_BASE + 22) /* DMA1 11 Interrupt */
-/* IVG 9 */
-#define IRQ_DMA2_0 (IVG_BASE + 23) /* DMA2 0 (SPORT0 RX) */
-#define IRQ_SPORT0_RX IRQ_DMA2_0 /* DMA2 0 (SPORT0 RX) */
-#define IRQ_DMA2_1 (IVG_BASE + 24) /* DMA2 1 (SPORT0 TX) */
-#define IRQ_SPORT0_TX IRQ_DMA2_1 /* DMA2 1 (SPORT0 TX) */
-#define IRQ_DMA2_2 (IVG_BASE + 25) /* DMA2 2 (SPORT1 RX) */
-#define IRQ_SPORT1_RX IRQ_DMA2_2 /* DMA2 2 (SPORT1 RX) */
-#define IRQ_DMA2_3 (IVG_BASE + 26) /* DMA2 3 (SPORT2 TX) */
-#define IRQ_SPORT1_TX IRQ_DMA2_3 /* DMA2 3 (SPORT2 TX) */
-#define IRQ_DMA2_4 (IVG_BASE + 27) /* DMA2 4 (SPI) */
-#define IRQ_SPI IRQ_DMA2_4 /* DMA2 4 (SPI) */
-#define IRQ_DMA2_5 (IVG_BASE + 28) /* DMA2 5 (UART RX) */
-#define IRQ_UART_RX IRQ_DMA2_5 /* DMA2 5 (UART RX) */
-#define IRQ_DMA2_6 (IVG_BASE + 29) /* DMA2 6 (UART TX) */
-#define IRQ_UART_TX IRQ_DMA2_6 /* DMA2 6 (UART TX) */
-#define IRQ_DMA2_7 (IVG_BASE + 30) /* DMA2 7 Interrupt */
-#define IRQ_DMA2_8 (IVG_BASE + 31) /* DMA2 8 Interrupt */
-#define IRQ_DMA2_9 (IVG_BASE + 32) /* DMA2 9 Interrupt */
-#define IRQ_DMA2_10 (IVG_BASE + 33) /* DMA2 10 Interrupt */
-#define IRQ_DMA2_11 (IVG_BASE + 34) /* DMA2 11 Interrupt */
-/* IVG 10 */
-#define IRQ_TIMER0 (IVG_BASE + 35) /* TIMER 0 Interrupt */
-#define IRQ_TIMER1 (IVG_BASE + 36) /* TIMER 1 Interrupt */
-#define IRQ_TIMER2 (IVG_BASE + 37) /* TIMER 2 Interrupt */
-#define IRQ_TIMER3 (IVG_BASE + 38) /* TIMER 3 Interrupt */
-#define IRQ_TIMER4 (IVG_BASE + 39) /* TIMER 4 Interrupt */
-#define IRQ_TIMER5 (IVG_BASE + 40) /* TIMER 5 Interrupt */
-#define IRQ_TIMER6 (IVG_BASE + 41) /* TIMER 6 Interrupt */
-#define IRQ_TIMER7 (IVG_BASE + 42) /* TIMER 7 Interrupt */
-#define IRQ_TIMER8 (IVG_BASE + 43) /* TIMER 8 Interrupt */
-#define IRQ_TIMER9 (IVG_BASE + 44) /* TIMER 9 Interrupt */
-#define IRQ_TIMER10 (IVG_BASE + 45) /* TIMER 10 Interrupt */
-#define IRQ_TIMER11 (IVG_BASE + 46) /* TIMER 11 Interrupt */
-/* IVG 11 */
-#define IRQ_PROG0_INTA (IVG_BASE + 47) /* Programmable Flags0 A (8) */
-#define IRQ_PROG_INTA IRQ_PROG0_INTA /* Programmable Flags0 A (8) */
-#define IRQ_PROG0_INTB (IVG_BASE + 48) /* Programmable Flags0 B (8) */
-#define IRQ_PROG_INTB IRQ_PROG0_INTB /* Programmable Flags0 B (8) */
-#define IRQ_PROG1_INTA (IVG_BASE + 49) /* Programmable Flags1 A (8) */
-#define IRQ_PROG1_INTB (IVG_BASE + 50) /* Programmable Flags1 B (8) */
-#define IRQ_PROG2_INTA (IVG_BASE + 51) /* Programmable Flags2 A (8) */
-#define IRQ_PROG2_INTB (IVG_BASE + 52) /* Programmable Flags2 B (8) */
-/* IVG 8 */
-#define IRQ_DMA1_WRRD0 (IVG_BASE + 53) /* MDMA1 0 write/read INT */
-#define IRQ_DMA_WRRD0 IRQ_DMA1_WRRD0 /* MDMA1 0 write/read INT */
+#include <mach-common/irq.h>
+
+#define NR_PERI_INTS (2 * 32)
+
+#define IRQ_PLL_WAKEUP BFIN_IRQ(0) /* PLL Wakeup Interrupt */
+#define IRQ_DMA1_ERROR BFIN_IRQ(1) /* DMA1 Error (general) */
+#define IRQ_DMA_ERROR IRQ_DMA1_ERROR /* DMA1 Error (general) */
+#define IRQ_DMA2_ERROR BFIN_IRQ(2) /* DMA2 Error (general) */
+#define IRQ_IMDMA_ERROR BFIN_IRQ(3) /* IMDMA Error Interrupt */
+#define IRQ_PPI1_ERROR BFIN_IRQ(4) /* PPI1 Error Interrupt */
+#define IRQ_PPI_ERROR IRQ_PPI1_ERROR /* PPI1 Error Interrupt */
+#define IRQ_PPI2_ERROR BFIN_IRQ(5) /* PPI2 Error Interrupt */
+#define IRQ_SPORT0_ERROR BFIN_IRQ(6) /* SPORT0 Error Interrupt */
+#define IRQ_SPORT1_ERROR BFIN_IRQ(7) /* SPORT1 Error Interrupt */
+#define IRQ_SPI_ERROR BFIN_IRQ(8) /* SPI Error Interrupt */
+#define IRQ_UART_ERROR BFIN_IRQ(9) /* UART Error Interrupt */
+#define IRQ_RESERVED_ERROR BFIN_IRQ(10) /* Reversed */
+#define IRQ_DMA1_0 BFIN_IRQ(11) /* DMA1 0 Interrupt(PPI1) */
+#define IRQ_PPI IRQ_DMA1_0 /* DMA1 0 Interrupt(PPI1) */
+#define IRQ_PPI0 IRQ_DMA1_0 /* DMA1 0 Interrupt(PPI1) */
+#define IRQ_DMA1_1 BFIN_IRQ(12) /* DMA1 1 Interrupt(PPI2) */
+#define IRQ_PPI1 IRQ_DMA1_1 /* DMA1 1 Interrupt(PPI2) */
+#define IRQ_DMA1_2 BFIN_IRQ(13) /* DMA1 2 Interrupt */
+#define IRQ_DMA1_3 BFIN_IRQ(14) /* DMA1 3 Interrupt */
+#define IRQ_DMA1_4 BFIN_IRQ(15) /* DMA1 4 Interrupt */
+#define IRQ_DMA1_5 BFIN_IRQ(16) /* DMA1 5 Interrupt */
+#define IRQ_DMA1_6 BFIN_IRQ(17) /* DMA1 6 Interrupt */
+#define IRQ_DMA1_7 BFIN_IRQ(18) /* DMA1 7 Interrupt */
+#define IRQ_DMA1_8 BFIN_IRQ(19) /* DMA1 8 Interrupt */
+#define IRQ_DMA1_9 BFIN_IRQ(20) /* DMA1 9 Interrupt */
+#define IRQ_DMA1_10 BFIN_IRQ(21) /* DMA1 10 Interrupt */
+#define IRQ_DMA1_11 BFIN_IRQ(22) /* DMA1 11 Interrupt */
+#define IRQ_DMA2_0 BFIN_IRQ(23) /* DMA2 0 (SPORT0 RX) */
+#define IRQ_SPORT0_RX IRQ_DMA2_0 /* DMA2 0 (SPORT0 RX) */
+#define IRQ_DMA2_1 BFIN_IRQ(24) /* DMA2 1 (SPORT0 TX) */
+#define IRQ_SPORT0_TX IRQ_DMA2_1 /* DMA2 1 (SPORT0 TX) */
+#define IRQ_DMA2_2 BFIN_IRQ(25) /* DMA2 2 (SPORT1 RX) */
+#define IRQ_SPORT1_RX IRQ_DMA2_2 /* DMA2 2 (SPORT1 RX) */
+#define IRQ_DMA2_3 BFIN_IRQ(26) /* DMA2 3 (SPORT2 TX) */
+#define IRQ_SPORT1_TX IRQ_DMA2_3 /* DMA2 3 (SPORT2 TX) */
+#define IRQ_DMA2_4 BFIN_IRQ(27) /* DMA2 4 (SPI) */
+#define IRQ_SPI IRQ_DMA2_4 /* DMA2 4 (SPI) */
+#define IRQ_DMA2_5 BFIN_IRQ(28) /* DMA2 5 (UART RX) */
+#define IRQ_UART_RX IRQ_DMA2_5 /* DMA2 5 (UART RX) */
+#define IRQ_DMA2_6 BFIN_IRQ(29) /* DMA2 6 (UART TX) */
+#define IRQ_UART_TX IRQ_DMA2_6 /* DMA2 6 (UART TX) */
+#define IRQ_DMA2_7 BFIN_IRQ(30) /* DMA2 7 Interrupt */
+#define IRQ_DMA2_8 BFIN_IRQ(31) /* DMA2 8 Interrupt */
+#define IRQ_DMA2_9 BFIN_IRQ(32) /* DMA2 9 Interrupt */
+#define IRQ_DMA2_10 BFIN_IRQ(33) /* DMA2 10 Interrupt */
+#define IRQ_DMA2_11 BFIN_IRQ(34) /* DMA2 11 Interrupt */
+#define IRQ_TIMER0 BFIN_IRQ(35) /* TIMER 0 Interrupt */
+#define IRQ_TIMER1 BFIN_IRQ(36) /* TIMER 1 Interrupt */
+#define IRQ_TIMER2 BFIN_IRQ(37) /* TIMER 2 Interrupt */
+#define IRQ_TIMER3 BFIN_IRQ(38) /* TIMER 3 Interrupt */
+#define IRQ_TIMER4 BFIN_IRQ(39) /* TIMER 4 Interrupt */
+#define IRQ_TIMER5 BFIN_IRQ(40) /* TIMER 5 Interrupt */
+#define IRQ_TIMER6 BFIN_IRQ(41) /* TIMER 6 Interrupt */
+#define IRQ_TIMER7 BFIN_IRQ(42) /* TIMER 7 Interrupt */
+#define IRQ_TIMER8 BFIN_IRQ(43) /* TIMER 8 Interrupt */
+#define IRQ_TIMER9 BFIN_IRQ(44) /* TIMER 9 Interrupt */
+#define IRQ_TIMER10 BFIN_IRQ(45) /* TIMER 10 Interrupt */
+#define IRQ_TIMER11 BFIN_IRQ(46) /* TIMER 11 Interrupt */
+#define IRQ_PROG0_INTA BFIN_IRQ(47) /* Programmable Flags0 A (8) */
+#define IRQ_PROG_INTA IRQ_PROG0_INTA /* Programmable Flags0 A (8) */
+#define IRQ_PROG0_INTB BFIN_IRQ(48) /* Programmable Flags0 B (8) */
+#define IRQ_PROG_INTB IRQ_PROG0_INTB /* Programmable Flags0 B (8) */
+#define IRQ_PROG1_INTA BFIN_IRQ(49) /* Programmable Flags1 A (8) */
+#define IRQ_PROG1_INTB BFIN_IRQ(50) /* Programmable Flags1 B (8) */
+#define IRQ_PROG2_INTA BFIN_IRQ(51) /* Programmable Flags2 A (8) */
+#define IRQ_PROG2_INTB BFIN_IRQ(52) /* Programmable Flags2 B (8) */
+#define IRQ_DMA1_WRRD0 BFIN_IRQ(53) /* MDMA1 0 write/read INT */
+#define IRQ_DMA_WRRD0 IRQ_DMA1_WRRD0 /* MDMA1 0 write/read INT */
#define IRQ_MEM_DMA0 IRQ_DMA1_WRRD0
-#define IRQ_DMA1_WRRD1 (IVG_BASE + 54) /* MDMA1 1 write/read INT */
-#define IRQ_DMA_WRRD1 IRQ_DMA1_WRRD1 /* MDMA1 1 write/read INT */
+#define IRQ_DMA1_WRRD1 BFIN_IRQ(54) /* MDMA1 1 write/read INT */
+#define IRQ_DMA_WRRD1 IRQ_DMA1_WRRD1 /* MDMA1 1 write/read INT */
#define IRQ_MEM_DMA1 IRQ_DMA1_WRRD1
-/* IVG 9 */
-#define IRQ_DMA2_WRRD0 (IVG_BASE + 55) /* MDMA2 0 write/read INT */
+#define IRQ_DMA2_WRRD0 BFIN_IRQ(55) /* MDMA2 0 write/read INT */
#define IRQ_MEM_DMA2 IRQ_DMA2_WRRD0
-#define IRQ_DMA2_WRRD1 (IVG_BASE + 56) /* MDMA2 1 write/read INT */
+#define IRQ_DMA2_WRRD1 BFIN_IRQ(56) /* MDMA2 1 write/read INT */
#define IRQ_MEM_DMA3 IRQ_DMA2_WRRD1
-/* IVG 12 */
-#define IRQ_IMDMA_WRRD0 (IVG_BASE + 57) /* IMDMA 0 write/read INT */
+#define IRQ_IMDMA_WRRD0 BFIN_IRQ(57) /* IMDMA 0 write/read INT */
#define IRQ_IMEM_DMA0 IRQ_IMDMA_WRRD0
-#define IRQ_IMDMA_WRRD1 (IVG_BASE + 58) /* IMDMA 1 write/read INT */
+#define IRQ_IMDMA_WRRD1 BFIN_IRQ(58) /* IMDMA 1 write/read INT */
#define IRQ_IMEM_DMA1 IRQ_IMDMA_WRRD1
-/* IVG 13 */
-#define IRQ_WATCH (IVG_BASE + 59) /* Watch Dog Timer */
-/* IVG 7 */
-#define IRQ_RESERVED_1 (IVG_BASE + 60) /* Reserved interrupt */
-#define IRQ_RESERVED_2 (IVG_BASE + 61) /* Reserved interrupt */
-#define IRQ_SUPPLE_0 (IVG_BASE + 62) /* Supplemental interrupt 0 */
-#define IRQ_SUPPLE_1 (IVG_BASE + 63) /* supplemental interrupt 1 */
+#define IRQ_WATCH BFIN_IRQ(59) /* Watch Dog Timer */
+#define IRQ_RESERVED_1 BFIN_IRQ(60) /* Reserved interrupt */
+#define IRQ_RESERVED_2 BFIN_IRQ(61) /* Reserved interrupt */
+#define IRQ_SUPPLE_0 BFIN_IRQ(62) /* Supplemental interrupt 0 */
+#define IRQ_SUPPLE_1 BFIN_IRQ(63) /* supplemental interrupt 1 */
+
+#define SYS_IRQS 71
#define IRQ_PF0 73
#define IRQ_PF1 74
@@ -266,158 +152,85 @@
#define GPIO_IRQ_BASE IRQ_PF0
#define NR_MACH_IRQS (IRQ_PF47 + 1)
-#define NR_IRQS (NR_MACH_IRQS + NR_SPARE_IRQS)
-
-#define IVG7 7
-#define IVG8 8
-#define IVG9 9
-#define IVG10 10
-#define IVG11 11
-#define IVG12 12
-#define IVG13 13
-#define IVG14 14
-#define IVG15 15
-
-/*
- * DEFAULT PRIORITIES:
- */
-
-#define CONFIG_DEF_PLL_WAKEUP 7
-#define CONFIG_DEF_DMA1_ERROR 7
-#define CONFIG_DEF_DMA2_ERROR 7
-#define CONFIG_DEF_IMDMA_ERROR 7
-#define CONFIG_DEF_PPI1_ERROR 7
-#define CONFIG_DEF_PPI2_ERROR 7
-#define CONFIG_DEF_SPORT0_ERROR 7
-#define CONFIG_DEF_SPORT1_ERROR 7
-#define CONFIG_DEF_SPI_ERROR 7
-#define CONFIG_DEF_UART_ERROR 7
-#define CONFIG_DEF_RESERVED_ERROR 7
-#define CONFIG_DEF_DMA1_0 8
-#define CONFIG_DEF_DMA1_1 8
-#define CONFIG_DEF_DMA1_2 8
-#define CONFIG_DEF_DMA1_3 8
-#define CONFIG_DEF_DMA1_4 8
-#define CONFIG_DEF_DMA1_5 8
-#define CONFIG_DEF_DMA1_6 8
-#define CONFIG_DEF_DMA1_7 8
-#define CONFIG_DEF_DMA1_8 8
-#define CONFIG_DEF_DMA1_9 8
-#define CONFIG_DEF_DMA1_10 8
-#define CONFIG_DEF_DMA1_11 8
-#define CONFIG_DEF_DMA2_0 9
-#define CONFIG_DEF_DMA2_1 9
-#define CONFIG_DEF_DMA2_2 9
-#define CONFIG_DEF_DMA2_3 9
-#define CONFIG_DEF_DMA2_4 9
-#define CONFIG_DEF_DMA2_5 9
-#define CONFIG_DEF_DMA2_6 9
-#define CONFIG_DEF_DMA2_7 9
-#define CONFIG_DEF_DMA2_8 9
-#define CONFIG_DEF_DMA2_9 9
-#define CONFIG_DEF_DMA2_10 9
-#define CONFIG_DEF_DMA2_11 9
-#define CONFIG_DEF_TIMER0 10
-#define CONFIG_DEF_TIMER1 10
-#define CONFIG_DEF_TIMER2 10
-#define CONFIG_DEF_TIMER3 10
-#define CONFIG_DEF_TIMER4 10
-#define CONFIG_DEF_TIMER5 10
-#define CONFIG_DEF_TIMER6 10
-#define CONFIG_DEF_TIMER7 10
-#define CONFIG_DEF_TIMER8 10
-#define CONFIG_DEF_TIMER9 10
-#define CONFIG_DEF_TIMER10 10
-#define CONFIG_DEF_TIMER11 10
-#define CONFIG_DEF_PROG0_INTA 11
-#define CONFIG_DEF_PROG0_INTB 11
-#define CONFIG_DEF_PROG1_INTA 11
-#define CONFIG_DEF_PROG1_INTB 11
-#define CONFIG_DEF_PROG2_INTA 11
-#define CONFIG_DEF_PROG2_INTB 11
-#define CONFIG_DEF_DMA1_WRRD0 8
-#define CONFIG_DEF_DMA1_WRRD1 8
-#define CONFIG_DEF_DMA2_WRRD0 9
-#define CONFIG_DEF_DMA2_WRRD1 9
-#define CONFIG_DEF_IMDMA_WRRD0 12
-#define CONFIG_DEF_IMDMA_WRRD1 12
-#define CONFIG_DEF_WATCH 13
-#define CONFIG_DEF_RESERVED_1 7
-#define CONFIG_DEF_RESERVED_2 7
-#define CONFIG_DEF_SUPPLE_0 7
-#define CONFIG_DEF_SUPPLE_1 7
/* IAR0 BIT FIELDS */
-#define IRQ_PLL_WAKEUP_POS 0
-#define IRQ_DMA1_ERROR_POS 4
-#define IRQ_DMA2_ERROR_POS 8
-#define IRQ_IMDMA_ERROR_POS 12
-#define IRQ_PPI0_ERROR_POS 16
-#define IRQ_PPI1_ERROR_POS 20
-#define IRQ_SPORT0_ERROR_POS 24
-#define IRQ_SPORT1_ERROR_POS 28
+#define IRQ_PLL_WAKEUP_POS 0
+#define IRQ_DMA1_ERROR_POS 4
+#define IRQ_DMA2_ERROR_POS 8
+#define IRQ_IMDMA_ERROR_POS 12
+#define IRQ_PPI0_ERROR_POS 16
+#define IRQ_PPI1_ERROR_POS 20
+#define IRQ_SPORT0_ERROR_POS 24
+#define IRQ_SPORT1_ERROR_POS 28
+
/* IAR1 BIT FIELDS */
-#define IRQ_SPI_ERROR_POS 0
-#define IRQ_UART_ERROR_POS 4
-#define IRQ_RESERVED_ERROR_POS 8
-#define IRQ_DMA1_0_POS 12
-#define IRQ_DMA1_1_POS 16
-#define IRQ_DMA1_2_POS 20
-#define IRQ_DMA1_3_POS 24
-#define IRQ_DMA1_4_POS 28
+#define IRQ_SPI_ERROR_POS 0
+#define IRQ_UART_ERROR_POS 4
+#define IRQ_RESERVED_ERROR_POS 8
+#define IRQ_DMA1_0_POS 12
+#define IRQ_DMA1_1_POS 16
+#define IRQ_DMA1_2_POS 20
+#define IRQ_DMA1_3_POS 24
+#define IRQ_DMA1_4_POS 28
+
/* IAR2 BIT FIELDS */
-#define IRQ_DMA1_5_POS 0
-#define IRQ_DMA1_6_POS 4
-#define IRQ_DMA1_7_POS 8
-#define IRQ_DMA1_8_POS 12
-#define IRQ_DMA1_9_POS 16
-#define IRQ_DMA1_10_POS 20
-#define IRQ_DMA1_11_POS 24
-#define IRQ_DMA2_0_POS 28
+#define IRQ_DMA1_5_POS 0
+#define IRQ_DMA1_6_POS 4
+#define IRQ_DMA1_7_POS 8
+#define IRQ_DMA1_8_POS 12
+#define IRQ_DMA1_9_POS 16
+#define IRQ_DMA1_10_POS 20
+#define IRQ_DMA1_11_POS 24
+#define IRQ_DMA2_0_POS 28
+
/* IAR3 BIT FIELDS */
-#define IRQ_DMA2_1_POS 0
-#define IRQ_DMA2_2_POS 4
-#define IRQ_DMA2_3_POS 8
-#define IRQ_DMA2_4_POS 12
-#define IRQ_DMA2_5_POS 16
-#define IRQ_DMA2_6_POS 20
-#define IRQ_DMA2_7_POS 24
-#define IRQ_DMA2_8_POS 28
+#define IRQ_DMA2_1_POS 0
+#define IRQ_DMA2_2_POS 4
+#define IRQ_DMA2_3_POS 8
+#define IRQ_DMA2_4_POS 12
+#define IRQ_DMA2_5_POS 16
+#define IRQ_DMA2_6_POS 20
+#define IRQ_DMA2_7_POS 24
+#define IRQ_DMA2_8_POS 28
+
/* IAR4 BIT FIELDS */
-#define IRQ_DMA2_9_POS 0
-#define IRQ_DMA2_10_POS 4
-#define IRQ_DMA2_11_POS 8
-#define IRQ_TIMER0_POS 12
-#define IRQ_TIMER1_POS 16
-#define IRQ_TIMER2_POS 20
-#define IRQ_TIMER3_POS 24
-#define IRQ_TIMER4_POS 28
+#define IRQ_DMA2_9_POS 0
+#define IRQ_DMA2_10_POS 4
+#define IRQ_DMA2_11_POS 8
+#define IRQ_TIMER0_POS 12
+#define IRQ_TIMER1_POS 16
+#define IRQ_TIMER2_POS 20
+#define IRQ_TIMER3_POS 24
+#define IRQ_TIMER4_POS 28
+
/* IAR5 BIT FIELDS */
-#define IRQ_TIMER5_POS 0
-#define IRQ_TIMER6_POS 4
-#define IRQ_TIMER7_POS 8
-#define IRQ_TIMER8_POS 12
-#define IRQ_TIMER9_POS 16
-#define IRQ_TIMER10_POS 20
-#define IRQ_TIMER11_POS 24
-#define IRQ_PROG0_INTA_POS 28
+#define IRQ_TIMER5_POS 0
+#define IRQ_TIMER6_POS 4
+#define IRQ_TIMER7_POS 8
+#define IRQ_TIMER8_POS 12
+#define IRQ_TIMER9_POS 16
+#define IRQ_TIMER10_POS 20
+#define IRQ_TIMER11_POS 24
+#define IRQ_PROG0_INTA_POS 28
+
/* IAR6 BIT FIELDS */
-#define IRQ_PROG0_INTB_POS 0
-#define IRQ_PROG1_INTA_POS 4
-#define IRQ_PROG1_INTB_POS 8
-#define IRQ_PROG2_INTA_POS 12
-#define IRQ_PROG2_INTB_POS 16
-#define IRQ_DMA1_WRRD0_POS 20
-#define IRQ_DMA1_WRRD1_POS 24
-#define IRQ_DMA2_WRRD0_POS 28
-/* IAR7 BIT FIELDS */
-#define IRQ_DMA2_WRRD1_POS 0
-#define IRQ_IMDMA_WRRD0_POS 4
-#define IRQ_IMDMA_WRRD1_POS 8
-#define IRQ_WDTIMER_POS 12
-#define IRQ_RESERVED_1_POS 16
-#define IRQ_RESERVED_2_POS 20
-#define IRQ_SUPPLE_0_POS 24
-#define IRQ_SUPPLE_1_POS 28
+#define IRQ_PROG0_INTB_POS 0
+#define IRQ_PROG1_INTA_POS 4
+#define IRQ_PROG1_INTB_POS 8
+#define IRQ_PROG2_INTA_POS 12
+#define IRQ_PROG2_INTB_POS 16
+#define IRQ_DMA1_WRRD0_POS 20
+#define IRQ_DMA1_WRRD1_POS 24
+#define IRQ_DMA2_WRRD0_POS 28
-#endif /* _BF561_IRQ_H_ */
+/* IAR7 BIT FIELDS */
+#define IRQ_DMA2_WRRD1_POS 0
+#define IRQ_IMDMA_WRRD0_POS 4
+#define IRQ_IMDMA_WRRD1_POS 8
+#define IRQ_WDTIMER_POS 12
+#define IRQ_RESERVED_1_POS 16
+#define IRQ_RESERVED_2_POS 20
+#define IRQ_SUPPLE_0_POS 24
+#define IRQ_SUPPLE_1_POS 28
+
+#endif
diff --git a/arch/blackfin/mach-bf561/smp.c b/arch/blackfin/mach-bf561/smp.c
index 7b07740cf68c..85abd8be1343 100644
--- a/arch/blackfin/mach-bf561/smp.c
+++ b/arch/blackfin/mach-bf561/smp.c
@@ -24,17 +24,23 @@ static DEFINE_SPINLOCK(boot_lock);
void __init platform_init_cpus(void)
{
- cpu_set(0, cpu_possible_map); /* CoreA */
- cpu_set(1, cpu_possible_map); /* CoreB */
+ struct cpumask mask;
+
+ cpumask_set_cpu(0, &mask); /* CoreA */
+ cpumask_set_cpu(1, &mask); /* CoreB */
+ init_cpu_possible(&mask);
}
void __init platform_prepare_cpus(unsigned int max_cpus)
{
+ struct cpumask mask;
+
bfin_relocate_coreb_l1_mem();
/* Both cores ought to be present on a bf561! */
- cpu_set(0, cpu_present_map); /* CoreA */
- cpu_set(1, cpu_present_map); /* CoreB */
+ cpumask_set_cpu(0, &mask); /* CoreA */
+ cpumask_set_cpu(1, &mask); /* CoreB */
+ init_cpu_present(&mask);
}
int __init setup_profiling_timer(unsigned int multiplier) /* not supported */
@@ -62,9 +68,6 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
bfin_write_SICB_IWR1(IWR_DISABLE_ALL);
SSYNC();
- /* Store CPU-private information to the cpu_data array. */
- bfin_setup_cpudata(cpu);
-
/* We are done with local CPU inits, unblock the boot CPU. */
set_cpu_online(cpu, true);
spin_lock(&boot_lock);
diff --git a/arch/blackfin/mach-common/dpmc.c b/arch/blackfin/mach-common/dpmc.c
index 382099fd5561..f5685a496c58 100644
--- a/arch/blackfin/mach-common/dpmc.c
+++ b/arch/blackfin/mach-common/dpmc.c
@@ -19,9 +19,6 @@
#define DRIVER_NAME "bfin dpmc"
-#define dprintk(msg...) \
- cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, DRIVER_NAME, msg)
-
struct bfin_dpmc_platform_data *pdata;
/**
@@ -88,10 +85,11 @@ static void bfin_wakeup_cpu(void)
{
unsigned int cpu;
unsigned int this_cpu = smp_processor_id();
- cpumask_t mask = cpu_online_map;
+ cpumask_t mask;
- cpu_clear(this_cpu, mask);
- for_each_cpu_mask(cpu, mask)
+ cpumask_copy(&mask, cpu_online_mask);
+ cpumask_clear_cpu(this_cpu, &mask);
+ for_each_cpu(cpu, &mask)
platform_send_ipi_cpu(cpu, IRQ_SUPPLE_0);
}
diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c
index 43d9fb195c1e..1177369f9922 100644
--- a/arch/blackfin/mach-common/ints-priority.c
+++ b/arch/blackfin/mach-common/ints-priority.c
@@ -19,32 +19,14 @@
#ifdef CONFIG_IPIPE
#include <linux/ipipe.h>
#endif
-#ifdef CONFIG_KGDB
-#include <linux/kgdb.h>
-#endif
#include <asm/traps.h>
#include <asm/blackfin.h>
#include <asm/gpio.h>
#include <asm/irq_handler.h>
#include <asm/dpmc.h>
-#include <asm/bfin5xx_spi.h>
-#include <asm/bfin_sport.h>
-#include <asm/bfin_can.h>
#define SIC_SYSIRQ(irq) (irq - (IRQ_CORETMR + 1))
-#ifdef BF537_FAMILY
-# define BF537_GENERIC_ERROR_INT_DEMUX
-# define SPI_ERR_MASK (BIT_STAT_TXCOL | BIT_STAT_RBSY | BIT_STAT_MODF | BIT_STAT_TXE) /* SPI_STAT */
-# define SPORT_ERR_MASK (ROVF | RUVF | TOVF | TUVF) /* SPORT_STAT */
-# define PPI_ERR_MASK (0xFFFF & ~FLD) /* PPI_STATUS */
-# define EMAC_ERR_MASK (PHYINT | MMCINT | RXFSINT | TXFSINT | WAKEDET | RXDMAERR | TXDMAERR | STMDONE) /* EMAC_SYSTAT */
-# define UART_ERR_MASK (0x6) /* UART_IIR */
-# define CAN_ERR_MASK (EWTIF | EWRIF | EPIF | BOIF | WUIF | UIAIF | AAIF | RMLIF | UCEIF | EXTIF | ADIF) /* CAN_GIF */
-#else
-# undef BF537_GENERIC_ERROR_INT_DEMUX
-#endif
-
/*
* NOTES:
* - we have separated the physical Hardware interrupt from the
@@ -63,22 +45,19 @@ unsigned long bfin_irq_flags = 0x1f;
EXPORT_SYMBOL(bfin_irq_flags);
#endif
-/* The number of spurious interrupts */
-atomic_t num_spurious;
-
#ifdef CONFIG_PM
unsigned long bfin_sic_iwr[3]; /* Up to 3 SIC_IWRx registers */
unsigned vr_wakeup;
#endif
-struct ivgx {
+static struct ivgx {
/* irq number for request_irq, available in mach-bf5xx/irq.h */
unsigned int irqno;
/* corresponding bit in the SIC_ISR register */
unsigned int isrflag;
} ivg_table[NR_PERI_INTS];
-struct ivg_slice {
+static struct ivg_slice {
/* position of first irq in ivg_table for given ivg */
struct ivgx *ifirst;
struct ivgx *istop;
@@ -125,7 +104,7 @@ static void __init search_IAR(void)
* This is for core internal IRQs
*/
-static void bfin_ack_noop(struct irq_data *d)
+void bfin_ack_noop(struct irq_data *d)
{
/* Dummy function. */
}
@@ -154,26 +133,24 @@ static void bfin_core_unmask_irq(struct irq_data *d)
return;
}
-static void bfin_internal_mask_irq(unsigned int irq)
+void bfin_internal_mask_irq(unsigned int irq)
{
- unsigned long flags;
+ unsigned long flags = hard_local_irq_save();
-#ifdef CONFIG_BF53x
- flags = hard_local_irq_save();
- bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() &
- ~(1 << SIC_SYSIRQ(irq)));
-#else
- unsigned mask_bank, mask_bit;
- flags = hard_local_irq_save();
- mask_bank = SIC_SYSIRQ(irq) / 32;
- mask_bit = SIC_SYSIRQ(irq) % 32;
+#ifdef SIC_IMASK0
+ unsigned mask_bank = SIC_SYSIRQ(irq) / 32;
+ unsigned mask_bit = SIC_SYSIRQ(irq) % 32;
bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) &
~(1 << mask_bit));
-#ifdef CONFIG_SMP
+# ifdef CONFIG_SMP
bfin_write_SICB_IMASK(mask_bank, bfin_read_SICB_IMASK(mask_bank) &
~(1 << mask_bit));
+# endif
+#else
+ bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() &
+ ~(1 << SIC_SYSIRQ(irq)));
#endif
-#endif
+
hard_local_irq_restore(flags);
}
@@ -186,33 +163,31 @@ static void bfin_internal_mask_irq_chip(struct irq_data *d)
static void bfin_internal_unmask_irq_affinity(unsigned int irq,
const struct cpumask *affinity)
#else
-static void bfin_internal_unmask_irq(unsigned int irq)
+void bfin_internal_unmask_irq(unsigned int irq)
#endif
{
- unsigned long flags;
+ unsigned long flags = hard_local_irq_save();
-#ifdef CONFIG_BF53x
- flags = hard_local_irq_save();
- bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() |
- (1 << SIC_SYSIRQ(irq)));
-#else
- unsigned mask_bank, mask_bit;
- flags = hard_local_irq_save();
- mask_bank = SIC_SYSIRQ(irq) / 32;
- mask_bit = SIC_SYSIRQ(irq) % 32;
-#ifdef CONFIG_SMP
+#ifdef SIC_IMASK0
+ unsigned mask_bank = SIC_SYSIRQ(irq) / 32;
+ unsigned mask_bit = SIC_SYSIRQ(irq) % 32;
+# ifdef CONFIG_SMP
if (cpumask_test_cpu(0, affinity))
-#endif
+# endif
bfin_write_SIC_IMASK(mask_bank,
bfin_read_SIC_IMASK(mask_bank) |
(1 << mask_bit));
-#ifdef CONFIG_SMP
+# ifdef CONFIG_SMP
if (cpumask_test_cpu(1, affinity))
bfin_write_SICB_IMASK(mask_bank,
bfin_read_SICB_IMASK(mask_bank) |
(1 << mask_bit));
+# endif
+#else
+ bfin_write_SIC_IMASK(bfin_read_SIC_IMASK() |
+ (1 << SIC_SYSIRQ(irq)));
#endif
-#endif
+
hard_local_irq_restore(flags);
}
@@ -295,6 +270,8 @@ static int bfin_internal_set_wake_chip(struct irq_data *d, unsigned int state)
{
return bfin_internal_set_wake(d->irq, state);
}
+#else
+# define bfin_internal_set_wake_chip NULL
#endif
static struct irq_chip bfin_core_irqchip = {
@@ -315,12 +292,10 @@ static struct irq_chip bfin_internal_irqchip = {
#ifdef CONFIG_SMP
.irq_set_affinity = bfin_internal_set_affinity,
#endif
-#ifdef CONFIG_PM
.irq_set_wake = bfin_internal_set_wake_chip,
-#endif
};
-static void bfin_handle_irq(unsigned irq)
+void bfin_handle_irq(unsigned irq)
{
#ifdef CONFIG_IPIPE
struct pt_regs regs; /* Contents not used. */
@@ -332,102 +307,6 @@ static void bfin_handle_irq(unsigned irq)
#endif /* !CONFIG_IPIPE */
}
-#ifdef BF537_GENERIC_ERROR_INT_DEMUX
-static int error_int_mask;
-
-static void bfin_generic_error_mask_irq(struct irq_data *d)
-{
- error_int_mask &= ~(1L << (d->irq - IRQ_PPI_ERROR));
- if (!error_int_mask)
- bfin_internal_mask_irq(IRQ_GENERIC_ERROR);
-}
-
-static void bfin_generic_error_unmask_irq(struct irq_data *d)
-{
- bfin_internal_unmask_irq(IRQ_GENERIC_ERROR);
- error_int_mask |= 1L << (d->irq - IRQ_PPI_ERROR);
-}
-
-static struct irq_chip bfin_generic_error_irqchip = {
- .name = "ERROR",
- .irq_ack = bfin_ack_noop,
- .irq_mask_ack = bfin_generic_error_mask_irq,
- .irq_mask = bfin_generic_error_mask_irq,
- .irq_unmask = bfin_generic_error_unmask_irq,
-};
-
-static void bfin_demux_error_irq(unsigned int int_err_irq,
- struct irq_desc *inta_desc)
-{
- int irq = 0;
-
-#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
- if (bfin_read_EMAC_SYSTAT() & EMAC_ERR_MASK)
- irq = IRQ_MAC_ERROR;
- else
-#endif
- if (bfin_read_SPORT0_STAT() & SPORT_ERR_MASK)
- irq = IRQ_SPORT0_ERROR;
- else if (bfin_read_SPORT1_STAT() & SPORT_ERR_MASK)
- irq = IRQ_SPORT1_ERROR;
- else if (bfin_read_PPI_STATUS() & PPI_ERR_MASK)
- irq = IRQ_PPI_ERROR;
- else if (bfin_read_CAN_GIF() & CAN_ERR_MASK)
- irq = IRQ_CAN_ERROR;
- else if (bfin_read_SPI_STAT() & SPI_ERR_MASK)
- irq = IRQ_SPI_ERROR;
- else if ((bfin_read_UART0_IIR() & UART_ERR_MASK) == UART_ERR_MASK)
- irq = IRQ_UART0_ERROR;
- else if ((bfin_read_UART1_IIR() & UART_ERR_MASK) == UART_ERR_MASK)
- irq = IRQ_UART1_ERROR;
-
- if (irq) {
- if (error_int_mask & (1L << (irq - IRQ_PPI_ERROR)))
- bfin_handle_irq(irq);
- else {
-
- switch (irq) {
- case IRQ_PPI_ERROR:
- bfin_write_PPI_STATUS(PPI_ERR_MASK);
- break;
-#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
- case IRQ_MAC_ERROR:
- bfin_write_EMAC_SYSTAT(EMAC_ERR_MASK);
- break;
-#endif
- case IRQ_SPORT0_ERROR:
- bfin_write_SPORT0_STAT(SPORT_ERR_MASK);
- break;
-
- case IRQ_SPORT1_ERROR:
- bfin_write_SPORT1_STAT(SPORT_ERR_MASK);
- break;
-
- case IRQ_CAN_ERROR:
- bfin_write_CAN_GIS(CAN_ERR_MASK);
- break;
-
- case IRQ_SPI_ERROR:
- bfin_write_SPI_STAT(SPI_ERR_MASK);
- break;
-
- default:
- break;
- }
-
- pr_debug("IRQ %d:"
- " MASKED PERIPHERAL ERROR INTERRUPT ASSERTED\n",
- irq);
- }
- } else
- printk(KERN_ERR
- "%s : %s : LINE %d :\nIRQ ?: PERIPHERAL ERROR"
- " INTERRUPT ASSERTED BUT NO SOURCE FOUND\n",
- __func__, __FILE__, __LINE__);
-
-}
-#endif /* BF537_GENERIC_ERROR_INT_DEMUX */
-
#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
static int mac_stat_int_mask;
@@ -468,7 +347,7 @@ static void bfin_mac_status_mask_irq(struct irq_data *d)
unsigned int irq = d->irq;
mac_stat_int_mask &= ~(1L << (irq - IRQ_MAC_PHYINT));
-#ifdef BF537_GENERIC_ERROR_INT_DEMUX
+#ifdef BF537_FAMILY
switch (irq) {
case IRQ_MAC_PHYINT:
bfin_write_EMAC_SYSCTL(bfin_read_EMAC_SYSCTL() & ~PHYIE);
@@ -487,7 +366,7 @@ static void bfin_mac_status_unmask_irq(struct irq_data *d)
{
unsigned int irq = d->irq;
-#ifdef BF537_GENERIC_ERROR_INT_DEMUX
+#ifdef BF537_FAMILY
switch (irq) {
case IRQ_MAC_PHYINT:
bfin_write_EMAC_SYSCTL(bfin_read_EMAC_SYSCTL() | PHYIE);
@@ -505,12 +384,14 @@ static void bfin_mac_status_unmask_irq(struct irq_data *d)
#ifdef CONFIG_PM
int bfin_mac_status_set_wake(struct irq_data *d, unsigned int state)
{
-#ifdef BF537_GENERIC_ERROR_INT_DEMUX
+#ifdef BF537_FAMILY
return bfin_internal_set_wake(IRQ_GENERIC_ERROR, state);
#else
return bfin_internal_set_wake(IRQ_MAC_ERROR, state);
#endif
}
+#else
+# define bfin_mac_status_set_wake NULL
#endif
static struct irq_chip bfin_mac_status_irqchip = {
@@ -519,13 +400,11 @@ static struct irq_chip bfin_mac_status_irqchip = {
.irq_mask_ack = bfin_mac_status_mask_irq,
.irq_mask = bfin_mac_status_mask_irq,
.irq_unmask = bfin_mac_status_unmask_irq,
-#ifdef CONFIG_PM
.irq_set_wake = bfin_mac_status_set_wake,
-#endif
};
-static void bfin_demux_mac_status_irq(unsigned int int_err_irq,
- struct irq_desc *inta_desc)
+void bfin_demux_mac_status_irq(unsigned int int_err_irq,
+ struct irq_desc *inta_desc)
{
int i, irq = 0;
u32 status = bfin_read_EMAC_SYSTAT();
@@ -680,29 +559,48 @@ static int bfin_gpio_irq_type(struct irq_data *d, unsigned int type)
}
#ifdef CONFIG_PM
-int bfin_gpio_set_wake(struct irq_data *d, unsigned int state)
+static int bfin_gpio_set_wake(struct irq_data *d, unsigned int state)
{
return gpio_pm_wakeup_ctrl(irq_to_gpio(d->irq), state);
}
+#else
+# define bfin_gpio_set_wake NULL
#endif
-static void bfin_demux_gpio_irq(unsigned int inta_irq,
- struct irq_desc *desc)
+static void bfin_demux_gpio_block(unsigned int irq)
{
- unsigned int i, gpio, mask, irq, search = 0;
+ unsigned int gpio, mask;
+
+ gpio = irq_to_gpio(irq);
+ mask = get_gpiop_data(gpio) & get_gpiop_maska(gpio);
+
+ while (mask) {
+ if (mask & 1)
+ bfin_handle_irq(irq);
+ irq++;
+ mask >>= 1;
+ }
+}
+
+void bfin_demux_gpio_irq(unsigned int inta_irq,
+ struct irq_desc *desc)
+{
+ unsigned int irq;
switch (inta_irq) {
-#if defined(CONFIG_BF53x)
- case IRQ_PROG_INTA:
- irq = IRQ_PF0;
- search = 1;
+#if defined(BF537_FAMILY)
+ case IRQ_PF_INTA_PG_INTA:
+ bfin_demux_gpio_block(IRQ_PF0);
+ irq = IRQ_PG0;
break;
-# if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
- case IRQ_MAC_RX:
+ case IRQ_PH_INTA_MAC_RX:
irq = IRQ_PH0;
break;
-# endif
-#elif defined(CONFIG_BF538) || defined(CONFIG_BF539)
+#elif defined(BF533_FAMILY)
+ case IRQ_PROG_INTA:
+ irq = IRQ_PF0;
+ break;
+#elif defined(BF538_FAMILY)
case IRQ_PORTF_INTA:
irq = IRQ_PF0;
break;
@@ -732,31 +630,7 @@ static void bfin_demux_gpio_irq(unsigned int inta_irq,
return;
}
- if (search) {
- for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) {
- irq += i;
-
- mask = get_gpiop_data(i) & get_gpiop_maska(i);
-
- while (mask) {
- if (mask & 1)
- bfin_handle_irq(irq);
- irq++;
- mask >>= 1;
- }
- }
- } else {
- gpio = irq_to_gpio(irq);
- mask = get_gpiop_data(gpio) & get_gpiop_maska(gpio);
-
- do {
- if (mask & 1)
- bfin_handle_irq(irq);
- irq++;
- mask >>= 1;
- } while (mask);
- }
-
+ bfin_demux_gpio_block(irq);
}
#else /* CONFIG_BF54x */
@@ -974,15 +848,11 @@ static int bfin_gpio_irq_type(struct irq_data *d, unsigned int type)
}
#ifdef CONFIG_PM
-u32 pint_saved_masks[NR_PINT_SYS_IRQS];
-u32 pint_wakeup_masks[NR_PINT_SYS_IRQS];
-
-int bfin_gpio_set_wake(struct irq_data *d, unsigned int state)
+static int bfin_gpio_set_wake(struct irq_data *d, unsigned int state)
{
u32 pint_irq;
u32 pint_val = irq2pint_lut[d->irq - SYS_IRQS];
u32 bank = PINT_2_BANK(pint_val);
- u32 pintbit = PINT_BIT(pint_val);
switch (bank) {
case 0:
@@ -1003,46 +873,14 @@ int bfin_gpio_set_wake(struct irq_data *d, unsigned int state)
bfin_internal_set_wake(pint_irq, state);
- if (state)
- pint_wakeup_masks[bank] |= pintbit;
- else
- pint_wakeup_masks[bank] &= ~pintbit;
-
return 0;
}
-
-u32 bfin_pm_setup(void)
-{
- u32 val, i;
-
- for (i = 0; i < NR_PINT_SYS_IRQS; i++) {
- val = pint[i]->mask_clear;
- pint_saved_masks[i] = val;
- if (val ^ pint_wakeup_masks[i]) {
- pint[i]->mask_clear = val;
- pint[i]->mask_set = pint_wakeup_masks[i];
- }
- }
-
- return 0;
-}
-
-void bfin_pm_restore(void)
-{
- u32 i, val;
-
- for (i = 0; i < NR_PINT_SYS_IRQS; i++) {
- val = pint_saved_masks[i];
- if (val ^ pint_wakeup_masks[i]) {
- pint[i]->mask_clear = pint[i]->mask_clear;
- pint[i]->mask_set = val;
- }
- }
-}
+#else
+# define bfin_gpio_set_wake NULL
#endif
-static void bfin_demux_gpio_irq(unsigned int inta_irq,
- struct irq_desc *desc)
+void bfin_demux_gpio_irq(unsigned int inta_irq,
+ struct irq_desc *desc)
{
u32 bank, pint_val;
u32 request, irq;
@@ -1091,9 +929,7 @@ static struct irq_chip bfin_gpio_irqchip = {
.irq_set_type = bfin_gpio_irq_type,
.irq_startup = bfin_gpio_irq_startup,
.irq_shutdown = bfin_gpio_irq_shutdown,
-#ifdef CONFIG_PM
.irq_set_wake = bfin_gpio_set_wake,
-#endif
};
void __cpuinit init_exception_vectors(void)
@@ -1127,12 +963,12 @@ int __init init_arch_irq(void)
{
int irq;
unsigned long ilat = 0;
+
/* Disable all the peripheral intrs - page 4-29 HW Ref manual */
-#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561) \
- || defined(BF538_FAMILY) || defined(CONFIG_BF51x)
+#ifdef SIC_IMASK0
bfin_write_SIC_IMASK0(SIC_UNMASK_ALL);
bfin_write_SIC_IMASK1(SIC_UNMASK_ALL);
-# ifdef CONFIG_BF54x
+# ifdef SIC_IMASK2
bfin_write_SIC_IMASK2(SIC_UNMASK_ALL);
# endif
# ifdef CONFIG_SMP
@@ -1145,11 +981,6 @@ int __init init_arch_irq(void)
local_irq_disable();
-#if (defined(CONFIG_BF537) || defined(CONFIG_BF536))
- /* Clear EMAC Interrupt Status bits so we can demux it later */
- bfin_write_EMAC_SYSTAT(-1);
-#endif
-
#ifdef CONFIG_BF54x
# ifdef CONFIG_PINTx_REASSIGN
pint[0]->assign = CONFIG_PINT0_ASSIGN;
@@ -1168,11 +999,11 @@ int __init init_arch_irq(void)
irq_set_chip(irq, &bfin_internal_irqchip);
switch (irq) {
-#if defined(CONFIG_BF53x)
+#if defined(BF537_FAMILY)
+ case IRQ_PH_INTA_MAC_RX:
+ case IRQ_PF_INTA_PG_INTA:
+#elif defined(BF533_FAMILY)
case IRQ_PROG_INTA:
-# if defined(BF537_FAMILY) && !(defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE))
- case IRQ_MAC_RX:
-# endif
#elif defined(CONFIG_BF54x)
case IRQ_PINT0:
case IRQ_PINT1:
@@ -1186,16 +1017,11 @@ int __init init_arch_irq(void)
case IRQ_PROG0_INTA:
case IRQ_PROG1_INTA:
case IRQ_PROG2_INTA:
-#elif defined(CONFIG_BF538) || defined(CONFIG_BF539)
+#elif defined(BF538_FAMILY)
case IRQ_PORTF_INTA:
#endif
irq_set_chained_handler(irq, bfin_demux_gpio_irq);
break;
-#ifdef BF537_GENERIC_ERROR_INT_DEMUX
- case IRQ_GENERIC_ERROR:
- irq_set_chained_handler(irq, bfin_demux_error_irq);
- break;
-#endif
#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
case IRQ_MAC_ERROR:
irq_set_chained_handler(irq,
@@ -1213,11 +1039,10 @@ int __init init_arch_irq(void)
case IRQ_CORETMR:
# ifdef CONFIG_SMP
irq_set_handler(irq, handle_percpu_irq);
- break;
# else
irq_set_handler(irq, handle_simple_irq);
- break;
# endif
+ break;
#endif
#ifdef CONFIG_TICKSOURCE_GPTMR0
@@ -1226,26 +1051,17 @@ int __init init_arch_irq(void)
break;
#endif
-#ifdef CONFIG_IPIPE
default:
+#ifdef CONFIG_IPIPE
irq_set_handler(irq, handle_level_irq);
- break;
-#else /* !CONFIG_IPIPE */
- default:
+#else
irq_set_handler(irq, handle_simple_irq);
+#endif
break;
-#endif /* !CONFIG_IPIPE */
}
}
-#ifdef BF537_GENERIC_ERROR_INT_DEMUX
- for (irq = IRQ_PPI_ERROR; irq <= IRQ_UART1_ERROR; irq++)
- irq_set_chip_and_handler(irq, &bfin_generic_error_irqchip,
- handle_level_irq);
-#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
- irq_set_chained_handler(IRQ_MAC_ERROR, bfin_demux_mac_status_irq);
-#endif
-#endif
+ init_mach_irq();
#if defined(CONFIG_BFIN_MAC) || defined(CONFIG_BFIN_MAC_MODULE)
for (irq = IRQ_MAC_PHYINT; irq <= IRQ_MAC_STMDONE; irq++)
@@ -1307,53 +1123,54 @@ int __init init_arch_irq(void)
#ifdef CONFIG_DO_IRQ_L1
__attribute__((l1_text))
#endif
-void do_irq(int vec, struct pt_regs *fp)
+static int vec_to_irq(int vec)
{
- if (vec == EVT_IVTMR_P) {
- vec = IRQ_CORETMR;
- } else {
- struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;
- struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;
-#if defined(SIC_ISR0)
- unsigned long sic_status[3];
+ struct ivgx *ivg = ivg7_13[vec - IVG7].ifirst;
+ struct ivgx *ivg_stop = ivg7_13[vec - IVG7].istop;
+ unsigned long sic_status[3];
+
+ if (likely(vec == EVT_IVTMR_P))
+ return IRQ_CORETMR;
- if (smp_processor_id()) {
+#ifdef SIC_ISR
+ sic_status[0] = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
+#else
+ if (smp_processor_id()) {
# ifdef SICB_ISR0
- /* This will be optimized out in UP mode. */
- sic_status[0] = bfin_read_SICB_ISR0() & bfin_read_SICB_IMASK0();
- sic_status[1] = bfin_read_SICB_ISR1() & bfin_read_SICB_IMASK1();
-# endif
- } else {
- sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
- sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
- }
-# ifdef SIC_ISR2
- sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
+ /* This will be optimized out in UP mode. */
+ sic_status[0] = bfin_read_SICB_ISR0() & bfin_read_SICB_IMASK0();
+ sic_status[1] = bfin_read_SICB_ISR1() & bfin_read_SICB_IMASK1();
# endif
- for (;; ivg++) {
- if (ivg >= ivg_stop) {
- atomic_inc(&num_spurious);
- return;
- }
- if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)
- break;
- }
-#else
- unsigned long sic_status;
-
- sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
+ } else {
+ sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
+ sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
+ }
+#endif
+#ifdef SIC_ISR2
+ sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
+#endif
- for (;; ivg++) {
- if (ivg >= ivg_stop) {
- atomic_inc(&num_spurious);
- return;
- } else if (sic_status & ivg->isrflag)
- break;
- }
+ for (;; ivg++) {
+ if (ivg >= ivg_stop)
+ return -1;
+#ifdef SIC_ISR
+ if (sic_status[0] & ivg->isrflag)
+#else
+ if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)
#endif
- vec = ivg->irqno;
+ return ivg->irqno;
}
- asm_do_IRQ(vec, fp);
+}
+
+#ifdef CONFIG_DO_IRQ_L1
+__attribute__((l1_text))
+#endif
+void do_irq(int vec, struct pt_regs *fp)
+{
+ int irq = vec_to_irq(vec);
+ if (irq == -1)
+ return;
+ asm_do_IRQ(irq, fp);
}
#ifdef CONFIG_IPIPE
@@ -1391,40 +1208,9 @@ asmlinkage int __ipipe_grab_irq(int vec, struct pt_regs *regs)
struct ivgx *ivg = ivg7_13[vec-IVG7].ifirst;
int irq, s = 0;
- if (likely(vec == EVT_IVTMR_P))
- irq = IRQ_CORETMR;
- else {
-#if defined(SIC_ISR0)
- unsigned long sic_status[3];
-
- sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0();
- sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1();
-# ifdef SIC_ISR2
- sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2();
-# endif
- for (;; ivg++) {
- if (ivg >= ivg_stop) {
- atomic_inc(&num_spurious);
- return 0;
- }
- if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag)
- break;
- }
-#else
- unsigned long sic_status;
-
- sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR();
-
- for (;; ivg++) {
- if (ivg >= ivg_stop) {
- atomic_inc(&num_spurious);
- return 0;
- } else if (sic_status & ivg->isrflag)
- break;
- }
-#endif
- irq = ivg->irqno;
- }
+ irq = vec_to_irq(vec);
+ if (irq == -1)
+ return 0;
if (irq == IRQ_SYSTMR) {
#if !defined(CONFIG_GENERIC_CLOCKEVENTS) || defined(CONFIG_TICKSOURCE_GPTMR0)
diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c
index 8bce5ed031e4..35e7e1eb0188 100644
--- a/arch/blackfin/mach-common/smp.c
+++ b/arch/blackfin/mach-common/smp.c
@@ -25,6 +25,7 @@
#include <linux/slab.h>
#include <asm/atomic.h>
#include <asm/cacheflush.h>
+#include <asm/irq_handler.h>
#include <asm/mmu_context.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
@@ -96,7 +97,7 @@ static void ipi_cpu_stop(unsigned int cpu)
dump_stack();
spin_unlock(&stop_lock);
- cpu_clear(cpu, cpu_online_map);
+ set_cpu_online(cpu, false);
local_irq_disable();
@@ -146,7 +147,7 @@ static void ipi_call_function(unsigned int cpu, struct ipi_message *msg)
*/
resync_core_dcache();
#endif
- cpu_clear(cpu, *msg->call_struct.waitmask);
+ cpumask_clear_cpu(cpu, msg->call_struct.waitmask);
}
}
@@ -177,6 +178,9 @@ static irqreturn_t ipi_handler_int1(int irq, void *dev_instance)
while (msg_queue->count) {
msg = &msg_queue->ipi_message[msg_queue->head];
switch (msg->type) {
+ case BFIN_IPI_RESCHEDULE:
+ scheduler_ipi();
+ break;
case BFIN_IPI_CALL_FUNC:
spin_unlock_irqrestore(&msg_queue->lock, flags);
ipi_call_function(cpu, msg);
@@ -219,9 +223,10 @@ static inline void smp_send_message(cpumask_t callmap, unsigned long type,
struct ipi_message_queue *msg_queue;
struct ipi_message *msg;
unsigned long flags, next_msg;
- cpumask_t waitmask = callmap; /* waitmask is shared by all cpus */
+ cpumask_t waitmask; /* waitmask is shared by all cpus */
- for_each_cpu_mask(cpu, callmap) {
+ cpumask_copy(&waitmask, &callmap);
+ for_each_cpu(cpu, &callmap) {
msg_queue = &per_cpu(ipi_msg_queue, cpu);
spin_lock_irqsave(&msg_queue->lock, flags);
if (msg_queue->count < BFIN_IPI_MSGQ_LEN) {
@@ -243,7 +248,7 @@ static inline void smp_send_message(cpumask_t callmap, unsigned long type,
}
if (wait) {
- while (!cpus_empty(waitmask))
+ while (!cpumask_empty(&waitmask))
blackfin_dcache_invalidate_range(
(unsigned long)(&waitmask),
(unsigned long)(&waitmask));
@@ -262,9 +267,9 @@ int smp_call_function(void (*func)(void *info), void *info, int wait)
cpumask_t callmap;
preempt_disable();
- callmap = cpu_online_map;
- cpu_clear(smp_processor_id(), callmap);
- if (!cpus_empty(callmap))
+ cpumask_copy(&callmap, cpu_online_mask);
+ cpumask_clear_cpu(smp_processor_id(), &callmap);
+ if (!cpumask_empty(&callmap))
smp_send_message(callmap, BFIN_IPI_CALL_FUNC, func, info, wait);
preempt_enable();
@@ -281,8 +286,8 @@ int smp_call_function_single(int cpuid, void (*func) (void *info), void *info,
if (cpu_is_offline(cpu))
return 0;
- cpus_clear(callmap);
- cpu_set(cpu, callmap);
+ cpumask_clear(&callmap);
+ cpumask_set_cpu(cpu, &callmap);
smp_send_message(callmap, BFIN_IPI_CALL_FUNC, func, info, wait);
@@ -305,9 +310,9 @@ void smp_send_stop(void)
cpumask_t callmap;
preempt_disable();
- callmap = cpu_online_map;
- cpu_clear(smp_processor_id(), callmap);
- if (!cpus_empty(callmap))
+ cpumask_copy(&callmap, cpu_online_mask);
+ cpumask_clear_cpu(smp_processor_id(), &callmap);
+ if (!cpumask_empty(&callmap))
smp_send_message(callmap, BFIN_IPI_CPU_STOP, NULL, NULL, 0);
preempt_enable();
diff --git a/arch/blackfin/mm/sram-alloc.c b/arch/blackfin/mm/sram-alloc.c
index dfd304a4a3ea..29d98faa1efd 100644
--- a/arch/blackfin/mm/sram-alloc.c
+++ b/arch/blackfin/mm/sram-alloc.c
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/spinlock.h>
#include <linux/rtc.h>
#include <linux/slab.h>
@@ -764,7 +765,7 @@ EXPORT_SYMBOL(sram_alloc_with_lsl);
/* Need to keep line of output the same. Currently, that is 44 bytes
* (including newline).
*/
-static int _sram_proc_read(char *buf, int *len, int count, const char *desc,
+static int _sram_proc_show(struct seq_file *m, const char *desc,
struct sram_piece *pfree_head,
struct sram_piece *pused_head)
{
@@ -773,13 +774,13 @@ static int _sram_proc_read(char *buf, int *len, int count, const char *desc,
if (!pfree_head || !pused_head)
return -1;
- *len += sprintf(&buf[*len], "--- SRAM %-14s Size PID State \n", desc);
+ seq_printf(m, "--- SRAM %-14s Size PID State \n", desc);
/* search the relevant memory slot */
pslot = pused_head->next;
while (pslot != NULL) {
- *len += sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
+ seq_printf(m, "%p-%p %10i %5i %-10s\n",
pslot->paddr, pslot->paddr + pslot->size,
pslot->size, pslot->pid, "ALLOCATED");
@@ -789,7 +790,7 @@ static int _sram_proc_read(char *buf, int *len, int count, const char *desc,
pslot = pfree_head->next;
while (pslot != NULL) {
- *len += sprintf(&buf[*len], "%p-%p %10i %5i %-10s\n",
+ seq_printf(m, "%p-%p %10i %5i %-10s\n",
pslot->paddr, pslot->paddr + pslot->size,
pslot->size, pslot->pid, "FREE");
@@ -798,54 +799,62 @@ static int _sram_proc_read(char *buf, int *len, int count, const char *desc,
return 0;
}
-static int sram_proc_read(char *buf, char **start, off_t offset, int count,
- int *eof, void *data)
+static int sram_proc_show(struct seq_file *m, void *v)
{
- int len = 0;
unsigned int cpu;
for (cpu = 0; cpu < num_possible_cpus(); ++cpu) {
- if (_sram_proc_read(buf, &len, count, "Scratchpad",
+ if (_sram_proc_show(m, "Scratchpad",
&per_cpu(free_l1_ssram_head, cpu), &per_cpu(used_l1_ssram_head, cpu)))
goto not_done;
#if L1_DATA_A_LENGTH != 0
- if (_sram_proc_read(buf, &len, count, "L1 Data A",
+ if (_sram_proc_show(m, "L1 Data A",
&per_cpu(free_l1_data_A_sram_head, cpu),
&per_cpu(used_l1_data_A_sram_head, cpu)))
goto not_done;
#endif
#if L1_DATA_B_LENGTH != 0
- if (_sram_proc_read(buf, &len, count, "L1 Data B",
+ if (_sram_proc_show(m, "L1 Data B",
&per_cpu(free_l1_data_B_sram_head, cpu),
&per_cpu(used_l1_data_B_sram_head, cpu)))
goto not_done;
#endif
#if L1_CODE_LENGTH != 0
- if (_sram_proc_read(buf, &len, count, "L1 Instruction",
+ if (_sram_proc_show(m, "L1 Instruction",
&per_cpu(free_l1_inst_sram_head, cpu),
&per_cpu(used_l1_inst_sram_head, cpu)))
goto not_done;
#endif
}
#if L2_LENGTH != 0
- if (_sram_proc_read(buf, &len, count, "L2", &free_l2_sram_head,
- &used_l2_sram_head))
+ if (_sram_proc_show(m, "L2", &free_l2_sram_head, &used_l2_sram_head))
goto not_done;
#endif
- *eof = 1;
not_done:
- return len;
+ return 0;
+}
+
+static int sram_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, sram_proc_show, NULL);
}
+static const struct file_operations sram_proc_ops = {
+ .open = sram_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static int __init sram_proc_init(void)
{
struct proc_dir_entry *ptr;
- ptr = create_proc_entry("sram", S_IFREG | S_IRUGO, NULL);
+
+ ptr = proc_create("sram", S_IRUGO, NULL, &sram_proc_ops);
if (!ptr) {
printk(KERN_WARNING "unable to create /proc/sram\n");
return -1;
}
- ptr->read_proc = sram_proc_read;
return 0;
}
late_initcall(sram_proc_init);
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig
index a6d03069d0ff..b6b94a27d276 100644
--- a/arch/cris/Kconfig
+++ b/arch/cris/Kconfig
@@ -31,10 +31,6 @@ config ARCH_HAS_ILOG2_U64
bool
default n
-config GENERIC_FIND_NEXT_BIT
- bool
- default y
-
config GENERIC_HWEIGHT
bool
default y
diff --git a/arch/cris/arch-v32/kernel/irq.c b/arch/cris/arch-v32/kernel/irq.c
index 68a1a5901ca5..5ebe6e841820 100644
--- a/arch/cris/arch-v32/kernel/irq.c
+++ b/arch/cris/arch-v32/kernel/irq.c
@@ -266,11 +266,11 @@ static int irq_cpu(int irq)
/* Let the interrupt stay if possible */
- if (cpu_isset(cpu, irq_allocations[irq - FIRST_IRQ].mask))
+ if (cpumask_test_cpu(cpu, &irq_allocations[irq - FIRST_IRQ].mask))
goto out;
/* IRQ must be moved to another CPU. */
- cpu = first_cpu(irq_allocations[irq - FIRST_IRQ].mask);
+ cpu = cpumask_first(&irq_allocations[irq - FIRST_IRQ].mask);
irq_allocations[irq - FIRST_IRQ].cpu = cpu;
out:
spin_unlock_irqrestore(&irq_lock, flags);
diff --git a/arch/cris/arch-v32/kernel/smp.c b/arch/cris/arch-v32/kernel/smp.c
index 4c9e3e1ba5d1..a0843a71aaee 100644
--- a/arch/cris/arch-v32/kernel/smp.c
+++ b/arch/cris/arch-v32/kernel/smp.c
@@ -81,7 +81,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
/* Mark all possible CPUs as present */
for (i = 0; i < max_cpus; i++)
- cpu_set(i, phys_cpu_present_map);
+ cpumask_set_cpu(i, &phys_cpu_present_map);
}
void __devinit smp_prepare_boot_cpu(void)
@@ -98,7 +98,7 @@ void __devinit smp_prepare_boot_cpu(void)
SUPP_REG_WR(RW_MM_TLB_PGD, pgd);
set_cpu_online(0, true);
- cpu_set(0, phys_cpu_present_map);
+ cpumask_set_cpu(0, &phys_cpu_present_map);
set_cpu_possible(0, true);
}
@@ -112,8 +112,9 @@ smp_boot_one_cpu(int cpuid)
{
unsigned timeout;
struct task_struct *idle;
- cpumask_t cpu_mask = CPU_MASK_NONE;
+ cpumask_t cpu_mask;
+ cpumask_clear(&cpu_mask);
idle = fork_idle(cpuid);
if (IS_ERR(idle))
panic("SMP: fork failed for CPU:%d", cpuid);
@@ -125,10 +126,10 @@ smp_boot_one_cpu(int cpuid)
cpu_now_booting = cpuid;
/* Kick it */
- cpu_set(cpuid, cpu_online_map);
- cpu_set(cpuid, cpu_mask);
+ set_cpu_online(cpuid, true);
+ cpumask_set_cpu(cpuid, &cpu_mask);
send_ipi(IPI_BOOT, 0, cpu_mask);
- cpu_clear(cpuid, cpu_online_map);
+ set_cpu_online(cpuid, false);
/* Wait for CPU to come online */
for (timeout = 0; timeout < 10000; timeout++) {
@@ -176,7 +177,7 @@ void __init smp_callin(void)
notify_cpu_starting(cpu);
local_irq_enable();
- cpu_set(cpu, cpu_online_map);
+ set_cpu_online(cpu, true);
cpu_idle();
}
@@ -214,8 +215,9 @@ int __cpuinit __cpu_up(unsigned int cpu)
void smp_send_reschedule(int cpu)
{
- cpumask_t cpu_mask = CPU_MASK_NONE;
- cpu_set(cpu, cpu_mask);
+ cpumask_t cpu_mask;
+ cpumask_clear(&cpu_mask);
+ cpumask_set_cpu(cpu, &cpu_mask);
send_ipi(IPI_SCHEDULE, 0, cpu_mask);
}
@@ -232,7 +234,7 @@ void flush_tlb_common(struct mm_struct* mm, struct vm_area_struct* vma, unsigned
spin_lock_irqsave(&tlbstate_lock, flags);
cpu_mask = (mm == FLUSH_ALL ? cpu_all_mask : *mm_cpumask(mm));
- cpu_clear(smp_processor_id(), cpu_mask);
+ cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
flush_mm = mm;
flush_vma = vma;
flush_addr = addr;
@@ -277,10 +279,10 @@ int send_ipi(int vector, int wait, cpumask_t cpu_mask)
int ret = 0;
/* Calculate CPUs to send to. */
- cpus_and(cpu_mask, cpu_mask, cpu_online_map);
+ cpumask_and(&cpu_mask, &cpu_mask, cpu_online_mask);
/* Send the IPI. */
- for_each_cpu_mask(i, cpu_mask)
+ for_each_cpu(i, &cpu_mask)
{
ipi.vector |= vector;
REG_WR(intr_vect, irq_regs[i], rw_ipi, ipi);
@@ -288,7 +290,7 @@ int send_ipi(int vector, int wait, cpumask_t cpu_mask)
/* Wait for IPI to finish on other CPUS */
if (wait) {
- for_each_cpu_mask(i, cpu_mask) {
+ for_each_cpu(i, &cpu_mask) {
int j;
for (j = 0 ; j < 1000; j++) {
ipi = REG_RD(intr_vect, irq_regs[i], rw_ipi);
@@ -314,11 +316,12 @@ int send_ipi(int vector, int wait, cpumask_t cpu_mask)
*/
int smp_call_function(void (*func)(void *info), void *info, int wait)
{
- cpumask_t cpu_mask = CPU_MASK_ALL;
+ cpumask_t cpu_mask;
struct call_data_struct data;
int ret;
- cpu_clear(smp_processor_id(), cpu_mask);
+ cpumask_setall(&cpu_mask);
+ cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
WARN_ON(irqs_disabled());
@@ -342,15 +345,18 @@ irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id)
ipi = REG_RD(intr_vect, irq_regs[smp_processor_id()], rw_ipi);
+ if (ipi.vector & IPI_SCHEDULE) {
+ scheduler_ipi();
+ }
if (ipi.vector & IPI_CALL) {
- func(info);
+ func(info);
}
if (ipi.vector & IPI_FLUSH_TLB) {
- if (flush_mm == FLUSH_ALL)
- __flush_tlb_all();
- else if (flush_vma == FLUSH_ALL)
+ if (flush_mm == FLUSH_ALL)
+ __flush_tlb_all();
+ else if (flush_vma == FLUSH_ALL)
__flush_tlb_mm(flush_mm);
- else
+ else
__flush_tlb_page(flush_vma, flush_addr);
}
diff --git a/arch/cris/arch-v32/mach-fs/Makefile b/arch/cris/arch-v32/mach-fs/Makefile
index 4ff407a1b931..41fa6a6893a9 100644
--- a/arch/cris/arch-v32/mach-fs/Makefile
+++ b/arch/cris/arch-v32/mach-fs/Makefile
@@ -4,7 +4,7 @@
#
obj-y := dma.o pinmux.o io.o arbiter.o
-bj-$(CONFIG_ETRAX_VCS_SIM) += vcs_hook.o
+obj-$(CONFIG_ETRAX_VCS_SIM) += vcs_hook.o
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
clean:
diff --git a/arch/cris/kernel/vmlinux.lds.S b/arch/cris/kernel/vmlinux.lds.S
index 728bbd9e7d4c..a6990cb0f098 100644
--- a/arch/cris/kernel/vmlinux.lds.S
+++ b/arch/cris/kernel/vmlinux.lds.S
@@ -102,7 +102,7 @@ SECTIONS
#endif
__vmlinux_end = .; /* Last address of the physical file. */
#ifdef CONFIG_ETRAX_ARCH_V32
- PERCPU(32, PAGE_SIZE)
+ PERCPU_SECTION(32)
.init.ramfs : {
INIT_RAM_FS
diff --git a/arch/cris/mm/init.c b/arch/cris/mm/init.c
index df33ab89d70f..d72ab58fd83e 100644
--- a/arch/cris/mm/init.c
+++ b/arch/cris/mm/init.c
@@ -13,8 +13,6 @@
#include <linux/bootmem.h>
#include <asm/tlb.h>
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
unsigned long empty_zero_page;
extern char _stext, _edata, _etext; /* From linkerscript */
diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig
index 064f62196745..cb884e489425 100644
--- a/arch/frv/Kconfig
+++ b/arch/frv/Kconfig
@@ -19,14 +19,6 @@ config RWSEM_GENERIC_SPINLOCK
config RWSEM_XCHGADD_ALGORITHM
bool
-config GENERIC_FIND_NEXT_BIT
- bool
- default y
-
-config GENERIC_FIND_BIT_LE
- bool
- default y
-
config GENERIC_HWEIGHT
bool
default y
diff --git a/arch/frv/kernel/vmlinux.lds.S b/arch/frv/kernel/vmlinux.lds.S
index 0daae8af5787..7e958d829ec9 100644
--- a/arch/frv/kernel/vmlinux.lds.S
+++ b/arch/frv/kernel/vmlinux.lds.S
@@ -37,7 +37,7 @@ SECTIONS
_einittext = .;
INIT_DATA_SECTION(8)
- PERCPU(L1_CACHE_BYTES, 4096)
+ PERCPU_SECTION(L1_CACHE_BYTES)
. = ALIGN(PAGE_SIZE);
__init_end = .;
diff --git a/arch/frv/mm/init.c b/arch/frv/mm/init.c
index ed64588ac3a7..fbe5f0dbae06 100644
--- a/arch/frv/mm/init.c
+++ b/arch/frv/mm/init.c
@@ -41,8 +41,6 @@
#undef DEBUG
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
/*
* BAD_PAGE is the page that is used for page faults when linux
* is out-of-memory. Older versions of linux just did a
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig
index e20322ffcaf8..091ed6192ae8 100644
--- a/arch/h8300/Kconfig
+++ b/arch/h8300/Kconfig
@@ -41,14 +41,6 @@ config ARCH_HAS_ILOG2_U64
bool
default n
-config GENERIC_FIND_NEXT_BIT
- bool
- default y
-
-config GENERIC_FIND_BIT_LE
- bool
- default y
-
config GENERIC_HWEIGHT
bool
default y
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index e5cc56ae6ce3..38280ef4a2af 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -78,10 +78,6 @@ config HUGETLB_PAGE_SIZE_VARIABLE
depends on HUGETLB_PAGE
default y
-config GENERIC_FIND_NEXT_BIT
- bool
- default y
-
config GENERIC_CALIBRATE_DELAY
bool
default y
diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
index 4ce8d1358fee..80241fe03f50 100644
--- a/arch/ia64/hp/common/sba_iommu.c
+++ b/arch/ia64/hp/common/sba_iommu.c
@@ -37,6 +37,7 @@
#include <linux/crash_dump.h>
#include <linux/iommu-helper.h>
#include <linux/dma-mapping.h>
+#include <linux/prefetch.h>
#include <asm/delay.h> /* ia64_get_itc() */
#include <asm/io.h>
@@ -1063,7 +1064,7 @@ static void sba_unmap_page(struct device *dev, dma_addr_t iova, size_t size,
/*
** Address does not fall w/in IOVA, must be bypassing
*/
- DBG_BYPASS("sba_unmap_single_atttrs() bypass addr: 0x%lx\n",
+ DBG_BYPASS("sba_unmap_single_attrs() bypass addr: 0x%lx\n",
iova);
#ifdef ENABLE_MARK_CLEAN
diff --git a/arch/ia64/include/asm/tlb.h b/arch/ia64/include/asm/tlb.h
index 23cce999eb1c..c3ffe3e54edc 100644
--- a/arch/ia64/include/asm/tlb.h
+++ b/arch/ia64/include/asm/tlb.h
@@ -47,21 +47,27 @@
#include <asm/machvec.h>
#ifdef CONFIG_SMP
-# define FREE_PTE_NR 2048
# define tlb_fast_mode(tlb) ((tlb)->nr == ~0U)
#else
-# define FREE_PTE_NR 0
# define tlb_fast_mode(tlb) (1)
#endif
+/*
+ * If we can't allocate a page to make a big batch of page pointers
+ * to work on, then just handle a few from the on-stack structure.
+ */
+#define IA64_GATHER_BUNDLE 8
+
struct mmu_gather {
struct mm_struct *mm;
unsigned int nr; /* == ~0U => fast mode */
+ unsigned int max;
unsigned char fullmm; /* non-zero means full mm flush */
unsigned char need_flush; /* really unmapped some PTEs? */
unsigned long start_addr;
unsigned long end_addr;
- struct page *pages[FREE_PTE_NR];
+ struct page **pages;
+ struct page *local[IA64_GATHER_BUNDLE];
};
struct ia64_tr_entry {
@@ -90,9 +96,6 @@ extern struct ia64_tr_entry *ia64_idtrs[NR_CPUS];
#define RR_RID_MASK 0x00000000ffffff00L
#define RR_TO_RID(val) ((val >> 8) & 0xffffff)
-/* Users of the generic TLB shootdown code must declare this storage space. */
-DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
-
/*
* Flush the TLB for address range START to END and, if not in fast mode, release the
* freed pages that where gathered up to this point.
@@ -147,15 +150,23 @@ ia64_tlb_flush_mmu (struct mmu_gather *tlb, unsigned long start, unsigned long e
}
}
-/*
- * Return a pointer to an initialized struct mmu_gather.
- */
-static inline struct mmu_gather *
-tlb_gather_mmu (struct mm_struct *mm, unsigned int full_mm_flush)
+static inline void __tlb_alloc_page(struct mmu_gather *tlb)
{
- struct mmu_gather *tlb = &get_cpu_var(mmu_gathers);
+ unsigned long addr = __get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0);
+ if (addr) {
+ tlb->pages = (void *)addr;
+ tlb->max = PAGE_SIZE / sizeof(void *);
+ }
+}
+
+
+static inline void
+tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned int full_mm_flush)
+{
tlb->mm = mm;
+ tlb->max = ARRAY_SIZE(tlb->local);
+ tlb->pages = tlb->local;
/*
* Use fast mode if only 1 CPU is online.
*
@@ -172,7 +183,6 @@ tlb_gather_mmu (struct mm_struct *mm, unsigned int full_mm_flush)
tlb->nr = (num_online_cpus() == 1) ? ~0U : 0;
tlb->fullmm = full_mm_flush;
tlb->start_addr = ~0UL;
- return tlb;
}
/*
@@ -180,7 +190,7 @@ tlb_gather_mmu (struct mm_struct *mm, unsigned int full_mm_flush)
* collected.
*/
static inline void
-tlb_finish_mmu (struct mmu_gather *tlb, unsigned long start, unsigned long end)
+tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
{
/*
* Note: tlb->nr may be 0 at this point, so we can't rely on tlb->start_addr and
@@ -191,7 +201,8 @@ tlb_finish_mmu (struct mmu_gather *tlb, unsigned long start, unsigned long end)
/* keep the page table cache within bounds */
check_pgt_cache();
- put_cpu_var(mmu_gathers);
+ if (tlb->pages != tlb->local)
+ free_pages((unsigned long)tlb->pages, 0);
}
/*
@@ -199,18 +210,33 @@ tlb_finish_mmu (struct mmu_gather *tlb, unsigned long start, unsigned long end)
* must be delayed until after the TLB has been flushed (see comments at the beginning of
* this file).
*/
-static inline void
-tlb_remove_page (struct mmu_gather *tlb, struct page *page)
+static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)
{
tlb->need_flush = 1;
if (tlb_fast_mode(tlb)) {
free_page_and_swap_cache(page);
- return;
+ return 1; /* avoid calling tlb_flush_mmu */
}
+
+ if (!tlb->nr && tlb->pages == tlb->local)
+ __tlb_alloc_page(tlb);
+
tlb->pages[tlb->nr++] = page;
- if (tlb->nr >= FREE_PTE_NR)
- ia64_tlb_flush_mmu(tlb, tlb->start_addr, tlb->end_addr);
+ VM_BUG_ON(tlb->nr > tlb->max);
+
+ return tlb->max - tlb->nr;
+}
+
+static inline void tlb_flush_mmu(struct mmu_gather *tlb)
+{
+ ia64_tlb_flush_mmu(tlb, tlb->start_addr, tlb->end_addr);
+}
+
+static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+ if (!__tlb_remove_page(tlb, page))
+ tlb_flush_mmu(tlb);
}
/*
diff --git a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c
index 22f61526a8e1..f09b174244d5 100644
--- a/arch/ia64/kernel/cpufreq/acpi-cpufreq.c
+++ b/arch/ia64/kernel/cpufreq/acpi-cpufreq.c
@@ -23,8 +23,6 @@
#include <linux/acpi.h>
#include <acpi/processor.h>
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "acpi-cpufreq", msg)
-
MODULE_AUTHOR("Venkatesh Pallipadi");
MODULE_DESCRIPTION("ACPI Processor P-States Driver");
MODULE_LICENSE("GPL");
@@ -47,12 +45,12 @@ processor_set_pstate (
{
s64 retval;
- dprintk("processor_set_pstate\n");
+ pr_debug("processor_set_pstate\n");
retval = ia64_pal_set_pstate((u64)value);
if (retval) {
- dprintk("Failed to set freq to 0x%x, with error 0x%lx\n",
+ pr_debug("Failed to set freq to 0x%x, with error 0x%lx\n",
value, retval);
return -ENODEV;
}
@@ -67,14 +65,14 @@ processor_get_pstate (
u64 pstate_index = 0;
s64 retval;
- dprintk("processor_get_pstate\n");
+ pr_debug("processor_get_pstate\n");
retval = ia64_pal_get_pstate(&pstate_index,
PAL_GET_PSTATE_TYPE_INSTANT);
*value = (u32) pstate_index;
if (retval)
- dprintk("Failed to get current freq with "
+ pr_debug("Failed to get current freq with "
"error 0x%lx, idx 0x%x\n", retval, *value);
return (int)retval;
@@ -90,7 +88,7 @@ extract_clock (
{
unsigned long i;
- dprintk("extract_clock\n");
+ pr_debug("extract_clock\n");
for (i = 0; i < data->acpi_data.state_count; i++) {
if (value == data->acpi_data.states[i].status)
@@ -110,7 +108,7 @@ processor_get_freq (
cpumask_t saved_mask;
unsigned long clock_freq;
- dprintk("processor_get_freq\n");
+ pr_debug("processor_get_freq\n");
saved_mask = current->cpus_allowed;
set_cpus_allowed_ptr(current, cpumask_of(cpu));
@@ -148,7 +146,7 @@ processor_set_freq (
cpumask_t saved_mask;
int retval;
- dprintk("processor_set_freq\n");
+ pr_debug("processor_set_freq\n");
saved_mask = current->cpus_allowed;
set_cpus_allowed_ptr(current, cpumask_of(cpu));
@@ -159,16 +157,16 @@ processor_set_freq (
if (state == data->acpi_data.state) {
if (unlikely(data->resume)) {
- dprintk("Called after resume, resetting to P%d\n", state);
+ pr_debug("Called after resume, resetting to P%d\n", state);
data->resume = 0;
} else {
- dprintk("Already at target state (P%d)\n", state);
+ pr_debug("Already at target state (P%d)\n", state);
retval = 0;
goto migrate_end;
}
}
- dprintk("Transitioning from P%d to P%d\n",
+ pr_debug("Transitioning from P%d to P%d\n",
data->acpi_data.state, state);
/* cpufreq frequency struct */
@@ -186,7 +184,7 @@ processor_set_freq (
value = (u32) data->acpi_data.states[state].control;
- dprintk("Transitioning to state: 0x%08x\n", value);
+ pr_debug("Transitioning to state: 0x%08x\n", value);
ret = processor_set_pstate(value);
if (ret) {
@@ -219,7 +217,7 @@ acpi_cpufreq_get (
{
struct cpufreq_acpi_io *data = acpi_io_data[cpu];
- dprintk("acpi_cpufreq_get\n");
+ pr_debug("acpi_cpufreq_get\n");
return processor_get_freq(data, cpu);
}
@@ -235,7 +233,7 @@ acpi_cpufreq_target (
unsigned int next_state = 0;
unsigned int result = 0;
- dprintk("acpi_cpufreq_setpolicy\n");
+ pr_debug("acpi_cpufreq_setpolicy\n");
result = cpufreq_frequency_table_target(policy,
data->freq_table, target_freq, relation, &next_state);
@@ -255,7 +253,7 @@ acpi_cpufreq_verify (
unsigned int result = 0;
struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
- dprintk("acpi_cpufreq_verify\n");
+ pr_debug("acpi_cpufreq_verify\n");
result = cpufreq_frequency_table_verify(policy,
data->freq_table);
@@ -273,7 +271,7 @@ acpi_cpufreq_cpu_init (
struct cpufreq_acpi_io *data;
unsigned int result = 0;
- dprintk("acpi_cpufreq_cpu_init\n");
+ pr_debug("acpi_cpufreq_cpu_init\n");
data = kzalloc(sizeof(struct cpufreq_acpi_io), GFP_KERNEL);
if (!data)
@@ -288,7 +286,7 @@ acpi_cpufreq_cpu_init (
/* capability check */
if (data->acpi_data.state_count <= 1) {
- dprintk("No P-States\n");
+ pr_debug("No P-States\n");
result = -ENODEV;
goto err_unreg;
}
@@ -297,7 +295,7 @@ acpi_cpufreq_cpu_init (
ACPI_ADR_SPACE_FIXED_HARDWARE) ||
(data->acpi_data.status_register.space_id !=
ACPI_ADR_SPACE_FIXED_HARDWARE)) {
- dprintk("Unsupported address space [%d, %d]\n",
+ pr_debug("Unsupported address space [%d, %d]\n",
(u32) (data->acpi_data.control_register.space_id),
(u32) (data->acpi_data.status_register.space_id));
result = -ENODEV;
@@ -348,7 +346,7 @@ acpi_cpufreq_cpu_init (
"activated.\n", cpu);
for (i = 0; i < data->acpi_data.state_count; i++)
- dprintk(" %cP%d: %d MHz, %d mW, %d uS, %d uS, 0x%x 0x%x\n",
+ pr_debug(" %cP%d: %d MHz, %d mW, %d uS, %d uS, 0x%x 0x%x\n",
(i == data->acpi_data.state?'*':' '), i,
(u32) data->acpi_data.states[i].core_frequency,
(u32) data->acpi_data.states[i].power,
@@ -383,7 +381,7 @@ acpi_cpufreq_cpu_exit (
{
struct cpufreq_acpi_io *data = acpi_io_data[policy->cpu];
- dprintk("acpi_cpufreq_cpu_exit\n");
+ pr_debug("acpi_cpufreq_cpu_exit\n");
if (data) {
cpufreq_frequency_table_put_attr(policy->cpu);
@@ -418,7 +416,7 @@ static struct cpufreq_driver acpi_cpufreq_driver = {
static int __init
acpi_cpufreq_init (void)
{
- dprintk("acpi_cpufreq_init\n");
+ pr_debug("acpi_cpufreq_init\n");
return cpufreq_register_driver(&acpi_cpufreq_driver);
}
@@ -427,7 +425,7 @@ acpi_cpufreq_init (void)
static void __exit
acpi_cpufreq_exit (void)
{
- dprintk("acpi_cpufreq_exit\n");
+ pr_debug("acpi_cpufreq_exit\n");
cpufreq_unregister_driver(&acpi_cpufreq_driver);
return;
diff --git a/arch/ia64/kernel/cyclone.c b/arch/ia64/kernel/cyclone.c
index 1b811c61bdc6..f64097b5118a 100644
--- a/arch/ia64/kernel/cyclone.c
+++ b/arch/ia64/kernel/cyclone.c
@@ -31,8 +31,6 @@ static struct clocksource clocksource_cyclone = {
.rating = 300,
.read = read_cyclone,
.mask = (1LL << 40) - 1,
- .mult = 0, /*to be calculated*/
- .shift = 16,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
@@ -118,9 +116,7 @@ int __init init_cyclone_clock(void)
/* initialize last tick */
cyclone_mc = cyclone_timer;
clocksource_cyclone.fsys_mmio = cyclone_timer;
- clocksource_cyclone.mult = clocksource_hz2mult(CYCLONE_TIMER_FREQ,
- clocksource_cyclone.shift);
- clocksource_register(&clocksource_cyclone);
+ clocksource_register_hz(&clocksource_cyclone, CYCLONE_TIMER_FREQ);
return 0;
}
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
index 5b704740f160..782c3a357f24 100644
--- a/arch/ia64/kernel/irq_ia64.c
+++ b/arch/ia64/kernel/irq_ia64.c
@@ -31,6 +31,7 @@
#include <linux/irq.h>
#include <linux/ratelimit.h>
#include <linux/acpi.h>
+#include <linux/sched.h>
#include <asm/delay.h>
#include <asm/intrinsics.h>
@@ -496,6 +497,7 @@ ia64_handle_irq (ia64_vector vector, struct pt_regs *regs)
smp_local_flush_tlb();
kstat_incr_irqs_this_cpu(irq, desc);
} else if (unlikely(IS_RESCHEDULE(vector))) {
+ scheduler_ipi();
kstat_incr_irqs_this_cpu(irq, desc);
} else {
ia64_setreg(_IA64_REG_CR_TPR, vector);
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index 156ad803d5b7..85118dfe9bb5 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -36,7 +36,7 @@
static cycle_t itc_get_cycles(struct clocksource *cs);
struct fsyscall_gtod_data_t fsyscall_gtod_data = {
- .lock = SEQLOCK_UNLOCKED,
+ .lock = __SEQLOCK_UNLOCKED(fsyscall_gtod_data.lock),
};
struct itc_jitter_data_t itc_jitter_data;
@@ -73,8 +73,6 @@ static struct clocksource clocksource_itc = {
.rating = 350,
.read = itc_get_cycles,
.mask = CLOCKSOURCE_MASK(64),
- .mult = 0, /*to be calculated*/
- .shift = 16,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
#ifdef CONFIG_PARAVIRT
.resume = paravirt_clocksource_resume,
@@ -365,11 +363,8 @@ ia64_init_itm (void)
ia64_cpu_local_tick();
if (!itc_clocksource) {
- /* Sort out mult/shift values: */
- clocksource_itc.mult =
- clocksource_hz2mult(local_cpu_data->itc_freq,
- clocksource_itc.shift);
- clocksource_register(&clocksource_itc);
+ clocksource_register_hz(&clocksource_itc,
+ local_cpu_data->itc_freq);
itc_clocksource = &clocksource_itc;
}
}
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
index 787de4a77d82..53c0ba004e9e 100644
--- a/arch/ia64/kernel/vmlinux.lds.S
+++ b/arch/ia64/kernel/vmlinux.lds.S
@@ -209,6 +209,7 @@ SECTIONS {
data : {
} :data
.data : AT(ADDR(.data) - LOAD_OFFSET) {
+ _sdata = .;
INIT_TASK_DATA(PAGE_SIZE)
CACHELINE_ALIGNED_DATA(SMP_CACHE_BYTES)
READ_MOSTLY_DATA(SMP_CACHE_BYTES)
diff --git a/arch/ia64/kvm/vti.h b/arch/ia64/kvm/vti.h
index f6c5617e16af..b214b5b0432d 100644
--- a/arch/ia64/kvm/vti.h
+++ b/arch/ia64/kvm/vti.h
@@ -83,13 +83,13 @@
union vac {
unsigned long value;
struct {
- int a_int:1;
- int a_from_int_cr:1;
- int a_to_int_cr:1;
- int a_from_psr:1;
- int a_from_cpuid:1;
- int a_cover:1;
- int a_bsw:1;
+ unsigned int a_int:1;
+ unsigned int a_from_int_cr:1;
+ unsigned int a_to_int_cr:1;
+ unsigned int a_from_psr:1;
+ unsigned int a_from_cpuid:1;
+ unsigned int a_cover:1;
+ unsigned int a_bsw:1;
long reserved:57;
};
};
@@ -97,12 +97,12 @@ union vac {
union vdc {
unsigned long value;
struct {
- int d_vmsw:1;
- int d_extint:1;
- int d_ibr_dbr:1;
- int d_pmc:1;
- int d_to_pmd:1;
- int d_itm:1;
+ unsigned int d_vmsw:1;
+ unsigned int d_extint:1;
+ unsigned int d_ibr_dbr:1;
+ unsigned int d_pmc:1;
+ unsigned int d_to_pmd:1;
+ unsigned int d_itm:1;
long reserved:58;
};
};
diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c
index 9a018cde5d84..f114a3b14c6a 100644
--- a/arch/ia64/mm/contig.c
+++ b/arch/ia64/mm/contig.c
@@ -44,13 +44,16 @@ void show_mem(unsigned int filter)
pg_data_t *pgdat;
printk(KERN_INFO "Mem-info:\n");
- show_free_areas();
+ show_free_areas(filter);
printk(KERN_INFO "Node memory in pages:\n");
for_each_online_pgdat(pgdat) {
unsigned long present;
unsigned long flags;
int shared = 0, cached = 0, reserved = 0;
+ int nid = pgdat->node_id;
+ if (skip_free_areas_node(filter, nid))
+ continue;
pgdat_resize_lock(pgdat, &flags);
present = pgdat->node_present_pages;
for(i = 0; i < pgdat->node_spanned_pages; i++) {
@@ -64,8 +67,7 @@ void show_mem(unsigned int filter)
if (max_gap < LARGE_GAP)
continue;
#endif
- i = vmemmap_find_next_valid_pfn(pgdat->node_id,
- i) - 1;
+ i = vmemmap_find_next_valid_pfn(nid, i) - 1;
continue;
}
if (PageReserved(page))
@@ -81,7 +83,7 @@ void show_mem(unsigned int filter)
total_cached += cached;
total_shared += shared;
printk(KERN_INFO "Node %4d: RAM: %11ld, rsvd: %8d, "
- "shrd: %10d, swpd: %10d\n", pgdat->node_id,
+ "shrd: %10d, swpd: %10d\n", nid,
present, reserved, shared, cached);
}
printk(KERN_INFO "%ld pages of RAM\n", total_present);
diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c
index 82ab1bc6afb1..c641333cd997 100644
--- a/arch/ia64/mm/discontig.c
+++ b/arch/ia64/mm/discontig.c
@@ -622,13 +622,16 @@ void show_mem(unsigned int filter)
pg_data_t *pgdat;
printk(KERN_INFO "Mem-info:\n");
- show_free_areas();
+ show_free_areas(filter);
printk(KERN_INFO "Node memory in pages:\n");
for_each_online_pgdat(pgdat) {
unsigned long present;
unsigned long flags;
int shared = 0, cached = 0, reserved = 0;
+ int nid = pgdat->node_id;
+ if (skip_free_areas_node(filter, nid))
+ continue;
pgdat_resize_lock(pgdat, &flags);
present = pgdat->node_present_pages;
for(i = 0; i < pgdat->node_spanned_pages; i++) {
@@ -638,8 +641,7 @@ void show_mem(unsigned int filter)
if (pfn_valid(pgdat->node_start_pfn + i))
page = pfn_to_page(pgdat->node_start_pfn + i);
else {
- i = vmemmap_find_next_valid_pfn(pgdat->node_id,
- i) - 1;
+ i = vmemmap_find_next_valid_pfn(nid, i) - 1;
continue;
}
if (PageReserved(page))
@@ -655,7 +657,7 @@ void show_mem(unsigned int filter)
total_cached += cached;
total_shared += shared;
printk(KERN_INFO "Node %4d: RAM: %11ld, rsvd: %8d, "
- "shrd: %10d, swpd: %10d\n", pgdat->node_id,
+ "shrd: %10d, swpd: %10d\n", nid,
present, reserved, shared, cached);
}
printk(KERN_INFO "%ld pages of RAM\n", total_present);
diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c
index 0799fea4c588..20b359376128 100644
--- a/arch/ia64/mm/fault.c
+++ b/arch/ia64/mm/fault.c
@@ -10,6 +10,7 @@
#include <linux/interrupt.h>
#include <linux/kprobes.h>
#include <linux/kdebug.h>
+#include <linux/prefetch.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index ed41759efcac..00cb0e26c64e 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -36,8 +36,6 @@
#include <asm/mca.h>
#include <asm/paravirt.h>
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
extern void ia64_tlb_init (void);
unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL;
diff --git a/arch/ia64/oprofile/backtrace.c b/arch/ia64/oprofile/backtrace.c
index 5cdd7e4a597c..f7b798993cea 100644
--- a/arch/ia64/oprofile/backtrace.c
+++ b/arch/ia64/oprofile/backtrace.c
@@ -29,7 +29,7 @@ typedef struct
unsigned int depth;
struct pt_regs *regs;
struct unw_frame_info frame;
- u64 *prev_pfs_loc; /* state for WAR for old spinlock ool code */
+ unsigned long *prev_pfs_loc; /* state for WAR for old spinlock ool code */
} ia64_backtrace_t;
/* Returns non-zero if the PC is in the Interrupt Vector Table */
diff --git a/arch/ia64/sn/kernel/sn2/timer.c b/arch/ia64/sn/kernel/sn2/timer.c
index 21d6f09e3447..c34efda122e1 100644
--- a/arch/ia64/sn/kernel/sn2/timer.c
+++ b/arch/ia64/sn/kernel/sn2/timer.c
@@ -33,8 +33,6 @@ static struct clocksource clocksource_sn2 = {
.rating = 450,
.read = read_sn2,
.mask = (1LL << 55) - 1,
- .mult = 0,
- .shift = 10,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
@@ -57,9 +55,7 @@ ia64_sn_udelay (unsigned long usecs)
void __init sn_timer_init(void)
{
clocksource_sn2.fsys_mmio = RTC_COUNTER_ADDR;
- clocksource_sn2.mult = clocksource_hz2mult(sn_rtc_cycles_per_second,
- clocksource_sn2.shift);
- clocksource_register(&clocksource_sn2);
+ clocksource_register_hz(&clocksource_sn2, sn_rtc_cycles_per_second);
ia64_udelay = &ia64_sn_udelay;
}
diff --git a/arch/ia64/xen/irq_xen.c b/arch/ia64/xen/irq_xen.c
index 108bb858acf2..b279e142c633 100644
--- a/arch/ia64/xen/irq_xen.c
+++ b/arch/ia64/xen/irq_xen.c
@@ -92,6 +92,8 @@ static unsigned short saved_irq_cnt;
static int xen_slab_ready;
#ifdef CONFIG_SMP
+#include <linux/sched.h>
+
/* Dummy stub. Though we may check XEN_RESCHEDULE_VECTOR before __do_IRQ,
* it ends up to issue several memory accesses upon percpu data and
* thus adds unnecessary traffic to other paths.
@@ -99,7 +101,13 @@ static int xen_slab_ready;
static irqreturn_t
xen_dummy_handler(int irq, void *dev_id)
{
+ return IRQ_HANDLED;
+}
+static irqreturn_t
+xen_resched_handler(int irq, void *dev_id)
+{
+ scheduler_ipi();
return IRQ_HANDLED;
}
@@ -110,7 +118,7 @@ static struct irqaction xen_ipi_irqaction = {
};
static struct irqaction xen_resched_irqaction = {
- .handler = xen_dummy_handler,
+ .handler = xen_resched_handler,
.flags = IRQF_DISABLED,
.name = "resched"
};
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig
index 736b808d2291..85b44e858225 100644
--- a/arch/m32r/Kconfig
+++ b/arch/m32r/Kconfig
@@ -256,14 +256,6 @@ config ARCH_HAS_ILOG2_U64
bool
default n
-config GENERIC_FIND_NEXT_BIT
- bool
- default y
-
-config GENERIC_FIND_BIT_LE
- bool
- default y
-
config GENERIC_HWEIGHT
bool
default y
diff --git a/arch/m32r/Kconfig.debug b/arch/m32r/Kconfig.debug
index 2e1019ddbb22..bb1afc1a31cc 100644
--- a/arch/m32r/Kconfig.debug
+++ b/arch/m32r/Kconfig.debug
@@ -9,15 +9,6 @@ config DEBUG_STACKOVERFLOW
This option will cause messages to be printed if free stack space
drops below a certain limit.
-config DEBUG_STACK_USAGE
- bool "Stack utilization instrumentation"
- depends on DEBUG_KERNEL
- help
- Enables the display of the minimum amount of free stack which each
- task has ever had available in the sysrq-T and sysrq-P debug output.
-
- This option will slow down process creation somewhat.
-
config DEBUG_PAGEALLOC
bool "Debug page memory allocations"
depends on DEBUG_KERNEL && BROKEN
diff --git a/arch/m32r/include/asm/smp.h b/arch/m32r/include/asm/smp.h
index e67ded1aab91..cf7829a61551 100644
--- a/arch/m32r/include/asm/smp.h
+++ b/arch/m32r/include/asm/smp.h
@@ -81,11 +81,11 @@ static __inline__ int cpu_number_map(int cpu)
static __inline__ unsigned int num_booting_cpus(void)
{
- return cpus_weight(cpu_callout_map);
+ return cpumask_weight(&cpu_callout_map);
}
extern void smp_send_timer(void);
-extern unsigned long send_IPI_mask_phys(cpumask_t, int, int);
+extern unsigned long send_IPI_mask_phys(const cpumask_t*, int, int);
extern void arch_send_call_function_single_ipi(int cpu);
extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
@@ -94,8 +94,6 @@ extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
#define NO_PROC_ID (0xff) /* No processor magic marker */
-#define PROC_CHANGE_PENALTY (15) /* Schedule penalty */
-
/*
* M32R-mp IPI
*/
diff --git a/arch/m32r/kernel/smp.c b/arch/m32r/kernel/smp.c
index 31cef20b2996..092d40a6708e 100644
--- a/arch/m32r/kernel/smp.c
+++ b/arch/m32r/kernel/smp.c
@@ -30,6 +30,7 @@
#include <asm/io.h>
#include <asm/mmu_context.h>
#include <asm/m32r.h>
+#include <asm/tlbflush.h>
/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
/* Data structures and variables */
@@ -61,33 +62,22 @@ extern spinlock_t ipi_lock[];
/* Function Prototypes */
/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
-void smp_send_reschedule(int);
void smp_reschedule_interrupt(void);
-
-void smp_flush_cache_all(void);
void smp_flush_cache_all_interrupt(void);
-void smp_flush_tlb_all(void);
static void flush_tlb_all_ipi(void *);
-
-void smp_flush_tlb_mm(struct mm_struct *);
-void smp_flush_tlb_range(struct vm_area_struct *, unsigned long, \
- unsigned long);
-void smp_flush_tlb_page(struct vm_area_struct *, unsigned long);
static void flush_tlb_others(cpumask_t, struct mm_struct *,
struct vm_area_struct *, unsigned long);
+
void smp_invalidate_interrupt(void);
-void smp_send_stop(void);
static void stop_this_cpu(void *);
-void smp_send_timer(void);
void smp_ipi_timer_interrupt(struct pt_regs *);
void smp_local_timer_interrupt(void);
static void send_IPI_allbutself(int, int);
static void send_IPI_mask(const struct cpumask *, int, int);
-unsigned long send_IPI_mask_phys(cpumask_t, int, int);
/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
/* Rescheduling request Routines */
@@ -122,8 +112,6 @@ void smp_send_reschedule(int cpu_id)
*
* Description: This routine executes on CPU which received
* 'RESCHEDULE_IPI'.
- * Rescheduling is processed at the exit of interrupt
- * operation.
*
* Born on Date: 2002.02.05
*
@@ -138,7 +126,7 @@ void smp_send_reschedule(int cpu_id)
*==========================================================================*/
void smp_reschedule_interrupt(void)
{
- /* nothing to do */
+ scheduler_ipi();
}
/*==========================================================================*
@@ -164,10 +152,10 @@ void smp_flush_cache_all(void)
unsigned long *mask;
preempt_disable();
- cpumask = cpu_online_map;
- cpu_clear(smp_processor_id(), cpumask);
+ cpumask_copy(&cpumask, cpu_online_mask);
+ cpumask_clear_cpu(smp_processor_id(), &cpumask);
spin_lock(&flushcache_lock);
- mask=cpus_addr(cpumask);
+ mask=cpumask_bits(&cpumask);
atomic_set_mask(*mask, (atomic_t *)&flushcache_cpumask);
send_IPI_mask(&cpumask, INVALIDATE_CACHE_IPI, 0);
_flush_cache_copyback_all();
@@ -265,8 +253,8 @@ void smp_flush_tlb_mm(struct mm_struct *mm)
preempt_disable();
cpu_id = smp_processor_id();
mmc = &mm->context[cpu_id];
- cpu_mask = *mm_cpumask(mm);
- cpu_clear(cpu_id, cpu_mask);
+ cpumask_copy(&cpu_mask, mm_cpumask(mm));
+ cpumask_clear_cpu(cpu_id, &cpu_mask);
if (*mmc != NO_CONTEXT) {
local_irq_save(flags);
@@ -277,7 +265,7 @@ void smp_flush_tlb_mm(struct mm_struct *mm)
cpumask_clear_cpu(cpu_id, mm_cpumask(mm));
local_irq_restore(flags);
}
- if (!cpus_empty(cpu_mask))
+ if (!cpumask_empty(&cpu_mask))
flush_tlb_others(cpu_mask, mm, NULL, FLUSH_ALL);
preempt_enable();
@@ -335,8 +323,8 @@ void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long va)
preempt_disable();
cpu_id = smp_processor_id();
mmc = &mm->context[cpu_id];
- cpu_mask = *mm_cpumask(mm);
- cpu_clear(cpu_id, cpu_mask);
+ cpumask_copy(&cpu_mask, mm_cpumask(mm));
+ cpumask_clear_cpu(cpu_id, &cpu_mask);
#ifdef DEBUG_SMP
if (!mm)
@@ -350,7 +338,7 @@ void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long va)
__flush_tlb_page(va);
local_irq_restore(flags);
}
- if (!cpus_empty(cpu_mask))
+ if (!cpumask_empty(&cpu_mask))
flush_tlb_others(cpu_mask, mm, vma, va);
preempt_enable();
@@ -397,14 +385,14 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
* - current CPU must not be in mask
* - mask must exist :)
*/
- BUG_ON(cpus_empty(cpumask));
+ BUG_ON(cpumask_empty(&cpumask));
- BUG_ON(cpu_isset(smp_processor_id(), cpumask));
+ BUG_ON(cpumask_test_cpu(smp_processor_id(), &cpumask));
BUG_ON(!mm);
/* If a CPU which we ran on has gone down, OK. */
- cpus_and(cpumask, cpumask, cpu_online_map);
- if (cpus_empty(cpumask))
+ cpumask_and(&cpumask, &cpumask, cpu_online_mask);
+ if (cpumask_empty(&cpumask))
return;
/*
@@ -418,7 +406,7 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
flush_mm = mm;
flush_vma = vma;
flush_va = va;
- mask=cpus_addr(cpumask);
+ mask=cpumask_bits(&cpumask);
atomic_set_mask(*mask, (atomic_t *)&flush_cpumask);
/*
@@ -427,7 +415,7 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
*/
send_IPI_mask(&cpumask, INVALIDATE_TLB_IPI, 0);
- while (!cpus_empty(flush_cpumask)) {
+ while (!cpumask_empty((cpumask_t*)&flush_cpumask)) {
/* nothing. lockup detection does not belong here */
mb();
}
@@ -462,7 +450,7 @@ void smp_invalidate_interrupt(void)
int cpu_id = smp_processor_id();
unsigned long *mmc = &flush_mm->context[cpu_id];
- if (!cpu_isset(cpu_id, flush_cpumask))
+ if (!cpumask_test_cpu(cpu_id, &flush_cpumask))
return;
if (flush_va == FLUSH_ALL) {
@@ -480,7 +468,7 @@ void smp_invalidate_interrupt(void)
__flush_tlb_page(va);
}
}
- cpu_clear(cpu_id, flush_cpumask);
+ cpumask_clear_cpu(cpu_id, (cpumask_t*)&flush_cpumask);
}
/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
@@ -532,7 +520,7 @@ static void stop_this_cpu(void *dummy)
/*
* Remove this CPU:
*/
- cpu_clear(cpu_id, cpu_online_map);
+ set_cpu_online(cpu_id, false);
/*
* PSW IE = 1;
@@ -727,8 +715,8 @@ static void send_IPI_allbutself(int ipi_num, int try)
{
cpumask_t cpumask;
- cpumask = cpu_online_map;
- cpu_clear(smp_processor_id(), cpumask);
+ cpumask_copy(&cpumask, cpu_online_mask);
+ cpumask_clear_cpu(smp_processor_id(), &cpumask);
send_IPI_mask(&cpumask, ipi_num, try);
}
@@ -765,13 +753,13 @@ static void send_IPI_mask(const struct cpumask *cpumask, int ipi_num, int try)
cpumask_and(&tmp, cpumask, cpu_online_mask);
BUG_ON(!cpumask_equal(cpumask, &tmp));
- physid_mask = CPU_MASK_NONE;
+ cpumask_clear(&physid_mask);
for_each_cpu(cpu_id, cpumask) {
if ((phys_id = cpu_to_physid(cpu_id)) != -1)
- cpu_set(phys_id, physid_mask);
+ cpumask_set_cpu(phys_id, &physid_mask);
}
- send_IPI_mask_phys(physid_mask, ipi_num, try);
+ send_IPI_mask_phys(&physid_mask, ipi_num, try);
}
/*==========================================================================*
@@ -794,14 +782,14 @@ static void send_IPI_mask(const struct cpumask *cpumask, int ipi_num, int try)
* ---------- --- --------------------------------------------------------
*
*==========================================================================*/
-unsigned long send_IPI_mask_phys(cpumask_t physid_mask, int ipi_num,
+unsigned long send_IPI_mask_phys(const cpumask_t *physid_mask, int ipi_num,
int try)
{
spinlock_t *ipilock;
volatile unsigned long *ipicr_addr;
unsigned long ipicr_val;
unsigned long my_physid_mask;
- unsigned long mask = cpus_addr(physid_mask)[0];
+ unsigned long mask = cpumask_bits(physid_mask)[0];
if (mask & ~physids_coerce(phys_cpu_present_map))
diff --git a/arch/m32r/kernel/smpboot.c b/arch/m32r/kernel/smpboot.c
index e034844cfc0d..cfdbe5d15002 100644
--- a/arch/m32r/kernel/smpboot.c
+++ b/arch/m32r/kernel/smpboot.c
@@ -135,9 +135,9 @@ void __devinit smp_prepare_boot_cpu(void)
{
bsp_phys_id = hard_smp_processor_id();
physid_set(bsp_phys_id, phys_cpu_present_map);
- cpu_set(0, cpu_online_map); /* BSP's cpu_id == 0 */
- cpu_set(0, cpu_callout_map);
- cpu_set(0, cpu_callin_map);
+ set_cpu_online(0, true); /* BSP's cpu_id == 0 */
+ cpumask_set_cpu(0, &cpu_callout_map);
+ cpumask_set_cpu(0, &cpu_callin_map);
/*
* Initialize the logical to physical CPU number mapping
@@ -178,7 +178,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
for (phys_id = 0 ; phys_id < nr_cpu ; phys_id++)
physid_set(phys_id, phys_cpu_present_map);
#ifndef CONFIG_HOTPLUG_CPU
- init_cpu_present(&cpu_possible_map);
+ init_cpu_present(cpu_possible_mask);
#endif
show_mp_info(nr_cpu);
@@ -294,10 +294,10 @@ static void __init do_boot_cpu(int phys_id)
send_status = 0;
boot_status = 0;
- cpu_set(phys_id, cpu_bootout_map);
+ cpumask_set_cpu(phys_id, &cpu_bootout_map);
/* Send Startup IPI */
- send_IPI_mask_phys(cpumask_of_cpu(phys_id), CPU_BOOT_IPI, 0);
+ send_IPI_mask_phys(cpumask_of(phys_id), CPU_BOOT_IPI, 0);
Dprintk("Waiting for send to finish...\n");
timeout = 0;
@@ -306,7 +306,7 @@ static void __init do_boot_cpu(int phys_id)
do {
Dprintk("+");
udelay(1000);
- send_status = !cpu_isset(phys_id, cpu_bootin_map);
+ send_status = !cpumask_test_cpu(phys_id, &cpu_bootin_map);
} while (send_status && (timeout++ < 100));
Dprintk("After Startup.\n");
@@ -316,19 +316,19 @@ static void __init do_boot_cpu(int phys_id)
* allow APs to start initializing.
*/
Dprintk("Before Callout %d.\n", cpu_id);
- cpu_set(cpu_id, cpu_callout_map);
+ cpumask_set_cpu(cpu_id, &cpu_callout_map);
Dprintk("After Callout %d.\n", cpu_id);
/*
* Wait 5s total for a response
*/
for (timeout = 0; timeout < 5000; timeout++) {
- if (cpu_isset(cpu_id, cpu_callin_map))
+ if (cpumask_test_cpu(cpu_id, &cpu_callin_map))
break; /* It has booted */
udelay(1000);
}
- if (cpu_isset(cpu_id, cpu_callin_map)) {
+ if (cpumask_test_cpu(cpu_id, &cpu_callin_map)) {
/* number CPUs logically, starting from 1 (BSP is 0) */
Dprintk("OK.\n");
} else {
@@ -340,9 +340,9 @@ static void __init do_boot_cpu(int phys_id)
if (send_status || boot_status) {
unmap_cpu_to_physid(cpu_id, phys_id);
- cpu_clear(cpu_id, cpu_callout_map);
- cpu_clear(cpu_id, cpu_callin_map);
- cpu_clear(cpu_id, cpu_initialized);
+ cpumask_clear_cpu(cpu_id, &cpu_callout_map);
+ cpumask_clear_cpu(cpu_id, &cpu_callin_map);
+ cpumask_clear_cpu(cpu_id, &cpu_initialized);
cpucount--;
}
}
@@ -351,17 +351,17 @@ int __cpuinit __cpu_up(unsigned int cpu_id)
{
int timeout;
- cpu_set(cpu_id, smp_commenced_mask);
+ cpumask_set_cpu(cpu_id, &smp_commenced_mask);
/*
* Wait 5s total for a response
*/
for (timeout = 0; timeout < 5000; timeout++) {
- if (cpu_isset(cpu_id, cpu_online_map))
+ if (cpu_online(cpu_id))
break;
udelay(1000);
}
- if (!cpu_isset(cpu_id, cpu_online_map))
+ if (!cpu_online(cpu_id))
BUG();
return 0;
@@ -373,11 +373,11 @@ void __init smp_cpus_done(unsigned int max_cpus)
unsigned long bogosum = 0;
for (timeout = 0; timeout < 5000; timeout++) {
- if (cpus_equal(cpu_callin_map, cpu_online_map))
+ if (cpumask_equal(&cpu_callin_map, cpu_online_mask))
break;
udelay(1000);
}
- if (!cpus_equal(cpu_callin_map, cpu_online_map))
+ if (!cpumask_equal(&cpu_callin_map, cpu_online_mask))
BUG();
for (cpu_id = 0 ; cpu_id < num_online_cpus() ; cpu_id++)
@@ -388,7 +388,7 @@ void __init smp_cpus_done(unsigned int max_cpus)
*/
Dprintk("Before bogomips.\n");
if (cpucount) {
- for_each_cpu_mask(cpu_id, cpu_online_map)
+ for_each_cpu(cpu_id,cpu_online_mask)
bogosum += cpu_data[cpu_id].loops_per_jiffy;
printk(KERN_INFO "Total of %d processors activated " \
@@ -425,7 +425,7 @@ int __init start_secondary(void *unused)
cpu_init();
preempt_disable();
smp_callin();
- while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
+ while (!cpumask_test_cpu(smp_processor_id(), &smp_commenced_mask))
cpu_relax();
smp_online();
@@ -463,7 +463,7 @@ static void __init smp_callin(void)
int cpu_id = smp_processor_id();
unsigned long timeout;
- if (cpu_isset(cpu_id, cpu_callin_map)) {
+ if (cpumask_test_cpu(cpu_id, &cpu_callin_map)) {
printk("huh, phys CPU#%d, CPU#%d already present??\n",
phys_id, cpu_id);
BUG();
@@ -474,7 +474,7 @@ static void __init smp_callin(void)
timeout = jiffies + (2 * HZ);
while (time_before(jiffies, timeout)) {
/* Has the boot CPU finished it's STARTUP sequence ? */
- if (cpu_isset(cpu_id, cpu_callout_map))
+ if (cpumask_test_cpu(cpu_id, &cpu_callout_map))
break;
cpu_relax();
}
@@ -486,7 +486,7 @@ static void __init smp_callin(void)
}
/* Allow the master to continue. */
- cpu_set(cpu_id, cpu_callin_map);
+ cpumask_set_cpu(cpu_id, &cpu_callin_map);
}
static void __init smp_online(void)
@@ -503,7 +503,7 @@ static void __init smp_online(void)
/* Save our processor parameters */
smp_store_cpu_info(cpu_id);
- cpu_set(cpu_id, cpu_online_map);
+ set_cpu_online(cpu_id, true);
}
/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
diff --git a/arch/m32r/kernel/vmlinux.lds.S b/arch/m32r/kernel/vmlinux.lds.S
index c194d64cdbb9..018e4a711d79 100644
--- a/arch/m32r/kernel/vmlinux.lds.S
+++ b/arch/m32r/kernel/vmlinux.lds.S
@@ -44,6 +44,7 @@ SECTIONS
EXCEPTION_TABLE(16)
NOTES
+ _sdata = .; /* Start of data section */
RODATA
RW_DATA_SECTION(32, PAGE_SIZE, THREAD_SIZE)
_edata = .; /* End of data section */
@@ -53,7 +54,7 @@ SECTIONS
__init_begin = .;
INIT_TEXT_SECTION(PAGE_SIZE)
INIT_DATA_SECTION(16)
- PERCPU(32, PAGE_SIZE)
+ PERCPU_SECTION(32)
. = ALIGN(PAGE_SIZE);
__init_end = .;
/* freed after init ends here */
diff --git a/arch/m32r/mm/discontig.c b/arch/m32r/mm/discontig.c
index 5d2858f6eede..2c468e8b5853 100644
--- a/arch/m32r/mm/discontig.c
+++ b/arch/m32r/mm/discontig.c
@@ -149,6 +149,7 @@ unsigned long __init zone_sizes_init(void)
zholes_size[ZONE_DMA] = mp->holes;
holes += zholes_size[ZONE_DMA];
+ node_set_state(nid, N_NORMAL_MEMORY);
free_area_init_node(nid, zones_size, start_pfn, zholes_size);
}
diff --git a/arch/m32r/mm/init.c b/arch/m32r/mm/init.c
index 73e2205ebf5a..78b660e903da 100644
--- a/arch/m32r/mm/init.c
+++ b/arch/m32r/mm/init.c
@@ -35,8 +35,6 @@ extern char __init_begin, __init_end;
pgd_t swapper_pg_dir[1024];
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
/*
* Cache of MMU context last used.
*/
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 75531da02a40..d66e34c718d0 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -5,6 +5,7 @@ config M68K
select HAVE_AOUT if MMU
select GENERIC_ATOMIC64 if MMU
select HAVE_GENERIC_HARDIRQS if !MMU
+ select GENERIC_IRQ_SHOW if !MMU
config RWSEM_GENERIC_SPINLOCK
bool
diff --git a/arch/m68k/Kconfig.nommu b/arch/m68k/Kconfig.nommu
index 273bccab9517..fc98f9b9d4d2 100644
--- a/arch/m68k/Kconfig.nommu
+++ b/arch/m68k/Kconfig.nommu
@@ -2,10 +2,6 @@ config FPU
bool
default n
-config GENERIC_FIND_NEXT_BIT
- bool
- default y
-
config GENERIC_GPIO
bool
default n
diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c
index b995513d527f..95022b04b62d 100644
--- a/arch/m68k/atari/atakeyb.c
+++ b/arch/m68k/atari/atakeyb.c
@@ -36,13 +36,10 @@
/* Hook for MIDI serial driver */
void (*atari_MIDI_interrupt_hook) (void);
-/* Hook for mouse driver */
-void (*atari_mouse_interrupt_hook) (char *);
/* Hook for keyboard inputdev driver */
void (*atari_input_keyboard_interrupt_hook) (unsigned char, char);
/* Hook for mouse inputdev driver */
void (*atari_input_mouse_interrupt_hook) (char *);
-EXPORT_SYMBOL(atari_mouse_interrupt_hook);
EXPORT_SYMBOL(atari_input_keyboard_interrupt_hook);
EXPORT_SYMBOL(atari_input_mouse_interrupt_hook);
@@ -263,8 +260,8 @@ repeat:
kb_state.buf[kb_state.len++] = scancode;
if (kb_state.len == 3) {
kb_state.state = KEYBOARD;
- if (atari_mouse_interrupt_hook)
- atari_mouse_interrupt_hook(kb_state.buf);
+ if (atari_input_mouse_interrupt_hook)
+ atari_input_mouse_interrupt_hook(kb_state.buf);
}
break;
@@ -575,7 +572,7 @@ int atari_keyb_init(void)
kb_state.len = 0;
error = request_irq(IRQ_MFP_ACIA, atari_keyboard_interrupt,
- IRQ_TYPE_SLOW, "keyboard/mouse/MIDI",
+ IRQ_TYPE_SLOW, "keyboard,mouse,MIDI",
atari_keyboard_interrupt);
if (error)
return error;
diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c
index 604329fafbb8..ddbf43ca8858 100644
--- a/arch/m68k/atari/stdma.c
+++ b/arch/m68k/atari/stdma.c
@@ -180,7 +180,7 @@ void __init stdma_init(void)
{
stdma_isr = NULL;
if (request_irq(IRQ_MFP_FDC, stdma_int, IRQ_TYPE_SLOW | IRQF_SHARED,
- "ST-DMA: floppy/ACSI/IDE/Falcon-SCSI", stdma_int))
+ "ST-DMA floppy,ACSI,IDE,Falcon-SCSI", stdma_int))
pr_err("Couldn't register ST-DMA interrupt\n");
}
diff --git a/arch/m68k/include/asm/MC68EZ328.h b/arch/m68k/include/asm/MC68EZ328.h
index 69b7f9139e5e..d1bde58ab0dd 100644
--- a/arch/m68k/include/asm/MC68EZ328.h
+++ b/arch/m68k/include/asm/MC68EZ328.h
@@ -1047,7 +1047,7 @@ typedef volatile struct {
#define WATCHDOG_EN 0x0001 /* Watchdog Enabled */
#define WATCHDOG_ISEL 0x0002 /* Select the watchdog interrupt */
-#define WATCHDOG_INTF 0x0080 /* Watchdog interrupt occcured */
+#define WATCHDOG_INTF 0x0080 /* Watchdog interrupt occurred */
#define WATCHDOG_CNT_MASK 0x0300 /* Watchdog Counter */
#define WATCHDOG_CNT_SHIFT 8
diff --git a/arch/m68k/include/asm/MC68VZ328.h b/arch/m68k/include/asm/MC68VZ328.h
index 2b9bf626a0a5..6bd1bf1f85ea 100644
--- a/arch/m68k/include/asm/MC68VZ328.h
+++ b/arch/m68k/include/asm/MC68VZ328.h
@@ -1143,7 +1143,7 @@ typedef struct {
#define WATCHDOG_EN 0x0001 /* Watchdog Enabled */
#define WATCHDOG_ISEL 0x0002 /* Select the watchdog interrupt */
-#define WATCHDOG_INTF 0x0080 /* Watchdog interrupt occcured */
+#define WATCHDOG_INTF 0x0080 /* Watchdog interrupt occurred */
#define WATCHDOG_CNT_MASK 0x0300 /* Watchdog Counter */
#define WATCHDOG_CNT_SHIFT 8
diff --git a/arch/m68k/include/asm/atarikb.h b/arch/m68k/include/asm/atarikb.h
index 546e7da5804f..68f3622bf591 100644
--- a/arch/m68k/include/asm/atarikb.h
+++ b/arch/m68k/include/asm/atarikb.h
@@ -34,8 +34,6 @@ void ikbd_joystick_disable(void);
/* Hook for MIDI serial driver */
extern void (*atari_MIDI_interrupt_hook) (void);
-/* Hook for mouse driver */
-extern void (*atari_mouse_interrupt_hook) (char *);
/* Hook for keyboard inputdev driver */
extern void (*atari_input_keyboard_interrupt_hook) (unsigned char, char);
/* Hook for mouse inputdev driver */
diff --git a/arch/m68k/include/asm/bitops_mm.h b/arch/m68k/include/asm/bitops_mm.h
index 9d69f6e62365..89cf5b814a4d 100644
--- a/arch/m68k/include/asm/bitops_mm.h
+++ b/arch/m68k/include/asm/bitops_mm.h
@@ -181,14 +181,15 @@ static inline int find_first_zero_bit(const unsigned long *vaddr,
{
const unsigned long *p = vaddr;
int res = 32;
+ unsigned int words;
unsigned long num;
if (!size)
return 0;
- size = (size + 31) >> 5;
+ words = (size + 31) >> 5;
while (!(num = ~*p++)) {
- if (!--size)
+ if (!--words)
goto out;
}
@@ -196,8 +197,10 @@ static inline int find_first_zero_bit(const unsigned long *vaddr,
: "=d" (res) : "d" (num & -num));
res ^= 31;
out:
- return ((long)p - (long)vaddr - 4) * 8 + res;
+ res += ((long)p - (long)vaddr - 4) * 8;
+ return res < size ? res : size;
}
+#define find_first_zero_bit find_first_zero_bit
static inline int find_next_zero_bit(const unsigned long *vaddr, int size,
int offset)
@@ -215,27 +218,33 @@ static inline int find_next_zero_bit(const unsigned long *vaddr, int size,
/* Look for zero in first longword */
__asm__ __volatile__ ("bfffo %1{#0,#0},%0"
: "=d" (res) : "d" (num & -num));
- if (res < 32)
- return offset + (res ^ 31);
+ if (res < 32) {
+ offset += res ^ 31;
+ return offset < size ? offset : size;
+ }
offset += 32;
+
+ if (offset >= size)
+ return size;
}
/* No zero yet, search remaining full bytes for a zero */
- res = find_first_zero_bit(p, size - ((long)p - (long)vaddr) * 8);
- return offset + res;
+ return offset + find_first_zero_bit(p, size - offset);
}
+#define find_next_zero_bit find_next_zero_bit
static inline int find_first_bit(const unsigned long *vaddr, unsigned size)
{
const unsigned long *p = vaddr;
int res = 32;
+ unsigned int words;
unsigned long num;
if (!size)
return 0;
- size = (size + 31) >> 5;
+ words = (size + 31) >> 5;
while (!(num = *p++)) {
- if (!--size)
+ if (!--words)
goto out;
}
@@ -243,8 +252,10 @@ static inline int find_first_bit(const unsigned long *vaddr, unsigned size)
: "=d" (res) : "d" (num & -num));
res ^= 31;
out:
- return ((long)p - (long)vaddr - 4) * 8 + res;
+ res += ((long)p - (long)vaddr - 4) * 8;
+ return res < size ? res : size;
}
+#define find_first_bit find_first_bit
static inline int find_next_bit(const unsigned long *vaddr, int size,
int offset)
@@ -262,14 +273,19 @@ static inline int find_next_bit(const unsigned long *vaddr, int size,
/* Look for one in first longword */
__asm__ __volatile__ ("bfffo %1{#0,#0},%0"
: "=d" (res) : "d" (num & -num));
- if (res < 32)
- return offset + (res ^ 31);
+ if (res < 32) {
+ offset += res ^ 31;
+ return offset < size ? offset : size;
+ }
offset += 32;
+
+ if (offset >= size)
+ return size;
}
/* No one yet, search remaining full bytes for a one */
- res = find_first_bit(p, size - ((long)p - (long)vaddr) * 8);
- return offset + res;
+ return offset + find_first_bit(p, size - offset);
}
+#define find_next_bit find_next_bit
/*
* ffz = Find First Zero in word. Undefined if no zero exists,
@@ -366,24 +382,27 @@ static inline int test_bit_le(int nr, const void *vaddr)
static inline int find_first_zero_bit_le(const void *vaddr, unsigned size)
{
const unsigned long *p = vaddr, *addr = vaddr;
- int res;
+ int res = 0;
+ unsigned int words;
if (!size)
return 0;
- size = (size >> 5) + ((size & 31) > 0);
- while (*p++ == ~0UL)
- {
- if (--size == 0)
- return (p - addr) << 5;
+ words = (size >> 5) + ((size & 31) > 0);
+ while (*p++ == ~0UL) {
+ if (--words == 0)
+ goto out;
}
--p;
for (res = 0; res < 32; res++)
if (!test_bit_le(res, p))
break;
- return (p - addr) * 32 + res;
+out:
+ res += (p - addr) * 32;
+ return res < size ? res : size;
}
+#define find_first_zero_bit_le find_first_zero_bit_le
static inline unsigned long find_next_zero_bit_le(const void *addr,
unsigned long size, unsigned long offset)
@@ -400,35 +419,45 @@ static inline unsigned long find_next_zero_bit_le(const void *addr,
offset -= bit;
/* Look for zero in first longword */
for (res = bit; res < 32; res++)
- if (!test_bit_le(res, p))
- return offset + res;
+ if (!test_bit_le(res, p)) {
+ offset += res;
+ return offset < size ? offset : size;
+ }
p++;
offset += 32;
+
+ if (offset >= size)
+ return size;
}
/* No zero yet, search remaining full bytes for a zero */
return offset + find_first_zero_bit_le(p, size - offset);
}
+#define find_next_zero_bit_le find_next_zero_bit_le
static inline int find_first_bit_le(const void *vaddr, unsigned size)
{
const unsigned long *p = vaddr, *addr = vaddr;
- int res;
+ int res = 0;
+ unsigned int words;
if (!size)
return 0;
- size = (size >> 5) + ((size & 31) > 0);
+ words = (size >> 5) + ((size & 31) > 0);
while (*p++ == 0UL) {
- if (--size == 0)
- return (p - addr) << 5;
+ if (--words == 0)
+ goto out;
}
--p;
for (res = 0; res < 32; res++)
if (test_bit_le(res, p))
break;
- return (p - addr) * 32 + res;
+out:
+ res += (p - addr) * 32;
+ return res < size ? res : size;
}
+#define find_first_bit_le find_first_bit_le
static inline unsigned long find_next_bit_le(const void *addr,
unsigned long size, unsigned long offset)
@@ -445,14 +474,20 @@ static inline unsigned long find_next_bit_le(const void *addr,
offset -= bit;
/* Look for one in first longword */
for (res = bit; res < 32; res++)
- if (test_bit_le(res, p))
- return offset + res;
+ if (test_bit_le(res, p)) {
+ offset += res;
+ return offset < size ? offset : size;
+ }
p++;
offset += 32;
+
+ if (offset >= size)
+ return size;
}
/* No set bit yet, search remaining full bytes for a set bit */
return offset + find_first_bit_le(p, size - offset);
}
+#define find_next_bit_le find_next_bit_le
/* Bitmap functions for the ext2 filesystem. */
diff --git a/arch/m68k/include/asm/bitops_no.h b/arch/m68k/include/asm/bitops_no.h
index 7d3779fdc5b6..72e85acdd7bd 100644
--- a/arch/m68k/include/asm/bitops_no.h
+++ b/arch/m68k/include/asm/bitops_no.h
@@ -246,23 +246,7 @@ static inline int __test_and_clear_bit_le(int nr, volatile void *addr)
return retval;
}
-#define ext2_set_bit_atomic(lock, nr, addr) \
- ({ \
- int ret; \
- spin_lock(lock); \
- ret = __test_and_set_bit_le((nr), (addr)); \
- spin_unlock(lock); \
- ret; \
- })
-
-#define ext2_clear_bit_atomic(lock, nr, addr) \
- ({ \
- int ret; \
- spin_lock(lock); \
- ret = __test_and_clear_bit_le((nr), (addr)); \
- spin_unlock(lock); \
- ret; \
- })
+#include <asm-generic/bitops/ext2-atomic.h>
static inline int test_bit_le(int nr, const volatile void *addr)
{
@@ -335,6 +319,10 @@ found_first:
found_middle:
return result + ffz(__swab32(tmp));
}
+#define find_next_zero_bit_le find_next_zero_bit_le
+
+extern unsigned long find_next_bit_le(const void *addr,
+ unsigned long size, unsigned long offset);
#endif /* __KERNEL__ */
diff --git a/arch/m68k/include/asm/io_no.h b/arch/m68k/include/asm/io_no.h
index cf20f3097af6..353bf754a972 100644
--- a/arch/m68k/include/asm/io_no.h
+++ b/arch/m68k/include/asm/io_no.h
@@ -144,8 +144,10 @@ static inline void io_insl(unsigned int addr, void *buf, int len)
#define IOMAP_NOCACHE_NONSER 2
#define IOMAP_WRITETHROUGH 3
-extern void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag);
-
+static inline void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
+{
+ return (void *) physaddr;
+}
static inline void *ioremap(unsigned long physaddr, unsigned long size)
{
return __ioremap(physaddr, size, IOMAP_NOCACHE_SER);
@@ -163,7 +165,7 @@ static inline void *ioremap_fullcache(unsigned long physaddr, unsigned long size
return __ioremap(physaddr, size, IOMAP_FULL_CACHING);
}
-extern void iounmap(void *addr);
+#define iounmap(addr) do { } while(0)
/*
* Convert a physical pointer to a virtual kernel pointer for /dev/mem
diff --git a/arch/m68k/include/asm/unistd.h b/arch/m68k/include/asm/unistd.h
index 29e17907d9f2..f3b649de2a1b 100644
--- a/arch/m68k/include/asm/unistd.h
+++ b/arch/m68k/include/asm/unistd.h
@@ -22,7 +22,7 @@
#define __NR_mknod 14
#define __NR_chmod 15
#define __NR_chown 16
-#define __NR_break 17
+/*#define __NR_break 17*/
#define __NR_oldstat 18
#define __NR_lseek 19
#define __NR_getpid 20
@@ -36,11 +36,11 @@
#define __NR_oldfstat 28
#define __NR_pause 29
#define __NR_utime 30
-#define __NR_stty 31
-#define __NR_gtty 32
+/*#define __NR_stty 31*/
+/*#define __NR_gtty 32*/
#define __NR_access 33
#define __NR_nice 34
-#define __NR_ftime 35
+/*#define __NR_ftime 35*/
#define __NR_sync 36
#define __NR_kill 37
#define __NR_rename 38
@@ -49,7 +49,7 @@
#define __NR_dup 41
#define __NR_pipe 42
#define __NR_times 43
-#define __NR_prof 44
+/*#define __NR_prof 44*/
#define __NR_brk 45
#define __NR_setgid 46
#define __NR_getgid 47
@@ -58,13 +58,13 @@
#define __NR_getegid 50
#define __NR_acct 51
#define __NR_umount2 52
-#define __NR_lock 53
+/*#define __NR_lock 53*/
#define __NR_ioctl 54
#define __NR_fcntl 55
-#define __NR_mpx 56
+/*#define __NR_mpx 56*/
#define __NR_setpgid 57
-#define __NR_ulimit 58
-#define __NR_oldolduname 59
+/*#define __NR_ulimit 58*/
+/*#define __NR_oldolduname 59*/
#define __NR_umask 60
#define __NR_chroot 61
#define __NR_ustat 62
@@ -103,10 +103,10 @@
#define __NR_fchown 95
#define __NR_getpriority 96
#define __NR_setpriority 97
-#define __NR_profil 98
+/*#define __NR_profil 98*/
#define __NR_statfs 99
#define __NR_fstatfs 100
-#define __NR_ioperm 101
+/*#define __NR_ioperm 101*/
#define __NR_socketcall 102
#define __NR_syslog 103
#define __NR_setitimer 104
@@ -114,11 +114,11 @@
#define __NR_stat 106
#define __NR_lstat 107
#define __NR_fstat 108
-#define __NR_olduname 109
-#define __NR_iopl /* 110 */ not supported
+/*#define __NR_olduname 109*/
+/*#define __NR_iopl 110*/ /* not supported */
#define __NR_vhangup 111
-#define __NR_idle /* 112 */ Obsolete
-#define __NR_vm86 /* 113 */ not supported
+/*#define __NR_idle 112*/ /* Obsolete */
+/*#define __NR_vm86 113*/ /* not supported */
#define __NR_wait4 114
#define __NR_swapoff 115
#define __NR_sysinfo 116
@@ -132,17 +132,17 @@
#define __NR_adjtimex 124
#define __NR_mprotect 125
#define __NR_sigprocmask 126
-#define __NR_create_module 127
+/*#define __NR_create_module 127*/
#define __NR_init_module 128
#define __NR_delete_module 129
-#define __NR_get_kernel_syms 130
+/*#define __NR_get_kernel_syms 130*/
#define __NR_quotactl 131
#define __NR_getpgid 132
#define __NR_fchdir 133
#define __NR_bdflush 134
#define __NR_sysfs 135
#define __NR_personality 136
-#define __NR_afs_syscall 137 /* Syscall for Andrew File System */
+/*#define __NR_afs_syscall 137*/ /* Syscall for Andrew File System */
#define __NR_setfsuid 138
#define __NR_setfsgid 139
#define __NR__llseek 140
@@ -172,7 +172,7 @@
#define __NR_setresuid 164
#define __NR_getresuid 165
#define __NR_getpagesize 166
-#define __NR_query_module 167
+/*#define __NR_query_module 167*/
#define __NR_poll 168
#define __NR_nfsservctl 169
#define __NR_setresgid 170
@@ -193,8 +193,8 @@
#define __NR_capset 185
#define __NR_sigaltstack 186
#define __NR_sendfile 187
-#define __NR_getpmsg 188 /* some people actually want streams */
-#define __NR_putpmsg 189 /* some people actually want streams */
+/*#define __NR_getpmsg 188*/ /* some people actually want streams */
+/*#define __NR_putpmsg 189*/ /* some people actually want streams */
#define __NR_vfork 190
#define __NR_ugetrlimit 191
#define __NR_mmap2 192
@@ -223,6 +223,8 @@
#define __NR_setfsuid32 215
#define __NR_setfsgid32 216
#define __NR_pivot_root 217
+/* 218*/
+/* 219*/
#define __NR_getdents64 220
#define __NR_gettid 221
#define __NR_tkill 222
@@ -281,7 +283,7 @@
#define __NR_mq_notify 275
#define __NR_mq_getsetattr 276
#define __NR_waitid 277
-#define __NR_vserver 278
+/*#define __NR_vserver 278*/
#define __NR_add_key 279
#define __NR_request_key 280
#define __NR_keyctl 281
diff --git a/arch/m68k/kernel/Makefile_mm b/arch/m68k/kernel/Makefile_mm
index 55d5d6b680a2..aced67804579 100644
--- a/arch/m68k/kernel/Makefile_mm
+++ b/arch/m68k/kernel/Makefile_mm
@@ -10,7 +10,7 @@ endif
extra-y += vmlinux.lds
obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o module.o \
- sys_m68k.o time.o setup.o m68k_ksyms.o devres.o
+ sys_m68k.o time.o setup.o m68k_ksyms.o devres.o syscalltable.o
devres-y = ../../../kernel/irq/devres.o
diff --git a/arch/m68k/kernel/asm-offsets.c b/arch/m68k/kernel/asm-offsets.c
index 59a69a5c62f2..983fed9d469b 100644
--- a/arch/m68k/kernel/asm-offsets.c
+++ b/arch/m68k/kernel/asm-offsets.c
@@ -1,5 +1,105 @@
-#ifdef CONFIG_MMU
-#include "asm-offsets_mm.c"
+/*
+ * This program is used to generate definitions needed by
+ * assembly language modules.
+ *
+ * We use the technique used in the OSF Mach kernel code:
+ * generate asm statements containing #defines,
+ * compile this file to assembler, and then extract the
+ * #defines from the assembly-language output.
+ */
+
+#define ASM_OFFSETS_C
+
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/kbuild.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/amigahw.h>
+#include <linux/font.h>
+
+int main(void)
+{
+ /* offsets into the task struct */
+ DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
+ DEFINE(TASK_MM, offsetof(struct task_struct, mm));
+ DEFINE(TASK_INFO, offsetof(struct task_struct, thread.info));
+ DEFINE(TASK_TINFO, offsetof(struct task_struct, thread.info));
+
+ /* offsets into the thread struct */
+ DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
+ DEFINE(THREAD_USP, offsetof(struct thread_struct, usp));
+ DEFINE(THREAD_SR, offsetof(struct thread_struct, sr));
+ DEFINE(THREAD_FS, offsetof(struct thread_struct, fs));
+ DEFINE(THREAD_CRP, offsetof(struct thread_struct, crp));
+ DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0));
+ DEFINE(THREAD_FPREG, offsetof(struct thread_struct, fp));
+ DEFINE(THREAD_FPCNTL, offsetof(struct thread_struct, fpcntl));
+ DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate));
+
+ /* offsets into the thread_info struct */
+ DEFINE(TINFO_PREEMPT, offsetof(struct thread_info, preempt_count));
+ DEFINE(TINFO_FLAGS, offsetof(struct thread_info, flags));
+
+ /* offsets into the pt_regs */
+ DEFINE(PT_OFF_D0, offsetof(struct pt_regs, d0));
+ DEFINE(PT_OFF_ORIG_D0, offsetof(struct pt_regs, orig_d0));
+ DEFINE(PT_OFF_D1, offsetof(struct pt_regs, d1));
+ DEFINE(PT_OFF_D2, offsetof(struct pt_regs, d2));
+ DEFINE(PT_OFF_D3, offsetof(struct pt_regs, d3));
+ DEFINE(PT_OFF_D4, offsetof(struct pt_regs, d4));
+ DEFINE(PT_OFF_D5, offsetof(struct pt_regs, d5));
+ DEFINE(PT_OFF_A0, offsetof(struct pt_regs, a0));
+ DEFINE(PT_OFF_A1, offsetof(struct pt_regs, a1));
+ DEFINE(PT_OFF_A2, offsetof(struct pt_regs, a2));
+ DEFINE(PT_OFF_PC, offsetof(struct pt_regs, pc));
+ DEFINE(PT_OFF_SR, offsetof(struct pt_regs, sr));
+
+ /* bitfields are a bit difficult */
+#ifdef CONFIG_COLDFIRE
+ DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, sr) - 2);
#else
-#include "asm-offsets_no.c"
+ DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4);
+#endif
+
+ /* offsets into the irq_cpustat_t struct */
+ DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
+
+ /* signal defines */
+ DEFINE(LSIGSEGV, SIGSEGV);
+ DEFINE(LSEGV_MAPERR, SEGV_MAPERR);
+ DEFINE(LSIGTRAP, SIGTRAP);
+ DEFINE(LTRAP_TRACE, TRAP_TRACE);
+
+#ifdef CONFIG_MMU
+ /* offsets into the bi_record struct */
+ DEFINE(BIR_TAG, offsetof(struct bi_record, tag));
+ DEFINE(BIR_SIZE, offsetof(struct bi_record, size));
+ DEFINE(BIR_DATA, offsetof(struct bi_record, data));
+
+ /* offsets into font_desc (drivers/video/console/font.h) */
+ DEFINE(FONT_DESC_IDX, offsetof(struct font_desc, idx));
+ DEFINE(FONT_DESC_NAME, offsetof(struct font_desc, name));
+ DEFINE(FONT_DESC_WIDTH, offsetof(struct font_desc, width));
+ DEFINE(FONT_DESC_HEIGHT, offsetof(struct font_desc, height));
+ DEFINE(FONT_DESC_DATA, offsetof(struct font_desc, data));
+ DEFINE(FONT_DESC_PREF, offsetof(struct font_desc, pref));
+
+ /* offsets into the custom struct */
+ DEFINE(CUSTOMBASE, &amiga_custom);
+ DEFINE(C_INTENAR, offsetof(struct CUSTOM, intenar));
+ DEFINE(C_INTREQR, offsetof(struct CUSTOM, intreqr));
+ DEFINE(C_INTENA, offsetof(struct CUSTOM, intena));
+ DEFINE(C_INTREQ, offsetof(struct CUSTOM, intreq));
+ DEFINE(C_SERDATR, offsetof(struct CUSTOM, serdatr));
+ DEFINE(C_SERDAT, offsetof(struct CUSTOM, serdat));
+ DEFINE(C_SERPER, offsetof(struct CUSTOM, serper));
+ DEFINE(CIAABASE, &ciaa);
+ DEFINE(CIABBASE, &ciab);
+ DEFINE(C_PRA, offsetof(struct CIA, pra));
+ DEFINE(ZTWOBASE, zTwoBase);
#endif
+
+ return 0;
+}
diff --git a/arch/m68k/kernel/asm-offsets_mm.c b/arch/m68k/kernel/asm-offsets_mm.c
deleted file mode 100644
index 78e59b82ebc3..000000000000
--- a/arch/m68k/kernel/asm-offsets_mm.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * This program is used to generate definitions needed by
- * assembly language modules.
- *
- * We use the technique used in the OSF Mach kernel code:
- * generate asm statements containing #defines,
- * compile this file to assembler, and then extract the
- * #defines from the assembly-language output.
- */
-
-#define ASM_OFFSETS_C
-
-#include <linux/stddef.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
-#include <linux/kbuild.h>
-#include <asm/bootinfo.h>
-#include <asm/irq.h>
-#include <asm/amigahw.h>
-#include <linux/font.h>
-
-int main(void)
-{
- /* offsets into the task struct */
- DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
- DEFINE(TASK_INFO, offsetof(struct task_struct, thread.info));
- DEFINE(TASK_MM, offsetof(struct task_struct, mm));
-#ifdef CONFIG_MMU
- DEFINE(TASK_TINFO, offsetof(struct task_struct, thread.info));
-#endif
-
- /* offsets into the thread struct */
- DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
- DEFINE(THREAD_USP, offsetof(struct thread_struct, usp));
- DEFINE(THREAD_SR, offsetof(struct thread_struct, sr));
- DEFINE(THREAD_FS, offsetof(struct thread_struct, fs));
- DEFINE(THREAD_CRP, offsetof(struct thread_struct, crp));
- DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0));
- DEFINE(THREAD_FPREG, offsetof(struct thread_struct, fp));
- DEFINE(THREAD_FPCNTL, offsetof(struct thread_struct, fpcntl));
- DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate));
-
- /* offsets into the thread_info struct */
- DEFINE(TINFO_PREEMPT, offsetof(struct thread_info, preempt_count));
- DEFINE(TINFO_FLAGS, offsetof(struct thread_info, flags));
-
- /* offsets into the pt_regs */
- DEFINE(PT_OFF_D0, offsetof(struct pt_regs, d0));
- DEFINE(PT_OFF_ORIG_D0, offsetof(struct pt_regs, orig_d0));
- DEFINE(PT_OFF_D1, offsetof(struct pt_regs, d1));
- DEFINE(PT_OFF_D2, offsetof(struct pt_regs, d2));
- DEFINE(PT_OFF_D3, offsetof(struct pt_regs, d3));
- DEFINE(PT_OFF_D4, offsetof(struct pt_regs, d4));
- DEFINE(PT_OFF_D5, offsetof(struct pt_regs, d5));
- DEFINE(PT_OFF_A0, offsetof(struct pt_regs, a0));
- DEFINE(PT_OFF_A1, offsetof(struct pt_regs, a1));
- DEFINE(PT_OFF_A2, offsetof(struct pt_regs, a2));
- DEFINE(PT_OFF_PC, offsetof(struct pt_regs, pc));
- DEFINE(PT_OFF_SR, offsetof(struct pt_regs, sr));
- /* bitfields are a bit difficult */
- DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4);
-
- /* offsets into the irq_cpustat_t struct */
- DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
-
- /* offsets into the bi_record struct */
- DEFINE(BIR_TAG, offsetof(struct bi_record, tag));
- DEFINE(BIR_SIZE, offsetof(struct bi_record, size));
- DEFINE(BIR_DATA, offsetof(struct bi_record, data));
-
- /* offsets into font_desc (drivers/video/console/font.h) */
- DEFINE(FONT_DESC_IDX, offsetof(struct font_desc, idx));
- DEFINE(FONT_DESC_NAME, offsetof(struct font_desc, name));
- DEFINE(FONT_DESC_WIDTH, offsetof(struct font_desc, width));
- DEFINE(FONT_DESC_HEIGHT, offsetof(struct font_desc, height));
- DEFINE(FONT_DESC_DATA, offsetof(struct font_desc, data));
- DEFINE(FONT_DESC_PREF, offsetof(struct font_desc, pref));
-
- /* signal defines */
- DEFINE(LSIGSEGV, SIGSEGV);
- DEFINE(LSEGV_MAPERR, SEGV_MAPERR);
- DEFINE(LSIGTRAP, SIGTRAP);
- DEFINE(LTRAP_TRACE, TRAP_TRACE);
-
- /* offsets into the custom struct */
- DEFINE(CUSTOMBASE, &amiga_custom);
- DEFINE(C_INTENAR, offsetof(struct CUSTOM, intenar));
- DEFINE(C_INTREQR, offsetof(struct CUSTOM, intreqr));
- DEFINE(C_INTENA, offsetof(struct CUSTOM, intena));
- DEFINE(C_INTREQ, offsetof(struct CUSTOM, intreq));
- DEFINE(C_SERDATR, offsetof(struct CUSTOM, serdatr));
- DEFINE(C_SERDAT, offsetof(struct CUSTOM, serdat));
- DEFINE(C_SERPER, offsetof(struct CUSTOM, serper));
- DEFINE(CIAABASE, &ciaa);
- DEFINE(CIABBASE, &ciab);
- DEFINE(C_PRA, offsetof(struct CIA, pra));
- DEFINE(ZTWOBASE, zTwoBase);
-
- return 0;
-}
diff --git a/arch/m68k/kernel/asm-offsets_no.c b/arch/m68k/kernel/asm-offsets_no.c
deleted file mode 100644
index ffe02f41ad46..000000000000
--- a/arch/m68k/kernel/asm-offsets_no.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * This program is used to generate definitions needed by
- * assembly language modules.
- *
- * We use the technique used in the OSF Mach kernel code:
- * generate asm statements containing #defines,
- * compile this file to assembler, and then extract the
- * #defines from the assembly-language output.
- */
-
-#include <linux/stddef.h>
-#include <linux/sched.h>
-#include <linux/kernel_stat.h>
-#include <linux/ptrace.h>
-#include <linux/hardirq.h>
-#include <linux/kbuild.h>
-#include <asm/bootinfo.h>
-#include <asm/irq.h>
-#include <asm/thread_info.h>
-
-int main(void)
-{
- /* offsets into the task struct */
- DEFINE(TASK_THREAD, offsetof(struct task_struct, thread));
- DEFINE(TASK_MM, offsetof(struct task_struct, mm));
-
- /* offsets into the irq_cpustat_t struct */
- DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t, __softirq_pending));
-
- /* offsets into the thread struct */
- DEFINE(THREAD_KSP, offsetof(struct thread_struct, ksp));
- DEFINE(THREAD_USP, offsetof(struct thread_struct, usp));
- DEFINE(THREAD_SR, offsetof(struct thread_struct, sr));
- DEFINE(THREAD_FS, offsetof(struct thread_struct, fs));
- DEFINE(THREAD_CRP, offsetof(struct thread_struct, crp));
- DEFINE(THREAD_ESP0, offsetof(struct thread_struct, esp0));
- DEFINE(THREAD_FPREG, offsetof(struct thread_struct, fp));
- DEFINE(THREAD_FPCNTL, offsetof(struct thread_struct, fpcntl));
- DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate));
-
- /* offsets into the pt_regs */
- DEFINE(PT_OFF_D0, offsetof(struct pt_regs, d0));
- DEFINE(PT_OFF_ORIG_D0, offsetof(struct pt_regs, orig_d0));
- DEFINE(PT_OFF_D1, offsetof(struct pt_regs, d1));
- DEFINE(PT_OFF_D2, offsetof(struct pt_regs, d2));
- DEFINE(PT_OFF_D3, offsetof(struct pt_regs, d3));
- DEFINE(PT_OFF_D4, offsetof(struct pt_regs, d4));
- DEFINE(PT_OFF_D5, offsetof(struct pt_regs, d5));
- DEFINE(PT_OFF_A0, offsetof(struct pt_regs, a0));
- DEFINE(PT_OFF_A1, offsetof(struct pt_regs, a1));
- DEFINE(PT_OFF_A2, offsetof(struct pt_regs, a2));
- DEFINE(PT_OFF_PC, offsetof(struct pt_regs, pc));
- DEFINE(PT_OFF_SR, offsetof(struct pt_regs, sr));
-
-#ifdef CONFIG_COLDFIRE
- /* bitfields are a bit difficult */
- DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, sr) - 2);
-#else
- /* bitfields are a bit difficult */
- DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, pc) + 4);
-#endif
-
- /* signal defines */
- DEFINE(SIGSEGV, SIGSEGV);
- DEFINE(SEGV_MAPERR, SEGV_MAPERR);
- DEFINE(SIGTRAP, SIGTRAP);
- DEFINE(TRAP_TRACE, TRAP_TRACE);
-
- DEFINE(PT_PTRACED, PT_PTRACED);
-
- /* Offsets in thread_info structure */
- DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
- DEFINE(TI_PREEMPTCOUNT, offsetof(struct thread_info, preempt_count));
-
- return 0;
-}
diff --git a/arch/m68k/kernel/entry_mm.S b/arch/m68k/kernel/entry_mm.S
index 1359ee659574..bd0ec05263b2 100644
--- a/arch/m68k/kernel/entry_mm.S
+++ b/arch/m68k/kernel/entry_mm.S
@@ -407,351 +407,3 @@ resume:
rts
-.data
-ALIGN
-sys_call_table:
- .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */
- .long sys_exit
- .long sys_fork
- .long sys_read
- .long sys_write
- .long sys_open /* 5 */
- .long sys_close
- .long sys_waitpid
- .long sys_creat
- .long sys_link
- .long sys_unlink /* 10 */
- .long sys_execve
- .long sys_chdir
- .long sys_time
- .long sys_mknod
- .long sys_chmod /* 15 */
- .long sys_chown16
- .long sys_ni_syscall /* old break syscall holder */
- .long sys_stat
- .long sys_lseek
- .long sys_getpid /* 20 */
- .long sys_mount
- .long sys_oldumount
- .long sys_setuid16
- .long sys_getuid16
- .long sys_stime /* 25 */
- .long sys_ptrace
- .long sys_alarm
- .long sys_fstat
- .long sys_pause
- .long sys_utime /* 30 */
- .long sys_ni_syscall /* old stty syscall holder */
- .long sys_ni_syscall /* old gtty syscall holder */
- .long sys_access
- .long sys_nice
- .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */
- .long sys_sync
- .long sys_kill
- .long sys_rename
- .long sys_mkdir
- .long sys_rmdir /* 40 */
- .long sys_dup
- .long sys_pipe
- .long sys_times
- .long sys_ni_syscall /* old prof syscall holder */
- .long sys_brk /* 45 */
- .long sys_setgid16
- .long sys_getgid16
- .long sys_signal
- .long sys_geteuid16
- .long sys_getegid16 /* 50 */
- .long sys_acct
- .long sys_umount /* recycled never used phys() */
- .long sys_ni_syscall /* old lock syscall holder */
- .long sys_ioctl
- .long sys_fcntl /* 55 */
- .long sys_ni_syscall /* old mpx syscall holder */
- .long sys_setpgid
- .long sys_ni_syscall /* old ulimit syscall holder */
- .long sys_ni_syscall
- .long sys_umask /* 60 */
- .long sys_chroot
- .long sys_ustat
- .long sys_dup2
- .long sys_getppid
- .long sys_getpgrp /* 65 */
- .long sys_setsid
- .long sys_sigaction
- .long sys_sgetmask
- .long sys_ssetmask
- .long sys_setreuid16 /* 70 */
- .long sys_setregid16
- .long sys_sigsuspend
- .long sys_sigpending
- .long sys_sethostname
- .long sys_setrlimit /* 75 */
- .long sys_old_getrlimit
- .long sys_getrusage
- .long sys_gettimeofday
- .long sys_settimeofday
- .long sys_getgroups16 /* 80 */
- .long sys_setgroups16
- .long sys_old_select
- .long sys_symlink
- .long sys_lstat
- .long sys_readlink /* 85 */
- .long sys_uselib
- .long sys_swapon
- .long sys_reboot
- .long sys_old_readdir
- .long sys_old_mmap /* 90 */
- .long sys_munmap
- .long sys_truncate
- .long sys_ftruncate
- .long sys_fchmod
- .long sys_fchown16 /* 95 */
- .long sys_getpriority
- .long sys_setpriority
- .long sys_ni_syscall /* old profil syscall holder */
- .long sys_statfs
- .long sys_fstatfs /* 100 */
- .long sys_ni_syscall /* ioperm for i386 */
- .long sys_socketcall
- .long sys_syslog
- .long sys_setitimer
- .long sys_getitimer /* 105 */
- .long sys_newstat
- .long sys_newlstat
- .long sys_newfstat
- .long sys_ni_syscall
- .long sys_ni_syscall /* 110 */ /* iopl for i386 */
- .long sys_vhangup
- .long sys_ni_syscall /* obsolete idle() syscall */
- .long sys_ni_syscall /* vm86old for i386 */
- .long sys_wait4
- .long sys_swapoff /* 115 */
- .long sys_sysinfo
- .long sys_ipc
- .long sys_fsync
- .long sys_sigreturn
- .long sys_clone /* 120 */
- .long sys_setdomainname
- .long sys_newuname
- .long sys_cacheflush /* modify_ldt for i386 */
- .long sys_adjtimex
- .long sys_mprotect /* 125 */
- .long sys_sigprocmask
- .long sys_ni_syscall /* old "create_module" */
- .long sys_init_module
- .long sys_delete_module
- .long sys_ni_syscall /* 130 - old "get_kernel_syms" */
- .long sys_quotactl
- .long sys_getpgid
- .long sys_fchdir
- .long sys_bdflush
- .long sys_sysfs /* 135 */
- .long sys_personality
- .long sys_ni_syscall /* for afs_syscall */
- .long sys_setfsuid16
- .long sys_setfsgid16
- .long sys_llseek /* 140 */
- .long sys_getdents
- .long sys_select
- .long sys_flock
- .long sys_msync
- .long sys_readv /* 145 */
- .long sys_writev
- .long sys_getsid
- .long sys_fdatasync
- .long sys_sysctl
- .long sys_mlock /* 150 */
- .long sys_munlock
- .long sys_mlockall
- .long sys_munlockall
- .long sys_sched_setparam
- .long sys_sched_getparam /* 155 */
- .long sys_sched_setscheduler
- .long sys_sched_getscheduler
- .long sys_sched_yield
- .long sys_sched_get_priority_max
- .long sys_sched_get_priority_min /* 160 */
- .long sys_sched_rr_get_interval
- .long sys_nanosleep
- .long sys_mremap
- .long sys_setresuid16
- .long sys_getresuid16 /* 165 */
- .long sys_getpagesize
- .long sys_ni_syscall /* old sys_query_module */
- .long sys_poll
- .long sys_nfsservctl
- .long sys_setresgid16 /* 170 */
- .long sys_getresgid16
- .long sys_prctl
- .long sys_rt_sigreturn
- .long sys_rt_sigaction
- .long sys_rt_sigprocmask /* 175 */
- .long sys_rt_sigpending
- .long sys_rt_sigtimedwait
- .long sys_rt_sigqueueinfo
- .long sys_rt_sigsuspend
- .long sys_pread64 /* 180 */
- .long sys_pwrite64
- .long sys_lchown16;
- .long sys_getcwd
- .long sys_capget
- .long sys_capset /* 185 */
- .long sys_sigaltstack
- .long sys_sendfile
- .long sys_ni_syscall /* streams1 */
- .long sys_ni_syscall /* streams2 */
- .long sys_vfork /* 190 */
- .long sys_getrlimit
- .long sys_mmap2
- .long sys_truncate64
- .long sys_ftruncate64
- .long sys_stat64 /* 195 */
- .long sys_lstat64
- .long sys_fstat64
- .long sys_chown
- .long sys_getuid
- .long sys_getgid /* 200 */
- .long sys_geteuid
- .long sys_getegid
- .long sys_setreuid
- .long sys_setregid
- .long sys_getgroups /* 205 */
- .long sys_setgroups
- .long sys_fchown
- .long sys_setresuid
- .long sys_getresuid
- .long sys_setresgid /* 210 */
- .long sys_getresgid
- .long sys_lchown
- .long sys_setuid
- .long sys_setgid
- .long sys_setfsuid /* 215 */
- .long sys_setfsgid
- .long sys_pivot_root
- .long sys_ni_syscall
- .long sys_ni_syscall
- .long sys_getdents64 /* 220 */
- .long sys_gettid
- .long sys_tkill
- .long sys_setxattr
- .long sys_lsetxattr
- .long sys_fsetxattr /* 225 */
- .long sys_getxattr
- .long sys_lgetxattr
- .long sys_fgetxattr
- .long sys_listxattr
- .long sys_llistxattr /* 230 */
- .long sys_flistxattr
- .long sys_removexattr
- .long sys_lremovexattr
- .long sys_fremovexattr
- .long sys_futex /* 235 */
- .long sys_sendfile64
- .long sys_mincore
- .long sys_madvise
- .long sys_fcntl64
- .long sys_readahead /* 240 */
- .long sys_io_setup
- .long sys_io_destroy
- .long sys_io_getevents
- .long sys_io_submit
- .long sys_io_cancel /* 245 */
- .long sys_fadvise64
- .long sys_exit_group
- .long sys_lookup_dcookie
- .long sys_epoll_create
- .long sys_epoll_ctl /* 250 */
- .long sys_epoll_wait
- .long sys_remap_file_pages
- .long sys_set_tid_address
- .long sys_timer_create
- .long sys_timer_settime /* 255 */
- .long sys_timer_gettime
- .long sys_timer_getoverrun
- .long sys_timer_delete
- .long sys_clock_settime
- .long sys_clock_gettime /* 260 */
- .long sys_clock_getres
- .long sys_clock_nanosleep
- .long sys_statfs64
- .long sys_fstatfs64
- .long sys_tgkill /* 265 */
- .long sys_utimes
- .long sys_fadvise64_64
- .long sys_mbind
- .long sys_get_mempolicy
- .long sys_set_mempolicy /* 270 */
- .long sys_mq_open
- .long sys_mq_unlink
- .long sys_mq_timedsend
- .long sys_mq_timedreceive
- .long sys_mq_notify /* 275 */
- .long sys_mq_getsetattr
- .long sys_waitid
- .long sys_ni_syscall /* for sys_vserver */
- .long sys_add_key
- .long sys_request_key /* 280 */
- .long sys_keyctl
- .long sys_ioprio_set
- .long sys_ioprio_get
- .long sys_inotify_init
- .long sys_inotify_add_watch /* 285 */
- .long sys_inotify_rm_watch
- .long sys_migrate_pages
- .long sys_openat
- .long sys_mkdirat
- .long sys_mknodat /* 290 */
- .long sys_fchownat
- .long sys_futimesat
- .long sys_fstatat64
- .long sys_unlinkat
- .long sys_renameat /* 295 */
- .long sys_linkat
- .long sys_symlinkat
- .long sys_readlinkat
- .long sys_fchmodat
- .long sys_faccessat /* 300 */
- .long sys_ni_syscall /* Reserved for pselect6 */
- .long sys_ni_syscall /* Reserved for ppoll */
- .long sys_unshare
- .long sys_set_robust_list
- .long sys_get_robust_list /* 305 */
- .long sys_splice
- .long sys_sync_file_range
- .long sys_tee
- .long sys_vmsplice
- .long sys_move_pages /* 310 */
- .long sys_sched_setaffinity
- .long sys_sched_getaffinity
- .long sys_kexec_load
- .long sys_getcpu
- .long sys_epoll_pwait /* 315 */
- .long sys_utimensat
- .long sys_signalfd
- .long sys_timerfd_create
- .long sys_eventfd
- .long sys_fallocate /* 320 */
- .long sys_timerfd_settime
- .long sys_timerfd_gettime
- .long sys_signalfd4
- .long sys_eventfd2
- .long sys_epoll_create1 /* 325 */
- .long sys_dup3
- .long sys_pipe2
- .long sys_inotify_init1
- .long sys_preadv
- .long sys_pwritev /* 330 */
- .long sys_rt_tgsigqueueinfo
- .long sys_perf_event_open
- .long sys_get_thread_area
- .long sys_set_thread_area
- .long sys_atomic_cmpxchg_32 /* 335 */
- .long sys_atomic_barrier
- .long sys_fanotify_init
- .long sys_fanotify_mark
- .long sys_prlimit64
- .long sys_name_to_handle_at /* 340 */
- .long sys_open_by_handle_at
- .long sys_clock_adjtime
- .long sys_syncfs
-
diff --git a/arch/m68k/kernel/entry_no.S b/arch/m68k/kernel/entry_no.S
index 2783f25e38bd..5f0f6b598b5a 100644
--- a/arch/m68k/kernel/entry_no.S
+++ b/arch/m68k/kernel/entry_no.S
@@ -24,7 +24,6 @@
* linux 2.4 support David McCullough <davidm@snapgear.com>
*/
-#include <linux/sys.h>
#include <linux/linkage.h>
#include <asm/errno.h>
#include <asm/setup.h>
diff --git a/arch/m68k/kernel/irq.c b/arch/m68k/kernel/irq.c
index 15dbc3e9d20c..544b8717d499 100644
--- a/arch/m68k/kernel/irq.c
+++ b/arch/m68k/kernel/irq.c
@@ -28,31 +28,3 @@ asmlinkage void do_IRQ(int irq, struct pt_regs *regs)
set_irq_regs(oldregs);
}
-
-int show_interrupts(struct seq_file *p, void *v)
-{
- struct irqaction *ap;
- int irq = *((loff_t *) v);
-
- if (irq == 0)
- seq_puts(p, " CPU0\n");
-
- if (irq < NR_IRQS) {
- struct irq_desc *desc = irq_to_desc(irq);
-
- ap = desc->action;
- if (ap) {
- seq_printf(p, "%3d: ", irq);
- seq_printf(p, "%10u ", kstat_irqs(irq));
- seq_printf(p, "%14s ", irq_desc_get_chip(desc)->name);
-
- seq_printf(p, "%s", ap->name);
- for (ap = ap->next; ap; ap = ap->next)
- seq_printf(p, ", %s", ap->name);
- seq_putc(p, '\n');
- }
- }
-
- return 0;
-}
-
diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c
index 4752c28ce0ac..33f82769547c 100644
--- a/arch/m68k/kernel/m68k_ksyms.c
+++ b/arch/m68k/kernel/m68k_ksyms.c
@@ -1,5 +1,33 @@
-#ifdef CONFIG_MMU
-#include "m68k_ksyms_mm.c"
-#else
-#include "m68k_ksyms_no.c"
+#include <linux/module.h>
+
+asmlinkage long long __ashldi3 (long long, int);
+asmlinkage long long __ashrdi3 (long long, int);
+asmlinkage long long __lshrdi3 (long long, int);
+asmlinkage long long __muldi3 (long long, long long);
+
+/* The following are special because they're not called
+ explicitly (the C compiler generates them). Fortunately,
+ their interface isn't gonna change any time soon now, so
+ it's OK to leave it out of version control. */
+EXPORT_SYMBOL(__ashldi3);
+EXPORT_SYMBOL(__ashrdi3);
+EXPORT_SYMBOL(__lshrdi3);
+EXPORT_SYMBOL(__muldi3);
+
+#if !defined(__mc68020__) && !defined(__mc68030__) && \
+ !defined(__mc68040__) && !defined(__mc68060__) && !defined(__mcpu32__)
+/*
+ * Simpler 68k and ColdFire parts also need a few other gcc functions.
+ */
+extern long long __divsi3(long long, long long);
+extern long long __modsi3(long long, long long);
+extern long long __mulsi3(long long, long long);
+extern long long __udivsi3(long long, long long);
+extern long long __umodsi3(long long, long long);
+
+EXPORT_SYMBOL(__divsi3);
+EXPORT_SYMBOL(__modsi3);
+EXPORT_SYMBOL(__mulsi3);
+EXPORT_SYMBOL(__udivsi3);
+EXPORT_SYMBOL(__umodsi3);
#endif
diff --git a/arch/m68k/kernel/m68k_ksyms_mm.c b/arch/m68k/kernel/m68k_ksyms_mm.c
deleted file mode 100644
index d900e77e5363..000000000000
--- a/arch/m68k/kernel/m68k_ksyms_mm.c
+++ /dev/null
@@ -1,16 +0,0 @@
-#include <linux/module.h>
-
-asmlinkage long long __ashldi3 (long long, int);
-asmlinkage long long __ashrdi3 (long long, int);
-asmlinkage long long __lshrdi3 (long long, int);
-asmlinkage long long __muldi3 (long long, long long);
-
-/* The following are special because they're not called
- explicitly (the C compiler generates them). Fortunately,
- their interface isn't gonna change any time soon now, so
- it's OK to leave it out of version control. */
-EXPORT_SYMBOL(__ashldi3);
-EXPORT_SYMBOL(__ashrdi3);
-EXPORT_SYMBOL(__lshrdi3);
-EXPORT_SYMBOL(__muldi3);
-
diff --git a/arch/m68k/kernel/m68k_ksyms_no.c b/arch/m68k/kernel/m68k_ksyms_no.c
deleted file mode 100644
index 39fe0a7aec32..000000000000
--- a/arch/m68k/kernel/m68k_ksyms_no.c
+++ /dev/null
@@ -1,78 +0,0 @@
-#include <linux/module.h>
-#include <linux/linkage.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/user.h>
-#include <linux/elfcore.h>
-#include <linux/in6.h>
-#include <linux/interrupt.h>
-
-#include <asm/setup.h>
-#include <asm/machdep.h>
-#include <asm/pgalloc.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/checksum.h>
-#include <asm/current.h>
-
-extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
-
-/* platform dependent support */
-
-EXPORT_SYMBOL(__ioremap);
-EXPORT_SYMBOL(iounmap);
-EXPORT_SYMBOL(dump_fpu);
-
-EXPORT_SYMBOL(ip_fast_csum);
-
-EXPORT_SYMBOL(kernel_thread);
-
-/* Networking helper routines. */
-EXPORT_SYMBOL(csum_partial_copy_nocheck);
-
-/* The following are special because they're not called
- explicitly (the C compiler generates them). Fortunately,
- their interface isn't gonna change any time soon now, so
- it's OK to leave it out of version control. */
-EXPORT_SYMBOL(memcpy);
-EXPORT_SYMBOL(memset);
-
-/*
- * libgcc functions - functions that are used internally by the
- * compiler... (prototypes are not correct though, but that
- * doesn't really matter since they're not versioned).
- */
-extern void __ashldi3(void);
-extern void __ashrdi3(void);
-extern void __divsi3(void);
-extern void __lshrdi3(void);
-extern void __modsi3(void);
-extern void __muldi3(void);
-extern void __mulsi3(void);
-extern void __udivsi3(void);
-extern void __umodsi3(void);
-
- /* gcc lib functions */
-EXPORT_SYMBOL(__ashldi3);
-EXPORT_SYMBOL(__ashrdi3);
-EXPORT_SYMBOL(__divsi3);
-EXPORT_SYMBOL(__lshrdi3);
-EXPORT_SYMBOL(__modsi3);
-EXPORT_SYMBOL(__muldi3);
-EXPORT_SYMBOL(__mulsi3);
-EXPORT_SYMBOL(__udivsi3);
-EXPORT_SYMBOL(__umodsi3);
-
-#ifdef CONFIG_COLDFIRE
-extern unsigned int *dma_device_address;
-extern unsigned long dma_base_addr, _ramend;
-EXPORT_SYMBOL(dma_base_addr);
-EXPORT_SYMBOL(dma_device_address);
-EXPORT_SYMBOL(_ramend);
-
-extern asmlinkage void trap(void);
-extern void *_ramvec;
-EXPORT_SYMBOL(trap);
-EXPORT_SYMBOL(_ramvec);
-#endif /* CONFIG_COLDFIRE */
diff --git a/arch/m68k/kernel/process_no.c b/arch/m68k/kernel/process_no.c
index e2a63af5d517..9b86ad11c68e 100644
--- a/arch/m68k/kernel/process_no.c
+++ b/arch/m68k/kernel/process_no.c
@@ -151,6 +151,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
set_fs(fs);
return retval;
}
+EXPORT_SYMBOL(kernel_thread);
void flush_thread(void)
{
@@ -283,6 +284,7 @@ int dump_fpu(struct pt_regs *regs, struct user_m68kfp_struct *fpu)
#endif
return 1;
}
+EXPORT_SYMBOL(dump_fpu);
/*
* Generic dumping code. Used for panic and debug.
diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c
index 63013df33584..8623f8dc16f8 100644
--- a/arch/m68k/kernel/sys_m68k.c
+++ b/arch/m68k/kernel/sys_m68k.c
@@ -1,5 +1,580 @@
+/*
+ * linux/arch/m68k/kernel/sys_m68k.c
+ *
+ * This file contains various random system calls that
+ * have a non-standard calling sequence on the Linux/m68k
+ * platform.
+ */
+
+#include <linux/capability.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/smp.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/stat.h>
+#include <linux/syscalls.h>
+#include <linux/mman.h>
+#include <linux/file.h>
+#include <linux/ipc.h>
+
+#include <asm/setup.h>
+#include <asm/uaccess.h>
+#include <asm/cachectl.h>
+#include <asm/traps.h>
+#include <asm/page.h>
+#include <asm/unistd.h>
+#include <asm/cacheflush.h>
+
#ifdef CONFIG_MMU
-#include "sys_m68k_mm.c"
+
+#include <asm/tlb.h>
+
+asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
+ unsigned long error_code);
+
+asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags,
+ unsigned long fd, unsigned long pgoff)
+{
+ /*
+ * This is wrong for sun3 - there PAGE_SIZE is 8Kb,
+ * so we need to shift the argument down by 1; m68k mmap64(3)
+ * (in libc) expects the last argument of mmap2 in 4Kb units.
+ */
+ return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff);
+}
+
+/* Convert virtual (user) address VADDR to physical address PADDR */
+#define virt_to_phys_040(vaddr) \
+({ \
+ unsigned long _mmusr, _paddr; \
+ \
+ __asm__ __volatile__ (".chip 68040\n\t" \
+ "ptestr (%1)\n\t" \
+ "movec %%mmusr,%0\n\t" \
+ ".chip 68k" \
+ : "=r" (_mmusr) \
+ : "a" (vaddr)); \
+ _paddr = (_mmusr & MMU_R_040) ? (_mmusr & PAGE_MASK) : 0; \
+ _paddr; \
+})
+
+static inline int
+cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
+{
+ unsigned long paddr, i;
+
+ switch (scope)
+ {
+ case FLUSH_SCOPE_ALL:
+ switch (cache)
+ {
+ case FLUSH_CACHE_DATA:
+ /* This nop is needed for some broken versions of the 68040. */
+ __asm__ __volatile__ ("nop\n\t"
+ ".chip 68040\n\t"
+ "cpusha %dc\n\t"
+ ".chip 68k");
+ break;
+ case FLUSH_CACHE_INSN:
+ __asm__ __volatile__ ("nop\n\t"
+ ".chip 68040\n\t"
+ "cpusha %ic\n\t"
+ ".chip 68k");
+ break;
+ default:
+ case FLUSH_CACHE_BOTH:
+ __asm__ __volatile__ ("nop\n\t"
+ ".chip 68040\n\t"
+ "cpusha %bc\n\t"
+ ".chip 68k");
+ break;
+ }
+ break;
+
+ case FLUSH_SCOPE_LINE:
+ /* Find the physical address of the first mapped page in the
+ address range. */
+ if ((paddr = virt_to_phys_040(addr))) {
+ paddr += addr & ~(PAGE_MASK | 15);
+ len = (len + (addr & 15) + 15) >> 4;
+ } else {
+ unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
+
+ if (len <= tmp)
+ return 0;
+ addr += tmp;
+ len -= tmp;
+ tmp = PAGE_SIZE;
+ for (;;)
+ {
+ if ((paddr = virt_to_phys_040(addr)))
+ break;
+ if (len <= tmp)
+ return 0;
+ addr += tmp;
+ len -= tmp;
+ }
+ len = (len + 15) >> 4;
+ }
+ i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
+ while (len--)
+ {
+ switch (cache)
+ {
+ case FLUSH_CACHE_DATA:
+ __asm__ __volatile__ ("nop\n\t"
+ ".chip 68040\n\t"
+ "cpushl %%dc,(%0)\n\t"
+ ".chip 68k"
+ : : "a" (paddr));
+ break;
+ case FLUSH_CACHE_INSN:
+ __asm__ __volatile__ ("nop\n\t"
+ ".chip 68040\n\t"
+ "cpushl %%ic,(%0)\n\t"
+ ".chip 68k"
+ : : "a" (paddr));
+ break;
+ default:
+ case FLUSH_CACHE_BOTH:
+ __asm__ __volatile__ ("nop\n\t"
+ ".chip 68040\n\t"
+ "cpushl %%bc,(%0)\n\t"
+ ".chip 68k"
+ : : "a" (paddr));
+ break;
+ }
+ if (!--i && len)
+ {
+ /*
+ * No need to page align here since it is done by
+ * virt_to_phys_040().
+ */
+ addr += PAGE_SIZE;
+ i = PAGE_SIZE / 16;
+ /* Recompute physical address when crossing a page
+ boundary. */
+ for (;;)
+ {
+ if ((paddr = virt_to_phys_040(addr)))
+ break;
+ if (len <= i)
+ return 0;
+ len -= i;
+ addr += PAGE_SIZE;
+ }
+ }
+ else
+ paddr += 16;
+ }
+ break;
+
+ default:
+ case FLUSH_SCOPE_PAGE:
+ len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
+ for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
+ {
+ if (!(paddr = virt_to_phys_040(addr)))
+ continue;
+ switch (cache)
+ {
+ case FLUSH_CACHE_DATA:
+ __asm__ __volatile__ ("nop\n\t"
+ ".chip 68040\n\t"
+ "cpushp %%dc,(%0)\n\t"
+ ".chip 68k"
+ : : "a" (paddr));
+ break;
+ case FLUSH_CACHE_INSN:
+ __asm__ __volatile__ ("nop\n\t"
+ ".chip 68040\n\t"
+ "cpushp %%ic,(%0)\n\t"
+ ".chip 68k"
+ : : "a" (paddr));
+ break;
+ default:
+ case FLUSH_CACHE_BOTH:
+ __asm__ __volatile__ ("nop\n\t"
+ ".chip 68040\n\t"
+ "cpushp %%bc,(%0)\n\t"
+ ".chip 68k"
+ : : "a" (paddr));
+ break;
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+#define virt_to_phys_060(vaddr) \
+({ \
+ unsigned long paddr; \
+ __asm__ __volatile__ (".chip 68060\n\t" \
+ "plpar (%0)\n\t" \
+ ".chip 68k" \
+ : "=a" (paddr) \
+ : "0" (vaddr)); \
+ (paddr); /* XXX */ \
+})
+
+static inline int
+cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
+{
+ unsigned long paddr, i;
+
+ /*
+ * 68060 manual says:
+ * cpush %dc : flush DC, remains valid (with our %cacr setup)
+ * cpush %ic : invalidate IC
+ * cpush %bc : flush DC + invalidate IC
+ */
+ switch (scope)
+ {
+ case FLUSH_SCOPE_ALL:
+ switch (cache)
+ {
+ case FLUSH_CACHE_DATA:
+ __asm__ __volatile__ (".chip 68060\n\t"
+ "cpusha %dc\n\t"
+ ".chip 68k");
+ break;
+ case FLUSH_CACHE_INSN:
+ __asm__ __volatile__ (".chip 68060\n\t"
+ "cpusha %ic\n\t"
+ ".chip 68k");
+ break;
+ default:
+ case FLUSH_CACHE_BOTH:
+ __asm__ __volatile__ (".chip 68060\n\t"
+ "cpusha %bc\n\t"
+ ".chip 68k");
+ break;
+ }
+ break;
+
+ case FLUSH_SCOPE_LINE:
+ /* Find the physical address of the first mapped page in the
+ address range. */
+ len += addr & 15;
+ addr &= -16;
+ if (!(paddr = virt_to_phys_060(addr))) {
+ unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
+
+ if (len <= tmp)
+ return 0;
+ addr += tmp;
+ len -= tmp;
+ tmp = PAGE_SIZE;
+ for (;;)
+ {
+ if ((paddr = virt_to_phys_060(addr)))
+ break;
+ if (len <= tmp)
+ return 0;
+ addr += tmp;
+ len -= tmp;
+ }
+ }
+ len = (len + 15) >> 4;
+ i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
+ while (len--)
+ {
+ switch (cache)
+ {
+ case FLUSH_CACHE_DATA:
+ __asm__ __volatile__ (".chip 68060\n\t"
+ "cpushl %%dc,(%0)\n\t"
+ ".chip 68k"
+ : : "a" (paddr));
+ break;
+ case FLUSH_CACHE_INSN:
+ __asm__ __volatile__ (".chip 68060\n\t"
+ "cpushl %%ic,(%0)\n\t"
+ ".chip 68k"
+ : : "a" (paddr));
+ break;
+ default:
+ case FLUSH_CACHE_BOTH:
+ __asm__ __volatile__ (".chip 68060\n\t"
+ "cpushl %%bc,(%0)\n\t"
+ ".chip 68k"
+ : : "a" (paddr));
+ break;
+ }
+ if (!--i && len)
+ {
+
+ /*
+ * We just want to jump to the first cache line
+ * in the next page.
+ */
+ addr += PAGE_SIZE;
+ addr &= PAGE_MASK;
+
+ i = PAGE_SIZE / 16;
+ /* Recompute physical address when crossing a page
+ boundary. */
+ for (;;)
+ {
+ if ((paddr = virt_to_phys_060(addr)))
+ break;
+ if (len <= i)
+ return 0;
+ len -= i;
+ addr += PAGE_SIZE;
+ }
+ }
+ else
+ paddr += 16;
+ }
+ break;
+
+ default:
+ case FLUSH_SCOPE_PAGE:
+ len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
+ addr &= PAGE_MASK; /* Workaround for bug in some
+ revisions of the 68060 */
+ for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
+ {
+ if (!(paddr = virt_to_phys_060(addr)))
+ continue;
+ switch (cache)
+ {
+ case FLUSH_CACHE_DATA:
+ __asm__ __volatile__ (".chip 68060\n\t"
+ "cpushp %%dc,(%0)\n\t"
+ ".chip 68k"
+ : : "a" (paddr));
+ break;
+ case FLUSH_CACHE_INSN:
+ __asm__ __volatile__ (".chip 68060\n\t"
+ "cpushp %%ic,(%0)\n\t"
+ ".chip 68k"
+ : : "a" (paddr));
+ break;
+ default:
+ case FLUSH_CACHE_BOTH:
+ __asm__ __volatile__ (".chip 68060\n\t"
+ "cpushp %%bc,(%0)\n\t"
+ ".chip 68k"
+ : : "a" (paddr));
+ break;
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+/* sys_cacheflush -- flush (part of) the processor cache. */
+asmlinkage int
+sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
+{
+ struct vm_area_struct *vma;
+ int ret = -EINVAL;
+
+ if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL ||
+ cache & ~FLUSH_CACHE_BOTH)
+ goto out;
+
+ if (scope == FLUSH_SCOPE_ALL) {
+ /* Only the superuser may explicitly flush the whole cache. */
+ ret = -EPERM;
+ if (!capable(CAP_SYS_ADMIN))
+ goto out;
+ } else {
+ /*
+ * Verify that the specified address region actually belongs
+ * to this process.
+ */
+ vma = find_vma (current->mm, addr);
+ ret = -EINVAL;
+ /* Check for overflow. */
+ if (addr + len < addr)
+ goto out;
+ if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end)
+ goto out;
+ }
+
+ if (CPU_IS_020_OR_030) {
+ if (scope == FLUSH_SCOPE_LINE && len < 256) {
+ unsigned long cacr;
+ __asm__ ("movec %%cacr, %0" : "=r" (cacr));
+ if (cache & FLUSH_CACHE_INSN)
+ cacr |= 4;
+ if (cache & FLUSH_CACHE_DATA)
+ cacr |= 0x400;
+ len >>= 2;
+ while (len--) {
+ __asm__ __volatile__ ("movec %1, %%caar\n\t"
+ "movec %0, %%cacr"
+ : /* no outputs */
+ : "r" (cacr), "r" (addr));
+ addr += 4;
+ }
+ } else {
+ /* Flush the whole cache, even if page granularity requested. */
+ unsigned long cacr;
+ __asm__ ("movec %%cacr, %0" : "=r" (cacr));
+ if (cache & FLUSH_CACHE_INSN)
+ cacr |= 8;
+ if (cache & FLUSH_CACHE_DATA)
+ cacr |= 0x800;
+ __asm__ __volatile__ ("movec %0, %%cacr" : : "r" (cacr));
+ }
+ ret = 0;
+ goto out;
+ } else {
+ /*
+ * 040 or 060: don't blindly trust 'scope', someone could
+ * try to flush a few megs of memory.
+ */
+
+ if (len>=3*PAGE_SIZE && scope<FLUSH_SCOPE_PAGE)
+ scope=FLUSH_SCOPE_PAGE;
+ if (len>=10*PAGE_SIZE && scope<FLUSH_SCOPE_ALL)
+ scope=FLUSH_SCOPE_ALL;
+ if (CPU_IS_040) {
+ ret = cache_flush_040 (addr, scope, cache, len);
+ } else if (CPU_IS_060) {
+ ret = cache_flush_060 (addr, scope, cache, len);
+ }
+ }
+out:
+ return ret;
+}
+
+/* This syscall gets its arguments in A0 (mem), D2 (oldval) and
+ D1 (newval). */
+asmlinkage int
+sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
+ unsigned long __user * mem)
+{
+ /* This was borrowed from ARM's implementation. */
+ for (;;) {
+ struct mm_struct *mm = current->mm;
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte;
+ spinlock_t *ptl;
+ unsigned long mem_value;
+
+ down_read(&mm->mmap_sem);
+ pgd = pgd_offset(mm, (unsigned long)mem);
+ if (!pgd_present(*pgd))
+ goto bad_access;
+ pmd = pmd_offset(pgd, (unsigned long)mem);
+ if (!pmd_present(*pmd))
+ goto bad_access;
+ pte = pte_offset_map_lock(mm, pmd, (unsigned long)mem, &ptl);
+ if (!pte_present(*pte) || !pte_dirty(*pte)
+ || !pte_write(*pte)) {
+ pte_unmap_unlock(pte, ptl);
+ goto bad_access;
+ }
+
+ mem_value = *mem;
+ if (mem_value == oldval)
+ *mem = newval;
+
+ pte_unmap_unlock(pte, ptl);
+ up_read(&mm->mmap_sem);
+ return mem_value;
+
+ bad_access:
+ up_read(&mm->mmap_sem);
+ /* This is not necessarily a bad access, we can get here if
+ a memory we're trying to write to should be copied-on-write.
+ Make the kernel do the necessary page stuff, then re-iterate.
+ Simulate a write access fault to do that. */
+ {
+ /* The first argument of the function corresponds to
+ D1, which is the first field of struct pt_regs. */
+ struct pt_regs *fp = (struct pt_regs *)&newval;
+
+ /* '3' is an RMW flag. */
+ if (do_page_fault(fp, (unsigned long)mem, 3))
+ /* If the do_page_fault() failed, we don't
+ have anything meaningful to return.
+ There should be a SIGSEGV pending for
+ the process. */
+ return 0xdeadbeef;
+ }
+ }
+}
+
#else
-#include "sys_m68k_no.c"
-#endif
+
+/* sys_cacheflush -- flush (part of) the processor cache. */
+asmlinkage int
+sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
+{
+ flush_cache_all();
+ return 0;
+}
+
+/* This syscall gets its arguments in A0 (mem), D2 (oldval) and
+ D1 (newval). */
+asmlinkage int
+sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
+ unsigned long __user * mem)
+{
+ struct mm_struct *mm = current->mm;
+ unsigned long mem_value;
+
+ down_read(&mm->mmap_sem);
+
+ mem_value = *mem;
+ if (mem_value == oldval)
+ *mem = newval;
+
+ up_read(&mm->mmap_sem);
+ return mem_value;
+}
+
+#endif /* CONFIG_MMU */
+
+asmlinkage int sys_getpagesize(void)
+{
+ return PAGE_SIZE;
+}
+
+/*
+ * Do a system call from kernel instead of calling sys_execve so we
+ * end up with proper pt_regs.
+ */
+int kernel_execve(const char *filename,
+ const char *const argv[],
+ const char *const envp[])
+{
+ register long __res asm ("%d0") = __NR_execve;
+ register long __a asm ("%d1") = (long)(filename);
+ register long __b asm ("%d2") = (long)(argv);
+ register long __c asm ("%d3") = (long)(envp);
+ asm volatile ("trap #0" : "+d" (__res)
+ : "d" (__a), "d" (__b), "d" (__c));
+ return __res;
+}
+
+asmlinkage unsigned long sys_get_thread_area(void)
+{
+ return current_thread_info()->tp_value;
+}
+
+asmlinkage int sys_set_thread_area(unsigned long tp)
+{
+ current_thread_info()->tp_value = tp;
+ return 0;
+}
+
+asmlinkage int sys_atomic_barrier(void)
+{
+ /* no code needed for uniprocs */
+ return 0;
+}
diff --git a/arch/m68k/kernel/sys_m68k_mm.c b/arch/m68k/kernel/sys_m68k_mm.c
deleted file mode 100644
index 3db2e7f902aa..000000000000
--- a/arch/m68k/kernel/sys_m68k_mm.c
+++ /dev/null
@@ -1,546 +0,0 @@
-/*
- * linux/arch/m68k/kernel/sys_m68k.c
- *
- * This file contains various random system calls that
- * have a non-standard calling sequence on the Linux/m68k
- * platform.
- */
-
-#include <linux/capability.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/smp.h>
-#include <linux/sem.h>
-#include <linux/msg.h>
-#include <linux/shm.h>
-#include <linux/stat.h>
-#include <linux/syscalls.h>
-#include <linux/mman.h>
-#include <linux/file.h>
-#include <linux/ipc.h>
-
-#include <asm/setup.h>
-#include <asm/uaccess.h>
-#include <asm/cachectl.h>
-#include <asm/traps.h>
-#include <asm/page.h>
-#include <asm/unistd.h>
-#include <linux/elf.h>
-#include <asm/tlb.h>
-
-asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
- unsigned long error_code);
-
-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, unsigned long pgoff)
-{
- /*
- * This is wrong for sun3 - there PAGE_SIZE is 8Kb,
- * so we need to shift the argument down by 1; m68k mmap64(3)
- * (in libc) expects the last argument of mmap2 in 4Kb units.
- */
- return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff);
-}
-
-/* Convert virtual (user) address VADDR to physical address PADDR */
-#define virt_to_phys_040(vaddr) \
-({ \
- unsigned long _mmusr, _paddr; \
- \
- __asm__ __volatile__ (".chip 68040\n\t" \
- "ptestr (%1)\n\t" \
- "movec %%mmusr,%0\n\t" \
- ".chip 68k" \
- : "=r" (_mmusr) \
- : "a" (vaddr)); \
- _paddr = (_mmusr & MMU_R_040) ? (_mmusr & PAGE_MASK) : 0; \
- _paddr; \
-})
-
-static inline int
-cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
-{
- unsigned long paddr, i;
-
- switch (scope)
- {
- case FLUSH_SCOPE_ALL:
- switch (cache)
- {
- case FLUSH_CACHE_DATA:
- /* This nop is needed for some broken versions of the 68040. */
- __asm__ __volatile__ ("nop\n\t"
- ".chip 68040\n\t"
- "cpusha %dc\n\t"
- ".chip 68k");
- break;
- case FLUSH_CACHE_INSN:
- __asm__ __volatile__ ("nop\n\t"
- ".chip 68040\n\t"
- "cpusha %ic\n\t"
- ".chip 68k");
- break;
- default:
- case FLUSH_CACHE_BOTH:
- __asm__ __volatile__ ("nop\n\t"
- ".chip 68040\n\t"
- "cpusha %bc\n\t"
- ".chip 68k");
- break;
- }
- break;
-
- case FLUSH_SCOPE_LINE:
- /* Find the physical address of the first mapped page in the
- address range. */
- if ((paddr = virt_to_phys_040(addr))) {
- paddr += addr & ~(PAGE_MASK | 15);
- len = (len + (addr & 15) + 15) >> 4;
- } else {
- unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
-
- if (len <= tmp)
- return 0;
- addr += tmp;
- len -= tmp;
- tmp = PAGE_SIZE;
- for (;;)
- {
- if ((paddr = virt_to_phys_040(addr)))
- break;
- if (len <= tmp)
- return 0;
- addr += tmp;
- len -= tmp;
- }
- len = (len + 15) >> 4;
- }
- i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
- while (len--)
- {
- switch (cache)
- {
- case FLUSH_CACHE_DATA:
- __asm__ __volatile__ ("nop\n\t"
- ".chip 68040\n\t"
- "cpushl %%dc,(%0)\n\t"
- ".chip 68k"
- : : "a" (paddr));
- break;
- case FLUSH_CACHE_INSN:
- __asm__ __volatile__ ("nop\n\t"
- ".chip 68040\n\t"
- "cpushl %%ic,(%0)\n\t"
- ".chip 68k"
- : : "a" (paddr));
- break;
- default:
- case FLUSH_CACHE_BOTH:
- __asm__ __volatile__ ("nop\n\t"
- ".chip 68040\n\t"
- "cpushl %%bc,(%0)\n\t"
- ".chip 68k"
- : : "a" (paddr));
- break;
- }
- if (!--i && len)
- {
- /*
- * No need to page align here since it is done by
- * virt_to_phys_040().
- */
- addr += PAGE_SIZE;
- i = PAGE_SIZE / 16;
- /* Recompute physical address when crossing a page
- boundary. */
- for (;;)
- {
- if ((paddr = virt_to_phys_040(addr)))
- break;
- if (len <= i)
- return 0;
- len -= i;
- addr += PAGE_SIZE;
- }
- }
- else
- paddr += 16;
- }
- break;
-
- default:
- case FLUSH_SCOPE_PAGE:
- len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
- for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
- {
- if (!(paddr = virt_to_phys_040(addr)))
- continue;
- switch (cache)
- {
- case FLUSH_CACHE_DATA:
- __asm__ __volatile__ ("nop\n\t"
- ".chip 68040\n\t"
- "cpushp %%dc,(%0)\n\t"
- ".chip 68k"
- : : "a" (paddr));
- break;
- case FLUSH_CACHE_INSN:
- __asm__ __volatile__ ("nop\n\t"
- ".chip 68040\n\t"
- "cpushp %%ic,(%0)\n\t"
- ".chip 68k"
- : : "a" (paddr));
- break;
- default:
- case FLUSH_CACHE_BOTH:
- __asm__ __volatile__ ("nop\n\t"
- ".chip 68040\n\t"
- "cpushp %%bc,(%0)\n\t"
- ".chip 68k"
- : : "a" (paddr));
- break;
- }
- }
- break;
- }
- return 0;
-}
-
-#define virt_to_phys_060(vaddr) \
-({ \
- unsigned long paddr; \
- __asm__ __volatile__ (".chip 68060\n\t" \
- "plpar (%0)\n\t" \
- ".chip 68k" \
- : "=a" (paddr) \
- : "0" (vaddr)); \
- (paddr); /* XXX */ \
-})
-
-static inline int
-cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
-{
- unsigned long paddr, i;
-
- /*
- * 68060 manual says:
- * cpush %dc : flush DC, remains valid (with our %cacr setup)
- * cpush %ic : invalidate IC
- * cpush %bc : flush DC + invalidate IC
- */
- switch (scope)
- {
- case FLUSH_SCOPE_ALL:
- switch (cache)
- {
- case FLUSH_CACHE_DATA:
- __asm__ __volatile__ (".chip 68060\n\t"
- "cpusha %dc\n\t"
- ".chip 68k");
- break;
- case FLUSH_CACHE_INSN:
- __asm__ __volatile__ (".chip 68060\n\t"
- "cpusha %ic\n\t"
- ".chip 68k");
- break;
- default:
- case FLUSH_CACHE_BOTH:
- __asm__ __volatile__ (".chip 68060\n\t"
- "cpusha %bc\n\t"
- ".chip 68k");
- break;
- }
- break;
-
- case FLUSH_SCOPE_LINE:
- /* Find the physical address of the first mapped page in the
- address range. */
- len += addr & 15;
- addr &= -16;
- if (!(paddr = virt_to_phys_060(addr))) {
- unsigned long tmp = PAGE_SIZE - (addr & ~PAGE_MASK);
-
- if (len <= tmp)
- return 0;
- addr += tmp;
- len -= tmp;
- tmp = PAGE_SIZE;
- for (;;)
- {
- if ((paddr = virt_to_phys_060(addr)))
- break;
- if (len <= tmp)
- return 0;
- addr += tmp;
- len -= tmp;
- }
- }
- len = (len + 15) >> 4;
- i = (PAGE_SIZE - (paddr & ~PAGE_MASK)) >> 4;
- while (len--)
- {
- switch (cache)
- {
- case FLUSH_CACHE_DATA:
- __asm__ __volatile__ (".chip 68060\n\t"
- "cpushl %%dc,(%0)\n\t"
- ".chip 68k"
- : : "a" (paddr));
- break;
- case FLUSH_CACHE_INSN:
- __asm__ __volatile__ (".chip 68060\n\t"
- "cpushl %%ic,(%0)\n\t"
- ".chip 68k"
- : : "a" (paddr));
- break;
- default:
- case FLUSH_CACHE_BOTH:
- __asm__ __volatile__ (".chip 68060\n\t"
- "cpushl %%bc,(%0)\n\t"
- ".chip 68k"
- : : "a" (paddr));
- break;
- }
- if (!--i && len)
- {
-
- /*
- * We just want to jump to the first cache line
- * in the next page.
- */
- addr += PAGE_SIZE;
- addr &= PAGE_MASK;
-
- i = PAGE_SIZE / 16;
- /* Recompute physical address when crossing a page
- boundary. */
- for (;;)
- {
- if ((paddr = virt_to_phys_060(addr)))
- break;
- if (len <= i)
- return 0;
- len -= i;
- addr += PAGE_SIZE;
- }
- }
- else
- paddr += 16;
- }
- break;
-
- default:
- case FLUSH_SCOPE_PAGE:
- len += (addr & ~PAGE_MASK) + (PAGE_SIZE - 1);
- addr &= PAGE_MASK; /* Workaround for bug in some
- revisions of the 68060 */
- for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
- {
- if (!(paddr = virt_to_phys_060(addr)))
- continue;
- switch (cache)
- {
- case FLUSH_CACHE_DATA:
- __asm__ __volatile__ (".chip 68060\n\t"
- "cpushp %%dc,(%0)\n\t"
- ".chip 68k"
- : : "a" (paddr));
- break;
- case FLUSH_CACHE_INSN:
- __asm__ __volatile__ (".chip 68060\n\t"
- "cpushp %%ic,(%0)\n\t"
- ".chip 68k"
- : : "a" (paddr));
- break;
- default:
- case FLUSH_CACHE_BOTH:
- __asm__ __volatile__ (".chip 68060\n\t"
- "cpushp %%bc,(%0)\n\t"
- ".chip 68k"
- : : "a" (paddr));
- break;
- }
- }
- break;
- }
- return 0;
-}
-
-/* sys_cacheflush -- flush (part of) the processor cache. */
-asmlinkage int
-sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
-{
- struct vm_area_struct *vma;
- int ret = -EINVAL;
-
- if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL ||
- cache & ~FLUSH_CACHE_BOTH)
- goto out;
-
- if (scope == FLUSH_SCOPE_ALL) {
- /* Only the superuser may explicitly flush the whole cache. */
- ret = -EPERM;
- if (!capable(CAP_SYS_ADMIN))
- goto out;
- } else {
- /*
- * Verify that the specified address region actually belongs
- * to this process.
- */
- vma = find_vma (current->mm, addr);
- ret = -EINVAL;
- /* Check for overflow. */
- if (addr + len < addr)
- goto out;
- if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end)
- goto out;
- }
-
- if (CPU_IS_020_OR_030) {
- if (scope == FLUSH_SCOPE_LINE && len < 256) {
- unsigned long cacr;
- __asm__ ("movec %%cacr, %0" : "=r" (cacr));
- if (cache & FLUSH_CACHE_INSN)
- cacr |= 4;
- if (cache & FLUSH_CACHE_DATA)
- cacr |= 0x400;
- len >>= 2;
- while (len--) {
- __asm__ __volatile__ ("movec %1, %%caar\n\t"
- "movec %0, %%cacr"
- : /* no outputs */
- : "r" (cacr), "r" (addr));
- addr += 4;
- }
- } else {
- /* Flush the whole cache, even if page granularity requested. */
- unsigned long cacr;
- __asm__ ("movec %%cacr, %0" : "=r" (cacr));
- if (cache & FLUSH_CACHE_INSN)
- cacr |= 8;
- if (cache & FLUSH_CACHE_DATA)
- cacr |= 0x800;
- __asm__ __volatile__ ("movec %0, %%cacr" : : "r" (cacr));
- }
- ret = 0;
- goto out;
- } else {
- /*
- * 040 or 060: don't blindly trust 'scope', someone could
- * try to flush a few megs of memory.
- */
-
- if (len>=3*PAGE_SIZE && scope<FLUSH_SCOPE_PAGE)
- scope=FLUSH_SCOPE_PAGE;
- if (len>=10*PAGE_SIZE && scope<FLUSH_SCOPE_ALL)
- scope=FLUSH_SCOPE_ALL;
- if (CPU_IS_040) {
- ret = cache_flush_040 (addr, scope, cache, len);
- } else if (CPU_IS_060) {
- ret = cache_flush_060 (addr, scope, cache, len);
- }
- }
-out:
- return ret;
-}
-
-asmlinkage int sys_getpagesize(void)
-{
- return PAGE_SIZE;
-}
-
-/*
- * Do a system call from kernel instead of calling sys_execve so we
- * end up with proper pt_regs.
- */
-int kernel_execve(const char *filename,
- const char *const argv[],
- const char *const envp[])
-{
- register long __res asm ("%d0") = __NR_execve;
- register long __a asm ("%d1") = (long)(filename);
- register long __b asm ("%d2") = (long)(argv);
- register long __c asm ("%d3") = (long)(envp);
- asm volatile ("trap #0" : "+d" (__res)
- : "d" (__a), "d" (__b), "d" (__c));
- return __res;
-}
-
-asmlinkage unsigned long sys_get_thread_area(void)
-{
- return current_thread_info()->tp_value;
-}
-
-asmlinkage int sys_set_thread_area(unsigned long tp)
-{
- current_thread_info()->tp_value = tp;
- return 0;
-}
-
-/* This syscall gets its arguments in A0 (mem), D2 (oldval) and
- D1 (newval). */
-asmlinkage int
-sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
- unsigned long __user * mem)
-{
- /* This was borrowed from ARM's implementation. */
- for (;;) {
- struct mm_struct *mm = current->mm;
- pgd_t *pgd;
- pmd_t *pmd;
- pte_t *pte;
- spinlock_t *ptl;
- unsigned long mem_value;
-
- down_read(&mm->mmap_sem);
- pgd = pgd_offset(mm, (unsigned long)mem);
- if (!pgd_present(*pgd))
- goto bad_access;
- pmd = pmd_offset(pgd, (unsigned long)mem);
- if (!pmd_present(*pmd))
- goto bad_access;
- pte = pte_offset_map_lock(mm, pmd, (unsigned long)mem, &ptl);
- if (!pte_present(*pte) || !pte_dirty(*pte)
- || !pte_write(*pte)) {
- pte_unmap_unlock(pte, ptl);
- goto bad_access;
- }
-
- mem_value = *mem;
- if (mem_value == oldval)
- *mem = newval;
-
- pte_unmap_unlock(pte, ptl);
- up_read(&mm->mmap_sem);
- return mem_value;
-
- bad_access:
- up_read(&mm->mmap_sem);
- /* This is not necessarily a bad access, we can get here if
- a memory we're trying to write to should be copied-on-write.
- Make the kernel do the necessary page stuff, then re-iterate.
- Simulate a write access fault to do that. */
- {
- /* The first argument of the function corresponds to
- D1, which is the first field of struct pt_regs. */
- struct pt_regs *fp = (struct pt_regs *)&newval;
-
- /* '3' is an RMW flag. */
- if (do_page_fault(fp, (unsigned long)mem, 3))
- /* If the do_page_fault() failed, we don't
- have anything meaningful to return.
- There should be a SIGSEGV pending for
- the process. */
- return 0xdeadbeef;
- }
- }
-}
-
-asmlinkage int sys_atomic_barrier(void)
-{
- /* no code needed for uniprocs */
- return 0;
-}
diff --git a/arch/m68k/kernel/sys_m68k_no.c b/arch/m68k/kernel/sys_m68k_no.c
deleted file mode 100644
index 68488ae47f0a..000000000000
--- a/arch/m68k/kernel/sys_m68k_no.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * linux/arch/m68knommu/kernel/sys_m68k.c
- *
- * This file contains various random system calls that
- * have a non-standard calling sequence on the Linux/m68k
- * platform.
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/sem.h>
-#include <linux/msg.h>
-#include <linux/shm.h>
-#include <linux/stat.h>
-#include <linux/syscalls.h>
-#include <linux/mman.h>
-#include <linux/file.h>
-#include <linux/ipc.h>
-#include <linux/fs.h>
-
-#include <asm/setup.h>
-#include <asm/uaccess.h>
-#include <asm/cachectl.h>
-#include <asm/traps.h>
-#include <asm/cacheflush.h>
-#include <asm/unistd.h>
-
-/* sys_cacheflush -- flush (part of) the processor cache. */
-asmlinkage int
-sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
-{
- flush_cache_all();
- return(0);
-}
-
-asmlinkage int sys_getpagesize(void)
-{
- return PAGE_SIZE;
-}
-
-/*
- * Do a system call from kernel instead of calling sys_execve so we
- * end up with proper pt_regs.
- */
-int kernel_execve(const char *filename,
- const char *const argv[],
- const char *const envp[])
-{
- register long __res asm ("%d0") = __NR_execve;
- register long __a asm ("%d1") = (long)(filename);
- register long __b asm ("%d2") = (long)(argv);
- register long __c asm ("%d3") = (long)(envp);
- asm volatile ("trap #0" : "+d" (__res)
- : "d" (__a), "d" (__b), "d" (__c));
- return __res;
-}
-
-asmlinkage unsigned long sys_get_thread_area(void)
-{
- return current_thread_info()->tp_value;
-}
-
-asmlinkage int sys_set_thread_area(unsigned long tp)
-{
- current_thread_info()->tp_value = tp;
- return 0;
-}
-
-/* This syscall gets its arguments in A0 (mem), D2 (oldval) and
- D1 (newval). */
-asmlinkage int
-sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
- unsigned long __user * mem)
-{
- struct mm_struct *mm = current->mm;
- unsigned long mem_value;
-
- down_read(&mm->mmap_sem);
-
- mem_value = *mem;
- if (mem_value == oldval)
- *mem = newval;
-
- up_read(&mm->mmap_sem);
- return mem_value;
-}
-
-asmlinkage int sys_atomic_barrier(void)
-{
- /* no code needed for uniprocs */
- return 0;
-}
diff --git a/arch/m68k/kernel/syscalltable.S b/arch/m68k/kernel/syscalltable.S
index 9b8393d8adb8..6f7b09122a00 100644
--- a/arch/m68k/kernel/syscalltable.S
+++ b/arch/m68k/kernel/syscalltable.S
@@ -1,6 +1,4 @@
/*
- * linux/arch/m68knommu/kernel/syscalltable.S
- *
* Copyright (C) 2002, Greg Ungerer (gerg@snapgear.com)
*
* Based on older entry.S files, the following copyrights apply:
@@ -9,171 +7,175 @@
* Kenneth Albanowski <kjahds@kjahds.com>,
* Copyright (C) 2000 Lineo Inc. (www.lineo.com)
* Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * Linux/m68k support by Hamish Macdonald
*/
-#include <linux/sys.h>
#include <linux/linkage.h>
-#include <asm/unistd.h>
-.text
+#ifndef CONFIG_MMU
+#define sys_mmap2 sys_mmap_pgoff
+#endif
+
+.section .rodata
ALIGN
ENTRY(sys_call_table)
- .long sys_restart_syscall /* 0 - old "setup()" system call */
+ .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */
.long sys_exit
.long sys_fork
.long sys_read
.long sys_write
- .long sys_open /* 5 */
+ .long sys_open /* 5 */
.long sys_close
.long sys_waitpid
.long sys_creat
.long sys_link
- .long sys_unlink /* 10 */
+ .long sys_unlink /* 10 */
.long sys_execve
.long sys_chdir
.long sys_time
.long sys_mknod
- .long sys_chmod /* 15 */
+ .long sys_chmod /* 15 */
.long sys_chown16
- .long sys_ni_syscall /* old break syscall holder */
+ .long sys_ni_syscall /* old break syscall holder */
.long sys_stat
.long sys_lseek
- .long sys_getpid /* 20 */
+ .long sys_getpid /* 20 */
.long sys_mount
.long sys_oldumount
.long sys_setuid16
.long sys_getuid16
- .long sys_stime /* 25 */
+ .long sys_stime /* 25 */
.long sys_ptrace
.long sys_alarm
.long sys_fstat
.long sys_pause
- .long sys_utime /* 30 */
- .long sys_ni_syscall /* old stty syscall holder */
- .long sys_ni_syscall /* old gtty syscall holder */
+ .long sys_utime /* 30 */
+ .long sys_ni_syscall /* old stty syscall holder */
+ .long sys_ni_syscall /* old gtty syscall holder */
.long sys_access
.long sys_nice
- .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */
+ .long sys_ni_syscall /* 35 - old ftime syscall holder */
.long sys_sync
.long sys_kill
.long sys_rename
.long sys_mkdir
- .long sys_rmdir /* 40 */
+ .long sys_rmdir /* 40 */
.long sys_dup
.long sys_pipe
.long sys_times
- .long sys_ni_syscall /* old prof syscall holder */
- .long sys_brk /* 45 */
+ .long sys_ni_syscall /* old prof syscall holder */
+ .long sys_brk /* 45 */
.long sys_setgid16
.long sys_getgid16
.long sys_signal
.long sys_geteuid16
- .long sys_getegid16 /* 50 */
+ .long sys_getegid16 /* 50 */
.long sys_acct
- .long sys_umount /* recycled never used phys() */
- .long sys_ni_syscall /* old lock syscall holder */
+ .long sys_umount /* recycled never used phys() */
+ .long sys_ni_syscall /* old lock syscall holder */
.long sys_ioctl
- .long sys_fcntl /* 55 */
- .long sys_ni_syscall /* old mpx syscall holder */
+ .long sys_fcntl /* 55 */
+ .long sys_ni_syscall /* old mpx syscall holder */
.long sys_setpgid
- .long sys_ni_syscall /* old ulimit syscall holder */
+ .long sys_ni_syscall /* old ulimit syscall holder */
.long sys_ni_syscall
- .long sys_umask /* 60 */
+ .long sys_umask /* 60 */
.long sys_chroot
.long sys_ustat
.long sys_dup2
.long sys_getppid
- .long sys_getpgrp /* 65 */
+ .long sys_getpgrp /* 65 */
.long sys_setsid
.long sys_sigaction
.long sys_sgetmask
.long sys_ssetmask
- .long sys_setreuid16 /* 70 */
+ .long sys_setreuid16 /* 70 */
.long sys_setregid16
.long sys_sigsuspend
.long sys_sigpending
.long sys_sethostname
- .long sys_setrlimit /* 75 */
+ .long sys_setrlimit /* 75 */
.long sys_old_getrlimit
.long sys_getrusage
.long sys_gettimeofday
.long sys_settimeofday
- .long sys_getgroups16 /* 80 */
+ .long sys_getgroups16 /* 80 */
.long sys_setgroups16
.long sys_old_select
.long sys_symlink
.long sys_lstat
- .long sys_readlink /* 85 */
+ .long sys_readlink /* 85 */
.long sys_uselib
- .long sys_ni_syscall /* sys_swapon */
+ .long sys_swapon
.long sys_reboot
.long sys_old_readdir
- .long sys_old_mmap /* 90 */
+ .long sys_old_mmap /* 90 */
.long sys_munmap
.long sys_truncate
.long sys_ftruncate
.long sys_fchmod
- .long sys_fchown16 /* 95 */
+ .long sys_fchown16 /* 95 */
.long sys_getpriority
.long sys_setpriority
- .long sys_ni_syscall /* old profil syscall holder */
+ .long sys_ni_syscall /* old profil syscall holder */
.long sys_statfs
- .long sys_fstatfs /* 100 */
- .long sys_ni_syscall /* ioperm for i386 */
+ .long sys_fstatfs /* 100 */
+ .long sys_ni_syscall /* ioperm for i386 */
.long sys_socketcall
.long sys_syslog
.long sys_setitimer
- .long sys_getitimer /* 105 */
+ .long sys_getitimer /* 105 */
.long sys_newstat
.long sys_newlstat
.long sys_newfstat
.long sys_ni_syscall
- .long sys_ni_syscall /* iopl for i386 */ /* 110 */
+ .long sys_ni_syscall /* 110 - iopl for i386 */
.long sys_vhangup
- .long sys_ni_syscall /* obsolete idle() syscall */
- .long sys_ni_syscall /* vm86old for i386 */
+ .long sys_ni_syscall /* obsolete idle() syscall */
+ .long sys_ni_syscall /* vm86old for i386 */
.long sys_wait4
- .long sys_ni_syscall /* 115 */ /* sys_swapoff */
+ .long sys_swapoff /* 115 */
.long sys_sysinfo
.long sys_ipc
.long sys_fsync
.long sys_sigreturn
- .long sys_clone /* 120 */
+ .long sys_clone /* 120 */
.long sys_setdomainname
.long sys_newuname
- .long sys_cacheflush /* modify_ldt for i386 */
+ .long sys_cacheflush /* modify_ldt for i386 */
.long sys_adjtimex
- .long sys_ni_syscall /* 125 */ /* sys_mprotect */
+ .long sys_mprotect /* 125 */
.long sys_sigprocmask
- .long sys_ni_syscall /* old "creat_module" */
+ .long sys_ni_syscall /* old "create_module" */
.long sys_init_module
.long sys_delete_module
- .long sys_ni_syscall /* 130: old "get_kernel_syms" */
+ .long sys_ni_syscall /* 130 - old "get_kernel_syms" */
.long sys_quotactl
.long sys_getpgid
.long sys_fchdir
.long sys_bdflush
- .long sys_sysfs /* 135 */
+ .long sys_sysfs /* 135 */
.long sys_personality
- .long sys_ni_syscall /* for afs_syscall */
+ .long sys_ni_syscall /* for afs_syscall */
.long sys_setfsuid16
.long sys_setfsgid16
- .long sys_llseek /* 140 */
+ .long sys_llseek /* 140 */
.long sys_getdents
.long sys_select
.long sys_flock
- .long sys_ni_syscall /* sys_msync */
- .long sys_readv /* 145 */
+ .long sys_msync
+ .long sys_readv /* 145 */
.long sys_writev
.long sys_getsid
.long sys_fdatasync
.long sys_sysctl
- .long sys_ni_syscall /* 150 */ /* sys_mlock */
- .long sys_ni_syscall /* sys_munlock */
- .long sys_ni_syscall /* sys_mlockall */
- .long sys_ni_syscall /* sys_munlockall */
+ .long sys_mlock /* 150 */
+ .long sys_munlock
+ .long sys_mlockall
+ .long sys_munlockall
.long sys_sched_setparam
- .long sys_sched_getparam /* 155 */
+ .long sys_sched_getparam /* 155 */
.long sys_sched_setscheduler
.long sys_sched_getscheduler
.long sys_sched_yield
@@ -181,124 +183,124 @@ ENTRY(sys_call_table)
.long sys_sched_get_priority_min /* 160 */
.long sys_sched_rr_get_interval
.long sys_nanosleep
- .long sys_ni_syscall /* sys_mremap */
+ .long sys_mremap
.long sys_setresuid16
- .long sys_getresuid16 /* 165 */
- .long sys_getpagesize /* sys_getpagesize */
- .long sys_ni_syscall /* old "query_module" */
+ .long sys_getresuid16 /* 165 */
+ .long sys_getpagesize
+ .long sys_ni_syscall /* old "query_module" */
.long sys_poll
- .long sys_ni_syscall /* sys_nfsservctl */
- .long sys_setresgid16 /* 170 */
+ .long sys_nfsservctl
+ .long sys_setresgid16 /* 170 */
.long sys_getresgid16
.long sys_prctl
.long sys_rt_sigreturn
.long sys_rt_sigaction
- .long sys_rt_sigprocmask /* 175 */
+ .long sys_rt_sigprocmask /* 175 */
.long sys_rt_sigpending
.long sys_rt_sigtimedwait
.long sys_rt_sigqueueinfo
.long sys_rt_sigsuspend
- .long sys_pread64 /* 180 */
+ .long sys_pread64 /* 180 */
.long sys_pwrite64
.long sys_lchown16
.long sys_getcwd
.long sys_capget
- .long sys_capset /* 185 */
+ .long sys_capset /* 185 */
.long sys_sigaltstack
.long sys_sendfile
- .long sys_ni_syscall /* streams1 */
- .long sys_ni_syscall /* streams2 */
- .long sys_vfork /* 190 */
+ .long sys_ni_syscall /* streams1 */
+ .long sys_ni_syscall /* streams2 */
+ .long sys_vfork /* 190 */
.long sys_getrlimit
- .long sys_mmap_pgoff
+ .long sys_mmap2
.long sys_truncate64
.long sys_ftruncate64
- .long sys_stat64 /* 195 */
+ .long sys_stat64 /* 195 */
.long sys_lstat64
.long sys_fstat64
.long sys_chown
.long sys_getuid
- .long sys_getgid /* 200 */
+ .long sys_getgid /* 200 */
.long sys_geteuid
.long sys_getegid
.long sys_setreuid
.long sys_setregid
- .long sys_getgroups /* 205 */
+ .long sys_getgroups /* 205 */
.long sys_setgroups
.long sys_fchown
.long sys_setresuid
.long sys_getresuid
- .long sys_setresgid /* 210 */
+ .long sys_setresgid /* 210 */
.long sys_getresgid
.long sys_lchown
.long sys_setuid
.long sys_setgid
- .long sys_setfsuid /* 215 */
+ .long sys_setfsuid /* 215 */
.long sys_setfsgid
.long sys_pivot_root
.long sys_ni_syscall
.long sys_ni_syscall
- .long sys_getdents64 /* 220 */
+ .long sys_getdents64 /* 220 */
.long sys_gettid
.long sys_tkill
.long sys_setxattr
.long sys_lsetxattr
- .long sys_fsetxattr /* 225 */
+ .long sys_fsetxattr /* 225 */
.long sys_getxattr
.long sys_lgetxattr
.long sys_fgetxattr
.long sys_listxattr
- .long sys_llistxattr /* 230 */
+ .long sys_llistxattr /* 230 */
.long sys_flistxattr
.long sys_removexattr
.long sys_lremovexattr
.long sys_fremovexattr
- .long sys_futex /* 235 */
+ .long sys_futex /* 235 */
.long sys_sendfile64
- .long sys_ni_syscall /* sys_mincore */
- .long sys_ni_syscall /* sys_madvise */
+ .long sys_mincore
+ .long sys_madvise
.long sys_fcntl64
- .long sys_readahead /* 240 */
+ .long sys_readahead /* 240 */
.long sys_io_setup
.long sys_io_destroy
.long sys_io_getevents
.long sys_io_submit
- .long sys_io_cancel /* 245 */
+ .long sys_io_cancel /* 245 */
.long sys_fadvise64
.long sys_exit_group
.long sys_lookup_dcookie
.long sys_epoll_create
- .long sys_epoll_ctl /* 250 */
+ .long sys_epoll_ctl /* 250 */
.long sys_epoll_wait
- .long sys_ni_syscall /* sys_remap_file_pages */
+ .long sys_remap_file_pages
.long sys_set_tid_address
.long sys_timer_create
- .long sys_timer_settime /* 255 */
+ .long sys_timer_settime /* 255 */
.long sys_timer_gettime
.long sys_timer_getoverrun
.long sys_timer_delete
.long sys_clock_settime
- .long sys_clock_gettime /* 260 */
+ .long sys_clock_gettime /* 260 */
.long sys_clock_getres
.long sys_clock_nanosleep
.long sys_statfs64
.long sys_fstatfs64
- .long sys_tgkill /* 265 */
+ .long sys_tgkill /* 265 */
.long sys_utimes
.long sys_fadvise64_64
- .long sys_mbind
+ .long sys_mbind
.long sys_get_mempolicy
- .long sys_set_mempolicy /* 270 */
+ .long sys_set_mempolicy /* 270 */
.long sys_mq_open
.long sys_mq_unlink
.long sys_mq_timedsend
.long sys_mq_timedreceive
- .long sys_mq_notify /* 275 */
+ .long sys_mq_notify /* 275 */
.long sys_mq_getsetattr
.long sys_waitid
- .long sys_ni_syscall /* for sys_vserver */
+ .long sys_ni_syscall /* for sys_vserver */
.long sys_add_key
- .long sys_request_key /* 280 */
+ .long sys_request_key /* 280 */
.long sys_keyctl
.long sys_ioprio_set
.long sys_ioprio_get
@@ -319,8 +321,8 @@ ENTRY(sys_call_table)
.long sys_readlinkat
.long sys_fchmodat
.long sys_faccessat /* 300 */
- .long sys_ni_syscall /* Reserved for pselect6 */
- .long sys_ni_syscall /* Reserved for ppoll */
+ .long sys_pselect6
+ .long sys_ppoll
.long sys_unshare
.long sys_set_robust_list
.long sys_get_robust_list /* 305 */
@@ -363,7 +365,3 @@ ENTRY(sys_call_table)
.long sys_clock_adjtime
.long sys_syncfs
- .rept NR_syscalls-(.-sys_call_table)/4
- .long sys_ni_syscall
- .endr
-
diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds
index 878be5f38cad..d0993594f558 100644
--- a/arch/m68k/kernel/vmlinux-std.lds
+++ b/arch/m68k/kernel/vmlinux-std.lds
@@ -25,6 +25,8 @@ SECTIONS
EXCEPTION_TABLE(16)
+ _sdata = .; /* Start of data section */
+
RODATA
RW_DATA_SECTION(16, PAGE_SIZE, THREAD_SIZE)
diff --git a/arch/m68k/kernel/vmlinux-sun3.lds b/arch/m68k/kernel/vmlinux-sun3.lds
index 1ad6b7ad2c17..8080469ee6c1 100644
--- a/arch/m68k/kernel/vmlinux-sun3.lds
+++ b/arch/m68k/kernel/vmlinux-sun3.lds
@@ -25,6 +25,7 @@ SECTIONS
_etext = .; /* End of text section */
EXCEPTION_TABLE(16) :data
+ _sdata = .; /* Start of rw data section */
RW_DATA_SECTION(16, PAGE_SIZE, THREAD_SIZE) :data
/* End of data goes *here* so that freeing init code works properly. */
_edata = .;
diff --git a/arch/m68k/lib/Makefile b/arch/m68k/lib/Makefile
index 1f95881d8437..df421e501436 100644
--- a/arch/m68k/lib/Makefile
+++ b/arch/m68k/lib/Makefile
@@ -1,5 +1,14 @@
+
+#
+# Makefile for m68k-specific library files..
+#
+
+lib-y := ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \
+ memcpy.o memset.o memmove.o
+
ifdef CONFIG_MMU
-include arch/m68k/lib/Makefile_mm
+lib-y += string.o uaccess.o checksum_mm.o
else
-include arch/m68k/lib/Makefile_no
+lib-y += mulsi3.o divsi3.o udivsi3.o modsi3.o umodsi3.o delay.o checksum_no.o
endif
+
diff --git a/arch/m68k/lib/Makefile_mm b/arch/m68k/lib/Makefile_mm
deleted file mode 100644
index af9abf8d9d98..000000000000
--- a/arch/m68k/lib/Makefile_mm
+++ /dev/null
@@ -1,6 +0,0 @@
-#
-# Makefile for m68k-specific library files..
-#
-
-lib-y := ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \
- checksum.o string.o uaccess.o
diff --git a/arch/m68k/lib/Makefile_no b/arch/m68k/lib/Makefile_no
deleted file mode 100644
index 32d852e586d7..000000000000
--- a/arch/m68k/lib/Makefile_no
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for m68knommu specific library files..
-#
-
-lib-y := ashldi3.o ashrdi3.o lshrdi3.o \
- muldi3.o mulsi3.o divsi3.o udivsi3.o modsi3.o umodsi3.o \
- checksum.o memcpy.o memmove.o memset.o delay.o
diff --git a/arch/m68k/lib/checksum.c b/arch/m68k/lib/checksum.c
deleted file mode 100644
index 1297536060de..000000000000
--- a/arch/m68k/lib/checksum.c
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifdef CONFIG_MMU
-#include "checksum_mm.c"
-#else
-#include "checksum_no.c"
-#endif
diff --git a/arch/m68k/lib/checksum_no.c b/arch/m68k/lib/checksum_no.c
index eccf25d3d73e..e4c6354da765 100644
--- a/arch/m68k/lib/checksum_no.c
+++ b/arch/m68k/lib/checksum_no.c
@@ -101,6 +101,7 @@ __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
{
return (__force __sum16)~do_csum(iph,ihl*4);
}
+EXPORT_SYMBOL(ip_fast_csum);
#endif
/*
@@ -140,6 +141,7 @@ csum_partial_copy_from_user(const void __user *src, void *dst,
memcpy(dst, (__force const void *)src, len);
return csum_partial(dst, len, sum);
}
+EXPORT_SYMBOL(csum_partial_copy_from_user);
/*
* copy from ds while checksumming, otherwise like csum_partial
@@ -151,3 +153,4 @@ csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
memcpy(dst, src, len);
return csum_partial(dst, len, sum);
}
+EXPORT_SYMBOL(csum_partial_copy_nocheck);
diff --git a/arch/m68k/lib/memcpy.c b/arch/m68k/lib/memcpy.c
index b50dbcad4746..62182c81e91c 100644
--- a/arch/m68k/lib/memcpy.c
+++ b/arch/m68k/lib/memcpy.c
@@ -1,62 +1,80 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
-#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/string.h>
-void * memcpy(void * to, const void * from, size_t n)
+void *memcpy(void *to, const void *from, size_t n)
{
-#ifdef CONFIG_COLDFIRE
- void *xto = to;
- size_t temp;
+ void *xto = to;
+ size_t temp, temp1;
- if (!n)
- return xto;
- if ((long) to & 1)
- {
- char *cto = to;
- const char *cfrom = from;
- *cto++ = *cfrom++;
- to = cto;
- from = cfrom;
- n--;
- }
- if (n > 2 && (long) to & 2)
- {
- short *sto = to;
- const short *sfrom = from;
- *sto++ = *sfrom++;
- to = sto;
- from = sfrom;
- n -= 2;
- }
- temp = n >> 2;
- if (temp)
- {
- long *lto = to;
- const long *lfrom = from;
- for (; temp; temp--)
- *lto++ = *lfrom++;
- to = lto;
- from = lfrom;
- }
- if (n & 2)
- {
- short *sto = to;
- const short *sfrom = from;
- *sto++ = *sfrom++;
- to = sto;
- from = sfrom;
- }
- if (n & 1)
- {
- char *cto = to;
- const char *cfrom = from;
- *cto = *cfrom;
- }
- return xto;
+ if (!n)
+ return xto;
+ if ((long)to & 1) {
+ char *cto = to;
+ const char *cfrom = from;
+ *cto++ = *cfrom++;
+ to = cto;
+ from = cfrom;
+ n--;
+ }
+ if (n > 2 && (long)to & 2) {
+ short *sto = to;
+ const short *sfrom = from;
+ *sto++ = *sfrom++;
+ to = sto;
+ from = sfrom;
+ n -= 2;
+ }
+ temp = n >> 2;
+ if (temp) {
+ long *lto = to;
+ const long *lfrom = from;
+#if defined(__mc68020__) || defined(__mc68030__) || \
+ defined(__mc68040__) || defined(__mc68060__) || defined(__mcpu32__)
+ asm volatile (
+ " movel %2,%3\n"
+ " andw #7,%3\n"
+ " lsrl #3,%2\n"
+ " negw %3\n"
+ " jmp %%pc@(1f,%3:w:2)\n"
+ "4: movel %0@+,%1@+\n"
+ " movel %0@+,%1@+\n"
+ " movel %0@+,%1@+\n"
+ " movel %0@+,%1@+\n"
+ " movel %0@+,%1@+\n"
+ " movel %0@+,%1@+\n"
+ " movel %0@+,%1@+\n"
+ " movel %0@+,%1@+\n"
+ "1: dbra %2,4b\n"
+ " clrw %2\n"
+ " subql #1,%2\n"
+ " jpl 4b"
+ : "=a" (lfrom), "=a" (lto), "=d" (temp), "=&d" (temp1)
+ : "0" (lfrom), "1" (lto), "2" (temp));
#else
- const char *c_from = from;
- char *c_to = to;
- while (n-- > 0)
- *c_to++ = *c_from++;
- return((void *) to);
+ for (; temp; temp--)
+ *lto++ = *lfrom++;
#endif
+ to = lto;
+ from = lfrom;
+ }
+ if (n & 2) {
+ short *sto = to;
+ const short *sfrom = from;
+ *sto++ = *sfrom++;
+ to = sto;
+ from = sfrom;
+ }
+ if (n & 1) {
+ char *cto = to;
+ const char *cfrom = from;
+ *cto = *cfrom;
+ }
+ return xto;
}
+EXPORT_SYMBOL(memcpy);
diff --git a/arch/m68k/lib/memmove.c b/arch/m68k/lib/memmove.c
index b3dcfe9dab7e..6519f7f349f6 100644
--- a/arch/m68k/lib/memmove.c
+++ b/arch/m68k/lib/memmove.c
@@ -4,8 +4,6 @@
* for more details.
*/
-#define __IN_STRING_C
-
#include <linux/module.h>
#include <linux/string.h>
diff --git a/arch/m68k/lib/memset.c b/arch/m68k/lib/memset.c
index 1389bf455633..f649e6a2e644 100644
--- a/arch/m68k/lib/memset.c
+++ b/arch/m68k/lib/memset.c
@@ -1,47 +1,75 @@
-#include <linux/types.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.
+ */
-void * memset(void * s, int c, size_t count)
+#include <linux/module.h>
+#include <linux/string.h>
+
+void *memset(void *s, int c, size_t count)
{
- void *xs = s;
- size_t temp;
+ void *xs = s;
+ size_t temp;
- if (!count)
- return xs;
- c &= 0xff;
- c |= c << 8;
- c |= c << 16;
- if ((long) s & 1)
- {
- char *cs = s;
- *cs++ = c;
- s = cs;
- count--;
- }
- if (count > 2 && (long) s & 2)
- {
- short *ss = s;
- *ss++ = c;
- s = ss;
- count -= 2;
- }
- temp = count >> 2;
- if (temp)
- {
- long *ls = s;
- for (; temp; temp--)
- *ls++ = c;
- s = ls;
- }
- if (count & 2)
- {
- short *ss = s;
- *ss++ = c;
- s = ss;
- }
- if (count & 1)
- {
- char *cs = s;
- *cs = c;
- }
- return xs;
+ if (!count)
+ return xs;
+ c &= 0xff;
+ c |= c << 8;
+ c |= c << 16;
+ if ((long)s & 1) {
+ char *cs = s;
+ *cs++ = c;
+ s = cs;
+ count--;
+ }
+ if (count > 2 && (long)s & 2) {
+ short *ss = s;
+ *ss++ = c;
+ s = ss;
+ count -= 2;
+ }
+ temp = count >> 2;
+ if (temp) {
+ long *ls = s;
+#if defined(__mc68020__) || defined(__mc68030__) || \
+ defined(__mc68040__) || defined(__mc68060__) || defined(__mcpu32__)
+ size_t temp1;
+ asm volatile (
+ " movel %1,%2\n"
+ " andw #7,%2\n"
+ " lsrl #3,%1\n"
+ " negw %2\n"
+ " jmp %%pc@(2f,%2:w:2)\n"
+ "1: movel %3,%0@+\n"
+ " movel %3,%0@+\n"
+ " movel %3,%0@+\n"
+ " movel %3,%0@+\n"
+ " movel %3,%0@+\n"
+ " movel %3,%0@+\n"
+ " movel %3,%0@+\n"
+ " movel %3,%0@+\n"
+ "2: dbra %1,1b\n"
+ " clrw %1\n"
+ " subql #1,%1\n"
+ " jpl 1b"
+ : "=a" (ls), "=d" (temp), "=&d" (temp1)
+ : "d" (c), "0" (ls), "1" (temp));
+#else
+ for (; temp; temp--)
+ *ls++ = c;
+#endif
+ s = ls;
+ }
+ if (count & 2) {
+ short *ss = s;
+ *ss++ = c;
+ s = ss;
+ }
+ if (count & 1) {
+ char *cs = s;
+ *cs = c;
+ }
+ return xs;
}
+EXPORT_SYMBOL(memset);
diff --git a/arch/m68k/lib/muldi3.c b/arch/m68k/lib/muldi3.c
index 16e0eb338ee0..079bafca073e 100644
--- a/arch/m68k/lib/muldi3.c
+++ b/arch/m68k/lib/muldi3.c
@@ -1,5 +1,98 @@
-#ifdef CONFIG_MMU
-#include "muldi3_mm.c"
+/* muldi3.c extracted from gcc-2.7.2.3/libgcc2.c and
+ gcc-2.7.2.3/longlong.h which is: */
+/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#if defined(__mc68020__) || defined(__mc68030__) || \
+ defined(__mc68040__) || defined(__mc68060__) || defined(__mcpu32__)
+
+#define umul_ppmm(w1, w0, u, v) \
+ __asm__ ("mulu%.l %3,%1:%0" \
+ : "=d" ((USItype)(w0)), \
+ "=d" ((USItype)(w1)) \
+ : "%0" ((USItype)(u)), \
+ "dmi" ((USItype)(v)))
+
#else
-#include "muldi3_no.c"
+
+#define SI_TYPE_SIZE 32
+#define __BITS4 (SI_TYPE_SIZE / 4)
+#define __ll_B (1L << (SI_TYPE_SIZE / 2))
+#define __ll_lowpart(t) ((USItype) (t) % __ll_B)
+#define __ll_highpart(t) ((USItype) (t) / __ll_B)
+
+#define umul_ppmm(w1, w0, u, v) \
+ do { \
+ USItype __x0, __x1, __x2, __x3; \
+ USItype __ul, __vl, __uh, __vh; \
+ \
+ __ul = __ll_lowpart (u); \
+ __uh = __ll_highpart (u); \
+ __vl = __ll_lowpart (v); \
+ __vh = __ll_highpart (v); \
+ \
+ __x0 = (USItype) __ul * __vl; \
+ __x1 = (USItype) __ul * __vh; \
+ __x2 = (USItype) __uh * __vl; \
+ __x3 = (USItype) __uh * __vh; \
+ \
+ __x1 += __ll_highpart (__x0);/* this can't give carry */ \
+ __x1 += __x2; /* but this indeed can */ \
+ if (__x1 < __x2) /* did we get it? */ \
+ __x3 += __ll_B; /* yes, add it in the proper pos. */ \
+ \
+ (w1) = __x3 + __ll_highpart (__x1); \
+ (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0); \
+ } while (0)
+
#endif
+
+#define __umulsidi3(u, v) \
+ ({DIunion __w; \
+ umul_ppmm (__w.s.high, __w.s.low, u, v); \
+ __w.ll; })
+
+typedef int SItype __attribute__ ((mode (SI)));
+typedef unsigned int USItype __attribute__ ((mode (SI)));
+typedef int DItype __attribute__ ((mode (DI)));
+typedef int word_type __attribute__ ((mode (__word__)));
+
+struct DIstruct {SItype high, low;};
+
+typedef union
+{
+ struct DIstruct s;
+ DItype ll;
+} DIunion;
+
+DItype
+__muldi3 (DItype u, DItype v)
+{
+ DIunion w;
+ DIunion uu, vv;
+
+ uu.ll = u,
+ vv.ll = v;
+
+ w.ll = __umulsidi3 (uu.s.low, vv.s.low);
+ w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high
+ + (USItype) uu.s.high * (USItype) vv.s.low);
+
+ return w.ll;
+}
diff --git a/arch/m68k/lib/muldi3_mm.c b/arch/m68k/lib/muldi3_mm.c
deleted file mode 100644
index be4f275649e3..000000000000
--- a/arch/m68k/lib/muldi3_mm.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/* muldi3.c extracted from gcc-2.7.2.3/libgcc2.c and
- gcc-2.7.2.3/longlong.h which is: */
-/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
-
-This file is part of GNU CC.
-
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
-
-#define BITS_PER_UNIT 8
-
-#define umul_ppmm(w1, w0, u, v) \
- __asm__ ("mulu%.l %3,%1:%0" \
- : "=d" ((USItype)(w0)), \
- "=d" ((USItype)(w1)) \
- : "%0" ((USItype)(u)), \
- "dmi" ((USItype)(v)))
-
-#define __umulsidi3(u, v) \
- ({DIunion __w; \
- umul_ppmm (__w.s.high, __w.s.low, u, v); \
- __w.ll; })
-
-typedef int SItype __attribute__ ((mode (SI)));
-typedef unsigned int USItype __attribute__ ((mode (SI)));
-typedef int DItype __attribute__ ((mode (DI)));
-typedef int word_type __attribute__ ((mode (__word__)));
-
-struct DIstruct {SItype high, low;};
-
-typedef union
-{
- struct DIstruct s;
- DItype ll;
-} DIunion;
-
-DItype
-__muldi3 (DItype u, DItype v)
-{
- DIunion w;
- DIunion uu, vv;
-
- uu.ll = u,
- vv.ll = v;
-
- w.ll = __umulsidi3 (uu.s.low, vv.s.low);
- w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high
- + (USItype) uu.s.high * (USItype) vv.s.low);
-
- return w.ll;
-}
diff --git a/arch/m68k/lib/muldi3_no.c b/arch/m68k/lib/muldi3_no.c
deleted file mode 100644
index 34af72c30303..000000000000
--- a/arch/m68k/lib/muldi3_no.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/* muldi3.c extracted from gcc-2.7.2.3/libgcc2.c and
- gcc-2.7.2.3/longlong.h which is: */
-/* Copyright (C) 1989, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
-
-This file is part of GNU CC.
-
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
-
-#define BITS_PER_UNIT 8
-#define SI_TYPE_SIZE 32
-
-#define __BITS4 (SI_TYPE_SIZE / 4)
-#define __ll_B (1L << (SI_TYPE_SIZE / 2))
-#define __ll_lowpart(t) ((USItype) (t) % __ll_B)
-#define __ll_highpart(t) ((USItype) (t) / __ll_B)
-
-#define umul_ppmm(w1, w0, u, v) \
- do { \
- USItype __x0, __x1, __x2, __x3; \
- USItype __ul, __vl, __uh, __vh; \
- \
- __ul = __ll_lowpart (u); \
- __uh = __ll_highpart (u); \
- __vl = __ll_lowpart (v); \
- __vh = __ll_highpart (v); \
- \
- __x0 = (USItype) __ul * __vl; \
- __x1 = (USItype) __ul * __vh; \
- __x2 = (USItype) __uh * __vl; \
- __x3 = (USItype) __uh * __vh; \
- \
- __x1 += __ll_highpart (__x0);/* this can't give carry */ \
- __x1 += __x2; /* but this indeed can */ \
- if (__x1 < __x2) /* did we get it? */ \
- __x3 += __ll_B; /* yes, add it in the proper pos. */ \
- \
- (w1) = __x3 + __ll_highpart (__x1); \
- (w0) = __ll_lowpart (__x1) * __ll_B + __ll_lowpart (__x0); \
- } while (0)
-
-#define __umulsidi3(u, v) \
- ({DIunion __w; \
- umul_ppmm (__w.s.high, __w.s.low, u, v); \
- __w.ll; })
-
-typedef int SItype __attribute__ ((mode (SI)));
-typedef unsigned int USItype __attribute__ ((mode (SI)));
-typedef int DItype __attribute__ ((mode (DI)));
-typedef int word_type __attribute__ ((mode (__word__)));
-
-struct DIstruct {SItype high, low;};
-
-typedef union
-{
- struct DIstruct s;
- DItype ll;
-} DIunion;
-
-DItype
-__muldi3 (DItype u, DItype v)
-{
- DIunion w;
- DIunion uu, vv;
-
- uu.ll = u,
- vv.ll = v;
-
- w.ll = __umulsidi3 (uu.s.low, vv.s.low);
- w.s.high += ((USItype) uu.s.low * (USItype) vv.s.high
- + (USItype) uu.s.high * (USItype) vv.s.low);
-
- return w.ll;
-}
diff --git a/arch/m68k/lib/string.c b/arch/m68k/lib/string.c
index d399c5f25636..b9a57abfad08 100644
--- a/arch/m68k/lib/string.c
+++ b/arch/m68k/lib/string.c
@@ -20,226 +20,3 @@ char *strcat(char *dest, const char *src)
return __kernel_strcpy(dest + __kernel_strlen(dest), src);
}
EXPORT_SYMBOL(strcat);
-
-void *memset(void *s, int c, size_t count)
-{
- void *xs = s;
- size_t temp, temp1;
-
- if (!count)
- return xs;
- c &= 0xff;
- c |= c << 8;
- c |= c << 16;
- if ((long)s & 1) {
- char *cs = s;
- *cs++ = c;
- s = cs;
- count--;
- }
- if (count > 2 && (long)s & 2) {
- short *ss = s;
- *ss++ = c;
- s = ss;
- count -= 2;
- }
- temp = count >> 2;
- if (temp) {
- long *ls = s;
-
- asm volatile (
- " movel %1,%2\n"
- " andw #7,%2\n"
- " lsrl #3,%1\n"
- " negw %2\n"
- " jmp %%pc@(2f,%2:w:2)\n"
- "1: movel %3,%0@+\n"
- " movel %3,%0@+\n"
- " movel %3,%0@+\n"
- " movel %3,%0@+\n"
- " movel %3,%0@+\n"
- " movel %3,%0@+\n"
- " movel %3,%0@+\n"
- " movel %3,%0@+\n"
- "2: dbra %1,1b\n"
- " clrw %1\n"
- " subql #1,%1\n"
- " jpl 1b"
- : "=a" (ls), "=d" (temp), "=&d" (temp1)
- : "d" (c), "0" (ls), "1" (temp));
- s = ls;
- }
- if (count & 2) {
- short *ss = s;
- *ss++ = c;
- s = ss;
- }
- if (count & 1) {
- char *cs = s;
- *cs = c;
- }
- return xs;
-}
-EXPORT_SYMBOL(memset);
-
-void *memcpy(void *to, const void *from, size_t n)
-{
- void *xto = to;
- size_t temp, temp1;
-
- if (!n)
- return xto;
- if ((long)to & 1) {
- char *cto = to;
- const char *cfrom = from;
- *cto++ = *cfrom++;
- to = cto;
- from = cfrom;
- n--;
- }
- if (n > 2 && (long)to & 2) {
- short *sto = to;
- const short *sfrom = from;
- *sto++ = *sfrom++;
- to = sto;
- from = sfrom;
- n -= 2;
- }
- temp = n >> 2;
- if (temp) {
- long *lto = to;
- const long *lfrom = from;
-
- asm volatile (
- " movel %2,%3\n"
- " andw #7,%3\n"
- " lsrl #3,%2\n"
- " negw %3\n"
- " jmp %%pc@(1f,%3:w:2)\n"
- "4: movel %0@+,%1@+\n"
- " movel %0@+,%1@+\n"
- " movel %0@+,%1@+\n"
- " movel %0@+,%1@+\n"
- " movel %0@+,%1@+\n"
- " movel %0@+,%1@+\n"
- " movel %0@+,%1@+\n"
- " movel %0@+,%1@+\n"
- "1: dbra %2,4b\n"
- " clrw %2\n"
- " subql #1,%2\n"
- " jpl 4b"
- : "=a" (lfrom), "=a" (lto), "=d" (temp), "=&d" (temp1)
- : "0" (lfrom), "1" (lto), "2" (temp));
- to = lto;
- from = lfrom;
- }
- if (n & 2) {
- short *sto = to;
- const short *sfrom = from;
- *sto++ = *sfrom++;
- to = sto;
- from = sfrom;
- }
- if (n & 1) {
- char *cto = to;
- const char *cfrom = from;
- *cto = *cfrom;
- }
- return xto;
-}
-EXPORT_SYMBOL(memcpy);
-
-void *memmove(void *dest, const void *src, size_t n)
-{
- void *xdest = dest;
- size_t temp;
-
- if (!n)
- return xdest;
-
- if (dest < src) {
- if ((long)dest & 1) {
- char *cdest = dest;
- const char *csrc = src;
- *cdest++ = *csrc++;
- dest = cdest;
- src = csrc;
- n--;
- }
- if (n > 2 && (long)dest & 2) {
- short *sdest = dest;
- const short *ssrc = src;
- *sdest++ = *ssrc++;
- dest = sdest;
- src = ssrc;
- n -= 2;
- }
- temp = n >> 2;
- if (temp) {
- long *ldest = dest;
- const long *lsrc = src;
- temp--;
- do
- *ldest++ = *lsrc++;
- while (temp--);
- dest = ldest;
- src = lsrc;
- }
- if (n & 2) {
- short *sdest = dest;
- const short *ssrc = src;
- *sdest++ = *ssrc++;
- dest = sdest;
- src = ssrc;
- }
- if (n & 1) {
- char *cdest = dest;
- const char *csrc = src;
- *cdest = *csrc;
- }
- } else {
- dest = (char *)dest + n;
- src = (const char *)src + n;
- if ((long)dest & 1) {
- char *cdest = dest;
- const char *csrc = src;
- *--cdest = *--csrc;
- dest = cdest;
- src = csrc;
- n--;
- }
- if (n > 2 && (long)dest & 2) {
- short *sdest = dest;
- const short *ssrc = src;
- *--sdest = *--ssrc;
- dest = sdest;
- src = ssrc;
- n -= 2;
- }
- temp = n >> 2;
- if (temp) {
- long *ldest = dest;
- const long *lsrc = src;
- temp--;
- do
- *--ldest = *--lsrc;
- while (temp--);
- dest = ldest;
- src = lsrc;
- }
- if (n & 2) {
- short *sdest = dest;
- const short *ssrc = src;
- *--sdest = *--ssrc;
- dest = sdest;
- src = ssrc;
- }
- if (n & 1) {
- char *cdest = dest;
- const char *csrc = src;
- *--cdest = *--csrc;
- }
- }
- return xdest;
-}
-EXPORT_SYMBOL(memmove);
diff --git a/arch/m68k/mm/Makefile b/arch/m68k/mm/Makefile
index b60270e4954b..09cadf1058d5 100644
--- a/arch/m68k/mm/Makefile
+++ b/arch/m68k/mm/Makefile
@@ -1,5 +1,9 @@
-ifdef CONFIG_MMU
-include arch/m68k/mm/Makefile_mm
-else
-include arch/m68k/mm/Makefile_no
-endif
+#
+# Makefile for the linux m68k-specific parts of the memory manager.
+#
+
+obj-y := init.o
+
+obj-$(CONFIG_MMU) += cache.o fault.o hwtest.o
+obj-$(CONFIG_MMU_MOTOROLA) += kmap.o memory.o motorola.o
+obj-$(CONFIG_MMU_SUN3) += sun3kmap.o sun3mmu.o
diff --git a/arch/m68k/mm/Makefile_mm b/arch/m68k/mm/Makefile_mm
deleted file mode 100644
index 5eaa43c4cb3c..000000000000
--- a/arch/m68k/mm/Makefile_mm
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# Makefile for the linux m68k-specific parts of the memory manager.
-#
-
-obj-y := cache.o init.o fault.o hwtest.o
-
-obj-$(CONFIG_MMU_MOTOROLA) += kmap.o memory.o motorola.o
-obj-$(CONFIG_MMU_SUN3) += sun3kmap.o sun3mmu.o
diff --git a/arch/m68k/mm/Makefile_no b/arch/m68k/mm/Makefile_no
deleted file mode 100644
index b54ab6b4b523..000000000000
--- a/arch/m68k/mm/Makefile_no
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the linux m68knommu specific parts of the memory manager.
-#
-
-obj-y += init.o kmap.o
diff --git a/arch/m68k/mm/init_mm.c b/arch/m68k/mm/init_mm.c
index 8bc842554e5b..9113c2f17607 100644
--- a/arch/m68k/mm/init_mm.c
+++ b/arch/m68k/mm/init_mm.c
@@ -32,8 +32,6 @@
#include <asm/sections.h>
#include <asm/tlb.h>
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
pg_data_t pg_data_map[MAX_NUMNODES];
EXPORT_SYMBOL(pg_data_map);
diff --git a/arch/m68k/mm/init_no.c b/arch/m68k/mm/init_no.c
index 8a6653f56bd8..7cbd7bd1f8bc 100644
--- a/arch/m68k/mm/init_no.c
+++ b/arch/m68k/mm/init_no.c
@@ -38,28 +38,10 @@
#include <asm/system.h>
#include <asm/machdep.h>
-#undef DEBUG
-
-extern void die_if_kernel(char *,struct pt_regs *,long);
-extern void free_initmem(void);
-
/*
- * BAD_PAGE is the page that is used for page faults when linux
- * is out-of-memory. Older versions of linux just did a
- * do_exit(), but using this instead means there is less risk
- * for a process dying in kernel mode, possibly leaving a inode
- * unused etc..
- *
- * BAD_PAGETABLE is the accompanying page-table: it is initialized
- * to point to BAD_PAGE entries.
- *
* ZERO_PAGE is a special page that is used for zero-initialized
* data and COW.
*/
-static unsigned long empty_bad_page_table;
-
-static unsigned long empty_bad_page;
-
unsigned long empty_zero_page;
extern unsigned long memory_start;
@@ -77,22 +59,9 @@ void __init paging_init(void)
* Make sure start_mem is page aligned, otherwise bootmem and
* page_alloc get different views of the world.
*/
-#ifdef DEBUG
- unsigned long start_mem = PAGE_ALIGN(memory_start);
-#endif
unsigned long end_mem = memory_end & PAGE_MASK;
+ unsigned long zones_size[MAX_NR_ZONES] = {0, };
-#ifdef DEBUG
- printk (KERN_DEBUG "start_mem is %#lx\nvirtual_end is %#lx\n",
- start_mem, end_mem);
-#endif
-
- /*
- * Initialize the bad page table and bad page to point
- * to a couple of allocated pages.
- */
- empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
- empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
memset((void *)empty_zero_page, 0, PAGE_SIZE);
@@ -101,19 +70,8 @@ void __init paging_init(void)
*/
set_fs (USER_DS);
-#ifdef DEBUG
- printk (KERN_DEBUG "before free_area_init\n");
-
- printk (KERN_DEBUG "free_area_init -> start_mem is %#lx\nvirtual_end is %#lx\n",
- start_mem, end_mem);
-#endif
-
- {
- unsigned long zones_size[MAX_NR_ZONES] = {0, };
-
- zones_size[ZONE_DMA] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT;
- free_area_init(zones_size);
- }
+ zones_size[ZONE_DMA] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT;
+ free_area_init(zones_size);
}
void __init mem_init(void)
@@ -166,8 +124,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
}
#endif
-void
-free_initmem()
+void free_initmem(void)
{
#ifdef CONFIG_RAMKERNEL
unsigned long addr;
diff --git a/arch/m68k/mm/kmap.c b/arch/m68k/mm/kmap.c
index a373d136b2b2..69345849454b 100644
--- a/arch/m68k/mm/kmap.c
+++ b/arch/m68k/mm/kmap.c
@@ -1,5 +1,367 @@
-#ifdef CONFIG_MMU
-#include "kmap_mm.c"
+/*
+ * linux/arch/m68k/mm/kmap.c
+ *
+ * Copyright (C) 1997 Roman Hodek
+ *
+ * 10/01/99 cleaned up the code and changing to the same interface
+ * used by other architectures /Roman Zippel
+ */
+
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#include <asm/setup.h>
+#include <asm/segment.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#undef DEBUG
+
+#define PTRTREESIZE (256*1024)
+
+/*
+ * For 040/060 we can use the virtual memory area like other architectures,
+ * but for 020/030 we want to use early termination page descriptor and we
+ * can't mix this with normal page descriptors, so we have to copy that code
+ * (mm/vmalloc.c) and return appriorate aligned addresses.
+ */
+
+#ifdef CPU_M68040_OR_M68060_ONLY
+
+#define IO_SIZE PAGE_SIZE
+
+static inline struct vm_struct *get_io_area(unsigned long size)
+{
+ return get_vm_area(size, VM_IOREMAP);
+}
+
+
+static inline void free_io_area(void *addr)
+{
+ vfree((void *)(PAGE_MASK & (unsigned long)addr));
+}
+
#else
-#include "kmap_no.c"
+
+#define IO_SIZE (256*1024)
+
+static struct vm_struct *iolist;
+
+static struct vm_struct *get_io_area(unsigned long size)
+{
+ unsigned long addr;
+ struct vm_struct **p, *tmp, *area;
+
+ area = kmalloc(sizeof(*area), GFP_KERNEL);
+ if (!area)
+ return NULL;
+ addr = KMAP_START;
+ for (p = &iolist; (tmp = *p) ; p = &tmp->next) {
+ if (size + addr < (unsigned long)tmp->addr)
+ break;
+ if (addr > KMAP_END-size) {
+ kfree(area);
+ return NULL;
+ }
+ addr = tmp->size + (unsigned long)tmp->addr;
+ }
+ area->addr = (void *)addr;
+ area->size = size + IO_SIZE;
+ area->next = *p;
+ *p = area;
+ return area;
+}
+
+static inline void free_io_area(void *addr)
+{
+ struct vm_struct **p, *tmp;
+
+ if (!addr)
+ return;
+ addr = (void *)((unsigned long)addr & -IO_SIZE);
+ for (p = &iolist ; (tmp = *p) ; p = &tmp->next) {
+ if (tmp->addr == addr) {
+ *p = tmp->next;
+ __iounmap(tmp->addr, tmp->size);
+ kfree(tmp);
+ return;
+ }
+ }
+}
+
#endif
+
+/*
+ * Map some physical address range into the kernel address space.
+ */
+/* Rewritten by Andreas Schwab to remove all races. */
+
+void __iomem *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
+{
+ struct vm_struct *area;
+ unsigned long virtaddr, retaddr;
+ long offset;
+ pgd_t *pgd_dir;
+ pmd_t *pmd_dir;
+ pte_t *pte_dir;
+
+ /*
+ * Don't allow mappings that wrap..
+ */
+ if (!size || physaddr > (unsigned long)(-size))
+ return NULL;
+
+#ifdef CONFIG_AMIGA
+ if (MACH_IS_AMIGA) {
+ if ((physaddr >= 0x40000000) && (physaddr + size < 0x60000000)
+ && (cacheflag == IOMAP_NOCACHE_SER))
+ return (void __iomem *)physaddr;
+ }
+#endif
+
+#ifdef DEBUG
+ printk("ioremap: 0x%lx,0x%lx(%d) - ", physaddr, size, cacheflag);
+#endif
+ /*
+ * Mappings have to be aligned
+ */
+ offset = physaddr & (IO_SIZE - 1);
+ physaddr &= -IO_SIZE;
+ size = (size + offset + IO_SIZE - 1) & -IO_SIZE;
+
+ /*
+ * Ok, go for it..
+ */
+ area = get_io_area(size);
+ if (!area)
+ return NULL;
+
+ virtaddr = (unsigned long)area->addr;
+ retaddr = virtaddr + offset;
+#ifdef DEBUG
+ printk("0x%lx,0x%lx,0x%lx", physaddr, virtaddr, retaddr);
+#endif
+
+ /*
+ * add cache and table flags to physical address
+ */
+ if (CPU_IS_040_OR_060) {
+ physaddr |= (_PAGE_PRESENT | _PAGE_GLOBAL040 |
+ _PAGE_ACCESSED | _PAGE_DIRTY);
+ switch (cacheflag) {
+ case IOMAP_FULL_CACHING:
+ physaddr |= _PAGE_CACHE040;
+ break;
+ case IOMAP_NOCACHE_SER:
+ default:
+ physaddr |= _PAGE_NOCACHE_S;
+ break;
+ case IOMAP_NOCACHE_NONSER:
+ physaddr |= _PAGE_NOCACHE;
+ break;
+ case IOMAP_WRITETHROUGH:
+ physaddr |= _PAGE_CACHE040W;
+ break;
+ }
+ } else {
+ physaddr |= (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
+ switch (cacheflag) {
+ case IOMAP_NOCACHE_SER:
+ case IOMAP_NOCACHE_NONSER:
+ default:
+ physaddr |= _PAGE_NOCACHE030;
+ break;
+ case IOMAP_FULL_CACHING:
+ case IOMAP_WRITETHROUGH:
+ break;
+ }
+ }
+
+ while ((long)size > 0) {
+#ifdef DEBUG
+ if (!(virtaddr & (PTRTREESIZE-1)))
+ printk ("\npa=%#lx va=%#lx ", physaddr, virtaddr);
+#endif
+ pgd_dir = pgd_offset_k(virtaddr);
+ pmd_dir = pmd_alloc(&init_mm, pgd_dir, virtaddr);
+ if (!pmd_dir) {
+ printk("ioremap: no mem for pmd_dir\n");
+ return NULL;
+ }
+
+ if (CPU_IS_020_OR_030) {
+ pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr;
+ physaddr += PTRTREESIZE;
+ virtaddr += PTRTREESIZE;
+ size -= PTRTREESIZE;
+ } else {
+ pte_dir = pte_alloc_kernel(pmd_dir, virtaddr);
+ if (!pte_dir) {
+ printk("ioremap: no mem for pte_dir\n");
+ return NULL;
+ }
+
+ pte_val(*pte_dir) = physaddr;
+ virtaddr += PAGE_SIZE;
+ physaddr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ }
+#ifdef DEBUG
+ printk("\n");
+#endif
+ flush_tlb_all();
+
+ return (void __iomem *)retaddr;
+}
+EXPORT_SYMBOL(__ioremap);
+
+/*
+ * Unmap a ioremap()ed region again
+ */
+void iounmap(void __iomem *addr)
+{
+#ifdef CONFIG_AMIGA
+ if ((!MACH_IS_AMIGA) ||
+ (((unsigned long)addr < 0x40000000) ||
+ ((unsigned long)addr > 0x60000000)))
+ free_io_area((__force void *)addr);
+#else
+ free_io_area((__force void *)addr);
+#endif
+}
+EXPORT_SYMBOL(iounmap);
+
+/*
+ * __iounmap unmaps nearly everything, so be careful
+ * it doesn't free currently pointer/page tables anymore but it
+ * wans't used anyway and might be added later.
+ */
+void __iounmap(void *addr, unsigned long size)
+{
+ unsigned long virtaddr = (unsigned long)addr;
+ pgd_t *pgd_dir;
+ pmd_t *pmd_dir;
+ pte_t *pte_dir;
+
+ while ((long)size > 0) {
+ pgd_dir = pgd_offset_k(virtaddr);
+ if (pgd_bad(*pgd_dir)) {
+ printk("iounmap: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
+ pgd_clear(pgd_dir);
+ return;
+ }
+ pmd_dir = pmd_offset(pgd_dir, virtaddr);
+
+ if (CPU_IS_020_OR_030) {
+ int pmd_off = (virtaddr/PTRTREESIZE) & 15;
+ int pmd_type = pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK;
+
+ if (pmd_type == _PAGE_PRESENT) {
+ pmd_dir->pmd[pmd_off] = 0;
+ virtaddr += PTRTREESIZE;
+ size -= PTRTREESIZE;
+ continue;
+ } else if (pmd_type == 0)
+ continue;
+ }
+
+ if (pmd_bad(*pmd_dir)) {
+ printk("iounmap: bad pmd (%08lx)\n", pmd_val(*pmd_dir));
+ pmd_clear(pmd_dir);
+ return;
+ }
+ pte_dir = pte_offset_kernel(pmd_dir, virtaddr);
+
+ pte_val(*pte_dir) = 0;
+ virtaddr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ flush_tlb_all();
+}
+
+/*
+ * Set new cache mode for some kernel address space.
+ * The caller must push data for that range itself, if such data may already
+ * be in the cache.
+ */
+void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
+{
+ unsigned long virtaddr = (unsigned long)addr;
+ pgd_t *pgd_dir;
+ pmd_t *pmd_dir;
+ pte_t *pte_dir;
+
+ if (CPU_IS_040_OR_060) {
+ switch (cmode) {
+ case IOMAP_FULL_CACHING:
+ cmode = _PAGE_CACHE040;
+ break;
+ case IOMAP_NOCACHE_SER:
+ default:
+ cmode = _PAGE_NOCACHE_S;
+ break;
+ case IOMAP_NOCACHE_NONSER:
+ cmode = _PAGE_NOCACHE;
+ break;
+ case IOMAP_WRITETHROUGH:
+ cmode = _PAGE_CACHE040W;
+ break;
+ }
+ } else {
+ switch (cmode) {
+ case IOMAP_NOCACHE_SER:
+ case IOMAP_NOCACHE_NONSER:
+ default:
+ cmode = _PAGE_NOCACHE030;
+ break;
+ case IOMAP_FULL_CACHING:
+ case IOMAP_WRITETHROUGH:
+ cmode = 0;
+ }
+ }
+
+ while ((long)size > 0) {
+ pgd_dir = pgd_offset_k(virtaddr);
+ if (pgd_bad(*pgd_dir)) {
+ printk("iocachemode: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
+ pgd_clear(pgd_dir);
+ return;
+ }
+ pmd_dir = pmd_offset(pgd_dir, virtaddr);
+
+ if (CPU_IS_020_OR_030) {
+ int pmd_off = (virtaddr/PTRTREESIZE) & 15;
+
+ if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) {
+ pmd_dir->pmd[pmd_off] = (pmd_dir->pmd[pmd_off] &
+ _CACHEMASK040) | cmode;
+ virtaddr += PTRTREESIZE;
+ size -= PTRTREESIZE;
+ continue;
+ }
+ }
+
+ if (pmd_bad(*pmd_dir)) {
+ printk("iocachemode: bad pmd (%08lx)\n", pmd_val(*pmd_dir));
+ pmd_clear(pmd_dir);
+ return;
+ }
+ pte_dir = pte_offset_kernel(pmd_dir, virtaddr);
+
+ pte_val(*pte_dir) = (pte_val(*pte_dir) & _CACHEMASK040) | cmode;
+ virtaddr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ flush_tlb_all();
+}
+EXPORT_SYMBOL(kernel_set_cachemode);
diff --git a/arch/m68k/mm/kmap_mm.c b/arch/m68k/mm/kmap_mm.c
deleted file mode 100644
index 69345849454b..000000000000
--- a/arch/m68k/mm/kmap_mm.c
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * linux/arch/m68k/mm/kmap.c
- *
- * Copyright (C) 1997 Roman Hodek
- *
- * 10/01/99 cleaned up the code and changing to the same interface
- * used by other architectures /Roman Zippel
- */
-
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-
-#include <asm/setup.h>
-#include <asm/segment.h>
-#include <asm/page.h>
-#include <asm/pgalloc.h>
-#include <asm/io.h>
-#include <asm/system.h>
-
-#undef DEBUG
-
-#define PTRTREESIZE (256*1024)
-
-/*
- * For 040/060 we can use the virtual memory area like other architectures,
- * but for 020/030 we want to use early termination page descriptor and we
- * can't mix this with normal page descriptors, so we have to copy that code
- * (mm/vmalloc.c) and return appriorate aligned addresses.
- */
-
-#ifdef CPU_M68040_OR_M68060_ONLY
-
-#define IO_SIZE PAGE_SIZE
-
-static inline struct vm_struct *get_io_area(unsigned long size)
-{
- return get_vm_area(size, VM_IOREMAP);
-}
-
-
-static inline void free_io_area(void *addr)
-{
- vfree((void *)(PAGE_MASK & (unsigned long)addr));
-}
-
-#else
-
-#define IO_SIZE (256*1024)
-
-static struct vm_struct *iolist;
-
-static struct vm_struct *get_io_area(unsigned long size)
-{
- unsigned long addr;
- struct vm_struct **p, *tmp, *area;
-
- area = kmalloc(sizeof(*area), GFP_KERNEL);
- if (!area)
- return NULL;
- addr = KMAP_START;
- for (p = &iolist; (tmp = *p) ; p = &tmp->next) {
- if (size + addr < (unsigned long)tmp->addr)
- break;
- if (addr > KMAP_END-size) {
- kfree(area);
- return NULL;
- }
- addr = tmp->size + (unsigned long)tmp->addr;
- }
- area->addr = (void *)addr;
- area->size = size + IO_SIZE;
- area->next = *p;
- *p = area;
- return area;
-}
-
-static inline void free_io_area(void *addr)
-{
- struct vm_struct **p, *tmp;
-
- if (!addr)
- return;
- addr = (void *)((unsigned long)addr & -IO_SIZE);
- for (p = &iolist ; (tmp = *p) ; p = &tmp->next) {
- if (tmp->addr == addr) {
- *p = tmp->next;
- __iounmap(tmp->addr, tmp->size);
- kfree(tmp);
- return;
- }
- }
-}
-
-#endif
-
-/*
- * Map some physical address range into the kernel address space.
- */
-/* Rewritten by Andreas Schwab to remove all races. */
-
-void __iomem *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
-{
- struct vm_struct *area;
- unsigned long virtaddr, retaddr;
- long offset;
- pgd_t *pgd_dir;
- pmd_t *pmd_dir;
- pte_t *pte_dir;
-
- /*
- * Don't allow mappings that wrap..
- */
- if (!size || physaddr > (unsigned long)(-size))
- return NULL;
-
-#ifdef CONFIG_AMIGA
- if (MACH_IS_AMIGA) {
- if ((physaddr >= 0x40000000) && (physaddr + size < 0x60000000)
- && (cacheflag == IOMAP_NOCACHE_SER))
- return (void __iomem *)physaddr;
- }
-#endif
-
-#ifdef DEBUG
- printk("ioremap: 0x%lx,0x%lx(%d) - ", physaddr, size, cacheflag);
-#endif
- /*
- * Mappings have to be aligned
- */
- offset = physaddr & (IO_SIZE - 1);
- physaddr &= -IO_SIZE;
- size = (size + offset + IO_SIZE - 1) & -IO_SIZE;
-
- /*
- * Ok, go for it..
- */
- area = get_io_area(size);
- if (!area)
- return NULL;
-
- virtaddr = (unsigned long)area->addr;
- retaddr = virtaddr + offset;
-#ifdef DEBUG
- printk("0x%lx,0x%lx,0x%lx", physaddr, virtaddr, retaddr);
-#endif
-
- /*
- * add cache and table flags to physical address
- */
- if (CPU_IS_040_OR_060) {
- physaddr |= (_PAGE_PRESENT | _PAGE_GLOBAL040 |
- _PAGE_ACCESSED | _PAGE_DIRTY);
- switch (cacheflag) {
- case IOMAP_FULL_CACHING:
- physaddr |= _PAGE_CACHE040;
- break;
- case IOMAP_NOCACHE_SER:
- default:
- physaddr |= _PAGE_NOCACHE_S;
- break;
- case IOMAP_NOCACHE_NONSER:
- physaddr |= _PAGE_NOCACHE;
- break;
- case IOMAP_WRITETHROUGH:
- physaddr |= _PAGE_CACHE040W;
- break;
- }
- } else {
- physaddr |= (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
- switch (cacheflag) {
- case IOMAP_NOCACHE_SER:
- case IOMAP_NOCACHE_NONSER:
- default:
- physaddr |= _PAGE_NOCACHE030;
- break;
- case IOMAP_FULL_CACHING:
- case IOMAP_WRITETHROUGH:
- break;
- }
- }
-
- while ((long)size > 0) {
-#ifdef DEBUG
- if (!(virtaddr & (PTRTREESIZE-1)))
- printk ("\npa=%#lx va=%#lx ", physaddr, virtaddr);
-#endif
- pgd_dir = pgd_offset_k(virtaddr);
- pmd_dir = pmd_alloc(&init_mm, pgd_dir, virtaddr);
- if (!pmd_dir) {
- printk("ioremap: no mem for pmd_dir\n");
- return NULL;
- }
-
- if (CPU_IS_020_OR_030) {
- pmd_dir->pmd[(virtaddr/PTRTREESIZE) & 15] = physaddr;
- physaddr += PTRTREESIZE;
- virtaddr += PTRTREESIZE;
- size -= PTRTREESIZE;
- } else {
- pte_dir = pte_alloc_kernel(pmd_dir, virtaddr);
- if (!pte_dir) {
- printk("ioremap: no mem for pte_dir\n");
- return NULL;
- }
-
- pte_val(*pte_dir) = physaddr;
- virtaddr += PAGE_SIZE;
- physaddr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- }
-#ifdef DEBUG
- printk("\n");
-#endif
- flush_tlb_all();
-
- return (void __iomem *)retaddr;
-}
-EXPORT_SYMBOL(__ioremap);
-
-/*
- * Unmap a ioremap()ed region again
- */
-void iounmap(void __iomem *addr)
-{
-#ifdef CONFIG_AMIGA
- if ((!MACH_IS_AMIGA) ||
- (((unsigned long)addr < 0x40000000) ||
- ((unsigned long)addr > 0x60000000)))
- free_io_area((__force void *)addr);
-#else
- free_io_area((__force void *)addr);
-#endif
-}
-EXPORT_SYMBOL(iounmap);
-
-/*
- * __iounmap unmaps nearly everything, so be careful
- * it doesn't free currently pointer/page tables anymore but it
- * wans't used anyway and might be added later.
- */
-void __iounmap(void *addr, unsigned long size)
-{
- unsigned long virtaddr = (unsigned long)addr;
- pgd_t *pgd_dir;
- pmd_t *pmd_dir;
- pte_t *pte_dir;
-
- while ((long)size > 0) {
- pgd_dir = pgd_offset_k(virtaddr);
- if (pgd_bad(*pgd_dir)) {
- printk("iounmap: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
- pgd_clear(pgd_dir);
- return;
- }
- pmd_dir = pmd_offset(pgd_dir, virtaddr);
-
- if (CPU_IS_020_OR_030) {
- int pmd_off = (virtaddr/PTRTREESIZE) & 15;
- int pmd_type = pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK;
-
- if (pmd_type == _PAGE_PRESENT) {
- pmd_dir->pmd[pmd_off] = 0;
- virtaddr += PTRTREESIZE;
- size -= PTRTREESIZE;
- continue;
- } else if (pmd_type == 0)
- continue;
- }
-
- if (pmd_bad(*pmd_dir)) {
- printk("iounmap: bad pmd (%08lx)\n", pmd_val(*pmd_dir));
- pmd_clear(pmd_dir);
- return;
- }
- pte_dir = pte_offset_kernel(pmd_dir, virtaddr);
-
- pte_val(*pte_dir) = 0;
- virtaddr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- flush_tlb_all();
-}
-
-/*
- * Set new cache mode for some kernel address space.
- * The caller must push data for that range itself, if such data may already
- * be in the cache.
- */
-void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
-{
- unsigned long virtaddr = (unsigned long)addr;
- pgd_t *pgd_dir;
- pmd_t *pmd_dir;
- pte_t *pte_dir;
-
- if (CPU_IS_040_OR_060) {
- switch (cmode) {
- case IOMAP_FULL_CACHING:
- cmode = _PAGE_CACHE040;
- break;
- case IOMAP_NOCACHE_SER:
- default:
- cmode = _PAGE_NOCACHE_S;
- break;
- case IOMAP_NOCACHE_NONSER:
- cmode = _PAGE_NOCACHE;
- break;
- case IOMAP_WRITETHROUGH:
- cmode = _PAGE_CACHE040W;
- break;
- }
- } else {
- switch (cmode) {
- case IOMAP_NOCACHE_SER:
- case IOMAP_NOCACHE_NONSER:
- default:
- cmode = _PAGE_NOCACHE030;
- break;
- case IOMAP_FULL_CACHING:
- case IOMAP_WRITETHROUGH:
- cmode = 0;
- }
- }
-
- while ((long)size > 0) {
- pgd_dir = pgd_offset_k(virtaddr);
- if (pgd_bad(*pgd_dir)) {
- printk("iocachemode: bad pgd(%08lx)\n", pgd_val(*pgd_dir));
- pgd_clear(pgd_dir);
- return;
- }
- pmd_dir = pmd_offset(pgd_dir, virtaddr);
-
- if (CPU_IS_020_OR_030) {
- int pmd_off = (virtaddr/PTRTREESIZE) & 15;
-
- if ((pmd_dir->pmd[pmd_off] & _DESCTYPE_MASK) == _PAGE_PRESENT) {
- pmd_dir->pmd[pmd_off] = (pmd_dir->pmd[pmd_off] &
- _CACHEMASK040) | cmode;
- virtaddr += PTRTREESIZE;
- size -= PTRTREESIZE;
- continue;
- }
- }
-
- if (pmd_bad(*pmd_dir)) {
- printk("iocachemode: bad pmd (%08lx)\n", pmd_val(*pmd_dir));
- pmd_clear(pmd_dir);
- return;
- }
- pte_dir = pte_offset_kernel(pmd_dir, virtaddr);
-
- pte_val(*pte_dir) = (pte_val(*pte_dir) & _CACHEMASK040) | cmode;
- virtaddr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- flush_tlb_all();
-}
-EXPORT_SYMBOL(kernel_set_cachemode);
diff --git a/arch/m68k/mm/kmap_no.c b/arch/m68k/mm/kmap_no.c
deleted file mode 100644
index ece8d5ad4e6c..000000000000
--- a/arch/m68k/mm/kmap_no.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * linux/arch/m68knommu/mm/kmap.c
- *
- * Copyright (C) 2000 Lineo, <davidm@snapgear.com>
- * Copyright (C) 2000-2002 David McCullough <davidm@snapgear.com>
- */
-
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/vmalloc.h>
-
-#include <asm/setup.h>
-#include <asm/segment.h>
-#include <asm/page.h>
-#include <asm/pgalloc.h>
-#include <asm/io.h>
-#include <asm/system.h>
-
-#undef DEBUG
-
-/*
- * Map some physical address range into the kernel address space.
- */
-void *__ioremap(unsigned long physaddr, unsigned long size, int cacheflag)
-{
- return (void *)physaddr;
-}
-
-/*
- * Unmap a ioremap()ed region again.
- */
-void iounmap(void *addr)
-{
-}
-
-/*
- * Set new cache mode for some kernel address space.
- * The caller must push data for that range itself, if such data may already
- * be in the cache.
- */
-void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
-{
-}
diff --git a/arch/m68k/platform/68328/entry.S b/arch/m68k/platform/68328/entry.S
index 676960cf022a..f68dce766c0a 100644
--- a/arch/m68k/platform/68328/entry.S
+++ b/arch/m68k/platform/68328/entry.S
@@ -10,7 +10,6 @@
* Linux/m68k support by Hamish Macdonald
*/
-#include <linux/sys.h>
#include <linux/linkage.h>
#include <asm/thread_info.h>
#include <asm/unistd.h>
@@ -80,7 +79,7 @@ ENTRY(system_call)
movel %sp,%d1 /* get thread_info pointer */
andl #-THREAD_SIZE,%d1
movel %d1,%a2
- btst #(TIF_SYSCALL_TRACE%8),%a2@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
+ btst #(TIF_SYSCALL_TRACE%8),%a2@(TINFO_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
jne do_trace
cmpl #NR_syscalls,%d0
jcc badsys
@@ -107,12 +106,12 @@ Luser_return:
andl #-THREAD_SIZE,%d1
movel %d1,%a2
1:
- move %a2@(TI_FLAGS),%d1 /* thread_info->flags */
+ move %a2@(TINFO_FLAGS),%d1 /* thread_info->flags */
jne Lwork_to_do
RESTORE_ALL
Lwork_to_do:
- movel %a2@(TI_FLAGS),%d1 /* thread_info->flags */
+ movel %a2@(TINFO_FLAGS),%d1 /* thread_info->flags */
btst #TIF_NEED_RESCHED,%d1
jne reschedule
diff --git a/arch/m68k/platform/68360/entry.S b/arch/m68k/platform/68360/entry.S
index 46c1b18c9dcb..a07b14feed92 100644
--- a/arch/m68k/platform/68360/entry.S
+++ b/arch/m68k/platform/68360/entry.S
@@ -12,7 +12,6 @@
* M68360 Port by SED Systems, and Lineo.
*/
-#include <linux/sys.h>
#include <linux/linkage.h>
#include <asm/thread_info.h>
#include <asm/unistd.h>
@@ -76,7 +75,7 @@ ENTRY(system_call)
movel %sp,%d1 /* get thread_info pointer */
andl #-THREAD_SIZE,%d1
movel %d1,%a2
- btst #(TIF_SYSCALL_TRACE%8),%a2@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
+ btst #(TIF_SYSCALL_TRACE%8),%a2@(TINFO_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
jne do_trace
cmpl #NR_syscalls,%d0
jcc badsys
@@ -103,12 +102,12 @@ Luser_return:
andl #-THREAD_SIZE,%d1
movel %d1,%a2
1:
- move %a2@(TI_FLAGS),%d1 /* thread_info->flags */
+ move %a2@(TINFO_FLAGS),%d1 /* thread_info->flags */
jne Lwork_to_do
RESTORE_ALL
Lwork_to_do:
- movel %a2@(TI_FLAGS),%d1 /* thread_info->flags */
+ movel %a2@(TINFO_FLAGS),%d1 /* thread_info->flags */
btst #TIF_NEED_RESCHED,%d1
jne reschedule
diff --git a/arch/m68k/platform/coldfire/dma.c b/arch/m68k/platform/coldfire/dma.c
index e88b95e2cc62..df5ce20d181c 100644
--- a/arch/m68k/platform/coldfire/dma.c
+++ b/arch/m68k/platform/coldfire/dma.c
@@ -9,6 +9,7 @@
/***************************************************************************/
#include <linux/kernel.h>
+#include <linux/module.h>
#include <asm/dma.h>
#include <asm/coldfire.h>
#include <asm/mcfsim.h>
@@ -33,7 +34,9 @@ unsigned int dma_base_addr[MAX_M68K_DMA_CHANNELS] = {
MCFDMA_BASE3,
#endif
};
+EXPORT_SYMBOL(dma_base_addr);
unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
+EXPORT_SYMBOL(dma_device_address);
/***************************************************************************/
diff --git a/arch/m68k/platform/coldfire/entry.S b/arch/m68k/platform/coldfire/entry.S
index eab63f09965b..27c2b001161e 100644
--- a/arch/m68k/platform/coldfire/entry.S
+++ b/arch/m68k/platform/coldfire/entry.S
@@ -26,7 +26,6 @@
* Bug, speed and maintainability fixes by Philippe De Muyter <phdm@macqel.be>
*/
-#include <linux/sys.h>
#include <linux/linkage.h>
#include <asm/unistd.h>
#include <asm/thread_info.h>
@@ -78,7 +77,7 @@ ENTRY(system_call)
movel %d2,%a0
movel %a0@,%a1 /* save top of frame */
movel %sp,%a1@(TASK_THREAD+THREAD_ESP0)
- btst #(TIF_SYSCALL_TRACE%8),%a0@(TI_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
+ btst #(TIF_SYSCALL_TRACE%8),%a0@(TINFO_FLAGS+(31-TIF_SYSCALL_TRACE)/8)
bnes 1f
movel %d3,%a0
@@ -113,11 +112,11 @@ ret_from_exception:
movel %sp,%d1 /* get thread_info pointer */
andl #-THREAD_SIZE,%d1 /* at base of kernel stack */
movel %d1,%a0
- movel %a0@(TI_FLAGS),%d1 /* get thread_info->flags */
+ movel %a0@(TINFO_FLAGS),%d1 /* get thread_info->flags */
andl #(1<<TIF_NEED_RESCHED),%d1
jeq Lkernel_return
- movel %a0@(TI_PREEMPTCOUNT),%d1
+ movel %a0@(TINFO_PREEMPT),%d1
cmpl #0,%d1
jne Lkernel_return
@@ -137,14 +136,14 @@ Luser_return:
movel %sp,%d1 /* get thread_info pointer */
andl #-THREAD_SIZE,%d1 /* at base of kernel stack */
movel %d1,%a0
- movel %a0@(TI_FLAGS),%d1 /* get thread_info->flags */
+ movel %a0@(TINFO_FLAGS),%d1 /* get thread_info->flags */
jne Lwork_to_do /* still work to do */
Lreturn:
RESTORE_USER
Lwork_to_do:
- movel %a0@(TI_FLAGS),%d1 /* get thread_info->flags */
+ movel %a0@(TINFO_FLAGS),%d1 /* get thread_info->flags */
move #0x2000,%sr /* enable intrs again */
btst #TIF_NEED_RESCHED,%d1
jne reschedule
diff --git a/arch/m68k/platform/coldfire/head.S b/arch/m68k/platform/coldfire/head.S
index 6ae91a499184..c33483824a2e 100644
--- a/arch/m68k/platform/coldfire/head.S
+++ b/arch/m68k/platform/coldfire/head.S
@@ -8,7 +8,6 @@
/*****************************************************************************/
-#include <linux/sys.h>
#include <linux/linkage.h>
#include <linux/init.h>
#include <asm/asm-offsets.h>
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig
index eccdefe70d4e..e446bab2427b 100644
--- a/arch/microblaze/Kconfig
+++ b/arch/microblaze/Kconfig
@@ -33,12 +33,6 @@ config ARCH_HAS_ILOG2_U32
config ARCH_HAS_ILOG2_U64
def_bool n
-config GENERIC_FIND_NEXT_BIT
- def_bool y
-
-config GENERIC_FIND_BIT_LE
- def_bool y
-
config GENERIC_HWEIGHT
def_bool y
diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c
index d8a214f11ac2..e5550ce4e0eb 100644
--- a/arch/microblaze/kernel/timer.c
+++ b/arch/microblaze/kernel/timer.c
@@ -217,16 +217,12 @@ static struct clocksource clocksource_microblaze = {
.rating = 300,
.read = microblaze_read,
.mask = CLOCKSOURCE_MASK(32),
- .shift = 8, /* I can shift it */
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
static int __init microblaze_clocksource_init(void)
{
- clocksource_microblaze.mult =
- clocksource_hz2mult(timer_clock_freq,
- clocksource_microblaze.shift);
- if (clocksource_register(&clocksource_microblaze))
+ if (clocksource_register_hz(&clocksource_microblaze, timer_clock_freq))
panic("failed to register clocksource");
/* stop timer1 */
diff --git a/arch/microblaze/mm/init.c b/arch/microblaze/mm/init.c
index c8437866d3b7..213f2d671669 100644
--- a/arch/microblaze/mm/init.c
+++ b/arch/microblaze/mm/init.c
@@ -32,8 +32,6 @@ unsigned int __page_offset;
EXPORT_SYMBOL(__page_offset);
#else
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
static int init_bootmem_done;
#endif /* CONFIG_MMU */
diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms
index 7ff9b5492041..aef6c917b45a 100644
--- a/arch/mips/Kbuild.platforms
+++ b/arch/mips/Kbuild.platforms
@@ -11,6 +11,7 @@ platforms += dec
platforms += emma
platforms += jazz
platforms += jz4740
+platforms += lantiq
platforms += lasat
platforms += loongson
platforms += mipssim
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 351c80fbba7e..653da62d0682 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -212,6 +212,24 @@ config MACH_JZ4740
select HAVE_PWM
select HAVE_CLK
+config LANTIQ
+ bool "Lantiq based platforms"
+ select DMA_NONCOHERENT
+ select IRQ_CPU
+ select CEVT_R4K
+ select CSRC_R4K
+ select SYS_HAS_CPU_MIPS32_R1
+ select SYS_HAS_CPU_MIPS32_R2
+ select SYS_SUPPORTS_BIG_ENDIAN
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_MULTITHREADING
+ select SYS_HAS_EARLY_PRINTK
+ select ARCH_REQUIRE_GPIOLIB
+ select SWAP_IO_SPACE
+ select BOOT_RAW
+ select HAVE_CLK
+ select MIPS_MACHINE
+
config LASAT
bool "LASAT Networks platforms"
select CEVT_R4K
@@ -736,6 +754,33 @@ config CAVIUM_OCTEON_REFERENCE_BOARD
Hikari
Say Y here for most Octeon reference boards.
+config NLM_XLR_BOARD
+ bool "Netlogic XLR/XLS based systems"
+ depends on EXPERIMENTAL
+ select BOOT_ELF32
+ select NLM_COMMON
+ select NLM_XLR
+ select SYS_HAS_CPU_XLR
+ select SYS_SUPPORTS_SMP
+ select HW_HAS_PCI
+ select SWAP_IO_SPACE
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_64BIT_KERNEL
+ select 64BIT_PHYS_ADDR
+ select SYS_SUPPORTS_BIG_ENDIAN
+ select SYS_SUPPORTS_HIGHMEM
+ select DMA_COHERENT
+ select NR_CPUS_DEFAULT_32
+ select CEVT_R4K
+ select CSRC_R4K
+ select IRQ_CPU
+ select ZONE_DMA if 64BIT
+ select SYNC_R4K
+ select SYS_HAS_EARLY_PRINTK
+ help
+ Support for systems based on Netlogic XLR and XLS processors.
+ Say Y here if you have a XLR or XLS based board.
+
endchoice
source "arch/mips/alchemy/Kconfig"
@@ -743,6 +788,7 @@ source "arch/mips/ath79/Kconfig"
source "arch/mips/bcm63xx/Kconfig"
source "arch/mips/jazz/Kconfig"
source "arch/mips/jz4740/Kconfig"
+source "arch/mips/lantiq/Kconfig"
source "arch/mips/lasat/Kconfig"
source "arch/mips/pmc-sierra/Kconfig"
source "arch/mips/powertv/Kconfig"
@@ -752,6 +798,7 @@ source "arch/mips/txx9/Kconfig"
source "arch/mips/vr41xx/Kconfig"
source "arch/mips/cavium-octeon/Kconfig"
source "arch/mips/loongson/Kconfig"
+source "arch/mips/netlogic/Kconfig"
endmenu
@@ -774,14 +821,6 @@ config ARCH_SUPPORTS_OPROFILE
bool
default y if !MIPS_MT_SMTC
-config GENERIC_FIND_NEXT_BIT
- bool
- default y
-
-config GENERIC_FIND_BIT_LE
- bool
- default y
-
config GENERIC_HWEIGHT
bool
default y
@@ -1420,6 +1459,17 @@ config CPU_BMIPS5000
help
Broadcom BMIPS5000 processors.
+config CPU_XLR
+ bool "Netlogic XLR SoC"
+ depends on SYS_HAS_CPU_XLR
+ select CPU_SUPPORTS_32BIT_KERNEL
+ select CPU_SUPPORTS_64BIT_KERNEL
+ select CPU_SUPPORTS_HIGHMEM
+ select WEAK_ORDERING
+ select WEAK_REORDERING_BEYOND_LLSC
+ select CPU_SUPPORTS_HUGEPAGES
+ help
+ Netlogic Microsystems XLR/XLS processors.
endchoice
if CPU_LOONGSON2F
@@ -1550,6 +1600,9 @@ config SYS_HAS_CPU_BMIPS4380
config SYS_HAS_CPU_BMIPS5000
bool
+config SYS_HAS_CPU_XLR
+ bool
+
#
# CPU may reorder R->R, R->W, W->R, W->W
# Reordering beyond LL and SC is handled in WEAK_REORDERING_BEYOND_LLSC
@@ -2334,6 +2387,7 @@ config MMU
config I8253
bool
+ select CLKSRC_I8253
select MIPS_EXTERNAL_TIMER
config ZONE_DMA32
diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug
index 5358f90b4dd2..83ed00a5644a 100644
--- a/arch/mips/Kconfig.debug
+++ b/arch/mips/Kconfig.debug
@@ -76,15 +76,6 @@ config DEBUG_STACKOVERFLOW
provides another way to check stack overflow happened on kernel mode
stack usually caused by nested interruption.
-config DEBUG_STACK_USAGE
- bool "Enable stack utilization instrumentation"
- depends on DEBUG_KERNEL
- help
- Enables the display of the minimum amount of free stack which each
- task has ever had available in the sysrq-T and sysrq-P debug output.
-
- This option will slow down process creation somewhat.
-
config SMTC_IDLE_HOOK_DEBUG
bool "Enable additional debug checks before going into CPU idle loop"
depends on DEBUG_KERNEL && MIPS_MT_SMTC
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 53e3514ba10e..884819cd0607 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -191,6 +191,18 @@ endif
#
include $(srctree)/arch/mips/Kbuild.platforms
+#
+# NETLOGIC SOC Common (common)
+#
+cflags-$(CONFIG_NLM_COMMON) += -I$(srctree)/arch/mips/include/asm/mach-netlogic
+cflags-$(CONFIG_NLM_COMMON) += -I$(srctree)/arch/mips/include/asm/netlogic
+
+#
+# NETLOGIC XLR/XLS SoC, Simulator and boards
+#
+core-$(CONFIG_NLM_XLR) += arch/mips/netlogic/xlr/
+load-$(CONFIG_NLM_XLR_BOARD) += 0xffffffff84000000
+
cflags-y += -I$(srctree)/arch/mips/include/asm/mach-generic
drivers-$(CONFIG_PCI) += arch/mips/pci/
diff --git a/arch/mips/alchemy/common/dbdma.c b/arch/mips/alchemy/common/dbdma.c
index ca0506a8585a..3a5abb54d505 100644
--- a/arch/mips/alchemy/common/dbdma.c
+++ b/arch/mips/alchemy/common/dbdma.c
@@ -36,7 +36,7 @@
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/module.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1xxx_dbdma.h>
@@ -58,7 +58,8 @@ static DEFINE_SPINLOCK(au1xxx_dbdma_spin_lock);
/* I couldn't find a macro that did this... */
#define ALIGN_ADDR(x, a) ((((u32)(x)) + (a-1)) & ~(a-1))
-static dbdma_global_t *dbdma_gptr = (dbdma_global_t *)DDMA_GLOBAL_BASE;
+static dbdma_global_t *dbdma_gptr =
+ (dbdma_global_t *)KSEG1ADDR(AU1550_DBDMA_CONF_PHYS_ADDR);
static int dbdma_initialized;
static dbdev_tab_t dbdev_tab[] = {
@@ -299,7 +300,7 @@ u32 au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,
if (ctp != NULL) {
memset(ctp, 0, sizeof(chan_tab_t));
ctp->chan_index = chan = i;
- dcp = DDMA_CHANNEL_BASE;
+ dcp = KSEG1ADDR(AU1550_DBDMA_PHYS_ADDR);
dcp += (0x0100 * chan);
ctp->chan_ptr = (au1x_dma_chan_t *)dcp;
cp = (au1x_dma_chan_t *)dcp;
@@ -958,105 +959,75 @@ u32 au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr)
}
-struct alchemy_dbdma_sysdev {
- struct sys_device sysdev;
- u32 pm_regs[NUM_DBDMA_CHANS + 1][6];
-};
+static unsigned long alchemy_dbdma_pm_data[NUM_DBDMA_CHANS + 1][6];
-static int alchemy_dbdma_suspend(struct sys_device *dev,
- pm_message_t state)
+static int alchemy_dbdma_suspend(void)
{
- struct alchemy_dbdma_sysdev *sdev =
- container_of(dev, struct alchemy_dbdma_sysdev, sysdev);
int i;
- u32 addr;
+ void __iomem *addr;
- addr = DDMA_GLOBAL_BASE;
- sdev->pm_regs[0][0] = au_readl(addr + 0x00);
- sdev->pm_regs[0][1] = au_readl(addr + 0x04);
- sdev->pm_regs[0][2] = au_readl(addr + 0x08);
- sdev->pm_regs[0][3] = au_readl(addr + 0x0c);
+ addr = (void __iomem *)KSEG1ADDR(AU1550_DBDMA_CONF_PHYS_ADDR);
+ alchemy_dbdma_pm_data[0][0] = __raw_readl(addr + 0x00);
+ alchemy_dbdma_pm_data[0][1] = __raw_readl(addr + 0x04);
+ alchemy_dbdma_pm_data[0][2] = __raw_readl(addr + 0x08);
+ alchemy_dbdma_pm_data[0][3] = __raw_readl(addr + 0x0c);
/* save channel configurations */
- for (i = 1, addr = DDMA_CHANNEL_BASE; i <= NUM_DBDMA_CHANS; i++) {
- sdev->pm_regs[i][0] = au_readl(addr + 0x00);
- sdev->pm_regs[i][1] = au_readl(addr + 0x04);
- sdev->pm_regs[i][2] = au_readl(addr + 0x08);
- sdev->pm_regs[i][3] = au_readl(addr + 0x0c);
- sdev->pm_regs[i][4] = au_readl(addr + 0x10);
- sdev->pm_regs[i][5] = au_readl(addr + 0x14);
+ addr = (void __iomem *)KSEG1ADDR(AU1550_DBDMA_PHYS_ADDR);
+ for (i = 1; i <= NUM_DBDMA_CHANS; i++) {
+ alchemy_dbdma_pm_data[i][0] = __raw_readl(addr + 0x00);
+ alchemy_dbdma_pm_data[i][1] = __raw_readl(addr + 0x04);
+ alchemy_dbdma_pm_data[i][2] = __raw_readl(addr + 0x08);
+ alchemy_dbdma_pm_data[i][3] = __raw_readl(addr + 0x0c);
+ alchemy_dbdma_pm_data[i][4] = __raw_readl(addr + 0x10);
+ alchemy_dbdma_pm_data[i][5] = __raw_readl(addr + 0x14);
/* halt channel */
- au_writel(sdev->pm_regs[i][0] & ~1, addr + 0x00);
- au_sync();
- while (!(au_readl(addr + 0x14) & 1))
- au_sync();
+ __raw_writel(alchemy_dbdma_pm_data[i][0] & ~1, addr + 0x00);
+ wmb();
+ while (!(__raw_readl(addr + 0x14) & 1))
+ wmb();
addr += 0x100; /* next channel base */
}
/* disable channel interrupts */
- au_writel(0, DDMA_GLOBAL_BASE + 0x0c);
- au_sync();
+ addr = (void __iomem *)KSEG1ADDR(AU1550_DBDMA_CONF_PHYS_ADDR);
+ __raw_writel(0, addr + 0x0c);
+ wmb();
return 0;
}
-static int alchemy_dbdma_resume(struct sys_device *dev)
+static void alchemy_dbdma_resume(void)
{
- struct alchemy_dbdma_sysdev *sdev =
- container_of(dev, struct alchemy_dbdma_sysdev, sysdev);
int i;
- u32 addr;
+ void __iomem *addr;
- addr = DDMA_GLOBAL_BASE;
- au_writel(sdev->pm_regs[0][0], addr + 0x00);
- au_writel(sdev->pm_regs[0][1], addr + 0x04);
- au_writel(sdev->pm_regs[0][2], addr + 0x08);
- au_writel(sdev->pm_regs[0][3], addr + 0x0c);
+ addr = (void __iomem *)KSEG1ADDR(AU1550_DBDMA_CONF_PHYS_ADDR);
+ __raw_writel(alchemy_dbdma_pm_data[0][0], addr + 0x00);
+ __raw_writel(alchemy_dbdma_pm_data[0][1], addr + 0x04);
+ __raw_writel(alchemy_dbdma_pm_data[0][2], addr + 0x08);
+ __raw_writel(alchemy_dbdma_pm_data[0][3], addr + 0x0c);
/* restore channel configurations */
- for (i = 1, addr = DDMA_CHANNEL_BASE; i <= NUM_DBDMA_CHANS; i++) {
- au_writel(sdev->pm_regs[i][0], addr + 0x00);
- au_writel(sdev->pm_regs[i][1], addr + 0x04);
- au_writel(sdev->pm_regs[i][2], addr + 0x08);
- au_writel(sdev->pm_regs[i][3], addr + 0x0c);
- au_writel(sdev->pm_regs[i][4], addr + 0x10);
- au_writel(sdev->pm_regs[i][5], addr + 0x14);
- au_sync();
+ addr = (void __iomem *)KSEG1ADDR(AU1550_DBDMA_PHYS_ADDR);
+ for (i = 1; i <= NUM_DBDMA_CHANS; i++) {
+ __raw_writel(alchemy_dbdma_pm_data[i][0], addr + 0x00);
+ __raw_writel(alchemy_dbdma_pm_data[i][1], addr + 0x04);
+ __raw_writel(alchemy_dbdma_pm_data[i][2], addr + 0x08);
+ __raw_writel(alchemy_dbdma_pm_data[i][3], addr + 0x0c);
+ __raw_writel(alchemy_dbdma_pm_data[i][4], addr + 0x10);
+ __raw_writel(alchemy_dbdma_pm_data[i][5], addr + 0x14);
+ wmb();
addr += 0x100; /* next channel base */
}
-
- return 0;
}
-static struct sysdev_class alchemy_dbdma_sysdev_class = {
- .name = "dbdma",
+static struct syscore_ops alchemy_dbdma_syscore_ops = {
.suspend = alchemy_dbdma_suspend,
.resume = alchemy_dbdma_resume,
};
-static int __init alchemy_dbdma_sysdev_init(void)
-{
- struct alchemy_dbdma_sysdev *sdev;
- int ret;
-
- ret = sysdev_class_register(&alchemy_dbdma_sysdev_class);
- if (ret)
- return ret;
-
- sdev = kzalloc(sizeof(struct alchemy_dbdma_sysdev), GFP_KERNEL);
- if (!sdev)
- return -ENOMEM;
-
- sdev->sysdev.id = -1;
- sdev->sysdev.cls = &alchemy_dbdma_sysdev_class;
- ret = sysdev_register(&sdev->sysdev);
- if (ret)
- kfree(sdev);
-
- return ret;
-}
-
static int __init au1xxx_dbdma_init(void)
{
int irq_nr, ret;
@@ -1084,11 +1055,7 @@ static int __init au1xxx_dbdma_init(void)
else {
dbdma_initialized = 1;
printk(KERN_INFO "Alchemy DBDMA initialized\n");
- ret = alchemy_dbdma_sysdev_init();
- if (ret) {
- printk(KERN_ERR "DBDMA PM init failed\n");
- ret = 0;
- }
+ register_syscore_ops(&alchemy_dbdma_syscore_ops);
}
return ret;
diff --git a/arch/mips/alchemy/common/dma.c b/arch/mips/alchemy/common/dma.c
index d5278877891d..347980e79a89 100644
--- a/arch/mips/alchemy/common/dma.c
+++ b/arch/mips/alchemy/common/dma.c
@@ -58,6 +58,9 @@
* returned from request_dma.
*/
+/* DMA Channel register block spacing */
+#define DMA_CHANNEL_LEN 0x00000100
+
DEFINE_SPINLOCK(au1000_dma_spin_lock);
struct dma_chan au1000_dma_table[NUM_AU1000_DMA_CHANNELS] = {
@@ -77,22 +80,23 @@ static const struct dma_dev {
unsigned int fifo_addr;
unsigned int dma_mode;
} dma_dev_table[DMA_NUM_DEV] = {
- {UART0_ADDR + UART_TX, 0},
- {UART0_ADDR + UART_RX, 0},
- {0, 0},
- {0, 0},
- {AC97C_DATA, DMA_DW16 }, /* coherent */
- {AC97C_DATA, DMA_DR | DMA_DW16 }, /* coherent */
- {UART3_ADDR + UART_TX, DMA_DW8 | DMA_NC},
- {UART3_ADDR + UART_RX, DMA_DR | DMA_DW8 | DMA_NC},
- {USBD_EP0RD, DMA_DR | DMA_DW8 | DMA_NC},
- {USBD_EP0WR, DMA_DW8 | DMA_NC},
- {USBD_EP2WR, DMA_DW8 | DMA_NC},
- {USBD_EP3WR, DMA_DW8 | DMA_NC},
- {USBD_EP4RD, DMA_DR | DMA_DW8 | DMA_NC},
- {USBD_EP5RD, DMA_DR | DMA_DW8 | DMA_NC},
- {I2S_DATA, DMA_DW32 | DMA_NC},
- {I2S_DATA, DMA_DR | DMA_DW32 | DMA_NC}
+ { AU1000_UART0_PHYS_ADDR + 0x04, DMA_DW8 }, /* UART0_TX */
+ { AU1000_UART0_PHYS_ADDR + 0x00, DMA_DW8 | DMA_DR }, /* UART0_RX */
+ { 0, 0 }, /* DMA_REQ0 */
+ { 0, 0 }, /* DMA_REQ1 */
+ { AU1000_AC97_PHYS_ADDR + 0x08, DMA_DW16 }, /* AC97 TX c */
+ { AU1000_AC97_PHYS_ADDR + 0x08, DMA_DW16 | DMA_DR }, /* AC97 RX c */
+ { AU1000_UART3_PHYS_ADDR + 0x04, DMA_DW8 | DMA_NC }, /* UART3_TX */
+ { AU1000_UART3_PHYS_ADDR + 0x00, DMA_DW8 | DMA_NC | DMA_DR }, /* UART3_RX */
+ { AU1000_USBD_PHYS_ADDR + 0x00, DMA_DW8 | DMA_NC | DMA_DR }, /* EP0RD */
+ { AU1000_USBD_PHYS_ADDR + 0x04, DMA_DW8 | DMA_NC }, /* EP0WR */
+ { AU1000_USBD_PHYS_ADDR + 0x08, DMA_DW8 | DMA_NC }, /* EP2WR */
+ { AU1000_USBD_PHYS_ADDR + 0x0c, DMA_DW8 | DMA_NC }, /* EP3WR */
+ { AU1000_USBD_PHYS_ADDR + 0x10, DMA_DW8 | DMA_NC | DMA_DR }, /* EP4RD */
+ { AU1000_USBD_PHYS_ADDR + 0x14, DMA_DW8 | DMA_NC | DMA_DR }, /* EP5RD */
+ /* on Au1500, these 2 are DMA_REQ2/3 (GPIO208/209) instead! */
+ { AU1000_I2S_PHYS_ADDR + 0x00, DMA_DW32 | DMA_NC}, /* I2S TX */
+ { AU1000_I2S_PHYS_ADDR + 0x00, DMA_DW32 | DMA_NC | DMA_DR}, /* I2S RX */
};
int au1000_dma_read_proc(char *buf, char **start, off_t fpos,
@@ -123,10 +127,10 @@ int au1000_dma_read_proc(char *buf, char **start, off_t fpos,
/* Device FIFO addresses and default DMA modes - 2nd bank */
static const struct dma_dev dma_dev_table_bank2[DMA_NUM_DEV_BANK2] = {
- { SD0_XMIT_FIFO, DMA_DS | DMA_DW8 }, /* coherent */
- { SD0_RECV_FIFO, DMA_DS | DMA_DR | DMA_DW8 }, /* coherent */
- { SD1_XMIT_FIFO, DMA_DS | DMA_DW8 }, /* coherent */
- { SD1_RECV_FIFO, DMA_DS | DMA_DR | DMA_DW8 } /* coherent */
+ { AU1100_SD0_PHYS_ADDR + 0x00, DMA_DS | DMA_DW8 }, /* coherent */
+ { AU1100_SD0_PHYS_ADDR + 0x04, DMA_DS | DMA_DW8 | DMA_DR }, /* coherent */
+ { AU1100_SD1_PHYS_ADDR + 0x00, DMA_DS | DMA_DW8 }, /* coherent */
+ { AU1100_SD1_PHYS_ADDR + 0x04, DMA_DS | DMA_DW8 | DMA_DR } /* coherent */
};
void dump_au1000_dma_channel(unsigned int dmanr)
@@ -202,7 +206,7 @@ int request_au1000_dma(int dev_id, const char *dev_str,
}
/* fill it in */
- chan->io = DMA_CHANNEL_BASE + i * DMA_CHANNEL_LEN;
+ chan->io = KSEG1ADDR(AU1000_DMA_PHYS_ADDR) + i * DMA_CHANNEL_LEN;
chan->dev_id = dev_id;
chan->dev_str = dev_str;
chan->fifo_addr = dev->fifo_addr;
diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c
index 55dd7c888517..8b60ba0675e2 100644
--- a/arch/mips/alchemy/common/irq.c
+++ b/arch/mips/alchemy/common/irq.c
@@ -30,7 +30,7 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <asm/irq_cpu.h>
#include <asm/mipsregs.h>
@@ -39,6 +39,36 @@
#include <asm/mach-pb1x00/pb1000.h>
#endif
+/* Interrupt Controller register offsets */
+#define IC_CFG0RD 0x40
+#define IC_CFG0SET 0x40
+#define IC_CFG0CLR 0x44
+#define IC_CFG1RD 0x48
+#define IC_CFG1SET 0x48
+#define IC_CFG1CLR 0x4C
+#define IC_CFG2RD 0x50
+#define IC_CFG2SET 0x50
+#define IC_CFG2CLR 0x54
+#define IC_REQ0INT 0x54
+#define IC_SRCRD 0x58
+#define IC_SRCSET 0x58
+#define IC_SRCCLR 0x5C
+#define IC_REQ1INT 0x5C
+#define IC_ASSIGNRD 0x60
+#define IC_ASSIGNSET 0x60
+#define IC_ASSIGNCLR 0x64
+#define IC_WAKERD 0x68
+#define IC_WAKESET 0x68
+#define IC_WAKECLR 0x6C
+#define IC_MASKRD 0x70
+#define IC_MASKSET 0x70
+#define IC_MASKCLR 0x74
+#define IC_RISINGRD 0x78
+#define IC_RISINGCLR 0x78
+#define IC_FALLINGRD 0x7C
+#define IC_FALLINGCLR 0x7C
+#define IC_TESTBIT 0x80
+
static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type);
/* NOTE on interrupt priorities: The original writers of this code said:
@@ -221,89 +251,101 @@ struct au1xxx_irqmap au1200_irqmap[] __initdata = {
static void au1x_ic0_unmask(struct irq_data *d)
{
unsigned int bit = d->irq - AU1000_INTC0_INT_BASE;
- au_writel(1 << bit, IC0_MASKSET);
- au_writel(1 << bit, IC0_WAKESET);
- au_sync();
+ void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR);
+
+ __raw_writel(1 << bit, base + IC_MASKSET);
+ __raw_writel(1 << bit, base + IC_WAKESET);
+ wmb();
}
static void au1x_ic1_unmask(struct irq_data *d)
{
unsigned int bit = d->irq - AU1000_INTC1_INT_BASE;
- au_writel(1 << bit, IC1_MASKSET);
- au_writel(1 << bit, IC1_WAKESET);
+ void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR);
+
+ __raw_writel(1 << bit, base + IC_MASKSET);
+ __raw_writel(1 << bit, base + IC_WAKESET);
/* very hacky. does the pb1000 cpld auto-disable this int?
* nowhere in the current kernel sources is it disabled. --mlau
*/
#if defined(CONFIG_MIPS_PB1000)
if (d->irq == AU1000_GPIO15_INT)
- au_writel(0x4000, PB1000_MDR); /* enable int */
+ __raw_writel(0x4000, (void __iomem *)PB1000_MDR); /* enable int */
#endif
- au_sync();
+ wmb();
}
static void au1x_ic0_mask(struct irq_data *d)
{
unsigned int bit = d->irq - AU1000_INTC0_INT_BASE;
- au_writel(1 << bit, IC0_MASKCLR);
- au_writel(1 << bit, IC0_WAKECLR);
- au_sync();
+ void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR);
+
+ __raw_writel(1 << bit, base + IC_MASKCLR);
+ __raw_writel(1 << bit, base + IC_WAKECLR);
+ wmb();
}
static void au1x_ic1_mask(struct irq_data *d)
{
unsigned int bit = d->irq - AU1000_INTC1_INT_BASE;
- au_writel(1 << bit, IC1_MASKCLR);
- au_writel(1 << bit, IC1_WAKECLR);
- au_sync();
+ void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR);
+
+ __raw_writel(1 << bit, base + IC_MASKCLR);
+ __raw_writel(1 << bit, base + IC_WAKECLR);
+ wmb();
}
static void au1x_ic0_ack(struct irq_data *d)
{
unsigned int bit = d->irq - AU1000_INTC0_INT_BASE;
+ void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR);
/*
* This may assume that we don't get interrupts from
* both edges at once, or if we do, that we don't care.
*/
- au_writel(1 << bit, IC0_FALLINGCLR);
- au_writel(1 << bit, IC0_RISINGCLR);
- au_sync();
+ __raw_writel(1 << bit, base + IC_FALLINGCLR);
+ __raw_writel(1 << bit, base + IC_RISINGCLR);
+ wmb();
}
static void au1x_ic1_ack(struct irq_data *d)
{
unsigned int bit = d->irq - AU1000_INTC1_INT_BASE;
+ void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR);
/*
* This may assume that we don't get interrupts from
* both edges at once, or if we do, that we don't care.
*/
- au_writel(1 << bit, IC1_FALLINGCLR);
- au_writel(1 << bit, IC1_RISINGCLR);
- au_sync();
+ __raw_writel(1 << bit, base + IC_FALLINGCLR);
+ __raw_writel(1 << bit, base + IC_RISINGCLR);
+ wmb();
}
static void au1x_ic0_maskack(struct irq_data *d)
{
unsigned int bit = d->irq - AU1000_INTC0_INT_BASE;
+ void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR);
- au_writel(1 << bit, IC0_WAKECLR);
- au_writel(1 << bit, IC0_MASKCLR);
- au_writel(1 << bit, IC0_RISINGCLR);
- au_writel(1 << bit, IC0_FALLINGCLR);
- au_sync();
+ __raw_writel(1 << bit, base + IC_WAKECLR);
+ __raw_writel(1 << bit, base + IC_MASKCLR);
+ __raw_writel(1 << bit, base + IC_RISINGCLR);
+ __raw_writel(1 << bit, base + IC_FALLINGCLR);
+ wmb();
}
static void au1x_ic1_maskack(struct irq_data *d)
{
unsigned int bit = d->irq - AU1000_INTC1_INT_BASE;
+ void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR);
- au_writel(1 << bit, IC1_WAKECLR);
- au_writel(1 << bit, IC1_MASKCLR);
- au_writel(1 << bit, IC1_RISINGCLR);
- au_writel(1 << bit, IC1_FALLINGCLR);
- au_sync();
+ __raw_writel(1 << bit, base + IC_WAKECLR);
+ __raw_writel(1 << bit, base + IC_MASKCLR);
+ __raw_writel(1 << bit, base + IC_RISINGCLR);
+ __raw_writel(1 << bit, base + IC_FALLINGCLR);
+ wmb();
}
static int au1x_ic1_setwake(struct irq_data *d, unsigned int on)
@@ -318,13 +360,13 @@ static int au1x_ic1_setwake(struct irq_data *d, unsigned int on)
return -EINVAL;
local_irq_save(flags);
- wakemsk = au_readl(SYS_WAKEMSK);
+ wakemsk = __raw_readl((void __iomem *)SYS_WAKEMSK);
if (on)
wakemsk |= 1 << bit;
else
wakemsk &= ~(1 << bit);
- au_writel(wakemsk, SYS_WAKEMSK);
- au_sync();
+ __raw_writel(wakemsk, (void __iomem *)SYS_WAKEMSK);
+ wmb();
local_irq_restore(flags);
return 0;
@@ -356,81 +398,74 @@ static struct irq_chip au1x_ic1_chip = {
static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type)
{
struct irq_chip *chip;
- unsigned long icr[6];
- unsigned int bit, ic, irq = d->irq;
+ unsigned int bit, irq = d->irq;
irq_flow_handler_t handler = NULL;
unsigned char *name = NULL;
+ void __iomem *base;
int ret;
if (irq >= AU1000_INTC1_INT_BASE) {
bit = irq - AU1000_INTC1_INT_BASE;
chip = &au1x_ic1_chip;
- ic = 1;
+ base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR);
} else {
bit = irq - AU1000_INTC0_INT_BASE;
chip = &au1x_ic0_chip;
- ic = 0;
+ base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR);
}
if (bit > 31)
return -EINVAL;
- icr[0] = ic ? IC1_CFG0SET : IC0_CFG0SET;
- icr[1] = ic ? IC1_CFG1SET : IC0_CFG1SET;
- icr[2] = ic ? IC1_CFG2SET : IC0_CFG2SET;
- icr[3] = ic ? IC1_CFG0CLR : IC0_CFG0CLR;
- icr[4] = ic ? IC1_CFG1CLR : IC0_CFG1CLR;
- icr[5] = ic ? IC1_CFG2CLR : IC0_CFG2CLR;
-
ret = 0;
switch (flow_type) { /* cfgregs 2:1:0 */
case IRQ_TYPE_EDGE_RISING: /* 0:0:1 */
- au_writel(1 << bit, icr[5]);
- au_writel(1 << bit, icr[4]);
- au_writel(1 << bit, icr[0]);
+ __raw_writel(1 << bit, base + IC_CFG2CLR);
+ __raw_writel(1 << bit, base + IC_CFG1CLR);
+ __raw_writel(1 << bit, base + IC_CFG0SET);
handler = handle_edge_irq;
name = "riseedge";
break;
case IRQ_TYPE_EDGE_FALLING: /* 0:1:0 */
- au_writel(1 << bit, icr[5]);
- au_writel(1 << bit, icr[1]);
- au_writel(1 << bit, icr[3]);
+ __raw_writel(1 << bit, base + IC_CFG2CLR);
+ __raw_writel(1 << bit, base + IC_CFG1SET);
+ __raw_writel(1 << bit, base + IC_CFG0CLR);
handler = handle_edge_irq;
name = "falledge";
break;
case IRQ_TYPE_EDGE_BOTH: /* 0:1:1 */
- au_writel(1 << bit, icr[5]);
- au_writel(1 << bit, icr[1]);
- au_writel(1 << bit, icr[0]);
+ __raw_writel(1 << bit, base + IC_CFG2CLR);
+ __raw_writel(1 << bit, base + IC_CFG1SET);
+ __raw_writel(1 << bit, base + IC_CFG0SET);
handler = handle_edge_irq;
name = "bothedge";
break;
case IRQ_TYPE_LEVEL_HIGH: /* 1:0:1 */
- au_writel(1 << bit, icr[2]);
- au_writel(1 << bit, icr[4]);
- au_writel(1 << bit, icr[0]);
+ __raw_writel(1 << bit, base + IC_CFG2SET);
+ __raw_writel(1 << bit, base + IC_CFG1CLR);
+ __raw_writel(1 << bit, base + IC_CFG0SET);
handler = handle_level_irq;
name = "hilevel";
break;
case IRQ_TYPE_LEVEL_LOW: /* 1:1:0 */
- au_writel(1 << bit, icr[2]);
- au_writel(1 << bit, icr[1]);
- au_writel(1 << bit, icr[3]);
+ __raw_writel(1 << bit, base + IC_CFG2SET);
+ __raw_writel(1 << bit, base + IC_CFG1SET);
+ __raw_writel(1 << bit, base + IC_CFG0CLR);
handler = handle_level_irq;
name = "lowlevel";
break;
case IRQ_TYPE_NONE: /* 0:0:0 */
- au_writel(1 << bit, icr[5]);
- au_writel(1 << bit, icr[4]);
- au_writel(1 << bit, icr[3]);
+ __raw_writel(1 << bit, base + IC_CFG2CLR);
+ __raw_writel(1 << bit, base + IC_CFG1CLR);
+ __raw_writel(1 << bit, base + IC_CFG0CLR);
break;
default:
ret = -EINVAL;
}
__irq_set_chip_handler_name_locked(d->irq, chip, handler, name);
- au_sync();
+ wmb();
return ret;
}
@@ -444,21 +479,21 @@ asmlinkage void plat_irq_dispatch(void)
off = MIPS_CPU_IRQ_BASE + 7;
goto handle;
} else if (pending & CAUSEF_IP2) {
- s = IC0_REQ0INT;
+ s = KSEG1ADDR(AU1000_IC0_PHYS_ADDR) + IC_REQ0INT;
off = AU1000_INTC0_INT_BASE;
} else if (pending & CAUSEF_IP3) {
- s = IC0_REQ1INT;
+ s = KSEG1ADDR(AU1000_IC0_PHYS_ADDR) + IC_REQ1INT;
off = AU1000_INTC0_INT_BASE;
} else if (pending & CAUSEF_IP4) {
- s = IC1_REQ0INT;
+ s = KSEG1ADDR(AU1000_IC1_PHYS_ADDR) + IC_REQ0INT;
off = AU1000_INTC1_INT_BASE;
} else if (pending & CAUSEF_IP5) {
- s = IC1_REQ1INT;
+ s = KSEG1ADDR(AU1000_IC1_PHYS_ADDR) + IC_REQ1INT;
off = AU1000_INTC1_INT_BASE;
} else
goto spurious;
- s = au_readl(s);
+ s = __raw_readl((void __iomem *)s);
if (unlikely(!s)) {
spurious:
spurious_interrupt();
@@ -469,48 +504,42 @@ handle:
do_IRQ(off);
}
+
+static inline void ic_init(void __iomem *base)
+{
+ /* initialize interrupt controller to a safe state */
+ __raw_writel(0xffffffff, base + IC_CFG0CLR);
+ __raw_writel(0xffffffff, base + IC_CFG1CLR);
+ __raw_writel(0xffffffff, base + IC_CFG2CLR);
+ __raw_writel(0xffffffff, base + IC_MASKCLR);
+ __raw_writel(0xffffffff, base + IC_ASSIGNCLR);
+ __raw_writel(0xffffffff, base + IC_WAKECLR);
+ __raw_writel(0xffffffff, base + IC_SRCSET);
+ __raw_writel(0xffffffff, base + IC_FALLINGCLR);
+ __raw_writel(0xffffffff, base + IC_RISINGCLR);
+ __raw_writel(0x00000000, base + IC_TESTBIT);
+ wmb();
+}
+
static void __init au1000_init_irq(struct au1xxx_irqmap *map)
{
unsigned int bit, irq_nr;
- int i;
-
- /*
- * Initialize interrupt controllers to a safe state.
- */
- au_writel(0xffffffff, IC0_CFG0CLR);
- au_writel(0xffffffff, IC0_CFG1CLR);
- au_writel(0xffffffff, IC0_CFG2CLR);
- au_writel(0xffffffff, IC0_MASKCLR);
- au_writel(0xffffffff, IC0_ASSIGNCLR);
- au_writel(0xffffffff, IC0_WAKECLR);
- au_writel(0xffffffff, IC0_SRCSET);
- au_writel(0xffffffff, IC0_FALLINGCLR);
- au_writel(0xffffffff, IC0_RISINGCLR);
- au_writel(0x00000000, IC0_TESTBIT);
-
- au_writel(0xffffffff, IC1_CFG0CLR);
- au_writel(0xffffffff, IC1_CFG1CLR);
- au_writel(0xffffffff, IC1_CFG2CLR);
- au_writel(0xffffffff, IC1_MASKCLR);
- au_writel(0xffffffff, IC1_ASSIGNCLR);
- au_writel(0xffffffff, IC1_WAKECLR);
- au_writel(0xffffffff, IC1_SRCSET);
- au_writel(0xffffffff, IC1_FALLINGCLR);
- au_writel(0xffffffff, IC1_RISINGCLR);
- au_writel(0x00000000, IC1_TESTBIT);
+ void __iomem *base;
+ ic_init((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR));
+ ic_init((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR));
mips_cpu_irq_init();
/* register all 64 possible IC0+IC1 irq sources as type "none".
* Use set_irq_type() to set edge/level behaviour at runtime.
*/
- for (i = AU1000_INTC0_INT_BASE;
- (i < AU1000_INTC0_INT_BASE + 32); i++)
- au1x_ic_settype(irq_get_irq_data(i), IRQ_TYPE_NONE);
+ for (irq_nr = AU1000_INTC0_INT_BASE;
+ (irq_nr < AU1000_INTC0_INT_BASE + 32); irq_nr++)
+ au1x_ic_settype(irq_get_irq_data(irq_nr), IRQ_TYPE_NONE);
- for (i = AU1000_INTC1_INT_BASE;
- (i < AU1000_INTC1_INT_BASE + 32); i++)
- au1x_ic_settype(irq_get_irq_data(i), IRQ_TYPE_NONE);
+ for (irq_nr = AU1000_INTC1_INT_BASE;
+ (irq_nr < AU1000_INTC1_INT_BASE + 32); irq_nr++)
+ au1x_ic_settype(irq_get_irq_data(irq_nr), IRQ_TYPE_NONE);
/*
* Initialize IC0, which is fixed per processor.
@@ -520,13 +549,13 @@ static void __init au1000_init_irq(struct au1xxx_irqmap *map)
if (irq_nr >= AU1000_INTC1_INT_BASE) {
bit = irq_nr - AU1000_INTC1_INT_BASE;
- if (map->im_request)
- au_writel(1 << bit, IC1_ASSIGNSET);
+ base = (void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR);
} else {
bit = irq_nr - AU1000_INTC0_INT_BASE;
- if (map->im_request)
- au_writel(1 << bit, IC0_ASSIGNSET);
+ base = (void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR);
}
+ if (map->im_request)
+ __raw_writel(1 << bit, base + IC_ASSIGNSET);
au1x_ic_settype(irq_get_irq_data(irq_nr), map->im_type);
++map;
@@ -556,90 +585,62 @@ void __init arch_init_irq(void)
}
}
-struct alchemy_ic_sysdev {
- struct sys_device sysdev;
- void __iomem *base;
- unsigned long pmdata[7];
-};
-static int alchemy_ic_suspend(struct sys_device *dev, pm_message_t state)
-{
- struct alchemy_ic_sysdev *icdev =
- container_of(dev, struct alchemy_ic_sysdev, sysdev);
+static unsigned long alchemy_ic_pmdata[7 * 2];
- icdev->pmdata[0] = __raw_readl(icdev->base + IC_CFG0RD);
- icdev->pmdata[1] = __raw_readl(icdev->base + IC_CFG1RD);
- icdev->pmdata[2] = __raw_readl(icdev->base + IC_CFG2RD);
- icdev->pmdata[3] = __raw_readl(icdev->base + IC_SRCRD);
- icdev->pmdata[4] = __raw_readl(icdev->base + IC_ASSIGNRD);
- icdev->pmdata[5] = __raw_readl(icdev->base + IC_WAKERD);
- icdev->pmdata[6] = __raw_readl(icdev->base + IC_MASKRD);
-
- return 0;
+static inline void alchemy_ic_suspend_one(void __iomem *base, unsigned long *d)
+{
+ d[0] = __raw_readl(base + IC_CFG0RD);
+ d[1] = __raw_readl(base + IC_CFG1RD);
+ d[2] = __raw_readl(base + IC_CFG2RD);
+ d[3] = __raw_readl(base + IC_SRCRD);
+ d[4] = __raw_readl(base + IC_ASSIGNRD);
+ d[5] = __raw_readl(base + IC_WAKERD);
+ d[6] = __raw_readl(base + IC_MASKRD);
+ ic_init(base); /* shut it up too while at it */
}
-static int alchemy_ic_resume(struct sys_device *dev)
+static inline void alchemy_ic_resume_one(void __iomem *base, unsigned long *d)
{
- struct alchemy_ic_sysdev *icdev =
- container_of(dev, struct alchemy_ic_sysdev, sysdev);
-
- __raw_writel(0xffffffff, icdev->base + IC_MASKCLR);
- __raw_writel(0xffffffff, icdev->base + IC_CFG0CLR);
- __raw_writel(0xffffffff, icdev->base + IC_CFG1CLR);
- __raw_writel(0xffffffff, icdev->base + IC_CFG2CLR);
- __raw_writel(0xffffffff, icdev->base + IC_SRCCLR);
- __raw_writel(0xffffffff, icdev->base + IC_ASSIGNCLR);
- __raw_writel(0xffffffff, icdev->base + IC_WAKECLR);
- __raw_writel(0xffffffff, icdev->base + IC_RISINGCLR);
- __raw_writel(0xffffffff, icdev->base + IC_FALLINGCLR);
- __raw_writel(0x00000000, icdev->base + IC_TESTBIT);
- wmb();
- __raw_writel(icdev->pmdata[0], icdev->base + IC_CFG0SET);
- __raw_writel(icdev->pmdata[1], icdev->base + IC_CFG1SET);
- __raw_writel(icdev->pmdata[2], icdev->base + IC_CFG2SET);
- __raw_writel(icdev->pmdata[3], icdev->base + IC_SRCSET);
- __raw_writel(icdev->pmdata[4], icdev->base + IC_ASSIGNSET);
- __raw_writel(icdev->pmdata[5], icdev->base + IC_WAKESET);
+ ic_init(base);
+
+ __raw_writel(d[0], base + IC_CFG0SET);
+ __raw_writel(d[1], base + IC_CFG1SET);
+ __raw_writel(d[2], base + IC_CFG2SET);
+ __raw_writel(d[3], base + IC_SRCSET);
+ __raw_writel(d[4], base + IC_ASSIGNSET);
+ __raw_writel(d[5], base + IC_WAKESET);
wmb();
- __raw_writel(icdev->pmdata[6], icdev->base + IC_MASKSET);
+ __raw_writel(d[6], base + IC_MASKSET);
wmb();
+}
+static int alchemy_ic_suspend(void)
+{
+ alchemy_ic_suspend_one((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR),
+ alchemy_ic_pmdata);
+ alchemy_ic_suspend_one((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR),
+ &alchemy_ic_pmdata[7]);
return 0;
}
-static struct sysdev_class alchemy_ic_sysdev_class = {
- .name = "ic",
+static void alchemy_ic_resume(void)
+{
+ alchemy_ic_resume_one((void __iomem *)KSEG1ADDR(AU1000_IC1_PHYS_ADDR),
+ &alchemy_ic_pmdata[7]);
+ alchemy_ic_resume_one((void __iomem *)KSEG1ADDR(AU1000_IC0_PHYS_ADDR),
+ alchemy_ic_pmdata);
+}
+
+static struct syscore_ops alchemy_ic_syscore_ops = {
.suspend = alchemy_ic_suspend,
.resume = alchemy_ic_resume,
};
-static int __init alchemy_ic_sysdev_init(void)
+static int __init alchemy_ic_pm_init(void)
{
- struct alchemy_ic_sysdev *icdev;
- unsigned long icbase[2] = { IC0_PHYS_ADDR, IC1_PHYS_ADDR };
- int err, i;
-
- err = sysdev_class_register(&alchemy_ic_sysdev_class);
- if (err)
- return err;
-
- for (i = 0; i < 2; i++) {
- icdev = kzalloc(sizeof(struct alchemy_ic_sysdev), GFP_KERNEL);
- if (!icdev)
- return -ENOMEM;
-
- icdev->base = ioremap(icbase[i], 0x1000);
-
- icdev->sysdev.id = i;
- icdev->sysdev.cls = &alchemy_ic_sysdev_class;
- err = sysdev_register(&icdev->sysdev);
- if (err) {
- kfree(icdev);
- return err;
- }
- }
-
+ register_syscore_ops(&alchemy_ic_syscore_ops);
return 0;
}
-device_initcall(alchemy_ic_sysdev_init);
+device_initcall(alchemy_ic_pm_init);
diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c
index 9e7814db3d03..3b2c18b14341 100644
--- a/arch/mips/alchemy/common/platform.c
+++ b/arch/mips/alchemy/common/platform.c
@@ -13,9 +13,10 @@
#include <linux/dma-mapping.h>
#include <linux/etherdevice.h>
+#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
-#include <linux/init.h>
+#include <linux/slab.h>
#include <asm/mach-au1x00/au1xxx.h>
#include <asm/mach-au1x00/au1xxx_dbdma.h>
@@ -30,21 +31,12 @@ static void alchemy_8250_pm(struct uart_port *port, unsigned int state,
#ifdef CONFIG_SERIAL_8250
switch (state) {
case 0:
- if ((__raw_readl(port->membase + UART_MOD_CNTRL) & 3) != 3) {
- /* power-on sequence as suggested in the databooks */
- __raw_writel(0, port->membase + UART_MOD_CNTRL);
- wmb();
- __raw_writel(1, port->membase + UART_MOD_CNTRL);
- wmb();
- }
- __raw_writel(3, port->membase + UART_MOD_CNTRL); /* full on */
- wmb();
+ alchemy_uart_enable(CPHYSADDR(port->membase));
serial8250_do_pm(port, state, old_state);
break;
case 3: /* power off */
serial8250_do_pm(port, state, old_state);
- __raw_writel(0, port->membase + UART_MOD_CNTRL);
- wmb();
+ alchemy_uart_disable(CPHYSADDR(port->membase));
break;
default:
serial8250_do_pm(port, state, old_state);
@@ -65,38 +57,60 @@ static void alchemy_8250_pm(struct uart_port *port, unsigned int state,
.pm = alchemy_8250_pm, \
}
-static struct plat_serial8250_port au1x00_uart_data[] = {
-#if defined(CONFIG_SOC_AU1000)
- PORT(UART0_PHYS_ADDR, AU1000_UART0_INT),
- PORT(UART1_PHYS_ADDR, AU1000_UART1_INT),
- PORT(UART2_PHYS_ADDR, AU1000_UART2_INT),
- PORT(UART3_PHYS_ADDR, AU1000_UART3_INT),
-#elif defined(CONFIG_SOC_AU1500)
- PORT(UART0_PHYS_ADDR, AU1500_UART0_INT),
- PORT(UART3_PHYS_ADDR, AU1500_UART3_INT),
-#elif defined(CONFIG_SOC_AU1100)
- PORT(UART0_PHYS_ADDR, AU1100_UART0_INT),
- PORT(UART1_PHYS_ADDR, AU1100_UART1_INT),
- PORT(UART3_PHYS_ADDR, AU1100_UART3_INT),
-#elif defined(CONFIG_SOC_AU1550)
- PORT(UART0_PHYS_ADDR, AU1550_UART0_INT),
- PORT(UART1_PHYS_ADDR, AU1550_UART1_INT),
- PORT(UART3_PHYS_ADDR, AU1550_UART3_INT),
-#elif defined(CONFIG_SOC_AU1200)
- PORT(UART0_PHYS_ADDR, AU1200_UART0_INT),
- PORT(UART1_PHYS_ADDR, AU1200_UART1_INT),
-#endif
- { },
+static struct plat_serial8250_port au1x00_uart_data[][4] __initdata = {
+ [ALCHEMY_CPU_AU1000] = {
+ PORT(AU1000_UART0_PHYS_ADDR, AU1000_UART0_INT),
+ PORT(AU1000_UART1_PHYS_ADDR, AU1000_UART1_INT),
+ PORT(AU1000_UART2_PHYS_ADDR, AU1000_UART2_INT),
+ PORT(AU1000_UART3_PHYS_ADDR, AU1000_UART3_INT),
+ },
+ [ALCHEMY_CPU_AU1500] = {
+ PORT(AU1000_UART0_PHYS_ADDR, AU1500_UART0_INT),
+ PORT(AU1000_UART3_PHYS_ADDR, AU1500_UART3_INT),
+ },
+ [ALCHEMY_CPU_AU1100] = {
+ PORT(AU1000_UART0_PHYS_ADDR, AU1100_UART0_INT),
+ PORT(AU1000_UART1_PHYS_ADDR, AU1100_UART1_INT),
+ PORT(AU1000_UART3_PHYS_ADDR, AU1100_UART3_INT),
+ },
+ [ALCHEMY_CPU_AU1550] = {
+ PORT(AU1000_UART0_PHYS_ADDR, AU1550_UART0_INT),
+ PORT(AU1000_UART1_PHYS_ADDR, AU1550_UART1_INT),
+ PORT(AU1000_UART3_PHYS_ADDR, AU1550_UART3_INT),
+ },
+ [ALCHEMY_CPU_AU1200] = {
+ PORT(AU1000_UART0_PHYS_ADDR, AU1200_UART0_INT),
+ PORT(AU1000_UART1_PHYS_ADDR, AU1200_UART1_INT),
+ },
};
static struct platform_device au1xx0_uart_device = {
.name = "serial8250",
.id = PLAT8250_DEV_AU1X00,
- .dev = {
- .platform_data = au1x00_uart_data,
- },
};
+static void __init alchemy_setup_uarts(int ctype)
+{
+ unsigned int uartclk = get_au1x00_uart_baud_base() * 16;
+ int s = sizeof(struct plat_serial8250_port);
+ int c = alchemy_get_uarts(ctype);
+ struct plat_serial8250_port *ports;
+
+ ports = kzalloc(s * (c + 1), GFP_KERNEL);
+ if (!ports) {
+ printk(KERN_INFO "Alchemy: no memory for UART data\n");
+ return;
+ }
+ memcpy(ports, au1x00_uart_data[ctype], s * c);
+ au1xx0_uart_device.dev.platform_data = ports;
+
+ /* Fill up uartclk. */
+ for (s = 0; s < c; s++)
+ ports[s].uartclk = uartclk;
+ if (platform_device_register(&au1xx0_uart_device))
+ printk(KERN_INFO "Alchemy: failed to register UARTs\n");
+}
+
/* OHCI (USB full speed host controller) */
static struct resource au1xxx_usb_ohci_resources[] = {
[0] = {
@@ -269,8 +283,8 @@ extern struct au1xmmc_platform_data au1xmmc_platdata[2];
static struct resource au1200_mmc0_resources[] = {
[0] = {
- .start = SD0_PHYS_ADDR,
- .end = SD0_PHYS_ADDR + 0x7ffff,
+ .start = AU1100_SD0_PHYS_ADDR,
+ .end = AU1100_SD0_PHYS_ADDR + 0xfff,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -305,8 +319,8 @@ static struct platform_device au1200_mmc0_device = {
#ifndef CONFIG_MIPS_DB1200
static struct resource au1200_mmc1_resources[] = {
[0] = {
- .start = SD1_PHYS_ADDR,
- .end = SD1_PHYS_ADDR + 0x7ffff,
+ .start = AU1100_SD1_PHYS_ADDR,
+ .end = AU1100_SD1_PHYS_ADDR + 0xfff,
.flags = IORESOURCE_MEM,
},
[1] = {
@@ -359,15 +373,16 @@ static struct platform_device pbdb_smbus_device = {
#endif
/* Macro to help defining the Ethernet MAC resources */
+#define MAC_RES_COUNT 3 /* MAC regs base, MAC enable reg, MAC INT */
#define MAC_RES(_base, _enable, _irq) \
{ \
- .start = CPHYSADDR(_base), \
- .end = CPHYSADDR(_base + 0xffff), \
+ .start = _base, \
+ .end = _base + 0xffff, \
.flags = IORESOURCE_MEM, \
}, \
{ \
- .start = CPHYSADDR(_enable), \
- .end = CPHYSADDR(_enable + 0x3), \
+ .start = _enable, \
+ .end = _enable + 0x3, \
.flags = IORESOURCE_MEM, \
}, \
{ \
@@ -376,19 +391,29 @@ static struct platform_device pbdb_smbus_device = {
.flags = IORESOURCE_IRQ \
}
-static struct resource au1xxx_eth0_resources[] = {
-#if defined(CONFIG_SOC_AU1000)
- MAC_RES(AU1000_ETH0_BASE, AU1000_MAC0_ENABLE, AU1000_MAC0_DMA_INT),
-#elif defined(CONFIG_SOC_AU1100)
- MAC_RES(AU1100_ETH0_BASE, AU1100_MAC0_ENABLE, AU1100_MAC0_DMA_INT),
-#elif defined(CONFIG_SOC_AU1550)
- MAC_RES(AU1550_ETH0_BASE, AU1550_MAC0_ENABLE, AU1550_MAC0_DMA_INT),
-#elif defined(CONFIG_SOC_AU1500)
- MAC_RES(AU1500_ETH0_BASE, AU1500_MAC0_ENABLE, AU1500_MAC0_DMA_INT),
-#endif
+static struct resource au1xxx_eth0_resources[][MAC_RES_COUNT] __initdata = {
+ [ALCHEMY_CPU_AU1000] = {
+ MAC_RES(AU1000_MAC0_PHYS_ADDR,
+ AU1000_MACEN_PHYS_ADDR,
+ AU1000_MAC0_DMA_INT)
+ },
+ [ALCHEMY_CPU_AU1500] = {
+ MAC_RES(AU1500_MAC0_PHYS_ADDR,
+ AU1500_MACEN_PHYS_ADDR,
+ AU1500_MAC0_DMA_INT)
+ },
+ [ALCHEMY_CPU_AU1100] = {
+ MAC_RES(AU1000_MAC0_PHYS_ADDR,
+ AU1000_MACEN_PHYS_ADDR,
+ AU1100_MAC0_DMA_INT)
+ },
+ [ALCHEMY_CPU_AU1550] = {
+ MAC_RES(AU1000_MAC0_PHYS_ADDR,
+ AU1000_MACEN_PHYS_ADDR,
+ AU1550_MAC0_DMA_INT)
+ },
};
-
static struct au1000_eth_platform_data au1xxx_eth0_platform_data = {
.phy1_search_mac0 = 1,
};
@@ -396,20 +421,26 @@ static struct au1000_eth_platform_data au1xxx_eth0_platform_data = {
static struct platform_device au1xxx_eth0_device = {
.name = "au1000-eth",
.id = 0,
- .num_resources = ARRAY_SIZE(au1xxx_eth0_resources),
- .resource = au1xxx_eth0_resources,
+ .num_resources = MAC_RES_COUNT,
.dev.platform_data = &au1xxx_eth0_platform_data,
};
-#ifndef CONFIG_SOC_AU1100
-static struct resource au1xxx_eth1_resources[] = {
-#if defined(CONFIG_SOC_AU1000)
- MAC_RES(AU1000_ETH1_BASE, AU1000_MAC1_ENABLE, AU1000_MAC1_DMA_INT),
-#elif defined(CONFIG_SOC_AU1550)
- MAC_RES(AU1550_ETH1_BASE, AU1550_MAC1_ENABLE, AU1550_MAC1_DMA_INT),
-#elif defined(CONFIG_SOC_AU1500)
- MAC_RES(AU1500_ETH1_BASE, AU1500_MAC1_ENABLE, AU1500_MAC1_DMA_INT),
-#endif
+static struct resource au1xxx_eth1_resources[][MAC_RES_COUNT] __initdata = {
+ [ALCHEMY_CPU_AU1000] = {
+ MAC_RES(AU1000_MAC1_PHYS_ADDR,
+ AU1000_MACEN_PHYS_ADDR + 4,
+ AU1000_MAC1_DMA_INT)
+ },
+ [ALCHEMY_CPU_AU1500] = {
+ MAC_RES(AU1500_MAC1_PHYS_ADDR,
+ AU1500_MACEN_PHYS_ADDR + 4,
+ AU1500_MAC1_DMA_INT)
+ },
+ [ALCHEMY_CPU_AU1550] = {
+ MAC_RES(AU1000_MAC1_PHYS_ADDR,
+ AU1000_MACEN_PHYS_ADDR + 4,
+ AU1550_MAC1_DMA_INT)
+ },
};
static struct au1000_eth_platform_data au1xxx_eth1_platform_data = {
@@ -419,11 +450,9 @@ static struct au1000_eth_platform_data au1xxx_eth1_platform_data = {
static struct platform_device au1xxx_eth1_device = {
.name = "au1000-eth",
.id = 1,
- .num_resources = ARRAY_SIZE(au1xxx_eth1_resources),
- .resource = au1xxx_eth1_resources,
+ .num_resources = MAC_RES_COUNT,
.dev.platform_data = &au1xxx_eth1_platform_data,
};
-#endif
void __init au1xxx_override_eth_cfg(unsigned int port,
struct au1000_eth_platform_data *eth_data)
@@ -434,15 +463,65 @@ void __init au1xxx_override_eth_cfg(unsigned int port,
if (port == 0)
memcpy(&au1xxx_eth0_platform_data, eth_data,
sizeof(struct au1000_eth_platform_data));
-#ifndef CONFIG_SOC_AU1100
else
memcpy(&au1xxx_eth1_platform_data, eth_data,
sizeof(struct au1000_eth_platform_data));
-#endif
+}
+
+static void __init alchemy_setup_macs(int ctype)
+{
+ int ret, i;
+ unsigned char ethaddr[6];
+ struct resource *macres;
+
+ /* Handle 1st MAC */
+ if (alchemy_get_macs(ctype) < 1)
+ return;
+
+ macres = kmalloc(sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL);
+ if (!macres) {
+ printk(KERN_INFO "Alchemy: no memory for MAC0 resources\n");
+ return;
+ }
+ memcpy(macres, au1xxx_eth0_resources[ctype],
+ sizeof(struct resource) * MAC_RES_COUNT);
+ au1xxx_eth0_device.resource = macres;
+
+ 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);
+
+ ret = platform_device_register(&au1xxx_eth0_device);
+ if (!ret)
+ printk(KERN_INFO "Alchemy: failed to register MAC0\n");
+
+
+ /* Handle 2nd MAC */
+ if (alchemy_get_macs(ctype) < 2)
+ return;
+
+ macres = kmalloc(sizeof(struct resource) * MAC_RES_COUNT, GFP_KERNEL);
+ if (!macres) {
+ printk(KERN_INFO "Alchemy: no memory for MAC1 resources\n");
+ return;
+ }
+ memcpy(macres, au1xxx_eth1_resources[ctype],
+ sizeof(struct resource) * MAC_RES_COUNT);
+ au1xxx_eth1_device.resource = macres;
+
+ 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 (!(au_readl(SYS_PINFUNC) & (u32)SYS_PF_NI2)) {
+ ret = platform_device_register(&au1xxx_eth1_device);
+ if (ret)
+ printk(KERN_INFO "Alchemy: failed to register MAC1\n");
+ }
}
static struct platform_device *au1xxx_platform_devices[] __initdata = {
- &au1xx0_uart_device,
&au1xxx_usb_ohci_device,
#ifdef CONFIG_FB_AU1100
&au1100_lcd_device,
@@ -460,36 +539,17 @@ static struct platform_device *au1xxx_platform_devices[] __initdata = {
#ifdef SMBUS_PSC_BASE
&pbdb_smbus_device,
#endif
- &au1xxx_eth0_device,
};
static int __init au1xxx_platform_init(void)
{
- unsigned int uartclk = get_au1x00_uart_baud_base() * 16;
- int err, i;
- unsigned char ethaddr[6];
+ int err, ctype = alchemy_get_cputype();
- /* 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);
+ alchemy_setup_uarts(ctype);
+ alchemy_setup_macs(ctype);
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))
- err = platform_device_register(&au1xxx_eth1_device);
-#endif
-
return err;
}
diff --git a/arch/mips/alchemy/common/setup.c b/arch/mips/alchemy/common/setup.c
index 561e5da2658b..1b887c868417 100644
--- a/arch/mips/alchemy/common/setup.c
+++ b/arch/mips/alchemy/common/setup.c
@@ -52,8 +52,6 @@ void __init plat_mem_setup(void)
/* this is faster than wasting cycles trying to approximate it */
preset_lpj = (est_freq >> 1) / HZ;
- board_setup(); /* board specific setup */
-
if (au1xxx_cpu_needs_config_od())
/* Various early Au1xx0 errata corrected by this */
set_c0_config(1 << 19); /* Set Config[OD] */
@@ -61,6 +59,8 @@ void __init plat_mem_setup(void)
/* Clear to obtain best system bus performance */
clear_c0_config(1 << 19); /* Clear Config[OD] */
+ board_setup(); /* board specific setup */
+
/* IO/MEM resources. */
set_io_port_base(0);
ioport_resource.start = IOPORT_RESOURCE_START;
diff --git a/arch/mips/alchemy/common/time.c b/arch/mips/alchemy/common/time.c
index 2aecb2fdf982..d5da6adbf634 100644
--- a/arch/mips/alchemy/common/time.c
+++ b/arch/mips/alchemy/common/time.c
@@ -141,8 +141,7 @@ static int __init alchemy_time_init(unsigned int m2int)
goto cntr_err;
/* register counter1 clocksource and event device */
- clocksource_set_clock(&au1x_counter1_clocksource, 32768);
- clocksource_register(&au1x_counter1_clocksource);
+ clocksource_register_hz(&au1x_counter1_clocksource, 32768);
cd->shift = 32;
cd->mult = div_sc(32768, NSEC_PER_SEC, cd->shift);
diff --git a/arch/mips/alchemy/devboards/db1200/setup.c b/arch/mips/alchemy/devboards/db1200/setup.c
index 4a8980027ecf..1dac4f27d334 100644
--- a/arch/mips/alchemy/devboards/db1200/setup.c
+++ b/arch/mips/alchemy/devboards/db1200/setup.c
@@ -23,6 +23,13 @@ void __init board_setup(void)
unsigned long freq0, clksrc, div, pfc;
unsigned short whoami;
+ /* Set Config[OD] (disable overlapping bus transaction):
+ * This gets rid of a _lot_ of spurious interrupts (especially
+ * wrt. IDE); but incurs ~10% performance hit in some
+ * cpu-bound applications.
+ */
+ set_c0_config(1 << 19);
+
bcsr_init(DB1200_BCSR_PHYS_ADDR,
DB1200_BCSR_PHYS_ADDR + DB1200_BCSR_HEXLED_OFS);
diff --git a/arch/mips/alchemy/devboards/pb1000/board_setup.c b/arch/mips/alchemy/devboards/pb1000/board_setup.c
index 2d85c4b5be09..e64fdcbf75d0 100644
--- a/arch/mips/alchemy/devboards/pb1000/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1000/board_setup.c
@@ -65,7 +65,7 @@ void __init board_setup(void)
/* Set AUX clock to 12 MHz * 8 = 96 MHz */
au_writel(8, SYS_AUXPLL);
- au_writel(0, SYS_PINSTATERD);
+ alchemy_gpio1_input_enable();
udelay(100);
#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
diff --git a/arch/mips/alchemy/devboards/pb1500/board_setup.c b/arch/mips/alchemy/devboards/pb1500/board_setup.c
index 83f46215eb0c..3b4fa3206969 100644
--- a/arch/mips/alchemy/devboards/pb1500/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1500/board_setup.c
@@ -56,7 +56,7 @@ void __init board_setup(void)
sys_clksrc = sys_freqctrl = pin_func = 0;
/* Set AUX clock to 12 MHz * 8 = 96 MHz */
au_writel(8, SYS_AUXPLL);
- au_writel(0, SYS_PINSTATERD);
+ alchemy_gpio1_input_enable();
udelay(100);
/* GPIO201 is input for PCMCIA card detect */
diff --git a/arch/mips/alchemy/devboards/prom.c b/arch/mips/alchemy/devboards/prom.c
index baeb21385058..e5306b56da6d 100644
--- a/arch/mips/alchemy/devboards/prom.c
+++ b/arch/mips/alchemy/devboards/prom.c
@@ -62,5 +62,5 @@ void __init prom_init(void)
void prom_putchar(unsigned char c)
{
- alchemy_uart_putchar(UART0_PHYS_ADDR, c);
+ alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
}
diff --git a/arch/mips/alchemy/gpr/board_setup.c b/arch/mips/alchemy/gpr/board_setup.c
index ad2e3f137933..5f8f0691ed2d 100644
--- a/arch/mips/alchemy/gpr/board_setup.c
+++ b/arch/mips/alchemy/gpr/board_setup.c
@@ -36,9 +36,6 @@
#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 },
};
@@ -67,18 +64,15 @@ static void gpr_power_off(void)
void __init board_setup(void)
{
- printk(KERN_INFO "Tarpeze ITS GPR board\n");
+ printk(KERN_INFO "Trapeze 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" */
+ /* Enable UART1/3 */
+ alchemy_uart_enable(AU1000_UART3_PHYS_ADDR);
+ alchemy_uart_enable(AU1000_UART1_PHYS_ADDR);
/* Take away Reset of UMTS-card */
alchemy_gpio_direction_output(215, 1);
diff --git a/arch/mips/alchemy/gpr/init.c b/arch/mips/alchemy/gpr/init.c
index f044f4c541d7..229aafae680c 100644
--- a/arch/mips/alchemy/gpr/init.c
+++ b/arch/mips/alchemy/gpr/init.c
@@ -59,5 +59,5 @@ void __init prom_init(void)
void prom_putchar(unsigned char c)
{
- alchemy_uart_putchar(UART0_PHYS_ADDR, c);
+ alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
}
diff --git a/arch/mips/alchemy/mtx-1/board_setup.c b/arch/mips/alchemy/mtx-1/board_setup.c
index cf436ab679ae..3ae984cf98cf 100644
--- a/arch/mips/alchemy/mtx-1/board_setup.c
+++ b/arch/mips/alchemy/mtx-1/board_setup.c
@@ -87,7 +87,7 @@ void __init board_setup(void)
au_writel(SYS_PF_NI2, SYS_PINFUNC);
/* Initialize GPIO */
- au_writel(0xFFFFFFFF, SYS_TRIOUTCLR);
+ au_writel(~0, KSEG1ADDR(AU1000_SYS_PHYS_ADDR) + SYS_TRIOUTCLR);
alchemy_gpio_direction_output(0, 0); /* Disable M66EN (PCI 66MHz) */
alchemy_gpio_direction_output(3, 1); /* Disable PCI CLKRUN# */
alchemy_gpio_direction_output(1, 1); /* Enable EXT_IO3 */
diff --git a/arch/mips/alchemy/mtx-1/init.c b/arch/mips/alchemy/mtx-1/init.c
index f8d25575fa05..2e81cc7f3422 100644
--- a/arch/mips/alchemy/mtx-1/init.c
+++ b/arch/mips/alchemy/mtx-1/init.c
@@ -62,5 +62,5 @@ void __init prom_init(void)
void prom_putchar(unsigned char c)
{
- alchemy_uart_putchar(UART0_PHYS_ADDR, c);
+ alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
}
diff --git a/arch/mips/alchemy/mtx-1/platform.c b/arch/mips/alchemy/mtx-1/platform.c
index 956f946218c5..55628e390fd7 100644
--- a/arch/mips/alchemy/mtx-1/platform.c
+++ b/arch/mips/alchemy/mtx-1/platform.c
@@ -53,8 +53,8 @@ static struct platform_device mtx1_button = {
static struct resource mtx1_wdt_res[] = {
[0] = {
- .start = 15,
- .end = 15,
+ .start = 215,
+ .end = 215,
.name = "mtx1-wdt-gpio",
.flags = IORESOURCE_IRQ,
}
diff --git a/arch/mips/alchemy/xxs1500/board_setup.c b/arch/mips/alchemy/xxs1500/board_setup.c
index febfb0fb0896..81e57fad07ab 100644
--- a/arch/mips/alchemy/xxs1500/board_setup.c
+++ b/arch/mips/alchemy/xxs1500/board_setup.c
@@ -66,13 +66,10 @@ void __init board_setup(void)
au_writel(pin_func, SYS_PINFUNC);
/* Enable UART */
- au_writel(0x01, UART3_ADDR + UART_MOD_CNTRL); /* clock enable (CE) */
- mdelay(10);
- au_writel(0x03, UART3_ADDR + UART_MOD_CNTRL); /* CE and "enable" */
- mdelay(10);
-
- /* Enable DTR = USB power up */
- au_writel(0x01, UART3_ADDR + UART_MCR); /* UART_MCR_DTR is 0x01??? */
+ alchemy_uart_enable(AU1000_UART3_PHYS_ADDR);
+ /* Enable DTR (MCR bit 0) = USB power up */
+ __raw_writel(1, (void __iomem *)KSEG1ADDR(AU1000_UART3_PHYS_ADDR + 0x18));
+ wmb();
#ifdef CONFIG_PCI
#if defined(__MIPSEB__)
diff --git a/arch/mips/alchemy/xxs1500/init.c b/arch/mips/alchemy/xxs1500/init.c
index 34a90a4bb6f4..0ee02cfa989d 100644
--- a/arch/mips/alchemy/xxs1500/init.c
+++ b/arch/mips/alchemy/xxs1500/init.c
@@ -59,5 +59,5 @@ void __init prom_init(void)
void prom_putchar(unsigned char c)
{
- alchemy_uart_putchar(UART0_PHYS_ADDR, c);
+ alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
}
diff --git a/arch/mips/ath79/Kconfig b/arch/mips/ath79/Kconfig
index b05828260f7f..47707410582c 100644
--- a/arch/mips/ath79/Kconfig
+++ b/arch/mips/ath79/Kconfig
@@ -26,12 +26,17 @@ config ATH79_MACH_PB44
endmenu
config SOC_AR71XX
+ select USB_ARCH_HAS_EHCI
+ select USB_ARCH_HAS_OHCI
def_bool n
config SOC_AR724X
+ select USB_ARCH_HAS_EHCI
+ select USB_ARCH_HAS_OHCI
def_bool n
config SOC_AR913X
+ select USB_ARCH_HAS_EHCI
def_bool n
config ATH79_DEV_AR913X_WMAC
diff --git a/arch/mips/bcm47xx/nvram.c b/arch/mips/bcm47xx/nvram.c
index e5b6615731e5..54db815bc86c 100644
--- a/arch/mips/bcm47xx/nvram.c
+++ b/arch/mips/bcm47xx/nvram.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 2005 Broadcom Corporation
* Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2010-2011 Hauke Mehrtens <hauke@hauke-m.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
@@ -23,7 +24,7 @@
static char nvram_buf[NVRAM_SPACE];
/* Probe for NVRAM header */
-static void __init early_nvram_init(void)
+static void early_nvram_init(void)
{
struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
struct nvram_header *header;
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index c95f90bf734c..73b529b57433 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -3,6 +3,7 @@
* Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
* Copyright (C) 2006 Michael Buesch <mb@bu3sch.de>
* Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org>
+ * Copyright (C) 2010-2011 Hauke Mehrtens <hauke@hauke-m.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
@@ -57,10 +58,49 @@ static void bcm47xx_machine_halt(void)
}
#define READ_FROM_NVRAM(_outvar, name, buf) \
- if (nvram_getenv(name, buf, sizeof(buf)) >= 0)\
+ if (nvram_getprefix(prefix, name, buf, sizeof(buf)) >= 0)\
sprom->_outvar = simple_strtoul(buf, NULL, 0);
-static void bcm47xx_fill_sprom(struct ssb_sprom *sprom)
+#define READ_FROM_NVRAM2(_outvar, name1, name2, buf) \
+ if (nvram_getprefix(prefix, name1, buf, sizeof(buf)) >= 0 || \
+ nvram_getprefix(prefix, name2, buf, sizeof(buf)) >= 0)\
+ sprom->_outvar = simple_strtoul(buf, NULL, 0);
+
+static inline int nvram_getprefix(const char *prefix, char *name,
+ char *buf, int len)
+{
+ if (prefix) {
+ char key[100];
+
+ snprintf(key, sizeof(key), "%s%s", prefix, name);
+ return nvram_getenv(key, buf, len);
+ }
+
+ return nvram_getenv(name, buf, len);
+}
+
+static u32 nvram_getu32(const char *name, char *buf, int len)
+{
+ int rv;
+ char key[100];
+ u16 var0, var1;
+
+ snprintf(key, sizeof(key), "%s0", name);
+ rv = nvram_getenv(key, buf, len);
+ /* return 0 here so this looks like unset */
+ if (rv < 0)
+ return 0;
+ var0 = simple_strtoul(buf, NULL, 0);
+
+ snprintf(key, sizeof(key), "%s1", name);
+ rv = nvram_getenv(key, buf, len);
+ if (rv < 0)
+ return 0;
+ var1 = simple_strtoul(buf, NULL, 0);
+ return var1 << 16 | var0;
+}
+
+static void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix)
{
char buf[100];
u32 boardflags;
@@ -69,11 +109,12 @@ static void bcm47xx_fill_sprom(struct ssb_sprom *sprom)
sprom->revision = 1; /* Fallback: Old hardware does not define this. */
READ_FROM_NVRAM(revision, "sromrev", buf);
- if (nvram_getenv("il0macaddr", buf, sizeof(buf)) >= 0)
+ if (nvram_getprefix(prefix, "il0macaddr", buf, sizeof(buf)) >= 0 ||
+ nvram_getprefix(prefix, "macaddr", buf, sizeof(buf)) >= 0)
nvram_parse_macaddr(buf, sprom->il0mac);
- if (nvram_getenv("et0macaddr", buf, sizeof(buf)) >= 0)
+ if (nvram_getprefix(prefix, "et0macaddr", buf, sizeof(buf)) >= 0)
nvram_parse_macaddr(buf, sprom->et0mac);
- if (nvram_getenv("et1macaddr", buf, sizeof(buf)) >= 0)
+ if (nvram_getprefix(prefix, "et1macaddr", buf, sizeof(buf)) >= 0)
nvram_parse_macaddr(buf, sprom->et1mac);
READ_FROM_NVRAM(et0phyaddr, "et0phyaddr", buf);
READ_FROM_NVRAM(et1phyaddr, "et1phyaddr", buf);
@@ -95,20 +136,36 @@ static void bcm47xx_fill_sprom(struct ssb_sprom *sprom)
READ_FROM_NVRAM(pa1hib0, "pa1hib0", buf);
READ_FROM_NVRAM(pa1hib2, "pa1hib1", buf);
READ_FROM_NVRAM(pa1hib1, "pa1hib2", buf);
- READ_FROM_NVRAM(gpio0, "wl0gpio0", buf);
- READ_FROM_NVRAM(gpio1, "wl0gpio1", buf);
- READ_FROM_NVRAM(gpio2, "wl0gpio2", buf);
- READ_FROM_NVRAM(gpio3, "wl0gpio3", buf);
- READ_FROM_NVRAM(maxpwr_bg, "pa0maxpwr", buf);
- READ_FROM_NVRAM(maxpwr_al, "pa1lomaxpwr", buf);
- READ_FROM_NVRAM(maxpwr_a, "pa1maxpwr", buf);
- READ_FROM_NVRAM(maxpwr_ah, "pa1himaxpwr", buf);
- READ_FROM_NVRAM(itssi_a, "pa1itssit", buf);
- READ_FROM_NVRAM(itssi_bg, "pa0itssit", buf);
+ READ_FROM_NVRAM2(gpio0, "ledbh0", "wl0gpio0", buf);
+ READ_FROM_NVRAM2(gpio1, "ledbh1", "wl0gpio1", buf);
+ READ_FROM_NVRAM2(gpio2, "ledbh2", "wl0gpio2", buf);
+ READ_FROM_NVRAM2(gpio3, "ledbh3", "wl0gpio3", buf);
+ READ_FROM_NVRAM2(maxpwr_bg, "maxp2ga0", "pa0maxpwr", buf);
+ READ_FROM_NVRAM2(maxpwr_al, "maxp5gla0", "pa1lomaxpwr", buf);
+ READ_FROM_NVRAM2(maxpwr_a, "maxp5ga0", "pa1maxpwr", buf);
+ READ_FROM_NVRAM2(maxpwr_ah, "maxp5gha0", "pa1himaxpwr", buf);
+ READ_FROM_NVRAM2(itssi_bg, "itt5ga0", "pa0itssit", buf);
+ READ_FROM_NVRAM2(itssi_a, "itt2ga0", "pa1itssit", buf);
READ_FROM_NVRAM(tri2g, "tri2g", buf);
READ_FROM_NVRAM(tri5gl, "tri5gl", buf);
READ_FROM_NVRAM(tri5g, "tri5g", buf);
READ_FROM_NVRAM(tri5gh, "tri5gh", buf);
+ READ_FROM_NVRAM(txpid2g[0], "txpid2ga0", buf);
+ READ_FROM_NVRAM(txpid2g[1], "txpid2ga1", buf);
+ READ_FROM_NVRAM(txpid2g[2], "txpid2ga2", buf);
+ READ_FROM_NVRAM(txpid2g[3], "txpid2ga3", buf);
+ READ_FROM_NVRAM(txpid5g[0], "txpid5ga0", buf);
+ READ_FROM_NVRAM(txpid5g[1], "txpid5ga1", buf);
+ READ_FROM_NVRAM(txpid5g[2], "txpid5ga2", buf);
+ READ_FROM_NVRAM(txpid5g[3], "txpid5ga3", buf);
+ READ_FROM_NVRAM(txpid5gl[0], "txpid5gla0", buf);
+ READ_FROM_NVRAM(txpid5gl[1], "txpid5gla1", buf);
+ READ_FROM_NVRAM(txpid5gl[2], "txpid5gla2", buf);
+ READ_FROM_NVRAM(txpid5gl[3], "txpid5gla3", buf);
+ READ_FROM_NVRAM(txpid5gh[0], "txpid5gha0", buf);
+ READ_FROM_NVRAM(txpid5gh[1], "txpid5gha1", buf);
+ READ_FROM_NVRAM(txpid5gh[2], "txpid5gha2", buf);
+ READ_FROM_NVRAM(txpid5gh[3], "txpid5gha3", buf);
READ_FROM_NVRAM(rxpo2g, "rxpo2g", buf);
READ_FROM_NVRAM(rxpo5g, "rxpo5g", buf);
READ_FROM_NVRAM(rssisav2g, "rssisav2g", buf);
@@ -120,19 +177,27 @@ static void bcm47xx_fill_sprom(struct ssb_sprom *sprom)
READ_FROM_NVRAM(rssismf5g, "rssismf5g", buf);
READ_FROM_NVRAM(bxa5g, "bxa5g", buf);
READ_FROM_NVRAM(cck2gpo, "cck2gpo", buf);
- READ_FROM_NVRAM(ofdm2gpo, "ofdm2gpo", buf);
- READ_FROM_NVRAM(ofdm5glpo, "ofdm5glpo", buf);
- READ_FROM_NVRAM(ofdm5gpo, "ofdm5gpo", buf);
- READ_FROM_NVRAM(ofdm5ghpo, "ofdm5ghpo", buf);
- if (nvram_getenv("boardflags", buf, sizeof(buf)) >= 0) {
+ sprom->ofdm2gpo = nvram_getu32("ofdm2gpo", buf, sizeof(buf));
+ sprom->ofdm5glpo = nvram_getu32("ofdm5glpo", buf, sizeof(buf));
+ sprom->ofdm5gpo = nvram_getu32("ofdm5gpo", buf, sizeof(buf));
+ sprom->ofdm5ghpo = nvram_getu32("ofdm5ghpo", buf, sizeof(buf));
+
+ READ_FROM_NVRAM(antenna_gain.ghz24.a0, "ag0", buf);
+ READ_FROM_NVRAM(antenna_gain.ghz24.a1, "ag1", buf);
+ READ_FROM_NVRAM(antenna_gain.ghz24.a2, "ag2", buf);
+ READ_FROM_NVRAM(antenna_gain.ghz24.a3, "ag3", buf);
+ memcpy(&sprom->antenna_gain.ghz5, &sprom->antenna_gain.ghz24,
+ sizeof(sprom->antenna_gain.ghz5));
+
+ if (nvram_getprefix(prefix, "boardflags", buf, sizeof(buf)) >= 0) {
boardflags = simple_strtoul(buf, NULL, 0);
if (boardflags) {
sprom->boardflags_lo = (boardflags & 0x0000FFFFU);
sprom->boardflags_hi = (boardflags & 0xFFFF0000U) >> 16;
}
}
- if (nvram_getenv("boardflags2", buf, sizeof(buf)) >= 0) {
+ if (nvram_getprefix(prefix, "boardflags2", buf, sizeof(buf)) >= 0) {
boardflags = simple_strtoul(buf, NULL, 0);
if (boardflags) {
sprom->boardflags2_lo = (boardflags & 0x0000FFFFU);
@@ -141,6 +206,22 @@ static void bcm47xx_fill_sprom(struct ssb_sprom *sprom)
}
}
+int bcm47xx_get_sprom(struct ssb_bus *bus, struct ssb_sprom *out)
+{
+ char prefix[10];
+
+ if (bus->bustype == SSB_BUSTYPE_PCI) {
+ snprintf(prefix, sizeof(prefix), "pci/%u/%u/",
+ bus->host_pci->bus->number + 1,
+ PCI_SLOT(bus->host_pci->devfn));
+ bcm47xx_fill_sprom(out, prefix);
+ return 0;
+ } else {
+ printk(KERN_WARNING "bcm47xx: unable to fill SPROM for given bustype.\n");
+ return -EINVAL;
+ }
+}
+
static int bcm47xx_get_invariants(struct ssb_bus *bus,
struct ssb_init_invariants *iv)
{
@@ -158,7 +239,7 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus,
if (nvram_getenv("boardrev", buf, sizeof(buf)) >= 0)
iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0);
- bcm47xx_fill_sprom(&iv->sprom);
+ bcm47xx_fill_sprom(&iv->sprom, NULL);
if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0)
iv->has_cardbus_slot = !!simple_strtoul(buf, NULL, 10);
@@ -172,6 +253,11 @@ void __init plat_mem_setup(void)
char buf[100];
struct ssb_mipscore *mcore;
+ err = ssb_arch_register_fallback_sprom(&bcm47xx_get_sprom);
+ if (err)
+ printk(KERN_WARNING "bcm47xx: someone else already registered"
+ " a ssb SPROM callback handler (err %d)\n", err);
+
err = ssb_bus_ssbbus_register(&ssb_bcm47xx, SSB_ENUM_BASE,
bcm47xx_get_invariants);
if (err)
diff --git a/arch/mips/bcm63xx/boards/board_bcm963xx.c b/arch/mips/bcm63xx/boards/board_bcm963xx.c
index 8dba8cfb752f..40b223b603be 100644
--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c
+++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
@@ -643,6 +643,17 @@ static struct ssb_sprom bcm63xx_sprom = {
.boardflags_lo = 0x2848,
.boardflags_hi = 0x0000,
};
+
+int bcm63xx_get_fallback_sprom(struct ssb_bus *bus, struct ssb_sprom *out)
+{
+ if (bus->bustype == SSB_BUSTYPE_PCI) {
+ memcpy(out, &bcm63xx_sprom, sizeof(struct ssb_sprom));
+ return 0;
+ } else {
+ printk(KERN_ERR PFX "unable to fill SPROM for given bustype.\n");
+ return -EINVAL;
+ }
+}
#endif
/*
@@ -793,8 +804,9 @@ void __init board_prom_init(void)
if (!board_get_mac_address(bcm63xx_sprom.il0mac)) {
memcpy(bcm63xx_sprom.et0mac, bcm63xx_sprom.il0mac, ETH_ALEN);
memcpy(bcm63xx_sprom.et1mac, bcm63xx_sprom.il0mac, ETH_ALEN);
- if (ssb_arch_set_fallback_sprom(&bcm63xx_sprom) < 0)
- printk(KERN_ERR "failed to register fallback SPROM\n");
+ if (ssb_arch_register_fallback_sprom(
+ &bcm63xx_get_fallback_sprom) < 0)
+ printk(KERN_ERR PFX "failed to register fallback SPROM\n");
}
#endif
}
diff --git a/arch/mips/boot/compressed/uart-alchemy.c b/arch/mips/boot/compressed/uart-alchemy.c
index 1bff22fa089b..eb063e6dead9 100644
--- a/arch/mips/boot/compressed/uart-alchemy.c
+++ b/arch/mips/boot/compressed/uart-alchemy.c
@@ -3,5 +3,5 @@
void putc(char c)
{
/* all current (Jan. 2010) in-kernel boards */
- alchemy_uart_putchar(UART0_PHYS_ADDR, c);
+ alchemy_uart_putchar(AU1000_UART0_PHYS_ADDR, c);
}
diff --git a/arch/mips/cavium-octeon/csrc-octeon.c b/arch/mips/cavium-octeon/csrc-octeon.c
index 26bf71130bf8..29d56afbb02d 100644
--- a/arch/mips/cavium-octeon/csrc-octeon.c
+++ b/arch/mips/cavium-octeon/csrc-octeon.c
@@ -105,8 +105,7 @@ unsigned long long notrace sched_clock(void)
void __init plat_time_init(void)
{
clocksource_mips.rating = 300;
- clocksource_set_clock(&clocksource_mips, octeon_get_clock_rate());
- clocksource_register(&clocksource_mips);
+ clocksource_register_hz(&clocksource_mips, octeon_get_clock_rate());
}
static u64 octeon_udelay_factor;
diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c
index 0707fae3f0ee..2d9028f1474c 100644
--- a/arch/mips/cavium-octeon/setup.c
+++ b/arch/mips/cavium-octeon/setup.c
@@ -288,7 +288,6 @@ void octeon_user_io_init(void)
union octeon_cvmemctl cvmmemctl;
union cvmx_iob_fau_timeout fau_timeout;
union cvmx_pow_nw_tim nm_tim;
- uint64_t cvmctl;
/* Get the current settings for CP0_CVMMEMCTL_REG */
cvmmemctl.u64 = read_c0_cvmmemctl();
@@ -392,12 +391,6 @@ void octeon_user_io_init(void)
CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE,
CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE * 128);
- /* Move the performance counter interrupts to IRQ 6 */
- cvmctl = read_c0_cvmctl();
- cvmctl &= ~(7 << 7);
- cvmctl |= 6 << 7;
- write_c0_cvmctl(cvmctl);
-
/* Set a default for the hardware timeouts */
fau_timeout.u64 = 0;
fau_timeout.s.tout_val = 0xfff;
diff --git a/arch/mips/cavium-octeon/smp.c b/arch/mips/cavium-octeon/smp.c
index ba78b21cc8d0..8b606423bbd7 100644
--- a/arch/mips/cavium-octeon/smp.c
+++ b/arch/mips/cavium-octeon/smp.c
@@ -37,13 +37,15 @@ static irqreturn_t mailbox_interrupt(int irq, void *dev_id)
uint64_t action;
/* Load the mailbox register to figure out what we're supposed to do */
- action = cvmx_read_csr(CVMX_CIU_MBOX_CLRX(coreid));
+ action = cvmx_read_csr(CVMX_CIU_MBOX_CLRX(coreid)) & 0xffff;
/* Clear the mailbox to clear the interrupt */
cvmx_write_csr(CVMX_CIU_MBOX_CLRX(coreid), action);
if (action & SMP_CALL_FUNCTION)
smp_call_function_interrupt();
+ if (action & SMP_RESCHEDULE_YOURSELF)
+ scheduler_ipi();
/* Check if we've been told to flush the icache */
if (action & SMP_ICACHE_FLUSH)
@@ -200,16 +202,15 @@ void octeon_prepare_cpus(unsigned int max_cpus)
if (labi->labi_signature != LABI_SIGNATURE)
panic("The bootloader version on this board is incorrect.");
#endif
-
- cvmx_write_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num()), 0xffffffff);
+ /*
+ * Only the low order mailbox bits are used for IPIs, leave
+ * the other bits alone.
+ */
+ cvmx_write_csr(CVMX_CIU_MBOX_CLRX(cvmx_get_core_num()), 0xffff);
if (request_irq(OCTEON_IRQ_MBOX0, mailbox_interrupt, IRQF_DISABLED,
- "mailbox0", mailbox_interrupt)) {
+ "SMP-IPI", mailbox_interrupt)) {
panic("Cannot request_irq(OCTEON_IRQ_MBOX0)\n");
}
- if (request_irq(OCTEON_IRQ_MBOX1, mailbox_interrupt, IRQF_DISABLED,
- "mailbox1", mailbox_interrupt)) {
- panic("Cannot request_irq(OCTEON_IRQ_MBOX1)\n");
- }
}
/**
diff --git a/arch/mips/configs/bcm47xx_defconfig b/arch/mips/configs/bcm47xx_defconfig
index 22fdf2f0cc23..ad15fb10322b 100644
--- a/arch/mips/configs/bcm47xx_defconfig
+++ b/arch/mips/configs/bcm47xx_defconfig
@@ -16,7 +16,6 @@ CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_AUDIT=y
CONFIG_TINY_RCU=y
CONFIG_CGROUPS=y
-CONFIG_CGROUP_NS=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_RELAY=y
CONFIG_BLK_DEV_INITRD=y
diff --git a/arch/mips/configs/lemote2f_defconfig b/arch/mips/configs/lemote2f_defconfig
index 167c1d07b809..b6acd2f256b6 100644
--- a/arch/mips/configs/lemote2f_defconfig
+++ b/arch/mips/configs/lemote2f_defconfig
@@ -86,8 +86,8 @@ CONFIG_NET_SCHED=y
CONFIG_NET_EMATCH=y
CONFIG_NET_CLS_ACT=y
CONFIG_BT=m
-CONFIG_BT_L2CAP=m
-CONFIG_BT_SCO=m
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
CONFIG_BT_RFCOMM=m
CONFIG_BT_RFCOMM_TTY=y
CONFIG_BT_BNEP=m
@@ -329,7 +329,7 @@ CONFIG_USB_LED=m
CONFIG_USB_GADGET=m
CONFIG_USB_GADGET_M66592=y
CONFIG_MMC=m
-CONFIG_LEDS_CLASS=m
+CONFIG_LEDS_CLASS=y
CONFIG_STAGING=y
# CONFIG_STAGING_EXCLUDE_BUILD is not set
CONFIG_FB_SM7XX=y
diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig
index 7270f3183bda..5527abbb7dea 100644
--- a/arch/mips/configs/malta_defconfig
+++ b/arch/mips/configs/malta_defconfig
@@ -374,7 +374,7 @@ CONFIG_FB_CIRRUS=y
# CONFIG_VGA_CONSOLE is not set
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_HID=m
-CONFIG_LEDS_CLASS=m
+CONFIG_LEDS_CLASS=y
CONFIG_LEDS_TRIGGER_TIMER=m
CONFIG_LEDS_TRIGGER_IDE_DISK=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=m
diff --git a/arch/mips/configs/mtx1_defconfig b/arch/mips/configs/mtx1_defconfig
index a97a42c6b2c8..37862b2ce363 100644
--- a/arch/mips/configs/mtx1_defconfig
+++ b/arch/mips/configs/mtx1_defconfig
@@ -225,8 +225,8 @@ CONFIG_TOSHIBA_FIR=m
CONFIG_VLSI_FIR=m
CONFIG_MCS_FIR=m
CONFIG_BT=m
-CONFIG_BT_L2CAP=m
-CONFIG_BT_SCO=m
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
CONFIG_BT_RFCOMM=m
CONFIG_BT_RFCOMM_TTY=y
CONFIG_BT_BNEP=m
diff --git a/arch/mips/configs/nlm_xlr_defconfig b/arch/mips/configs/nlm_xlr_defconfig
new file mode 100644
index 000000000000..e4b399fdaa61
--- /dev/null
+++ b/arch/mips/configs/nlm_xlr_defconfig
@@ -0,0 +1,574 @@
+CONFIG_NLM_XLR_BOARD=y
+CONFIG_HIGHMEM=y
+CONFIG_KSM=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
+CONFIG_SMP=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_PREEMPT_VOLUNTARY=y
+CONFIG_KEXEC=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_CROSS_COMPILE="mips64-unknown-linux-gnu-"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_AUDIT=y
+CONFIG_NAMESPACES=y
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="usr/dev_file_list usr/rootfs"
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_INITRAMFS_COMPRESSION_GZIP=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EXPERT=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_ELF_CORE is not set
+# CONFIG_PCSPKR_PLATFORM is not set
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_PROFILING=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_BLK_DEV_INTEGRITY=y
+CONFIG_BINFMT_MISC=m
+CONFIG_PM_RUNTIME=y
+CONFIG_PM_DEBUG=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=m
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_NET_IPIP=m
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=m
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_SCALABLE=m
+CONFIG_TCP_CONG_LP=m
+CONFIG_TCP_CONG_VENO=m
+CONFIG_TCP_CONG_YEAH=m
+CONFIG_TCP_CONG_ILLINOIS=m
+CONFIG_TCP_MD5SIG=y
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_IPV6_SIT=m
+CONFIG_IPV6_TUNNEL=m
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_NETLABEL=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NF_CT_NETLINK=m
+CONFIG_NETFILTER_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+CONFIG_NETFILTER_XT_TARGET_SECMARK=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+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=m
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+CONFIG_IP_VS=m
+CONFIG_IP_VS_IPV6=y
+CONFIG_IP_VS_PROTO_TCP=y
+CONFIG_IP_VS_PROTO_UDP=y
+CONFIG_IP_VS_PROTO_ESP=y
+CONFIG_IP_VS_PROTO_AH=y
+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
+CONFIG_IP_VS_FTP=m
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=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_NF_NAT=m
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_SECURITY=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_IP6_NF_SECURITY=m
+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_IP6=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=m
+CONFIG_IP_DCCP=m
+CONFIG_RDS=m
+CONFIG_RDS_TCP=m
+CONFIG_TIPC=m
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+CONFIG_DECNET=m
+CONFIG_LLC2=m
+CONFIG_IPX=m
+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=m
+CONFIG_IEEE802154=m
+CONFIG_NET_SCHED=y
+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=m
+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=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_EMATCH=y
+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=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_NAT=m
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_ACT_SIMP=m
+CONFIG_NET_ACT_SKBEDIT=m
+CONFIG_DCB=y
+CONFIG_NET_PKTGEN=m
+# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_STANDALONE is not set
+CONFIG_CONNECTOR=y
+CONFIG_MTD=m
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_OSD=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=65536
+CONFIG_CDROM_PKTCDVD=y
+CONFIG_MISC_DEVICES=y
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI=y
+CONFIG_SCSI_TGT=m
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+CONFIG_CHR_DEV_OSST=m
+CONFIG_BLK_DEV_SR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=m
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_SPI_ATTRS=m
+CONFIG_SCSI_FC_TGT_ATTRS=y
+CONFIG_SCSI_SAS_LIBSAS=m
+CONFIG_SCSI_SRP_ATTRS=m
+CONFIG_SCSI_SRP_TGT_ATTRS=y
+CONFIG_ISCSI_TCP=m
+CONFIG_LIBFCOE=m
+CONFIG_SCSI_DEBUG=m
+CONFIG_SCSI_DH=y
+CONFIG_SCSI_DH_RDAC=m
+CONFIG_SCSI_DH_HP_SW=m
+CONFIG_SCSI_DH_EMC=m
+CONFIG_SCSI_DH_ALUA=m
+CONFIG_SCSI_OSD_INITIATOR=m
+CONFIG_SCSI_OSD_ULD=m
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_SERPORT=m
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIO_RAW=m
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
+CONFIG_LEGACY_PTY_COUNT=0
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_N_HDLC=m
+# CONFIG_DEVKMEM is not set
+CONFIG_STALDRV=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=48
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_TIMERIOMEM=m
+CONFIG_RAW_DRIVER=m
+# CONFIG_HWMON is not set
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_UIO=y
+CONFIG_UIO_PDRV=m
+CONFIG_UIO_PDRV_GENIRQ=m
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_GFS2_FS=m
+CONFIG_GFS2_FS_LOCKING_DLM=y
+CONFIG_OCFS2_FS=m
+CONFIG_BTRFS_FS=m
+CONFIG_BTRFS_FS_POSIX_ACL=y
+CONFIG_NILFS2_FS=m
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+# CONFIG_PRINT_QUOTA_WARNING is not set
+CONFIG_QFMT_V1=m
+CONFIG_QFMT_V2=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=y
+CONFIG_CUSE=m
+CONFIG_FSCACHE=m
+CONFIG_FSCACHE_STATS=y
+CONFIG_FSCACHE_HISTOGRAM=y
+CONFIG_CACHEFILES=m
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_NTFS_FS=m
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_ADFS_FS=m
+CONFIG_AFFS_FS=m
+CONFIG_ECRYPT_FS=y
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_BEFS_FS=m
+CONFIG_BFS_FS=m
+CONFIG_EFS_FS=m
+CONFIG_CRAMFS=m
+CONFIG_SQUASHFS=m
+CONFIG_VXFS_FS=m
+CONFIG_MINIX_FS=m
+CONFIG_OMFS_FS=m
+CONFIG_HPFS_FS=m
+CONFIG_QNX4FS_FS=m
+CONFIG_ROMFS_FS=m
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+CONFIG_EXOFS_FS=m
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_FSCACHE=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_CIFS=m
+CONFIG_CIFS_WEAK_PW_HASH=y
+CONFIG_CIFS_UPCALL=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+CONFIG_CIFS_DFS_UPCALL=y
+CONFIG_CIFS_EXPERIMENTAL=y
+CONFIG_NCP_FS=m
+CONFIG_NCPFS_PACKET_SIGNING=y
+CONFIG_NCPFS_IOCTL_LOCKING=y
+CONFIG_NCPFS_STRONG=y
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+CONFIG_NCPFS_NLS=y
+CONFIG_NCPFS_EXTRAS=y
+CONFIG_CODA_FS=m
+CONFIG_AFS_FS=m
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_ACORN_PARTITION=y
+CONFIG_ACORN_PARTITION_ICS=y
+CONFIG_ACORN_PARTITION_RISCIX=y
+CONFIG_OSF_PARTITION=y
+CONFIG_AMIGA_PARTITION=y
+CONFIG_ATARI_PARTITION=y
+CONFIG_MAC_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_LDM_PARTITION=y
+CONFIG_SGI_PARTITION=y
+CONFIG_ULTRIX_PARTITION=y
+CONFIG_SUN_PARTITION=y
+CONFIG_KARMA_PARTITION=y
+CONFIG_EFI_PARTITION=y
+CONFIG_SYSV68_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="cp437"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+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_932=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=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=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_PRINTK_TIME=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_UNUSED_SYMBOLS=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_SCHED_TRACER=y
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_KGDB=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_LSM_MMAP_MIN_ADDR=0
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SMACK=y
+CONFIG_SECURITY_TOMOYO=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_CRYPTD=m
+CONFIG_CRYPTO_TEST=m
+CONFIG_CRYPTO_CCM=m
+CONFIG_CRYPTO_GCM=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_XCBC=m
+CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD128=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_RMD256=m
+CONFIG_CRYPTO_RMD320=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_SALSA20=m
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_ZLIB=m
+CONFIG_CRYPTO_LZO=m
+CONFIG_CRC_CCITT=m
+CONFIG_CRC7=m
diff --git a/arch/mips/fw/arc/cmdline.c b/arch/mips/fw/arc/cmdline.c
index 5c8603c85f20..9fdf07e50f1b 100644
--- a/arch/mips/fw/arc/cmdline.c
+++ b/arch/mips/fw/arc/cmdline.c
@@ -5,7 +5,7 @@
*
* cmdline.c: Kernel command line creation using ARCS argc/argv.
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
*/
#include <linux/init.h>
#include <linux/kernel.h>
diff --git a/arch/mips/fw/arc/env.c b/arch/mips/fw/arc/env.c
index 6f5dd42b96e2..1118a26b32ee 100644
--- a/arch/mips/fw/arc/env.c
+++ b/arch/mips/fw/arc/env.c
@@ -5,7 +5,7 @@
*
* env.c: ARCS environment variable routines.
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
*/
#include <linux/init.h>
#include <linux/kernel.h>
diff --git a/arch/mips/fw/arc/identify.c b/arch/mips/fw/arc/identify.c
index 0ce9acf10c39..788060a53dce 100644
--- a/arch/mips/fw/arc/identify.c
+++ b/arch/mips/fw/arc/identify.c
@@ -9,7 +9,7 @@
*
* This code is based on arch/mips/sgi/kernel/system.c, which is
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
*/
#include <linux/init.h>
#include <linux/kernel.h>
diff --git a/arch/mips/fw/arc/init.c b/arch/mips/fw/arc/init.c
index 3ad8788b6eaa..629b24db0d3a 100644
--- a/arch/mips/fw/arc/init.c
+++ b/arch/mips/fw/arc/init.c
@@ -5,7 +5,7 @@
*
* PROM library initialisation code.
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
*/
#include <linux/init.h>
#include <linux/kernel.h>
diff --git a/arch/mips/fw/arc/misc.c b/arch/mips/fw/arc/misc.c
index e527c5fd5a32..29627fbae7ad 100644
--- a/arch/mips/fw/arc/misc.c
+++ b/arch/mips/fw/arc/misc.c
@@ -5,7 +5,7 @@
*
* Miscellaneous ARCS PROM routines.
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
* Copyright (C) 1999 Ralf Baechle (ralf@gnu.org)
* Copyright (C) 1999 Silicon Graphics, Inc.
*/
diff --git a/arch/mips/fw/arc/salone.c b/arch/mips/fw/arc/salone.c
index e6afb64723d0..9b568950d1fd 100644
--- a/arch/mips/fw/arc/salone.c
+++ b/arch/mips/fw/arc/salone.c
@@ -2,7 +2,7 @@
* Routines to load into memory and execute stand-along program images using
* ARCS PROM firmware.
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
*/
#include <linux/init.h>
#include <asm/sgialib.h>
diff --git a/arch/mips/fw/arc/time.c b/arch/mips/fw/arc/time.c
index 42138c837d48..190cdb50b895 100644
--- a/arch/mips/fw/arc/time.c
+++ b/arch/mips/fw/arc/time.c
@@ -5,7 +5,7 @@
*
* Extracting time information from ARCS prom.
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
*/
#include <linux/init.h>
diff --git a/arch/mips/fw/arc/tree.c b/arch/mips/fw/arc/tree.c
index d68e5a59c1f6..924a37dc2569 100644
--- a/arch/mips/fw/arc/tree.c
+++ b/arch/mips/fw/arc/tree.c
@@ -5,7 +5,7 @@
*
* PROM component device tree code.
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
* Copyright (C) 1999 Ralf Baechle (ralf@gnu.org)
* Copyright (C) 1999 Silicon Graphics, Inc.
*/
diff --git a/arch/mips/include/asm/asmmacro-32.h b/arch/mips/include/asm/asmmacro-32.h
index 5de3963f511e..2413afe21b33 100644
--- a/arch/mips/include/asm/asmmacro-32.h
+++ b/arch/mips/include/asm/asmmacro-32.h
@@ -1,7 +1,7 @@
/*
* asmmacro.h: Assembler macros to make things easier to read.
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
* Copyright (C) 1998, 1999, 2003 Ralf Baechle
*/
#ifndef _ASM_ASMMACRO_32_H
diff --git a/arch/mips/include/asm/asmmacro-64.h b/arch/mips/include/asm/asmmacro-64.h
index 225feefcb25d..08a527dfe4a3 100644
--- a/arch/mips/include/asm/asmmacro-64.h
+++ b/arch/mips/include/asm/asmmacro-64.h
@@ -1,7 +1,7 @@
/*
* asmmacro.h: Assembler macros to make things easier to read.
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
* Copyright (C) 1998, 1999 Ralf Baechle
* Copyright (C) 1999 Silicon Graphics, Inc.
*/
diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h
index 86877539c6e8..5f95a4bfc735 100644
--- a/arch/mips/include/asm/cpu.h
+++ b/arch/mips/include/asm/cpu.h
@@ -2,7 +2,7 @@
* cpu.h: Values of the PRId register used to match up
* various MIPS cpu types.
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
* Copyright (C) 2004 Maciej W. Rozycki
*/
#ifndef _ASM_CPU_H
@@ -33,6 +33,7 @@
#define PRID_COMP_TOSHIBA 0x070000
#define PRID_COMP_LSI 0x080000
#define PRID_COMP_LEXRA 0x0b0000
+#define PRID_COMP_NETLOGIC 0x0c0000
#define PRID_COMP_CAVIUM 0x0d0000
#define PRID_COMP_INGENIC 0xd00000
@@ -142,6 +143,31 @@
#define PRID_IMP_JZRISC 0x0200
/*
+ * These are the PRID's for when 23:16 == PRID_COMP_NETLOGIC
+ */
+#define PRID_IMP_NETLOGIC_XLR732 0x0000
+#define PRID_IMP_NETLOGIC_XLR716 0x0200
+#define PRID_IMP_NETLOGIC_XLR532 0x0900
+#define PRID_IMP_NETLOGIC_XLR308 0x0600
+#define PRID_IMP_NETLOGIC_XLR532C 0x0800
+#define PRID_IMP_NETLOGIC_XLR516C 0x0a00
+#define PRID_IMP_NETLOGIC_XLR508C 0x0b00
+#define PRID_IMP_NETLOGIC_XLR308C 0x0f00
+#define PRID_IMP_NETLOGIC_XLS608 0x8000
+#define PRID_IMP_NETLOGIC_XLS408 0x8800
+#define PRID_IMP_NETLOGIC_XLS404 0x8c00
+#define PRID_IMP_NETLOGIC_XLS208 0x8e00
+#define PRID_IMP_NETLOGIC_XLS204 0x8f00
+#define PRID_IMP_NETLOGIC_XLS108 0xce00
+#define PRID_IMP_NETLOGIC_XLS104 0xcf00
+#define PRID_IMP_NETLOGIC_XLS616B 0x4000
+#define PRID_IMP_NETLOGIC_XLS608B 0x4a00
+#define PRID_IMP_NETLOGIC_XLS416B 0x4400
+#define PRID_IMP_NETLOGIC_XLS412B 0x4c00
+#define PRID_IMP_NETLOGIC_XLS408B 0x4e00
+#define PRID_IMP_NETLOGIC_XLS404B 0x4f00
+
+/*
* Definitions for 7:0 on legacy processors
*/
@@ -234,6 +260,7 @@ enum cpu_type_enum {
*/
CPU_5KC, CPU_20KC, CPU_25KF, CPU_SB1, CPU_SB1A, CPU_LOONGSON2,
CPU_CAVIUM_OCTEON, CPU_CAVIUM_OCTEON_PLUS, CPU_CAVIUM_OCTEON2,
+ CPU_XLR,
CPU_LAST
};
diff --git a/arch/mips/include/asm/i8253.h b/arch/mips/include/asm/i8253.h
index 48bb82372994..9ad011366f73 100644
--- a/arch/mips/include/asm/i8253.h
+++ b/arch/mips/include/asm/i8253.h
@@ -12,8 +12,13 @@
#define PIT_CH0 0x40
#define PIT_CH2 0x42
+#define PIT_LATCH LATCH
+
extern raw_spinlock_t i8253_lock;
extern void setup_pit_timer(void);
+#define inb_pit inb_p
+#define outb_pit outb_p
+
#endif /* __ASM_I8253_H */
diff --git a/arch/mips/include/asm/jump_label.h b/arch/mips/include/asm/jump_label.h
index 7622ccf75076..1881b316ca45 100644
--- a/arch/mips/include/asm/jump_label.h
+++ b/arch/mips/include/asm/jump_label.h
@@ -20,16 +20,18 @@
#define WORD_INSN ".word"
#endif
-#define JUMP_LABEL(key, label) \
- do { \
- asm goto("1:\tnop\n\t" \
- "nop\n\t" \
- ".pushsection __jump_table, \"a\"\n\t" \
- WORD_INSN " 1b, %l[" #label "], %0\n\t" \
- ".popsection\n\t" \
- : : "i" (key) : : label); \
- } while (0)
-
+static __always_inline bool arch_static_branch(struct jump_label_key *key)
+{
+ asm goto("1:\tnop\n\t"
+ "nop\n\t"
+ ".pushsection __jump_table, \"aw\"\n\t"
+ WORD_INSN " 1b, %l[l_yes], %0\n\t"
+ ".popsection\n\t"
+ : : "i" (key) : : l_yes);
+ return false;
+l_yes:
+ return true;
+}
#endif /* __KERNEL__ */
diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h
index a6976619160a..f260ebed713b 100644
--- a/arch/mips/include/asm/mach-au1x00/au1000.h
+++ b/arch/mips/include/asm/mach-au1x00/au1000.h
@@ -161,6 +161,45 @@ static inline int alchemy_get_cputype(void)
return ALCHEMY_CPU_UNKNOWN;
}
+/* return number of uarts on a given cputype */
+static inline int alchemy_get_uarts(int type)
+{
+ switch (type) {
+ case ALCHEMY_CPU_AU1000:
+ return 4;
+ case ALCHEMY_CPU_AU1500:
+ case ALCHEMY_CPU_AU1200:
+ return 2;
+ case ALCHEMY_CPU_AU1100:
+ case ALCHEMY_CPU_AU1550:
+ return 3;
+ }
+ return 0;
+}
+
+/* enable an UART block if it isn't already */
+static inline void alchemy_uart_enable(u32 uart_phys)
+{
+ void __iomem *addr = (void __iomem *)KSEG1ADDR(uart_phys);
+
+ /* reset, enable clock, deassert reset */
+ if ((__raw_readl(addr + 0x100) & 3) != 3) {
+ __raw_writel(0, addr + 0x100);
+ wmb();
+ __raw_writel(1, addr + 0x100);
+ wmb();
+ }
+ __raw_writel(3, addr + 0x100);
+ wmb();
+}
+
+static inline void alchemy_uart_disable(u32 uart_phys)
+{
+ void __iomem *addr = (void __iomem *)KSEG1ADDR(uart_phys);
+ __raw_writel(0, addr + 0x100); /* UART_MOD_CNTRL */
+ wmb();
+}
+
static inline void alchemy_uart_putchar(u32 uart_phys, u8 c)
{
void __iomem *base = (void __iomem *)KSEG1ADDR(uart_phys);
@@ -180,6 +219,20 @@ static inline void alchemy_uart_putchar(u32 uart_phys, u8 c)
wmb();
}
+/* return number of ethernet MACs on a given cputype */
+static inline int alchemy_get_macs(int type)
+{
+ switch (type) {
+ case ALCHEMY_CPU_AU1000:
+ case ALCHEMY_CPU_AU1500:
+ case ALCHEMY_CPU_AU1550:
+ return 2;
+ case ALCHEMY_CPU_AU1100:
+ return 1;
+ }
+ return 0;
+}
+
/* arch/mips/au1000/common/clocks.c */
extern void set_au1x00_speed(unsigned int new_freq);
extern unsigned int get_au1x00_speed(void);
@@ -630,38 +683,42 @@ enum soc_au1200_ints {
/*
* Physical base addresses for integrated peripherals
+ * 0..au1000 1..au1500 2..au1100 3..au1550 4..au1200
*/
+#define AU1000_AC97_PHYS_ADDR 0x10000000 /* 012 */
+#define AU1000_USBD_PHYS_ADDR 0x10200000 /* 0123 */
+#define AU1000_IC0_PHYS_ADDR 0x10400000 /* 01234 */
+#define AU1000_MAC0_PHYS_ADDR 0x10500000 /* 023 */
+#define AU1000_MAC1_PHYS_ADDR 0x10510000 /* 023 */
+#define AU1000_MACEN_PHYS_ADDR 0x10520000 /* 023 */
+#define AU1100_SD0_PHYS_ADDR 0x10600000 /* 24 */
+#define AU1100_SD1_PHYS_ADDR 0x10680000 /* 24 */
+#define AU1000_I2S_PHYS_ADDR 0x11000000 /* 02 */
+#define AU1500_MAC0_PHYS_ADDR 0x11500000 /* 1 */
+#define AU1500_MAC1_PHYS_ADDR 0x11510000 /* 1 */
+#define AU1500_MACEN_PHYS_ADDR 0x11520000 /* 1 */
+#define AU1000_UART0_PHYS_ADDR 0x11100000 /* 01234 */
+#define AU1000_UART1_PHYS_ADDR 0x11200000 /* 0234 */
+#define AU1000_UART2_PHYS_ADDR 0x11300000 /* 0 */
+#define AU1000_UART3_PHYS_ADDR 0x11400000 /* 0123 */
+#define AU1500_GPIO2_PHYS_ADDR 0x11700000 /* 1234 */
+#define AU1000_IC1_PHYS_ADDR 0x11800000 /* 01234 */
+#define AU1000_SYS_PHYS_ADDR 0x11900000 /* 01234 */
+#define AU1000_DMA_PHYS_ADDR 0x14002000 /* 012 */
+#define AU1550_DBDMA_PHYS_ADDR 0x14002000 /* 34 */
+#define AU1550_DBDMA_CONF_PHYS_ADDR 0x14003000 /* 34 */
+#define AU1000_MACDMA0_PHYS_ADDR 0x14004000 /* 0123 */
+#define AU1000_MACDMA1_PHYS_ADDR 0x14004200 /* 0123 */
+
+
#ifdef CONFIG_SOC_AU1000
#define MEM_PHYS_ADDR 0x14000000
#define STATIC_MEM_PHYS_ADDR 0x14001000
-#define DMA0_PHYS_ADDR 0x14002000
-#define DMA1_PHYS_ADDR 0x14002100
-#define DMA2_PHYS_ADDR 0x14002200
-#define DMA3_PHYS_ADDR 0x14002300
-#define DMA4_PHYS_ADDR 0x14002400
-#define DMA5_PHYS_ADDR 0x14002500
-#define DMA6_PHYS_ADDR 0x14002600
-#define DMA7_PHYS_ADDR 0x14002700
-#define IC0_PHYS_ADDR 0x10400000
-#define IC1_PHYS_ADDR 0x11800000
-#define AC97_PHYS_ADDR 0x10000000
#define USBH_PHYS_ADDR 0x10100000
-#define USBD_PHYS_ADDR 0x10200000
#define IRDA_PHYS_ADDR 0x10300000
-#define MAC0_PHYS_ADDR 0x10500000
-#define MAC1_PHYS_ADDR 0x10510000
-#define MACEN_PHYS_ADDR 0x10520000
-#define MACDMA0_PHYS_ADDR 0x14004000
-#define MACDMA1_PHYS_ADDR 0x14004200
-#define I2S_PHYS_ADDR 0x11000000
-#define UART0_PHYS_ADDR 0x11100000
-#define UART1_PHYS_ADDR 0x11200000
-#define UART2_PHYS_ADDR 0x11300000
-#define UART3_PHYS_ADDR 0x11400000
#define SSI0_PHYS_ADDR 0x11600000
#define SSI1_PHYS_ADDR 0x11680000
-#define SYS_PHYS_ADDR 0x11900000
#define PCMCIA_IO_PHYS_ADDR 0xF00000000ULL
#define PCMCIA_ATTR_PHYS_ADDR 0xF40000000ULL
#define PCMCIA_MEM_PHYS_ADDR 0xF80000000ULL
@@ -672,30 +729,8 @@ enum soc_au1200_ints {
#ifdef CONFIG_SOC_AU1500
#define MEM_PHYS_ADDR 0x14000000
#define STATIC_MEM_PHYS_ADDR 0x14001000
-#define DMA0_PHYS_ADDR 0x14002000
-#define DMA1_PHYS_ADDR 0x14002100
-#define DMA2_PHYS_ADDR 0x14002200
-#define DMA3_PHYS_ADDR 0x14002300
-#define DMA4_PHYS_ADDR 0x14002400
-#define DMA5_PHYS_ADDR 0x14002500
-#define DMA6_PHYS_ADDR 0x14002600
-#define DMA7_PHYS_ADDR 0x14002700
-#define IC0_PHYS_ADDR 0x10400000
-#define IC1_PHYS_ADDR 0x11800000
-#define AC97_PHYS_ADDR 0x10000000
#define USBH_PHYS_ADDR 0x10100000
-#define USBD_PHYS_ADDR 0x10200000
#define PCI_PHYS_ADDR 0x14005000
-#define MAC0_PHYS_ADDR 0x11500000
-#define MAC1_PHYS_ADDR 0x11510000
-#define MACEN_PHYS_ADDR 0x11520000
-#define MACDMA0_PHYS_ADDR 0x14004000
-#define MACDMA1_PHYS_ADDR 0x14004200
-#define I2S_PHYS_ADDR 0x11000000
-#define UART0_PHYS_ADDR 0x11100000
-#define UART3_PHYS_ADDR 0x11400000
-#define GPIO2_PHYS_ADDR 0x11700000
-#define SYS_PHYS_ADDR 0x11900000
#define PCI_MEM_PHYS_ADDR 0x400000000ULL
#define PCI_IO_PHYS_ADDR 0x500000000ULL
#define PCI_CONFIG0_PHYS_ADDR 0x600000000ULL
@@ -710,34 +745,10 @@ enum soc_au1200_ints {
#ifdef CONFIG_SOC_AU1100
#define MEM_PHYS_ADDR 0x14000000
#define STATIC_MEM_PHYS_ADDR 0x14001000
-#define DMA0_PHYS_ADDR 0x14002000
-#define DMA1_PHYS_ADDR 0x14002100
-#define DMA2_PHYS_ADDR 0x14002200
-#define DMA3_PHYS_ADDR 0x14002300
-#define DMA4_PHYS_ADDR 0x14002400
-#define DMA5_PHYS_ADDR 0x14002500
-#define DMA6_PHYS_ADDR 0x14002600
-#define DMA7_PHYS_ADDR 0x14002700
-#define IC0_PHYS_ADDR 0x10400000
-#define SD0_PHYS_ADDR 0x10600000
-#define SD1_PHYS_ADDR 0x10680000
-#define IC1_PHYS_ADDR 0x11800000
-#define AC97_PHYS_ADDR 0x10000000
#define USBH_PHYS_ADDR 0x10100000
-#define USBD_PHYS_ADDR 0x10200000
#define IRDA_PHYS_ADDR 0x10300000
-#define MAC0_PHYS_ADDR 0x10500000
-#define MACEN_PHYS_ADDR 0x10520000
-#define MACDMA0_PHYS_ADDR 0x14004000
-#define MACDMA1_PHYS_ADDR 0x14004200
-#define I2S_PHYS_ADDR 0x11000000
-#define UART0_PHYS_ADDR 0x11100000
-#define UART1_PHYS_ADDR 0x11200000
-#define UART3_PHYS_ADDR 0x11400000
#define SSI0_PHYS_ADDR 0x11600000
#define SSI1_PHYS_ADDR 0x11680000
-#define GPIO2_PHYS_ADDR 0x11700000
-#define SYS_PHYS_ADDR 0x11900000
#define LCD_PHYS_ADDR 0x15000000
#define PCMCIA_IO_PHYS_ADDR 0xF00000000ULL
#define PCMCIA_ATTR_PHYS_ADDR 0xF40000000ULL
@@ -749,22 +760,8 @@ enum soc_au1200_ints {
#ifdef CONFIG_SOC_AU1550
#define MEM_PHYS_ADDR 0x14000000
#define STATIC_MEM_PHYS_ADDR 0x14001000
-#define IC0_PHYS_ADDR 0x10400000
-#define IC1_PHYS_ADDR 0x11800000
#define USBH_PHYS_ADDR 0x14020000
-#define USBD_PHYS_ADDR 0x10200000
#define PCI_PHYS_ADDR 0x14005000
-#define MAC0_PHYS_ADDR 0x10500000
-#define MAC1_PHYS_ADDR 0x10510000
-#define MACEN_PHYS_ADDR 0x10520000
-#define MACDMA0_PHYS_ADDR 0x14004000
-#define MACDMA1_PHYS_ADDR 0x14004200
-#define UART0_PHYS_ADDR 0x11100000
-#define UART1_PHYS_ADDR 0x11200000
-#define UART3_PHYS_ADDR 0x11400000
-#define GPIO2_PHYS_ADDR 0x11700000
-#define SYS_PHYS_ADDR 0x11900000
-#define DDMA_PHYS_ADDR 0x14002000
#define PE_PHYS_ADDR 0x14008000
#define PSC0_PHYS_ADDR 0x11A00000
#define PSC1_PHYS_ADDR 0x11B00000
@@ -786,19 +783,10 @@ enum soc_au1200_ints {
#define STATIC_MEM_PHYS_ADDR 0x14001000
#define AES_PHYS_ADDR 0x10300000
#define CIM_PHYS_ADDR 0x14004000
-#define IC0_PHYS_ADDR 0x10400000
-#define IC1_PHYS_ADDR 0x11800000
#define USBM_PHYS_ADDR 0x14020000
#define USBH_PHYS_ADDR 0x14020100
-#define UART0_PHYS_ADDR 0x11100000
-#define UART1_PHYS_ADDR 0x11200000
-#define GPIO2_PHYS_ADDR 0x11700000
-#define SYS_PHYS_ADDR 0x11900000
-#define DDMA_PHYS_ADDR 0x14002000
#define PSC0_PHYS_ADDR 0x11A00000
#define PSC1_PHYS_ADDR 0x11B00000
-#define SD0_PHYS_ADDR 0x10600000
-#define SD1_PHYS_ADDR 0x10680000
#define LCD_PHYS_ADDR 0x15000000
#define SWCNT_PHYS_ADDR 0x1110010C
#define MAEFE_PHYS_ADDR 0x14012000
@@ -835,183 +823,43 @@ enum soc_au1200_ints {
#endif
-/* Interrupt Controller register offsets */
-#define IC_CFG0RD 0x40
-#define IC_CFG0SET 0x40
-#define IC_CFG0CLR 0x44
-#define IC_CFG1RD 0x48
-#define IC_CFG1SET 0x48
-#define IC_CFG1CLR 0x4C
-#define IC_CFG2RD 0x50
-#define IC_CFG2SET 0x50
-#define IC_CFG2CLR 0x54
-#define IC_REQ0INT 0x54
-#define IC_SRCRD 0x58
-#define IC_SRCSET 0x58
-#define IC_SRCCLR 0x5C
-#define IC_REQ1INT 0x5C
-#define IC_ASSIGNRD 0x60
-#define IC_ASSIGNSET 0x60
-#define IC_ASSIGNCLR 0x64
-#define IC_WAKERD 0x68
-#define IC_WAKESET 0x68
-#define IC_WAKECLR 0x6C
-#define IC_MASKRD 0x70
-#define IC_MASKSET 0x70
-#define IC_MASKCLR 0x74
-#define IC_RISINGRD 0x78
-#define IC_RISINGCLR 0x78
-#define IC_FALLINGRD 0x7C
-#define IC_FALLINGCLR 0x7C
-#define IC_TESTBIT 0x80
-
-
-/* Interrupt Controller 0 */
-#define IC0_CFG0RD 0xB0400040
-#define IC0_CFG0SET 0xB0400040
-#define IC0_CFG0CLR 0xB0400044
-
-#define IC0_CFG1RD 0xB0400048
-#define IC0_CFG1SET 0xB0400048
-#define IC0_CFG1CLR 0xB040004C
-
-#define IC0_CFG2RD 0xB0400050
-#define IC0_CFG2SET 0xB0400050
-#define IC0_CFG2CLR 0xB0400054
-
-#define IC0_REQ0INT 0xB0400054
-#define IC0_SRCRD 0xB0400058
-#define IC0_SRCSET 0xB0400058
-#define IC0_SRCCLR 0xB040005C
-#define IC0_REQ1INT 0xB040005C
-
-#define IC0_ASSIGNRD 0xB0400060
-#define IC0_ASSIGNSET 0xB0400060
-#define IC0_ASSIGNCLR 0xB0400064
-
-#define IC0_WAKERD 0xB0400068
-#define IC0_WAKESET 0xB0400068
-#define IC0_WAKECLR 0xB040006C
-
-#define IC0_MASKRD 0xB0400070
-#define IC0_MASKSET 0xB0400070
-#define IC0_MASKCLR 0xB0400074
-
-#define IC0_RISINGRD 0xB0400078
-#define IC0_RISINGCLR 0xB0400078
-#define IC0_FALLINGRD 0xB040007C
-#define IC0_FALLINGCLR 0xB040007C
-
-#define IC0_TESTBIT 0xB0400080
-
-/* Interrupt Controller 1 */
-#define IC1_CFG0RD 0xB1800040
-#define IC1_CFG0SET 0xB1800040
-#define IC1_CFG0CLR 0xB1800044
-
-#define IC1_CFG1RD 0xB1800048
-#define IC1_CFG1SET 0xB1800048
-#define IC1_CFG1CLR 0xB180004C
-
-#define IC1_CFG2RD 0xB1800050
-#define IC1_CFG2SET 0xB1800050
-#define IC1_CFG2CLR 0xB1800054
-
-#define IC1_REQ0INT 0xB1800054
-#define IC1_SRCRD 0xB1800058
-#define IC1_SRCSET 0xB1800058
-#define IC1_SRCCLR 0xB180005C
-#define IC1_REQ1INT 0xB180005C
-
-#define IC1_ASSIGNRD 0xB1800060
-#define IC1_ASSIGNSET 0xB1800060
-#define IC1_ASSIGNCLR 0xB1800064
-
-#define IC1_WAKERD 0xB1800068
-#define IC1_WAKESET 0xB1800068
-#define IC1_WAKECLR 0xB180006C
-
-#define IC1_MASKRD 0xB1800070
-#define IC1_MASKSET 0xB1800070
-#define IC1_MASKCLR 0xB1800074
-
-#define IC1_RISINGRD 0xB1800078
-#define IC1_RISINGCLR 0xB1800078
-#define IC1_FALLINGRD 0xB180007C
-#define IC1_FALLINGCLR 0xB180007C
-
-#define IC1_TESTBIT 0xB1800080
/* Au1000 */
#ifdef CONFIG_SOC_AU1000
-#define UART0_ADDR 0xB1100000
-#define UART3_ADDR 0xB1400000
-
#define USB_OHCI_BASE 0x10100000 /* phys addr for ioremap */
#define USB_HOST_CONFIG 0xB017FFFC
#define FOR_PLATFORM_C_USB_HOST_INT AU1000_USB_HOST_INT
-
-#define AU1000_ETH0_BASE 0xB0500000
-#define AU1000_ETH1_BASE 0xB0510000
-#define AU1000_MAC0_ENABLE 0xB0520000
-#define AU1000_MAC1_ENABLE 0xB0520004
-#define NUM_ETH_INTERFACES 2
#endif /* CONFIG_SOC_AU1000 */
/* Au1500 */
#ifdef CONFIG_SOC_AU1500
-#define UART0_ADDR 0xB1100000
-#define UART3_ADDR 0xB1400000
-
#define USB_OHCI_BASE 0x10100000 /* phys addr for ioremap */
#define USB_HOST_CONFIG 0xB017fffc
#define FOR_PLATFORM_C_USB_HOST_INT AU1500_USB_HOST_INT
-
-#define AU1500_ETH0_BASE 0xB1500000
-#define AU1500_ETH1_BASE 0xB1510000
-#define AU1500_MAC0_ENABLE 0xB1520000
-#define AU1500_MAC1_ENABLE 0xB1520004
-#define NUM_ETH_INTERFACES 2
#endif /* CONFIG_SOC_AU1500 */
/* Au1100 */
#ifdef CONFIG_SOC_AU1100
-#define UART0_ADDR 0xB1100000
-#define UART3_ADDR 0xB1400000
-
#define USB_OHCI_BASE 0x10100000 /* phys addr for ioremap */
#define USB_HOST_CONFIG 0xB017FFFC
#define FOR_PLATFORM_C_USB_HOST_INT AU1100_USB_HOST_INT
-
-#define AU1100_ETH0_BASE 0xB0500000
-#define AU1100_MAC0_ENABLE 0xB0520000
-#define NUM_ETH_INTERFACES 1
#endif /* CONFIG_SOC_AU1100 */
#ifdef CONFIG_SOC_AU1550
-#define UART0_ADDR 0xB1100000
#define USB_OHCI_BASE 0x14020000 /* phys addr for ioremap */
#define USB_OHCI_LEN 0x00060000
#define USB_HOST_CONFIG 0xB4027ffc
#define FOR_PLATFORM_C_USB_HOST_INT AU1550_USB_HOST_INT
-
-#define AU1550_ETH0_BASE 0xB0500000
-#define AU1550_ETH1_BASE 0xB0510000
-#define AU1550_MAC0_ENABLE 0xB0520000
-#define AU1550_MAC1_ENABLE 0xB0520004
-#define NUM_ETH_INTERFACES 2
#endif /* CONFIG_SOC_AU1550 */
#ifdef CONFIG_SOC_AU1200
-#define UART0_ADDR 0xB1100000
-
#define USB_UOC_BASE 0x14020020
#define USB_UOC_LEN 0x20
#define USB_OHCI_BASE 0x14020100
@@ -1504,22 +1352,6 @@ enum soc_au1200_ints {
#define SYS_PINFUNC_S1B (1 << 2)
#endif
-#define SYS_TRIOUTRD 0xB1900100
-#define SYS_TRIOUTCLR 0xB1900100
-#define SYS_OUTPUTRD 0xB1900108
-#define SYS_OUTPUTSET 0xB1900108
-#define SYS_OUTPUTCLR 0xB190010C
-#define SYS_PINSTATERD 0xB1900110
-#define SYS_PININPUTEN 0xB1900110
-
-/* GPIO2, Au1500, Au1550 only */
-#define GPIO2_BASE 0xB1700000
-#define GPIO2_DIR (GPIO2_BASE + 0)
-#define GPIO2_OUTPUT (GPIO2_BASE + 8)
-#define GPIO2_PINSTATE (GPIO2_BASE + 0xC)
-#define GPIO2_INTENABLE (GPIO2_BASE + 0x10)
-#define GPIO2_ENABLE (GPIO2_BASE + 0x14)
-
/* Power Management */
#define SYS_SCRATCH0 0xB1900018
#define SYS_SCRATCH1 0xB190001C
@@ -1635,12 +1467,6 @@ enum soc_au1200_ints {
# define AC97C_RS (1 << 1)
# define AC97C_CE (1 << 0)
-/* Secure Digital (SD) Controller */
-#define SD0_XMIT_FIFO 0xB0600000
-#define SD0_RECV_FIFO 0xB0600004
-#define SD1_XMIT_FIFO 0xB0680000
-#define SD1_RECV_FIFO 0xB0680004
-
#if defined(CONFIG_SOC_AU1500) || defined(CONFIG_SOC_AU1550)
/* Au1500 PCI Controller */
#define Au1500_CFG_BASE 0xB4005000 /* virtual, KSEG1 addr */
diff --git a/arch/mips/include/asm/mach-au1x00/au1000_dma.h b/arch/mips/include/asm/mach-au1x00/au1000_dma.h
index c333b4e1cd44..59f5b55b2200 100644
--- a/arch/mips/include/asm/mach-au1x00/au1000_dma.h
+++ b/arch/mips/include/asm/mach-au1x00/au1000_dma.h
@@ -37,10 +37,6 @@
#define NUM_AU1000_DMA_CHANNELS 8
-/* DMA Channel Base Addresses */
-#define DMA_CHANNEL_BASE 0xB4002000
-#define DMA_CHANNEL_LEN 0x00000100
-
/* DMA Channel Register Offsets */
#define DMA_MODE_SET 0x00000000
#define DMA_MODE_READ DMA_MODE_SET
diff --git a/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h b/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h
index c8a553a36ba4..2fdacfe85e23 100644
--- a/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h
+++ b/arch/mips/include/asm/mach-au1x00/au1xxx_dbdma.h
@@ -37,14 +37,6 @@
#ifndef _LANGUAGE_ASSEMBLY
-/*
- * The DMA base addresses.
- * The channels are every 256 bytes (0x0100) from the channel 0 base.
- * Interrupt status/enable is bits 15:0 for channels 15 to zero.
- */
-#define DDMA_GLOBAL_BASE 0xb4003000
-#define DDMA_CHANNEL_BASE 0xb4002000
-
typedef volatile struct dbdma_global {
u32 ddma_config;
u32 ddma_intstat;
diff --git a/arch/mips/include/asm/mach-au1x00/gpio-au1000.h b/arch/mips/include/asm/mach-au1x00/gpio-au1000.h
index 62d2f136d941..1f41a522906d 100644
--- a/arch/mips/include/asm/mach-au1x00/gpio-au1000.h
+++ b/arch/mips/include/asm/mach-au1x00/gpio-au1000.h
@@ -24,6 +24,23 @@
#define MAKE_IRQ(intc, off) (AU1000_INTC##intc##_INT_BASE + (off))
+/* GPIO1 registers within SYS_ area */
+#define SYS_TRIOUTRD 0x100
+#define SYS_TRIOUTCLR 0x100
+#define SYS_OUTPUTRD 0x108
+#define SYS_OUTPUTSET 0x108
+#define SYS_OUTPUTCLR 0x10C
+#define SYS_PINSTATERD 0x110
+#define SYS_PININPUTEN 0x110
+
+/* register offsets within GPIO2 block */
+#define GPIO2_DIR 0x00
+#define GPIO2_OUTPUT 0x08
+#define GPIO2_PINSTATE 0x0C
+#define GPIO2_INTENABLE 0x10
+#define GPIO2_ENABLE 0x14
+
+struct gpio;
static inline int au1000_gpio1_to_irq(int gpio)
{
@@ -200,23 +217,26 @@ static inline int au1200_irq_to_gpio(int irq)
*/
static inline void alchemy_gpio1_set_value(int gpio, int v)
{
+ void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_SYS_PHYS_ADDR);
unsigned long mask = 1 << (gpio - ALCHEMY_GPIO1_BASE);
unsigned long r = v ? SYS_OUTPUTSET : SYS_OUTPUTCLR;
- au_writel(mask, r);
- au_sync();
+ __raw_writel(mask, base + r);
+ wmb();
}
static inline int alchemy_gpio1_get_value(int gpio)
{
+ void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_SYS_PHYS_ADDR);
unsigned long mask = 1 << (gpio - ALCHEMY_GPIO1_BASE);
- return au_readl(SYS_PINSTATERD) & mask;
+ return __raw_readl(base + SYS_PINSTATERD) & mask;
}
static inline int alchemy_gpio1_direction_input(int gpio)
{
+ void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_SYS_PHYS_ADDR);
unsigned long mask = 1 << (gpio - ALCHEMY_GPIO1_BASE);
- au_writel(mask, SYS_TRIOUTCLR);
- au_sync();
+ __raw_writel(mask, base + SYS_TRIOUTCLR);
+ wmb();
return 0;
}
@@ -257,27 +277,31 @@ static inline int alchemy_gpio1_to_irq(int gpio)
*/
static inline void __alchemy_gpio2_mod_dir(int gpio, int to_out)
{
+ void __iomem *base = (void __iomem *)KSEG1ADDR(AU1500_GPIO2_PHYS_ADDR);
unsigned long mask = 1 << (gpio - ALCHEMY_GPIO2_BASE);
- unsigned long d = au_readl(GPIO2_DIR);
+ unsigned long d = __raw_readl(base + GPIO2_DIR);
+
if (to_out)
d |= mask;
else
d &= ~mask;
- au_writel(d, GPIO2_DIR);
- au_sync();
+ __raw_writel(d, base + GPIO2_DIR);
+ wmb();
}
static inline void alchemy_gpio2_set_value(int gpio, int v)
{
+ void __iomem *base = (void __iomem *)KSEG1ADDR(AU1500_GPIO2_PHYS_ADDR);
unsigned long mask;
mask = ((v) ? 0x00010001 : 0x00010000) << (gpio - ALCHEMY_GPIO2_BASE);
- au_writel(mask, GPIO2_OUTPUT);
- au_sync();
+ __raw_writel(mask, base + GPIO2_OUTPUT);
+ wmb();
}
static inline int alchemy_gpio2_get_value(int gpio)
{
- return au_readl(GPIO2_PINSTATE) & (1 << (gpio - ALCHEMY_GPIO2_BASE));
+ void __iomem *base = (void __iomem *)KSEG1ADDR(AU1500_GPIO2_PHYS_ADDR);
+ return __raw_readl(base + GPIO2_PINSTATE) & (1 << (gpio - ALCHEMY_GPIO2_BASE));
}
static inline int alchemy_gpio2_direction_input(int gpio)
@@ -329,21 +353,23 @@ static inline int alchemy_gpio2_to_irq(int gpio)
*/
static inline void alchemy_gpio1_input_enable(void)
{
- au_writel(0, SYS_PININPUTEN); /* the write op is key */
- au_sync();
+ void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_SYS_PHYS_ADDR);
+ __raw_writel(0, base + SYS_PININPUTEN); /* the write op is key */
+ wmb();
}
/* GPIO2 shared interrupts and control */
static inline void __alchemy_gpio2_mod_int(int gpio2, int en)
{
- unsigned long r = au_readl(GPIO2_INTENABLE);
+ void __iomem *base = (void __iomem *)KSEG1ADDR(AU1500_GPIO2_PHYS_ADDR);
+ unsigned long r = __raw_readl(base + GPIO2_INTENABLE);
if (en)
r |= 1 << gpio2;
else
r &= ~(1 << gpio2);
- au_writel(r, GPIO2_INTENABLE);
- au_sync();
+ __raw_writel(r, base + GPIO2_INTENABLE);
+ wmb();
}
/**
@@ -418,10 +444,11 @@ static inline void alchemy_gpio2_disable_int(int gpio2)
*/
static inline void alchemy_gpio2_enable(void)
{
- au_writel(3, GPIO2_ENABLE); /* reset, clock enabled */
- au_sync();
- au_writel(1, GPIO2_ENABLE); /* clock enabled */
- au_sync();
+ void __iomem *base = (void __iomem *)KSEG1ADDR(AU1500_GPIO2_PHYS_ADDR);
+ __raw_writel(3, base + GPIO2_ENABLE); /* reset, clock enabled */
+ wmb();
+ __raw_writel(1, base + GPIO2_ENABLE); /* clock enabled */
+ wmb();
}
/**
@@ -431,8 +458,9 @@ static inline void alchemy_gpio2_enable(void)
*/
static inline void alchemy_gpio2_disable(void)
{
- au_writel(2, GPIO2_ENABLE); /* reset, clock disabled */
- au_sync();
+ void __iomem *base = (void __iomem *)KSEG1ADDR(AU1500_GPIO2_PHYS_ADDR);
+ __raw_writel(2, base + GPIO2_ENABLE); /* reset, clock disabled */
+ wmb();
}
/**********************************************************************/
@@ -556,6 +584,16 @@ static inline void gpio_set_value(int gpio, int v)
alchemy_gpio_set_value(gpio, v);
}
+static inline int gpio_get_value_cansleep(unsigned gpio)
+{
+ return gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value_cansleep(unsigned gpio, int value)
+{
+ gpio_set_value(gpio, value);
+}
+
static inline int gpio_is_valid(int gpio)
{
return alchemy_gpio_is_valid(gpio);
@@ -581,10 +619,50 @@ static inline int gpio_request(unsigned gpio, const char *label)
return 0;
}
+static inline int gpio_request_one(unsigned gpio,
+ unsigned long flags, const char *label)
+{
+ return 0;
+}
+
+static inline int gpio_request_array(struct gpio *array, size_t num)
+{
+ return 0;
+}
+
static inline void gpio_free(unsigned gpio)
{
}
+static inline void gpio_free_array(struct gpio *array, size_t num)
+{
+}
+
+static inline int gpio_set_debounce(unsigned gpio, unsigned debounce)
+{
+ return -ENOSYS;
+}
+
+static inline int gpio_export(unsigned gpio, bool direction_may_change)
+{
+ return -ENOSYS;
+}
+
+static inline int gpio_export_link(struct device *dev, const char *name,
+ unsigned gpio)
+{
+ return -ENOSYS;
+}
+
+static inline int gpio_sysfs_set_active_low(unsigned gpio, int value)
+{
+ return -ENOSYS;
+}
+
+static inline void gpio_unexport(unsigned gpio)
+{
+}
+
#endif /* !CONFIG_ALCHEMY_GPIO_INDIRECT */
diff --git a/arch/mips/include/asm/mach-bcm47xx/nvram.h b/arch/mips/include/asm/mach-bcm47xx/nvram.h
index 9759588ba3cf..184d5ecb5f51 100644
--- a/arch/mips/include/asm/mach-bcm47xx/nvram.h
+++ b/arch/mips/include/asm/mach-bcm47xx/nvram.h
@@ -39,8 +39,16 @@ extern int nvram_getenv(char *name, char *val, size_t val_len);
static inline void nvram_parse_macaddr(char *buf, u8 *macaddr)
{
- sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0], &macaddr[1],
- &macaddr[2], &macaddr[3], &macaddr[4], &macaddr[5]);
+ if (strchr(buf, ':'))
+ sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0],
+ &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
+ &macaddr[5]);
+ else if (strchr(buf, '-'))
+ sscanf(buf, "%hhx-%hhx-%hhx-%hhx-%hhx-%hhx", &macaddr[0],
+ &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
+ &macaddr[5]);
+ else
+ printk(KERN_WARNING "Can not parse mac address: %s\n", buf);
}
#endif
diff --git a/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h b/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h
index 0b2b5eb22e9b..dedef7d2b01f 100644
--- a/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h
+++ b/arch/mips/include/asm/mach-cavium-octeon/kernel-entry-init.h
@@ -63,6 +63,11 @@
# CN30XX Disable instruction prefetching
or v0, v0, 0x2000
skip:
+ # First clear off CvmCtl[IPPCI] bit and move the performance
+ # counters interrupt to IRQ 6
+ li v1, ~(7 << 7)
+ and v0, v0, v1
+ ori v0, v0, (6 << 7)
# Write the cavium control register
dmtc0 v0, CP0_CVMCTL_REG
sync
diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h
new file mode 100644
index 000000000000..ce2f02929d22
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/lantiq.h
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+#ifndef _LANTIQ_H__
+#define _LANTIQ_H__
+
+#include <linux/irq.h>
+
+/* generic reg access functions */
+#define ltq_r32(reg) __raw_readl(reg)
+#define ltq_w32(val, reg) __raw_writel(val, reg)
+#define ltq_w32_mask(clear, set, reg) \
+ ltq_w32((ltq_r32(reg) & ~(clear)) | (set), reg)
+#define ltq_r8(reg) __raw_readb(reg)
+#define ltq_w8(val, reg) __raw_writeb(val, reg)
+
+/* register access macros for EBU and CGU */
+#define ltq_ebu_w32(x, y) ltq_w32((x), ltq_ebu_membase + (y))
+#define ltq_ebu_r32(x) ltq_r32(ltq_ebu_membase + (x))
+#define ltq_cgu_w32(x, y) ltq_w32((x), ltq_cgu_membase + (y))
+#define ltq_cgu_r32(x) ltq_r32(ltq_cgu_membase + (x))
+
+extern __iomem void *ltq_ebu_membase;
+extern __iomem void *ltq_cgu_membase;
+
+extern unsigned int ltq_get_cpu_ver(void);
+extern unsigned int ltq_get_soc_type(void);
+
+/* clock speeds */
+#define CLOCK_60M 60000000
+#define CLOCK_83M 83333333
+#define CLOCK_111M 111111111
+#define CLOCK_133M 133333333
+#define CLOCK_167M 166666667
+#define CLOCK_200M 200000000
+#define CLOCK_266M 266666666
+#define CLOCK_333M 333333333
+#define CLOCK_400M 400000000
+
+/* spinlock all ebu i/o */
+extern spinlock_t ebu_lock;
+
+/* some irq helpers */
+extern void ltq_disable_irq(struct irq_data *data);
+extern void ltq_mask_and_ack_irq(struct irq_data *data);
+extern void ltq_enable_irq(struct irq_data *data);
+
+/* find out what caused the last cpu reset */
+extern int ltq_reset_cause(void);
+#define LTQ_RST_CAUSE_WDTRST 0x20
+
+#define IOPORT_RESOURCE_START 0x10000000
+#define IOPORT_RESOURCE_END 0xffffffff
+#define IOMEM_RESOURCE_START 0x10000000
+#define IOMEM_RESOURCE_END 0xffffffff
+#define LTQ_FLASH_START 0x10000000
+#define LTQ_FLASH_MAX 0x04000000
+
+#endif
diff --git a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h
new file mode 100644
index 000000000000..a305f1d0259e
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LANTIQ_PLATFORM_H__
+#define _LANTIQ_PLATFORM_H__
+
+#include <linux/mtd/partitions.h>
+#include <linux/socket.h>
+
+/* struct used to pass info to the pci core */
+enum {
+ PCI_CLOCK_INT = 0,
+ PCI_CLOCK_EXT
+};
+
+#define PCI_EXIN0 0x0001
+#define PCI_EXIN1 0x0002
+#define PCI_EXIN2 0x0004
+#define PCI_EXIN3 0x0008
+#define PCI_EXIN4 0x0010
+#define PCI_EXIN5 0x0020
+#define PCI_EXIN_MAX 6
+
+#define PCI_GNT1 0x0040
+#define PCI_GNT2 0x0080
+#define PCI_GNT3 0x0100
+#define PCI_GNT4 0x0200
+
+#define PCI_REQ1 0x0400
+#define PCI_REQ2 0x0800
+#define PCI_REQ3 0x1000
+#define PCI_REQ4 0x2000
+#define PCI_REQ_SHIFT 10
+#define PCI_REQ_MASK 0xf
+
+struct ltq_pci_data {
+ int clock;
+ int gpio;
+ int irq[16];
+};
+
+/* struct used to pass info to network drivers */
+struct ltq_eth_data {
+ struct sockaddr mac;
+ int mii_mode;
+};
+
+#endif
diff --git a/arch/mips/include/asm/mach-lantiq/war.h b/arch/mips/include/asm/mach-lantiq/war.h
new file mode 100644
index 000000000000..01b08ef368d1
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/war.h
@@ -0,0 +1,24 @@
+/*
+ * 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_MIPS_MACH_LANTIQ_WAR_H
+#define __ASM_MIPS_MACH_LANTIQ_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
diff --git a/arch/mips/include/asm/mach-lantiq/xway/irq.h b/arch/mips/include/asm/mach-lantiq/xway/irq.h
new file mode 100644
index 000000000000..a1471d2dd0d2
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/xway/irq.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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef __LANTIQ_IRQ_H
+#define __LANTIQ_IRQ_H
+
+#include <lantiq_irq.h>
+
+#define NR_IRQS 256
+
+#include_next <irq.h>
+
+#endif
diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h
new file mode 100644
index 000000000000..b4465a888e20
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LANTIQ_XWAY_IRQ_H__
+#define _LANTIQ_XWAY_IRQ_H__
+
+#define INT_NUM_IRQ0 8
+#define INT_NUM_IM0_IRL0 (INT_NUM_IRQ0 + 0)
+#define INT_NUM_IM1_IRL0 (INT_NUM_IRQ0 + 32)
+#define INT_NUM_IM2_IRL0 (INT_NUM_IRQ0 + 64)
+#define INT_NUM_IM3_IRL0 (INT_NUM_IRQ0 + 96)
+#define INT_NUM_IM4_IRL0 (INT_NUM_IRQ0 + 128)
+#define INT_NUM_IM_OFFSET (INT_NUM_IM1_IRL0 - INT_NUM_IM0_IRL0)
+
+#define LTQ_ASC_TIR(x) (INT_NUM_IM3_IRL0 + (x * 8))
+#define LTQ_ASC_RIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 1)
+#define LTQ_ASC_EIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 2)
+
+#define LTQ_ASC_ASE_TIR INT_NUM_IM2_IRL0
+#define LTQ_ASC_ASE_RIR (INT_NUM_IM2_IRL0 + 2)
+#define LTQ_ASC_ASE_EIR (INT_NUM_IM2_IRL0 + 3)
+
+#define LTQ_SSC_TIR (INT_NUM_IM0_IRL0 + 15)
+#define LTQ_SSC_RIR (INT_NUM_IM0_IRL0 + 14)
+#define LTQ_SSC_EIR (INT_NUM_IM0_IRL0 + 16)
+
+#define LTQ_MEI_DYING_GASP_INT (INT_NUM_IM1_IRL0 + 21)
+#define LTQ_MEI_INT (INT_NUM_IM1_IRL0 + 23)
+
+#define LTQ_TIMER6_INT (INT_NUM_IM1_IRL0 + 23)
+#define LTQ_USB_INT (INT_NUM_IM1_IRL0 + 22)
+#define LTQ_USB_OC_INT (INT_NUM_IM4_IRL0 + 23)
+
+#define MIPS_CPU_TIMER_IRQ 7
+
+#define LTQ_DMA_CH0_INT (INT_NUM_IM2_IRL0)
+#define LTQ_DMA_CH1_INT (INT_NUM_IM2_IRL0 + 1)
+#define LTQ_DMA_CH2_INT (INT_NUM_IM2_IRL0 + 2)
+#define LTQ_DMA_CH3_INT (INT_NUM_IM2_IRL0 + 3)
+#define LTQ_DMA_CH4_INT (INT_NUM_IM2_IRL0 + 4)
+#define LTQ_DMA_CH5_INT (INT_NUM_IM2_IRL0 + 5)
+#define LTQ_DMA_CH6_INT (INT_NUM_IM2_IRL0 + 6)
+#define LTQ_DMA_CH7_INT (INT_NUM_IM2_IRL0 + 7)
+#define LTQ_DMA_CH8_INT (INT_NUM_IM2_IRL0 + 8)
+#define LTQ_DMA_CH9_INT (INT_NUM_IM2_IRL0 + 9)
+#define LTQ_DMA_CH10_INT (INT_NUM_IM2_IRL0 + 10)
+#define LTQ_DMA_CH11_INT (INT_NUM_IM2_IRL0 + 11)
+#define LTQ_DMA_CH12_INT (INT_NUM_IM2_IRL0 + 25)
+#define LTQ_DMA_CH13_INT (INT_NUM_IM2_IRL0 + 26)
+#define LTQ_DMA_CH14_INT (INT_NUM_IM2_IRL0 + 27)
+#define LTQ_DMA_CH15_INT (INT_NUM_IM2_IRL0 + 28)
+#define LTQ_DMA_CH16_INT (INT_NUM_IM2_IRL0 + 29)
+#define LTQ_DMA_CH17_INT (INT_NUM_IM2_IRL0 + 30)
+#define LTQ_DMA_CH18_INT (INT_NUM_IM2_IRL0 + 16)
+#define LTQ_DMA_CH19_INT (INT_NUM_IM2_IRL0 + 21)
+
+#define LTQ_PPE_MBOX_INT (INT_NUM_IM2_IRL0 + 24)
+
+#define INT_NUM_IM4_IRL14 (INT_NUM_IM4_IRL0 + 14)
+
+#endif
diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
new file mode 100644
index 000000000000..8a3c6be669d2
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LTQ_XWAY_H__
+#define _LTQ_XWAY_H__
+
+#ifdef CONFIG_SOC_TYPE_XWAY
+
+#include <lantiq.h>
+
+/* Chip IDs */
+#define SOC_ID_DANUBE1 0x129
+#define SOC_ID_DANUBE2 0x12B
+#define SOC_ID_TWINPASS 0x12D
+#define SOC_ID_AMAZON_SE 0x152
+#define SOC_ID_ARX188 0x16C
+#define SOC_ID_ARX168 0x16D
+#define SOC_ID_ARX182 0x16F
+
+/* SoC Types */
+#define SOC_TYPE_DANUBE 0x01
+#define SOC_TYPE_TWINPASS 0x02
+#define SOC_TYPE_AR9 0x03
+#define SOC_TYPE_VR9 0x04
+#define SOC_TYPE_AMAZON_SE 0x05
+
+/* ASC0/1 - serial port */
+#define LTQ_ASC0_BASE_ADDR 0x1E100400
+#define LTQ_ASC1_BASE_ADDR 0x1E100C00
+#define LTQ_ASC_SIZE 0x400
+
+/* RCU - reset control unit */
+#define LTQ_RCU_BASE_ADDR 0x1F203000
+#define LTQ_RCU_SIZE 0x1000
+
+/* GPTU - general purpose timer unit */
+#define LTQ_GPTU_BASE_ADDR 0x18000300
+#define LTQ_GPTU_SIZE 0x100
+
+/* EBU - external bus unit */
+#define LTQ_EBU_GPIO_START 0x14000000
+#define LTQ_EBU_GPIO_SIZE 0x1000
+
+#define LTQ_EBU_BASE_ADDR 0x1E105300
+#define LTQ_EBU_SIZE 0x100
+
+#define LTQ_EBU_BUSCON0 0x0060
+#define LTQ_EBU_PCC_CON 0x0090
+#define LTQ_EBU_PCC_IEN 0x00A4
+#define LTQ_EBU_PCC_ISTAT 0x00A0
+#define LTQ_EBU_BUSCON1 0x0064
+#define LTQ_EBU_ADDRSEL1 0x0024
+#define EBU_WRDIS 0x80000000
+
+/* CGU - clock generation unit */
+#define LTQ_CGU_BASE_ADDR 0x1F103000
+#define LTQ_CGU_SIZE 0x1000
+
+/* ICU - interrupt control unit */
+#define LTQ_ICU_BASE_ADDR 0x1F880200
+#define LTQ_ICU_SIZE 0x100
+
+/* EIU - external interrupt unit */
+#define LTQ_EIU_BASE_ADDR 0x1F101000
+#define LTQ_EIU_SIZE 0x1000
+
+/* PMU - power management unit */
+#define LTQ_PMU_BASE_ADDR 0x1F102000
+#define LTQ_PMU_SIZE 0x1000
+
+#define PMU_DMA 0x0020
+#define PMU_USB 0x8041
+#define PMU_LED 0x0800
+#define PMU_GPT 0x1000
+#define PMU_PPE 0x2000
+#define PMU_FPI 0x4000
+#define PMU_SWITCH 0x10000000
+
+/* ETOP - ethernet */
+#define LTQ_ETOP_BASE_ADDR 0x1E180000
+#define LTQ_ETOP_SIZE 0x40000
+
+/* DMA */
+#define LTQ_DMA_BASE_ADDR 0x1E104100
+#define LTQ_DMA_SIZE 0x800
+
+/* PCI */
+#define PCI_CR_BASE_ADDR 0x1E105400
+#define PCI_CR_SIZE 0x400
+
+/* WDT */
+#define LTQ_WDT_BASE_ADDR 0x1F8803F0
+#define LTQ_WDT_SIZE 0x10
+
+/* STP - serial to parallel conversion unit */
+#define LTQ_STP_BASE_ADDR 0x1E100BB0
+#define LTQ_STP_SIZE 0x40
+
+/* GPIO */
+#define LTQ_GPIO0_BASE_ADDR 0x1E100B10
+#define LTQ_GPIO1_BASE_ADDR 0x1E100B40
+#define LTQ_GPIO2_BASE_ADDR 0x1E100B70
+#define LTQ_GPIO_SIZE 0x30
+
+/* SSC */
+#define LTQ_SSC_BASE_ADDR 0x1e100800
+#define LTQ_SSC_SIZE 0x100
+
+/* MEI - dsl core */
+#define LTQ_MEI_BASE_ADDR 0x1E116000
+
+/* DEU - data encryption unit */
+#define LTQ_DEU_BASE_ADDR 0x1E103100
+
+/* MPS - multi processor unit (voice) */
+#define LTQ_MPS_BASE_ADDR (KSEG1 + 0x1F107000)
+#define LTQ_MPS_CHIPID ((u32 *)(LTQ_MPS_BASE_ADDR + 0x0344))
+
+/* request a non-gpio and set the PIO config */
+extern int ltq_gpio_request(unsigned int pin, unsigned int alt0,
+ unsigned int alt1, unsigned int dir, const char *name);
+extern void ltq_pmu_enable(unsigned int module);
+extern void ltq_pmu_disable(unsigned int module);
+
+static inline int ltq_is_ar9(void)
+{
+ return (ltq_get_soc_type() == SOC_TYPE_AR9);
+}
+
+static inline int ltq_is_vr9(void)
+{
+ return (ltq_get_soc_type() == SOC_TYPE_VR9);
+}
+
+#endif /* CONFIG_SOC_TYPE_XWAY */
+#endif /* _LTQ_XWAY_H__ */
diff --git a/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h b/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h
new file mode 100644
index 000000000000..872943a4b90e
--- /dev/null
+++ b/arch/mips/include/asm/mach-lantiq/xway/xway_dma.h
@@ -0,0 +1,60 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef LTQ_DMA_H__
+#define LTQ_DMA_H__
+
+#define LTQ_DESC_SIZE 0x08 /* each descriptor is 64bit */
+#define LTQ_DESC_NUM 0x40 /* 64 descriptors / channel */
+
+#define LTQ_DMA_OWN BIT(31) /* owner bit */
+#define LTQ_DMA_C BIT(30) /* complete bit */
+#define LTQ_DMA_SOP BIT(29) /* start of packet */
+#define LTQ_DMA_EOP BIT(28) /* end of packet */
+#define LTQ_DMA_TX_OFFSET(x) ((x & 0x1f) << 23) /* data bytes offset */
+#define LTQ_DMA_RX_OFFSET(x) ((x & 0x7) << 23) /* data bytes offset */
+#define LTQ_DMA_SIZE_MASK (0xffff) /* the size field is 16 bit */
+
+struct ltq_dma_desc {
+ u32 ctl;
+ u32 addr;
+};
+
+struct ltq_dma_channel {
+ int nr; /* the channel number */
+ int irq; /* the mapped irq */
+ int desc; /* the current descriptor */
+ struct ltq_dma_desc *desc_base; /* the descriptor base */
+ int phys; /* physical addr */
+};
+
+enum {
+ DMA_PORT_ETOP = 0,
+ DMA_PORT_DEU,
+};
+
+extern void ltq_dma_enable_irq(struct ltq_dma_channel *ch);
+extern void ltq_dma_disable_irq(struct ltq_dma_channel *ch);
+extern void ltq_dma_ack_irq(struct ltq_dma_channel *ch);
+extern void ltq_dma_open(struct ltq_dma_channel *ch);
+extern void ltq_dma_close(struct ltq_dma_channel *ch);
+extern void ltq_dma_alloc_tx(struct ltq_dma_channel *ch);
+extern void ltq_dma_alloc_rx(struct ltq_dma_channel *ch);
+extern void ltq_dma_free(struct ltq_dma_channel *ch);
+extern void ltq_dma_init_port(int p);
+
+#endif
diff --git a/arch/mips/include/asm/mach-netlogic/cpu-feature-overrides.h b/arch/mips/include/asm/mach-netlogic/cpu-feature-overrides.h
new file mode 100644
index 000000000000..3b728275b9b0
--- /dev/null
+++ b/arch/mips/include/asm/mach-netlogic/cpu-feature-overrides.h
@@ -0,0 +1,47 @@
+/*
+ * 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) 2011 Netlogic Microsystems
+ * Copyright (C) 2003 Ralf Baechle
+ */
+#ifndef __ASM_MACH_NETLOGIC_CPU_FEATURE_OVERRIDES_H
+#define __ASM_MACH_NETLOGIC_CPU_FEATURE_OVERRIDES_H
+
+#define cpu_has_4kex 1
+#define cpu_has_4k_cache 1
+#define cpu_has_watch 1
+#define cpu_has_mips16 0
+#define cpu_has_counter 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_vtag_icache 0
+#define cpu_has_dc_aliases 0
+#define cpu_has_ic_fills_f_dc 0
+#define cpu_has_dsp 0
+#define cpu_has_mipsmt 0
+#define cpu_has_userlocal 0
+#define cpu_icache_snoops_remote_store 0
+
+#define cpu_has_nofpuex 0
+#define cpu_has_64bits 1
+
+#define cpu_has_mips32r1 1
+#define cpu_has_mips32r2 0
+#define cpu_has_mips64r1 1
+#define cpu_has_mips64r2 0
+
+#define cpu_has_inclusive_pcaches 0
+
+#define cpu_dcache_line_size() 32
+#define cpu_icache_line_size() 32
+
+#endif /* __ASM_MACH_NETLOGIC_CPU_FEATURE_OVERRIDES_H */
diff --git a/arch/mips/include/asm/mach-netlogic/irq.h b/arch/mips/include/asm/mach-netlogic/irq.h
new file mode 100644
index 000000000000..b5902458e7c1
--- /dev/null
+++ b/arch/mips/include/asm/mach-netlogic/irq.h
@@ -0,0 +1,14 @@
+/*
+ * 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) 2011 Netlogic Microsystems.
+ */
+#ifndef __ASM_NETLOGIC_IRQ_H
+#define __ASM_NETLOGIC_IRQ_H
+
+#define NR_IRQS 64
+#define MIPS_CPU_IRQ_BASE 0
+
+#endif /* __ASM_NETLOGIC_IRQ_H */
diff --git a/arch/mips/include/asm/mach-netlogic/war.h b/arch/mips/include/asm/mach-netlogic/war.h
new file mode 100644
index 000000000000..22da89327352
--- /dev/null
+++ b/arch/mips/include/asm/mach-netlogic/war.h
@@ -0,0 +1,26 @@
+/*
+ * 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) 2011 Netlogic Microsystems.
+ * Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
+ */
+#ifndef __ASM_MIPS_MACH_NLM_WAR_H
+#define __ASM_MIPS_MACH_NLM_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_NLM_WAR_H */
diff --git a/arch/mips/include/asm/module.h b/arch/mips/include/asm/module.h
index d94085a3eafb..bc01a02cacd8 100644
--- a/arch/mips/include/asm/module.h
+++ b/arch/mips/include/asm/module.h
@@ -118,6 +118,8 @@ search_module_dbetables(unsigned long addr)
#define MODULE_PROC_FAMILY "LOONGSON2 "
#elif defined CONFIG_CPU_CAVIUM_OCTEON
#define MODULE_PROC_FAMILY "OCTEON "
+#elif defined CONFIG_CPU_XLR
+#define MODULE_PROC_FAMILY "XLR "
#else
#error MODULE_PROC_FAMILY undefined for your processor configuration
#endif
diff --git a/arch/mips/include/asm/netlogic/interrupt.h b/arch/mips/include/asm/netlogic/interrupt.h
new file mode 100644
index 000000000000..a85aadb6cfd7
--- /dev/null
+++ b/arch/mips/include/asm/netlogic/interrupt.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ASM_NLM_INTERRUPT_H
+#define _ASM_NLM_INTERRUPT_H
+
+/* Defines for the IRQ numbers */
+
+#define IRQ_IPI_SMP_FUNCTION 3
+#define IRQ_IPI_SMP_RESCHEDULE 4
+#define IRQ_MSGRING 6
+#define IRQ_TIMER 7
+
+#endif
diff --git a/arch/mips/include/asm/netlogic/mips-extns.h b/arch/mips/include/asm/netlogic/mips-extns.h
new file mode 100644
index 000000000000..8c53d0ba4bf2
--- /dev/null
+++ b/arch/mips/include/asm/netlogic/mips-extns.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ASM_NLM_MIPS_EXTS_H
+#define _ASM_NLM_MIPS_EXTS_H
+
+/*
+ * XLR and XLP interrupt request and interrupt mask registers
+ */
+#define read_c0_eirr() __read_64bit_c0_register($9, 6)
+#define read_c0_eimr() __read_64bit_c0_register($9, 7)
+#define write_c0_eirr(val) __write_64bit_c0_register($9, 6, val)
+
+/*
+ * Writing EIMR in 32 bit is a special case, the lower 8 bit of the
+ * EIMR is shadowed in the status register, so we cannot save and
+ * restore status register for split read.
+ */
+#define write_c0_eimr(val) \
+do { \
+ if (sizeof(unsigned long) == 4) { \
+ unsigned long __flags; \
+ \
+ local_irq_save(__flags); \
+ __asm__ __volatile__( \
+ ".set\tmips64\n\t" \
+ "dsll\t%L0, %L0, 32\n\t" \
+ "dsrl\t%L0, %L0, 32\n\t" \
+ "dsll\t%M0, %M0, 32\n\t" \
+ "or\t%L0, %L0, %M0\n\t" \
+ "dmtc0\t%L0, $9, 7\n\t" \
+ ".set\tmips0" \
+ : : "r" (val)); \
+ __flags = (__flags & 0xffff00ff) | (((val) & 0xff) << 8);\
+ local_irq_restore(__flags); \
+ } else \
+ __write_64bit_c0_register($9, 7, (val)); \
+} while (0)
+
+static inline int hard_smp_processor_id(void)
+{
+ return __read_32bit_c0_register($15, 1) & 0x3ff;
+}
+
+#endif /*_ASM_NLM_MIPS_EXTS_H */
diff --git a/arch/mips/include/asm/netlogic/psb-bootinfo.h b/arch/mips/include/asm/netlogic/psb-bootinfo.h
new file mode 100644
index 000000000000..6878307f0ee6
--- /dev/null
+++ b/arch/mips/include/asm/netlogic/psb-bootinfo.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ASM_NETLOGIC_BOOTINFO_H
+#define _ASM_NETLOGIC_BOOTINFO_H
+
+struct psb_info {
+ uint64_t boot_level;
+ uint64_t io_base;
+ uint64_t output_device;
+ uint64_t uart_print;
+ uint64_t led_output;
+ uint64_t init;
+ uint64_t exit;
+ uint64_t warm_reset;
+ uint64_t wakeup;
+ uint64_t online_cpu_map;
+ uint64_t master_reentry_sp;
+ uint64_t master_reentry_gp;
+ uint64_t master_reentry_fn;
+ uint64_t slave_reentry_fn;
+ uint64_t magic_dword;
+ uint64_t uart_putchar;
+ uint64_t size;
+ uint64_t uart_getchar;
+ uint64_t nmi_handler;
+ uint64_t psb_version;
+ uint64_t mac_addr;
+ uint64_t cpu_frequency;
+ uint64_t board_version;
+ uint64_t malloc;
+ uint64_t free;
+ uint64_t global_shmem_addr;
+ uint64_t global_shmem_size;
+ uint64_t psb_os_cpu_map;
+ uint64_t userapp_cpu_map;
+ uint64_t wakeup_os;
+ uint64_t psb_mem_map;
+ uint64_t board_major_version;
+ uint64_t board_minor_version;
+ uint64_t board_manf_revision;
+ uint64_t board_serial_number;
+ uint64_t psb_physaddr_map;
+ uint64_t xlr_loaderip_config;
+ uint64_t bldr_envp;
+ uint64_t avail_mem_map;
+};
+
+enum {
+ NETLOGIC_IO_SPACE = 0x10,
+ PCIX_IO_SPACE,
+ PCIX_CFG_SPACE,
+ PCIX_MEMORY_SPACE,
+ HT_IO_SPACE,
+ HT_CFG_SPACE,
+ HT_MEMORY_SPACE,
+ SRAM_SPACE,
+ FLASH_CONTROLLER_SPACE
+};
+
+#define NLM_MAX_ARGS 64
+#define NLM_MAX_ENVS 32
+
+/* This is what netlboot passes and linux boot_mem_map is subtly different */
+#define NLM_BOOT_MEM_MAP_MAX 32
+struct nlm_boot_mem_map {
+ int nr_map;
+ struct nlm_boot_mem_map_entry {
+ uint64_t addr; /* start of memory segment */
+ uint64_t size; /* size of memory segment */
+ uint32_t type; /* type of memory segment */
+ } map[NLM_BOOT_MEM_MAP_MAX];
+};
+
+/* Pointer to saved boot loader info */
+extern struct psb_info nlm_prom_info;
+
+#endif
diff --git a/arch/mips/include/asm/netlogic/xlr/gpio.h b/arch/mips/include/asm/netlogic/xlr/gpio.h
new file mode 100644
index 000000000000..51f6ad4aeb14
--- /dev/null
+++ b/arch/mips/include/asm/netlogic/xlr/gpio.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ASM_NLM_GPIO_H
+#define _ASM_NLM_GPIO_H
+
+#define NETLOGIC_GPIO_INT_EN_REG 0
+#define NETLOGIC_GPIO_INPUT_INVERSION_REG 1
+#define NETLOGIC_GPIO_IO_DIR_REG 2
+#define NETLOGIC_GPIO_IO_DATA_WR_REG 3
+#define NETLOGIC_GPIO_IO_DATA_RD_REG 4
+
+#define NETLOGIC_GPIO_SWRESET_REG 8
+#define NETLOGIC_GPIO_DRAM1_CNTRL_REG 9
+#define NETLOGIC_GPIO_DRAM1_RATIO_REG 10
+#define NETLOGIC_GPIO_DRAM1_RESET_REG 11
+#define NETLOGIC_GPIO_DRAM1_STATUS_REG 12
+#define NETLOGIC_GPIO_DRAM2_CNTRL_REG 13
+#define NETLOGIC_GPIO_DRAM2_RATIO_REG 14
+#define NETLOGIC_GPIO_DRAM2_RESET_REG 15
+#define NETLOGIC_GPIO_DRAM2_STATUS_REG 16
+
+#define NETLOGIC_GPIO_PWRON_RESET_CFG_REG 21
+#define NETLOGIC_GPIO_BIST_ALL_GO_STATUS_REG 24
+#define NETLOGIC_GPIO_BIST_CPU_GO_STATUS_REG 25
+#define NETLOGIC_GPIO_BIST_DEV_GO_STATUS_REG 26
+
+#define NETLOGIC_GPIO_FUSE_BANK_REG 35
+#define NETLOGIC_GPIO_CPU_RESET_REG 40
+#define NETLOGIC_GPIO_RNG_REG 43
+
+#define NETLOGIC_PWRON_RESET_PCMCIA_BOOT 17
+#define NETLOGIC_GPIO_LED_BITMAP 0x1700000
+#define NETLOGIC_GPIO_LED_0_SHIFT 20
+#define NETLOGIC_GPIO_LED_1_SHIFT 24
+
+#define NETLOGIC_GPIO_LED_OUTPUT_CODE_RESET 0x01
+#define NETLOGIC_GPIO_LED_OUTPUT_CODE_HARD_RESET 0x02
+#define NETLOGIC_GPIO_LED_OUTPUT_CODE_SOFT_RESET 0x03
+#define NETLOGIC_GPIO_LED_OUTPUT_CODE_MAIN 0x04
+
+#endif
diff --git a/arch/mips/include/asm/netlogic/xlr/iomap.h b/arch/mips/include/asm/netlogic/xlr/iomap.h
new file mode 100644
index 000000000000..2e3a4dd53045
--- /dev/null
+++ b/arch/mips/include/asm/netlogic/xlr/iomap.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ASM_NLM_IOMAP_H
+#define _ASM_NLM_IOMAP_H
+
+#define DEFAULT_NETLOGIC_IO_BASE CKSEG1ADDR(0x1ef00000)
+#define NETLOGIC_IO_DDR2_CHN0_OFFSET 0x01000
+#define NETLOGIC_IO_DDR2_CHN1_OFFSET 0x02000
+#define NETLOGIC_IO_DDR2_CHN2_OFFSET 0x03000
+#define NETLOGIC_IO_DDR2_CHN3_OFFSET 0x04000
+#define NETLOGIC_IO_PIC_OFFSET 0x08000
+#define NETLOGIC_IO_UART_0_OFFSET 0x14000
+#define NETLOGIC_IO_UART_1_OFFSET 0x15100
+
+#define NETLOGIC_IO_SIZE 0x1000
+
+#define NETLOGIC_IO_BRIDGE_OFFSET 0x00000
+
+#define NETLOGIC_IO_RLD2_CHN0_OFFSET 0x05000
+#define NETLOGIC_IO_RLD2_CHN1_OFFSET 0x06000
+
+#define NETLOGIC_IO_SRAM_OFFSET 0x07000
+
+#define NETLOGIC_IO_PCIX_OFFSET 0x09000
+#define NETLOGIC_IO_HT_OFFSET 0x0A000
+
+#define NETLOGIC_IO_SECURITY_OFFSET 0x0B000
+
+#define NETLOGIC_IO_GMAC_0_OFFSET 0x0C000
+#define NETLOGIC_IO_GMAC_1_OFFSET 0x0D000
+#define NETLOGIC_IO_GMAC_2_OFFSET 0x0E000
+#define NETLOGIC_IO_GMAC_3_OFFSET 0x0F000
+
+/* XLS devices */
+#define NETLOGIC_IO_GMAC_4_OFFSET 0x20000
+#define NETLOGIC_IO_GMAC_5_OFFSET 0x21000
+#define NETLOGIC_IO_GMAC_6_OFFSET 0x22000
+#define NETLOGIC_IO_GMAC_7_OFFSET 0x23000
+
+#define NETLOGIC_IO_PCIE_0_OFFSET 0x1E000
+#define NETLOGIC_IO_PCIE_1_OFFSET 0x1F000
+#define NETLOGIC_IO_SRIO_0_OFFSET 0x1E000
+#define NETLOGIC_IO_SRIO_1_OFFSET 0x1F000
+
+#define NETLOGIC_IO_USB_0_OFFSET 0x24000
+#define NETLOGIC_IO_USB_1_OFFSET 0x25000
+
+#define NETLOGIC_IO_COMP_OFFSET 0x1D000
+/* end XLS devices */
+
+/* XLR devices */
+#define NETLOGIC_IO_SPI4_0_OFFSET 0x10000
+#define NETLOGIC_IO_XGMAC_0_OFFSET 0x11000
+#define NETLOGIC_IO_SPI4_1_OFFSET 0x12000
+#define NETLOGIC_IO_XGMAC_1_OFFSET 0x13000
+/* end XLR devices */
+
+#define NETLOGIC_IO_I2C_0_OFFSET 0x16000
+#define NETLOGIC_IO_I2C_1_OFFSET 0x17000
+
+#define NETLOGIC_IO_GPIO_OFFSET 0x18000
+#define NETLOGIC_IO_FLASH_OFFSET 0x19000
+#define NETLOGIC_IO_TB_OFFSET 0x1C000
+
+#define NETLOGIC_CPLD_OFFSET KSEG1ADDR(0x1d840000)
+
+/*
+ * Base Address (Virtual) of the PCI Config address space
+ * For now, choose 256M phys in kseg1 = 0xA0000000 + (1<<28)
+ * Config space spans 256 (num of buses) * 256 (num functions) * 256 bytes
+ * ie 1<<24 = 16M
+ */
+#define DEFAULT_PCI_CONFIG_BASE 0x18000000
+#define DEFAULT_HT_TYPE0_CFG_BASE 0x16000000
+#define DEFAULT_HT_TYPE1_CFG_BASE 0x17000000
+
+#ifndef __ASSEMBLY__
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+typedef volatile __u32 nlm_reg_t;
+extern unsigned long netlogic_io_base;
+
+/* FIXME read once in write_reg */
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+#define netlogic_read_reg(base, offset) ((base)[(offset)])
+#define netlogic_write_reg(base, offset, value) ((base)[(offset)] = (value))
+#else
+#define netlogic_read_reg(base, offset) (be32_to_cpu((base)[(offset)]))
+#define netlogic_write_reg(base, offset, value) \
+ ((base)[(offset)] = cpu_to_be32((value)))
+#endif
+
+#define netlogic_read_reg_le32(base, offset) (le32_to_cpu((base)[(offset)]))
+#define netlogic_write_reg_le32(base, offset, value) \
+ ((base)[(offset)] = cpu_to_le32((value)))
+#define netlogic_io_mmio(offset) ((nlm_reg_t *)(netlogic_io_base+(offset)))
+#endif /* __ASSEMBLY__ */
+#endif
diff --git a/arch/mips/include/asm/netlogic/xlr/pic.h b/arch/mips/include/asm/netlogic/xlr/pic.h
new file mode 100644
index 000000000000..5cceb746f080
--- /dev/null
+++ b/arch/mips/include/asm/netlogic/xlr/pic.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ASM_NLM_XLR_PIC_H
+#define _ASM_NLM_XLR_PIC_H
+
+#define PIC_CLKS_PER_SEC 66666666ULL
+/* PIC hardware interrupt numbers */
+#define PIC_IRT_WD_INDEX 0
+#define PIC_IRT_TIMER_0_INDEX 1
+#define PIC_IRT_TIMER_1_INDEX 2
+#define PIC_IRT_TIMER_2_INDEX 3
+#define PIC_IRT_TIMER_3_INDEX 4
+#define PIC_IRT_TIMER_4_INDEX 5
+#define PIC_IRT_TIMER_5_INDEX 6
+#define PIC_IRT_TIMER_6_INDEX 7
+#define PIC_IRT_TIMER_7_INDEX 8
+#define PIC_IRT_CLOCK_INDEX PIC_IRT_TIMER_7_INDEX
+#define PIC_IRT_UART_0_INDEX 9
+#define PIC_IRT_UART_1_INDEX 10
+#define PIC_IRT_I2C_0_INDEX 11
+#define PIC_IRT_I2C_1_INDEX 12
+#define PIC_IRT_PCMCIA_INDEX 13
+#define PIC_IRT_GPIO_INDEX 14
+#define PIC_IRT_HYPER_INDEX 15
+#define PIC_IRT_PCIX_INDEX 16
+/* XLS */
+#define PIC_IRT_CDE_INDEX 15
+#define PIC_IRT_BRIDGE_TB_XLS_INDEX 16
+/* XLS */
+#define PIC_IRT_GMAC0_INDEX 17
+#define PIC_IRT_GMAC1_INDEX 18
+#define PIC_IRT_GMAC2_INDEX 19
+#define PIC_IRT_GMAC3_INDEX 20
+#define PIC_IRT_XGS0_INDEX 21
+#define PIC_IRT_XGS1_INDEX 22
+#define PIC_IRT_HYPER_FATAL_INDEX 23
+#define PIC_IRT_PCIX_FATAL_INDEX 24
+#define PIC_IRT_BRIDGE_AERR_INDEX 25
+#define PIC_IRT_BRIDGE_BERR_INDEX 26
+#define PIC_IRT_BRIDGE_TB_XLR_INDEX 27
+#define PIC_IRT_BRIDGE_AERR_NMI_INDEX 28
+/* XLS */
+#define PIC_IRT_GMAC4_INDEX 21
+#define PIC_IRT_GMAC5_INDEX 22
+#define PIC_IRT_GMAC6_INDEX 23
+#define PIC_IRT_GMAC7_INDEX 24
+#define PIC_IRT_BRIDGE_ERR_INDEX 25
+#define PIC_IRT_PCIE_LINK0_INDEX 26
+#define PIC_IRT_PCIE_LINK1_INDEX 27
+#define PIC_IRT_PCIE_LINK2_INDEX 23
+#define PIC_IRT_PCIE_LINK3_INDEX 24
+#define PIC_IRT_PCIE_XLSB0_LINK2_INDEX 28
+#define PIC_IRT_PCIE_XLSB0_LINK3_INDEX 29
+#define PIC_IRT_SRIO_LINK0_INDEX 26
+#define PIC_IRT_SRIO_LINK1_INDEX 27
+#define PIC_IRT_SRIO_LINK2_INDEX 28
+#define PIC_IRT_SRIO_LINK3_INDEX 29
+#define PIC_IRT_PCIE_INT_INDEX 28
+#define PIC_IRT_PCIE_FATAL_INDEX 29
+#define PIC_IRT_GPIO_B_INDEX 30
+#define PIC_IRT_USB_INDEX 31
+/* XLS */
+#define PIC_NUM_IRTS 32
+
+
+#define PIC_CLOCK_TIMER 7
+
+/* PIC Registers */
+#define PIC_CTRL 0x00
+#define PIC_IPI 0x04
+#define PIC_INT_ACK 0x06
+
+#define WD_MAX_VAL_0 0x08
+#define WD_MAX_VAL_1 0x09
+#define WD_MASK_0 0x0a
+#define WD_MASK_1 0x0b
+#define WD_HEARBEAT_0 0x0c
+#define WD_HEARBEAT_1 0x0d
+
+#define PIC_IRT_0_BASE 0x40
+#define PIC_IRT_1_BASE 0x80
+#define PIC_TIMER_MAXVAL_0_BASE 0x100
+#define PIC_TIMER_MAXVAL_1_BASE 0x110
+#define PIC_TIMER_COUNT_0_BASE 0x120
+#define PIC_TIMER_COUNT_1_BASE 0x130
+
+#define PIC_IRT_0(picintr) (PIC_IRT_0_BASE + (picintr))
+#define PIC_IRT_1(picintr) (PIC_IRT_1_BASE + (picintr))
+
+#define PIC_TIMER_MAXVAL_0(i) (PIC_TIMER_MAXVAL_0_BASE + (i))
+#define PIC_TIMER_MAXVAL_1(i) (PIC_TIMER_MAXVAL_1_BASE + (i))
+#define PIC_TIMER_COUNT_0(i) (PIC_TIMER_COUNT_0_BASE + (i))
+#define PIC_TIMER_COUNT_1(i) (PIC_TIMER_COUNT_0_BASE + (i))
+
+/*
+ * Mapping between hardware interrupt numbers and IRQs on CPU
+ * we use a simple scheme to map PIC interrupts 0-31 to IRQs
+ * 8-39. This leaves the IRQ 0-7 for cpu interrupts like
+ * count/compare and FMN
+ */
+#define PIC_IRQ_BASE 8
+#define PIC_INTR_TO_IRQ(i) (PIC_IRQ_BASE + (i))
+#define PIC_IRQ_TO_INTR(i) ((i) - PIC_IRQ_BASE)
+
+#define PIC_IRT_FIRST_IRQ PIC_IRQ_BASE
+#define PIC_WD_IRQ PIC_INTR_TO_IRQ(PIC_IRT_WD_INDEX)
+#define PIC_TIMER_0_IRQ PIC_INTR_TO_IRQ(PIC_IRT_TIMER_0_INDEX)
+#define PIC_TIMER_1_IRQ PIC_INTR_TO_IRQ(PIC_IRT_TIMER_1_INDEX)
+#define PIC_TIMER_2_IRQ PIC_INTR_TO_IRQ(PIC_IRT_TIMER_2_INDEX)
+#define PIC_TIMER_3_IRQ PIC_INTR_TO_IRQ(PIC_IRT_TIMER_3_INDEX)
+#define PIC_TIMER_4_IRQ PIC_INTR_TO_IRQ(PIC_IRT_TIMER_4_INDEX)
+#define PIC_TIMER_5_IRQ PIC_INTR_TO_IRQ(PIC_IRT_TIMER_5_INDEX)
+#define PIC_TIMER_6_IRQ PIC_INTR_TO_IRQ(PIC_IRT_TIMER_6_INDEX)
+#define PIC_TIMER_7_IRQ PIC_INTR_TO_IRQ(PIC_IRT_TIMER_7_INDEX)
+#define PIC_CLOCK_IRQ (PIC_TIMER_7_IRQ)
+#define PIC_UART_0_IRQ PIC_INTR_TO_IRQ(PIC_IRT_UART_0_INDEX)
+#define PIC_UART_1_IRQ PIC_INTR_TO_IRQ(PIC_IRT_UART_1_INDEX)
+#define PIC_I2C_0_IRQ PIC_INTR_TO_IRQ(PIC_IRT_I2C_0_INDEX)
+#define PIC_I2C_1_IRQ PIC_INTR_TO_IRQ(PIC_IRT_I2C_1_INDEX)
+#define PIC_PCMCIA_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCMCIA_INDEX)
+#define PIC_GPIO_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GPIO_INDEX)
+#define PIC_HYPER_IRQ PIC_INTR_TO_IRQ(PIC_IRT_HYPER_INDEX)
+#define PIC_PCIX_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIX_INDEX)
+/* XLS */
+#define PIC_CDE_IRQ PIC_INTR_TO_IRQ(PIC_IRT_CDE_INDEX)
+#define PIC_BRIDGE_TB_XLS_IRQ PIC_INTR_TO_IRQ(PIC_IRT_BRIDGE_TB_XLS_INDEX)
+/* end XLS */
+#define PIC_GMAC_0_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GMAC0_INDEX)
+#define PIC_GMAC_1_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GMAC1_INDEX)
+#define PIC_GMAC_2_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GMAC2_INDEX)
+#define PIC_GMAC_3_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GMAC3_INDEX)
+#define PIC_XGS_0_IRQ PIC_INTR_TO_IRQ(PIC_IRT_XGS0_INDEX)
+#define PIC_XGS_1_IRQ PIC_INTR_TO_IRQ(PIC_IRT_XGS1_INDEX)
+#define PIC_HYPER_FATAL_IRQ PIC_INTR_TO_IRQ(PIC_IRT_HYPER_FATAL_INDEX)
+#define PIC_PCIX_FATAL_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIX_FATAL_INDEX)
+#define PIC_BRIDGE_AERR_IRQ PIC_INTR_TO_IRQ(PIC_IRT_BRIDGE_AERR_INDEX)
+#define PIC_BRIDGE_BERR_IRQ PIC_INTR_TO_IRQ(PIC_IRT_BRIDGE_BERR_INDEX)
+#define PIC_BRIDGE_TB_XLR_IRQ PIC_INTR_TO_IRQ(PIC_IRT_BRIDGE_TB_XLR_INDEX)
+#define PIC_BRIDGE_AERR_NMI_IRQ PIC_INTR_TO_IRQ(PIC_IRT_BRIDGE_AERR_NMI_INDEX)
+/* XLS defines */
+#define PIC_GMAC_4_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GMAC4_INDEX)
+#define PIC_GMAC_5_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GMAC5_INDEX)
+#define PIC_GMAC_6_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GMAC6_INDEX)
+#define PIC_GMAC_7_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GMAC7_INDEX)
+#define PIC_BRIDGE_ERR_IRQ PIC_INTR_TO_IRQ(PIC_IRT_BRIDGE_ERR_INDEX)
+#define PIC_PCIE_LINK0_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_LINK0_INDEX)
+#define PIC_PCIE_LINK1_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_LINK1_INDEX)
+#define PIC_PCIE_LINK2_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_LINK2_INDEX)
+#define PIC_PCIE_LINK3_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_LINK3_INDEX)
+#define PIC_PCIE_XLSB0_LINK2_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_XLSB0_LINK2_INDEX)
+#define PIC_PCIE_XLSB0_LINK3_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_XLSB0_LINK3_INDEX)
+#define PIC_SRIO_LINK0_IRQ PIC_INTR_TO_IRQ(PIC_IRT_SRIO_LINK0_INDEX)
+#define PIC_SRIO_LINK1_IRQ PIC_INTR_TO_IRQ(PIC_IRT_SRIO_LINK1_INDEX)
+#define PIC_SRIO_LINK2_IRQ PIC_INTR_TO_IRQ(PIC_IRT_SRIO_LINK2_INDEX)
+#define PIC_SRIO_LINK3_IRQ PIC_INTR_TO_IRQ(PIC_IRT_SRIO_LINK3_INDEX)
+#define PIC_PCIE_INT_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_INT__INDEX)
+#define PIC_PCIE_FATAL_IRQ PIC_INTR_TO_IRQ(PIC_IRT_PCIE_FATAL_INDEX)
+#define PIC_GPIO_B_IRQ PIC_INTR_TO_IRQ(PIC_IRT_GPIO_B_INDEX)
+#define PIC_USB_IRQ PIC_INTR_TO_IRQ(PIC_IRT_USB_INDEX)
+#define PIC_IRT_LAST_IRQ PIC_USB_IRQ
+/* end XLS */
+
+#ifndef __ASSEMBLY__
+static inline void pic_send_ipi(u32 ipi)
+{
+ nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
+
+ netlogic_write_reg(mmio, PIC_IPI, ipi);
+}
+
+static inline u32 pic_read_control(void)
+{
+ nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
+
+ return netlogic_read_reg(mmio, PIC_CTRL);
+}
+
+static inline void pic_write_control(u32 control)
+{
+ nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
+
+ netlogic_write_reg(mmio, PIC_CTRL, control);
+}
+
+static inline void pic_update_control(u32 control)
+{
+ nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
+
+ netlogic_write_reg(mmio, PIC_CTRL,
+ (control | netlogic_read_reg(mmio, PIC_CTRL)));
+}
+
+#define PIC_IRQ_IS_EDGE_TRIGGERED(irq) (((irq) >= PIC_TIMER_0_IRQ) && \
+ ((irq) <= PIC_TIMER_7_IRQ))
+#define PIC_IRQ_IS_IRT(irq) (((irq) >= PIC_IRT_FIRST_IRQ) && \
+ ((irq) <= PIC_IRT_LAST_IRQ))
+#endif
+
+#endif /* _ASM_NLM_XLR_PIC_H */
diff --git a/arch/mips/include/asm/netlogic/xlr/xlr.h b/arch/mips/include/asm/netlogic/xlr/xlr.h
new file mode 100644
index 000000000000..3e6372692a04
--- /dev/null
+++ b/arch/mips/include/asm/netlogic/xlr/xlr.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _ASM_NLM_XLR_H
+#define _ASM_NLM_XLR_H
+
+/* Platform UART functions */
+struct uart_port;
+unsigned int nlm_xlr_uart_in(struct uart_port *, int);
+void nlm_xlr_uart_out(struct uart_port *, int, int);
+
+/* SMP support functions */
+struct irq_desc;
+void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc);
+void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc);
+int nlm_wakeup_secondary_cpus(u32 wakeup_mask);
+void nlm_smp_irq_init(void);
+void nlm_boot_smp_nmi(void);
+void prom_pre_boot_secondary_cpus(void);
+
+extern struct plat_smp_ops nlm_smp_ops;
+extern unsigned long nlm_common_ebase;
+
+/* XLS B silicon "Rook" */
+static inline unsigned int nlm_chip_is_xls_b(void)
+{
+ uint32_t prid = read_c0_prid();
+
+ return ((prid & 0xf000) == 0x4000);
+}
+
+/*
+ * XLR chip types
+ */
+ /* The XLS product line has chip versions 0x[48c]? */
+static inline unsigned int nlm_chip_is_xls(void)
+{
+ uint32_t prid = read_c0_prid();
+
+ return ((prid & 0xf000) == 0x8000 || (prid & 0xf000) == 0x4000 ||
+ (prid & 0xf000) == 0xc000);
+}
+
+#endif /* _ASM_NLM_XLR_H */
diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h
index 9f1b8dba2c81..de39b1f343ea 100644
--- a/arch/mips/include/asm/ptrace.h
+++ b/arch/mips/include/asm/ptrace.h
@@ -141,7 +141,8 @@ extern int ptrace_set_watch_regs(struct task_struct *child,
#define instruction_pointer(regs) ((regs)->cp0_epc)
#define profile_pc(regs) instruction_pointer(regs)
-extern asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit);
+extern asmlinkage void syscall_trace_enter(struct pt_regs *regs);
+extern asmlinkage void syscall_trace_leave(struct pt_regs *regs);
extern NORET_TYPE void die(const char *, struct pt_regs *) ATTRIB_NORET;
diff --git a/arch/mips/include/asm/r4kcache.h b/arch/mips/include/asm/r4kcache.h
index 387bf59f1e37..54ea47da59a1 100644
--- a/arch/mips/include/asm/r4kcache.h
+++ b/arch/mips/include/asm/r4kcache.h
@@ -5,7 +5,7 @@
*
* Inline assembly cache operations.
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
* Copyright (C) 1997 - 2002 Ralf Baechle (ralf@gnu.org)
* Copyright (C) 2004 Ralf Baechle (ralf@linux-mips.org)
*/
diff --git a/arch/mips/include/asm/sgialib.h b/arch/mips/include/asm/sgialib.h
index 2a2f1bddc276..f58115769457 100644
--- a/arch/mips/include/asm/sgialib.h
+++ b/arch/mips/include/asm/sgialib.h
@@ -5,7 +5,7 @@
*
* SGI ARCS firmware interface library for the Linux kernel.
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
* Copyright (C) 2001, 2002 Ralf Baechle (ralf@gnu.org)
*/
#ifndef _ASM_SGIALIB_H
diff --git a/arch/mips/include/asm/sgiarcs.h b/arch/mips/include/asm/sgiarcs.h
index 721327f88601..149342951436 100644
--- a/arch/mips/include/asm/sgiarcs.h
+++ b/arch/mips/include/asm/sgiarcs.h
@@ -5,7 +5,7 @@
*
* ARC firmware interface defines.
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
* Copyright (C) 1999, 2001 Ralf Baechle (ralf@gnu.org)
* Copyright (C) 1999 Silicon Graphics, Inc.
*/
diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h
index d71160de4d10..97f8bf6639e7 100644
--- a/arch/mips/include/asm/thread_info.h
+++ b/arch/mips/include/asm/thread_info.h
@@ -149,6 +149,9 @@ register struct thread_info *__current_thread_info __asm__("$28");
#define _TIF_FPUBOUND (1<<TIF_FPUBOUND)
#define _TIF_LOAD_WATCH (1<<TIF_LOAD_WATCH)
+/* work to do in syscall_trace_leave() */
+#define _TIF_WORK_SYSCALL_EXIT (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT)
+
/* work to do on interrupt/exception return */
#define _TIF_WORK_MASK (0x0000ffef & \
~(_TIF_SECCOMP | _TIF_SYSCALL_AUDIT))
diff --git a/arch/mips/include/asm/time.h b/arch/mips/include/asm/time.h
index c7f1bfef1574..bc14447e69b5 100644
--- a/arch/mips/include/asm/time.h
+++ b/arch/mips/include/asm/time.h
@@ -84,12 +84,6 @@ static inline int init_mips_clocksource(void)
#endif
}
-static inline void clocksource_set_clock(struct clocksource *cs,
- unsigned int clock)
-{
- clocksource_calc_mult_shift(cs, clock, 4);
-}
-
static inline void clockevent_set_clock(struct clock_event_device *cd,
unsigned int clock)
{
diff --git a/arch/mips/jz4740/setup.c b/arch/mips/jz4740/setup.c
index 6a9e14dab91e..d97cfbf882f5 100644
--- a/arch/mips/jz4740/setup.c
+++ b/arch/mips/jz4740/setup.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
+ * Copyright (C) 2011, Maarten ter Huurne <maarten@treewalker.org>
* JZ4740 setup code
*
* This program is free software; you can redistribute it and/or modify it
@@ -14,13 +15,44 @@
*/
#include <linux/init.h>
+#include <linux/io.h>
#include <linux/kernel.h>
+#include <asm/bootinfo.h>
+
+#include <asm/mach-jz4740/base.h>
+
#include "reset.h"
+
+#define JZ4740_EMC_SDRAM_CTRL 0x80
+
+
+static void __init jz4740_detect_mem(void)
+{
+ void __iomem *jz_emc_base;
+ u32 ctrl, bus, bank, rows, cols;
+ phys_t size;
+
+ jz_emc_base = ioremap(JZ4740_EMC_BASE_ADDR, 0x100);
+ ctrl = readl(jz_emc_base + JZ4740_EMC_SDRAM_CTRL);
+ bus = 2 - ((ctrl >> 31) & 1);
+ bank = 1 + ((ctrl >> 19) & 1);
+ cols = 8 + ((ctrl >> 26) & 7);
+ rows = 11 + ((ctrl >> 20) & 3);
+ printk(KERN_DEBUG
+ "SDRAM preconfigured: bus:%u bank:%u rows:%u cols:%u\n",
+ bus, bank, rows, cols);
+ iounmap(jz_emc_base);
+
+ size = 1 << (bus + bank + cols + rows);
+ add_memory_region(0, size, BOOT_MEM_RAM);
+}
+
void __init plat_mem_setup(void)
{
jz4740_reset_init();
+ jz4740_detect_mem();
}
const char *get_system_type(void)
diff --git a/arch/mips/jz4740/time.c b/arch/mips/jz4740/time.c
index eaa853a54af6..f83c2dd07a27 100644
--- a/arch/mips/jz4740/time.c
+++ b/arch/mips/jz4740/time.c
@@ -121,8 +121,7 @@ void __init plat_time_init(void)
clockevents_register_device(&jz4740_clockevent);
- clocksource_set_clock(&jz4740_clocksource, clk_rate);
- ret = clocksource_register(&jz4740_clocksource);
+ ret = clocksource_register_hz(&jz4740_clocksource, clk_rate);
if (ret)
printk(KERN_ERR "Failed to register clocksource: %d\n", ret);
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index cedee2bcbd18..83bba332bbfc 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_CPU_TX39XX) += r2300_fpu.o r2300_switch.o
obj-$(CONFIG_CPU_TX49XX) += r4k_fpu.o r4k_switch.o
obj-$(CONFIG_CPU_VR41XX) += r4k_fpu.o r4k_switch.o
obj-$(CONFIG_CPU_CAVIUM_OCTEON) += octeon_switch.o
+obj-$(CONFIG_CPU_XLR) += r4k_fpu.o r4k_switch.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_SMP_UP) += smp-up.o
diff --git a/arch/mips/kernel/cevt-txx9.c b/arch/mips/kernel/cevt-txx9.c
index 0b7377361e22..f0ab92a1b057 100644
--- a/arch/mips/kernel/cevt-txx9.c
+++ b/arch/mips/kernel/cevt-txx9.c
@@ -51,8 +51,7 @@ void __init txx9_clocksource_init(unsigned long baseaddr,
{
struct txx9_tmr_reg __iomem *tmrptr;
- clocksource_set_clock(&txx9_clocksource.cs, TIMER_CLK(imbusclk));
- clocksource_register(&txx9_clocksource.cs);
+ clocksource_register_hz(&txx9_clocksource.cs, TIMER_CLK(imbusclk));
tmrptr = ioremap(baseaddr, sizeof(struct txx9_tmr_reg));
__raw_writel(TCR_BASE, &tmrptr->tcr);
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index f65d4c8c65a6..bb133d10b145 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -291,6 +291,12 @@ static inline int cpu_has_confreg(void)
#endif
}
+static inline void set_elf_platform(int cpu, const char *plat)
+{
+ if (cpu == 0)
+ __elf_platform = plat;
+}
+
/*
* Get the FPU Implementation/Revision.
*/
@@ -614,6 +620,16 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
case PRID_IMP_LOONGSON2:
c->cputype = CPU_LOONGSON2;
__cpu_name[cpu] = "ICT Loongson-2";
+
+ switch (c->processor_id & PRID_REV_MASK) {
+ case PRID_REV_LOONGSON2E:
+ set_elf_platform(cpu, "loongson2e");
+ break;
+ case PRID_REV_LOONGSON2F:
+ set_elf_platform(cpu, "loongson2f");
+ break;
+ }
+
c->isa_level = MIPS_CPU_ISA_III;
c->options = R4K_OPTS |
MIPS_CPU_FPU | MIPS_CPU_LLSC |
@@ -911,12 +927,14 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
case PRID_IMP_BMIPS32_REV8:
c->cputype = CPU_BMIPS32;
__cpu_name[cpu] = "Broadcom BMIPS32";
+ set_elf_platform(cpu, "bmips32");
break;
case PRID_IMP_BMIPS3300:
case PRID_IMP_BMIPS3300_ALT:
case PRID_IMP_BMIPS3300_BUG:
c->cputype = CPU_BMIPS3300;
__cpu_name[cpu] = "Broadcom BMIPS3300";
+ set_elf_platform(cpu, "bmips3300");
break;
case PRID_IMP_BMIPS43XX: {
int rev = c->processor_id & 0xff;
@@ -925,15 +943,18 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
rev <= PRID_REV_BMIPS4380_HI) {
c->cputype = CPU_BMIPS4380;
__cpu_name[cpu] = "Broadcom BMIPS4380";
+ set_elf_platform(cpu, "bmips4380");
} else {
c->cputype = CPU_BMIPS4350;
__cpu_name[cpu] = "Broadcom BMIPS4350";
+ set_elf_platform(cpu, "bmips4350");
}
break;
}
case PRID_IMP_BMIPS5000:
c->cputype = CPU_BMIPS5000;
__cpu_name[cpu] = "Broadcom BMIPS5000";
+ set_elf_platform(cpu, "bmips5000");
c->options |= MIPS_CPU_ULRI;
break;
}
@@ -956,14 +977,12 @@ static inline void cpu_probe_cavium(struct cpuinfo_mips *c, unsigned int cpu)
c->cputype = CPU_CAVIUM_OCTEON_PLUS;
__cpu_name[cpu] = "Cavium Octeon+";
platform:
- if (cpu == 0)
- __elf_platform = "octeon";
+ set_elf_platform(cpu, "octeon");
break;
case PRID_IMP_CAVIUM_CN63XX:
c->cputype = CPU_CAVIUM_OCTEON2;
__cpu_name[cpu] = "Cavium Octeon II";
- if (cpu == 0)
- __elf_platform = "octeon2";
+ set_elf_platform(cpu, "octeon2");
break;
default:
printk(KERN_INFO "Unknown Octeon chip!\n");
@@ -988,6 +1007,59 @@ static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu)
}
}
+static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu)
+{
+ decode_configs(c);
+
+ c->options = (MIPS_CPU_TLB |
+ MIPS_CPU_4KEX |
+ MIPS_CPU_COUNTER |
+ MIPS_CPU_DIVEC |
+ MIPS_CPU_WATCH |
+ MIPS_CPU_EJTAG |
+ MIPS_CPU_LLSC);
+
+ switch (c->processor_id & 0xff00) {
+ case PRID_IMP_NETLOGIC_XLR732:
+ case PRID_IMP_NETLOGIC_XLR716:
+ case PRID_IMP_NETLOGIC_XLR532:
+ case PRID_IMP_NETLOGIC_XLR308:
+ case PRID_IMP_NETLOGIC_XLR532C:
+ case PRID_IMP_NETLOGIC_XLR516C:
+ case PRID_IMP_NETLOGIC_XLR508C:
+ case PRID_IMP_NETLOGIC_XLR308C:
+ c->cputype = CPU_XLR;
+ __cpu_name[cpu] = "Netlogic XLR";
+ break;
+
+ case PRID_IMP_NETLOGIC_XLS608:
+ case PRID_IMP_NETLOGIC_XLS408:
+ case PRID_IMP_NETLOGIC_XLS404:
+ case PRID_IMP_NETLOGIC_XLS208:
+ case PRID_IMP_NETLOGIC_XLS204:
+ case PRID_IMP_NETLOGIC_XLS108:
+ case PRID_IMP_NETLOGIC_XLS104:
+ case PRID_IMP_NETLOGIC_XLS616B:
+ case PRID_IMP_NETLOGIC_XLS608B:
+ case PRID_IMP_NETLOGIC_XLS416B:
+ case PRID_IMP_NETLOGIC_XLS412B:
+ case PRID_IMP_NETLOGIC_XLS408B:
+ case PRID_IMP_NETLOGIC_XLS404B:
+ c->cputype = CPU_XLR;
+ __cpu_name[cpu] = "Netlogic XLS";
+ break;
+
+ default:
+ printk(KERN_INFO "Unknown Netlogic chip id [%02x]!\n",
+ c->processor_id);
+ c->cputype = CPU_XLR;
+ break;
+ }
+
+ c->isa_level = MIPS_CPU_ISA_M64R1;
+ c->tlbsize = ((read_c0_config1() >> 25) & 0x3f) + 1;
+}
+
#ifdef CONFIG_64BIT
/* For use by uaccess.h */
u64 __ua_limit;
@@ -1035,6 +1107,9 @@ __cpuinit void cpu_probe(void)
case PRID_COMP_INGENIC:
cpu_probe_ingenic(c, cpu);
break;
+ case PRID_COMP_NETLOGIC:
+ cpu_probe_netlogic(c, cpu);
+ break;
}
BUG_ON(!__cpu_name[cpu]);
diff --git a/arch/mips/kernel/csrc-bcm1480.c b/arch/mips/kernel/csrc-bcm1480.c
index 51489f8a825e..f96f99c794a3 100644
--- a/arch/mips/kernel/csrc-bcm1480.c
+++ b/arch/mips/kernel/csrc-bcm1480.c
@@ -49,6 +49,5 @@ void __init sb1480_clocksource_init(void)
plldiv = G_BCM1480_SYS_PLL_DIV(__raw_readq(IOADDR(A_SCD_SYSTEM_CFG)));
zbbus = ((plldiv >> 1) * 50000000) + ((plldiv & 1) * 25000000);
- clocksource_set_clock(cs, zbbus);
- clocksource_register(cs);
+ clocksource_register_hz(cs, zbbus);
}
diff --git a/arch/mips/kernel/csrc-ioasic.c b/arch/mips/kernel/csrc-ioasic.c
index 23da108506b0..46bd7fa98d6c 100644
--- a/arch/mips/kernel/csrc-ioasic.c
+++ b/arch/mips/kernel/csrc-ioasic.c
@@ -59,7 +59,5 @@ void __init dec_ioasic_clocksource_init(void)
printk(KERN_INFO "I/O ASIC clock frequency %dHz\n", freq);
clocksource_dec.rating = 200 + freq / 10000000;
- clocksource_set_clock(&clocksource_dec, freq);
-
- clocksource_register(&clocksource_dec);
+ clocksource_register_hz(&clocksource_dec, freq);
}
diff --git a/arch/mips/kernel/csrc-powertv.c b/arch/mips/kernel/csrc-powertv.c
index a27c16c8690e..2e7c5232da8d 100644
--- a/arch/mips/kernel/csrc-powertv.c
+++ b/arch/mips/kernel/csrc-powertv.c
@@ -78,9 +78,7 @@ static void __init powertv_c0_hpt_clocksource_init(void)
clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000;
- clocksource_set_clock(&clocksource_mips, mips_hpt_frequency);
-
- clocksource_register(&clocksource_mips);
+ clocksource_register_hz(&clocksource_mips, mips_hpt_frequency);
}
/**
@@ -130,43 +128,16 @@ static struct clocksource clocksource_tim_c = {
/**
* powertv_tim_c_clocksource_init - set up a clock source for the TIM_C clock
*
- * The hard part here is coming up with a constant k and shift s such that
- * the 48-bit TIM_C value multiplied by k doesn't overflow and that value,
- * when shifted right by s, yields the corresponding number of nanoseconds.
* We know that TIM_C counts at 27 MHz/8, so each cycle corresponds to
- * 1 / (27,000,000/8) seconds. Multiply that by a billion and you get the
- * number of nanoseconds. Since the TIM_C value has 48 bits and the math is
- * done in 64 bits, avoiding an overflow means that k must be less than
- * 64 - 48 = 16 bits.
+ * 1 / (27,000,000/8) seconds.
*/
static void __init powertv_tim_c_clocksource_init(void)
{
- int prescale;
- unsigned long dividend;
- unsigned long k;
- int s;
- const int max_k_bits = (64 - 48) - 1;
- const unsigned long billion = 1000000000;
const unsigned long counts_per_second = 27000000 / 8;
- prescale = BITS_PER_LONG - ilog2(billion) - 1;
- dividend = billion << prescale;
- k = dividend / counts_per_second;
- s = ilog2(k) - max_k_bits;
-
- if (s < 0)
- s = prescale;
-
- else {
- k >>= s;
- s += prescale;
- }
-
- clocksource_tim_c.mult = k;
- clocksource_tim_c.shift = s;
clocksource_tim_c.rating = 200;
- clocksource_register(&clocksource_tim_c);
+ clocksource_register_hz(&clocksource_tim_c, counts_per_second);
tim_c = (struct tim_c *) asic_reg_addr(tim_ch);
}
diff --git a/arch/mips/kernel/csrc-r4k.c b/arch/mips/kernel/csrc-r4k.c
index e95a3cd48eea..decd1fa38d55 100644
--- a/arch/mips/kernel/csrc-r4k.c
+++ b/arch/mips/kernel/csrc-r4k.c
@@ -30,9 +30,7 @@ int __init init_r4k_clocksource(void)
/* Calculate a somewhat reasonable rating value */
clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000;
- clocksource_set_clock(&clocksource_mips, mips_hpt_frequency);
-
- clocksource_register(&clocksource_mips);
+ clocksource_register_hz(&clocksource_mips, mips_hpt_frequency);
return 0;
}
diff --git a/arch/mips/kernel/csrc-sb1250.c b/arch/mips/kernel/csrc-sb1250.c
index d14d3d1907fa..e9606d907685 100644
--- a/arch/mips/kernel/csrc-sb1250.c
+++ b/arch/mips/kernel/csrc-sb1250.c
@@ -65,6 +65,5 @@ void __init sb1250_clocksource_init(void)
IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM,
R_SCD_TIMER_CFG)));
- clocksource_set_clock(cs, V_SCD_TIMER_FREQ);
- clocksource_register(cs);
+ clocksource_register_hz(cs, V_SCD_TIMER_FREQ);
}
diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S
index ffa331029e08..37acfa036d44 100644
--- a/arch/mips/kernel/entry.S
+++ b/arch/mips/kernel/entry.S
@@ -167,14 +167,13 @@ work_notifysig: # deal with pending signals and
FEXPORT(syscall_exit_work_partial)
SAVE_STATIC
syscall_exit_work:
- li t0, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
+ li t0, _TIF_WORK_SYSCALL_EXIT
and t0, a2 # a2 is preloaded with TI_FLAGS
beqz t0, work_pending # trace bit set?
- local_irq_enable # could let do_syscall_trace()
+ local_irq_enable # could let syscall_trace_leave()
# call schedule() instead
move a0, sp
- li a1, 1
- jal do_syscall_trace
+ jal syscall_trace_leave
b resume_userspace
#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_MIPS_MT)
diff --git a/arch/mips/kernel/i8253.c b/arch/mips/kernel/i8253.c
index 2392a7a296d4..391221b6a6aa 100644
--- a/arch/mips/kernel/i8253.c
+++ b/arch/mips/kernel/i8253.c
@@ -125,87 +125,11 @@ void __init setup_pit_timer(void)
setup_irq(0, &irq0);
}
-/*
- * Since the PIT overflows every tick, its not very useful
- * to just read by itself. So use jiffies to emulate a free
- * running counter:
- */
-static cycle_t pit_read(struct clocksource *cs)
-{
- unsigned long flags;
- int count;
- u32 jifs;
- static int old_count;
- static u32 old_jifs;
-
- raw_spin_lock_irqsave(&i8253_lock, flags);
- /*
- * Although our caller may have the read side of xtime_lock,
- * this is now a seqlock, and we are cheating in this routine
- * by having side effects on state that we cannot undo if
- * there is a collision on the seqlock and our caller has to
- * retry. (Namely, old_jifs and old_count.) So we must treat
- * jiffies as volatile despite the lock. We read jiffies
- * before latching the timer count to guarantee that although
- * the jiffies value might be older than the count (that is,
- * the counter may underflow between the last point where
- * jiffies was incremented and the point where we latch the
- * count), it cannot be newer.
- */
- jifs = jiffies;
- outb_p(0x00, PIT_MODE); /* latch the count ASAP */
- count = inb_p(PIT_CH0); /* read the latched count */
- count |= inb_p(PIT_CH0) << 8;
-
- /* VIA686a test code... reset the latch if count > max + 1 */
- if (count > LATCH) {
- outb_p(0x34, PIT_MODE);
- outb_p(LATCH & 0xff, PIT_CH0);
- outb(LATCH >> 8, PIT_CH0);
- count = LATCH - 1;
- }
-
- /*
- * It's possible for count to appear to go the wrong way for a
- * couple of reasons:
- *
- * 1. The timer counter underflows, but we haven't handled the
- * resulting interrupt and incremented jiffies yet.
- * 2. Hardware problem with the timer, not giving us continuous time,
- * the counter does small "jumps" upwards on some Pentium systems,
- * (see c't 95/10 page 335 for Neptun bug.)
- *
- * Previous attempts to handle these cases intelligently were
- * buggy, so we just do the simple thing now.
- */
- if (count > old_count && jifs == old_jifs) {
- count = old_count;
- }
- old_count = count;
- old_jifs = jifs;
-
- raw_spin_unlock_irqrestore(&i8253_lock, flags);
-
- count = (LATCH - 1) - count;
-
- return (cycle_t)(jifs * LATCH) + count;
-}
-
-static struct clocksource clocksource_pit = {
- .name = "pit",
- .rating = 110,
- .read = pit_read,
- .mask = CLOCKSOURCE_MASK(32),
- .mult = 0,
- .shift = 20,
-};
-
static int __init init_pit_clocksource(void)
{
if (num_possible_cpus() > 1) /* PIT does not scale! */
return 0;
- clocksource_pit.mult = clocksource_hz2mult(CLOCK_TICK_RATE, 20);
- return clocksource_register(&clocksource_pit);
+ return clocksource_i8253_init();
}
arch_initcall(init_pit_clocksource);
diff --git a/arch/mips/kernel/octeon_switch.S b/arch/mips/kernel/octeon_switch.S
index dd18b26a358a..ce89c8061708 100644
--- a/arch/mips/kernel/octeon_switch.S
+++ b/arch/mips/kernel/octeon_switch.S
@@ -4,7 +4,7 @@
* for more details.
*
* Copyright (C) 1994, 1995, 1996, 1998, 1999, 2002, 2003 Ralf Baechle
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
* Copyright (C) 1994, 1995, 1996, by Andreas Busse
* Copyright (C) 1999 Silicon Graphics, Inc.
* Copyright (C) 2000 MIPS Technologies, Inc.
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 584e6b55c865..4e6ea1ffad46 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -533,15 +533,10 @@ static inline int audit_arch(void)
* Notification of system call entry/exit
* - triggered by current->work.syscall_trace
*/
-asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
+asmlinkage void syscall_trace_enter(struct pt_regs *regs)
{
/* do the secure computing check first */
- if (!entryexit)
- secure_computing(regs->regs[2]);
-
- if (unlikely(current->audit_context) && entryexit)
- audit_syscall_exit(AUDITSC_RESULT(regs->regs[7]),
- -regs->regs[2]);
+ secure_computing(regs->regs[2]);
if (!(current->ptrace & PT_PTRACED))
goto out;
@@ -565,8 +560,40 @@ asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
}
out:
- if (unlikely(current->audit_context) && !entryexit)
+ if (unlikely(current->audit_context))
audit_syscall_entry(audit_arch(), regs->regs[2],
regs->regs[4], regs->regs[5],
regs->regs[6], regs->regs[7]);
}
+
+/*
+ * Notification of system call entry/exit
+ * - triggered by current->work.syscall_trace
+ */
+asmlinkage void syscall_trace_leave(struct pt_regs *regs)
+{
+ if (unlikely(current->audit_context))
+ audit_syscall_exit(AUDITSC_RESULT(regs->regs[7]),
+ -regs->regs[2]);
+
+ if (!(current->ptrace & PT_PTRACED))
+ return;
+
+ if (!test_thread_flag(TIF_SYSCALL_TRACE))
+ return;
+
+ /* The 0x80 provides a way for the tracing parent to distinguish
+ between a syscall stop and SIGTRAP delivery */
+ ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ?
+ 0x80 : 0));
+
+ /*
+ * this isn't the same as continuing with a signal, but it will do
+ * for normal use. strace only continues with a signal if the
+ * stopping signal is not SIGTRAP. -brl
+ */
+ if (current->exit_code) {
+ send_sig(current->exit_code, current, 1);
+ current->exit_code = 0;
+ }
+}
diff --git a/arch/mips/kernel/r2300_fpu.S b/arch/mips/kernel/r2300_fpu.S
index ac68e68339db..61c8a0f2a60c 100644
--- a/arch/mips/kernel/r2300_fpu.S
+++ b/arch/mips/kernel/r2300_fpu.S
@@ -6,7 +6,7 @@
* Copyright (C) 1996, 1998 by Ralf Baechle
*
* Multi-arch abstraction and asm macros for easier reading:
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
*
* Further modifications to make this work:
* Copyright (c) 1998 Harald Koerfgen
diff --git a/arch/mips/kernel/r2300_switch.S b/arch/mips/kernel/r2300_switch.S
index 698414b7a253..293898391e67 100644
--- a/arch/mips/kernel/r2300_switch.S
+++ b/arch/mips/kernel/r2300_switch.S
@@ -5,7 +5,7 @@
* Copyright (C) 1994, 1995, 1996 by Andreas Busse
*
* Multi-cpu abstraction and macros for easier reading:
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
*
* Further modifications to make this work:
* Copyright (c) 1998-2000 Harald Koerfgen
diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S
index dbd42adc52ed..55ffe149dae9 100644
--- a/arch/mips/kernel/r4k_fpu.S
+++ b/arch/mips/kernel/r4k_fpu.S
@@ -6,7 +6,7 @@
* Copyright (C) 1996, 98, 99, 2000, 01 Ralf Baechle
*
* Multi-arch abstraction and asm macros for easier reading:
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
*
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 2000 MIPS Technologies, Inc.
diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S
index 8893ee1a2368..9414f9354469 100644
--- a/arch/mips/kernel/r4k_switch.S
+++ b/arch/mips/kernel/r4k_switch.S
@@ -4,7 +4,7 @@
* for more details.
*
* Copyright (C) 1994, 1995, 1996, 1998, 1999, 2002, 2003 Ralf Baechle
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
* Copyright (C) 1994, 1995, 1996, by Andreas Busse
* Copyright (C) 1999 Silicon Graphics, Inc.
* Copyright (C) 2000 MIPS Technologies, Inc.
diff --git a/arch/mips/kernel/r6000_fpu.S b/arch/mips/kernel/r6000_fpu.S
index 43cda53f5af6..da0fbe46d83b 100644
--- a/arch/mips/kernel/r6000_fpu.S
+++ b/arch/mips/kernel/r6000_fpu.S
@@ -8,7 +8,7 @@
* Copyright (C) 1996 by Ralf Baechle
*
* Multi-arch abstraction and asm macros for easier reading:
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
*/
#include <asm/asm.h>
#include <asm/fpregdef.h>
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index 7f1377eb22d3..7a8e1dd7f6f2 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -88,8 +88,7 @@ syscall_trace_entry:
SAVE_STATIC
move s0, t2
move a0, sp
- li a1, 0
- jal do_syscall_trace
+ jal syscall_trace_enter
move t0, s0
RESTORE_STATIC
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index 7c0ef7f128bf..2d31c83224f9 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -91,8 +91,7 @@ syscall_trace_entry:
SAVE_STATIC
move s0, t2
move a0, sp
- li a1, 0
- jal do_syscall_trace
+ jal syscall_trace_enter
move t0, s0
RESTORE_STATIC
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index de6c5563beab..38a0503b9a4a 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -89,8 +89,7 @@ n32_syscall_trace_entry:
SAVE_STATIC
move s0, t2
move a0, sp
- li a1, 0
- jal do_syscall_trace
+ jal syscall_trace_enter
move t0, s0
RESTORE_STATIC
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index b0541dda8830..91ea5e4041dd 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -123,8 +123,7 @@ trace_a_syscall:
move s0, t2 # Save syscall pointer
move a0, sp
- li a1, 0
- jal do_syscall_trace
+ jal syscall_trace_enter
move t0, s0
RESTORE_STATIC
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
index 5a88cc4ccd5a..cedac4633741 100644
--- a/arch/mips/kernel/smtc.c
+++ b/arch/mips/kernel/smtc.c
@@ -929,7 +929,7 @@ static void post_direct_ipi(int cpu, struct smtc_ipi *pipi)
static void ipi_resched_interrupt(void)
{
- /* Return from interrupt should be enough to cause scheduler check */
+ scheduler_ipi();
}
static void ipi_call_interrupt(void)
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index 58beabf50b3c..d02765708ddb 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -10,12 +10,9 @@
#include <linux/capability.h>
#include <linux/errno.h>
#include <linux/linkage.h>
-#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/smp.h>
-#include <linux/mman.h>
#include <linux/ptrace.h>
-#include <linux/sched.h>
#include <linux/string.h>
#include <linux/syscalls.h>
#include <linux/file.h>
@@ -25,11 +22,9 @@
#include <linux/msg.h>
#include <linux/shm.h>
#include <linux/compiler.h>
-#include <linux/module.h>
#include <linux/ipc.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
-#include <linux/random.h>
#include <linux/elf.h>
#include <asm/asm.h>
@@ -66,121 +61,6 @@ out:
return res;
}
-unsigned long shm_align_mask = PAGE_SIZE - 1; /* Sane caches */
-
-EXPORT_SYMBOL(shm_align_mask);
-
-#define COLOUR_ALIGN(addr,pgoff) \
- ((((addr) + shm_align_mask) & ~shm_align_mask) + \
- (((pgoff) << PAGE_SHIFT) & shm_align_mask))
-
-unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
- unsigned long len, unsigned long pgoff, unsigned long flags)
-{
- struct vm_area_struct * vmm;
- int do_color_align;
- unsigned long task_size;
-
-#ifdef CONFIG_32BIT
- task_size = TASK_SIZE;
-#else /* Must be CONFIG_64BIT*/
- task_size = test_thread_flag(TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE;
-#endif
-
- if (len > task_size)
- return -ENOMEM;
-
- if (flags & MAP_FIXED) {
- /* Even MAP_FIXED mappings must reside within task_size. */
- if (task_size - len < addr)
- return -EINVAL;
-
- /*
- * We do not accept a shared mapping if it would violate
- * cache aliasing constraints.
- */
- if ((flags & MAP_SHARED) &&
- ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask))
- return -EINVAL;
- return addr;
- }
-
- do_color_align = 0;
- if (filp || (flags & MAP_SHARED))
- do_color_align = 1;
- if (addr) {
- if (do_color_align)
- addr = COLOUR_ALIGN(addr, pgoff);
- else
- addr = PAGE_ALIGN(addr);
- vmm = find_vma(current->mm, addr);
- if (task_size - len >= addr &&
- (!vmm || addr + len <= vmm->vm_start))
- return addr;
- }
- addr = current->mm->mmap_base;
- if (do_color_align)
- addr = COLOUR_ALIGN(addr, pgoff);
- else
- addr = PAGE_ALIGN(addr);
-
- for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
- /* At this point: (!vmm || addr < vmm->vm_end). */
- if (task_size - len < addr)
- return -ENOMEM;
- if (!vmm || addr + len <= vmm->vm_start)
- return addr;
- addr = vmm->vm_end;
- if (do_color_align)
- addr = COLOUR_ALIGN(addr, pgoff);
- }
-}
-
-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/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
index e4b0b0bec039..a81176f44c74 100644
--- a/arch/mips/kernel/vmlinux.lds.S
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -65,9 +65,11 @@ SECTIONS
NOTES :text :note
.dummy : { *(.dummy) } :text
+ _sdata = .; /* Start of data section */
RODATA
/* writeable */
+ _sdata = .; /* Start of data section */
.data : { /* Data */
. = . + DATAOFFSET; /* for CONFIG_MAPPED_KERNEL */
@@ -116,7 +118,7 @@ SECTIONS
EXIT_DATA
}
- PERCPU(1 << CONFIG_MIPS_L1_CACHE_SHIFT, PAGE_SIZE)
+ PERCPU_SECTION(1 << CONFIG_MIPS_L1_CACHE_SHIFT)
. = ALIGN(PAGE_SIZE);
__init_end = .;
/* freed after init ends here */
diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig
new file mode 100644
index 000000000000..3fccf2104513
--- /dev/null
+++ b/arch/mips/lantiq/Kconfig
@@ -0,0 +1,23 @@
+if LANTIQ
+
+config SOC_TYPE_XWAY
+ bool
+ default n
+
+choice
+ prompt "SoC Type"
+ default SOC_XWAY
+
+config SOC_AMAZON_SE
+ bool "Amazon SE"
+ select SOC_TYPE_XWAY
+
+config SOC_XWAY
+ bool "XWAY"
+ select SOC_TYPE_XWAY
+ select HW_HAS_PCI
+endchoice
+
+source "arch/mips/lantiq/xway/Kconfig"
+
+endif
diff --git a/arch/mips/lantiq/Makefile b/arch/mips/lantiq/Makefile
new file mode 100644
index 000000000000..e5dae0e24b00
--- /dev/null
+++ b/arch/mips/lantiq/Makefile
@@ -0,0 +1,11 @@
+# Copyright (C) 2010 John Crispin <blogic@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.
+
+obj-y := irq.o setup.o clk.o prom.o devices.o
+
+obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+
+obj-$(CONFIG_SOC_TYPE_XWAY) += xway/
diff --git a/arch/mips/lantiq/Platform b/arch/mips/lantiq/Platform
new file mode 100644
index 000000000000..f3dff05722de
--- /dev/null
+++ b/arch/mips/lantiq/Platform
@@ -0,0 +1,8 @@
+#
+# Lantiq
+#
+
+platform-$(CONFIG_LANTIQ) += lantiq/
+cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq
+load-$(CONFIG_LANTIQ) = 0xffffffff80002000
+cflags-$(CONFIG_SOC_TYPE_XWAY) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/xway
diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c
new file mode 100644
index 000000000000..94560899d13e
--- /dev/null
+++ b/arch/mips/lantiq/clk.c
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com>
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/list.h>
+
+#include <asm/time.h>
+#include <asm/irq.h>
+#include <asm/div64.h>
+
+#include <lantiq_soc.h>
+
+#include "clk.h"
+
+struct clk {
+ const char *name;
+ unsigned long rate;
+ unsigned long (*get_rate) (void);
+};
+
+static struct clk *cpu_clk;
+static int cpu_clk_cnt;
+
+/* lantiq socs have 3 static clocks */
+static struct clk cpu_clk_generic[] = {
+ {
+ .name = "cpu",
+ .get_rate = ltq_get_cpu_hz,
+ }, {
+ .name = "fpi",
+ .get_rate = ltq_get_fpi_hz,
+ }, {
+ .name = "io",
+ .get_rate = ltq_get_io_region_clock,
+ },
+};
+
+static struct resource ltq_cgu_resource = {
+ .name = "cgu",
+ .start = LTQ_CGU_BASE_ADDR,
+ .end = LTQ_CGU_BASE_ADDR + LTQ_CGU_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+/* remapped clock register range */
+void __iomem *ltq_cgu_membase;
+
+void clk_init(void)
+{
+ cpu_clk = cpu_clk_generic;
+ cpu_clk_cnt = ARRAY_SIZE(cpu_clk_generic);
+}
+
+static inline int clk_good(struct clk *clk)
+{
+ return clk && !IS_ERR(clk);
+}
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ if (unlikely(!clk_good(clk)))
+ return 0;
+
+ if (clk->rate != 0)
+ return clk->rate;
+
+ if (clk->get_rate != NULL)
+ return clk->get_rate();
+
+ return 0;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+ int i;
+
+ for (i = 0; i < cpu_clk_cnt; i++)
+ if (!strcmp(id, cpu_clk[i].name))
+ return &cpu_clk[i];
+ BUG();
+ return ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL(clk_get);
+
+void clk_put(struct clk *clk)
+{
+ /* not used */
+}
+EXPORT_SYMBOL(clk_put);
+
+static inline u32 ltq_get_counter_resolution(void)
+{
+ u32 res;
+
+ __asm__ __volatile__(
+ ".set push\n"
+ ".set mips32r2\n"
+ "rdhwr %0, $3\n"
+ ".set pop\n"
+ : "=&r" (res)
+ : /* no input */
+ : "memory");
+
+ return res;
+}
+
+void __init plat_time_init(void)
+{
+ struct clk *clk;
+
+ if (insert_resource(&iomem_resource, &ltq_cgu_resource) < 0)
+ panic("Failed to insert cgu memory\n");
+
+ if (request_mem_region(ltq_cgu_resource.start,
+ resource_size(&ltq_cgu_resource), "cgu") < 0)
+ panic("Failed to request cgu memory\n");
+
+ ltq_cgu_membase = ioremap_nocache(ltq_cgu_resource.start,
+ resource_size(&ltq_cgu_resource));
+ if (!ltq_cgu_membase) {
+ pr_err("Failed to remap cgu memory\n");
+ unreachable();
+ }
+ clk = clk_get(0, "cpu");
+ mips_hpt_frequency = clk_get_rate(clk) / ltq_get_counter_resolution();
+ write_c0_compare(read_c0_count());
+ clk_put(clk);
+}
diff --git a/arch/mips/lantiq/clk.h b/arch/mips/lantiq/clk.h
new file mode 100644
index 000000000000..3328925f2c3f
--- /dev/null
+++ b/arch/mips/lantiq/clk.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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LTQ_CLK_H__
+#define _LTQ_CLK_H__
+
+extern void clk_init(void);
+
+extern unsigned long ltq_get_cpu_hz(void);
+extern unsigned long ltq_get_fpi_hz(void);
+extern unsigned long ltq_get_io_region_clock(void);
+
+#endif
diff --git a/arch/mips/lantiq/devices.c b/arch/mips/lantiq/devices.c
new file mode 100644
index 000000000000..7b82c34cb169
--- /dev/null
+++ b/arch/mips/lantiq/devices.c
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/etherdevice.h>
+#include <linux/reboot.h>
+#include <linux/time.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+
+#include <lantiq_soc.h>
+
+#include "devices.h"
+
+/* nor flash */
+static struct resource ltq_nor_resource = {
+ .name = "nor",
+ .start = LTQ_FLASH_START,
+ .end = LTQ_FLASH_START + LTQ_FLASH_MAX - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device ltq_nor = {
+ .name = "ltq_nor",
+ .resource = &ltq_nor_resource,
+ .num_resources = 1,
+};
+
+void __init ltq_register_nor(struct physmap_flash_data *data)
+{
+ ltq_nor.dev.platform_data = data;
+ platform_device_register(&ltq_nor);
+}
+
+/* watchdog */
+static struct resource ltq_wdt_resource = {
+ .name = "watchdog",
+ .start = LTQ_WDT_BASE_ADDR,
+ .end = LTQ_WDT_BASE_ADDR + LTQ_WDT_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+void __init ltq_register_wdt(void)
+{
+ platform_device_register_simple("ltq_wdt", 0, &ltq_wdt_resource, 1);
+}
+
+/* asc ports */
+static struct resource ltq_asc0_resources[] = {
+ {
+ .name = "asc0",
+ .start = LTQ_ASC0_BASE_ADDR,
+ .end = LTQ_ASC0_BASE_ADDR + LTQ_ASC_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ IRQ_RES(tx, LTQ_ASC_TIR(0)),
+ IRQ_RES(rx, LTQ_ASC_RIR(0)),
+ IRQ_RES(err, LTQ_ASC_EIR(0)),
+};
+
+static struct resource ltq_asc1_resources[] = {
+ {
+ .name = "asc1",
+ .start = LTQ_ASC1_BASE_ADDR,
+ .end = LTQ_ASC1_BASE_ADDR + LTQ_ASC_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ IRQ_RES(tx, LTQ_ASC_TIR(1)),
+ IRQ_RES(rx, LTQ_ASC_RIR(1)),
+ IRQ_RES(err, LTQ_ASC_EIR(1)),
+};
+
+void __init ltq_register_asc(int port)
+{
+ switch (port) {
+ case 0:
+ platform_device_register_simple("ltq_asc", 0,
+ ltq_asc0_resources, ARRAY_SIZE(ltq_asc0_resources));
+ break;
+ case 1:
+ platform_device_register_simple("ltq_asc", 1,
+ ltq_asc1_resources, ARRAY_SIZE(ltq_asc1_resources));
+ break;
+ default:
+ break;
+ }
+}
+
+#ifdef CONFIG_PCI
+/* pci */
+static struct platform_device ltq_pci = {
+ .name = "ltq_pci",
+ .num_resources = 0,
+};
+
+void __init ltq_register_pci(struct ltq_pci_data *data)
+{
+ ltq_pci.dev.platform_data = data;
+ platform_device_register(&ltq_pci);
+}
+#else
+void __init ltq_register_pci(struct ltq_pci_data *data)
+{
+ pr_err("kernel is compiled without PCI support\n");
+}
+#endif
diff --git a/arch/mips/lantiq/devices.h b/arch/mips/lantiq/devices.h
new file mode 100644
index 000000000000..2947bb19a528
--- /dev/null
+++ b/arch/mips/lantiq/devices.h
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LTQ_DEVICES_H__
+#define _LTQ_DEVICES_H__
+
+#include <lantiq_platform.h>
+#include <linux/mtd/physmap.h>
+
+#define IRQ_RES(resname, irq) \
+ {.name = #resname, .start = (irq), .flags = IORESOURCE_IRQ}
+
+extern void ltq_register_nor(struct physmap_flash_data *data);
+extern void ltq_register_wdt(void);
+extern void ltq_register_asc(int port);
+extern void ltq_register_pci(struct ltq_pci_data *data);
+
+#endif
diff --git a/arch/mips/lantiq/early_printk.c b/arch/mips/lantiq/early_printk.c
new file mode 100644
index 000000000000..972e05f87631
--- /dev/null
+++ b/arch/mips/lantiq/early_printk.c
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/cpu.h>
+
+#include <lantiq.h>
+#include <lantiq_soc.h>
+
+/* no ioremap possible at this early stage, lets use KSEG1 instead */
+#define LTQ_ASC_BASE KSEG1ADDR(LTQ_ASC1_BASE_ADDR)
+#define ASC_BUF 1024
+#define LTQ_ASC_FSTAT ((u32 *)(LTQ_ASC_BASE + 0x0048))
+#define LTQ_ASC_TBUF ((u32 *)(LTQ_ASC_BASE + 0x0020))
+#define TXMASK 0x3F00
+#define TXOFFSET 8
+
+void prom_putchar(char c)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ do { } while ((ltq_r32(LTQ_ASC_FSTAT) & TXMASK) >> TXOFFSET);
+ if (c == '\n')
+ ltq_w32('\r', LTQ_ASC_TBUF);
+ ltq_w32(c, LTQ_ASC_TBUF);
+ local_irq_restore(flags);
+}
diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c
new file mode 100644
index 000000000000..fc89795cafdb
--- /dev/null
+++ b/arch/mips/lantiq/irq.c
@@ -0,0 +1,326 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com>
+ */
+
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+
+#include <asm/bootinfo.h>
+#include <asm/irq_cpu.h>
+
+#include <lantiq_soc.h>
+#include <irq.h>
+
+/* register definitions */
+#define LTQ_ICU_IM0_ISR 0x0000
+#define LTQ_ICU_IM0_IER 0x0008
+#define LTQ_ICU_IM0_IOSR 0x0010
+#define LTQ_ICU_IM0_IRSR 0x0018
+#define LTQ_ICU_IM0_IMR 0x0020
+#define LTQ_ICU_IM1_ISR 0x0028
+#define LTQ_ICU_OFFSET (LTQ_ICU_IM1_ISR - LTQ_ICU_IM0_ISR)
+
+#define LTQ_EIU_EXIN_C 0x0000
+#define LTQ_EIU_EXIN_INIC 0x0004
+#define LTQ_EIU_EXIN_INEN 0x000C
+
+/* irq numbers used by the external interrupt unit (EIU) */
+#define LTQ_EIU_IR0 (INT_NUM_IM4_IRL0 + 30)
+#define LTQ_EIU_IR1 (INT_NUM_IM3_IRL0 + 31)
+#define LTQ_EIU_IR2 (INT_NUM_IM1_IRL0 + 26)
+#define LTQ_EIU_IR3 INT_NUM_IM1_IRL0
+#define LTQ_EIU_IR4 (INT_NUM_IM1_IRL0 + 1)
+#define LTQ_EIU_IR5 (INT_NUM_IM1_IRL0 + 2)
+#define LTQ_EIU_IR6 (INT_NUM_IM2_IRL0 + 30)
+
+#define MAX_EIU 6
+
+/* irqs generated by device attached to the EBU need to be acked in
+ * a special manner
+ */
+#define LTQ_ICU_EBU_IRQ 22
+
+#define ltq_icu_w32(x, y) ltq_w32((x), ltq_icu_membase + (y))
+#define ltq_icu_r32(x) ltq_r32(ltq_icu_membase + (x))
+
+#define ltq_eiu_w32(x, y) ltq_w32((x), ltq_eiu_membase + (y))
+#define ltq_eiu_r32(x) ltq_r32(ltq_eiu_membase + (x))
+
+static unsigned short ltq_eiu_irq[MAX_EIU] = {
+ LTQ_EIU_IR0,
+ LTQ_EIU_IR1,
+ LTQ_EIU_IR2,
+ LTQ_EIU_IR3,
+ LTQ_EIU_IR4,
+ LTQ_EIU_IR5,
+};
+
+static struct resource ltq_icu_resource = {
+ .name = "icu",
+ .start = LTQ_ICU_BASE_ADDR,
+ .end = LTQ_ICU_BASE_ADDR + LTQ_ICU_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct resource ltq_eiu_resource = {
+ .name = "eiu",
+ .start = LTQ_EIU_BASE_ADDR,
+ .end = LTQ_EIU_BASE_ADDR + LTQ_ICU_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static void __iomem *ltq_icu_membase;
+static void __iomem *ltq_eiu_membase;
+
+void ltq_disable_irq(struct irq_data *d)
+{
+ u32 ier = LTQ_ICU_IM0_IER;
+ int irq_nr = d->irq - INT_NUM_IRQ0;
+
+ ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
+ irq_nr %= INT_NUM_IM_OFFSET;
+ ltq_icu_w32(ltq_icu_r32(ier) & ~(1 << irq_nr), ier);
+}
+
+void ltq_mask_and_ack_irq(struct irq_data *d)
+{
+ u32 ier = LTQ_ICU_IM0_IER;
+ u32 isr = LTQ_ICU_IM0_ISR;
+ int irq_nr = d->irq - INT_NUM_IRQ0;
+
+ ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
+ isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
+ irq_nr %= INT_NUM_IM_OFFSET;
+ ltq_icu_w32(ltq_icu_r32(ier) & ~(1 << irq_nr), ier);
+ ltq_icu_w32((1 << irq_nr), isr);
+}
+
+static void ltq_ack_irq(struct irq_data *d)
+{
+ u32 isr = LTQ_ICU_IM0_ISR;
+ int irq_nr = d->irq - INT_NUM_IRQ0;
+
+ isr += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
+ irq_nr %= INT_NUM_IM_OFFSET;
+ ltq_icu_w32((1 << irq_nr), isr);
+}
+
+void ltq_enable_irq(struct irq_data *d)
+{
+ u32 ier = LTQ_ICU_IM0_IER;
+ int irq_nr = d->irq - INT_NUM_IRQ0;
+
+ ier += LTQ_ICU_OFFSET * (irq_nr / INT_NUM_IM_OFFSET);
+ irq_nr %= INT_NUM_IM_OFFSET;
+ ltq_icu_w32(ltq_icu_r32(ier) | (1 << irq_nr), ier);
+}
+
+static unsigned int ltq_startup_eiu_irq(struct irq_data *d)
+{
+ int i;
+ int irq_nr = d->irq - INT_NUM_IRQ0;
+
+ ltq_enable_irq(d);
+ for (i = 0; i < MAX_EIU; i++) {
+ if (irq_nr == ltq_eiu_irq[i]) {
+ /* low level - we should really handle set_type */
+ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_C) |
+ (0x6 << (i * 4)), LTQ_EIU_EXIN_C);
+ /* clear all pending */
+ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INIC) & ~(1 << i),
+ LTQ_EIU_EXIN_INIC);
+ /* enable */
+ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) | (1 << i),
+ LTQ_EIU_EXIN_INEN);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static void ltq_shutdown_eiu_irq(struct irq_data *d)
+{
+ int i;
+ int irq_nr = d->irq - INT_NUM_IRQ0;
+
+ ltq_disable_irq(d);
+ for (i = 0; i < MAX_EIU; i++) {
+ if (irq_nr == ltq_eiu_irq[i]) {
+ /* disable */
+ ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~(1 << i),
+ LTQ_EIU_EXIN_INEN);
+ break;
+ }
+ }
+}
+
+static struct irq_chip ltq_irq_type = {
+ "icu",
+ .irq_enable = ltq_enable_irq,
+ .irq_disable = ltq_disable_irq,
+ .irq_unmask = ltq_enable_irq,
+ .irq_ack = ltq_ack_irq,
+ .irq_mask = ltq_disable_irq,
+ .irq_mask_ack = ltq_mask_and_ack_irq,
+};
+
+static struct irq_chip ltq_eiu_type = {
+ "eiu",
+ .irq_startup = ltq_startup_eiu_irq,
+ .irq_shutdown = ltq_shutdown_eiu_irq,
+ .irq_enable = ltq_enable_irq,
+ .irq_disable = ltq_disable_irq,
+ .irq_unmask = ltq_enable_irq,
+ .irq_ack = ltq_ack_irq,
+ .irq_mask = ltq_disable_irq,
+ .irq_mask_ack = ltq_mask_and_ack_irq,
+};
+
+static void ltq_hw_irqdispatch(int module)
+{
+ u32 irq;
+
+ irq = ltq_icu_r32(LTQ_ICU_IM0_IOSR + (module * LTQ_ICU_OFFSET));
+ if (irq == 0)
+ return;
+
+ /* silicon bug causes only the msb set to 1 to be valid. all
+ * other bits might be bogus
+ */
+ irq = __fls(irq);
+ do_IRQ((int)irq + INT_NUM_IM0_IRL0 + (INT_NUM_IM_OFFSET * module));
+
+ /* if this is a EBU irq, we need to ack it or get a deadlock */
+ if ((irq == LTQ_ICU_EBU_IRQ) && (module == 0))
+ ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_ISTAT) | 0x10,
+ LTQ_EBU_PCC_ISTAT);
+}
+
+#define DEFINE_HWx_IRQDISPATCH(x) \
+ static void ltq_hw ## x ## _irqdispatch(void) \
+ { \
+ ltq_hw_irqdispatch(x); \
+ }
+DEFINE_HWx_IRQDISPATCH(0)
+DEFINE_HWx_IRQDISPATCH(1)
+DEFINE_HWx_IRQDISPATCH(2)
+DEFINE_HWx_IRQDISPATCH(3)
+DEFINE_HWx_IRQDISPATCH(4)
+
+static void ltq_hw5_irqdispatch(void)
+{
+ do_IRQ(MIPS_CPU_TIMER_IRQ);
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+ unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
+ unsigned int i;
+
+ if (pending & CAUSEF_IP7) {
+ do_IRQ(MIPS_CPU_TIMER_IRQ);
+ goto out;
+ } else {
+ for (i = 0; i < 5; i++) {
+ if (pending & (CAUSEF_IP2 << i)) {
+ ltq_hw_irqdispatch(i);
+ goto out;
+ }
+ }
+ }
+ pr_alert("Spurious IRQ: CAUSE=0x%08x\n", read_c0_status());
+
+out:
+ return;
+}
+
+static struct irqaction cascade = {
+ .handler = no_action,
+ .flags = IRQF_DISABLED,
+ .name = "cascade",
+};
+
+void __init arch_init_irq(void)
+{
+ int i;
+
+ if (insert_resource(&iomem_resource, &ltq_icu_resource) < 0)
+ panic("Failed to insert icu memory\n");
+
+ if (request_mem_region(ltq_icu_resource.start,
+ resource_size(&ltq_icu_resource), "icu") < 0)
+ panic("Failed to request icu memory\n");
+
+ ltq_icu_membase = ioremap_nocache(ltq_icu_resource.start,
+ resource_size(&ltq_icu_resource));
+ if (!ltq_icu_membase)
+ panic("Failed to remap icu memory\n");
+
+ if (insert_resource(&iomem_resource, &ltq_eiu_resource) < 0)
+ panic("Failed to insert eiu memory\n");
+
+ if (request_mem_region(ltq_eiu_resource.start,
+ resource_size(&ltq_eiu_resource), "eiu") < 0)
+ panic("Failed to request eiu memory\n");
+
+ ltq_eiu_membase = ioremap_nocache(ltq_eiu_resource.start,
+ resource_size(&ltq_eiu_resource));
+ if (!ltq_eiu_membase)
+ panic("Failed to remap eiu memory\n");
+
+ /* make sure all irqs are turned off by default */
+ for (i = 0; i < 5; i++)
+ ltq_icu_w32(0, LTQ_ICU_IM0_IER + (i * LTQ_ICU_OFFSET));
+
+ /* clear all possibly pending interrupts */
+ ltq_icu_w32(~0, LTQ_ICU_IM0_ISR + (i * LTQ_ICU_OFFSET));
+
+ mips_cpu_irq_init();
+
+ for (i = 2; i <= 6; i++)
+ setup_irq(i, &cascade);
+
+ if (cpu_has_vint) {
+ pr_info("Setting up vectored interrupts\n");
+ set_vi_handler(2, ltq_hw0_irqdispatch);
+ set_vi_handler(3, ltq_hw1_irqdispatch);
+ set_vi_handler(4, ltq_hw2_irqdispatch);
+ set_vi_handler(5, ltq_hw3_irqdispatch);
+ set_vi_handler(6, ltq_hw4_irqdispatch);
+ set_vi_handler(7, ltq_hw5_irqdispatch);
+ }
+
+ for (i = INT_NUM_IRQ0;
+ i <= (INT_NUM_IRQ0 + (5 * INT_NUM_IM_OFFSET)); i++)
+ if ((i == LTQ_EIU_IR0) || (i == LTQ_EIU_IR1) ||
+ (i == LTQ_EIU_IR2))
+ irq_set_chip_and_handler(i, &ltq_eiu_type,
+ handle_level_irq);
+ /* EIU3-5 only exist on ar9 and vr9 */
+ else if (((i == LTQ_EIU_IR3) || (i == LTQ_EIU_IR4) ||
+ (i == LTQ_EIU_IR5)) && (ltq_is_ar9() || ltq_is_vr9()))
+ irq_set_chip_and_handler(i, &ltq_eiu_type,
+ handle_level_irq);
+ else
+ irq_set_chip_and_handler(i, &ltq_irq_type,
+ handle_level_irq);
+
+#if !defined(CONFIG_MIPS_MT_SMP) && !defined(CONFIG_MIPS_MT_SMTC)
+ set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 |
+ IE_IRQ3 | IE_IRQ4 | IE_IRQ5);
+#else
+ set_c0_status(IE_SW0 | IE_SW1 | IE_IRQ0 | IE_IRQ1 |
+ IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5);
+#endif
+}
+
+unsigned int __cpuinit get_c0_compare_int(void)
+{
+ return CP0_LEGACY_COMPARE_IRQ;
+}
diff --git a/arch/mips/lantiq/machtypes.h b/arch/mips/lantiq/machtypes.h
new file mode 100644
index 000000000000..7e01b8c484eb
--- /dev/null
+++ b/arch/mips/lantiq/machtypes.h
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LANTIQ_MACH_H__
+#define _LANTIQ_MACH_H__
+
+#include <asm/mips_machine.h>
+
+enum lantiq_mach_type {
+ LTQ_MACH_GENERIC = 0,
+ LTQ_MACH_EASY50712, /* Danube evaluation board */
+ LTQ_MACH_EASY50601, /* Amazon SE evaluation board */
+};
+
+#endif
diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c
new file mode 100644
index 000000000000..56ba007bf1e5
--- /dev/null
+++ b/arch/mips/lantiq/prom.c
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <asm/bootinfo.h>
+#include <asm/time.h>
+
+#include <lantiq.h>
+
+#include "prom.h"
+#include "clk.h"
+
+static struct ltq_soc_info soc_info;
+
+unsigned int ltq_get_cpu_ver(void)
+{
+ return soc_info.rev;
+}
+EXPORT_SYMBOL(ltq_get_cpu_ver);
+
+unsigned int ltq_get_soc_type(void)
+{
+ return soc_info.type;
+}
+EXPORT_SYMBOL(ltq_get_soc_type);
+
+const char *get_system_type(void)
+{
+ return soc_info.sys_type;
+}
+
+void prom_free_prom_memory(void)
+{
+}
+
+static void __init prom_init_cmdline(void)
+{
+ int argc = fw_arg0;
+ char **argv = (char **) KSEG1ADDR(fw_arg1);
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ char *p = (char *) KSEG1ADDR(argv[i]);
+
+ if (p && *p) {
+ strlcat(arcs_cmdline, p, sizeof(arcs_cmdline));
+ strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline));
+ }
+ }
+}
+
+void __init prom_init(void)
+{
+ struct clk *clk;
+
+ ltq_soc_detect(&soc_info);
+ clk_init();
+ clk = clk_get(0, "cpu");
+ snprintf(soc_info.sys_type, LTQ_SYS_TYPE_LEN - 1, "%s rev1.%d",
+ soc_info.name, soc_info.rev);
+ clk_put(clk);
+ soc_info.sys_type[LTQ_SYS_TYPE_LEN - 1] = '\0';
+ pr_info("SoC: %s\n", soc_info.sys_type);
+ prom_init_cmdline();
+}
diff --git a/arch/mips/lantiq/prom.h b/arch/mips/lantiq/prom.h
new file mode 100644
index 000000000000..b4229d94280f
--- /dev/null
+++ b/arch/mips/lantiq/prom.h
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LTQ_PROM_H__
+#define _LTQ_PROM_H__
+
+#define LTQ_SYS_TYPE_LEN 0x100
+
+struct ltq_soc_info {
+ unsigned char *name;
+ unsigned int rev;
+ unsigned int partnum;
+ unsigned int type;
+ unsigned char sys_type[LTQ_SYS_TYPE_LEN];
+};
+
+extern void ltq_soc_detect(struct ltq_soc_info *i);
+extern void ltq_soc_setup(void);
+
+#endif
diff --git a/arch/mips/lantiq/setup.c b/arch/mips/lantiq/setup.c
new file mode 100644
index 000000000000..9b8af77ed0f9
--- /dev/null
+++ b/arch/mips/lantiq/setup.c
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <asm/bootinfo.h>
+
+#include <lantiq_soc.h>
+
+#include "machtypes.h"
+#include "devices.h"
+#include "prom.h"
+
+void __init plat_mem_setup(void)
+{
+ /* assume 16M as default incase uboot fails to pass proper ramsize */
+ unsigned long memsize = 16;
+ char **envp = (char **) KSEG1ADDR(fw_arg2);
+
+ ioport_resource.start = IOPORT_RESOURCE_START;
+ ioport_resource.end = IOPORT_RESOURCE_END;
+ iomem_resource.start = IOMEM_RESOURCE_START;
+ iomem_resource.end = IOMEM_RESOURCE_END;
+
+ set_io_port_base((unsigned long) KSEG1);
+
+ while (*envp) {
+ char *e = (char *)KSEG1ADDR(*envp);
+ if (!strncmp(e, "memsize=", 8)) {
+ e += 8;
+ if (strict_strtoul(e, 0, &memsize))
+ pr_warn("bad memsize specified\n");
+ }
+ envp++;
+ }
+ memsize *= 1024 * 1024;
+ add_memory_region(0x00000000, memsize, BOOT_MEM_RAM);
+}
+
+static int __init
+lantiq_setup(void)
+{
+ ltq_soc_setup();
+ mips_machine_setup();
+ return 0;
+}
+
+arch_initcall(lantiq_setup);
+
+static void __init
+lantiq_generic_init(void)
+{
+ /* Nothing to do */
+}
+
+MIPS_MACHINE(LTQ_MACH_GENERIC,
+ "Generic",
+ "Generic Lantiq based board",
+ lantiq_generic_init);
diff --git a/arch/mips/lantiq/xway/Kconfig b/arch/mips/lantiq/xway/Kconfig
new file mode 100644
index 000000000000..2b857de36620
--- /dev/null
+++ b/arch/mips/lantiq/xway/Kconfig
@@ -0,0 +1,23 @@
+if SOC_XWAY
+
+menu "MIPS Machine"
+
+config LANTIQ_MACH_EASY50712
+ bool "Easy50712 - Danube"
+ default y
+
+endmenu
+
+endif
+
+if SOC_AMAZON_SE
+
+menu "MIPS Machine"
+
+config LANTIQ_MACH_EASY50601
+ bool "Easy50601 - Amazon SE"
+ default y
+
+endmenu
+
+endif
diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile
new file mode 100644
index 000000000000..c517f2e77563
--- /dev/null
+++ b/arch/mips/lantiq/xway/Makefile
@@ -0,0 +1,7 @@
+obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o
+
+obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o setup-xway.o
+obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o setup-ase.o
+
+obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o
+obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o
diff --git a/arch/mips/lantiq/xway/clk-ase.c b/arch/mips/lantiq/xway/clk-ase.c
new file mode 100644
index 000000000000..22d823acd536
--- /dev/null
+++ b/arch/mips/lantiq/xway/clk-ase.c
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+
+#include <asm/time.h>
+#include <asm/irq.h>
+#include <asm/div64.h>
+
+#include <lantiq_soc.h>
+
+/* cgu registers */
+#define LTQ_CGU_SYS 0x0010
+
+unsigned int ltq_get_io_region_clock(void)
+{
+ return CLOCK_133M;
+}
+EXPORT_SYMBOL(ltq_get_io_region_clock);
+
+unsigned int ltq_get_fpi_bus_clock(int fpi)
+{
+ return CLOCK_133M;
+}
+EXPORT_SYMBOL(ltq_get_fpi_bus_clock);
+
+unsigned int ltq_get_cpu_hz(void)
+{
+ if (ltq_cgu_r32(LTQ_CGU_SYS) & (1 << 5))
+ return CLOCK_266M;
+ else
+ return CLOCK_133M;
+}
+EXPORT_SYMBOL(ltq_get_cpu_hz);
+
+unsigned int ltq_get_fpi_hz(void)
+{
+ return CLOCK_133M;
+}
+EXPORT_SYMBOL(ltq_get_fpi_hz);
diff --git a/arch/mips/lantiq/xway/clk-xway.c b/arch/mips/lantiq/xway/clk-xway.c
new file mode 100644
index 000000000000..ddd39593c581
--- /dev/null
+++ b/arch/mips/lantiq/xway/clk-xway.c
@@ -0,0 +1,223 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+
+#include <asm/time.h>
+#include <asm/irq.h>
+#include <asm/div64.h>
+
+#include <lantiq_soc.h>
+
+static unsigned int ltq_ram_clocks[] = {
+ CLOCK_167M, CLOCK_133M, CLOCK_111M, CLOCK_83M };
+#define DDR_HZ ltq_ram_clocks[ltq_cgu_r32(LTQ_CGU_SYS) & 0x3]
+
+#define BASIC_FREQUENCY_1 35328000
+#define BASIC_FREQUENCY_2 36000000
+#define BASIS_REQUENCY_USB 12000000
+
+#define GET_BITS(x, msb, lsb) \
+ (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb))
+
+#define LTQ_CGU_PLL0_CFG 0x0004
+#define LTQ_CGU_PLL1_CFG 0x0008
+#define LTQ_CGU_PLL2_CFG 0x000C
+#define LTQ_CGU_SYS 0x0010
+#define LTQ_CGU_UPDATE 0x0014
+#define LTQ_CGU_IF_CLK 0x0018
+#define LTQ_CGU_OSC_CON 0x001C
+#define LTQ_CGU_SMD 0x0020
+#define LTQ_CGU_CT1SR 0x0028
+#define LTQ_CGU_CT2SR 0x002C
+#define LTQ_CGU_PCMCR 0x0030
+#define LTQ_CGU_PCI_CR 0x0034
+#define LTQ_CGU_PD_PC 0x0038
+#define LTQ_CGU_FMR 0x003C
+
+#define CGU_PLL0_PHASE_DIVIDER_ENABLE \
+ (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 31))
+#define CGU_PLL0_BYPASS \
+ (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 30))
+#define CGU_PLL0_CFG_DSMSEL \
+ (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 28))
+#define CGU_PLL0_CFG_FRAC_EN \
+ (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 27))
+#define CGU_PLL1_SRC \
+ (ltq_cgu_r32(LTQ_CGU_PLL1_CFG) & (1 << 31))
+#define CGU_PLL2_PHASE_DIVIDER_ENABLE \
+ (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & (1 << 20))
+#define CGU_SYS_FPI_SEL (1 << 6)
+#define CGU_SYS_DDR_SEL 0x3
+#define CGU_PLL0_SRC (1 << 29)
+
+#define CGU_PLL0_CFG_PLLK GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 26, 17)
+#define CGU_PLL0_CFG_PLLN GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 12, 6)
+#define CGU_PLL0_CFG_PLLM GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 5, 2)
+#define CGU_PLL2_SRC GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 18, 17)
+#define CGU_PLL2_CFG_INPUT_DIV GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 16, 13)
+
+static unsigned int ltq_get_pll0_fdiv(void);
+
+static inline unsigned int get_input_clock(int pll)
+{
+ switch (pll) {
+ case 0:
+ if (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & CGU_PLL0_SRC)
+ return BASIS_REQUENCY_USB;
+ else if (CGU_PLL0_PHASE_DIVIDER_ENABLE)
+ return BASIC_FREQUENCY_1;
+ else
+ return BASIC_FREQUENCY_2;
+ case 1:
+ if (CGU_PLL1_SRC)
+ return BASIS_REQUENCY_USB;
+ else if (CGU_PLL0_PHASE_DIVIDER_ENABLE)
+ return BASIC_FREQUENCY_1;
+ else
+ return BASIC_FREQUENCY_2;
+ case 2:
+ switch (CGU_PLL2_SRC) {
+ case 0:
+ return ltq_get_pll0_fdiv();
+ case 1:
+ return CGU_PLL2_PHASE_DIVIDER_ENABLE ?
+ BASIC_FREQUENCY_1 :
+ BASIC_FREQUENCY_2;
+ case 2:
+ return BASIS_REQUENCY_USB;
+ }
+ default:
+ return 0;
+ }
+}
+
+static inline unsigned int cal_dsm(int pll, unsigned int num, unsigned int den)
+{
+ u64 res, clock = get_input_clock(pll);
+
+ res = num * clock;
+ do_div(res, den);
+ return res;
+}
+
+static inline unsigned int mash_dsm(int pll, unsigned int M, unsigned int N,
+ unsigned int K)
+{
+ unsigned int num = ((N + 1) << 10) + K;
+ unsigned int den = (M + 1) << 10;
+
+ return cal_dsm(pll, num, den);
+}
+
+static inline unsigned int ssff_dsm_1(int pll, unsigned int M, unsigned int N,
+ unsigned int K)
+{
+ unsigned int num = ((N + 1) << 11) + K + 512;
+ unsigned int den = (M + 1) << 11;
+
+ return cal_dsm(pll, num, den);
+}
+
+static inline unsigned int ssff_dsm_2(int pll, unsigned int M, unsigned int N,
+ unsigned int K)
+{
+ unsigned int num = K >= 512 ?
+ ((N + 1) << 12) + K - 512 : ((N + 1) << 12) + K + 3584;
+ unsigned int den = (M + 1) << 12;
+
+ return cal_dsm(pll, num, den);
+}
+
+static inline unsigned int dsm(int pll, unsigned int M, unsigned int N,
+ unsigned int K, unsigned int dsmsel, unsigned int phase_div_en)
+{
+ if (!dsmsel)
+ return mash_dsm(pll, M, N, K);
+ else if (!phase_div_en)
+ return mash_dsm(pll, M, N, K);
+ else
+ return ssff_dsm_2(pll, M, N, K);
+}
+
+static inline unsigned int ltq_get_pll0_fosc(void)
+{
+ if (CGU_PLL0_BYPASS)
+ return get_input_clock(0);
+ else
+ return !CGU_PLL0_CFG_FRAC_EN
+ ? dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, 0,
+ CGU_PLL0_CFG_DSMSEL,
+ CGU_PLL0_PHASE_DIVIDER_ENABLE)
+ : dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN,
+ CGU_PLL0_CFG_PLLK, CGU_PLL0_CFG_DSMSEL,
+ CGU_PLL0_PHASE_DIVIDER_ENABLE);
+}
+
+static unsigned int ltq_get_pll0_fdiv(void)
+{
+ unsigned int div = CGU_PLL2_CFG_INPUT_DIV + 1;
+
+ return (ltq_get_pll0_fosc() + (div >> 1)) / div;
+}
+
+unsigned int ltq_get_io_region_clock(void)
+{
+ unsigned int ret = ltq_get_pll0_fosc();
+
+ switch (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & CGU_SYS_DDR_SEL) {
+ default:
+ case 0:
+ return (ret + 1) / 2;
+ case 1:
+ return (ret * 2 + 2) / 5;
+ case 2:
+ return (ret + 1) / 3;
+ case 3:
+ return (ret + 2) / 4;
+ }
+}
+EXPORT_SYMBOL(ltq_get_io_region_clock);
+
+unsigned int ltq_get_fpi_bus_clock(int fpi)
+{
+ unsigned int ret = ltq_get_io_region_clock();
+
+ if ((fpi == 2) && (ltq_cgu_r32(LTQ_CGU_SYS) & CGU_SYS_FPI_SEL))
+ ret >>= 1;
+ return ret;
+}
+EXPORT_SYMBOL(ltq_get_fpi_bus_clock);
+
+unsigned int ltq_get_cpu_hz(void)
+{
+ switch (ltq_cgu_r32(LTQ_CGU_SYS) & 0xc) {
+ case 0:
+ return CLOCK_333M;
+ case 4:
+ return DDR_HZ;
+ case 8:
+ return DDR_HZ << 1;
+ default:
+ return DDR_HZ >> 1;
+ }
+}
+EXPORT_SYMBOL(ltq_get_cpu_hz);
+
+unsigned int ltq_get_fpi_hz(void)
+{
+ unsigned int ddr_clock = DDR_HZ;
+
+ if (ltq_cgu_r32(LTQ_CGU_SYS) & 0x40)
+ return ddr_clock >> 1;
+ return ddr_clock;
+}
+EXPORT_SYMBOL(ltq_get_fpi_hz);
diff --git a/arch/mips/lantiq/xway/devices.c b/arch/mips/lantiq/xway/devices.c
new file mode 100644
index 000000000000..e09e789dfc27
--- /dev/null
+++ b/arch/mips/lantiq/xway/devices.c
@@ -0,0 +1,121 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/mtd/physmap.h>
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/etherdevice.h>
+#include <linux/reboot.h>
+#include <linux/time.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+
+#include <lantiq_soc.h>
+#include <lantiq_irq.h>
+#include <lantiq_platform.h>
+
+#include "devices.h"
+
+/* gpio */
+static struct resource ltq_gpio_resource[] = {
+ {
+ .name = "gpio0",
+ .start = LTQ_GPIO0_BASE_ADDR,
+ .end = LTQ_GPIO0_BASE_ADDR + LTQ_GPIO_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .name = "gpio1",
+ .start = LTQ_GPIO1_BASE_ADDR,
+ .end = LTQ_GPIO1_BASE_ADDR + LTQ_GPIO_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .name = "gpio2",
+ .start = LTQ_GPIO2_BASE_ADDR,
+ .end = LTQ_GPIO2_BASE_ADDR + LTQ_GPIO_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+void __init ltq_register_gpio(void)
+{
+ platform_device_register_simple("ltq_gpio", 0,
+ &ltq_gpio_resource[0], 1);
+ platform_device_register_simple("ltq_gpio", 1,
+ &ltq_gpio_resource[1], 1);
+
+ /* AR9 and VR9 have an extra gpio block */
+ if (ltq_is_ar9() || ltq_is_vr9()) {
+ platform_device_register_simple("ltq_gpio", 2,
+ &ltq_gpio_resource[2], 1);
+ }
+}
+
+/* serial to parallel conversion */
+static struct resource ltq_stp_resource = {
+ .name = "stp",
+ .start = LTQ_STP_BASE_ADDR,
+ .end = LTQ_STP_BASE_ADDR + LTQ_STP_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+void __init ltq_register_gpio_stp(void)
+{
+ platform_device_register_simple("ltq_stp", 0, &ltq_stp_resource, 1);
+}
+
+/* asc ports - amazon se has its own serial mapping */
+static struct resource ltq_ase_asc_resources[] = {
+ {
+ .name = "asc0",
+ .start = LTQ_ASC1_BASE_ADDR,
+ .end = LTQ_ASC1_BASE_ADDR + LTQ_ASC_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ IRQ_RES(tx, LTQ_ASC_ASE_TIR),
+ IRQ_RES(rx, LTQ_ASC_ASE_RIR),
+ IRQ_RES(err, LTQ_ASC_ASE_EIR),
+};
+
+void __init ltq_register_ase_asc(void)
+{
+ platform_device_register_simple("ltq_asc", 0,
+ ltq_ase_asc_resources, ARRAY_SIZE(ltq_ase_asc_resources));
+}
+
+/* ethernet */
+static struct resource ltq_etop_resources = {
+ .name = "etop",
+ .start = LTQ_ETOP_BASE_ADDR,
+ .end = LTQ_ETOP_BASE_ADDR + LTQ_ETOP_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device ltq_etop = {
+ .name = "ltq_etop",
+ .resource = &ltq_etop_resources,
+ .num_resources = 1,
+};
+
+void __init
+ltq_register_etop(struct ltq_eth_data *eth)
+{
+ if (eth) {
+ ltq_etop.dev.platform_data = eth;
+ platform_device_register(&ltq_etop);
+ }
+}
diff --git a/arch/mips/lantiq/xway/devices.h b/arch/mips/lantiq/xway/devices.h
new file mode 100644
index 000000000000..e90493471bc1
--- /dev/null
+++ b/arch/mips/lantiq/xway/devices.h
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LTQ_DEVICES_XWAY_H__
+#define _LTQ_DEVICES_XWAY_H__
+
+#include "../devices.h"
+#include <linux/phy.h>
+
+extern void ltq_register_gpio(void);
+extern void ltq_register_gpio_stp(void);
+extern void ltq_register_ase_asc(void);
+extern void ltq_register_etop(struct ltq_eth_data *eth);
+
+#endif
diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c
new file mode 100644
index 000000000000..4278a459d6c4
--- /dev/null
+++ b/arch/mips/lantiq/xway/dma.c
@@ -0,0 +1,253 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+
+#include <lantiq_soc.h>
+#include <xway_dma.h>
+
+#define LTQ_DMA_CTRL 0x10
+#define LTQ_DMA_CPOLL 0x14
+#define LTQ_DMA_CS 0x18
+#define LTQ_DMA_CCTRL 0x1C
+#define LTQ_DMA_CDBA 0x20
+#define LTQ_DMA_CDLEN 0x24
+#define LTQ_DMA_CIS 0x28
+#define LTQ_DMA_CIE 0x2C
+#define LTQ_DMA_PS 0x40
+#define LTQ_DMA_PCTRL 0x44
+#define LTQ_DMA_IRNEN 0xf4
+
+#define DMA_DESCPT BIT(3) /* descriptor complete irq */
+#define DMA_TX BIT(8) /* TX channel direction */
+#define DMA_CHAN_ON BIT(0) /* channel on / off bit */
+#define DMA_PDEN BIT(6) /* enable packet drop */
+#define DMA_CHAN_RST BIT(1) /* channel on / off bit */
+#define DMA_RESET BIT(0) /* channel on / off bit */
+#define DMA_IRQ_ACK 0x7e /* IRQ status register */
+#define DMA_POLL BIT(31) /* turn on channel polling */
+#define DMA_CLK_DIV4 BIT(6) /* polling clock divider */
+#define DMA_2W_BURST BIT(1) /* 2 word burst length */
+#define DMA_MAX_CHANNEL 20 /* the soc has 20 channels */
+#define DMA_ETOP_ENDIANESS (0xf << 8) /* endianess swap etop channels */
+#define DMA_WEIGHT (BIT(17) | BIT(16)) /* default channel wheight */
+
+#define ltq_dma_r32(x) ltq_r32(ltq_dma_membase + (x))
+#define ltq_dma_w32(x, y) ltq_w32(x, ltq_dma_membase + (y))
+#define ltq_dma_w32_mask(x, y, z) ltq_w32_mask(x, y, \
+ ltq_dma_membase + (z))
+
+static struct resource ltq_dma_resource = {
+ .name = "dma",
+ .start = LTQ_DMA_BASE_ADDR,
+ .end = LTQ_DMA_BASE_ADDR + LTQ_DMA_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static void __iomem *ltq_dma_membase;
+
+void
+ltq_dma_enable_irq(struct ltq_dma_channel *ch)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ ltq_dma_w32(ch->nr, LTQ_DMA_CS);
+ ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN);
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(ltq_dma_enable_irq);
+
+void
+ltq_dma_disable_irq(struct ltq_dma_channel *ch)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ ltq_dma_w32(ch->nr, LTQ_DMA_CS);
+ ltq_dma_w32_mask(1 << ch->nr, 0, LTQ_DMA_IRNEN);
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(ltq_dma_disable_irq);
+
+void
+ltq_dma_ack_irq(struct ltq_dma_channel *ch)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ ltq_dma_w32(ch->nr, LTQ_DMA_CS);
+ ltq_dma_w32(DMA_IRQ_ACK, LTQ_DMA_CIS);
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(ltq_dma_ack_irq);
+
+void
+ltq_dma_open(struct ltq_dma_channel *ch)
+{
+ unsigned long flag;
+
+ local_irq_save(flag);
+ ltq_dma_w32(ch->nr, LTQ_DMA_CS);
+ ltq_dma_w32_mask(0, DMA_CHAN_ON, LTQ_DMA_CCTRL);
+ ltq_dma_enable_irq(ch);
+ local_irq_restore(flag);
+}
+EXPORT_SYMBOL_GPL(ltq_dma_open);
+
+void
+ltq_dma_close(struct ltq_dma_channel *ch)
+{
+ unsigned long flag;
+
+ local_irq_save(flag);
+ ltq_dma_w32(ch->nr, LTQ_DMA_CS);
+ ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL);
+ ltq_dma_disable_irq(ch);
+ local_irq_restore(flag);
+}
+EXPORT_SYMBOL_GPL(ltq_dma_close);
+
+static void
+ltq_dma_alloc(struct ltq_dma_channel *ch)
+{
+ unsigned long flags;
+
+ ch->desc = 0;
+ ch->desc_base = dma_alloc_coherent(NULL,
+ LTQ_DESC_NUM * LTQ_DESC_SIZE,
+ &ch->phys, GFP_ATOMIC);
+ memset(ch->desc_base, 0, LTQ_DESC_NUM * LTQ_DESC_SIZE);
+
+ local_irq_save(flags);
+ ltq_dma_w32(ch->nr, LTQ_DMA_CS);
+ ltq_dma_w32(ch->phys, LTQ_DMA_CDBA);
+ ltq_dma_w32(LTQ_DESC_NUM, LTQ_DMA_CDLEN);
+ ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL);
+ wmb();
+ ltq_dma_w32_mask(0, DMA_CHAN_RST, LTQ_DMA_CCTRL);
+ while (ltq_dma_r32(LTQ_DMA_CCTRL) & DMA_CHAN_RST)
+ ;
+ local_irq_restore(flags);
+}
+
+void
+ltq_dma_alloc_tx(struct ltq_dma_channel *ch)
+{
+ unsigned long flags;
+
+ ltq_dma_alloc(ch);
+
+ local_irq_save(flags);
+ ltq_dma_w32(DMA_DESCPT, LTQ_DMA_CIE);
+ ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN);
+ ltq_dma_w32(DMA_WEIGHT | DMA_TX, LTQ_DMA_CCTRL);
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(ltq_dma_alloc_tx);
+
+void
+ltq_dma_alloc_rx(struct ltq_dma_channel *ch)
+{
+ unsigned long flags;
+
+ ltq_dma_alloc(ch);
+
+ local_irq_save(flags);
+ ltq_dma_w32(DMA_DESCPT, LTQ_DMA_CIE);
+ ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN);
+ ltq_dma_w32(DMA_WEIGHT, LTQ_DMA_CCTRL);
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(ltq_dma_alloc_rx);
+
+void
+ltq_dma_free(struct ltq_dma_channel *ch)
+{
+ if (!ch->desc_base)
+ return;
+ ltq_dma_close(ch);
+ dma_free_coherent(NULL, LTQ_DESC_NUM * LTQ_DESC_SIZE,
+ ch->desc_base, ch->phys);
+}
+EXPORT_SYMBOL_GPL(ltq_dma_free);
+
+void
+ltq_dma_init_port(int p)
+{
+ ltq_dma_w32(p, LTQ_DMA_PS);
+ switch (p) {
+ case DMA_PORT_ETOP:
+ /*
+ * Tell the DMA engine to swap the endianess of data frames and
+ * drop packets if the channel arbitration fails.
+ */
+ ltq_dma_w32_mask(0, DMA_ETOP_ENDIANESS | DMA_PDEN,
+ LTQ_DMA_PCTRL);
+ break;
+
+ case DMA_PORT_DEU:
+ ltq_dma_w32((DMA_2W_BURST << 4) | (DMA_2W_BURST << 2),
+ LTQ_DMA_PCTRL);
+ break;
+
+ default:
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(ltq_dma_init_port);
+
+int __init
+ltq_dma_init(void)
+{
+ int i;
+
+ /* insert and request the memory region */
+ if (insert_resource(&iomem_resource, &ltq_dma_resource) < 0)
+ panic("Failed to insert dma memory\n");
+
+ if (request_mem_region(ltq_dma_resource.start,
+ resource_size(&ltq_dma_resource), "dma") < 0)
+ panic("Failed to request dma memory\n");
+
+ /* remap dma register range */
+ ltq_dma_membase = ioremap_nocache(ltq_dma_resource.start,
+ resource_size(&ltq_dma_resource));
+ if (!ltq_dma_membase)
+ panic("Failed to remap dma memory\n");
+
+ /* power up and reset the dma engine */
+ ltq_pmu_enable(PMU_DMA);
+ ltq_dma_w32_mask(0, DMA_RESET, LTQ_DMA_CTRL);
+
+ /* disable all interrupts */
+ ltq_dma_w32(0, LTQ_DMA_IRNEN);
+
+ /* reset/configure each channel */
+ for (i = 0; i < DMA_MAX_CHANNEL; i++) {
+ ltq_dma_w32(i, LTQ_DMA_CS);
+ ltq_dma_w32(DMA_CHAN_RST, LTQ_DMA_CCTRL);
+ ltq_dma_w32(DMA_POLL | DMA_CLK_DIV4, LTQ_DMA_CPOLL);
+ ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL);
+ }
+ return 0;
+}
+
+postcore_initcall(ltq_dma_init);
diff --git a/arch/mips/lantiq/xway/ebu.c b/arch/mips/lantiq/xway/ebu.c
new file mode 100644
index 000000000000..66eb52fa50a1
--- /dev/null
+++ b/arch/mips/lantiq/xway/ebu.c
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ *
+ * EBU - the external bus unit attaches PCI, NOR and NAND
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/ioport.h>
+
+#include <lantiq_soc.h>
+
+/* all access to the ebu must be locked */
+DEFINE_SPINLOCK(ebu_lock);
+EXPORT_SYMBOL_GPL(ebu_lock);
+
+static struct resource ltq_ebu_resource = {
+ .name = "ebu",
+ .start = LTQ_EBU_BASE_ADDR,
+ .end = LTQ_EBU_BASE_ADDR + LTQ_EBU_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+/* remapped base addr of the clock unit and external bus unit */
+void __iomem *ltq_ebu_membase;
+
+static int __init lantiq_ebu_init(void)
+{
+ /* insert and request the memory region */
+ if (insert_resource(&iomem_resource, &ltq_ebu_resource) < 0)
+ panic("Failed to insert ebu memory\n");
+
+ if (request_mem_region(ltq_ebu_resource.start,
+ resource_size(&ltq_ebu_resource), "ebu") < 0)
+ panic("Failed to request ebu memory\n");
+
+ /* remap ebu register range */
+ ltq_ebu_membase = ioremap_nocache(ltq_ebu_resource.start,
+ resource_size(&ltq_ebu_resource));
+ if (!ltq_ebu_membase)
+ panic("Failed to remap ebu memory\n");
+
+ /* make sure to unprotect the memory region where flash is located */
+ ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0);
+ return 0;
+}
+
+postcore_initcall(lantiq_ebu_init);
diff --git a/arch/mips/lantiq/xway/gpio.c b/arch/mips/lantiq/xway/gpio.c
new file mode 100644
index 000000000000..a321451a5455
--- /dev/null
+++ b/arch/mips/lantiq/xway/gpio.c
@@ -0,0 +1,195 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+
+#include <lantiq_soc.h>
+
+#define LTQ_GPIO_OUT 0x00
+#define LTQ_GPIO_IN 0x04
+#define LTQ_GPIO_DIR 0x08
+#define LTQ_GPIO_ALTSEL0 0x0C
+#define LTQ_GPIO_ALTSEL1 0x10
+#define LTQ_GPIO_OD 0x14
+
+#define PINS_PER_PORT 16
+#define MAX_PORTS 3
+
+#define ltq_gpio_getbit(m, r, p) (!!(ltq_r32(m + r) & (1 << p)))
+#define ltq_gpio_setbit(m, r, p) ltq_w32_mask(0, (1 << p), m + r)
+#define ltq_gpio_clearbit(m, r, p) ltq_w32_mask((1 << p), 0, m + r)
+
+struct ltq_gpio {
+ void __iomem *membase;
+ struct gpio_chip chip;
+};
+
+static struct ltq_gpio ltq_gpio_port[MAX_PORTS];
+
+int gpio_to_irq(unsigned int gpio)
+{
+ return -EINVAL;
+}
+EXPORT_SYMBOL(gpio_to_irq);
+
+int irq_to_gpio(unsigned int gpio)
+{
+ return -EINVAL;
+}
+EXPORT_SYMBOL(irq_to_gpio);
+
+int ltq_gpio_request(unsigned int pin, unsigned int alt0,
+ unsigned int alt1, unsigned int dir, const char *name)
+{
+ int id = 0;
+
+ if (pin >= (MAX_PORTS * PINS_PER_PORT))
+ return -EINVAL;
+ if (gpio_request(pin, name)) {
+ pr_err("failed to setup lantiq gpio: %s\n", name);
+ return -EBUSY;
+ }
+ if (dir)
+ gpio_direction_output(pin, 1);
+ else
+ gpio_direction_input(pin);
+ while (pin >= PINS_PER_PORT) {
+ pin -= PINS_PER_PORT;
+ id++;
+ }
+ if (alt0)
+ ltq_gpio_setbit(ltq_gpio_port[id].membase,
+ LTQ_GPIO_ALTSEL0, pin);
+ else
+ ltq_gpio_clearbit(ltq_gpio_port[id].membase,
+ LTQ_GPIO_ALTSEL0, pin);
+ if (alt1)
+ ltq_gpio_setbit(ltq_gpio_port[id].membase,
+ LTQ_GPIO_ALTSEL1, pin);
+ else
+ ltq_gpio_clearbit(ltq_gpio_port[id].membase,
+ LTQ_GPIO_ALTSEL1, pin);
+ return 0;
+}
+EXPORT_SYMBOL(ltq_gpio_request);
+
+static void ltq_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
+{
+ struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
+
+ if (value)
+ ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OUT, offset);
+ else
+ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OUT, offset);
+}
+
+static int ltq_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
+
+ return ltq_gpio_getbit(ltq_gpio->membase, LTQ_GPIO_IN, offset);
+}
+
+static int ltq_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
+{
+ struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
+
+ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OD, offset);
+ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset);
+
+ return 0;
+}
+
+static int ltq_gpio_direction_output(struct gpio_chip *chip,
+ unsigned int offset, int value)
+{
+ struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
+
+ ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OD, offset);
+ ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset);
+ ltq_gpio_set(chip, offset, value);
+
+ return 0;
+}
+
+static int ltq_gpio_req(struct gpio_chip *chip, unsigned offset)
+{
+ struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
+
+ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL0, offset);
+ ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL1, offset);
+ return 0;
+}
+
+static int ltq_gpio_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+
+ if (pdev->id >= MAX_PORTS) {
+ dev_err(&pdev->dev, "invalid gpio port %d\n",
+ pdev->id);
+ return -EINVAL;
+ }
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get memory for gpio port %d\n",
+ pdev->id);
+ return -ENOENT;
+ }
+ res = devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res), dev_name(&pdev->dev));
+ if (!res) {
+ dev_err(&pdev->dev,
+ "failed to request memory for gpio port %d\n",
+ pdev->id);
+ return -EBUSY;
+ }
+ ltq_gpio_port[pdev->id].membase = devm_ioremap_nocache(&pdev->dev,
+ res->start, resource_size(res));
+ if (!ltq_gpio_port[pdev->id].membase) {
+ dev_err(&pdev->dev, "failed to remap memory for gpio port %d\n",
+ pdev->id);
+ return -ENOMEM;
+ }
+ ltq_gpio_port[pdev->id].chip.label = "ltq_gpio";
+ ltq_gpio_port[pdev->id].chip.direction_input = ltq_gpio_direction_input;
+ ltq_gpio_port[pdev->id].chip.direction_output =
+ ltq_gpio_direction_output;
+ ltq_gpio_port[pdev->id].chip.get = ltq_gpio_get;
+ ltq_gpio_port[pdev->id].chip.set = ltq_gpio_set;
+ ltq_gpio_port[pdev->id].chip.request = ltq_gpio_req;
+ ltq_gpio_port[pdev->id].chip.base = PINS_PER_PORT * pdev->id;
+ ltq_gpio_port[pdev->id].chip.ngpio = PINS_PER_PORT;
+ platform_set_drvdata(pdev, &ltq_gpio_port[pdev->id]);
+ return gpiochip_add(&ltq_gpio_port[pdev->id].chip);
+}
+
+static struct platform_driver
+ltq_gpio_driver = {
+ .probe = ltq_gpio_probe,
+ .driver = {
+ .name = "ltq_gpio",
+ .owner = THIS_MODULE,
+ },
+};
+
+int __init ltq_gpio_init(void)
+{
+ int ret = platform_driver_register(&ltq_gpio_driver);
+
+ if (ret)
+ pr_info("ltq_gpio : Error registering platfom driver!");
+ return ret;
+}
+
+postcore_initcall(ltq_gpio_init);
diff --git a/arch/mips/lantiq/xway/gpio_ebu.c b/arch/mips/lantiq/xway/gpio_ebu.c
new file mode 100644
index 000000000000..a479355abdb9
--- /dev/null
+++ b/arch/mips/lantiq/xway/gpio_ebu.c
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+
+#include <lantiq_soc.h>
+
+/*
+ * By attaching hardware latches to the EBU it is possible to create output
+ * only gpios. This driver configures a special memory address, which when
+ * written to outputs 16 bit to the latches.
+ */
+
+#define LTQ_EBU_BUSCON 0x1e7ff /* 16 bit access, slowest timing */
+#define LTQ_EBU_WP 0x80000000 /* write protect bit */
+
+/* we keep a shadow value of the last value written to the ebu */
+static int ltq_ebu_gpio_shadow = 0x0;
+static void __iomem *ltq_ebu_gpio_membase;
+
+static void ltq_ebu_apply(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ebu_lock, flags);
+ ltq_ebu_w32(LTQ_EBU_BUSCON, LTQ_EBU_BUSCON1);
+ *((__u16 *)ltq_ebu_gpio_membase) = ltq_ebu_gpio_shadow;
+ ltq_ebu_w32(LTQ_EBU_BUSCON | LTQ_EBU_WP, LTQ_EBU_BUSCON1);
+ spin_unlock_irqrestore(&ebu_lock, flags);
+}
+
+static void ltq_ebu_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ if (value)
+ ltq_ebu_gpio_shadow |= (1 << offset);
+ else
+ ltq_ebu_gpio_shadow &= ~(1 << offset);
+ ltq_ebu_apply();
+}
+
+static int ltq_ebu_direction_output(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ ltq_ebu_set(chip, offset, value);
+
+ return 0;
+}
+
+static struct gpio_chip ltq_ebu_chip = {
+ .label = "ltq_ebu",
+ .direction_output = ltq_ebu_direction_output,
+ .set = ltq_ebu_set,
+ .base = 72,
+ .ngpio = 16,
+ .can_sleep = 1,
+ .owner = THIS_MODULE,
+};
+
+static int ltq_ebu_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get memory resource\n");
+ return -ENOENT;
+ }
+
+ res = devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res), dev_name(&pdev->dev));
+ if (!res) {
+ dev_err(&pdev->dev, "failed to request memory resource\n");
+ return -EBUSY;
+ }
+
+ ltq_ebu_gpio_membase = devm_ioremap_nocache(&pdev->dev, res->start,
+ resource_size(res));
+ if (!ltq_ebu_gpio_membase) {
+ dev_err(&pdev->dev, "Failed to ioremap mem region\n");
+ return -ENOMEM;
+ }
+
+ /* grab the default shadow value passed form the platform code */
+ ltq_ebu_gpio_shadow = (unsigned int) pdev->dev.platform_data;
+
+ /* tell the ebu controller which memory address we will be using */
+ ltq_ebu_w32(pdev->resource->start | 0x1, LTQ_EBU_ADDRSEL1);
+
+ /* write protect the region */
+ ltq_ebu_w32(LTQ_EBU_BUSCON | LTQ_EBU_WP, LTQ_EBU_BUSCON1);
+
+ ret = gpiochip_add(&ltq_ebu_chip);
+ if (!ret)
+ ltq_ebu_apply();
+ return ret;
+}
+
+static struct platform_driver ltq_ebu_driver = {
+ .probe = ltq_ebu_probe,
+ .driver = {
+ .name = "ltq_ebu",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ltq_ebu_init(void)
+{
+ int ret = platform_driver_register(&ltq_ebu_driver);
+
+ if (ret)
+ pr_info("ltq_ebu : Error registering platfom driver!");
+ return ret;
+}
+
+postcore_initcall(ltq_ebu_init);
diff --git a/arch/mips/lantiq/xway/gpio_stp.c b/arch/mips/lantiq/xway/gpio_stp.c
new file mode 100644
index 000000000000..67d59d690340
--- /dev/null
+++ b/arch/mips/lantiq/xway/gpio_stp.c
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2007 John Crispin <blogic@openwrt.org>
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <lantiq_soc.h>
+
+#define LTQ_STP_CON0 0x00
+#define LTQ_STP_CON1 0x04
+#define LTQ_STP_CPU0 0x08
+#define LTQ_STP_CPU1 0x0C
+#define LTQ_STP_AR 0x10
+
+#define LTQ_STP_CON_SWU (1 << 31)
+#define LTQ_STP_2HZ 0
+#define LTQ_STP_4HZ (1 << 23)
+#define LTQ_STP_8HZ (2 << 23)
+#define LTQ_STP_10HZ (3 << 23)
+#define LTQ_STP_SPEED_MASK (0xf << 23)
+#define LTQ_STP_UPD_FPI (1 << 31)
+#define LTQ_STP_UPD_MASK (3 << 30)
+#define LTQ_STP_ADSL_SRC (3 << 24)
+
+#define LTQ_STP_GROUP0 (1 << 0)
+
+#define LTQ_STP_RISING 0
+#define LTQ_STP_FALLING (1 << 26)
+#define LTQ_STP_EDGE_MASK (1 << 26)
+
+#define ltq_stp_r32(reg) __raw_readl(ltq_stp_membase + reg)
+#define ltq_stp_w32(val, reg) __raw_writel(val, ltq_stp_membase + reg)
+#define ltq_stp_w32_mask(clear, set, reg) \
+ ltq_w32((ltq_r32(ltq_stp_membase + reg) & ~(clear)) | (set), \
+ ltq_stp_membase + (reg))
+
+static int ltq_stp_shadow = 0xffff;
+static void __iomem *ltq_stp_membase;
+
+static void ltq_stp_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ if (value)
+ ltq_stp_shadow |= (1 << offset);
+ else
+ ltq_stp_shadow &= ~(1 << offset);
+ ltq_stp_w32(ltq_stp_shadow, LTQ_STP_CPU0);
+}
+
+static int ltq_stp_direction_output(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ ltq_stp_set(chip, offset, value);
+
+ return 0;
+}
+
+static struct gpio_chip ltq_stp_chip = {
+ .label = "ltq_stp",
+ .direction_output = ltq_stp_direction_output,
+ .set = ltq_stp_set,
+ .base = 48,
+ .ngpio = 24,
+ .can_sleep = 1,
+ .owner = THIS_MODULE,
+};
+
+static int ltq_stp_hw_init(void)
+{
+ /* the 3 pins used to control the external stp */
+ ltq_gpio_request(4, 1, 0, 1, "stp-st");
+ ltq_gpio_request(5, 1, 0, 1, "stp-d");
+ ltq_gpio_request(6, 1, 0, 1, "stp-sh");
+
+ /* sane defaults */
+ ltq_stp_w32(0, LTQ_STP_AR);
+ ltq_stp_w32(0, LTQ_STP_CPU0);
+ ltq_stp_w32(0, LTQ_STP_CPU1);
+ ltq_stp_w32(LTQ_STP_CON_SWU, LTQ_STP_CON0);
+ ltq_stp_w32(0, LTQ_STP_CON1);
+
+ /* rising or falling edge */
+ ltq_stp_w32_mask(LTQ_STP_EDGE_MASK, LTQ_STP_FALLING, LTQ_STP_CON0);
+
+ /* per default stp 15-0 are set */
+ ltq_stp_w32_mask(0, LTQ_STP_GROUP0, LTQ_STP_CON1);
+
+ /* stp are update periodically by the FPI bus */
+ ltq_stp_w32_mask(LTQ_STP_UPD_MASK, LTQ_STP_UPD_FPI, LTQ_STP_CON1);
+
+ /* set stp update speed */
+ ltq_stp_w32_mask(LTQ_STP_SPEED_MASK, LTQ_STP_8HZ, LTQ_STP_CON1);
+
+ /* tell the hardware that pin (led) 0 and 1 are controlled
+ * by the dsl arc
+ */
+ ltq_stp_w32_mask(0, LTQ_STP_ADSL_SRC, LTQ_STP_CON0);
+
+ ltq_pmu_enable(PMU_LED);
+ return 0;
+}
+
+static int __devinit ltq_stp_probe(struct platform_device *pdev)
+{
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ int ret = 0;
+
+ if (!res)
+ return -ENOENT;
+ res = devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res), dev_name(&pdev->dev));
+ if (!res) {
+ dev_err(&pdev->dev, "failed to request STP memory\n");
+ return -EBUSY;
+ }
+ ltq_stp_membase = devm_ioremap_nocache(&pdev->dev, res->start,
+ resource_size(res));
+ if (!ltq_stp_membase) {
+ dev_err(&pdev->dev, "failed to remap STP memory\n");
+ return -ENOMEM;
+ }
+ ret = gpiochip_add(&ltq_stp_chip);
+ if (!ret)
+ ret = ltq_stp_hw_init();
+
+ return ret;
+}
+
+static struct platform_driver ltq_stp_driver = {
+ .probe = ltq_stp_probe,
+ .driver = {
+ .name = "ltq_stp",
+ .owner = THIS_MODULE,
+ },
+};
+
+int __init ltq_stp_init(void)
+{
+ int ret = platform_driver_register(&ltq_stp_driver);
+
+ if (ret)
+ pr_info("ltq_stp: error registering platfom driver");
+ return ret;
+}
+
+postcore_initcall(ltq_stp_init);
diff --git a/arch/mips/lantiq/xway/mach-easy50601.c b/arch/mips/lantiq/xway/mach-easy50601.c
new file mode 100644
index 000000000000..d5aaf637ab19
--- /dev/null
+++ b/arch/mips/lantiq/xway/mach-easy50601.c
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/input.h>
+
+#include <lantiq.h>
+
+#include "../machtypes.h"
+#include "devices.h"
+
+static struct mtd_partition easy50601_partitions[] = {
+ {
+ .name = "uboot",
+ .offset = 0x0,
+ .size = 0x10000,
+ },
+ {
+ .name = "uboot_env",
+ .offset = 0x10000,
+ .size = 0x10000,
+ },
+ {
+ .name = "linux",
+ .offset = 0x20000,
+ .size = 0xE0000,
+ },
+ {
+ .name = "rootfs",
+ .offset = 0x100000,
+ .size = 0x300000,
+ },
+};
+
+static struct physmap_flash_data easy50601_flash_data = {
+ .nr_parts = ARRAY_SIZE(easy50601_partitions),
+ .parts = easy50601_partitions,
+};
+
+static void __init easy50601_init(void)
+{
+ ltq_register_nor(&easy50601_flash_data);
+}
+
+MIPS_MACHINE(LTQ_MACH_EASY50601,
+ "EASY50601",
+ "EASY50601 Eval Board",
+ easy50601_init);
diff --git a/arch/mips/lantiq/xway/mach-easy50712.c b/arch/mips/lantiq/xway/mach-easy50712.c
new file mode 100644
index 000000000000..ea5027b3239d
--- /dev/null
+++ b/arch/mips/lantiq/xway/mach-easy50712.c
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/physmap.h>
+#include <linux/input.h>
+#include <linux/phy.h>
+
+#include <lantiq_soc.h>
+#include <irq.h>
+
+#include "../machtypes.h"
+#include "devices.h"
+
+static struct mtd_partition easy50712_partitions[] = {
+ {
+ .name = "uboot",
+ .offset = 0x0,
+ .size = 0x10000,
+ },
+ {
+ .name = "uboot_env",
+ .offset = 0x10000,
+ .size = 0x10000,
+ },
+ {
+ .name = "linux",
+ .offset = 0x20000,
+ .size = 0xe0000,
+ },
+ {
+ .name = "rootfs",
+ .offset = 0x100000,
+ .size = 0x300000,
+ },
+};
+
+static struct physmap_flash_data easy50712_flash_data = {
+ .nr_parts = ARRAY_SIZE(easy50712_partitions),
+ .parts = easy50712_partitions,
+};
+
+static struct ltq_pci_data ltq_pci_data = {
+ .clock = PCI_CLOCK_INT,
+ .gpio = PCI_GNT1 | PCI_REQ1,
+ .irq = {
+ [14] = INT_NUM_IM0_IRL0 + 22,
+ },
+};
+
+static struct ltq_eth_data ltq_eth_data = {
+ .mii_mode = PHY_INTERFACE_MODE_MII,
+};
+
+static void __init easy50712_init(void)
+{
+ ltq_register_gpio_stp();
+ ltq_register_nor(&easy50712_flash_data);
+ ltq_register_pci(&ltq_pci_data);
+ ltq_register_etop(&ltq_eth_data);
+}
+
+MIPS_MACHINE(LTQ_MACH_EASY50712,
+ "EASY50712",
+ "EASY50712 Eval Board",
+ easy50712_init);
diff --git a/arch/mips/lantiq/xway/pmu.c b/arch/mips/lantiq/xway/pmu.c
new file mode 100644
index 000000000000..9d69f01e352b
--- /dev/null
+++ b/arch/mips/lantiq/xway/pmu.c
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/ioport.h>
+
+#include <lantiq_soc.h>
+
+/* PMU - the power management unit allows us to turn part of the core
+ * on and off
+ */
+
+/* the enable / disable registers */
+#define LTQ_PMU_PWDCR 0x1C
+#define LTQ_PMU_PWDSR 0x20
+
+#define ltq_pmu_w32(x, y) ltq_w32((x), ltq_pmu_membase + (y))
+#define ltq_pmu_r32(x) ltq_r32(ltq_pmu_membase + (x))
+
+static struct resource ltq_pmu_resource = {
+ .name = "pmu",
+ .start = LTQ_PMU_BASE_ADDR,
+ .end = LTQ_PMU_BASE_ADDR + LTQ_PMU_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+static void __iomem *ltq_pmu_membase;
+
+void ltq_pmu_enable(unsigned int module)
+{
+ int err = 1000000;
+
+ ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) & ~module, LTQ_PMU_PWDCR);
+ do {} while (--err && (ltq_pmu_r32(LTQ_PMU_PWDSR) & module));
+
+ if (!err)
+ panic("activating PMU module failed!\n");
+}
+EXPORT_SYMBOL(ltq_pmu_enable);
+
+void ltq_pmu_disable(unsigned int module)
+{
+ ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) | module, LTQ_PMU_PWDCR);
+}
+EXPORT_SYMBOL(ltq_pmu_disable);
+
+int __init ltq_pmu_init(void)
+{
+ if (insert_resource(&iomem_resource, &ltq_pmu_resource) < 0)
+ panic("Failed to insert pmu memory\n");
+
+ if (request_mem_region(ltq_pmu_resource.start,
+ resource_size(&ltq_pmu_resource), "pmu") < 0)
+ panic("Failed to request pmu memory\n");
+
+ ltq_pmu_membase = ioremap_nocache(ltq_pmu_resource.start,
+ resource_size(&ltq_pmu_resource));
+ if (!ltq_pmu_membase)
+ panic("Failed to remap pmu memory\n");
+ return 0;
+}
+
+core_initcall(ltq_pmu_init);
diff --git a/arch/mips/lantiq/xway/prom-ase.c b/arch/mips/lantiq/xway/prom-ase.c
new file mode 100644
index 000000000000..abe49f4db57f
--- /dev/null
+++ b/arch/mips/lantiq/xway/prom-ase.c
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <asm/bootinfo.h>
+#include <asm/time.h>
+
+#include <lantiq_soc.h>
+
+#include "../prom.h"
+
+#define SOC_AMAZON_SE "Amazon_SE"
+
+#define PART_SHIFT 12
+#define PART_MASK 0x0FFFFFFF
+#define REV_SHIFT 28
+#define REV_MASK 0xF0000000
+
+void __init ltq_soc_detect(struct ltq_soc_info *i)
+{
+ i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT;
+ i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT;
+ switch (i->partnum) {
+ case SOC_ID_AMAZON_SE:
+ i->name = SOC_AMAZON_SE;
+ i->type = SOC_TYPE_AMAZON_SE;
+ break;
+
+ default:
+ unreachable();
+ break;
+ }
+}
diff --git a/arch/mips/lantiq/xway/prom-xway.c b/arch/mips/lantiq/xway/prom-xway.c
new file mode 100644
index 000000000000..1686692ac24d
--- /dev/null
+++ b/arch/mips/lantiq/xway/prom-xway.c
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <asm/bootinfo.h>
+#include <asm/time.h>
+
+#include <lantiq_soc.h>
+
+#include "../prom.h"
+
+#define SOC_DANUBE "Danube"
+#define SOC_TWINPASS "Twinpass"
+#define SOC_AR9 "AR9"
+
+#define PART_SHIFT 12
+#define PART_MASK 0x0FFFFFFF
+#define REV_SHIFT 28
+#define REV_MASK 0xF0000000
+
+void __init ltq_soc_detect(struct ltq_soc_info *i)
+{
+ i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT;
+ i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT;
+ switch (i->partnum) {
+ case SOC_ID_DANUBE1:
+ case SOC_ID_DANUBE2:
+ i->name = SOC_DANUBE;
+ i->type = SOC_TYPE_DANUBE;
+ break;
+
+ case SOC_ID_TWINPASS:
+ i->name = SOC_TWINPASS;
+ i->type = SOC_TYPE_DANUBE;
+ break;
+
+ case SOC_ID_ARX188:
+ case SOC_ID_ARX168:
+ case SOC_ID_ARX182:
+ i->name = SOC_AR9;
+ i->type = SOC_TYPE_AR9;
+ break;
+
+ default:
+ unreachable();
+ break;
+ }
+}
diff --git a/arch/mips/lantiq/xway/reset.c b/arch/mips/lantiq/xway/reset.c
new file mode 100644
index 000000000000..a1be36d0e490
--- /dev/null
+++ b/arch/mips/lantiq/xway/reset.c
@@ -0,0 +1,91 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/pm.h>
+#include <linux/module.h>
+#include <asm/reboot.h>
+
+#include <lantiq_soc.h>
+
+#define ltq_rcu_w32(x, y) ltq_w32((x), ltq_rcu_membase + (y))
+#define ltq_rcu_r32(x) ltq_r32(ltq_rcu_membase + (x))
+
+/* register definitions */
+#define LTQ_RCU_RST 0x0010
+#define LTQ_RCU_RST_ALL 0x40000000
+
+#define LTQ_RCU_RST_STAT 0x0014
+#define LTQ_RCU_STAT_SHIFT 26
+
+static struct resource ltq_rcu_resource = {
+ .name = "rcu",
+ .start = LTQ_RCU_BASE_ADDR,
+ .end = LTQ_RCU_BASE_ADDR + LTQ_RCU_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+/* remapped base addr of the reset control unit */
+static void __iomem *ltq_rcu_membase;
+
+/* This function is used by the watchdog driver */
+int ltq_reset_cause(void)
+{
+ u32 val = ltq_rcu_r32(LTQ_RCU_RST_STAT);
+ return val >> LTQ_RCU_STAT_SHIFT;
+}
+EXPORT_SYMBOL_GPL(ltq_reset_cause);
+
+static void ltq_machine_restart(char *command)
+{
+ pr_notice("System restart\n");
+ local_irq_disable();
+ ltq_rcu_w32(ltq_rcu_r32(LTQ_RCU_RST) | LTQ_RCU_RST_ALL, LTQ_RCU_RST);
+ unreachable();
+}
+
+static void ltq_machine_halt(void)
+{
+ pr_notice("System halted.\n");
+ local_irq_disable();
+ unreachable();
+}
+
+static void ltq_machine_power_off(void)
+{
+ pr_notice("Please turn off the power now.\n");
+ local_irq_disable();
+ unreachable();
+}
+
+static int __init mips_reboot_setup(void)
+{
+ /* insert and request the memory region */
+ if (insert_resource(&iomem_resource, &ltq_rcu_resource) < 0)
+ panic("Failed to insert rcu memory\n");
+
+ if (request_mem_region(ltq_rcu_resource.start,
+ resource_size(&ltq_rcu_resource), "rcu") < 0)
+ panic("Failed to request rcu memory\n");
+
+ /* remap rcu register range */
+ ltq_rcu_membase = ioremap_nocache(ltq_rcu_resource.start,
+ resource_size(&ltq_rcu_resource));
+ if (!ltq_rcu_membase)
+ panic("Failed to remap rcu memory\n");
+
+ _machine_restart = ltq_machine_restart;
+ _machine_halt = ltq_machine_halt;
+ pm_power_off = ltq_machine_power_off;
+
+ return 0;
+}
+
+arch_initcall(mips_reboot_setup);
diff --git a/arch/mips/lantiq/xway/setup-ase.c b/arch/mips/lantiq/xway/setup-ase.c
new file mode 100644
index 000000000000..f6f326798a39
--- /dev/null
+++ b/arch/mips/lantiq/xway/setup-ase.c
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
+ */
+
+#include <lantiq_soc.h>
+
+#include "../prom.h"
+#include "devices.h"
+
+void __init ltq_soc_setup(void)
+{
+ ltq_register_ase_asc();
+ ltq_register_gpio();
+ ltq_register_wdt();
+}
diff --git a/arch/mips/lantiq/xway/setup-xway.c b/arch/mips/lantiq/xway/setup-xway.c
new file mode 100644
index 000000000000..c292f643a858
--- /dev/null
+++ b/arch/mips/lantiq/xway/setup-xway.c
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
+ */
+
+#include <lantiq_soc.h>
+
+#include "../prom.h"
+#include "devices.h"
+
+void __init ltq_soc_setup(void)
+{
+ ltq_register_asc(0);
+ ltq_register_asc(1);
+ ltq_register_gpio();
+ ltq_register_wdt();
+}
diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
index 2adead5a8a37..b2cad4fd5fc4 100644
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_CPU_TX39XX) += r3k_dump_tlb.o
obj-$(CONFIG_CPU_TX49XX) += dump_tlb.o
obj-$(CONFIG_CPU_VR41XX) += dump_tlb.o
obj-$(CONFIG_CPU_CAVIUM_OCTEON) += dump_tlb.o
+obj-$(CONFIG_CPU_XLR) += dump_tlb.o
# libgcc-style stuff needed in the kernel
obj-y += ashldi3.o ashrdi3.o cmpdi2.o lshrdi3.o ucmpdi2.o
diff --git a/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c b/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
index 8c807c965199..0cb1b9760e34 100644
--- a/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
+++ b/arch/mips/loongson/common/cs5536/cs5536_mfgpt.c
@@ -201,8 +201,6 @@ static struct clocksource clocksource_mfgpt = {
.rating = 120, /* Functional for real use, but not desired */
.read = mfgpt_read,
.mask = CLOCKSOURCE_MASK(32),
- .mult = 0,
- .shift = 22,
};
int __init init_mfgpt_clocksource(void)
@@ -210,8 +208,7 @@ int __init init_mfgpt_clocksource(void)
if (num_possible_cpus() > 1) /* MFGPT does not scale! */
return 0;
- clocksource_mfgpt.mult = clocksource_hz2mult(MFGPT_TICK_RATE, 22);
- return clocksource_register(&clocksource_mfgpt);
+ return clocksource_register_hz(&clocksource_mfgpt, MFGPT_TICK_RATE);
}
arch_initcall(init_mfgpt_clocksource);
diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile
index d679c772d082..4d8c1623eee2 100644
--- a/arch/mips/mm/Makefile
+++ b/arch/mips/mm/Makefile
@@ -3,7 +3,8 @@
#
obj-y += cache.o dma-default.o extable.o fault.o \
- init.o tlbex.o tlbex-fault.o uasm.o page.o
+ init.o mmap.o tlbex.o tlbex-fault.o uasm.o \
+ page.o
obj-$(CONFIG_32BIT) += ioremap.o pgtable-32.o
obj-$(CONFIG_64BIT) += pgtable-64.o
@@ -29,6 +30,7 @@ obj-$(CONFIG_CPU_TX39XX) += c-tx39.o tlb-r3k.o
obj-$(CONFIG_CPU_TX49XX) += c-r4k.o cex-gen.o tlb-r4k.o
obj-$(CONFIG_CPU_VR41XX) += c-r4k.o cex-gen.o tlb-r4k.o
obj-$(CONFIG_CPU_CAVIUM_OCTEON) += c-octeon.o cex-oct.o tlb-r4k.o
+obj-$(CONFIG_CPU_XLR) += c-r4k.o tlb-r4k.o cex-gen.o
obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o
obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o
diff --git a/arch/mips/mm/c-r3k.c b/arch/mips/mm/c-r3k.c
index 54e5f7b9f440..e6b0efd3f6a4 100644
--- a/arch/mips/mm/c-r3k.c
+++ b/arch/mips/mm/c-r3k.c
@@ -1,7 +1,7 @@
/*
* r2300.c: R2000 and R3000 specific mmu/cache code.
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
*
* with a lot of changes to make this thing work for R3000s
* Tx39XX R4k style caches added. HK
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index 71bddf8f7d25..eeb642e4066e 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
* Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Ralf Baechle (ralf@gnu.org)
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
*/
@@ -1006,6 +1006,7 @@ static void __cpuinit probe_pcache(void)
case CPU_25KF:
case CPU_SB1:
case CPU_SB1A:
+ case CPU_XLR:
c->dcache.flags |= MIPS_CACHE_PINDEX;
break;
diff --git a/arch/mips/mm/c-tx39.c b/arch/mips/mm/c-tx39.c
index 6515b4418714..d352fad3e451 100644
--- a/arch/mips/mm/c-tx39.c
+++ b/arch/mips/mm/c-tx39.c
@@ -1,7 +1,7 @@
/*
* r2300.c: R2000 and R3000 specific mmu/cache code.
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
*
* with a lot of changes to make this thing work for R3000s
* Tx39XX R4k style caches added. HK
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 279599e9a779..1aadeb42c5a5 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -64,8 +64,6 @@
#endif /* CONFIG_MIPS_MT_SMTC */
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
/*
* We have up to 8 empty zeroed pages so we can map one of the right colour
* when needed. This is necessary only on R4000 / R4400 SC and MC versions
diff --git a/arch/mips/mm/mmap.c b/arch/mips/mm/mmap.c
new file mode 100644
index 000000000000..ae3c20a9556e
--- /dev/null
+++ b/arch/mips/mm/mmap.c
@@ -0,0 +1,122 @@
+/*
+ * 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) 2011 Wind River Systems,
+ * written by Ralf Baechle <ralf@linux-mips.org>
+ */
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+
+unsigned long shm_align_mask = PAGE_SIZE - 1; /* Sane caches */
+
+EXPORT_SYMBOL(shm_align_mask);
+
+#define COLOUR_ALIGN(addr,pgoff) \
+ ((((addr) + shm_align_mask) & ~shm_align_mask) + \
+ (((pgoff) << PAGE_SHIFT) & shm_align_mask))
+
+unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
+ unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+ struct vm_area_struct * vmm;
+ int do_color_align;
+
+ if (len > TASK_SIZE)
+ return -ENOMEM;
+
+ if (flags & MAP_FIXED) {
+ /* Even MAP_FIXED mappings must reside within TASK_SIZE. */
+ if (TASK_SIZE - len < addr)
+ return -EINVAL;
+
+ /*
+ * We do not accept a shared mapping if it would violate
+ * cache aliasing constraints.
+ */
+ if ((flags & MAP_SHARED) &&
+ ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask))
+ return -EINVAL;
+ return addr;
+ }
+
+ do_color_align = 0;
+ if (filp || (flags & MAP_SHARED))
+ do_color_align = 1;
+ if (addr) {
+ if (do_color_align)
+ addr = COLOUR_ALIGN(addr, pgoff);
+ else
+ addr = PAGE_ALIGN(addr);
+ vmm = find_vma(current->mm, addr);
+ if (TASK_SIZE - len >= addr &&
+ (!vmm || addr + len <= vmm->vm_start))
+ return addr;
+ }
+ addr = current->mm->mmap_base;
+ if (do_color_align)
+ addr = COLOUR_ALIGN(addr, pgoff);
+ else
+ addr = PAGE_ALIGN(addr);
+
+ for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
+ /* At this point: (!vmm || addr < vmm->vm_end). */
+ if (TASK_SIZE - len < addr)
+ return -ENOMEM;
+ if (!vmm || addr + len <= vmm->vm_start)
+ return addr;
+ addr = vmm->vm_end;
+ if (do_color_align)
+ addr = COLOUR_ALIGN(addr, pgoff);
+ }
+}
+
+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;
+}
diff --git a/arch/mips/mm/sc-ip22.c b/arch/mips/mm/sc-ip22.c
index 13adb5782110..a6bd11fba7bf 100644
--- a/arch/mips/mm/sc-ip22.c
+++ b/arch/mips/mm/sc-ip22.c
@@ -2,7 +2,7 @@
* sc-ip22.c: Indy cache management functions.
*
* Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org),
- * derived from r4xx0.c by David S. Miller (dm@engr.sgi.com).
+ * derived from r4xx0.c by David S. Miller (davem@davemloft.net).
*/
#include <linux/init.h>
#include <linux/kernel.h>
diff --git a/arch/mips/mm/sc-r5k.c b/arch/mips/mm/sc-r5k.c
index f330d38e5575..ae1e533a096e 100644
--- a/arch/mips/mm/sc-r5k.c
+++ b/arch/mips/mm/sc-r5k.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org),
- * derived from r4xx0.c by David S. Miller (dm@engr.sgi.com).
+ * derived from r4xx0.c by David S. Miller (davem@davemloft.net).
*/
#include <linux/init.h>
#include <linux/kernel.h>
diff --git a/arch/mips/mm/tlb-r3k.c b/arch/mips/mm/tlb-r3k.c
index 0f5ab236ab69..40424affef83 100644
--- a/arch/mips/mm/tlb-r3k.c
+++ b/arch/mips/mm/tlb-r3k.c
@@ -1,7 +1,7 @@
/*
* r2300.c: R2000 and R3000 specific mmu/cache code.
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
*
* with a lot of changes to make this thing work for R3000s
* Tx39XX R4k style caches added. HK
diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c
index c618eed933a1..ba40325caea6 100644
--- a/arch/mips/mm/tlb-r4k.c
+++ b/arch/mips/mm/tlb-r4k.c
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
* Copyright (C) 1997, 1998, 1999, 2000 Ralf Baechle ralf@gnu.org
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 2002 MIPS Technologies, Inc. All rights reserved.
diff --git a/arch/mips/mm/tlb-r8k.c b/arch/mips/mm/tlb-r8k.c
index 2b82f23df1a1..3d95f76c106b 100644
--- a/arch/mips/mm/tlb-r8k.c
+++ b/arch/mips/mm/tlb-r8k.c
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
* Copyright (C) 1997, 1998, 1999, 2000 Ralf Baechle ralf@gnu.org
* Carsten Langgaard, carstenl@mips.com
* Copyright (C) 2002 MIPS Technologies, Inc. All rights reserved.
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index f5734c2c8097..424ed4b92e6d 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -404,6 +404,7 @@ static void __cpuinit build_tlb_write_entry(u32 **p, struct uasm_label **l,
case CPU_5KC:
case CPU_TX49XX:
case CPU_PR4450:
+ case CPU_XLR:
uasm_i_nop(p);
tlbw(p);
break;
diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c
index e85c977328da..1d36c511a7a5 100644
--- a/arch/mips/mti-malta/malta-int.c
+++ b/arch/mips/mti-malta/malta-int.c
@@ -308,6 +308,8 @@ static void ipi_call_dispatch(void)
static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
{
+ scheduler_ipi();
+
return IRQ_HANDLED;
}
diff --git a/arch/mips/netlogic/Kconfig b/arch/mips/netlogic/Kconfig
new file mode 100644
index 000000000000..a5ca743613f2
--- /dev/null
+++ b/arch/mips/netlogic/Kconfig
@@ -0,0 +1,5 @@
+config NLM_COMMON
+ bool
+
+config NLM_XLR
+ bool
diff --git a/arch/mips/netlogic/xlr/Makefile b/arch/mips/netlogic/xlr/Makefile
new file mode 100644
index 000000000000..9bd3f731f62e
--- /dev/null
+++ b/arch/mips/netlogic/xlr/Makefile
@@ -0,0 +1,5 @@
+obj-y += setup.o platform.o irq.o setup.o time.o
+obj-$(CONFIG_SMP) += smp.o smpboot.o
+obj-$(CONFIG_EARLY_PRINTK) += xlr_console.o
+
+EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/netlogic/xlr/irq.c b/arch/mips/netlogic/xlr/irq.c
new file mode 100644
index 000000000000..1446d58e364c
--- /dev/null
+++ b/arch/mips/netlogic/xlr/irq.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+
+#include <asm/mipsregs.h>
+
+#include <asm/netlogic/xlr/iomap.h>
+#include <asm/netlogic/xlr/pic.h>
+#include <asm/netlogic/xlr/xlr.h>
+
+#include <asm/netlogic/interrupt.h>
+#include <asm/netlogic/mips-extns.h>
+
+static u64 nlm_irq_mask;
+static DEFINE_SPINLOCK(nlm_pic_lock);
+
+static void xlr_pic_enable(struct irq_data *d)
+{
+ nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
+ unsigned long flags;
+ nlm_reg_t reg;
+ int irq = d->irq;
+
+ WARN(!PIC_IRQ_IS_IRT(irq), "Bad irq %d", irq);
+
+ spin_lock_irqsave(&nlm_pic_lock, flags);
+ reg = netlogic_read_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE);
+ netlogic_write_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE,
+ reg | (1 << 6) | (1 << 30) | (1 << 31));
+ spin_unlock_irqrestore(&nlm_pic_lock, flags);
+}
+
+static void xlr_pic_mask(struct irq_data *d)
+{
+ nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
+ unsigned long flags;
+ nlm_reg_t reg;
+ int irq = d->irq;
+
+ WARN(!PIC_IRQ_IS_IRT(irq), "Bad irq %d", irq);
+
+ spin_lock_irqsave(&nlm_pic_lock, flags);
+ reg = netlogic_read_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE);
+ netlogic_write_reg(mmio, PIC_IRT_1_BASE + irq - PIC_IRQ_BASE,
+ reg | (1 << 6) | (1 << 30) | (0 << 31));
+ spin_unlock_irqrestore(&nlm_pic_lock, flags);
+}
+
+#ifdef CONFIG_PCI
+/* Extra ACK needed for XLR on chip PCI controller */
+static void xlr_pci_ack(struct irq_data *d)
+{
+ nlm_reg_t *pci_mmio = netlogic_io_mmio(NETLOGIC_IO_PCIX_OFFSET);
+
+ netlogic_read_reg(pci_mmio, (0x140 >> 2));
+}
+
+/* Extra ACK needed for XLS on chip PCIe controller */
+static void xls_pcie_ack(struct irq_data *d)
+{
+ nlm_reg_t *pcie_mmio_le = netlogic_io_mmio(NETLOGIC_IO_PCIE_1_OFFSET);
+
+ switch (d->irq) {
+ case PIC_PCIE_LINK0_IRQ:
+ netlogic_write_reg(pcie_mmio_le, (0x90 >> 2), 0xffffffff);
+ break;
+ case PIC_PCIE_LINK1_IRQ:
+ netlogic_write_reg(pcie_mmio_le, (0x94 >> 2), 0xffffffff);
+ break;
+ case PIC_PCIE_LINK2_IRQ:
+ netlogic_write_reg(pcie_mmio_le, (0x190 >> 2), 0xffffffff);
+ break;
+ case PIC_PCIE_LINK3_IRQ:
+ netlogic_write_reg(pcie_mmio_le, (0x194 >> 2), 0xffffffff);
+ break;
+ }
+}
+
+/* For XLS B silicon, the 3,4 PCI interrupts are different */
+static void xls_pcie_ack_b(struct irq_data *d)
+{
+ nlm_reg_t *pcie_mmio_le = netlogic_io_mmio(NETLOGIC_IO_PCIE_1_OFFSET);
+
+ switch (d->irq) {
+ case PIC_PCIE_LINK0_IRQ:
+ netlogic_write_reg(pcie_mmio_le, (0x90 >> 2), 0xffffffff);
+ break;
+ case PIC_PCIE_LINK1_IRQ:
+ netlogic_write_reg(pcie_mmio_le, (0x94 >> 2), 0xffffffff);
+ break;
+ case PIC_PCIE_XLSB0_LINK2_IRQ:
+ netlogic_write_reg(pcie_mmio_le, (0x190 >> 2), 0xffffffff);
+ break;
+ case PIC_PCIE_XLSB0_LINK3_IRQ:
+ netlogic_write_reg(pcie_mmio_le, (0x194 >> 2), 0xffffffff);
+ break;
+ }
+}
+#endif
+
+static void xlr_pic_ack(struct irq_data *d)
+{
+ unsigned long flags;
+ nlm_reg_t *mmio;
+ int irq = d->irq;
+ void *hd = irq_data_get_irq_handler_data(d);
+
+ WARN(!PIC_IRQ_IS_IRT(irq), "Bad irq %d", irq);
+
+ if (hd) {
+ void (*extra_ack)(void *) = hd;
+ extra_ack(d);
+ }
+ mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
+ spin_lock_irqsave(&nlm_pic_lock, flags);
+ netlogic_write_reg(mmio, PIC_INT_ACK, (1 << (irq - PIC_IRQ_BASE)));
+ spin_unlock_irqrestore(&nlm_pic_lock, flags);
+}
+
+/*
+ * This chip definition handles interrupts routed thru the XLR
+ * hardware PIC, currently IRQs 8-39 are mapped to hardware intr
+ * 0-31 wired the XLR PIC
+ */
+static struct irq_chip xlr_pic = {
+ .name = "XLR-PIC",
+ .irq_enable = xlr_pic_enable,
+ .irq_mask = xlr_pic_mask,
+ .irq_ack = xlr_pic_ack,
+};
+
+static void rsvd_irq_handler(struct irq_data *d)
+{
+ WARN(d->irq >= PIC_IRQ_BASE, "Bad irq %d", d->irq);
+}
+
+/*
+ * Chip definition for CPU originated interrupts(timer, msg) and
+ * IPIs
+ */
+struct irq_chip nlm_cpu_intr = {
+ .name = "XLR-CPU-INTR",
+ .irq_enable = rsvd_irq_handler,
+ .irq_mask = rsvd_irq_handler,
+ .irq_ack = rsvd_irq_handler,
+};
+
+void __init init_xlr_irqs(void)
+{
+ nlm_reg_t *mmio = netlogic_io_mmio(NETLOGIC_IO_PIC_OFFSET);
+ uint32_t thread_mask = 1;
+ int level, i;
+
+ pr_info("Interrupt thread mask [%x]\n", thread_mask);
+ for (i = 0; i < PIC_NUM_IRTS; i++) {
+ level = PIC_IRQ_IS_EDGE_TRIGGERED(i);
+
+ /* Bind all PIC irqs to boot cpu */
+ netlogic_write_reg(mmio, PIC_IRT_0_BASE + i, thread_mask);
+
+ /*
+ * Use local scheduling and high polarity for all IRTs
+ * Invalidate all IRTs, by default
+ */
+ netlogic_write_reg(mmio, PIC_IRT_1_BASE + i,
+ (level << 30) | (1 << 6) | (PIC_IRQ_BASE + i));
+ }
+
+ /* Make all IRQs as level triggered by default */
+ for (i = 0; i < NR_IRQS; i++) {
+ if (PIC_IRQ_IS_IRT(i))
+ irq_set_chip_and_handler(i, &xlr_pic, handle_level_irq);
+ else
+ irq_set_chip_and_handler(i, &nlm_cpu_intr,
+ handle_level_irq);
+ }
+#ifdef CONFIG_SMP
+ irq_set_chip_and_handler(IRQ_IPI_SMP_FUNCTION, &nlm_cpu_intr,
+ nlm_smp_function_ipi_handler);
+ irq_set_chip_and_handler(IRQ_IPI_SMP_RESCHEDULE, &nlm_cpu_intr,
+ nlm_smp_resched_ipi_handler);
+ nlm_irq_mask |=
+ ((1ULL << IRQ_IPI_SMP_FUNCTION) | (1ULL << IRQ_IPI_SMP_RESCHEDULE));
+#endif
+
+#ifdef CONFIG_PCI
+ /*
+ * For PCI interrupts, we need to ack the PIC controller too, overload
+ * irq handler data to do this
+ */
+ if (nlm_chip_is_xls()) {
+ if (nlm_chip_is_xls_b()) {
+ irq_set_handler_data(PIC_PCIE_LINK0_IRQ,
+ xls_pcie_ack_b);
+ irq_set_handler_data(PIC_PCIE_LINK1_IRQ,
+ xls_pcie_ack_b);
+ irq_set_handler_data(PIC_PCIE_XLSB0_LINK2_IRQ,
+ xls_pcie_ack_b);
+ irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ,
+ xls_pcie_ack_b);
+ } else {
+ irq_set_handler_data(PIC_PCIE_LINK0_IRQ, xls_pcie_ack);
+ irq_set_handler_data(PIC_PCIE_LINK1_IRQ, xls_pcie_ack);
+ irq_set_handler_data(PIC_PCIE_LINK2_IRQ, xls_pcie_ack);
+ irq_set_handler_data(PIC_PCIE_LINK3_IRQ, xls_pcie_ack);
+ }
+ } else {
+ /* XLR PCI controller ACK */
+ irq_set_handler_data(PIC_PCIE_XLSB0_LINK3_IRQ, xlr_pci_ack);
+ }
+#endif
+ /* unmask all PIC related interrupts. If no handler is installed by the
+ * drivers, it'll just ack the interrupt and return
+ */
+ for (i = PIC_IRT_FIRST_IRQ; i <= PIC_IRT_LAST_IRQ; i++)
+ nlm_irq_mask |= (1ULL << i);
+
+ nlm_irq_mask |= (1ULL << IRQ_TIMER);
+}
+
+void __init arch_init_irq(void)
+{
+ /* Initialize the irq descriptors */
+ init_xlr_irqs();
+ write_c0_eimr(nlm_irq_mask);
+}
+
+void __cpuinit nlm_smp_irq_init(void)
+{
+ /* set interrupt mask for non-zero cpus */
+ write_c0_eimr(nlm_irq_mask);
+}
+
+asmlinkage void plat_irq_dispatch(void)
+{
+ uint64_t eirr;
+ int i;
+
+ eirr = read_c0_eirr() & read_c0_eimr();
+ if (!eirr)
+ return;
+
+ /* no need of EIRR here, writing compare clears interrupt */
+ if (eirr & (1 << IRQ_TIMER)) {
+ do_IRQ(IRQ_TIMER);
+ return;
+ }
+
+ /* use dcltz: optimize below code */
+ for (i = 63; i != -1; i--) {
+ if (eirr & (1ULL << i))
+ break;
+ }
+ if (i == -1) {
+ pr_err("no interrupt !!\n");
+ return;
+ }
+
+ /* Ack eirr */
+ write_c0_eirr(1ULL << i);
+
+ do_IRQ(i);
+}
diff --git a/arch/mips/netlogic/xlr/platform.c b/arch/mips/netlogic/xlr/platform.c
new file mode 100644
index 000000000000..609ec2534642
--- /dev/null
+++ b/arch/mips/netlogic/xlr/platform.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2011, Netlogic Microsystems.
+ * Copyright 2004, Matt Porter <mporter@kernel.crashing.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/resource.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
+
+#include <asm/netlogic/xlr/iomap.h>
+#include <asm/netlogic/xlr/pic.h>
+#include <asm/netlogic/xlr/xlr.h>
+
+unsigned int nlm_xlr_uart_in(struct uart_port *p, int offset)
+{
+ nlm_reg_t *mmio;
+ unsigned int value;
+
+ /* XLR uart does not need any mapping of regs */
+ mmio = (nlm_reg_t *)(p->membase + (offset << p->regshift));
+ value = netlogic_read_reg(mmio, 0);
+
+ /* See XLR/XLS errata */
+ if (offset == UART_MSR)
+ value ^= 0xF0;
+ else if (offset == UART_MCR)
+ value ^= 0x3;
+
+ return value;
+}
+
+void nlm_xlr_uart_out(struct uart_port *p, int offset, int value)
+{
+ nlm_reg_t *mmio;
+
+ /* XLR uart does not need any mapping of regs */
+ mmio = (nlm_reg_t *)(p->membase + (offset << p->regshift));
+
+ /* See XLR/XLS errata */
+ if (offset == UART_MSR)
+ value ^= 0xF0;
+ else if (offset == UART_MCR)
+ value ^= 0x3;
+
+ netlogic_write_reg(mmio, 0, value);
+}
+
+#define PORT(_irq) \
+ { \
+ .irq = _irq, \
+ .regshift = 2, \
+ .iotype = UPIO_MEM32, \
+ .flags = (UPF_SKIP_TEST | \
+ UPF_FIXED_TYPE | UPF_BOOT_AUTOCONF),\
+ .uartclk = PIC_CLKS_PER_SEC, \
+ .type = PORT_16550A, \
+ .serial_in = nlm_xlr_uart_in, \
+ .serial_out = nlm_xlr_uart_out, \
+ }
+
+static struct plat_serial8250_port xlr_uart_data[] = {
+ PORT(PIC_UART_0_IRQ),
+ PORT(PIC_UART_1_IRQ),
+ {},
+};
+
+static struct platform_device uart_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = xlr_uart_data,
+ },
+};
+
+static int __init nlm_uart_init(void)
+{
+ nlm_reg_t *mmio;
+
+ mmio = netlogic_io_mmio(NETLOGIC_IO_UART_0_OFFSET);
+ xlr_uart_data[0].membase = (void __iomem *)mmio;
+ xlr_uart_data[0].mapbase = CPHYSADDR((unsigned long)mmio);
+
+ mmio = netlogic_io_mmio(NETLOGIC_IO_UART_1_OFFSET);
+ xlr_uart_data[1].membase = (void __iomem *)mmio;
+ xlr_uart_data[1].mapbase = CPHYSADDR((unsigned long)mmio);
+
+ return platform_device_register(&uart_device);
+}
+
+arch_initcall(nlm_uart_init);
diff --git a/arch/mips/netlogic/xlr/setup.c b/arch/mips/netlogic/xlr/setup.c
new file mode 100644
index 000000000000..482802569e74
--- /dev/null
+++ b/arch/mips/netlogic/xlr/setup.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/serial_8250.h>
+#include <linux/pm.h>
+
+#include <asm/reboot.h>
+#include <asm/time.h>
+#include <asm/bootinfo.h>
+#include <asm/smp-ops.h>
+
+#include <asm/netlogic/interrupt.h>
+#include <asm/netlogic/psb-bootinfo.h>
+
+#include <asm/netlogic/xlr/xlr.h>
+#include <asm/netlogic/xlr/iomap.h>
+#include <asm/netlogic/xlr/pic.h>
+#include <asm/netlogic/xlr/gpio.h>
+
+unsigned long netlogic_io_base = (unsigned long)(DEFAULT_NETLOGIC_IO_BASE);
+unsigned long nlm_common_ebase = 0x0;
+struct psb_info nlm_prom_info;
+
+static void nlm_early_serial_setup(void)
+{
+ struct uart_port s;
+ nlm_reg_t *uart_base;
+
+ uart_base = netlogic_io_mmio(NETLOGIC_IO_UART_0_OFFSET);
+ memset(&s, 0, sizeof(s));
+ s.flags = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
+ s.iotype = UPIO_MEM32;
+ s.regshift = 2;
+ s.irq = PIC_UART_0_IRQ;
+ s.uartclk = PIC_CLKS_PER_SEC;
+ s.serial_in = nlm_xlr_uart_in;
+ s.serial_out = nlm_xlr_uart_out;
+ s.mapbase = (unsigned long)uart_base;
+ s.membase = (unsigned char __iomem *)uart_base;
+ early_serial_setup(&s);
+}
+
+static void nlm_linux_exit(void)
+{
+ nlm_reg_t *mmio;
+
+ mmio = netlogic_io_mmio(NETLOGIC_IO_GPIO_OFFSET);
+ /* trigger a chip reset by writing 1 to GPIO_SWRESET_REG */
+ netlogic_write_reg(mmio, NETLOGIC_GPIO_SWRESET_REG, 1);
+ for ( ; ; )
+ cpu_wait();
+}
+
+void __init plat_mem_setup(void)
+{
+ panic_timeout = 5;
+ _machine_restart = (void (*)(char *))nlm_linux_exit;
+ _machine_halt = nlm_linux_exit;
+ pm_power_off = nlm_linux_exit;
+}
+
+const char *get_system_type(void)
+{
+ return "Netlogic XLR/XLS Series";
+}
+
+void __init prom_free_prom_memory(void)
+{
+ /* Nothing yet */
+}
+
+static void build_arcs_cmdline(int *argv)
+{
+ int i, remain, len;
+ char *arg;
+
+ remain = sizeof(arcs_cmdline) - 1;
+ arcs_cmdline[0] = '\0';
+ for (i = 0; argv[i] != 0; i++) {
+ arg = (char *)(long)argv[i];
+ len = strlen(arg);
+ if (len + 1 > remain)
+ break;
+ strcat(arcs_cmdline, arg);
+ strcat(arcs_cmdline, " ");
+ remain -= len + 1;
+ }
+
+ /* Add the default options here */
+ if ((strstr(arcs_cmdline, "console=")) == NULL) {
+ arg = "console=ttyS0,38400 ";
+ len = strlen(arg);
+ if (len > remain)
+ goto fail;
+ strcat(arcs_cmdline, arg);
+ remain -= len;
+ }
+#ifdef CONFIG_BLK_DEV_INITRD
+ if ((strstr(arcs_cmdline, "rdinit=")) == NULL) {
+ arg = "rdinit=/sbin/init ";
+ len = strlen(arg);
+ if (len > remain)
+ goto fail;
+ strcat(arcs_cmdline, arg);
+ remain -= len;
+ }
+#endif
+ return;
+fail:
+ panic("Cannot add %s, command line too big!", arg);
+}
+
+static void prom_add_memory(void)
+{
+ struct nlm_boot_mem_map *bootm;
+ u64 start, size;
+ u64 pref_backup = 512; /* avoid pref walking beyond end */
+ int i;
+
+ bootm = (void *)(long)nlm_prom_info.psb_mem_map;
+ for (i = 0; i < bootm->nr_map; i++) {
+ if (bootm->map[i].type != BOOT_MEM_RAM)
+ continue;
+ start = bootm->map[i].addr;
+ size = bootm->map[i].size;
+
+ /* Work around for using bootloader mem */
+ if (i == 0 && start == 0 && size == 0x0c000000)
+ size = 0x0ff00000;
+
+ add_memory_region(start, size - pref_backup, BOOT_MEM_RAM);
+ }
+}
+
+void __init prom_init(void)
+{
+ int *argv, *envp; /* passed as 32 bit ptrs */
+ struct psb_info *prom_infop;
+
+ /* truncate to 32 bit and sign extend all args */
+ argv = (int *)(long)(int)fw_arg1;
+ envp = (int *)(long)(int)fw_arg2;
+ prom_infop = (struct psb_info *)(long)(int)fw_arg3;
+
+ nlm_prom_info = *prom_infop;
+
+ nlm_early_serial_setup();
+ build_arcs_cmdline(argv);
+ nlm_common_ebase = read_c0_ebase() & (~((1 << 12) - 1));
+ prom_add_memory();
+
+#ifdef CONFIG_SMP
+ nlm_wakeup_secondary_cpus(nlm_prom_info.online_cpu_map);
+ register_smp_ops(&nlm_smp_ops);
+#endif
+}
diff --git a/arch/mips/netlogic/xlr/smp.c b/arch/mips/netlogic/xlr/smp.c
new file mode 100644
index 000000000000..b495a7f1433b
--- /dev/null
+++ b/arch/mips/netlogic/xlr/smp.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/irq.h>
+
+#include <asm/mmu_context.h>
+
+#include <asm/netlogic/interrupt.h>
+#include <asm/netlogic/mips-extns.h>
+
+#include <asm/netlogic/xlr/iomap.h>
+#include <asm/netlogic/xlr/pic.h>
+#include <asm/netlogic/xlr/xlr.h>
+
+void core_send_ipi(int logical_cpu, unsigned int action)
+{
+ int cpu = cpu_logical_map(logical_cpu);
+ u32 tid = cpu & 0x3;
+ u32 pid = (cpu >> 2) & 0x07;
+ u32 ipi = (tid << 16) | (pid << 20);
+
+ if (action & SMP_CALL_FUNCTION)
+ ipi |= IRQ_IPI_SMP_FUNCTION;
+ else if (action & SMP_RESCHEDULE_YOURSELF)
+ ipi |= IRQ_IPI_SMP_RESCHEDULE;
+ else
+ return;
+
+ pic_send_ipi(ipi);
+}
+
+void nlm_send_ipi_single(int cpu, unsigned int action)
+{
+ core_send_ipi(cpu, action);
+}
+
+void nlm_send_ipi_mask(const struct cpumask *mask, unsigned int action)
+{
+ int cpu;
+
+ for_each_cpu(cpu, mask) {
+ core_send_ipi(cpu, action);
+ }
+}
+
+/* IRQ_IPI_SMP_FUNCTION Handler */
+void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc)
+{
+ smp_call_function_interrupt();
+}
+
+/* IRQ_IPI_SMP_RESCHEDULE handler */
+void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc)
+{
+ set_need_resched();
+}
+
+void nlm_common_ipi_handler(int irq, struct pt_regs *regs)
+{
+ if (irq == IRQ_IPI_SMP_FUNCTION) {
+ smp_call_function_interrupt();
+ } else {
+ /* Announce that we are for reschduling */
+ set_need_resched();
+ }
+}
+
+/*
+ * Called before going into mips code, early cpu init
+ */
+void nlm_early_init_secondary(void)
+{
+ write_c0_ebase((uint32_t)nlm_common_ebase);
+ /* TLB partition here later */
+}
+
+/*
+ * Code to run on secondary just after probing the CPU
+ */
+static void __cpuinit nlm_init_secondary(void)
+{
+ nlm_smp_irq_init();
+}
+
+void nlm_smp_finish(void)
+{
+#ifdef notyet
+ nlm_common_msgring_cpu_init();
+#endif
+}
+
+void nlm_cpus_done(void)
+{
+}
+
+/*
+ * Boot all other cpus in the system, initialize them, and bring them into
+ * the boot function
+ */
+int nlm_cpu_unblock[NR_CPUS];
+int nlm_cpu_ready[NR_CPUS];
+unsigned long nlm_next_gp;
+unsigned long nlm_next_sp;
+cpumask_t phys_cpu_present_map;
+
+void nlm_boot_secondary(int logical_cpu, struct task_struct *idle)
+{
+ unsigned long gp = (unsigned long)task_thread_info(idle);
+ unsigned long sp = (unsigned long)__KSTK_TOS(idle);
+ int cpu = cpu_logical_map(logical_cpu);
+
+ nlm_next_sp = sp;
+ nlm_next_gp = gp;
+
+ /* barrier */
+ __sync();
+ nlm_cpu_unblock[cpu] = 1;
+}
+
+void __init nlm_smp_setup(void)
+{
+ unsigned int boot_cpu;
+ int num_cpus, i;
+
+ boot_cpu = hard_smp_processor_id();
+ cpus_clear(phys_cpu_present_map);
+
+ cpu_set(boot_cpu, phys_cpu_present_map);
+ __cpu_number_map[boot_cpu] = 0;
+ __cpu_logical_map[0] = boot_cpu;
+ cpu_set(0, cpu_possible_map);
+
+ num_cpus = 1;
+ for (i = 0; i < NR_CPUS; i++) {
+ if (nlm_cpu_ready[i]) {
+ cpu_set(i, phys_cpu_present_map);
+ __cpu_number_map[i] = num_cpus;
+ __cpu_logical_map[num_cpus] = i;
+ cpu_set(num_cpus, cpu_possible_map);
+ ++num_cpus;
+ }
+ }
+
+ pr_info("Phys CPU present map: %lx, possible map %lx\n",
+ (unsigned long)phys_cpu_present_map.bits[0],
+ (unsigned long)cpu_possible_map.bits[0]);
+
+ pr_info("Detected %i Slave CPU(s)\n", num_cpus);
+}
+
+void nlm_prepare_cpus(unsigned int max_cpus)
+{
+}
+
+struct plat_smp_ops nlm_smp_ops = {
+ .send_ipi_single = nlm_send_ipi_single,
+ .send_ipi_mask = nlm_send_ipi_mask,
+ .init_secondary = nlm_init_secondary,
+ .smp_finish = nlm_smp_finish,
+ .cpus_done = nlm_cpus_done,
+ .boot_secondary = nlm_boot_secondary,
+ .smp_setup = nlm_smp_setup,
+ .prepare_cpus = nlm_prepare_cpus,
+};
+
+unsigned long secondary_entry_point;
+
+int nlm_wakeup_secondary_cpus(u32 wakeup_mask)
+{
+ unsigned int tid, pid, ipi, i, boot_cpu;
+ void *reset_vec;
+
+ secondary_entry_point = (unsigned long)prom_pre_boot_secondary_cpus;
+ reset_vec = (void *)CKSEG1ADDR(0x1fc00000);
+ memcpy(reset_vec, nlm_boot_smp_nmi, 0x80);
+ boot_cpu = hard_smp_processor_id();
+
+ for (i = 0; i < NR_CPUS; i++) {
+ if (i == boot_cpu)
+ continue;
+ if (wakeup_mask & (1u << i)) {
+ tid = i & 0x3;
+ pid = (i >> 2) & 0x7;
+ ipi = (tid << 16) | (pid << 20) | (1 << 8);
+ pic_send_ipi(ipi);
+ }
+ }
+
+ return 0;
+}
diff --git a/arch/mips/netlogic/xlr/smpboot.S b/arch/mips/netlogic/xlr/smpboot.S
new file mode 100644
index 000000000000..b8e074402c99
--- /dev/null
+++ b/arch/mips/netlogic/xlr/smpboot.S
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <asm/asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+
+
+/* Don't jump to linux function from Bootloader stack. Change it
+ * here. Kernel might allocate bootloader memory before all the CPUs are
+ * brought up (eg: Inode cache region) and we better don't overwrite this
+ * memory
+ */
+NESTED(prom_pre_boot_secondary_cpus, 16, sp)
+ .set mips64
+ mfc0 t0, $15, 1 # read ebase
+ andi t0, 0x1f # t0 has the processor_id()
+ sll t0, 2 # offset in cpu array
+
+ PTR_LA t1, nlm_cpu_ready # mark CPU ready
+ PTR_ADDU t1, t0
+ li t2, 1
+ sw t2, 0(t1)
+
+ PTR_LA t1, nlm_cpu_unblock
+ PTR_ADDU t1, t0
+1: lw t2, 0(t1) # wait till unblocked
+ beqz t2, 1b
+ nop
+
+ PTR_LA t1, nlm_next_sp
+ PTR_L sp, 0(t1)
+ PTR_LA t1, nlm_next_gp
+ PTR_L gp, 0(t1)
+
+ PTR_LA t0, nlm_early_init_secondary
+ jalr t0
+ nop
+
+ PTR_LA t0, smp_bootstrap
+ jr t0
+ nop
+END(prom_pre_boot_secondary_cpus)
+
+NESTED(nlm_boot_smp_nmi, 0, sp)
+ .set push
+ .set noat
+ .set mips64
+ .set noreorder
+
+ /* Clear the NMI and BEV bits */
+ MFC0 k0, CP0_STATUS
+ li k1, 0xffb7ffff
+ and k0, k0, k1
+ MTC0 k0, CP0_STATUS
+
+ PTR_LA k1, secondary_entry_point
+ PTR_L k0, 0(k1)
+ jr k0
+ nop
+ .set pop
+END(nlm_boot_smp_nmi)
diff --git a/arch/mips/netlogic/xlr/time.c b/arch/mips/netlogic/xlr/time.c
new file mode 100644
index 000000000000..0d81b262593c
--- /dev/null
+++ b/arch/mips/netlogic/xlr/time.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/init.h>
+
+#include <asm/time.h>
+#include <asm/netlogic/interrupt.h>
+#include <asm/netlogic/psb-bootinfo.h>
+
+unsigned int __cpuinit get_c0_compare_int(void)
+{
+ return IRQ_TIMER;
+}
+
+void __init plat_time_init(void)
+{
+ mips_hpt_frequency = nlm_prom_info.cpu_frequency;
+ pr_info("MIPS counter frequency [%ld]\n",
+ (unsigned long)mips_hpt_frequency);
+}
diff --git a/arch/mips/netlogic/xlr/xlr_console.c b/arch/mips/netlogic/xlr/xlr_console.c
new file mode 100644
index 000000000000..759df0692201
--- /dev/null
+++ b/arch/mips/netlogic/xlr/xlr_console.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/types.h>
+#include <asm/netlogic/xlr/iomap.h>
+
+void prom_putchar(char c)
+{
+ nlm_reg_t *mmio;
+
+ mmio = netlogic_io_mmio(NETLOGIC_IO_UART_0_OFFSET);
+ while (netlogic_read_reg(mmio, 0x5) == 0)
+ ;
+ netlogic_write_reg(mmio, 0x0, c);
+}
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
index c9209ca6c8e7..4df879937446 100644
--- a/arch/mips/pci/Makefile
+++ b/arch/mips/pci/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_SIBYTE_SB1250) += fixup-sb1250.o pci-sb1250.o
obj-$(CONFIG_SIBYTE_BCM112X) += fixup-sb1250.o pci-sb1250.o
obj-$(CONFIG_SIBYTE_BCM1x80) += pci-bcm1480.o pci-bcm1480ht.o
obj-$(CONFIG_SNI_RM) += fixup-sni.o ops-sni.o
+obj-$(CONFIG_SOC_XWAY) += pci-lantiq.o ops-lantiq.o
obj-$(CONFIG_TANBAC_TB0219) += fixup-tb0219.o
obj-$(CONFIG_TANBAC_TB0226) += fixup-tb0226.o
obj-$(CONFIG_TANBAC_TB0287) += fixup-tb0287.o
@@ -55,6 +56,7 @@ obj-$(CONFIG_ZAO_CAPCELLA) += fixup-capcella.o
obj-$(CONFIG_WR_PPMC) += fixup-wrppmc.o
obj-$(CONFIG_MIKROTIK_RB532) += pci-rc32434.o ops-rc32434.o fixup-rc32434.o
obj-$(CONFIG_CPU_CAVIUM_OCTEON) += pci-octeon.o pcie-octeon.o
+obj-$(CONFIG_NLM_XLR) += pci-xlr.o
ifdef CONFIG_PCI_MSI
obj-$(CONFIG_CPU_CAVIUM_OCTEON) += msi-octeon.o
diff --git a/arch/mips/pci/ops-lantiq.c b/arch/mips/pci/ops-lantiq.c
new file mode 100644
index 000000000000..1f2afb55cc71
--- /dev/null
+++ b/arch/mips/pci/ops-lantiq.c
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <asm/addrspace.h>
+#include <linux/vmalloc.h>
+
+#include <lantiq_soc.h>
+
+#include "pci-lantiq.h"
+
+#define LTQ_PCI_CFG_BUSNUM_SHF 16
+#define LTQ_PCI_CFG_DEVNUM_SHF 11
+#define LTQ_PCI_CFG_FUNNUM_SHF 8
+
+#define PCI_ACCESS_READ 0
+#define PCI_ACCESS_WRITE 1
+
+static int ltq_pci_config_access(unsigned char access_type, struct pci_bus *bus,
+ unsigned int devfn, unsigned int where, u32 *data)
+{
+ unsigned long cfg_base;
+ unsigned long flags;
+ u32 temp;
+
+ /* we support slot from 0 to 15 dev_fn & 0x68 (AD29) is the
+ SoC itself */
+ if ((bus->number != 0) || ((devfn & 0xf8) > 0x78)
+ || ((devfn & 0xf8) == 0) || ((devfn & 0xf8) == 0x68))
+ return 1;
+
+ spin_lock_irqsave(&ebu_lock, flags);
+
+ cfg_base = (unsigned long) ltq_pci_mapped_cfg;
+ cfg_base |= (bus->number << LTQ_PCI_CFG_BUSNUM_SHF) | (devfn <<
+ LTQ_PCI_CFG_FUNNUM_SHF) | (where & ~0x3);
+
+ /* Perform access */
+ if (access_type == PCI_ACCESS_WRITE) {
+ ltq_w32(swab32(*data), ((u32 *)cfg_base));
+ } else {
+ *data = ltq_r32(((u32 *)(cfg_base)));
+ *data = swab32(*data);
+ }
+ wmb();
+
+ /* clean possible Master abort */
+ cfg_base = (unsigned long) ltq_pci_mapped_cfg;
+ cfg_base |= (0x0 << LTQ_PCI_CFG_FUNNUM_SHF) + 4;
+ temp = ltq_r32(((u32 *)(cfg_base)));
+ temp = swab32(temp);
+ cfg_base = (unsigned long) ltq_pci_mapped_cfg;
+ cfg_base |= (0x68 << LTQ_PCI_CFG_FUNNUM_SHF) + 4;
+ ltq_w32(temp, ((u32 *)cfg_base));
+
+ spin_unlock_irqrestore(&ebu_lock, flags);
+
+ if (((*data) == 0xffffffff) && (access_type == PCI_ACCESS_READ))
+ return 1;
+
+ return 0;
+}
+
+int ltq_pci_read_config_dword(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *val)
+{
+ u32 data = 0;
+
+ if (ltq_pci_config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (size == 1)
+ *val = (data >> ((where & 3) << 3)) & 0xff;
+ else if (size == 2)
+ *val = (data >> ((where & 3) << 3)) & 0xffff;
+ else
+ *val = data;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+int ltq_pci_write_config_dword(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ u32 data = 0;
+
+ if (size == 4) {
+ data = val;
+ } else {
+ if (ltq_pci_config_access(PCI_ACCESS_READ, bus,
+ devfn, where, &data))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (size == 1)
+ data = (data & ~(0xff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ else if (size == 2)
+ data = (data & ~(0xffff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ }
+
+ if (ltq_pci_config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ return PCIBIOS_SUCCESSFUL;
+}
diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c
new file mode 100644
index 000000000000..603d7493e966
--- /dev/null
+++ b/arch/mips/pci/pci-lantiq.c
@@ -0,0 +1,297 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/platform_device.h>
+
+#include <asm/pci.h>
+#include <asm/gpio.h>
+#include <asm/addrspace.h>
+
+#include <lantiq_soc.h>
+#include <lantiq_irq.h>
+#include <lantiq_platform.h>
+
+#include "pci-lantiq.h"
+
+#define LTQ_PCI_CFG_BASE 0x17000000
+#define LTQ_PCI_CFG_SIZE 0x00008000
+#define LTQ_PCI_MEM_BASE 0x18000000
+#define LTQ_PCI_MEM_SIZE 0x02000000
+#define LTQ_PCI_IO_BASE 0x1AE00000
+#define LTQ_PCI_IO_SIZE 0x00200000
+
+#define PCI_CR_FCI_ADDR_MAP0 0x00C0
+#define PCI_CR_FCI_ADDR_MAP1 0x00C4
+#define PCI_CR_FCI_ADDR_MAP2 0x00C8
+#define PCI_CR_FCI_ADDR_MAP3 0x00CC
+#define PCI_CR_FCI_ADDR_MAP4 0x00D0
+#define PCI_CR_FCI_ADDR_MAP5 0x00D4
+#define PCI_CR_FCI_ADDR_MAP6 0x00D8
+#define PCI_CR_FCI_ADDR_MAP7 0x00DC
+#define PCI_CR_CLK_CTRL 0x0000
+#define PCI_CR_PCI_MOD 0x0030
+#define PCI_CR_PC_ARB 0x0080
+#define PCI_CR_FCI_ADDR_MAP11hg 0x00E4
+#define PCI_CR_BAR11MASK 0x0044
+#define PCI_CR_BAR12MASK 0x0048
+#define PCI_CR_BAR13MASK 0x004C
+#define PCI_CS_BASE_ADDR1 0x0010
+#define PCI_CR_PCI_ADDR_MAP11 0x0064
+#define PCI_CR_FCI_BURST_LENGTH 0x00E8
+#define PCI_CR_PCI_EOI 0x002C
+#define PCI_CS_STS_CMD 0x0004
+
+#define PCI_MASTER0_REQ_MASK_2BITS 8
+#define PCI_MASTER1_REQ_MASK_2BITS 10
+#define PCI_MASTER2_REQ_MASK_2BITS 12
+#define INTERNAL_ARB_ENABLE_BIT 0
+
+#define LTQ_CGU_IFCCR 0x0018
+#define LTQ_CGU_PCICR 0x0034
+
+#define ltq_pci_w32(x, y) ltq_w32((x), ltq_pci_membase + (y))
+#define ltq_pci_r32(x) ltq_r32(ltq_pci_membase + (x))
+
+#define ltq_pci_cfg_w32(x, y) ltq_w32((x), ltq_pci_mapped_cfg + (y))
+#define ltq_pci_cfg_r32(x) ltq_r32(ltq_pci_mapped_cfg + (x))
+
+struct ltq_pci_gpio_map {
+ int pin;
+ int alt0;
+ int alt1;
+ int dir;
+ char *name;
+};
+
+/* the pci core can make use of the following gpios */
+static struct ltq_pci_gpio_map ltq_pci_gpio_map[] = {
+ { 0, 1, 0, 0, "pci-exin0" },
+ { 1, 1, 0, 0, "pci-exin1" },
+ { 2, 1, 0, 0, "pci-exin2" },
+ { 39, 1, 0, 0, "pci-exin3" },
+ { 10, 1, 0, 0, "pci-exin4" },
+ { 9, 1, 0, 0, "pci-exin5" },
+ { 30, 1, 0, 1, "pci-gnt1" },
+ { 23, 1, 0, 1, "pci-gnt2" },
+ { 19, 1, 0, 1, "pci-gnt3" },
+ { 38, 1, 0, 1, "pci-gnt4" },
+ { 29, 1, 0, 0, "pci-req1" },
+ { 31, 1, 0, 0, "pci-req2" },
+ { 3, 1, 0, 0, "pci-req3" },
+ { 37, 1, 0, 0, "pci-req4" },
+};
+
+__iomem void *ltq_pci_mapped_cfg;
+static __iomem void *ltq_pci_membase;
+
+int (*ltqpci_plat_dev_init)(struct pci_dev *dev) = NULL;
+
+/* Since the PCI REQ pins can be reused for other functionality, make it
+ possible to exclude those from interpretation by the PCI controller */
+static int ltq_pci_req_mask = 0xf;
+
+static int *ltq_pci_irq_map;
+
+struct pci_ops ltq_pci_ops = {
+ .read = ltq_pci_read_config_dword,
+ .write = ltq_pci_write_config_dword
+};
+
+static struct resource pci_io_resource = {
+ .name = "pci io space",
+ .start = LTQ_PCI_IO_BASE,
+ .end = LTQ_PCI_IO_BASE + LTQ_PCI_IO_SIZE - 1,
+ .flags = IORESOURCE_IO
+};
+
+static struct resource pci_mem_resource = {
+ .name = "pci memory space",
+ .start = LTQ_PCI_MEM_BASE,
+ .end = LTQ_PCI_MEM_BASE + LTQ_PCI_MEM_SIZE - 1,
+ .flags = IORESOURCE_MEM
+};
+
+static struct pci_controller ltq_pci_controller = {
+ .pci_ops = &ltq_pci_ops,
+ .mem_resource = &pci_mem_resource,
+ .mem_offset = 0x00000000UL,
+ .io_resource = &pci_io_resource,
+ .io_offset = 0x00000000UL,
+};
+
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ if (ltqpci_plat_dev_init)
+ return ltqpci_plat_dev_init(dev);
+
+ return 0;
+}
+
+static u32 ltq_calc_bar11mask(void)
+{
+ u32 mem, bar11mask;
+
+ /* BAR11MASK value depends on available memory on system. */
+ mem = num_physpages * PAGE_SIZE;
+ bar11mask = (0x0ffffff0 & ~((1 << (fls(mem) - 1)) - 1)) | 8;
+
+ return bar11mask;
+}
+
+static void ltq_pci_setup_gpio(int gpio)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(ltq_pci_gpio_map); i++) {
+ if (gpio & (1 << i)) {
+ ltq_gpio_request(ltq_pci_gpio_map[i].pin,
+ ltq_pci_gpio_map[i].alt0,
+ ltq_pci_gpio_map[i].alt1,
+ ltq_pci_gpio_map[i].dir,
+ ltq_pci_gpio_map[i].name);
+ }
+ }
+ ltq_gpio_request(21, 0, 0, 1, "pci-reset");
+ ltq_pci_req_mask = (gpio >> PCI_REQ_SHIFT) & PCI_REQ_MASK;
+}
+
+static int __devinit ltq_pci_startup(struct ltq_pci_data *conf)
+{
+ u32 temp_buffer;
+
+ /* set clock to 33Mhz */
+ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~0xf00000, LTQ_CGU_IFCCR);
+ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | 0x800000, LTQ_CGU_IFCCR);
+
+ /* external or internal clock ? */
+ if (conf->clock) {
+ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) & ~(1 << 16),
+ LTQ_CGU_IFCCR);
+ ltq_cgu_w32((1 << 30), LTQ_CGU_PCICR);
+ } else {
+ ltq_cgu_w32(ltq_cgu_r32(LTQ_CGU_IFCCR) | (1 << 16),
+ LTQ_CGU_IFCCR);
+ ltq_cgu_w32((1 << 31) | (1 << 30), LTQ_CGU_PCICR);
+ }
+
+ /* setup pci clock and gpis used by pci */
+ ltq_pci_setup_gpio(conf->gpio);
+
+ /* enable auto-switching between PCI and EBU */
+ ltq_pci_w32(0xa, PCI_CR_CLK_CTRL);
+
+ /* busy, i.e. configuration is not done, PCI access has to be retried */
+ ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_MOD) & ~(1 << 24), PCI_CR_PCI_MOD);
+ wmb();
+ /* BUS Master/IO/MEM access */
+ ltq_pci_cfg_w32(ltq_pci_cfg_r32(PCI_CS_STS_CMD) | 7, PCI_CS_STS_CMD);
+
+ /* enable external 2 PCI masters */
+ temp_buffer = ltq_pci_r32(PCI_CR_PC_ARB);
+ temp_buffer &= (~(ltq_pci_req_mask << 16));
+ /* enable internal arbiter */
+ temp_buffer |= (1 << INTERNAL_ARB_ENABLE_BIT);
+ /* enable internal PCI master reqest */
+ temp_buffer &= (~(3 << PCI_MASTER0_REQ_MASK_2BITS));
+
+ /* enable EBU request */
+ temp_buffer &= (~(3 << PCI_MASTER1_REQ_MASK_2BITS));
+
+ /* enable all external masters request */
+ temp_buffer &= (~(3 << PCI_MASTER2_REQ_MASK_2BITS));
+ ltq_pci_w32(temp_buffer, PCI_CR_PC_ARB);
+ wmb();
+
+ /* setup BAR memory regions */
+ ltq_pci_w32(0x18000000, PCI_CR_FCI_ADDR_MAP0);
+ ltq_pci_w32(0x18400000, PCI_CR_FCI_ADDR_MAP1);
+ ltq_pci_w32(0x18800000, PCI_CR_FCI_ADDR_MAP2);
+ ltq_pci_w32(0x18c00000, PCI_CR_FCI_ADDR_MAP3);
+ ltq_pci_w32(0x19000000, PCI_CR_FCI_ADDR_MAP4);
+ ltq_pci_w32(0x19400000, PCI_CR_FCI_ADDR_MAP5);
+ ltq_pci_w32(0x19800000, PCI_CR_FCI_ADDR_MAP6);
+ ltq_pci_w32(0x19c00000, PCI_CR_FCI_ADDR_MAP7);
+ ltq_pci_w32(0x1ae00000, PCI_CR_FCI_ADDR_MAP11hg);
+ ltq_pci_w32(ltq_calc_bar11mask(), PCI_CR_BAR11MASK);
+ ltq_pci_w32(0, PCI_CR_PCI_ADDR_MAP11);
+ ltq_pci_w32(0, PCI_CS_BASE_ADDR1);
+ /* both TX and RX endian swap are enabled */
+ ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_EOI) | 3, PCI_CR_PCI_EOI);
+ wmb();
+ ltq_pci_w32(ltq_pci_r32(PCI_CR_BAR12MASK) | 0x80000000,
+ PCI_CR_BAR12MASK);
+ ltq_pci_w32(ltq_pci_r32(PCI_CR_BAR13MASK) | 0x80000000,
+ PCI_CR_BAR13MASK);
+ /*use 8 dw burst length */
+ ltq_pci_w32(0x303, PCI_CR_FCI_BURST_LENGTH);
+ ltq_pci_w32(ltq_pci_r32(PCI_CR_PCI_MOD) | (1 << 24), PCI_CR_PCI_MOD);
+ wmb();
+
+ /* setup irq line */
+ ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_CON) | 0xc, LTQ_EBU_PCC_CON);
+ ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_IEN) | 0x10, LTQ_EBU_PCC_IEN);
+
+ /* toggle reset pin */
+ __gpio_set_value(21, 0);
+ wmb();
+ mdelay(1);
+ __gpio_set_value(21, 1);
+ return 0;
+}
+
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ if (ltq_pci_irq_map[slot])
+ return ltq_pci_irq_map[slot];
+ printk(KERN_ERR "lq_pci: trying to map irq for unknown slot %d\n",
+ slot);
+
+ return 0;
+}
+
+static int __devinit ltq_pci_probe(struct platform_device *pdev)
+{
+ struct ltq_pci_data *ltq_pci_data =
+ (struct ltq_pci_data *) pdev->dev.platform_data;
+ pci_probe_only = 0;
+ ltq_pci_irq_map = ltq_pci_data->irq;
+ ltq_pci_membase = ioremap_nocache(PCI_CR_BASE_ADDR, PCI_CR_SIZE);
+ ltq_pci_mapped_cfg =
+ ioremap_nocache(LTQ_PCI_CFG_BASE, LTQ_PCI_CFG_BASE);
+ ltq_pci_controller.io_map_base =
+ (unsigned long)ioremap(LTQ_PCI_IO_BASE, LTQ_PCI_IO_SIZE - 1);
+ ltq_pci_startup(ltq_pci_data);
+ register_pci_controller(&ltq_pci_controller);
+
+ return 0;
+}
+
+static struct platform_driver
+ltq_pci_driver = {
+ .probe = ltq_pci_probe,
+ .driver = {
+ .name = "ltq_pci",
+ .owner = THIS_MODULE,
+ },
+};
+
+int __init pcibios_init(void)
+{
+ int ret = platform_driver_register(&ltq_pci_driver);
+ if (ret)
+ printk(KERN_INFO "ltq_pci: Error registering platfom driver!");
+ return ret;
+}
+
+arch_initcall(pcibios_init);
diff --git a/arch/mips/pci/pci-lantiq.h b/arch/mips/pci/pci-lantiq.h
new file mode 100644
index 000000000000..66bf6cd6be3c
--- /dev/null
+++ b/arch/mips/pci/pci-lantiq.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.
+ *
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#ifndef _LTQ_PCI_H__
+#define _LTQ_PCI_H__
+
+extern __iomem void *ltq_pci_mapped_cfg;
+extern int ltq_pci_read_config_dword(struct pci_bus *bus,
+ unsigned int devfn, int where, int size, u32 *val);
+extern int ltq_pci_write_config_dword(struct pci_bus *bus,
+ unsigned int devfn, int where, int size, u32 val);
+
+#endif
diff --git a/arch/mips/pci/pci-xlr.c b/arch/mips/pci/pci-xlr.c
new file mode 100644
index 000000000000..38fece16c435
--- /dev/null
+++ b/arch/mips/pci/pci-xlr.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). 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 NetLogic
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``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 NETLOGIC OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/console.h>
+
+#include <asm/io.h>
+
+#include <asm/netlogic/interrupt.h>
+#include <asm/netlogic/xlr/iomap.h>
+#include <asm/netlogic/xlr/pic.h>
+#include <asm/netlogic/xlr/xlr.h>
+
+static void *pci_config_base;
+
+#define pci_cfg_addr(bus, devfn, off) (((bus) << 16) | ((devfn) << 8) | (off))
+
+/* PCI ops */
+static inline u32 pci_cfg_read_32bit(struct pci_bus *bus, unsigned int devfn,
+ int where)
+{
+ u32 data;
+ u32 *cfgaddr;
+
+ cfgaddr = (u32 *)(pci_config_base +
+ pci_cfg_addr(bus->number, devfn, where & ~3));
+ data = *cfgaddr;
+ return cpu_to_le32(data);
+}
+
+static inline void pci_cfg_write_32bit(struct pci_bus *bus, unsigned int devfn,
+ int where, u32 data)
+{
+ u32 *cfgaddr;
+
+ cfgaddr = (u32 *)(pci_config_base +
+ pci_cfg_addr(bus->number, devfn, where & ~3));
+ *cfgaddr = cpu_to_le32(data);
+}
+
+static int nlm_pcibios_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *val)
+{
+ u32 data;
+
+ if ((size == 2) && (where & 1))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ else if ((size == 4) && (where & 3))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ data = pci_cfg_read_32bit(bus, devfn, where);
+
+ if (size == 1)
+ *val = (data >> ((where & 3) << 3)) & 0xff;
+ else if (size == 2)
+ *val = (data >> ((where & 3) << 3)) & 0xffff;
+ else
+ *val = data;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+static int nlm_pcibios_write(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ u32 data;
+
+ if ((size == 2) && (where & 1))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ else if ((size == 4) && (where & 3))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ data = pci_cfg_read_32bit(bus, devfn, where);
+
+ if (size == 1)
+ data = (data & ~(0xff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ else if (size == 2)
+ data = (data & ~(0xffff << ((where & 3) << 3))) |
+ (val << ((where & 3) << 3));
+ else
+ data = val;
+
+ pci_cfg_write_32bit(bus, devfn, where, data);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops nlm_pci_ops = {
+ .read = nlm_pcibios_read,
+ .write = nlm_pcibios_write
+};
+
+static struct resource nlm_pci_mem_resource = {
+ .name = "XLR PCI MEM",
+ .start = 0xd0000000UL, /* 256MB PCI mem @ 0xd000_0000 */
+ .end = 0xdfffffffUL,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct resource nlm_pci_io_resource = {
+ .name = "XLR IO MEM",
+ .start = 0x10000000UL, /* 16MB PCI IO @ 0x1000_0000 */
+ .end = 0x100fffffUL,
+ .flags = IORESOURCE_IO,
+};
+
+struct pci_controller nlm_pci_controller = {
+ .index = 0,
+ .pci_ops = &nlm_pci_ops,
+ .mem_resource = &nlm_pci_mem_resource,
+ .mem_offset = 0x00000000UL,
+ .io_resource = &nlm_pci_io_resource,
+ .io_offset = 0x00000000UL,
+};
+
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+ if (!nlm_chip_is_xls())
+ return PIC_PCIX_IRQ; /* for XLR just one IRQ*/
+
+ /*
+ * For XLS PCIe, there is an IRQ per Link, find out which
+ * link the device is on to assign interrupts
+ */
+ if (dev->bus->self == NULL)
+ return 0;
+
+ switch (dev->bus->self->devfn) {
+ case 0x0:
+ return PIC_PCIE_LINK0_IRQ;
+ case 0x8:
+ return PIC_PCIE_LINK1_IRQ;
+ case 0x10:
+ if (nlm_chip_is_xls_b())
+ return PIC_PCIE_XLSB0_LINK2_IRQ;
+ else
+ return PIC_PCIE_LINK2_IRQ;
+ case 0x18:
+ if (nlm_chip_is_xls_b())
+ return PIC_PCIE_XLSB0_LINK3_IRQ;
+ else
+ return PIC_PCIE_LINK3_IRQ;
+ }
+ WARN(1, "Unexpected devfn %d\n", dev->bus->self->devfn);
+ return 0;
+}
+
+/* Do platform specific device initialization at pci_enable_device() time */
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+ return 0;
+}
+
+static int __init pcibios_init(void)
+{
+ /* PSB assigns PCI resources */
+ pci_probe_only = 1;
+ pci_config_base = ioremap(DEFAULT_PCI_CONFIG_BASE, 16 << 20);
+
+ /* Extend IO port for memory mapped io */
+ ioport_resource.start = 0;
+ ioport_resource.end = ~0;
+
+ set_io_port_base(CKSEG1);
+ nlm_pci_controller.io_map_base = CKSEG1;
+
+ pr_info("Registering XLR/XLS PCIX/PCIE Controller.\n");
+ register_pci_controller(&nlm_pci_controller);
+
+ return 0;
+}
+
+arch_initcall(pcibios_init);
+
+struct pci_fixup pcibios_fixups[] = {
+ {0}
+};
diff --git a/arch/mips/pmc-sierra/yosemite/smp.c b/arch/mips/pmc-sierra/yosemite/smp.c
index efc9e889b349..2608752898c0 100644
--- a/arch/mips/pmc-sierra/yosemite/smp.c
+++ b/arch/mips/pmc-sierra/yosemite/smp.c
@@ -55,6 +55,8 @@ void titan_mailbox_irq(void)
if (status & 0x2)
smp_call_function_interrupt();
+ if (status & 0x4)
+ scheduler_ipi();
break;
case 1:
@@ -63,6 +65,8 @@ void titan_mailbox_irq(void)
if (status & 0x2)
smp_call_function_interrupt();
+ if (status & 0x4)
+ scheduler_ipi();
break;
}
}
diff --git a/arch/mips/sgi-ip22/ip22-hpc.c b/arch/mips/sgi-ip22/ip22-hpc.c
index 5c00cdd20d8e..bb70589b5f74 100644
--- a/arch/mips/sgi-ip22/ip22-hpc.c
+++ b/arch/mips/sgi-ip22/ip22-hpc.c
@@ -1,7 +1,7 @@
/*
* ip22-hpc.c: Routines for generic manipulation of the HPC controllers.
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
* Copyright (C) 1998 Ralf Baechle
*/
diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c
index 476423a01296..b4d08e4d2ea9 100644
--- a/arch/mips/sgi-ip22/ip22-int.c
+++ b/arch/mips/sgi-ip22/ip22-int.c
@@ -2,7 +2,7 @@
* ip22-int.c: Routines for generic manipulation of the INT[23] ASIC
* found on INDY and Indigo2 workstations.
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
* Copyright (C) 1997, 1998 Ralf Baechle (ralf@gnu.org)
* Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu)
* - Indigo2 changes
diff --git a/arch/mips/sgi-ip22/ip22-mc.c b/arch/mips/sgi-ip22/ip22-mc.c
index 5268ac187bbd..d22262ee6853 100644
--- a/arch/mips/sgi-ip22/ip22-mc.c
+++ b/arch/mips/sgi-ip22/ip22-mc.c
@@ -1,7 +1,7 @@
/*
* ip22-mc.c: Routines for manipulating SGI Memory Controller.
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
* Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) - Indigo2 changes
* Copyright (C) 2003 Ladislav Michl (ladis@linux-mips.org)
* Copyright (C) 2004 Peter Fuerst (pf@net.alphadv.de) - IP28
diff --git a/arch/mips/sgi-ip22/ip22-setup.c b/arch/mips/sgi-ip22/ip22-setup.c
index 5deeb68b6c9c..5e6621349471 100644
--- a/arch/mips/sgi-ip22/ip22-setup.c
+++ b/arch/mips/sgi-ip22/ip22-setup.c
@@ -1,7 +1,7 @@
/*
* ip22-setup.c: SGI specific setup, including init of the feature struct.
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
* Copyright (C) 1997, 1998 Ralf Baechle (ralf@gnu.org)
*/
#include <linux/init.h>
diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c
index 0a04603d577c..b18b04e48577 100644
--- a/arch/mips/sgi-ip27/ip27-irq.c
+++ b/arch/mips/sgi-ip27/ip27-irq.c
@@ -147,8 +147,10 @@ static void ip27_do_irq_mask0(void)
#ifdef CONFIG_SMP
if (pend0 & (1UL << CPU_RESCHED_A_IRQ)) {
LOCAL_HUB_CLR_INTR(CPU_RESCHED_A_IRQ);
+ scheduler_ipi();
} else if (pend0 & (1UL << CPU_RESCHED_B_IRQ)) {
LOCAL_HUB_CLR_INTR(CPU_RESCHED_B_IRQ);
+ scheduler_ipi();
} else if (pend0 & (1UL << CPU_CALL_A_IRQ)) {
LOCAL_HUB_CLR_INTR(CPU_CALL_A_IRQ);
smp_call_function_interrupt();
diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c
index a152538d3c97..ef74f3267f91 100644
--- a/arch/mips/sgi-ip27/ip27-timer.c
+++ b/arch/mips/sgi-ip27/ip27-timer.c
@@ -66,18 +66,7 @@ static int rt_next_event(unsigned long delta, struct clock_event_device *evt)
static void rt_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
- switch (mode) {
- case CLOCK_EVT_MODE_ONESHOT:
- /* The only mode supported */
- break;
-
- case CLOCK_EVT_MODE_PERIODIC:
- case CLOCK_EVT_MODE_UNUSED:
- case CLOCK_EVT_MODE_SHUTDOWN:
- case CLOCK_EVT_MODE_RESUME:
- /* Nothing to do */
- break;
- }
+ /* Nothing to do ... */
}
int rt_timer_irq;
@@ -174,8 +163,7 @@ static void __init hub_rt_clocksource_init(void)
{
struct clocksource *cs = &hub_rt_clocksource;
- clocksource_set_clock(cs, CYCLES_PER_SEC);
- clocksource_register(cs);
+ clocksource_register_hz(cs, CYCLES_PER_SEC);
}
void __init plat_time_init(void)
diff --git a/arch/mips/sibyte/bcm1480/smp.c b/arch/mips/sibyte/bcm1480/smp.c
index 47b347c992ea..d667875be564 100644
--- a/arch/mips/sibyte/bcm1480/smp.c
+++ b/arch/mips/sibyte/bcm1480/smp.c
@@ -20,6 +20,7 @@
#include <linux/delay.h>
#include <linux/smp.h>
#include <linux/kernel_stat.h>
+#include <linux/sched.h>
#include <asm/mmu_context.h>
#include <asm/io.h>
@@ -189,10 +190,8 @@ void bcm1480_mailbox_interrupt(void)
/* Clear the mailbox to clear the interrupt */
__raw_writeq(((u64)action)<<48, mailbox_0_clear_regs[cpu]);
- /*
- * Nothing to do for SMP_RESCHEDULE_YOURSELF; returning from the
- * interrupt will do the reschedule for us
- */
+ if (action & SMP_RESCHEDULE_YOURSELF)
+ scheduler_ipi();
if (action & SMP_CALL_FUNCTION)
smp_call_function_interrupt();
diff --git a/arch/mips/sibyte/sb1250/smp.c b/arch/mips/sibyte/sb1250/smp.c
index c00a5cb1128d..38e7f6bd7922 100644
--- a/arch/mips/sibyte/sb1250/smp.c
+++ b/arch/mips/sibyte/sb1250/smp.c
@@ -21,6 +21,7 @@
#include <linux/interrupt.h>
#include <linux/smp.h>
#include <linux/kernel_stat.h>
+#include <linux/sched.h>
#include <asm/mmu_context.h>
#include <asm/io.h>
@@ -177,10 +178,8 @@ void sb1250_mailbox_interrupt(void)
/* Clear the mailbox to clear the interrupt */
____raw_writeq(((u64)action) << 48, mailbox_clear_regs[cpu]);
- /*
- * Nothing to do for SMP_RESCHEDULE_YOURSELF; returning from the
- * interrupt will do the reschedule for us
- */
+ if (action & SMP_RESCHEDULE_YOURSELF)
+ scheduler_ipi();
if (action & SMP_CALL_FUNCTION)
smp_call_function_interrupt();
diff --git a/arch/mips/txx9/generic/setup_tx4939.c b/arch/mips/txx9/generic/setup_tx4939.c
index 3dc19f482959..e9f95dcde379 100644
--- a/arch/mips/txx9/generic/setup_tx4939.c
+++ b/arch/mips/txx9/generic/setup_tx4939.c
@@ -318,19 +318,15 @@ void __init tx4939_sio_init(unsigned int sclk, unsigned int cts_mask)
}
#if defined(CONFIG_TC35815) || defined(CONFIG_TC35815_MODULE)
-static int tx4939_get_eth_speed(struct net_device *dev)
+static u32 tx4939_get_eth_speed(struct net_device *dev)
{
- struct ethtool_cmd cmd = { ETHTOOL_GSET };
- int speed = 100; /* default 100Mbps */
- int err;
- if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings)
- return speed;
- err = dev->ethtool_ops->get_settings(dev, &cmd);
- if (err < 0)
- return speed;
- speed = cmd.speed == SPEED_100 ? 100 : 10;
- return speed;
+ struct ethtool_cmd cmd;
+ if (dev_ethtool_get_settings(dev, &cmd))
+ return 100; /* default 100Mbps */
+
+ return ethtool_cmd_speed(&cmd);
}
+
static int tx4939_netdev_event(struct notifier_block *this,
unsigned long event,
void *ptr)
@@ -343,8 +339,7 @@ static int tx4939_netdev_event(struct notifier_block *this,
else if (dev->irq == TXX9_IRQ_BASE + TX4939_IR_ETH(1))
bit = TX4939_PCFG_SPEED1;
if (bit) {
- int speed = tx4939_get_eth_speed(dev);
- if (speed == 100)
+ if (tx4939_get_eth_speed(dev) == 100)
txx9_set64(&tx4939_ccfgptr->pcfg, bit);
else
txx9_clear64(&tx4939_ccfgptr->pcfg, bit);
diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig
index feaf09cc8632..1f870340ebdd 100644
--- a/arch/mn10300/Kconfig
+++ b/arch/mn10300/Kconfig
@@ -44,9 +44,6 @@ config GENERIC_CALIBRATE_DELAY
config GENERIC_CMOS_UPDATE
def_bool n
-config GENERIC_FIND_NEXT_BIT
- def_bool y
-
config GENERIC_HWEIGHT
def_bool y
diff --git a/arch/mn10300/configs/asb2364_defconfig b/arch/mn10300/configs/asb2364_defconfig
index 31d76261a3d5..fbb96ae3122a 100644
--- a/arch/mn10300/configs/asb2364_defconfig
+++ b/arch/mn10300/configs/asb2364_defconfig
@@ -8,7 +8,6 @@ CONFIG_TASK_XACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_CGROUPS=y
-CONFIG_CGROUP_NS=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
diff --git a/arch/mn10300/kernel/irq.c b/arch/mn10300/kernel/irq.c
index 86af0d7d0771..2623d19f4f4c 100644
--- a/arch/mn10300/kernel/irq.c
+++ b/arch/mn10300/kernel/irq.c
@@ -87,7 +87,7 @@ static void mn10300_cpupic_mask_ack(struct irq_data *d)
tmp2 = GxICR(irq);
irq_affinity_online[irq] =
- any_online_cpu(*d->affinity);
+ cpumask_any_and(d->affinity, cpu_online_mask);
CROSS_GxICR(irq, irq_affinity_online[irq]) =
(tmp & (GxICR_LEVEL | GxICR_ENABLE)) | GxICR_DETECT;
tmp = CROSS_GxICR(irq, irq_affinity_online[irq]);
@@ -124,7 +124,8 @@ static void mn10300_cpupic_unmask_clear(struct irq_data *d)
} else {
tmp = GxICR(irq);
- irq_affinity_online[irq] = any_online_cpu(*d->affinity);
+ irq_affinity_online[irq] = cpumask_any_and(d->affinity,
+ cpu_online_mask);
CROSS_GxICR(irq, irq_affinity_online[irq]) = (tmp & GxICR_LEVEL) | GxICR_ENABLE | GxICR_DETECT;
tmp = CROSS_GxICR(irq, irq_affinity_online[irq]);
}
@@ -366,11 +367,11 @@ void migrate_irqs(void)
if (irqd_is_per_cpu(data))
continue;
- if (cpu_isset(self, data->affinity) &&
- !cpus_intersects(irq_affinity[irq], cpu_online_map)) {
+ if (cpumask_test_cpu(self, &data->affinity) &&
+ !cpumask_intersects(&irq_affinity[irq], cpu_online_mask)) {
int cpu_id;
- cpu_id = first_cpu(cpu_online_map);
- cpu_set(cpu_id, data->affinity);
+ cpu_id = cpumask_first(cpu_online_mask);
+ cpumask_set_cpu(cpu_id, &data->affinity);
}
/* We need to operate irq_affinity_online atomically. */
arch_local_cli_save(flags);
@@ -381,7 +382,8 @@ void migrate_irqs(void)
GxICR(irq) = x & GxICR_LEVEL;
tmp = GxICR(irq);
- new = any_online_cpu(data->affinity);
+ new = cpumask_any_and(&data->affinity,
+ cpu_online_mask);
irq_affinity_online[irq] = new;
CROSS_GxICR(irq, new) =
diff --git a/arch/mn10300/kernel/smp.c b/arch/mn10300/kernel/smp.c
index 226c826a2194..9242e9fcc564 100644
--- a/arch/mn10300/kernel/smp.c
+++ b/arch/mn10300/kernel/smp.c
@@ -309,7 +309,7 @@ static void send_IPI_mask(const cpumask_t *cpumask, int irq)
u16 tmp;
for (i = 0; i < NR_CPUS; i++) {
- if (cpu_isset(i, *cpumask)) {
+ if (cpumask_test_cpu(i, cpumask)) {
/* send IPI */
tmp = CROSS_GxICR(irq, i);
CROSS_GxICR(irq, i) =
@@ -342,8 +342,8 @@ void send_IPI_allbutself(int irq)
{
cpumask_t cpumask;
- cpumask = cpu_online_map;
- cpu_clear(smp_processor_id(), cpumask);
+ cpumask_copy(&cpumask, cpu_online_mask);
+ cpumask_clear_cpu(smp_processor_id(), &cpumask);
send_IPI_mask(&cpumask, irq);
}
@@ -393,8 +393,8 @@ int smp_nmi_call_function(smp_call_func_t func, void *info, int wait)
data.func = func;
data.info = info;
- data.started = cpu_online_map;
- cpu_clear(smp_processor_id(), data.started);
+ cpumask_copy(&data.started, cpu_online_mask);
+ cpumask_clear_cpu(smp_processor_id(), &data.started);
data.wait = wait;
if (wait)
data.finished = data.started;
@@ -410,14 +410,14 @@ int smp_nmi_call_function(smp_call_func_t func, void *info, int wait)
if (CALL_FUNCTION_NMI_IPI_TIMEOUT > 0) {
for (cnt = 0;
cnt < CALL_FUNCTION_NMI_IPI_TIMEOUT &&
- !cpus_empty(data.started);
+ !cpumask_empty(&data.started);
cnt++)
mdelay(1);
if (wait && cnt < CALL_FUNCTION_NMI_IPI_TIMEOUT) {
for (cnt = 0;
cnt < CALL_FUNCTION_NMI_IPI_TIMEOUT &&
- !cpus_empty(data.finished);
+ !cpumask_empty(&data.finished);
cnt++)
mdelay(1);
}
@@ -428,10 +428,10 @@ int smp_nmi_call_function(smp_call_func_t func, void *info, int wait)
} else {
/* If timeout value is zero, wait until cpumask has been
* cleared */
- while (!cpus_empty(data.started))
+ while (!cpumask_empty(&data.started))
barrier();
if (wait)
- while (!cpus_empty(data.finished))
+ while (!cpumask_empty(&data.finished))
barrier();
}
@@ -472,12 +472,12 @@ void stop_this_cpu(void *unused)
#endif /* CONFIG_GDBSTUB */
flags = arch_local_cli_save();
- cpu_clear(smp_processor_id(), cpu_online_map);
+ set_cpu_online(smp_processor_id(), false);
while (!stopflag)
cpu_relax();
- cpu_set(smp_processor_id(), cpu_online_map);
+ set_cpu_online(smp_processor_id(), true);
arch_local_irq_restore(flags);
}
@@ -494,14 +494,11 @@ void smp_send_stop(void)
* @irq: The interrupt number.
* @dev_id: The device ID.
*
- * We need do nothing here, since the scheduling will be effected on our way
- * back through entry.S.
- *
* Returns IRQ_HANDLED to indicate we handled the interrupt successfully.
*/
static irqreturn_t smp_reschedule_interrupt(int irq, void *dev_id)
{
- /* do nothing */
+ scheduler_ipi();
return IRQ_HANDLED;
}
@@ -532,12 +529,13 @@ void smp_nmi_call_function_interrupt(void)
* execute the function
*/
smp_mb();
- cpu_clear(smp_processor_id(), nmi_call_data->started);
+ cpumask_clear_cpu(smp_processor_id(), &nmi_call_data->started);
(*func)(info);
if (wait) {
smp_mb();
- cpu_clear(smp_processor_id(), nmi_call_data->finished);
+ cpumask_clear_cpu(smp_processor_id(),
+ &nmi_call_data->finished);
}
}
@@ -660,7 +658,7 @@ int __init start_secondary(void *unused)
{
smp_cpu_init();
smp_callin();
- while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
+ while (!cpumask_test_cpu(smp_processor_id(), &smp_commenced_mask))
cpu_relax();
local_flush_tlb();
@@ -783,13 +781,14 @@ static int __init do_boot_cpu(int phy_id)
if (send_status == 0) {
/* Allow AP to start initializing */
- cpu_set(cpu_id, cpu_callout_map);
+ cpumask_set_cpu(cpu_id, &cpu_callout_map);
/* Wait for setting cpu_callin_map */
timeout = 0;
do {
udelay(1000);
- callin_status = cpu_isset(cpu_id, cpu_callin_map);
+ callin_status = cpumask_test_cpu(cpu_id,
+ &cpu_callin_map);
} while (callin_status == 0 && timeout++ < 5000);
if (callin_status == 0)
@@ -799,9 +798,9 @@ static int __init do_boot_cpu(int phy_id)
}
if (send_status == GxICR_REQUEST || callin_status == 0) {
- cpu_clear(cpu_id, cpu_callout_map);
- cpu_clear(cpu_id, cpu_callin_map);
- cpu_clear(cpu_id, cpu_initialized);
+ cpumask_clear_cpu(cpu_id, &cpu_callout_map);
+ cpumask_clear_cpu(cpu_id, &cpu_callin_map);
+ cpumask_clear_cpu(cpu_id, &cpu_initialized);
cpucount--;
return 1;
}
@@ -836,7 +835,7 @@ static void __init smp_callin(void)
cpu = smp_processor_id();
timeout = jiffies + (2 * HZ);
- if (cpu_isset(cpu, cpu_callin_map)) {
+ if (cpumask_test_cpu(cpu, &cpu_callin_map)) {
printk(KERN_ERR "CPU#%d already present.\n", cpu);
BUG();
}
@@ -844,7 +843,7 @@ static void __init smp_callin(void)
/* Wait for AP startup 2s total */
while (time_before(jiffies, timeout)) {
- if (cpu_isset(cpu, cpu_callout_map))
+ if (cpumask_test_cpu(cpu, &cpu_callout_map))
break;
cpu_relax();
}
@@ -864,11 +863,11 @@ static void __init smp_callin(void)
smp_store_cpu_info(cpu);
/* Allow the boot processor to continue */
- cpu_set(cpu, cpu_callin_map);
+ cpumask_set_cpu(cpu, &cpu_callin_map);
}
/**
- * smp_online - Set cpu_online_map
+ * smp_online - Set cpu_online_mask
*/
static void __init smp_online(void)
{
@@ -878,7 +877,7 @@ static void __init smp_online(void)
local_irq_enable();
- cpu_set(cpu, cpu_online_map);
+ set_cpu_online(cpu, true);
smp_wmb();
}
@@ -895,13 +894,13 @@ void __init smp_cpus_done(unsigned int max_cpus)
/*
* smp_prepare_boot_cpu - Set up stuff for the boot processor.
*
- * Set up the cpu_online_map, cpu_callout_map and cpu_callin_map of the boot
+ * Set up the cpu_online_mask, cpu_callout_map and cpu_callin_map of the boot
* processor (CPU 0).
*/
void __devinit smp_prepare_boot_cpu(void)
{
- cpu_set(0, cpu_callout_map);
- cpu_set(0, cpu_callin_map);
+ cpumask_set_cpu(0, &cpu_callout_map);
+ cpumask_set_cpu(0, &cpu_callin_map);
current_thread_info()->cpu = 0;
}
@@ -934,16 +933,16 @@ int __devinit __cpu_up(unsigned int cpu)
run_wakeup_cpu(cpu);
#endif /* CONFIG_HOTPLUG_CPU */
- cpu_set(cpu, smp_commenced_mask);
+ cpumask_set_cpu(cpu, &smp_commenced_mask);
/* Wait 5s total for a response */
for (timeout = 0 ; timeout < 5000 ; timeout++) {
- if (cpu_isset(cpu, cpu_online_map))
+ if (cpu_online(cpu))
break;
udelay(1000);
}
- BUG_ON(!cpu_isset(cpu, cpu_online_map));
+ BUG_ON(!cpu_online(cpu));
return 0;
}
@@ -989,7 +988,7 @@ int __cpu_disable(void)
return -EBUSY;
migrate_irqs();
- cpu_clear(cpu, current->active_mm->cpu_vm_mask);
+ cpumask_clear_cpu(cpu, &mm_cpumask(current->active_mm));
return 0;
}
@@ -1094,13 +1093,13 @@ static int hotplug_cpu_nmi_call_function(cpumask_t cpumask,
do {
mn10300_local_dcache_inv_range(start, end);
barrier();
- } while (!cpus_empty(nmi_call_func_mask_data.started));
+ } while (!cpumask_empty(&nmi_call_func_mask_data.started));
if (wait) {
do {
mn10300_local_dcache_inv_range(start, end);
barrier();
- } while (!cpus_empty(nmi_call_func_mask_data.finished));
+ } while (!cpumask_empty(&nmi_call_func_mask_data.finished));
}
spin_unlock(&smp_nmi_call_lock);
@@ -1111,9 +1110,9 @@ static void restart_wakeup_cpu(void)
{
unsigned int cpu = smp_processor_id();
- cpu_set(cpu, cpu_callin_map);
+ cpumask_set_cpu(cpu, &cpu_callin_map);
local_flush_tlb();
- cpu_set(cpu, cpu_online_map);
+ set_cpu_online(cpu, true);
smp_wmb();
}
@@ -1144,8 +1143,9 @@ static void sleep_cpu(void *unused)
static void run_sleep_cpu(unsigned int cpu)
{
unsigned long flags;
- cpumask_t cpumask = cpumask_of(cpu);
+ cpumask_t cpumask;
+ cpumask_copy(&cpumask, &cpumask_of(cpu));
flags = arch_local_cli_save();
hotplug_cpu_nmi_call_function(cpumask, prepare_sleep_cpu, NULL, 1);
hotplug_cpu_nmi_call_function(cpumask, sleep_cpu, NULL, 0);
diff --git a/arch/mn10300/kernel/vmlinux.lds.S b/arch/mn10300/kernel/vmlinux.lds.S
index 968bcd2cb022..6f702a6ab395 100644
--- a/arch/mn10300/kernel/vmlinux.lds.S
+++ b/arch/mn10300/kernel/vmlinux.lds.S
@@ -70,7 +70,7 @@ SECTIONS
.exit.text : { EXIT_TEXT; }
.exit.data : { EXIT_DATA; }
- PERCPU(32, PAGE_SIZE)
+ PERCPU_SECTION(32)
. = ALIGN(PAGE_SIZE);
__init_end = .;
/* freed after init ends here */
diff --git a/arch/mn10300/mm/cache-smp.c b/arch/mn10300/mm/cache-smp.c
index 4a6e9a4b5b27..2d23b9eeee62 100644
--- a/arch/mn10300/mm/cache-smp.c
+++ b/arch/mn10300/mm/cache-smp.c
@@ -74,7 +74,7 @@ void smp_cache_interrupt(void)
break;
}
- cpu_clear(smp_processor_id(), smp_cache_ipi_map);
+ cpumask_clear_cpu(smp_processor_id(), &smp_cache_ipi_map);
}
/**
@@ -94,12 +94,12 @@ void smp_cache_call(unsigned long opr_mask,
smp_cache_mask = opr_mask;
smp_cache_start = start;
smp_cache_end = end;
- smp_cache_ipi_map = cpu_online_map;
- cpu_clear(smp_processor_id(), smp_cache_ipi_map);
+ cpumask_copy(&smp_cache_ipi_map, cpu_online_mask);
+ cpumask_clear_cpu(smp_processor_id(), &smp_cache_ipi_map);
send_IPI_allbutself(FLUSH_CACHE_IPI);
- while (!cpus_empty(smp_cache_ipi_map))
+ while (!cpumask_empty(&smp_cache_ipi_map))
/* nothing. lockup detection does not belong here */
mb();
}
diff --git a/arch/mn10300/mm/init.c b/arch/mn10300/mm/init.c
index 48907cc3bdb7..13801824e3ee 100644
--- a/arch/mn10300/mm/init.c
+++ b/arch/mn10300/mm/init.c
@@ -37,8 +37,6 @@
#include <asm/tlb.h>
#include <asm/sections.h>
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
unsigned long highstart_pfn, highend_pfn;
#ifdef CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
diff --git a/arch/mn10300/mm/tlb-smp.c b/arch/mn10300/mm/tlb-smp.c
index 0b6a5ad1960e..9a777498a916 100644
--- a/arch/mn10300/mm/tlb-smp.c
+++ b/arch/mn10300/mm/tlb-smp.c
@@ -64,7 +64,7 @@ void smp_flush_tlb(void *unused)
cpu_id = get_cpu();
- if (!cpu_isset(cpu_id, flush_cpumask))
+ if (!cpumask_test_cpu(cpu_id, &flush_cpumask))
/* This was a BUG() but until someone can quote me the line
* from the intel manual that guarantees an IPI to multiple
* CPUs is retried _only_ on the erroring CPUs its staying as a
@@ -80,7 +80,7 @@ void smp_flush_tlb(void *unused)
local_flush_tlb_page(flush_mm, flush_va);
smp_mb__before_clear_bit();
- cpu_clear(cpu_id, flush_cpumask);
+ cpumask_clear_cpu(cpu_id, &flush_cpumask);
smp_mb__after_clear_bit();
out:
put_cpu();
@@ -103,11 +103,11 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
* - we do not send IPIs to as-yet unbooted CPUs.
*/
BUG_ON(!mm);
- BUG_ON(cpus_empty(cpumask));
- BUG_ON(cpu_isset(smp_processor_id(), cpumask));
+ BUG_ON(cpumask_empty(&cpumask));
+ BUG_ON(cpumask_test_cpu(smp_processor_id(), &cpumask));
- cpus_and(tmp, cpumask, cpu_online_map);
- BUG_ON(!cpus_equal(cpumask, tmp));
+ cpumask_and(&tmp, &cpumask, cpu_online_mask);
+ BUG_ON(!cpumask_equal(&cpumask, &tmp));
/* I'm not happy about this global shared spinlock in the MM hot path,
* but we'll see how contended it is.
@@ -128,7 +128,7 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
/* FIXME: if NR_CPUS>=3, change send_IPI_mask */
smp_call_function(smp_flush_tlb, NULL, 1);
- while (!cpus_empty(flush_cpumask))
+ while (!cpumask_empty(&flush_cpumask))
/* Lockup detection does not belong here */
smp_mb();
@@ -146,11 +146,11 @@ void flush_tlb_mm(struct mm_struct *mm)
cpumask_t cpu_mask;
preempt_disable();
- cpu_mask = mm->cpu_vm_mask;
- cpu_clear(smp_processor_id(), cpu_mask);
+ cpumask_copy(&cpu_mask, mm_cpumask(mm));
+ cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
local_flush_tlb();
- if (!cpus_empty(cpu_mask))
+ if (!cpumask_empty(&cpu_mask))
flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
preempt_enable();
@@ -165,11 +165,11 @@ void flush_tlb_current_task(void)
cpumask_t cpu_mask;
preempt_disable();
- cpu_mask = mm->cpu_vm_mask;
- cpu_clear(smp_processor_id(), cpu_mask);
+ cpumask_copy(&cpu_mask, mm_cpumask(mm));
+ cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
local_flush_tlb();
- if (!cpus_empty(cpu_mask))
+ if (!cpumask_empty(&cpu_mask))
flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
preempt_enable();
@@ -186,11 +186,11 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long va)
cpumask_t cpu_mask;
preempt_disable();
- cpu_mask = mm->cpu_vm_mask;
- cpu_clear(smp_processor_id(), cpu_mask);
+ cpumask_copy(&cpu_mask, mm_cpumask(mm));
+ cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
local_flush_tlb_page(mm, va);
- if (!cpus_empty(cpu_mask))
+ if (!cpumask_empty(&cpu_mask))
flush_tlb_others(cpu_mask, mm, va);
preempt_enable();
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index 69ff049c8571..65adc86a230e 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -47,14 +47,6 @@ config ARCH_HAS_ILOG2_U64
bool
default n
-config GENERIC_FIND_NEXT_BIT
- bool
- default y
-
-config GENERIC_FIND_BIT_LE
- bool
- default y
-
config GENERIC_BUG
bool
default y
diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h
index d18328b3f938..da601dd34c05 100644
--- a/arch/parisc/include/asm/cacheflush.h
+++ b/arch/parisc/include/asm/cacheflush.h
@@ -3,6 +3,7 @@
#include <linux/mm.h>
#include <linux/uaccess.h>
+#include <asm/tlbflush.h>
/* The usual comment is "Caches aren't brain-dead on the <architecture>".
* Unfortunately, that doesn't apply to PA-RISC. */
@@ -112,8 +113,10 @@ void flush_dcache_page_asm(unsigned long phys_addr, unsigned long vaddr);
static inline void
flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vmaddr)
{
- if (PageAnon(page))
+ if (PageAnon(page)) {
+ flush_tlb_page(vma, vmaddr);
flush_dcache_page_asm(page_to_phys(page), vmaddr);
+ }
}
#ifdef CONFIG_DEBUG_RODATA
diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h
index 5d7b8ce9fdf3..22dadeb58695 100644
--- a/arch/parisc/include/asm/pgtable.h
+++ b/arch/parisc/include/asm/pgtable.h
@@ -177,7 +177,10 @@ struct vm_area_struct;
#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | _PAGE_DIRTY | _PAGE_ACCESSED)
#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
-#define _PAGE_KERNEL (_PAGE_PRESENT | _PAGE_EXEC | _PAGE_READ | _PAGE_WRITE | _PAGE_DIRTY | _PAGE_ACCESSED)
+#define _PAGE_KERNEL_RO (_PAGE_PRESENT | _PAGE_READ | _PAGE_DIRTY | _PAGE_ACCESSED)
+#define _PAGE_KERNEL_EXEC (_PAGE_KERNEL_RO | _PAGE_EXEC)
+#define _PAGE_KERNEL_RWX (_PAGE_KERNEL_EXEC | _PAGE_WRITE)
+#define _PAGE_KERNEL (_PAGE_KERNEL_RO | _PAGE_WRITE)
/* The pgd/pmd contains a ptr (in phys addr space); since all pgds/pmds
* are page-aligned, we don't care about the PAGE_OFFSET bits, except
@@ -208,7 +211,9 @@ struct vm_area_struct;
#define PAGE_COPY PAGE_EXECREAD
#define PAGE_RWX __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_WRITE | _PAGE_EXEC |_PAGE_ACCESSED)
#define PAGE_KERNEL __pgprot(_PAGE_KERNEL)
-#define PAGE_KERNEL_RO __pgprot(_PAGE_KERNEL & ~_PAGE_WRITE)
+#define PAGE_KERNEL_EXEC __pgprot(_PAGE_KERNEL_EXEC)
+#define PAGE_KERNEL_RWX __pgprot(_PAGE_KERNEL_RWX)
+#define PAGE_KERNEL_RO __pgprot(_PAGE_KERNEL_RO)
#define PAGE_KERNEL_UNC __pgprot(_PAGE_KERNEL | _PAGE_NO_CACHE)
#define PAGE_GATEWAY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_GATEWAY| _PAGE_READ)
diff --git a/arch/parisc/include/asm/smp.h b/arch/parisc/include/asm/smp.h
index 2e73623feb6b..e8f8037d872b 100644
--- a/arch/parisc/include/asm/smp.h
+++ b/arch/parisc/include/asm/smp.h
@@ -33,15 +33,6 @@ extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
#endif /* !ASSEMBLY */
-/*
- * This magic constant controls our willingness to transfer
- * a process across CPUs. Such a transfer incurs cache and tlb
- * misses. The current value is inherited from i386. Still needs
- * to be tuned for parisc.
- */
-
-#define PROC_CHANGE_PENALTY 15 /* Schedule penalty */
-
#define raw_smp_processor_id() (current_thread_info()->cpu)
#else /* CONFIG_SMP */
diff --git a/arch/parisc/include/asm/unistd.h b/arch/parisc/include/asm/unistd.h
index 3eb82c2a5ec3..9cbc2c3bf630 100644
--- a/arch/parisc/include/asm/unistd.h
+++ b/arch/parisc/include/asm/unistd.h
@@ -814,8 +814,14 @@
#define __NR_recvmmsg (__NR_Linux + 319)
#define __NR_accept4 (__NR_Linux + 320)
#define __NR_prlimit64 (__NR_Linux + 321)
-
-#define __NR_Linux_syscalls (__NR_prlimit64 + 1)
+#define __NR_fanotify_init (__NR_Linux + 322)
+#define __NR_fanotify_mark (__NR_Linux + 323)
+#define __NR_clock_adjtime (__NR_Linux + 324)
+#define __NR_name_to_handle_at (__NR_Linux + 325)
+#define __NR_open_by_handle_at (__NR_Linux + 326)
+#define __NR_syncfs (__NR_Linux + 327)
+
+#define __NR_Linux_syscalls (__NR_syncfs + 1)
#define __IGNORE_select /* newselect */
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index 3f11331c2775..83335f3da5fc 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -304,10 +304,20 @@ void flush_dcache_page(struct page *page)
offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT;
addr = mpnt->vm_start + offset;
+ /* The TLB is the engine of coherence on parisc: The
+ * CPU is entitled to speculate any page with a TLB
+ * mapping, so here we kill the mapping then flush the
+ * page along a special flush only alias mapping.
+ * This guarantees that the page is no-longer in the
+ * cache for any process and nor may it be
+ * speculatively read in (until the user or kernel
+ * specifically accesses it, of course) */
+
+ flush_tlb_page(mpnt, addr);
if (old_addr == 0 || (old_addr & (SHMLBA - 1)) != (addr & (SHMLBA - 1))) {
__flush_cache_page(mpnt, addr, page_to_phys(page));
if (old_addr)
- printk(KERN_ERR "INEQUIVALENT ALIASES 0x%lx and 0x%lx in file %s\n", old_addr, addr, mpnt->vm_file ? mpnt->vm_file->f_path.dentry->d_name.name : "(null)");
+ printk(KERN_ERR "INEQUIVALENT ALIASES 0x%lx and 0x%lx in file %s\n", old_addr, addr, mpnt->vm_file ? (char *)mpnt->vm_file->f_path.dentry->d_name.name : "(null)");
old_addr = addr;
}
}
@@ -499,6 +509,7 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long
{
BUG_ON(!vma->vm_mm->context);
+ flush_tlb_page(vma, vmaddr);
__flush_cache_page(vma, vmaddr, page_to_phys(pfn_to_page(pfn)));
}
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
index ead8d2a1034c..6f0594439143 100644
--- a/arch/parisc/kernel/entry.S
+++ b/arch/parisc/kernel/entry.S
@@ -692,6 +692,9 @@ ENTRY(fault_vector_11)
END(fault_vector_11)
#endif
+ /* Fault vector is separately protected and *must* be on its own page */
+ .align PAGE_SIZE
+ENTRY(end_fault_vector)
.import handle_interruption,code
.import do_cpu_irq_mask,code
diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S
index 145c5e4caaa0..37aabd772fbb 100644
--- a/arch/parisc/kernel/head.S
+++ b/arch/parisc/kernel/head.S
@@ -106,8 +106,9 @@ $bss_loop:
#endif
- /* Now initialize the PTEs themselves */
- ldo 0+_PAGE_KERNEL(%r0),%r3 /* Hardwired 0 phys addr start */
+ /* Now initialize the PTEs themselves. We use RWX for
+ * everything ... it will get remapped correctly later */
+ ldo 0+_PAGE_KERNEL_RWX(%r0),%r3 /* Hardwired 0 phys addr start */
ldi (1<<(KERNEL_INITIAL_ORDER-PAGE_SHIFT)),%r11 /* PFN count */
load32 PA(pg0),%r1
diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c
index 6e81bb596e5b..cedbbb8b18d9 100644
--- a/arch/parisc/kernel/module.c
+++ b/arch/parisc/kernel/module.c
@@ -61,8 +61,10 @@
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/bug.h>
+#include <linux/mm.h>
#include <linux/slab.h>
+#include <asm/pgtable.h>
#include <asm/unwind.h>
#if 0
@@ -214,7 +216,13 @@ void *module_alloc(unsigned long size)
{
if (size == 0)
return NULL;
- return vmalloc(size);
+ /* using RWX means less protection for modules, but it's
+ * easier than trying to map the text, data, init_text and
+ * init_data correctly */
+ return __vmalloc_node_range(size, 1, VMALLOC_START, VMALLOC_END,
+ GFP_KERNEL | __GFP_HIGHMEM,
+ PAGE_KERNEL_RWX, -1,
+ __builtin_return_address(0));
}
#ifndef CONFIG_64BIT
diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S
index a85823668cba..93ff3d90edd1 100644
--- a/arch/parisc/kernel/pacache.S
+++ b/arch/parisc/kernel/pacache.S
@@ -817,10 +817,7 @@ ENTRY(purge_kernel_dcache_page)
.procend
ENDPROC(purge_kernel_dcache_page)
-
- .export flush_user_dcache_range_asm
-
-flush_user_dcache_range_asm:
+ENTRY(flush_user_dcache_range_asm)
.proc
.callinfo NO_CALLS
.entry
@@ -839,6 +836,7 @@ flush_user_dcache_range_asm:
.exit
.procend
+ENDPROC(flush_user_dcache_range_asm)
ENTRY(flush_kernel_dcache_range_asm)
.proc
diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c
index 69d63d354ef0..828305f19cff 100644
--- a/arch/parisc/kernel/smp.c
+++ b/arch/parisc/kernel/smp.c
@@ -155,10 +155,7 @@ ipi_interrupt(int irq, void *dev_id)
case IPI_RESCHEDULE:
smp_debug(100, KERN_DEBUG "CPU%d IPI_RESCHEDULE\n", this_cpu);
- /*
- * Reschedule callback. Everything to be
- * done is done by the interrupt return path.
- */
+ scheduler_ipi();
break;
case IPI_CALL_FUNC:
diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c
index 88a0ad14a9c9..dc9a62462323 100644
--- a/arch/parisc/kernel/sys_parisc32.c
+++ b/arch/parisc/kernel/sys_parisc32.c
@@ -228,3 +228,11 @@ asmlinkage long compat_sys_fallocate(int fd, int mode, u32 offhi, u32 offlo,
return sys_fallocate(fd, mode, ((loff_t)offhi << 32) | offlo,
((loff_t)lenhi << 32) | lenlo);
}
+
+asmlinkage long compat_sys_fanotify_mark(int fan_fd, int flags, u32 mask_hi,
+ u32 mask_lo, int fd,
+ const char __user *pathname)
+{
+ return sys_fanotify_mark(fan_fd, flags, ((u64)mask_hi << 32) | mask_lo,
+ fd, pathname);
+}
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
index 4be85ee10b85..a5b02ce4d41e 100644
--- a/arch/parisc/kernel/syscall_table.S
+++ b/arch/parisc/kernel/syscall_table.S
@@ -420,6 +420,12 @@
ENTRY_COMP(recvmmsg)
ENTRY_SAME(accept4) /* 320 */
ENTRY_SAME(prlimit64)
+ ENTRY_SAME(fanotify_init)
+ ENTRY_COMP(fanotify_mark)
+ ENTRY_COMP(clock_adjtime)
+ ENTRY_SAME(name_to_handle_at) /* 325 */
+ ENTRY_COMP(open_by_handle_at)
+ ENTRY_SAME(syncfs)
/* Nothing yet */
diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S
index 8f1e4efd143e..fa6f2b8163e0 100644
--- a/arch/parisc/kernel/vmlinux.lds.S
+++ b/arch/parisc/kernel/vmlinux.lds.S
@@ -69,6 +69,9 @@ SECTIONS
/* End of text section */
_etext = .;
+ /* Start of data section */
+ _sdata = .;
+
RODATA
/* writeable */
@@ -134,6 +137,7 @@ SECTIONS
. = ALIGN(16384);
__init_begin = .;
INIT_TEXT_SECTION(16384)
+ . = ALIGN(PAGE_SIZE);
INIT_DATA_SECTION(16)
/* we have to discard exit text and such at runtime, not link time */
.exit.text :
@@ -145,7 +149,7 @@ SECTIONS
EXIT_DATA
}
- PERCPU(L1_CACHE_BYTES, PAGE_SIZE)
+ PERCPU_SECTION(L1_CACHE_BYTES)
. = ALIGN(PAGE_SIZE);
__init_end = .;
/* freed after init ends here */
diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
index b1d126258dee..82f364e209fc 100644
--- a/arch/parisc/mm/init.c
+++ b/arch/parisc/mm/init.c
@@ -31,8 +31,6 @@
#include <asm/mmzone.h>
#include <asm/sections.h>
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
extern int data_start;
#ifdef CONFIG_DISCONTIGMEM
@@ -371,24 +369,158 @@ static void __init setup_bootmem(void)
request_resource(&sysram_resources[0], &pdcdata_resource);
}
+static void __init map_pages(unsigned long start_vaddr,
+ unsigned long start_paddr, unsigned long size,
+ pgprot_t pgprot, int force)
+{
+ pgd_t *pg_dir;
+ pmd_t *pmd;
+ pte_t *pg_table;
+ unsigned long end_paddr;
+ unsigned long start_pmd;
+ unsigned long start_pte;
+ unsigned long tmp1;
+ unsigned long tmp2;
+ unsigned long address;
+ unsigned long vaddr;
+ unsigned long ro_start;
+ unsigned long ro_end;
+ unsigned long fv_addr;
+ unsigned long gw_addr;
+ extern const unsigned long fault_vector_20;
+ extern void * const linux_gateway_page;
+
+ ro_start = __pa((unsigned long)_text);
+ ro_end = __pa((unsigned long)&data_start);
+ fv_addr = __pa((unsigned long)&fault_vector_20) & PAGE_MASK;
+ gw_addr = __pa((unsigned long)&linux_gateway_page) & PAGE_MASK;
+
+ end_paddr = start_paddr + size;
+
+ pg_dir = pgd_offset_k(start_vaddr);
+
+#if PTRS_PER_PMD == 1
+ start_pmd = 0;
+#else
+ start_pmd = ((start_vaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1));
+#endif
+ start_pte = ((start_vaddr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
+
+ address = start_paddr;
+ vaddr = start_vaddr;
+ while (address < end_paddr) {
+#if PTRS_PER_PMD == 1
+ pmd = (pmd_t *)__pa(pg_dir);
+#else
+ pmd = (pmd_t *)pgd_address(*pg_dir);
+
+ /*
+ * pmd is physical at this point
+ */
+
+ if (!pmd) {
+ pmd = (pmd_t *) alloc_bootmem_low_pages_node(NODE_DATA(0), PAGE_SIZE << PMD_ORDER);
+ pmd = (pmd_t *) __pa(pmd);
+ }
+
+ pgd_populate(NULL, pg_dir, __va(pmd));
+#endif
+ pg_dir++;
+
+ /* now change pmd to kernel virtual addresses */
+
+ pmd = (pmd_t *)__va(pmd) + start_pmd;
+ for (tmp1 = start_pmd; tmp1 < PTRS_PER_PMD; tmp1++, pmd++) {
+
+ /*
+ * pg_table is physical at this point
+ */
+
+ pg_table = (pte_t *)pmd_address(*pmd);
+ if (!pg_table) {
+ pg_table = (pte_t *)
+ alloc_bootmem_low_pages_node(NODE_DATA(0), PAGE_SIZE);
+ pg_table = (pte_t *) __pa(pg_table);
+ }
+
+ pmd_populate_kernel(NULL, pmd, __va(pg_table));
+
+ /* now change pg_table to kernel virtual addresses */
+
+ pg_table = (pte_t *) __va(pg_table) + start_pte;
+ for (tmp2 = start_pte; tmp2 < PTRS_PER_PTE; tmp2++, pg_table++) {
+ pte_t pte;
+
+ /*
+ * Map the fault vector writable so we can
+ * write the HPMC checksum.
+ */
+ if (force)
+ pte = __mk_pte(address, pgprot);
+ else if (core_kernel_text(vaddr) &&
+ address != fv_addr)
+ pte = __mk_pte(address, PAGE_KERNEL_EXEC);
+ else
+#if defined(CONFIG_PARISC_PAGE_SIZE_4KB)
+ if (address >= ro_start && address < ro_end
+ && address != fv_addr
+ && address != gw_addr)
+ pte = __mk_pte(address, PAGE_KERNEL_RO);
+ else
+#endif
+ pte = __mk_pte(address, pgprot);
+
+ if (address >= end_paddr) {
+ if (force)
+ break;
+ else
+ pte_val(pte) = 0;
+ }
+
+ set_pte(pg_table, pte);
+
+ address += PAGE_SIZE;
+ vaddr += PAGE_SIZE;
+ }
+ start_pte = 0;
+
+ if (address >= end_paddr)
+ break;
+ }
+ start_pmd = 0;
+ }
+}
+
void free_initmem(void)
{
unsigned long addr;
unsigned long init_begin = (unsigned long)__init_begin;
unsigned long init_end = (unsigned long)__init_end;
-#ifdef CONFIG_DEBUG_KERNEL
+ /* The init text pages are marked R-X. We have to
+ * flush the icache and mark them RW-
+ *
+ * This is tricky, because map_pages is in the init section.
+ * Do a dummy remap of the data section first (the data
+ * section is already PAGE_KERNEL) to pull in the TLB entries
+ * for map_kernel */
+ map_pages(init_begin, __pa(init_begin), init_end - init_begin,
+ PAGE_KERNEL_RWX, 1);
+ /* now remap at PAGE_KERNEL since the TLB is pre-primed to execute
+ * map_pages */
+ map_pages(init_begin, __pa(init_begin), init_end - init_begin,
+ PAGE_KERNEL, 1);
+
+ /* force the kernel to see the new TLB entries */
+ __flush_tlb_range(0, init_begin, init_end);
/* Attempt to catch anyone trying to execute code here
* by filling the page with BRK insns.
*/
memset((void *)init_begin, 0x00, init_end - init_begin);
+ /* finally dump all the instructions which were cached, since the
+ * pages are no-longer executable */
flush_icache_range(init_begin, init_end);
-#endif
- /* align __init_begin and __init_end to page size,
- ignoring linker script where we might have tried to save RAM */
- init_begin = PAGE_ALIGN(init_begin);
- init_end = PAGE_ALIGN(init_end);
for (addr = init_begin; addr < init_end; addr += PAGE_SIZE) {
ClearPageReserved(virt_to_page(addr));
init_page_count(virt_to_page(addr));
@@ -552,7 +684,7 @@ void show_mem(unsigned int filter)
int shared = 0, cached = 0;
printk(KERN_INFO "Mem-info:\n");
- show_free_areas();
+ show_free_areas(filter);
#ifndef CONFIG_DISCONTIGMEM
i = max_mapnr;
while (i-- > 0) {
@@ -618,114 +750,6 @@ void show_mem(unsigned int filter)
#endif
}
-
-static void __init map_pages(unsigned long start_vaddr, unsigned long start_paddr, unsigned long size, pgprot_t pgprot)
-{
- pgd_t *pg_dir;
- pmd_t *pmd;
- pte_t *pg_table;
- unsigned long end_paddr;
- unsigned long start_pmd;
- unsigned long start_pte;
- unsigned long tmp1;
- unsigned long tmp2;
- unsigned long address;
- unsigned long ro_start;
- unsigned long ro_end;
- unsigned long fv_addr;
- unsigned long gw_addr;
- extern const unsigned long fault_vector_20;
- extern void * const linux_gateway_page;
-
- ro_start = __pa((unsigned long)_text);
- ro_end = __pa((unsigned long)&data_start);
- fv_addr = __pa((unsigned long)&fault_vector_20) & PAGE_MASK;
- gw_addr = __pa((unsigned long)&linux_gateway_page) & PAGE_MASK;
-
- end_paddr = start_paddr + size;
-
- pg_dir = pgd_offset_k(start_vaddr);
-
-#if PTRS_PER_PMD == 1
- start_pmd = 0;
-#else
- start_pmd = ((start_vaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1));
-#endif
- start_pte = ((start_vaddr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
-
- address = start_paddr;
- while (address < end_paddr) {
-#if PTRS_PER_PMD == 1
- pmd = (pmd_t *)__pa(pg_dir);
-#else
- pmd = (pmd_t *)pgd_address(*pg_dir);
-
- /*
- * pmd is physical at this point
- */
-
- if (!pmd) {
- pmd = (pmd_t *) alloc_bootmem_low_pages_node(NODE_DATA(0),PAGE_SIZE << PMD_ORDER);
- pmd = (pmd_t *) __pa(pmd);
- }
-
- pgd_populate(NULL, pg_dir, __va(pmd));
-#endif
- pg_dir++;
-
- /* now change pmd to kernel virtual addresses */
-
- pmd = (pmd_t *)__va(pmd) + start_pmd;
- for (tmp1 = start_pmd; tmp1 < PTRS_PER_PMD; tmp1++,pmd++) {
-
- /*
- * pg_table is physical at this point
- */
-
- pg_table = (pte_t *)pmd_address(*pmd);
- if (!pg_table) {
- pg_table = (pte_t *)
- alloc_bootmem_low_pages_node(NODE_DATA(0),PAGE_SIZE);
- pg_table = (pte_t *) __pa(pg_table);
- }
-
- pmd_populate_kernel(NULL, pmd, __va(pg_table));
-
- /* now change pg_table to kernel virtual addresses */
-
- pg_table = (pte_t *) __va(pg_table) + start_pte;
- for (tmp2 = start_pte; tmp2 < PTRS_PER_PTE; tmp2++,pg_table++) {
- pte_t pte;
-
- /*
- * Map the fault vector writable so we can
- * write the HPMC checksum.
- */
-#if defined(CONFIG_PARISC_PAGE_SIZE_4KB)
- if (address >= ro_start && address < ro_end
- && address != fv_addr
- && address != gw_addr)
- pte = __mk_pte(address, PAGE_KERNEL_RO);
- else
-#endif
- pte = __mk_pte(address, pgprot);
-
- if (address >= end_paddr)
- pte_val(pte) = 0;
-
- set_pte(pg_table, pte);
-
- address += PAGE_SIZE;
- }
- start_pte = 0;
-
- if (address >= end_paddr)
- break;
- }
- start_pmd = 0;
- }
-}
-
/*
* pagetable_init() sets up the page tables
*
@@ -750,14 +774,14 @@ static void __init pagetable_init(void)
size = pmem_ranges[range].pages << PAGE_SHIFT;
map_pages((unsigned long)__va(start_paddr), start_paddr,
- size, PAGE_KERNEL);
+ size, PAGE_KERNEL, 0);
}
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_end && initrd_end > mem_limit) {
printk(KERN_INFO "initrd: mapping %08lx-%08lx\n", initrd_start, initrd_end);
map_pages(initrd_start, __pa(initrd_start),
- initrd_end - initrd_start, PAGE_KERNEL);
+ initrd_end - initrd_start, PAGE_KERNEL, 0);
}
#endif
@@ -782,7 +806,7 @@ static void __init gateway_init(void)
*/
map_pages(linux_gateway_page_addr, __pa(&linux_gateway_page),
- PAGE_SIZE, PAGE_GATEWAY);
+ PAGE_SIZE, PAGE_GATEWAY, 1);
}
#ifdef CONFIG_HPUX
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 8f4d50b0adfa..2729c6663d8a 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -91,14 +91,6 @@ config GENERIC_HWEIGHT
bool
default y
-config GENERIC_FIND_NEXT_BIT
- bool
- default y
-
-config GENERIC_FIND_BIT_LE
- bool
- default y
-
config GENERIC_GPIO
bool
help
@@ -140,6 +132,8 @@ config PPC
select IRQ_PER_CPU
select GENERIC_IRQ_SHOW
select GENERIC_IRQ_SHOW_LEVEL
+ select HAVE_RCU_TABLE_FREE if SMP
+ select HAVE_SYSCALL_TRACEPOINTS
config EARLY_PRINTK
bool
@@ -193,6 +187,12 @@ config SYS_SUPPORTS_APM_EMULATION
default y if PMAC_APM_EMU
bool
+config EPAPR_BOOT
+ bool
+ help
+ Used to allow a board to specify it wants an ePAPR compliant wrapper.
+ default n
+
config DEFAULT_UIMAGE
bool
help
diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug
index 2d38a50e66ba..e72dcf6a421d 100644
--- a/arch/powerpc/Kconfig.debug
+++ b/arch/powerpc/Kconfig.debug
@@ -35,27 +35,6 @@ config DEBUG_STACKOVERFLOW
This option will cause messages to be printed if free stack space
drops below a certain limit.
-config DEBUG_STACK_USAGE
- bool "Stack utilization instrumentation"
- depends on DEBUG_KERNEL
- help
- Enables the display of the minimum amount of free stack which each
- task has ever had available in the sysrq-T and sysrq-P debug output.
-
- This option will slow down process creation somewhat.
-
-config DEBUG_PER_CPU_MAPS
- bool "Debug access to per_cpu maps"
- depends on DEBUG_KERNEL
- depends on SMP
- default n
- ---help---
- Say Y to verify that the per_cpu map being accessed has
- been setup. Adds a fair amount of code to kernel memory
- and decreases performance.
-
- Say N if unsure.
-
config HCALL_STATS
bool "Hypervisor call instrumentation"
depends on PPC_PSERIES && DEBUG_FS && TRACEPOINTS
@@ -267,6 +246,11 @@ config PPC_EARLY_DEBUG_USBGECKO
Select this to enable early debugging for Nintendo GameCube/Wii
consoles via an external USB Gecko adapter.
+config PPC_EARLY_DEBUG_WSP
+ bool "Early debugging via WSP's internal UART"
+ depends on PPC_WSP
+ select PPC_UDBG_16550
+
endchoice
config PPC_EARLY_DEBUG_44x_PHYSLOW
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 89178164af5e..c26200b40a47 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -69,7 +69,8 @@ src-wlib := string.S crt0.S crtsavres.S stdio.c main.c \
cpm-serial.c stdlib.c mpc52xx-psc.c planetcore.c uartlite.c \
fsl-soc.c mpc8xx.c pq2.c ugecon.c
src-plat := of.c cuboot-52xx.c cuboot-824x.c cuboot-83xx.c cuboot-85xx.c holly.c \
- cuboot-ebony.c cuboot-hotfoot.c treeboot-ebony.c prpmc2800.c \
+ cuboot-ebony.c cuboot-hotfoot.c epapr.c treeboot-ebony.c \
+ prpmc2800.c \
ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \
cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c \
cuboot-bamboo.c cuboot-mpc7448hpc2.c cuboot-taishan.c \
@@ -127,7 +128,7 @@ quiet_cmd_bootas = BOOTAS $@
cmd_bootas = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -c -o $@ $<
quiet_cmd_bootar = BOOTAR $@
- cmd_bootar = $(CROSS32AR) -cr $@.$$$$ $(filter-out FORCE,$^); mv $@.$$$$ $@
+ cmd_bootar = $(CROSS32AR) -cr$(KBUILD_ARFLAGS) $@.$$$$ $(filter-out FORCE,$^); mv $@.$$$$ $@
$(obj-libfdt): $(obj)/%.o: $(srctree)/scripts/dtc/libfdt/%.c FORCE
$(call if_changed_dep,bootcc)
@@ -182,6 +183,7 @@ image-$(CONFIG_PPC_HOLLY) += dtbImage.holly
image-$(CONFIG_PPC_PRPMC2800) += dtbImage.prpmc2800
image-$(CONFIG_PPC_ISERIES) += zImage.iseries
image-$(CONFIG_DEFAULT_UIMAGE) += uImage
+image-$(CONFIG_EPAPR_BOOT) += zImage.epapr
#
# Targets which embed a device tree blob
diff --git a/arch/powerpc/boot/crt0.S b/arch/powerpc/boot/crt0.S
index f1c4dfc635be..0f7428a37efb 100644
--- a/arch/powerpc/boot/crt0.S
+++ b/arch/powerpc/boot/crt0.S
@@ -6,16 +6,28 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * NOTE: this code runs in 32 bit mode and is packaged as ELF32.
+ * NOTE: this code runs in 32 bit mode, is position-independent,
+ * and is packaged as ELF32.
*/
#include "ppc_asm.h"
.text
- /* a procedure descriptor used when booting this as a COFF file */
+ /* A procedure descriptor used when booting this as a COFF file.
+ * When making COFF, this comes first in the link and we're
+ * linked at 0x500000.
+ */
.globl _zimage_start_opd
_zimage_start_opd:
- .long _zimage_start, 0, 0, 0
+ .long 0x500000, 0, 0, 0
+
+p_start: .long _start
+p_etext: .long _etext
+p_bss_start: .long __bss_start
+p_end: .long _end
+
+ .weak _platform_stack_top
+p_pstack: .long _platform_stack_top
.weak _zimage_start
.globl _zimage_start
@@ -24,37 +36,65 @@ _zimage_start:
_zimage_start_lib:
/* Work out the offset between the address we were linked at
and the address where we're running. */
- bl 1f
-1: mflr r0
- lis r9,1b@ha
- addi r9,r9,1b@l
- subf. r0,r9,r0
- beq 3f /* if running at same address as linked */
+ bl .+4
+p_base: mflr r10 /* r10 now points to runtime addr of p_base */
+ /* grab the link address of the dynamic section in r11 */
+ addis r11,r10,(_GLOBAL_OFFSET_TABLE_-p_base)@ha
+ lwz r11,(_GLOBAL_OFFSET_TABLE_-p_base)@l(r11)
+ cmpwi r11,0
+ beq 3f /* if not linked -pie */
+ /* get the runtime address of the dynamic section in r12 */
+ .weak __dynamic_start
+ addis r12,r10,(__dynamic_start-p_base)@ha
+ addi r12,r12,(__dynamic_start-p_base)@l
+ subf r11,r11,r12 /* runtime - linktime offset */
+
+ /* The dynamic section contains a series of tagged entries.
+ * We need the RELA and RELACOUNT entries. */
+RELA = 7
+RELACOUNT = 0x6ffffff9
+ li r9,0
+ li r0,0
+9: lwz r8,0(r12) /* get tag */
+ cmpwi r8,0
+ beq 10f /* end of list */
+ cmpwi r8,RELA
+ bne 11f
+ lwz r9,4(r12) /* get RELA pointer in r9 */
+ b 12f
+11: addis r8,r8,(-RELACOUNT)@ha
+ cmpwi r8,RELACOUNT@l
+ bne 12f
+ lwz r0,4(r12) /* get RELACOUNT value in r0 */
+12: addi r12,r12,8
+ b 9b
- /* The .got2 section contains a list of addresses, so add
- the address offset onto each entry. */
- lis r9,__got2_start@ha
- addi r9,r9,__got2_start@l
- lis r8,__got2_end@ha
- addi r8,r8,__got2_end@l
- subf. r8,r9,r8
+ /* The relocation section contains a list of relocations.
+ * We now do the R_PPC_RELATIVE ones, which point to words
+ * which need to be initialized with addend + offset.
+ * The R_PPC_RELATIVE ones come first and there are RELACOUNT
+ * of them. */
+10: /* skip relocation if we don't have both */
+ cmpwi r0,0
beq 3f
- srwi. r8,r8,2
- mtctr r8
- add r9,r0,r9
-2: lwz r8,0(r9)
- add r8,r8,r0
- stw r8,0(r9)
- addi r9,r9,4
+ cmpwi r9,0
+ beq 3f
+
+ add r9,r9,r11 /* Relocate RELA pointer */
+ mtctr r0
+2: lbz r0,4+3(r9) /* ELF32_R_INFO(reloc->r_info) */
+ cmpwi r0,22 /* R_PPC_RELATIVE */
+ bne 3f
+ lwz r12,0(r9) /* reloc->r_offset */
+ lwz r0,8(r9) /* reloc->r_addend */
+ add r0,r0,r11
+ stwx r0,r11,r12
+ addi r9,r9,12
bdnz 2b
/* Do a cache flush for our text, in case the loader didn't */
-3: lis r9,_start@ha
- addi r9,r9,_start@l
- add r9,r0,r9
- lis r8,_etext@ha
- addi r8,r8,_etext@l
- add r8,r0,r8
+3: lwz r9,p_start-p_base(r10) /* note: these are relocated now */
+ lwz r8,p_etext-p_base(r10)
4: dcbf r0,r9
icbi r0,r9
addi r9,r9,0x20
@@ -64,27 +104,19 @@ _zimage_start_lib:
isync
/* Clear the BSS */
- lis r9,__bss_start@ha
- addi r9,r9,__bss_start@l
- add r9,r0,r9
- lis r8,_end@ha
- addi r8,r8,_end@l
- add r8,r0,r8
- li r10,0
-5: stw r10,0(r9)
+ lwz r9,p_bss_start-p_base(r10)
+ lwz r8,p_end-p_base(r10)
+ li r0,0
+5: stw r0,0(r9)
addi r9,r9,4
cmplw cr0,r9,r8
blt 5b
/* Possibly set up a custom stack */
-.weak _platform_stack_top
- lis r8,_platform_stack_top@ha
- addi r8,r8,_platform_stack_top@l
+ lwz r8,p_pstack-p_base(r10)
cmpwi r8,0
beq 6f
- add r8,r0,r8
lwz r1,0(r8)
- add r1,r0,r1
li r0,0
stwu r0,-16(r1) /* establish a stack frame */
6:
diff --git a/arch/powerpc/boot/dts/canyonlands.dts b/arch/powerpc/boot/dts/canyonlands.dts
index 2779f08313a5..22dd6ae84da0 100644
--- a/arch/powerpc/boot/dts/canyonlands.dts
+++ b/arch/powerpc/boot/dts/canyonlands.dts
@@ -530,5 +530,23 @@
0x0 0x0 0x0 0x3 &UIC3 0x12 0x4 /* swizzled int C */
0x0 0x0 0x0 0x4 &UIC3 0x13 0x4 /* swizzled int D */>;
};
+
+ MSI: ppc4xx-msi@C10000000 {
+ compatible = "amcc,ppc4xx-msi", "ppc4xx-msi";
+ reg = < 0xC 0x10000000 0x100>;
+ sdr-base = <0x36C>;
+ msi-data = <0x00000000>;
+ msi-mask = <0x44440000>;
+ interrupt-count = <3>;
+ interrupts = <0 1 2 3>;
+ interrupt-parent = <&UIC3>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = <0 &UIC3 0x18 1
+ 1 &UIC3 0x19 1
+ 2 &UIC3 0x1A 1
+ 3 &UIC3 0x1B 1>;
+ };
};
};
diff --git a/arch/powerpc/boot/dts/katmai.dts b/arch/powerpc/boot/dts/katmai.dts
index 7c3be5e45748..f913dbe25d35 100644
--- a/arch/powerpc/boot/dts/katmai.dts
+++ b/arch/powerpc/boot/dts/katmai.dts
@@ -442,6 +442,24 @@
0x0 0x0 0x0 0x4 &UIC3 0xb 0x4 /* swizzled int D */>;
};
+ MSI: ppc4xx-msi@400300000 {
+ compatible = "amcc,ppc4xx-msi", "ppc4xx-msi";
+ reg = < 0x4 0x00300000 0x100>;
+ sdr-base = <0x3B0>;
+ msi-data = <0x00000000>;
+ msi-mask = <0x44440000>;
+ interrupt-count = <3>;
+ interrupts =<0 1 2 3>;
+ interrupt-parent = <&UIC0>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = <0 &UIC0 0xC 1
+ 1 &UIC0 0x0D 1
+ 2 &UIC0 0x0E 1
+ 3 &UIC0 0x0F 1>;
+ };
+
I2O: i2o@400100000 {
compatible = "ibm,i2o-440spe";
reg = <0x00000004 0x00100000 0x100>;
diff --git a/arch/powerpc/boot/dts/kilauea.dts b/arch/powerpc/boot/dts/kilauea.dts
index 89edb16649c3..1613d6e4049e 100644
--- a/arch/powerpc/boot/dts/kilauea.dts
+++ b/arch/powerpc/boot/dts/kilauea.dts
@@ -403,5 +403,33 @@
0x0 0x0 0x0 0x3 &UIC2 0xd 0x4 /* swizzled int C */
0x0 0x0 0x0 0x4 &UIC2 0xe 0x4 /* swizzled int D */>;
};
+
+ MSI: ppc4xx-msi@C10000000 {
+ compatible = "amcc,ppc4xx-msi", "ppc4xx-msi";
+ reg = < 0x0 0xEF620000 0x100>;
+ sdr-base = <0x4B0>;
+ msi-data = <0x00000000>;
+ msi-mask = <0x44440000>;
+ interrupt-count = <12>;
+ interrupts = <0 1 2 3 4 5 6 7 8 9 0xA 0xB 0xC 0xD>;
+ interrupt-parent = <&UIC2>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = <0 &UIC2 0x10 1
+ 1 &UIC2 0x11 1
+ 2 &UIC2 0x12 1
+ 2 &UIC2 0x13 1
+ 2 &UIC2 0x14 1
+ 2 &UIC2 0x15 1
+ 2 &UIC2 0x16 1
+ 2 &UIC2 0x17 1
+ 2 &UIC2 0x18 1
+ 2 &UIC2 0x19 1
+ 2 &UIC2 0x1A 1
+ 2 &UIC2 0x1B 1
+ 2 &UIC2 0x1C 1
+ 3 &UIC2 0x1D 1>;
+ };
};
};
diff --git a/arch/powerpc/boot/dts/mpc8313erdb.dts b/arch/powerpc/boot/dts/mpc8313erdb.dts
index 761faa7b6964..ac1eb320c7b4 100644
--- a/arch/powerpc/boot/dts/mpc8313erdb.dts
+++ b/arch/powerpc/boot/dts/mpc8313erdb.dts
@@ -176,6 +176,19 @@
sleep = <&pmc 0x00300000>;
};
+ ptp_clock@24E00 {
+ compatible = "fsl,etsec-ptp";
+ reg = <0x24E00 0xB0>;
+ interrupts = <12 0x8 13 0x8>;
+ interrupt-parent = < &ipic >;
+ fsl,tclk-period = <10>;
+ fsl,tmr-prsc = <100>;
+ fsl,tmr-add = <0x999999A4>;
+ fsl,tmr-fiper1 = <0x3B9AC9F6>;
+ fsl,tmr-fiper2 = <0x00018696>;
+ fsl,max-adj = <659999998>;
+ };
+
enet0: ethernet@24000 {
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/powerpc/boot/dts/mpc8572ds.dts b/arch/powerpc/boot/dts/mpc8572ds.dts
index cafc1285c140..f6c04d25e916 100644
--- a/arch/powerpc/boot/dts/mpc8572ds.dts
+++ b/arch/powerpc/boot/dts/mpc8572ds.dts
@@ -324,6 +324,19 @@
};
};
+ ptp_clock@24E00 {
+ compatible = "fsl,etsec-ptp";
+ reg = <0x24E00 0xB0>;
+ interrupts = <68 2 69 2 70 2 71 2>;
+ interrupt-parent = < &mpic >;
+ fsl,tclk-period = <5>;
+ fsl,tmr-prsc = <200>;
+ fsl,tmr-add = <0xAAAAAAAB>;
+ fsl,tmr-fiper1 = <0x3B9AC9FB>;
+ fsl,tmr-fiper2 = <0x3B9AC9FB>;
+ fsl,max-adj = <499999999>;
+ };
+
enet0: ethernet@24000 {
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/powerpc/boot/dts/p1020rdb.dts b/arch/powerpc/boot/dts/p1020rdb.dts
index e0668f877794..d6a8ae458137 100644
--- a/arch/powerpc/boot/dts/p1020rdb.dts
+++ b/arch/powerpc/boot/dts/p1020rdb.dts
@@ -9,12 +9,11 @@
* option) any later version.
*/
-/dts-v1/;
+/include/ "p1020si.dtsi"
+
/ {
- model = "fsl,P1020";
+ model = "fsl,P1020RDB";
compatible = "fsl,P1020RDB";
- #address-cells = <2>;
- #size-cells = <2>;
aliases {
serial0 = &serial0;
@@ -26,34 +25,11 @@
pci1 = &pci1;
};
- cpus {
- #address-cells = <1>;
- #size-cells = <0>;
-
- PowerPC,P1020@0 {
- device_type = "cpu";
- reg = <0x0>;
- next-level-cache = <&L2>;
- };
-
- PowerPC,P1020@1 {
- device_type = "cpu";
- reg = <0x1>;
- next-level-cache = <&L2>;
- };
- };
-
memory {
device_type = "memory";
};
localbus@ffe05000 {
- #address-cells = <2>;
- #size-cells = <1>;
- compatible = "fsl,p1020-elbc", "fsl,elbc", "simple-bus";
- reg = <0 0xffe05000 0 0x1000>;
- interrupts = <19 2>;
- interrupt-parent = <&mpic>;
/* NOR, NAND Flashes and Vitesse 5 port L2 switch */
ranges = <0x0 0x0 0x0 0xef000000 0x01000000
@@ -165,88 +141,14 @@
};
soc@ffe00000 {
- #address-cells = <1>;
- #size-cells = <1>;
- device_type = "soc";
- compatible = "fsl,p1020-immr", "simple-bus";
- ranges = <0x0 0x0 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,p1020-ecm", "fsl,ecm";
- reg = <0x1000 0x1000>;
- interrupts = <16 2>;
- interrupt-parent = <&mpic>;
- };
-
- memory-controller@2000 {
- compatible = "fsl,p1020-memory-controller";
- reg = <0x2000 0x1000>;
- 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;
rtc@68 {
compatible = "dallas,ds1339";
reg = <0x68>;
};
};
- i2c@3100 {
- #address-cells = <1>;
- #size-cells = <0>;
- cell-index = <1>;
- compatible = "fsl-i2c";
- reg = <0x3100 0x100>;
- interrupts = <43 2>;
- interrupt-parent = <&mpic>;
- dfsrr;
- };
-
- serial0: serial@4500 {
- cell-index = <0>;
- device_type = "serial";
- compatible = "ns16550";
- reg = <0x4500 0x100>;
- clock-frequency = <0>;
- interrupts = <42 2>;
- interrupt-parent = <&mpic>;
- };
-
- serial1: serial@4600 {
- cell-index = <1>;
- device_type = "serial";
- compatible = "ns16550";
- reg = <0x4600 0x100>;
- clock-frequency = <0>;
- interrupts = <42 2>;
- interrupt-parent = <&mpic>;
- };
-
spi@7000 {
- cell-index = <0>;
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl,espi";
- reg = <0x7000 0x1000>;
- interrupts = <59 0x2>;
- interrupt-parent = <&mpic>;
- mode = "cpu";
fsl_m25p80@0 {
#address-cells = <1>;
@@ -294,66 +196,7 @@
};
};
- gpio: gpio-controller@f000 {
- #gpio-cells = <2>;
- compatible = "fsl,mpc8572-gpio";
- reg = <0xf000 0x100>;
- interrupts = <47 0x2>;
- interrupt-parent = <&mpic>;
- gpio-controller;
- };
-
- L2: l2-cache-controller@20000 {
- compatible = "fsl,p1020-l2-cache-controller";
- reg = <0x20000 0x1000>;
- cache-line-size = <32>; // 32 bytes
- cache-size = <0x40000>; // L2,256K
- interrupt-parent = <&mpic>;
- 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>;
- interrupt-parent = <&mpic>;
- interrupts = <20 2>;
- };
- dma-channel@80 {
- compatible = "fsl,eloplus-dma-channel";
- reg = <0x80 0x80>;
- cell-index = <1>;
- interrupt-parent = <&mpic>;
- interrupts = <21 2>;
- };
- dma-channel@100 {
- compatible = "fsl,eloplus-dma-channel";
- reg = <0x100 0x80>;
- cell-index = <2>;
- interrupt-parent = <&mpic>;
- interrupts = <22 2>;
- };
- dma-channel@180 {
- compatible = "fsl,eloplus-dma-channel";
- reg = <0x180 0x80>;
- cell-index = <3>;
- interrupt-parent = <&mpic>;
- interrupts = <23 2>;
- };
- };
-
mdio@24000 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl,etsec2-mdio";
- reg = <0x24000 0x1000 0xb0030 0x4>;
phy0: ethernet-phy@0 {
interrupt-parent = <&mpic>;
@@ -369,10 +212,6 @@
};
mdio@25000 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl,etsec2-tbi";
- reg = <0x25000 0x1000 0xb1030 0x4>;
tbi0: tbi-phy@11 {
reg = <0x11>;
@@ -381,97 +220,25 @@
};
enet0: ethernet@b0000 {
- #address-cells = <1>;
- #size-cells = <1>;
- 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 ];
- interrupt-parent = <&mpic>;
fixed-link = <1 1 1000 0 0>;
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>;
- 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 ];
- interrupt-parent = <&mpic>;
phy-handle = <&phy0>;
tbi-handle = <&tbi0>;
phy-connection-type = "sgmii";
- 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>;
- };
};
enet2: ethernet@b2000 {
- #address-cells = <1>;
- #size-cells = <1>;
- 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 ];
- interrupt-parent = <&mpic>;
phy-handle = <&phy1>;
phy-connection-type = "rgmii-id";
- queue-group@0 {
- #address-cells = <1>;
- #size-cells = <1>;
- reg = <0xb2000 0x1000>;
- interrupts = <31 2 32 2 33 2>;
- };
-
- queue-group@1 {
- #address-cells = <1>;
- #size-cells = <1>;
- reg = <0xb6000 0x1000>;
- interrupts = <25 2 26 2 27 2>;
- };
};
usb@22000 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl-usb2-dr";
- reg = <0x22000 0x1000>;
- interrupt-parent = <&mpic>;
- interrupts = <28 0x2>;
phy_type = "ulpi";
};
@@ -481,82 +248,23 @@
it enables USB2. OTOH, U-Boot does create a new node
when there isn't any. So, just comment it out.
usb@23000 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl-usb2-dr";
- reg = <0x23000 0x1000>;
- interrupt-parent = <&mpic>;
- interrupts = <46 0x2>;
phy_type = "ulpi";
};
*/
- sdhci@2e000 {
- compatible = "fsl,p1020-esdhc", "fsl,esdhc";
- reg = <0x2e000 0x1000>;
- interrupts = <72 0x2>;
- interrupt-parent = <&mpic>;
- /* Filled in by U-Boot */
- clock-frequency = <0>;
- };
-
- crypto@30000 {
- compatible = "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>;
- interrupt-parent = <&mpic>;
- fsl,num-channels = <4>;
- fsl,channel-fifo-len = <24>;
- fsl,exec-units-mask = <0xbfe>;
- fsl,descriptor-types-mask = <0x3ab0ebf>;
- };
-
- 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,p1020-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>;
- interrupt-parent = <&mpic>;
- };
-
- global-utilities@e0000 { //global utilities block
- compatible = "fsl,p1020-guts";
- reg = <0xe0000 0x1000>;
- fsl,has-rstcr;
- };
};
pci0: pcie@ffe09000 {
- compatible = "fsl,mpc8548-pcie";
- device_type = "pci";
- #interrupt-cells = <1>;
- #size-cells = <2>;
- #address-cells = <3>;
- reg = <0 0xffe09000 0 0x1000>;
- bus-range = <0 255>;
ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
- clock-frequency = <33333333>;
- interrupt-parent = <&mpic>;
- interrupts = <16 2>;
+ interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+ interrupt-map = <
+ /* IDSEL 0x0 */
+ 0000 0x0 0x0 0x1 &mpic 0x4 0x1
+ 0000 0x0 0x0 0x2 &mpic 0x5 0x1
+ 0000 0x0 0x0 0x3 &mpic 0x6 0x1
+ 0000 0x0 0x0 0x4 &mpic 0x7 0x1
+ >;
pcie@0 {
reg = <0x0 0x0 0x0 0x0 0x0>;
#size-cells = <2>;
@@ -573,18 +281,16 @@
};
pci1: pcie@ffe0a000 {
- compatible = "fsl,mpc8548-pcie";
- device_type = "pci";
- #interrupt-cells = <1>;
- #size-cells = <2>;
- #address-cells = <3>;
- reg = <0 0xffe0a000 0 0x1000>;
- bus-range = <0 255>;
ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000
0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
- clock-frequency = <33333333>;
- interrupt-parent = <&mpic>;
- interrupts = <16 2>;
+ interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+ interrupt-map = <
+ /* IDSEL 0x0 */
+ 0000 0x0 0x0 0x1 &mpic 0x0 0x1
+ 0000 0x0 0x0 0x2 &mpic 0x1 0x1
+ 0000 0x0 0x0 0x3 &mpic 0x2 0x1
+ 0000 0x0 0x0 0x4 &mpic 0x3 0x1
+ >;
pcie@0 {
reg = <0x0 0x0 0x0 0x0 0x0>;
#size-cells = <2>;
diff --git a/arch/powerpc/boot/dts/p1020rdb_camp_core0.dts b/arch/powerpc/boot/dts/p1020rdb_camp_core0.dts
new file mode 100644
index 000000000000..f0bf7f42f097
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1020rdb_camp_core0.dts
@@ -0,0 +1,213 @@
+/*
+ * P1020 RDB Core0 Device Tree Source in CAMP mode.
+ *
+ * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache
+ * can be shared, all the other devices must be assigned to one core only.
+ * This dts file allows core0 to have memory, l2, i2c, spi, gpio, tdm, dma, usb,
+ * eth1, eth2, sdhc, crypto, global-util, message, pci0, pci1, msi.
+ *
+ * Please note to add "-b 0" for core0's dts compiling.
+ *
+ * Copyright 2011 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+/include/ "p1020si.dtsi"
+
+/ {
+ model = "fsl,P1020RDB";
+ compatible = "fsl,P1020RDB", "fsl,MPC85XXRDB-CAMP";
+
+ aliases {
+ ethernet1 = &enet1;
+ ethernet2 = &enet2;
+ serial0 = &serial0;
+ pci0 = &pci0;
+ pci1 = &pci1;
+ };
+
+ cpus {
+ PowerPC,P1020@1 {
+ status = "disabled";
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ };
+
+ localbus@ffe05000 {
+ status = "disabled";
+ };
+
+ soc@ffe00000 {
+ i2c@3000 {
+ rtc@68 {
+ compatible = "dallas,ds1339";
+ reg = <0x68>;
+ };
+ };
+
+ serial1: serial@4600 {
+ status = "disabled";
+ };
+
+ spi@7000 {
+ fsl_m25p80@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,espi-flash";
+ reg = <0>;
+ linux,modalias = "fsl_m25p80";
+ spi-max-frequency = <40000000>;
+
+ partition@0 {
+ /* 512KB for u-boot Bootloader Image */
+ reg = <0x0 0x00080000>;
+ label = "SPI (RO) U-Boot Image";
+ read-only;
+ };
+
+ partition@80000 {
+ /* 512KB for DTB Image */
+ reg = <0x00080000 0x00080000>;
+ label = "SPI (RO) DTB Image";
+ read-only;
+ };
+
+ partition@100000 {
+ /* 4MB for Linux Kernel Image */
+ reg = <0x00100000 0x00400000>;
+ label = "SPI (RO) Linux Kernel Image";
+ read-only;
+ };
+
+ partition@500000 {
+ /* 4MB for Compressed RFS Image */
+ reg = <0x00500000 0x00400000>;
+ label = "SPI (RO) Compressed RFS Image";
+ read-only;
+ };
+
+ partition@900000 {
+ /* 7MB for JFFS2 based RFS */
+ reg = <0x00900000 0x00700000>;
+ label = "SPI (RW) JFFS2 RFS";
+ };
+ };
+ };
+
+ mdio@24000 {
+ phy0: ethernet-phy@0 {
+ interrupt-parent = <&mpic>;
+ interrupts = <3 1>;
+ reg = <0x0>;
+ };
+ phy1: ethernet-phy@1 {
+ interrupt-parent = <&mpic>;
+ interrupts = <2 1>;
+ reg = <0x1>;
+ };
+ };
+
+ mdio@25000 {
+ tbi0: tbi-phy@11 {
+ reg = <0x11>;
+ device_type = "tbi-phy";
+ };
+ };
+
+ enet0: ethernet@b0000 {
+ status = "disabled";
+ };
+
+ enet1: ethernet@b1000 {
+ phy-handle = <&phy0>;
+ tbi-handle = <&tbi0>;
+ phy-connection-type = "sgmii";
+ };
+
+ enet2: ethernet@b2000 {
+ phy-handle = <&phy1>;
+ phy-connection-type = "rgmii-id";
+ };
+
+ usb@22000 {
+ phy_type = "ulpi";
+ };
+
+ /* USB2 is shared with localbus, so it must be disabled
+ by default. We can't put 'status = "disabled";' here
+ since U-Boot doesn't clear the status property when
+ it enables USB2. OTOH, U-Boot does create a new node
+ when there isn't any. So, just comment it out.
+ usb@23000 {
+ phy_type = "ulpi";
+ };
+ */
+
+ mpic: pic@40000 {
+ protected-sources = <
+ 42 29 30 34 /* serial1, enet0-queue-group0 */
+ 17 18 24 45 /* enet0-queue-group1, crypto */
+ >;
+ };
+
+ };
+
+ pci0: pcie@ffe09000 {
+ ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
+ 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
+ interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+ interrupt-map = <
+ /* IDSEL 0x0 */
+ 0000 0x0 0x0 0x1 &mpic 0x4 0x1
+ 0000 0x0 0x0 0x2 &mpic 0x5 0x1
+ 0000 0x0 0x0 0x3 &mpic 0x6 0x1
+ 0000 0x0 0x0 0x4 &mpic 0x7 0x1
+ >;
+ pcie@0 {
+ reg = <0x0 0x0 0x0 0x0 0x0>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ device_type = "pci";
+ ranges = <0x2000000 0x0 0xa0000000
+ 0x2000000 0x0 0xa0000000
+ 0x0 0x20000000
+
+ 0x1000000 0x0 0x0
+ 0x1000000 0x0 0x0
+ 0x0 0x100000>;
+ };
+ };
+
+ pci1: pcie@ffe0a000 {
+ ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000
+ 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
+ interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+ interrupt-map = <
+ /* IDSEL 0x0 */
+ 0000 0x0 0x0 0x1 &mpic 0x0 0x1
+ 0000 0x0 0x0 0x2 &mpic 0x1 0x1
+ 0000 0x0 0x0 0x3 &mpic 0x2 0x1
+ 0000 0x0 0x0 0x4 &mpic 0x3 0x1
+ >;
+ pcie@0 {
+ reg = <0x0 0x0 0x0 0x0 0x0>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ device_type = "pci";
+ ranges = <0x2000000 0x0 0x80000000
+ 0x2000000 0x0 0x80000000
+ 0x0 0x20000000
+
+ 0x1000000 0x0 0x0
+ 0x1000000 0x0 0x0
+ 0x0 0x100000>;
+ };
+ };
+};
diff --git a/arch/powerpc/boot/dts/p1020rdb_camp_core1.dts b/arch/powerpc/boot/dts/p1020rdb_camp_core1.dts
new file mode 100644
index 000000000000..6ec02204a44e
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1020rdb_camp_core1.dts
@@ -0,0 +1,148 @@
+/*
+ * P1020 RDB Core1 Device Tree Source in CAMP mode.
+ *
+ * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache
+ * can be shared, all the other devices must be assigned to one core only.
+ * This dts allows core1 to have l2, eth0, crypto.
+ *
+ * Please note to add "-b 1" for core1's dts compiling.
+ *
+ * Copyright 2011 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+/include/ "p1020si.dtsi"
+
+/ {
+ model = "fsl,P1020RDB";
+ compatible = "fsl,P1020RDB", "fsl,MPC85XXRDB-CAMP";
+
+ aliases {
+ ethernet0 = &enet0;
+ serial0 = &serial1;
+ };
+
+ cpus {
+ PowerPC,P1020@0 {
+ status = "disabled";
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ };
+
+ localbus@ffe05000 {
+ status = "disabled";
+ };
+
+ soc@ffe00000 {
+ ecm-law@0 {
+ status = "disabled";
+ };
+
+ ecm@1000 {
+ status = "disabled";
+ };
+
+ memory-controller@2000 {
+ status = "disabled";
+ };
+
+ i2c@3000 {
+ status = "disabled";
+ };
+
+ i2c@3100 {
+ status = "disabled";
+ };
+
+ serial0: serial@4500 {
+ status = "disabled";
+ };
+
+ spi@7000 {
+ status = "disabled";
+ };
+
+ gpio: gpio-controller@f000 {
+ status = "disabled";
+ };
+
+ dma@21300 {
+ status = "disabled";
+ };
+
+ mdio@24000 {
+ status = "disabled";
+ };
+
+ mdio@25000 {
+ status = "disabled";
+ };
+
+ enet0: ethernet@b0000 {
+ fixed-link = <1 1 1000 0 0>;
+ phy-connection-type = "rgmii-id";
+
+ };
+
+ enet1: ethernet@b1000 {
+ status = "disabled";
+ };
+
+ enet2: ethernet@b2000 {
+ status = "disabled";
+ };
+
+ usb@22000 {
+ status = "disabled";
+ };
+
+ sdhci@2e000 {
+ status = "disabled";
+ };
+
+ mpic: pic@40000 {
+ protected-sources = <
+ 16 /* ecm, mem, L2, pci0, pci1 */
+ 43 42 59 /* i2c, serial0, spi */
+ 47 63 62 /* gpio, tdm */
+ 20 21 22 23 /* dma */
+ 03 02 /* mdio */
+ 35 36 40 /* enet1-queue-group0 */
+ 51 52 67 /* enet1-queue-group1 */
+ 31 32 33 /* enet2-queue-group0 */
+ 25 26 27 /* enet2-queue-group1 */
+ 28 72 58 /* usb, sdhci, crypto */
+ 0xb0 0xb1 0xb2 /* message */
+ 0xb3 0xb4 0xb5
+ 0xb6 0xb7
+ 0xe0 0xe1 0xe2 /* msi */
+ 0xe3 0xe4 0xe5
+ 0xe6 0xe7 /* sdhci, crypto , pci */
+ >;
+ };
+
+ msi@41600 {
+ status = "disabled";
+ };
+
+ global-utilities@e0000 { //global utilities block
+ status = "disabled";
+ };
+
+ };
+
+ pci0: pcie@ffe09000 {
+ status = "disabled";
+ };
+
+ pci1: pcie@ffe0a000 {
+ status = "disabled";
+ };
+};
diff --git a/arch/powerpc/boot/dts/p1020si.dtsi b/arch/powerpc/boot/dts/p1020si.dtsi
new file mode 100644
index 000000000000..5c5acb66c3fc
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1020si.dtsi
@@ -0,0 +1,377 @@
+/*
+ * P1020si Device Tree Source
+ *
+ * Copyright 2011 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/;
+/ {
+ compatible = "fsl,P1020";
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,P1020@0 {
+ device_type = "cpu";
+ reg = <0x0>;
+ next-level-cache = <&L2>;
+ };
+
+ PowerPC,P1020@1 {
+ device_type = "cpu";
+ reg = <0x1>;
+ next-level-cache = <&L2>;
+ };
+ };
+
+ localbus@ffe05000 {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ compatible = "fsl,p1020-elbc", "fsl,elbc", "simple-bus";
+ reg = <0 0xffe05000 0 0x1000>;
+ interrupts = <19 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ soc@ffe00000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ device_type = "soc";
+ compatible = "fsl,p1020-immr", "simple-bus";
+ ranges = <0x0 0x0 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,p1020-ecm", "fsl,ecm";
+ reg = <0x1000 0x1000>;
+ interrupts = <16 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ memory-controller@2000 {
+ compatible = "fsl,p1020-memory-controller";
+ reg = <0x2000 0x1000>;
+ 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;
+ };
+
+ i2c@3100 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cell-index = <1>;
+ compatible = "fsl-i2c";
+ reg = <0x3100 0x100>;
+ interrupts = <43 2>;
+ interrupt-parent = <&mpic>;
+ dfsrr;
+ };
+
+ serial0: serial@4500 {
+ cell-index = <0>;
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0x4500 0x100>;
+ clock-frequency = <0>;
+ interrupts = <42 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ serial1: serial@4600 {
+ cell-index = <1>;
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0x4600 0x100>;
+ clock-frequency = <0>;
+ interrupts = <42 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ spi@7000 {
+ cell-index = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,espi";
+ reg = <0x7000 0x1000>;
+ interrupts = <59 0x2>;
+ interrupt-parent = <&mpic>;
+ mode = "cpu";
+ };
+
+ gpio: gpio-controller@f000 {
+ #gpio-cells = <2>;
+ compatible = "fsl,mpc8572-gpio";
+ reg = <0xf000 0x100>;
+ interrupts = <47 0x2>;
+ interrupt-parent = <&mpic>;
+ gpio-controller;
+ };
+
+ L2: l2-cache-controller@20000 {
+ compatible = "fsl,p1020-l2-cache-controller";
+ reg = <0x20000 0x1000>;
+ cache-line-size = <32>; // 32 bytes
+ cache-size = <0x40000>; // L2,256K
+ interrupt-parent = <&mpic>;
+ 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>;
+ interrupt-parent = <&mpic>;
+ interrupts = <20 2>;
+ };
+ dma-channel@80 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x80 0x80>;
+ cell-index = <1>;
+ interrupt-parent = <&mpic>;
+ interrupts = <21 2>;
+ };
+ dma-channel@100 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x100 0x80>;
+ cell-index = <2>;
+ interrupt-parent = <&mpic>;
+ interrupts = <22 2>;
+ };
+ dma-channel@180 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x180 0x80>;
+ cell-index = <3>;
+ interrupt-parent = <&mpic>;
+ interrupts = <23 2>;
+ };
+ };
+
+ mdio@24000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,etsec2-mdio";
+ reg = <0x24000 0x1000 0xb0030 0x4>;
+
+ };
+
+ mdio@25000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,etsec2-tbi";
+ reg = <0x25000 0x1000 0xb1030 0x4>;
+
+ };
+
+ enet0: ethernet@b0000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ 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 ];
+ interrupt-parent = <&mpic>;
+
+ 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>;
+ 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 ];
+ interrupt-parent = <&mpic>;
+
+ 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>;
+ };
+ };
+
+ enet2: ethernet@b2000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ 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 ];
+ interrupt-parent = <&mpic>;
+
+ queue-group@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xb2000 0x1000>;
+ interrupts = <31 2 32 2 33 2>;
+ };
+
+ queue-group@1 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xb6000 0x1000>;
+ interrupts = <25 2 26 2 27 2>;
+ };
+ };
+
+ usb@22000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl-usb2-dr";
+ reg = <0x22000 0x1000>;
+ interrupt-parent = <&mpic>;
+ interrupts = <28 0x2>;
+ };
+
+ /* USB2 is shared with localbus, so it must be disabled
+ by default. We can't put 'status = "disabled";' here
+ since U-Boot doesn't clear the status property when
+ it enables USB2. OTOH, U-Boot does create a new node
+ when there isn't any. So, just comment it out.
+ usb@23000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl-usb2-dr";
+ reg = <0x23000 0x1000>;
+ interrupt-parent = <&mpic>;
+ interrupts = <46 0x2>;
+ phy_type = "ulpi";
+ };
+ */
+
+ sdhci@2e000 {
+ compatible = "fsl,p1020-esdhc", "fsl,esdhc";
+ reg = <0x2e000 0x1000>;
+ interrupts = <72 0x2>;
+ interrupt-parent = <&mpic>;
+ /* Filled in by U-Boot */
+ clock-frequency = <0>;
+ };
+
+ crypto@30000 {
+ compatible = "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>;
+ interrupt-parent = <&mpic>;
+ fsl,num-channels = <4>;
+ fsl,channel-fifo-len = <24>;
+ fsl,exec-units-mask = <0xbfe>;
+ fsl,descriptor-types-mask = <0x3ab0ebf>;
+ };
+
+ 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,p1020-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>;
+ interrupt-parent = <&mpic>;
+ };
+
+ global-utilities@e0000 { //global utilities block
+ compatible = "fsl,p1020-guts","fsl,p2020-guts";
+ reg = <0xe0000 0x1000>;
+ fsl,has-rstcr;
+ };
+ };
+
+ pci0: pcie@ffe09000 {
+ compatible = "fsl,mpc8548-pcie";
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = <0 0xffe09000 0 0x1000>;
+ bus-range = <0 255>;
+ clock-frequency = <33333333>;
+ interrupt-parent = <&mpic>;
+ interrupts = <16 2>;
+ };
+
+ pci1: pcie@ffe0a000 {
+ compatible = "fsl,mpc8548-pcie";
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = <0 0xffe0a000 0 0x1000>;
+ bus-range = <0 255>;
+ clock-frequency = <33333333>;
+ interrupt-parent = <&mpic>;
+ interrupts = <16 2>;
+ };
+};
diff --git a/arch/powerpc/boot/dts/p1022ds.dts b/arch/powerpc/boot/dts/p1022ds.dts
index 59ef405c1c91..4f685a779f4c 100644
--- a/arch/powerpc/boot/dts/p1022ds.dts
+++ b/arch/powerpc/boot/dts/p1022ds.dts
@@ -52,7 +52,7 @@
#size-cells = <1>;
compatible = "fsl,p1022-elbc", "fsl,elbc", "simple-bus";
reg = <0 0xffe05000 0 0x1000>;
- interrupts = <19 2>;
+ interrupts = <19 2 0 0>;
ranges = <0x0 0x0 0xf 0xe8000000 0x08000000
0x1 0x0 0xf 0xe0000000 0x08000000
@@ -157,7 +157,7 @@
* IRQ8 is generated if the "EVENT" switch is pressed
* and PX_CTL[EVESEL] is set to 00.
*/
- interrupts = <8 8>;
+ interrupts = <8 8 0 0>;
};
};
@@ -178,13 +178,13 @@
ecm@1000 {
compatible = "fsl,p1022-ecm", "fsl,ecm";
reg = <0x1000 0x1000>;
- interrupts = <16 2>;
+ interrupts = <16 2 0 0>;
};
memory-controller@2000 {
compatible = "fsl,p1022-memory-controller";
reg = <0x2000 0x1000>;
- interrupts = <16 2>;
+ interrupts = <16 2 0 0>;
};
i2c@3000 {
@@ -193,7 +193,7 @@
cell-index = <0>;
compatible = "fsl-i2c";
reg = <0x3000 0x100>;
- interrupts = <43 2>;
+ interrupts = <43 2 0 0>;
dfsrr;
};
@@ -203,7 +203,7 @@
cell-index = <1>;
compatible = "fsl-i2c";
reg = <0x3100 0x100>;
- interrupts = <43 2>;
+ interrupts = <43 2 0 0>;
dfsrr;
wm8776:codec@1a {
@@ -220,7 +220,7 @@
compatible = "ns16550";
reg = <0x4500 0x100>;
clock-frequency = <0>;
- interrupts = <42 2>;
+ interrupts = <42 2 0 0>;
};
serial1: serial@4600 {
@@ -229,7 +229,7 @@
compatible = "ns16550";
reg = <0x4600 0x100>;
clock-frequency = <0>;
- interrupts = <42 2>;
+ interrupts = <42 2 0 0>;
};
spi@7000 {
@@ -238,7 +238,7 @@
#size-cells = <0>;
compatible = "fsl,espi";
reg = <0x7000 0x1000>;
- interrupts = <59 0x2>;
+ interrupts = <59 0x2 0 0>;
espi,num-ss-bits = <4>;
mode = "cpu";
@@ -275,7 +275,7 @@
compatible = "fsl,mpc8610-ssi";
cell-index = <0>;
reg = <0x15000 0x100>;
- interrupts = <75 2>;
+ interrupts = <75 2 0 0>;
fsl,mode = "i2s-slave";
codec-handle = <&wm8776>;
fsl,playback-dma = <&dma00>;
@@ -294,25 +294,25 @@
compatible = "fsl,ssi-dma-channel";
reg = <0x0 0x80>;
cell-index = <0>;
- interrupts = <76 2>;
+ interrupts = <76 2 0 0>;
};
dma01: dma-channel@80 {
compatible = "fsl,ssi-dma-channel";
reg = <0x80 0x80>;
cell-index = <1>;
- interrupts = <77 2>;
+ interrupts = <77 2 0 0>;
};
dma-channel@100 {
compatible = "fsl,eloplus-dma-channel";
reg = <0x100 0x80>;
cell-index = <2>;
- interrupts = <78 2>;
+ interrupts = <78 2 0 0>;
};
dma-channel@180 {
compatible = "fsl,eloplus-dma-channel";
reg = <0x180 0x80>;
cell-index = <3>;
- interrupts = <79 2>;
+ interrupts = <79 2 0 0>;
};
};
@@ -320,7 +320,7 @@
#gpio-cells = <2>;
compatible = "fsl,mpc8572-gpio";
reg = <0xf000 0x100>;
- interrupts = <47 0x2>;
+ interrupts = <47 0x2 0 0>;
gpio-controller;
};
@@ -329,7 +329,7 @@
reg = <0x20000 0x1000>;
cache-line-size = <32>; // 32 bytes
cache-size = <0x40000>; // L2, 256K
- interrupts = <16 2>;
+ interrupts = <16 2 0 0>;
};
dma@21300 {
@@ -343,25 +343,25 @@
compatible = "fsl,eloplus-dma-channel";
reg = <0x0 0x80>;
cell-index = <0>;
- interrupts = <20 2>;
+ interrupts = <20 2 0 0>;
};
dma-channel@80 {
compatible = "fsl,eloplus-dma-channel";
reg = <0x80 0x80>;
cell-index = <1>;
- interrupts = <21 2>;
+ interrupts = <21 2 0 0>;
};
dma-channel@100 {
compatible = "fsl,eloplus-dma-channel";
reg = <0x100 0x80>;
cell-index = <2>;
- interrupts = <22 2>;
+ interrupts = <22 2 0 0>;
};
dma-channel@180 {
compatible = "fsl,eloplus-dma-channel";
reg = <0x180 0x80>;
cell-index = <3>;
- interrupts = <23 2>;
+ interrupts = <23 2 0 0>;
};
};
@@ -370,7 +370,7 @@
#size-cells = <0>;
compatible = "fsl-usb2-dr";
reg = <0x22000 0x1000>;
- interrupts = <28 0x2>;
+ interrupts = <28 0x2 0 0>;
phy_type = "ulpi";
};
@@ -381,11 +381,11 @@
reg = <0x24000 0x1000 0xb0030 0x4>;
phy0: ethernet-phy@0 {
- interrupts = <3 1>;
+ interrupts = <3 1 0 0>;
reg = <0x1>;
};
phy1: ethernet-phy@1 {
- interrupts = <9 1>;
+ interrupts = <9 1 0 0>;
reg = <0x2>;
};
};
@@ -416,13 +416,13 @@
#address-cells = <1>;
#size-cells = <1>;
reg = <0xB0000 0x1000>;
- interrupts = <29 2 30 2 34 2>;
+ interrupts = <29 2 0 0 30 2 0 0 34 2 0 0>;
};
queue-group@1{
#address-cells = <1>;
#size-cells = <1>;
reg = <0xB4000 0x1000>;
- interrupts = <17 2 18 2 24 2>;
+ interrupts = <17 2 0 0 18 2 0 0 24 2 0 0>;
};
};
@@ -443,20 +443,20 @@
#address-cells = <1>;
#size-cells = <1>;
reg = <0xB1000 0x1000>;
- interrupts = <35 2 36 2 40 2>;
+ interrupts = <35 2 0 0 36 2 0 0 40 2 0 0>;
};
queue-group@1{
#address-cells = <1>;
#size-cells = <1>;
reg = <0xB5000 0x1000>;
- interrupts = <51 2 52 2 67 2>;
+ interrupts = <51 2 0 0 52 2 0 0 67 2 0 0>;
};
};
sdhci@2e000 {
compatible = "fsl,p1022-esdhc", "fsl,esdhc";
reg = <0x2e000 0x1000>;
- interrupts = <72 0x2>;
+ interrupts = <72 0x2 0 0>;
fsl,sdhci-auto-cmd12;
/* Filled in by U-Boot */
clock-frequency = <0>;
@@ -467,7 +467,7 @@
"fsl,sec2.4", "fsl,sec2.2", "fsl,sec2.1",
"fsl,sec2.0";
reg = <0x30000 0x10000>;
- interrupts = <45 2 58 2>;
+ interrupts = <45 2 0 0 58 2 0 0>;
fsl,num-channels = <4>;
fsl,channel-fifo-len = <24>;
fsl,exec-units-mask = <0x97c>;
@@ -478,14 +478,14 @@
compatible = "fsl,p1022-sata", "fsl,pq-sata-v2";
reg = <0x18000 0x1000>;
cell-index = <1>;
- interrupts = <74 0x2>;
+ interrupts = <74 0x2 0 0>;
};
sata@19000 {
compatible = "fsl,p1022-sata", "fsl,pq-sata-v2";
reg = <0x19000 0x1000>;
cell-index = <2>;
- interrupts = <41 0x2>;
+ interrupts = <41 0x2 0 0>;
};
power@e0070{
@@ -496,21 +496,33 @@
display@10000 {
compatible = "fsl,diu", "fsl,p1022-diu";
reg = <0x10000 1000>;
- interrupts = <64 2>;
+ interrupts = <64 2 0 0>;
};
timer@41100 {
compatible = "fsl,mpic-global-timer";
- reg = <0x41100 0x204>;
- interrupts = <0xf7 0x2>;
+ reg = <0x41100 0x100 0x41300 4>;
+ interrupts = <0 0 3 0
+ 1 0 3 0
+ 2 0 3 0
+ 3 0 3 0>;
+ };
+
+ timer@42100 {
+ compatible = "fsl,mpic-global-timer";
+ reg = <0x42100 0x100 0x42300 4>;
+ interrupts = <4 0 3 0
+ 5 0 3 0
+ 6 0 3 0
+ 7 0 3 0>;
};
mpic: pic@40000 {
interrupt-controller;
#address-cells = <0>;
- #interrupt-cells = <2>;
+ #interrupt-cells = <4>;
reg = <0x40000 0x40000>;
- compatible = "chrp,open-pic";
+ compatible = "fsl,mpic";
device_type = "open-pic";
};
@@ -519,14 +531,14 @@
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>;
+ 0xe0 0 0 0
+ 0xe1 0 0 0
+ 0xe2 0 0 0
+ 0xe3 0 0 0
+ 0xe4 0 0 0
+ 0xe5 0 0 0
+ 0xe6 0 0 0
+ 0xe7 0 0 0>;
};
global-utilities@e0000 { //global utilities block
@@ -547,7 +559,7 @@
ranges = <0x2000000 0x0 0xa0000000 0xc 0x20000000 0x0 0x20000000
0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>;
clock-frequency = <33333333>;
- interrupts = <16 2>;
+ interrupts = <16 2 0 0>;
interrupt-map-mask = <0xf800 0 0 7>;
interrupt-map = <
/* IDSEL 0x0 */
@@ -582,7 +594,7 @@
ranges = <0x2000000 0x0 0xc0000000 0xc 0x40000000 0x0 0x20000000
0x1000000 0x0 0x00000000 0xf 0xffc20000 0x0 0x10000>;
clock-frequency = <33333333>;
- interrupts = <16 2>;
+ interrupts = <16 2 0 0>;
interrupt-map-mask = <0xf800 0 0 7>;
interrupt-map = <
/* IDSEL 0x0 */
@@ -618,7 +630,7 @@
ranges = <0x2000000 0x0 0x80000000 0xc 0x00000000 0x0 0x20000000
0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>;
clock-frequency = <33333333>;
- interrupts = <16 2>;
+ interrupts = <16 2 0 0>;
interrupt-map-mask = <0xf800 0 0 7>;
interrupt-map = <
/* IDSEL 0x0 */
diff --git a/arch/powerpc/boot/dts/p2020ds.dts b/arch/powerpc/boot/dts/p2020ds.dts
index 11019142813c..dae403100f2f 100644
--- a/arch/powerpc/boot/dts/p2020ds.dts
+++ b/arch/powerpc/boot/dts/p2020ds.dts
@@ -1,7 +1,7 @@
/*
* P2020 DS Device Tree Source
*
- * Copyright 2009 Freescale Semiconductor Inc.
+ * Copyright 2009-2011 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
@@ -9,12 +9,11 @@
* option) any later version.
*/
-/dts-v1/;
+/include/ "p2020si.dtsi"
+
/ {
- model = "fsl,P2020";
+ model = "fsl,P2020DS";
compatible = "fsl,P2020DS";
- #address-cells = <2>;
- #size-cells = <2>;
aliases {
ethernet0 = &enet0;
@@ -27,35 +26,13 @@
pci2 = &pci2;
};
- cpus {
- #address-cells = <1>;
- #size-cells = <0>;
-
- PowerPC,P2020@0 {
- device_type = "cpu";
- reg = <0x0>;
- next-level-cache = <&L2>;
- };
-
- PowerPC,P2020@1 {
- device_type = "cpu";
- reg = <0x1>;
- next-level-cache = <&L2>;
- };
- };
memory {
device_type = "memory";
};
localbus@ffe05000 {
- #address-cells = <2>;
- #size-cells = <1>;
compatible = "fsl,elbc", "simple-bus";
- reg = <0 0xffe05000 0 0x1000>;
- interrupts = <19 2>;
- interrupt-parent = <&mpic>;
-
ranges = <0x0 0x0 0x0 0xe8000000 0x08000000
0x1 0x0 0x0 0xe0000000 0x08000000
0x2 0x0 0x0 0xffa00000 0x00040000
@@ -158,352 +135,90 @@
};
soc@ffe00000 {
- #address-cells = <1>;
- #size-cells = <1>;
- device_type = "soc";
- compatible = "fsl,p2020-immr", "simple-bus";
- ranges = <0x0 0 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,p2020-ecm", "fsl,ecm";
- reg = <0x1000 0x1000>;
- interrupts = <17 2>;
- interrupt-parent = <&mpic>;
- };
-
- memory-controller@2000 {
- compatible = "fsl,p2020-memory-controller";
- reg = <0x2000 0x1000>;
- interrupt-parent = <&mpic>;
- interrupts = <18 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;
- };
-
- i2c@3100 {
- #address-cells = <1>;
- #size-cells = <0>;
- cell-index = <1>;
- compatible = "fsl-i2c";
- reg = <0x3100 0x100>;
- interrupts = <43 2>;
- interrupt-parent = <&mpic>;
- dfsrr;
- };
- serial0: serial@4500 {
- cell-index = <0>;
- device_type = "serial";
- compatible = "ns16550";
- reg = <0x4500 0x100>;
- clock-frequency = <0>;
- interrupts = <42 2>;
- interrupt-parent = <&mpic>;
- };
-
- serial1: serial@4600 {
- cell-index = <1>;
- device_type = "serial";
- compatible = "ns16550";
- reg = <0x4600 0x100>;
- clock-frequency = <0>;
- interrupts = <42 2>;
- interrupt-parent = <&mpic>;
- };
-
- spi@7000 {
- compatible = "fsl,espi";
- reg = <0x7000 0x1000>;
- interrupts = <59 0x2>;
- interrupt-parent = <&mpic>;
+ usb@22000 {
+ phy_type = "ulpi";
};
- dma@c300 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "fsl,eloplus-dma";
- reg = <0xc300 0x4>;
- ranges = <0x0 0xc100 0x200>;
- cell-index = <1>;
- dma-channel@0 {
- compatible = "fsl,eloplus-dma-channel";
- reg = <0x0 0x80>;
- cell-index = <0>;
+ mdio@24520 {
+ phy0: ethernet-phy@0 {
interrupt-parent = <&mpic>;
- interrupts = <76 2>;
+ interrupts = <3 1>;
+ reg = <0x0>;
};
- dma-channel@80 {
- compatible = "fsl,eloplus-dma-channel";
- reg = <0x80 0x80>;
- cell-index = <1>;
+ phy1: ethernet-phy@1 {
interrupt-parent = <&mpic>;
- interrupts = <77 2>;
+ interrupts = <3 1>;
+ reg = <0x1>;
};
- dma-channel@100 {
- compatible = "fsl,eloplus-dma-channel";
- reg = <0x100 0x80>;
- cell-index = <2>;
+ phy2: ethernet-phy@2 {
interrupt-parent = <&mpic>;
- interrupts = <78 2>;
+ interrupts = <3 1>;
+ reg = <0x2>;
};
- dma-channel@180 {
- compatible = "fsl,eloplus-dma-channel";
- reg = <0x180 0x80>;
- cell-index = <3>;
- interrupt-parent = <&mpic>;
- interrupts = <79 2>;
+ tbi0: tbi-phy@11 {
+ reg = <0x11>;
+ device_type = "tbi-phy";
};
- };
- gpio: gpio-controller@f000 {
- #gpio-cells = <2>;
- compatible = "fsl,mpc8572-gpio";
- reg = <0xf000 0x100>;
- interrupts = <47 0x2>;
- interrupt-parent = <&mpic>;
- gpio-controller;
};
- L2: l2-cache-controller@20000 {
- compatible = "fsl,p2020-l2-cache-controller";
- reg = <0x20000 0x1000>;
- cache-line-size = <32>; // 32 bytes
- cache-size = <0x80000>; // L2, 512k
- interrupt-parent = <&mpic>;
- interrupts = <16 2>;
+ mdio@25520 {
+ tbi1: tbi-phy@11 {
+ reg = <0x11>;
+ device_type = "tbi-phy";
+ };
};
- 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>;
- interrupt-parent = <&mpic>;
- interrupts = <20 2>;
- };
- dma-channel@80 {
- compatible = "fsl,eloplus-dma-channel";
- reg = <0x80 0x80>;
- cell-index = <1>;
- interrupt-parent = <&mpic>;
- interrupts = <21 2>;
- };
- dma-channel@100 {
- compatible = "fsl,eloplus-dma-channel";
- reg = <0x100 0x80>;
- cell-index = <2>;
- interrupt-parent = <&mpic>;
- interrupts = <22 2>;
- };
- dma-channel@180 {
- compatible = "fsl,eloplus-dma-channel";
- reg = <0x180 0x80>;
- cell-index = <3>;
- interrupt-parent = <&mpic>;
- interrupts = <23 2>;
+ mdio@26520 {
+ tbi2: tbi-phy@11 {
+ reg = <0x11>;
+ device_type = "tbi-phy";
};
+
};
- usb@22000 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl-usb2-dr";
- reg = <0x22000 0x1000>;
- interrupt-parent = <&mpic>;
- interrupts = <28 0x2>;
- phy_type = "ulpi";
+ ptp_clock@24E00 {
+ compatible = "fsl,etsec-ptp";
+ reg = <0x24E00 0xB0>;
+ interrupts = <68 2 69 2 70 2>;
+ interrupt-parent = < &mpic >;
+ fsl,tclk-period = <5>;
+ fsl,tmr-prsc = <200>;
+ fsl,tmr-add = <0xCCCCCCCD>;
+ fsl,tmr-fiper1 = <0x3B9AC9FB>;
+ fsl,tmr-fiper2 = <0x0001869B>;
+ fsl,max-adj = <249999999>;
};
enet0: ethernet@24000 {
- #address-cells = <1>;
- #size-cells = <1>;
- cell-index = <0>;
- device_type = "network";
- model = "eTSEC";
- 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>;
phy-connection-type = "rgmii-id";
-
- mdio@520 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl,gianfar-mdio";
- reg = <0x520 0x20>;
-
- phy0: ethernet-phy@0 {
- interrupt-parent = <&mpic>;
- interrupts = <3 1>;
- reg = <0x0>;
- };
- phy1: ethernet-phy@1 {
- interrupt-parent = <&mpic>;
- interrupts = <3 1>;
- reg = <0x1>;
- };
- phy2: ethernet-phy@2 {
- interrupt-parent = <&mpic>;
- interrupts = <3 1>;
- reg = <0x2>;
- };
- 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 2 36 2 40 2>;
- interrupt-parent = <&mpic>;
tbi-handle = <&tbi1>;
phy-handle = <&phy1>;
phy-connection-type = "rgmii-id";
- 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";
- };
- };
};
enet2: ethernet@26000 {
- #address-cells = <1>;
- #size-cells = <1>;
- cell-index = <2>;
- device_type = "network";
- model = "eTSEC";
- compatible = "gianfar";
- reg = <0x26000 0x1000>;
- ranges = <0x0 0x26000 0x1000>;
- local-mac-address = [ 00 00 00 00 00 00 ];
- interrupts = <31 2 32 2 33 2>;
- interrupt-parent = <&mpic>;
tbi-handle = <&tbi2>;
phy-handle = <&phy2>;
phy-connection-type = "rgmii-id";
-
- mdio@520 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl,gianfar-tbi";
- reg = <0x520 0x20>;
-
- tbi2: tbi-phy@11 {
- reg = <0x11>;
- device_type = "tbi-phy";
- };
- };
- };
-
- sdhci@2e000 {
- compatible = "fsl,p2020-esdhc", "fsl,esdhc";
- reg = <0x2e000 0x1000>;
- interrupts = <72 0x2>;
- interrupt-parent = <&mpic>;
- /* Filled in by U-Boot */
- clock-frequency = <0>;
- };
-
- crypto@30000 {
- compatible = "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>;
- interrupt-parent = <&mpic>;
- fsl,num-channels = <4>;
- fsl,channel-fifo-len = <24>;
- fsl,exec-units-mask = <0xbfe>;
- fsl,descriptor-types-mask = <0x3ab0ebf>;
};
- 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,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>;
- interrupt-parent = <&mpic>;
- };
-
- global-utilities@e0000 { //global utilities block
- compatible = "fsl,p2020-guts";
- reg = <0xe0000 0x1000>;
- fsl,has-rstcr;
};
};
pci0: pcie@ffe08000 {
- compatible = "fsl,mpc8548-pcie";
- device_type = "pci";
- #interrupt-cells = <1>;
- #size-cells = <2>;
- #address-cells = <3>;
- reg = <0 0xffe08000 0 0x1000>;
- bus-range = <0 255>;
ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000
0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
- clock-frequency = <33333333>;
- interrupt-parent = <&mpic>;
- interrupts = <24 2>;
interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
interrupt-map = <
/* IDSEL 0x0 */
@@ -528,18 +243,8 @@
};
pci1: pcie@ffe09000 {
- compatible = "fsl,mpc8548-pcie";
- device_type = "pci";
- #interrupt-cells = <1>;
- #size-cells = <2>;
- #address-cells = <3>;
- reg = <0 0xffe09000 0 0x1000>;
- bus-range = <0 255>;
ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
- clock-frequency = <33333333>;
- interrupt-parent = <&mpic>;
- interrupts = <25 2>;
interrupt-map-mask = <0xff00 0x0 0x0 0x7>;
interrupt-map = <
@@ -667,18 +372,8 @@
};
pci2: pcie@ffe0a000 {
- compatible = "fsl,mpc8548-pcie";
- device_type = "pci";
- #interrupt-cells = <1>;
- #size-cells = <2>;
- #address-cells = <3>;
- reg = <0 0xffe0a000 0 0x1000>;
- bus-range = <0 255>;
ranges = <0x2000000 0x0 0xc0000000 0 0xc0000000 0x0 0x20000000
0x1000000 0x0 0x00000000 0 0xffc20000 0x0 0x10000>;
- clock-frequency = <33333333>;
- interrupt-parent = <&mpic>;
- interrupts = <26 2>;
interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
interrupt-map = <
/* IDSEL 0x0 */
diff --git a/arch/powerpc/boot/dts/p2020rdb.dts b/arch/powerpc/boot/dts/p2020rdb.dts
index e2d48fd4416e..1d7a05f3021e 100644
--- a/arch/powerpc/boot/dts/p2020rdb.dts
+++ b/arch/powerpc/boot/dts/p2020rdb.dts
@@ -9,12 +9,11 @@
* option) any later version.
*/
-/dts-v1/;
+/include/ "p2020si.dtsi"
+
/ {
- model = "fsl,P2020";
+ model = "fsl,P2020RDB";
compatible = "fsl,P2020RDB";
- #address-cells = <2>;
- #size-cells = <2>;
aliases {
ethernet0 = &enet0;
@@ -26,34 +25,11 @@
pci1 = &pci1;
};
- cpus {
- #address-cells = <1>;
- #size-cells = <0>;
-
- PowerPC,P2020@0 {
- device_type = "cpu";
- reg = <0x0>;
- next-level-cache = <&L2>;
- };
-
- PowerPC,P2020@1 {
- device_type = "cpu";
- reg = <0x1>;
- next-level-cache = <&L2>;
- };
- };
-
memory {
device_type = "memory";
};
localbus@ffe05000 {
- #address-cells = <2>;
- #size-cells = <1>;
- compatible = "fsl,p2020-elbc", "fsl,elbc", "simple-bus";
- reg = <0 0xffe05000 0 0x1000>;
- interrupts = <19 2>;
- interrupt-parent = <&mpic>;
/* NOR and NAND Flashes */
ranges = <0x0 0x0 0x0 0xef000000 0x01000000
@@ -165,90 +141,16 @@
};
soc@ffe00000 {
- #address-cells = <1>;
- #size-cells = <1>;
- device_type = "soc";
- compatible = "fsl,p2020-immr", "simple-bus";
- ranges = <0x0 0x0 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,p2020-ecm", "fsl,ecm";
- reg = <0x1000 0x1000>;
- interrupts = <17 2>;
- interrupt-parent = <&mpic>;
- };
-
- memory-controller@2000 {
- compatible = "fsl,p2020-memory-controller";
- reg = <0x2000 0x1000>;
- interrupt-parent = <&mpic>;
- interrupts = <18 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;
rtc@68 {
compatible = "dallas,ds1339";
reg = <0x68>;
};
};
- i2c@3100 {
- #address-cells = <1>;
- #size-cells = <0>;
- cell-index = <1>;
- compatible = "fsl-i2c";
- reg = <0x3100 0x100>;
- interrupts = <43 2>;
- interrupt-parent = <&mpic>;
- dfsrr;
- };
-
- serial0: serial@4500 {
- cell-index = <0>;
- device_type = "serial";
- compatible = "ns16550";
- reg = <0x4500 0x100>;
- clock-frequency = <0>;
- interrupts = <42 2>;
- interrupt-parent = <&mpic>;
- };
-
- serial1: serial@4600 {
- cell-index = <1>;
- device_type = "serial";
- compatible = "ns16550";
- reg = <0x4600 0x100>;
- clock-frequency = <0>;
- interrupts = <42 2>;
- interrupt-parent = <&mpic>;
- };
+ spi@7000 {
- spi@7000 {
- cell-index = <0>;
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl,espi";
- reg = <0x7000 0x1000>;
- interrupts = <59 0x2>;
- interrupt-parent = <&mpic>;
- mode = "cpu";
-
- fsl_m25p80@0 {
+ fsl_m25p80@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "fsl,espi-flash";
@@ -294,254 +196,81 @@
};
};
- dma@c300 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "fsl,eloplus-dma";
- reg = <0xc300 0x4>;
- ranges = <0x0 0xc100 0x200>;
- cell-index = <1>;
- dma-channel@0 {
- compatible = "fsl,eloplus-dma-channel";
- reg = <0x0 0x80>;
- cell-index = <0>;
- interrupt-parent = <&mpic>;
- interrupts = <76 2>;
- };
- dma-channel@80 {
- compatible = "fsl,eloplus-dma-channel";
- reg = <0x80 0x80>;
- cell-index = <1>;
- interrupt-parent = <&mpic>;
- interrupts = <77 2>;
- };
- dma-channel@100 {
- compatible = "fsl,eloplus-dma-channel";
- reg = <0x100 0x80>;
- cell-index = <2>;
+ usb@22000 {
+ phy_type = "ulpi";
+ };
+
+ mdio@24520 {
+ phy0: ethernet-phy@0 {
interrupt-parent = <&mpic>;
- interrupts = <78 2>;
- };
- dma-channel@180 {
- compatible = "fsl,eloplus-dma-channel";
- reg = <0x180 0x80>;
- cell-index = <3>;
+ interrupts = <3 1>;
+ reg = <0x0>;
+ };
+ phy1: ethernet-phy@1 {
interrupt-parent = <&mpic>;
- interrupts = <79 2>;
- };
+ interrupts = <3 1>;
+ reg = <0x1>;
+ };
};
- gpio: gpio-controller@f000 {
- #gpio-cells = <2>;
- compatible = "fsl,mpc8572-gpio";
- reg = <0xf000 0x100>;
- interrupts = <47 0x2>;
- interrupt-parent = <&mpic>;
- gpio-controller;
+ mdio@25520 {
+ tbi0: tbi-phy@11 {
+ reg = <0x11>;
+ device_type = "tbi-phy";
+ };
};
- L2: l2-cache-controller@20000 {
- compatible = "fsl,p2020-l2-cache-controller";
- reg = <0x20000 0x1000>;
- cache-line-size = <32>; // 32 bytes
- cache-size = <0x80000>; // L2,512K
- interrupt-parent = <&mpic>;
- interrupts = <16 2>;
+ mdio@26520 {
+ status = "disabled";
};
- 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>;
- interrupt-parent = <&mpic>;
- interrupts = <20 2>;
- };
- dma-channel@80 {
- compatible = "fsl,eloplus-dma-channel";
- reg = <0x80 0x80>;
- cell-index = <1>;
- interrupt-parent = <&mpic>;
- interrupts = <21 2>;
- };
- dma-channel@100 {
- compatible = "fsl,eloplus-dma-channel";
- reg = <0x100 0x80>;
- cell-index = <2>;
- interrupt-parent = <&mpic>;
- interrupts = <22 2>;
- };
- dma-channel@180 {
- compatible = "fsl,eloplus-dma-channel";
- reg = <0x180 0x80>;
- cell-index = <3>;
- interrupt-parent = <&mpic>;
- interrupts = <23 2>;
- };
- };
-
- usb@22000 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl-usb2-dr";
- reg = <0x22000 0x1000>;
- interrupt-parent = <&mpic>;
- interrupts = <28 0x2>;
- phy_type = "ulpi";
+ ptp_clock@24E00 {
+ compatible = "fsl,etsec-ptp";
+ reg = <0x24E00 0xB0>;
+ interrupts = <68 2 69 2 70 2>;
+ interrupt-parent = < &mpic >;
+ fsl,tclk-period = <5>;
+ fsl,tmr-prsc = <200>;
+ fsl,tmr-add = <0xCCCCCCCD>;
+ fsl,tmr-fiper1 = <0x3B9AC9FB>;
+ fsl,tmr-fiper2 = <0x0001869B>;
+ fsl,max-adj = <249999999>;
};
enet0: ethernet@24000 {
- #address-cells = <1>;
- #size-cells = <1>;
- cell-index = <0>;
- device_type = "network";
- model = "eTSEC";
- 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>;
fixed-link = <1 1 1000 0 0>;
phy-connection-type = "rgmii-id";
-
- mdio@520 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl,gianfar-mdio";
- reg = <0x520 0x20>;
-
- phy0: ethernet-phy@0 {
- interrupt-parent = <&mpic>;
- interrupts = <3 1>;
- reg = <0x0>;
- };
- phy1: ethernet-phy@1 {
- interrupt-parent = <&mpic>;
- interrupts = <3 1>;
- reg = <0x1>;
- };
- };
};
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 2 36 2 40 2>;
- interrupt-parent = <&mpic>;
tbi-handle = <&tbi0>;
phy-handle = <&phy0>;
phy-connection-type = "sgmii";
-
- mdio@520 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl,gianfar-tbi";
- reg = <0x520 0x20>;
-
- tbi0: tbi-phy@11 {
- reg = <0x11>;
- device_type = "tbi-phy";
- };
- };
};
enet2: ethernet@26000 {
- #address-cells = <1>;
- #size-cells = <1>;
- cell-index = <2>;
- device_type = "network";
- model = "eTSEC";
- compatible = "gianfar";
- reg = <0x26000 0x1000>;
- ranges = <0x0 0x26000 0x1000>;
- local-mac-address = [ 00 00 00 00 00 00 ];
- interrupts = <31 2 32 2 33 2>;
- interrupt-parent = <&mpic>;
phy-handle = <&phy1>;
phy-connection-type = "rgmii-id";
};
- sdhci@2e000 {
- compatible = "fsl,p2020-esdhc", "fsl,esdhc";
- reg = <0x2e000 0x1000>;
- interrupts = <72 0x2>;
- interrupt-parent = <&mpic>;
- /* Filled in by U-Boot */
- clock-frequency = <0>;
- };
-
- crypto@30000 {
- compatible = "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>;
- interrupt-parent = <&mpic>;
- fsl,num-channels = <4>;
- fsl,channel-fifo-len = <24>;
- fsl,exec-units-mask = <0xbfe>;
- fsl,descriptor-types-mask = <0x3ab0ebf>;
- };
-
- 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,p2020-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>;
- interrupt-parent = <&mpic>;
- };
+ };
- global-utilities@e0000 { //global utilities block
- compatible = "fsl,p2020-guts";
- reg = <0xe0000 0x1000>;
- fsl,has-rstcr;
- };
+ pci0: pcie@ffe08000 {
+ status = "disabled";
};
- pci0: pcie@ffe09000 {
- compatible = "fsl,mpc8548-pcie";
- device_type = "pci";
- #interrupt-cells = <1>;
- #size-cells = <2>;
- #address-cells = <3>;
- reg = <0 0xffe09000 0 0x1000>;
- bus-range = <0 255>;
+ pci1: pcie@ffe09000 {
ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
- clock-frequency = <33333333>;
- interrupt-parent = <&mpic>;
- interrupts = <25 2>;
- pcie@0 {
+ interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+ interrupt-map = <
+ /* IDSEL 0x0 */
+ 0000 0x0 0x0 0x1 &mpic 0x4 0x1
+ 0000 0x0 0x0 0x2 &mpic 0x5 0x1
+ 0000 0x0 0x0 0x3 &mpic 0x6 0x1
+ 0000 0x0 0x0 0x4 &mpic 0x7 0x1
+ >;
+ pcie@0 {
reg = <0x0 0x0 0x0 0x0 0x0>;
#size-cells = <2>;
#address-cells = <3>;
@@ -556,19 +285,17 @@
};
};
- pci1: pcie@ffe0a000 {
- compatible = "fsl,mpc8548-pcie";
- device_type = "pci";
- #interrupt-cells = <1>;
- #size-cells = <2>;
- #address-cells = <3>;
- reg = <0 0xffe0a000 0 0x1000>;
- bus-range = <0 255>;
+ pci2: pcie@ffe0a000 {
ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000
0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
- clock-frequency = <33333333>;
- interrupt-parent = <&mpic>;
- interrupts = <26 2>;
+ interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+ interrupt-map = <
+ /* IDSEL 0x0 */
+ 0000 0x0 0x0 0x1 &mpic 0x0 0x1
+ 0000 0x0 0x0 0x2 &mpic 0x1 0x1
+ 0000 0x0 0x0 0x3 &mpic 0x2 0x1
+ 0000 0x0 0x0 0x4 &mpic 0x3 0x1
+ >;
pcie@0 {
reg = <0x0 0x0 0x0 0x0 0x0>;
#size-cells = <2>;
diff --git a/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts b/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts
index b69c3a5dc858..fc8ddddfccb6 100644
--- a/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts
+++ b/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts
@@ -14,12 +14,11 @@
* option) any later version.
*/
-/dts-v1/;
+/include/ "p2020si.dtsi"
+
/ {
- model = "fsl,P2020";
+ model = "fsl,P2020RDB";
compatible = "fsl,P2020RDB", "fsl,MPC85XXRDB-CAMP";
- #address-cells = <2>;
- #size-cells = <2>;
aliases {
ethernet1 = &enet1;
@@ -29,91 +28,33 @@
};
cpus {
- #address-cells = <1>;
- #size-cells = <0>;
-
- PowerPC,P2020@0 {
- device_type = "cpu";
- reg = <0x0>;
- next-level-cache = <&L2>;
+ PowerPC,P2020@1 {
+ status = "disabled";
};
+
};
memory {
device_type = "memory";
};
- soc@ffe00000 {
- #address-cells = <1>;
- #size-cells = <1>;
- device_type = "soc";
- compatible = "fsl,p2020-immr", "simple-bus";
- ranges = <0x0 0x0 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,p2020-ecm", "fsl,ecm";
- reg = <0x1000 0x1000>;
- interrupts = <17 2>;
- interrupt-parent = <&mpic>;
- };
-
- memory-controller@2000 {
- compatible = "fsl,p2020-memory-controller";
- reg = <0x2000 0x1000>;
- interrupt-parent = <&mpic>;
- interrupts = <18 2>;
- };
+ localbus@ffe05000 {
+ status = "disabled";
+ };
+ soc@ffe00000 {
i2c@3000 {
- #address-cells = <1>;
- #size-cells = <0>;
- cell-index = <0>;
- compatible = "fsl-i2c";
- reg = <0x3000 0x100>;
- interrupts = <43 2>;
- interrupt-parent = <&mpic>;
- dfsrr;
rtc@68 {
compatible = "dallas,ds1339";
reg = <0x68>;
};
};
- i2c@3100 {
- #address-cells = <1>;
- #size-cells = <0>;
- cell-index = <1>;
- compatible = "fsl-i2c";
- reg = <0x3100 0x100>;
- interrupts = <43 2>;
- interrupt-parent = <&mpic>;
- dfsrr;
- };
-
- serial0: serial@4500 {
- cell-index = <0>;
- device_type = "serial";
- compatible = "ns16550";
- reg = <0x4500 0x100>;
- clock-frequency = <0>;
+ serial1: serial@4600 {
+ status = "disabled";
};
spi@7000 {
- cell-index = <0>;
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl,espi";
- reg = <0x7000 0x1000>;
- interrupts = <59 0x2>;
- interrupt-parent = <&mpic>;
- mode = "cpu";
fsl_m25p80@0 {
#address-cells = <1>;
@@ -161,76 +102,15 @@
};
};
- gpio: gpio-controller@f000 {
- #gpio-cells = <2>;
- compatible = "fsl,mpc8572-gpio";
- reg = <0xf000 0x100>;
- interrupts = <47 0x2>;
- interrupt-parent = <&mpic>;
- gpio-controller;
- };
-
- L2: l2-cache-controller@20000 {
- compatible = "fsl,p2020-l2-cache-controller";
- reg = <0x20000 0x1000>;
- cache-line-size = <32>; // 32 bytes
- cache-size = <0x80000>; // L2,512K
- interrupt-parent = <&mpic>;
- 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>;
- interrupt-parent = <&mpic>;
- interrupts = <20 2>;
- };
- dma-channel@80 {
- compatible = "fsl,eloplus-dma-channel";
- reg = <0x80 0x80>;
- cell-index = <1>;
- interrupt-parent = <&mpic>;
- interrupts = <21 2>;
- };
- dma-channel@100 {
- compatible = "fsl,eloplus-dma-channel";
- reg = <0x100 0x80>;
- cell-index = <2>;
- interrupt-parent = <&mpic>;
- interrupts = <22 2>;
- };
- dma-channel@180 {
- compatible = "fsl,eloplus-dma-channel";
- reg = <0x180 0x80>;
- cell-index = <3>;
- interrupt-parent = <&mpic>;
- interrupts = <23 2>;
- };
+ dma@c300 {
+ status = "disabled";
};
usb@22000 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl-usb2-dr";
- reg = <0x22000 0x1000>;
- interrupt-parent = <&mpic>;
- interrupts = <28 0x2>;
phy_type = "ulpi";
};
mdio@24520 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl,gianfar-mdio";
- reg = <0x24520 0x20>;
phy0: ethernet-phy@0 {
interrupt-parent = <&mpic>;
@@ -245,29 +125,21 @@
};
mdio@25520 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl,gianfar-tbi";
- reg = <0x26520 0x20>;
-
tbi0: tbi-phy@11 {
reg = <0x11>;
device_type = "tbi-phy";
};
};
+ mdio@26520 {
+ status = "disabled";
+ };
+
+ enet0: ethernet@24000 {
+ status = "disabled";
+ };
+
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 2 36 2 40 2>;
- interrupt-parent = <&mpic>;
tbi-handle = <&tbi0>;
phy-handle = <&phy0>;
phy-connection-type = "sgmii";
@@ -275,49 +147,12 @@
};
enet2: ethernet@26000 {
- #address-cells = <1>;
- #size-cells = <1>;
- cell-index = <2>;
- device_type = "network";
- model = "eTSEC";
- compatible = "gianfar";
- reg = <0x26000 0x1000>;
- ranges = <0x0 0x26000 0x1000>;
- local-mac-address = [ 00 00 00 00 00 00 ];
- interrupts = <31 2 32 2 33 2>;
- interrupt-parent = <&mpic>;
phy-handle = <&phy1>;
phy-connection-type = "rgmii-id";
};
- sdhci@2e000 {
- compatible = "fsl,p2020-esdhc", "fsl,esdhc";
- reg = <0x2e000 0x1000>;
- interrupts = <72 0x2>;
- interrupt-parent = <&mpic>;
- /* Filled in by U-Boot */
- clock-frequency = <0>;
- };
-
- crypto@30000 {
- compatible = "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>;
- interrupt-parent = <&mpic>;
- fsl,num-channels = <4>;
- fsl,channel-fifo-len = <24>;
- fsl,exec-units-mask = <0xbfe>;
- fsl,descriptor-types-mask = <0x3ab0ebf>;
- };
mpic: pic@40000 {
- interrupt-controller;
- #address-cells = <0>;
- #interrupt-cells = <2>;
- reg = <0x40000 0x40000>;
- compatible = "chrp,open-pic";
- device_type = "open-pic";
protected-sources = <
42 76 77 78 79 /* serial1 , dma2 */
29 30 34 26 /* enet0, pci1 */
@@ -326,26 +161,28 @@
>;
};
- global-utilities@e0000 {
- compatible = "fsl,p2020-guts";
- reg = <0xe0000 0x1000>;
- fsl,has-rstcr;
+ msi@41600 {
+ status = "disabled";
};
+
+
};
- pci0: pcie@ffe09000 {
- compatible = "fsl,mpc8548-pcie";
- device_type = "pci";
- #interrupt-cells = <1>;
- #size-cells = <2>;
- #address-cells = <3>;
- reg = <0 0xffe09000 0 0x1000>;
- bus-range = <0 255>;
+ pci0: pcie@ffe08000 {
+ status = "disabled";
+ };
+
+ pci1: pcie@ffe09000 {
ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
- clock-frequency = <33333333>;
- interrupt-parent = <&mpic>;
- interrupts = <25 2>;
+ interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+ interrupt-map = <
+ /* IDSEL 0x0 */
+ 0000 0x0 0x0 0x1 &mpic 0x4 0x1
+ 0000 0x0 0x0 0x2 &mpic 0x5 0x1
+ 0000 0x0 0x0 0x3 &mpic 0x6 0x1
+ 0000 0x0 0x0 0x4 &mpic 0x7 0x1
+ >;
pcie@0 {
reg = <0x0 0x0 0x0 0x0 0x0>;
#size-cells = <2>;
@@ -360,4 +197,8 @@
0x0 0x100000>;
};
};
+
+ pci2: pcie@ffe0a000 {
+ status = "disabled";
+ };
};
diff --git a/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts b/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts
index 7a31d46c01b0..261c34ba45ec 100644
--- a/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts
+++ b/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts
@@ -15,27 +15,21 @@
* option) any later version.
*/
-/dts-v1/;
+/include/ "p2020si.dtsi"
+
/ {
- model = "fsl,P2020";
+ model = "fsl,P2020RDB";
compatible = "fsl,P2020RDB", "fsl,MPC85XXRDB-CAMP";
- #address-cells = <2>;
- #size-cells = <2>;
aliases {
ethernet0 = &enet0;
- serial0 = &serial0;
+ serial0 = &serial1;
pci1 = &pci1;
};
cpus {
- #address-cells = <1>;
- #size-cells = <0>;
-
- PowerPC,P2020@1 {
- device_type = "cpu";
- reg = <0x1>;
- next-level-cache = <&L2>;
+ PowerPC,P2020@0 {
+ status = "disabled";
};
};
@@ -43,20 +37,37 @@
device_type = "memory";
};
+ localbus@ffe05000 {
+ status = "disabled";
+ };
+
soc@ffe00000 {
- #address-cells = <1>;
- #size-cells = <1>;
- device_type = "soc";
- compatible = "fsl,p2020-immr", "simple-bus";
- ranges = <0x0 0x0 0xffe00000 0x100000>;
- bus-frequency = <0>; // Filled out by uboot.
-
- serial0: serial@4600 {
- cell-index = <1>;
- device_type = "serial";
- compatible = "ns16550";
- reg = <0x4600 0x100>;
- clock-frequency = <0>;
+ ecm-law@0 {
+ status = "disabled";
+ };
+
+ ecm@1000 {
+ status = "disabled";
+ };
+
+ memory-controller@2000 {
+ status = "disabled";
+ };
+
+ i2c@3000 {
+ status = "disabled";
+ };
+
+ i2c@3100 {
+ status = "disabled";
+ };
+
+ serial0: serial@4500 {
+ status = "disabled";
+ };
+
+ spi@7000 {
+ status = "disabled";
};
dma@c300 {
@@ -96,6 +107,10 @@
};
};
+ gpio: gpio-controller@f000 {
+ status = "disabled";
+ };
+
L2: l2-cache-controller@20000 {
compatible = "fsl,p2020-l2-cache-controller";
reg = <0x20000 0x1000>;
@@ -104,31 +119,49 @@
interrupt-parent = <&mpic>;
};
+ dma@21300 {
+ status = "disabled";
+ };
+
+ usb@22000 {
+ status = "disabled";
+ };
+
+ mdio@24520 {
+ status = "disabled";
+ };
+
+ mdio@25520 {
+ status = "disabled";
+ };
+
+ mdio@26520 {
+ status = "disabled";
+ };
enet0: ethernet@24000 {
- #address-cells = <1>;
- #size-cells = <1>;
- cell-index = <0>;
- device_type = "network";
- model = "eTSEC";
- 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>;
fixed-link = <1 1 1000 0 0>;
phy-connection-type = "rgmii-id";
};
+ enet1: ethernet@25000 {
+ status = "disabled";
+ };
+
+ enet2: ethernet@26000 {
+ status = "disabled";
+ };
+
+ sdhci@2e000 {
+ status = "disabled";
+ };
+
+ crypto@30000 {
+ status = "disabled";
+ };
+
mpic: pic@40000 {
- interrupt-controller;
- #address-cells = <0>;
- #interrupt-cells = <2>;
- reg = <0x40000 0x40000>;
- compatible = "chrp,open-pic";
- device_type = "open-pic";
protected-sources = <
17 18 43 42 59 47 /*ecm, mem, i2c, serial0, spi,gpio */
16 20 21 22 23 28 /* L2, dma1, USB */
@@ -152,21 +185,32 @@
0xe7 0>;
interrupt-parent = <&mpic>;
};
+
+ global-utilities@e0000 { //global utilities block
+ status = "disabled";
+ };
+
};
- pci1: pcie@ffe0a000 {
- compatible = "fsl,mpc8548-pcie";
- device_type = "pci";
- #interrupt-cells = <1>;
- #size-cells = <2>;
- #address-cells = <3>;
- reg = <0 0xffe0a000 0 0x1000>;
- bus-range = <0 255>;
+ pci0: pcie@ffe08000 {
+ status = "disabled";
+ };
+
+ pci1: pcie@ffe09000 {
+ status = "disabled";
+ };
+
+ pci2: pcie@ffe0a000 {
ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000
0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
- clock-frequency = <33333333>;
- interrupt-parent = <&mpic>;
- interrupts = <26 2>;
+ interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+ interrupt-map = <
+ /* IDSEL 0x0 */
+ 0000 0x0 0x0 0x1 &mpic 0x0 0x1
+ 0000 0x0 0x0 0x2 &mpic 0x1 0x1
+ 0000 0x0 0x0 0x3 &mpic 0x2 0x1
+ 0000 0x0 0x0 0x4 &mpic 0x3 0x1
+ >;
pcie@0 {
reg = <0x0 0x0 0x0 0x0 0x0>;
#size-cells = <2>;
diff --git a/arch/powerpc/boot/dts/p2020si.dtsi b/arch/powerpc/boot/dts/p2020si.dtsi
new file mode 100644
index 000000000000..6def17f265d3
--- /dev/null
+++ b/arch/powerpc/boot/dts/p2020si.dtsi
@@ -0,0 +1,382 @@
+/*
+ * P2020 Device Tree Source
+ *
+ * Copyright 2011 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/;
+/ {
+ compatible = "fsl,P2020";
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,P2020@0 {
+ device_type = "cpu";
+ reg = <0x0>;
+ next-level-cache = <&L2>;
+ };
+
+ PowerPC,P2020@1 {
+ device_type = "cpu";
+ reg = <0x1>;
+ next-level-cache = <&L2>;
+ };
+ };
+
+ localbus@ffe05000 {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ compatible = "fsl,p2020-elbc", "fsl,elbc", "simple-bus";
+ reg = <0 0xffe05000 0 0x1000>;
+ interrupts = <19 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ soc@ffe00000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ device_type = "soc";
+ compatible = "fsl,p2020-immr", "simple-bus";
+ ranges = <0x0 0x0 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,p2020-ecm", "fsl,ecm";
+ reg = <0x1000 0x1000>;
+ interrupts = <17 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ memory-controller@2000 {
+ compatible = "fsl,p2020-memory-controller";
+ reg = <0x2000 0x1000>;
+ interrupt-parent = <&mpic>;
+ interrupts = <18 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;
+ };
+
+ i2c@3100 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cell-index = <1>;
+ compatible = "fsl-i2c";
+ reg = <0x3100 0x100>;
+ interrupts = <43 2>;
+ interrupt-parent = <&mpic>;
+ dfsrr;
+ };
+
+ serial0: serial@4500 {
+ cell-index = <0>;
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0x4500 0x100>;
+ clock-frequency = <0>;
+ interrupts = <42 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ serial1: serial@4600 {
+ cell-index = <1>;
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0x4600 0x100>;
+ clock-frequency = <0>;
+ interrupts = <42 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ spi@7000 {
+ cell-index = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,espi";
+ reg = <0x7000 0x1000>;
+ interrupts = <59 0x2>;
+ interrupt-parent = <&mpic>;
+ mode = "cpu";
+ };
+
+ dma@c300 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,eloplus-dma";
+ reg = <0xc300 0x4>;
+ ranges = <0x0 0xc100 0x200>;
+ cell-index = <1>;
+ dma-channel@0 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x0 0x80>;
+ cell-index = <0>;
+ interrupt-parent = <&mpic>;
+ interrupts = <76 2>;
+ };
+ dma-channel@80 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x80 0x80>;
+ cell-index = <1>;
+ interrupt-parent = <&mpic>;
+ interrupts = <77 2>;
+ };
+ dma-channel@100 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x100 0x80>;
+ cell-index = <2>;
+ interrupt-parent = <&mpic>;
+ interrupts = <78 2>;
+ };
+ dma-channel@180 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x180 0x80>;
+ cell-index = <3>;
+ interrupt-parent = <&mpic>;
+ interrupts = <79 2>;
+ };
+ };
+
+ gpio: gpio-controller@f000 {
+ #gpio-cells = <2>;
+ compatible = "fsl,mpc8572-gpio";
+ reg = <0xf000 0x100>;
+ interrupts = <47 0x2>;
+ interrupt-parent = <&mpic>;
+ gpio-controller;
+ };
+
+ L2: l2-cache-controller@20000 {
+ compatible = "fsl,p2020-l2-cache-controller";
+ reg = <0x20000 0x1000>;
+ cache-line-size = <32>; // 32 bytes
+ cache-size = <0x80000>; // L2,512K
+ interrupt-parent = <&mpic>;
+ 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>;
+ interrupt-parent = <&mpic>;
+ interrupts = <20 2>;
+ };
+ dma-channel@80 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x80 0x80>;
+ cell-index = <1>;
+ interrupt-parent = <&mpic>;
+ interrupts = <21 2>;
+ };
+ dma-channel@100 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x100 0x80>;
+ cell-index = <2>;
+ interrupt-parent = <&mpic>;
+ interrupts = <22 2>;
+ };
+ dma-channel@180 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x180 0x80>;
+ cell-index = <3>;
+ interrupt-parent = <&mpic>;
+ interrupts = <23 2>;
+ };
+ };
+
+ usb@22000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl-usb2-dr";
+ reg = <0x22000 0x1000>;
+ interrupt-parent = <&mpic>;
+ interrupts = <28 0x2>;
+ };
+
+ mdio@24520 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,gianfar-mdio";
+ reg = <0x24520 0x20>;
+ };
+
+ mdio@25520 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,gianfar-tbi";
+ reg = <0x26520 0x20>;
+ };
+
+ mdio@26520 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,gianfar-tbi";
+ reg = <0x520 0x20>;
+ };
+
+ enet0: ethernet@24000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ cell-index = <0>;
+ device_type = "network";
+ model = "eTSEC";
+ 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>;
+ };
+
+ 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 2 36 2 40 2>;
+ interrupt-parent = <&mpic>;
+
+ };
+
+ enet2: ethernet@26000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ cell-index = <2>;
+ device_type = "network";
+ model = "eTSEC";
+ compatible = "gianfar";
+ reg = <0x26000 0x1000>;
+ ranges = <0x0 0x26000 0x1000>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <31 2 32 2 33 2>;
+ interrupt-parent = <&mpic>;
+
+ };
+
+ sdhci@2e000 {
+ compatible = "fsl,p2020-esdhc", "fsl,esdhc";
+ reg = <0x2e000 0x1000>;
+ interrupts = <72 0x2>;
+ interrupt-parent = <&mpic>;
+ /* Filled in by U-Boot */
+ clock-frequency = <0>;
+ };
+
+ crypto@30000 {
+ compatible = "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>;
+ interrupt-parent = <&mpic>;
+ fsl,num-channels = <4>;
+ fsl,channel-fifo-len = <24>;
+ fsl,exec-units-mask = <0xbfe>;
+ fsl,descriptor-types-mask = <0x3ab0ebf>;
+ };
+
+ 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,p2020-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>;
+ interrupt-parent = <&mpic>;
+ };
+
+ global-utilities@e0000 { //global utilities block
+ compatible = "fsl,p2020-guts";
+ reg = <0xe0000 0x1000>;
+ fsl,has-rstcr;
+ };
+ };
+
+ pci0: pcie@ffe08000 {
+ compatible = "fsl,mpc8548-pcie";
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = <0 0xffe08000 0 0x1000>;
+ bus-range = <0 255>;
+ clock-frequency = <33333333>;
+ interrupt-parent = <&mpic>;
+ interrupts = <24 2>;
+ };
+
+ pci1: pcie@ffe09000 {
+ compatible = "fsl,mpc8548-pcie";
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = <0 0xffe09000 0 0x1000>;
+ bus-range = <0 255>;
+ clock-frequency = <33333333>;
+ interrupt-parent = <&mpic>;
+ interrupts = <25 2>;
+ };
+
+ pci2: pcie@ffe0a000 {
+ compatible = "fsl,mpc8548-pcie";
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = <0 0xffe0a000 0 0x1000>;
+ bus-range = <0 255>;
+ clock-frequency = <33333333>;
+ interrupt-parent = <&mpic>;
+ interrupts = <26 2>;
+ };
+};
diff --git a/arch/powerpc/boot/dts/p4080ds.dts b/arch/powerpc/boot/dts/p4080ds.dts
index 5b7fc29dd6cf..927f94d16e9b 100644
--- a/arch/powerpc/boot/dts/p4080ds.dts
+++ b/arch/powerpc/boot/dts/p4080ds.dts
@@ -1,7 +1,7 @@
/*
* P4080DS Device Tree Source
*
- * Copyright 2009 Freescale Semiconductor Inc.
+ * Copyright 2009-2011 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
@@ -33,6 +33,17 @@
dma1 = &dma1;
sdhc = &sdhc;
+ crypto = &crypto;
+ sec_jr0 = &sec_jr0;
+ sec_jr1 = &sec_jr1;
+ sec_jr2 = &sec_jr2;
+ sec_jr3 = &sec_jr3;
+ rtic_a = &rtic_a;
+ rtic_b = &rtic_b;
+ rtic_c = &rtic_c;
+ rtic_d = &rtic_d;
+ sec_mon = &sec_mon;
+
rio0 = &rapidio0;
};
@@ -410,6 +421,79 @@
dr_mode = "host";
phy_type = "ulpi";
};
+
+ crypto: crypto@300000 {
+ compatible = "fsl,sec-v4.0";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x300000 0x10000>;
+ ranges = <0 0x300000 0x10000>;
+ interrupt-parent = <&mpic>;
+ interrupts = <92 2>;
+
+ sec_jr0: jr@1000 {
+ compatible = "fsl,sec-v4.0-job-ring";
+ reg = <0x1000 0x1000>;
+ interrupt-parent = <&mpic>;
+ interrupts = <88 2>;
+ };
+
+ sec_jr1: jr@2000 {
+ compatible = "fsl,sec-v4.0-job-ring";
+ reg = <0x2000 0x1000>;
+ interrupt-parent = <&mpic>;
+ interrupts = <89 2>;
+ };
+
+ sec_jr2: jr@3000 {
+ compatible = "fsl,sec-v4.0-job-ring";
+ reg = <0x3000 0x1000>;
+ interrupt-parent = <&mpic>;
+ interrupts = <90 2>;
+ };
+
+ sec_jr3: jr@4000 {
+ compatible = "fsl,sec-v4.0-job-ring";
+ reg = <0x4000 0x1000>;
+ interrupt-parent = <&mpic>;
+ interrupts = <91 2>;
+ };
+
+ rtic@6000 {
+ compatible = "fsl,sec-v4.0-rtic";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x6000 0x100>;
+ ranges = <0x0 0x6100 0xe00>;
+
+ rtic_a: rtic-a@0 {
+ compatible = "fsl,sec-v4.0-rtic-memory";
+ reg = <0x00 0x20 0x100 0x80>;
+ };
+
+ rtic_b: rtic-b@20 {
+ compatible = "fsl,sec-v4.0-rtic-memory";
+ reg = <0x20 0x20 0x200 0x80>;
+ };
+
+ rtic_c: rtic-c@40 {
+ compatible = "fsl,sec-v4.0-rtic-memory";
+ reg = <0x40 0x20 0x300 0x80>;
+ };
+
+ rtic_d: rtic-d@60 {
+ compatible = "fsl,sec-v4.0-rtic-memory";
+ reg = <0x60 0x20 0x500 0x80>;
+ };
+ };
+ };
+
+ sec_mon: sec_mon@314000 {
+ compatible = "fsl,sec-v4.0-mon";
+ reg = <0x314000 0x1000>;
+ interrupt-parent = <&mpic>;
+ interrupts = <93 2>;
+ };
};
rapidio0: rapidio@ffe0c0000 {
diff --git a/arch/powerpc/boot/dts/redwood.dts b/arch/powerpc/boot/dts/redwood.dts
index 81636c01d906..d86a3a498118 100644
--- a/arch/powerpc/boot/dts/redwood.dts
+++ b/arch/powerpc/boot/dts/redwood.dts
@@ -358,8 +358,28 @@
0x0 0x0 0x0 0x4 &UIC3 0xb 0x4 /* swizzled int D */>;
};
+ MSI: ppc4xx-msi@400300000 {
+ compatible = "amcc,ppc4xx-msi", "ppc4xx-msi";
+ reg = < 0x4 0x00300000 0x100
+ 0x4 0x00300000 0x100>;
+ sdr-base = <0x3B0>;
+ msi-data = <0x00000000>;
+ msi-mask = <0x44440000>;
+ interrupt-count = <3>;
+ interrupts =<0 1 2 3>;
+ interrupt-parent = <&UIC0>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = <0 &UIC0 0xC 1
+ 1 &UIC0 0x0D 1
+ 2 &UIC0 0x0E 1
+ 3 &UIC0 0x0F 1>;
+ };
+
};
+
chosen {
linux,stdout-path = "/plb/opb/serial@ef600200";
};
diff --git a/arch/powerpc/boot/epapr.c b/arch/powerpc/boot/epapr.c
new file mode 100644
index 000000000000..06c1961bd124
--- /dev/null
+++ b/arch/powerpc/boot/epapr.c
@@ -0,0 +1,66 @@
+/*
+ * Bootwrapper for ePAPR compliant firmwares
+ *
+ * Copyright 2010 David Gibson <david@gibson.dropbear.id.au>, IBM Corporation.
+ *
+ * Based on earlier bootwrappers by:
+ * (c) Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp,\
+ * and
+ * Scott Wood <scottwood@freescale.com>
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include "ops.h"
+#include "stdio.h"
+#include "io.h"
+#include <libfdt.h>
+
+BSS_STACK(4096);
+
+#define EPAPR_SMAGIC 0x65504150
+#define EPAPR_EMAGIC 0x45504150
+
+static unsigned epapr_magic;
+static unsigned long ima_size;
+static unsigned long fdt_addr;
+
+static void platform_fixups(void)
+{
+ if ((epapr_magic != EPAPR_EMAGIC)
+ && (epapr_magic != EPAPR_SMAGIC))
+ fatal("r6 contained 0x%08x instead of ePAPR magic number\n",
+ epapr_magic);
+
+ if (ima_size < (unsigned long)_end)
+ printf("WARNING: Image loaded outside IMA!"
+ " (_end=%p, ima_size=0x%lx)\n", _end, ima_size);
+ if (ima_size < fdt_addr)
+ printf("WARNING: Device tree address is outside IMA!"
+ "(fdt_addr=0x%lx, ima_size=0x%lx)\n", fdt_addr,
+ ima_size);
+ if (ima_size < fdt_addr + fdt_totalsize((void *)fdt_addr))
+ printf("WARNING: Device tree extends outside IMA!"
+ " (fdt_addr=0x%lx, size=0x%x, ima_size=0x%lx\n",
+ fdt_addr, fdt_totalsize((void *)fdt_addr), ima_size);
+}
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7)
+{
+ epapr_magic = r6;
+ ima_size = r7;
+ fdt_addr = r3;
+
+ /* FIXME: we should process reserve entries */
+
+ simple_alloc_init(_end, ima_size - (unsigned long)_end, 32, 64);
+
+ fdt_init((void *)fdt_addr);
+
+ serial_console_init();
+ platform_ops.fixups = platform_fixups;
+}
diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper
index cb97e7511d7e..c74531af72c0 100755
--- a/arch/powerpc/boot/wrapper
+++ b/arch/powerpc/boot/wrapper
@@ -39,6 +39,7 @@ dts=
cacheit=
binary=
gzip=.gz
+pie=
# cross-compilation prefix
CROSS=
@@ -157,9 +158,10 @@ pmac|chrp)
platformo=$object/of.o
;;
coff)
- platformo=$object/of.o
+ platformo="$object/crt0.o $object/of.o"
lds=$object/zImage.coff.lds
link_address='0x500000'
+ pie=
;;
miboot|uboot)
# miboot and U-boot want just the bare bits, not an ELF binary
@@ -208,6 +210,7 @@ ps3)
ksection=.kernel:vmlinux.bin
isection=.kernel:initrd
link_address=''
+ pie=
;;
ep88xc|ep405|ep8248e)
platformo="$object/fixed-head.o $object/$platform.o"
@@ -244,6 +247,10 @@ gamecube|wii)
treeboot-iss4xx-mpic)
platformo="$object/treeboot-iss4xx.o"
;;
+epapr)
+ link_address='0x20000000'
+ pie=-pie
+ ;;
esac
vmz="$tmpdir/`basename \"$kernel\"`.$ext"
@@ -251,7 +258,7 @@ if [ -z "$cacheit" -o ! -f "$vmz$gzip" -o "$vmz$gzip" -ot "$kernel" ]; then
${CROSS}objcopy $objflags "$kernel" "$vmz.$$"
if [ -n "$gzip" ]; then
- gzip -f -9 "$vmz.$$"
+ gzip -n -f -9 "$vmz.$$"
fi
if [ -n "$cacheit" ]; then
@@ -310,9 +317,9 @@ fi
if [ "$platform" != "miboot" ]; then
if [ -n "$link_address" ] ; then
- text_start="-Ttext $link_address --defsym _start=$link_address"
+ text_start="-Ttext $link_address"
fi
- ${CROSS}ld -m elf32ppc -T $lds $text_start -o "$ofile" \
+ ${CROSS}ld -m elf32ppc -T $lds $text_start $pie -o "$ofile" \
$platformo $tmp $object/wrapper.a
rm $tmp
fi
@@ -336,7 +343,7 @@ coff)
$objbin/hack-coff "$ofile"
;;
cuboot*)
- gzip -f -9 "$ofile"
+ gzip -n -f -9 "$ofile"
${MKIMAGE} -A ppc -O linux -T kernel -C gzip -a "$base" -e "$entry" \
$uboot_version -d "$ofile".gz "$ofile"
;;
@@ -383,6 +390,6 @@ ps3)
odir="$(dirname "$ofile.bin")"
rm -f "$odir/otheros.bld"
- gzip --force -9 --stdout "$ofile.bin" > "$odir/otheros.bld"
+ gzip -n --force -9 --stdout "$ofile.bin" > "$odir/otheros.bld"
;;
esac
diff --git a/arch/powerpc/boot/zImage.coff.lds.S b/arch/powerpc/boot/zImage.coff.lds.S
index 856dc78b14ef..de4c9e3c9344 100644
--- a/arch/powerpc/boot/zImage.coff.lds.S
+++ b/arch/powerpc/boot/zImage.coff.lds.S
@@ -3,13 +3,13 @@ ENTRY(_zimage_start_opd)
EXTERN(_zimage_start_opd)
SECTIONS
{
- _start = .;
.text :
{
+ _start = .;
*(.text)
*(.fixup)
+ _etext = .;
}
- _etext = .;
. = ALIGN(4096);
.data :
{
@@ -17,9 +17,7 @@ SECTIONS
*(.data*)
*(__builtin_*)
*(.sdata*)
- __got2_start = .;
*(.got2)
- __got2_end = .;
_dtb_start = .;
*(.kernel:dtb)
diff --git a/arch/powerpc/boot/zImage.lds.S b/arch/powerpc/boot/zImage.lds.S
index 0962d62bdb50..2bd8731f1365 100644
--- a/arch/powerpc/boot/zImage.lds.S
+++ b/arch/powerpc/boot/zImage.lds.S
@@ -3,49 +3,64 @@ ENTRY(_zimage_start)
EXTERN(_zimage_start)
SECTIONS
{
- _start = .;
.text :
{
+ _start = .;
*(.text)
*(.fixup)
+ _etext = .;
}
- _etext = .;
. = ALIGN(4096);
.data :
{
*(.rodata*)
*(.data*)
*(.sdata*)
- __got2_start = .;
*(.got2)
- __got2_end = .;
}
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .dynamic :
+ {
+ __dynamic_start = .;
+ *(.dynamic)
+ }
+ .hash : { *(.hash) }
+ .interp : { *(.interp) }
+ .rela.dyn : { *(.rela*) }
. = ALIGN(8);
- _dtb_start = .;
- .kernel:dtb : { *(.kernel:dtb) }
- _dtb_end = .;
-
- . = ALIGN(4096);
- _vmlinux_start = .;
- .kernel:vmlinux.strip : { *(.kernel:vmlinux.strip) }
- _vmlinux_end = .;
+ .kernel:dtb :
+ {
+ _dtb_start = .;
+ *(.kernel:dtb)
+ _dtb_end = .;
+ }
. = ALIGN(4096);
- _initrd_start = .;
- .kernel:initrd : { *(.kernel:initrd) }
- _initrd_end = .;
+ .kernel:vmlinux.strip :
+ {
+ _vmlinux_start = .;
+ *(.kernel:vmlinux.strip)
+ _vmlinux_end = .;
+ }
. = ALIGN(4096);
- _edata = .;
+ .kernel:initrd :
+ {
+ _initrd_start = .;
+ *(.kernel:initrd)
+ _initrd_end = .;
+ }
. = ALIGN(4096);
- __bss_start = .;
.bss :
{
- *(.sbss)
- *(.bss)
+ _edata = .;
+ __bss_start = .;
+ *(.sbss)
+ *(.bss)
+ *(COMMON)
+ _end = . ;
}
- . = ALIGN(4096);
- _end = . ;
}
diff --git a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig
index c683bce4c26e..126ef1b08a01 100644
--- a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig
+++ b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig
@@ -104,7 +104,6 @@ CONFIG_ROOT_NFS=y
CONFIG_PARTITION_ADVANCED=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DETECT_HUNG_TASK=y
-# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_SYSCTL_SYSCALL_CHECK=y
CONFIG_CRYPTO_PCBC=m
diff --git a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig
index a721cd3d793f..abcf00ad939e 100644
--- a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig
+++ b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig
@@ -101,7 +101,6 @@ CONFIG_ROOT_NFS=y
CONFIG_PARTITION_ADVANCED=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DETECT_HUNG_TASK=y
-# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_SYSCTL_SYSCALL_CHECK=y
CONFIG_CRYPTO_PCBC=m
diff --git a/arch/powerpc/configs/85xx/mpc8540_ads_defconfig b/arch/powerpc/configs/85xx/mpc8540_ads_defconfig
index 55e0725500dc..11662c217ac0 100644
--- a/arch/powerpc/configs/85xx/mpc8540_ads_defconfig
+++ b/arch/powerpc/configs/85xx/mpc8540_ads_defconfig
@@ -58,7 +58,6 @@ CONFIG_PARTITION_ADVANCED=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DETECT_HUNG_TASK=y
CONFIG_DEBUG_MUTEXES=y
-# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_SYSCTL_SYSCALL_CHECK=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/powerpc/configs/85xx/mpc8560_ads_defconfig b/arch/powerpc/configs/85xx/mpc8560_ads_defconfig
index d724095530a6..ebe9b30b0721 100644
--- a/arch/powerpc/configs/85xx/mpc8560_ads_defconfig
+++ b/arch/powerpc/configs/85xx/mpc8560_ads_defconfig
@@ -59,7 +59,6 @@ CONFIG_PARTITION_ADVANCED=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DETECT_HUNG_TASK=y
CONFIG_DEBUG_MUTEXES=y
-# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_SYSCTL_SYSCALL_CHECK=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig b/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig
index 4b44beaa21ae..eb25229b387a 100644
--- a/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig
+++ b/arch/powerpc/configs/85xx/mpc85xx_cds_defconfig
@@ -63,7 +63,6 @@ CONFIG_PARTITION_ADVANCED=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DETECT_HUNG_TASK=y
CONFIG_DEBUG_MUTEXES=y
-# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_SYSCTL_SYSCALL_CHECK=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig b/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig
index b614508d6fd2..f51c7ebc181e 100644
--- a/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig
+++ b/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig
@@ -168,7 +168,6 @@ CONFIG_MAC_PARTITION=y
CONFIG_CRC_T10DIF=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DETECT_HUNG_TASK=y
-# CONFIG_DEBUG_BUGVERBOSE is not set
CONFIG_DEBUG_INFO=y
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_SYSCTL_SYSCALL_CHECK=y
diff --git a/arch/powerpc/configs/c2k_defconfig b/arch/powerpc/configs/c2k_defconfig
index f9e6a3ea5a64..2a84fd7f631c 100644
--- a/arch/powerpc/configs/c2k_defconfig
+++ b/arch/powerpc/configs/c2k_defconfig
@@ -132,8 +132,8 @@ CONFIG_NET_CLS_RSVP=m
CONFIG_NET_CLS_RSVP6=m
CONFIG_NET_CLS_IND=y
CONFIG_BT=m
-CONFIG_BT_L2CAP=m
-CONFIG_BT_SCO=m
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
CONFIG_BT_RFCOMM=m
CONFIG_BT_RFCOMM_TTY=y
CONFIG_BT_BNEP=m
diff --git a/arch/powerpc/configs/e55xx_smp_defconfig b/arch/powerpc/configs/e55xx_smp_defconfig
index 9fa1613e5e2b..d32283555b53 100644
--- a/arch/powerpc/configs/e55xx_smp_defconfig
+++ b/arch/powerpc/configs/e55xx_smp_defconfig
@@ -6,10 +6,10 @@ CONFIG_NR_CPUS=2
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_SPARSE_IRQ=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED_V2=y
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_EXPERT=y
@@ -25,8 +25,32 @@ CONFIG_P5020_DS=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_BINFMT_MISC=m
-CONFIG_SPARSE_IRQ=y
# CONFIG_PCI is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_ARPD=y
+CONFIG_INET_ESP=y
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_IPV6=y
+CONFIG_IP_SCTP=m
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_PROC_DEVICETREE=y
CONFIG_BLK_DEV_LOOP=y
@@ -34,6 +58,9 @@ CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=131072
CONFIG_MISC_DEVICES=y
CONFIG_EEPROM_LEGACY=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+CONFIG_NET_ETHERNET=y
CONFIG_INPUT_FF_MEMLESS=m
# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_KEYBOARD is not set
@@ -64,22 +91,14 @@ CONFIG_NLS=y
CONFIG_NLS_UTF8=m
CONFIG_CRC_T10DIF=y
CONFIG_CRC_ITU_T=m
-CONFIG_LIBCRC32C=m
CONFIG_FRAME_WARN=1024
CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DETECT_HUNG_TASK=y
-# CONFIG_DEBUG_BUGVERBOSE is not set
CONFIG_DEBUG_INFO=y
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_SYSCTL_SYSCALL_CHECK=y
CONFIG_VIRQ_DEBUG=y
-CONFIG_CRYPTO=y
-CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_SHA1=m
-CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
CONFIG_CRYPTO_DEV_TALITOS=y
diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig
index c06a86c33098..96b89df7752a 100644
--- a/arch/powerpc/configs/mpc85xx_defconfig
+++ b/arch/powerpc/configs/mpc85xx_defconfig
@@ -204,7 +204,6 @@ CONFIG_CRC_T10DIF=y
CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DETECT_HUNG_TASK=y
-# CONFIG_DEBUG_BUGVERBOSE is not set
CONFIG_DEBUG_INFO=y
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_SYSCTL_SYSCALL_CHECK=y
diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig
index 942ced90557c..de65841aa04e 100644
--- a/arch/powerpc/configs/mpc85xx_smp_defconfig
+++ b/arch/powerpc/configs/mpc85xx_smp_defconfig
@@ -206,7 +206,6 @@ CONFIG_CRC_T10DIF=y
CONFIG_DEBUG_FS=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DETECT_HUNG_TASK=y
-# CONFIG_DEBUG_BUGVERBOSE is not set
CONFIG_DEBUG_INFO=y
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_SYSCTL_SYSCALL_CHECK=y
diff --git a/arch/powerpc/configs/mpc86xx_defconfig b/arch/powerpc/configs/mpc86xx_defconfig
index 038a308cbfc4..a1cc8179e9fd 100644
--- a/arch/powerpc/configs/mpc86xx_defconfig
+++ b/arch/powerpc/configs/mpc86xx_defconfig
@@ -171,7 +171,6 @@ CONFIG_MAC_PARTITION=y
CONFIG_CRC_T10DIF=y
CONFIG_DEBUG_KERNEL=y
CONFIG_DETECT_HUNG_TASK=y
-# CONFIG_DEBUG_BUGVERBOSE is not set
CONFIG_DEBUG_INFO=y
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
CONFIG_SYSCTL_SYSCALL_CHECK=y
diff --git a/arch/powerpc/configs/pmac32_defconfig b/arch/powerpc/configs/pmac32_defconfig
index ac4fc41035f6..f8b394a76ac3 100644
--- a/arch/powerpc/configs/pmac32_defconfig
+++ b/arch/powerpc/configs/pmac32_defconfig
@@ -112,8 +112,8 @@ CONFIG_IRDA_CACHE_LAST_LSAP=y
CONFIG_IRDA_FAST_RR=y
CONFIG_IRTTY_SIR=m
CONFIG_BT=m
-CONFIG_BT_L2CAP=m
-CONFIG_BT_SCO=m
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
CONFIG_BT_RFCOMM=m
CONFIG_BT_RFCOMM_TTY=y
CONFIG_BT_BNEP=m
diff --git a/arch/powerpc/configs/ppc6xx_defconfig b/arch/powerpc/configs/ppc6xx_defconfig
index 0a10fb009ef7..04360f9b0109 100644
--- a/arch/powerpc/configs/ppc6xx_defconfig
+++ b/arch/powerpc/configs/ppc6xx_defconfig
@@ -10,7 +10,6 @@ CONFIG_TASK_XACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_AUDIT=y
CONFIG_CGROUPS=y
-CONFIG_CGROUP_NS=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_RESOURCE_COUNTERS=y
@@ -351,8 +350,8 @@ CONFIG_VLSI_FIR=m
CONFIG_VIA_FIR=m
CONFIG_MCS_FIR=m
CONFIG_BT=m
-CONFIG_BT_L2CAP=m
-CONFIG_BT_SCO=m
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
CONFIG_BT_RFCOMM=m
CONFIG_BT_RFCOMM_TTY=y
CONFIG_BT_BNEP=m
diff --git a/arch/powerpc/configs/ps3_defconfig b/arch/powerpc/configs/ps3_defconfig
index caba919f65d8..6472322bf13b 100644
--- a/arch/powerpc/configs/ps3_defconfig
+++ b/arch/powerpc/configs/ps3_defconfig
@@ -52,8 +52,8 @@ CONFIG_IP_PNP_DHCP=y
# CONFIG_INET_DIAG is not set
CONFIG_IPV6=y
CONFIG_BT=m
-CONFIG_BT_L2CAP=m
-CONFIG_BT_SCO=m
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
CONFIG_BT_RFCOMM=m
CONFIG_BT_RFCOMM_TTY=y
CONFIG_BT_BNEP=m
diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig
index 249ddd0a27cd..c9f212b5f3de 100644
--- a/arch/powerpc/configs/pseries_defconfig
+++ b/arch/powerpc/configs/pseries_defconfig
@@ -15,7 +15,6 @@ CONFIG_AUDITSYSCALL=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_CGROUPS=y
-CONFIG_CGROUP_NS=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CPUSETS=y
@@ -146,12 +145,18 @@ CONFIG_SCSI_MULTI_LUN=y
CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_FC_ATTRS=y
CONFIG_SCSI_SAS_ATTRS=m
+CONFIG_SCSI_CXGB3_ISCSI=m
+CONFIG_SCSI_CXGB4_ISCSI=m
+CONFIG_SCSI_BNX2_ISCSI=m
+CONFIG_SCSI_BNX2_ISCSI=m
+CONFIG_BE2ISCSI=m
CONFIG_SCSI_IBMVSCSI=y
CONFIG_SCSI_IBMVFC=m
CONFIG_SCSI_SYM53C8XX_2=y
CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
CONFIG_SCSI_IPR=y
CONFIG_SCSI_QLA_FC=m
+CONFIG_SCSI_QLA_ISCSI=m
CONFIG_SCSI_LPFC=m
CONFIG_ATA=y
# CONFIG_ATA_SFF is not set
@@ -197,6 +202,8 @@ CONFIG_S2IO=m
CONFIG_MYRI10GE=m
CONFIG_NETXEN_NIC=m
CONFIG_MLX4_EN=m
+CONFIG_QLGE=m
+CONFIG_BE2NET=m
CONFIG_PPP=m
CONFIG_PPP_ASYNC=m
CONFIG_PPP_SYNC_TTY=m
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index 1833d1a07e79..c0d842cfd012 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -157,6 +157,7 @@ extern const char *powerpc_base_platform;
#define CPU_FTR_476_DD2 ASM_CONST(0x0000000000010000)
#define CPU_FTR_NEED_COHERENT ASM_CONST(0x0000000000020000)
#define CPU_FTR_NO_BTIC ASM_CONST(0x0000000000040000)
+#define CPU_FTR_DEBUG_LVL_EXC ASM_CONST(0x0000000000080000)
#define CPU_FTR_NODSISRALIGN ASM_CONST(0x0000000000100000)
#define CPU_FTR_PPC_LE ASM_CONST(0x0000000000200000)
#define CPU_FTR_REAL_LE ASM_CONST(0x0000000000400000)
@@ -178,22 +179,18 @@ extern const char *powerpc_base_platform;
#define LONG_ASM_CONST(x) 0
#endif
-#define CPU_FTR_SLB LONG_ASM_CONST(0x0000000100000000)
-#define CPU_FTR_16M_PAGE LONG_ASM_CONST(0x0000000200000000)
-#define CPU_FTR_TLBIEL LONG_ASM_CONST(0x0000000400000000)
+
+#define CPU_FTR_HVMODE_206 LONG_ASM_CONST(0x0000000800000000)
+#define CPU_FTR_CFAR LONG_ASM_CONST(0x0000001000000000)
#define CPU_FTR_IABR LONG_ASM_CONST(0x0000002000000000)
#define CPU_FTR_MMCRA LONG_ASM_CONST(0x0000004000000000)
#define CPU_FTR_CTRL LONG_ASM_CONST(0x0000008000000000)
#define CPU_FTR_SMT LONG_ASM_CONST(0x0000010000000000)
-#define CPU_FTR_LOCKLESS_TLBIE LONG_ASM_CONST(0x0000040000000000)
-#define CPU_FTR_CI_LARGE_PAGE LONG_ASM_CONST(0x0000100000000000)
#define CPU_FTR_PAUSE_ZERO LONG_ASM_CONST(0x0000200000000000)
#define CPU_FTR_PURR LONG_ASM_CONST(0x0000400000000000)
#define CPU_FTR_CELL_TB_BUG LONG_ASM_CONST(0x0000800000000000)
#define CPU_FTR_SPURR LONG_ASM_CONST(0x0001000000000000)
#define CPU_FTR_DSCR LONG_ASM_CONST(0x0002000000000000)
-#define CPU_FTR_1T_SEGMENT LONG_ASM_CONST(0x0004000000000000)
-#define CPU_FTR_NO_SLBIE_B LONG_ASM_CONST(0x0008000000000000)
#define CPU_FTR_VSX LONG_ASM_CONST(0x0010000000000000)
#define CPU_FTR_SAO LONG_ASM_CONST(0x0020000000000000)
#define CPU_FTR_CP_USE_DCBTZ LONG_ASM_CONST(0x0040000000000000)
@@ -202,12 +199,14 @@ extern const char *powerpc_base_platform;
#define CPU_FTR_STCX_CHECKS_ADDRESS LONG_ASM_CONST(0x0200000000000000)
#define CPU_FTR_POPCNTB LONG_ASM_CONST(0x0400000000000000)
#define CPU_FTR_POPCNTD LONG_ASM_CONST(0x0800000000000000)
+#define CPU_FTR_ICSWX LONG_ASM_CONST(0x1000000000000000)
#ifndef __ASSEMBLY__
-#define CPU_FTR_PPCAS_ARCH_V2 (CPU_FTR_SLB | \
- CPU_FTR_TLBIEL | CPU_FTR_NOEXECUTE | \
- CPU_FTR_NODSISRALIGN | CPU_FTR_16M_PAGE)
+#define CPU_FTR_PPCAS_ARCH_V2 (CPU_FTR_NOEXECUTE | CPU_FTR_NODSISRALIGN)
+
+#define MMU_FTR_PPCAS_ARCH_V2 (MMU_FTR_SLB | MMU_FTR_TLBIEL | \
+ MMU_FTR_16M_PAGE)
/* We only set the altivec features if the kernel was compiled with altivec
* support
@@ -387,7 +386,8 @@ extern const char *powerpc_base_platform;
CPU_FTR_DBELL)
#define CPU_FTRS_E5500 (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | \
CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \
- CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD)
+ CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
+ CPU_FTR_DEBUG_LVL_EXC)
#define CPU_FTRS_GENERIC_32 (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN)
/* 64-bit CPUs */
@@ -407,44 +407,45 @@ extern const char *powerpc_base_platform;
#define CPU_FTRS_POWER5 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
CPU_FTR_MMCRA | CPU_FTR_SMT | \
- CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
- CPU_FTR_PURR | CPU_FTR_STCX_CHECKS_ADDRESS | \
- CPU_FTR_POPCNTB)
+ CPU_FTR_COHERENT_ICACHE | CPU_FTR_PURR | \
+ CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB)
#define CPU_FTRS_POWER6 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
CPU_FTR_MMCRA | CPU_FTR_SMT | \
- CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
+ CPU_FTR_COHERENT_ICACHE | \
CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
CPU_FTR_DSCR | CPU_FTR_UNALIGNED_LD_STD | \
- CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB)
+ CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_CFAR)
#define CPU_FTRS_POWER7 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
- CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
+ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | CPU_FTR_HVMODE_206 |\
CPU_FTR_MMCRA | CPU_FTR_SMT | \
- CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE | \
+ CPU_FTR_COHERENT_ICACHE | \
CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
CPU_FTR_DSCR | CPU_FTR_SAO | CPU_FTR_ASYM_SMT | \
- CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD)
+ CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
+ CPU_FTR_ICSWX | CPU_FTR_CFAR)
#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 | \
- CPU_FTR_PAUSE_ZERO | CPU_FTR_CI_LARGE_PAGE | \
- CPU_FTR_CELL_TB_BUG | CPU_FTR_CP_USE_DCBTZ | \
+ CPU_FTR_PAUSE_ZERO | CPU_FTR_CELL_TB_BUG | CPU_FTR_CP_USE_DCBTZ | \
CPU_FTR_UNALIGNED_LD_STD)
#define CPU_FTRS_PA6T (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
- CPU_FTR_PPCAS_ARCH_V2 | \
- CPU_FTR_ALTIVEC_COMP | CPU_FTR_CI_LARGE_PAGE | \
- CPU_FTR_PURR | CPU_FTR_REAL_LE | CPU_FTR_NO_SLBIE_B)
+ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP | \
+ CPU_FTR_PURR | CPU_FTR_REAL_LE)
#define CPU_FTRS_COMPATIBLE (CPU_FTR_USE_TB | CPU_FTR_PPCAS_ARCH_V2)
+#define CPU_FTRS_A2 (CPU_FTR_USE_TB | CPU_FTR_SMT | CPU_FTR_DBELL | \
+ CPU_FTR_NOEXECUTE | CPU_FTR_NODSISRALIGN)
+
#ifdef __powerpc64__
#ifdef CONFIG_PPC_BOOK3E
-#define CPU_FTRS_POSSIBLE (CPU_FTRS_E5500)
+#define CPU_FTRS_POSSIBLE (CPU_FTRS_E5500 | CPU_FTRS_A2)
#else
#define CPU_FTRS_POSSIBLE \
(CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 | \
CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_POWER6 | \
CPU_FTRS_POWER7 | CPU_FTRS_CELL | CPU_FTRS_PA6T | \
- CPU_FTR_1T_SEGMENT | CPU_FTR_VSX)
+ CPU_FTR_VSX)
#endif
#else
enum {
@@ -487,7 +488,7 @@ enum {
#ifdef __powerpc64__
#ifdef CONFIG_PPC_BOOK3E
-#define CPU_FTRS_ALWAYS (CPU_FTRS_E5500)
+#define CPU_FTRS_ALWAYS (CPU_FTRS_E5500 & CPU_FTRS_A2)
#else
#define CPU_FTRS_ALWAYS \
(CPU_FTRS_POWER3 & CPU_FTRS_RS64 & CPU_FTRS_POWER4 & \
diff --git a/arch/powerpc/include/asm/cputhreads.h b/arch/powerpc/include/asm/cputhreads.h
index f71bb4c118b4..ce516e5eb0d3 100644
--- a/arch/powerpc/include/asm/cputhreads.h
+++ b/arch/powerpc/include/asm/cputhreads.h
@@ -37,16 +37,16 @@ extern cpumask_t threads_core_mask;
* This can typically be used for things like IPI for tlb invalidations
* since those need to be done only once per core/TLB
*/
-static inline cpumask_t cpu_thread_mask_to_cores(cpumask_t threads)
+static inline cpumask_t cpu_thread_mask_to_cores(const struct cpumask *threads)
{
cpumask_t tmp, res;
int i;
- res = CPU_MASK_NONE;
+ cpumask_clear(&res);
for (i = 0; i < NR_CPUS; i += threads_per_core) {
- cpus_shift_left(tmp, threads_core_mask, i);
- if (cpus_intersects(threads, tmp))
- cpu_set(i, res);
+ cpumask_shift_left(&tmp, &threads_core_mask, i);
+ if (cpumask_intersects(threads, &tmp))
+ cpumask_set_cpu(i, &res);
}
return res;
}
@@ -58,7 +58,7 @@ static inline int cpu_nr_cores(void)
static inline cpumask_t cpu_online_cores_map(void)
{
- return cpu_thread_mask_to_cores(cpu_online_map);
+ return cpu_thread_mask_to_cores(cpu_online_mask);
}
#ifdef CONFIG_SMP
diff --git a/arch/powerpc/include/asm/dbell.h b/arch/powerpc/include/asm/dbell.h
index 0893ab9343a6..9c70d0ca96d4 100644
--- a/arch/powerpc/include/asm/dbell.h
+++ b/arch/powerpc/include/asm/dbell.h
@@ -27,9 +27,8 @@ enum ppc_dbell {
PPC_G_DBELL_MC = 4, /* guest mcheck doorbell */
};
-extern void doorbell_message_pass(int target, int msg);
+extern void doorbell_cause_ipi(int cpu, unsigned long data);
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/emulated_ops.h b/arch/powerpc/include/asm/emulated_ops.h
index f0fb4fc1f6e6..45921672b97a 100644
--- a/arch/powerpc/include/asm/emulated_ops.h
+++ b/arch/powerpc/include/asm/emulated_ops.h
@@ -52,6 +52,10 @@ extern struct ppc_emulated {
#ifdef CONFIG_VSX
struct ppc_emulated_entry vsx;
#endif
+#ifdef CONFIG_PPC64
+ struct ppc_emulated_entry mfdscr;
+ struct ppc_emulated_entry mtdscr;
+#endif
} ppc_emulated;
extern u32 ppc_warn_emulated;
diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h
index 7778d6f0c878..f5dfe3411f64 100644
--- a/arch/powerpc/include/asm/exception-64s.h
+++ b/arch/powerpc/include/asm/exception-64s.h
@@ -46,6 +46,7 @@
#define EX_CCR 60
#define EX_R3 64
#define EX_LR 72
+#define EX_CFAR 80
/*
* We're short on space and time in the exception prolog, so we can't
@@ -56,30 +57,40 @@
#define LOAD_HANDLER(reg, label) \
addi reg,reg,(label)-_stext; /* virt addr of handler ... */
-#define EXCEPTION_PROLOG_1(area) \
- mfspr r13,SPRN_SPRG_PACA; /* get paca address into r13 */ \
+/* Exception register prefixes */
+#define EXC_HV H
+#define EXC_STD
+
+#define EXCEPTION_PROLOG_1(area) \
+ GET_PACA(r13); \
std r9,area+EX_R9(r13); /* save r9 - r12 */ \
std r10,area+EX_R10(r13); \
std r11,area+EX_R11(r13); \
std r12,area+EX_R12(r13); \
- mfspr r9,SPRN_SPRG_SCRATCH0; \
+ BEGIN_FTR_SECTION_NESTED(66); \
+ mfspr r10,SPRN_CFAR; \
+ std r10,area+EX_CFAR(r13); \
+ END_FTR_SECTION_NESTED(CPU_FTR_CFAR, CPU_FTR_CFAR, 66); \
+ GET_SCRATCH0(r9); \
std r9,area+EX_R13(r13); \
mfcr r9
-#define EXCEPTION_PROLOG_PSERIES_1(label) \
+#define __EXCEPTION_PROLOG_PSERIES_1(label, h) \
ld r12,PACAKBASE(r13); /* get high part of &label */ \
ld r10,PACAKMSR(r13); /* get MSR value for kernel */ \
- mfspr r11,SPRN_SRR0; /* save SRR0 */ \
+ mfspr r11,SPRN_##h##SRR0; /* save SRR0 */ \
LOAD_HANDLER(r12,label) \
- mtspr SPRN_SRR0,r12; \
- mfspr r12,SPRN_SRR1; /* and SRR1 */ \
- mtspr SPRN_SRR1,r10; \
- rfid; \
+ mtspr SPRN_##h##SRR0,r12; \
+ mfspr r12,SPRN_##h##SRR1; /* and SRR1 */ \
+ mtspr SPRN_##h##SRR1,r10; \
+ h##rfid; \
b . /* prevent speculative execution */
+#define EXCEPTION_PROLOG_PSERIES_1(label, h) \
+ __EXCEPTION_PROLOG_PSERIES_1(label, h)
-#define EXCEPTION_PROLOG_PSERIES(area, label) \
+#define EXCEPTION_PROLOG_PSERIES(area, label, h) \
EXCEPTION_PROLOG_1(area); \
- EXCEPTION_PROLOG_PSERIES_1(label);
+ EXCEPTION_PROLOG_PSERIES_1(label, h);
/*
* The common exception prolog is used for all except a few exceptions
@@ -98,10 +109,11 @@
beq- 1f; \
ld r1,PACAKSAVE(r13); /* kernel stack to use */ \
1: cmpdi cr1,r1,0; /* check if r1 is in userspace */ \
- bge- cr1,2f; /* abort if it is */ \
- b 3f; \
-2: li r1,(n); /* will be reloaded later */ \
+ blt+ cr1,3f; /* abort if it is */ \
+ li r1,(n); /* will be reloaded later */ \
sth r1,PACA_TRAP_SAVE(r13); \
+ std r3,area+EX_R3(r13); \
+ addi r3,r13,area; /* r3 -> where regs are saved*/ \
b bad_stack; \
3: std r9,_CCR(r1); /* save CR in stackframe */ \
std r11,_NIP(r1); /* save SRR0 in stackframe */ \
@@ -123,6 +135,10 @@
std r9,GPR11(r1); \
std r10,GPR12(r1); \
std r11,GPR13(r1); \
+ BEGIN_FTR_SECTION_NESTED(66); \
+ ld r10,area+EX_CFAR(r13); \
+ std r10,ORIG_GPR3(r1); \
+ END_FTR_SECTION_NESTED(CPU_FTR_CFAR, CPU_FTR_CFAR, 66); \
ld r2,PACATOC(r13); /* get kernel TOC into r2 */ \
mflr r9; /* save LR in stackframe */ \
std r9,_LINK(r1); \
@@ -143,57 +159,62 @@
/*
* Exception vectors.
*/
-#define STD_EXCEPTION_PSERIES(n, label) \
- . = n; \
+#define STD_EXCEPTION_PSERIES(loc, vec, label) \
+ . = loc; \
.globl label##_pSeries; \
label##_pSeries: \
HMT_MEDIUM; \
- DO_KVM n; \
- mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \
- EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common)
+ DO_KVM vec; \
+ SET_SCRATCH0(r13); /* save r13 */ \
+ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, EXC_STD)
-#define HSTD_EXCEPTION_PSERIES(n, label) \
- . = n; \
- .globl label##_pSeries; \
-label##_pSeries: \
+#define STD_EXCEPTION_HV(loc, vec, label) \
+ . = loc; \
+ .globl label##_hv; \
+label##_hv: \
HMT_MEDIUM; \
- mtspr SPRN_SPRG_SCRATCH0,r20; /* save r20 */ \
- mfspr r20,SPRN_HSRR0; /* copy HSRR0 to SRR0 */ \
- mtspr SPRN_SRR0,r20; \
- mfspr r20,SPRN_HSRR1; /* copy HSRR0 to SRR0 */ \
- mtspr SPRN_SRR1,r20; \
- mfspr r20,SPRN_SPRG_SCRATCH0; /* restore r20 */ \
- mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \
- EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common)
+ DO_KVM vec; \
+ SET_SCRATCH0(r13); /* save r13 */ \
+ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, EXC_HV)
-
-#define MASKABLE_EXCEPTION_PSERIES(n, label) \
- . = n; \
- .globl label##_pSeries; \
-label##_pSeries: \
+#define __MASKABLE_EXCEPTION_PSERIES(vec, label, h) \
HMT_MEDIUM; \
- DO_KVM n; \
- mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \
- mfspr r13,SPRN_SPRG_PACA; /* get paca address into r13 */ \
+ DO_KVM vec; \
+ SET_SCRATCH0(r13); /* save r13 */ \
+ GET_PACA(r13); \
std r9,PACA_EXGEN+EX_R9(r13); /* save r9, r10 */ \
std r10,PACA_EXGEN+EX_R10(r13); \
lbz r10,PACASOFTIRQEN(r13); \
mfcr r9; \
cmpwi r10,0; \
- beq masked_interrupt; \
- mfspr r10,SPRN_SPRG_SCRATCH0; \
+ beq masked_##h##interrupt; \
+ GET_SCRATCH0(r10); \
std r10,PACA_EXGEN+EX_R13(r13); \
std r11,PACA_EXGEN+EX_R11(r13); \
std r12,PACA_EXGEN+EX_R12(r13); \
ld r12,PACAKBASE(r13); /* get high part of &label */ \
ld r10,PACAKMSR(r13); /* get MSR value for kernel */ \
- mfspr r11,SPRN_SRR0; /* save SRR0 */ \
+ mfspr r11,SPRN_##h##SRR0; /* save SRR0 */ \
LOAD_HANDLER(r12,label##_common) \
- mtspr SPRN_SRR0,r12; \
- mfspr r12,SPRN_SRR1; /* and SRR1 */ \
- mtspr SPRN_SRR1,r10; \
- rfid; \
+ mtspr SPRN_##h##SRR0,r12; \
+ mfspr r12,SPRN_##h##SRR1; /* and SRR1 */ \
+ mtspr SPRN_##h##SRR1,r10; \
+ h##rfid; \
b . /* prevent speculative execution */
+#define _MASKABLE_EXCEPTION_PSERIES(vec, label, h) \
+ __MASKABLE_EXCEPTION_PSERIES(vec, label, h)
+
+#define MASKABLE_EXCEPTION_PSERIES(loc, vec, label) \
+ . = loc; \
+ .globl label##_pSeries; \
+label##_pSeries: \
+ _MASKABLE_EXCEPTION_PSERIES(vec, label, EXC_STD)
+
+#define MASKABLE_EXCEPTION_HV(loc, vec, label) \
+ . = loc; \
+ .globl label##_hv; \
+label##_hv: \
+ _MASKABLE_EXCEPTION_PSERIES(vec, label, EXC_HV)
#ifdef CONFIG_PPC_ISERIES
#define DISABLE_INTS \
diff --git a/arch/powerpc/include/asm/feature-fixups.h b/arch/powerpc/include/asm/feature-fixups.h
index 921a8470e18a..9a67a38bf7b9 100644
--- a/arch/powerpc/include/asm/feature-fixups.h
+++ b/arch/powerpc/include/asm/feature-fixups.h
@@ -49,7 +49,7 @@ label##5: \
FTR_ENTRY_OFFSET label##2b-label##5b; \
FTR_ENTRY_OFFSET label##3b-label##5b; \
FTR_ENTRY_OFFSET label##4b-label##5b; \
- .ifgt (label##4b-label##3b)-(label##2b-label##1b); \
+ .ifgt (label##4b- label##3b)-(label##2b- label##1b); \
.error "Feature section else case larger than body"; \
.endif; \
.popsection;
@@ -146,6 +146,19 @@ label##5: \
#ifndef __ASSEMBLY__
+#define ASM_FTR_IF(section_if, section_else, msk, val) \
+ stringify_in_c(BEGIN_FTR_SECTION) \
+ section_if "; " \
+ stringify_in_c(FTR_SECTION_ELSE) \
+ section_else "; " \
+ stringify_in_c(ALT_FTR_SECTION_END((msk), (val)))
+
+#define ASM_FTR_IFSET(section_if, section_else, msk) \
+ ASM_FTR_IF(section_if, section_else, (msk), (msk))
+
+#define ASM_FTR_IFCLR(section_if, section_else, msk) \
+ ASM_FTR_IF(section_if, section_else, (msk), 0)
+
#define ASM_MMU_FTR_IF(section_if, section_else, msk, val) \
stringify_in_c(BEGIN_MMU_FTR_SECTION) \
section_if "; " \
diff --git a/arch/powerpc/include/asm/firmware.h b/arch/powerpc/include/asm/firmware.h
index 4ef662e4a31d..3a6c586c4e40 100644
--- a/arch/powerpc/include/asm/firmware.h
+++ b/arch/powerpc/include/asm/firmware.h
@@ -47,6 +47,7 @@
#define FW_FEATURE_BEAT ASM_CONST(0x0000000001000000)
#define FW_FEATURE_CMO ASM_CONST(0x0000000002000000)
#define FW_FEATURE_VPHN ASM_CONST(0x0000000004000000)
+#define FW_FEATURE_XCMO ASM_CONST(0x0000000008000000)
#ifndef __ASSEMBLY__
@@ -60,7 +61,7 @@ enum {
FW_FEATURE_VIO | FW_FEATURE_RDMA | FW_FEATURE_LLAN |
FW_FEATURE_BULK_REMOVE | FW_FEATURE_XDABR |
FW_FEATURE_MULTITCE | FW_FEATURE_SPLPAR | FW_FEATURE_LPAR |
- FW_FEATURE_CMO | FW_FEATURE_VPHN,
+ FW_FEATURE_CMO | FW_FEATURE_VPHN | FW_FEATURE_XCMO,
FW_FEATURE_PSERIES_ALWAYS = 0,
FW_FEATURE_ISERIES_POSSIBLE = FW_FEATURE_ISERIES | FW_FEATURE_LPAR,
FW_FEATURE_ISERIES_ALWAYS = FW_FEATURE_ISERIES | FW_FEATURE_LPAR,
diff --git a/arch/powerpc/include/asm/fsl_lbc.h b/arch/powerpc/include/asm/fsl_lbc.h
index 5c1bf3466749..8a0b5ece8f76 100644
--- a/arch/powerpc/include/asm/fsl_lbc.h
+++ b/arch/powerpc/include/asm/fsl_lbc.h
@@ -157,6 +157,8 @@ struct fsl_lbc_regs {
#define LBCR_EPAR_SHIFT 16
#define LBCR_BMT 0x0000FF00
#define LBCR_BMT_SHIFT 8
+#define LBCR_BMTPS 0x0000000F
+#define LBCR_BMTPS_SHIFT 0
#define LBCR_INIT 0x00040000
__be32 lcrr; /**< Clock Ratio Register */
#define LCRR_DBYP 0x80000000
diff --git a/arch/powerpc/include/asm/ftrace.h b/arch/powerpc/include/asm/ftrace.h
index dde1296b8b41..169d039ed402 100644
--- a/arch/powerpc/include/asm/ftrace.h
+++ b/arch/powerpc/include/asm/ftrace.h
@@ -60,4 +60,18 @@ struct dyn_arch_ftrace {
#endif
+#if defined(CONFIG_FTRACE_SYSCALLS) && defined(CONFIG_PPC64) && !defined(__ASSEMBLY__)
+#define ARCH_HAS_SYSCALL_MATCH_SYM_NAME
+static inline bool arch_syscall_match_sym_name(const char *sym, const char *name)
+{
+ /*
+ * Compare the symbol name with the system call name. Skip the .sys or .SyS
+ * prefix from the symbol name and the sys prefix from the system call name and
+ * just match the rest. This is only needed on ppc64 since symbol names on
+ * 32bit do not start with a period so the generic function will work.
+ */
+ return !strcmp(sym + 4, name + 3);
+}
+#endif /* CONFIG_FTRACE_SYSCALLS && CONFIG_PPC64 && !__ASSEMBLY__ */
+
#endif /* _ASM_POWERPC_FTRACE */
diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
index 8edec710cc6d..fd8201dddd4b 100644
--- a/arch/powerpc/include/asm/hvcall.h
+++ b/arch/powerpc/include/asm/hvcall.h
@@ -102,6 +102,7 @@
#define H_ANDCOND (1UL<<(63-33))
#define H_ICACHE_INVALIDATE (1UL<<(63-40)) /* icbi, etc. (ignored for IO pages) */
#define H_ICACHE_SYNCHRONIZE (1UL<<(63-41)) /* dcbst, icbi, etc (ignored for IO pages */
+#define H_COALESCE_CAND (1UL<<(63-42)) /* page is a good candidate for coalescing */
#define H_ZERO_PAGE (1UL<<(63-48)) /* zero the page before mapping (ignored for IO pages) */
#define H_COPY_PAGE (1UL<<(63-49))
#define H_N (1UL<<(63-61))
@@ -234,7 +235,8 @@
#define H_GET_MPP 0x2D4
#define H_HOME_NODE_ASSOCIATIVITY 0x2EC
#define H_BEST_ENERGY 0x2F4
-#define MAX_HCALL_OPCODE H_BEST_ENERGY
+#define H_GET_MPP_X 0x314
+#define MAX_HCALL_OPCODE H_GET_MPP_X
#ifndef __ASSEMBLY__
@@ -312,6 +314,16 @@ struct hvcall_mpp_data {
int h_get_mpp(struct hvcall_mpp_data *);
+struct hvcall_mpp_x_data {
+ unsigned long coalesced_bytes;
+ unsigned long pool_coalesced_bytes;
+ unsigned long pool_purr_cycles;
+ unsigned long pool_spurr_cycles;
+ unsigned long reserved[3];
+};
+
+int h_get_mpp_x(struct hvcall_mpp_x_data *mpp_x_data);
+
#ifdef CONFIG_PPC_PSERIES
extern int CMO_PrPSP;
extern int CMO_SecPSP;
diff --git a/arch/powerpc/platforms/cell/io-workarounds.h b/arch/powerpc/include/asm/io-workarounds.h
index 6efc7782ebf2..fbae49286926 100644
--- a/arch/powerpc/platforms/cell/io-workarounds.h
+++ b/arch/powerpc/include/asm/io-workarounds.h
@@ -31,7 +31,6 @@ struct iowa_bus {
void *private;
};
-void __devinit io_workaround_init(void);
void __devinit iowa_register_bus(struct pci_controller *, struct ppc_pci_io *,
int (*)(struct iowa_bus *, void *), void *);
struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR);
diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h
index 001f2f11c19b..45698d55cd6a 100644
--- a/arch/powerpc/include/asm/io.h
+++ b/arch/powerpc/include/asm/io.h
@@ -2,6 +2,8 @@
#define _ASM_POWERPC_IO_H
#ifdef __KERNEL__
+#define ARCH_HAS_IOREMAP_WC
+
/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -481,10 +483,16 @@ __do_out_asm(_rec_outl, "stwbrx")
_memcpy_fromio(dst,PCI_FIX_ADDR(src),n)
#endif /* !CONFIG_EEH */
-#ifdef CONFIG_PPC_INDIRECT_IO
-#define DEF_PCI_HOOK(x) x
+#ifdef CONFIG_PPC_INDIRECT_PIO
+#define DEF_PCI_HOOK_pio(x) x
+#else
+#define DEF_PCI_HOOK_pio(x) NULL
+#endif
+
+#ifdef CONFIG_PPC_INDIRECT_MMIO
+#define DEF_PCI_HOOK_mem(x) x
#else
-#define DEF_PCI_HOOK(x) NULL
+#define DEF_PCI_HOOK_mem(x) NULL
#endif
/* Structure containing all the hooks */
@@ -504,7 +512,7 @@ extern struct ppc_pci_io {
#define DEF_PCI_AC_RET(name, ret, at, al, space, aa) \
static inline ret name at \
{ \
- if (DEF_PCI_HOOK(ppc_pci_io.name) != NULL) \
+ if (DEF_PCI_HOOK_##space(ppc_pci_io.name) != NULL) \
return ppc_pci_io.name al; \
return __do_##name al; \
}
@@ -512,7 +520,7 @@ static inline ret name at \
#define DEF_PCI_AC_NORET(name, at, al, space, aa) \
static inline void name at \
{ \
- if (DEF_PCI_HOOK(ppc_pci_io.name) != NULL) \
+ if (DEF_PCI_HOOK_##space(ppc_pci_io.name) != NULL) \
ppc_pci_io.name al; \
else \
__do_##name al; \
@@ -616,12 +624,13 @@ static inline void iosync(void)
* * ioremap is the standard one and provides non-cacheable guarded mappings
* and can be hooked by the platform via ppc_md
*
- * * ioremap_flags allows to specify the page flags as an argument and can
- * also be hooked by the platform via ppc_md. ioremap_prot is the exact
- * same thing as ioremap_flags.
+ * * ioremap_prot allows to specify the page flags as an argument and can
+ * also be hooked by the platform via ppc_md.
*
* * ioremap_nocache is identical to ioremap
*
+ * * ioremap_wc enables write combining
+ *
* * iounmap undoes such a mapping and can be hooked
*
* * __ioremap_at (and the pending __iounmap_at) are low level functions to
@@ -629,7 +638,7 @@ static inline void iosync(void)
* currently be hooked. Must be page aligned.
*
* * __ioremap is the low level implementation used by ioremap and
- * ioremap_flags and cannot be hooked (but can be used by a hook on one
+ * ioremap_prot and cannot be hooked (but can be used by a hook on one
* of the previous ones)
*
* * __ioremap_caller is the same as above but takes an explicit caller
@@ -640,10 +649,10 @@ static inline void iosync(void)
*
*/
extern void __iomem *ioremap(phys_addr_t address, unsigned long size);
-extern void __iomem *ioremap_flags(phys_addr_t address, unsigned long size,
- unsigned long flags);
+extern void __iomem *ioremap_prot(phys_addr_t address, unsigned long size,
+ unsigned long flags);
+extern void __iomem *ioremap_wc(phys_addr_t address, unsigned long size);
#define ioremap_nocache(addr, size) ioremap((addr), (size))
-#define ioremap_prot(addr, size, prot) ioremap_flags((addr), (size), (prot))
extern void iounmap(volatile void __iomem *addr);
diff --git a/arch/powerpc/include/asm/io_event_irq.h b/arch/powerpc/include/asm/io_event_irq.h
new file mode 100644
index 000000000000..b1a9a1be3c21
--- /dev/null
+++ b/arch/powerpc/include/asm/io_event_irq.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2010, 2011 Mark Nelson and Tseng-Hui (Frank) Lin, 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.
+ */
+
+#ifndef _ASM_POWERPC_IO_EVENT_IRQ_H
+#define _ASM_POWERPC_IO_EVENT_IRQ_H
+
+#include <linux/types.h>
+#include <linux/notifier.h>
+
+#define PSERIES_IOEI_RPC_MAX_LEN 216
+
+#define PSERIES_IOEI_TYPE_ERR_DETECTED 0x01
+#define PSERIES_IOEI_TYPE_ERR_RECOVERED 0x02
+#define PSERIES_IOEI_TYPE_EVENT 0x03
+#define PSERIES_IOEI_TYPE_RPC_PASS_THRU 0x04
+
+#define PSERIES_IOEI_SUBTYPE_NOT_APP 0x00
+#define PSERIES_IOEI_SUBTYPE_REBALANCE_REQ 0x01
+#define PSERIES_IOEI_SUBTYPE_NODE_ONLINE 0x03
+#define PSERIES_IOEI_SUBTYPE_NODE_OFFLINE 0x04
+#define PSERIES_IOEI_SUBTYPE_DUMP_SIZE_CHANGE 0x05
+#define PSERIES_IOEI_SUBTYPE_TORRENT_IRV_UPDATE 0x06
+#define PSERIES_IOEI_SUBTYPE_TORRENT_HFI_CFGED 0x07
+
+#define PSERIES_IOEI_SCOPE_NOT_APP 0x00
+#define PSERIES_IOEI_SCOPE_RIO_HUB 0x36
+#define PSERIES_IOEI_SCOPE_RIO_BRIDGE 0x37
+#define PSERIES_IOEI_SCOPE_PHB 0x38
+#define PSERIES_IOEI_SCOPE_EADS_GLOBAL 0x39
+#define PSERIES_IOEI_SCOPE_EADS_SLOT 0x3A
+#define PSERIES_IOEI_SCOPE_TORRENT_HUB 0x3B
+#define PSERIES_IOEI_SCOPE_SERVICE_PROC 0x51
+
+/* Platform Event Log Format, Version 6, data portition of IO event section */
+struct pseries_io_event {
+ uint8_t event_type; /* 0x00 IO-Event Type */
+ uint8_t rpc_data_len; /* 0x01 RPC data length */
+ uint8_t scope; /* 0x02 Error/Event Scope */
+ uint8_t event_subtype; /* 0x03 I/O-Event Sub-Type */
+ uint32_t drc_index; /* 0x04 DRC Index */
+ uint8_t rpc_data[PSERIES_IOEI_RPC_MAX_LEN];
+ /* 0x08 RPC Data (0-216 bytes, */
+ /* padded to 4 bytes alignment) */
+};
+
+extern struct atomic_notifier_head pseries_ioei_notifier_list;
+
+#endif /* _ASM_POWERPC_IO_EVENT_IRQ_H */
diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h
index 67ab5fb7d153..1bff591f7f72 100644
--- a/arch/powerpc/include/asm/irq.h
+++ b/arch/powerpc/include/asm/irq.h
@@ -88,9 +88,6 @@ struct irq_host_ops {
/* Dispose of such a mapping */
void (*unmap)(struct irq_host *h, unsigned int virq);
- /* Update of such a mapping */
- void (*remap)(struct irq_host *h, unsigned int virq, irq_hw_number_t hw);
-
/* Translate device-tree interrupt specifier from raw format coming
* from the firmware to a irq_hw_number_t (interrupt line number) and
* type (sense) that can be passed to set_irq_type(). In the absence
@@ -128,19 +125,10 @@ struct irq_host {
struct device_node *of_node;
};
-/* The main irq map itself is an array of NR_IRQ entries containing the
- * associate host and irq number. An entry with a host of NULL is free.
- * An entry can be allocated if it's free, the allocator always then sets
- * hwirq first to the host's invalid irq number and then fills ops.
- */
-struct irq_map_entry {
- irq_hw_number_t hwirq;
- struct irq_host *host;
-};
-
-extern struct irq_map_entry irq_map[NR_IRQS];
-
+struct irq_data;
+extern irq_hw_number_t irqd_to_hwirq(struct irq_data *d);
extern irq_hw_number_t virq_to_hw(unsigned int virq);
+extern bool virq_is_host(unsigned int virq, struct irq_host *host);
/**
* irq_alloc_host - Allocate a new irq_host data structure
diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h
index f54408d995b5..8a33698c61bd 100644
--- a/arch/powerpc/include/asm/kexec.h
+++ b/arch/powerpc/include/asm/kexec.h
@@ -76,7 +76,7 @@ extern void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *));
extern cpumask_t cpus_in_sr;
static inline int kexec_sr_activated(int cpu)
{
- return cpu_isset(cpu,cpus_in_sr);
+ return cpumask_test_cpu(cpu, &cpus_in_sr);
}
struct kimage;
diff --git a/arch/powerpc/include/asm/kvm.h b/arch/powerpc/include/asm/kvm.h
index 18ea6963ad77..d2ca5ed3877b 100644
--- a/arch/powerpc/include/asm/kvm.h
+++ b/arch/powerpc/include/asm/kvm.h
@@ -45,6 +45,114 @@ struct kvm_regs {
__u64 gpr[32];
};
+#define KVM_SREGS_E_IMPL_NONE 0
+#define KVM_SREGS_E_IMPL_FSL 1
+
+#define KVM_SREGS_E_FSL_PIDn (1 << 0) /* PID1/PID2 */
+
+/*
+ * Feature bits indicate which sections of the sregs struct are valid,
+ * both in KVM_GET_SREGS and KVM_SET_SREGS. On KVM_SET_SREGS, registers
+ * corresponding to unset feature bits will not be modified. This allows
+ * restoring a checkpoint made without that feature, while keeping the
+ * default values of the new registers.
+ *
+ * KVM_SREGS_E_BASE contains:
+ * CSRR0/1 (refers to SRR2/3 on 40x)
+ * ESR
+ * DEAR
+ * MCSR
+ * TSR
+ * TCR
+ * DEC
+ * TB
+ * VRSAVE (USPRG0)
+ */
+#define KVM_SREGS_E_BASE (1 << 0)
+
+/*
+ * KVM_SREGS_E_ARCH206 contains:
+ *
+ * PIR
+ * MCSRR0/1
+ * DECAR
+ * IVPR
+ */
+#define KVM_SREGS_E_ARCH206 (1 << 1)
+
+/*
+ * Contains EPCR, plus the upper half of 64-bit registers
+ * that are 32-bit on 32-bit implementations.
+ */
+#define KVM_SREGS_E_64 (1 << 2)
+
+#define KVM_SREGS_E_SPRG8 (1 << 3)
+#define KVM_SREGS_E_MCIVPR (1 << 4)
+
+/*
+ * IVORs are used -- contains IVOR0-15, plus additional IVORs
+ * in combination with an appropriate feature bit.
+ */
+#define KVM_SREGS_E_IVOR (1 << 5)
+
+/*
+ * Contains MAS0-4, MAS6-7, TLBnCFG, MMUCFG.
+ * Also TLBnPS if MMUCFG[MAVN] = 1.
+ */
+#define KVM_SREGS_E_ARCH206_MMU (1 << 6)
+
+/* DBSR, DBCR, IAC, DAC, DVC */
+#define KVM_SREGS_E_DEBUG (1 << 7)
+
+/* Enhanced debug -- DSRR0/1, SPRG9 */
+#define KVM_SREGS_E_ED (1 << 8)
+
+/* Embedded Floating Point (SPE) -- IVOR32-34 if KVM_SREGS_E_IVOR */
+#define KVM_SREGS_E_SPE (1 << 9)
+
+/* External Proxy (EXP) -- EPR */
+#define KVM_SREGS_EXP (1 << 10)
+
+/* External PID (E.PD) -- EPSC/EPLC */
+#define KVM_SREGS_E_PD (1 << 11)
+
+/* Processor Control (E.PC) -- IVOR36-37 if KVM_SREGS_E_IVOR */
+#define KVM_SREGS_E_PC (1 << 12)
+
+/* Page table (E.PT) -- EPTCFG */
+#define KVM_SREGS_E_PT (1 << 13)
+
+/* Embedded Performance Monitor (E.PM) -- IVOR35 if KVM_SREGS_E_IVOR */
+#define KVM_SREGS_E_PM (1 << 14)
+
+/*
+ * Special updates:
+ *
+ * Some registers may change even while a vcpu is not running.
+ * To avoid losing these changes, by default these registers are
+ * not updated by KVM_SET_SREGS. To force an update, set the bit
+ * in u.e.update_special corresponding to the register to be updated.
+ *
+ * The update_special field is zero on return from KVM_GET_SREGS.
+ *
+ * When restoring a checkpoint, the caller can set update_special
+ * to 0xffffffff to ensure that everything is restored, even new features
+ * that the caller doesn't know about.
+ */
+#define KVM_SREGS_E_UPDATE_MCSR (1 << 0)
+#define KVM_SREGS_E_UPDATE_TSR (1 << 1)
+#define KVM_SREGS_E_UPDATE_DEC (1 << 2)
+#define KVM_SREGS_E_UPDATE_DBSR (1 << 3)
+
+/*
+ * In KVM_SET_SREGS, reserved/pad fields must be left untouched from a
+ * previous KVM_GET_REGS.
+ *
+ * Unless otherwise indicated, setting any register with KVM_SET_SREGS
+ * directly sets its value. It does not trigger any special semantics such
+ * as write-one-to-clear. Calling KVM_SET_SREGS on an unmodified struct
+ * just received from KVM_GET_SREGS is always a no-op.
+ */
struct kvm_sregs {
__u32 pvr;
union {
@@ -62,6 +170,82 @@ struct kvm_sregs {
__u64 dbat[8];
} ppc32;
} s;
+ struct {
+ union {
+ struct { /* KVM_SREGS_E_IMPL_FSL */
+ __u32 features; /* KVM_SREGS_E_FSL_ */
+ __u32 svr;
+ __u64 mcar;
+ __u32 hid0;
+
+ /* KVM_SREGS_E_FSL_PIDn */
+ __u32 pid1, pid2;
+ } fsl;
+ __u8 pad[256];
+ } impl;
+
+ __u32 features; /* KVM_SREGS_E_ */
+ __u32 impl_id; /* KVM_SREGS_E_IMPL_ */
+ __u32 update_special; /* KVM_SREGS_E_UPDATE_ */
+ __u32 pir; /* read-only */
+ __u64 sprg8;
+ __u64 sprg9; /* E.ED */
+ __u64 csrr0;
+ __u64 dsrr0; /* E.ED */
+ __u64 mcsrr0;
+ __u32 csrr1;
+ __u32 dsrr1; /* E.ED */
+ __u32 mcsrr1;
+ __u32 esr;
+ __u64 dear;
+ __u64 ivpr;
+ __u64 mcivpr;
+ __u64 mcsr; /* KVM_SREGS_E_UPDATE_MCSR */
+
+ __u32 tsr; /* KVM_SREGS_E_UPDATE_TSR */
+ __u32 tcr;
+ __u32 decar;
+ __u32 dec; /* KVM_SREGS_E_UPDATE_DEC */
+
+ /*
+ * Userspace can read TB directly, but the
+ * value reported here is consistent with "dec".
+ *
+ * Read-only.
+ */
+ __u64 tb;
+
+ __u32 dbsr; /* KVM_SREGS_E_UPDATE_DBSR */
+ __u32 dbcr[3];
+ __u32 iac[4];
+ __u32 dac[2];
+ __u32 dvc[2];
+ __u8 num_iac; /* read-only */
+ __u8 num_dac; /* read-only */
+ __u8 num_dvc; /* read-only */
+ __u8 pad;
+
+ __u32 epr; /* EXP */
+ __u32 vrsave; /* a.k.a. USPRG0 */
+ __u32 epcr; /* KVM_SREGS_E_64 */
+
+ __u32 mas0;
+ __u32 mas1;
+ __u64 mas2;
+ __u64 mas7_3;
+ __u32 mas4;
+ __u32 mas6;
+
+ __u32 ivor_low[16]; /* IVOR0-15 */
+ __u32 ivor_high[18]; /* IVOR32+, plus room to expand */
+
+ __u32 mmucfg; /* read-only */
+ __u32 eptcfg; /* E.PT, read-only */
+ __u32 tlbcfg[4];/* read-only */
+ __u32 tlbps[4]; /* read-only */
+
+ __u32 eplc, epsc; /* E.PD */
+ } e;
__u8 pad[1020];
} u;
};
diff --git a/arch/powerpc/include/asm/kvm_44x.h b/arch/powerpc/include/asm/kvm_44x.h
index d22d39942a92..a0e57618ff33 100644
--- a/arch/powerpc/include/asm/kvm_44x.h
+++ b/arch/powerpc/include/asm/kvm_44x.h
@@ -61,7 +61,6 @@ static inline struct kvmppc_vcpu_44x *to_44x(struct kvm_vcpu *vcpu)
return container_of(vcpu, struct kvmppc_vcpu_44x, vcpu);
}
-void kvmppc_set_pid(struct kvm_vcpu *vcpu, u32 new_pid);
void kvmppc_44x_tlb_put(struct kvm_vcpu *vcpu);
void kvmppc_44x_tlb_load(struct kvm_vcpu *vcpu);
diff --git a/arch/powerpc/include/asm/kvm_asm.h b/arch/powerpc/include/asm/kvm_asm.h
index 5b7504674397..0951b17f4eb5 100644
--- a/arch/powerpc/include/asm/kvm_asm.h
+++ b/arch/powerpc/include/asm/kvm_asm.h
@@ -59,6 +59,7 @@
#define BOOK3S_INTERRUPT_INST_SEGMENT 0x480
#define BOOK3S_INTERRUPT_EXTERNAL 0x500
#define BOOK3S_INTERRUPT_EXTERNAL_LEVEL 0x501
+#define BOOK3S_INTERRUPT_EXTERNAL_HV 0x502
#define BOOK3S_INTERRUPT_ALIGNMENT 0x600
#define BOOK3S_INTERRUPT_PROGRAM 0x700
#define BOOK3S_INTERRUPT_FP_UNAVAIL 0x800
diff --git a/arch/powerpc/include/asm/kvm_book3s_asm.h b/arch/powerpc/include/asm/kvm_book3s_asm.h
index 36fdb3aff30b..d5a8a3861635 100644
--- a/arch/powerpc/include/asm/kvm_book3s_asm.h
+++ b/arch/powerpc/include/asm/kvm_book3s_asm.h
@@ -34,6 +34,7 @@
(\intno == BOOK3S_INTERRUPT_DATA_SEGMENT) || \
(\intno == BOOK3S_INTERRUPT_INST_SEGMENT) || \
(\intno == BOOK3S_INTERRUPT_EXTERNAL) || \
+ (\intno == BOOK3S_INTERRUPT_EXTERNAL_HV) || \
(\intno == BOOK3S_INTERRUPT_ALIGNMENT) || \
(\intno == BOOK3S_INTERRUPT_PROGRAM) || \
(\intno == BOOK3S_INTERRUPT_FP_UNAVAIL) || \
diff --git a/arch/powerpc/include/asm/kvm_e500.h b/arch/powerpc/include/asm/kvm_e500.h
index 7fea26fffb25..7a2a565f88c4 100644
--- a/arch/powerpc/include/asm/kvm_e500.h
+++ b/arch/powerpc/include/asm/kvm_e500.h
@@ -43,6 +43,7 @@ struct kvmppc_vcpu_e500 {
u32 host_pid[E500_PID_NUM];
u32 pid[E500_PID_NUM];
+ u32 svr;
u32 mas0;
u32 mas1;
@@ -58,6 +59,7 @@ struct kvmppc_vcpu_e500 {
u32 hid1;
u32 tlb0cfg;
u32 tlb1cfg;
+ u64 mcar;
struct kvm_vcpu vcpu;
};
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index bba3b9b72a39..186f150b9b89 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -223,6 +223,7 @@ struct kvm_vcpu_arch {
ulong hflags;
ulong guest_owned_ext;
#endif
+ u32 vrsave; /* also USPRG0 */
u32 mmucr;
ulong sprg4;
ulong sprg5;
@@ -232,6 +233,9 @@ struct kvm_vcpu_arch {
ulong csrr1;
ulong dsrr0;
ulong dsrr1;
+ ulong mcsrr0;
+ ulong mcsrr1;
+ ulong mcsr;
ulong esr;
u32 dec;
u32 decar;
@@ -255,6 +259,7 @@ struct kvm_vcpu_arch {
u32 dbsr;
#ifdef CONFIG_KVM_EXIT_TIMING
+ struct mutex exit_timing_lock;
struct kvmppc_exit_timing timing_exit;
struct kvmppc_exit_timing timing_last_enter;
u32 last_exit_type;
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index ecb3bc74c344..9345238edecf 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -61,6 +61,7 @@ extern int kvmppc_emulate_instruction(struct kvm_run *run,
struct kvm_vcpu *vcpu);
extern int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu);
extern void kvmppc_emulate_dec(struct kvm_vcpu *vcpu);
+extern u32 kvmppc_get_dec(struct kvm_vcpu *vcpu, u64 tb);
/* Core-specific hooks */
@@ -142,4 +143,12 @@ static inline u32 kvmppc_set_field(u64 inst, int msb, int lsb, int value)
return r;
}
+void kvmppc_core_get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs);
+int kvmppc_core_set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs);
+
+void kvmppc_get_sregs_ivor(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs);
+int kvmppc_set_sregs_ivor(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs);
+
+void kvmppc_set_pid(struct kvm_vcpu *vcpu, u32 pid);
+
#endif /* __POWERPC_KVM_PPC_H__ */
diff --git a/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h
index a077adc0b35e..e0298d26ce5d 100644
--- a/arch/powerpc/include/asm/lppaca.h
+++ b/arch/powerpc/include/asm/lppaca.h
@@ -210,6 +210,8 @@ struct dtl_entry {
#define DISPATCH_LOG_BYTES 4096 /* bytes per cpu */
#define N_DISPATCH_LOG (DISPATCH_LOG_BYTES / sizeof(struct dtl_entry))
+extern struct kmem_cache *dtl_cache;
+
/*
* When CONFIG_VIRT_CPU_ACCOUNTING = y, the cpu accounting code controls
* reading from the dispatch trace log. If other code wants to consume
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index e4f01915fbb0..47cacddb14cf 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -29,21 +29,6 @@ struct file;
struct pci_controller;
struct kimage;
-#ifdef CONFIG_SMP
-struct smp_ops_t {
- void (*message_pass)(int target, int msg);
- int (*probe)(void);
- void (*kick_cpu)(int nr);
- void (*setup_cpu)(int nr);
- void (*bringup_done)(void);
- void (*take_timebase)(void);
- void (*give_timebase)(void);
- int (*cpu_disable)(void);
- void (*cpu_die)(unsigned int nr);
- int (*cpu_bootable)(unsigned int nr);
-};
-#endif
-
struct machdep_calls {
char *name;
#ifdef CONFIG_PPC64
@@ -267,6 +252,7 @@ struct machdep_calls {
extern void e500_idle(void);
extern void power4_idle(void);
+extern void power7_idle(void);
extern void ppc6xx_idle(void);
extern void book3e_idle(void);
@@ -311,12 +297,6 @@ extern sys_ctrler_t sys_ctrler;
#endif /* CONFIG_PPC_PMAC */
-#ifdef CONFIG_SMP
-/* Poor default implementations */
-extern void __devinit smp_generic_give_timebase(void);
-extern void __devinit smp_generic_take_timebase(void);
-#endif /* CONFIG_SMP */
-
/* Functions to produce codes on the leds.
* The SRC code should be unique for the message category and should
diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h
index 17194fcd4040..3ea0f9a259d8 100644
--- a/arch/powerpc/include/asm/mmu-book3e.h
+++ b/arch/powerpc/include/asm/mmu-book3e.h
@@ -43,6 +43,7 @@
#define MAS0_TLBSEL(x) (((x) << 28) & 0x30000000)
#define MAS0_ESEL(x) (((x) << 16) & 0x0FFF0000)
#define MAS0_NV(x) ((x) & 0x00000FFF)
+#define MAS0_ESEL_MASK 0x0FFF0000
#define MAS0_HES 0x00004000
#define MAS0_WQ_ALLWAYS 0x00000000
#define MAS0_WQ_COND 0x00001000
@@ -137,6 +138,21 @@
#define MMUCSR0_TLB2PS 0x00078000 /* TLB2 Page Size */
#define MMUCSR0_TLB3PS 0x00780000 /* TLB3 Page Size */
+/* MMUCFG bits */
+#define MMUCFG_MAVN_NASK 0x00000003
+#define MMUCFG_MAVN_V1_0 0x00000000
+#define MMUCFG_MAVN_V2_0 0x00000001
+#define MMUCFG_NTLB_MASK 0x0000000c
+#define MMUCFG_NTLB_SHIFT 2
+#define MMUCFG_PIDSIZE_MASK 0x000007c0
+#define MMUCFG_PIDSIZE_SHIFT 6
+#define MMUCFG_TWC 0x00008000
+#define MMUCFG_LRAT 0x00010000
+#define MMUCFG_RASIZE_MASK 0x00fe0000
+#define MMUCFG_RASIZE_SHIFT 17
+#define MMUCFG_LPIDSIZE_MASK 0x0f000000
+#define MMUCFG_LPIDSIZE_SHIFT 24
+
/* TLBnCFG encoding */
#define TLBnCFG_N_ENTRY 0x00000fff /* number of entries */
#define TLBnCFG_HES 0x00002000 /* HW select supported */
@@ -229,6 +245,10 @@ extern struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT];
extern int mmu_linear_psize;
extern int mmu_vmemmap_psize;
+#ifdef CONFIG_PPC64
+extern unsigned long linear_map_top;
+#endif
+
#endif /* !__ASSEMBLY__ */
#endif /* _ASM_POWERPC_MMU_BOOK3E_H_ */
diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h
index ae7b3efec8e5..d865bd909c7d 100644
--- a/arch/powerpc/include/asm/mmu-hash64.h
+++ b/arch/powerpc/include/asm/mmu-hash64.h
@@ -408,6 +408,7 @@ static inline void subpage_prot_init_new_context(struct mm_struct *mm) { }
#endif /* CONFIG_PPC_SUBPAGE_PROT */
typedef unsigned long mm_context_id_t;
+struct spinlock;
typedef struct {
mm_context_id_t id;
@@ -423,6 +424,11 @@ typedef struct {
#ifdef CONFIG_PPC_SUBPAGE_PROT
struct subpage_prot_table spt;
#endif /* CONFIG_PPC_SUBPAGE_PROT */
+#ifdef CONFIG_PPC_ICSWX
+ struct spinlock *cop_lockp; /* guard acop and cop_pid */
+ unsigned long acop; /* mask of enabled coprocessor types */
+ unsigned int cop_pid; /* pid value used with coprocessors */
+#endif /* CONFIG_PPC_ICSWX */
} mm_context_t;
diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h
index bb40a06d3b77..4138b21ae80a 100644
--- a/arch/powerpc/include/asm/mmu.h
+++ b/arch/powerpc/include/asm/mmu.h
@@ -56,11 +56,6 @@
*/
#define MMU_FTR_NEED_DTLB_SW_LRU ASM_CONST(0x00200000)
-/* This indicates that the processor uses the ISA 2.06 server tlbie
- * mnemonics
- */
-#define MMU_FTR_TLBIE_206 ASM_CONST(0x00400000)
-
/* Enable use of TLB reservation. Processor should support tlbsrx.
* instruction and MAS0[WQ].
*/
@@ -70,6 +65,53 @@
*/
#define MMU_FTR_USE_PAIRED_MAS ASM_CONST(0x01000000)
+/* MMU is SLB-based
+ */
+#define MMU_FTR_SLB ASM_CONST(0x02000000)
+
+/* Support 16M large pages
+ */
+#define MMU_FTR_16M_PAGE ASM_CONST(0x04000000)
+
+/* Supports TLBIEL variant
+ */
+#define MMU_FTR_TLBIEL ASM_CONST(0x08000000)
+
+/* Supports tlbies w/o locking
+ */
+#define MMU_FTR_LOCKLESS_TLBIE ASM_CONST(0x10000000)
+
+/* Large pages can be marked CI
+ */
+#define MMU_FTR_CI_LARGE_PAGE ASM_CONST(0x20000000)
+
+/* 1T segments available
+ */
+#define MMU_FTR_1T_SEGMENT ASM_CONST(0x40000000)
+
+/* Doesn't support the B bit (1T segment) in SLBIE
+ */
+#define MMU_FTR_NO_SLBIE_B ASM_CONST(0x80000000)
+
+/* MMU feature bit sets for various CPUs */
+#define MMU_FTRS_DEFAULT_HPTE_ARCH_V2 \
+ MMU_FTR_HPTE_TABLE | MMU_FTR_PPCAS_ARCH_V2
+#define MMU_FTRS_POWER4 MMU_FTRS_DEFAULT_HPTE_ARCH_V2
+#define MMU_FTRS_PPC970 MMU_FTRS_POWER4
+#define MMU_FTRS_POWER5 MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE
+#define MMU_FTRS_POWER6 MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE
+#define MMU_FTRS_POWER7 MMU_FTRS_POWER4 | MMU_FTR_LOCKLESS_TLBIE
+#define MMU_FTRS_CELL MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \
+ MMU_FTR_CI_LARGE_PAGE
+#define MMU_FTRS_PA6T MMU_FTRS_DEFAULT_HPTE_ARCH_V2 | \
+ MMU_FTR_CI_LARGE_PAGE | MMU_FTR_NO_SLBIE_B
+#define MMU_FTRS_A2 MMU_FTR_TYPE_3E | MMU_FTR_USE_TLBILX | \
+ MMU_FTR_USE_TLBIVAX_BCAST | \
+ MMU_FTR_LOCK_BCAST_INVAL | \
+ MMU_FTR_USE_TLBRSRV | \
+ MMU_FTR_USE_PAIRED_MAS | \
+ MMU_FTR_TLBIEL | \
+ MMU_FTR_16M_PAGE
#ifndef __ASSEMBLY__
#include <asm/cputable.h>
diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h
index 81fb41289d6c..a73668a5f30d 100644
--- a/arch/powerpc/include/asm/mmu_context.h
+++ b/arch/powerpc/include/asm/mmu_context.h
@@ -32,6 +32,10 @@ extern void __destroy_context(unsigned long context_id);
extern void mmu_context_init(void);
#endif
+extern void switch_cop(struct mm_struct *next);
+extern int use_cop(unsigned long acop, struct mm_struct *mm);
+extern void drop_cop(unsigned long acop, struct mm_struct *mm);
+
/*
* switch_mm is the entry point called from the architecture independent
* code in kernel/sched.c
@@ -55,6 +59,12 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
if (prev == next)
return;
+#ifdef CONFIG_PPC_ICSWX
+ /* Switch coprocessor context only if prev or next uses a coprocessor */
+ if (prev->context.acop || next->context.acop)
+ switch_cop(next);
+#endif /* CONFIG_PPC_ICSWX */
+
/* We must stop all altivec streams before changing the HW
* context
*/
@@ -67,7 +77,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
* sub architectures.
*/
#ifdef CONFIG_PPC_STD_MMU_64
- if (cpu_has_feature(CPU_FTR_SLB))
+ if (mmu_has_feature(MMU_FTR_SLB))
switch_slb(tsk, next);
else
switch_stab(tsk, next);
diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h
index 7005ee0b074d..df18989e78d4 100644
--- a/arch/powerpc/include/asm/mpic.h
+++ b/arch/powerpc/include/asm/mpic.h
@@ -3,7 +3,6 @@
#ifdef __KERNEL__
#include <linux/irq.h>
-#include <linux/sysdev.h>
#include <asm/dcr.h>
#include <asm/msi_bitmap.h>
@@ -263,6 +262,7 @@ struct mpic
#ifdef CONFIG_SMP
struct irq_chip hc_ipi;
#endif
+ struct irq_chip hc_tm;
const char *name;
/* Flags */
unsigned int flags;
@@ -281,7 +281,7 @@ struct mpic
/* vector numbers used for internal sources (ipi/timers) */
unsigned int ipi_vecs[4];
- unsigned int timer_vecs[4];
+ unsigned int timer_vecs[8];
/* Spurious vector to program into unused sources */
unsigned int spurious_vec;
@@ -320,8 +320,6 @@ struct mpic
/* link */
struct mpic *next;
- struct sys_device sysdev;
-
#ifdef CONFIG_PM
struct mpic_irq_save *save_data;
#endif
@@ -371,6 +369,8 @@ struct mpic
* NOTE: This flag trumps MPIC_WANTS_RESET.
*/
#define MPIC_NO_RESET 0x00004000
+/* Freescale MPIC (compatible includes "fsl,mpic") */
+#define MPIC_FSL 0x00008000
/* MPIC HW modification ID */
#define MPIC_REGSET_MASK 0xf0000000
diff --git a/arch/powerpc/include/asm/pSeries_reconfig.h b/arch/powerpc/include/asm/pSeries_reconfig.h
index d4b4bfa26fb3..89d2f99c1bf4 100644
--- a/arch/powerpc/include/asm/pSeries_reconfig.h
+++ b/arch/powerpc/include/asm/pSeries_reconfig.h
@@ -18,13 +18,18 @@
extern int pSeries_reconfig_notifier_register(struct notifier_block *);
extern void pSeries_reconfig_notifier_unregister(struct notifier_block *);
extern struct blocking_notifier_head pSeries_reconfig_chain;
+/* Not the best place to put this, will be fixed when we move some
+ * of the rtas suspend-me stuff to pseries */
+extern void pSeries_coalesce_init(void);
#else /* !CONFIG_PPC_PSERIES */
static inline int pSeries_reconfig_notifier_register(struct notifier_block *nb)
{
return 0;
}
static inline void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) { }
+static inline void pSeries_coalesce_init(void) { }
#endif /* CONFIG_PPC_PSERIES */
+
#endif /* __KERNEL__ */
#endif /* _PPC64_PSERIES_RECONFIG_H */
diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
index ec57540cd7af..74126765106a 100644
--- a/arch/powerpc/include/asm/paca.h
+++ b/arch/powerpc/include/asm/paca.h
@@ -92,9 +92,9 @@ struct paca_struct {
* Now, starting in cacheline 2, the exception save areas
*/
/* used for most interrupts/exceptions */
- u64 exgen[10] __attribute__((aligned(0x80)));
- u64 exmc[10]; /* used for machine checks */
- u64 exslb[10]; /* used for SLB/segment table misses
+ u64 exgen[11] __attribute__((aligned(0x80)));
+ u64 exmc[11]; /* used for machine checks */
+ u64 exslb[11]; /* used for SLB/segment table misses
* on the linear mapping */
/* SLB related definitions */
u16 vmalloc_sllp;
@@ -106,7 +106,8 @@ struct paca_struct {
pgd_t *pgd; /* Current PGD */
pgd_t *kernel_pgd; /* Kernel PGD */
u64 exgen[8] __attribute__((aligned(0x80)));
- u64 extlb[EX_TLB_SIZE*3] __attribute__((aligned(0x80)));
+ /* We can have up to 3 levels of reentrancy in the TLB miss handler */
+ u64 extlb[3][EX_TLB_SIZE / sizeof(u64)] __attribute__((aligned(0x80)));
u64 exmc[8]; /* used for machine checks */
u64 excrit[8]; /* used for crit interrupts */
u64 exdbg[8]; /* used for debug interrupts */
@@ -125,7 +126,7 @@ struct paca_struct {
struct task_struct *__current; /* Pointer to current */
u64 kstack; /* Saved Kernel stack addr */
u64 stab_rr; /* stab/slb round-robin counter */
- u64 saved_r1; /* r1 save for RTAS calls */
+ u64 saved_r1; /* r1 save for RTAS calls or PM */
u64 saved_msr; /* MSR saved here by enter_rtas */
u16 trap_save; /* Used when bad stack is encountered */
u8 soft_enabled; /* irq soft-enable flag */
diff --git a/arch/powerpc/include/asm/page_64.h b/arch/powerpc/include/asm/page_64.h
index 812b2cd80aed..9356262fd3cc 100644
--- a/arch/powerpc/include/asm/page_64.h
+++ b/arch/powerpc/include/asm/page_64.h
@@ -59,24 +59,7 @@ static __inline__ void clear_page(void *addr)
: "ctr", "memory");
}
-extern void copy_4K_page(void *to, void *from);
-
-#ifdef CONFIG_PPC_64K_PAGES
-static inline void copy_page(void *to, void *from)
-{
- unsigned int i;
- for (i=0; i < (1 << (PAGE_SHIFT - 12)); i++) {
- copy_4K_page(to, from);
- to += 4096;
- from += 4096;
- }
-}
-#else /* CONFIG_PPC_64K_PAGES */
-static inline void copy_page(void *to, void *from)
-{
- copy_4K_page(to, from);
-}
-#endif /* CONFIG_PPC_64K_PAGES */
+extern void copy_page(void *to, void *from);
/* Log 2 of page table size */
extern u64 ppc64_pft_size;
@@ -130,7 +113,7 @@ extern void slice_set_user_psize(struct mm_struct *mm, unsigned int psize);
extern void slice_set_range_psize(struct mm_struct *mm, unsigned long start,
unsigned long len, unsigned int psize);
-#define slice_mm_new_context(mm) ((mm)->context.id == 0)
+#define slice_mm_new_context(mm) ((mm)->context.id == MMU_NO_CONTEXT)
#endif /* __ASSEMBLY__ */
#else
diff --git a/arch/powerpc/include/asm/pgalloc.h b/arch/powerpc/include/asm/pgalloc.h
index abe8532bd14e..bf301ac62f35 100644
--- a/arch/powerpc/include/asm/pgalloc.h
+++ b/arch/powerpc/include/asm/pgalloc.h
@@ -31,14 +31,29 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t ptepage)
#endif
#ifdef CONFIG_SMP
-extern void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift);
-extern void pte_free_finish(void);
+struct mmu_gather;
+extern void tlb_remove_table(struct mmu_gather *, void *);
+
+static inline void pgtable_free_tlb(struct mmu_gather *tlb, void *table, int shift)
+{
+ unsigned long pgf = (unsigned long)table;
+ BUG_ON(shift > MAX_PGTABLE_INDEX_SIZE);
+ pgf |= shift;
+ tlb_remove_table(tlb, (void *)pgf);
+}
+
+static inline void __tlb_remove_table(void *_table)
+{
+ void *table = (void *)((unsigned long)_table & ~MAX_PGTABLE_INDEX_SIZE);
+ unsigned shift = (unsigned long)_table & MAX_PGTABLE_INDEX_SIZE;
+
+ pgtable_free(table, shift);
+}
#else /* CONFIG_SMP */
static inline void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift)
{
pgtable_free(table, shift);
}
-static inline void pte_free_finish(void) { }
#endif /* !CONFIG_SMP */
static inline void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage,
diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h
index 2b09cd522d33..81576ee0cfb1 100644
--- a/arch/powerpc/include/asm/pgtable-ppc64.h
+++ b/arch/powerpc/include/asm/pgtable-ppc64.h
@@ -257,21 +257,20 @@ static inline int __ptep_test_and_clear_young(struct mm_struct *mm,
static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr,
pte_t *ptep)
{
- unsigned long old;
- if ((pte_val(*ptep) & _PAGE_RW) == 0)
- return;
- old = pte_update(mm, addr, ptep, _PAGE_RW, 0);
+ if ((pte_val(*ptep) & _PAGE_RW) == 0)
+ return;
+
+ pte_update(mm, addr, ptep, _PAGE_RW, 0);
}
static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
unsigned long addr, pte_t *ptep)
{
- unsigned long old;
-
if ((pte_val(*ptep) & _PAGE_RW) == 0)
return;
- old = pte_update(mm, addr, ptep, _PAGE_RW, 1);
+
+ pte_update(mm, addr, ptep, _PAGE_RW, 1);
}
/*
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
index 1255569387b6..e472659d906c 100644
--- a/arch/powerpc/include/asm/ppc-opcode.h
+++ b/arch/powerpc/include/asm/ppc-opcode.h
@@ -41,6 +41,10 @@
#define PPC_INST_RFCI 0x4c000066
#define PPC_INST_RFDI 0x4c00004e
#define PPC_INST_RFMCI 0x4c00004c
+#define PPC_INST_MFSPR_DSCR 0x7c1102a6
+#define PPC_INST_MFSPR_DSCR_MASK 0xfc1fffff
+#define PPC_INST_MTSPR_DSCR 0x7c1103a6
+#define PPC_INST_MTSPR_DSCR_MASK 0xfc1fffff
#define PPC_INST_STRING 0x7c00042a
#define PPC_INST_STRING_MASK 0xfc0007fe
@@ -56,6 +60,17 @@
#define PPC_INST_TLBSRX_DOT 0x7c0006a5
#define PPC_INST_XXLOR 0xf0000510
+#define PPC_INST_NAP 0x4c000364
+#define PPC_INST_SLEEP 0x4c0003a4
+
+/* A2 specific instructions */
+#define PPC_INST_ERATWE 0x7c0001a6
+#define PPC_INST_ERATRE 0x7c000166
+#define PPC_INST_ERATILX 0x7c000066
+#define PPC_INST_ERATIVAX 0x7c000666
+#define PPC_INST_ERATSX 0x7c000126
+#define PPC_INST_ERATSX_DOT 0x7c000127
+
/* macros to insert fields into opcodes */
#define __PPC_RA(a) (((a) & 0x1f) << 16)
#define __PPC_RB(b) (((b) & 0x1f) << 11)
@@ -67,6 +82,8 @@
#define __PPC_XT(s) __PPC_XS(s)
#define __PPC_T_TLB(t) (((t) & 0x3) << 21)
#define __PPC_WC(w) (((w) & 0x3) << 21)
+#define __PPC_WS(w) (((w) & 0x1f) << 11)
+
/*
* Only use the larx hint bit on 64bit CPUs. e500v1/v2 based CPUs will treat a
* larx with EH set as an illegal instruction.
@@ -113,6 +130,21 @@
#define PPC_TLBIVAX(a,b) stringify_in_c(.long PPC_INST_TLBIVAX | \
__PPC_RA(a) | __PPC_RB(b))
+#define PPC_ERATWE(s, a, w) stringify_in_c(.long PPC_INST_ERATWE | \
+ __PPC_RS(s) | __PPC_RA(a) | __PPC_WS(w))
+#define PPC_ERATRE(s, a, w) stringify_in_c(.long PPC_INST_ERATRE | \
+ __PPC_RS(s) | __PPC_RA(a) | __PPC_WS(w))
+#define PPC_ERATILX(t, a, b) stringify_in_c(.long PPC_INST_ERATILX | \
+ __PPC_T_TLB(t) | __PPC_RA(a) | \
+ __PPC_RB(b))
+#define PPC_ERATIVAX(s, a, b) stringify_in_c(.long PPC_INST_ERATIVAX | \
+ __PPC_RS(s) | __PPC_RA(a) | __PPC_RB(b))
+#define PPC_ERATSX(t, a, w) stringify_in_c(.long PPC_INST_ERATSX | \
+ __PPC_RS(t) | __PPC_RA(a) | __PPC_RB(b))
+#define PPC_ERATSX_DOT(t, a, w) stringify_in_c(.long PPC_INST_ERATSX_DOT | \
+ __PPC_RS(t) | __PPC_RA(a) | __PPC_RB(b))
+
+
/*
* Define what the VSX XX1 form instructions will look like, then add
* the 128 bit load store instructions based on that.
@@ -126,4 +158,7 @@
#define XXLOR(t, a, b) stringify_in_c(.long PPC_INST_XXLOR | \
VSX_XX3((t), (a), (b)))
+#define PPC_NAP stringify_in_c(.long PPC_INST_NAP)
+#define PPC_SLEEP stringify_in_c(.long PPC_INST_SLEEP)
+
#endif /* _ASM_POWERPC_PPC_OPCODE_H */
diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h
index 98210067c1cc..1b422381fc16 100644
--- a/arch/powerpc/include/asm/ppc_asm.h
+++ b/arch/powerpc/include/asm/ppc_asm.h
@@ -170,6 +170,7 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
#define HMT_MEDIUM or 2,2,2
#define HMT_MEDIUM_HIGH or 5,5,5 # medium high priority
#define HMT_HIGH or 3,3,3
+#define HMT_EXTRA_HIGH or 7,7,7 # power7 only
#ifdef __KERNEL__
#ifdef CONFIG_PPC64
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index de1967a1ff57..d50c2b6d9bc3 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -238,6 +238,10 @@ struct thread_struct {
#ifdef CONFIG_KVM_BOOK3S_32_HANDLER
void* kvm_shadow_vcpu; /* KVM internal data */
#endif /* CONFIG_KVM_BOOK3S_32_HANDLER */
+#ifdef CONFIG_PPC64
+ unsigned long dscr;
+ int dscr_inherit;
+#endif
};
#define ARCH_MIN_TASKALIGN 16
diff --git a/arch/powerpc/include/asm/pte-hash64-64k.h b/arch/powerpc/include/asm/pte-hash64-64k.h
index c4490f9c67c4..59247e816ac5 100644
--- a/arch/powerpc/include/asm/pte-hash64-64k.h
+++ b/arch/powerpc/include/asm/pte-hash64-64k.h
@@ -22,7 +22,7 @@
#define _PAGE_HASHPTE _PAGE_HPTE_SUB
/* Note the full page bits must be in the same location as for normal
- * 4k pages as the same asssembly will be used to insert 64K pages
+ * 4k pages as the same assembly will be used to insert 64K pages
* wether the kernel has CONFIG_PPC_64K_PAGES or not
*/
#define _PAGE_F_SECOND 0x00008000 /* full page: hidx bits */
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 7e4abebe76c0..c5cae0dd176c 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -99,17 +99,23 @@
#define MSR_LE __MASK(MSR_LE_LG) /* Little Endian */
#if defined(CONFIG_PPC_BOOK3S_64)
+#define MSR_64BIT MSR_SF
+
/* Server variant */
#define MSR_ MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_ISF |MSR_HV
-#define MSR_KERNEL MSR_ | MSR_SF
+#define MSR_KERNEL MSR_ | MSR_64BIT
#define MSR_USER32 MSR_ | MSR_PR | MSR_EE
-#define MSR_USER64 MSR_USER32 | MSR_SF
+#define MSR_USER64 MSR_USER32 | MSR_64BIT
#elif defined(CONFIG_PPC_BOOK3S_32) || defined(CONFIG_8xx)
/* Default MSR for kernel mode. */
#define MSR_KERNEL (MSR_ME|MSR_RI|MSR_IR|MSR_DR)
#define MSR_USER (MSR_KERNEL|MSR_PR|MSR_EE)
#endif
+#ifndef MSR_64BIT
+#define MSR_64BIT 0
+#endif
+
/* Floating Point Status and Control Register (FPSCR) Fields */
#define FPSCR_FX 0x80000000 /* FPU exception summary */
#define FPSCR_FEX 0x40000000 /* FPU enabled exception summary */
@@ -182,6 +188,8 @@
#define SPRN_CTR 0x009 /* Count Register */
#define SPRN_DSCR 0x11
+#define SPRN_CFAR 0x1c /* Come From Address Register */
+#define SPRN_ACOP 0x1F /* Available Coprocessor Register */
#define SPRN_CTRLF 0x088
#define SPRN_CTRLT 0x098
#define CTRL_CT 0xc0000000 /* current thread */
@@ -210,8 +218,43 @@
#define SPRN_TBWL 0x11C /* Time Base Lower Register (super, R/W) */
#define SPRN_TBWU 0x11D /* Time Base Upper Register (super, R/W) */
#define SPRN_SPURR 0x134 /* Scaled PURR */
+#define SPRN_HSPRG0 0x130 /* Hypervisor Scratch 0 */
+#define SPRN_HSPRG1 0x131 /* Hypervisor Scratch 1 */
+#define SPRN_HDSISR 0x132
+#define SPRN_HDAR 0x133
+#define SPRN_HDEC 0x136 /* Hypervisor Decrementer */
#define SPRN_HIOR 0x137 /* 970 Hypervisor interrupt offset */
+#define SPRN_RMOR 0x138 /* Real mode offset register */
+#define SPRN_HRMOR 0x139 /* Real mode offset register */
+#define SPRN_HSRR0 0x13A /* Hypervisor Save/Restore 0 */
+#define SPRN_HSRR1 0x13B /* Hypervisor Save/Restore 1 */
#define SPRN_LPCR 0x13E /* LPAR Control Register */
+#define LPCR_VPM0 (1ul << (63-0))
+#define LPCR_VPM1 (1ul << (63-1))
+#define LPCR_ISL (1ul << (63-2))
+#define LPCR_DPFD_SH (63-11)
+#define LPCR_VRMA_L (1ul << (63-12))
+#define LPCR_VRMA_LP0 (1ul << (63-15))
+#define LPCR_VRMA_LP1 (1ul << (63-16))
+#define LPCR_RMLS 0x1C000000 /* impl dependent rmo limit sel */
+#define LPCR_ILE 0x02000000 /* !HV irqs set MSR:LE */
+#define LPCR_PECE 0x00007000 /* powersave exit cause enable */
+#define LPCR_PECE0 0x00004000 /* ext. exceptions can cause exit */
+#define LPCR_PECE1 0x00002000 /* decrementer can cause exit */
+#define LPCR_PECE2 0x00001000 /* machine check etc can cause exit */
+#define LPCR_MER 0x00000800 /* Mediated External Exception */
+#define LPCR_LPES0 0x00000008 /* LPAR Env selector 0 */
+#define LPCR_LPES1 0x00000004 /* LPAR Env selector 1 */
+#define LPCR_RMI 0x00000002 /* real mode is cache inhibit */
+#define LPCR_HDICE 0x00000001 /* Hyp Decr enable (HV,PR,EE) */
+#define SPRN_LPID 0x13F /* Logical Partition Identifier */
+#define SPRN_HMER 0x150 /* Hardware m? error recovery */
+#define SPRN_HMEER 0x151 /* Hardware m? enable error recovery */
+#define SPRN_HEIR 0x153 /* Hypervisor Emulated Instruction Register */
+#define SPRN_TLBINDEXR 0x154 /* P7 TLB control register */
+#define SPRN_TLBVPNR 0x155 /* P7 TLB control register */
+#define SPRN_TLBRPNR 0x156 /* P7 TLB control register */
+#define SPRN_TLBLPIDR 0x157 /* P7 TLB control register */
#define SPRN_DBAT0L 0x219 /* Data BAT 0 Lower Register */
#define SPRN_DBAT0U 0x218 /* Data BAT 0 Upper Register */
#define SPRN_DBAT1L 0x21B /* Data BAT 1 Lower Register */
@@ -434,16 +477,23 @@
#define SPRN_SRR0 0x01A /* Save/Restore Register 0 */
#define SPRN_SRR1 0x01B /* Save/Restore Register 1 */
#define SRR1_WAKEMASK 0x00380000 /* reason for wakeup */
-#define SRR1_WAKERESET 0x00380000 /* System reset */
#define SRR1_WAKESYSERR 0x00300000 /* System error */
#define SRR1_WAKEEE 0x00200000 /* External interrupt */
#define SRR1_WAKEMT 0x00280000 /* mtctrl */
+#define SRR1_WAKEHMI 0x00280000 /* Hypervisor maintenance */
#define SRR1_WAKEDEC 0x00180000 /* Decrementer interrupt */
#define SRR1_WAKETHERM 0x00100000 /* Thermal management interrupt */
+#define SRR1_WAKERESET 0x00100000 /* System reset */
+#define SRR1_WAKESTATE 0x00030000 /* Powersave exit mask [46:47] */
+#define SRR1_WS_DEEPEST 0x00030000 /* Some resources not maintained,
+ * may not be recoverable */
+#define SRR1_WS_DEEPER 0x00020000 /* Some resources not maintained */
+#define SRR1_WS_DEEP 0x00010000 /* All resources maintained */
#define SRR1_PROGFPE 0x00100000 /* Floating Point Enabled */
#define SRR1_PROGPRIV 0x00040000 /* Privileged instruction */
#define SRR1_PROGTRAP 0x00020000 /* Trap */
#define SRR1_PROGADDR 0x00010000 /* SRR0 contains subsequent addr */
+
#define SPRN_HSRR0 0x13A /* Save/Restore Register 0 */
#define SPRN_HSRR1 0x13B /* Save/Restore Register 1 */
@@ -673,12 +723,15 @@
* SPRG usage:
*
* All 64-bit:
- * - SPRG1 stores PACA pointer
+ * - SPRG1 stores PACA pointer except 64-bit server in
+ * HV mode in which case it is HSPRG0
*
* 64-bit server:
* - SPRG0 unused (reserved for HV on Power4)
* - SPRG2 scratch for exception vectors
* - SPRG3 unused (user visible)
+ * - HSPRG0 stores PACA in HV mode
+ * - HSPRG1 scratch for "HV" exceptions
*
* 64-bit embedded
* - SPRG0 generic exception scratch
@@ -741,6 +794,41 @@
#ifdef CONFIG_PPC_BOOK3S_64
#define SPRN_SPRG_SCRATCH0 SPRN_SPRG2
+#define SPRN_SPRG_HPACA SPRN_HSPRG0
+#define SPRN_SPRG_HSCRATCH0 SPRN_HSPRG1
+
+#define GET_PACA(rX) \
+ BEGIN_FTR_SECTION_NESTED(66); \
+ mfspr rX,SPRN_SPRG_PACA; \
+ FTR_SECTION_ELSE_NESTED(66); \
+ mfspr rX,SPRN_SPRG_HPACA; \
+ ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_HVMODE_206, 66)
+
+#define SET_PACA(rX) \
+ BEGIN_FTR_SECTION_NESTED(66); \
+ mtspr SPRN_SPRG_PACA,rX; \
+ FTR_SECTION_ELSE_NESTED(66); \
+ mtspr SPRN_SPRG_HPACA,rX; \
+ ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_HVMODE_206, 66)
+
+#define GET_SCRATCH0(rX) \
+ BEGIN_FTR_SECTION_NESTED(66); \
+ mfspr rX,SPRN_SPRG_SCRATCH0; \
+ FTR_SECTION_ELSE_NESTED(66); \
+ mfspr rX,SPRN_SPRG_HSCRATCH0; \
+ ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_HVMODE_206, 66)
+
+#define SET_SCRATCH0(rX) \
+ BEGIN_FTR_SECTION_NESTED(66); \
+ mtspr SPRN_SPRG_SCRATCH0,rX; \
+ FTR_SECTION_ELSE_NESTED(66); \
+ mtspr SPRN_SPRG_HSCRATCH0,rX; \
+ ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_HVMODE_206, 66)
+
+#else /* CONFIG_PPC_BOOK3S_64 */
+#define GET_SCRATCH0(rX) mfspr rX,SPRN_SPRG_SCRATCH0
+#define SET_SCRATCH0(rX) mtspr SPRN_SPRG_SCRATCH0,rX
+
#endif
#ifdef CONFIG_PPC_BOOK3E_64
@@ -750,6 +838,10 @@
#define SPRN_SPRG_TLB_EXFRAME SPRN_SPRG2
#define SPRN_SPRG_TLB_SCRATCH SPRN_SPRG6
#define SPRN_SPRG_GEN_SCRATCH SPRN_SPRG0
+
+#define SET_PACA(rX) mtspr SPRN_SPRG_PACA,rX
+#define GET_PACA(rX) mfspr rX,SPRN_SPRG_PACA
+
#endif
#ifdef CONFIG_PPC_BOOK3S_32
@@ -800,6 +892,8 @@
#define SPRN_SPRG_SCRATCH1 SPRN_SPRG1
#endif
+
+
/*
* An mtfsf instruction with the L bit set. On CPUs that support this a
* full 64bits of FPSCR is restored and on other CPUs the L bit is ignored.
@@ -894,6 +988,8 @@
#define PV_POWER5p 0x003B
#define PV_POWER7 0x003F
#define PV_970FX 0x003C
+#define PV_POWER6 0x003E
+#define PV_POWER7 0x003F
#define PV_630 0x0040
#define PV_630p 0x0041
#define PV_970MP 0x0044
diff --git a/arch/powerpc/include/asm/reg_a2.h b/arch/powerpc/include/asm/reg_a2.h
new file mode 100644
index 000000000000..3d52a1132f3d
--- /dev/null
+++ b/arch/powerpc/include/asm/reg_a2.h
@@ -0,0 +1,165 @@
+/*
+ * Register definitions specific to the A2 core
+ *
+ * Copyright (C) 2008 Ben. Herrenschmidt (benh@kernel.crashing.org), 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.
+ */
+
+#ifndef __ASM_POWERPC_REG_A2_H__
+#define __ASM_POWERPC_REG_A2_H__
+
+#define SPRN_TENSR 0x1b5
+#define SPRN_TENS 0x1b6 /* Thread ENable Set */
+#define SPRN_TENC 0x1b7 /* Thread ENable Clear */
+
+#define SPRN_A2_CCR0 0x3f0 /* Core Configuration Register 0 */
+#define SPRN_A2_CCR1 0x3f1 /* Core Configuration Register 1 */
+#define SPRN_A2_CCR2 0x3f2 /* Core Configuration Register 2 */
+#define SPRN_MMUCR0 0x3fc /* MMU Control Register 0 */
+#define SPRN_MMUCR1 0x3fd /* MMU Control Register 1 */
+#define SPRN_MMUCR2 0x3fe /* MMU Control Register 2 */
+#define SPRN_MMUCR3 0x3ff /* MMU Control Register 3 */
+
+#define SPRN_IAR 0x372
+
+#define SPRN_IUCR0 0x3f3
+#define IUCR0_ICBI_ACK 0x1000
+
+#define SPRN_XUCR0 0x3f6 /* Execution Unit Config Register 0 */
+
+#define A2_IERAT_SIZE 16
+#define A2_DERAT_SIZE 32
+
+/* A2 MMUCR0 bits */
+#define MMUCR0_ECL 0x80000000 /* Extended Class for TLB fills */
+#define MMUCR0_TID_NZ 0x40000000 /* TID is non-zero */
+#define MMUCR0_TS 0x10000000 /* Translation space for TLB fills */
+#define MMUCR0_TGS 0x20000000 /* Guest space for TLB fills */
+#define MMUCR0_TLBSEL 0x0c000000 /* TLB or ERAT target for TLB fills */
+#define MMUCR0_TLBSEL_U 0x00000000 /* TLBSEL = UTLB */
+#define MMUCR0_TLBSEL_I 0x08000000 /* TLBSEL = I-ERAT */
+#define MMUCR0_TLBSEL_D 0x0c000000 /* TLBSEL = D-ERAT */
+#define MMUCR0_LOCKSRSH 0x02000000 /* Use TLB lock on tlbsx. */
+#define MMUCR0_TID_MASK 0x000000ff /* TID field */
+
+/* A2 MMUCR1 bits */
+#define MMUCR1_IRRE 0x80000000 /* I-ERAT round robin enable */
+#define MMUCR1_DRRE 0x40000000 /* D-ERAT round robin enable */
+#define MMUCR1_REE 0x20000000 /* Reference Exception Enable*/
+#define MMUCR1_CEE 0x10000000 /* Change exception enable */
+#define MMUCR1_CSINV_ALL 0x00000000 /* Inval ERAT on all CS evts */
+#define MMUCR1_CSINV_NISYNC 0x04000000 /* Inval ERAT on all ex isync*/
+#define MMUCR1_CSINV_NEVER 0x0c000000 /* Don't inval ERAT on CS */
+#define MMUCR1_ICTID 0x00080000 /* IERAT class field as TID */
+#define MMUCR1_ITTID 0x00040000 /* IERAT thdid field as TID */
+#define MMUCR1_DCTID 0x00020000 /* DERAT class field as TID */
+#define MMUCR1_DTTID 0x00010000 /* DERAT thdid field as TID */
+#define MMUCR1_DCCD 0x00008000 /* DERAT class ignore */
+#define MMUCR1_TLBWE_BINV 0x00004000 /* back invalidate on tlbwe */
+
+/* A2 MMUCR2 bits */
+#define MMUCR2_PSSEL_SHIFT 4
+
+/* A2 MMUCR3 bits */
+#define MMUCR3_THID 0x0000000f /* Thread ID */
+
+/* *** ERAT TLB bits definitions */
+#define TLB0_EPN_MASK ASM_CONST(0xfffffffffffff000)
+#define TLB0_CLASS_MASK ASM_CONST(0x0000000000000c00)
+#define TLB0_CLASS_00 ASM_CONST(0x0000000000000000)
+#define TLB0_CLASS_01 ASM_CONST(0x0000000000000400)
+#define TLB0_CLASS_10 ASM_CONST(0x0000000000000800)
+#define TLB0_CLASS_11 ASM_CONST(0x0000000000000c00)
+#define TLB0_V ASM_CONST(0x0000000000000200)
+#define TLB0_X ASM_CONST(0x0000000000000100)
+#define TLB0_SIZE_MASK ASM_CONST(0x00000000000000f0)
+#define TLB0_SIZE_4K ASM_CONST(0x0000000000000010)
+#define TLB0_SIZE_64K ASM_CONST(0x0000000000000030)
+#define TLB0_SIZE_1M ASM_CONST(0x0000000000000050)
+#define TLB0_SIZE_16M ASM_CONST(0x0000000000000070)
+#define TLB0_SIZE_1G ASM_CONST(0x00000000000000a0)
+#define TLB0_THDID_MASK ASM_CONST(0x000000000000000f)
+#define TLB0_THDID_0 ASM_CONST(0x0000000000000001)
+#define TLB0_THDID_1 ASM_CONST(0x0000000000000002)
+#define TLB0_THDID_2 ASM_CONST(0x0000000000000004)
+#define TLB0_THDID_3 ASM_CONST(0x0000000000000008)
+#define TLB0_THDID_ALL ASM_CONST(0x000000000000000f)
+
+#define TLB1_RESVATTR ASM_CONST(0x00f0000000000000)
+#define TLB1_U0 ASM_CONST(0x0008000000000000)
+#define TLB1_U1 ASM_CONST(0x0004000000000000)
+#define TLB1_U2 ASM_CONST(0x0002000000000000)
+#define TLB1_U3 ASM_CONST(0x0001000000000000)
+#define TLB1_R ASM_CONST(0x0000800000000000)
+#define TLB1_C ASM_CONST(0x0000400000000000)
+#define TLB1_RPN_MASK ASM_CONST(0x000003fffffff000)
+#define TLB1_W ASM_CONST(0x0000000000000800)
+#define TLB1_I ASM_CONST(0x0000000000000400)
+#define TLB1_M ASM_CONST(0x0000000000000200)
+#define TLB1_G ASM_CONST(0x0000000000000100)
+#define TLB1_E ASM_CONST(0x0000000000000080)
+#define TLB1_VF ASM_CONST(0x0000000000000040)
+#define TLB1_UX ASM_CONST(0x0000000000000020)
+#define TLB1_SX ASM_CONST(0x0000000000000010)
+#define TLB1_UW ASM_CONST(0x0000000000000008)
+#define TLB1_SW ASM_CONST(0x0000000000000004)
+#define TLB1_UR ASM_CONST(0x0000000000000002)
+#define TLB1_SR ASM_CONST(0x0000000000000001)
+
+#ifdef CONFIG_PPC_EARLY_DEBUG_WSP
+#define WSP_UART_PHYS 0xffc000c000
+/* This needs to be careful chosen to hit a !0 congruence class
+ * in the TLB since we bolt it in way 3, which is already occupied
+ * by our linear mapping primary bolted entry in CC 0.
+ */
+#define WSP_UART_VIRT 0xf000000000001000
+#endif
+
+/* A2 erativax attributes definitions */
+#define ERATIVAX_RS_IS_ALL 0x000
+#define ERATIVAX_RS_IS_TID 0x040
+#define ERATIVAX_RS_IS_CLASS 0x080
+#define ERATIVAX_RS_IS_FULLMATCH 0x0c0
+#define ERATIVAX_CLASS_00 0x000
+#define ERATIVAX_CLASS_01 0x010
+#define ERATIVAX_CLASS_10 0x020
+#define ERATIVAX_CLASS_11 0x030
+#define ERATIVAX_PSIZE_4K (TLB_PSIZE_4K >> 1)
+#define ERATIVAX_PSIZE_64K (TLB_PSIZE_64K >> 1)
+#define ERATIVAX_PSIZE_1M (TLB_PSIZE_1M >> 1)
+#define ERATIVAX_PSIZE_16M (TLB_PSIZE_16M >> 1)
+#define ERATIVAX_PSIZE_1G (TLB_PSIZE_1G >> 1)
+
+/* A2 eratilx attributes definitions */
+#define ERATILX_T_ALL 0
+#define ERATILX_T_TID 1
+#define ERATILX_T_TGS 2
+#define ERATILX_T_FULLMATCH 3
+#define ERATILX_T_CLASS0 4
+#define ERATILX_T_CLASS1 5
+#define ERATILX_T_CLASS2 6
+#define ERATILX_T_CLASS3 7
+
+/* XUCR0 bits */
+#define XUCR0_TRACE_UM_T0 0x40000000 /* Thread 0 */
+#define XUCR0_TRACE_UM_T1 0x20000000 /* Thread 1 */
+#define XUCR0_TRACE_UM_T2 0x10000000 /* Thread 2 */
+#define XUCR0_TRACE_UM_T3 0x08000000 /* Thread 3 */
+
+/* A2 CCR0 register */
+#define A2_CCR0_PME_DISABLED 0x00000000
+#define A2_CCR0_PME_SLEEP 0x40000000
+#define A2_CCR0_PME_RVW 0x80000000
+#define A2_CCR0_PME_DISABLED2 0xc0000000
+
+/* A2 CCR2 register */
+#define A2_CCR2_ERAT_ONLY_MODE 0x00000001
+#define A2_CCR2_ENABLE_ICSWX 0x00000002
+#define A2_CCR2_ENABLE_PC 0x20000000
+#define A2_CCR2_ENABLE_TRACE 0x40000000
+
+#endif /* __ASM_POWERPC_REG_A2_H__ */
diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h
index b316794aa2b5..0f0ad9fa01c1 100644
--- a/arch/powerpc/include/asm/reg_booke.h
+++ b/arch/powerpc/include/asm/reg_booke.h
@@ -27,10 +27,12 @@
#define MSR_CM (1<<31) /* Computation Mode (0=32-bit, 1=64-bit) */
#if defined(CONFIG_PPC_BOOK3E_64)
+#define MSR_64BIT MSR_CM
+
#define MSR_ MSR_ME | MSR_CE
-#define MSR_KERNEL MSR_ | MSR_CM
+#define MSR_KERNEL MSR_ | MSR_64BIT
#define MSR_USER32 MSR_ | MSR_PR | MSR_EE | MSR_DE
-#define MSR_USER64 MSR_USER32 | MSR_CM | MSR_DE
+#define MSR_USER64 MSR_USER32 | MSR_64BIT
#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)
@@ -81,6 +83,10 @@
#define SPRN_IVOR13 0x19D /* Interrupt Vector Offset Register 13 */
#define SPRN_IVOR14 0x19E /* Interrupt Vector Offset Register 14 */
#define SPRN_IVOR15 0x19F /* Interrupt Vector Offset Register 15 */
+#define SPRN_IVOR38 0x1B0 /* Interrupt Vector Offset Register 38 */
+#define SPRN_IVOR39 0x1B1 /* Interrupt Vector Offset Register 39 */
+#define SPRN_IVOR40 0x1B2 /* Interrupt Vector Offset Register 40 */
+#define SPRN_IVOR41 0x1B3 /* Interrupt Vector Offset Register 41 */
#define SPRN_SPEFSCR 0x200 /* SPE & Embedded FP Status & Control */
#define SPRN_BBEAR 0x201 /* Branch Buffer Entry Address Register */
#define SPRN_BBTAR 0x202 /* Branch Buffer Target Address Register */
diff --git a/arch/powerpc/include/asm/rio.h b/arch/powerpc/include/asm/rio.h
index 0018bf80cb25..d902abd33995 100644
--- a/arch/powerpc/include/asm/rio.h
+++ b/arch/powerpc/include/asm/rio.h
@@ -14,5 +14,10 @@
#define ASM_PPC_RIO_H
extern void platform_rio_init(void);
+#ifdef CONFIG_RAPIDIO
+extern int fsl_rio_mcheck_exception(struct pt_regs *);
+#else
+static inline int fsl_rio_mcheck_exception(struct pt_regs *regs) {return 0; }
+#endif
#endif /* ASM_PPC_RIO_H */
diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h
index 9a1193e30f26..58625d1e7802 100644
--- a/arch/powerpc/include/asm/rtas.h
+++ b/arch/powerpc/include/asm/rtas.h
@@ -158,7 +158,50 @@ struct rtas_error_log {
unsigned long target:4; /* Target of failed operation */
unsigned long type:8; /* General event or error*/
unsigned long extended_log_length:32; /* length in bytes */
- unsigned char buffer[1];
+ unsigned char buffer[1]; /* Start of extended log */
+ /* Variable length. */
+};
+
+#define RTAS_V6EXT_LOG_FORMAT_EVENT_LOG 14
+
+#define RTAS_V6EXT_COMPANY_ID_IBM (('I' << 24) | ('B' << 16) | ('M' << 8))
+
+/* RTAS general extended event log, Version 6. The extended log starts
+ * from "buffer" field of struct rtas_error_log defined above.
+ */
+struct rtas_ext_event_log_v6 {
+ /* Byte 0 */
+ uint32_t log_valid:1; /* 1:Log valid */
+ uint32_t unrecoverable_error:1; /* 1:Unrecoverable error */
+ uint32_t recoverable_error:1; /* 1:recoverable (correctable */
+ /* or successfully retried) */
+ uint32_t degraded_operation:1; /* 1:Unrecoverable err, bypassed*/
+ /* - degraded operation (e.g. */
+ /* CPU or mem taken off-line) */
+ uint32_t predictive_error:1;
+ uint32_t new_log:1; /* 1:"New" log (Always 1 for */
+ /* data returned from RTAS */
+ uint32_t big_endian:1; /* 1: Big endian */
+ uint32_t :1; /* reserved */
+ /* Byte 1 */
+ uint32_t :8; /* reserved */
+ /* Byte 2 */
+ uint32_t powerpc_format:1; /* Set to 1 (indicating log is */
+ /* in PowerPC format */
+ uint32_t :3; /* reserved */
+ uint32_t log_format:4; /* Log format indicator. Define */
+ /* format used for byte 12-2047 */
+ /* Byte 3 */
+ uint32_t :8; /* reserved */
+ /* Byte 4-11 */
+ uint8_t reserved[8]; /* reserved */
+ /* Byte 12-15 */
+ uint32_t company_id; /* Company ID of the company */
+ /* that defines the format for */
+ /* the vendor specific log type */
+ /* Byte 16-end of log */
+ uint8_t vendor_log[1]; /* Start of vendor specific log */
+ /* Variable length. */
};
/*
diff --git a/arch/powerpc/include/asm/scom.h b/arch/powerpc/include/asm/scom.h
new file mode 100644
index 000000000000..0cabfd7bc2d1
--- /dev/null
+++ b/arch/powerpc/include/asm/scom.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2010 Benjamin Herrenschmidt, IBM Corp
+ * <benh@kernel.crashing.org>
+ * and David Gibson, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _ASM_POWERPC_SCOM_H
+#define _ASM_POWERPC_SCOM_H
+
+#ifdef __KERNEL__
+#ifndef __ASSEMBLY__
+#ifdef CONFIG_PPC_SCOM
+
+/*
+ * The SCOM bus is a sideband bus used for accessing various internal
+ * registers of the processor or the chipset. The implementation details
+ * differ between processors and platforms, and the access method as
+ * well.
+ *
+ * This API allows to "map" ranges of SCOM register numbers associated
+ * with a given SCOM controller. The later must be represented by a
+ * device node, though some implementations might support NULL if there
+ * is no possible ambiguity
+ *
+ * Then, scom_read/scom_write can be used to accesses registers inside
+ * that range. The argument passed is a register number relative to
+ * the beginning of the range mapped.
+ */
+
+typedef void *scom_map_t;
+
+/* Value for an invalid SCOM map */
+#define SCOM_MAP_INVALID (NULL)
+
+/* The scom_controller data structure is what the platform passes
+ * to the core code in scom_init, it provides the actual implementation
+ * of all the SCOM functions
+ */
+struct scom_controller {
+ scom_map_t (*map)(struct device_node *ctrl_dev, u64 reg, u64 count);
+ void (*unmap)(scom_map_t map);
+
+ u64 (*read)(scom_map_t map, u32 reg);
+ void (*write)(scom_map_t map, u32 reg, u64 value);
+};
+
+extern const struct scom_controller *scom_controller;
+
+/**
+ * scom_init - Initialize the SCOM backend, called by the platform
+ * @controller: The platform SCOM controller
+ */
+static inline void scom_init(const struct scom_controller *controller)
+{
+ scom_controller = controller;
+}
+
+/**
+ * scom_map_ok - Test is a SCOM mapping is successful
+ * @map: The result of scom_map to test
+ */
+static inline int scom_map_ok(scom_map_t map)
+{
+ return map != SCOM_MAP_INVALID;
+}
+
+/**
+ * scom_map - Map a block of SCOM registers
+ * @ctrl_dev: Device node of the SCOM controller
+ * some implementations allow NULL here
+ * @reg: first SCOM register to map
+ * @count: Number of SCOM registers to map
+ */
+
+static inline scom_map_t scom_map(struct device_node *ctrl_dev,
+ u64 reg, u64 count)
+{
+ return scom_controller->map(ctrl_dev, reg, count);
+}
+
+/**
+ * scom_find_parent - Find the SCOM controller for a device
+ * @dev: OF node of the device
+ *
+ * This is not meant for general usage, but in combination with
+ * scom_map() allows to map registers not represented by the
+ * device own scom-reg property. Useful for applying HW workarounds
+ * on things not properly represented in the device-tree for example.
+ */
+struct device_node *scom_find_parent(struct device_node *dev);
+
+
+/**
+ * scom_map_device - Map a device's block of SCOM registers
+ * @dev: OF node of the device
+ * @index: Register bank index (index in "scom-reg" property)
+ *
+ * This function will use the device-tree binding for SCOM which
+ * is to follow "scom-parent" properties until it finds a node with
+ * a "scom-controller" property to find the controller. It will then
+ * use the "scom-reg" property which is made of reg/count pairs,
+ * each of them having a size defined by the controller's #scom-cells
+ * property
+ */
+extern scom_map_t scom_map_device(struct device_node *dev, int index);
+
+
+/**
+ * scom_unmap - Unmap a block of SCOM registers
+ * @map: Result of scom_map is to be unmapped
+ */
+static inline void scom_unmap(scom_map_t map)
+{
+ if (scom_map_ok(map))
+ scom_controller->unmap(map);
+}
+
+/**
+ * scom_read - Read a SCOM register
+ * @map: Result of scom_map
+ * @reg: Register index within that map
+ */
+static inline u64 scom_read(scom_map_t map, u32 reg)
+{
+ return scom_controller->read(map, reg);
+}
+
+/**
+ * scom_write - Write to a SCOM register
+ * @map: Result of scom_map
+ * @reg: Register index within that map
+ * @value: Value to write
+ */
+static inline void scom_write(scom_map_t map, u32 reg, u64 value)
+{
+ scom_controller->write(map, reg, value);
+}
+
+#endif /* CONFIG_PPC_SCOM */
+#endif /* __ASSEMBLY__ */
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_SCOM_H */
diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h
index a902a0d3ae0d..11eb404b5606 100644
--- a/arch/powerpc/include/asm/smp.h
+++ b/arch/powerpc/include/asm/smp.h
@@ -20,6 +20,7 @@
#include <linux/threads.h>
#include <linux/cpumask.h>
#include <linux/kernel.h>
+#include <linux/irqreturn.h>
#ifndef __ASSEMBLY__
@@ -29,14 +30,32 @@
#include <asm/percpu.h>
extern int boot_cpuid;
+extern int boot_cpu_count;
extern void cpu_die(void);
#ifdef CONFIG_SMP
-extern void smp_send_debugger_break(int cpu);
-extern void smp_message_recv(int);
+struct smp_ops_t {
+ void (*message_pass)(int cpu, int msg);
+#ifdef CONFIG_PPC_SMP_MUXED_IPI
+ void (*cause_ipi)(int cpu, unsigned long data);
+#endif
+ int (*probe)(void);
+ int (*kick_cpu)(int nr);
+ void (*setup_cpu)(int nr);
+ void (*bringup_done)(void);
+ void (*take_timebase)(void);
+ void (*give_timebase)(void);
+ int (*cpu_disable)(void);
+ void (*cpu_die)(unsigned int nr);
+ int (*cpu_bootable)(unsigned int nr);
+};
+
+extern void smp_send_debugger_break(void);
extern void start_secondary_resume(void);
+extern void __devinit smp_generic_give_timebase(void);
+extern void __devinit smp_generic_take_timebase(void);
DECLARE_PER_CPU(unsigned int, cpu_pvr);
@@ -93,13 +112,16 @@ extern int cpu_to_core_id(int cpu);
#define PPC_MSG_CALL_FUNC_SINGLE 2
#define PPC_MSG_DEBUGGER_BREAK 3
-/*
- * irq controllers that have dedicated ipis per message and don't
- * need additional code in the action handler may use this
- */
+/* for irq controllers that have dedicated ipis per message (4) */
extern int smp_request_message_ipi(int virq, int message);
extern const char *smp_ipi_name[];
+/* for irq controllers with only a single ipi */
+extern void smp_muxed_ipi_set_data(int cpu, unsigned long data);
+extern void smp_muxed_ipi_message_pass(int cpu, int msg);
+extern void smp_muxed_ipi_resend(void);
+extern irqreturn_t smp_ipi_demux(void);
+
void smp_init_iSeries(void);
void smp_init_pSeries(void);
void smp_init_cell(void);
@@ -149,7 +171,7 @@ extern int smt_enabled_at_boot;
extern int smp_mpic_probe(void);
extern void smp_mpic_setup_cpu(int cpu);
-extern void smp_generic_kick_cpu(int nr);
+extern int smp_generic_kick_cpu(int nr);
extern void smp_generic_give_timebase(void);
extern void smp_generic_take_timebase(void);
diff --git a/arch/powerpc/include/asm/syscall.h b/arch/powerpc/include/asm/syscall.h
index 23913e902fc3..b54b2add07be 100644
--- a/arch/powerpc/include/asm/syscall.h
+++ b/arch/powerpc/include/asm/syscall.h
@@ -15,6 +15,11 @@
#include <linux/sched.h>
+/* ftrace syscalls requires exporting the sys_call_table */
+#ifdef CONFIG_FTRACE_SYSCALLS
+extern const unsigned long *sys_call_table;
+#endif /* CONFIG_FTRACE_SYSCALLS */
+
static inline long syscall_get_nr(struct task_struct *task,
struct pt_regs *regs)
{
diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h
index 60f64b132bd4..8489d372077f 100644
--- a/arch/powerpc/include/asm/systbl.h
+++ b/arch/powerpc/include/asm/systbl.h
@@ -352,3 +352,4 @@ SYSCALL_SPU(name_to_handle_at)
COMPAT_SYS_SPU(open_by_handle_at)
COMPAT_SYS_SPU(clock_adjtime)
SYSCALL_SPU(syncfs)
+COMPAT_SYS_SPU(sendmmsg)
diff --git a/arch/powerpc/include/asm/system.h b/arch/powerpc/include/asm/system.h
index 5e474ddd2273..2dc595dda03b 100644
--- a/arch/powerpc/include/asm/system.h
+++ b/arch/powerpc/include/asm/system.h
@@ -219,8 +219,6 @@ extern int mem_init_done; /* set on boot once kmalloc can be called */
extern int init_bootmem_done; /* set once bootmem is available */
extern phys_addr_t memory_limit;
extern unsigned long klimit;
-
-extern void *alloc_maybe_bootmem(size_t size, gfp_t mask);
extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask);
extern int powersave_nap; /* set if nap mode can be used in idle loop */
diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h
index d8529ef13b23..836f231ec1f0 100644
--- a/arch/powerpc/include/asm/thread_info.h
+++ b/arch/powerpc/include/asm/thread_info.h
@@ -110,7 +110,8 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_NOERROR 12 /* Force successful syscall return */
#define TIF_NOTIFY_RESUME 13 /* callback before returning to user */
#define TIF_FREEZE 14 /* Freezing for suspend */
-#define TIF_RUNLATCH 15 /* Is the runlatch enabled? */
+#define TIF_SYSCALL_TRACEPOINT 15 /* syscall tracepoint instrumentation */
+#define TIF_RUNLATCH 16 /* Is the runlatch enabled? */
/* as above, but as bit values */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
@@ -127,8 +128,10 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_NOERROR (1<<TIF_NOERROR)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
#define _TIF_FREEZE (1<<TIF_FREEZE)
+#define _TIF_SYSCALL_TRACEPOINT (1<<TIF_SYSCALL_TRACEPOINT)
#define _TIF_RUNLATCH (1<<TIF_RUNLATCH)
-#define _TIF_SYSCALL_T_OR_A (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP)
+#define _TIF_SYSCALL_T_OR_A (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
+ _TIF_SECCOMP | _TIF_SYSCALL_TRACEPOINT)
#define _TIF_USER_WORK_MASK (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
_TIF_NOTIFY_RESUME)
@@ -139,10 +142,12 @@ static inline struct thread_info *current_thread_info(void)
#define TLF_NAPPING 0 /* idle thread enabled NAP mode */
#define TLF_SLEEPING 1 /* suspend code enabled SLEEP mode */
#define TLF_RESTORE_SIGMASK 2 /* Restore signal mask in do_signal */
+#define TLF_LAZY_MMU 3 /* tlb_batch is active */
#define _TLF_NAPPING (1 << TLF_NAPPING)
#define _TLF_SLEEPING (1 << TLF_SLEEPING)
#define _TLF_RESTORE_SIGMASK (1 << TLF_RESTORE_SIGMASK)
+#define _TLF_LAZY_MMU (1 << TLF_LAZY_MMU)
#ifndef __ASSEMBLY__
#define HAVE_SET_RESTORE_SIGMASK 1
diff --git a/arch/powerpc/include/asm/tlbflush.h b/arch/powerpc/include/asm/tlbflush.h
index d50a380b2b6f..81143fcbd113 100644
--- a/arch/powerpc/include/asm/tlbflush.h
+++ b/arch/powerpc/include/asm/tlbflush.h
@@ -79,6 +79,8 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm)
#elif defined(CONFIG_PPC_STD_MMU_64)
+#define MMU_NO_CONTEXT 0
+
/*
* TLB flushing for 64-bit hash-MMU CPUs
*/
diff --git a/arch/powerpc/include/asm/udbg.h b/arch/powerpc/include/asm/udbg.h
index 11ae699135ba..58580e94a2bb 100644
--- a/arch/powerpc/include/asm/udbg.h
+++ b/arch/powerpc/include/asm/udbg.h
@@ -52,6 +52,7 @@ extern void __init udbg_init_44x_as1(void);
extern void __init udbg_init_40x_realmode(void);
extern void __init udbg_init_cpm(void);
extern void __init udbg_init_usbgecko(void);
+extern void __init udbg_init_wsp(void);
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_UDBG_H */
diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h
index 3c215648ce6d..6d23c8193caa 100644
--- a/arch/powerpc/include/asm/unistd.h
+++ b/arch/powerpc/include/asm/unistd.h
@@ -371,10 +371,11 @@
#define __NR_open_by_handle_at 346
#define __NR_clock_adjtime 347
#define __NR_syncfs 348
+#define __NR_sendmmsg 349
#ifdef __KERNEL__
-#define __NR_syscalls 349
+#define __NR_syscalls 350
#define __NR__exit __NR_exit
#define NR_syscalls __NR_syscalls
diff --git a/arch/powerpc/include/asm/wsp.h b/arch/powerpc/include/asm/wsp.h
new file mode 100644
index 000000000000..c7dc83088a33
--- /dev/null
+++ b/arch/powerpc/include/asm/wsp.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2011 Michael Ellerman, 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.
+ */
+#ifndef __ASM_POWERPC_WSP_H
+#define __ASM_POWERPC_WSP_H
+
+extern int wsp_get_chip_id(struct device_node *dn);
+
+#endif /* __ASM_POWERPC_WSP_H */
diff --git a/arch/powerpc/include/asm/xics.h b/arch/powerpc/include/asm/xics.h
new file mode 100644
index 000000000000..b183a4062011
--- /dev/null
+++ b/arch/powerpc/include/asm/xics.h
@@ -0,0 +1,142 @@
+/*
+ * Common definitions accross all variants of ICP and ICS interrupt
+ * controllers.
+ */
+
+#ifndef _XICS_H
+#define _XICS_H
+
+#include <linux/interrupt.h>
+
+#define XICS_IPI 2
+#define XICS_IRQ_SPURIOUS 0
+
+/* Want a priority other than 0. Various HW issues require this. */
+#define DEFAULT_PRIORITY 5
+
+/*
+ * Mark IPIs as higher priority so we can take them inside interrupts that
+ * arent marked IRQF_DISABLED
+ */
+#define IPI_PRIORITY 4
+
+/* The least favored priority */
+#define LOWEST_PRIORITY 0xFF
+
+/* The number of priorities defined above */
+#define MAX_NUM_PRIORITIES 3
+
+/* Native ICP */
+extern int icp_native_init(void);
+
+/* PAPR ICP */
+extern int icp_hv_init(void);
+
+/* ICP ops */
+struct icp_ops {
+ unsigned int (*get_irq)(void);
+ void (*eoi)(struct irq_data *d);
+ void (*set_priority)(unsigned char prio);
+ void (*teardown_cpu)(void);
+ void (*flush_ipi)(void);
+#ifdef CONFIG_SMP
+ void (*cause_ipi)(int cpu, unsigned long data);
+ irq_handler_t ipi_action;
+#endif
+};
+
+extern const struct icp_ops *icp_ops;
+
+/* Native ICS */
+extern int ics_native_init(void);
+
+/* RTAS ICS */
+extern int ics_rtas_init(void);
+
+/* ICS instance, hooked up to chip_data of an irq */
+struct ics {
+ struct list_head link;
+ int (*map)(struct ics *ics, unsigned int virq);
+ void (*mask_unknown)(struct ics *ics, unsigned long vec);
+ long (*get_server)(struct ics *ics, unsigned long vec);
+ int (*host_match)(struct ics *ics, struct device_node *node);
+ char data[];
+};
+
+/* Commons */
+extern unsigned int xics_default_server;
+extern unsigned int xics_default_distrib_server;
+extern unsigned int xics_interrupt_server_size;
+extern struct irq_host *xics_host;
+
+struct xics_cppr {
+ unsigned char stack[MAX_NUM_PRIORITIES];
+ int index;
+};
+
+DECLARE_PER_CPU(struct xics_cppr, xics_cppr);
+
+static inline void xics_push_cppr(unsigned int vec)
+{
+ struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr);
+
+ if (WARN_ON(os_cppr->index >= MAX_NUM_PRIORITIES - 1))
+ return;
+
+ if (vec == XICS_IPI)
+ os_cppr->stack[++os_cppr->index] = IPI_PRIORITY;
+ else
+ os_cppr->stack[++os_cppr->index] = DEFAULT_PRIORITY;
+}
+
+static inline unsigned char xics_pop_cppr(void)
+{
+ struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr);
+
+ if (WARN_ON(os_cppr->index < 1))
+ return LOWEST_PRIORITY;
+
+ return os_cppr->stack[--os_cppr->index];
+}
+
+static inline void xics_set_base_cppr(unsigned char cppr)
+{
+ struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr);
+
+ /* we only really want to set the priority when there's
+ * just one cppr value on the stack
+ */
+ WARN_ON(os_cppr->index != 0);
+
+ os_cppr->stack[0] = cppr;
+}
+
+static inline unsigned char xics_cppr_top(void)
+{
+ struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr);
+
+ return os_cppr->stack[os_cppr->index];
+}
+
+DECLARE_PER_CPU_SHARED_ALIGNED(unsigned long, xics_ipi_message);
+
+extern void xics_init(void);
+extern void xics_setup_cpu(void);
+extern void xics_update_irq_servers(void);
+extern void xics_set_cpu_giq(unsigned int gserver, unsigned int join);
+extern void xics_mask_unknown_vec(unsigned int vec);
+extern irqreturn_t xics_ipi_dispatch(int cpu);
+extern int xics_smp_probe(void);
+extern void xics_register_ics(struct ics *ics);
+extern void xics_teardown_cpu(void);
+extern void xics_kexec_teardown_cpu(int secondary);
+extern void xics_migrate_irqs_away(void);
+#ifdef CONFIG_SMP
+extern int xics_get_irq_server(unsigned int virq, const struct cpumask *cpumask,
+ unsigned int strict_check);
+#else
+#define xics_get_irq_server(virq, cpumask, strict_check) (xics_default_server)
+#endif
+
+
+#endif /* _XICS_H */
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 3bb2a3e6a337..e8b981897d44 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -38,11 +38,14 @@ obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.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
+obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_power7.o
obj64-$(CONFIG_RELOCATABLE) += reloc_64.o
obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o idle_book3e.o
+obj-$(CONFIG_PPC_A2) += cpu_setup_a2.o
obj-$(CONFIG_PPC64) += vdso64/
obj-$(CONFIG_ALTIVEC) += vecemu.o
obj-$(CONFIG_PPC_970_NAP) += idle_power4.o
+obj-$(CONFIG_PPC_P7_NAP) += idle_power7.o
obj-$(CONFIG_PPC_OF) += of_platform.o prom_parse.o
obj-$(CONFIG_PPC_CLOCK) += clock.o
procfs-y := proc_powerpc.o
@@ -75,7 +78,6 @@ obj-$(CONFIG_PPC_FSL_BOOK3E) += 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
extra-$(CONFIG_40x) := head_40x.o
extra-$(CONFIG_44x) := head_44x.o
extra-$(CONFIG_FSL_BOOKE) := head_fsl_booke.o
@@ -103,8 +105,11 @@ obj-$(CONFIG_KEXEC) += machine_kexec.o crash.o \
obj-$(CONFIG_AUDIT) += audit.o
obj64-$(CONFIG_AUDIT) += compat_audit.o
+obj-$(CONFIG_PPC_IO_WORKAROUNDS) += io-workarounds.o
+
obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
+obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o
obj-$(CONFIG_PERF_EVENTS) += perf_callchain.o
obj-$(CONFIG_PPC_PERF_CTRS) += perf_event.o
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 23e6a93145ab..36e1c8a29be8 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -74,6 +74,7 @@ int main(void)
DEFINE(AUDITCONTEXT, offsetof(struct task_struct, audit_context));
DEFINE(SIGSEGV, SIGSEGV);
DEFINE(NMI_MASK, NMI_MASK);
+ DEFINE(THREAD_DSCR, offsetof(struct thread_struct, dscr));
#else
DEFINE(THREAD_INFO, offsetof(struct task_struct, stack));
#endif /* CONFIG_PPC64 */
@@ -395,6 +396,7 @@ int main(void)
DEFINE(VCPU_HOST_STACK, offsetof(struct kvm_vcpu, arch.host_stack));
DEFINE(VCPU_HOST_PID, offsetof(struct kvm_vcpu, arch.host_pid));
DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.gpr));
+ DEFINE(VCPU_VRSAVE, offsetof(struct kvm_vcpu, arch.vrsave));
DEFINE(VCPU_SPRG4, offsetof(struct kvm_vcpu, arch.sprg4));
DEFINE(VCPU_SPRG5, offsetof(struct kvm_vcpu, arch.sprg5));
DEFINE(VCPU_SPRG6, offsetof(struct kvm_vcpu, arch.sprg6));
diff --git a/arch/powerpc/kernel/cpu_setup_a2.S b/arch/powerpc/kernel/cpu_setup_a2.S
new file mode 100644
index 000000000000..7f818feaa7a5
--- /dev/null
+++ b/arch/powerpc/kernel/cpu_setup_a2.S
@@ -0,0 +1,114 @@
+/*
+ * A2 specific assembly support code
+ *
+ * Copyright 2009 Ben Herrenschmidt, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/asm-offsets.h>
+#include <asm/ppc_asm.h>
+#include <asm/ppc-opcode.h>
+#include <asm/processor.h>
+#include <asm/reg_a2.h>
+#include <asm/reg.h>
+#include <asm/thread_info.h>
+
+/*
+ * Disable thdid and class fields in ERATs to bump PID to full 14 bits capacity.
+ * This also prevents external LPID accesses but that isn't a problem when not a
+ * guest. Under PV, this setting will be ignored and MMUCR will return the right
+ * number of PID bits we can use.
+ */
+#define MMUCR1_EXTEND_PID \
+ (MMUCR1_ICTID | MMUCR1_ITTID | MMUCR1_DCTID | \
+ MMUCR1_DTTID | MMUCR1_DCCD)
+
+/*
+ * Use extended PIDs if enabled.
+ * Don't clear the ERATs on context sync events and enable I & D LRU.
+ * Enable ERAT back invalidate when tlbwe overwrites an entry.
+ */
+#define INITIAL_MMUCR1 \
+ (MMUCR1_EXTEND_PID | MMUCR1_CSINV_NEVER | MMUCR1_IRRE | \
+ MMUCR1_DRRE | MMUCR1_TLBWE_BINV)
+
+_GLOBAL(__setup_cpu_a2)
+ /* Some of these are actually thread local and some are
+ * core local but doing it always won't hurt
+ */
+
+#ifdef CONFIG_PPC_WSP_COPRO
+ /* Make sure ACOP starts out as zero */
+ li r3,0
+ mtspr SPRN_ACOP,r3
+
+ /* Enable icswx instruction */
+ mfspr r3,SPRN_A2_CCR2
+ ori r3,r3,A2_CCR2_ENABLE_ICSWX
+ mtspr SPRN_A2_CCR2,r3
+
+ /* Unmask all CTs in HACOP */
+ li r3,-1
+ mtspr SPRN_HACOP,r3
+#endif /* CONFIG_PPC_WSP_COPRO */
+
+ /* Enable doorbell */
+ mfspr r3,SPRN_A2_CCR2
+ oris r3,r3,A2_CCR2_ENABLE_PC@h
+ mtspr SPRN_A2_CCR2,r3
+ isync
+
+ /* Setup CCR0 to disable power saving for now as it's busted
+ * in the current implementations. Setup CCR1 to wake on
+ * interrupts normally (we write the default value but who
+ * knows what FW may have clobbered...)
+ */
+ li r3,0
+ mtspr SPRN_A2_CCR0, r3
+ LOAD_REG_IMMEDIATE(r3,0x0f0f0f0f)
+ mtspr SPRN_A2_CCR1, r3
+
+ /* Initialise MMUCR1 */
+ lis r3,INITIAL_MMUCR1@h
+ ori r3,r3,INITIAL_MMUCR1@l
+ mtspr SPRN_MMUCR1,r3
+
+ /* Set MMUCR2 to enable 4K, 64K, 1M, 16M and 1G pages */
+ LOAD_REG_IMMEDIATE(r3, 0x000a7531)
+ mtspr SPRN_MMUCR2,r3
+
+ /* Set MMUCR3 to write all thids bit to the TLB */
+ LOAD_REG_IMMEDIATE(r3, 0x0000000f)
+ mtspr SPRN_MMUCR3,r3
+
+ /* Don't do ERAT stuff if running guest mode */
+ mfmsr r3
+ andis. r0,r3,MSR_GS@h
+ bne 1f
+
+ /* Now set the I-ERAT watermark to 15 */
+ lis r4,(MMUCR0_TLBSEL_I|MMUCR0_ECL)@h
+ mtspr SPRN_MMUCR0, r4
+ li r4,A2_IERAT_SIZE-1
+ PPC_ERATWE(r4,r4,3)
+
+ /* Now set the D-ERAT watermark to 31 */
+ lis r4,(MMUCR0_TLBSEL_D|MMUCR0_ECL)@h
+ mtspr SPRN_MMUCR0, r4
+ li r4,A2_DERAT_SIZE-1
+ PPC_ERATWE(r4,r4,3)
+
+ /* And invalidate the beast just in case. That won't get rid of
+ * a bolted entry though it will be in LRU and so will go away eventually
+ * but let's not bother for now
+ */
+ PPC_ERATILX(0,0,0)
+1:
+ blr
+
+_GLOBAL(__restore_cpu_a2)
+ b __setup_cpu_a2
diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
index 913611105c1f..8053db02b85e 100644
--- a/arch/powerpc/kernel/cpu_setup_fsl_booke.S
+++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S
@@ -88,6 +88,9 @@ _GLOBAL(__setup_cpu_e5500)
bl __e500_dcache_setup
#ifdef CONFIG_PPC_BOOK3E_64
bl .__setup_base_ivors
+ bl .setup_perfmon_ivor
+ bl .setup_doorbell_ivors
+ bl .setup_ehv_ivors
#else
bl __setup_e500mc_ivors
#endif
diff --git a/arch/powerpc/kernel/cpu_setup_power7.S b/arch/powerpc/kernel/cpu_setup_power7.S
new file mode 100644
index 000000000000..4f9a93fcfe07
--- /dev/null
+++ b/arch/powerpc/kernel/cpu_setup_power7.S
@@ -0,0 +1,91 @@
+/*
+ * This file contains low level CPU setup functions.
+ * Copyright (C) 2003 Benjamin Herrenschmidt (benh@kernel.crashing.org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/cputable.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/cache.h>
+
+/* Entry: r3 = crap, r4 = ptr to cputable entry
+ *
+ * Note that we can be called twice for pseudo-PVRs
+ */
+_GLOBAL(__setup_cpu_power7)
+ mflr r11
+ bl __init_hvmode_206
+ mtlr r11
+ beqlr
+ li r0,0
+ mtspr SPRN_LPID,r0
+ bl __init_LPCR
+ bl __init_TLB
+ mtlr r11
+ blr
+
+_GLOBAL(__restore_cpu_power7)
+ mflr r11
+ mfmsr r3
+ rldicl. r0,r3,4,63
+ beqlr
+ li r0,0
+ mtspr SPRN_LPID,r0
+ bl __init_LPCR
+ bl __init_TLB
+ mtlr r11
+ blr
+
+__init_hvmode_206:
+ /* Disable CPU_FTR_HVMODE_206 and exit if MSR:HV is not set */
+ mfmsr r3
+ rldicl. r0,r3,4,63
+ bnelr
+ ld r5,CPU_SPEC_FEATURES(r4)
+ LOAD_REG_IMMEDIATE(r6,CPU_FTR_HVMODE_206)
+ xor r5,r5,r6
+ std r5,CPU_SPEC_FEATURES(r4)
+ blr
+
+__init_LPCR:
+ /* Setup a sane LPCR:
+ *
+ * LPES = 0b01 (HSRR0/1 used for 0x500)
+ * PECE = 0b111
+ * DPFD = 4
+ *
+ * Other bits untouched for now
+ */
+ mfspr r3,SPRN_LPCR
+ ori r3,r3,(LPCR_LPES0|LPCR_LPES1)
+ xori r3,r3, LPCR_LPES0
+ ori r3,r3,(LPCR_PECE0|LPCR_PECE1|LPCR_PECE2)
+ li r5,7
+ sldi r5,r5,LPCR_DPFD_SH
+ andc r3,r3,r5
+ li r5,4
+ sldi r5,r5,LPCR_DPFD_SH
+ or r3,r3,r5
+ mtspr SPRN_LPCR,r3
+ isync
+ blr
+
+__init_TLB:
+ /* Clear the TLB */
+ li r6,128
+ mtctr r6
+ li r7,0xc00 /* IS field = 0b11 */
+ ptesync
+2: tlbiel r7
+ addi r7,r7,0x1000
+ bdnz 2b
+ ptesync
+1: blr
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index b9602ee06deb..34d2722b9451 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -62,10 +62,12 @@ extern void __setup_cpu_745x(unsigned long offset, struct cpu_spec* spec);
extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec);
extern void __setup_cpu_ppc970MP(unsigned long offset, struct cpu_spec* spec);
extern void __setup_cpu_pa6t(unsigned long offset, struct cpu_spec* spec);
+extern void __setup_cpu_a2(unsigned long offset, struct cpu_spec* spec);
extern void __restore_cpu_pa6t(void);
extern void __restore_cpu_ppc970(void);
extern void __setup_cpu_power7(unsigned long offset, struct cpu_spec* spec);
extern void __restore_cpu_power7(void);
+extern void __restore_cpu_a2(void);
#endif /* CONFIG_PPC64 */
#if defined(CONFIG_E500)
extern void __setup_cpu_e5500(unsigned long offset, struct cpu_spec* spec);
@@ -199,7 +201,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_name = "POWER4 (gp)",
.cpu_features = CPU_FTRS_POWER4,
.cpu_user_features = COMMON_USER_POWER4,
- .mmu_features = MMU_FTR_HPTE_TABLE,
+ .mmu_features = MMU_FTRS_POWER4,
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 8,
@@ -214,7 +216,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_name = "POWER4+ (gq)",
.cpu_features = CPU_FTRS_POWER4,
.cpu_user_features = COMMON_USER_POWER4,
- .mmu_features = MMU_FTR_HPTE_TABLE,
+ .mmu_features = MMU_FTRS_POWER4,
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 8,
@@ -230,7 +232,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_features = CPU_FTRS_PPC970,
.cpu_user_features = COMMON_USER_POWER4 |
PPC_FEATURE_HAS_ALTIVEC_COMP,
- .mmu_features = MMU_FTR_HPTE_TABLE,
+ .mmu_features = MMU_FTRS_PPC970,
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 8,
@@ -248,7 +250,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_features = CPU_FTRS_PPC970,
.cpu_user_features = COMMON_USER_POWER4 |
PPC_FEATURE_HAS_ALTIVEC_COMP,
- .mmu_features = MMU_FTR_HPTE_TABLE,
+ .mmu_features = MMU_FTRS_PPC970,
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 8,
@@ -284,7 +286,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_features = CPU_FTRS_PPC970,
.cpu_user_features = COMMON_USER_POWER4 |
PPC_FEATURE_HAS_ALTIVEC_COMP,
- .mmu_features = MMU_FTR_HPTE_TABLE,
+ .mmu_features = MMU_FTRS_PPC970,
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 8,
@@ -302,7 +304,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_features = CPU_FTRS_PPC970,
.cpu_user_features = COMMON_USER_POWER4 |
PPC_FEATURE_HAS_ALTIVEC_COMP,
- .mmu_features = MMU_FTR_HPTE_TABLE,
+ .mmu_features = MMU_FTRS_PPC970,
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 8,
@@ -318,7 +320,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_name = "POWER5 (gr)",
.cpu_features = CPU_FTRS_POWER5,
.cpu_user_features = COMMON_USER_POWER5,
- .mmu_features = MMU_FTR_HPTE_TABLE,
+ .mmu_features = MMU_FTRS_POWER5,
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 6,
@@ -338,7 +340,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_name = "POWER5+ (gs)",
.cpu_features = CPU_FTRS_POWER5,
.cpu_user_features = COMMON_USER_POWER5_PLUS,
- .mmu_features = MMU_FTR_HPTE_TABLE,
+ .mmu_features = MMU_FTRS_POWER5,
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 6,
@@ -354,7 +356,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_name = "POWER5+ (gs)",
.cpu_features = CPU_FTRS_POWER5,
.cpu_user_features = COMMON_USER_POWER5_PLUS,
- .mmu_features = MMU_FTR_HPTE_TABLE,
+ .mmu_features = MMU_FTRS_POWER5,
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 6,
@@ -371,7 +373,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_name = "POWER5+",
.cpu_features = CPU_FTRS_POWER5,
.cpu_user_features = COMMON_USER_POWER5_PLUS,
- .mmu_features = MMU_FTR_HPTE_TABLE,
+ .mmu_features = MMU_FTRS_POWER5,
.icache_bsize = 128,
.dcache_bsize = 128,
.oprofile_cpu_type = "ppc64/ibm-compat-v1",
@@ -385,7 +387,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_features = CPU_FTRS_POWER6,
.cpu_user_features = COMMON_USER_POWER6 |
PPC_FEATURE_POWER6_EXT,
- .mmu_features = MMU_FTR_HPTE_TABLE,
+ .mmu_features = MMU_FTRS_POWER6,
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 6,
@@ -404,7 +406,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_name = "POWER6 (architected)",
.cpu_features = CPU_FTRS_POWER6,
.cpu_user_features = COMMON_USER_POWER6,
- .mmu_features = MMU_FTR_HPTE_TABLE,
+ .mmu_features = MMU_FTRS_POWER6,
.icache_bsize = 128,
.dcache_bsize = 128,
.oprofile_cpu_type = "ppc64/ibm-compat-v1",
@@ -417,12 +419,13 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_name = "POWER7 (architected)",
.cpu_features = CPU_FTRS_POWER7,
.cpu_user_features = COMMON_USER_POWER7,
- .mmu_features = MMU_FTR_HPTE_TABLE |
- MMU_FTR_TLBIE_206,
+ .mmu_features = MMU_FTRS_POWER7,
.icache_bsize = 128,
.dcache_bsize = 128,
.oprofile_type = PPC_OPROFILE_POWER4,
.oprofile_cpu_type = "ppc64/ibm-compat-v1",
+ .cpu_setup = __setup_cpu_power7,
+ .cpu_restore = __restore_cpu_power7,
.platform = "power7",
},
{ /* Power7 */
@@ -431,14 +434,15 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_name = "POWER7 (raw)",
.cpu_features = CPU_FTRS_POWER7,
.cpu_user_features = COMMON_USER_POWER7,
- .mmu_features = MMU_FTR_HPTE_TABLE |
- MMU_FTR_TLBIE_206,
+ .mmu_features = MMU_FTRS_POWER7,
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 6,
.pmc_type = PPC_PMC_IBM,
.oprofile_cpu_type = "ppc64/power7",
.oprofile_type = PPC_OPROFILE_POWER4,
+ .cpu_setup = __setup_cpu_power7,
+ .cpu_restore = __restore_cpu_power7,
.platform = "power7",
},
{ /* Power7+ */
@@ -447,14 +451,15 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_name = "POWER7+ (raw)",
.cpu_features = CPU_FTRS_POWER7,
.cpu_user_features = COMMON_USER_POWER7,
- .mmu_features = MMU_FTR_HPTE_TABLE |
- MMU_FTR_TLBIE_206,
+ .mmu_features = MMU_FTRS_POWER7,
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 6,
.pmc_type = PPC_PMC_IBM,
.oprofile_cpu_type = "ppc64/power7",
.oprofile_type = PPC_OPROFILE_POWER4,
+ .cpu_setup = __setup_cpu_power7,
+ .cpu_restore = __restore_cpu_power7,
.platform = "power7+",
},
{ /* Cell Broadband Engine */
@@ -465,7 +470,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_user_features = COMMON_USER_PPC64 |
PPC_FEATURE_CELL | PPC_FEATURE_HAS_ALTIVEC_COMP |
PPC_FEATURE_SMT,
- .mmu_features = MMU_FTR_HPTE_TABLE,
+ .mmu_features = MMU_FTRS_CELL,
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 4,
@@ -480,7 +485,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_name = "PA6T",
.cpu_features = CPU_FTRS_PA6T,
.cpu_user_features = COMMON_USER_PA6T,
- .mmu_features = MMU_FTR_HPTE_TABLE,
+ .mmu_features = MMU_FTRS_PA6T,
.icache_bsize = 64,
.dcache_bsize = 64,
.num_pmcs = 6,
@@ -497,7 +502,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_name = "POWER4 (compatible)",
.cpu_features = CPU_FTRS_COMPATIBLE,
.cpu_user_features = COMMON_USER_PPC64,
- .mmu_features = MMU_FTR_HPTE_TABLE,
+ .mmu_features = MMU_FTRS_DEFAULT_HPTE_ARCH_V2,
.icache_bsize = 128,
.dcache_bsize = 128,
.num_pmcs = 6,
@@ -2005,7 +2010,22 @@ static struct cpu_spec __initdata cpu_specs[] = {
#endif /* CONFIG_PPC32 */
#endif /* CONFIG_E500 */
-#ifdef CONFIG_PPC_BOOK3E_64
+#ifdef CONFIG_PPC_A2
+ { /* Standard A2 (>= DD2) + FPU core */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x00480000,
+ .cpu_name = "A2 (>= DD2)",
+ .cpu_features = CPU_FTRS_A2,
+ .cpu_user_features = COMMON_USER_PPC64,
+ .mmu_features = MMU_FTRS_A2,
+ .icache_bsize = 64,
+ .dcache_bsize = 64,
+ .num_pmcs = 0,
+ .cpu_setup = __setup_cpu_a2,
+ .cpu_restore = __restore_cpu_a2,
+ .machine_check = machine_check_generic,
+ .platform = "ppca2",
+ },
{ /* This is a default entry to get going, to be replaced by
* a real one at some stage
*/
@@ -2026,7 +2046,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.machine_check = machine_check_generic,
.platform = "power6",
},
-#endif
+#endif /* CONFIG_PPC_A2 */
};
static struct cpu_spec the_cpu_spec;
diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c
index 5b5e1f002a8e..4e6ee944495a 100644
--- a/arch/powerpc/kernel/crash.c
+++ b/arch/powerpc/kernel/crash.c
@@ -64,9 +64,9 @@ void crash_ipi_callback(struct pt_regs *regs)
return;
hard_irq_disable();
- if (!cpu_isset(cpu, cpus_in_crash))
+ if (!cpumask_test_cpu(cpu, &cpus_in_crash))
crash_save_cpu(regs, cpu);
- cpu_set(cpu, cpus_in_crash);
+ cpumask_set_cpu(cpu, &cpus_in_crash);
/*
* Entered via soft-reset - could be the kdump
@@ -77,8 +77,8 @@ void crash_ipi_callback(struct pt_regs *regs)
* Tell the kexec CPU that entered via soft-reset and ready
* to go down.
*/
- if (cpu_isset(cpu, cpus_in_sr)) {
- cpu_clear(cpu, cpus_in_sr);
+ if (cpumask_test_cpu(cpu, &cpus_in_sr)) {
+ cpumask_clear_cpu(cpu, &cpus_in_sr);
atomic_inc(&enter_on_soft_reset);
}
@@ -87,7 +87,7 @@ void crash_ipi_callback(struct pt_regs *regs)
* This barrier is needed to make sure that all CPUs are stopped.
* If not, soft-reset will be invoked to bring other CPUs.
*/
- while (!cpu_isset(crashing_cpu, cpus_in_crash))
+ while (!cpumask_test_cpu(crashing_cpu, &cpus_in_crash))
cpu_relax();
if (ppc_md.kexec_cpu_down)
@@ -109,7 +109,7 @@ static void crash_soft_reset_check(int cpu)
{
unsigned int ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */
- cpu_clear(cpu, cpus_in_sr);
+ cpumask_clear_cpu(cpu, &cpus_in_sr);
while (atomic_read(&enter_on_soft_reset) != ncpus)
cpu_relax();
}
@@ -132,7 +132,7 @@ static void crash_kexec_prepare_cpus(int cpu)
*/
printk(KERN_EMERG "Sending IPI to other cpus...\n");
msecs = 10000;
- while ((cpus_weight(cpus_in_crash) < ncpus) && (--msecs > 0)) {
+ while ((cpumask_weight(&cpus_in_crash) < ncpus) && (--msecs > 0)) {
cpu_relax();
mdelay(1);
}
@@ -144,52 +144,24 @@ static void crash_kexec_prepare_cpus(int cpu)
* user to do soft reset such that we get all.
* Soft-reset will be used until better mechanism is implemented.
*/
- if (cpus_weight(cpus_in_crash) < ncpus) {
+ if (cpumask_weight(&cpus_in_crash) < ncpus) {
printk(KERN_EMERG "done waiting: %d cpu(s) not responding\n",
- ncpus - cpus_weight(cpus_in_crash));
+ ncpus - cpumask_weight(&cpus_in_crash));
printk(KERN_EMERG "Activate soft-reset to stop other cpu(s)\n");
- cpus_in_sr = CPU_MASK_NONE;
+ cpumask_clear(&cpus_in_sr);
atomic_set(&enter_on_soft_reset, 0);
- while (cpus_weight(cpus_in_crash) < ncpus)
+ while (cpumask_weight(&cpus_in_crash) < ncpus)
cpu_relax();
}
/*
* Make sure all CPUs are entered via soft-reset if the kdump is
* invoked using soft-reset.
*/
- if (cpu_isset(cpu, cpus_in_sr))
+ if (cpumask_test_cpu(cpu, &cpus_in_sr))
crash_soft_reset_check(cpu);
/* Leave the IPI callback set */
}
-/* wait for all the CPUs to hit real mode but timeout if they don't come in */
-#ifdef CONFIG_PPC_STD_MMU_64
-static void crash_kexec_wait_realmode(int cpu)
-{
- unsigned int msecs;
- int i;
-
- msecs = 10000;
- for (i=0; i < NR_CPUS && msecs > 0; i++) {
- if (i == cpu)
- continue;
-
- while (paca[i].kexec_state < KEXEC_STATE_REAL_MODE) {
- barrier();
- if (!cpu_possible(i)) {
- break;
- }
- if (!cpu_online(i)) {
- break;
- }
- msecs--;
- mdelay(1);
- }
- }
- mb();
-}
-#endif /* CONFIG_PPC_STD_MMU_64 */
-
/*
* This function will be called by secondary cpus or by kexec cpu
* if soft-reset is activated to stop some CPUs.
@@ -210,7 +182,7 @@ void crash_kexec_secondary(struct pt_regs *regs)
* exited using 'x'(exit and recover) or
* kexec_should_crash() failed for all running tasks.
*/
- cpu_clear(cpu, cpus_in_sr);
+ cpumask_clear_cpu(cpu, &cpus_in_sr);
local_irq_restore(flags);
return;
}
@@ -224,7 +196,7 @@ void crash_kexec_secondary(struct pt_regs *regs)
* then start kexec boot.
*/
crash_soft_reset_check(cpu);
- cpu_set(crashing_cpu, cpus_in_crash);
+ cpumask_set_cpu(crashing_cpu, &cpus_in_crash);
if (ppc_md.kexec_cpu_down)
ppc_md.kexec_cpu_down(1, 0);
machine_kexec(kexec_crash_image);
@@ -234,7 +206,6 @@ void crash_kexec_secondary(struct pt_regs *regs)
}
#else /* ! CONFIG_SMP */
-static inline void crash_kexec_wait_realmode(int cpu) {}
static void crash_kexec_prepare_cpus(int cpu)
{
@@ -253,10 +224,40 @@ static void crash_kexec_prepare_cpus(int cpu)
void crash_kexec_secondary(struct pt_regs *regs)
{
- cpus_in_sr = CPU_MASK_NONE;
+ cpumask_clear(&cpus_in_sr);
}
#endif /* CONFIG_SMP */
+/* wait for all the CPUs to hit real mode but timeout if they don't come in */
+#if defined(CONFIG_SMP) && defined(CONFIG_PPC_STD_MMU_64)
+static void crash_kexec_wait_realmode(int cpu)
+{
+ unsigned int msecs;
+ int i;
+
+ msecs = 10000;
+ for (i=0; i < nr_cpu_ids && msecs > 0; i++) {
+ if (i == cpu)
+ continue;
+
+ while (paca[i].kexec_state < KEXEC_STATE_REAL_MODE) {
+ barrier();
+ if (!cpu_possible(i)) {
+ break;
+ }
+ if (!cpu_online(i)) {
+ break;
+ }
+ msecs--;
+ mdelay(1);
+ }
+ }
+ mb();
+}
+#else
+static inline void crash_kexec_wait_realmode(int cpu) {}
+#endif /* CONFIG_SMP && CONFIG_PPC_STD_MMU_64 */
+
/*
* Register a function to be called on shutdown. Only use this if you
* can't reset your device in the second kernel.
@@ -345,7 +346,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
crashing_cpu = smp_processor_id();
crash_save_cpu(regs, crashing_cpu);
crash_kexec_prepare_cpus(crashing_cpu);
- cpu_set(crashing_cpu, cpus_in_crash);
+ cpumask_set_cpu(crashing_cpu, &cpus_in_crash);
crash_kexec_wait_realmode(crashing_cpu);
machine_kexec_mask_interrupts();
diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c
index 3307a52d797f..2cc451aaaca7 100644
--- a/arch/powerpc/kernel/dbell.c
+++ b/arch/powerpc/kernel/dbell.c
@@ -13,84 +13,35 @@
#include <linux/kernel.h>
#include <linux/smp.h>
#include <linux/threads.h>
-#include <linux/percpu.h>
+#include <linux/hardirq.h>
#include <asm/dbell.h>
#include <asm/irq_regs.h>
#ifdef CONFIG_SMP
-struct doorbell_cpu_info {
- unsigned long messages; /* current messages bits */
- unsigned int tag; /* tag value */
-};
-
-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);
+ unsigned long tag = mfspr(SPRN_PIR) & 0x3fff;
- info->messages = 0;
- info->tag = mfspr(SPRN_PIR) & 0x3fff;
+ smp_muxed_ipi_set_data(smp_processor_id(), tag);
}
-void doorbell_message_pass(int target, int msg)
+void doorbell_cause_ipi(int cpu, unsigned long data)
{
- struct doorbell_cpu_info *info;
- int i;
-
- 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) {
- for_each_online_cpu(i) {
- if (i == smp_processor_id())
- continue;
- 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) {
- info = &per_cpu(doorbell_cpu_info, i);
- set_bit(msg, &info->messages);
- }
- ppc_msgsnd(PPC_DBELL, PPC_DBELL_MSG_BRDCAST, 0);
- }
+ ppc_msgsnd(PPC_DBELL, 0, data);
}
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 */
+ irq_enter();
- if (!info->messages || (num_online_cpus() < 2))
- goto out;
+ smp_ipi_demux();
- for (msg = 0; msg < 4; msg++)
- if (test_and_clear_bit(msg, &info->messages))
- smp_message_recv(msg);
-
-out:
+ irq_exit();
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)
{
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index d82878c4daa6..d834425186ae 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -421,6 +421,12 @@ BEGIN_FTR_SECTION
std r24,THREAD_VRSAVE(r3)
END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
#endif /* CONFIG_ALTIVEC */
+#ifdef CONFIG_PPC64
+BEGIN_FTR_SECTION
+ mfspr r25,SPRN_DSCR
+ std r25,THREAD_DSCR(r3)
+END_FTR_SECTION_IFSET(CPU_FTR_DSCR)
+#endif
and. r0,r0,r22
beq+ 1f
andc r22,r22,r0
@@ -462,10 +468,10 @@ BEGIN_FTR_SECTION
FTR_SECTION_ELSE_NESTED(95)
clrrdi r6,r8,40 /* get its 1T ESID */
clrrdi r9,r1,40 /* get current sp 1T ESID */
- ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_1T_SEGMENT, 95)
+ ALT_MMU_FTR_SECTION_END_NESTED_IFCLR(MMU_FTR_1T_SEGMENT, 95)
FTR_SECTION_ELSE
b 2f
-ALT_FTR_SECTION_END_IFSET(CPU_FTR_SLB)
+ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_SLB)
clrldi. r0,r6,2 /* is new ESID c00000000? */
cmpd cr1,r6,r9 /* or is new ESID the same as current ESID? */
cror eq,4*cr1+eq,eq
@@ -479,7 +485,7 @@ BEGIN_FTR_SECTION
li r9,MMU_SEGSIZE_1T /* insert B field */
oris r6,r6,(MMU_SEGSIZE_1T << SLBIE_SSIZE_SHIFT)@h
rldimi r7,r9,SLB_VSID_SSIZE_SHIFT,0
-END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT)
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
/* Update the last bolted SLB. No write barriers are needed
* here, provided we only update the current CPU's SLB shadow
@@ -491,7 +497,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT)
std r7,SLBSHADOW_STACKVSID(r9) /* Save VSID */
std r0,SLBSHADOW_STACKESID(r9) /* Save ESID */
- /* No need to check for CPU_FTR_NO_SLBIE_B here, since when
+ /* No need to check for MMU_FTR_NO_SLBIE_B here, since when
* we have 1TB segments, the only CPUs known to have the errata
* only support less than 1TB of system memory and we'll never
* actually hit this code path.
@@ -522,6 +528,15 @@ BEGIN_FTR_SECTION
mtspr SPRN_VRSAVE,r0 /* if G4, restore VRSAVE reg */
END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
#endif /* CONFIG_ALTIVEC */
+#ifdef CONFIG_PPC64
+BEGIN_FTR_SECTION
+ ld r0,THREAD_DSCR(r4)
+ cmpd r0,r25
+ beq 1f
+ mtspr SPRN_DSCR,r0
+1:
+END_FTR_SECTION_IFSET(CPU_FTR_DSCR)
+#endif
/* r3-r13 are destroyed -- Cort */
REST_8GPRS(14, r1)
@@ -838,7 +853,7 @@ _GLOBAL(enter_rtas)
_STATIC(rtas_return_loc)
/* relocation is off at this point */
- mfspr r4,SPRN_SPRG_PACA /* Get PACA */
+ GET_PACA(r4)
clrldi r4,r4,2 /* convert to realmode address */
bcl 20,31,$+4
@@ -869,7 +884,7 @@ _STATIC(rtas_restore_regs)
REST_8GPRS(14, r1) /* Restore the non-volatiles */
REST_10GPRS(22, r1) /* ditto */
- mfspr r13,SPRN_SPRG_PACA
+ GET_PACA(r13)
ld r4,_CCR(r1)
mtcr r4
diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S
index 9651acc3504a..d24d4400cc79 100644
--- a/arch/powerpc/kernel/exceptions-64e.S
+++ b/arch/powerpc/kernel/exceptions-64e.S
@@ -17,6 +17,7 @@
#include <asm/cputable.h>
#include <asm/setup.h>
#include <asm/thread_info.h>
+#include <asm/reg_a2.h>
#include <asm/exception-64e.h>
#include <asm/bug.h>
#include <asm/irqflags.h>
@@ -252,9 +253,6 @@ exception_marker:
.balign 0x1000
.globl interrupt_base_book3e
interrupt_base_book3e: /* fake trap */
- /* Note: If real debug exceptions are supported by the HW, the vector
- * below will have to be patched up to point to an appropriate handler
- */
EXCEPTION_STUB(0x000, machine_check) /* 0x0200 */
EXCEPTION_STUB(0x020, critical_input) /* 0x0580 */
EXCEPTION_STUB(0x040, debug_crit) /* 0x0d00 */
@@ -271,8 +269,13 @@ interrupt_base_book3e: /* fake trap */
EXCEPTION_STUB(0x1a0, watchdog) /* 0x09f0 */
EXCEPTION_STUB(0x1c0, data_tlb_miss)
EXCEPTION_STUB(0x1e0, instruction_tlb_miss)
+ EXCEPTION_STUB(0x260, perfmon)
EXCEPTION_STUB(0x280, doorbell)
EXCEPTION_STUB(0x2a0, doorbell_crit)
+ EXCEPTION_STUB(0x2c0, guest_doorbell)
+ EXCEPTION_STUB(0x2e0, guest_doorbell_crit)
+ EXCEPTION_STUB(0x300, hypercall)
+ EXCEPTION_STUB(0x320, ehpriv)
.globl interrupt_end_book3e
interrupt_end_book3e:
@@ -454,6 +457,70 @@ interrupt_end_book3e:
kernel_dbg_exc:
b . /* NYI */
+/* Debug exception as a debug interrupt*/
+ START_EXCEPTION(debug_debug);
+ DBG_EXCEPTION_PROLOG(0xd00, PROLOG_ADDITION_2REGS)
+
+ /*
+ * If there is a single step or branch-taken exception in an
+ * exception entry sequence, it was probably meant to apply to
+ * the code where the exception occurred (since exception entry
+ * doesn't turn off DE automatically). We simulate the effect
+ * of turning off DE on entry to an exception handler by turning
+ * off DE in the DSRR1 value and clearing the debug status.
+ */
+
+ mfspr r14,SPRN_DBSR /* check single-step/branch taken */
+ andis. r15,r14,DBSR_IC@h
+ beq+ 1f
+
+ LOAD_REG_IMMEDIATE(r14,interrupt_base_book3e)
+ LOAD_REG_IMMEDIATE(r15,interrupt_end_book3e)
+ cmpld cr0,r10,r14
+ cmpld cr1,r10,r15
+ blt+ cr0,1f
+ bge+ cr1,1f
+
+ /* here it looks like we got an inappropriate debug exception. */
+ lis r14,DBSR_IC@h /* clear the IC event */
+ rlwinm r11,r11,0,~MSR_DE /* clear DE in the DSRR1 value */
+ mtspr SPRN_DBSR,r14
+ mtspr SPRN_DSRR1,r11
+ lwz r10,PACA_EXDBG+EX_CR(r13) /* restore registers */
+ ld r1,PACA_EXDBG+EX_R1(r13)
+ ld r14,PACA_EXDBG+EX_R14(r13)
+ ld r15,PACA_EXDBG+EX_R15(r13)
+ mtcr r10
+ ld r10,PACA_EXDBG+EX_R10(r13) /* restore registers */
+ ld r11,PACA_EXDBG+EX_R11(r13)
+ mfspr r13,SPRN_SPRG_DBG_SCRATCH
+ rfdi
+
+ /* Normal debug exception */
+ /* XXX We only handle coming from userspace for now since we can't
+ * quite save properly an interrupted kernel state yet
+ */
+1: andi. r14,r11,MSR_PR; /* check for userspace again */
+ beq kernel_dbg_exc; /* if from kernel mode */
+
+ /* Now we mash up things to make it look like we are coming on a
+ * normal exception
+ */
+ mfspr r15,SPRN_SPRG_DBG_SCRATCH
+ mtspr SPRN_SPRG_GEN_SCRATCH,r15
+ mfspr r14,SPRN_DBSR
+ EXCEPTION_COMMON(0xd00, PACA_EXDBG, INTS_DISABLE_ALL)
+ std r14,_DSISR(r1)
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ mr r4,r14
+ ld r14,PACA_EXDBG+EX_R14(r13)
+ ld r15,PACA_EXDBG+EX_R15(r13)
+ bl .save_nvgprs
+ bl .DebugException
+ b .ret_from_except
+
+ MASKABLE_EXCEPTION(0x260, perfmon, .performance_monitor_exception, ACK_NONE)
+
/* Doorbell interrupt */
MASKABLE_EXCEPTION(0x2070, doorbell, .doorbell_exception, ACK_NONE)
@@ -468,6 +535,11 @@ kernel_dbg_exc:
// b ret_from_crit_except
b .
+ MASKABLE_EXCEPTION(0x2c0, guest_doorbell, .unknown_exception, ACK_NONE)
+ MASKABLE_EXCEPTION(0x2e0, guest_doorbell_crit, .unknown_exception, ACK_NONE)
+ MASKABLE_EXCEPTION(0x310, hypercall, .unknown_exception, ACK_NONE)
+ MASKABLE_EXCEPTION(0x320, ehpriv, .unknown_exception, ACK_NONE)
+
/*
* An interrupt came in while soft-disabled; clear EE in SRR1,
@@ -587,7 +659,12 @@ fast_exception_return:
BAD_STACK_TRAMPOLINE(0x000)
BAD_STACK_TRAMPOLINE(0x100)
BAD_STACK_TRAMPOLINE(0x200)
+BAD_STACK_TRAMPOLINE(0x260)
+BAD_STACK_TRAMPOLINE(0x2c0)
+BAD_STACK_TRAMPOLINE(0x2e0)
BAD_STACK_TRAMPOLINE(0x300)
+BAD_STACK_TRAMPOLINE(0x310)
+BAD_STACK_TRAMPOLINE(0x320)
BAD_STACK_TRAMPOLINE(0x400)
BAD_STACK_TRAMPOLINE(0x500)
BAD_STACK_TRAMPOLINE(0x600)
@@ -864,8 +941,23 @@ have_hes:
* that will have to be made dependent on whether we are running under
* a hypervisor I suppose.
*/
- ori r3,r3,MAS0_HES | MAS0_WQ_ALLWAYS
- mtspr SPRN_MAS0,r3
+
+ /* BEWARE, MAGIC
+ * This code is called as an ordinary function on the boot CPU. But to
+ * avoid duplication, this code is also used in SCOM bringup of
+ * secondary CPUs. We read the code between the initial_tlb_code_start
+ * and initial_tlb_code_end labels one instruction at a time and RAM it
+ * into the new core via SCOM. That doesn't process branches, so there
+ * must be none between those two labels. It also means if this code
+ * ever takes any parameters, the SCOM code must also be updated to
+ * provide them.
+ */
+ .globl a2_tlbinit_code_start
+a2_tlbinit_code_start:
+
+ ori r11,r3,MAS0_WQ_ALLWAYS
+ oris r11,r11,MAS0_ESEL(3)@h /* Use way 3: workaround A2 erratum 376 */
+ mtspr SPRN_MAS0,r11
lis r3,(MAS1_VALID | MAS1_IPROT)@h
ori r3,r3,BOOK3E_PAGESZ_1GB << MAS1_TSIZE_SHIFT
mtspr SPRN_MAS1,r3
@@ -879,18 +971,86 @@ have_hes:
/* Write the TLB entry */
tlbwe
+ .globl a2_tlbinit_after_linear_map
+a2_tlbinit_after_linear_map:
+
/* Now we branch the new virtual address mapped by this entry */
LOAD_REG_IMMEDIATE(r3,1f)
mtctr r3
bctr
1: /* We are now running at PAGE_OFFSET, clean the TLB of everything
- * else (XXX we should scan for bolted crap from the firmware too)
+ * else (including IPROTed things left by firmware)
+ * r4 = TLBnCFG
+ * r3 = current address (more or less)
*/
+
+ li r5,0
+ mtspr SPRN_MAS6,r5
+ tlbsx 0,r3
+
+ rlwinm r9,r4,0,TLBnCFG_N_ENTRY
+ rlwinm r10,r4,8,0xff
+ addi r10,r10,-1 /* Get inner loop mask */
+
+ li r3,1
+
+ mfspr r5,SPRN_MAS1
+ rlwinm r5,r5,0,(~(MAS1_VALID|MAS1_IPROT))
+
+ mfspr r6,SPRN_MAS2
+ rldicr r6,r6,0,51 /* Extract EPN */
+
+ mfspr r7,SPRN_MAS0
+ rlwinm r7,r7,0,0xffff0fff /* Clear HES and WQ */
+
+ rlwinm r8,r7,16,0xfff /* Extract ESEL */
+
+2: add r4,r3,r8
+ and r4,r4,r10
+
+ rlwimi r7,r4,16,MAS0_ESEL_MASK
+
+ mtspr SPRN_MAS0,r7
+ mtspr SPRN_MAS1,r5
+ mtspr SPRN_MAS2,r6
+ tlbwe
+
+ addi r3,r3,1
+ and. r4,r3,r10
+
+ bne 3f
+ addis r6,r6,(1<<30)@h
+3:
+ cmpw r3,r9
+ blt 2b
+
+ .globl a2_tlbinit_after_iprot_flush
+a2_tlbinit_after_iprot_flush:
+
+#ifdef CONFIG_PPC_EARLY_DEBUG_WSP
+ /* Now establish early debug mappings if applicable */
+ /* Restore the MAS0 we used for linear mapping load */
+ mtspr SPRN_MAS0,r11
+
+ lis r3,(MAS1_VALID | MAS1_IPROT)@h
+ ori r3,r3,(BOOK3E_PAGESZ_4K << MAS1_TSIZE_SHIFT)
+ mtspr SPRN_MAS1,r3
+ LOAD_REG_IMMEDIATE(r3, WSP_UART_VIRT | MAS2_I | MAS2_G)
+ mtspr SPRN_MAS2,r3
+ LOAD_REG_IMMEDIATE(r3, WSP_UART_PHYS | MAS3_SR | MAS3_SW)
+ mtspr SPRN_MAS7_MAS3,r3
+ /* re-use the MAS8 value from the linear mapping */
+ tlbwe
+#endif /* CONFIG_PPC_EARLY_DEBUG_WSP */
+
PPC_TLBILX(0,0,0)
sync
isync
+ .globl a2_tlbinit_code_end
+a2_tlbinit_code_end:
+
/* We translate LR and return */
mflr r3
tovirt(r3,r3)
@@ -1040,3 +1200,33 @@ _GLOBAL(__setup_base_ivors)
sync
blr
+
+_GLOBAL(setup_perfmon_ivor)
+ SET_IVOR(35, 0x260) /* Performance Monitor */
+ blr
+
+_GLOBAL(setup_doorbell_ivors)
+ SET_IVOR(36, 0x280) /* Processor Doorbell */
+ SET_IVOR(37, 0x2a0) /* Processor Doorbell Crit */
+
+ /* Check MMUCFG[LPIDSIZE] to determine if we have category E.HV */
+ mfspr r10,SPRN_MMUCFG
+ rlwinm. r10,r10,0,MMUCFG_LPIDSIZE
+ beqlr
+
+ SET_IVOR(38, 0x2c0) /* Guest Processor Doorbell */
+ SET_IVOR(39, 0x2e0) /* Guest Processor Doorbell Crit/MC */
+ blr
+
+_GLOBAL(setup_ehv_ivors)
+ /*
+ * We may be running as a guest and lack E.HV even on a chip
+ * that normally has it.
+ */
+ mfspr r10,SPRN_MMUCFG
+ rlwinm. r10,r10,0,MMUCFG_LPIDSIZE
+ beqlr
+
+ SET_IVOR(40, 0x300) /* Embedded Hypervisor System Call */
+ SET_IVOR(41, 0x320) /* Embedded Hypervisor Privilege */
+ blr
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index aeb739e18769..a85f4874cba7 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -37,23 +37,51 @@
.globl __start_interrupts
__start_interrupts:
- STD_EXCEPTION_PSERIES(0x100, system_reset)
+ .globl system_reset_pSeries;
+system_reset_pSeries:
+ HMT_MEDIUM;
+ DO_KVM 0x100;
+ SET_SCRATCH0(r13)
+#ifdef CONFIG_PPC_P7_NAP
+BEGIN_FTR_SECTION
+ /* Running native on arch 2.06 or later, check if we are
+ * waking up from nap. We only handle no state loss and
+ * supervisor state loss. We do -not- handle hypervisor
+ * state loss at this time.
+ */
+ mfspr r13,SPRN_SRR1
+ rlwinm r13,r13,47-31,30,31
+ cmpwi cr0,r13,1
+ bne 1f
+ b .power7_wakeup_noloss
+1: cmpwi cr0,r13,2
+ bne 1f
+ b .power7_wakeup_loss
+ /* Total loss of HV state is fatal, we could try to use the
+ * PIR to locate a PACA, then use an emergency stack etc...
+ * but for now, let's just stay stuck here
+ */
+1: cmpwi cr0,r13,3
+ beq .
+END_FTR_SECTION_IFSET(CPU_FTR_HVMODE_206)
+#endif /* CONFIG_PPC_P7_NAP */
+ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD)
. = 0x200
_machine_check_pSeries:
HMT_MEDIUM
DO_KVM 0x200
- mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */
- EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)
+ SET_SCRATCH0(r13)
+ EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common, EXC_STD)
. = 0x300
.globl data_access_pSeries
data_access_pSeries:
HMT_MEDIUM
DO_KVM 0x300
- mtspr SPRN_SPRG_SCRATCH0,r13
+ SET_SCRATCH0(r13)
BEGIN_FTR_SECTION
- mfspr r13,SPRN_SPRG_PACA
+ GET_PACA(r13)
std r9,PACA_EXSLB+EX_R9(r13)
std r10,PACA_EXSLB+EX_R10(r13)
mfspr r10,SPRN_DAR
@@ -67,22 +95,22 @@ BEGIN_FTR_SECTION
std r11,PACA_EXGEN+EX_R11(r13)
ld r11,PACA_EXSLB+EX_R9(r13)
std r12,PACA_EXGEN+EX_R12(r13)
- mfspr r12,SPRN_SPRG_SCRATCH0
+ GET_SCRATCH0(r12)
std r10,PACA_EXGEN+EX_R10(r13)
std r11,PACA_EXGEN+EX_R9(r13)
std r12,PACA_EXGEN+EX_R13(r13)
- EXCEPTION_PROLOG_PSERIES_1(data_access_common)
+ EXCEPTION_PROLOG_PSERIES_1(data_access_common, EXC_STD)
FTR_SECTION_ELSE
- EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common)
-ALT_FTR_SECTION_END_IFCLR(CPU_FTR_SLB)
+ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, data_access_common, EXC_STD)
+ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_SLB)
. = 0x380
.globl data_access_slb_pSeries
data_access_slb_pSeries:
HMT_MEDIUM
DO_KVM 0x380
- mtspr SPRN_SPRG_SCRATCH0,r13
- mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */
+ SET_SCRATCH0(r13)
+ GET_PACA(r13)
std r3,PACA_EXSLB+EX_R3(r13)
mfspr r3,SPRN_DAR
std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */
@@ -95,7 +123,7 @@ data_access_slb_pSeries:
std r10,PACA_EXSLB+EX_R10(r13)
std r11,PACA_EXSLB+EX_R11(r13)
std r12,PACA_EXSLB+EX_R12(r13)
- mfspr r10,SPRN_SPRG_SCRATCH0
+ GET_SCRATCH0(r10)
std r10,PACA_EXSLB+EX_R13(r13)
mfspr r12,SPRN_SRR1 /* and SRR1 */
#ifndef CONFIG_RELOCATABLE
@@ -113,15 +141,15 @@ data_access_slb_pSeries:
bctr
#endif
- STD_EXCEPTION_PSERIES(0x400, instruction_access)
+ STD_EXCEPTION_PSERIES(0x400, 0x400, instruction_access)
. = 0x480
.globl instruction_access_slb_pSeries
instruction_access_slb_pSeries:
HMT_MEDIUM
DO_KVM 0x480
- mtspr SPRN_SPRG_SCRATCH0,r13
- mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */
+ SET_SCRATCH0(r13)
+ GET_PACA(r13)
std r3,PACA_EXSLB+EX_R3(r13)
mfspr r3,SPRN_SRR0 /* SRR0 is faulting address */
std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */
@@ -134,7 +162,7 @@ instruction_access_slb_pSeries:
std r10,PACA_EXSLB+EX_R10(r13)
std r11,PACA_EXSLB+EX_R11(r13)
std r12,PACA_EXSLB+EX_R12(r13)
- mfspr r10,SPRN_SPRG_SCRATCH0
+ GET_SCRATCH0(r10)
std r10,PACA_EXSLB+EX_R13(r13)
mfspr r12,SPRN_SRR1 /* and SRR1 */
#ifndef CONFIG_RELOCATABLE
@@ -147,13 +175,29 @@ instruction_access_slb_pSeries:
bctr
#endif
- MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt)
- STD_EXCEPTION_PSERIES(0x600, alignment)
- STD_EXCEPTION_PSERIES(0x700, program_check)
- STD_EXCEPTION_PSERIES(0x800, fp_unavailable)
- MASKABLE_EXCEPTION_PSERIES(0x900, decrementer)
- STD_EXCEPTION_PSERIES(0xa00, trap_0a)
- STD_EXCEPTION_PSERIES(0xb00, trap_0b)
+ /* We open code these as we can't have a ". = x" (even with
+ * x = "." within a feature section
+ */
+ . = 0x500;
+ .globl hardware_interrupt_pSeries;
+ .globl hardware_interrupt_hv;
+hardware_interrupt_pSeries:
+hardware_interrupt_hv:
+ BEGIN_FTR_SECTION
+ _MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt, EXC_STD)
+ FTR_SECTION_ELSE
+ _MASKABLE_EXCEPTION_PSERIES(0x502, hardware_interrupt, EXC_HV)
+ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_HVMODE_206)
+
+ STD_EXCEPTION_PSERIES(0x600, 0x600, alignment)
+ STD_EXCEPTION_PSERIES(0x700, 0x700, program_check)
+ STD_EXCEPTION_PSERIES(0x800, 0x800, fp_unavailable)
+
+ MASKABLE_EXCEPTION_PSERIES(0x900, 0x900, decrementer)
+ MASKABLE_EXCEPTION_HV(0x980, 0x980, decrementer)
+
+ STD_EXCEPTION_PSERIES(0xa00, 0xa00, trap_0a)
+ STD_EXCEPTION_PSERIES(0xb00, 0xb00, trap_0b)
. = 0xc00
.globl system_call_pSeries
@@ -165,13 +209,13 @@ BEGIN_FTR_SECTION
beq- 1f
END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE)
mr r9,r13
- mfspr r13,SPRN_SPRG_PACA
+ GET_PACA(r13)
mfspr r11,SPRN_SRR0
- ld r12,PACAKBASE(r13)
- ld r10,PACAKMSR(r13)
- LOAD_HANDLER(r12, system_call_entry)
- mtspr SPRN_SRR0,r12
mfspr r12,SPRN_SRR1
+ ld r10,PACAKBASE(r13)
+ LOAD_HANDLER(r10, system_call_entry)
+ mtspr SPRN_SRR0,r10
+ ld r10,PACAKMSR(r13)
mtspr SPRN_SRR1,r10
rfid
b . /* prevent speculative execution */
@@ -183,8 +227,21 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE)
rfid /* return to userspace */
b .
- STD_EXCEPTION_PSERIES(0xd00, single_step)
- STD_EXCEPTION_PSERIES(0xe00, trap_0e)
+ STD_EXCEPTION_PSERIES(0xd00, 0xd00, single_step)
+
+ /* At 0xe??? we have a bunch of hypervisor exceptions, we branch
+ * out of line to handle them
+ */
+ . = 0xe00
+ b h_data_storage_hv
+ . = 0xe20
+ b h_instr_storage_hv
+ . = 0xe40
+ b emulation_assist_hv
+ . = 0xe50
+ b hmi_exception_hv
+ . = 0xe60
+ b hmi_exception_hv
/* We need to deal with the Altivec unavailable exception
* here which is at 0xf20, thus in the middle of the
@@ -193,39 +250,42 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE)
*/
performance_monitor_pSeries_1:
. = 0xf00
- DO_KVM 0xf00
b performance_monitor_pSeries
altivec_unavailable_pSeries_1:
. = 0xf20
- DO_KVM 0xf20
b altivec_unavailable_pSeries
vsx_unavailable_pSeries_1:
. = 0xf40
- DO_KVM 0xf40
b vsx_unavailable_pSeries
#ifdef CONFIG_CBE_RAS
- HSTD_EXCEPTION_PSERIES(0x1200, cbe_system_error)
+ STD_EXCEPTION_HV(0x1200, 0x1202, cbe_system_error)
#endif /* CONFIG_CBE_RAS */
- STD_EXCEPTION_PSERIES(0x1300, instruction_breakpoint)
+ STD_EXCEPTION_PSERIES(0x1300, 0x1300, instruction_breakpoint)
#ifdef CONFIG_CBE_RAS
- HSTD_EXCEPTION_PSERIES(0x1600, cbe_maintenance)
+ STD_EXCEPTION_HV(0x1600, 0x1602, cbe_maintenance)
#endif /* CONFIG_CBE_RAS */
- STD_EXCEPTION_PSERIES(0x1700, altivec_assist)
+ STD_EXCEPTION_PSERIES(0x1700, 0x1700, altivec_assist)
#ifdef CONFIG_CBE_RAS
- HSTD_EXCEPTION_PSERIES(0x1800, cbe_thermal)
+ STD_EXCEPTION_HV(0x1800, 0x1802, cbe_thermal)
#endif /* CONFIG_CBE_RAS */
. = 0x3000
-/*** pSeries interrupt support ***/
+/*** Out of line interrupts support ***/
+
+ /* moved from 0xe00 */
+ STD_EXCEPTION_HV(., 0xe00, h_data_storage)
+ STD_EXCEPTION_HV(., 0xe20, h_instr_storage)
+ STD_EXCEPTION_HV(., 0xe40, emulation_assist)
+ STD_EXCEPTION_HV(., 0xe60, hmi_exception) /* need to flush cache ? */
/* moved from 0xf00 */
- STD_EXCEPTION_PSERIES(., performance_monitor)
- STD_EXCEPTION_PSERIES(., altivec_unavailable)
- STD_EXCEPTION_PSERIES(., vsx_unavailable)
+ STD_EXCEPTION_PSERIES(., 0xf00, performance_monitor)
+ STD_EXCEPTION_PSERIES(., 0xf20, altivec_unavailable)
+ STD_EXCEPTION_PSERIES(., 0xf40, vsx_unavailable)
/*
* An interrupt came in while soft-disabled; clear EE in SRR1,
@@ -240,17 +300,30 @@ masked_interrupt:
rotldi r10,r10,16
mtspr SPRN_SRR1,r10
ld r10,PACA_EXGEN+EX_R10(r13)
- mfspr r13,SPRN_SPRG_SCRATCH0
+ GET_SCRATCH0(r13)
rfid
b .
+masked_Hinterrupt:
+ stb r10,PACAHARDIRQEN(r13)
+ mtcrf 0x80,r9
+ ld r9,PACA_EXGEN+EX_R9(r13)
+ mfspr r10,SPRN_HSRR1
+ rldicl r10,r10,48,1 /* clear MSR_EE */
+ rotldi r10,r10,16
+ mtspr SPRN_HSRR1,r10
+ ld r10,PACA_EXGEN+EX_R10(r13)
+ GET_SCRATCH0(r13)
+ hrfid
+ b .
+
.align 7
do_stab_bolted_pSeries:
std r11,PACA_EXSLB+EX_R11(r13)
std r12,PACA_EXSLB+EX_R12(r13)
- mfspr r10,SPRN_SPRG_SCRATCH0
+ GET_SCRATCH0(r10)
std r10,PACA_EXSLB+EX_R13(r13)
- EXCEPTION_PROLOG_PSERIES_1(.do_stab_bolted)
+ EXCEPTION_PROLOG_PSERIES_1(.do_stab_bolted, EXC_STD)
#ifdef CONFIG_PPC_PSERIES
/*
@@ -260,15 +333,15 @@ do_stab_bolted_pSeries:
.align 7
system_reset_fwnmi:
HMT_MEDIUM
- mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */
- EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common)
+ SET_SCRATCH0(r13) /* save r13 */
+ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD)
.globl machine_check_fwnmi
.align 7
machine_check_fwnmi:
HMT_MEDIUM
- mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */
- EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)
+ SET_SCRATCH0(r13) /* save r13 */
+ EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common, EXC_STD)
#endif /* CONFIG_PPC_PSERIES */
@@ -282,7 +355,7 @@ slb_miss_user_pseries:
std r10,PACA_EXGEN+EX_R10(r13)
std r11,PACA_EXGEN+EX_R11(r13)
std r12,PACA_EXGEN+EX_R12(r13)
- mfspr r10,SPRG_SCRATCH0
+ GET_SCRATCH0(r10)
ld r11,PACA_EXSLB+EX_R9(r13)
ld r12,PACA_EXSLB+EX_R3(r13)
std r10,PACA_EXGEN+EX_R13(r13)
@@ -342,6 +415,8 @@ machine_check_common:
STD_EXCEPTION_COMMON(0xb00, trap_0b, .unknown_exception)
STD_EXCEPTION_COMMON(0xd00, single_step, .single_step_exception)
STD_EXCEPTION_COMMON(0xe00, trap_0e, .unknown_exception)
+ STD_EXCEPTION_COMMON(0xe40, emulation_assist, .program_check_exception)
+ STD_EXCEPTION_COMMON(0xe60, hmi_exception, .unknown_exception)
STD_EXCEPTION_COMMON_IDLE(0xf00, performance_monitor, .performance_monitor_exception)
STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, .instruction_breakpoint_exception)
#ifdef CONFIG_ALTIVEC
@@ -386,9 +461,24 @@ bad_stack:
std r12,_XER(r1)
SAVE_GPR(0,r1)
SAVE_GPR(2,r1)
- SAVE_4GPRS(3,r1)
- SAVE_2GPRS(7,r1)
- SAVE_10GPRS(12,r1)
+ ld r10,EX_R3(r3)
+ std r10,GPR3(r1)
+ SAVE_GPR(4,r1)
+ SAVE_4GPRS(5,r1)
+ ld r9,EX_R9(r3)
+ ld r10,EX_R10(r3)
+ SAVE_2GPRS(9,r1)
+ ld r9,EX_R11(r3)
+ ld r10,EX_R12(r3)
+ ld r11,EX_R13(r3)
+ std r9,GPR11(r1)
+ std r10,GPR12(r1)
+ std r11,GPR13(r1)
+BEGIN_FTR_SECTION
+ ld r10,EX_CFAR(r3)
+ std r10,ORIG_GPR3(r1)
+END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
+ SAVE_8GPRS(14,r1)
SAVE_10GPRS(22,r1)
lhz r12,PACA_TRAP_SAVE(r13)
std r12,_TRAP(r1)
@@ -397,6 +487,9 @@ bad_stack:
li r12,0
std r12,0(r11)
ld r2,PACATOC(r13)
+ ld r11,exception_marker@toc(r2)
+ std r12,RESULT(r1)
+ std r11,STACK_FRAME_OVERHEAD-16(r1)
1: addi r3,r1,STACK_FRAME_OVERHEAD
bl .kernel_bad_stack
b 1b
@@ -419,6 +512,19 @@ data_access_common:
li r5,0x300
b .do_hash_page /* Try to handle as hpte fault */
+ .align 7
+ .globl h_data_storage_common
+h_data_storage_common:
+ mfspr r10,SPRN_HDAR
+ std r10,PACA_EXGEN+EX_DAR(r13)
+ mfspr r10,SPRN_HDSISR
+ stw r10,PACA_EXGEN+EX_DSISR(r13)
+ EXCEPTION_PROLOG_COMMON(0xe00, PACA_EXGEN)
+ bl .save_nvgprs
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .unknown_exception
+ b .ret_from_except
+
.align 7
.globl instruction_access_common
instruction_access_common:
@@ -428,6 +534,8 @@ instruction_access_common:
li r5,0x400
b .do_hash_page /* Try to handle as hpte fault */
+ STD_EXCEPTION_COMMON(0xe20, h_instr_storage, .unknown_exception)
+
/*
* Here is the common SLB miss user that is used when going to virtual
* mode for SLB misses, that is currently not used
@@ -750,7 +858,7 @@ _STATIC(do_hash_page)
BEGIN_FTR_SECTION
andis. r0,r4,0x0020 /* Is it a segment table fault? */
bne- do_ste_alloc /* If so handle it */
-END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
+END_MMU_FTR_SECTION_IFCLR(MMU_FTR_SLB)
clrrdi r11,r1,THREAD_SHIFT
lwz r0,TI_PREEMPT(r11) /* If we're in an "NMI" */
diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c
index ce1f3e44c24f..bf99cfa6bbfe 100644
--- a/arch/powerpc/kernel/ftrace.c
+++ b/arch/powerpc/kernel/ftrace.c
@@ -22,6 +22,7 @@
#include <asm/cacheflush.h>
#include <asm/code-patching.h>
#include <asm/ftrace.h>
+#include <asm/syscall.h>
#ifdef CONFIG_DYNAMIC_FTRACE
@@ -600,3 +601,10 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
}
}
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+#if defined(CONFIG_FTRACE_SYSCALLS) && defined(CONFIG_PPC64)
+unsigned long __init arch_syscall_addr(int nr)
+{
+ return sys_call_table[nr*2];
+}
+#endif /* CONFIG_FTRACE_SYSCALLS && CONFIG_PPC64 */
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
index c5c24beb8387..ba250d505e07 100644
--- a/arch/powerpc/kernel/head_32.S
+++ b/arch/powerpc/kernel/head_32.S
@@ -805,19 +805,6 @@ _ENTRY(copy_and_flush)
blr
#ifdef CONFIG_SMP
-#ifdef CONFIG_GEMINI
- .globl __secondary_start_gemini
-__secondary_start_gemini:
- mfspr r4,SPRN_HID0
- ori r4,r4,HID0_ICFI
- li r3,0
- ori r3,r3,HID0_ICE
- andc r4,r4,r3
- mtspr SPRN_HID0,r4
- sync
- b __secondary_start
-#endif /* CONFIG_GEMINI */
-
.globl __secondary_start_mpc86xx
__secondary_start_mpc86xx:
mfspr r3, SPRN_PIR
@@ -890,15 +877,6 @@ __secondary_start:
mtspr SPRN_SRR1,r4
SYNC
RFI
-
-_GLOBAL(start_secondary_resume)
- /* Reset stack */
- rlwinm r1,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */
- addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD
- li r3,0
- std r3,0(r1) /* Zero the stack frame pointer */
- bl start_secondary
- b .
#endif /* CONFIG_SMP */
#ifdef CONFIG_KVM_BOOK3S_HANDLER
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 3a319f9c9d3e..ba504099844a 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -147,6 +147,8 @@ __secondary_hold:
mtctr r4
mr r3,r24
li r4,0
+ /* Make sure that patched code is visible */
+ isync
bctr
#else
BUG_OPCODE
@@ -216,19 +218,25 @@ generic_secondary_common_init:
*/
LOAD_REG_ADDR(r13, paca) /* Load paca pointer */
ld r13,0(r13) /* Get base vaddr of paca array */
+#ifndef CONFIG_SMP
+ addi r13,r13,PACA_SIZE /* know r13 if used accidentally */
+ b .kexec_wait /* wait for next kernel if !SMP */
+#else
+ LOAD_REG_ADDR(r7, nr_cpu_ids) /* Load nr_cpu_ids address */
+ lwz r7,0(r7) /* also the max paca allocated */
li r5,0 /* logical cpu id */
1: lhz r6,PACAHWCPUID(r13) /* Load HW procid from paca */
cmpw r6,r24 /* Compare to our id */
beq 2f
addi r13,r13,PACA_SIZE /* Loop to next PACA on miss */
addi r5,r5,1
- cmpwi r5,NR_CPUS
+ cmpw r5,r7 /* Check if more pacas exist */
blt 1b
mr r3,r24 /* not found, copy phys to r3 */
b .kexec_wait /* next kernel might do better */
-2: mtspr SPRN_SPRG_PACA,r13 /* Save vaddr of paca in an SPRG */
+2: SET_PACA(r13)
#ifdef CONFIG_PPC_BOOK3E
addi r12,r13,PACA_EXTLB /* and TLB exc frame in another */
mtspr SPRN_SPRG_TLB_EXFRAME,r12
@@ -236,34 +244,39 @@ generic_secondary_common_init:
/* From now on, r24 is expected to be logical cpuid */
mr r24,r5
-3: HMT_LOW
- lbz r23,PACAPROCSTART(r13) /* Test if this processor should */
- /* start. */
-
-#ifndef CONFIG_SMP
- b 3b /* Never go on non-SMP */
-#else
- cmpwi 0,r23,0
- beq 3b /* Loop until told to go */
-
- sync /* order paca.run and cur_cpu_spec */
/* See if we need to call a cpu state restore handler */
LOAD_REG_ADDR(r23, cur_cpu_spec)
ld r23,0(r23)
ld r23,CPU_SPEC_RESTORE(r23)
cmpdi 0,r23,0
- beq 4f
+ beq 3f
ld r23,0(r23)
mtctr r23
bctrl
-4: /* Create a temp kernel stack for use before relocation is on. */
+3: LOAD_REG_ADDR(r3, boot_cpu_count) /* Decrement boot_cpu_count */
+ lwarx r4,0,r3
+ subi r4,r4,1
+ stwcx. r4,0,r3
+ bne 3b
+ isync
+
+4: HMT_LOW
+ lbz r23,PACAPROCSTART(r13) /* Test if this processor should */
+ /* start. */
+ cmpwi 0,r23,0
+ beq 4b /* Loop until told to go */
+
+ sync /* order paca.run and cur_cpu_spec */
+ isync /* In case code patching happened */
+
+ /* Create a temp kernel stack for use before relocation is on. */
ld r1,PACAEMERGSP(r13)
subi r1,r1,STACK_FRAME_OVERHEAD
b __secondary_start
-#endif
+#endif /* SMP */
/*
* Turn the MMU off.
@@ -534,7 +547,7 @@ _GLOBAL(pmac_secondary_start)
ld r4,0(r4) /* Get base vaddr of paca array */
mulli r13,r24,PACA_SIZE /* Calculate vaddr of right paca */
add r13,r13,r4 /* for this processor. */
- mtspr SPRN_SPRG_PACA,r13 /* Save vaddr of paca in an SPRG*/
+ SET_PACA(r13) /* Save vaddr of paca in an SPRG*/
/* Mark interrupts soft and hard disabled (they might be enabled
* in the PACA when doing hotplug)
@@ -645,7 +658,7 @@ _GLOBAL(enable_64b_mode)
oris r11,r11,0x8000 /* CM bit set, we'll set ICM later */
mtmsr r11
#else /* CONFIG_PPC_BOOK3E */
- li r12,(MSR_SF | MSR_ISF)@highest
+ li r12,(MSR_64BIT | MSR_ISF)@highest
sldi r12,r12,48
or r11,r11,r12
mtmsrd r11
diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S
new file mode 100644
index 000000000000..f8f0bc7f1d4f
--- /dev/null
+++ b/arch/powerpc/kernel/idle_power7.S
@@ -0,0 +1,97 @@
+/*
+ * This file contains the power_save function for 970-family CPUs.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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/processor.h>
+#include <asm/page.h>
+#include <asm/cputable.h>
+#include <asm/thread_info.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/ppc-opcode.h>
+
+#undef DEBUG
+
+ .text
+
+_GLOBAL(power7_idle)
+ /* Now check if user or arch enabled NAP mode */
+ LOAD_REG_ADDRBASE(r3,powersave_nap)
+ lwz r4,ADDROFF(powersave_nap)(r3)
+ cmpwi 0,r4,0
+ beqlr
+
+ /* NAP is a state loss, we create a regs frame on the
+ * stack, fill it up with the state we care about and
+ * stick a pointer to it in PACAR1. We really only
+ * need to save PC, some CR bits and the NV GPRs,
+ * but for now an interrupt frame will do.
+ */
+ mflr r0
+ std r0,16(r1)
+ stdu r1,-INT_FRAME_SIZE(r1)
+ std r0,_LINK(r1)
+ std r0,_NIP(r1)
+
+#ifndef CONFIG_SMP
+ /* Make sure FPU, VSX etc... are flushed as we may lose
+ * state when going to nap mode
+ */
+ bl .discard_lazy_cpu_state
+#endif /* CONFIG_SMP */
+
+ /* Hard disable interrupts */
+ mfmsr r9
+ rldicl r9,r9,48,1
+ rotldi r9,r9,16
+ mtmsrd r9,1 /* hard-disable interrupts */
+ li r0,0
+ stb r0,PACASOFTIRQEN(r13) /* we'll hard-enable shortly */
+ stb r0,PACAHARDIRQEN(r13)
+
+ /* Continue saving state */
+ SAVE_GPR(2, r1)
+ SAVE_NVGPRS(r1)
+ mfcr r3
+ std r3,_CCR(r1)
+ std r9,_MSR(r1)
+ std r1,PACAR1(r13)
+
+ /* Magic NAP mode enter sequence */
+ std r0,0(r1)
+ ptesync
+ ld r0,0(r1)
+1: cmp cr0,r0,r0
+ bne 1b
+ PPC_NAP
+ b .
+
+_GLOBAL(power7_wakeup_loss)
+ GET_PACA(r13)
+ ld r1,PACAR1(r13)
+ REST_NVGPRS(r1)
+ REST_GPR(2, r1)
+ ld r3,_CCR(r1)
+ ld r4,_MSR(r1)
+ ld r5,_NIP(r1)
+ addi r1,r1,INT_FRAME_SIZE
+ mtcr r3
+ mtspr SPRN_SRR1,r4
+ mtspr SPRN_SRR0,r5
+ rfid
+
+_GLOBAL(power7_wakeup_noloss)
+ GET_PACA(r13)
+ ld r1,PACAR1(r13)
+ ld r4,_MSR(r1)
+ ld r5,_NIP(r1)
+ addi r1,r1,INT_FRAME_SIZE
+ mtspr SPRN_SRR1,r4
+ mtspr SPRN_SRR0,r5
+ rfid
diff --git a/arch/powerpc/platforms/cell/io-workarounds.c b/arch/powerpc/kernel/io-workarounds.c
index 5c1118e31940..ffafaea3d261 100644
--- a/arch/powerpc/platforms/cell/io-workarounds.c
+++ b/arch/powerpc/kernel/io-workarounds.c
@@ -17,8 +17,7 @@
#include <asm/machdep.h>
#include <asm/pgtable.h>
#include <asm/ppc-pci.h>
-
-#include "io-workarounds.h"
+#include <asm/io-workarounds.h>
#define IOWA_MAX_BUS 8
@@ -145,7 +144,19 @@ static void __iomem *iowa_ioremap(phys_addr_t addr, unsigned long size,
return res;
}
-/* Regist new bus to support workaround */
+/* Enable IO workaround */
+static void __devinit io_workaround_init(void)
+{
+ static int io_workaround_inited;
+
+ if (io_workaround_inited)
+ return;
+ ppc_pci_io = iowa_pci_io;
+ ppc_md.ioremap = iowa_ioremap;
+ io_workaround_inited = 1;
+}
+
+/* Register new bus to support workaround */
void __devinit iowa_register_bus(struct pci_controller *phb,
struct ppc_pci_io *ops,
int (*initfunc)(struct iowa_bus *, void *), void *data)
@@ -153,6 +164,8 @@ void __devinit iowa_register_bus(struct pci_controller *phb,
struct iowa_bus *bus;
struct device_node *np = phb->dn;
+ io_workaround_init();
+
if (iowa_bus_count >= IOWA_MAX_BUS) {
pr_err("IOWA:Too many pci bridges, "
"workarounds disabled for %s\n", np->full_name);
@@ -162,6 +175,7 @@ void __devinit iowa_register_bus(struct pci_controller *phb,
bus = &iowa_busses[iowa_bus_count];
bus->phb = phb;
bus->ops = ops;
+ bus->private = data;
if (initfunc)
if ((*initfunc)(bus, data))
@@ -172,14 +186,3 @@ void __devinit iowa_register_bus(struct pci_controller *phb,
pr_debug("IOWA:[%d]Add bus, %s.\n", iowa_bus_count-1, np->full_name);
}
-/* enable IO workaround */
-void __devinit io_workaround_init(void)
-{
- static int io_workaround_inited;
-
- if (io_workaround_inited)
- return;
- ppc_pci_io = iowa_pci_io;
- ppc_md.ioremap = iowa_ioremap;
- io_workaround_inited = 1;
-}
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index f621b7d2d869..5b428e308666 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -66,7 +66,6 @@
#include <asm/ptrace.h>
#include <asm/machdep.h>
#include <asm/udbg.h>
-#include <asm/dbell.h>
#include <asm/smp.h>
#ifdef CONFIG_PPC64
@@ -160,7 +159,8 @@ notrace void arch_local_irq_restore(unsigned long en)
#if defined(CONFIG_BOOKE) && defined(CONFIG_SMP)
/* Check for pending doorbell interrupts and resend to ourself */
- doorbell_check_self();
+ if (cpu_has_feature(CPU_FTR_DBELL))
+ smp_muxed_ipi_resend();
#endif
/*
@@ -295,17 +295,20 @@ static inline void handle_one_irq(unsigned int irq)
unsigned long saved_sp_limit;
struct irq_desc *desc;
+ desc = irq_to_desc(irq);
+ if (!desc)
+ return;
+
/* Switch to the irq stack to handle this */
curtp = current_thread_info();
irqtp = hardirq_ctx[smp_processor_id()];
if (curtp == irqtp) {
/* We're already on the irq stack, just handle it */
- generic_handle_irq(irq);
+ desc->handle_irq(irq, desc);
return;
}
- desc = irq_to_desc(irq);
saved_sp_limit = current->thread.ksp_limit;
irqtp->task = curtp->task;
@@ -397,24 +400,28 @@ struct thread_info *mcheckirq_ctx[NR_CPUS] __read_mostly;
void exc_lvl_ctx_init(void)
{
struct thread_info *tp;
- int i, hw_cpu;
+ int i, cpu_nr;
for_each_possible_cpu(i) {
- hw_cpu = get_hard_smp_processor_id(i);
- memset((void *)critirq_ctx[hw_cpu], 0, THREAD_SIZE);
- tp = critirq_ctx[hw_cpu];
- tp->cpu = i;
+#ifdef CONFIG_PPC64
+ cpu_nr = i;
+#else
+ cpu_nr = get_hard_smp_processor_id(i);
+#endif
+ memset((void *)critirq_ctx[cpu_nr], 0, THREAD_SIZE);
+ tp = critirq_ctx[cpu_nr];
+ tp->cpu = cpu_nr;
tp->preempt_count = 0;
#ifdef CONFIG_BOOKE
- memset((void *)dbgirq_ctx[hw_cpu], 0, THREAD_SIZE);
- tp = dbgirq_ctx[hw_cpu];
- tp->cpu = i;
+ memset((void *)dbgirq_ctx[cpu_nr], 0, THREAD_SIZE);
+ tp = dbgirq_ctx[cpu_nr];
+ tp->cpu = cpu_nr;
tp->preempt_count = 0;
- memset((void *)mcheckirq_ctx[hw_cpu], 0, THREAD_SIZE);
- tp = mcheckirq_ctx[hw_cpu];
- tp->cpu = i;
+ memset((void *)mcheckirq_ctx[cpu_nr], 0, THREAD_SIZE);
+ tp = mcheckirq_ctx[cpu_nr];
+ tp->cpu = cpu_nr;
tp->preempt_count = HARDIRQ_OFFSET;
#endif
}
@@ -477,20 +484,41 @@ void do_softirq(void)
* IRQ controller and virtual interrupts
*/
+/* The main irq map itself is an array of NR_IRQ entries containing the
+ * associate host and irq number. An entry with a host of NULL is free.
+ * An entry can be allocated if it's free, the allocator always then sets
+ * hwirq first to the host's invalid irq number and then fills ops.
+ */
+struct irq_map_entry {
+ irq_hw_number_t hwirq;
+ struct irq_host *host;
+};
+
static LIST_HEAD(irq_hosts);
static DEFINE_RAW_SPINLOCK(irq_big_lock);
-static unsigned int revmap_trees_allocated;
static DEFINE_MUTEX(revmap_trees_mutex);
-struct irq_map_entry irq_map[NR_IRQS];
+static struct irq_map_entry irq_map[NR_IRQS];
static unsigned int irq_virq_count = NR_IRQS;
static struct irq_host *irq_default_host;
+irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
+{
+ return irq_map[d->irq].hwirq;
+}
+EXPORT_SYMBOL_GPL(irqd_to_hwirq);
+
irq_hw_number_t virq_to_hw(unsigned int virq)
{
return irq_map[virq].hwirq;
}
EXPORT_SYMBOL_GPL(virq_to_hw);
+bool virq_is_host(unsigned int virq, struct irq_host *host)
+{
+ return irq_map[virq].host == host;
+}
+EXPORT_SYMBOL_GPL(virq_is_host);
+
static int default_irq_host_match(struct irq_host *h, struct device_node *np)
{
return h->of_node != NULL && h->of_node == np;
@@ -511,7 +539,7 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
/* Allocate structure and revmap table if using linear mapping */
if (revmap_type == IRQ_HOST_MAP_LINEAR)
size += revmap_arg * sizeof(unsigned int);
- host = zalloc_maybe_bootmem(size, GFP_KERNEL);
+ host = kzalloc(size, GFP_KERNEL);
if (host == NULL)
return NULL;
@@ -532,15 +560,8 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
if (revmap_type == IRQ_HOST_MAP_LEGACY) {
if (irq_map[0].host != NULL) {
raw_spin_unlock_irqrestore(&irq_big_lock, flags);
- /* If we are early boot, we can't free the structure,
- * too bad...
- * this will be fixed once slab is made available early
- * instead of the current cruft
- */
- if (mem_init_done) {
- of_node_put(host->of_node);
- kfree(host);
- }
+ of_node_put(host->of_node);
+ kfree(host);
return NULL;
}
irq_map[0].host = host;
@@ -561,14 +582,14 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
irq_map[i].host = host;
smp_wmb();
- /* Clear norequest flags */
- irq_clear_status_flags(i, IRQ_NOREQUEST);
-
/* Legacy flags are left to default at this point,
* one can then use irq_create_mapping() to
* explicitly change them
*/
ops->map(host, i, i);
+
+ /* Clear norequest flags */
+ irq_clear_status_flags(i, IRQ_NOREQUEST);
}
break;
case IRQ_HOST_MAP_LINEAR:
@@ -579,6 +600,9 @@ struct irq_host *irq_alloc_host(struct device_node *of_node,
smp_wmb();
host->revmap_data.linear.revmap = rmap;
break;
+ case IRQ_HOST_MAP_TREE:
+ INIT_RADIX_TREE(&host->revmap_data.tree, GFP_KERNEL);
+ break;
default:
break;
}
@@ -636,8 +660,6 @@ static int irq_setup_virq(struct irq_host *host, unsigned int virq,
goto error;
}
- irq_clear_status_flags(virq, IRQ_NOREQUEST);
-
/* map it */
smp_wmb();
irq_map[virq].hwirq = hwirq;
@@ -648,6 +670,8 @@ static int irq_setup_virq(struct irq_host *host, unsigned int virq,
goto errdesc;
}
+ irq_clear_status_flags(virq, IRQ_NOREQUEST);
+
return 0;
errdesc:
@@ -699,13 +723,9 @@ unsigned int irq_create_mapping(struct irq_host *host,
}
pr_debug("irq: -> using host @%p\n", host);
- /* Check if mapping already exist, if it does, call
- * host->ops->map() to update the flags
- */
+ /* Check if mapping already exists */
virq = irq_find_mapping(host, hwirq);
if (virq != NO_IRQ) {
- if (host->ops->remap)
- host->ops->remap(host, virq, hwirq);
pr_debug("irq: -> existing mapping on virq %d\n", virq);
return virq;
}
@@ -786,14 +806,15 @@ void irq_dispose_mapping(unsigned int virq)
return;
host = irq_map[virq].host;
- WARN_ON (host == NULL);
- if (host == NULL)
+ if (WARN_ON(host == NULL))
return;
/* Never unmap legacy interrupts */
if (host->revmap_type == IRQ_HOST_MAP_LEGACY)
return;
+ irq_set_status_flags(virq, IRQ_NOREQUEST);
+
/* remove chip and handler */
irq_set_chip_and_handler(virq, NULL, NULL);
@@ -813,13 +834,6 @@ void irq_dispose_mapping(unsigned int virq)
host->revmap_data.linear.revmap[hwirq] = NO_IRQ;
break;
case IRQ_HOST_MAP_TREE:
- /*
- * Check if radix tree allocated yet, if not then nothing to
- * remove.
- */
- smp_rmb();
- if (revmap_trees_allocated < 1)
- break;
mutex_lock(&revmap_trees_mutex);
radix_tree_delete(&host->revmap_data.tree, hwirq);
mutex_unlock(&revmap_trees_mutex);
@@ -830,8 +844,6 @@ void irq_dispose_mapping(unsigned int virq)
smp_mb();
irq_map[virq].hwirq = host->inval_irq;
- irq_set_status_flags(virq, IRQ_NOREQUEST);
-
irq_free_descs(virq, 1);
/* Free it */
irq_free_virt(virq, 1);
@@ -877,21 +889,17 @@ unsigned int irq_radix_revmap_lookup(struct irq_host *host,
struct irq_map_entry *ptr;
unsigned int virq;
- WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE);
-
- /*
- * Check if the radix tree exists and has bee initialized.
- * If not, we fallback to slow mode
- */
- if (revmap_trees_allocated < 2)
+ if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_TREE))
return irq_find_mapping(host, hwirq);
- /* Now try to resolve */
/*
- * No rcu_read_lock(ing) needed, the ptr returned can't go under us
- * as it's referencing an entry in the static irq_map table.
+ * The ptr returned references the static global irq_map.
+ * but freeing an irq can delete nodes along the path to
+ * do the lookup via call_rcu.
*/
+ rcu_read_lock();
ptr = radix_tree_lookup(&host->revmap_data.tree, hwirq);
+ rcu_read_unlock();
/*
* If found in radix tree, then fine.
@@ -909,16 +917,7 @@ unsigned int irq_radix_revmap_lookup(struct irq_host *host,
void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,
irq_hw_number_t hwirq)
{
-
- WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE);
-
- /*
- * Check if the radix tree exists yet.
- * If not, then the irq will be inserted into the tree when it gets
- * initialized.
- */
- smp_rmb();
- if (revmap_trees_allocated < 1)
+ if (WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE))
return;
if (virq != NO_IRQ) {
@@ -934,7 +933,8 @@ unsigned int irq_linear_revmap(struct irq_host *host,
{
unsigned int *revmap;
- WARN_ON(host->revmap_type != IRQ_HOST_MAP_LINEAR);
+ if (WARN_ON_ONCE(host->revmap_type != IRQ_HOST_MAP_LINEAR))
+ return irq_find_mapping(host, hwirq);
/* Check revmap bounds */
if (unlikely(hwirq >= host->revmap_data.linear.size))
@@ -1007,14 +1007,23 @@ void irq_free_virt(unsigned int virq, unsigned int count)
WARN_ON (virq < NUM_ISA_INTERRUPTS);
WARN_ON (count == 0 || (virq + count) > irq_virq_count);
+ if (virq < NUM_ISA_INTERRUPTS) {
+ if (virq + count < NUM_ISA_INTERRUPTS)
+ return;
+ count =- NUM_ISA_INTERRUPTS - virq;
+ virq = NUM_ISA_INTERRUPTS;
+ }
+
+ if (count > irq_virq_count || virq > irq_virq_count - count) {
+ if (virq > irq_virq_count)
+ return;
+ count = irq_virq_count - virq;
+ }
+
raw_spin_lock_irqsave(&irq_big_lock, flags);
for (i = virq; i < (virq + count); i++) {
struct irq_host *host;
- if (i < NUM_ISA_INTERRUPTS ||
- (virq + count) > irq_virq_count)
- continue;
-
host = irq_map[i].host;
irq_map[i].hwirq = host->inval_irq;
smp_wmb();
@@ -1028,53 +1037,6 @@ int arch_early_irq_init(void)
return 0;
}
-/* We need to create the radix trees late */
-static int irq_late_init(void)
-{
- struct irq_host *h;
- unsigned int i;
-
- /*
- * No mutual exclusion with respect to accessors of the tree is needed
- * here as the synchronization is done via the state variable
- * revmap_trees_allocated.
- */
- list_for_each_entry(h, &irq_hosts, link) {
- if (h->revmap_type == IRQ_HOST_MAP_TREE)
- INIT_RADIX_TREE(&h->revmap_data.tree, GFP_KERNEL);
- }
-
- /*
- * Make sure the radix trees inits are visible before setting
- * the flag
- */
- smp_wmb();
- revmap_trees_allocated = 1;
-
- /*
- * Insert the reverse mapping for those interrupts already present
- * in irq_map[].
- */
- mutex_lock(&revmap_trees_mutex);
- for (i = 0; i < irq_virq_count; i++) {
- if (irq_map[i].host &&
- (irq_map[i].host->revmap_type == IRQ_HOST_MAP_TREE))
- radix_tree_insert(&irq_map[i].host->revmap_data.tree,
- irq_map[i].hwirq, &irq_map[i]);
- }
- mutex_unlock(&revmap_trees_mutex);
-
- /*
- * Make sure the radix trees insertions are visible before setting
- * the flag
- */
- smp_wmb();
- revmap_trees_allocated = 2;
-
- return 0;
-}
-arch_initcall(irq_late_init);
-
#ifdef CONFIG_VIRQ_DEBUG
static int virq_debug_show(struct seq_file *m, void *private)
{
@@ -1082,10 +1044,11 @@ static int virq_debug_show(struct seq_file *m, void *private)
struct irq_desc *desc;
const char *p;
static const char none[] = "none";
+ void *data;
int i;
- seq_printf(m, "%-5s %-7s %-15s %s\n", "virq", "hwirq",
- "chip name", "host name");
+ seq_printf(m, "%-5s %-7s %-15s %-18s %s\n", "virq", "hwirq",
+ "chip name", "chip data", "host name");
for (i = 1; i < nr_irqs; i++) {
desc = irq_to_desc(i);
@@ -1098,7 +1061,7 @@ static int virq_debug_show(struct seq_file *m, void *private)
struct irq_chip *chip;
seq_printf(m, "%5d ", i);
- seq_printf(m, "0x%05lx ", virq_to_hw(i));
+ seq_printf(m, "0x%05lx ", irq_map[i].hwirq);
chip = irq_desc_get_chip(desc);
if (chip && chip->name)
@@ -1107,6 +1070,9 @@ static int virq_debug_show(struct seq_file *m, void *private)
p = none;
seq_printf(m, "%-15s ", p);
+ data = irq_desc_get_chip_data(desc);
+ seq_printf(m, "0x%16p ", data);
+
if (irq_map[i].host && irq_map[i].host->of_node)
p = irq_map[i].host->of_node->full_name;
else
diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c
index 42850ee00ada..76a6e40a6f7c 100644
--- a/arch/powerpc/kernel/kgdb.c
+++ b/arch/powerpc/kernel/kgdb.c
@@ -109,7 +109,7 @@ static int kgdb_call_nmi_hook(struct pt_regs *regs)
#ifdef CONFIG_SMP
void kgdb_roundup_cpus(unsigned long flags)
{
- smp_send_debugger_break(MSG_ALL_BUT_SELF);
+ smp_send_debugger_break();
}
#endif
@@ -142,7 +142,7 @@ static int kgdb_singlestep(struct pt_regs *regs)
return 0;
/*
- * On Book E and perhaps other processsors, singlestep is handled on
+ * On Book E and perhaps other processors, singlestep is handled on
* the critical exception stack. This causes current_thread_info()
* to fail, since it it locates the thread_info by masking off
* the low bits of the current stack pointer. We work around
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c
index 301db65f05a1..84daabe2fcba 100644
--- a/arch/powerpc/kernel/lparcfg.c
+++ b/arch/powerpc/kernel/lparcfg.c
@@ -132,34 +132,6 @@ static int iseries_lparcfg_data(struct seq_file *m, void *v)
/*
* Methods used to fetch LPAR data when running on a pSeries platform.
*/
-/**
- * h_get_mpp
- * H_GET_MPP hcall returns info in 7 parms
- */
-int h_get_mpp(struct hvcall_mpp_data *mpp_data)
-{
- int rc;
- unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
-
- rc = plpar_hcall9(H_GET_MPP, retbuf);
-
- mpp_data->entitled_mem = retbuf[0];
- mpp_data->mapped_mem = retbuf[1];
-
- mpp_data->group_num = (retbuf[2] >> 2 * 8) & 0xffff;
- mpp_data->pool_num = retbuf[2] & 0xffff;
-
- mpp_data->mem_weight = (retbuf[3] >> 7 * 8) & 0xff;
- mpp_data->unallocated_mem_weight = (retbuf[3] >> 6 * 8) & 0xff;
- mpp_data->unallocated_entitlement = retbuf[3] & 0xffffffffffff;
-
- mpp_data->pool_size = retbuf[4];
- mpp_data->loan_request = retbuf[5];
- mpp_data->backing_mem = retbuf[6];
-
- return rc;
-}
-EXPORT_SYMBOL(h_get_mpp);
struct hvcall_ppp_data {
u64 entitlement;
@@ -345,6 +317,30 @@ static void parse_mpp_data(struct seq_file *m)
seq_printf(m, "backing_memory=%ld bytes\n", mpp_data.backing_mem);
}
+/**
+ * parse_mpp_x_data
+ * Parse out data returned from h_get_mpp_x
+ */
+static void parse_mpp_x_data(struct seq_file *m)
+{
+ struct hvcall_mpp_x_data mpp_x_data;
+
+ if (!firmware_has_feature(FW_FEATURE_XCMO))
+ return;
+ if (h_get_mpp_x(&mpp_x_data))
+ return;
+
+ seq_printf(m, "coalesced_bytes=%ld\n", mpp_x_data.coalesced_bytes);
+
+ if (mpp_x_data.pool_coalesced_bytes)
+ seq_printf(m, "pool_coalesced_bytes=%ld\n",
+ mpp_x_data.pool_coalesced_bytes);
+ if (mpp_x_data.pool_purr_cycles)
+ seq_printf(m, "coalesce_pool_purr=%ld\n", mpp_x_data.pool_purr_cycles);
+ if (mpp_x_data.pool_spurr_cycles)
+ seq_printf(m, "coalesce_pool_spurr=%ld\n", mpp_x_data.pool_spurr_cycles);
+}
+
#define SPLPAR_CHARACTERISTICS_TOKEN 20
#define SPLPAR_MAXLENGTH 1026*(sizeof(char))
@@ -520,6 +516,7 @@ static int pseries_lparcfg_data(struct seq_file *m, void *v)
parse_system_parameter_string(m);
parse_ppp_data(m);
parse_mpp_data(m);
+ parse_mpp_x_data(m);
pseries_cmo_data(m);
splpar_dispatch_data(m);
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 094bd9821ad4..998a10028608 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -694,6 +694,17 @@ _GLOBAL(kernel_thread)
addi r1,r1,16
blr
+#ifdef CONFIG_SMP
+_GLOBAL(start_secondary_resume)
+ /* Reset stack */
+ rlwinm r1,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */
+ addi r1,r1,THREAD_SIZE-STACK_FRAME_OVERHEAD
+ li r3,0
+ stw r3,0(r1) /* Zero the stack frame pointer */
+ bl start_secondary
+ b .
+#endif /* CONFIG_SMP */
+
/*
* This routine is just here to keep GCC happy - sigh...
*/
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index 206a321a71d3..e89df59cdc5a 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -462,7 +462,8 @@ _GLOBAL(disable_kernel_fp)
* wait for the flag to change, indicating this kernel is going away but
* the slave code for the next one is at addresses 0 to 100.
*
- * This is used by all slaves.
+ * This is used by all slaves, even those that did not find a matching
+ * paca in the secondary startup code.
*
* Physical (hardware) cpu id should be in r3.
*/
@@ -471,10 +472,6 @@ _GLOBAL(kexec_wait)
1: mflr r5
addi r5,r5,kexec_flag-1b
- li r4,KEXEC_STATE_REAL_MODE
- stb r4,PACAKEXECSTATE(r13)
- SYNC
-
99: HMT_LOW
#ifdef CONFIG_KEXEC /* use no memory without kexec */
lwz r4,0(r5)
@@ -499,11 +496,17 @@ kexec_flag:
*
* get phys id from paca
* switch to real mode
+ * mark the paca as no longer used
* join other cpus in kexec_wait(phys_id)
*/
_GLOBAL(kexec_smp_wait)
lhz r3,PACAHWCPUID(r13)
bl real_mode
+
+ li r4,KEXEC_STATE_REAL_MODE
+ stb r4,PACAKEXECSTATE(r13)
+ SYNC
+
b .kexec_wait
/*
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index 10f0aadee95b..efeb88184182 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -7,7 +7,7 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/threads.h>
+#include <linux/smp.h>
#include <linux/module.h>
#include <linux/memblock.h>
@@ -156,18 +156,29 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu)
/* Put the paca pointer into r13 and SPRG_PACA */
void setup_paca(struct paca_struct *new_paca)
{
+ /* Setup r13 */
local_paca = new_paca;
- mtspr(SPRN_SPRG_PACA, local_paca);
+
#ifdef CONFIG_PPC_BOOK3E
+ /* On Book3E, initialize the TLB miss exception frames */
mtspr(SPRN_SPRG_TLB_EXFRAME, local_paca->extlb);
+#else
+ /* In HV mode, we setup both HPACA and PACA to avoid problems
+ * if we do a GET_PACA() before the feature fixups have been
+ * applied
+ */
+ if (cpu_has_feature(CPU_FTR_HVMODE_206))
+ mtspr(SPRN_SPRG_HPACA, local_paca);
#endif
+ mtspr(SPRN_SPRG_PACA, local_paca);
+
}
static int __initdata paca_size;
void __init allocate_pacas(void)
{
- int nr_cpus, cpu, limit;
+ int cpu, limit;
/*
* We can't take SLB misses on the paca, and we want to access them
@@ -179,23 +190,18 @@ void __init allocate_pacas(void)
if (firmware_has_feature(FW_FEATURE_ISERIES))
limit = min(limit, HvPagesToMap * HVPAGESIZE);
- nr_cpus = NR_CPUS;
- /* On iSeries we know we can never have more than 64 cpus */
- if (firmware_has_feature(FW_FEATURE_ISERIES))
- nr_cpus = min(64, nr_cpus);
-
- paca_size = PAGE_ALIGN(sizeof(struct paca_struct) * nr_cpus);
+ paca_size = PAGE_ALIGN(sizeof(struct paca_struct) * nr_cpu_ids);
paca = __va(memblock_alloc_base(paca_size, PAGE_SIZE, limit));
memset(paca, 0, paca_size);
printk(KERN_DEBUG "Allocated %u bytes for %d pacas at %p\n",
- paca_size, nr_cpus, paca);
+ paca_size, nr_cpu_ids, paca);
- allocate_lppacas(nr_cpus, limit);
+ allocate_lppacas(nr_cpu_ids, limit);
/* Can't use for_each_*_cpu, as they aren't functional yet */
- for (cpu = 0; cpu < nr_cpus; cpu++)
+ for (cpu = 0; cpu < nr_cpu_ids; cpu++)
initialise_paca(&paca[cpu], cpu);
}
diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c
index d225d99fe39d..6baabc13306a 100644
--- a/arch/powerpc/kernel/pci_dn.c
+++ b/arch/powerpc/kernel/pci_dn.c
@@ -43,10 +43,9 @@ void * __devinit update_dn_pci_info(struct device_node *dn, void *data)
const u32 *regs;
struct pci_dn *pdn;
- pdn = alloc_maybe_bootmem(sizeof(*pdn), GFP_KERNEL);
+ pdn = zalloc_maybe_bootmem(sizeof(*pdn), GFP_KERNEL);
if (pdn == NULL)
return NULL;
- memset(pdn, 0, sizeof(*pdn));
dn->data = pdn;
pdn->node = dn;
pdn->phb = phb;
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index ef3ef566235e..7d28f540200c 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -54,7 +54,6 @@ extern void single_step_exception(struct pt_regs *regs);
extern int sys_sigreturn(struct pt_regs *regs);
EXPORT_SYMBOL(clear_pages);
-EXPORT_SYMBOL(copy_page);
EXPORT_SYMBOL(ISA_DMA_THRESHOLD);
EXPORT_SYMBOL(DMA_MODE_READ);
EXPORT_SYMBOL(DMA_MODE_WRITE);
@@ -88,9 +87,7 @@ EXPORT_SYMBOL(__copy_tofrom_user);
EXPORT_SYMBOL(__clear_user);
EXPORT_SYMBOL(__strncpy_from_user);
EXPORT_SYMBOL(__strnlen_user);
-#ifdef CONFIG_PPC64
-EXPORT_SYMBOL(copy_4K_page);
-#endif
+EXPORT_SYMBOL(copy_page);
#if defined(CONFIG_PCI) && defined(CONFIG_PPC32)
EXPORT_SYMBOL(isa_io_base);
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index f74f355a9617..91e52df3d81d 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -395,6 +395,9 @@ struct task_struct *__switch_to(struct task_struct *prev,
struct thread_struct *new_thread, *old_thread;
unsigned long flags;
struct task_struct *last;
+#ifdef CONFIG_PPC_BOOK3S_64
+ struct ppc64_tlb_batch *batch;
+#endif
#ifdef CONFIG_SMP
/* avoid complexity of lazy save/restore of fpu
@@ -513,7 +516,17 @@ struct task_struct *__switch_to(struct task_struct *prev,
old_thread->accum_tb += (current_tb - start_tb);
new_thread->start_tb = current_tb;
}
-#endif
+#endif /* CONFIG_PPC64 */
+
+#ifdef CONFIG_PPC_BOOK3S_64
+ batch = &__get_cpu_var(ppc64_tlb_batch);
+ if (batch->active) {
+ current_thread_info()->local_flags |= _TLF_LAZY_MMU;
+ if (batch->index)
+ __flush_tlb_pending(batch);
+ batch->active = 0;
+ }
+#endif /* CONFIG_PPC_BOOK3S_64 */
local_irq_save(flags);
@@ -528,6 +541,14 @@ struct task_struct *__switch_to(struct task_struct *prev,
hard_irq_disable();
last = _switch(old_thread, new_thread);
+#ifdef CONFIG_PPC_BOOK3S_64
+ if (current_thread_info()->local_flags & _TLF_LAZY_MMU) {
+ current_thread_info()->local_flags &= ~_TLF_LAZY_MMU;
+ batch = &__get_cpu_var(ppc64_tlb_batch);
+ batch->active = 1;
+ }
+#endif /* CONFIG_PPC_BOOK3S_64 */
+
local_irq_restore(flags);
return last;
@@ -702,6 +723,8 @@ void prepare_to_copy(struct task_struct *tsk)
/*
* Copy a thread..
*/
+extern unsigned long dscr_default; /* defined in arch/powerpc/kernel/sysfs.c */
+
int copy_thread(unsigned long clone_flags, unsigned long usp,
unsigned long unused, struct task_struct *p,
struct pt_regs *regs)
@@ -755,11 +778,11 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
_ALIGN_UP(sizeof(struct thread_info), 16);
#ifdef CONFIG_PPC_STD_MMU_64
- if (cpu_has_feature(CPU_FTR_SLB)) {
+ if (mmu_has_feature(MMU_FTR_SLB)) {
unsigned long sp_vsid;
unsigned long llp = mmu_psize_defs[mmu_linear_psize].sllp;
- if (cpu_has_feature(CPU_FTR_1T_SEGMENT))
+ if (mmu_has_feature(MMU_FTR_1T_SEGMENT))
sp_vsid = get_kernel_vsid(sp, MMU_SEGSIZE_1T)
<< SLB_VSID_SHIFT_1T;
else
@@ -769,6 +792,20 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
p->thread.ksp_vsid = sp_vsid;
}
#endif /* CONFIG_PPC_STD_MMU_64 */
+#ifdef CONFIG_PPC64
+ if (cpu_has_feature(CPU_FTR_DSCR)) {
+ if (current->thread.dscr_inherit) {
+ p->thread.dscr_inherit = 1;
+ p->thread.dscr = current->thread.dscr;
+ } else if (0 != dscr_default) {
+ p->thread.dscr_inherit = 1;
+ p->thread.dscr = dscr_default;
+ } else {
+ p->thread.dscr_inherit = 0;
+ p->thread.dscr = 0;
+ }
+ }
+#endif
/*
* The PPC64 ABI makes use of a TOC to contain function
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index e74fa12afc82..48aeb55faae9 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -68,6 +68,7 @@ int __initdata iommu_force_on;
unsigned long tce_alloc_start, tce_alloc_end;
u64 ppc64_rma_size;
#endif
+static phys_addr_t first_memblock_size;
static int __init early_parse_mem(char *p)
{
@@ -123,18 +124,19 @@ static void __init move_device_tree(void)
*/
static struct ibm_pa_feature {
unsigned long cpu_features; /* CPU_FTR_xxx bit */
+ unsigned long mmu_features; /* MMU_FTR_xxx bit */
unsigned int cpu_user_ftrs; /* PPC_FEATURE_xxx bit */
unsigned char pabyte; /* byte number in ibm,pa-features */
unsigned char pabit; /* bit number (big-endian) */
unsigned char invert; /* if 1, pa bit set => clear feature */
} ibm_pa_features[] __initdata = {
- {0, PPC_FEATURE_HAS_MMU, 0, 0, 0},
- {0, PPC_FEATURE_HAS_FPU, 0, 1, 0},
- {CPU_FTR_SLB, 0, 0, 2, 0},
- {CPU_FTR_CTRL, 0, 0, 3, 0},
- {CPU_FTR_NOEXECUTE, 0, 0, 6, 0},
- {CPU_FTR_NODSISRALIGN, 0, 1, 1, 1},
- {CPU_FTR_CI_LARGE_PAGE, 0, 1, 2, 0},
+ {0, 0, PPC_FEATURE_HAS_MMU, 0, 0, 0},
+ {0, 0, PPC_FEATURE_HAS_FPU, 0, 1, 0},
+ {0, MMU_FTR_SLB, 0, 0, 2, 0},
+ {CPU_FTR_CTRL, 0, 0, 0, 3, 0},
+ {CPU_FTR_NOEXECUTE, 0, 0, 0, 6, 0},
+ {CPU_FTR_NODSISRALIGN, 0, 0, 1, 1, 1},
+ {0, MMU_FTR_CI_LARGE_PAGE, 0, 1, 2, 0},
{CPU_FTR_REAL_LE, PPC_FEATURE_TRUE_LE, 5, 0, 0},
};
@@ -166,9 +168,11 @@ static void __init scan_features(unsigned long node, unsigned char *ftrs,
if (bit ^ fp->invert) {
cur_cpu_spec->cpu_features |= fp->cpu_features;
cur_cpu_spec->cpu_user_features |= fp->cpu_user_ftrs;
+ cur_cpu_spec->mmu_features |= fp->mmu_features;
} else {
cur_cpu_spec->cpu_features &= ~fp->cpu_features;
cur_cpu_spec->cpu_user_features &= ~fp->cpu_user_ftrs;
+ cur_cpu_spec->mmu_features &= ~fp->mmu_features;
}
}
}
@@ -268,13 +272,13 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
const char *uname, int depth,
void *data)
{
- static int logical_cpuid = 0;
char *type = of_get_flat_dt_prop(node, "device_type", NULL);
const u32 *prop;
const u32 *intserv;
int i, nthreads;
unsigned long len;
- int found = 0;
+ int found = -1;
+ int found_thread = 0;
/* We are scanning "cpu" nodes only */
if (type == NULL || strcmp(type, "cpu") != 0)
@@ -298,11 +302,10 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
* version 2 of the kexec param format adds the phys cpuid of
* booted proc.
*/
- if (initial_boot_params && initial_boot_params->version >= 2) {
- if (intserv[i] ==
- initial_boot_params->boot_cpuid_phys) {
- found = 1;
- break;
+ if (initial_boot_params->version >= 2) {
+ if (intserv[i] == initial_boot_params->boot_cpuid_phys) {
+ found = boot_cpu_count;
+ found_thread = i;
}
} else {
/*
@@ -311,23 +314,20 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
* off secondary threads.
*/
if (of_get_flat_dt_prop(node,
- "linux,boot-cpu", NULL) != NULL) {
- found = 1;
- break;
- }
+ "linux,boot-cpu", NULL) != NULL)
+ found = boot_cpu_count;
}
-
#ifdef CONFIG_SMP
/* logical cpu id is always 0 on UP kernels */
- logical_cpuid++;
+ boot_cpu_count++;
#endif
}
- if (found) {
- DBG("boot cpu: logical %d physical %d\n", logical_cpuid,
- intserv[i]);
- boot_cpuid = logical_cpuid;
- set_hard_smp_processor_id(boot_cpuid, intserv[i]);
+ if (found >= 0) {
+ DBG("boot cpu: logical %d physical %d\n", found,
+ intserv[found_thread]);
+ boot_cpuid = found;
+ set_hard_smp_processor_id(found, intserv[found_thread]);
/*
* PAPR defines "logical" PVR values for cpus that
@@ -509,11 +509,14 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size)
size = 0x80000000ul - base;
}
#endif
-
- /* First MEMBLOCK added, do some special initializations */
- if (memstart_addr == ~(phys_addr_t)0)
- setup_initial_memory_limit(base, size);
- memstart_addr = min((u64)memstart_addr, base);
+ /* Keep track of the beginning of memory -and- the size of
+ * the very first block in the device-tree as it represents
+ * the RMA on ppc64 server
+ */
+ if (base < memstart_addr) {
+ memstart_addr = base;
+ first_memblock_size = size;
+ }
/* Add the chunk to the MEMBLOCK list */
memblock_add(base, size);
@@ -698,6 +701,7 @@ void __init early_init_devtree(void *params)
of_scan_flat_dt(early_init_dt_scan_root, NULL);
of_scan_flat_dt(early_init_dt_scan_memory_ppc, NULL);
+ setup_initial_memory_limit(memstart_addr, first_memblock_size);
/* Save command line for /proc/cmdline and then parse parameters */
strlcpy(boot_command_line, cmd_line, COMMAND_LINE_SIZE);
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index 941ff4dbc567..c016033ba78d 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -335,6 +335,7 @@ static void __init prom_printf(const char *format, ...)
const char *p, *q, *s;
va_list args;
unsigned long v;
+ long vs;
struct prom_t *_prom = &RELOC(prom);
va_start(args, format);
@@ -368,12 +369,35 @@ static void __init prom_printf(const char *format, ...)
v = va_arg(args, unsigned long);
prom_print_hex(v);
break;
+ case 'd':
+ ++q;
+ vs = va_arg(args, int);
+ if (vs < 0) {
+ prom_print(RELOC("-"));
+ vs = -vs;
+ }
+ prom_print_dec(vs);
+ break;
case 'l':
++q;
- if (*q == 'u') { /* '%lu' */
+ if (*q == 0)
+ break;
+ else if (*q == 'x') {
+ ++q;
+ v = va_arg(args, unsigned long);
+ prom_print_hex(v);
+ } else if (*q == 'u') { /* '%lu' */
++q;
v = va_arg(args, unsigned long);
prom_print_dec(v);
+ } else if (*q == 'd') { /* %ld */
+ ++q;
+ vs = va_arg(args, long);
+ if (vs < 0) {
+ prom_print(RELOC("-"));
+ vs = -vs;
+ }
+ prom_print_dec(vs);
}
break;
}
@@ -676,8 +700,10 @@ static void __init early_cmdline_parse(void)
#endif /* CONFIG_PCI_MSI */
#ifdef CONFIG_PPC_SMLPAR
#define OV5_CMO 0x80 /* Cooperative Memory Overcommitment */
+#define OV5_XCMO 0x40 /* Page Coalescing */
#else
#define OV5_CMO 0x00
+#define OV5_XCMO 0x00
#endif
#define OV5_TYPE1_AFFINITY 0x80 /* Type 1 NUMA affinity */
@@ -732,7 +758,7 @@ static unsigned char ibm_architecture_vec[] = {
OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY |
OV5_DONATE_DEDICATE_CPU | OV5_MSI,
0,
- OV5_CMO,
+ OV5_CMO | OV5_XCMO,
OV5_TYPE1_AFFINITY,
0,
0,
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index a6ae1cfad86c..cb22024f2b42 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -29,6 +29,7 @@
#include <linux/signal.h>
#include <linux/seccomp.h>
#include <linux/audit.h>
+#include <trace/syscall.h>
#ifdef CONFIG_PPC32
#include <linux/module.h>
#endif
@@ -40,6 +41,9 @@
#include <asm/pgtable.h>
#include <asm/system.h>
+#define CREATE_TRACE_POINTS
+#include <trace/events/syscalls.h>
+
/*
* The parameter save area on the stack is used to store arguments being passed
* to callee function and is located at fixed offset from stack pointer.
@@ -1710,6 +1714,9 @@ long do_syscall_trace_enter(struct pt_regs *regs)
*/
ret = -1L;
+ if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
+ trace_sys_enter(regs, regs->gpr[0]);
+
if (unlikely(current->audit_context)) {
#ifdef CONFIG_PPC64
if (!is_32bit_task())
@@ -1738,6 +1745,9 @@ void do_syscall_trace_leave(struct pt_regs *regs)
audit_syscall_exit((regs->ccr&0x10000000)?AUDITSC_FAILURE:AUDITSC_SUCCESS,
regs->result);
+ if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
+ trace_sys_exit(regs, regs->result);
+
step = test_thread_flag(TIF_SINGLESTEP);
if (step || test_thread_flag(TIF_SYSCALL_TRACE))
tracehook_report_syscall_exit(regs, step);
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index 2097f2b3cba8..271ff6318eda 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -42,6 +42,7 @@
#include <asm/time.h>
#include <asm/mmu.h>
#include <asm/topology.h>
+#include <asm/pSeries_reconfig.h>
struct rtas_t rtas = {
.lock = __ARCH_SPIN_LOCK_UNLOCKED
@@ -494,7 +495,7 @@ unsigned int rtas_busy_delay(int status)
might_sleep();
ms = rtas_busy_delay_time(status);
- if (ms)
+ if (ms && need_resched())
msleep(ms);
return ms;
@@ -731,6 +732,7 @@ static int __rtas_suspend_last_cpu(struct rtas_suspend_me_data *data, int wake_w
atomic_set(&data->error, rc);
start_topology_update();
+ pSeries_coalesce_init();
if (wake_when_done) {
atomic_set(&data->done, 1);
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index 21f30cb68077..79fca2651b65 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -381,7 +381,7 @@ static void __init cpu_init_thread_core_maps(int tpc)
int i;
threads_per_core = tpc;
- threads_core_mask = CPU_MASK_NONE;
+ cpumask_clear(&threads_core_mask);
/* This implementation only supports power of 2 number of threads
* for simplicity and performance
@@ -390,7 +390,7 @@ static void __init cpu_init_thread_core_maps(int tpc)
BUG_ON(tpc != (1 << threads_shift));
for (i = 0; i < tpc; i++)
- cpu_set(i, threads_core_mask);
+ cpumask_set_cpu(i, &threads_core_mask);
printk(KERN_INFO "CPU maps initialized for %d thread%s per core\n",
tpc, tpc > 1 ? "s" : "");
@@ -404,7 +404,7 @@ static void __init cpu_init_thread_core_maps(int tpc)
* cpu_present_mask
*
* Having the possible map set up early allows us to restrict allocations
- * of things like irqstacks to num_possible_cpus() rather than NR_CPUS.
+ * of things like irqstacks to nr_cpu_ids rather than NR_CPUS.
*
* We do not initialize the online map here; cpus set their own bits in
* cpu_online_mask as they come up.
@@ -424,7 +424,7 @@ void __init smp_setup_cpu_maps(void)
DBG("smp_setup_cpu_maps()\n");
- while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) {
+ while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < nr_cpu_ids) {
const int *intserv;
int j, len;
@@ -443,7 +443,7 @@ void __init smp_setup_cpu_maps(void)
intserv = &cpu; /* assume logical == phys */
}
- for (j = 0; j < nthreads && cpu < NR_CPUS; j++) {
+ for (j = 0; j < nthreads && cpu < nr_cpu_ids; j++) {
DBG(" thread %d -> cpu %d (hard id %d)\n",
j, cpu, intserv[j]);
set_cpu_present(cpu, true);
@@ -483,12 +483,12 @@ void __init smp_setup_cpu_maps(void)
if (cpu_has_feature(CPU_FTR_SMT))
maxcpus *= nthreads;
- if (maxcpus > NR_CPUS) {
+ if (maxcpus > nr_cpu_ids) {
printk(KERN_WARNING
"Partition configured for %d cpus, "
"operating system maximum is %d.\n",
- maxcpus, NR_CPUS);
- maxcpus = NR_CPUS;
+ maxcpus, nr_cpu_ids);
+ maxcpus = nr_cpu_ids;
} else
printk(KERN_INFO "Partition configured for %d cpus.\n",
maxcpus);
@@ -510,7 +510,7 @@ void __init smp_setup_cpu_maps(void)
cpu_init_thread_core_maps(nthreads);
/* Now that possible cpus are set, set nr_cpu_ids for later use */
- nr_cpu_ids = find_last_bit(cpumask_bits(cpu_possible_mask),NR_CPUS) + 1;
+ setup_nr_cpu_ids();
free_unused_pacas();
}
@@ -602,6 +602,10 @@ int check_legacy_ioport(unsigned long base_port)
* name instead */
if (!np)
np = of_find_node_by_name(NULL, "8042");
+ if (np) {
+ of_i8042_kbd_irq = 1;
+ of_i8042_aux_irq = 12;
+ }
break;
case FDC_BASE: /* FDC1 */
np = of_find_node_by_type(NULL, "fdc");
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 1d2fbc905303..620d792b52e4 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -48,6 +48,7 @@ extern void bootx_init(unsigned long r4, unsigned long phys);
int boot_cpuid = -1;
EXPORT_SYMBOL_GPL(boot_cpuid);
+int __initdata boot_cpu_count;
int boot_cpuid_phys;
int smp_hw_index[NR_CPUS];
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 5a0401fcaebd..a88bf2713d41 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -62,6 +62,7 @@
#include <asm/udbg.h>
#include <asm/kexec.h>
#include <asm/mmu_context.h>
+#include <asm/code-patching.h>
#include "setup.h"
@@ -72,6 +73,7 @@
#endif
int boot_cpuid = 0;
+int __initdata boot_cpu_count;
u64 ppc64_pft_size;
/* Pick defaults since we might want to patch instructions
@@ -233,6 +235,7 @@ void early_setup_secondary(void)
void smp_release_cpus(void)
{
unsigned long *ptr;
+ int i;
DBG(" -> smp_release_cpus()\n");
@@ -245,7 +248,16 @@ void smp_release_cpus(void)
ptr = (unsigned long *)((unsigned long)&__secondary_hold_spinloop
- PHYSICAL_START);
*ptr = __pa(generic_secondary_smp_init);
- mb();
+
+ /* And wait a bit for them to catch up */
+ for (i = 0; i < 100000; i++) {
+ mb();
+ HMT_low();
+ if (boot_cpu_count == 0)
+ break;
+ udelay(1);
+ }
+ DBG("boot_cpu_count = %d\n", boot_cpu_count);
DBG(" <- smp_release_cpus()\n");
}
@@ -423,17 +435,30 @@ void __init setup_system(void)
DBG(" <- setup_system()\n");
}
-static u64 slb0_limit(void)
+/* This returns the limit below which memory accesses to the linear
+ * mapping are guarnateed not to cause a TLB or SLB miss. This is
+ * used to allocate interrupt or emergency stacks for which our
+ * exception entry path doesn't deal with being interrupted.
+ */
+static u64 safe_stack_limit(void)
{
- if (cpu_has_feature(CPU_FTR_1T_SEGMENT)) {
+#ifdef CONFIG_PPC_BOOK3E
+ /* Freescale BookE bolts the entire linear mapping */
+ if (mmu_has_feature(MMU_FTR_TYPE_FSL_E))
+ return linear_map_top;
+ /* Other BookE, we assume the first GB is bolted */
+ return 1ul << 30;
+#else
+ /* BookS, the first segment is bolted */
+ if (mmu_has_feature(MMU_FTR_1T_SEGMENT))
return 1UL << SID_SHIFT_1T;
- }
return 1UL << SID_SHIFT;
+#endif
}
static void __init irqstack_early_init(void)
{
- u64 limit = slb0_limit();
+ u64 limit = safe_stack_limit();
unsigned int i;
/*
@@ -453,6 +478,9 @@ static void __init irqstack_early_init(void)
#ifdef CONFIG_PPC_BOOK3E
static void __init exc_lvl_early_init(void)
{
+ extern unsigned int interrupt_base_book3e;
+ extern unsigned int exc_debug_debug_book3e;
+
unsigned int i;
for_each_possible_cpu(i) {
@@ -463,6 +491,10 @@ static void __init exc_lvl_early_init(void)
mcheckirq_ctx[i] = (struct thread_info *)
__va(memblock_alloc(THREAD_SIZE, THREAD_SIZE));
}
+
+ if (cpu_has_feature(CPU_FTR_DEBUG_LVL_EXC))
+ patch_branch(&interrupt_base_book3e + (0x040 / 4) + 1,
+ (unsigned long)&exc_debug_debug_book3e, 0);
}
#else
#define exc_lvl_early_init()
@@ -486,7 +518,7 @@ static void __init emergency_stack_init(void)
* bringup, we need to get at them in real mode. This means they
* must also be within the RMO region.
*/
- limit = min(slb0_limit(), ppc64_rma_size);
+ limit = min(safe_stack_limit(), ppc64_rma_size);
for_each_possible_cpu(i) {
unsigned long sp;
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index 27c4a4584f80..da989fff19cc 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -381,7 +381,7 @@ badframe:
regs, uc, &uc->uc_mcontext);
#endif
if (show_unhandled_signals && printk_ratelimit())
- printk(regs->msr & MSR_SF ? fmt64 : fmt32,
+ printk(regs->msr & MSR_64BIT ? fmt64 : fmt32,
current->comm, current->pid, "rt_sigreturn",
(long)uc, regs->nip, regs->link);
@@ -469,7 +469,7 @@ badframe:
regs, frame, newsp);
#endif
if (show_unhandled_signals && printk_ratelimit())
- printk(regs->msr & MSR_SF ? fmt64 : fmt32,
+ printk(regs->msr & MSR_64BIT ? fmt64 : fmt32,
current->comm, current->pid, "setup_rt_frame",
(long)frame, regs->nip, regs->link);
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index cbdbb14be4b0..8ebc6700b98d 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -95,7 +95,7 @@ int smt_enabled_at_boot = 1;
static void (*crash_ipi_function_ptr)(struct pt_regs *) = NULL;
#ifdef CONFIG_PPC64
-void __devinit smp_generic_kick_cpu(int nr)
+int __devinit smp_generic_kick_cpu(int nr)
{
BUG_ON(nr < 0 || nr >= NR_CPUS);
@@ -106,37 +106,10 @@ void __devinit smp_generic_kick_cpu(int nr)
*/
paca[nr].cpu_start = 1;
smp_mb();
-}
-#endif
-void smp_message_recv(int msg)
-{
- switch(msg) {
- case PPC_MSG_CALL_FUNCTION:
- generic_smp_call_function_interrupt();
- break;
- case PPC_MSG_RESCHEDULE:
- /* we notice need_resched on exit */
- break;
- case PPC_MSG_CALL_FUNC_SINGLE:
- generic_smp_call_function_single_interrupt();
- break;
- case PPC_MSG_DEBUGGER_BREAK:
- if (crash_ipi_function_ptr) {
- crash_ipi_function_ptr(get_irq_regs());
- break;
- }
-#ifdef CONFIG_DEBUGGER
- debugger_ipi(get_irq_regs());
- break;
-#endif /* CONFIG_DEBUGGER */
- /* FALLTHROUGH */
- default:
- printk("SMP %d: smp_message_recv(): unknown msg %d\n",
- smp_processor_id(), msg);
- break;
- }
+ return 0;
}
+#endif
static irqreturn_t call_function_action(int irq, void *data)
{
@@ -146,7 +119,7 @@ static irqreturn_t call_function_action(int irq, void *data)
static irqreturn_t reschedule_action(int irq, void *data)
{
- /* we just need the return path side effect of checking need_resched */
+ scheduler_ipi();
return IRQ_HANDLED;
}
@@ -158,7 +131,15 @@ static irqreturn_t call_function_single_action(int irq, void *data)
static irqreturn_t debug_ipi_action(int irq, void *data)
{
- smp_message_recv(PPC_MSG_DEBUGGER_BREAK);
+ if (crash_ipi_function_ptr) {
+ crash_ipi_function_ptr(get_irq_regs());
+ return IRQ_HANDLED;
+ }
+
+#ifdef CONFIG_DEBUGGER
+ debugger_ipi(get_irq_regs());
+#endif /* CONFIG_DEBUGGER */
+
return IRQ_HANDLED;
}
@@ -197,6 +178,66 @@ int smp_request_message_ipi(int virq, int msg)
return err;
}
+#ifdef CONFIG_PPC_SMP_MUXED_IPI
+struct cpu_messages {
+ int messages; /* current messages */
+ unsigned long data; /* data for cause ipi */
+};
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpu_messages, ipi_message);
+
+void smp_muxed_ipi_set_data(int cpu, unsigned long data)
+{
+ struct cpu_messages *info = &per_cpu(ipi_message, cpu);
+
+ info->data = data;
+}
+
+void smp_muxed_ipi_message_pass(int cpu, int msg)
+{
+ struct cpu_messages *info = &per_cpu(ipi_message, cpu);
+ char *message = (char *)&info->messages;
+
+ message[msg] = 1;
+ mb();
+ smp_ops->cause_ipi(cpu, info->data);
+}
+
+void smp_muxed_ipi_resend(void)
+{
+ struct cpu_messages *info = &__get_cpu_var(ipi_message);
+
+ if (info->messages)
+ smp_ops->cause_ipi(smp_processor_id(), info->data);
+}
+
+irqreturn_t smp_ipi_demux(void)
+{
+ struct cpu_messages *info = &__get_cpu_var(ipi_message);
+ unsigned int all;
+
+ mb(); /* order any irq clear */
+
+ do {
+ all = xchg_local(&info->messages, 0);
+
+#ifdef __BIG_ENDIAN
+ if (all & (1 << (24 - 8 * PPC_MSG_CALL_FUNCTION)))
+ generic_smp_call_function_interrupt();
+ if (all & (1 << (24 - 8 * PPC_MSG_RESCHEDULE)))
+ scheduler_ipi();
+ if (all & (1 << (24 - 8 * PPC_MSG_CALL_FUNC_SINGLE)))
+ generic_smp_call_function_single_interrupt();
+ if (all & (1 << (24 - 8 * PPC_MSG_DEBUGGER_BREAK)))
+ debug_ipi_action(0, NULL);
+#else
+#error Unsupported ENDIAN
+#endif
+ } while (info->messages);
+
+ return IRQ_HANDLED;
+}
+#endif /* CONFIG_PPC_SMP_MUXED_IPI */
+
void smp_send_reschedule(int cpu)
{
if (likely(smp_ops))
@@ -216,11 +257,18 @@ void arch_send_call_function_ipi_mask(const struct cpumask *mask)
smp_ops->message_pass(cpu, PPC_MSG_CALL_FUNCTION);
}
-#ifdef CONFIG_DEBUGGER
-void smp_send_debugger_break(int cpu)
+#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
+void smp_send_debugger_break(void)
{
- if (likely(smp_ops))
- smp_ops->message_pass(cpu, PPC_MSG_DEBUGGER_BREAK);
+ int cpu;
+ int me = raw_smp_processor_id();
+
+ if (unlikely(!smp_ops))
+ return;
+
+ for_each_online_cpu(cpu)
+ if (cpu != me)
+ smp_ops->message_pass(cpu, PPC_MSG_DEBUGGER_BREAK);
}
#endif
@@ -228,9 +276,9 @@ void smp_send_debugger_break(int cpu)
void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *))
{
crash_ipi_function_ptr = crash_ipi_callback;
- if (crash_ipi_callback && smp_ops) {
+ if (crash_ipi_callback) {
mb();
- smp_ops->message_pass(MSG_ALL_BUT_SELF, PPC_MSG_DEBUGGER_BREAK);
+ smp_send_debugger_break();
}
}
#endif
@@ -410,8 +458,6 @@ int __cpuinit __cpu_up(unsigned int cpu)
{
int rc, c;
- secondary_ti = current_set[cpu];
-
if (smp_ops == NULL ||
(smp_ops->cpu_bootable && !smp_ops->cpu_bootable(cpu)))
return -EINVAL;
@@ -421,6 +467,8 @@ int __cpuinit __cpu_up(unsigned int cpu)
if (rc)
return rc;
+ secondary_ti = current_set[cpu];
+
/* Make sure callin-map entry is 0 (can be leftover a CPU
* hotplug
*/
@@ -434,7 +482,11 @@ int __cpuinit __cpu_up(unsigned int cpu)
/* wake up cpus */
DBG("smp: kicking cpu %d\n", cpu);
- smp_ops->kick_cpu(cpu);
+ rc = smp_ops->kick_cpu(cpu);
+ if (rc) {
+ pr_err("smp: failed starting cpu %d (rc %d)\n", cpu, rc);
+ return rc;
+ }
/*
* wait to see if the cpu made a callin (is actually up).
@@ -507,7 +559,7 @@ int cpu_first_thread_of_core(int core)
}
EXPORT_SYMBOL_GPL(cpu_first_thread_of_core);
-/* Must be called when no change can occur to cpu_present_map,
+/* Must be called when no change can occur to cpu_present_mask,
* i.e. during cpu online or offline.
*/
static struct device_node *cpu_to_l2cache(int cpu)
@@ -608,7 +660,7 @@ void __init smp_cpus_done(unsigned int max_cpus)
* se we pin us down to CPU 0 for a short while
*/
alloc_cpumask_var(&old_mask, GFP_NOWAIT);
- cpumask_copy(old_mask, &current->cpus_allowed);
+ cpumask_copy(old_mask, tsk_cpus_allowed(current));
set_cpus_allowed_ptr(current, cpumask_of(boot_cpuid));
if (smp_ops && smp_ops->setup_cpu)
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
index c0d8c2006bf4..f0f2199e64e1 100644
--- a/arch/powerpc/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@ -182,6 +182,41 @@ static SYSDEV_ATTR(mmcra, 0600, show_mmcra, store_mmcra);
static SYSDEV_ATTR(spurr, 0600, show_spurr, NULL);
static SYSDEV_ATTR(dscr, 0600, show_dscr, store_dscr);
static SYSDEV_ATTR(purr, 0600, show_purr, store_purr);
+
+unsigned long dscr_default = 0;
+EXPORT_SYMBOL(dscr_default);
+
+static ssize_t show_dscr_default(struct sysdev_class *class,
+ struct sysdev_class_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%lx\n", dscr_default);
+}
+
+static ssize_t __used store_dscr_default(struct sysdev_class *class,
+ struct sysdev_class_attribute *attr, const char *buf,
+ size_t count)
+{
+ unsigned long val;
+ int ret = 0;
+
+ ret = sscanf(buf, "%lx", &val);
+ if (ret != 1)
+ return -EINVAL;
+ dscr_default = val;
+
+ return count;
+}
+
+static SYSDEV_CLASS_ATTR(dscr_default, 0600,
+ show_dscr_default, store_dscr_default);
+
+static void sysfs_create_dscr_default(void)
+{
+ int err = 0;
+ if (cpu_has_feature(CPU_FTR_DSCR))
+ err = sysfs_create_file(&cpu_sysdev_class.kset.kobj,
+ &attr_dscr_default.attr);
+}
#endif /* CONFIG_PPC64 */
#ifdef HAS_PPC_PMC_PA6T
@@ -617,6 +652,9 @@ static int __init topology_init(void)
if (cpu_online(cpu))
register_cpu_online(cpu);
}
+#ifdef CONFIG_PPC64
+ sysfs_create_dscr_default();
+#endif /* CONFIG_PPC64 */
return 0;
}
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 5ddb801bc154..0ff4ab98d50c 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -55,6 +55,7 @@
#endif
#include <asm/kexec.h>
#include <asm/ppc-opcode.h>
+#include <asm/rio.h>
#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
int (*__debugger)(struct pt_regs *regs) __read_mostly;
@@ -143,7 +144,6 @@ int die(const char *str, struct pt_regs *regs, long err)
#endif
printk("%s\n", ppc_md.name ? ppc_md.name : "");
- sysfs_printk_last_file();
if (notify_die(DIE_OOPS, str, regs, err, 255,
SIGSEGV) == NOTIFY_STOP)
return 1;
@@ -199,7 +199,7 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
} else if (show_unhandled_signals &&
unhandled_signal(current, signr) &&
printk_ratelimit()) {
- printk(regs->msr & MSR_SF ? fmt64 : fmt32,
+ printk(regs->msr & MSR_64BIT ? fmt64 : fmt32,
current->comm, current->pid, signr,
addr, regs->nip, regs->link, code);
}
@@ -221,7 +221,7 @@ void system_reset_exception(struct pt_regs *regs)
}
#ifdef CONFIG_KEXEC
- cpu_set(smp_processor_id(), cpus_in_sr);
+ cpumask_set_cpu(smp_processor_id(), &cpus_in_sr);
#endif
die("System Reset", regs, SIGABRT);
@@ -425,6 +425,12 @@ int machine_check_e500mc(struct pt_regs *regs)
unsigned long reason = mcsr;
int recoverable = 1;
+ if (reason & MCSR_BUS_RBERR) {
+ recoverable = fsl_rio_mcheck_exception(regs);
+ if (recoverable == 1)
+ goto silent_out;
+ }
+
printk("Machine check in kernel mode.\n");
printk("Caused by (from MCSR=%lx): ", reason);
@@ -500,6 +506,7 @@ int machine_check_e500mc(struct pt_regs *regs)
reason & MCSR_MEA ? "Effective" : "Physical", addr);
}
+silent_out:
mtspr(SPRN_MCSR, mcsr);
return mfspr(SPRN_MCSR) == 0 && recoverable;
}
@@ -508,6 +515,11 @@ int machine_check_e500(struct pt_regs *regs)
{
unsigned long reason = get_mc_reason(regs);
+ if (reason & MCSR_BUS_RBERR) {
+ if (fsl_rio_mcheck_exception(regs))
+ return 1;
+ }
+
printk("Machine check in kernel mode.\n");
printk("Caused by (from MCSR=%lx): ", reason);
@@ -909,6 +921,26 @@ static int emulate_instruction(struct pt_regs *regs)
return emulate_isel(regs, instword);
}
+#ifdef CONFIG_PPC64
+ /* Emulate the mfspr rD, DSCR. */
+ if (((instword & PPC_INST_MFSPR_DSCR_MASK) == PPC_INST_MFSPR_DSCR) &&
+ cpu_has_feature(CPU_FTR_DSCR)) {
+ PPC_WARN_EMULATED(mfdscr, regs);
+ rd = (instword >> 21) & 0x1f;
+ regs->gpr[rd] = mfspr(SPRN_DSCR);
+ return 0;
+ }
+ /* Emulate the mtspr DSCR, rD. */
+ if (((instword & PPC_INST_MTSPR_DSCR_MASK) == PPC_INST_MTSPR_DSCR) &&
+ cpu_has_feature(CPU_FTR_DSCR)) {
+ PPC_WARN_EMULATED(mtdscr, regs);
+ rd = (instword >> 21) & 0x1f;
+ mtspr(SPRN_DSCR, regs->gpr[rd]);
+ current->thread.dscr_inherit = 1;
+ return 0;
+ }
+#endif
+
return -EINVAL;
}
@@ -1506,6 +1538,10 @@ struct ppc_emulated ppc_emulated = {
#ifdef CONFIG_VSX
WARN_EMULATED_SETUP(vsx),
#endif
+#ifdef CONFIG_PPC64
+ WARN_EMULATED_SETUP(mfdscr),
+ WARN_EMULATED_SETUP(mtdscr),
+#endif
};
u32 ppc_warn_emulated;
diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c
index e39cad83c884..23d65abbedce 100644
--- a/arch/powerpc/kernel/udbg.c
+++ b/arch/powerpc/kernel/udbg.c
@@ -62,6 +62,8 @@ void __init udbg_early_init(void)
udbg_init_cpm();
#elif defined(CONFIG_PPC_EARLY_DEBUG_USBGECKO)
udbg_init_usbgecko();
+#elif defined(CONFIG_PPC_EARLY_DEBUG_WSP)
+ udbg_init_wsp();
#endif
#ifdef CONFIG_PPC_EARLY_DEBUG
diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c
index baa33a7517bc..6837f839ab78 100644
--- a/arch/powerpc/kernel/udbg_16550.c
+++ b/arch/powerpc/kernel/udbg_16550.c
@@ -11,6 +11,7 @@
#include <linux/types.h>
#include <asm/udbg.h>
#include <asm/io.h>
+#include <asm/reg_a2.h>
extern u8 real_readb(volatile u8 __iomem *addr);
extern void real_writeb(u8 data, volatile u8 __iomem *addr);
@@ -298,3 +299,53 @@ void __init udbg_init_40x_realmode(void)
udbg_getc_poll = NULL;
}
#endif /* CONFIG_PPC_EARLY_DEBUG_40x */
+
+#ifdef CONFIG_PPC_EARLY_DEBUG_WSP
+static void udbg_wsp_flush(void)
+{
+ if (udbg_comport) {
+ while ((readb(&udbg_comport->lsr) & LSR_THRE) == 0)
+ /* wait for idle */;
+ }
+}
+
+static void udbg_wsp_putc(char c)
+{
+ if (udbg_comport) {
+ if (c == '\n')
+ udbg_wsp_putc('\r');
+ udbg_wsp_flush();
+ writeb(c, &udbg_comport->thr); eieio();
+ }
+}
+
+static int udbg_wsp_getc(void)
+{
+ if (udbg_comport) {
+ while ((readb(&udbg_comport->lsr) & LSR_DR) == 0)
+ ; /* wait for char */
+ return readb(&udbg_comport->rbr);
+ }
+ return -1;
+}
+
+static int udbg_wsp_getc_poll(void)
+{
+ if (udbg_comport)
+ if (readb(&udbg_comport->lsr) & LSR_DR)
+ return readb(&udbg_comport->rbr);
+ return -1;
+}
+
+void __init udbg_init_wsp(void)
+{
+ udbg_comport = (struct NS16550 __iomem *)WSP_UART_VIRT;
+
+ udbg_init_uart(udbg_comport, 57600, 50000000);
+
+ udbg_putc = udbg_wsp_putc;
+ udbg_flush = udbg_wsp_flush;
+ udbg_getc = udbg_wsp_getc;
+ udbg_getc_poll = udbg_wsp_getc_poll;
+}
+#endif /* CONFIG_PPC_EARLY_DEBUG_WSP */
diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S
index 9de6f396cf85..4d5a3edff49e 100644
--- a/arch/powerpc/kernel/vector.S
+++ b/arch/powerpc/kernel/vector.S
@@ -102,7 +102,7 @@ _GLOBAL(giveup_altivec)
MTMSRD(r5) /* enable use of VMX now */
isync
PPC_LCMPI 0,r3,0
- beqlr- /* if no previous owner, done */
+ beqlr /* if no previous owner, done */
addi r3,r3,THREAD /* want THREAD of task */
PPC_LL r5,PT_REGS(r3)
PPC_LCMPI 0,r5,0
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index b9150f07d266..920276c0f6a1 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -160,7 +160,7 @@ SECTIONS
INIT_RAM_FS
}
- PERCPU(L1_CACHE_BYTES, PAGE_SIZE)
+ PERCPU_SECTION(L1_CACHE_BYTES)
. = ALIGN(8);
.machine.desc : AT(ADDR(.machine.desc) - LOAD_OFFSET) {
diff --git a/arch/powerpc/kvm/44x.c b/arch/powerpc/kvm/44x.c
index 74d0e7421143..da3a1225c0ac 100644
--- a/arch/powerpc/kvm/44x.c
+++ b/arch/powerpc/kvm/44x.c
@@ -107,6 +107,16 @@ int kvmppc_core_vcpu_translate(struct kvm_vcpu *vcpu,
return 0;
}
+void kvmppc_core_get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
+{
+ kvmppc_get_sregs_ivor(vcpu, sregs);
+}
+
+int kvmppc_core_set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
+{
+ return kvmppc_set_sregs_ivor(vcpu, sregs);
+}
+
struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
{
struct kvmppc_vcpu_44x *vcpu_44x;
diff --git a/arch/powerpc/kvm/44x_emulate.c b/arch/powerpc/kvm/44x_emulate.c
index 65ea083a5b27..549bb2c9a47a 100644
--- a/arch/powerpc/kvm/44x_emulate.c
+++ b/arch/powerpc/kvm/44x_emulate.c
@@ -158,7 +158,6 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
emulated = kvmppc_booke_emulate_mtspr(vcpu, sprn, rs);
}
- kvmppc_set_exit_type(vcpu, EMULATED_MTSPR_EXITS);
return emulated;
}
@@ -179,7 +178,6 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
emulated = kvmppc_booke_emulate_mfspr(vcpu, sprn, rt);
}
- kvmppc_set_exit_type(vcpu, EMULATED_MFSPR_EXITS);
return emulated;
}
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index c961de40c676..0f95b5cce033 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -236,7 +236,7 @@ void kvmppc_core_queue_dec(struct kvm_vcpu *vcpu)
int kvmppc_core_pending_dec(struct kvm_vcpu *vcpu)
{
- return test_bit(BOOK3S_INTERRUPT_DECREMENTER >> 7, &vcpu->arch.pending_exceptions);
+ return test_bit(BOOK3S_IRQPRIO_DECREMENTER, &vcpu->arch.pending_exceptions);
}
void kvmppc_core_dequeue_dec(struct kvm_vcpu *vcpu)
diff --git a/arch/powerpc/kvm/book3s_rmhandlers.S b/arch/powerpc/kvm/book3s_rmhandlers.S
index 2b9c9088d00e..1a1b34487e71 100644
--- a/arch/powerpc/kvm/book3s_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_rmhandlers.S
@@ -35,9 +35,7 @@
#if defined(CONFIG_PPC_BOOK3S_64)
-#define LOAD_SHADOW_VCPU(reg) \
- mfspr reg, SPRN_SPRG_PACA
-
+#define LOAD_SHADOW_VCPU(reg) GET_PACA(reg)
#define SHADOW_VCPU_OFF PACA_KVM_SVCPU
#define MSR_NOIRQ MSR_KERNEL & ~(MSR_IR | MSR_DR)
#define FUNC(name) GLUE(.,name)
@@ -72,7 +70,7 @@
.global kvmppc_trampoline_\intno
kvmppc_trampoline_\intno:
- mtspr SPRN_SPRG_SCRATCH0, r13 /* Save r13 */
+ SET_SCRATCH0(r13) /* Save r13 */
/*
* First thing to do is to find out if we're coming
@@ -91,7 +89,7 @@ kvmppc_trampoline_\intno:
lwz r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH1)(r13)
mtcr r12
PPC_LL r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH0)(r13)
- mfspr r13, SPRN_SPRG_SCRATCH0 /* r13 = original r13 */
+ GET_SCRATCH0(r13) /* r13 = original r13 */
b kvmppc_resume_\intno /* Get back original handler */
/* Now we know we're handling a KVM guest */
@@ -114,6 +112,9 @@ INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_MACHINE_CHECK
INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_DATA_STORAGE
INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_INST_STORAGE
INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_EXTERNAL
+#ifdef CONFIG_PPC_BOOK3S_64
+INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_EXTERNAL_HV
+#endif
INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_ALIGNMENT
INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_PROGRAM
INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_FP_UNAVAIL
@@ -158,7 +159,7 @@ kvmppc_handler_skip_ins:
lwz r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH1)(r13)
mtcr r12
PPC_LL r12, (SHADOW_VCPU_OFF + SVCPU_SCRATCH0)(r13)
- mfspr r13, SPRN_SPRG_SCRATCH0
+ GET_SCRATCH0(r13)
/* And get back into the code */
RFI
diff --git a/arch/powerpc/kvm/book3s_segment.S b/arch/powerpc/kvm/book3s_segment.S
index 7c52ed0b7051..451264274b8c 100644
--- a/arch/powerpc/kvm/book3s_segment.S
+++ b/arch/powerpc/kvm/book3s_segment.S
@@ -155,14 +155,20 @@ kvmppc_handler_trampoline_exit:
PPC_LL r2, (SHADOW_VCPU_OFF + SVCPU_HOST_R2)(r13)
/* Save guest PC and MSR */
- mfsrr0 r3
+ andi. r0,r12,0x2
+ beq 1f
+ mfspr r3,SPRN_HSRR0
+ mfspr r4,SPRN_HSRR1
+ andi. r12,r12,0x3ffd
+ b 2f
+1: mfsrr0 r3
mfsrr1 r4
-
+2:
PPC_STL r3, (SHADOW_VCPU_OFF + SVCPU_PC)(r13)
PPC_STL r4, (SHADOW_VCPU_OFF + SVCPU_SHADOW_SRR1)(r13)
/* Get scratch'ed off registers */
- mfspr r9, SPRN_SPRG_SCRATCH0
+ GET_SCRATCH0(r9)
PPC_LL r8, (SHADOW_VCPU_OFF + SVCPU_SCRATCH0)(r13)
lwz r7, (SHADOW_VCPU_OFF + SVCPU_SCRATCH1)(r13)
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index ef76acb455c3..8462b3a1c1c7 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -569,6 +569,7 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
kvmppc_set_msr(vcpu, regs->msr);
vcpu->arch.shared->srr0 = regs->srr0;
vcpu->arch.shared->srr1 = regs->srr1;
+ kvmppc_set_pid(vcpu, regs->pid);
vcpu->arch.shared->sprg0 = regs->sprg0;
vcpu->arch.shared->sprg1 = regs->sprg1;
vcpu->arch.shared->sprg2 = regs->sprg2;
@@ -584,16 +585,165 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
return 0;
}
+static void get_sregs_base(struct kvm_vcpu *vcpu,
+ struct kvm_sregs *sregs)
+{
+ u64 tb = get_tb();
+
+ sregs->u.e.features |= KVM_SREGS_E_BASE;
+
+ sregs->u.e.csrr0 = vcpu->arch.csrr0;
+ sregs->u.e.csrr1 = vcpu->arch.csrr1;
+ sregs->u.e.mcsr = vcpu->arch.mcsr;
+ sregs->u.e.esr = vcpu->arch.esr;
+ sregs->u.e.dear = vcpu->arch.shared->dar;
+ sregs->u.e.tsr = vcpu->arch.tsr;
+ sregs->u.e.tcr = vcpu->arch.tcr;
+ sregs->u.e.dec = kvmppc_get_dec(vcpu, tb);
+ sregs->u.e.tb = tb;
+ sregs->u.e.vrsave = vcpu->arch.vrsave;
+}
+
+static int set_sregs_base(struct kvm_vcpu *vcpu,
+ struct kvm_sregs *sregs)
+{
+ if (!(sregs->u.e.features & KVM_SREGS_E_BASE))
+ return 0;
+
+ vcpu->arch.csrr0 = sregs->u.e.csrr0;
+ vcpu->arch.csrr1 = sregs->u.e.csrr1;
+ vcpu->arch.mcsr = sregs->u.e.mcsr;
+ vcpu->arch.esr = sregs->u.e.esr;
+ vcpu->arch.shared->dar = sregs->u.e.dear;
+ vcpu->arch.vrsave = sregs->u.e.vrsave;
+ vcpu->arch.tcr = sregs->u.e.tcr;
+
+ if (sregs->u.e.update_special & KVM_SREGS_E_UPDATE_DEC)
+ vcpu->arch.dec = sregs->u.e.dec;
+
+ kvmppc_emulate_dec(vcpu);
+
+ if (sregs->u.e.update_special & KVM_SREGS_E_UPDATE_TSR) {
+ /*
+ * FIXME: existing KVM timer handling is incomplete.
+ * TSR cannot be read by the guest, and its value in
+ * vcpu->arch is always zero. For now, just handle
+ * the case where the caller is trying to inject a
+ * decrementer interrupt.
+ */
+
+ if ((sregs->u.e.tsr & TSR_DIS) &&
+ (vcpu->arch.tcr & TCR_DIE))
+ kvmppc_core_queue_dec(vcpu);
+ }
+
+ return 0;
+}
+
+static void get_sregs_arch206(struct kvm_vcpu *vcpu,
+ struct kvm_sregs *sregs)
+{
+ sregs->u.e.features |= KVM_SREGS_E_ARCH206;
+
+ sregs->u.e.pir = 0;
+ sregs->u.e.mcsrr0 = vcpu->arch.mcsrr0;
+ sregs->u.e.mcsrr1 = vcpu->arch.mcsrr1;
+ sregs->u.e.decar = vcpu->arch.decar;
+ sregs->u.e.ivpr = vcpu->arch.ivpr;
+}
+
+static int set_sregs_arch206(struct kvm_vcpu *vcpu,
+ struct kvm_sregs *sregs)
+{
+ if (!(sregs->u.e.features & KVM_SREGS_E_ARCH206))
+ return 0;
+
+ if (sregs->u.e.pir != 0)
+ return -EINVAL;
+
+ vcpu->arch.mcsrr0 = sregs->u.e.mcsrr0;
+ vcpu->arch.mcsrr1 = sregs->u.e.mcsrr1;
+ vcpu->arch.decar = sregs->u.e.decar;
+ vcpu->arch.ivpr = sregs->u.e.ivpr;
+
+ return 0;
+}
+
+void kvmppc_get_sregs_ivor(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
+{
+ sregs->u.e.features |= KVM_SREGS_E_IVOR;
+
+ sregs->u.e.ivor_low[0] = vcpu->arch.ivor[BOOKE_IRQPRIO_CRITICAL];
+ sregs->u.e.ivor_low[1] = vcpu->arch.ivor[BOOKE_IRQPRIO_MACHINE_CHECK];
+ sregs->u.e.ivor_low[2] = vcpu->arch.ivor[BOOKE_IRQPRIO_DATA_STORAGE];
+ sregs->u.e.ivor_low[3] = vcpu->arch.ivor[BOOKE_IRQPRIO_INST_STORAGE];
+ sregs->u.e.ivor_low[4] = vcpu->arch.ivor[BOOKE_IRQPRIO_EXTERNAL];
+ sregs->u.e.ivor_low[5] = vcpu->arch.ivor[BOOKE_IRQPRIO_ALIGNMENT];
+ sregs->u.e.ivor_low[6] = vcpu->arch.ivor[BOOKE_IRQPRIO_PROGRAM];
+ sregs->u.e.ivor_low[7] = vcpu->arch.ivor[BOOKE_IRQPRIO_FP_UNAVAIL];
+ sregs->u.e.ivor_low[8] = vcpu->arch.ivor[BOOKE_IRQPRIO_SYSCALL];
+ sregs->u.e.ivor_low[9] = vcpu->arch.ivor[BOOKE_IRQPRIO_AP_UNAVAIL];
+ sregs->u.e.ivor_low[10] = vcpu->arch.ivor[BOOKE_IRQPRIO_DECREMENTER];
+ sregs->u.e.ivor_low[11] = vcpu->arch.ivor[BOOKE_IRQPRIO_FIT];
+ sregs->u.e.ivor_low[12] = vcpu->arch.ivor[BOOKE_IRQPRIO_WATCHDOG];
+ sregs->u.e.ivor_low[13] = vcpu->arch.ivor[BOOKE_IRQPRIO_DTLB_MISS];
+ sregs->u.e.ivor_low[14] = vcpu->arch.ivor[BOOKE_IRQPRIO_ITLB_MISS];
+ sregs->u.e.ivor_low[15] = vcpu->arch.ivor[BOOKE_IRQPRIO_DEBUG];
+}
+
+int kvmppc_set_sregs_ivor(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
+{
+ if (!(sregs->u.e.features & KVM_SREGS_E_IVOR))
+ return 0;
+
+ vcpu->arch.ivor[BOOKE_IRQPRIO_CRITICAL] = sregs->u.e.ivor_low[0];
+ vcpu->arch.ivor[BOOKE_IRQPRIO_MACHINE_CHECK] = sregs->u.e.ivor_low[1];
+ vcpu->arch.ivor[BOOKE_IRQPRIO_DATA_STORAGE] = sregs->u.e.ivor_low[2];
+ vcpu->arch.ivor[BOOKE_IRQPRIO_INST_STORAGE] = sregs->u.e.ivor_low[3];
+ vcpu->arch.ivor[BOOKE_IRQPRIO_EXTERNAL] = sregs->u.e.ivor_low[4];
+ vcpu->arch.ivor[BOOKE_IRQPRIO_ALIGNMENT] = sregs->u.e.ivor_low[5];
+ vcpu->arch.ivor[BOOKE_IRQPRIO_PROGRAM] = sregs->u.e.ivor_low[6];
+ vcpu->arch.ivor[BOOKE_IRQPRIO_FP_UNAVAIL] = sregs->u.e.ivor_low[7];
+ vcpu->arch.ivor[BOOKE_IRQPRIO_SYSCALL] = sregs->u.e.ivor_low[8];
+ vcpu->arch.ivor[BOOKE_IRQPRIO_AP_UNAVAIL] = sregs->u.e.ivor_low[9];
+ vcpu->arch.ivor[BOOKE_IRQPRIO_DECREMENTER] = sregs->u.e.ivor_low[10];
+ vcpu->arch.ivor[BOOKE_IRQPRIO_FIT] = sregs->u.e.ivor_low[11];
+ vcpu->arch.ivor[BOOKE_IRQPRIO_WATCHDOG] = sregs->u.e.ivor_low[12];
+ vcpu->arch.ivor[BOOKE_IRQPRIO_DTLB_MISS] = sregs->u.e.ivor_low[13];
+ vcpu->arch.ivor[BOOKE_IRQPRIO_ITLB_MISS] = sregs->u.e.ivor_low[14];
+ vcpu->arch.ivor[BOOKE_IRQPRIO_DEBUG] = sregs->u.e.ivor_low[15];
+
+ return 0;
+}
+
int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs)
{
- return -ENOTSUPP;
+ sregs->pvr = vcpu->arch.pvr;
+
+ get_sregs_base(vcpu, sregs);
+ get_sregs_arch206(vcpu, sregs);
+ kvmppc_core_get_sregs(vcpu, sregs);
+ return 0;
}
int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
struct kvm_sregs *sregs)
{
- return -ENOTSUPP;
+ int ret;
+
+ if (vcpu->arch.pvr != sregs->pvr)
+ return -EINVAL;
+
+ ret = set_sregs_base(vcpu, sregs);
+ if (ret < 0)
+ return ret;
+
+ ret = set_sregs_arch206(vcpu, sregs);
+ if (ret < 0)
+ return ret;
+
+ return kvmppc_core_set_sregs(vcpu, sregs);
}
int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
diff --git a/arch/powerpc/kvm/booke_interrupts.S b/arch/powerpc/kvm/booke_interrupts.S
index 1cc471faac2d..b58ccae95904 100644
--- a/arch/powerpc/kvm/booke_interrupts.S
+++ b/arch/powerpc/kvm/booke_interrupts.S
@@ -380,7 +380,6 @@ lightweight_exit:
* because host interrupt handlers would get confused. */
lwz r1, VCPU_GPR(r1)(r4)
- /* XXX handle USPRG0 */
/* Host interrupt handlers may have clobbered these guest-readable
* SPRGs, so we need to reload them here with the guest's values. */
lwz r3, VCPU_SPRG4(r4)
diff --git a/arch/powerpc/kvm/e500.c b/arch/powerpc/kvm/e500.c
index e3768ee9b595..318dbc61ba44 100644
--- a/arch/powerpc/kvm/e500.c
+++ b/arch/powerpc/kvm/e500.c
@@ -63,6 +63,7 @@ int kvmppc_core_vcpu_setup(struct kvm_vcpu *vcpu)
/* Registers init */
vcpu->arch.pvr = mfspr(SPRN_PVR);
+ vcpu_e500->svr = mfspr(SPRN_SVR);
/* Since booke kvm only support one core, update all vcpus' PIR to 0 */
vcpu->vcpu_id = 0;
@@ -96,6 +97,81 @@ int kvmppc_core_vcpu_translate(struct kvm_vcpu *vcpu,
return 0;
}
+void kvmppc_core_get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
+{
+ struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
+
+ sregs->u.e.features |= KVM_SREGS_E_ARCH206_MMU | KVM_SREGS_E_SPE |
+ KVM_SREGS_E_PM;
+ sregs->u.e.impl_id = KVM_SREGS_E_IMPL_FSL;
+
+ sregs->u.e.impl.fsl.features = 0;
+ sregs->u.e.impl.fsl.svr = vcpu_e500->svr;
+ sregs->u.e.impl.fsl.hid0 = vcpu_e500->hid0;
+ sregs->u.e.impl.fsl.mcar = vcpu_e500->mcar;
+
+ sregs->u.e.mas0 = vcpu_e500->mas0;
+ sregs->u.e.mas1 = vcpu_e500->mas1;
+ sregs->u.e.mas2 = vcpu_e500->mas2;
+ sregs->u.e.mas7_3 = ((u64)vcpu_e500->mas7 << 32) | vcpu_e500->mas3;
+ sregs->u.e.mas4 = vcpu_e500->mas4;
+ sregs->u.e.mas6 = vcpu_e500->mas6;
+
+ sregs->u.e.mmucfg = mfspr(SPRN_MMUCFG);
+ sregs->u.e.tlbcfg[0] = vcpu_e500->tlb0cfg;
+ sregs->u.e.tlbcfg[1] = vcpu_e500->tlb1cfg;
+ sregs->u.e.tlbcfg[2] = 0;
+ sregs->u.e.tlbcfg[3] = 0;
+
+ sregs->u.e.ivor_high[0] = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL];
+ sregs->u.e.ivor_high[1] = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_DATA];
+ sregs->u.e.ivor_high[2] = vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND];
+ sregs->u.e.ivor_high[3] =
+ vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR];
+
+ kvmppc_get_sregs_ivor(vcpu, sregs);
+}
+
+int kvmppc_core_set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
+{
+ struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
+
+ if (sregs->u.e.impl_id == KVM_SREGS_E_IMPL_FSL) {
+ vcpu_e500->svr = sregs->u.e.impl.fsl.svr;
+ vcpu_e500->hid0 = sregs->u.e.impl.fsl.hid0;
+ vcpu_e500->mcar = sregs->u.e.impl.fsl.mcar;
+ }
+
+ if (sregs->u.e.features & KVM_SREGS_E_ARCH206_MMU) {
+ vcpu_e500->mas0 = sregs->u.e.mas0;
+ vcpu_e500->mas1 = sregs->u.e.mas1;
+ vcpu_e500->mas2 = sregs->u.e.mas2;
+ vcpu_e500->mas7 = sregs->u.e.mas7_3 >> 32;
+ vcpu_e500->mas3 = (u32)sregs->u.e.mas7_3;
+ vcpu_e500->mas4 = sregs->u.e.mas4;
+ vcpu_e500->mas6 = sregs->u.e.mas6;
+ }
+
+ if (!(sregs->u.e.features & KVM_SREGS_E_IVOR))
+ return 0;
+
+ if (sregs->u.e.features & KVM_SREGS_E_SPE) {
+ vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_UNAVAIL] =
+ sregs->u.e.ivor_high[0];
+ vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_DATA] =
+ sregs->u.e.ivor_high[1];
+ vcpu->arch.ivor[BOOKE_IRQPRIO_SPE_FP_ROUND] =
+ sregs->u.e.ivor_high[2];
+ }
+
+ if (sregs->u.e.features & KVM_SREGS_E_PM) {
+ vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR] =
+ sregs->u.e.ivor_high[3];
+ }
+
+ return kvmppc_set_sregs_ivor(vcpu, sregs);
+}
+
struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
{
struct kvmppc_vcpu_e500 *vcpu_e500;
diff --git a/arch/powerpc/kvm/e500_emulate.c b/arch/powerpc/kvm/e500_emulate.c
index 8e3edfbc9634..69cd665a0caf 100644
--- a/arch/powerpc/kvm/e500_emulate.c
+++ b/arch/powerpc/kvm/e500_emulate.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved.
+ * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All rights reserved.
*
* Author: Yu Liu, <yu.liu@freescale.com>
*
@@ -78,8 +78,7 @@ int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs)
switch (sprn) {
case SPRN_PID:
- vcpu_e500->pid[0] = vcpu->arch.shadow_pid =
- vcpu->arch.pid = spr_val;
+ kvmppc_set_pid(vcpu, spr_val);
break;
case SPRN_PID1:
vcpu_e500->pid[1] = spr_val; break;
@@ -175,6 +174,8 @@ int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
kvmppc_set_gpr(vcpu, rt, vcpu_e500->hid0); break;
case SPRN_HID1:
kvmppc_set_gpr(vcpu, rt, vcpu_e500->hid1); break;
+ case SPRN_SVR:
+ kvmppc_set_gpr(vcpu, rt, vcpu_e500->svr); break;
case SPRN_MMUCSR0:
kvmppc_set_gpr(vcpu, rt, 0); break;
diff --git a/arch/powerpc/kvm/e500_tlb.c b/arch/powerpc/kvm/e500_tlb.c
index d6d6d47a75a9..b18fe353397d 100644
--- a/arch/powerpc/kvm/e500_tlb.c
+++ b/arch/powerpc/kvm/e500_tlb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved.
+ * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All rights reserved.
*
* Author: Yu Liu, yu.liu@freescale.com
*
@@ -24,6 +24,7 @@
#include "../mm/mmu_decl.h"
#include "e500_tlb.h"
#include "trace.h"
+#include "timing.h"
#define to_htlb1_esel(esel) (tlb1_entry_num - (esel) - 1)
@@ -506,6 +507,7 @@ int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *vcpu, int rb)
vcpu_e500->mas7 = 0;
}
+ kvmppc_set_exit_type(vcpu, EMULATED_TLBSX_EXITS);
return EMULATE_DONE;
}
@@ -571,6 +573,7 @@ int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu)
write_host_tlbe(vcpu_e500, stlbsel, sesel);
}
+ kvmppc_set_exit_type(vcpu, EMULATED_TLBWE_EXITS);
return EMULATE_DONE;
}
@@ -672,6 +675,14 @@ int kvmppc_e500_tlb_search(struct kvm_vcpu *vcpu,
return -1;
}
+void kvmppc_set_pid(struct kvm_vcpu *vcpu, u32 pid)
+{
+ struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
+
+ vcpu_e500->pid[0] = vcpu->arch.shadow_pid =
+ vcpu->arch.pid = pid;
+}
+
void kvmppc_e500_tlb_setup(struct kvmppc_vcpu_e500 *vcpu_e500)
{
struct tlbe *tlbe;
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c
index c64fd2909bb2..141dce3c6810 100644
--- a/arch/powerpc/kvm/emulate.c
+++ b/arch/powerpc/kvm/emulate.c
@@ -114,6 +114,12 @@ void kvmppc_emulate_dec(struct kvm_vcpu *vcpu)
}
}
+u32 kvmppc_get_dec(struct kvm_vcpu *vcpu, u64 tb)
+{
+ u64 jd = tb - vcpu->arch.dec_jiffies;
+ return vcpu->arch.dec - jd;
+}
+
/* XXX to do:
* lhax
* lhaux
@@ -279,11 +285,8 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
case SPRN_DEC:
{
- u64 jd = get_tb() - vcpu->arch.dec_jiffies;
- kvmppc_set_gpr(vcpu, rt, vcpu->arch.dec - jd);
- pr_debug("mfDEC: %x - %llx = %lx\n",
- vcpu->arch.dec, jd,
- kvmppc_get_gpr(vcpu, rt));
+ kvmppc_set_gpr(vcpu, rt,
+ kvmppc_get_dec(vcpu, get_tb()));
break;
}
default:
@@ -294,6 +297,7 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
}
break;
}
+ kvmppc_set_exit_type(vcpu, EMULATED_MFSPR_EXITS);
break;
case OP_31_XOP_STHX:
@@ -363,6 +367,7 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
printk("mtspr: unknown spr %x\n", sprn);
break;
}
+ kvmppc_set_exit_type(vcpu, EMULATED_MTSPR_EXITS);
break;
case OP_31_XOP_DCBI:
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 99758460efde..616dd516ca1f 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -175,7 +175,11 @@ int kvm_dev_ioctl_check_extension(long ext)
int r;
switch (ext) {
+#ifdef CONFIG_BOOKE
+ case KVM_CAP_PPC_BOOKE_SREGS:
+#else
case KVM_CAP_PPC_SEGSTATE:
+#endif
case KVM_CAP_PPC_PAIRED_SINGLES:
case KVM_CAP_PPC_UNSET_IRQ:
case KVM_CAP_PPC_IRQ_LEVEL:
@@ -284,6 +288,10 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
tasklet_init(&vcpu->arch.tasklet, kvmppc_decrementer_func, (ulong)vcpu);
vcpu->arch.dec_timer.function = kvmppc_decrementer_wakeup;
+#ifdef CONFIG_KVM_EXIT_TIMING
+ mutex_init(&vcpu->arch.exit_timing_lock);
+#endif
+
return 0;
}
@@ -294,12 +302,25 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{
+#ifdef CONFIG_BOOKE
+ /*
+ * vrsave (formerly usprg0) isn't used by Linux, but may
+ * be used by the guest.
+ *
+ * On non-booke this is associated with Altivec and
+ * is handled by code in book3s.c.
+ */
+ mtspr(SPRN_VRSAVE, vcpu->arch.vrsave);
+#endif
kvmppc_core_vcpu_load(vcpu, cpu);
}
void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
{
kvmppc_core_vcpu_put(vcpu);
+#ifdef CONFIG_BOOKE
+ vcpu->arch.vrsave = mfspr(SPRN_VRSAVE);
+#endif
}
int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
diff --git a/arch/powerpc/kvm/timing.c b/arch/powerpc/kvm/timing.c
index a021f5827a33..319177df9587 100644
--- a/arch/powerpc/kvm/timing.c
+++ b/arch/powerpc/kvm/timing.c
@@ -34,8 +34,8 @@ void kvmppc_init_timing_stats(struct kvm_vcpu *vcpu)
{
int i;
- /* pause guest execution to avoid concurrent updates */
- mutex_lock(&vcpu->mutex);
+ /* Take a lock to avoid concurrent updates */
+ mutex_lock(&vcpu->arch.exit_timing_lock);
vcpu->arch.last_exit_type = 0xDEAD;
for (i = 0; i < __NUMBER_OF_KVM_EXIT_TYPES; i++) {
@@ -49,7 +49,7 @@ void kvmppc_init_timing_stats(struct kvm_vcpu *vcpu)
vcpu->arch.timing_exit.tv64 = 0;
vcpu->arch.timing_last_enter.tv64 = 0;
- mutex_unlock(&vcpu->mutex);
+ mutex_unlock(&vcpu->arch.exit_timing_lock);
}
static void add_exit_timing(struct kvm_vcpu *vcpu, u64 duration, int type)
@@ -65,6 +65,8 @@ static void add_exit_timing(struct kvm_vcpu *vcpu, u64 duration, int type)
return;
}
+ mutex_lock(&vcpu->arch.exit_timing_lock);
+
vcpu->arch.timing_count_type[type]++;
/* sum */
@@ -93,6 +95,8 @@ static void add_exit_timing(struct kvm_vcpu *vcpu, u64 duration, int type)
vcpu->arch.timing_min_duration[type] = duration;
if (unlikely(duration > vcpu->arch.timing_max_duration[type]))
vcpu->arch.timing_max_duration[type] = duration;
+
+ mutex_unlock(&vcpu->arch.exit_timing_lock);
}
void kvmppc_update_timing_stats(struct kvm_vcpu *vcpu)
@@ -147,17 +151,30 @@ static int kvmppc_exit_timing_show(struct seq_file *m, void *private)
{
struct kvm_vcpu *vcpu = m->private;
int i;
+ u64 min, max, sum, sum_quad;
seq_printf(m, "%s", "type count min max sum sum_squared\n");
+
for (i = 0; i < __NUMBER_OF_KVM_EXIT_TYPES; i++) {
+
+ min = vcpu->arch.timing_min_duration[i];
+ do_div(min, tb_ticks_per_usec);
+ max = vcpu->arch.timing_max_duration[i];
+ do_div(max, tb_ticks_per_usec);
+ sum = vcpu->arch.timing_sum_duration[i];
+ do_div(sum, tb_ticks_per_usec);
+ sum_quad = vcpu->arch.timing_sum_quad_duration[i];
+ do_div(sum_quad, tb_ticks_per_usec);
+
seq_printf(m, "%12s %10d %10lld %10lld %20lld %20lld\n",
kvm_exit_names[i],
vcpu->arch.timing_count_type[i],
- vcpu->arch.timing_min_duration[i],
- vcpu->arch.timing_max_duration[i],
- vcpu->arch.timing_sum_duration[i],
- vcpu->arch.timing_sum_quad_duration[i]);
+ min,
+ max,
+ sum,
+ sum_quad);
+
}
return 0;
}
diff --git a/arch/powerpc/lib/alloc.c b/arch/powerpc/lib/alloc.c
index f53e09c7dac7..13b676c20d12 100644
--- a/arch/powerpc/lib/alloc.c
+++ b/arch/powerpc/lib/alloc.c
@@ -6,14 +6,6 @@
#include <asm/system.h>
-void * __init_refok alloc_maybe_bootmem(size_t size, gfp_t mask)
-{
- if (mem_init_done)
- return kmalloc(size, mask);
- else
- return alloc_bootmem(size);
-}
-
void * __init_refok zalloc_maybe_bootmem(size_t size, gfp_t mask)
{
void *p;
diff --git a/arch/powerpc/lib/copypage_64.S b/arch/powerpc/lib/copypage_64.S
index 4d4eeb900486..53dcb6b1b708 100644
--- a/arch/powerpc/lib/copypage_64.S
+++ b/arch/powerpc/lib/copypage_64.S
@@ -6,6 +6,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
+#include <asm/page.h>
#include <asm/processor.h>
#include <asm/ppc_asm.h>
#include <asm/asm-offsets.h>
@@ -15,9 +16,9 @@ PPC64_CACHES:
.tc ppc64_caches[TC],ppc64_caches
.section ".text"
-
-_GLOBAL(copy_4K_page)
- li r5,4096 /* 4K page size */
+_GLOBAL(copy_page)
+ lis r5,PAGE_SIZE@h
+ ori r5,r5,PAGE_SIZE@l
BEGIN_FTR_SECTION
ld r10,PPC64_CACHES@toc(r2)
lwz r11,DCACHEL1LOGLINESIZE(r10) /* log2 of cache line size */
diff --git a/arch/powerpc/lib/devres.c b/arch/powerpc/lib/devres.c
index deac4d30daf4..e91615abae66 100644
--- a/arch/powerpc/lib/devres.c
+++ b/arch/powerpc/lib/devres.c
@@ -9,11 +9,11 @@
#include <linux/device.h> /* devres_*(), devm_ioremap_release() */
#include <linux/gfp.h>
-#include <linux/io.h> /* ioremap_flags() */
+#include <linux/io.h> /* ioremap_prot() */
#include <linux/module.h> /* EXPORT_SYMBOL() */
/**
- * devm_ioremap_prot - Managed ioremap_flags()
+ * devm_ioremap_prot - Managed ioremap_prot()
* @dev: Generic device to remap IO address for
* @offset: BUS offset to map
* @size: Size of map
@@ -31,7 +31,7 @@ void __iomem *devm_ioremap_prot(struct device *dev, resource_size_t offset,
if (!ptr)
return NULL;
- addr = ioremap_flags(offset, size, flags);
+ addr = ioremap_prot(offset, size, flags);
if (addr) {
*ptr = addr;
devres_add(dev, ptr);
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index ae5189ab0049..9a52349874ee 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -11,6 +11,7 @@
#include <linux/kernel.h>
#include <linux/kprobes.h>
#include <linux/ptrace.h>
+#include <linux/prefetch.h>
#include <asm/sstep.h>
#include <asm/processor.h>
#include <asm/uaccess.h>
@@ -45,6 +46,18 @@ extern int do_stxvd2x(int rn, unsigned long ea);
#endif
/*
+ * Emulate the truncation of 64 bit values in 32-bit mode.
+ */
+static unsigned long truncate_if_32bit(unsigned long msr, unsigned long val)
+{
+#ifdef __powerpc64__
+ if ((msr & MSR_64BIT) == 0)
+ val &= 0xffffffffUL;
+#endif
+ return val;
+}
+
+/*
* Determine whether a conditional branch instruction would branch.
*/
static int __kprobes branch_taken(unsigned int instr, struct pt_regs *regs)
@@ -90,11 +103,8 @@ static unsigned long __kprobes dform_ea(unsigned int instr, struct pt_regs *regs
if (instr & 0x04000000) /* update forms */
regs->gpr[ra] = ea;
}
-#ifdef __powerpc64__
- if (!(regs->msr & MSR_SF))
- ea &= 0xffffffffUL;
-#endif
- return ea;
+
+ return truncate_if_32bit(regs->msr, ea);
}
#ifdef __powerpc64__
@@ -113,9 +123,8 @@ static unsigned long __kprobes dsform_ea(unsigned int instr, struct pt_regs *reg
if ((instr & 3) == 1) /* update forms */
regs->gpr[ra] = ea;
}
- if (!(regs->msr & MSR_SF))
- ea &= 0xffffffffUL;
- return ea;
+
+ return truncate_if_32bit(regs->msr, ea);
}
#endif /* __powerpc64 */
@@ -136,11 +145,8 @@ static unsigned long __kprobes xform_ea(unsigned int instr, struct pt_regs *regs
if (do_update) /* update forms */
regs->gpr[ra] = ea;
}
-#ifdef __powerpc64__
- if (!(regs->msr & MSR_SF))
- ea &= 0xffffffffUL;
-#endif
- return ea;
+
+ return truncate_if_32bit(regs->msr, ea);
}
/*
@@ -466,7 +472,7 @@ static void __kprobes set_cr0(struct pt_regs *regs, int rd)
regs->ccr = (regs->ccr & 0x0fffffff) | ((regs->xer >> 3) & 0x10000000);
#ifdef __powerpc64__
- if (!(regs->msr & MSR_SF))
+ if (!(regs->msr & MSR_64BIT))
val = (int) val;
#endif
if (val < 0)
@@ -487,7 +493,7 @@ static void __kprobes add_with_carry(struct pt_regs *regs, int rd,
++val;
regs->gpr[rd] = val;
#ifdef __powerpc64__
- if (!(regs->msr & MSR_SF)) {
+ if (!(regs->msr & MSR_64BIT)) {
val = (unsigned int) val;
val1 = (unsigned int) val1;
}
@@ -570,8 +576,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
if ((instr & 2) == 0)
imm += regs->nip;
regs->nip += 4;
- if ((regs->msr & MSR_SF) == 0)
- regs->nip &= 0xffffffffUL;
+ regs->nip = truncate_if_32bit(regs->msr, regs->nip);
if (instr & 1)
regs->link = regs->nip;
if (branch_taken(instr, regs))
@@ -604,13 +609,9 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
imm -= 0x04000000;
if ((instr & 2) == 0)
imm += regs->nip;
- if (instr & 1) {
- regs->link = regs->nip + 4;
- if ((regs->msr & MSR_SF) == 0)
- regs->link &= 0xffffffffUL;
- }
- if ((regs->msr & MSR_SF) == 0)
- imm &= 0xffffffffUL;
+ if (instr & 1)
+ regs->link = truncate_if_32bit(regs->msr, regs->nip + 4);
+ imm = truncate_if_32bit(regs->msr, imm);
regs->nip = imm;
return 1;
case 19:
@@ -618,11 +619,8 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
case 16: /* bclr */
case 528: /* bcctr */
imm = (instr & 0x400)? regs->ctr: regs->link;
- regs->nip += 4;
- if ((regs->msr & MSR_SF) == 0) {
- regs->nip &= 0xffffffffUL;
- imm &= 0xffffffffUL;
- }
+ regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4);
+ imm = truncate_if_32bit(regs->msr, imm);
if (instr & 1)
regs->link = regs->nip;
if (branch_taken(instr, regs))
@@ -1616,11 +1614,7 @@ int __kprobes emulate_step(struct pt_regs *regs, unsigned int instr)
return 0; /* invoke DSI if -EFAULT? */
}
instr_done:
- regs->nip += 4;
-#ifdef __powerpc64__
- if ((regs->msr & MSR_SF) == 0)
- regs->nip &= 0xffffffffUL;
-#endif
+ regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4);
return 1;
logical_done:
diff --git a/arch/powerpc/mm/hash_low_64.S b/arch/powerpc/mm/hash_low_64.S
index 5b7dd4ea02b5..a242b5d7cbe4 100644
--- a/arch/powerpc/mm/hash_low_64.S
+++ b/arch/powerpc/mm/hash_low_64.S
@@ -118,7 +118,7 @@ _GLOBAL(__hash_page_4K)
BEGIN_FTR_SECTION
cmpdi r9,0 /* check segment size */
bne 3f
-END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT)
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
/* Calc va and put it in r29 */
rldicr r29,r5,28,63-28
rldicl r3,r3,0,36
@@ -401,7 +401,7 @@ _GLOBAL(__hash_page_4K)
BEGIN_FTR_SECTION
cmpdi r9,0 /* check segment size */
bne 3f
-END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT)
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
/* Calc va and put it in r29 */
rldicr r29,r5,28,63-28 /* r29 = (vsid << 28) */
rldicl r3,r3,0,36 /* r3 = (ea & 0x0fffffff) */
@@ -715,7 +715,7 @@ BEGIN_FTR_SECTION
andi. r0,r31,_PAGE_NO_CACHE
/* If so, bail out and refault as a 4k page */
bne- ht64_bail_ok
-END_FTR_SECTION_IFCLR(CPU_FTR_CI_LARGE_PAGE)
+END_MMU_FTR_SECTION_IFCLR(MMU_FTR_CI_LARGE_PAGE)
/* Prepare new PTE value (turn access RW into DIRTY, then
* add BUSY and ACCESSED)
*/
@@ -736,7 +736,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_CI_LARGE_PAGE)
BEGIN_FTR_SECTION
cmpdi r9,0 /* check segment size */
bne 3f
-END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT)
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
/* Calc va and put it in r29 */
rldicr r29,r5,28,63-28
rldicl r3,r3,0,36
diff --git a/arch/powerpc/mm/hash_native_64.c b/arch/powerpc/mm/hash_native_64.c
index 784a400e0781..dfd764896db0 100644
--- a/arch/powerpc/mm/hash_native_64.c
+++ b/arch/powerpc/mm/hash_native_64.c
@@ -50,9 +50,8 @@ static inline void __tlbie(unsigned long va, int psize, int ssize)
case MMU_PAGE_4K:
va &= ~0xffful;
va |= ssize << 8;
- asm volatile(ASM_MMU_FTR_IFCLR("tlbie %0,0", PPC_TLBIE(%1,%0),
- %2)
- : : "r" (va), "r"(0), "i" (MMU_FTR_TLBIE_206)
+ asm volatile(ASM_FTR_IFCLR("tlbie %0,0", PPC_TLBIE(%1,%0), %2)
+ : : "r" (va), "r"(0), "i" (CPU_FTR_HVMODE_206)
: "memory");
break;
default:
@@ -61,9 +60,8 @@ static inline void __tlbie(unsigned long va, int psize, int ssize)
va |= penc << 12;
va |= ssize << 8;
va |= 1; /* L */
- asm volatile(ASM_MMU_FTR_IFCLR("tlbie %0,1", PPC_TLBIE(%1,%0),
- %2)
- : : "r" (va), "r"(0), "i" (MMU_FTR_TLBIE_206)
+ asm volatile(ASM_FTR_IFCLR("tlbie %0,1", PPC_TLBIE(%1,%0), %2)
+ : : "r" (va), "r"(0), "i" (CPU_FTR_HVMODE_206)
: "memory");
break;
}
@@ -98,8 +96,8 @@ static inline void __tlbiel(unsigned long va, int psize, int ssize)
static inline void tlbie(unsigned long va, int psize, int ssize, int local)
{
- unsigned int use_local = local && cpu_has_feature(CPU_FTR_TLBIEL);
- int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE);
+ unsigned int use_local = local && mmu_has_feature(MMU_FTR_TLBIEL);
+ int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE);
if (use_local)
use_local = mmu_psize_defs[psize].tlbiel;
@@ -503,7 +501,7 @@ static void native_flush_hash_range(unsigned long number, int local)
} pte_iterate_hashed_end();
}
- if (cpu_has_feature(CPU_FTR_TLBIEL) &&
+ if (mmu_has_feature(MMU_FTR_TLBIEL) &&
mmu_psize_defs[psize].tlbiel && local) {
asm volatile("ptesync":::"memory");
for (i = 0; i < number; i++) {
@@ -517,7 +515,7 @@ static void native_flush_hash_range(unsigned long number, int local)
}
asm volatile("ptesync":::"memory");
} else {
- int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE);
+ int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE);
if (lock_tlbie)
raw_spin_lock(&native_tlbie_lock);
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 58a022d0f463..26b2872b3d00 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -53,6 +53,7 @@
#include <asm/sections.h>
#include <asm/spu.h>
#include <asm/udbg.h>
+#include <asm/code-patching.h>
#ifdef DEBUG
#define DBG(fmt...) udbg_printf(fmt)
@@ -258,11 +259,11 @@ static int __init htab_dt_scan_seg_sizes(unsigned long node,
for (; size >= 4; size -= 4, ++prop) {
if (prop[0] == 40) {
DBG("1T segment support detected\n");
- cur_cpu_spec->cpu_features |= CPU_FTR_1T_SEGMENT;
+ cur_cpu_spec->mmu_features |= MMU_FTR_1T_SEGMENT;
return 1;
}
}
- cur_cpu_spec->cpu_features &= ~CPU_FTR_NO_SLBIE_B;
+ cur_cpu_spec->mmu_features &= ~MMU_FTR_NO_SLBIE_B;
return 0;
}
@@ -288,7 +289,7 @@ static int __init htab_dt_scan_page_sizes(unsigned long node,
if (prop != NULL) {
DBG("Page sizes from device-tree:\n");
size /= 4;
- cur_cpu_spec->cpu_features &= ~(CPU_FTR_16M_PAGE);
+ cur_cpu_spec->mmu_features &= ~(MMU_FTR_16M_PAGE);
while(size > 0) {
unsigned int shift = prop[0];
unsigned int slbenc = prop[1];
@@ -316,7 +317,7 @@ static int __init htab_dt_scan_page_sizes(unsigned long node,
break;
case 0x18:
idx = MMU_PAGE_16M;
- cur_cpu_spec->cpu_features |= CPU_FTR_16M_PAGE;
+ cur_cpu_spec->mmu_features |= MMU_FTR_16M_PAGE;
break;
case 0x22:
idx = MMU_PAGE_16G;
@@ -411,7 +412,7 @@ static void __init htab_init_page_sizes(void)
* Not in the device-tree, let's fallback on known size
* list for 16M capable GP & GR
*/
- if (cpu_has_feature(CPU_FTR_16M_PAGE))
+ if (mmu_has_feature(MMU_FTR_16M_PAGE))
memcpy(mmu_psize_defs, mmu_psize_defaults_gp,
sizeof(mmu_psize_defaults_gp));
found:
@@ -441,7 +442,7 @@ static void __init htab_init_page_sizes(void)
mmu_vmalloc_psize = MMU_PAGE_64K;
if (mmu_linear_psize == MMU_PAGE_4K)
mmu_linear_psize = MMU_PAGE_64K;
- if (cpu_has_feature(CPU_FTR_CI_LARGE_PAGE)) {
+ if (mmu_has_feature(MMU_FTR_CI_LARGE_PAGE)) {
/*
* Don't use 64k pages for ioremap on pSeries, since
* that would stop us accessing the HEA ethernet.
@@ -547,15 +548,7 @@ int remove_section_mapping(unsigned long start, unsigned long end)
}
#endif /* CONFIG_MEMORY_HOTPLUG */
-static inline void make_bl(unsigned int *insn_addr, void *func)
-{
- unsigned long funcp = *((unsigned long *)func);
- int offset = funcp - (unsigned long)insn_addr;
-
- *insn_addr = (unsigned int)(0x48000001 | (offset & 0x03fffffc));
- flush_icache_range((unsigned long)insn_addr, 4+
- (unsigned long)insn_addr);
-}
+#define FUNCTION_TEXT(A) ((*(unsigned long *)(A)))
static void __init htab_finish_init(void)
{
@@ -570,16 +563,33 @@ static void __init htab_finish_init(void)
extern unsigned int *ht64_call_hpte_remove;
extern unsigned int *ht64_call_hpte_updatepp;
- make_bl(ht64_call_hpte_insert1, ppc_md.hpte_insert);
- make_bl(ht64_call_hpte_insert2, ppc_md.hpte_insert);
- make_bl(ht64_call_hpte_remove, ppc_md.hpte_remove);
- make_bl(ht64_call_hpte_updatepp, ppc_md.hpte_updatepp);
+ patch_branch(ht64_call_hpte_insert1,
+ FUNCTION_TEXT(ppc_md.hpte_insert),
+ BRANCH_SET_LINK);
+ patch_branch(ht64_call_hpte_insert2,
+ FUNCTION_TEXT(ppc_md.hpte_insert),
+ BRANCH_SET_LINK);
+ patch_branch(ht64_call_hpte_remove,
+ FUNCTION_TEXT(ppc_md.hpte_remove),
+ BRANCH_SET_LINK);
+ patch_branch(ht64_call_hpte_updatepp,
+ FUNCTION_TEXT(ppc_md.hpte_updatepp),
+ BRANCH_SET_LINK);
+
#endif /* CONFIG_PPC_HAS_HASH_64K */
- make_bl(htab_call_hpte_insert1, ppc_md.hpte_insert);
- make_bl(htab_call_hpte_insert2, ppc_md.hpte_insert);
- make_bl(htab_call_hpte_remove, ppc_md.hpte_remove);
- make_bl(htab_call_hpte_updatepp, ppc_md.hpte_updatepp);
+ patch_branch(htab_call_hpte_insert1,
+ FUNCTION_TEXT(ppc_md.hpte_insert),
+ BRANCH_SET_LINK);
+ patch_branch(htab_call_hpte_insert2,
+ FUNCTION_TEXT(ppc_md.hpte_insert),
+ BRANCH_SET_LINK);
+ patch_branch(htab_call_hpte_remove,
+ FUNCTION_TEXT(ppc_md.hpte_remove),
+ BRANCH_SET_LINK);
+ patch_branch(htab_call_hpte_updatepp,
+ FUNCTION_TEXT(ppc_md.hpte_updatepp),
+ BRANCH_SET_LINK);
}
static void __init htab_initialize(void)
@@ -598,7 +608,7 @@ static void __init htab_initialize(void)
/* Initialize page sizes */
htab_init_page_sizes();
- if (cpu_has_feature(CPU_FTR_1T_SEGMENT)) {
+ if (mmu_has_feature(MMU_FTR_1T_SEGMENT)) {
mmu_kernel_ssize = MMU_SEGSIZE_1T;
mmu_highuser_ssize = MMU_SEGSIZE_1T;
printk(KERN_INFO "Using 1TB segments\n");
@@ -739,7 +749,7 @@ void __init early_init_mmu(void)
/* Initialize stab / SLB management except on iSeries
*/
- if (cpu_has_feature(CPU_FTR_SLB))
+ if (mmu_has_feature(MMU_FTR_SLB))
slb_initialize();
else if (!firmware_has_feature(FW_FEATURE_ISERIES))
stab_initialize(get_paca()->stab_real);
@@ -756,7 +766,7 @@ void __cpuinit early_init_mmu_secondary(void)
* in real mode on pSeries and we want a virtual address on
* iSeries anyway
*/
- if (cpu_has_feature(CPU_FTR_SLB))
+ if (mmu_has_feature(MMU_FTR_SLB))
slb_initialize();
else
stab_initialize(get_paca()->stab_addr);
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index 9bb249c3046e..0b9a5c1901b9 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -529,7 +529,7 @@ static int __init hugetlbpage_init(void)
{
int psize;
- if (!cpu_has_feature(CPU_FTR_16M_PAGE))
+ if (!mmu_has_feature(MMU_FTR_16M_PAGE))
return -ENODEV;
for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) {
diff --git a/arch/powerpc/mm/mmu_context_hash64.c b/arch/powerpc/mm/mmu_context_hash64.c
index 2535828aa84b..3bafc3deca6d 100644
--- a/arch/powerpc/mm/mmu_context_hash64.c
+++ b/arch/powerpc/mm/mmu_context_hash64.c
@@ -20,9 +20,205 @@
#include <linux/idr.h>
#include <linux/module.h>
#include <linux/gfp.h>
+#include <linux/slab.h>
#include <asm/mmu_context.h>
+#ifdef CONFIG_PPC_ICSWX
+/*
+ * The processor and its L2 cache cause the icswx instruction to
+ * generate a COP_REQ transaction on PowerBus. The transaction has
+ * no address, and the processor does not perform an MMU access
+ * to authenticate the transaction. The command portion of the
+ * PowerBus COP_REQ transaction includes the LPAR_ID (LPID) and
+ * the coprocessor Process ID (PID), which the coprocessor compares
+ * to the authorized LPID and PID held in the coprocessor, to determine
+ * if the process is authorized to generate the transaction.
+ * The data of the COP_REQ transaction is 128-byte or less and is
+ * placed in cacheable memory on a 128-byte cache line boundary.
+ *
+ * The task to use a coprocessor should use use_cop() to allocate
+ * a coprocessor PID before executing icswx instruction. use_cop()
+ * also enables the coprocessor context switching. Drop_cop() is
+ * used to free the coprocessor PID.
+ *
+ * Example:
+ * Host Fabric Interface (HFI) is a PowerPC network coprocessor.
+ * Each HFI have multiple windows. Each HFI window serves as a
+ * network device sending to and receiving from HFI network.
+ * HFI immediate send function uses icswx instruction. The immediate
+ * send function allows small (single cache-line) packets be sent
+ * without using the regular HFI send FIFO and doorbell, which are
+ * much slower than immediate send.
+ *
+ * For each task intending to use HFI immediate send, the HFI driver
+ * calls use_cop() to obtain a coprocessor PID for the task.
+ * The HFI driver then allocate a free HFI window and save the
+ * coprocessor PID to the HFI window to allow the task to use the
+ * HFI window.
+ *
+ * The HFI driver repeatedly creates immediate send packets and
+ * issues icswx instruction to send data through the HFI window.
+ * The HFI compares the coprocessor PID in the CPU PID register
+ * to the PID held in the HFI window to determine if the transaction
+ * is allowed.
+ *
+ * When the task to release the HFI window, the HFI driver calls
+ * drop_cop() to release the coprocessor PID.
+ */
+
+#define COP_PID_NONE 0
+#define COP_PID_MIN (COP_PID_NONE + 1)
+#define COP_PID_MAX (0xFFFF)
+
+static DEFINE_SPINLOCK(mmu_context_acop_lock);
+static DEFINE_IDA(cop_ida);
+
+void switch_cop(struct mm_struct *next)
+{
+ mtspr(SPRN_PID, next->context.cop_pid);
+ mtspr(SPRN_ACOP, next->context.acop);
+}
+
+static int new_cop_pid(struct ida *ida, int min_id, int max_id,
+ spinlock_t *lock)
+{
+ int index;
+ int err;
+
+again:
+ if (!ida_pre_get(ida, GFP_KERNEL))
+ return -ENOMEM;
+
+ spin_lock(lock);
+ err = ida_get_new_above(ida, min_id, &index);
+ spin_unlock(lock);
+
+ if (err == -EAGAIN)
+ goto again;
+ else if (err)
+ return err;
+
+ if (index > max_id) {
+ spin_lock(lock);
+ ida_remove(ida, index);
+ spin_unlock(lock);
+ return -ENOMEM;
+ }
+
+ return index;
+}
+
+static void sync_cop(void *arg)
+{
+ struct mm_struct *mm = arg;
+
+ if (mm == current->active_mm)
+ switch_cop(current->active_mm);
+}
+
+/**
+ * Start using a coprocessor.
+ * @acop: mask of coprocessor to be used.
+ * @mm: The mm the coprocessor to associate with. Most likely current mm.
+ *
+ * Return a positive PID if successful. Negative errno otherwise.
+ * The returned PID will be fed to the coprocessor to determine if an
+ * icswx transaction is authenticated.
+ */
+int use_cop(unsigned long acop, struct mm_struct *mm)
+{
+ int ret;
+
+ if (!cpu_has_feature(CPU_FTR_ICSWX))
+ return -ENODEV;
+
+ if (!mm || !acop)
+ return -EINVAL;
+
+ /* We need to make sure mm_users doesn't change */
+ down_read(&mm->mmap_sem);
+ spin_lock(mm->context.cop_lockp);
+
+ if (mm->context.cop_pid == COP_PID_NONE) {
+ ret = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX,
+ &mmu_context_acop_lock);
+ if (ret < 0)
+ goto out;
+
+ mm->context.cop_pid = ret;
+ }
+ mm->context.acop |= acop;
+
+ sync_cop(mm);
+
+ /*
+ * If this is a threaded process then there might be other threads
+ * running. We need to send an IPI to force them to pick up any
+ * change in PID and ACOP.
+ */
+ if (atomic_read(&mm->mm_users) > 1)
+ smp_call_function(sync_cop, mm, 1);
+
+ ret = mm->context.cop_pid;
+
+out:
+ spin_unlock(mm->context.cop_lockp);
+ up_read(&mm->mmap_sem);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(use_cop);
+
+/**
+ * Stop using a coprocessor.
+ * @acop: mask of coprocessor to be stopped.
+ * @mm: The mm the coprocessor associated with.
+ */
+void drop_cop(unsigned long acop, struct mm_struct *mm)
+{
+ int free_pid = COP_PID_NONE;
+
+ if (!cpu_has_feature(CPU_FTR_ICSWX))
+ return;
+
+ if (WARN_ON_ONCE(!mm))
+ return;
+
+ /* We need to make sure mm_users doesn't change */
+ down_read(&mm->mmap_sem);
+ spin_lock(mm->context.cop_lockp);
+
+ mm->context.acop &= ~acop;
+
+ if ((!mm->context.acop) && (mm->context.cop_pid != COP_PID_NONE)) {
+ free_pid = mm->context.cop_pid;
+ mm->context.cop_pid = COP_PID_NONE;
+ }
+
+ sync_cop(mm);
+
+ /*
+ * If this is a threaded process then there might be other threads
+ * running. We need to send an IPI to force them to pick up any
+ * change in PID and ACOP.
+ */
+ if (atomic_read(&mm->mm_users) > 1)
+ smp_call_function(sync_cop, mm, 1);
+
+ if (free_pid != COP_PID_NONE) {
+ spin_lock(&mmu_context_acop_lock);
+ ida_remove(&cop_ida, free_pid);
+ spin_unlock(&mmu_context_acop_lock);
+ }
+
+ spin_unlock(mm->context.cop_lockp);
+ up_read(&mm->mmap_sem);
+}
+EXPORT_SYMBOL_GPL(drop_cop);
+
+#endif /* CONFIG_PPC_ICSWX */
+
static DEFINE_SPINLOCK(mmu_context_lock);
static DEFINE_IDA(mmu_context_ida);
@@ -31,7 +227,6 @@ static DEFINE_IDA(mmu_context_ida);
* Each segment contains 2^28 bytes. Each context maps 2^44 bytes,
* so we can support 2^19-1 contexts (19 == 35 + 28 - 44).
*/
-#define NO_CONTEXT 0
#define MAX_CONTEXT ((1UL << 19) - 1)
int __init_new_context(void)
@@ -79,6 +274,16 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
slice_set_user_psize(mm, mmu_virtual_psize);
subpage_prot_init_new_context(mm);
mm->context.id = index;
+#ifdef CONFIG_PPC_ICSWX
+ mm->context.cop_lockp = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
+ if (!mm->context.cop_lockp) {
+ __destroy_context(index);
+ subpage_prot_free(mm);
+ mm->context.id = MMU_NO_CONTEXT;
+ return -ENOMEM;
+ }
+ spin_lock_init(mm->context.cop_lockp);
+#endif /* CONFIG_PPC_ICSWX */
return 0;
}
@@ -93,7 +298,12 @@ EXPORT_SYMBOL_GPL(__destroy_context);
void destroy_context(struct mm_struct *mm)
{
+#ifdef CONFIG_PPC_ICSWX
+ drop_cop(mm->context.acop, mm);
+ kfree(mm->context.cop_lockp);
+ mm->context.cop_lockp = NULL;
+#endif /* CONFIG_PPC_ICSWX */
__destroy_context(mm->context.id);
subpage_prot_free(mm);
- mm->context.id = NO_CONTEXT;
+ mm->context.id = MMU_NO_CONTEXT;
}
diff --git a/arch/powerpc/mm/mmu_context_nohash.c b/arch/powerpc/mm/mmu_context_nohash.c
index c0aab52da3a5..336807de550e 100644
--- a/arch/powerpc/mm/mmu_context_nohash.c
+++ b/arch/powerpc/mm/mmu_context_nohash.c
@@ -338,12 +338,14 @@ static int __cpuinit mmu_context_cpu_notify(struct notifier_block *self,
return NOTIFY_OK;
switch (action) {
- case CPU_ONLINE:
- case CPU_ONLINE_FROZEN:
+ case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
pr_devel("MMU: Allocating stale context map for CPU %d\n", cpu);
stale_map[cpu] = kzalloc(CTX_MAP_SIZE, GFP_KERNEL);
break;
#ifdef CONFIG_HOTPLUG_CPU
+ case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
case CPU_DEAD:
case CPU_DEAD_FROZEN:
pr_devel("MMU: Freeing stale context map for CPU %d\n", cpu);
@@ -407,7 +409,17 @@ void __init mmu_context_init(void)
} else if (mmu_has_feature(MMU_FTR_TYPE_47x)) {
first_context = 1;
last_context = 65535;
- } else {
+ } else
+#ifdef CONFIG_PPC_BOOK3E_MMU
+ if (mmu_has_feature(MMU_FTR_TYPE_3E)) {
+ u32 mmucfg = mfspr(SPRN_MMUCFG);
+ u32 pid_bits = (mmucfg & MMUCFG_PIDSIZE_MASK)
+ >> MMUCFG_PIDSIZE_SHIFT;
+ first_context = 1;
+ last_context = (1UL << (pid_bits + 1)) - 1;
+ } else
+#endif
+ {
first_context = 1;
last_context = 255;
}
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index 5ec1dad2a19d..2164006fe170 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -311,14 +311,13 @@ EXPORT_SYMBOL_GPL(of_node_to_nid);
static int __init find_min_common_depth(void)
{
int depth;
- struct device_node *rtas_root;
struct device_node *chosen;
+ struct device_node *root;
const char *vec5;
- rtas_root = of_find_node_by_path("/rtas");
-
- if (!rtas_root)
- return -1;
+ root = of_find_node_by_path("/rtas");
+ if (!root)
+ root = of_find_node_by_path("/");
/*
* This property is a set of 32-bit integers, each representing
@@ -332,7 +331,7 @@ static int __init find_min_common_depth(void)
* NUMA boundary and the following are progressively less significant
* boundaries. There can be more than one level of NUMA.
*/
- distance_ref_points = of_get_property(rtas_root,
+ distance_ref_points = of_get_property(root,
"ibm,associativity-reference-points",
&distance_ref_points_depth);
@@ -376,11 +375,11 @@ static int __init find_min_common_depth(void)
distance_ref_points_depth = MAX_DISTANCE_REF_POINTS;
}
- of_node_put(rtas_root);
+ of_node_put(root);
return depth;
err:
- of_node_put(rtas_root);
+ of_node_put(root);
return -1;
}
@@ -1453,7 +1452,7 @@ int arch_update_cpu_topology(void)
unsigned int associativity[VPHN_ASSOC_BUFSIZE] = {0};
struct sys_device *sysdev;
- for_each_cpu_mask(cpu, cpu_associativity_changes_mask) {
+ for_each_cpu(cpu,&cpu_associativity_changes_mask) {
vphn_get_associativity(cpu, associativity);
nid = associativity_to_nid(associativity);
diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c
index 6a3997f98dfb..af40c8768a78 100644
--- a/arch/powerpc/mm/pgtable.c
+++ b/arch/powerpc/mm/pgtable.c
@@ -33,110 +33,6 @@
#include "mmu_decl.h"
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
-#ifdef CONFIG_SMP
-
-/*
- * Handle batching of page table freeing on SMP. Page tables are
- * queued up and send to be freed later by RCU in order to avoid
- * freeing a page table page that is being walked without locks
- */
-
-static DEFINE_PER_CPU(struct pte_freelist_batch *, pte_freelist_cur);
-static unsigned long pte_freelist_forced_free;
-
-struct pte_freelist_batch
-{
- struct rcu_head rcu;
- unsigned int index;
- unsigned long tables[0];
-};
-
-#define PTE_FREELIST_SIZE \
- ((PAGE_SIZE - sizeof(struct pte_freelist_batch)) \
- / sizeof(unsigned long))
-
-static void pte_free_smp_sync(void *arg)
-{
- /* Do nothing, just ensure we sync with all CPUs */
-}
-
-/* This is only called when we are critically out of memory
- * (and fail to get a page in pte_free_tlb).
- */
-static void pgtable_free_now(void *table, unsigned shift)
-{
- pte_freelist_forced_free++;
-
- smp_call_function(pte_free_smp_sync, NULL, 1);
-
- pgtable_free(table, shift);
-}
-
-static void pte_free_rcu_callback(struct rcu_head *head)
-{
- struct pte_freelist_batch *batch =
- container_of(head, struct pte_freelist_batch, rcu);
- unsigned int i;
-
- for (i = 0; i < batch->index; i++) {
- void *table = (void *)(batch->tables[i] & ~MAX_PGTABLE_INDEX_SIZE);
- unsigned shift = batch->tables[i] & MAX_PGTABLE_INDEX_SIZE;
-
- pgtable_free(table, shift);
- }
-
- free_page((unsigned long)batch);
-}
-
-static void pte_free_submit(struct pte_freelist_batch *batch)
-{
- call_rcu_sched(&batch->rcu, pte_free_rcu_callback);
-}
-
-void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift)
-{
- /* This is safe since tlb_gather_mmu has disabled preemption */
- struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur);
- unsigned long pgf;
-
- if (atomic_read(&tlb->mm->mm_users) < 2 ||
- cpumask_equal(mm_cpumask(tlb->mm), cpumask_of(smp_processor_id()))){
- pgtable_free(table, shift);
- return;
- }
-
- if (*batchp == NULL) {
- *batchp = (struct pte_freelist_batch *)__get_free_page(GFP_ATOMIC);
- if (*batchp == NULL) {
- pgtable_free_now(table, shift);
- return;
- }
- (*batchp)->index = 0;
- }
- BUG_ON(shift > MAX_PGTABLE_INDEX_SIZE);
- pgf = (unsigned long)table | shift;
- (*batchp)->tables[(*batchp)->index++] = pgf;
- if ((*batchp)->index == PTE_FREELIST_SIZE) {
- pte_free_submit(*batchp);
- *batchp = NULL;
- }
-}
-
-void pte_free_finish(void)
-{
- /* This is safe since tlb_gather_mmu has disabled preemption */
- struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur);
-
- if (*batchp == NULL)
- return;
- pte_free_submit(*batchp);
- *batchp = NULL;
-}
-
-#endif /* CONFIG_SMP */
-
static inline int is_exec_fault(void)
{
return current->thread.regs && TRAP(current->thread.regs) == 0x400;
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index 8dc41c0157fe..51f87956f8f8 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -133,7 +133,15 @@ ioremap(phys_addr_t addr, unsigned long size)
EXPORT_SYMBOL(ioremap);
void __iomem *
-ioremap_flags(phys_addr_t addr, unsigned long size, unsigned long flags)
+ioremap_wc(phys_addr_t addr, unsigned long size)
+{
+ return __ioremap_caller(addr, size, _PAGE_NO_CACHE,
+ __builtin_return_address(0));
+}
+EXPORT_SYMBOL(ioremap_wc);
+
+void __iomem *
+ioremap_prot(phys_addr_t addr, unsigned long size, unsigned long flags)
{
/* writeable implies dirty for kernel addresses */
if (flags & _PAGE_RW)
@@ -152,7 +160,7 @@ ioremap_flags(phys_addr_t addr, unsigned long size, unsigned long flags)
return __ioremap_caller(addr, size, flags, __builtin_return_address(0));
}
-EXPORT_SYMBOL(ioremap_flags);
+EXPORT_SYMBOL(ioremap_prot);
void __iomem *
__ioremap(phys_addr_t addr, unsigned long size, unsigned long flags)
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index 88927a05cdc2..6e595f6496d4 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -255,7 +255,17 @@ void __iomem * ioremap(phys_addr_t addr, unsigned long size)
return __ioremap_caller(addr, size, flags, caller);
}
-void __iomem * ioremap_flags(phys_addr_t addr, unsigned long size,
+void __iomem * ioremap_wc(phys_addr_t addr, unsigned long size)
+{
+ unsigned long flags = _PAGE_NO_CACHE;
+ void *caller = __builtin_return_address(0);
+
+ if (ppc_md.ioremap)
+ return ppc_md.ioremap(addr, size, flags, caller);
+ return __ioremap_caller(addr, size, flags, caller);
+}
+
+void __iomem * ioremap_prot(phys_addr_t addr, unsigned long size,
unsigned long flags)
{
void *caller = __builtin_return_address(0);
@@ -311,7 +321,8 @@ void iounmap(volatile void __iomem *token)
}
EXPORT_SYMBOL(ioremap);
-EXPORT_SYMBOL(ioremap_flags);
+EXPORT_SYMBOL(ioremap_wc);
+EXPORT_SYMBOL(ioremap_prot);
EXPORT_SYMBOL(__ioremap);
EXPORT_SYMBOL(__ioremap_at);
EXPORT_SYMBOL(iounmap);
diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c
index 1d98ecc8eecd..e22276cb67a4 100644
--- a/arch/powerpc/mm/slb.c
+++ b/arch/powerpc/mm/slb.c
@@ -24,6 +24,7 @@
#include <asm/firmware.h>
#include <linux/compiler.h>
#include <asm/udbg.h>
+#include <asm/code-patching.h>
extern void slb_allocate_realmode(unsigned long ea);
@@ -166,7 +167,7 @@ static inline int esids_match(unsigned long addr1, unsigned long addr2)
int esid_1t_count;
/* System is not 1T segment size capable. */
- if (!cpu_has_feature(CPU_FTR_1T_SEGMENT))
+ if (!mmu_has_feature(MMU_FTR_1T_SEGMENT))
return (GET_ESID(addr1) == GET_ESID(addr2));
esid_1t_count = (((addr1 >> SID_SHIFT_1T) != 0) +
@@ -201,7 +202,7 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm)
*/
hard_irq_disable();
offset = get_paca()->slb_cache_ptr;
- if (!cpu_has_feature(CPU_FTR_NO_SLBIE_B) &&
+ if (!mmu_has_feature(MMU_FTR_NO_SLBIE_B) &&
offset <= SLB_CACHE_ENTRIES) {
int i;
asm volatile("isync" : : : "memory");
@@ -249,9 +250,8 @@ void switch_slb(struct task_struct *tsk, struct mm_struct *mm)
static inline void patch_slb_encoding(unsigned int *insn_addr,
unsigned int immed)
{
- *insn_addr = (*insn_addr & 0xffff0000) | immed;
- flush_icache_range((unsigned long)insn_addr, 4+
- (unsigned long)insn_addr);
+ int insn = (*insn_addr & 0xffff0000) | immed;
+ patch_instruction(insn_addr, insn);
}
void slb_set_size(u16 size)
diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S
index 95ce35581696..ef653dc95b65 100644
--- a/arch/powerpc/mm/slb_low.S
+++ b/arch/powerpc/mm/slb_low.S
@@ -58,7 +58,7 @@ _GLOBAL(slb_miss_kernel_load_linear)
li r11,0
BEGIN_FTR_SECTION
b slb_finish_load
-END_FTR_SECTION_IFCLR(CPU_FTR_1T_SEGMENT)
+END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT)
b slb_finish_load_1T
1:
@@ -87,7 +87,7 @@ _GLOBAL(slb_miss_kernel_load_vmemmap)
6:
BEGIN_FTR_SECTION
b slb_finish_load
-END_FTR_SECTION_IFCLR(CPU_FTR_1T_SEGMENT)
+END_MMU_FTR_SECTION_IFCLR(MMU_FTR_1T_SEGMENT)
b slb_finish_load_1T
0: /* user address: proto-VSID = context << 15 | ESID. First check
@@ -138,11 +138,11 @@ END_FTR_SECTION_IFCLR(CPU_FTR_1T_SEGMENT)
ld r9,PACACONTEXTID(r13)
BEGIN_FTR_SECTION
cmpldi r10,0x1000
-END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT)
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
rldimi r10,r9,USER_ESID_BITS,0
BEGIN_FTR_SECTION
bge slb_finish_load_1T
-END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT)
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
b slb_finish_load
8: /* invalid EA */
diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c
index 446a01842a73..41e31642a86a 100644
--- a/arch/powerpc/mm/stab.c
+++ b/arch/powerpc/mm/stab.c
@@ -243,7 +243,7 @@ void __init stabs_alloc(void)
{
int cpu;
- if (cpu_has_feature(CPU_FTR_SLB))
+ if (mmu_has_feature(MMU_FTR_SLB))
return;
for_each_possible_cpu(cpu) {
diff --git a/arch/powerpc/mm/tlb_hash32.c b/arch/powerpc/mm/tlb_hash32.c
index 690566b66e8e..27b863c14941 100644
--- a/arch/powerpc/mm/tlb_hash32.c
+++ b/arch/powerpc/mm/tlb_hash32.c
@@ -71,9 +71,6 @@ void tlb_flush(struct mmu_gather *tlb)
*/
_tlbia();
}
-
- /* Push out batch of freed page tables */
- pte_free_finish();
}
/*
diff --git a/arch/powerpc/mm/tlb_hash64.c b/arch/powerpc/mm/tlb_hash64.c
index c14d09f614f3..31f18207970b 100644
--- a/arch/powerpc/mm/tlb_hash64.c
+++ b/arch/powerpc/mm/tlb_hash64.c
@@ -155,7 +155,7 @@ void __flush_tlb_pending(struct ppc64_tlb_batch *batch)
void tlb_flush(struct mmu_gather *tlb)
{
- struct ppc64_tlb_batch *tlbbatch = &__get_cpu_var(ppc64_tlb_batch);
+ struct ppc64_tlb_batch *tlbbatch = &get_cpu_var(ppc64_tlb_batch);
/* If there's a TLB batch pending, then we must flush it because the
* pages are going to be freed and we really don't want to have a CPU
@@ -164,8 +164,7 @@ void tlb_flush(struct mmu_gather *tlb)
if (tlbbatch->index)
__flush_tlb_pending(tlbbatch);
- /* Push out batch of freed page tables */
- pte_free_finish();
+ put_cpu_var(ppc64_tlb_batch);
}
/**
diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c
index 2a030d89bbc6..0bdad3aecc67 100644
--- a/arch/powerpc/mm/tlb_nohash.c
+++ b/arch/powerpc/mm/tlb_nohash.c
@@ -299,9 +299,6 @@ EXPORT_SYMBOL(flush_tlb_range);
void tlb_flush(struct mmu_gather *tlb)
{
flush_tlb_mm(tlb->mm);
-
- /* Push out batch of freed page tables */
- pte_free_finish();
}
/*
diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c
index 8ee51a252cf1..e6bec74be131 100644
--- a/arch/powerpc/oprofile/op_model_power4.c
+++ b/arch/powerpc/oprofile/op_model_power4.c
@@ -261,6 +261,28 @@ static int get_kernel(unsigned long pc, unsigned long mmcra)
return is_kernel;
}
+static bool pmc_overflow(unsigned long val)
+{
+ if ((int)val < 0)
+ return true;
+
+ /*
+ * Events on POWER7 can roll back if a speculative event doesn't
+ * eventually complete. Unfortunately in some rare cases they will
+ * raise a performance monitor exception. We need to catch this to
+ * ensure we reset the PMC. In all cases the PMC will be 256 or less
+ * cycles from overflow.
+ *
+ * We only do this if the first pass fails to find any overflowing
+ * PMCs because a user might set a period of less than 256 and we
+ * don't want to mistakenly reset them.
+ */
+ if (__is_processor(PV_POWER7) && ((0x80000000 - val) <= 256))
+ return true;
+
+ return false;
+}
+
static void power4_handle_interrupt(struct pt_regs *regs,
struct op_counter_config *ctr)
{
@@ -281,7 +303,7 @@ static void power4_handle_interrupt(struct pt_regs *regs,
for (i = 0; i < cur_cpu_spec->num_pmcs; ++i) {
val = classic_ctr_read(i);
- if (val < 0) {
+ if (pmc_overflow(val)) {
if (oprofile_running && ctr[i].enabled) {
oprofile_add_ext_sample(pc, regs, i, is_kernel);
classic_ctr_write(i, reset_value[i]);
diff --git a/arch/powerpc/platforms/40x/Kconfig b/arch/powerpc/platforms/40x/Kconfig
index b72176434ebe..d733d7ca939c 100644
--- a/arch/powerpc/platforms/40x/Kconfig
+++ b/arch/powerpc/platforms/40x/Kconfig
@@ -57,6 +57,8 @@ config KILAUEA
select 405EX
select PPC40x_SIMPLE
select PPC4xx_PCI_EXPRESS
+ select PCI_MSI
+ select PPC4xx_MSI
help
This option enables support for the AMCC PPC405EX evaluation board.
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
index f485fc5f6d5e..e958b6f48ec2 100644
--- a/arch/powerpc/platforms/44x/Kconfig
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -74,6 +74,8 @@ config KATMAI
select 440SPe
select PCI
select PPC4xx_PCI_EXPRESS
+ select PCI_MSI
+ select PCC4xx_MSI
help
This option enables support for the AMCC PPC440SPe evaluation board.
@@ -118,6 +120,8 @@ config CANYONLANDS
select 460EX
select PCI
select PPC4xx_PCI_EXPRESS
+ select PCI_MSI
+ select PPC4xx_MSI
select IBM_NEW_EMAC_RGMII
select IBM_NEW_EMAC_ZMII
help
@@ -144,6 +148,8 @@ config REDWOOD
select 460SX
select PCI
select PPC4xx_PCI_EXPRESS
+ select PCI_MSI
+ select PPC4xx_MSI
help
This option enables support for the AMCC PPC460SX Redwood board.
diff --git a/arch/powerpc/platforms/44x/iss4xx.c b/arch/powerpc/platforms/44x/iss4xx.c
index aa46e9d1e771..19395f18b1db 100644
--- a/arch/powerpc/platforms/44x/iss4xx.c
+++ b/arch/powerpc/platforms/44x/iss4xx.c
@@ -87,7 +87,7 @@ static void __cpuinit smp_iss4xx_setup_cpu(int cpu)
mpic_setup_this_cpu();
}
-static void __cpuinit smp_iss4xx_kick_cpu(int cpu)
+static int __cpuinit smp_iss4xx_kick_cpu(int cpu)
{
struct device_node *cpunode = of_get_cpu_node(cpu, NULL);
const u64 *spin_table_addr_prop;
@@ -104,7 +104,7 @@ static void __cpuinit smp_iss4xx_kick_cpu(int cpu)
NULL);
if (spin_table_addr_prop == NULL) {
pr_err("CPU%d: Can't start, missing cpu-release-addr !\n", cpu);
- return;
+ return -ENOENT;
}
/* Assume it's mapped as part of the linear mapping. This is a bit
@@ -117,6 +117,8 @@ static void __cpuinit smp_iss4xx_kick_cpu(int cpu)
smp_wmb();
spin_table[1] = __pa(start_secondary_47x);
mb();
+
+ return 0;
}
static struct smp_ops_t iss_smp_ops = {
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
index cfc4b2009982..9f09319352c0 100644
--- a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
+++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c
@@ -61,7 +61,7 @@ irq_to_pic_bit(unsigned int irq)
static void
cpld_mask_irq(struct irq_data *d)
{
- unsigned int cpld_irq = (unsigned int)irq_map[d->irq].hwirq;
+ unsigned int cpld_irq = (unsigned int)irqd_to_hwirq(d);
void __iomem *pic_mask = irq_to_pic_mask(cpld_irq);
out_8(pic_mask,
@@ -71,7 +71,7 @@ cpld_mask_irq(struct irq_data *d)
static void
cpld_unmask_irq(struct irq_data *d)
{
- unsigned int cpld_irq = (unsigned int)irq_map[d->irq].hwirq;
+ unsigned int cpld_irq = (unsigned int)irqd_to_hwirq(d);
void __iomem *pic_mask = irq_to_pic_mask(cpld_irq);
out_8(pic_mask,
@@ -97,7 +97,7 @@ cpld_pic_get_irq(int offset, u8 ignore, u8 __iomem *statusp,
status |= (ignore | mask);
if (status == 0xff)
- return NO_IRQ_IGNORE;
+ return NO_IRQ;
cpld_irq = ffz(status) + offset;
@@ -109,14 +109,14 @@ cpld_pic_cascade(unsigned int irq, struct irq_desc *desc)
{
irq = cpld_pic_get_irq(0, PCI_IGNORE, &cpld_regs->pci_status,
&cpld_regs->pci_mask);
- if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) {
+ if (irq != NO_IRQ) {
generic_handle_irq(irq);
return;
}
irq = cpld_pic_get_irq(8, MISC_IGNORE, &cpld_regs->misc_status,
&cpld_regs->misc_mask);
- if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) {
+ if (irq != NO_IRQ) {
generic_handle_irq(irq);
return;
}
diff --git a/arch/powerpc/platforms/52xx/media5200.c b/arch/powerpc/platforms/52xx/media5200.c
index 57a6a349e932..96f85e5e0cd3 100644
--- a/arch/powerpc/platforms/52xx/media5200.c
+++ b/arch/powerpc/platforms/52xx/media5200.c
@@ -56,7 +56,7 @@ static void media5200_irq_unmask(struct irq_data *d)
spin_lock_irqsave(&media5200_irq.lock, flags);
val = in_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE);
- val |= 1 << (MEDIA5200_IRQ_SHIFT + irq_map[d->irq].hwirq);
+ val |= 1 << (MEDIA5200_IRQ_SHIFT + irqd_to_hwirq(d));
out_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE, val);
spin_unlock_irqrestore(&media5200_irq.lock, flags);
}
@@ -68,7 +68,7 @@ static void media5200_irq_mask(struct irq_data *d)
spin_lock_irqsave(&media5200_irq.lock, flags);
val = in_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE);
- val &= ~(1 << (MEDIA5200_IRQ_SHIFT + irq_map[d->irq].hwirq));
+ val &= ~(1 << (MEDIA5200_IRQ_SHIFT + irqd_to_hwirq(d)));
out_be32(media5200_irq.regs + MEDIA5200_IRQ_ENABLE, val);
spin_unlock_irqrestore(&media5200_irq.lock, flags);
}
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c
index 1dd15400f6f0..1a9a49570579 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c
@@ -157,48 +157,30 @@ static inline void io_be_clrbit(u32 __iomem *addr, int bitno)
*/
static void mpc52xx_extirq_mask(struct irq_data *d)
{
- int irq;
- int l2irq;
-
- irq = irq_map[d->irq].hwirq;
- l2irq = irq & MPC52xx_IRQ_L2_MASK;
-
+ int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
io_be_clrbit(&intr->ctrl, 11 - l2irq);
}
static void mpc52xx_extirq_unmask(struct irq_data *d)
{
- int irq;
- int l2irq;
-
- irq = irq_map[d->irq].hwirq;
- l2irq = irq & MPC52xx_IRQ_L2_MASK;
-
+ int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
io_be_setbit(&intr->ctrl, 11 - l2irq);
}
static void mpc52xx_extirq_ack(struct irq_data *d)
{
- int irq;
- int l2irq;
-
- irq = irq_map[d->irq].hwirq;
- l2irq = irq & MPC52xx_IRQ_L2_MASK;
-
+ int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
io_be_setbit(&intr->ctrl, 27-l2irq);
}
static int mpc52xx_extirq_set_type(struct irq_data *d, unsigned int flow_type)
{
u32 ctrl_reg, type;
- int irq;
- int l2irq;
+ int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
void *handler = handle_level_irq;
- irq = irq_map[d->irq].hwirq;
- l2irq = irq & MPC52xx_IRQ_L2_MASK;
-
- pr_debug("%s: irq=%x. l2=%d flow_type=%d\n", __func__, irq, l2irq, flow_type);
+ pr_debug("%s: irq=%x. l2=%d flow_type=%d\n", __func__,
+ (int) irqd_to_hwirq(d), l2irq, flow_type);
switch (flow_type) {
case IRQF_TRIGGER_HIGH: type = 0; break;
@@ -237,23 +219,13 @@ static int mpc52xx_null_set_type(struct irq_data *d, unsigned int flow_type)
static void mpc52xx_main_mask(struct irq_data *d)
{
- int irq;
- int l2irq;
-
- irq = irq_map[d->irq].hwirq;
- l2irq = irq & MPC52xx_IRQ_L2_MASK;
-
+ int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
io_be_setbit(&intr->main_mask, 16 - l2irq);
}
static void mpc52xx_main_unmask(struct irq_data *d)
{
- int irq;
- int l2irq;
-
- irq = irq_map[d->irq].hwirq;
- l2irq = irq & MPC52xx_IRQ_L2_MASK;
-
+ int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
io_be_clrbit(&intr->main_mask, 16 - l2irq);
}
@@ -270,23 +242,13 @@ static struct irq_chip mpc52xx_main_irqchip = {
*/
static void mpc52xx_periph_mask(struct irq_data *d)
{
- int irq;
- int l2irq;
-
- irq = irq_map[d->irq].hwirq;
- l2irq = irq & MPC52xx_IRQ_L2_MASK;
-
+ int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
io_be_setbit(&intr->per_mask, 31 - l2irq);
}
static void mpc52xx_periph_unmask(struct irq_data *d)
{
- int irq;
- int l2irq;
-
- irq = irq_map[d->irq].hwirq;
- l2irq = irq & MPC52xx_IRQ_L2_MASK;
-
+ int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
io_be_clrbit(&intr->per_mask, 31 - l2irq);
}
@@ -303,34 +265,19 @@ static struct irq_chip mpc52xx_periph_irqchip = {
*/
static void mpc52xx_sdma_mask(struct irq_data *d)
{
- int irq;
- int l2irq;
-
- irq = irq_map[d->irq].hwirq;
- l2irq = irq & MPC52xx_IRQ_L2_MASK;
-
+ int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
io_be_setbit(&sdma->IntMask, l2irq);
}
static void mpc52xx_sdma_unmask(struct irq_data *d)
{
- int irq;
- int l2irq;
-
- irq = irq_map[d->irq].hwirq;
- l2irq = irq & MPC52xx_IRQ_L2_MASK;
-
+ int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
io_be_clrbit(&sdma->IntMask, l2irq);
}
static void mpc52xx_sdma_ack(struct irq_data *d)
{
- int irq;
- int l2irq;
-
- irq = irq_map[d->irq].hwirq;
- l2irq = irq & MPC52xx_IRQ_L2_MASK;
-
+ int l2irq = irqd_to_hwirq(d) & MPC52xx_IRQ_L2_MASK;
out_be32(&sdma->IntPend, 1 << l2irq);
}
@@ -539,7 +486,7 @@ void __init mpc52xx_init_irq(void)
unsigned int mpc52xx_get_irq(void)
{
u32 status;
- int irq = NO_IRQ_IGNORE;
+ int irq;
status = in_be32(&intr->enc_status);
if (status & 0x00000400) { /* critical */
@@ -562,6 +509,8 @@ unsigned int mpc52xx_get_irq(void)
} else {
irq |= (MPC52xx_IRQ_L1_PERP << MPC52xx_IRQ_L1_OFFSET);
}
+ } else {
+ return NO_IRQ;
}
return irq_linear_revmap(mpc52xx_irqhost, irq);
diff --git a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
index 4a4eb6ffa12f..8ccf9ed62fe2 100644
--- a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
+++ b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c
@@ -42,7 +42,7 @@ struct pq2ads_pci_pic {
static void pq2ads_pci_mask_irq(struct irq_data *d)
{
struct pq2ads_pci_pic *priv = irq_data_get_irq_chip_data(d);
- int irq = NUM_IRQS - virq_to_hw(d->irq) - 1;
+ int irq = NUM_IRQS - irqd_to_hwirq(d) - 1;
if (irq != -1) {
unsigned long flags;
@@ -58,7 +58,7 @@ static void pq2ads_pci_mask_irq(struct irq_data *d)
static void pq2ads_pci_unmask_irq(struct irq_data *d)
{
struct pq2ads_pci_pic *priv = irq_data_get_irq_chip_data(d);
- int irq = NUM_IRQS - virq_to_hw(d->irq) - 1;
+ int irq = NUM_IRQS - irqd_to_hwirq(d) - 1;
if (irq != -1) {
unsigned long flags;
@@ -112,16 +112,8 @@ static int pci_pic_host_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static void pci_host_unmap(struct irq_host *h, unsigned int virq)
-{
- /* remove chip and handler */
- irq_set_chip_data(virq, NULL);
- irq_set_chip(virq, NULL);
-}
-
static struct irq_host_ops pci_pic_host_ops = {
.map = pci_pic_host_map,
- .unmap = pci_host_unmap,
};
int __init pq2ads_pci_init_irq(void)
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c
index 0d00ff9d05a0..d6a93a10c0f5 100644
--- a/arch/powerpc/platforms/85xx/smp.c
+++ b/arch/powerpc/platforms/85xx/smp.c
@@ -41,7 +41,7 @@ extern void __early_start(void);
#define NUM_BOOT_ENTRY 8
#define SIZE_BOOT_ENTRY (NUM_BOOT_ENTRY * sizeof(u32))
-static void __init
+static int __init
smp_85xx_kick_cpu(int nr)
{
unsigned long flags;
@@ -60,7 +60,7 @@ smp_85xx_kick_cpu(int nr)
if (cpu_rel_addr == NULL) {
printk(KERN_ERR "No cpu-release-addr for cpu %d\n", nr);
- return;
+ return -ENOENT;
}
/*
@@ -107,6 +107,8 @@ smp_85xx_kick_cpu(int nr)
iounmap(bptr_vaddr);
pr_debug("waited %d msecs for CPU #%d.\n", n, nr);
+
+ return 0;
}
static void __init
@@ -233,8 +235,10 @@ void __init mpc85xx_smp_init(void)
smp_85xx_ops.message_pass = smp_mpic_message_pass;
}
- if (cpu_has_feature(CPU_FTR_DBELL))
- smp_85xx_ops.message_pass = doorbell_message_pass;
+ if (cpu_has_feature(CPU_FTR_DBELL)) {
+ smp_85xx_ops.message_pass = smp_muxed_ipi_message_pass;
+ smp_85xx_ops.cause_ipi = doorbell_cause_ipi;
+ }
BUG_ON(!smp_85xx_ops.message_pass);
diff --git a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c
index db864623b4ae..12cb9bb2cc68 100644
--- a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c
+++ b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c
@@ -48,8 +48,6 @@ static struct socrates_fpga_irq_info fpga_irqs[SOCRATES_FPGA_NUM_IRQS] = {
[8] = {0, IRQ_TYPE_LEVEL_HIGH},
};
-#define socrates_fpga_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq)
-
static DEFINE_RAW_SPINLOCK(socrates_fpga_pic_lock);
static void __iomem *socrates_fpga_pic_iobase;
@@ -110,11 +108,9 @@ void socrates_fpga_pic_cascade(unsigned int irq, struct irq_desc *desc)
static void socrates_fpga_pic_ack(struct irq_data *d)
{
unsigned long flags;
- unsigned int hwirq, irq_line;
+ unsigned int irq_line, hwirq = irqd_to_hwirq(d);
uint32_t mask;
- hwirq = socrates_fpga_irq_to_hw(d->irq);
-
irq_line = fpga_irqs[hwirq].irq_line;
raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
@@ -127,12 +123,10 @@ static void socrates_fpga_pic_ack(struct irq_data *d)
static void socrates_fpga_pic_mask(struct irq_data *d)
{
unsigned long flags;
- unsigned int hwirq;
+ unsigned int hwirq = irqd_to_hwirq(d);
int irq_line;
u32 mask;
- hwirq = socrates_fpga_irq_to_hw(d->irq);
-
irq_line = fpga_irqs[hwirq].irq_line;
raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
@@ -145,12 +139,10 @@ static void socrates_fpga_pic_mask(struct irq_data *d)
static void socrates_fpga_pic_mask_ack(struct irq_data *d)
{
unsigned long flags;
- unsigned int hwirq;
+ unsigned int hwirq = irqd_to_hwirq(d);
int irq_line;
u32 mask;
- hwirq = socrates_fpga_irq_to_hw(d->irq);
-
irq_line = fpga_irqs[hwirq].irq_line;
raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
@@ -164,12 +156,10 @@ static void socrates_fpga_pic_mask_ack(struct irq_data *d)
static void socrates_fpga_pic_unmask(struct irq_data *d)
{
unsigned long flags;
- unsigned int hwirq;
+ unsigned int hwirq = irqd_to_hwirq(d);
int irq_line;
u32 mask;
- hwirq = socrates_fpga_irq_to_hw(d->irq);
-
irq_line = fpga_irqs[hwirq].irq_line;
raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
@@ -182,12 +172,10 @@ static void socrates_fpga_pic_unmask(struct irq_data *d)
static void socrates_fpga_pic_eoi(struct irq_data *d)
{
unsigned long flags;
- unsigned int hwirq;
+ unsigned int hwirq = irqd_to_hwirq(d);
int irq_line;
u32 mask;
- hwirq = socrates_fpga_irq_to_hw(d->irq);
-
irq_line = fpga_irqs[hwirq].irq_line;
raw_spin_lock_irqsave(&socrates_fpga_pic_lock, flags);
mask = socrates_fpga_pic_read(FPGA_PIC_IRQMASK(irq_line))
@@ -201,12 +189,10 @@ static int socrates_fpga_pic_set_type(struct irq_data *d,
unsigned int flow_type)
{
unsigned long flags;
- unsigned int hwirq;
+ unsigned int hwirq = irqd_to_hwirq(d);
int polarity;
u32 mask;
- hwirq = socrates_fpga_irq_to_hw(d->irq);
-
if (fpga_irqs[hwirq].type != IRQ_TYPE_NONE)
return -EINVAL;
diff --git a/arch/powerpc/platforms/86xx/gef_pic.c b/arch/powerpc/platforms/86xx/gef_pic.c
index 0beec7d5566b..94594e58594c 100644
--- a/arch/powerpc/platforms/86xx/gef_pic.c
+++ b/arch/powerpc/platforms/86xx/gef_pic.c
@@ -46,8 +46,6 @@
#define GEF_PIC_CPU0_MCP_MASK GEF_PIC_MCP_MASK(0)
#define GEF_PIC_CPU1_MCP_MASK GEF_PIC_MCP_MASK(1)
-#define gef_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq)
-
static DEFINE_RAW_SPINLOCK(gef_pic_lock);
@@ -113,11 +111,9 @@ void gef_pic_cascade(unsigned int irq, struct irq_desc *desc)
static void gef_pic_mask(struct irq_data *d)
{
unsigned long flags;
- unsigned int hwirq;
+ unsigned int hwirq = irqd_to_hwirq(d);
u32 mask;
- hwirq = gef_irq_to_hw(d->irq);
-
raw_spin_lock_irqsave(&gef_pic_lock, flags);
mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
mask &= ~(1 << hwirq);
@@ -136,11 +132,9 @@ static void gef_pic_mask_ack(struct irq_data *d)
static void gef_pic_unmask(struct irq_data *d)
{
unsigned long flags;
- unsigned int hwirq;
+ unsigned int hwirq = irqd_to_hwirq(d);
u32 mask;
- hwirq = gef_irq_to_hw(d->irq);
-
raw_spin_lock_irqsave(&gef_pic_lock, flags);
mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
mask |= (1 << hwirq);
diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
index 018cc67be426..a896511690c2 100644
--- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
+++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
@@ -66,7 +66,7 @@ static void __init mpc8610_suspend_init(void)
return;
}
- ret = request_irq(irq, mpc8610_sw9_irq, 0, "sw9/wakeup", NULL);
+ ret = request_irq(irq, mpc8610_sw9_irq, 0, "sw9:wakeup", NULL);
if (ret) {
pr_err("%s: can't request pixis event IRQ: %d\n",
__func__, ret);
@@ -105,45 +105,77 @@ machine_device_initcall(mpc86xx_hpcd, mpc8610_declare_of_platform_devices);
#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
-static u32 get_busfreq(void)
-{
- struct device_node *node;
-
- u32 fs_busfreq = 0;
- node = of_find_node_by_type(NULL, "cpu");
- if (node) {
- unsigned int size;
- const unsigned int *prop =
- of_get_property(node, "bus-frequency", &size);
- if (prop)
- fs_busfreq = *prop;
- of_node_put(node);
- };
- return fs_busfreq;
-}
+/*
+ * DIU Area Descriptor
+ *
+ * The MPC8610 reference manual shows the bits of the AD register in
+ * little-endian order, which causes the BLUE_C field to be split into two
+ * parts. To simplify the definition of the MAKE_AD() macro, we define the
+ * fields in big-endian order and byte-swap the result.
+ *
+ * So even though the registers don't look like they're in the
+ * same bit positions as they are on the P1022, the same value is written to
+ * the AD register on the MPC8610 and on the P1022.
+ */
+#define AD_BYTE_F 0x10000000
+#define AD_ALPHA_C_MASK 0x0E000000
+#define AD_ALPHA_C_SHIFT 25
+#define AD_BLUE_C_MASK 0x01800000
+#define AD_BLUE_C_SHIFT 23
+#define AD_GREEN_C_MASK 0x00600000
+#define AD_GREEN_C_SHIFT 21
+#define AD_RED_C_MASK 0x00180000
+#define AD_RED_C_SHIFT 19
+#define AD_PALETTE 0x00040000
+#define AD_PIXEL_S_MASK 0x00030000
+#define AD_PIXEL_S_SHIFT 16
+#define AD_COMP_3_MASK 0x0000F000
+#define AD_COMP_3_SHIFT 12
+#define AD_COMP_2_MASK 0x00000F00
+#define AD_COMP_2_SHIFT 8
+#define AD_COMP_1_MASK 0x000000F0
+#define AD_COMP_1_SHIFT 4
+#define AD_COMP_0_MASK 0x0000000F
+#define AD_COMP_0_SHIFT 0
+
+#define MAKE_AD(alpha, red, blue, green, size, c0, c1, c2, c3) \
+ cpu_to_le32(AD_BYTE_F | (alpha << AD_ALPHA_C_SHIFT) | \
+ (blue << AD_BLUE_C_SHIFT) | (green << AD_GREEN_C_SHIFT) | \
+ (red << AD_RED_C_SHIFT) | (c3 << AD_COMP_3_SHIFT) | \
+ (c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \
+ (c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT))
unsigned int mpc8610hpcd_get_pixel_format(unsigned int bits_per_pixel,
int monitor_port)
{
static const unsigned long pixelformat[][3] = {
- {0x88882317, 0x88083218, 0x65052119},
- {0x88883316, 0x88082219, 0x65053118},
+ {
+ MAKE_AD(3, 0, 2, 1, 3, 8, 8, 8, 8),
+ MAKE_AD(4, 2, 0, 1, 2, 8, 8, 8, 0),
+ MAKE_AD(4, 0, 2, 1, 1, 5, 6, 5, 0)
+ },
+ {
+ MAKE_AD(3, 2, 0, 1, 3, 8, 8, 8, 8),
+ MAKE_AD(4, 0, 2, 1, 2, 8, 8, 8, 0),
+ MAKE_AD(4, 2, 0, 1, 1, 5, 6, 5, 0)
+ },
};
- unsigned int pix_fmt, arch_monitor;
+ unsigned int arch_monitor;
+ /* The DVI port is mis-wired on revision 1 of this board. */
arch_monitor = ((*pixis_arch == 0x01) && (monitor_port == 0))? 0 : 1;
- /* DVI port for board version 0x01 */
-
- if (bits_per_pixel == 32)
- pix_fmt = pixelformat[arch_monitor][0];
- else if (bits_per_pixel == 24)
- pix_fmt = pixelformat[arch_monitor][1];
- else if (bits_per_pixel == 16)
- pix_fmt = pixelformat[arch_monitor][2];
- else
- pix_fmt = pixelformat[1][0];
-
- return pix_fmt;
+
+ switch (bits_per_pixel) {
+ case 32:
+ return pixelformat[arch_monitor][0];
+ case 24:
+ return pixelformat[arch_monitor][1];
+ case 16:
+ return pixelformat[arch_monitor][2];
+ default:
+ pr_err("fsl-diu: unsupported pixel depth %u\n", bits_per_pixel);
+ return 0;
+ }
}
void mpc8610hpcd_set_gamma_table(int monitor_port, char *gamma_table_base)
@@ -190,8 +222,7 @@ void mpc8610hpcd_set_pixel_clock(unsigned int pixclock)
}
/* Pixel Clock configuration */
- pr_debug("DIU: Bus Frequency = %d\n", get_busfreq());
- speed_ccb = get_busfreq();
+ speed_ccb = fsl_get_sys_freq();
/* Calculate the pixel clock with the smallest error */
/* calculate the following in steps to avoid overflow */
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_smp.c b/arch/powerpc/platforms/86xx/mpc86xx_smp.c
index eacea0e3fcc8..af09baee22cb 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx_smp.c
+++ b/arch/powerpc/platforms/86xx/mpc86xx_smp.c
@@ -56,7 +56,7 @@ smp_86xx_release_core(int nr)
}
-static void __init
+static int __init
smp_86xx_kick_cpu(int nr)
{
unsigned int save_vector;
@@ -65,7 +65,7 @@ smp_86xx_kick_cpu(int nr)
unsigned int *vector = (unsigned int *)(KERNELBASE + 0x100);
if (nr < 0 || nr >= NR_CPUS)
- return;
+ return -ENOENT;
pr_debug("smp_86xx_kick_cpu: kick CPU #%d\n", nr);
@@ -92,6 +92,8 @@ smp_86xx_kick_cpu(int nr)
local_irq_restore(flags);
pr_debug("wait CPU #%d for %d msecs.\n", nr, n);
+
+ return 0;
}
diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c
index 9ecce995dd4b..1e121088826f 100644
--- a/arch/powerpc/platforms/8xx/m8xx_setup.c
+++ b/arch/powerpc/platforms/8xx/m8xx_setup.c
@@ -150,7 +150,7 @@ void __init mpc8xx_calibrate_decr(void)
*/
cpu = of_find_node_by_type(NULL, "cpu");
virq= irq_of_parse_and_map(cpu, 0);
- irq = irq_map[virq].hwirq;
+ irq = virq_to_hw(virq);
sys_tmr2 = immr_map(im_sit);
out_be16(&sys_tmr2->sit_tbscr, ((1 << (7 - (irq/2))) << 8) |
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index f7b07720aa30..f970ca2b180c 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -20,6 +20,7 @@ source "arch/powerpc/platforms/embedded6xx/Kconfig"
source "arch/powerpc/platforms/44x/Kconfig"
source "arch/powerpc/platforms/40x/Kconfig"
source "arch/powerpc/platforms/amigaone/Kconfig"
+source "arch/powerpc/platforms/wsp/Kconfig"
config KVM_GUEST
bool "KVM Guest support"
@@ -56,16 +57,19 @@ config UDBG_RTAS_CONSOLE
depends on PPC_RTAS
default n
+config PPC_SMP_MUXED_IPI
+ bool
+ help
+ Select this opton if your platform supports SMP and your
+ interrupt controller provides less than 4 interrupts to each
+ cpu. This will enable the generic code to multiplex the 4
+ messages on to one ipi.
+
config PPC_UDBG_BEAT
bool "BEAT based debug console"
depends on PPC_CELLEB
default n
-config XICS
- depends on PPC_PSERIES
- bool
- default y
-
config IPIC
bool
default n
@@ -147,14 +151,27 @@ config PPC_970_NAP
bool
default n
+config PPC_P7_NAP
+ bool
+ default n
+
config PPC_INDIRECT_IO
bool
select GENERIC_IOMAP
- default n
+
+config PPC_INDIRECT_PIO
+ bool
+ select PPC_INDIRECT_IO
+
+config PPC_INDIRECT_MMIO
+ bool
+ select PPC_INDIRECT_IO
+
+config PPC_IO_WORKAROUNDS
+ bool
config GENERIC_IOMAP
bool
- default n
source "drivers/cpufreq/Kconfig"
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 111138c55f9c..2165b65876f9 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -73,6 +73,7 @@ config PPC_BOOK3S_64
config PPC_BOOK3E_64
bool "Embedded processors"
select PPC_FPU # Make it a choice ?
+ select PPC_SMP_MUXED_IPI
endchoice
@@ -107,6 +108,10 @@ config POWER4
depends on PPC64 && PPC_BOOK3S
def_bool y
+config PPC_A2
+ bool
+ depends on PPC_BOOK3E_64
+
config TUNE_CELL
bool "Optimize for Cell Broadband Engine"
depends on PPC64 && PPC_BOOK3S
@@ -174,6 +179,7 @@ config FSL_BOOKE
config PPC_FSL_BOOK3E
bool
select FSL_EMB_PERFMON
+ select PPC_SMP_MUXED_IPI
default y if FSL_BOOKE
config PTE_64BIT
@@ -226,6 +232,24 @@ config VSX
If in doubt, say Y here.
+config PPC_ICSWX
+ bool "Support for PowerPC icswx coprocessor instruction"
+ depends on POWER4
+ default n
+ ---help---
+
+ This option enables kernel support for the PowerPC Initiate
+ Coprocessor Store Word (icswx) coprocessor instruction on POWER7
+ or newer processors.
+
+ This option is only useful if you have a processor that supports
+ the icswx coprocessor instruction. It does not have any effect
+ on processors without the icswx coprocessor instruction.
+
+ This option slightly increases kernel memory usage.
+
+ If in doubt, say N here.
+
config SPE
bool "SPE Support"
depends on E200 || (E500 && !PPC_E500MC)
diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile
index fdb9f0b0d7a8..73e2116cfeed 100644
--- a/arch/powerpc/platforms/Makefile
+++ b/arch/powerpc/platforms/Makefile
@@ -22,3 +22,4 @@ obj-$(CONFIG_PPC_CELL) += cell/
obj-$(CONFIG_PPC_PS3) += ps3/
obj-$(CONFIG_EMBEDDED6xx) += embedded6xx/
obj-$(CONFIG_AMIGAONE) += amigaone/
+obj-$(CONFIG_PPC_WSP) += wsp/
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
index 81239ebed83f..67d5009b4e86 100644
--- a/arch/powerpc/platforms/cell/Kconfig
+++ b/arch/powerpc/platforms/cell/Kconfig
@@ -6,7 +6,8 @@ config PPC_CELL_COMMON
bool
select PPC_CELL
select PPC_DCR_MMIO
- select PPC_INDIRECT_IO
+ select PPC_INDIRECT_PIO
+ select PPC_INDIRECT_MMIO
select PPC_NATIVE
select PPC_RTAS
select IRQ_EDGE_EOI_HANDLER
@@ -15,6 +16,7 @@ config PPC_CELL_NATIVE
bool
select PPC_CELL_COMMON
select MPIC
+ select PPC_IO_WORKAROUNDS
select IBM_NEW_EMAC_EMAC4
select IBM_NEW_EMAC_RGMII
select IBM_NEW_EMAC_ZMII #test only
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile
index 83fafe922641..a4a89350bcfc 100644
--- a/arch/powerpc/platforms/cell/Makefile
+++ b/arch/powerpc/platforms/cell/Makefile
@@ -1,7 +1,7 @@
obj-$(CONFIG_PPC_CELL_COMMON) += cbe_regs.o interrupt.o pervasive.o
obj-$(CONFIG_PPC_CELL_NATIVE) += iommu.o setup.o spider-pic.o \
- pmu.o io-workarounds.o spider-pci.o
+ pmu.o spider-pci.o
obj-$(CONFIG_CBE_RAS) += ras.o
obj-$(CONFIG_CBE_THERM) += cbe_thermal.o
@@ -39,11 +39,10 @@ obj-y += celleb_setup.o \
celleb_pci.o celleb_scc_epci.o \
celleb_scc_pciex.o \
celleb_scc_uhc.o \
- io-workarounds.o spider-pci.o \
- beat.o beat_htab.o beat_hvCall.o \
- beat_interrupt.o beat_iommu.o
+ spider-pci.o beat.o beat_htab.o \
+ beat_hvCall.o beat_interrupt.o \
+ beat_iommu.o
-obj-$(CONFIG_SMP) += beat_smp.o
obj-$(CONFIG_PPC_UDBG_BEAT) += beat_udbg.o
obj-$(CONFIG_SERIAL_TXX9) += celleb_scc_sio.o
obj-$(CONFIG_SPU_BASE) += beat_spu_priv1.o
diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
index bb5ebf8fa80b..ac06903e136a 100644
--- a/arch/powerpc/platforms/cell/axon_msi.c
+++ b/arch/powerpc/platforms/cell/axon_msi.c
@@ -113,7 +113,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
pr_devel("axon_msi: woff %x roff %x msi %x\n",
write_offset, msic->read_offset, msi);
- if (msi < NR_IRQS && irq_map[msi].host == msic->irq_host) {
+ if (msi < NR_IRQS && irq_get_chip_data(msi) == msic) {
generic_handle_irq(msi);
msic->fifo_virt[idx] = cpu_to_le32(0xffffffff);
} else {
@@ -320,6 +320,7 @@ static struct irq_chip msic_irq_chip = {
static int msic_host_map(struct irq_host *h, unsigned int virq,
irq_hw_number_t hw)
{
+ irq_set_chip_data(virq, h->host_data);
irq_set_chip_and_handler(virq, &msic_irq_chip, handle_simple_irq);
return 0;
diff --git a/arch/powerpc/platforms/cell/beat_interrupt.c b/arch/powerpc/platforms/cell/beat_interrupt.c
index 4cb9e147c307..55015e1f6939 100644
--- a/arch/powerpc/platforms/cell/beat_interrupt.c
+++ b/arch/powerpc/platforms/cell/beat_interrupt.c
@@ -148,16 +148,6 @@ static int beatic_pic_host_map(struct irq_host *h, unsigned int virq,
}
/*
- * Update binding hardware IRQ number (hw) and Virtuql
- * IRQ number (virq). This is called only once for a given mapping.
- */
-static void beatic_pic_host_remap(struct irq_host *h, unsigned int virq,
- irq_hw_number_t hw)
-{
- beat_construct_and_connect_irq_plug(virq, hw);
-}
-
-/*
* Translate device-tree interrupt spec to irq_hw_number_t style (ulong),
* to pass away to irq_create_mapping().
*
@@ -184,7 +174,6 @@ static int beatic_pic_host_match(struct irq_host *h, struct device_node *np)
static struct irq_host_ops beatic_pic_host_ops = {
.map = beatic_pic_host_map,
- .remap = beatic_pic_host_remap,
.unmap = beatic_pic_host_unmap,
.xlate = beatic_pic_host_xlate,
.match = beatic_pic_host_match,
@@ -257,22 +246,6 @@ void __init beatic_init_IRQ(void)
irq_set_default_host(beatic_host);
}
-#ifdef CONFIG_SMP
-
-/* Nullified to compile with SMP mode */
-void beatic_setup_cpu(int cpu)
-{
-}
-
-void beatic_cause_IPI(int cpu, int mesg)
-{
-}
-
-void beatic_request_IPIs(void)
-{
-}
-#endif /* CONFIG_SMP */
-
void beatic_deinit_IRQ(void)
{
int i;
diff --git a/arch/powerpc/platforms/cell/beat_interrupt.h b/arch/powerpc/platforms/cell/beat_interrupt.h
index b470fd0051f1..a7e52f91a078 100644
--- a/arch/powerpc/platforms/cell/beat_interrupt.h
+++ b/arch/powerpc/platforms/cell/beat_interrupt.h
@@ -24,9 +24,6 @@
extern void beatic_init_IRQ(void);
extern unsigned int beatic_get_irq(void);
-extern void beatic_cause_IPI(int cpu, int mesg);
-extern void beatic_request_IPIs(void);
-extern void beatic_setup_cpu(int);
extern void beatic_deinit_IRQ(void);
#endif
diff --git a/arch/powerpc/platforms/cell/beat_smp.c b/arch/powerpc/platforms/cell/beat_smp.c
deleted file mode 100644
index 26efc204c47f..000000000000
--- a/arch/powerpc/platforms/cell/beat_smp.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * SMP support for Celleb platform. (Incomplete)
- *
- * (C) Copyright 2006 TOSHIBA CORPORATION
- *
- * This code is based on arch/powerpc/platforms/cell/smp.c:
- * Dave Engebretsen, Peter Bergner, and
- * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com
- * Plus various changes from other IBM teams...
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#undef DEBUG
-
-#include <linux/kernel.h>
-#include <linux/smp.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/threads.h>
-#include <linux/cpu.h>
-
-#include <asm/irq.h>
-#include <asm/smp.h>
-#include <asm/machdep.h>
-#include <asm/udbg.h>
-
-#include "beat_interrupt.h"
-
-#ifdef DEBUG
-#define DBG(fmt...) udbg_printf(fmt)
-#else
-#define DBG(fmt...)
-#endif
-
-/*
- * The primary thread of each non-boot processor is recorded here before
- * smp init.
- */
-/* static cpumask_t of_spin_map; */
-
-/**
- * smp_startup_cpu() - start the given cpu
- *
- * At boot time, there is nothing to do for primary threads which were
- * started from Open Firmware. For anything else, call RTAS with the
- * appropriate start location.
- *
- * Returns:
- * 0 - failure
- * 1 - success
- */
-static inline int __devinit smp_startup_cpu(unsigned int lcpu)
-{
- return 0;
-}
-
-static void smp_beatic_message_pass(int target, int msg)
-{
- unsigned int i;
-
- if (target < NR_CPUS) {
- beatic_cause_IPI(target, msg);
- } else {
- for_each_online_cpu(i) {
- if (target == MSG_ALL_BUT_SELF
- && i == smp_processor_id())
- continue;
- beatic_cause_IPI(i, msg);
- }
- }
-}
-
-static int __init smp_beatic_probe(void)
-{
- return cpus_weight(cpu_possible_map);
-}
-
-static void __devinit smp_beatic_setup_cpu(int cpu)
-{
- beatic_setup_cpu(cpu);
-}
-
-static void __devinit smp_celleb_kick_cpu(int nr)
-{
- BUG_ON(nr < 0 || nr >= NR_CPUS);
-
- if (!smp_startup_cpu(nr))
- return;
-}
-
-static int smp_celleb_cpu_bootable(unsigned int nr)
-{
- return 1;
-}
-static struct smp_ops_t bpa_beatic_smp_ops = {
- .message_pass = smp_beatic_message_pass,
- .probe = smp_beatic_probe,
- .kick_cpu = smp_celleb_kick_cpu,
- .setup_cpu = smp_beatic_setup_cpu,
- .cpu_bootable = smp_celleb_cpu_bootable,
-};
-
-/* This is called very early */
-void __init smp_init_celleb(void)
-{
- DBG(" -> smp_init_celleb()\n");
-
- smp_ops = &bpa_beatic_smp_ops;
-
- DBG(" <- smp_init_celleb()\n");
-}
diff --git a/arch/powerpc/platforms/cell/cbe_regs.c b/arch/powerpc/platforms/cell/cbe_regs.c
index dbc338f187a2..f3917e7a5b44 100644
--- a/arch/powerpc/platforms/cell/cbe_regs.c
+++ b/arch/powerpc/platforms/cell/cbe_regs.c
@@ -45,8 +45,8 @@ static struct cbe_thread_map
unsigned int cbe_id;
} cbe_thread_map[NR_CPUS];
-static cpumask_t cbe_local_mask[MAX_CBE] = { [0 ... MAX_CBE-1] = CPU_MASK_NONE };
-static cpumask_t cbe_first_online_cpu = CPU_MASK_NONE;
+static cpumask_t cbe_local_mask[MAX_CBE] = { [0 ... MAX_CBE-1] = {CPU_BITS_NONE} };
+static cpumask_t cbe_first_online_cpu = { CPU_BITS_NONE };
static struct cbe_regs_map *cbe_find_map(struct device_node *np)
{
@@ -159,7 +159,8 @@ EXPORT_SYMBOL_GPL(cbe_cpu_to_node);
u32 cbe_node_to_cpu(int node)
{
- return find_first_bit( (unsigned long *) &cbe_local_mask[node], sizeof(cpumask_t));
+ return cpumask_first(&cbe_local_mask[node]);
+
}
EXPORT_SYMBOL_GPL(cbe_node_to_cpu);
@@ -268,9 +269,9 @@ void __init cbe_regs_init(void)
thread->regs = map;
thread->cbe_id = cbe_id;
map->be_node = thread->be_node;
- cpu_set(i, cbe_local_mask[cbe_id]);
+ cpumask_set_cpu(i, &cbe_local_mask[cbe_id]);
if(thread->thread_id == 0)
- cpu_set(i, cbe_first_online_cpu);
+ cpumask_set_cpu(i, &cbe_first_online_cpu);
}
}
diff --git a/arch/powerpc/platforms/cell/celleb_pci.c b/arch/powerpc/platforms/cell/celleb_pci.c
index 404d1fc04d59..5822141aa63f 100644
--- a/arch/powerpc/platforms/cell/celleb_pci.c
+++ b/arch/powerpc/platforms/cell/celleb_pci.c
@@ -41,7 +41,6 @@
#include <asm/pci-bridge.h>
#include <asm/ppc-pci.h>
-#include "io-workarounds.h"
#include "celleb_pci.h"
#define MAX_PCI_DEVICES 32
@@ -320,7 +319,7 @@ static int __init celleb_setup_fake_pci_device(struct device_node *node,
size = 256;
config = &private->fake_config[devno][fn];
- *config = alloc_maybe_bootmem(size, GFP_KERNEL);
+ *config = zalloc_maybe_bootmem(size, GFP_KERNEL);
if (*config == NULL) {
printk(KERN_ERR "PCI: "
"not enough memory for fake configuration space\n");
@@ -331,7 +330,7 @@ static int __init celleb_setup_fake_pci_device(struct device_node *node,
size = sizeof(struct celleb_pci_resource);
res = &private->res[devno][fn];
- *res = alloc_maybe_bootmem(size, GFP_KERNEL);
+ *res = zalloc_maybe_bootmem(size, GFP_KERNEL);
if (*res == NULL) {
printk(KERN_ERR
"PCI: not enough memory for resource data space\n");
@@ -432,7 +431,7 @@ static int __init phb_set_bus_ranges(struct device_node *dev,
static void __init celleb_alloc_private_mem(struct pci_controller *hose)
{
hose->private_data =
- alloc_maybe_bootmem(sizeof(struct celleb_pci_private),
+ zalloc_maybe_bootmem(sizeof(struct celleb_pci_private),
GFP_KERNEL);
}
@@ -469,18 +468,6 @@ static struct of_device_id celleb_phb_match[] __initdata = {
},
};
-static int __init celleb_io_workaround_init(struct pci_controller *phb,
- struct celleb_phb_spec *phb_spec)
-{
- if (phb_spec->ops) {
- iowa_register_bus(phb, phb_spec->ops, phb_spec->iowa_init,
- phb_spec->iowa_data);
- io_workaround_init();
- }
-
- return 0;
-}
-
int __init celleb_setup_phb(struct pci_controller *phb)
{
struct device_node *dev = phb->dn;
@@ -500,7 +487,11 @@ int __init celleb_setup_phb(struct pci_controller *phb)
if (rc)
return 1;
- return celleb_io_workaround_init(phb, phb_spec);
+ if (phb_spec->ops)
+ iowa_register_bus(phb, phb_spec->ops,
+ phb_spec->iowa_init,
+ phb_spec->iowa_data);
+ return 0;
}
int celleb_pci_probe_mode(struct pci_bus *bus)
diff --git a/arch/powerpc/platforms/cell/celleb_pci.h b/arch/powerpc/platforms/cell/celleb_pci.h
index 4cba1523ec50..a801fcc5f389 100644
--- a/arch/powerpc/platforms/cell/celleb_pci.h
+++ b/arch/powerpc/platforms/cell/celleb_pci.h
@@ -26,8 +26,9 @@
#include <asm/pci-bridge.h>
#include <asm/prom.h>
#include <asm/ppc-pci.h>
+#include <asm/io-workarounds.h>
-#include "io-workarounds.h"
+struct iowa_bus;
struct celleb_phb_spec {
int (*setup)(struct device_node *, struct pci_controller *);
diff --git a/arch/powerpc/platforms/cell/celleb_setup.c b/arch/powerpc/platforms/cell/celleb_setup.c
index e53845579770..d58d9bae4b9b 100644
--- a/arch/powerpc/platforms/cell/celleb_setup.c
+++ b/arch/powerpc/platforms/cell/celleb_setup.c
@@ -128,10 +128,6 @@ static void __init celleb_setup_arch_beat(void)
spu_management_ops = &spu_management_of_ops;
#endif
-#ifdef CONFIG_SMP
- smp_init_celleb();
-#endif
-
celleb_setup_arch_common();
}
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
index 44cfd1bef89b..3e4eba603e6b 100644
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -176,14 +176,14 @@ EXPORT_SYMBOL_GPL(iic_get_target_id);
#ifdef CONFIG_SMP
/* Use the highest interrupt priorities for IPI */
-static inline int iic_ipi_to_irq(int ipi)
+static inline int iic_msg_to_irq(int msg)
{
- return IIC_IRQ_TYPE_IPI + 0xf - ipi;
+ return IIC_IRQ_TYPE_IPI + 0xf - msg;
}
-void iic_cause_IPI(int cpu, int mesg)
+void iic_message_pass(int cpu, int msg)
{
- out_be64(&per_cpu(cpu_iic, cpu).regs->generate, (0xf - mesg) << 4);
+ out_be64(&per_cpu(cpu_iic, cpu).regs->generate, (0xf - msg) << 4);
}
struct irq_host *iic_get_irq_host(int node)
@@ -192,38 +192,31 @@ struct irq_host *iic_get_irq_host(int node)
}
EXPORT_SYMBOL_GPL(iic_get_irq_host);
-static irqreturn_t iic_ipi_action(int irq, void *dev_id)
-{
- int ipi = (int)(long)dev_id;
-
- smp_message_recv(ipi);
-
- return IRQ_HANDLED;
-}
-static void iic_request_ipi(int ipi, const char *name)
+static void iic_request_ipi(int msg)
{
int virq;
- virq = irq_create_mapping(iic_host, iic_ipi_to_irq(ipi));
+ virq = irq_create_mapping(iic_host, iic_msg_to_irq(msg));
if (virq == NO_IRQ) {
printk(KERN_ERR
- "iic: failed to map IPI %s\n", name);
+ "iic: failed to map IPI %s\n", smp_ipi_name[msg]);
return;
}
- if (request_irq(virq, iic_ipi_action, IRQF_DISABLED, name,
- (void *)(long)ipi))
- printk(KERN_ERR
- "iic: failed to request IPI %s\n", name);
+
+ /*
+ * If smp_request_message_ipi encounters an error it will notify
+ * the error. If a message is not needed it will return non-zero.
+ */
+ if (smp_request_message_ipi(virq, msg))
+ irq_dispose_mapping(virq);
}
void iic_request_IPIs(void)
{
- iic_request_ipi(PPC_MSG_CALL_FUNCTION, "IPI-call");
- iic_request_ipi(PPC_MSG_RESCHEDULE, "IPI-resched");
- iic_request_ipi(PPC_MSG_CALL_FUNC_SINGLE, "IPI-call-single");
-#ifdef CONFIG_DEBUGGER
- iic_request_ipi(PPC_MSG_DEBUGGER_BREAK, "IPI-debug");
-#endif /* CONFIG_DEBUGGER */
+ iic_request_ipi(PPC_MSG_CALL_FUNCTION);
+ iic_request_ipi(PPC_MSG_RESCHEDULE);
+ iic_request_ipi(PPC_MSG_CALL_FUNC_SINGLE);
+ iic_request_ipi(PPC_MSG_DEBUGGER_BREAK);
}
#endif /* CONFIG_SMP */
diff --git a/arch/powerpc/platforms/cell/interrupt.h b/arch/powerpc/platforms/cell/interrupt.h
index 942dc39d6045..4f60ae6ca358 100644
--- a/arch/powerpc/platforms/cell/interrupt.h
+++ b/arch/powerpc/platforms/cell/interrupt.h
@@ -75,7 +75,7 @@ enum {
};
extern void iic_init_IRQ(void);
-extern void iic_cause_IPI(int cpu, int mesg);
+extern void iic_message_pass(int cpu, int msg);
extern void iic_request_IPIs(void);
extern void iic_setup_cpu(void);
diff --git a/arch/powerpc/platforms/cell/qpace_setup.c b/arch/powerpc/platforms/cell/qpace_setup.c
index d31c594cfdf3..51e290126bc1 100644
--- a/arch/powerpc/platforms/cell/qpace_setup.c
+++ b/arch/powerpc/platforms/cell/qpace_setup.c
@@ -42,7 +42,6 @@
#include "interrupt.h"
#include "pervasive.h"
#include "ras.h"
-#include "io-workarounds.h"
static void qpace_show_cpuinfo(struct seq_file *m)
{
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
index fd57bfe00edf..c73cf4c43fc2 100644
--- a/arch/powerpc/platforms/cell/setup.c
+++ b/arch/powerpc/platforms/cell/setup.c
@@ -51,11 +51,11 @@
#include <asm/udbg.h>
#include <asm/mpic.h>
#include <asm/cell-regs.h>
+#include <asm/io-workarounds.h>
#include "interrupt.h"
#include "pervasive.h"
#include "ras.h"
-#include "io-workarounds.h"
#ifdef DEBUG
#define DBG(fmt...) udbg_printf(fmt)
@@ -136,8 +136,6 @@ static int __devinit cell_setup_phb(struct pci_controller *phb)
iowa_register_bus(phb, &spiderpci_ops, &spiderpci_iowa_init,
(void *)SPIDER_PCI_REG_BASE);
- io_workaround_init();
-
return 0;
}
diff --git a/arch/powerpc/platforms/cell/smp.c b/arch/powerpc/platforms/cell/smp.c
index f774530075b7..dbb641ea90dd 100644
--- a/arch/powerpc/platforms/cell/smp.c
+++ b/arch/powerpc/platforms/cell/smp.c
@@ -77,7 +77,7 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu)
unsigned int pcpu;
int start_cpu;
- if (cpu_isset(lcpu, of_spin_map))
+ if (cpumask_test_cpu(lcpu, &of_spin_map))
/* Already started by OF and sitting in spin loop */
return 1;
@@ -103,27 +103,11 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu)
return 1;
}
-static void smp_iic_message_pass(int target, int msg)
-{
- unsigned int i;
-
- if (target < NR_CPUS) {
- iic_cause_IPI(target, msg);
- } else {
- for_each_online_cpu(i) {
- if (target == MSG_ALL_BUT_SELF
- && i == smp_processor_id())
- continue;
- iic_cause_IPI(i, msg);
- }
- }
-}
-
static int __init smp_iic_probe(void)
{
iic_request_IPIs();
- return cpus_weight(cpu_possible_map);
+ return cpumask_weight(cpu_possible_mask);
}
static void __devinit smp_cell_setup_cpu(int cpu)
@@ -137,12 +121,12 @@ static void __devinit smp_cell_setup_cpu(int cpu)
mtspr(SPRN_DABRX, DABRX_KERNEL | DABRX_USER);
}
-static void __devinit smp_cell_kick_cpu(int nr)
+static int __devinit smp_cell_kick_cpu(int nr)
{
BUG_ON(nr < 0 || nr >= NR_CPUS);
if (!smp_startup_cpu(nr))
- return;
+ return -ENOENT;
/*
* The processor is currently spinning, waiting for the
@@ -150,6 +134,8 @@ static void __devinit smp_cell_kick_cpu(int nr)
* the processor will continue on to secondary_start
*/
paca[nr].cpu_start = 1;
+
+ return 0;
}
static int smp_cell_cpu_bootable(unsigned int nr)
@@ -166,7 +152,7 @@ static int smp_cell_cpu_bootable(unsigned int nr)
return 1;
}
static struct smp_ops_t bpa_iic_smp_ops = {
- .message_pass = smp_iic_message_pass,
+ .message_pass = iic_message_pass,
.probe = smp_iic_probe,
.kick_cpu = smp_cell_kick_cpu,
.setup_cpu = smp_cell_setup_cpu,
@@ -186,13 +172,12 @@ void __init smp_init_cell(void)
if (cpu_has_feature(CPU_FTR_SMT)) {
for_each_present_cpu(i) {
if (cpu_thread_in_core(i) == 0)
- cpu_set(i, of_spin_map);
+ cpumask_set_cpu(i, &of_spin_map);
}
- } else {
- of_spin_map = cpu_present_map;
- }
+ } else
+ cpumask_copy(&of_spin_map, cpu_present_mask);
- cpu_clear(boot_cpuid, of_spin_map);
+ cpumask_clear_cpu(boot_cpuid, &of_spin_map);
/* Non-lpar has additional take/give timebase */
if (rtas_token("freeze-time-base") != RTAS_UNKNOWN_SERVICE) {
diff --git a/arch/powerpc/platforms/cell/spider-pci.c b/arch/powerpc/platforms/cell/spider-pci.c
index ca7731c0b595..f1f7878893f3 100644
--- a/arch/powerpc/platforms/cell/spider-pci.c
+++ b/arch/powerpc/platforms/cell/spider-pci.c
@@ -27,8 +27,7 @@
#include <asm/ppc-pci.h>
#include <asm/pci-bridge.h>
-
-#include "io-workarounds.h"
+#include <asm/io-workarounds.h>
#define SPIDER_PCI_DISABLE_PREFETCH
diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c
index c5cf50e6b45a..442c28c00f88 100644
--- a/arch/powerpc/platforms/cell/spider-pic.c
+++ b/arch/powerpc/platforms/cell/spider-pic.c
@@ -68,9 +68,9 @@ struct spider_pic {
};
static struct spider_pic spider_pics[SPIDER_CHIP_COUNT];
-static struct spider_pic *spider_virq_to_pic(unsigned int virq)
+static struct spider_pic *spider_irq_data_to_pic(struct irq_data *d)
{
- return irq_map[virq].host->host_data;
+ return irq_data_get_irq_chip_data(d);
}
static void __iomem *spider_get_irq_config(struct spider_pic *pic,
@@ -81,24 +81,24 @@ static void __iomem *spider_get_irq_config(struct spider_pic *pic,
static void spider_unmask_irq(struct irq_data *d)
{
- struct spider_pic *pic = spider_virq_to_pic(d->irq);
- void __iomem *cfg = spider_get_irq_config(pic, irq_map[d->irq].hwirq);
+ struct spider_pic *pic = spider_irq_data_to_pic(d);
+ void __iomem *cfg = spider_get_irq_config(pic, irqd_to_hwirq(d));
out_be32(cfg, in_be32(cfg) | 0x30000000u);
}
static void spider_mask_irq(struct irq_data *d)
{
- struct spider_pic *pic = spider_virq_to_pic(d->irq);
- void __iomem *cfg = spider_get_irq_config(pic, irq_map[d->irq].hwirq);
+ struct spider_pic *pic = spider_irq_data_to_pic(d);
+ void __iomem *cfg = spider_get_irq_config(pic, irqd_to_hwirq(d));
out_be32(cfg, in_be32(cfg) & ~0x30000000u);
}
static void spider_ack_irq(struct irq_data *d)
{
- struct spider_pic *pic = spider_virq_to_pic(d->irq);
- unsigned int src = irq_map[d->irq].hwirq;
+ struct spider_pic *pic = spider_irq_data_to_pic(d);
+ unsigned int src = irqd_to_hwirq(d);
/* Reset edge detection logic if necessary
*/
@@ -116,8 +116,8 @@ static void spider_ack_irq(struct irq_data *d)
static int spider_set_irq_type(struct irq_data *d, unsigned int type)
{
unsigned int sense = type & IRQ_TYPE_SENSE_MASK;
- struct spider_pic *pic = spider_virq_to_pic(d->irq);
- unsigned int hw = irq_map[d->irq].hwirq;
+ struct spider_pic *pic = spider_irq_data_to_pic(d);
+ unsigned int hw = irqd_to_hwirq(d);
void __iomem *cfg = spider_get_irq_config(pic, hw);
u32 old_mask;
u32 ic;
@@ -171,6 +171,7 @@ static struct irq_chip spider_pic = {
static int spider_host_map(struct irq_host *h, unsigned int virq,
irq_hw_number_t hw)
{
+ irq_set_chip_data(virq, h->host_data);
irq_set_chip_and_handler(virq, &spider_pic, handle_level_irq);
/* Set default irq type */
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index acfaccea5f4f..3675da73623f 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -32,6 +32,7 @@
#include <linux/io.h>
#include <linux/mutex.h>
#include <linux/linux_logo.h>
+#include <linux/syscore_ops.h>
#include <asm/spu.h>
#include <asm/spu_priv1.h>
#include <asm/spu_csa.h>
@@ -521,18 +522,8 @@ void spu_init_channels(struct spu *spu)
}
EXPORT_SYMBOL_GPL(spu_init_channels);
-static int spu_shutdown(struct sys_device *sysdev)
-{
- struct spu *spu = container_of(sysdev, struct spu, sysdev);
-
- spu_free_irqs(spu);
- spu_destroy_spu(spu);
- return 0;
-}
-
static struct sysdev_class spu_sysdev_class = {
.name = "spu",
- .shutdown = spu_shutdown,
};
int spu_add_sysdev_attr(struct sysdev_attribute *attr)
@@ -797,6 +788,22 @@ static inline void crash_register_spus(struct list_head *list)
}
#endif
+static void spu_shutdown(void)
+{
+ struct spu *spu;
+
+ mutex_lock(&spu_full_list_mutex);
+ list_for_each_entry(spu, &spu_full_list, full_list) {
+ spu_free_irqs(spu);
+ spu_destroy_spu(spu);
+ }
+ mutex_unlock(&spu_full_list_mutex);
+}
+
+static struct syscore_ops spu_syscore_ops = {
+ .shutdown = spu_shutdown,
+};
+
static int __init init_spu_base(void)
{
int i, ret = 0;
@@ -830,6 +837,7 @@ static int __init init_spu_base(void)
crash_register_spus(&spu_full_list);
mutex_unlock(&spu_full_list_mutex);
spu_add_sysdev_attr(&attr_stat);
+ register_syscore_ops(&spu_syscore_ops);
spu_init_affinity();
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index 65203857b0ce..32cb4e66d2cd 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -141,7 +141,7 @@ void __spu_update_sched_info(struct spu_context *ctx)
* runqueue. The context will be rescheduled on the proper node
* if it is timesliced or preempted.
*/
- ctx->cpus_allowed = current->cpus_allowed;
+ cpumask_copy(&ctx->cpus_allowed, tsk_cpus_allowed(current));
/* Save the current cpu id for spu interrupt routing. */
ctx->last_ran = raw_smp_processor_id();
diff --git a/arch/powerpc/platforms/chrp/smp.c b/arch/powerpc/platforms/chrp/smp.c
index 02cafecc90e3..a800122e4dda 100644
--- a/arch/powerpc/platforms/chrp/smp.c
+++ b/arch/powerpc/platforms/chrp/smp.c
@@ -30,10 +30,12 @@
#include <asm/mpic.h>
#include <asm/rtas.h>
-static void __devinit smp_chrp_kick_cpu(int nr)
+static int __devinit smp_chrp_kick_cpu(int nr)
{
*(unsigned long *)KERNELBASE = nr;
asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
+
+ return 0;
}
static void __devinit smp_chrp_setup_cpu(int cpu_nr)
diff --git a/arch/powerpc/platforms/embedded6xx/flipper-pic.c b/arch/powerpc/platforms/embedded6xx/flipper-pic.c
index 12aa62b6f227..f61a2dd96b99 100644
--- a/arch/powerpc/platforms/embedded6xx/flipper-pic.c
+++ b/arch/powerpc/platforms/embedded6xx/flipper-pic.c
@@ -48,7 +48,7 @@
static void flipper_pic_mask_and_ack(struct irq_data *d)
{
- int irq = virq_to_hw(d->irq);
+ int irq = irqd_to_hwirq(d);
void __iomem *io_base = irq_data_get_irq_chip_data(d);
u32 mask = 1 << irq;
@@ -59,7 +59,7 @@ static void flipper_pic_mask_and_ack(struct irq_data *d)
static void flipper_pic_ack(struct irq_data *d)
{
- int irq = virq_to_hw(d->irq);
+ int irq = irqd_to_hwirq(d);
void __iomem *io_base = irq_data_get_irq_chip_data(d);
/* this is at least needed for RSW */
@@ -68,7 +68,7 @@ static void flipper_pic_ack(struct irq_data *d)
static void flipper_pic_mask(struct irq_data *d)
{
- int irq = virq_to_hw(d->irq);
+ int irq = irqd_to_hwirq(d);
void __iomem *io_base = irq_data_get_irq_chip_data(d);
clrbits32(io_base + FLIPPER_IMR, 1 << irq);
@@ -76,7 +76,7 @@ static void flipper_pic_mask(struct irq_data *d)
static void flipper_pic_unmask(struct irq_data *d)
{
- int irq = virq_to_hw(d->irq);
+ int irq = irqd_to_hwirq(d);
void __iomem *io_base = irq_data_get_irq_chip_data(d);
setbits32(io_base + FLIPPER_IMR, 1 << irq);
@@ -107,12 +107,6 @@ static int flipper_pic_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static void flipper_pic_unmap(struct irq_host *h, unsigned int irq)
-{
- irq_set_chip_data(irq, NULL);
- irq_set_chip(irq, NULL);
-}
-
static int flipper_pic_match(struct irq_host *h, struct device_node *np)
{
return 1;
@@ -121,7 +115,6 @@ static int flipper_pic_match(struct irq_host *h, struct device_node *np)
static struct irq_host_ops flipper_irq_host_ops = {
.map = flipper_pic_map,
- .unmap = flipper_pic_unmap,
.match = flipper_pic_match,
};
diff --git a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
index 2bdddfc9d520..e4919170c6bc 100644
--- a/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
+++ b/arch/powerpc/platforms/embedded6xx/hlwd-pic.c
@@ -43,7 +43,7 @@
static void hlwd_pic_mask_and_ack(struct irq_data *d)
{
- int irq = virq_to_hw(d->irq);
+ int irq = irqd_to_hwirq(d);
void __iomem *io_base = irq_data_get_irq_chip_data(d);
u32 mask = 1 << irq;
@@ -53,7 +53,7 @@ static void hlwd_pic_mask_and_ack(struct irq_data *d)
static void hlwd_pic_ack(struct irq_data *d)
{
- int irq = virq_to_hw(d->irq);
+ int irq = irqd_to_hwirq(d);
void __iomem *io_base = irq_data_get_irq_chip_data(d);
out_be32(io_base + HW_BROADWAY_ICR, 1 << irq);
@@ -61,7 +61,7 @@ static void hlwd_pic_ack(struct irq_data *d)
static void hlwd_pic_mask(struct irq_data *d)
{
- int irq = virq_to_hw(d->irq);
+ int irq = irqd_to_hwirq(d);
void __iomem *io_base = irq_data_get_irq_chip_data(d);
clrbits32(io_base + HW_BROADWAY_IMR, 1 << irq);
@@ -69,7 +69,7 @@ static void hlwd_pic_mask(struct irq_data *d)
static void hlwd_pic_unmask(struct irq_data *d)
{
- int irq = virq_to_hw(d->irq);
+ int irq = irqd_to_hwirq(d);
void __iomem *io_base = irq_data_get_irq_chip_data(d);
setbits32(io_base + HW_BROADWAY_IMR, 1 << irq);
@@ -100,15 +100,8 @@ static int hlwd_pic_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static void hlwd_pic_unmap(struct irq_host *h, unsigned int irq)
-{
- irq_set_chip_data(irq, NULL);
- irq_set_chip(irq, NULL);
-}
-
static struct irq_host_ops hlwd_irq_host_ops = {
.map = hlwd_pic_map,
- .unmap = hlwd_pic_unmap,
};
static unsigned int __hlwd_pic_get_irq(struct irq_host *h)
diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig
index e5bc9f75d474..b57cda3a0817 100644
--- a/arch/powerpc/platforms/iseries/Kconfig
+++ b/arch/powerpc/platforms/iseries/Kconfig
@@ -1,7 +1,9 @@
config PPC_ISERIES
bool "IBM Legacy iSeries"
depends on PPC64 && PPC_BOOK3S
- select PPC_INDIRECT_IO
+ select PPC_SMP_MUXED_IPI
+ select PPC_INDIRECT_PIO
+ select PPC_INDIRECT_MMIO
select PPC_PCI_CHOICE if EXPERT
menu "iSeries device drivers"
diff --git a/arch/powerpc/platforms/iseries/exception.S b/arch/powerpc/platforms/iseries/exception.S
index 32a56c6dfa72..29c02f36b32f 100644
--- a/arch/powerpc/platforms/iseries/exception.S
+++ b/arch/powerpc/platforms/iseries/exception.S
@@ -31,6 +31,7 @@
#include <asm/thread_info.h>
#include <asm/ptrace.h>
#include <asm/cputable.h>
+#include <asm/mmu.h>
#include "exception.h"
@@ -60,29 +61,31 @@ system_reset_iSeries:
/* Spin on __secondary_hold_spinloop until it is updated by the boot cpu. */
/* In the UP case we'll yield() later, and we will not access the paca anyway */
#ifdef CONFIG_SMP
-1:
+iSeries_secondary_wait_paca:
HMT_LOW
LOAD_REG_ADDR(r23, __secondary_hold_spinloop)
ld r23,0(r23)
- sync
- LOAD_REG_ADDR(r3,current_set)
- sldi r28,r24,3 /* get current_set[cpu#] */
- ldx r3,r3,r28
- addi r1,r3,THREAD_SIZE
- subi r1,r1,STACK_FRAME_OVERHEAD
- cmpwi 0,r23,0 /* Keep poking the Hypervisor until */
- bne 2f /* we're released */
- /* Let the Hypervisor know we are alive */
+ cmpdi 0,r23,0
+ bne 2f /* go on when the master is ready */
+
+ /* Keep poking the Hypervisor until we're released */
/* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */
lis r3,0x8002
rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */
li r0,-1 /* r0=-1 indicates a Hypervisor call */
sc /* Invoke the hypervisor via a system call */
- b 1b
-#endif
+ b iSeries_secondary_wait_paca
2:
+ HMT_MEDIUM
+ sync
+
+ LOAD_REG_ADDR(r3, nr_cpu_ids) /* get number of pacas allocated */
+ lwz r3,0(r3) /* nr_cpus= or NR_CPUS can limit */
+ cmpld 0,r24,r3 /* is our cpu number allocated? */
+ bge iSeries_secondary_yield /* no, yield forever */
+
/* Load our paca now that it's been allocated */
LOAD_REG_ADDR(r13, paca)
ld r13,0(r13)
@@ -93,10 +96,24 @@ system_reset_iSeries:
ori r23,r23,MSR_RI
mtmsrd r23 /* RI on */
- HMT_LOW
-#ifdef CONFIG_SMP
+iSeries_secondary_smp_loop:
lbz r23,PACAPROCSTART(r13) /* Test if this processor
* should start */
+ cmpwi 0,r23,0
+ bne 3f /* go on when we are told */
+
+ HMT_LOW
+ /* Let the Hypervisor know we are alive */
+ /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */
+ lis r3,0x8002
+ rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */
+ li r0,-1 /* r0=-1 indicates a Hypervisor call */
+ sc /* Invoke the hypervisor via a system call */
+ mfspr r13,SPRN_SPRG_PACA /* Put r13 back ???? */
+ b iSeries_secondary_smp_loop /* wait for signal to start */
+
+3:
+ HMT_MEDIUM
sync
LOAD_REG_ADDR(r3,current_set)
sldi r28,r24,3 /* get current_set[cpu#] */
@@ -104,27 +121,22 @@ system_reset_iSeries:
addi r1,r3,THREAD_SIZE
subi r1,r1,STACK_FRAME_OVERHEAD
- cmpwi 0,r23,0
- beq iSeries_secondary_smp_loop /* Loop until told to go */
b __secondary_start /* Loop until told to go */
-iSeries_secondary_smp_loop:
- /* Let the Hypervisor know we are alive */
- /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */
- lis r3,0x8002
- rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */
-#else /* CONFIG_SMP */
+#endif /* CONFIG_SMP */
+
+iSeries_secondary_yield:
/* Yield the processor. This is required for non-SMP kernels
which are running on multi-threaded machines. */
+ HMT_LOW
lis r3,0x8000
rldicr r3,r3,32,15 /* r3 = (r3 << 32) & 0xffff000000000000 */
addi r3,r3,18 /* r3 = 0x8000000000000012 which is "yield" */
li r4,0 /* "yield timed" */
li r5,-1 /* "yield forever" */
-#endif /* CONFIG_SMP */
li r0,-1 /* r0=-1 indicates a Hypervisor call */
sc /* Invoke the hypervisor via a system call */
mfspr r13,SPRN_SPRG_PACA /* Put r13 back ???? */
- b 2b /* If SMP not configured, secondaries
+ b iSeries_secondary_yield /* If SMP not configured, secondaries
* loop forever */
/*** ISeries-LPAR interrupt handlers ***/
@@ -157,7 +169,7 @@ BEGIN_FTR_SECTION
FTR_SECTION_ELSE
EXCEPTION_PROLOG_1(PACA_EXGEN)
EXCEPTION_PROLOG_ISERIES_1
-ALT_FTR_SECTION_END_IFCLR(CPU_FTR_SLB)
+ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_SLB)
b data_access_common
.do_stab_bolted_iSeries:
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c
index 52a6889832c7..b2103453eb01 100644
--- a/arch/powerpc/platforms/iseries/irq.c
+++ b/arch/powerpc/platforms/iseries/irq.c
@@ -42,7 +42,6 @@
#include "irq.h"
#include "pci.h"
#include "call_pci.h"
-#include "smp.h"
#ifdef CONFIG_PCI
@@ -171,7 +170,7 @@ static void iseries_enable_IRQ(struct irq_data *d)
{
u32 bus, dev_id, function, mask;
const u32 sub_bus = 0;
- unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq;
+ unsigned int rirq = (unsigned int)irqd_to_hwirq(d);
/* The IRQ has already been locked by the caller */
bus = REAL_IRQ_TO_BUS(rirq);
@@ -188,7 +187,7 @@ static unsigned int iseries_startup_IRQ(struct irq_data *d)
{
u32 bus, dev_id, function, mask;
const u32 sub_bus = 0;
- unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq;
+ unsigned int rirq = (unsigned int)irqd_to_hwirq(d);
bus = REAL_IRQ_TO_BUS(rirq);
function = REAL_IRQ_TO_FUNC(rirq);
@@ -234,7 +233,7 @@ static void iseries_shutdown_IRQ(struct irq_data *d)
{
u32 bus, dev_id, function, mask;
const u32 sub_bus = 0;
- unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq;
+ unsigned int rirq = (unsigned int)irqd_to_hwirq(d);
/* irq should be locked by the caller */
bus = REAL_IRQ_TO_BUS(rirq);
@@ -257,7 +256,7 @@ static void iseries_disable_IRQ(struct irq_data *d)
{
u32 bus, dev_id, function, mask;
const u32 sub_bus = 0;
- unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq;
+ unsigned int rirq = (unsigned int)irqd_to_hwirq(d);
/* The IRQ has already been locked by the caller */
bus = REAL_IRQ_TO_BUS(rirq);
@@ -271,7 +270,7 @@ static void iseries_disable_IRQ(struct irq_data *d)
static void iseries_end_IRQ(struct irq_data *d)
{
- unsigned int rirq = (unsigned int)irq_map[d->irq].hwirq;
+ unsigned int rirq = (unsigned int)irqd_to_hwirq(d);
HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq),
(REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq));
@@ -316,7 +315,7 @@ unsigned int iSeries_get_irq(void)
#ifdef CONFIG_SMP
if (get_lppaca()->int_dword.fields.ipi_cnt) {
get_lppaca()->int_dword.fields.ipi_cnt = 0;
- iSeries_smp_message_recv();
+ smp_ipi_demux();
}
#endif /* CONFIG_SMP */
if (hvlpevent_is_pending())
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index 2946ae10fbfd..c25a0815c26b 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -249,7 +249,7 @@ static unsigned long iSeries_process_mainstore_vpd(struct MemoryBlock *mb_array,
unsigned long i;
unsigned long mem_blocks = 0;
- if (cpu_has_feature(CPU_FTR_SLB))
+ if (mmu_has_feature(MMU_FTR_SLB))
mem_blocks = iSeries_process_Regatta_mainstore_vpd(mb_array,
max_entries);
else
@@ -634,7 +634,7 @@ static int __init iseries_probe(void)
hpte_init_iSeries();
/* iSeries does not support 16M pages */
- cur_cpu_spec->cpu_features &= ~CPU_FTR_16M_PAGE;
+ cur_cpu_spec->mmu_features &= ~MMU_FTR_16M_PAGE;
return 1;
}
@@ -685,6 +685,11 @@ void * __init iSeries_early_setup(void)
powerpc_firmware_features |= FW_FEATURE_ISERIES;
powerpc_firmware_features |= FW_FEATURE_LPAR;
+#ifdef CONFIG_SMP
+ /* On iSeries we know we can never have more than 64 cpus */
+ nr_cpu_ids = max(nr_cpu_ids, 64);
+#endif
+
iSeries_fixup_klimit();
/*
diff --git a/arch/powerpc/platforms/iseries/smp.c b/arch/powerpc/platforms/iseries/smp.c
index 6c6029914dbc..e3265adde5d3 100644
--- a/arch/powerpc/platforms/iseries/smp.c
+++ b/arch/powerpc/platforms/iseries/smp.c
@@ -42,57 +42,23 @@
#include <asm/cputable.h>
#include <asm/system.h>
-#include "smp.h"
-
-static unsigned long iSeries_smp_message[NR_CPUS];
-
-void iSeries_smp_message_recv(void)
-{
- 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, &iSeries_smp_message[cpu]))
- smp_message_recv(msg);
-}
-
-static inline void smp_iSeries_do_message(int cpu, int msg)
+static void smp_iSeries_cause_ipi(int cpu, unsigned long data)
{
- set_bit(msg, &iSeries_smp_message[cpu]);
HvCall_sendIPI(&(paca[cpu]));
}
-static void smp_iSeries_message_pass(int target, int msg)
-{
- int i;
-
- if (target < NR_CPUS)
- smp_iSeries_do_message(target, msg);
- else {
- for_each_online_cpu(i) {
- if ((target == MSG_ALL_BUT_SELF) &&
- (i == smp_processor_id()))
- continue;
- smp_iSeries_do_message(i, msg);
- }
- }
-}
-
static int smp_iSeries_probe(void)
{
return cpumask_weight(cpu_possible_mask);
}
-static void smp_iSeries_kick_cpu(int nr)
+static int smp_iSeries_kick_cpu(int nr)
{
BUG_ON((nr < 0) || (nr >= NR_CPUS));
/* Verify that our partition has a processor nr */
if (lppaca_of(nr).dyn_proc_status >= 2)
- return;
+ return -ENOENT;
/* The processor is currently spinning, waiting
* for the cpu_start field to become non-zero
@@ -100,6 +66,8 @@ static void smp_iSeries_kick_cpu(int nr)
* continue on to secondary_start in iSeries_head.S
*/
paca[nr].cpu_start = 1;
+
+ return 0;
}
static void __devinit smp_iSeries_setup_cpu(int nr)
@@ -107,7 +75,8 @@ static void __devinit smp_iSeries_setup_cpu(int nr)
}
static struct smp_ops_t iSeries_smp_ops = {
- .message_pass = smp_iSeries_message_pass,
+ .message_pass = smp_muxed_ipi_message_pass,
+ .cause_ipi = smp_iSeries_cause_ipi,
.probe = smp_iSeries_probe,
.kick_cpu = smp_iSeries_kick_cpu,
.setup_cpu = smp_iSeries_setup_cpu,
diff --git a/arch/powerpc/platforms/iseries/smp.h b/arch/powerpc/platforms/iseries/smp.h
deleted file mode 100644
index d501f7de01e7..000000000000
--- a/arch/powerpc/platforms/iseries/smp.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _PLATFORMS_ISERIES_SMP_H
-#define _PLATFORMS_ISERIES_SMP_H
-
-extern void iSeries_smp_message_recv(void);
-
-#endif /* _PLATFORMS_ISERIES_SMP_H */
diff --git a/arch/powerpc/platforms/powermac/Kconfig b/arch/powerpc/platforms/powermac/Kconfig
index 1e1a0873e1dd..1afd10f67858 100644
--- a/arch/powerpc/platforms/powermac/Kconfig
+++ b/arch/powerpc/platforms/powermac/Kconfig
@@ -18,4 +18,13 @@ config PPC_PMAC64
select PPC_970_NAP
default y
-
+config PPC_PMAC32_PSURGE
+ bool "Support for powersurge upgrade cards" if EXPERT
+ depends on SMP && PPC32 && PPC_PMAC
+ select PPC_SMP_MUXED_IPI
+ default y
+ help
+ The powersurge cpu boards can be used in the generation
+ of powermacs that have a socket for an upgradeable cpu card,
+ including the 7500, 8500, 9500, 9600. Support exists for
+ both dual and quad socket upgrade cards.
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
index 023f24086a0a..9089b0421191 100644
--- a/arch/powerpc/platforms/powermac/pic.c
+++ b/arch/powerpc/platforms/powermac/pic.c
@@ -21,7 +21,7 @@
#include <linux/signal.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/adb.h>
#include <linux/pmu.h>
#include <linux/module.h>
@@ -84,7 +84,7 @@ static void __pmac_retrigger(unsigned int irq_nr)
static void pmac_mask_and_ack_irq(struct irq_data *d)
{
- unsigned int src = irq_map[d->irq].hwirq;
+ unsigned int src = irqd_to_hwirq(d);
unsigned long bit = 1UL << (src & 0x1f);
int i = src >> 5;
unsigned long flags;
@@ -106,7 +106,7 @@ static void pmac_mask_and_ack_irq(struct irq_data *d)
static void pmac_ack_irq(struct irq_data *d)
{
- unsigned int src = irq_map[d->irq].hwirq;
+ unsigned int src = irqd_to_hwirq(d);
unsigned long bit = 1UL << (src & 0x1f);
int i = src >> 5;
unsigned long flags;
@@ -152,7 +152,7 @@ static void __pmac_set_irq_mask(unsigned int irq_nr, int nokicklost)
static unsigned int pmac_startup_irq(struct irq_data *d)
{
unsigned long flags;
- unsigned int src = irq_map[d->irq].hwirq;
+ unsigned int src = irqd_to_hwirq(d);
unsigned long bit = 1UL << (src & 0x1f);
int i = src >> 5;
@@ -169,7 +169,7 @@ static unsigned int pmac_startup_irq(struct irq_data *d)
static void pmac_mask_irq(struct irq_data *d)
{
unsigned long flags;
- unsigned int src = irq_map[d->irq].hwirq;
+ unsigned int src = irqd_to_hwirq(d);
raw_spin_lock_irqsave(&pmac_pic_lock, flags);
__clear_bit(src, ppc_cached_irq_mask);
@@ -180,7 +180,7 @@ static void pmac_mask_irq(struct irq_data *d)
static void pmac_unmask_irq(struct irq_data *d)
{
unsigned long flags;
- unsigned int src = irq_map[d->irq].hwirq;
+ unsigned int src = irqd_to_hwirq(d);
raw_spin_lock_irqsave(&pmac_pic_lock, flags);
__set_bit(src, ppc_cached_irq_mask);
@@ -193,7 +193,7 @@ static int pmac_retrigger(struct irq_data *d)
unsigned long flags;
raw_spin_lock_irqsave(&pmac_pic_lock, flags);
- __pmac_retrigger(irq_map[d->irq].hwirq);
+ __pmac_retrigger(irqd_to_hwirq(d));
raw_spin_unlock_irqrestore(&pmac_pic_lock, flags);
return 1;
}
@@ -239,15 +239,12 @@ static unsigned int pmac_pic_get_irq(void)
unsigned long bits = 0;
unsigned long flags;
-#ifdef CONFIG_SMP
- void psurge_smp_message_recv(void);
-
- /* IPI's are a hack on the powersurge -- Cort */
- if ( smp_processor_id() != 0 ) {
- psurge_smp_message_recv();
- return NO_IRQ_IGNORE; /* ignore, already handled */
+#ifdef CONFIG_PPC_PMAC32_PSURGE
+ /* IPI's are a hack on the powersurge -- Cort */
+ if (smp_processor_id() != 0) {
+ return psurge_secondary_virq;
}
-#endif /* CONFIG_SMP */
+#endif /* CONFIG_PPC_PMAC32_PSURGE */
raw_spin_lock_irqsave(&pmac_pic_lock, flags);
for (irq = max_real_irqs; (irq -= 32) >= 0; ) {
int i = irq >> 5;
@@ -677,7 +674,7 @@ not_found:
return viaint;
}
-static int pmacpic_suspend(struct sys_device *sysdev, pm_message_t state)
+static int pmacpic_suspend(void)
{
int viaint = pmacpic_find_viaint();
@@ -698,7 +695,7 @@ static int pmacpic_suspend(struct sys_device *sysdev, pm_message_t state)
return 0;
}
-static int pmacpic_resume(struct sys_device *sysdev)
+static void pmacpic_resume(void)
{
int i;
@@ -709,39 +706,19 @@ static int pmacpic_resume(struct sys_device *sysdev)
for (i = 0; i < max_real_irqs; ++i)
if (test_bit(i, sleep_save_mask))
pmac_unmask_irq(irq_get_irq_data(i));
-
- return 0;
}
-#endif /* CONFIG_PM && CONFIG_PPC32 */
-
-static struct sysdev_class pmacpic_sysclass = {
- .name = "pmac_pic",
-};
-
-static struct sys_device device_pmacpic = {
- .id = 0,
- .cls = &pmacpic_sysclass,
-};
-
-static struct sysdev_driver driver_pmacpic = {
-#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
- .suspend = &pmacpic_suspend,
- .resume = &pmacpic_resume,
-#endif /* CONFIG_PM && CONFIG_PPC32 */
+static struct syscore_ops pmacpic_syscore_ops = {
+ .suspend = pmacpic_suspend,
+ .resume = pmacpic_resume,
};
-static int __init init_pmacpic_sysfs(void)
+static int __init init_pmacpic_syscore(void)
{
-#ifdef CONFIG_PPC32
- if (max_irqs == 0)
- return -ENODEV;
-#endif
- printk(KERN_DEBUG "Registering pmac pic with sysfs...\n");
- sysdev_class_register(&pmacpic_sysclass);
- sysdev_register(&device_pmacpic);
- sysdev_driver_register(&pmacpic_sysclass, &driver_pmacpic);
+ register_syscore_ops(&pmacpic_syscore_ops);
return 0;
}
-machine_subsys_initcall(powermac, init_pmacpic_sysfs);
+machine_subsys_initcall(powermac, init_pmacpic_syscore);
+
+#endif /* CONFIG_PM && CONFIG_PPC32 */
diff --git a/arch/powerpc/platforms/powermac/pic.h b/arch/powerpc/platforms/powermac/pic.h
deleted file mode 100644
index d622a8345aaa..000000000000
--- a/arch/powerpc/platforms/powermac/pic.h
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef __PPC_PLATFORMS_PMAC_PIC_H
-#define __PPC_PLATFORMS_PMAC_PIC_H
-
-#include <linux/irq.h>
-
-extern struct irq_chip pmac_pic;
-
-extern void pmac_pic_init(void);
-extern int pmac_get_irq(void);
-
-#endif /* __PPC_PLATFORMS_PMAC_PIC_H */
diff --git a/arch/powerpc/platforms/powermac/pmac.h b/arch/powerpc/platforms/powermac/pmac.h
index 20468f49aec0..8327cce2bdb0 100644
--- a/arch/powerpc/platforms/powermac/pmac.h
+++ b/arch/powerpc/platforms/powermac/pmac.h
@@ -33,6 +33,7 @@ extern void pmac_setup_pci_dma(void);
extern void pmac_check_ht_link(void);
extern void pmac_setup_smp(void);
+extern int psurge_secondary_virq;
extern void low_cpu_die(void) __attribute__((noreturn));
extern int pmac_nvram_init(void);
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
index bc5f0dc6ae1e..db092d7c4c5b 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -70,7 +70,7 @@ static void (*pmac_tb_freeze)(int freeze);
static u64 timebase;
static int tb_req;
-#ifdef CONFIG_PPC32
+#ifdef CONFIG_PPC_PMAC32_PSURGE
/*
* Powersurge (old powermac SMP) support.
@@ -124,6 +124,10 @@ static volatile u32 __iomem *psurge_start;
/* what sort of powersurge board we have */
static int psurge_type = PSURGE_NONE;
+/* irq for secondary cpus to report */
+static struct irq_host *psurge_host;
+int psurge_secondary_virq;
+
/*
* Set and clear IPIs for powersurge.
*/
@@ -156,51 +160,52 @@ static inline void psurge_clr_ipi(int cpu)
/*
* On powersurge (old SMP powermac architecture) we don't have
* separate IPIs for separate messages like openpic does. Instead
- * we have a bitmap for each processor, where a 1 bit means that
- * the corresponding message is pending for that processor.
- * Ideally each cpu's entry would be in a different cache line.
+ * use the generic demux helpers
* -- paulus.
*/
-static unsigned long psurge_smp_message[NR_CPUS];
-
-void psurge_smp_message_recv(void)
+static irqreturn_t psurge_ipi_intr(int irq, void *d)
{
- int cpu = smp_processor_id();
- int msg;
+ psurge_clr_ipi(smp_processor_id());
+ smp_ipi_demux();
- /* clear interrupt */
- psurge_clr_ipi(cpu);
-
- if (num_online_cpus() < 2)
- return;
+ return IRQ_HANDLED;
+}
- /* make sure there is a message there */
- for (msg = 0; msg < 4; msg++)
- if (test_and_clear_bit(msg, &psurge_smp_message[cpu]))
- smp_message_recv(msg);
+static void smp_psurge_cause_ipi(int cpu, unsigned long data)
+{
+ psurge_set_ipi(cpu);
}
-irqreturn_t psurge_primary_intr(int irq, void *d)
+static int psurge_host_map(struct irq_host *h, unsigned int virq,
+ irq_hw_number_t hw)
{
- psurge_smp_message_recv();
- return IRQ_HANDLED;
+ irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_percpu_irq);
+
+ return 0;
}
-static void smp_psurge_message_pass(int target, int msg)
+struct irq_host_ops psurge_host_ops = {
+ .map = psurge_host_map,
+};
+
+static int psurge_secondary_ipi_init(void)
{
- int i;
+ int rc = -ENOMEM;
- if (num_online_cpus() < 2)
- return;
+ psurge_host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0,
+ &psurge_host_ops, 0);
- for_each_online_cpu(i) {
- if (target == MSG_ALL
- || (target == MSG_ALL_BUT_SELF && i != smp_processor_id())
- || target == i) {
- set_bit(msg, &psurge_smp_message[i]);
- psurge_set_ipi(i);
- }
- }
+ if (psurge_host)
+ psurge_secondary_virq = irq_create_direct_mapping(psurge_host);
+
+ if (psurge_secondary_virq)
+ rc = request_irq(psurge_secondary_virq, psurge_ipi_intr,
+ IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL);
+
+ if (rc)
+ pr_err("Failed to setup secondary cpu IPI\n");
+
+ return rc;
}
/*
@@ -311,6 +316,9 @@ static int __init smp_psurge_probe(void)
ncpus = 2;
}
+ if (psurge_secondary_ipi_init())
+ return 1;
+
psurge_start = ioremap(PSURGE_START, 4);
psurge_pri_intr = ioremap(PSURGE_PRI_INTR, 4);
@@ -329,7 +337,7 @@ static int __init smp_psurge_probe(void)
return ncpus;
}
-static void __init smp_psurge_kick_cpu(int nr)
+static int __init smp_psurge_kick_cpu(int nr)
{
unsigned long start = __pa(__secondary_start_pmac_0) + nr * 8;
unsigned long a, flags;
@@ -394,11 +402,13 @@ static void __init smp_psurge_kick_cpu(int nr)
psurge_set_ipi(1);
if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354);
+
+ return 0;
}
static struct irqaction psurge_irqaction = {
- .handler = psurge_primary_intr,
- .flags = IRQF_DISABLED,
+ .handler = psurge_ipi_intr,
+ .flags = IRQF_DISABLED|IRQF_PERCPU,
.name = "primary IPI",
};
@@ -437,14 +447,15 @@ void __init smp_psurge_give_timebase(void)
/* PowerSurge-style Macs */
struct smp_ops_t psurge_smp_ops = {
- .message_pass = smp_psurge_message_pass,
+ .message_pass = smp_muxed_ipi_message_pass,
+ .cause_ipi = smp_psurge_cause_ipi,
.probe = smp_psurge_probe,
.kick_cpu = smp_psurge_kick_cpu,
.setup_cpu = smp_psurge_setup_cpu,
.give_timebase = smp_psurge_give_timebase,
.take_timebase = smp_psurge_take_timebase,
};
-#endif /* CONFIG_PPC32 - actually powersurge support */
+#endif /* CONFIG_PPC_PMAC32_PSURGE */
/*
* Core 99 and later support
@@ -791,14 +802,14 @@ static int __init smp_core99_probe(void)
return ncpus;
}
-static void __devinit smp_core99_kick_cpu(int nr)
+static int __devinit smp_core99_kick_cpu(int nr)
{
unsigned int save_vector;
unsigned long target, flags;
unsigned int *vector = (unsigned int *)(PAGE_OFFSET+0x100);
if (nr < 0 || nr > 3)
- return;
+ return -ENOENT;
if (ppc_md.progress)
ppc_md.progress("smp_core99_kick_cpu", 0x346);
@@ -830,6 +841,8 @@ static void __devinit smp_core99_kick_cpu(int nr)
local_irq_restore(flags);
if (ppc_md.progress) ppc_md.progress("smp_core99_kick_cpu done", 0x347);
+
+ return 0;
}
static void __devinit smp_core99_setup_cpu(int cpu_nr)
@@ -1002,7 +1015,7 @@ void __init pmac_setup_smp(void)
of_node_put(np);
smp_ops = &core99_smp_ops;
}
-#ifdef CONFIG_PPC32
+#ifdef CONFIG_PPC_PMAC32_PSURGE
else {
/* We have to set bits in cpu_possible_mask here since the
* secondary CPU(s) aren't in the device tree. Various
@@ -1015,7 +1028,7 @@ void __init pmac_setup_smp(void)
set_cpu_possible(cpu, true);
smp_ops = &psurge_smp_ops;
}
-#endif /* CONFIG_PPC32 */
+#endif /* CONFIG_PPC_PMAC32_PSURGE */
#ifdef CONFIG_HOTPLUG_CPU
ppc_md.cpu_die = pmac_cpu_die;
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c
index f2f6413b81d3..600ed2c0ed59 100644
--- a/arch/powerpc/platforms/ps3/interrupt.c
+++ b/arch/powerpc/platforms/ps3/interrupt.c
@@ -197,7 +197,7 @@ static int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
result = irq_set_chip_data(*virq, pd);
if (result) {
- pr_debug("%s:%d: set_irq_chip_data failed\n",
+ pr_debug("%s:%d: irq_set_chip_data failed\n",
__func__, __LINE__);
goto fail_set;
}
@@ -659,11 +659,6 @@ static void __maybe_unused _dump_mask(struct ps3_private *pd,
static void dump_bmp(struct ps3_private* pd) {};
#endif /* defined(DEBUG) */
-static void ps3_host_unmap(struct irq_host *h, unsigned int virq)
-{
- irq_set_chip_data(virq, NULL);
-}
-
static int ps3_host_map(struct irq_host *h, unsigned int virq,
irq_hw_number_t hwirq)
{
@@ -683,7 +678,6 @@ static int ps3_host_match(struct irq_host *h, struct device_node *np)
static struct irq_host_ops ps3_host_ops = {
.map = ps3_host_map,
- .unmap = ps3_host_unmap,
.match = ps3_host_match,
};
diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c
index 51ffde40af2b..4c44794faac0 100644
--- a/arch/powerpc/platforms/ps3/smp.c
+++ b/arch/powerpc/platforms/ps3/smp.c
@@ -39,7 +39,7 @@
#define MSG_COUNT 4
static DEFINE_PER_CPU(unsigned int [MSG_COUNT], ps3_ipi_virqs);
-static void do_message_pass(int target, int msg)
+static void ps3_smp_message_pass(int cpu, int msg)
{
int result;
unsigned int virq;
@@ -49,28 +49,12 @@ static void do_message_pass(int target, int msg)
return;
}
- virq = per_cpu(ps3_ipi_virqs, target)[msg];
+ virq = per_cpu(ps3_ipi_virqs, cpu)[msg];
result = ps3_send_event_locally(virq);
if (result)
DBG("%s:%d: ps3_send_event_locally(%d, %d) failed"
- " (%d)\n", __func__, __LINE__, target, msg, result);
-}
-
-static void ps3_smp_message_pass(int target, int msg)
-{
- int cpu;
-
- if (target < NR_CPUS)
- do_message_pass(target, msg);
- else if (target == MSG_ALL_BUT_SELF) {
- for_each_online_cpu(cpu)
- if (cpu != smp_processor_id())
- do_message_pass(cpu, msg);
- } else {
- for_each_online_cpu(cpu)
- do_message_pass(cpu, msg);
- }
+ " (%d)\n", __func__, __LINE__, cpu, msg, result);
}
static int ps3_smp_probe(void)
diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c
index 39a472e9e80f..375a9f92158d 100644
--- a/arch/powerpc/platforms/ps3/spu.c
+++ b/arch/powerpc/platforms/ps3/spu.c
@@ -197,7 +197,7 @@ static void spu_unmap(struct spu *spu)
* The current HV requires the spu shadow regs to be mapped with the
* PTE page protection bits set as read-only (PP=3). This implementation
* uses the low level __ioremap() to bypass the page protection settings
- * inforced by ioremap_flags() to get the needed PTE bits set for the
+ * inforced by ioremap_prot() to get the needed PTE bits set for the
* shadow regs.
*/
@@ -214,7 +214,7 @@ static int __init setup_areas(struct spu *spu)
goto fail_ioremap;
}
- spu->local_store = (__force void *)ioremap_flags(spu->local_store_phys,
+ spu->local_store = (__force void *)ioremap_prot(spu->local_store_phys,
LS_SIZE, _PAGE_NO_CACHE);
if (!spu->local_store) {
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig
index 5b3da4b4ea79..71af4c5d6c05 100644
--- a/arch/powerpc/platforms/pseries/Kconfig
+++ b/arch/powerpc/platforms/pseries/Kconfig
@@ -3,7 +3,10 @@ config PPC_PSERIES
bool "IBM pSeries & new (POWER5-based) iSeries"
select MPIC
select PCI_MSI
- select XICS
+ select PPC_XICS
+ select PPC_ICP_NATIVE
+ select PPC_ICP_HV
+ select PPC_ICS_RTAS
select PPC_I8259
select PPC_RTAS
select PPC_RTAS_DAEMON
@@ -47,6 +50,24 @@ config SCANLOG
tristate "Scanlog dump interface"
depends on RTAS_PROC && PPC_PSERIES
+config IO_EVENT_IRQ
+ bool "IO Event Interrupt support"
+ depends on PPC_PSERIES
+ default y
+ help
+ Select this option, if you want to enable support for IO Event
+ interrupts. IO event interrupt is a mechanism provided by RTAS
+ to return information about hardware error and non-error events
+ which may need OS attention. RTAS returns events for multiple
+ event types and scopes. Device drivers can register their handlers
+ to receive events.
+
+ This option will only enable the IO event platform code. You
+ will still need to enable or compile the actual drivers
+ that use this infrastruture to handle IO event interrupts.
+
+ Say Y if you are unsure.
+
config LPARCFG
bool "LPAR Configuration Data"
depends on PPC_PSERIES || PPC_ISERIES
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index fc5237810ece..3556e402cbf5 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -5,7 +5,6 @@ obj-y := lpar.o hvCall.o nvram.o reconfig.o \
setup.o iommu.o event_sources.o ras.o \
firmware.o power.o dlpar.o mobility.o
obj-$(CONFIG_SMP) += smp.o
-obj-$(CONFIG_XICS) += xics.o
obj-$(CONFIG_SCANLOG) += scanlog.o
obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o eeh_sysfs.o
obj-$(CONFIG_KEXEC) += kexec.o
@@ -22,6 +21,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
+obj-$(CONFIG_IO_EVENT_IRQ) += io_event_irq.o
ifeq ($(CONFIG_PPC_PSERIES),y)
obj-$(CONFIG_SUSPEND) += suspend.o
diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c
index c371bc06434b..e9190073bb97 100644
--- a/arch/powerpc/platforms/pseries/dtl.c
+++ b/arch/powerpc/platforms/pseries/dtl.c
@@ -52,10 +52,10 @@ static u8 dtl_event_mask = 0x7;
/*
- * Size of per-cpu log buffers. Default is just under 16 pages worth.
+ * Size of per-cpu log buffers. Firmware requires that the buffer does
+ * not cross a 4k boundary.
*/
-static int dtl_buf_entries = (16 * 85);
-
+static int dtl_buf_entries = N_DISPATCH_LOG;
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
struct dtl_ring {
@@ -151,7 +151,7 @@ static int dtl_start(struct dtl *dtl)
/* Register our dtl buffer with the hypervisor. The HV expects the
* buffer size to be passed in the second word of the buffer */
- ((u32 *)dtl->buf)[1] = dtl->buf_entries * sizeof(struct dtl_entry);
+ ((u32 *)dtl->buf)[1] = DISPATCH_LOG_BYTES;
hwcpu = get_hard_smp_processor_id(dtl->cpu);
addr = __pa(dtl->buf);
@@ -196,13 +196,15 @@ static int dtl_enable(struct dtl *dtl)
long int rc;
struct dtl_entry *buf = NULL;
+ if (!dtl_cache)
+ return -ENOMEM;
+
/* only allow one reader */
if (dtl->buf)
return -EBUSY;
n_entries = dtl_buf_entries;
- buf = kmalloc_node(n_entries * sizeof(struct dtl_entry),
- GFP_KERNEL, cpu_to_node(dtl->cpu));
+ buf = kmem_cache_alloc_node(dtl_cache, GFP_KERNEL, cpu_to_node(dtl->cpu));
if (!buf) {
printk(KERN_WARNING "%s: buffer alloc failed for cpu %d\n",
__func__, dtl->cpu);
@@ -223,7 +225,7 @@ static int dtl_enable(struct dtl *dtl)
spin_unlock(&dtl->lock);
if (rc)
- kfree(buf);
+ kmem_cache_free(dtl_cache, buf);
return rc;
}
@@ -231,7 +233,7 @@ static void dtl_disable(struct dtl *dtl)
{
spin_lock(&dtl->lock);
dtl_stop(dtl);
- kfree(dtl->buf);
+ kmem_cache_free(dtl_cache, dtl->buf);
dtl->buf = NULL;
dtl->buf_entries = 0;
spin_unlock(&dtl->lock);
@@ -365,7 +367,7 @@ static int dtl_init(void)
event_mask_file = debugfs_create_x8("dtl_event_mask", 0600,
dtl_dir, &dtl_event_mask);
- buf_entries_file = debugfs_create_u32("dtl_buf_entries", 0600,
+ buf_entries_file = debugfs_create_u32("dtl_buf_entries", 0400,
dtl_dir, &dtl_buf_entries);
if (!event_mask_file || !buf_entries_file) {
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 89649173d3a3..46b55cf563e3 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -93,6 +93,7 @@ static int ibm_slot_error_detail;
static int ibm_get_config_addr_info;
static int ibm_get_config_addr_info2;
static int ibm_configure_bridge;
+static int ibm_configure_pe;
int eeh_subsystem_enabled;
EXPORT_SYMBOL(eeh_subsystem_enabled);
@@ -261,6 +262,8 @@ void eeh_slot_error_detail(struct pci_dn *pdn, int severity)
pci_regs_buf[0] = 0;
rtas_pci_enable(pdn, EEH_THAW_MMIO);
+ rtas_configure_bridge(pdn);
+ eeh_restore_bars(pdn);
loglen = gather_pci_data(pdn, pci_regs_buf, EEH_PCI_REGS_LOG_LEN);
rtas_slot_error_detail(pdn, severity, pci_regs_buf, loglen);
@@ -448,6 +451,39 @@ void eeh_clear_slot (struct device_node *dn, int mode_flag)
raw_spin_unlock_irqrestore(&confirm_error_lock, flags);
}
+void __eeh_set_pe_freset(struct device_node *parent, unsigned int *freset)
+{
+ struct device_node *dn;
+
+ for_each_child_of_node(parent, dn) {
+ if (PCI_DN(dn)) {
+
+ struct pci_dev *dev = PCI_DN(dn)->pcidev;
+
+ if (dev && dev->driver)
+ *freset |= dev->needs_freset;
+
+ __eeh_set_pe_freset(dn, freset);
+ }
+ }
+}
+
+void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset)
+{
+ struct pci_dev *dev;
+ dn = find_device_pe(dn);
+
+ /* Back up one, since config addrs might be shared */
+ if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent))
+ dn = dn->parent;
+
+ dev = PCI_DN(dn)->pcidev;
+ if (dev)
+ *freset |= dev->needs_freset;
+
+ __eeh_set_pe_freset(dn, freset);
+}
+
/**
* eeh_dn_check_failure - check if all 1's data is due to EEH slot freeze
* @dn device node
@@ -692,15 +728,24 @@ rtas_pci_slot_reset(struct pci_dn *pdn, int state)
if (pdn->eeh_pe_config_addr)
config_addr = pdn->eeh_pe_config_addr;
- rc = rtas_call(ibm_set_slot_reset,4,1, NULL,
+ rc = rtas_call(ibm_set_slot_reset, 4, 1, NULL,
config_addr,
BUID_HI(pdn->phb->buid),
BUID_LO(pdn->phb->buid),
state);
- if (rc)
- printk (KERN_WARNING "EEH: Unable to reset the failed slot,"
- " (%d) #RST=%d dn=%s\n",
- rc, state, pdn->node->full_name);
+
+ /* Fundamental-reset not supported on this PE, try hot-reset */
+ if (rc == -8 && state == 3) {
+ rc = rtas_call(ibm_set_slot_reset, 4, 1, NULL,
+ config_addr,
+ BUID_HI(pdn->phb->buid),
+ BUID_LO(pdn->phb->buid), 1);
+ if (rc)
+ printk(KERN_WARNING
+ "EEH: Unable to reset the failed slot,"
+ " #RST=%d dn=%s\n",
+ rc, pdn->node->full_name);
+ }
}
/**
@@ -736,18 +781,21 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat
/**
* rtas_set_slot_reset -- assert the pci #RST line for 1/4 second
* @pdn: pci device node to be reset.
- *
- * Return 0 if success, else a non-zero value.
*/
static void __rtas_set_slot_reset(struct pci_dn *pdn)
{
- struct pci_dev *dev = pdn->pcidev;
+ unsigned int freset = 0;
- /* Determine type of EEH reset required by device,
- * default hot reset or fundamental reset
- */
- if (dev && dev->needs_freset)
+ /* Determine type of EEH reset required for
+ * Partitionable Endpoint, a hot-reset (1)
+ * or a fundamental reset (3).
+ * A fundamental reset required by any device under
+ * Partitionable Endpoint trumps hot-reset.
+ */
+ eeh_set_pe_freset(pdn->node, &freset);
+
+ if (freset)
rtas_pci_slot_reset(pdn, 3);
else
rtas_pci_slot_reset(pdn, 1);
@@ -895,13 +943,20 @@ rtas_configure_bridge(struct pci_dn *pdn)
{
int config_addr;
int rc;
+ int token;
/* Use PE configuration address, if present */
config_addr = pdn->eeh_config_addr;
if (pdn->eeh_pe_config_addr)
config_addr = pdn->eeh_pe_config_addr;
- rc = rtas_call(ibm_configure_bridge,3,1, NULL,
+ /* Use new configure-pe function, if supported */
+ if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE)
+ token = ibm_configure_pe;
+ else
+ token = ibm_configure_bridge;
+
+ rc = rtas_call(token, 3, 1, NULL,
config_addr,
BUID_HI(pdn->phb->buid),
BUID_LO(pdn->phb->buid));
@@ -1077,6 +1132,7 @@ void __init eeh_init(void)
ibm_get_config_addr_info = rtas_token("ibm,get-config-addr-info");
ibm_get_config_addr_info2 = rtas_token("ibm,get-config-addr-info2");
ibm_configure_bridge = rtas_token ("ibm,configure-bridge");
+ ibm_configure_pe = rtas_token("ibm,configure-pe");
if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE)
return;
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index b8d70f5d9aa9..1b6cb10589e0 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -328,7 +328,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
struct pci_bus *frozen_bus;
int rc = 0;
enum pci_ers_result result = PCI_ERS_RESULT_NONE;
- const char *location, *pci_str, *drv_str;
+ const char *location, *pci_str, *drv_str, *bus_pci_str, *bus_drv_str;
frozen_dn = find_device_pe(event->dn);
if (!frozen_dn) {
@@ -364,13 +364,8 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
frozen_pdn = PCI_DN(frozen_dn);
frozen_pdn->eeh_freeze_count++;
- if (frozen_pdn->pcidev) {
- pci_str = pci_name (frozen_pdn->pcidev);
- drv_str = pcid_name (frozen_pdn->pcidev);
- } else {
- pci_str = eeh_pci_name(event->dev);
- drv_str = pcid_name (event->dev);
- }
+ pci_str = eeh_pci_name(event->dev);
+ drv_str = pcid_name(event->dev);
if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES)
goto excess_failures;
@@ -378,8 +373,17 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event)
printk(KERN_WARNING
"EEH: This PCI device has failed %d times in the last hour:\n",
frozen_pdn->eeh_freeze_count);
+
+ if (frozen_pdn->pcidev) {
+ bus_pci_str = pci_name(frozen_pdn->pcidev);
+ bus_drv_str = pcid_name(frozen_pdn->pcidev);
+ printk(KERN_WARNING
+ "EEH: Bus location=%s driver=%s pci addr=%s\n",
+ location, bus_drv_str, bus_pci_str);
+ }
+
printk(KERN_WARNING
- "EEH: location=%s driver=%s pci addr=%s\n",
+ "EEH: Device location=%s driver=%s pci addr=%s\n",
location, drv_str, pci_str);
/* Walk the various device drivers attached to this slot through
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index ef8c45489e20..46f13a3c5d09 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -19,6 +19,7 @@
*/
#include <linux/kernel.h>
+#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/cpu.h>
#include <asm/system.h>
@@ -28,7 +29,7 @@
#include <asm/machdep.h>
#include <asm/vdso_datapage.h>
#include <asm/pSeries_reconfig.h>
-#include "xics.h"
+#include <asm/xics.h>
#include "plpar_wrappers.h"
#include "offline_states.h"
@@ -280,7 +281,7 @@ static int pseries_add_processor(struct device_node *np)
}
for_each_cpu(cpu, tmp) {
- BUG_ON(cpumask_test_cpu(cpu, cpu_present_mask));
+ BUG_ON(cpu_present(cpu));
set_cpu_present(cpu, true);
set_hard_smp_processor_id(cpu, *intserv++);
}
diff --git a/arch/powerpc/platforms/pseries/io_event_irq.c b/arch/powerpc/platforms/pseries/io_event_irq.c
new file mode 100644
index 000000000000..c829e6067d54
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/io_event_irq.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2010 2011 Mark Nelson and Tseng-Hui (Frank) Lin, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/list.h>
+#include <linux/notifier.h>
+
+#include <asm/machdep.h>
+#include <asm/rtas.h>
+#include <asm/irq.h>
+#include <asm/io_event_irq.h>
+
+#include "pseries.h"
+
+/*
+ * IO event interrupt is a mechanism provided by RTAS to return
+ * information about hardware error and non-error events. Device
+ * drivers can register their event handlers to receive events.
+ * Device drivers are expected to use atomic_notifier_chain_register()
+ * and atomic_notifier_chain_unregister() to register and unregister
+ * their event handlers. Since multiple IO event types and scopes
+ * share an IO event interrupt, the event handlers are called one
+ * by one until the IO event is claimed by one of the handlers.
+ * The event handlers are expected to return NOTIFY_OK if the
+ * event is handled by the event handler or NOTIFY_DONE if the
+ * event does not belong to the handler.
+ *
+ * Usage:
+ *
+ * Notifier function:
+ * #include <asm/io_event_irq.h>
+ * int event_handler(struct notifier_block *nb, unsigned long val, void *data) {
+ * p = (struct pseries_io_event_sect_data *) data;
+ * if (! is_my_event(p->scope, p->event_type)) return NOTIFY_DONE;
+ * :
+ * :
+ * return NOTIFY_OK;
+ * }
+ * struct notifier_block event_nb = {
+ * .notifier_call = event_handler,
+ * }
+ *
+ * Registration:
+ * atomic_notifier_chain_register(&pseries_ioei_notifier_list, &event_nb);
+ *
+ * Unregistration:
+ * atomic_notifier_chain_unregister(&pseries_ioei_notifier_list, &event_nb);
+ */
+
+ATOMIC_NOTIFIER_HEAD(pseries_ioei_notifier_list);
+EXPORT_SYMBOL_GPL(pseries_ioei_notifier_list);
+
+static int ioei_check_exception_token;
+
+/* pSeries event log format */
+
+/* Two bytes ASCII section IDs */
+#define PSERIES_ELOG_SECT_ID_PRIV_HDR (('P' << 8) | 'H')
+#define PSERIES_ELOG_SECT_ID_USER_HDR (('U' << 8) | 'H')
+#define PSERIES_ELOG_SECT_ID_PRIMARY_SRC (('P' << 8) | 'S')
+#define PSERIES_ELOG_SECT_ID_EXTENDED_UH (('E' << 8) | 'H')
+#define PSERIES_ELOG_SECT_ID_FAILING_MTMS (('M' << 8) | 'T')
+#define PSERIES_ELOG_SECT_ID_SECONDARY_SRC (('S' << 8) | 'S')
+#define PSERIES_ELOG_SECT_ID_DUMP_LOCATOR (('D' << 8) | 'H')
+#define PSERIES_ELOG_SECT_ID_FW_ERROR (('S' << 8) | 'W')
+#define PSERIES_ELOG_SECT_ID_IMPACT_PART_ID (('L' << 8) | 'P')
+#define PSERIES_ELOG_SECT_ID_LOGIC_RESOURCE_ID (('L' << 8) | 'R')
+#define PSERIES_ELOG_SECT_ID_HMC_ID (('H' << 8) | 'M')
+#define PSERIES_ELOG_SECT_ID_EPOW (('E' << 8) | 'P')
+#define PSERIES_ELOG_SECT_ID_IO_EVENT (('I' << 8) | 'E')
+#define PSERIES_ELOG_SECT_ID_MANUFACT_INFO (('M' << 8) | 'I')
+#define PSERIES_ELOG_SECT_ID_CALL_HOME (('C' << 8) | 'H')
+#define PSERIES_ELOG_SECT_ID_USER_DEF (('U' << 8) | 'D')
+
+/* Vendor specific Platform Event Log Format, Version 6, section header */
+struct pseries_elog_section {
+ uint16_t id; /* 0x00 2-byte ASCII section ID */
+ uint16_t length; /* 0x02 Section length in bytes */
+ uint8_t version; /* 0x04 Section version */
+ uint8_t subtype; /* 0x05 Section subtype */
+ uint16_t creator_component; /* 0x06 Creator component ID */
+ uint8_t data[]; /* 0x08 Start of section data */
+};
+
+static char ioei_rtas_buf[RTAS_DATA_BUF_SIZE] __cacheline_aligned;
+
+/**
+ * Find data portion of a specific section in RTAS extended event log.
+ * @elog: RTAS error/event log.
+ * @sect_id: secsion ID.
+ *
+ * Return:
+ * pointer to the section data of the specified section
+ * NULL if not found
+ */
+static struct pseries_elog_section *find_xelog_section(struct rtas_error_log *elog,
+ uint16_t sect_id)
+{
+ struct rtas_ext_event_log_v6 *xelog =
+ (struct rtas_ext_event_log_v6 *) elog->buffer;
+ struct pseries_elog_section *sect;
+ unsigned char *p, *log_end;
+
+ /* Check that we understand the format */
+ if (elog->extended_log_length < sizeof(struct rtas_ext_event_log_v6) ||
+ xelog->log_format != RTAS_V6EXT_LOG_FORMAT_EVENT_LOG ||
+ xelog->company_id != RTAS_V6EXT_COMPANY_ID_IBM)
+ return NULL;
+
+ log_end = elog->buffer + elog->extended_log_length;
+ p = xelog->vendor_log;
+ while (p < log_end) {
+ sect = (struct pseries_elog_section *)p;
+ if (sect->id == sect_id)
+ return sect;
+ p += sect->length;
+ }
+ return NULL;
+}
+
+/**
+ * Find the data portion of an IO Event section from event log.
+ * @elog: RTAS error/event log.
+ *
+ * Return:
+ * pointer to a valid IO event section data. NULL if not found.
+ */
+static struct pseries_io_event * ioei_find_event(struct rtas_error_log *elog)
+{
+ struct pseries_elog_section *sect;
+
+ /* We should only ever get called for io-event interrupts, but if
+ * we do get called for another type then something went wrong so
+ * make some noise about it.
+ * RTAS_TYPE_IO only exists in extended event log version 6 or later.
+ * No need to check event log version.
+ */
+ if (unlikely(elog->type != RTAS_TYPE_IO)) {
+ printk_once(KERN_WARNING "io_event_irq: Unexpected event type %d",
+ elog->type);
+ return NULL;
+ }
+
+ sect = find_xelog_section(elog, PSERIES_ELOG_SECT_ID_IO_EVENT);
+ if (unlikely(!sect)) {
+ printk_once(KERN_WARNING "io_event_irq: RTAS extended event "
+ "log does not contain an IO Event section. "
+ "Could be a bug in system firmware!\n");
+ return NULL;
+ }
+ return (struct pseries_io_event *) &sect->data;
+}
+
+/*
+ * PAPR:
+ * - check-exception returns the first found error or event and clear that
+ * error or event so it is reported once.
+ * - Each interrupt returns one event. If a plateform chooses to report
+ * multiple events through a single interrupt, it must ensure that the
+ * interrupt remains asserted until check-exception has been used to
+ * process all out-standing events for that interrupt.
+ *
+ * Implementation notes:
+ * - Events must be processed in the order they are returned. Hence,
+ * sequential in nature.
+ * - The owner of an event is determined by combinations of scope,
+ * event type, and sub-type. There is no easy way to pre-sort clients
+ * by scope or event type alone. For example, Torrent ISR route change
+ * event is reported with scope 0x00 (Not Applicatable) rather than
+ * 0x3B (Torrent-hub). It is better to let the clients to identify
+ * who owns the the event.
+ */
+
+static irqreturn_t ioei_interrupt(int irq, void *dev_id)
+{
+ struct pseries_io_event *event;
+ int rtas_rc;
+
+ for (;;) {
+ rtas_rc = rtas_call(ioei_check_exception_token, 6, 1, NULL,
+ RTAS_VECTOR_EXTERNAL_INTERRUPT,
+ virq_to_hw(irq),
+ RTAS_IO_EVENTS, 1 /* Time Critical */,
+ __pa(ioei_rtas_buf),
+ RTAS_DATA_BUF_SIZE);
+ if (rtas_rc != 0)
+ break;
+
+ event = ioei_find_event((struct rtas_error_log *)ioei_rtas_buf);
+ if (!event)
+ continue;
+
+ atomic_notifier_call_chain(&pseries_ioei_notifier_list,
+ 0, event);
+ }
+ return IRQ_HANDLED;
+}
+
+static int __init ioei_init(void)
+{
+ struct device_node *np;
+
+ ioei_check_exception_token = rtas_token("check-exception");
+ if (ioei_check_exception_token == RTAS_UNKNOWN_SERVICE) {
+ pr_warning("IO Event IRQ not supported on this system !\n");
+ return -ENODEV;
+ }
+ np = of_find_node_by_path("/event-sources/ibm,io-events");
+ if (np) {
+ request_event_sources_irqs(np, ioei_interrupt, "IO_EVENT");
+ of_node_put(np);
+ } else {
+ pr_err("io_event_irq: No ibm,io-events on system! "
+ "IO Event interrupt disabled.\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+machine_subsys_initcall(pseries, ioei_init);
+
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index 6d5412a18b26..01faab9456ca 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -659,15 +659,18 @@ static void remove_ddw(struct device_node *np)
{
struct dynamic_dma_window_prop *dwp;
struct property *win64;
- const u32 *ddr_avail;
+ const u32 *ddw_avail;
u64 liobn;
int len, ret;
- ddr_avail = of_get_property(np, "ibm,ddw-applicable", &len);
+ ddw_avail = of_get_property(np, "ibm,ddw-applicable", &len);
win64 = of_find_property(np, DIRECT64_PROPNAME, NULL);
- if (!win64 || !ddr_avail || len < 3 * sizeof(u32))
+ if (!win64)
return;
+ if (!ddw_avail || len < 3 * sizeof(u32) || win64->length < sizeof(*dwp))
+ goto delprop;
+
dwp = win64->value;
liobn = (u64)be32_to_cpu(dwp->liobn);
@@ -681,28 +684,29 @@ static void remove_ddw(struct device_node *np)
pr_debug("%s successfully cleared tces in window.\n",
np->full_name);
- ret = rtas_call(ddr_avail[2], 1, 1, NULL, liobn);
+ ret = rtas_call(ddw_avail[2], 1, 1, NULL, liobn);
if (ret)
pr_warning("%s: failed to remove direct window: rtas returned "
"%d to ibm,remove-pe-dma-window(%x) %llx\n",
- np->full_name, ret, ddr_avail[2], liobn);
+ np->full_name, ret, ddw_avail[2], liobn);
else
pr_debug("%s: successfully removed direct window: rtas returned "
"%d to ibm,remove-pe-dma-window(%x) %llx\n",
- np->full_name, ret, ddr_avail[2], liobn);
-}
+ np->full_name, ret, ddw_avail[2], liobn);
+delprop:
+ ret = prom_remove_property(np, win64);
+ if (ret)
+ pr_warning("%s: failed to remove direct window property: %d\n",
+ np->full_name, ret);
+}
-static int dupe_ddw_if_already_created(struct pci_dev *dev, struct device_node *pdn)
+static u64 find_existing_ddw(struct device_node *pdn)
{
- struct device_node *dn;
- struct pci_dn *pcidn;
struct direct_window *window;
const struct dynamic_dma_window_prop *direct64;
u64 dma_addr = 0;
- dn = pci_device_to_OF_node(dev);
- pcidn = PCI_DN(dn);
spin_lock(&direct_window_list_lock);
/* check if we already created a window and dupe that config if so */
list_for_each_entry(window, &direct_window_list, list) {
@@ -717,36 +721,40 @@ static int dupe_ddw_if_already_created(struct pci_dev *dev, struct device_node *
return dma_addr;
}
-static u64 dupe_ddw_if_kexec(struct pci_dev *dev, struct device_node *pdn)
+static int find_existing_ddw_windows(void)
{
- struct device_node *dn;
- struct pci_dn *pcidn;
int len;
+ struct device_node *pdn;
struct direct_window *window;
const struct dynamic_dma_window_prop *direct64;
- u64 dma_addr = 0;
- dn = pci_device_to_OF_node(dev);
- pcidn = PCI_DN(dn);
- direct64 = of_get_property(pdn, DIRECT64_PROPNAME, &len);
- if (direct64) {
+ if (!firmware_has_feature(FW_FEATURE_LPAR))
+ return 0;
+
+ for_each_node_with_property(pdn, DIRECT64_PROPNAME) {
+ direct64 = of_get_property(pdn, DIRECT64_PROPNAME, &len);
+ if (!direct64)
+ continue;
+
window = kzalloc(sizeof(*window), GFP_KERNEL);
- if (!window) {
+ if (!window || len < sizeof(struct dynamic_dma_window_prop)) {
+ kfree(window);
remove_ddw(pdn);
- } else {
- window->device = pdn;
- window->prop = direct64;
- spin_lock(&direct_window_list_lock);
- list_add(&window->list, &direct_window_list);
- spin_unlock(&direct_window_list_lock);
- dma_addr = direct64->dma_base;
+ continue;
}
+
+ window->device = pdn;
+ window->prop = direct64;
+ spin_lock(&direct_window_list_lock);
+ list_add(&window->list, &direct_window_list);
+ spin_unlock(&direct_window_list_lock);
}
- return dma_addr;
+ return 0;
}
+machine_arch_initcall(pseries, find_existing_ddw_windows);
-static int query_ddw(struct pci_dev *dev, const u32 *ddr_avail,
+static int query_ddw(struct pci_dev *dev, const u32 *ddw_avail,
struct ddw_query_response *query)
{
struct device_node *dn;
@@ -767,15 +775,15 @@ static int query_ddw(struct pci_dev *dev, const u32 *ddr_avail,
if (pcidn->eeh_pe_config_addr)
cfg_addr = pcidn->eeh_pe_config_addr;
buid = pcidn->phb->buid;
- ret = rtas_call(ddr_avail[0], 3, 5, (u32 *)query,
+ ret = rtas_call(ddw_avail[0], 3, 5, (u32 *)query,
cfg_addr, BUID_HI(buid), BUID_LO(buid));
dev_info(&dev->dev, "ibm,query-pe-dma-windows(%x) %x %x %x"
- " returned %d\n", ddr_avail[0], cfg_addr, BUID_HI(buid),
+ " returned %d\n", ddw_avail[0], cfg_addr, BUID_HI(buid),
BUID_LO(buid), ret);
return ret;
}
-static int create_ddw(struct pci_dev *dev, const u32 *ddr_avail,
+static int create_ddw(struct pci_dev *dev, const u32 *ddw_avail,
struct ddw_create_response *create, int page_shift,
int window_shift)
{
@@ -800,12 +808,12 @@ static int create_ddw(struct pci_dev *dev, const u32 *ddr_avail,
do {
/* extra outputs are LIOBN and dma-addr (hi, lo) */
- ret = rtas_call(ddr_avail[1], 5, 4, (u32 *)create, cfg_addr,
+ ret = rtas_call(ddw_avail[1], 5, 4, (u32 *)create, cfg_addr,
BUID_HI(buid), BUID_LO(buid), page_shift, window_shift);
} while (rtas_busy_delay(ret));
dev_info(&dev->dev,
"ibm,create-pe-dma-window(%x) %x %x %x %x %x returned %d "
- "(liobn = 0x%x starting addr = %x %x)\n", ddr_avail[1],
+ "(liobn = 0x%x starting addr = %x %x)\n", ddw_avail[1],
cfg_addr, BUID_HI(buid), BUID_LO(buid), page_shift,
window_shift, ret, create->liobn, create->addr_hi, create->addr_lo);
@@ -831,18 +839,14 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
int page_shift;
u64 dma_addr, max_addr;
struct device_node *dn;
- const u32 *uninitialized_var(ddr_avail);
+ const u32 *uninitialized_var(ddw_avail);
struct direct_window *window;
- struct property *uninitialized_var(win64);
+ struct property *win64;
struct dynamic_dma_window_prop *ddwprop;
mutex_lock(&direct_window_init_mutex);
- dma_addr = dupe_ddw_if_already_created(dev, pdn);
- if (dma_addr != 0)
- goto out_unlock;
-
- dma_addr = dupe_ddw_if_kexec(dev, pdn);
+ dma_addr = find_existing_ddw(pdn);
if (dma_addr != 0)
goto out_unlock;
@@ -854,8 +858,8 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
* for the given node in that order.
* the property is actually in the parent, not the PE
*/
- ddr_avail = of_get_property(pdn, "ibm,ddw-applicable", &len);
- if (!ddr_avail || len < 3 * sizeof(u32))
+ ddw_avail = of_get_property(pdn, "ibm,ddw-applicable", &len);
+ if (!ddw_avail || len < 3 * sizeof(u32))
goto out_unlock;
/*
@@ -865,7 +869,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
* of page sizes: supported and supported for migrate-dma.
*/
dn = pci_device_to_OF_node(dev);
- ret = query_ddw(dev, ddr_avail, &query);
+ ret = query_ddw(dev, ddw_avail, &query);
if (ret != 0)
goto out_unlock;
@@ -907,13 +911,14 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
}
win64->name = kstrdup(DIRECT64_PROPNAME, GFP_KERNEL);
win64->value = ddwprop = kmalloc(sizeof(*ddwprop), GFP_KERNEL);
+ win64->length = sizeof(*ddwprop);
if (!win64->name || !win64->value) {
dev_info(&dev->dev,
"couldn't allocate property name and value\n");
goto out_free_prop;
}
- ret = create_ddw(dev, ddr_avail, &create, page_shift, len);
+ ret = create_ddw(dev, ddw_avail, &create, page_shift, len);
if (ret != 0)
goto out_free_prop;
@@ -1021,13 +1026,16 @@ static int dma_set_mask_pSeriesLP(struct device *dev, u64 dma_mask)
const void *dma_window = NULL;
u64 dma_offset;
- if (!dev->dma_mask || !dma_supported(dev, dma_mask))
+ if (!dev->dma_mask)
return -EIO;
+ if (!dev_is_pci(dev))
+ goto check_mask;
+
+ pdev = to_pci_dev(dev);
+
/* only attempt to use a new window if 64-bit DMA is requested */
if (!disable_ddw && dma_mask == DMA_BIT_MASK(64)) {
- pdev = to_pci_dev(dev);
-
dn = pci_device_to_OF_node(pdev);
dev_dbg(dev, "node is %s\n", dn->full_name);
@@ -1054,12 +1062,17 @@ static int dma_set_mask_pSeriesLP(struct device *dev, u64 dma_mask)
}
}
- /* fall-through to iommu ops */
- if (!ddw_enabled) {
- dev_info(dev, "Using 32-bit DMA via iommu\n");
+ /* fall back on iommu ops, restore table pointer with ops */
+ if (!ddw_enabled && get_dma_ops(dev) != &dma_iommu_ops) {
+ dev_info(dev, "Restoring 32-bit DMA via iommu\n");
set_dma_ops(dev, &dma_iommu_ops);
+ pci_dma_dev_setup_pSeriesLP(pdev);
}
+check_mask:
+ if (!dma_supported(dev, dma_mask))
+ return -EIO;
+
*dev->dma_mask = dma_mask;
return 0;
}
diff --git a/arch/powerpc/platforms/pseries/kexec.c b/arch/powerpc/platforms/pseries/kexec.c
index 77d38a5e2ff9..54cf3a4aa16b 100644
--- a/arch/powerpc/platforms/pseries/kexec.c
+++ b/arch/powerpc/platforms/pseries/kexec.c
@@ -7,15 +7,18 @@
* 2 of the License, or (at your option) any later version.
*/
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+
#include <asm/machdep.h>
#include <asm/page.h>
#include <asm/firmware.h>
#include <asm/kexec.h>
#include <asm/mpic.h>
+#include <asm/xics.h>
#include <asm/smp.h>
#include "pseries.h"
-#include "xics.h"
#include "plpar_wrappers.h"
static void pseries_kexec_cpu_down(int crash_shutdown, int secondary)
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index ca5d5898d320..39e6e0a7b2fa 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -329,6 +329,8 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group,
/* Make pHyp happy */
if ((rflags & _PAGE_NO_CACHE) & !(rflags & _PAGE_WRITETHRU))
hpte_r &= ~_PAGE_COHERENT;
+ if (firmware_has_feature(FW_FEATURE_XCMO) && !(hpte_r & HPTE_R_N))
+ flags |= H_COALESCE_CAND;
lpar_rc = plpar_pte_enter(flags, hpte_group, hpte_v, hpte_r, &slot);
if (unlikely(lpar_rc == H_PTEG_FULL)) {
@@ -573,7 +575,7 @@ static void pSeries_lpar_flush_hash_range(unsigned long number, int local)
unsigned long i, pix, rc;
unsigned long flags = 0;
struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
- int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE);
+ int lock_tlbie = !mmu_has_feature(MMU_FTR_LOCKLESS_TLBIE);
unsigned long param[9];
unsigned long va;
unsigned long hash, index, shift, hidx, slot;
@@ -771,3 +773,47 @@ out:
local_irq_restore(flags);
}
#endif
+
+/**
+ * h_get_mpp
+ * H_GET_MPP hcall returns info in 7 parms
+ */
+int h_get_mpp(struct hvcall_mpp_data *mpp_data)
+{
+ int rc;
+ unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
+
+ rc = plpar_hcall9(H_GET_MPP, retbuf);
+
+ mpp_data->entitled_mem = retbuf[0];
+ mpp_data->mapped_mem = retbuf[1];
+
+ mpp_data->group_num = (retbuf[2] >> 2 * 8) & 0xffff;
+ mpp_data->pool_num = retbuf[2] & 0xffff;
+
+ mpp_data->mem_weight = (retbuf[3] >> 7 * 8) & 0xff;
+ mpp_data->unallocated_mem_weight = (retbuf[3] >> 6 * 8) & 0xff;
+ mpp_data->unallocated_entitlement = retbuf[3] & 0xffffffffffff;
+
+ mpp_data->pool_size = retbuf[4];
+ mpp_data->loan_request = retbuf[5];
+ mpp_data->backing_mem = retbuf[6];
+
+ return rc;
+}
+EXPORT_SYMBOL(h_get_mpp);
+
+int h_get_mpp_x(struct hvcall_mpp_x_data *mpp_x_data)
+{
+ int rc;
+ unsigned long retbuf[PLPAR_HCALL9_BUFSIZE] = { 0 };
+
+ rc = plpar_hcall9(H_GET_MPP_X, retbuf);
+
+ mpp_x_data->coalesced_bytes = retbuf[0];
+ mpp_x_data->pool_coalesced_bytes = retbuf[1];
+ mpp_x_data->pool_purr_cycles = retbuf[2];
+ mpp_x_data->pool_spurr_cycles = retbuf[3];
+
+ return rc;
+}
diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h
index d9801117124b..4bf21207d7d3 100644
--- a/arch/powerpc/platforms/pseries/plpar_wrappers.h
+++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h
@@ -270,31 +270,4 @@ static inline long plpar_put_term_char(unsigned long termno, unsigned long len,
lbuf[1]);
}
-static inline long plpar_eoi(unsigned long xirr)
-{
- return plpar_hcall_norets(H_EOI, xirr);
-}
-
-static inline long plpar_cppr(unsigned long cppr)
-{
- return plpar_hcall_norets(H_CPPR, cppr);
-}
-
-static inline long plpar_ipi(unsigned long servernum, unsigned long mfrr)
-{
- return plpar_hcall_norets(H_IPI, servernum, mfrr);
-}
-
-static inline long plpar_xirr(unsigned long *xirr_ret, unsigned char cppr)
-{
- long rc;
- unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
-
- rc = plpar_hcall(H_XIRR, retbuf, cppr);
-
- *xirr_ret = retbuf[0];
-
- return rc;
-}
-
#endif /* _PSERIES_PLPAR_WRAPPERS_H */
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c
index c55d7ad9c648..086d2ae4e06a 100644
--- a/arch/powerpc/platforms/pseries/ras.c
+++ b/arch/powerpc/platforms/pseries/ras.c
@@ -122,7 +122,7 @@ static irqreturn_t ras_epow_interrupt(int irq, void *dev_id)
status = rtas_call(ras_check_exception_token, 6, 1, NULL,
RTAS_VECTOR_EXTERNAL_INTERRUPT,
- irq_map[irq].hwirq,
+ virq_to_hw(irq),
RTAS_EPOW_WARNING | RTAS_POWERMGM_EVENTS,
critical, __pa(&ras_log_buf),
rtas_get_error_log_max());
@@ -157,7 +157,7 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id)
status = rtas_call(ras_check_exception_token, 6, 1, NULL,
RTAS_VECTOR_EXTERNAL_INTERRUPT,
- irq_map[irq].hwirq,
+ virq_to_hw(irq),
RTAS_INTERNAL_ERROR, 1 /*Time Critical */,
__pa(&ras_log_buf),
rtas_get_error_log_max());
@@ -227,7 +227,7 @@ static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs)
struct rtas_error_log *h, *errhdr = NULL;
if (!VALID_FWNMI_BUFFER(regs->gpr[3])) {
- printk(KERN_ERR "FWNMI: corrupt r3\n");
+ printk(KERN_ERR "FWNMI: corrupt r3 0x%016lx\n", regs->gpr[3]);
return NULL;
}
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 6c42cfde8415..593acceeff96 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -53,9 +53,9 @@
#include <asm/irq.h>
#include <asm/time.h>
#include <asm/nvram.h>
-#include "xics.h"
#include <asm/pmc.h>
#include <asm/mpic.h>
+#include <asm/xics.h>
#include <asm/ppc-pci.h>
#include <asm/i8259.h>
#include <asm/udbg.h>
@@ -205,6 +205,9 @@ static void __init pseries_mpic_init_IRQ(void)
mpic_assign_isu(mpic, n, isuaddr);
}
+ /* Setup top-level get_irq */
+ ppc_md.get_irq = mpic_get_irq;
+
/* All ISUs are setup, complete initialization */
mpic_init(mpic);
@@ -214,7 +217,7 @@ static void __init pseries_mpic_init_IRQ(void)
static void __init pseries_xics_init_IRQ(void)
{
- xics_init_IRQ();
+ xics_init();
pseries_setup_i8259_cascade();
}
@@ -238,7 +241,6 @@ static void __init pseries_discover_pic(void)
if (strstr(typep, "open-pic")) {
pSeries_mpic_node = of_node_get(np);
ppc_md.init_IRQ = pseries_mpic_init_IRQ;
- ppc_md.get_irq = mpic_get_irq;
setup_kexec_cpu_down_mpic();
smp_init_pseries_mpic();
return;
@@ -276,6 +278,8 @@ static struct notifier_block pci_dn_reconfig_nb = {
.notifier_call = pci_dn_reconfig_notifier,
};
+struct kmem_cache *dtl_cache;
+
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
/*
* Allocate space for the dispatch trace log for all possible cpus
@@ -287,18 +291,12 @@ static int alloc_dispatch_logs(void)
int cpu, ret;
struct paca_struct *pp;
struct dtl_entry *dtl;
- struct kmem_cache *dtl_cache;
if (!firmware_has_feature(FW_FEATURE_SPLPAR))
return 0;
- dtl_cache = kmem_cache_create("dtl", DISPATCH_LOG_BYTES,
- DISPATCH_LOG_BYTES, 0, NULL);
- if (!dtl_cache) {
- pr_warn("Failed to create dispatch trace log buffer cache\n");
- pr_warn("Stolen time statistics will be unreliable\n");
+ if (!dtl_cache)
return 0;
- }
for_each_possible_cpu(cpu) {
pp = &paca[cpu];
@@ -332,10 +330,27 @@ static int alloc_dispatch_logs(void)
return 0;
}
-
-early_initcall(alloc_dispatch_logs);
+#else /* !CONFIG_VIRT_CPU_ACCOUNTING */
+static inline int alloc_dispatch_logs(void)
+{
+ return 0;
+}
#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
+static int alloc_dispatch_log_kmem_cache(void)
+{
+ dtl_cache = kmem_cache_create("dtl", DISPATCH_LOG_BYTES,
+ DISPATCH_LOG_BYTES, 0, NULL);
+ if (!dtl_cache) {
+ pr_warn("Failed to create dispatch trace log buffer cache\n");
+ pr_warn("Stolen time statistics will be unreliable\n");
+ return 0;
+ }
+
+ return alloc_dispatch_logs();
+}
+early_initcall(alloc_dispatch_log_kmem_cache);
+
static void __init pSeries_setup_arch(void)
{
/* Discover PIC type and setup ppc_md accordingly */
@@ -403,6 +418,16 @@ static int pseries_set_xdabr(unsigned long dabr)
#define CMO_CHARACTERISTICS_TOKEN 44
#define CMO_MAXLENGTH 1026
+void pSeries_coalesce_init(void)
+{
+ struct hvcall_mpp_x_data mpp_x_data;
+
+ if (firmware_has_feature(FW_FEATURE_CMO) && !h_get_mpp_x(&mpp_x_data))
+ powerpc_firmware_features |= FW_FEATURE_XCMO;
+ else
+ powerpc_firmware_features &= ~FW_FEATURE_XCMO;
+}
+
/**
* fw_cmo_feature_init - FW_FEATURE_CMO is not stored in ibm,hypertas-functions,
* handle that here. (Stolen from parse_system_parameter_string)
@@ -472,6 +497,7 @@ void pSeries_cmo_feature_init(void)
pr_debug("CMO enabled, PrPSP=%d, SecPSP=%d\n", CMO_PrPSP,
CMO_SecPSP);
powerpc_firmware_features |= FW_FEATURE_CMO;
+ pSeries_coalesce_init();
} else
pr_debug("CMO not enabled, PrPSP=%d, SecPSP=%d\n", CMO_PrPSP,
CMO_SecPSP);
diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c
index a509c5292a67..fbffd7e47ab8 100644
--- a/arch/powerpc/platforms/pseries/smp.c
+++ b/arch/powerpc/platforms/pseries/smp.c
@@ -44,10 +44,11 @@
#include <asm/mpic.h>
#include <asm/vdso_datapage.h>
#include <asm/cputhreads.h>
+#include <asm/mpic.h>
+#include <asm/xics.h>
#include "plpar_wrappers.h"
#include "pseries.h"
-#include "xics.h"
#include "offline_states.h"
@@ -136,7 +137,6 @@ out:
return 1;
}
-#ifdef CONFIG_XICS
static void __devinit smp_xics_setup_cpu(int cpu)
{
if (cpu != boot_cpuid)
@@ -151,14 +151,13 @@ static void __devinit smp_xics_setup_cpu(int cpu)
set_default_offline_state(cpu);
#endif
}
-#endif /* CONFIG_XICS */
-static void __devinit smp_pSeries_kick_cpu(int nr)
+static int __devinit smp_pSeries_kick_cpu(int nr)
{
BUG_ON(nr < 0 || nr >= NR_CPUS);
if (!smp_startup_cpu(nr))
- return;
+ return -ENOENT;
/*
* The processor is currently spinning, waiting for the
@@ -180,6 +179,8 @@ static void __devinit smp_pSeries_kick_cpu(int nr)
"Ret= %ld\n", nr, rc);
}
#endif
+
+ return 0;
}
static int smp_pSeries_cpu_bootable(unsigned int nr)
@@ -197,23 +198,22 @@ static int smp_pSeries_cpu_bootable(unsigned int nr)
return 1;
}
-#ifdef CONFIG_MPIC
+
static struct smp_ops_t pSeries_mpic_smp_ops = {
.message_pass = smp_mpic_message_pass,
.probe = smp_mpic_probe,
.kick_cpu = smp_pSeries_kick_cpu,
.setup_cpu = smp_mpic_setup_cpu,
};
-#endif
-#ifdef CONFIG_XICS
+
static struct smp_ops_t pSeries_xics_smp_ops = {
- .message_pass = smp_xics_message_pass,
- .probe = smp_xics_probe,
+ .message_pass = smp_muxed_ipi_message_pass,
+ .cause_ipi = NULL, /* Filled at runtime by xics_smp_probe() */
+ .probe = xics_smp_probe,
.kick_cpu = smp_pSeries_kick_cpu,
.setup_cpu = smp_xics_setup_cpu,
.cpu_bootable = smp_pSeries_cpu_bootable,
};
-#endif
/* This is called very early */
static void __init smp_init_pseries(void)
@@ -245,14 +245,12 @@ static void __init smp_init_pseries(void)
pr_debug(" <- smp_init_pSeries()\n");
}
-#ifdef CONFIG_MPIC
void __init smp_init_pseries_mpic(void)
{
smp_ops = &pSeries_mpic_smp_ops;
smp_init_pseries();
}
-#endif
void __init smp_init_pseries_xics(void)
{
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
deleted file mode 100644
index d6901334d66e..000000000000
--- a/arch/powerpc/platforms/pseries/xics.c
+++ /dev/null
@@ -1,949 +0,0 @@
-/*
- * arch/powerpc/platforms/pseries/xics.c
- *
- * Copyright 2000 IBM Corporation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/types.h>
-#include <linux/threads.h>
-#include <linux/kernel.h>
-#include <linux/irq.h>
-#include <linux/smp.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/radix-tree.h>
-#include <linux/cpu.h>
-#include <linux/msi.h>
-#include <linux/of.h>
-#include <linux/percpu.h>
-
-#include <asm/firmware.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/smp.h>
-#include <asm/rtas.h>
-#include <asm/hvcall.h>
-#include <asm/machdep.h>
-
-#include "xics.h"
-#include "plpar_wrappers.h"
-
-static struct irq_host *xics_host;
-
-#define XICS_IPI 2
-#define XICS_IRQ_SPURIOUS 0
-
-/* Want a priority other than 0. Various HW issues require this. */
-#define DEFAULT_PRIORITY 5
-
-/*
- * Mark IPIs as higher priority so we can take them inside interrupts that
- * arent marked IRQF_DISABLED
- */
-#define IPI_PRIORITY 4
-
-/* The least favored priority */
-#define LOWEST_PRIORITY 0xFF
-
-/* The number of priorities defined above */
-#define MAX_NUM_PRIORITIES 3
-
-static unsigned int default_server = 0xFF;
-static unsigned int default_distrib_server = 0;
-static unsigned int interrupt_server_size = 8;
-
-/* RTAS service tokens */
-static int ibm_get_xive;
-static int ibm_set_xive;
-static int ibm_int_on;
-static int ibm_int_off;
-
-struct xics_cppr {
- unsigned char stack[MAX_NUM_PRIORITIES];
- int index;
-};
-
-static DEFINE_PER_CPU(struct xics_cppr, xics_cppr);
-
-/* Direct hardware low level accessors */
-
-/* The part of the interrupt presentation layer that we care about */
-struct xics_ipl {
- union {
- u32 word;
- u8 bytes[4];
- } xirr_poll;
- union {
- u32 word;
- u8 bytes[4];
- } xirr;
- u32 dummy;
- union {
- u32 word;
- u8 bytes[4];
- } qirr;
-};
-
-static struct xics_ipl __iomem *xics_per_cpu[NR_CPUS];
-
-static inline unsigned int direct_xirr_info_get(void)
-{
- int cpu = smp_processor_id();
-
- return in_be32(&xics_per_cpu[cpu]->xirr.word);
-}
-
-static inline void direct_xirr_info_set(unsigned int value)
-{
- int cpu = smp_processor_id();
-
- out_be32(&xics_per_cpu[cpu]->xirr.word, value);
-}
-
-static inline void direct_cppr_info(u8 value)
-{
- int cpu = smp_processor_id();
-
- out_8(&xics_per_cpu[cpu]->xirr.bytes[0], value);
-}
-
-static inline void direct_qirr_info(int n_cpu, u8 value)
-{
- out_8(&xics_per_cpu[n_cpu]->qirr.bytes[0], value);
-}
-
-
-/* LPAR low level accessors */
-
-static inline unsigned int lpar_xirr_info_get(unsigned char cppr)
-{
- unsigned long lpar_rc;
- unsigned long return_value;
-
- lpar_rc = plpar_xirr(&return_value, cppr);
- if (lpar_rc != H_SUCCESS)
- panic(" bad return code xirr - rc = %lx\n", lpar_rc);
- return (unsigned int)return_value;
-}
-
-static inline void lpar_xirr_info_set(unsigned int value)
-{
- unsigned long lpar_rc;
-
- lpar_rc = plpar_eoi(value);
- if (lpar_rc != H_SUCCESS)
- panic("bad return code EOI - rc = %ld, value=%x\n", lpar_rc,
- value);
-}
-
-static inline void lpar_cppr_info(u8 value)
-{
- unsigned long lpar_rc;
-
- lpar_rc = plpar_cppr(value);
- if (lpar_rc != H_SUCCESS)
- panic("bad return code cppr - rc = %lx\n", lpar_rc);
-}
-
-static inline void lpar_qirr_info(int n_cpu , u8 value)
-{
- unsigned long lpar_rc;
-
- lpar_rc = plpar_ipi(get_hard_smp_processor_id(n_cpu), value);
- if (lpar_rc != H_SUCCESS)
- panic("bad return code qirr - rc = %lx\n", lpar_rc);
-}
-
-
-/* Interface to generic irq subsystem */
-
-#ifdef CONFIG_SMP
-/*
- * For the moment we only implement delivery to all cpus or one cpu.
- *
- * If the requested affinity is cpu_all_mask, we set global affinity.
- * If not we set it to the first cpu in the mask, even if multiple cpus
- * are set. This is so things like irqbalance (which set core and package
- * wide affinities) do the right thing.
- */
-static int get_irq_server(unsigned int virq, const struct cpumask *cpumask,
- unsigned int strict_check)
-{
-
- if (!distribute_irqs)
- return default_server;
-
- if (!cpumask_subset(cpu_possible_mask, cpumask)) {
- int server = cpumask_first_and(cpu_online_mask, cpumask);
-
- if (server < nr_cpu_ids)
- return get_hard_smp_processor_id(server);
-
- if (strict_check)
- return -1;
- }
-
- /*
- * Workaround issue with some versions of JS20 firmware that
- * deliver interrupts to cpus which haven't been started. This
- * happens when using the maxcpus= boot option.
- */
- if (cpumask_equal(cpu_online_mask, cpu_present_mask))
- return default_distrib_server;
-
- return default_server;
-}
-#else
-#define get_irq_server(virq, cpumask, strict_check) (default_server)
-#endif
-
-static void xics_unmask_irq(struct irq_data *d)
-{
- unsigned int hwirq;
- int call_status;
- int server;
-
- pr_devel("xics: unmask virq %d\n", d->irq);
-
- hwirq = (unsigned int)irq_map[d->irq].hwirq;
- pr_devel(" -> map to hwirq 0x%x\n", hwirq);
- if (hwirq == XICS_IPI || hwirq == XICS_IRQ_SPURIOUS)
- return;
-
- server = get_irq_server(d->irq, d->affinity, 0);
-
- call_status = rtas_call(ibm_set_xive, 3, 1, NULL, hwirq, server,
- DEFAULT_PRIORITY);
- if (call_status != 0) {
- printk(KERN_ERR
- "%s: ibm_set_xive irq %u server %x returned %d\n",
- __func__, hwirq, server, call_status);
- return;
- }
-
- /* Now unmask the interrupt (often a no-op) */
- call_status = rtas_call(ibm_int_on, 1, 1, NULL, hwirq);
- if (call_status != 0) {
- printk(KERN_ERR "%s: ibm_int_on irq=%u returned %d\n",
- __func__, hwirq, call_status);
- return;
- }
-}
-
-static unsigned int xics_startup(struct irq_data *d)
-{
- /*
- * The generic MSI code returns with the interrupt disabled on the
- * card, using the MSI mask bits. Firmware doesn't appear to unmask
- * at that level, so we do it here by hand.
- */
- if (d->msi_desc)
- unmask_msi_irq(d);
-
- /* unmask it */
- xics_unmask_irq(d);
- return 0;
-}
-
-static void xics_mask_real_irq(unsigned int hwirq)
-{
- int call_status;
-
- if (hwirq == XICS_IPI)
- return;
-
- call_status = rtas_call(ibm_int_off, 1, 1, NULL, hwirq);
- if (call_status != 0) {
- printk(KERN_ERR "%s: ibm_int_off irq=%u returned %d\n",
- __func__, hwirq, call_status);
- return;
- }
-
- /* Have to set XIVE to 0xff to be able to remove a slot */
- call_status = rtas_call(ibm_set_xive, 3, 1, NULL, hwirq,
- default_server, 0xff);
- if (call_status != 0) {
- printk(KERN_ERR "%s: ibm_set_xive(0xff) irq=%u returned %d\n",
- __func__, hwirq, call_status);
- return;
- }
-}
-
-static void xics_mask_irq(struct irq_data *d)
-{
- unsigned int hwirq;
-
- pr_devel("xics: mask virq %d\n", d->irq);
-
- hwirq = (unsigned int)irq_map[d->irq].hwirq;
- if (hwirq == XICS_IPI || hwirq == XICS_IRQ_SPURIOUS)
- return;
- xics_mask_real_irq(hwirq);
-}
-
-static void xics_mask_unknown_vec(unsigned int vec)
-{
- printk(KERN_ERR "Interrupt %u (real) is invalid, disabling it.\n", vec);
- xics_mask_real_irq(vec);
-}
-
-static inline unsigned int xics_xirr_vector(unsigned int xirr)
-{
- /*
- * The top byte is the old cppr, to be restored on EOI.
- * The remaining 24 bits are the vector.
- */
- return xirr & 0x00ffffff;
-}
-
-static void push_cppr(unsigned int vec)
-{
- struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr);
-
- if (WARN_ON(os_cppr->index >= MAX_NUM_PRIORITIES - 1))
- return;
-
- if (vec == XICS_IPI)
- os_cppr->stack[++os_cppr->index] = IPI_PRIORITY;
- else
- os_cppr->stack[++os_cppr->index] = DEFAULT_PRIORITY;
-}
-
-static unsigned int xics_get_irq_direct(void)
-{
- unsigned int xirr = direct_xirr_info_get();
- unsigned int vec = xics_xirr_vector(xirr);
- unsigned int irq;
-
- if (vec == XICS_IRQ_SPURIOUS)
- return NO_IRQ;
-
- irq = irq_radix_revmap_lookup(xics_host, vec);
- if (likely(irq != NO_IRQ)) {
- push_cppr(vec);
- return irq;
- }
-
- /* We don't have a linux mapping, so have rtas mask it. */
- xics_mask_unknown_vec(vec);
-
- /* We might learn about it later, so EOI it */
- direct_xirr_info_set(xirr);
- return NO_IRQ;
-}
-
-static unsigned int xics_get_irq_lpar(void)
-{
- struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr);
- unsigned int xirr = lpar_xirr_info_get(os_cppr->stack[os_cppr->index]);
- unsigned int vec = xics_xirr_vector(xirr);
- unsigned int irq;
-
- if (vec == XICS_IRQ_SPURIOUS)
- return NO_IRQ;
-
- irq = irq_radix_revmap_lookup(xics_host, vec);
- if (likely(irq != NO_IRQ)) {
- push_cppr(vec);
- return irq;
- }
-
- /* We don't have a linux mapping, so have RTAS mask it. */
- xics_mask_unknown_vec(vec);
-
- /* We might learn about it later, so EOI it */
- lpar_xirr_info_set(xirr);
- return NO_IRQ;
-}
-
-static unsigned char pop_cppr(void)
-{
- struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr);
-
- if (WARN_ON(os_cppr->index < 1))
- return LOWEST_PRIORITY;
-
- return os_cppr->stack[--os_cppr->index];
-}
-
-static void xics_eoi_direct(struct irq_data *d)
-{
- unsigned int hwirq = (unsigned int)irq_map[d->irq].hwirq;
-
- iosync();
- direct_xirr_info_set((pop_cppr() << 24) | hwirq);
-}
-
-static void xics_eoi_lpar(struct irq_data *d)
-{
- unsigned int hwirq = (unsigned int)irq_map[d->irq].hwirq;
-
- iosync();
- lpar_xirr_info_set((pop_cppr() << 24) | hwirq);
-}
-
-static int
-xics_set_affinity(struct irq_data *d, const struct cpumask *cpumask, bool force)
-{
- unsigned int hwirq;
- int status;
- int xics_status[2];
- int irq_server;
-
- hwirq = (unsigned int)irq_map[d->irq].hwirq;
- if (hwirq == XICS_IPI || hwirq == XICS_IRQ_SPURIOUS)
- return -1;
-
- status = rtas_call(ibm_get_xive, 1, 3, xics_status, hwirq);
-
- if (status) {
- printk(KERN_ERR "%s: ibm,get-xive irq=%u returns %d\n",
- __func__, hwirq, status);
- return -1;
- }
-
- irq_server = get_irq_server(d->irq, cpumask, 1);
- if (irq_server == -1) {
- char cpulist[128];
- cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask);
- printk(KERN_WARNING
- "%s: No online cpus in the mask %s for irq %d\n",
- __func__, cpulist, d->irq);
- return -1;
- }
-
- status = rtas_call(ibm_set_xive, 3, 1, NULL,
- hwirq, irq_server, xics_status[1]);
-
- if (status) {
- printk(KERN_ERR "%s: ibm,set-xive irq=%u returns %d\n",
- __func__, hwirq, status);
- return -1;
- }
-
- return 0;
-}
-
-static struct irq_chip xics_pic_direct = {
- .name = "XICS",
- .irq_startup = xics_startup,
- .irq_mask = xics_mask_irq,
- .irq_unmask = xics_unmask_irq,
- .irq_eoi = xics_eoi_direct,
- .irq_set_affinity = xics_set_affinity
-};
-
-static struct irq_chip xics_pic_lpar = {
- .name = "XICS",
- .irq_startup = xics_startup,
- .irq_mask = xics_mask_irq,
- .irq_unmask = xics_unmask_irq,
- .irq_eoi = xics_eoi_lpar,
- .irq_set_affinity = xics_set_affinity
-};
-
-
-/* Interface to arch irq controller subsystem layer */
-
-/* Points to the irq_chip we're actually using */
-static struct irq_chip *xics_irq_chip;
-
-static int xics_host_match(struct irq_host *h, struct device_node *node)
-{
- /* IBM machines have interrupt parents of various funky types for things
- * like vdevices, events, etc... The trick we use here is to match
- * everything here except the legacy 8259 which is compatible "chrp,iic"
- */
- return !of_device_is_compatible(node, "chrp,iic");
-}
-
-static int xics_host_map(struct irq_host *h, unsigned int virq,
- irq_hw_number_t hw)
-{
- pr_devel("xics: map virq %d, hwirq 0x%lx\n", virq, hw);
-
- /* Insert the interrupt mapping into the radix tree for fast lookup */
- irq_radix_revmap_insert(xics_host, virq, hw);
-
- irq_set_status_flags(virq, IRQ_LEVEL);
- irq_set_chip_and_handler(virq, xics_irq_chip, handle_fasteoi_irq);
- return 0;
-}
-
-static int xics_host_xlate(struct irq_host *h, struct device_node *ct,
- const u32 *intspec, unsigned int intsize,
- irq_hw_number_t *out_hwirq, unsigned int *out_flags)
-
-{
- /* Current xics implementation translates everything
- * to level. It is not technically right for MSIs but this
- * is irrelevant at this point. We might get smarter in the future
- */
- *out_hwirq = intspec[0];
- *out_flags = IRQ_TYPE_LEVEL_LOW;
-
- return 0;
-}
-
-static struct irq_host_ops xics_host_ops = {
- .match = xics_host_match,
- .map = xics_host_map,
- .xlate = xics_host_xlate,
-};
-
-static void __init xics_init_host(void)
-{
- if (firmware_has_feature(FW_FEATURE_LPAR))
- xics_irq_chip = &xics_pic_lpar;
- else
- xics_irq_chip = &xics_pic_direct;
-
- xics_host = irq_alloc_host(NULL, IRQ_HOST_MAP_TREE, 0, &xics_host_ops,
- XICS_IRQ_SPURIOUS);
- BUG_ON(xics_host == NULL);
- irq_set_default_host(xics_host);
-}
-
-
-/* Inter-processor interrupt support */
-
-#ifdef CONFIG_SMP
-/*
- * XICS only has a single IPI, so encode the messages per CPU
- */
-static DEFINE_PER_CPU_SHARED_ALIGNED(unsigned long, xics_ipi_message);
-
-static inline void smp_xics_do_message(int cpu, int msg)
-{
- unsigned long *tgt = &per_cpu(xics_ipi_message, cpu);
-
- set_bit(msg, tgt);
- mb();
- if (firmware_has_feature(FW_FEATURE_LPAR))
- lpar_qirr_info(cpu, IPI_PRIORITY);
- else
- direct_qirr_info(cpu, IPI_PRIORITY);
-}
-
-void smp_xics_message_pass(int target, int msg)
-{
- unsigned int i;
-
- if (target < NR_CPUS) {
- smp_xics_do_message(target, msg);
- } else {
- for_each_online_cpu(i) {
- if (target == MSG_ALL_BUT_SELF
- && i == smp_processor_id())
- continue;
- smp_xics_do_message(i, msg);
- }
- }
-}
-
-static irqreturn_t xics_ipi_dispatch(int cpu)
-{
- unsigned long *tgt = &per_cpu(xics_ipi_message, cpu);
-
- mb(); /* order mmio clearing qirr */
- while (*tgt) {
- if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, tgt)) {
- smp_message_recv(PPC_MSG_CALL_FUNCTION);
- }
- if (test_and_clear_bit(PPC_MSG_RESCHEDULE, tgt)) {
- smp_message_recv(PPC_MSG_RESCHEDULE);
- }
- if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE, tgt)) {
- smp_message_recv(PPC_MSG_CALL_FUNC_SINGLE);
- }
-#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
- if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, tgt)) {
- smp_message_recv(PPC_MSG_DEBUGGER_BREAK);
- }
-#endif
- }
- return IRQ_HANDLED;
-}
-
-static irqreturn_t xics_ipi_action_direct(int irq, void *dev_id)
-{
- int cpu = smp_processor_id();
-
- direct_qirr_info(cpu, 0xff);
-
- return xics_ipi_dispatch(cpu);
-}
-
-static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id)
-{
- int cpu = smp_processor_id();
-
- lpar_qirr_info(cpu, 0xff);
-
- return xics_ipi_dispatch(cpu);
-}
-
-static void xics_request_ipi(void)
-{
- unsigned int ipi;
- int rc;
-
- ipi = irq_create_mapping(xics_host, XICS_IPI);
- BUG_ON(ipi == NO_IRQ);
-
- /*
- * IPIs are marked IRQF_DISABLED as they must run with irqs
- * disabled
- */
- irq_set_handler(ipi, handle_percpu_irq);
- if (firmware_has_feature(FW_FEATURE_LPAR))
- rc = request_irq(ipi, xics_ipi_action_lpar,
- IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL);
- else
- rc = request_irq(ipi, xics_ipi_action_direct,
- IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL);
- BUG_ON(rc);
-}
-
-int __init smp_xics_probe(void)
-{
- xics_request_ipi();
-
- return cpumask_weight(cpu_possible_mask);
-}
-
-#endif /* CONFIG_SMP */
-
-
-/* Initialization */
-
-static void xics_update_irq_servers(void)
-{
- int i, j;
- struct device_node *np;
- u32 ilen;
- const u32 *ireg;
- u32 hcpuid;
-
- /* Find the server numbers for the boot cpu. */
- np = of_get_cpu_node(boot_cpuid, NULL);
- BUG_ON(!np);
-
- ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
- if (!ireg) {
- of_node_put(np);
- return;
- }
-
- i = ilen / sizeof(int);
- hcpuid = get_hard_smp_processor_id(boot_cpuid);
-
- /* Global interrupt distribution server is specified in the last
- * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last
- * entry fom this property for current boot cpu id and use it as
- * default distribution server
- */
- for (j = 0; j < i; j += 2) {
- if (ireg[j] == hcpuid) {
- default_server = hcpuid;
- default_distrib_server = ireg[j+1];
- }
- }
-
- of_node_put(np);
-}
-
-static void __init xics_map_one_cpu(int hw_id, unsigned long addr,
- unsigned long size)
-{
- int i;
-
- /* This may look gross but it's good enough for now, we don't quite
- * have a hard -> linux processor id matching.
- */
- for_each_possible_cpu(i) {
- if (!cpu_present(i))
- continue;
- if (hw_id == get_hard_smp_processor_id(i)) {
- xics_per_cpu[i] = ioremap(addr, size);
- return;
- }
- }
-}
-
-static void __init xics_init_one_node(struct device_node *np,
- unsigned int *indx)
-{
- unsigned int ilen;
- const u32 *ireg;
-
- /* This code does the theorically broken assumption that the interrupt
- * server numbers are the same as the hard CPU numbers.
- * This happens to be the case so far but we are playing with fire...
- * should be fixed one of these days. -BenH.
- */
- ireg = of_get_property(np, "ibm,interrupt-server-ranges", NULL);
-
- /* Do that ever happen ? we'll know soon enough... but even good'old
- * f80 does have that property ..
- */
- WARN_ON(ireg == NULL);
- if (ireg) {
- /*
- * set node starting index for this node
- */
- *indx = *ireg;
- }
- ireg = of_get_property(np, "reg", &ilen);
- if (!ireg)
- panic("xics_init_IRQ: can't find interrupt reg property");
-
- while (ilen >= (4 * sizeof(u32))) {
- unsigned long addr, size;
-
- /* XXX Use proper OF parsing code here !!! */
- addr = (unsigned long)*ireg++ << 32;
- ilen -= sizeof(u32);
- addr |= *ireg++;
- ilen -= sizeof(u32);
- size = (unsigned long)*ireg++ << 32;
- ilen -= sizeof(u32);
- size |= *ireg++;
- ilen -= sizeof(u32);
- xics_map_one_cpu(*indx, addr, size);
- (*indx)++;
- }
-}
-
-void __init xics_init_IRQ(void)
-{
- struct device_node *np;
- u32 indx = 0;
- int found = 0;
- const u32 *isize;
-
- ppc64_boot_msg(0x20, "XICS Init");
-
- ibm_get_xive = rtas_token("ibm,get-xive");
- ibm_set_xive = rtas_token("ibm,set-xive");
- ibm_int_on = rtas_token("ibm,int-on");
- ibm_int_off = rtas_token("ibm,int-off");
-
- for_each_node_by_type(np, "PowerPC-External-Interrupt-Presentation") {
- found = 1;
- if (firmware_has_feature(FW_FEATURE_LPAR)) {
- of_node_put(np);
- break;
- }
- xics_init_one_node(np, &indx);
- }
- if (found == 0)
- return;
-
- /* get the bit size of server numbers */
- found = 0;
-
- for_each_compatible_node(np, NULL, "ibm,ppc-xics") {
- isize = of_get_property(np, "ibm,interrupt-server#-size", NULL);
-
- if (!isize)
- continue;
-
- if (!found) {
- interrupt_server_size = *isize;
- found = 1;
- } else if (*isize != interrupt_server_size) {
- printk(KERN_WARNING "XICS: "
- "mismatched ibm,interrupt-server#-size\n");
- interrupt_server_size = max(*isize,
- interrupt_server_size);
- }
- }
-
- xics_update_irq_servers();
- xics_init_host();
-
- if (firmware_has_feature(FW_FEATURE_LPAR))
- ppc_md.get_irq = xics_get_irq_lpar;
- else
- ppc_md.get_irq = xics_get_irq_direct;
-
- xics_setup_cpu();
-
- ppc64_boot_msg(0x21, "XICS Done");
-}
-
-/* Cpu startup, shutdown, and hotplug */
-
-static void xics_set_cpu_priority(unsigned char cppr)
-{
- struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr);
-
- /*
- * we only really want to set the priority when there's
- * just one cppr value on the stack
- */
- WARN_ON(os_cppr->index != 0);
-
- os_cppr->stack[0] = cppr;
-
- if (firmware_has_feature(FW_FEATURE_LPAR))
- lpar_cppr_info(cppr);
- else
- direct_cppr_info(cppr);
- iosync();
-}
-
-/* Have the calling processor join or leave the specified global queue */
-static void xics_set_cpu_giq(unsigned int gserver, unsigned int join)
-{
- int index;
- int status;
-
- if (!rtas_indicator_present(GLOBAL_INTERRUPT_QUEUE, NULL))
- return;
-
- index = (1UL << interrupt_server_size) - 1 - gserver;
-
- status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE, index, join);
-
- WARN(status < 0, "set-indicator(%d, %d, %u) returned %d\n",
- GLOBAL_INTERRUPT_QUEUE, index, join, status);
-}
-
-void xics_setup_cpu(void)
-{
- xics_set_cpu_priority(LOWEST_PRIORITY);
-
- xics_set_cpu_giq(default_distrib_server, 1);
-}
-
-void xics_teardown_cpu(void)
-{
- struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr);
- int cpu = smp_processor_id();
-
- /*
- * we have to reset the cppr index to 0 because we're
- * not going to return from the IPI
- */
- os_cppr->index = 0;
- xics_set_cpu_priority(0);
-
- /* Clear any pending IPI request */
- if (firmware_has_feature(FW_FEATURE_LPAR))
- lpar_qirr_info(cpu, 0xff);
- else
- direct_qirr_info(cpu, 0xff);
-}
-
-void xics_kexec_teardown_cpu(int secondary)
-{
- xics_teardown_cpu();
-
- /*
- * we take the ipi irq but and never return so we
- * need to EOI the IPI, but want to leave our priority 0
- *
- * should we check all the other interrupts too?
- * should we be flagging idle loop instead?
- * or creating some task to be scheduled?
- */
-
- if (firmware_has_feature(FW_FEATURE_LPAR))
- lpar_xirr_info_set((0x00 << 24) | XICS_IPI);
- else
- direct_xirr_info_set((0x00 << 24) | XICS_IPI);
-
- /*
- * Some machines need to have at least one cpu in the GIQ,
- * so leave the master cpu in the group.
- */
- if (secondary)
- xics_set_cpu_giq(default_distrib_server, 0);
-}
-
-#ifdef CONFIG_HOTPLUG_CPU
-
-/* Interrupts are disabled. */
-void xics_migrate_irqs_away(void)
-{
- int cpu = smp_processor_id(), hw_cpu = hard_smp_processor_id();
- int virq;
-
- /* If we used to be the default server, move to the new "boot_cpuid" */
- if (hw_cpu == default_server)
- xics_update_irq_servers();
-
- /* Reject any interrupt that was queued to us... */
- xics_set_cpu_priority(0);
-
- /* Remove ourselves from the global interrupt queue */
- xics_set_cpu_giq(default_distrib_server, 0);
-
- /* Allow IPIs again... */
- xics_set_cpu_priority(DEFAULT_PRIORITY);
-
- for_each_irq(virq) {
- struct irq_desc *desc;
- struct irq_chip *chip;
- unsigned int hwirq;
- int xics_status[2];
- int status;
- unsigned long flags;
-
- /* We can't set affinity on ISA interrupts */
- if (virq < NUM_ISA_INTERRUPTS)
- continue;
- if (irq_map[virq].host != xics_host)
- continue;
- hwirq = (unsigned int)irq_map[virq].hwirq;
- /* We need to get IPIs still. */
- if (hwirq == XICS_IPI || hwirq == XICS_IRQ_SPURIOUS)
- continue;
-
- desc = irq_to_desc(virq);
-
- /* We only need to migrate enabled IRQS */
- if (desc == NULL || desc->action == NULL)
- continue;
-
- chip = irq_desc_get_chip(desc);
- if (chip == NULL || chip->irq_set_affinity == NULL)
- continue;
-
- raw_spin_lock_irqsave(&desc->lock, flags);
-
- status = rtas_call(ibm_get_xive, 1, 3, xics_status, hwirq);
- if (status) {
- printk(KERN_ERR "%s: ibm,get-xive irq=%u returns %d\n",
- __func__, hwirq, status);
- goto unlock;
- }
-
- /*
- * We only support delivery to all cpus or to one cpu.
- * The irq has to be migrated only in the single cpu
- * case.
- */
- if (xics_status[0] != hw_cpu)
- goto unlock;
-
- /* This is expected during cpu offline. */
- if (cpu_online(cpu))
- printk(KERN_WARNING "IRQ %u affinity broken off cpu %u\n",
- virq, cpu);
-
- /* Reset affinity to all cpus */
- cpumask_setall(desc->irq_data.affinity);
- chip->irq_set_affinity(&desc->irq_data, cpu_all_mask, true);
-unlock:
- raw_spin_unlock_irqrestore(&desc->lock, flags);
- }
-}
-#endif
diff --git a/arch/powerpc/platforms/pseries/xics.h b/arch/powerpc/platforms/pseries/xics.h
deleted file mode 100644
index d1d5a83039ae..000000000000
--- a/arch/powerpc/platforms/pseries/xics.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * arch/powerpc/platforms/pseries/xics.h
- *
- * Copyright 2000 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.
- */
-
-#ifndef _POWERPC_KERNEL_XICS_H
-#define _POWERPC_KERNEL_XICS_H
-
-extern void xics_init_IRQ(void);
-extern void xics_setup_cpu(void);
-extern void xics_teardown_cpu(void);
-extern void xics_kexec_teardown_cpu(int secondary);
-extern void xics_migrate_irqs_away(void);
-extern int smp_xics_probe(void);
-extern void smp_xics_message_pass(int target, int msg);
-
-#endif /* _POWERPC_KERNEL_XICS_H */
diff --git a/arch/powerpc/platforms/wsp/Kconfig b/arch/powerpc/platforms/wsp/Kconfig
new file mode 100644
index 000000000000..c3c48eb62cc1
--- /dev/null
+++ b/arch/powerpc/platforms/wsp/Kconfig
@@ -0,0 +1,28 @@
+config PPC_WSP
+ bool
+ default n
+
+menu "WSP platform selection"
+ depends on PPC_BOOK3E_64
+
+config PPC_PSR2
+ bool "PSR-2 platform"
+ select PPC_A2
+ select GENERIC_TBSYNC
+ select PPC_SCOM
+ select EPAPR_BOOT
+ select PPC_WSP
+ select PPC_XICS
+ select PPC_ICP_NATIVE
+ default y
+
+endmenu
+
+config PPC_A2_DD2
+ bool "Support for DD2 based A2/WSP systems"
+ depends on PPC_A2
+
+config WORKAROUND_ERRATUM_463
+ depends on PPC_A2_DD2
+ bool "Workaround erratum 463"
+ default y
diff --git a/arch/powerpc/platforms/wsp/Makefile b/arch/powerpc/platforms/wsp/Makefile
new file mode 100644
index 000000000000..095be73d6cd4
--- /dev/null
+++ b/arch/powerpc/platforms/wsp/Makefile
@@ -0,0 +1,6 @@
+ccflags-y += -mno-minimal-toc
+
+obj-y += setup.o ics.o
+obj-$(CONFIG_PPC_PSR2) += psr2.o opb_pic.o
+obj-$(CONFIG_PPC_WSP) += scom_wsp.o
+obj-$(CONFIG_SMP) += smp.o scom_smp.o
diff --git a/arch/powerpc/platforms/wsp/ics.c b/arch/powerpc/platforms/wsp/ics.c
new file mode 100644
index 000000000000..e53bd9e7b125
--- /dev/null
+++ b/arch/powerpc/platforms/wsp/ics.c
@@ -0,0 +1,712 @@
+/*
+ * Copyright 2008-2011 IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/cpu.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/msi.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/xics.h>
+
+#include "wsp.h"
+#include "ics.h"
+
+
+/* WSP ICS */
+
+struct wsp_ics {
+ struct ics ics;
+ struct device_node *dn;
+ void __iomem *regs;
+ spinlock_t lock;
+ unsigned long *bitmap;
+ u32 chip_id;
+ u32 lsi_base;
+ u32 lsi_count;
+ u64 hwirq_start;
+ u64 count;
+#ifdef CONFIG_SMP
+ int *hwirq_cpu_map;
+#endif
+};
+
+#define to_wsp_ics(ics) container_of(ics, struct wsp_ics, ics)
+
+#define INT_SRC_LAYER_BUID_REG(base) ((base) + 0x00)
+#define IODA_TBL_ADDR_REG(base) ((base) + 0x18)
+#define IODA_TBL_DATA_REG(base) ((base) + 0x20)
+#define XIVE_UPDATE_REG(base) ((base) + 0x28)
+#define ICS_INT_CAPS_REG(base) ((base) + 0x30)
+
+#define TBL_AUTO_INCREMENT ((1UL << 63) | (1UL << 15))
+#define TBL_SELECT_XIST (1UL << 48)
+#define TBL_SELECT_XIVT (1UL << 49)
+
+#define IODA_IRQ(irq) ((irq) & (0x7FFULL)) /* HRM 5.1.3.4 */
+
+#define XIST_REQUIRED 0x8
+#define XIST_REJECTED 0x4
+#define XIST_PRESENTED 0x2
+#define XIST_PENDING 0x1
+
+#define XIVE_SERVER_SHIFT 42
+#define XIVE_SERVER_MASK 0xFFFFULL
+#define XIVE_PRIORITY_MASK 0xFFULL
+#define XIVE_PRIORITY_SHIFT 32
+#define XIVE_WRITE_ENABLE (1ULL << 63)
+
+/*
+ * The docs refer to a 6 bit field called ChipID, which consists of a
+ * 3 bit NodeID and a 3 bit ChipID. On WSP the ChipID is always zero
+ * so we ignore it, and every where we use "chip id" in this code we
+ * mean the NodeID.
+ */
+#define WSP_ICS_CHIP_SHIFT 17
+
+
+static struct wsp_ics *ics_list;
+static int num_ics;
+
+/* ICS Source controller accessors */
+
+static u64 wsp_ics_get_xive(struct wsp_ics *ics, unsigned int irq)
+{
+ unsigned long flags;
+ u64 xive;
+
+ spin_lock_irqsave(&ics->lock, flags);
+ out_be64(IODA_TBL_ADDR_REG(ics->regs), TBL_SELECT_XIVT | IODA_IRQ(irq));
+ xive = in_be64(IODA_TBL_DATA_REG(ics->regs));
+ spin_unlock_irqrestore(&ics->lock, flags);
+
+ return xive;
+}
+
+static void wsp_ics_set_xive(struct wsp_ics *ics, unsigned int irq, u64 xive)
+{
+ xive &= ~XIVE_ADDR_MASK;
+ xive |= (irq & XIVE_ADDR_MASK);
+ xive |= XIVE_WRITE_ENABLE;
+
+ out_be64(XIVE_UPDATE_REG(ics->regs), xive);
+}
+
+static u64 xive_set_server(u64 xive, unsigned int server)
+{
+ u64 mask = ~(XIVE_SERVER_MASK << XIVE_SERVER_SHIFT);
+
+ xive &= mask;
+ xive |= (server & XIVE_SERVER_MASK) << XIVE_SERVER_SHIFT;
+
+ return xive;
+}
+
+static u64 xive_set_priority(u64 xive, unsigned int priority)
+{
+ u64 mask = ~(XIVE_PRIORITY_MASK << XIVE_PRIORITY_SHIFT);
+
+ xive &= mask;
+ xive |= (priority & XIVE_PRIORITY_MASK) << XIVE_PRIORITY_SHIFT;
+
+ return xive;
+}
+
+
+#ifdef CONFIG_SMP
+/* Find logical CPUs within mask on a given chip and store result in ret */
+void cpus_on_chip(int chip_id, cpumask_t *mask, cpumask_t *ret)
+{
+ int cpu, chip;
+ struct device_node *cpu_dn, *dn;
+ const u32 *prop;
+
+ cpumask_clear(ret);
+ for_each_cpu(cpu, mask) {
+ cpu_dn = of_get_cpu_node(cpu, NULL);
+ if (!cpu_dn)
+ continue;
+
+ prop = of_get_property(cpu_dn, "at-node", NULL);
+ if (!prop) {
+ of_node_put(cpu_dn);
+ continue;
+ }
+
+ dn = of_find_node_by_phandle(*prop);
+ of_node_put(cpu_dn);
+
+ chip = wsp_get_chip_id(dn);
+ if (chip == chip_id)
+ cpumask_set_cpu(cpu, ret);
+
+ of_node_put(dn);
+ }
+}
+
+/* Store a suitable CPU to handle a hwirq in the ics->hwirq_cpu_map cache */
+static int cache_hwirq_map(struct wsp_ics *ics, unsigned int hwirq,
+ const cpumask_t *affinity)
+{
+ cpumask_var_t avail, newmask;
+ int ret = -ENOMEM, cpu, cpu_rover = 0, target;
+ int index = hwirq - ics->hwirq_start;
+ unsigned int nodeid;
+
+ BUG_ON(index < 0 || index >= ics->count);
+
+ if (!ics->hwirq_cpu_map)
+ return -ENOMEM;
+
+ if (!distribute_irqs) {
+ ics->hwirq_cpu_map[hwirq - ics->hwirq_start] = xics_default_server;
+ return 0;
+ }
+
+ /* Allocate needed CPU masks */
+ if (!alloc_cpumask_var(&avail, GFP_KERNEL))
+ goto ret;
+ if (!alloc_cpumask_var(&newmask, GFP_KERNEL))
+ goto freeavail;
+
+ /* Find PBus attached to the source of this IRQ */
+ nodeid = (hwirq >> WSP_ICS_CHIP_SHIFT) & 0x3; /* 12:14 */
+
+ /* Find CPUs that could handle this IRQ */
+ if (affinity)
+ cpumask_and(avail, cpu_online_mask, affinity);
+ else
+ cpumask_copy(avail, cpu_online_mask);
+
+ /* Narrow selection down to logical CPUs on the same chip */
+ cpus_on_chip(nodeid, avail, newmask);
+
+ /* Ensure we haven't narrowed it down to 0 */
+ if (unlikely(cpumask_empty(newmask))) {
+ if (unlikely(cpumask_empty(avail))) {
+ ret = -1;
+ goto out;
+ }
+ cpumask_copy(newmask, avail);
+ }
+
+ /* Choose a CPU out of those we narrowed it down to in round robin */
+ target = hwirq % cpumask_weight(newmask);
+ for_each_cpu(cpu, newmask) {
+ if (cpu_rover++ >= target) {
+ ics->hwirq_cpu_map[index] = get_hard_smp_processor_id(cpu);
+ ret = 0;
+ goto out;
+ }
+ }
+
+ /* Shouldn't happen */
+ WARN_ON(1);
+
+out:
+ free_cpumask_var(newmask);
+freeavail:
+ free_cpumask_var(avail);
+ret:
+ if (ret < 0) {
+ ics->hwirq_cpu_map[index] = cpumask_first(cpu_online_mask);
+ pr_warning("Error, falling hwirq 0x%x routing back to CPU %i\n",
+ hwirq, ics->hwirq_cpu_map[index]);
+ }
+ return ret;
+}
+
+static void alloc_irq_map(struct wsp_ics *ics)
+{
+ int i;
+
+ ics->hwirq_cpu_map = kmalloc(sizeof(int) * ics->count, GFP_KERNEL);
+ if (!ics->hwirq_cpu_map) {
+ pr_warning("Allocate hwirq_cpu_map failed, "
+ "IRQ balancing disabled\n");
+ return;
+ }
+
+ for (i=0; i < ics->count; i++)
+ ics->hwirq_cpu_map[i] = xics_default_server;
+}
+
+static int get_irq_server(struct wsp_ics *ics, unsigned int hwirq)
+{
+ int index = hwirq - ics->hwirq_start;
+
+ BUG_ON(index < 0 || index >= ics->count);
+
+ if (!ics->hwirq_cpu_map)
+ return xics_default_server;
+
+ return ics->hwirq_cpu_map[index];
+}
+#else /* !CONFIG_SMP */
+static int cache_hwirq_map(struct wsp_ics *ics, unsigned int hwirq,
+ const cpumask_t *affinity)
+{
+ return 0;
+}
+
+static int get_irq_server(struct wsp_ics *ics, unsigned int hwirq)
+{
+ return xics_default_server;
+}
+
+static void alloc_irq_map(struct wsp_ics *ics) { }
+#endif
+
+static void wsp_chip_unmask_irq(struct irq_data *d)
+{
+ unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
+ struct wsp_ics *ics;
+ int server;
+ u64 xive;
+
+ if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)
+ return;
+
+ ics = d->chip_data;
+ if (WARN_ON(!ics))
+ return;
+
+ server = get_irq_server(ics, hw_irq);
+
+ xive = wsp_ics_get_xive(ics, hw_irq);
+ xive = xive_set_server(xive, server);
+ xive = xive_set_priority(xive, DEFAULT_PRIORITY);
+ wsp_ics_set_xive(ics, hw_irq, xive);
+}
+
+static unsigned int wsp_chip_startup(struct irq_data *d)
+{
+ /* unmask it */
+ wsp_chip_unmask_irq(d);
+ return 0;
+}
+
+static void wsp_mask_real_irq(unsigned int hw_irq, struct wsp_ics *ics)
+{
+ u64 xive;
+
+ if (hw_irq == XICS_IPI)
+ return;
+
+ if (WARN_ON(!ics))
+ return;
+ xive = wsp_ics_get_xive(ics, hw_irq);
+ xive = xive_set_server(xive, xics_default_server);
+ xive = xive_set_priority(xive, LOWEST_PRIORITY);
+ wsp_ics_set_xive(ics, hw_irq, xive);
+}
+
+static void wsp_chip_mask_irq(struct irq_data *d)
+{
+ unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
+ struct wsp_ics *ics = d->chip_data;
+
+ if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)
+ return;
+
+ wsp_mask_real_irq(hw_irq, ics);
+}
+
+static int wsp_chip_set_affinity(struct irq_data *d,
+ const struct cpumask *cpumask, bool force)
+{
+ unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
+ struct wsp_ics *ics;
+ int ret;
+ u64 xive;
+
+ if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)
+ return -1;
+
+ ics = d->chip_data;
+ if (WARN_ON(!ics))
+ return -1;
+ xive = wsp_ics_get_xive(ics, hw_irq);
+
+ /*
+ * For the moment only implement delivery to all cpus or one cpu.
+ * Get current irq_server for the given irq
+ */
+ ret = cache_hwirq_map(ics, d->irq, cpumask);
+ if (ret == -1) {
+ char cpulist[128];
+ cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask);
+ pr_warning("%s: No online cpus in the mask %s for irq %d\n",
+ __func__, cpulist, d->irq);
+ return -1;
+ } else if (ret == -ENOMEM) {
+ pr_warning("%s: Out of memory\n", __func__);
+ return -1;
+ }
+
+ xive = xive_set_server(xive, get_irq_server(ics, hw_irq));
+ wsp_ics_set_xive(ics, hw_irq, xive);
+
+ return 0;
+}
+
+static struct irq_chip wsp_irq_chip = {
+ .name = "WSP ICS",
+ .irq_startup = wsp_chip_startup,
+ .irq_mask = wsp_chip_mask_irq,
+ .irq_unmask = wsp_chip_unmask_irq,
+ .irq_set_affinity = wsp_chip_set_affinity
+};
+
+static int wsp_ics_host_match(struct ics *ics, struct device_node *dn)
+{
+ /* All ICSs in the system implement a global irq number space,
+ * so match against them all. */
+ return of_device_is_compatible(dn, "ibm,ppc-xics");
+}
+
+static int wsp_ics_match_hwirq(struct wsp_ics *wsp_ics, unsigned int hwirq)
+{
+ if (hwirq >= wsp_ics->hwirq_start &&
+ hwirq < wsp_ics->hwirq_start + wsp_ics->count)
+ return 1;
+
+ return 0;
+}
+
+static int wsp_ics_map(struct ics *ics, unsigned int virq)
+{
+ struct wsp_ics *wsp_ics = to_wsp_ics(ics);
+ unsigned int hw_irq = virq_to_hw(virq);
+ unsigned long flags;
+
+ if (!wsp_ics_match_hwirq(wsp_ics, hw_irq))
+ return -ENOENT;
+
+ irq_set_chip_and_handler(virq, &wsp_irq_chip, handle_fasteoi_irq);
+
+ irq_set_chip_data(virq, wsp_ics);
+
+ spin_lock_irqsave(&wsp_ics->lock, flags);
+ bitmap_allocate_region(wsp_ics->bitmap, hw_irq - wsp_ics->hwirq_start, 0);
+ spin_unlock_irqrestore(&wsp_ics->lock, flags);
+
+ return 0;
+}
+
+static void wsp_ics_mask_unknown(struct ics *ics, unsigned long hw_irq)
+{
+ struct wsp_ics *wsp_ics = to_wsp_ics(ics);
+
+ if (!wsp_ics_match_hwirq(wsp_ics, hw_irq))
+ return;
+
+ pr_err("%s: IRQ %lu (real) is invalid, disabling it.\n", __func__, hw_irq);
+ wsp_mask_real_irq(hw_irq, wsp_ics);
+}
+
+static long wsp_ics_get_server(struct ics *ics, unsigned long hw_irq)
+{
+ struct wsp_ics *wsp_ics = to_wsp_ics(ics);
+
+ if (!wsp_ics_match_hwirq(wsp_ics, hw_irq))
+ return -ENOENT;
+
+ return get_irq_server(wsp_ics, hw_irq);
+}
+
+/* HW Number allocation API */
+
+static struct wsp_ics *wsp_ics_find_dn_ics(struct device_node *dn)
+{
+ struct device_node *iparent;
+ int i;
+
+ iparent = of_irq_find_parent(dn);
+ if (!iparent) {
+ pr_err("wsp_ics: Failed to find interrupt parent!\n");
+ return NULL;
+ }
+
+ for(i = 0; i < num_ics; i++) {
+ if(ics_list[i].dn == iparent)
+ break;
+ }
+
+ if (i >= num_ics) {
+ pr_err("wsp_ics: Unable to find parent bitmap!\n");
+ return NULL;
+ }
+
+ return &ics_list[i];
+}
+
+int wsp_ics_alloc_irq(struct device_node *dn, int num)
+{
+ struct wsp_ics *ics;
+ int order, offset;
+
+ ics = wsp_ics_find_dn_ics(dn);
+ if (!ics)
+ return -ENODEV;
+
+ /* Fast, but overly strict if num isn't a power of two */
+ order = get_count_order(num);
+
+ spin_lock_irq(&ics->lock);
+ offset = bitmap_find_free_region(ics->bitmap, ics->count, order);
+ spin_unlock_irq(&ics->lock);
+
+ if (offset < 0)
+ return offset;
+
+ return offset + ics->hwirq_start;
+}
+
+void wsp_ics_free_irq(struct device_node *dn, unsigned int irq)
+{
+ struct wsp_ics *ics;
+
+ ics = wsp_ics_find_dn_ics(dn);
+ if (WARN_ON(!ics))
+ return;
+
+ spin_lock_irq(&ics->lock);
+ bitmap_release_region(ics->bitmap, irq, 0);
+ spin_unlock_irq(&ics->lock);
+}
+
+/* Initialisation */
+
+static int __init wsp_ics_bitmap_setup(struct wsp_ics *ics,
+ struct device_node *dn)
+{
+ int len, i, j, size;
+ u32 start, count;
+ const u32 *p;
+
+ size = BITS_TO_LONGS(ics->count) * sizeof(long);
+ ics->bitmap = kzalloc(size, GFP_KERNEL);
+ if (!ics->bitmap) {
+ pr_err("wsp_ics: ENOMEM allocating IRQ bitmap!\n");
+ return -ENOMEM;
+ }
+
+ spin_lock_init(&ics->lock);
+
+ p = of_get_property(dn, "available-ranges", &len);
+ if (!p || !len) {
+ /* FIXME this should be a WARN() once mambo is updated */
+ pr_err("wsp_ics: No available-ranges defined for %s\n",
+ dn->full_name);
+ return 0;
+ }
+
+ if (len % (2 * sizeof(u32)) != 0) {
+ /* FIXME this should be a WARN() once mambo is updated */
+ pr_err("wsp_ics: Invalid available-ranges for %s\n",
+ dn->full_name);
+ return 0;
+ }
+
+ bitmap_fill(ics->bitmap, ics->count);
+
+ for (i = 0; i < len / sizeof(u32); i += 2) {
+ start = of_read_number(p + i, 1);
+ count = of_read_number(p + i + 1, 1);
+
+ pr_devel("%s: start: %d count: %d\n", __func__, start, count);
+
+ if ((start + count) > (ics->hwirq_start + ics->count) ||
+ start < ics->hwirq_start) {
+ pr_err("wsp_ics: Invalid range! -> %d to %d\n",
+ start, start + count);
+ break;
+ }
+
+ for (j = 0; j < count; j++)
+ bitmap_release_region(ics->bitmap,
+ (start + j) - ics->hwirq_start, 0);
+ }
+
+ /* Ensure LSIs are not available for allocation */
+ bitmap_allocate_region(ics->bitmap, ics->lsi_base,
+ get_count_order(ics->lsi_count));
+
+ return 0;
+}
+
+static int __init wsp_ics_setup(struct wsp_ics *ics, struct device_node *dn)
+{
+ u32 lsi_buid, msi_buid, msi_base, msi_count;
+ void __iomem *regs;
+ const u32 *p;
+ int rc, len, i;
+ u64 caps, buid;
+
+ p = of_get_property(dn, "interrupt-ranges", &len);
+ if (!p || len < (2 * sizeof(u32))) {
+ pr_err("wsp_ics: No/bad interrupt-ranges found on %s\n",
+ dn->full_name);
+ return -ENOENT;
+ }
+
+ if (len > (2 * sizeof(u32))) {
+ pr_err("wsp_ics: Multiple ics ranges not supported.\n");
+ return -EINVAL;
+ }
+
+ regs = of_iomap(dn, 0);
+ if (!regs) {
+ pr_err("wsp_ics: of_iomap(%s) failed\n", dn->full_name);
+ return -ENXIO;
+ }
+
+ ics->hwirq_start = of_read_number(p, 1);
+ ics->count = of_read_number(p + 1, 1);
+ ics->regs = regs;
+
+ ics->chip_id = wsp_get_chip_id(dn);
+ if (WARN_ON(ics->chip_id < 0))
+ ics->chip_id = 0;
+
+ /* Get some informations about the critter */
+ caps = in_be64(ICS_INT_CAPS_REG(ics->regs));
+ buid = in_be64(INT_SRC_LAYER_BUID_REG(ics->regs));
+ ics->lsi_count = caps >> 56;
+ msi_count = (caps >> 44) & 0x7ff;
+
+ /* Note: LSI BUID is 9 bits, but really only 3 are BUID and the
+ * rest is mixed in the interrupt number. We store the whole
+ * thing though
+ */
+ lsi_buid = (buid >> 48) & 0x1ff;
+ ics->lsi_base = (ics->chip_id << WSP_ICS_CHIP_SHIFT) | lsi_buid << 5;
+ msi_buid = (buid >> 37) & 0x7;
+ msi_base = (ics->chip_id << WSP_ICS_CHIP_SHIFT) | msi_buid << 11;
+
+ pr_info("wsp_ics: Found %s\n", dn->full_name);
+ pr_info("wsp_ics: irq range : 0x%06llx..0x%06llx\n",
+ ics->hwirq_start, ics->hwirq_start + ics->count - 1);
+ pr_info("wsp_ics: %4d LSIs : 0x%06x..0x%06x\n",
+ ics->lsi_count, ics->lsi_base,
+ ics->lsi_base + ics->lsi_count - 1);
+ pr_info("wsp_ics: %4d MSIs : 0x%06x..0x%06x\n",
+ msi_count, msi_base,
+ msi_base + msi_count - 1);
+
+ /* Let's check the HW config is sane */
+ if (ics->lsi_base < ics->hwirq_start ||
+ (ics->lsi_base + ics->lsi_count) > (ics->hwirq_start + ics->count))
+ pr_warning("wsp_ics: WARNING ! LSIs out of interrupt-ranges !\n");
+ if (msi_base < ics->hwirq_start ||
+ (msi_base + msi_count) > (ics->hwirq_start + ics->count))
+ pr_warning("wsp_ics: WARNING ! MSIs out of interrupt-ranges !\n");
+
+ /* We don't check for overlap between LSI and MSI, which will happen
+ * if we use the same BUID, I'm not sure yet how legit that is.
+ */
+
+ rc = wsp_ics_bitmap_setup(ics, dn);
+ if (rc) {
+ iounmap(regs);
+ return rc;
+ }
+
+ ics->dn = of_node_get(dn);
+ alloc_irq_map(ics);
+
+ for(i = 0; i < ics->count; i++)
+ wsp_mask_real_irq(ics->hwirq_start + i, ics);
+
+ ics->ics.map = wsp_ics_map;
+ ics->ics.mask_unknown = wsp_ics_mask_unknown;
+ ics->ics.get_server = wsp_ics_get_server;
+ ics->ics.host_match = wsp_ics_host_match;
+
+ xics_register_ics(&ics->ics);
+
+ return 0;
+}
+
+static void __init wsp_ics_set_default_server(void)
+{
+ struct device_node *np;
+ u32 hwid;
+
+ /* Find the server number for the boot cpu. */
+ np = of_get_cpu_node(boot_cpuid, NULL);
+ BUG_ON(!np);
+
+ hwid = get_hard_smp_processor_id(boot_cpuid);
+
+ pr_info("wsp_ics: default server is %#x, CPU %s\n", hwid, np->full_name);
+ xics_default_server = hwid;
+
+ of_node_put(np);
+}
+
+static int __init wsp_ics_init(void)
+{
+ struct device_node *dn;
+ struct wsp_ics *ics;
+ int rc, found;
+
+ wsp_ics_set_default_server();
+
+ found = 0;
+ for_each_compatible_node(dn, NULL, "ibm,ppc-xics")
+ found++;
+
+ if (found == 0) {
+ pr_err("wsp_ics: No ICS's found!\n");
+ return -ENODEV;
+ }
+
+ ics_list = kmalloc(sizeof(*ics) * found, GFP_KERNEL);
+ if (!ics_list) {
+ pr_err("wsp_ics: No memory for structs.\n");
+ return -ENOMEM;
+ }
+
+ num_ics = 0;
+ ics = ics_list;
+ for_each_compatible_node(dn, NULL, "ibm,wsp-xics") {
+ rc = wsp_ics_setup(ics, dn);
+ if (rc == 0) {
+ ics++;
+ num_ics++;
+ }
+ }
+
+ if (found != num_ics) {
+ pr_err("wsp_ics: Failed setting up %d ICS's\n",
+ found - num_ics);
+ return -1;
+ }
+
+ return 0;
+}
+
+void __init wsp_init_irq(void)
+{
+ wsp_ics_init();
+ xics_init();
+
+ /* We need to patch our irq chip's EOI to point to the right ICP */
+ wsp_irq_chip.irq_eoi = icp_ops->eoi;
+}
diff --git a/arch/powerpc/platforms/wsp/ics.h b/arch/powerpc/platforms/wsp/ics.h
new file mode 100644
index 000000000000..e34d53102640
--- /dev/null
+++ b/arch/powerpc/platforms/wsp/ics.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2009 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.
+ */
+
+#ifndef __ICS_H
+#define __ICS_H
+
+#define XIVE_ADDR_MASK 0x7FFULL
+
+extern void wsp_init_irq(void);
+
+extern int wsp_ics_alloc_irq(struct device_node *dn, int num);
+extern void wsp_ics_free_irq(struct device_node *dn, unsigned int irq);
+
+#endif /* __ICS_H */
diff --git a/arch/powerpc/platforms/wsp/opb_pic.c b/arch/powerpc/platforms/wsp/opb_pic.c
new file mode 100644
index 000000000000..be05631a3c1c
--- /dev/null
+++ b/arch/powerpc/platforms/wsp/opb_pic.c
@@ -0,0 +1,332 @@
+/*
+ * IBM Onboard Peripheral Bus Interrupt Controller
+ *
+ * Copyright 2010 Jack Miller, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+
+#include <asm/reg_a2.h>
+#include <asm/irq.h>
+
+#define OPB_NR_IRQS 32
+
+#define OPB_MLSASIER 0x04 /* MLS Accumulated Status IER */
+#define OPB_MLSIR 0x50 /* MLS Interrupt Register */
+#define OPB_MLSIER 0x54 /* MLS Interrupt Enable Register */
+#define OPB_MLSIPR 0x58 /* MLS Interrupt Polarity Register */
+#define OPB_MLSIIR 0x5c /* MLS Interrupt Inputs Register */
+
+static int opb_index = 0;
+
+struct opb_pic {
+ struct irq_host *host;
+ void *regs;
+ int index;
+ spinlock_t lock;
+};
+
+static u32 opb_in(struct opb_pic *opb, int offset)
+{
+ return in_be32(opb->regs + offset);
+}
+
+static void opb_out(struct opb_pic *opb, int offset, u32 val)
+{
+ out_be32(opb->regs + offset, val);
+}
+
+static void opb_unmask_irq(struct irq_data *d)
+{
+ struct opb_pic *opb;
+ unsigned long flags;
+ u32 ier, bitset;
+
+ opb = d->chip_data;
+ bitset = (1 << (31 - irqd_to_hwirq(d)));
+
+ spin_lock_irqsave(&opb->lock, flags);
+
+ ier = opb_in(opb, OPB_MLSIER);
+ opb_out(opb, OPB_MLSIER, ier | bitset);
+ ier = opb_in(opb, OPB_MLSIER);
+
+ spin_unlock_irqrestore(&opb->lock, flags);
+}
+
+static void opb_mask_irq(struct irq_data *d)
+{
+ struct opb_pic *opb;
+ unsigned long flags;
+ u32 ier, mask;
+
+ opb = d->chip_data;
+ mask = ~(1 << (31 - irqd_to_hwirq(d)));
+
+ spin_lock_irqsave(&opb->lock, flags);
+
+ ier = opb_in(opb, OPB_MLSIER);
+ opb_out(opb, OPB_MLSIER, ier & mask);
+ ier = opb_in(opb, OPB_MLSIER); // Flush posted writes
+
+ spin_unlock_irqrestore(&opb->lock, flags);
+}
+
+static void opb_ack_irq(struct irq_data *d)
+{
+ struct opb_pic *opb;
+ unsigned long flags;
+ u32 bitset;
+
+ opb = d->chip_data;
+ bitset = (1 << (31 - irqd_to_hwirq(d)));
+
+ spin_lock_irqsave(&opb->lock, flags);
+
+ opb_out(opb, OPB_MLSIR, bitset);
+ opb_in(opb, OPB_MLSIR); // Flush posted writes
+
+ spin_unlock_irqrestore(&opb->lock, flags);
+}
+
+static void opb_mask_ack_irq(struct irq_data *d)
+{
+ struct opb_pic *opb;
+ unsigned long flags;
+ u32 bitset;
+ u32 ier, ir;
+
+ opb = d->chip_data;
+ bitset = (1 << (31 - irqd_to_hwirq(d)));
+
+ spin_lock_irqsave(&opb->lock, flags);
+
+ ier = opb_in(opb, OPB_MLSIER);
+ opb_out(opb, OPB_MLSIER, ier & ~bitset);
+ ier = opb_in(opb, OPB_MLSIER); // Flush posted writes
+
+ opb_out(opb, OPB_MLSIR, bitset);
+ ir = opb_in(opb, OPB_MLSIR); // Flush posted writes
+
+ spin_unlock_irqrestore(&opb->lock, flags);
+}
+
+static int opb_set_irq_type(struct irq_data *d, unsigned int flow)
+{
+ struct opb_pic *opb;
+ unsigned long flags;
+ int invert, ipr, mask, bit;
+
+ opb = d->chip_data;
+
+ /* The only information we're interested in in the type is whether it's
+ * a high or low trigger. For high triggered interrupts, the polarity
+ * set for it in the MLS Interrupt Polarity Register is 0, for low
+ * interrupts it's 1 so that the proper input in the MLS Interrupt Input
+ * Register is interrupted as asserting the interrupt. */
+
+ switch (flow) {
+ case IRQ_TYPE_NONE:
+ opb_mask_irq(d);
+ return 0;
+
+ case IRQ_TYPE_LEVEL_HIGH:
+ invert = 0;
+ break;
+
+ case IRQ_TYPE_LEVEL_LOW:
+ invert = 1;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ bit = (1 << (31 - irqd_to_hwirq(d)));
+ mask = ~bit;
+
+ spin_lock_irqsave(&opb->lock, flags);
+
+ ipr = opb_in(opb, OPB_MLSIPR);
+ ipr = (ipr & mask) | (invert ? bit : 0);
+ opb_out(opb, OPB_MLSIPR, ipr);
+ ipr = opb_in(opb, OPB_MLSIPR); // Flush posted writes
+
+ spin_unlock_irqrestore(&opb->lock, flags);
+
+ /* Record the type in the interrupt descriptor */
+ irqd_set_trigger_type(d, flow);
+
+ return 0;
+}
+
+static struct irq_chip opb_irq_chip = {
+ .name = "OPB",
+ .irq_mask = opb_mask_irq,
+ .irq_unmask = opb_unmask_irq,
+ .irq_mask_ack = opb_mask_ack_irq,
+ .irq_ack = opb_ack_irq,
+ .irq_set_type = opb_set_irq_type
+};
+
+static int opb_host_map(struct irq_host *host, unsigned int virq,
+ irq_hw_number_t hwirq)
+{
+ struct opb_pic *opb;
+
+ opb = host->host_data;
+
+ /* Most of the important stuff is handled by the generic host code, like
+ * the lookup, so just attach some info to the virtual irq */
+
+ irq_set_chip_data(virq, opb);
+ irq_set_chip_and_handler(virq, &opb_irq_chip, handle_level_irq);
+ irq_set_irq_type(virq, IRQ_TYPE_NONE);
+
+ return 0;
+}
+
+static int opb_host_xlate(struct irq_host *host, struct device_node *dn,
+ const u32 *intspec, unsigned int intsize,
+ irq_hw_number_t *out_hwirq, unsigned int *out_type)
+{
+ /* Interrupt size must == 2 */
+ BUG_ON(intsize != 2);
+ *out_hwirq = intspec[0];
+ *out_type = intspec[1];
+ return 0;
+}
+
+static struct irq_host_ops opb_host_ops = {
+ .map = opb_host_map,
+ .xlate = opb_host_xlate,
+};
+
+irqreturn_t opb_irq_handler(int irq, void *private)
+{
+ struct opb_pic *opb;
+ u32 ir, src, subvirq;
+
+ opb = (struct opb_pic *) private;
+
+ /* Read the OPB MLS Interrupt Register for
+ * asserted interrupts */
+ ir = opb_in(opb, OPB_MLSIR);
+ if (!ir)
+ return IRQ_NONE;
+
+ do {
+ /* Get 1 - 32 source, *NOT* bit */
+ src = 32 - ffs(ir);
+
+ /* Translate from the OPB's conception of interrupt number to
+ * Linux's virtual IRQ */
+
+ subvirq = irq_linear_revmap(opb->host, src);
+
+ generic_handle_irq(subvirq);
+ } while ((ir = opb_in(opb, OPB_MLSIR)));
+
+ return IRQ_HANDLED;
+}
+
+struct opb_pic *opb_pic_init_one(struct device_node *dn)
+{
+ struct opb_pic *opb;
+ struct resource res;
+
+ if (of_address_to_resource(dn, 0, &res)) {
+ printk(KERN_ERR "opb: Couldn't translate resource\n");
+ return NULL;
+ }
+
+ opb = kzalloc(sizeof(struct opb_pic), GFP_KERNEL);
+ if (!opb) {
+ printk(KERN_ERR "opb: Failed to allocate opb struct!\n");
+ return NULL;
+ }
+
+ /* Get access to the OPB MMIO registers */
+ opb->regs = ioremap(res.start + 0x10000, 0x1000);
+ if (!opb->regs) {
+ printk(KERN_ERR "opb: Failed to allocate register space!\n");
+ goto free_opb;
+ }
+
+ /* Allocate an irq host so that Linux knows that despite only
+ * having one interrupt to issue, we're the controller for multiple
+ * hardware IRQs, so later we can lookup their virtual IRQs. */
+
+ opb->host = irq_alloc_host(dn, IRQ_HOST_MAP_LINEAR,
+ OPB_NR_IRQS, &opb_host_ops, -1);
+
+ if (!opb->host) {
+ printk(KERN_ERR "opb: Failed to allocate IRQ host!\n");
+ goto free_regs;
+ }
+
+ opb->index = opb_index++;
+ spin_lock_init(&opb->lock);
+ opb->host->host_data = opb;
+
+ /* Disable all interrupts by default */
+ opb_out(opb, OPB_MLSASIER, 0);
+ opb_out(opb, OPB_MLSIER, 0);
+
+ /* ACK any interrupts left by FW */
+ opb_out(opb, OPB_MLSIR, 0xFFFFFFFF);
+
+ return opb;
+
+free_regs:
+ iounmap(opb->regs);
+free_opb:
+ kfree(opb);
+ return NULL;
+}
+
+void __init opb_pic_init(void)
+{
+ struct device_node *dn;
+ struct opb_pic *opb;
+ int virq;
+ int rc;
+
+ /* Call init_one for each OPB device */
+ for_each_compatible_node(dn, NULL, "ibm,opb") {
+
+ /* Fill in an OPB struct */
+ opb = opb_pic_init_one(dn);
+ if (!opb) {
+ printk(KERN_WARNING "opb: Failed to init node, skipped!\n");
+ continue;
+ }
+
+ /* Map / get opb's hardware virtual irq */
+ virq = irq_of_parse_and_map(dn, 0);
+ if (virq <= 0) {
+ printk("opb: irq_op_parse_and_map failed!\n");
+ continue;
+ }
+
+ /* Attach opb interrupt handler to new virtual IRQ */
+ rc = request_irq(virq, opb_irq_handler, 0, "OPB LS Cascade", opb);
+ if (rc) {
+ printk("opb: request_irq failed: %d\n", rc);
+ continue;
+ }
+
+ printk("OPB%d init with %d IRQs at %p\n", opb->index,
+ OPB_NR_IRQS, opb->regs);
+ }
+}
diff --git a/arch/powerpc/platforms/wsp/psr2.c b/arch/powerpc/platforms/wsp/psr2.c
new file mode 100644
index 000000000000..40f28916ff6c
--- /dev/null
+++ b/arch/powerpc/platforms/wsp/psr2.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2008-2011, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/of.h>
+#include <linux/smp.h>
+
+#include <asm/machdep.h>
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/udbg.h>
+
+#include "ics.h"
+#include "wsp.h"
+
+
+static void psr2_spin(void)
+{
+ hard_irq_disable();
+ for (;;) ;
+}
+
+static void psr2_restart(char *cmd)
+{
+ psr2_spin();
+}
+
+static int psr2_probe_devices(void)
+{
+ struct device_node *np;
+
+ /* Our RTC is a ds1500. It seems to be programatically compatible
+ * with the ds1511 for which we have a driver so let's use that
+ */
+ np = of_find_compatible_node(NULL, NULL, "dallas,ds1500");
+ if (np != NULL) {
+ struct resource res;
+ if (of_address_to_resource(np, 0, &res) == 0)
+ platform_device_register_simple("ds1511", 0, &res, 1);
+ }
+ return 0;
+}
+machine_arch_initcall(psr2_md, psr2_probe_devices);
+
+static void __init psr2_setup_arch(void)
+{
+ /* init to some ~sane value until calibrate_delay() runs */
+ loops_per_jiffy = 50000000;
+
+ scom_init_wsp();
+
+ /* Setup SMP callback */
+#ifdef CONFIG_SMP
+ a2_setup_smp();
+#endif
+}
+
+static int __init psr2_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+
+ if (!of_flat_dt_is_compatible(root, "ibm,psr2"))
+ return 0;
+
+ return 1;
+}
+
+static void __init psr2_init_irq(void)
+{
+ wsp_init_irq();
+ opb_pic_init();
+}
+
+define_machine(psr2_md) {
+ .name = "PSR2 A2",
+ .probe = psr2_probe,
+ .setup_arch = psr2_setup_arch,
+ .restart = psr2_restart,
+ .power_off = psr2_spin,
+ .halt = psr2_spin,
+ .calibrate_decr = generic_calibrate_decr,
+ .init_IRQ = psr2_init_irq,
+ .progress = udbg_progress,
+ .power_save = book3e_idle,
+};
diff --git a/arch/powerpc/platforms/wsp/scom_smp.c b/arch/powerpc/platforms/wsp/scom_smp.c
new file mode 100644
index 000000000000..141e78032097
--- /dev/null
+++ b/arch/powerpc/platforms/wsp/scom_smp.c
@@ -0,0 +1,427 @@
+/*
+ * SCOM support for A2 platforms
+ *
+ * Copyright 2007-2011 Benjamin Herrenschmidt, David Gibson,
+ * Michael Ellerman, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/cpumask.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <asm/cputhreads.h>
+#include <asm/reg_a2.h>
+#include <asm/scom.h>
+#include <asm/udbg.h>
+
+#include "wsp.h"
+
+#define SCOM_RAMC 0x2a /* Ram Command */
+#define SCOM_RAMC_TGT1_EXT 0x80000000
+#define SCOM_RAMC_SRC1_EXT 0x40000000
+#define SCOM_RAMC_SRC2_EXT 0x20000000
+#define SCOM_RAMC_SRC3_EXT 0x10000000
+#define SCOM_RAMC_ENABLE 0x00080000
+#define SCOM_RAMC_THREADSEL 0x00060000
+#define SCOM_RAMC_EXECUTE 0x00010000
+#define SCOM_RAMC_MSR_OVERRIDE 0x00008000
+#define SCOM_RAMC_MSR_PR 0x00004000
+#define SCOM_RAMC_MSR_GS 0x00002000
+#define SCOM_RAMC_FORCE 0x00001000
+#define SCOM_RAMC_FLUSH 0x00000800
+#define SCOM_RAMC_INTERRUPT 0x00000004
+#define SCOM_RAMC_ERROR 0x00000002
+#define SCOM_RAMC_DONE 0x00000001
+#define SCOM_RAMI 0x29 /* Ram Instruction */
+#define SCOM_RAMIC 0x28 /* Ram Instruction and Command */
+#define SCOM_RAMIC_INSN 0xffffffff00000000
+#define SCOM_RAMD 0x2d /* Ram Data */
+#define SCOM_RAMDH 0x2e /* Ram Data High */
+#define SCOM_RAMDL 0x2f /* Ram Data Low */
+#define SCOM_PCCR0 0x33 /* PC Configuration Register 0 */
+#define SCOM_PCCR0_ENABLE_DEBUG 0x80000000
+#define SCOM_PCCR0_ENABLE_RAM 0x40000000
+#define SCOM_THRCTL 0x30 /* Thread Control and Status */
+#define SCOM_THRCTL_T0_STOP 0x80000000
+#define SCOM_THRCTL_T1_STOP 0x40000000
+#define SCOM_THRCTL_T2_STOP 0x20000000
+#define SCOM_THRCTL_T3_STOP 0x10000000
+#define SCOM_THRCTL_T0_STEP 0x08000000
+#define SCOM_THRCTL_T1_STEP 0x04000000
+#define SCOM_THRCTL_T2_STEP 0x02000000
+#define SCOM_THRCTL_T3_STEP 0x01000000
+#define SCOM_THRCTL_T0_RUN 0x00800000
+#define SCOM_THRCTL_T1_RUN 0x00400000
+#define SCOM_THRCTL_T2_RUN 0x00200000
+#define SCOM_THRCTL_T3_RUN 0x00100000
+#define SCOM_THRCTL_T0_PM 0x00080000
+#define SCOM_THRCTL_T1_PM 0x00040000
+#define SCOM_THRCTL_T2_PM 0x00020000
+#define SCOM_THRCTL_T3_PM 0x00010000
+#define SCOM_THRCTL_T0_UDE 0x00008000
+#define SCOM_THRCTL_T1_UDE 0x00004000
+#define SCOM_THRCTL_T2_UDE 0x00002000
+#define SCOM_THRCTL_T3_UDE 0x00001000
+#define SCOM_THRCTL_ASYNC_DIS 0x00000800
+#define SCOM_THRCTL_TB_DIS 0x00000400
+#define SCOM_THRCTL_DEC_DIS 0x00000200
+#define SCOM_THRCTL_AND 0x31 /* Thread Control and Status */
+#define SCOM_THRCTL_OR 0x32 /* Thread Control and Status */
+
+
+static DEFINE_PER_CPU(scom_map_t, scom_ptrs);
+
+static scom_map_t get_scom(int cpu, struct device_node *np, int *first_thread)
+{
+ scom_map_t scom = per_cpu(scom_ptrs, cpu);
+ int tcpu;
+
+ if (scom_map_ok(scom)) {
+ *first_thread = 0;
+ return scom;
+ }
+
+ *first_thread = 1;
+
+ scom = scom_map_device(np, 0);
+
+ for (tcpu = cpu_first_thread_sibling(cpu);
+ tcpu <= cpu_last_thread_sibling(cpu); tcpu++)
+ per_cpu(scom_ptrs, tcpu) = scom;
+
+ /* Hack: for the boot core, this will actually get called on
+ * the second thread up, not the first so our test above will
+ * set first_thread incorrectly. */
+ if (cpu_first_thread_sibling(cpu) == 0)
+ *first_thread = 0;
+
+ return scom;
+}
+
+static int a2_scom_ram(scom_map_t scom, int thread, u32 insn, int extmask)
+{
+ u64 cmd, mask, val;
+ int n = 0;
+
+ cmd = ((u64)insn << 32) | (((u64)extmask & 0xf) << 28)
+ | ((u64)thread << 17) | SCOM_RAMC_ENABLE | SCOM_RAMC_EXECUTE;
+ mask = SCOM_RAMC_DONE | SCOM_RAMC_INTERRUPT | SCOM_RAMC_ERROR;
+
+ scom_write(scom, SCOM_RAMIC, cmd);
+
+ while (!((val = scom_read(scom, SCOM_RAMC)) & mask)) {
+ pr_devel("Waiting on RAMC = 0x%llx\n", val);
+ if (++n == 3) {
+ pr_err("RAMC timeout on instruction 0x%08x, thread %d\n",
+ insn, thread);
+ return -1;
+ }
+ }
+
+ if (val & SCOM_RAMC_INTERRUPT) {
+ pr_err("RAMC interrupt on instruction 0x%08x, thread %d\n",
+ insn, thread);
+ return -SCOM_RAMC_INTERRUPT;
+ }
+
+ if (val & SCOM_RAMC_ERROR) {
+ pr_err("RAMC error on instruction 0x%08x, thread %d\n",
+ insn, thread);
+ return -SCOM_RAMC_ERROR;
+ }
+
+ return 0;
+}
+
+static int a2_scom_getgpr(scom_map_t scom, int thread, int gpr, int alt,
+ u64 *out_gpr)
+{
+ int rc;
+
+ /* or rN, rN, rN */
+ u32 insn = 0x7c000378 | (gpr << 21) | (gpr << 16) | (gpr << 11);
+ rc = a2_scom_ram(scom, thread, insn, alt ? 0xf : 0x0);
+ if (rc)
+ return rc;
+
+ *out_gpr = scom_read(scom, SCOM_RAMD);
+
+ return 0;
+}
+
+static int a2_scom_getspr(scom_map_t scom, int thread, int spr, u64 *out_spr)
+{
+ int rc, sprhi, sprlo;
+ u32 insn;
+
+ sprhi = spr >> 5;
+ sprlo = spr & 0x1f;
+ insn = 0x7c2002a6 | (sprlo << 16) | (sprhi << 11); /* mfspr r1,spr */
+
+ if (spr == 0x0ff0)
+ insn = 0x7c2000a6; /* mfmsr r1 */
+
+ rc = a2_scom_ram(scom, thread, insn, 0xf);
+ if (rc)
+ return rc;
+ return a2_scom_getgpr(scom, thread, 1, 1, out_spr);
+}
+
+static int a2_scom_setgpr(scom_map_t scom, int thread, int gpr,
+ int alt, u64 val)
+{
+ u32 lis = 0x3c000000 | (gpr << 21);
+ u32 li = 0x38000000 | (gpr << 21);
+ u32 oris = 0x64000000 | (gpr << 21) | (gpr << 16);
+ u32 ori = 0x60000000 | (gpr << 21) | (gpr << 16);
+ u32 rldicr32 = 0x780007c6 | (gpr << 21) | (gpr << 16);
+ u32 highest = val >> 48;
+ u32 higher = (val >> 32) & 0xffff;
+ u32 high = (val >> 16) & 0xffff;
+ u32 low = val & 0xffff;
+ int lext = alt ? 0x8 : 0x0;
+ int oext = alt ? 0xf : 0x0;
+ int rc = 0;
+
+ if (highest)
+ rc |= a2_scom_ram(scom, thread, lis | highest, lext);
+
+ if (higher) {
+ if (highest)
+ rc |= a2_scom_ram(scom, thread, oris | higher, oext);
+ else
+ rc |= a2_scom_ram(scom, thread, li | higher, lext);
+ }
+
+ if (highest || higher)
+ rc |= a2_scom_ram(scom, thread, rldicr32, oext);
+
+ if (high) {
+ if (highest || higher)
+ rc |= a2_scom_ram(scom, thread, oris | high, oext);
+ else
+ rc |= a2_scom_ram(scom, thread, lis | high, lext);
+ }
+
+ if (highest || higher || high)
+ rc |= a2_scom_ram(scom, thread, ori | low, oext);
+ else
+ rc |= a2_scom_ram(scom, thread, li | low, lext);
+
+ return rc;
+}
+
+static int a2_scom_setspr(scom_map_t scom, int thread, int spr, u64 val)
+{
+ int sprhi = spr >> 5;
+ int sprlo = spr & 0x1f;
+ /* mtspr spr, r1 */
+ u32 insn = 0x7c2003a6 | (sprlo << 16) | (sprhi << 11);
+
+ if (spr == 0x0ff0)
+ insn = 0x7c200124; /* mtmsr r1 */
+
+ if (a2_scom_setgpr(scom, thread, 1, 1, val))
+ return -1;
+
+ return a2_scom_ram(scom, thread, insn, 0xf);
+}
+
+static int a2_scom_initial_tlb(scom_map_t scom, int thread)
+{
+ extern u32 a2_tlbinit_code_start[], a2_tlbinit_code_end[];
+ extern u32 a2_tlbinit_after_iprot_flush[];
+ extern u32 a2_tlbinit_after_linear_map[];
+ u32 assoc, entries, i;
+ u64 epn, tlbcfg;
+ u32 *p;
+ int rc;
+
+ /* Invalidate all entries (including iprot) */
+
+ rc = a2_scom_getspr(scom, thread, SPRN_TLB0CFG, &tlbcfg);
+ if (rc)
+ goto scom_fail;
+ entries = tlbcfg & TLBnCFG_N_ENTRY;
+ assoc = (tlbcfg & TLBnCFG_ASSOC) >> 24;
+ epn = 0;
+
+ /* Set MMUCR2 to enable 4K, 64K, 1M, 16M and 1G pages */
+ a2_scom_setspr(scom, thread, SPRN_MMUCR2, 0x000a7531);
+ /* Set MMUCR3 to write all thids bit to the TLB */
+ a2_scom_setspr(scom, thread, SPRN_MMUCR3, 0x0000000f);
+
+ /* Set MAS1 for 1G page size, and MAS2 to our initial EPN */
+ a2_scom_setspr(scom, thread, SPRN_MAS1, MAS1_TSIZE(BOOK3E_PAGESZ_1GB));
+ a2_scom_setspr(scom, thread, SPRN_MAS2, epn);
+ for (i = 0; i < entries; i++) {
+
+ a2_scom_setspr(scom, thread, SPRN_MAS0, MAS0_ESEL(i % assoc));
+
+ /* tlbwe */
+ rc = a2_scom_ram(scom, thread, 0x7c0007a4, 0);
+ if (rc)
+ goto scom_fail;
+
+ /* Next entry is new address? */
+ if((i + 1) % assoc == 0) {
+ epn += (1 << 30);
+ a2_scom_setspr(scom, thread, SPRN_MAS2, epn);
+ }
+ }
+
+ /* Setup args for linear mapping */
+ rc = a2_scom_setgpr(scom, thread, 3, 0, MAS0_TLBSEL(0));
+ if (rc)
+ goto scom_fail;
+
+ /* Linear mapping */
+ for (p = a2_tlbinit_code_start; p < a2_tlbinit_after_linear_map; p++) {
+ rc = a2_scom_ram(scom, thread, *p, 0);
+ if (rc)
+ goto scom_fail;
+ }
+
+ /*
+ * For the boot thread, between the linear mapping and the debug
+ * mappings there is a loop to flush iprot mappings. Ramming doesn't do
+ * branches, but the secondary threads don't need to be nearly as smart
+ * (i.e. we don't need to worry about invalidating the mapping we're
+ * standing on).
+ */
+
+ /* Debug mappings. Expects r11 = MAS0 from linear map (set above) */
+ for (p = a2_tlbinit_after_iprot_flush; p < a2_tlbinit_code_end; p++) {
+ rc = a2_scom_ram(scom, thread, *p, 0);
+ if (rc)
+ goto scom_fail;
+ }
+
+scom_fail:
+ if (rc)
+ pr_err("Setting up initial TLB failed, err %d\n", rc);
+
+ if (rc == -SCOM_RAMC_INTERRUPT) {
+ /* Interrupt, dump some status */
+ int rc[10];
+ u64 iar, srr0, srr1, esr, mas0, mas1, mas2, mas7_3, mas8, ccr2;
+ rc[0] = a2_scom_getspr(scom, thread, SPRN_IAR, &iar);
+ rc[1] = a2_scom_getspr(scom, thread, SPRN_SRR0, &srr0);
+ rc[2] = a2_scom_getspr(scom, thread, SPRN_SRR1, &srr1);
+ rc[3] = a2_scom_getspr(scom, thread, SPRN_ESR, &esr);
+ rc[4] = a2_scom_getspr(scom, thread, SPRN_MAS0, &mas0);
+ rc[5] = a2_scom_getspr(scom, thread, SPRN_MAS1, &mas1);
+ rc[6] = a2_scom_getspr(scom, thread, SPRN_MAS2, &mas2);
+ rc[7] = a2_scom_getspr(scom, thread, SPRN_MAS7_MAS3, &mas7_3);
+ rc[8] = a2_scom_getspr(scom, thread, SPRN_MAS8, &mas8);
+ rc[9] = a2_scom_getspr(scom, thread, SPRN_A2_CCR2, &ccr2);
+ pr_err(" -> retreived IAR =0x%llx (err %d)\n", iar, rc[0]);
+ pr_err(" retreived SRR0=0x%llx (err %d)\n", srr0, rc[1]);
+ pr_err(" retreived SRR1=0x%llx (err %d)\n", srr1, rc[2]);
+ pr_err(" retreived ESR =0x%llx (err %d)\n", esr, rc[3]);
+ pr_err(" retreived MAS0=0x%llx (err %d)\n", mas0, rc[4]);
+ pr_err(" retreived MAS1=0x%llx (err %d)\n", mas1, rc[5]);
+ pr_err(" retreived MAS2=0x%llx (err %d)\n", mas2, rc[6]);
+ pr_err(" retreived MS73=0x%llx (err %d)\n", mas7_3, rc[7]);
+ pr_err(" retreived MAS8=0x%llx (err %d)\n", mas8, rc[8]);
+ pr_err(" retreived CCR2=0x%llx (err %d)\n", ccr2, rc[9]);
+ }
+
+ return rc;
+}
+
+int __devinit a2_scom_startup_cpu(unsigned int lcpu, int thr_idx,
+ struct device_node *np)
+{
+ u64 init_iar, init_msr, init_ccr2;
+ unsigned long start_here;
+ int rc, core_setup;
+ scom_map_t scom;
+ u64 pccr0;
+
+ scom = get_scom(lcpu, np, &core_setup);
+ if (!scom) {
+ printk(KERN_ERR "Couldn't map SCOM for CPU%d\n", lcpu);
+ return -1;
+ }
+
+ pr_devel("Bringing up CPU%d using SCOM...\n", lcpu);
+
+ pccr0 = scom_read(scom, SCOM_PCCR0);
+ scom_write(scom, SCOM_PCCR0, pccr0 | SCOM_PCCR0_ENABLE_DEBUG |
+ SCOM_PCCR0_ENABLE_RAM);
+
+ /* Stop the thead with THRCTL. If we are setting up the TLB we stop all
+ * threads. We also disable asynchronous interrupts while RAMing.
+ */
+ if (core_setup)
+ scom_write(scom, SCOM_THRCTL_OR,
+ SCOM_THRCTL_T0_STOP |
+ SCOM_THRCTL_T1_STOP |
+ SCOM_THRCTL_T2_STOP |
+ SCOM_THRCTL_T3_STOP |
+ SCOM_THRCTL_ASYNC_DIS);
+ else
+ scom_write(scom, SCOM_THRCTL_OR, SCOM_THRCTL_T0_STOP >> thr_idx);
+
+ /* Flush its pipeline just in case */
+ scom_write(scom, SCOM_RAMC, ((u64)thr_idx << 17) |
+ SCOM_RAMC_FLUSH | SCOM_RAMC_ENABLE);
+
+ a2_scom_getspr(scom, thr_idx, SPRN_IAR, &init_iar);
+ a2_scom_getspr(scom, thr_idx, 0x0ff0, &init_msr);
+ a2_scom_getspr(scom, thr_idx, SPRN_A2_CCR2, &init_ccr2);
+
+ /* Set MSR to MSR_CM (0x0ff0 is magic value for MSR_CM) */
+ rc = a2_scom_setspr(scom, thr_idx, 0x0ff0, MSR_CM);
+ if (rc) {
+ pr_err("Failed to set MSR ! err %d\n", rc);
+ return rc;
+ }
+
+ /* RAM in an sync/isync for the sake of it */
+ a2_scom_ram(scom, thr_idx, 0x7c0004ac, 0);
+ a2_scom_ram(scom, thr_idx, 0x4c00012c, 0);
+
+ if (core_setup) {
+ pr_devel("CPU%d is first thread in core, initializing TLB...\n",
+ lcpu);
+ rc = a2_scom_initial_tlb(scom, thr_idx);
+ if (rc)
+ goto fail;
+ }
+
+ start_here = *(unsigned long *)(core_setup ? generic_secondary_smp_init
+ : generic_secondary_thread_init);
+ pr_devel("CPU%d entry point at 0x%lx...\n", lcpu, start_here);
+
+ rc |= a2_scom_setspr(scom, thr_idx, SPRN_IAR, start_here);
+ rc |= a2_scom_setgpr(scom, thr_idx, 3, 0,
+ get_hard_smp_processor_id(lcpu));
+ /*
+ * Tell book3e_secondary_core_init not to set up the TLB, we've
+ * already done that.
+ */
+ rc |= a2_scom_setgpr(scom, thr_idx, 4, 0, 1);
+
+ rc |= a2_scom_setspr(scom, thr_idx, SPRN_TENS, 0x1 << thr_idx);
+
+ scom_write(scom, SCOM_RAMC, 0);
+ scom_write(scom, SCOM_THRCTL_AND, ~(SCOM_THRCTL_T0_STOP >> thr_idx));
+ scom_write(scom, SCOM_PCCR0, pccr0);
+fail:
+ pr_devel(" SCOM initialization %s\n", rc ? "failed" : "succeeded");
+ if (rc) {
+ pr_err("Old IAR=0x%08llx MSR=0x%08llx CCR2=0x%08llx\n",
+ init_iar, init_msr, init_ccr2);
+ }
+
+ return rc;
+}
diff --git a/arch/powerpc/platforms/wsp/scom_wsp.c b/arch/powerpc/platforms/wsp/scom_wsp.c
new file mode 100644
index 000000000000..4052e2259f30
--- /dev/null
+++ b/arch/powerpc/platforms/wsp/scom_wsp.c
@@ -0,0 +1,77 @@
+/*
+ * SCOM backend for WSP
+ *
+ * Copyright 2010 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/cpumask.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <asm/cputhreads.h>
+#include <asm/reg_a2.h>
+#include <asm/scom.h>
+#include <asm/udbg.h>
+
+#include "wsp.h"
+
+
+static scom_map_t wsp_scom_map(struct device_node *dev, u64 reg, u64 count)
+{
+ struct resource r;
+ u64 xscom_addr;
+
+ if (!of_get_property(dev, "scom-controller", NULL)) {
+ pr_err("%s: device %s is not a SCOM controller\n",
+ __func__, dev->full_name);
+ return SCOM_MAP_INVALID;
+ }
+
+ if (of_address_to_resource(dev, 0, &r)) {
+ pr_debug("Failed to find SCOM controller address\n");
+ return 0;
+ }
+
+ /* Transform the SCOM address into an XSCOM offset */
+ xscom_addr = ((reg & 0x7f000000) >> 1) | ((reg & 0xfffff) << 3);
+
+ return (scom_map_t)ioremap(r.start + xscom_addr, count << 3);
+}
+
+static void wsp_scom_unmap(scom_map_t map)
+{
+ iounmap((void *)map);
+}
+
+static u64 wsp_scom_read(scom_map_t map, u32 reg)
+{
+ u64 __iomem *addr = (u64 __iomem *)map;
+
+ return in_be64(addr + reg);
+}
+
+static void wsp_scom_write(scom_map_t map, u32 reg, u64 value)
+{
+ u64 __iomem *addr = (u64 __iomem *)map;
+
+ return out_be64(addr + reg, value);
+}
+
+static const struct scom_controller wsp_scom_controller = {
+ .map = wsp_scom_map,
+ .unmap = wsp_scom_unmap,
+ .read = wsp_scom_read,
+ .write = wsp_scom_write
+};
+
+void scom_init_wsp(void)
+{
+ scom_init(&wsp_scom_controller);
+}
diff --git a/arch/powerpc/platforms/wsp/setup.c b/arch/powerpc/platforms/wsp/setup.c
new file mode 100644
index 000000000000..11ac2f05e01c
--- /dev/null
+++ b/arch/powerpc/platforms/wsp/setup.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2010 Michael Ellerman, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/of_platform.h>
+
+#include "wsp.h"
+
+/*
+ * Find chip-id by walking up device tree looking for ibm,wsp-chip-id property.
+ * Won't work for nodes that are not a descendant of a wsp node.
+ */
+int wsp_get_chip_id(struct device_node *dn)
+{
+ const u32 *p;
+ int rc;
+
+ /* Start looking at the specified node, not its parent */
+ dn = of_node_get(dn);
+ while (dn && !(p = of_get_property(dn, "ibm,wsp-chip-id", NULL)))
+ dn = of_get_next_parent(dn);
+
+ if (!dn)
+ return -1;
+
+ rc = *p;
+ of_node_put(dn);
+
+ return rc;
+}
diff --git a/arch/powerpc/platforms/wsp/smp.c b/arch/powerpc/platforms/wsp/smp.c
new file mode 100644
index 000000000000..9d20fa9d3710
--- /dev/null
+++ b/arch/powerpc/platforms/wsp/smp.c
@@ -0,0 +1,88 @@
+/*
+ * SMP Support for A2 platforms
+ *
+ * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/cpumask.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/smp.h>
+
+#include <asm/dbell.h>
+#include <asm/machdep.h>
+#include <asm/xics.h>
+
+#include "ics.h"
+#include "wsp.h"
+
+static void __devinit smp_a2_setup_cpu(int cpu)
+{
+ doorbell_setup_this_cpu();
+
+ if (cpu != boot_cpuid)
+ xics_setup_cpu();
+}
+
+int __devinit smp_a2_kick_cpu(int nr)
+{
+ const char *enable_method;
+ struct device_node *np;
+ int thr_idx;
+
+ if (nr < 0 || nr >= NR_CPUS)
+ return -ENOENT;
+
+ np = of_get_cpu_node(nr, &thr_idx);
+ if (!np)
+ return -ENODEV;
+
+ enable_method = of_get_property(np, "enable-method", NULL);
+ pr_devel("CPU%d has enable-method: \"%s\"\n", nr, enable_method);
+
+ if (!enable_method) {
+ printk(KERN_ERR "CPU%d has no enable-method\n", nr);
+ return -ENOENT;
+ } else if (strcmp(enable_method, "ibm,a2-scom") == 0) {
+ if (a2_scom_startup_cpu(nr, thr_idx, np))
+ return -1;
+ } else {
+ printk(KERN_ERR "CPU%d: Don't understand enable-method \"%s\"\n",
+ nr, enable_method);
+ return -EINVAL;
+ }
+
+ /*
+ * The processor is currently spinning, waiting for the
+ * cpu_start field to become non-zero After we set cpu_start,
+ * the processor will continue on to secondary_start
+ */
+ paca[nr].cpu_start = 1;
+
+ return 0;
+}
+
+static int __init smp_a2_probe(void)
+{
+ return cpus_weight(cpu_possible_map);
+}
+
+static struct smp_ops_t a2_smp_ops = {
+ .message_pass = smp_muxed_ipi_message_pass,
+ .cause_ipi = doorbell_cause_ipi,
+ .probe = smp_a2_probe,
+ .kick_cpu = smp_a2_kick_cpu,
+ .setup_cpu = smp_a2_setup_cpu,
+};
+
+void __init a2_setup_smp(void)
+{
+ smp_ops = &a2_smp_ops;
+}
diff --git a/arch/powerpc/platforms/wsp/wsp.h b/arch/powerpc/platforms/wsp/wsp.h
new file mode 100644
index 000000000000..7c3e087fd2f2
--- /dev/null
+++ b/arch/powerpc/platforms/wsp/wsp.h
@@ -0,0 +1,17 @@
+#ifndef __WSP_H
+#define __WSP_H
+
+#include <asm/wsp.h>
+
+extern void wsp_setup_pci(void);
+extern void scom_init_wsp(void);
+
+extern void a2_setup_smp(void);
+extern int a2_scom_startup_cpu(unsigned int lcpu, int thr_idx,
+ struct device_node *np);
+int smp_a2_cpu_bootable(unsigned int nr);
+int __devinit smp_a2_kick_cpu(int nr);
+
+void opb_pic_init(void);
+
+#endif /* __WSP_H */
diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig
index 396582835cb5..7b4df37ac381 100644
--- a/arch/powerpc/sysdev/Kconfig
+++ b/arch/powerpc/sysdev/Kconfig
@@ -7,8 +7,25 @@ config PPC4xx_PCI_EXPRESS
depends on PCI && 4xx
default n
+config PPC4xx_MSI
+ bool
+ depends on PCI_MSI
+ depends on PCI && 4xx
+ default n
+
config PPC_MSI_BITMAP
bool
depends on PCI_MSI
default y if MPIC
default y if FSL_PCI
+ default y if PPC4xx_MSI
+
+source "arch/powerpc/sysdev/xics/Kconfig"
+
+config PPC_SCOM
+ bool
+
+config SCOM_DEBUGFS
+ bool "Expose SCOM controllers via debugfs"
+ depends on PPC_SCOM
+ default n
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 1e0c933ef772..0efa990e3344 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_OF_RTC) += of_rtc.o
ifeq ($(CONFIG_PCI),y)
obj-$(CONFIG_4xx) += ppc4xx_pci.o
endif
+obj-$(CONFIG_PPC4xx_MSI) += ppc4xx_msi.o
obj-$(CONFIG_PPC4xx_CPM) += ppc4xx_cpm.o
obj-$(CONFIG_PPC4xx_GPIO) += ppc4xx_gpio.o
@@ -57,3 +58,9 @@ obj-$(CONFIG_PPC_MPC52xx) += mpc5xxx_clocks.o
ifeq ($(CONFIG_SUSPEND),y)
obj-$(CONFIG_6xx) += 6xx-suspend.o
endif
+
+obj-$(CONFIG_PPC_SCOM) += scom.o
+
+subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
+
+obj-$(CONFIG_PPC_XICS) += xics/
diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c
index 1636dd896707..bd0d54060b94 100644
--- a/arch/powerpc/sysdev/axonram.c
+++ b/arch/powerpc/sysdev/axonram.c
@@ -216,7 +216,7 @@ static int axon_ram_probe(struct platform_device *device)
AXON_RAM_DEVICE_NAME, axon_ram_bank_id, bank->size >> 20);
bank->ph_addr = resource.start;
- bank->io_addr = (unsigned long) ioremap_flags(
+ bank->io_addr = (unsigned long) ioremap_prot(
bank->ph_addr, bank->size, _PAGE_NO_CACHE);
if (bank->io_addr == 0) {
dev_err(&device->dev, "ioremap() failed\n");
diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c
index e0bc944eb23f..350787c83e22 100644
--- a/arch/powerpc/sysdev/cpm1.c
+++ b/arch/powerpc/sysdev/cpm1.c
@@ -58,21 +58,21 @@ static struct irq_host *cpm_pic_host;
static void cpm_mask_irq(struct irq_data *d)
{
- unsigned int cpm_vec = (unsigned int)irq_map[d->irq].hwirq;
+ unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d);
clrbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec));
}
static void cpm_unmask_irq(struct irq_data *d)
{
- unsigned int cpm_vec = (unsigned int)irq_map[d->irq].hwirq;
+ unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d);
setbits32(&cpic_reg->cpic_cimr, (1 << cpm_vec));
}
static void cpm_end_irq(struct irq_data *d)
{
- unsigned int cpm_vec = (unsigned int)irq_map[d->irq].hwirq;
+ unsigned int cpm_vec = (unsigned int)irqd_to_hwirq(d);
out_be32(&cpic_reg->cpic_cisr, (1 << cpm_vec));
}
@@ -157,7 +157,7 @@ unsigned int cpm_pic_init(void)
goto end;
/* Initialize the CPM interrupt controller. */
- hwirq = (unsigned int)irq_map[sirq].hwirq;
+ hwirq = (unsigned int)virq_to_hw(sirq);
out_be32(&cpic_reg->cpic_cicr,
(CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1) |
((hwirq/2) << 13) | CICR_HP_MASK);
diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c
index 5495c1be472b..bcab50e2a9eb 100644
--- a/arch/powerpc/sysdev/cpm2_pic.c
+++ b/arch/powerpc/sysdev/cpm2_pic.c
@@ -81,7 +81,7 @@ static const u_char irq_to_siubit[] = {
static void cpm2_mask_irq(struct irq_data *d)
{
int bit, word;
- unsigned int irq_nr = virq_to_hw(d->irq);
+ unsigned int irq_nr = irqd_to_hwirq(d);
bit = irq_to_siubit[irq_nr];
word = irq_to_siureg[irq_nr];
@@ -93,7 +93,7 @@ static void cpm2_mask_irq(struct irq_data *d)
static void cpm2_unmask_irq(struct irq_data *d)
{
int bit, word;
- unsigned int irq_nr = virq_to_hw(d->irq);
+ unsigned int irq_nr = irqd_to_hwirq(d);
bit = irq_to_siubit[irq_nr];
word = irq_to_siureg[irq_nr];
@@ -105,7 +105,7 @@ static void cpm2_unmask_irq(struct irq_data *d)
static void cpm2_ack(struct irq_data *d)
{
int bit, word;
- unsigned int irq_nr = virq_to_hw(d->irq);
+ unsigned int irq_nr = irqd_to_hwirq(d);
bit = irq_to_siubit[irq_nr];
word = irq_to_siureg[irq_nr];
@@ -116,7 +116,7 @@ static void cpm2_ack(struct irq_data *d)
static void cpm2_end_irq(struct irq_data *d)
{
int bit, word;
- unsigned int irq_nr = virq_to_hw(d->irq);
+ unsigned int irq_nr = irqd_to_hwirq(d);
bit = irq_to_siubit[irq_nr];
word = irq_to_siureg[irq_nr];
@@ -133,7 +133,7 @@ static void cpm2_end_irq(struct irq_data *d)
static int cpm2_set_irq_type(struct irq_data *d, unsigned int flow_type)
{
- unsigned int src = virq_to_hw(d->irq);
+ unsigned int src = irqd_to_hwirq(d);
unsigned int vold, vnew, edibit;
/* Port C interrupts are either IRQ_TYPE_EDGE_FALLING or
diff --git a/arch/powerpc/sysdev/fsl_85xx_cache_sram.c b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c
index 54fb1922fe30..116415899176 100644
--- a/arch/powerpc/sysdev/fsl_85xx_cache_sram.c
+++ b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c
@@ -106,10 +106,10 @@ int __init instantiate_cache_sram(struct platform_device *dev,
goto out_free;
}
- cache_sram->base_virt = ioremap_flags(cache_sram->base_phys,
+ cache_sram->base_virt = ioremap_prot(cache_sram->base_phys,
cache_sram->size, _PAGE_COHERENT | PAGE_KERNEL);
if (!cache_sram->base_virt) {
- dev_err(&dev->dev, "%s: ioremap_flags failed\n",
+ dev_err(&dev->dev, "%s: ioremap_prot failed\n",
dev->dev.of_node->full_name);
ret = -ENOMEM;
goto out_release;
diff --git a/arch/powerpc/sysdev/fsl_lbc.c b/arch/powerpc/sysdev/fsl_lbc.c
index 4fcb5a4e60dd..0608b1657da4 100644
--- a/arch/powerpc/sysdev/fsl_lbc.c
+++ b/arch/powerpc/sysdev/fsl_lbc.c
@@ -184,7 +184,8 @@ int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar)
}
EXPORT_SYMBOL(fsl_upm_run_pattern);
-static int __devinit fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl)
+static int __devinit fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl,
+ struct device_node *node)
{
struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
@@ -198,6 +199,10 @@ static int __devinit fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl)
/* Enable interrupts for any detected events */
out_be32(&lbc->lteir, LTEIR_ENABLE);
+ /* Set the monitor timeout value to the maximum for erratum A001 */
+ if (of_device_is_compatible(node, "fsl,elbc"))
+ clrsetbits_be32(&lbc->lbcr, LBCR_BMT, LBCR_BMTPS);
+
return 0;
}
@@ -304,7 +309,7 @@ static int __devinit fsl_lbc_ctrl_probe(struct platform_device *dev)
fsl_lbc_ctrl_dev->dev = &dev->dev;
- ret = fsl_lbc_ctrl_init(fsl_lbc_ctrl_dev);
+ ret = fsl_lbc_ctrl_init(fsl_lbc_ctrl_dev, dev->dev.of_node);
if (ret < 0)
goto err;
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index 01cd2f089512..92e78333c47c 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -110,7 +110,7 @@ static void fsl_teardown_msi_irqs(struct pci_dev *pdev)
list_for_each_entry(entry, &pdev->msi_list, list) {
if (entry->irq == NO_IRQ)
continue;
- msi_data = irq_get_handler_data(entry->irq);
+ msi_data = irq_get_chip_data(entry->irq);
irq_set_msi_desc(entry->irq, NULL);
msi_bitmap_free_hwirqs(&msi_data->bitmap,
virq_to_hw(entry->irq), 1);
@@ -168,7 +168,7 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
rc = -ENOSPC;
goto out_free;
}
- irq_set_handler_data(virq, msi_data);
+ /* chip_data is msi_data via host->hostdata in host->map() */
irq_set_msi_desc(virq, entry);
fsl_compose_msi_msg(pdev, hwirq, &msg, msi_data);
@@ -193,7 +193,7 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
u32 have_shift = 0;
struct fsl_msi_cascade_data *cascade_data;
- cascade_data = (struct fsl_msi_cascade_data *)irq_get_handler_data(irq);
+ cascade_data = irq_get_handler_data(irq);
msi_data = cascade_data->msi_data;
raw_spin_lock(&desc->lock);
@@ -253,7 +253,7 @@ unlock:
static int fsl_of_msi_remove(struct platform_device *ofdev)
{
- struct fsl_msi *msi = ofdev->dev.platform_data;
+ struct fsl_msi *msi = platform_get_drvdata(ofdev);
int virq, i;
struct fsl_msi_cascade_data *cascade_data;
@@ -330,7 +330,7 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev)
dev_err(&dev->dev, "No memory for MSI structure\n");
return -ENOMEM;
}
- dev->dev.platform_data = msi;
+ platform_set_drvdata(dev, msi);
msi->irqhost = irq_alloc_host(dev->dev.of_node, IRQ_HOST_MAP_LINEAR,
NR_MSI_IRQS, &fsl_msi_host_ops, 0);
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c
index 49798532b477..5b206a2fe17c 100644
--- a/arch/powerpc/sysdev/fsl_rio.c
+++ b/arch/powerpc/sysdev/fsl_rio.c
@@ -10,7 +10,7 @@
* - Added Port-Write message handling
* - Added Machine Check exception handling
*
- * Copyright (C) 2007, 2008 Freescale Semiconductor, Inc.
+ * Copyright (C) 2007, 2008, 2010 Freescale Semiconductor, Inc.
* Zhang Wei <wei.zhang@freescale.com>
*
* Copyright 2005 MontaVista Software, Inc.
@@ -47,15 +47,33 @@
#define IRQ_RIO_RX(m) (((struct rio_priv *)(m->priv))->rxirq)
#define IRQ_RIO_PW(m) (((struct rio_priv *)(m->priv))->pwirq)
+#define IPWSR_CLEAR 0x98
+#define OMSR_CLEAR 0x1cb3
+#define IMSR_CLEAR 0x491
+#define IDSR_CLEAR 0x91
+#define ODSR_CLEAR 0x1c00
+#define LTLEECSR_ENABLE_ALL 0xFFC000FC
+#define ESCSR_CLEAR 0x07120204
+
+#define RIO_PORT1_EDCSR 0x0640
+#define RIO_PORT2_EDCSR 0x0680
+#define RIO_PORT1_IECSR 0x10130
+#define RIO_PORT2_IECSR 0x101B0
+#define RIO_IM0SR 0x13064
+#define RIO_IM1SR 0x13164
+#define RIO_OM0SR 0x13004
+#define RIO_OM1SR 0x13104
+
#define RIO_ATMU_REGS_OFFSET 0x10c00
#define RIO_P_MSG_REGS_OFFSET 0x11000
#define RIO_S_MSG_REGS_OFFSET 0x13000
#define RIO_GCCSR 0x13c
#define RIO_ESCSR 0x158
+#define RIO_PORT2_ESCSR 0x178
#define RIO_CCSR 0x15c
#define RIO_LTLEDCSR 0x0608
-#define RIO_LTLEDCSR_IER 0x80000000
-#define RIO_LTLEDCSR_PRT 0x01000000
+#define RIO_LTLEDCSR_IER 0x80000000
+#define RIO_LTLEDCSR_PRT 0x01000000
#define RIO_LTLEECSR 0x060c
#define RIO_EPWISR 0x10010
#define RIO_ISR_AACR 0x10120
@@ -88,7 +106,10 @@
#define RIO_IPWSR_PWD 0x00000008
#define RIO_IPWSR_PWB 0x00000004
-#define RIO_EPWISR_PINT 0x80000000
+/* EPWISR Error match value */
+#define RIO_EPWISR_PINT1 0x80000000
+#define RIO_EPWISR_PINT2 0x40000000
+#define RIO_EPWISR_MU 0x00000002
#define RIO_EPWISR_PW 0x00000001
#define RIO_MSG_DESC_SIZE 32
@@ -260,9 +281,7 @@ struct rio_priv {
static void __iomem *rio_regs_win;
#ifdef CONFIG_E500
-static int (*saved_mcheck_exception)(struct pt_regs *regs);
-
-static int fsl_rio_mcheck_exception(struct pt_regs *regs)
+int fsl_rio_mcheck_exception(struct pt_regs *regs)
{
const struct exception_table_entry *entry = NULL;
unsigned long reason = mfspr(SPRN_MCSR);
@@ -284,11 +303,9 @@ static int fsl_rio_mcheck_exception(struct pt_regs *regs)
}
}
- if (saved_mcheck_exception)
- return saved_mcheck_exception(regs);
- else
- return cur_cpu_spec->machine_check(regs);
+ return 0;
}
+EXPORT_SYMBOL_GPL(fsl_rio_mcheck_exception);
#endif
/**
@@ -1064,6 +1081,40 @@ static int fsl_rio_doorbell_init(struct rio_mport *mport)
return rc;
}
+static void port_error_handler(struct rio_mport *port, int offset)
+{
+ /*XXX: Error recovery is not implemented, we just clear errors */
+ out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0);
+
+ if (offset == 0) {
+ out_be32((u32 *)(rio_regs_win + RIO_PORT1_EDCSR), 0);
+ out_be32((u32 *)(rio_regs_win + RIO_PORT1_IECSR), 0);
+ out_be32((u32 *)(rio_regs_win + RIO_ESCSR), ESCSR_CLEAR);
+ } else {
+ out_be32((u32 *)(rio_regs_win + RIO_PORT2_EDCSR), 0);
+ out_be32((u32 *)(rio_regs_win + RIO_PORT2_IECSR), 0);
+ out_be32((u32 *)(rio_regs_win + RIO_PORT2_ESCSR), ESCSR_CLEAR);
+ }
+}
+
+static void msg_unit_error_handler(struct rio_mport *port)
+{
+ struct rio_priv *priv = port->priv;
+
+ /*XXX: Error recovery is not implemented, we just clear errors */
+ out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0);
+
+ out_be32((u32 *)(rio_regs_win + RIO_IM0SR), IMSR_CLEAR);
+ out_be32((u32 *)(rio_regs_win + RIO_IM1SR), IMSR_CLEAR);
+ out_be32((u32 *)(rio_regs_win + RIO_OM0SR), OMSR_CLEAR);
+ out_be32((u32 *)(rio_regs_win + RIO_OM1SR), OMSR_CLEAR);
+
+ out_be32(&priv->msg_regs->odsr, ODSR_CLEAR);
+ out_be32(&priv->msg_regs->dsr, IDSR_CLEAR);
+
+ out_be32(&priv->msg_regs->pwsr, IPWSR_CLEAR);
+}
+
/**
* fsl_rio_port_write_handler - MPC85xx port write interrupt handler
* @irq: Linux interrupt number
@@ -1144,10 +1195,22 @@ fsl_rio_port_write_handler(int irq, void *dev_instance)
}
pw_done:
- if (epwisr & RIO_EPWISR_PINT) {
+ if (epwisr & RIO_EPWISR_PINT1) {
+ tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
+ pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
+ port_error_handler(port, 0);
+ }
+
+ if (epwisr & RIO_EPWISR_PINT2) {
tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
- out_be32(priv->regs_win + RIO_LTLEDCSR, 0);
+ port_error_handler(port, 1);
+ }
+
+ if (epwisr & RIO_EPWISR_MU) {
+ tmp = in_be32(priv->regs_win + RIO_LTLEDCSR);
+ pr_debug("RIO_LTLEDCSR = 0x%x\n", tmp);
+ msg_unit_error_handler(port);
}
return IRQ_HANDLED;
@@ -1258,12 +1321,14 @@ static int fsl_rio_port_write_init(struct rio_mport *mport)
/* Hook up port-write handler */
- rc = request_irq(IRQ_RIO_PW(mport), fsl_rio_port_write_handler, 0,
- "port-write", (void *)mport);
+ rc = request_irq(IRQ_RIO_PW(mport), fsl_rio_port_write_handler,
+ IRQF_SHARED, "port-write", (void *)mport);
if (rc < 0) {
pr_err("MPC85xx RIO: unable to request inbound doorbell irq");
goto err_out;
}
+ /* Enable Error Interrupt */
+ out_be32((u32 *)(rio_regs_win + RIO_LTLEECSR), LTLEECSR_ENABLE_ALL);
INIT_WORK(&priv->pw_work, fsl_pw_dpc);
spin_lock_init(&priv->pw_fifo_lock);
@@ -1538,11 +1603,6 @@ int fsl_rio_setup(struct platform_device *dev)
fsl_rio_doorbell_init(port);
fsl_rio_port_write_init(port);
-#ifdef CONFIG_E500
- saved_mcheck_exception = ppc_md.machine_check_exception;
- ppc_md.machine_check_exception = fsl_rio_mcheck_exception;
-#endif
-
return 0;
err:
iounmap(priv->regs_win);
diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c
index 142770cb84b6..d18bb27e4df9 100644
--- a/arch/powerpc/sysdev/i8259.c
+++ b/arch/powerpc/sysdev/i8259.c
@@ -185,18 +185,6 @@ static int i8259_host_map(struct irq_host *h, unsigned int virq,
return 0;
}
-static void i8259_host_unmap(struct irq_host *h, unsigned int virq)
-{
- /* Make sure irq is masked in hardware */
- i8259_mask_irq(irq_get_irq_data(virq));
-
- /* remove chip and handler */
- irq_set_chip_and_handler(virq, NULL, NULL);
-
- /* Make sure it's completed */
- synchronize_irq(virq);
-}
-
static int i8259_host_xlate(struct irq_host *h, struct device_node *ct,
const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq, unsigned int *out_flags)
@@ -220,7 +208,6 @@ static int i8259_host_xlate(struct irq_host *h, struct device_node *ct,
static struct irq_host_ops i8259_host_ops = {
.match = i8259_host_match,
.map = i8259_host_map,
- .unmap = i8259_host_unmap,
.xlate = i8259_host_xlate,
};
diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c
index fa438be962b7..7367d17364cb 100644
--- a/arch/powerpc/sysdev/ipic.c
+++ b/arch/powerpc/sysdev/ipic.c
@@ -18,7 +18,7 @@
#include <linux/stddef.h>
#include <linux/sched.h>
#include <linux/signal.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/device.h>
#include <linux/bootmem.h>
#include <linux/spinlock.h>
@@ -521,12 +521,10 @@ static inline struct ipic * ipic_from_irq(unsigned int virq)
return primary_ipic;
}
-#define ipic_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq)
-
static void ipic_unmask_irq(struct irq_data *d)
{
struct ipic *ipic = ipic_from_irq(d->irq);
- unsigned int src = ipic_irq_to_hw(d->irq);
+ unsigned int src = irqd_to_hwirq(d);
unsigned long flags;
u32 temp;
@@ -542,7 +540,7 @@ static void ipic_unmask_irq(struct irq_data *d)
static void ipic_mask_irq(struct irq_data *d)
{
struct ipic *ipic = ipic_from_irq(d->irq);
- unsigned int src = ipic_irq_to_hw(d->irq);
+ unsigned int src = irqd_to_hwirq(d);
unsigned long flags;
u32 temp;
@@ -562,7 +560,7 @@ static void ipic_mask_irq(struct irq_data *d)
static void ipic_ack_irq(struct irq_data *d)
{
struct ipic *ipic = ipic_from_irq(d->irq);
- unsigned int src = ipic_irq_to_hw(d->irq);
+ unsigned int src = irqd_to_hwirq(d);
unsigned long flags;
u32 temp;
@@ -581,7 +579,7 @@ static void ipic_ack_irq(struct irq_data *d)
static void ipic_mask_irq_and_ack(struct irq_data *d)
{
struct ipic *ipic = ipic_from_irq(d->irq);
- unsigned int src = ipic_irq_to_hw(d->irq);
+ unsigned int src = irqd_to_hwirq(d);
unsigned long flags;
u32 temp;
@@ -604,7 +602,7 @@ static void ipic_mask_irq_and_ack(struct irq_data *d)
static int ipic_set_irq_type(struct irq_data *d, unsigned int flow_type)
{
struct ipic *ipic = ipic_from_irq(d->irq);
- unsigned int src = ipic_irq_to_hw(d->irq);
+ unsigned int src = irqd_to_hwirq(d);
unsigned int vold, vnew, edibit;
if (flow_type == IRQ_TYPE_NONE)
@@ -793,7 +791,7 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags)
int ipic_set_priority(unsigned int virq, unsigned int priority)
{
struct ipic *ipic = ipic_from_irq(virq);
- unsigned int src = ipic_irq_to_hw(virq);
+ unsigned int src = virq_to_hw(virq);
u32 temp;
if (priority > 7)
@@ -821,7 +819,7 @@ int ipic_set_priority(unsigned int virq, unsigned int priority)
void ipic_set_highest_priority(unsigned int virq)
{
struct ipic *ipic = ipic_from_irq(virq);
- unsigned int src = ipic_irq_to_hw(virq);
+ unsigned int src = virq_to_hw(virq);
u32 temp;
temp = ipic_read(ipic->regs, IPIC_SICFR);
@@ -902,7 +900,7 @@ static struct {
u32 sercr;
} ipic_saved_state;
-static int ipic_suspend(struct sys_device *sdev, pm_message_t state)
+static int ipic_suspend(void)
{
struct ipic *ipic = primary_ipic;
@@ -933,7 +931,7 @@ static int ipic_suspend(struct sys_device *sdev, pm_message_t state)
return 0;
}
-static int ipic_resume(struct sys_device *sdev)
+static void ipic_resume(void)
{
struct ipic *ipic = primary_ipic;
@@ -949,44 +947,26 @@ static int ipic_resume(struct sys_device *sdev)
ipic_write(ipic->regs, IPIC_SECNR, ipic_saved_state.secnr);
ipic_write(ipic->regs, IPIC_SERMR, ipic_saved_state.sermr);
ipic_write(ipic->regs, IPIC_SERCR, ipic_saved_state.sercr);
-
- return 0;
}
#else
#define ipic_suspend NULL
#define ipic_resume NULL
#endif
-static struct sysdev_class ipic_sysclass = {
- .name = "ipic",
+static struct syscore_ops ipic_syscore_ops = {
.suspend = ipic_suspend,
.resume = ipic_resume,
};
-static struct sys_device device_ipic = {
- .id = 0,
- .cls = &ipic_sysclass,
-};
-
-static int __init init_ipic_sysfs(void)
+static int __init init_ipic_syscore(void)
{
- int rc;
-
if (!primary_ipic || !primary_ipic->regs)
return -ENODEV;
- printk(KERN_DEBUG "Registering ipic with sysfs...\n");
- rc = sysdev_class_register(&ipic_sysclass);
- if (rc) {
- printk(KERN_ERR "Failed registering ipic sys class\n");
- return -ENODEV;
- }
- rc = sysdev_register(&device_ipic);
- if (rc) {
- printk(KERN_ERR "Failed registering ipic sys device\n");
- return -ENODEV;
- }
+ printk(KERN_DEBUG "Registering ipic system core operations\n");
+ register_syscore_ops(&ipic_syscore_ops);
+
return 0;
}
-subsys_initcall(init_ipic_sysfs);
+subsys_initcall(init_ipic_syscore);
diff --git a/arch/powerpc/sysdev/mmio_nvram.c b/arch/powerpc/sysdev/mmio_nvram.c
index 207324209065..ddc877a3a23a 100644
--- a/arch/powerpc/sysdev/mmio_nvram.c
+++ b/arch/powerpc/sysdev/mmio_nvram.c
@@ -115,6 +115,8 @@ int __init mmio_nvram_init(void)
int ret;
nvram_node = of_find_node_by_type(NULL, "nvram");
+ if (!nvram_node)
+ nvram_node = of_find_compatible_node(NULL, NULL, "nvram");
if (!nvram_node) {
printk(KERN_WARNING "nvram: no node found in device-tree\n");
return -ENODEV;
diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c
index a88800ff4d01..20924f2246f0 100644
--- a/arch/powerpc/sysdev/mpc8xx_pic.c
+++ b/arch/powerpc/sysdev/mpc8xx_pic.c
@@ -28,7 +28,7 @@ int cpm_get_irq(struct pt_regs *regs);
static void mpc8xx_unmask_irq(struct irq_data *d)
{
int bit, word;
- unsigned int irq_nr = (unsigned int)irq_map[d->irq].hwirq;
+ unsigned int irq_nr = (unsigned int)irqd_to_hwirq(d);
bit = irq_nr & 0x1f;
word = irq_nr >> 5;
@@ -40,7 +40,7 @@ static void mpc8xx_unmask_irq(struct irq_data *d)
static void mpc8xx_mask_irq(struct irq_data *d)
{
int bit, word;
- unsigned int irq_nr = (unsigned int)irq_map[d->irq].hwirq;
+ unsigned int irq_nr = (unsigned int)irqd_to_hwirq(d);
bit = irq_nr & 0x1f;
word = irq_nr >> 5;
@@ -52,7 +52,7 @@ static void mpc8xx_mask_irq(struct irq_data *d)
static void mpc8xx_ack(struct irq_data *d)
{
int bit;
- unsigned int irq_nr = (unsigned int)irq_map[d->irq].hwirq;
+ unsigned int irq_nr = (unsigned int)irqd_to_hwirq(d);
bit = irq_nr & 0x1f;
out_be32(&siu_reg->sc_sipend, 1 << (31-bit));
@@ -61,7 +61,7 @@ static void mpc8xx_ack(struct irq_data *d)
static void mpc8xx_end_irq(struct irq_data *d)
{
int bit, word;
- unsigned int irq_nr = (unsigned int)irq_map[d->irq].hwirq;
+ unsigned int irq_nr = (unsigned int)irqd_to_hwirq(d);
bit = irq_nr & 0x1f;
word = irq_nr >> 5;
@@ -73,7 +73,7 @@ static void mpc8xx_end_irq(struct irq_data *d)
static int mpc8xx_set_irq_type(struct irq_data *d, unsigned int flow_type)
{
if (flow_type & IRQ_TYPE_EDGE_FALLING) {
- irq_hw_number_t hw = (unsigned int)irq_map[d->irq].hwirq;
+ irq_hw_number_t hw = (unsigned int)irqd_to_hwirq(d);
unsigned int siel = in_be32(&siu_reg->sc_siel);
/* only external IRQ senses are programmable */
diff --git a/arch/powerpc/sysdev/mpc8xxx_gpio.c b/arch/powerpc/sysdev/mpc8xxx_gpio.c
index 0892a2841c2b..fb4963abdf55 100644
--- a/arch/powerpc/sysdev/mpc8xxx_gpio.c
+++ b/arch/powerpc/sysdev/mpc8xxx_gpio.c
@@ -163,7 +163,7 @@ static void mpc8xxx_irq_unmask(struct irq_data *d)
spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
- setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(virq_to_hw(d->irq)));
+ setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
}
@@ -176,7 +176,7 @@ static void mpc8xxx_irq_mask(struct irq_data *d)
spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
- clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(virq_to_hw(d->irq)));
+ clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
}
@@ -186,7 +186,7 @@ static void mpc8xxx_irq_ack(struct irq_data *d)
struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
- out_be32(mm->regs + GPIO_IER, mpc8xxx_gpio2mask(virq_to_hw(d->irq)));
+ out_be32(mm->regs + GPIO_IER, mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
}
static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
@@ -199,14 +199,14 @@ static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
case IRQ_TYPE_EDGE_FALLING:
spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
setbits32(mm->regs + GPIO_ICR,
- mpc8xxx_gpio2mask(virq_to_hw(d->irq)));
+ mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
break;
case IRQ_TYPE_EDGE_BOTH:
spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
clrbits32(mm->regs + GPIO_ICR,
- mpc8xxx_gpio2mask(virq_to_hw(d->irq)));
+ mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
break;
@@ -221,7 +221,7 @@ static int mpc512x_irq_set_type(struct irq_data *d, unsigned int flow_type)
{
struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
- unsigned long gpio = virq_to_hw(d->irq);
+ unsigned long gpio = irqd_to_hwirq(d);
void __iomem *reg;
unsigned int shift;
unsigned long flags;
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index f91c065bed5a..3a8de5bb628a 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -6,6 +6,7 @@
* with various broken implementations of this HW.
*
* Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp.
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
@@ -27,6 +28,7 @@
#include <linux/spinlock.h>
#include <linux/pci.h>
#include <linux/slab.h>
+#include <linux/syscore_ops.h>
#include <asm/ptrace.h>
#include <asm/signal.h>
@@ -218,6 +220,28 @@ static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 valu
_mpic_write(mpic->reg_type, &mpic->gregs, offset, value);
}
+static inline u32 _mpic_tm_read(struct mpic *mpic, unsigned int tm)
+{
+ unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) +
+ ((tm & 3) * MPIC_INFO(TIMER_STRIDE));
+
+ if (tm >= 4)
+ offset += 0x1000 / 4;
+
+ return _mpic_read(mpic->reg_type, &mpic->tmregs, offset);
+}
+
+static inline void _mpic_tm_write(struct mpic *mpic, unsigned int tm, u32 value)
+{
+ unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) +
+ ((tm & 3) * MPIC_INFO(TIMER_STRIDE));
+
+ if (tm >= 4)
+ offset += 0x1000 / 4;
+
+ _mpic_write(mpic->reg_type, &mpic->tmregs, offset, value);
+}
+
static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg)
{
unsigned int cpu = mpic_processor_id(mpic);
@@ -268,6 +292,8 @@ static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no,
#define mpic_write(b,r,v) _mpic_write(mpic->reg_type,&(b),(r),(v))
#define mpic_ipi_read(i) _mpic_ipi_read(mpic,(i))
#define mpic_ipi_write(i,v) _mpic_ipi_write(mpic,(i),(v))
+#define mpic_tm_read(i) _mpic_tm_read(mpic,(i))
+#define mpic_tm_write(i,v) _mpic_tm_write(mpic,(i),(v))
#define mpic_cpu_read(i) _mpic_cpu_read(mpic,(i))
#define mpic_cpu_write(i,v) _mpic_cpu_write(mpic,(i),(v))
#define mpic_irq_read(s,r) _mpic_irq_read(mpic,(s),(r))
@@ -607,8 +633,6 @@ static int irq_choose_cpu(const struct cpumask *mask)
}
#endif
-#define mpic_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq)
-
/* Find an mpic associated with a given linux interrupt */
static struct mpic *mpic_find(unsigned int irq)
{
@@ -621,11 +645,18 @@ static struct mpic *mpic_find(unsigned int irq)
/* Determine if the linux irq is an IPI */
static unsigned int mpic_is_ipi(struct mpic *mpic, unsigned int irq)
{
- unsigned int src = mpic_irq_to_hw(irq);
+ unsigned int src = virq_to_hw(irq);
return (src >= mpic->ipi_vecs[0] && src <= mpic->ipi_vecs[3]);
}
+/* Determine if the linux irq is a timer */
+static unsigned int mpic_is_tm(struct mpic *mpic, unsigned int irq)
+{
+ unsigned int src = virq_to_hw(irq);
+
+ return (src >= mpic->timer_vecs[0] && src <= mpic->timer_vecs[7]);
+}
/* Convert a cpu mask from logical to physical cpu numbers. */
static inline u32 mpic_physmask(u32 cpumask)
@@ -633,7 +664,7 @@ static inline u32 mpic_physmask(u32 cpumask)
int i;
u32 mask = 0;
- for (i = 0; i < NR_CPUS; ++i, cpumask >>= 1)
+ for (i = 0; i < min(32, NR_CPUS); ++i, cpumask >>= 1)
mask |= (cpumask & 1) << get_hard_smp_processor_id(i);
return mask;
}
@@ -674,7 +705,7 @@ void mpic_unmask_irq(struct irq_data *d)
{
unsigned int loops = 100000;
struct mpic *mpic = mpic_from_irq_data(d);
- unsigned int src = mpic_irq_to_hw(d->irq);
+ unsigned int src = irqd_to_hwirq(d);
DBG("%p: %s: enable_irq: %d (src %d)\n", mpic, mpic->name, d->irq, src);
@@ -695,7 +726,7 @@ void mpic_mask_irq(struct irq_data *d)
{
unsigned int loops = 100000;
struct mpic *mpic = mpic_from_irq_data(d);
- unsigned int src = mpic_irq_to_hw(d->irq);
+ unsigned int src = irqd_to_hwirq(d);
DBG("%s: disable_irq: %d (src %d)\n", mpic->name, d->irq, src);
@@ -733,7 +764,7 @@ void mpic_end_irq(struct irq_data *d)
static void mpic_unmask_ht_irq(struct irq_data *d)
{
struct mpic *mpic = mpic_from_irq_data(d);
- unsigned int src = mpic_irq_to_hw(d->irq);
+ unsigned int src = irqd_to_hwirq(d);
mpic_unmask_irq(d);
@@ -744,7 +775,7 @@ static void mpic_unmask_ht_irq(struct irq_data *d)
static unsigned int mpic_startup_ht_irq(struct irq_data *d)
{
struct mpic *mpic = mpic_from_irq_data(d);
- unsigned int src = mpic_irq_to_hw(d->irq);
+ unsigned int src = irqd_to_hwirq(d);
mpic_unmask_irq(d);
mpic_startup_ht_interrupt(mpic, src, irqd_is_level_type(d));
@@ -755,7 +786,7 @@ static unsigned int mpic_startup_ht_irq(struct irq_data *d)
static void mpic_shutdown_ht_irq(struct irq_data *d)
{
struct mpic *mpic = mpic_from_irq_data(d);
- unsigned int src = mpic_irq_to_hw(d->irq);
+ unsigned int src = irqd_to_hwirq(d);
mpic_shutdown_ht_interrupt(mpic, src);
mpic_mask_irq(d);
@@ -764,7 +795,7 @@ static void mpic_shutdown_ht_irq(struct irq_data *d)
static void mpic_end_ht_irq(struct irq_data *d)
{
struct mpic *mpic = mpic_from_irq_data(d);
- unsigned int src = mpic_irq_to_hw(d->irq);
+ unsigned int src = irqd_to_hwirq(d);
#ifdef DEBUG_IRQ
DBG("%s: end_irq: %d\n", mpic->name, d->irq);
@@ -785,7 +816,7 @@ static void mpic_end_ht_irq(struct irq_data *d)
static void mpic_unmask_ipi(struct irq_data *d)
{
struct mpic *mpic = mpic_from_ipi(d);
- unsigned int src = mpic_irq_to_hw(d->irq) - mpic->ipi_vecs[0];
+ unsigned int src = virq_to_hw(d->irq) - mpic->ipi_vecs[0];
DBG("%s: enable_ipi: %d (ipi %d)\n", mpic->name, d->irq, src);
mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK);
@@ -812,27 +843,42 @@ static void mpic_end_ipi(struct irq_data *d)
#endif /* CONFIG_SMP */
+static void mpic_unmask_tm(struct irq_data *d)
+{
+ struct mpic *mpic = mpic_from_irq_data(d);
+ unsigned int src = virq_to_hw(d->irq) - mpic->timer_vecs[0];
+
+ DBG("%s: enable_tm: %d (tm %d)\n", mpic->name, irq, src);
+ mpic_tm_write(src, mpic_tm_read(src) & ~MPIC_VECPRI_MASK);
+ mpic_tm_read(src);
+}
+
+static void mpic_mask_tm(struct irq_data *d)
+{
+ struct mpic *mpic = mpic_from_irq_data(d);
+ unsigned int src = virq_to_hw(d->irq) - mpic->timer_vecs[0];
+
+ mpic_tm_write(src, mpic_tm_read(src) | MPIC_VECPRI_MASK);
+ mpic_tm_read(src);
+}
+
int mpic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
bool force)
{
struct mpic *mpic = mpic_from_irq_data(d);
- unsigned int src = mpic_irq_to_hw(d->irq);
+ unsigned int src = irqd_to_hwirq(d);
if (mpic->flags & MPIC_SINGLE_DEST_CPU) {
int cpuid = irq_choose_cpu(cpumask);
mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid);
} else {
- cpumask_var_t tmp;
-
- alloc_cpumask_var(&tmp, GFP_KERNEL);
+ u32 mask = cpumask_bits(cpumask)[0];
- cpumask_and(tmp, cpumask, cpu_online_mask);
+ mask &= cpumask_bits(cpu_online_mask)[0];
mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION),
- mpic_physmask(cpumask_bits(tmp)[0]));
-
- free_cpumask_var(tmp);
+ mpic_physmask(mask));
}
return 0;
@@ -862,7 +908,7 @@ static unsigned int mpic_type_to_vecpri(struct mpic *mpic, unsigned int type)
int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type)
{
struct mpic *mpic = mpic_from_irq_data(d);
- unsigned int src = mpic_irq_to_hw(d->irq);
+ unsigned int src = irqd_to_hwirq(d);
unsigned int vecpri, vold, vnew;
DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n",
@@ -898,7 +944,7 @@ int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type)
void mpic_set_vector(unsigned int virq, unsigned int vector)
{
struct mpic *mpic = mpic_from_irq(virq);
- unsigned int src = mpic_irq_to_hw(virq);
+ unsigned int src = virq_to_hw(virq);
unsigned int vecpri;
DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n",
@@ -916,7 +962,7 @@ void mpic_set_vector(unsigned int virq, unsigned int vector)
void mpic_set_destination(unsigned int virq, unsigned int cpuid)
{
struct mpic *mpic = mpic_from_irq(virq);
- unsigned int src = mpic_irq_to_hw(virq);
+ unsigned int src = virq_to_hw(virq);
DBG("mpic: set_destination(mpic:@%p,virq:%d,src:%d,cpuid:0x%x)\n",
mpic, virq, src, cpuid);
@@ -942,6 +988,12 @@ static struct irq_chip mpic_ipi_chip = {
};
#endif /* CONFIG_SMP */
+static struct irq_chip mpic_tm_chip = {
+ .irq_mask = mpic_mask_tm,
+ .irq_unmask = mpic_unmask_tm,
+ .irq_eoi = mpic_end_irq,
+};
+
#ifdef CONFIG_MPIC_U3_HT_IRQS
static struct irq_chip mpic_irq_ht_chip = {
.irq_startup = mpic_startup_ht_irq,
@@ -985,6 +1037,16 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq,
}
#endif /* CONFIG_SMP */
+ if (hw >= mpic->timer_vecs[0] && hw <= mpic->timer_vecs[7]) {
+ WARN_ON(!(mpic->flags & MPIC_PRIMARY));
+
+ DBG("mpic: mapping as timer\n");
+ irq_set_chip_data(virq, mpic);
+ irq_set_chip_and_handler(virq, &mpic->hc_tm,
+ handle_fasteoi_irq);
+ return 0;
+ }
+
if (hw >= mpic->irq_count)
return -EINVAL;
@@ -1025,6 +1087,7 @@ static int mpic_host_xlate(struct irq_host *h, struct device_node *ct,
irq_hw_number_t *out_hwirq, unsigned int *out_flags)
{
+ struct mpic *mpic = h->host_data;
static unsigned char map_mpic_senses[4] = {
IRQ_TYPE_EDGE_RISING,
IRQ_TYPE_LEVEL_LOW,
@@ -1033,7 +1096,38 @@ static int mpic_host_xlate(struct irq_host *h, struct device_node *ct,
};
*out_hwirq = intspec[0];
- if (intsize > 1) {
+ if (intsize >= 4 && (mpic->flags & MPIC_FSL)) {
+ /*
+ * Freescale MPIC with extended intspec:
+ * First two cells are as usual. Third specifies
+ * an "interrupt type". Fourth is type-specific data.
+ *
+ * See Documentation/devicetree/bindings/powerpc/fsl/mpic.txt
+ */
+ switch (intspec[2]) {
+ case 0:
+ case 1: /* no EISR/EIMR support for now, treat as shared IRQ */
+ break;
+ case 2:
+ if (intspec[0] >= ARRAY_SIZE(mpic->ipi_vecs))
+ return -EINVAL;
+
+ *out_hwirq = mpic->ipi_vecs[intspec[0]];
+ break;
+ case 3:
+ if (intspec[0] >= ARRAY_SIZE(mpic->timer_vecs))
+ return -EINVAL;
+
+ *out_hwirq = mpic->timer_vecs[intspec[0]];
+ break;
+ default:
+ pr_debug("%s: unknown irq type %u\n",
+ __func__, intspec[2]);
+ return -EINVAL;
+ }
+
+ *out_flags = map_mpic_senses[intspec[1] & 3];
+ } else if (intsize > 1) {
u32 mask = 0x3;
/* Apple invented a new race of encoding on machines with
@@ -1109,6 +1203,9 @@ struct mpic * __init mpic_alloc(struct device_node *node,
mpic->hc_ipi.name = name;
#endif /* CONFIG_SMP */
+ mpic->hc_tm = mpic_tm_chip;
+ mpic->hc_tm.name = name;
+
mpic->flags = flags;
mpic->isu_size = isu_size;
mpic->irq_count = irq_count;
@@ -1119,10 +1216,14 @@ struct mpic * __init mpic_alloc(struct device_node *node,
else
intvec_top = 255;
- mpic->timer_vecs[0] = intvec_top - 8;
- mpic->timer_vecs[1] = intvec_top - 7;
- mpic->timer_vecs[2] = intvec_top - 6;
- mpic->timer_vecs[3] = intvec_top - 5;
+ mpic->timer_vecs[0] = intvec_top - 12;
+ mpic->timer_vecs[1] = intvec_top - 11;
+ mpic->timer_vecs[2] = intvec_top - 10;
+ mpic->timer_vecs[3] = intvec_top - 9;
+ mpic->timer_vecs[4] = intvec_top - 8;
+ mpic->timer_vecs[5] = intvec_top - 7;
+ mpic->timer_vecs[6] = intvec_top - 6;
+ mpic->timer_vecs[7] = intvec_top - 5;
mpic->ipi_vecs[0] = intvec_top - 4;
mpic->ipi_vecs[1] = intvec_top - 3;
mpic->ipi_vecs[2] = intvec_top - 2;
@@ -1132,6 +1233,8 @@ struct mpic * __init mpic_alloc(struct device_node *node,
/* Check for "big-endian" in device-tree */
if (node && of_get_property(node, "big-endian", NULL) != NULL)
mpic->flags |= MPIC_BIG_ENDIAN;
+ if (node && of_device_is_compatible(node, "fsl,mpic"))
+ mpic->flags |= MPIC_FSL;
/* Look for protected sources */
if (node) {
@@ -1323,15 +1426,17 @@ void __init mpic_init(struct mpic *mpic)
/* Set current processor priority to max */
mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf);
- /* Initialize timers: just disable them all */
+ /* Initialize timers to our reserved vectors and mask them for now */
for (i = 0; i < 4; i++) {
mpic_write(mpic->tmregs,
i * MPIC_INFO(TIMER_STRIDE) +
- MPIC_INFO(TIMER_DESTINATION), 0);
+ MPIC_INFO(TIMER_DESTINATION),
+ 1 << hard_smp_processor_id());
mpic_write(mpic->tmregs,
i * MPIC_INFO(TIMER_STRIDE) +
MPIC_INFO(TIMER_VECTOR_PRI),
MPIC_VECPRI_MASK |
+ (9 << MPIC_VECPRI_PRIORITY_SHIFT) |
(mpic->timer_vecs[0] + i));
}
@@ -1427,7 +1532,7 @@ void __init mpic_set_serial_int(struct mpic *mpic, int enable)
void mpic_irq_set_priority(unsigned int irq, unsigned int pri)
{
struct mpic *mpic = mpic_find(irq);
- unsigned int src = mpic_irq_to_hw(irq);
+ unsigned int src = virq_to_hw(irq);
unsigned long flags;
u32 reg;
@@ -1440,6 +1545,11 @@ void mpic_irq_set_priority(unsigned int irq, unsigned int pri)
~MPIC_VECPRI_PRIORITY_MASK;
mpic_ipi_write(src - mpic->ipi_vecs[0],
reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT));
+ } else if (mpic_is_tm(mpic, irq)) {
+ reg = mpic_tm_read(src - mpic->timer_vecs[0]) &
+ ~MPIC_VECPRI_PRIORITY_MASK;
+ mpic_tm_write(src - mpic->timer_vecs[0],
+ reg | (pri << MPIC_VECPRI_PRIORITY_SHIFT));
} else {
reg = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI))
& ~MPIC_VECPRI_PRIORITY_MASK;
@@ -1619,46 +1729,28 @@ void mpic_request_ipis(void)
}
}
-static void mpic_send_ipi(unsigned int ipi_no, const struct cpumask *cpu_mask)
+void smp_mpic_message_pass(int cpu, int msg)
{
struct mpic *mpic = mpic_primary;
+ u32 physmask;
BUG_ON(mpic == NULL);
-#ifdef DEBUG_IPI
- DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, ipi_no);
-#endif
-
- mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) +
- ipi_no * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE),
- mpic_physmask(cpumask_bits(cpu_mask)[0]));
-}
-
-void smp_mpic_message_pass(int target, int msg)
-{
- cpumask_var_t tmp;
-
/* make sure we're sending something that translates to an IPI */
if ((unsigned int)msg > 3) {
printk("SMP %d: smp_message_pass: unknown msg %d\n",
smp_processor_id(), msg);
return;
}
- switch (target) {
- case MSG_ALL:
- mpic_send_ipi(msg, cpu_online_mask);
- break;
- case MSG_ALL_BUT_SELF:
- alloc_cpumask_var(&tmp, GFP_NOWAIT);
- cpumask_andnot(tmp, cpu_online_mask,
- cpumask_of(smp_processor_id()));
- mpic_send_ipi(msg, tmp);
- free_cpumask_var(tmp);
- break;
- default:
- mpic_send_ipi(msg, cpumask_of(target));
- break;
- }
+
+#ifdef DEBUG_IPI
+ DBG("%s: send_ipi(ipi_no: %d)\n", mpic->name, msg);
+#endif
+
+ physmask = 1 << get_hard_smp_processor_id(cpu);
+
+ mpic_cpu_write(MPIC_INFO(CPU_IPI_DISPATCH_0) +
+ msg * MPIC_INFO(CPU_IPI_DISPATCH_STRIDE), physmask);
}
int __init smp_mpic_probe(void)
@@ -1702,9 +1794,8 @@ void mpic_reset_core(int cpu)
#endif /* CONFIG_SMP */
#ifdef CONFIG_PM
-static int mpic_suspend(struct sys_device *dev, pm_message_t state)
+static void mpic_suspend_one(struct mpic *mpic)
{
- struct mpic *mpic = container_of(dev, struct mpic, sysdev);
int i;
for (i = 0; i < mpic->num_sources; i++) {
@@ -1713,13 +1804,22 @@ static int mpic_suspend(struct sys_device *dev, pm_message_t state)
mpic->save_data[i].dest =
mpic_irq_read(i, MPIC_INFO(IRQ_DESTINATION));
}
+}
+
+static int mpic_suspend(void)
+{
+ struct mpic *mpic = mpics;
+
+ while (mpic) {
+ mpic_suspend_one(mpic);
+ mpic = mpic->next;
+ }
return 0;
}
-static int mpic_resume(struct sys_device *dev)
+static void mpic_resume_one(struct mpic *mpic)
{
- struct mpic *mpic = container_of(dev, struct mpic, sysdev);
int i;
for (i = 0; i < mpic->num_sources; i++) {
@@ -1746,33 +1846,28 @@ static int mpic_resume(struct sys_device *dev)
}
#endif
} /* end for loop */
+}
- return 0;
+static void mpic_resume(void)
+{
+ struct mpic *mpic = mpics;
+
+ while (mpic) {
+ mpic_resume_one(mpic);
+ mpic = mpic->next;
+ }
}
-#endif
-static struct sysdev_class mpic_sysclass = {
-#ifdef CONFIG_PM
+static struct syscore_ops mpic_syscore_ops = {
.resume = mpic_resume,
.suspend = mpic_suspend,
-#endif
- .name = "mpic",
};
static int mpic_init_sys(void)
{
- struct mpic *mpic = mpics;
- int error, id = 0;
-
- error = sysdev_class_register(&mpic_sysclass);
-
- while (mpic && !error) {
- mpic->sysdev.cls = &mpic_sysclass;
- mpic->sysdev.id = id++;
- error = sysdev_register(&mpic->sysdev);
- mpic = mpic->next;
- }
- return error;
+ register_syscore_ops(&mpic_syscore_ops);
+ return 0;
}
device_initcall(mpic_init_sys);
+#endif
diff --git a/arch/powerpc/sysdev/mv64x60_pic.c b/arch/powerpc/sysdev/mv64x60_pic.c
index e9c633c7c083..14d130268e7a 100644
--- a/arch/powerpc/sysdev/mv64x60_pic.c
+++ b/arch/powerpc/sysdev/mv64x60_pic.c
@@ -78,7 +78,7 @@ static struct irq_host *mv64x60_irq_host;
static void mv64x60_mask_low(struct irq_data *d)
{
- int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK;
+ int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK;
unsigned long flags;
spin_lock_irqsave(&mv64x60_lock, flags);
@@ -91,7 +91,7 @@ static void mv64x60_mask_low(struct irq_data *d)
static void mv64x60_unmask_low(struct irq_data *d)
{
- int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK;
+ int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK;
unsigned long flags;
spin_lock_irqsave(&mv64x60_lock, flags);
@@ -115,7 +115,7 @@ static struct irq_chip mv64x60_chip_low = {
static void mv64x60_mask_high(struct irq_data *d)
{
- int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK;
+ int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK;
unsigned long flags;
spin_lock_irqsave(&mv64x60_lock, flags);
@@ -128,7 +128,7 @@ static void mv64x60_mask_high(struct irq_data *d)
static void mv64x60_unmask_high(struct irq_data *d)
{
- int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK;
+ int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK;
unsigned long flags;
spin_lock_irqsave(&mv64x60_lock, flags);
@@ -152,7 +152,7 @@ static struct irq_chip mv64x60_chip_high = {
static void mv64x60_mask_gpp(struct irq_data *d)
{
- int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK;
+ int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK;
unsigned long flags;
spin_lock_irqsave(&mv64x60_lock, flags);
@@ -165,7 +165,7 @@ static void mv64x60_mask_gpp(struct irq_data *d)
static void mv64x60_mask_ack_gpp(struct irq_data *d)
{
- int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK;
+ int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK;
unsigned long flags;
spin_lock_irqsave(&mv64x60_lock, flags);
@@ -180,7 +180,7 @@ static void mv64x60_mask_ack_gpp(struct irq_data *d)
static void mv64x60_unmask_gpp(struct irq_data *d)
{
- int level2 = irq_map[d->irq].hwirq & MV64x60_LEVEL2_MASK;
+ int level2 = irqd_to_hwirq(d) & MV64x60_LEVEL2_MASK;
unsigned long flags;
spin_lock_irqsave(&mv64x60_lock, flags);
diff --git a/arch/powerpc/sysdev/ppc4xx_msi.c b/arch/powerpc/sysdev/ppc4xx_msi.c
new file mode 100644
index 000000000000..367af0241851
--- /dev/null
+++ b/arch/powerpc/sysdev/ppc4xx_msi.c
@@ -0,0 +1,276 @@
+/*
+ * Adding PCI-E MSI support for PPC4XX SoCs.
+ *
+ * Copyright (c) 2010, Applied Micro Circuits Corporation
+ * Authors: Tirumala R Marri <tmarri@apm.com>
+ * Feng Kan <fkan@apm.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/irq.h>
+#include <linux/bootmem.h>
+#include <linux/pci.h>
+#include <linux/msi.h>
+#include <linux/of_platform.h>
+#include <linux/interrupt.h>
+#include <asm/prom.h>
+#include <asm/hw_irq.h>
+#include <asm/ppc-pci.h>
+#include <boot/dcr.h>
+#include <asm/dcr-regs.h>
+#include <asm/msi_bitmap.h>
+
+#define PEIH_TERMADH 0x00
+#define PEIH_TERMADL 0x08
+#define PEIH_MSIED 0x10
+#define PEIH_MSIMK 0x18
+#define PEIH_MSIASS 0x20
+#define PEIH_FLUSH0 0x30
+#define PEIH_FLUSH1 0x38
+#define PEIH_CNTRST 0x48
+#define NR_MSI_IRQS 4
+
+struct ppc4xx_msi {
+ u32 msi_addr_lo;
+ u32 msi_addr_hi;
+ void __iomem *msi_regs;
+ int msi_virqs[NR_MSI_IRQS];
+ struct msi_bitmap bitmap;
+ struct device_node *msi_dev;
+};
+
+static struct ppc4xx_msi ppc4xx_msi;
+
+static int ppc4xx_msi_init_allocator(struct platform_device *dev,
+ struct ppc4xx_msi *msi_data)
+{
+ int err;
+
+ err = msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS,
+ dev->dev.of_node);
+ if (err)
+ return err;
+
+ err = msi_bitmap_reserve_dt_hwirqs(&msi_data->bitmap);
+ if (err < 0) {
+ msi_bitmap_free(&msi_data->bitmap);
+ return err;
+ }
+
+ return 0;
+}
+
+static int ppc4xx_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+ int int_no = -ENOMEM;
+ unsigned int virq;
+ struct msi_msg msg;
+ struct msi_desc *entry;
+ struct ppc4xx_msi *msi_data = &ppc4xx_msi;
+
+ list_for_each_entry(entry, &dev->msi_list, list) {
+ int_no = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
+ if (int_no >= 0)
+ break;
+ if (int_no < 0) {
+ pr_debug("%s: fail allocating msi interrupt\n",
+ __func__);
+ }
+ virq = irq_of_parse_and_map(msi_data->msi_dev, int_no);
+ if (virq == NO_IRQ) {
+ dev_err(&dev->dev, "%s: fail mapping irq\n", __func__);
+ msi_bitmap_free_hwirqs(&msi_data->bitmap, int_no, 1);
+ return -ENOSPC;
+ }
+ dev_dbg(&dev->dev, "%s: virq = %d\n", __func__, virq);
+
+ /* Setup msi address space */
+ msg.address_hi = msi_data->msi_addr_hi;
+ msg.address_lo = msi_data->msi_addr_lo;
+
+ irq_set_msi_desc(virq, entry);
+ msg.data = int_no;
+ write_msi_msg(virq, &msg);
+ }
+ return 0;
+}
+
+void ppc4xx_teardown_msi_irqs(struct pci_dev *dev)
+{
+ struct msi_desc *entry;
+ struct ppc4xx_msi *msi_data = &ppc4xx_msi;
+
+ dev_dbg(&dev->dev, "PCIE-MSI: tearing down msi irqs\n");
+
+ list_for_each_entry(entry, &dev->msi_list, list) {
+ if (entry->irq == NO_IRQ)
+ continue;
+ irq_set_msi_desc(entry->irq, NULL);
+ msi_bitmap_free_hwirqs(&msi_data->bitmap,
+ virq_to_hw(entry->irq), 1);
+ irq_dispose_mapping(entry->irq);
+ }
+}
+
+static int ppc4xx_msi_check_device(struct pci_dev *pdev, int nvec, int type)
+{
+ dev_dbg(&pdev->dev, "PCIE-MSI:%s called. vec %x type %d\n",
+ __func__, nvec, type);
+ if (type == PCI_CAP_ID_MSIX)
+ pr_debug("ppc4xx msi: MSI-X untested, trying anyway.\n");
+
+ return 0;
+}
+
+static int ppc4xx_setup_pcieh_hw(struct platform_device *dev,
+ struct resource res, struct ppc4xx_msi *msi)
+{
+ const u32 *msi_data;
+ const u32 *msi_mask;
+ const u32 *sdr_addr;
+ dma_addr_t msi_phys;
+ void *msi_virt;
+
+ sdr_addr = of_get_property(dev->dev.of_node, "sdr-base", NULL);
+ if (!sdr_addr)
+ return -1;
+
+ SDR0_WRITE(sdr_addr, (u64)res.start >> 32); /*HIGH addr */
+ SDR0_WRITE(sdr_addr + 1, res.start & 0xFFFFFFFF); /* Low addr */
+
+
+ msi->msi_dev = of_find_node_by_name(NULL, "ppc4xx-msi");
+ if (msi->msi_dev)
+ return -ENODEV;
+
+ msi->msi_regs = of_iomap(msi->msi_dev, 0);
+ if (!msi->msi_regs) {
+ dev_err(&dev->dev, "of_iomap problem failed\n");
+ return -ENOMEM;
+ }
+ dev_dbg(&dev->dev, "PCIE-MSI: msi register mapped 0x%x 0x%x\n",
+ (u32) (msi->msi_regs + PEIH_TERMADH), (u32) (msi->msi_regs));
+
+ msi_virt = dma_alloc_coherent(&dev->dev, 64, &msi_phys, GFP_KERNEL);
+ msi->msi_addr_hi = 0x0;
+ msi->msi_addr_lo = (u32) msi_phys;
+ dev_dbg(&dev->dev, "PCIE-MSI: msi address 0x%x\n", msi->msi_addr_lo);
+
+ /* Progam the Interrupt handler Termination addr registers */
+ out_be32(msi->msi_regs + PEIH_TERMADH, msi->msi_addr_hi);
+ out_be32(msi->msi_regs + PEIH_TERMADL, msi->msi_addr_lo);
+
+ msi_data = of_get_property(dev->dev.of_node, "msi-data", NULL);
+ if (!msi_data)
+ return -1;
+ msi_mask = of_get_property(dev->dev.of_node, "msi-mask", NULL);
+ if (!msi_mask)
+ return -1;
+ /* Program MSI Expected data and Mask bits */
+ out_be32(msi->msi_regs + PEIH_MSIED, *msi_data);
+ out_be32(msi->msi_regs + PEIH_MSIMK, *msi_mask);
+
+ return 0;
+}
+
+static int ppc4xx_of_msi_remove(struct platform_device *dev)
+{
+ struct ppc4xx_msi *msi = dev->dev.platform_data;
+ int i;
+ int virq;
+
+ for (i = 0; i < NR_MSI_IRQS; i++) {
+ virq = msi->msi_virqs[i];
+ if (virq != NO_IRQ)
+ irq_dispose_mapping(virq);
+ }
+
+ if (msi->bitmap.bitmap)
+ msi_bitmap_free(&msi->bitmap);
+ iounmap(msi->msi_regs);
+ of_node_put(msi->msi_dev);
+ kfree(msi);
+
+ return 0;
+}
+
+static int __devinit ppc4xx_msi_probe(struct platform_device *dev)
+{
+ struct ppc4xx_msi *msi;
+ struct resource res;
+ int err = 0;
+
+ msi = &ppc4xx_msi;/*keep the msi data for further use*/
+
+ dev_dbg(&dev->dev, "PCIE-MSI: Setting up MSI support...\n");
+
+ msi = kzalloc(sizeof(struct ppc4xx_msi), GFP_KERNEL);
+ if (!msi) {
+ dev_err(&dev->dev, "No memory for MSI structure\n");
+ return -ENOMEM;
+ }
+ dev->dev.platform_data = msi;
+
+ /* Get MSI ranges */
+ err = of_address_to_resource(dev->dev.of_node, 0, &res);
+ if (err) {
+ dev_err(&dev->dev, "%s resource error!\n",
+ dev->dev.of_node->full_name);
+ goto error_out;
+ }
+
+ if (ppc4xx_setup_pcieh_hw(dev, res, msi))
+ goto error_out;
+
+ err = ppc4xx_msi_init_allocator(dev, msi);
+ if (err) {
+ dev_err(&dev->dev, "Error allocating MSI bitmap\n");
+ goto error_out;
+ }
+
+ ppc_md.setup_msi_irqs = ppc4xx_setup_msi_irqs;
+ ppc_md.teardown_msi_irqs = ppc4xx_teardown_msi_irqs;
+ ppc_md.msi_check_device = ppc4xx_msi_check_device;
+ return err;
+
+error_out:
+ ppc4xx_of_msi_remove(dev);
+ return err;
+}
+static const struct of_device_id ppc4xx_msi_ids[] = {
+ {
+ .compatible = "amcc,ppc4xx-msi",
+ },
+ {}
+};
+static struct platform_driver ppc4xx_msi_driver = {
+ .probe = ppc4xx_msi_probe,
+ .remove = ppc4xx_of_msi_remove,
+ .driver = {
+ .name = "ppc4xx-msi",
+ .owner = THIS_MODULE,
+ .of_match_table = ppc4xx_msi_ids,
+ },
+
+};
+
+static __init int ppc4xx_msi_init(void)
+{
+ return platform_driver_register(&ppc4xx_msi_driver);
+}
+
+subsys_initcall(ppc4xx_msi_init);
diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c
index 832d6924ad1c..b2acda07220d 100644
--- a/arch/powerpc/sysdev/qe_lib/qe_ic.c
+++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c
@@ -197,12 +197,10 @@ static inline struct qe_ic *qe_ic_from_irq_data(struct irq_data *d)
return irq_data_get_irq_chip_data(d);
}
-#define virq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq)
-
static void qe_ic_unmask_irq(struct irq_data *d)
{
struct qe_ic *qe_ic = qe_ic_from_irq_data(d);
- unsigned int src = virq_to_hw(d->irq);
+ unsigned int src = irqd_to_hwirq(d);
unsigned long flags;
u32 temp;
@@ -218,7 +216,7 @@ static void qe_ic_unmask_irq(struct irq_data *d)
static void qe_ic_mask_irq(struct irq_data *d)
{
struct qe_ic *qe_ic = qe_ic_from_irq_data(d);
- unsigned int src = virq_to_hw(d->irq);
+ unsigned int src = irqd_to_hwirq(d);
unsigned long flags;
u32 temp;
diff --git a/arch/powerpc/sysdev/scom.c b/arch/powerpc/sysdev/scom.c
new file mode 100644
index 000000000000..b2593ce30c9b
--- /dev/null
+++ b/arch/powerpc/sysdev/scom.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2010 Benjamin Herrenschmidt, IBM Corp
+ * <benh@kernel.crashing.org>
+ * and David Gibson, 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/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <asm/prom.h>
+#include <asm/scom.h>
+
+const struct scom_controller *scom_controller;
+EXPORT_SYMBOL_GPL(scom_controller);
+
+struct device_node *scom_find_parent(struct device_node *node)
+{
+ struct device_node *par, *tmp;
+ const u32 *p;
+
+ for (par = of_node_get(node); par;) {
+ if (of_get_property(par, "scom-controller", NULL))
+ break;
+ p = of_get_property(par, "scom-parent", NULL);
+ tmp = par;
+ if (p == NULL)
+ par = of_get_parent(par);
+ else
+ par = of_find_node_by_phandle(*p);
+ of_node_put(tmp);
+ }
+ return par;
+}
+EXPORT_SYMBOL_GPL(scom_find_parent);
+
+scom_map_t scom_map_device(struct device_node *dev, int index)
+{
+ struct device_node *parent;
+ unsigned int cells, size;
+ const u32 *prop;
+ u64 reg, cnt;
+ scom_map_t ret;
+
+ parent = scom_find_parent(dev);
+
+ if (parent == NULL)
+ return 0;
+
+ prop = of_get_property(parent, "#scom-cells", NULL);
+ cells = prop ? *prop : 1;
+
+ prop = of_get_property(dev, "scom-reg", &size);
+ if (!prop)
+ return 0;
+ size >>= 2;
+
+ if (index >= (size / (2*cells)))
+ return 0;
+
+ reg = of_read_number(&prop[index * cells * 2], cells);
+ cnt = of_read_number(&prop[index * cells * 2 + cells], cells);
+
+ ret = scom_map(parent, reg, cnt);
+ of_node_put(parent);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(scom_map_device);
+
+#ifdef CONFIG_SCOM_DEBUGFS
+struct scom_debug_entry {
+ struct device_node *dn;
+ unsigned long addr;
+ scom_map_t map;
+ spinlock_t lock;
+ char name[8];
+ struct debugfs_blob_wrapper blob;
+};
+
+static int scom_addr_set(void *data, u64 val)
+{
+ struct scom_debug_entry *ent = data;
+
+ ent->addr = 0;
+ scom_unmap(ent->map);
+
+ ent->map = scom_map(ent->dn, val, 1);
+ if (scom_map_ok(ent->map))
+ ent->addr = val;
+ else
+ return -EFAULT;
+
+ return 0;
+}
+
+static int scom_addr_get(void *data, u64 *val)
+{
+ struct scom_debug_entry *ent = data;
+ *val = ent->addr;
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(scom_addr_fops, scom_addr_get, scom_addr_set,
+ "0x%llx\n");
+
+static int scom_val_set(void *data, u64 val)
+{
+ struct scom_debug_entry *ent = data;
+
+ if (!scom_map_ok(ent->map))
+ return -EFAULT;
+
+ scom_write(ent->map, 0, val);
+
+ return 0;
+}
+
+static int scom_val_get(void *data, u64 *val)
+{
+ struct scom_debug_entry *ent = data;
+
+ if (!scom_map_ok(ent->map))
+ return -EFAULT;
+
+ *val = scom_read(ent->map, 0);
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(scom_val_fops, scom_val_get, scom_val_set,
+ "0x%llx\n");
+
+static int scom_debug_init_one(struct dentry *root, struct device_node *dn,
+ int i)
+{
+ struct scom_debug_entry *ent;
+ struct dentry *dir;
+
+ ent = kzalloc(sizeof(*ent), GFP_KERNEL);
+ if (!ent)
+ return -ENOMEM;
+
+ ent->dn = of_node_get(dn);
+ ent->map = SCOM_MAP_INVALID;
+ spin_lock_init(&ent->lock);
+ snprintf(ent->name, 8, "scom%d", i);
+ ent->blob.data = dn->full_name;
+ ent->blob.size = strlen(dn->full_name);
+
+ dir = debugfs_create_dir(ent->name, root);
+ if (!dir) {
+ of_node_put(dn);
+ kfree(ent);
+ return -1;
+ }
+
+ debugfs_create_file("addr", 0600, dir, ent, &scom_addr_fops);
+ debugfs_create_file("value", 0600, dir, ent, &scom_val_fops);
+ debugfs_create_blob("path", 0400, dir, &ent->blob);
+
+ return 0;
+}
+
+static int scom_debug_init(void)
+{
+ struct device_node *dn;
+ struct dentry *root;
+ int i, rc;
+
+ root = debugfs_create_dir("scom", powerpc_debugfs_root);
+ if (!root)
+ return -1;
+
+ i = rc = 0;
+ for_each_node_with_property(dn, "scom-controller")
+ rc |= scom_debug_init_one(root, dn, i++);
+
+ return rc;
+}
+device_initcall(scom_debug_init);
+#endif /* CONFIG_SCOM_DEBUGFS */
diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c
index 5d9138516628..984cd2029158 100644
--- a/arch/powerpc/sysdev/uic.c
+++ b/arch/powerpc/sysdev/uic.c
@@ -41,8 +41,6 @@
#define UIC_VR 0x7
#define UIC_VCR 0x8
-#define uic_irq_to_hw(virq) (irq_map[virq].hwirq)
-
struct uic *primary_uic;
struct uic {
@@ -58,7 +56,7 @@ struct uic {
static void uic_unmask_irq(struct irq_data *d)
{
struct uic *uic = irq_data_get_irq_chip_data(d);
- unsigned int src = uic_irq_to_hw(d->irq);
+ unsigned int src = irqd_to_hwirq(d);
unsigned long flags;
u32 er, sr;
@@ -76,7 +74,7 @@ static void uic_unmask_irq(struct irq_data *d)
static void uic_mask_irq(struct irq_data *d)
{
struct uic *uic = irq_data_get_irq_chip_data(d);
- unsigned int src = uic_irq_to_hw(d->irq);
+ unsigned int src = irqd_to_hwirq(d);
unsigned long flags;
u32 er;
@@ -90,7 +88,7 @@ static void uic_mask_irq(struct irq_data *d)
static void uic_ack_irq(struct irq_data *d)
{
struct uic *uic = irq_data_get_irq_chip_data(d);
- unsigned int src = uic_irq_to_hw(d->irq);
+ unsigned int src = irqd_to_hwirq(d);
unsigned long flags;
spin_lock_irqsave(&uic->lock, flags);
@@ -101,7 +99,7 @@ static void uic_ack_irq(struct irq_data *d)
static void uic_mask_ack_irq(struct irq_data *d)
{
struct uic *uic = irq_data_get_irq_chip_data(d);
- unsigned int src = uic_irq_to_hw(d->irq);
+ unsigned int src = irqd_to_hwirq(d);
unsigned long flags;
u32 er, sr;
@@ -126,7 +124,7 @@ static void uic_mask_ack_irq(struct irq_data *d)
static int uic_set_irq_type(struct irq_data *d, unsigned int flow_type)
{
struct uic *uic = irq_data_get_irq_chip_data(d);
- unsigned int src = uic_irq_to_hw(d->irq);
+ unsigned int src = irqd_to_hwirq(d);
unsigned long flags;
int trigger, polarity;
u32 tr, pr, mask;
diff --git a/arch/powerpc/sysdev/xics/Kconfig b/arch/powerpc/sysdev/xics/Kconfig
new file mode 100644
index 000000000000..0031eda320c3
--- /dev/null
+++ b/arch/powerpc/sysdev/xics/Kconfig
@@ -0,0 +1,13 @@
+config PPC_XICS
+ def_bool n
+ select PPC_SMP_MUXED_IPI
+
+config PPC_ICP_NATIVE
+ def_bool n
+
+config PPC_ICP_HV
+ def_bool n
+
+config PPC_ICS_RTAS
+ def_bool n
+
diff --git a/arch/powerpc/sysdev/xics/Makefile b/arch/powerpc/sysdev/xics/Makefile
new file mode 100644
index 000000000000..b75a6059337f
--- /dev/null
+++ b/arch/powerpc/sysdev/xics/Makefile
@@ -0,0 +1,6 @@
+subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror
+
+obj-y += xics-common.o
+obj-$(CONFIG_PPC_ICP_NATIVE) += icp-native.o
+obj-$(CONFIG_PPC_ICP_HV) += icp-hv.o
+obj-$(CONFIG_PPC_ICS_RTAS) += ics-rtas.o
diff --git a/arch/powerpc/sysdev/xics/icp-hv.c b/arch/powerpc/sysdev/xics/icp-hv.c
new file mode 100644
index 000000000000..9518d367a64f
--- /dev/null
+++ b/arch/powerpc/sysdev/xics/icp-hv.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2011 IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/cpu.h>
+#include <linux/of.h>
+
+#include <asm/smp.h>
+#include <asm/irq.h>
+#include <asm/errno.h>
+#include <asm/xics.h>
+#include <asm/io.h>
+#include <asm/hvcall.h>
+
+static inline unsigned int icp_hv_get_xirr(unsigned char cppr)
+{
+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
+ long rc;
+
+ rc = plpar_hcall(H_XIRR, retbuf, cppr);
+ if (rc != H_SUCCESS)
+ panic(" bad return code xirr - rc = %lx\n", rc);
+ return (unsigned int)retbuf[0];
+}
+
+static inline void icp_hv_set_xirr(unsigned int value)
+{
+ long rc = plpar_hcall_norets(H_EOI, value);
+ if (rc != H_SUCCESS)
+ panic("bad return code EOI - rc = %ld, value=%x\n", rc, value);
+}
+
+static inline void icp_hv_set_cppr(u8 value)
+{
+ long rc = plpar_hcall_norets(H_CPPR, value);
+ if (rc != H_SUCCESS)
+ panic("bad return code cppr - rc = %lx\n", rc);
+}
+
+static inline void icp_hv_set_qirr(int n_cpu , u8 value)
+{
+ long rc = plpar_hcall_norets(H_IPI, get_hard_smp_processor_id(n_cpu),
+ value);
+ if (rc != H_SUCCESS)
+ panic("bad return code qirr - rc = %lx\n", rc);
+}
+
+static void icp_hv_eoi(struct irq_data *d)
+{
+ unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
+
+ iosync();
+ icp_hv_set_xirr((xics_pop_cppr() << 24) | hw_irq);
+}
+
+static void icp_hv_teardown_cpu(void)
+{
+ int cpu = smp_processor_id();
+
+ /* Clear any pending IPI */
+ icp_hv_set_qirr(cpu, 0xff);
+}
+
+static void icp_hv_flush_ipi(void)
+{
+ /* We take the ipi irq but and never return so we
+ * need to EOI the IPI, but want to leave our priority 0
+ *
+ * should we check all the other interrupts too?
+ * should we be flagging idle loop instead?
+ * or creating some task to be scheduled?
+ */
+
+ icp_hv_set_xirr((0x00 << 24) | XICS_IPI);
+}
+
+static unsigned int icp_hv_get_irq(void)
+{
+ unsigned int xirr = icp_hv_get_xirr(xics_cppr_top());
+ unsigned int vec = xirr & 0x00ffffff;
+ unsigned int irq;
+
+ if (vec == XICS_IRQ_SPURIOUS)
+ return NO_IRQ;
+
+ irq = irq_radix_revmap_lookup(xics_host, vec);
+ if (likely(irq != NO_IRQ)) {
+ xics_push_cppr(vec);
+ return irq;
+ }
+
+ /* We don't have a linux mapping, so have rtas mask it. */
+ xics_mask_unknown_vec(vec);
+
+ /* We might learn about it later, so EOI it */
+ icp_hv_set_xirr(xirr);
+
+ return NO_IRQ;
+}
+
+static void icp_hv_set_cpu_priority(unsigned char cppr)
+{
+ xics_set_base_cppr(cppr);
+ icp_hv_set_cppr(cppr);
+ iosync();
+}
+
+#ifdef CONFIG_SMP
+
+static void icp_hv_cause_ipi(int cpu, unsigned long data)
+{
+ icp_hv_set_qirr(cpu, IPI_PRIORITY);
+}
+
+static irqreturn_t icp_hv_ipi_action(int irq, void *dev_id)
+{
+ int cpu = smp_processor_id();
+
+ icp_hv_set_qirr(cpu, 0xff);
+
+ return smp_ipi_demux();
+}
+
+#endif /* CONFIG_SMP */
+
+static const struct icp_ops icp_hv_ops = {
+ .get_irq = icp_hv_get_irq,
+ .eoi = icp_hv_eoi,
+ .set_priority = icp_hv_set_cpu_priority,
+ .teardown_cpu = icp_hv_teardown_cpu,
+ .flush_ipi = icp_hv_flush_ipi,
+#ifdef CONFIG_SMP
+ .ipi_action = icp_hv_ipi_action,
+ .cause_ipi = icp_hv_cause_ipi,
+#endif
+};
+
+int icp_hv_init(void)
+{
+ struct device_node *np;
+
+ np = of_find_compatible_node(NULL, NULL, "ibm,ppc-xicp");
+ if (!np)
+ np = of_find_node_by_type(NULL,
+ "PowerPC-External-Interrupt-Presentation");
+ if (!np)
+ return -ENODEV;
+
+ icp_ops = &icp_hv_ops;
+
+ return 0;
+}
+
diff --git a/arch/powerpc/sysdev/xics/icp-native.c b/arch/powerpc/sysdev/xics/icp-native.c
new file mode 100644
index 000000000000..1f15ad436140
--- /dev/null
+++ b/arch/powerpc/sysdev/xics/icp-native.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright 2011 IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/cpu.h>
+#include <linux/of.h>
+#include <linux/spinlock.h>
+
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/irq.h>
+#include <asm/errno.h>
+#include <asm/xics.h>
+
+struct icp_ipl {
+ union {
+ u32 word;
+ u8 bytes[4];
+ } xirr_poll;
+ union {
+ u32 word;
+ u8 bytes[4];
+ } xirr;
+ u32 dummy;
+ union {
+ u32 word;
+ u8 bytes[4];
+ } qirr;
+ u32 link_a;
+ u32 link_b;
+ u32 link_c;
+};
+
+static struct icp_ipl __iomem *icp_native_regs[NR_CPUS];
+
+static inline unsigned int icp_native_get_xirr(void)
+{
+ int cpu = smp_processor_id();
+
+ return in_be32(&icp_native_regs[cpu]->xirr.word);
+}
+
+static inline void icp_native_set_xirr(unsigned int value)
+{
+ int cpu = smp_processor_id();
+
+ out_be32(&icp_native_regs[cpu]->xirr.word, value);
+}
+
+static inline void icp_native_set_cppr(u8 value)
+{
+ int cpu = smp_processor_id();
+
+ out_8(&icp_native_regs[cpu]->xirr.bytes[0], value);
+}
+
+static inline void icp_native_set_qirr(int n_cpu, u8 value)
+{
+ out_8(&icp_native_regs[n_cpu]->qirr.bytes[0], value);
+}
+
+static void icp_native_set_cpu_priority(unsigned char cppr)
+{
+ xics_set_base_cppr(cppr);
+ icp_native_set_cppr(cppr);
+ iosync();
+}
+
+static void icp_native_eoi(struct irq_data *d)
+{
+ unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
+
+ iosync();
+ icp_native_set_xirr((xics_pop_cppr() << 24) | hw_irq);
+}
+
+static void icp_native_teardown_cpu(void)
+{
+ int cpu = smp_processor_id();
+
+ /* Clear any pending IPI */
+ icp_native_set_qirr(cpu, 0xff);
+}
+
+static void icp_native_flush_ipi(void)
+{
+ /* We take the ipi irq but and never return so we
+ * need to EOI the IPI, but want to leave our priority 0
+ *
+ * should we check all the other interrupts too?
+ * should we be flagging idle loop instead?
+ * or creating some task to be scheduled?
+ */
+
+ icp_native_set_xirr((0x00 << 24) | XICS_IPI);
+}
+
+static unsigned int icp_native_get_irq(void)
+{
+ unsigned int xirr = icp_native_get_xirr();
+ unsigned int vec = xirr & 0x00ffffff;
+ unsigned int irq;
+
+ if (vec == XICS_IRQ_SPURIOUS)
+ return NO_IRQ;
+
+ irq = irq_radix_revmap_lookup(xics_host, vec);
+ if (likely(irq != NO_IRQ)) {
+ xics_push_cppr(vec);
+ return irq;
+ }
+
+ /* We don't have a linux mapping, so have rtas mask it. */
+ xics_mask_unknown_vec(vec);
+
+ /* We might learn about it later, so EOI it */
+ icp_native_set_xirr(xirr);
+
+ return NO_IRQ;
+}
+
+#ifdef CONFIG_SMP
+
+static void icp_native_cause_ipi(int cpu, unsigned long data)
+{
+ icp_native_set_qirr(cpu, IPI_PRIORITY);
+}
+
+static irqreturn_t icp_native_ipi_action(int irq, void *dev_id)
+{
+ int cpu = smp_processor_id();
+
+ icp_native_set_qirr(cpu, 0xff);
+
+ return smp_ipi_demux();
+}
+
+#endif /* CONFIG_SMP */
+
+static int __init icp_native_map_one_cpu(int hw_id, unsigned long addr,
+ unsigned long size)
+{
+ char *rname;
+ int i, cpu = -1;
+
+ /* This may look gross but it's good enough for now, we don't quite
+ * have a hard -> linux processor id matching.
+ */
+ for_each_possible_cpu(i) {
+ if (!cpu_present(i))
+ continue;
+ if (hw_id == get_hard_smp_processor_id(i)) {
+ cpu = i;
+ break;
+ }
+ }
+
+ /* Fail, skip that CPU. Don't print, it's normal, some XICS come up
+ * with way more entries in there than you have CPUs
+ */
+ if (cpu == -1)
+ return 0;
+
+ rname = kasprintf(GFP_KERNEL, "CPU %d [0x%x] Interrupt Presentation",
+ cpu, hw_id);
+
+ if (!request_mem_region(addr, size, rname)) {
+ pr_warning("icp_native: Could not reserve ICP MMIO"
+ " for CPU %d, interrupt server #0x%x\n",
+ cpu, hw_id);
+ return -EBUSY;
+ }
+
+ icp_native_regs[cpu] = ioremap(addr, size);
+ if (!icp_native_regs[cpu]) {
+ pr_warning("icp_native: Failed ioremap for CPU %d, "
+ "interrupt server #0x%x, addr %#lx\n",
+ cpu, hw_id, addr);
+ release_mem_region(addr, size);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static int __init icp_native_init_one_node(struct device_node *np,
+ unsigned int *indx)
+{
+ unsigned int ilen;
+ const u32 *ireg;
+ int i;
+ int reg_tuple_size;
+ int num_servers = 0;
+
+ /* This code does the theorically broken assumption that the interrupt
+ * server numbers are the same as the hard CPU numbers.
+ * This happens to be the case so far but we are playing with fire...
+ * should be fixed one of these days. -BenH.
+ */
+ ireg = of_get_property(np, "ibm,interrupt-server-ranges", &ilen);
+
+ /* Do that ever happen ? we'll know soon enough... but even good'old
+ * f80 does have that property ..
+ */
+ WARN_ON((ireg == NULL) || (ilen != 2*sizeof(u32)));
+
+ if (ireg) {
+ *indx = of_read_number(ireg, 1);
+ if (ilen >= 2*sizeof(u32))
+ num_servers = of_read_number(ireg + 1, 1);
+ }
+
+ ireg = of_get_property(np, "reg", &ilen);
+ if (!ireg) {
+ pr_err("icp_native: Can't find interrupt reg property");
+ return -1;
+ }
+
+ reg_tuple_size = (of_n_addr_cells(np) + of_n_size_cells(np)) * 4;
+ if (((ilen % reg_tuple_size) != 0)
+ || (num_servers && (num_servers != (ilen / reg_tuple_size)))) {
+ pr_err("icp_native: ICP reg len (%d) != num servers (%d)",
+ ilen / reg_tuple_size, num_servers);
+ return -1;
+ }
+
+ for (i = 0; i < (ilen / reg_tuple_size); i++) {
+ struct resource r;
+ int err;
+
+ err = of_address_to_resource(np, i, &r);
+ if (err) {
+ pr_err("icp_native: Could not translate ICP MMIO"
+ " for interrupt server 0x%x (%d)\n", *indx, err);
+ return -1;
+ }
+
+ if (icp_native_map_one_cpu(*indx, r.start, r.end - r.start))
+ return -1;
+
+ (*indx)++;
+ }
+ return 0;
+}
+
+static const struct icp_ops icp_native_ops = {
+ .get_irq = icp_native_get_irq,
+ .eoi = icp_native_eoi,
+ .set_priority = icp_native_set_cpu_priority,
+ .teardown_cpu = icp_native_teardown_cpu,
+ .flush_ipi = icp_native_flush_ipi,
+#ifdef CONFIG_SMP
+ .ipi_action = icp_native_ipi_action,
+ .cause_ipi = icp_native_cause_ipi,
+#endif
+};
+
+int icp_native_init(void)
+{
+ struct device_node *np;
+ u32 indx = 0;
+ int found = 0;
+
+ for_each_compatible_node(np, NULL, "ibm,ppc-xicp")
+ if (icp_native_init_one_node(np, &indx) == 0)
+ found = 1;
+ if (!found) {
+ for_each_node_by_type(np,
+ "PowerPC-External-Interrupt-Presentation") {
+ if (icp_native_init_one_node(np, &indx) == 0)
+ found = 1;
+ }
+ }
+
+ if (found == 0)
+ return -ENODEV;
+
+ icp_ops = &icp_native_ops;
+
+ return 0;
+}
diff --git a/arch/powerpc/sysdev/xics/ics-rtas.c b/arch/powerpc/sysdev/xics/ics-rtas.c
new file mode 100644
index 000000000000..c782f85cf7e4
--- /dev/null
+++ b/arch/powerpc/sysdev/xics/ics-rtas.c
@@ -0,0 +1,240 @@
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/cpu.h>
+#include <linux/of.h>
+#include <linux/spinlock.h>
+#include <linux/msi.h>
+
+#include <asm/prom.h>
+#include <asm/smp.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/errno.h>
+#include <asm/xics.h>
+#include <asm/rtas.h>
+
+/* RTAS service tokens */
+static int ibm_get_xive;
+static int ibm_set_xive;
+static int ibm_int_on;
+static int ibm_int_off;
+
+static int ics_rtas_map(struct ics *ics, unsigned int virq);
+static void ics_rtas_mask_unknown(struct ics *ics, unsigned long vec);
+static long ics_rtas_get_server(struct ics *ics, unsigned long vec);
+static int ics_rtas_host_match(struct ics *ics, struct device_node *node);
+
+/* Only one global & state struct ics */
+static struct ics ics_rtas = {
+ .map = ics_rtas_map,
+ .mask_unknown = ics_rtas_mask_unknown,
+ .get_server = ics_rtas_get_server,
+ .host_match = ics_rtas_host_match,
+};
+
+static void ics_rtas_unmask_irq(struct irq_data *d)
+{
+ unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
+ int call_status;
+ int server;
+
+ pr_devel("xics: unmask virq %d [hw 0x%x]\n", d->irq, hw_irq);
+
+ if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)
+ return;
+
+ server = xics_get_irq_server(d->irq, d->affinity, 0);
+
+ call_status = rtas_call(ibm_set_xive, 3, 1, NULL, hw_irq, server,
+ DEFAULT_PRIORITY);
+ if (call_status != 0) {
+ printk(KERN_ERR
+ "%s: ibm_set_xive irq %u server %x returned %d\n",
+ __func__, hw_irq, server, call_status);
+ return;
+ }
+
+ /* Now unmask the interrupt (often a no-op) */
+ call_status = rtas_call(ibm_int_on, 1, 1, NULL, hw_irq);
+ if (call_status != 0) {
+ printk(KERN_ERR "%s: ibm_int_on irq=%u returned %d\n",
+ __func__, hw_irq, call_status);
+ return;
+ }
+}
+
+static unsigned int ics_rtas_startup(struct irq_data *d)
+{
+#ifdef CONFIG_PCI_MSI
+ /*
+ * The generic MSI code returns with the interrupt disabled on the
+ * card, using the MSI mask bits. Firmware doesn't appear to unmask
+ * at that level, so we do it here by hand.
+ */
+ if (d->msi_desc)
+ unmask_msi_irq(d);
+#endif
+ /* unmask it */
+ ics_rtas_unmask_irq(d);
+ return 0;
+}
+
+static void ics_rtas_mask_real_irq(unsigned int hw_irq)
+{
+ int call_status;
+
+ if (hw_irq == XICS_IPI)
+ return;
+
+ call_status = rtas_call(ibm_int_off, 1, 1, NULL, hw_irq);
+ if (call_status != 0) {
+ printk(KERN_ERR "%s: ibm_int_off irq=%u returned %d\n",
+ __func__, hw_irq, call_status);
+ return;
+ }
+
+ /* Have to set XIVE to 0xff to be able to remove a slot */
+ call_status = rtas_call(ibm_set_xive, 3, 1, NULL, hw_irq,
+ xics_default_server, 0xff);
+ if (call_status != 0) {
+ printk(KERN_ERR "%s: ibm_set_xive(0xff) irq=%u returned %d\n",
+ __func__, hw_irq, call_status);
+ return;
+ }
+}
+
+static void ics_rtas_mask_irq(struct irq_data *d)
+{
+ unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
+
+ pr_devel("xics: mask virq %d [hw 0x%x]\n", d->irq, hw_irq);
+
+ if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)
+ return;
+ ics_rtas_mask_real_irq(hw_irq);
+}
+
+static int ics_rtas_set_affinity(struct irq_data *d,
+ const struct cpumask *cpumask,
+ bool force)
+{
+ unsigned int hw_irq = (unsigned int)irqd_to_hwirq(d);
+ int status;
+ int xics_status[2];
+ int irq_server;
+
+ if (hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS)
+ return -1;
+
+ status = rtas_call(ibm_get_xive, 1, 3, xics_status, hw_irq);
+
+ if (status) {
+ printk(KERN_ERR "%s: ibm,get-xive irq=%u returns %d\n",
+ __func__, hw_irq, status);
+ return -1;
+ }
+
+ irq_server = xics_get_irq_server(d->irq, cpumask, 1);
+ if (irq_server == -1) {
+ char cpulist[128];
+ cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask);
+ printk(KERN_WARNING
+ "%s: No online cpus in the mask %s for irq %d\n",
+ __func__, cpulist, d->irq);
+ return -1;
+ }
+
+ status = rtas_call(ibm_set_xive, 3, 1, NULL,
+ hw_irq, irq_server, xics_status[1]);
+
+ if (status) {
+ printk(KERN_ERR "%s: ibm,set-xive irq=%u returns %d\n",
+ __func__, hw_irq, status);
+ return -1;
+ }
+
+ return IRQ_SET_MASK_OK;
+}
+
+static struct irq_chip ics_rtas_irq_chip = {
+ .name = "XICS",
+ .irq_startup = ics_rtas_startup,
+ .irq_mask = ics_rtas_mask_irq,
+ .irq_unmask = ics_rtas_unmask_irq,
+ .irq_eoi = NULL, /* Patched at init time */
+ .irq_set_affinity = ics_rtas_set_affinity
+};
+
+static int ics_rtas_map(struct ics *ics, unsigned int virq)
+{
+ unsigned int hw_irq = (unsigned int)virq_to_hw(virq);
+ int status[2];
+ int rc;
+
+ if (WARN_ON(hw_irq == XICS_IPI || hw_irq == XICS_IRQ_SPURIOUS))
+ return -EINVAL;
+
+ /* Check if RTAS knows about this interrupt */
+ rc = rtas_call(ibm_get_xive, 1, 3, status, hw_irq);
+ if (rc)
+ return -ENXIO;
+
+ irq_set_chip_and_handler(virq, &ics_rtas_irq_chip, handle_fasteoi_irq);
+ irq_set_chip_data(virq, &ics_rtas);
+
+ return 0;
+}
+
+static void ics_rtas_mask_unknown(struct ics *ics, unsigned long vec)
+{
+ ics_rtas_mask_real_irq(vec);
+}
+
+static long ics_rtas_get_server(struct ics *ics, unsigned long vec)
+{
+ int rc, status[2];
+
+ rc = rtas_call(ibm_get_xive, 1, 3, status, vec);
+ if (rc)
+ return -1;
+ return status[0];
+}
+
+static int ics_rtas_host_match(struct ics *ics, struct device_node *node)
+{
+ /* IBM machines have interrupt parents of various funky types for things
+ * like vdevices, events, etc... The trick we use here is to match
+ * everything here except the legacy 8259 which is compatible "chrp,iic"
+ */
+ return !of_device_is_compatible(node, "chrp,iic");
+}
+
+int ics_rtas_init(void)
+{
+ ibm_get_xive = rtas_token("ibm,get-xive");
+ ibm_set_xive = rtas_token("ibm,set-xive");
+ ibm_int_on = rtas_token("ibm,int-on");
+ ibm_int_off = rtas_token("ibm,int-off");
+
+ /* We enable the RTAS "ICS" if RTAS is present with the
+ * appropriate tokens
+ */
+ if (ibm_get_xive == RTAS_UNKNOWN_SERVICE ||
+ ibm_set_xive == RTAS_UNKNOWN_SERVICE)
+ return -ENODEV;
+
+ /* We need to patch our irq chip's EOI to point to the
+ * right ICP
+ */
+ ics_rtas_irq_chip.irq_eoi = icp_ops->eoi;
+
+ /* Register ourselves */
+ xics_register_ics(&ics_rtas);
+
+ return 0;
+}
+
diff --git a/arch/powerpc/sysdev/xics/xics-common.c b/arch/powerpc/sysdev/xics/xics-common.c
new file mode 100644
index 000000000000..445c5a01b766
--- /dev/null
+++ b/arch/powerpc/sysdev/xics/xics-common.c
@@ -0,0 +1,443 @@
+/*
+ * Copyright 2011 IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+#include <linux/types.h>
+#include <linux/threads.h>
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/debugfs.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include <linux/seq_file.h>
+#include <linux/init.h>
+#include <linux/cpu.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/machdep.h>
+#include <asm/irq.h>
+#include <asm/errno.h>
+#include <asm/rtas.h>
+#include <asm/xics.h>
+#include <asm/firmware.h>
+
+/* Globals common to all ICP/ICS implementations */
+const struct icp_ops *icp_ops;
+
+unsigned int xics_default_server = 0xff;
+unsigned int xics_default_distrib_server = 0;
+unsigned int xics_interrupt_server_size = 8;
+
+DEFINE_PER_CPU(struct xics_cppr, xics_cppr);
+
+struct irq_host *xics_host;
+
+static LIST_HEAD(ics_list);
+
+void xics_update_irq_servers(void)
+{
+ int i, j;
+ struct device_node *np;
+ u32 ilen;
+ const u32 *ireg;
+ u32 hcpuid;
+
+ /* Find the server numbers for the boot cpu. */
+ np = of_get_cpu_node(boot_cpuid, NULL);
+ BUG_ON(!np);
+
+ hcpuid = get_hard_smp_processor_id(boot_cpuid);
+ xics_default_server = xics_default_distrib_server = hcpuid;
+
+ pr_devel("xics: xics_default_server = 0x%x\n", xics_default_server);
+
+ ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
+ if (!ireg) {
+ of_node_put(np);
+ return;
+ }
+
+ i = ilen / sizeof(int);
+
+ /* Global interrupt distribution server is specified in the last
+ * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last
+ * entry fom this property for current boot cpu id and use it as
+ * default distribution server
+ */
+ for (j = 0; j < i; j += 2) {
+ if (ireg[j] == hcpuid) {
+ xics_default_distrib_server = ireg[j+1];
+ break;
+ }
+ }
+ pr_devel("xics: xics_default_distrib_server = 0x%x\n",
+ xics_default_distrib_server);
+ of_node_put(np);
+}
+
+/* GIQ stuff, currently only supported on RTAS setups, will have
+ * to be sorted properly for bare metal
+ */
+void xics_set_cpu_giq(unsigned int gserver, unsigned int join)
+{
+#ifdef CONFIG_PPC_RTAS
+ int index;
+ int status;
+
+ if (!rtas_indicator_present(GLOBAL_INTERRUPT_QUEUE, NULL))
+ return;
+
+ index = (1UL << xics_interrupt_server_size) - 1 - gserver;
+
+ status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE, index, join);
+
+ WARN(status < 0, "set-indicator(%d, %d, %u) returned %d\n",
+ GLOBAL_INTERRUPT_QUEUE, index, join, status);
+#endif
+}
+
+void xics_setup_cpu(void)
+{
+ icp_ops->set_priority(LOWEST_PRIORITY);
+
+ xics_set_cpu_giq(xics_default_distrib_server, 1);
+}
+
+void xics_mask_unknown_vec(unsigned int vec)
+{
+ struct ics *ics;
+
+ pr_err("Interrupt 0x%x (real) is invalid, disabling it.\n", vec);
+
+ list_for_each_entry(ics, &ics_list, link)
+ ics->mask_unknown(ics, vec);
+}
+
+
+#ifdef CONFIG_SMP
+
+static void xics_request_ipi(void)
+{
+ unsigned int ipi;
+
+ ipi = irq_create_mapping(xics_host, XICS_IPI);
+ BUG_ON(ipi == NO_IRQ);
+
+ /*
+ * IPIs are marked IRQF_DISABLED as they must run with irqs
+ * disabled, and PERCPU. The handler was set in map.
+ */
+ BUG_ON(request_irq(ipi, icp_ops->ipi_action,
+ IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL));
+}
+
+int __init xics_smp_probe(void)
+{
+ /* Setup cause_ipi callback based on which ICP is used */
+ smp_ops->cause_ipi = icp_ops->cause_ipi;
+
+ /* Register all the IPIs */
+ xics_request_ipi();
+
+ return cpumask_weight(cpu_possible_mask);
+}
+
+#endif /* CONFIG_SMP */
+
+void xics_teardown_cpu(void)
+{
+ struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr);
+
+ /*
+ * we have to reset the cppr index to 0 because we're
+ * not going to return from the IPI
+ */
+ os_cppr->index = 0;
+ icp_ops->set_priority(0);
+ icp_ops->teardown_cpu();
+}
+
+void xics_kexec_teardown_cpu(int secondary)
+{
+ xics_teardown_cpu();
+
+ icp_ops->flush_ipi();
+
+ /*
+ * Some machines need to have at least one cpu in the GIQ,
+ * so leave the master cpu in the group.
+ */
+ if (secondary)
+ xics_set_cpu_giq(xics_default_distrib_server, 0);
+}
+
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+/* Interrupts are disabled. */
+void xics_migrate_irqs_away(void)
+{
+ int cpu = smp_processor_id(), hw_cpu = hard_smp_processor_id();
+ unsigned int irq, virq;
+
+ /* If we used to be the default server, move to the new "boot_cpuid" */
+ if (hw_cpu == xics_default_server)
+ xics_update_irq_servers();
+
+ /* Reject any interrupt that was queued to us... */
+ icp_ops->set_priority(0);
+
+ /* Remove ourselves from the global interrupt queue */
+ xics_set_cpu_giq(xics_default_distrib_server, 0);
+
+ /* Allow IPIs again... */
+ icp_ops->set_priority(DEFAULT_PRIORITY);
+
+ for_each_irq(virq) {
+ struct irq_desc *desc;
+ struct irq_chip *chip;
+ long server;
+ unsigned long flags;
+ struct ics *ics;
+
+ /* We can't set affinity on ISA interrupts */
+ if (virq < NUM_ISA_INTERRUPTS)
+ continue;
+ if (!virq_is_host(virq, xics_host))
+ continue;
+ irq = (unsigned int)virq_to_hw(virq);
+ /* We need to get IPIs still. */
+ if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS)
+ continue;
+ desc = irq_to_desc(virq);
+ /* We only need to migrate enabled IRQS */
+ if (!desc || !desc->action)
+ continue;
+ chip = irq_desc_get_chip(desc);
+ if (!chip || !chip->irq_set_affinity)
+ continue;
+
+ raw_spin_lock_irqsave(&desc->lock, flags);
+
+ /* Locate interrupt server */
+ server = -1;
+ ics = irq_get_chip_data(virq);
+ if (ics)
+ server = ics->get_server(ics, irq);
+ if (server < 0) {
+ printk(KERN_ERR "%s: Can't find server for irq %d\n",
+ __func__, irq);
+ goto unlock;
+ }
+
+ /* We only support delivery to all cpus or to one cpu.
+ * The irq has to be migrated only in the single cpu
+ * case.
+ */
+ if (server != hw_cpu)
+ goto unlock;
+
+ /* This is expected during cpu offline. */
+ if (cpu_online(cpu))
+ pr_warning("IRQ %u affinity broken off cpu %u\n",
+ virq, cpu);
+
+ /* Reset affinity to all cpus */
+ raw_spin_unlock_irqrestore(&desc->lock, flags);
+ irq_set_affinity(virq, cpu_all_mask);
+ continue;
+unlock:
+ raw_spin_unlock_irqrestore(&desc->lock, flags);
+ }
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
+#ifdef CONFIG_SMP
+/*
+ * For the moment we only implement delivery to all cpus or one cpu.
+ *
+ * If the requested affinity is cpu_all_mask, we set global affinity.
+ * If not we set it to the first cpu in the mask, even if multiple cpus
+ * are set. This is so things like irqbalance (which set core and package
+ * wide affinities) do the right thing.
+ *
+ * We need to fix this to implement support for the links
+ */
+int xics_get_irq_server(unsigned int virq, const struct cpumask *cpumask,
+ unsigned int strict_check)
+{
+
+ if (!distribute_irqs)
+ return xics_default_server;
+
+ if (!cpumask_subset(cpu_possible_mask, cpumask)) {
+ int server = cpumask_first_and(cpu_online_mask, cpumask);
+
+ if (server < nr_cpu_ids)
+ return get_hard_smp_processor_id(server);
+
+ if (strict_check)
+ return -1;
+ }
+
+ /*
+ * Workaround issue with some versions of JS20 firmware that
+ * deliver interrupts to cpus which haven't been started. This
+ * happens when using the maxcpus= boot option.
+ */
+ if (cpumask_equal(cpu_online_mask, cpu_present_mask))
+ return xics_default_distrib_server;
+
+ return xics_default_server;
+}
+#endif /* CONFIG_SMP */
+
+static int xics_host_match(struct irq_host *h, struct device_node *node)
+{
+ struct ics *ics;
+
+ list_for_each_entry(ics, &ics_list, link)
+ if (ics->host_match(ics, node))
+ return 1;
+
+ return 0;
+}
+
+/* Dummies */
+static void xics_ipi_unmask(struct irq_data *d) { }
+static void xics_ipi_mask(struct irq_data *d) { }
+
+static struct irq_chip xics_ipi_chip = {
+ .name = "XICS",
+ .irq_eoi = NULL, /* Patched at init time */
+ .irq_mask = xics_ipi_mask,
+ .irq_unmask = xics_ipi_unmask,
+};
+
+static int xics_host_map(struct irq_host *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct ics *ics;
+
+ pr_devel("xics: map virq %d, hwirq 0x%lx\n", virq, hw);
+
+ /* Insert the interrupt mapping into the radix tree for fast lookup */
+ irq_radix_revmap_insert(xics_host, virq, hw);
+
+ /* They aren't all level sensitive but we just don't really know */
+ irq_set_status_flags(virq, IRQ_LEVEL);
+
+ /* Don't call into ICS for IPIs */
+ if (hw == XICS_IPI) {
+ irq_set_chip_and_handler(virq, &xics_ipi_chip,
+ handle_percpu_irq);
+ return 0;
+ }
+
+ /* Let the ICS setup the chip data */
+ list_for_each_entry(ics, &ics_list, link)
+ if (ics->map(ics, virq) == 0)
+ return 0;
+
+ return -EINVAL;
+}
+
+static int xics_host_xlate(struct irq_host *h, struct device_node *ct,
+ const u32 *intspec, unsigned int intsize,
+ irq_hw_number_t *out_hwirq, unsigned int *out_flags)
+
+{
+ /* Current xics implementation translates everything
+ * to level. It is not technically right for MSIs but this
+ * is irrelevant at this point. We might get smarter in the future
+ */
+ *out_hwirq = intspec[0];
+ *out_flags = IRQ_TYPE_LEVEL_LOW;
+
+ return 0;
+}
+
+static struct irq_host_ops xics_host_ops = {
+ .match = xics_host_match,
+ .map = xics_host_map,
+ .xlate = xics_host_xlate,
+};
+
+static void __init xics_init_host(void)
+{
+ xics_host = irq_alloc_host(NULL, IRQ_HOST_MAP_TREE, 0, &xics_host_ops,
+ XICS_IRQ_SPURIOUS);
+ BUG_ON(xics_host == NULL);
+ irq_set_default_host(xics_host);
+}
+
+void __init xics_register_ics(struct ics *ics)
+{
+ list_add(&ics->link, &ics_list);
+}
+
+static void __init xics_get_server_size(void)
+{
+ struct device_node *np;
+ const u32 *isize;
+
+ /* We fetch the interrupt server size from the first ICS node
+ * we find if any
+ */
+ np = of_find_compatible_node(NULL, NULL, "ibm,ppc-xics");
+ if (!np)
+ return;
+ isize = of_get_property(np, "ibm,interrupt-server#-size", NULL);
+ if (!isize)
+ return;
+ xics_interrupt_server_size = *isize;
+ of_node_put(np);
+}
+
+void __init xics_init(void)
+{
+ int rc = -1;
+
+ /* Fist locate ICP */
+#ifdef CONFIG_PPC_ICP_HV
+ if (firmware_has_feature(FW_FEATURE_LPAR))
+ rc = icp_hv_init();
+#endif
+#ifdef CONFIG_PPC_ICP_NATIVE
+ if (rc < 0)
+ rc = icp_native_init();
+#endif
+ if (rc < 0) {
+ pr_warning("XICS: Cannot find a Presentation Controller !\n");
+ return;
+ }
+
+ /* Copy get_irq callback over to ppc_md */
+ ppc_md.get_irq = icp_ops->get_irq;
+
+ /* Patch up IPI chip EOI */
+ xics_ipi_chip.irq_eoi = icp_ops->eoi;
+
+ /* Now locate ICS */
+#ifdef CONFIG_PPC_ICS_RTAS
+ rc = ics_rtas_init();
+#endif
+ if (rc < 0)
+ pr_warning("XICS: Cannot find a Source Controller !\n");
+
+ /* Initialize common bits */
+ xics_get_server_size();
+ xics_update_irq_servers();
+ xics_init_host();
+ xics_setup_cpu();
+}
diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c
index 0a13fc19e287..6183799754af 100644
--- a/arch/powerpc/sysdev/xilinx_intc.c
+++ b/arch/powerpc/sysdev/xilinx_intc.c
@@ -71,7 +71,7 @@ static unsigned char xilinx_intc_map_senses[] = {
*/
static void xilinx_intc_mask(struct irq_data *d)
{
- int irq = virq_to_hw(d->irq);
+ int irq = irqd_to_hwirq(d);
void * regs = irq_data_get_irq_chip_data(d);
pr_debug("mask: %d\n", irq);
out_be32(regs + XINTC_CIE, 1 << irq);
@@ -87,7 +87,7 @@ static int xilinx_intc_set_type(struct irq_data *d, unsigned int flow_type)
*/
static void xilinx_intc_level_unmask(struct irq_data *d)
{
- int irq = virq_to_hw(d->irq);
+ int irq = irqd_to_hwirq(d);
void * regs = irq_data_get_irq_chip_data(d);
pr_debug("unmask: %d\n", irq);
out_be32(regs + XINTC_SIE, 1 << irq);
@@ -112,7 +112,7 @@ static struct irq_chip xilinx_intc_level_irqchip = {
*/
static void xilinx_intc_edge_unmask(struct irq_data *d)
{
- int irq = virq_to_hw(d->irq);
+ int irq = irqd_to_hwirq(d);
void *regs = irq_data_get_irq_chip_data(d);
pr_debug("unmask: %d\n", irq);
out_be32(regs + XINTC_SIE, 1 << irq);
@@ -120,7 +120,7 @@ static void xilinx_intc_edge_unmask(struct irq_data *d)
static void xilinx_intc_edge_ack(struct irq_data *d)
{
- int irq = virq_to_hw(d->irq);
+ int irq = irqd_to_hwirq(d);
void * regs = irq_data_get_irq_chip_data(d);
pr_debug("ack: %d\n", irq);
out_be32(regs + XINTC_IAR, 1 << irq);
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 33794c1d92c3..42541bbcc7fa 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -334,7 +334,7 @@ static void release_output_lock(void)
int cpus_are_in_xmon(void)
{
- return !cpus_empty(cpus_in_xmon);
+ return !cpumask_empty(&cpus_in_xmon);
}
#endif
@@ -373,7 +373,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
#ifdef CONFIG_SMP
cpu = smp_processor_id();
- if (cpu_isset(cpu, cpus_in_xmon)) {
+ if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
get_output_lock();
excprint(regs);
printf("cpu 0x%x: Exception %lx %s in xmon, "
@@ -396,10 +396,10 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
}
xmon_fault_jmp[cpu] = recurse_jmp;
- cpu_set(cpu, cpus_in_xmon);
+ cpumask_set_cpu(cpu, &cpus_in_xmon);
bp = NULL;
- if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF))
+ if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
bp = at_breakpoint(regs->nip);
if (bp || unrecoverable_excp(regs))
fromipi = 0;
@@ -437,10 +437,10 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
xmon_owner = cpu;
mb();
if (ncpus > 1) {
- smp_send_debugger_break(MSG_ALL_BUT_SELF);
+ smp_send_debugger_break();
/* wait for other cpus to come in */
for (timeout = 100000000; timeout != 0; --timeout) {
- if (cpus_weight(cpus_in_xmon) >= ncpus)
+ if (cpumask_weight(&cpus_in_xmon) >= ncpus)
break;
barrier();
}
@@ -484,7 +484,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
}
}
leave:
- cpu_clear(cpu, cpus_in_xmon);
+ cpumask_clear_cpu(cpu, &cpus_in_xmon);
xmon_fault_jmp[cpu] = NULL;
#else
/* UP is simple... */
@@ -529,7 +529,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
}
}
#else
- if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) {
+ if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
bp = at_breakpoint(regs->nip);
if (bp != NULL) {
int stepped = emulate_step(regs, bp->instr[0]);
@@ -578,7 +578,7 @@ static int xmon_bpt(struct pt_regs *regs)
struct bpt *bp;
unsigned long offset;
- if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
+ if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
return 0;
/* Are we at the trap at bp->instr[1] for some bp? */
@@ -609,7 +609,7 @@ static int xmon_sstep(struct pt_regs *regs)
static int xmon_dabr_match(struct pt_regs *regs)
{
- if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
+ if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
return 0;
if (dabr.enabled == 0)
return 0;
@@ -619,7 +619,7 @@ static int xmon_dabr_match(struct pt_regs *regs)
static int xmon_iabr_match(struct pt_regs *regs)
{
- if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) != (MSR_IR|MSR_SF))
+ if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) != (MSR_IR|MSR_64BIT))
return 0;
if (iabr == NULL)
return 0;
@@ -630,7 +630,7 @@ static int xmon_iabr_match(struct pt_regs *regs)
static int xmon_ipi(struct pt_regs *regs)
{
#ifdef CONFIG_SMP
- if (in_xmon && !cpu_isset(smp_processor_id(), cpus_in_xmon))
+ if (in_xmon && !cpumask_test_cpu(smp_processor_id(), &cpus_in_xmon))
xmon_core(regs, 1);
#endif
return 0;
@@ -644,7 +644,7 @@ static int xmon_fault_handler(struct pt_regs *regs)
if (in_xmon && catch_memory_errors)
handle_fault(regs); /* doesn't return */
- if ((regs->msr & (MSR_IR|MSR_PR|MSR_SF)) == (MSR_IR|MSR_SF)) {
+ if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT)) {
bp = in_breakpoint_table(regs->nip, &offset);
if (bp != NULL) {
regs->nip = bp->address + offset;
@@ -929,7 +929,7 @@ static int do_step(struct pt_regs *regs)
int stepped;
/* check we are in 64-bit kernel mode, translation enabled */
- if ((regs->msr & (MSR_SF|MSR_PR|MSR_IR)) == (MSR_SF|MSR_IR)) {
+ if ((regs->msr & (MSR_64BIT|MSR_PR|MSR_IR)) == (MSR_64BIT|MSR_IR)) {
if (mread(regs->nip, &instr, 4) == 4) {
stepped = emulate_step(regs, instr);
if (stepped < 0) {
@@ -976,7 +976,7 @@ static int cpu_cmd(void)
printf("cpus stopped:");
count = 0;
for (cpu = 0; cpu < NR_CPUS; ++cpu) {
- if (cpu_isset(cpu, cpus_in_xmon)) {
+ if (cpumask_test_cpu(cpu, &cpus_in_xmon)) {
if (count == 0)
printf(" %x", cpu);
++count;
@@ -992,7 +992,7 @@ static int cpu_cmd(void)
return 0;
}
/* try to switch to cpu specified */
- if (!cpu_isset(cpu, cpus_in_xmon)) {
+ if (!cpumask_test_cpu(cpu, &cpus_in_xmon)) {
printf("cpu 0x%x isn't in xmon\n", cpu);
return 0;
}
@@ -1497,6 +1497,10 @@ static void prregs(struct pt_regs *fp)
#endif
printf("pc = ");
xmon_print_symbol(fp->nip, " ", "\n");
+ if (TRAP(fp) != 0xc00 && cpu_has_feature(CPU_FTR_CFAR)) {
+ printf("cfar= ");
+ xmon_print_symbol(fp->orig_gpr3, " ", "\n");
+ }
printf("lr = ");
xmon_print_symbol(fp->link, " ", "\n");
printf("msr = "REG" cr = %.8lx\n", fp->msr, fp->ccr);
@@ -2663,7 +2667,7 @@ static void dump_stab(void)
void dump_segments(void)
{
- if (cpu_has_feature(CPU_FTR_SLB))
+ if (mmu_has_feature(MMU_FTR_SLB))
dump_slb();
else
dump_stab();
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 2508a6f31588..9fab2aa9c2c8 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -2,7 +2,7 @@ config MMU
def_bool y
config ZONE_DMA
- def_bool y if 64BIT
+ def_bool y
config LOCKDEP_SUPPORT
def_bool y
@@ -88,6 +88,7 @@ config S390
select HAVE_KERNEL_XZ
select HAVE_GET_USER_PAGES_FAST
select HAVE_ARCH_MUTEX_CPU_RELAX
+ select HAVE_ARCH_JUMP_LABEL if !MARCH_G5
select ARCH_INLINE_SPIN_TRYLOCK
select ARCH_INLINE_SPIN_TRYLOCK_BH
select ARCH_INLINE_SPIN_LOCK
@@ -229,17 +230,6 @@ config SYSVIPC_COMPAT
config AUDIT_ARCH
def_bool y
-config S390_EXEC_PROTECT
- def_bool y
- prompt "Data execute protection"
- help
- This option allows to enable a buffer overflow protection for user
- space programs and it also selects the addressing mode option above.
- The kernel parameter noexec=on will enable this feature and also
- switch the addressing modes, default is disabled. Enabling this (via
- kernel parameter) on machines earlier than IBM System z9 this will
- reduce system performance.
-
comment "Code generation options"
choice
diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c
index 5c91995b74e4..24bff4f1cc52 100644
--- a/arch/s390/appldata/appldata_base.c
+++ b/arch/s390/appldata/appldata_base.c
@@ -130,9 +130,7 @@ static void appldata_work_fn(struct work_struct *work)
{
struct list_head *lh;
struct appldata_ops *ops;
- int i;
- i = 0;
get_online_cpus();
mutex_lock(&appldata_ops_mutex);
list_for_each(lh, &appldata_ops_list) {
diff --git a/arch/s390/appldata/appldata_mem.c b/arch/s390/appldata/appldata_mem.c
index e43fe7537031..f7d3dc555bdb 100644
--- a/arch/s390/appldata/appldata_mem.c
+++ b/arch/s390/appldata/appldata_mem.c
@@ -92,9 +92,7 @@ static void appldata_get_mem_data(void *data)
mem_data->pswpin = ev[PSWPIN];
mem_data->pswpout = ev[PSWPOUT];
mem_data->pgalloc = ev[PGALLOC_NORMAL];
-#ifdef CONFIG_ZONE_DMA
mem_data->pgalloc += ev[PGALLOC_DMA];
-#endif
mem_data->pgfault = ev[PGFAULT];
mem_data->pgmajfault = ev[PGMAJFAULT];
diff --git a/arch/s390/crypto/Makefile b/arch/s390/crypto/Makefile
index 1cf81d77c5a5..7f0b7cda6259 100644
--- a/arch/s390/crypto/Makefile
+++ b/arch/s390/crypto/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_CRYPTO_SHA512_S390) += sha512_s390.o sha_common.o
obj-$(CONFIG_CRYPTO_DES_S390) += des_s390.o
obj-$(CONFIG_CRYPTO_AES_S390) += aes_s390.o
obj-$(CONFIG_S390_PRNG) += prng.o
+obj-$(CONFIG_CRYPTO_GHASH_S390) += ghash_s390.o
diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c
index 58f46734465f..a9ce135893f8 100644
--- a/arch/s390/crypto/aes_s390.c
+++ b/arch/s390/crypto/aes_s390.c
@@ -31,7 +31,8 @@
#define AES_KEYLEN_192 2
#define AES_KEYLEN_256 4
-static char keylen_flag = 0;
+static u8 *ctrblk;
+static char keylen_flag;
struct s390_aes_ctx {
u8 iv[AES_BLOCK_SIZE];
@@ -45,6 +46,24 @@ struct s390_aes_ctx {
} fallback;
};
+struct pcc_param {
+ u8 key[32];
+ u8 tweak[16];
+ u8 block[16];
+ u8 bit[16];
+ u8 xts[16];
+};
+
+struct s390_xts_ctx {
+ u8 key[32];
+ u8 xts_param[16];
+ struct pcc_param pcc;
+ long enc;
+ long dec;
+ int key_len;
+ struct crypto_blkcipher *fallback;
+};
+
/*
* Check if the key_len is supported by the HW.
* Returns 0 if it is, a positive number if it is not and software fallback is
@@ -504,15 +523,337 @@ static struct crypto_alg cbc_aes_alg = {
}
};
+static int xts_fallback_setkey(struct crypto_tfm *tfm, const u8 *key,
+ unsigned int len)
+{
+ struct s390_xts_ctx *xts_ctx = crypto_tfm_ctx(tfm);
+ unsigned int ret;
+
+ xts_ctx->fallback->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
+ xts_ctx->fallback->base.crt_flags |= (tfm->crt_flags &
+ CRYPTO_TFM_REQ_MASK);
+
+ ret = crypto_blkcipher_setkey(xts_ctx->fallback, key, len);
+ if (ret) {
+ tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
+ tfm->crt_flags |= (xts_ctx->fallback->base.crt_flags &
+ CRYPTO_TFM_RES_MASK);
+ }
+ return ret;
+}
+
+static int xts_fallback_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct s390_xts_ctx *xts_ctx = crypto_blkcipher_ctx(desc->tfm);
+ struct crypto_blkcipher *tfm;
+ unsigned int ret;
+
+ tfm = desc->tfm;
+ desc->tfm = xts_ctx->fallback;
+
+ ret = crypto_blkcipher_decrypt_iv(desc, dst, src, nbytes);
+
+ desc->tfm = tfm;
+ return ret;
+}
+
+static int xts_fallback_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct s390_xts_ctx *xts_ctx = crypto_blkcipher_ctx(desc->tfm);
+ struct crypto_blkcipher *tfm;
+ unsigned int ret;
+
+ tfm = desc->tfm;
+ desc->tfm = xts_ctx->fallback;
+
+ ret = crypto_blkcipher_encrypt_iv(desc, dst, src, nbytes);
+
+ desc->tfm = tfm;
+ return ret;
+}
+
+static int xts_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+ unsigned int key_len)
+{
+ struct s390_xts_ctx *xts_ctx = crypto_tfm_ctx(tfm);
+ u32 *flags = &tfm->crt_flags;
+
+ switch (key_len) {
+ case 32:
+ xts_ctx->enc = KM_XTS_128_ENCRYPT;
+ xts_ctx->dec = KM_XTS_128_DECRYPT;
+ memcpy(xts_ctx->key + 16, in_key, 16);
+ memcpy(xts_ctx->pcc.key + 16, in_key + 16, 16);
+ break;
+ case 48:
+ xts_ctx->enc = 0;
+ xts_ctx->dec = 0;
+ xts_fallback_setkey(tfm, in_key, key_len);
+ break;
+ case 64:
+ xts_ctx->enc = KM_XTS_256_ENCRYPT;
+ xts_ctx->dec = KM_XTS_256_DECRYPT;
+ memcpy(xts_ctx->key, in_key, 32);
+ memcpy(xts_ctx->pcc.key, in_key + 32, 32);
+ break;
+ default:
+ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+ return -EINVAL;
+ }
+ xts_ctx->key_len = key_len;
+ return 0;
+}
+
+static int xts_aes_crypt(struct blkcipher_desc *desc, long func,
+ struct s390_xts_ctx *xts_ctx,
+ struct blkcipher_walk *walk)
+{
+ unsigned int offset = (xts_ctx->key_len >> 1) & 0x10;
+ int ret = blkcipher_walk_virt(desc, walk);
+ unsigned int nbytes = walk->nbytes;
+ unsigned int n;
+ u8 *in, *out;
+ void *param;
+
+ if (!nbytes)
+ goto out;
+
+ memset(xts_ctx->pcc.block, 0, sizeof(xts_ctx->pcc.block));
+ memset(xts_ctx->pcc.bit, 0, sizeof(xts_ctx->pcc.bit));
+ memset(xts_ctx->pcc.xts, 0, sizeof(xts_ctx->pcc.xts));
+ memcpy(xts_ctx->pcc.tweak, walk->iv, sizeof(xts_ctx->pcc.tweak));
+ param = xts_ctx->pcc.key + offset;
+ ret = crypt_s390_pcc(func, param);
+ BUG_ON(ret < 0);
+
+ memcpy(xts_ctx->xts_param, xts_ctx->pcc.xts, 16);
+ param = xts_ctx->key + offset;
+ do {
+ /* only use complete blocks */
+ n = nbytes & ~(AES_BLOCK_SIZE - 1);
+ out = walk->dst.virt.addr;
+ in = walk->src.virt.addr;
+
+ ret = crypt_s390_km(func, param, out, in, n);
+ BUG_ON(ret < 0 || ret != n);
+
+ nbytes &= AES_BLOCK_SIZE - 1;
+ ret = blkcipher_walk_done(desc, walk, nbytes);
+ } while ((nbytes = walk->nbytes));
+out:
+ return ret;
+}
+
+static int xts_aes_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct s390_xts_ctx *xts_ctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+
+ if (unlikely(xts_ctx->key_len == 48))
+ return xts_fallback_encrypt(desc, dst, src, nbytes);
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ return xts_aes_crypt(desc, xts_ctx->enc, xts_ctx, &walk);
+}
+
+static int xts_aes_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct s390_xts_ctx *xts_ctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+
+ if (unlikely(xts_ctx->key_len == 48))
+ return xts_fallback_decrypt(desc, dst, src, nbytes);
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ return xts_aes_crypt(desc, xts_ctx->dec, xts_ctx, &walk);
+}
+
+static int xts_fallback_init(struct crypto_tfm *tfm)
+{
+ const char *name = tfm->__crt_alg->cra_name;
+ struct s390_xts_ctx *xts_ctx = crypto_tfm_ctx(tfm);
+
+ xts_ctx->fallback = crypto_alloc_blkcipher(name, 0,
+ CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
+
+ if (IS_ERR(xts_ctx->fallback)) {
+ pr_err("Allocating XTS fallback algorithm %s failed\n",
+ name);
+ return PTR_ERR(xts_ctx->fallback);
+ }
+ return 0;
+}
+
+static void xts_fallback_exit(struct crypto_tfm *tfm)
+{
+ struct s390_xts_ctx *xts_ctx = crypto_tfm_ctx(tfm);
+
+ crypto_free_blkcipher(xts_ctx->fallback);
+ xts_ctx->fallback = NULL;
+}
+
+static struct crypto_alg xts_aes_alg = {
+ .cra_name = "xts(aes)",
+ .cra_driver_name = "xts-aes-s390",
+ .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct s390_xts_ctx),
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(xts_aes_alg.cra_list),
+ .cra_init = xts_fallback_init,
+ .cra_exit = xts_fallback_exit,
+ .cra_u = {
+ .blkcipher = {
+ .min_keysize = 2 * AES_MIN_KEY_SIZE,
+ .max_keysize = 2 * AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = xts_aes_set_key,
+ .encrypt = xts_aes_encrypt,
+ .decrypt = xts_aes_decrypt,
+ }
+ }
+};
+
+static int ctr_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+ unsigned int key_len)
+{
+ struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm);
+
+ switch (key_len) {
+ case 16:
+ sctx->enc = KMCTR_AES_128_ENCRYPT;
+ sctx->dec = KMCTR_AES_128_DECRYPT;
+ break;
+ case 24:
+ sctx->enc = KMCTR_AES_192_ENCRYPT;
+ sctx->dec = KMCTR_AES_192_DECRYPT;
+ break;
+ case 32:
+ sctx->enc = KMCTR_AES_256_ENCRYPT;
+ sctx->dec = KMCTR_AES_256_DECRYPT;
+ break;
+ }
+
+ return aes_set_key(tfm, in_key, key_len);
+}
+
+static int ctr_aes_crypt(struct blkcipher_desc *desc, long func,
+ struct s390_aes_ctx *sctx, struct blkcipher_walk *walk)
+{
+ int ret = blkcipher_walk_virt_block(desc, walk, AES_BLOCK_SIZE);
+ unsigned int i, n, nbytes;
+ u8 buf[AES_BLOCK_SIZE];
+ u8 *out, *in;
+
+ if (!walk->nbytes)
+ return ret;
+
+ memcpy(ctrblk, walk->iv, AES_BLOCK_SIZE);
+ while ((nbytes = walk->nbytes) >= AES_BLOCK_SIZE) {
+ out = walk->dst.virt.addr;
+ in = walk->src.virt.addr;
+ while (nbytes >= AES_BLOCK_SIZE) {
+ /* only use complete blocks, max. PAGE_SIZE */
+ n = (nbytes > PAGE_SIZE) ? PAGE_SIZE :
+ nbytes & ~(AES_BLOCK_SIZE - 1);
+ for (i = AES_BLOCK_SIZE; i < n; i += AES_BLOCK_SIZE) {
+ memcpy(ctrblk + i, ctrblk + i - AES_BLOCK_SIZE,
+ AES_BLOCK_SIZE);
+ crypto_inc(ctrblk + i, AES_BLOCK_SIZE);
+ }
+ ret = crypt_s390_kmctr(func, sctx->key, out, in, n, ctrblk);
+ BUG_ON(ret < 0 || ret != n);
+ if (n > AES_BLOCK_SIZE)
+ memcpy(ctrblk, ctrblk + n - AES_BLOCK_SIZE,
+ AES_BLOCK_SIZE);
+ crypto_inc(ctrblk, AES_BLOCK_SIZE);
+ out += n;
+ in += n;
+ nbytes -= n;
+ }
+ ret = blkcipher_walk_done(desc, walk, nbytes);
+ }
+ /*
+ * final block may be < AES_BLOCK_SIZE, copy only nbytes
+ */
+ if (nbytes) {
+ out = walk->dst.virt.addr;
+ in = walk->src.virt.addr;
+ ret = crypt_s390_kmctr(func, sctx->key, buf, in,
+ AES_BLOCK_SIZE, ctrblk);
+ BUG_ON(ret < 0 || ret != AES_BLOCK_SIZE);
+ memcpy(out, buf, nbytes);
+ crypto_inc(ctrblk, AES_BLOCK_SIZE);
+ ret = blkcipher_walk_done(desc, walk, 0);
+ }
+ memcpy(walk->iv, ctrblk, AES_BLOCK_SIZE);
+ return ret;
+}
+
+static int ctr_aes_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ return ctr_aes_crypt(desc, sctx->enc, sctx, &walk);
+}
+
+static int ctr_aes_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ return ctr_aes_crypt(desc, sctx->dec, sctx, &walk);
+}
+
+static struct crypto_alg ctr_aes_alg = {
+ .cra_name = "ctr(aes)",
+ .cra_driver_name = "ctr-aes-s390",
+ .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct s390_aes_ctx),
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(ctr_aes_alg.cra_list),
+ .cra_u = {
+ .blkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = ctr_aes_set_key,
+ .encrypt = ctr_aes_encrypt,
+ .decrypt = ctr_aes_decrypt,
+ }
+ }
+};
+
static int __init aes_s390_init(void)
{
int ret;
- if (crypt_s390_func_available(KM_AES_128_ENCRYPT))
+ if (crypt_s390_func_available(KM_AES_128_ENCRYPT, CRYPT_S390_MSA))
keylen_flag |= AES_KEYLEN_128;
- if (crypt_s390_func_available(KM_AES_192_ENCRYPT))
+ if (crypt_s390_func_available(KM_AES_192_ENCRYPT, CRYPT_S390_MSA))
keylen_flag |= AES_KEYLEN_192;
- if (crypt_s390_func_available(KM_AES_256_ENCRYPT))
+ if (crypt_s390_func_available(KM_AES_256_ENCRYPT, CRYPT_S390_MSA))
keylen_flag |= AES_KEYLEN_256;
if (!keylen_flag)
@@ -535,9 +876,40 @@ static int __init aes_s390_init(void)
if (ret)
goto cbc_aes_err;
+ if (crypt_s390_func_available(KM_XTS_128_ENCRYPT,
+ CRYPT_S390_MSA | CRYPT_S390_MSA4) &&
+ crypt_s390_func_available(KM_XTS_256_ENCRYPT,
+ CRYPT_S390_MSA | CRYPT_S390_MSA4)) {
+ ret = crypto_register_alg(&xts_aes_alg);
+ if (ret)
+ goto xts_aes_err;
+ }
+
+ if (crypt_s390_func_available(KMCTR_AES_128_ENCRYPT,
+ CRYPT_S390_MSA | CRYPT_S390_MSA4) &&
+ crypt_s390_func_available(KMCTR_AES_192_ENCRYPT,
+ CRYPT_S390_MSA | CRYPT_S390_MSA4) &&
+ crypt_s390_func_available(KMCTR_AES_256_ENCRYPT,
+ CRYPT_S390_MSA | CRYPT_S390_MSA4)) {
+ ctrblk = (u8 *) __get_free_page(GFP_KERNEL);
+ if (!ctrblk) {
+ ret = -ENOMEM;
+ goto ctr_aes_err;
+ }
+ ret = crypto_register_alg(&ctr_aes_alg);
+ if (ret) {
+ free_page((unsigned long) ctrblk);
+ goto ctr_aes_err;
+ }
+ }
+
out:
return ret;
+ctr_aes_err:
+ crypto_unregister_alg(&xts_aes_alg);
+xts_aes_err:
+ crypto_unregister_alg(&cbc_aes_alg);
cbc_aes_err:
crypto_unregister_alg(&ecb_aes_alg);
ecb_aes_err:
@@ -548,6 +920,9 @@ aes_err:
static void __exit aes_s390_fini(void)
{
+ crypto_unregister_alg(&ctr_aes_alg);
+ free_page((unsigned long) ctrblk);
+ crypto_unregister_alg(&xts_aes_alg);
crypto_unregister_alg(&cbc_aes_alg);
crypto_unregister_alg(&ecb_aes_alg);
crypto_unregister_alg(&aes_alg);
diff --git a/arch/s390/crypto/crypt_s390.h b/arch/s390/crypto/crypt_s390.h
index 7ee9a1b4ad9f..49676771bd66 100644
--- a/arch/s390/crypto/crypt_s390.h
+++ b/arch/s390/crypto/crypt_s390.h
@@ -24,13 +24,18 @@
#define CRYPT_S390_PRIORITY 300
#define CRYPT_S390_COMPOSITE_PRIORITY 400
+#define CRYPT_S390_MSA 0x1
+#define CRYPT_S390_MSA3 0x2
+#define CRYPT_S390_MSA4 0x4
+
/* s390 cryptographic operations */
enum crypt_s390_operations {
CRYPT_S390_KM = 0x0100,
CRYPT_S390_KMC = 0x0200,
CRYPT_S390_KIMD = 0x0300,
CRYPT_S390_KLMD = 0x0400,
- CRYPT_S390_KMAC = 0x0500
+ CRYPT_S390_KMAC = 0x0500,
+ CRYPT_S390_KMCTR = 0x0600
};
/*
@@ -51,6 +56,10 @@ enum crypt_s390_km_func {
KM_AES_192_DECRYPT = CRYPT_S390_KM | 0x13 | 0x80,
KM_AES_256_ENCRYPT = CRYPT_S390_KM | 0x14,
KM_AES_256_DECRYPT = CRYPT_S390_KM | 0x14 | 0x80,
+ KM_XTS_128_ENCRYPT = CRYPT_S390_KM | 0x32,
+ KM_XTS_128_DECRYPT = CRYPT_S390_KM | 0x32 | 0x80,
+ KM_XTS_256_ENCRYPT = CRYPT_S390_KM | 0x34,
+ KM_XTS_256_DECRYPT = CRYPT_S390_KM | 0x34 | 0x80,
};
/*
@@ -75,6 +84,26 @@ enum crypt_s390_kmc_func {
};
/*
+ * function codes for KMCTR (CIPHER MESSAGE WITH COUNTER)
+ * instruction
+ */
+enum crypt_s390_kmctr_func {
+ KMCTR_QUERY = CRYPT_S390_KMCTR | 0x0,
+ KMCTR_DEA_ENCRYPT = CRYPT_S390_KMCTR | 0x1,
+ KMCTR_DEA_DECRYPT = CRYPT_S390_KMCTR | 0x1 | 0x80,
+ KMCTR_TDEA_128_ENCRYPT = CRYPT_S390_KMCTR | 0x2,
+ KMCTR_TDEA_128_DECRYPT = CRYPT_S390_KMCTR | 0x2 | 0x80,
+ KMCTR_TDEA_192_ENCRYPT = CRYPT_S390_KMCTR | 0x3,
+ KMCTR_TDEA_192_DECRYPT = CRYPT_S390_KMCTR | 0x3 | 0x80,
+ KMCTR_AES_128_ENCRYPT = CRYPT_S390_KMCTR | 0x12,
+ KMCTR_AES_128_DECRYPT = CRYPT_S390_KMCTR | 0x12 | 0x80,
+ KMCTR_AES_192_ENCRYPT = CRYPT_S390_KMCTR | 0x13,
+ KMCTR_AES_192_DECRYPT = CRYPT_S390_KMCTR | 0x13 | 0x80,
+ KMCTR_AES_256_ENCRYPT = CRYPT_S390_KMCTR | 0x14,
+ KMCTR_AES_256_DECRYPT = CRYPT_S390_KMCTR | 0x14 | 0x80,
+};
+
+/*
* function codes for KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST)
* instruction
*/
@@ -83,6 +112,7 @@ enum crypt_s390_kimd_func {
KIMD_SHA_1 = CRYPT_S390_KIMD | 1,
KIMD_SHA_256 = CRYPT_S390_KIMD | 2,
KIMD_SHA_512 = CRYPT_S390_KIMD | 3,
+ KIMD_GHASH = CRYPT_S390_KIMD | 65,
};
/*
@@ -284,6 +314,45 @@ static inline int crypt_s390_kmac(long func, void *param,
}
/**
+ * crypt_s390_kmctr:
+ * @func: the function code passed to KMCTR; see crypt_s390_kmctr_func
+ * @param: address of parameter block; see POP for details on each func
+ * @dest: address of destination memory area
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ * @counter: address of counter value
+ *
+ * Executes the KMCTR (CIPHER MESSAGE WITH COUNTER) operation of the CPU.
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for encryption/decryption funcs
+ */
+static inline int crypt_s390_kmctr(long func, void *param, u8 *dest,
+ const u8 *src, long src_len, u8 *counter)
+{
+ register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
+ register void *__param asm("1") = param;
+ register const u8 *__src asm("2") = src;
+ register long __src_len asm("3") = src_len;
+ register u8 *__dest asm("4") = dest;
+ register u8 *__ctr asm("6") = counter;
+ int ret = -1;
+
+ asm volatile(
+ "0: .insn rrf,0xb92d0000,%3,%1,%4,0 \n" /* KMCTR opcode */
+ "1: brc 1,0b \n" /* handle partial completion */
+ " la %0,0\n"
+ "2:\n"
+ EX_TABLE(0b,2b) EX_TABLE(1b,2b)
+ : "+d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest),
+ "+a" (__ctr)
+ : "d" (__func), "a" (__param) : "cc", "memory");
+ if (ret < 0)
+ return ret;
+ return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
+}
+
+/**
* crypt_s390_func_available:
* @func: the function code of the specific function; 0 if op in general
*
@@ -291,13 +360,17 @@ static inline int crypt_s390_kmac(long func, void *param,
*
* Returns 1 if func available; 0 if func or op in general not available
*/
-static inline int crypt_s390_func_available(int func)
+static inline int crypt_s390_func_available(int func,
+ unsigned int facility_mask)
{
unsigned char status[16];
int ret;
- /* check if CPACF facility (bit 17) is available */
- if (!test_facility(17))
+ if (facility_mask & CRYPT_S390_MSA && !test_facility(17))
+ return 0;
+ if (facility_mask & CRYPT_S390_MSA3 && !test_facility(76))
+ return 0;
+ if (facility_mask & CRYPT_S390_MSA4 && !test_facility(77))
return 0;
switch (func & CRYPT_S390_OP_MASK) {
@@ -316,6 +389,10 @@ static inline int crypt_s390_func_available(int func)
case CRYPT_S390_KMAC:
ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0);
break;
+ case CRYPT_S390_KMCTR:
+ ret = crypt_s390_kmctr(KMCTR_QUERY, &status, NULL, NULL, 0,
+ NULL);
+ break;
default:
return 0;
}
@@ -326,4 +403,31 @@ static inline int crypt_s390_func_available(int func)
return (status[func >> 3] & (0x80 >> (func & 7))) != 0;
}
+/**
+ * crypt_s390_pcc:
+ * @func: the function code passed to KM; see crypt_s390_km_func
+ * @param: address of parameter block; see POP for details on each func
+ *
+ * Executes the PCC (PERFORM CRYPTOGRAPHIC COMPUTATION) operation of the CPU.
+ *
+ * Returns -1 for failure, 0 for success.
+ */
+static inline int crypt_s390_pcc(long func, void *param)
+{
+ register long __func asm("0") = func & 0x7f; /* encrypt or decrypt */
+ register void *__param asm("1") = param;
+ int ret = -1;
+
+ asm volatile(
+ "0: .insn rre,0xb92c0000,0,0 \n" /* PCC opcode */
+ "1: brc 1,0b \n" /* handle partial completion */
+ " la %0,0\n"
+ "2:\n"
+ EX_TABLE(0b,2b) EX_TABLE(1b,2b)
+ : "+d" (ret)
+ : "d" (__func), "a" (__param) : "cc", "memory");
+ return ret;
+}
+
+
#endif /* _CRYPTO_ARCH_S390_CRYPT_S390_H */
diff --git a/arch/s390/crypto/des_check_key.c b/arch/s390/crypto/des_check_key.c
deleted file mode 100644
index 5706af266442..000000000000
--- a/arch/s390/crypto/des_check_key.c
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Function for checking keys for the DES and Tripple DES Encryption
- * algorithms.
- *
- * Originally released as descore by Dana L. How <how@isl.stanford.edu>.
- * Modified by Raimar Falke <rf13@inf.tu-dresden.de> for the Linux-Kernel.
- * Derived from Cryptoapi and Nettle implementations, adapted for in-place
- * scatterlist interface. Changed LGPL to GPL per section 3 of the LGPL.
- *
- * s390 Version:
- * Copyright IBM Corp. 2003
- * Author(s): Thomas Spatzier
- * Jan Glauber (jan.glauber@de.ibm.com)
- *
- * Derived from "crypto/des.c"
- * Copyright (c) 1992 Dana L. How.
- * Copyright (c) Raimar Falke <rf13@inf.tu-dresden.de>
- * Copyright (c) Gisle Sflensminde <gisle@ii.uib.no>
- * Copyright (C) 2001 Niels Mvller.
- * Copyright (c) 2002 James Morris <jmorris@intercode.com.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.
- *
- */
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/crypto.h>
-#include "crypto_des.h"
-
-#define ROR(d,c,o) ((d) = (d) >> (c) | (d) << (o))
-
-static const u8 parity[] = {
- 8,1,0,8,0,8,8,0,0,8,8,0,8,0,2,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,3,
- 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,
- 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,
- 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,
- 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,
- 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,
- 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,
- 4,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,5,0,8,0,8,8,0,0,8,8,0,8,0,6,8,
-};
-
-/*
- * RFC2451: Weak key checks SHOULD be performed.
- */
-int
-crypto_des_check_key(const u8 *key, unsigned int keylen, u32 *flags)
-{
- u32 n, w;
-
- n = parity[key[0]]; n <<= 4;
- n |= parity[key[1]]; n <<= 4;
- n |= parity[key[2]]; n <<= 4;
- n |= parity[key[3]]; n <<= 4;
- n |= parity[key[4]]; n <<= 4;
- n |= parity[key[5]]; n <<= 4;
- n |= parity[key[6]]; n <<= 4;
- n |= parity[key[7]];
- w = 0x88888888L;
-
- if ((*flags & CRYPTO_TFM_REQ_WEAK_KEY)
- && !((n - (w >> 3)) & w)) { /* 1 in 10^10 keys passes this test */
- if (n < 0x41415151) {
- if (n < 0x31312121) {
- if (n < 0x14141515) {
- /* 01 01 01 01 01 01 01 01 */
- if (n == 0x11111111) goto weak;
- /* 01 1F 01 1F 01 0E 01 0E */
- if (n == 0x13131212) goto weak;
- } else {
- /* 01 E0 01 E0 01 F1 01 F1 */
- if (n == 0x14141515) goto weak;
- /* 01 FE 01 FE 01 FE 01 FE */
- if (n == 0x16161616) goto weak;
- }
- } else {
- if (n < 0x34342525) {
- /* 1F 01 1F 01 0E 01 0E 01 */
- if (n == 0x31312121) goto weak;
- /* 1F 1F 1F 1F 0E 0E 0E 0E (?) */
- if (n == 0x33332222) goto weak;
- } else {
- /* 1F E0 1F E0 0E F1 0E F1 */
- if (n == 0x34342525) goto weak;
- /* 1F FE 1F FE 0E FE 0E FE */
- if (n == 0x36362626) goto weak;
- }
- }
- } else {
- if (n < 0x61616161) {
- if (n < 0x44445555) {
- /* E0 01 E0 01 F1 01 F1 01 */
- if (n == 0x41415151) goto weak;
- /* E0 1F E0 1F F1 0E F1 0E */
- if (n == 0x43435252) goto weak;
- } else {
- /* E0 E0 E0 E0 F1 F1 F1 F1 (?) */
- if (n == 0x44445555) goto weak;
- /* E0 FE E0 FE F1 FE F1 FE */
- if (n == 0x46465656) goto weak;
- }
- } else {
- if (n < 0x64646565) {
- /* FE 01 FE 01 FE 01 FE 01 */
- if (n == 0x61616161) goto weak;
- /* FE 1F FE 1F FE 0E FE 0E */
- if (n == 0x63636262) goto weak;
- } else {
- /* FE E0 FE E0 FE F1 FE F1 */
- if (n == 0x64646565) goto weak;
- /* FE FE FE FE FE FE FE FE */
- if (n == 0x66666666) goto weak;
- }
- }
- }
- }
- return 0;
-weak:
- *flags |= CRYPTO_TFM_RES_WEAK_KEY;
- return -EINVAL;
-}
-
-EXPORT_SYMBOL(crypto_des_check_key);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Key Check function for DES & DES3 Cipher Algorithms");
diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c
index cc5420118393..a52bfd124d86 100644
--- a/arch/s390/crypto/des_s390.c
+++ b/arch/s390/crypto/des_s390.c
@@ -3,7 +3,7 @@
*
* s390 implementation of the DES Cipher Algorithm.
*
- * Copyright IBM Corp. 2003,2007
+ * Copyright IBM Corp. 2003,2011
* Author(s): Thomas Spatzier
* Jan Glauber (jan.glauber@de.ibm.com)
*
@@ -22,22 +22,19 @@
#include "crypt_s390.h"
-#define DES3_192_KEY_SIZE (3 * DES_KEY_SIZE)
+#define DES3_KEY_SIZE (3 * DES_KEY_SIZE)
-struct crypt_s390_des_ctx {
- u8 iv[DES_BLOCK_SIZE];
- u8 key[DES_KEY_SIZE];
-};
+static u8 *ctrblk;
-struct crypt_s390_des3_192_ctx {
+struct s390_des_ctx {
u8 iv[DES_BLOCK_SIZE];
- u8 key[DES3_192_KEY_SIZE];
+ u8 key[DES3_KEY_SIZE];
};
static int des_setkey(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keylen)
+ unsigned int key_len)
{
- struct crypt_s390_des_ctx *dctx = crypto_tfm_ctx(tfm);
+ struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm);
u32 *flags = &tfm->crt_flags;
u32 tmp[DES_EXPKEY_WORDS];
@@ -47,22 +44,22 @@ static int des_setkey(struct crypto_tfm *tfm, const u8 *key,
return -EINVAL;
}
- memcpy(dctx->key, key, keylen);
+ memcpy(ctx->key, key, key_len);
return 0;
}
static void des_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
{
- struct crypt_s390_des_ctx *dctx = crypto_tfm_ctx(tfm);
+ struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm);
- crypt_s390_km(KM_DEA_ENCRYPT, dctx->key, out, in, DES_BLOCK_SIZE);
+ crypt_s390_km(KM_DEA_ENCRYPT, ctx->key, out, in, DES_BLOCK_SIZE);
}
static void des_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
{
- struct crypt_s390_des_ctx *dctx = crypto_tfm_ctx(tfm);
+ struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm);
- crypt_s390_km(KM_DEA_DECRYPT, dctx->key, out, in, DES_BLOCK_SIZE);
+ crypt_s390_km(KM_DEA_DECRYPT, ctx->key, out, in, DES_BLOCK_SIZE);
}
static struct crypto_alg des_alg = {
@@ -71,7 +68,7 @@ static struct crypto_alg des_alg = {
.cra_priority = CRYPT_S390_PRIORITY,
.cra_flags = CRYPTO_ALG_TYPE_CIPHER,
.cra_blocksize = DES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct crypt_s390_des_ctx),
+ .cra_ctxsize = sizeof(struct s390_des_ctx),
.cra_module = THIS_MODULE,
.cra_list = LIST_HEAD_INIT(des_alg.cra_list),
.cra_u = {
@@ -86,7 +83,7 @@ static struct crypto_alg des_alg = {
};
static int ecb_desall_crypt(struct blkcipher_desc *desc, long func,
- void *param, struct blkcipher_walk *walk)
+ u8 *key, struct blkcipher_walk *walk)
{
int ret = blkcipher_walk_virt(desc, walk);
unsigned int nbytes;
@@ -97,7 +94,7 @@ static int ecb_desall_crypt(struct blkcipher_desc *desc, long func,
u8 *out = walk->dst.virt.addr;
u8 *in = walk->src.virt.addr;
- ret = crypt_s390_km(func, param, out, in, n);
+ ret = crypt_s390_km(func, key, out, in, n);
BUG_ON((ret < 0) || (ret != n));
nbytes &= DES_BLOCK_SIZE - 1;
@@ -108,7 +105,7 @@ static int ecb_desall_crypt(struct blkcipher_desc *desc, long func,
}
static int cbc_desall_crypt(struct blkcipher_desc *desc, long func,
- void *param, struct blkcipher_walk *walk)
+ u8 *iv, struct blkcipher_walk *walk)
{
int ret = blkcipher_walk_virt(desc, walk);
unsigned int nbytes = walk->nbytes;
@@ -116,20 +113,20 @@ static int cbc_desall_crypt(struct blkcipher_desc *desc, long func,
if (!nbytes)
goto out;
- memcpy(param, walk->iv, DES_BLOCK_SIZE);
+ memcpy(iv, walk->iv, DES_BLOCK_SIZE);
do {
/* only use complete blocks */
unsigned int n = nbytes & ~(DES_BLOCK_SIZE - 1);
u8 *out = walk->dst.virt.addr;
u8 *in = walk->src.virt.addr;
- ret = crypt_s390_kmc(func, param, out, in, n);
+ ret = crypt_s390_kmc(func, iv, out, in, n);
BUG_ON((ret < 0) || (ret != n));
nbytes &= DES_BLOCK_SIZE - 1;
ret = blkcipher_walk_done(desc, walk, nbytes);
} while ((nbytes = walk->nbytes));
- memcpy(walk->iv, param, DES_BLOCK_SIZE);
+ memcpy(walk->iv, iv, DES_BLOCK_SIZE);
out:
return ret;
@@ -139,22 +136,22 @@ static int ecb_des_encrypt(struct blkcipher_desc *desc,
struct scatterlist *dst, struct scatterlist *src,
unsigned int nbytes)
{
- struct crypt_s390_des_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
struct blkcipher_walk walk;
blkcipher_walk_init(&walk, dst, src, nbytes);
- return ecb_desall_crypt(desc, KM_DEA_ENCRYPT, sctx->key, &walk);
+ return ecb_desall_crypt(desc, KM_DEA_ENCRYPT, ctx->key, &walk);
}
static int ecb_des_decrypt(struct blkcipher_desc *desc,
struct scatterlist *dst, struct scatterlist *src,
unsigned int nbytes)
{
- struct crypt_s390_des_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
struct blkcipher_walk walk;
blkcipher_walk_init(&walk, dst, src, nbytes);
- return ecb_desall_crypt(desc, KM_DEA_DECRYPT, sctx->key, &walk);
+ return ecb_desall_crypt(desc, KM_DEA_DECRYPT, ctx->key, &walk);
}
static struct crypto_alg ecb_des_alg = {
@@ -163,7 +160,7 @@ static struct crypto_alg ecb_des_alg = {
.cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
.cra_blocksize = DES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct crypt_s390_des_ctx),
+ .cra_ctxsize = sizeof(struct s390_des_ctx),
.cra_type = &crypto_blkcipher_type,
.cra_module = THIS_MODULE,
.cra_list = LIST_HEAD_INIT(ecb_des_alg.cra_list),
@@ -182,22 +179,22 @@ static int cbc_des_encrypt(struct blkcipher_desc *desc,
struct scatterlist *dst, struct scatterlist *src,
unsigned int nbytes)
{
- struct crypt_s390_des_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
struct blkcipher_walk walk;
blkcipher_walk_init(&walk, dst, src, nbytes);
- return cbc_desall_crypt(desc, KMC_DEA_ENCRYPT, sctx->iv, &walk);
+ return cbc_desall_crypt(desc, KMC_DEA_ENCRYPT, ctx->iv, &walk);
}
static int cbc_des_decrypt(struct blkcipher_desc *desc,
struct scatterlist *dst, struct scatterlist *src,
unsigned int nbytes)
{
- struct crypt_s390_des_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
struct blkcipher_walk walk;
blkcipher_walk_init(&walk, dst, src, nbytes);
- return cbc_desall_crypt(desc, KMC_DEA_DECRYPT, sctx->iv, &walk);
+ return cbc_desall_crypt(desc, KMC_DEA_DECRYPT, ctx->iv, &walk);
}
static struct crypto_alg cbc_des_alg = {
@@ -206,7 +203,7 @@ static struct crypto_alg cbc_des_alg = {
.cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
.cra_blocksize = DES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct crypt_s390_des_ctx),
+ .cra_ctxsize = sizeof(struct s390_des_ctx),
.cra_type = &crypto_blkcipher_type,
.cra_module = THIS_MODULE,
.cra_list = LIST_HEAD_INIT(cbc_des_alg.cra_list),
@@ -235,10 +232,10 @@ static struct crypto_alg cbc_des_alg = {
* property.
*
*/
-static int des3_192_setkey(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keylen)
+static int des3_setkey(struct crypto_tfm *tfm, const u8 *key,
+ unsigned int key_len)
{
- struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm);
+ struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm);
u32 *flags = &tfm->crt_flags;
if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) &&
@@ -248,141 +245,276 @@ static int des3_192_setkey(struct crypto_tfm *tfm, const u8 *key,
*flags |= CRYPTO_TFM_RES_WEAK_KEY;
return -EINVAL;
}
- memcpy(dctx->key, key, keylen);
+ memcpy(ctx->key, key, key_len);
return 0;
}
-static void des3_192_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+static void des3_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
{
- struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm);
+ struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm);
- crypt_s390_km(KM_TDEA_192_ENCRYPT, dctx->key, dst, (void*)src,
- DES_BLOCK_SIZE);
+ crypt_s390_km(KM_TDEA_192_ENCRYPT, ctx->key, dst, src, DES_BLOCK_SIZE);
}
-static void des3_192_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
+static void des3_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
{
- struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm);
+ struct s390_des_ctx *ctx = crypto_tfm_ctx(tfm);
- crypt_s390_km(KM_TDEA_192_DECRYPT, dctx->key, dst, (void*)src,
- DES_BLOCK_SIZE);
+ crypt_s390_km(KM_TDEA_192_DECRYPT, ctx->key, dst, src, DES_BLOCK_SIZE);
}
-static struct crypto_alg des3_192_alg = {
+static struct crypto_alg des3_alg = {
.cra_name = "des3_ede",
.cra_driver_name = "des3_ede-s390",
.cra_priority = CRYPT_S390_PRIORITY,
.cra_flags = CRYPTO_ALG_TYPE_CIPHER,
.cra_blocksize = DES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct crypt_s390_des3_192_ctx),
+ .cra_ctxsize = sizeof(struct s390_des_ctx),
.cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(des3_192_alg.cra_list),
+ .cra_list = LIST_HEAD_INIT(des3_alg.cra_list),
.cra_u = {
.cipher = {
- .cia_min_keysize = DES3_192_KEY_SIZE,
- .cia_max_keysize = DES3_192_KEY_SIZE,
- .cia_setkey = des3_192_setkey,
- .cia_encrypt = des3_192_encrypt,
- .cia_decrypt = des3_192_decrypt,
+ .cia_min_keysize = DES3_KEY_SIZE,
+ .cia_max_keysize = DES3_KEY_SIZE,
+ .cia_setkey = des3_setkey,
+ .cia_encrypt = des3_encrypt,
+ .cia_decrypt = des3_decrypt,
}
}
};
-static int ecb_des3_192_encrypt(struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ecb_des3_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
{
- struct crypt_s390_des3_192_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
struct blkcipher_walk walk;
blkcipher_walk_init(&walk, dst, src, nbytes);
- return ecb_desall_crypt(desc, KM_TDEA_192_ENCRYPT, sctx->key, &walk);
+ return ecb_desall_crypt(desc, KM_TDEA_192_ENCRYPT, ctx->key, &walk);
}
-static int ecb_des3_192_decrypt(struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int ecb_des3_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
{
- struct crypt_s390_des3_192_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
struct blkcipher_walk walk;
blkcipher_walk_init(&walk, dst, src, nbytes);
- return ecb_desall_crypt(desc, KM_TDEA_192_DECRYPT, sctx->key, &walk);
+ return ecb_desall_crypt(desc, KM_TDEA_192_DECRYPT, ctx->key, &walk);
}
-static struct crypto_alg ecb_des3_192_alg = {
+static struct crypto_alg ecb_des3_alg = {
.cra_name = "ecb(des3_ede)",
.cra_driver_name = "ecb-des3_ede-s390",
.cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
.cra_blocksize = DES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct crypt_s390_des3_192_ctx),
+ .cra_ctxsize = sizeof(struct s390_des_ctx),
.cra_type = &crypto_blkcipher_type,
.cra_module = THIS_MODULE,
.cra_list = LIST_HEAD_INIT(
- ecb_des3_192_alg.cra_list),
+ ecb_des3_alg.cra_list),
.cra_u = {
.blkcipher = {
- .min_keysize = DES3_192_KEY_SIZE,
- .max_keysize = DES3_192_KEY_SIZE,
- .setkey = des3_192_setkey,
- .encrypt = ecb_des3_192_encrypt,
- .decrypt = ecb_des3_192_decrypt,
+ .min_keysize = DES3_KEY_SIZE,
+ .max_keysize = DES3_KEY_SIZE,
+ .setkey = des3_setkey,
+ .encrypt = ecb_des3_encrypt,
+ .decrypt = ecb_des3_decrypt,
}
}
};
-static int cbc_des3_192_encrypt(struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int cbc_des3_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
{
- struct crypt_s390_des3_192_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
struct blkcipher_walk walk;
blkcipher_walk_init(&walk, dst, src, nbytes);
- return cbc_desall_crypt(desc, KMC_TDEA_192_ENCRYPT, sctx->iv, &walk);
+ return cbc_desall_crypt(desc, KMC_TDEA_192_ENCRYPT, ctx->iv, &walk);
}
-static int cbc_des3_192_decrypt(struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
+static int cbc_des3_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
{
- struct crypt_s390_des3_192_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
+ struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
struct blkcipher_walk walk;
blkcipher_walk_init(&walk, dst, src, nbytes);
- return cbc_desall_crypt(desc, KMC_TDEA_192_DECRYPT, sctx->iv, &walk);
+ return cbc_desall_crypt(desc, KMC_TDEA_192_DECRYPT, ctx->iv, &walk);
}
-static struct crypto_alg cbc_des3_192_alg = {
+static struct crypto_alg cbc_des3_alg = {
.cra_name = "cbc(des3_ede)",
.cra_driver_name = "cbc-des3_ede-s390",
.cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
.cra_blocksize = DES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct crypt_s390_des3_192_ctx),
+ .cra_ctxsize = sizeof(struct s390_des_ctx),
.cra_type = &crypto_blkcipher_type,
.cra_module = THIS_MODULE,
.cra_list = LIST_HEAD_INIT(
- cbc_des3_192_alg.cra_list),
+ cbc_des3_alg.cra_list),
.cra_u = {
.blkcipher = {
- .min_keysize = DES3_192_KEY_SIZE,
- .max_keysize = DES3_192_KEY_SIZE,
+ .min_keysize = DES3_KEY_SIZE,
+ .max_keysize = DES3_KEY_SIZE,
.ivsize = DES_BLOCK_SIZE,
- .setkey = des3_192_setkey,
- .encrypt = cbc_des3_192_encrypt,
- .decrypt = cbc_des3_192_decrypt,
+ .setkey = des3_setkey,
+ .encrypt = cbc_des3_encrypt,
+ .decrypt = cbc_des3_decrypt,
}
}
};
-static int des_s390_init(void)
+static int ctr_desall_crypt(struct blkcipher_desc *desc, long func,
+ struct s390_des_ctx *ctx, struct blkcipher_walk *walk)
+{
+ int ret = blkcipher_walk_virt_block(desc, walk, DES_BLOCK_SIZE);
+ unsigned int i, n, nbytes;
+ u8 buf[DES_BLOCK_SIZE];
+ u8 *out, *in;
+
+ memcpy(ctrblk, walk->iv, DES_BLOCK_SIZE);
+ while ((nbytes = walk->nbytes) >= DES_BLOCK_SIZE) {
+ out = walk->dst.virt.addr;
+ in = walk->src.virt.addr;
+ while (nbytes >= DES_BLOCK_SIZE) {
+ /* align to block size, max. PAGE_SIZE */
+ n = (nbytes > PAGE_SIZE) ? PAGE_SIZE :
+ nbytes & ~(DES_BLOCK_SIZE - 1);
+ for (i = DES_BLOCK_SIZE; i < n; i += DES_BLOCK_SIZE) {
+ memcpy(ctrblk + i, ctrblk + i - DES_BLOCK_SIZE,
+ DES_BLOCK_SIZE);
+ crypto_inc(ctrblk + i, DES_BLOCK_SIZE);
+ }
+ ret = crypt_s390_kmctr(func, ctx->key, out, in, n, ctrblk);
+ BUG_ON((ret < 0) || (ret != n));
+ if (n > DES_BLOCK_SIZE)
+ memcpy(ctrblk, ctrblk + n - DES_BLOCK_SIZE,
+ DES_BLOCK_SIZE);
+ crypto_inc(ctrblk, DES_BLOCK_SIZE);
+ out += n;
+ in += n;
+ nbytes -= n;
+ }
+ ret = blkcipher_walk_done(desc, walk, nbytes);
+ }
+
+ /* final block may be < DES_BLOCK_SIZE, copy only nbytes */
+ if (nbytes) {
+ out = walk->dst.virt.addr;
+ in = walk->src.virt.addr;
+ ret = crypt_s390_kmctr(func, ctx->key, buf, in,
+ DES_BLOCK_SIZE, ctrblk);
+ BUG_ON(ret < 0 || ret != DES_BLOCK_SIZE);
+ memcpy(out, buf, nbytes);
+ crypto_inc(ctrblk, DES_BLOCK_SIZE);
+ ret = blkcipher_walk_done(desc, walk, 0);
+ }
+ memcpy(walk->iv, ctrblk, DES_BLOCK_SIZE);
+ return ret;
+}
+
+static int ctr_des_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ return ctr_desall_crypt(desc, KMCTR_DEA_ENCRYPT, ctx, &walk);
+}
+
+static int ctr_des_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ return ctr_desall_crypt(desc, KMCTR_DEA_DECRYPT, ctx, &walk);
+}
+
+static struct crypto_alg ctr_des_alg = {
+ .cra_name = "ctr(des)",
+ .cra_driver_name = "ctr-des-s390",
+ .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct s390_des_ctx),
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(ctr_des_alg.cra_list),
+ .cra_u = {
+ .blkcipher = {
+ .min_keysize = DES_KEY_SIZE,
+ .max_keysize = DES_KEY_SIZE,
+ .ivsize = DES_BLOCK_SIZE,
+ .setkey = des_setkey,
+ .encrypt = ctr_des_encrypt,
+ .decrypt = ctr_des_decrypt,
+ }
+ }
+};
+
+static int ctr_des3_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ return ctr_desall_crypt(desc, KMCTR_TDEA_192_ENCRYPT, ctx, &walk);
+}
+
+static int ctr_des3_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct s390_des_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ return ctr_desall_crypt(desc, KMCTR_TDEA_192_DECRYPT, ctx, &walk);
+}
+
+static struct crypto_alg ctr_des3_alg = {
+ .cra_name = "ctr(des3_ede)",
+ .cra_driver_name = "ctr-des3_ede-s390",
+ .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct s390_des_ctx),
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(ctr_des3_alg.cra_list),
+ .cra_u = {
+ .blkcipher = {
+ .min_keysize = DES3_KEY_SIZE,
+ .max_keysize = DES3_KEY_SIZE,
+ .ivsize = DES_BLOCK_SIZE,
+ .setkey = des3_setkey,
+ .encrypt = ctr_des3_encrypt,
+ .decrypt = ctr_des3_decrypt,
+ }
+ }
+};
+
+static int __init des_s390_init(void)
{
int ret;
- if (!crypt_s390_func_available(KM_DEA_ENCRYPT) ||
- !crypt_s390_func_available(KM_TDEA_192_ENCRYPT))
+ if (!crypt_s390_func_available(KM_DEA_ENCRYPT, CRYPT_S390_MSA) ||
+ !crypt_s390_func_available(KM_TDEA_192_ENCRYPT, CRYPT_S390_MSA))
return -EOPNOTSUPP;
ret = crypto_register_alg(&des_alg);
@@ -394,23 +526,46 @@ static int des_s390_init(void)
ret = crypto_register_alg(&cbc_des_alg);
if (ret)
goto cbc_des_err;
- ret = crypto_register_alg(&des3_192_alg);
+ ret = crypto_register_alg(&des3_alg);
if (ret)
- goto des3_192_err;
- ret = crypto_register_alg(&ecb_des3_192_alg);
+ goto des3_err;
+ ret = crypto_register_alg(&ecb_des3_alg);
if (ret)
- goto ecb_des3_192_err;
- ret = crypto_register_alg(&cbc_des3_192_alg);
+ goto ecb_des3_err;
+ ret = crypto_register_alg(&cbc_des3_alg);
if (ret)
- goto cbc_des3_192_err;
+ goto cbc_des3_err;
+
+ if (crypt_s390_func_available(KMCTR_DEA_ENCRYPT,
+ CRYPT_S390_MSA | CRYPT_S390_MSA4) &&
+ crypt_s390_func_available(KMCTR_TDEA_192_ENCRYPT,
+ CRYPT_S390_MSA | CRYPT_S390_MSA4)) {
+ ret = crypto_register_alg(&ctr_des_alg);
+ if (ret)
+ goto ctr_des_err;
+ ret = crypto_register_alg(&ctr_des3_alg);
+ if (ret)
+ goto ctr_des3_err;
+ ctrblk = (u8 *) __get_free_page(GFP_KERNEL);
+ if (!ctrblk) {
+ ret = -ENOMEM;
+ goto ctr_mem_err;
+ }
+ }
out:
return ret;
-cbc_des3_192_err:
- crypto_unregister_alg(&ecb_des3_192_alg);
-ecb_des3_192_err:
- crypto_unregister_alg(&des3_192_alg);
-des3_192_err:
+ctr_mem_err:
+ crypto_unregister_alg(&ctr_des3_alg);
+ctr_des3_err:
+ crypto_unregister_alg(&ctr_des_alg);
+ctr_des_err:
+ crypto_unregister_alg(&cbc_des3_alg);
+cbc_des3_err:
+ crypto_unregister_alg(&ecb_des3_alg);
+ecb_des3_err:
+ crypto_unregister_alg(&des3_alg);
+des3_err:
crypto_unregister_alg(&cbc_des_alg);
cbc_des_err:
crypto_unregister_alg(&ecb_des_alg);
@@ -422,9 +577,14 @@ des_err:
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);
+ if (ctrblk) {
+ crypto_unregister_alg(&ctr_des_alg);
+ crypto_unregister_alg(&ctr_des3_alg);
+ free_page((unsigned long) ctrblk);
+ }
+ crypto_unregister_alg(&cbc_des3_alg);
+ crypto_unregister_alg(&ecb_des3_alg);
+ crypto_unregister_alg(&des3_alg);
crypto_unregister_alg(&cbc_des_alg);
crypto_unregister_alg(&ecb_des_alg);
crypto_unregister_alg(&des_alg);
diff --git a/arch/s390/crypto/ghash_s390.c b/arch/s390/crypto/ghash_s390.c
new file mode 100644
index 000000000000..b1bd170f24b1
--- /dev/null
+++ b/arch/s390/crypto/ghash_s390.c
@@ -0,0 +1,162 @@
+/*
+ * Cryptographic API.
+ *
+ * s390 implementation of the GHASH algorithm for GCM (Galois/Counter Mode).
+ *
+ * Copyright IBM Corp. 2011
+ * Author(s): Gerald Schaefer <gerald.schaefer@de.ibm.com>
+ */
+
+#include <crypto/internal/hash.h>
+#include <linux/module.h>
+
+#include "crypt_s390.h"
+
+#define GHASH_BLOCK_SIZE 16
+#define GHASH_DIGEST_SIZE 16
+
+struct ghash_ctx {
+ u8 icv[16];
+ u8 key[16];
+};
+
+struct ghash_desc_ctx {
+ u8 buffer[GHASH_BLOCK_SIZE];
+ u32 bytes;
+};
+
+static int ghash_init(struct shash_desc *desc)
+{
+ struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
+
+ memset(dctx, 0, sizeof(*dctx));
+
+ return 0;
+}
+
+static int ghash_setkey(struct crypto_shash *tfm,
+ const u8 *key, unsigned int keylen)
+{
+ struct ghash_ctx *ctx = crypto_shash_ctx(tfm);
+
+ if (keylen != GHASH_BLOCK_SIZE) {
+ crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+ }
+
+ memcpy(ctx->key, key, GHASH_BLOCK_SIZE);
+ memset(ctx->icv, 0, GHASH_BLOCK_SIZE);
+
+ return 0;
+}
+
+static int ghash_update(struct shash_desc *desc,
+ const u8 *src, unsigned int srclen)
+{
+ struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
+ struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
+ unsigned int n;
+ u8 *buf = dctx->buffer;
+ int ret;
+
+ if (dctx->bytes) {
+ u8 *pos = buf + (GHASH_BLOCK_SIZE - dctx->bytes);
+
+ n = min(srclen, dctx->bytes);
+ dctx->bytes -= n;
+ srclen -= n;
+
+ memcpy(pos, src, n);
+ src += n;
+
+ if (!dctx->bytes) {
+ ret = crypt_s390_kimd(KIMD_GHASH, ctx, buf,
+ GHASH_BLOCK_SIZE);
+ BUG_ON(ret != GHASH_BLOCK_SIZE);
+ }
+ }
+
+ n = srclen & ~(GHASH_BLOCK_SIZE - 1);
+ if (n) {
+ ret = crypt_s390_kimd(KIMD_GHASH, ctx, src, n);
+ BUG_ON(ret != n);
+ src += n;
+ srclen -= n;
+ }
+
+ if (srclen) {
+ dctx->bytes = GHASH_BLOCK_SIZE - srclen;
+ memcpy(buf, src, srclen);
+ }
+
+ return 0;
+}
+
+static void ghash_flush(struct ghash_ctx *ctx, struct ghash_desc_ctx *dctx)
+{
+ u8 *buf = dctx->buffer;
+ int ret;
+
+ if (dctx->bytes) {
+ u8 *pos = buf + (GHASH_BLOCK_SIZE - dctx->bytes);
+
+ memset(pos, 0, dctx->bytes);
+
+ ret = crypt_s390_kimd(KIMD_GHASH, ctx, buf, GHASH_BLOCK_SIZE);
+ BUG_ON(ret != GHASH_BLOCK_SIZE);
+ }
+
+ dctx->bytes = 0;
+}
+
+static int ghash_final(struct shash_desc *desc, u8 *dst)
+{
+ struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
+ struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
+
+ ghash_flush(ctx, dctx);
+ memcpy(dst, ctx->icv, GHASH_BLOCK_SIZE);
+
+ return 0;
+}
+
+static struct shash_alg ghash_alg = {
+ .digestsize = GHASH_DIGEST_SIZE,
+ .init = ghash_init,
+ .update = ghash_update,
+ .final = ghash_final,
+ .setkey = ghash_setkey,
+ .descsize = sizeof(struct ghash_desc_ctx),
+ .base = {
+ .cra_name = "ghash",
+ .cra_driver_name = "ghash-s390",
+ .cra_priority = CRYPT_S390_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
+ .cra_blocksize = GHASH_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct ghash_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(ghash_alg.base.cra_list),
+ },
+};
+
+static int __init ghash_mod_init(void)
+{
+ if (!crypt_s390_func_available(KIMD_GHASH,
+ CRYPT_S390_MSA | CRYPT_S390_MSA4))
+ return -EOPNOTSUPP;
+
+ return crypto_register_shash(&ghash_alg);
+}
+
+static void __exit ghash_mod_exit(void)
+{
+ crypto_unregister_shash(&ghash_alg);
+}
+
+module_init(ghash_mod_init);
+module_exit(ghash_mod_exit);
+
+MODULE_ALIAS("ghash");
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("GHASH Message Digest Algorithm, s390 implementation");
diff --git a/arch/s390/crypto/prng.c b/arch/s390/crypto/prng.c
index 8b16c479585b..0808fbf0f7d3 100644
--- a/arch/s390/crypto/prng.c
+++ b/arch/s390/crypto/prng.c
@@ -166,7 +166,7 @@ static int __init prng_init(void)
int ret;
/* check if the CPU has a PRNG */
- if (!crypt_s390_func_available(KMC_PRNG))
+ if (!crypt_s390_func_available(KMC_PRNG, CRYPT_S390_MSA))
return -EOPNOTSUPP;
if (prng_chunk_size < 8)
diff --git a/arch/s390/crypto/sha1_s390.c b/arch/s390/crypto/sha1_s390.c
index f6de7826c979..e9868c6e0a08 100644
--- a/arch/s390/crypto/sha1_s390.c
+++ b/arch/s390/crypto/sha1_s390.c
@@ -90,7 +90,7 @@ static struct shash_alg alg = {
static int __init sha1_s390_init(void)
{
- if (!crypt_s390_func_available(KIMD_SHA_1))
+ if (!crypt_s390_func_available(KIMD_SHA_1, CRYPT_S390_MSA))
return -EOPNOTSUPP;
return crypto_register_shash(&alg);
}
diff --git a/arch/s390/crypto/sha256_s390.c b/arch/s390/crypto/sha256_s390.c
index 61a7db372121..5ed8d64fc2ed 100644
--- a/arch/s390/crypto/sha256_s390.c
+++ b/arch/s390/crypto/sha256_s390.c
@@ -86,7 +86,7 @@ static struct shash_alg alg = {
static int sha256_s390_init(void)
{
- if (!crypt_s390_func_available(KIMD_SHA_256))
+ if (!crypt_s390_func_available(KIMD_SHA_256, CRYPT_S390_MSA))
return -EOPNOTSUPP;
return crypto_register_shash(&alg);
diff --git a/arch/s390/crypto/sha512_s390.c b/arch/s390/crypto/sha512_s390.c
index 4bf73d0dc525..32a81383b69c 100644
--- a/arch/s390/crypto/sha512_s390.c
+++ b/arch/s390/crypto/sha512_s390.c
@@ -132,7 +132,7 @@ static int __init init(void)
{
int ret;
- if (!crypt_s390_func_available(KIMD_SHA_512))
+ if (!crypt_s390_func_available(KIMD_SHA_512, CRYPT_S390_MSA))
return -EOPNOTSUPP;
if ((ret = crypto_register_shash(&sha512_alg)) < 0)
goto out;
diff --git a/arch/s390/hypfs/hypfs.h b/arch/s390/hypfs/hypfs.h
index 80c1526f2af3..d9df5a060a83 100644
--- a/arch/s390/hypfs/hypfs.h
+++ b/arch/s390/hypfs/hypfs.h
@@ -47,7 +47,7 @@ struct hypfs_dbfs_data {
void *buf;
void *buf_free_ptr;
size_t size;
- struct hypfs_dbfs_file *dbfs_file;;
+ struct hypfs_dbfs_file *dbfs_file;
struct kref kref;
};
diff --git a/arch/s390/include/asm/bitops.h b/arch/s390/include/asm/bitops.h
index e1c8f3a49884..667c6e9f6a34 100644
--- a/arch/s390/include/asm/bitops.h
+++ b/arch/s390/include/asm/bitops.h
@@ -621,6 +621,7 @@ static inline unsigned long find_first_zero_bit(const unsigned long *addr,
bits = __ffz_word(bytes*8, __load_ulong_be(addr, bytes));
return (bits < size) ? bits : size;
}
+#define find_first_zero_bit find_first_zero_bit
/**
* find_first_bit - find the first set bit in a memory region
@@ -641,6 +642,7 @@ static inline unsigned long find_first_bit(const unsigned long * addr,
bits = __ffs_word(bytes*8, __load_ulong_be(addr, bytes));
return (bits < size) ? bits : size;
}
+#define find_first_bit find_first_bit
/**
* find_next_zero_bit - find the first zero bit in a memory region
@@ -677,6 +679,7 @@ static inline int find_next_zero_bit (const unsigned long * addr,
}
return offset + find_first_zero_bit(p, size);
}
+#define find_next_zero_bit find_next_zero_bit
/**
* find_next_bit - find the first set bit in a memory region
@@ -713,6 +716,7 @@ static inline int find_next_bit (const unsigned long * addr,
}
return offset + find_first_bit(p, size);
}
+#define find_next_bit find_next_bit
/*
* Every architecture must define this function. It's the fastest
@@ -742,41 +746,6 @@ static inline int sched_find_first_bit(unsigned long *b)
* 23 22 21 20 19 18 17 16 31 30 29 28 27 26 25 24
*/
-static inline void __set_bit_le(unsigned long nr, void *addr)
-{
- __set_bit(nr ^ (__BITOPS_WORDSIZE - 8), addr);
-}
-
-static inline void __clear_bit_le(unsigned long nr, void *addr)
-{
- __clear_bit(nr ^ (__BITOPS_WORDSIZE - 8), addr);
-}
-
-static inline int __test_and_set_bit_le(unsigned long nr, void *addr)
-{
- return __test_and_set_bit(nr ^ (__BITOPS_WORDSIZE - 8), addr);
-}
-
-static inline int test_and_set_bit_le(unsigned long nr, void *addr)
-{
- return test_and_set_bit(nr ^ (__BITOPS_WORDSIZE - 8), addr);
-}
-
-static inline int __test_and_clear_bit_le(unsigned long nr, void *addr)
-{
- return __test_and_clear_bit(nr ^ (__BITOPS_WORDSIZE - 8), addr);
-}
-
-static inline int test_and_clear_bit_le(unsigned long nr, void *addr)
-{
- return test_and_clear_bit(nr ^ (__BITOPS_WORDSIZE - 8), addr);
-}
-
-static inline int test_bit_le(unsigned long nr, const void *addr)
-{
- return test_bit(nr ^ (__BITOPS_WORDSIZE - 8), addr);
-}
-
static inline int find_first_zero_bit_le(void *vaddr, unsigned int size)
{
unsigned long bytes, bits;
@@ -787,6 +756,7 @@ static inline int find_first_zero_bit_le(void *vaddr, unsigned int size)
bits = __ffz_word(bytes*8, __load_ulong_le(vaddr, bytes));
return (bits < size) ? bits : size;
}
+#define find_first_zero_bit_le find_first_zero_bit_le
static inline int find_next_zero_bit_le(void *vaddr, unsigned long size,
unsigned long offset)
@@ -816,6 +786,7 @@ static inline int find_next_zero_bit_le(void *vaddr, unsigned long size,
}
return offset + find_first_zero_bit_le(p, size);
}
+#define find_next_zero_bit_le find_next_zero_bit_le
static inline unsigned long find_first_bit_le(void *vaddr, unsigned long size)
{
@@ -827,6 +798,7 @@ static inline unsigned long find_first_bit_le(void *vaddr, unsigned long size)
bits = __ffs_word(bytes*8, __load_ulong_le(vaddr, bytes));
return (bits < size) ? bits : size;
}
+#define find_first_bit_le find_first_bit_le
static inline int find_next_bit_le(void *vaddr, unsigned long size,
unsigned long offset)
@@ -856,6 +828,9 @@ static inline int find_next_bit_le(void *vaddr, unsigned long size,
}
return offset + find_first_bit_le(p, size);
}
+#define find_next_bit_le find_next_bit_le
+
+#include <asm-generic/bitops/le.h>
#define ext2_set_bit_atomic(lock, nr, addr) \
test_and_set_bit_le(nr, addr)
diff --git a/arch/s390/include/asm/cacheflush.h b/arch/s390/include/asm/cacheflush.h
index 43a5c78046db..3e20383d0921 100644
--- a/arch/s390/include/asm/cacheflush.h
+++ b/arch/s390/include/asm/cacheflush.h
@@ -11,5 +11,6 @@ void kernel_map_pages(struct page *page, int numpages, int enable);
int set_memory_ro(unsigned long addr, int numpages);
int set_memory_rw(unsigned long addr, int numpages);
int set_memory_nx(unsigned long addr, int numpages);
+int set_memory_x(unsigned long addr, int numpages);
#endif /* _S390_CACHEFLUSH_H */
diff --git a/arch/s390/include/asm/cmpxchg.h b/arch/s390/include/asm/cmpxchg.h
index 7488e52efa97..81d7908416cf 100644
--- a/arch/s390/include/asm/cmpxchg.h
+++ b/arch/s390/include/asm/cmpxchg.h
@@ -167,7 +167,6 @@ static inline unsigned long __cmpxchg(void *ptr, unsigned long old,
#ifdef CONFIG_64BIT
#define cmpxchg64(ptr, o, n) \
({ \
- BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
cmpxchg((ptr), (o), (n)); \
})
#else /* CONFIG_64BIT */
diff --git a/arch/s390/include/asm/delay.h b/arch/s390/include/asm/delay.h
index 8a096b83f51f..0e3b35f96be1 100644
--- a/arch/s390/include/asm/delay.h
+++ b/arch/s390/include/asm/delay.h
@@ -14,10 +14,12 @@
#ifndef _S390_DELAY_H
#define _S390_DELAY_H
-extern void __udelay(unsigned long long usecs);
-extern void udelay_simple(unsigned long long usecs);
-extern void __delay(unsigned long loops);
+void __ndelay(unsigned long long nsecs);
+void __udelay(unsigned long long usecs);
+void udelay_simple(unsigned long long usecs);
+void __delay(unsigned long loops);
+#define ndelay(n) __ndelay((unsigned long long) (n))
#define udelay(n) __udelay((unsigned long long) (n))
#define mdelay(n) __udelay((unsigned long long) (n) * 1000)
diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h
index 10c029cfcc7d..64b61bf72e93 100644
--- a/arch/s390/include/asm/elf.h
+++ b/arch/s390/include/asm/elf.h
@@ -196,18 +196,6 @@ do { \
} while (0)
#endif /* __s390x__ */
-/*
- * An executable for which elf_read_implies_exec() returns TRUE will
- * have the READ_IMPLIES_EXEC personality flag set automatically.
- */
-#define elf_read_implies_exec(ex, executable_stack) \
-({ \
- if (current->mm->context.noexec && \
- executable_stack != EXSTACK_DISABLE_X) \
- disable_noexec(current->mm, current); \
- current->mm->context.noexec == 0; \
-})
-
#define STACK_RND_MASK 0x7ffUL
#define ARCH_DLINFO \
diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h
index 3c29be4836ed..b7931faaef6d 100644
--- a/arch/s390/include/asm/ftrace.h
+++ b/arch/s390/include/asm/ftrace.h
@@ -11,15 +11,13 @@ struct dyn_arch_ftrace { };
#ifdef CONFIG_64BIT
#define MCOUNT_INSN_SIZE 12
-#define MCOUNT_OFFSET 8
#else
#define MCOUNT_INSN_SIZE 20
-#define MCOUNT_OFFSET 4
#endif
static inline unsigned long ftrace_call_adjust(unsigned long addr)
{
- return addr - MCOUNT_OFFSET;
+ return addr;
}
#endif /* __ASSEMBLY__ */
diff --git a/arch/s390/include/asm/hugetlb.h b/arch/s390/include/asm/hugetlb.h
index b56403c2df28..799ed0f1643d 100644
--- a/arch/s390/include/asm/hugetlb.h
+++ b/arch/s390/include/asm/hugetlb.h
@@ -111,21 +111,10 @@ static inline void huge_ptep_invalidate(struct mm_struct *mm,
{
pmd_t *pmdp = (pmd_t *) ptep;
- if (!MACHINE_HAS_IDTE) {
- __pmd_csp(pmdp);
- if (mm->context.noexec) {
- pmdp = get_shadow_table(pmdp);
- __pmd_csp(pmdp);
- }
- return;
- }
-
- __pmd_idte(address, pmdp);
- if (mm->context.noexec) {
- pmdp = get_shadow_table(pmdp);
+ if (MACHINE_HAS_IDTE)
__pmd_idte(address, pmdp);
- }
- return;
+ else
+ __pmd_csp(pmdp);
}
#define huge_ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \
diff --git a/arch/s390/include/asm/irq.h b/arch/s390/include/asm/irq.h
index db14a311f1d2..ba7b01c726a3 100644
--- a/arch/s390/include/asm/irq.h
+++ b/arch/s390/include/asm/irq.h
@@ -2,6 +2,7 @@
#define _ASM_IRQ_H
#include <linux/hardirq.h>
+#include <linux/types.h>
enum interruption_class {
EXTERNAL_INTERRUPT,
@@ -15,6 +16,7 @@ enum interruption_class {
EXTINT_VRT,
EXTINT_SCP,
EXTINT_IUC,
+ EXTINT_CPM,
IOINT_QAI,
IOINT_QDI,
IOINT_DAS,
@@ -30,4 +32,11 @@ enum interruption_class {
NR_IRQS,
};
+typedef void (*ext_int_handler_t)(unsigned int, unsigned int, unsigned long);
+
+int register_external_interrupt(u16 code, ext_int_handler_t handler);
+int unregister_external_interrupt(u16 code, ext_int_handler_t handler);
+void service_subclass_irq_register(void);
+void service_subclass_irq_unregister(void);
+
#endif /* _ASM_IRQ_H */
diff --git a/arch/s390/include/asm/jump_label.h b/arch/s390/include/asm/jump_label.h
new file mode 100644
index 000000000000..95a6cf2b5b67
--- /dev/null
+++ b/arch/s390/include/asm/jump_label.h
@@ -0,0 +1,37 @@
+#ifndef _ASM_S390_JUMP_LABEL_H
+#define _ASM_S390_JUMP_LABEL_H
+
+#include <linux/types.h>
+
+#define JUMP_LABEL_NOP_SIZE 6
+
+#ifdef CONFIG_64BIT
+#define ASM_PTR ".quad"
+#define ASM_ALIGN ".balign 8"
+#else
+#define ASM_PTR ".long"
+#define ASM_ALIGN ".balign 4"
+#endif
+
+static __always_inline bool arch_static_branch(struct jump_label_key *key)
+{
+ asm goto("0: brcl 0,0\n"
+ ".pushsection __jump_table, \"aw\"\n"
+ ASM_ALIGN "\n"
+ ASM_PTR " 0b, %l[label], %0\n"
+ ".popsection\n"
+ : : "X" (key) : : label);
+ return false;
+label:
+ return true;
+}
+
+typedef unsigned long jump_label_t;
+
+struct jump_entry {
+ jump_label_t code;
+ jump_label_t target;
+ jump_label_t key;
+};
+
+#endif
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h
index 65e172f8209d..228cf0b295db 100644
--- a/arch/s390/include/asm/lowcore.h
+++ b/arch/s390/include/asm/lowcore.h
@@ -124,7 +124,7 @@ struct _lowcore {
/* Address space pointer. */
__u32 kernel_asce; /* 0x02ac */
__u32 user_asce; /* 0x02b0 */
- __u32 user_exec_asce; /* 0x02b4 */
+ __u32 current_pid; /* 0x02b4 */
/* SMP info area */
__u32 cpu_nr; /* 0x02b8 */
@@ -255,7 +255,7 @@ struct _lowcore {
/* Address space pointer. */
__u64 kernel_asce; /* 0x0310 */
__u64 user_asce; /* 0x0318 */
- __u64 user_exec_asce; /* 0x0320 */
+ __u64 current_pid; /* 0x0320 */
/* SMP info area */
__u32 cpu_nr; /* 0x0328 */
diff --git a/arch/s390/include/asm/mmu.h b/arch/s390/include/asm/mmu.h
index 78522cdefdd4..82d0847896a0 100644
--- a/arch/s390/include/asm/mmu.h
+++ b/arch/s390/include/asm/mmu.h
@@ -5,19 +5,18 @@ typedef struct {
atomic_t attach_count;
unsigned int flush_mm;
spinlock_t list_lock;
- struct list_head crst_list;
struct list_head pgtable_list;
unsigned long asce_bits;
unsigned long asce_limit;
unsigned long vdso_base;
- int noexec;
- int has_pgste; /* The mmu context has extended page tables */
- int alloc_pgste; /* cloned contexts will have extended page tables */
+ /* Cloned contexts will be created with extended page tables. */
+ unsigned int alloc_pgste:1;
+ /* The mmu context has extended page tables. */
+ unsigned int has_pgste:1;
} mm_context_t;
#define INIT_MM_CONTEXT(name) \
.context.list_lock = __SPIN_LOCK_UNLOCKED(name.context.list_lock), \
- .context.crst_list = LIST_HEAD_INIT(name.context.crst_list), \
.context.pgtable_list = LIST_HEAD_INIT(name.context.pgtable_list),
#endif
diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h
index 8c277caa8d3a..5682f160ff82 100644
--- a/arch/s390/include/asm/mmu_context.h
+++ b/arch/s390/include/asm/mmu_context.h
@@ -35,11 +35,9 @@ static inline int init_new_context(struct task_struct *tsk,
* and if has_pgste is set, it will create extended page
* tables.
*/
- mm->context.noexec = 0;
mm->context.has_pgste = 1;
mm->context.alloc_pgste = 1;
} else {
- mm->context.noexec = (user_mode == SECONDARY_SPACE_MODE);
mm->context.has_pgste = 0;
mm->context.alloc_pgste = 0;
}
@@ -63,10 +61,8 @@ static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk)
S390_lowcore.user_asce = mm->context.asce_bits | __pa(pgd);
if (user_mode != HOME_SPACE_MODE) {
/* Load primary space page table origin. */
- pgd = mm->context.noexec ? get_shadow_table(pgd) : pgd;
- S390_lowcore.user_exec_asce = mm->context.asce_bits | __pa(pgd);
asm volatile(LCTL_OPCODE" 1,1,%0\n"
- : : "m" (S390_lowcore.user_exec_asce) );
+ : : "m" (S390_lowcore.user_asce) );
} else
/* Load home space page table origin. */
asm volatile(LCTL_OPCODE" 13,13,%0"
diff --git a/arch/s390/include/asm/page.h b/arch/s390/include/asm/page.h
index 3c987e9ec8d6..accb372ddc7e 100644
--- a/arch/s390/include/asm/page.h
+++ b/arch/s390/include/asm/page.h
@@ -90,6 +90,7 @@ static inline void copy_page(void *to, void *from)
*/
typedef struct { unsigned long pgprot; } pgprot_t;
+typedef struct { unsigned long pgste; } pgste_t;
typedef struct { unsigned long pte; } pte_t;
typedef struct { unsigned long pmd; } pmd_t;
typedef struct { unsigned long pud; } pud_t;
@@ -97,18 +98,21 @@ typedef struct { unsigned long pgd; } pgd_t;
typedef pte_t *pgtable_t;
#define pgprot_val(x) ((x).pgprot)
+#define pgste_val(x) ((x).pgste)
#define pte_val(x) ((x).pte)
#define pmd_val(x) ((x).pmd)
#define pud_val(x) ((x).pud)
#define pgd_val(x) ((x).pgd)
+#define __pgste(x) ((pgste_t) { (x) } )
#define __pte(x) ((pte_t) { (x) } )
#define __pmd(x) ((pmd_t) { (x) } )
+#define __pud(x) ((pud_t) { (x) } )
#define __pgd(x) ((pgd_t) { (x) } )
#define __pgprot(x) ((pgprot_t) { (x) } )
-static inline void
-page_set_storage_key(unsigned long addr, unsigned int skey, int mapped)
+static inline void page_set_storage_key(unsigned long addr,
+ unsigned char skey, int mapped)
{
if (!mapped)
asm volatile(".insn rrf,0xb22b0000,%0,%1,8,0"
@@ -117,15 +121,59 @@ page_set_storage_key(unsigned long addr, unsigned int skey, int mapped)
asm volatile("sske %0,%1" : : "d" (skey), "a" (addr));
}
-static inline unsigned int
-page_get_storage_key(unsigned long addr)
+static inline unsigned char page_get_storage_key(unsigned long addr)
{
- unsigned int skey;
+ unsigned char skey;
- asm volatile("iske %0,%1" : "=d" (skey) : "a" (addr), "0" (0));
+ asm volatile("iske %0,%1" : "=d" (skey) : "a" (addr));
return skey;
}
+static inline int page_reset_referenced(unsigned long addr)
+{
+ unsigned int ipm;
+
+ asm volatile(
+ " rrbe 0,%1\n"
+ " ipm %0\n"
+ : "=d" (ipm) : "a" (addr) : "cc");
+ return !!(ipm & 0x20000000);
+}
+
+/* Bits int the storage key */
+#define _PAGE_CHANGED 0x02 /* HW changed bit */
+#define _PAGE_REFERENCED 0x04 /* HW referenced bit */
+#define _PAGE_FP_BIT 0x08 /* HW fetch protection bit */
+#define _PAGE_ACC_BITS 0xf0 /* HW access control bits */
+
+/*
+ * Test and clear dirty bit in storage key.
+ * We can't clear the changed bit atomically. This is a potential
+ * race against modification of the referenced bit. This function
+ * should therefore only be called if it is not mapped in any
+ * address space.
+ */
+#define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_DIRTY
+static inline int page_test_and_clear_dirty(unsigned long pfn, int mapped)
+{
+ unsigned char skey;
+
+ skey = page_get_storage_key(pfn << PAGE_SHIFT);
+ if (!(skey & _PAGE_CHANGED))
+ return 0;
+ page_set_storage_key(pfn << PAGE_SHIFT, skey & ~_PAGE_CHANGED, mapped);
+ return 1;
+}
+
+/*
+ * Test and clear referenced bit in storage key.
+ */
+#define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG
+static inline int page_test_and_clear_young(unsigned long pfn)
+{
+ return page_reset_referenced(pfn << PAGE_SHIFT);
+}
+
struct page;
void arch_free_page(struct page *page, int order);
void arch_alloc_page(struct page *page, int order);
diff --git a/arch/s390/include/asm/percpu.h b/arch/s390/include/asm/percpu.h
index f7ad8719d02d..5325c89a5843 100644
--- a/arch/s390/include/asm/percpu.h
+++ b/arch/s390/include/asm/percpu.h
@@ -1,6 +1,9 @@
#ifndef __ARCH_S390_PERCPU__
#define __ARCH_S390_PERCPU__
+#include <linux/preempt.h>
+#include <asm/cmpxchg.h>
+
/*
* s390 uses its own implementation for per cpu data, the offset of
* the cpu local data area is cached in the cpu's lowcore memory.
@@ -16,6 +19,71 @@
#define ARCH_NEEDS_WEAK_PER_CPU
#endif
+#define arch_irqsafe_cpu_to_op(pcp, val, op) \
+do { \
+ typedef typeof(pcp) pcp_op_T__; \
+ pcp_op_T__ old__, new__, prev__; \
+ pcp_op_T__ *ptr__; \
+ preempt_disable(); \
+ ptr__ = __this_cpu_ptr(&(pcp)); \
+ prev__ = *ptr__; \
+ do { \
+ old__ = prev__; \
+ new__ = old__ op (val); \
+ switch (sizeof(*ptr__)) { \
+ case 8: \
+ prev__ = cmpxchg64(ptr__, old__, new__); \
+ break; \
+ default: \
+ prev__ = cmpxchg(ptr__, old__, new__); \
+ } \
+ } while (prev__ != old__); \
+ preempt_enable(); \
+} while (0)
+
+#define irqsafe_cpu_add_1(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, +)
+#define irqsafe_cpu_add_2(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, +)
+#define irqsafe_cpu_add_4(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, +)
+#define irqsafe_cpu_add_8(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, +)
+
+#define irqsafe_cpu_and_1(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, &)
+#define irqsafe_cpu_and_2(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, &)
+#define irqsafe_cpu_and_4(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, &)
+#define irqsafe_cpu_and_8(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, &)
+
+#define irqsafe_cpu_or_1(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, |)
+#define irqsafe_cpu_or_2(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, |)
+#define irqsafe_cpu_or_4(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, |)
+#define irqsafe_cpu_or_8(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, |)
+
+#define irqsafe_cpu_xor_1(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, ^)
+#define irqsafe_cpu_xor_2(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, ^)
+#define irqsafe_cpu_xor_4(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, ^)
+#define irqsafe_cpu_xor_8(pcp, val) arch_irqsafe_cpu_to_op(pcp, val, ^)
+
+#define arch_irqsafe_cpu_cmpxchg(pcp, oval, nval) \
+({ \
+ typedef typeof(pcp) pcp_op_T__; \
+ pcp_op_T__ ret__; \
+ pcp_op_T__ *ptr__; \
+ preempt_disable(); \
+ ptr__ = __this_cpu_ptr(&(pcp)); \
+ switch (sizeof(*ptr__)) { \
+ case 8: \
+ ret__ = cmpxchg64(ptr__, oval, nval); \
+ break; \
+ default: \
+ ret__ = cmpxchg(ptr__, oval, nval); \
+ } \
+ preempt_enable(); \
+ ret__; \
+})
+
+#define irqsafe_cpu_cmpxchg_1(pcp, oval, nval) arch_irqsafe_cpu_cmpxchg(pcp, oval, nval)
+#define irqsafe_cpu_cmpxchg_2(pcp, oval, nval) arch_irqsafe_cpu_cmpxchg(pcp, oval, nval)
+#define irqsafe_cpu_cmpxchg_4(pcp, oval, nval) arch_irqsafe_cpu_cmpxchg(pcp, oval, nval)
+#define irqsafe_cpu_cmpxchg_8(pcp, oval, nval) arch_irqsafe_cpu_cmpxchg(pcp, oval, nval)
+
#include <asm-generic/percpu.h>
#endif /* __ARCH_S390_PERCPU__ */
diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h
index 082eb4e50e8b..f6314af3b354 100644
--- a/arch/s390/include/asm/pgalloc.h
+++ b/arch/s390/include/asm/pgalloc.h
@@ -19,14 +19,13 @@
#define check_pgt_cache() do {} while (0)
-unsigned long *crst_table_alloc(struct mm_struct *, int);
+unsigned long *crst_table_alloc(struct mm_struct *);
void crst_table_free(struct mm_struct *, unsigned long *);
void crst_table_free_rcu(struct mm_struct *, unsigned long *);
unsigned long *page_table_alloc(struct mm_struct *);
void page_table_free(struct mm_struct *, unsigned long *);
void page_table_free_rcu(struct mm_struct *, unsigned long *);
-void disable_noexec(struct mm_struct *, struct task_struct *);
static inline void clear_table(unsigned long *s, unsigned long val, size_t n)
{
@@ -50,9 +49,6 @@ static inline void clear_table(unsigned long *s, unsigned long val, size_t n)
static inline void crst_table_init(unsigned long *crst, unsigned long entry)
{
clear_table(crst, entry, sizeof(unsigned long)*2048);
- crst = get_shadow_table(crst);
- if (crst)
- clear_table(crst, entry, sizeof(unsigned long)*2048);
}
#ifndef __s390x__
@@ -69,10 +65,7 @@ static inline unsigned long pgd_entry_type(struct mm_struct *mm)
#define pmd_free(mm, x) do { } while (0)
#define pgd_populate(mm, pgd, pud) BUG()
-#define pgd_populate_kernel(mm, pgd, pud) BUG()
-
#define pud_populate(mm, pud, pmd) BUG()
-#define pud_populate_kernel(mm, pud, pmd) BUG()
#else /* __s390x__ */
@@ -90,7 +83,7 @@ void crst_table_downgrade(struct mm_struct *, unsigned long limit);
static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address)
{
- unsigned long *table = crst_table_alloc(mm, mm->context.noexec);
+ unsigned long *table = crst_table_alloc(mm);
if (table)
crst_table_init(table, _REGION3_ENTRY_EMPTY);
return (pud_t *) table;
@@ -99,43 +92,21 @@ static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long address)
static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
{
- unsigned long *table = crst_table_alloc(mm, mm->context.noexec);
+ unsigned long *table = crst_table_alloc(mm);
if (table)
crst_table_init(table, _SEGMENT_ENTRY_EMPTY);
return (pmd_t *) table;
}
#define pmd_free(mm, pmd) crst_table_free(mm, (unsigned long *) pmd)
-static inline void pgd_populate_kernel(struct mm_struct *mm,
- pgd_t *pgd, pud_t *pud)
-{
- pgd_val(*pgd) = _REGION2_ENTRY | __pa(pud);
-}
-
static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud)
{
- pgd_populate_kernel(mm, pgd, pud);
- if (mm->context.noexec) {
- pgd = get_shadow_table(pgd);
- pud = get_shadow_table(pud);
- pgd_populate_kernel(mm, pgd, pud);
- }
-}
-
-static inline void pud_populate_kernel(struct mm_struct *mm,
- pud_t *pud, pmd_t *pmd)
-{
- pud_val(*pud) = _REGION3_ENTRY | __pa(pmd);
+ pgd_val(*pgd) = _REGION2_ENTRY | __pa(pud);
}
static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
{
- pud_populate_kernel(mm, pud, pmd);
- if (mm->context.noexec) {
- pud = get_shadow_table(pud);
- pmd = get_shadow_table(pmd);
- pud_populate_kernel(mm, pud, pmd);
- }
+ pud_val(*pud) = _REGION3_ENTRY | __pa(pmd);
}
#endif /* __s390x__ */
@@ -143,29 +114,19 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
static inline pgd_t *pgd_alloc(struct mm_struct *mm)
{
spin_lock_init(&mm->context.list_lock);
- INIT_LIST_HEAD(&mm->context.crst_list);
INIT_LIST_HEAD(&mm->context.pgtable_list);
- return (pgd_t *)
- crst_table_alloc(mm, user_mode == SECONDARY_SPACE_MODE);
+ return (pgd_t *) crst_table_alloc(mm);
}
#define pgd_free(mm, pgd) crst_table_free(mm, (unsigned long *) pgd)
-static inline void pmd_populate_kernel(struct mm_struct *mm,
- pmd_t *pmd, pte_t *pte)
-{
- pmd_val(*pmd) = _SEGMENT_ENTRY + __pa(pte);
-}
-
static inline void pmd_populate(struct mm_struct *mm,
pmd_t *pmd, pgtable_t pte)
{
- pmd_populate_kernel(mm, pmd, pte);
- if (mm->context.noexec) {
- pmd = get_shadow_table(pmd);
- pmd_populate_kernel(mm, pmd, pte + PTRS_PER_PTE);
- }
+ pmd_val(*pmd) = _SEGMENT_ENTRY + __pa(pte);
}
+#define pmd_populate_kernel(mm, pmd, pte) pmd_populate(mm, pmd, pte)
+
#define pmd_pgtable(pmd) \
(pgtable_t)(pmd_val(pmd) & -sizeof(pte_t)*PTRS_PER_PTE)
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 02ace3491c51..c4773a2ef3d3 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -31,9 +31,8 @@
#ifndef __ASSEMBLY__
#include <linux/sched.h>
#include <linux/mm_types.h>
-#include <asm/bitops.h>
#include <asm/bug.h>
-#include <asm/processor.h>
+#include <asm/page.h>
extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096)));
extern void paging_init(void);
@@ -243,11 +242,13 @@ extern unsigned long VMALLOC_START;
/* Software bits in the page table entry */
#define _PAGE_SWT 0x001 /* SW pte type bit t */
#define _PAGE_SWX 0x002 /* SW pte type bit x */
-#define _PAGE_SPECIAL 0x004 /* SW associated with special page */
+#define _PAGE_SWC 0x004 /* SW pte changed bit (for KVM) */
+#define _PAGE_SWR 0x008 /* SW pte referenced bit (for KVM) */
+#define _PAGE_SPECIAL 0x010 /* SW associated with special page */
#define __HAVE_ARCH_PTE_SPECIAL
/* Set of bits not changed in pte_modify */
-#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_SPECIAL)
+#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_SPECIAL | _PAGE_SWC | _PAGE_SWR)
/* Six different types of pages. */
#define _PAGE_TYPE_EMPTY 0x400
@@ -256,8 +257,6 @@ extern unsigned long VMALLOC_START;
#define _PAGE_TYPE_FILE 0x601 /* bit 0x002 is used for offset !! */
#define _PAGE_TYPE_RO 0x200
#define _PAGE_TYPE_RW 0x000
-#define _PAGE_TYPE_EX_RO 0x202
-#define _PAGE_TYPE_EX_RW 0x002
/*
* Only four types for huge pages, using the invalid bit and protection bit
@@ -287,8 +286,6 @@ extern unsigned long VMALLOC_START;
* _PAGE_TYPE_FILE 11?1 -> 11?1
* _PAGE_TYPE_RO 0100 -> 1100
* _PAGE_TYPE_RW 0000 -> 1000
- * _PAGE_TYPE_EX_RO 0110 -> 1110
- * _PAGE_TYPE_EX_RW 0010 -> 1010
*
* pte_none is true for bits combinations 1000, 1010, 1100, 1110
* pte_present is true for bits combinations 0000, 0010, 0100, 0110, 1001
@@ -297,14 +294,17 @@ extern unsigned long VMALLOC_START;
*/
/* Page status table bits for virtualization */
-#define RCP_PCL_BIT 55
-#define RCP_HR_BIT 54
-#define RCP_HC_BIT 53
-#define RCP_GR_BIT 50
-#define RCP_GC_BIT 49
-
-/* User dirty bit for KVM's migration feature */
-#define KVM_UD_BIT 47
+#define RCP_ACC_BITS 0xf000000000000000UL
+#define RCP_FP_BIT 0x0800000000000000UL
+#define RCP_PCL_BIT 0x0080000000000000UL
+#define RCP_HR_BIT 0x0040000000000000UL
+#define RCP_HC_BIT 0x0020000000000000UL
+#define RCP_GR_BIT 0x0004000000000000UL
+#define RCP_GC_BIT 0x0002000000000000UL
+
+/* User dirty / referenced bit for KVM's migration feature */
+#define KVM_UR_BIT 0x0000800000000000UL
+#define KVM_UC_BIT 0x0000400000000000UL
#ifndef __s390x__
@@ -377,85 +377,54 @@ extern unsigned long VMALLOC_START;
#define _ASCE_USER_BITS (_ASCE_SPACE_SWITCH | _ASCE_PRIVATE_SPACE | \
_ASCE_ALT_EVENT)
-/* Bits int the storage key */
-#define _PAGE_CHANGED 0x02 /* HW changed bit */
-#define _PAGE_REFERENCED 0x04 /* HW referenced bit */
-
/*
* Page protection definitions.
*/
#define PAGE_NONE __pgprot(_PAGE_TYPE_NONE)
#define PAGE_RO __pgprot(_PAGE_TYPE_RO)
#define PAGE_RW __pgprot(_PAGE_TYPE_RW)
-#define PAGE_EX_RO __pgprot(_PAGE_TYPE_EX_RO)
-#define PAGE_EX_RW __pgprot(_PAGE_TYPE_EX_RW)
#define PAGE_KERNEL PAGE_RW
#define PAGE_COPY PAGE_RO
/*
- * Dependent on the EXEC_PROTECT option s390 can do execute protection.
- * Write permission always implies read permission. In theory with a
- * primary/secondary page table execute only can be implemented but
- * it would cost an additional bit in the pte to distinguish all the
- * different pte types. To avoid that execute permission currently
- * implies read permission as well.
+ * On s390 the page table entry has an invalid bit and a read-only bit.
+ * Read permission implies execute permission and write permission
+ * implies read permission.
*/
/*xwr*/
#define __P000 PAGE_NONE
#define __P001 PAGE_RO
#define __P010 PAGE_RO
#define __P011 PAGE_RO
-#define __P100 PAGE_EX_RO
-#define __P101 PAGE_EX_RO
-#define __P110 PAGE_EX_RO
-#define __P111 PAGE_EX_RO
+#define __P100 PAGE_RO
+#define __P101 PAGE_RO
+#define __P110 PAGE_RO
+#define __P111 PAGE_RO
#define __S000 PAGE_NONE
#define __S001 PAGE_RO
#define __S010 PAGE_RW
#define __S011 PAGE_RW
-#define __S100 PAGE_EX_RO
-#define __S101 PAGE_EX_RO
-#define __S110 PAGE_EX_RW
-#define __S111 PAGE_EX_RW
-
-#ifndef __s390x__
-# define PxD_SHADOW_SHIFT 1
-#else /* __s390x__ */
-# define PxD_SHADOW_SHIFT 2
-#endif /* __s390x__ */
+#define __S100 PAGE_RO
+#define __S101 PAGE_RO
+#define __S110 PAGE_RW
+#define __S111 PAGE_RW
-static inline void *get_shadow_table(void *table)
+static inline int mm_exclusive(struct mm_struct *mm)
{
- unsigned long addr, offset;
- struct page *page;
-
- addr = (unsigned long) table;
- offset = addr & ((PAGE_SIZE << PxD_SHADOW_SHIFT) - 1);
- page = virt_to_page((void *)(addr ^ offset));
- return (void *)(addr_t)(page->index ? (page->index | offset) : 0UL);
+ return likely(mm == current->active_mm &&
+ atomic_read(&mm->context.attach_count) <= 1);
}
-/*
- * Certain architectures need to do special things when PTEs
- * within a page table are directly modified. Thus, the following
- * hook is made available.
- */
-static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
- pte_t *ptep, pte_t entry)
+static inline int mm_has_pgste(struct mm_struct *mm)
{
- *ptep = entry;
- if (mm->context.noexec) {
- if (!(pte_val(entry) & _PAGE_INVALID) &&
- (pte_val(entry) & _PAGE_SWX))
- pte_val(entry) |= _PAGE_RO;
- else
- pte_val(entry) = _PAGE_TYPE_EMPTY;
- ptep[PTRS_PER_PTE] = entry;
- }
+#ifdef CONFIG_PGSTE
+ if (unlikely(mm->context.has_pgste))
+ return 1;
+#endif
+ return 0;
}
-
/*
* pgd/pmd/pte query functions
*/
@@ -568,52 +537,127 @@ static inline int pte_special(pte_t pte)
}
#define __HAVE_ARCH_PTE_SAME
-#define pte_same(a,b) (pte_val(a) == pte_val(b))
+static inline int pte_same(pte_t a, pte_t b)
+{
+ return pte_val(a) == pte_val(b);
+}
-static inline void rcp_lock(pte_t *ptep)
+static inline pgste_t pgste_get_lock(pte_t *ptep)
{
+ unsigned long new = 0;
#ifdef CONFIG_PGSTE
- unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
+ unsigned long old;
+
preempt_disable();
- while (test_and_set_bit(RCP_PCL_BIT, pgste))
- ;
+ asm(
+ " lg %0,%2\n"
+ "0: lgr %1,%0\n"
+ " nihh %0,0xff7f\n" /* clear RCP_PCL_BIT in old */
+ " oihh %1,0x0080\n" /* set RCP_PCL_BIT in new */
+ " csg %0,%1,%2\n"
+ " jl 0b\n"
+ : "=&d" (old), "=&d" (new), "=Q" (ptep[PTRS_PER_PTE])
+ : "Q" (ptep[PTRS_PER_PTE]) : "cc");
#endif
+ return __pgste(new);
}
-static inline void rcp_unlock(pte_t *ptep)
+static inline void pgste_set_unlock(pte_t *ptep, pgste_t pgste)
{
#ifdef CONFIG_PGSTE
- unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
- clear_bit(RCP_PCL_BIT, pgste);
+ asm(
+ " nihh %1,0xff7f\n" /* clear RCP_PCL_BIT */
+ " stg %1,%0\n"
+ : "=Q" (ptep[PTRS_PER_PTE])
+ : "d" (pgste_val(pgste)), "Q" (ptep[PTRS_PER_PTE]) : "cc");
preempt_enable();
#endif
}
-/* forward declaration for SetPageUptodate in page-flags.h*/
-static inline void page_clear_dirty(struct page *page, int mapped);
-#include <linux/page-flags.h>
-
-static inline void ptep_rcp_copy(pte_t *ptep)
+static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste)
{
#ifdef CONFIG_PGSTE
- struct page *page = virt_to_page(pte_val(*ptep));
- unsigned int skey;
- unsigned long *pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
-
- skey = page_get_storage_key(page_to_phys(page));
- if (skey & _PAGE_CHANGED) {
- set_bit_simple(RCP_GC_BIT, pgste);
- set_bit_simple(KVM_UD_BIT, pgste);
+ unsigned long pfn, bits;
+ unsigned char skey;
+
+ pfn = pte_val(*ptep) >> PAGE_SHIFT;
+ skey = page_get_storage_key(pfn);
+ bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED);
+ /* Clear page changed & referenced bit in the storage key */
+ if (bits) {
+ skey ^= bits;
+ page_set_storage_key(pfn, skey, 1);
}
- if (skey & _PAGE_REFERENCED)
- set_bit_simple(RCP_GR_BIT, pgste);
- if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) {
- SetPageDirty(page);
- set_bit_simple(KVM_UD_BIT, pgste);
- }
- if (test_and_clear_bit_simple(RCP_HR_BIT, pgste))
- SetPageReferenced(page);
+ /* Transfer page changed & referenced bit to guest bits in pgste */
+ pgste_val(pgste) |= bits << 48; /* RCP_GR_BIT & RCP_GC_BIT */
+ /* Get host changed & referenced bits from pgste */
+ bits |= (pgste_val(pgste) & (RCP_HR_BIT | RCP_HC_BIT)) >> 52;
+ /* Clear host bits in pgste. */
+ pgste_val(pgste) &= ~(RCP_HR_BIT | RCP_HC_BIT);
+ pgste_val(pgste) &= ~(RCP_ACC_BITS | RCP_FP_BIT);
+ /* Copy page access key and fetch protection bit to pgste */
+ pgste_val(pgste) |=
+ (unsigned long) (skey & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56;
+ /* Transfer changed and referenced to kvm user bits */
+ pgste_val(pgste) |= bits << 45; /* KVM_UR_BIT & KVM_UC_BIT */
+ /* Transfer changed & referenced to pte sofware bits */
+ pte_val(*ptep) |= bits << 1; /* _PAGE_SWR & _PAGE_SWC */
#endif
+ return pgste;
+
+}
+
+static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste)
+{
+#ifdef CONFIG_PGSTE
+ int young;
+
+ young = page_reset_referenced(pte_val(*ptep) & PAGE_MASK);
+ /* Transfer page referenced bit to pte software bit (host view) */
+ if (young || (pgste_val(pgste) & RCP_HR_BIT))
+ pte_val(*ptep) |= _PAGE_SWR;
+ /* Clear host referenced bit in pgste. */
+ pgste_val(pgste) &= ~RCP_HR_BIT;
+ /* Transfer page referenced bit to guest bit in pgste */
+ pgste_val(pgste) |= (unsigned long) young << 50; /* set RCP_GR_BIT */
+#endif
+ return pgste;
+
+}
+
+static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste)
+{
+#ifdef CONFIG_PGSTE
+ unsigned long pfn;
+ unsigned long okey, nkey;
+
+ pfn = pte_val(*ptep) >> PAGE_SHIFT;
+ okey = nkey = page_get_storage_key(pfn);
+ nkey &= ~(_PAGE_ACC_BITS | _PAGE_FP_BIT);
+ /* Set page access key and fetch protection bit from pgste */
+ nkey |= (pgste_val(pgste) & (RCP_ACC_BITS | RCP_FP_BIT)) >> 56;
+ if (okey != nkey)
+ page_set_storage_key(pfn, nkey, 1);
+#endif
+}
+
+/*
+ * Certain architectures need to do special things when PTEs
+ * within a page table are directly modified. Thus, the following
+ * hook is made available.
+ */
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t entry)
+{
+ pgste_t pgste;
+
+ if (mm_has_pgste(mm)) {
+ pgste = pgste_get_lock(ptep);
+ pgste_set_pte(ptep, pgste);
+ *ptep = entry;
+ pgste_set_unlock(ptep, pgste);
+ } else
+ *ptep = entry;
}
/*
@@ -627,19 +671,19 @@ static inline int pte_write(pte_t pte)
static inline int pte_dirty(pte_t pte)
{
- /* A pte is neither clean nor dirty on s/390. The dirty bit
- * is in the storage key. See page_test_and_clear_dirty for
- * details.
- */
+#ifdef CONFIG_PGSTE
+ if (pte_val(pte) & _PAGE_SWC)
+ return 1;
+#endif
return 0;
}
static inline int pte_young(pte_t pte)
{
- /* A pte is neither young nor old on s/390. The young bit
- * is in the storage key. See page_test_and_clear_young for
- * details.
- */
+#ifdef CONFIG_PGSTE
+ if (pte_val(pte) & _PAGE_SWR)
+ return 1;
+#endif
return 0;
}
@@ -647,64 +691,30 @@ static inline int pte_young(pte_t pte)
* pgd/pmd/pte modification functions
*/
-#ifndef __s390x__
-
-#define pgd_clear(pgd) do { } while (0)
-#define pud_clear(pud) do { } while (0)
-
-#else /* __s390x__ */
-
-static inline void pgd_clear_kernel(pgd_t * pgd)
+static inline void pgd_clear(pgd_t *pgd)
{
+#ifdef __s390x__
if ((pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R2)
pgd_val(*pgd) = _REGION2_ENTRY_EMPTY;
+#endif
}
-static inline void pgd_clear(pgd_t * pgd)
-{
- pgd_t *shadow = get_shadow_table(pgd);
-
- pgd_clear_kernel(pgd);
- if (shadow)
- pgd_clear_kernel(shadow);
-}
-
-static inline void pud_clear_kernel(pud_t *pud)
+static inline void pud_clear(pud_t *pud)
{
+#ifdef __s390x__
if ((pud_val(*pud) & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3)
pud_val(*pud) = _REGION3_ENTRY_EMPTY;
+#endif
}
-static inline void pud_clear(pud_t *pud)
-{
- pud_t *shadow = get_shadow_table(pud);
-
- pud_clear_kernel(pud);
- if (shadow)
- pud_clear_kernel(shadow);
-}
-
-#endif /* __s390x__ */
-
-static inline void pmd_clear_kernel(pmd_t * pmdp)
+static inline void pmd_clear(pmd_t *pmdp)
{
pmd_val(*pmdp) = _SEGMENT_ENTRY_EMPTY;
}
-static inline void pmd_clear(pmd_t *pmd)
-{
- pmd_t *shadow = get_shadow_table(pmd);
-
- pmd_clear_kernel(pmd);
- if (shadow)
- pmd_clear_kernel(shadow);
-}
-
static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{
pte_val(*ptep) = _PAGE_TYPE_EMPTY;
- if (mm->context.noexec)
- pte_val(ptep[PTRS_PER_PTE]) = _PAGE_TYPE_EMPTY;
}
/*
@@ -734,35 +744,27 @@ static inline pte_t pte_mkwrite(pte_t pte)
static inline pte_t pte_mkclean(pte_t pte)
{
- /* The only user of pte_mkclean is the fork() code.
- We must *not* clear the *physical* page dirty bit
- just because fork() wants to clear the dirty bit in
- *one* of the page's mappings. So we just do nothing. */
+#ifdef CONFIG_PGSTE
+ pte_val(pte) &= ~_PAGE_SWC;
+#endif
return pte;
}
static inline pte_t pte_mkdirty(pte_t pte)
{
- /* We do not explicitly set the dirty bit because the
- * sske instruction is slow. It is faster to let the
- * next instruction set the dirty bit.
- */
return pte;
}
static inline pte_t pte_mkold(pte_t pte)
{
- /* S/390 doesn't keep its dirty/referenced bit in the pte.
- * There is no point in clearing the real referenced bit.
- */
+#ifdef CONFIG_PGSTE
+ pte_val(pte) &= ~_PAGE_SWR;
+#endif
return pte;
}
static inline pte_t pte_mkyoung(pte_t pte)
{
- /* S/390 doesn't keep its dirty/referenced bit in the pte.
- * There is no point in setting the real referenced bit.
- */
return pte;
}
@@ -800,62 +802,60 @@ static inline pte_t pte_mkhuge(pte_t pte)
}
#endif
-#ifdef CONFIG_PGSTE
/*
- * Get (and clear) the user dirty bit for a PTE.
+ * Get (and clear) the user dirty bit for a pte.
*/
-static inline int kvm_s390_test_and_clear_page_dirty(struct mm_struct *mm,
- pte_t *ptep)
+static inline int ptep_test_and_clear_user_dirty(struct mm_struct *mm,
+ pte_t *ptep)
{
- int dirty;
- unsigned long *pgste;
- struct page *page;
- unsigned int skey;
-
- if (!mm->context.has_pgste)
- return -EINVAL;
- rcp_lock(ptep);
- pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
- page = virt_to_page(pte_val(*ptep));
- skey = page_get_storage_key(page_to_phys(page));
- if (skey & _PAGE_CHANGED) {
- set_bit_simple(RCP_GC_BIT, pgste);
- set_bit_simple(KVM_UD_BIT, pgste);
+ pgste_t pgste;
+ int dirty = 0;
+
+ if (mm_has_pgste(mm)) {
+ pgste = pgste_get_lock(ptep);
+ pgste = pgste_update_all(ptep, pgste);
+ dirty = !!(pgste_val(pgste) & KVM_UC_BIT);
+ pgste_val(pgste) &= ~KVM_UC_BIT;
+ pgste_set_unlock(ptep, pgste);
+ return dirty;
}
- if (test_and_clear_bit_simple(RCP_HC_BIT, pgste)) {
- SetPageDirty(page);
- set_bit_simple(KVM_UD_BIT, pgste);
- }
- dirty = test_and_clear_bit_simple(KVM_UD_BIT, pgste);
- if (skey & _PAGE_CHANGED)
- page_clear_dirty(page, 1);
- rcp_unlock(ptep);
return dirty;
}
-#endif
+
+/*
+ * Get (and clear) the user referenced bit for a pte.
+ */
+static inline int ptep_test_and_clear_user_young(struct mm_struct *mm,
+ pte_t *ptep)
+{
+ pgste_t pgste;
+ int young = 0;
+
+ if (mm_has_pgste(mm)) {
+ pgste = pgste_get_lock(ptep);
+ pgste = pgste_update_young(ptep, pgste);
+ young = !!(pgste_val(pgste) & KVM_UR_BIT);
+ pgste_val(pgste) &= ~KVM_UR_BIT;
+ pgste_set_unlock(ptep, pgste);
+ }
+ return young;
+}
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
unsigned long addr, pte_t *ptep)
{
-#ifdef CONFIG_PGSTE
- unsigned long physpage;
- int young;
- unsigned long *pgste;
+ pgste_t pgste;
+ pte_t pte;
- if (!vma->vm_mm->context.has_pgste)
- return 0;
- physpage = pte_val(*ptep) & PAGE_MASK;
- pgste = (unsigned long *) (ptep + PTRS_PER_PTE);
-
- young = ((page_get_storage_key(physpage) & _PAGE_REFERENCED) != 0);
- rcp_lock(ptep);
- if (young)
- set_bit_simple(RCP_GR_BIT, pgste);
- young |= test_and_clear_bit_simple(RCP_HR_BIT, pgste);
- rcp_unlock(ptep);
- return young;
-#endif
+ if (mm_has_pgste(vma->vm_mm)) {
+ pgste = pgste_get_lock(ptep);
+ pgste = pgste_update_young(ptep, pgste);
+ pte = *ptep;
+ *ptep = pte_mkold(pte);
+ pgste_set_unlock(ptep, pgste);
+ return pte_young(pte);
+ }
return 0;
}
@@ -867,10 +867,7 @@ static inline int ptep_clear_flush_young(struct vm_area_struct *vma,
* On s390 reference bits are in storage key and never in TLB
* With virtualization we handle the reference bit, without we
* we can simply return */
-#ifdef CONFIG_PGSTE
return ptep_test_and_clear_young(vma, address, ptep);
-#endif
- return 0;
}
static inline void __ptep_ipte(unsigned long address, pte_t *ptep)
@@ -890,25 +887,6 @@ static inline void __ptep_ipte(unsigned long address, pte_t *ptep)
}
}
-static inline void ptep_invalidate(struct mm_struct *mm,
- unsigned long address, pte_t *ptep)
-{
- if (mm->context.has_pgste) {
- rcp_lock(ptep);
- __ptep_ipte(address, ptep);
- ptep_rcp_copy(ptep);
- pte_val(*ptep) = _PAGE_TYPE_EMPTY;
- rcp_unlock(ptep);
- return;
- }
- __ptep_ipte(address, ptep);
- pte_val(*ptep) = _PAGE_TYPE_EMPTY;
- if (mm->context.noexec) {
- __ptep_ipte(address, ptep + PTRS_PER_PTE);
- pte_val(*(ptep + PTRS_PER_PTE)) = _PAGE_TYPE_EMPTY;
- }
-}
-
/*
* This is hard to understand. ptep_get_and_clear and ptep_clear_flush
* both clear the TLB for the unmapped pte. The reason is that
@@ -923,24 +901,72 @@ static inline void ptep_invalidate(struct mm_struct *mm,
* is a nop.
*/
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
-#define ptep_get_and_clear(__mm, __address, __ptep) \
-({ \
- pte_t __pte = *(__ptep); \
- (__mm)->context.flush_mm = 1; \
- if (atomic_read(&(__mm)->context.attach_count) > 1 || \
- (__mm) != current->active_mm) \
- ptep_invalidate(__mm, __address, __ptep); \
- else \
- pte_clear((__mm), (__address), (__ptep)); \
- __pte; \
-})
+static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
+ unsigned long address, pte_t *ptep)
+{
+ pgste_t pgste;
+ pte_t pte;
+
+ mm->context.flush_mm = 1;
+ if (mm_has_pgste(mm))
+ pgste = pgste_get_lock(ptep);
+
+ pte = *ptep;
+ if (!mm_exclusive(mm))
+ __ptep_ipte(address, ptep);
+ pte_val(*ptep) = _PAGE_TYPE_EMPTY;
+
+ if (mm_has_pgste(mm)) {
+ pgste = pgste_update_all(&pte, pgste);
+ pgste_set_unlock(ptep, pgste);
+ }
+ return pte;
+}
+
+#define __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION
+static inline pte_t ptep_modify_prot_start(struct mm_struct *mm,
+ unsigned long address,
+ pte_t *ptep)
+{
+ pte_t pte;
+
+ mm->context.flush_mm = 1;
+ if (mm_has_pgste(mm))
+ pgste_get_lock(ptep);
+
+ pte = *ptep;
+ if (!mm_exclusive(mm))
+ __ptep_ipte(address, ptep);
+ return pte;
+}
+
+static inline void ptep_modify_prot_commit(struct mm_struct *mm,
+ unsigned long address,
+ pte_t *ptep, pte_t pte)
+{
+ *ptep = pte;
+ if (mm_has_pgste(mm))
+ pgste_set_unlock(ptep, *(pgste_t *)(ptep + PTRS_PER_PTE));
+}
#define __HAVE_ARCH_PTEP_CLEAR_FLUSH
static inline pte_t ptep_clear_flush(struct vm_area_struct *vma,
unsigned long address, pte_t *ptep)
{
- pte_t pte = *ptep;
- ptep_invalidate(vma->vm_mm, address, ptep);
+ pgste_t pgste;
+ pte_t pte;
+
+ if (mm_has_pgste(vma->vm_mm))
+ pgste = pgste_get_lock(ptep);
+
+ pte = *ptep;
+ __ptep_ipte(address, ptep);
+ pte_val(*ptep) = _PAGE_TYPE_EMPTY;
+
+ if (mm_has_pgste(vma->vm_mm)) {
+ pgste = pgste_update_all(&pte, pgste);
+ pgste_set_unlock(ptep, pgste);
+ }
return pte;
}
@@ -953,76 +979,67 @@ static inline pte_t ptep_clear_flush(struct vm_area_struct *vma,
*/
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL
static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm,
- unsigned long addr,
+ unsigned long address,
pte_t *ptep, int full)
{
- pte_t pte = *ptep;
+ pgste_t pgste;
+ pte_t pte;
+
+ if (mm_has_pgste(mm))
+ pgste = pgste_get_lock(ptep);
+
+ pte = *ptep;
+ if (!full)
+ __ptep_ipte(address, ptep);
+ pte_val(*ptep) = _PAGE_TYPE_EMPTY;
- if (full)
- pte_clear(mm, addr, ptep);
- else
- ptep_invalidate(mm, addr, ptep);
+ if (mm_has_pgste(mm)) {
+ pgste = pgste_update_all(&pte, pgste);
+ pgste_set_unlock(ptep, pgste);
+ }
return pte;
}
#define __HAVE_ARCH_PTEP_SET_WRPROTECT
-#define ptep_set_wrprotect(__mm, __addr, __ptep) \
-({ \
- pte_t __pte = *(__ptep); \
- if (pte_write(__pte)) { \
- (__mm)->context.flush_mm = 1; \
- if (atomic_read(&(__mm)->context.attach_count) > 1 || \
- (__mm) != current->active_mm) \
- ptep_invalidate(__mm, __addr, __ptep); \
- set_pte_at(__mm, __addr, __ptep, pte_wrprotect(__pte)); \
- } \
-})
+static inline pte_t ptep_set_wrprotect(struct mm_struct *mm,
+ unsigned long address, pte_t *ptep)
+{
+ pgste_t pgste;
+ pte_t pte = *ptep;
-#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
-#define ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \
-({ \
- int __changed = !pte_same(*(__ptep), __entry); \
- if (__changed) { \
- ptep_invalidate((__vma)->vm_mm, __addr, __ptep); \
- set_pte_at((__vma)->vm_mm, __addr, __ptep, __entry); \
- } \
- __changed; \
-})
+ if (pte_write(pte)) {
+ mm->context.flush_mm = 1;
+ if (mm_has_pgste(mm))
+ pgste = pgste_get_lock(ptep);
-/*
- * Test and clear dirty bit in storage key.
- * We can't clear the changed bit atomically. This is a potential
- * race against modification of the referenced bit. This function
- * should therefore only be called if it is not mapped in any
- * address space.
- */
-#define __HAVE_ARCH_PAGE_TEST_DIRTY
-static inline int page_test_dirty(struct page *page)
-{
- return (page_get_storage_key(page_to_phys(page)) & _PAGE_CHANGED) != 0;
-}
+ if (!mm_exclusive(mm))
+ __ptep_ipte(address, ptep);
+ *ptep = pte_wrprotect(pte);
-#define __HAVE_ARCH_PAGE_CLEAR_DIRTY
-static inline void page_clear_dirty(struct page *page, int mapped)
-{
- page_set_storage_key(page_to_phys(page), PAGE_DEFAULT_KEY, mapped);
+ if (mm_has_pgste(mm))
+ pgste_set_unlock(ptep, pgste);
+ }
+ return pte;
}
-/*
- * Test and clear referenced bit in storage key.
- */
-#define __HAVE_ARCH_PAGE_TEST_AND_CLEAR_YOUNG
-static inline int page_test_and_clear_young(struct page *page)
+#define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
+static inline int ptep_set_access_flags(struct vm_area_struct *vma,
+ unsigned long address, pte_t *ptep,
+ pte_t entry, int dirty)
{
- unsigned long physpage = page_to_phys(page);
- int ccode;
-
- asm volatile(
- " rrbe 0,%1\n"
- " ipm %0\n"
- " srl %0,28\n"
- : "=d" (ccode) : "a" (physpage) : "cc" );
- return ccode & 2;
+ pgste_t pgste;
+
+ if (pte_same(*ptep, entry))
+ return 0;
+ if (mm_has_pgste(vma->vm_mm))
+ pgste = pgste_get_lock(ptep);
+
+ __ptep_ipte(address, ptep);
+ *ptep = entry;
+
+ if (mm_has_pgste(vma->vm_mm))
+ pgste_set_unlock(ptep, pgste);
+ return 1;
}
/*
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index 2c79b6416271..1300c3025334 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -84,6 +84,7 @@ struct thread_struct {
struct per_event per_event; /* Cause of the last PER trap */
/* pfault_wait is used to block the process on a pfault event */
unsigned long pfault_wait;
+ struct list_head list;
};
typedef struct thread_struct thread_struct;
diff --git a/arch/s390/include/asm/s390_ext.h b/arch/s390/include/asm/s390_ext.h
deleted file mode 100644
index 080876d5f196..000000000000
--- a/arch/s390/include/asm/s390_ext.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright IBM Corp. 1999,2010
- * Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com>,
- * Martin Schwidefsky <schwidefsky@de.ibm.com>,
- */
-
-#ifndef _S390_EXTINT_H
-#define _S390_EXTINT_H
-
-#include <linux/types.h>
-
-typedef void (*ext_int_handler_t)(unsigned int, unsigned int, unsigned long);
-
-int register_external_interrupt(__u16 code, ext_int_handler_t handler);
-int unregister_external_interrupt(__u16 code, ext_int_handler_t handler);
-
-#endif /* _S390_EXTINT_H */
diff --git a/arch/s390/include/asm/tlb.h b/arch/s390/include/asm/tlb.h
index 9074a54c4d10..77eee5477a52 100644
--- a/arch/s390/include/asm/tlb.h
+++ b/arch/s390/include/asm/tlb.h
@@ -29,65 +29,77 @@
#include <asm/smp.h>
#include <asm/tlbflush.h>
-#ifndef CONFIG_SMP
-#define TLB_NR_PTRS 1
-#else
-#define TLB_NR_PTRS 508
-#endif
-
struct mmu_gather {
struct mm_struct *mm;
unsigned int fullmm;
unsigned int nr_ptes;
unsigned int nr_pxds;
- void *array[TLB_NR_PTRS];
+ unsigned int max;
+ void **array;
+ void *local[8];
};
-DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
-
-static inline struct mmu_gather *tlb_gather_mmu(struct mm_struct *mm,
- unsigned int full_mm_flush)
+static inline void __tlb_alloc_page(struct mmu_gather *tlb)
{
- struct mmu_gather *tlb = &get_cpu_var(mmu_gathers);
+ unsigned long addr = __get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0);
+ if (addr) {
+ tlb->array = (void *) addr;
+ tlb->max = PAGE_SIZE / sizeof(void *);
+ }
+}
+
+static inline void tlb_gather_mmu(struct mmu_gather *tlb,
+ struct mm_struct *mm,
+ unsigned int full_mm_flush)
+{
tlb->mm = mm;
+ tlb->max = ARRAY_SIZE(tlb->local);
+ tlb->array = tlb->local;
tlb->fullmm = full_mm_flush;
- tlb->nr_ptes = 0;
- tlb->nr_pxds = TLB_NR_PTRS;
if (tlb->fullmm)
__tlb_flush_mm(mm);
- return tlb;
+ else
+ __tlb_alloc_page(tlb);
+ tlb->nr_ptes = 0;
+ tlb->nr_pxds = tlb->max;
}
-static inline void tlb_flush_mmu(struct mmu_gather *tlb,
- unsigned long start, unsigned long end)
+static inline void tlb_flush_mmu(struct mmu_gather *tlb)
{
- if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pxds < TLB_NR_PTRS))
+ if (!tlb->fullmm && (tlb->nr_ptes > 0 || tlb->nr_pxds < tlb->max))
__tlb_flush_mm(tlb->mm);
while (tlb->nr_ptes > 0)
page_table_free_rcu(tlb->mm, tlb->array[--tlb->nr_ptes]);
- while (tlb->nr_pxds < TLB_NR_PTRS)
+ while (tlb->nr_pxds < tlb->max)
crst_table_free_rcu(tlb->mm, tlb->array[tlb->nr_pxds++]);
}
static inline void tlb_finish_mmu(struct mmu_gather *tlb,
unsigned long start, unsigned long end)
{
- tlb_flush_mmu(tlb, start, end);
+ tlb_flush_mmu(tlb);
rcu_table_freelist_finish();
/* keep the page table cache within bounds */
check_pgt_cache();
- put_cpu_var(mmu_gathers);
+ if (tlb->array != tlb->local)
+ free_pages((unsigned long) tlb->array, 0);
}
/*
* Release the page cache reference for a pte removed by
- * tlb_ptep_clear_flush. In both flush modes the tlb fo a page cache page
+ * tlb_ptep_clear_flush. In both flush modes the tlb for a page cache page
* has already been freed, so just do free_page_and_swap_cache.
*/
+static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+ free_page_and_swap_cache(page);
+ return 1; /* avoid calling tlb_flush_mmu */
+}
+
static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
{
free_page_and_swap_cache(page);
@@ -103,7 +115,7 @@ static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
if (!tlb->fullmm) {
tlb->array[tlb->nr_ptes++] = pte;
if (tlb->nr_ptes >= tlb->nr_pxds)
- tlb_flush_mmu(tlb, 0, 0);
+ tlb_flush_mmu(tlb);
} else
page_table_free(tlb->mm, (unsigned long *) pte);
}
@@ -124,7 +136,7 @@ static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd,
if (!tlb->fullmm) {
tlb->array[--tlb->nr_pxds] = pmd;
if (tlb->nr_ptes >= tlb->nr_pxds)
- tlb_flush_mmu(tlb, 0, 0);
+ tlb_flush_mmu(tlb);
} else
crst_table_free(tlb->mm, (unsigned long *) pmd);
#endif
@@ -146,7 +158,7 @@ static inline void pud_free_tlb(struct mmu_gather *tlb, pud_t *pud,
if (!tlb->fullmm) {
tlb->array[--tlb->nr_pxds] = pud;
if (tlb->nr_ptes >= tlb->nr_pxds)
- tlb_flush_mmu(tlb, 0, 0);
+ tlb_flush_mmu(tlb);
} else
crst_table_free(tlb->mm, (unsigned long *) pud);
#endif
diff --git a/arch/s390/include/asm/tlbflush.h b/arch/s390/include/asm/tlbflush.h
index 29d5d6d4becc..b7a4f2eb0057 100644
--- a/arch/s390/include/asm/tlbflush.h
+++ b/arch/s390/include/asm/tlbflush.h
@@ -50,7 +50,7 @@ static inline void __tlb_flush_full(struct mm_struct *mm)
/*
* If the process only ran on the local cpu, do a local flush.
*/
- local_cpumask = cpumask_of_cpu(smp_processor_id());
+ cpumask_copy(&local_cpumask, cpumask_of(smp_processor_id()));
if (cpumask_equal(mm_cpumask(mm), &local_cpumask))
__tlb_flush_local();
else
@@ -80,16 +80,11 @@ static inline void __tlb_flush_mm(struct mm_struct * mm)
* on all cpus instead of doing a local flush if the mm
* only ran on the local cpu.
*/
- if (MACHINE_HAS_IDTE) {
- if (mm->context.noexec)
- __tlb_flush_idte((unsigned long)
- get_shadow_table(mm->pgd) |
- mm->context.asce_bits);
+ if (MACHINE_HAS_IDTE)
__tlb_flush_idte((unsigned long) mm->pgd |
mm->context.asce_bits);
- return;
- }
- __tlb_flush_full(mm);
+ else
+ __tlb_flush_full(mm);
}
static inline void __tlb_flush_mm_cond(struct mm_struct * mm)
diff --git a/arch/s390/include/asm/topology.h b/arch/s390/include/asm/topology.h
index c5338834ddbd..005d77d8ae2a 100644
--- a/arch/s390/include/asm/topology.h
+++ b/arch/s390/include/asm/topology.h
@@ -7,7 +7,7 @@
extern unsigned char cpu_core_id[NR_CPUS];
extern cpumask_t cpu_core_map[NR_CPUS];
-static inline const struct cpumask *cpu_coregroup_mask(unsigned int cpu)
+static inline const struct cpumask *cpu_coregroup_mask(int cpu)
{
return &cpu_core_map[cpu];
}
@@ -21,7 +21,7 @@ static inline const struct cpumask *cpu_coregroup_mask(unsigned int cpu)
extern unsigned char cpu_book_id[NR_CPUS];
extern cpumask_t cpu_book_map[NR_CPUS];
-static inline const struct cpumask *cpu_book_mask(unsigned int cpu)
+static inline const struct cpumask *cpu_book_mask(int cpu)
{
return &cpu_book_map[cpu];
}
diff --git a/arch/s390/include/asm/uaccess.h b/arch/s390/include/asm/uaccess.h
index 2d9ea11f919a..2b23885e81e9 100644
--- a/arch/s390/include/asm/uaccess.h
+++ b/arch/s390/include/asm/uaccess.h
@@ -49,12 +49,13 @@
#define segment_eq(a,b) ((a).ar4 == (b).ar4)
+#define __access_ok(addr, size) \
+({ \
+ __chk_user_ptr(addr); \
+ 1; \
+})
-static inline int __access_ok(const void __user *addr, unsigned long size)
-{
- return 1;
-}
-#define access_ok(type,addr,size) __access_ok(addr,size)
+#define access_ok(type, addr, size) __access_ok(addr, size)
/*
* The exception table consists of pairs of addresses: the first is the
diff --git a/arch/s390/include/asm/unistd.h b/arch/s390/include/asm/unistd.h
index e82152572377..9208e69245a0 100644
--- a/arch/s390/include/asm/unistd.h
+++ b/arch/s390/include/asm/unistd.h
@@ -385,6 +385,7 @@
/* Ignore system calls that are also reachable via sys_socket */
#define __IGNORE_recvmmsg
+#define __IGNORE_sendmmsg
#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index 64230bc392fa..df3732249baa 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -20,10 +20,10 @@ CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"'
CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w
-obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o \
- processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
- s390_ext.o debug.o irq.o ipl.o dis.o diag.o mem_detect.o \
- vdso.o vtime.o sysinfo.o nmi.o sclp.o
+obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o vtime.o \
+ processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o \
+ debug.o irq.o ipl.o dis.o diag.o mem_detect.o sclp.o vdso.o \
+ sysinfo.o jump_label.o
obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o)
obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
index fe03c140002a..edfbd17d7082 100644
--- a/arch/s390/kernel/asm-offsets.c
+++ b/arch/s390/kernel/asm-offsets.c
@@ -124,13 +124,11 @@ int main(void)
DEFINE(__LC_LAST_UPDATE_TIMER, offsetof(struct _lowcore, last_update_timer));
DEFINE(__LC_LAST_UPDATE_CLOCK, offsetof(struct _lowcore, last_update_clock));
DEFINE(__LC_CURRENT, offsetof(struct _lowcore, current_task));
+ DEFINE(__LC_CURRENT_PID, offsetof(struct _lowcore, current_pid));
DEFINE(__LC_THREAD_INFO, offsetof(struct _lowcore, thread_info));
DEFINE(__LC_KERNEL_STACK, offsetof(struct _lowcore, kernel_stack));
DEFINE(__LC_ASYNC_STACK, offsetof(struct _lowcore, async_stack));
DEFINE(__LC_PANIC_STACK, offsetof(struct _lowcore, panic_stack));
- DEFINE(__LC_KERNEL_ASCE, offsetof(struct _lowcore, kernel_asce));
- DEFINE(__LC_USER_ASCE, offsetof(struct _lowcore, user_asce));
- DEFINE(__LC_USER_EXEC_ASCE, offsetof(struct _lowcore, user_exec_asce));
DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock));
DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock));
DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags));
diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c
index 3d4a78fc1adc..1ca3d1d6a86c 100644
--- a/arch/s390/kernel/dis.c
+++ b/arch/s390/kernel/dis.c
@@ -30,9 +30,9 @@
#include <asm/atomic.h>
#include <asm/mathemu.h>
#include <asm/cpcmd.h>
-#include <asm/s390_ext.h>
#include <asm/lowcore.h>
#include <asm/debug.h>
+#include <asm/irq.h>
#ifndef CONFIG_64BIT
#define ONELONG "%08lx: "
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 1b67fc6ebdc2..0476174dfff5 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -212,6 +212,7 @@ __switch_to:
lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4
lm %r6,%r15,__SF_GPRS(%r15) # load gprs of next task
st %r3,__LC_CURRENT # store task struct of next
+ mvc __LC_CURRENT_PID(4,%r0),__TASK_pid(%r3) # store pid of next
st %r5,__LC_THREAD_INFO # store thread info of next
ahi %r5,STACK_SIZE # end of kernel stack of next
st %r5,__LC_KERNEL_STACK # store end of kernel stack
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 9fd864563499..d61967e2eab0 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -220,6 +220,7 @@ __switch_to:
lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4
lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task
stg %r3,__LC_CURRENT # store task struct of next
+ mvc __LC_CURRENT_PID+4(4,%r0),__TASK_pid(%r3) # store pid of next
stg %r5,__LC_THREAD_INFO # store thread info of next
aghi %r5,STACK_SIZE # end of kernel stack of next
stg %r5,__LC_KERNEL_STACK # store end of kernel stack
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
index ea5099c9709c..e3264f6a9720 100644
--- a/arch/s390/kernel/irq.c
+++ b/arch/s390/kernel/irq.c
@@ -1,19 +1,28 @@
/*
- * Copyright IBM Corp. 2004,2010
- * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
- * Thomas Spatzier (tspat@de.ibm.com)
+ * Copyright IBM Corp. 2004,2011
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>,
+ * Holger Smolinski <Holger.Smolinski@de.ibm.com>,
+ * Thomas Spatzier <tspat@de.ibm.com>,
*
* This file contains interrupt related functions.
*/
-#include <linux/module.h>
-#include <linux/kernel.h>
#include <linux/kernel_stat.h>
#include <linux/interrupt.h>
#include <linux/seq_file.h>
-#include <linux/cpu.h>
#include <linux/proc_fs.h>
#include <linux/profile.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ftrace.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/cpu.h>
+#include <asm/irq_regs.h>
+#include <asm/cputime.h>
+#include <asm/lowcore.h>
+#include <asm/irq.h>
+#include "entry.h"
struct irq_class {
char *name;
@@ -32,6 +41,7 @@ static const struct irq_class intrclass_names[] = {
{.name = "VRT", .desc = "[EXT] Virtio" },
{.name = "SCP", .desc = "[EXT] Service Call" },
{.name = "IUC", .desc = "[EXT] IUCV" },
+ {.name = "CPM", .desc = "[EXT] CPU Measurement" },
{.name = "QAI", .desc = "[I/O] QDIO Adapter Interrupt" },
{.name = "QDI", .desc = "[I/O] QDIO Interrupt" },
{.name = "DAS", .desc = "[I/O] DASD" },
@@ -81,8 +91,7 @@ int show_interrupts(struct seq_file *p, void *v)
* For compatibilty only. S/390 specific setup of interrupts et al. is done
* much later in init_channel_subsystem().
*/
-void __init
-init_IRQ(void)
+void __init init_IRQ(void)
{
/* nothing... */
}
@@ -133,3 +142,116 @@ void init_irq_proc(void)
create_prof_cpu_mask(root_irq_dir);
}
#endif
+
+/*
+ * ext_int_hash[index] is the start of the list for all external interrupts
+ * that hash to this index. With the current set of external interrupts
+ * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console, 0x4000
+ * iucv and 0x2603 pfault) this is always the first element.
+ */
+
+struct ext_int_info {
+ struct ext_int_info *next;
+ ext_int_handler_t handler;
+ u16 code;
+};
+
+static struct ext_int_info *ext_int_hash[256];
+
+static inline int ext_hash(u16 code)
+{
+ return (code + (code >> 9)) & 0xff;
+}
+
+int register_external_interrupt(u16 code, ext_int_handler_t handler)
+{
+ struct ext_int_info *p;
+ int index;
+
+ p = kmalloc(sizeof(*p), GFP_ATOMIC);
+ if (!p)
+ return -ENOMEM;
+ p->code = code;
+ p->handler = handler;
+ index = ext_hash(code);
+ p->next = ext_int_hash[index];
+ ext_int_hash[index] = p;
+ return 0;
+}
+EXPORT_SYMBOL(register_external_interrupt);
+
+int unregister_external_interrupt(u16 code, ext_int_handler_t handler)
+{
+ struct ext_int_info *p, *q;
+ int index;
+
+ index = ext_hash(code);
+ q = NULL;
+ p = ext_int_hash[index];
+ while (p) {
+ if (p->code == code && p->handler == handler)
+ break;
+ q = p;
+ p = p->next;
+ }
+ if (!p)
+ return -ENOENT;
+ if (q)
+ q->next = p->next;
+ else
+ ext_int_hash[index] = p->next;
+ kfree(p);
+ return 0;
+}
+EXPORT_SYMBOL(unregister_external_interrupt);
+
+void __irq_entry do_extint(struct pt_regs *regs, unsigned int ext_int_code,
+ unsigned int param32, unsigned long param64)
+{
+ struct pt_regs *old_regs;
+ unsigned short code;
+ struct ext_int_info *p;
+ int index;
+
+ code = (unsigned short) ext_int_code;
+ old_regs = set_irq_regs(regs);
+ s390_idle_check(regs, S390_lowcore.int_clock,
+ S390_lowcore.async_enter_timer);
+ irq_enter();
+ if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
+ /* Serve timer interrupts first. */
+ clock_comparator_work();
+ kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
+ if (code != 0x1004)
+ __get_cpu_var(s390_idle).nohz_delay = 1;
+ index = ext_hash(code);
+ for (p = ext_int_hash[index]; p; p = p->next) {
+ if (likely(p->code == code))
+ p->handler(ext_int_code, param32, param64);
+ }
+ irq_exit();
+ set_irq_regs(old_regs);
+}
+
+static DEFINE_SPINLOCK(sc_irq_lock);
+static int sc_irq_refcount;
+
+void service_subclass_irq_register(void)
+{
+ spin_lock(&sc_irq_lock);
+ if (!sc_irq_refcount)
+ ctl_set_bit(0, 9);
+ sc_irq_refcount++;
+ spin_unlock(&sc_irq_lock);
+}
+EXPORT_SYMBOL(service_subclass_irq_register);
+
+void service_subclass_irq_unregister(void)
+{
+ spin_lock(&sc_irq_lock);
+ sc_irq_refcount--;
+ if (!sc_irq_refcount)
+ ctl_clear_bit(0, 9);
+ spin_unlock(&sc_irq_lock);
+}
+EXPORT_SYMBOL(service_subclass_irq_unregister);
diff --git a/arch/s390/kernel/jump_label.c b/arch/s390/kernel/jump_label.c
new file mode 100644
index 000000000000..44cc06bedf77
--- /dev/null
+++ b/arch/s390/kernel/jump_label.c
@@ -0,0 +1,59 @@
+/*
+ * Jump label s390 support
+ *
+ * Copyright IBM Corp. 2011
+ * Author(s): Jan Glauber <jang@linux.vnet.ibm.com>
+ */
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/stop_machine.h>
+#include <linux/jump_label.h>
+#include <asm/ipl.h>
+
+#ifdef HAVE_JUMP_LABEL
+
+struct insn {
+ u16 opcode;
+ s32 offset;
+} __packed;
+
+struct insn_args {
+ unsigned long *target;
+ struct insn *insn;
+ ssize_t size;
+};
+
+static int __arch_jump_label_transform(void *data)
+{
+ struct insn_args *args = data;
+ int rc;
+
+ rc = probe_kernel_write(args->target, args->insn, args->size);
+ WARN_ON_ONCE(rc < 0);
+ return 0;
+}
+
+void arch_jump_label_transform(struct jump_entry *entry,
+ enum jump_label_type type)
+{
+ struct insn_args args;
+ struct insn insn;
+
+ if (type == JUMP_LABEL_ENABLE) {
+ /* brcl 15,offset */
+ insn.opcode = 0xc0f4;
+ insn.offset = (entry->target - entry->code) >> 1;
+ } else {
+ /* brcl 0,0 */
+ insn.opcode = 0xc004;
+ insn.offset = 0;
+ }
+
+ args.target = (void *) entry->code;
+ args.insn = &insn;
+ args.size = JUMP_LABEL_NOP_SIZE;
+
+ stop_machine(__arch_jump_label_transform, &args, NULL);
+}
+
+#endif
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index a895e69379f7..541a7509faeb 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -9,41 +9,26 @@
#include <linux/compiler.h>
#include <linux/cpu.h>
-#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
-#include <linux/fs.h>
#include <linux/smp.h>
-#include <linux/stddef.h>
#include <linux/slab.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/vmalloc.h>
-#include <linux/user.h>
#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/notifier.h>
#include <linux/tick.h>
-#include <linux/elfcore.h>
-#include <linux/kernel_stat.h>
#include <linux/personality.h>
#include <linux/syscalls.h>
#include <linux/compat.h>
#include <linux/kprobes.h>
#include <linux/random.h>
-#include <asm/compat.h>
-#include <asm/uaccess.h>
-#include <asm/pgtable.h>
+#include <linux/module.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/irq.h>
#include <asm/timer.h>
#include <asm/nmi.h>
+#include <asm/compat.h>
#include <asm/smp.h>
#include "entry.h"
diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c
deleted file mode 100644
index 185029919c4d..000000000000
--- a/arch/s390/kernel/s390_ext.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright IBM Corp. 1999,2010
- * Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com>,
- * Martin Schwidefsky <schwidefsky@de.ibm.com>,
- */
-
-#include <linux/kernel_stat.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/ftrace.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <asm/s390_ext.h>
-#include <asm/irq_regs.h>
-#include <asm/cputime.h>
-#include <asm/lowcore.h>
-#include <asm/irq.h>
-#include "entry.h"
-
-struct ext_int_info {
- struct ext_int_info *next;
- ext_int_handler_t handler;
- __u16 code;
-};
-
-/*
- * ext_int_hash[index] is the start of the list for all external interrupts
- * that hash to this index. With the current set of external interrupts
- * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console, 0x4000
- * iucv and 0x2603 pfault) this is always the first element.
- */
-static struct ext_int_info *ext_int_hash[256];
-
-static inline int ext_hash(__u16 code)
-{
- return (code + (code >> 9)) & 0xff;
-}
-
-int register_external_interrupt(__u16 code, ext_int_handler_t handler)
-{
- struct ext_int_info *p;
- int index;
-
- p = kmalloc(sizeof(*p), GFP_ATOMIC);
- if (!p)
- return -ENOMEM;
- p->code = code;
- p->handler = handler;
- index = ext_hash(code);
- p->next = ext_int_hash[index];
- ext_int_hash[index] = p;
- return 0;
-}
-EXPORT_SYMBOL(register_external_interrupt);
-
-int unregister_external_interrupt(__u16 code, ext_int_handler_t handler)
-{
- struct ext_int_info *p, *q;
- int index;
-
- index = ext_hash(code);
- q = NULL;
- p = ext_int_hash[index];
- while (p) {
- if (p->code == code && p->handler == handler)
- break;
- q = p;
- p = p->next;
- }
- if (!p)
- return -ENOENT;
- if (q)
- q->next = p->next;
- else
- ext_int_hash[index] = p->next;
- kfree(p);
- return 0;
-}
-EXPORT_SYMBOL(unregister_external_interrupt);
-
-void __irq_entry do_extint(struct pt_regs *regs, unsigned int ext_int_code,
- unsigned int param32, unsigned long param64)
-{
- struct pt_regs *old_regs;
- unsigned short code;
- struct ext_int_info *p;
- int index;
-
- code = (unsigned short) ext_int_code;
- old_regs = set_irq_regs(regs);
- s390_idle_check(regs, S390_lowcore.int_clock,
- S390_lowcore.async_enter_timer);
- irq_enter();
- if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
- /* Serve timer interrupts first. */
- clock_comparator_work();
- kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
- if (code != 0x1004)
- __get_cpu_var(s390_idle).nohz_delay = 1;
- index = ext_hash(code);
- for (p = ext_int_hash[index]; p; p = p->next) {
- if (likely(p->code == code))
- p->handler(ext_int_code, param32, param64);
- }
- irq_exit();
- set_irq_regs(old_regs);
-}
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index f5434d1ecb31..0c35dee10b00 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -305,8 +305,7 @@ static int set_amode_and_uaccess(unsigned long user_amode,
*/
static int __init early_parse_switch_amode(char *p)
{
- if (user_mode != SECONDARY_SPACE_MODE)
- user_mode = PRIMARY_SPACE_MODE;
+ user_mode = PRIMARY_SPACE_MODE;
return 0;
}
early_param("switch_amode", early_parse_switch_amode);
@@ -315,10 +314,6 @@ static int __init early_parse_user_mode(char *p)
{
if (p && strcmp(p, "primary") == 0)
user_mode = PRIMARY_SPACE_MODE;
-#ifdef CONFIG_S390_EXEC_PROTECT
- else if (p && strcmp(p, "secondary") == 0)
- user_mode = SECONDARY_SPACE_MODE;
-#endif
else if (!p || strcmp(p, "home") == 0)
user_mode = HOME_SPACE_MODE;
else
@@ -327,31 +322,9 @@ static int __init early_parse_user_mode(char *p)
}
early_param("user_mode", early_parse_user_mode);
-#ifdef CONFIG_S390_EXEC_PROTECT
-/*
- * Enable execute protection?
- */
-static int __init early_parse_noexec(char *p)
-{
- if (!strncmp(p, "off", 3))
- return 0;
- user_mode = SECONDARY_SPACE_MODE;
- return 0;
-}
-early_param("noexec", early_parse_noexec);
-#endif /* CONFIG_S390_EXEC_PROTECT */
-
static void setup_addressing_mode(void)
{
- if (user_mode == SECONDARY_SPACE_MODE) {
- if (set_amode_and_uaccess(PSW_ASC_SECONDARY,
- PSW32_ASC_SECONDARY))
- pr_info("Execute protection active, "
- "mvcos available\n");
- else
- pr_info("Execute protection active, "
- "mvcos not available\n");
- } else if (user_mode == PRIMARY_SPACE_MODE) {
+ if (user_mode == PRIMARY_SPACE_MODE) {
if (set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY))
pr_info("Address spaces switched, "
"mvcos available\n");
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 63a97db83f96..52420d2785b3 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -44,7 +44,6 @@
#include <asm/sigp.h>
#include <asm/pgalloc.h>
#include <asm/irq.h>
-#include <asm/s390_ext.h>
#include <asm/cpcmd.h>
#include <asm/tlbflush.h>
#include <asm/timer.h>
@@ -165,12 +164,12 @@ static void do_ext_call_interrupt(unsigned int ext_int_code,
kstat_cpu(smp_processor_id()).irqs[EXTINT_IPI]++;
/*
* handle bit signal external calls
- *
- * For the ec_schedule signal we have to do nothing. All the work
- * is done automatically when we return from the interrupt.
*/
bits = xchg(&S390_lowcore.ext_call_fast, 0);
+ if (test_bit(ec_schedule, &bits))
+ scheduler_ipi();
+
if (test_bit(ec_call_function, &bits))
generic_smp_call_function_interrupt();
@@ -335,7 +334,7 @@ static int smp_rescan_cpus_sigp(cpumask_t avail)
smp_cpu_polarization[logical_cpu] = POLARIZATION_UNKNWN;
if (!cpu_stopped(logical_cpu))
continue;
- cpu_set(logical_cpu, cpu_present_map);
+ set_cpu_present(logical_cpu, true);
smp_cpu_state[logical_cpu] = CPU_STATE_CONFIGURED;
logical_cpu = cpumask_next(logical_cpu, &avail);
if (logical_cpu >= nr_cpu_ids)
@@ -367,7 +366,7 @@ static int smp_rescan_cpus_sclp(cpumask_t avail)
continue;
__cpu_logical_map[logical_cpu] = cpu_id;
smp_cpu_polarization[logical_cpu] = POLARIZATION_UNKNWN;
- cpu_set(logical_cpu, cpu_present_map);
+ set_cpu_present(logical_cpu, true);
if (cpu >= info->configured)
smp_cpu_state[logical_cpu] = CPU_STATE_STANDBY;
else
@@ -385,7 +384,7 @@ static int __smp_rescan_cpus(void)
{
cpumask_t avail;
- cpus_xor(avail, cpu_possible_map, cpu_present_map);
+ cpumask_xor(&avail, cpu_possible_mask, cpu_present_mask);
if (smp_use_sigp_detection)
return smp_rescan_cpus_sigp(avail);
else
@@ -467,7 +466,7 @@ int __cpuinit start_secondary(void *cpuvoid)
notify_cpu_starting(smp_processor_id());
/* Mark this cpu as online */
ipi_call_lock();
- cpu_set(smp_processor_id(), cpu_online_map);
+ set_cpu_online(smp_processor_id(), true);
ipi_call_unlock();
/* Switch on interrupts */
local_irq_enable();
@@ -644,7 +643,7 @@ int __cpu_disable(void)
struct ec_creg_mask_parms cr_parms;
int cpu = smp_processor_id();
- cpu_clear(cpu, cpu_online_map);
+ set_cpu_online(cpu, false);
/* Disable pfault pseudo page faults on this cpu. */
pfault_fini();
@@ -654,8 +653,8 @@ int __cpu_disable(void)
/* disable all external interrupts */
cr_parms.orvals[0] = 0;
- cr_parms.andvals[0] = ~(1 << 15 | 1 << 14 | 1 << 13 | 1 << 12 |
- 1 << 11 | 1 << 10 | 1 << 6 | 1 << 4);
+ cr_parms.andvals[0] = ~(1 << 15 | 1 << 14 | 1 << 13 | 1 << 11 |
+ 1 << 10 | 1 << 9 | 1 << 6 | 1 << 4);
/* disable all I/O interrupts */
cr_parms.orvals[6] = 0;
cr_parms.andvals[6] = ~(1 << 31 | 1 << 30 | 1 << 29 | 1 << 28 |
@@ -681,7 +680,7 @@ void __cpu_die(unsigned int cpu)
atomic_dec(&init_mm.context.attach_count);
}
-void cpu_die(void)
+void __noreturn cpu_die(void)
{
idle_task_exit();
while (sigp(smp_processor_id(), sigp_stop) == sigp_busy)
@@ -738,8 +737,8 @@ void __init smp_prepare_boot_cpu(void)
BUG_ON(smp_processor_id() != 0);
current_thread_info()->cpu = 0;
- cpu_set(0, cpu_present_map);
- cpu_set(0, cpu_online_map);
+ set_cpu_present(0, true);
+ set_cpu_online(0, true);
S390_lowcore.percpu_offset = __per_cpu_offset[0];
current_set[0] = current;
smp_cpu_state[0] = CPU_STATE_CONFIGURED;
@@ -1016,21 +1015,21 @@ int __ref smp_rescan_cpus(void)
get_online_cpus();
mutex_lock(&smp_cpu_state_mutex);
- newcpus = cpu_present_map;
+ cpumask_copy(&newcpus, cpu_present_mask);
rc = __smp_rescan_cpus();
if (rc)
goto out;
- cpus_andnot(newcpus, cpu_present_map, newcpus);
- for_each_cpu_mask(cpu, newcpus) {
+ cpumask_andnot(&newcpus, cpu_present_mask, &newcpus);
+ for_each_cpu(cpu, &newcpus) {
rc = smp_add_present_cpu(cpu);
if (rc)
- cpu_clear(cpu, cpu_present_map);
+ set_cpu_present(cpu, false);
}
rc = 0;
out:
mutex_unlock(&smp_cpu_state_mutex);
put_online_cpus();
- if (!cpus_empty(newcpus))
+ if (!cpumask_empty(&newcpus))
topology_schedule_update();
return rc;
}
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index 87be655557aa..dff933065ab6 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -41,7 +41,6 @@
#include <linux/kprobes.h>
#include <asm/uaccess.h>
#include <asm/delay.h>
-#include <asm/s390_ext.h>
#include <asm/div64.h>
#include <asm/vdso.h>
#include <asm/irq.h>
@@ -810,7 +809,7 @@ static int etr_sync_clock_stop(struct etr_aib *aib, int port)
etr_sync.etr_port = port;
get_online_cpus();
atomic_set(&etr_sync.cpus, num_online_cpus() - 1);
- rc = stop_machine(etr_sync_clock, &etr_sync, &cpu_online_map);
+ rc = stop_machine(etr_sync_clock, &etr_sync, cpu_online_mask);
put_online_cpus();
return rc;
}
@@ -1579,7 +1578,7 @@ static void stp_work_fn(struct work_struct *work)
memset(&stp_sync, 0, sizeof(stp_sync));
get_online_cpus();
atomic_set(&stp_sync.cpus, num_online_cpus() - 1);
- stop_machine(stp_sync_clock, &stp_sync, &cpu_online_map);
+ stop_machine(stp_sync_clock, &stp_sync, cpu_online_mask);
put_online_cpus();
if (!check_sync_clock())
diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c
index 94b06c31fc8a..0cd340b72632 100644
--- a/arch/s390/kernel/topology.c
+++ b/arch/s390/kernel/topology.c
@@ -17,7 +17,6 @@
#include <linux/smp.h>
#include <linux/cpuset.h>
#include <asm/delay.h>
-#include <asm/s390_ext.h>
#define PTF_HORIZONTAL (0UL)
#define PTF_VERTICAL (1UL)
@@ -52,20 +51,20 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu)
{
cpumask_t mask;
- cpus_clear(mask);
+ cpumask_clear(&mask);
if (!topology_enabled || !MACHINE_HAS_TOPOLOGY) {
cpumask_copy(&mask, cpumask_of(cpu));
return mask;
}
while (info) {
- if (cpu_isset(cpu, info->mask)) {
+ if (cpumask_test_cpu(cpu, &info->mask)) {
mask = info->mask;
break;
}
info = info->next;
}
- if (cpus_empty(mask))
- mask = cpumask_of_cpu(cpu);
+ if (cpumask_empty(&mask))
+ cpumask_copy(&mask, cpumask_of(cpu));
return mask;
}
@@ -85,10 +84,10 @@ static void add_cpus_to_mask(struct topology_cpu *tl_cpu,
if (cpu_logical_map(lcpu) != rcpu)
continue;
#ifdef CONFIG_SCHED_BOOK
- cpu_set(lcpu, book->mask);
+ cpumask_set_cpu(lcpu, &book->mask);
cpu_book_id[lcpu] = book->id;
#endif
- cpu_set(lcpu, core->mask);
+ cpumask_set_cpu(lcpu, &core->mask);
cpu_core_id[lcpu] = core->id;
smp_cpu_polarization[lcpu] = tl_cpu->pp;
}
@@ -101,13 +100,13 @@ static void clear_masks(void)
info = &core_info;
while (info) {
- cpus_clear(info->mask);
+ cpumask_clear(&info->mask);
info = info->next;
}
#ifdef CONFIG_SCHED_BOOK
info = &book_info;
while (info) {
- cpus_clear(info->mask);
+ cpumask_clear(&info->mask);
info = info->next;
}
#endif
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index b5a4a739b477..a65d2e82f61d 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -39,7 +39,6 @@
#include <asm/atomic.h>
#include <asm/mathemu.h>
#include <asm/cpcmd.h>
-#include <asm/s390_ext.h>
#include <asm/lowcore.h>
#include <asm/debug.h>
#include "entry.h"
diff --git a/arch/s390/kernel/vdso32/Makefile b/arch/s390/kernel/vdso32/Makefile
index d13e8755a8cc..8ad2b34ad151 100644
--- a/arch/s390/kernel/vdso32/Makefile
+++ b/arch/s390/kernel/vdso32/Makefile
@@ -22,6 +22,9 @@ obj-y += vdso32_wrapper.o
extra-y += vdso32.lds
CPPFLAGS_vdso32.lds += -P -C -U$(ARCH)
+# Disable gcov profiling for VDSO code
+GCOV_PROFILE := n
+
# Force dependency (incbin is bad)
$(obj)/vdso32_wrapper.o : $(obj)/vdso32.so
diff --git a/arch/s390/kernel/vdso64/Makefile b/arch/s390/kernel/vdso64/Makefile
index 449352dda9cd..2a8ddfd12a5b 100644
--- a/arch/s390/kernel/vdso64/Makefile
+++ b/arch/s390/kernel/vdso64/Makefile
@@ -22,6 +22,9 @@ obj-y += vdso64_wrapper.o
extra-y += vdso64.lds
CPPFLAGS_vdso64.lds += -P -C -U$(ARCH)
+# Disable gcov profiling for VDSO code
+GCOV_PROFILE := n
+
# Force dependency (incbin is bad)
$(obj)/vdso64_wrapper.o : $(obj)/vdso64.so
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
index 1bc18cdb525b..56fe6bc81fee 100644
--- a/arch/s390/kernel/vmlinux.lds.S
+++ b/arch/s390/kernel/vmlinux.lds.S
@@ -77,7 +77,7 @@ SECTIONS
. = ALIGN(PAGE_SIZE);
INIT_DATA_SECTION(0x100)
- PERCPU(0x100, PAGE_SIZE)
+ PERCPU_SECTION(0x100)
. = ALIGN(PAGE_SIZE);
__init_end = .; /* freed after init ends here */
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c
index 5e8ead4b4aba..2d6228f60cd6 100644
--- a/arch/s390/kernel/vtime.c
+++ b/arch/s390/kernel/vtime.c
@@ -22,10 +22,10 @@
#include <linux/cpu.h>
#include <linux/kprobes.h>
-#include <asm/s390_ext.h>
#include <asm/timer.h>
#include <asm/irq_regs.h>
#include <asm/cputime.h>
+#include <asm/irq.h>
static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c
index 0f53110e1d09..a65229d91c92 100644
--- a/arch/s390/lib/delay.c
+++ b/arch/s390/lib/delay.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/irqflags.h>
#include <linux/interrupt.h>
+#include <asm/div64.h>
void __delay(unsigned long loops)
{
@@ -116,3 +117,17 @@ void udelay_simple(unsigned long long usecs)
while (get_clock() < end)
cpu_relax();
}
+
+void __ndelay(unsigned long long nsecs)
+{
+ u64 end;
+
+ nsecs <<= 9;
+ do_div(nsecs, 125);
+ end = get_clock() + nsecs;
+ if (nsecs & ~0xfffUL)
+ __udelay(nsecs >> 12);
+ while (get_clock() < end)
+ barrier();
+}
+EXPORT_SYMBOL(__ndelay);
diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c
index 3cc95dd0a3a6..075ddada4911 100644
--- a/arch/s390/mm/extmem.c
+++ b/arch/s390/mm/extmem.c
@@ -412,6 +412,7 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
struct dcss_segment *seg;
int rc, diag_cc;
+ start_addr = end_addr = 0;
seg = kmalloc(sizeof(*seg), GFP_KERNEL | GFP_DMA);
if (seg == NULL) {
rc = -ENOMEM;
@@ -573,6 +574,7 @@ segment_modify_shared (char *name, int do_nonshared)
unsigned long start_addr, end_addr, dummy;
int rc, diag_cc;
+ start_addr = end_addr = 0;
mutex_lock(&dcss_lock);
seg = segment_by_name (name);
if (seg == NULL) {
@@ -681,8 +683,6 @@ void
segment_save(char *name)
{
struct dcss_segment *seg;
- int startpfn = 0;
- int endpfn = 0;
char cmd1[160];
char cmd2[80];
int i, response;
@@ -698,8 +698,6 @@ segment_save(char *name)
goto out;
}
- startpfn = seg->start_addr >> PAGE_SHIFT;
- endpfn = (seg->end) >> PAGE_SHIFT;
sprintf(cmd1, "DEFSEG %s", name);
for (i=0; i<seg->segcnt; i++) {
sprintf(cmd1+strlen(cmd1), " %lX-%lX %s",
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index ab988135e5c6..fe103e891e7a 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -34,7 +34,7 @@
#include <asm/asm-offsets.h>
#include <asm/system.h>
#include <asm/pgtable.h>
-#include <asm/s390_ext.h>
+#include <asm/irq.h>
#include <asm/mmu_context.h>
#include <asm/compat.h>
#include "../kernel/entry.h"
@@ -225,33 +225,6 @@ static noinline void do_sigbus(struct pt_regs *regs, long int_code,
force_sig_info(SIGBUS, &si, tsk);
}
-#ifdef CONFIG_S390_EXEC_PROTECT
-static noinline int signal_return(struct pt_regs *regs, long int_code,
- unsigned long trans_exc_code)
-{
- u16 instruction;
- int rc;
-
- rc = __get_user(instruction, (u16 __user *) regs->psw.addr);
-
- if (!rc && instruction == 0x0a77) {
- clear_tsk_thread_flag(current, TIF_PER_TRAP);
- if (is_compat_task())
- sys32_sigreturn();
- else
- sys_sigreturn();
- } else if (!rc && instruction == 0x0aad) {
- clear_tsk_thread_flag(current, TIF_PER_TRAP);
- if (is_compat_task())
- sys32_rt_sigreturn();
- else
- sys_rt_sigreturn();
- } else
- do_sigsegv(regs, int_code, SEGV_MAPERR, trans_exc_code);
- return 0;
-}
-#endif /* CONFIG_S390_EXEC_PROTECT */
-
static noinline void do_fault_error(struct pt_regs *regs, long int_code,
unsigned long trans_exc_code, int fault)
{
@@ -259,13 +232,6 @@ static noinline void do_fault_error(struct pt_regs *regs, long int_code,
switch (fault) {
case VM_FAULT_BADACCESS:
-#ifdef CONFIG_S390_EXEC_PROTECT
- if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_SECONDARY &&
- (trans_exc_code & 3) == 0) {
- signal_return(regs, int_code, trans_exc_code);
- break;
- }
-#endif /* CONFIG_S390_EXEC_PROTECT */
case VM_FAULT_BADMAP:
/* Bad memory access. Check if it is kernel or user space. */
if (regs->psw.mask & PSW_MASK_PSTATE) {
@@ -279,9 +245,12 @@ static noinline void do_fault_error(struct pt_regs *regs, long int_code,
do_no_context(regs, int_code, trans_exc_code);
break;
default: /* fault & VM_FAULT_ERROR */
- if (fault & VM_FAULT_OOM)
- pagefault_out_of_memory();
- else if (fault & VM_FAULT_SIGBUS) {
+ if (fault & VM_FAULT_OOM) {
+ if (!(regs->psw.mask & PSW_MASK_PSTATE))
+ do_no_context(regs, int_code, trans_exc_code);
+ else
+ pagefault_out_of_memory();
+ } else if (fault & VM_FAULT_SIGBUS) {
/* Kernel mode? Handle exceptions or die */
if (!(regs->psw.mask & PSW_MASK_PSTATE))
do_no_context(regs, int_code, trans_exc_code);
@@ -311,7 +280,8 @@ static inline int do_exception(struct pt_regs *regs, int access,
struct mm_struct *mm;
struct vm_area_struct *vma;
unsigned long address;
- int fault, write;
+ unsigned int flags;
+ int fault;
if (notify_page_fault(regs))
return 0;
@@ -330,6 +300,10 @@ static inline int do_exception(struct pt_regs *regs, int access,
address = trans_exc_code & __FAIL_ADDR_MASK;
perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, 0, regs, address);
+ flags = FAULT_FLAG_ALLOW_RETRY;
+ if (access == VM_WRITE || (trans_exc_code & store_indication) == 0x400)
+ flags |= FAULT_FLAG_WRITE;
+retry:
down_read(&mm->mmap_sem);
fault = VM_FAULT_BADMAP;
@@ -359,21 +333,31 @@ static inline int do_exception(struct pt_regs *regs, int access,
* make sure we exit gracefully rather than endlessly redo
* the fault.
*/
- write = (access == VM_WRITE ||
- (trans_exc_code & store_indication) == 0x400) ?
- FAULT_FLAG_WRITE : 0;
- fault = handle_mm_fault(mm, vma, address, write);
+ fault = handle_mm_fault(mm, vma, address, flags);
if (unlikely(fault & VM_FAULT_ERROR))
goto out_up;
- if (fault & VM_FAULT_MAJOR) {
- tsk->maj_flt++;
- perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0,
- regs, address);
- } else {
- tsk->min_flt++;
- perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0,
- regs, address);
+ /*
+ * Major/minor page fault accounting is only done on the
+ * initial attempt. If we go through a retry, it is extremely
+ * likely that the page will be found in page cache at that point.
+ */
+ if (flags & FAULT_FLAG_ALLOW_RETRY) {
+ if (fault & VM_FAULT_MAJOR) {
+ tsk->maj_flt++;
+ perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, 0,
+ regs, address);
+ } else {
+ tsk->min_flt++;
+ perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, 0,
+ regs, address);
+ }
+ if (fault & VM_FAULT_RETRY) {
+ /* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk
+ * of starvation. */
+ flags &= ~FAULT_FLAG_ALLOW_RETRY;
+ goto retry;
+ }
}
/*
* The instruction that caused the program check will
@@ -414,11 +398,6 @@ void __kprobes do_dat_exception(struct pt_regs *regs, long pgm_int_code,
int access, fault;
access = VM_READ | VM_EXEC | VM_WRITE;
-#ifdef CONFIG_S390_EXEC_PROTECT
- if ((regs->psw.mask & PSW_MASK_ASC) == PSW_ASC_SECONDARY &&
- (trans_exc_code & 3) == 0)
- access = VM_EXEC;
-#endif
fault = do_exception(regs, access, trans_exc_code);
if (unlikely(fault))
do_fault_error(regs, pgm_int_code & 255, trans_exc_code, fault);
@@ -468,10 +447,9 @@ int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write)
access = write ? VM_WRITE : VM_READ;
fault = do_exception(&regs, access, uaddr | 2);
if (unlikely(fault)) {
- if (fault & VM_FAULT_OOM) {
- pagefault_out_of_memory();
- fault = 0;
- } else if (fault & VM_FAULT_SIGBUS)
+ if (fault & VM_FAULT_OOM)
+ return -EFAULT;
+ else if (fault & VM_FAULT_SIGBUS)
do_sigbus(&regs, pgm_int_code, uaddr);
}
return fault ? -EFAULT : 0;
@@ -491,22 +469,28 @@ static int __init nopfault(char *str)
__setup("nopfault", nopfault);
-typedef struct {
- __u16 refdiagc;
- __u16 reffcode;
- __u16 refdwlen;
- __u16 refversn;
- __u64 refgaddr;
- __u64 refselmk;
- __u64 refcmpmk;
- __u64 reserved;
-} __attribute__ ((packed, aligned(8))) pfault_refbk_t;
+struct pfault_refbk {
+ u16 refdiagc;
+ u16 reffcode;
+ u16 refdwlen;
+ u16 refversn;
+ u64 refgaddr;
+ u64 refselmk;
+ u64 refcmpmk;
+ u64 reserved;
+} __attribute__ ((packed, aligned(8)));
int pfault_init(void)
{
- pfault_refbk_t refbk =
- { 0x258, 0, 5, 2, __LC_CURRENT, 1ULL << 48, 1ULL << 48,
- __PF_RES_FIELD };
+ struct pfault_refbk refbk = {
+ .refdiagc = 0x258,
+ .reffcode = 0,
+ .refdwlen = 5,
+ .refversn = 2,
+ .refgaddr = __LC_CURRENT_PID,
+ .refselmk = 1ULL << 48,
+ .refcmpmk = 1ULL << 48,
+ .reserved = __PF_RES_FIELD };
int rc;
if (!MACHINE_IS_VM || pfault_disable)
@@ -518,18 +502,20 @@ int pfault_init(void)
"2:\n"
EX_TABLE(0b,1b)
: "=d" (rc) : "a" (&refbk), "m" (refbk) : "cc");
- __ctl_set_bit(0, 9);
return rc;
}
void pfault_fini(void)
{
- pfault_refbk_t refbk =
- { 0x258, 1, 5, 2, 0ULL, 0ULL, 0ULL, 0ULL };
+ struct pfault_refbk refbk = {
+ .refdiagc = 0x258,
+ .reffcode = 1,
+ .refdwlen = 5,
+ .refversn = 2,
+ };
if (!MACHINE_IS_VM || pfault_disable)
return;
- __ctl_clear_bit(0,9);
asm volatile(
" diag %0,0,0x258\n"
"0:\n"
@@ -537,11 +523,15 @@ void pfault_fini(void)
: : "a" (&refbk), "m" (refbk) : "cc");
}
+static DEFINE_SPINLOCK(pfault_lock);
+static LIST_HEAD(pfault_list);
+
static void pfault_interrupt(unsigned int ext_int_code,
unsigned int param32, unsigned long param64)
{
struct task_struct *tsk;
__u16 subcode;
+ pid_t pid;
/*
* Get the external interruption subcode & pfault
@@ -553,44 +543,79 @@ static void pfault_interrupt(unsigned int ext_int_code,
if ((subcode & 0xff00) != __SUBCODE_MASK)
return;
kstat_cpu(smp_processor_id()).irqs[EXTINT_PFL]++;
-
- /*
- * Get the token (= address of the task structure of the affected task).
- */
-#ifdef CONFIG_64BIT
- tsk = (struct task_struct *) param64;
-#else
- tsk = (struct task_struct *) param32;
-#endif
-
+ if (subcode & 0x0080) {
+ /* Get the token (= pid of the affected task). */
+ pid = sizeof(void *) == 4 ? param32 : param64;
+ rcu_read_lock();
+ tsk = find_task_by_pid_ns(pid, &init_pid_ns);
+ if (tsk)
+ get_task_struct(tsk);
+ rcu_read_unlock();
+ if (!tsk)
+ return;
+ } else {
+ tsk = current;
+ }
+ spin_lock(&pfault_lock);
if (subcode & 0x0080) {
/* signal bit is set -> a page has been swapped in by VM */
- if (xchg(&tsk->thread.pfault_wait, -1) != 0) {
+ if (tsk->thread.pfault_wait == 1) {
/* Initial interrupt was faster than the completion
* interrupt. pfault_wait is valid. Set pfault_wait
* back to zero and wake up the process. This can
* safely be done because the task is still sleeping
* and can't produce new pfaults. */
tsk->thread.pfault_wait = 0;
+ list_del(&tsk->thread.list);
wake_up_process(tsk);
- put_task_struct(tsk);
+ } else {
+ /* Completion interrupt was faster than initial
+ * interrupt. Set pfault_wait to -1 so the initial
+ * interrupt doesn't put the task to sleep. */
+ tsk->thread.pfault_wait = -1;
}
+ put_task_struct(tsk);
} else {
/* signal bit not set -> a real page is missing. */
- get_task_struct(tsk);
- set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (xchg(&tsk->thread.pfault_wait, 1) != 0) {
+ if (tsk->thread.pfault_wait == -1) {
/* Completion interrupt was faster than the initial
- * interrupt (swapped in a -1 for pfault_wait). Set
- * pfault_wait back to zero and exit. This can be
- * done safely because tsk is running in kernel
- * mode and can't produce new pfaults. */
+ * interrupt (pfault_wait == -1). Set pfault_wait
+ * back to zero and exit. */
tsk->thread.pfault_wait = 0;
- set_task_state(tsk, TASK_RUNNING);
- put_task_struct(tsk);
- } else
+ } else {
+ /* Initial interrupt arrived before completion
+ * interrupt. Let the task sleep. */
+ tsk->thread.pfault_wait = 1;
+ list_add(&tsk->thread.list, &pfault_list);
+ set_task_state(tsk, TASK_UNINTERRUPTIBLE);
set_tsk_need_resched(tsk);
+ }
+ }
+ spin_unlock(&pfault_lock);
+}
+
+static int __cpuinit pfault_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu)
+{
+ struct thread_struct *thread, *next;
+ struct task_struct *tsk;
+
+ switch (action) {
+ case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
+ spin_lock_irq(&pfault_lock);
+ list_for_each_entry_safe(thread, next, &pfault_list, list) {
+ thread->pfault_wait = 0;
+ list_del(&thread->list);
+ tsk = container_of(thread, struct task_struct, thread);
+ wake_up_process(tsk);
+ }
+ spin_unlock_irq(&pfault_lock);
+ break;
+ default:
+ break;
}
+ return NOTIFY_OK;
}
static int __init pfault_irq_init(void)
@@ -599,22 +624,22 @@ static int __init pfault_irq_init(void)
if (!MACHINE_IS_VM)
return 0;
- /*
- * Try to get pfault pseudo page faults going.
- */
rc = register_external_interrupt(0x2603, pfault_interrupt);
- if (rc) {
- pfault_disable = 1;
- return rc;
- }
- if (pfault_init() == 0)
- return 0;
+ if (rc)
+ goto out_extint;
+ rc = pfault_init() == 0 ? 0 : -EOPNOTSUPP;
+ if (rc)
+ goto out_pfault;
+ service_subclass_irq_register();
+ hotcpu_notifier(pfault_cpu_notify, 0);
+ return 0;
- /* Tough luck, no pfault. */
- pfault_disable = 1;
+out_pfault:
unregister_external_interrupt(0x2603, pfault_interrupt);
- return 0;
+out_extint:
+ pfault_disable = 1;
+ return rc;
}
early_initcall(pfault_irq_init);
-#endif
+#endif /* CONFIG_PFAULT */
diff --git a/arch/s390/mm/hugetlbpage.c b/arch/s390/mm/hugetlbpage.c
index 639cd21f2218..a4d856db9154 100644
--- a/arch/s390/mm/hugetlbpage.c
+++ b/arch/s390/mm/hugetlbpage.c
@@ -13,7 +13,6 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *pteptr, pte_t pteval)
{
pmd_t *pmdp = (pmd_t *) pteptr;
- pte_t shadow_pteval = pteval;
unsigned long mask;
if (!MACHINE_HAS_HPAGE) {
@@ -21,18 +20,9 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
mask = pte_val(pteval) &
(_SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO);
pte_val(pteval) = (_SEGMENT_ENTRY + __pa(pteptr)) | mask;
- if (mm->context.noexec) {
- pteptr += PTRS_PER_PTE;
- pte_val(shadow_pteval) =
- (_SEGMENT_ENTRY + __pa(pteptr)) | mask;
- }
}
pmd_val(*pmdp) = pte_val(pteval);
- if (mm->context.noexec) {
- pmdp = get_shadow_table(pmdp);
- pmd_val(*pmdp) = pte_val(shadow_pteval);
- }
}
int arch_prepare_hugepage(struct page *page)
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index bb409332a484..59b663109d90 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -119,9 +119,7 @@ void __init paging_init(void)
sparse_memory_present_with_active_regions(MAX_NUMNODES);
sparse_init();
memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
-#ifdef CONFIG_ZONE_DMA
max_zone_pfns[ZONE_DMA] = PFN_DOWN(MAX_DMA_ADDRESS);
-#endif
max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
free_area_init_nodes(max_zone_pfns);
fault_init();
@@ -175,7 +173,8 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
pmd = pmd_offset(pud, address);
pte = pte_offset_kernel(pmd, address);
if (!enable) {
- ptep_invalidate(&init_mm, address, pte);
+ __ptep_ipte(address, pte);
+ pte_val(*pte) = _PAGE_TYPE_EMPTY;
continue;
}
*pte = mk_pte_phys(address, __pgprot(_PAGE_TYPE_RW));
diff --git a/arch/s390/mm/pageattr.c b/arch/s390/mm/pageattr.c
index 0607e4b14b27..d013ed39743b 100644
--- a/arch/s390/mm/pageattr.c
+++ b/arch/s390/mm/pageattr.c
@@ -28,7 +28,7 @@ static void change_page_attr(unsigned long addr, int numpages,
pte = *ptep;
pte = set(pte);
- ptep_invalidate(&init_mm, addr, ptep);
+ __ptep_ipte(addr, ptep);
*ptep = pte;
addr += PAGE_SIZE;
}
@@ -54,3 +54,8 @@ int set_memory_nx(unsigned long addr, int numpages)
return 0;
}
EXPORT_SYMBOL_GPL(set_memory_nx);
+
+int set_memory_x(unsigned long addr, int numpages)
+{
+ return 0;
+}
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index e1850c28cd68..14c6fae6fe6b 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -36,11 +36,9 @@ struct rcu_table_freelist {
((PAGE_SIZE - sizeof(struct rcu_table_freelist)) \
/ sizeof(unsigned long))
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
static DEFINE_PER_CPU(struct rcu_table_freelist *, rcu_table_freelist);
static void __page_table_free(struct mm_struct *mm, unsigned long *table);
-static void __crst_table_free(struct mm_struct *mm, unsigned long *table);
static struct rcu_table_freelist *rcu_table_freelist_get(struct mm_struct *mm)
{
@@ -67,7 +65,7 @@ static void rcu_table_freelist_callback(struct rcu_head *head)
while (batch->pgt_index > 0)
__page_table_free(batch->mm, batch->table[--batch->pgt_index]);
while (batch->crst_index < RCU_FREELIST_SIZE)
- __crst_table_free(batch->mm, batch->table[batch->crst_index++]);
+ crst_table_free(batch->mm, batch->table[batch->crst_index++]);
free_page((unsigned long) batch);
}
@@ -125,63 +123,33 @@ static int __init parse_vmalloc(char *arg)
}
early_param("vmalloc", parse_vmalloc);
-unsigned long *crst_table_alloc(struct mm_struct *mm, int noexec)
+unsigned long *crst_table_alloc(struct mm_struct *mm)
{
struct page *page = alloc_pages(GFP_KERNEL, ALLOC_ORDER);
if (!page)
return NULL;
- page->index = 0;
- if (noexec) {
- struct page *shadow = alloc_pages(GFP_KERNEL, ALLOC_ORDER);
- if (!shadow) {
- __free_pages(page, ALLOC_ORDER);
- return NULL;
- }
- page->index = page_to_phys(shadow);
- }
- spin_lock_bh(&mm->context.list_lock);
- list_add(&page->lru, &mm->context.crst_list);
- spin_unlock_bh(&mm->context.list_lock);
return (unsigned long *) page_to_phys(page);
}
-static void __crst_table_free(struct mm_struct *mm, unsigned long *table)
-{
- unsigned long *shadow = get_shadow_table(table);
-
- if (shadow)
- free_pages((unsigned long) shadow, ALLOC_ORDER);
- free_pages((unsigned long) table, ALLOC_ORDER);
-}
-
void crst_table_free(struct mm_struct *mm, unsigned long *table)
{
- struct page *page = virt_to_page(table);
-
- spin_lock_bh(&mm->context.list_lock);
- list_del(&page->lru);
- spin_unlock_bh(&mm->context.list_lock);
- __crst_table_free(mm, table);
+ free_pages((unsigned long) table, ALLOC_ORDER);
}
void crst_table_free_rcu(struct mm_struct *mm, unsigned long *table)
{
struct rcu_table_freelist *batch;
- struct page *page = virt_to_page(table);
- spin_lock_bh(&mm->context.list_lock);
- list_del(&page->lru);
- spin_unlock_bh(&mm->context.list_lock);
if (atomic_read(&mm->mm_users) < 2 &&
cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) {
- __crst_table_free(mm, table);
+ crst_table_free(mm, table);
return;
}
batch = rcu_table_freelist_get(mm);
if (!batch) {
smp_call_function(smp_sync, NULL, 1);
- __crst_table_free(mm, table);
+ crst_table_free(mm, table);
return;
}
batch->table[--batch->crst_index] = table;
@@ -197,7 +165,7 @@ int crst_table_upgrade(struct mm_struct *mm, unsigned long limit)
BUG_ON(limit > (1UL << 53));
repeat:
- table = crst_table_alloc(mm, mm->context.noexec);
+ table = crst_table_alloc(mm);
if (!table)
return -ENOMEM;
spin_lock_bh(&mm->page_table_lock);
@@ -273,7 +241,7 @@ unsigned long *page_table_alloc(struct mm_struct *mm)
unsigned long *table;
unsigned long bits;
- bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL;
+ bits = (mm->context.has_pgste) ? 3UL : 1UL;
spin_lock_bh(&mm->context.list_lock);
page = NULL;
if (!list_empty(&mm->context.pgtable_list)) {
@@ -329,7 +297,7 @@ void page_table_free(struct mm_struct *mm, unsigned long *table)
struct page *page;
unsigned long bits;
- bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL;
+ bits = (mm->context.has_pgste) ? 3UL : 1UL;
bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long);
page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
spin_lock_bh(&mm->context.list_lock);
@@ -366,7 +334,7 @@ void page_table_free_rcu(struct mm_struct *mm, unsigned long *table)
page_table_free(mm, table);
return;
}
- bits = (mm->context.noexec || mm->context.has_pgste) ? 3UL : 1UL;
+ bits = (mm->context.has_pgste) ? 3UL : 1UL;
bits <<= (__pa(table) & (PAGE_SIZE - 1)) / 256 / sizeof(unsigned long);
page = pfn_to_page(__pa(table) >> PAGE_SHIFT);
spin_lock_bh(&mm->context.list_lock);
@@ -379,25 +347,6 @@ void page_table_free_rcu(struct mm_struct *mm, unsigned long *table)
rcu_table_freelist_finish();
}
-void disable_noexec(struct mm_struct *mm, struct task_struct *tsk)
-{
- struct page *page;
-
- spin_lock_bh(&mm->context.list_lock);
- /* Free shadow region and segment tables. */
- list_for_each_entry(page, &mm->context.crst_list, lru)
- if (page->index) {
- free_pages((unsigned long) page->index, ALLOC_ORDER);
- page->index = 0;
- }
- /* "Free" second halves of page tables. */
- list_for_each_entry(page, &mm->context.pgtable_list, lru)
- page->flags &= ~SECOND_HALVES;
- spin_unlock_bh(&mm->context.list_lock);
- mm->context.noexec = 0;
- update_mm(mm, tsk);
-}
-
/*
* switch on pgstes for its userspace process (for kvm)
*/
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
index 34c43f23b28c..8c1970d1dd91 100644
--- a/arch/s390/mm/vmem.c
+++ b/arch/s390/mm/vmem.c
@@ -95,7 +95,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
pu_dir = vmem_pud_alloc();
if (!pu_dir)
goto out;
- pgd_populate_kernel(&init_mm, pg_dir, pu_dir);
+ pgd_populate(&init_mm, pg_dir, pu_dir);
}
pu_dir = pud_offset(pg_dir, address);
@@ -103,7 +103,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
pm_dir = vmem_pmd_alloc();
if (!pm_dir)
goto out;
- pud_populate_kernel(&init_mm, pu_dir, pm_dir);
+ pud_populate(&init_mm, pu_dir, pm_dir);
}
pte = mk_pte_phys(address, __pgprot(ro ? _PAGE_RO : 0));
@@ -123,7 +123,7 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
pt_dir = vmem_pte_alloc();
if (!pt_dir)
goto out;
- pmd_populate_kernel(&init_mm, pm_dir, pt_dir);
+ pmd_populate(&init_mm, pm_dir, pt_dir);
}
pt_dir = pte_offset_kernel(pm_dir, address);
@@ -159,7 +159,7 @@ static void vmem_remove_range(unsigned long start, unsigned long size)
continue;
if (pmd_huge(*pm_dir)) {
- pmd_clear_kernel(pm_dir);
+ pmd_clear(pm_dir);
address += HPAGE_SIZE - PAGE_SIZE;
continue;
}
@@ -192,7 +192,7 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
pu_dir = vmem_pud_alloc();
if (!pu_dir)
goto out;
- pgd_populate_kernel(&init_mm, pg_dir, pu_dir);
+ pgd_populate(&init_mm, pg_dir, pu_dir);
}
pu_dir = pud_offset(pg_dir, address);
@@ -200,7 +200,7 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
pm_dir = vmem_pmd_alloc();
if (!pm_dir)
goto out;
- pud_populate_kernel(&init_mm, pu_dir, pm_dir);
+ pud_populate(&init_mm, pu_dir, pm_dir);
}
pm_dir = pmd_offset(pu_dir, address);
@@ -208,7 +208,7 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
pt_dir = vmem_pte_alloc();
if (!pt_dir)
goto out;
- pmd_populate_kernel(&init_mm, pm_dir, pt_dir);
+ pmd_populate(&init_mm, pm_dir, pt_dir);
}
pt_dir = pte_offset_kernel(pm_dir, address);
diff --git a/arch/s390/oprofile/hwsampler.c b/arch/s390/oprofile/hwsampler.c
index 33cbd373cce4..4552ce40c81a 100644
--- a/arch/s390/oprofile/hwsampler.c
+++ b/arch/s390/oprofile/hwsampler.c
@@ -5,6 +5,7 @@
* Author: Heinz Graalfs <graalfs@de.ibm.com>
*/
+#include <linux/kernel_stat.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/smp.h>
@@ -18,7 +19,7 @@
#include <linux/oprofile.h>
#include <asm/lowcore.h>
-#include <asm/s390_ext.h>
+#include <asm/irq.h>
#include "hwsampler.h"
@@ -579,7 +580,7 @@ static int hws_cpu_callback(struct notifier_block *nfb,
{
/* We do not have sampler space available for all possible CPUs.
All CPUs should be online when hw sampling is activated. */
- return NOTIFY_BAD;
+ return (hws_state <= HWS_DEALLOCATED) ? NOTIFY_OK : NOTIFY_BAD;
}
static struct notifier_block hws_cpu_notifier = {
@@ -674,17 +675,11 @@ int hwsampler_activate(unsigned int cpu)
static void hws_ext_handler(unsigned int ext_int_code,
unsigned int param32, unsigned long param64)
{
- int cpu;
struct hws_cpu_buffer *cb;
- cpu = smp_processor_id();
- cb = &per_cpu(sampler_cpu_buffer, cpu);
-
- atomic_xchg(
- &cb->ext_params,
- atomic_read(&cb->ext_params)
- | S390_lowcore.ext_params);
-
+ kstat_cpu(smp_processor_id()).irqs[EXTINT_CPM]++;
+ cb = &__get_cpu_var(sampler_cpu_buffer);
+ atomic_xchg(&cb->ext_params, atomic_read(&cb->ext_params) | param32);
if (hws_wq)
queue_work(hws_wq, &cb->worker);
}
@@ -764,7 +759,7 @@ static int worker_check_error(unsigned int cpu, int ext_params)
if (!sdbt || !*sdbt)
return -EINVAL;
- if (ext_params & EI_IEA)
+ if (ext_params & EI_PRA)
cb->req_alert++;
if (ext_params & EI_LSDA)
@@ -1009,7 +1004,7 @@ int hwsampler_deallocate()
if (hws_state != HWS_STOPPED)
goto deallocate_exit;
- smp_ctl_clear_bit(0, 5); /* set bit 58 CR0 off */
+ ctl_clear_bit(0, 5); /* set bit 58 CR0 off */
deallocate_sdbt();
hws_state = HWS_DEALLOCATED;
@@ -1123,7 +1118,7 @@ int hwsampler_shutdown()
mutex_lock(&hws_sem);
if (hws_state == HWS_STOPPED) {
- smp_ctl_clear_bit(0, 5); /* set bit 58 CR0 off */
+ ctl_clear_bit(0, 5); /* set bit 58 CR0 off */
deallocate_sdbt();
}
if (hws_wq) {
@@ -1198,7 +1193,7 @@ start_all_exit:
hws_oom = 1;
hws_flush_all = 0;
/* now let them in, 1407 CPUMF external interrupts */
- smp_ctl_set_bit(0, 5); /* set CR0 bit 58 */
+ ctl_set_bit(0, 5); /* set CR0 bit 58 */
return 0;
}
diff --git a/arch/score/Kconfig b/arch/score/Kconfig
index e73bc781cc14..288add8d168f 100644
--- a/arch/score/Kconfig
+++ b/arch/score/Kconfig
@@ -43,9 +43,6 @@ config NO_DMA
config RWSEM_GENERIC_SPINLOCK
def_bool y
-config GENERIC_FIND_NEXT_BIT
- def_bool y
-
config GENERIC_HWEIGHT
def_bool y
diff --git a/arch/score/Kconfig.debug b/arch/score/Kconfig.debug
index 451ed54ce646..a1f346df0a71 100644
--- a/arch/score/Kconfig.debug
+++ b/arch/score/Kconfig.debug
@@ -16,15 +16,6 @@ config CMDLINE
other cases you can specify kernel args so that you don't have
to set them up in board prom initialization routines.
-config DEBUG_STACK_USAGE
- bool "Enable stack utilization instrumentation"
- depends on DEBUG_KERNEL
- help
- Enables the display of the minimum amount of free stack which each
- task has ever had available in the sysrq-T and sysrq-P debug output.
-
- This option will slow down process creation somewhat.
-
config RUNTIME_DEBUG
bool "Enable run-time debugging"
depends on DEBUG_KERNEL
diff --git a/arch/score/mm/init.c b/arch/score/mm/init.c
index 50fdec54c70a..cee6bce1e30c 100644
--- a/arch/score/mm/init.c
+++ b/arch/score/mm/init.c
@@ -38,8 +38,6 @@
#include <asm/sections.h>
#include <asm/tlb.h>
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
unsigned long empty_zero_page;
EXPORT_SYMBOL_GPL(empty_zero_page);
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 4b89da248d17..74495a5ea027 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -21,10 +21,10 @@ config SUPERH
select HAVE_REGS_AND_STACK_ACCESS_API
select HAVE_GENERIC_HARDIRQS
select HAVE_SPARSE_IRQ
+ select IRQ_FORCED_THREADING
select RTC_LIB
select GENERIC_ATOMIC64
select GENERIC_IRQ_SHOW
- select ARCH_NO_SYSDEV_OPS
help
The SuperH is a RISC processor targeted for use in embedded systems
and consumer electronics; it was also used in the Sega Dreamcast
@@ -71,12 +71,6 @@ config GENERIC_CSUM
def_bool y
depends on SUPERH64
-config GENERIC_FIND_NEXT_BIT
- def_bool y
-
-config GENERIC_FIND_BIT_LE
- def_bool y
-
config GENERIC_HWEIGHT
def_bool y
diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug
index 1553d56cf4e0..c1d5a820b1aa 100644
--- a/arch/sh/Kconfig.debug
+++ b/arch/sh/Kconfig.debug
@@ -28,15 +28,6 @@ config STACK_DEBUG
every function call and will therefore incur a major
performance hit. Most users should say N.
-config DEBUG_STACK_USAGE
- bool "Stack utilization instrumentation"
- depends on DEBUG_KERNEL
- help
- Enables the display of the minimum amount of free stack which each
- task has ever had available in the sysrq-T and sysrq-P debug output.
-
- This option will slow down process creation somewhat.
-
config 4KSTACKS
bool "Use 4Kb for kernel stacks instead of 8Kb"
depends on DEBUG_KERNEL && (MMU || BROKEN) && !PAGE_SIZE_64KB
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index 86a0d565aded..bb13d0e1b964 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -482,7 +482,7 @@ static struct i2c_board_info ts_i2c_clients = {
.irq = IRQ0,
};
-#if defined(CONFIG_MMC_TMIO) || defined(CONFIG_MMC_TMIO_MODULE)
+#if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
/* SDHI0 */
static void sdhi0_set_pwr(struct platform_device *pdev, int state)
{
@@ -522,7 +522,7 @@ static struct platform_device sdhi0_device = {
},
};
-#if !defined(CONFIG_MMC_SH_MMCIF)
+#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
/* SDHI1 */
static void sdhi1_set_pwr(struct platform_device *pdev, int state)
{
@@ -836,7 +836,7 @@ static struct platform_device vou_device = {
},
};
-#if defined(CONFIG_MMC_SH_MMCIF)
+#if defined(CONFIG_MMC_SH_MMCIF) || defined(CONFIG_MMC_SH_MMCIF_MODULE)
/* SH_MMCIF */
static void mmcif_set_pwr(struct platform_device *pdev, int state)
{
@@ -898,9 +898,9 @@ static struct platform_device *ecovec_devices[] __initdata = {
&ceu0_device,
&ceu1_device,
&keysc_device,
-#if defined(CONFIG_MMC_TMIO) || defined(CONFIG_MMC_TMIO_MODULE)
+#if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
&sdhi0_device,
-#if !defined(CONFIG_MMC_SH_MMCIF)
+#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
&sdhi1_device,
#endif
#else
@@ -912,7 +912,7 @@ static struct platform_device *ecovec_devices[] __initdata = {
&fsi_device,
&irda_device,
&vou_device,
-#if defined(CONFIG_MMC_SH_MMCIF)
+#if defined(CONFIG_MMC_SH_MMCIF) || defined(CONFIG_MMC_SH_MMCIF_MODULE)
&sh_mmcif_device,
#endif
};
@@ -1180,7 +1180,7 @@ static int __init arch_setup(void)
gpio_direction_input(GPIO_PTR5);
gpio_direction_input(GPIO_PTR6);
-#if defined(CONFIG_MMC_TMIO) || defined(CONFIG_MMC_TMIO_MODULE)
+#if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
/* enable SDHI0 on CN11 (needs DS2.4 set to ON) */
gpio_request(GPIO_FN_SDHI0CD, NULL);
gpio_request(GPIO_FN_SDHI0WP, NULL);
@@ -1193,7 +1193,7 @@ static int __init arch_setup(void)
gpio_request(GPIO_PTB6, NULL);
gpio_direction_output(GPIO_PTB6, 0);
-#if !defined(CONFIG_MMC_SH_MMCIF)
+#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
/* enable SDHI1 on CN12 (needs DS2.6,7 set to ON,OFF) */
gpio_request(GPIO_FN_SDHI1CD, NULL);
gpio_request(GPIO_FN_SDHI1WP, NULL);
@@ -1284,7 +1284,7 @@ static int __init arch_setup(void)
gpio_request(GPIO_PTU5, NULL);
gpio_direction_output(GPIO_PTU5, 0);
-#if defined(CONFIG_MMC_SH_MMCIF)
+#if defined(CONFIG_MMC_SH_MMCIF) || defined(CONFIG_MMC_SH_MMCIF_MODULE)
/* enable MMCIF (needs DS2.6,7 set to OFF,ON) */
gpio_request(GPIO_FN_MMC_D7, NULL);
gpio_request(GPIO_FN_MMC_D6, NULL);
diff --git a/arch/sh/configs/apsh4ad0a_defconfig b/arch/sh/configs/apsh4ad0a_defconfig
index e71a531f1e31..e7583484cc07 100644
--- a/arch/sh/configs/apsh4ad0a_defconfig
+++ b/arch/sh/configs/apsh4ad0a_defconfig
@@ -7,7 +7,6 @@ CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_CGROUPS=y
-CONFIG_CGROUP_NS=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
@@ -48,7 +47,6 @@ CONFIG_PREEMPT=y
CONFIG_BINFMT_MISC=y
CONFIG_PM=y
CONFIG_PM_DEBUG=y
-CONFIG_PM_VERBOSE=y
CONFIG_PM_RUNTIME=y
CONFIG_CPU_IDLE=y
CONFIG_NET=y
diff --git a/arch/sh/configs/ecovec24_defconfig b/arch/sh/configs/ecovec24_defconfig
index 8d13e8a5a750..911e30c9abfd 100644
--- a/arch/sh/configs/ecovec24_defconfig
+++ b/arch/sh/configs/ecovec24_defconfig
@@ -115,7 +115,7 @@ CONFIG_USB_GADGET=y
CONFIG_USB_FILE_STORAGE=m
CONFIG_MMC=y
CONFIG_MMC_SPI=y
-CONFIG_MMC_TMIO=y
+CONFIG_MMC_SDHI=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_RS5C372=y
CONFIG_UIO=y
diff --git a/arch/sh/configs/sdk7786_defconfig b/arch/sh/configs/sdk7786_defconfig
index dc4a2eb6a616..8a7dd7b59c5c 100644
--- a/arch/sh/configs/sdk7786_defconfig
+++ b/arch/sh/configs/sdk7786_defconfig
@@ -12,7 +12,6 @@ CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_CGROUPS=y
CONFIG_CGROUP_DEBUG=y
-CONFIG_CGROUP_NS=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CPUSETS=y
@@ -83,7 +82,6 @@ CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
CONFIG_BINFMT_MISC=y
CONFIG_PM=y
CONFIG_PM_DEBUG=y
-CONFIG_PM_VERBOSE=y
CONFIG_PM_RUNTIME=y
CONFIG_CPU_IDLE=y
CONFIG_NET=y
diff --git a/arch/sh/configs/se7206_defconfig b/arch/sh/configs/se7206_defconfig
index a468ff227fc6..72c3fad7383f 100644
--- a/arch/sh/configs/se7206_defconfig
+++ b/arch/sh/configs/se7206_defconfig
@@ -8,7 +8,6 @@ CONFIG_RCU_TRACE=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_CGROUPS=y
CONFIG_CGROUP_DEBUG=y
-CONFIG_CGROUP_NS=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_RESOURCE_COUNTERS=y
diff --git a/arch/sh/configs/sh7757lcr_defconfig b/arch/sh/configs/sh7757lcr_defconfig
index fa0ecf87034c..33ddb130a7c8 100644
--- a/arch/sh/configs/sh7757lcr_defconfig
+++ b/arch/sh/configs/sh7757lcr_defconfig
@@ -70,7 +70,7 @@ CONFIG_USB_EHCI_HCD=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_STORAGE=y
CONFIG_MMC=y
-CONFIG_MMC_TMIO=y
+CONFIG_MMC_SDHI=y
CONFIG_MMC_SH_MMCIF=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
diff --git a/arch/sh/configs/shx3_defconfig b/arch/sh/configs/shx3_defconfig
index 3f92d37c6374..6bb413036892 100644
--- a/arch/sh/configs/shx3_defconfig
+++ b/arch/sh/configs/shx3_defconfig
@@ -9,7 +9,6 @@ CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_CGROUPS=y
-CONFIG_CGROUP_NS=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
diff --git a/arch/sh/configs/urquell_defconfig b/arch/sh/configs/urquell_defconfig
index 7b3daec6fefe..8bfa4d056d7a 100644
--- a/arch/sh/configs/urquell_defconfig
+++ b/arch/sh/configs/urquell_defconfig
@@ -9,7 +9,6 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_CGROUPS=y
CONFIG_CGROUP_DEBUG=y
-CONFIG_CGROUP_NS=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CPUSETS=y
diff --git a/arch/sh/drivers/pci/fixups-se7751.c b/arch/sh/drivers/pci/fixups-se7751.c
index a4c7d3a4efca..fd3e6b02f289 100644
--- a/arch/sh/drivers/pci/fixups-se7751.c
+++ b/arch/sh/drivers/pci/fixups-se7751.c
@@ -6,7 +6,7 @@
#include <linux/io.h>
#include "pci-sh4.h"
-int __init pcibios_map_platform_irq(u8 slot, u8 pin)
+int __init pcibios_map_platform_irq(struct pci_dev *, u8 slot, u8 pin)
{
switch (slot) {
case 0: return 13;
diff --git a/arch/sh/include/asm/kgdb.h b/arch/sh/include/asm/kgdb.h
index 4235e228d921..f3613952d1ae 100644
--- a/arch/sh/include/asm/kgdb.h
+++ b/arch/sh/include/asm/kgdb.h
@@ -34,5 +34,6 @@ static inline void arch_kgdb_breakpoint(void)
#define CACHE_FLUSH_IS_SAFE 1
#define BREAK_INSTR_SIZE 2
+#define GDB_ADJUSTS_BREAK_OFFSET
#endif /* __ASM_SH_KGDB_H */
diff --git a/arch/sh/include/asm/ptrace.h b/arch/sh/include/asm/ptrace.h
index de167d3a1a80..40725b4a8018 100644
--- a/arch/sh/include/asm/ptrace.h
+++ b/arch/sh/include/asm/ptrace.h
@@ -40,9 +40,8 @@
#include <asm/system.h>
#define user_mode(regs) (((regs)->sr & 0x40000000)==0)
-#define user_stack_pointer(_regs) ((unsigned long)(_regs)->regs[15])
#define kernel_stack_pointer(_regs) ((unsigned long)(_regs)->regs[15])
-#define instruction_pointer(regs) ((unsigned long)(regs)->pc)
+#define GET_USP(regs) ((regs)->regs[15])
extern void show_regs(struct pt_regs *);
@@ -139,6 +138,9 @@ static inline unsigned long profile_pc(struct pt_regs *regs)
return pc;
}
+#define profile_pc profile_pc
+
+#include <asm-generic/ptrace.h>
#endif /* __KERNEL__ */
#endif /* __ASM_SH_PTRACE_H */
diff --git a/arch/sh/include/asm/stacktrace.h b/arch/sh/include/asm/stacktrace.h
index 797018213718..a7e2d4dfd087 100644
--- a/arch/sh/include/asm/stacktrace.h
+++ b/arch/sh/include/asm/stacktrace.h
@@ -10,9 +10,6 @@
/* Generic stack tracer with callbacks */
struct stacktrace_ops {
- void (*warning)(void *data, char *msg);
- /* msg must contain %s for the symbol */
- void (*warning_symbol)(void *data, char *msg, unsigned long symbol);
void (*address)(void *data, unsigned long address, int reliable);
/* On negative return stop dumping */
int (*stack)(void *data, char *name);
diff --git a/arch/sh/include/asm/tlb.h b/arch/sh/include/asm/tlb.h
index 75abb38dffd5..6c308d8b9a50 100644
--- a/arch/sh/include/asm/tlb.h
+++ b/arch/sh/include/asm/tlb.h
@@ -23,8 +23,6 @@ struct mmu_gather {
unsigned long start, end;
};
-DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
-
static inline void init_tlb_gather(struct mmu_gather *tlb)
{
tlb->start = TASK_SIZE;
@@ -36,17 +34,13 @@ static inline void init_tlb_gather(struct mmu_gather *tlb)
}
}
-static inline struct mmu_gather *
-tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
+static inline void
+tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned int full_mm_flush)
{
- struct mmu_gather *tlb = &get_cpu_var(mmu_gathers);
-
tlb->mm = mm;
tlb->fullmm = full_mm_flush;
init_tlb_gather(tlb);
-
- return tlb;
}
static inline void
@@ -57,8 +51,6 @@ tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
/* keep the page table cache within bounds */
check_pgt_cache();
-
- put_cpu_var(mmu_gathers);
}
static inline void
@@ -91,7 +83,21 @@ tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)
}
}
-#define tlb_remove_page(tlb,page) free_page_and_swap_cache(page)
+static inline void tlb_flush_mmu(struct mmu_gather *tlb)
+{
+}
+
+static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+ free_page_and_swap_cache(page);
+ return 1; /* avoid calling tlb_flush_mmu */
+}
+
+static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+ __tlb_remove_page(tlb, page);
+}
+
#define pte_free_tlb(tlb, ptep, addr) pte_free((tlb)->mm, ptep)
#define pmd_free_tlb(tlb, pmdp, addr) pmd_free((tlb)->mm, pmdp)
#define pud_free_tlb(tlb, pudp, addr) pud_free((tlb)->mm, pudp)
diff --git a/arch/sh/include/asm/unistd_32.h b/arch/sh/include/asm/unistd_32.h
index ca7765e5f967..bb7d2702c2c9 100644
--- a/arch/sh/include/asm/unistd_32.h
+++ b/arch/sh/include/asm/unistd_32.h
@@ -373,8 +373,9 @@
#define __NR_open_by_handle_at 360
#define __NR_clock_adjtime 361
#define __NR_syncfs 362
+#define __NR_sendmmsg 363
-#define NR_syscalls 363
+#define NR_syscalls 364
#ifdef __KERNEL__
diff --git a/arch/sh/include/asm/unistd_64.h b/arch/sh/include/asm/unistd_64.h
index a694009bb816..46327cea1e5c 100644
--- a/arch/sh/include/asm/unistd_64.h
+++ b/arch/sh/include/asm/unistd_64.h
@@ -394,10 +394,11 @@
#define __NR_open_by_handle_at 371
#define __NR_clock_adjtime 372
#define __NR_syncfs 373
+#define __NR_sendmmsg 374
#ifdef __KERNEL__
-#define NR_syscalls 374
+#define NR_syscalls 375
#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR
diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile
index d49c2135fd48..ae95935d93cd 100644
--- a/arch/sh/kernel/cpu/Makefile
+++ b/arch/sh/kernel/cpu/Makefile
@@ -17,7 +17,5 @@ obj-$(CONFIG_ARCH_SHMOBILE) += shmobile/
obj-$(CONFIG_SH_ADC) += adc.o
obj-$(CONFIG_SH_CLK_CPG_LEGACY) += clock-cpg.o
-obj-$(CONFIG_SH_FPU) += fpu.o
-obj-$(CONFIG_SH_FPU_EMU) += fpu.o
-obj-y += irq/ init.o clock.o hwblk.o proc.o
+obj-y += irq/ init.o clock.o fpu.o hwblk.o proc.o
diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c
index 14726eef1ce0..f0907995b4c9 100644
--- a/arch/sh/kernel/cpu/sh4/sq.c
+++ b/arch/sh/kernel/cpu/sh4/sq.c
@@ -20,6 +20,7 @@
#include <linux/vmalloc.h>
#include <linux/mm.h>
#include <linux/io.h>
+#include <linux/prefetch.h>
#include <asm/page.h>
#include <asm/cacheflush.h>
#include <cpu/sq.h>
diff --git a/arch/sh/kernel/cpu/shmobile/pm_runtime.c b/arch/sh/kernel/cpu/shmobile/pm_runtime.c
index 6dcb8166a64d..64c807c39208 100644
--- a/arch/sh/kernel/cpu/shmobile/pm_runtime.c
+++ b/arch/sh/kernel/cpu/shmobile/pm_runtime.c
@@ -139,7 +139,7 @@ void platform_pm_runtime_suspend_idle(void)
queue_work(pm_wq, &hwblk_work);
}
-int platform_pm_runtime_suspend(struct device *dev)
+static int default_platform_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct pdev_archdata *ad = &pdev->archdata;
@@ -147,7 +147,7 @@ int platform_pm_runtime_suspend(struct device *dev)
int hwblk = ad->hwblk_id;
int ret = 0;
- dev_dbg(dev, "platform_pm_runtime_suspend() [%d]\n", hwblk);
+ dev_dbg(dev, "%s() [%d]\n", __func__, hwblk);
/* ignore off-chip platform devices */
if (!hwblk)
@@ -157,7 +157,7 @@ int platform_pm_runtime_suspend(struct device *dev)
might_sleep();
/* catch misconfigured drivers not starting with resume */
- if (test_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags)) {
+ if (test_bit(PDEV_ARCHDATA_FLAG_INIT, &ad->flags)) {
ret = -EINVAL;
goto out;
}
@@ -170,8 +170,8 @@ int platform_pm_runtime_suspend(struct device *dev)
/* put device on idle list */
spin_lock_irqsave(&hwblk_lock, flags);
- list_add_tail(&pdev->archdata.entry, &hwblk_idle_list);
- __set_bit(PDEV_ARCHDATA_FLAG_IDLE, &pdev->archdata.flags);
+ list_add_tail(&ad->entry, &hwblk_idle_list);
+ __set_bit(PDEV_ARCHDATA_FLAG_IDLE, &ad->flags);
spin_unlock_irqrestore(&hwblk_lock, flags);
/* increase idle count */
@@ -183,20 +183,20 @@ int platform_pm_runtime_suspend(struct device *dev)
mutex_unlock(&ad->mutex);
out:
- dev_dbg(dev, "platform_pm_runtime_suspend() [%d] returns %d\n",
- hwblk, ret);
+ dev_dbg(dev, "%s() [%d] returns %d\n",
+ __func__, hwblk, ret);
return ret;
}
-int platform_pm_runtime_resume(struct device *dev)
+static int default_platform_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct pdev_archdata *ad = &pdev->archdata;
int hwblk = ad->hwblk_id;
int ret = 0;
- dev_dbg(dev, "platform_pm_runtime_resume() [%d]\n", hwblk);
+ dev_dbg(dev, "%s() [%d]\n", __func__, hwblk);
/* ignore off-chip platform devices */
if (!hwblk)
@@ -228,19 +228,19 @@ int platform_pm_runtime_resume(struct device *dev)
*/
mutex_unlock(&ad->mutex);
out:
- dev_dbg(dev, "platform_pm_runtime_resume() [%d] returns %d\n",
- hwblk, ret);
+ dev_dbg(dev, "%s() [%d] returns %d\n",
+ __func__, hwblk, ret);
return ret;
}
-int platform_pm_runtime_idle(struct device *dev)
+static int default_platform_runtime_idle(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
int hwblk = pdev->archdata.hwblk_id;
int ret = 0;
- dev_dbg(dev, "platform_pm_runtime_idle() [%d]\n", hwblk);
+ dev_dbg(dev, "%s() [%d]\n", __func__, hwblk);
/* ignore off-chip platform devices */
if (!hwblk)
@@ -252,10 +252,19 @@ int platform_pm_runtime_idle(struct device *dev)
/* suspend synchronously to disable clocks immediately */
ret = pm_runtime_suspend(dev);
out:
- dev_dbg(dev, "platform_pm_runtime_idle() [%d] done!\n", hwblk);
+ dev_dbg(dev, "%s() [%d] done!\n", __func__, hwblk);
return ret;
}
+static struct dev_power_domain default_power_domain = {
+ .ops = {
+ .runtime_suspend = default_platform_runtime_suspend,
+ .runtime_resume = default_platform_runtime_resume,
+ .runtime_idle = default_platform_runtime_idle,
+ USE_PLATFORM_PM_SLEEP_OPS
+ },
+};
+
static int platform_bus_notify(struct notifier_block *nb,
unsigned long action, void *data)
{
@@ -276,6 +285,7 @@ static int platform_bus_notify(struct notifier_block *nb,
hwblk_disable(hwblk_info, hwblk);
/* make sure driver re-inits itself once */
__set_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags);
+ dev->pwr_domain = &default_power_domain;
break;
/* TODO: add BUS_NOTIFY_BIND_DRIVER and increase idle count */
case BUS_NOTIFY_BOUND_DRIVER:
@@ -289,6 +299,7 @@ static int platform_bus_notify(struct notifier_block *nb,
__set_bit(PDEV_ARCHDATA_FLAG_INIT, &pdev->archdata.flags);
break;
case BUS_NOTIFY_DEL_DEVICE:
+ dev->pwr_domain = NULL;
break;
}
return 0;
diff --git a/arch/sh/kernel/dumpstack.c b/arch/sh/kernel/dumpstack.c
index 6f5ad1513409..694158b9a50f 100644
--- a/arch/sh/kernel/dumpstack.c
+++ b/arch/sh/kernel/dumpstack.c
@@ -69,19 +69,6 @@ stack_reader_dump(struct task_struct *task, struct pt_regs *regs,
}
}
-static void
-print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
-{
- printk(data);
- print_symbol(msg, symbol);
- printk("\n");
-}
-
-static void print_trace_warning(void *data, char *msg)
-{
- printk("%s%s\n", (char *)data, msg);
-}
-
static int print_trace_stack(void *data, char *name)
{
printk("%s <%s> ", (char *)data, name);
@@ -98,8 +85,6 @@ static void print_trace_address(void *data, unsigned long addr, int reliable)
}
static const struct stacktrace_ops print_trace_ops = {
- .warning = print_trace_warning,
- .warning_symbol = print_trace_warning_symbol,
.stack = print_trace_stack,
.address = print_trace_address,
};
diff --git a/arch/sh/kernel/module.c b/arch/sh/kernel/module.c
index ae0be697a89e..19b1f8826aef 100644
--- a/arch/sh/kernel/module.c
+++ b/arch/sh/kernel/module.c
@@ -93,6 +93,8 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
#endif
switch (ELF32_R_TYPE(rel[i].r_info)) {
+ case R_SH_NONE:
+ break;
case R_SH_DIR32:
value = get_unaligned(location);
value += relocation;
diff --git a/arch/sh/kernel/perf_callchain.c b/arch/sh/kernel/perf_callchain.c
index d5ca1ef50fa9..cc80b614b5fa 100644
--- a/arch/sh/kernel/perf_callchain.c
+++ b/arch/sh/kernel/perf_callchain.c
@@ -14,16 +14,6 @@
#include <asm/unwinder.h>
#include <asm/ptrace.h>
-
-static void callchain_warning(void *data, char *msg)
-{
-}
-
-static void
-callchain_warning_symbol(void *data, char *msg, unsigned long symbol)
-{
-}
-
static int callchain_stack(void *data, char *name)
{
return 0;
@@ -38,8 +28,6 @@ static void callchain_address(void *data, unsigned long addr, int reliable)
}
static const struct stacktrace_ops callchain_ops = {
- .warning = callchain_warning,
- .warning_symbol = callchain_warning_symbol,
.stack = callchain_stack,
.address = callchain_address,
};
diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c
index 509b36b45115..6207561ea34a 100644
--- a/arch/sh/kernel/smp.c
+++ b/arch/sh/kernel/smp.c
@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/cpu.h>
#include <linux/interrupt.h>
+#include <linux/sched.h>
#include <asm/atomic.h>
#include <asm/processor.h>
#include <asm/system.h>
@@ -323,6 +324,7 @@ void smp_message_recv(unsigned int msg)
generic_smp_call_function_interrupt();
break;
case SMP_MSG_RESCHEDULE:
+ scheduler_ipi();
break;
case SMP_MSG_FUNCTION_SINGLE:
generic_smp_call_function_single_interrupt();
diff --git a/arch/sh/kernel/stacktrace.c b/arch/sh/kernel/stacktrace.c
index c2e45c48409c..bf989e063a0c 100644
--- a/arch/sh/kernel/stacktrace.c
+++ b/arch/sh/kernel/stacktrace.c
@@ -17,15 +17,6 @@
#include <asm/ptrace.h>
#include <asm/stacktrace.h>
-static void save_stack_warning(void *data, char *msg)
-{
-}
-
-static void
-save_stack_warning_symbol(void *data, char *msg, unsigned long symbol)
-{
-}
-
static int save_stack_stack(void *data, char *name)
{
return 0;
@@ -51,8 +42,6 @@ static void save_stack_address(void *data, unsigned long addr, int reliable)
}
static const struct stacktrace_ops save_stack_ops = {
- .warning = save_stack_warning,
- .warning_symbol = save_stack_warning_symbol,
.stack = save_stack_stack,
.address = save_stack_address,
};
@@ -88,8 +77,6 @@ save_stack_address_nosched(void *data, unsigned long addr, int reliable)
}
static const struct stacktrace_ops save_stack_ops_nosched = {
- .warning = save_stack_warning,
- .warning_symbol = save_stack_warning_symbol,
.stack = save_stack_stack,
.address = save_stack_address_nosched,
};
diff --git a/arch/sh/kernel/syscalls_32.S b/arch/sh/kernel/syscalls_32.S
index 030966a9305c..7c486f3e3a3c 100644
--- a/arch/sh/kernel/syscalls_32.S
+++ b/arch/sh/kernel/syscalls_32.S
@@ -380,3 +380,4 @@ ENTRY(sys_call_table)
.long sys_open_by_handle_at /* 360 */
.long sys_clock_adjtime
.long sys_syncfs
+ .long sys_sendmmsg
diff --git a/arch/sh/kernel/syscalls_64.S b/arch/sh/kernel/syscalls_64.S
index ca0a6142ab63..ba1a737afe80 100644
--- a/arch/sh/kernel/syscalls_64.S
+++ b/arch/sh/kernel/syscalls_64.S
@@ -400,3 +400,4 @@ sys_call_table:
.long sys_open_by_handle_at
.long sys_clock_adjtime
.long sys_syncfs
+ .long sys_sendmmsg
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
index 3484c2f65aba..b51a17104b5f 100644
--- a/arch/sh/kernel/traps_32.c
+++ b/arch/sh/kernel/traps_32.c
@@ -87,7 +87,6 @@ void die(const char * str, struct pt_regs * regs, long err)
bust_spinlocks(1);
printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
- sysfs_printk_last_file();
print_modules();
show_regs(regs);
diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S
index af4d46187a79..731c10ce67b5 100644
--- a/arch/sh/kernel/vmlinux.lds.S
+++ b/arch/sh/kernel/vmlinux.lds.S
@@ -66,7 +66,7 @@ SECTIONS
__machvec_end = .;
}
- PERCPU(L1_CACHE_BYTES, PAGE_SIZE)
+ PERCPU_SECTION(L1_CACHE_BYTES)
/*
* .exit.text is discarded at runtime, not link time, to deal with
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index 0d3f912e3334..58a93fb3d965 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -28,7 +28,6 @@
#include <asm/cache.h>
#include <asm/sizes.h>
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
pgd_t swapper_pg_dir[PTRS_PER_PGD];
void __init generic_mem_init(void)
diff --git a/arch/sh/oprofile/backtrace.c b/arch/sh/oprofile/backtrace.c
index 37f3a75ea6cb..9c88dcd56e86 100644
--- a/arch/sh/oprofile/backtrace.c
+++ b/arch/sh/oprofile/backtrace.c
@@ -23,17 +23,6 @@
#include <asm/sections.h>
#include <asm/stacktrace.h>
-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)
{
/* Yes, we want all stacks */
@@ -49,8 +38,6 @@ static void backtrace_address(void *data, unsigned long addr, int reliable)
}
static struct stacktrace_ops backtrace_ops = {
- .warning = backtrace_warning,
- .warning_symbol = backtrace_warning_symbol,
.stack = backtrace_stack,
.address = backtrace_address,
};
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index e560d102215a..af32e17fa170 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -25,6 +25,10 @@ config SPARC
select HAVE_DMA_ATTRS
select HAVE_DMA_API_DEBUG
select HAVE_ARCH_JUMP_LABEL
+ select HAVE_GENERIC_HARDIRQS
+ select GENERIC_HARDIRQS_NO_DEPRECATED
+ select GENERIC_IRQ_SHOW
+ select USE_GENERIC_SMP_HELPERS if SMP
config SPARC32
def_bool !64BIT
@@ -43,15 +47,12 @@ config SPARC64
select HAVE_DYNAMIC_FTRACE
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_SYSCALL_TRACEPOINTS
- select USE_GENERIC_SMP_HELPERS if SMP
select RTC_DRV_CMOS
select RTC_DRV_BQ4802
select RTC_DRV_SUN4V
select RTC_DRV_STARFIRE
select HAVE_PERF_EVENTS
select PERF_USE_VMALLOC
- select HAVE_GENERIC_HARDIRQS
- select GENERIC_IRQ_SHOW
select IRQ_PREFLOW_FASTEOI
config ARCH_DEFCONFIG
@@ -189,14 +190,6 @@ config RWSEM_XCHGADD_ALGORITHM
bool
default y if SPARC64
-config GENERIC_FIND_NEXT_BIT
- bool
- default y
-
-config GENERIC_FIND_BIT_LE
- bool
- default y
-
config GENERIC_HWEIGHT
bool
default y if !ULTRA_HAS_POPULATION_COUNT
diff --git a/arch/sparc/Kconfig.debug b/arch/sparc/Kconfig.debug
index d9a795efbc04..6db35fba79fd 100644
--- a/arch/sparc/Kconfig.debug
+++ b/arch/sparc/Kconfig.debug
@@ -6,15 +6,6 @@ config TRACE_IRQFLAGS_SUPPORT
source "lib/Kconfig.debug"
-config DEBUG_STACK_USAGE
- bool "Enable stack utilization instrumentation"
- depends on DEBUG_KERNEL
- help
- Enables the display of the minimum amount of free stack which each
- task has ever had available in the sysrq-T and sysrq-P debug output.
-
- This option will slow down process creation somewhat.
-
config DEBUG_DCFLUSH
bool "D-cache flush debugging"
depends on SPARC64 && DEBUG_KERNEL
diff --git a/arch/sparc/include/asm/cpudata_32.h b/arch/sparc/include/asm/cpudata_32.h
index 31d48a0e32c7..a4c5a938b936 100644
--- a/arch/sparc/include/asm/cpudata_32.h
+++ b/arch/sparc/include/asm/cpudata_32.h
@@ -16,6 +16,10 @@ typedef struct {
unsigned long clock_tick;
unsigned int multiplier;
unsigned int counter;
+#ifdef CONFIG_SMP
+ unsigned int irq_resched_count;
+ unsigned int irq_call_count;
+#endif
int prom_node;
int mid;
int next;
@@ -23,5 +27,6 @@ typedef struct {
DECLARE_PER_CPU(cpuinfo_sparc, __cpu_data);
#define cpu_data(__cpu) per_cpu(__cpu_data, (__cpu))
+#define local_cpu_data() __get_cpu_var(__cpu_data)
#endif /* _SPARC_CPUDATA_H */
diff --git a/arch/sparc/include/asm/floppy_32.h b/arch/sparc/include/asm/floppy_32.h
index 86666f70322e..482c79e2a416 100644
--- a/arch/sparc/include/asm/floppy_32.h
+++ b/arch/sparc/include/asm/floppy_32.h
@@ -281,28 +281,27 @@ static inline void sun_fd_enable_dma(void)
pdma_areasize = pdma_size;
}
-/* Our low-level entry point in arch/sparc/kernel/entry.S */
-extern int sparc_floppy_request_irq(int irq, unsigned long flags,
- irq_handler_t irq_handler);
+extern int sparc_floppy_request_irq(unsigned int irq,
+ irq_handler_t irq_handler);
static int sun_fd_request_irq(void)
{
static int once = 0;
- int error;
- if(!once) {
+ if (!once) {
once = 1;
- error = sparc_floppy_request_irq(FLOPPY_IRQ,
- IRQF_DISABLED,
- floppy_interrupt);
- return ((error == 0) ? 0 : -1);
- } else return 0;
+ return sparc_floppy_request_irq(FLOPPY_IRQ, floppy_interrupt);
+ } else {
+ return 0;
+ }
}
static struct linux_prom_registers fd_regs[2];
static int sun_floppy_init(void)
{
+ struct platform_device *op;
+ struct device_node *dp;
char state[128];
phandle tnode, fd_node;
int num_regs;
@@ -310,7 +309,6 @@ static int sun_floppy_init(void)
use_virtual_dma = 1;
- FLOPPY_IRQ = 11;
/* Forget it if we aren't on a machine that could possibly
* ever have a floppy drive.
*/
@@ -349,6 +347,26 @@ static int sun_floppy_init(void)
sun_fdc = (struct sun_flpy_controller *)
of_ioremap(&r, 0, fd_regs[0].reg_size, "floppy");
+ /* Look up irq in platform_device.
+ * We try "SUNW,fdtwo" and "fd"
+ */
+ for_each_node_by_name(dp, "SUNW,fdtwo") {
+ op = of_find_device_by_node(dp);
+ if (op)
+ break;
+ }
+ if (!op) {
+ for_each_node_by_name(dp, "fd") {
+ op = of_find_device_by_node(dp);
+ if (op)
+ break;
+ }
+ }
+ if (!op)
+ goto no_sun_fdc;
+
+ FLOPPY_IRQ = op->archdata.irqs[0];
+
/* Last minute sanity check... */
if(sun_fdc->status_82072 == 0xff) {
sun_fdc = NULL;
diff --git a/arch/sparc/include/asm/io.h b/arch/sparc/include/asm/io.h
index a34b2994937a..f6902cf3cbe9 100644
--- a/arch/sparc/include/asm/io.h
+++ b/arch/sparc/include/asm/io.h
@@ -5,4 +5,17 @@
#else
#include <asm/io_32.h>
#endif
+
+/*
+ * Defines used for both SPARC32 and SPARC64
+ */
+
+/* Big endian versions of memory read/write routines */
+#define readb_be(__addr) __raw_readb(__addr)
+#define readw_be(__addr) __raw_readw(__addr)
+#define readl_be(__addr) __raw_readl(__addr)
+#define writeb_be(__b, __addr) __raw_writeb(__b, __addr)
+#define writel_be(__w, __addr) __raw_writel(__w, __addr)
+#define writew_be(__l, __addr) __raw_writew(__l, __addr)
+
#endif
diff --git a/arch/sparc/include/asm/irq_32.h b/arch/sparc/include/asm/irq_32.h
index eced3e3ebd30..2ae3acaeb1b3 100644
--- a/arch/sparc/include/asm/irq_32.h
+++ b/arch/sparc/include/asm/irq_32.h
@@ -6,7 +6,11 @@
#ifndef _SPARC_IRQ_H
#define _SPARC_IRQ_H
-#define NR_IRQS 16
+/* Allocated number of logical irq numbers.
+ * sun4d boxes (ss2000e) should be OK with ~32.
+ * Be on the safe side and make room for 64
+ */
+#define NR_IRQS 64
#include <linux/interrupt.h>
diff --git a/arch/sparc/include/asm/jump_label.h b/arch/sparc/include/asm/jump_label.h
index 427d4684e0d2..fc73a82366f8 100644
--- a/arch/sparc/include/asm/jump_label.h
+++ b/arch/sparc/include/asm/jump_label.h
@@ -7,17 +7,20 @@
#define JUMP_LABEL_NOP_SIZE 4
-#define JUMP_LABEL(key, label) \
- do { \
- asm goto("1:\n\t" \
- "nop\n\t" \
- "nop\n\t" \
- ".pushsection __jump_table, \"a\"\n\t"\
- ".align 4\n\t" \
- ".word 1b, %l[" #label "], %c0\n\t" \
- ".popsection \n\t" \
- : : "i" (key) : : label);\
- } while (0)
+static __always_inline bool arch_static_branch(struct jump_label_key *key)
+{
+ asm goto("1:\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ ".pushsection __jump_table, \"aw\"\n\t"
+ ".align 4\n\t"
+ ".word 1b, %l[l_yes], %c0\n\t"
+ ".popsection \n\t"
+ : : "i" (key) : : l_yes);
+ return false;
+l_yes:
+ return true;
+}
#endif /* __KERNEL__ */
diff --git a/arch/sparc/include/asm/leon.h b/arch/sparc/include/asm/leon.h
index c04f96fb753c..6bdaf1e43d2a 100644
--- a/arch/sparc/include/asm/leon.h
+++ b/arch/sparc/include/asm/leon.h
@@ -52,29 +52,6 @@
#define LEON_DIAGF_VALID 0x2000
#define LEON_DIAGF_VALID_SHIFT 13
-/*
- * Interrupt Sources
- *
- * The interrupt source numbers directly map to the trap type and to
- * the bits used in the Interrupt Clear, Interrupt Force, Interrupt Mask,
- * and the Interrupt Pending Registers.
- */
-#define LEON_INTERRUPT_CORRECTABLE_MEMORY_ERROR 1
-#define LEON_INTERRUPT_UART_1_RX_TX 2
-#define LEON_INTERRUPT_UART_0_RX_TX 3
-#define LEON_INTERRUPT_EXTERNAL_0 4
-#define LEON_INTERRUPT_EXTERNAL_1 5
-#define LEON_INTERRUPT_EXTERNAL_2 6
-#define LEON_INTERRUPT_EXTERNAL_3 7
-#define LEON_INTERRUPT_TIMER1 8
-#define LEON_INTERRUPT_TIMER2 9
-#define LEON_INTERRUPT_EMPTY1 10
-#define LEON_INTERRUPT_EMPTY2 11
-#define LEON_INTERRUPT_OPEN_ETH 12
-#define LEON_INTERRUPT_EMPTY4 13
-#define LEON_INTERRUPT_EMPTY5 14
-#define LEON_INTERRUPT_EMPTY6 15
-
/* irq masks */
#define LEON_HARD_INT(x) (1 << (x)) /* irq 0-15 */
#define LEON_IRQMASK_R 0x0000fffe /* bit 15- 1 of lregs.irqmask */
@@ -183,7 +160,6 @@ static inline void leon_srmmu_enabletlb(void)
/* macro access for leon_readnobuffer_reg() */
#define LEON_BYPASSCACHE_LOAD_VA(x) leon_readnobuffer_reg((unsigned long)(x))
-extern void sparc_leon_eirq_register(int eirq);
extern void leon_init(void);
extern void leon_switch_mm(void);
extern void leon_init_IRQ(void);
@@ -239,8 +215,8 @@ static inline int sparc_leon3_cpuid(void)
#endif /*!__ASSEMBLY__*/
#ifdef CONFIG_SMP
-# define LEON3_IRQ_RESCHEDULE 13
-# define LEON3_IRQ_TICKER (leon_percpu_timer_dev[0].irq)
+# define LEON3_IRQ_IPI_DEFAULT 13
+# define LEON3_IRQ_TICKER (leon3_ticker_irq)
# define LEON3_IRQ_CROSS_CALL 15
#endif
@@ -339,9 +315,9 @@ struct leon2_cacheregs {
#include <linux/interrupt.h>
struct device_node;
-extern int sparc_leon_eirq_get(int eirq, int cpu);
-extern irqreturn_t sparc_leon_eirq_isr(int dummy, void *dev_id);
-extern void sparc_leon_eirq_register(int eirq);
+extern unsigned int leon_build_device_irq(unsigned int real_irq,
+ irq_flow_handler_t flow_handler,
+ const char *name, int do_ack);
extern void leon_clear_clock_irq(void);
extern void leon_load_profile_irq(int cpu, unsigned int limit);
extern void leon_init_timers(irq_handler_t counter_fn);
@@ -358,6 +334,7 @@ extern void leon3_getCacheRegs(struct leon3_cacheregs *regs);
extern int leon_flush_needed(void);
extern void leon_switch_mm(void);
extern int srmmu_swprobe_trace;
+extern int leon3_ticker_irq;
#ifdef CONFIG_SMP
extern int leon_smp_nrcpus(void);
@@ -366,17 +343,19 @@ extern void leon_smp_done(void);
extern void leon_boot_cpus(void);
extern int leon_boot_one_cpu(int i);
void leon_init_smp(void);
-extern void cpu_probe(void);
extern void cpu_idle(void);
extern void init_IRQ(void);
extern void cpu_panic(void);
extern int __leon_processor_id(void);
void leon_enable_irq_cpu(unsigned int irq_nr, unsigned int cpu);
+extern irqreturn_t leon_percpu_timer_interrupt(int irq, void *unused);
-extern unsigned int real_irq_entry[], smpleon_ticker[];
+extern unsigned int real_irq_entry[];
+extern unsigned int smpleon_ipi[];
extern unsigned int patchme_maybe_smp_msg[];
extern unsigned int t_nmi[], linux_trap_ipi15_leon[];
extern unsigned int linux_trap_ipi15_sun4m[];
+extern int leon_ipi_irq;
#endif /* CONFIG_SMP */
diff --git a/arch/sparc/include/asm/pcic.h b/arch/sparc/include/asm/pcic.h
index f20ef562b265..7eb5d78f5211 100644
--- a/arch/sparc/include/asm/pcic.h
+++ b/arch/sparc/include/asm/pcic.h
@@ -29,11 +29,17 @@ struct linux_pcic {
int pcic_imdim;
};
-extern int pcic_probe(void);
-/* Erm... MJ redefined pcibios_present() so that it does not work early. */
+#ifdef CONFIG_PCI
extern int pcic_present(void);
+extern int pcic_probe(void);
+extern void pci_time_init(void);
extern void sun4m_pci_init_IRQ(void);
-
+#else
+static inline int pcic_present(void) { return 0; }
+static inline int pcic_probe(void) { return 0; }
+static inline void pci_time_init(void) {}
+static inline void sun4m_pci_init_IRQ(void) {}
+#endif
#endif
/* Size of PCI I/O space which we relocate. */
diff --git a/arch/sparc/include/asm/pgalloc_64.h b/arch/sparc/include/asm/pgalloc_64.h
index 5bdfa2c6e400..4e5e0878144f 100644
--- a/arch/sparc/include/asm/pgalloc_64.h
+++ b/arch/sparc/include/asm/pgalloc_64.h
@@ -78,4 +78,7 @@ static inline void check_pgt_cache(void)
quicklist_trim(0, NULL, 25, 16);
}
+#define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, pte)
+#define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tlb)->mm, pmd)
+
#endif /* _SPARC64_PGALLOC_H */
diff --git a/arch/sparc/include/asm/pgtable_32.h b/arch/sparc/include/asm/pgtable_32.h
index 303bd4dc8292..5b31a8e89823 100644
--- a/arch/sparc/include/asm/pgtable_32.h
+++ b/arch/sparc/include/asm/pgtable_32.h
@@ -8,6 +8,8 @@
* Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
+#include <linux/const.h>
+
#ifndef __ASSEMBLY__
#include <asm-generic/4level-fixup.h>
@@ -456,9 +458,9 @@ extern int io_remap_pfn_range(struct vm_area_struct *vma,
#endif /* !(__ASSEMBLY__) */
-#define VMALLOC_START 0xfe600000
+#define VMALLOC_START _AC(0xfe600000,UL)
/* XXX Alter this when I get around to fixing sun4c - Anton */
-#define VMALLOC_END 0xffc00000
+#define VMALLOC_END _AC(0xffc00000,UL)
/* We provide our own get_unmapped_area to cope with VA holes for userland */
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h
index f8dddb7045bb..1e03c5a6b4f7 100644
--- a/arch/sparc/include/asm/pgtable_64.h
+++ b/arch/sparc/include/asm/pgtable_64.h
@@ -655,9 +655,11 @@ static inline int pte_special(pte_t pte)
#define pte_unmap(pte) do { } while (0)
/* Actual page table PTE updates. */
-extern void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, pte_t *ptep, pte_t orig);
+extern void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr,
+ pte_t *ptep, pte_t orig, int fullmm);
-static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte)
+static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte, int fullmm)
{
pte_t orig = *ptep;
@@ -670,12 +672,19 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *p
* and SUN4V pte layout, so this inline test is fine.
*/
if (likely(mm != &init_mm) && (pte_val(orig) & _PAGE_VALID))
- tlb_batch_add(mm, addr, ptep, orig);
+ tlb_batch_add(mm, addr, ptep, orig, fullmm);
}
+#define set_pte_at(mm,addr,ptep,pte) \
+ __set_pte_at((mm), (addr), (ptep), (pte), 0)
+
#define pte_clear(mm,addr,ptep) \
set_pte_at((mm), (addr), (ptep), __pte(0UL))
+#define __HAVE_ARCH_PTE_CLEAR_NOT_PRESENT_FULL
+#define pte_clear_not_present_full(mm,addr,ptep,fullmm) \
+ __set_pte_at((mm), (addr), (ptep), __pte(0UL), (fullmm))
+
#ifdef DCACHE_ALIASING_POSSIBLE
#define __HAVE_ARCH_MOVE_PTE
#define move_pte(pte, prot, old_addr, new_addr) \
@@ -699,6 +708,9 @@ extern pmd_t swapper_low_pmd_dir[2048];
extern void paging_init(void);
extern unsigned long find_ecache_flush_span(unsigned long size);
+struct seq_file;
+extern void mmu_info(struct seq_file *);
+
/* These do nothing with the way I have things setup. */
#define mmu_lockarea(vaddr, len) (vaddr)
#define mmu_unlockarea(vaddr, len) do { } while(0)
diff --git a/arch/sparc/include/asm/setup.h b/arch/sparc/include/asm/setup.h
index 2643c62f4ac0..64718ba26434 100644
--- a/arch/sparc/include/asm/setup.h
+++ b/arch/sparc/include/asm/setup.h
@@ -11,4 +11,16 @@
# define COMMAND_LINE_SIZE 256
#endif
+#ifdef __KERNEL__
+
+#ifdef CONFIG_SPARC32
+/* The CPU that was used for booting
+ * Only sun4d + leon may have boot_cpu_id != 0
+ */
+extern unsigned char boot_cpu_id;
+extern unsigned char boot_cpu_id4;
+#endif
+
+#endif /* __KERNEL__ */
+
#endif /* _SPARC_SETUP_H */
diff --git a/arch/sparc/include/asm/smp_32.h b/arch/sparc/include/asm/smp_32.h
index d82d7f4c0a79..093f10843ff2 100644
--- a/arch/sparc/include/asm/smp_32.h
+++ b/arch/sparc/include/asm/smp_32.h
@@ -50,42 +50,38 @@ void smp_callin(void);
void smp_boot_cpus(void);
void smp_store_cpu_info(int);
+void smp_resched_interrupt(void);
+void smp_call_function_single_interrupt(void);
+void smp_call_function_interrupt(void);
+
struct seq_file;
void smp_bogo(struct seq_file *);
void smp_info(struct seq_file *);
BTFIXUPDEF_CALL(void, smp_cross_call, smpfunc_t, cpumask_t, unsigned long, unsigned long, unsigned long, unsigned long)
BTFIXUPDEF_CALL(int, __hard_smp_processor_id, void)
+BTFIXUPDEF_CALL(void, smp_ipi_resched, int);
+BTFIXUPDEF_CALL(void, smp_ipi_single, int);
+BTFIXUPDEF_CALL(void, smp_ipi_mask_one, int);
BTFIXUPDEF_BLACKBOX(hard_smp_processor_id)
BTFIXUPDEF_BLACKBOX(load_current)
#define smp_cross_call(func,mask,arg1,arg2,arg3,arg4) BTFIXUP_CALL(smp_cross_call)(func,mask,arg1,arg2,arg3,arg4)
-static inline void xc0(smpfunc_t func) { smp_cross_call(func, cpu_online_map, 0, 0, 0, 0); }
+static inline void xc0(smpfunc_t func) { smp_cross_call(func, *cpu_online_mask, 0, 0, 0, 0); }
static inline void xc1(smpfunc_t func, unsigned long arg1)
-{ smp_cross_call(func, cpu_online_map, arg1, 0, 0, 0); }
+{ smp_cross_call(func, *cpu_online_mask, arg1, 0, 0, 0); }
static inline void xc2(smpfunc_t func, unsigned long arg1, unsigned long arg2)
-{ smp_cross_call(func, cpu_online_map, arg1, arg2, 0, 0); }
+{ smp_cross_call(func, *cpu_online_mask, arg1, arg2, 0, 0); }
static inline void xc3(smpfunc_t func, unsigned long arg1, unsigned long arg2,
unsigned long arg3)
-{ smp_cross_call(func, cpu_online_map, arg1, arg2, arg3, 0); }
+{ smp_cross_call(func, *cpu_online_mask, arg1, arg2, arg3, 0); }
static inline void xc4(smpfunc_t func, unsigned long arg1, unsigned long arg2,
unsigned long arg3, unsigned long arg4)
-{ smp_cross_call(func, cpu_online_map, arg1, arg2, arg3, arg4); }
-
-static inline int smp_call_function(void (*func)(void *info), void *info, int wait)
-{
- xc1((smpfunc_t)func, (unsigned long)info);
- return 0;
-}
+{ smp_cross_call(func, *cpu_online_mask, arg1, arg2, arg3, arg4); }
-static inline int smp_call_function_single(int cpuid, void (*func) (void *info),
- void *info, int wait)
-{
- smp_cross_call((smpfunc_t)func, cpumask_of_cpu(cpuid),
- (unsigned long) info, 0, 0, 0);
- return 0;
-}
+extern void arch_send_call_function_single_ipi(int cpu);
+extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
static inline int cpu_logical_map(int cpu)
{
@@ -135,6 +131,11 @@ static inline int hard_smp_processor_id(void)
__asm__ __volatile__("lda [%g0] ASI_M_VIKING_TMP1, %0\n\t"
"nop; nop" :
"=&r" (cpuid));
+ - leon
+ __asm__ __volatile__( "rd %asr17, %0\n\t"
+ "srl %0, 0x1c, %0\n\t"
+ "nop\n\t" :
+ "=&r" (cpuid));
See btfixup.h and btfixupprep.c to understand how a blackbox works.
*/
__asm__ __volatile__("sethi %%hi(___b_hard_smp_processor_id), %0\n\t"
diff --git a/arch/sparc/include/asm/smp_64.h b/arch/sparc/include/asm/smp_64.h
index f49e11cd4ded..20bca8950710 100644
--- a/arch/sparc/include/asm/smp_64.h
+++ b/arch/sparc/include/asm/smp_64.h
@@ -49,6 +49,10 @@ extern void cpu_play_dead(void);
extern void smp_fetch_global_regs(void);
+struct seq_file;
+void smp_bogo(struct seq_file *);
+void smp_info(struct seq_file *);
+
#ifdef CONFIG_HOTPLUG_CPU
extern int __cpu_disable(void);
extern void __cpu_die(unsigned int cpu);
diff --git a/arch/sparc/include/asm/spinlock_32.h b/arch/sparc/include/asm/spinlock_32.h
index 7f9b9dba38a6..5f5b8bf3f50d 100644
--- a/arch/sparc/include/asm/spinlock_32.h
+++ b/arch/sparc/include/asm/spinlock_32.h
@@ -9,6 +9,7 @@
#ifndef __ASSEMBLY__
#include <asm/psr.h>
+#include <asm/processor.h> /* for cpu_relax */
#define arch_spin_is_locked(lock) (*((volatile unsigned char *)(lock)) != 0)
diff --git a/arch/sparc/include/asm/system_32.h b/arch/sparc/include/asm/system_32.h
index 890036b3689a..47a7e862474e 100644
--- a/arch/sparc/include/asm/system_32.h
+++ b/arch/sparc/include/asm/system_32.h
@@ -15,11 +15,6 @@
#include <linux/irqflags.h>
-static inline unsigned int probe_irq_mask(unsigned long val)
-{
- return 0;
-}
-
/*
* Sparc (general) CPU types
*/
diff --git a/arch/sparc/include/asm/system_64.h b/arch/sparc/include/asm/system_64.h
index e3b65d8cf41b..3c96d3bb9f15 100644
--- a/arch/sparc/include/asm/system_64.h
+++ b/arch/sparc/include/asm/system_64.h
@@ -29,10 +29,6 @@ enum sparc_cpu {
/* This cannot ever be a sun4c :) That's just history. */
#define ARCH_SUN4C 0
-extern const char *sparc_cpu_type;
-extern const char *sparc_fpu_type;
-extern const char *sparc_pmu_type;
-
extern char reboot_command[];
/* These are here in an effort to more fully work around Spitfire Errata
diff --git a/arch/sparc/include/asm/tlb_64.h b/arch/sparc/include/asm/tlb_64.h
index dca406b9b6fc..190e18913cc6 100644
--- a/arch/sparc/include/asm/tlb_64.h
+++ b/arch/sparc/include/asm/tlb_64.h
@@ -7,66 +7,11 @@
#include <asm/tlbflush.h>
#include <asm/mmu_context.h>
-#define TLB_BATCH_NR 192
-
-/*
- * For UP we don't need to worry about TLB flush
- * and page free order so much..
- */
-#ifdef CONFIG_SMP
- #define FREE_PTE_NR 506
- #define tlb_fast_mode(bp) ((bp)->pages_nr == ~0U)
-#else
- #define FREE_PTE_NR 1
- #define tlb_fast_mode(bp) 1
-#endif
-
-struct mmu_gather {
- struct mm_struct *mm;
- unsigned int pages_nr;
- unsigned int need_flush;
- unsigned int fullmm;
- unsigned int tlb_nr;
- unsigned long vaddrs[TLB_BATCH_NR];
- struct page *pages[FREE_PTE_NR];
-};
-
-DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
-
#ifdef CONFIG_SMP
extern void smp_flush_tlb_pending(struct mm_struct *,
unsigned long, unsigned long *);
#endif
-extern void __flush_tlb_pending(unsigned long, unsigned long, unsigned long *);
-extern void flush_tlb_pending(void);
-
-static inline struct mmu_gather *tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
-{
- struct mmu_gather *mp = &get_cpu_var(mmu_gathers);
-
- BUG_ON(mp->tlb_nr);
-
- mp->mm = mm;
- mp->pages_nr = num_online_cpus() > 1 ? 0U : ~0U;
- mp->fullmm = full_mm_flush;
-
- return mp;
-}
-
-
-static inline void tlb_flush_mmu(struct mmu_gather *mp)
-{
- if (!mp->fullmm)
- flush_tlb_pending();
- if (mp->need_flush) {
- free_pages_and_swap_cache(mp->pages, mp->pages_nr);
- mp->pages_nr = 0;
- mp->need_flush = 0;
- }
-
-}
-
#ifdef CONFIG_SMP
extern void smp_flush_tlb_mm(struct mm_struct *mm);
#define do_flush_tlb_mm(mm) smp_flush_tlb_mm(mm)
@@ -74,38 +19,14 @@ extern void smp_flush_tlb_mm(struct mm_struct *mm);
#define do_flush_tlb_mm(mm) __flush_tlb_mm(CTX_HWBITS(mm->context), SECONDARY_CONTEXT)
#endif
-static inline void tlb_finish_mmu(struct mmu_gather *mp, unsigned long start, unsigned long end)
-{
- tlb_flush_mmu(mp);
-
- if (mp->fullmm)
- mp->fullmm = 0;
-
- /* keep the page table cache within bounds */
- check_pgt_cache();
-
- put_cpu_var(mmu_gathers);
-}
-
-static inline void tlb_remove_page(struct mmu_gather *mp, struct page *page)
-{
- if (tlb_fast_mode(mp)) {
- free_page_and_swap_cache(page);
- return;
- }
- mp->need_flush = 1;
- mp->pages[mp->pages_nr++] = page;
- if (mp->pages_nr >= FREE_PTE_NR)
- tlb_flush_mmu(mp);
-}
-
-#define tlb_remove_tlb_entry(mp,ptep,addr) do { } while (0)
-#define pte_free_tlb(mp, ptepage, addr) pte_free((mp)->mm, ptepage)
-#define pmd_free_tlb(mp, pmdp, addr) pmd_free((mp)->mm, pmdp)
-#define pud_free_tlb(tlb,pudp, addr) __pud_free_tlb(tlb,pudp,addr)
+extern void __flush_tlb_pending(unsigned long, unsigned long, unsigned long *);
+extern void flush_tlb_pending(void);
-#define tlb_migrate_finish(mm) do { } while (0)
#define tlb_start_vma(tlb, vma) do { } while (0)
#define tlb_end_vma(tlb, vma) do { } while (0)
+#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0)
+#define tlb_flush(tlb) flush_tlb_pending()
+
+#include <asm-generic/tlb.h>
#endif /* _SPARC64_TLB_H */
diff --git a/arch/sparc/include/asm/tlbflush_64.h b/arch/sparc/include/asm/tlbflush_64.h
index fbb675dbe0c9..2ef463494153 100644
--- a/arch/sparc/include/asm/tlbflush_64.h
+++ b/arch/sparc/include/asm/tlbflush_64.h
@@ -5,9 +5,17 @@
#include <asm/mmu_context.h>
/* TSB flush operations. */
-struct mmu_gather;
+
+#define TLB_BATCH_NR 192
+
+struct tlb_batch {
+ struct mm_struct *mm;
+ unsigned long tlb_nr;
+ unsigned long vaddrs[TLB_BATCH_NR];
+};
+
extern void flush_tsb_kernel_range(unsigned long start, unsigned long end);
-extern void flush_tsb_user(struct mmu_gather *mp);
+extern void flush_tsb_user(struct tlb_batch *tb);
/* TLB flush operations. */
diff --git a/arch/sparc/include/asm/topology_64.h b/arch/sparc/include/asm/topology_64.h
index 1c79f32734a0..8b9c556d630b 100644
--- a/arch/sparc/include/asm/topology_64.h
+++ b/arch/sparc/include/asm/topology_64.h
@@ -65,6 +65,10 @@ static inline int pcibus_to_node(struct pci_bus *pbus)
#define smt_capable() (sparc64_multi_core)
#endif /* CONFIG_SMP */
-#define cpu_coregroup_mask(cpu) (&cpu_core_map[cpu])
+extern cpumask_t cpu_core_map[NR_CPUS];
+static inline const struct cpumask *cpu_coregroup_mask(int cpu)
+{
+ return &cpu_core_map[cpu];
+}
#endif /* _ASM_SPARC64_TOPOLOGY_H */
diff --git a/arch/sparc/include/asm/unistd.h b/arch/sparc/include/asm/unistd.h
index 9d897b6db983..c5387ed0add8 100644
--- a/arch/sparc/include/asm/unistd.h
+++ b/arch/sparc/include/asm/unistd.h
@@ -404,8 +404,9 @@
#define __NR_open_by_handle_at 333
#define __NR_clock_adjtime 334
#define __NR_syncfs 335
+#define __NR_sendmmsg 336
-#define NR_syscalls 336
+#define NR_syscalls 337
#ifdef __32bit_syscall_numbers__
/* Sparc 32-bit only has the "setresuid32", "getresuid32" variants,
diff --git a/arch/sparc/include/asm/winmacro.h b/arch/sparc/include/asm/winmacro.h
index 5b0a06dc3bcb..a9be04b0d049 100644
--- a/arch/sparc/include/asm/winmacro.h
+++ b/arch/sparc/include/asm/winmacro.h
@@ -103,6 +103,7 @@
st %scratch, [%cur_reg + TI_W_SAVED];
#ifdef CONFIG_SMP
+/* Results of LOAD_CURRENT() after BTFIXUP for SUN4M, SUN4D & LEON (comments) */
#define LOAD_CURRENT4M(dest_reg, idreg) \
rd %tbr, %idreg; \
sethi %hi(current_set), %dest_reg; \
@@ -118,6 +119,14 @@
or %dest_reg, %lo(C_LABEL(current_set)), %dest_reg; \
ld [%idreg + %dest_reg], %dest_reg;
+#define LOAD_CURRENT_LEON(dest_reg, idreg) \
+ rd %asr17, %idreg; \
+ sethi %hi(current_set), %dest_reg; \
+ srl %idreg, 0x1c, %idreg; \
+ or %dest_reg, %lo(current_set), %dest_reg; \
+ sll %idreg, 0x2, %idreg; \
+ ld [%idreg + %dest_reg], %dest_reg;
+
/* Blackbox - take care with this... - check smp4m and smp4d before changing this. */
#define LOAD_CURRENT(dest_reg, idreg) \
sethi %hi(___b_load_current), %idreg; \
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index 99aa4db6e9c2..9cff2709a96d 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -71,10 +71,6 @@ obj-$(CONFIG_SPARC64) += pcr.o
obj-$(CONFIG_SPARC64) += nmi.o
obj-$(CONFIG_SPARC64_SMP) += cpumap.o
-# sparc32 do not use GENERIC_HARDIRQS but uses the generic devres implementation
-obj-$(CONFIG_SPARC32) += devres.o
-devres-y := ../../../kernel/irq/devres.o
-
obj-y += dma.o
obj-$(CONFIG_SPARC32_PCI) += pcic.o
diff --git a/arch/sparc/kernel/cpu.c b/arch/sparc/kernel/cpu.c
index 7925c54f4133..138dbbc8dc84 100644
--- a/arch/sparc/kernel/cpu.c
+++ b/arch/sparc/kernel/cpu.c
@@ -4,6 +4,7 @@
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
*/
+#include <linux/seq_file.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -11,7 +12,9 @@
#include <linux/threads.h>
#include <asm/spitfire.h>
+#include <asm/pgtable.h>
#include <asm/oplib.h>
+#include <asm/setup.h>
#include <asm/page.h>
#include <asm/head.h>
#include <asm/psr.h>
@@ -23,6 +26,9 @@
DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 };
EXPORT_PER_CPU_SYMBOL(__cpu_data);
+int ncpus_probed;
+unsigned int fsr_storage;
+
struct cpu_info {
int psr_vers;
const char *name;
@@ -247,13 +253,12 @@ static const struct manufacturer_info __initconst manufacturer_info[] = {
* machine type value into consideration too. I will fix this.
*/
-const char *sparc_cpu_type;
-const char *sparc_fpu_type;
+static const char *sparc_cpu_type;
+static const char *sparc_fpu_type;
const char *sparc_pmu_type;
-unsigned int fsr_storage;
-static void set_cpu_and_fpu(int psr_impl, int psr_vers, int fpu_vers)
+static void __init set_cpu_and_fpu(int psr_impl, int psr_vers, int fpu_vers)
{
const struct manufacturer_info *manuf;
int i;
@@ -313,7 +318,123 @@ static void set_cpu_and_fpu(int psr_impl, int psr_vers, int fpu_vers)
}
#ifdef CONFIG_SPARC32
-void __cpuinit cpu_probe(void)
+static int show_cpuinfo(struct seq_file *m, void *__unused)
+{
+ seq_printf(m,
+ "cpu\t\t: %s\n"
+ "fpu\t\t: %s\n"
+ "promlib\t\t: Version %d Revision %d\n"
+ "prom\t\t: %d.%d\n"
+ "type\t\t: %s\n"
+ "ncpus probed\t: %d\n"
+ "ncpus active\t: %d\n"
+#ifndef CONFIG_SMP
+ "CPU0Bogo\t: %lu.%02lu\n"
+ "CPU0ClkTck\t: %ld\n"
+#endif
+ ,
+ sparc_cpu_type,
+ sparc_fpu_type ,
+ romvec->pv_romvers,
+ prom_rev,
+ romvec->pv_printrev >> 16,
+ romvec->pv_printrev & 0xffff,
+ &cputypval[0],
+ ncpus_probed,
+ num_online_cpus()
+#ifndef CONFIG_SMP
+ , cpu_data(0).udelay_val/(500000/HZ),
+ (cpu_data(0).udelay_val/(5000/HZ)) % 100,
+ cpu_data(0).clock_tick
+#endif
+ );
+
+#ifdef CONFIG_SMP
+ smp_bogo(m);
+#endif
+ mmu_info(m);
+#ifdef CONFIG_SMP
+ smp_info(m);
+#endif
+ return 0;
+}
+#endif /* CONFIG_SPARC32 */
+
+#ifdef CONFIG_SPARC64
+unsigned int dcache_parity_tl1_occurred;
+unsigned int icache_parity_tl1_occurred;
+
+
+static int show_cpuinfo(struct seq_file *m, void *__unused)
+{
+ seq_printf(m,
+ "cpu\t\t: %s\n"
+ "fpu\t\t: %s\n"
+ "pmu\t\t: %s\n"
+ "prom\t\t: %s\n"
+ "type\t\t: %s\n"
+ "ncpus probed\t: %d\n"
+ "ncpus active\t: %d\n"
+ "D$ parity tl1\t: %u\n"
+ "I$ parity tl1\t: %u\n"
+#ifndef CONFIG_SMP
+ "Cpu0ClkTck\t: %016lx\n"
+#endif
+ ,
+ sparc_cpu_type,
+ sparc_fpu_type,
+ sparc_pmu_type,
+ prom_version,
+ ((tlb_type == hypervisor) ?
+ "sun4v" :
+ "sun4u"),
+ ncpus_probed,
+ num_online_cpus(),
+ dcache_parity_tl1_occurred,
+ icache_parity_tl1_occurred
+#ifndef CONFIG_SMP
+ , cpu_data(0).clock_tick
+#endif
+ );
+#ifdef CONFIG_SMP
+ smp_bogo(m);
+#endif
+ mmu_info(m);
+#ifdef CONFIG_SMP
+ smp_info(m);
+#endif
+ return 0;
+}
+#endif /* CONFIG_SPARC64 */
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+ /* The pointer we are returning is arbitrary,
+ * it just has to be non-NULL and not IS_ERR
+ * in the success case.
+ */
+ return *pos == 0 ? &c_start : NULL;
+}
+
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ ++*pos;
+ return c_start(m, pos);
+}
+
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+
+const struct seq_operations cpuinfo_op = {
+ .start =c_start,
+ .next = c_next,
+ .stop = c_stop,
+ .show = show_cpuinfo,
+};
+
+#ifdef CONFIG_SPARC32
+static int __init cpu_type_probe(void)
{
int psr_impl, psr_vers, fpu_vers;
int psr;
@@ -332,8 +453,12 @@ void __cpuinit cpu_probe(void)
put_psr(psr);
set_cpu_and_fpu(psr_impl, psr_vers, fpu_vers);
+
+ return 0;
}
-#else
+#endif /* CONFIG_SPARC32 */
+
+#ifdef CONFIG_SPARC64
static void __init sun4v_cpu_probe(void)
{
switch (sun4v_chip_type) {
@@ -374,6 +499,6 @@ static int __init cpu_type_probe(void)
}
return 0;
}
+#endif /* CONFIG_SPARC64 */
early_initcall(cpu_type_probe);
-#endif
diff --git a/arch/sparc/kernel/cpumap.c b/arch/sparc/kernel/cpumap.c
index 8de64c8126bc..d91fd782743a 100644
--- a/arch/sparc/kernel/cpumap.c
+++ b/arch/sparc/kernel/cpumap.c
@@ -202,7 +202,7 @@ static struct cpuinfo_tree *build_cpuinfo_tree(void)
new_tree->total_nodes = n;
memcpy(&new_tree->level, tmp_level, sizeof(tmp_level));
- prev_cpu = cpu = first_cpu(cpu_online_map);
+ prev_cpu = cpu = cpumask_first(cpu_online_mask);
/* Initialize all levels in the tree with the first CPU */
for (level = CPUINFO_LVL_PROC; level >= CPUINFO_LVL_ROOT; level--) {
@@ -381,7 +381,7 @@ static int simple_map_to_cpu(unsigned int index)
}
/* Impossible, since num_online_cpus() <= num_possible_cpus() */
- return first_cpu(cpu_online_map);
+ return cpumask_first(cpu_online_mask);
}
static int _map_to_cpu(unsigned int index)
diff --git a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c
index d2eddd6647cd..113c052c3043 100644
--- a/arch/sparc/kernel/devices.c
+++ b/arch/sparc/kernel/devices.c
@@ -20,7 +20,6 @@
#include <asm/system.h>
#include <asm/cpudata.h>
-extern void cpu_probe(void);
extern void clock_stop_probe(void); /* tadpole.c */
extern void sun4c_probe_memerr_reg(void);
@@ -115,7 +114,7 @@ int cpu_get_hwmid(phandle prom_node)
void __init device_scan(void)
{
- prom_printf("Booting Linux...\n");
+ printk(KERN_NOTICE "Booting Linux...\n");
#ifndef CONFIG_SMP
{
@@ -133,7 +132,6 @@ void __init device_scan(void)
}
#endif /* !CONFIG_SMP */
- cpu_probe();
{
extern void auxio_probe(void);
extern void auxio_power_probe(void);
diff --git a/arch/sparc/kernel/ds.c b/arch/sparc/kernel/ds.c
index 3add4de8a1a9..dd1342c0a3be 100644
--- a/arch/sparc/kernel/ds.c
+++ b/arch/sparc/kernel/ds.c
@@ -497,7 +497,7 @@ static void dr_cpu_init_response(struct ds_data *resp, u64 req_num,
tag->num_records = ncpus;
i = 0;
- for_each_cpu_mask(cpu, *mask) {
+ for_each_cpu(cpu, mask) {
ent[i].cpu = cpu;
ent[i].result = DR_CPU_RES_OK;
ent[i].stat = default_stat;
@@ -534,7 +534,7 @@ static int __cpuinit dr_cpu_configure(struct ds_info *dp,
int resp_len, ncpus, cpu;
unsigned long flags;
- ncpus = cpus_weight(*mask);
+ ncpus = cpumask_weight(mask);
resp_len = dr_cpu_size_response(ncpus);
resp = kzalloc(resp_len, GFP_KERNEL);
if (!resp)
@@ -547,7 +547,7 @@ static int __cpuinit dr_cpu_configure(struct ds_info *dp,
mdesc_populate_present_mask(mask);
mdesc_fill_in_cpu_data(mask);
- for_each_cpu_mask(cpu, *mask) {
+ for_each_cpu(cpu, mask) {
int err;
printk(KERN_INFO "ds-%llu: Starting cpu %d...\n",
@@ -593,7 +593,7 @@ static int dr_cpu_unconfigure(struct ds_info *dp,
int resp_len, ncpus, cpu;
unsigned long flags;
- ncpus = cpus_weight(*mask);
+ ncpus = cpumask_weight(mask);
resp_len = dr_cpu_size_response(ncpus);
resp = kzalloc(resp_len, GFP_KERNEL);
if (!resp)
@@ -603,7 +603,7 @@ static int dr_cpu_unconfigure(struct ds_info *dp,
resp_len, ncpus, mask,
DR_CPU_STAT_UNCONFIGURED);
- for_each_cpu_mask(cpu, *mask) {
+ for_each_cpu(cpu, mask) {
int err;
printk(KERN_INFO "ds-%llu: Shutting down cpu %d...\n",
@@ -649,13 +649,13 @@ static void __cpuinit dr_cpu_data(struct ds_info *dp,
purge_dups(cpu_list, tag->num_records);
- cpus_clear(mask);
+ cpumask_clear(&mask);
for (i = 0; i < tag->num_records; i++) {
if (cpu_list[i] == CPU_SENTINEL)
continue;
if (cpu_list[i] < nr_cpu_ids)
- cpu_set(cpu_list[i], mask);
+ cpumask_set_cpu(cpu_list[i], &mask);
}
if (tag->type == DR_CPU_CONFIGURE)
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index 6da784a5612b..8341963f4c84 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -269,19 +269,22 @@ smp4m_ticker:
/* Here is where we check for possible SMP IPI passed to us
* on some level other than 15 which is the NMI and only used
* for cross calls. That has a separate entry point below.
+ *
+ * IPIs are sent on Level 12, 13 and 14. See IRQ_IPI_*.
*/
maybe_smp4m_msg:
GET_PROCESSOR4M_ID(o3)
sethi %hi(sun4m_irq_percpu), %l5
sll %o3, 2, %o3
or %l5, %lo(sun4m_irq_percpu), %o5
- sethi %hi(0x40000000), %o2
+ sethi %hi(0x70000000), %o2 ! Check all soft-IRQs
ld [%o5 + %o3], %o1
ld [%o1 + 0x00], %o3 ! sun4m_irq_percpu[cpu]->pending
andcc %o3, %o2, %g0
be,a smp4m_ticker
cmp %l7, 14
- st %o2, [%o1 + 0x04] ! sun4m_irq_percpu[cpu]->clear=0x40000000
+ /* Soft-IRQ IPI */
+ st %o2, [%o1 + 0x04] ! sun4m_irq_percpu[cpu]->clear=0x70000000
WRITE_PAUSE
ld [%o1 + 0x00], %g0 ! sun4m_irq_percpu[cpu]->pending
WRITE_PAUSE
@@ -290,9 +293,27 @@ maybe_smp4m_msg:
WRITE_PAUSE
wr %l4, PSR_ET, %psr
WRITE_PAUSE
- call smp_reschedule_irq
+ sll %o2, 28, %o2 ! shift for simpler checks below
+maybe_smp4m_msg_check_single:
+ andcc %o2, 0x1, %g0
+ beq,a maybe_smp4m_msg_check_mask
+ andcc %o2, 0x2, %g0
+ call smp_call_function_single_interrupt
nop
-
+ andcc %o2, 0x2, %g0
+maybe_smp4m_msg_check_mask:
+ beq,a maybe_smp4m_msg_check_resched
+ andcc %o2, 0x4, %g0
+ call smp_call_function_interrupt
+ nop
+ andcc %o2, 0x4, %g0
+maybe_smp4m_msg_check_resched:
+ /* rescheduling is done in RESTORE_ALL regardless, but incr stats */
+ beq,a maybe_smp4m_msg_out
+ nop
+ call smp_resched_interrupt
+ nop
+maybe_smp4m_msg_out:
RESTORE_ALL
.align 4
@@ -401,18 +422,18 @@ linux_trap_ipi15_sun4d:
1: b,a 1b
#ifdef CONFIG_SPARC_LEON
-
- .globl smpleon_ticker
- /* SMP per-cpu ticker interrupts are handled specially. */
-smpleon_ticker:
+ .globl smpleon_ipi
+ .extern leon_ipi_interrupt
+ /* SMP per-cpu IPI interrupts are handled specially. */
+smpleon_ipi:
SAVE_ALL
or %l0, PSR_PIL, %g2
wr %g2, 0x0, %psr
WRITE_PAUSE
wr %g2, PSR_ET, %psr
WRITE_PAUSE
- call leon_percpu_timer_interrupt
- add %sp, STACKFRAME_SZ, %o0
+ call leonsmp_ipi_interrupt
+ add %sp, STACKFRAME_SZ, %o1 ! pt_regs
wr %l0, PSR_ET, %psr
WRITE_PAUSE
RESTORE_ALL
diff --git a/arch/sparc/kernel/head_32.S b/arch/sparc/kernel/head_32.S
index 59423491cef8..587785759838 100644
--- a/arch/sparc/kernel/head_32.S
+++ b/arch/sparc/kernel/head_32.S
@@ -810,31 +810,25 @@ found_version:
got_prop:
#ifdef CONFIG_SPARC_LEON
/* no cpu-type check is needed, it is a SPARC-LEON */
-#ifdef CONFIG_SMP
- ba leon_smp_init
- nop
- .global leon_smp_init
-leon_smp_init:
- sethi %hi(boot_cpu_id), %g1 ! master always 0
- stb %g0, [%g1 + %lo(boot_cpu_id)]
- sethi %hi(boot_cpu_id4), %g1 ! master always 0
- stb %g0, [%g1 + %lo(boot_cpu_id4)]
+ sethi %hi(boot_cpu_id), %g2 ! boot-cpu index
- rd %asr17,%g1
- srl %g1,28,%g1
+#ifdef CONFIG_SMP
+ ldub [%g2 + %lo(boot_cpu_id)], %g1
+ cmp %g1, 0xff ! unset means first CPU
+ bne leon_smp_cpu_startup ! continue only with master
+ nop
+#endif
+ /* Get CPU-ID from most significant 4-bit of ASR17 */
+ rd %asr17, %g1
+ srl %g1, 28, %g1
- cmp %g0,%g1
- beq sun4c_continue_boot !continue with master
- nop
+ /* Update boot_cpu_id only on boot cpu */
+ stub %g1, [%g2 + %lo(boot_cpu_id)]
- ba leon_smp_cpu_startup
- nop
-#else
ba sun4c_continue_boot
nop
#endif
-#endif
set cputypval, %o2
ldub [%o2 + 0x4], %l1
@@ -893,9 +887,6 @@ sun4d_init:
sta %g4, [%g0] ASI_M_VIKING_TMP1
sethi %hi(boot_cpu_id), %g5
stb %g4, [%g5 + %lo(boot_cpu_id)]
- sll %g4, 2, %g4
- sethi %hi(boot_cpu_id4), %g5
- stb %g4, [%g5 + %lo(boot_cpu_id4)]
#endif
/* Fall through to sun4m_init */
@@ -1024,14 +1015,28 @@ sun4c_continue_boot:
bl 1b
add %o0, 0x1, %o0
+ /* If boot_cpu_id has not been setup by machine specific
+ * init-code above we default it to zero.
+ */
+ sethi %hi(boot_cpu_id), %g2
+ ldub [%g2 + %lo(boot_cpu_id)], %g3
+ cmp %g3, 0xff
+ bne 1f
+ nop
+ mov %g0, %g3
+ stub %g3, [%g2 + %lo(boot_cpu_id)]
+
+1: /* boot_cpu_id set. calculate boot_cpu_id4 = boot_cpu_id*4 */
+ sll %g3, 2, %g3
+ sethi %hi(boot_cpu_id4), %g2
+ stub %g3, [%g2 + %lo(boot_cpu_id4)]
+
/* Initialize the uwinmask value for init task just in case.
* But first make current_set[boot_cpu_id] point to something useful.
*/
set init_thread_union, %g6
set current_set, %g2
#ifdef CONFIG_SMP
- sethi %hi(boot_cpu_id4), %g3
- ldub [%g3 + %lo(boot_cpu_id4)], %g3
st %g6, [%g2]
add %g2, %g3, %g2
#endif
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index c6ce9a6a4790..1c9c80a1a86a 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -50,10 +50,15 @@
#include <asm/io-unit.h>
#include <asm/leon.h>
+/* This function must make sure that caches and memory are coherent after DMA
+ * On LEON systems without cache snooping it flushes the entire D-CACHE.
+ */
#ifndef CONFIG_SPARC_LEON
-#define mmu_inval_dma_area(p, l) /* Anton pulled it out for 2.4.0-xx */
+static inline void dma_make_coherent(unsigned long pa, unsigned long len)
+{
+}
#else
-static inline void mmu_inval_dma_area(void *va, unsigned long len)
+static inline void dma_make_coherent(unsigned long pa, unsigned long len)
{
if (!sparc_leon3_snooping_enabled())
leon_flush_dcache_all();
@@ -284,7 +289,6 @@ static void *sbus_alloc_coherent(struct device *dev, size_t len,
printk("sbus_alloc_consistent: cannot occupy 0x%lx", len_total);
goto err_nova;
}
- mmu_inval_dma_area((void *)va, len_total);
// XXX The mmu_map_dma_area does this for us below, see comments.
// sparc_mapiorange(0, virt_to_phys(va), res->start, len_total);
@@ -336,7 +340,6 @@ static void sbus_free_coherent(struct device *dev, size_t n, void *p,
release_resource(res);
kfree(res);
- /* mmu_inval_dma_area(va, n); */ /* it's consistent, isn't it */
pgv = virt_to_page(p);
mmu_unmap_dma_area(dev, ba, n);
@@ -463,7 +466,6 @@ static void *pci32_alloc_coherent(struct device *dev, size_t len,
printk("pci_alloc_consistent: cannot occupy 0x%lx", len_total);
goto err_nova;
}
- mmu_inval_dma_area(va, len_total);
sparc_mapiorange(0, virt_to_phys(va), res->start, len_total);
*pba = virt_to_phys(va); /* equals virt_to_bus (R.I.P.) for us. */
@@ -489,7 +491,6 @@ static void pci32_free_coherent(struct device *dev, size_t n, void *p,
dma_addr_t ba)
{
struct resource *res;
- void *pgp;
if ((res = _sparc_find_resource(&_sparc_dvma,
(unsigned long)p)) == NULL) {
@@ -509,14 +510,12 @@ static void pci32_free_coherent(struct device *dev, size_t n, void *p,
return;
}
- pgp = phys_to_virt(ba); /* bus_to_virt actually */
- mmu_inval_dma_area(pgp, n);
+ dma_make_coherent(ba, n);
sparc_unmapiorange((unsigned long)p, n);
release_resource(res);
kfree(res);
-
- free_pages((unsigned long)pgp, get_order(n));
+ free_pages((unsigned long)phys_to_virt(ba), get_order(n));
}
/*
@@ -535,7 +534,7 @@ static void pci32_unmap_page(struct device *dev, dma_addr_t ba, size_t size,
enum dma_data_direction dir, struct dma_attrs *attrs)
{
if (dir != PCI_DMA_TODEVICE)
- mmu_inval_dma_area(phys_to_virt(ba), PAGE_ALIGN(size));
+ dma_make_coherent(ba, PAGE_ALIGN(size));
}
/* Map a set of buffers described by scatterlist in streaming
@@ -562,8 +561,7 @@ static int pci32_map_sg(struct device *device, struct scatterlist *sgl,
/* IIep is write-through, not flushing. */
for_each_sg(sgl, sg, nents, n) {
- BUG_ON(page_address(sg_page(sg)) == NULL);
- sg->dma_address = virt_to_phys(sg_virt(sg));
+ sg->dma_address = sg_phys(sg);
sg->dma_length = sg->length;
}
return nents;
@@ -582,9 +580,7 @@ static void pci32_unmap_sg(struct device *dev, struct scatterlist *sgl,
if (dir != PCI_DMA_TODEVICE) {
for_each_sg(sgl, sg, nents, n) {
- BUG_ON(page_address(sg_page(sg)) == NULL);
- mmu_inval_dma_area(page_address(sg_page(sg)),
- PAGE_ALIGN(sg->length));
+ dma_make_coherent(sg_phys(sg), PAGE_ALIGN(sg->length));
}
}
}
@@ -603,8 +599,7 @@ static void pci32_sync_single_for_cpu(struct device *dev, dma_addr_t ba,
size_t size, enum dma_data_direction dir)
{
if (dir != PCI_DMA_TODEVICE) {
- mmu_inval_dma_area(phys_to_virt(ba),
- PAGE_ALIGN(size));
+ dma_make_coherent(ba, PAGE_ALIGN(size));
}
}
@@ -612,8 +607,7 @@ static void pci32_sync_single_for_device(struct device *dev, dma_addr_t ba,
size_t size, enum dma_data_direction dir)
{
if (dir != PCI_DMA_TODEVICE) {
- mmu_inval_dma_area(phys_to_virt(ba),
- PAGE_ALIGN(size));
+ dma_make_coherent(ba, PAGE_ALIGN(size));
}
}
@@ -631,9 +625,7 @@ static void pci32_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl,
if (dir != PCI_DMA_TODEVICE) {
for_each_sg(sgl, sg, nents, n) {
- BUG_ON(page_address(sg_page(sg)) == NULL);
- mmu_inval_dma_area(page_address(sg_page(sg)),
- PAGE_ALIGN(sg->length));
+ dma_make_coherent(sg_phys(sg), PAGE_ALIGN(sg->length));
}
}
}
@@ -646,9 +638,7 @@ static void pci32_sync_sg_for_device(struct device *device, struct scatterlist *
if (dir != PCI_DMA_TODEVICE) {
for_each_sg(sgl, sg, nents, n) {
- BUG_ON(page_address(sg_page(sg)) == NULL);
- mmu_inval_dma_area(page_address(sg_page(sg)),
- PAGE_ALIGN(sg->length));
+ dma_make_coherent(sg_phys(sg), PAGE_ALIGN(sg->length));
}
}
}
diff --git a/arch/sparc/kernel/irq.h b/arch/sparc/kernel/irq.h
index 008453b798ec..100b9c204e78 100644
--- a/arch/sparc/kernel/irq.h
+++ b/arch/sparc/kernel/irq.h
@@ -2,6 +2,23 @@
#include <asm/btfixup.h>
+struct irq_bucket {
+ struct irq_bucket *next;
+ unsigned int real_irq;
+ unsigned int irq;
+ unsigned int pil;
+};
+
+#define SUN4D_MAX_BOARD 10
+#define SUN4D_MAX_IRQ ((SUN4D_MAX_BOARD + 2) << 5)
+
+/* Map between the irq identifier used in hw to the
+ * irq_bucket. The map is sufficient large to hold
+ * the sun4d hw identifiers.
+ */
+extern struct irq_bucket *irq_map[SUN4D_MAX_IRQ];
+
+
/* sun4m specific type definitions */
/* This maps direct to CPU specific interrupt registers */
@@ -35,6 +52,10 @@ struct sparc_irq_config {
};
extern struct sparc_irq_config sparc_irq_config;
+unsigned int irq_alloc(unsigned int real_irq, unsigned int pil);
+void irq_link(unsigned int irq);
+void irq_unlink(unsigned int irq);
+void handler_irq(unsigned int pil, struct pt_regs *regs);
/* Dave Redman (djhr@tadpole.co.uk)
* changed these to function pointers.. it saves cycles and will allow
@@ -44,33 +65,9 @@ extern struct sparc_irq_config sparc_irq_config;
* Changed these to btfixup entities... It saves cycles :)
*/
-BTFIXUPDEF_CALL(void, disable_irq, unsigned int)
-BTFIXUPDEF_CALL(void, enable_irq, unsigned int)
-BTFIXUPDEF_CALL(void, disable_pil_irq, unsigned int)
-BTFIXUPDEF_CALL(void, enable_pil_irq, unsigned int)
BTFIXUPDEF_CALL(void, clear_clock_irq, void)
BTFIXUPDEF_CALL(void, load_profile_irq, int, unsigned int)
-static inline void __disable_irq(unsigned int irq)
-{
- BTFIXUP_CALL(disable_irq)(irq);
-}
-
-static inline void __enable_irq(unsigned int irq)
-{
- BTFIXUP_CALL(enable_irq)(irq);
-}
-
-static inline void disable_pil_irq(unsigned int irq)
-{
- BTFIXUP_CALL(disable_pil_irq)(irq);
-}
-
-static inline void enable_pil_irq(unsigned int irq)
-{
- BTFIXUP_CALL(enable_pil_irq)(irq);
-}
-
static inline void clear_clock_irq(void)
{
BTFIXUP_CALL(clear_clock_irq)();
@@ -89,4 +86,10 @@ BTFIXUPDEF_CALL(void, set_irq_udt, int)
#define set_cpu_int(cpu,level) BTFIXUP_CALL(set_cpu_int)(cpu,level)
#define clear_cpu_int(cpu,level) BTFIXUP_CALL(clear_cpu_int)(cpu,level)
#define set_irq_udt(cpu) BTFIXUP_CALL(set_irq_udt)(cpu)
+
+/* All SUN4D IPIs are sent on this IRQ, may be shared with hard IRQs */
+#define SUN4D_IPI_IRQ 14
+
+extern void sun4d_ipi_interrupt(void);
+
#endif
diff --git a/arch/sparc/kernel/irq_32.c b/arch/sparc/kernel/irq_32.c
index 7c93df4099cb..9b89d842913c 100644
--- a/arch/sparc/kernel/irq_32.c
+++ b/arch/sparc/kernel/irq_32.c
@@ -15,6 +15,7 @@
#include <linux/seq_file.h>
#include <asm/cacheflush.h>
+#include <asm/cpudata.h>
#include <asm/pcic.h>
#include <asm/leon.h>
@@ -101,284 +102,173 @@ EXPORT_SYMBOL(arch_local_irq_restore);
* directed CPU interrupts using the existing enable/disable irq code
* with tweaks.
*
+ * Sun4d complicates things even further. IRQ numbers are arbitrary
+ * 32-bit values in that case. Since this is similar to sparc64,
+ * we adopt a virtual IRQ numbering scheme as is done there.
+ * Virutal interrupt numbers are allocated by build_irq(). So NR_IRQS
+ * just becomes a limit of how many interrupt sources we can handle in
+ * a single system. Even fully loaded SS2000 machines top off at
+ * about 32 interrupt sources or so, therefore a NR_IRQS value of 64
+ * is more than enough.
+ *
+ * We keep a map of per-PIL enable interrupts. These get wired
+ * up via the irq_chip->startup() method which gets invoked by
+ * the generic IRQ layer during request_irq().
*/
+/* Table of allocated irqs. Unused entries has irq == 0 */
+static struct irq_bucket irq_table[NR_IRQS];
+/* Protect access to irq_table */
+static DEFINE_SPINLOCK(irq_table_lock);
-/*
- * Dave Redman (djhr@tadpole.co.uk)
- *
- * There used to be extern calls and hard coded values here.. very sucky!
- * instead, because some of the devices attach very early, I do something
- * equally sucky but at least we'll never try to free statically allocated
- * space or call kmalloc before kmalloc_init :(.
- *
- * In fact it's the timer10 that attaches first.. then timer14
- * then kmalloc_init is called.. then the tty interrupts attach.
- * hmmm....
- *
- */
-#define MAX_STATIC_ALLOC 4
-struct irqaction static_irqaction[MAX_STATIC_ALLOC];
-int static_irq_count;
-
-static struct {
- struct irqaction *action;
- int flags;
-} sparc_irq[NR_IRQS];
-#define SPARC_IRQ_INPROGRESS 1
-
-/* Used to protect the IRQ action lists */
-DEFINE_SPINLOCK(irq_action_lock);
+/* Map between the irq identifier used in hw to the irq_bucket. */
+struct irq_bucket *irq_map[SUN4D_MAX_IRQ];
+/* Protect access to irq_map */
+static DEFINE_SPINLOCK(irq_map_lock);
-int show_interrupts(struct seq_file *p, void *v)
+/* Allocate a new irq from the irq_table */
+unsigned int irq_alloc(unsigned int real_irq, unsigned int pil)
{
- int i = *(loff_t *)v;
- struct irqaction *action;
unsigned long flags;
-#ifdef CONFIG_SMP
- int j;
-#endif
+ unsigned int i;
+
+ spin_lock_irqsave(&irq_table_lock, flags);
+ for (i = 1; i < NR_IRQS; i++) {
+ if (irq_table[i].real_irq == real_irq && irq_table[i].pil == pil)
+ goto found;
+ }
- if (sparc_cpu_model == sun4d)
- return show_sun4d_interrupts(p, v);
+ for (i = 1; i < NR_IRQS; i++) {
+ if (!irq_table[i].irq)
+ break;
+ }
- spin_lock_irqsave(&irq_action_lock, flags);
if (i < NR_IRQS) {
- action = sparc_irq[i].action;
- if (!action)
- goto out_unlock;
- seq_printf(p, "%3d: ", i);
-#ifndef CONFIG_SMP
- seq_printf(p, "%10u ", kstat_irqs(i));
-#else
- for_each_online_cpu(j) {
- seq_printf(p, "%10u ",
- kstat_cpu(j).irqs[i]);
- }
-#endif
- seq_printf(p, " %c %s",
- (action->flags & IRQF_DISABLED) ? '+' : ' ',
- action->name);
- for (action = action->next; action; action = action->next) {
- seq_printf(p, ",%s %s",
- (action->flags & IRQF_DISABLED) ? " +" : "",
- action->name);
- }
- seq_putc(p, '\n');
+ irq_table[i].real_irq = real_irq;
+ irq_table[i].irq = i;
+ irq_table[i].pil = pil;
+ } else {
+ printk(KERN_ERR "IRQ: Out of virtual IRQs.\n");
+ i = 0;
}
-out_unlock:
- spin_unlock_irqrestore(&irq_action_lock, flags);
- return 0;
+found:
+ spin_unlock_irqrestore(&irq_table_lock, flags);
+
+ return i;
}
-void free_irq(unsigned int irq, void *dev_id)
+/* Based on a single pil handler_irq may need to call several
+ * interrupt handlers. Use irq_map as entry to irq_table,
+ * and let each entry in irq_table point to the next entry.
+ */
+void irq_link(unsigned int irq)
{
- struct irqaction *action;
- struct irqaction **actionp;
+ struct irq_bucket *p;
unsigned long flags;
- unsigned int cpu_irq;
-
- if (sparc_cpu_model == sun4d) {
- sun4d_free_irq(irq, dev_id);
- return;
- }
- cpu_irq = irq & (NR_IRQS - 1);
- if (cpu_irq > 14) { /* 14 irq levels on the sparc */
- printk(KERN_ERR "Trying to free bogus IRQ %d\n", irq);
- return;
- }
+ unsigned int pil;
- spin_lock_irqsave(&irq_action_lock, flags);
+ BUG_ON(irq >= NR_IRQS);
- actionp = &sparc_irq[cpu_irq].action;
- action = *actionp;
+ spin_lock_irqsave(&irq_map_lock, flags);
- if (!action->handler) {
- printk(KERN_ERR "Trying to free free IRQ%d\n", irq);
- goto out_unlock;
- }
- if (dev_id) {
- for (; action; action = action->next) {
- if (action->dev_id == dev_id)
- break;
- actionp = &action->next;
- }
- if (!action) {
- printk(KERN_ERR "Trying to free free shared IRQ%d\n",
- irq);
- goto out_unlock;
- }
- } else if (action->flags & IRQF_SHARED) {
- printk(KERN_ERR "Trying to free shared IRQ%d with NULL device ID\n",
- irq);
- goto out_unlock;
- }
- if (action->flags & SA_STATIC_ALLOC) {
- /*
- * This interrupt is marked as specially allocated
- * so it is a bad idea to free it.
- */
- printk(KERN_ERR "Attempt to free statically allocated IRQ%d (%s)\n",
- irq, action->name);
- goto out_unlock;
- }
-
- *actionp = action->next;
+ p = &irq_table[irq];
+ pil = p->pil;
+ BUG_ON(pil > SUN4D_MAX_IRQ);
+ p->next = irq_map[pil];
+ irq_map[pil] = p;
- spin_unlock_irqrestore(&irq_action_lock, flags);
+ spin_unlock_irqrestore(&irq_map_lock, flags);
+}
- synchronize_irq(irq);
+void irq_unlink(unsigned int irq)
+{
+ struct irq_bucket *p, **pnext;
+ unsigned long flags;
- spin_lock_irqsave(&irq_action_lock, flags);
+ BUG_ON(irq >= NR_IRQS);
- kfree(action);
+ spin_lock_irqsave(&irq_map_lock, flags);
- if (!sparc_irq[cpu_irq].action)
- __disable_irq(irq);
+ p = &irq_table[irq];
+ BUG_ON(p->pil > SUN4D_MAX_IRQ);
+ pnext = &irq_map[p->pil];
+ while (*pnext != p)
+ pnext = &(*pnext)->next;
+ *pnext = p->next;
-out_unlock:
- spin_unlock_irqrestore(&irq_action_lock, flags);
+ spin_unlock_irqrestore(&irq_map_lock, flags);
}
-EXPORT_SYMBOL(free_irq);
-
-/*
- * This is called when we want to synchronize with
- * interrupts. We may for example tell a device to
- * stop sending interrupts: but to make sure there
- * are no interrupts that are executing on another
- * CPU we need to call this function.
- */
-#ifdef CONFIG_SMP
-void synchronize_irq(unsigned int irq)
-{
- unsigned int cpu_irq;
- cpu_irq = irq & (NR_IRQS - 1);
- while (sparc_irq[cpu_irq].flags & SPARC_IRQ_INPROGRESS)
- cpu_relax();
-}
-EXPORT_SYMBOL(synchronize_irq);
-#endif /* SMP */
-void unexpected_irq(int irq, void *dev_id, struct pt_regs *regs)
+/* /proc/interrupts printing */
+int arch_show_interrupts(struct seq_file *p, int prec)
{
- int i;
- struct irqaction *action;
- unsigned int cpu_irq;
+ int j;
- cpu_irq = irq & (NR_IRQS - 1);
- action = sparc_irq[cpu_irq].action;
-
- printk(KERN_ERR "IO device interrupt, irq = %d\n", irq);
- printk(KERN_ERR "PC = %08lx NPC = %08lx FP=%08lx\n", regs->pc,
- regs->npc, regs->u_regs[14]);
- if (action) {
- printk(KERN_ERR "Expecting: ");
- for (i = 0; i < 16; i++)
- if (action->handler)
- printk(KERN_CONT "[%s:%d:0x%x] ", action->name,
- i, (unsigned int)action->handler);
- }
- printk(KERN_ERR "AIEEE\n");
- panic("bogus interrupt received");
+#ifdef CONFIG_SMP
+ seq_printf(p, "RES: ");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", cpu_data(j).irq_resched_count);
+ seq_printf(p, " IPI rescheduling interrupts\n");
+ seq_printf(p, "CAL: ");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", cpu_data(j).irq_call_count);
+ seq_printf(p, " IPI function call interrupts\n");
+#endif
+ seq_printf(p, "NMI: ");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", cpu_data(j).counter);
+ seq_printf(p, " Non-maskable interrupts\n");
+ return 0;
}
-void handler_irq(int pil, struct pt_regs *regs)
+void handler_irq(unsigned int pil, struct pt_regs *regs)
{
struct pt_regs *old_regs;
- struct irqaction *action;
- int cpu = smp_processor_id();
+ struct irq_bucket *p;
+ BUG_ON(pil > 15);
old_regs = set_irq_regs(regs);
irq_enter();
- disable_pil_irq(pil);
-#ifdef CONFIG_SMP
- /* Only rotate on lower priority IRQs (scsi, ethernet, etc.). */
- if ((sparc_cpu_model==sun4m) && (pil < 10))
- smp4m_irq_rotate(cpu);
-#endif
- action = sparc_irq[pil].action;
- sparc_irq[pil].flags |= SPARC_IRQ_INPROGRESS;
- kstat_cpu(cpu).irqs[pil]++;
- do {
- if (!action || !action->handler)
- unexpected_irq(pil, NULL, regs);
- action->handler(pil, action->dev_id);
- action = action->next;
- } while (action);
- sparc_irq[pil].flags &= ~SPARC_IRQ_INPROGRESS;
- enable_pil_irq(pil);
+
+ p = irq_map[pil];
+ while (p) {
+ struct irq_bucket *next = p->next;
+
+ generic_handle_irq(p->irq);
+ p = next;
+ }
irq_exit();
set_irq_regs(old_regs);
}
#if defined(CONFIG_BLK_DEV_FD) || defined(CONFIG_BLK_DEV_FD_MODULE)
+static unsigned int floppy_irq;
-/*
- * Fast IRQs on the Sparc can only have one routine attached to them,
- * thus no sharing possible.
- */
-static int request_fast_irq(unsigned int irq,
- void (*handler)(void),
- unsigned long irqflags, const char *devname)
+int sparc_floppy_request_irq(unsigned int irq, irq_handler_t irq_handler)
{
- struct irqaction *action;
- unsigned long flags;
unsigned int cpu_irq;
- int ret;
+ int err;
+
#if defined CONFIG_SMP && !defined CONFIG_SPARC_LEON
struct tt_entry *trap_table;
#endif
- cpu_irq = irq & (NR_IRQS - 1);
- if (cpu_irq > 14) {
- ret = -EINVAL;
- goto out;
- }
- if (!handler) {
- ret = -EINVAL;
- goto out;
- }
- spin_lock_irqsave(&irq_action_lock, flags);
+ err = request_irq(irq, irq_handler, 0, "floppy", NULL);
+ if (err)
+ return -1;
- action = sparc_irq[cpu_irq].action;
- if (action) {
- if (action->flags & IRQF_SHARED)
- panic("Trying to register fast irq when already shared.\n");
- if (irqflags & IRQF_SHARED)
- panic("Trying to register fast irq as shared.\n");
+ /* Save for later use in floppy interrupt handler */
+ floppy_irq = irq;
- /* Anyway, someone already owns it so cannot be made fast. */
- printk(KERN_ERR "request_fast_irq: Trying to register yet already owned.\n");
- ret = -EBUSY;
- goto out_unlock;
- }
-
- /*
- * If this is flagged as statically allocated then we use our
- * private struct which is never freed.
- */
- if (irqflags & SA_STATIC_ALLOC) {
- if (static_irq_count < MAX_STATIC_ALLOC)
- action = &static_irqaction[static_irq_count++];
- else
- printk(KERN_ERR "Fast IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",
- irq, devname);
- }
-
- if (action == NULL)
- action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);
- if (!action) {
- ret = -ENOMEM;
- goto out_unlock;
- }
+ cpu_irq = (irq & (NR_IRQS - 1));
/* Dork with trap table if we get this far. */
#define INSTANTIATE(table) \
table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_one = SPARC_RD_PSR_L0; \
table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_two = \
- SPARC_BRANCH((unsigned long) handler, \
+ SPARC_BRANCH((unsigned long) floppy_hardint, \
(unsigned long) &table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_two);\
table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_three = SPARC_RD_WIM_L3; \
table[SP_TRAP_IRQ1+(cpu_irq-1)].inst_four = SPARC_NOP;
@@ -399,22 +289,9 @@ static int request_fast_irq(unsigned int irq,
* writing we have no CPU-neutral interface to fine-grained flushes.
*/
flush_cache_all();
-
- action->flags = irqflags;
- action->name = devname;
- action->dev_id = NULL;
- action->next = NULL;
-
- sparc_irq[cpu_irq].action = action;
-
- __enable_irq(irq);
-
- ret = 0;
-out_unlock:
- spin_unlock_irqrestore(&irq_action_lock, flags);
-out:
- return ret;
+ return 0;
}
+EXPORT_SYMBOL(sparc_floppy_request_irq);
/*
* These variables are used to access state from the assembler
@@ -440,154 +317,23 @@ EXPORT_SYMBOL(pdma_base);
unsigned long pdma_areasize;
EXPORT_SYMBOL(pdma_areasize);
-static irq_handler_t floppy_irq_handler;
-
+/* Use the generic irq support to call floppy_interrupt
+ * which was setup using request_irq() in sparc_floppy_request_irq().
+ * We only have one floppy interrupt so we do not need to check
+ * for additional handlers being wired up by irq_link()
+ */
void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs)
{
struct pt_regs *old_regs;
- int cpu = smp_processor_id();
old_regs = set_irq_regs(regs);
- disable_pil_irq(irq);
irq_enter();
- kstat_cpu(cpu).irqs[irq]++;
- floppy_irq_handler(irq, dev_id);
+ generic_handle_irq(floppy_irq);
irq_exit();
- enable_pil_irq(irq);
set_irq_regs(old_regs);
- /*
- * XXX Eek, it's totally changed with preempt_count() and such
- * if (softirq_pending(cpu))
- * do_softirq();
- */
-}
-
-int sparc_floppy_request_irq(int irq, unsigned long flags,
- irq_handler_t irq_handler)
-{
- floppy_irq_handler = irq_handler;
- return request_fast_irq(irq, floppy_hardint, flags, "floppy");
}
-EXPORT_SYMBOL(sparc_floppy_request_irq);
-
#endif
-int request_irq(unsigned int irq,
- irq_handler_t handler,
- unsigned long irqflags, const char *devname, void *dev_id)
-{
- struct irqaction *action, **actionp;
- unsigned long flags;
- unsigned int cpu_irq;
- int ret;
-
- if (sparc_cpu_model == sun4d)
- return sun4d_request_irq(irq, handler, irqflags, devname, dev_id);
-
- cpu_irq = irq & (NR_IRQS - 1);
- if (cpu_irq > 14) {
- ret = -EINVAL;
- goto out;
- }
- if (!handler) {
- ret = -EINVAL;
- goto out;
- }
-
- spin_lock_irqsave(&irq_action_lock, flags);
-
- actionp = &sparc_irq[cpu_irq].action;
- action = *actionp;
- if (action) {
- if (!(action->flags & IRQF_SHARED) || !(irqflags & IRQF_SHARED)) {
- ret = -EBUSY;
- goto out_unlock;
- }
- if ((action->flags & IRQF_DISABLED) != (irqflags & IRQF_DISABLED)) {
- printk(KERN_ERR "Attempt to mix fast and slow interrupts on IRQ%d denied\n",
- irq);
- ret = -EBUSY;
- goto out_unlock;
- }
- for ( ; action; action = *actionp)
- actionp = &action->next;
- }
-
- /* If this is flagged as statically allocated then we use our
- * private struct which is never freed.
- */
- if (irqflags & SA_STATIC_ALLOC) {
- if (static_irq_count < MAX_STATIC_ALLOC)
- action = &static_irqaction[static_irq_count++];
- else
- printk(KERN_ERR "Request for IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",
- irq, devname);
- }
- if (action == NULL)
- action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);
- if (!action) {
- ret = -ENOMEM;
- goto out_unlock;
- }
-
- action->handler = handler;
- action->flags = irqflags;
- action->name = devname;
- action->next = NULL;
- action->dev_id = dev_id;
-
- *actionp = action;
-
- __enable_irq(irq);
-
- ret = 0;
-out_unlock:
- spin_unlock_irqrestore(&irq_action_lock, flags);
-out:
- return ret;
-}
-EXPORT_SYMBOL(request_irq);
-
-void disable_irq_nosync(unsigned int irq)
-{
- __disable_irq(irq);
-}
-EXPORT_SYMBOL(disable_irq_nosync);
-
-void disable_irq(unsigned int irq)
-{
- __disable_irq(irq);
-}
-EXPORT_SYMBOL(disable_irq);
-
-void enable_irq(unsigned int irq)
-{
- __enable_irq(irq);
-}
-EXPORT_SYMBOL(enable_irq);
-
-/*
- * We really don't need these at all on the Sparc. We only have
- * stubs here because they are exported to modules.
- */
-unsigned long probe_irq_on(void)
-{
- return 0;
-}
-EXPORT_SYMBOL(probe_irq_on);
-
-int probe_irq_off(unsigned long mask)
-{
- return 0;
-}
-EXPORT_SYMBOL(probe_irq_off);
-
-static unsigned int build_device_irq(struct platform_device *op,
- unsigned int real_irq)
-{
- return real_irq;
-}
-
/* djhr
* This could probably be made indirect too and assigned in the CPU
* bits of the code. That would be much nicer I think and would also
@@ -598,8 +344,6 @@ static unsigned int build_device_irq(struct platform_device *op,
void __init init_IRQ(void)
{
- sparc_irq_config.build_device_irq = build_device_irq;
-
switch (sparc_cpu_model) {
case sun4c:
case sun4:
@@ -607,14 +351,11 @@ void __init init_IRQ(void)
break;
case sun4m:
-#ifdef CONFIG_PCI
pcic_probe();
- if (pcic_present()) {
+ if (pcic_present())
sun4m_pci_init_IRQ();
- break;
- }
-#endif
- sun4m_init_IRQ();
+ else
+ sun4m_init_IRQ();
break;
case sun4d:
@@ -632,9 +373,3 @@ void __init init_IRQ(void)
btfixup();
}
-#ifdef CONFIG_PROC_FS
-void init_irq_proc(void)
-{
- /* For now, nothing... */
-}
-#endif /* CONFIG_PROC_FS */
diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c
index b1d275ce3435..4e78862d12fd 100644
--- a/arch/sparc/kernel/irq_64.c
+++ b/arch/sparc/kernel/irq_64.c
@@ -224,13 +224,13 @@ static int irq_choose_cpu(unsigned int irq, const struct cpumask *affinity)
int cpuid;
cpumask_copy(&mask, affinity);
- if (cpus_equal(mask, cpu_online_map)) {
+ if (cpumask_equal(&mask, cpu_online_mask)) {
cpuid = map_to_cpu(irq);
} else {
cpumask_t tmp;
- cpus_and(tmp, cpu_online_map, mask);
- cpuid = cpus_empty(tmp) ? map_to_cpu(irq) : first_cpu(tmp);
+ cpumask_and(&tmp, cpu_online_mask, &mask);
+ cpuid = cpumask_empty(&tmp) ? map_to_cpu(irq) : cpumask_first(&tmp);
}
return cpuid;
diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h
index 24ad449886be..6f6544cfa0ef 100644
--- a/arch/sparc/kernel/kernel.h
+++ b/arch/sparc/kernel/kernel.h
@@ -6,11 +6,9 @@
#include <asm/traps.h>
/* cpu.c */
-extern const char *sparc_cpu_type;
extern const char *sparc_pmu_type;
-extern const char *sparc_fpu_type;
-
extern unsigned int fsr_storage;
+extern int ncpus_probed;
#ifdef CONFIG_SPARC32
/* cpu.c */
@@ -37,6 +35,7 @@ extern void sun4c_init_IRQ(void);
extern unsigned int lvl14_resolution;
extern void sun4m_init_IRQ(void);
+extern void sun4m_unmask_profile_irq(void);
extern void sun4m_clear_profile_irq(int cpu);
/* sun4d_irq.c */
diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c
index 2969f777fa11..2f538ac2e139 100644
--- a/arch/sparc/kernel/leon_kernel.c
+++ b/arch/sparc/kernel/leon_kernel.c
@@ -19,53 +19,70 @@
#include <asm/leon_amba.h>
#include <asm/traps.h>
#include <asm/cacheflush.h>
+#include <asm/smp.h>
+#include <asm/setup.h>
#include "prom.h"
#include "irq.h"
struct leon3_irqctrl_regs_map *leon3_irqctrl_regs; /* interrupt controller base address */
struct leon3_gptimer_regs_map *leon3_gptimer_regs; /* timer controller base address */
-struct amba_apb_device leon_percpu_timer_dev[16];
int leondebug_irq_disable;
int leon_debug_irqout;
static int dummy_master_l10_counter;
unsigned long amba_system_id;
+static DEFINE_SPINLOCK(leon_irq_lock);
unsigned long leon3_gptimer_irq; /* interrupt controller irq number */
unsigned long leon3_gptimer_idx; /* Timer Index (0..6) within Timer Core */
+int leon3_ticker_irq; /* Timer ticker IRQ */
unsigned int sparc_leon_eirq;
-#define LEON_IMASK ((&leon3_irqctrl_regs->mask[0]))
+#define LEON_IMASK(cpu) (&leon3_irqctrl_regs->mask[cpu])
+#define LEON_IACK (&leon3_irqctrl_regs->iclear)
+#define LEON_DO_ACK_HW 1
-/* Return the IRQ of the pending IRQ on the extended IRQ controller */
-int sparc_leon_eirq_get(int eirq, int cpu)
+/* Return the last ACKed IRQ by the Extended IRQ controller. It has already
+ * been (automatically) ACKed when the CPU takes the trap.
+ */
+static inline unsigned int leon_eirq_get(int cpu)
{
return LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->intid[cpu]) & 0x1f;
}
-irqreturn_t sparc_leon_eirq_isr(int dummy, void *dev_id)
+/* Handle one or multiple IRQs from the extended interrupt controller */
+static void leon_handle_ext_irq(unsigned int irq, struct irq_desc *desc)
{
- printk(KERN_ERR "sparc_leon_eirq_isr: ERROR EXTENDED IRQ\n");
- return IRQ_HANDLED;
+ unsigned int eirq;
+ int cpu = sparc_leon3_cpuid();
+
+ eirq = leon_eirq_get(cpu);
+ if ((eirq & 0x10) && irq_map[eirq]->irq) /* bit4 tells if IRQ happened */
+ generic_handle_irq(irq_map[eirq]->irq);
}
/* The extended IRQ controller has been found, this function registers it */
-void sparc_leon_eirq_register(int eirq)
+void leon_eirq_setup(unsigned int eirq)
{
- int irq;
+ unsigned long mask, oldmask;
+ unsigned int veirq;
- /* Register a "BAD" handler for this interrupt, it should never happen */
- irq = request_irq(eirq, sparc_leon_eirq_isr,
- (IRQF_DISABLED | SA_STATIC_ALLOC), "extirq", NULL);
-
- if (irq) {
- printk(KERN_ERR
- "sparc_leon_eirq_register: unable to attach IRQ%d\n",
- eirq);
- } else {
- sparc_leon_eirq = eirq;
+ if (eirq < 1 || eirq > 0xf) {
+ printk(KERN_ERR "LEON EXT IRQ NUMBER BAD: %d\n", eirq);
+ return;
}
+ veirq = leon_build_device_irq(eirq, leon_handle_ext_irq, "extirq", 0);
+
+ /*
+ * Unmask the Extended IRQ, the IRQs routed through the Ext-IRQ
+ * controller have a mask-bit of their own, so this is safe.
+ */
+ irq_link(veirq);
+ mask = 1 << eirq;
+ oldmask = LEON3_BYPASS_LOAD_PA(LEON_IMASK(boot_cpu_id));
+ LEON3_BYPASS_STORE_PA(LEON_IMASK(boot_cpu_id), (oldmask | mask));
+ sparc_leon_eirq = eirq;
}
static inline unsigned long get_irqmask(unsigned int irq)
@@ -83,35 +100,151 @@ static inline unsigned long get_irqmask(unsigned int irq)
return mask;
}
-static void leon_enable_irq(unsigned int irq_nr)
+#ifdef CONFIG_SMP
+static int irq_choose_cpu(const struct cpumask *affinity)
{
- unsigned long mask, flags;
- mask = get_irqmask(irq_nr);
- local_irq_save(flags);
- LEON3_BYPASS_STORE_PA(LEON_IMASK,
- (LEON3_BYPASS_LOAD_PA(LEON_IMASK) | (mask)));
- local_irq_restore(flags);
+ cpumask_t mask;
+
+ cpus_and(mask, cpu_online_map, *affinity);
+ if (cpus_equal(mask, cpu_online_map) || cpus_empty(mask))
+ return boot_cpu_id;
+ else
+ return first_cpu(mask);
}
+#else
+#define irq_choose_cpu(affinity) boot_cpu_id
+#endif
-static void leon_disable_irq(unsigned int irq_nr)
+static int leon_set_affinity(struct irq_data *data, const struct cpumask *dest,
+ bool force)
{
- unsigned long mask, flags;
- mask = get_irqmask(irq_nr);
- local_irq_save(flags);
- LEON3_BYPASS_STORE_PA(LEON_IMASK,
- (LEON3_BYPASS_LOAD_PA(LEON_IMASK) & ~(mask)));
- local_irq_restore(flags);
+ unsigned long mask, oldmask, flags;
+ int oldcpu, newcpu;
+
+ mask = (unsigned long)data->chip_data;
+ oldcpu = irq_choose_cpu(data->affinity);
+ newcpu = irq_choose_cpu(dest);
+
+ if (oldcpu == newcpu)
+ goto out;
+
+ /* unmask on old CPU first before enabling on the selected CPU */
+ spin_lock_irqsave(&leon_irq_lock, flags);
+ oldmask = LEON3_BYPASS_LOAD_PA(LEON_IMASK(oldcpu));
+ LEON3_BYPASS_STORE_PA(LEON_IMASK(oldcpu), (oldmask & ~mask));
+ oldmask = LEON3_BYPASS_LOAD_PA(LEON_IMASK(newcpu));
+ LEON3_BYPASS_STORE_PA(LEON_IMASK(newcpu), (oldmask | mask));
+ spin_unlock_irqrestore(&leon_irq_lock, flags);
+out:
+ return IRQ_SET_MASK_OK;
+}
+
+static void leon_unmask_irq(struct irq_data *data)
+{
+ unsigned long mask, oldmask, flags;
+ int cpu;
+
+ mask = (unsigned long)data->chip_data;
+ cpu = irq_choose_cpu(data->affinity);
+ spin_lock_irqsave(&leon_irq_lock, flags);
+ oldmask = LEON3_BYPASS_LOAD_PA(LEON_IMASK(cpu));
+ LEON3_BYPASS_STORE_PA(LEON_IMASK(cpu), (oldmask | mask));
+ spin_unlock_irqrestore(&leon_irq_lock, flags);
+}
+
+static void leon_mask_irq(struct irq_data *data)
+{
+ unsigned long mask, oldmask, flags;
+ int cpu;
+
+ mask = (unsigned long)data->chip_data;
+ cpu = irq_choose_cpu(data->affinity);
+ spin_lock_irqsave(&leon_irq_lock, flags);
+ oldmask = LEON3_BYPASS_LOAD_PA(LEON_IMASK(cpu));
+ LEON3_BYPASS_STORE_PA(LEON_IMASK(cpu), (oldmask & ~mask));
+ spin_unlock_irqrestore(&leon_irq_lock, flags);
+}
+
+static unsigned int leon_startup_irq(struct irq_data *data)
+{
+ irq_link(data->irq);
+ leon_unmask_irq(data);
+ return 0;
+}
+static void leon_shutdown_irq(struct irq_data *data)
+{
+ leon_mask_irq(data);
+ irq_unlink(data->irq);
+}
+
+/* Used by external level sensitive IRQ handlers on the LEON: ACK IRQ ctrl */
+static void leon_eoi_irq(struct irq_data *data)
+{
+ unsigned long mask = (unsigned long)data->chip_data;
+
+ if (mask & LEON_DO_ACK_HW)
+ LEON3_BYPASS_STORE_PA(LEON_IACK, mask & ~LEON_DO_ACK_HW);
+}
+
+static struct irq_chip leon_irq = {
+ .name = "leon",
+ .irq_startup = leon_startup_irq,
+ .irq_shutdown = leon_shutdown_irq,
+ .irq_mask = leon_mask_irq,
+ .irq_unmask = leon_unmask_irq,
+ .irq_eoi = leon_eoi_irq,
+ .irq_set_affinity = leon_set_affinity,
+};
+
+/*
+ * Build a LEON IRQ for the edge triggered LEON IRQ controller:
+ * Edge (normal) IRQ - handle_simple_irq, ack=DONT-CARE, never ack
+ * Level IRQ (PCI|Level-GPIO) - handle_fasteoi_irq, ack=1, ack after ISR
+ * Per-CPU Edge - handle_percpu_irq, ack=0
+ */
+unsigned int leon_build_device_irq(unsigned int real_irq,
+ irq_flow_handler_t flow_handler,
+ const char *name, int do_ack)
+{
+ unsigned int irq;
+ unsigned long mask;
+
+ irq = 0;
+ mask = get_irqmask(real_irq);
+ if (mask == 0)
+ goto out;
+
+ irq = irq_alloc(real_irq, real_irq);
+ if (irq == 0)
+ goto out;
+
+ if (do_ack)
+ mask |= LEON_DO_ACK_HW;
+
+ irq_set_chip_and_handler_name(irq, &leon_irq,
+ flow_handler, name);
+ irq_set_chip_data(irq, (void *)mask);
+
+out:
+ return irq;
+}
+
+static unsigned int _leon_build_device_irq(struct platform_device *op,
+ unsigned int real_irq)
+{
+ return leon_build_device_irq(real_irq, handle_simple_irq, "edge", 0);
}
void __init leon_init_timers(irq_handler_t counter_fn)
{
- int irq;
+ int irq, eirq;
struct device_node *rootnp, *np, *nnp;
struct property *pp;
int len;
- int cpu, icsel;
+ int icsel;
int ampopts;
+ int err;
leondebug_irq_disable = 0;
leon_debug_irqout = 0;
@@ -173,98 +306,85 @@ void __init leon_init_timers(irq_handler_t counter_fn)
leon3_gptimer_irq = *(unsigned int *)pp->value;
} while (0);
- if (leon3_gptimer_regs && leon3_irqctrl_regs && leon3_gptimer_irq) {
- LEON3_BYPASS_STORE_PA(
- &leon3_gptimer_regs->e[leon3_gptimer_idx].val, 0);
- LEON3_BYPASS_STORE_PA(
- &leon3_gptimer_regs->e[leon3_gptimer_idx].rld,
- (((1000000 / HZ) - 1)));
- LEON3_BYPASS_STORE_PA(
+ if (!(leon3_gptimer_regs && leon3_irqctrl_regs && leon3_gptimer_irq))
+ goto bad;
+
+ LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].val, 0);
+ LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].rld,
+ (((1000000 / HZ) - 1)));
+ LEON3_BYPASS_STORE_PA(
&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, 0);
#ifdef CONFIG_SMP
- leon_percpu_timer_dev[0].start = (int)leon3_gptimer_regs;
- leon_percpu_timer_dev[0].irq = leon3_gptimer_irq + 1 +
- leon3_gptimer_idx;
-
- if (!(LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->config) &
- (1<<LEON3_GPTIMER_SEPIRQ))) {
- prom_printf("irq timer not configured with separate irqs\n");
- BUG();
- }
+ leon3_ticker_irq = leon3_gptimer_irq + 1 + leon3_gptimer_idx;
- LEON3_BYPASS_STORE_PA(
- &leon3_gptimer_regs->e[leon3_gptimer_idx+1].val, 0);
- LEON3_BYPASS_STORE_PA(
- &leon3_gptimer_regs->e[leon3_gptimer_idx+1].rld,
- (((1000000/HZ) - 1)));
- LEON3_BYPASS_STORE_PA(
- &leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl, 0);
-# endif
-
- /*
- * The IRQ controller may (if implemented) consist of multiple
- * IRQ controllers, each mapped on a 4Kb boundary.
- * Each CPU may be routed to different IRQCTRLs, however
- * we assume that all CPUs (in SMP system) is routed to the
- * same IRQ Controller, and for non-SMP only one IRQCTRL is
- * accessed anyway.
- * In AMP systems, Linux must run on CPU0 for the time being.
- */
- cpu = sparc_leon3_cpuid();
- icsel = LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->icsel[cpu/8]);
- icsel = (icsel >> ((7 - (cpu&0x7)) * 4)) & 0xf;
- leon3_irqctrl_regs += icsel;
- } else {
- goto bad;
+ if (!(LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->config) &
+ (1<<LEON3_GPTIMER_SEPIRQ))) {
+ printk(KERN_ERR "timer not configured with separate irqs\n");
+ BUG();
}
- irq = request_irq(leon3_gptimer_irq+leon3_gptimer_idx,
- counter_fn,
- (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL);
+ LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].val,
+ 0);
+ LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].rld,
+ (((1000000/HZ) - 1)));
+ LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl,
+ 0);
+#endif
- if (irq) {
- printk(KERN_ERR "leon_time_init: unable to attach IRQ%d\n",
- LEON_INTERRUPT_TIMER1);
+ /*
+ * The IRQ controller may (if implemented) consist of multiple
+ * IRQ controllers, each mapped on a 4Kb boundary.
+ * Each CPU may be routed to different IRQCTRLs, however
+ * we assume that all CPUs (in SMP system) is routed to the
+ * same IRQ Controller, and for non-SMP only one IRQCTRL is
+ * accessed anyway.
+ * In AMP systems, Linux must run on CPU0 for the time being.
+ */
+ icsel = LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->icsel[boot_cpu_id/8]);
+ icsel = (icsel >> ((7 - (boot_cpu_id&0x7)) * 4)) & 0xf;
+ leon3_irqctrl_regs += icsel;
+
+ /* Mask all IRQs on boot-cpu IRQ controller */
+ LEON3_BYPASS_STORE_PA(&leon3_irqctrl_regs->mask[boot_cpu_id], 0);
+
+ /* Probe extended IRQ controller */
+ eirq = (LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->mpstatus)
+ >> 16) & 0xf;
+ if (eirq != 0)
+ leon_eirq_setup(eirq);
+
+ irq = _leon_build_device_irq(NULL, leon3_gptimer_irq+leon3_gptimer_idx);
+ err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL);
+ if (err) {
+ printk(KERN_ERR "unable to attach timer IRQ%d\n", irq);
prom_halt();
}
-# ifdef CONFIG_SMP
- {
- unsigned long flags;
- struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (leon_percpu_timer_dev[0].irq - 1)];
-
- /* For SMP we use the level 14 ticker, however the bootup code
- * has copied the firmwares level 14 vector into boot cpu's
- * trap table, we must fix this now or we get squashed.
- */
- local_irq_save(flags);
-
- patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */
-
- /* Adjust so that we jump directly to smpleon_ticker */
- trap_table->inst_three += smpleon_ticker - real_irq_entry;
+ LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl,
+ LEON3_GPTIMER_EN |
+ LEON3_GPTIMER_RL |
+ LEON3_GPTIMER_LD |
+ LEON3_GPTIMER_IRQEN);
- local_flush_cache_all();
- local_irq_restore(flags);
+#ifdef CONFIG_SMP
+ /* Install per-cpu IRQ handler for broadcasted ticker */
+ irq = leon_build_device_irq(leon3_ticker_irq, handle_percpu_irq,
+ "per-cpu", 0);
+ err = request_irq(irq, leon_percpu_timer_interrupt,
+ IRQF_PERCPU | IRQF_TIMER, "ticker",
+ NULL);
+ if (err) {
+ printk(KERN_ERR "unable to attach ticker IRQ%d\n", irq);
+ prom_halt();
}
-# endif
-
- if (leon3_gptimer_regs) {
- LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl,
- LEON3_GPTIMER_EN |
- LEON3_GPTIMER_RL |
- LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN);
-#ifdef CONFIG_SMP
- LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl,
- LEON3_GPTIMER_EN |
- LEON3_GPTIMER_RL |
- LEON3_GPTIMER_LD |
- LEON3_GPTIMER_IRQEN);
+ LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl,
+ LEON3_GPTIMER_EN |
+ LEON3_GPTIMER_RL |
+ LEON3_GPTIMER_LD |
+ LEON3_GPTIMER_IRQEN);
#endif
-
- }
return;
bad:
printk(KERN_ERR "No Timer/irqctrl found\n");
@@ -281,9 +401,6 @@ void leon_load_profile_irq(int cpu, unsigned int limit)
BUG();
}
-
-
-
void __init leon_trans_init(struct device_node *dp)
{
if (strcmp(dp->type, "cpu") == 0 && strcmp(dp->name, "<NULL>") == 0) {
@@ -337,22 +454,18 @@ void leon_enable_irq_cpu(unsigned int irq_nr, unsigned int cpu)
{
unsigned long mask, flags, *addr;
mask = get_irqmask(irq_nr);
- local_irq_save(flags);
- addr = (unsigned long *)&(leon3_irqctrl_regs->mask[cpu]);
- LEON3_BYPASS_STORE_PA(addr, (LEON3_BYPASS_LOAD_PA(addr) | (mask)));
- local_irq_restore(flags);
+ spin_lock_irqsave(&leon_irq_lock, flags);
+ addr = (unsigned long *)LEON_IMASK(cpu);
+ LEON3_BYPASS_STORE_PA(addr, (LEON3_BYPASS_LOAD_PA(addr) | mask));
+ spin_unlock_irqrestore(&leon_irq_lock, flags);
}
#endif
void __init leon_init_IRQ(void)
{
- sparc_irq_config.init_timers = leon_init_timers;
-
- BTFIXUPSET_CALL(enable_irq, leon_enable_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(disable_irq, leon_disable_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(enable_pil_irq, leon_enable_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(disable_pil_irq, leon_disable_irq, BTFIXUPCALL_NORM);
+ sparc_irq_config.init_timers = leon_init_timers;
+ sparc_irq_config.build_device_irq = _leon_build_device_irq;
BTFIXUPSET_CALL(clear_clock_irq, leon_clear_clock_irq,
BTFIXUPCALL_NORM);
diff --git a/arch/sparc/kernel/leon_smp.c b/arch/sparc/kernel/leon_smp.c
index 8f5de4aa3c0a..fe8fb44c609c 100644
--- a/arch/sparc/kernel/leon_smp.c
+++ b/arch/sparc/kernel/leon_smp.c
@@ -14,6 +14,7 @@
#include <linux/smp.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
+#include <linux/of.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
@@ -29,6 +30,7 @@
#include <asm/ptrace.h>
#include <asm/atomic.h>
#include <asm/irq_regs.h>
+#include <asm/traps.h>
#include <asm/delay.h>
#include <asm/irq.h>
@@ -50,9 +52,12 @@
extern ctxd_t *srmmu_ctx_table_phys;
static int smp_processors_ready;
extern volatile unsigned long cpu_callin_map[NR_CPUS];
-extern unsigned char boot_cpu_id;
extern cpumask_t smp_commenced_mask;
void __init leon_configure_cache_smp(void);
+static void leon_ipi_init(void);
+
+/* IRQ number of LEON IPIs */
+int leon_ipi_irq = LEON3_IRQ_IPI_DEFAULT;
static inline unsigned long do_swap(volatile unsigned long *ptr,
unsigned long val)
@@ -94,8 +99,6 @@ void __cpuinit leon_callin(void)
local_flush_cache_all();
local_flush_tlb_all();
- cpu_probe();
-
/* Fix idle thread fields. */
__asm__ __volatile__("ld [%0], %%g6\n\t" : : "r"(&current_set[cpuid])
: "memory" /* paranoid */);
@@ -104,11 +107,11 @@ void __cpuinit leon_callin(void)
atomic_inc(&init_mm.mm_count);
current->active_mm = &init_mm;
- while (!cpu_isset(cpuid, smp_commenced_mask))
+ while (!cpumask_test_cpu(cpuid, &smp_commenced_mask))
mb();
local_irq_enable();
- cpu_set(cpuid, cpu_online_map);
+ set_cpu_online(cpuid, true);
}
/*
@@ -179,13 +182,16 @@ void __init leon_boot_cpus(void)
int nrcpu = leon_smp_nrcpus();
int me = smp_processor_id();
+ /* Setup IPI */
+ leon_ipi_init();
+
printk(KERN_INFO "%d:(%d:%d) cpus mpirq at 0x%x\n", (unsigned int)me,
(unsigned int)nrcpu, (unsigned int)NR_CPUS,
(unsigned int)&(leon3_irqctrl_regs->mpstatus));
leon_enable_irq_cpu(LEON3_IRQ_CROSS_CALL, me);
leon_enable_irq_cpu(LEON3_IRQ_TICKER, me);
- leon_enable_irq_cpu(LEON3_IRQ_RESCHEDULE, me);
+ leon_enable_irq_cpu(leon_ipi_irq, me);
leon_smp_setbroadcast(1 << LEON3_IRQ_TICKER);
@@ -220,6 +226,10 @@ int __cpuinit leon_boot_one_cpu(int i)
(unsigned int)&leon3_irqctrl_regs->mpstatus);
local_flush_cache_all();
+ /* Make sure all IRQs are of from the start for this new CPU */
+ LEON_BYPASS_STORE_PA(&leon3_irqctrl_regs->mask[i], 0);
+
+ /* Wake one CPU */
LEON_BYPASS_STORE_PA(&(leon3_irqctrl_regs->mpstatus), 1 << i);
/* wheee... it's going... */
@@ -236,7 +246,7 @@ int __cpuinit leon_boot_one_cpu(int i)
} else {
leon_enable_irq_cpu(LEON3_IRQ_CROSS_CALL, i);
leon_enable_irq_cpu(LEON3_IRQ_TICKER, i);
- leon_enable_irq_cpu(LEON3_IRQ_RESCHEDULE, i);
+ leon_enable_irq_cpu(leon_ipi_irq, i);
}
local_flush_cache_all();
@@ -262,21 +272,21 @@ void __init leon_smp_done(void)
local_flush_cache_all();
/* Free unneeded trap tables */
- if (!cpu_isset(1, cpu_present_map)) {
+ if (!cpu_present(1)) {
ClearPageReserved(virt_to_page(&trapbase_cpu1));
init_page_count(virt_to_page(&trapbase_cpu1));
free_page((unsigned long)&trapbase_cpu1);
totalram_pages++;
num_physpages++;
}
- if (!cpu_isset(2, cpu_present_map)) {
+ if (!cpu_present(2)) {
ClearPageReserved(virt_to_page(&trapbase_cpu2));
init_page_count(virt_to_page(&trapbase_cpu2));
free_page((unsigned long)&trapbase_cpu2);
totalram_pages++;
num_physpages++;
}
- if (!cpu_isset(3, cpu_present_map)) {
+ if (!cpu_present(3)) {
ClearPageReserved(virt_to_page(&trapbase_cpu3));
init_page_count(virt_to_page(&trapbase_cpu3));
free_page((unsigned long)&trapbase_cpu3);
@@ -292,6 +302,99 @@ void leon_irq_rotate(int cpu)
{
}
+struct leon_ipi_work {
+ int single;
+ int msk;
+ int resched;
+};
+
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct leon_ipi_work, leon_ipi_work);
+
+/* Initialize IPIs on the LEON, in order to save IRQ resources only one IRQ
+ * is used for all three types of IPIs.
+ */
+static void __init leon_ipi_init(void)
+{
+ int cpu, len;
+ struct leon_ipi_work *work;
+ struct property *pp;
+ struct device_node *rootnp;
+ struct tt_entry *trap_table;
+ unsigned long flags;
+
+ /* Find IPI IRQ or stick with default value */
+ rootnp = of_find_node_by_path("/ambapp0");
+ if (rootnp) {
+ pp = of_find_property(rootnp, "ipi_num", &len);
+ if (pp && (*(int *)pp->value))
+ leon_ipi_irq = *(int *)pp->value;
+ }
+ printk(KERN_INFO "leon: SMP IPIs at IRQ %d\n", leon_ipi_irq);
+
+ /* Adjust so that we jump directly to smpleon_ipi */
+ local_irq_save(flags);
+ trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (leon_ipi_irq - 1)];
+ trap_table->inst_three += smpleon_ipi - real_irq_entry;
+ local_flush_cache_all();
+ local_irq_restore(flags);
+
+ for_each_possible_cpu(cpu) {
+ work = &per_cpu(leon_ipi_work, cpu);
+ work->single = work->msk = work->resched = 0;
+ }
+}
+
+static void leon_ipi_single(int cpu)
+{
+ struct leon_ipi_work *work = &per_cpu(leon_ipi_work, cpu);
+
+ /* Mark work */
+ work->single = 1;
+
+ /* Generate IRQ on the CPU */
+ set_cpu_int(cpu, leon_ipi_irq);
+}
+
+static void leon_ipi_mask_one(int cpu)
+{
+ struct leon_ipi_work *work = &per_cpu(leon_ipi_work, cpu);
+
+ /* Mark work */
+ work->msk = 1;
+
+ /* Generate IRQ on the CPU */
+ set_cpu_int(cpu, leon_ipi_irq);
+}
+
+static void leon_ipi_resched(int cpu)
+{
+ struct leon_ipi_work *work = &per_cpu(leon_ipi_work, cpu);
+
+ /* Mark work */
+ work->resched = 1;
+
+ /* Generate IRQ on the CPU (any IRQ will cause resched) */
+ set_cpu_int(cpu, leon_ipi_irq);
+}
+
+void leonsmp_ipi_interrupt(void)
+{
+ struct leon_ipi_work *work = &__get_cpu_var(leon_ipi_work);
+
+ if (work->single) {
+ work->single = 0;
+ smp_call_function_single_interrupt();
+ }
+ if (work->msk) {
+ work->msk = 0;
+ smp_call_function_interrupt();
+ }
+ if (work->resched) {
+ work->resched = 0;
+ smp_resched_interrupt();
+ }
+}
+
static struct smp_funcall {
smpfunc_t func;
unsigned long arg1;
@@ -337,10 +440,10 @@ static void leon_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
{
register int i;
- cpu_clear(smp_processor_id(), mask);
- cpus_and(mask, cpu_online_map, mask);
+ cpumask_clear_cpu(smp_processor_id(), &mask);
+ cpumask_and(&mask, cpu_online_mask, &mask);
for (i = 0; i <= high; i++) {
- if (cpu_isset(i, mask)) {
+ if (cpumask_test_cpu(i, &mask)) {
ccall_info.processors_in[i] = 0;
ccall_info.processors_out[i] = 0;
set_cpu_int(i, LEON3_IRQ_CROSS_CALL);
@@ -354,7 +457,7 @@ static void leon_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
i = 0;
do {
- if (!cpu_isset(i, mask))
+ if (!cpumask_test_cpu(i, &mask))
continue;
while (!ccall_info.processors_in[i])
@@ -363,7 +466,7 @@ static void leon_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
i = 0;
do {
- if (!cpu_isset(i, mask))
+ if (!cpumask_test_cpu(i, &mask))
continue;
while (!ccall_info.processors_out[i])
@@ -386,27 +489,23 @@ void leon_cross_call_irq(void)
ccall_info.processors_out[i] = 1;
}
-void leon_percpu_timer_interrupt(struct pt_regs *regs)
+irqreturn_t leon_percpu_timer_interrupt(int irq, void *unused)
{
- struct pt_regs *old_regs;
int cpu = smp_processor_id();
- old_regs = set_irq_regs(regs);
-
leon_clear_profile_irq(cpu);
profile_tick(CPU_PROFILING);
if (!--prof_counter(cpu)) {
- int user = user_mode(regs);
+ int user = user_mode(get_irq_regs());
- irq_enter();
update_process_times(user);
- irq_exit();
prof_counter(cpu) = prof_multiplier(cpu);
}
- set_irq_regs(old_regs);
+
+ return IRQ_HANDLED;
}
static void __init smp_setup_percpu_timer(void)
@@ -449,6 +548,9 @@ void __init leon_init_smp(void)
BTFIXUPSET_CALL(smp_cross_call, leon_cross_call, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(__hard_smp_processor_id, __leon_processor_id,
BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(smp_ipi_resched, leon_ipi_resched, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(smp_ipi_single, leon_ipi_single, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(smp_ipi_mask_one, leon_ipi_mask_one, BTFIXUPCALL_NORM);
}
#endif /* CONFIG_SPARC_LEON */
diff --git a/arch/sparc/kernel/mdesc.c b/arch/sparc/kernel/mdesc.c
index 56db06432ce9..42f28c7420e1 100644
--- a/arch/sparc/kernel/mdesc.c
+++ b/arch/sparc/kernel/mdesc.c
@@ -768,7 +768,7 @@ static void * __cpuinit mdesc_iterate_over_cpus(void *(*func)(struct mdesc_handl
cpuid, NR_CPUS);
continue;
}
- if (!cpu_isset(cpuid, *mask))
+ if (!cpumask_test_cpu(cpuid, mask))
continue;
#endif
diff --git a/arch/sparc/kernel/of_device_64.c b/arch/sparc/kernel/of_device_64.c
index 5c149689bb20..3bb2eace58cf 100644
--- a/arch/sparc/kernel/of_device_64.c
+++ b/arch/sparc/kernel/of_device_64.c
@@ -622,8 +622,9 @@ static unsigned int __init build_one_device_irq(struct platform_device *op,
out:
nid = of_node_to_nid(dp);
if (nid != -1) {
- cpumask_t numa_mask = *cpumask_of_node(nid);
+ cpumask_t numa_mask;
+ cpumask_copy(&numa_mask, cpumask_of_node(nid));
irq_set_affinity(irq, &numa_mask);
}
diff --git a/arch/sparc/kernel/pci_msi.c b/arch/sparc/kernel/pci_msi.c
index 30982e9ab626..580651af73f2 100644
--- a/arch/sparc/kernel/pci_msi.c
+++ b/arch/sparc/kernel/pci_msi.c
@@ -284,8 +284,9 @@ static int bringup_one_msi_queue(struct pci_pbm_info *pbm,
nid = pbm->numa_node;
if (nid != -1) {
- cpumask_t numa_mask = *cpumask_of_node(nid);
+ cpumask_t numa_mask;
+ cpumask_copy(&numa_mask, cpumask_of_node(nid));
irq_set_affinity(irq, &numa_mask);
}
err = request_irq(irq, sparc64_msiq_interrupt, 0,
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index 2cdc131b50ac..948601a066ff 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -164,6 +164,9 @@ void __iomem *pcic_regs;
volatile int pcic_speculative;
volatile int pcic_trapped;
+/* forward */
+unsigned int pcic_build_device_irq(struct platform_device *op,
+ unsigned int real_irq);
#define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (((unsigned int)bus) << 16) | (((unsigned int)device_fn) << 8) | (where & ~3))
@@ -523,6 +526,7 @@ static void
pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node)
{
struct pcic_ca2irq *p;
+ unsigned int real_irq;
int i, ivec;
char namebuf[64];
@@ -551,26 +555,25 @@ pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node)
i = p->pin;
if (i >= 0 && i < 4) {
ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_LO);
- dev->irq = ivec >> (i << 2) & 0xF;
+ real_irq = ivec >> (i << 2) & 0xF;
} else if (i >= 4 && i < 8) {
ivec = readw(pcic->pcic_regs+PCI_INT_SELECT_HI);
- dev->irq = ivec >> ((i-4) << 2) & 0xF;
+ real_irq = ivec >> ((i-4) << 2) & 0xF;
} else { /* Corrupted map */
printk("PCIC: BAD PIN %d\n", i); for (;;) {}
}
/* P3 */ /* printk("PCIC: device %s pin %d ivec 0x%x irq %x\n", namebuf, i, ivec, dev->irq); */
- /*
- * dev->irq=0 means PROM did not bother to program the upper
+ /* real_irq means PROM did not bother to program the upper
* half of PCIC. This happens on JS-E with PROM 3.11, for instance.
*/
- if (dev->irq == 0 || p->force) {
+ if (real_irq == 0 || p->force) {
if (p->irq == 0 || p->irq >= 15) { /* Corrupted map */
printk("PCIC: BAD IRQ %d\n", p->irq); for (;;) {}
}
printk("PCIC: setting irq %d at pin %d for device %02x:%02x\n",
p->irq, p->pin, dev->bus->number, dev->devfn);
- dev->irq = p->irq;
+ real_irq = p->irq;
i = p->pin;
if (i >= 4) {
@@ -584,7 +587,8 @@ pcic_fill_irq(struct linux_pcic *pcic, struct pci_dev *dev, int node)
ivec |= p->irq << (i << 2);
writew(ivec, pcic->pcic_regs+PCI_INT_SELECT_LO);
}
- }
+ }
+ dev->irq = pcic_build_device_irq(NULL, real_irq);
}
/*
@@ -729,6 +733,7 @@ void __init pci_time_init(void)
struct linux_pcic *pcic = &pcic0;
unsigned long v;
int timer_irq, irq;
+ int err;
do_arch_gettimeoffset = pci_gettimeoffset;
@@ -740,9 +745,10 @@ void __init pci_time_init(void)
timer_irq = PCI_COUNTER_IRQ_SYS(v);
writel (PCI_COUNTER_IRQ_SET(timer_irq, 0),
pcic->pcic_regs+PCI_COUNTER_IRQ);
- irq = request_irq(timer_irq, pcic_timer_handler,
- (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL);
- if (irq) {
+ irq = pcic_build_device_irq(NULL, timer_irq);
+ err = request_irq(irq, pcic_timer_handler,
+ IRQF_TIMER, "timer", NULL);
+ if (err) {
prom_printf("time_init: unable to attach IRQ%d\n", timer_irq);
prom_halt();
}
@@ -803,50 +809,73 @@ static inline unsigned long get_irqmask(int irq_nr)
return 1 << irq_nr;
}
-static void pcic_disable_irq(unsigned int irq_nr)
+static void pcic_mask_irq(struct irq_data *data)
{
unsigned long mask, flags;
- mask = get_irqmask(irq_nr);
+ mask = (unsigned long)data->chip_data;
local_irq_save(flags);
writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_SET);
local_irq_restore(flags);
}
-static void pcic_enable_irq(unsigned int irq_nr)
+static void pcic_unmask_irq(struct irq_data *data)
{
unsigned long mask, flags;
- mask = get_irqmask(irq_nr);
+ mask = (unsigned long)data->chip_data;
local_irq_save(flags);
writel(mask, pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR);
local_irq_restore(flags);
}
-static void pcic_load_profile_irq(int cpu, unsigned int limit)
+static unsigned int pcic_startup_irq(struct irq_data *data)
{
- printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__);
+ irq_link(data->irq);
+ pcic_unmask_irq(data);
+ return 0;
}
-/* We assume the caller has disabled local interrupts when these are called,
- * or else very bizarre behavior will result.
- */
-static void pcic_disable_pil_irq(unsigned int pil)
+static struct irq_chip pcic_irq = {
+ .name = "pcic",
+ .irq_startup = pcic_startup_irq,
+ .irq_mask = pcic_mask_irq,
+ .irq_unmask = pcic_unmask_irq,
+};
+
+unsigned int pcic_build_device_irq(struct platform_device *op,
+ unsigned int real_irq)
{
- writel(get_irqmask(pil), pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_SET);
+ unsigned int irq;
+ unsigned long mask;
+
+ irq = 0;
+ mask = get_irqmask(real_irq);
+ if (mask == 0)
+ goto out;
+
+ irq = irq_alloc(real_irq, real_irq);
+ if (irq == 0)
+ goto out;
+
+ irq_set_chip_and_handler_name(irq, &pcic_irq,
+ handle_level_irq, "PCIC");
+ irq_set_chip_data(irq, (void *)mask);
+
+out:
+ return irq;
}
-static void pcic_enable_pil_irq(unsigned int pil)
+
+static void pcic_load_profile_irq(int cpu, unsigned int limit)
{
- writel(get_irqmask(pil), pcic0.pcic_regs+PCI_SYS_INT_TARGET_MASK_CLEAR);
+ printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__);
}
void __init sun4m_pci_init_IRQ(void)
{
- BTFIXUPSET_CALL(enable_irq, pcic_enable_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(disable_irq, pcic_disable_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(enable_pil_irq, pcic_enable_pil_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(disable_pil_irq, pcic_disable_pil_irq, BTFIXUPCALL_NORM);
+ sparc_irq_config.build_device_irq = pcic_build_device_irq;
+
BTFIXUPSET_CALL(clear_clock_irq, pcic_clear_clock_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(load_profile_irq, pcic_load_profile_irq, BTFIXUPCALL_NORM);
}
diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c
index ee8426ede7c7..2cb0e1c001e2 100644
--- a/arch/sparc/kernel/perf_event.c
+++ b/arch/sparc/kernel/perf_event.c
@@ -26,6 +26,7 @@
#include <asm/nmi.h>
#include <asm/pcr.h>
+#include "kernel.h"
#include "kstack.h"
/* Sparc64 chips have two performance counters, 32-bits each, with
diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c
index 17529298c50a..c8cc461ff75f 100644
--- a/arch/sparc/kernel/process_32.c
+++ b/arch/sparc/kernel/process_32.c
@@ -128,8 +128,16 @@ void cpu_idle(void)
set_thread_flag(TIF_POLLING_NRFLAG);
/* endless idle loop with no priority at all */
while(1) {
- while (!need_resched())
- cpu_relax();
+#ifdef CONFIG_SPARC_LEON
+ if (pm_idle) {
+ while (!need_resched())
+ (*pm_idle)();
+ } else
+#endif
+ {
+ while (!need_resched())
+ cpu_relax();
+ }
preempt_enable_no_resched();
schedule();
preempt_disable();
diff --git a/arch/sparc/kernel/prom_32.c b/arch/sparc/kernel/prom_32.c
index 05fb25330583..5ce3d15a99b0 100644
--- a/arch/sparc/kernel/prom_32.c
+++ b/arch/sparc/kernel/prom_32.c
@@ -326,7 +326,6 @@ void __init of_console_init(void)
of_console_options = NULL;
}
- prom_printf(msg, of_console_path);
printk(msg, of_console_path);
}
diff --git a/arch/sparc/kernel/setup_32.c b/arch/sparc/kernel/setup_32.c
index 7b8b76c9557f..3249d3f3234d 100644
--- a/arch/sparc/kernel/setup_32.c
+++ b/arch/sparc/kernel/setup_32.c
@@ -82,7 +82,7 @@ static void prom_sync_me(void)
"nop\n\t" : : "r" (&trapbase));
prom_printf("PROM SYNC COMMAND...\n");
- show_free_areas();
+ show_free_areas(0);
if(current->pid != 0) {
local_irq_enable();
sys_sync();
@@ -103,16 +103,20 @@ static unsigned int boot_flags __initdata = 0;
/* Exported for mm/init.c:paging_init. */
unsigned long cmdline_memory_size __initdata = 0;
+/* which CPU booted us (0xff = not set) */
+unsigned char boot_cpu_id = 0xff; /* 0xff will make it into DATA section... */
+unsigned char boot_cpu_id4; /* boot_cpu_id << 2 */
+
static void
prom_console_write(struct console *con, const char *s, unsigned n)
{
prom_write(s, n);
}
-static struct console prom_debug_console = {
- .name = "debug",
+static struct console prom_early_console = {
+ .name = "earlyprom",
.write = prom_console_write,
- .flags = CON_PRINTBUFFER,
+ .flags = CON_PRINTBUFFER | CON_BOOT,
.index = -1,
};
@@ -133,8 +137,7 @@ static void __init process_switch(char c)
prom_halt();
break;
case 'p':
- /* Use PROM debug console. */
- register_console(&prom_debug_console);
+ /* Just ignore, this behavior is now the default. */
break;
default:
printk("Unknown boot switch (-%c)\n", c);
@@ -215,6 +218,10 @@ void __init setup_arch(char **cmdline_p)
strcpy(boot_command_line, *cmdline_p);
parse_early_param();
+ boot_flags_init(*cmdline_p);
+
+ register_console(&prom_early_console);
+
/* Set sparc_cpu_model */
sparc_cpu_model = sun_unknown;
if (!strcmp(&cputypval[0], "sun4 "))
@@ -265,7 +272,6 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
#endif
- boot_flags_init(*cmdline_p);
idprom_init();
if (ARCH_SUN4C)
@@ -311,75 +317,6 @@ void __init setup_arch(char **cmdline_p)
smp_setup_cpu_possible_map();
}
-static int ncpus_probed;
-
-static int show_cpuinfo(struct seq_file *m, void *__unused)
-{
- seq_printf(m,
- "cpu\t\t: %s\n"
- "fpu\t\t: %s\n"
- "promlib\t\t: Version %d Revision %d\n"
- "prom\t\t: %d.%d\n"
- "type\t\t: %s\n"
- "ncpus probed\t: %d\n"
- "ncpus active\t: %d\n"
-#ifndef CONFIG_SMP
- "CPU0Bogo\t: %lu.%02lu\n"
- "CPU0ClkTck\t: %ld\n"
-#endif
- ,
- sparc_cpu_type,
- sparc_fpu_type ,
- romvec->pv_romvers,
- prom_rev,
- romvec->pv_printrev >> 16,
- romvec->pv_printrev & 0xffff,
- &cputypval[0],
- ncpus_probed,
- num_online_cpus()
-#ifndef CONFIG_SMP
- , cpu_data(0).udelay_val/(500000/HZ),
- (cpu_data(0).udelay_val/(5000/HZ)) % 100,
- cpu_data(0).clock_tick
-#endif
- );
-
-#ifdef CONFIG_SMP
- smp_bogo(m);
-#endif
- mmu_info(m);
-#ifdef CONFIG_SMP
- smp_info(m);
-#endif
- return 0;
-}
-
-static void *c_start(struct seq_file *m, loff_t *pos)
-{
- /* The pointer we are returning is arbitrary,
- * it just has to be non-NULL and not IS_ERR
- * in the success case.
- */
- return *pos == 0 ? &c_start : NULL;
-}
-
-static void *c_next(struct seq_file *m, void *v, loff_t *pos)
-{
- ++*pos;
- return c_start(m, pos);
-}
-
-static void c_stop(struct seq_file *m, void *v)
-{
-}
-
-const struct seq_operations cpuinfo_op = {
- .start =c_start,
- .next = c_next,
- .stop = c_stop,
- .show = show_cpuinfo,
-};
-
extern int stop_a_enabled;
void sun_do_break(void)
diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c
index 29bafe051bb1..f3b6850cc8db 100644
--- a/arch/sparc/kernel/setup_64.c
+++ b/arch/sparc/kernel/setup_64.c
@@ -339,84 +339,6 @@ void __init setup_arch(char **cmdline_p)
paging_init();
}
-/* BUFFER is PAGE_SIZE bytes long. */
-
-extern void smp_info(struct seq_file *);
-extern void smp_bogo(struct seq_file *);
-extern void mmu_info(struct seq_file *);
-
-unsigned int dcache_parity_tl1_occurred;
-unsigned int icache_parity_tl1_occurred;
-
-int ncpus_probed;
-
-static int show_cpuinfo(struct seq_file *m, void *__unused)
-{
- seq_printf(m,
- "cpu\t\t: %s\n"
- "fpu\t\t: %s\n"
- "pmu\t\t: %s\n"
- "prom\t\t: %s\n"
- "type\t\t: %s\n"
- "ncpus probed\t: %d\n"
- "ncpus active\t: %d\n"
- "D$ parity tl1\t: %u\n"
- "I$ parity tl1\t: %u\n"
-#ifndef CONFIG_SMP
- "Cpu0ClkTck\t: %016lx\n"
-#endif
- ,
- sparc_cpu_type,
- sparc_fpu_type,
- sparc_pmu_type,
- prom_version,
- ((tlb_type == hypervisor) ?
- "sun4v" :
- "sun4u"),
- ncpus_probed,
- num_online_cpus(),
- dcache_parity_tl1_occurred,
- icache_parity_tl1_occurred
-#ifndef CONFIG_SMP
- , cpu_data(0).clock_tick
-#endif
- );
-#ifdef CONFIG_SMP
- smp_bogo(m);
-#endif
- mmu_info(m);
-#ifdef CONFIG_SMP
- smp_info(m);
-#endif
- return 0;
-}
-
-static void *c_start(struct seq_file *m, loff_t *pos)
-{
- /* The pointer we are returning is arbitrary,
- * it just has to be non-NULL and not IS_ERR
- * in the success case.
- */
- return *pos == 0 ? &c_start : NULL;
-}
-
-static void *c_next(struct seq_file *m, void *v, loff_t *pos)
-{
- ++*pos;
- return c_start(m, pos);
-}
-
-static void c_stop(struct seq_file *m, void *v)
-{
-}
-
-const struct seq_operations cpuinfo_op = {
- .start =c_start,
- .next = c_next,
- .stop = c_stop,
- .show = show_cpuinfo,
-};
-
extern int stop_a_enabled;
void sun_do_break(void)
diff --git a/arch/sparc/kernel/smp_32.c b/arch/sparc/kernel/smp_32.c
index 850a1360c0d6..d5b3958be0b4 100644
--- a/arch/sparc/kernel/smp_32.c
+++ b/arch/sparc/kernel/smp_32.c
@@ -37,8 +37,6 @@
#include "irq.h"
volatile unsigned long cpu_callin_map[NR_CPUS] __cpuinitdata = {0,};
-unsigned char boot_cpu_id = 0;
-unsigned char boot_cpu_id4 = 0; /* boot_cpu_id << 2 */
cpumask_t smp_commenced_mask = CPU_MASK_NONE;
@@ -129,13 +127,58 @@ struct linux_prom_registers smp_penguin_ctable __cpuinitdata = { 0 };
void smp_send_reschedule(int cpu)
{
- /* See sparc64 */
+ /*
+ * CPU model dependent way of implementing IPI generation targeting
+ * a single CPU. The trap handler needs only to do trap entry/return
+ * to call schedule.
+ */
+ BTFIXUP_CALL(smp_ipi_resched)(cpu);
}
void smp_send_stop(void)
{
}
+void arch_send_call_function_single_ipi(int cpu)
+{
+ /* trigger one IPI single call on one CPU */
+ BTFIXUP_CALL(smp_ipi_single)(cpu);
+}
+
+void arch_send_call_function_ipi_mask(const struct cpumask *mask)
+{
+ int cpu;
+
+ /* trigger IPI mask call on each CPU */
+ for_each_cpu(cpu, mask)
+ BTFIXUP_CALL(smp_ipi_mask_one)(cpu);
+}
+
+void smp_resched_interrupt(void)
+{
+ irq_enter();
+ scheduler_ipi();
+ local_cpu_data().irq_resched_count++;
+ irq_exit();
+ /* re-schedule routine called by interrupt return code. */
+}
+
+void smp_call_function_single_interrupt(void)
+{
+ irq_enter();
+ generic_smp_call_function_single_interrupt();
+ local_cpu_data().irq_call_count++;
+ irq_exit();
+}
+
+void smp_call_function_interrupt(void)
+{
+ irq_enter();
+ generic_smp_call_function_interrupt();
+ local_cpu_data().irq_call_count++;
+ irq_exit();
+}
+
void smp_flush_cache_all(void)
{
xc0((smpfunc_t) BTFIXUP_CALL(local_flush_cache_all));
@@ -151,9 +194,10 @@ void smp_flush_tlb_all(void)
void smp_flush_cache_mm(struct mm_struct *mm)
{
if(mm->context != NO_CONTEXT) {
- cpumask_t cpu_mask = *mm_cpumask(mm);
- cpu_clear(smp_processor_id(), cpu_mask);
- if (!cpus_empty(cpu_mask))
+ cpumask_t cpu_mask;
+ cpumask_copy(&cpu_mask, mm_cpumask(mm));
+ cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
+ if (!cpumask_empty(&cpu_mask))
xc1((smpfunc_t) BTFIXUP_CALL(local_flush_cache_mm), (unsigned long) mm);
local_flush_cache_mm(mm);
}
@@ -162,9 +206,10 @@ void smp_flush_cache_mm(struct mm_struct *mm)
void smp_flush_tlb_mm(struct mm_struct *mm)
{
if(mm->context != NO_CONTEXT) {
- cpumask_t cpu_mask = *mm_cpumask(mm);
- cpu_clear(smp_processor_id(), cpu_mask);
- if (!cpus_empty(cpu_mask)) {
+ cpumask_t cpu_mask;
+ cpumask_copy(&cpu_mask, mm_cpumask(mm));
+ cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
+ if (!cpumask_empty(&cpu_mask)) {
xc1((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_mm), (unsigned long) mm);
if(atomic_read(&mm->mm_users) == 1 && current->active_mm == mm)
cpumask_copy(mm_cpumask(mm),
@@ -180,9 +225,10 @@ void smp_flush_cache_range(struct vm_area_struct *vma, unsigned long start,
struct mm_struct *mm = vma->vm_mm;
if (mm->context != NO_CONTEXT) {
- cpumask_t cpu_mask = *mm_cpumask(mm);
- cpu_clear(smp_processor_id(), cpu_mask);
- if (!cpus_empty(cpu_mask))
+ cpumask_t cpu_mask;
+ cpumask_copy(&cpu_mask, mm_cpumask(mm));
+ cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
+ if (!cpumask_empty(&cpu_mask))
xc3((smpfunc_t) BTFIXUP_CALL(local_flush_cache_range), (unsigned long) vma, start, end);
local_flush_cache_range(vma, start, end);
}
@@ -194,9 +240,10 @@ void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
struct mm_struct *mm = vma->vm_mm;
if (mm->context != NO_CONTEXT) {
- cpumask_t cpu_mask = *mm_cpumask(mm);
- cpu_clear(smp_processor_id(), cpu_mask);
- if (!cpus_empty(cpu_mask))
+ cpumask_t cpu_mask;
+ cpumask_copy(&cpu_mask, mm_cpumask(mm));
+ cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
+ if (!cpumask_empty(&cpu_mask))
xc3((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_range), (unsigned long) vma, start, end);
local_flush_tlb_range(vma, start, end);
}
@@ -207,9 +254,10 @@ void smp_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
struct mm_struct *mm = vma->vm_mm;
if(mm->context != NO_CONTEXT) {
- cpumask_t cpu_mask = *mm_cpumask(mm);
- cpu_clear(smp_processor_id(), cpu_mask);
- if (!cpus_empty(cpu_mask))
+ cpumask_t cpu_mask;
+ cpumask_copy(&cpu_mask, mm_cpumask(mm));
+ cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
+ if (!cpumask_empty(&cpu_mask))
xc2((smpfunc_t) BTFIXUP_CALL(local_flush_cache_page), (unsigned long) vma, page);
local_flush_cache_page(vma, page);
}
@@ -220,19 +268,15 @@ void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
struct mm_struct *mm = vma->vm_mm;
if(mm->context != NO_CONTEXT) {
- cpumask_t cpu_mask = *mm_cpumask(mm);
- cpu_clear(smp_processor_id(), cpu_mask);
- if (!cpus_empty(cpu_mask))
+ cpumask_t cpu_mask;
+ cpumask_copy(&cpu_mask, mm_cpumask(mm));
+ cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
+ if (!cpumask_empty(&cpu_mask))
xc2((smpfunc_t) BTFIXUP_CALL(local_flush_tlb_page), (unsigned long) vma, page);
local_flush_tlb_page(vma, page);
}
}
-void smp_reschedule_irq(void)
-{
- set_need_resched();
-}
-
void smp_flush_page_to_ram(unsigned long page)
{
/* Current theory is that those who call this are the one's
@@ -249,9 +293,10 @@ void smp_flush_page_to_ram(unsigned long page)
void smp_flush_sig_insns(struct mm_struct *mm, unsigned long insn_addr)
{
- cpumask_t cpu_mask = *mm_cpumask(mm);
- cpu_clear(smp_processor_id(), cpu_mask);
- if (!cpus_empty(cpu_mask))
+ cpumask_t cpu_mask;
+ cpumask_copy(&cpu_mask, mm_cpumask(mm));
+ cpumask_clear_cpu(smp_processor_id(), &cpu_mask);
+ if (!cpumask_empty(&cpu_mask))
xc2((smpfunc_t) BTFIXUP_CALL(local_flush_sig_insns), (unsigned long) mm, insn_addr);
local_flush_sig_insns(mm, insn_addr);
}
@@ -405,7 +450,7 @@ int __cpuinit __cpu_up(unsigned int cpu)
};
if (!ret) {
- cpu_set(cpu, smp_commenced_mask);
+ cpumask_set_cpu(cpu, &smp_commenced_mask);
while (!cpu_online(cpu))
mb();
}
diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c
index 3e94a8c23238..99cb17251bb5 100644
--- a/arch/sparc/kernel/smp_64.c
+++ b/arch/sparc/kernel/smp_64.c
@@ -121,11 +121,11 @@ void __cpuinit smp_callin(void)
/* inform the notifiers about the new cpu */
notify_cpu_starting(cpuid);
- while (!cpu_isset(cpuid, smp_commenced_mask))
+ while (!cpumask_test_cpu(cpuid, &smp_commenced_mask))
rmb();
ipi_call_lock_irq();
- cpu_set(cpuid, cpu_online_map);
+ set_cpu_online(cpuid, true);
ipi_call_unlock_irq();
/* idle thread is expected to have preempt disabled */
@@ -785,7 +785,7 @@ static void xcall_deliver(u64 data0, u64 data1, u64 data2, const cpumask_t *mask
/* Send cross call to all processors mentioned in MASK_P
* except self. Really, there are only two cases currently,
- * "&cpu_online_map" and "&mm->cpu_vm_mask".
+ * "cpu_online_mask" and "mm_cpumask(mm)".
*/
static void smp_cross_call_masked(unsigned long *func, u32 ctx, u64 data1, u64 data2, const cpumask_t *mask)
{
@@ -797,7 +797,7 @@ static void smp_cross_call_masked(unsigned long *func, u32 ctx, u64 data1, u64 d
/* Send cross call to all processors except self. */
static void smp_cross_call(unsigned long *func, u32 ctx, u64 data1, u64 data2)
{
- smp_cross_call_masked(func, ctx, data1, data2, &cpu_online_map);
+ smp_cross_call_masked(func, ctx, data1, data2, cpu_online_mask);
}
extern unsigned long xcall_sync_tick;
@@ -805,7 +805,7 @@ extern unsigned long xcall_sync_tick;
static void smp_start_sync_tick_client(int cpu)
{
xcall_deliver((u64) &xcall_sync_tick, 0, 0,
- &cpumask_of_cpu(cpu));
+ cpumask_of(cpu));
}
extern unsigned long xcall_call_function;
@@ -820,7 +820,7 @@ extern unsigned long xcall_call_function_single;
void arch_send_call_function_single_ipi(int cpu)
{
xcall_deliver((u64) &xcall_call_function_single, 0, 0,
- &cpumask_of_cpu(cpu));
+ cpumask_of(cpu));
}
void __irq_entry smp_call_function_client(int irq, struct pt_regs *regs)
@@ -918,7 +918,7 @@ void smp_flush_dcache_page_impl(struct page *page, int cpu)
}
if (data0) {
xcall_deliver(data0, __pa(pg_addr),
- (u64) pg_addr, &cpumask_of_cpu(cpu));
+ (u64) pg_addr, cpumask_of(cpu));
#ifdef CONFIG_DEBUG_DCFLUSH
atomic_inc(&dcpage_flushes_xcall);
#endif
@@ -954,7 +954,7 @@ void flush_dcache_page_all(struct mm_struct *mm, struct page *page)
}
if (data0) {
xcall_deliver(data0, __pa(pg_addr),
- (u64) pg_addr, &cpu_online_map);
+ (u64) pg_addr, cpu_online_mask);
#ifdef CONFIG_DEBUG_DCFLUSH
atomic_inc(&dcpage_flushes_xcall);
#endif
@@ -1197,32 +1197,32 @@ void __devinit smp_fill_in_sib_core_maps(void)
for_each_present_cpu(i) {
unsigned int j;
- cpus_clear(cpu_core_map[i]);
+ cpumask_clear(&cpu_core_map[i]);
if (cpu_data(i).core_id == 0) {
- cpu_set(i, cpu_core_map[i]);
+ cpumask_set_cpu(i, &cpu_core_map[i]);
continue;
}
for_each_present_cpu(j) {
if (cpu_data(i).core_id ==
cpu_data(j).core_id)
- cpu_set(j, cpu_core_map[i]);
+ cpumask_set_cpu(j, &cpu_core_map[i]);
}
}
for_each_present_cpu(i) {
unsigned int j;
- cpus_clear(per_cpu(cpu_sibling_map, i));
+ cpumask_clear(&per_cpu(cpu_sibling_map, i));
if (cpu_data(i).proc_id == -1) {
- cpu_set(i, per_cpu(cpu_sibling_map, i));
+ cpumask_set_cpu(i, &per_cpu(cpu_sibling_map, i));
continue;
}
for_each_present_cpu(j) {
if (cpu_data(i).proc_id ==
cpu_data(j).proc_id)
- cpu_set(j, per_cpu(cpu_sibling_map, i));
+ cpumask_set_cpu(j, &per_cpu(cpu_sibling_map, i));
}
}
}
@@ -1232,10 +1232,10 @@ int __cpuinit __cpu_up(unsigned int cpu)
int ret = smp_boot_one_cpu(cpu);
if (!ret) {
- cpu_set(cpu, smp_commenced_mask);
- while (!cpu_isset(cpu, cpu_online_map))
+ cpumask_set_cpu(cpu, &smp_commenced_mask);
+ while (!cpu_online(cpu))
mb();
- if (!cpu_isset(cpu, cpu_online_map)) {
+ if (!cpu_online(cpu)) {
ret = -ENODEV;
} else {
/* On SUN4V, writes to %tick and %stick are
@@ -1269,7 +1269,7 @@ void cpu_play_dead(void)
tb->nonresum_mondo_pa, 0);
}
- cpu_clear(cpu, smp_commenced_mask);
+ cpumask_clear_cpu(cpu, &smp_commenced_mask);
membar_safe("#Sync");
local_irq_disable();
@@ -1290,13 +1290,13 @@ int __cpu_disable(void)
cpuinfo_sparc *c;
int i;
- for_each_cpu_mask(i, cpu_core_map[cpu])
- cpu_clear(cpu, cpu_core_map[i]);
- cpus_clear(cpu_core_map[cpu]);
+ for_each_cpu(i, &cpu_core_map[cpu])
+ cpumask_clear_cpu(cpu, &cpu_core_map[i]);
+ cpumask_clear(&cpu_core_map[cpu]);
- for_each_cpu_mask(i, per_cpu(cpu_sibling_map, cpu))
- cpu_clear(cpu, per_cpu(cpu_sibling_map, i));
- cpus_clear(per_cpu(cpu_sibling_map, cpu));
+ for_each_cpu(i, &per_cpu(cpu_sibling_map, cpu))
+ cpumask_clear_cpu(cpu, &per_cpu(cpu_sibling_map, i));
+ cpumask_clear(&per_cpu(cpu_sibling_map, cpu));
c = &cpu_data(cpu);
@@ -1313,7 +1313,7 @@ int __cpu_disable(void)
local_irq_disable();
ipi_call_lock();
- cpu_clear(cpu, cpu_online_map);
+ set_cpu_online(cpu, false);
ipi_call_unlock();
cpu_map_rebuild();
@@ -1327,11 +1327,11 @@ void __cpu_die(unsigned int cpu)
for (i = 0; i < 100; i++) {
smp_rmb();
- if (!cpu_isset(cpu, smp_commenced_mask))
+ if (!cpumask_test_cpu(cpu, &smp_commenced_mask))
break;
msleep(100);
}
- if (cpu_isset(cpu, smp_commenced_mask)) {
+ if (cpumask_test_cpu(cpu, &smp_commenced_mask)) {
printk(KERN_ERR "CPU %u didn't die...\n", cpu);
} else {
#if defined(CONFIG_SUN_LDOMS)
@@ -1341,7 +1341,7 @@ void __cpu_die(unsigned int cpu)
do {
hv_err = sun4v_cpu_stop(cpu);
if (hv_err == HV_EOK) {
- cpu_clear(cpu, cpu_present_map);
+ set_cpu_present(cpu, false);
break;
}
} while (--limit > 0);
@@ -1362,12 +1362,13 @@ void __init smp_cpus_done(unsigned int max_cpus)
void smp_send_reschedule(int cpu)
{
xcall_deliver((u64) &xcall_receive_signal, 0, 0,
- &cpumask_of_cpu(cpu));
+ cpumask_of(cpu));
}
void __irq_entry smp_receive_signal_client(int irq, struct pt_regs *regs)
{
clear_softint(1 << irq);
+ scheduler_ipi();
}
/* This is a nop because we capture all other cpus
diff --git a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c
index 90eea38ad66f..f6bf25a2ff80 100644
--- a/arch/sparc/kernel/sun4c_irq.c
+++ b/arch/sparc/kernel/sun4c_irq.c
@@ -65,62 +65,94 @@
*/
unsigned char __iomem *interrupt_enable;
-static void sun4c_disable_irq(unsigned int irq_nr)
+static void sun4c_mask_irq(struct irq_data *data)
{
- unsigned long flags;
- unsigned char current_mask, new_mask;
-
- local_irq_save(flags);
- irq_nr &= (NR_IRQS - 1);
- current_mask = sbus_readb(interrupt_enable);
- switch (irq_nr) {
- case 1:
- new_mask = ((current_mask) & (~(SUN4C_INT_E1)));
- break;
- case 8:
- new_mask = ((current_mask) & (~(SUN4C_INT_E8)));
- break;
- case 10:
- new_mask = ((current_mask) & (~(SUN4C_INT_E10)));
- break;
- case 14:
- new_mask = ((current_mask) & (~(SUN4C_INT_E14)));
- break;
- default:
+ unsigned long mask = (unsigned long)data->chip_data;
+
+ if (mask) {
+ unsigned long flags;
+
+ local_irq_save(flags);
+ mask = sbus_readb(interrupt_enable) & ~mask;
+ sbus_writeb(mask, interrupt_enable);
local_irq_restore(flags);
- return;
}
- sbus_writeb(new_mask, interrupt_enable);
- local_irq_restore(flags);
}
-static void sun4c_enable_irq(unsigned int irq_nr)
+static void sun4c_unmask_irq(struct irq_data *data)
{
- unsigned long flags;
- unsigned char current_mask, new_mask;
-
- local_irq_save(flags);
- irq_nr &= (NR_IRQS - 1);
- current_mask = sbus_readb(interrupt_enable);
- switch (irq_nr) {
- case 1:
- new_mask = ((current_mask) | SUN4C_INT_E1);
- break;
- case 8:
- new_mask = ((current_mask) | SUN4C_INT_E8);
- break;
- case 10:
- new_mask = ((current_mask) | SUN4C_INT_E10);
- break;
- case 14:
- new_mask = ((current_mask) | SUN4C_INT_E14);
- break;
- default:
+ unsigned long mask = (unsigned long)data->chip_data;
+
+ if (mask) {
+ unsigned long flags;
+
+ local_irq_save(flags);
+ mask = sbus_readb(interrupt_enable) | mask;
+ sbus_writeb(mask, interrupt_enable);
local_irq_restore(flags);
- return;
}
- sbus_writeb(new_mask, interrupt_enable);
- local_irq_restore(flags);
+}
+
+static unsigned int sun4c_startup_irq(struct irq_data *data)
+{
+ irq_link(data->irq);
+ sun4c_unmask_irq(data);
+
+ return 0;
+}
+
+static void sun4c_shutdown_irq(struct irq_data *data)
+{
+ sun4c_mask_irq(data);
+ irq_unlink(data->irq);
+}
+
+static struct irq_chip sun4c_irq = {
+ .name = "sun4c",
+ .irq_startup = sun4c_startup_irq,
+ .irq_shutdown = sun4c_shutdown_irq,
+ .irq_mask = sun4c_mask_irq,
+ .irq_unmask = sun4c_unmask_irq,
+};
+
+static unsigned int sun4c_build_device_irq(struct platform_device *op,
+ unsigned int real_irq)
+{
+ unsigned int irq;
+
+ if (real_irq >= 16) {
+ prom_printf("Bogus sun4c IRQ %u\n", real_irq);
+ prom_halt();
+ }
+
+ irq = irq_alloc(real_irq, real_irq);
+ if (irq) {
+ unsigned long mask = 0UL;
+
+ switch (real_irq) {
+ case 1:
+ mask = SUN4C_INT_E1;
+ break;
+ case 8:
+ mask = SUN4C_INT_E8;
+ break;
+ case 10:
+ mask = SUN4C_INT_E10;
+ break;
+ case 14:
+ mask = SUN4C_INT_E14;
+ break;
+ default:
+ /* All the rest are either always enabled,
+ * or are for signalling software interrupts.
+ */
+ break;
+ }
+ irq_set_chip_and_handler_name(irq, &sun4c_irq,
+ handle_level_irq, "level");
+ irq_set_chip_data(irq, (void *)mask);
+ }
+ return irq;
}
struct sun4c_timer_info {
@@ -144,8 +176,9 @@ static void sun4c_load_profile_irq(int cpu, unsigned int limit)
static void __init sun4c_init_timers(irq_handler_t counter_fn)
{
- const struct linux_prom_irqs *irq;
+ const struct linux_prom_irqs *prom_irqs;
struct device_node *dp;
+ unsigned int irq;
const u32 *addr;
int err;
@@ -163,9 +196,9 @@ static void __init sun4c_init_timers(irq_handler_t counter_fn)
sun4c_timers = (void __iomem *) (unsigned long) addr[0];
- irq = of_get_property(dp, "intr", NULL);
+ prom_irqs = of_get_property(dp, "intr", NULL);
of_node_put(dp);
- if (!irq) {
+ if (!prom_irqs) {
prom_printf("sun4c_init_timers: No intr property\n");
prom_halt();
}
@@ -178,15 +211,15 @@ static void __init sun4c_init_timers(irq_handler_t counter_fn)
master_l10_counter = &sun4c_timers->l10_count;
- err = request_irq(irq[0].pri, counter_fn,
- (IRQF_DISABLED | SA_STATIC_ALLOC),
- "timer", NULL);
+ irq = sun4c_build_device_irq(NULL, prom_irqs[0].pri);
+ err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL);
if (err) {
prom_printf("sun4c_init_timers: request_irq() fails with %d\n", err);
prom_halt();
}
- sun4c_disable_irq(irq[1].pri);
+ /* disable timer interrupt */
+ sun4c_mask_irq(irq_get_irq_data(irq));
}
#ifdef CONFIG_SMP
@@ -215,14 +248,11 @@ void __init sun4c_init_IRQ(void)
interrupt_enable = (void __iomem *) (unsigned long) addr[0];
- BTFIXUPSET_CALL(enable_irq, sun4c_enable_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(disable_irq, sun4c_disable_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(enable_pil_irq, sun4c_enable_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(disable_pil_irq, sun4c_disable_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP);
- sparc_irq_config.init_timers = sun4c_init_timers;
+ sparc_irq_config.init_timers = sun4c_init_timers;
+ sparc_irq_config.build_device_irq = sun4c_build_device_irq;
#ifdef CONFIG_SMP
BTFIXUPSET_CALL(set_cpu_int, sun4c_nop, BTFIXUPCALL_NOP);
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
index 77b4a8992710..a9ea60eb2c10 100644
--- a/arch/sparc/kernel/sun4d_irq.c
+++ b/arch/sparc/kernel/sun4d_irq.c
@@ -14,6 +14,7 @@
#include <asm/io.h>
#include <asm/sbi.h>
#include <asm/cacheflush.h>
+#include <asm/setup.h>
#include "kernel.h"
#include "irq.h"
@@ -22,22 +23,20 @@
* cpu local. CPU local interrupts cover the timer interrupts
* and whatnot, and we encode those as normal PILs between
* 0 and 15.
- *
- * SBUS interrupts are encoded integers including the board number
- * (plus one), the SBUS level, and the SBUS slot number. Sun4D
- * IRQ dispatch is done by:
- *
- * 1) Reading the BW local interrupt table in order to get the bus
- * interrupt mask.
- *
- * This table is indexed by SBUS interrupt level which can be
- * derived from the PIL we got interrupted on.
- *
- * 2) For each bus showing interrupt pending from #1, read the
- * SBI interrupt state register. This will indicate which slots
- * have interrupts pending for that SBUS interrupt level.
+ * SBUS interrupts are encodes as a combination of board, level and slot.
*/
+struct sun4d_handler_data {
+ unsigned int cpuid; /* target cpu */
+ unsigned int real_irq; /* interrupt level */
+};
+
+
+static unsigned int sun4d_encode_irq(int board, int lvl, int slot)
+{
+ return (board + 1) << 5 | (lvl << 2) | slot;
+}
+
struct sun4d_timer_regs {
u32 l10_timer_limit;
u32 l10_cur_countx;
@@ -48,17 +47,12 @@ struct sun4d_timer_regs {
static struct sun4d_timer_regs __iomem *sun4d_timers;
-#define TIMER_IRQ 10
-
-#define MAX_STATIC_ALLOC 4
-static unsigned char sbus_tid[32];
-
-static struct irqaction *irq_action[NR_IRQS];
+#define SUN4D_TIMER_IRQ 10
-static struct sbus_action {
- struct irqaction *action;
- /* For SMP this needs to be extended */
-} *sbus_actions;
+/* Specify which cpu handle interrupts from which board.
+ * Index is board - value is cpu.
+ */
+static unsigned char board_to_cpu[32];
static int pil_to_sbus[] = {
0,
@@ -79,152 +73,81 @@ static int pil_to_sbus[] = {
0,
};
-static int sbus_to_pil[] = {
- 0,
- 2,
- 3,
- 5,
- 7,
- 9,
- 11,
- 13,
-};
-
-static int nsbi;
-
/* Exported for sun4d_smp.c */
DEFINE_SPINLOCK(sun4d_imsk_lock);
-int show_sun4d_interrupts(struct seq_file *p, void *v)
+/* SBUS interrupts are encoded integers including the board number
+ * (plus one), the SBUS level, and the SBUS slot number. Sun4D
+ * IRQ dispatch is done by:
+ *
+ * 1) Reading the BW local interrupt table in order to get the bus
+ * interrupt mask.
+ *
+ * This table is indexed by SBUS interrupt level which can be
+ * derived from the PIL we got interrupted on.
+ *
+ * 2) For each bus showing interrupt pending from #1, read the
+ * SBI interrupt state register. This will indicate which slots
+ * have interrupts pending for that SBUS interrupt level.
+ *
+ * 3) Call the genreric IRQ support.
+ */
+static void sun4d_sbus_handler_irq(int sbusl)
{
- int i = *(loff_t *) v, j = 0, k = 0, sbusl;
- struct irqaction *action;
- unsigned long flags;
-#ifdef CONFIG_SMP
- int x;
-#endif
-
- spin_lock_irqsave(&irq_action_lock, flags);
- if (i < NR_IRQS) {
- sbusl = pil_to_sbus[i];
- if (!sbusl) {
- action = *(i + irq_action);
- if (!action)
- goto out_unlock;
- } else {
- for (j = 0; j < nsbi; j++) {
- for (k = 0; k < 4; k++)
- action = sbus_actions[(j << 5) + (sbusl << 2) + k].action;
- if (action)
- goto found_it;
- }
- goto out_unlock;
- }
-found_it: seq_printf(p, "%3d: ", i);
-#ifndef CONFIG_SMP
- seq_printf(p, "%10u ", kstat_irqs(i));
-#else
- for_each_online_cpu(x)
- seq_printf(p, "%10u ",
- kstat_cpu(cpu_logical_map(x)).irqs[i]);
-#endif
- seq_printf(p, "%c %s",
- (action->flags & IRQF_DISABLED) ? '+' : ' ',
- action->name);
- action = action->next;
- for (;;) {
- for (; action; action = action->next) {
- seq_printf(p, ",%s %s",
- (action->flags & IRQF_DISABLED) ? " +" : "",
- action->name);
- }
- if (!sbusl)
- break;
- k++;
- if (k < 4) {
- action = sbus_actions[(j << 5) + (sbusl << 2) + k].action;
- } else {
- j++;
- if (j == nsbi)
- break;
- k = 0;
- action = sbus_actions[(j << 5) + (sbusl << 2)].action;
+ unsigned int bus_mask;
+ unsigned int sbino, slot;
+ unsigned int sbil;
+
+ bus_mask = bw_get_intr_mask(sbusl) & 0x3ffff;
+ bw_clear_intr_mask(sbusl, bus_mask);
+
+ sbil = (sbusl << 2);
+ /* Loop for each pending SBI */
+ for (sbino = 0; bus_mask; sbino++) {
+ unsigned int idx, mask;
+
+ bus_mask >>= 1;
+ if (!(bus_mask & 1))
+ continue;
+ /* XXX This seems to ACK the irq twice. acquire_sbi()
+ * XXX uses swap, therefore this writes 0xf << sbil,
+ * XXX then later release_sbi() will write the individual
+ * XXX bits which were set again.
+ */
+ mask = acquire_sbi(SBI2DEVID(sbino), 0xf << sbil);
+ mask &= (0xf << sbil);
+
+ /* Loop for each pending SBI slot */
+ idx = 0;
+ slot = (1 << sbil);
+ while (mask != 0) {
+ unsigned int pil;
+ struct irq_bucket *p;
+
+ idx++;
+ slot <<= 1;
+ if (!(mask & slot))
+ continue;
+
+ mask &= ~slot;
+ pil = sun4d_encode_irq(sbino, sbil, idx);
+
+ p = irq_map[pil];
+ while (p) {
+ struct irq_bucket *next;
+
+ next = p->next;
+ generic_handle_irq(p->irq);
+ p = next;
}
+ release_sbi(SBI2DEVID(sbino), slot);
}
- seq_putc(p, '\n');
}
-out_unlock:
- spin_unlock_irqrestore(&irq_action_lock, flags);
- return 0;
-}
-
-void sun4d_free_irq(unsigned int irq, void *dev_id)
-{
- struct irqaction *action, **actionp;
- struct irqaction *tmp = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&irq_action_lock, flags);
- if (irq < 15)
- actionp = irq + irq_action;
- else
- actionp = &(sbus_actions[irq - (1 << 5)].action);
- action = *actionp;
- if (!action) {
- printk(KERN_ERR "Trying to free free IRQ%d\n", irq);
- goto out_unlock;
- }
- if (dev_id) {
- for (; action; action = action->next) {
- if (action->dev_id == dev_id)
- break;
- tmp = action;
- }
- if (!action) {
- printk(KERN_ERR "Trying to free free shared IRQ%d\n",
- irq);
- goto out_unlock;
- }
- } else if (action->flags & IRQF_SHARED) {
- printk(KERN_ERR "Trying to free shared IRQ%d with NULL device ID\n",
- irq);
- goto out_unlock;
- }
- if (action->flags & SA_STATIC_ALLOC) {
- /*
- * This interrupt is marked as specially allocated
- * so it is a bad idea to free it.
- */
- printk(KERN_ERR "Attempt to free statically allocated IRQ%d (%s)\n",
- irq, action->name);
- goto out_unlock;
- }
-
- if (tmp)
- tmp->next = action->next;
- else
- *actionp = action->next;
-
- spin_unlock_irqrestore(&irq_action_lock, flags);
-
- synchronize_irq(irq);
-
- spin_lock_irqsave(&irq_action_lock, flags);
-
- kfree(action);
-
- if (!(*actionp))
- __disable_irq(irq);
-
-out_unlock:
- spin_unlock_irqrestore(&irq_action_lock, flags);
}
void sun4d_handler_irq(int pil, struct pt_regs *regs)
{
struct pt_regs *old_regs;
- struct irqaction *action;
- int cpu = smp_processor_id();
/* SBUS IRQ level (1 - 7) */
int sbusl = pil_to_sbus[pil];
@@ -233,160 +156,96 @@ void sun4d_handler_irq(int pil, struct pt_regs *regs)
cc_set_iclr(1 << pil);
+#ifdef CONFIG_SMP
+ /*
+ * Check IPI data structures after IRQ has been cleared. Hard and Soft
+ * IRQ can happen at the same time, so both cases are always handled.
+ */
+ if (pil == SUN4D_IPI_IRQ)
+ sun4d_ipi_interrupt();
+#endif
+
old_regs = set_irq_regs(regs);
irq_enter();
- kstat_cpu(cpu).irqs[pil]++;
- if (!sbusl) {
- action = *(pil + irq_action);
- if (!action)
- unexpected_irq(pil, NULL, regs);
- do {
- action->handler(pil, action->dev_id);
- action = action->next;
- } while (action);
+ if (sbusl == 0) {
+ /* cpu interrupt */
+ struct irq_bucket *p;
+
+ p = irq_map[pil];
+ while (p) {
+ struct irq_bucket *next;
+
+ next = p->next;
+ generic_handle_irq(p->irq);
+ p = next;
+ }
} else {
- int bus_mask = bw_get_intr_mask(sbusl) & 0x3ffff;
- int sbino;
- struct sbus_action *actionp;
- unsigned mask, slot;
- int sbil = (sbusl << 2);
-
- bw_clear_intr_mask(sbusl, bus_mask);
-
- /* Loop for each pending SBI */
- for (sbino = 0; bus_mask; sbino++, bus_mask >>= 1)
- if (bus_mask & 1) {
- mask = acquire_sbi(SBI2DEVID(sbino), 0xf << sbil);
- mask &= (0xf << sbil);
- actionp = sbus_actions + (sbino << 5) + (sbil);
- /* Loop for each pending SBI slot */
- for (slot = (1 << sbil); mask; slot <<= 1, actionp++)
- if (mask & slot) {
- mask &= ~slot;
- action = actionp->action;
-
- if (!action)
- unexpected_irq(pil, NULL, regs);
- do {
- action->handler(pil, action->dev_id);
- action = action->next;
- } while (action);
- release_sbi(SBI2DEVID(sbino), slot);
- }
- }
+ /* SBUS interrupt */
+ sun4d_sbus_handler_irq(sbusl);
}
irq_exit();
set_irq_regs(old_regs);
}
-int sun4d_request_irq(unsigned int irq,
- irq_handler_t handler,
- unsigned long irqflags, const char *devname, void *dev_id)
+
+static void sun4d_mask_irq(struct irq_data *data)
{
- struct irqaction *action, *tmp = NULL, **actionp;
+ struct sun4d_handler_data *handler_data = data->handler_data;
+ unsigned int real_irq;
+#ifdef CONFIG_SMP
+ int cpuid = handler_data->cpuid;
unsigned long flags;
- int ret;
-
- if (irq > 14 && irq < (1 << 5)) {
- ret = -EINVAL;
- goto out;
- }
-
- if (!handler) {
- ret = -EINVAL;
- goto out;
- }
-
- spin_lock_irqsave(&irq_action_lock, flags);
-
- if (irq >= (1 << 5))
- actionp = &(sbus_actions[irq - (1 << 5)].action);
- else
- actionp = irq + irq_action;
- action = *actionp;
-
- if (action) {
- if ((action->flags & IRQF_SHARED) && (irqflags & IRQF_SHARED)) {
- for (tmp = action; tmp->next; tmp = tmp->next)
- /* find last entry - tmp used below */;
- } else {
- ret = -EBUSY;
- goto out_unlock;
- }
- if ((action->flags & IRQF_DISABLED) ^ (irqflags & IRQF_DISABLED)) {
- printk(KERN_ERR "Attempt to mix fast and slow interrupts on IRQ%d denied\n",
- irq);
- ret = -EBUSY;
- goto out_unlock;
- }
- action = NULL; /* Or else! */
- }
-
- /* If this is flagged as statically allocated then we use our
- * private struct which is never freed.
- */
- if (irqflags & SA_STATIC_ALLOC) {
- if (static_irq_count < MAX_STATIC_ALLOC)
- action = &static_irqaction[static_irq_count++];
- else
- printk(KERN_ERR "Request for IRQ%d (%s) SA_STATIC_ALLOC failed using kmalloc\n",
- irq, devname);
- }
-
- if (action == NULL)
- action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);
-
- if (!action) {
- ret = -ENOMEM;
- goto out_unlock;
- }
-
- action->handler = handler;
- action->flags = irqflags;
- action->name = devname;
- action->next = NULL;
- action->dev_id = dev_id;
-
- if (tmp)
- tmp->next = action;
- else
- *actionp = action;
-
- __enable_irq(irq);
-
- ret = 0;
-out_unlock:
- spin_unlock_irqrestore(&irq_action_lock, flags);
-out:
- return ret;
+#endif
+ real_irq = handler_data->real_irq;
+#ifdef CONFIG_SMP
+ spin_lock_irqsave(&sun4d_imsk_lock, flags);
+ cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) | (1 << real_irq));
+ spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
+#else
+ cc_set_imsk(cc_get_imsk() | (1 << real_irq));
+#endif
}
-static void sun4d_disable_irq(unsigned int irq)
+static void sun4d_unmask_irq(struct irq_data *data)
{
- int tid = sbus_tid[(irq >> 5) - 1];
+ struct sun4d_handler_data *handler_data = data->handler_data;
+ unsigned int real_irq;
+#ifdef CONFIG_SMP
+ int cpuid = handler_data->cpuid;
unsigned long flags;
+#endif
+ real_irq = handler_data->real_irq;
- if (irq < NR_IRQS)
- return;
-
+#ifdef CONFIG_SMP
spin_lock_irqsave(&sun4d_imsk_lock, flags);
- cc_set_imsk_other(tid, cc_get_imsk_other(tid) | (1 << sbus_to_pil[(irq >> 2) & 7]));
+ cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) | ~(1 << real_irq));
spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
+#else
+ cc_set_imsk(cc_get_imsk() | ~(1 << real_irq));
+#endif
}
-static void sun4d_enable_irq(unsigned int irq)
+static unsigned int sun4d_startup_irq(struct irq_data *data)
{
- int tid = sbus_tid[(irq >> 5) - 1];
- unsigned long flags;
-
- if (irq < NR_IRQS)
- return;
+ irq_link(data->irq);
+ sun4d_unmask_irq(data);
+ return 0;
+}
- spin_lock_irqsave(&sun4d_imsk_lock, flags);
- cc_set_imsk_other(tid, cc_get_imsk_other(tid) & ~(1 << sbus_to_pil[(irq >> 2) & 7]));
- spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
+static void sun4d_shutdown_irq(struct irq_data *data)
+{
+ sun4d_mask_irq(data);
+ irq_unlink(data->irq);
}
+struct irq_chip sun4d_irq = {
+ .name = "sun4d",
+ .irq_startup = sun4d_startup_irq,
+ .irq_shutdown = sun4d_shutdown_irq,
+ .irq_unmask = sun4d_unmask_irq,
+ .irq_mask = sun4d_mask_irq,
+};
+
#ifdef CONFIG_SMP
static void sun4d_set_cpu_int(int cpu, int level)
{
@@ -413,7 +272,7 @@ void __init sun4d_distribute_irqs(void)
for_each_node_by_name(dp, "sbi") {
int devid = of_getintprop_default(dp, "device-id", 0);
int board = of_getintprop_default(dp, "board#", 0);
- sbus_tid[board] = cpuid;
+ board_to_cpu[board] = cpuid;
set_sbi_tid(devid, cpuid << 3);
}
printk(KERN_ERR "All sbus IRQs directed to CPU%d\n", cpuid);
@@ -443,15 +302,16 @@ static void __init sun4d_load_profile_irqs(void)
unsigned int sun4d_build_device_irq(struct platform_device *op,
unsigned int real_irq)
{
- static int pil_to_sbus[] = {
- 0, 0, 1, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 0,
- };
struct device_node *dp = op->dev.of_node;
struct device_node *io_unit, *sbi = dp->parent;
const struct linux_prom_registers *regs;
+ struct sun4d_handler_data *handler_data;
+ unsigned int pil;
+ unsigned int irq;
int board, slot;
int sbusl;
+ irq = 0;
while (sbi) {
if (!strcmp(sbi->name, "sbi"))
break;
@@ -484,7 +344,28 @@ unsigned int sun4d_build_device_irq(struct platform_device *op,
sbusl = pil_to_sbus[real_irq];
if (sbusl)
- return (((board + 1) << 5) + (sbusl << 2) + slot);
+ pil = sun4d_encode_irq(board, sbusl, slot);
+ else
+ pil = real_irq;
+
+ irq = irq_alloc(real_irq, pil);
+ if (irq == 0)
+ goto err_out;
+
+ handler_data = irq_get_handler_data(irq);
+ if (unlikely(handler_data))
+ goto err_out;
+
+ handler_data = kzalloc(sizeof(struct sun4d_handler_data), GFP_ATOMIC);
+ if (unlikely(!handler_data)) {
+ prom_printf("IRQ: kzalloc(sun4d_handler_data) failed.\n");
+ prom_halt();
+ }
+ handler_data->cpuid = board_to_cpu[board];
+ handler_data->real_irq = real_irq;
+ irq_set_chip_and_handler_name(irq, &sun4d_irq,
+ handle_level_irq, "level");
+ irq_set_handler_data(irq, handler_data);
err_out:
return real_irq;
@@ -518,6 +399,7 @@ static void __init sun4d_init_timers(irq_handler_t counter_fn)
{
struct device_node *dp;
struct resource res;
+ unsigned int irq;
const u32 *reg;
int err;
@@ -552,9 +434,8 @@ static void __init sun4d_init_timers(irq_handler_t counter_fn)
master_l10_counter = &sun4d_timers->l10_cur_count;
- err = request_irq(TIMER_IRQ, counter_fn,
- (IRQF_DISABLED | SA_STATIC_ALLOC),
- "timer", NULL);
+ irq = sun4d_build_device_irq(NULL, SUN4D_TIMER_IRQ);
+ err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL);
if (err) {
prom_printf("sun4d_init_timers: request_irq() failed with %d\n",
err);
@@ -567,27 +448,16 @@ static void __init sun4d_init_timers(irq_handler_t counter_fn)
void __init sun4d_init_sbi_irq(void)
{
struct device_node *dp;
- int target_cpu = 0;
+ int target_cpu;
-#ifdef CONFIG_SMP
target_cpu = boot_cpu_id;
-#endif
-
- nsbi = 0;
- for_each_node_by_name(dp, "sbi")
- nsbi++;
- sbus_actions = kzalloc(nsbi * 8 * 4 * sizeof(struct sbus_action), GFP_ATOMIC);
- if (!sbus_actions) {
- prom_printf("SUN4D: Cannot allocate sbus_actions, halting.\n");
- prom_halt();
- }
for_each_node_by_name(dp, "sbi") {
int devid = of_getintprop_default(dp, "device-id", 0);
int board = of_getintprop_default(dp, "board#", 0);
unsigned int mask;
set_sbi_tid(devid, target_cpu << 3);
- sbus_tid[board] = target_cpu;
+ board_to_cpu[board] = target_cpu;
/* Get rid of pending irqs from PROM */
mask = acquire_sbi(devid, 0xffffffff);
@@ -603,12 +473,10 @@ void __init sun4d_init_IRQ(void)
{
local_irq_disable();
- BTFIXUPSET_CALL(enable_irq, sun4d_enable_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(disable_irq, sun4d_disable_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM);
- sparc_irq_config.init_timers = sun4d_init_timers;
+ sparc_irq_config.init_timers = sun4d_init_timers;
sparc_irq_config.build_device_irq = sun4d_build_device_irq;
#ifdef CONFIG_SMP
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index 475d50b96cd0..133387980b56 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -32,6 +32,7 @@ static inline unsigned long sun4d_swap(volatile unsigned long *ptr, unsigned lon
return val;
}
+static void smp4d_ipi_init(void);
static void smp_setup_percpu_timer(void);
static unsigned char cpu_leds[32];
@@ -80,8 +81,6 @@ void __cpuinit smp4d_callin(void)
local_flush_cache_all();
local_flush_tlb_all();
- cpu_probe();
-
while ((unsigned long)current_set[cpuid] < PAGE_OFFSET)
barrier();
@@ -105,7 +104,7 @@ void __cpuinit smp4d_callin(void)
local_irq_enable(); /* We don't allow PIL 14 yet */
- while (!cpu_isset(cpuid, smp_commenced_mask))
+ while (!cpumask_test_cpu(cpuid, &smp_commenced_mask))
barrier();
spin_lock_irqsave(&sun4d_imsk_lock, flags);
@@ -120,6 +119,7 @@ void __cpuinit smp4d_callin(void)
*/
void __init smp4d_boot_cpus(void)
{
+ smp4d_ipi_init();
if (boot_cpu_id)
current_set[0] = NULL;
smp_setup_percpu_timer();
@@ -191,6 +191,80 @@ void __init smp4d_smp_done(void)
sun4d_distribute_irqs();
}
+/* Memory structure giving interrupt handler information about IPI generated */
+struct sun4d_ipi_work {
+ int single;
+ int msk;
+ int resched;
+};
+
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct sun4d_ipi_work, sun4d_ipi_work);
+
+/* Initialize IPIs on the SUN4D SMP machine */
+static void __init smp4d_ipi_init(void)
+{
+ int cpu;
+ struct sun4d_ipi_work *work;
+
+ printk(KERN_INFO "smp4d: setup IPI at IRQ %d\n", SUN4D_IPI_IRQ);
+
+ for_each_possible_cpu(cpu) {
+ work = &per_cpu(sun4d_ipi_work, cpu);
+ work->single = work->msk = work->resched = 0;
+ }
+}
+
+void sun4d_ipi_interrupt(void)
+{
+ struct sun4d_ipi_work *work = &__get_cpu_var(sun4d_ipi_work);
+
+ if (work->single) {
+ work->single = 0;
+ smp_call_function_single_interrupt();
+ }
+ if (work->msk) {
+ work->msk = 0;
+ smp_call_function_interrupt();
+ }
+ if (work->resched) {
+ work->resched = 0;
+ smp_resched_interrupt();
+ }
+}
+
+static void smp4d_ipi_single(int cpu)
+{
+ struct sun4d_ipi_work *work = &per_cpu(sun4d_ipi_work, cpu);
+
+ /* Mark work */
+ work->single = 1;
+
+ /* Generate IRQ on the CPU */
+ sun4d_send_ipi(cpu, SUN4D_IPI_IRQ);
+}
+
+static void smp4d_ipi_mask_one(int cpu)
+{
+ struct sun4d_ipi_work *work = &per_cpu(sun4d_ipi_work, cpu);
+
+ /* Mark work */
+ work->msk = 1;
+
+ /* Generate IRQ on the CPU */
+ sun4d_send_ipi(cpu, SUN4D_IPI_IRQ);
+}
+
+static void smp4d_ipi_resched(int cpu)
+{
+ struct sun4d_ipi_work *work = &per_cpu(sun4d_ipi_work, cpu);
+
+ /* Mark work */
+ work->resched = 1;
+
+ /* Generate IRQ on the CPU (any IRQ will cause resched) */
+ sun4d_send_ipi(cpu, SUN4D_IPI_IRQ);
+}
+
static struct smp_funcall {
smpfunc_t func;
unsigned long arg1;
@@ -239,10 +313,10 @@ static void smp4d_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
{
register int i;
- cpu_clear(smp_processor_id(), mask);
- cpus_and(mask, cpu_online_map, mask);
+ cpumask_clear_cpu(smp_processor_id(), &mask);
+ cpumask_and(&mask, cpu_online_mask, &mask);
for (i = 0; i <= high; i++) {
- if (cpu_isset(i, mask)) {
+ if (cpumask_test_cpu(i, &mask)) {
ccall_info.processors_in[i] = 0;
ccall_info.processors_out[i] = 0;
sun4d_send_ipi(i, IRQ_CROSS_CALL);
@@ -255,7 +329,7 @@ static void smp4d_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
i = 0;
do {
- if (!cpu_isset(i, mask))
+ if (!cpumask_test_cpu(i, &mask))
continue;
while (!ccall_info.processors_in[i])
barrier();
@@ -263,7 +337,7 @@ static void smp4d_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
i = 0;
do {
- if (!cpu_isset(i, mask))
+ if (!cpumask_test_cpu(i, &mask))
continue;
while (!ccall_info.processors_out[i])
barrier();
@@ -356,6 +430,9 @@ void __init sun4d_init_smp(void)
BTFIXUPSET_BLACKBOX(load_current, smp4d_blackbox_current);
BTFIXUPSET_CALL(smp_cross_call, smp4d_cross_call, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(__hard_smp_processor_id, __smp4d_processor_id, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(smp_ipi_resched, smp4d_ipi_resched, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(smp_ipi_single, smp4d_ipi_single, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(smp_ipi_mask_one, smp4d_ipi_mask_one, BTFIXUPCALL_NORM);
for (i = 0; i < NR_CPUS; i++) {
ccall_info.processors_in[i] = 1;
diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c
index 69df6257a32e..422c16dad1f6 100644
--- a/arch/sparc/kernel/sun4m_irq.c
+++ b/arch/sparc/kernel/sun4m_irq.c
@@ -100,6 +100,11 @@
struct sun4m_irq_percpu __iomem *sun4m_irq_percpu[SUN4M_NCPUS];
struct sun4m_irq_global __iomem *sun4m_irq_global;
+struct sun4m_handler_data {
+ bool percpu;
+ long mask;
+};
+
/* Dave Redman (djhr@tadpole.co.uk)
* The sun4m interrupt registers.
*/
@@ -142,9 +147,9 @@ struct sun4m_irq_global __iomem *sun4m_irq_global;
#define OBP_INT_LEVEL_VME 0x40
#define SUN4M_TIMER_IRQ (OBP_INT_LEVEL_ONBOARD | 10)
-#define SUM4M_PROFILE_IRQ (OBP_INT_LEVEL_ONBOARD | 14)
+#define SUN4M_PROFILE_IRQ (OBP_INT_LEVEL_ONBOARD | 14)
-static unsigned long irq_mask[0x50] = {
+static unsigned long sun4m_imask[0x50] = {
/* 0x00 - SMP */
0, SUN4M_SOFT_INT(1),
SUN4M_SOFT_INT(2), SUN4M_SOFT_INT(3),
@@ -169,7 +174,7 @@ static unsigned long irq_mask[0x50] = {
SUN4M_INT_VIDEO, SUN4M_INT_MODULE,
SUN4M_INT_REALTIME, SUN4M_INT_FLOPPY,
(SUN4M_INT_SERIAL | SUN4M_INT_KBDMS),
- SUN4M_INT_AUDIO, 0, SUN4M_INT_MODULE_ERR,
+ SUN4M_INT_AUDIO, SUN4M_INT_E14, SUN4M_INT_MODULE_ERR,
/* 0x30 - sbus */
0, 0, SUN4M_INT_SBUS(0), SUN4M_INT_SBUS(1),
0, SUN4M_INT_SBUS(2), 0, SUN4M_INT_SBUS(3),
@@ -182,105 +187,110 @@ static unsigned long irq_mask[0x50] = {
0, SUN4M_INT_VME(6), 0, 0
};
-static unsigned long sun4m_get_irqmask(unsigned int irq)
+static void sun4m_mask_irq(struct irq_data *data)
{
- unsigned long mask;
-
- if (irq < 0x50)
- mask = irq_mask[irq];
- else
- mask = 0;
+ struct sun4m_handler_data *handler_data = data->handler_data;
+ int cpu = smp_processor_id();
- if (!mask)
- printk(KERN_ERR "sun4m_get_irqmask: IRQ%d has no valid mask!\n",
- irq);
+ if (handler_data->mask) {
+ unsigned long flags;
- return mask;
+ local_irq_save(flags);
+ if (handler_data->percpu) {
+ sbus_writel(handler_data->mask, &sun4m_irq_percpu[cpu]->set);
+ } else {
+ sbus_writel(handler_data->mask, &sun4m_irq_global->mask_set);
+ }
+ local_irq_restore(flags);
+ }
}
-static void sun4m_disable_irq(unsigned int irq_nr)
+static void sun4m_unmask_irq(struct irq_data *data)
{
- unsigned long mask, flags;
+ struct sun4m_handler_data *handler_data = data->handler_data;
int cpu = smp_processor_id();
- mask = sun4m_get_irqmask(irq_nr);
- local_irq_save(flags);
- if (irq_nr > 15)
- sbus_writel(mask, &sun4m_irq_global->mask_set);
- else
- sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
- local_irq_restore(flags);
-}
-
-static void sun4m_enable_irq(unsigned int irq_nr)
-{
- unsigned long mask, flags;
- int cpu = smp_processor_id();
+ if (handler_data->mask) {
+ unsigned long flags;
- /* Dreadful floppy hack. When we use 0x2b instead of
- * 0x0b the system blows (it starts to whistle!).
- * So we continue to use 0x0b. Fixme ASAP. --P3
- */
- if (irq_nr != 0x0b) {
- mask = sun4m_get_irqmask(irq_nr);
- local_irq_save(flags);
- if (irq_nr > 15)
- sbus_writel(mask, &sun4m_irq_global->mask_clear);
- else
- sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
- local_irq_restore(flags);
- } else {
local_irq_save(flags);
- sbus_writel(SUN4M_INT_FLOPPY, &sun4m_irq_global->mask_clear);
+ if (handler_data->percpu) {
+ sbus_writel(handler_data->mask, &sun4m_irq_percpu[cpu]->clear);
+ } else {
+ sbus_writel(handler_data->mask, &sun4m_irq_global->mask_clear);
+ }
local_irq_restore(flags);
}
}
-static unsigned long cpu_pil_to_imask[16] = {
-/*0*/ 0x00000000,
-/*1*/ 0x00000000,
-/*2*/ SUN4M_INT_SBUS(0) | SUN4M_INT_VME(0),
-/*3*/ SUN4M_INT_SBUS(1) | SUN4M_INT_VME(1),
-/*4*/ SUN4M_INT_SCSI,
-/*5*/ SUN4M_INT_SBUS(2) | SUN4M_INT_VME(2),
-/*6*/ SUN4M_INT_ETHERNET,
-/*7*/ SUN4M_INT_SBUS(3) | SUN4M_INT_VME(3),
-/*8*/ SUN4M_INT_VIDEO,
-/*9*/ SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR,
-/*10*/ SUN4M_INT_REALTIME,
-/*11*/ SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY,
-/*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS,
-/*13*/ SUN4M_INT_SBUS(6) | SUN4M_INT_VME(6) | SUN4M_INT_AUDIO,
-/*14*/ SUN4M_INT_E14,
-/*15*/ SUN4M_INT_ERROR,
-};
+static unsigned int sun4m_startup_irq(struct irq_data *data)
+{
+ irq_link(data->irq);
+ sun4m_unmask_irq(data);
+ return 0;
+}
-/* We assume the caller has disabled local interrupts when these are called,
- * or else very bizarre behavior will result.
- */
-static void sun4m_disable_pil_irq(unsigned int pil)
+static void sun4m_shutdown_irq(struct irq_data *data)
{
- sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_set);
+ sun4m_mask_irq(data);
+ irq_unlink(data->irq);
}
-static void sun4m_enable_pil_irq(unsigned int pil)
+static struct irq_chip sun4m_irq = {
+ .name = "sun4m",
+ .irq_startup = sun4m_startup_irq,
+ .irq_shutdown = sun4m_shutdown_irq,
+ .irq_mask = sun4m_mask_irq,
+ .irq_unmask = sun4m_unmask_irq,
+};
+
+
+static unsigned int sun4m_build_device_irq(struct platform_device *op,
+ unsigned int real_irq)
{
- sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_clear);
+ struct sun4m_handler_data *handler_data;
+ unsigned int irq;
+ unsigned int pil;
+
+ if (real_irq >= OBP_INT_LEVEL_VME) {
+ prom_printf("Bogus sun4m IRQ %u\n", real_irq);
+ prom_halt();
+ }
+ pil = (real_irq & 0xf);
+ irq = irq_alloc(real_irq, pil);
+
+ if (irq == 0)
+ goto out;
+
+ handler_data = irq_get_handler_data(irq);
+ if (unlikely(handler_data))
+ goto out;
+
+ handler_data = kzalloc(sizeof(struct sun4m_handler_data), GFP_ATOMIC);
+ if (unlikely(!handler_data)) {
+ prom_printf("IRQ: kzalloc(sun4m_handler_data) failed.\n");
+ prom_halt();
+ }
+
+ handler_data->mask = sun4m_imask[real_irq];
+ handler_data->percpu = real_irq < OBP_INT_LEVEL_ONBOARD;
+ irq_set_chip_and_handler_name(irq, &sun4m_irq,
+ handle_level_irq, "level");
+ irq_set_handler_data(irq, handler_data);
+
+out:
+ return irq;
}
#ifdef CONFIG_SMP
static void sun4m_send_ipi(int cpu, int level)
{
- unsigned long mask = sun4m_get_irqmask(level);
-
- sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
+ sbus_writel(SUN4M_SOFT_INT(level), &sun4m_irq_percpu[cpu]->set);
}
static void sun4m_clear_ipi(int cpu, int level)
{
- unsigned long mask = sun4m_get_irqmask(level);
-
- sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
+ sbus_writel(SUN4M_SOFT_INT(level), &sun4m_irq_percpu[cpu]->clear);
}
static void sun4m_set_udt(int cpu)
@@ -343,7 +353,15 @@ void sun4m_nmi(struct pt_regs *regs)
prom_halt();
}
-/* Exported for sun4m_smp.c */
+void sun4m_unmask_profile_irq(void)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ sbus_writel(sun4m_imask[SUN4M_PROFILE_IRQ], &sun4m_irq_global->mask_clear);
+ local_irq_restore(flags);
+}
+
void sun4m_clear_profile_irq(int cpu)
{
sbus_readl(&timers_percpu[cpu]->l14_limit);
@@ -358,6 +376,7 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn)
{
struct device_node *dp = of_find_node_by_name(NULL, "counter");
int i, err, len, num_cpu_timers;
+ unsigned int irq;
const u32 *addr;
if (!dp) {
@@ -384,8 +403,9 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn)
master_l10_counter = &timers_global->l10_count;
- err = request_irq(SUN4M_TIMER_IRQ, counter_fn,
- (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL);
+ irq = sun4m_build_device_irq(NULL, SUN4M_TIMER_IRQ);
+
+ err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL);
if (err) {
printk(KERN_ERR "sun4m_init_timers: Register IRQ error %d.\n",
err);
@@ -452,14 +472,11 @@ void __init sun4m_init_IRQ(void)
if (num_cpu_iregs == 4)
sbus_writel(0, &sun4m_irq_global->interrupt_target);
- BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM);
sparc_irq_config.init_timers = sun4m_init_timers;
+ sparc_irq_config.build_device_irq = sun4m_build_device_irq;
#ifdef CONFIG_SMP
BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM);
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
index 5cc7dc51de3d..594768686525 100644
--- a/arch/sparc/kernel/sun4m_smp.c
+++ b/arch/sparc/kernel/sun4m_smp.c
@@ -15,6 +15,9 @@
#include "irq.h"
#include "kernel.h"
+#define IRQ_IPI_SINGLE 12
+#define IRQ_IPI_MASK 13
+#define IRQ_IPI_RESCHED 14
#define IRQ_CROSS_CALL 15
static inline unsigned long
@@ -26,6 +29,7 @@ swap_ulong(volatile unsigned long *ptr, unsigned long val)
return val;
}
+static void smp4m_ipi_init(void);
static void smp_setup_percpu_timer(void);
void __cpuinit smp4m_callin(void)
@@ -59,8 +63,6 @@ void __cpuinit smp4m_callin(void)
local_flush_cache_all();
local_flush_tlb_all();
- cpu_probe();
-
/* Fix idle thread fields. */
__asm__ __volatile__("ld [%0], %%g6\n\t"
: : "r" (&current_set[cpuid])
@@ -70,7 +72,7 @@ void __cpuinit smp4m_callin(void)
atomic_inc(&init_mm.mm_count);
current->active_mm = &init_mm;
- while (!cpu_isset(cpuid, smp_commenced_mask))
+ while (!cpumask_test_cpu(cpuid, &smp_commenced_mask))
mb();
local_irq_enable();
@@ -83,6 +85,7 @@ void __cpuinit smp4m_callin(void)
*/
void __init smp4m_boot_cpus(void)
{
+ smp4m_ipi_init();
smp_setup_percpu_timer();
local_flush_cache_all();
}
@@ -150,18 +153,25 @@ void __init smp4m_smp_done(void)
/* Ok, they are spinning and ready to go. */
}
-/* At each hardware IRQ, we get this called to forward IRQ reception
- * to the next processor. The caller must disable the IRQ level being
- * serviced globally so that there are no double interrupts received.
- *
- * XXX See sparc64 irq.c.
- */
-void smp4m_irq_rotate(int cpu)
+
+/* Initialize IPIs on the SUN4M SMP machine */
+static void __init smp4m_ipi_init(void)
+{
+}
+
+static void smp4m_ipi_resched(int cpu)
+{
+ set_cpu_int(cpu, IRQ_IPI_RESCHED);
+}
+
+static void smp4m_ipi_single(int cpu)
{
- int next = cpu_data(cpu).next;
+ set_cpu_int(cpu, IRQ_IPI_SINGLE);
+}
- if (next != cpu)
- set_irq_udt(next);
+static void smp4m_ipi_mask_one(int cpu)
+{
+ set_cpu_int(cpu, IRQ_IPI_MASK);
}
static struct smp_funcall {
@@ -199,10 +209,10 @@ static void smp4m_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
{
register int i;
- cpu_clear(smp_processor_id(), mask);
- cpus_and(mask, cpu_online_map, mask);
+ cpumask_clear_cpu(smp_processor_id(), &mask);
+ cpumask_and(&mask, cpu_online_mask, &mask);
for (i = 0; i < ncpus; i++) {
- if (cpu_isset(i, mask)) {
+ if (cpumask_test_cpu(i, &mask)) {
ccall_info.processors_in[i] = 0;
ccall_info.processors_out[i] = 0;
set_cpu_int(i, IRQ_CROSS_CALL);
@@ -218,7 +228,7 @@ static void smp4m_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
i = 0;
do {
- if (!cpu_isset(i, mask))
+ if (!cpumask_test_cpu(i, &mask))
continue;
while (!ccall_info.processors_in[i])
barrier();
@@ -226,7 +236,7 @@ static void smp4m_cross_call(smpfunc_t func, cpumask_t mask, unsigned long arg1,
i = 0;
do {
- if (!cpu_isset(i, mask))
+ if (!cpumask_test_cpu(i, &mask))
continue;
while (!ccall_info.processors_out[i])
barrier();
@@ -277,7 +287,7 @@ static void __cpuinit smp_setup_percpu_timer(void)
load_profile_irq(cpu, lvl14_resolution);
if (cpu == boot_cpu_id)
- enable_pil_irq(14);
+ sun4m_unmask_profile_irq();
}
static void __init smp4m_blackbox_id(unsigned *addr)
@@ -306,4 +316,7 @@ void __init sun4m_init_smp(void)
BTFIXUPSET_BLACKBOX(load_current, smp4m_blackbox_current);
BTFIXUPSET_CALL(smp_cross_call, smp4m_cross_call, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(__hard_smp_processor_id, __smp4m_processor_id, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(smp_ipi_resched, smp4m_ipi_resched, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(smp_ipi_single, smp4m_ipi_single, BTFIXUPCALL_NORM);
+ BTFIXUPSET_CALL(smp_ipi_mask_one, smp4m_ipi_mask_one, BTFIXUPCALL_NORM);
}
diff --git a/arch/sparc/kernel/sysfs.c b/arch/sparc/kernel/sysfs.c
index 1eb8b00aed75..7408201d7efb 100644
--- a/arch/sparc/kernel/sysfs.c
+++ b/arch/sparc/kernel/sysfs.c
@@ -103,9 +103,10 @@ static unsigned long run_on_cpu(unsigned long cpu,
unsigned long (*func)(unsigned long),
unsigned long arg)
{
- cpumask_t old_affinity = current->cpus_allowed;
+ cpumask_t old_affinity;
unsigned long ret;
+ cpumask_copy(&old_affinity, tsk_cpus_allowed(current));
/* should return -EINVAL to userspace */
if (set_cpus_allowed_ptr(current, cpumask_of(cpu)))
return 0;
diff --git a/arch/sparc/kernel/systbls_32.S b/arch/sparc/kernel/systbls_32.S
index 47ac73c32e88..332c83ff7701 100644
--- a/arch/sparc/kernel/systbls_32.S
+++ b/arch/sparc/kernel/systbls_32.S
@@ -84,4 +84,4 @@ sys_call_table:
/*320*/ .long sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv
/*325*/ .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init
/*330*/ .long sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime
-/*335*/ .long sys_syncfs
+/*335*/ .long sys_syncfs, sys_sendmmsg
diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S
index 4f3170c1ef47..43887ca0be0e 100644
--- a/arch/sparc/kernel/systbls_64.S
+++ b/arch/sparc/kernel/systbls_64.S
@@ -85,7 +85,7 @@ sys_call_table32:
/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, compat_sys_preadv
.word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open, compat_sys_recvmmsg, sys_fanotify_init
/*330*/ .word sys32_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, compat_sys_open_by_handle_at, compat_sys_clock_adjtime
- .word sys_syncfs
+ .word sys_syncfs, compat_sys_sendmmsg
#endif /* CONFIG_COMPAT */
@@ -162,4 +162,4 @@ sys_call_table:
/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1, sys_accept4, sys_preadv
.word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init
/*330*/ .word sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime
- .word sys_syncfs
+ .word sys_syncfs, sys_sendmmsg
diff --git a/arch/sparc/kernel/time_32.c b/arch/sparc/kernel/time_32.c
index 96046a4024c2..1060e0672a4b 100644
--- a/arch/sparc/kernel/time_32.c
+++ b/arch/sparc/kernel/time_32.c
@@ -228,14 +228,10 @@ static void __init sbus_time_init(void)
void __init time_init(void)
{
-#ifdef CONFIG_PCI
- extern void pci_time_init(void);
- if (pcic_present()) {
+ if (pcic_present())
pci_time_init();
- return;
- }
-#endif
- sbus_time_init();
+ else
+ sbus_time_init();
}
diff --git a/arch/sparc/kernel/us2e_cpufreq.c b/arch/sparc/kernel/us2e_cpufreq.c
index 8f982b76c712..531d54fc9829 100644
--- a/arch/sparc/kernel/us2e_cpufreq.c
+++ b/arch/sparc/kernel/us2e_cpufreq.c
@@ -237,7 +237,7 @@ static unsigned int us2e_freq_get(unsigned int cpu)
if (!cpu_online(cpu))
return 0;
- cpus_allowed = current->cpus_allowed;
+ cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current));
set_cpus_allowed_ptr(current, cpumask_of(cpu));
clock_tick = sparc64_get_clock_tick(cpu) / 1000;
@@ -258,7 +258,7 @@ static void us2e_set_cpu_divider_index(unsigned int cpu, unsigned int index)
if (!cpu_online(cpu))
return;
- cpus_allowed = current->cpus_allowed;
+ cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current));
set_cpus_allowed_ptr(current, cpumask_of(cpu));
new_freq = clock_tick = sparc64_get_clock_tick(cpu) / 1000;
diff --git a/arch/sparc/kernel/us3_cpufreq.c b/arch/sparc/kernel/us3_cpufreq.c
index f35d1e794548..9a8ceb700833 100644
--- a/arch/sparc/kernel/us3_cpufreq.c
+++ b/arch/sparc/kernel/us3_cpufreq.c
@@ -85,7 +85,7 @@ static unsigned int us3_freq_get(unsigned int cpu)
if (!cpu_online(cpu))
return 0;
- cpus_allowed = current->cpus_allowed;
+ cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current));
set_cpus_allowed_ptr(current, cpumask_of(cpu));
reg = read_safari_cfg();
@@ -105,7 +105,7 @@ static void us3_set_cpu_divider_index(unsigned int cpu, unsigned int index)
if (!cpu_online(cpu))
return;
- cpus_allowed = current->cpus_allowed;
+ cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current));
set_cpus_allowed_ptr(current, cpumask_of(cpu));
new_freq = sparc64_get_clock_tick(cpu) / 1000;
diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S
index 92b557afe535..c0220759003e 100644
--- a/arch/sparc/kernel/vmlinux.lds.S
+++ b/arch/sparc/kernel/vmlinux.lds.S
@@ -108,7 +108,7 @@ SECTIONS
__sun4v_2insn_patch_end = .;
}
- PERCPU(SMP_CACHE_BYTES, PAGE_SIZE)
+ PERCPU_SECTION(SMP_CACHE_BYTES)
. = ALIGN(PAGE_SIZE);
__init_end = .;
diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile
index 846d1c4374ea..7f01b8fce8bc 100644
--- a/arch/sparc/lib/Makefile
+++ b/arch/sparc/lib/Makefile
@@ -15,7 +15,6 @@ lib-$(CONFIG_SPARC32) += divdi3.o udivdi3.o
lib-$(CONFIG_SPARC32) += copy_user.o locks.o
lib-y += atomic_$(BITS).o
lib-$(CONFIG_SPARC32) += lshrdi3.o ashldi3.o
-lib-$(CONFIG_SPARC32) += rwsem_32.o
lib-$(CONFIG_SPARC32) += muldi3.o bitext.o cmpdi2.o
lib-$(CONFIG_SPARC64) += copy_page.o clear_page.o bzero.o
diff --git a/arch/sparc/lib/rwsem_32.S b/arch/sparc/lib/rwsem_32.S
deleted file mode 100644
index 9675268e7fde..000000000000
--- a/arch/sparc/lib/rwsem_32.S
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Assembly part of rw semaphores.
- *
- * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com)
- */
-
-#include <asm/ptrace.h>
-#include <asm/psr.h>
-
- .section .sched.text, "ax"
- .align 4
-
- .globl ___down_read
-___down_read:
- rd %psr, %g3
- nop
- nop
- nop
- or %g3, PSR_PIL, %g7
- wr %g7, 0, %psr
- nop
- nop
- nop
-#ifdef CONFIG_SMP
-1: ldstub [%g1 + 4], %g7
- tst %g7
- bne 1b
- ld [%g1], %g7
- sub %g7, 1, %g7
- st %g7, [%g1]
- stb %g0, [%g1 + 4]
-#else
- ld [%g1], %g7
- sub %g7, 1, %g7
- st %g7, [%g1]
-#endif
- wr %g3, 0, %psr
- add %g7, 1, %g7
- nop
- nop
- subcc %g7, 1, %g7
- bneg 3f
- nop
-2: jmpl %o7, %g0
- mov %g4, %o7
-3: save %sp, -64, %sp
- mov %g1, %l1
- mov %g4, %l4
- bcs 4f
- mov %g5, %l5
- call down_read_failed
- mov %l1, %o0
- mov %l1, %g1
- mov %l4, %g4
- ba ___down_read
- restore %l5, %g0, %g5
-4: call down_read_failed_biased
- mov %l1, %o0
- mov %l1, %g1
- mov %l4, %g4
- ba 2b
- restore %l5, %g0, %g5
-
- .globl ___down_write
-___down_write:
- rd %psr, %g3
- nop
- nop
- nop
- or %g3, PSR_PIL, %g7
- wr %g7, 0, %psr
- sethi %hi(0x01000000), %g2
- nop
- nop
-#ifdef CONFIG_SMP
-1: ldstub [%g1 + 4], %g7
- tst %g7
- bne 1b
- ld [%g1], %g7
- sub %g7, %g2, %g7
- st %g7, [%g1]
- stb %g0, [%g1 + 4]
-#else
- ld [%g1], %g7
- sub %g7, %g2, %g7
- st %g7, [%g1]
-#endif
- wr %g3, 0, %psr
- add %g7, %g2, %g7
- nop
- nop
- subcc %g7, %g2, %g7
- bne 3f
- nop
-2: jmpl %o7, %g0
- mov %g4, %o7
-3: save %sp, -64, %sp
- mov %g1, %l1
- mov %g4, %l4
- bcs 4f
- mov %g5, %l5
- call down_write_failed
- mov %l1, %o0
- mov %l1, %g1
- mov %l4, %g4
- ba ___down_write
- restore %l5, %g0, %g5
-4: call down_write_failed_biased
- mov %l1, %o0
- mov %l1, %g1
- mov %l4, %g4
- ba 2b
- restore %l5, %g0, %g5
-
- .text
- .globl ___up_read
-___up_read:
- rd %psr, %g3
- nop
- nop
- nop
- or %g3, PSR_PIL, %g7
- wr %g7, 0, %psr
- nop
- nop
- nop
-#ifdef CONFIG_SMP
-1: ldstub [%g1 + 4], %g7
- tst %g7
- bne 1b
- ld [%g1], %g7
- add %g7, 1, %g7
- st %g7, [%g1]
- stb %g0, [%g1 + 4]
-#else
- ld [%g1], %g7
- add %g7, 1, %g7
- st %g7, [%g1]
-#endif
- wr %g3, 0, %psr
- nop
- nop
- nop
- cmp %g7, 0
- be 3f
- nop
-2: jmpl %o7, %g0
- mov %g4, %o7
-3: save %sp, -64, %sp
- mov %g1, %l1
- mov %g4, %l4
- mov %g5, %l5
- clr %o1
- call __rwsem_wake
- mov %l1, %o0
- mov %l1, %g1
- mov %l4, %g4
- ba 2b
- restore %l5, %g0, %g5
-
- .globl ___up_write
-___up_write:
- rd %psr, %g3
- nop
- nop
- nop
- or %g3, PSR_PIL, %g7
- wr %g7, 0, %psr
- sethi %hi(0x01000000), %g2
- nop
- nop
-#ifdef CONFIG_SMP
-1: ldstub [%g1 + 4], %g7
- tst %g7
- bne 1b
- ld [%g1], %g7
- add %g7, %g2, %g7
- st %g7, [%g1]
- stb %g0, [%g1 + 4]
-#else
- ld [%g1], %g7
- add %g7, %g2, %g7
- st %g7, [%g1]
-#endif
- wr %g3, 0, %psr
- sub %g7, %g2, %g7
- nop
- nop
- addcc %g7, %g2, %g7
- bcs 3f
- nop
-2: jmpl %o7, %g0
- mov %g4, %o7
-3: save %sp, -64, %sp
- mov %g1, %l1
- mov %g4, %l4
- mov %g5, %l5
- mov %g7, %o1
- call __rwsem_wake
- mov %l1, %o0
- mov %l1, %g1
- mov %l4, %g4
- ba 2b
- restore %l5, %g0, %g5
diff --git a/arch/sparc/mm/init_32.c b/arch/sparc/mm/init_32.c
index 4c31e2b6e71b..ca217327e8d2 100644
--- a/arch/sparc/mm/init_32.c
+++ b/arch/sparc/mm/init_32.c
@@ -37,8 +37,6 @@
#include <asm/prom.h>
#include <asm/leon.h>
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
unsigned long *sparc_valid_addr_bitmap;
EXPORT_SYMBOL(sparc_valid_addr_bitmap);
@@ -78,7 +76,7 @@ void __init kmap_init(void)
void show_mem(unsigned int filter)
{
printk("Mem-info:\n");
- show_free_areas();
+ show_free_areas(filter);
printk("Free swap: %6ldkB\n",
nr_swap_pages << (PAGE_SHIFT-10));
printk("%ld pages of RAM\n", totalram_pages);
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c
index 2f6ae1d1fb6b..e10cd03fab80 100644
--- a/arch/sparc/mm/init_64.c
+++ b/arch/sparc/mm/init_64.c
@@ -862,7 +862,7 @@ static void init_node_masks_nonnuma(void)
for (i = 0; i < NR_CPUS; i++)
numa_cpu_lookup_table[i] = 0;
- numa_cpumask_lookup_table[0] = CPU_MASK_ALL;
+ cpumask_setall(&numa_cpumask_lookup_table[0]);
}
#ifdef CONFIG_NEED_MULTIPLE_NODES
@@ -1080,7 +1080,7 @@ static void __init numa_parse_mdesc_group_cpus(struct mdesc_handle *md,
{
u64 arc;
- cpus_clear(*mask);
+ cpumask_clear(mask);
mdesc_for_each_arc(arc, md, grp, MDESC_ARC_TYPE_BACK) {
u64 target = mdesc_arc_target(md, arc);
@@ -1091,7 +1091,7 @@ static void __init numa_parse_mdesc_group_cpus(struct mdesc_handle *md,
continue;
id = mdesc_get_property(md, target, "id", NULL);
if (*id < nr_cpu_ids)
- cpu_set(*id, *mask);
+ cpumask_set_cpu(*id, mask);
}
}
@@ -1153,13 +1153,13 @@ static int __init numa_parse_mdesc_group(struct mdesc_handle *md, u64 grp,
numa_parse_mdesc_group_cpus(md, grp, &mask);
- for_each_cpu_mask(cpu, mask)
+ for_each_cpu(cpu, &mask)
numa_cpu_lookup_table[cpu] = index;
- numa_cpumask_lookup_table[index] = mask;
+ cpumask_copy(&numa_cpumask_lookup_table[index], &mask);
if (numa_debug) {
printk(KERN_INFO "NUMA GROUP[%d]: cpus [ ", index);
- for_each_cpu_mask(cpu, mask)
+ for_each_cpu(cpu, &mask)
printk("%d ", cpu);
printk("]\n");
}
@@ -1218,7 +1218,7 @@ static int __init numa_parse_jbus(void)
index = 0;
for_each_present_cpu(cpu) {
numa_cpu_lookup_table[cpu] = index;
- numa_cpumask_lookup_table[index] = cpumask_of_cpu(cpu);
+ cpumask_copy(&numa_cpumask_lookup_table[index], cpumask_of(cpu));
node_masks[index].mask = ~((1UL << 36UL) - 1UL);
node_masks[index].val = cpu << 36UL;
diff --git a/arch/sparc/mm/tlb.c b/arch/sparc/mm/tlb.c
index d8f21e24a82f..b1f279cd00bf 100644
--- a/arch/sparc/mm/tlb.c
+++ b/arch/sparc/mm/tlb.c
@@ -19,33 +19,34 @@
/* Heavily inspired by the ppc64 code. */
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+static DEFINE_PER_CPU(struct tlb_batch, tlb_batch);
void flush_tlb_pending(void)
{
- struct mmu_gather *mp = &get_cpu_var(mmu_gathers);
+ struct tlb_batch *tb = &get_cpu_var(tlb_batch);
- if (mp->tlb_nr) {
- flush_tsb_user(mp);
+ if (tb->tlb_nr) {
+ flush_tsb_user(tb);
- if (CTX_VALID(mp->mm->context)) {
+ if (CTX_VALID(tb->mm->context)) {
#ifdef CONFIG_SMP
- smp_flush_tlb_pending(mp->mm, mp->tlb_nr,
- &mp->vaddrs[0]);
+ smp_flush_tlb_pending(tb->mm, tb->tlb_nr,
+ &tb->vaddrs[0]);
#else
- __flush_tlb_pending(CTX_HWBITS(mp->mm->context),
- mp->tlb_nr, &mp->vaddrs[0]);
+ __flush_tlb_pending(CTX_HWBITS(tb->mm->context),
+ tb->tlb_nr, &tb->vaddrs[0]);
#endif
}
- mp->tlb_nr = 0;
+ tb->tlb_nr = 0;
}
- put_cpu_var(mmu_gathers);
+ put_cpu_var(tlb_batch);
}
-void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, pte_t *ptep, pte_t orig)
+void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr,
+ pte_t *ptep, pte_t orig, int fullmm)
{
- struct mmu_gather *mp = &__get_cpu_var(mmu_gathers);
+ struct tlb_batch *tb = &get_cpu_var(tlb_batch);
unsigned long nr;
vaddr &= PAGE_MASK;
@@ -77,21 +78,25 @@ void tlb_batch_add(struct mm_struct *mm, unsigned long vaddr, pte_t *ptep, pte_t
no_cache_flush:
- if (mp->fullmm)
+ if (fullmm) {
+ put_cpu_var(tlb_batch);
return;
+ }
- nr = mp->tlb_nr;
+ nr = tb->tlb_nr;
- if (unlikely(nr != 0 && mm != mp->mm)) {
+ if (unlikely(nr != 0 && mm != tb->mm)) {
flush_tlb_pending();
nr = 0;
}
if (nr == 0)
- mp->mm = mm;
+ tb->mm = mm;
- mp->vaddrs[nr] = vaddr;
- mp->tlb_nr = ++nr;
+ tb->vaddrs[nr] = vaddr;
+ tb->tlb_nr = ++nr;
if (nr >= TLB_BATCH_NR)
flush_tlb_pending();
+
+ put_cpu_var(tlb_batch);
}
diff --git a/arch/sparc/mm/tsb.c b/arch/sparc/mm/tsb.c
index 101d7c82870b..948461513499 100644
--- a/arch/sparc/mm/tsb.c
+++ b/arch/sparc/mm/tsb.c
@@ -47,12 +47,13 @@ void flush_tsb_kernel_range(unsigned long start, unsigned long end)
}
}
-static void __flush_tsb_one(struct mmu_gather *mp, unsigned long hash_shift, unsigned long tsb, unsigned long nentries)
+static void __flush_tsb_one(struct tlb_batch *tb, unsigned long hash_shift,
+ unsigned long tsb, unsigned long nentries)
{
unsigned long i;
- for (i = 0; i < mp->tlb_nr; i++) {
- unsigned long v = mp->vaddrs[i];
+ for (i = 0; i < tb->tlb_nr; i++) {
+ unsigned long v = tb->vaddrs[i];
unsigned long tag, ent, hash;
v &= ~0x1UL;
@@ -65,9 +66,9 @@ static void __flush_tsb_one(struct mmu_gather *mp, unsigned long hash_shift, uns
}
}
-void flush_tsb_user(struct mmu_gather *mp)
+void flush_tsb_user(struct tlb_batch *tb)
{
- struct mm_struct *mm = mp->mm;
+ struct mm_struct *mm = tb->mm;
unsigned long nentries, base, flags;
spin_lock_irqsave(&mm->context.lock, flags);
@@ -76,7 +77,7 @@ void flush_tsb_user(struct mmu_gather *mp)
nentries = mm->context.tsb_block[MM_TSB_BASE].tsb_nentries;
if (tlb_type == cheetah_plus || tlb_type == hypervisor)
base = __pa(base);
- __flush_tsb_one(mp, PAGE_SHIFT, base, nentries);
+ __flush_tsb_one(tb, PAGE_SHIFT, base, nentries);
#ifdef CONFIG_HUGETLB_PAGE
if (mm->context.tsb_block[MM_TSB_HUGE].tsb) {
@@ -84,7 +85,7 @@ void flush_tsb_user(struct mmu_gather *mp)
nentries = mm->context.tsb_block[MM_TSB_HUGE].tsb_nentries;
if (tlb_type == cheetah_plus || tlb_type == hypervisor)
base = __pa(base);
- __flush_tsb_one(mp, HPAGE_SHIFT, base, nentries);
+ __flush_tsb_one(tb, HPAGE_SHIFT, base, nentries);
}
#endif
spin_unlock_irqrestore(&mm->context.lock, flags);
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig
index e32b0c23c4c8..e1e50101b3bb 100644
--- a/arch/tile/Kconfig
+++ b/arch/tile/Kconfig
@@ -5,7 +5,6 @@ config TILE
def_bool y
select HAVE_KVM if !TILEGX
select GENERIC_FIND_FIRST_BIT
- select GENERIC_FIND_NEXT_BIT
select USE_GENERIC_SMP_HELPERS
select CC_OPTIMIZE_FOR_SIZE
select HAVE_GENERIC_HARDIRQS
@@ -339,6 +338,14 @@ config NO_IOPORT
source "drivers/pci/Kconfig"
+config HOTPLUG
+ bool "Support for hot-pluggable devices"
+ ---help---
+ Say Y here if you want to plug devices into your computer while
+ the system is running, and be able to use them quickly. In many
+ cases, the devices can likewise be unplugged at any time too.
+ One well-known example of this is USB.
+
source "drivers/pci/hotplug/Kconfig"
endmenu
diff --git a/arch/tile/Kconfig.debug b/arch/tile/Kconfig.debug
index 9bc161a02c71..ddbfc3322d7f 100644
--- a/arch/tile/Kconfig.debug
+++ b/arch/tile/Kconfig.debug
@@ -21,15 +21,6 @@ config DEBUG_STACKOVERFLOW
This option will cause messages to be printed if free stack space
drops below a certain limit.
-config DEBUG_STACK_USAGE
- bool "Stack utilization instrumentation"
- depends on DEBUG_KERNEL
- help
- Enables the display of the minimum amount of free stack which each
- task has ever had available in the sysrq-T and sysrq-P debug output.
-
- This option will slow down process creation somewhat.
-
config DEBUG_EXTRA_FLAGS
string "Additional compiler arguments when building with '-g'"
depends on DEBUG_INFO
diff --git a/arch/tile/configs/tile_defconfig b/arch/tile/configs/tile_defconfig
deleted file mode 100644
index 0fe54445fda5..000000000000
--- a/arch/tile/configs/tile_defconfig
+++ /dev/null
@@ -1,71 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE="usr/contents.txt"
-CONFIG_EXPERT=y
-# CONFIG_COMPAT_BRK is not set
-CONFIG_PROFILING=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_HZ_100=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-CONFIG_IPV6=y
-# CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-CONFIG_NETDEVICES=y
-CONFIG_TUN=y
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_WLAN is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_HW_RANDOM is not set
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-# CONFIG_HID_SUPPORT is not set
-CONFIG_RTC_CLASS=y
-# CONFIG_RTC_INTF_SYSFS is not set
-# CONFIG_RTC_INTF_PROC is not set
-CONFIG_EXT2_FS=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_FUSE_FS=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=m
-CONFIG_TMPFS=y
-CONFIG_HUGETLBFS=y
-CONFIG_NFS_FS=m
-CONFIG_NFS_V3=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_FRAME_WARN=2048
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DETECT_HUNG_TASK=y
-CONFIG_DEBUG_SPINLOCK_SLEEP=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_VM=y
-# CONFIG_RCU_CPU_STALL_DETECTOR is not set
-CONFIG_DEBUG_STACKOVERFLOW=y
-CONFIG_DEBUG_EXTRA_FLAGS="-femit-struct-debug-baseonly"
diff --git a/arch/tile/configs/tilegx_defconfig b/arch/tile/configs/tilegx_defconfig
new file mode 100644
index 000000000000..09f1c7fad8bf
--- /dev/null
+++ b/arch/tile/configs/tilegx_defconfig
@@ -0,0 +1,1833 @@
+#
+# Automatically generated make config: don't edit
+# Linux/tilegx 2.6.39-rc5 Kernel Configuration
+# Wed May 4 11:08:04 2011
+#
+CONFIG_TILE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_SEMAPHORE_SLEEPERS=y
+CONFIG_HAVE_ARCH_ALLOC_REMAP=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
+CONFIG_SYS_SUPPORTS_HUGETLBFS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_DEFAULT_MIGRATION_COST=10000000
+CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
+CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_STRICT_DEVMEM=y
+CONFIG_SMP=y
+# CONFIG_DEBUG_COPY_FROM_USER is not set
+CONFIG_HVC_TILE=y
+CONFIG_TILEGX=y
+CONFIG_64BIT=y
+CONFIG_ARCH_DEFCONFIG="arch/tile/configs/tilegx_defconfig"
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO 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_FHANDLE is not set
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_AUDIT=y
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_PENDING_IRQ=y
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=64
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_RCU_FAST_NO_HZ is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=19
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_DEBUG=y
+CONFIG_CGROUP_NS=y
+# CONFIG_CGROUP_FREEZER is not set
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CPUSETS=y
+CONFIG_PROC_PID_CPUSET=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+CONFIG_CGROUP_MEM_RES_CTLR=y
+CONFIG_CGROUP_MEM_RES_CTLR_SWAP=y
+CONFIG_CGROUP_MEM_RES_CTLR_SWAP_ENABLED=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_BLK_CGROUP=y
+# CONFIG_DEBUG_BLK_CGROUP is not set
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+CONFIG_USER_NS=y
+CONFIG_PID_NS=y
+CONFIG_NET_NS=y
+# CONFIG_SCHED_AUTOGROUP is not set
+CONFIG_MM_OWNER=y
+# CONFIG_SYSFS_DEPRECATED is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="usr/contents.txt"
+CONFIG_INITRAMFS_ROOT_UID=0
+CONFIG_INITRAMFS_ROOT_GID=0
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+CONFIG_INITRAMFS_COMPRESSION_NONE=y
+# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EXPERT=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_EMBEDDED=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+# 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=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+CONFIG_BLK_DEV_BSG=y
+CONFIG_BLK_DEV_INTEGRITY=y
+# CONFIG_BLK_DEV_THROTTLING is not set
+CONFIG_BLOCK_COMPAT=y
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_CFQ_GROUP_IOSCHED=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_PADATA=y
+# 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=y
+
+#
+# Tilera-specific configuration
+#
+CONFIG_NR_CPUS=100
+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_KEXEC is not set
+CONFIG_COMPAT=y
+CONFIG_SYSVIPC_COMPAT=y
+# CONFIG_HIGHMEM is not set
+CONFIG_NUMA=y
+CONFIG_NODES_SHIFT=2
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_DISCONTIGMEM_MANUAL=y
+CONFIG_DISCONTIGMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_NEED_MULTIPLE_NODES=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_COMPACTION is not set
+CONFIG_MIGRATION=y
+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_CMDLINE_BOOL is not set
+CONFIG_VMALLOC_RESERVE=0x1000000
+CONFIG_HARDWALL=y
+CONFIG_KERNEL_PL=1
+
+#
+# Bus options
+#
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_NO_IOMEM is not set
+# CONFIG_NO_IOPORT is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_PCI_DEBUG=y
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCI_IOV is not set
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_COMPAT_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+CONFIG_BINFMT_MISC=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_SUB_POLICY=y
+CONFIG_XFRM_MIGRATE=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_XFRM_IPCOMP=m
+CONFIG_NET_KEY=m
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+# CONFIG_IP_FIB_TRIE_STATS is not set
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_ROUTE_CLASSID=y
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+# CONFIG_NET_IPGRE_DEMUX is not set
+CONFIG_IP_MROUTE=y
+# CONFIG_IP_MROUTE_MULTIPLE_TABLES is not set
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_TUNNEL=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=m
+CONFIG_INET_LRO=y
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+CONFIG_TCP_CONG_ADVANCED=y
+CONFIG_TCP_CONG_BIC=m
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_TCP_CONG_WESTWOOD=m
+CONFIG_TCP_CONG_HTCP=m
+CONFIG_TCP_CONG_HSTCP=m
+CONFIG_TCP_CONG_HYBLA=m
+CONFIG_TCP_CONG_VEGAS=m
+CONFIG_TCP_CONG_SCALABLE=m
+CONFIG_TCP_CONG_LP=m
+CONFIG_TCP_CONG_VENO=m
+CONFIG_TCP_CONG_YEAH=m
+CONFIG_TCP_CONG_ILLINOIS=m
+CONFIG_DEFAULT_CUBIC=y
+# CONFIG_DEFAULT_RENO is not set
+CONFIG_DEFAULT_TCP_CONG="cubic"
+CONFIG_TCP_MD5SIG=y
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_MIP6=m
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+CONFIG_IPV6_SIT=m
+# CONFIG_IPV6_SIT_6RD is not set
+CONFIG_IPV6_NDISC_NODETYPE=y
+CONFIG_IPV6_TUNNEL=m
+CONFIG_IPV6_MULTIPLE_TABLES=y
+# CONFIG_IPV6_SUBTREES is not set
+CONFIG_IPV6_MROUTE=y
+# CONFIG_IPV6_MROUTE_MULTIPLE_TABLES is not set
+CONFIG_IPV6_PIMSM_V2=y
+CONFIG_NETLABEL=y
+CONFIG_NETWORK_SECMARK=y
+# CONFIG_NETWORK_PHY_TIMESTAMPING is not set
+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=y
+CONFIG_NF_CONNTRACK_MARK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_ZONES=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+# CONFIG_NF_CONNTRACK_TIMESTAMP is not set
+CONFIG_NF_CT_PROTO_DCCP=m
+CONFIG_NF_CT_PROTO_GRE=m
+CONFIG_NF_CT_PROTO_SCTP=m
+CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_BROADCAST=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+# CONFIG_NF_CONNTRACK_SNMP is not set
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SANE=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+# CONFIG_NF_CT_NETLINK is not set
+CONFIG_NETFILTER_TPROXY=m
+CONFIG_NETFILTER_XTABLES=y
+
+#
+# Xtables combined modules
+#
+CONFIG_NETFILTER_XT_MARK=m
+CONFIG_NETFILTER_XT_CONNMARK=m
+
+#
+# Xtables targets
+#
+# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set
+# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m
+CONFIG_NETFILTER_XT_TARGET_CT=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
+CONFIG_NETFILTER_XT_TARGET_HL=m
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFLOG=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_TARGET_RATEEST=m
+CONFIG_NETFILTER_XT_TARGET_TEE=m
+CONFIG_NETFILTER_XT_TARGET_TPROXY=m
+CONFIG_NETFILTER_XT_TARGET_TRACE=m
+CONFIG_NETFILTER_XT_TARGET_SECMARK=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
+
+#
+# Xtables matches
+#
+# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set
+CONFIG_NETFILTER_XT_MATCH_CLUSTER=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+# CONFIG_NETFILTER_XT_MATCH_CPU is not set
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_HL=m
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
+CONFIG_NETFILTER_XT_MATCH_IPVS=m
+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=m
+CONFIG_NETFILTER_XT_MATCH_OWNER=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_RATEEST=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_RECENT=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_SOCKET=m
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_TIME=m
+CONFIG_NETFILTER_XT_MATCH_U32=m
+# CONFIG_IP_SET is not set
+CONFIG_IP_VS=m
+CONFIG_IP_VS_IPV6=y
+# 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=y
+
+#
+# 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 is not set
+# CONFIG_IP_VS_SH is not set
+CONFIG_IP_VS_SED=m
+CONFIG_IP_VS_NQ=m
+
+#
+# IPVS application helper
+#
+# CONFIG_IP_VS_NFCT is not set
+# CONFIG_IP_VS_PE_SIP is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=y
+CONFIG_NF_CONNTRACK_IPV4=y
+# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+# CONFIG_NF_NAT is not set
+CONFIG_IP_NF_MANGLE=m
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_SECURITY=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV6=m
+CONFIG_NF_CONNTRACK_IPV6=m
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_MH=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_RAW=m
+CONFIG_IP6_NF_SECURITY=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_IP6=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=m
+# CONFIG_IP_DCCP is not set
+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=m
+CONFIG_RDS_TCP=m
+# CONFIG_RDS_DEBUG is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
+CONFIG_STP=m
+CONFIG_GARP=m
+CONFIG_BRIDGE=m
+CONFIG_BRIDGE_IGMP_SNOOPING=y
+CONFIG_NET_DSA=y
+CONFIG_NET_DSA_TAG_DSA=y
+CONFIG_NET_DSA_TAG_EDSA=y
+CONFIG_NET_DSA_TAG_TRAILER=y
+CONFIG_NET_DSA_MV88E6XXX=y
+CONFIG_NET_DSA_MV88E6060=y
+CONFIG_NET_DSA_MV88E6XXX_NEED_PPU=y
+CONFIG_NET_DSA_MV88E6131=y
+CONFIG_NET_DSA_MV88E6123_61_65=y
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+CONFIG_PHONET=m
+# 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_PRIO=m
+CONFIG_NET_SCH_MULTIQ=m
+CONFIG_NET_SCH_RED=m
+# CONFIG_NET_SCH_SFB is not set
+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=m
+# CONFIG_NET_SCH_MQPRIO is not set
+# CONFIG_NET_SCH_CHOKE 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_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_CLS_FLOW=m
+CONFIG_NET_CLS_CGROUP=y
+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=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_NAT=m
+CONFIG_NET_ACT_PEDIT=m
+CONFIG_NET_ACT_SIMP=m
+CONFIG_NET_ACT_SKBEDIT=m
+# CONFIG_NET_ACT_CSUM is not set
+CONFIG_NET_CLS_IND=y
+CONFIG_NET_SCH_FIFO=y
+CONFIG_DCB=y
+CONFIG_DNS_RESOLVER=y
+# CONFIG_BATMAN_ADV is not set
+CONFIG_RPS=y
+CONFIG_RFS_ACCEL=y
+CONFIG_XPS=y
+
+#
+# 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_FIB_RULES=y
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+# CONFIG_CEPH_LIB is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+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_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=m
+# CONFIG_BLK_DEV_DRBD is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_SX8=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+CONFIG_ATA_OVER_ETH=y
+# CONFIG_BLK_DEV_RBD is not set
+# CONFIG_SENSORS_LIS3LV02D 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 is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_APDS9802ALS is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_ISL29020 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_SENSORS_BH1780 is not set
+# CONFIG_SENSORS_BH1770 is not set
+# CONFIG_SENSORS_APDS990X is not set
+# CONFIG_HMC6352 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_BMP085 is not set
+# CONFIG_PCH_PHUB 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
+
+#
+# Texas Instruments shared transport line discipline
+#
+# CONFIG_SENSORS_LIS3_I2C is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=m
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI=m
+CONFIG_SCSI_DMA=y
+CONFIG_SCSI_TGT=m
+# CONFIG_SCSI_NETLINK is not set
+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 is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+CONFIG_SCSI_SAS_ATTRS=m
+# 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_ISCSI_BOOT_SYSFS is not set
+# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_CXGB4_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
+# CONFIG_SCSI_BNX2X_FCOE is not set
+# CONFIG_BE2ISCSI is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_HPSA is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_3W_SAS 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_MVSAS 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_MPT2SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE 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_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_PMCRAID is not set
+# CONFIG_SCSI_PM8001 is not set
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_BFA_FC is not set
+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+CONFIG_ATA=m
+# 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_ACARD_AHCI is not set
+CONFIG_SATA_SIL24=m
+CONFIG_ATA_SFF=y
+
+#
+# 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_SATA_PROMISE 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
+
+#
+# PATA SFF controllers with BMDMA
+#
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARASAN_CF is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP 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_CS5536 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR 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_IT8213 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87415 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_RDC is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SCH is not set
+# CONFIG_PATA_SERVERWORKS 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_RZ1000 is not set
+
+#
+# Generic fallback / legacy drivers
+#
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_LEGACY is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+CONFIG_MD_AUTODETECT=y
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID456=m
+CONFIG_MULTICORE_RAID456=y
+# CONFIG_MD_MULTIPATH is not set
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_DEBUG=y
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+# CONFIG_DM_RAID is not set
+CONFIG_DM_LOG_USERSPACE=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_QL=m
+CONFIG_DM_MULTIPATH_ST=m
+CONFIG_DM_DELAY=m
+CONFIG_DM_UEVENT=y
+# CONFIG_DM_FLAKEY is not set
+# CONFIG_TARGET_CORE is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_FIREWIRE_NOSY is not set
+# CONFIG_I2O is not set
+CONFIG_NETDEVICES=y
+CONFIG_IFB=m
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_MACVLAN=m
+CONFIG_MACVTAP=m
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=y
+CONFIG_VETH=m
+# CONFIG_ARCNET is not set
+# CONFIG_MII 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_BCM63XX_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 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+CONFIG_E1000E=m
+# CONFIG_IP1000 is not set
+# CONFIG_IGB is not set
+# CONFIG_IGBVF 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 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL1C is not set
+# CONFIG_JME is not set
+# CONFIG_STMMAC_ETH is not set
+# CONFIG_PCH_GBE is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+# CONFIG_WLAN is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+
+#
+# CAIF transport drivers
+#
+# CONFIG_TILE_NET 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 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
+
+#
+# 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 is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+# CONFIG_N_GSM is not set
+CONFIG_DEVKMEM=y
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MFD_HSU is not set
+# 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_SERIAL_PCH_UART is not set
+# CONFIG_TTY_PRINTK is not set
+CONFIG_HVC_DRIVER=y
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_TIMERIOMEM=m
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# PCMCIA character devices
+#
+# 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_MUX is not set
+CONFIG_I2C_HELPER_AUTO=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_INTEL_MID is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_PXA_PCI is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+# CONFIG_I2C_EG20T is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM 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
+
+#
+# PPS generators support
+#
+# 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
+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_TPS6105X is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_TC3589X 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_MAX8997 is not set
+# CONFIG_MFD_MAX8998 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X_I2C 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_LPC_SCH is not set
+# CONFIG_MFD_RDC321X is not set
+# CONFIG_MFD_JANZ_CMODIO is not set
+# CONFIG_MFD_VX855 is not set
+# CONFIG_MFD_WL1273_CORE 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_STUB_POULSBO 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
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT 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_NFC_DEVICES is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_EDAC is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_DS3232 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_ISL12022 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_BQ32K is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_TILE=y
+# 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=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT2_FS_XIP=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_DEFAULTS_TO_ORDERED=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_XATTR=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_FS_XIP=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_JBD2=y
+CONFIG_JBD2_DEBUG=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_XFS_FS=m
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_POSIX_ACL=y
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_DEBUG is not set
+CONFIG_GFS2_FS=m
+CONFIG_GFS2_FS_LOCKING_DLM=y
+# CONFIG_OCFS2_FS is not set
+CONFIG_BTRFS_FS=m
+CONFIG_BTRFS_FS_POSIX_ACL=y
+# CONFIG_NILFS2_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_EXPORTFS=y
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_FANOTIFY is not set
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+# CONFIG_PRINT_QUOTA_WARNING is not set
+# CONFIG_QUOTA_DEBUG is not set
+CONFIG_QUOTA_TREE=y
+# CONFIG_QFMT_V1 is not set
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=y
+CONFIG_CUSE=m
+CONFIG_GENERIC_ACL=y
+
+#
+# Caches
+#
+CONFIG_FSCACHE=m
+CONFIG_FSCACHE_STATS=y
+# CONFIG_FSCACHE_HISTOGRAM is not set
+# CONFIG_FSCACHE_DEBUG is not set
+# CONFIG_FSCACHE_OBJECT_LIST is not set
+CONFIG_CACHEFILES=m
+# CONFIG_CACHEFILES_DEBUG is not set
+# CONFIG_CACHEFILES_HISTOGRAM 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="ascii"
+# 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=y
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_CONFIGFS_FS=m
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+CONFIG_ECRYPT_FS=m
+# 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_LOGFS is not set
+CONFIG_CRAMFS=m
+CONFIG_SQUASHFS=m
+# CONFIG_SQUASHFS_XATTR is not set
+# CONFIG_SQUASHFS_LZO is not set
+# CONFIG_SQUASHFS_XZ is not set
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# 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_PSTORE is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_NFS_V4_1=y
+CONFIG_PNFS_FILE_LAYOUT=m
+CONFIG_NFS_FSCACHE=y
+# CONFIG_NFS_USE_LEGACY_DNS is not set
+CONFIG_NFS_USE_KERNEL_DNS=y
+# CONFIG_NFS_USE_NEW_IDMAPPER is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_DEPRECATED=y
+CONFIG_NFSD_V2_ACL=y
+CONFIG_NFSD_V3=y
+CONFIG_NFSD_V3_ACL=y
+CONFIG_NFSD_V4=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_CEPH_FS is not set
+CONFIG_CIFS=m
+CONFIG_CIFS_STATS=y
+# CONFIG_CIFS_STATS2 is not set
+CONFIG_CIFS_WEAK_PW_HASH=y
+CONFIG_CIFS_UPCALL=y
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_DEBUG2 is not set
+CONFIG_CIFS_DFS_UPCALL=y
+CONFIG_CIFS_FSCACHE=y
+# CONFIG_CIFS_ACL is not set
+CONFIG_CIFS_EXPERIMENTAL=y
+# 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=y
+CONFIG_AMIGA_PARTITION=y
+# CONFIG_ATARI_PARTITION is not set
+CONFIG_MAC_PARTITION=y
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MINIX_SUBPARTITION=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+CONFIG_SUN_PARTITION=y
+CONFIG_KARMA_PARTITION=y
+CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+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_932=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=y
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=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=m
+CONFIG_DLM_DEBUG=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=2048
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_STRIP_ASM_SYMS=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+CONFIG_HEADERS_CHECK=y
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_SHIRQ=y
+CONFIG_LOCKUP_DETECTOR=y
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+# CONFIG_BOOTPARAM_HARDLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_HARDLOCKUP_PANIC_VALUE=0
+# 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=y
+CONFIG_TIMER_STATS=y
+# 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_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_LOCK_STAT is not set
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_REDUCED=y
+CONFIG_DEBUG_VM=y
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_LIST=y
+# CONFIG_TEST_LIST_SORT is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+CONFIG_DEBUG_CREDENTIALS=y
+# 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=y
+# CONFIG_LKDTM is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BUILD_DOCSRC is not set
+CONFIG_DYNAMIC_DEBUG=y
+# CONFIG_ATOMIC64_SELFTEST is not set
+CONFIG_ASYNC_RAID6_TEST=m
+# CONFIG_SAMPLES is not set
+# CONFIG_TEST_KSTRTOX is not set
+CONFIG_EARLY_PRINTK=y
+CONFIG_DEBUG_STACKOVERFLOW=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_EXTRA_FLAGS=""
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITYFS=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_NETWORK_XFRM=y
+# CONFIG_SECURITY_PATH is not set
+CONFIG_LSM_MMAP_MIN_ADDR=65536
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM=y
+CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=1
+CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_SECURITY_SELINUX_DEVELOP=y
+CONFIG_SECURITY_SELINUX_AVC_STATS=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+# CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX is not set
+# CONFIG_SECURITY_SMACK is not set
+# CONFIG_SECURITY_TOMOYO is not set
+# CONFIG_SECURITY_APPARMOR is not set
+# CONFIG_IMA is not set
+CONFIG_DEFAULT_SECURITY_SELINUX=y
+# CONFIG_DEFAULT_SECURITY_DAC is not set
+CONFIG_DEFAULT_SECURITY="selinux"
+CONFIG_XOR_BLOCKS=m
+CONFIG_ASYNC_CORE=m
+CONFIG_ASYNC_MEMCPY=m
+CONFIG_ASYNC_XOR=m
+CONFIG_ASYNC_PQ=m
+CONFIG_ASYNC_RAID6_RECOV=m
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=m
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=m
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=m
+CONFIG_CRYPTO_PCOMP2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+CONFIG_CRYPTO_GF128MUL=m
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_PCRYPT=m
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_CRYPTO_CRYPTD=m
+CONFIG_CRYPTO_AUTHENC=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Authenticated Encryption with Associated Data
+#
+CONFIG_CRYPTO_CCM=m
+CONFIG_CRYPTO_GCM=m
+CONFIG_CRYPTO_SEQIV=m
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=m
+CONFIG_CRYPTO_CTR=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_XCBC=m
+CONFIG_CRYPTO_VMAC=m
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_GHASH=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_RMD128=m
+CONFIG_CRYPTO_RMD160=m
+CONFIG_CRYPTO_RMD256=m
+CONFIG_CRYPTO_RMD320=m
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+# CONFIG_CRYPTO_SALSA20 is not set
+CONFIG_CRYPTO_SEED=m
+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=m
+CONFIG_CRYPTO_LZO=m
+
+#
+# Random Number Generation
+#
+CONFIG_CRYPTO_ANSI_CPRNG=m
+# CONFIG_CRYPTO_USER_API_HASH is not set
+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_DEV_HIFN_795X=m
+CONFIG_CRYPTO_DEV_HIFN_795X_RNG=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_RAID6_PQ=m
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_FIRST_BIT=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC16=y
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=m
+CONFIG_AUDIT_GENERIC=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_LZO_COMPRESS=m
+CONFIG_LZO_DECOMPRESS=m
+# CONFIG_XZ_DEC is not set
+# CONFIG_XZ_DEC_BCJ is not set
+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_CPU_RMAP=y
+CONFIG_NLATTR=y
+# CONFIG_AVERAGE is not set
+# CONFIG_VIRTUALIZATION is not set
diff --git a/arch/tile/configs/tilepro_defconfig b/arch/tile/configs/tilepro_defconfig
new file mode 100644
index 000000000000..f58dc362b944
--- /dev/null
+++ b/arch/tile/configs/tilepro_defconfig
@@ -0,0 +1,1163 @@
+#
+# Automatically generated make config: don't edit
+# Linux/tile 2.6.39-rc5 Kernel Configuration
+# Tue May 3 09:15:02 2011
+#
+CONFIG_TILE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_SEMAPHORE_SLEEPERS=y
+CONFIG_HAVE_ARCH_ALLOC_REMAP=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
+CONFIG_SYS_SUPPORTS_HUGETLBFS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_DEFAULT_MIGRATION_COST=10000000
+CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
+CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_STRICT_DEVMEM=y
+CONFIG_SMP=y
+# CONFIG_DEBUG_COPY_FROM_USER is not set
+CONFIG_HVC_TILE=y
+# CONFIG_TILEGX is not set
+CONFIG_ARCH_DEFCONFIG="arch/tile/configs/tile_defconfig"
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+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_FHANDLE=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_PENDING_IRQ=y
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_RCU_FAST_NO_HZ 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_NAMESPACES is not set
+# CONFIG_SCHED_AUTOGROUP is not set
+# CONFIG_SYSFS_DEPRECATED is not set
+# CONFIG_RELAY is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="usr/contents.txt"
+CONFIG_INITRAMFS_ROOT_UID=0
+CONFIG_INITRAMFS_ROOT_GID=0
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+CONFIG_INITRAMFS_COMPRESSION_NONE=y
+# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EXPERT=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_EMBEDDED=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+
+#
+# GCOV-based kernel profiling
+#
+# 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 is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_STOP_MACHINE=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 is not set
+# CONFIG_IOSCHED_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=y
+
+#
+# Tilera-specific configuration
+#
+CONFIG_NR_CPUS=64
+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_KEXEC is not set
+CONFIG_HIGHMEM=y
+CONFIG_NUMA=y
+CONFIG_NODES_SHIFT=2
+# CONFIG_VMSPLIT_3_75G is not set
+# CONFIG_VMSPLIT_3_5G is not set
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2_75G is not set
+# CONFIG_VMSPLIT_2_5G is not set
+# CONFIG_VMSPLIT_2_25G is not set
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_DISCONTIGMEM_MANUAL=y
+CONFIG_DISCONTIGMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_NEED_MULTIPLE_NODES=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_COMPACTION is not set
+CONFIG_MIGRATION=y
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_VMALLOC_RESERVE=0x1000000
+CONFIG_HARDWALL=y
+CONFIG_KERNEL_PL=1
+
+#
+# Bus options
+#
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_NO_IOMEM is not set
+# CONFIG_NO_IOPORT is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCI_IOV is not set
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# 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
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+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_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE_DEMUX 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=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# 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=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
+# CONFIG_IPV6_SIT_6RD is not set
+CONFIG_IPV6_NDISC_NODETYPE=y
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING 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_L2TP 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
+# CONFIG_BATMAN_ADV is not set
+CONFIG_RPS=y
+CONFIG_RFS_ACCEL=y
+CONFIG_XPS=y
+
+#
+# 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
+# CONFIG_CAIF is not set
+# CONFIG_CEPH_LIB 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=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_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 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_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_RBD is not set
+# CONFIG_SENSORS_LIS3LV02D is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_PCH_PHUB is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# 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
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_ISCSI_BOOT_SYSFS is not set
+# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_SCSI_CXGB4_ISCSI is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
+# CONFIG_SCSI_BNX2X_FCOE is not set
+# CONFIG_BE2ISCSI is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_HPSA is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_3W_SAS 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_MVSAS 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_MPT2SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE 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_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_PMCRAID is not set
+# CONFIG_SCSI_PM8001 is not set
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_BFA_FC is not set
+# CONFIG_SCSI_LOWLEVEL_PCMCIA 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_TARGET_CORE is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_FIREWIRE_NOSY is not set
+# CONFIG_I2O 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=y
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+# CONFIG_MII is not set
+# CONFIG_PHYLIB is not set
+# CONFIG_NET_ETHERNET is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB is not set
+# CONFIG_IGBVF 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 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL1C is not set
+# CONFIG_JME is not set
+# CONFIG_STMMAC_ETH is not set
+# CONFIG_PCH_GBE is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+# CONFIG_WLAN is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+
+#
+# CAIF transport drivers
+#
+CONFIG_TILE_NET=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 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
+
+#
+# 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 is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+# CONFIG_N_GSM is not set
+CONFIG_DEVKMEM=y
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MFD_HSU is not set
+# 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_SERIAL_PCH_UART is not set
+# CONFIG_TTY_PRINTK is not set
+CONFIG_HVC_DRIVER=y
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# PCMCIA character devices
+#
+# 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
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+
+#
+# PPS generators support
+#
+# 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_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_SCH5627 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_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
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_MFD_SUPPORT=y
+# 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_ABX500_CORE is not set
+# CONFIG_LPC_SCH is not set
+# CONFIG_MFD_RDC321X is not set
+# CONFIG_MFD_JANZ_CMODIO is not set
+# CONFIG_MFD_VX855 is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+CONFIG_VGA_ARB=y
+CONFIG_VGA_ARB_MAX_GPUS=16
+# CONFIG_DRM is not set
+# CONFIG_STUB_POULSBO 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
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT 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 is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+# 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_NFC_DEVICES is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+CONFIG_EDAC=y
+
+#
+# Reporting subsystems
+#
+# CONFIG_EDAC_DEBUG is not set
+CONFIG_EDAC_MM_EDAC=y
+CONFIG_EDAC_TILE=y
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+# CONFIG_RTC_INTF_SYSFS is not set
+# CONFIG_RTC_INTF_PROC is not set
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_TILE=y
+# 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=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_EXPORTFS=y
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_FANOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=y
+# CONFIG_CUSE 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_FAT_FS=y
+CONFIG_MSDOS_FS=y
+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 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_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_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_PSTORE is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+# CONFIG_RPCSEC_GSS_KRB5 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 is not set
+CONFIG_MSDOS_PARTITION=y
+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 is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=2048
+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_SECTION_MISMATCH is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_LOCKUP_DETECTOR is not set
+# CONFIG_HARDLOCKUP_DETECTOR is not set
+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_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+# CONFIG_LOCK_STAT is not set
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_INFO_REDUCED is not set
+CONFIG_DEBUG_VM=y
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_TEST_LIST_SORT 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_SYSCTL_SYSCALL_CHECK is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_TEST_KSTRTOX is not set
+CONFIG_EARLY_PRINTK=y
+CONFIG_DEBUG_STACKOVERFLOW=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_EXTRA_FLAGS="-femit-struct-debug-baseonly"
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS 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=m
+CONFIG_CRYPTO_ALGAPI2=m
+CONFIG_CRYPTO_RNG=m
+CONFIG_CRYPTO_RNG2=m
+# 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_PCRYPT is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# 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=m
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+CONFIG_CRYPTO_ANSI_CPRNG=m
+# CONFIG_CRYPTO_USER_API_HASH is not set
+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
+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_FIRST_BIT=y
+CONFIG_GENERIC_FIND_NEXT_BIT=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 is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+# CONFIG_XZ_DEC is not set
+# CONFIG_XZ_DEC_BCJ is not set
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_CPU_RMAP=y
+CONFIG_NLATTR=y
+# CONFIG_AVERAGE is not set
+CONFIG_HAVE_KVM=y
+# CONFIG_VIRTUALIZATION is not set
diff --git a/arch/tile/include/arch/chip_tilegx.h b/arch/tile/include/arch/chip_tilegx.h
new file mode 100644
index 000000000000..ea8e4f2c9483
--- /dev/null
+++ b/arch/tile/include/arch/chip_tilegx.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in 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.
+ */
+
+/*
+ * @file
+ * Global header file.
+ * This header file specifies defines for TILE-Gx.
+ */
+
+#ifndef __ARCH_CHIP_H__
+#define __ARCH_CHIP_H__
+
+/** Specify chip version.
+ * When possible, prefer the CHIP_xxx symbols below for future-proofing.
+ * This is intended for cross-compiling; native compilation should
+ * use the predefined __tile_chip__ symbol.
+ */
+#define TILE_CHIP 10
+
+/** Specify chip revision.
+ * This provides for the case of a respin of a particular chip type;
+ * the normal value for this symbol is "0".
+ * This is intended for cross-compiling; native compilation should
+ * use the predefined __tile_chip_rev__ symbol.
+ */
+#define TILE_CHIP_REV 0
+
+/** The name of this architecture. */
+#define CHIP_ARCH_NAME "tilegx"
+
+/** The ELF e_machine type for binaries for this chip. */
+#define CHIP_ELF_TYPE() EM_TILEGX
+
+/** The alternate ELF e_machine type for binaries for this chip. */
+#define CHIP_COMPAT_ELF_TYPE() 0x2597
+
+/** What is the native word size of the machine? */
+#define CHIP_WORD_SIZE() 64
+
+/** How many bits of a virtual address are used. Extra bits must be
+ * the sign extension of the low bits.
+ */
+#define CHIP_VA_WIDTH() 42
+
+/** How many bits are in a physical address? */
+#define CHIP_PA_WIDTH() 40
+
+/** Size of the L2 cache, in bytes. */
+#define CHIP_L2_CACHE_SIZE() 262144
+
+/** Log size of an L2 cache line in bytes. */
+#define CHIP_L2_LOG_LINE_SIZE() 6
+
+/** Size of an L2 cache line, in bytes. */
+#define CHIP_L2_LINE_SIZE() (1 << CHIP_L2_LOG_LINE_SIZE())
+
+/** Associativity of the L2 cache. */
+#define CHIP_L2_ASSOC() 8
+
+/** Size of the L1 data cache, in bytes. */
+#define CHIP_L1D_CACHE_SIZE() 32768
+
+/** Log size of an L1 data cache line in bytes. */
+#define CHIP_L1D_LOG_LINE_SIZE() 6
+
+/** Size of an L1 data cache line, in bytes. */
+#define CHIP_L1D_LINE_SIZE() (1 << CHIP_L1D_LOG_LINE_SIZE())
+
+/** Associativity of the L1 data cache. */
+#define CHIP_L1D_ASSOC() 2
+
+/** Size of the L1 instruction cache, in bytes. */
+#define CHIP_L1I_CACHE_SIZE() 32768
+
+/** Log size of an L1 instruction cache line in bytes. */
+#define CHIP_L1I_LOG_LINE_SIZE() 6
+
+/** Size of an L1 instruction cache line, in bytes. */
+#define CHIP_L1I_LINE_SIZE() (1 << CHIP_L1I_LOG_LINE_SIZE())
+
+/** Associativity of the L1 instruction cache. */
+#define CHIP_L1I_ASSOC() 2
+
+/** Stride with which flush instructions must be issued. */
+#define CHIP_FLUSH_STRIDE() CHIP_L2_LINE_SIZE()
+
+/** Stride with which inv instructions must be issued. */
+#define CHIP_INV_STRIDE() CHIP_L2_LINE_SIZE()
+
+/** Stride with which finv instructions must be issued. */
+#define CHIP_FINV_STRIDE() CHIP_L2_LINE_SIZE()
+
+/** Can the local cache coherently cache data that is homed elsewhere? */
+#define CHIP_HAS_COHERENT_LOCAL_CACHE() 1
+
+/** How many simultaneous outstanding victims can the L2 cache have? */
+#define CHIP_MAX_OUTSTANDING_VICTIMS() 128
+
+/** Does the TLB support the NC and NOALLOC bits? */
+#define CHIP_HAS_NC_AND_NOALLOC_BITS() 1
+
+/** Does the chip support hash-for-home caching? */
+#define CHIP_HAS_CBOX_HOME_MAP() 1
+
+/** Number of entries in the chip's home map tables. */
+#define CHIP_CBOX_HOME_MAP_SIZE() 128
+
+/** Do uncacheable requests miss in the cache regardless of whether
+ * there is matching data? */
+#define CHIP_HAS_ENFORCED_UNCACHEABLE_REQUESTS() 1
+
+/** Does the mf instruction wait for victims? */
+#define CHIP_HAS_MF_WAITS_FOR_VICTIMS() 0
+
+/** Does the chip have an "inv" instruction that doesn't also flush? */
+#define CHIP_HAS_INV() 1
+
+/** Does the chip have a "wh64" instruction? */
+#define CHIP_HAS_WH64() 1
+
+/** Does this chip have a 'dword_align' instruction? */
+#define CHIP_HAS_DWORD_ALIGN() 0
+
+/** Number of performance counters. */
+#define CHIP_PERFORMANCE_COUNTERS() 4
+
+/** Does this chip have auxiliary performance counters? */
+#define CHIP_HAS_AUX_PERF_COUNTERS() 1
+
+/** Is the CBOX_MSR1 SPR supported? */
+#define CHIP_HAS_CBOX_MSR1() 0
+
+/** Is the TILE_RTF_HWM SPR supported? */
+#define CHIP_HAS_TILE_RTF_HWM() 1
+
+/** Is the TILE_WRITE_PENDING SPR supported? */
+#define CHIP_HAS_TILE_WRITE_PENDING() 0
+
+/** Is the PROC_STATUS SPR supported? */
+#define CHIP_HAS_PROC_STATUS_SPR() 1
+
+/** Is the DSTREAM_PF SPR supported? */
+#define CHIP_HAS_DSTREAM_PF() 1
+
+/** Log of the number of mshims we have. */
+#define CHIP_LOG_NUM_MSHIMS() 2
+
+/** Are the bases of the interrupt vector areas fixed? */
+#define CHIP_HAS_FIXED_INTVEC_BASE() 0
+
+/** Are the interrupt masks split up into 2 SPRs? */
+#define CHIP_HAS_SPLIT_INTR_MASK() 0
+
+/** Is the cycle count split up into 2 SPRs? */
+#define CHIP_HAS_SPLIT_CYCLE() 0
+
+/** Does the chip have a static network? */
+#define CHIP_HAS_SN() 0
+
+/** Does the chip have a static network processor? */
+#define CHIP_HAS_SN_PROC() 0
+
+/** Size of the L1 static network processor instruction cache, in bytes. */
+/* #define CHIP_L1SNI_CACHE_SIZE() -- does not apply to chip 10 */
+
+/** Does the chip have DMA support in each tile? */
+#define CHIP_HAS_TILE_DMA() 0
+
+/** Does the chip have the second revision of the directly accessible
+ * dynamic networks? This encapsulates a number of characteristics,
+ * including the absence of the catch-all, the absence of inline message
+ * tags, the absence of support for network context-switching, and so on.
+ */
+#define CHIP_HAS_REV1_XDN() 1
+
+/** Does the chip have cmpexch and similar (fetchadd, exch, etc.)? */
+#define CHIP_HAS_CMPEXCH() 1
+
+/** Does the chip have memory-mapped I/O support? */
+#define CHIP_HAS_MMIO() 1
+
+/** Does the chip have post-completion interrupts? */
+#define CHIP_HAS_POST_COMPLETION_INTERRUPTS() 1
+
+/** Does the chip have native single step support? */
+#define CHIP_HAS_SINGLE_STEP() 1
+
+#ifndef __OPEN_SOURCE__ /* features only relevant to hypervisor-level code */
+
+/** How many entries are present in the instruction TLB? */
+#define CHIP_ITLB_ENTRIES() 16
+
+/** How many entries are present in the data TLB? */
+#define CHIP_DTLB_ENTRIES() 32
+
+/** How many MAF entries does the XAUI shim have? */
+#define CHIP_XAUI_MAF_ENTRIES() 32
+
+/** Does the memory shim have a source-id table? */
+#define CHIP_HAS_MSHIM_SRCID_TABLE() 0
+
+/** Does the L1 instruction cache clear on reset? */
+#define CHIP_HAS_L1I_CLEAR_ON_RESET() 1
+
+/** Does the chip come out of reset with valid coordinates on all tiles?
+ * Note that if defined, this also implies that the upper left is 1,1.
+ */
+#define CHIP_HAS_VALID_TILE_COORD_RESET() 1
+
+/** Does the chip have unified packet formats? */
+#define CHIP_HAS_UNIFIED_PACKET_FORMATS() 1
+
+/** Does the chip support write reordering? */
+#define CHIP_HAS_WRITE_REORDERING() 1
+
+/** Does the chip support Y-X routing as well as X-Y? */
+#define CHIP_HAS_Y_X_ROUTING() 1
+
+/** Is INTCTRL_3 managed with the correct MPL? */
+#define CHIP_HAS_INTCTRL_3_STATUS_FIX() 1
+
+/** Is it possible to configure the chip to be big-endian? */
+#define CHIP_HAS_BIG_ENDIAN_CONFIG() 1
+
+/** Is the CACHE_RED_WAY_OVERRIDDEN SPR supported? */
+#define CHIP_HAS_CACHE_RED_WAY_OVERRIDDEN() 0
+
+/** Is the DIAG_TRACE_WAY SPR supported? */
+#define CHIP_HAS_DIAG_TRACE_WAY() 0
+
+/** Is the MEM_STRIPE_CONFIG SPR supported? */
+#define CHIP_HAS_MEM_STRIPE_CONFIG() 1
+
+/** Are the TLB_PERF SPRs supported? */
+#define CHIP_HAS_TLB_PERF() 1
+
+/** Is the VDN_SNOOP_SHIM_CTL SPR supported? */
+#define CHIP_HAS_VDN_SNOOP_SHIM_CTL() 0
+
+/** Does the chip support rev1 DMA packets? */
+#define CHIP_HAS_REV1_DMA_PACKETS() 1
+
+/** Does the chip have an IPI shim? */
+#define CHIP_HAS_IPI() 1
+
+#endif /* !__OPEN_SOURCE__ */
+#endif /* __ARCH_CHIP_H__ */
diff --git a/arch/tile/include/arch/icache.h b/arch/tile/include/arch/icache.h
index 5c87c9016338..762eafa8a11e 100644
--- a/arch/tile/include/arch/icache.h
+++ b/arch/tile/include/arch/icache.h
@@ -16,7 +16,7 @@
/**
* @file
*
- * Support for invalidating bytes in the instruction
+ * Support for invalidating bytes in the instruction cache.
*/
#ifndef __ARCH_ICACHE_H__
@@ -30,11 +30,10 @@
*
* @param addr The start of memory to be invalidated.
* @param size The number of bytes to be invalidated.
- * @param page_size The system's page size, typically the PAGE_SIZE constant
- * in sys/page.h. This value must be a power of two no larger
- * than the page containing the code to be invalidated. If the value
- * is smaller than the actual page size, this function will still
- * work, but may run slower than necessary.
+ * @param page_size The system's page size, e.g. getpagesize() in userspace.
+ * This value must be a power of two no larger than the page containing
+ * the code to be invalidated. If the value is smaller than the actual page
+ * size, this function will still work, but may run slower than necessary.
*/
static __inline void
invalidate_icache(const void* addr, unsigned long size,
diff --git a/arch/tile/include/arch/interrupts_64.h b/arch/tile/include/arch/interrupts_64.h
new file mode 100644
index 000000000000..5bb58b2e4e6f
--- /dev/null
+++ b/arch/tile/include/arch/interrupts_64.h
@@ -0,0 +1,276 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in 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.
+ */
+
+#ifndef __ARCH_INTERRUPTS_H__
+#define __ARCH_INTERRUPTS_H__
+
+/** Mask for an interrupt. */
+#ifdef __ASSEMBLER__
+/* Note: must handle breaking interrupts into high and low words manually. */
+#define INT_MASK(intno) (1 << (intno))
+#else
+#define INT_MASK(intno) (1ULL << (intno))
+#endif
+
+
+/** Where a given interrupt executes */
+#define INTERRUPT_VECTOR(i, pl) (0xFC000000 + ((pl) << 24) + ((i) << 8))
+
+/** Where to store a vector for a given interrupt. */
+#define USER_INTERRUPT_VECTOR(i) INTERRUPT_VECTOR(i, 0)
+
+/** The base address of user-level interrupts. */
+#define USER_INTERRUPT_VECTOR_BASE INTERRUPT_VECTOR(0, 0)
+
+
+/** Additional synthetic interrupt. */
+#define INT_BREAKPOINT (63)
+
+#define INT_MEM_ERROR 0
+#define INT_SINGLE_STEP_3 1
+#define INT_SINGLE_STEP_2 2
+#define INT_SINGLE_STEP_1 3
+#define INT_SINGLE_STEP_0 4
+#define INT_IDN_COMPLETE 5
+#define INT_UDN_COMPLETE 6
+#define INT_ITLB_MISS 7
+#define INT_ILL 8
+#define INT_GPV 9
+#define INT_IDN_ACCESS 10
+#define INT_UDN_ACCESS 11
+#define INT_SWINT_3 12
+#define INT_SWINT_2 13
+#define INT_SWINT_1 14
+#define INT_SWINT_0 15
+#define INT_ILL_TRANS 16
+#define INT_UNALIGN_DATA 17
+#define INT_DTLB_MISS 18
+#define INT_DTLB_ACCESS 19
+#define INT_IDN_FIREWALL 20
+#define INT_UDN_FIREWALL 21
+#define INT_TILE_TIMER 22
+#define INT_AUX_TILE_TIMER 23
+#define INT_IDN_TIMER 24
+#define INT_UDN_TIMER 25
+#define INT_IDN_AVAIL 26
+#define INT_UDN_AVAIL 27
+#define INT_IPI_3 28
+#define INT_IPI_2 29
+#define INT_IPI_1 30
+#define INT_IPI_0 31
+#define INT_PERF_COUNT 32
+#define INT_AUX_PERF_COUNT 33
+#define INT_INTCTRL_3 34
+#define INT_INTCTRL_2 35
+#define INT_INTCTRL_1 36
+#define INT_INTCTRL_0 37
+#define INT_BOOT_ACCESS 38
+#define INT_WORLD_ACCESS 39
+#define INT_I_ASID 40
+#define INT_D_ASID 41
+#define INT_DOUBLE_FAULT 42
+
+#define NUM_INTERRUPTS 43
+
+#ifndef __ASSEMBLER__
+#define QUEUED_INTERRUPTS ( \
+ INT_MASK(INT_MEM_ERROR) | \
+ INT_MASK(INT_IDN_COMPLETE) | \
+ INT_MASK(INT_UDN_COMPLETE) | \
+ INT_MASK(INT_IDN_FIREWALL) | \
+ INT_MASK(INT_UDN_FIREWALL) | \
+ INT_MASK(INT_TILE_TIMER) | \
+ INT_MASK(INT_AUX_TILE_TIMER) | \
+ INT_MASK(INT_IDN_TIMER) | \
+ INT_MASK(INT_UDN_TIMER) | \
+ INT_MASK(INT_IDN_AVAIL) | \
+ INT_MASK(INT_UDN_AVAIL) | \
+ INT_MASK(INT_IPI_3) | \
+ INT_MASK(INT_IPI_2) | \
+ INT_MASK(INT_IPI_1) | \
+ INT_MASK(INT_IPI_0) | \
+ INT_MASK(INT_PERF_COUNT) | \
+ INT_MASK(INT_AUX_PERF_COUNT) | \
+ INT_MASK(INT_INTCTRL_3) | \
+ INT_MASK(INT_INTCTRL_2) | \
+ INT_MASK(INT_INTCTRL_1) | \
+ INT_MASK(INT_INTCTRL_0) | \
+ INT_MASK(INT_BOOT_ACCESS) | \
+ INT_MASK(INT_WORLD_ACCESS) | \
+ INT_MASK(INT_I_ASID) | \
+ INT_MASK(INT_D_ASID) | \
+ INT_MASK(INT_DOUBLE_FAULT) | \
+ 0)
+#define NONQUEUED_INTERRUPTS ( \
+ INT_MASK(INT_SINGLE_STEP_3) | \
+ INT_MASK(INT_SINGLE_STEP_2) | \
+ INT_MASK(INT_SINGLE_STEP_1) | \
+ INT_MASK(INT_SINGLE_STEP_0) | \
+ INT_MASK(INT_ITLB_MISS) | \
+ INT_MASK(INT_ILL) | \
+ INT_MASK(INT_GPV) | \
+ INT_MASK(INT_IDN_ACCESS) | \
+ INT_MASK(INT_UDN_ACCESS) | \
+ INT_MASK(INT_SWINT_3) | \
+ INT_MASK(INT_SWINT_2) | \
+ INT_MASK(INT_SWINT_1) | \
+ INT_MASK(INT_SWINT_0) | \
+ INT_MASK(INT_ILL_TRANS) | \
+ INT_MASK(INT_UNALIGN_DATA) | \
+ INT_MASK(INT_DTLB_MISS) | \
+ INT_MASK(INT_DTLB_ACCESS) | \
+ 0)
+#define CRITICAL_MASKED_INTERRUPTS ( \
+ INT_MASK(INT_MEM_ERROR) | \
+ INT_MASK(INT_SINGLE_STEP_3) | \
+ INT_MASK(INT_SINGLE_STEP_2) | \
+ INT_MASK(INT_SINGLE_STEP_1) | \
+ INT_MASK(INT_SINGLE_STEP_0) | \
+ INT_MASK(INT_IDN_COMPLETE) | \
+ INT_MASK(INT_UDN_COMPLETE) | \
+ INT_MASK(INT_IDN_FIREWALL) | \
+ INT_MASK(INT_UDN_FIREWALL) | \
+ INT_MASK(INT_TILE_TIMER) | \
+ INT_MASK(INT_AUX_TILE_TIMER) | \
+ INT_MASK(INT_IDN_TIMER) | \
+ INT_MASK(INT_UDN_TIMER) | \
+ INT_MASK(INT_IDN_AVAIL) | \
+ INT_MASK(INT_UDN_AVAIL) | \
+ INT_MASK(INT_IPI_3) | \
+ INT_MASK(INT_IPI_2) | \
+ INT_MASK(INT_IPI_1) | \
+ INT_MASK(INT_IPI_0) | \
+ INT_MASK(INT_PERF_COUNT) | \
+ INT_MASK(INT_AUX_PERF_COUNT) | \
+ INT_MASK(INT_INTCTRL_3) | \
+ INT_MASK(INT_INTCTRL_2) | \
+ INT_MASK(INT_INTCTRL_1) | \
+ INT_MASK(INT_INTCTRL_0) | \
+ 0)
+#define CRITICAL_UNMASKED_INTERRUPTS ( \
+ INT_MASK(INT_ITLB_MISS) | \
+ INT_MASK(INT_ILL) | \
+ INT_MASK(INT_GPV) | \
+ INT_MASK(INT_IDN_ACCESS) | \
+ INT_MASK(INT_UDN_ACCESS) | \
+ INT_MASK(INT_SWINT_3) | \
+ INT_MASK(INT_SWINT_2) | \
+ INT_MASK(INT_SWINT_1) | \
+ INT_MASK(INT_SWINT_0) | \
+ INT_MASK(INT_ILL_TRANS) | \
+ INT_MASK(INT_UNALIGN_DATA) | \
+ INT_MASK(INT_DTLB_MISS) | \
+ INT_MASK(INT_DTLB_ACCESS) | \
+ INT_MASK(INT_BOOT_ACCESS) | \
+ INT_MASK(INT_WORLD_ACCESS) | \
+ INT_MASK(INT_I_ASID) | \
+ INT_MASK(INT_D_ASID) | \
+ INT_MASK(INT_DOUBLE_FAULT) | \
+ 0)
+#define MASKABLE_INTERRUPTS ( \
+ INT_MASK(INT_MEM_ERROR) | \
+ INT_MASK(INT_SINGLE_STEP_3) | \
+ INT_MASK(INT_SINGLE_STEP_2) | \
+ INT_MASK(INT_SINGLE_STEP_1) | \
+ INT_MASK(INT_SINGLE_STEP_0) | \
+ INT_MASK(INT_IDN_COMPLETE) | \
+ INT_MASK(INT_UDN_COMPLETE) | \
+ INT_MASK(INT_IDN_FIREWALL) | \
+ INT_MASK(INT_UDN_FIREWALL) | \
+ INT_MASK(INT_TILE_TIMER) | \
+ INT_MASK(INT_AUX_TILE_TIMER) | \
+ INT_MASK(INT_IDN_TIMER) | \
+ INT_MASK(INT_UDN_TIMER) | \
+ INT_MASK(INT_IDN_AVAIL) | \
+ INT_MASK(INT_UDN_AVAIL) | \
+ INT_MASK(INT_IPI_3) | \
+ INT_MASK(INT_IPI_2) | \
+ INT_MASK(INT_IPI_1) | \
+ INT_MASK(INT_IPI_0) | \
+ INT_MASK(INT_PERF_COUNT) | \
+ INT_MASK(INT_AUX_PERF_COUNT) | \
+ INT_MASK(INT_INTCTRL_3) | \
+ INT_MASK(INT_INTCTRL_2) | \
+ INT_MASK(INT_INTCTRL_1) | \
+ INT_MASK(INT_INTCTRL_0) | \
+ 0)
+#define UNMASKABLE_INTERRUPTS ( \
+ INT_MASK(INT_ITLB_MISS) | \
+ INT_MASK(INT_ILL) | \
+ INT_MASK(INT_GPV) | \
+ INT_MASK(INT_IDN_ACCESS) | \
+ INT_MASK(INT_UDN_ACCESS) | \
+ INT_MASK(INT_SWINT_3) | \
+ INT_MASK(INT_SWINT_2) | \
+ INT_MASK(INT_SWINT_1) | \
+ INT_MASK(INT_SWINT_0) | \
+ INT_MASK(INT_ILL_TRANS) | \
+ INT_MASK(INT_UNALIGN_DATA) | \
+ INT_MASK(INT_DTLB_MISS) | \
+ INT_MASK(INT_DTLB_ACCESS) | \
+ INT_MASK(INT_BOOT_ACCESS) | \
+ INT_MASK(INT_WORLD_ACCESS) | \
+ INT_MASK(INT_I_ASID) | \
+ INT_MASK(INT_D_ASID) | \
+ INT_MASK(INT_DOUBLE_FAULT) | \
+ 0)
+#define SYNC_INTERRUPTS ( \
+ INT_MASK(INT_SINGLE_STEP_3) | \
+ INT_MASK(INT_SINGLE_STEP_2) | \
+ INT_MASK(INT_SINGLE_STEP_1) | \
+ INT_MASK(INT_SINGLE_STEP_0) | \
+ INT_MASK(INT_IDN_COMPLETE) | \
+ INT_MASK(INT_UDN_COMPLETE) | \
+ INT_MASK(INT_ITLB_MISS) | \
+ INT_MASK(INT_ILL) | \
+ INT_MASK(INT_GPV) | \
+ INT_MASK(INT_IDN_ACCESS) | \
+ INT_MASK(INT_UDN_ACCESS) | \
+ INT_MASK(INT_SWINT_3) | \
+ INT_MASK(INT_SWINT_2) | \
+ INT_MASK(INT_SWINT_1) | \
+ INT_MASK(INT_SWINT_0) | \
+ INT_MASK(INT_ILL_TRANS) | \
+ INT_MASK(INT_UNALIGN_DATA) | \
+ INT_MASK(INT_DTLB_MISS) | \
+ INT_MASK(INT_DTLB_ACCESS) | \
+ 0)
+#define NON_SYNC_INTERRUPTS ( \
+ INT_MASK(INT_MEM_ERROR) | \
+ INT_MASK(INT_IDN_FIREWALL) | \
+ INT_MASK(INT_UDN_FIREWALL) | \
+ INT_MASK(INT_TILE_TIMER) | \
+ INT_MASK(INT_AUX_TILE_TIMER) | \
+ INT_MASK(INT_IDN_TIMER) | \
+ INT_MASK(INT_UDN_TIMER) | \
+ INT_MASK(INT_IDN_AVAIL) | \
+ INT_MASK(INT_UDN_AVAIL) | \
+ INT_MASK(INT_IPI_3) | \
+ INT_MASK(INT_IPI_2) | \
+ INT_MASK(INT_IPI_1) | \
+ INT_MASK(INT_IPI_0) | \
+ INT_MASK(INT_PERF_COUNT) | \
+ INT_MASK(INT_AUX_PERF_COUNT) | \
+ INT_MASK(INT_INTCTRL_3) | \
+ INT_MASK(INT_INTCTRL_2) | \
+ INT_MASK(INT_INTCTRL_1) | \
+ INT_MASK(INT_INTCTRL_0) | \
+ INT_MASK(INT_BOOT_ACCESS) | \
+ INT_MASK(INT_WORLD_ACCESS) | \
+ INT_MASK(INT_I_ASID) | \
+ INT_MASK(INT_D_ASID) | \
+ INT_MASK(INT_DOUBLE_FAULT) | \
+ 0)
+#endif /* !__ASSEMBLER__ */
+#endif /* !__ARCH_INTERRUPTS_H__ */
diff --git a/arch/tile/include/arch/spr_def.h b/arch/tile/include/arch/spr_def.h
index 442fcba0d122..f548efeb2de3 100644
--- a/arch/tile/include/arch/spr_def.h
+++ b/arch/tile/include/arch/spr_def.h
@@ -12,6 +12,15 @@
* more details.
*/
+/* Include the proper base SPR definition file. */
+#ifdef __tilegx__
+#include <arch/spr_def_64.h>
+#else
+#include <arch/spr_def_32.h>
+#endif
+
+#ifdef __KERNEL__
+
/*
* In addition to including the proper base SPR definition file, depending
* on machine architecture, this file defines several macros which allow
@@ -29,7 +38,6 @@
#define _concat4(a, b, c, d) __concat4(a, b, c, d)
#ifdef __tilegx__
-#include <arch/spr_def_64.h>
/* TILE-Gx dependent, protection-level dependent SPRs. */
@@ -65,7 +73,6 @@
_concat4(INT_SINGLE_STEP_, CONFIG_KERNEL_PL,,)
#else
-#include <arch/spr_def_32.h>
/* TILEPro dependent, protection-level dependent SPRs. */
@@ -102,3 +109,5 @@
_concat4(SPR_INTCTRL_, CONFIG_KERNEL_PL, _STATUS,)
#define INT_INTCTRL_K \
_concat4(INT_INTCTRL_, CONFIG_KERNEL_PL,,)
+
+#endif /* __KERNEL__ */
diff --git a/arch/tile/include/arch/spr_def_64.h b/arch/tile/include/arch/spr_def_64.h
new file mode 100644
index 000000000000..cd3e5f95d5fd
--- /dev/null
+++ b/arch/tile/include/arch/spr_def_64.h
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in 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.
+ */
+
+#ifndef __DOXYGEN__
+
+#ifndef __ARCH_SPR_DEF_H__
+#define __ARCH_SPR_DEF_H__
+
+#define SPR_AUX_PERF_COUNT_0 0x2105
+#define SPR_AUX_PERF_COUNT_1 0x2106
+#define SPR_AUX_PERF_COUNT_CTL 0x2107
+#define SPR_AUX_PERF_COUNT_STS 0x2108
+#define SPR_CMPEXCH_VALUE 0x2780
+#define SPR_CYCLE 0x2781
+#define SPR_DONE 0x2705
+#define SPR_DSTREAM_PF 0x2706
+#define SPR_EVENT_BEGIN 0x2782
+#define SPR_EVENT_END 0x2783
+#define SPR_EX_CONTEXT_0_0 0x2580
+#define SPR_EX_CONTEXT_0_1 0x2581
+#define SPR_EX_CONTEXT_0_1__PL_SHIFT 0
+#define SPR_EX_CONTEXT_0_1__PL_RMASK 0x3
+#define SPR_EX_CONTEXT_0_1__PL_MASK 0x3
+#define SPR_EX_CONTEXT_0_1__ICS_SHIFT 2
+#define SPR_EX_CONTEXT_0_1__ICS_RMASK 0x1
+#define SPR_EX_CONTEXT_0_1__ICS_MASK 0x4
+#define SPR_EX_CONTEXT_1_0 0x2480
+#define SPR_EX_CONTEXT_1_1 0x2481
+#define SPR_EX_CONTEXT_1_1__PL_SHIFT 0
+#define SPR_EX_CONTEXT_1_1__PL_RMASK 0x3
+#define SPR_EX_CONTEXT_1_1__PL_MASK 0x3
+#define SPR_EX_CONTEXT_1_1__ICS_SHIFT 2
+#define SPR_EX_CONTEXT_1_1__ICS_RMASK 0x1
+#define SPR_EX_CONTEXT_1_1__ICS_MASK 0x4
+#define SPR_EX_CONTEXT_2_0 0x2380
+#define SPR_EX_CONTEXT_2_1 0x2381
+#define SPR_EX_CONTEXT_2_1__PL_SHIFT 0
+#define SPR_EX_CONTEXT_2_1__PL_RMASK 0x3
+#define SPR_EX_CONTEXT_2_1__PL_MASK 0x3
+#define SPR_EX_CONTEXT_2_1__ICS_SHIFT 2
+#define SPR_EX_CONTEXT_2_1__ICS_RMASK 0x1
+#define SPR_EX_CONTEXT_2_1__ICS_MASK 0x4
+#define SPR_FAIL 0x2707
+#define SPR_ILL_TRANS_REASON__I_STREAM_VA_RMASK 0x1
+#define SPR_INTCTRL_0_STATUS 0x2505
+#define SPR_INTCTRL_1_STATUS 0x2405
+#define SPR_INTCTRL_2_STATUS 0x2305
+#define SPR_INTERRUPT_CRITICAL_SECTION 0x2708
+#define SPR_INTERRUPT_MASK_0 0x2506
+#define SPR_INTERRUPT_MASK_1 0x2406
+#define SPR_INTERRUPT_MASK_2 0x2306
+#define SPR_INTERRUPT_MASK_RESET_0 0x2507
+#define SPR_INTERRUPT_MASK_RESET_1 0x2407
+#define SPR_INTERRUPT_MASK_RESET_2 0x2307
+#define SPR_INTERRUPT_MASK_SET_0 0x2508
+#define SPR_INTERRUPT_MASK_SET_1 0x2408
+#define SPR_INTERRUPT_MASK_SET_2 0x2308
+#define SPR_INTERRUPT_VECTOR_BASE_0 0x2509
+#define SPR_INTERRUPT_VECTOR_BASE_1 0x2409
+#define SPR_INTERRUPT_VECTOR_BASE_2 0x2309
+#define SPR_INTERRUPT_VECTOR_BASE_3 0x2209
+#define SPR_IPI_EVENT_0 0x1f05
+#define SPR_IPI_EVENT_1 0x1e05
+#define SPR_IPI_EVENT_2 0x1d05
+#define SPR_IPI_EVENT_RESET_0 0x1f06
+#define SPR_IPI_EVENT_RESET_1 0x1e06
+#define SPR_IPI_EVENT_RESET_2 0x1d06
+#define SPR_IPI_EVENT_SET_0 0x1f07
+#define SPR_IPI_EVENT_SET_1 0x1e07
+#define SPR_IPI_EVENT_SET_2 0x1d07
+#define SPR_IPI_MASK_0 0x1f08
+#define SPR_IPI_MASK_1 0x1e08
+#define SPR_IPI_MASK_2 0x1d08
+#define SPR_IPI_MASK_RESET_0 0x1f09
+#define SPR_IPI_MASK_RESET_1 0x1e09
+#define SPR_IPI_MASK_RESET_2 0x1d09
+#define SPR_IPI_MASK_SET_0 0x1f0a
+#define SPR_IPI_MASK_SET_1 0x1e0a
+#define SPR_IPI_MASK_SET_2 0x1d0a
+#define SPR_MPL_AUX_TILE_TIMER_SET_0 0x1700
+#define SPR_MPL_AUX_TILE_TIMER_SET_1 0x1701
+#define SPR_MPL_AUX_TILE_TIMER_SET_2 0x1702
+#define SPR_MPL_INTCTRL_0_SET_0 0x2500
+#define SPR_MPL_INTCTRL_0_SET_1 0x2501
+#define SPR_MPL_INTCTRL_0_SET_2 0x2502
+#define SPR_MPL_INTCTRL_1_SET_0 0x2400
+#define SPR_MPL_INTCTRL_1_SET_1 0x2401
+#define SPR_MPL_INTCTRL_1_SET_2 0x2402
+#define SPR_MPL_INTCTRL_2_SET_0 0x2300
+#define SPR_MPL_INTCTRL_2_SET_1 0x2301
+#define SPR_MPL_INTCTRL_2_SET_2 0x2302
+#define SPR_MPL_UDN_ACCESS_SET_0 0x0b00
+#define SPR_MPL_UDN_ACCESS_SET_1 0x0b01
+#define SPR_MPL_UDN_ACCESS_SET_2 0x0b02
+#define SPR_MPL_UDN_AVAIL_SET_0 0x1b00
+#define SPR_MPL_UDN_AVAIL_SET_1 0x1b01
+#define SPR_MPL_UDN_AVAIL_SET_2 0x1b02
+#define SPR_MPL_UDN_COMPLETE_SET_0 0x0600
+#define SPR_MPL_UDN_COMPLETE_SET_1 0x0601
+#define SPR_MPL_UDN_COMPLETE_SET_2 0x0602
+#define SPR_MPL_UDN_FIREWALL_SET_0 0x1500
+#define SPR_MPL_UDN_FIREWALL_SET_1 0x1501
+#define SPR_MPL_UDN_FIREWALL_SET_2 0x1502
+#define SPR_MPL_UDN_TIMER_SET_0 0x1900
+#define SPR_MPL_UDN_TIMER_SET_1 0x1901
+#define SPR_MPL_UDN_TIMER_SET_2 0x1902
+#define SPR_MPL_WORLD_ACCESS_SET_0 0x2700
+#define SPR_MPL_WORLD_ACCESS_SET_1 0x2701
+#define SPR_MPL_WORLD_ACCESS_SET_2 0x2702
+#define SPR_PASS 0x2709
+#define SPR_PERF_COUNT_0 0x2005
+#define SPR_PERF_COUNT_1 0x2006
+#define SPR_PERF_COUNT_CTL 0x2007
+#define SPR_PERF_COUNT_DN_CTL 0x2008
+#define SPR_PERF_COUNT_STS 0x2009
+#define SPR_PROC_STATUS 0x2784
+#define SPR_SIM_CONTROL 0x2785
+#define SPR_SINGLE_STEP_CONTROL_0 0x0405
+#define SPR_SINGLE_STEP_CONTROL_0__CANCELED_MASK 0x1
+#define SPR_SINGLE_STEP_CONTROL_0__INHIBIT_MASK 0x2
+#define SPR_SINGLE_STEP_CONTROL_1 0x0305
+#define SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK 0x1
+#define SPR_SINGLE_STEP_CONTROL_1__INHIBIT_MASK 0x2
+#define SPR_SINGLE_STEP_CONTROL_2 0x0205
+#define SPR_SINGLE_STEP_CONTROL_2__CANCELED_MASK 0x1
+#define SPR_SINGLE_STEP_CONTROL_2__INHIBIT_MASK 0x2
+#define SPR_SINGLE_STEP_EN_0_0 0x250a
+#define SPR_SINGLE_STEP_EN_0_1 0x240a
+#define SPR_SINGLE_STEP_EN_0_2 0x230a
+#define SPR_SINGLE_STEP_EN_1_0 0x250b
+#define SPR_SINGLE_STEP_EN_1_1 0x240b
+#define SPR_SINGLE_STEP_EN_1_2 0x230b
+#define SPR_SINGLE_STEP_EN_2_0 0x250c
+#define SPR_SINGLE_STEP_EN_2_1 0x240c
+#define SPR_SINGLE_STEP_EN_2_2 0x230c
+#define SPR_SYSTEM_SAVE_0_0 0x2582
+#define SPR_SYSTEM_SAVE_0_1 0x2583
+#define SPR_SYSTEM_SAVE_0_2 0x2584
+#define SPR_SYSTEM_SAVE_0_3 0x2585
+#define SPR_SYSTEM_SAVE_1_0 0x2482
+#define SPR_SYSTEM_SAVE_1_1 0x2483
+#define SPR_SYSTEM_SAVE_1_2 0x2484
+#define SPR_SYSTEM_SAVE_1_3 0x2485
+#define SPR_SYSTEM_SAVE_2_0 0x2382
+#define SPR_SYSTEM_SAVE_2_1 0x2383
+#define SPR_SYSTEM_SAVE_2_2 0x2384
+#define SPR_SYSTEM_SAVE_2_3 0x2385
+#define SPR_TILE_COORD 0x270b
+#define SPR_TILE_RTF_HWM 0x270c
+#define SPR_TILE_TIMER_CONTROL 0x1605
+#define SPR_UDN_AVAIL_EN 0x1b05
+#define SPR_UDN_DATA_AVAIL 0x0b80
+#define SPR_UDN_DEADLOCK_TIMEOUT 0x1906
+#define SPR_UDN_DEMUX_COUNT_0 0x0b05
+#define SPR_UDN_DEMUX_COUNT_1 0x0b06
+#define SPR_UDN_DEMUX_COUNT_2 0x0b07
+#define SPR_UDN_DEMUX_COUNT_3 0x0b08
+#define SPR_UDN_DIRECTION_PROTECT 0x1505
+
+#endif /* !defined(__ARCH_SPR_DEF_H__) */
+
+#endif /* !defined(__DOXYGEN__) */
diff --git a/arch/tile/include/asm/atomic.h b/arch/tile/include/asm/atomic.h
index 75a16028a952..739cfe0499d1 100644
--- a/arch/tile/include/asm/atomic.h
+++ b/arch/tile/include/asm/atomic.h
@@ -130,17 +130,52 @@ static inline int atomic_read(const atomic_t *v)
*/
#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
-
-/*
- * We define xchg() and cmpxchg() in the included headers.
- * Note that we do not define __HAVE_ARCH_CMPXCHG, since that would imply
- * that cmpxchg() is an efficient operation, which is not particularly true.
- */
-
/* Nonexistent functions intended to cause link errors. */
extern unsigned long __xchg_called_with_bad_pointer(void);
extern unsigned long __cmpxchg_called_with_bad_pointer(void);
+#define xchg(ptr, x) \
+ ({ \
+ typeof(*(ptr)) __x; \
+ switch (sizeof(*(ptr))) { \
+ case 4: \
+ __x = (typeof(__x))(typeof(__x-__x))atomic_xchg( \
+ (atomic_t *)(ptr), \
+ (u32)(typeof((x)-(x)))(x)); \
+ break; \
+ case 8: \
+ __x = (typeof(__x))(typeof(__x-__x))atomic64_xchg( \
+ (atomic64_t *)(ptr), \
+ (u64)(typeof((x)-(x)))(x)); \
+ break; \
+ default: \
+ __xchg_called_with_bad_pointer(); \
+ } \
+ __x; \
+ })
+
+#define cmpxchg(ptr, o, n) \
+ ({ \
+ typeof(*(ptr)) __x; \
+ switch (sizeof(*(ptr))) { \
+ case 4: \
+ __x = (typeof(__x))(typeof(__x-__x))atomic_cmpxchg( \
+ (atomic_t *)(ptr), \
+ (u32)(typeof((o)-(o)))(o), \
+ (u32)(typeof((n)-(n)))(n)); \
+ break; \
+ case 8: \
+ __x = (typeof(__x))(typeof(__x-__x))atomic64_cmpxchg( \
+ (atomic64_t *)(ptr), \
+ (u64)(typeof((o)-(o)))(o), \
+ (u64)(typeof((n)-(n)))(n)); \
+ break; \
+ default: \
+ __cmpxchg_called_with_bad_pointer(); \
+ } \
+ __x; \
+ })
+
#define tas(ptr) (xchg((ptr), 1))
#endif /* __ASSEMBLY__ */
diff --git a/arch/tile/include/asm/atomic_32.h b/arch/tile/include/asm/atomic_32.h
index ed359aee8837..92a8bee32311 100644
--- a/arch/tile/include/asm/atomic_32.h
+++ b/arch/tile/include/asm/atomic_32.h
@@ -110,16 +110,6 @@ static inline void atomic_set(atomic_t *v, int n)
_atomic_xchg(v, n);
}
-#define xchg(ptr, x) ((typeof(*(ptr))) \
- ((sizeof(*(ptr)) == sizeof(atomic_t)) ? \
- atomic_xchg((atomic_t *)(ptr), (long)(x)) : \
- __xchg_called_with_bad_pointer()))
-
-#define cmpxchg(ptr, o, n) ((typeof(*(ptr))) \
- ((sizeof(*(ptr)) == sizeof(atomic_t)) ? \
- atomic_cmpxchg((atomic_t *)(ptr), (long)(o), (long)(n)) : \
- __cmpxchg_called_with_bad_pointer()))
-
/* A 64bit atomic type */
typedef struct {
diff --git a/arch/tile/include/asm/atomic_64.h b/arch/tile/include/asm/atomic_64.h
new file mode 100644
index 000000000000..1c1e60d8ccb6
--- /dev/null
+++ b/arch/tile/include/asm/atomic_64.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in 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.
+ *
+ * Do not include directly; use <asm/atomic.h>.
+ */
+
+#ifndef _ASM_TILE_ATOMIC_64_H
+#define _ASM_TILE_ATOMIC_64_H
+
+#ifndef __ASSEMBLY__
+
+#include <arch/spr_def.h>
+
+/* First, the 32-bit atomic ops that are "real" on our 64-bit platform. */
+
+#define atomic_set(v, i) ((v)->counter = (i))
+
+/*
+ * The smp_mb() operations throughout are to support the fact that
+ * Linux requires memory barriers before and after the operation,
+ * on any routine which updates memory and returns a value.
+ */
+
+static inline int atomic_cmpxchg(atomic_t *v, int o, int n)
+{
+ int val;
+ __insn_mtspr(SPR_CMPEXCH_VALUE, o);
+ smp_mb(); /* barrier for proper semantics */
+ val = __insn_cmpexch4((void *)&v->counter, n);
+ smp_mb(); /* barrier for proper semantics */
+ return val;
+}
+
+static inline int atomic_xchg(atomic_t *v, int n)
+{
+ int val;
+ smp_mb(); /* barrier for proper semantics */
+ val = __insn_exch4((void *)&v->counter, n);
+ smp_mb(); /* barrier for proper semantics */
+ return val;
+}
+
+static inline void atomic_add(int i, atomic_t *v)
+{
+ __insn_fetchadd4((void *)&v->counter, i);
+}
+
+static inline int atomic_add_return(int i, atomic_t *v)
+{
+ int val;
+ smp_mb(); /* barrier for proper semantics */
+ val = __insn_fetchadd4((void *)&v->counter, i) + i;
+ barrier(); /* the "+ i" above will wait on memory */
+ return val;
+}
+
+static inline int atomic_add_unless(atomic_t *v, int a, int u)
+{
+ int guess, oldval = v->counter;
+ do {
+ if (oldval == u)
+ break;
+ guess = oldval;
+ oldval = atomic_cmpxchg(v, guess, guess + a);
+ } while (guess != oldval);
+ return oldval != u;
+}
+
+/* Now the true 64-bit operations. */
+
+#define ATOMIC64_INIT(i) { (i) }
+
+#define atomic64_read(v) ((v)->counter)
+#define atomic64_set(v, i) ((v)->counter = (i))
+
+static inline long atomic64_cmpxchg(atomic64_t *v, long o, long n)
+{
+ long val;
+ smp_mb(); /* barrier for proper semantics */
+ __insn_mtspr(SPR_CMPEXCH_VALUE, o);
+ val = __insn_cmpexch((void *)&v->counter, n);
+ smp_mb(); /* barrier for proper semantics */
+ return val;
+}
+
+static inline long atomic64_xchg(atomic64_t *v, long n)
+{
+ long val;
+ smp_mb(); /* barrier for proper semantics */
+ val = __insn_exch((void *)&v->counter, n);
+ smp_mb(); /* barrier for proper semantics */
+ return val;
+}
+
+static inline void atomic64_add(long i, atomic64_t *v)
+{
+ __insn_fetchadd((void *)&v->counter, i);
+}
+
+static inline long atomic64_add_return(long i, atomic64_t *v)
+{
+ int val;
+ smp_mb(); /* barrier for proper semantics */
+ val = __insn_fetchadd((void *)&v->counter, i) + i;
+ barrier(); /* the "+ i" above will wait on memory */
+ return val;
+}
+
+static inline long atomic64_add_unless(atomic64_t *v, long a, long u)
+{
+ long guess, oldval = v->counter;
+ do {
+ if (oldval == u)
+ break;
+ guess = oldval;
+ oldval = atomic64_cmpxchg(v, guess, guess + a);
+ } while (guess != oldval);
+ return oldval != u;
+}
+
+#define atomic64_sub_return(i, v) atomic64_add_return(-(i), (v))
+#define atomic64_sub(i, v) atomic64_add(-(i), (v))
+#define atomic64_inc_return(v) atomic64_add_return(1, (v))
+#define atomic64_dec_return(v) atomic64_sub_return(1, (v))
+#define atomic64_inc(v) atomic64_add(1, (v))
+#define atomic64_dec(v) atomic64_sub(1, (v))
+
+#define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0)
+#define atomic64_dec_and_test(v) (atomic64_dec_return(v) == 0)
+#define atomic64_sub_and_test(i, v) (atomic64_sub_return((i), (v)) == 0)
+#define atomic64_add_negative(i, v) (atomic64_add_return((i), (v)) < 0)
+
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
+
+/* Atomic dec and inc don't implement barrier, so provide them if needed. */
+#define smp_mb__before_atomic_dec() smp_mb()
+#define smp_mb__after_atomic_dec() smp_mb()
+#define smp_mb__before_atomic_inc() smp_mb()
+#define smp_mb__after_atomic_inc() smp_mb()
+
+/* Define this to indicate that cmpxchg is an efficient operation. */
+#define __HAVE_ARCH_CMPXCHG
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_TILE_ATOMIC_64_H */
diff --git a/arch/tile/include/asm/backtrace.h b/arch/tile/include/asm/backtrace.h
index f18887d82399..bd5399a69edf 100644
--- a/arch/tile/include/asm/backtrace.h
+++ b/arch/tile/include/asm/backtrace.h
@@ -12,80 +12,41 @@
* more details.
*/
-#ifndef _TILE_BACKTRACE_H
-#define _TILE_BACKTRACE_H
-
-
+#ifndef _ASM_TILE_BACKTRACE_H
+#define _ASM_TILE_BACKTRACE_H
#include <linux/types.h>
-#include <arch/chip.h>
-
-#if defined(__tile__)
-typedef unsigned long VirtualAddress;
-#elif CHIP_VA_WIDTH() > 32
-typedef unsigned long long VirtualAddress;
-#else
-typedef unsigned int VirtualAddress;
-#endif
-
-
-/** Reads 'size' bytes from 'address' and writes the data to 'result'.
+/* Reads 'size' bytes from 'address' and writes the data to 'result'.
* Returns true if successful, else false (e.g. memory not readable).
*/
typedef bool (*BacktraceMemoryReader)(void *result,
- VirtualAddress address,
+ unsigned long address,
unsigned int size,
void *extra);
typedef struct {
- /** Current PC. */
- VirtualAddress pc;
+ /* Current PC. */
+ unsigned long pc;
- /** Current stack pointer value. */
- VirtualAddress sp;
+ /* Current stack pointer value. */
+ unsigned long sp;
- /** Current frame pointer value (i.e. caller's stack pointer) */
- VirtualAddress fp;
+ /* Current frame pointer value (i.e. caller's stack pointer) */
+ unsigned long fp;
- /** Internal use only: caller's PC for first frame. */
- VirtualAddress initial_frame_caller_pc;
+ /* Internal use only: caller's PC for first frame. */
+ unsigned long initial_frame_caller_pc;
- /** Internal use only: callback to read memory. */
+ /* Internal use only: callback to read memory. */
BacktraceMemoryReader read_memory_func;
- /** Internal use only: arbitrary argument to read_memory_func. */
+ /* Internal use only: arbitrary argument to read_memory_func. */
void *read_memory_func_extra;
} BacktraceIterator;
-/** Initializes a backtracer to start from the given location.
- *
- * If the frame pointer cannot be determined it is set to -1.
- *
- * @param state The state to be filled in.
- * @param read_memory_func A callback that reads memory. If NULL, a default
- * value is provided.
- * @param read_memory_func_extra An arbitrary argument to read_memory_func.
- * @param pc The current PC.
- * @param lr The current value of the 'lr' register.
- * @param sp The current value of the 'sp' register.
- * @param r52 The current value of the 'r52' register.
- */
-extern void backtrace_init(BacktraceIterator *state,
- BacktraceMemoryReader read_memory_func,
- void *read_memory_func_extra,
- VirtualAddress pc, VirtualAddress lr,
- VirtualAddress sp, VirtualAddress r52);
-
-
-/** Advances the backtracing state to the calling frame, returning
- * true iff successful.
- */
-extern bool backtrace_next(BacktraceIterator *state);
-
-
typedef enum {
/* We have no idea what the caller's pc is. */
@@ -138,7 +99,7 @@ enum {
};
-/** Internal constants used to define 'info' operands. */
+/* Internal constants used to define 'info' operands. */
enum {
/* 0 and 1 are reserved, as are all negative numbers. */
@@ -147,13 +108,10 @@ enum {
CALLER_SP_IN_R52_BASE = 4,
CALLER_SP_OFFSET_BASE = 8,
-
- /* Marks the entry point of certain functions. */
- ENTRY_POINT_INFO_OP = 16
};
-/** Current backtracer state describing where it thinks the caller is. */
+/* Current backtracer state describing where it thinks the caller is. */
typedef struct {
/*
* Public fields
@@ -192,7 +150,13 @@ typedef struct {
} CallerLocation;
+extern void backtrace_init(BacktraceIterator *state,
+ BacktraceMemoryReader read_memory_func,
+ void *read_memory_func_extra,
+ unsigned long pc, unsigned long lr,
+ unsigned long sp, unsigned long r52);
+extern bool backtrace_next(BacktraceIterator *state);
-#endif /* _TILE_BACKTRACE_H */
+#endif /* _ASM_TILE_BACKTRACE_H */
diff --git a/arch/tile/include/asm/bitops.h b/arch/tile/include/asm/bitops.h
index 132e6bbd07e9..16f1fa51fea1 100644
--- a/arch/tile/include/asm/bitops.h
+++ b/arch/tile/include/asm/bitops.h
@@ -122,6 +122,7 @@ static inline unsigned long __arch_hweight64(__u64 w)
#include <asm-generic/bitops/lock.h>
#include <asm-generic/bitops/find.h>
#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/non-atomic.h>
#include <asm-generic/bitops/le.h>
#endif /* _ASM_TILE_BITOPS_H */
diff --git a/arch/tile/include/asm/bitops_32.h b/arch/tile/include/asm/bitops_32.h
index 2638be51a164..d31ab905cfa7 100644
--- a/arch/tile/include/asm/bitops_32.h
+++ b/arch/tile/include/asm/bitops_32.h
@@ -126,7 +126,6 @@ static inline int test_and_change_bit(unsigned nr,
#define smp_mb__before_clear_bit() smp_mb()
#define smp_mb__after_clear_bit() do {} while (0)
-#include <asm-generic/bitops/non-atomic.h>
#include <asm-generic/bitops/ext2-atomic.h>
#endif /* _ASM_TILE_BITOPS_32_H */
diff --git a/arch/tile/include/asm/bitops_64.h b/arch/tile/include/asm/bitops_64.h
new file mode 100644
index 000000000000..99615e8d2d8b
--- /dev/null
+++ b/arch/tile/include/asm/bitops_64.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in 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.
+ */
+
+#ifndef _ASM_TILE_BITOPS_64_H
+#define _ASM_TILE_BITOPS_64_H
+
+#include <linux/compiler.h>
+#include <asm/atomic.h>
+#include <asm/system.h>
+
+/* See <asm/bitops.h> for API comments. */
+
+static inline void set_bit(unsigned nr, volatile unsigned long *addr)
+{
+ unsigned long mask = (1UL << (nr % BITS_PER_LONG));
+ __insn_fetchor((void *)(addr + nr / BITS_PER_LONG), mask);
+}
+
+static inline void clear_bit(unsigned nr, volatile unsigned long *addr)
+{
+ unsigned long mask = (1UL << (nr % BITS_PER_LONG));
+ __insn_fetchand((void *)(addr + nr / BITS_PER_LONG), ~mask);
+}
+
+#define smp_mb__before_clear_bit() smp_mb()
+#define smp_mb__after_clear_bit() smp_mb()
+
+
+static inline void change_bit(unsigned nr, volatile unsigned long *addr)
+{
+ unsigned long old, mask = (1UL << (nr % BITS_PER_LONG));
+ long guess, oldval;
+ addr += nr / BITS_PER_LONG;
+ old = *addr;
+ do {
+ guess = oldval;
+ oldval = atomic64_cmpxchg((atomic64_t *)addr,
+ guess, guess ^ mask);
+ } while (guess != oldval);
+}
+
+
+/*
+ * The test_and_xxx_bit() routines require a memory fence before we
+ * start the operation, and after the operation completes. We use
+ * smp_mb() before, and rely on the "!= 0" comparison, plus a compiler
+ * barrier(), to block until the atomic op is complete.
+ */
+
+static inline int test_and_set_bit(unsigned nr, volatile unsigned long *addr)
+{
+ int val;
+ unsigned long mask = (1UL << (nr % BITS_PER_LONG));
+ smp_mb(); /* barrier for proper semantics */
+ val = (__insn_fetchor((void *)(addr + nr / BITS_PER_LONG), mask)
+ & mask) != 0;
+ barrier();
+ return val;
+}
+
+
+static inline int test_and_clear_bit(unsigned nr, volatile unsigned long *addr)
+{
+ int val;
+ unsigned long mask = (1UL << (nr % BITS_PER_LONG));
+ smp_mb(); /* barrier for proper semantics */
+ val = (__insn_fetchand((void *)(addr + nr / BITS_PER_LONG), ~mask)
+ & mask) != 0;
+ barrier();
+ return val;
+}
+
+
+static inline int test_and_change_bit(unsigned nr,
+ volatile unsigned long *addr)
+{
+ unsigned long mask = (1UL << (nr % BITS_PER_LONG));
+ long guess, oldval = *addr;
+ addr += nr / BITS_PER_LONG;
+ oldval = *addr;
+ do {
+ guess = oldval;
+ oldval = atomic64_cmpxchg((atomic64_t *)addr,
+ guess, guess ^ mask);
+ } while (guess != oldval);
+ return (oldval & mask) != 0;
+}
+
+#define ext2_set_bit_atomic(lock, nr, addr) \
+ test_and_set_bit((nr), (unsigned long *)(addr))
+#define ext2_clear_bit_atomic(lock, nr, addr) \
+ test_and_clear_bit((nr), (unsigned long *)(addr))
+
+#endif /* _ASM_TILE_BITOPS_64_H */
diff --git a/arch/tile/include/asm/cacheflush.h b/arch/tile/include/asm/cacheflush.h
index 12fb0fb330ee..e925f4bb498f 100644
--- a/arch/tile/include/asm/cacheflush.h
+++ b/arch/tile/include/asm/cacheflush.h
@@ -116,22 +116,28 @@ static inline void __finv_buffer(void *buffer, size_t size)
}
-/* Invalidate a VA range, then memory fence. */
+/* Invalidate a VA range and wait for it to be complete. */
static inline void inv_buffer(void *buffer, size_t size)
{
__inv_buffer(buffer, size);
- mb_incoherent();
+ mb();
}
-/* Flush a VA range, then memory fence. */
-static inline void flush_buffer(void *buffer, size_t size)
+/*
+ * Flush a locally-homecached VA range and wait for the evicted
+ * cachelines to hit memory.
+ */
+static inline void flush_buffer_local(void *buffer, size_t size)
{
__flush_buffer(buffer, size);
mb_incoherent();
}
-/* Flush & invalidate a VA range, then memory fence. */
-static inline void finv_buffer(void *buffer, size_t size)
+/*
+ * Flush and invalidate a locally-homecached VA range and wait for the
+ * evicted cachelines to hit memory.
+ */
+static inline void finv_buffer_local(void *buffer, size_t size)
{
__finv_buffer(buffer, size);
mb_incoherent();
diff --git a/arch/tile/include/asm/compat.h b/arch/tile/include/asm/compat.h
index c3ae570c0a5d..bf95f55b82b0 100644
--- a/arch/tile/include/asm/compat.h
+++ b/arch/tile/include/asm/compat.h
@@ -215,8 +215,8 @@ struct compat_sigaction;
struct compat_siginfo;
struct compat_sigaltstack;
long compat_sys_execve(const char __user *path,
- const compat_uptr_t __user *argv,
- const compat_uptr_t __user *envp, struct pt_regs *);
+ compat_uptr_t __user *argv,
+ compat_uptr_t __user *envp, struct pt_regs *);
long compat_sys_rt_sigaction(int sig, struct compat_sigaction __user *act,
struct compat_sigaction __user *oact,
size_t sigsetsize);
diff --git a/arch/tile/include/asm/dma-mapping.h b/arch/tile/include/asm/dma-mapping.h
index 15e1dceecc64..eaa06d175b39 100644
--- a/arch/tile/include/asm/dma-mapping.h
+++ b/arch/tile/include/asm/dma-mapping.h
@@ -65,7 +65,8 @@ extern void dma_sync_single_range_for_cpu(struct device *, dma_addr_t,
extern void dma_sync_single_range_for_device(struct device *, dma_addr_t,
unsigned long offset, size_t,
enum dma_data_direction);
-extern void dma_cache_sync(void *vaddr, size_t, enum dma_data_direction);
+extern void dma_cache_sync(struct device *dev, void *vaddr, size_t,
+ enum dma_data_direction);
static inline int
dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
diff --git a/arch/tile/include/asm/fb.h b/arch/tile/include/asm/fb.h
new file mode 100644
index 000000000000..3a4988e8df45
--- /dev/null
+++ b/arch/tile/include/asm/fb.h
@@ -0,0 +1 @@
+#include <asm-generic/fb.h>
diff --git a/arch/tile/include/asm/io.h b/arch/tile/include/asm/io.h
index d3cbb9b14cbe..c9ea1652af03 100644
--- a/arch/tile/include/asm/io.h
+++ b/arch/tile/include/asm/io.h
@@ -52,6 +52,7 @@ extern void iounmap(volatile void __iomem *addr);
#endif
#define ioremap_nocache(physaddr, size) ioremap(physaddr, size)
+#define ioremap_wc(physaddr, size) ioremap(physaddr, size)
#define ioremap_writethrough(physaddr, size) ioremap(physaddr, size)
#define ioremap_fullcache(physaddr, size) ioremap(physaddr, size)
@@ -161,6 +162,15 @@ static inline void _tile_writeq(u64 val, unsigned long addr)
#define iowrite32 writel
#define iowrite64 writeq
+static inline void memset_io(void *dst, int val, size_t len)
+{
+ int x;
+ BUG_ON((unsigned long)dst & 0x3);
+ val = (val & 0xff) * 0x01010101;
+ for (x = 0; x < len; x += 4)
+ writel(val, dst + x);
+}
+
static inline void memcpy_fromio(void *dst, const volatile void __iomem *src,
size_t len)
{
@@ -269,6 +279,11 @@ static inline void outsl(unsigned long addr, const void *buffer, int count)
ioport_panic();
}
+#define ioread16be(addr) be16_to_cpu(ioread16(addr))
+#define ioread32be(addr) be32_to_cpu(ioread32(addr))
+#define iowrite16be(v, addr) iowrite16(be16_to_cpu(v), (addr))
+#define iowrite32be(v, addr) iowrite32(be32_to_cpu(v), (addr))
+
#define ioread8_rep(p, dst, count) \
insb((unsigned long) (p), (dst), (count))
#define ioread16_rep(p, dst, count) \
@@ -283,4 +298,7 @@ static inline void outsl(unsigned long addr, const void *buffer, int count)
#define iowrite32_rep(p, src, count) \
outsl((unsigned long) (p), (src), (count))
+#define virt_to_bus virt_to_phys
+#define bus_to_virt phys_to_virt
+
#endif /* _ASM_TILE_IO_H */
diff --git a/arch/tile/include/asm/irq.h b/arch/tile/include/asm/irq.h
index 572fd3ef1d73..94e9a511de84 100644
--- a/arch/tile/include/asm/irq.h
+++ b/arch/tile/include/asm/irq.h
@@ -23,6 +23,8 @@
/* IRQ numbers used for linux IPIs. */
#define IRQ_RESCHEDULE 1
+#define irq_canonicalize(irq) (irq)
+
void ack_bad_irq(unsigned int irq);
/*
diff --git a/arch/tile/include/asm/mmu_context.h b/arch/tile/include/asm/mmu_context.h
index 9bc0d0725c28..15fb24641120 100644
--- a/arch/tile/include/asm/mmu_context.h
+++ b/arch/tile/include/asm/mmu_context.h
@@ -100,8 +100,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
__get_cpu_var(current_asid) = asid;
/* Clear cpu from the old mm, and set it in the new one. */
- cpumask_clear_cpu(cpu, &prev->cpu_vm_mask);
- cpumask_set_cpu(cpu, &next->cpu_vm_mask);
+ cpumask_clear_cpu(cpu, mm_cpumask(prev));
+ cpumask_set_cpu(cpu, mm_cpumask(next));
/* Re-load page tables */
install_page_table(next->pgd, asid);
diff --git a/arch/tile/include/asm/opcode-tile_32.h b/arch/tile/include/asm/opcode-tile_32.h
index eda60ecbae3d..03df7b1e77bf 100644
--- a/arch/tile/include/asm/opcode-tile_32.h
+++ b/arch/tile/include/asm/opcode-tile_32.h
@@ -1502,5 +1502,12 @@ extern int parse_insn_tile(tile_bundle_bits bits,
decoded[TILE_MAX_INSTRUCTIONS_PER_BUNDLE]);
+/* Given a set of bundle bits and a specific pipe, returns which
+ * instruction the bundle contains in that pipe.
+ */
+extern const struct tile_opcode *
+find_opcode(tile_bundle_bits bits, tile_pipeline pipe);
+
+
#endif /* opcode_tile_h */
diff --git a/arch/tile/include/asm/opcode-tile_64.h b/arch/tile/include/asm/opcode-tile_64.h
index eda60ecbae3d..c0633466cd5c 100644
--- a/arch/tile/include/asm/opcode-tile_64.h
+++ b/arch/tile/include/asm/opcode-tile_64.h
@@ -5,863 +5,711 @@
#ifndef opcode_tile_h
#define opcode_tile_h
-typedef unsigned long long tile_bundle_bits;
+typedef unsigned long long tilegx_bundle_bits;
enum
{
- TILE_MAX_OPERANDS = 5 /* mm */
+ TILEGX_MAX_OPERANDS = 4 /* bfexts */
};
typedef enum
{
- TILE_OPC_BPT,
- TILE_OPC_INFO,
- TILE_OPC_INFOL,
- TILE_OPC_J,
- TILE_OPC_JAL,
- TILE_OPC_MOVE,
- TILE_OPC_MOVE_SN,
- TILE_OPC_MOVEI,
- TILE_OPC_MOVEI_SN,
- TILE_OPC_MOVELI,
- TILE_OPC_MOVELI_SN,
- TILE_OPC_MOVELIS,
- TILE_OPC_PREFETCH,
- TILE_OPC_RAISE,
- TILE_OPC_ADD,
- TILE_OPC_ADD_SN,
- TILE_OPC_ADDB,
- TILE_OPC_ADDB_SN,
- TILE_OPC_ADDBS_U,
- TILE_OPC_ADDBS_U_SN,
- TILE_OPC_ADDH,
- TILE_OPC_ADDH_SN,
- TILE_OPC_ADDHS,
- TILE_OPC_ADDHS_SN,
- TILE_OPC_ADDI,
- TILE_OPC_ADDI_SN,
- TILE_OPC_ADDIB,
- TILE_OPC_ADDIB_SN,
- TILE_OPC_ADDIH,
- TILE_OPC_ADDIH_SN,
- TILE_OPC_ADDLI,
- TILE_OPC_ADDLI_SN,
- TILE_OPC_ADDLIS,
- TILE_OPC_ADDS,
- TILE_OPC_ADDS_SN,
- TILE_OPC_ADIFFB_U,
- TILE_OPC_ADIFFB_U_SN,
- TILE_OPC_ADIFFH,
- TILE_OPC_ADIFFH_SN,
- TILE_OPC_AND,
- TILE_OPC_AND_SN,
- TILE_OPC_ANDI,
- TILE_OPC_ANDI_SN,
- TILE_OPC_AULI,
- TILE_OPC_AVGB_U,
- TILE_OPC_AVGB_U_SN,
- TILE_OPC_AVGH,
- TILE_OPC_AVGH_SN,
- TILE_OPC_BBNS,
- TILE_OPC_BBNS_SN,
- TILE_OPC_BBNST,
- TILE_OPC_BBNST_SN,
- TILE_OPC_BBS,
- TILE_OPC_BBS_SN,
- TILE_OPC_BBST,
- TILE_OPC_BBST_SN,
- TILE_OPC_BGEZ,
- TILE_OPC_BGEZ_SN,
- TILE_OPC_BGEZT,
- TILE_OPC_BGEZT_SN,
- TILE_OPC_BGZ,
- TILE_OPC_BGZ_SN,
- TILE_OPC_BGZT,
- TILE_OPC_BGZT_SN,
- TILE_OPC_BITX,
- TILE_OPC_BITX_SN,
- TILE_OPC_BLEZ,
- TILE_OPC_BLEZ_SN,
- TILE_OPC_BLEZT,
- TILE_OPC_BLEZT_SN,
- TILE_OPC_BLZ,
- TILE_OPC_BLZ_SN,
- TILE_OPC_BLZT,
- TILE_OPC_BLZT_SN,
- TILE_OPC_BNZ,
- TILE_OPC_BNZ_SN,
- TILE_OPC_BNZT,
- TILE_OPC_BNZT_SN,
- TILE_OPC_BYTEX,
- TILE_OPC_BYTEX_SN,
- TILE_OPC_BZ,
- TILE_OPC_BZ_SN,
- TILE_OPC_BZT,
- TILE_OPC_BZT_SN,
- TILE_OPC_CLZ,
- TILE_OPC_CLZ_SN,
- TILE_OPC_CRC32_32,
- TILE_OPC_CRC32_32_SN,
- TILE_OPC_CRC32_8,
- TILE_OPC_CRC32_8_SN,
- TILE_OPC_CTZ,
- TILE_OPC_CTZ_SN,
- TILE_OPC_DRAIN,
- TILE_OPC_DTLBPR,
- TILE_OPC_DWORD_ALIGN,
- TILE_OPC_DWORD_ALIGN_SN,
- TILE_OPC_FINV,
- TILE_OPC_FLUSH,
- TILE_OPC_FNOP,
- TILE_OPC_ICOH,
- TILE_OPC_ILL,
- TILE_OPC_INTHB,
- TILE_OPC_INTHB_SN,
- TILE_OPC_INTHH,
- TILE_OPC_INTHH_SN,
- TILE_OPC_INTLB,
- TILE_OPC_INTLB_SN,
- TILE_OPC_INTLH,
- TILE_OPC_INTLH_SN,
- TILE_OPC_INV,
- TILE_OPC_IRET,
- TILE_OPC_JALB,
- TILE_OPC_JALF,
- TILE_OPC_JALR,
- TILE_OPC_JALRP,
- TILE_OPC_JB,
- TILE_OPC_JF,
- TILE_OPC_JR,
- TILE_OPC_JRP,
- TILE_OPC_LB,
- TILE_OPC_LB_SN,
- TILE_OPC_LB_U,
- TILE_OPC_LB_U_SN,
- TILE_OPC_LBADD,
- TILE_OPC_LBADD_SN,
- TILE_OPC_LBADD_U,
- TILE_OPC_LBADD_U_SN,
- TILE_OPC_LH,
- TILE_OPC_LH_SN,
- TILE_OPC_LH_U,
- TILE_OPC_LH_U_SN,
- TILE_OPC_LHADD,
- TILE_OPC_LHADD_SN,
- TILE_OPC_LHADD_U,
- TILE_OPC_LHADD_U_SN,
- TILE_OPC_LNK,
- TILE_OPC_LNK_SN,
- TILE_OPC_LW,
- TILE_OPC_LW_SN,
- TILE_OPC_LW_NA,
- TILE_OPC_LW_NA_SN,
- TILE_OPC_LWADD,
- TILE_OPC_LWADD_SN,
- TILE_OPC_LWADD_NA,
- TILE_OPC_LWADD_NA_SN,
- TILE_OPC_MAXB_U,
- TILE_OPC_MAXB_U_SN,
- TILE_OPC_MAXH,
- TILE_OPC_MAXH_SN,
- TILE_OPC_MAXIB_U,
- TILE_OPC_MAXIB_U_SN,
- TILE_OPC_MAXIH,
- TILE_OPC_MAXIH_SN,
- TILE_OPC_MF,
- TILE_OPC_MFSPR,
- TILE_OPC_MINB_U,
- TILE_OPC_MINB_U_SN,
- TILE_OPC_MINH,
- TILE_OPC_MINH_SN,
- TILE_OPC_MINIB_U,
- TILE_OPC_MINIB_U_SN,
- TILE_OPC_MINIH,
- TILE_OPC_MINIH_SN,
- TILE_OPC_MM,
- TILE_OPC_MNZ,
- TILE_OPC_MNZ_SN,
- TILE_OPC_MNZB,
- TILE_OPC_MNZB_SN,
- TILE_OPC_MNZH,
- TILE_OPC_MNZH_SN,
- TILE_OPC_MTSPR,
- TILE_OPC_MULHH_SS,
- TILE_OPC_MULHH_SS_SN,
- TILE_OPC_MULHH_SU,
- TILE_OPC_MULHH_SU_SN,
- TILE_OPC_MULHH_UU,
- TILE_OPC_MULHH_UU_SN,
- TILE_OPC_MULHHA_SS,
- TILE_OPC_MULHHA_SS_SN,
- TILE_OPC_MULHHA_SU,
- TILE_OPC_MULHHA_SU_SN,
- TILE_OPC_MULHHA_UU,
- TILE_OPC_MULHHA_UU_SN,
- TILE_OPC_MULHHSA_UU,
- TILE_OPC_MULHHSA_UU_SN,
- TILE_OPC_MULHL_SS,
- TILE_OPC_MULHL_SS_SN,
- TILE_OPC_MULHL_SU,
- TILE_OPC_MULHL_SU_SN,
- TILE_OPC_MULHL_US,
- TILE_OPC_MULHL_US_SN,
- TILE_OPC_MULHL_UU,
- TILE_OPC_MULHL_UU_SN,
- TILE_OPC_MULHLA_SS,
- TILE_OPC_MULHLA_SS_SN,
- TILE_OPC_MULHLA_SU,
- TILE_OPC_MULHLA_SU_SN,
- TILE_OPC_MULHLA_US,
- TILE_OPC_MULHLA_US_SN,
- TILE_OPC_MULHLA_UU,
- TILE_OPC_MULHLA_UU_SN,
- TILE_OPC_MULHLSA_UU,
- TILE_OPC_MULHLSA_UU_SN,
- TILE_OPC_MULLL_SS,
- TILE_OPC_MULLL_SS_SN,
- TILE_OPC_MULLL_SU,
- TILE_OPC_MULLL_SU_SN,
- TILE_OPC_MULLL_UU,
- TILE_OPC_MULLL_UU_SN,
- TILE_OPC_MULLLA_SS,
- TILE_OPC_MULLLA_SS_SN,
- TILE_OPC_MULLLA_SU,
- TILE_OPC_MULLLA_SU_SN,
- TILE_OPC_MULLLA_UU,
- TILE_OPC_MULLLA_UU_SN,
- TILE_OPC_MULLLSA_UU,
- TILE_OPC_MULLLSA_UU_SN,
- TILE_OPC_MVNZ,
- TILE_OPC_MVNZ_SN,
- TILE_OPC_MVZ,
- TILE_OPC_MVZ_SN,
- TILE_OPC_MZ,
- TILE_OPC_MZ_SN,
- TILE_OPC_MZB,
- TILE_OPC_MZB_SN,
- TILE_OPC_MZH,
- TILE_OPC_MZH_SN,
- TILE_OPC_NAP,
- TILE_OPC_NOP,
- TILE_OPC_NOR,
- TILE_OPC_NOR_SN,
- TILE_OPC_OR,
- TILE_OPC_OR_SN,
- TILE_OPC_ORI,
- TILE_OPC_ORI_SN,
- TILE_OPC_PACKBS_U,
- TILE_OPC_PACKBS_U_SN,
- TILE_OPC_PACKHB,
- TILE_OPC_PACKHB_SN,
- TILE_OPC_PACKHS,
- TILE_OPC_PACKHS_SN,
- TILE_OPC_PACKLB,
- TILE_OPC_PACKLB_SN,
- TILE_OPC_PCNT,
- TILE_OPC_PCNT_SN,
- TILE_OPC_RL,
- TILE_OPC_RL_SN,
- TILE_OPC_RLI,
- TILE_OPC_RLI_SN,
- TILE_OPC_S1A,
- TILE_OPC_S1A_SN,
- TILE_OPC_S2A,
- TILE_OPC_S2A_SN,
- TILE_OPC_S3A,
- TILE_OPC_S3A_SN,
- TILE_OPC_SADAB_U,
- TILE_OPC_SADAB_U_SN,
- TILE_OPC_SADAH,
- TILE_OPC_SADAH_SN,
- TILE_OPC_SADAH_U,
- TILE_OPC_SADAH_U_SN,
- TILE_OPC_SADB_U,
- TILE_OPC_SADB_U_SN,
- TILE_OPC_SADH,
- TILE_OPC_SADH_SN,
- TILE_OPC_SADH_U,
- TILE_OPC_SADH_U_SN,
- TILE_OPC_SB,
- TILE_OPC_SBADD,
- TILE_OPC_SEQ,
- TILE_OPC_SEQ_SN,
- TILE_OPC_SEQB,
- TILE_OPC_SEQB_SN,
- TILE_OPC_SEQH,
- TILE_OPC_SEQH_SN,
- TILE_OPC_SEQI,
- TILE_OPC_SEQI_SN,
- TILE_OPC_SEQIB,
- TILE_OPC_SEQIB_SN,
- TILE_OPC_SEQIH,
- TILE_OPC_SEQIH_SN,
- TILE_OPC_SH,
- TILE_OPC_SHADD,
- TILE_OPC_SHL,
- TILE_OPC_SHL_SN,
- TILE_OPC_SHLB,
- TILE_OPC_SHLB_SN,
- TILE_OPC_SHLH,
- TILE_OPC_SHLH_SN,
- TILE_OPC_SHLI,
- TILE_OPC_SHLI_SN,
- TILE_OPC_SHLIB,
- TILE_OPC_SHLIB_SN,
- TILE_OPC_SHLIH,
- TILE_OPC_SHLIH_SN,
- TILE_OPC_SHR,
- TILE_OPC_SHR_SN,
- TILE_OPC_SHRB,
- TILE_OPC_SHRB_SN,
- TILE_OPC_SHRH,
- TILE_OPC_SHRH_SN,
- TILE_OPC_SHRI,
- TILE_OPC_SHRI_SN,
- TILE_OPC_SHRIB,
- TILE_OPC_SHRIB_SN,
- TILE_OPC_SHRIH,
- TILE_OPC_SHRIH_SN,
- TILE_OPC_SLT,
- TILE_OPC_SLT_SN,
- TILE_OPC_SLT_U,
- TILE_OPC_SLT_U_SN,
- TILE_OPC_SLTB,
- TILE_OPC_SLTB_SN,
- TILE_OPC_SLTB_U,
- TILE_OPC_SLTB_U_SN,
- TILE_OPC_SLTE,
- TILE_OPC_SLTE_SN,
- TILE_OPC_SLTE_U,
- TILE_OPC_SLTE_U_SN,
- TILE_OPC_SLTEB,
- TILE_OPC_SLTEB_SN,
- TILE_OPC_SLTEB_U,
- TILE_OPC_SLTEB_U_SN,
- TILE_OPC_SLTEH,
- TILE_OPC_SLTEH_SN,
- TILE_OPC_SLTEH_U,
- TILE_OPC_SLTEH_U_SN,
- TILE_OPC_SLTH,
- TILE_OPC_SLTH_SN,
- TILE_OPC_SLTH_U,
- TILE_OPC_SLTH_U_SN,
- TILE_OPC_SLTI,
- TILE_OPC_SLTI_SN,
- TILE_OPC_SLTI_U,
- TILE_OPC_SLTI_U_SN,
- TILE_OPC_SLTIB,
- TILE_OPC_SLTIB_SN,
- TILE_OPC_SLTIB_U,
- TILE_OPC_SLTIB_U_SN,
- TILE_OPC_SLTIH,
- TILE_OPC_SLTIH_SN,
- TILE_OPC_SLTIH_U,
- TILE_OPC_SLTIH_U_SN,
- TILE_OPC_SNE,
- TILE_OPC_SNE_SN,
- TILE_OPC_SNEB,
- TILE_OPC_SNEB_SN,
- TILE_OPC_SNEH,
- TILE_OPC_SNEH_SN,
- TILE_OPC_SRA,
- TILE_OPC_SRA_SN,
- TILE_OPC_SRAB,
- TILE_OPC_SRAB_SN,
- TILE_OPC_SRAH,
- TILE_OPC_SRAH_SN,
- TILE_OPC_SRAI,
- TILE_OPC_SRAI_SN,
- TILE_OPC_SRAIB,
- TILE_OPC_SRAIB_SN,
- TILE_OPC_SRAIH,
- TILE_OPC_SRAIH_SN,
- TILE_OPC_SUB,
- TILE_OPC_SUB_SN,
- TILE_OPC_SUBB,
- TILE_OPC_SUBB_SN,
- TILE_OPC_SUBBS_U,
- TILE_OPC_SUBBS_U_SN,
- TILE_OPC_SUBH,
- TILE_OPC_SUBH_SN,
- TILE_OPC_SUBHS,
- TILE_OPC_SUBHS_SN,
- TILE_OPC_SUBS,
- TILE_OPC_SUBS_SN,
- TILE_OPC_SW,
- TILE_OPC_SWADD,
- TILE_OPC_SWINT0,
- TILE_OPC_SWINT1,
- TILE_OPC_SWINT2,
- TILE_OPC_SWINT3,
- TILE_OPC_TBLIDXB0,
- TILE_OPC_TBLIDXB0_SN,
- TILE_OPC_TBLIDXB1,
- TILE_OPC_TBLIDXB1_SN,
- TILE_OPC_TBLIDXB2,
- TILE_OPC_TBLIDXB2_SN,
- TILE_OPC_TBLIDXB3,
- TILE_OPC_TBLIDXB3_SN,
- TILE_OPC_TNS,
- TILE_OPC_TNS_SN,
- TILE_OPC_WH64,
- TILE_OPC_XOR,
- TILE_OPC_XOR_SN,
- TILE_OPC_XORI,
- TILE_OPC_XORI_SN,
- TILE_OPC_NONE
-} tile_mnemonic;
+ TILEGX_OPC_BPT,
+ TILEGX_OPC_INFO,
+ TILEGX_OPC_INFOL,
+ TILEGX_OPC_MOVE,
+ TILEGX_OPC_MOVEI,
+ TILEGX_OPC_MOVELI,
+ TILEGX_OPC_PREFETCH,
+ TILEGX_OPC_PREFETCH_ADD_L1,
+ TILEGX_OPC_PREFETCH_ADD_L1_FAULT,
+ TILEGX_OPC_PREFETCH_ADD_L2,
+ TILEGX_OPC_PREFETCH_ADD_L2_FAULT,
+ TILEGX_OPC_PREFETCH_ADD_L3,
+ TILEGX_OPC_PREFETCH_ADD_L3_FAULT,
+ TILEGX_OPC_PREFETCH_L1,
+ TILEGX_OPC_PREFETCH_L1_FAULT,
+ TILEGX_OPC_PREFETCH_L2,
+ TILEGX_OPC_PREFETCH_L2_FAULT,
+ TILEGX_OPC_PREFETCH_L3,
+ TILEGX_OPC_PREFETCH_L3_FAULT,
+ TILEGX_OPC_RAISE,
+ TILEGX_OPC_ADD,
+ TILEGX_OPC_ADDI,
+ TILEGX_OPC_ADDLI,
+ TILEGX_OPC_ADDX,
+ TILEGX_OPC_ADDXI,
+ TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXSC,
+ TILEGX_OPC_AND,
+ TILEGX_OPC_ANDI,
+ TILEGX_OPC_BEQZ,
+ TILEGX_OPC_BEQZT,
+ TILEGX_OPC_BFEXTS,
+ TILEGX_OPC_BFEXTU,
+ TILEGX_OPC_BFINS,
+ TILEGX_OPC_BGEZ,
+ TILEGX_OPC_BGEZT,
+ TILEGX_OPC_BGTZ,
+ TILEGX_OPC_BGTZT,
+ TILEGX_OPC_BLBC,
+ TILEGX_OPC_BLBCT,
+ TILEGX_OPC_BLBS,
+ TILEGX_OPC_BLBST,
+ TILEGX_OPC_BLEZ,
+ TILEGX_OPC_BLEZT,
+ TILEGX_OPC_BLTZ,
+ TILEGX_OPC_BLTZT,
+ TILEGX_OPC_BNEZ,
+ TILEGX_OPC_BNEZT,
+ TILEGX_OPC_CLZ,
+ TILEGX_OPC_CMOVEQZ,
+ TILEGX_OPC_CMOVNEZ,
+ TILEGX_OPC_CMPEQ,
+ TILEGX_OPC_CMPEQI,
+ TILEGX_OPC_CMPEXCH,
+ TILEGX_OPC_CMPEXCH4,
+ TILEGX_OPC_CMPLES,
+ TILEGX_OPC_CMPLEU,
+ TILEGX_OPC_CMPLTS,
+ TILEGX_OPC_CMPLTSI,
+ TILEGX_OPC_CMPLTU,
+ TILEGX_OPC_CMPLTUI,
+ TILEGX_OPC_CMPNE,
+ TILEGX_OPC_CMUL,
+ TILEGX_OPC_CMULA,
+ TILEGX_OPC_CMULAF,
+ TILEGX_OPC_CMULF,
+ TILEGX_OPC_CMULFR,
+ TILEGX_OPC_CMULH,
+ TILEGX_OPC_CMULHR,
+ TILEGX_OPC_CRC32_32,
+ TILEGX_OPC_CRC32_8,
+ TILEGX_OPC_CTZ,
+ TILEGX_OPC_DBLALIGN,
+ TILEGX_OPC_DBLALIGN2,
+ TILEGX_OPC_DBLALIGN4,
+ TILEGX_OPC_DBLALIGN6,
+ TILEGX_OPC_DRAIN,
+ TILEGX_OPC_DTLBPR,
+ TILEGX_OPC_EXCH,
+ TILEGX_OPC_EXCH4,
+ TILEGX_OPC_FDOUBLE_ADD_FLAGS,
+ TILEGX_OPC_FDOUBLE_ADDSUB,
+ TILEGX_OPC_FDOUBLE_MUL_FLAGS,
+ TILEGX_OPC_FDOUBLE_PACK1,
+ TILEGX_OPC_FDOUBLE_PACK2,
+ TILEGX_OPC_FDOUBLE_SUB_FLAGS,
+ TILEGX_OPC_FDOUBLE_UNPACK_MAX,
+ TILEGX_OPC_FDOUBLE_UNPACK_MIN,
+ TILEGX_OPC_FETCHADD,
+ TILEGX_OPC_FETCHADD4,
+ TILEGX_OPC_FETCHADDGEZ,
+ TILEGX_OPC_FETCHADDGEZ4,
+ TILEGX_OPC_FETCHAND,
+ TILEGX_OPC_FETCHAND4,
+ TILEGX_OPC_FETCHOR,
+ TILEGX_OPC_FETCHOR4,
+ TILEGX_OPC_FINV,
+ TILEGX_OPC_FLUSH,
+ TILEGX_OPC_FLUSHWB,
+ TILEGX_OPC_FNOP,
+ TILEGX_OPC_FSINGLE_ADD1,
+ TILEGX_OPC_FSINGLE_ADDSUB2,
+ TILEGX_OPC_FSINGLE_MUL1,
+ TILEGX_OPC_FSINGLE_MUL2,
+ TILEGX_OPC_FSINGLE_PACK1,
+ TILEGX_OPC_FSINGLE_PACK2,
+ TILEGX_OPC_FSINGLE_SUB1,
+ TILEGX_OPC_ICOH,
+ TILEGX_OPC_ILL,
+ TILEGX_OPC_INV,
+ TILEGX_OPC_IRET,
+ TILEGX_OPC_J,
+ TILEGX_OPC_JAL,
+ TILEGX_OPC_JALR,
+ TILEGX_OPC_JALRP,
+ TILEGX_OPC_JR,
+ TILEGX_OPC_JRP,
+ TILEGX_OPC_LD,
+ TILEGX_OPC_LD1S,
+ TILEGX_OPC_LD1S_ADD,
+ TILEGX_OPC_LD1U,
+ TILEGX_OPC_LD1U_ADD,
+ TILEGX_OPC_LD2S,
+ TILEGX_OPC_LD2S_ADD,
+ TILEGX_OPC_LD2U,
+ TILEGX_OPC_LD2U_ADD,
+ TILEGX_OPC_LD4S,
+ TILEGX_OPC_LD4S_ADD,
+ TILEGX_OPC_LD4U,
+ TILEGX_OPC_LD4U_ADD,
+ TILEGX_OPC_LD_ADD,
+ TILEGX_OPC_LDNA,
+ TILEGX_OPC_LDNA_ADD,
+ TILEGX_OPC_LDNT,
+ TILEGX_OPC_LDNT1S,
+ TILEGX_OPC_LDNT1S_ADD,
+ TILEGX_OPC_LDNT1U,
+ TILEGX_OPC_LDNT1U_ADD,
+ TILEGX_OPC_LDNT2S,
+ TILEGX_OPC_LDNT2S_ADD,
+ TILEGX_OPC_LDNT2U,
+ TILEGX_OPC_LDNT2U_ADD,
+ TILEGX_OPC_LDNT4S,
+ TILEGX_OPC_LDNT4S_ADD,
+ TILEGX_OPC_LDNT4U,
+ TILEGX_OPC_LDNT4U_ADD,
+ TILEGX_OPC_LDNT_ADD,
+ TILEGX_OPC_LNK,
+ TILEGX_OPC_MF,
+ TILEGX_OPC_MFSPR,
+ TILEGX_OPC_MM,
+ TILEGX_OPC_MNZ,
+ TILEGX_OPC_MTSPR,
+ TILEGX_OPC_MUL_HS_HS,
+ TILEGX_OPC_MUL_HS_HU,
+ TILEGX_OPC_MUL_HS_LS,
+ TILEGX_OPC_MUL_HS_LU,
+ TILEGX_OPC_MUL_HU_HU,
+ TILEGX_OPC_MUL_HU_LS,
+ TILEGX_OPC_MUL_HU_LU,
+ TILEGX_OPC_MUL_LS_LS,
+ TILEGX_OPC_MUL_LS_LU,
+ TILEGX_OPC_MUL_LU_LU,
+ TILEGX_OPC_MULA_HS_HS,
+ TILEGX_OPC_MULA_HS_HU,
+ TILEGX_OPC_MULA_HS_LS,
+ TILEGX_OPC_MULA_HS_LU,
+ TILEGX_OPC_MULA_HU_HU,
+ TILEGX_OPC_MULA_HU_LS,
+ TILEGX_OPC_MULA_HU_LU,
+ TILEGX_OPC_MULA_LS_LS,
+ TILEGX_OPC_MULA_LS_LU,
+ TILEGX_OPC_MULA_LU_LU,
+ TILEGX_OPC_MULAX,
+ TILEGX_OPC_MULX,
+ TILEGX_OPC_MZ,
+ TILEGX_OPC_NAP,
+ TILEGX_OPC_NOP,
+ TILEGX_OPC_NOR,
+ TILEGX_OPC_OR,
+ TILEGX_OPC_ORI,
+ TILEGX_OPC_PCNT,
+ TILEGX_OPC_REVBITS,
+ TILEGX_OPC_REVBYTES,
+ TILEGX_OPC_ROTL,
+ TILEGX_OPC_ROTLI,
+ TILEGX_OPC_SHL,
+ TILEGX_OPC_SHL16INSLI,
+ TILEGX_OPC_SHL1ADD,
+ TILEGX_OPC_SHL1ADDX,
+ TILEGX_OPC_SHL2ADD,
+ TILEGX_OPC_SHL2ADDX,
+ TILEGX_OPC_SHL3ADD,
+ TILEGX_OPC_SHL3ADDX,
+ TILEGX_OPC_SHLI,
+ TILEGX_OPC_SHLX,
+ TILEGX_OPC_SHLXI,
+ TILEGX_OPC_SHRS,
+ TILEGX_OPC_SHRSI,
+ TILEGX_OPC_SHRU,
+ TILEGX_OPC_SHRUI,
+ TILEGX_OPC_SHRUX,
+ TILEGX_OPC_SHRUXI,
+ TILEGX_OPC_SHUFFLEBYTES,
+ TILEGX_OPC_ST,
+ TILEGX_OPC_ST1,
+ TILEGX_OPC_ST1_ADD,
+ TILEGX_OPC_ST2,
+ TILEGX_OPC_ST2_ADD,
+ TILEGX_OPC_ST4,
+ TILEGX_OPC_ST4_ADD,
+ TILEGX_OPC_ST_ADD,
+ TILEGX_OPC_STNT,
+ TILEGX_OPC_STNT1,
+ TILEGX_OPC_STNT1_ADD,
+ TILEGX_OPC_STNT2,
+ TILEGX_OPC_STNT2_ADD,
+ TILEGX_OPC_STNT4,
+ TILEGX_OPC_STNT4_ADD,
+ TILEGX_OPC_STNT_ADD,
+ TILEGX_OPC_SUB,
+ TILEGX_OPC_SUBX,
+ TILEGX_OPC_SUBXSC,
+ TILEGX_OPC_SWINT0,
+ TILEGX_OPC_SWINT1,
+ TILEGX_OPC_SWINT2,
+ TILEGX_OPC_SWINT3,
+ TILEGX_OPC_TBLIDXB0,
+ TILEGX_OPC_TBLIDXB1,
+ TILEGX_OPC_TBLIDXB2,
+ TILEGX_OPC_TBLIDXB3,
+ TILEGX_OPC_V1ADD,
+ TILEGX_OPC_V1ADDI,
+ TILEGX_OPC_V1ADDUC,
+ TILEGX_OPC_V1ADIFFU,
+ TILEGX_OPC_V1AVGU,
+ TILEGX_OPC_V1CMPEQ,
+ TILEGX_OPC_V1CMPEQI,
+ TILEGX_OPC_V1CMPLES,
+ TILEGX_OPC_V1CMPLEU,
+ TILEGX_OPC_V1CMPLTS,
+ TILEGX_OPC_V1CMPLTSI,
+ TILEGX_OPC_V1CMPLTU,
+ TILEGX_OPC_V1CMPLTUI,
+ TILEGX_OPC_V1CMPNE,
+ TILEGX_OPC_V1DDOTPU,
+ TILEGX_OPC_V1DDOTPUA,
+ TILEGX_OPC_V1DDOTPUS,
+ TILEGX_OPC_V1DDOTPUSA,
+ TILEGX_OPC_V1DOTP,
+ TILEGX_OPC_V1DOTPA,
+ TILEGX_OPC_V1DOTPU,
+ TILEGX_OPC_V1DOTPUA,
+ TILEGX_OPC_V1DOTPUS,
+ TILEGX_OPC_V1DOTPUSA,
+ TILEGX_OPC_V1INT_H,
+ TILEGX_OPC_V1INT_L,
+ TILEGX_OPC_V1MAXU,
+ TILEGX_OPC_V1MAXUI,
+ TILEGX_OPC_V1MINU,
+ TILEGX_OPC_V1MINUI,
+ TILEGX_OPC_V1MNZ,
+ TILEGX_OPC_V1MULTU,
+ TILEGX_OPC_V1MULU,
+ TILEGX_OPC_V1MULUS,
+ TILEGX_OPC_V1MZ,
+ TILEGX_OPC_V1SADAU,
+ TILEGX_OPC_V1SADU,
+ TILEGX_OPC_V1SHL,
+ TILEGX_OPC_V1SHLI,
+ TILEGX_OPC_V1SHRS,
+ TILEGX_OPC_V1SHRSI,
+ TILEGX_OPC_V1SHRU,
+ TILEGX_OPC_V1SHRUI,
+ TILEGX_OPC_V1SUB,
+ TILEGX_OPC_V1SUBUC,
+ TILEGX_OPC_V2ADD,
+ TILEGX_OPC_V2ADDI,
+ TILEGX_OPC_V2ADDSC,
+ TILEGX_OPC_V2ADIFFS,
+ TILEGX_OPC_V2AVGS,
+ TILEGX_OPC_V2CMPEQ,
+ TILEGX_OPC_V2CMPEQI,
+ TILEGX_OPC_V2CMPLES,
+ TILEGX_OPC_V2CMPLEU,
+ TILEGX_OPC_V2CMPLTS,
+ TILEGX_OPC_V2CMPLTSI,
+ TILEGX_OPC_V2CMPLTU,
+ TILEGX_OPC_V2CMPLTUI,
+ TILEGX_OPC_V2CMPNE,
+ TILEGX_OPC_V2DOTP,
+ TILEGX_OPC_V2DOTPA,
+ TILEGX_OPC_V2INT_H,
+ TILEGX_OPC_V2INT_L,
+ TILEGX_OPC_V2MAXS,
+ TILEGX_OPC_V2MAXSI,
+ TILEGX_OPC_V2MINS,
+ TILEGX_OPC_V2MINSI,
+ TILEGX_OPC_V2MNZ,
+ TILEGX_OPC_V2MULFSC,
+ TILEGX_OPC_V2MULS,
+ TILEGX_OPC_V2MULTS,
+ TILEGX_OPC_V2MZ,
+ TILEGX_OPC_V2PACKH,
+ TILEGX_OPC_V2PACKL,
+ TILEGX_OPC_V2PACKUC,
+ TILEGX_OPC_V2SADAS,
+ TILEGX_OPC_V2SADAU,
+ TILEGX_OPC_V2SADS,
+ TILEGX_OPC_V2SADU,
+ TILEGX_OPC_V2SHL,
+ TILEGX_OPC_V2SHLI,
+ TILEGX_OPC_V2SHLSC,
+ TILEGX_OPC_V2SHRS,
+ TILEGX_OPC_V2SHRSI,
+ TILEGX_OPC_V2SHRU,
+ TILEGX_OPC_V2SHRUI,
+ TILEGX_OPC_V2SUB,
+ TILEGX_OPC_V2SUBSC,
+ TILEGX_OPC_V4ADD,
+ TILEGX_OPC_V4ADDSC,
+ TILEGX_OPC_V4INT_H,
+ TILEGX_OPC_V4INT_L,
+ TILEGX_OPC_V4PACKSC,
+ TILEGX_OPC_V4SHL,
+ TILEGX_OPC_V4SHLSC,
+ TILEGX_OPC_V4SHRS,
+ TILEGX_OPC_V4SHRU,
+ TILEGX_OPC_V4SUB,
+ TILEGX_OPC_V4SUBSC,
+ TILEGX_OPC_WH64,
+ TILEGX_OPC_XOR,
+ TILEGX_OPC_XORI,
+ TILEGX_OPC_NONE
+} tilegx_mnemonic;
/* 64-bit pattern for a { bpt ; nop } bundle. */
-#define TILE_BPT_BUNDLE 0x400b3cae70166000ULL
+#define TILEGX_BPT_BUNDLE 0x286a44ae51485000ULL
-#define TILE_ELF_MACHINE_CODE EM_TILEPRO
+#define TILE_ELF_MACHINE_CODE EM_TILE64
-#define TILE_ELF_NAME "elf32-tilepro"
+#define TILE_ELF_NAME "elf32-tile64"
static __inline unsigned int
-get_BrOff_SN(tile_bundle_bits num)
+get_BFEnd_X0(tilegx_bundle_bits num)
{
const unsigned int n = (unsigned int)num;
- return (((n >> 0)) & 0x3ff);
+ return (((n >> 12)) & 0x3f);
}
static __inline unsigned int
-get_BrOff_X1(tile_bundle_bits n)
+get_BFOpcodeExtension_X0(tilegx_bundle_bits num)
{
- return (((unsigned int)(n >> 43)) & 0x00007fff) |
- (((unsigned int)(n >> 20)) & 0x00018000);
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 24)) & 0xf);
}
static __inline unsigned int
-get_BrType_X1(tile_bundle_bits n)
+get_BFStart_X0(tilegx_bundle_bits num)
{
- return (((unsigned int)(n >> 31)) & 0xf);
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 18)) & 0x3f);
}
static __inline unsigned int
-get_Dest_Imm8_X1(tile_bundle_bits n)
+get_BrOff_X1(tilegx_bundle_bits n)
{
return (((unsigned int)(n >> 31)) & 0x0000003f) |
- (((unsigned int)(n >> 43)) & 0x000000c0);
+ (((unsigned int)(n >> 37)) & 0x0001ffc0);
}
static __inline unsigned int
-get_Dest_SN(tile_bundle_bits num)
+get_BrType_X1(tilegx_bundle_bits n)
{
- const unsigned int n = (unsigned int)num;
- return (((n >> 2)) & 0x3);
+ return (((unsigned int)(n >> 54)) & 0x1f);
}
static __inline unsigned int
-get_Dest_X0(tile_bundle_bits num)
+get_Dest_Imm8_X1(tilegx_bundle_bits n)
+{
+ return (((unsigned int)(n >> 31)) & 0x0000003f) |
+ (((unsigned int)(n >> 43)) & 0x000000c0);
+}
+
+static __inline unsigned int
+get_Dest_X0(tilegx_bundle_bits num)
{
const unsigned int n = (unsigned int)num;
return (((n >> 0)) & 0x3f);
}
static __inline unsigned int
-get_Dest_X1(tile_bundle_bits n)
+get_Dest_X1(tilegx_bundle_bits n)
{
return (((unsigned int)(n >> 31)) & 0x3f);
}
static __inline unsigned int
-get_Dest_Y0(tile_bundle_bits num)
+get_Dest_Y0(tilegx_bundle_bits num)
{
const unsigned int n = (unsigned int)num;
return (((n >> 0)) & 0x3f);
}
static __inline unsigned int
-get_Dest_Y1(tile_bundle_bits n)
+get_Dest_Y1(tilegx_bundle_bits n)
{
return (((unsigned int)(n >> 31)) & 0x3f);
}
static __inline unsigned int
-get_Imm16_X0(tile_bundle_bits num)
+get_Imm16_X0(tilegx_bundle_bits num)
{
const unsigned int n = (unsigned int)num;
return (((n >> 12)) & 0xffff);
}
static __inline unsigned int
-get_Imm16_X1(tile_bundle_bits n)
+get_Imm16_X1(tilegx_bundle_bits n)
{
return (((unsigned int)(n >> 43)) & 0xffff);
}
static __inline unsigned int
-get_Imm8_SN(tile_bundle_bits num)
-{
- const unsigned int n = (unsigned int)num;
- return (((n >> 0)) & 0xff);
-}
-
-static __inline unsigned int
-get_Imm8_X0(tile_bundle_bits num)
+get_Imm8OpcodeExtension_X0(tilegx_bundle_bits num)
{
const unsigned int n = (unsigned int)num;
- return (((n >> 12)) & 0xff);
+ return (((n >> 20)) & 0xff);
}
static __inline unsigned int
-get_Imm8_X1(tile_bundle_bits n)
+get_Imm8OpcodeExtension_X1(tilegx_bundle_bits n)
{
- return (((unsigned int)(n >> 43)) & 0xff);
+ return (((unsigned int)(n >> 51)) & 0xff);
}
static __inline unsigned int
-get_Imm8_Y0(tile_bundle_bits num)
+get_Imm8_X0(tilegx_bundle_bits num)
{
const unsigned int n = (unsigned int)num;
return (((n >> 12)) & 0xff);
}
static __inline unsigned int
-get_Imm8_Y1(tile_bundle_bits n)
+get_Imm8_X1(tilegx_bundle_bits n)
{
return (((unsigned int)(n >> 43)) & 0xff);
}
static __inline unsigned int
-get_ImmOpcodeExtension_X0(tile_bundle_bits num)
-{
- const unsigned int n = (unsigned int)num;
- return (((n >> 20)) & 0x7f);
-}
-
-static __inline unsigned int
-get_ImmOpcodeExtension_X1(tile_bundle_bits n)
-{
- return (((unsigned int)(n >> 51)) & 0x7f);
-}
-
-static __inline unsigned int
-get_ImmRROpcodeExtension_SN(tile_bundle_bits num)
+get_Imm8_Y0(tilegx_bundle_bits num)
{
const unsigned int n = (unsigned int)num;
- return (((n >> 8)) & 0x3);
-}
-
-static __inline unsigned int
-get_JOffLong_X1(tile_bundle_bits n)
-{
- return (((unsigned int)(n >> 43)) & 0x00007fff) |
- (((unsigned int)(n >> 20)) & 0x00018000) |
- (((unsigned int)(n >> 14)) & 0x001e0000) |
- (((unsigned int)(n >> 16)) & 0x07e00000) |
- (((unsigned int)(n >> 31)) & 0x18000000);
-}
-
-static __inline unsigned int
-get_JOff_X1(tile_bundle_bits n)
-{
- return (((unsigned int)(n >> 43)) & 0x00007fff) |
- (((unsigned int)(n >> 20)) & 0x00018000) |
- (((unsigned int)(n >> 14)) & 0x001e0000) |
- (((unsigned int)(n >> 16)) & 0x07e00000) |
- (((unsigned int)(n >> 31)) & 0x08000000);
-}
-
-static __inline unsigned int
-get_MF_Imm15_X1(tile_bundle_bits n)
-{
- return (((unsigned int)(n >> 37)) & 0x00003fff) |
- (((unsigned int)(n >> 44)) & 0x00004000);
+ return (((n >> 12)) & 0xff);
}
static __inline unsigned int
-get_MMEnd_X0(tile_bundle_bits num)
+get_Imm8_Y1(tilegx_bundle_bits n)
{
- const unsigned int n = (unsigned int)num;
- return (((n >> 18)) & 0x1f);
+ return (((unsigned int)(n >> 43)) & 0xff);
}
static __inline unsigned int
-get_MMEnd_X1(tile_bundle_bits n)
+get_JumpOff_X1(tilegx_bundle_bits n)
{
- return (((unsigned int)(n >> 49)) & 0x1f);
+ return (((unsigned int)(n >> 31)) & 0x7ffffff);
}
static __inline unsigned int
-get_MMStart_X0(tile_bundle_bits num)
+get_JumpOpcodeExtension_X1(tilegx_bundle_bits n)
{
- const unsigned int n = (unsigned int)num;
- return (((n >> 23)) & 0x1f);
+ return (((unsigned int)(n >> 58)) & 0x1);
}
static __inline unsigned int
-get_MMStart_X1(tile_bundle_bits n)
+get_MF_Imm14_X1(tilegx_bundle_bits n)
{
- return (((unsigned int)(n >> 54)) & 0x1f);
+ return (((unsigned int)(n >> 37)) & 0x3fff);
}
static __inline unsigned int
-get_MT_Imm15_X1(tile_bundle_bits n)
+get_MT_Imm14_X1(tilegx_bundle_bits n)
{
return (((unsigned int)(n >> 31)) & 0x0000003f) |
- (((unsigned int)(n >> 37)) & 0x00003fc0) |
- (((unsigned int)(n >> 44)) & 0x00004000);
+ (((unsigned int)(n >> 37)) & 0x00003fc0);
}
static __inline unsigned int
-get_Mode(tile_bundle_bits n)
+get_Mode(tilegx_bundle_bits n)
{
- return (((unsigned int)(n >> 63)) & 0x1);
+ return (((unsigned int)(n >> 62)) & 0x3);
}
static __inline unsigned int
-get_NoRegOpcodeExtension_SN(tile_bundle_bits num)
-{
- const unsigned int n = (unsigned int)num;
- return (((n >> 0)) & 0xf);
-}
-
-static __inline unsigned int
-get_Opcode_SN(tile_bundle_bits num)
-{
- const unsigned int n = (unsigned int)num;
- return (((n >> 10)) & 0x3f);
-}
-
-static __inline unsigned int
-get_Opcode_X0(tile_bundle_bits num)
+get_Opcode_X0(tilegx_bundle_bits num)
{
const unsigned int n = (unsigned int)num;
return (((n >> 28)) & 0x7);
}
static __inline unsigned int
-get_Opcode_X1(tile_bundle_bits n)
+get_Opcode_X1(tilegx_bundle_bits n)
{
- return (((unsigned int)(n >> 59)) & 0xf);
+ return (((unsigned int)(n >> 59)) & 0x7);
}
static __inline unsigned int
-get_Opcode_Y0(tile_bundle_bits num)
+get_Opcode_Y0(tilegx_bundle_bits num)
{
const unsigned int n = (unsigned int)num;
return (((n >> 27)) & 0xf);
}
static __inline unsigned int
-get_Opcode_Y1(tile_bundle_bits n)
+get_Opcode_Y1(tilegx_bundle_bits n)
{
- return (((unsigned int)(n >> 59)) & 0xf);
+ return (((unsigned int)(n >> 58)) & 0xf);
}
static __inline unsigned int
-get_Opcode_Y2(tile_bundle_bits n)
+get_Opcode_Y2(tilegx_bundle_bits n)
{
- return (((unsigned int)(n >> 56)) & 0x7);
-}
-
-static __inline unsigned int
-get_RROpcodeExtension_SN(tile_bundle_bits num)
-{
- const unsigned int n = (unsigned int)num;
- return (((n >> 4)) & 0xf);
+ return (((n >> 26)) & 0x00000001) |
+ (((unsigned int)(n >> 56)) & 0x00000002);
}
static __inline unsigned int
-get_RRROpcodeExtension_X0(tile_bundle_bits num)
+get_RRROpcodeExtension_X0(tilegx_bundle_bits num)
{
const unsigned int n = (unsigned int)num;
- return (((n >> 18)) & 0x1ff);
+ return (((n >> 18)) & 0x3ff);
}
static __inline unsigned int
-get_RRROpcodeExtension_X1(tile_bundle_bits n)
+get_RRROpcodeExtension_X1(tilegx_bundle_bits n)
{
- return (((unsigned int)(n >> 49)) & 0x1ff);
+ return (((unsigned int)(n >> 49)) & 0x3ff);
}
static __inline unsigned int
-get_RRROpcodeExtension_Y0(tile_bundle_bits num)
+get_RRROpcodeExtension_Y0(tilegx_bundle_bits num)
{
const unsigned int n = (unsigned int)num;
return (((n >> 18)) & 0x3);
}
static __inline unsigned int
-get_RRROpcodeExtension_Y1(tile_bundle_bits n)
+get_RRROpcodeExtension_Y1(tilegx_bundle_bits n)
{
return (((unsigned int)(n >> 49)) & 0x3);
}
static __inline unsigned int
-get_RouteOpcodeExtension_SN(tile_bundle_bits num)
-{
- const unsigned int n = (unsigned int)num;
- return (((n >> 0)) & 0x3ff);
-}
-
-static __inline unsigned int
-get_S_X0(tile_bundle_bits num)
+get_ShAmt_X0(tilegx_bundle_bits num)
{
const unsigned int n = (unsigned int)num;
- return (((n >> 27)) & 0x1);
+ return (((n >> 12)) & 0x3f);
}
static __inline unsigned int
-get_S_X1(tile_bundle_bits n)
+get_ShAmt_X1(tilegx_bundle_bits n)
{
- return (((unsigned int)(n >> 58)) & 0x1);
+ return (((unsigned int)(n >> 43)) & 0x3f);
}
static __inline unsigned int
-get_ShAmt_X0(tile_bundle_bits num)
+get_ShAmt_Y0(tilegx_bundle_bits num)
{
const unsigned int n = (unsigned int)num;
- return (((n >> 12)) & 0x1f);
+ return (((n >> 12)) & 0x3f);
}
static __inline unsigned int
-get_ShAmt_X1(tile_bundle_bits n)
+get_ShAmt_Y1(tilegx_bundle_bits n)
{
- return (((unsigned int)(n >> 43)) & 0x1f);
+ return (((unsigned int)(n >> 43)) & 0x3f);
}
static __inline unsigned int
-get_ShAmt_Y0(tile_bundle_bits num)
+get_ShiftOpcodeExtension_X0(tilegx_bundle_bits num)
{
const unsigned int n = (unsigned int)num;
- return (((n >> 12)) & 0x1f);
+ return (((n >> 18)) & 0x3ff);
}
static __inline unsigned int
-get_ShAmt_Y1(tile_bundle_bits n)
+get_ShiftOpcodeExtension_X1(tilegx_bundle_bits n)
{
- return (((unsigned int)(n >> 43)) & 0x1f);
+ return (((unsigned int)(n >> 49)) & 0x3ff);
}
static __inline unsigned int
-get_SrcA_X0(tile_bundle_bits num)
+get_ShiftOpcodeExtension_Y0(tilegx_bundle_bits num)
{
const unsigned int n = (unsigned int)num;
- return (((n >> 6)) & 0x3f);
+ return (((n >> 18)) & 0x3);
}
static __inline unsigned int
-get_SrcA_X1(tile_bundle_bits n)
+get_ShiftOpcodeExtension_Y1(tilegx_bundle_bits n)
{
- return (((unsigned int)(n >> 37)) & 0x3f);
+ return (((unsigned int)(n >> 49)) & 0x3);
}
static __inline unsigned int
-get_SrcA_Y0(tile_bundle_bits num)
+get_SrcA_X0(tilegx_bundle_bits num)
{
const unsigned int n = (unsigned int)num;
return (((n >> 6)) & 0x3f);
}
static __inline unsigned int
-get_SrcA_Y1(tile_bundle_bits n)
+get_SrcA_X1(tilegx_bundle_bits n)
{
return (((unsigned int)(n >> 37)) & 0x3f);
}
static __inline unsigned int
-get_SrcA_Y2(tile_bundle_bits n)
+get_SrcA_Y0(tilegx_bundle_bits num)
{
- return (((n >> 26)) & 0x00000001) |
- (((unsigned int)(n >> 50)) & 0x0000003e);
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 6)) & 0x3f);
}
static __inline unsigned int
-get_SrcBDest_Y2(tile_bundle_bits num)
+get_SrcA_Y1(tilegx_bundle_bits n)
{
- const unsigned int n = (unsigned int)num;
- return (((n >> 20)) & 0x3f);
+ return (((unsigned int)(n >> 37)) & 0x3f);
}
static __inline unsigned int
-get_SrcB_X0(tile_bundle_bits num)
+get_SrcA_Y2(tilegx_bundle_bits num)
{
const unsigned int n = (unsigned int)num;
- return (((n >> 12)) & 0x3f);
+ return (((n >> 20)) & 0x3f);
}
static __inline unsigned int
-get_SrcB_X1(tile_bundle_bits n)
+get_SrcBDest_Y2(tilegx_bundle_bits n)
{
- return (((unsigned int)(n >> 43)) & 0x3f);
+ return (((unsigned int)(n >> 51)) & 0x3f);
}
static __inline unsigned int
-get_SrcB_Y0(tile_bundle_bits num)
+get_SrcB_X0(tilegx_bundle_bits num)
{
const unsigned int n = (unsigned int)num;
return (((n >> 12)) & 0x3f);
}
static __inline unsigned int
-get_SrcB_Y1(tile_bundle_bits n)
+get_SrcB_X1(tilegx_bundle_bits n)
{
return (((unsigned int)(n >> 43)) & 0x3f);
}
static __inline unsigned int
-get_Src_SN(tile_bundle_bits num)
+get_SrcB_Y0(tilegx_bundle_bits num)
{
const unsigned int n = (unsigned int)num;
- return (((n >> 0)) & 0x3);
-}
-
-static __inline unsigned int
-get_UnOpcodeExtension_X0(tile_bundle_bits num)
-{
- const unsigned int n = (unsigned int)num;
- return (((n >> 12)) & 0x1f);
-}
-
-static __inline unsigned int
-get_UnOpcodeExtension_X1(tile_bundle_bits n)
-{
- return (((unsigned int)(n >> 43)) & 0x1f);
-}
-
-static __inline unsigned int
-get_UnOpcodeExtension_Y0(tile_bundle_bits num)
-{
- const unsigned int n = (unsigned int)num;
- return (((n >> 12)) & 0x1f);
+ return (((n >> 12)) & 0x3f);
}
static __inline unsigned int
-get_UnOpcodeExtension_Y1(tile_bundle_bits n)
+get_SrcB_Y1(tilegx_bundle_bits n)
{
- return (((unsigned int)(n >> 43)) & 0x1f);
+ return (((unsigned int)(n >> 43)) & 0x3f);
}
static __inline unsigned int
-get_UnShOpcodeExtension_X0(tile_bundle_bits num)
+get_UnaryOpcodeExtension_X0(tilegx_bundle_bits num)
{
const unsigned int n = (unsigned int)num;
- return (((n >> 17)) & 0x3ff);
+ return (((n >> 12)) & 0x3f);
}
static __inline unsigned int
-get_UnShOpcodeExtension_X1(tile_bundle_bits n)
+get_UnaryOpcodeExtension_X1(tilegx_bundle_bits n)
{
- return (((unsigned int)(n >> 48)) & 0x3ff);
+ return (((unsigned int)(n >> 43)) & 0x3f);
}
static __inline unsigned int
-get_UnShOpcodeExtension_Y0(tile_bundle_bits num)
+get_UnaryOpcodeExtension_Y0(tilegx_bundle_bits num)
{
const unsigned int n = (unsigned int)num;
- return (((n >> 17)) & 0x7);
+ return (((n >> 12)) & 0x3f);
}
static __inline unsigned int
-get_UnShOpcodeExtension_Y1(tile_bundle_bits n)
+get_UnaryOpcodeExtension_Y1(tilegx_bundle_bits n)
{
- return (((unsigned int)(n >> 48)) & 0x7);
+ return (((unsigned int)(n >> 43)) & 0x3f);
}
@@ -874,546 +722,441 @@ sign_extend(int n, int num_bits)
-static __inline tile_bundle_bits
-create_BrOff_SN(int num)
+static __inline tilegx_bundle_bits
+create_BFEnd_X0(int num)
{
const unsigned int n = (unsigned int)num;
- return ((n & 0x3ff) << 0);
+ return ((n & 0x3f) << 12);
}
-static __inline tile_bundle_bits
-create_BrOff_X1(int num)
+static __inline tilegx_bundle_bits
+create_BFOpcodeExtension_X0(int num)
{
const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x00007fff)) << 43) |
- (((tile_bundle_bits)(n & 0x00018000)) << 20);
+ return ((n & 0xf) << 24);
}
-static __inline tile_bundle_bits
-create_BrType_X1(int num)
+static __inline tilegx_bundle_bits
+create_BFStart_X0(int num)
{
const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0xf)) << 31);
+ return ((n & 0x3f) << 18);
}
-static __inline tile_bundle_bits
-create_Dest_Imm8_X1(int num)
+static __inline tilegx_bundle_bits
+create_BrOff_X1(int num)
{
const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x0000003f)) << 31) |
- (((tile_bundle_bits)(n & 0x000000c0)) << 43);
+ return (((tilegx_bundle_bits)(n & 0x0000003f)) << 31) |
+ (((tilegx_bundle_bits)(n & 0x0001ffc0)) << 37);
}
-static __inline tile_bundle_bits
-create_Dest_SN(int num)
+static __inline tilegx_bundle_bits
+create_BrType_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tilegx_bundle_bits)(n & 0x1f)) << 54);
+}
+
+static __inline tilegx_bundle_bits
+create_Dest_Imm8_X1(int num)
{
const unsigned int n = (unsigned int)num;
- return ((n & 0x3) << 2);
+ return (((tilegx_bundle_bits)(n & 0x0000003f)) << 31) |
+ (((tilegx_bundle_bits)(n & 0x000000c0)) << 43);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_Dest_X0(int num)
{
const unsigned int n = (unsigned int)num;
return ((n & 0x3f) << 0);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_Dest_X1(int num)
{
const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x3f)) << 31);
+ return (((tilegx_bundle_bits)(n & 0x3f)) << 31);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_Dest_Y0(int num)
{
const unsigned int n = (unsigned int)num;
return ((n & 0x3f) << 0);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_Dest_Y1(int num)
{
const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x3f)) << 31);
+ return (((tilegx_bundle_bits)(n & 0x3f)) << 31);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_Imm16_X0(int num)
{
const unsigned int n = (unsigned int)num;
return ((n & 0xffff) << 12);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_Imm16_X1(int num)
{
const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0xffff)) << 43);
+ return (((tilegx_bundle_bits)(n & 0xffff)) << 43);
}
-static __inline tile_bundle_bits
-create_Imm8_SN(int num)
+static __inline tilegx_bundle_bits
+create_Imm8OpcodeExtension_X0(int num)
{
const unsigned int n = (unsigned int)num;
- return ((n & 0xff) << 0);
+ return ((n & 0xff) << 20);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
+create_Imm8OpcodeExtension_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tilegx_bundle_bits)(n & 0xff)) << 51);
+}
+
+static __inline tilegx_bundle_bits
create_Imm8_X0(int num)
{
const unsigned int n = (unsigned int)num;
return ((n & 0xff) << 12);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_Imm8_X1(int num)
{
const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0xff)) << 43);
+ return (((tilegx_bundle_bits)(n & 0xff)) << 43);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_Imm8_Y0(int num)
{
const unsigned int n = (unsigned int)num;
return ((n & 0xff) << 12);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_Imm8_Y1(int num)
{
const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0xff)) << 43);
-}
-
-static __inline tile_bundle_bits
-create_ImmOpcodeExtension_X0(int num)
-{
- const unsigned int n = (unsigned int)num;
- return ((n & 0x7f) << 20);
-}
-
-static __inline tile_bundle_bits
-create_ImmOpcodeExtension_X1(int num)
-{
- const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x7f)) << 51);
-}
-
-static __inline tile_bundle_bits
-create_ImmRROpcodeExtension_SN(int num)
-{
- const unsigned int n = (unsigned int)num;
- return ((n & 0x3) << 8);
-}
-
-static __inline tile_bundle_bits
-create_JOffLong_X1(int num)
-{
- const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x00007fff)) << 43) |
- (((tile_bundle_bits)(n & 0x00018000)) << 20) |
- (((tile_bundle_bits)(n & 0x001e0000)) << 14) |
- (((tile_bundle_bits)(n & 0x07e00000)) << 16) |
- (((tile_bundle_bits)(n & 0x18000000)) << 31);
-}
-
-static __inline tile_bundle_bits
-create_JOff_X1(int num)
-{
- const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x00007fff)) << 43) |
- (((tile_bundle_bits)(n & 0x00018000)) << 20) |
- (((tile_bundle_bits)(n & 0x001e0000)) << 14) |
- (((tile_bundle_bits)(n & 0x07e00000)) << 16) |
- (((tile_bundle_bits)(n & 0x08000000)) << 31);
-}
-
-static __inline tile_bundle_bits
-create_MF_Imm15_X1(int num)
-{
- const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x00003fff)) << 37) |
- (((tile_bundle_bits)(n & 0x00004000)) << 44);
+ return (((tilegx_bundle_bits)(n & 0xff)) << 43);
}
-static __inline tile_bundle_bits
-create_MMEnd_X0(int num)
+static __inline tilegx_bundle_bits
+create_JumpOff_X1(int num)
{
const unsigned int n = (unsigned int)num;
- return ((n & 0x1f) << 18);
+ return (((tilegx_bundle_bits)(n & 0x7ffffff)) << 31);
}
-static __inline tile_bundle_bits
-create_MMEnd_X1(int num)
+static __inline tilegx_bundle_bits
+create_JumpOpcodeExtension_X1(int num)
{
const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x1f)) << 49);
+ return (((tilegx_bundle_bits)(n & 0x1)) << 58);
}
-static __inline tile_bundle_bits
-create_MMStart_X0(int num)
+static __inline tilegx_bundle_bits
+create_MF_Imm14_X1(int num)
{
const unsigned int n = (unsigned int)num;
- return ((n & 0x1f) << 23);
+ return (((tilegx_bundle_bits)(n & 0x3fff)) << 37);
}
-static __inline tile_bundle_bits
-create_MMStart_X1(int num)
+static __inline tilegx_bundle_bits
+create_MT_Imm14_X1(int num)
{
const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x1f)) << 54);
+ return (((tilegx_bundle_bits)(n & 0x0000003f)) << 31) |
+ (((tilegx_bundle_bits)(n & 0x00003fc0)) << 37);
}
-static __inline tile_bundle_bits
-create_MT_Imm15_X1(int num)
-{
- const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x0000003f)) << 31) |
- (((tile_bundle_bits)(n & 0x00003fc0)) << 37) |
- (((tile_bundle_bits)(n & 0x00004000)) << 44);
-}
-
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_Mode(int num)
{
const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x1)) << 63);
+ return (((tilegx_bundle_bits)(n & 0x3)) << 62);
}
-static __inline tile_bundle_bits
-create_NoRegOpcodeExtension_SN(int num)
-{
- const unsigned int n = (unsigned int)num;
- return ((n & 0xf) << 0);
-}
-
-static __inline tile_bundle_bits
-create_Opcode_SN(int num)
-{
- const unsigned int n = (unsigned int)num;
- return ((n & 0x3f) << 10);
-}
-
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_Opcode_X0(int num)
{
const unsigned int n = (unsigned int)num;
return ((n & 0x7) << 28);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_Opcode_X1(int num)
{
const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0xf)) << 59);
+ return (((tilegx_bundle_bits)(n & 0x7)) << 59);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_Opcode_Y0(int num)
{
const unsigned int n = (unsigned int)num;
return ((n & 0xf) << 27);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_Opcode_Y1(int num)
{
const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0xf)) << 59);
+ return (((tilegx_bundle_bits)(n & 0xf)) << 58);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_Opcode_Y2(int num)
{
const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x7)) << 56);
-}
-
-static __inline tile_bundle_bits
-create_RROpcodeExtension_SN(int num)
-{
- const unsigned int n = (unsigned int)num;
- return ((n & 0xf) << 4);
+ return ((n & 0x00000001) << 26) |
+ (((tilegx_bundle_bits)(n & 0x00000002)) << 56);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_RRROpcodeExtension_X0(int num)
{
const unsigned int n = (unsigned int)num;
- return ((n & 0x1ff) << 18);
+ return ((n & 0x3ff) << 18);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_RRROpcodeExtension_X1(int num)
{
const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x1ff)) << 49);
+ return (((tilegx_bundle_bits)(n & 0x3ff)) << 49);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_RRROpcodeExtension_Y0(int num)
{
const unsigned int n = (unsigned int)num;
return ((n & 0x3) << 18);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_RRROpcodeExtension_Y1(int num)
{
const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x3)) << 49);
+ return (((tilegx_bundle_bits)(n & 0x3)) << 49);
}
-static __inline tile_bundle_bits
-create_RouteOpcodeExtension_SN(int num)
+static __inline tilegx_bundle_bits
+create_ShAmt_X0(int num)
{
const unsigned int n = (unsigned int)num;
- return ((n & 0x3ff) << 0);
+ return ((n & 0x3f) << 12);
}
-static __inline tile_bundle_bits
-create_S_X0(int num)
+static __inline tilegx_bundle_bits
+create_ShAmt_X1(int num)
{
const unsigned int n = (unsigned int)num;
- return ((n & 0x1) << 27);
+ return (((tilegx_bundle_bits)(n & 0x3f)) << 43);
}
-static __inline tile_bundle_bits
-create_S_X1(int num)
+static __inline tilegx_bundle_bits
+create_ShAmt_Y0(int num)
{
const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x1)) << 58);
+ return ((n & 0x3f) << 12);
}
-static __inline tile_bundle_bits
-create_ShAmt_X0(int num)
+static __inline tilegx_bundle_bits
+create_ShAmt_Y1(int num)
{
const unsigned int n = (unsigned int)num;
- return ((n & 0x1f) << 12);
+ return (((tilegx_bundle_bits)(n & 0x3f)) << 43);
}
-static __inline tile_bundle_bits
-create_ShAmt_X1(int num)
+static __inline tilegx_bundle_bits
+create_ShiftOpcodeExtension_X0(int num)
{
const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x1f)) << 43);
+ return ((n & 0x3ff) << 18);
}
-static __inline tile_bundle_bits
-create_ShAmt_Y0(int num)
+static __inline tilegx_bundle_bits
+create_ShiftOpcodeExtension_X1(int num)
{
const unsigned int n = (unsigned int)num;
- return ((n & 0x1f) << 12);
+ return (((tilegx_bundle_bits)(n & 0x3ff)) << 49);
}
-static __inline tile_bundle_bits
-create_ShAmt_Y1(int num)
+static __inline tilegx_bundle_bits
+create_ShiftOpcodeExtension_Y0(int num)
{
const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x1f)) << 43);
+ return ((n & 0x3) << 18);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
+create_ShiftOpcodeExtension_Y1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tilegx_bundle_bits)(n & 0x3)) << 49);
+}
+
+static __inline tilegx_bundle_bits
create_SrcA_X0(int num)
{
const unsigned int n = (unsigned int)num;
return ((n & 0x3f) << 6);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_SrcA_X1(int num)
{
const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x3f)) << 37);
+ return (((tilegx_bundle_bits)(n & 0x3f)) << 37);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_SrcA_Y0(int num)
{
const unsigned int n = (unsigned int)num;
return ((n & 0x3f) << 6);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_SrcA_Y1(int num)
{
const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x3f)) << 37);
+ return (((tilegx_bundle_bits)(n & 0x3f)) << 37);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_SrcA_Y2(int num)
{
const unsigned int n = (unsigned int)num;
- return ((n & 0x00000001) << 26) |
- (((tile_bundle_bits)(n & 0x0000003e)) << 50);
+ return ((n & 0x3f) << 20);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_SrcBDest_Y2(int num)
{
const unsigned int n = (unsigned int)num;
- return ((n & 0x3f) << 20);
+ return (((tilegx_bundle_bits)(n & 0x3f)) << 51);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_SrcB_X0(int num)
{
const unsigned int n = (unsigned int)num;
return ((n & 0x3f) << 12);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_SrcB_X1(int num)
{
const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x3f)) << 43);
+ return (((tilegx_bundle_bits)(n & 0x3f)) << 43);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_SrcB_Y0(int num)
{
const unsigned int n = (unsigned int)num;
return ((n & 0x3f) << 12);
}
-static __inline tile_bundle_bits
+static __inline tilegx_bundle_bits
create_SrcB_Y1(int num)
{
const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x3f)) << 43);
+ return (((tilegx_bundle_bits)(n & 0x3f)) << 43);
}
-static __inline tile_bundle_bits
-create_Src_SN(int num)
+static __inline tilegx_bundle_bits
+create_UnaryOpcodeExtension_X0(int num)
{
const unsigned int n = (unsigned int)num;
- return ((n & 0x3) << 0);
-}
-
-static __inline tile_bundle_bits
-create_UnOpcodeExtension_X0(int num)
-{
- const unsigned int n = (unsigned int)num;
- return ((n & 0x1f) << 12);
-}
-
-static __inline tile_bundle_bits
-create_UnOpcodeExtension_X1(int num)
-{
- const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x1f)) << 43);
-}
-
-static __inline tile_bundle_bits
-create_UnOpcodeExtension_Y0(int num)
-{
- const unsigned int n = (unsigned int)num;
- return ((n & 0x1f) << 12);
-}
-
-static __inline tile_bundle_bits
-create_UnOpcodeExtension_Y1(int num)
-{
- const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x1f)) << 43);
-}
-
-static __inline tile_bundle_bits
-create_UnShOpcodeExtension_X0(int num)
-{
- const unsigned int n = (unsigned int)num;
- return ((n & 0x3ff) << 17);
+ return ((n & 0x3f) << 12);
}
-static __inline tile_bundle_bits
-create_UnShOpcodeExtension_X1(int num)
+static __inline tilegx_bundle_bits
+create_UnaryOpcodeExtension_X1(int num)
{
const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x3ff)) << 48);
+ return (((tilegx_bundle_bits)(n & 0x3f)) << 43);
}
-static __inline tile_bundle_bits
-create_UnShOpcodeExtension_Y0(int num)
+static __inline tilegx_bundle_bits
+create_UnaryOpcodeExtension_Y0(int num)
{
const unsigned int n = (unsigned int)num;
- return ((n & 0x7) << 17);
+ return ((n & 0x3f) << 12);
}
-static __inline tile_bundle_bits
-create_UnShOpcodeExtension_Y1(int num)
+static __inline tilegx_bundle_bits
+create_UnaryOpcodeExtension_Y1(int num)
{
const unsigned int n = (unsigned int)num;
- return (((tile_bundle_bits)(n & 0x7)) << 48);
+ return (((tilegx_bundle_bits)(n & 0x3f)) << 43);
}
-
typedef enum
{
- TILE_PIPELINE_X0,
- TILE_PIPELINE_X1,
- TILE_PIPELINE_Y0,
- TILE_PIPELINE_Y1,
- TILE_PIPELINE_Y2,
-} tile_pipeline;
+ TILEGX_PIPELINE_X0,
+ TILEGX_PIPELINE_X1,
+ TILEGX_PIPELINE_Y0,
+ TILEGX_PIPELINE_Y1,
+ TILEGX_PIPELINE_Y2,
+} tilegx_pipeline;
-#define tile_is_x_pipeline(p) ((int)(p) <= (int)TILE_PIPELINE_X1)
+#define tilegx_is_x_pipeline(p) ((int)(p) <= (int)TILEGX_PIPELINE_X1)
typedef enum
{
- TILE_OP_TYPE_REGISTER,
- TILE_OP_TYPE_IMMEDIATE,
- TILE_OP_TYPE_ADDRESS,
- TILE_OP_TYPE_SPR
-} tile_operand_type;
+ TILEGX_OP_TYPE_REGISTER,
+ TILEGX_OP_TYPE_IMMEDIATE,
+ TILEGX_OP_TYPE_ADDRESS,
+ TILEGX_OP_TYPE_SPR
+} tilegx_operand_type;
-/* This is the bit that determines if a bundle is in the Y encoding. */
-#define TILE_BUNDLE_Y_ENCODING_MASK ((tile_bundle_bits)1 << 63)
+/* These are the bits that determine if a bundle is in the X encoding. */
+#define TILEGX_BUNDLE_MODE_MASK ((tilegx_bundle_bits)3 << 62)
enum
{
/* Maximum number of instructions in a bundle (2 for X, 3 for Y). */
- TILE_MAX_INSTRUCTIONS_PER_BUNDLE = 3,
+ TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE = 3,
/* How many different pipeline encodings are there? X0, X1, Y0, Y1, Y2. */
- TILE_NUM_PIPELINE_ENCODINGS = 5,
+ TILEGX_NUM_PIPELINE_ENCODINGS = 5,
- /* Log base 2 of TILE_BUNDLE_SIZE_IN_BYTES. */
- TILE_LOG2_BUNDLE_SIZE_IN_BYTES = 3,
+ /* Log base 2 of TILEGX_BUNDLE_SIZE_IN_BYTES. */
+ TILEGX_LOG2_BUNDLE_SIZE_IN_BYTES = 3,
/* Instructions take this many bytes. */
- TILE_BUNDLE_SIZE_IN_BYTES = 1 << TILE_LOG2_BUNDLE_SIZE_IN_BYTES,
+ TILEGX_BUNDLE_SIZE_IN_BYTES = 1 << TILEGX_LOG2_BUNDLE_SIZE_IN_BYTES,
- /* Log base 2 of TILE_BUNDLE_ALIGNMENT_IN_BYTES. */
- TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES = 3,
+ /* Log base 2 of TILEGX_BUNDLE_ALIGNMENT_IN_BYTES. */
+ TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES = 3,
/* Bundles should be aligned modulo this number of bytes. */
- TILE_BUNDLE_ALIGNMENT_IN_BYTES =
- (1 << TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES),
-
- /* Log base 2 of TILE_SN_INSTRUCTION_SIZE_IN_BYTES. */
- TILE_LOG2_SN_INSTRUCTION_SIZE_IN_BYTES = 1,
-
- /* Static network instructions take this many bytes. */
- TILE_SN_INSTRUCTION_SIZE_IN_BYTES =
- (1 << TILE_LOG2_SN_INSTRUCTION_SIZE_IN_BYTES),
+ TILEGX_BUNDLE_ALIGNMENT_IN_BYTES =
+ (1 << TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES),
/* Number of registers (some are magic, such as network I/O). */
- TILE_NUM_REGISTERS = 64,
-
- /* Number of static network registers. */
- TILE_NUM_SN_REGISTERS = 4
+ TILEGX_NUM_REGISTERS = 64,
};
-struct tile_operand
+struct tilegx_operand
{
/* Is this operand a register, immediate or address? */
- tile_operand_type type;
+ tilegx_operand_type type;
/* The default relocation type for this operand. */
signed int default_reloc : 16;
@@ -1437,27 +1180,27 @@ struct tile_operand
unsigned int rightshift : 2;
/* Return the bits for this operand to be ORed into an existing bundle. */
- tile_bundle_bits (*insert) (int op);
+ tilegx_bundle_bits (*insert) (int op);
/* Extract this operand and return it. */
- unsigned int (*extract) (tile_bundle_bits bundle);
+ unsigned int (*extract) (tilegx_bundle_bits bundle);
};
-extern const struct tile_operand tile_operands[];
+extern const struct tilegx_operand tilegx_operands[];
/* One finite-state machine per pipe for rapid instruction decoding. */
extern const unsigned short * const
-tile_bundle_decoder_fsms[TILE_NUM_PIPELINE_ENCODINGS];
+tilegx_bundle_decoder_fsms[TILEGX_NUM_PIPELINE_ENCODINGS];
-struct tile_opcode
+struct tilegx_opcode
{
/* The opcode mnemonic, e.g. "add" */
const char *name;
/* The enum value for this mnemonic. */
- tile_mnemonic mnemonic;
+ tilegx_mnemonic mnemonic;
/* A bit mask of which of the five pipes this instruction
is compatible with:
@@ -1478,29 +1221,28 @@ struct tile_opcode
unsigned char can_bundle;
/* The description of the operands. Each of these is an
- * index into the tile_operands[] table. */
- unsigned char operands[TILE_NUM_PIPELINE_ENCODINGS][TILE_MAX_OPERANDS];
+ * index into the tilegx_operands[] table. */
+ unsigned char operands[TILEGX_NUM_PIPELINE_ENCODINGS][TILEGX_MAX_OPERANDS];
};
-extern const struct tile_opcode tile_opcodes[];
-
+extern const struct tilegx_opcode tilegx_opcodes[];
/* Used for non-textual disassembly into structs. */
-struct tile_decoded_instruction
+struct tilegx_decoded_instruction
{
- const struct tile_opcode *opcode;
- const struct tile_operand *operands[TILE_MAX_OPERANDS];
- int operand_values[TILE_MAX_OPERANDS];
+ const struct tilegx_opcode *opcode;
+ const struct tilegx_operand *operands[TILEGX_MAX_OPERANDS];
+ long long operand_values[TILEGX_MAX_OPERANDS];
};
/* Disassemble a bundle into a struct for machine processing. */
-extern int parse_insn_tile(tile_bundle_bits bits,
- unsigned int pc,
- struct tile_decoded_instruction
- decoded[TILE_MAX_INSTRUCTIONS_PER_BUNDLE]);
+extern int parse_insn_tilegx(tilegx_bundle_bits bits,
+ unsigned long long pc,
+ struct tilegx_decoded_instruction
+ decoded[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE]);
-#endif /* opcode_tile_h */
+#endif /* opcode_tilegx_h */
diff --git a/arch/tile/include/asm/opcode_constants_64.h b/arch/tile/include/asm/opcode_constants_64.h
index 227d033b180c..710192869476 100644
--- a/arch/tile/include/asm/opcode_constants_64.h
+++ b/arch/tile/include/asm/opcode_constants_64.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -19,462 +19,591 @@
#define _TILE_OPCODE_CONSTANTS_H
enum
{
- ADDBS_U_SPECIAL_0_OPCODE_X0 = 98,
- ADDBS_U_SPECIAL_0_OPCODE_X1 = 68,
- ADDB_SPECIAL_0_OPCODE_X0 = 1,
- ADDB_SPECIAL_0_OPCODE_X1 = 1,
- ADDHS_SPECIAL_0_OPCODE_X0 = 99,
- ADDHS_SPECIAL_0_OPCODE_X1 = 69,
- ADDH_SPECIAL_0_OPCODE_X0 = 2,
- ADDH_SPECIAL_0_OPCODE_X1 = 2,
- ADDIB_IMM_0_OPCODE_X0 = 1,
- ADDIB_IMM_0_OPCODE_X1 = 1,
- ADDIH_IMM_0_OPCODE_X0 = 2,
- ADDIH_IMM_0_OPCODE_X1 = 2,
- ADDI_IMM_0_OPCODE_X0 = 3,
- ADDI_IMM_0_OPCODE_X1 = 3,
- ADDI_IMM_1_OPCODE_SN = 1,
- ADDI_OPCODE_Y0 = 9,
- ADDI_OPCODE_Y1 = 7,
- ADDLIS_OPCODE_X0 = 1,
- ADDLIS_OPCODE_X1 = 2,
- ADDLI_OPCODE_X0 = 2,
- ADDLI_OPCODE_X1 = 3,
- ADDS_SPECIAL_0_OPCODE_X0 = 96,
- ADDS_SPECIAL_0_OPCODE_X1 = 66,
- ADD_SPECIAL_0_OPCODE_X0 = 3,
- ADD_SPECIAL_0_OPCODE_X1 = 3,
- ADD_SPECIAL_0_OPCODE_Y0 = 0,
- ADD_SPECIAL_0_OPCODE_Y1 = 0,
- ADIFFB_U_SPECIAL_0_OPCODE_X0 = 4,
- ADIFFH_SPECIAL_0_OPCODE_X0 = 5,
- ANDI_IMM_0_OPCODE_X0 = 1,
- ANDI_IMM_0_OPCODE_X1 = 4,
- ANDI_OPCODE_Y0 = 10,
- ANDI_OPCODE_Y1 = 8,
- AND_SPECIAL_0_OPCODE_X0 = 6,
- AND_SPECIAL_0_OPCODE_X1 = 4,
- AND_SPECIAL_2_OPCODE_Y0 = 0,
- AND_SPECIAL_2_OPCODE_Y1 = 0,
- AULI_OPCODE_X0 = 3,
- AULI_OPCODE_X1 = 4,
- AVGB_U_SPECIAL_0_OPCODE_X0 = 7,
- AVGH_SPECIAL_0_OPCODE_X0 = 8,
- BBNST_BRANCH_OPCODE_X1 = 15,
- BBNS_BRANCH_OPCODE_X1 = 14,
- BBNS_OPCODE_SN = 63,
- BBST_BRANCH_OPCODE_X1 = 13,
- BBS_BRANCH_OPCODE_X1 = 12,
- BBS_OPCODE_SN = 62,
- BGEZT_BRANCH_OPCODE_X1 = 7,
- BGEZ_BRANCH_OPCODE_X1 = 6,
- BGEZ_OPCODE_SN = 61,
- BGZT_BRANCH_OPCODE_X1 = 5,
- BGZ_BRANCH_OPCODE_X1 = 4,
- BGZ_OPCODE_SN = 58,
- BITX_UN_0_SHUN_0_OPCODE_X0 = 1,
- BITX_UN_0_SHUN_0_OPCODE_Y0 = 1,
- BLEZT_BRANCH_OPCODE_X1 = 11,
- BLEZ_BRANCH_OPCODE_X1 = 10,
- BLEZ_OPCODE_SN = 59,
- BLZT_BRANCH_OPCODE_X1 = 9,
- BLZ_BRANCH_OPCODE_X1 = 8,
- BLZ_OPCODE_SN = 60,
- BNZT_BRANCH_OPCODE_X1 = 3,
- BNZ_BRANCH_OPCODE_X1 = 2,
- BNZ_OPCODE_SN = 57,
- BPT_NOREG_RR_IMM_0_OPCODE_SN = 1,
- BRANCH_OPCODE_X1 = 5,
- BYTEX_UN_0_SHUN_0_OPCODE_X0 = 2,
- BYTEX_UN_0_SHUN_0_OPCODE_Y0 = 2,
- BZT_BRANCH_OPCODE_X1 = 1,
- BZ_BRANCH_OPCODE_X1 = 0,
- BZ_OPCODE_SN = 56,
- CLZ_UN_0_SHUN_0_OPCODE_X0 = 3,
- CLZ_UN_0_SHUN_0_OPCODE_Y0 = 3,
- CRC32_32_SPECIAL_0_OPCODE_X0 = 9,
- CRC32_8_SPECIAL_0_OPCODE_X0 = 10,
- CTZ_UN_0_SHUN_0_OPCODE_X0 = 4,
- CTZ_UN_0_SHUN_0_OPCODE_Y0 = 4,
- DRAIN_UN_0_SHUN_0_OPCODE_X1 = 1,
- DTLBPR_UN_0_SHUN_0_OPCODE_X1 = 2,
- DWORD_ALIGN_SPECIAL_0_OPCODE_X0 = 95,
- FINV_UN_0_SHUN_0_OPCODE_X1 = 3,
- FLUSH_UN_0_SHUN_0_OPCODE_X1 = 4,
- FNOP_NOREG_RR_IMM_0_OPCODE_SN = 3,
- FNOP_UN_0_SHUN_0_OPCODE_X0 = 5,
- FNOP_UN_0_SHUN_0_OPCODE_X1 = 5,
- FNOP_UN_0_SHUN_0_OPCODE_Y0 = 5,
- FNOP_UN_0_SHUN_0_OPCODE_Y1 = 1,
- HALT_NOREG_RR_IMM_0_OPCODE_SN = 0,
- ICOH_UN_0_SHUN_0_OPCODE_X1 = 6,
- ILL_UN_0_SHUN_0_OPCODE_X1 = 7,
- ILL_UN_0_SHUN_0_OPCODE_Y1 = 2,
- IMM_0_OPCODE_SN = 0,
- IMM_0_OPCODE_X0 = 4,
- IMM_0_OPCODE_X1 = 6,
- IMM_1_OPCODE_SN = 1,
- IMM_OPCODE_0_X0 = 5,
- INTHB_SPECIAL_0_OPCODE_X0 = 11,
- INTHB_SPECIAL_0_OPCODE_X1 = 5,
- INTHH_SPECIAL_0_OPCODE_X0 = 12,
- INTHH_SPECIAL_0_OPCODE_X1 = 6,
- INTLB_SPECIAL_0_OPCODE_X0 = 13,
- INTLB_SPECIAL_0_OPCODE_X1 = 7,
- INTLH_SPECIAL_0_OPCODE_X0 = 14,
- INTLH_SPECIAL_0_OPCODE_X1 = 8,
- INV_UN_0_SHUN_0_OPCODE_X1 = 8,
- IRET_UN_0_SHUN_0_OPCODE_X1 = 9,
- JALB_OPCODE_X1 = 13,
- JALF_OPCODE_X1 = 12,
- JALRP_SPECIAL_0_OPCODE_X1 = 9,
- JALRR_IMM_1_OPCODE_SN = 3,
- JALR_RR_IMM_0_OPCODE_SN = 5,
- JALR_SPECIAL_0_OPCODE_X1 = 10,
- JB_OPCODE_X1 = 11,
- JF_OPCODE_X1 = 10,
- JRP_SPECIAL_0_OPCODE_X1 = 11,
- JRR_IMM_1_OPCODE_SN = 2,
- JR_RR_IMM_0_OPCODE_SN = 4,
- JR_SPECIAL_0_OPCODE_X1 = 12,
- LBADD_IMM_0_OPCODE_X1 = 22,
- LBADD_U_IMM_0_OPCODE_X1 = 23,
- LB_OPCODE_Y2 = 0,
- LB_UN_0_SHUN_0_OPCODE_X1 = 10,
- LB_U_OPCODE_Y2 = 1,
- LB_U_UN_0_SHUN_0_OPCODE_X1 = 11,
- LHADD_IMM_0_OPCODE_X1 = 24,
- LHADD_U_IMM_0_OPCODE_X1 = 25,
- LH_OPCODE_Y2 = 2,
- LH_UN_0_SHUN_0_OPCODE_X1 = 12,
- LH_U_OPCODE_Y2 = 3,
- LH_U_UN_0_SHUN_0_OPCODE_X1 = 13,
- LNK_SPECIAL_0_OPCODE_X1 = 13,
- LWADD_IMM_0_OPCODE_X1 = 26,
- LWADD_NA_IMM_0_OPCODE_X1 = 27,
- LW_NA_UN_0_SHUN_0_OPCODE_X1 = 24,
- LW_OPCODE_Y2 = 4,
- LW_UN_0_SHUN_0_OPCODE_X1 = 14,
- MAXB_U_SPECIAL_0_OPCODE_X0 = 15,
- MAXB_U_SPECIAL_0_OPCODE_X1 = 14,
- MAXH_SPECIAL_0_OPCODE_X0 = 16,
- MAXH_SPECIAL_0_OPCODE_X1 = 15,
- MAXIB_U_IMM_0_OPCODE_X0 = 4,
- MAXIB_U_IMM_0_OPCODE_X1 = 5,
- MAXIH_IMM_0_OPCODE_X0 = 5,
- MAXIH_IMM_0_OPCODE_X1 = 6,
- MFSPR_IMM_0_OPCODE_X1 = 7,
- MF_UN_0_SHUN_0_OPCODE_X1 = 15,
- MINB_U_SPECIAL_0_OPCODE_X0 = 17,
- MINB_U_SPECIAL_0_OPCODE_X1 = 16,
- MINH_SPECIAL_0_OPCODE_X0 = 18,
- MINH_SPECIAL_0_OPCODE_X1 = 17,
- MINIB_U_IMM_0_OPCODE_X0 = 6,
- MINIB_U_IMM_0_OPCODE_X1 = 8,
- MINIH_IMM_0_OPCODE_X0 = 7,
- MINIH_IMM_0_OPCODE_X1 = 9,
- MM_OPCODE_X0 = 6,
- MM_OPCODE_X1 = 7,
- MNZB_SPECIAL_0_OPCODE_X0 = 19,
- MNZB_SPECIAL_0_OPCODE_X1 = 18,
- MNZH_SPECIAL_0_OPCODE_X0 = 20,
- MNZH_SPECIAL_0_OPCODE_X1 = 19,
- MNZ_SPECIAL_0_OPCODE_X0 = 21,
- MNZ_SPECIAL_0_OPCODE_X1 = 20,
- MNZ_SPECIAL_1_OPCODE_Y0 = 0,
- MNZ_SPECIAL_1_OPCODE_Y1 = 1,
- MOVEI_IMM_1_OPCODE_SN = 0,
- MOVE_RR_IMM_0_OPCODE_SN = 8,
- MTSPR_IMM_0_OPCODE_X1 = 10,
- MULHHA_SS_SPECIAL_0_OPCODE_X0 = 22,
- MULHHA_SS_SPECIAL_7_OPCODE_Y0 = 0,
- MULHHA_SU_SPECIAL_0_OPCODE_X0 = 23,
- MULHHA_UU_SPECIAL_0_OPCODE_X0 = 24,
- MULHHA_UU_SPECIAL_7_OPCODE_Y0 = 1,
- MULHHSA_UU_SPECIAL_0_OPCODE_X0 = 25,
- MULHH_SS_SPECIAL_0_OPCODE_X0 = 26,
- MULHH_SS_SPECIAL_6_OPCODE_Y0 = 0,
- MULHH_SU_SPECIAL_0_OPCODE_X0 = 27,
- MULHH_UU_SPECIAL_0_OPCODE_X0 = 28,
- MULHH_UU_SPECIAL_6_OPCODE_Y0 = 1,
- MULHLA_SS_SPECIAL_0_OPCODE_X0 = 29,
- MULHLA_SU_SPECIAL_0_OPCODE_X0 = 30,
- MULHLA_US_SPECIAL_0_OPCODE_X0 = 31,
- MULHLA_UU_SPECIAL_0_OPCODE_X0 = 32,
- MULHLSA_UU_SPECIAL_0_OPCODE_X0 = 33,
- MULHLSA_UU_SPECIAL_5_OPCODE_Y0 = 0,
- MULHL_SS_SPECIAL_0_OPCODE_X0 = 34,
- MULHL_SU_SPECIAL_0_OPCODE_X0 = 35,
- MULHL_US_SPECIAL_0_OPCODE_X0 = 36,
- MULHL_UU_SPECIAL_0_OPCODE_X0 = 37,
- MULLLA_SS_SPECIAL_0_OPCODE_X0 = 38,
- MULLLA_SS_SPECIAL_7_OPCODE_Y0 = 2,
- MULLLA_SU_SPECIAL_0_OPCODE_X0 = 39,
- MULLLA_UU_SPECIAL_0_OPCODE_X0 = 40,
- MULLLA_UU_SPECIAL_7_OPCODE_Y0 = 3,
- MULLLSA_UU_SPECIAL_0_OPCODE_X0 = 41,
- MULLL_SS_SPECIAL_0_OPCODE_X0 = 42,
- MULLL_SS_SPECIAL_6_OPCODE_Y0 = 2,
- MULLL_SU_SPECIAL_0_OPCODE_X0 = 43,
- MULLL_UU_SPECIAL_0_OPCODE_X0 = 44,
- MULLL_UU_SPECIAL_6_OPCODE_Y0 = 3,
- MVNZ_SPECIAL_0_OPCODE_X0 = 45,
- MVNZ_SPECIAL_1_OPCODE_Y0 = 1,
- MVZ_SPECIAL_0_OPCODE_X0 = 46,
- MVZ_SPECIAL_1_OPCODE_Y0 = 2,
- MZB_SPECIAL_0_OPCODE_X0 = 47,
- MZB_SPECIAL_0_OPCODE_X1 = 21,
- MZH_SPECIAL_0_OPCODE_X0 = 48,
- MZH_SPECIAL_0_OPCODE_X1 = 22,
- MZ_SPECIAL_0_OPCODE_X0 = 49,
- MZ_SPECIAL_0_OPCODE_X1 = 23,
- MZ_SPECIAL_1_OPCODE_Y0 = 3,
- MZ_SPECIAL_1_OPCODE_Y1 = 2,
- NAP_UN_0_SHUN_0_OPCODE_X1 = 16,
- NOP_NOREG_RR_IMM_0_OPCODE_SN = 2,
- NOP_UN_0_SHUN_0_OPCODE_X0 = 6,
- NOP_UN_0_SHUN_0_OPCODE_X1 = 17,
- NOP_UN_0_SHUN_0_OPCODE_Y0 = 6,
- NOP_UN_0_SHUN_0_OPCODE_Y1 = 3,
- NOREG_RR_IMM_0_OPCODE_SN = 0,
- NOR_SPECIAL_0_OPCODE_X0 = 50,
- NOR_SPECIAL_0_OPCODE_X1 = 24,
- NOR_SPECIAL_2_OPCODE_Y0 = 1,
- NOR_SPECIAL_2_OPCODE_Y1 = 1,
- ORI_IMM_0_OPCODE_X0 = 8,
- ORI_IMM_0_OPCODE_X1 = 11,
- ORI_OPCODE_Y0 = 11,
- ORI_OPCODE_Y1 = 9,
- OR_SPECIAL_0_OPCODE_X0 = 51,
- OR_SPECIAL_0_OPCODE_X1 = 25,
- OR_SPECIAL_2_OPCODE_Y0 = 2,
- OR_SPECIAL_2_OPCODE_Y1 = 2,
- PACKBS_U_SPECIAL_0_OPCODE_X0 = 103,
- PACKBS_U_SPECIAL_0_OPCODE_X1 = 73,
- PACKHB_SPECIAL_0_OPCODE_X0 = 52,
- PACKHB_SPECIAL_0_OPCODE_X1 = 26,
- PACKHS_SPECIAL_0_OPCODE_X0 = 102,
- PACKHS_SPECIAL_0_OPCODE_X1 = 72,
- PACKLB_SPECIAL_0_OPCODE_X0 = 53,
- PACKLB_SPECIAL_0_OPCODE_X1 = 27,
- PCNT_UN_0_SHUN_0_OPCODE_X0 = 7,
- PCNT_UN_0_SHUN_0_OPCODE_Y0 = 7,
- RLI_SHUN_0_OPCODE_X0 = 1,
- RLI_SHUN_0_OPCODE_X1 = 1,
- RLI_SHUN_0_OPCODE_Y0 = 1,
- RLI_SHUN_0_OPCODE_Y1 = 1,
- RL_SPECIAL_0_OPCODE_X0 = 54,
- RL_SPECIAL_0_OPCODE_X1 = 28,
- RL_SPECIAL_3_OPCODE_Y0 = 0,
- RL_SPECIAL_3_OPCODE_Y1 = 0,
- RR_IMM_0_OPCODE_SN = 0,
- S1A_SPECIAL_0_OPCODE_X0 = 55,
- S1A_SPECIAL_0_OPCODE_X1 = 29,
- S1A_SPECIAL_0_OPCODE_Y0 = 1,
- S1A_SPECIAL_0_OPCODE_Y1 = 1,
- S2A_SPECIAL_0_OPCODE_X0 = 56,
- S2A_SPECIAL_0_OPCODE_X1 = 30,
- S2A_SPECIAL_0_OPCODE_Y0 = 2,
- S2A_SPECIAL_0_OPCODE_Y1 = 2,
- S3A_SPECIAL_0_OPCODE_X0 = 57,
- S3A_SPECIAL_0_OPCODE_X1 = 31,
- S3A_SPECIAL_5_OPCODE_Y0 = 1,
- S3A_SPECIAL_5_OPCODE_Y1 = 1,
- SADAB_U_SPECIAL_0_OPCODE_X0 = 58,
- SADAH_SPECIAL_0_OPCODE_X0 = 59,
- SADAH_U_SPECIAL_0_OPCODE_X0 = 60,
- SADB_U_SPECIAL_0_OPCODE_X0 = 61,
- SADH_SPECIAL_0_OPCODE_X0 = 62,
- SADH_U_SPECIAL_0_OPCODE_X0 = 63,
- SBADD_IMM_0_OPCODE_X1 = 28,
- SB_OPCODE_Y2 = 5,
- SB_SPECIAL_0_OPCODE_X1 = 32,
- SEQB_SPECIAL_0_OPCODE_X0 = 64,
- SEQB_SPECIAL_0_OPCODE_X1 = 33,
- SEQH_SPECIAL_0_OPCODE_X0 = 65,
- SEQH_SPECIAL_0_OPCODE_X1 = 34,
- SEQIB_IMM_0_OPCODE_X0 = 9,
- SEQIB_IMM_0_OPCODE_X1 = 12,
- SEQIH_IMM_0_OPCODE_X0 = 10,
- SEQIH_IMM_0_OPCODE_X1 = 13,
- SEQI_IMM_0_OPCODE_X0 = 11,
- SEQI_IMM_0_OPCODE_X1 = 14,
- SEQI_OPCODE_Y0 = 12,
- SEQI_OPCODE_Y1 = 10,
- SEQ_SPECIAL_0_OPCODE_X0 = 66,
- SEQ_SPECIAL_0_OPCODE_X1 = 35,
- SEQ_SPECIAL_5_OPCODE_Y0 = 2,
- SEQ_SPECIAL_5_OPCODE_Y1 = 2,
- SHADD_IMM_0_OPCODE_X1 = 29,
- SHL8II_IMM_0_OPCODE_SN = 3,
- SHLB_SPECIAL_0_OPCODE_X0 = 67,
- SHLB_SPECIAL_0_OPCODE_X1 = 36,
- SHLH_SPECIAL_0_OPCODE_X0 = 68,
- SHLH_SPECIAL_0_OPCODE_X1 = 37,
- SHLIB_SHUN_0_OPCODE_X0 = 2,
- SHLIB_SHUN_0_OPCODE_X1 = 2,
- SHLIH_SHUN_0_OPCODE_X0 = 3,
- SHLIH_SHUN_0_OPCODE_X1 = 3,
- SHLI_SHUN_0_OPCODE_X0 = 4,
- SHLI_SHUN_0_OPCODE_X1 = 4,
- SHLI_SHUN_0_OPCODE_Y0 = 2,
- SHLI_SHUN_0_OPCODE_Y1 = 2,
- SHL_SPECIAL_0_OPCODE_X0 = 69,
- SHL_SPECIAL_0_OPCODE_X1 = 38,
- SHL_SPECIAL_3_OPCODE_Y0 = 1,
- SHL_SPECIAL_3_OPCODE_Y1 = 1,
- SHR1_RR_IMM_0_OPCODE_SN = 9,
- SHRB_SPECIAL_0_OPCODE_X0 = 70,
- SHRB_SPECIAL_0_OPCODE_X1 = 39,
- SHRH_SPECIAL_0_OPCODE_X0 = 71,
- SHRH_SPECIAL_0_OPCODE_X1 = 40,
- SHRIB_SHUN_0_OPCODE_X0 = 5,
- SHRIB_SHUN_0_OPCODE_X1 = 5,
- SHRIH_SHUN_0_OPCODE_X0 = 6,
- SHRIH_SHUN_0_OPCODE_X1 = 6,
- SHRI_SHUN_0_OPCODE_X0 = 7,
- SHRI_SHUN_0_OPCODE_X1 = 7,
- SHRI_SHUN_0_OPCODE_Y0 = 3,
- SHRI_SHUN_0_OPCODE_Y1 = 3,
- SHR_SPECIAL_0_OPCODE_X0 = 72,
- SHR_SPECIAL_0_OPCODE_X1 = 41,
- SHR_SPECIAL_3_OPCODE_Y0 = 2,
- SHR_SPECIAL_3_OPCODE_Y1 = 2,
- SHUN_0_OPCODE_X0 = 7,
- SHUN_0_OPCODE_X1 = 8,
- SHUN_0_OPCODE_Y0 = 13,
- SHUN_0_OPCODE_Y1 = 11,
- SH_OPCODE_Y2 = 6,
- SH_SPECIAL_0_OPCODE_X1 = 42,
- SLTB_SPECIAL_0_OPCODE_X0 = 73,
- SLTB_SPECIAL_0_OPCODE_X1 = 43,
- SLTB_U_SPECIAL_0_OPCODE_X0 = 74,
- SLTB_U_SPECIAL_0_OPCODE_X1 = 44,
- SLTEB_SPECIAL_0_OPCODE_X0 = 75,
- SLTEB_SPECIAL_0_OPCODE_X1 = 45,
- SLTEB_U_SPECIAL_0_OPCODE_X0 = 76,
- SLTEB_U_SPECIAL_0_OPCODE_X1 = 46,
- SLTEH_SPECIAL_0_OPCODE_X0 = 77,
- SLTEH_SPECIAL_0_OPCODE_X1 = 47,
- SLTEH_U_SPECIAL_0_OPCODE_X0 = 78,
- SLTEH_U_SPECIAL_0_OPCODE_X1 = 48,
- SLTE_SPECIAL_0_OPCODE_X0 = 79,
- SLTE_SPECIAL_0_OPCODE_X1 = 49,
- SLTE_SPECIAL_4_OPCODE_Y0 = 0,
- SLTE_SPECIAL_4_OPCODE_Y1 = 0,
- SLTE_U_SPECIAL_0_OPCODE_X0 = 80,
- SLTE_U_SPECIAL_0_OPCODE_X1 = 50,
- SLTE_U_SPECIAL_4_OPCODE_Y0 = 1,
- SLTE_U_SPECIAL_4_OPCODE_Y1 = 1,
- SLTH_SPECIAL_0_OPCODE_X0 = 81,
- SLTH_SPECIAL_0_OPCODE_X1 = 51,
- SLTH_U_SPECIAL_0_OPCODE_X0 = 82,
- SLTH_U_SPECIAL_0_OPCODE_X1 = 52,
- SLTIB_IMM_0_OPCODE_X0 = 12,
- SLTIB_IMM_0_OPCODE_X1 = 15,
- SLTIB_U_IMM_0_OPCODE_X0 = 13,
- SLTIB_U_IMM_0_OPCODE_X1 = 16,
- SLTIH_IMM_0_OPCODE_X0 = 14,
- SLTIH_IMM_0_OPCODE_X1 = 17,
- SLTIH_U_IMM_0_OPCODE_X0 = 15,
- SLTIH_U_IMM_0_OPCODE_X1 = 18,
- SLTI_IMM_0_OPCODE_X0 = 16,
- SLTI_IMM_0_OPCODE_X1 = 19,
- SLTI_OPCODE_Y0 = 14,
- SLTI_OPCODE_Y1 = 12,
- SLTI_U_IMM_0_OPCODE_X0 = 17,
- SLTI_U_IMM_0_OPCODE_X1 = 20,
- SLTI_U_OPCODE_Y0 = 15,
- SLTI_U_OPCODE_Y1 = 13,
- SLT_SPECIAL_0_OPCODE_X0 = 83,
- SLT_SPECIAL_0_OPCODE_X1 = 53,
- SLT_SPECIAL_4_OPCODE_Y0 = 2,
- SLT_SPECIAL_4_OPCODE_Y1 = 2,
- SLT_U_SPECIAL_0_OPCODE_X0 = 84,
- SLT_U_SPECIAL_0_OPCODE_X1 = 54,
- SLT_U_SPECIAL_4_OPCODE_Y0 = 3,
- SLT_U_SPECIAL_4_OPCODE_Y1 = 3,
- SNEB_SPECIAL_0_OPCODE_X0 = 85,
- SNEB_SPECIAL_0_OPCODE_X1 = 55,
- SNEH_SPECIAL_0_OPCODE_X0 = 86,
- SNEH_SPECIAL_0_OPCODE_X1 = 56,
- SNE_SPECIAL_0_OPCODE_X0 = 87,
- SNE_SPECIAL_0_OPCODE_X1 = 57,
- SNE_SPECIAL_5_OPCODE_Y0 = 3,
- SNE_SPECIAL_5_OPCODE_Y1 = 3,
- SPECIAL_0_OPCODE_X0 = 0,
- SPECIAL_0_OPCODE_X1 = 1,
- SPECIAL_0_OPCODE_Y0 = 1,
- SPECIAL_0_OPCODE_Y1 = 1,
- SPECIAL_1_OPCODE_Y0 = 2,
- SPECIAL_1_OPCODE_Y1 = 2,
- SPECIAL_2_OPCODE_Y0 = 3,
- SPECIAL_2_OPCODE_Y1 = 3,
- SPECIAL_3_OPCODE_Y0 = 4,
- SPECIAL_3_OPCODE_Y1 = 4,
- SPECIAL_4_OPCODE_Y0 = 5,
- SPECIAL_4_OPCODE_Y1 = 5,
- SPECIAL_5_OPCODE_Y0 = 6,
- SPECIAL_5_OPCODE_Y1 = 6,
- SPECIAL_6_OPCODE_Y0 = 7,
- SPECIAL_7_OPCODE_Y0 = 8,
- SRAB_SPECIAL_0_OPCODE_X0 = 88,
- SRAB_SPECIAL_0_OPCODE_X1 = 58,
- SRAH_SPECIAL_0_OPCODE_X0 = 89,
- SRAH_SPECIAL_0_OPCODE_X1 = 59,
- SRAIB_SHUN_0_OPCODE_X0 = 8,
- SRAIB_SHUN_0_OPCODE_X1 = 8,
- SRAIH_SHUN_0_OPCODE_X0 = 9,
- SRAIH_SHUN_0_OPCODE_X1 = 9,
- SRAI_SHUN_0_OPCODE_X0 = 10,
- SRAI_SHUN_0_OPCODE_X1 = 10,
- SRAI_SHUN_0_OPCODE_Y0 = 4,
- SRAI_SHUN_0_OPCODE_Y1 = 4,
- SRA_SPECIAL_0_OPCODE_X0 = 90,
- SRA_SPECIAL_0_OPCODE_X1 = 60,
- SRA_SPECIAL_3_OPCODE_Y0 = 3,
- SRA_SPECIAL_3_OPCODE_Y1 = 3,
- SUBBS_U_SPECIAL_0_OPCODE_X0 = 100,
- SUBBS_U_SPECIAL_0_OPCODE_X1 = 70,
- SUBB_SPECIAL_0_OPCODE_X0 = 91,
- SUBB_SPECIAL_0_OPCODE_X1 = 61,
- SUBHS_SPECIAL_0_OPCODE_X0 = 101,
- SUBHS_SPECIAL_0_OPCODE_X1 = 71,
- SUBH_SPECIAL_0_OPCODE_X0 = 92,
- SUBH_SPECIAL_0_OPCODE_X1 = 62,
- SUBS_SPECIAL_0_OPCODE_X0 = 97,
- SUBS_SPECIAL_0_OPCODE_X1 = 67,
- SUB_SPECIAL_0_OPCODE_X0 = 93,
- SUB_SPECIAL_0_OPCODE_X1 = 63,
- SUB_SPECIAL_0_OPCODE_Y0 = 3,
- SUB_SPECIAL_0_OPCODE_Y1 = 3,
- SWADD_IMM_0_OPCODE_X1 = 30,
- SWINT0_UN_0_SHUN_0_OPCODE_X1 = 18,
- SWINT1_UN_0_SHUN_0_OPCODE_X1 = 19,
- SWINT2_UN_0_SHUN_0_OPCODE_X1 = 20,
- SWINT3_UN_0_SHUN_0_OPCODE_X1 = 21,
- SW_OPCODE_Y2 = 7,
- SW_SPECIAL_0_OPCODE_X1 = 64,
- TBLIDXB0_UN_0_SHUN_0_OPCODE_X0 = 8,
- TBLIDXB0_UN_0_SHUN_0_OPCODE_Y0 = 8,
- TBLIDXB1_UN_0_SHUN_0_OPCODE_X0 = 9,
- TBLIDXB1_UN_0_SHUN_0_OPCODE_Y0 = 9,
- TBLIDXB2_UN_0_SHUN_0_OPCODE_X0 = 10,
- TBLIDXB2_UN_0_SHUN_0_OPCODE_Y0 = 10,
- TBLIDXB3_UN_0_SHUN_0_OPCODE_X0 = 11,
- TBLIDXB3_UN_0_SHUN_0_OPCODE_Y0 = 11,
- TNS_UN_0_SHUN_0_OPCODE_X1 = 22,
- UN_0_SHUN_0_OPCODE_X0 = 11,
- UN_0_SHUN_0_OPCODE_X1 = 11,
- UN_0_SHUN_0_OPCODE_Y0 = 5,
- UN_0_SHUN_0_OPCODE_Y1 = 5,
- WH64_UN_0_SHUN_0_OPCODE_X1 = 23,
- XORI_IMM_0_OPCODE_X0 = 2,
- XORI_IMM_0_OPCODE_X1 = 21,
- XOR_SPECIAL_0_OPCODE_X0 = 94,
- XOR_SPECIAL_0_OPCODE_X1 = 65,
- XOR_SPECIAL_2_OPCODE_Y0 = 3,
- XOR_SPECIAL_2_OPCODE_Y1 = 3
+ ADDI_IMM8_OPCODE_X0 = 1,
+ ADDI_IMM8_OPCODE_X1 = 1,
+ ADDI_OPCODE_Y0 = 0,
+ ADDI_OPCODE_Y1 = 1,
+ ADDLI_OPCODE_X0 = 1,
+ ADDLI_OPCODE_X1 = 0,
+ ADDXI_IMM8_OPCODE_X0 = 2,
+ ADDXI_IMM8_OPCODE_X1 = 2,
+ ADDXI_OPCODE_Y0 = 1,
+ ADDXI_OPCODE_Y1 = 2,
+ ADDXLI_OPCODE_X0 = 2,
+ ADDXLI_OPCODE_X1 = 1,
+ ADDXSC_RRR_0_OPCODE_X0 = 1,
+ ADDXSC_RRR_0_OPCODE_X1 = 1,
+ ADDX_RRR_0_OPCODE_X0 = 2,
+ ADDX_RRR_0_OPCODE_X1 = 2,
+ ADDX_RRR_0_OPCODE_Y0 = 0,
+ ADDX_SPECIAL_0_OPCODE_Y1 = 0,
+ ADD_RRR_0_OPCODE_X0 = 3,
+ ADD_RRR_0_OPCODE_X1 = 3,
+ ADD_RRR_0_OPCODE_Y0 = 1,
+ ADD_SPECIAL_0_OPCODE_Y1 = 1,
+ ANDI_IMM8_OPCODE_X0 = 3,
+ ANDI_IMM8_OPCODE_X1 = 3,
+ ANDI_OPCODE_Y0 = 2,
+ ANDI_OPCODE_Y1 = 3,
+ AND_RRR_0_OPCODE_X0 = 4,
+ AND_RRR_0_OPCODE_X1 = 4,
+ AND_RRR_5_OPCODE_Y0 = 0,
+ AND_RRR_5_OPCODE_Y1 = 0,
+ BEQZT_BRANCH_OPCODE_X1 = 16,
+ BEQZ_BRANCH_OPCODE_X1 = 17,
+ BFEXTS_BF_OPCODE_X0 = 4,
+ BFEXTU_BF_OPCODE_X0 = 5,
+ BFINS_BF_OPCODE_X0 = 6,
+ BF_OPCODE_X0 = 3,
+ BGEZT_BRANCH_OPCODE_X1 = 18,
+ BGEZ_BRANCH_OPCODE_X1 = 19,
+ BGTZT_BRANCH_OPCODE_X1 = 20,
+ BGTZ_BRANCH_OPCODE_X1 = 21,
+ BLBCT_BRANCH_OPCODE_X1 = 22,
+ BLBC_BRANCH_OPCODE_X1 = 23,
+ BLBST_BRANCH_OPCODE_X1 = 24,
+ BLBS_BRANCH_OPCODE_X1 = 25,
+ BLEZT_BRANCH_OPCODE_X1 = 26,
+ BLEZ_BRANCH_OPCODE_X1 = 27,
+ BLTZT_BRANCH_OPCODE_X1 = 28,
+ BLTZ_BRANCH_OPCODE_X1 = 29,
+ BNEZT_BRANCH_OPCODE_X1 = 30,
+ BNEZ_BRANCH_OPCODE_X1 = 31,
+ BRANCH_OPCODE_X1 = 2,
+ CMOVEQZ_RRR_0_OPCODE_X0 = 5,
+ CMOVEQZ_RRR_4_OPCODE_Y0 = 0,
+ CMOVNEZ_RRR_0_OPCODE_X0 = 6,
+ CMOVNEZ_RRR_4_OPCODE_Y0 = 1,
+ CMPEQI_IMM8_OPCODE_X0 = 4,
+ CMPEQI_IMM8_OPCODE_X1 = 4,
+ CMPEQI_OPCODE_Y0 = 3,
+ CMPEQI_OPCODE_Y1 = 4,
+ CMPEQ_RRR_0_OPCODE_X0 = 7,
+ CMPEQ_RRR_0_OPCODE_X1 = 5,
+ CMPEQ_RRR_3_OPCODE_Y0 = 0,
+ CMPEQ_RRR_3_OPCODE_Y1 = 2,
+ CMPEXCH4_RRR_0_OPCODE_X1 = 6,
+ CMPEXCH_RRR_0_OPCODE_X1 = 7,
+ CMPLES_RRR_0_OPCODE_X0 = 8,
+ CMPLES_RRR_0_OPCODE_X1 = 8,
+ CMPLES_RRR_2_OPCODE_Y0 = 0,
+ CMPLES_RRR_2_OPCODE_Y1 = 0,
+ CMPLEU_RRR_0_OPCODE_X0 = 9,
+ CMPLEU_RRR_0_OPCODE_X1 = 9,
+ CMPLEU_RRR_2_OPCODE_Y0 = 1,
+ CMPLEU_RRR_2_OPCODE_Y1 = 1,
+ CMPLTSI_IMM8_OPCODE_X0 = 5,
+ CMPLTSI_IMM8_OPCODE_X1 = 5,
+ CMPLTSI_OPCODE_Y0 = 4,
+ CMPLTSI_OPCODE_Y1 = 5,
+ CMPLTS_RRR_0_OPCODE_X0 = 10,
+ CMPLTS_RRR_0_OPCODE_X1 = 10,
+ CMPLTS_RRR_2_OPCODE_Y0 = 2,
+ CMPLTS_RRR_2_OPCODE_Y1 = 2,
+ CMPLTUI_IMM8_OPCODE_X0 = 6,
+ CMPLTUI_IMM8_OPCODE_X1 = 6,
+ CMPLTU_RRR_0_OPCODE_X0 = 11,
+ CMPLTU_RRR_0_OPCODE_X1 = 11,
+ CMPLTU_RRR_2_OPCODE_Y0 = 3,
+ CMPLTU_RRR_2_OPCODE_Y1 = 3,
+ CMPNE_RRR_0_OPCODE_X0 = 12,
+ CMPNE_RRR_0_OPCODE_X1 = 12,
+ CMPNE_RRR_3_OPCODE_Y0 = 1,
+ CMPNE_RRR_3_OPCODE_Y1 = 3,
+ CMULAF_RRR_0_OPCODE_X0 = 13,
+ CMULA_RRR_0_OPCODE_X0 = 14,
+ CMULFR_RRR_0_OPCODE_X0 = 15,
+ CMULF_RRR_0_OPCODE_X0 = 16,
+ CMULHR_RRR_0_OPCODE_X0 = 17,
+ CMULH_RRR_0_OPCODE_X0 = 18,
+ CMUL_RRR_0_OPCODE_X0 = 19,
+ CNTLZ_UNARY_OPCODE_X0 = 1,
+ CNTLZ_UNARY_OPCODE_Y0 = 1,
+ CNTTZ_UNARY_OPCODE_X0 = 2,
+ CNTTZ_UNARY_OPCODE_Y0 = 2,
+ CRC32_32_RRR_0_OPCODE_X0 = 20,
+ CRC32_8_RRR_0_OPCODE_X0 = 21,
+ DBLALIGN2_RRR_0_OPCODE_X0 = 22,
+ DBLALIGN2_RRR_0_OPCODE_X1 = 13,
+ DBLALIGN4_RRR_0_OPCODE_X0 = 23,
+ DBLALIGN4_RRR_0_OPCODE_X1 = 14,
+ DBLALIGN6_RRR_0_OPCODE_X0 = 24,
+ DBLALIGN6_RRR_0_OPCODE_X1 = 15,
+ DBLALIGN_RRR_0_OPCODE_X0 = 25,
+ DRAIN_UNARY_OPCODE_X1 = 1,
+ DTLBPR_UNARY_OPCODE_X1 = 2,
+ EXCH4_RRR_0_OPCODE_X1 = 16,
+ EXCH_RRR_0_OPCODE_X1 = 17,
+ FDOUBLE_ADDSUB_RRR_0_OPCODE_X0 = 26,
+ FDOUBLE_ADD_FLAGS_RRR_0_OPCODE_X0 = 27,
+ FDOUBLE_MUL_FLAGS_RRR_0_OPCODE_X0 = 28,
+ FDOUBLE_PACK1_RRR_0_OPCODE_X0 = 29,
+ FDOUBLE_PACK2_RRR_0_OPCODE_X0 = 30,
+ FDOUBLE_SUB_FLAGS_RRR_0_OPCODE_X0 = 31,
+ FDOUBLE_UNPACK_MAX_RRR_0_OPCODE_X0 = 32,
+ FDOUBLE_UNPACK_MIN_RRR_0_OPCODE_X0 = 33,
+ FETCHADD4_RRR_0_OPCODE_X1 = 18,
+ FETCHADDGEZ4_RRR_0_OPCODE_X1 = 19,
+ FETCHADDGEZ_RRR_0_OPCODE_X1 = 20,
+ FETCHADD_RRR_0_OPCODE_X1 = 21,
+ FETCHAND4_RRR_0_OPCODE_X1 = 22,
+ FETCHAND_RRR_0_OPCODE_X1 = 23,
+ FETCHOR4_RRR_0_OPCODE_X1 = 24,
+ FETCHOR_RRR_0_OPCODE_X1 = 25,
+ FINV_UNARY_OPCODE_X1 = 3,
+ FLUSHWB_UNARY_OPCODE_X1 = 4,
+ FLUSH_UNARY_OPCODE_X1 = 5,
+ FNOP_UNARY_OPCODE_X0 = 3,
+ FNOP_UNARY_OPCODE_X1 = 6,
+ FNOP_UNARY_OPCODE_Y0 = 3,
+ FNOP_UNARY_OPCODE_Y1 = 8,
+ FSINGLE_ADD1_RRR_0_OPCODE_X0 = 34,
+ FSINGLE_ADDSUB2_RRR_0_OPCODE_X0 = 35,
+ FSINGLE_MUL1_RRR_0_OPCODE_X0 = 36,
+ FSINGLE_MUL2_RRR_0_OPCODE_X0 = 37,
+ FSINGLE_PACK1_UNARY_OPCODE_X0 = 4,
+ FSINGLE_PACK1_UNARY_OPCODE_Y0 = 4,
+ FSINGLE_PACK2_RRR_0_OPCODE_X0 = 38,
+ FSINGLE_SUB1_RRR_0_OPCODE_X0 = 39,
+ ICOH_UNARY_OPCODE_X1 = 7,
+ ILL_UNARY_OPCODE_X1 = 8,
+ ILL_UNARY_OPCODE_Y1 = 9,
+ IMM8_OPCODE_X0 = 4,
+ IMM8_OPCODE_X1 = 3,
+ INV_UNARY_OPCODE_X1 = 9,
+ IRET_UNARY_OPCODE_X1 = 10,
+ JALRP_UNARY_OPCODE_X1 = 11,
+ JALRP_UNARY_OPCODE_Y1 = 10,
+ JALR_UNARY_OPCODE_X1 = 12,
+ JALR_UNARY_OPCODE_Y1 = 11,
+ JAL_JUMP_OPCODE_X1 = 0,
+ JRP_UNARY_OPCODE_X1 = 13,
+ JRP_UNARY_OPCODE_Y1 = 12,
+ JR_UNARY_OPCODE_X1 = 14,
+ JR_UNARY_OPCODE_Y1 = 13,
+ JUMP_OPCODE_X1 = 4,
+ J_JUMP_OPCODE_X1 = 1,
+ LD1S_ADD_IMM8_OPCODE_X1 = 7,
+ LD1S_OPCODE_Y2 = 0,
+ LD1S_UNARY_OPCODE_X1 = 15,
+ LD1U_ADD_IMM8_OPCODE_X1 = 8,
+ LD1U_OPCODE_Y2 = 1,
+ LD1U_UNARY_OPCODE_X1 = 16,
+ LD2S_ADD_IMM8_OPCODE_X1 = 9,
+ LD2S_OPCODE_Y2 = 2,
+ LD2S_UNARY_OPCODE_X1 = 17,
+ LD2U_ADD_IMM8_OPCODE_X1 = 10,
+ LD2U_OPCODE_Y2 = 3,
+ LD2U_UNARY_OPCODE_X1 = 18,
+ LD4S_ADD_IMM8_OPCODE_X1 = 11,
+ LD4S_OPCODE_Y2 = 1,
+ LD4S_UNARY_OPCODE_X1 = 19,
+ LD4U_ADD_IMM8_OPCODE_X1 = 12,
+ LD4U_OPCODE_Y2 = 2,
+ LD4U_UNARY_OPCODE_X1 = 20,
+ LDNA_UNARY_OPCODE_X1 = 21,
+ LDNT1S_ADD_IMM8_OPCODE_X1 = 13,
+ LDNT1S_UNARY_OPCODE_X1 = 22,
+ LDNT1U_ADD_IMM8_OPCODE_X1 = 14,
+ LDNT1U_UNARY_OPCODE_X1 = 23,
+ LDNT2S_ADD_IMM8_OPCODE_X1 = 15,
+ LDNT2S_UNARY_OPCODE_X1 = 24,
+ LDNT2U_ADD_IMM8_OPCODE_X1 = 16,
+ LDNT2U_UNARY_OPCODE_X1 = 25,
+ LDNT4S_ADD_IMM8_OPCODE_X1 = 17,
+ LDNT4S_UNARY_OPCODE_X1 = 26,
+ LDNT4U_ADD_IMM8_OPCODE_X1 = 18,
+ LDNT4U_UNARY_OPCODE_X1 = 27,
+ LDNT_ADD_IMM8_OPCODE_X1 = 19,
+ LDNT_UNARY_OPCODE_X1 = 28,
+ LD_ADD_IMM8_OPCODE_X1 = 20,
+ LD_OPCODE_Y2 = 3,
+ LD_UNARY_OPCODE_X1 = 29,
+ LNK_UNARY_OPCODE_X1 = 30,
+ LNK_UNARY_OPCODE_Y1 = 14,
+ LWNA_ADD_IMM8_OPCODE_X1 = 21,
+ MFSPR_IMM8_OPCODE_X1 = 22,
+ MF_UNARY_OPCODE_X1 = 31,
+ MM_BF_OPCODE_X0 = 7,
+ MNZ_RRR_0_OPCODE_X0 = 40,
+ MNZ_RRR_0_OPCODE_X1 = 26,
+ MNZ_RRR_4_OPCODE_Y0 = 2,
+ MNZ_RRR_4_OPCODE_Y1 = 2,
+ MODE_OPCODE_YA2 = 1,
+ MODE_OPCODE_YB2 = 2,
+ MODE_OPCODE_YC2 = 3,
+ MTSPR_IMM8_OPCODE_X1 = 23,
+ MULAX_RRR_0_OPCODE_X0 = 41,
+ MULAX_RRR_3_OPCODE_Y0 = 2,
+ MULA_HS_HS_RRR_0_OPCODE_X0 = 42,
+ MULA_HS_HS_RRR_9_OPCODE_Y0 = 0,
+ MULA_HS_HU_RRR_0_OPCODE_X0 = 43,
+ MULA_HS_LS_RRR_0_OPCODE_X0 = 44,
+ MULA_HS_LU_RRR_0_OPCODE_X0 = 45,
+ MULA_HU_HU_RRR_0_OPCODE_X0 = 46,
+ MULA_HU_HU_RRR_9_OPCODE_Y0 = 1,
+ MULA_HU_LS_RRR_0_OPCODE_X0 = 47,
+ MULA_HU_LU_RRR_0_OPCODE_X0 = 48,
+ MULA_LS_LS_RRR_0_OPCODE_X0 = 49,
+ MULA_LS_LS_RRR_9_OPCODE_Y0 = 2,
+ MULA_LS_LU_RRR_0_OPCODE_X0 = 50,
+ MULA_LU_LU_RRR_0_OPCODE_X0 = 51,
+ MULA_LU_LU_RRR_9_OPCODE_Y0 = 3,
+ MULX_RRR_0_OPCODE_X0 = 52,
+ MULX_RRR_3_OPCODE_Y0 = 3,
+ MUL_HS_HS_RRR_0_OPCODE_X0 = 53,
+ MUL_HS_HS_RRR_8_OPCODE_Y0 = 0,
+ MUL_HS_HU_RRR_0_OPCODE_X0 = 54,
+ MUL_HS_LS_RRR_0_OPCODE_X0 = 55,
+ MUL_HS_LU_RRR_0_OPCODE_X0 = 56,
+ MUL_HU_HU_RRR_0_OPCODE_X0 = 57,
+ MUL_HU_HU_RRR_8_OPCODE_Y0 = 1,
+ MUL_HU_LS_RRR_0_OPCODE_X0 = 58,
+ MUL_HU_LU_RRR_0_OPCODE_X0 = 59,
+ MUL_LS_LS_RRR_0_OPCODE_X0 = 60,
+ MUL_LS_LS_RRR_8_OPCODE_Y0 = 2,
+ MUL_LS_LU_RRR_0_OPCODE_X0 = 61,
+ MUL_LU_LU_RRR_0_OPCODE_X0 = 62,
+ MUL_LU_LU_RRR_8_OPCODE_Y0 = 3,
+ MZ_RRR_0_OPCODE_X0 = 63,
+ MZ_RRR_0_OPCODE_X1 = 27,
+ MZ_RRR_4_OPCODE_Y0 = 3,
+ MZ_RRR_4_OPCODE_Y1 = 3,
+ NAP_UNARY_OPCODE_X1 = 32,
+ NOP_UNARY_OPCODE_X0 = 5,
+ NOP_UNARY_OPCODE_X1 = 33,
+ NOP_UNARY_OPCODE_Y0 = 5,
+ NOP_UNARY_OPCODE_Y1 = 15,
+ NOR_RRR_0_OPCODE_X0 = 64,
+ NOR_RRR_0_OPCODE_X1 = 28,
+ NOR_RRR_5_OPCODE_Y0 = 1,
+ NOR_RRR_5_OPCODE_Y1 = 1,
+ ORI_IMM8_OPCODE_X0 = 7,
+ ORI_IMM8_OPCODE_X1 = 24,
+ OR_RRR_0_OPCODE_X0 = 65,
+ OR_RRR_0_OPCODE_X1 = 29,
+ OR_RRR_5_OPCODE_Y0 = 2,
+ OR_RRR_5_OPCODE_Y1 = 2,
+ PCNT_UNARY_OPCODE_X0 = 6,
+ PCNT_UNARY_OPCODE_Y0 = 6,
+ REVBITS_UNARY_OPCODE_X0 = 7,
+ REVBITS_UNARY_OPCODE_Y0 = 7,
+ REVBYTES_UNARY_OPCODE_X0 = 8,
+ REVBYTES_UNARY_OPCODE_Y0 = 8,
+ ROTLI_SHIFT_OPCODE_X0 = 1,
+ ROTLI_SHIFT_OPCODE_X1 = 1,
+ ROTLI_SHIFT_OPCODE_Y0 = 0,
+ ROTLI_SHIFT_OPCODE_Y1 = 0,
+ ROTL_RRR_0_OPCODE_X0 = 66,
+ ROTL_RRR_0_OPCODE_X1 = 30,
+ ROTL_RRR_6_OPCODE_Y0 = 0,
+ ROTL_RRR_6_OPCODE_Y1 = 0,
+ RRR_0_OPCODE_X0 = 5,
+ RRR_0_OPCODE_X1 = 5,
+ RRR_0_OPCODE_Y0 = 5,
+ RRR_0_OPCODE_Y1 = 6,
+ RRR_1_OPCODE_Y0 = 6,
+ RRR_1_OPCODE_Y1 = 7,
+ RRR_2_OPCODE_Y0 = 7,
+ RRR_2_OPCODE_Y1 = 8,
+ RRR_3_OPCODE_Y0 = 8,
+ RRR_3_OPCODE_Y1 = 9,
+ RRR_4_OPCODE_Y0 = 9,
+ RRR_4_OPCODE_Y1 = 10,
+ RRR_5_OPCODE_Y0 = 10,
+ RRR_5_OPCODE_Y1 = 11,
+ RRR_6_OPCODE_Y0 = 11,
+ RRR_6_OPCODE_Y1 = 12,
+ RRR_7_OPCODE_Y0 = 12,
+ RRR_7_OPCODE_Y1 = 13,
+ RRR_8_OPCODE_Y0 = 13,
+ RRR_9_OPCODE_Y0 = 14,
+ SHIFT_OPCODE_X0 = 6,
+ SHIFT_OPCODE_X1 = 6,
+ SHIFT_OPCODE_Y0 = 15,
+ SHIFT_OPCODE_Y1 = 14,
+ SHL16INSLI_OPCODE_X0 = 7,
+ SHL16INSLI_OPCODE_X1 = 7,
+ SHL1ADDX_RRR_0_OPCODE_X0 = 67,
+ SHL1ADDX_RRR_0_OPCODE_X1 = 31,
+ SHL1ADDX_RRR_7_OPCODE_Y0 = 1,
+ SHL1ADDX_RRR_7_OPCODE_Y1 = 1,
+ SHL1ADD_RRR_0_OPCODE_X0 = 68,
+ SHL1ADD_RRR_0_OPCODE_X1 = 32,
+ SHL1ADD_RRR_1_OPCODE_Y0 = 0,
+ SHL1ADD_RRR_1_OPCODE_Y1 = 0,
+ SHL2ADDX_RRR_0_OPCODE_X0 = 69,
+ SHL2ADDX_RRR_0_OPCODE_X1 = 33,
+ SHL2ADDX_RRR_7_OPCODE_Y0 = 2,
+ SHL2ADDX_RRR_7_OPCODE_Y1 = 2,
+ SHL2ADD_RRR_0_OPCODE_X0 = 70,
+ SHL2ADD_RRR_0_OPCODE_X1 = 34,
+ SHL2ADD_RRR_1_OPCODE_Y0 = 1,
+ SHL2ADD_RRR_1_OPCODE_Y1 = 1,
+ SHL3ADDX_RRR_0_OPCODE_X0 = 71,
+ SHL3ADDX_RRR_0_OPCODE_X1 = 35,
+ SHL3ADDX_RRR_7_OPCODE_Y0 = 3,
+ SHL3ADDX_RRR_7_OPCODE_Y1 = 3,
+ SHL3ADD_RRR_0_OPCODE_X0 = 72,
+ SHL3ADD_RRR_0_OPCODE_X1 = 36,
+ SHL3ADD_RRR_1_OPCODE_Y0 = 2,
+ SHL3ADD_RRR_1_OPCODE_Y1 = 2,
+ SHLI_SHIFT_OPCODE_X0 = 2,
+ SHLI_SHIFT_OPCODE_X1 = 2,
+ SHLI_SHIFT_OPCODE_Y0 = 1,
+ SHLI_SHIFT_OPCODE_Y1 = 1,
+ SHLXI_SHIFT_OPCODE_X0 = 3,
+ SHLXI_SHIFT_OPCODE_X1 = 3,
+ SHLX_RRR_0_OPCODE_X0 = 73,
+ SHLX_RRR_0_OPCODE_X1 = 37,
+ SHL_RRR_0_OPCODE_X0 = 74,
+ SHL_RRR_0_OPCODE_X1 = 38,
+ SHL_RRR_6_OPCODE_Y0 = 1,
+ SHL_RRR_6_OPCODE_Y1 = 1,
+ SHRSI_SHIFT_OPCODE_X0 = 4,
+ SHRSI_SHIFT_OPCODE_X1 = 4,
+ SHRSI_SHIFT_OPCODE_Y0 = 2,
+ SHRSI_SHIFT_OPCODE_Y1 = 2,
+ SHRS_RRR_0_OPCODE_X0 = 75,
+ SHRS_RRR_0_OPCODE_X1 = 39,
+ SHRS_RRR_6_OPCODE_Y0 = 2,
+ SHRS_RRR_6_OPCODE_Y1 = 2,
+ SHRUI_SHIFT_OPCODE_X0 = 5,
+ SHRUI_SHIFT_OPCODE_X1 = 5,
+ SHRUI_SHIFT_OPCODE_Y0 = 3,
+ SHRUI_SHIFT_OPCODE_Y1 = 3,
+ SHRUXI_SHIFT_OPCODE_X0 = 6,
+ SHRUXI_SHIFT_OPCODE_X1 = 6,
+ SHRUX_RRR_0_OPCODE_X0 = 76,
+ SHRUX_RRR_0_OPCODE_X1 = 40,
+ SHRU_RRR_0_OPCODE_X0 = 77,
+ SHRU_RRR_0_OPCODE_X1 = 41,
+ SHRU_RRR_6_OPCODE_Y0 = 3,
+ SHRU_RRR_6_OPCODE_Y1 = 3,
+ SHUFFLEBYTES_RRR_0_OPCODE_X0 = 78,
+ ST1_ADD_IMM8_OPCODE_X1 = 25,
+ ST1_OPCODE_Y2 = 0,
+ ST1_RRR_0_OPCODE_X1 = 42,
+ ST2_ADD_IMM8_OPCODE_X1 = 26,
+ ST2_OPCODE_Y2 = 1,
+ ST2_RRR_0_OPCODE_X1 = 43,
+ ST4_ADD_IMM8_OPCODE_X1 = 27,
+ ST4_OPCODE_Y2 = 2,
+ ST4_RRR_0_OPCODE_X1 = 44,
+ STNT1_ADD_IMM8_OPCODE_X1 = 28,
+ STNT1_RRR_0_OPCODE_X1 = 45,
+ STNT2_ADD_IMM8_OPCODE_X1 = 29,
+ STNT2_RRR_0_OPCODE_X1 = 46,
+ STNT4_ADD_IMM8_OPCODE_X1 = 30,
+ STNT4_RRR_0_OPCODE_X1 = 47,
+ STNT_ADD_IMM8_OPCODE_X1 = 31,
+ STNT_RRR_0_OPCODE_X1 = 48,
+ ST_ADD_IMM8_OPCODE_X1 = 32,
+ ST_OPCODE_Y2 = 3,
+ ST_RRR_0_OPCODE_X1 = 49,
+ SUBXSC_RRR_0_OPCODE_X0 = 79,
+ SUBXSC_RRR_0_OPCODE_X1 = 50,
+ SUBX_RRR_0_OPCODE_X0 = 80,
+ SUBX_RRR_0_OPCODE_X1 = 51,
+ SUBX_RRR_0_OPCODE_Y0 = 2,
+ SUBX_RRR_0_OPCODE_Y1 = 2,
+ SUB_RRR_0_OPCODE_X0 = 81,
+ SUB_RRR_0_OPCODE_X1 = 52,
+ SUB_RRR_0_OPCODE_Y0 = 3,
+ SUB_RRR_0_OPCODE_Y1 = 3,
+ SWINT0_UNARY_OPCODE_X1 = 34,
+ SWINT1_UNARY_OPCODE_X1 = 35,
+ SWINT2_UNARY_OPCODE_X1 = 36,
+ SWINT3_UNARY_OPCODE_X1 = 37,
+ TBLIDXB0_UNARY_OPCODE_X0 = 9,
+ TBLIDXB0_UNARY_OPCODE_Y0 = 9,
+ TBLIDXB1_UNARY_OPCODE_X0 = 10,
+ TBLIDXB1_UNARY_OPCODE_Y0 = 10,
+ TBLIDXB2_UNARY_OPCODE_X0 = 11,
+ TBLIDXB2_UNARY_OPCODE_Y0 = 11,
+ TBLIDXB3_UNARY_OPCODE_X0 = 12,
+ TBLIDXB3_UNARY_OPCODE_Y0 = 12,
+ UNARY_RRR_0_OPCODE_X0 = 82,
+ UNARY_RRR_0_OPCODE_X1 = 53,
+ UNARY_RRR_1_OPCODE_Y0 = 3,
+ UNARY_RRR_1_OPCODE_Y1 = 3,
+ V1ADDI_IMM8_OPCODE_X0 = 8,
+ V1ADDI_IMM8_OPCODE_X1 = 33,
+ V1ADDUC_RRR_0_OPCODE_X0 = 83,
+ V1ADDUC_RRR_0_OPCODE_X1 = 54,
+ V1ADD_RRR_0_OPCODE_X0 = 84,
+ V1ADD_RRR_0_OPCODE_X1 = 55,
+ V1ADIFFU_RRR_0_OPCODE_X0 = 85,
+ V1AVGU_RRR_0_OPCODE_X0 = 86,
+ V1CMPEQI_IMM8_OPCODE_X0 = 9,
+ V1CMPEQI_IMM8_OPCODE_X1 = 34,
+ V1CMPEQ_RRR_0_OPCODE_X0 = 87,
+ V1CMPEQ_RRR_0_OPCODE_X1 = 56,
+ V1CMPLES_RRR_0_OPCODE_X0 = 88,
+ V1CMPLES_RRR_0_OPCODE_X1 = 57,
+ V1CMPLEU_RRR_0_OPCODE_X0 = 89,
+ V1CMPLEU_RRR_0_OPCODE_X1 = 58,
+ V1CMPLTSI_IMM8_OPCODE_X0 = 10,
+ V1CMPLTSI_IMM8_OPCODE_X1 = 35,
+ V1CMPLTS_RRR_0_OPCODE_X0 = 90,
+ V1CMPLTS_RRR_0_OPCODE_X1 = 59,
+ V1CMPLTUI_IMM8_OPCODE_X0 = 11,
+ V1CMPLTUI_IMM8_OPCODE_X1 = 36,
+ V1CMPLTU_RRR_0_OPCODE_X0 = 91,
+ V1CMPLTU_RRR_0_OPCODE_X1 = 60,
+ V1CMPNE_RRR_0_OPCODE_X0 = 92,
+ V1CMPNE_RRR_0_OPCODE_X1 = 61,
+ V1DDOTPUA_RRR_0_OPCODE_X0 = 161,
+ V1DDOTPUSA_RRR_0_OPCODE_X0 = 93,
+ V1DDOTPUS_RRR_0_OPCODE_X0 = 94,
+ V1DDOTPU_RRR_0_OPCODE_X0 = 162,
+ V1DOTPA_RRR_0_OPCODE_X0 = 95,
+ V1DOTPUA_RRR_0_OPCODE_X0 = 163,
+ V1DOTPUSA_RRR_0_OPCODE_X0 = 96,
+ V1DOTPUS_RRR_0_OPCODE_X0 = 97,
+ V1DOTPU_RRR_0_OPCODE_X0 = 164,
+ V1DOTP_RRR_0_OPCODE_X0 = 98,
+ V1INT_H_RRR_0_OPCODE_X0 = 99,
+ V1INT_H_RRR_0_OPCODE_X1 = 62,
+ V1INT_L_RRR_0_OPCODE_X0 = 100,
+ V1INT_L_RRR_0_OPCODE_X1 = 63,
+ V1MAXUI_IMM8_OPCODE_X0 = 12,
+ V1MAXUI_IMM8_OPCODE_X1 = 37,
+ V1MAXU_RRR_0_OPCODE_X0 = 101,
+ V1MAXU_RRR_0_OPCODE_X1 = 64,
+ V1MINUI_IMM8_OPCODE_X0 = 13,
+ V1MINUI_IMM8_OPCODE_X1 = 38,
+ V1MINU_RRR_0_OPCODE_X0 = 102,
+ V1MINU_RRR_0_OPCODE_X1 = 65,
+ V1MNZ_RRR_0_OPCODE_X0 = 103,
+ V1MNZ_RRR_0_OPCODE_X1 = 66,
+ V1MULTU_RRR_0_OPCODE_X0 = 104,
+ V1MULUS_RRR_0_OPCODE_X0 = 105,
+ V1MULU_RRR_0_OPCODE_X0 = 106,
+ V1MZ_RRR_0_OPCODE_X0 = 107,
+ V1MZ_RRR_0_OPCODE_X1 = 67,
+ V1SADAU_RRR_0_OPCODE_X0 = 108,
+ V1SADU_RRR_0_OPCODE_X0 = 109,
+ V1SHLI_SHIFT_OPCODE_X0 = 7,
+ V1SHLI_SHIFT_OPCODE_X1 = 7,
+ V1SHL_RRR_0_OPCODE_X0 = 110,
+ V1SHL_RRR_0_OPCODE_X1 = 68,
+ V1SHRSI_SHIFT_OPCODE_X0 = 8,
+ V1SHRSI_SHIFT_OPCODE_X1 = 8,
+ V1SHRS_RRR_0_OPCODE_X0 = 111,
+ V1SHRS_RRR_0_OPCODE_X1 = 69,
+ V1SHRUI_SHIFT_OPCODE_X0 = 9,
+ V1SHRUI_SHIFT_OPCODE_X1 = 9,
+ V1SHRU_RRR_0_OPCODE_X0 = 112,
+ V1SHRU_RRR_0_OPCODE_X1 = 70,
+ V1SUBUC_RRR_0_OPCODE_X0 = 113,
+ V1SUBUC_RRR_0_OPCODE_X1 = 71,
+ V1SUB_RRR_0_OPCODE_X0 = 114,
+ V1SUB_RRR_0_OPCODE_X1 = 72,
+ V2ADDI_IMM8_OPCODE_X0 = 14,
+ V2ADDI_IMM8_OPCODE_X1 = 39,
+ V2ADDSC_RRR_0_OPCODE_X0 = 115,
+ V2ADDSC_RRR_0_OPCODE_X1 = 73,
+ V2ADD_RRR_0_OPCODE_X0 = 116,
+ V2ADD_RRR_0_OPCODE_X1 = 74,
+ V2ADIFFS_RRR_0_OPCODE_X0 = 117,
+ V2AVGS_RRR_0_OPCODE_X0 = 118,
+ V2CMPEQI_IMM8_OPCODE_X0 = 15,
+ V2CMPEQI_IMM8_OPCODE_X1 = 40,
+ V2CMPEQ_RRR_0_OPCODE_X0 = 119,
+ V2CMPEQ_RRR_0_OPCODE_X1 = 75,
+ V2CMPLES_RRR_0_OPCODE_X0 = 120,
+ V2CMPLES_RRR_0_OPCODE_X1 = 76,
+ V2CMPLEU_RRR_0_OPCODE_X0 = 121,
+ V2CMPLEU_RRR_0_OPCODE_X1 = 77,
+ V2CMPLTSI_IMM8_OPCODE_X0 = 16,
+ V2CMPLTSI_IMM8_OPCODE_X1 = 41,
+ V2CMPLTS_RRR_0_OPCODE_X0 = 122,
+ V2CMPLTS_RRR_0_OPCODE_X1 = 78,
+ V2CMPLTUI_IMM8_OPCODE_X0 = 17,
+ V2CMPLTUI_IMM8_OPCODE_X1 = 42,
+ V2CMPLTU_RRR_0_OPCODE_X0 = 123,
+ V2CMPLTU_RRR_0_OPCODE_X1 = 79,
+ V2CMPNE_RRR_0_OPCODE_X0 = 124,
+ V2CMPNE_RRR_0_OPCODE_X1 = 80,
+ V2DOTPA_RRR_0_OPCODE_X0 = 125,
+ V2DOTP_RRR_0_OPCODE_X0 = 126,
+ V2INT_H_RRR_0_OPCODE_X0 = 127,
+ V2INT_H_RRR_0_OPCODE_X1 = 81,
+ V2INT_L_RRR_0_OPCODE_X0 = 128,
+ V2INT_L_RRR_0_OPCODE_X1 = 82,
+ V2MAXSI_IMM8_OPCODE_X0 = 18,
+ V2MAXSI_IMM8_OPCODE_X1 = 43,
+ V2MAXS_RRR_0_OPCODE_X0 = 129,
+ V2MAXS_RRR_0_OPCODE_X1 = 83,
+ V2MINSI_IMM8_OPCODE_X0 = 19,
+ V2MINSI_IMM8_OPCODE_X1 = 44,
+ V2MINS_RRR_0_OPCODE_X0 = 130,
+ V2MINS_RRR_0_OPCODE_X1 = 84,
+ V2MNZ_RRR_0_OPCODE_X0 = 131,
+ V2MNZ_RRR_0_OPCODE_X1 = 85,
+ V2MULFSC_RRR_0_OPCODE_X0 = 132,
+ V2MULS_RRR_0_OPCODE_X0 = 133,
+ V2MULTS_RRR_0_OPCODE_X0 = 134,
+ V2MZ_RRR_0_OPCODE_X0 = 135,
+ V2MZ_RRR_0_OPCODE_X1 = 86,
+ V2PACKH_RRR_0_OPCODE_X0 = 136,
+ V2PACKH_RRR_0_OPCODE_X1 = 87,
+ V2PACKL_RRR_0_OPCODE_X0 = 137,
+ V2PACKL_RRR_0_OPCODE_X1 = 88,
+ V2PACKUC_RRR_0_OPCODE_X0 = 138,
+ V2PACKUC_RRR_0_OPCODE_X1 = 89,
+ V2SADAS_RRR_0_OPCODE_X0 = 139,
+ V2SADAU_RRR_0_OPCODE_X0 = 140,
+ V2SADS_RRR_0_OPCODE_X0 = 141,
+ V2SADU_RRR_0_OPCODE_X0 = 142,
+ V2SHLI_SHIFT_OPCODE_X0 = 10,
+ V2SHLI_SHIFT_OPCODE_X1 = 10,
+ V2SHLSC_RRR_0_OPCODE_X0 = 143,
+ V2SHLSC_RRR_0_OPCODE_X1 = 90,
+ V2SHL_RRR_0_OPCODE_X0 = 144,
+ V2SHL_RRR_0_OPCODE_X1 = 91,
+ V2SHRSI_SHIFT_OPCODE_X0 = 11,
+ V2SHRSI_SHIFT_OPCODE_X1 = 11,
+ V2SHRS_RRR_0_OPCODE_X0 = 145,
+ V2SHRS_RRR_0_OPCODE_X1 = 92,
+ V2SHRUI_SHIFT_OPCODE_X0 = 12,
+ V2SHRUI_SHIFT_OPCODE_X1 = 12,
+ V2SHRU_RRR_0_OPCODE_X0 = 146,
+ V2SHRU_RRR_0_OPCODE_X1 = 93,
+ V2SUBSC_RRR_0_OPCODE_X0 = 147,
+ V2SUBSC_RRR_0_OPCODE_X1 = 94,
+ V2SUB_RRR_0_OPCODE_X0 = 148,
+ V2SUB_RRR_0_OPCODE_X1 = 95,
+ V4ADDSC_RRR_0_OPCODE_X0 = 149,
+ V4ADDSC_RRR_0_OPCODE_X1 = 96,
+ V4ADD_RRR_0_OPCODE_X0 = 150,
+ V4ADD_RRR_0_OPCODE_X1 = 97,
+ V4INT_H_RRR_0_OPCODE_X0 = 151,
+ V4INT_H_RRR_0_OPCODE_X1 = 98,
+ V4INT_L_RRR_0_OPCODE_X0 = 152,
+ V4INT_L_RRR_0_OPCODE_X1 = 99,
+ V4PACKSC_RRR_0_OPCODE_X0 = 153,
+ V4PACKSC_RRR_0_OPCODE_X1 = 100,
+ V4SHLSC_RRR_0_OPCODE_X0 = 154,
+ V4SHLSC_RRR_0_OPCODE_X1 = 101,
+ V4SHL_RRR_0_OPCODE_X0 = 155,
+ V4SHL_RRR_0_OPCODE_X1 = 102,
+ V4SHRS_RRR_0_OPCODE_X0 = 156,
+ V4SHRS_RRR_0_OPCODE_X1 = 103,
+ V4SHRU_RRR_0_OPCODE_X0 = 157,
+ V4SHRU_RRR_0_OPCODE_X1 = 104,
+ V4SUBSC_RRR_0_OPCODE_X0 = 158,
+ V4SUBSC_RRR_0_OPCODE_X1 = 105,
+ V4SUB_RRR_0_OPCODE_X0 = 159,
+ V4SUB_RRR_0_OPCODE_X1 = 106,
+ WH64_UNARY_OPCODE_X1 = 38,
+ XORI_IMM8_OPCODE_X0 = 20,
+ XORI_IMM8_OPCODE_X1 = 45,
+ XOR_RRR_0_OPCODE_X0 = 160,
+ XOR_RRR_0_OPCODE_X1 = 107,
+ XOR_RRR_5_OPCODE_Y0 = 3,
+ XOR_RRR_5_OPCODE_Y1 = 3
};
#endif /* !_TILE_OPCODE_CONSTANTS_H */
diff --git a/arch/tile/include/asm/page.h b/arch/tile/include/asm/page.h
index 3eb53525bf9d..db93518fac03 100644
--- a/arch/tile/include/asm/page.h
+++ b/arch/tile/include/asm/page.h
@@ -16,7 +16,8 @@
#define _ASM_TILE_PAGE_H
#include <linux/const.h>
-#include <hv/pagesize.h>
+#include <hv/hypervisor.h>
+#include <arch/chip.h>
/* PAGE_SHIFT and HPAGE_SHIFT determine the page sizes. */
#define PAGE_SHIFT HV_LOG2_PAGE_SIZE_SMALL
@@ -28,8 +29,6 @@
#define PAGE_MASK (~(PAGE_SIZE - 1))
#define HPAGE_MASK (~(HPAGE_SIZE - 1))
-#ifdef __KERNEL__
-
/*
* If the Kconfig doesn't specify, set a maximum zone order that
* is enough so that we can create huge pages from small pages given
@@ -39,9 +38,6 @@
#define CONFIG_FORCE_MAX_ZONEORDER (HPAGE_SHIFT - PAGE_SHIFT + 1)
#endif
-#include <hv/hypervisor.h>
-#include <arch/chip.h>
-
#ifndef __ASSEMBLY__
#include <linux/types.h>
@@ -91,6 +87,10 @@ typedef struct page *pgtable_t;
/* Must be a macro since it is used to create constants. */
#define __pgprot(val) hv_pte(val)
+/* Rarely-used initializers, typically with a "zero" value. */
+#define __pte(x) hv_pte(x)
+#define __pgd(x) hv_pte(x)
+
static inline u64 pgprot_val(pgprot_t pgprot)
{
return hv_pte_val(pgprot);
@@ -110,6 +110,8 @@ static inline u64 pgd_val(pgd_t pgd)
typedef HV_PTE pmd_t;
+#define __pmd(x) hv_pte(x)
+
static inline u64 pmd_val(pmd_t pmd)
{
return hv_pte_val(pmd);
@@ -318,7 +320,7 @@ static inline int pfn_valid(unsigned long pfn)
/* Provide as macros since these require some other headers included. */
#define page_to_pa(page) ((phys_addr_t)(page_to_pfn(page)) << PAGE_SHIFT)
-#define virt_to_page(kaddr) pfn_to_page(kaddr_to_pfn(kaddr))
+#define virt_to_page(kaddr) pfn_to_page(kaddr_to_pfn((void *)(kaddr)))
#define page_to_virt(page) pfn_to_kaddr(page_to_pfn(page))
struct mm_struct;
@@ -331,6 +333,4 @@ extern pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr);
#include <asm-generic/memory_model.h>
-#endif /* __KERNEL__ */
-
#endif /* _ASM_TILE_PAGE_H */
diff --git a/arch/tile/include/asm/parport.h b/arch/tile/include/asm/parport.h
new file mode 100644
index 000000000000..cf252af64590
--- /dev/null
+++ b/arch/tile/include/asm/parport.h
@@ -0,0 +1 @@
+#include <asm-generic/parport.h>
diff --git a/arch/tile/include/asm/pci.h b/arch/tile/include/asm/pci.h
index c3fc458a0d32..7f03cefed1b9 100644
--- a/arch/tile/include/asm/pci.h
+++ b/arch/tile/include/asm/pci.h
@@ -46,7 +46,8 @@ struct pci_controller {
*/
#define PCI_DMA_BUS_IS_PHYS 1
-int __init tile_pci_init(void);
+int __devinit tile_pci_init(void);
+int __devinit pcibios_init(void);
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
static inline void pci_iounmap(struct pci_dev *dev, void __iomem *addr) {}
diff --git a/arch/tile/include/asm/pgtable_64.h b/arch/tile/include/asm/pgtable_64.h
new file mode 100644
index 000000000000..fd80328523b4
--- /dev/null
+++ b/arch/tile/include/asm/pgtable_64.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in 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.
+ *
+ */
+
+#ifndef _ASM_TILE_PGTABLE_64_H
+#define _ASM_TILE_PGTABLE_64_H
+
+/* The level-0 page table breaks the address space into 32-bit chunks. */
+#define PGDIR_SHIFT HV_LOG2_L1_SPAN
+#define PGDIR_SIZE HV_L1_SPAN
+#define PGDIR_MASK (~(PGDIR_SIZE-1))
+#define PTRS_PER_PGD HV_L0_ENTRIES
+#define SIZEOF_PGD (PTRS_PER_PGD * sizeof(pgd_t))
+
+/*
+ * The level-1 index is defined by the huge page size. A PMD is composed
+ * of PTRS_PER_PMD pgd_t's and is the middle level of the page table.
+ */
+#define PMD_SHIFT HV_LOG2_PAGE_SIZE_LARGE
+#define PMD_SIZE HV_PAGE_SIZE_LARGE
+#define PMD_MASK (~(PMD_SIZE-1))
+#define PTRS_PER_PMD (1 << (PGDIR_SHIFT - PMD_SHIFT))
+#define SIZEOF_PMD (PTRS_PER_PMD * sizeof(pmd_t))
+
+/*
+ * The level-2 index is defined by the difference between the huge
+ * page size and the normal page size. A PTE is composed of
+ * PTRS_PER_PTE pte_t's and is the bottom level of the page table.
+ * Note that the hypervisor docs use PTE for what we call pte_t, so
+ * this nomenclature is somewhat confusing.
+ */
+#define PTRS_PER_PTE (1 << (HV_LOG2_PAGE_SIZE_LARGE - HV_LOG2_PAGE_SIZE_SMALL))
+#define SIZEOF_PTE (PTRS_PER_PTE * sizeof(pte_t))
+
+/*
+ * Align the vmalloc area to an L2 page table, and leave a guard page
+ * at the beginning and end. The vmalloc code also puts in an internal
+ * guard page between each allocation.
+ */
+#define _VMALLOC_END HUGE_VMAP_BASE
+#define VMALLOC_END (_VMALLOC_END - PAGE_SIZE)
+#define VMALLOC_START (_VMALLOC_START + PAGE_SIZE)
+
+#define HUGE_VMAP_END (HUGE_VMAP_BASE + PGDIR_SIZE)
+
+#ifndef __ASSEMBLY__
+
+/* We have no pud since we are a three-level page table. */
+#include <asm-generic/pgtable-nopud.h>
+
+static inline int pud_none(pud_t pud)
+{
+ return pud_val(pud) == 0;
+}
+
+static inline int pud_present(pud_t pud)
+{
+ return pud_val(pud) & _PAGE_PRESENT;
+}
+
+#define pmd_ERROR(e) \
+ pr_err("%s:%d: bad pmd 0x%016llx.\n", __FILE__, __LINE__, pmd_val(e))
+
+static inline void pud_clear(pud_t *pudp)
+{
+ __pte_clear(&pudp->pgd);
+}
+
+static inline int pud_bad(pud_t pud)
+{
+ return ((pud_val(pud) & _PAGE_ALL) != _PAGE_TABLE);
+}
+
+/* Return the page-table frame number (ptfn) that a pud_t points at. */
+#define pud_ptfn(pud) hv_pte_get_ptfn((pud).pgd)
+
+/*
+ * A given kernel pud_t maps to a kernel pmd_t table at a specific
+ * virtual address. Since kernel pmd_t tables can be aligned at
+ * sub-page granularity, this macro can return non-page-aligned
+ * pointers, despite its name.
+ */
+#define pud_page_vaddr(pud) \
+ (__va((phys_addr_t)pud_ptfn(pud) << HV_LOG2_PAGE_TABLE_ALIGN))
+
+/*
+ * A pud_t points to a pmd_t array. Since we can have multiple per
+ * page, we don't have a one-to-one mapping of pud_t's to pages.
+ */
+#define pud_page(pud) pfn_to_page(HV_PTFN_TO_PFN(pud_ptfn(pud)))
+
+static inline unsigned long pud_index(unsigned long address)
+{
+ return (address >> PUD_SHIFT) & (PTRS_PER_PUD - 1);
+}
+
+#define pmd_offset(pud, address) \
+ ((pmd_t *)pud_page_vaddr(*(pud)) + pmd_index(address))
+
+static inline void __set_pmd(pmd_t *pmdp, pmd_t pmdval)
+{
+ set_pte(pmdp, pmdval);
+}
+
+/* Create a pmd from a PTFN and pgprot. */
+static inline pmd_t ptfn_pmd(unsigned long ptfn, pgprot_t prot)
+{
+ return hv_pte_set_ptfn(prot, ptfn);
+}
+
+/* Return the page-table frame number (ptfn) that a pmd_t points at. */
+static inline unsigned long pmd_ptfn(pmd_t pmd)
+{
+ return hv_pte_get_ptfn(pmd);
+}
+
+static inline void pmd_clear(pmd_t *pmdp)
+{
+ __pte_clear(pmdp);
+}
+
+/* Normalize an address to having the correct high bits set. */
+#define pgd_addr_normalize pgd_addr_normalize
+static inline unsigned long pgd_addr_normalize(unsigned long addr)
+{
+ return ((long)addr << (CHIP_WORD_SIZE() - CHIP_VA_WIDTH())) >>
+ (CHIP_WORD_SIZE() - CHIP_VA_WIDTH());
+}
+
+/* We don't define any pgds for these addresses. */
+static inline int pgd_addr_invalid(unsigned long addr)
+{
+ return addr >= MEM_HV_START ||
+ (addr > MEM_LOW_END && addr < MEM_HIGH_START);
+}
+
+/*
+ * Use atomic instructions to provide atomicity against the hypervisor.
+ */
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
+static inline int ptep_test_and_clear_young(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep)
+{
+ return (__insn_fetchand(&ptep->val, ~HV_PTE_ACCESSED) >>
+ HV_PTE_INDEX_ACCESSED) & 0x1;
+}
+
+#define __HAVE_ARCH_PTEP_SET_WRPROTECT
+static inline void ptep_set_wrprotect(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ __insn_fetchand(&ptep->val, ~HV_PTE_WRITABLE);
+}
+
+#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
+static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ return hv_pte(__insn_exch(&ptep->val, 0UL));
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_TILE_PGTABLE_64_H */
diff --git a/arch/tile/include/asm/processor.h b/arch/tile/include/asm/processor.h
index e6889474038a..34c1e01ffb5e 100644
--- a/arch/tile/include/asm/processor.h
+++ b/arch/tile/include/asm/processor.h
@@ -215,6 +215,8 @@ static inline void release_thread(struct task_struct *dead_task)
extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
+extern int do_work_pending(struct pt_regs *regs, u32 flags);
+
/*
* Return saved (kernel) PC of a blocked thread.
@@ -255,10 +257,6 @@ static inline void cpu_relax(void)
barrier();
}
-struct siginfo;
-extern void arch_coredump_signal(struct siginfo *, struct pt_regs *);
-#define arch_coredump_signal arch_coredump_signal
-
/* Info on this processor (see fs/proc/cpuinfo.c) */
struct seq_operations;
extern const struct seq_operations cpuinfo_op;
@@ -269,9 +267,6 @@ extern char chip_model[64];
/* Data on which physical memory controller corresponds to which NUMA node. */
extern int node_controller[];
-/* Do we dump information to the console when a user application crashes? */
-extern int show_crashinfo;
-
#if CHIP_HAS_CBOX_HOME_MAP()
/* Does the heap allocator return hash-for-home pages by default? */
extern int hash_default;
diff --git a/arch/tile/include/asm/serial.h b/arch/tile/include/asm/serial.h
new file mode 100644
index 000000000000..a0cb0caff152
--- /dev/null
+++ b/arch/tile/include/asm/serial.h
@@ -0,0 +1 @@
+#include <asm-generic/serial.h>
diff --git a/arch/tile/include/asm/signal.h b/arch/tile/include/asm/signal.h
index 81d92a45cd4b..1e1e616783eb 100644
--- a/arch/tile/include/asm/signal.h
+++ b/arch/tile/include/asm/signal.h
@@ -28,6 +28,10 @@ struct pt_regs;
int restore_sigcontext(struct pt_regs *, struct sigcontext __user *);
int setup_sigcontext(struct sigcontext __user *, struct pt_regs *);
void do_signal(struct pt_regs *regs);
+void signal_fault(const char *type, struct pt_regs *,
+ void __user *frame, int sig);
+void trace_unhandled_signal(const char *type, struct pt_regs *regs,
+ unsigned long address, int signo);
#endif
#endif /* _ASM_TILE_SIGNAL_H */
diff --git a/arch/tile/include/asm/spinlock_64.h b/arch/tile/include/asm/spinlock_64.h
new file mode 100644
index 000000000000..72be5904e020
--- /dev/null
+++ b/arch/tile/include/asm/spinlock_64.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in 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.
+ *
+ * 64-bit SMP ticket spinlocks, allowing only a single CPU anywhere
+ * (the type definitions are in asm/spinlock_types.h)
+ */
+
+#ifndef _ASM_TILE_SPINLOCK_64_H
+#define _ASM_TILE_SPINLOCK_64_H
+
+/* Shifts and masks for the various fields in "lock". */
+#define __ARCH_SPIN_CURRENT_SHIFT 17
+#define __ARCH_SPIN_NEXT_MASK 0x7fff
+#define __ARCH_SPIN_NEXT_OVERFLOW 0x8000
+
+/*
+ * Return the "current" portion of a ticket lock value,
+ * i.e. the number that currently owns the lock.
+ */
+static inline int arch_spin_current(u32 val)
+{
+ return val >> __ARCH_SPIN_CURRENT_SHIFT;
+}
+
+/*
+ * Return the "next" portion of a ticket lock value,
+ * i.e. the number that the next task to try to acquire the lock will get.
+ */
+static inline int arch_spin_next(u32 val)
+{
+ return val & __ARCH_SPIN_NEXT_MASK;
+}
+
+/* The lock is locked if a task would have to wait to get it. */
+static inline int arch_spin_is_locked(arch_spinlock_t *lock)
+{
+ u32 val = lock->lock;
+ return arch_spin_current(val) != arch_spin_next(val);
+}
+
+/* Bump the current ticket so the next task owns the lock. */
+static inline void arch_spin_unlock(arch_spinlock_t *lock)
+{
+ wmb(); /* guarantee anything modified under the lock is visible */
+ __insn_fetchadd4(&lock->lock, 1U << __ARCH_SPIN_CURRENT_SHIFT);
+}
+
+void arch_spin_unlock_wait(arch_spinlock_t *lock);
+
+void arch_spin_lock_slow(arch_spinlock_t *lock, u32 val);
+
+/* Grab the "next" ticket number and bump it atomically.
+ * If the current ticket is not ours, go to the slow path.
+ * We also take the slow path if the "next" value overflows.
+ */
+static inline void arch_spin_lock(arch_spinlock_t *lock)
+{
+ u32 val = __insn_fetchadd4(&lock->lock, 1);
+ u32 ticket = val & (__ARCH_SPIN_NEXT_MASK | __ARCH_SPIN_NEXT_OVERFLOW);
+ if (unlikely(arch_spin_current(val) != ticket))
+ arch_spin_lock_slow(lock, ticket);
+}
+
+/* Try to get the lock, and return whether we succeeded. */
+int arch_spin_trylock(arch_spinlock_t *lock);
+
+/* We cannot take an interrupt after getting a ticket, so don't enable them. */
+#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
+
+/*
+ * Read-write spinlocks, allowing multiple readers
+ * but only one writer.
+ *
+ * We use fetchadd() for readers, and fetchor() with the sign bit
+ * for writers.
+ */
+
+#define __WRITE_LOCK_BIT (1 << 31)
+
+static inline int arch_write_val_locked(int val)
+{
+ return val < 0; /* Optimize "val & __WRITE_LOCK_BIT". */
+}
+
+/**
+ * read_can_lock - would read_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+static inline int arch_read_can_lock(arch_rwlock_t *rw)
+{
+ return !arch_write_val_locked(rw->lock);
+}
+
+/**
+ * write_can_lock - would write_trylock() succeed?
+ * @lock: the rwlock in question.
+ */
+static inline int arch_write_can_lock(arch_rwlock_t *rw)
+{
+ return rw->lock == 0;
+}
+
+extern void __read_lock_failed(arch_rwlock_t *rw);
+
+static inline void arch_read_lock(arch_rwlock_t *rw)
+{
+ u32 val = __insn_fetchaddgez4(&rw->lock, 1);
+ if (unlikely(arch_write_val_locked(val)))
+ __read_lock_failed(rw);
+}
+
+extern void __write_lock_failed(arch_rwlock_t *rw, u32 val);
+
+static inline void arch_write_lock(arch_rwlock_t *rw)
+{
+ u32 val = __insn_fetchor4(&rw->lock, __WRITE_LOCK_BIT);
+ if (unlikely(val != 0))
+ __write_lock_failed(rw, val);
+}
+
+static inline void arch_read_unlock(arch_rwlock_t *rw)
+{
+ __insn_mf();
+ __insn_fetchadd4(&rw->lock, -1);
+}
+
+static inline void arch_write_unlock(arch_rwlock_t *rw)
+{
+ __insn_mf();
+ rw->lock = 0;
+}
+
+static inline int arch_read_trylock(arch_rwlock_t *rw)
+{
+ return !arch_write_val_locked(__insn_fetchaddgez4(&rw->lock, 1));
+}
+
+static inline int arch_write_trylock(arch_rwlock_t *rw)
+{
+ u32 val = __insn_fetchor4(&rw->lock, __WRITE_LOCK_BIT);
+ if (likely(val == 0))
+ return 1;
+ if (!arch_write_val_locked(val))
+ __insn_fetchand4(&rw->lock, ~__WRITE_LOCK_BIT);
+ return 0;
+}
+
+#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
+#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
+
+#endif /* _ASM_TILE_SPINLOCK_64_H */
diff --git a/arch/tile/include/asm/stat.h b/arch/tile/include/asm/stat.h
index b16e5db8f0e7..c0db34d56be3 100644
--- a/arch/tile/include/asm/stat.h
+++ b/arch/tile/include/asm/stat.h
@@ -1,4 +1,4 @@
-#ifdef CONFIG_COMPAT
+#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
#define __ARCH_WANT_STAT64 /* Used for compat_sys_stat64() etc. */
#endif
#include <asm-generic/stat.h>
diff --git a/arch/tile/include/asm/swab.h b/arch/tile/include/asm/swab.h
index 25c686a00f1d..7c37b38f6c8d 100644
--- a/arch/tile/include/asm/swab.h
+++ b/arch/tile/include/asm/swab.h
@@ -18,12 +18,6 @@
/* Tile gcc is always >= 4.3.0, so we use __builtin_bswap. */
#define __arch_swab32(x) __builtin_bswap32(x)
#define __arch_swab64(x) __builtin_bswap64(x)
-
-/* Use the variant that is natural for the wordsize. */
-#ifdef CONFIG_64BIT
-#define __arch_swab16(x) (__builtin_bswap64(x) >> 48)
-#else
#define __arch_swab16(x) (__builtin_bswap32(x) >> 16)
-#endif
#endif /* _ASM_TILE_SWAB_H */
diff --git a/arch/tile/include/asm/thread_info.h b/arch/tile/include/asm/thread_info.h
index 3405b52853b8..bc4f562bd459 100644
--- a/arch/tile/include/asm/thread_info.h
+++ b/arch/tile/include/asm/thread_info.h
@@ -125,6 +125,7 @@ extern void cpu_idle_on_new_stack(struct thread_info *old_ti,
#define TIF_SYSCALL_AUDIT 5 /* syscall auditing active */
#define TIF_SECCOMP 6 /* secure computing */
#define TIF_MEMDIE 7 /* OOM killer at work */
+#define TIF_NOTIFY_RESUME 8 /* callback before returning to user */
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
@@ -134,10 +135,12 @@ extern void cpu_idle_on_new_stack(struct thread_info *old_ti,
#define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT)
#define _TIF_SECCOMP (1<<TIF_SECCOMP)
#define _TIF_MEMDIE (1<<TIF_MEMDIE)
+#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
/* Work to do on any return to user space. */
#define _TIF_ALLWORK_MASK \
- (_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_SINGLESTEP|_TIF_ASYNC_TLB)
+ (_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_SINGLESTEP|\
+ _TIF_ASYNC_TLB|_TIF_NOTIFY_RESUME)
/*
* Thread-synchronous status.
diff --git a/arch/tile/include/asm/topology.h b/arch/tile/include/asm/topology.h
index 343172d422a9..6fdd0c860193 100644
--- a/arch/tile/include/asm/topology.h
+++ b/arch/tile/include/asm/topology.h
@@ -44,25 +44,64 @@ static inline const struct cpumask *cpumask_of_node(int node)
/* For now, use numa node -1 for global allocation. */
#define pcibus_to_node(bus) ((void)(bus), -1)
+/*
+ * TILE architecture has many cores integrated in one processor, so we need
+ * setup bigger balance_interval for both CPU/NODE scheduling domains to
+ * reduce process scheduling costs.
+ */
+
+/* sched_domains SD_CPU_INIT for TILE architecture */
+#define SD_CPU_INIT (struct sched_domain) { \
+ .min_interval = 4, \
+ .max_interval = 128, \
+ .busy_factor = 64, \
+ .imbalance_pct = 125, \
+ .cache_nice_tries = 1, \
+ .busy_idx = 2, \
+ .idle_idx = 1, \
+ .newidle_idx = 0, \
+ .wake_idx = 0, \
+ .forkexec_idx = 0, \
+ \
+ .flags = 1*SD_LOAD_BALANCE \
+ | 1*SD_BALANCE_NEWIDLE \
+ | 1*SD_BALANCE_EXEC \
+ | 1*SD_BALANCE_FORK \
+ | 0*SD_BALANCE_WAKE \
+ | 0*SD_WAKE_AFFINE \
+ | 0*SD_PREFER_LOCAL \
+ | 0*SD_SHARE_CPUPOWER \
+ | 0*SD_SHARE_PKG_RESOURCES \
+ | 0*SD_SERIALIZE \
+ , \
+ .last_balance = jiffies, \
+ .balance_interval = 32, \
+}
+
/* sched_domains SD_NODE_INIT for TILE architecture */
-#define SD_NODE_INIT (struct sched_domain) { \
- .min_interval = 8, \
- .max_interval = 32, \
- .busy_factor = 32, \
- .imbalance_pct = 125, \
- .cache_nice_tries = 1, \
- .busy_idx = 3, \
- .idle_idx = 1, \
- .newidle_idx = 2, \
- .wake_idx = 1, \
- .flags = SD_LOAD_BALANCE \
- | SD_BALANCE_NEWIDLE \
- | SD_BALANCE_EXEC \
- | SD_BALANCE_FORK \
- | SD_WAKE_AFFINE \
- | SD_SERIALIZE, \
- .last_balance = jiffies, \
- .balance_interval = 1, \
+#define SD_NODE_INIT (struct sched_domain) { \
+ .min_interval = 16, \
+ .max_interval = 512, \
+ .busy_factor = 32, \
+ .imbalance_pct = 125, \
+ .cache_nice_tries = 1, \
+ .busy_idx = 3, \
+ .idle_idx = 1, \
+ .newidle_idx = 2, \
+ .wake_idx = 1, \
+ .flags = 1*SD_LOAD_BALANCE \
+ | 1*SD_BALANCE_NEWIDLE \
+ | 1*SD_BALANCE_EXEC \
+ | 1*SD_BALANCE_FORK \
+ | 0*SD_BALANCE_WAKE \
+ | 0*SD_WAKE_AFFINE \
+ | 0*SD_PREFER_LOCAL \
+ | 0*SD_SHARE_CPUPOWER \
+ | 0*SD_SHARE_PKG_RESOURCES \
+ | 1*SD_SERIALIZE \
+ , \
+ .last_balance = jiffies, \
+ .balance_interval = 128, \
}
/* By definition, we create nodes based on online memory. */
diff --git a/arch/tile/include/asm/traps.h b/arch/tile/include/asm/traps.h
index d06e35f57201..5f20f920f932 100644
--- a/arch/tile/include/asm/traps.h
+++ b/arch/tile/include/asm/traps.h
@@ -15,10 +15,14 @@
#ifndef _ASM_TILE_TRAPS_H
#define _ASM_TILE_TRAPS_H
+#include <arch/chip.h>
+
/* mm/fault.c */
void do_page_fault(struct pt_regs *, int fault_num,
unsigned long address, unsigned long write);
+#if CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC()
void do_async_page_fault(struct pt_regs *);
+#endif
#ifndef __tilegx__
/*
diff --git a/arch/tile/include/asm/unistd.h b/arch/tile/include/asm/unistd.h
index b35c2db71199..f70bf1c541f1 100644
--- a/arch/tile/include/asm/unistd.h
+++ b/arch/tile/include/asm/unistd.h
@@ -15,7 +15,7 @@
#if !defined(_ASM_TILE_UNISTD_H) || defined(__SYSCALL)
#define _ASM_TILE_UNISTD_H
-#ifndef __LP64__
+#if !defined(__LP64__) || defined(__SYSCALL_COMPAT)
/* Use the flavor of this syscall that matches the 32-bit API better. */
#define __ARCH_WANT_SYNC_FILE_RANGE2
#endif
diff --git a/arch/tile/include/hv/pagesize.h b/arch/tile/include/asm/vga.h
index 58bed114fedd..7b46e754d611 100644
--- a/arch/tile/include/hv/pagesize.h
+++ b/arch/tile/include/asm/vga.h
@@ -10,23 +10,30 @@
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for
* more details.
+ *
+ * Access to VGA videoram.
*/
-/**
- * @file pagesize.h
- */
+#ifndef _ASM_TILE_VGA_H
+#define _ASM_TILE_VGA_H
-#ifndef _HV_PAGESIZE_H
-#define _HV_PAGESIZE_H
+#include <asm/io.h>
-/** The log2 of the size of small pages, in bytes. This value should
- * be verified at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_SMALL).
- */
-#define HV_LOG2_PAGE_SIZE_SMALL 16
+#define VT_BUF_HAVE_RW
-/** The log2 of the size of large pages, in bytes. This value should be
- * verified at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_LARGE).
- */
-#define HV_LOG2_PAGE_SIZE_LARGE 24
+static inline void scr_writew(u16 val, volatile u16 *addr)
+{
+ __raw_writew(val, (volatile u16 __iomem *) addr);
+}
+
+static inline u16 scr_readw(volatile const u16 *addr)
+{
+ return __raw_readw((volatile const u16 __iomem *) addr);
+}
+
+#define vga_readb(a) readb((u8 __iomem *)(a))
+#define vga_writeb(v,a) writeb(v, (u8 __iomem *)(a))
+
+#define VGA_MAP_MEM(x,s) ((unsigned long) ioremap(x, s))
-#endif /* _HV_PAGESIZE_H */
+#endif
diff --git a/arch/tile/include/hv/hypervisor.h b/arch/tile/include/hv/hypervisor.h
index ee41bca4c8c4..72ec1e972f15 100644
--- a/arch/tile/include/hv/hypervisor.h
+++ b/arch/tile/include/hv/hypervisor.h
@@ -22,8 +22,6 @@
#include <arch/chip.h>
-#include <hv/pagesize.h>
-
/* Linux builds want unsigned long constants, but assembler wants numbers */
#ifdef __ASSEMBLER__
/** One, for assembler */
@@ -44,11 +42,21 @@
*/
#define HV_L1_SPAN (__HV_SIZE_ONE << HV_LOG2_L1_SPAN)
+/** The log2 of the size of small pages, in bytes. This value should
+ * be verified at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_SMALL).
+ */
+#define HV_LOG2_PAGE_SIZE_SMALL 16
+
/** The size of small pages, in bytes. This value should be verified
* at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_SMALL).
*/
#define HV_PAGE_SIZE_SMALL (__HV_SIZE_ONE << HV_LOG2_PAGE_SIZE_SMALL)
+/** The log2 of the size of large pages, in bytes. This value should be
+ * verified at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_LARGE).
+ */
+#define HV_LOG2_PAGE_SIZE_LARGE 24
+
/** The size of large pages, in bytes. This value should be verified
* at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_LARGE).
*/
diff --git a/arch/tile/kernel/backtrace.c b/arch/tile/kernel/backtrace.c
index 55a6a74974b4..1dc71eabfc5a 100644
--- a/arch/tile/kernel/backtrace.c
+++ b/arch/tile/kernel/backtrace.c
@@ -14,19 +14,11 @@
#include <linux/kernel.h>
#include <linux/string.h>
-
#include <asm/backtrace.h>
-
-#include <arch/chip.h>
-
#include <asm/opcode-tile.h>
+#include <arch/abi.h>
-
-#define TREG_SP 54
-#define TREG_LR 55
-
-
-#if TILE_CHIP >= 10
+#ifdef __tilegx__
#define tile_bundle_bits tilegx_bundle_bits
#define TILE_MAX_INSTRUCTIONS_PER_BUNDLE TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE
#define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEGX_BUNDLE_ALIGNMENT_IN_BYTES
@@ -47,7 +39,7 @@ typedef long long bt_int_reg_t;
typedef int bt_int_reg_t;
#endif
-/** A decoded bundle used for backtracer analysis. */
+/* A decoded bundle used for backtracer analysis. */
struct BacktraceBundle {
tile_bundle_bits bits;
int num_insns;
@@ -56,23 +48,7 @@ struct BacktraceBundle {
};
-/* This implementation only makes sense for native tools. */
-/** Default function to read memory. */
-static bool bt_read_memory(void *result, VirtualAddress addr,
- unsigned int size, void *extra)
-{
- /* FIXME: this should do some horrible signal stuff to catch
- * SEGV cleanly and fail.
- *
- * Or else the caller should do the setjmp for efficiency.
- */
-
- memcpy(result, (const void *)addr, size);
- return true;
-}
-
-
-/** Locates an instruction inside the given bundle that
+/* Locates an instruction inside the given bundle that
* has the specified mnemonic, and whose first 'num_operands_to_match'
* operands exactly match those in 'operand_values'.
*/
@@ -107,13 +83,13 @@ static const struct tile_decoded_instruction *find_matching_insn(
return NULL;
}
-/** Does this bundle contain an 'iret' instruction? */
+/* Does this bundle contain an 'iret' instruction? */
static inline bool bt_has_iret(const struct BacktraceBundle *bundle)
{
return find_matching_insn(bundle, TILE_OPC_IRET, NULL, 0) != NULL;
}
-/** Does this bundle contain an 'addi sp, sp, OFFSET' or
+/* Does this bundle contain an 'addi sp, sp, OFFSET' or
* 'addli sp, sp, OFFSET' instruction, and if so, what is OFFSET?
*/
static bool bt_has_addi_sp(const struct BacktraceBundle *bundle, int *adjust)
@@ -124,7 +100,7 @@ static bool bt_has_addi_sp(const struct BacktraceBundle *bundle, int *adjust)
find_matching_insn(bundle, TILE_OPC_ADDI, vals, 2);
if (insn == NULL)
insn = find_matching_insn(bundle, TILE_OPC_ADDLI, vals, 2);
-#if TILE_CHIP >= 10
+#ifdef __tilegx__
if (insn == NULL)
insn = find_matching_insn(bundle, TILEGX_OPC_ADDXLI, vals, 2);
if (insn == NULL)
@@ -137,7 +113,7 @@ static bool bt_has_addi_sp(const struct BacktraceBundle *bundle, int *adjust)
return true;
}
-/** Does this bundle contain any 'info OP' or 'infol OP'
+/* Does this bundle contain any 'info OP' or 'infol OP'
* instruction, and if so, what are their OP? Note that OP is interpreted
* as an unsigned value by this code since that's what the caller wants.
* Returns the number of info ops found.
@@ -161,7 +137,7 @@ static int bt_get_info_ops(const struct BacktraceBundle *bundle,
return num_ops;
}
-/** Does this bundle contain a jrp instruction, and if so, to which
+/* Does this bundle contain a jrp instruction, and if so, to which
* register is it jumping?
*/
static bool bt_has_jrp(const struct BacktraceBundle *bundle, int *target_reg)
@@ -175,7 +151,7 @@ static bool bt_has_jrp(const struct BacktraceBundle *bundle, int *target_reg)
return true;
}
-/** Does this bundle modify the specified register in any way? */
+/* Does this bundle modify the specified register in any way? */
static bool bt_modifies_reg(const struct BacktraceBundle *bundle, int reg)
{
int i, j;
@@ -195,34 +171,34 @@ static bool bt_modifies_reg(const struct BacktraceBundle *bundle, int reg)
return false;
}
-/** Does this bundle modify sp? */
+/* Does this bundle modify sp? */
static inline bool bt_modifies_sp(const struct BacktraceBundle *bundle)
{
return bt_modifies_reg(bundle, TREG_SP);
}
-/** Does this bundle modify lr? */
+/* Does this bundle modify lr? */
static inline bool bt_modifies_lr(const struct BacktraceBundle *bundle)
{
return bt_modifies_reg(bundle, TREG_LR);
}
-/** Does this bundle contain the instruction 'move fp, sp'? */
+/* Does this bundle contain the instruction 'move fp, sp'? */
static inline bool bt_has_move_r52_sp(const struct BacktraceBundle *bundle)
{
static const int vals[2] = { 52, TREG_SP };
return find_matching_insn(bundle, TILE_OPC_MOVE, vals, 2) != NULL;
}
-/** Does this bundle contain a store of lr to sp? */
+/* Does this bundle contain a store of lr to sp? */
static inline bool bt_has_sw_sp_lr(const struct BacktraceBundle *bundle)
{
static const int vals[2] = { TREG_SP, TREG_LR };
return find_matching_insn(bundle, OPCODE_STORE, vals, 2) != NULL;
}
-#if TILE_CHIP >= 10
-/** Track moveli values placed into registers. */
+#ifdef __tilegx__
+/* Track moveli values placed into registers. */
static inline void bt_update_moveli(const struct BacktraceBundle *bundle,
int moveli_args[])
{
@@ -238,7 +214,7 @@ static inline void bt_update_moveli(const struct BacktraceBundle *bundle,
}
}
-/** Does this bundle contain an 'add sp, sp, reg' instruction
+/* Does this bundle contain an 'add sp, sp, reg' instruction
* from a register that we saw a moveli into, and if so, what
* is the value in the register?
*/
@@ -260,11 +236,11 @@ static bool bt_has_add_sp(const struct BacktraceBundle *bundle, int *adjust,
}
#endif
-/** Locates the caller's PC and SP for a program starting at the
+/* Locates the caller's PC and SP for a program starting at the
* given address.
*/
static void find_caller_pc_and_caller_sp(CallerLocation *location,
- const VirtualAddress start_pc,
+ const unsigned long start_pc,
BacktraceMemoryReader read_memory_func,
void *read_memory_func_extra)
{
@@ -288,9 +264,9 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
tile_bundle_bits prefetched_bundles[32];
int num_bundles_prefetched = 0;
int next_bundle = 0;
- VirtualAddress pc;
+ unsigned long pc;
-#if TILE_CHIP >= 10
+#ifdef __tilegx__
/* Naively try to track moveli values to support addx for -m32. */
int moveli_args[TILEGX_NUM_REGISTERS] = { 0 };
#endif
@@ -369,10 +345,6 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
/* Weird; reserved value, ignore it. */
continue;
}
- if (info_operand & ENTRY_POINT_INFO_OP) {
- /* This info op is ignored by the backtracer. */
- continue;
- }
/* Skip info ops which are not in the
* "one_ago" mode we want right now.
@@ -453,7 +425,7 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
if (!sp_determined) {
int adjust;
if (bt_has_addi_sp(&bundle, &adjust)
-#if TILE_CHIP >= 10
+#ifdef __tilegx__
|| bt_has_add_sp(&bundle, &adjust, moveli_args)
#endif
) {
@@ -504,7 +476,7 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
}
}
-#if TILE_CHIP >= 10
+#ifdef __tilegx__
/* Track moveli arguments for -m32 mode. */
bt_update_moveli(&bundle, moveli_args);
#endif
@@ -546,18 +518,26 @@ static void find_caller_pc_and_caller_sp(CallerLocation *location,
}
}
+/* Initializes a backtracer to start from the given location.
+ *
+ * If the frame pointer cannot be determined it is set to -1.
+ *
+ * state: The state to be filled in.
+ * read_memory_func: A callback that reads memory.
+ * read_memory_func_extra: An arbitrary argument to read_memory_func.
+ * pc: The current PC.
+ * lr: The current value of the 'lr' register.
+ * sp: The current value of the 'sp' register.
+ * r52: The current value of the 'r52' register.
+ */
void backtrace_init(BacktraceIterator *state,
BacktraceMemoryReader read_memory_func,
void *read_memory_func_extra,
- VirtualAddress pc, VirtualAddress lr,
- VirtualAddress sp, VirtualAddress r52)
+ unsigned long pc, unsigned long lr,
+ unsigned long sp, unsigned long r52)
{
CallerLocation location;
- VirtualAddress fp, initial_frame_caller_pc;
-
- if (read_memory_func == NULL) {
- read_memory_func = bt_read_memory;
- }
+ unsigned long fp, initial_frame_caller_pc;
/* Find out where we are in the initial frame. */
find_caller_pc_and_caller_sp(&location, pc,
@@ -630,12 +610,15 @@ void backtrace_init(BacktraceIterator *state,
/* Handle the case where the register holds more bits than the VA. */
static bool valid_addr_reg(bt_int_reg_t reg)
{
- return ((VirtualAddress)reg == reg);
+ return ((unsigned long)reg == reg);
}
+/* Advances the backtracing state to the calling frame, returning
+ * true iff successful.
+ */
bool backtrace_next(BacktraceIterator *state)
{
- VirtualAddress next_fp, next_pc;
+ unsigned long next_fp, next_pc;
bt_int_reg_t next_frame[2];
if (state->fp == -1) {
diff --git a/arch/tile/kernel/compat.c b/arch/tile/kernel/compat.c
index dbc213adf5e1..bf5e9d70266c 100644
--- a/arch/tile/kernel/compat.c
+++ b/arch/tile/kernel/compat.c
@@ -135,26 +135,15 @@ long tile_compat_sys_msgrcv(int msqid,
/* Provide the compat syscall number to call mapping. */
#undef __SYSCALL
-#define __SYSCALL(nr, call) [nr] = (compat_##call),
+#define __SYSCALL(nr, call) [nr] = (call),
/* The generic versions of these don't work for Tile. */
#define compat_sys_msgrcv tile_compat_sys_msgrcv
#define compat_sys_msgsnd tile_compat_sys_msgsnd
/* See comments in sys.c */
-#define compat_sys_fadvise64 sys32_fadvise64
#define compat_sys_fadvise64_64 sys32_fadvise64_64
#define compat_sys_readahead sys32_readahead
-#define compat_sys_sync_file_range compat_sys_sync_file_range2
-
-/* We leverage the "struct stat64" type for 32-bit time_t/nsec. */
-#define compat_sys_stat64 sys_stat64
-#define compat_sys_lstat64 sys_lstat64
-#define compat_sys_fstat64 sys_fstat64
-#define compat_sys_fstatat64 sys_fstatat64
-
-/* The native sys_ptrace dynamically handles compat binaries. */
-#define compat_sys_ptrace sys_ptrace
/* Call the trampolines to manage pt_regs where necessary. */
#define compat_sys_execve _compat_sys_execve
diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c
index dbb0dfc7bece..a7869ad62776 100644
--- a/arch/tile/kernel/compat_signal.c
+++ b/arch/tile/kernel/compat_signal.c
@@ -317,7 +317,7 @@ long compat_sys_rt_sigreturn(struct pt_regs *regs)
return 0;
badframe:
- force_sig(SIGSEGV, current);
+ signal_fault("bad sigreturn frame", regs, frame, 0);
return 0;
}
@@ -431,6 +431,6 @@ int compat_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
return 0;
give_sigsegv:
- force_sigsegv(sig, current);
+ signal_fault("bad setup frame", regs, frame, sig);
return -EFAULT;
}
diff --git a/arch/tile/kernel/futex_64.S b/arch/tile/kernel/futex_64.S
new file mode 100644
index 000000000000..f465d1eda20f
--- /dev/null
+++ b/arch/tile/kernel/futex_64.S
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in 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.
+ *
+ * Atomically access user memory, but use MMU to avoid propagating
+ * kernel exceptions.
+ */
+
+#include <linux/linkage.h>
+#include <asm/errno.h>
+#include <asm/futex.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+
+/*
+ * Provide a set of atomic memory operations supporting <asm/futex.h>.
+ *
+ * r0: user address to manipulate
+ * r1: new value to write, or for cmpxchg, old value to compare against
+ * r2: (cmpxchg only) new value to write
+ *
+ * Return __get_user struct, r0 with value, r1 with error.
+ */
+#define FUTEX_OP(name, ...) \
+STD_ENTRY(futex_##name) \
+ __VA_ARGS__; \
+ { \
+ move r1, zero; \
+ jrp lr \
+ }; \
+ STD_ENDPROC(futex_##name); \
+ .pushsection __ex_table,"a"; \
+ .quad 1b, get_user_fault; \
+ .popsection
+
+ .pushsection .fixup,"ax"
+get_user_fault:
+ { movei r1, -EFAULT; jrp lr }
+ ENDPROC(get_user_fault)
+ .popsection
+
+FUTEX_OP(cmpxchg, mtspr CMPEXCH_VALUE, r1; 1: cmpexch4 r0, r0, r2)
+FUTEX_OP(set, 1: exch4 r0, r0, r1)
+FUTEX_OP(add, 1: fetchadd4 r0, r0, r1)
+FUTEX_OP(or, 1: fetchor4 r0, r0, r1)
+FUTEX_OP(andn, nor r1, r1, zero; 1: fetchand4 r0, r0, r1)
diff --git a/arch/tile/kernel/hardwall.c b/arch/tile/kernel/hardwall.c
index e910530436e6..3bddef710de4 100644
--- a/arch/tile/kernel/hardwall.c
+++ b/arch/tile/kernel/hardwall.c
@@ -268,12 +268,10 @@ void __kprobes do_hardwall_trap(struct pt_regs* regs, int fault_num)
found_processes = 0;
list_for_each_entry(p, &rect->task_head, thread.hardwall_list) {
BUG_ON(p->thread.hardwall != rect);
- if (p->sighand) {
+ if (!(p->flags & PF_EXITING)) {
found_processes = 1;
pr_notice("hardwall: killing %d\n", p->pid);
- spin_lock(&p->sighand->siglock);
- __group_send_sig_info(info.si_signo, &info, p);
- spin_unlock(&p->sighand->siglock);
+ do_send_sig_info(info.si_signo, &info, p, false);
}
}
if (!found_processes)
diff --git a/arch/tile/kernel/head_64.S b/arch/tile/kernel/head_64.S
new file mode 100644
index 000000000000..6bc3a932fe45
--- /dev/null
+++ b/arch/tile/kernel/head_64.S
@@ -0,0 +1,269 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in 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.
+ *
+ * TILE startup code.
+ */
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/thread_info.h>
+#include <asm/processor.h>
+#include <asm/asm-offsets.h>
+#include <hv/hypervisor.h>
+#include <arch/chip.h>
+#include <arch/spr_def.h>
+
+/*
+ * This module contains the entry code for kernel images. It performs the
+ * minimal setup needed to call the generic C routines.
+ */
+
+ __HEAD
+ENTRY(_start)
+ /* Notify the hypervisor of what version of the API we want */
+ {
+ movei r1, TILE_CHIP
+ movei r2, TILE_CHIP_REV
+ }
+ {
+ moveli r0, _HV_VERSION
+ jal hv_init
+ }
+ /* Get a reasonable default ASID in r0 */
+ {
+ move r0, zero
+ jal hv_inquire_asid
+ }
+
+ /*
+ * Install the default page table. The relocation required to
+ * statically define the table is a bit too complex, so we have
+ * to plug in the pointer from the L0 to the L1 table by hand.
+ * We only do this on the first cpu to boot, though, since the
+ * other CPUs should see a properly-constructed page table.
+ */
+ {
+ v4int_l r2, zero, r0 /* ASID for hv_install_context */
+ moveli r4, hw1_last(swapper_pgprot - PAGE_OFFSET)
+ }
+ {
+ shl16insli r4, r4, hw0(swapper_pgprot - PAGE_OFFSET)
+ }
+ {
+ ld r1, r4 /* access_pte for hv_install_context */
+ }
+ {
+ moveli r0, hw1_last(.Lsv_data_pmd - PAGE_OFFSET)
+ moveli r6, hw1_last(temp_data_pmd - PAGE_OFFSET)
+ }
+ {
+ /* After initializing swapper_pgprot, HV_PTE_GLOBAL is set. */
+ bfextu r7, r1, HV_PTE_INDEX_GLOBAL, HV_PTE_INDEX_GLOBAL
+ inv r4
+ }
+ bnez r7, .Lno_write
+ {
+ shl16insli r0, r0, hw0(.Lsv_data_pmd - PAGE_OFFSET)
+ shl16insli r6, r6, hw0(temp_data_pmd - PAGE_OFFSET)
+ }
+ {
+ /* Cut off the low bits of the PT address. */
+ shrui r6, r6, HV_LOG2_PAGE_TABLE_ALIGN
+ /* Start with our access pte. */
+ move r5, r1
+ }
+ {
+ /* Stuff the address into the page table pointer slot of the PTE. */
+ bfins r5, r6, HV_PTE_INDEX_PTFN, \
+ HV_PTE_INDEX_PTFN + HV_PTE_PTFN_BITS - 1
+ }
+ {
+ /* Store the L0 data PTE. */
+ st r0, r5
+ addli r6, r6, (temp_code_pmd - temp_data_pmd) >> \
+ HV_LOG2_PAGE_TABLE_ALIGN
+ }
+ {
+ addli r0, r0, .Lsv_code_pmd - .Lsv_data_pmd
+ bfins r5, r6, HV_PTE_INDEX_PTFN, \
+ HV_PTE_INDEX_PTFN + HV_PTE_PTFN_BITS - 1
+ }
+ /* Store the L0 code PTE. */
+ st r0, r5
+
+.Lno_write:
+ moveli lr, hw2_last(1f)
+ {
+ shl16insli lr, lr, hw1(1f)
+ moveli r0, hw1_last(swapper_pg_dir - PAGE_OFFSET)
+ }
+ {
+ shl16insli lr, lr, hw0(1f)
+ shl16insli r0, r0, hw0(swapper_pg_dir - PAGE_OFFSET)
+ }
+ {
+ move r3, zero
+ j hv_install_context
+ }
+1:
+
+ /* Install the interrupt base. */
+ moveli r0, hw2_last(MEM_SV_START)
+ shl16insli r0, r0, hw1(MEM_SV_START)
+ shl16insli r0, r0, hw0(MEM_SV_START)
+ mtspr SPR_INTERRUPT_VECTOR_BASE_K, r0
+
+ /*
+ * Get our processor number and save it away in SAVE_K_0.
+ * Extract stuff from the topology structure: r4 = y, r6 = x,
+ * r5 = width. FIXME: consider whether we want to just make these
+ * 64-bit values (and if so fix smp_topology write below, too).
+ */
+ jal hv_inquire_topology
+ {
+ v4int_l r5, zero, r1 /* r5 = width */
+ shrui r4, r0, 32 /* r4 = y */
+ }
+ {
+ v4int_l r6, zero, r0 /* r6 = x */
+ mul_lu_lu r4, r4, r5
+ }
+ {
+ add r4, r4, r6 /* r4 == cpu == y*width + x */
+ }
+
+#ifdef CONFIG_SMP
+ /*
+ * Load up our per-cpu offset. When the first (master) tile
+ * boots, this value is still zero, so we will load boot_pc
+ * with start_kernel, and boot_sp with init_stack + THREAD_SIZE.
+ * The master tile initializes the per-cpu offset array, so that
+ * when subsequent (secondary) tiles boot, they will instead load
+ * from their per-cpu versions of boot_sp and boot_pc.
+ */
+ moveli r5, hw2_last(__per_cpu_offset)
+ shl16insli r5, r5, hw1(__per_cpu_offset)
+ shl16insli r5, r5, hw0(__per_cpu_offset)
+ shl3add r5, r4, r5
+ ld r5, r5
+ bnez r5, 1f
+
+ /*
+ * Save the width and height to the smp_topology variable
+ * for later use.
+ */
+ moveli r0, hw2_last(smp_topology + HV_TOPOLOGY_WIDTH_OFFSET)
+ shl16insli r0, r0, hw1(smp_topology + HV_TOPOLOGY_WIDTH_OFFSET)
+ shl16insli r0, r0, hw0(smp_topology + HV_TOPOLOGY_WIDTH_OFFSET)
+ st r0, r1
+1:
+#else
+ move r5, zero
+#endif
+
+ /* Load and go with the correct pc and sp. */
+ {
+ moveli r1, hw2_last(boot_sp)
+ moveli r0, hw2_last(boot_pc)
+ }
+ {
+ shl16insli r1, r1, hw1(boot_sp)
+ shl16insli r0, r0, hw1(boot_pc)
+ }
+ {
+ shl16insli r1, r1, hw0(boot_sp)
+ shl16insli r0, r0, hw0(boot_pc)
+ }
+ {
+ add r1, r1, r5
+ add r0, r0, r5
+ }
+ ld r0, r0
+ ld sp, r1
+ or r4, sp, r4
+ mtspr SPR_SYSTEM_SAVE_K_0, r4 /* save ksp0 + cpu */
+ addi sp, sp, -STACK_TOP_DELTA
+ {
+ move lr, zero /* stop backtraces in the called function */
+ jr r0
+ }
+ ENDPROC(_start)
+
+__PAGE_ALIGNED_BSS
+ .align PAGE_SIZE
+ENTRY(empty_zero_page)
+ .fill PAGE_SIZE,1,0
+ END(empty_zero_page)
+
+ .macro PTE cpa, bits1
+ .quad HV_PTE_PAGE | HV_PTE_DIRTY | HV_PTE_PRESENT | HV_PTE_ACCESSED |\
+ HV_PTE_GLOBAL | (HV_PTE_MODE_CACHE_NO_L3 << HV_PTE_INDEX_MODE) |\
+ (\bits1) | (HV_CPA_TO_PFN(\cpa) << HV_PTE_INDEX_PFN)
+ .endm
+
+__PAGE_ALIGNED_DATA
+ .align PAGE_SIZE
+ENTRY(swapper_pg_dir)
+ .org swapper_pg_dir + HV_L0_INDEX(PAGE_OFFSET) * HV_PTE_SIZE
+.Lsv_data_pmd:
+ .quad 0 /* PTE temp_data_pmd - PAGE_OFFSET, 0 */
+ .org swapper_pg_dir + HV_L0_INDEX(MEM_SV_START) * HV_PTE_SIZE
+.Lsv_code_pmd:
+ .quad 0 /* PTE temp_code_pmd - PAGE_OFFSET, 0 */
+ .org swapper_pg_dir + HV_L0_SIZE
+ END(swapper_pg_dir)
+
+ .align HV_PAGE_TABLE_ALIGN
+ENTRY(temp_data_pmd)
+ /*
+ * We fill the PAGE_OFFSET pmd with huge pages with
+ * VA = PA + PAGE_OFFSET. We remap things with more precise access
+ * permissions later.
+ */
+ .set addr, 0
+ .rept HV_L1_ENTRIES
+ PTE addr, HV_PTE_READABLE | HV_PTE_WRITABLE
+ .set addr, addr + HV_PAGE_SIZE_LARGE
+ .endr
+ .org temp_data_pmd + HV_L1_SIZE
+ END(temp_data_pmd)
+
+ .align HV_PAGE_TABLE_ALIGN
+ENTRY(temp_code_pmd)
+ /*
+ * We fill the MEM_SV_START pmd with huge pages with
+ * VA = PA + PAGE_OFFSET. We remap things with more precise access
+ * permissions later.
+ */
+ .set addr, 0
+ .rept HV_L1_ENTRIES
+ PTE addr, HV_PTE_READABLE | HV_PTE_EXECUTABLE
+ .set addr, addr + HV_PAGE_SIZE_LARGE
+ .endr
+ .org temp_code_pmd + HV_L1_SIZE
+ END(temp_code_pmd)
+
+ /*
+ * Isolate swapper_pgprot to its own cache line, since each cpu
+ * starting up will read it using VA-is-PA and local homing.
+ * This would otherwise likely conflict with other data on the cache
+ * line, once we have set its permanent home in the page tables.
+ */
+ __INITDATA
+ .align CHIP_L2_LINE_SIZE()
+ENTRY(swapper_pgprot)
+ .quad HV_PTE_PRESENT | (HV_PTE_MODE_CACHE_NO_L3 << HV_PTE_INDEX_MODE)
+ .align CHIP_L2_LINE_SIZE()
+ END(swapper_pgprot)
diff --git a/arch/tile/kernel/intvec_32.S b/arch/tile/kernel/intvec_32.S
index fffcfa6b3a62..72ade79b621b 100644
--- a/arch/tile/kernel/intvec_32.S
+++ b/arch/tile/kernel/intvec_32.S
@@ -851,14 +851,27 @@ STD_ENTRY(interrupt_return)
/* Check to see if there is any work to do before returning to user. */
{
addi r29, r32, THREAD_INFO_FLAGS_OFFSET
- moveli r28, lo16(_TIF_ALLWORK_MASK)
+ moveli r1, lo16(_TIF_ALLWORK_MASK)
}
{
lw r29, r29
- auli r28, r28, ha16(_TIF_ALLWORK_MASK)
+ auli r1, r1, ha16(_TIF_ALLWORK_MASK)
}
- and r28, r29, r28
- bnz r28, .Lwork_pending
+ and r1, r29, r1
+ bzt r1, .Lrestore_all
+
+ /*
+ * Make sure we have all the registers saved for signal
+ * handling or single-step. Call out to C code to figure out
+ * exactly what we need to do for each flag bit, then if
+ * necessary, reload the flags and recheck.
+ */
+ push_extra_callee_saves r0
+ {
+ PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
+ jal do_work_pending
+ }
+ bnz r0, .Lresume_userspace
/*
* In the NMI case we
@@ -1099,99 +1112,6 @@ STD_ENTRY(interrupt_return)
pop_reg r50
pop_reg r51, sp, PTREGS_OFFSET_REG(29) - PTREGS_OFFSET_REG(51)
j .Lcontinue_restore_regs
-
-.Lwork_pending:
- /* Mask the reschedule flag */
- andi r28, r29, _TIF_NEED_RESCHED
-
- {
- /*
- * If the NEED_RESCHED flag is called, we call schedule(), which
- * may drop this context right here and go do something else.
- * On return, jump back to .Lresume_userspace and recheck.
- */
- bz r28, .Lasync_tlb
-
- /* Mask the async-tlb flag */
- andi r28, r29, _TIF_ASYNC_TLB
- }
-
- jal schedule
- FEEDBACK_REENTER(interrupt_return)
-
- /* Reload the flags and check again */
- j .Lresume_userspace
-
-.Lasync_tlb:
- {
- bz r28, .Lneed_sigpending
-
- /* Mask the sigpending flag */
- andi r28, r29, _TIF_SIGPENDING
- }
-
- PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
- jal do_async_page_fault
- FEEDBACK_REENTER(interrupt_return)
-
- /*
- * Go restart the "resume userspace" process. We may have
- * fired a signal, and we need to disable interrupts again.
- */
- j .Lresume_userspace
-
-.Lneed_sigpending:
- /*
- * At this point we are either doing signal handling or single-step,
- * so either way make sure we have all the registers saved.
- */
- push_extra_callee_saves r0
-
- {
- /* If no signal pending, skip to singlestep check */
- bz r28, .Lneed_singlestep
-
- /* Mask the singlestep flag */
- andi r28, r29, _TIF_SINGLESTEP
- }
-
- jal do_signal
- FEEDBACK_REENTER(interrupt_return)
-
- /* Reload the flags and check again */
- j .Lresume_userspace
-
-.Lneed_singlestep:
- {
- /* Get a pointer to the EX1 field */
- PTREGS_PTR(r29, PTREGS_OFFSET_EX1)
-
- /* If we get here, our bit must be set. */
- bz r28, .Lwork_confusion
- }
- /* If we are in priv mode, don't single step */
- lw r28, r29
- andi r28, r28, SPR_EX_CONTEXT_1_1__PL_MASK /* mask off ICS */
- bnz r28, .Lrestore_all
-
- /* Allow interrupts within the single step code */
- TRACE_IRQS_ON /* Note: clobbers registers r0-r29 */
- IRQ_ENABLE(r20, r21)
-
- /* try to single-step the current instruction */
- PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
- jal single_step_once
- FEEDBACK_REENTER(interrupt_return)
-
- /* Re-disable interrupts. TRACE_IRQS_OFF in .Lrestore_all. */
- IRQ_DISABLE(r20,r21)
-
- j .Lrestore_all
-
-.Lwork_confusion:
- move r0, r28
- panic "thread_info allwork flags unhandled on userspace resume: %#x"
-
STD_ENDPROC(interrupt_return)
/*
@@ -1550,7 +1470,10 @@ STD_ENTRY(_sys_clone)
* We place it in the __HEAD section to ensure it is relatively
* near to the intvec_SWINT_1 code (reachable by a conditional branch).
*
- * Must match register usage in do_page_fault().
+ * Our use of ATOMIC_LOCK_REG here must match do_page_fault_ics().
+ *
+ * As we do in lib/atomic_asm_32.S, we bypass a store if the value we
+ * would store is the same as the value we just loaded.
*/
__HEAD
.align 64
@@ -1611,17 +1534,7 @@ ENTRY(sys_cmpxchg)
{
shri r20, r25, 32 - ATOMIC_HASH_L1_SHIFT
slt_u r23, r0, r23
-
- /*
- * Ensure that the TLB is loaded before we take out the lock.
- * On TILEPro, this will start fetching the value all the way
- * into our L1 as well (and if it gets modified before we
- * grab the lock, it will be invalidated from our cache
- * before we reload it). On tile64, we'll start fetching it
- * into our L1 if we're the home, and if we're not, we'll
- * still at least start fetching it into the home's L2.
- */
- lw r26, r0
+ lw r26, r0 /* see comment in the "#else" for the "lw r26". */
}
{
s2a r21, r20, r21
@@ -1637,18 +1550,9 @@ ENTRY(sys_cmpxchg)
bbs r23, .Lcmpxchg64
andi r23, r0, 7 /* Precompute alignment for cmpxchg64. */
}
-
{
- /*
- * We very carefully align the code that actually runs with
- * the lock held (nine bundles) so that we know it is all in
- * the icache when we start. This instruction (the jump) is
- * at the start of the first cache line, address zero mod 64;
- * we jump to somewhere in the second cache line to issue the
- * tns, then jump back to finish up.
- */
s2a ATOMIC_LOCK_REG_NAME, r25, r21
- j .Lcmpxchg32_tns
+ j .Lcmpxchg32_tns /* see comment in the #else for the jump. */
}
#else /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
@@ -1713,24 +1617,25 @@ ENTRY(sys_cmpxchg)
{
/*
* We very carefully align the code that actually runs with
- * the lock held (nine bundles) so that we know it is all in
+ * the lock held (twelve bundles) so that we know it is all in
* the icache when we start. This instruction (the jump) is
* at the start of the first cache line, address zero mod 64;
- * we jump to somewhere in the second cache line to issue the
- * tns, then jump back to finish up.
+ * we jump to the very end of the second cache line to get that
+ * line loaded in the icache, then fall through to issue the tns
+ * in the third cache line, at which point it's all cached.
+ * Note that is for performance, not correctness.
*/
j .Lcmpxchg32_tns
}
#endif /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
- ENTRY(__sys_cmpxchg_grab_lock)
+/* Symbol for do_page_fault_ics() to use to compare against the PC. */
+.global __sys_cmpxchg_grab_lock
+__sys_cmpxchg_grab_lock:
/*
* Perform the actual cmpxchg or atomic_update.
- * Note that the system <arch/atomic.h> header relies on
- * atomic_update() to always perform an "mf", so don't make
- * it optional or conditional without modifying that code.
*/
.Ldo_cmpxchg32:
{
@@ -1748,10 +1653,13 @@ ENTRY(sys_cmpxchg)
}
{
mvnz r24, r23, r25 /* Use atomic_update value if appropriate. */
- bbns r22, .Lcmpxchg32_mismatch
+ bbns r22, .Lcmpxchg32_nostore
}
+ seq r22, r24, r21 /* Are we storing the value we loaded? */
+ bbs r22, .Lcmpxchg32_nostore
sw r0, r24
+ /* The following instruction is the start of the second cache line. */
/* Do slow mtspr here so the following "mf" waits less. */
{
move sp, r27
@@ -1759,7 +1667,6 @@ ENTRY(sys_cmpxchg)
}
mf
- /* The following instruction is the start of the second cache line. */
{
move r0, r21
sw ATOMIC_LOCK_REG_NAME, zero
@@ -1767,7 +1674,7 @@ ENTRY(sys_cmpxchg)
iret
/* Duplicated code here in the case where we don't overlap "mf" */
-.Lcmpxchg32_mismatch:
+.Lcmpxchg32_nostore:
{
move r0, r21
sw ATOMIC_LOCK_REG_NAME, zero
@@ -1783,8 +1690,6 @@ ENTRY(sys_cmpxchg)
* and for 64-bit cmpxchg. We provide it as a macro and put
* it into both versions. We can't share the code literally
* since it depends on having the right branch-back address.
- * Note that the first few instructions should share the cache
- * line with the second half of the actual locked code.
*/
.macro cmpxchg_lock, bitwidth
@@ -1810,7 +1715,7 @@ ENTRY(sys_cmpxchg)
}
/*
* The preceding instruction is the last thing that must be
- * on the second cache line.
+ * hot in the icache before we do the "tns" above.
*/
#ifdef CONFIG_SMP
@@ -1841,6 +1746,12 @@ ENTRY(sys_cmpxchg)
.endm
.Lcmpxchg32_tns:
+ /*
+ * This is the last instruction on the second cache line.
+ * The nop here loads the second line, then we fall through
+ * to the tns to load the third line before we take the lock.
+ */
+ nop
cmpxchg_lock 32
/*
diff --git a/arch/tile/kernel/intvec_64.S b/arch/tile/kernel/intvec_64.S
new file mode 100644
index 000000000000..79c93e10ba27
--- /dev/null
+++ b/arch/tile/kernel/intvec_64.S
@@ -0,0 +1,1231 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in 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.
+ *
+ * Linux interrupt vectors.
+ */
+
+#include <linux/linkage.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <asm/ptrace.h>
+#include <asm/thread_info.h>
+#include <asm/irqflags.h>
+#include <asm/asm-offsets.h>
+#include <asm/types.h>
+#include <hv/hypervisor.h>
+#include <arch/abi.h>
+#include <arch/interrupts.h>
+#include <arch/spr_def.h>
+
+#ifdef CONFIG_PREEMPT
+# error "No support for kernel preemption currently"
+#endif
+
+#define PTREGS_PTR(reg, ptreg) addli reg, sp, C_ABI_SAVE_AREA_SIZE + (ptreg)
+
+#define PTREGS_OFFSET_SYSCALL PTREGS_OFFSET_REG(TREG_SYSCALL_NR)
+
+
+ .macro push_reg reg, ptr=sp, delta=-8
+ {
+ st \ptr, \reg
+ addli \ptr, \ptr, \delta
+ }
+ .endm
+
+ .macro pop_reg reg, ptr=sp, delta=8
+ {
+ ld \reg, \ptr
+ addli \ptr, \ptr, \delta
+ }
+ .endm
+
+ .macro pop_reg_zero reg, zreg, ptr=sp, delta=8
+ {
+ move \zreg, zero
+ ld \reg, \ptr
+ addi \ptr, \ptr, \delta
+ }
+ .endm
+
+ .macro push_extra_callee_saves reg
+ PTREGS_PTR(\reg, PTREGS_OFFSET_REG(51))
+ push_reg r51, \reg
+ push_reg r50, \reg
+ push_reg r49, \reg
+ push_reg r48, \reg
+ push_reg r47, \reg
+ push_reg r46, \reg
+ push_reg r45, \reg
+ push_reg r44, \reg
+ push_reg r43, \reg
+ push_reg r42, \reg
+ push_reg r41, \reg
+ push_reg r40, \reg
+ push_reg r39, \reg
+ push_reg r38, \reg
+ push_reg r37, \reg
+ push_reg r36, \reg
+ push_reg r35, \reg
+ push_reg r34, \reg, PTREGS_OFFSET_BASE - PTREGS_OFFSET_REG(34)
+ .endm
+
+ .macro panic str
+ .pushsection .rodata, "a"
+1:
+ .asciz "\str"
+ .popsection
+ {
+ moveli r0, hw2_last(1b)
+ }
+ {
+ shl16insli r0, r0, hw1(1b)
+ }
+ {
+ shl16insli r0, r0, hw0(1b)
+ jal panic
+ }
+ .endm
+
+
+#ifdef __COLLECT_LINKER_FEEDBACK__
+ .pushsection .text.intvec_feedback,"ax"
+intvec_feedback:
+ .popsection
+#endif
+
+ /*
+ * Default interrupt handler.
+ *
+ * vecnum is where we'll put this code.
+ * c_routine is the C routine we'll call.
+ *
+ * The C routine is passed two arguments:
+ * - A pointer to the pt_regs state.
+ * - The interrupt vector number.
+ *
+ * The "processing" argument specifies the code for processing
+ * the interrupt. Defaults to "handle_interrupt".
+ */
+ .macro int_hand vecnum, vecname, c_routine, processing=handle_interrupt
+ .org (\vecnum << 8)
+intvec_\vecname:
+ /* Temporarily save a register so we have somewhere to work. */
+
+ mtspr SPR_SYSTEM_SAVE_K_1, r0
+ mfspr r0, SPR_EX_CONTEXT_K_1
+
+ andi r0, r0, SPR_EX_CONTEXT_1_1__PL_MASK /* mask off ICS */
+
+ .ifc \vecnum, INT_DOUBLE_FAULT
+ /*
+ * For double-faults from user-space, fall through to the normal
+ * register save and stack setup path. Otherwise, it's the
+ * hypervisor giving us one last chance to dump diagnostics, and we
+ * branch to the kernel_double_fault routine to do so.
+ */
+ beqz r0, 1f
+ j _kernel_double_fault
+1:
+ .else
+ /*
+ * If we're coming from user-space, then set sp to the top of
+ * the kernel stack. Otherwise, assume sp is already valid.
+ */
+ {
+ bnez r0, 0f
+ move r0, sp
+ }
+ .endif
+
+ .ifc \c_routine, do_page_fault
+ /*
+ * The page_fault handler may be downcalled directly by the
+ * hypervisor even when Linux is running and has ICS set.
+ *
+ * In this case the contents of EX_CONTEXT_K_1 reflect the
+ * previous fault and can't be relied on to choose whether or
+ * not to reinitialize the stack pointer. So we add a test
+ * to see whether SYSTEM_SAVE_K_2 has the high bit set,
+ * and if so we don't reinitialize sp, since we must be coming
+ * from Linux. (In fact the precise case is !(val & ~1),
+ * but any Linux PC has to have the high bit set.)
+ *
+ * Note that the hypervisor *always* sets SYSTEM_SAVE_K_2 for
+ * any path that turns into a downcall to one of our TLB handlers.
+ *
+ * FIXME: if we end up never using this path, perhaps we should
+ * prevent the hypervisor from generating downcalls in this case.
+ * The advantage of getting a downcall is we can panic in Linux.
+ */
+ mfspr r0, SPR_SYSTEM_SAVE_K_2
+ {
+ bltz r0, 0f /* high bit in S_S_1_2 is for a PC to use */
+ move r0, sp
+ }
+ .endif
+
+
+ /*
+ * SYSTEM_SAVE_K_0 holds the cpu number in the low bits, and
+ * the current stack top in the higher bits. So we recover
+ * our stack top by just masking off the low bits, then
+ * point sp at the top aligned address on the actual stack page.
+ */
+ mfspr r0, SPR_SYSTEM_SAVE_K_0
+ mm r0, zero, LOG2_THREAD_SIZE, 63
+
+0:
+ /*
+ * Align the stack mod 64 so we can properly predict what
+ * cache lines we need to write-hint to reduce memory fetch
+ * latency as we enter the kernel. The layout of memory is
+ * as follows, with cache line 0 at the lowest VA, and cache
+ * line 8 just below the r0 value this "andi" computes.
+ * Note that we never write to cache line 8, and we skip
+ * cache lines 1-3 for syscalls.
+ *
+ * cache line 8: ptregs padding (two words)
+ * cache line 7: sp, lr, pc, ex1, faultnum, orig_r0, flags, cmpexch
+ * cache line 6: r46...r53 (tp)
+ * cache line 5: r38...r45
+ * cache line 4: r30...r37
+ * cache line 3: r22...r29
+ * cache line 2: r14...r21
+ * cache line 1: r6...r13
+ * cache line 0: 2 x frame, r0..r5
+ */
+ andi r0, r0, -64
+
+ /*
+ * Push the first four registers on the stack, so that we can set
+ * them to vector-unique values before we jump to the common code.
+ *
+ * Registers are pushed on the stack as a struct pt_regs,
+ * with the sp initially just above the struct, and when we're
+ * done, sp points to the base of the struct, minus
+ * C_ABI_SAVE_AREA_SIZE, so we can directly jal to C code.
+ *
+ * This routine saves just the first four registers, plus the
+ * stack context so we can do proper backtracing right away,
+ * and defers to handle_interrupt to save the rest.
+ * The backtracer needs pc, ex1, lr, sp, r52, and faultnum.
+ */
+ addli r0, r0, PTREGS_OFFSET_LR - (PTREGS_SIZE + KSTK_PTREGS_GAP)
+ wh64 r0 /* cache line 7 */
+ {
+ st r0, lr
+ addli r0, r0, PTREGS_OFFSET_SP - PTREGS_OFFSET_LR
+ }
+ {
+ st r0, sp
+ addli sp, r0, PTREGS_OFFSET_REG(52) - PTREGS_OFFSET_SP
+ }
+ wh64 sp /* cache line 6 */
+ {
+ st sp, r52
+ addli sp, sp, PTREGS_OFFSET_REG(1) - PTREGS_OFFSET_REG(52)
+ }
+ wh64 sp /* cache line 0 */
+ {
+ st sp, r1
+ addli sp, sp, PTREGS_OFFSET_REG(2) - PTREGS_OFFSET_REG(1)
+ }
+ {
+ st sp, r2
+ addli sp, sp, PTREGS_OFFSET_REG(3) - PTREGS_OFFSET_REG(2)
+ }
+ {
+ st sp, r3
+ addli sp, sp, PTREGS_OFFSET_PC - PTREGS_OFFSET_REG(3)
+ }
+ mfspr r0, SPR_EX_CONTEXT_K_0
+ .ifc \processing,handle_syscall
+ /*
+ * Bump the saved PC by one bundle so that when we return, we won't
+ * execute the same swint instruction again. We need to do this while
+ * we're in the critical section.
+ */
+ addi r0, r0, 8
+ .endif
+ {
+ st sp, r0
+ addli sp, sp, PTREGS_OFFSET_EX1 - PTREGS_OFFSET_PC
+ }
+ mfspr r0, SPR_EX_CONTEXT_K_1
+ {
+ st sp, r0
+ addi sp, sp, PTREGS_OFFSET_FAULTNUM - PTREGS_OFFSET_EX1
+ /*
+ * Use r0 for syscalls so it's a temporary; use r1 for interrupts
+ * so that it gets passed through unchanged to the handler routine.
+ * Note that the .if conditional confusingly spans bundles.
+ */
+ .ifc \processing,handle_syscall
+ movei r0, \vecnum
+ }
+ {
+ st sp, r0
+ .else
+ movei r1, \vecnum
+ }
+ {
+ st sp, r1
+ .endif
+ addli sp, sp, PTREGS_OFFSET_REG(0) - PTREGS_OFFSET_FAULTNUM
+ }
+ mfspr r0, SPR_SYSTEM_SAVE_K_1 /* Original r0 */
+ {
+ st sp, r0
+ addi sp, sp, -PTREGS_OFFSET_REG(0) - 8
+ }
+ {
+ st sp, zero /* write zero into "Next SP" frame pointer */
+ addi sp, sp, -8 /* leave SP pointing at bottom of frame */
+ }
+ .ifc \processing,handle_syscall
+ j handle_syscall
+ .else
+ /* Capture per-interrupt SPR context to registers. */
+ .ifc \c_routine, do_page_fault
+ mfspr r2, SPR_SYSTEM_SAVE_K_3 /* address of page fault */
+ mfspr r3, SPR_SYSTEM_SAVE_K_2 /* info about page fault */
+ .else
+ .ifc \vecnum, INT_ILL_TRANS
+ mfspr r2, ILL_TRANS_REASON
+ .else
+ .ifc \vecnum, INT_DOUBLE_FAULT
+ mfspr r2, SPR_SYSTEM_SAVE_K_2 /* double fault info from HV */
+ .else
+ .ifc \c_routine, do_trap
+ mfspr r2, GPV_REASON
+ .else
+ .ifc \c_routine, op_handle_perf_interrupt
+ mfspr r2, PERF_COUNT_STS
+#if CHIP_HAS_AUX_PERF_COUNTERS()
+ .else
+ .ifc \c_routine, op_handle_aux_perf_interrupt
+ mfspr r2, AUX_PERF_COUNT_STS
+ .endif
+#endif
+ .endif
+ .endif
+ .endif
+ .endif
+ .endif
+ /* Put function pointer in r0 */
+ moveli r0, hw2_last(\c_routine)
+ shl16insli r0, r0, hw1(\c_routine)
+ {
+ shl16insli r0, r0, hw0(\c_routine)
+ j \processing
+ }
+ .endif
+ ENDPROC(intvec_\vecname)
+
+#ifdef __COLLECT_LINKER_FEEDBACK__
+ .pushsection .text.intvec_feedback,"ax"
+ .org (\vecnum << 5)
+ FEEDBACK_ENTER_EXPLICIT(intvec_\vecname, .intrpt1, 1 << 8)
+ jrp lr
+ .popsection
+#endif
+
+ .endm
+
+
+ /*
+ * Save the rest of the registers that we didn't save in the actual
+ * vector itself. We can't use r0-r10 inclusive here.
+ */
+ .macro finish_interrupt_save, function
+
+ /* If it's a syscall, save a proper orig_r0, otherwise just zero. */
+ PTREGS_PTR(r52, PTREGS_OFFSET_ORIG_R0)
+ {
+ .ifc \function,handle_syscall
+ st r52, r0
+ .else
+ st r52, zero
+ .endif
+ PTREGS_PTR(r52, PTREGS_OFFSET_TP)
+ }
+ st r52, tp
+ {
+ mfspr tp, CMPEXCH_VALUE
+ PTREGS_PTR(r52, PTREGS_OFFSET_CMPEXCH)
+ }
+
+ /*
+ * For ordinary syscalls, we save neither caller- nor callee-
+ * save registers, since the syscall invoker doesn't expect the
+ * caller-saves to be saved, and the called kernel functions will
+ * take care of saving the callee-saves for us.
+ *
+ * For interrupts we save just the caller-save registers. Saving
+ * them is required (since the "caller" can't save them). Again,
+ * the called kernel functions will restore the callee-save
+ * registers for us appropriately.
+ *
+ * On return, we normally restore nothing special for syscalls,
+ * and just the caller-save registers for interrupts.
+ *
+ * However, there are some important caveats to all this:
+ *
+ * - We always save a few callee-save registers to give us
+ * some scratchpad registers to carry across function calls.
+ *
+ * - fork/vfork/etc require us to save all the callee-save
+ * registers, which we do in PTREGS_SYSCALL_ALL_REGS, below.
+ *
+ * - We always save r0..r5 and r10 for syscalls, since we need
+ * to reload them a bit later for the actual kernel call, and
+ * since we might need them for -ERESTARTNOINTR, etc.
+ *
+ * - Before invoking a signal handler, we save the unsaved
+ * callee-save registers so they are visible to the
+ * signal handler or any ptracer.
+ *
+ * - If the unsaved callee-save registers are modified, we set
+ * a bit in pt_regs so we know to reload them from pt_regs
+ * and not just rely on the kernel function unwinding.
+ * (Done for ptrace register writes and SA_SIGINFO handler.)
+ */
+ {
+ st r52, tp
+ PTREGS_PTR(r52, PTREGS_OFFSET_REG(33))
+ }
+ wh64 r52 /* cache line 4 */
+ push_reg r33, r52
+ push_reg r32, r52
+ push_reg r31, r52
+ .ifc \function,handle_syscall
+ push_reg r30, r52, PTREGS_OFFSET_SYSCALL - PTREGS_OFFSET_REG(30)
+ push_reg TREG_SYSCALL_NR_NAME, r52, \
+ PTREGS_OFFSET_REG(5) - PTREGS_OFFSET_SYSCALL
+ .else
+
+ push_reg r30, r52, PTREGS_OFFSET_REG(29) - PTREGS_OFFSET_REG(30)
+ wh64 r52 /* cache line 3 */
+ push_reg r29, r52
+ push_reg r28, r52
+ push_reg r27, r52
+ push_reg r26, r52
+ push_reg r25, r52
+ push_reg r24, r52
+ push_reg r23, r52
+ push_reg r22, r52
+ wh64 r52 /* cache line 2 */
+ push_reg r21, r52
+ push_reg r20, r52
+ push_reg r19, r52
+ push_reg r18, r52
+ push_reg r17, r52
+ push_reg r16, r52
+ push_reg r15, r52
+ push_reg r14, r52
+ wh64 r52 /* cache line 1 */
+ push_reg r13, r52
+ push_reg r12, r52
+ push_reg r11, r52
+ push_reg r10, r52
+ push_reg r9, r52
+ push_reg r8, r52
+ push_reg r7, r52
+ push_reg r6, r52
+
+ .endif
+
+ push_reg r5, r52
+ st r52, r4
+
+ /* Load tp with our per-cpu offset. */
+#ifdef CONFIG_SMP
+ {
+ mfspr r20, SPR_SYSTEM_SAVE_K_0
+ moveli r21, hw2_last(__per_cpu_offset)
+ }
+ {
+ shl16insli r21, r21, hw1(__per_cpu_offset)
+ bfextu r20, r20, 0, LOG2_THREAD_SIZE-1
+ }
+ shl16insli r21, r21, hw0(__per_cpu_offset)
+ shl3add r20, r20, r21
+ ld tp, r20
+#else
+ move tp, zero
+#endif
+
+ /*
+ * If we will be returning to the kernel, we will need to
+ * reset the interrupt masks to the state they had before.
+ * Set DISABLE_IRQ in flags iff we came from PL1 with irqs disabled.
+ */
+ mfspr r32, SPR_EX_CONTEXT_K_1
+ {
+ andi r32, r32, SPR_EX_CONTEXT_1_1__PL_MASK /* mask off ICS */
+ PTREGS_PTR(r21, PTREGS_OFFSET_FLAGS)
+ }
+ beqzt r32, 1f /* zero if from user space */
+ IRQS_DISABLED(r32) /* zero if irqs enabled */
+#if PT_FLAGS_DISABLE_IRQ != 1
+# error Value of IRQS_DISABLED used to set PT_FLAGS_DISABLE_IRQ; fix
+#endif
+1:
+ .ifnc \function,handle_syscall
+ /* Record the fact that we saved the caller-save registers above. */
+ ori r32, r32, PT_FLAGS_CALLER_SAVES
+ .endif
+ st r21, r32
+
+#ifdef __COLLECT_LINKER_FEEDBACK__
+ /*
+ * Notify the feedback routines that we were in the
+ * appropriate fixed interrupt vector area. Note that we
+ * still have ICS set at this point, so we can't invoke any
+ * atomic operations or we will panic. The feedback
+ * routines internally preserve r0..r10 and r30 up.
+ */
+ .ifnc \function,handle_syscall
+ shli r20, r1, 5
+ .else
+ moveli r20, INT_SWINT_1 << 5
+ .endif
+ moveli r21, hw2_last(intvec_feedback)
+ shl16insli r21, r21, hw1(intvec_feedback)
+ shl16insli r21, r21, hw0(intvec_feedback)
+ add r20, r20, r21
+ jalr r20
+
+ /* And now notify the feedback routines that we are here. */
+ FEEDBACK_ENTER(\function)
+#endif
+
+ /*
+ * we've captured enough state to the stack (including in
+ * particular our EX_CONTEXT state) that we can now release
+ * the interrupt critical section and replace it with our
+ * standard "interrupts disabled" mask value. This allows
+ * synchronous interrupts (and profile interrupts) to punch
+ * through from this point onwards.
+ */
+ .ifc \function,handle_nmi
+ IRQ_DISABLE_ALL(r20)
+ .else
+ IRQ_DISABLE(r20, r21)
+ .endif
+ mtspr INTERRUPT_CRITICAL_SECTION, zero
+
+ /*
+ * Prepare the first 256 stack bytes to be rapidly accessible
+ * without having to fetch the background data.
+ */
+ addi r52, sp, -64
+ {
+ wh64 r52
+ addi r52, r52, -64
+ }
+ {
+ wh64 r52
+ addi r52, r52, -64
+ }
+ {
+ wh64 r52
+ addi r52, r52, -64
+ }
+ wh64 r52
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+ .ifnc \function,handle_nmi
+ /*
+ * We finally have enough state set up to notify the irq
+ * tracing code that irqs were disabled on entry to the handler.
+ * The TRACE_IRQS_OFF call clobbers registers r0-r29.
+ * For syscalls, we already have the register state saved away
+ * on the stack, so we don't bother to do any register saves here,
+ * and later we pop the registers back off the kernel stack.
+ * For interrupt handlers, save r0-r3 in callee-saved registers.
+ */
+ .ifnc \function,handle_syscall
+ { move r30, r0; move r31, r1 }
+ { move r32, r2; move r33, r3 }
+ .endif
+ TRACE_IRQS_OFF
+ .ifnc \function,handle_syscall
+ { move r0, r30; move r1, r31 }
+ { move r2, r32; move r3, r33 }
+ .endif
+ .endif
+#endif
+
+ .endm
+
+ /*
+ * Redispatch a downcall.
+ */
+ .macro dc_dispatch vecnum, vecname
+ .org (\vecnum << 8)
+intvec_\vecname:
+ j hv_downcall_dispatch
+ ENDPROC(intvec_\vecname)
+ .endm
+
+ /*
+ * Common code for most interrupts. The C function we're eventually
+ * going to is in r0, and the faultnum is in r1; the original
+ * values for those registers are on the stack.
+ */
+ .pushsection .text.handle_interrupt,"ax"
+handle_interrupt:
+ finish_interrupt_save handle_interrupt
+
+ /* Jump to the C routine; it should enable irqs as soon as possible. */
+ {
+ jalr r0
+ PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
+ }
+ FEEDBACK_REENTER(handle_interrupt)
+ {
+ movei r30, 0 /* not an NMI */
+ j interrupt_return
+ }
+ STD_ENDPROC(handle_interrupt)
+
+/*
+ * This routine takes a boolean in r30 indicating if this is an NMI.
+ * If so, we also expect a boolean in r31 indicating whether to
+ * re-enable the oprofile interrupts.
+ */
+STD_ENTRY(interrupt_return)
+ /* If we're resuming to kernel space, don't check thread flags. */
+ {
+ bnez r30, .Lrestore_all /* NMIs don't special-case user-space */
+ PTREGS_PTR(r29, PTREGS_OFFSET_EX1)
+ }
+ ld r29, r29
+ andi r29, r29, SPR_EX_CONTEXT_1_1__PL_MASK /* mask off ICS */
+ {
+ beqzt r29, .Lresume_userspace
+ PTREGS_PTR(r29, PTREGS_OFFSET_PC)
+ }
+
+ /* If we're resuming to _cpu_idle_nap, bump PC forward by 8. */
+ moveli r27, hw2_last(_cpu_idle_nap)
+ {
+ ld r28, r29
+ shl16insli r27, r27, hw1(_cpu_idle_nap)
+ }
+ {
+ shl16insli r27, r27, hw0(_cpu_idle_nap)
+ }
+ {
+ cmpeq r27, r27, r28
+ }
+ {
+ blbc r27, .Lrestore_all
+ addi r28, r28, 8
+ }
+ st r29, r28
+ j .Lrestore_all
+
+.Lresume_userspace:
+ FEEDBACK_REENTER(interrupt_return)
+
+ /*
+ * Disable interrupts so as to make sure we don't
+ * miss an interrupt that sets any of the thread flags (like
+ * need_resched or sigpending) between sampling and the iret.
+ * Routines like schedule() or do_signal() may re-enable
+ * interrupts before returning.
+ */
+ IRQ_DISABLE(r20, r21)
+ TRACE_IRQS_OFF /* Note: clobbers registers r0-r29 */
+
+ /* Get base of stack in r32; note r30/31 are used as arguments here. */
+ GET_THREAD_INFO(r32)
+
+
+ /* Check to see if there is any work to do before returning to user. */
+ {
+ addi r29, r32, THREAD_INFO_FLAGS_OFFSET
+ moveli r1, hw1_last(_TIF_ALLWORK_MASK)
+ }
+ {
+ ld r29, r29
+ shl16insli r1, r1, hw0(_TIF_ALLWORK_MASK)
+ }
+ and r1, r29, r1
+ beqzt r1, .Lrestore_all
+
+ /*
+ * Make sure we have all the registers saved for signal
+ * handling or single-step. Call out to C code to figure out
+ * exactly what we need to do for each flag bit, then if
+ * necessary, reload the flags and recheck.
+ */
+ push_extra_callee_saves r0
+ {
+ PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
+ jal do_work_pending
+ }
+ bnez r0, .Lresume_userspace
+
+ /*
+ * In the NMI case we
+ * omit the call to single_process_check_nohz, which normally checks
+ * to see if we should start or stop the scheduler tick, because
+ * we can't call arbitrary Linux code from an NMI context.
+ * We always call the homecache TLB deferral code to re-trigger
+ * the deferral mechanism.
+ *
+ * The other chunk of responsibility this code has is to reset the
+ * interrupt masks appropriately to reset irqs and NMIs. We have
+ * to call TRACE_IRQS_OFF and TRACE_IRQS_ON to support all the
+ * lockdep-type stuff, but we can't set ICS until afterwards, since
+ * ICS can only be used in very tight chunks of code to avoid
+ * tripping over various assertions that it is off.
+ */
+.Lrestore_all:
+ PTREGS_PTR(r0, PTREGS_OFFSET_EX1)
+ {
+ ld r0, r0
+ PTREGS_PTR(r32, PTREGS_OFFSET_FLAGS)
+ }
+ {
+ andi r0, r0, SPR_EX_CONTEXT_1_1__PL_MASK
+ ld r32, r32
+ }
+ bnez r0, 1f
+ j 2f
+#if PT_FLAGS_DISABLE_IRQ != 1
+# error Assuming PT_FLAGS_DISABLE_IRQ == 1 so we can use blbct below
+#endif
+1: blbct r32, 2f
+ IRQ_DISABLE(r20,r21)
+ TRACE_IRQS_OFF
+ movei r0, 1
+ mtspr INTERRUPT_CRITICAL_SECTION, r0
+ beqzt r30, .Lrestore_regs
+ j 3f
+2: TRACE_IRQS_ON
+ movei r0, 1
+ mtspr INTERRUPT_CRITICAL_SECTION, r0
+ IRQ_ENABLE(r20, r21)
+ beqzt r30, .Lrestore_regs
+3:
+
+
+ /*
+ * We now commit to returning from this interrupt, since we will be
+ * doing things like setting EX_CONTEXT SPRs and unwinding the stack
+ * frame. No calls should be made to any other code after this point.
+ * This code should only be entered with ICS set.
+ * r32 must still be set to ptregs.flags.
+ * We launch loads to each cache line separately first, so we can
+ * get some parallelism out of the memory subsystem.
+ * We start zeroing caller-saved registers throughout, since
+ * that will save some cycles if this turns out to be a syscall.
+ */
+.Lrestore_regs:
+ FEEDBACK_REENTER(interrupt_return) /* called from elsewhere */
+
+ /*
+ * Rotate so we have one high bit and one low bit to test.
+ * - low bit says whether to restore all the callee-saved registers,
+ * or just r30-r33, and r52 up.
+ * - high bit (i.e. sign bit) says whether to restore all the
+ * caller-saved registers, or just r0.
+ */
+#if PT_FLAGS_CALLER_SAVES != 2 || PT_FLAGS_RESTORE_REGS != 4
+# error Rotate trick does not work :-)
+#endif
+ {
+ rotli r20, r32, 62
+ PTREGS_PTR(sp, PTREGS_OFFSET_REG(0))
+ }
+
+ /*
+ * Load cache lines 0, 4, 6 and 7, in that order, then use
+ * the last loaded value, which makes it likely that the other
+ * cache lines have also loaded, at which point we should be
+ * able to safely read all the remaining words on those cache
+ * lines without waiting for the memory subsystem.
+ */
+ pop_reg r0, sp, PTREGS_OFFSET_REG(30) - PTREGS_OFFSET_REG(0)
+ pop_reg r30, sp, PTREGS_OFFSET_REG(52) - PTREGS_OFFSET_REG(30)
+ pop_reg_zero r52, r3, sp, PTREGS_OFFSET_CMPEXCH - PTREGS_OFFSET_REG(52)
+ pop_reg_zero r21, r27, sp, PTREGS_OFFSET_EX1 - PTREGS_OFFSET_CMPEXCH
+ pop_reg_zero lr, r2, sp, PTREGS_OFFSET_PC - PTREGS_OFFSET_EX1
+ {
+ mtspr CMPEXCH_VALUE, r21
+ move r4, zero
+ }
+ pop_reg r21, sp, PTREGS_OFFSET_REG(31) - PTREGS_OFFSET_PC
+ {
+ mtspr SPR_EX_CONTEXT_K_1, lr
+ andi lr, lr, SPR_EX_CONTEXT_1_1__PL_MASK /* mask off ICS */
+ }
+ {
+ mtspr SPR_EX_CONTEXT_K_0, r21
+ move r5, zero
+ }
+
+ /* Restore callee-saveds that we actually use. */
+ pop_reg_zero r31, r6
+ pop_reg_zero r32, r7
+ pop_reg_zero r33, r8, sp, PTREGS_OFFSET_REG(29) - PTREGS_OFFSET_REG(33)
+
+ /*
+ * If we modified other callee-saveds, restore them now.
+ * This is rare, but could be via ptrace or signal handler.
+ */
+ {
+ move r9, zero
+ blbs r20, .Lrestore_callees
+ }
+.Lcontinue_restore_regs:
+
+ /* Check if we're returning from a syscall. */
+ {
+ move r10, zero
+ bltzt r20, 1f /* no, so go restore callee-save registers */
+ }
+
+ /*
+ * Check if we're returning to userspace.
+ * Note that if we're not, we don't worry about zeroing everything.
+ */
+ {
+ addli sp, sp, PTREGS_OFFSET_LR - PTREGS_OFFSET_REG(29)
+ bnez lr, .Lkernel_return
+ }
+
+ /*
+ * On return from syscall, we've restored r0 from pt_regs, but we
+ * clear the remainder of the caller-saved registers. We could
+ * restore the syscall arguments, but there's not much point,
+ * and it ensures user programs aren't trying to use the
+ * caller-saves if we clear them, as well as avoiding leaking
+ * kernel pointers into userspace.
+ */
+ pop_reg_zero lr, r11, sp, PTREGS_OFFSET_TP - PTREGS_OFFSET_LR
+ pop_reg_zero tp, r12, sp, PTREGS_OFFSET_SP - PTREGS_OFFSET_TP
+ {
+ ld sp, sp
+ move r13, zero
+ move r14, zero
+ }
+ { move r15, zero; move r16, zero }
+ { move r17, zero; move r18, zero }
+ { move r19, zero; move r20, zero }
+ { move r21, zero; move r22, zero }
+ { move r23, zero; move r24, zero }
+ { move r25, zero; move r26, zero }
+
+ /* Set r1 to errno if we are returning an error, otherwise zero. */
+ {
+ moveli r29, 4096
+ sub r1, zero, r0
+ }
+ {
+ move r28, zero
+ cmpltu r29, r1, r29
+ }
+ {
+ mnz r1, r29, r1
+ move r29, zero
+ }
+ iret
+
+ /*
+ * Not a syscall, so restore caller-saved registers.
+ * First kick off loads for cache lines 1-3, which we're touching
+ * for the first time here.
+ */
+ .align 64
+1: pop_reg r29, sp, PTREGS_OFFSET_REG(21) - PTREGS_OFFSET_REG(29)
+ pop_reg r21, sp, PTREGS_OFFSET_REG(13) - PTREGS_OFFSET_REG(21)
+ pop_reg r13, sp, PTREGS_OFFSET_REG(1) - PTREGS_OFFSET_REG(13)
+ pop_reg r1
+ pop_reg r2
+ pop_reg r3
+ pop_reg r4
+ pop_reg r5
+ pop_reg r6
+ pop_reg r7
+ pop_reg r8
+ pop_reg r9
+ pop_reg r10
+ pop_reg r11
+ pop_reg r12, sp, 16
+ /* r13 already restored above */
+ pop_reg r14
+ pop_reg r15
+ pop_reg r16
+ pop_reg r17
+ pop_reg r18
+ pop_reg r19
+ pop_reg r20, sp, 16
+ /* r21 already restored above */
+ pop_reg r22
+ pop_reg r23
+ pop_reg r24
+ pop_reg r25
+ pop_reg r26
+ pop_reg r27
+ pop_reg r28, sp, PTREGS_OFFSET_LR - PTREGS_OFFSET_REG(28)
+ /* r29 already restored above */
+ bnez lr, .Lkernel_return
+ pop_reg lr, sp, PTREGS_OFFSET_TP - PTREGS_OFFSET_LR
+ pop_reg tp, sp, PTREGS_OFFSET_SP - PTREGS_OFFSET_TP
+ ld sp, sp
+ iret
+
+ /*
+ * We can't restore tp when in kernel mode, since a thread might
+ * have migrated from another cpu and brought a stale tp value.
+ */
+.Lkernel_return:
+ pop_reg lr, sp, PTREGS_OFFSET_SP - PTREGS_OFFSET_LR
+ ld sp, sp
+ iret
+
+ /* Restore callee-saved registers from r34 to r51. */
+.Lrestore_callees:
+ addli sp, sp, PTREGS_OFFSET_REG(34) - PTREGS_OFFSET_REG(29)
+ pop_reg r34
+ pop_reg r35
+ pop_reg r36
+ pop_reg r37
+ pop_reg r38
+ pop_reg r39
+ pop_reg r40
+ pop_reg r41
+ pop_reg r42
+ pop_reg r43
+ pop_reg r44
+ pop_reg r45
+ pop_reg r46
+ pop_reg r47
+ pop_reg r48
+ pop_reg r49
+ pop_reg r50
+ pop_reg r51, sp, PTREGS_OFFSET_REG(29) - PTREGS_OFFSET_REG(51)
+ j .Lcontinue_restore_regs
+ STD_ENDPROC(interrupt_return)
+
+ /*
+ * "NMI" interrupts mask ALL interrupts before calling the
+ * handler, and don't check thread flags, etc., on the way
+ * back out. In general, the only things we do here for NMIs
+ * are register save/restore and dataplane kernel-TLB management.
+ * We don't (for example) deal with start/stop of the sched tick.
+ */
+ .pushsection .text.handle_nmi,"ax"
+handle_nmi:
+ finish_interrupt_save handle_nmi
+ {
+ jalr r0
+ PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
+ }
+ FEEDBACK_REENTER(handle_nmi)
+ {
+ movei r30, 1
+ move r31, r0
+ }
+ j interrupt_return
+ STD_ENDPROC(handle_nmi)
+
+ /*
+ * Parallel code for syscalls to handle_interrupt.
+ */
+ .pushsection .text.handle_syscall,"ax"
+handle_syscall:
+ finish_interrupt_save handle_syscall
+
+ /* Enable irqs. */
+ TRACE_IRQS_ON
+ IRQ_ENABLE(r20, r21)
+
+ /* Bump the counter for syscalls made on this tile. */
+ moveli r20, hw2_last(irq_stat + IRQ_CPUSTAT_SYSCALL_COUNT_OFFSET)
+ shl16insli r20, r20, hw1(irq_stat + IRQ_CPUSTAT_SYSCALL_COUNT_OFFSET)
+ shl16insli r20, r20, hw0(irq_stat + IRQ_CPUSTAT_SYSCALL_COUNT_OFFSET)
+ add r20, r20, tp
+ ld4s r21, r20
+ addi r21, r21, 1
+ st4 r20, r21
+
+ /* Trace syscalls, if requested. */
+ GET_THREAD_INFO(r31)
+ addi r31, r31, THREAD_INFO_FLAGS_OFFSET
+ ld r30, r31
+ andi r30, r30, _TIF_SYSCALL_TRACE
+ {
+ addi r30, r31, THREAD_INFO_STATUS_OFFSET - THREAD_INFO_FLAGS_OFFSET
+ beqzt r30, .Lrestore_syscall_regs
+ }
+ jal do_syscall_trace
+ FEEDBACK_REENTER(handle_syscall)
+
+ /*
+ * We always reload our registers from the stack at this
+ * point. They might be valid, if we didn't build with
+ * TRACE_IRQFLAGS, and this isn't a dataplane tile, and we're not
+ * doing syscall tracing, but there are enough cases now that it
+ * seems simplest just to do the reload unconditionally.
+ */
+.Lrestore_syscall_regs:
+ {
+ ld r30, r30
+ PTREGS_PTR(r11, PTREGS_OFFSET_REG(0))
+ }
+ pop_reg r0, r11
+ pop_reg r1, r11
+ pop_reg r2, r11
+ pop_reg r3, r11
+ pop_reg r4, r11
+ pop_reg r5, r11, PTREGS_OFFSET_SYSCALL - PTREGS_OFFSET_REG(5)
+ {
+ ld TREG_SYSCALL_NR_NAME, r11
+ moveli r21, __NR_syscalls
+ }
+
+ /* Ensure that the syscall number is within the legal range. */
+ {
+ moveli r20, hw2(sys_call_table)
+ blbs r30, .Lcompat_syscall
+ }
+ {
+ cmpltu r21, TREG_SYSCALL_NR_NAME, r21
+ shl16insli r20, r20, hw1(sys_call_table)
+ }
+ {
+ blbc r21, .Linvalid_syscall
+ shl16insli r20, r20, hw0(sys_call_table)
+ }
+.Lload_syscall_pointer:
+ shl3add r20, TREG_SYSCALL_NR_NAME, r20
+ ld r20, r20
+
+ /* Jump to syscall handler. */
+ jalr r20
+.Lhandle_syscall_link: /* value of "lr" after "jalr r20" above */
+
+ /*
+ * Write our r0 onto the stack so it gets restored instead
+ * of whatever the user had there before.
+ * In compat mode, sign-extend r0 before storing it.
+ */
+ {
+ PTREGS_PTR(r29, PTREGS_OFFSET_REG(0))
+ blbct r30, 1f
+ }
+ addxi r0, r0, 0
+1: st r29, r0
+
+.Lsyscall_sigreturn_skip:
+ FEEDBACK_REENTER(handle_syscall)
+
+ /* Do syscall trace again, if requested. */
+ ld r30, r31
+ andi r30, r30, _TIF_SYSCALL_TRACE
+ beqzt r30, 1f
+ jal do_syscall_trace
+ FEEDBACK_REENTER(handle_syscall)
+1: j .Lresume_userspace /* jump into middle of interrupt_return */
+
+.Lcompat_syscall:
+ /*
+ * Load the base of the compat syscall table in r20, and
+ * range-check the syscall number (duplicated from 64-bit path).
+ * Sign-extend all the user's passed arguments to make them consistent.
+ * Also save the original "r(n)" values away in "r(11+n)" in
+ * case the syscall table entry wants to validate them.
+ */
+ moveli r20, hw2(compat_sys_call_table)
+ {
+ cmpltu r21, TREG_SYSCALL_NR_NAME, r21
+ shl16insli r20, r20, hw1(compat_sys_call_table)
+ }
+ {
+ blbc r21, .Linvalid_syscall
+ shl16insli r20, r20, hw0(compat_sys_call_table)
+ }
+ { move r11, r0; addxi r0, r0, 0 }
+ { move r12, r1; addxi r1, r1, 0 }
+ { move r13, r2; addxi r2, r2, 0 }
+ { move r14, r3; addxi r3, r3, 0 }
+ { move r15, r4; addxi r4, r4, 0 }
+ { move r16, r5; addxi r5, r5, 0 }
+ j .Lload_syscall_pointer
+
+.Linvalid_syscall:
+ /* Report an invalid syscall back to the user program */
+ {
+ PTREGS_PTR(r29, PTREGS_OFFSET_REG(0))
+ movei r28, -ENOSYS
+ }
+ st r29, r28
+ j .Lresume_userspace /* jump into middle of interrupt_return */
+ STD_ENDPROC(handle_syscall)
+
+ /* Return the address for oprofile to suppress in backtraces. */
+STD_ENTRY_SECTION(handle_syscall_link_address, .text.handle_syscall)
+ lnk r0
+ {
+ addli r0, r0, .Lhandle_syscall_link - .
+ jrp lr
+ }
+ STD_ENDPROC(handle_syscall_link_address)
+
+STD_ENTRY(ret_from_fork)
+ jal sim_notify_fork
+ jal schedule_tail
+ FEEDBACK_REENTER(ret_from_fork)
+ j .Lresume_userspace
+ STD_ENDPROC(ret_from_fork)
+
+/* Various stub interrupt handlers and syscall handlers */
+
+STD_ENTRY_LOCAL(_kernel_double_fault)
+ mfspr r1, SPR_EX_CONTEXT_K_0
+ move r2, lr
+ move r3, sp
+ move r4, r52
+ addi sp, sp, -C_ABI_SAVE_AREA_SIZE
+ j kernel_double_fault
+ STD_ENDPROC(_kernel_double_fault)
+
+STD_ENTRY_LOCAL(bad_intr)
+ mfspr r2, SPR_EX_CONTEXT_K_0
+ panic "Unhandled interrupt %#x: PC %#lx"
+ STD_ENDPROC(bad_intr)
+
+/* Put address of pt_regs in reg and jump. */
+#define PTREGS_SYSCALL(x, reg) \
+ STD_ENTRY(_##x); \
+ { \
+ PTREGS_PTR(reg, PTREGS_OFFSET_BASE); \
+ j x \
+ }; \
+ STD_ENDPROC(_##x)
+
+/*
+ * Special-case sigreturn to not write r0 to the stack on return.
+ * This is technically more efficient, but it also avoids difficulties
+ * in the 64-bit OS when handling 32-bit compat code, since we must not
+ * sign-extend r0 for the sigreturn return-value case.
+ */
+#define PTREGS_SYSCALL_SIGRETURN(x, reg) \
+ STD_ENTRY(_##x); \
+ addli lr, lr, .Lsyscall_sigreturn_skip - .Lhandle_syscall_link; \
+ { \
+ PTREGS_PTR(reg, PTREGS_OFFSET_BASE); \
+ j x \
+ }; \
+ STD_ENDPROC(_##x)
+
+PTREGS_SYSCALL(sys_execve, r3)
+PTREGS_SYSCALL(sys_sigaltstack, r2)
+PTREGS_SYSCALL_SIGRETURN(sys_rt_sigreturn, r0)
+#ifdef CONFIG_COMPAT
+PTREGS_SYSCALL(compat_sys_execve, r3)
+PTREGS_SYSCALL(compat_sys_sigaltstack, r2)
+PTREGS_SYSCALL_SIGRETURN(compat_sys_rt_sigreturn, r0)
+#endif
+
+/* Save additional callee-saves to pt_regs, put address in r4 and jump. */
+STD_ENTRY(_sys_clone)
+ push_extra_callee_saves r4
+ j sys_clone
+ STD_ENDPROC(_sys_clone)
+
+/* The single-step support may need to read all the registers. */
+int_unalign:
+ push_extra_callee_saves r0
+ j do_trap
+
+/* Include .intrpt1 array of interrupt vectors */
+ .section ".intrpt1", "ax"
+
+#define op_handle_perf_interrupt bad_intr
+#define op_handle_aux_perf_interrupt bad_intr
+
+#ifndef CONFIG_HARDWALL
+#define do_hardwall_trap bad_intr
+#endif
+
+ int_hand INT_MEM_ERROR, MEM_ERROR, bad_intr
+ int_hand INT_SINGLE_STEP_3, SINGLE_STEP_3, bad_intr
+#if CONFIG_KERNEL_PL == 2
+ int_hand INT_SINGLE_STEP_2, SINGLE_STEP_2, gx_singlestep_handle
+ int_hand INT_SINGLE_STEP_1, SINGLE_STEP_1, bad_intr
+#else
+ int_hand INT_SINGLE_STEP_2, SINGLE_STEP_2, bad_intr
+ int_hand INT_SINGLE_STEP_1, SINGLE_STEP_1, gx_singlestep_handle
+#endif
+ int_hand INT_SINGLE_STEP_0, SINGLE_STEP_0, bad_intr
+ int_hand INT_IDN_COMPLETE, IDN_COMPLETE, bad_intr
+ int_hand INT_UDN_COMPLETE, UDN_COMPLETE, bad_intr
+ int_hand INT_ITLB_MISS, ITLB_MISS, do_page_fault
+ int_hand INT_ILL, ILL, do_trap
+ int_hand INT_GPV, GPV, do_trap
+ int_hand INT_IDN_ACCESS, IDN_ACCESS, do_trap
+ int_hand INT_UDN_ACCESS, UDN_ACCESS, do_trap
+ int_hand INT_SWINT_3, SWINT_3, do_trap
+ int_hand INT_SWINT_2, SWINT_2, do_trap
+ int_hand INT_SWINT_1, SWINT_1, SYSCALL, handle_syscall
+ int_hand INT_SWINT_0, SWINT_0, do_trap
+ int_hand INT_ILL_TRANS, ILL_TRANS, do_trap
+ int_hand INT_UNALIGN_DATA, UNALIGN_DATA, int_unalign
+ int_hand INT_DTLB_MISS, DTLB_MISS, do_page_fault
+ int_hand INT_DTLB_ACCESS, DTLB_ACCESS, do_page_fault
+ int_hand INT_IDN_FIREWALL, IDN_FIREWALL, bad_intr
+ int_hand INT_UDN_FIREWALL, UDN_FIREWALL, do_hardwall_trap
+ int_hand INT_TILE_TIMER, TILE_TIMER, do_timer_interrupt
+ int_hand INT_IDN_TIMER, IDN_TIMER, bad_intr
+ int_hand INT_UDN_TIMER, UDN_TIMER, bad_intr
+ int_hand INT_IDN_AVAIL, IDN_AVAIL, bad_intr
+ int_hand INT_UDN_AVAIL, UDN_AVAIL, bad_intr
+ int_hand INT_IPI_3, IPI_3, bad_intr
+#if CONFIG_KERNEL_PL == 2
+ int_hand INT_IPI_2, IPI_2, tile_dev_intr
+ int_hand INT_IPI_1, IPI_1, bad_intr
+#else
+ int_hand INT_IPI_2, IPI_2, bad_intr
+ int_hand INT_IPI_1, IPI_1, tile_dev_intr
+#endif
+ int_hand INT_IPI_0, IPI_0, bad_intr
+ int_hand INT_PERF_COUNT, PERF_COUNT, \
+ op_handle_perf_interrupt, handle_nmi
+ int_hand INT_AUX_PERF_COUNT, AUX_PERF_COUNT, \
+ op_handle_perf_interrupt, handle_nmi
+ int_hand INT_INTCTRL_3, INTCTRL_3, bad_intr
+#if CONFIG_KERNEL_PL == 2
+ dc_dispatch INT_INTCTRL_2, INTCTRL_2
+ int_hand INT_INTCTRL_1, INTCTRL_1, bad_intr
+#else
+ int_hand INT_INTCTRL_2, INTCTRL_2, bad_intr
+ dc_dispatch INT_INTCTRL_1, INTCTRL_1
+#endif
+ int_hand INT_INTCTRL_0, INTCTRL_0, bad_intr
+ int_hand INT_MESSAGE_RCV_DWNCL, MESSAGE_RCV_DWNCL, \
+ hv_message_intr
+ int_hand INT_DEV_INTR_DWNCL, DEV_INTR_DWNCL, bad_intr
+ int_hand INT_I_ASID, I_ASID, bad_intr
+ int_hand INT_D_ASID, D_ASID, bad_intr
+ int_hand INT_DOUBLE_FAULT, DOUBLE_FAULT, do_trap
+
+ /* Synthetic interrupt delivered only by the simulator */
+ int_hand INT_BREAKPOINT, BREAKPOINT, do_breakpoint
diff --git a/arch/tile/kernel/module.c b/arch/tile/kernel/module.c
index e2ab82b7c7e7..f68df69f1f67 100644
--- a/arch/tile/kernel/module.c
+++ b/arch/tile/kernel/module.c
@@ -22,6 +22,7 @@
#include <linux/kernel.h>
#include <asm/opcode-tile.h>
#include <asm/pgtable.h>
+#include <asm/homecache.h>
#ifdef __tilegx__
# define Elf_Rela Elf64_Rela
@@ -86,8 +87,13 @@ error:
void module_free(struct module *mod, void *module_region)
{
vfree(module_region);
+
+ /* Globally flush the L1 icache. */
+ flush_remote(0, HV_FLUSH_EVICT_L1I, cpu_online_mask,
+ 0, 0, 0, NULL, NULL, 0);
+
/*
- * FIXME: If module_region == mod->init_region, trim exception
+ * FIXME: If module_region == mod->module_init, trim exception
* table entries.
*/
}
diff --git a/arch/tile/kernel/pci-dma.c b/arch/tile/kernel/pci-dma.c
index 658752b2835e..658f2ce426a4 100644
--- a/arch/tile/kernel/pci-dma.c
+++ b/arch/tile/kernel/pci-dma.c
@@ -244,7 +244,7 @@ EXPORT_SYMBOL(dma_sync_single_range_for_device);
* dma_alloc_noncoherent() returns non-cacheable memory, so there's no
* need to do any flushing here.
*/
-void dma_cache_sync(void *vaddr, size_t size,
+void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
enum dma_data_direction direction)
{
}
diff --git a/arch/tile/kernel/pci.c b/arch/tile/kernel/pci.c
index ea38f0c9ec7c..6d4cb5d7a9fd 100644
--- a/arch/tile/kernel/pci.c
+++ b/arch/tile/kernel/pci.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -59,6 +59,7 @@ int __write_once tile_plx_gen1;
static struct pci_controller controllers[TILE_NUM_PCIE];
static int num_controllers;
+static int pci_scan_flags[TILE_NUM_PCIE];
static struct pci_ops tile_cfg_ops;
@@ -79,7 +80,7 @@ EXPORT_SYMBOL(pcibios_align_resource);
* controller_id is the controller number, config type is 0 or 1 for
* config0 or config1 operations.
*/
-static int __init tile_pcie_open(int controller_id, int config_type)
+static int __devinit tile_pcie_open(int controller_id, int config_type)
{
char filename[32];
int fd;
@@ -95,7 +96,7 @@ static int __init tile_pcie_open(int controller_id, int config_type)
/*
* Get the IRQ numbers from the HV and set up the handlers for them.
*/
-static int __init tile_init_irqs(int controller_id,
+static int __devinit tile_init_irqs(int controller_id,
struct pci_controller *controller)
{
char filename[32];
@@ -139,71 +140,74 @@ static int __init tile_init_irqs(int controller_id,
*
* Returns the number of controllers discovered.
*/
-int __init tile_pci_init(void)
+int __devinit tile_pci_init(void)
{
int i;
pr_info("PCI: Searching for controllers...\n");
+ /* Re-init number of PCIe controllers to support hot-plug feature. */
+ num_controllers = 0;
+
/* Do any configuration we need before using the PCIe */
for (i = 0; i < TILE_NUM_PCIE; i++) {
- int hv_cfg_fd0 = -1;
- int hv_cfg_fd1 = -1;
- int hv_mem_fd = -1;
- char name[32];
- struct pci_controller *controller;
-
/*
- * Open the fd to the HV. If it fails then this
- * device doesn't exist.
+ * To see whether we need a real config op based on
+ * the results of pcibios_init(), to support PCIe hot-plug.
*/
- hv_cfg_fd0 = tile_pcie_open(i, 0);
- if (hv_cfg_fd0 < 0)
- continue;
- hv_cfg_fd1 = tile_pcie_open(i, 1);
- if (hv_cfg_fd1 < 0) {
- pr_err("PCI: Couldn't open config fd to HV "
- "for controller %d\n", i);
- goto err_cont;
- }
-
- sprintf(name, "pcie/%d/mem", i);
- hv_mem_fd = hv_dev_open((HV_VirtAddr)name, 0);
- if (hv_mem_fd < 0) {
- pr_err("PCI: Could not open mem fd to HV!\n");
- goto err_cont;
- }
+ if (pci_scan_flags[i] == 0) {
+ int hv_cfg_fd0 = -1;
+ int hv_cfg_fd1 = -1;
+ int hv_mem_fd = -1;
+ char name[32];
+ struct pci_controller *controller;
+
+ /*
+ * Open the fd to the HV. If it fails then this
+ * device doesn't exist.
+ */
+ hv_cfg_fd0 = tile_pcie_open(i, 0);
+ if (hv_cfg_fd0 < 0)
+ continue;
+ hv_cfg_fd1 = tile_pcie_open(i, 1);
+ if (hv_cfg_fd1 < 0) {
+ pr_err("PCI: Couldn't open config fd to HV "
+ "for controller %d\n", i);
+ goto err_cont;
+ }
- pr_info("PCI: Found PCI controller #%d\n", i);
+ sprintf(name, "pcie/%d/mem", i);
+ hv_mem_fd = hv_dev_open((HV_VirtAddr)name, 0);
+ if (hv_mem_fd < 0) {
+ pr_err("PCI: Could not open mem fd to HV!\n");
+ goto err_cont;
+ }
- controller = &controllers[num_controllers];
+ pr_info("PCI: Found PCI controller #%d\n", i);
- if (tile_init_irqs(i, controller)) {
- pr_err("PCI: Could not initialize "
- "IRQs, aborting.\n");
- goto err_cont;
- }
+ controller = &controllers[i];
- controller->index = num_controllers;
- controller->hv_cfg_fd[0] = hv_cfg_fd0;
- controller->hv_cfg_fd[1] = hv_cfg_fd1;
- controller->hv_mem_fd = hv_mem_fd;
- controller->first_busno = 0;
- controller->last_busno = 0xff;
- controller->ops = &tile_cfg_ops;
+ controller->index = i;
+ controller->hv_cfg_fd[0] = hv_cfg_fd0;
+ controller->hv_cfg_fd[1] = hv_cfg_fd1;
+ controller->hv_mem_fd = hv_mem_fd;
+ controller->first_busno = 0;
+ controller->last_busno = 0xff;
+ controller->ops = &tile_cfg_ops;
- num_controllers++;
- continue;
+ num_controllers++;
+ continue;
err_cont:
- if (hv_cfg_fd0 >= 0)
- hv_dev_close(hv_cfg_fd0);
- if (hv_cfg_fd1 >= 0)
- hv_dev_close(hv_cfg_fd1);
- if (hv_mem_fd >= 0)
- hv_dev_close(hv_mem_fd);
- continue;
+ if (hv_cfg_fd0 >= 0)
+ hv_dev_close(hv_cfg_fd0);
+ if (hv_cfg_fd1 >= 0)
+ hv_dev_close(hv_cfg_fd1);
+ if (hv_mem_fd >= 0)
+ hv_dev_close(hv_mem_fd);
+ continue;
+ }
}
/*
@@ -232,7 +236,7 @@ static int tile_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
}
-static void __init fixup_read_and_payload_sizes(void)
+static void __devinit fixup_read_and_payload_sizes(void)
{
struct pci_dev *dev = NULL;
int smallest_max_payload = 0x1; /* Tile maxes out at 256 bytes. */
@@ -282,7 +286,7 @@ static void __init fixup_read_and_payload_sizes(void)
* The controllers have been set up by the time we get here, by a call to
* tile_pci_init.
*/
-static int __init pcibios_init(void)
+int __devinit pcibios_init(void)
{
int i;
@@ -296,25 +300,36 @@ static int __init pcibios_init(void)
mdelay(250);
/* Scan all of the recorded PCI controllers. */
- for (i = 0; i < num_controllers; i++) {
- struct pci_controller *controller = &controllers[i];
- struct pci_bus *bus;
-
- pr_info("PCI: initializing controller #%d\n", i);
-
+ for (i = 0; i < TILE_NUM_PCIE; i++) {
/*
- * This comes from the generic Linux PCI driver.
- *
- * It reads the PCI tree for this bus into the Linux
- * data structures.
- *
- * This is inlined in linux/pci.h and calls into
- * pci_scan_bus_parented() in probe.c.
+ * Do real pcibios init ops if the controller is initialized
+ * by tile_pci_init() successfully and not initialized by
+ * pcibios_init() yet to support PCIe hot-plug.
*/
- bus = pci_scan_bus(0, controller->ops, controller);
- controller->root_bus = bus;
- controller->last_busno = bus->subordinate;
+ if (pci_scan_flags[i] == 0 && controllers[i].ops != NULL) {
+ struct pci_controller *controller = &controllers[i];
+ struct pci_bus *bus;
+ if (tile_init_irqs(i, controller)) {
+ pr_err("PCI: Could not initialize IRQs\n");
+ continue;
+ }
+
+ pr_info("PCI: initializing controller #%d\n", i);
+
+ /*
+ * This comes from the generic Linux PCI driver.
+ *
+ * It reads the PCI tree for this bus into the Linux
+ * data structures.
+ *
+ * This is inlined in linux/pci.h and calls into
+ * pci_scan_bus_parented() in probe.c.
+ */
+ bus = pci_scan_bus(0, controller->ops, controller);
+ controller->root_bus = bus;
+ controller->last_busno = bus->subordinate;
+ }
}
/* Do machine dependent PCI interrupt routing */
@@ -326,34 +341,45 @@ static int __init pcibios_init(void)
* It allocates all of the resources (I/O memory, etc)
* associated with the devices read in above.
*/
-
pci_assign_unassigned_resources();
/* Configure the max_read_size and max_payload_size values. */
fixup_read_and_payload_sizes();
/* Record the I/O resources in the PCI controller structure. */
- for (i = 0; i < num_controllers; i++) {
- struct pci_bus *root_bus = controllers[i].root_bus;
- struct pci_bus *next_bus;
- struct pci_dev *dev;
-
- list_for_each_entry(dev, &root_bus->devices, bus_list) {
- /* Find the PCI host controller, ie. the 1st bridge. */
- if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
- (PCI_SLOT(dev->devfn) == 0)) {
- next_bus = dev->subordinate;
- controllers[i].mem_resources[0] =
- *next_bus->resource[0];
- controllers[i].mem_resources[1] =
- *next_bus->resource[1];
- controllers[i].mem_resources[2] =
- *next_bus->resource[2];
-
- break;
+ for (i = 0; i < TILE_NUM_PCIE; i++) {
+ /*
+ * Do real pcibios init ops if the controller is initialized
+ * by tile_pci_init() successfully and not initialized by
+ * pcibios_init() yet to support PCIe hot-plug.
+ */
+ if (pci_scan_flags[i] == 0 && controllers[i].ops != NULL) {
+ struct pci_bus *root_bus = controllers[i].root_bus;
+ struct pci_bus *next_bus;
+ struct pci_dev *dev;
+
+ list_for_each_entry(dev, &root_bus->devices, bus_list) {
+ /*
+ * Find the PCI host controller, ie. the 1st
+ * bridge.
+ */
+ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
+ (PCI_SLOT(dev->devfn) == 0)) {
+ next_bus = dev->subordinate;
+ controllers[i].mem_resources[0] =
+ *next_bus->resource[0];
+ controllers[i].mem_resources[1] =
+ *next_bus->resource[1];
+ controllers[i].mem_resources[2] =
+ *next_bus->resource[2];
+
+ /* Setup flags. */
+ pci_scan_flags[i] = 1;
+
+ break;
+ }
}
}
-
}
return 0;
@@ -381,7 +407,7 @@ char __devinit *pcibios_setup(char *str)
/*
* This is called from the generic Linux layer.
*/
-void __init pcibios_update_irq(struct pci_dev *dev, int irq)
+void __devinit pcibios_update_irq(struct pci_dev *dev, int irq)
{
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c
index d0065103eb7b..9c45d8bbdf57 100644
--- a/arch/tile/kernel/process.c
+++ b/arch/tile/kernel/process.c
@@ -25,10 +25,13 @@
#include <linux/hardirq.h>
#include <linux/syscalls.h>
#include <linux/kernel.h>
+#include <linux/tracehook.h>
+#include <linux/signal.h>
#include <asm/system.h>
#include <asm/stack.h>
#include <asm/homecache.h>
#include <asm/syscalls.h>
+#include <asm/traps.h>
#ifdef CONFIG_HARDWALL
#include <asm/hardwall.h>
#endif
@@ -546,6 +549,51 @@ struct task_struct *__sched _switch_to(struct task_struct *prev,
return __switch_to(prev, next, next_current_ksp0(next));
}
+/*
+ * This routine is called on return from interrupt if any of the
+ * TIF_WORK_MASK flags are set in thread_info->flags. It is
+ * entered with interrupts disabled so we don't miss an event
+ * that modified the thread_info flags. If any flag is set, we
+ * handle it and return, and the calling assembly code will
+ * re-disable interrupts, reload the thread flags, and call back
+ * if more flags need to be handled.
+ *
+ * We return whether we need to check the thread_info flags again
+ * or not. Note that we don't clear TIF_SINGLESTEP here, so it's
+ * important that it be tested last, and then claim that we don't
+ * need to recheck the flags.
+ */
+int do_work_pending(struct pt_regs *regs, u32 thread_info_flags)
+{
+ if (thread_info_flags & _TIF_NEED_RESCHED) {
+ schedule();
+ return 1;
+ }
+#if CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC()
+ if (thread_info_flags & _TIF_ASYNC_TLB) {
+ do_async_page_fault(regs);
+ return 1;
+ }
+#endif
+ if (thread_info_flags & _TIF_SIGPENDING) {
+ do_signal(regs);
+ return 1;
+ }
+ if (thread_info_flags & _TIF_NOTIFY_RESUME) {
+ clear_thread_flag(TIF_NOTIFY_RESUME);
+ tracehook_notify_resume(regs);
+ if (current->replacement_session_keyring)
+ key_replace_session_keyring();
+ return 1;
+ }
+ if (thread_info_flags & _TIF_SINGLESTEP) {
+ if ((regs->ex1 & SPR_EX_CONTEXT_1_1__PL_MASK) == 0)
+ single_step_once(regs);
+ return 0;
+ }
+ panic("work_pending: bad flags %#x\n", thread_info_flags);
+}
+
/* Note there is an implicit fifth argument if (clone_flags & CLONE_SETTLS). */
SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
void __user *, parent_tidptr, void __user *, child_tidptr,
@@ -582,8 +630,8 @@ out:
#ifdef CONFIG_COMPAT
long compat_sys_execve(const char __user *path,
- const compat_uptr_t __user *argv,
- const compat_uptr_t __user *envp,
+ compat_uptr_t __user *argv,
+ compat_uptr_t __user *envp,
struct pt_regs *regs)
{
long error;
diff --git a/arch/tile/kernel/regs_64.S b/arch/tile/kernel/regs_64.S
new file mode 100644
index 000000000000..f748c1e85285
--- /dev/null
+++ b/arch/tile/kernel/regs_64.S
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in 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.
+ */
+
+#include <linux/linkage.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>
+#include <asm/asm-offsets.h>
+#include <arch/spr_def.h>
+#include <asm/processor.h>
+
+/*
+ * See <asm/system.h>; called with prev and next task_struct pointers.
+ * "prev" is returned in r0 for _switch_to and also for ret_from_fork.
+ *
+ * We want to save pc/sp in "prev", and get the new pc/sp from "next".
+ * We also need to save all the callee-saved registers on the stack.
+ *
+ * Intel enables/disables access to the hardware cycle counter in
+ * seccomp (secure computing) environments if necessary, based on
+ * has_secure_computing(). We might want to do this at some point,
+ * though it would require virtualizing the other SPRs under WORLD_ACCESS.
+ *
+ * Since we're saving to the stack, we omit sp from this list.
+ * And for parallels with other architectures, we save lr separately,
+ * in the thread_struct itself (as the "pc" field).
+ *
+ * This code also needs to be aligned with process.c copy_thread()
+ */
+
+#if CALLEE_SAVED_REGS_COUNT != 24
+# error Mismatch between <asm/system.h> and kernel/entry.S
+#endif
+#define FRAME_SIZE ((2 + CALLEE_SAVED_REGS_COUNT) * 8)
+
+#define SAVE_REG(r) { st r12, r; addi r12, r12, 8 }
+#define LOAD_REG(r) { ld r, r12; addi r12, r12, 8 }
+#define FOR_EACH_CALLEE_SAVED_REG(f) \
+ f(r30); f(r31); \
+ f(r32); f(r33); f(r34); f(r35); f(r36); f(r37); f(r38); f(r39); \
+ f(r40); f(r41); f(r42); f(r43); f(r44); f(r45); f(r46); f(r47); \
+ f(r48); f(r49); f(r50); f(r51); f(r52);
+
+STD_ENTRY_SECTION(__switch_to, .sched.text)
+ {
+ move r10, sp
+ st sp, lr
+ }
+ {
+ addli r11, sp, -FRAME_SIZE + 8
+ addli sp, sp, -FRAME_SIZE
+ }
+ {
+ st r11, r10
+ addli r4, r1, TASK_STRUCT_THREAD_KSP_OFFSET
+ }
+ {
+ ld r13, r4 /* Load new sp to a temp register early. */
+ addi r12, sp, 16
+ }
+ FOR_EACH_CALLEE_SAVED_REG(SAVE_REG)
+ addli r3, r0, TASK_STRUCT_THREAD_KSP_OFFSET
+ {
+ st r3, sp
+ addli r3, r0, TASK_STRUCT_THREAD_PC_OFFSET
+ }
+ {
+ st r3, lr
+ addli r4, r1, TASK_STRUCT_THREAD_PC_OFFSET
+ }
+ {
+ ld lr, r4
+ addi r12, r13, 16
+ }
+ {
+ /* Update sp and ksp0 simultaneously to avoid backtracer warnings. */
+ move sp, r13
+ mtspr SPR_SYSTEM_SAVE_K_0, r2
+ }
+ FOR_EACH_CALLEE_SAVED_REG(LOAD_REG)
+.L__switch_to_pc:
+ {
+ addli sp, sp, FRAME_SIZE
+ jrp lr /* r0 is still valid here, so return it */
+ }
+ STD_ENDPROC(__switch_to)
+
+/* Return a suitable address for the backtracer for suspended threads */
+STD_ENTRY_SECTION(get_switch_to_pc, .sched.text)
+ lnk r0
+ {
+ addli r0, r0, .L__switch_to_pc - .
+ jrp lr
+ }
+ STD_ENDPROC(get_switch_to_pc)
+
+STD_ENTRY(get_pt_regs)
+ .irp reg, r0, r1, r2, r3, r4, r5, r6, r7, \
+ r8, r9, r10, r11, r12, r13, r14, r15, \
+ r16, r17, r18, r19, r20, r21, r22, r23, \
+ r24, r25, r26, r27, r28, r29, r30, r31, \
+ r32, r33, r34, r35, r36, r37, r38, r39, \
+ r40, r41, r42, r43, r44, r45, r46, r47, \
+ r48, r49, r50, r51, r52, tp, sp
+ {
+ st r0, \reg
+ addi r0, r0, 8
+ }
+ .endr
+ {
+ st r0, lr
+ addi r0, r0, PTREGS_OFFSET_PC - PTREGS_OFFSET_LR
+ }
+ lnk r1
+ {
+ st r0, r1
+ addi r0, r0, PTREGS_OFFSET_EX1 - PTREGS_OFFSET_PC
+ }
+ mfspr r1, INTERRUPT_CRITICAL_SECTION
+ shli r1, r1, SPR_EX_CONTEXT_1_1__ICS_SHIFT
+ ori r1, r1, KERNEL_PL
+ {
+ st r0, r1
+ addi r0, r0, PTREGS_OFFSET_FAULTNUM - PTREGS_OFFSET_EX1
+ }
+ {
+ st r0, zero /* clear faultnum */
+ addi r0, r0, PTREGS_OFFSET_ORIG_R0 - PTREGS_OFFSET_FAULTNUM
+ }
+ {
+ st r0, zero /* clear orig_r0 */
+ addli r0, r0, -PTREGS_OFFSET_ORIG_R0 /* restore r0 to base */
+ }
+ jrp lr
+ STD_ENDPROC(get_pt_regs)
diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c
index 3696b1832566..6cdc9ba55fe0 100644
--- a/arch/tile/kernel/setup.c
+++ b/arch/tile/kernel/setup.c
@@ -912,6 +912,8 @@ void __cpuinit setup_cpu(int boot)
#endif
}
+#ifdef CONFIG_BLK_DEV_INITRD
+
static int __initdata set_initramfs_file;
static char __initdata initramfs_file[128] = "initramfs.cpio.gz";
@@ -969,6 +971,10 @@ void __init free_initrd_mem(unsigned long begin, unsigned long end)
free_bootmem(__pa(begin), end - begin);
}
+#else
+static inline void load_hv_initrd(void) {}
+#endif /* CONFIG_BLK_DEV_INITRD */
+
static void __init validate_hv(void)
{
/*
diff --git a/arch/tile/kernel/signal.c b/arch/tile/kernel/signal.c
index 1260321155f1..bedaf4e9f3a7 100644
--- a/arch/tile/kernel/signal.c
+++ b/arch/tile/kernel/signal.c
@@ -39,7 +39,6 @@
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-
SYSCALL_DEFINE3(sigaltstack, const stack_t __user *, uss,
stack_t __user *, uoss, struct pt_regs *, regs)
{
@@ -78,6 +77,13 @@ int restore_sigcontext(struct pt_regs *regs,
return err;
}
+void signal_fault(const char *type, struct pt_regs *regs,
+ void __user *frame, int sig)
+{
+ trace_unhandled_signal(type, regs, (unsigned long)frame, SIGSEGV);
+ force_sigsegv(sig, current);
+}
+
/* The assembly shim for this function arranges to ignore the return value. */
SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs)
{
@@ -105,7 +111,7 @@ SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs)
return 0;
badframe:
- force_sig(SIGSEGV, current);
+ signal_fault("bad sigreturn frame", regs, frame, 0);
return 0;
}
@@ -231,7 +237,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
return 0;
give_sigsegv:
- force_sigsegv(sig, current);
+ signal_fault("bad setup frame", regs, frame, sig);
return -EFAULT;
}
@@ -245,7 +251,6 @@ static int handle_signal(unsigned long sig, siginfo_t *info,
{
int ret;
-
/* Are we from a system call? */
if (regs->faultnum == INT_SWINT_1) {
/* If so, check system call restarting.. */
@@ -363,3 +368,118 @@ done:
/* Avoid double syscall restart if there are nested signals. */
regs->faultnum = INT_SWINT_1_SIGRETURN;
}
+
+int show_unhandled_signals = 1;
+
+static int __init crashinfo(char *str)
+{
+ unsigned long val;
+ const char *word;
+
+ if (*str == '\0')
+ val = 2;
+ else if (*str != '=' || strict_strtoul(++str, 0, &val) != 0)
+ return 0;
+ show_unhandled_signals = val;
+ switch (show_unhandled_signals) {
+ case 0:
+ word = "No";
+ break;
+ case 1:
+ word = "One-line";
+ break;
+ default:
+ word = "Detailed";
+ break;
+ }
+ pr_info("%s crash reports will be generated on the console\n", word);
+ return 1;
+}
+__setup("crashinfo", crashinfo);
+
+static void dump_mem(void __user *address)
+{
+ void __user *addr;
+ enum { region_size = 256, bytes_per_line = 16 };
+ int i, j, k;
+ int found_readable_mem = 0;
+
+ pr_err("\n");
+ if (!access_ok(VERIFY_READ, address, 1)) {
+ pr_err("Not dumping at address 0x%lx (kernel address)\n",
+ (unsigned long)address);
+ return;
+ }
+
+ addr = (void __user *)
+ (((unsigned long)address & -bytes_per_line) - region_size/2);
+ if (addr > address)
+ addr = NULL;
+ for (i = 0; i < region_size;
+ addr += bytes_per_line, i += bytes_per_line) {
+ unsigned char buf[bytes_per_line];
+ char line[100];
+ if (copy_from_user(buf, addr, bytes_per_line))
+ continue;
+ if (!found_readable_mem) {
+ pr_err("Dumping memory around address 0x%lx:\n",
+ (unsigned long)address);
+ found_readable_mem = 1;
+ }
+ j = sprintf(line, REGFMT":", (unsigned long)addr);
+ for (k = 0; k < bytes_per_line; ++k)
+ j += sprintf(&line[j], " %02x", buf[k]);
+ pr_err("%s\n", line);
+ }
+ if (!found_readable_mem)
+ pr_err("No readable memory around address 0x%lx\n",
+ (unsigned long)address);
+}
+
+void trace_unhandled_signal(const char *type, struct pt_regs *regs,
+ unsigned long address, int sig)
+{
+ struct task_struct *tsk = current;
+
+ if (show_unhandled_signals == 0)
+ return;
+
+ /* If the signal is handled, don't show it here. */
+ if (!is_global_init(tsk)) {
+ void __user *handler =
+ tsk->sighand->action[sig-1].sa.sa_handler;
+ if (handler != SIG_IGN && handler != SIG_DFL)
+ return;
+ }
+
+ /* Rate-limit the one-line output, not the detailed output. */
+ if (show_unhandled_signals <= 1 && !printk_ratelimit())
+ return;
+
+ printk("%s%s[%d]: %s at %lx pc "REGFMT" signal %d",
+ task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG,
+ tsk->comm, task_pid_nr(tsk), type, address, regs->pc, sig);
+
+ print_vma_addr(KERN_CONT " in ", regs->pc);
+
+ printk(KERN_CONT "\n");
+
+ if (show_unhandled_signals > 1) {
+ switch (sig) {
+ case SIGILL:
+ case SIGFPE:
+ case SIGSEGV:
+ case SIGBUS:
+ pr_err("User crash: signal %d,"
+ " trap %ld, address 0x%lx\n",
+ sig, regs->faultnum, address);
+ show_regs(regs);
+ dump_mem((void __user *)address);
+ break;
+ default:
+ pr_err("User crash: signal %d, trap %ld\n",
+ sig, regs->faultnum);
+ break;
+ }
+ }
+}
diff --git a/arch/tile/kernel/single_step.c b/arch/tile/kernel/single_step.c
index 84a729e06ec4..4032ca8e51b6 100644
--- a/arch/tile/kernel/single_step.c
+++ b/arch/tile/kernel/single_step.c
@@ -186,6 +186,8 @@ static tile_bundle_bits rewrite_load_store_unaligned(
.si_code = SEGV_MAPERR,
.si_addr = addr
};
+ trace_unhandled_signal("segfault", regs,
+ (unsigned long)addr, SIGSEGV);
force_sig_info(info.si_signo, &info, current);
return (tile_bundle_bits) 0;
}
@@ -196,6 +198,8 @@ static tile_bundle_bits rewrite_load_store_unaligned(
.si_code = BUS_ADRALN,
.si_addr = addr
};
+ trace_unhandled_signal("unaligned trap", regs,
+ (unsigned long)addr, SIGBUS);
force_sig_info(info.si_signo, &info, current);
return (tile_bundle_bits) 0;
}
@@ -318,6 +322,14 @@ void single_step_once(struct pt_regs *regs)
" .popsection\n"
);
+ /*
+ * Enable interrupts here to allow touching userspace and the like.
+ * The callers expect this: do_trap() already has interrupts
+ * enabled, and do_work_pending() handles functions that enable
+ * interrupts internally.
+ */
+ local_irq_enable();
+
if (state == NULL) {
/* allocate a page of writable, executable memory */
state = kmalloc(sizeof(struct single_step_state), GFP_KERNEL);
diff --git a/arch/tile/kernel/smp.c b/arch/tile/kernel/smp.c
index a4293102ef81..c52224d5ed45 100644
--- a/arch/tile/kernel/smp.c
+++ b/arch/tile/kernel/smp.c
@@ -189,12 +189,8 @@ void flush_icache_range(unsigned long start, unsigned long end)
/* Called when smp_send_reschedule() triggers IRQ_RESCHEDULE. */
static irqreturn_t handle_reschedule_ipi(int irq, void *token)
{
- /*
- * Nothing to do here; when we return from interrupt, the
- * rescheduling will occur there. But do bump the interrupt
- * profiler count in the meantime.
- */
__get_cpu_var(irq_stat).irq_resched_count++;
+ scheduler_ipi();
return IRQ_HANDLED;
}
diff --git a/arch/tile/kernel/stack.c b/arch/tile/kernel/stack.c
index dd81713a90dc..37ee4d037e0b 100644
--- a/arch/tile/kernel/stack.c
+++ b/arch/tile/kernel/stack.c
@@ -36,7 +36,7 @@
#define KBT_LOOP 3 /* Backtrace entered a loop */
/* Is address on the specified kernel stack? */
-static int in_kernel_stack(struct KBacktraceIterator *kbt, VirtualAddress sp)
+static int in_kernel_stack(struct KBacktraceIterator *kbt, unsigned long sp)
{
ulong kstack_base = (ulong) kbt->task->stack;
if (kstack_base == 0) /* corrupt task pointer; just follow stack... */
@@ -45,7 +45,7 @@ static int in_kernel_stack(struct KBacktraceIterator *kbt, VirtualAddress sp)
}
/* Is address valid for reading? */
-static int valid_address(struct KBacktraceIterator *kbt, VirtualAddress address)
+static int valid_address(struct KBacktraceIterator *kbt, unsigned long address)
{
HV_PTE *l1_pgtable = kbt->pgtable;
HV_PTE *l2_pgtable;
@@ -97,7 +97,7 @@ static int valid_address(struct KBacktraceIterator *kbt, VirtualAddress address)
}
/* Callback for backtracer; basically a glorified memcpy */
-static bool read_memory_func(void *result, VirtualAddress address,
+static bool read_memory_func(void *result, unsigned long address,
unsigned int size, void *vkbt)
{
int retval;
@@ -124,7 +124,7 @@ static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt)
{
const char *fault = NULL; /* happy compiler */
char fault_buf[64];
- VirtualAddress sp = kbt->it.sp;
+ unsigned long sp = kbt->it.sp;
struct pt_regs *p;
if (!in_kernel_stack(kbt, sp))
@@ -163,7 +163,7 @@ static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt)
}
/* Is the pc pointing to a sigreturn trampoline? */
-static int is_sigreturn(VirtualAddress pc)
+static int is_sigreturn(unsigned long pc)
{
return (pc == VDSO_BASE);
}
@@ -260,7 +260,7 @@ static void validate_stack(struct pt_regs *regs)
void KBacktraceIterator_init(struct KBacktraceIterator *kbt,
struct task_struct *t, struct pt_regs *regs)
{
- VirtualAddress pc, lr, sp, r52;
+ unsigned long pc, lr, sp, r52;
int is_current;
/*
@@ -331,7 +331,7 @@ EXPORT_SYMBOL(KBacktraceIterator_end);
void KBacktraceIterator_next(struct KBacktraceIterator *kbt)
{
- VirtualAddress old_pc = kbt->it.pc, old_sp = kbt->it.sp;
+ unsigned long old_pc = kbt->it.pc, old_sp = kbt->it.sp;
kbt->new_context = 0;
if (!backtrace_next(&kbt->it) && !KBacktraceIterator_restart(kbt)) {
kbt->end = KBT_DONE;
diff --git a/arch/tile/kernel/sys.c b/arch/tile/kernel/sys.c
index e2187d24a9b4..cb44ba7ccd2d 100644
--- a/arch/tile/kernel/sys.c
+++ b/arch/tile/kernel/sys.c
@@ -56,13 +56,6 @@ ssize_t sys32_readahead(int fd, u32 offset_lo, u32 offset_hi, u32 count)
return sys_readahead(fd, ((loff_t)offset_hi << 32) | offset_lo, count);
}
-long sys32_fadvise64(int fd, u32 offset_lo, u32 offset_hi,
- u32 len, int advice)
-{
- return sys_fadvise64_64(fd, ((loff_t)offset_hi << 32) | offset_lo,
- len, advice);
-}
-
int sys32_fadvise64_64(int fd, u32 offset_lo, u32 offset_hi,
u32 len_lo, u32 len_hi, int advice)
{
@@ -103,10 +96,8 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
#ifndef __tilegx__
/* See comments at the top of the file. */
-#define sys_fadvise64 sys32_fadvise64
#define sys_fadvise64_64 sys32_fadvise64_64
#define sys_readahead sys32_readahead
-#define sys_sync_file_range sys_sync_file_range2
#endif
/* Call the trampolines to manage pt_regs where necessary. */
diff --git a/arch/tile/kernel/tile-desc_32.c b/arch/tile/kernel/tile-desc_32.c
index 69af0e150f78..7e31a1285788 100644
--- a/arch/tile/kernel/tile-desc_32.c
+++ b/arch/tile/kernel/tile-desc_32.c
@@ -2413,12 +2413,13 @@ const struct tile_operand tile_operands[43] =
-/* Given a set of bundle bits and the lookup FSM for a specific pipe,
- * returns which instruction the bundle contains in that pipe.
+/* Given a set of bundle bits and a specific pipe, returns which
+ * instruction the bundle contains in that pipe.
*/
-static const struct tile_opcode *
-find_opcode(tile_bundle_bits bits, const unsigned short *table)
+const struct tile_opcode *
+find_opcode(tile_bundle_bits bits, tile_pipeline pipe)
{
+ const unsigned short *table = tile_bundle_decoder_fsms[pipe];
int index = 0;
while (1)
@@ -2465,7 +2466,7 @@ parse_insn_tile(tile_bundle_bits bits,
int i;
d = &decoded[num_instructions++];
- opc = find_opcode (bits, tile_bundle_decoder_fsms[pipe]);
+ opc = find_opcode (bits, (tile_pipeline)pipe);
d->opcode = opc;
/* Decode each operand, sign extending, etc. as appropriate. */
diff --git a/arch/tile/kernel/tile-desc_64.c b/arch/tile/kernel/tile-desc_64.c
new file mode 100644
index 000000000000..d57007bed77f
--- /dev/null
+++ b/arch/tile/kernel/tile-desc_64.c
@@ -0,0 +1,2200 @@
+/* This define is BFD_RELOC_##x for real bfd, or -1 for everyone else. */
+#define BFD_RELOC(x) -1
+
+/* Special registers. */
+#define TREG_LR 55
+#define TREG_SN 56
+#define TREG_ZERO 63
+
+/* FIXME: Rename this. */
+#include <asm/opcode-tile_64.h>
+
+#include <linux/stddef.h>
+
+const struct tilegx_opcode tilegx_opcodes[334] =
+{
+ { "bpt", TILEGX_OPC_BPT, 0x2, 0, TREG_ZERO, 0,
+ { { 0, }, { }, { 0, }, { 0, }, { 0, } },
+ },
+ { "info", TILEGX_OPC_INFO, 0xf, 1, TREG_ZERO, 1,
+ { { 0 }, { 1 }, { 2 }, { 3 }, { 0, } },
+ },
+ { "infol", TILEGX_OPC_INFOL, 0x3, 1, TREG_ZERO, 1,
+ { { 4 }, { 5 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "move", TILEGX_OPC_MOVE, 0xf, 2, TREG_ZERO, 1,
+ { { 6, 7 }, { 8, 9 }, { 10, 11 }, { 12, 13 }, { 0, } },
+ },
+ { "movei", TILEGX_OPC_MOVEI, 0xf, 2, TREG_ZERO, 1,
+ { { 6, 0 }, { 8, 1 }, { 10, 2 }, { 12, 3 }, { 0, } },
+ },
+ { "moveli", TILEGX_OPC_MOVELI, 0x3, 2, TREG_ZERO, 1,
+ { { 6, 4 }, { 8, 5 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "prefetch", TILEGX_OPC_PREFETCH, 0x12, 1, TREG_ZERO, 1,
+ { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } },
+ },
+ { "prefetch_add_l1", TILEGX_OPC_PREFETCH_ADD_L1, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "prefetch_add_l1_fault", TILEGX_OPC_PREFETCH_ADD_L1_FAULT, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "prefetch_add_l2", TILEGX_OPC_PREFETCH_ADD_L2, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "prefetch_add_l2_fault", TILEGX_OPC_PREFETCH_ADD_L2_FAULT, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "prefetch_add_l3", TILEGX_OPC_PREFETCH_ADD_L3, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "prefetch_add_l3_fault", TILEGX_OPC_PREFETCH_ADD_L3_FAULT, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "prefetch_l1", TILEGX_OPC_PREFETCH_L1, 0x12, 1, TREG_ZERO, 1,
+ { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } },
+ },
+ { "prefetch_l1_fault", TILEGX_OPC_PREFETCH_L1_FAULT, 0x12, 1, TREG_ZERO, 1,
+ { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } },
+ },
+ { "prefetch_l2", TILEGX_OPC_PREFETCH_L2, 0x12, 1, TREG_ZERO, 1,
+ { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } },
+ },
+ { "prefetch_l2_fault", TILEGX_OPC_PREFETCH_L2_FAULT, 0x12, 1, TREG_ZERO, 1,
+ { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } },
+ },
+ { "prefetch_l3", TILEGX_OPC_PREFETCH_L3, 0x12, 1, TREG_ZERO, 1,
+ { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } },
+ },
+ { "prefetch_l3_fault", TILEGX_OPC_PREFETCH_L3_FAULT, 0x12, 1, TREG_ZERO, 1,
+ { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } },
+ },
+ { "raise", TILEGX_OPC_RAISE, 0x2, 0, TREG_ZERO, 1,
+ { { 0, }, { }, { 0, }, { 0, }, { 0, } },
+ },
+ { "add", TILEGX_OPC_ADD, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "addi", TILEGX_OPC_ADDI, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 0 }, { 8, 9, 1 }, { 10, 11, 2 }, { 12, 13, 3 }, { 0, } },
+ },
+ { "addli", TILEGX_OPC_ADDLI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 4 }, { 8, 9, 5 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "addx", TILEGX_OPC_ADDX, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "addxi", TILEGX_OPC_ADDXI, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 0 }, { 8, 9, 1 }, { 10, 11, 2 }, { 12, 13, 3 }, { 0, } },
+ },
+ { "addxli", TILEGX_OPC_ADDXLI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 4 }, { 8, 9, 5 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "addxsc", TILEGX_OPC_ADDXSC, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "and", TILEGX_OPC_AND, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "andi", TILEGX_OPC_ANDI, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 0 }, { 8, 9, 1 }, { 10, 11, 2 }, { 12, 13, 3 }, { 0, } },
+ },
+ { "beqz", TILEGX_OPC_BEQZ, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "beqzt", TILEGX_OPC_BEQZT, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "bfexts", TILEGX_OPC_BFEXTS, 0x1, 4, TREG_ZERO, 1,
+ { { 6, 7, 21, 22 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "bfextu", TILEGX_OPC_BFEXTU, 0x1, 4, TREG_ZERO, 1,
+ { { 6, 7, 21, 22 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "bfins", TILEGX_OPC_BFINS, 0x1, 4, TREG_ZERO, 1,
+ { { 23, 7, 21, 22 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "bgez", TILEGX_OPC_BGEZ, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "bgezt", TILEGX_OPC_BGEZT, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "bgtz", TILEGX_OPC_BGTZ, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "bgtzt", TILEGX_OPC_BGTZT, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "blbc", TILEGX_OPC_BLBC, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "blbct", TILEGX_OPC_BLBCT, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "blbs", TILEGX_OPC_BLBS, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "blbst", TILEGX_OPC_BLBST, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "blez", TILEGX_OPC_BLEZ, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "blezt", TILEGX_OPC_BLEZT, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "bltz", TILEGX_OPC_BLTZ, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "bltzt", TILEGX_OPC_BLTZT, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "bnez", TILEGX_OPC_BNEZ, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "bnezt", TILEGX_OPC_BNEZT, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "clz", TILEGX_OPC_CLZ, 0x5, 2, TREG_ZERO, 1,
+ { { 6, 7 }, { 0, }, { 10, 11 }, { 0, }, { 0, } },
+ },
+ { "cmoveqz", TILEGX_OPC_CMOVEQZ, 0x5, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+ },
+ { "cmovnez", TILEGX_OPC_CMOVNEZ, 0x5, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+ },
+ { "cmpeq", TILEGX_OPC_CMPEQ, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "cmpeqi", TILEGX_OPC_CMPEQI, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 0 }, { 8, 9, 1 }, { 10, 11, 2 }, { 12, 13, 3 }, { 0, } },
+ },
+ { "cmpexch", TILEGX_OPC_CMPEXCH, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "cmpexch4", TILEGX_OPC_CMPEXCH4, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "cmples", TILEGX_OPC_CMPLES, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "cmpleu", TILEGX_OPC_CMPLEU, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "cmplts", TILEGX_OPC_CMPLTS, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "cmpltsi", TILEGX_OPC_CMPLTSI, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 0 }, { 8, 9, 1 }, { 10, 11, 2 }, { 12, 13, 3 }, { 0, } },
+ },
+ { "cmpltu", TILEGX_OPC_CMPLTU, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "cmpltui", TILEGX_OPC_CMPLTUI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "cmpne", TILEGX_OPC_CMPNE, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "cmul", TILEGX_OPC_CMUL, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "cmula", TILEGX_OPC_CMULA, 0x1, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "cmulaf", TILEGX_OPC_CMULAF, 0x1, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "cmulf", TILEGX_OPC_CMULF, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "cmulfr", TILEGX_OPC_CMULFR, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "cmulh", TILEGX_OPC_CMULH, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "cmulhr", TILEGX_OPC_CMULHR, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "crc32_32", TILEGX_OPC_CRC32_32, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "crc32_8", TILEGX_OPC_CRC32_8, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "ctz", TILEGX_OPC_CTZ, 0x5, 2, TREG_ZERO, 1,
+ { { 6, 7 }, { 0, }, { 10, 11 }, { 0, }, { 0, } },
+ },
+ { "dblalign", TILEGX_OPC_DBLALIGN, 0x1, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "dblalign2", TILEGX_OPC_DBLALIGN2, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "dblalign4", TILEGX_OPC_DBLALIGN4, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "dblalign6", TILEGX_OPC_DBLALIGN6, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "drain", TILEGX_OPC_DRAIN, 0x2, 0, TREG_ZERO, 0,
+ { { 0, }, { }, { 0, }, { 0, }, { 0, } },
+ },
+ { "dtlbpr", TILEGX_OPC_DTLBPR, 0x2, 1, TREG_ZERO, 1,
+ { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "exch", TILEGX_OPC_EXCH, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "exch4", TILEGX_OPC_EXCH4, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "fdouble_add_flags", TILEGX_OPC_FDOUBLE_ADD_FLAGS, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "fdouble_addsub", TILEGX_OPC_FDOUBLE_ADDSUB, 0x1, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "fdouble_mul_flags", TILEGX_OPC_FDOUBLE_MUL_FLAGS, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "fdouble_pack1", TILEGX_OPC_FDOUBLE_PACK1, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "fdouble_pack2", TILEGX_OPC_FDOUBLE_PACK2, 0x1, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "fdouble_sub_flags", TILEGX_OPC_FDOUBLE_SUB_FLAGS, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "fdouble_unpack_max", TILEGX_OPC_FDOUBLE_UNPACK_MAX, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "fdouble_unpack_min", TILEGX_OPC_FDOUBLE_UNPACK_MIN, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "fetchadd", TILEGX_OPC_FETCHADD, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "fetchadd4", TILEGX_OPC_FETCHADD4, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "fetchaddgez", TILEGX_OPC_FETCHADDGEZ, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "fetchaddgez4", TILEGX_OPC_FETCHADDGEZ4, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "fetchand", TILEGX_OPC_FETCHAND, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "fetchand4", TILEGX_OPC_FETCHAND4, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "fetchor", TILEGX_OPC_FETCHOR, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "fetchor4", TILEGX_OPC_FETCHOR4, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "finv", TILEGX_OPC_FINV, 0x2, 1, TREG_ZERO, 1,
+ { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "flush", TILEGX_OPC_FLUSH, 0x2, 1, TREG_ZERO, 1,
+ { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "flushwb", TILEGX_OPC_FLUSHWB, 0x2, 0, TREG_ZERO, 1,
+ { { 0, }, { }, { 0, }, { 0, }, { 0, } },
+ },
+ { "fnop", TILEGX_OPC_FNOP, 0xf, 0, TREG_ZERO, 1,
+ { { }, { }, { }, { }, { 0, } },
+ },
+ { "fsingle_add1", TILEGX_OPC_FSINGLE_ADD1, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "fsingle_addsub2", TILEGX_OPC_FSINGLE_ADDSUB2, 0x1, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "fsingle_mul1", TILEGX_OPC_FSINGLE_MUL1, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "fsingle_mul2", TILEGX_OPC_FSINGLE_MUL2, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "fsingle_pack1", TILEGX_OPC_FSINGLE_PACK1, 0x5, 2, TREG_ZERO, 1,
+ { { 6, 7 }, { 0, }, { 10, 11 }, { 0, }, { 0, } },
+ },
+ { "fsingle_pack2", TILEGX_OPC_FSINGLE_PACK2, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "fsingle_sub1", TILEGX_OPC_FSINGLE_SUB1, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "icoh", TILEGX_OPC_ICOH, 0x2, 1, TREG_ZERO, 1,
+ { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "ill", TILEGX_OPC_ILL, 0xa, 0, TREG_ZERO, 1,
+ { { 0, }, { }, { 0, }, { }, { 0, } },
+ },
+ { "inv", TILEGX_OPC_INV, 0x2, 1, TREG_ZERO, 1,
+ { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "iret", TILEGX_OPC_IRET, 0x2, 0, TREG_ZERO, 1,
+ { { 0, }, { }, { 0, }, { 0, }, { 0, } },
+ },
+ { "j", TILEGX_OPC_J, 0x2, 1, TREG_ZERO, 1,
+ { { 0, }, { 25 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "jal", TILEGX_OPC_JAL, 0x2, 1, TREG_LR, 1,
+ { { 0, }, { 25 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "jalr", TILEGX_OPC_JALR, 0xa, 1, TREG_LR, 1,
+ { { 0, }, { 9 }, { 0, }, { 13 }, { 0, } },
+ },
+ { "jalrp", TILEGX_OPC_JALRP, 0xa, 1, TREG_LR, 1,
+ { { 0, }, { 9 }, { 0, }, { 13 }, { 0, } },
+ },
+ { "jr", TILEGX_OPC_JR, 0xa, 1, TREG_ZERO, 1,
+ { { 0, }, { 9 }, { 0, }, { 13 }, { 0, } },
+ },
+ { "jrp", TILEGX_OPC_JRP, 0xa, 1, TREG_ZERO, 1,
+ { { 0, }, { 9 }, { 0, }, { 13 }, { 0, } },
+ },
+ { "ld", TILEGX_OPC_LD, 0x12, 2, TREG_ZERO, 1,
+ { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } },
+ },
+ { "ld1s", TILEGX_OPC_LD1S, 0x12, 2, TREG_ZERO, 1,
+ { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } },
+ },
+ { "ld1s_add", TILEGX_OPC_LD1S_ADD, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "ld1u", TILEGX_OPC_LD1U, 0x12, 2, TREG_ZERO, 1,
+ { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } },
+ },
+ { "ld1u_add", TILEGX_OPC_LD1U_ADD, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "ld2s", TILEGX_OPC_LD2S, 0x12, 2, TREG_ZERO, 1,
+ { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } },
+ },
+ { "ld2s_add", TILEGX_OPC_LD2S_ADD, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "ld2u", TILEGX_OPC_LD2U, 0x12, 2, TREG_ZERO, 1,
+ { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } },
+ },
+ { "ld2u_add", TILEGX_OPC_LD2U_ADD, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "ld4s", TILEGX_OPC_LD4S, 0x12, 2, TREG_ZERO, 1,
+ { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } },
+ },
+ { "ld4s_add", TILEGX_OPC_LD4S_ADD, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "ld4u", TILEGX_OPC_LD4U, 0x12, 2, TREG_ZERO, 1,
+ { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } },
+ },
+ { "ld4u_add", TILEGX_OPC_LD4U_ADD, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "ld_add", TILEGX_OPC_LD_ADD, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "ldna", TILEGX_OPC_LDNA, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "ldna_add", TILEGX_OPC_LDNA_ADD, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "ldnt", TILEGX_OPC_LDNT, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "ldnt1s", TILEGX_OPC_LDNT1S, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "ldnt1s_add", TILEGX_OPC_LDNT1S_ADD, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "ldnt1u", TILEGX_OPC_LDNT1U, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "ldnt1u_add", TILEGX_OPC_LDNT1U_ADD, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "ldnt2s", TILEGX_OPC_LDNT2S, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "ldnt2s_add", TILEGX_OPC_LDNT2S_ADD, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "ldnt2u", TILEGX_OPC_LDNT2U, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "ldnt2u_add", TILEGX_OPC_LDNT2U_ADD, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "ldnt4s", TILEGX_OPC_LDNT4S, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "ldnt4s_add", TILEGX_OPC_LDNT4S_ADD, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "ldnt4u", TILEGX_OPC_LDNT4U, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "ldnt4u_add", TILEGX_OPC_LDNT4U_ADD, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "ldnt_add", TILEGX_OPC_LDNT_ADD, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "lnk", TILEGX_OPC_LNK, 0xa, 1, TREG_ZERO, 1,
+ { { 0, }, { 8 }, { 0, }, { 12 }, { 0, } },
+ },
+ { "mf", TILEGX_OPC_MF, 0x2, 0, TREG_ZERO, 1,
+ { { 0, }, { }, { 0, }, { 0, }, { 0, } },
+ },
+ { "mfspr", TILEGX_OPC_MFSPR, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 8, 27 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "mm", TILEGX_OPC_MM, 0x1, 4, TREG_ZERO, 1,
+ { { 23, 7, 21, 22 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "mnz", TILEGX_OPC_MNZ, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "mtspr", TILEGX_OPC_MTSPR, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 28, 9 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "mul_hs_hs", TILEGX_OPC_MUL_HS_HS, 0x5, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 10, 11, 18 }, { 0, }, { 0, } },
+ },
+ { "mul_hs_hu", TILEGX_OPC_MUL_HS_HU, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "mul_hs_ls", TILEGX_OPC_MUL_HS_LS, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "mul_hs_lu", TILEGX_OPC_MUL_HS_LU, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "mul_hu_hu", TILEGX_OPC_MUL_HU_HU, 0x5, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 10, 11, 18 }, { 0, }, { 0, } },
+ },
+ { "mul_hu_ls", TILEGX_OPC_MUL_HU_LS, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "mul_hu_lu", TILEGX_OPC_MUL_HU_LU, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "mul_ls_ls", TILEGX_OPC_MUL_LS_LS, 0x5, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 10, 11, 18 }, { 0, }, { 0, } },
+ },
+ { "mul_ls_lu", TILEGX_OPC_MUL_LS_LU, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "mul_lu_lu", TILEGX_OPC_MUL_LU_LU, 0x5, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 10, 11, 18 }, { 0, }, { 0, } },
+ },
+ { "mula_hs_hs", TILEGX_OPC_MULA_HS_HS, 0x5, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+ },
+ { "mula_hs_hu", TILEGX_OPC_MULA_HS_HU, 0x1, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "mula_hs_ls", TILEGX_OPC_MULA_HS_LS, 0x1, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "mula_hs_lu", TILEGX_OPC_MULA_HS_LU, 0x1, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "mula_hu_hu", TILEGX_OPC_MULA_HU_HU, 0x5, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+ },
+ { "mula_hu_ls", TILEGX_OPC_MULA_HU_LS, 0x1, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "mula_hu_lu", TILEGX_OPC_MULA_HU_LU, 0x1, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "mula_ls_ls", TILEGX_OPC_MULA_LS_LS, 0x5, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+ },
+ { "mula_ls_lu", TILEGX_OPC_MULA_LS_LU, 0x1, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "mula_lu_lu", TILEGX_OPC_MULA_LU_LU, 0x5, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+ },
+ { "mulax", TILEGX_OPC_MULAX, 0x5, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } },
+ },
+ { "mulx", TILEGX_OPC_MULX, 0x5, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 10, 11, 18 }, { 0, }, { 0, } },
+ },
+ { "mz", TILEGX_OPC_MZ, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "nap", TILEGX_OPC_NAP, 0x2, 0, TREG_ZERO, 0,
+ { { 0, }, { }, { 0, }, { 0, }, { 0, } },
+ },
+ { "nop", TILEGX_OPC_NOP, 0xf, 0, TREG_ZERO, 1,
+ { { }, { }, { }, { }, { 0, } },
+ },
+ { "nor", TILEGX_OPC_NOR, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "or", TILEGX_OPC_OR, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "ori", TILEGX_OPC_ORI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "pcnt", TILEGX_OPC_PCNT, 0x5, 2, TREG_ZERO, 1,
+ { { 6, 7 }, { 0, }, { 10, 11 }, { 0, }, { 0, } },
+ },
+ { "revbits", TILEGX_OPC_REVBITS, 0x5, 2, TREG_ZERO, 1,
+ { { 6, 7 }, { 0, }, { 10, 11 }, { 0, }, { 0, } },
+ },
+ { "revbytes", TILEGX_OPC_REVBYTES, 0x5, 2, TREG_ZERO, 1,
+ { { 6, 7 }, { 0, }, { 10, 11 }, { 0, }, { 0, } },
+ },
+ { "rotl", TILEGX_OPC_ROTL, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "rotli", TILEGX_OPC_ROTLI, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 29 }, { 8, 9, 30 }, { 10, 11, 31 }, { 12, 13, 32 }, { 0, } },
+ },
+ { "shl", TILEGX_OPC_SHL, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "shl16insli", TILEGX_OPC_SHL16INSLI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 4 }, { 8, 9, 5 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "shl1add", TILEGX_OPC_SHL1ADD, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "shl1addx", TILEGX_OPC_SHL1ADDX, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "shl2add", TILEGX_OPC_SHL2ADD, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "shl2addx", TILEGX_OPC_SHL2ADDX, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "shl3add", TILEGX_OPC_SHL3ADD, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "shl3addx", TILEGX_OPC_SHL3ADDX, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "shli", TILEGX_OPC_SHLI, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 29 }, { 8, 9, 30 }, { 10, 11, 31 }, { 12, 13, 32 }, { 0, } },
+ },
+ { "shlx", TILEGX_OPC_SHLX, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "shlxi", TILEGX_OPC_SHLXI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "shrs", TILEGX_OPC_SHRS, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "shrsi", TILEGX_OPC_SHRSI, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 29 }, { 8, 9, 30 }, { 10, 11, 31 }, { 12, 13, 32 }, { 0, } },
+ },
+ { "shru", TILEGX_OPC_SHRU, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "shrui", TILEGX_OPC_SHRUI, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 29 }, { 8, 9, 30 }, { 10, 11, 31 }, { 12, 13, 32 }, { 0, } },
+ },
+ { "shrux", TILEGX_OPC_SHRUX, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "shruxi", TILEGX_OPC_SHRUXI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "shufflebytes", TILEGX_OPC_SHUFFLEBYTES, 0x1, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "st", TILEGX_OPC_ST, 0x12, 2, TREG_ZERO, 1,
+ { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 14, 33 } },
+ },
+ { "st1", TILEGX_OPC_ST1, 0x12, 2, TREG_ZERO, 1,
+ { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 14, 33 } },
+ },
+ { "st1_add", TILEGX_OPC_ST1_ADD, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "st2", TILEGX_OPC_ST2, 0x12, 2, TREG_ZERO, 1,
+ { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 14, 33 } },
+ },
+ { "st2_add", TILEGX_OPC_ST2_ADD, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "st4", TILEGX_OPC_ST4, 0x12, 2, TREG_ZERO, 1,
+ { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 14, 33 } },
+ },
+ { "st4_add", TILEGX_OPC_ST4_ADD, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "st_add", TILEGX_OPC_ST_ADD, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "stnt", TILEGX_OPC_STNT, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "stnt1", TILEGX_OPC_STNT1, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "stnt1_add", TILEGX_OPC_STNT1_ADD, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "stnt2", TILEGX_OPC_STNT2, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "stnt2_add", TILEGX_OPC_STNT2_ADD, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "stnt4", TILEGX_OPC_STNT4, 0x2, 2, TREG_ZERO, 1,
+ { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "stnt4_add", TILEGX_OPC_STNT4_ADD, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "stnt_add", TILEGX_OPC_STNT_ADD, 0x2, 3, TREG_ZERO, 1,
+ { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "sub", TILEGX_OPC_SUB, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "subx", TILEGX_OPC_SUBX, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "subxsc", TILEGX_OPC_SUBXSC, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "swint0", TILEGX_OPC_SWINT0, 0x2, 0, TREG_ZERO, 0,
+ { { 0, }, { }, { 0, }, { 0, }, { 0, } },
+ },
+ { "swint1", TILEGX_OPC_SWINT1, 0x2, 0, TREG_ZERO, 0,
+ { { 0, }, { }, { 0, }, { 0, }, { 0, } },
+ },
+ { "swint2", TILEGX_OPC_SWINT2, 0x2, 0, TREG_ZERO, 0,
+ { { 0, }, { }, { 0, }, { 0, }, { 0, } },
+ },
+ { "swint3", TILEGX_OPC_SWINT3, 0x2, 0, TREG_ZERO, 0,
+ { { 0, }, { }, { 0, }, { 0, }, { 0, } },
+ },
+ { "tblidxb0", TILEGX_OPC_TBLIDXB0, 0x5, 2, TREG_ZERO, 1,
+ { { 23, 7 }, { 0, }, { 24, 11 }, { 0, }, { 0, } },
+ },
+ { "tblidxb1", TILEGX_OPC_TBLIDXB1, 0x5, 2, TREG_ZERO, 1,
+ { { 23, 7 }, { 0, }, { 24, 11 }, { 0, }, { 0, } },
+ },
+ { "tblidxb2", TILEGX_OPC_TBLIDXB2, 0x5, 2, TREG_ZERO, 1,
+ { { 23, 7 }, { 0, }, { 24, 11 }, { 0, }, { 0, } },
+ },
+ { "tblidxb3", TILEGX_OPC_TBLIDXB3, 0x5, 2, TREG_ZERO, 1,
+ { { 23, 7 }, { 0, }, { 24, 11 }, { 0, }, { 0, } },
+ },
+ { "v1add", TILEGX_OPC_V1ADD, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1addi", TILEGX_OPC_V1ADDI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1adduc", TILEGX_OPC_V1ADDUC, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1adiffu", TILEGX_OPC_V1ADIFFU, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1avgu", TILEGX_OPC_V1AVGU, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1cmpeq", TILEGX_OPC_V1CMPEQ, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1cmpeqi", TILEGX_OPC_V1CMPEQI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1cmples", TILEGX_OPC_V1CMPLES, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1cmpleu", TILEGX_OPC_V1CMPLEU, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1cmplts", TILEGX_OPC_V1CMPLTS, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1cmpltsi", TILEGX_OPC_V1CMPLTSI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1cmpltu", TILEGX_OPC_V1CMPLTU, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1cmpltui", TILEGX_OPC_V1CMPLTUI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1cmpne", TILEGX_OPC_V1CMPNE, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1ddotpu", TILEGX_OPC_V1DDOTPU, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1ddotpua", TILEGX_OPC_V1DDOTPUA, 0x1, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1ddotpus", TILEGX_OPC_V1DDOTPUS, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1ddotpusa", TILEGX_OPC_V1DDOTPUSA, 0x1, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1dotp", TILEGX_OPC_V1DOTP, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1dotpa", TILEGX_OPC_V1DOTPA, 0x1, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1dotpu", TILEGX_OPC_V1DOTPU, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1dotpua", TILEGX_OPC_V1DOTPUA, 0x1, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1dotpus", TILEGX_OPC_V1DOTPUS, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1dotpusa", TILEGX_OPC_V1DOTPUSA, 0x1, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1int_h", TILEGX_OPC_V1INT_H, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1int_l", TILEGX_OPC_V1INT_L, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1maxu", TILEGX_OPC_V1MAXU, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1maxui", TILEGX_OPC_V1MAXUI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1minu", TILEGX_OPC_V1MINU, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1minui", TILEGX_OPC_V1MINUI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1mnz", TILEGX_OPC_V1MNZ, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1multu", TILEGX_OPC_V1MULTU, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1mulu", TILEGX_OPC_V1MULU, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1mulus", TILEGX_OPC_V1MULUS, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1mz", TILEGX_OPC_V1MZ, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1sadau", TILEGX_OPC_V1SADAU, 0x1, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1sadu", TILEGX_OPC_V1SADU, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1shl", TILEGX_OPC_V1SHL, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1shli", TILEGX_OPC_V1SHLI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1shrs", TILEGX_OPC_V1SHRS, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1shrsi", TILEGX_OPC_V1SHRSI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1shru", TILEGX_OPC_V1SHRU, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1shrui", TILEGX_OPC_V1SHRUI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1sub", TILEGX_OPC_V1SUB, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v1subuc", TILEGX_OPC_V1SUBUC, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2add", TILEGX_OPC_V2ADD, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2addi", TILEGX_OPC_V2ADDI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2addsc", TILEGX_OPC_V2ADDSC, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2adiffs", TILEGX_OPC_V2ADIFFS, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2avgs", TILEGX_OPC_V2AVGS, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2cmpeq", TILEGX_OPC_V2CMPEQ, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2cmpeqi", TILEGX_OPC_V2CMPEQI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2cmples", TILEGX_OPC_V2CMPLES, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2cmpleu", TILEGX_OPC_V2CMPLEU, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2cmplts", TILEGX_OPC_V2CMPLTS, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2cmpltsi", TILEGX_OPC_V2CMPLTSI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2cmpltu", TILEGX_OPC_V2CMPLTU, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2cmpltui", TILEGX_OPC_V2CMPLTUI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2cmpne", TILEGX_OPC_V2CMPNE, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2dotp", TILEGX_OPC_V2DOTP, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2dotpa", TILEGX_OPC_V2DOTPA, 0x1, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2int_h", TILEGX_OPC_V2INT_H, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2int_l", TILEGX_OPC_V2INT_L, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2maxs", TILEGX_OPC_V2MAXS, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2maxsi", TILEGX_OPC_V2MAXSI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2mins", TILEGX_OPC_V2MINS, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2minsi", TILEGX_OPC_V2MINSI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2mnz", TILEGX_OPC_V2MNZ, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2mulfsc", TILEGX_OPC_V2MULFSC, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2muls", TILEGX_OPC_V2MULS, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2mults", TILEGX_OPC_V2MULTS, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2mz", TILEGX_OPC_V2MZ, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2packh", TILEGX_OPC_V2PACKH, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2packl", TILEGX_OPC_V2PACKL, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2packuc", TILEGX_OPC_V2PACKUC, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2sadas", TILEGX_OPC_V2SADAS, 0x1, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2sadau", TILEGX_OPC_V2SADAU, 0x1, 3, TREG_ZERO, 1,
+ { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2sads", TILEGX_OPC_V2SADS, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2sadu", TILEGX_OPC_V2SADU, 0x1, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2shl", TILEGX_OPC_V2SHL, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2shli", TILEGX_OPC_V2SHLI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2shlsc", TILEGX_OPC_V2SHLSC, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2shrs", TILEGX_OPC_V2SHRS, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2shrsi", TILEGX_OPC_V2SHRSI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2shru", TILEGX_OPC_V2SHRU, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2shrui", TILEGX_OPC_V2SHRUI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2sub", TILEGX_OPC_V2SUB, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v2subsc", TILEGX_OPC_V2SUBSC, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v4add", TILEGX_OPC_V4ADD, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v4addsc", TILEGX_OPC_V4ADDSC, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v4int_h", TILEGX_OPC_V4INT_H, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v4int_l", TILEGX_OPC_V4INT_L, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v4packsc", TILEGX_OPC_V4PACKSC, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v4shl", TILEGX_OPC_V4SHL, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v4shlsc", TILEGX_OPC_V4SHLSC, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v4shrs", TILEGX_OPC_V4SHRS, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v4shru", TILEGX_OPC_V4SHRU, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v4sub", TILEGX_OPC_V4SUB, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "v4subsc", TILEGX_OPC_V4SUBSC, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "wh64", TILEGX_OPC_WH64, 0x2, 1, TREG_ZERO, 1,
+ { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } },
+ },
+ { "xor", TILEGX_OPC_XOR, 0xf, 3, TREG_ZERO, 1,
+ { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } },
+ },
+ { "xori", TILEGX_OPC_XORI, 0x3, 3, TREG_ZERO, 1,
+ { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } },
+ },
+ { NULL, TILEGX_OPC_NONE, 0, 0, TREG_ZERO, 0, { { 0, } },
+ }
+};
+#define BITFIELD(start, size) ((start) | (((1 << (size)) - 1) << 6))
+#define CHILD(array_index) (TILEGX_OPC_NONE + (array_index))
+
+static const unsigned short decode_X0_fsm[936] =
+{
+ BITFIELD(22, 9) /* index 0 */,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+ CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+ CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+ CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+ CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+ CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+ CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+ CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+ CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+ CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+ CHILD(513), CHILD(513), CHILD(513), CHILD(513), TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_BFEXTS,
+ TILEGX_OPC_BFEXTS, TILEGX_OPC_BFEXTS, TILEGX_OPC_BFEXTS, TILEGX_OPC_BFEXTU,
+ TILEGX_OPC_BFEXTU, TILEGX_OPC_BFEXTU, TILEGX_OPC_BFEXTU, TILEGX_OPC_BFINS,
+ TILEGX_OPC_BFINS, TILEGX_OPC_BFINS, TILEGX_OPC_BFINS, TILEGX_OPC_MM,
+ TILEGX_OPC_MM, TILEGX_OPC_MM, TILEGX_OPC_MM, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, CHILD(528), CHILD(578),
+ CHILD(583), CHILD(588), CHILD(593), CHILD(598), TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, CHILD(603), CHILD(620), CHILD(637), CHILD(654), CHILD(671),
+ CHILD(703), CHILD(797), CHILD(814), CHILD(831), CHILD(848), CHILD(865),
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, CHILD(889), TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+ CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+ CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+ CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+ CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+ CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+ CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+ CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+ CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+ CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+ CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906),
+ BITFIELD(6, 2) /* index 513 */,
+ TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, CHILD(518),
+ BITFIELD(8, 2) /* index 518 */,
+ TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, CHILD(523),
+ BITFIELD(10, 2) /* index 523 */,
+ TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_MOVELI,
+ BITFIELD(20, 2) /* index 528 */,
+ TILEGX_OPC_NONE, CHILD(533), TILEGX_OPC_ADDXI, CHILD(548),
+ BITFIELD(6, 2) /* index 533 */,
+ TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(538),
+ BITFIELD(8, 2) /* index 538 */,
+ TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(543),
+ BITFIELD(10, 2) /* index 543 */,
+ TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_MOVEI,
+ BITFIELD(0, 2) /* index 548 */,
+ TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(553),
+ BITFIELD(2, 2) /* index 553 */,
+ TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(558),
+ BITFIELD(4, 2) /* index 558 */,
+ TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(563),
+ BITFIELD(6, 2) /* index 563 */,
+ TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(568),
+ BITFIELD(8, 2) /* index 568 */,
+ TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(573),
+ BITFIELD(10, 2) /* index 573 */,
+ TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_INFO,
+ BITFIELD(20, 2) /* index 578 */,
+ TILEGX_OPC_CMPEQI, TILEGX_OPC_CMPLTSI, TILEGX_OPC_CMPLTUI, TILEGX_OPC_ORI,
+ BITFIELD(20, 2) /* index 583 */,
+ TILEGX_OPC_V1ADDI, TILEGX_OPC_V1CMPEQI, TILEGX_OPC_V1CMPLTSI,
+ TILEGX_OPC_V1CMPLTUI,
+ BITFIELD(20, 2) /* index 588 */,
+ TILEGX_OPC_V1MAXUI, TILEGX_OPC_V1MINUI, TILEGX_OPC_V2ADDI,
+ TILEGX_OPC_V2CMPEQI,
+ BITFIELD(20, 2) /* index 593 */,
+ TILEGX_OPC_V2CMPLTSI, TILEGX_OPC_V2CMPLTUI, TILEGX_OPC_V2MAXSI,
+ TILEGX_OPC_V2MINSI,
+ BITFIELD(20, 2) /* index 598 */,
+ TILEGX_OPC_XORI, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ BITFIELD(18, 4) /* index 603 */,
+ TILEGX_OPC_NONE, TILEGX_OPC_ADDXSC, TILEGX_OPC_ADDX, TILEGX_OPC_ADD,
+ TILEGX_OPC_AND, TILEGX_OPC_CMOVEQZ, TILEGX_OPC_CMOVNEZ, TILEGX_OPC_CMPEQ,
+ TILEGX_OPC_CMPLES, TILEGX_OPC_CMPLEU, TILEGX_OPC_CMPLTS, TILEGX_OPC_CMPLTU,
+ TILEGX_OPC_CMPNE, TILEGX_OPC_CMULAF, TILEGX_OPC_CMULA, TILEGX_OPC_CMULFR,
+ BITFIELD(18, 4) /* index 620 */,
+ TILEGX_OPC_CMULF, TILEGX_OPC_CMULHR, TILEGX_OPC_CMULH, TILEGX_OPC_CMUL,
+ TILEGX_OPC_CRC32_32, TILEGX_OPC_CRC32_8, TILEGX_OPC_DBLALIGN2,
+ TILEGX_OPC_DBLALIGN4, TILEGX_OPC_DBLALIGN6, TILEGX_OPC_DBLALIGN,
+ TILEGX_OPC_FDOUBLE_ADDSUB, TILEGX_OPC_FDOUBLE_ADD_FLAGS,
+ TILEGX_OPC_FDOUBLE_MUL_FLAGS, TILEGX_OPC_FDOUBLE_PACK1,
+ TILEGX_OPC_FDOUBLE_PACK2, TILEGX_OPC_FDOUBLE_SUB_FLAGS,
+ BITFIELD(18, 4) /* index 637 */,
+ TILEGX_OPC_FDOUBLE_UNPACK_MAX, TILEGX_OPC_FDOUBLE_UNPACK_MIN,
+ TILEGX_OPC_FSINGLE_ADD1, TILEGX_OPC_FSINGLE_ADDSUB2,
+ TILEGX_OPC_FSINGLE_MUL1, TILEGX_OPC_FSINGLE_MUL2, TILEGX_OPC_FSINGLE_PACK2,
+ TILEGX_OPC_FSINGLE_SUB1, TILEGX_OPC_MNZ, TILEGX_OPC_MULAX,
+ TILEGX_OPC_MULA_HS_HS, TILEGX_OPC_MULA_HS_HU, TILEGX_OPC_MULA_HS_LS,
+ TILEGX_OPC_MULA_HS_LU, TILEGX_OPC_MULA_HU_HU, TILEGX_OPC_MULA_HU_LS,
+ BITFIELD(18, 4) /* index 654 */,
+ TILEGX_OPC_MULA_HU_LU, TILEGX_OPC_MULA_LS_LS, TILEGX_OPC_MULA_LS_LU,
+ TILEGX_OPC_MULA_LU_LU, TILEGX_OPC_MULX, TILEGX_OPC_MUL_HS_HS,
+ TILEGX_OPC_MUL_HS_HU, TILEGX_OPC_MUL_HS_LS, TILEGX_OPC_MUL_HS_LU,
+ TILEGX_OPC_MUL_HU_HU, TILEGX_OPC_MUL_HU_LS, TILEGX_OPC_MUL_HU_LU,
+ TILEGX_OPC_MUL_LS_LS, TILEGX_OPC_MUL_LS_LU, TILEGX_OPC_MUL_LU_LU,
+ TILEGX_OPC_MZ,
+ BITFIELD(18, 4) /* index 671 */,
+ TILEGX_OPC_NOR, CHILD(688), TILEGX_OPC_ROTL, TILEGX_OPC_SHL1ADDX,
+ TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL2ADDX, TILEGX_OPC_SHL2ADD,
+ TILEGX_OPC_SHL3ADDX, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHLX, TILEGX_OPC_SHL,
+ TILEGX_OPC_SHRS, TILEGX_OPC_SHRUX, TILEGX_OPC_SHRU, TILEGX_OPC_SHUFFLEBYTES,
+ TILEGX_OPC_SUBXSC,
+ BITFIELD(12, 2) /* index 688 */,
+ TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(693),
+ BITFIELD(14, 2) /* index 693 */,
+ TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(698),
+ BITFIELD(16, 2) /* index 698 */,
+ TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_MOVE,
+ BITFIELD(18, 4) /* index 703 */,
+ TILEGX_OPC_SUBX, TILEGX_OPC_SUB, CHILD(720), TILEGX_OPC_V1ADDUC,
+ TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADIFFU, TILEGX_OPC_V1AVGU,
+ TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLEU,
+ TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPNE,
+ TILEGX_OPC_V1DDOTPUSA, TILEGX_OPC_V1DDOTPUS, TILEGX_OPC_V1DOTPA,
+ BITFIELD(12, 4) /* index 720 */,
+ TILEGX_OPC_NONE, CHILD(737), CHILD(742), CHILD(747), CHILD(752), CHILD(757),
+ CHILD(762), CHILD(767), CHILD(772), CHILD(777), CHILD(782), CHILD(787),
+ CHILD(792), TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ BITFIELD(16, 2) /* index 737 */,
+ TILEGX_OPC_CLZ, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ BITFIELD(16, 2) /* index 742 */,
+ TILEGX_OPC_CTZ, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ BITFIELD(16, 2) /* index 747 */,
+ TILEGX_OPC_FNOP, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ BITFIELD(16, 2) /* index 752 */,
+ TILEGX_OPC_FSINGLE_PACK1, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ BITFIELD(16, 2) /* index 757 */,
+ TILEGX_OPC_NOP, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ BITFIELD(16, 2) /* index 762 */,
+ TILEGX_OPC_PCNT, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ BITFIELD(16, 2) /* index 767 */,
+ TILEGX_OPC_REVBITS, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ BITFIELD(16, 2) /* index 772 */,
+ TILEGX_OPC_REVBYTES, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ BITFIELD(16, 2) /* index 777 */,
+ TILEGX_OPC_TBLIDXB0, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ BITFIELD(16, 2) /* index 782 */,
+ TILEGX_OPC_TBLIDXB1, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ BITFIELD(16, 2) /* index 787 */,
+ TILEGX_OPC_TBLIDXB2, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ BITFIELD(16, 2) /* index 792 */,
+ TILEGX_OPC_TBLIDXB3, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ BITFIELD(18, 4) /* index 797 */,
+ TILEGX_OPC_V1DOTPUSA, TILEGX_OPC_V1DOTPUS, TILEGX_OPC_V1DOTP,
+ TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_L, TILEGX_OPC_V1MAXU,
+ TILEGX_OPC_V1MINU, TILEGX_OPC_V1MNZ, TILEGX_OPC_V1MULTU, TILEGX_OPC_V1MULUS,
+ TILEGX_OPC_V1MULU, TILEGX_OPC_V1MZ, TILEGX_OPC_V1SADAU, TILEGX_OPC_V1SADU,
+ TILEGX_OPC_V1SHL, TILEGX_OPC_V1SHRS,
+ BITFIELD(18, 4) /* index 814 */,
+ TILEGX_OPC_V1SHRU, TILEGX_OPC_V1SUBUC, TILEGX_OPC_V1SUB, TILEGX_OPC_V2ADDSC,
+ TILEGX_OPC_V2ADD, TILEGX_OPC_V2ADIFFS, TILEGX_OPC_V2AVGS,
+ TILEGX_OPC_V2CMPEQ, TILEGX_OPC_V2CMPLES, TILEGX_OPC_V2CMPLEU,
+ TILEGX_OPC_V2CMPLTS, TILEGX_OPC_V2CMPLTU, TILEGX_OPC_V2CMPNE,
+ TILEGX_OPC_V2DOTPA, TILEGX_OPC_V2DOTP, TILEGX_OPC_V2INT_H,
+ BITFIELD(18, 4) /* index 831 */,
+ TILEGX_OPC_V2INT_L, TILEGX_OPC_V2MAXS, TILEGX_OPC_V2MINS, TILEGX_OPC_V2MNZ,
+ TILEGX_OPC_V2MULFSC, TILEGX_OPC_V2MULS, TILEGX_OPC_V2MULTS, TILEGX_OPC_V2MZ,
+ TILEGX_OPC_V2PACKH, TILEGX_OPC_V2PACKL, TILEGX_OPC_V2PACKUC,
+ TILEGX_OPC_V2SADAS, TILEGX_OPC_V2SADAU, TILEGX_OPC_V2SADS,
+ TILEGX_OPC_V2SADU, TILEGX_OPC_V2SHLSC,
+ BITFIELD(18, 4) /* index 848 */,
+ TILEGX_OPC_V2SHL, TILEGX_OPC_V2SHRS, TILEGX_OPC_V2SHRU, TILEGX_OPC_V2SUBSC,
+ TILEGX_OPC_V2SUB, TILEGX_OPC_V4ADDSC, TILEGX_OPC_V4ADD, TILEGX_OPC_V4INT_H,
+ TILEGX_OPC_V4INT_L, TILEGX_OPC_V4PACKSC, TILEGX_OPC_V4SHLSC,
+ TILEGX_OPC_V4SHL, TILEGX_OPC_V4SHRS, TILEGX_OPC_V4SHRU, TILEGX_OPC_V4SUBSC,
+ TILEGX_OPC_V4SUB,
+ BITFIELD(18, 3) /* index 865 */,
+ CHILD(874), CHILD(877), CHILD(880), CHILD(883), CHILD(886), TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ BITFIELD(21, 1) /* index 874 */,
+ TILEGX_OPC_XOR, TILEGX_OPC_NONE,
+ BITFIELD(21, 1) /* index 877 */,
+ TILEGX_OPC_V1DDOTPUA, TILEGX_OPC_NONE,
+ BITFIELD(21, 1) /* index 880 */,
+ TILEGX_OPC_V1DDOTPU, TILEGX_OPC_NONE,
+ BITFIELD(21, 1) /* index 883 */,
+ TILEGX_OPC_V1DOTPUA, TILEGX_OPC_NONE,
+ BITFIELD(21, 1) /* index 886 */,
+ TILEGX_OPC_V1DOTPU, TILEGX_OPC_NONE,
+ BITFIELD(18, 4) /* index 889 */,
+ TILEGX_OPC_NONE, TILEGX_OPC_ROTLI, TILEGX_OPC_SHLI, TILEGX_OPC_SHLXI,
+ TILEGX_OPC_SHRSI, TILEGX_OPC_SHRUI, TILEGX_OPC_SHRUXI, TILEGX_OPC_V1SHLI,
+ TILEGX_OPC_V1SHRSI, TILEGX_OPC_V1SHRUI, TILEGX_OPC_V2SHLI,
+ TILEGX_OPC_V2SHRSI, TILEGX_OPC_V2SHRUI, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE,
+ BITFIELD(0, 2) /* index 906 */,
+ TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+ CHILD(911),
+ BITFIELD(2, 2) /* index 911 */,
+ TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+ CHILD(916),
+ BITFIELD(4, 2) /* index 916 */,
+ TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+ CHILD(921),
+ BITFIELD(6, 2) /* index 921 */,
+ TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+ CHILD(926),
+ BITFIELD(8, 2) /* index 926 */,
+ TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+ CHILD(931),
+ BITFIELD(10, 2) /* index 931 */,
+ TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+ TILEGX_OPC_INFOL,
+};
+
+static const unsigned short decode_X1_fsm[1206] =
+{
+ BITFIELD(53, 9) /* index 0 */,
+ CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+ CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+ CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+ CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+ CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+ CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+ CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+ CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+ CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+ CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513),
+ CHILD(513), CHILD(513), CHILD(513), CHILD(513), TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI,
+ TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_BEQZT,
+ TILEGX_OPC_BEQZT, TILEGX_OPC_BEQZ, TILEGX_OPC_BEQZ, TILEGX_OPC_BGEZT,
+ TILEGX_OPC_BGEZT, TILEGX_OPC_BGEZ, TILEGX_OPC_BGEZ, TILEGX_OPC_BGTZT,
+ TILEGX_OPC_BGTZT, TILEGX_OPC_BGTZ, TILEGX_OPC_BGTZ, TILEGX_OPC_BLBCT,
+ TILEGX_OPC_BLBCT, TILEGX_OPC_BLBC, TILEGX_OPC_BLBC, TILEGX_OPC_BLBST,
+ TILEGX_OPC_BLBST, TILEGX_OPC_BLBS, TILEGX_OPC_BLBS, TILEGX_OPC_BLEZT,
+ TILEGX_OPC_BLEZT, TILEGX_OPC_BLEZ, TILEGX_OPC_BLEZ, TILEGX_OPC_BLTZT,
+ TILEGX_OPC_BLTZT, TILEGX_OPC_BLTZ, TILEGX_OPC_BLTZ, TILEGX_OPC_BNEZT,
+ TILEGX_OPC_BNEZT, TILEGX_OPC_BNEZ, TILEGX_OPC_BNEZ, CHILD(528), CHILD(578),
+ CHILD(598), CHILD(663), CHILD(683), CHILD(688), CHILD(693), CHILD(698),
+ CHILD(703), CHILD(708), CHILD(713), CHILD(718), TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_JAL,
+ TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+ TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+ TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+ TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+ TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+ TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+ TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL,
+ TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_J, TILEGX_OPC_J,
+ TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J,
+ TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J,
+ TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J,
+ TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J,
+ TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J,
+ TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J,
+ CHILD(723), CHILD(740), CHILD(772), CHILD(789), CHILD(1108), CHILD(1125),
+ CHILD(1142), TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, CHILD(1159), TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, CHILD(1176), CHILD(1176), CHILD(1176),
+ CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+ CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+ CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+ CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+ CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+ CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+ CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+ CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+ CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+ CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+ CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+ CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176),
+ CHILD(1176),
+ BITFIELD(37, 2) /* index 513 */,
+ TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, CHILD(518),
+ BITFIELD(39, 2) /* index 518 */,
+ TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, CHILD(523),
+ BITFIELD(41, 2) /* index 523 */,
+ TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_MOVELI,
+ BITFIELD(51, 2) /* index 528 */,
+ TILEGX_OPC_NONE, CHILD(533), TILEGX_OPC_ADDXI, CHILD(548),
+ BITFIELD(37, 2) /* index 533 */,
+ TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(538),
+ BITFIELD(39, 2) /* index 538 */,
+ TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(543),
+ BITFIELD(41, 2) /* index 543 */,
+ TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_MOVEI,
+ BITFIELD(31, 2) /* index 548 */,
+ TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(553),
+ BITFIELD(33, 2) /* index 553 */,
+ TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(558),
+ BITFIELD(35, 2) /* index 558 */,
+ TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(563),
+ BITFIELD(37, 2) /* index 563 */,
+ TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(568),
+ BITFIELD(39, 2) /* index 568 */,
+ TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(573),
+ BITFIELD(41, 2) /* index 573 */,
+ TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_INFO,
+ BITFIELD(51, 2) /* index 578 */,
+ TILEGX_OPC_CMPEQI, TILEGX_OPC_CMPLTSI, TILEGX_OPC_CMPLTUI, CHILD(583),
+ BITFIELD(31, 2) /* index 583 */,
+ TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, CHILD(588),
+ BITFIELD(33, 2) /* index 588 */,
+ TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, CHILD(593),
+ BITFIELD(35, 2) /* index 593 */,
+ TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD,
+ TILEGX_OPC_PREFETCH_ADD_L1_FAULT,
+ BITFIELD(51, 2) /* index 598 */,
+ CHILD(603), CHILD(618), CHILD(633), CHILD(648),
+ BITFIELD(31, 2) /* index 603 */,
+ TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, CHILD(608),
+ BITFIELD(33, 2) /* index 608 */,
+ TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, CHILD(613),
+ BITFIELD(35, 2) /* index 613 */,
+ TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD,
+ TILEGX_OPC_PREFETCH_ADD_L1,
+ BITFIELD(31, 2) /* index 618 */,
+ TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, CHILD(623),
+ BITFIELD(33, 2) /* index 623 */,
+ TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, CHILD(628),
+ BITFIELD(35, 2) /* index 628 */,
+ TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD,
+ TILEGX_OPC_PREFETCH_ADD_L2_FAULT,
+ BITFIELD(31, 2) /* index 633 */,
+ TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, CHILD(638),
+ BITFIELD(33, 2) /* index 638 */,
+ TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, CHILD(643),
+ BITFIELD(35, 2) /* index 643 */,
+ TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD,
+ TILEGX_OPC_PREFETCH_ADD_L2,
+ BITFIELD(31, 2) /* index 648 */,
+ TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD, CHILD(653),
+ BITFIELD(33, 2) /* index 653 */,
+ TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD, CHILD(658),
+ BITFIELD(35, 2) /* index 658 */,
+ TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD,
+ TILEGX_OPC_PREFETCH_ADD_L3_FAULT,
+ BITFIELD(51, 2) /* index 663 */,
+ CHILD(668), TILEGX_OPC_LDNT1S_ADD, TILEGX_OPC_LDNT1U_ADD,
+ TILEGX_OPC_LDNT2S_ADD,
+ BITFIELD(31, 2) /* index 668 */,
+ TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, CHILD(673),
+ BITFIELD(33, 2) /* index 673 */,
+ TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, CHILD(678),
+ BITFIELD(35, 2) /* index 678 */,
+ TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD,
+ TILEGX_OPC_PREFETCH_ADD_L3,
+ BITFIELD(51, 2) /* index 683 */,
+ TILEGX_OPC_LDNT2U_ADD, TILEGX_OPC_LDNT4S_ADD, TILEGX_OPC_LDNT4U_ADD,
+ TILEGX_OPC_LDNT_ADD,
+ BITFIELD(51, 2) /* index 688 */,
+ TILEGX_OPC_LD_ADD, TILEGX_OPC_LDNA_ADD, TILEGX_OPC_MFSPR, TILEGX_OPC_MTSPR,
+ BITFIELD(51, 2) /* index 693 */,
+ TILEGX_OPC_ORI, TILEGX_OPC_ST1_ADD, TILEGX_OPC_ST2_ADD, TILEGX_OPC_ST4_ADD,
+ BITFIELD(51, 2) /* index 698 */,
+ TILEGX_OPC_STNT1_ADD, TILEGX_OPC_STNT2_ADD, TILEGX_OPC_STNT4_ADD,
+ TILEGX_OPC_STNT_ADD,
+ BITFIELD(51, 2) /* index 703 */,
+ TILEGX_OPC_ST_ADD, TILEGX_OPC_V1ADDI, TILEGX_OPC_V1CMPEQI,
+ TILEGX_OPC_V1CMPLTSI,
+ BITFIELD(51, 2) /* index 708 */,
+ TILEGX_OPC_V1CMPLTUI, TILEGX_OPC_V1MAXUI, TILEGX_OPC_V1MINUI,
+ TILEGX_OPC_V2ADDI,
+ BITFIELD(51, 2) /* index 713 */,
+ TILEGX_OPC_V2CMPEQI, TILEGX_OPC_V2CMPLTSI, TILEGX_OPC_V2CMPLTUI,
+ TILEGX_OPC_V2MAXSI,
+ BITFIELD(51, 2) /* index 718 */,
+ TILEGX_OPC_V2MINSI, TILEGX_OPC_XORI, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ BITFIELD(49, 4) /* index 723 */,
+ TILEGX_OPC_NONE, TILEGX_OPC_ADDXSC, TILEGX_OPC_ADDX, TILEGX_OPC_ADD,
+ TILEGX_OPC_AND, TILEGX_OPC_CMPEQ, TILEGX_OPC_CMPEXCH4, TILEGX_OPC_CMPEXCH,
+ TILEGX_OPC_CMPLES, TILEGX_OPC_CMPLEU, TILEGX_OPC_CMPLTS, TILEGX_OPC_CMPLTU,
+ TILEGX_OPC_CMPNE, TILEGX_OPC_DBLALIGN2, TILEGX_OPC_DBLALIGN4,
+ TILEGX_OPC_DBLALIGN6,
+ BITFIELD(49, 4) /* index 740 */,
+ TILEGX_OPC_EXCH4, TILEGX_OPC_EXCH, TILEGX_OPC_FETCHADD4,
+ TILEGX_OPC_FETCHADDGEZ4, TILEGX_OPC_FETCHADDGEZ, TILEGX_OPC_FETCHADD,
+ TILEGX_OPC_FETCHAND4, TILEGX_OPC_FETCHAND, TILEGX_OPC_FETCHOR4,
+ TILEGX_OPC_FETCHOR, TILEGX_OPC_MNZ, TILEGX_OPC_MZ, TILEGX_OPC_NOR,
+ CHILD(757), TILEGX_OPC_ROTL, TILEGX_OPC_SHL1ADDX,
+ BITFIELD(43, 2) /* index 757 */,
+ TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(762),
+ BITFIELD(45, 2) /* index 762 */,
+ TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(767),
+ BITFIELD(47, 2) /* index 767 */,
+ TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_MOVE,
+ BITFIELD(49, 4) /* index 772 */,
+ TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL2ADDX, TILEGX_OPC_SHL2ADD,
+ TILEGX_OPC_SHL3ADDX, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHLX, TILEGX_OPC_SHL,
+ TILEGX_OPC_SHRS, TILEGX_OPC_SHRUX, TILEGX_OPC_SHRU, TILEGX_OPC_ST1,
+ TILEGX_OPC_ST2, TILEGX_OPC_ST4, TILEGX_OPC_STNT1, TILEGX_OPC_STNT2,
+ TILEGX_OPC_STNT4,
+ BITFIELD(46, 7) /* index 789 */,
+ TILEGX_OPC_STNT, TILEGX_OPC_STNT, TILEGX_OPC_STNT, TILEGX_OPC_STNT,
+ TILEGX_OPC_STNT, TILEGX_OPC_STNT, TILEGX_OPC_STNT, TILEGX_OPC_STNT,
+ TILEGX_OPC_ST, TILEGX_OPC_ST, TILEGX_OPC_ST, TILEGX_OPC_ST, TILEGX_OPC_ST,
+ TILEGX_OPC_ST, TILEGX_OPC_ST, TILEGX_OPC_ST, TILEGX_OPC_SUBXSC,
+ TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBXSC,
+ TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBX,
+ TILEGX_OPC_SUBX, TILEGX_OPC_SUBX, TILEGX_OPC_SUBX, TILEGX_OPC_SUBX,
+ TILEGX_OPC_SUBX, TILEGX_OPC_SUBX, TILEGX_OPC_SUBX, TILEGX_OPC_SUB,
+ TILEGX_OPC_SUB, TILEGX_OPC_SUB, TILEGX_OPC_SUB, TILEGX_OPC_SUB,
+ TILEGX_OPC_SUB, TILEGX_OPC_SUB, TILEGX_OPC_SUB, CHILD(918), CHILD(927),
+ CHILD(1006), CHILD(1090), CHILD(1099), TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADDUC,
+ TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADDUC,
+ TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADD,
+ TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADD,
+ TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADD, TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPEQ,
+ TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPEQ,
+ TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPEQ,
+ TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLES,
+ TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLES,
+ TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLEU,
+ TILEGX_OPC_V1CMPLEU, TILEGX_OPC_V1CMPLEU, TILEGX_OPC_V1CMPLEU,
+ TILEGX_OPC_V1CMPLEU, TILEGX_OPC_V1CMPLEU, TILEGX_OPC_V1CMPLEU,
+ TILEGX_OPC_V1CMPLEU, TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTS,
+ TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTS,
+ TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTS,
+ TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPLTU,
+ TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPLTU,
+ TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPNE,
+ TILEGX_OPC_V1CMPNE, TILEGX_OPC_V1CMPNE, TILEGX_OPC_V1CMPNE,
+ TILEGX_OPC_V1CMPNE, TILEGX_OPC_V1CMPNE, TILEGX_OPC_V1CMPNE,
+ TILEGX_OPC_V1CMPNE, TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_H,
+ TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_H,
+ TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_H,
+ TILEGX_OPC_V1INT_L, TILEGX_OPC_V1INT_L, TILEGX_OPC_V1INT_L,
+ TILEGX_OPC_V1INT_L, TILEGX_OPC_V1INT_L, TILEGX_OPC_V1INT_L,
+ TILEGX_OPC_V1INT_L, TILEGX_OPC_V1INT_L,
+ BITFIELD(43, 3) /* index 918 */,
+ TILEGX_OPC_NONE, TILEGX_OPC_DRAIN, TILEGX_OPC_DTLBPR, TILEGX_OPC_FINV,
+ TILEGX_OPC_FLUSHWB, TILEGX_OPC_FLUSH, TILEGX_OPC_FNOP, TILEGX_OPC_ICOH,
+ BITFIELD(43, 3) /* index 927 */,
+ CHILD(936), TILEGX_OPC_INV, TILEGX_OPC_IRET, TILEGX_OPC_JALRP,
+ TILEGX_OPC_JALR, TILEGX_OPC_JRP, TILEGX_OPC_JR, CHILD(991),
+ BITFIELD(31, 2) /* index 936 */,
+ CHILD(941), CHILD(966), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+ BITFIELD(33, 2) /* index 941 */,
+ TILEGX_OPC_ILL, TILEGX_OPC_ILL, TILEGX_OPC_ILL, CHILD(946),
+ BITFIELD(35, 2) /* index 946 */,
+ TILEGX_OPC_ILL, CHILD(951), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+ BITFIELD(37, 2) /* index 951 */,
+ TILEGX_OPC_ILL, CHILD(956), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+ BITFIELD(39, 2) /* index 956 */,
+ TILEGX_OPC_ILL, CHILD(961), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+ BITFIELD(41, 2) /* index 961 */,
+ TILEGX_OPC_ILL, TILEGX_OPC_ILL, TILEGX_OPC_BPT, TILEGX_OPC_ILL,
+ BITFIELD(33, 2) /* index 966 */,
+ TILEGX_OPC_ILL, TILEGX_OPC_ILL, TILEGX_OPC_ILL, CHILD(971),
+ BITFIELD(35, 2) /* index 971 */,
+ TILEGX_OPC_ILL, CHILD(976), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+ BITFIELD(37, 2) /* index 976 */,
+ TILEGX_OPC_ILL, CHILD(981), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+ BITFIELD(39, 2) /* index 981 */,
+ TILEGX_OPC_ILL, CHILD(986), TILEGX_OPC_ILL, TILEGX_OPC_ILL,
+ BITFIELD(41, 2) /* index 986 */,
+ TILEGX_OPC_ILL, TILEGX_OPC_ILL, TILEGX_OPC_RAISE, TILEGX_OPC_ILL,
+ BITFIELD(31, 2) /* index 991 */,
+ TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, CHILD(996),
+ BITFIELD(33, 2) /* index 996 */,
+ TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, CHILD(1001),
+ BITFIELD(35, 2) /* index 1001 */,
+ TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, TILEGX_OPC_LD1S,
+ TILEGX_OPC_PREFETCH_L1_FAULT,
+ BITFIELD(43, 3) /* index 1006 */,
+ CHILD(1015), CHILD(1030), CHILD(1045), CHILD(1060), CHILD(1075),
+ TILEGX_OPC_LDNA, TILEGX_OPC_LDNT1S, TILEGX_OPC_LDNT1U,
+ BITFIELD(31, 2) /* index 1015 */,
+ TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, CHILD(1020),
+ BITFIELD(33, 2) /* index 1020 */,
+ TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, CHILD(1025),
+ BITFIELD(35, 2) /* index 1025 */,
+ TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_PREFETCH,
+ BITFIELD(31, 2) /* index 1030 */,
+ TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, CHILD(1035),
+ BITFIELD(33, 2) /* index 1035 */,
+ TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, CHILD(1040),
+ BITFIELD(35, 2) /* index 1040 */,
+ TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, TILEGX_OPC_LD2S,
+ TILEGX_OPC_PREFETCH_L2_FAULT,
+ BITFIELD(31, 2) /* index 1045 */,
+ TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, CHILD(1050),
+ BITFIELD(33, 2) /* index 1050 */,
+ TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, CHILD(1055),
+ BITFIELD(35, 2) /* index 1055 */,
+ TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_PREFETCH_L2,
+ BITFIELD(31, 2) /* index 1060 */,
+ TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, CHILD(1065),
+ BITFIELD(33, 2) /* index 1065 */,
+ TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, CHILD(1070),
+ BITFIELD(35, 2) /* index 1070 */,
+ TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, TILEGX_OPC_LD4S,
+ TILEGX_OPC_PREFETCH_L3_FAULT,
+ BITFIELD(31, 2) /* index 1075 */,
+ TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, CHILD(1080),
+ BITFIELD(33, 2) /* index 1080 */,
+ TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, CHILD(1085),
+ BITFIELD(35, 2) /* index 1085 */,
+ TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_PREFETCH_L3,
+ BITFIELD(43, 3) /* index 1090 */,
+ TILEGX_OPC_LDNT2S, TILEGX_OPC_LDNT2U, TILEGX_OPC_LDNT4S, TILEGX_OPC_LDNT4U,
+ TILEGX_OPC_LDNT, TILEGX_OPC_LD, TILEGX_OPC_LNK, TILEGX_OPC_MF,
+ BITFIELD(43, 3) /* index 1099 */,
+ TILEGX_OPC_NAP, TILEGX_OPC_NOP, TILEGX_OPC_SWINT0, TILEGX_OPC_SWINT1,
+ TILEGX_OPC_SWINT2, TILEGX_OPC_SWINT3, TILEGX_OPC_WH64, TILEGX_OPC_NONE,
+ BITFIELD(49, 4) /* index 1108 */,
+ TILEGX_OPC_V1MAXU, TILEGX_OPC_V1MINU, TILEGX_OPC_V1MNZ, TILEGX_OPC_V1MZ,
+ TILEGX_OPC_V1SHL, TILEGX_OPC_V1SHRS, TILEGX_OPC_V1SHRU, TILEGX_OPC_V1SUBUC,
+ TILEGX_OPC_V1SUB, TILEGX_OPC_V2ADDSC, TILEGX_OPC_V2ADD, TILEGX_OPC_V2CMPEQ,
+ TILEGX_OPC_V2CMPLES, TILEGX_OPC_V2CMPLEU, TILEGX_OPC_V2CMPLTS,
+ TILEGX_OPC_V2CMPLTU,
+ BITFIELD(49, 4) /* index 1125 */,
+ TILEGX_OPC_V2CMPNE, TILEGX_OPC_V2INT_H, TILEGX_OPC_V2INT_L,
+ TILEGX_OPC_V2MAXS, TILEGX_OPC_V2MINS, TILEGX_OPC_V2MNZ, TILEGX_OPC_V2MZ,
+ TILEGX_OPC_V2PACKH, TILEGX_OPC_V2PACKL, TILEGX_OPC_V2PACKUC,
+ TILEGX_OPC_V2SHLSC, TILEGX_OPC_V2SHL, TILEGX_OPC_V2SHRS, TILEGX_OPC_V2SHRU,
+ TILEGX_OPC_V2SUBSC, TILEGX_OPC_V2SUB,
+ BITFIELD(49, 4) /* index 1142 */,
+ TILEGX_OPC_V4ADDSC, TILEGX_OPC_V4ADD, TILEGX_OPC_V4INT_H,
+ TILEGX_OPC_V4INT_L, TILEGX_OPC_V4PACKSC, TILEGX_OPC_V4SHLSC,
+ TILEGX_OPC_V4SHL, TILEGX_OPC_V4SHRS, TILEGX_OPC_V4SHRU, TILEGX_OPC_V4SUBSC,
+ TILEGX_OPC_V4SUB, TILEGX_OPC_XOR, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ BITFIELD(49, 4) /* index 1159 */,
+ TILEGX_OPC_NONE, TILEGX_OPC_ROTLI, TILEGX_OPC_SHLI, TILEGX_OPC_SHLXI,
+ TILEGX_OPC_SHRSI, TILEGX_OPC_SHRUI, TILEGX_OPC_SHRUXI, TILEGX_OPC_V1SHLI,
+ TILEGX_OPC_V1SHRSI, TILEGX_OPC_V1SHRUI, TILEGX_OPC_V2SHLI,
+ TILEGX_OPC_V2SHRSI, TILEGX_OPC_V2SHRUI, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE,
+ BITFIELD(31, 2) /* index 1176 */,
+ TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+ CHILD(1181),
+ BITFIELD(33, 2) /* index 1181 */,
+ TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+ CHILD(1186),
+ BITFIELD(35, 2) /* index 1186 */,
+ TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+ CHILD(1191),
+ BITFIELD(37, 2) /* index 1191 */,
+ TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+ CHILD(1196),
+ BITFIELD(39, 2) /* index 1196 */,
+ TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+ CHILD(1201),
+ BITFIELD(41, 2) /* index 1201 */,
+ TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI,
+ TILEGX_OPC_INFOL,
+};
+
+static const unsigned short decode_Y0_fsm[178] =
+{
+ BITFIELD(27, 4) /* index 0 */,
+ CHILD(17), TILEGX_OPC_ADDXI, CHILD(32), TILEGX_OPC_CMPEQI,
+ TILEGX_OPC_CMPLTSI, CHILD(62), CHILD(67), CHILD(118), CHILD(123),
+ CHILD(128), CHILD(133), CHILD(153), CHILD(158), CHILD(163), CHILD(168),
+ CHILD(173),
+ BITFIELD(6, 2) /* index 17 */,
+ TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(22),
+ BITFIELD(8, 2) /* index 22 */,
+ TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(27),
+ BITFIELD(10, 2) /* index 27 */,
+ TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_MOVEI,
+ BITFIELD(0, 2) /* index 32 */,
+ TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(37),
+ BITFIELD(2, 2) /* index 37 */,
+ TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(42),
+ BITFIELD(4, 2) /* index 42 */,
+ TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(47),
+ BITFIELD(6, 2) /* index 47 */,
+ TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(52),
+ BITFIELD(8, 2) /* index 52 */,
+ TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(57),
+ BITFIELD(10, 2) /* index 57 */,
+ TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_INFO,
+ BITFIELD(18, 2) /* index 62 */,
+ TILEGX_OPC_ADDX, TILEGX_OPC_ADD, TILEGX_OPC_SUBX, TILEGX_OPC_SUB,
+ BITFIELD(15, 5) /* index 67 */,
+ TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD,
+ TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD,
+ TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL2ADD,
+ TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD,
+ TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD,
+ TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD,
+ TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD,
+ TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, CHILD(100),
+ CHILD(109), TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ BITFIELD(12, 3) /* index 100 */,
+ TILEGX_OPC_NONE, TILEGX_OPC_CLZ, TILEGX_OPC_CTZ, TILEGX_OPC_FNOP,
+ TILEGX_OPC_FSINGLE_PACK1, TILEGX_OPC_NOP, TILEGX_OPC_PCNT,
+ TILEGX_OPC_REVBITS,
+ BITFIELD(12, 3) /* index 109 */,
+ TILEGX_OPC_REVBYTES, TILEGX_OPC_TBLIDXB0, TILEGX_OPC_TBLIDXB1,
+ TILEGX_OPC_TBLIDXB2, TILEGX_OPC_TBLIDXB3, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ TILEGX_OPC_NONE,
+ BITFIELD(18, 2) /* index 118 */,
+ TILEGX_OPC_CMPLES, TILEGX_OPC_CMPLEU, TILEGX_OPC_CMPLTS, TILEGX_OPC_CMPLTU,
+ BITFIELD(18, 2) /* index 123 */,
+ TILEGX_OPC_CMPEQ, TILEGX_OPC_CMPNE, TILEGX_OPC_MULAX, TILEGX_OPC_MULX,
+ BITFIELD(18, 2) /* index 128 */,
+ TILEGX_OPC_CMOVEQZ, TILEGX_OPC_CMOVNEZ, TILEGX_OPC_MNZ, TILEGX_OPC_MZ,
+ BITFIELD(18, 2) /* index 133 */,
+ TILEGX_OPC_AND, TILEGX_OPC_NOR, CHILD(138), TILEGX_OPC_XOR,
+ BITFIELD(12, 2) /* index 138 */,
+ TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(143),
+ BITFIELD(14, 2) /* index 143 */,
+ TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(148),
+ BITFIELD(16, 2) /* index 148 */,
+ TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_MOVE,
+ BITFIELD(18, 2) /* index 153 */,
+ TILEGX_OPC_ROTL, TILEGX_OPC_SHL, TILEGX_OPC_SHRS, TILEGX_OPC_SHRU,
+ BITFIELD(18, 2) /* index 158 */,
+ TILEGX_OPC_NONE, TILEGX_OPC_SHL1ADDX, TILEGX_OPC_SHL2ADDX,
+ TILEGX_OPC_SHL3ADDX,
+ BITFIELD(18, 2) /* index 163 */,
+ TILEGX_OPC_MUL_HS_HS, TILEGX_OPC_MUL_HU_HU, TILEGX_OPC_MUL_LS_LS,
+ TILEGX_OPC_MUL_LU_LU,
+ BITFIELD(18, 2) /* index 168 */,
+ TILEGX_OPC_MULA_HS_HS, TILEGX_OPC_MULA_HU_HU, TILEGX_OPC_MULA_LS_LS,
+ TILEGX_OPC_MULA_LU_LU,
+ BITFIELD(18, 2) /* index 173 */,
+ TILEGX_OPC_ROTLI, TILEGX_OPC_SHLI, TILEGX_OPC_SHRSI, TILEGX_OPC_SHRUI,
+};
+
+static const unsigned short decode_Y1_fsm[167] =
+{
+ BITFIELD(58, 4) /* index 0 */,
+ TILEGX_OPC_NONE, CHILD(17), TILEGX_OPC_ADDXI, CHILD(32), TILEGX_OPC_CMPEQI,
+ TILEGX_OPC_CMPLTSI, CHILD(62), CHILD(67), CHILD(117), CHILD(122),
+ CHILD(127), CHILD(132), CHILD(152), CHILD(157), CHILD(162), TILEGX_OPC_NONE,
+ BITFIELD(37, 2) /* index 17 */,
+ TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(22),
+ BITFIELD(39, 2) /* index 22 */,
+ TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(27),
+ BITFIELD(41, 2) /* index 27 */,
+ TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_MOVEI,
+ BITFIELD(31, 2) /* index 32 */,
+ TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(37),
+ BITFIELD(33, 2) /* index 37 */,
+ TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(42),
+ BITFIELD(35, 2) /* index 42 */,
+ TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(47),
+ BITFIELD(37, 2) /* index 47 */,
+ TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(52),
+ BITFIELD(39, 2) /* index 52 */,
+ TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(57),
+ BITFIELD(41, 2) /* index 57 */,
+ TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_INFO,
+ BITFIELD(49, 2) /* index 62 */,
+ TILEGX_OPC_ADDX, TILEGX_OPC_ADD, TILEGX_OPC_SUBX, TILEGX_OPC_SUB,
+ BITFIELD(47, 4) /* index 67 */,
+ TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD,
+ TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD,
+ TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL3ADD,
+ TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, CHILD(84),
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE,
+ BITFIELD(43, 3) /* index 84 */,
+ CHILD(93), CHILD(96), CHILD(99), CHILD(102), CHILD(105), CHILD(108),
+ CHILD(111), CHILD(114),
+ BITFIELD(46, 1) /* index 93 */,
+ TILEGX_OPC_NONE, TILEGX_OPC_FNOP,
+ BITFIELD(46, 1) /* index 96 */,
+ TILEGX_OPC_NONE, TILEGX_OPC_ILL,
+ BITFIELD(46, 1) /* index 99 */,
+ TILEGX_OPC_NONE, TILEGX_OPC_JALRP,
+ BITFIELD(46, 1) /* index 102 */,
+ TILEGX_OPC_NONE, TILEGX_OPC_JALR,
+ BITFIELD(46, 1) /* index 105 */,
+ TILEGX_OPC_NONE, TILEGX_OPC_JRP,
+ BITFIELD(46, 1) /* index 108 */,
+ TILEGX_OPC_NONE, TILEGX_OPC_JR,
+ BITFIELD(46, 1) /* index 111 */,
+ TILEGX_OPC_NONE, TILEGX_OPC_LNK,
+ BITFIELD(46, 1) /* index 114 */,
+ TILEGX_OPC_NONE, TILEGX_OPC_NOP,
+ BITFIELD(49, 2) /* index 117 */,
+ TILEGX_OPC_CMPLES, TILEGX_OPC_CMPLEU, TILEGX_OPC_CMPLTS, TILEGX_OPC_CMPLTU,
+ BITFIELD(49, 2) /* index 122 */,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_CMPEQ, TILEGX_OPC_CMPNE,
+ BITFIELD(49, 2) /* index 127 */,
+ TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_MNZ, TILEGX_OPC_MZ,
+ BITFIELD(49, 2) /* index 132 */,
+ TILEGX_OPC_AND, TILEGX_OPC_NOR, CHILD(137), TILEGX_OPC_XOR,
+ BITFIELD(43, 2) /* index 137 */,
+ TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(142),
+ BITFIELD(45, 2) /* index 142 */,
+ TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(147),
+ BITFIELD(47, 2) /* index 147 */,
+ TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_MOVE,
+ BITFIELD(49, 2) /* index 152 */,
+ TILEGX_OPC_ROTL, TILEGX_OPC_SHL, TILEGX_OPC_SHRS, TILEGX_OPC_SHRU,
+ BITFIELD(49, 2) /* index 157 */,
+ TILEGX_OPC_NONE, TILEGX_OPC_SHL1ADDX, TILEGX_OPC_SHL2ADDX,
+ TILEGX_OPC_SHL3ADDX,
+ BITFIELD(49, 2) /* index 162 */,
+ TILEGX_OPC_ROTLI, TILEGX_OPC_SHLI, TILEGX_OPC_SHRSI, TILEGX_OPC_SHRUI,
+};
+
+static const unsigned short decode_Y2_fsm[118] =
+{
+ BITFIELD(62, 2) /* index 0 */,
+ TILEGX_OPC_NONE, CHILD(5), CHILD(66), CHILD(109),
+ BITFIELD(55, 3) /* index 5 */,
+ CHILD(14), CHILD(14), CHILD(14), CHILD(17), CHILD(40), CHILD(40), CHILD(40),
+ CHILD(43),
+ BITFIELD(26, 1) /* index 14 */,
+ TILEGX_OPC_LD1S, TILEGX_OPC_LD1U,
+ BITFIELD(26, 1) /* index 17 */,
+ CHILD(20), CHILD(30),
+ BITFIELD(51, 2) /* index 20 */,
+ TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, CHILD(25),
+ BITFIELD(53, 2) /* index 25 */,
+ TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, TILEGX_OPC_LD1S,
+ TILEGX_OPC_PREFETCH_L1_FAULT,
+ BITFIELD(51, 2) /* index 30 */,
+ TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, CHILD(35),
+ BITFIELD(53, 2) /* index 35 */,
+ TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_PREFETCH,
+ BITFIELD(26, 1) /* index 40 */,
+ TILEGX_OPC_LD2S, TILEGX_OPC_LD2U,
+ BITFIELD(26, 1) /* index 43 */,
+ CHILD(46), CHILD(56),
+ BITFIELD(51, 2) /* index 46 */,
+ TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, CHILD(51),
+ BITFIELD(53, 2) /* index 51 */,
+ TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, TILEGX_OPC_LD2S,
+ TILEGX_OPC_PREFETCH_L2_FAULT,
+ BITFIELD(51, 2) /* index 56 */,
+ TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, CHILD(61),
+ BITFIELD(53, 2) /* index 61 */,
+ TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_PREFETCH_L2,
+ BITFIELD(56, 2) /* index 66 */,
+ CHILD(71), CHILD(74), CHILD(90), CHILD(93),
+ BITFIELD(26, 1) /* index 71 */,
+ TILEGX_OPC_NONE, TILEGX_OPC_LD4S,
+ BITFIELD(26, 1) /* index 74 */,
+ TILEGX_OPC_NONE, CHILD(77),
+ BITFIELD(51, 2) /* index 77 */,
+ TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, CHILD(82),
+ BITFIELD(53, 2) /* index 82 */,
+ TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, CHILD(87),
+ BITFIELD(55, 1) /* index 87 */,
+ TILEGX_OPC_LD4S, TILEGX_OPC_PREFETCH_L3_FAULT,
+ BITFIELD(26, 1) /* index 90 */,
+ TILEGX_OPC_LD4U, TILEGX_OPC_LD,
+ BITFIELD(26, 1) /* index 93 */,
+ CHILD(96), TILEGX_OPC_LD,
+ BITFIELD(51, 2) /* index 96 */,
+ TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, CHILD(101),
+ BITFIELD(53, 2) /* index 101 */,
+ TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, CHILD(106),
+ BITFIELD(55, 1) /* index 106 */,
+ TILEGX_OPC_LD4U, TILEGX_OPC_PREFETCH_L3,
+ BITFIELD(26, 1) /* index 109 */,
+ CHILD(112), CHILD(115),
+ BITFIELD(57, 1) /* index 112 */,
+ TILEGX_OPC_ST1, TILEGX_OPC_ST4,
+ BITFIELD(57, 1) /* index 115 */,
+ TILEGX_OPC_ST2, TILEGX_OPC_ST,
+};
+
+#undef BITFIELD
+#undef CHILD
+const unsigned short * const
+tilegx_bundle_decoder_fsms[TILEGX_NUM_PIPELINE_ENCODINGS] =
+{
+ decode_X0_fsm,
+ decode_X1_fsm,
+ decode_Y0_fsm,
+ decode_Y1_fsm,
+ decode_Y2_fsm
+};
+const struct tilegx_operand tilegx_operands[35] =
+{
+ {
+ TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM8_X0),
+ 8, 1, 0, 0, 0, 0,
+ create_Imm8_X0, get_Imm8_X0
+ },
+ {
+ TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM8_X1),
+ 8, 1, 0, 0, 0, 0,
+ create_Imm8_X1, get_Imm8_X1
+ },
+ {
+ TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM8_Y0),
+ 8, 1, 0, 0, 0, 0,
+ create_Imm8_Y0, get_Imm8_Y0
+ },
+ {
+ TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM8_Y1),
+ 8, 1, 0, 0, 0, 0,
+ create_Imm8_Y1, get_Imm8_Y1
+ },
+ {
+ TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM16_X0_HW0_LAST),
+ 16, 1, 0, 0, 0, 0,
+ create_Imm16_X0, get_Imm16_X0
+ },
+ {
+ TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM16_X1_HW0_LAST),
+ 16, 1, 0, 0, 0, 0,
+ create_Imm16_X1, get_Imm16_X1
+ },
+ {
+ TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+ 6, 0, 0, 1, 0, 0,
+ create_Dest_X0, get_Dest_X0
+ },
+ {
+ TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+ 6, 0, 1, 0, 0, 0,
+ create_SrcA_X0, get_SrcA_X0
+ },
+ {
+ TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+ 6, 0, 0, 1, 0, 0,
+ create_Dest_X1, get_Dest_X1
+ },
+ {
+ TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+ 6, 0, 1, 0, 0, 0,
+ create_SrcA_X1, get_SrcA_X1
+ },
+ {
+ TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+ 6, 0, 0, 1, 0, 0,
+ create_Dest_Y0, get_Dest_Y0
+ },
+ {
+ TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+ 6, 0, 1, 0, 0, 0,
+ create_SrcA_Y0, get_SrcA_Y0
+ },
+ {
+ TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+ 6, 0, 0, 1, 0, 0,
+ create_Dest_Y1, get_Dest_Y1
+ },
+ {
+ TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+ 6, 0, 1, 0, 0, 0,
+ create_SrcA_Y1, get_SrcA_Y1
+ },
+ {
+ TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+ 6, 0, 1, 0, 0, 0,
+ create_SrcA_Y2, get_SrcA_Y2
+ },
+ {
+ TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+ 6, 0, 1, 1, 0, 0,
+ create_SrcA_X1, get_SrcA_X1
+ },
+ {
+ TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+ 6, 0, 1, 0, 0, 0,
+ create_SrcB_X0, get_SrcB_X0
+ },
+ {
+ TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+ 6, 0, 1, 0, 0, 0,
+ create_SrcB_X1, get_SrcB_X1
+ },
+ {
+ TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+ 6, 0, 1, 0, 0, 0,
+ create_SrcB_Y0, get_SrcB_Y0
+ },
+ {
+ TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+ 6, 0, 1, 0, 0, 0,
+ create_SrcB_Y1, get_SrcB_Y1
+ },
+ {
+ TILEGX_OP_TYPE_ADDRESS, BFD_RELOC(TILEGX_BROFF_X1),
+ 17, 1, 0, 0, 1, TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES,
+ create_BrOff_X1, get_BrOff_X1
+ },
+ {
+ TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(NONE),
+ 6, 0, 0, 0, 0, 0,
+ create_BFStart_X0, get_BFStart_X0
+ },
+ {
+ TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(NONE),
+ 6, 0, 0, 0, 0, 0,
+ create_BFEnd_X0, get_BFEnd_X0
+ },
+ {
+ TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+ 6, 0, 1, 1, 0, 0,
+ create_Dest_X0, get_Dest_X0
+ },
+ {
+ TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+ 6, 0, 1, 1, 0, 0,
+ create_Dest_Y0, get_Dest_Y0
+ },
+ {
+ TILEGX_OP_TYPE_ADDRESS, BFD_RELOC(TILEGX_JUMPOFF_X1),
+ 27, 1, 0, 0, 1, TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES,
+ create_JumpOff_X1, get_JumpOff_X1
+ },
+ {
+ TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+ 6, 0, 0, 1, 0, 0,
+ create_SrcBDest_Y2, get_SrcBDest_Y2
+ },
+ {
+ TILEGX_OP_TYPE_SPR, BFD_RELOC(TILEGX_MF_IMM14_X1),
+ 14, 0, 0, 0, 0, 0,
+ create_MF_Imm14_X1, get_MF_Imm14_X1
+ },
+ {
+ TILEGX_OP_TYPE_SPR, BFD_RELOC(TILEGX_MT_IMM14_X1),
+ 14, 0, 0, 0, 0, 0,
+ create_MT_Imm14_X1, get_MT_Imm14_X1
+ },
+ {
+ TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_SHAMT_X0),
+ 6, 0, 0, 0, 0, 0,
+ create_ShAmt_X0, get_ShAmt_X0
+ },
+ {
+ TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_SHAMT_X1),
+ 6, 0, 0, 0, 0, 0,
+ create_ShAmt_X1, get_ShAmt_X1
+ },
+ {
+ TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_SHAMT_Y0),
+ 6, 0, 0, 0, 0, 0,
+ create_ShAmt_Y0, get_ShAmt_Y0
+ },
+ {
+ TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_SHAMT_Y1),
+ 6, 0, 0, 0, 0, 0,
+ create_ShAmt_Y1, get_ShAmt_Y1
+ },
+ {
+ TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE),
+ 6, 0, 1, 0, 0, 0,
+ create_SrcBDest_Y2, get_SrcBDest_Y2
+ },
+ {
+ TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_DEST_IMM8_X1),
+ 8, 1, 0, 0, 0, 0,
+ create_Dest_Imm8_X1, get_Dest_Imm8_X1
+ }
+};
+
+
+
+
+/* Given a set of bundle bits and the lookup FSM for a specific pipe,
+ * returns which instruction the bundle contains in that pipe.
+ */
+static const struct tilegx_opcode *
+find_opcode(tilegx_bundle_bits bits, const unsigned short *table)
+{
+ int index = 0;
+
+ while (1)
+ {
+ unsigned short bitspec = table[index];
+ unsigned int bitfield =
+ ((unsigned int)(bits >> (bitspec & 63))) & (bitspec >> 6);
+
+ unsigned short next = table[index + 1 + bitfield];
+ if (next <= TILEGX_OPC_NONE)
+ return &tilegx_opcodes[next];
+
+ index = next - TILEGX_OPC_NONE;
+ }
+}
+
+
+int
+parse_insn_tilegx(tilegx_bundle_bits bits,
+ unsigned long long pc,
+ struct tilegx_decoded_instruction
+ decoded[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE])
+{
+ int num_instructions = 0;
+ int pipe;
+
+ int min_pipe, max_pipe;
+ if ((bits & TILEGX_BUNDLE_MODE_MASK) == 0)
+ {
+ min_pipe = TILEGX_PIPELINE_X0;
+ max_pipe = TILEGX_PIPELINE_X1;
+ }
+ else
+ {
+ min_pipe = TILEGX_PIPELINE_Y0;
+ max_pipe = TILEGX_PIPELINE_Y2;
+ }
+
+ /* For each pipe, find an instruction that fits. */
+ for (pipe = min_pipe; pipe <= max_pipe; pipe++)
+ {
+ const struct tilegx_opcode *opc;
+ struct tilegx_decoded_instruction *d;
+ int i;
+
+ d = &decoded[num_instructions++];
+ opc = find_opcode (bits, tilegx_bundle_decoder_fsms[pipe]);
+ d->opcode = opc;
+
+ /* Decode each operand, sign extending, etc. as appropriate. */
+ for (i = 0; i < opc->num_operands; i++)
+ {
+ const struct tilegx_operand *op =
+ &tilegx_operands[opc->operands[pipe][i]];
+ int raw_opval = op->extract (bits);
+ long long opval;
+
+ if (op->is_signed)
+ {
+ /* Sign-extend the operand. */
+ int shift = (int)((sizeof(int) * 8) - op->num_bits);
+ raw_opval = (raw_opval << shift) >> shift;
+ }
+
+ /* Adjust PC-relative scaled branch offsets. */
+ if (op->type == TILEGX_OP_TYPE_ADDRESS)
+ opval = (raw_opval * TILEGX_BUNDLE_SIZE_IN_BYTES) + pc;
+ else
+ opval = raw_opval;
+
+ /* Record the final value. */
+ d->operands[i] = op;
+ d->operand_values[i] = opval;
+ }
+ }
+
+ return num_instructions;
+}
diff --git a/arch/tile/kernel/time.c b/arch/tile/kernel/time.c
index 49a605be94c5..c4be58cc5d50 100644
--- a/arch/tile/kernel/time.c
+++ b/arch/tile/kernel/time.c
@@ -22,6 +22,7 @@
#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/delay.h>
+#include <linux/module.h>
#include <asm/irq_regs.h>
#include <asm/traps.h>
#include <hv/hypervisor.h>
@@ -56,6 +57,7 @@ cycles_t get_cycles(void)
return (((cycles_t)high) << 32) | low;
}
+EXPORT_SYMBOL(get_cycles);
#endif
/*
diff --git a/arch/tile/kernel/tlb.c b/arch/tile/kernel/tlb.c
index 2dffc1044d83..a5f241c24cac 100644
--- a/arch/tile/kernel/tlb.c
+++ b/arch/tile/kernel/tlb.c
@@ -34,13 +34,13 @@ void flush_tlb_mm(struct mm_struct *mm)
{
HV_Remote_ASID asids[NR_CPUS];
int i = 0, cpu;
- for_each_cpu(cpu, &mm->cpu_vm_mask) {
+ for_each_cpu(cpu, mm_cpumask(mm)) {
HV_Remote_ASID *asid = &asids[i++];
asid->y = cpu / smp_topology.width;
asid->x = cpu % smp_topology.width;
asid->asid = per_cpu(current_asid, cpu);
}
- flush_remote(0, HV_FLUSH_EVICT_L1I, &mm->cpu_vm_mask,
+ flush_remote(0, HV_FLUSH_EVICT_L1I, mm_cpumask(mm),
0, 0, 0, NULL, asids, i);
}
@@ -54,8 +54,8 @@ void flush_tlb_page_mm(const struct vm_area_struct *vma, struct mm_struct *mm,
{
unsigned long size = hv_page_size(vma);
int cache = (vma->vm_flags & VM_EXEC) ? HV_FLUSH_EVICT_L1I : 0;
- flush_remote(0, cache, &mm->cpu_vm_mask,
- va, size, size, &mm->cpu_vm_mask, NULL, 0);
+ flush_remote(0, cache, mm_cpumask(mm),
+ va, size, size, mm_cpumask(mm), NULL, 0);
}
void flush_tlb_page(const struct vm_area_struct *vma, unsigned long va)
@@ -70,8 +70,8 @@ void flush_tlb_range(const struct vm_area_struct *vma,
unsigned long size = hv_page_size(vma);
struct mm_struct *mm = vma->vm_mm;
int cache = (vma->vm_flags & VM_EXEC) ? HV_FLUSH_EVICT_L1I : 0;
- flush_remote(0, cache, &mm->cpu_vm_mask, start, end - start, size,
- &mm->cpu_vm_mask, NULL, 0);
+ flush_remote(0, cache, mm_cpumask(mm), start, end - start, size,
+ mm_cpumask(mm), NULL, 0);
}
void flush_tlb_all(void)
diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c
index 5474fc2e77e8..f9803dfa7357 100644
--- a/arch/tile/kernel/traps.c
+++ b/arch/tile/kernel/traps.c
@@ -308,6 +308,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num,
info.si_addr = (void __user *)address;
if (signo == SIGILL)
info.si_trapno = fault_num;
+ trace_unhandled_signal("trap", regs, address, signo);
force_sig_info(signo, &info, current);
}
diff --git a/arch/tile/kernel/vmlinux.lds.S b/arch/tile/kernel/vmlinux.lds.S
index 38f64fafdc10..631f10de12fe 100644
--- a/arch/tile/kernel/vmlinux.lds.S
+++ b/arch/tile/kernel/vmlinux.lds.S
@@ -60,7 +60,7 @@ SECTIONS
. = ALIGN(PAGE_SIZE);
VMLINUX_SYMBOL(_sinitdata) = .;
INIT_DATA_SECTION(16) :data =0
- PERCPU(L2_CACHE_BYTES, PAGE_SIZE)
+ PERCPU_SECTION(L2_CACHE_BYTES)
. = ALIGN(PAGE_SIZE);
VMLINUX_SYMBOL(_einitdata) = .;
diff --git a/arch/tile/lib/atomic_asm_32.S b/arch/tile/lib/atomic_asm_32.S
index 82f64cc63658..24448734f6f1 100644
--- a/arch/tile/lib/atomic_asm_32.S
+++ b/arch/tile/lib/atomic_asm_32.S
@@ -59,7 +59,7 @@
* bad kernel addresses).
*
* Note that if the value we would store is the same as what we
- * loaded, we bypass the load. Other platforms with true atomics can
+ * loaded, we bypass the store. Other platforms with true atomics can
* make the guarantee that a non-atomic __clear_bit(), for example,
* can safely race with an atomic test_and_set_bit(); this example is
* from bit_spinlock.h in slub_lock() / slub_unlock(). We can't do
diff --git a/arch/tile/lib/cacheflush.c b/arch/tile/lib/cacheflush.c
index 35c1d8ca5f38..8928aace7a64 100644
--- a/arch/tile/lib/cacheflush.c
+++ b/arch/tile/lib/cacheflush.c
@@ -15,6 +15,7 @@
#include <asm/page.h>
#include <asm/cacheflush.h>
#include <arch/icache.h>
+#include <arch/spr_def.h>
void __flush_icache_range(unsigned long start, unsigned long end)
@@ -39,6 +40,18 @@ void finv_buffer_remote(void *buffer, size_t size, int hfh)
char *p, *base;
size_t step_size, load_count;
const unsigned long STRIPE_WIDTH = 8192;
+#ifdef __tilegx__
+ /*
+ * On TILE-Gx, we must disable the dstream prefetcher before doing
+ * a cache flush; otherwise, we could end up with data in the cache
+ * that we don't want there. Note that normally we'd do an mf
+ * after the SPR write to disabling the prefetcher, but we do one
+ * below, before any further loads, so there's no need to do it
+ * here.
+ */
+ uint_reg_t old_dstream_pf = __insn_mfspr(SPR_DSTREAM_PF);
+ __insn_mtspr(SPR_DSTREAM_PF, 0);
+#endif
/*
* Flush and invalidate the buffer out of the local L1/L2
@@ -122,4 +135,9 @@ void finv_buffer_remote(void *buffer, size_t size, int hfh)
/* Wait for the load+inv's (and thus finvs) to have completed. */
__insn_mf();
+
+#ifdef __tilegx__
+ /* Reenable the prefetcher. */
+ __insn_mtspr(SPR_DSTREAM_PF, old_dstream_pf);
+#endif
}
diff --git a/arch/tile/lib/memchr_64.c b/arch/tile/lib/memchr_64.c
new file mode 100644
index 000000000000..84fdc8d8e735
--- /dev/null
+++ b/arch/tile/lib/memchr_64.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in 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.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+void *memchr(const void *s, int c, size_t n)
+{
+ const uint64_t *last_word_ptr;
+ const uint64_t *p;
+ const char *last_byte_ptr;
+ uintptr_t s_int;
+ uint64_t goal, before_mask, v, bits;
+ char *ret;
+
+ if (__builtin_expect(n == 0, 0)) {
+ /* Don't dereference any memory if the array is empty. */
+ return NULL;
+ }
+
+ /* Get an aligned pointer. */
+ s_int = (uintptr_t) s;
+ p = (const uint64_t *)(s_int & -8);
+
+ /* Create eight copies of the byte for which we are looking. */
+ goal = 0x0101010101010101ULL * (uint8_t) c;
+
+ /* Read the first word, but munge it so that bytes before the array
+ * will not match goal.
+ *
+ * Note that this shift count expression works because we know
+ * shift counts are taken mod 64.
+ */
+ before_mask = (1ULL << (s_int << 3)) - 1;
+ v = (*p | before_mask) ^ (goal & before_mask);
+
+ /* Compute the address of the last byte. */
+ last_byte_ptr = (const char *)s + n - 1;
+
+ /* Compute the address of the word containing the last byte. */
+ last_word_ptr = (const uint64_t *)((uintptr_t) last_byte_ptr & -8);
+
+ while ((bits = __insn_v1cmpeq(v, goal)) == 0) {
+ if (__builtin_expect(p == last_word_ptr, 0)) {
+ /* We already read the last word in the array,
+ * so give up.
+ */
+ return NULL;
+ }
+ v = *++p;
+ }
+
+ /* We found a match, but it might be in a byte past the end
+ * of the array.
+ */
+ ret = ((char *)p) + (__insn_ctz(bits) >> 3);
+ return (ret <= last_byte_ptr) ? ret : NULL;
+}
+EXPORT_SYMBOL(memchr);
diff --git a/arch/tile/lib/memcpy_64.c b/arch/tile/lib/memcpy_64.c
new file mode 100644
index 000000000000..3fab9a6a2bbe
--- /dev/null
+++ b/arch/tile/lib/memcpy_64.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in 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.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#define __memcpy memcpy
+/* EXPORT_SYMBOL() is in arch/tile/lib/exports.c since this should be asm. */
+
+/* Must be 8 bytes in size. */
+#define word_t uint64_t
+
+#if CHIP_L2_LINE_SIZE() != 64 && CHIP_L2_LINE_SIZE() != 128
+#error "Assumes 64 or 128 byte line size"
+#endif
+
+/* How many cache lines ahead should we prefetch? */
+#define PREFETCH_LINES_AHEAD 3
+
+/*
+ * Provide "base versions" of load and store for the normal code path.
+ * The kernel provides other versions for userspace copies.
+ */
+#define ST(p, v) (*(p) = (v))
+#define LD(p) (*(p))
+
+#ifndef USERCOPY_FUNC
+#define ST1 ST
+#define ST2 ST
+#define ST4 ST
+#define ST8 ST
+#define LD1 LD
+#define LD2 LD
+#define LD4 LD
+#define LD8 LD
+#define RETVAL dstv
+void *memcpy(void *__restrict dstv, const void *__restrict srcv, size_t n)
+#else
+/*
+ * Special kernel version will provide implementation of the LDn/STn
+ * macros to return a count of uncopied bytes due to mm fault.
+ */
+#define RETVAL 0
+int USERCOPY_FUNC(void *__restrict dstv, const void *__restrict srcv, size_t n)
+#endif
+{
+ char *__restrict dst1 = (char *)dstv;
+ const char *__restrict src1 = (const char *)srcv;
+ const char *__restrict src1_end;
+ const char *__restrict prefetch;
+ word_t *__restrict dst8; /* 8-byte pointer to destination memory. */
+ word_t final; /* Final bytes to write to trailing word, if any */
+ long i;
+
+ if (n < 16) {
+ for (; n; n--)
+ ST1(dst1++, LD1(src1++));
+ return RETVAL;
+ }
+
+ /*
+ * Locate the end of source memory we will copy. Don't
+ * prefetch past this.
+ */
+ src1_end = src1 + n - 1;
+
+ /* Prefetch ahead a few cache lines, but not past the end. */
+ prefetch = src1;
+ for (i = 0; i < PREFETCH_LINES_AHEAD; i++) {
+ __insn_prefetch(prefetch);
+ prefetch += CHIP_L2_LINE_SIZE();
+ prefetch = (prefetch > src1_end) ? prefetch : src1;
+ }
+
+ /* Copy bytes until dst is word-aligned. */
+ for (; (uintptr_t)dst1 & (sizeof(word_t) - 1); n--)
+ ST1(dst1++, LD1(src1++));
+
+ /* 8-byte pointer to destination memory. */
+ dst8 = (word_t *)dst1;
+
+ if (__builtin_expect((uintptr_t)src1 & (sizeof(word_t) - 1), 0)) {
+ /*
+ * Misaligned copy. Copy 8 bytes at a time, but don't
+ * bother with other fanciness.
+ *
+ * TODO: Consider prefetching and using wh64 as well.
+ */
+
+ /* Create an aligned src8. */
+ const word_t *__restrict src8 =
+ (const word_t *)((uintptr_t)src1 & -sizeof(word_t));
+ word_t b;
+
+ word_t a = LD8(src8++);
+ for (; n >= sizeof(word_t); n -= sizeof(word_t)) {
+ b = LD8(src8++);
+ a = __insn_dblalign(a, b, src1);
+ ST8(dst8++, a);
+ a = b;
+ }
+
+ if (n == 0)
+ return RETVAL;
+
+ b = ((const char *)src8 <= src1_end) ? *src8 : 0;
+
+ /*
+ * Final source bytes to write to trailing partial
+ * word, if any.
+ */
+ final = __insn_dblalign(a, b, src1);
+ } else {
+ /* Aligned copy. */
+
+ const word_t* __restrict src8 = (const word_t *)src1;
+
+ /* src8 and dst8 are both word-aligned. */
+ if (n >= CHIP_L2_LINE_SIZE()) {
+ /* Copy until 'dst' is cache-line-aligned. */
+ for (; (uintptr_t)dst8 & (CHIP_L2_LINE_SIZE() - 1);
+ n -= sizeof(word_t))
+ ST8(dst8++, LD8(src8++));
+
+ for (; n >= CHIP_L2_LINE_SIZE(); ) {
+ __insn_wh64(dst8);
+
+ /*
+ * Prefetch and advance to next line
+ * to prefetch, but don't go past the end
+ */
+ __insn_prefetch(prefetch);
+ prefetch += CHIP_L2_LINE_SIZE();
+ prefetch = (prefetch > src1_end) ? prefetch :
+ (const char *)src8;
+
+ /*
+ * Copy an entire cache line. Manually
+ * unrolled to avoid idiosyncracies of
+ * compiler unrolling.
+ */
+#define COPY_WORD(offset) ({ ST8(dst8+offset, LD8(src8+offset)); n -= 8; })
+ COPY_WORD(0);
+ COPY_WORD(1);
+ COPY_WORD(2);
+ COPY_WORD(3);
+ COPY_WORD(4);
+ COPY_WORD(5);
+ COPY_WORD(6);
+ COPY_WORD(7);
+#if CHIP_L2_LINE_SIZE() == 128
+ COPY_WORD(8);
+ COPY_WORD(9);
+ COPY_WORD(10);
+ COPY_WORD(11);
+ COPY_WORD(12);
+ COPY_WORD(13);
+ COPY_WORD(14);
+ COPY_WORD(15);
+#elif CHIP_L2_LINE_SIZE() != 64
+# error Fix code that assumes particular L2 cache line sizes
+#endif
+
+ dst8 += CHIP_L2_LINE_SIZE() / sizeof(word_t);
+ src8 += CHIP_L2_LINE_SIZE() / sizeof(word_t);
+ }
+ }
+
+ for (; n >= sizeof(word_t); n -= sizeof(word_t))
+ ST8(dst8++, LD8(src8++));
+
+ if (__builtin_expect(n == 0, 1))
+ return RETVAL;
+
+ final = LD8(src8);
+ }
+
+ /* n != 0 if we get here. Write out any trailing bytes. */
+ dst1 = (char *)dst8;
+ if (n & 4) {
+ ST4((uint32_t *)dst1, final);
+ dst1 += 4;
+ final >>= 32;
+ n &= 3;
+ }
+ if (n & 2) {
+ ST2((uint16_t *)dst1, final);
+ dst1 += 2;
+ final >>= 16;
+ n &= 1;
+ }
+ if (n)
+ ST1((uint8_t *)dst1, final);
+
+ return RETVAL;
+}
+
+
+#ifdef USERCOPY_FUNC
+#undef ST1
+#undef ST2
+#undef ST4
+#undef ST8
+#undef LD1
+#undef LD2
+#undef LD4
+#undef LD8
+#undef USERCOPY_FUNC
+#endif
diff --git a/arch/tile/lib/memcpy_user_64.c b/arch/tile/lib/memcpy_user_64.c
new file mode 100644
index 000000000000..4763b3aff1cc
--- /dev/null
+++ b/arch/tile/lib/memcpy_user_64.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in 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.
+ *
+ * Do memcpy(), but trap and return "n" when a load or store faults.
+ *
+ * Note: this idiom only works when memcpy() compiles to a leaf function.
+ * If "sp" is updated during memcpy, the "jrp lr" will be incorrect.
+ *
+ * Also note that we are capturing "n" from the containing scope here.
+ */
+
+#define _ST(p, inst, v) \
+ ({ \
+ asm("1: " #inst " %0, %1;" \
+ ".pushsection .coldtext.memcpy,\"ax\";" \
+ "2: { move r0, %2; jrp lr };" \
+ ".section __ex_table,\"a\";" \
+ ".quad 1b, 2b;" \
+ ".popsection" \
+ : "=m" (*(p)) : "r" (v), "r" (n)); \
+ })
+
+#define _LD(p, inst) \
+ ({ \
+ unsigned long __v; \
+ asm("1: " #inst " %0, %1;" \
+ ".pushsection .coldtext.memcpy,\"ax\";" \
+ "2: { move r0, %2; jrp lr };" \
+ ".section __ex_table,\"a\";" \
+ ".quad 1b, 2b;" \
+ ".popsection" \
+ : "=r" (__v) : "m" (*(p)), "r" (n)); \
+ __v; \
+ })
+
+#define USERCOPY_FUNC __copy_to_user_inatomic
+#define ST1(p, v) _ST((p), st1, (v))
+#define ST2(p, v) _ST((p), st2, (v))
+#define ST4(p, v) _ST((p), st4, (v))
+#define ST8(p, v) _ST((p), st, (v))
+#define LD1 LD
+#define LD2 LD
+#define LD4 LD
+#define LD8 LD
+#include "memcpy_64.c"
+
+#define USERCOPY_FUNC __copy_from_user_inatomic
+#define ST1 ST
+#define ST2 ST
+#define ST4 ST
+#define ST8 ST
+#define LD1(p) _LD((p), ld1u)
+#define LD2(p) _LD((p), ld2u)
+#define LD4(p) _LD((p), ld4u)
+#define LD8(p) _LD((p), ld)
+#include "memcpy_64.c"
+
+#define USERCOPY_FUNC __copy_in_user_inatomic
+#define ST1(p, v) _ST((p), st1, (v))
+#define ST2(p, v) _ST((p), st2, (v))
+#define ST4(p, v) _ST((p), st4, (v))
+#define ST8(p, v) _ST((p), st, (v))
+#define LD1(p) _LD((p), ld1u)
+#define LD2(p) _LD((p), ld2u)
+#define LD4(p) _LD((p), ld4u)
+#define LD8(p) _LD((p), ld)
+#include "memcpy_64.c"
+
+unsigned long __copy_from_user_zeroing(void *to, const void __user *from,
+ unsigned long n)
+{
+ unsigned long rc = __copy_from_user_inatomic(to, from, n);
+ if (unlikely(rc))
+ memset(to + n - rc, 0, rc);
+ return rc;
+}
diff --git a/arch/tile/lib/memset_64.c b/arch/tile/lib/memset_64.c
new file mode 100644
index 000000000000..3873085711d5
--- /dev/null
+++ b/arch/tile/lib/memset_64.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in 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.
+ */
+
+#include <arch/chip.h>
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+#undef memset
+
+void *memset(void *s, int c, size_t n)
+{
+ uint64_t *out64;
+ int n64, to_align64;
+ uint64_t v64;
+ uint8_t *out8 = s;
+
+ /* Experimentation shows that a trivial tight loop is a win up until
+ * around a size of 20, where writing a word at a time starts to win.
+ */
+#define BYTE_CUTOFF 20
+
+#if BYTE_CUTOFF < 7
+ /* This must be at least at least this big, or some code later
+ * on doesn't work.
+ */
+#error "BYTE_CUTOFF is too small"
+#endif
+
+ if (n < BYTE_CUTOFF) {
+ /* Strangely, this turns out to be the tightest way to
+ * write this loop.
+ */
+ if (n != 0) {
+ do {
+ /* Strangely, combining these into one line
+ * performs worse.
+ */
+ *out8 = c;
+ out8++;
+ } while (--n != 0);
+ }
+
+ return s;
+ }
+
+ /* Align 'out8'. We know n >= 7 so this won't write past the end. */
+ while (((uintptr_t) out8 & 7) != 0) {
+ *out8++ = c;
+ --n;
+ }
+
+ /* Align 'n'. */
+ while (n & 7)
+ out8[--n] = c;
+
+ out64 = (uint64_t *) out8;
+ n64 = n >> 3;
+
+ /* Tile input byte out to 64 bits. */
+ /* KLUDGE */
+ v64 = 0x0101010101010101ULL * (uint8_t)c;
+
+ /* This must be at least 8 or the following loop doesn't work. */
+#define CACHE_LINE_SIZE_IN_DOUBLEWORDS (CHIP_L2_LINE_SIZE() / 8)
+
+ /* Determine how many words we need to emit before the 'out32'
+ * pointer becomes aligned modulo the cache line size.
+ */
+ to_align64 = (-((uintptr_t)out64 >> 3)) &
+ (CACHE_LINE_SIZE_IN_DOUBLEWORDS - 1);
+
+ /* Only bother aligning and using wh64 if there is at least
+ * one full cache line to process. This check also prevents
+ * overrunning the end of the buffer with alignment words.
+ */
+ if (to_align64 <= n64 - CACHE_LINE_SIZE_IN_DOUBLEWORDS) {
+ int lines_left;
+
+ /* Align out64 mod the cache line size so we can use wh64. */
+ n64 -= to_align64;
+ for (; to_align64 != 0; to_align64--) {
+ *out64 = v64;
+ out64++;
+ }
+
+ /* Use unsigned divide to turn this into a right shift. */
+ lines_left = (unsigned)n64 / CACHE_LINE_SIZE_IN_DOUBLEWORDS;
+
+ do {
+ /* Only wh64 a few lines at a time, so we don't
+ * exceed the maximum number of victim lines.
+ */
+ int x = ((lines_left < CHIP_MAX_OUTSTANDING_VICTIMS())
+ ? lines_left
+ : CHIP_MAX_OUTSTANDING_VICTIMS());
+ uint64_t *wh = out64;
+ int i = x;
+ int j;
+
+ lines_left -= x;
+
+ do {
+ __insn_wh64(wh);
+ wh += CACHE_LINE_SIZE_IN_DOUBLEWORDS;
+ } while (--i);
+
+ for (j = x * (CACHE_LINE_SIZE_IN_DOUBLEWORDS / 4);
+ j != 0; j--) {
+ *out64++ = v64;
+ *out64++ = v64;
+ *out64++ = v64;
+ *out64++ = v64;
+ }
+ } while (lines_left != 0);
+
+ /* We processed all full lines above, so only this many
+ * words remain to be processed.
+ */
+ n64 &= CACHE_LINE_SIZE_IN_DOUBLEWORDS - 1;
+ }
+
+ /* Now handle any leftover values. */
+ if (n64 != 0) {
+ do {
+ *out64 = v64;
+ out64++;
+ } while (--n64 != 0);
+ }
+
+ return s;
+}
+EXPORT_SYMBOL(memset);
diff --git a/arch/tile/lib/spinlock_64.c b/arch/tile/lib/spinlock_64.c
new file mode 100644
index 000000000000..d6fb9581e980
--- /dev/null
+++ b/arch/tile/lib/spinlock_64.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in 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.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <asm/processor.h>
+
+#include "spinlock_common.h"
+
+/*
+ * Read the spinlock value without allocating in our cache and without
+ * causing an invalidation to another cpu with a copy of the cacheline.
+ * This is important when we are spinning waiting for the lock.
+ */
+static inline u32 arch_spin_read_noalloc(void *lock)
+{
+ return atomic_cmpxchg((atomic_t *)lock, -1, -1);
+}
+
+/*
+ * Wait until the high bits (current) match my ticket.
+ * If we notice the overflow bit set on entry, we clear it.
+ */
+void arch_spin_lock_slow(arch_spinlock_t *lock, u32 my_ticket)
+{
+ if (unlikely(my_ticket & __ARCH_SPIN_NEXT_OVERFLOW)) {
+ __insn_fetchand4(&lock->lock, ~__ARCH_SPIN_NEXT_OVERFLOW);
+ my_ticket &= ~__ARCH_SPIN_NEXT_OVERFLOW;
+ }
+
+ for (;;) {
+ u32 val = arch_spin_read_noalloc(lock);
+ u32 delta = my_ticket - arch_spin_current(val);
+ if (delta == 0)
+ return;
+ relax((128 / CYCLES_PER_RELAX_LOOP) * delta);
+ }
+}
+EXPORT_SYMBOL(arch_spin_lock_slow);
+
+/*
+ * Check the lock to see if it is plausible, and try to get it with cmpxchg().
+ */
+int arch_spin_trylock(arch_spinlock_t *lock)
+{
+ u32 val = arch_spin_read_noalloc(lock);
+ if (unlikely(arch_spin_current(val) != arch_spin_next(val)))
+ return 0;
+ return cmpxchg(&lock->lock, val, (val + 1) & ~__ARCH_SPIN_NEXT_OVERFLOW)
+ == val;
+}
+EXPORT_SYMBOL(arch_spin_trylock);
+
+void arch_spin_unlock_wait(arch_spinlock_t *lock)
+{
+ u32 iterations = 0;
+ while (arch_spin_is_locked(lock))
+ delay_backoff(iterations++);
+}
+EXPORT_SYMBOL(arch_spin_unlock_wait);
+
+/*
+ * If the read lock fails due to a writer, we retry periodically
+ * until the value is positive and we write our incremented reader count.
+ */
+void __read_lock_failed(arch_rwlock_t *rw)
+{
+ u32 val;
+ int iterations = 0;
+ do {
+ delay_backoff(iterations++);
+ val = __insn_fetchaddgez4(&rw->lock, 1);
+ } while (unlikely(arch_write_val_locked(val)));
+}
+EXPORT_SYMBOL(__read_lock_failed);
+
+/*
+ * If we failed because there were readers, clear the "writer" bit
+ * so we don't block additional readers. Otherwise, there was another
+ * writer anyway, so our "fetchor" made no difference. Then wait,
+ * issuing periodic fetchor instructions, till we get the lock.
+ */
+void __write_lock_failed(arch_rwlock_t *rw, u32 val)
+{
+ int iterations = 0;
+ do {
+ if (!arch_write_val_locked(val))
+ val = __insn_fetchand4(&rw->lock, ~__WRITE_LOCK_BIT);
+ delay_backoff(iterations++);
+ val = __insn_fetchor4(&rw->lock, __WRITE_LOCK_BIT);
+ } while (val != 0);
+}
+EXPORT_SYMBOL(__write_lock_failed);
diff --git a/arch/tile/lib/strchr_64.c b/arch/tile/lib/strchr_64.c
new file mode 100644
index 000000000000..617a9273aaa8
--- /dev/null
+++ b/arch/tile/lib/strchr_64.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in 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.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+#undef strchr
+
+char *strchr(const char *s, int c)
+{
+ int z, g;
+
+ /* Get an aligned pointer. */
+ const uintptr_t s_int = (uintptr_t) s;
+ const uint64_t *p = (const uint64_t *)(s_int & -8);
+
+ /* Create eight copies of the byte for which we are looking. */
+ const uint64_t goal = 0x0101010101010101ULL * (uint8_t) c;
+
+ /* Read the first aligned word, but force bytes before the string to
+ * match neither zero nor goal (we make sure the high bit of each
+ * byte is 1, and the low 7 bits are all the opposite of the goal
+ * byte).
+ *
+ * Note that this shift count expression works because we know shift
+ * counts are taken mod 64.
+ */
+ const uint64_t before_mask = (1ULL << (s_int << 3)) - 1;
+ uint64_t v = (*p | before_mask) ^
+ (goal & __insn_v1shrsi(before_mask, 1));
+
+ uint64_t zero_matches, goal_matches;
+ while (1) {
+ /* Look for a terminating '\0'. */
+ zero_matches = __insn_v1cmpeqi(v, 0);
+
+ /* Look for the goal byte. */
+ goal_matches = __insn_v1cmpeq(v, goal);
+
+ if (__builtin_expect((zero_matches | goal_matches) != 0, 0))
+ break;
+
+ v = *++p;
+ }
+
+ z = __insn_ctz(zero_matches);
+ g = __insn_ctz(goal_matches);
+
+ /* If we found c before '\0' we got a match. Note that if c == '\0'
+ * then g == z, and we correctly return the address of the '\0'
+ * rather than NULL.
+ */
+ return (g <= z) ? ((char *)p) + (g >> 3) : NULL;
+}
+EXPORT_SYMBOL(strchr);
diff --git a/arch/tile/lib/strlen_64.c b/arch/tile/lib/strlen_64.c
new file mode 100644
index 000000000000..1c92d46202a8
--- /dev/null
+++ b/arch/tile/lib/strlen_64.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in 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.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+#undef strlen
+
+size_t strlen(const char *s)
+{
+ /* Get an aligned pointer. */
+ const uintptr_t s_int = (uintptr_t) s;
+ const uint64_t *p = (const uint64_t *)(s_int & -8);
+
+ /* Read the first word, but force bytes before the string to be nonzero.
+ * This expression works because we know shift counts are taken mod 64.
+ */
+ uint64_t v = *p | ((1ULL << (s_int << 3)) - 1);
+
+ uint64_t bits;
+ while ((bits = __insn_v1cmpeqi(v, 0)) == 0)
+ v = *++p;
+
+ return ((const char *)p) + (__insn_ctz(bits) >> 3) - s;
+}
+EXPORT_SYMBOL(strlen);
diff --git a/arch/tile/lib/usercopy_64.S b/arch/tile/lib/usercopy_64.S
new file mode 100644
index 000000000000..2ff44f87b78e
--- /dev/null
+++ b/arch/tile/lib/usercopy_64.S
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in 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.
+ */
+
+#include <linux/linkage.h>
+#include <asm/errno.h>
+#include <asm/cache.h>
+#include <arch/chip.h>
+
+/* Access user memory, but use MMU to avoid propagating kernel exceptions. */
+
+ .pushsection .fixup,"ax"
+
+get_user_fault:
+ { movei r1, -EFAULT; move r0, zero }
+ jrp lr
+ ENDPROC(get_user_fault)
+
+put_user_fault:
+ { movei r0, -EFAULT; jrp lr }
+ ENDPROC(put_user_fault)
+
+ .popsection
+
+/*
+ * __get_user_N functions take a pointer in r0, and return 0 in r1
+ * on success, with the value in r0; or else -EFAULT in r1.
+ */
+#define __get_user_N(bytes, LOAD) \
+ STD_ENTRY(__get_user_##bytes); \
+1: { LOAD r0, r0; move r1, zero }; \
+ jrp lr; \
+ STD_ENDPROC(__get_user_##bytes); \
+ .pushsection __ex_table,"a"; \
+ .quad 1b, get_user_fault; \
+ .popsection
+
+__get_user_N(1, ld1u)
+__get_user_N(2, ld2u)
+__get_user_N(4, ld4u)
+__get_user_N(8, ld)
+
+/*
+ * __put_user_N functions take a value in r0 and a pointer in r1,
+ * and return 0 in r0 on success or -EFAULT on failure.
+ */
+#define __put_user_N(bytes, STORE) \
+ STD_ENTRY(__put_user_##bytes); \
+1: { STORE r1, r0; move r0, zero }; \
+ jrp lr; \
+ STD_ENDPROC(__put_user_##bytes); \
+ .pushsection __ex_table,"a"; \
+ .quad 1b, put_user_fault; \
+ .popsection
+
+__put_user_N(1, st1)
+__put_user_N(2, st2)
+__put_user_N(4, st4)
+__put_user_N(8, st)
+
+/*
+ * strnlen_user_asm takes the pointer in r0, and the length bound in r1.
+ * It returns the length, including the terminating NUL, or zero on exception.
+ * If length is greater than the bound, returns one plus the bound.
+ */
+STD_ENTRY(strnlen_user_asm)
+ { beqz r1, 2f; addi r3, r0, -1 } /* bias down to include NUL */
+1: { ld1u r4, r0; addi r1, r1, -1 }
+ beqz r4, 2f
+ { bnezt r1, 1b; addi r0, r0, 1 }
+2: { sub r0, r0, r3; jrp lr }
+ STD_ENDPROC(strnlen_user_asm)
+ .pushsection .fixup,"ax"
+strnlen_user_fault:
+ { move r0, zero; jrp lr }
+ ENDPROC(strnlen_user_fault)
+ .section __ex_table,"a"
+ .quad 1b, strnlen_user_fault
+ .popsection
+
+/*
+ * strncpy_from_user_asm takes the kernel target pointer in r0,
+ * the userspace source pointer in r1, and the length bound (including
+ * the trailing NUL) in r2. On success, it returns the string length
+ * (not including the trailing NUL), or -EFAULT on failure.
+ */
+STD_ENTRY(strncpy_from_user_asm)
+ { beqz r2, 2f; move r3, r0 }
+1: { ld1u r4, r1; addi r1, r1, 1; addi r2, r2, -1 }
+ { st1 r0, r4; addi r0, r0, 1 }
+ beqz r2, 2f
+ bnezt r4, 1b
+ addi r0, r0, -1 /* don't count the trailing NUL */
+2: { sub r0, r0, r3; jrp lr }
+ STD_ENDPROC(strncpy_from_user_asm)
+ .pushsection .fixup,"ax"
+strncpy_from_user_fault:
+ { movei r0, -EFAULT; jrp lr }
+ ENDPROC(strncpy_from_user_fault)
+ .section __ex_table,"a"
+ .quad 1b, strncpy_from_user_fault
+ .popsection
+
+/*
+ * clear_user_asm takes the user target address in r0 and the
+ * number of bytes to zero in r1.
+ * It returns the number of uncopiable bytes (hopefully zero) in r0.
+ * Note that we don't use a separate .fixup section here since we fall
+ * through into the "fixup" code as the last straight-line bundle anyway.
+ */
+STD_ENTRY(clear_user_asm)
+ { beqz r1, 2f; or r2, r0, r1 }
+ andi r2, r2, 7
+ beqzt r2, .Lclear_aligned_user_asm
+1: { st1 r0, zero; addi r0, r0, 1; addi r1, r1, -1 }
+ bnezt r1, 1b
+2: { move r0, r1; jrp lr }
+ .pushsection __ex_table,"a"
+ .quad 1b, 2b
+ .popsection
+
+.Lclear_aligned_user_asm:
+1: { st r0, zero; addi r0, r0, 8; addi r1, r1, -8 }
+ bnezt r1, 1b
+2: { move r0, r1; jrp lr }
+ STD_ENDPROC(clear_user_asm)
+ .pushsection __ex_table,"a"
+ .quad 1b, 2b
+ .popsection
+
+/*
+ * flush_user_asm takes the user target address in r0 and the
+ * number of bytes to flush in r1.
+ * It returns the number of unflushable bytes (hopefully zero) in r0.
+ */
+STD_ENTRY(flush_user_asm)
+ beqz r1, 2f
+ { movei r2, L2_CACHE_BYTES; add r1, r0, r1 }
+ { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 }
+ { and r0, r0, r2; and r1, r1, r2 }
+ { sub r1, r1, r0 }
+1: { flush r0; addi r1, r1, -CHIP_FLUSH_STRIDE() }
+ { addi r0, r0, CHIP_FLUSH_STRIDE(); bnezt r1, 1b }
+2: { move r0, r1; jrp lr }
+ STD_ENDPROC(flush_user_asm)
+ .pushsection __ex_table,"a"
+ .quad 1b, 2b
+ .popsection
+
+/*
+ * inv_user_asm takes the user target address in r0 and the
+ * number of bytes to invalidate in r1.
+ * It returns the number of not inv'able bytes (hopefully zero) in r0.
+ */
+STD_ENTRY(inv_user_asm)
+ beqz r1, 2f
+ { movei r2, L2_CACHE_BYTES; add r1, r0, r1 }
+ { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 }
+ { and r0, r0, r2; and r1, r1, r2 }
+ { sub r1, r1, r0 }
+1: { inv r0; addi r1, r1, -CHIP_INV_STRIDE() }
+ { addi r0, r0, CHIP_INV_STRIDE(); bnezt r1, 1b }
+2: { move r0, r1; jrp lr }
+ STD_ENDPROC(inv_user_asm)
+ .pushsection __ex_table,"a"
+ .quad 1b, 2b
+ .popsection
+
+/*
+ * finv_user_asm takes the user target address in r0 and the
+ * number of bytes to flush-invalidate in r1.
+ * It returns the number of not finv'able bytes (hopefully zero) in r0.
+ */
+STD_ENTRY(finv_user_asm)
+ beqz r1, 2f
+ { movei r2, L2_CACHE_BYTES; add r1, r0, r1 }
+ { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 }
+ { and r0, r0, r2; and r1, r1, r2 }
+ { sub r1, r1, r0 }
+1: { finv r0; addi r1, r1, -CHIP_FINV_STRIDE() }
+ { addi r0, r0, CHIP_FINV_STRIDE(); bnezt r1, 1b }
+2: { move r0, r1; jrp lr }
+ STD_ENDPROC(finv_user_asm)
+ .pushsection __ex_table,"a"
+ .quad 1b, 2b
+ .popsection
diff --git a/arch/tile/mm/fault.c b/arch/tile/mm/fault.c
index 51f8663bf074..25b7b90fd620 100644
--- a/arch/tile/mm/fault.c
+++ b/arch/tile/mm/fault.c
@@ -43,8 +43,11 @@
#include <arch/interrupts.h>
-static noinline void force_sig_info_fault(int si_signo, int si_code,
- unsigned long address, int fault_num, struct task_struct *tsk)
+static noinline void force_sig_info_fault(const char *type, int si_signo,
+ int si_code, unsigned long address,
+ int fault_num,
+ struct task_struct *tsk,
+ struct pt_regs *regs)
{
siginfo_t info;
@@ -59,6 +62,7 @@ static noinline void force_sig_info_fault(int si_signo, int si_code,
info.si_code = si_code;
info.si_addr = (void __user *)address;
info.si_trapno = fault_num;
+ trace_unhandled_signal(type, regs, address, si_signo);
force_sig_info(si_signo, &info, tsk);
}
@@ -71,11 +75,12 @@ SYSCALL_DEFINE2(cmpxchg_badaddr, unsigned long, address,
struct pt_regs *, regs)
{
if (address >= PAGE_OFFSET)
- force_sig_info_fault(SIGSEGV, SEGV_MAPERR, address,
- INT_DTLB_MISS, current);
+ force_sig_info_fault("atomic segfault", SIGSEGV, SEGV_MAPERR,
+ address, INT_DTLB_MISS, current, regs);
else
- force_sig_info_fault(SIGBUS, BUS_ADRALN, address,
- INT_UNALIGN_DATA, current);
+ force_sig_info_fault("atomic alignment fault", SIGBUS,
+ BUS_ADRALN, address,
+ INT_UNALIGN_DATA, current, regs);
/*
* Adjust pc to point at the actual instruction, which is unusual
@@ -471,8 +476,8 @@ bad_area_nosemaphore:
*/
local_irq_enable();
- force_sig_info_fault(SIGSEGV, si_code, address,
- fault_num, tsk);
+ force_sig_info_fault("segfault", SIGSEGV, si_code, address,
+ fault_num, tsk, regs);
return 0;
}
@@ -547,7 +552,8 @@ do_sigbus:
if (is_kernel_mode)
goto no_context;
- force_sig_info_fault(SIGBUS, BUS_ADRERR, address, fault_num, tsk);
+ force_sig_info_fault("bus error", SIGBUS, BUS_ADRERR, address,
+ fault_num, tsk, regs);
return 0;
}
@@ -732,6 +738,7 @@ void do_page_fault(struct pt_regs *regs, int fault_num,
panic("Bad fault number %d in do_page_fault", fault_num);
}
+#if CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC()
if (EX1_PL(regs->ex1) != USER_PL) {
struct async_tlb *async;
switch (fault_num) {
@@ -775,6 +782,7 @@ void do_page_fault(struct pt_regs *regs, int fault_num,
return;
}
}
+#endif
handle_page_fault(regs, fault_num, is_page_fault, address, write);
}
@@ -801,8 +809,6 @@ static void handle_async_page_fault(struct pt_regs *regs,
async->address, async->is_write);
}
}
-#endif /* CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC() */
-
/*
* This routine effectively re-issues asynchronous page faults
@@ -824,6 +830,8 @@ void do_async_page_fault(struct pt_regs *regs)
handle_async_page_fault(regs, &current->thread.sn_async_tlb);
#endif
}
+#endif /* CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC() */
+
void vmalloc_sync_all(void)
{
diff --git a/arch/tile/mm/init.c b/arch/tile/mm/init.c
index d6e87fda2fb2..4e10c4023028 100644
--- a/arch/tile/mm/init.c
+++ b/arch/tile/mm/init.c
@@ -60,8 +60,6 @@ unsigned long VMALLOC_RESERVE = CONFIG_VMALLOC_RESERVE;
EXPORT_SYMBOL(VMALLOC_RESERVE);
#endif
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
/* Create an L2 page table */
static pte_t * __init alloc_pte(void)
{
diff --git a/arch/tile/mm/migrate_64.S b/arch/tile/mm/migrate_64.S
new file mode 100644
index 000000000000..e76fea688beb
--- /dev/null
+++ b/arch/tile/mm/migrate_64.S
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in 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.
+ *
+ * This routine is a helper for migrating the home of a set of pages to
+ * a new cpu. See the documentation in homecache.c for more information.
+ */
+
+#include <linux/linkage.h>
+#include <linux/threads.h>
+#include <asm/page.h>
+#include <asm/thread_info.h>
+#include <asm/types.h>
+#include <asm/asm-offsets.h>
+#include <hv/hypervisor.h>
+
+ .text
+
+/*
+ * First, some definitions that apply to all the code in the file.
+ */
+
+/* Locals (caller-save) */
+#define r_tmp r10
+#define r_save_sp r11
+
+/* What we save where in the stack frame; must include all callee-saves. */
+#define FRAME_SP 8
+#define FRAME_R30 16
+#define FRAME_R31 24
+#define FRAME_R32 32
+#define FRAME_R33 40
+#define FRAME_SIZE 48
+
+
+
+
+/*
+ * On entry:
+ *
+ * r0 the new context PA to install (moved to r_context)
+ * r1 PTE to use for context access (moved to r_access)
+ * r2 ASID to use for new context (moved to r_asid)
+ * r3 pointer to cpumask with just this cpu set in it (r_my_cpumask)
+ */
+
+/* Arguments (caller-save) */
+#define r_context_in r0
+#define r_access_in r1
+#define r_asid_in r2
+#define r_my_cpumask r3
+
+/* Locals (callee-save); must not be more than FRAME_xxx above. */
+#define r_save_ics r30
+#define r_context r31
+#define r_access r32
+#define r_asid r33
+
+/*
+ * Caller-save locals and frame constants are the same as
+ * for homecache_migrate_stack_and_flush.
+ */
+
+STD_ENTRY(flush_and_install_context)
+ /*
+ * Create a stack frame; we can't touch it once we flush the
+ * cache until we install the new page table and flush the TLB.
+ */
+ {
+ move r_save_sp, sp
+ st sp, lr
+ addi sp, sp, -FRAME_SIZE
+ }
+ addi r_tmp, sp, FRAME_SP
+ {
+ st r_tmp, r_save_sp
+ addi r_tmp, sp, FRAME_R30
+ }
+ {
+ st r_tmp, r30
+ addi r_tmp, sp, FRAME_R31
+ }
+ {
+ st r_tmp, r31
+ addi r_tmp, sp, FRAME_R32
+ }
+ {
+ st r_tmp, r32
+ addi r_tmp, sp, FRAME_R33
+ }
+ st r_tmp, r33
+
+ /* Move some arguments to callee-save registers. */
+ {
+ move r_context, r_context_in
+ move r_access, r_access_in
+ }
+ move r_asid, r_asid_in
+
+ /* Disable interrupts, since we can't use our stack. */
+ {
+ mfspr r_save_ics, INTERRUPT_CRITICAL_SECTION
+ movei r_tmp, 1
+ }
+ mtspr INTERRUPT_CRITICAL_SECTION, r_tmp
+
+ /* First, flush our L2 cache. */
+ {
+ move r0, zero /* cache_pa */
+ moveli r1, hw2_last(HV_FLUSH_EVICT_L2) /* cache_control */
+ }
+ {
+ shl16insli r1, r1, hw1(HV_FLUSH_EVICT_L2)
+ move r2, r_my_cpumask /* cache_cpumask */
+ }
+ {
+ shl16insli r1, r1, hw0(HV_FLUSH_EVICT_L2)
+ move r3, zero /* tlb_va */
+ }
+ {
+ move r4, zero /* tlb_length */
+ move r5, zero /* tlb_pgsize */
+ }
+ {
+ move r6, zero /* tlb_cpumask */
+ move r7, zero /* asids */
+ }
+ {
+ move r8, zero /* asidcount */
+ jal hv_flush_remote
+ }
+ bnez r0, 1f
+
+ /* Now install the new page table. */
+ {
+ move r0, r_context
+ move r1, r_access
+ }
+ {
+ move r2, r_asid
+ movei r3, HV_CTX_DIRECTIO
+ }
+ jal hv_install_context
+ bnez r0, 1f
+
+ /* Finally, flush the TLB. */
+ {
+ movei r0, 0 /* preserve_global */
+ jal hv_flush_all
+ }
+
+1: /* Reset interrupts back how they were before. */
+ mtspr INTERRUPT_CRITICAL_SECTION, r_save_ics
+
+ /* Restore the callee-saved registers and return. */
+ addli lr, sp, FRAME_SIZE
+ {
+ ld lr, lr
+ addli r_tmp, sp, FRAME_R30
+ }
+ {
+ ld r30, r_tmp
+ addli r_tmp, sp, FRAME_R31
+ }
+ {
+ ld r31, r_tmp
+ addli r_tmp, sp, FRAME_R32
+ }
+ {
+ ld r32, r_tmp
+ addli r_tmp, sp, FRAME_R33
+ }
+ {
+ ld r33, r_tmp
+ addi sp, sp, FRAME_SIZE
+ }
+ jrp lr
+ STD_ENDPROC(flush_and_install_context)
diff --git a/arch/um/Kconfig.debug b/arch/um/Kconfig.debug
index 8fce5e536b0f..68205fd3b08c 100644
--- a/arch/um/Kconfig.debug
+++ b/arch/um/Kconfig.debug
@@ -28,13 +28,13 @@ config GCOV
If you're involved in UML kernel development and want to use gcov,
say Y. If you're unsure, say N.
-config DEBUG_STACK_USAGE
- bool "Stack utilization instrumentation"
- default N
- help
- Track the maximum kernel stack usage - this will look at each
- kernel stack at process exit and log it if it's the deepest
- stack seen so far.
+config EARLY_PRINTK
+ bool "Early printk"
+ default y
+ ---help---
+ Write kernel log output directly to stdout.
+
+ This is useful for kernel debugging when your machine crashes very
+ early before the console code is initialized.
- This option will slow down process creation and destruction somewhat.
endmenu
diff --git a/arch/um/Kconfig.x86 b/arch/um/Kconfig.x86
index a9da516a5274..8aae429a56e2 100644
--- a/arch/um/Kconfig.x86
+++ b/arch/um/Kconfig.x86
@@ -15,7 +15,6 @@ endmenu
config UML_X86
def_bool y
select GENERIC_FIND_FIRST_BIT
- select GENERIC_FIND_NEXT_BIT
config 64BIT
bool
@@ -29,10 +28,10 @@ config X86_64
def_bool 64BIT
config RWSEM_XCHGADD_ALGORITHM
- def_bool X86_XADD
+ def_bool X86_XADD && 64BIT
config RWSEM_GENERIC_SPINLOCK
- def_bool !X86_XADD
+ def_bool !RWSEM_XCHGADD_ALGORITHM
config 3_LEVEL_PGTABLES
bool "Three-level pagetables (EXPERIMENTAL)" if !64BIT
diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile
index 1d9b6ae967b0..e7582e1d248c 100644
--- a/arch/um/drivers/Makefile
+++ b/arch/um/drivers/Makefile
@@ -9,7 +9,7 @@
slip-objs := slip_kern.o slip_user.o
slirp-objs := slirp_kern.o slirp_user.o
daemon-objs := daemon_kern.o daemon_user.o
-mcast-objs := mcast_kern.o mcast_user.o
+umcast-objs := umcast_kern.o umcast_user.o
net-objs := net_kern.o net_user.o
mconsole-objs := mconsole_kern.o mconsole_user.o
hostaudio-objs := hostaudio_kern.o
@@ -44,7 +44,7 @@ obj-$(CONFIG_UML_NET_SLIP) += slip.o slip_common.o
obj-$(CONFIG_UML_NET_SLIRP) += slirp.o slip_common.o
obj-$(CONFIG_UML_NET_DAEMON) += daemon.o
obj-$(CONFIG_UML_NET_VDE) += vde.o
-obj-$(CONFIG_UML_NET_MCAST) += mcast.o
+obj-$(CONFIG_UML_NET_MCAST) += umcast.o
obj-$(CONFIG_UML_NET_PCAP) += pcap.o
obj-$(CONFIG_UML_NET) += net.o
obj-$(CONFIG_MCONSOLE) += mconsole.o
diff --git a/arch/um/drivers/mcast.h b/arch/um/drivers/mcast.h
deleted file mode 100644
index 6fa282e896be..000000000000
--- a/arch/um/drivers/mcast.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
- * Licensed under the GPL
- */
-
-#ifndef __DRIVERS_MCAST_H
-#define __DRIVERS_MCAST_H
-
-#include "net_user.h"
-
-struct mcast_data {
- char *addr;
- unsigned short port;
- void *mcast_addr;
- int ttl;
- void *dev;
-};
-
-extern const struct net_user_info mcast_user_info;
-
-extern int mcast_user_write(int fd, void *buf, int len,
- struct mcast_data *pri);
-
-#endif
diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c
deleted file mode 100644
index ffc6416d5ed7..000000000000
--- a/arch/um/drivers/mcast_kern.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * user-mode-linux networking multicast transport
- * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
- * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
- *
- * based on the existing uml-networking code, which is
- * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
- * James Leu (jleu@mindspring.net).
- * Copyright (C) 2001 by various other people who didn't put their name here.
- *
- * Licensed under the GPL.
- */
-
-#include "linux/init.h"
-#include <linux/netdevice.h>
-#include "mcast.h"
-#include "net_kern.h"
-
-struct mcast_init {
- char *addr;
- int port;
- int ttl;
-};
-
-static void mcast_init(struct net_device *dev, void *data)
-{
- struct uml_net_private *pri;
- struct mcast_data *dpri;
- struct mcast_init *init = data;
-
- pri = netdev_priv(dev);
- dpri = (struct mcast_data *) pri->user;
- dpri->addr = init->addr;
- dpri->port = init->port;
- dpri->ttl = init->ttl;
- dpri->dev = dev;
-
- printk("mcast backend multicast address: %s:%u, TTL:%u\n",
- dpri->addr, dpri->port, dpri->ttl);
-}
-
-static int mcast_read(int fd, struct sk_buff *skb, struct uml_net_private *lp)
-{
- return net_recvfrom(fd, skb_mac_header(skb),
- skb->dev->mtu + ETH_HEADER_OTHER);
-}
-
-static int mcast_write(int fd, struct sk_buff *skb, struct uml_net_private *lp)
-{
- return mcast_user_write(fd, skb->data, skb->len,
- (struct mcast_data *) &lp->user);
-}
-
-static const struct net_kern_info mcast_kern_info = {
- .init = mcast_init,
- .protocol = eth_protocol,
- .read = mcast_read,
- .write = mcast_write,
-};
-
-static int mcast_setup(char *str, char **mac_out, void *data)
-{
- struct mcast_init *init = data;
- char *port_str = NULL, *ttl_str = NULL, *remain;
- char *last;
-
- *init = ((struct mcast_init)
- { .addr = "239.192.168.1",
- .port = 1102,
- .ttl = 1 });
-
- remain = split_if_spec(str, mac_out, &init->addr, &port_str, &ttl_str,
- NULL);
- if (remain != NULL) {
- printk(KERN_ERR "mcast_setup - Extra garbage on "
- "specification : '%s'\n", remain);
- return 0;
- }
-
- if (port_str != NULL) {
- init->port = simple_strtoul(port_str, &last, 10);
- if ((*last != '\0') || (last == port_str)) {
- printk(KERN_ERR "mcast_setup - Bad port : '%s'\n",
- port_str);
- return 0;
- }
- }
-
- if (ttl_str != NULL) {
- init->ttl = simple_strtoul(ttl_str, &last, 10);
- if ((*last != '\0') || (last == ttl_str)) {
- printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n",
- ttl_str);
- return 0;
- }
- }
-
- printk(KERN_INFO "Configured mcast device: %s:%u-%u\n", init->addr,
- init->port, init->ttl);
-
- return 1;
-}
-
-static struct transport mcast_transport = {
- .list = LIST_HEAD_INIT(mcast_transport.list),
- .name = "mcast",
- .setup = mcast_setup,
- .user = &mcast_user_info,
- .kern = &mcast_kern_info,
- .private_size = sizeof(struct mcast_data),
- .setup_size = sizeof(struct mcast_init),
-};
-
-static int register_mcast(void)
-{
- register_transport(&mcast_transport);
- return 0;
-}
-
-late_initcall(register_mcast);
diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c
deleted file mode 100644
index ee19e91568a2..000000000000
--- a/arch/um/drivers/mcast_user.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * user-mode-linux networking multicast transport
- * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
- * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
- *
- * based on the existing uml-networking code, which is
- * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
- * James Leu (jleu@mindspring.net).
- * Copyright (C) 2001 by various other people who didn't put their name here.
- *
- * Licensed under the GPL.
- *
- */
-
-#include <unistd.h>
-#include <errno.h>
-#include <netinet/in.h>
-#include "kern_constants.h"
-#include "mcast.h"
-#include "net_user.h"
-#include "um_malloc.h"
-#include "user.h"
-
-static struct sockaddr_in *new_addr(char *addr, unsigned short port)
-{
- struct sockaddr_in *sin;
-
- sin = uml_kmalloc(sizeof(struct sockaddr_in), UM_GFP_KERNEL);
- if (sin == NULL) {
- printk(UM_KERN_ERR "new_addr: allocation of sockaddr_in "
- "failed\n");
- return NULL;
- }
- sin->sin_family = AF_INET;
- sin->sin_addr.s_addr = in_aton(addr);
- sin->sin_port = htons(port);
- return sin;
-}
-
-static int mcast_user_init(void *data, void *dev)
-{
- struct mcast_data *pri = data;
-
- pri->mcast_addr = new_addr(pri->addr, pri->port);
- pri->dev = dev;
- return 0;
-}
-
-static void mcast_remove(void *data)
-{
- struct mcast_data *pri = data;
-
- kfree(pri->mcast_addr);
- pri->mcast_addr = NULL;
-}
-
-static int mcast_open(void *data)
-{
- struct mcast_data *pri = data;
- struct sockaddr_in *sin = pri->mcast_addr;
- struct ip_mreq mreq;
- int fd, yes = 1, err = -EINVAL;
-
-
- if ((sin->sin_addr.s_addr == 0) || (sin->sin_port == 0))
- goto out;
-
- fd = socket(AF_INET, SOCK_DGRAM, 0);
-
- if (fd < 0) {
- err = -errno;
- printk(UM_KERN_ERR "mcast_open : data socket failed, "
- "errno = %d\n", errno);
- goto out;
- }
-
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
- err = -errno;
- printk(UM_KERN_ERR "mcast_open: SO_REUSEADDR failed, "
- "errno = %d\n", errno);
- goto out_close;
- }
-
- /* set ttl according to config */
- if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl,
- sizeof(pri->ttl)) < 0) {
- err = -errno;
- printk(UM_KERN_ERR "mcast_open: IP_MULTICAST_TTL failed, "
- "error = %d\n", errno);
- goto out_close;
- }
-
- /* set LOOP, so data does get fed back to local sockets */
- if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
- err = -errno;
- printk(UM_KERN_ERR "mcast_open: IP_MULTICAST_LOOP failed, "
- "error = %d\n", errno);
- goto out_close;
- }
-
- /* bind socket to mcast address */
- if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) {
- err = -errno;
- printk(UM_KERN_ERR "mcast_open : data bind failed, "
- "errno = %d\n", errno);
- goto out_close;
- }
-
- /* subscribe to the multicast group */
- mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr;
- mreq.imr_interface.s_addr = 0;
- if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP,
- &mreq, sizeof(mreq)) < 0) {
- err = -errno;
- printk(UM_KERN_ERR "mcast_open: IP_ADD_MEMBERSHIP failed, "
- "error = %d\n", errno);
- printk(UM_KERN_ERR "There appears not to be a multicast-"
- "capable network interface on the host.\n");
- printk(UM_KERN_ERR "eth0 should be configured in order to use "
- "the multicast transport.\n");
- goto out_close;
- }
-
- return fd;
-
- out_close:
- close(fd);
- out:
- return err;
-}
-
-static void mcast_close(int fd, void *data)
-{
- struct ip_mreq mreq;
- struct mcast_data *pri = data;
- struct sockaddr_in *sin = pri->mcast_addr;
-
- mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr;
- mreq.imr_interface.s_addr = 0;
- if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP,
- &mreq, sizeof(mreq)) < 0) {
- printk(UM_KERN_ERR "mcast_open: IP_DROP_MEMBERSHIP failed, "
- "error = %d\n", errno);
- }
-
- close(fd);
-}
-
-int mcast_user_write(int fd, void *buf, int len, struct mcast_data *pri)
-{
- struct sockaddr_in *data_addr = pri->mcast_addr;
-
- return net_sendto(fd, buf, len, data_addr, sizeof(*data_addr));
-}
-
-const struct net_user_info mcast_user_info = {
- .init = mcast_user_init,
- .open = mcast_open,
- .close = mcast_close,
- .remove = mcast_remove,
- .add_address = NULL,
- .delete_address = NULL,
- .mtu = ETH_MAX_PACKET,
- .max_packet = ETH_MAX_PACKET + ETH_HEADER_OTHER,
-};
diff --git a/arch/um/drivers/mmapper_kern.c b/arch/um/drivers/mmapper_kern.c
index 7e0619c2c2c6..c0ef803c7c70 100644
--- a/arch/um/drivers/mmapper_kern.c
+++ b/arch/um/drivers/mmapper_kern.c
@@ -116,7 +116,7 @@ static int __init mmapper_init(void)
if (err) {
printk(KERN_ERR "mmapper - misc_register failed, err = %d\n",
err);
- return err;;
+ return err;
}
return 0;
}
diff --git a/arch/um/drivers/umcast.h b/arch/um/drivers/umcast.h
new file mode 100644
index 000000000000..6f8c0fe890fb
--- /dev/null
+++ b/arch/um/drivers/umcast.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __DRIVERS_UMCAST_H
+#define __DRIVERS_UMCAST_H
+
+#include "net_user.h"
+
+struct umcast_data {
+ char *addr;
+ unsigned short lport;
+ unsigned short rport;
+ void *listen_addr;
+ void *remote_addr;
+ int ttl;
+ int unicast;
+ void *dev;
+};
+
+extern const struct net_user_info umcast_user_info;
+
+extern int umcast_user_write(int fd, void *buf, int len,
+ struct umcast_data *pri);
+
+#endif
diff --git a/arch/um/drivers/umcast_kern.c b/arch/um/drivers/umcast_kern.c
new file mode 100644
index 000000000000..42dab11d2ecf
--- /dev/null
+++ b/arch/um/drivers/umcast_kern.c
@@ -0,0 +1,188 @@
+/*
+ * user-mode-linux networking multicast transport
+ * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ *
+ * based on the existing uml-networking code, which is
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
+ * James Leu (jleu@mindspring.net).
+ * Copyright (C) 2001 by various other people who didn't put their name here.
+ *
+ * Licensed under the GPL.
+ */
+
+#include "linux/init.h"
+#include <linux/netdevice.h>
+#include "umcast.h"
+#include "net_kern.h"
+
+struct umcast_init {
+ char *addr;
+ int lport;
+ int rport;
+ int ttl;
+ bool unicast;
+};
+
+static void umcast_init(struct net_device *dev, void *data)
+{
+ struct uml_net_private *pri;
+ struct umcast_data *dpri;
+ struct umcast_init *init = data;
+
+ pri = netdev_priv(dev);
+ dpri = (struct umcast_data *) pri->user;
+ dpri->addr = init->addr;
+ dpri->lport = init->lport;
+ dpri->rport = init->rport;
+ dpri->unicast = init->unicast;
+ dpri->ttl = init->ttl;
+ dpri->dev = dev;
+
+ if (dpri->unicast) {
+ printk(KERN_INFO "ucast backend address: %s:%u listen port: "
+ "%u\n", dpri->addr, dpri->rport, dpri->lport);
+ } else {
+ printk(KERN_INFO "mcast backend multicast address: %s:%u, "
+ "TTL:%u\n", dpri->addr, dpri->lport, dpri->ttl);
+ }
+}
+
+static int umcast_read(int fd, struct sk_buff *skb, struct uml_net_private *lp)
+{
+ return net_recvfrom(fd, skb_mac_header(skb),
+ skb->dev->mtu + ETH_HEADER_OTHER);
+}
+
+static int umcast_write(int fd, struct sk_buff *skb, struct uml_net_private *lp)
+{
+ return umcast_user_write(fd, skb->data, skb->len,
+ (struct umcast_data *) &lp->user);
+}
+
+static const struct net_kern_info umcast_kern_info = {
+ .init = umcast_init,
+ .protocol = eth_protocol,
+ .read = umcast_read,
+ .write = umcast_write,
+};
+
+static int mcast_setup(char *str, char **mac_out, void *data)
+{
+ struct umcast_init *init = data;
+ char *port_str = NULL, *ttl_str = NULL, *remain;
+ char *last;
+
+ *init = ((struct umcast_init)
+ { .addr = "239.192.168.1",
+ .lport = 1102,
+ .ttl = 1 });
+
+ remain = split_if_spec(str, mac_out, &init->addr, &port_str, &ttl_str,
+ NULL);
+ if (remain != NULL) {
+ printk(KERN_ERR "mcast_setup - Extra garbage on "
+ "specification : '%s'\n", remain);
+ return 0;
+ }
+
+ if (port_str != NULL) {
+ init->lport = simple_strtoul(port_str, &last, 10);
+ if ((*last != '\0') || (last == port_str)) {
+ printk(KERN_ERR "mcast_setup - Bad port : '%s'\n",
+ port_str);
+ return 0;
+ }
+ }
+
+ if (ttl_str != NULL) {
+ init->ttl = simple_strtoul(ttl_str, &last, 10);
+ if ((*last != '\0') || (last == ttl_str)) {
+ printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n",
+ ttl_str);
+ return 0;
+ }
+ }
+
+ init->unicast = false;
+ init->rport = init->lport;
+
+ printk(KERN_INFO "Configured mcast device: %s:%u-%u\n", init->addr,
+ init->lport, init->ttl);
+
+ return 1;
+}
+
+static int ucast_setup(char *str, char **mac_out, void *data)
+{
+ struct umcast_init *init = data;
+ char *lport_str = NULL, *rport_str = NULL, *remain;
+ char *last;
+
+ *init = ((struct umcast_init)
+ { .addr = "",
+ .lport = 1102,
+ .rport = 1102 });
+
+ remain = split_if_spec(str, mac_out, &init->addr,
+ &lport_str, &rport_str, NULL);
+ if (remain != NULL) {
+ printk(KERN_ERR "ucast_setup - Extra garbage on "
+ "specification : '%s'\n", remain);
+ return 0;
+ }
+
+ if (lport_str != NULL) {
+ init->lport = simple_strtoul(lport_str, &last, 10);
+ if ((*last != '\0') || (last == lport_str)) {
+ printk(KERN_ERR "ucast_setup - Bad listen port : "
+ "'%s'\n", lport_str);
+ return 0;
+ }
+ }
+
+ if (rport_str != NULL) {
+ init->rport = simple_strtoul(rport_str, &last, 10);
+ if ((*last != '\0') || (last == rport_str)) {
+ printk(KERN_ERR "ucast_setup - Bad remote port : "
+ "'%s'\n", rport_str);
+ return 0;
+ }
+ }
+
+ init->unicast = true;
+
+ printk(KERN_INFO "Configured ucast device: :%u -> %s:%u\n",
+ init->lport, init->addr, init->rport);
+
+ return 1;
+}
+
+static struct transport mcast_transport = {
+ .list = LIST_HEAD_INIT(mcast_transport.list),
+ .name = "mcast",
+ .setup = mcast_setup,
+ .user = &umcast_user_info,
+ .kern = &umcast_kern_info,
+ .private_size = sizeof(struct umcast_data),
+ .setup_size = sizeof(struct umcast_init),
+};
+
+static struct transport ucast_transport = {
+ .list = LIST_HEAD_INIT(ucast_transport.list),
+ .name = "ucast",
+ .setup = ucast_setup,
+ .user = &umcast_user_info,
+ .kern = &umcast_kern_info,
+ .private_size = sizeof(struct umcast_data),
+ .setup_size = sizeof(struct umcast_init),
+};
+
+static int register_umcast(void)
+{
+ register_transport(&mcast_transport);
+ register_transport(&ucast_transport);
+ return 0;
+}
+
+late_initcall(register_umcast);
diff --git a/arch/um/drivers/umcast_user.c b/arch/um/drivers/umcast_user.c
new file mode 100644
index 000000000000..59c56fd6f52a
--- /dev/null
+++ b/arch/um/drivers/umcast_user.c
@@ -0,0 +1,186 @@
+/*
+ * user-mode-linux networking multicast transport
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Copyright (C) 2001 by Harald Welte <laforge@gnumonks.org>
+ *
+ * based on the existing uml-networking code, which is
+ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
+ * James Leu (jleu@mindspring.net).
+ * Copyright (C) 2001 by various other people who didn't put their name here.
+ *
+ * Licensed under the GPL.
+ *
+ */
+
+#include <unistd.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include "kern_constants.h"
+#include "umcast.h"
+#include "net_user.h"
+#include "um_malloc.h"
+#include "user.h"
+
+static struct sockaddr_in *new_addr(char *addr, unsigned short port)
+{
+ struct sockaddr_in *sin;
+
+ sin = uml_kmalloc(sizeof(struct sockaddr_in), UM_GFP_KERNEL);
+ if (sin == NULL) {
+ printk(UM_KERN_ERR "new_addr: allocation of sockaddr_in "
+ "failed\n");
+ return NULL;
+ }
+ sin->sin_family = AF_INET;
+ if (addr)
+ sin->sin_addr.s_addr = in_aton(addr);
+ else
+ sin->sin_addr.s_addr = INADDR_ANY;
+ sin->sin_port = htons(port);
+ return sin;
+}
+
+static int umcast_user_init(void *data, void *dev)
+{
+ struct umcast_data *pri = data;
+
+ pri->remote_addr = new_addr(pri->addr, pri->rport);
+ if (pri->unicast)
+ pri->listen_addr = new_addr(NULL, pri->lport);
+ else
+ pri->listen_addr = pri->remote_addr;
+ pri->dev = dev;
+ return 0;
+}
+
+static void umcast_remove(void *data)
+{
+ struct umcast_data *pri = data;
+
+ kfree(pri->listen_addr);
+ if (pri->unicast)
+ kfree(pri->remote_addr);
+ pri->listen_addr = pri->remote_addr = NULL;
+}
+
+static int umcast_open(void *data)
+{
+ struct umcast_data *pri = data;
+ struct sockaddr_in *lsin = pri->listen_addr;
+ struct sockaddr_in *rsin = pri->remote_addr;
+ struct ip_mreq mreq;
+ int fd, yes = 1, err = -EINVAL;
+
+
+ if ((!pri->unicast && lsin->sin_addr.s_addr == 0) ||
+ (rsin->sin_addr.s_addr == 0) ||
+ (lsin->sin_port == 0) || (rsin->sin_port == 0))
+ goto out;
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+
+ if (fd < 0) {
+ err = -errno;
+ printk(UM_KERN_ERR "umcast_open : data socket failed, "
+ "errno = %d\n", errno);
+ goto out;
+ }
+
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
+ err = -errno;
+ printk(UM_KERN_ERR "umcast_open: SO_REUSEADDR failed, "
+ "errno = %d\n", errno);
+ goto out_close;
+ }
+
+ if (!pri->unicast) {
+ /* set ttl according to config */
+ if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &pri->ttl,
+ sizeof(pri->ttl)) < 0) {
+ err = -errno;
+ printk(UM_KERN_ERR "umcast_open: IP_MULTICAST_TTL "
+ "failed, error = %d\n", errno);
+ goto out_close;
+ }
+
+ /* set LOOP, so data does get fed back to local sockets */
+ if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP,
+ &yes, sizeof(yes)) < 0) {
+ err = -errno;
+ printk(UM_KERN_ERR "umcast_open: IP_MULTICAST_LOOP "
+ "failed, error = %d\n", errno);
+ goto out_close;
+ }
+ }
+
+ /* bind socket to the address */
+ if (bind(fd, (struct sockaddr *) lsin, sizeof(*lsin)) < 0) {
+ err = -errno;
+ printk(UM_KERN_ERR "umcast_open : data bind failed, "
+ "errno = %d\n", errno);
+ goto out_close;
+ }
+
+ if (!pri->unicast) {
+ /* subscribe to the multicast group */
+ mreq.imr_multiaddr.s_addr = lsin->sin_addr.s_addr;
+ mreq.imr_interface.s_addr = 0;
+ if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP,
+ &mreq, sizeof(mreq)) < 0) {
+ err = -errno;
+ printk(UM_KERN_ERR "umcast_open: IP_ADD_MEMBERSHIP "
+ "failed, error = %d\n", errno);
+ printk(UM_KERN_ERR "There appears not to be a "
+ "multicast-capable network interface on the "
+ "host.\n");
+ printk(UM_KERN_ERR "eth0 should be configured in order "
+ "to use the multicast transport.\n");
+ goto out_close;
+ }
+ }
+
+ return fd;
+
+ out_close:
+ close(fd);
+ out:
+ return err;
+}
+
+static void umcast_close(int fd, void *data)
+{
+ struct umcast_data *pri = data;
+
+ if (!pri->unicast) {
+ struct ip_mreq mreq;
+ struct sockaddr_in *lsin = pri->listen_addr;
+
+ mreq.imr_multiaddr.s_addr = lsin->sin_addr.s_addr;
+ mreq.imr_interface.s_addr = 0;
+ if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP,
+ &mreq, sizeof(mreq)) < 0) {
+ printk(UM_KERN_ERR "umcast_close: IP_DROP_MEMBERSHIP "
+ "failed, error = %d\n", errno);
+ }
+ }
+
+ close(fd);
+}
+
+int umcast_user_write(int fd, void *buf, int len, struct umcast_data *pri)
+{
+ struct sockaddr_in *data_addr = pri->remote_addr;
+
+ return net_sendto(fd, buf, len, data_addr, sizeof(*data_addr));
+}
+
+const struct net_user_info umcast_user_info = {
+ .init = umcast_user_init,
+ .open = umcast_open,
+ .close = umcast_close,
+ .remove = umcast_remove,
+ .add_address = NULL,
+ .delete_address = NULL,
+ .mtu = ETH_MAX_PACKET,
+ .max_packet = ETH_MAX_PACKET + ETH_HEADER_OTHER,
+};
diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c
index da2caa5a21ef..8ac7146c237f 100644
--- a/arch/um/drivers/xterm.c
+++ b/arch/um/drivers/xterm.c
@@ -90,7 +90,7 @@ static int xterm_open(int input, int output, int primary, void *d,
int pid, fd, new, err;
char title[256], file[] = "/tmp/xterm-pipeXXXXXX";
char *argv[] = { terminal_emulator, title_switch, title, exec_switch,
- "/usr/lib/uml/port-helper", "-uml-socket",
+ OS_LIB_PATH "/uml/port-helper", "-uml-socket",
file, NULL };
if (access(argv[4], X_OK) < 0)
diff --git a/arch/um/include/asm/common.lds.S b/arch/um/include/asm/common.lds.S
index 34bede8aad4a..4938de5512d2 100644
--- a/arch/um/include/asm/common.lds.S
+++ b/arch/um/include/asm/common.lds.S
@@ -42,7 +42,7 @@
INIT_SETUP(0)
}
- PERCPU(32, 32)
+ PERCPU_SECTION(32)
.initcall.init : {
INIT_CALLS
diff --git a/arch/um/include/asm/processor-generic.h b/arch/um/include/asm/processor-generic.h
index d1d1b0d8a0cd..98d01bc4fa92 100644
--- a/arch/um/include/asm/processor-generic.h
+++ b/arch/um/include/asm/processor-generic.h
@@ -14,6 +14,8 @@ struct task_struct;
#include "registers.h"
#include "sysdep/archsetjmp.h"
+#include <linux/prefetch.h>
+
struct mm_struct;
struct thread_struct {
diff --git a/arch/um/include/asm/smp.h b/arch/um/include/asm/smp.h
index f27a96313174..4a4b09d4f366 100644
--- a/arch/um/include/asm/smp.h
+++ b/arch/um/include/asm/smp.h
@@ -11,7 +11,6 @@
#define cpu_logical_map(n) (n)
#define cpu_number_map(n) (n)
-#define PROC_CHANGE_PENALTY 15 /* Pick a number, any number */
extern int hard_smp_processor_id(void);
#define NO_PROC_ID -1
diff --git a/arch/um/include/asm/tlb.h b/arch/um/include/asm/tlb.h
index 660caedac9eb..4febacd1a8a1 100644
--- a/arch/um/include/asm/tlb.h
+++ b/arch/um/include/asm/tlb.h
@@ -22,9 +22,6 @@ struct mmu_gather {
unsigned int fullmm; /* non-zero means full mm flush */
};
-/* Users of the generic TLB shootdown code must declare this storage space. */
-DECLARE_PER_CPU(struct mmu_gather, mmu_gathers);
-
static inline void __tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep,
unsigned long address)
{
@@ -47,27 +44,20 @@ static inline void init_tlb_gather(struct mmu_gather *tlb)
}
}
-/* tlb_gather_mmu
- * Return a pointer to an initialized struct mmu_gather.
- */
-static inline struct mmu_gather *
-tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush)
+static inline void
+tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned int full_mm_flush)
{
- struct mmu_gather *tlb = &get_cpu_var(mmu_gathers);
-
tlb->mm = mm;
tlb->fullmm = full_mm_flush;
init_tlb_gather(tlb);
-
- return tlb;
}
extern void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
unsigned long end);
static inline void
-tlb_flush_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
+tlb_flush_mmu(struct mmu_gather *tlb)
{
if (!tlb->need_flush)
return;
@@ -83,12 +73,10 @@ tlb_flush_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
static inline void
tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
{
- tlb_flush_mmu(tlb, start, end);
+ tlb_flush_mmu(tlb);
/* keep the page table cache within bounds */
check_pgt_cache();
-
- put_cpu_var(mmu_gathers);
}
/* tlb_remove_page
@@ -96,11 +84,16 @@ tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end)
* while handling the additional races in SMP caused by other CPUs
* caching valid mappings in their TLBs.
*/
-static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)
{
tlb->need_flush = 1;
free_page_and_swap_cache(page);
- return;
+ return 1; /* avoid calling tlb_flush_mmu */
+}
+
+static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
+{
+ __tlb_remove_page(tlb, page);
}
/**
diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h
index c4617baaa4f2..83c7c2ecd614 100644
--- a/arch/um/include/shared/os.h
+++ b/arch/um/include/shared/os.h
@@ -29,6 +29,12 @@
#define OS_ACC_R_OK 4 /* Test for read permission. */
#define OS_ACC_RW_OK (OS_ACC_W_OK | OS_ACC_R_OK) /* Test for RW permission */
+#ifdef CONFIG_64BIT
+#define OS_LIB_PATH "/usr/lib64/"
+#else
+#define OS_LIB_PATH "/usr/lib/"
+#endif
+
/*
* types taken from stat_file() in hostfs_user.c
* (if they are wrong here, they are wrong there...).
@@ -238,6 +244,7 @@ extern int raw(int fd);
extern void setup_machinename(char *machine_out);
extern void setup_hostinfo(char *buf, int len);
extern void os_dump_core(void) __attribute__ ((noreturn));
+extern void um_early_printk(const char *s, unsigned int n);
/* time.c */
extern void idle_sleep(unsigned long long nsecs);
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile
index 1119233597a1..c4491c15afb2 100644
--- a/arch/um/kernel/Makefile
+++ b/arch/um/kernel/Makefile
@@ -17,6 +17,7 @@ obj-y = config.o exec.o exitcode.o init_task.o irq.o ksyms.o mem.o \
obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o
obj-$(CONFIG_GPROF) += gprof_syms.o
obj-$(CONFIG_GCOV) += gmon_syms.o
+obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
USER_OBJS := config.o
diff --git a/arch/um/kernel/early_printk.c b/arch/um/kernel/early_printk.c
new file mode 100644
index 000000000000..ec649bf72f68
--- /dev/null
+++ b/arch/um/kernel/early_printk.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2011 Richard Weinberger <richrd@nod.at>
+ *
+ * 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/console.h>
+#include <linux/init.h>
+#include "os.h"
+
+static void early_console_write(struct console *con, const char *s, unsigned int n)
+{
+ um_early_printk(s, n);
+}
+
+static struct console early_console = {
+ .name = "earlycon",
+ .write = early_console_write,
+ .flags = CON_BOOT,
+ .index = -1,
+};
+
+static int __init setup_early_printk(char *buf)
+{
+ register_console(&early_console);
+
+ return 0;
+}
+
+early_param("earlyprintk", setup_early_printk);
diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c
index 106bf27e2a9a..155206a66908 100644
--- a/arch/um/kernel/smp.c
+++ b/arch/um/kernel/smp.c
@@ -7,9 +7,6 @@
#include "asm/pgalloc.h"
#include "asm/tlb.h"
-/* For some reason, mmu_gathers are referenced when CONFIG_SMP is off. */
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
#ifdef CONFIG_SMP
#include "linux/sched.h"
@@ -173,7 +170,7 @@ void IPI_handler(int cpu)
break;
case 'R':
- set_tsk_need_resched(current);
+ scheduler_ipi();
break;
case 'S':
diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c
index 637c6505dc00..8c7b8823d1f0 100644
--- a/arch/um/kernel/trap.c
+++ b/arch/um/kernel/trap.c
@@ -113,6 +113,27 @@ out_of_memory:
return 0;
}
+static void show_segv_info(struct uml_pt_regs *regs)
+{
+ struct task_struct *tsk = current;
+ struct faultinfo *fi = UPT_FAULTINFO(regs);
+
+ if (!unhandled_signal(tsk, SIGSEGV))
+ return;
+
+ if (!printk_ratelimit())
+ return;
+
+ printk("%s%s[%d]: segfault at %lx ip %p sp %p error %x",
+ task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG,
+ tsk->comm, task_pid_nr(tsk), FAULT_ADDRESS(*fi),
+ (void *)UPT_IP(regs), (void *)UPT_SP(regs),
+ fi->error_code);
+
+ print_vma_addr(KERN_CONT " in ", UPT_IP(regs));
+ printk(KERN_CONT "\n");
+}
+
static void bad_segv(struct faultinfo fi, unsigned long ip)
{
struct siginfo si;
@@ -141,6 +162,7 @@ void segv_handler(int sig, struct uml_pt_regs *regs)
struct faultinfo * fi = UPT_FAULTINFO(regs);
if (UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)) {
+ show_segv_info(regs);
bad_segv(*fi, UPT_IP(regs));
return;
}
@@ -202,6 +224,8 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,
address, ip);
}
+ show_segv_info(regs);
+
if (err == -EACCES) {
si.si_signo = SIGBUS;
si.si_errno = 0;
diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c
index eee69b9f52c9..fb2a97a75fb1 100644
--- a/arch/um/os-Linux/main.c
+++ b/arch/um/os-Linux/main.c
@@ -78,7 +78,7 @@ static void install_fatal_handler(int sig)
}
}
-#define UML_LIB_PATH ":/usr/lib/uml"
+#define UML_LIB_PATH ":" OS_LIB_PATH "/uml"
static void setup_env_path(void)
{
@@ -142,7 +142,6 @@ int __init main(int argc, char **argv, char **envp)
*/
install_fatal_handler(SIGINT);
install_fatal_handler(SIGTERM);
- install_fatal_handler(SIGHUP);
scan_elf_aux(envp);
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c
index e0477c3ee894..0c45dc8efb05 100644
--- a/arch/um/os-Linux/process.c
+++ b/arch/um/os-Linux/process.c
@@ -253,6 +253,7 @@ void init_new_thread_signals(void)
SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGALRM,
SIGVTALRM, -1);
signal(SIGWINCH, SIG_IGN);
+ signal(SIGTERM, SIG_DFL);
}
int run_kernel_thread(int (*fn)(void *), void *arg, jmp_buf **jmp_ptr)
diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c
index 42827cafa6af..5803b1887672 100644
--- a/arch/um/os-Linux/util.c
+++ b/arch/um/os-Linux/util.c
@@ -139,3 +139,8 @@ void os_dump_core(void)
uml_abort();
}
+
+void um_early_printk(const char *s, unsigned int n)
+{
+ printf("%.*s", n, s);
+}
diff --git a/arch/unicore32/Kconfig.debug b/arch/unicore32/Kconfig.debug
index 3140151ede45..ae2ec334c3c6 100644
--- a/arch/unicore32/Kconfig.debug
+++ b/arch/unicore32/Kconfig.debug
@@ -27,13 +27,6 @@ config EARLY_PRINTK
with klogd/syslogd or the X server. You should normally N here,
unless you want to debug such a crash.
-config DEBUG_STACK_USAGE
- bool "Enable stack utilization instrumentation"
- depends on DEBUG_KERNEL
- help
- Enables the display of the minimum amount of free stack which each
- task has ever had available in the sysrq-T output.
-
# These options are only for real kernel hackers who want to get their hands dirty.
config DEBUG_LL
bool "Kernel low-level debugging functions"
diff --git a/arch/unicore32/kernel/irq.c b/arch/unicore32/kernel/irq.c
index 2aa30a364bbe..d4efa7d679ff 100644
--- a/arch/unicore32/kernel/irq.c
+++ b/arch/unicore32/kernel/irq.c
@@ -23,7 +23,7 @@
#include <linux/list.h>
#include <linux/kallsyms.h>
#include <linux/proc_fs.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/gpio.h>
#include <asm/system.h>
@@ -237,7 +237,7 @@ static struct puv3_irq_state {
unsigned int iccr;
} puv3_irq_state;
-static int puv3_irq_suspend(struct sys_device *dev, pm_message_t state)
+static int puv3_irq_suspend(void)
{
struct puv3_irq_state *st = &puv3_irq_state;
@@ -265,7 +265,7 @@ static int puv3_irq_suspend(struct sys_device *dev, pm_message_t state)
return 0;
}
-static int puv3_irq_resume(struct sys_device *dev)
+static void puv3_irq_resume(void)
{
struct puv3_irq_state *st = &puv3_irq_state;
@@ -278,27 +278,20 @@ static int puv3_irq_resume(struct sys_device *dev)
writel(st->icmr, INTC_ICMR);
}
- return 0;
}
-static struct sysdev_class puv3_irq_sysclass = {
- .name = "pkunity-irq",
+static struct syscore_ops puv3_irq_syscore_ops = {
.suspend = puv3_irq_suspend,
.resume = puv3_irq_resume,
};
-static struct sys_device puv3_irq_device = {
- .id = 0,
- .cls = &puv3_irq_sysclass,
-};
-
-static int __init puv3_irq_init_devicefs(void)
+static int __init puv3_irq_init_syscore(void)
{
- sysdev_class_register(&puv3_irq_sysclass);
- return sysdev_register(&puv3_irq_device);
+ register_syscore_ops(&puv3_irq_syscore_ops);
+ return 0;
}
-device_initcall(puv3_irq_init_devicefs);
+device_initcall(puv3_irq_init_syscore);
void __init init_IRQ(void)
{
diff --git a/arch/unicore32/kernel/traps.c b/arch/unicore32/kernel/traps.c
index 254e36fa9513..b9a26465e728 100644
--- a/arch/unicore32/kernel/traps.c
+++ b/arch/unicore32/kernel/traps.c
@@ -192,7 +192,6 @@ static int __die(const char *str, int err, struct thread_info *thread,
printk(KERN_EMERG "Internal error: %s: %x [#%d]\n",
str, err, ++die_counter);
- sysfs_printk_last_file();
/* trap and error numbers are mostly meaningless on UniCore */
ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, \
diff --git a/arch/unicore32/mm/init.c b/arch/unicore32/mm/init.c
index 1fc02633f700..2d3e7112d2a3 100644
--- a/arch/unicore32/mm/init.c
+++ b/arch/unicore32/mm/init.c
@@ -62,7 +62,7 @@ void show_mem(unsigned int filter)
struct meminfo *mi = &meminfo;
printk(KERN_DEFAULT "Mem-info:\n");
- show_free_areas();
+ show_free_areas(filter);
for_each_bank(i, mi) {
struct membank *bank = &mi->bank[i];
diff --git a/arch/unicore32/mm/mmu.c b/arch/unicore32/mm/mmu.c
index db2d334941b4..3e5c3e5a0b45 100644
--- a/arch/unicore32/mm/mmu.c
+++ b/arch/unicore32/mm/mmu.c
@@ -30,8 +30,6 @@
#include "mm.h"
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
/*
* empty_zero_page is a special page that is used for
* zero-initialized data and COW.
diff --git a/arch/x86/Kbuild b/arch/x86/Kbuild
index 0e103236b754..0e9dec6cadd1 100644
--- a/arch/x86/Kbuild
+++ b/arch/x86/Kbuild
@@ -15,3 +15,4 @@ obj-y += vdso/
obj-$(CONFIG_IA32_EMULATION) += ia32/
obj-y += platform/
+obj-y += net/
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index cc6c53a95bfd..da349723d411 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -8,6 +8,7 @@ config 64BIT
config X86_32
def_bool !64BIT
+ select CLKSRC_I8253
config X86_64
def_bool 64BIT
@@ -16,8 +17,6 @@ config X86_64
config X86
def_bool y
select HAVE_AOUT if X86_32
- select HAVE_READQ
- select HAVE_WRITEQ
select HAVE_UNSTABLE_SCHED_CLOCK
select HAVE_IDE
select HAVE_OPROFILE
@@ -65,13 +64,12 @@ config X86
select HAVE_GENERIC_HARDIRQS
select HAVE_SPARSE_IRQ
select GENERIC_FIND_FIRST_BIT
- select GENERIC_FIND_NEXT_BIT
select GENERIC_IRQ_PROBE
select GENERIC_PENDING_IRQ if SMP
select GENERIC_IRQ_SHOW
select IRQ_FORCED_THREADING
select USE_GENERIC_SMP_HELPERS if SMP
- select ARCH_NO_SYSDEV_OPS
+ select HAVE_BPF_JIT if (X86_64 && NET)
config INSTRUCTION_DECODER
def_bool (KPROBES || PERF_EVENTS)
@@ -112,7 +110,14 @@ config MMU
def_bool y
config ZONE_DMA
- def_bool y
+ bool "DMA memory allocation support" if EXPERT
+ default y
+ help
+ DMA memory allocation support allows devices with less than 32-bit
+ addressing to allocate within the first 16MB of address space.
+ Disable if no such devices will be used.
+
+ If unsure, say Y.
config SBUS
bool
@@ -365,17 +370,6 @@ config X86_UV
# Following is an alphabetically sorted list of 32 bit extended platforms
# Please maintain the alphabetic order if and when there are additions
-config X86_ELAN
- bool "AMD Elan"
- depends on X86_32
- depends on X86_EXTENDED_PLATFORM
- ---help---
- Select this for an AMD Elan processor.
-
- Do not use this option for K6/Athlon/Opteron processors!
-
- If unsure, choose "PC-compatible" instead.
-
config X86_INTEL_CE
bool "CE4100 TV platform"
depends on PCI
@@ -690,6 +684,7 @@ config AMD_IOMMU
bool "AMD IOMMU support"
select SWIOTLB
select PCI_MSI
+ select PCI_IOV
depends on X86_64 && PCI && ACPI
---help---
With this option you can enable support for AMD IOMMU hardware in
@@ -919,6 +914,7 @@ config TOSHIBA
config I8K
tristate "Dell laptop support"
+ select HWMON
---help---
This adds a driver to safely access the System Management Mode
of the CPU on the Dell Inspiron 8000. The System Management Mode
@@ -1174,7 +1170,7 @@ comment "NUMA (Summit) requires SMP, 64GB highmem support, ACPI"
config AMD_NUMA
def_bool y
prompt "Old style AMD Opteron NUMA detection"
- depends on X86_64 && NUMA && PCI
+ depends on NUMA && PCI
---help---
Enable AMD NUMA node topology detection. You should say Y here if
you have a multi processor AMD system. This uses an old method to
@@ -1201,7 +1197,7 @@ config NODES_SPAN_OTHER_NODES
config NUMA_EMU
bool "NUMA emulation"
- depends on X86_64 && NUMA
+ depends on NUMA
---help---
Enable NUMA emulation. A flat machine will be split
into virtual nodes when booted with "numa=fake=N", where N is the
@@ -1223,6 +1219,10 @@ config HAVE_ARCH_BOOTMEM
def_bool y
depends on X86_32 && NUMA
+config HAVE_ARCH_ALLOC_REMAP
+ def_bool y
+ depends on X86_32 && NUMA
+
config ARCH_HAVE_MEMORY_PRESENT
def_bool y
depends on X86_32 && DISCONTIGMEM
@@ -1231,13 +1231,9 @@ config NEED_NODE_MEMMAP_SIZE
def_bool y
depends on X86_32 && (DISCONTIGMEM || SPARSEMEM)
-config HAVE_ARCH_ALLOC_REMAP
- def_bool y
- depends on X86_32 && NUMA
-
config ARCH_FLATMEM_ENABLE
def_bool y
- depends on X86_32 && ARCH_SELECT_MEMORY_MODEL && !NUMA
+ depends on X86_32 && !NUMA
config ARCH_DISCONTIGMEM_ENABLE
def_bool y
@@ -1247,20 +1243,16 @@ config ARCH_DISCONTIGMEM_DEFAULT
def_bool y
depends on NUMA && X86_32
-config ARCH_PROC_KCORE_TEXT
- def_bool y
- depends on X86_64 && PROC_KCORE
-
-config ARCH_SPARSEMEM_DEFAULT
- def_bool y
- depends on X86_64
-
config ARCH_SPARSEMEM_ENABLE
def_bool y
depends on X86_64 || NUMA || (EXPERIMENTAL && X86_32) || X86_32_NON_STANDARD
select SPARSEMEM_STATIC if X86_32
select SPARSEMEM_VMEMMAP_ENABLE if X86_64
+config ARCH_SPARSEMEM_DEFAULT
+ def_bool y
+ depends on X86_64
+
config ARCH_SELECT_MEMORY_MODEL
def_bool y
depends on ARCH_SPARSEMEM_ENABLE
@@ -1269,6 +1261,10 @@ config ARCH_MEMORY_PROBE
def_bool X86_64
depends on MEMORY_HOTPLUG
+config ARCH_PROC_KCORE_TEXT
+ def_bool y
+ depends on X86_64 && PROC_KCORE
+
config ILLEGAL_POINTER_VALUE
hex
default 0 if X86_32
@@ -1703,10 +1699,6 @@ config ARCH_ENABLE_MEMORY_HOTREMOVE
def_bool y
depends on MEMORY_HOTPLUG
-config HAVE_ARCH_EARLY_PFN_TO_NID
- def_bool X86_64
- depends on NUMA
-
config USE_PERCPU_NUMA_NODE_ID
def_bool y
depends on NUMA
@@ -1848,7 +1840,7 @@ config APM_ALLOW_INTS
endif # APM
-source "arch/x86/kernel/cpu/cpufreq/Kconfig"
+source "drivers/cpufreq/Kconfig"
source "drivers/cpuidle/Kconfig"
@@ -2076,7 +2068,7 @@ config OLPC
depends on !X86_PAE
select GPIOLIB
select OF
- select OF_PROMTREE if PROC_DEVICETREE
+ select OF_PROMTREE
---help---
Add support for detecting the unique features of the OLPC
XO hardware.
diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu
index d161e939df62..6a7cfdf8ff69 100644
--- a/arch/x86/Kconfig.cpu
+++ b/arch/x86/Kconfig.cpu
@@ -1,6 +1,4 @@
# Put here option for CPU selection and depending optimization
-if !X86_ELAN
-
choice
prompt "Processor family"
default M686 if X86_32
@@ -203,6 +201,14 @@ config MWINCHIP3D
stores for this CPU, which can increase performance of some
operations.
+config MELAN
+ bool "AMD Elan"
+ depends on X86_32
+ ---help---
+ Select this for an AMD Elan processor.
+
+ Do not use this option for K6/Athlon/Opteron processors!
+
config MGEODEGX1
bool "GeodeGX1"
depends on X86_32
@@ -292,8 +298,6 @@ config X86_GENERIC
This is really intended for distributors who need more
generic optimizations.
-endif
-
#
# Define implied options from the CPU selection here
config X86_INTERNODE_CACHE_SHIFT
@@ -312,7 +316,7 @@ config X86_L1_CACHE_SHIFT
int
default "7" if MPENTIUM4 || MPSC
default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MATOM || MVIAC7 || X86_GENERIC || GENERIC_CPU
- default "4" if X86_ELAN || M486 || M386 || MGEODEGX1
+ default "4" if MELAN || M486 || M386 || MGEODEGX1
default "5" if MWINCHIP3D || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX
config X86_XADD
@@ -358,7 +362,7 @@ config X86_POPAD_OK
config X86_ALIGNMENT_16
def_bool y
- depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1
+ depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1
config X86_INTEL_USERCOPY
def_bool y
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 615e18810f48..c0f8a5c88910 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -66,26 +66,6 @@ config DEBUG_STACKOVERFLOW
This option will cause messages to be printed if free stack space
drops below a certain limit.
-config DEBUG_STACK_USAGE
- bool "Stack utilization instrumentation"
- depends on DEBUG_KERNEL
- ---help---
- Enables the display of the minimum amount of free stack which each
- task has ever had available in the sysrq-T and sysrq-P debug output.
-
- This option will slow down process creation somewhat.
-
-config DEBUG_PER_CPU_MAPS
- bool "Debug access to per_cpu maps"
- depends on DEBUG_KERNEL
- depends on SMP
- ---help---
- Say Y to verify that the per_cpu map being accessed has
- been setup. Adds a fair amount of code to kernel memory
- and decreases performance.
-
- Say N if unsure.
-
config X86_PTDUMP
bool "Export kernel pagetable layout to userspace via debugfs"
depends on DEBUG_KERNEL
diff --git a/arch/x86/Makefile_32.cpu b/arch/x86/Makefile_32.cpu
index f2ee1abb1df9..86cee7b749e1 100644
--- a/arch/x86/Makefile_32.cpu
+++ b/arch/x86/Makefile_32.cpu
@@ -37,7 +37,7 @@ cflags-$(CONFIG_MATOM) += $(call cc-option,-march=atom,$(call cc-option,-march=
$(call cc-option,-mtune=atom,$(call cc-option,-mtune=generic))
# AMD Elan support
-cflags-$(CONFIG_X86_ELAN) += -march=i486
+cflags-$(CONFIG_MELAN) += -march=i486
# Geode GX1 support
cflags-$(CONFIG_MGEODEGX1) += -march=pentium-mmx
diff --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig
index 6f9872658dd2..2bf18059fbea 100644
--- a/arch/x86/configs/i386_defconfig
+++ b/arch/x86/configs/i386_defconfig
@@ -10,7 +10,6 @@ CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_AUDIT=y
CONFIG_LOG_BUF_SHIFT=18
CONFIG_CGROUPS=y
-CONFIG_CGROUP_NS=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CPUSETS=y
CONFIG_CGROUP_CPUACCT=y
diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig
index ee01a9d5d4f0..22a0dc8e51dd 100644
--- a/arch/x86/configs/x86_64_defconfig
+++ b/arch/x86/configs/x86_64_defconfig
@@ -11,7 +11,6 @@ CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_AUDIT=y
CONFIG_LOG_BUF_SHIFT=18
CONFIG_CGROUPS=y
-CONFIG_CGROUP_NS=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CPUSETS=y
CONFIG_CGROUP_CPUACCT=y
diff --git a/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile
index 1a58ad89fdf7..c04f1b7a9139 100644
--- a/arch/x86/crypto/Makefile
+++ b/arch/x86/crypto/Makefile
@@ -2,8 +2,6 @@
# Arch-specific CryptoAPI modules.
#
-obj-$(CONFIG_CRYPTO_FPU) += fpu.o
-
obj-$(CONFIG_CRYPTO_AES_586) += aes-i586.o
obj-$(CONFIG_CRYPTO_TWOFISH_586) += twofish-i586.o
obj-$(CONFIG_CRYPTO_SALSA20_586) += salsa20-i586.o
@@ -24,6 +22,6 @@ aes-x86_64-y := aes-x86_64-asm_64.o aes_glue.o
twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_glue.o
salsa20-x86_64-y := salsa20-x86_64-asm_64.o salsa20_glue.o
-aesni-intel-y := aesni-intel_asm.o aesni-intel_glue.o
+aesni-intel-y := aesni-intel_asm.o aesni-intel_glue.o fpu.o
ghash-clmulni-intel-y := ghash-clmulni-intel_asm.o ghash-clmulni-intel_glue.o
diff --git a/arch/x86/crypto/aesni-intel_glue.c b/arch/x86/crypto/aesni-intel_glue.c
index 2577613fb32b..feee8ff1d05e 100644
--- a/arch/x86/crypto/aesni-intel_glue.c
+++ b/arch/x86/crypto/aesni-intel_glue.c
@@ -94,6 +94,10 @@ asmlinkage void aesni_cbc_enc(struct crypto_aes_ctx *ctx, u8 *out,
const u8 *in, unsigned int len, u8 *iv);
asmlinkage void aesni_cbc_dec(struct crypto_aes_ctx *ctx, u8 *out,
const u8 *in, unsigned int len, u8 *iv);
+
+int crypto_fpu_init(void);
+void crypto_fpu_exit(void);
+
#ifdef CONFIG_X86_64
asmlinkage void aesni_ctr_enc(struct crypto_aes_ctx *ctx, u8 *out,
const u8 *in, unsigned int len, u8 *iv);
@@ -1257,6 +1261,8 @@ static int __init aesni_init(void)
return -ENODEV;
}
+ if ((err = crypto_fpu_init()))
+ goto fpu_err;
if ((err = crypto_register_alg(&aesni_alg)))
goto aes_err;
if ((err = crypto_register_alg(&__aesni_alg)))
@@ -1334,6 +1340,7 @@ blk_ecb_err:
__aes_err:
crypto_unregister_alg(&aesni_alg);
aes_err:
+fpu_err:
return err;
}
@@ -1363,6 +1370,8 @@ static void __exit aesni_exit(void)
crypto_unregister_alg(&blk_ecb_alg);
crypto_unregister_alg(&__aesni_alg);
crypto_unregister_alg(&aesni_alg);
+
+ crypto_fpu_exit();
}
module_init(aesni_init);
diff --git a/arch/x86/crypto/fpu.c b/arch/x86/crypto/fpu.c
index 1a8f8649c035..98d7a188f46b 100644
--- a/arch/x86/crypto/fpu.c
+++ b/arch/x86/crypto/fpu.c
@@ -150,18 +150,12 @@ static struct crypto_template crypto_fpu_tmpl = {
.module = THIS_MODULE,
};
-static int __init crypto_fpu_module_init(void)
+int __init crypto_fpu_init(void)
{
return crypto_register_template(&crypto_fpu_tmpl);
}
-static void __exit crypto_fpu_module_exit(void)
+void __exit crypto_fpu_exit(void)
{
crypto_unregister_template(&crypto_fpu_tmpl);
}
-
-module_init(crypto_fpu_module_init);
-module_exit(crypto_fpu_module_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("FPU block cipher wrapper");
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index 849a9d23c71d..95f5826be458 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -848,4 +848,5 @@ ia32_sys_call_table:
.quad compat_sys_open_by_handle_at
.quad compat_sys_clock_adjtime
.quad sys_syncfs
+ .quad compat_sys_sendmmsg /* 345 */
ia32_syscall_end:
diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h
index 12e0e7dd869c..416d865eae39 100644
--- a/arch/x86/include/asm/acpi.h
+++ b/arch/x86/include/asm/acpi.h
@@ -183,8 +183,6 @@ static inline void disable_acpi(void) { }
#define ARCH_HAS_POWER_INIT 1
-struct bootnode;
-
#ifdef CONFIG_ACPI_NUMA
extern int acpi_numa;
extern int x86_acpi_numa_init(void);
diff --git a/arch/x86/include/asm/alternative-asm.h b/arch/x86/include/asm/alternative-asm.h
index a63a68be1cce..94d420b360d1 100644
--- a/arch/x86/include/asm/alternative-asm.h
+++ b/arch/x86/include/asm/alternative-asm.h
@@ -15,4 +15,13 @@
.endm
#endif
+.macro altinstruction_entry orig alt feature orig_len alt_len
+ .align 8
+ .quad \orig
+ .quad \alt
+ .word \feature
+ .byte \orig_len
+ .byte \alt_len
+.endm
+
#endif /* __ASSEMBLY__ */
diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h
index 13009d1af99a..bf535f947e8c 100644
--- a/arch/x86/include/asm/alternative.h
+++ b/arch/x86/include/asm/alternative.h
@@ -4,7 +4,6 @@
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/stringify.h>
-#include <linux/jump_label.h>
#include <asm/asm.h>
/*
@@ -191,12 +190,4 @@ extern void *text_poke(void *addr, const void *opcode, size_t len);
extern void *text_poke_smp(void *addr, const void *opcode, size_t len);
extern void text_poke_smp_batch(struct text_poke_param *params, int n);
-#if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL)
-#define IDEAL_NOP_SIZE_5 5
-extern unsigned char ideal_nop5[IDEAL_NOP_SIZE_5];
-extern void arch_init_ideal_nop5(void);
-#else
-static inline void arch_init_ideal_nop5(void) {}
-#endif
-
#endif /* _ASM_X86_ALTERNATIVE_H */
diff --git a/arch/x86/include/asm/amd_iommu_proto.h b/arch/x86/include/asm/amd_iommu_proto.h
index 916bc8111a01..55d95eb789b3 100644
--- a/arch/x86/include/asm/amd_iommu_proto.h
+++ b/arch/x86/include/asm/amd_iommu_proto.h
@@ -19,13 +19,12 @@
#ifndef _ASM_X86_AMD_IOMMU_PROTO_H
#define _ASM_X86_AMD_IOMMU_PROTO_H
-struct amd_iommu;
+#include <asm/amd_iommu_types.h>
extern int amd_iommu_init_dma_ops(void);
extern int amd_iommu_init_passthrough(void);
+extern irqreturn_t amd_iommu_int_thread(int irq, void *data);
extern irqreturn_t amd_iommu_int_handler(int irq, void *data);
-extern void amd_iommu_flush_all_domains(void);
-extern void amd_iommu_flush_all_devices(void);
extern void amd_iommu_apply_erratum_63(u16 devid);
extern void amd_iommu_reset_cmd_buffer(struct amd_iommu *iommu);
extern int amd_iommu_init_devices(void);
@@ -44,4 +43,12 @@ static inline bool is_rd890_iommu(struct pci_dev *pdev)
(pdev->device == PCI_DEVICE_ID_RD890_IOMMU);
}
+static inline bool iommu_feature(struct amd_iommu *iommu, u64 f)
+{
+ if (!(iommu->cap & (1 << IOMMU_CAP_EFR)))
+ return false;
+
+ return !!(iommu->features & f);
+}
+
#endif /* _ASM_X86_AMD_IOMMU_PROTO_H */
diff --git a/arch/x86/include/asm/amd_iommu_types.h b/arch/x86/include/asm/amd_iommu_types.h
index e3509fc303bf..4c9982995414 100644
--- a/arch/x86/include/asm/amd_iommu_types.h
+++ b/arch/x86/include/asm/amd_iommu_types.h
@@ -68,12 +68,25 @@
#define MMIO_CONTROL_OFFSET 0x0018
#define MMIO_EXCL_BASE_OFFSET 0x0020
#define MMIO_EXCL_LIMIT_OFFSET 0x0028
+#define MMIO_EXT_FEATURES 0x0030
#define MMIO_CMD_HEAD_OFFSET 0x2000
#define MMIO_CMD_TAIL_OFFSET 0x2008
#define MMIO_EVT_HEAD_OFFSET 0x2010
#define MMIO_EVT_TAIL_OFFSET 0x2018
#define MMIO_STATUS_OFFSET 0x2020
+
+/* Extended Feature Bits */
+#define FEATURE_PREFETCH (1ULL<<0)
+#define FEATURE_PPR (1ULL<<1)
+#define FEATURE_X2APIC (1ULL<<2)
+#define FEATURE_NX (1ULL<<3)
+#define FEATURE_GT (1ULL<<4)
+#define FEATURE_IA (1ULL<<6)
+#define FEATURE_GA (1ULL<<7)
+#define FEATURE_HE (1ULL<<8)
+#define FEATURE_PC (1ULL<<9)
+
/* MMIO status bits */
#define MMIO_STATUS_COM_WAIT_INT_MASK 0x04
@@ -113,7 +126,9 @@
/* command specific defines */
#define CMD_COMPL_WAIT 0x01
#define CMD_INV_DEV_ENTRY 0x02
-#define CMD_INV_IOMMU_PAGES 0x03
+#define CMD_INV_IOMMU_PAGES 0x03
+#define CMD_INV_IOTLB_PAGES 0x04
+#define CMD_INV_ALL 0x08
#define CMD_COMPL_WAIT_STORE_MASK 0x01
#define CMD_COMPL_WAIT_INT_MASK 0x02
@@ -215,6 +230,8 @@
#define IOMMU_PTE_IR (1ULL << 61)
#define IOMMU_PTE_IW (1ULL << 62)
+#define DTE_FLAG_IOTLB 0x01
+
#define IOMMU_PAGE_MASK (((1ULL << 52) - 1) & ~0xfffULL)
#define IOMMU_PTE_PRESENT(pte) ((pte) & IOMMU_PTE_P)
#define IOMMU_PTE_PAGE(pte) (phys_to_virt((pte) & IOMMU_PAGE_MASK))
@@ -227,6 +244,7 @@
/* IOMMU capabilities */
#define IOMMU_CAP_IOTLB 24
#define IOMMU_CAP_NPCACHE 26
+#define IOMMU_CAP_EFR 27
#define MAX_DOMAIN_ID 65536
@@ -249,6 +267,8 @@ extern bool amd_iommu_dump;
/* global flag if IOMMUs cache non-present entries */
extern bool amd_iommu_np_cache;
+/* Only true if all IOMMUs support device IOTLBs */
+extern bool amd_iommu_iotlb_sup;
/*
* Make iterating over all IOMMUs easier
@@ -371,6 +391,9 @@ struct amd_iommu {
/* flags read from acpi table */
u8 acpi_flags;
+ /* Extended features */
+ u64 features;
+
/*
* Capability pointer. There could be more than one IOMMU per PCI
* device function if there are more than one AMD IOMMU capability
@@ -409,9 +432,6 @@ struct amd_iommu {
/* if one, we need to send a completion wait command */
bool need_sync;
- /* becomes true if a command buffer reset is running */
- bool reset_in_progress;
-
/* default dma_ops domain for that IOMMU */
struct dma_ops_domain *default_dom;
diff --git a/arch/x86/include/asm/amd_nb.h b/arch/x86/include/asm/amd_nb.h
index 331682231bb4..67f87f257611 100644
--- a/arch/x86/include/asm/amd_nb.h
+++ b/arch/x86/include/asm/amd_nb.h
@@ -11,7 +11,6 @@ struct amd_nb_bus_dev_range {
extern const struct pci_device_id amd_nb_misc_ids[];
extern const struct amd_nb_bus_dev_range amd_nb_bus_dev_ranges[];
-struct bootnode;
extern bool early_is_amd_nb(u32 value);
extern int amd_cache_northbridges(void);
diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index 2b7d573be549..4a0b7c7e2cce 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -363,7 +363,12 @@ struct apic {
*/
int (*x86_32_early_logical_apicid)(int cpu);
- /* determine CPU -> NUMA node mapping */
+ /*
+ * Optional method called from setup_local_APIC() after logical
+ * apicid is guaranteed to be known to initialize apicid -> node
+ * mapping if NUMA initialization hasn't done so already. Don't
+ * add new users.
+ */
int (*x86_32_numa_cpu_node)(int cpu);
#endif
};
@@ -376,6 +381,26 @@ struct apic {
extern struct apic *apic;
/*
+ * APIC drivers are probed based on how they are listed in the .apicdrivers
+ * section. So the order is important and enforced by the ordering
+ * of different apic driver files in the Makefile.
+ *
+ * For the files having two apic drivers, we use apic_drivers()
+ * to enforce the order with in them.
+ */
+#define apic_driver(sym) \
+ static struct apic *__apicdrivers_##sym __used \
+ __aligned(sizeof(struct apic *)) \
+ __section(.apicdrivers) = { &sym }
+
+#define apic_drivers(sym1, sym2) \
+ static struct apic *__apicdrivers_##sym1##sym2[2] __used \
+ __aligned(sizeof(struct apic *)) \
+ __section(.apicdrivers) = { &sym1, &sym2 }
+
+extern struct apic *__apicdrivers[], *__apicdrivers_end[];
+
+/*
* APIC functionality to boot other CPUs - only used on SMP:
*/
#ifdef CONFIG_SMP
@@ -453,15 +478,10 @@ static inline unsigned default_get_apic_id(unsigned long x)
#define DEFAULT_TRAMPOLINE_PHYS_HIGH 0x469
#ifdef CONFIG_X86_64
-extern struct apic apic_flat;
-extern struct apic apic_physflat;
-extern struct apic apic_x2apic_cluster;
-extern struct apic apic_x2apic_phys;
extern int default_acpi_madt_oem_check(char *, char *);
extern void apic_send_IPI_self(int vector);
-extern struct apic apic_x2apic_uv_x;
DECLARE_PER_CPU(int, x2apic_extra_bits);
extern int default_cpu_present_to_apicid(int mps_cpu);
@@ -475,7 +495,7 @@ static inline void default_wait_for_init_deassert(atomic_t *deassert)
return;
}
-extern void generic_bigsmp_probe(void);
+extern struct apic *generic_bigsmp_probe(void);
#ifdef CONFIG_X86_LOCAL_APIC
@@ -511,8 +531,6 @@ extern struct apic apic_noop;
#ifdef CONFIG_X86_32
-extern struct apic apic_default;
-
static inline int noop_x86_32_early_logical_apicid(int cpu)
{
return BAD_APICID;
@@ -537,8 +555,6 @@ static inline int default_phys_pkg_id(int cpuid_apic, int index_msb)
return cpuid_apic >> index_msb;
}
-extern int default_x86_32_numa_cpu_node(int cpu);
-
#endif
static inline unsigned int
diff --git a/arch/x86/include/asm/bios_ebda.h b/arch/x86/include/asm/bios_ebda.h
index 3c7521063d3f..aa6a3170ab5a 100644
--- a/arch/x86/include/asm/bios_ebda.h
+++ b/arch/x86/include/asm/bios_ebda.h
@@ -4,16 +4,40 @@
#include <asm/io.h>
/*
- * there is a real-mode segmented pointer pointing to the
- * 4K EBDA area at 0x40E.
+ * Returns physical address of EBDA. Returns 0 if there is no EBDA.
*/
static inline unsigned int get_bios_ebda(void)
{
+ /*
+ * There is a real-mode segmented pointer pointing to the
+ * 4K EBDA area at 0x40E.
+ */
unsigned int address = *(unsigned short *)phys_to_virt(0x40E);
address <<= 4;
return address; /* 0 means none */
}
+/*
+ * Return the sanitized length of the EBDA in bytes, if it exists.
+ */
+static inline unsigned int get_bios_ebda_length(void)
+{
+ unsigned int address;
+ unsigned int length;
+
+ address = get_bios_ebda();
+ if (!address)
+ return 0;
+
+ /* EBDA length is byte 0 of the EBDA (stored in KiB) */
+ length = *(unsigned char *)phys_to_virt(address);
+ length <<= 10;
+
+ /* Trim the length if it extends beyond 640KiB */
+ length = min_t(unsigned int, (640 * 1024) - address, length);
+ return length;
+}
+
void reserve_ebda_region(void);
#ifdef CONFIG_X86_CHECK_BIOS_CORRUPTION
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index 91f3e087cf21..5dc6acc98dbd 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -195,6 +195,8 @@
/* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx), word 9 */
#define X86_FEATURE_FSGSBASE (9*32+ 0) /* {RD/WR}{FS/GS}BASE instructions*/
+#define X86_FEATURE_SMEP (9*32+ 7) /* Supervisor Mode Execution Protection */
+#define X86_FEATURE_ERMS (9*32+ 9) /* Enhanced REP MOVSB/STOSB */
#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
@@ -207,8 +209,7 @@ extern const char * const x86_power_flags[32];
#define test_cpu_cap(c, bit) \
test_bit(bit, (unsigned long *)((c)->x86_capability))
-#define cpu_has(c, bit) \
- (__builtin_constant_p(bit) && \
+#define REQUIRED_MASK_BIT_SET(bit) \
( (((bit)>>5)==0 && (1UL<<((bit)&31) & REQUIRED_MASK0)) || \
(((bit)>>5)==1 && (1UL<<((bit)&31) & REQUIRED_MASK1)) || \
(((bit)>>5)==2 && (1UL<<((bit)&31) & REQUIRED_MASK2)) || \
@@ -218,10 +219,16 @@ extern const char * const x86_power_flags[32];
(((bit)>>5)==6 && (1UL<<((bit)&31) & REQUIRED_MASK6)) || \
(((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 : \
+ (((bit)>>5)==9 && (1UL<<((bit)&31) & REQUIRED_MASK9)) )
+
+#define cpu_has(c, bit) \
+ (__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : \
test_cpu_cap(c, bit))
+#define this_cpu_has(bit) \
+ (__builtin_constant_p(bit) && REQUIRED_MASK_BIT_SET(bit) ? 1 : \
+ x86_this_cpu_test_bit(bit, (unsigned long *)&cpu_info.x86_capability))
+
#define boot_cpu_has(bit) cpu_has(&boot_cpu_data, bit)
#define set_cpu_cap(c, bit) set_bit(bit, (unsigned long *)((c)->x86_capability))
diff --git a/arch/x86/include/asm/dma.h b/arch/x86/include/asm/dma.h
index 057099e5faba..0bdb0c54d9a1 100644
--- a/arch/x86/include/asm/dma.h
+++ b/arch/x86/include/asm/dma.h
@@ -69,22 +69,18 @@
#define MAX_DMA_CHANNELS 8
-#ifdef CONFIG_X86_32
-
-/* The maximum address that we can perform a DMA transfer to on this platform */
-#define MAX_DMA_ADDRESS (PAGE_OFFSET + 0x1000000)
-
-#else
-
/* 16MB ISA DMA zone */
#define MAX_DMA_PFN ((16 * 1024 * 1024) >> PAGE_SHIFT)
/* 4GB broken PCI/AGP hardware bus master zone */
#define MAX_DMA32_PFN ((4UL * 1024 * 1024 * 1024) >> PAGE_SHIFT)
+#ifdef CONFIG_X86_32
+/* The maximum address that we can perform a DMA transfer to on this platform */
+#define MAX_DMA_ADDRESS (PAGE_OFFSET + 0x1000000)
+#else
/* Compat define for old dma zone */
#define MAX_DMA_ADDRESS ((unsigned long)__va(MAX_DMA_PFN << PAGE_SHIFT))
-
#endif
/* 8237 DMA controllers */
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 8e4a16508d4e..7093e4a6a0bc 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -90,6 +90,7 @@ extern void __iomem *efi_ioremap(unsigned long addr, unsigned long size,
#endif /* CONFIG_X86_32 */
extern int add_efi_memmap;
+extern void efi_set_executable(efi_memory_desc_t *md, bool executable);
extern void efi_memblock_x86_reserve_range(void);
extern void efi_call_phys_prelog(void);
extern void efi_call_phys_epilog(void);
diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h
index db24c2278be0..268c783ab1c0 100644
--- a/arch/x86/include/asm/ftrace.h
+++ b/arch/x86/include/asm/ftrace.h
@@ -38,11 +38,10 @@ extern void mcount(void);
static inline unsigned long ftrace_call_adjust(unsigned long addr)
{
/*
- * call mcount is "e8 <4 byte offset>"
- * The addr points to the 4 byte offset and the caller of this
- * function wants the pointer to e8. Simply subtract one.
+ * addr is the address of the mcount call instruction.
+ * recordmcount does the necessary offset calculation.
*/
- return addr - 1;
+ return addr;
}
#ifdef CONFIG_DYNAMIC_FTRACE
diff --git a/arch/x86/include/asm/i8253.h b/arch/x86/include/asm/i8253.h
index fc1f579fb965..65aaa91d5850 100644
--- a/arch/x86/include/asm/i8253.h
+++ b/arch/x86/include/asm/i8253.h
@@ -6,6 +6,8 @@
#define PIT_CH0 0x40
#define PIT_CH2 0x42
+#define PIT_LATCH LATCH
+
extern raw_spinlock_t i8253_lock;
extern struct clock_event_device *global_clock_event;
diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h
index 072273082528..d02804d650c4 100644
--- a/arch/x86/include/asm/io.h
+++ b/arch/x86/include/asm/io.h
@@ -38,7 +38,6 @@
#include <linux/string.h>
#include <linux/compiler.h>
-#include <asm-generic/int-ll64.h>
#include <asm/page.h>
#include <xen/xen.h>
@@ -87,27 +86,6 @@ build_mmio_write(__writel, "l", unsigned int, "r", )
build_mmio_read(readq, "q", unsigned long, "=r", :"memory")
build_mmio_write(writeq, "q", unsigned long, "r", :"memory")
-#else
-
-static inline __u64 readq(const volatile void __iomem *addr)
-{
- const volatile u32 __iomem *p = addr;
- u32 low, high;
-
- low = readl(p);
- high = readl(p + 1);
-
- return low + ((u64)high << 32);
-}
-
-static inline void writeq(__u64 val, volatile void __iomem *addr)
-{
- writel(val, addr);
- writel(val >> 32, addr+4);
-}
-
-#endif
-
#define readq_relaxed(a) readq(a)
#define __raw_readq(a) readq(a)
@@ -117,6 +95,8 @@ static inline void writeq(__u64 val, volatile void __iomem *addr)
#define readq readq
#define writeq writeq
+#endif
+
/**
* virt_to_phys - map virtual addresses to physical
* @address: address to remap
diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h
index a97a240f67f3..690d1cc9a877 100644
--- a/arch/x86/include/asm/io_apic.h
+++ b/arch/x86/include/asm/io_apic.h
@@ -105,12 +105,12 @@ struct IR_IO_APIC_route_entry {
* # of IO-APICs and # of IRQ routing registers
*/
extern int nr_ioapics;
-extern int nr_ioapic_registers[MAX_IO_APICS];
-#define MP_MAX_IOAPIC_PIN 127
+extern int mpc_ioapic_id(int ioapic);
+extern unsigned int mpc_ioapic_addr(int ioapic);
+extern struct mp_ioapic_gsi *mp_ioapic_gsi_routing(int ioapic);
-/* I/O APIC entries */
-extern struct mpc_ioapic mp_ioapics[MAX_IO_APICS];
+#define MP_MAX_IOAPIC_PIN 127
/* # of MP IRQ source entries */
extern int mp_irq_entries;
@@ -152,11 +152,9 @@ extern void ioapic_insert_resources(void);
int io_apic_setup_irq_pin_once(unsigned int irq, int node, struct io_apic_irq_attr *attr);
-extern struct IO_APIC_route_entry **alloc_ioapic_entries(void);
-extern void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries);
-extern int save_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries);
-extern void mask_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries);
-extern int restore_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries);
+extern int save_ioapic_entries(void);
+extern void mask_ioapic_entries(void);
+extern int restore_ioapic_entries(void);
extern int get_nr_irqs_gsi(void);
@@ -192,19 +190,13 @@ struct io_apic_irq_attr;
static inline int io_apic_set_pci_routing(struct device *dev, int irq,
struct io_apic_irq_attr *irq_attr) { return 0; }
-static inline struct IO_APIC_route_entry **alloc_ioapic_entries(void)
-{
- return NULL;
-}
-
-static inline void free_ioapic_entries(struct IO_APIC_route_entry **ent) { }
-static inline int save_IO_APIC_setup(struct IO_APIC_route_entry **ent)
+static inline int save_ioapic_entries(void)
{
return -ENOMEM;
}
-static inline void mask_IO_APIC_setup(struct IO_APIC_route_entry **ent) { }
-static inline int restore_IO_APIC_setup(struct IO_APIC_route_entry **ent)
+static inline void mask_ioapic_entries(void) { }
+static inline int restore_ioapic_entries(void)
{
return -ENOMEM;
}
diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h
index 574dbc22893a..a32b18ce6ead 100644
--- a/arch/x86/include/asm/jump_label.h
+++ b/arch/x86/include/asm/jump_label.h
@@ -5,20 +5,25 @@
#include <linux/types.h>
#include <asm/nops.h>
+#include <asm/asm.h>
#define JUMP_LABEL_NOP_SIZE 5
-# define JUMP_LABEL_INITIAL_NOP ".byte 0xe9 \n\t .long 0\n\t"
-
-# define JUMP_LABEL(key, label) \
- do { \
- asm goto("1:" \
- JUMP_LABEL_INITIAL_NOP \
- ".pushsection __jump_table, \"aw\" \n\t"\
- _ASM_PTR "1b, %l[" #label "], %c0 \n\t" \
- ".popsection \n\t" \
- : : "i" (key) : : label); \
- } while (0)
+#define JUMP_LABEL_INITIAL_NOP ".byte 0xe9 \n\t .long 0\n\t"
+
+static __always_inline bool arch_static_branch(struct jump_label_key *key)
+{
+ asm goto("1:"
+ JUMP_LABEL_INITIAL_NOP
+ ".pushsection __jump_table, \"aw\" \n\t"
+ _ASM_ALIGN "\n\t"
+ _ASM_PTR "1b, %l[l_yes], %c0 \n\t"
+ ".popsection \n\t"
+ : : "i" (key) : : l_yes);
+ return false;
+l_yes:
+ return true;
+}
#endif /* __KERNEL__ */
diff --git a/arch/x86/include/asm/kgdb.h b/arch/x86/include/asm/kgdb.h
index 396f5b5fc4d7..77e95f54570a 100644
--- a/arch/x86/include/asm/kgdb.h
+++ b/arch/x86/include/asm/kgdb.h
@@ -77,6 +77,7 @@ static inline void arch_kgdb_breakpoint(void)
}
#define BREAK_INSTR_SIZE 1
#define CACHE_FLUSH_IS_SAFE 1
+#define GDB_ADJUSTS_BREAK_OFFSET
extern int kgdb_ll_trap(int cmd, const char *str,
struct pt_regs *regs, long err, int trap, int sig);
diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h
index 0f5213564326..0049211959c0 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -14,6 +14,8 @@
#include <asm/desc_defs.h>
struct x86_emulate_ctxt;
+enum x86_intercept;
+enum x86_intercept_stage;
struct x86_exception {
u8 vector;
@@ -24,6 +26,24 @@ struct x86_exception {
};
/*
+ * This struct is used to carry enough information from the instruction
+ * decoder to main KVM so that a decision can be made whether the
+ * instruction needs to be intercepted or not.
+ */
+struct x86_instruction_info {
+ u8 intercept; /* which intercept */
+ u8 rep_prefix; /* rep prefix? */
+ u8 modrm_mod; /* mod part of modrm */
+ u8 modrm_reg; /* index of register used */
+ u8 modrm_rm; /* rm part of modrm */
+ u64 src_val; /* value of source operand */
+ u8 src_bytes; /* size of source operand */
+ u8 dst_bytes; /* size of destination operand */
+ u8 ad_bytes; /* size of src/dst address */
+ u64 next_rip; /* rip following the instruction */
+};
+
+/*
* x86_emulate_ops:
*
* These operations represent the instruction emulator's interface to memory.
@@ -62,6 +82,7 @@ struct x86_exception {
#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 */
+#define X86EMUL_INTERCEPTED 6 /* Intercepted by nested VMCB/VMCS */
struct x86_emulate_ops {
/*
@@ -71,8 +92,9 @@ struct x86_emulate_ops {
* @val: [OUT] Value read from memory, zero-extended to 'u_long'.
* @bytes: [IN ] Number of bytes to read from memory.
*/
- int (*read_std)(unsigned long addr, void *val,
- unsigned int bytes, struct kvm_vcpu *vcpu,
+ int (*read_std)(struct x86_emulate_ctxt *ctxt,
+ unsigned long addr, void *val,
+ unsigned int bytes,
struct x86_exception *fault);
/*
@@ -82,8 +104,8 @@ struct x86_emulate_ops {
* @val: [OUT] Value write to memory, zero-extended to 'u_long'.
* @bytes: [IN ] Number of bytes to write to memory.
*/
- int (*write_std)(unsigned long addr, void *val,
- unsigned int bytes, struct kvm_vcpu *vcpu,
+ int (*write_std)(struct x86_emulate_ctxt *ctxt,
+ unsigned long addr, void *val, unsigned int bytes,
struct x86_exception *fault);
/*
* fetch: Read bytes of standard (non-emulated/special) memory.
@@ -92,8 +114,8 @@ struct x86_emulate_ops {
* @val: [OUT] Value read from memory, zero-extended to 'u_long'.
* @bytes: [IN ] Number of bytes to read from memory.
*/
- int (*fetch)(unsigned long addr, void *val,
- unsigned int bytes, struct kvm_vcpu *vcpu,
+ int (*fetch)(struct x86_emulate_ctxt *ctxt,
+ unsigned long addr, void *val, unsigned int bytes,
struct x86_exception *fault);
/*
@@ -102,11 +124,9 @@ struct x86_emulate_ops {
* @val: [OUT] Value read from memory, zero-extended to 'u_long'.
* @bytes: [IN ] Number of bytes to read from memory.
*/
- int (*read_emulated)(unsigned long addr,
- void *val,
- unsigned int bytes,
- struct x86_exception *fault,
- struct kvm_vcpu *vcpu);
+ int (*read_emulated)(struct x86_emulate_ctxt *ctxt,
+ unsigned long addr, void *val, unsigned int bytes,
+ struct x86_exception *fault);
/*
* write_emulated: Write bytes to emulated/special memory area.
@@ -115,11 +135,10 @@ struct x86_emulate_ops {
* required).
* @bytes: [IN ] Number of bytes to write to memory.
*/
- int (*write_emulated)(unsigned long addr,
- const void *val,
+ int (*write_emulated)(struct x86_emulate_ctxt *ctxt,
+ unsigned long addr, const void *val,
unsigned int bytes,
- struct x86_exception *fault,
- struct kvm_vcpu *vcpu);
+ struct x86_exception *fault);
/*
* cmpxchg_emulated: Emulate an atomic (LOCKed) CMPXCHG operation on an
@@ -129,40 +148,54 @@ struct x86_emulate_ops {
* @new: [IN ] Value to write to @addr.
* @bytes: [IN ] Number of bytes to access using CMPXCHG.
*/
- int (*cmpxchg_emulated)(unsigned long addr,
+ int (*cmpxchg_emulated)(struct x86_emulate_ctxt *ctxt,
+ unsigned long addr,
const void *old,
const void *new,
unsigned int bytes,
- struct x86_exception *fault,
- struct kvm_vcpu *vcpu);
-
- int (*pio_in_emulated)(int size, unsigned short port, void *val,
- unsigned int count, struct kvm_vcpu *vcpu);
-
- int (*pio_out_emulated)(int size, unsigned short port, const void *val,
- unsigned int count, struct kvm_vcpu *vcpu);
-
- bool (*get_cached_descriptor)(struct desc_struct *desc, u32 *base3,
- int seg, struct kvm_vcpu *vcpu);
- void (*set_cached_descriptor)(struct desc_struct *desc, u32 base3,
- 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);
- void (*get_idt)(struct desc_ptr *dt, struct kvm_vcpu *vcpu);
- ulong (*get_cr)(int cr, struct kvm_vcpu *vcpu);
- int (*set_cr)(int cr, ulong val, struct kvm_vcpu *vcpu);
- int (*cpl)(struct kvm_vcpu *vcpu);
- 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);
+ struct x86_exception *fault);
+ void (*invlpg)(struct x86_emulate_ctxt *ctxt, ulong addr);
+
+ int (*pio_in_emulated)(struct x86_emulate_ctxt *ctxt,
+ int size, unsigned short port, void *val,
+ unsigned int count);
+
+ int (*pio_out_emulated)(struct x86_emulate_ctxt *ctxt,
+ int size, unsigned short port, const void *val,
+ unsigned int count);
+
+ bool (*get_segment)(struct x86_emulate_ctxt *ctxt, u16 *selector,
+ struct desc_struct *desc, u32 *base3, int seg);
+ void (*set_segment)(struct x86_emulate_ctxt *ctxt, u16 selector,
+ struct desc_struct *desc, u32 base3, int seg);
+ unsigned long (*get_cached_segment_base)(struct x86_emulate_ctxt *ctxt,
+ int seg);
+ void (*get_gdt)(struct x86_emulate_ctxt *ctxt, struct desc_ptr *dt);
+ void (*get_idt)(struct x86_emulate_ctxt *ctxt, struct desc_ptr *dt);
+ void (*set_gdt)(struct x86_emulate_ctxt *ctxt, struct desc_ptr *dt);
+ void (*set_idt)(struct x86_emulate_ctxt *ctxt, struct desc_ptr *dt);
+ ulong (*get_cr)(struct x86_emulate_ctxt *ctxt, int cr);
+ int (*set_cr)(struct x86_emulate_ctxt *ctxt, int cr, ulong val);
+ int (*cpl)(struct x86_emulate_ctxt *ctxt);
+ int (*get_dr)(struct x86_emulate_ctxt *ctxt, int dr, ulong *dest);
+ int (*set_dr)(struct x86_emulate_ctxt *ctxt, int dr, ulong value);
+ int (*set_msr)(struct x86_emulate_ctxt *ctxt, u32 msr_index, u64 data);
+ int (*get_msr)(struct x86_emulate_ctxt *ctxt, u32 msr_index, u64 *pdata);
+ void (*halt)(struct x86_emulate_ctxt *ctxt);
+ void (*wbinvd)(struct x86_emulate_ctxt *ctxt);
+ int (*fix_hypercall)(struct x86_emulate_ctxt *ctxt);
+ void (*get_fpu)(struct x86_emulate_ctxt *ctxt); /* disables preempt */
+ void (*put_fpu)(struct x86_emulate_ctxt *ctxt); /* reenables preempt */
+ int (*intercept)(struct x86_emulate_ctxt *ctxt,
+ struct x86_instruction_info *info,
+ enum x86_intercept_stage stage);
};
+typedef u32 __attribute__((vector_size(16))) sse128_t;
+
/* Type, address-of, and value of an instruction's operand. */
struct operand {
- enum { OP_REG, OP_MEM, OP_IMM, OP_NONE } type;
+ enum { OP_REG, OP_MEM, OP_IMM, OP_XMM, OP_NONE } type;
unsigned int bytes;
union {
unsigned long orig_val;
@@ -174,11 +207,13 @@ struct operand {
ulong ea;
unsigned seg;
} mem;
+ unsigned xmm;
} addr;
union {
unsigned long val;
u64 val64;
char valptr[sizeof(unsigned long) + 2];
+ sse128_t vec_val;
};
};
@@ -197,6 +232,7 @@ struct read_cache {
struct decode_cache {
u8 twobyte;
u8 b;
+ u8 intercept;
u8 lock_prefix;
u8 rep_prefix;
u8 op_bytes;
@@ -209,6 +245,7 @@ struct decode_cache {
u8 seg_override;
unsigned int d;
int (*execute)(struct x86_emulate_ctxt *ctxt);
+ int (*check_perm)(struct x86_emulate_ctxt *ctxt);
unsigned long regs[NR_VCPU_REGS];
unsigned long eip;
/* modrm */
@@ -227,17 +264,15 @@ struct x86_emulate_ctxt {
struct x86_emulate_ops *ops;
/* Register state before/after emulation. */
- struct kvm_vcpu *vcpu;
-
unsigned long eflags;
unsigned long eip; /* eip before instruction emulation */
/* Emulated execution mode, represented by an X86EMUL_MODE value. */
int mode;
- u32 cs_base;
/* interruptibility state, as a result of execution of STI or MOV SS */
int interruptibility;
+ bool guest_mode; /* guest running a nested guest */
bool perm_ok; /* do not check permissions if true */
bool only_vendor_specific_insn;
@@ -249,8 +284,8 @@ struct x86_emulate_ctxt {
};
/* Repeat String Operation Prefix */
-#define REPE_PREFIX 1
-#define REPNE_PREFIX 2
+#define REPE_PREFIX 0xf3
+#define REPNE_PREFIX 0xf2
/* Execution mode, passed to the emulator. */
#define X86EMUL_MODE_REAL 0 /* Real mode. */
@@ -259,6 +294,69 @@ struct x86_emulate_ctxt {
#define X86EMUL_MODE_PROT32 4 /* 32-bit protected mode. */
#define X86EMUL_MODE_PROT64 8 /* 64-bit (long) mode. */
+/* any protected mode */
+#define X86EMUL_MODE_PROT (X86EMUL_MODE_PROT16|X86EMUL_MODE_PROT32| \
+ X86EMUL_MODE_PROT64)
+
+enum x86_intercept_stage {
+ X86_ICTP_NONE = 0, /* Allow zero-init to not match anything */
+ X86_ICPT_PRE_EXCEPT,
+ X86_ICPT_POST_EXCEPT,
+ X86_ICPT_POST_MEMACCESS,
+};
+
+enum x86_intercept {
+ x86_intercept_none,
+ x86_intercept_cr_read,
+ x86_intercept_cr_write,
+ x86_intercept_clts,
+ x86_intercept_lmsw,
+ x86_intercept_smsw,
+ x86_intercept_dr_read,
+ x86_intercept_dr_write,
+ x86_intercept_lidt,
+ x86_intercept_sidt,
+ x86_intercept_lgdt,
+ x86_intercept_sgdt,
+ x86_intercept_lldt,
+ x86_intercept_sldt,
+ x86_intercept_ltr,
+ x86_intercept_str,
+ x86_intercept_rdtsc,
+ x86_intercept_rdpmc,
+ x86_intercept_pushf,
+ x86_intercept_popf,
+ x86_intercept_cpuid,
+ x86_intercept_rsm,
+ x86_intercept_iret,
+ x86_intercept_intn,
+ x86_intercept_invd,
+ x86_intercept_pause,
+ x86_intercept_hlt,
+ x86_intercept_invlpg,
+ x86_intercept_invlpga,
+ x86_intercept_vmrun,
+ x86_intercept_vmload,
+ x86_intercept_vmsave,
+ x86_intercept_vmmcall,
+ x86_intercept_stgi,
+ x86_intercept_clgi,
+ x86_intercept_skinit,
+ x86_intercept_rdtscp,
+ x86_intercept_icebp,
+ x86_intercept_wbinvd,
+ x86_intercept_monitor,
+ x86_intercept_mwait,
+ x86_intercept_rdmsr,
+ x86_intercept_wrmsr,
+ x86_intercept_in,
+ x86_intercept_ins,
+ x86_intercept_out,
+ x86_intercept_outs,
+
+ nr_x86_intercepts
+};
+
/* Host execution mode. */
#if defined(CONFIG_X86_32)
#define X86EMUL_MODE_HOST X86EMUL_MODE_PROT32
@@ -270,6 +368,7 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len);
#define EMULATION_FAILED -1
#define EMULATION_OK 0
#define EMULATION_RESTART 1
+#define EMULATION_INTERCEPTED 2
int x86_emulate_insn(struct x86_emulate_ctxt *ctxt);
int emulator_task_switch(struct x86_emulate_ctxt *ctxt,
u16 tss_selector, int reason,
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index c8af0991fdf0..d2ac8e2ee897 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -30,14 +30,30 @@
#define KVM_MEMORY_SLOTS 32
/* memory slots that does not exposed to userspace */
#define KVM_PRIVATE_MEM_SLOTS 4
+#define KVM_MMIO_SIZE 16
#define KVM_PIO_PAGE_OFFSET 1
#define KVM_COALESCED_MMIO_PAGE_OFFSET 2
+#define CR0_RESERVED_BITS \
+ (~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \
+ | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM \
+ | X86_CR0_NW | X86_CR0_CD | X86_CR0_PG))
+
#define CR3_PAE_RESERVED_BITS ((X86_CR3_PWT | X86_CR3_PCD) - 1)
#define CR3_NONPAE_RESERVED_BITS ((PAGE_SIZE-1) & ~(X86_CR3_PWT | X86_CR3_PCD))
#define CR3_L_MODE_RESERVED_BITS (CR3_NONPAE_RESERVED_BITS | \
0xFFFFFF0000000000ULL)
+#define CR4_RESERVED_BITS \
+ (~(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)
+
+
#define INVALID_PAGE (~(hpa_t)0)
#define VALID_PAGE(x) ((x) != INVALID_PAGE)
@@ -118,6 +134,9 @@ enum kvm_reg {
enum kvm_reg_ex {
VCPU_EXREG_PDPTR = NR_VCPU_REGS,
VCPU_EXREG_CR3,
+ VCPU_EXREG_RFLAGS,
+ VCPU_EXREG_CPL,
+ VCPU_EXREG_SEGMENTS,
};
enum {
@@ -256,7 +275,7 @@ struct kvm_mmu {
struct kvm_mmu_page *sp);
void (*invlpg)(struct kvm_vcpu *vcpu, gva_t gva);
void (*update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
- u64 *spte, const void *pte, unsigned long mmu_seq);
+ u64 *spte, const void *pte);
hpa_t root_hpa;
int root_level;
int shadow_root_level;
@@ -340,7 +359,6 @@ struct kvm_vcpu_arch {
struct fpu guest_fpu;
u64 xcr0;
- gva_t mmio_fault_cr2;
struct kvm_pio_request pio;
void *pio_data;
@@ -367,18 +385,22 @@ struct kvm_vcpu_arch {
/* emulate context */
struct x86_emulate_ctxt emulate_ctxt;
+ bool emulate_regs_need_sync_to_vcpu;
+ bool emulate_regs_need_sync_from_vcpu;
gpa_t time;
struct pvclock_vcpu_time_info hv_clock;
unsigned int hw_tsc_khz;
unsigned int time_offset;
struct page *time_page;
- u64 last_host_tsc;
u64 last_guest_tsc;
u64 last_kernel_ns;
u64 last_tsc_nsec;
u64 last_tsc_write;
+ u32 virtual_tsc_khz;
bool tsc_catchup;
+ u32 tsc_catchup_mult;
+ s8 tsc_catchup_shift;
bool nmi_pending;
bool nmi_injected;
@@ -448,9 +470,6 @@ struct kvm_arch {
u64 last_tsc_nsec;
u64 last_tsc_offset;
u64 last_tsc_write;
- u32 virtual_tsc_khz;
- u32 virtual_tsc_mult;
- s8 virtual_tsc_shift;
struct kvm_xen_hvm_config xen_hvm_config;
@@ -502,6 +521,8 @@ struct kvm_vcpu_stat {
u32 nmi_injections;
};
+struct x86_instruction_info;
+
struct kvm_x86_ops {
int (*cpu_has_kvm_support)(void); /* __init */
int (*disabled_by_bios)(void); /* __init */
@@ -586,9 +607,17 @@ struct kvm_x86_ops {
bool (*has_wbinvd_exit)(void);
+ void (*set_tsc_khz)(struct kvm_vcpu *vcpu, u32 user_tsc_khz);
void (*write_tsc_offset)(struct kvm_vcpu *vcpu, u64 offset);
+ u64 (*compute_tsc_offset)(struct kvm_vcpu *vcpu, u64 target_tsc);
+
void (*get_exit_info)(struct kvm_vcpu *vcpu, u64 *info1, u64 *info2);
+
+ int (*check_intercept)(struct kvm_vcpu *vcpu,
+ struct x86_instruction_info *info,
+ enum x86_intercept_stage stage);
+
const struct trace_print_flags *exit_reasons_str;
};
@@ -627,6 +656,13 @@ u8 kvm_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn);
extern bool tdp_enabled;
+/* control of guest tsc rate supported? */
+extern bool kvm_has_tsc_control;
+/* minimum supported tsc_khz for guests */
+extern u32 kvm_min_guest_tsc_khz;
+/* maximum supported tsc_khz for guests */
+extern u32 kvm_max_guest_tsc_khz;
+
enum emulation_result {
EMULATE_DONE, /* no further processing */
EMULATE_DO_MMIO, /* kvm_run filled with mmio request */
@@ -645,9 +681,6 @@ static inline int emulate_instruction(struct kvm_vcpu *vcpu,
return x86_emulate_instruction(vcpu, 0, emulation_type, NULL, 0);
}
-void realmode_lgdt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
-void realmode_lidt(struct kvm_vcpu *vcpu, u16 size, unsigned long address);
-
void kvm_enable_efer_bits(u64);
int kvm_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *data);
int kvm_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data);
@@ -657,8 +690,6 @@ struct x86_emulate_ctxt;
int kvm_fast_pio_out(struct kvm_vcpu *vcpu, int size, unsigned short port);
void kvm_emulate_cpuid(struct kvm_vcpu *vcpu);
int kvm_emulate_halt(struct kvm_vcpu *vcpu);
-int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address);
-int emulate_clts(struct kvm_vcpu *vcpu);
int kvm_emulate_wbinvd(struct kvm_vcpu *vcpu);
void kvm_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg);
@@ -721,8 +752,6 @@ gpa_t kvm_mmu_gva_to_gpa_system(struct kvm_vcpu *vcpu, gva_t gva,
int kvm_emulate_hypercall(struct kvm_vcpu *vcpu);
-int kvm_fix_hypercall(struct kvm_vcpu *vcpu);
-
int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva, u32 error_code,
void *insn, int insn_len);
void kvm_mmu_invlpg(struct kvm_vcpu *vcpu, gva_t gva);
diff --git a/arch/x86/include/asm/linkage.h b/arch/x86/include/asm/linkage.h
index 12d55e773eb6..48142971b25d 100644
--- a/arch/x86/include/asm/linkage.h
+++ b/arch/x86/include/asm/linkage.h
@@ -8,11 +8,6 @@
#ifdef CONFIG_X86_32
#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))
-/*
- * For 32-bit UML - mark functions implemented in assembly that use
- * regparm input parameters:
- */
-#define asmregparm __attribute__((regparm(3)))
/*
* Make sure the compiler doesn't do anything stupid with the
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h
index eb16e94ae04f..021979a6e23f 100644
--- a/arch/x86/include/asm/mce.h
+++ b/arch/x86/include/asm/mce.h
@@ -142,8 +142,6 @@ static inline void winchip_mcheck_init(struct cpuinfo_x86 *c) {}
static inline void enable_p5_mce(void) {}
#endif
-extern void (*x86_mce_decode_callback)(struct mce *m);
-
void mce_setup(struct mce *m);
void mce_log(struct mce *m);
DECLARE_PER_CPU(struct sys_device, mce_dev);
diff --git a/arch/x86/include/asm/mmzone_32.h b/arch/x86/include/asm/mmzone_32.h
index 91df7c51806c..5e83a416eca8 100644
--- a/arch/x86/include/asm/mmzone_32.h
+++ b/arch/x86/include/asm/mmzone_32.h
@@ -13,31 +13,11 @@ extern struct pglist_data *node_data[];
#define NODE_DATA(nid) (node_data[nid])
#include <asm/numaq.h>
-/* summit or generic arch */
-#include <asm/srat.h>
-
-extern int get_memcfg_numa_flat(void);
-/*
- * This allows any one NUMA architecture to be compiled
- * for, and still fall back to the flat function if it
- * fails.
- */
-static inline void get_memcfg_numa(void)
-{
-
- if (get_memcfg_numaq())
- return;
- if (get_memcfg_from_srat())
- return;
- get_memcfg_numa_flat();
-}
extern void resume_map_numa_kva(pgd_t *pgd);
#else /* !CONFIG_NUMA */
-#define get_memcfg_numa get_memcfg_numa_flat
-
static inline void resume_map_numa_kva(pgd_t *pgd) {}
#endif /* CONFIG_NUMA */
diff --git a/arch/x86/include/asm/mmzone_64.h b/arch/x86/include/asm/mmzone_64.h
index 288b96f815a6..b3f88d7867c7 100644
--- a/arch/x86/include/asm/mmzone_64.h
+++ b/arch/x86/include/asm/mmzone_64.h
@@ -4,36 +4,13 @@
#ifndef _ASM_X86_MMZONE_64_H
#define _ASM_X86_MMZONE_64_H
-
#ifdef CONFIG_NUMA
#include <linux/mmdebug.h>
-
#include <asm/smp.h>
-/* Simple perfect hash to map physical addresses to node numbers */
-struct memnode {
- int shift;
- unsigned int mapsize;
- s16 *map;
- s16 embedded_map[64 - 8];
-} ____cacheline_aligned; /* total size = 128 bytes */
-extern struct memnode memnode;
-#define memnode_shift memnode.shift
-#define memnodemap memnode.map
-#define memnodemapsize memnode.mapsize
-
extern struct pglist_data *node_data[];
-static inline __attribute__((pure)) int phys_to_nid(unsigned long addr)
-{
- unsigned nid;
- VIRTUAL_BUG_ON(!memnodemap);
- nid = memnodemap[addr >> memnode_shift];
- VIRTUAL_BUG_ON(nid >= MAX_NUMNODES || !node_data[nid]);
- return nid;
-}
-
#define NODE_DATA(nid) (node_data[nid])
#define node_start_pfn(nid) (NODE_DATA(nid)->node_start_pfn)
diff --git a/arch/x86/include/asm/module.h b/arch/x86/include/asm/module.h
index 67763c5d8b4e..9eae7752ae9b 100644
--- a/arch/x86/include/asm/module.h
+++ b/arch/x86/include/asm/module.h
@@ -35,7 +35,7 @@
#define MODULE_PROC_FAMILY "K7 "
#elif defined CONFIG_MK8
#define MODULE_PROC_FAMILY "K8 "
-#elif defined CONFIG_X86_ELAN
+#elif defined CONFIG_MELAN
#define MODULE_PROC_FAMILY "ELAN "
#elif defined CONFIG_MCRUSOE
#define MODULE_PROC_FAMILY "CRUSOE "
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 3cce71413d0b..485b4f1f079b 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -118,6 +118,7 @@
complete list. */
#define MSR_AMD64_PATCH_LEVEL 0x0000008b
+#define MSR_AMD64_TSC_RATIO 0xc0000104
#define MSR_AMD64_NB_CFG 0xc001001f
#define MSR_AMD64_PATCH_LOADER 0xc0010020
#define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140
diff --git a/arch/x86/include/asm/nops.h b/arch/x86/include/asm/nops.h
index af788496020b..405b4032a60b 100644
--- a/arch/x86/include/asm/nops.h
+++ b/arch/x86/include/asm/nops.h
@@ -1,7 +1,13 @@
#ifndef _ASM_X86_NOPS_H
#define _ASM_X86_NOPS_H
-/* Define nops for use with alternative() */
+/*
+ * Define nops for use with alternative() and for tracing.
+ *
+ * *_NOP5_ATOMIC must be a single instruction.
+ */
+
+#define NOP_DS_PREFIX 0x3e
/* generic versions from gas
1: nop
@@ -13,14 +19,15 @@
6: leal 0x00000000(%esi),%esi
7: leal 0x00000000(,%esi,1),%esi
*/
-#define GENERIC_NOP1 ".byte 0x90\n"
-#define GENERIC_NOP2 ".byte 0x89,0xf6\n"
-#define GENERIC_NOP3 ".byte 0x8d,0x76,0x00\n"
-#define GENERIC_NOP4 ".byte 0x8d,0x74,0x26,0x00\n"
-#define GENERIC_NOP5 GENERIC_NOP1 GENERIC_NOP4
-#define GENERIC_NOP6 ".byte 0x8d,0xb6,0x00,0x00,0x00,0x00\n"
-#define GENERIC_NOP7 ".byte 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00\n"
-#define GENERIC_NOP8 GENERIC_NOP1 GENERIC_NOP7
+#define GENERIC_NOP1 0x90
+#define GENERIC_NOP2 0x89,0xf6
+#define GENERIC_NOP3 0x8d,0x76,0x00
+#define GENERIC_NOP4 0x8d,0x74,0x26,0x00
+#define GENERIC_NOP5 GENERIC_NOP1,GENERIC_NOP4
+#define GENERIC_NOP6 0x8d,0xb6,0x00,0x00,0x00,0x00
+#define GENERIC_NOP7 0x8d,0xb4,0x26,0x00,0x00,0x00,0x00
+#define GENERIC_NOP8 GENERIC_NOP1,GENERIC_NOP7
+#define GENERIC_NOP5_ATOMIC NOP_DS_PREFIX,GENERIC_NOP4
/* Opteron 64bit nops
1: nop
@@ -29,13 +36,14 @@
4: osp osp osp nop
*/
#define K8_NOP1 GENERIC_NOP1
-#define K8_NOP2 ".byte 0x66,0x90\n"
-#define K8_NOP3 ".byte 0x66,0x66,0x90\n"
-#define K8_NOP4 ".byte 0x66,0x66,0x66,0x90\n"
-#define K8_NOP5 K8_NOP3 K8_NOP2
-#define K8_NOP6 K8_NOP3 K8_NOP3
-#define K8_NOP7 K8_NOP4 K8_NOP3
-#define K8_NOP8 K8_NOP4 K8_NOP4
+#define K8_NOP2 0x66,K8_NOP1
+#define K8_NOP3 0x66,K8_NOP2
+#define K8_NOP4 0x66,K8_NOP3
+#define K8_NOP5 K8_NOP3,K8_NOP2
+#define K8_NOP6 K8_NOP3,K8_NOP3
+#define K8_NOP7 K8_NOP4,K8_NOP3
+#define K8_NOP8 K8_NOP4,K8_NOP4
+#define K8_NOP5_ATOMIC 0x66,K8_NOP4
/* K7 nops
uses eax dependencies (arbitrary choice)
@@ -47,13 +55,14 @@
7: leal 0x00000000(,%eax,1),%eax
*/
#define K7_NOP1 GENERIC_NOP1
-#define K7_NOP2 ".byte 0x8b,0xc0\n"
-#define K7_NOP3 ".byte 0x8d,0x04,0x20\n"
-#define K7_NOP4 ".byte 0x8d,0x44,0x20,0x00\n"
-#define K7_NOP5 K7_NOP4 ASM_NOP1
-#define K7_NOP6 ".byte 0x8d,0x80,0,0,0,0\n"
-#define K7_NOP7 ".byte 0x8D,0x04,0x05,0,0,0,0\n"
-#define K7_NOP8 K7_NOP7 ASM_NOP1
+#define K7_NOP2 0x8b,0xc0
+#define K7_NOP3 0x8d,0x04,0x20
+#define K7_NOP4 0x8d,0x44,0x20,0x00
+#define K7_NOP5 K7_NOP4,K7_NOP1
+#define K7_NOP6 0x8d,0x80,0,0,0,0
+#define K7_NOP7 0x8D,0x04,0x05,0,0,0,0
+#define K7_NOP8 K7_NOP7,K7_NOP1
+#define K7_NOP5_ATOMIC NOP_DS_PREFIX,K7_NOP4
/* P6 nops
uses eax dependencies (Intel-recommended choice)
@@ -69,52 +78,65 @@
There is kernel code that depends on this.
*/
#define P6_NOP1 GENERIC_NOP1
-#define P6_NOP2 ".byte 0x66,0x90\n"
-#define P6_NOP3 ".byte 0x0f,0x1f,0x00\n"
-#define P6_NOP4 ".byte 0x0f,0x1f,0x40,0\n"
-#define P6_NOP5 ".byte 0x0f,0x1f,0x44,0x00,0\n"
-#define P6_NOP6 ".byte 0x66,0x0f,0x1f,0x44,0x00,0\n"
-#define P6_NOP7 ".byte 0x0f,0x1f,0x80,0,0,0,0\n"
-#define P6_NOP8 ".byte 0x0f,0x1f,0x84,0x00,0,0,0,0\n"
+#define P6_NOP2 0x66,0x90
+#define P6_NOP3 0x0f,0x1f,0x00
+#define P6_NOP4 0x0f,0x1f,0x40,0
+#define P6_NOP5 0x0f,0x1f,0x44,0x00,0
+#define P6_NOP6 0x66,0x0f,0x1f,0x44,0x00,0
+#define P6_NOP7 0x0f,0x1f,0x80,0,0,0,0
+#define P6_NOP8 0x0f,0x1f,0x84,0x00,0,0,0,0
+#define P6_NOP5_ATOMIC P6_NOP5
+
+#define _ASM_MK_NOP(x) ".byte " __stringify(x) "\n"
#if defined(CONFIG_MK7)
-#define ASM_NOP1 K7_NOP1
-#define ASM_NOP2 K7_NOP2
-#define ASM_NOP3 K7_NOP3
-#define ASM_NOP4 K7_NOP4
-#define ASM_NOP5 K7_NOP5
-#define ASM_NOP6 K7_NOP6
-#define ASM_NOP7 K7_NOP7
-#define ASM_NOP8 K7_NOP8
+#define ASM_NOP1 _ASM_MK_NOP(K7_NOP1)
+#define ASM_NOP2 _ASM_MK_NOP(K7_NOP2)
+#define ASM_NOP3 _ASM_MK_NOP(K7_NOP3)
+#define ASM_NOP4 _ASM_MK_NOP(K7_NOP4)
+#define ASM_NOP5 _ASM_MK_NOP(K7_NOP5)
+#define ASM_NOP6 _ASM_MK_NOP(K7_NOP6)
+#define ASM_NOP7 _ASM_MK_NOP(K7_NOP7)
+#define ASM_NOP8 _ASM_MK_NOP(K7_NOP8)
+#define ASM_NOP5_ATOMIC _ASM_MK_NOP(K7_NOP5_ATOMIC)
#elif defined(CONFIG_X86_P6_NOP)
-#define ASM_NOP1 P6_NOP1
-#define ASM_NOP2 P6_NOP2
-#define ASM_NOP3 P6_NOP3
-#define ASM_NOP4 P6_NOP4
-#define ASM_NOP5 P6_NOP5
-#define ASM_NOP6 P6_NOP6
-#define ASM_NOP7 P6_NOP7
-#define ASM_NOP8 P6_NOP8
+#define ASM_NOP1 _ASM_MK_NOP(P6_NOP1)
+#define ASM_NOP2 _ASM_MK_NOP(P6_NOP2)
+#define ASM_NOP3 _ASM_MK_NOP(P6_NOP3)
+#define ASM_NOP4 _ASM_MK_NOP(P6_NOP4)
+#define ASM_NOP5 _ASM_MK_NOP(P6_NOP5)
+#define ASM_NOP6 _ASM_MK_NOP(P6_NOP6)
+#define ASM_NOP7 _ASM_MK_NOP(P6_NOP7)
+#define ASM_NOP8 _ASM_MK_NOP(P6_NOP8)
+#define ASM_NOP5_ATOMIC _ASM_MK_NOP(P6_NOP5_ATOMIC)
#elif defined(CONFIG_X86_64)
-#define ASM_NOP1 K8_NOP1
-#define ASM_NOP2 K8_NOP2
-#define ASM_NOP3 K8_NOP3
-#define ASM_NOP4 K8_NOP4
-#define ASM_NOP5 K8_NOP5
-#define ASM_NOP6 K8_NOP6
-#define ASM_NOP7 K8_NOP7
-#define ASM_NOP8 K8_NOP8
+#define ASM_NOP1 _ASM_MK_NOP(K8_NOP1)
+#define ASM_NOP2 _ASM_MK_NOP(K8_NOP2)
+#define ASM_NOP3 _ASM_MK_NOP(K8_NOP3)
+#define ASM_NOP4 _ASM_MK_NOP(K8_NOP4)
+#define ASM_NOP5 _ASM_MK_NOP(K8_NOP5)
+#define ASM_NOP6 _ASM_MK_NOP(K8_NOP6)
+#define ASM_NOP7 _ASM_MK_NOP(K8_NOP7)
+#define ASM_NOP8 _ASM_MK_NOP(K8_NOP8)
+#define ASM_NOP5_ATOMIC _ASM_MK_NOP(K8_NOP5_ATOMIC)
#else
-#define ASM_NOP1 GENERIC_NOP1
-#define ASM_NOP2 GENERIC_NOP2
-#define ASM_NOP3 GENERIC_NOP3
-#define ASM_NOP4 GENERIC_NOP4
-#define ASM_NOP5 GENERIC_NOP5
-#define ASM_NOP6 GENERIC_NOP6
-#define ASM_NOP7 GENERIC_NOP7
-#define ASM_NOP8 GENERIC_NOP8
+#define ASM_NOP1 _ASM_MK_NOP(GENERIC_NOP1)
+#define ASM_NOP2 _ASM_MK_NOP(GENERIC_NOP2)
+#define ASM_NOP3 _ASM_MK_NOP(GENERIC_NOP3)
+#define ASM_NOP4 _ASM_MK_NOP(GENERIC_NOP4)
+#define ASM_NOP5 _ASM_MK_NOP(GENERIC_NOP5)
+#define ASM_NOP6 _ASM_MK_NOP(GENERIC_NOP6)
+#define ASM_NOP7 _ASM_MK_NOP(GENERIC_NOP7)
+#define ASM_NOP8 _ASM_MK_NOP(GENERIC_NOP8)
+#define ASM_NOP5_ATOMIC _ASM_MK_NOP(GENERIC_NOP5_ATOMIC)
#endif
#define ASM_NOP_MAX 8
+#define NOP_ATOMIC5 (ASM_NOP_MAX+1) /* Entry for the 5-byte atomic NOP */
+
+#ifndef __ASSEMBLY__
+extern const unsigned char * const *ideal_nops;
+extern void arch_init_ideal_nops(void);
+#endif
#endif /* _ASM_X86_NOPS_H */
diff --git a/arch/x86/include/asm/numa.h b/arch/x86/include/asm/numa.h
index a50fc9f493b3..bfacd2ccf651 100644
--- a/arch/x86/include/asm/numa.h
+++ b/arch/x86/include/asm/numa.h
@@ -1,12 +1,24 @@
#ifndef _ASM_X86_NUMA_H
#define _ASM_X86_NUMA_H
+#include <linux/nodemask.h>
+
#include <asm/topology.h>
#include <asm/apicdef.h>
#ifdef CONFIG_NUMA
#define NR_NODE_MEMBLKS (MAX_NUMNODES*2)
+#define ZONE_ALIGN (1UL << (MAX_ORDER+PAGE_SHIFT))
+
+/*
+ * Too small node sizes may confuse the VM badly. Usually they
+ * result from BIOS bugs. So dont recognize nodes as standalone
+ * NUMA entities that have less than this amount of RAM listed:
+ */
+#define NODE_MIN_SIZE (4*1024*1024)
+
+extern int numa_off;
/*
* __apicid_to_node[] stores the raw mapping between physical apicid and
@@ -17,15 +29,27 @@
* numa_cpu_node().
*/
extern s16 __apicid_to_node[MAX_LOCAL_APIC];
+extern nodemask_t numa_nodes_parsed __initdata;
+
+extern int __init numa_add_memblk(int nodeid, u64 start, u64 end);
+extern void __init numa_set_distance(int from, int to, int distance);
static inline void set_apicid_to_node(int apicid, s16 node)
{
__apicid_to_node[apicid] = node;
}
+
+extern int __cpuinit numa_cpu_node(int cpu);
+
#else /* CONFIG_NUMA */
static inline void set_apicid_to_node(int apicid, s16 node)
{
}
+
+static inline int numa_cpu_node(int cpu)
+{
+ return NUMA_NO_NODE;
+}
#endif /* CONFIG_NUMA */
#ifdef CONFIG_X86_32
@@ -37,14 +61,12 @@ static inline void set_apicid_to_node(int apicid, s16 node)
#ifdef CONFIG_NUMA
extern void __cpuinit numa_set_node(int cpu, int node);
extern void __cpuinit numa_clear_node(int cpu);
-extern void __init numa_init_array(void);
extern void __init init_cpu_to_node(void);
extern void __cpuinit numa_add_cpu(int cpu);
extern void __cpuinit numa_remove_cpu(int cpu);
#else /* CONFIG_NUMA */
static inline void numa_set_node(int cpu, int node) { }
static inline void numa_clear_node(int cpu) { }
-static inline void numa_init_array(void) { }
static inline void init_cpu_to_node(void) { }
static inline void numa_add_cpu(int cpu) { }
static inline void numa_remove_cpu(int cpu) { }
@@ -54,4 +76,10 @@ static inline void numa_remove_cpu(int cpu) { }
void debug_cpumask_set_cpu(int cpu, int node, bool enable);
#endif
+#ifdef CONFIG_NUMA_EMU
+#define FAKE_NODE_MIN_SIZE ((u64)32 << 20)
+#define FAKE_NODE_MIN_HASH_MASK (~(FAKE_NODE_MIN_SIZE - 1UL))
+void numa_emu_cmdline(char *);
+#endif /* CONFIG_NUMA_EMU */
+
#endif /* _ASM_X86_NUMA_H */
diff --git a/arch/x86/include/asm/numa_32.h b/arch/x86/include/asm/numa_32.h
index c6beed1ef103..e7d6b8254742 100644
--- a/arch/x86/include/asm/numa_32.h
+++ b/arch/x86/include/asm/numa_32.h
@@ -1,16 +1,6 @@
#ifndef _ASM_X86_NUMA_32_H
#define _ASM_X86_NUMA_32_H
-extern int numa_off;
-
-extern int pxm_to_nid(int pxm);
-
-#ifdef CONFIG_NUMA
-extern int __cpuinit numa_cpu_node(int cpu);
-#else /* CONFIG_NUMA */
-static inline int numa_cpu_node(int cpu) { return NUMA_NO_NODE; }
-#endif /* CONFIG_NUMA */
-
#ifdef CONFIG_HIGHMEM
extern void set_highmem_pages_init(void);
#else
diff --git a/arch/x86/include/asm/numa_64.h b/arch/x86/include/asm/numa_64.h
index 344eb1790b46..0c05f7ae46e8 100644
--- a/arch/x86/include/asm/numa_64.h
+++ b/arch/x86/include/asm/numa_64.h
@@ -1,42 +1,6 @@
#ifndef _ASM_X86_NUMA_64_H
#define _ASM_X86_NUMA_64_H
-#include <linux/nodemask.h>
-
-struct bootnode {
- u64 start;
- u64 end;
-};
-
-#define ZONE_ALIGN (1UL << (MAX_ORDER+PAGE_SHIFT))
-
-extern int numa_off;
-
extern unsigned long numa_free_all_bootmem(void);
-extern void setup_node_bootmem(int nodeid, unsigned long start,
- unsigned long end);
-
-#ifdef CONFIG_NUMA
-/*
- * Too small node sizes may confuse the VM badly. Usually they
- * result from BIOS bugs. So dont recognize nodes as standalone
- * NUMA entities that have less than this amount of RAM listed:
- */
-#define NODE_MIN_SIZE (4*1024*1024)
-
-extern nodemask_t numa_nodes_parsed __initdata;
-
-extern int __cpuinit numa_cpu_node(int cpu);
-extern int __init numa_add_memblk(int nodeid, u64 start, u64 end);
-extern void __init numa_set_distance(int from, int to, int distance);
-
-#ifdef CONFIG_NUMA_EMU
-#define FAKE_NODE_MIN_SIZE ((u64)32 << 20)
-#define FAKE_NODE_MIN_HASH_MASK (~(FAKE_NODE_MIN_SIZE - 1UL))
-void numa_emu_cmdline(char *);
-#endif /* CONFIG_NUMA_EMU */
-#else
-static inline int numa_cpu_node(int cpu) { return NUMA_NO_NODE; }
-#endif
#endif /* _ASM_X86_NUMA_64_H */
diff --git a/arch/x86/include/asm/numaq.h b/arch/x86/include/asm/numaq.h
index 37c516545ec8..c3b3c322fd87 100644
--- a/arch/x86/include/asm/numaq.h
+++ b/arch/x86/include/asm/numaq.h
@@ -29,7 +29,7 @@
#ifdef CONFIG_X86_NUMAQ
extern int found_numaq;
-extern int get_memcfg_numaq(void);
+extern int numaq_numa_init(void);
extern int pci_numaq_init(void);
extern void *xquad_portio;
@@ -166,11 +166,6 @@ struct sys_cfg_data {
void numaq_tsc_disable(void);
-#else
-static inline int get_memcfg_numaq(void)
-{
- return 0;
-}
#endif /* CONFIG_X86_NUMAQ */
#endif /* _ASM_X86_NUMAQ_H */
diff --git a/arch/x86/include/asm/olpc_ofw.h b/arch/x86/include/asm/olpc_ofw.h
index c5d3a5abbb9f..24487712e0b1 100644
--- a/arch/x86/include/asm/olpc_ofw.h
+++ b/arch/x86/include/asm/olpc_ofw.h
@@ -26,15 +26,12 @@ extern void setup_olpc_ofw_pgd(void);
/* check if OFW was detected during boot */
extern bool olpc_ofw_present(void);
+extern void olpc_dt_build_devicetree(void);
+
#else /* !CONFIG_OLPC */
static inline void olpc_ofw_detect(void) { }
static inline void setup_olpc_ofw_pgd(void) { }
-#endif /* !CONFIG_OLPC */
-
-#ifdef CONFIG_OF_PROMTREE
-extern void olpc_dt_build_devicetree(void);
-#else
static inline void olpc_dt_build_devicetree(void) { }
-#endif
+#endif /* !CONFIG_OLPC */
#endif /* _ASM_X86_OLPC_OFW_H */
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h
index 676129229630..d498943b906c 100644
--- a/arch/x86/include/asm/pci.h
+++ b/arch/x86/include/asm/pci.h
@@ -135,8 +135,6 @@ void default_teardown_msi_irqs(struct pci_dev *dev);
#include "pci_64.h"
#endif
-void dma32_reserve_bootmem(void);
-
/* implement the pci_ DMA API in terms of the generic device dma_ one */
#include <asm-generic/pci-dma-compat.h>
diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h
index d475b4398d8b..a0a9779084d1 100644
--- a/arch/x86/include/asm/percpu.h
+++ b/arch/x86/include/asm/percpu.h
@@ -509,6 +509,11 @@ do { \
* it in software. The address used in the cmpxchg16 instruction must be
* aligned to a 16 byte boundary.
*/
+#ifdef CONFIG_SMP
+#define CMPXCHG16B_EMU_CALL "call this_cpu_cmpxchg16b_emu\n\t" ASM_NOP3
+#else
+#define CMPXCHG16B_EMU_CALL "call this_cpu_cmpxchg16b_emu\n\t" ASM_NOP2
+#endif
#define percpu_cmpxchg16b_double(pcp1, o1, o2, n1, n2) \
({ \
char __ret; \
@@ -517,7 +522,7 @@ do { \
typeof(o2) __o2 = o2; \
typeof(o2) __n2 = n2; \
typeof(o2) __dummy; \
- alternative_io("call this_cpu_cmpxchg16b_emu\n\t" P6_NOP4, \
+ alternative_io(CMPXCHG16B_EMU_CALL, \
"cmpxchg16b " __percpu_prefix "(%%rsi)\n\tsetz %0\n\t", \
X86_FEATURE_CX16, \
ASM_OUTPUT2("=a"(__ret), "=d"(__dummy)), \
@@ -542,6 +547,33 @@ do { \
old__; \
})
+static __always_inline int x86_this_cpu_constant_test_bit(unsigned int nr,
+ const unsigned long __percpu *addr)
+{
+ unsigned long __percpu *a = (unsigned long *)addr + nr / BITS_PER_LONG;
+
+ return ((1UL << (nr % BITS_PER_LONG)) & percpu_read(*a)) != 0;
+}
+
+static inline int x86_this_cpu_variable_test_bit(int nr,
+ const unsigned long __percpu *addr)
+{
+ int oldbit;
+
+ asm volatile("bt "__percpu_arg(2)",%1\n\t"
+ "sbb %0,%0"
+ : "=r" (oldbit)
+ : "m" (*(unsigned long *)addr), "Ir" (nr));
+
+ return oldbit;
+}
+
+#define x86_this_cpu_test_bit(nr, addr) \
+ (__builtin_constant_p((nr)) \
+ ? x86_this_cpu_constant_test_bit((nr), (addr)) \
+ : x86_this_cpu_variable_test_bit((nr), (addr)))
+
+
#include <asm-generic/percpu.h>
/* We can use this directly for local CPU (faster). */
diff --git a/arch/x86/include/asm/probe_roms.h b/arch/x86/include/asm/probe_roms.h
new file mode 100644
index 000000000000..4950a0b1d09c
--- /dev/null
+++ b/arch/x86/include/asm/probe_roms.h
@@ -0,0 +1,8 @@
+#ifndef _PROBE_ROMS_H_
+#define _PROBE_ROMS_H_
+struct pci_dev;
+
+extern void __iomem *pci_map_biosrom(struct pci_dev *pdev);
+extern void pci_unmap_biosrom(void __iomem *rom);
+extern size_t pci_biosrom_size(struct pci_dev *pdev);
+#endif
diff --git a/arch/x86/include/asm/processor-flags.h b/arch/x86/include/asm/processor-flags.h
index a898a2b6e10c..59ab4dffa377 100644
--- a/arch/x86/include/asm/processor-flags.h
+++ b/arch/x86/include/asm/processor-flags.h
@@ -60,6 +60,7 @@
#define X86_CR4_OSXMMEXCPT 0x00000400 /* enable unmasked SSE exceptions */
#define X86_CR4_VMXE 0x00002000 /* enable VMX virtualization */
#define X86_CR4_OSXSAVE 0x00040000 /* enable xsave and xrestore */
+#define X86_CR4_SMEP 0x00100000 /* enable SMEP support */
/*
* x86-64 Task Priority Register, CR8
diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h
index 1babf8adecdf..94e7618fcac8 100644
--- a/arch/x86/include/asm/ptrace.h
+++ b/arch/x86/include/asm/ptrace.h
@@ -136,6 +136,7 @@ struct cpuinfo_x86;
struct task_struct;
extern unsigned long profile_pc(struct pt_regs *regs);
+#define profile_pc profile_pc
extern unsigned long
convert_ip_to_linear(struct task_struct *child, struct pt_regs *regs);
@@ -202,20 +203,11 @@ static inline unsigned long kernel_stack_pointer(struct pt_regs *regs)
#endif
}
-static inline unsigned long instruction_pointer(struct pt_regs *regs)
-{
- return regs->ip;
-}
-
-static inline unsigned long frame_pointer(struct pt_regs *regs)
-{
- return regs->bp;
-}
+#define GET_IP(regs) ((regs)->ip)
+#define GET_FP(regs) ((regs)->bp)
+#define GET_USP(regs) ((regs)->sp)
-static inline unsigned long user_stack_pointer(struct pt_regs *regs)
-{
- return regs->sp;
-}
+#include <asm-generic/ptrace.h>
/* Query offset/name of register from its name/offset */
extern int regs_query_register_offset(const char *name);
diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h
index db8aa19a08a2..9756551ec760 100644
--- a/arch/x86/include/asm/setup.h
+++ b/arch/x86/include/asm/setup.h
@@ -88,7 +88,7 @@ void *extend_brk(size_t size, size_t align);
* executable.)
*/
#define RESERVE_BRK(name,sz) \
- static void __section(.discard.text) __used \
+ static void __section(.discard.text) __used notrace \
__brk_reservation_fn_##name##__(void) { \
asm volatile ( \
".pushsection .brk_reservation,\"aw\",@nobits;" \
@@ -104,10 +104,10 @@ void *extend_brk(size_t size, size_t align);
type *name; \
RESERVE_BRK(name, sizeof(type) * entries)
+extern void probe_roms(void);
#ifdef __i386__
void __init i386_start_kernel(void);
-extern void probe_roms(void);
#else
void __init x86_64_start_kernel(char *real_mode);
diff --git a/arch/x86/include/asm/srat.h b/arch/x86/include/asm/srat.h
deleted file mode 100644
index b508d639d1a7..000000000000
--- a/arch/x86/include/asm/srat.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Some of the code in this file has been gleaned from the 64 bit
- * discontigmem support code base.
- *
- * Copyright (C) 2002, IBM Corp.
- *
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Send feedback to Pat Gaughen <gone@us.ibm.com>
- */
-
-#ifndef _ASM_X86_SRAT_H
-#define _ASM_X86_SRAT_H
-
-#ifdef CONFIG_ACPI_NUMA
-extern int get_memcfg_from_srat(void);
-#else
-static inline int get_memcfg_from_srat(void)
-{
- return 0;
-}
-#endif
-
-#endif /* _ASM_X86_SRAT_H */
diff --git a/arch/x86/include/asm/stacktrace.h b/arch/x86/include/asm/stacktrace.h
index d7e89c83645d..70bbe39043a9 100644
--- a/arch/x86/include/asm/stacktrace.h
+++ b/arch/x86/include/asm/stacktrace.h
@@ -37,9 +37,6 @@ print_context_stack_bp(struct thread_info *tinfo,
/* Generic stack tracer with callbacks */
struct stacktrace_ops {
- void (*warning)(void *data, char *msg);
- /* msg must contain %s for the symbol */
- void (*warning_symbol)(void *data, char *msg, unsigned long symbol);
void (*address)(void *data, unsigned long address, int reliable);
/* On negative return stop dumping */
int (*stack)(void *data, char *name);
diff --git a/arch/x86/include/asm/system.h b/arch/x86/include/asm/system.h
index 12569e691ce3..c2ff2a1d845e 100644
--- a/arch/x86/include/asm/system.h
+++ b/arch/x86/include/asm/system.h
@@ -303,24 +303,81 @@ static inline void native_wbinvd(void)
#ifdef CONFIG_PARAVIRT
#include <asm/paravirt.h>
#else
-#define read_cr0() (native_read_cr0())
-#define write_cr0(x) (native_write_cr0(x))
-#define read_cr2() (native_read_cr2())
-#define write_cr2(x) (native_write_cr2(x))
-#define read_cr3() (native_read_cr3())
-#define write_cr3(x) (native_write_cr3(x))
-#define read_cr4() (native_read_cr4())
-#define read_cr4_safe() (native_read_cr4_safe())
-#define write_cr4(x) (native_write_cr4(x))
-#define wbinvd() (native_wbinvd())
+
+static inline unsigned long read_cr0(void)
+{
+ return native_read_cr0();
+}
+
+static inline void write_cr0(unsigned long x)
+{
+ native_write_cr0(x);
+}
+
+static inline unsigned long read_cr2(void)
+{
+ return native_read_cr2();
+}
+
+static inline void write_cr2(unsigned long x)
+{
+ native_write_cr2(x);
+}
+
+static inline unsigned long read_cr3(void)
+{
+ return native_read_cr3();
+}
+
+static inline void write_cr3(unsigned long x)
+{
+ native_write_cr3(x);
+}
+
+static inline unsigned long read_cr4(void)
+{
+ return native_read_cr4();
+}
+
+static inline unsigned long read_cr4_safe(void)
+{
+ return native_read_cr4_safe();
+}
+
+static inline void write_cr4(unsigned long x)
+{
+ native_write_cr4(x);
+}
+
+static inline void wbinvd(void)
+{
+ native_wbinvd();
+}
+
#ifdef CONFIG_X86_64
-#define read_cr8() (native_read_cr8())
-#define write_cr8(x) (native_write_cr8(x))
-#define load_gs_index native_load_gs_index
+
+static inline unsigned long read_cr8(void)
+{
+ return native_read_cr8();
+}
+
+static inline void write_cr8(unsigned long x)
+{
+ native_write_cr8(x);
+}
+
+static inline void load_gs_index(unsigned selector)
+{
+ native_load_gs_index(selector);
+}
+
#endif
/* Clear the 'TS' bit */
-#define clts() (native_clts())
+static inline void clts(void)
+{
+ native_clts();
+}
#endif/* CONFIG_PARAVIRT */
diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h
index 910a7084f7f2..c00692476e9f 100644
--- a/arch/x86/include/asm/topology.h
+++ b/arch/x86/include/asm/topology.h
@@ -93,19 +93,11 @@ extern void setup_node_to_cpumask_map(void);
#define pcibus_to_node(bus) __pcibus_to_node(bus)
#ifdef CONFIG_X86_32
-extern unsigned long node_start_pfn[];
-extern unsigned long node_end_pfn[];
-extern unsigned long node_remap_size[];
-#define node_has_online_mem(nid) (node_start_pfn[nid] != node_end_pfn[nid])
-
# define SD_CACHE_NICE_TRIES 1
# define SD_IDLE_IDX 1
-
#else
-
# define SD_CACHE_NICE_TRIES 2
# define SD_IDLE_IDX 2
-
#endif
/* sched_domains SD_NODE_INIT for NUMA machines */
diff --git a/arch/x86/include/asm/tsc.h b/arch/x86/include/asm/tsc.h
index 83e2efd181e2..9db5583b6d38 100644
--- a/arch/x86/include/asm/tsc.h
+++ b/arch/x86/include/asm/tsc.h
@@ -51,6 +51,10 @@ extern int unsynchronized_tsc(void);
extern int check_tsc_unstable(void);
extern unsigned long native_calibrate_tsc(void);
+#ifdef CONFIG_X86_64
+extern cycles_t vread_tsc(void);
+#endif
+
/*
* Boot-time check whether the TSCs are synchronized across
* all CPUs/cores:
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index abd3e0ea762a..99ddd148a760 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -6,7 +6,6 @@
#include <linux/errno.h>
#include <linux/compiler.h>
#include <linux/thread_info.h>
-#include <linux/prefetch.h>
#include <linux/string.h>
#include <asm/asm.h>
#include <asm/page.h>
@@ -42,7 +41,7 @@
* Returns 0 if the range is valid, nonzero otherwise.
*
* This is equivalent to the following test:
- * (u33)addr + (u33)size >= (u33)current->addr_limit.seg (u65 for x86_64)
+ * (u33)addr + (u33)size > (u33)current->addr_limit.seg (u65 for x86_64)
*
* This needs 33-bit (65-bit for x86_64) arithmetic. We have a carry...
*/
diff --git a/arch/x86/include/asm/uaccess_32.h b/arch/x86/include/asm/uaccess_32.h
index 088d09fb1615..566e803cc602 100644
--- a/arch/x86/include/asm/uaccess_32.h
+++ b/arch/x86/include/asm/uaccess_32.h
@@ -6,7 +6,6 @@
*/
#include <linux/errno.h>
#include <linux/thread_info.h>
-#include <linux/prefetch.h>
#include <linux/string.h>
#include <asm/asm.h>
#include <asm/page.h>
diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h
index 316708d5af92..1c66d30971ad 100644
--- a/arch/x86/include/asm/uaccess_64.h
+++ b/arch/x86/include/asm/uaccess_64.h
@@ -6,7 +6,6 @@
*/
#include <linux/compiler.h>
#include <linux/errno.h>
-#include <linux/prefetch.h>
#include <linux/lockdep.h>
#include <asm/alternative.h>
#include <asm/cpufeature.h>
diff --git a/arch/x86/include/asm/unistd_32.h b/arch/x86/include/asm/unistd_32.h
index a755ef5e5977..fb6a625c99bf 100644
--- a/arch/x86/include/asm/unistd_32.h
+++ b/arch/x86/include/asm/unistd_32.h
@@ -350,10 +350,11 @@
#define __NR_open_by_handle_at 342
#define __NR_clock_adjtime 343
#define __NR_syncfs 344
+#define __NR_sendmmsg 345
#ifdef __KERNEL__
-#define NR_syscalls 345
+#define NR_syscalls 346
#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR
diff --git a/arch/x86/include/asm/unistd_64.h b/arch/x86/include/asm/unistd_64.h
index 160fa76bd578..79f90eb15aad 100644
--- a/arch/x86/include/asm/unistd_64.h
+++ b/arch/x86/include/asm/unistd_64.h
@@ -677,6 +677,8 @@ __SYSCALL(__NR_open_by_handle_at, sys_open_by_handle_at)
__SYSCALL(__NR_clock_adjtime, sys_clock_adjtime)
#define __NR_syncfs 306
__SYSCALL(__NR_syncfs, sys_syncfs)
+#define __NR_sendmmsg 307
+__SYSCALL(__NR_sendmmsg, sys_sendmmsg)
#ifndef __NO_STUBS
#define __ARCH_WANT_OLD_READDIR
diff --git a/arch/x86/include/asm/vdso.h b/arch/x86/include/asm/vdso.h
index 9064052b73de..bb0522850b74 100644
--- a/arch/x86/include/asm/vdso.h
+++ b/arch/x86/include/asm/vdso.h
@@ -1,20 +1,6 @@
#ifndef _ASM_X86_VDSO_H
#define _ASM_X86_VDSO_H
-#ifdef CONFIG_X86_64
-extern const char VDSO64_PRELINK[];
-
-/*
- * Given a pointer to the vDSO image, find the pointer to VDSO64_name
- * as that symbol is defined in the vDSO sources or linker script.
- */
-#define VDSO64_SYMBOL(base, name) \
-({ \
- extern const char VDSO64_##name[]; \
- (void *)(VDSO64_##name - VDSO64_PRELINK + (unsigned long)(base)); \
-})
-#endif
-
#if defined CONFIG_X86_32 || defined CONFIG_COMPAT
extern const char VDSO32_PRELINK[];
diff --git a/arch/x86/include/asm/vgtod.h b/arch/x86/include/asm/vgtod.h
index 3d61e204826f..646b4c1ca695 100644
--- a/arch/x86/include/asm/vgtod.h
+++ b/arch/x86/include/asm/vgtod.h
@@ -23,8 +23,6 @@ struct vsyscall_gtod_data {
struct timespec wall_to_monotonic;
struct timespec wall_time_coarse;
};
-extern struct vsyscall_gtod_data __vsyscall_gtod_data
-__section_vsyscall_gtod_data;
extern struct vsyscall_gtod_data vsyscall_gtod_data;
#endif /* _ASM_X86_VGTOD_H */
diff --git a/arch/x86/include/asm/vsyscall.h b/arch/x86/include/asm/vsyscall.h
index d0983d255fbd..d55597351f6a 100644
--- a/arch/x86/include/asm/vsyscall.h
+++ b/arch/x86/include/asm/vsyscall.h
@@ -16,27 +16,19 @@ enum vsyscall_num {
#ifdef __KERNEL__
#include <linux/seqlock.h>
-#define __section_vgetcpu_mode __attribute__ ((unused, __section__ (".vgetcpu_mode"), aligned(16)))
-#define __section_jiffies __attribute__ ((unused, __section__ (".jiffies"), aligned(16)))
-
/* Definitions for CONFIG_GENERIC_TIME definitions */
-#define __section_vsyscall_gtod_data __attribute__ \
- ((unused, __section__ (".vsyscall_gtod_data"),aligned(16)))
-#define __section_vsyscall_clock __attribute__ \
- ((unused, __section__ (".vsyscall_clock"),aligned(16)))
#define __vsyscall_fn \
__attribute__ ((unused, __section__(".vsyscall_fn"))) notrace
#define VGETCPU_RDTSCP 1
#define VGETCPU_LSL 2
-extern int __vgetcpu_mode;
-extern volatile unsigned long __jiffies;
-
/* kernel space (writeable) */
extern int vgetcpu_mode;
extern struct timezone sys_tz;
+#include <asm/vvar.h>
+
extern void map_vsyscall(void);
#endif /* __KERNEL__ */
diff --git a/arch/x86/include/asm/vvar.h b/arch/x86/include/asm/vvar.h
new file mode 100644
index 000000000000..341b3559452b
--- /dev/null
+++ b/arch/x86/include/asm/vvar.h
@@ -0,0 +1,52 @@
+/*
+ * vvar.h: Shared vDSO/kernel variable declarations
+ * Copyright (c) 2011 Andy Lutomirski
+ * Subject to the GNU General Public License, version 2
+ *
+ * A handful of variables are accessible (read-only) from userspace
+ * code in the vsyscall page and the vdso. They are declared here.
+ * Some other file must define them with DEFINE_VVAR.
+ *
+ * In normal kernel code, they are used like any other variable.
+ * In user code, they are accessed through the VVAR macro.
+ *
+ * Each of these variables lives in the vsyscall page, and each
+ * one needs a unique offset within the little piece of the page
+ * reserved for vvars. Specify that offset in DECLARE_VVAR.
+ * (There are 896 bytes available. If you mess up, the linker will
+ * catch it.)
+ */
+
+/* Offset of vars within vsyscall page */
+#define VSYSCALL_VARS_OFFSET (3072 + 128)
+
+#if defined(__VVAR_KERNEL_LDS)
+
+/* The kernel linker script defines its own magic to put vvars in the
+ * right place.
+ */
+#define DECLARE_VVAR(offset, type, name) \
+ EMIT_VVAR(name, VSYSCALL_VARS_OFFSET + offset)
+
+#else
+
+#define DECLARE_VVAR(offset, type, name) \
+ static type const * const vvaraddr_ ## name = \
+ (void *)(VSYSCALL_START + VSYSCALL_VARS_OFFSET + (offset));
+
+#define DEFINE_VVAR(type, name) \
+ type __vvar_ ## name \
+ __attribute__((section(".vsyscall_var_" #name), aligned(16)))
+
+#define VVAR(name) (*vvaraddr_ ## name)
+
+#endif
+
+/* DECLARE_VVAR(offset, type, name) */
+
+DECLARE_VVAR(0, volatile unsigned long, jiffies)
+DECLARE_VVAR(8, int, vgetcpu_mode)
+DECLARE_VVAR(128, struct vsyscall_gtod_data, vsyscall_gtod_data)
+
+#undef DECLARE_VVAR
+#undef VSYSCALL_VARS_OFFSET
diff --git a/arch/x86/include/asm/x2apic.h b/arch/x86/include/asm/x2apic.h
new file mode 100644
index 000000000000..6bf5b8e478c0
--- /dev/null
+++ b/arch/x86/include/asm/x2apic.h
@@ -0,0 +1,62 @@
+/*
+ * Common bits for X2APIC cluster/physical modes.
+ */
+
+#ifndef _ASM_X86_X2APIC_H
+#define _ASM_X86_X2APIC_H
+
+#include <asm/apic.h>
+#include <asm/ipi.h>
+#include <linux/cpumask.h>
+
+/*
+ * Need to use more than cpu 0, because we need more vectors
+ * when MSI-X are used.
+ */
+static const struct cpumask *x2apic_target_cpus(void)
+{
+ return cpu_online_mask;
+}
+
+static int x2apic_apic_id_registered(void)
+{
+ return 1;
+}
+
+/*
+ * For now each logical cpu is in its own vector allocation domain.
+ */
+static void x2apic_vector_allocation_domain(int cpu, struct cpumask *retmask)
+{
+ cpumask_clear(retmask);
+ cpumask_set_cpu(cpu, retmask);
+}
+
+static void
+__x2apic_send_IPI_dest(unsigned int apicid, int vector, unsigned int dest)
+{
+ unsigned long cfg = __prepare_ICR(0, vector, dest);
+ native_x2apic_icr_write(cfg, apicid);
+}
+
+static unsigned int x2apic_get_apic_id(unsigned long id)
+{
+ return id;
+}
+
+static unsigned long x2apic_set_apic_id(unsigned int id)
+{
+ return id;
+}
+
+static int x2apic_phys_pkg_id(int initial_apicid, int index_msb)
+{
+ return initial_apicid >> index_msb;
+}
+
+static void x2apic_send_IPI_self(int vector)
+{
+ apic_write(APIC_SELF_IPI, vector);
+}
+
+#endif /* _ASM_X86_X2APIC_H */
diff --git a/arch/x86/include/asm/xen/hypercall.h b/arch/x86/include/asm/xen/hypercall.h
index 8508bfe52296..d240ea950519 100644
--- a/arch/x86/include/asm/xen/hypercall.h
+++ b/arch/x86/include/asm/xen/hypercall.h
@@ -447,6 +447,13 @@ HYPERVISOR_hvm_op(int op, void *arg)
return _hypercall2(unsigned long, hvm_op, op, arg);
}
+static inline int
+HYPERVISOR_tmem_op(
+ struct tmem_op *op)
+{
+ return _hypercall1(int, tmem_op, op);
+}
+
static inline void
MULTI_fpu_taskswitch(struct multicall_entry *mcl, int set)
{
diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h
index c61934fbf22a..64a619d47d34 100644
--- a/arch/x86/include/asm/xen/page.h
+++ b/arch/x86/include/asm/xen/page.h
@@ -47,8 +47,9 @@ extern bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn);
extern unsigned long set_phys_range_identity(unsigned long pfn_s,
unsigned long pfn_e);
-extern int m2p_add_override(unsigned long mfn, struct page *page);
-extern int m2p_remove_override(struct page *page);
+extern int m2p_add_override(unsigned long mfn, struct page *page,
+ bool clear_pte);
+extern int m2p_remove_override(struct page *page, bool clear_pte);
extern struct page *m2p_find_override(unsigned long mfn);
extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn);
diff --git a/arch/x86/include/asm/xen/pci.h b/arch/x86/include/asm/xen/pci.h
index aa8620989162..4fbda9a3f339 100644
--- a/arch/x86/include/asm/xen/pci.h
+++ b/arch/x86/include/asm/xen/pci.h
@@ -15,10 +15,26 @@ static inline int pci_xen_hvm_init(void)
#endif
#if defined(CONFIG_XEN_DOM0)
void __init xen_setup_pirqs(void);
+int xen_find_device_domain_owner(struct pci_dev *dev);
+int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain);
+int xen_unregister_device_domain_owner(struct pci_dev *dev);
#else
static inline void __init xen_setup_pirqs(void)
{
}
+static inline int xen_find_device_domain_owner(struct pci_dev *dev)
+{
+ return -1;
+}
+static inline int xen_register_device_domain_owner(struct pci_dev *dev,
+ uint16_t domain)
+{
+ return -1;
+}
+static inline int xen_unregister_device_domain_owner(struct pci_dev *dev)
+{
+ return -1;
+}
#endif
#if defined(CONFIG_PCI_MSI)
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 7338ef2218bc..f5abe3a245b8 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -8,7 +8,6 @@ CPPFLAGS_vmlinux.lds += -U$(UTS_MACHINE)
ifdef CONFIG_FUNCTION_TRACER
# Do not profile debug and lowlevel utilities
-CFLAGS_REMOVE_tsc.o = -pg
CFLAGS_REMOVE_rtc.o = -pg
CFLAGS_REMOVE_paravirt-spinlocks.o = -pg
CFLAGS_REMOVE_pvclock.o = -pg
@@ -24,22 +23,25 @@ endif
nostackp := $(call cc-option, -fno-stack-protector)
CFLAGS_vsyscall_64.o := $(PROFILING) -g0 $(nostackp)
CFLAGS_hpet.o := $(nostackp)
-CFLAGS_tsc.o := $(nostackp)
+CFLAGS_vread_tsc_64.o := $(nostackp)
CFLAGS_paravirt.o := $(nostackp)
GCOV_PROFILE_vsyscall_64.o := n
GCOV_PROFILE_hpet.o := n
GCOV_PROFILE_tsc.o := n
GCOV_PROFILE_paravirt.o := n
+# vread_tsc_64 is hot and should be fully optimized:
+CFLAGS_REMOVE_vread_tsc_64.o = -pg -fno-optimize-sibling-calls
+
obj-y := process_$(BITS).o signal.o entry_$(BITS).o
obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o
obj-y += time.o ioport.o ldt.o dumpstack.o
obj-y += setup.o x86_init.o i8259.o irqinit.o jump_label.o
obj-$(CONFIG_IRQ_WORK) += irq_work.o
-obj-$(CONFIG_X86_32) += probe_roms_32.o
+obj-y += probe_roms.o
obj-$(CONFIG_X86_32) += sys_i386_32.o i386_ksyms_32.o
obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o
-obj-$(CONFIG_X86_64) += syscall_64.o vsyscall_64.o
+obj-$(CONFIG_X86_64) += syscall_64.o vsyscall_64.o vread_tsc_64.o
obj-y += bootflag.o e820.o
obj-y += pci-dma.o quirks.o topology.o kdebugfs.o
obj-y += alternative.o i8253.o pci-nommu.o hw_breakpoint.o
@@ -117,7 +119,7 @@ obj-$(CONFIG_OF) += devicetree.o
ifeq ($(CONFIG_X86_64),y)
obj-$(CONFIG_AUDIT) += audit_64.o
- obj-$(CONFIG_GART_IOMMU) += pci-gart_64.o aperture_64.o
+ obj-$(CONFIG_GART_IOMMU) += amd_gart_64.o aperture_64.o
obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary_64.o tce_64.o
obj-$(CONFIG_AMD_IOMMU) += amd_iommu_init.o amd_iommu.o
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index 9a966c579af5..4558f0d0822d 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -970,7 +970,7 @@ void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi)
mp_irq.irqflag = (trigger << 2) | polarity;
mp_irq.srcbus = MP_ISA_BUS;
mp_irq.srcbusirq = bus_irq; /* IRQ */
- mp_irq.dstapic = mp_ioapics[ioapic].apicid; /* APIC ID */
+ mp_irq.dstapic = mpc_ioapic_id(ioapic); /* APIC ID */
mp_irq.dstirq = pin; /* INTIN# */
mp_save_irq(&mp_irq);
@@ -1021,7 +1021,7 @@ void __init mp_config_acpi_legacy_irqs(void)
if (ioapic < 0)
continue;
pin = mp_find_ioapic_pin(ioapic, gsi);
- dstapic = mp_ioapics[ioapic].apicid;
+ dstapic = mpc_ioapic_id(ioapic);
for (idx = 0; idx < mp_irq_entries; idx++) {
struct mpc_intsrc *irq = mp_irqs + idx;
@@ -1082,7 +1082,7 @@ static int mp_config_acpi_gsi(struct device *dev, u32 gsi, int trigger,
mp_irq.srcbus = number;
mp_irq.srcbusirq = (((devfn >> 3) & 0x1f) << 2) | ((pin - 1) & 3);
ioapic = mp_find_ioapic(gsi);
- mp_irq.dstapic = mp_ioapics[ioapic].apicid;
+ mp_irq.dstapic = mpc_ioapic_id(ioapic);
mp_irq.dstirq = mp_find_ioapic_pin(ioapic, gsi);
mp_save_irq(&mp_irq);
@@ -1113,7 +1113,7 @@ int mp_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
if (ioapic_pin > MP_MAX_IOAPIC_PIN) {
printk(KERN_ERR "Invalid reference to IOAPIC pin "
- "%d-%d\n", mp_ioapics[ioapic].apicid,
+ "%d-%d\n", mpc_ioapic_id(ioapic),
ioapic_pin);
return gsi;
}
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c
index ff93bc1b09c3..18a857ba7a25 100644
--- a/arch/x86/kernel/acpi/sleep.c
+++ b/arch/x86/kernel/acpi/sleep.c
@@ -112,11 +112,6 @@ static int __init acpi_sleep_setup(char *str)
#ifdef CONFIG_HIBERNATION
if (strncmp(str, "s4_nohwsig", 10) == 0)
acpi_no_s4_hw_signature();
- if (strncmp(str, "s4_nonvs", 8) == 0) {
- pr_warning("ACPI: acpi_sleep=s4_nonvs is deprecated, "
- "please use acpi_sleep=nonvs instead");
- acpi_nvs_nosave();
- }
#endif
if (strncmp(str, "nonvs", 5) == 0)
acpi_nvs_nosave();
diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 4a234677e213..a81f2d52f869 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -67,17 +67,30 @@ __setup("noreplace-paravirt", setup_noreplace_paravirt);
#define DPRINTK(fmt, args...) if (debug_alternative) \
printk(KERN_DEBUG fmt, args)
+/*
+ * Each GENERIC_NOPX is of X bytes, and defined as an array of bytes
+ * that correspond to that nop. Getting from one nop to the next, we
+ * add to the array the offset that is equal to the sum of all sizes of
+ * nops preceding the one we are after.
+ *
+ * Note: The GENERIC_NOP5_ATOMIC is at the end, as it breaks the
+ * nice symmetry of sizes of the previous nops.
+ */
#if defined(GENERIC_NOP1) && !defined(CONFIG_X86_64)
-/* Use inline assembly to define this because the nops are defined
- as inline assembly strings in the include files and we cannot
- get them easily into strings. */
-asm("\t" __stringify(__INITRODATA_OR_MODULE) "\nintelnops: "
- GENERIC_NOP1 GENERIC_NOP2 GENERIC_NOP3 GENERIC_NOP4 GENERIC_NOP5 GENERIC_NOP6
- GENERIC_NOP7 GENERIC_NOP8
- "\t.previous");
-extern const unsigned char intelnops[];
-static const unsigned char *const __initconst_or_module
-intel_nops[ASM_NOP_MAX+1] = {
+static const unsigned char intelnops[] =
+{
+ GENERIC_NOP1,
+ GENERIC_NOP2,
+ GENERIC_NOP3,
+ GENERIC_NOP4,
+ GENERIC_NOP5,
+ GENERIC_NOP6,
+ GENERIC_NOP7,
+ GENERIC_NOP8,
+ GENERIC_NOP5_ATOMIC
+};
+static const unsigned char * const intel_nops[ASM_NOP_MAX+2] =
+{
NULL,
intelnops,
intelnops + 1,
@@ -87,17 +100,25 @@ intel_nops[ASM_NOP_MAX+1] = {
intelnops + 1 + 2 + 3 + 4 + 5,
intelnops + 1 + 2 + 3 + 4 + 5 + 6,
intelnops + 1 + 2 + 3 + 4 + 5 + 6 + 7,
+ intelnops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8,
};
#endif
#ifdef K8_NOP1
-asm("\t" __stringify(__INITRODATA_OR_MODULE) "\nk8nops: "
- K8_NOP1 K8_NOP2 K8_NOP3 K8_NOP4 K8_NOP5 K8_NOP6
- K8_NOP7 K8_NOP8
- "\t.previous");
-extern const unsigned char k8nops[];
-static const unsigned char *const __initconst_or_module
-k8_nops[ASM_NOP_MAX+1] = {
+static const unsigned char k8nops[] =
+{
+ K8_NOP1,
+ K8_NOP2,
+ K8_NOP3,
+ K8_NOP4,
+ K8_NOP5,
+ K8_NOP6,
+ K8_NOP7,
+ K8_NOP8,
+ K8_NOP5_ATOMIC
+};
+static const unsigned char * const k8_nops[ASM_NOP_MAX+2] =
+{
NULL,
k8nops,
k8nops + 1,
@@ -107,17 +128,25 @@ k8_nops[ASM_NOP_MAX+1] = {
k8nops + 1 + 2 + 3 + 4 + 5,
k8nops + 1 + 2 + 3 + 4 + 5 + 6,
k8nops + 1 + 2 + 3 + 4 + 5 + 6 + 7,
+ k8nops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8,
};
#endif
#if defined(K7_NOP1) && !defined(CONFIG_X86_64)
-asm("\t" __stringify(__INITRODATA_OR_MODULE) "\nk7nops: "
- K7_NOP1 K7_NOP2 K7_NOP3 K7_NOP4 K7_NOP5 K7_NOP6
- K7_NOP7 K7_NOP8
- "\t.previous");
-extern const unsigned char k7nops[];
-static const unsigned char *const __initconst_or_module
-k7_nops[ASM_NOP_MAX+1] = {
+static const unsigned char k7nops[] =
+{
+ K7_NOP1,
+ K7_NOP2,
+ K7_NOP3,
+ K7_NOP4,
+ K7_NOP5,
+ K7_NOP6,
+ K7_NOP7,
+ K7_NOP8,
+ K7_NOP5_ATOMIC
+};
+static const unsigned char * const k7_nops[ASM_NOP_MAX+2] =
+{
NULL,
k7nops,
k7nops + 1,
@@ -127,17 +156,25 @@ k7_nops[ASM_NOP_MAX+1] = {
k7nops + 1 + 2 + 3 + 4 + 5,
k7nops + 1 + 2 + 3 + 4 + 5 + 6,
k7nops + 1 + 2 + 3 + 4 + 5 + 6 + 7,
+ k7nops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8,
};
#endif
#ifdef P6_NOP1
-asm("\t" __stringify(__INITRODATA_OR_MODULE) "\np6nops: "
- P6_NOP1 P6_NOP2 P6_NOP3 P6_NOP4 P6_NOP5 P6_NOP6
- P6_NOP7 P6_NOP8
- "\t.previous");
-extern const unsigned char p6nops[];
-static const unsigned char *const __initconst_or_module
-p6_nops[ASM_NOP_MAX+1] = {
+static const unsigned char __initconst_or_module p6nops[] =
+{
+ P6_NOP1,
+ P6_NOP2,
+ P6_NOP3,
+ P6_NOP4,
+ P6_NOP5,
+ P6_NOP6,
+ P6_NOP7,
+ P6_NOP8,
+ P6_NOP5_ATOMIC
+};
+static const unsigned char * const p6_nops[ASM_NOP_MAX+2] =
+{
NULL,
p6nops,
p6nops + 1,
@@ -147,47 +184,65 @@ p6_nops[ASM_NOP_MAX+1] = {
p6nops + 1 + 2 + 3 + 4 + 5,
p6nops + 1 + 2 + 3 + 4 + 5 + 6,
p6nops + 1 + 2 + 3 + 4 + 5 + 6 + 7,
+ p6nops + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8,
};
#endif
+/* Initialize these to a safe default */
#ifdef CONFIG_X86_64
+const unsigned char * const *ideal_nops = p6_nops;
+#else
+const unsigned char * const *ideal_nops = intel_nops;
+#endif
-extern char __vsyscall_0;
-static const unsigned char *const *__init_or_module find_nop_table(void)
+void __init arch_init_ideal_nops(void)
{
- if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
- boot_cpu_has(X86_FEATURE_NOPL))
- return p6_nops;
- else
- return k8_nops;
-}
-
-#else /* CONFIG_X86_64 */
+ switch (boot_cpu_data.x86_vendor) {
+ case X86_VENDOR_INTEL:
+ /*
+ * Due to a decoder implementation quirk, some
+ * specific Intel CPUs actually perform better with
+ * the "k8_nops" than with the SDM-recommended NOPs.
+ */
+ if (boot_cpu_data.x86 == 6 &&
+ boot_cpu_data.x86_model >= 0x0f &&
+ boot_cpu_data.x86_model != 0x1c &&
+ boot_cpu_data.x86_model != 0x26 &&
+ boot_cpu_data.x86_model != 0x27 &&
+ boot_cpu_data.x86_model < 0x30) {
+ ideal_nops = k8_nops;
+ } else if (boot_cpu_has(X86_FEATURE_NOPL)) {
+ ideal_nops = p6_nops;
+ } else {
+#ifdef CONFIG_X86_64
+ ideal_nops = k8_nops;
+#else
+ ideal_nops = intel_nops;
+#endif
+ }
-static const unsigned char *const *__init_or_module find_nop_table(void)
-{
- if (boot_cpu_has(X86_FEATURE_K8))
- return k8_nops;
- else if (boot_cpu_has(X86_FEATURE_K7))
- return k7_nops;
- else if (boot_cpu_has(X86_FEATURE_NOPL))
- return p6_nops;
- else
- return intel_nops;
+ default:
+#ifdef CONFIG_X86_64
+ ideal_nops = k8_nops;
+#else
+ if (boot_cpu_has(X86_FEATURE_K8))
+ ideal_nops = k8_nops;
+ else if (boot_cpu_has(X86_FEATURE_K7))
+ ideal_nops = k7_nops;
+ else
+ ideal_nops = intel_nops;
+#endif
+ }
}
-#endif /* CONFIG_X86_64 */
-
/* Use this to add nops to a buffer, then text_poke the whole buffer. */
static void __init_or_module add_nops(void *insns, unsigned int len)
{
- const unsigned char *const *noptable = find_nop_table();
-
while (len > 0) {
unsigned int noplen = len;
if (noplen > ASM_NOP_MAX)
noplen = ASM_NOP_MAX;
- memcpy(insns, noptable[noplen], noplen);
+ memcpy(insns, ideal_nops[noplen], noplen);
insns += noplen;
len -= noplen;
}
@@ -195,6 +250,7 @@ static void __init_or_module add_nops(void *insns, unsigned int len)
extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
extern s32 __smp_locks[], __smp_locks_end[];
+extern char __vsyscall_0;
void *text_poke_early(void *addr, const void *opcode, size_t len);
/* Replace instructions with better alternatives for this CPU type.
@@ -210,6 +266,15 @@ void __init_or_module apply_alternatives(struct alt_instr *start,
u8 insnbuf[MAX_PATCH_LEN];
DPRINTK("%s: alt table %p -> %p\n", __func__, start, end);
+ /*
+ * The scan order should be from start to end. A later scanned
+ * alternative code can overwrite a previous scanned alternative code.
+ * Some kernel functions (e.g. memcpy, memset, etc) use this order to
+ * patch code.
+ *
+ * So be careful if you want to change the scan order to any other
+ * order.
+ */
for (a = start; a < end; a++) {
u8 *instr = a->instr;
BUG_ON(a->replacementlen > a->instrlen);
@@ -678,29 +743,3 @@ void __kprobes text_poke_smp_batch(struct text_poke_param *params, int n)
wrote_text = 0;
__stop_machine(stop_machine_text_poke, (void *)&tpp, NULL);
}
-
-#if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL)
-
-#ifdef CONFIG_X86_64
-unsigned char ideal_nop5[5] = { 0x66, 0x66, 0x66, 0x66, 0x90 };
-#else
-unsigned char ideal_nop5[5] = { 0x3e, 0x8d, 0x74, 0x26, 0x00 };
-#endif
-
-void __init arch_init_ideal_nop5(void)
-{
- /*
- * There is no good nop for all x86 archs. This selection
- * algorithm should be unified with the one in find_nop_table(),
- * but this should be good enough for now.
- *
- * For cases other than the ones below, use the safe (as in
- * always functional) defaults above.
- */
-#ifdef CONFIG_X86_64
- /* Don't use these on 32 bits due to broken virtualizers */
- if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
- memcpy(ideal_nop5, p6_nops[5], 5);
-#endif
-}
-#endif
diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/amd_gart_64.c
index b117efd24f71..b117efd24f71 100644
--- a/arch/x86/kernel/pci-gart_64.c
+++ b/arch/x86/kernel/amd_gart_64.c
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index 57ca77787220..cd8cbeb5fa34 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -18,6 +18,7 @@
*/
#include <linux/pci.h>
+#include <linux/pci-ats.h>
#include <linux/bitmap.h>
#include <linux/slab.h>
#include <linux/debugfs.h>
@@ -25,6 +26,7 @@
#include <linux/dma-mapping.h>
#include <linux/iommu-helper.h>
#include <linux/iommu.h>
+#include <linux/delay.h>
#include <asm/proto.h>
#include <asm/iommu.h>
#include <asm/gart.h>
@@ -34,7 +36,7 @@
#define CMD_SET_TYPE(cmd, t) ((cmd)->data[1] |= ((t) << 28))
-#define EXIT_LOOP_COUNT 10000000
+#define LOOP_TIMEOUT 100000
static DEFINE_RWLOCK(amd_iommu_devtable_lock);
@@ -57,7 +59,6 @@ struct iommu_cmd {
u32 data[4];
};
-static void reset_iommu_command_buffer(struct amd_iommu *iommu);
static void update_domain(struct protection_domain *domain);
/****************************************************************************
@@ -322,8 +323,6 @@ static void iommu_print_event(struct amd_iommu *iommu, void *__evt)
break;
case EVENT_TYPE_ILL_CMD:
printk("ILLEGAL_COMMAND_ERROR address=0x%016llx]\n", address);
- iommu->reset_in_progress = true;
- reset_iommu_command_buffer(iommu);
dump_command(address);
break;
case EVENT_TYPE_CMD_HARD_ERR:
@@ -367,7 +366,7 @@ static void iommu_poll_events(struct amd_iommu *iommu)
spin_unlock_irqrestore(&iommu->lock, flags);
}
-irqreturn_t amd_iommu_int_handler(int irq, void *data)
+irqreturn_t amd_iommu_int_thread(int irq, void *data)
{
struct amd_iommu *iommu;
@@ -377,192 +376,300 @@ irqreturn_t amd_iommu_int_handler(int irq, void *data)
return IRQ_HANDLED;
}
+irqreturn_t amd_iommu_int_handler(int irq, void *data)
+{
+ return IRQ_WAKE_THREAD;
+}
+
/****************************************************************************
*
* IOMMU command queuing functions
*
****************************************************************************/
-/*
- * Writes the command to the IOMMUs command buffer and informs the
- * hardware about the new command. Must be called with iommu->lock held.
- */
-static int __iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd)
+static int wait_on_sem(volatile u64 *sem)
+{
+ int i = 0;
+
+ while (*sem == 0 && i < LOOP_TIMEOUT) {
+ udelay(1);
+ i += 1;
+ }
+
+ if (i == LOOP_TIMEOUT) {
+ pr_alert("AMD-Vi: Completion-Wait loop timed out\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void copy_cmd_to_buffer(struct amd_iommu *iommu,
+ struct iommu_cmd *cmd,
+ u32 tail)
{
- u32 tail, head;
u8 *target;
- WARN_ON(iommu->cmd_buf_size & CMD_BUFFER_UNINITIALIZED);
- tail = readl(iommu->mmio_base + MMIO_CMD_TAIL_OFFSET);
target = iommu->cmd_buf + tail;
- memcpy_toio(target, cmd, sizeof(*cmd));
- tail = (tail + sizeof(*cmd)) % iommu->cmd_buf_size;
- head = readl(iommu->mmio_base + MMIO_CMD_HEAD_OFFSET);
- if (tail == head)
- return -ENOMEM;
+ tail = (tail + sizeof(*cmd)) % iommu->cmd_buf_size;
+
+ /* Copy command to buffer */
+ memcpy(target, cmd, sizeof(*cmd));
+
+ /* Tell the IOMMU about it */
writel(tail, iommu->mmio_base + MMIO_CMD_TAIL_OFFSET);
+}
- return 0;
+static void build_completion_wait(struct iommu_cmd *cmd, u64 address)
+{
+ WARN_ON(address & 0x7ULL);
+
+ memset(cmd, 0, sizeof(*cmd));
+ cmd->data[0] = lower_32_bits(__pa(address)) | CMD_COMPL_WAIT_STORE_MASK;
+ cmd->data[1] = upper_32_bits(__pa(address));
+ cmd->data[2] = 1;
+ CMD_SET_TYPE(cmd, CMD_COMPL_WAIT);
+}
+
+static void build_inv_dte(struct iommu_cmd *cmd, u16 devid)
+{
+ memset(cmd, 0, sizeof(*cmd));
+ cmd->data[0] = devid;
+ CMD_SET_TYPE(cmd, CMD_INV_DEV_ENTRY);
+}
+
+static void build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address,
+ size_t size, u16 domid, int pde)
+{
+ u64 pages;
+ int s;
+
+ pages = iommu_num_pages(address, size, PAGE_SIZE);
+ s = 0;
+
+ if (pages > 1) {
+ /*
+ * If we have to flush more than one page, flush all
+ * TLB entries for this domain
+ */
+ address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS;
+ s = 1;
+ }
+
+ address &= PAGE_MASK;
+
+ memset(cmd, 0, sizeof(*cmd));
+ cmd->data[1] |= domid;
+ cmd->data[2] = lower_32_bits(address);
+ cmd->data[3] = upper_32_bits(address);
+ CMD_SET_TYPE(cmd, CMD_INV_IOMMU_PAGES);
+ if (s) /* size bit - we flush more than one 4kb page */
+ cmd->data[2] |= CMD_INV_IOMMU_PAGES_SIZE_MASK;
+ if (pde) /* PDE bit - we wan't flush everything not only the PTEs */
+ cmd->data[2] |= CMD_INV_IOMMU_PAGES_PDE_MASK;
+}
+
+static void build_inv_iotlb_pages(struct iommu_cmd *cmd, u16 devid, int qdep,
+ u64 address, size_t size)
+{
+ u64 pages;
+ int s;
+
+ pages = iommu_num_pages(address, size, PAGE_SIZE);
+ s = 0;
+
+ if (pages > 1) {
+ /*
+ * If we have to flush more than one page, flush all
+ * TLB entries for this domain
+ */
+ address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS;
+ s = 1;
+ }
+
+ address &= PAGE_MASK;
+
+ memset(cmd, 0, sizeof(*cmd));
+ cmd->data[0] = devid;
+ cmd->data[0] |= (qdep & 0xff) << 24;
+ cmd->data[1] = devid;
+ cmd->data[2] = lower_32_bits(address);
+ cmd->data[3] = upper_32_bits(address);
+ CMD_SET_TYPE(cmd, CMD_INV_IOTLB_PAGES);
+ if (s)
+ cmd->data[2] |= CMD_INV_IOMMU_PAGES_SIZE_MASK;
+}
+
+static void build_inv_all(struct iommu_cmd *cmd)
+{
+ memset(cmd, 0, sizeof(*cmd));
+ CMD_SET_TYPE(cmd, CMD_INV_ALL);
}
/*
- * General queuing function for commands. Takes iommu->lock and calls
- * __iommu_queue_command().
+ * Writes the command to the IOMMUs command buffer and informs the
+ * hardware about the new command.
*/
static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd)
{
+ u32 left, tail, head, next_tail;
unsigned long flags;
- int ret;
+ WARN_ON(iommu->cmd_buf_size & CMD_BUFFER_UNINITIALIZED);
+
+again:
spin_lock_irqsave(&iommu->lock, flags);
- ret = __iommu_queue_command(iommu, cmd);
- if (!ret)
- iommu->need_sync = true;
- spin_unlock_irqrestore(&iommu->lock, flags);
- return ret;
-}
+ head = readl(iommu->mmio_base + MMIO_CMD_HEAD_OFFSET);
+ tail = readl(iommu->mmio_base + MMIO_CMD_TAIL_OFFSET);
+ next_tail = (tail + sizeof(*cmd)) % iommu->cmd_buf_size;
+ left = (head - next_tail) % iommu->cmd_buf_size;
-/*
- * This function waits until an IOMMU has completed a completion
- * wait command
- */
-static void __iommu_wait_for_completion(struct amd_iommu *iommu)
-{
- int ready = 0;
- unsigned status = 0;
- unsigned long i = 0;
+ if (left <= 2) {
+ struct iommu_cmd sync_cmd;
+ volatile u64 sem = 0;
+ int ret;
+
+ build_completion_wait(&sync_cmd, (u64)&sem);
+ copy_cmd_to_buffer(iommu, &sync_cmd, tail);
- INC_STATS_COUNTER(compl_wait);
+ spin_unlock_irqrestore(&iommu->lock, flags);
+
+ if ((ret = wait_on_sem(&sem)) != 0)
+ return ret;
- while (!ready && (i < EXIT_LOOP_COUNT)) {
- ++i;
- /* wait for the bit to become one */
- status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
- ready = status & MMIO_STATUS_COM_WAIT_INT_MASK;
+ goto again;
}
- /* set bit back to zero */
- status &= ~MMIO_STATUS_COM_WAIT_INT_MASK;
- writel(status, iommu->mmio_base + MMIO_STATUS_OFFSET);
+ copy_cmd_to_buffer(iommu, cmd, tail);
+
+ /* We need to sync now to make sure all commands are processed */
+ iommu->need_sync = true;
+
+ spin_unlock_irqrestore(&iommu->lock, flags);
- if (unlikely(i == EXIT_LOOP_COUNT))
- iommu->reset_in_progress = true;
+ return 0;
}
/*
* This function queues a completion wait command into the command
* buffer of an IOMMU
*/
-static int __iommu_completion_wait(struct amd_iommu *iommu)
+static int iommu_completion_wait(struct amd_iommu *iommu)
{
struct iommu_cmd cmd;
+ volatile u64 sem = 0;
+ int ret;
+
+ if (!iommu->need_sync)
+ return 0;
- memset(&cmd, 0, sizeof(cmd));
- cmd.data[0] = CMD_COMPL_WAIT_INT_MASK;
- CMD_SET_TYPE(&cmd, CMD_COMPL_WAIT);
+ build_completion_wait(&cmd, (u64)&sem);
- return __iommu_queue_command(iommu, &cmd);
+ ret = iommu_queue_command(iommu, &cmd);
+ if (ret)
+ return ret;
+
+ return wait_on_sem(&sem);
}
-/*
- * This function is called whenever we need to ensure that the IOMMU has
- * completed execution of all commands we sent. It sends a
- * COMPLETION_WAIT command and waits for it to finish. The IOMMU informs
- * us about that by writing a value to a physical address we pass with
- * the command.
- */
-static int iommu_completion_wait(struct amd_iommu *iommu)
+static int iommu_flush_dte(struct amd_iommu *iommu, u16 devid)
{
- int ret = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&iommu->lock, flags);
+ struct iommu_cmd cmd;
- if (!iommu->need_sync)
- goto out;
+ build_inv_dte(&cmd, devid);
- ret = __iommu_completion_wait(iommu);
+ return iommu_queue_command(iommu, &cmd);
+}
- iommu->need_sync = false;
+static void iommu_flush_dte_all(struct amd_iommu *iommu)
+{
+ u32 devid;
- if (ret)
- goto out;
+ for (devid = 0; devid <= 0xffff; ++devid)
+ iommu_flush_dte(iommu, devid);
- __iommu_wait_for_completion(iommu);
+ iommu_completion_wait(iommu);
+}
-out:
- spin_unlock_irqrestore(&iommu->lock, flags);
+/*
+ * This function uses heavy locking and may disable irqs for some time. But
+ * this is no issue because it is only called during resume.
+ */
+static void iommu_flush_tlb_all(struct amd_iommu *iommu)
+{
+ u32 dom_id;
- if (iommu->reset_in_progress)
- reset_iommu_command_buffer(iommu);
+ for (dom_id = 0; dom_id <= 0xffff; ++dom_id) {
+ struct iommu_cmd cmd;
+ build_inv_iommu_pages(&cmd, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS,
+ dom_id, 1);
+ iommu_queue_command(iommu, &cmd);
+ }
- return 0;
+ iommu_completion_wait(iommu);
}
-static void iommu_flush_complete(struct protection_domain *domain)
+static void iommu_flush_all(struct amd_iommu *iommu)
{
- int i;
+ struct iommu_cmd cmd;
- for (i = 0; i < amd_iommus_present; ++i) {
- if (!domain->dev_iommu[i])
- continue;
+ build_inv_all(&cmd);
- /*
- * Devices of this domain are behind this IOMMU
- * We need to wait for completion of all commands.
- */
- iommu_completion_wait(amd_iommus[i]);
+ iommu_queue_command(iommu, &cmd);
+ iommu_completion_wait(iommu);
+}
+
+void iommu_flush_all_caches(struct amd_iommu *iommu)
+{
+ if (iommu_feature(iommu, FEATURE_IA)) {
+ iommu_flush_all(iommu);
+ } else {
+ iommu_flush_dte_all(iommu);
+ iommu_flush_tlb_all(iommu);
}
}
/*
- * Command send function for invalidating a device table entry
+ * Command send function for flushing on-device TLB
*/
-static int iommu_flush_device(struct device *dev)
+static int device_flush_iotlb(struct device *dev, u64 address, size_t size)
{
+ struct pci_dev *pdev = to_pci_dev(dev);
struct amd_iommu *iommu;
struct iommu_cmd cmd;
u16 devid;
+ int qdep;
+ qdep = pci_ats_queue_depth(pdev);
devid = get_device_id(dev);
iommu = amd_iommu_rlookup_table[devid];
- /* Build command */
- memset(&cmd, 0, sizeof(cmd));
- CMD_SET_TYPE(&cmd, CMD_INV_DEV_ENTRY);
- cmd.data[0] = devid;
+ build_inv_iotlb_pages(&cmd, devid, qdep, address, size);
return iommu_queue_command(iommu, &cmd);
}
-static void __iommu_build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address,
- u16 domid, int pde, int s)
-{
- memset(cmd, 0, sizeof(*cmd));
- address &= PAGE_MASK;
- CMD_SET_TYPE(cmd, CMD_INV_IOMMU_PAGES);
- cmd->data[1] |= domid;
- cmd->data[2] = lower_32_bits(address);
- cmd->data[3] = upper_32_bits(address);
- if (s) /* size bit - we flush more than one 4kb page */
- cmd->data[2] |= CMD_INV_IOMMU_PAGES_SIZE_MASK;
- if (pde) /* PDE bit - we wan't flush everything not only the PTEs */
- cmd->data[2] |= CMD_INV_IOMMU_PAGES_PDE_MASK;
-}
-
/*
- * Generic command send function for invalidaing TLB entries
+ * Command send function for invalidating a device table entry
*/
-static int iommu_queue_inv_iommu_pages(struct amd_iommu *iommu,
- u64 address, u16 domid, int pde, int s)
+static int device_flush_dte(struct device *dev)
{
- struct iommu_cmd cmd;
+ struct amd_iommu *iommu;
+ struct pci_dev *pdev;
+ u16 devid;
int ret;
- __iommu_build_inv_iommu_pages(&cmd, address, domid, pde, s);
+ pdev = to_pci_dev(dev);
+ devid = get_device_id(dev);
+ iommu = amd_iommu_rlookup_table[devid];
- ret = iommu_queue_command(iommu, &cmd);
+ ret = iommu_flush_dte(iommu, devid);
+ if (ret)
+ return ret;
+
+ if (pci_ats_enabled(pdev))
+ ret = device_flush_iotlb(dev, 0, ~0UL);
return ret;
}
@@ -572,23 +679,14 @@ static int iommu_queue_inv_iommu_pages(struct amd_iommu *iommu,
* It invalidates a single PTE if the range to flush is within a single
* page. Otherwise it flushes the whole TLB of the IOMMU.
*/
-static void __iommu_flush_pages(struct protection_domain *domain,
- u64 address, size_t size, int pde)
+static void __domain_flush_pages(struct protection_domain *domain,
+ u64 address, size_t size, int pde)
{
- int s = 0, i;
- unsigned long pages = iommu_num_pages(address, size, PAGE_SIZE);
-
- address &= PAGE_MASK;
-
- if (pages > 1) {
- /*
- * If we have to flush more than one page, flush all
- * TLB entries for this domain
- */
- address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS;
- s = 1;
- }
+ struct iommu_dev_data *dev_data;
+ struct iommu_cmd cmd;
+ int ret = 0, i;
+ build_inv_iommu_pages(&cmd, address, size, domain->id, pde);
for (i = 0; i < amd_iommus_present; ++i) {
if (!domain->dev_iommu[i])
@@ -598,101 +696,70 @@ static void __iommu_flush_pages(struct protection_domain *domain,
* Devices of this domain are behind this IOMMU
* We need a TLB flush
*/
- iommu_queue_inv_iommu_pages(amd_iommus[i], address,
- domain->id, pde, s);
+ ret |= iommu_queue_command(amd_iommus[i], &cmd);
+ }
+
+ list_for_each_entry(dev_data, &domain->dev_list, list) {
+ struct pci_dev *pdev = to_pci_dev(dev_data->dev);
+
+ if (!pci_ats_enabled(pdev))
+ continue;
+
+ ret |= device_flush_iotlb(dev_data->dev, address, size);
}
- return;
+ WARN_ON(ret);
}
-static void iommu_flush_pages(struct protection_domain *domain,
- u64 address, size_t size)
+static void domain_flush_pages(struct protection_domain *domain,
+ u64 address, size_t size)
{
- __iommu_flush_pages(domain, address, size, 0);
+ __domain_flush_pages(domain, address, size, 0);
}
/* Flush the whole IO/TLB for a given protection domain */
-static void iommu_flush_tlb(struct protection_domain *domain)
+static void domain_flush_tlb(struct protection_domain *domain)
{
- __iommu_flush_pages(domain, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, 0);
+ __domain_flush_pages(domain, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, 0);
}
/* Flush the whole IO/TLB for a given protection domain - including PDE */
-static void iommu_flush_tlb_pde(struct protection_domain *domain)
+static void domain_flush_tlb_pde(struct protection_domain *domain)
{
- __iommu_flush_pages(domain, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, 1);
-}
-
-
-/*
- * This function flushes the DTEs for all devices in domain
- */
-static void iommu_flush_domain_devices(struct protection_domain *domain)
-{
- struct iommu_dev_data *dev_data;
- unsigned long flags;
-
- spin_lock_irqsave(&domain->lock, flags);
-
- list_for_each_entry(dev_data, &domain->dev_list, list)
- iommu_flush_device(dev_data->dev);
-
- spin_unlock_irqrestore(&domain->lock, flags);
+ __domain_flush_pages(domain, 0, CMD_INV_IOMMU_ALL_PAGES_ADDRESS, 1);
}
-static void iommu_flush_all_domain_devices(void)
+static void domain_flush_complete(struct protection_domain *domain)
{
- struct protection_domain *domain;
- unsigned long flags;
+ int i;
- spin_lock_irqsave(&amd_iommu_pd_lock, flags);
+ for (i = 0; i < amd_iommus_present; ++i) {
+ if (!domain->dev_iommu[i])
+ continue;
- list_for_each_entry(domain, &amd_iommu_pd_list, list) {
- iommu_flush_domain_devices(domain);
- iommu_flush_complete(domain);
+ /*
+ * Devices of this domain are behind this IOMMU
+ * We need to wait for completion of all commands.
+ */
+ iommu_completion_wait(amd_iommus[i]);
}
-
- spin_unlock_irqrestore(&amd_iommu_pd_lock, flags);
}
-void amd_iommu_flush_all_devices(void)
-{
- iommu_flush_all_domain_devices();
-}
/*
- * This function uses heavy locking and may disable irqs for some time. But
- * this is no issue because it is only called during resume.
+ * This function flushes the DTEs for all devices in domain
*/
-void amd_iommu_flush_all_domains(void)
+static void domain_flush_devices(struct protection_domain *domain)
{
- struct protection_domain *domain;
+ struct iommu_dev_data *dev_data;
unsigned long flags;
- spin_lock_irqsave(&amd_iommu_pd_lock, flags);
-
- list_for_each_entry(domain, &amd_iommu_pd_list, list) {
- spin_lock(&domain->lock);
- iommu_flush_tlb_pde(domain);
- iommu_flush_complete(domain);
- spin_unlock(&domain->lock);
- }
-
- spin_unlock_irqrestore(&amd_iommu_pd_lock, flags);
-}
-
-static void reset_iommu_command_buffer(struct amd_iommu *iommu)
-{
- pr_err("AMD-Vi: Resetting IOMMU command buffer\n");
-
- if (iommu->reset_in_progress)
- panic("AMD-Vi: ILLEGAL_COMMAND_ERROR while resetting command buffer\n");
+ spin_lock_irqsave(&domain->lock, flags);
- amd_iommu_reset_cmd_buffer(iommu);
- amd_iommu_flush_all_devices();
- amd_iommu_flush_all_domains();
+ list_for_each_entry(dev_data, &domain->dev_list, list)
+ device_flush_dte(dev_data->dev);
- iommu->reset_in_progress = false;
+ spin_unlock_irqrestore(&domain->lock, flags);
}
/****************************************************************************
@@ -1410,17 +1477,22 @@ static bool dma_ops_domain(struct protection_domain *domain)
return domain->flags & PD_DMA_OPS_MASK;
}
-static void set_dte_entry(u16 devid, struct protection_domain *domain)
+static void set_dte_entry(u16 devid, struct protection_domain *domain, bool ats)
{
u64 pte_root = virt_to_phys(domain->pt_root);
+ u32 flags = 0;
pte_root |= (domain->mode & DEV_ENTRY_MODE_MASK)
<< DEV_ENTRY_MODE_SHIFT;
pte_root |= IOMMU_PTE_IR | IOMMU_PTE_IW | IOMMU_PTE_P | IOMMU_PTE_TV;
- amd_iommu_dev_table[devid].data[2] = domain->id;
- amd_iommu_dev_table[devid].data[1] = upper_32_bits(pte_root);
- amd_iommu_dev_table[devid].data[0] = lower_32_bits(pte_root);
+ if (ats)
+ flags |= DTE_FLAG_IOTLB;
+
+ amd_iommu_dev_table[devid].data[3] |= flags;
+ amd_iommu_dev_table[devid].data[2] = domain->id;
+ amd_iommu_dev_table[devid].data[1] = upper_32_bits(pte_root);
+ amd_iommu_dev_table[devid].data[0] = lower_32_bits(pte_root);
}
static void clear_dte_entry(u16 devid)
@@ -1437,23 +1509,29 @@ static void do_attach(struct device *dev, struct protection_domain *domain)
{
struct iommu_dev_data *dev_data;
struct amd_iommu *iommu;
+ struct pci_dev *pdev;
+ bool ats = false;
u16 devid;
devid = get_device_id(dev);
iommu = amd_iommu_rlookup_table[devid];
dev_data = get_dev_data(dev);
+ pdev = to_pci_dev(dev);
+
+ if (amd_iommu_iotlb_sup)
+ ats = pci_ats_enabled(pdev);
/* Update data structures */
dev_data->domain = domain;
list_add(&dev_data->list, &domain->dev_list);
- set_dte_entry(devid, domain);
+ set_dte_entry(devid, domain, ats);
/* Do reference counting */
domain->dev_iommu[iommu->index] += 1;
domain->dev_cnt += 1;
/* Flush the DTE entry */
- iommu_flush_device(dev);
+ device_flush_dte(dev);
}
static void do_detach(struct device *dev)
@@ -1476,7 +1554,7 @@ static void do_detach(struct device *dev)
clear_dte_entry(devid);
/* Flush the DTE entry */
- iommu_flush_device(dev);
+ device_flush_dte(dev);
}
/*
@@ -1539,9 +1617,13 @@ out_unlock:
static int attach_device(struct device *dev,
struct protection_domain *domain)
{
+ struct pci_dev *pdev = to_pci_dev(dev);
unsigned long flags;
int ret;
+ if (amd_iommu_iotlb_sup)
+ pci_enable_ats(pdev, PAGE_SHIFT);
+
write_lock_irqsave(&amd_iommu_devtable_lock, flags);
ret = __attach_device(dev, domain);
write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
@@ -1551,7 +1633,7 @@ static int attach_device(struct device *dev,
* left the caches in the IOMMU dirty. So we have to flush
* here to evict all dirty stuff.
*/
- iommu_flush_tlb_pde(domain);
+ domain_flush_tlb_pde(domain);
return ret;
}
@@ -1598,12 +1680,16 @@ static void __detach_device(struct device *dev)
*/
static void detach_device(struct device *dev)
{
+ struct pci_dev *pdev = to_pci_dev(dev);
unsigned long flags;
/* lock device table */
write_lock_irqsave(&amd_iommu_devtable_lock, flags);
__detach_device(dev);
write_unlock_irqrestore(&amd_iommu_devtable_lock, flags);
+
+ if (amd_iommu_iotlb_sup && pci_ats_enabled(pdev))
+ pci_disable_ats(pdev);
}
/*
@@ -1615,10 +1701,9 @@ static struct protection_domain *domain_for_device(struct device *dev)
struct protection_domain *dom;
struct iommu_dev_data *dev_data, *alias_data;
unsigned long flags;
- u16 devid, alias;
+ u16 devid;
devid = get_device_id(dev);
- alias = amd_iommu_alias_table[devid];
dev_data = get_dev_data(dev);
alias_data = get_dev_data(dev_data->alias);
if (!alias_data)
@@ -1692,7 +1777,7 @@ static int device_change_notifier(struct notifier_block *nb,
goto out;
}
- iommu_flush_device(dev);
+ device_flush_dte(dev);
iommu_completion_wait(iommu);
out:
@@ -1753,8 +1838,9 @@ static void update_device_table(struct protection_domain *domain)
struct iommu_dev_data *dev_data;
list_for_each_entry(dev_data, &domain->dev_list, list) {
+ struct pci_dev *pdev = to_pci_dev(dev_data->dev);
u16 devid = get_device_id(dev_data->dev);
- set_dte_entry(devid, domain);
+ set_dte_entry(devid, domain, pci_ats_enabled(pdev));
}
}
@@ -1764,8 +1850,9 @@ static void update_domain(struct protection_domain *domain)
return;
update_device_table(domain);
- iommu_flush_domain_devices(domain);
- iommu_flush_tlb_pde(domain);
+
+ domain_flush_devices(domain);
+ domain_flush_tlb_pde(domain);
domain->updated = false;
}
@@ -1924,10 +2011,10 @@ retry:
ADD_STATS_COUNTER(alloced_io_mem, size);
if (unlikely(dma_dom->need_flush && !amd_iommu_unmap_flush)) {
- iommu_flush_tlb(&dma_dom->domain);
+ domain_flush_tlb(&dma_dom->domain);
dma_dom->need_flush = false;
} else if (unlikely(amd_iommu_np_cache))
- iommu_flush_pages(&dma_dom->domain, address, size);
+ domain_flush_pages(&dma_dom->domain, address, size);
out:
return address;
@@ -1976,7 +2063,7 @@ static void __unmap_single(struct dma_ops_domain *dma_dom,
dma_ops_free_addresses(dma_dom, dma_addr, pages);
if (amd_iommu_unmap_flush || dma_dom->need_flush) {
- iommu_flush_pages(&dma_dom->domain, flush_addr, size);
+ domain_flush_pages(&dma_dom->domain, flush_addr, size);
dma_dom->need_flush = false;
}
}
@@ -2012,7 +2099,7 @@ static dma_addr_t map_page(struct device *dev, struct page *page,
if (addr == DMA_ERROR_CODE)
goto out;
- iommu_flush_complete(domain);
+ domain_flush_complete(domain);
out:
spin_unlock_irqrestore(&domain->lock, flags);
@@ -2039,7 +2126,7 @@ static void unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size,
__unmap_single(domain->priv, dma_addr, size, dir);
- iommu_flush_complete(domain);
+ domain_flush_complete(domain);
spin_unlock_irqrestore(&domain->lock, flags);
}
@@ -2104,7 +2191,7 @@ static int map_sg(struct device *dev, struct scatterlist *sglist,
goto unmap;
}
- iommu_flush_complete(domain);
+ domain_flush_complete(domain);
out:
spin_unlock_irqrestore(&domain->lock, flags);
@@ -2150,7 +2237,7 @@ static void unmap_sg(struct device *dev, struct scatterlist *sglist,
s->dma_address = s->dma_length = 0;
}
- iommu_flush_complete(domain);
+ domain_flush_complete(domain);
spin_unlock_irqrestore(&domain->lock, flags);
}
@@ -2200,7 +2287,7 @@ static void *alloc_coherent(struct device *dev, size_t size,
goto out_free;
}
- iommu_flush_complete(domain);
+ domain_flush_complete(domain);
spin_unlock_irqrestore(&domain->lock, flags);
@@ -2232,7 +2319,7 @@ static void free_coherent(struct device *dev, size_t size,
__unmap_single(domain->priv, dma_addr, size, DMA_BIDIRECTIONAL);
- iommu_flush_complete(domain);
+ domain_flush_complete(domain);
spin_unlock_irqrestore(&domain->lock, flags);
@@ -2476,7 +2563,7 @@ static void amd_iommu_detach_device(struct iommu_domain *dom,
if (!iommu)
return;
- iommu_flush_device(dev);
+ device_flush_dte(dev);
iommu_completion_wait(iommu);
}
@@ -2542,7 +2629,7 @@ static int amd_iommu_unmap(struct iommu_domain *dom, unsigned long iova,
unmap_size = iommu_unmap_page(domain, iova, page_size);
mutex_unlock(&domain->api_lock);
- iommu_flush_tlb_pde(domain);
+ domain_flush_tlb_pde(domain);
return get_order(unmap_size);
}
diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c
index 246d727b65b7..9179c21120a8 100644
--- a/arch/x86/kernel/amd_iommu_init.c
+++ b/arch/x86/kernel/amd_iommu_init.c
@@ -137,6 +137,7 @@ int amd_iommus_present;
/* IOMMUs have a non-present cache? */
bool amd_iommu_np_cache __read_mostly;
+bool amd_iommu_iotlb_sup __read_mostly = true;
/*
* The ACPI table parsing functions set this variable on an error
@@ -180,6 +181,12 @@ static u32 dev_table_size; /* size of the device table */
static u32 alias_table_size; /* size of the alias table */
static u32 rlookup_table_size; /* size if the rlookup table */
+/*
+ * This function flushes all internal caches of
+ * the IOMMU used by this driver.
+ */
+extern void iommu_flush_all_caches(struct amd_iommu *iommu);
+
static inline void update_last_devid(u16 devid)
{
if (devid > amd_iommu_last_bdf)
@@ -293,9 +300,23 @@ static void iommu_feature_disable(struct amd_iommu *iommu, u8 bit)
/* Function to enable the hardware */
static void iommu_enable(struct amd_iommu *iommu)
{
- printk(KERN_INFO "AMD-Vi: Enabling IOMMU at %s cap 0x%hx\n",
+ static const char * const feat_str[] = {
+ "PreF", "PPR", "X2APIC", "NX", "GT", "[5]",
+ "IA", "GA", "HE", "PC", NULL
+ };
+ int i;
+
+ printk(KERN_INFO "AMD-Vi: Enabling IOMMU at %s cap 0x%hx",
dev_name(&iommu->dev->dev), iommu->cap_ptr);
+ if (iommu->cap & (1 << IOMMU_CAP_EFR)) {
+ printk(KERN_CONT " extended features: ");
+ for (i = 0; feat_str[i]; ++i)
+ if (iommu_feature(iommu, (1ULL << i)))
+ printk(KERN_CONT " %s", feat_str[i]);
+ }
+ printk(KERN_CONT "\n");
+
iommu_feature_enable(iommu, CONTROL_IOMMU_EN);
}
@@ -651,7 +672,7 @@ static void __init set_device_exclusion_range(u16 devid, struct ivmd_header *m)
static void __init init_iommu_from_pci(struct amd_iommu *iommu)
{
int cap_ptr = iommu->cap_ptr;
- u32 range, misc;
+ u32 range, misc, low, high;
int i, j;
pci_read_config_dword(iommu->dev, cap_ptr + MMIO_CAP_HDR_OFFSET,
@@ -667,6 +688,15 @@ static void __init init_iommu_from_pci(struct amd_iommu *iommu)
MMIO_GET_LD(range));
iommu->evt_msi_num = MMIO_MSI_NUM(misc);
+ if (!(iommu->cap & (1 << IOMMU_CAP_IOTLB)))
+ amd_iommu_iotlb_sup = false;
+
+ /* read extended feature bits */
+ low = readl(iommu->mmio_base + MMIO_EXT_FEATURES);
+ high = readl(iommu->mmio_base + MMIO_EXT_FEATURES + 4);
+
+ iommu->features = ((u64)high << 32) | low;
+
if (!is_rd890_iommu(iommu->dev))
return;
@@ -1004,10 +1034,11 @@ static int iommu_setup_msi(struct amd_iommu *iommu)
if (pci_enable_msi(iommu->dev))
return 1;
- r = request_irq(iommu->dev->irq, amd_iommu_int_handler,
- IRQF_SAMPLE_RANDOM,
- "AMD-Vi",
- NULL);
+ r = request_threaded_irq(iommu->dev->irq,
+ amd_iommu_int_handler,
+ amd_iommu_int_thread,
+ 0, "AMD-Vi",
+ iommu->dev);
if (r) {
pci_disable_msi(iommu->dev);
@@ -1244,6 +1275,7 @@ static void enable_iommus(void)
iommu_set_exclusion_range(iommu);
iommu_init_msi(iommu);
iommu_enable(iommu);
+ iommu_flush_all_caches(iommu);
}
}
@@ -1274,8 +1306,8 @@ static void amd_iommu_resume(void)
* we have to flush after the IOMMUs are enabled because a
* disabled IOMMU will never execute the commands we send
*/
- amd_iommu_flush_all_devices();
- amd_iommu_flush_all_domains();
+ for_each_iommu(iommu)
+ iommu_flush_all_caches(iommu);
}
static int amd_iommu_suspend(void)
diff --git a/arch/x86/kernel/apb_timer.c b/arch/x86/kernel/apb_timer.c
index cd1ffed4ee22..289e92862fd9 100644
--- a/arch/x86/kernel/apb_timer.c
+++ b/arch/x86/kernel/apb_timer.c
@@ -177,7 +177,6 @@ static struct clocksource clocksource_apbt = {
.rating = APBT_CLOCKSOURCE_RATING,
.read = apbt_read_clocksource,
.mask = APBT_MASK,
- .shift = APBT_SHIFT,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
.resume = apbt_restart_clocksource,
};
@@ -543,14 +542,7 @@ static int apbt_clocksource_register(void)
if (t1 == apbt_read_clocksource(&clocksource_apbt))
panic("APBT counter not counting. APBT disabled\n");
- /*
- * initialize and register APBT clocksource
- * convert that to ns/clock cycle
- * mult = (ns/c) * 2^APBT_SHIFT
- */
- clocksource_apbt.mult = div_sc(MSEC_PER_SEC,
- (unsigned long) apbt_freq, APBT_SHIFT);
- clocksource_register(&clocksource_apbt);
+ clocksource_register_khz(&clocksource_apbt, (u32)apbt_freq*1000);
return 0;
}
diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c
index 73fb469908c6..3d2661ca6542 100644
--- a/arch/x86/kernel/aperture_64.c
+++ b/arch/x86/kernel/aperture_64.c
@@ -30,6 +30,22 @@
#include <asm/amd_nb.h>
#include <asm/x86_init.h>
+/*
+ * Using 512M as goal, in case kexec will load kernel_big
+ * that will do the on-position decompress, and could overlap with
+ * with the gart aperture that is used.
+ * Sequence:
+ * kernel_small
+ * ==> kexec (with kdump trigger path or gart still enabled)
+ * ==> kernel_small (gart area become e820_reserved)
+ * ==> kexec (with kdump trigger path or gart still enabled)
+ * ==> kerne_big (uncompressed size will be big than 64M or 128M)
+ * So don't use 512M below as gart iommu, leave the space for kernel
+ * code for safe.
+ */
+#define GART_MIN_ADDR (512ULL << 20)
+#define GART_MAX_ADDR (1ULL << 32)
+
int gart_iommu_aperture;
int gart_iommu_aperture_disabled __initdata;
int gart_iommu_aperture_allowed __initdata;
@@ -70,21 +86,9 @@ static u32 __init allocate_aperture(void)
* memory. Unfortunately we cannot move it up because that would
* make the IOMMU useless.
*/
- /*
- * using 512M as goal, in case kexec will load kernel_big
- * that will do the on position decompress, and could overlap with
- * that position with gart that is used.
- * sequende:
- * kernel_small
- * ==> kexec (with kdump trigger path or previous doesn't shutdown gart)
- * ==> kernel_small(gart area become e820_reserved)
- * ==> kexec (with kdump trigger path or previous doesn't shutdown gart)
- * ==> kerne_big (uncompressed size will be big than 64M or 128M)
- * so don't use 512M below as gart iommu, leave the space for kernel
- * code for safe
- */
- addr = memblock_find_in_range(0, 1ULL<<32, aper_size, 512ULL<<20);
- if (addr == MEMBLOCK_ERROR || addr + aper_size > 0xffffffff) {
+ addr = memblock_find_in_range(GART_MIN_ADDR, GART_MAX_ADDR,
+ aper_size, aper_size);
+ if (addr == MEMBLOCK_ERROR || addr + aper_size > GART_MAX_ADDR) {
printk(KERN_ERR
"Cannot allocate aperture memory hole (%lx,%uK)\n",
addr, aper_size>>10);
diff --git a/arch/x86/kernel/apic/Makefile b/arch/x86/kernel/apic/Makefile
index 3966b564ea47..767fd04f2843 100644
--- a/arch/x86/kernel/apic/Makefile
+++ b/arch/x86/kernel/apic/Makefile
@@ -2,20 +2,25 @@
# 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
+obj-$(CONFIG_X86_LOCAL_APIC) += apic.o apic_noop.o ipi.o
obj-y += hw_nmi.o
obj-$(CONFIG_X86_IO_APIC) += io_apic.o
obj-$(CONFIG_SMP) += ipi.o
ifeq ($(CONFIG_X86_64),y)
-obj-y += apic_flat_64.o
-obj-$(CONFIG_X86_X2APIC) += x2apic_cluster.o
-obj-$(CONFIG_X86_X2APIC) += x2apic_phys.o
+# APIC probe will depend on the listing order here
obj-$(CONFIG_X86_UV) += x2apic_uv_x.o
+obj-$(CONFIG_X86_X2APIC) += x2apic_phys.o
+obj-$(CONFIG_X86_X2APIC) += x2apic_cluster.o
+obj-y += apic_flat_64.o
endif
-obj-$(CONFIG_X86_BIGSMP) += bigsmp_32.o
+# APIC probe will depend on the listing order here
obj-$(CONFIG_X86_NUMAQ) += numaq_32.o
-obj-$(CONFIG_X86_ES7000) += es7000_32.o
obj-$(CONFIG_X86_SUMMIT) += summit_32.o
+obj-$(CONFIG_X86_BIGSMP) += bigsmp_32.o
+obj-$(CONFIG_X86_ES7000) += es7000_32.o
+
+# For 32bit, probe_32 need to be listed last
+obj-$(CONFIG_X86_LOCAL_APIC) += probe_$(BITS).o
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index fabf01eff771..b961af86bfea 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -505,7 +505,7 @@ static void __cpuinit setup_APIC_timer(void)
{
struct clock_event_device *levt = &__get_cpu_var(lapic_events);
- if (cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_ARAT)) {
+ if (this_cpu_has(X86_FEATURE_ARAT)) {
lapic_clockevent.features &= ~CLOCK_EVT_FEAT_C3STOP;
/* Make LAPIC timer preferrable over percpu HPET */
lapic_clockevent.rating = 150;
@@ -1237,6 +1237,17 @@ void __cpuinit setup_local_APIC(void)
/* always use the value from LDR */
early_per_cpu(x86_cpu_to_logical_apicid, cpu) =
logical_smp_processor_id();
+
+ /*
+ * Some NUMA implementations (NUMAQ) don't initialize apicid to
+ * node mapping during NUMA init. Now that logical apicid is
+ * guaranteed to be known, give it another chance. This is already
+ * a bit too late - percpu allocation has already happened without
+ * proper NUMA affinity.
+ */
+ if (apic->x86_32_numa_cpu_node)
+ set_apicid_to_node(early_per_cpu(x86_cpu_to_apicid, cpu),
+ apic->x86_32_numa_cpu_node(cpu));
#endif
/*
@@ -1450,7 +1461,6 @@ int __init enable_IR(void)
void __init enable_IR_x2apic(void)
{
unsigned long flags;
- struct IO_APIC_route_entry **ioapic_entries;
int ret, x2apic_enabled = 0;
int dmar_table_init_ret;
@@ -1458,13 +1468,7 @@ void __init enable_IR_x2apic(void)
if (dmar_table_init_ret && !x2apic_supported())
return;
- ioapic_entries = alloc_ioapic_entries();
- if (!ioapic_entries) {
- pr_err("Allocate ioapic_entries failed\n");
- goto out;
- }
-
- ret = save_IO_APIC_setup(ioapic_entries);
+ ret = save_ioapic_entries();
if (ret) {
pr_info("Saving IO-APIC state failed: %d\n", ret);
goto out;
@@ -1472,7 +1476,7 @@ void __init enable_IR_x2apic(void)
local_irq_save(flags);
legacy_pic->mask_all();
- mask_IO_APIC_setup(ioapic_entries);
+ mask_ioapic_entries();
if (dmar_table_init_ret)
ret = 0;
@@ -1503,14 +1507,11 @@ void __init enable_IR_x2apic(void)
nox2apic:
if (!ret) /* IR enabling failed */
- restore_IO_APIC_setup(ioapic_entries);
+ restore_ioapic_entries();
legacy_pic->restore_mask();
local_irq_restore(flags);
out:
- if (ioapic_entries)
- free_ioapic_entries(ioapic_entries);
-
if (x2apic_enabled)
return;
@@ -1812,30 +1813,41 @@ void smp_spurious_interrupt(struct pt_regs *regs)
*/
void smp_error_interrupt(struct pt_regs *regs)
{
- u32 v, v1;
+ u32 v0, v1;
+ u32 i = 0;
+ static const char * const error_interrupt_reason[] = {
+ "Send CS error", /* APIC Error Bit 0 */
+ "Receive CS error", /* APIC Error Bit 1 */
+ "Send accept error", /* APIC Error Bit 2 */
+ "Receive accept error", /* APIC Error Bit 3 */
+ "Redirectable IPI", /* APIC Error Bit 4 */
+ "Send illegal vector", /* APIC Error Bit 5 */
+ "Received illegal vector", /* APIC Error Bit 6 */
+ "Illegal register address", /* APIC Error Bit 7 */
+ };
exit_idle();
irq_enter();
/* First tickle the hardware, only then report what went on. -- REW */
- v = apic_read(APIC_ESR);
+ v0 = apic_read(APIC_ESR);
apic_write(APIC_ESR, 0);
v1 = apic_read(APIC_ESR);
ack_APIC_irq();
atomic_inc(&irq_err_count);
- /*
- * Here is what the APIC error bits mean:
- * 0: Send CS error
- * 1: Receive CS error
- * 2: Send accept error
- * 3: Receive accept error
- * 4: Reserved
- * 5: Send illegal vector
- * 6: Received illegal vector
- * 7: Illegal register address
- */
- pr_debug("APIC error on CPU%d: %02x(%02x)\n",
- smp_processor_id(), v , v1);
+ apic_printk(APIC_DEBUG, KERN_DEBUG "APIC error on CPU%d: %02x(%02x)",
+ smp_processor_id(), v0 , v1);
+
+ v1 = v1 & 0xff;
+ while (v1) {
+ if (v1 & 0x1)
+ apic_printk(APIC_DEBUG, KERN_CONT " : %s", error_interrupt_reason[i]);
+ i++;
+ v1 >>= 1;
+ };
+
+ apic_printk(APIC_DEBUG, KERN_CONT "\n");
+
irq_exit();
}
@@ -2003,21 +2015,6 @@ void default_init_apic_ldr(void)
apic_write(APIC_LDR, val);
}
-#ifdef CONFIG_X86_32
-int default_x86_32_numa_cpu_node(int cpu)
-{
-#ifdef CONFIG_NUMA
- int apicid = early_per_cpu(x86_cpu_to_apicid, cpu);
-
- if (apicid != BAD_APICID)
- return __apicid_to_node[apicid];
- return NUMA_NO_NODE;
-#else
- return 0;
-#endif
-}
-#endif
-
/*
* Power management
*/
@@ -2088,28 +2085,20 @@ static void lapic_resume(void)
{
unsigned int l, h;
unsigned long flags;
- int maxlvt, ret;
- struct IO_APIC_route_entry **ioapic_entries = NULL;
+ int maxlvt;
if (!apic_pm_state.active)
return;
local_irq_save(flags);
if (intr_remapping_enabled) {
- ioapic_entries = alloc_ioapic_entries();
- if (!ioapic_entries) {
- WARN(1, "Alloc ioapic_entries in lapic resume failed.");
- goto restore;
- }
-
- ret = save_IO_APIC_setup(ioapic_entries);
- if (ret) {
- WARN(1, "Saving IO-APIC state failed: %d\n", ret);
- free_ioapic_entries(ioapic_entries);
- goto restore;
- }
-
- mask_IO_APIC_setup(ioapic_entries);
+ /*
+ * IO-APIC and PIC have their own resume routines.
+ * We just mask them here to make sure the interrupt
+ * subsystem is completely quiet while we enable x2apic
+ * and interrupt-remapping.
+ */
+ mask_ioapic_entries();
legacy_pic->mask_all();
}
@@ -2152,13 +2141,9 @@ static void lapic_resume(void)
apic_write(APIC_ESR, 0);
apic_read(APIC_ESR);
- if (intr_remapping_enabled) {
+ if (intr_remapping_enabled)
reenable_intr_remapping(x2apic_mode);
- legacy_pic->restore_mask();
- restore_IO_APIC_setup(ioapic_entries);
- free_ioapic_entries(ioapic_entries);
- }
-restore:
+
local_irq_restore(flags);
}
diff --git a/arch/x86/kernel/apic/apic_flat_64.c b/arch/x86/kernel/apic/apic_flat_64.c
index 5652d31fe108..f7a41e4cae47 100644
--- a/arch/x86/kernel/apic/apic_flat_64.c
+++ b/arch/x86/kernel/apic/apic_flat_64.c
@@ -16,6 +16,7 @@
#include <linux/ctype.h>
#include <linux/init.h>
#include <linux/hardirq.h>
+#include <linux/module.h>
#include <asm/smp.h>
#include <asm/apic.h>
#include <asm/ipi.h>
@@ -24,6 +25,12 @@
#include <acpi/acpi_bus.h>
#endif
+static struct apic apic_physflat;
+static struct apic apic_flat;
+
+struct apic __read_mostly *apic = &apic_flat;
+EXPORT_SYMBOL_GPL(apic);
+
static int flat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
{
return 1;
@@ -164,7 +171,7 @@ static int flat_phys_pkg_id(int initial_apic_id, int index_msb)
return initial_apic_id >> index_msb;
}
-struct apic apic_flat = {
+static struct apic apic_flat = {
.name = "flat",
.probe = NULL,
.acpi_madt_oem_check = flat_acpi_madt_oem_check,
@@ -312,10 +319,18 @@ physflat_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
return per_cpu(x86_cpu_to_apicid, cpu);
}
-struct apic apic_physflat = {
+static int physflat_probe(void)
+{
+ if (apic == &apic_physflat || num_possible_cpus() > 8)
+ return 1;
+
+ return 0;
+}
+
+static struct apic apic_physflat = {
.name = "physical flat",
- .probe = NULL,
+ .probe = physflat_probe,
.acpi_madt_oem_check = physflat_acpi_madt_oem_check,
.apic_id_registered = flat_apic_id_registered,
@@ -369,3 +384,8 @@ struct apic apic_physflat = {
.wait_icr_idle = native_apic_wait_icr_idle,
.safe_wait_icr_idle = native_safe_apic_wait_icr_idle,
};
+
+/*
+ * We need to check for physflat first, so this order is important.
+ */
+apic_drivers(apic_physflat, apic_flat);
diff --git a/arch/x86/kernel/apic/apic_noop.c b/arch/x86/kernel/apic/apic_noop.c
index f1baa2dc087a..775b82bc655c 100644
--- a/arch/x86/kernel/apic/apic_noop.c
+++ b/arch/x86/kernel/apic/apic_noop.c
@@ -119,14 +119,6 @@ static void noop_apic_write(u32 reg, u32 v)
WARN_ON_ONCE(cpu_has_apic && !disable_apic);
}
-#ifdef CONFIG_X86_32
-static int noop_x86_32_numa_cpu_node(int cpu)
-{
- /* we're always on node 0 */
- return 0;
-}
-#endif
-
struct apic apic_noop = {
.name = "noop",
.probe = noop_probe,
@@ -195,6 +187,5 @@ struct apic apic_noop = {
#ifdef CONFIG_X86_32
.x86_32_early_logical_apicid = noop_x86_32_early_logical_apicid,
- .x86_32_numa_cpu_node = noop_x86_32_numa_cpu_node,
#endif
};
diff --git a/arch/x86/kernel/apic/bigsmp_32.c b/arch/x86/kernel/apic/bigsmp_32.c
index 541a2e431659..efd737e827f4 100644
--- a/arch/x86/kernel/apic/bigsmp_32.c
+++ b/arch/x86/kernel/apic/bigsmp_32.c
@@ -193,7 +193,7 @@ static int probe_bigsmp(void)
return dmi_bigsmp;
}
-struct apic apic_bigsmp = {
+static struct apic apic_bigsmp = {
.name = "bigsmp",
.probe = probe_bigsmp,
@@ -253,5 +253,14 @@ struct apic apic_bigsmp = {
.safe_wait_icr_idle = native_safe_apic_wait_icr_idle,
.x86_32_early_logical_apicid = bigsmp_early_logical_apicid,
- .x86_32_numa_cpu_node = default_x86_32_numa_cpu_node,
};
+
+struct apic * __init generic_bigsmp_probe(void)
+{
+ if (probe_bigsmp())
+ return &apic_bigsmp;
+
+ return NULL;
+}
+
+apic_driver(apic_bigsmp);
diff --git a/arch/x86/kernel/apic/es7000_32.c b/arch/x86/kernel/apic/es7000_32.c
index 3e9de4854c5b..9536b3fe43f8 100644
--- a/arch/x86/kernel/apic/es7000_32.c
+++ b/arch/x86/kernel/apic/es7000_32.c
@@ -510,11 +510,6 @@ static void es7000_setup_apic_routing(void)
nr_ioapics, cpumask_bits(es7000_target_cpus())[0]);
}
-static int es7000_numa_cpu_node(int cpu)
-{
- return 0;
-}
-
static int es7000_cpu_present_to_apicid(int mps_cpu)
{
if (!mps_cpu)
@@ -625,7 +620,7 @@ static int es7000_mps_oem_check_cluster(struct mpc_table *mpc, char *oem,
}
/* We've been warned by a false positive warning.Use __refdata to keep calm. */
-struct apic __refdata apic_es7000_cluster = {
+static struct apic __refdata apic_es7000_cluster = {
.name = "es7000",
.probe = probe_es7000,
@@ -688,10 +683,9 @@ struct apic __refdata apic_es7000_cluster = {
.safe_wait_icr_idle = native_safe_apic_wait_icr_idle,
.x86_32_early_logical_apicid = es7000_early_logical_apicid,
- .x86_32_numa_cpu_node = es7000_numa_cpu_node,
};
-struct apic __refdata apic_es7000 = {
+static struct apic __refdata apic_es7000 = {
.name = "es7000",
.probe = probe_es7000,
@@ -752,5 +746,10 @@ struct apic __refdata apic_es7000 = {
.safe_wait_icr_idle = native_safe_apic_wait_icr_idle,
.x86_32_early_logical_apicid = es7000_early_logical_apicid,
- .x86_32_numa_cpu_node = es7000_numa_cpu_node,
};
+
+/*
+ * Need to check for es7000 followed by es7000_cluster, so this order
+ * in apic_drivers is important.
+ */
+apic_drivers(apic_es7000, apic_es7000_cluster);
diff --git a/arch/x86/kernel/apic/hw_nmi.c b/arch/x86/kernel/apic/hw_nmi.c
index 5260fe91bcb6..d5e57db0f7be 100644
--- a/arch/x86/kernel/apic/hw_nmi.c
+++ b/arch/x86/kernel/apic/hw_nmi.c
@@ -19,9 +19,9 @@
#include <linux/delay.h>
#ifdef CONFIG_HARDLOCKUP_DETECTOR
-u64 hw_nmi_get_sample_period(void)
+u64 hw_nmi_get_sample_period(int watchdog_thresh)
{
- return (u64)(cpu_khz) * 1000 * 60;
+ return (u64)(cpu_khz) * 1000 * watchdog_thresh;
}
#endif
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 45fd33d1fd3a..e5293394b548 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -76,17 +76,40 @@ int sis_apic_bug = -1;
static DEFINE_RAW_SPINLOCK(ioapic_lock);
static DEFINE_RAW_SPINLOCK(vector_lock);
-/*
- * # of IRQ routing registers
- */
-int nr_ioapic_registers[MAX_IO_APICS];
+static struct ioapic {
+ /*
+ * # of IRQ routing registers
+ */
+ int nr_registers;
+ /*
+ * Saved state during suspend/resume, or while enabling intr-remap.
+ */
+ struct IO_APIC_route_entry *saved_registers;
+ /* I/O APIC config */
+ struct mpc_ioapic mp_config;
+ /* IO APIC gsi routing info */
+ struct mp_ioapic_gsi gsi_config;
+ DECLARE_BITMAP(pin_programmed, MP_MAX_IOAPIC_PIN + 1);
+} ioapics[MAX_IO_APICS];
-/* I/O APIC entries */
-struct mpc_ioapic mp_ioapics[MAX_IO_APICS];
-int nr_ioapics;
+#define mpc_ioapic_ver(id) ioapics[id].mp_config.apicver
+
+int mpc_ioapic_id(int id)
+{
+ return ioapics[id].mp_config.apicid;
+}
-/* IO APIC gsi routing info */
-struct mp_ioapic_gsi mp_gsi_routing[MAX_IO_APICS];
+unsigned int mpc_ioapic_addr(int id)
+{
+ return ioapics[id].mp_config.apicaddr;
+}
+
+struct mp_ioapic_gsi *mp_ioapic_gsi_routing(int id)
+{
+ return &ioapics[id].gsi_config;
+}
+
+int nr_ioapics;
/* The one past the highest gsi number used */
u32 gsi_top;
@@ -179,6 +202,14 @@ int __init arch_early_irq_init(void)
io_apic_irqs = ~0UL;
}
+ for (i = 0; i < nr_ioapics; i++) {
+ ioapics[i].saved_registers =
+ kzalloc(sizeof(struct IO_APIC_route_entry) *
+ ioapics[i].nr_registers, GFP_KERNEL);
+ if (!ioapics[i].saved_registers)
+ pr_err("IOAPIC %d: suspend/resume impossible!\n", i);
+ }
+
cfg = irq_cfgx;
count = ARRAY_SIZE(irq_cfgx);
node = cpu_to_node(0);
@@ -297,7 +328,7 @@ struct io_apic {
static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx)
{
return (void __iomem *) __fix_to_virt(FIX_IO_APIC_BASE_0 + idx)
- + (mp_ioapics[idx].apicaddr & ~PAGE_MASK);
+ + (mpc_ioapic_addr(idx) & ~PAGE_MASK);
}
static inline void io_apic_eoi(unsigned int apic, unsigned int vector)
@@ -573,7 +604,7 @@ static void clear_IO_APIC (void)
int apic, pin;
for (apic = 0; apic < nr_ioapics; apic++)
- for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
+ for (pin = 0; pin < ioapics[apic].nr_registers; pin++)
clear_IO_APIC_pin(apic, pin);
}
@@ -615,74 +646,43 @@ static int __init ioapic_pirq_setup(char *str)
__setup("pirq=", ioapic_pirq_setup);
#endif /* CONFIG_X86_32 */
-struct IO_APIC_route_entry **alloc_ioapic_entries(void)
-{
- int apic;
- struct IO_APIC_route_entry **ioapic_entries;
-
- ioapic_entries = kzalloc(sizeof(*ioapic_entries) * nr_ioapics,
- GFP_KERNEL);
- if (!ioapic_entries)
- return 0;
-
- for (apic = 0; apic < nr_ioapics; apic++) {
- ioapic_entries[apic] =
- kzalloc(sizeof(struct IO_APIC_route_entry) *
- nr_ioapic_registers[apic], GFP_KERNEL);
- if (!ioapic_entries[apic])
- goto nomem;
- }
-
- return ioapic_entries;
-
-nomem:
- while (--apic >= 0)
- kfree(ioapic_entries[apic]);
- kfree(ioapic_entries);
-
- return 0;
-}
-
/*
* Saves all the IO-APIC RTE's
*/
-int save_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries)
+int save_ioapic_entries(void)
{
int apic, pin;
-
- if (!ioapic_entries)
- return -ENOMEM;
+ int err = 0;
for (apic = 0; apic < nr_ioapics; apic++) {
- if (!ioapic_entries[apic])
- return -ENOMEM;
+ if (!ioapics[apic].saved_registers) {
+ err = -ENOMEM;
+ continue;
+ }
- for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
- ioapic_entries[apic][pin] =
+ for (pin = 0; pin < ioapics[apic].nr_registers; pin++)
+ ioapics[apic].saved_registers[pin] =
ioapic_read_entry(apic, pin);
}
- return 0;
+ return err;
}
/*
* Mask all IO APIC entries.
*/
-void mask_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries)
+void mask_ioapic_entries(void)
{
int apic, pin;
- if (!ioapic_entries)
- return;
-
for (apic = 0; apic < nr_ioapics; apic++) {
- if (!ioapic_entries[apic])
- break;
+ if (!ioapics[apic].saved_registers)
+ continue;
- for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
+ for (pin = 0; pin < ioapics[apic].nr_registers; pin++) {
struct IO_APIC_route_entry entry;
- entry = ioapic_entries[apic][pin];
+ entry = ioapics[apic].saved_registers[pin];
if (!entry.mask) {
entry.mask = 1;
ioapic_write_entry(apic, pin, entry);
@@ -692,36 +692,23 @@ void mask_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries)
}
/*
- * Restore IO APIC entries which was saved in ioapic_entries.
+ * Restore IO APIC entries which was saved in the ioapic structure.
*/
-int restore_IO_APIC_setup(struct IO_APIC_route_entry **ioapic_entries)
+int restore_ioapic_entries(void)
{
int apic, pin;
- if (!ioapic_entries)
- return -ENOMEM;
-
for (apic = 0; apic < nr_ioapics; apic++) {
- if (!ioapic_entries[apic])
- return -ENOMEM;
+ if (!ioapics[apic].saved_registers)
+ continue;
- for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
+ for (pin = 0; pin < ioapics[apic].nr_registers; pin++)
ioapic_write_entry(apic, pin,
- ioapic_entries[apic][pin]);
+ ioapics[apic].saved_registers[pin]);
}
return 0;
}
-void free_ioapic_entries(struct IO_APIC_route_entry **ioapic_entries)
-{
- int apic;
-
- for (apic = 0; apic < nr_ioapics; apic++)
- kfree(ioapic_entries[apic]);
-
- kfree(ioapic_entries);
-}
-
/*
* Find the IRQ entry number of a certain pin.
*/
@@ -731,7 +718,7 @@ static int find_irq_entry(int apic, int pin, int type)
for (i = 0; i < mp_irq_entries; i++)
if (mp_irqs[i].irqtype == type &&
- (mp_irqs[i].dstapic == mp_ioapics[apic].apicid ||
+ (mp_irqs[i].dstapic == mpc_ioapic_id(apic) ||
mp_irqs[i].dstapic == MP_APIC_ALL) &&
mp_irqs[i].dstirq == pin)
return i;
@@ -773,7 +760,7 @@ static int __init find_isa_irq_apic(int irq, int type)
if (i < mp_irq_entries) {
int apic;
for(apic = 0; apic < nr_ioapics; apic++) {
- if (mp_ioapics[apic].apicid == mp_irqs[i].dstapic)
+ if (mpc_ioapic_id(apic) == mp_irqs[i].dstapic)
return apic;
}
}
@@ -942,6 +929,7 @@ static int pin_2_irq(int idx, int apic, int pin)
{
int irq;
int bus = mp_irqs[idx].srcbus;
+ struct mp_ioapic_gsi *gsi_cfg = mp_ioapic_gsi_routing(apic);
/*
* Debugging check, we are in big trouble if this message pops up!
@@ -952,7 +940,7 @@ static int pin_2_irq(int idx, int apic, int pin)
if (test_bit(bus, mp_bus_not_pci)) {
irq = mp_irqs[idx].srcbusirq;
} else {
- u32 gsi = mp_gsi_routing[apic].gsi_base + pin;
+ u32 gsi = gsi_cfg->gsi_base + pin;
if (gsi >= NR_IRQS_LEGACY)
irq = gsi;
@@ -1003,7 +991,7 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin,
int lbus = mp_irqs[i].srcbus;
for (apic = 0; apic < nr_ioapics; apic++)
- if (mp_ioapics[apic].apicid == mp_irqs[i].dstapic ||
+ if (mpc_ioapic_id(apic) == mp_irqs[i].dstapic ||
mp_irqs[i].dstapic == MP_APIC_ALL)
break;
@@ -1222,7 +1210,7 @@ static inline int IO_APIC_irq_trigger(int irq)
int apic, idx, pin;
for (apic = 0; apic < nr_ioapics; apic++) {
- for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
+ for (pin = 0; pin < ioapics[apic].nr_registers; pin++) {
idx = find_irq_entry(apic, pin, mp_INT);
if ((idx != -1) && (irq == pin_2_irq(idx, apic, pin)))
return irq_trigger(idx);
@@ -1350,14 +1338,14 @@ static void setup_ioapic_irq(int apic_id, int pin, unsigned int irq,
apic_printk(APIC_VERBOSE,KERN_DEBUG
"IOAPIC[%d]: Set routing entry (%d-%d -> 0x%x -> "
"IRQ %d Mode:%i Active:%i)\n",
- apic_id, mp_ioapics[apic_id].apicid, pin, cfg->vector,
+ apic_id, mpc_ioapic_id(apic_id), pin, cfg->vector,
irq, trigger, polarity);
- if (setup_ioapic_entry(mp_ioapics[apic_id].apicid, irq, &entry,
+ if (setup_ioapic_entry(mpc_ioapic_id(apic_id), irq, &entry,
dest, trigger, polarity, cfg->vector, pin)) {
printk("Failed to setup ioapic entry for ioapic %d, pin %d\n",
- mp_ioapics[apic_id].apicid, pin);
+ mpc_ioapic_id(apic_id), pin);
__clear_irq_vector(irq, cfg);
return;
}
@@ -1369,17 +1357,13 @@ static void setup_ioapic_irq(int apic_id, int pin, unsigned int irq,
ioapic_write_entry(apic_id, pin, entry);
}
-static struct {
- DECLARE_BITMAP(pin_programmed, MP_MAX_IOAPIC_PIN + 1);
-} mp_ioapic_routing[MAX_IO_APICS];
-
static bool __init io_apic_pin_not_connected(int idx, int apic_id, int pin)
{
if (idx != -1)
return false;
apic_printk(APIC_VERBOSE, KERN_DEBUG " apic %d pin %d not connected\n",
- mp_ioapics[apic_id].apicid, pin);
+ mpc_ioapic_id(apic_id), pin);
return true;
}
@@ -1389,7 +1373,7 @@ static void __init __io_apic_setup_irqs(unsigned int apic_id)
struct io_apic_irq_attr attr;
unsigned int pin, irq;
- for (pin = 0; pin < nr_ioapic_registers[apic_id]; pin++) {
+ for (pin = 0; pin < ioapics[apic_id].nr_registers; pin++) {
idx = find_irq_entry(apic_id, pin, mp_INT);
if (io_apic_pin_not_connected(idx, apic_id, pin))
continue;
@@ -1511,7 +1495,7 @@ __apicdebuginit(void) print_IO_APIC(void)
printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries);
for (i = 0; i < nr_ioapics; i++)
printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n",
- mp_ioapics[i].apicid, nr_ioapic_registers[i]);
+ mpc_ioapic_id(i), ioapics[i].nr_registers);
/*
* We are a bit conservative about what we expect. We have to
@@ -1531,7 +1515,7 @@ __apicdebuginit(void) print_IO_APIC(void)
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
printk("\n");
- printk(KERN_DEBUG "IO APIC #%d......\n", mp_ioapics[apic].apicid);
+ printk(KERN_DEBUG "IO APIC #%d......\n", mpc_ioapic_id(apic));
printk(KERN_DEBUG ".... register #00: %08X\n", reg_00.raw);
printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.bits.ID);
printk(KERN_DEBUG "....... : Delivery Type: %X\n", reg_00.bits.delivery_type);
@@ -1825,7 +1809,7 @@ void __init enable_IO_APIC(void)
for(apic = 0; apic < nr_ioapics; apic++) {
int pin;
/* See if any of the pins is in ExtINT mode */
- for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
+ for (pin = 0; pin < ioapics[apic].nr_registers; pin++) {
struct IO_APIC_route_entry entry;
entry = ioapic_read_entry(apic, pin);
@@ -1949,14 +1933,14 @@ void __init setup_ioapic_ids_from_mpc_nocheck(void)
reg_00.raw = io_apic_read(apic_id, 0);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
- old_id = mp_ioapics[apic_id].apicid;
+ old_id = mpc_ioapic_id(apic_id);
- if (mp_ioapics[apic_id].apicid >= get_physical_broadcast()) {
+ if (mpc_ioapic_id(apic_id) >= get_physical_broadcast()) {
printk(KERN_ERR "BIOS bug, IO-APIC#%d ID is %d in the MPC table!...\n",
- apic_id, mp_ioapics[apic_id].apicid);
+ apic_id, mpc_ioapic_id(apic_id));
printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
reg_00.bits.ID);
- mp_ioapics[apic_id].apicid = reg_00.bits.ID;
+ ioapics[apic_id].mp_config.apicid = reg_00.bits.ID;
}
/*
@@ -1965,9 +1949,9 @@ void __init setup_ioapic_ids_from_mpc_nocheck(void)
* 'stuck on smp_invalidate_needed IPI wait' messages.
*/
if (apic->check_apicid_used(&phys_id_present_map,
- mp_ioapics[apic_id].apicid)) {
+ mpc_ioapic_id(apic_id))) {
printk(KERN_ERR "BIOS bug, IO-APIC#%d ID %d is already used!...\n",
- apic_id, mp_ioapics[apic_id].apicid);
+ apic_id, mpc_ioapic_id(apic_id));
for (i = 0; i < get_physical_broadcast(); i++)
if (!physid_isset(i, phys_id_present_map))
break;
@@ -1976,13 +1960,14 @@ void __init setup_ioapic_ids_from_mpc_nocheck(void)
printk(KERN_ERR "... fixing up to %d. (tell your hw vendor)\n",
i);
physid_set(i, phys_id_present_map);
- mp_ioapics[apic_id].apicid = i;
+ ioapics[apic_id].mp_config.apicid = i;
} else {
physid_mask_t tmp;
- apic->apicid_to_cpu_present(mp_ioapics[apic_id].apicid, &tmp);
+ apic->apicid_to_cpu_present(mpc_ioapic_id(apic_id),
+ &tmp);
apic_printk(APIC_VERBOSE, "Setting %d in the "
"phys_id_present_map\n",
- mp_ioapics[apic_id].apicid);
+ mpc_ioapic_id(apic_id));
physids_or(phys_id_present_map, phys_id_present_map, tmp);
}
@@ -1990,24 +1975,24 @@ void __init setup_ioapic_ids_from_mpc_nocheck(void)
* We need to adjust the IRQ routing table
* if the ID changed.
*/
- if (old_id != mp_ioapics[apic_id].apicid)
+ if (old_id != mpc_ioapic_id(apic_id))
for (i = 0; i < mp_irq_entries; i++)
if (mp_irqs[i].dstapic == old_id)
mp_irqs[i].dstapic
- = mp_ioapics[apic_id].apicid;
+ = mpc_ioapic_id(apic_id);
/*
* Update the ID register according to the right value
* from the MPC table if they are different.
*/
- if (mp_ioapics[apic_id].apicid == reg_00.bits.ID)
+ if (mpc_ioapic_id(apic_id) == reg_00.bits.ID)
continue;
apic_printk(APIC_VERBOSE, KERN_INFO
"...changing IO-APIC physical APIC ID to %d ...",
- mp_ioapics[apic_id].apicid);
+ mpc_ioapic_id(apic_id));
- reg_00.bits.ID = mp_ioapics[apic_id].apicid;
+ reg_00.bits.ID = mpc_ioapic_id(apic_id);
raw_spin_lock_irqsave(&ioapic_lock, flags);
io_apic_write(apic_id, 0, reg_00.raw);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
@@ -2018,7 +2003,7 @@ void __init setup_ioapic_ids_from_mpc_nocheck(void)
raw_spin_lock_irqsave(&ioapic_lock, flags);
reg_00.raw = io_apic_read(apic_id, 0);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
- if (reg_00.bits.ID != mp_ioapics[apic_id].apicid)
+ if (reg_00.bits.ID != mpc_ioapic_id(apic_id))
printk("could not set ID!\n");
else
apic_printk(APIC_VERBOSE, " ok.\n");
@@ -2404,7 +2389,7 @@ static void eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
raw_spin_lock_irqsave(&ioapic_lock, flags);
for_each_irq_pin(entry, cfg->irq_2_pin) {
- if (mp_ioapics[entry->apic].apicver >= 0x20) {
+ if (mpc_ioapic_ver(entry->apic) >= 0x20) {
/*
* Intr-remapping uses pin number as the virtual vector
* in the RTE. Actual vector is programmed in
@@ -2918,49 +2903,19 @@ static int __init io_apic_bug_finalize(void)
late_initcall(io_apic_bug_finalize);
-static struct IO_APIC_route_entry *ioapic_saved_data[MAX_IO_APICS];
-
-static void suspend_ioapic(int ioapic_id)
+static void resume_ioapic_id(int ioapic_id)
{
- struct IO_APIC_route_entry *saved_data = ioapic_saved_data[ioapic_id];
- int i;
-
- if (!saved_data)
- return;
-
- for (i = 0; i < nr_ioapic_registers[ioapic_id]; i++)
- saved_data[i] = ioapic_read_entry(ioapic_id, i);
-}
-
-static int ioapic_suspend(void)
-{
- int ioapic_id;
-
- for (ioapic_id = 0; ioapic_id < nr_ioapics; ioapic_id++)
- suspend_ioapic(ioapic_id);
-
- return 0;
-}
-
-static void resume_ioapic(int ioapic_id)
-{
- struct IO_APIC_route_entry *saved_data = ioapic_saved_data[ioapic_id];
unsigned long flags;
union IO_APIC_reg_00 reg_00;
- int i;
- if (!saved_data)
- return;
raw_spin_lock_irqsave(&ioapic_lock, flags);
reg_00.raw = io_apic_read(ioapic_id, 0);
- if (reg_00.bits.ID != mp_ioapics[ioapic_id].apicid) {
- reg_00.bits.ID = mp_ioapics[ioapic_id].apicid;
+ if (reg_00.bits.ID != mpc_ioapic_id(ioapic_id)) {
+ reg_00.bits.ID = mpc_ioapic_id(ioapic_id);
io_apic_write(ioapic_id, 0, reg_00.raw);
}
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
- for (i = 0; i < nr_ioapic_registers[ioapic_id]; i++)
- ioapic_write_entry(ioapic_id, i, saved_data[i]);
}
static void ioapic_resume(void)
@@ -2968,28 +2923,18 @@ static void ioapic_resume(void)
int ioapic_id;
for (ioapic_id = nr_ioapics - 1; ioapic_id >= 0; ioapic_id--)
- resume_ioapic(ioapic_id);
+ resume_ioapic_id(ioapic_id);
+
+ restore_ioapic_entries();
}
static struct syscore_ops ioapic_syscore_ops = {
- .suspend = ioapic_suspend,
+ .suspend = save_ioapic_entries,
.resume = ioapic_resume,
};
static int __init ioapic_init_ops(void)
{
- int i;
-
- for (i = 0; i < nr_ioapics; i++) {
- unsigned int size;
-
- size = nr_ioapic_registers[i]
- * sizeof(struct IO_APIC_route_entry);
- ioapic_saved_data[i] = kzalloc(size, GFP_KERNEL);
- if (!ioapic_saved_data[i])
- pr_err("IOAPIC %d: suspend/resume impossible!\n", i);
- }
-
register_syscore_ops(&ioapic_syscore_ops);
return 0;
@@ -3592,14 +3537,14 @@ int io_apic_setup_irq_pin_once(unsigned int irq, int node,
int ret;
/* Avoid redundant programming */
- if (test_bit(pin, mp_ioapic_routing[id].pin_programmed)) {
+ if (test_bit(pin, ioapics[id].pin_programmed)) {
pr_debug("Pin %d-%d already programmed\n",
- mp_ioapics[id].apicid, pin);
+ mpc_ioapic_id(id), pin);
return 0;
}
ret = io_apic_setup_irq_pin(irq, node, attr);
if (!ret)
- set_bit(pin, mp_ioapic_routing[id].pin_programmed);
+ set_bit(pin, ioapics[id].pin_programmed);
return ret;
}
@@ -3764,8 +3709,7 @@ static u8 __init io_apic_unique_id(u8 id)
bitmap_zero(used, 256);
for (i = 0; i < nr_ioapics; i++) {
- struct mpc_ioapic *ia = &mp_ioapics[i];
- __set_bit(ia->apicid, used);
+ __set_bit(mpc_ioapic_id(i), used);
}
if (!test_bit(id, used))
return id;
@@ -3825,7 +3769,7 @@ void __init setup_ioapic_dest(void)
return;
for (ioapic = 0; ioapic < nr_ioapics; ioapic++)
- for (pin = 0; pin < nr_ioapic_registers[ioapic]; pin++) {
+ for (pin = 0; pin < ioapics[ioapic].nr_registers; pin++) {
irq_entry = find_irq_entry(ioapic, pin, mp_INT);
if (irq_entry == -1)
continue;
@@ -3896,7 +3840,7 @@ void __init ioapic_and_gsi_init(void)
ioapic_res = ioapic_setup_resources(nr_ioapics);
for (i = 0; i < nr_ioapics; i++) {
if (smp_found_config) {
- ioapic_phys = mp_ioapics[i].apicaddr;
+ ioapic_phys = mpc_ioapic_addr(i);
#ifdef CONFIG_X86_32
if (!ioapic_phys) {
printk(KERN_ERR
@@ -3956,8 +3900,9 @@ int mp_find_ioapic(u32 gsi)
/* Find the IOAPIC that manages this GSI. */
for (i = 0; i < nr_ioapics; i++) {
- if ((gsi >= mp_gsi_routing[i].gsi_base)
- && (gsi <= mp_gsi_routing[i].gsi_end))
+ struct mp_ioapic_gsi *gsi_cfg = mp_ioapic_gsi_routing(i);
+ if ((gsi >= gsi_cfg->gsi_base)
+ && (gsi <= gsi_cfg->gsi_end))
return i;
}
@@ -3967,12 +3912,16 @@ int mp_find_ioapic(u32 gsi)
int mp_find_ioapic_pin(int ioapic, u32 gsi)
{
+ struct mp_ioapic_gsi *gsi_cfg;
+
if (WARN_ON(ioapic == -1))
return -1;
- if (WARN_ON(gsi > mp_gsi_routing[ioapic].gsi_end))
+
+ gsi_cfg = mp_ioapic_gsi_routing(ioapic);
+ if (WARN_ON(gsi > gsi_cfg->gsi_end))
return -1;
- return gsi - mp_gsi_routing[ioapic].gsi_base;
+ return gsi - gsi_cfg->gsi_base;
}
static __init int bad_ioapic(unsigned long address)
@@ -3994,40 +3943,42 @@ void __init mp_register_ioapic(int id, u32 address, u32 gsi_base)
{
int idx = 0;
int entries;
+ struct mp_ioapic_gsi *gsi_cfg;
if (bad_ioapic(address))
return;
idx = nr_ioapics;
- mp_ioapics[idx].type = MP_IOAPIC;
- mp_ioapics[idx].flags = MPC_APIC_USABLE;
- mp_ioapics[idx].apicaddr = address;
+ ioapics[idx].mp_config.type = MP_IOAPIC;
+ ioapics[idx].mp_config.flags = MPC_APIC_USABLE;
+ ioapics[idx].mp_config.apicaddr = address;
set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
- mp_ioapics[idx].apicid = io_apic_unique_id(id);
- mp_ioapics[idx].apicver = io_apic_get_version(idx);
+ ioapics[idx].mp_config.apicid = io_apic_unique_id(id);
+ ioapics[idx].mp_config.apicver = io_apic_get_version(idx);
/*
* Build basic GSI lookup table to facilitate gsi->io_apic lookups
* and to prevent reprogramming of IOAPIC pins (PCI GSIs).
*/
entries = io_apic_get_redir_entries(idx);
- mp_gsi_routing[idx].gsi_base = gsi_base;
- mp_gsi_routing[idx].gsi_end = gsi_base + entries - 1;
+ gsi_cfg = mp_ioapic_gsi_routing(idx);
+ gsi_cfg->gsi_base = gsi_base;
+ gsi_cfg->gsi_end = gsi_base + entries - 1;
/*
* The number of IO-APIC IRQ registers (== #pins):
*/
- nr_ioapic_registers[idx] = entries;
+ ioapics[idx].nr_registers = entries;
- if (mp_gsi_routing[idx].gsi_end >= gsi_top)
- gsi_top = mp_gsi_routing[idx].gsi_end + 1;
+ if (gsi_cfg->gsi_end >= gsi_top)
+ gsi_top = gsi_cfg->gsi_end + 1;
printk(KERN_INFO "IOAPIC[%d]: apic_id %d, version %d, address 0x%x, "
- "GSI %d-%d\n", idx, mp_ioapics[idx].apicid,
- mp_ioapics[idx].apicver, mp_ioapics[idx].apicaddr,
- mp_gsi_routing[idx].gsi_base, mp_gsi_routing[idx].gsi_end);
+ "GSI %d-%d\n", idx, mpc_ioapic_id(idx),
+ mpc_ioapic_ver(idx), mpc_ioapic_addr(idx),
+ gsi_cfg->gsi_base, gsi_cfg->gsi_end);
nr_ioapics++;
}
diff --git a/arch/x86/kernel/apic/numaq_32.c b/arch/x86/kernel/apic/numaq_32.c
index 6273eee5134b..c4a61ca1349a 100644
--- a/arch/x86/kernel/apic/numaq_32.c
+++ b/arch/x86/kernel/apic/numaq_32.c
@@ -48,8 +48,6 @@
#include <asm/e820.h>
#include <asm/ipi.h>
-#define MB_TO_PAGES(addr) ((addr) << (20 - PAGE_SHIFT))
-
int found_numaq;
/*
@@ -79,31 +77,20 @@ int quad_local_to_mp_bus_id[NR_CPUS/4][4];
static inline void numaq_register_node(int node, struct sys_cfg_data *scd)
{
struct eachquadmem *eq = scd->eq + node;
+ u64 start = (u64)(eq->hi_shrd_mem_start - eq->priv_mem_size) << 20;
+ u64 end = (u64)(eq->hi_shrd_mem_start + eq->hi_shrd_mem_size) << 20;
+ int ret;
- node_set_online(node);
-
- /* Convert to pages */
- node_start_pfn[node] =
- MB_TO_PAGES(eq->hi_shrd_mem_start - eq->priv_mem_size);
-
- node_end_pfn[node] =
- MB_TO_PAGES(eq->hi_shrd_mem_start + eq->hi_shrd_mem_size);
-
- memblock_x86_register_active_regions(node, node_start_pfn[node],
- node_end_pfn[node]);
-
- memory_present(node, node_start_pfn[node], node_end_pfn[node]);
-
- node_remap_size[node] = node_memmap_size_bytes(node,
- node_start_pfn[node],
- node_end_pfn[node]);
+ node_set(node, numa_nodes_parsed);
+ ret = numa_add_memblk(node, start, end);
+ BUG_ON(ret < 0);
}
/*
* Function: smp_dump_qct()
*
* Description: gets memory layout from the quad config table. This
- * function also updates node_online_map with the nodes (quads) present.
+ * function also updates numa_nodes_parsed with the nodes (quads) present.
*/
static void __init smp_dump_qct(void)
{
@@ -112,7 +99,6 @@ static void __init smp_dump_qct(void)
scd = (void *)__va(SYS_CFG_DATA_PRIV_ADDR);
- nodes_clear(node_online_map);
for_each_node(node) {
if (scd->quads_present31_0 & (1 << node))
numaq_register_node(node, scd);
@@ -282,14 +268,14 @@ static __init void early_check_numaq(void)
}
}
-int __init get_memcfg_numaq(void)
+int __init numaq_numa_init(void)
{
early_check_numaq();
if (!found_numaq)
- return 0;
+ return -ENOENT;
smp_dump_qct();
- return 1;
+ return 0;
}
#define NUMAQ_APIC_DFR_VALUE (APIC_DFR_CLUSTER)
@@ -486,8 +472,8 @@ static void numaq_setup_portio_remap(void)
(u_long) xquad_portio, (u_long) num_quads*XQUAD_PORTIO_QUAD);
}
-/* Use __refdata to keep false positive warning calm. */
-struct apic __refdata apic_numaq = {
+/* Use __refdata to keep false positive warning calm. */
+static struct apic __refdata apic_numaq = {
.name = "NUMAQ",
.probe = probe_numaq,
@@ -551,3 +537,5 @@ struct apic __refdata apic_numaq = {
.x86_32_early_logical_apicid = noop_x86_32_early_logical_apicid,
.x86_32_numa_cpu_node = numaq_numa_cpu_node,
};
+
+apic_driver(apic_numaq);
diff --git a/arch/x86/kernel/apic/probe_32.c b/arch/x86/kernel/apic/probe_32.c
index fc84c7b61108..b5254ad044ab 100644
--- a/arch/x86/kernel/apic/probe_32.c
+++ b/arch/x86/kernel/apic/probe_32.c
@@ -52,31 +52,6 @@ static int __init print_ipi_mode(void)
}
late_initcall(print_ipi_mode);
-void __init default_setup_apic_routing(void)
-{
- int version = apic_version[boot_cpu_physical_apicid];
-
- if (num_possible_cpus() > 8) {
- switch (boot_cpu_data.x86_vendor) {
- case X86_VENDOR_INTEL:
- if (!APIC_XAPIC(version)) {
- def_to_bigsmp = 0;
- break;
- }
- /* If P4 and above fall through */
- case X86_VENDOR_AMD:
- def_to_bigsmp = 1;
- }
- }
-
-#ifdef CONFIG_X86_BIGSMP
- generic_bigsmp_probe();
-#endif
-
- if (apic->setup_apic_routing)
- apic->setup_apic_routing();
-}
-
static int default_x86_32_early_logical_apicid(int cpu)
{
return 1 << cpu;
@@ -112,7 +87,7 @@ static int probe_default(void)
return 1;
}
-struct apic apic_default = {
+static struct apic apic_default = {
.name = "default",
.probe = probe_default,
@@ -172,47 +147,24 @@ struct apic apic_default = {
.safe_wait_icr_idle = native_safe_apic_wait_icr_idle,
.x86_32_early_logical_apicid = default_x86_32_early_logical_apicid,
- .x86_32_numa_cpu_node = default_x86_32_numa_cpu_node,
};
-extern struct apic apic_numaq;
-extern struct apic apic_summit;
-extern struct apic apic_bigsmp;
-extern struct apic apic_es7000;
-extern struct apic apic_es7000_cluster;
+apic_driver(apic_default);
struct apic *apic = &apic_default;
EXPORT_SYMBOL_GPL(apic);
-static struct apic *apic_probe[] __initdata = {
-#ifdef CONFIG_X86_NUMAQ
- &apic_numaq,
-#endif
-#ifdef CONFIG_X86_SUMMIT
- &apic_summit,
-#endif
-#ifdef CONFIG_X86_BIGSMP
- &apic_bigsmp,
-#endif
-#ifdef CONFIG_X86_ES7000
- &apic_es7000,
- &apic_es7000_cluster,
-#endif
- &apic_default, /* must be last */
- NULL,
-};
-
static int cmdline_apic __initdata;
static int __init parse_apic(char *arg)
{
- int i;
+ struct apic **drv;
if (!arg)
return -EINVAL;
- for (i = 0; apic_probe[i]; i++) {
- if (!strcmp(apic_probe[i]->name, arg)) {
- apic = apic_probe[i];
+ for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) {
+ if (!strcmp((*drv)->name, arg)) {
+ apic = *drv;
cmdline_apic = 1;
return 0;
}
@@ -223,38 +175,58 @@ static int __init parse_apic(char *arg)
}
early_param("apic", parse_apic);
-void __init generic_bigsmp_probe(void)
+void __init default_setup_apic_routing(void)
{
+ int version = apic_version[boot_cpu_physical_apicid];
+
+ if (num_possible_cpus() > 8) {
+ switch (boot_cpu_data.x86_vendor) {
+ case X86_VENDOR_INTEL:
+ if (!APIC_XAPIC(version)) {
+ def_to_bigsmp = 0;
+ break;
+ }
+ /* If P4 and above fall through */
+ case X86_VENDOR_AMD:
+ def_to_bigsmp = 1;
+ }
+ }
+
#ifdef CONFIG_X86_BIGSMP
/*
- * This routine is used to switch to bigsmp mode when
+ * This is used to switch to bigsmp mode when
* - There is no apic= option specified by the user
* - generic_apic_probe() has chosen apic_default as the sub_arch
* - we find more than 8 CPUs in acpi LAPIC listing with xAPIC support
*/
if (!cmdline_apic && apic == &apic_default) {
- if (apic_bigsmp.probe()) {
- apic = &apic_bigsmp;
+ struct apic *bigsmp = generic_bigsmp_probe();
+ if (bigsmp) {
+ apic = bigsmp;
printk(KERN_INFO "Overriding APIC driver with %s\n",
apic->name);
}
}
#endif
+
+ if (apic->setup_apic_routing)
+ apic->setup_apic_routing();
}
void __init generic_apic_probe(void)
{
if (!cmdline_apic) {
- int i;
- for (i = 0; apic_probe[i]; i++) {
- if (apic_probe[i]->probe()) {
- apic = apic_probe[i];
+ struct apic **drv;
+
+ for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) {
+ if ((*drv)->probe()) {
+ apic = *drv;
break;
}
}
/* Not visible without early console */
- if (!apic_probe[i])
+ if (drv == __apicdrivers_end)
panic("Didn't find an APIC driver");
}
printk(KERN_INFO "Using APIC driver %s\n", apic->name);
@@ -265,16 +237,16 @@ void __init generic_apic_probe(void)
int __init
generic_mps_oem_check(struct mpc_table *mpc, char *oem, char *productid)
{
- int i;
+ struct apic **drv;
- for (i = 0; apic_probe[i]; ++i) {
- if (!apic_probe[i]->mps_oem_check)
+ for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) {
+ if (!((*drv)->mps_oem_check))
continue;
- if (!apic_probe[i]->mps_oem_check(mpc, oem, productid))
+ if (!(*drv)->mps_oem_check(mpc, oem, productid))
continue;
if (!cmdline_apic) {
- apic = apic_probe[i];
+ apic = *drv;
printk(KERN_INFO "Switched to APIC driver `%s'.\n",
apic->name);
}
@@ -285,16 +257,16 @@ generic_mps_oem_check(struct mpc_table *mpc, char *oem, char *productid)
int __init default_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
{
- int i;
+ struct apic **drv;
- for (i = 0; apic_probe[i]; ++i) {
- if (!apic_probe[i]->acpi_madt_oem_check)
+ for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) {
+ if (!(*drv)->acpi_madt_oem_check)
continue;
- if (!apic_probe[i]->acpi_madt_oem_check(oem_id, oem_table_id))
+ if (!(*drv)->acpi_madt_oem_check(oem_id, oem_table_id))
continue;
if (!cmdline_apic) {
- apic = apic_probe[i];
+ apic = *drv;
printk(KERN_INFO "Switched to APIC driver `%s'.\n",
apic->name);
}
diff --git a/arch/x86/kernel/apic/probe_64.c b/arch/x86/kernel/apic/probe_64.c
index d8c4a6feb286..3fe986698929 100644
--- a/arch/x86/kernel/apic/probe_64.c
+++ b/arch/x86/kernel/apic/probe_64.c
@@ -23,27 +23,6 @@
#include <asm/ipi.h>
#include <asm/setup.h>
-extern struct apic apic_flat;
-extern struct apic apic_physflat;
-extern struct apic apic_x2xpic_uv_x;
-extern struct apic apic_x2apic_phys;
-extern struct apic apic_x2apic_cluster;
-
-struct apic __read_mostly *apic = &apic_flat;
-EXPORT_SYMBOL_GPL(apic);
-
-static struct apic *apic_probe[] __initdata = {
-#ifdef CONFIG_X86_UV
- &apic_x2apic_uv_x,
-#endif
-#ifdef CONFIG_X86_X2APIC
- &apic_x2apic_phys,
- &apic_x2apic_cluster,
-#endif
- &apic_physflat,
- NULL,
-};
-
static int apicid_phys_pkg_id(int initial_apic_id, int index_msb)
{
return hard_smp_processor_id() >> index_msb;
@@ -54,26 +33,20 @@ static int apicid_phys_pkg_id(int initial_apic_id, int index_msb)
*/
void __init default_setup_apic_routing(void)
{
+ struct apic **drv;
enable_IR_x2apic();
-#ifdef CONFIG_X86_X2APIC
- if (x2apic_mode
-#ifdef CONFIG_X86_UV
- && apic != &apic_x2apic_uv_x
-#endif
- ) {
- if (x2apic_phys)
- apic = &apic_x2apic_phys;
- else
- apic = &apic_x2apic_cluster;
+ for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) {
+ if ((*drv)->probe && (*drv)->probe()) {
+ if (apic != *drv) {
+ apic = *drv;
+ pr_info("Switched APIC routing to %s.\n",
+ apic->name);
+ }
+ break;
+ }
}
-#endif
-
- if (apic == &apic_flat && num_possible_cpus() > 8)
- apic = &apic_physflat;
-
- printk(KERN_INFO "Setting APIC routing to %s\n", apic->name);
if (is_vsmp_box()) {
/* need to update phys_pkg_id */
@@ -90,13 +63,15 @@ void apic_send_IPI_self(int vector)
int __init default_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
{
- int i;
+ struct apic **drv;
- for (i = 0; apic_probe[i]; ++i) {
- if (apic_probe[i]->acpi_madt_oem_check(oem_id, oem_table_id)) {
- apic = apic_probe[i];
- printk(KERN_INFO "Setting APIC routing to %s.\n",
- apic->name);
+ for (drv = __apicdrivers; drv < __apicdrivers_end; drv++) {
+ if ((*drv)->acpi_madt_oem_check(oem_id, oem_table_id)) {
+ if (apic != *drv) {
+ apic = *drv;
+ pr_info("Setting APIC routing to %s.\n",
+ apic->name);
+ }
return 1;
}
}
diff --git a/arch/x86/kernel/apic/summit_32.c b/arch/x86/kernel/apic/summit_32.c
index e4b8059b414a..19114423c58c 100644
--- a/arch/x86/kernel/apic/summit_32.c
+++ b/arch/x86/kernel/apic/summit_32.c
@@ -491,7 +491,7 @@ void setup_summit(void)
}
#endif
-struct apic apic_summit = {
+static struct apic apic_summit = {
.name = "summit",
.probe = probe_summit,
@@ -551,5 +551,6 @@ struct apic apic_summit = {
.safe_wait_icr_idle = native_safe_apic_wait_icr_idle,
.x86_32_early_logical_apicid = summit_early_logical_apicid,
- .x86_32_numa_cpu_node = default_x86_32_numa_cpu_node,
};
+
+apic_driver(apic_summit);
diff --git a/arch/x86/kernel/apic/x2apic_cluster.c b/arch/x86/kernel/apic/x2apic_cluster.c
index 90949bbd566d..500795875827 100644
--- a/arch/x86/kernel/apic/x2apic_cluster.c
+++ b/arch/x86/kernel/apic/x2apic_cluster.c
@@ -5,118 +5,95 @@
#include <linux/ctype.h>
#include <linux/init.h>
#include <linux/dmar.h>
+#include <linux/cpu.h>
#include <asm/smp.h>
-#include <asm/apic.h>
-#include <asm/ipi.h>
+#include <asm/x2apic.h>
static DEFINE_PER_CPU(u32, x86_cpu_to_logical_apicid);
+static DEFINE_PER_CPU(cpumask_var_t, cpus_in_cluster);
+static DEFINE_PER_CPU(cpumask_var_t, ipi_mask);
static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
{
return x2apic_enabled();
}
-/*
- * need to use more than cpu 0, because we need more vectors when
- * MSI-X are used.
- */
-static const struct cpumask *x2apic_target_cpus(void)
+static inline u32 x2apic_cluster(int cpu)
{
- return cpu_online_mask;
-}
-
-/*
- * for now each logical cpu is in its own vector allocation domain.
- */
-static void x2apic_vector_allocation_domain(int cpu, struct cpumask *retmask)
-{
- cpumask_clear(retmask);
- cpumask_set_cpu(cpu, retmask);
+ return per_cpu(x86_cpu_to_logical_apicid, cpu) >> 16;
}
static void
- __x2apic_send_IPI_dest(unsigned int apicid, int vector, unsigned int dest)
+__x2apic_send_IPI_mask(const struct cpumask *mask, int vector, int apic_dest)
{
- unsigned long cfg;
+ struct cpumask *cpus_in_cluster_ptr;
+ struct cpumask *ipi_mask_ptr;
+ unsigned int cpu, this_cpu;
+ unsigned long flags;
+ u32 dest;
+
+ x2apic_wrmsr_fence();
+
+ local_irq_save(flags);
- cfg = __prepare_ICR(0, vector, dest);
+ this_cpu = smp_processor_id();
/*
- * send the IPI.
+ * We are to modify mask, so we need an own copy
+ * and be sure it's manipulated with irq off.
*/
- native_x2apic_icr_write(cfg, apicid);
-}
+ ipi_mask_ptr = __raw_get_cpu_var(ipi_mask);
+ cpumask_copy(ipi_mask_ptr, mask);
-/*
- * for now, we send the IPI's one by one in the cpumask.
- * TBD: Based on the cpu mask, we can send the IPI's to the cluster group
- * at once. We have 16 cpu's in a cluster. This will minimize IPI register
- * writes.
- */
-static void x2apic_send_IPI_mask(const struct cpumask *mask, int vector)
-{
- unsigned long query_cpu;
- unsigned long flags;
+ /*
+ * The idea is to send one IPI per cluster.
+ */
+ for_each_cpu(cpu, ipi_mask_ptr) {
+ unsigned long i;
- x2apic_wrmsr_fence();
+ cpus_in_cluster_ptr = per_cpu(cpus_in_cluster, cpu);
+ dest = 0;
- local_irq_save(flags);
- for_each_cpu(query_cpu, mask) {
- __x2apic_send_IPI_dest(
- per_cpu(x86_cpu_to_logical_apicid, query_cpu),
- vector, apic->dest_logical);
+ /* Collect cpus in cluster. */
+ for_each_cpu_and(i, ipi_mask_ptr, cpus_in_cluster_ptr) {
+ if (apic_dest == APIC_DEST_ALLINC || i != this_cpu)
+ dest |= per_cpu(x86_cpu_to_logical_apicid, i);
+ }
+
+ if (!dest)
+ continue;
+
+ __x2apic_send_IPI_dest(dest, vector, apic->dest_logical);
+ /*
+ * Cluster sibling cpus should be discared now so
+ * we would not send IPI them second time.
+ */
+ cpumask_andnot(ipi_mask_ptr, ipi_mask_ptr, cpus_in_cluster_ptr);
}
+
local_irq_restore(flags);
}
+static void x2apic_send_IPI_mask(const struct cpumask *mask, int vector)
+{
+ __x2apic_send_IPI_mask(mask, vector, APIC_DEST_ALLINC);
+}
+
static void
x2apic_send_IPI_mask_allbutself(const struct cpumask *mask, int vector)
{
- unsigned long this_cpu = smp_processor_id();
- unsigned long query_cpu;
- unsigned long flags;
-
- x2apic_wrmsr_fence();
-
- local_irq_save(flags);
- for_each_cpu(query_cpu, mask) {
- if (query_cpu == this_cpu)
- continue;
- __x2apic_send_IPI_dest(
- per_cpu(x86_cpu_to_logical_apicid, query_cpu),
- vector, apic->dest_logical);
- }
- local_irq_restore(flags);
+ __x2apic_send_IPI_mask(mask, vector, APIC_DEST_ALLBUT);
}
static void x2apic_send_IPI_allbutself(int vector)
{
- unsigned long this_cpu = smp_processor_id();
- unsigned long query_cpu;
- unsigned long flags;
-
- x2apic_wrmsr_fence();
-
- local_irq_save(flags);
- for_each_online_cpu(query_cpu) {
- if (query_cpu == this_cpu)
- continue;
- __x2apic_send_IPI_dest(
- per_cpu(x86_cpu_to_logical_apicid, query_cpu),
- vector, apic->dest_logical);
- }
- local_irq_restore(flags);
+ __x2apic_send_IPI_mask(cpu_online_mask, vector, APIC_DEST_ALLBUT);
}
static void x2apic_send_IPI_all(int vector)
{
- x2apic_send_IPI_mask(cpu_online_mask, vector);
-}
-
-static int x2apic_apic_id_registered(void)
-{
- return 1;
+ __x2apic_send_IPI_mask(cpu_online_mask, vector, APIC_DEST_ALLINC);
}
static unsigned int x2apic_cpu_mask_to_apicid(const struct cpumask *cpumask)
@@ -151,43 +128,90 @@ x2apic_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
return per_cpu(x86_cpu_to_logical_apicid, cpu);
}
-static unsigned int x2apic_cluster_phys_get_apic_id(unsigned long x)
+static void init_x2apic_ldr(void)
{
- unsigned int id;
+ unsigned int this_cpu = smp_processor_id();
+ unsigned int cpu;
- id = x;
- return id;
+ per_cpu(x86_cpu_to_logical_apicid, this_cpu) = apic_read(APIC_LDR);
+
+ __cpu_set(this_cpu, per_cpu(cpus_in_cluster, this_cpu));
+ for_each_online_cpu(cpu) {
+ if (x2apic_cluster(this_cpu) != x2apic_cluster(cpu))
+ continue;
+ __cpu_set(this_cpu, per_cpu(cpus_in_cluster, cpu));
+ __cpu_set(cpu, per_cpu(cpus_in_cluster, this_cpu));
+ }
}
-static unsigned long set_apic_id(unsigned int id)
+ /*
+ * At CPU state changes, update the x2apic cluster sibling info.
+ */
+static int __cpuinit
+update_clusterinfo(struct notifier_block *nfb, unsigned long action, void *hcpu)
{
- unsigned long x;
+ unsigned int this_cpu = (unsigned long)hcpu;
+ unsigned int cpu;
+ int err = 0;
+
+ switch (action) {
+ case CPU_UP_PREPARE:
+ if (!zalloc_cpumask_var(&per_cpu(cpus_in_cluster, this_cpu),
+ GFP_KERNEL)) {
+ err = -ENOMEM;
+ } else if (!zalloc_cpumask_var(&per_cpu(ipi_mask, this_cpu),
+ GFP_KERNEL)) {
+ free_cpumask_var(per_cpu(cpus_in_cluster, this_cpu));
+ err = -ENOMEM;
+ }
+ break;
+ case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
+ case CPU_DEAD:
+ for_each_online_cpu(cpu) {
+ if (x2apic_cluster(this_cpu) != x2apic_cluster(cpu))
+ continue;
+ __cpu_clear(this_cpu, per_cpu(cpus_in_cluster, cpu));
+ __cpu_clear(cpu, per_cpu(cpus_in_cluster, this_cpu));
+ }
+ free_cpumask_var(per_cpu(cpus_in_cluster, this_cpu));
+ free_cpumask_var(per_cpu(ipi_mask, this_cpu));
+ break;
+ }
- x = id;
- return x;
+ return notifier_from_errno(err);
}
-static int x2apic_cluster_phys_pkg_id(int initial_apicid, int index_msb)
-{
- return initial_apicid >> index_msb;
-}
+static struct notifier_block __refdata x2apic_cpu_notifier = {
+ .notifier_call = update_clusterinfo,
+};
-static void x2apic_send_IPI_self(int vector)
+static int x2apic_init_cpu_notifier(void)
{
- apic_write(APIC_SELF_IPI, vector);
+ int cpu = smp_processor_id();
+
+ zalloc_cpumask_var(&per_cpu(cpus_in_cluster, cpu), GFP_KERNEL);
+ zalloc_cpumask_var(&per_cpu(ipi_mask, cpu), GFP_KERNEL);
+
+ BUG_ON(!per_cpu(cpus_in_cluster, cpu) || !per_cpu(ipi_mask, cpu));
+
+ __cpu_set(cpu, per_cpu(cpus_in_cluster, cpu));
+ register_hotcpu_notifier(&x2apic_cpu_notifier);
+ return 1;
}
-static void init_x2apic_ldr(void)
+static int x2apic_cluster_probe(void)
{
- int cpu = smp_processor_id();
-
- per_cpu(x86_cpu_to_logical_apicid, cpu) = apic_read(APIC_LDR);
+ if (x2apic_mode)
+ return x2apic_init_cpu_notifier();
+ else
+ return 0;
}
-struct apic apic_x2apic_cluster = {
+static struct apic apic_x2apic_cluster = {
.name = "cluster x2apic",
- .probe = NULL,
+ .probe = x2apic_cluster_probe,
.acpi_madt_oem_check = x2apic_acpi_madt_oem_check,
.apic_id_registered = x2apic_apic_id_registered,
@@ -211,11 +235,11 @@ struct apic apic_x2apic_cluster = {
.setup_portio_remap = NULL,
.check_phys_apicid_present = default_check_phys_apicid_present,
.enable_apic_mode = NULL,
- .phys_pkg_id = x2apic_cluster_phys_pkg_id,
+ .phys_pkg_id = x2apic_phys_pkg_id,
.mps_oem_check = NULL,
- .get_apic_id = x2apic_cluster_phys_get_apic_id,
- .set_apic_id = set_apic_id,
+ .get_apic_id = x2apic_get_apic_id,
+ .set_apic_id = x2apic_set_apic_id,
.apic_id_mask = 0xFFFFFFFFu,
.cpu_mask_to_apicid = x2apic_cpu_mask_to_apicid,
@@ -240,3 +264,5 @@ struct apic apic_x2apic_cluster = {
.wait_icr_idle = native_x2apic_wait_icr_idle,
.safe_wait_icr_idle = native_safe_x2apic_wait_icr_idle,
};
+
+apic_driver(apic_x2apic_cluster);
diff --git a/arch/x86/kernel/apic/x2apic_phys.c b/arch/x86/kernel/apic/x2apic_phys.c
index c7e6d6645bf4..f5373dfde21e 100644
--- a/arch/x86/kernel/apic/x2apic_phys.c
+++ b/arch/x86/kernel/apic/x2apic_phys.c
@@ -7,11 +7,12 @@
#include <linux/dmar.h>
#include <asm/smp.h>
-#include <asm/apic.h>
-#include <asm/ipi.h>
+#include <asm/x2apic.h>
int x2apic_phys;
+static struct apic apic_x2apic_phys;
+
static int set_x2apic_phys_mode(char *arg)
{
x2apic_phys = 1;
@@ -27,94 +28,46 @@ static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
return 0;
}
-/*
- * need to use more than cpu 0, because we need more vectors when
- * MSI-X are used.
- */
-static const struct cpumask *x2apic_target_cpus(void)
-{
- return cpu_online_mask;
-}
-
-static void x2apic_vector_allocation_domain(int cpu, struct cpumask *retmask)
-{
- cpumask_clear(retmask);
- cpumask_set_cpu(cpu, retmask);
-}
-
-static void __x2apic_send_IPI_dest(unsigned int apicid, int vector,
- unsigned int dest)
-{
- unsigned long cfg;
-
- cfg = __prepare_ICR(0, vector, dest);
-
- /*
- * send the IPI.
- */
- native_x2apic_icr_write(cfg, apicid);
-}
-
-static void x2apic_send_IPI_mask(const struct cpumask *mask, int vector)
+static void
+__x2apic_send_IPI_mask(const struct cpumask *mask, int vector, int apic_dest)
{
unsigned long query_cpu;
+ unsigned long this_cpu;
unsigned long flags;
x2apic_wrmsr_fence();
local_irq_save(flags);
+
+ this_cpu = smp_processor_id();
for_each_cpu(query_cpu, mask) {
+ if (apic_dest == APIC_DEST_ALLBUT && this_cpu == query_cpu)
+ continue;
__x2apic_send_IPI_dest(per_cpu(x86_cpu_to_apicid, query_cpu),
vector, APIC_DEST_PHYSICAL);
}
local_irq_restore(flags);
}
+static void x2apic_send_IPI_mask(const struct cpumask *mask, int vector)
+{
+ __x2apic_send_IPI_mask(mask, vector, APIC_DEST_ALLINC);
+}
+
static void
x2apic_send_IPI_mask_allbutself(const struct cpumask *mask, int vector)
{
- unsigned long this_cpu = smp_processor_id();
- unsigned long query_cpu;
- unsigned long flags;
-
- x2apic_wrmsr_fence();
-
- local_irq_save(flags);
- for_each_cpu(query_cpu, mask) {
- if (query_cpu != this_cpu)
- __x2apic_send_IPI_dest(
- per_cpu(x86_cpu_to_apicid, query_cpu),
- vector, APIC_DEST_PHYSICAL);
- }
- local_irq_restore(flags);
+ __x2apic_send_IPI_mask(mask, vector, APIC_DEST_ALLBUT);
}
static void x2apic_send_IPI_allbutself(int vector)
{
- unsigned long this_cpu = smp_processor_id();
- unsigned long query_cpu;
- unsigned long flags;
-
- x2apic_wrmsr_fence();
-
- local_irq_save(flags);
- for_each_online_cpu(query_cpu) {
- if (query_cpu == this_cpu)
- continue;
- __x2apic_send_IPI_dest(per_cpu(x86_cpu_to_apicid, query_cpu),
- vector, APIC_DEST_PHYSICAL);
- }
- local_irq_restore(flags);
+ __x2apic_send_IPI_mask(cpu_online_mask, vector, APIC_DEST_ALLBUT);
}
static void x2apic_send_IPI_all(int vector)
{
- x2apic_send_IPI_mask(cpu_online_mask, vector);
-}
-
-static int x2apic_apic_id_registered(void)
-{
- return 1;
+ __x2apic_send_IPI_mask(cpu_online_mask, vector, APIC_DEST_ALLINC);
}
static unsigned int x2apic_cpu_mask_to_apicid(const struct cpumask *cpumask)
@@ -149,34 +102,22 @@ x2apic_cpu_mask_to_apicid_and(const struct cpumask *cpumask,
return per_cpu(x86_cpu_to_apicid, cpu);
}
-static unsigned int x2apic_phys_get_apic_id(unsigned long x)
-{
- return x;
-}
-
-static unsigned long set_apic_id(unsigned int id)
-{
- return id;
-}
-
-static int x2apic_phys_pkg_id(int initial_apicid, int index_msb)
+static void init_x2apic_ldr(void)
{
- return initial_apicid >> index_msb;
}
-static void x2apic_send_IPI_self(int vector)
+static int x2apic_phys_probe(void)
{
- apic_write(APIC_SELF_IPI, vector);
-}
+ if (x2apic_mode && x2apic_phys)
+ return 1;
-static void init_x2apic_ldr(void)
-{
+ return apic == &apic_x2apic_phys;
}
-struct apic apic_x2apic_phys = {
+static struct apic apic_x2apic_phys = {
.name = "physical x2apic",
- .probe = NULL,
+ .probe = x2apic_phys_probe,
.acpi_madt_oem_check = x2apic_acpi_madt_oem_check,
.apic_id_registered = x2apic_apic_id_registered,
@@ -203,8 +144,8 @@ struct apic apic_x2apic_phys = {
.phys_pkg_id = x2apic_phys_pkg_id,
.mps_oem_check = NULL,
- .get_apic_id = x2apic_phys_get_apic_id,
- .set_apic_id = set_apic_id,
+ .get_apic_id = x2apic_get_apic_id,
+ .set_apic_id = x2apic_set_apic_id,
.apic_id_mask = 0xFFFFFFFFu,
.cpu_mask_to_apicid = x2apic_cpu_mask_to_apicid,
@@ -229,3 +170,5 @@ struct apic apic_x2apic_phys = {
.wait_icr_idle = native_x2apic_wait_icr_idle,
.safe_wait_icr_idle = native_safe_x2apic_wait_icr_idle,
};
+
+apic_driver(apic_x2apic_phys);
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c
index 7acd2d2ac965..f450b683dfcf 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -58,6 +58,8 @@ unsigned int uv_apicid_hibits;
EXPORT_SYMBOL_GPL(uv_apicid_hibits);
static DEFINE_SPINLOCK(uv_nmi_lock);
+static struct apic apic_x2apic_uv_x;
+
static unsigned long __init uv_early_read_mmr(unsigned long addr)
{
unsigned long val, *mmr;
@@ -326,10 +328,15 @@ static void uv_send_IPI_self(int vector)
apic_write(APIC_SELF_IPI, vector);
}
-struct apic __refdata apic_x2apic_uv_x = {
+static int uv_probe(void)
+{
+ return apic == &apic_x2apic_uv_x;
+}
+
+static struct apic __refdata apic_x2apic_uv_x = {
.name = "UV large system",
- .probe = NULL,
+ .probe = uv_probe,
.acpi_madt_oem_check = uv_acpi_madt_oem_check,
.apic_id_registered = uv_apic_id_registered,
@@ -859,3 +866,5 @@ void __init uv_system_init(void)
if (is_kdump_kernel())
reboot_type = BOOT_ACPI;
}
+
+apic_driver(apic_x2apic_uv_x);
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c
index adee12e0da1f..3bfa02235965 100644
--- a/arch/x86/kernel/apm_32.c
+++ b/arch/x86/kernel/apm_32.c
@@ -1238,7 +1238,6 @@ static int suspend(int vetoable)
dpm_suspend_noirq(PMSG_SUSPEND);
local_irq_disable();
- sysdev_suspend(PMSG_SUSPEND);
syscore_suspend();
local_irq_enable();
@@ -1258,7 +1257,6 @@ static int suspend(int vetoable)
err = (err == APM_SUCCESS) ? 0 : -EIO;
syscore_resume();
- sysdev_resume();
local_irq_enable();
dpm_resume_noirq(PMSG_RESUME);
@@ -1282,7 +1280,6 @@ static void standby(void)
dpm_suspend_noirq(PMSG_SUSPEND);
local_irq_disable();
- sysdev_suspend(PMSG_SUSPEND);
syscore_suspend();
local_irq_enable();
@@ -1292,7 +1289,6 @@ static void standby(void)
local_irq_disable();
syscore_resume();
- sysdev_resume();
local_irq_enable();
dpm_resume_noirq(PMSG_RESUME);
diff --git a/arch/x86/kernel/cpu/Makefile b/arch/x86/kernel/cpu/Makefile
index 3f0ebe429a01..6042981d0309 100644
--- a/arch/x86/kernel/cpu/Makefile
+++ b/arch/x86/kernel/cpu/Makefile
@@ -30,7 +30,6 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o
obj-$(CONFIG_X86_MCE) += mcheck/
obj-$(CONFIG_MTRR) += mtrr/
-obj-$(CONFIG_CPU_FREQ) += cpufreq/
obj-$(CONFIG_X86_LOCAL_APIC) += perfctr-watchdog.o
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 6f9d1f6063e9..8f5cabb3c5b0 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -629,10 +629,13 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
* Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=33012
*/
u64 mask;
+ int err;
- rdmsrl(MSR_AMD64_MCx_MASK(4), mask);
- mask |= (1 << 10);
- wrmsrl(MSR_AMD64_MCx_MASK(4), mask);
+ err = rdmsrl_safe(MSR_AMD64_MCx_MASK(4), &mask);
+ if (err == 0) {
+ mask |= (1 << 10);
+ checking_wrmsrl(MSR_AMD64_MCx_MASK(4), mask);
+ }
}
}
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index e2ced0074a45..c8b41623377f 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -254,6 +254,25 @@ static inline void squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
}
#endif
+static int disable_smep __cpuinitdata;
+static __init int setup_disable_smep(char *arg)
+{
+ disable_smep = 1;
+ return 1;
+}
+__setup("nosmep", setup_disable_smep);
+
+static __cpuinit void setup_smep(struct cpuinfo_x86 *c)
+{
+ if (cpu_has(c, X86_FEATURE_SMEP)) {
+ if (unlikely(disable_smep)) {
+ setup_clear_cpu_cap(X86_FEATURE_SMEP);
+ clear_in_cr4(X86_CR4_SMEP);
+ } else
+ set_in_cr4(X86_CR4_SMEP);
+ }
+}
+
/*
* Some CPU features depend on higher CPUID levels, which may not always
* be available due to CPUID level capping or broken virtualization
@@ -565,8 +584,7 @@ void __cpuinit get_cpu_cap(struct cpuinfo_x86 *c)
cpuid_count(0x00000007, 0, &eax, &ebx, &ecx, &edx);
- if (eax > 0)
- c->x86_capability[9] = ebx;
+ c->x86_capability[9] = ebx;
}
/* AMD-defined flags: level 0x80000001 */
@@ -668,6 +686,8 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
c->cpu_index = 0;
#endif
filter_cpuid_features(c, false);
+
+ setup_smep(c);
}
void __init early_cpu_init(void)
@@ -753,6 +773,8 @@ static void __cpuinit generic_identify(struct cpuinfo_x86 *c)
#endif
}
+ setup_smep(c);
+
get_model_name(c); /* Default name */
detect_nopl(c);
diff --git a/arch/x86/kernel/cpu/cpufreq/Makefile b/arch/x86/kernel/cpu/cpufreq/Makefile
deleted file mode 100644
index bd54bf67e6fb..000000000000
--- a/arch/x86/kernel/cpu/cpufreq/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-# Link order matters. K8 is preferred to ACPI because of firmware bugs in early
-# K8 systems. ACPI is preferred to all other hardware-specific drivers.
-# speedstep-* is preferred over p4-clockmod.
-
-obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o mperf.o
-obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o mperf.o
-obj-$(CONFIG_X86_PCC_CPUFREQ) += pcc-cpufreq.o
-obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o
-obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o
-obj-$(CONFIG_X86_LONGHAUL) += longhaul.o
-obj-$(CONFIG_X86_E_POWERSAVER) += e_powersaver.o
-obj-$(CONFIG_ELAN_CPUFREQ) += elanfreq.o
-obj-$(CONFIG_SC520_CPUFREQ) += sc520_freq.o
-obj-$(CONFIG_X86_LONGRUN) += longrun.o
-obj-$(CONFIG_X86_GX_SUSPMOD) += gx-suspmod.o
-obj-$(CONFIG_X86_SPEEDSTEP_ICH) += speedstep-ich.o
-obj-$(CONFIG_X86_SPEEDSTEP_LIB) += speedstep-lib.o
-obj-$(CONFIG_X86_SPEEDSTEP_SMI) += speedstep-smi.o
-obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o
-obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o
-obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index df86bc8c859d..1edf5ba4fb2b 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -29,10 +29,10 @@
static void __cpuinit early_init_intel(struct cpuinfo_x86 *c)
{
+ u64 misc_enable;
+
/* Unmask CPUID levels if masked: */
if (c->x86 > 6 || (c->x86 == 6 && c->x86_model >= 0xd)) {
- u64 misc_enable;
-
rdmsrl(MSR_IA32_MISC_ENABLE, misc_enable);
if (misc_enable & MSR_IA32_MISC_ENABLE_LIMIT_CPUID) {
@@ -118,8 +118,6 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c)
* (model 2) with the same problem.
*/
if (c->x86 == 15) {
- u64 misc_enable;
-
rdmsrl(MSR_IA32_MISC_ENABLE, misc_enable);
if (misc_enable & MSR_IA32_MISC_ENABLE_FAST_STRING) {
@@ -130,6 +128,19 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c)
}
}
#endif
+
+ /*
+ * If fast string is not enabled in IA32_MISC_ENABLE for any reason,
+ * clear the fast string and enhanced fast string CPU capabilities.
+ */
+ if (c->x86 > 6 || (c->x86 == 6 && c->x86_model >= 0xd)) {
+ rdmsrl(MSR_IA32_MISC_ENABLE, misc_enable);
+ if (!(misc_enable & MSR_IA32_MISC_ENABLE_FAST_STRING)) {
+ printk(KERN_INFO "Disabled fast string operations\n");
+ setup_clear_cpu_cap(X86_FEATURE_REP_GOOD);
+ setup_clear_cpu_cap(X86_FEATURE_ERMS);
+ }
+ }
}
#ifdef CONFIG_X86_32
@@ -400,12 +411,10 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c)
switch (c->x86_model) {
case 5:
- if (c->x86_mask == 0) {
- if (l2 == 0)
- p = "Celeron (Covington)";
- else if (l2 == 256)
- p = "Mobile Pentium II (Dixon)";
- }
+ if (l2 == 0)
+ p = "Celeron (Covington)";
+ else if (l2 == 256)
+ p = "Mobile Pentium II (Dixon)";
break;
case 6:
diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index 1ce1af2899df..c105c533ed94 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -327,7 +327,6 @@ static void __cpuinit amd_calc_l3_indices(struct amd_l3_cache *l3)
l3->subcaches[2] = sc2 = !(val & BIT(8)) + !(val & BIT(9));
l3->subcaches[3] = sc3 = !(val & BIT(12)) + !(val & BIT(13));
- l3->indices = (max(max(max(sc0, sc1), sc2), sc3) << 10) - 1;
l3->indices = (max(max3(sc0, sc1, sc2), sc3) << 10) - 1;
}
@@ -454,27 +453,16 @@ int amd_set_l3_disable_slot(struct amd_l3_cache *l3, int cpu, unsigned slot,
{
int ret = 0;
-#define SUBCACHE_MASK (3UL << 20)
-#define SUBCACHE_INDEX 0xfff
-
- /*
- * check whether this slot is already used or
- * the index is already disabled
- */
+ /* check if @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))
+ if (index > l3->indices)
return -EINVAL;
- /* do not allow writes outside of allowed bits */
- if ((index & ~(SUBCACHE_MASK | SUBCACHE_INDEX)) ||
- ((index & SUBCACHE_INDEX) > l3->indices))
+ /* check whether the other slot has disabled the same index already */
+ if (index == amd_get_l3_disable_slot(l3, !slot))
return -EINVAL;
amd_l3_disable_index(l3, cpu, slot, index);
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 3385ea26f684..ff1ae9b6464d 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -105,20 +105,6 @@ static int cpu_missing;
ATOMIC_NOTIFIER_HEAD(x86_mce_decoder_chain);
EXPORT_SYMBOL_GPL(x86_mce_decoder_chain);
-static int default_decode_mce(struct notifier_block *nb, unsigned long val,
- void *data)
-{
- 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;
-}
-
-static struct notifier_block mce_dec_nb = {
- .notifier_call = default_decode_mce,
- .priority = -1,
-};
-
/* MCA banks polled by the period polling timer for corrected events */
DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = {
[0 ... BITS_TO_LONGS(MAX_NR_BANKS)-1] = ~0UL
@@ -212,6 +198,8 @@ void mce_log(struct mce *mce)
static void print_mce(struct mce *m)
{
+ int ret = 0;
+
pr_emerg(HW_ERR "CPU %d: Machine Check Exception: %Lx Bank %d: %016Lx\n",
m->extcpu, m->mcgstatus, m->bank, m->status);
@@ -239,7 +227,11 @@ static void print_mce(struct mce *m)
* Print out human-readable details about the MCE error,
* (if the CPU has an implementation for that)
*/
- atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, m);
+ ret = atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, m);
+ if (ret == NOTIFY_STOP)
+ return;
+
+ pr_emerg_ratelimited(HW_ERR "Run the above through 'mcelog --ascii'\n");
}
#define PANIC_TIMEOUT 5 /* 5 seconds */
@@ -590,7 +582,6 @@ 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);
}
/*
@@ -1722,8 +1713,6 @@ __setup("mce", mcheck_enable);
int __init mcheck_init(void)
{
- atomic_notifier_chain_register(&x86_mce_decoder_chain, &mce_dec_nb);
-
mcheck_intel_therm_init();
return 0;
diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c
index 0f034460260d..27c625178bf1 100644
--- a/arch/x86/kernel/cpu/mcheck/therm_throt.c
+++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c
@@ -187,8 +187,6 @@ static int therm_throt_process(bool new_event, int event, int level)
this_cpu,
level == CORE_LEVEL ? "Core" : "Package",
state->count);
-
- add_taint(TAINT_MACHINE_CHECK);
return 1;
}
if (old_event) {
@@ -355,7 +353,6 @@ static void notify_thresholds(__u64 msr_val)
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);
@@ -367,19 +364,19 @@ static void intel_thermal_interrupt(void)
CORE_LEVEL) != 0)
mce_log_therm_throt_event(CORE_THROTTLED | msr_val);
- if (cpu_has(c, X86_FEATURE_PLN))
+ if (this_cpu_has(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)) {
+ if (this_cpu_has(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 (this_cpu_has(X86_FEATURE_PLN))
if (therm_throt_process(msr_val &
PACKAGE_THERM_STATUS_POWER_LIMIT,
POWER_LIMIT_EVENT,
@@ -393,7 +390,6 @@ static void unexpected_thermal_interrupt(void)
{
printk(KERN_ERR "CPU%d: Unexpected LVT thermal interrupt!\n",
smp_processor_id());
- add_taint(TAINT_MACHINE_CHECK);
}
static void (*smp_thermal_vector)(void) = unexpected_thermal_interrupt;
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index e638689279d3..3a0338b4b179 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -31,6 +31,7 @@
#include <asm/nmi.h>
#include <asm/compat.h>
#include <asm/smp.h>
+#include <asm/alternative.h>
#if 0
#undef wrmsrl
@@ -363,12 +364,18 @@ again:
return new_raw_count;
}
-/* using X86_FEATURE_PERFCTR_CORE to later implement ALTERNATIVE() here */
static inline int x86_pmu_addr_offset(int index)
{
- if (boot_cpu_has(X86_FEATURE_PERFCTR_CORE))
- return index << 1;
- return index;
+ int offset;
+
+ /* offset = X86_FEATURE_PERFCTR_CORE ? index << 1 : index */
+ alternative_io(ASM_NOP2,
+ "shll $1, %%eax",
+ X86_FEATURE_PERFCTR_CORE,
+ "=a" (offset),
+ "a" (index));
+
+ return offset;
}
static inline unsigned int x86_pmu_config_addr(int index)
@@ -1766,17 +1773,6 @@ static struct pmu pmu = {
* callchain support
*/
-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)
{
return 0;
@@ -1790,8 +1786,6 @@ static void backtrace_address(void *data, unsigned long addr, int reliable)
}
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_bp,
diff --git a/arch/x86/kernel/cpu/perf_event_amd.c b/arch/x86/kernel/cpu/perf_event_amd.c
index cf4e369cea67..fe29c1d2219e 100644
--- a/arch/x86/kernel/cpu/perf_event_amd.c
+++ b/arch/x86/kernel/cpu/perf_event_amd.c
@@ -96,12 +96,14 @@ static __initconst const u64 amd_hw_cache_event_ids
*/
static const u64 amd_perfmon_event_map[] =
{
- [PERF_COUNT_HW_CPU_CYCLES] = 0x0076,
- [PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0,
- [PERF_COUNT_HW_CACHE_REFERENCES] = 0x0080,
- [PERF_COUNT_HW_CACHE_MISSES] = 0x0081,
- [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x00c2,
- [PERF_COUNT_HW_BRANCH_MISSES] = 0x00c3,
+ [PERF_COUNT_HW_CPU_CYCLES] = 0x0076,
+ [PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0,
+ [PERF_COUNT_HW_CACHE_REFERENCES] = 0x0080,
+ [PERF_COUNT_HW_CACHE_MISSES] = 0x0081,
+ [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x00c2,
+ [PERF_COUNT_HW_BRANCH_MISSES] = 0x00c3,
+ [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x00d0, /* "Decoder empty" event */
+ [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x00d1, /* "Dispatch stalls" event */
};
static u64 amd_pmu_event_map(int hw_event)
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c
index 447a28de6f09..41178c826c48 100644
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -36,7 +36,7 @@ static u64 intel_perfmon_event_map[PERF_COUNT_HW_MAX] __read_mostly =
[PERF_COUNT_HW_BUS_CYCLES] = 0x013c,
};
-static struct event_constraint intel_core_event_constraints[] =
+static struct event_constraint intel_core_event_constraints[] __read_mostly =
{
INTEL_EVENT_CONSTRAINT(0x11, 0x2), /* FP_ASSIST */
INTEL_EVENT_CONSTRAINT(0x12, 0x2), /* MUL */
@@ -47,7 +47,7 @@ static struct event_constraint intel_core_event_constraints[] =
EVENT_CONSTRAINT_END
};
-static struct event_constraint intel_core2_event_constraints[] =
+static struct event_constraint intel_core2_event_constraints[] __read_mostly =
{
FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */
@@ -70,7 +70,7 @@ static struct event_constraint intel_core2_event_constraints[] =
EVENT_CONSTRAINT_END
};
-static struct event_constraint intel_nehalem_event_constraints[] =
+static struct event_constraint intel_nehalem_event_constraints[] __read_mostly =
{
FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */
@@ -86,19 +86,19 @@ static struct event_constraint intel_nehalem_event_constraints[] =
EVENT_CONSTRAINT_END
};
-static struct extra_reg intel_nehalem_extra_regs[] =
+static struct extra_reg intel_nehalem_extra_regs[] __read_mostly =
{
INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0xffff),
EVENT_EXTRA_END
};
-static struct event_constraint intel_nehalem_percore_constraints[] =
+static struct event_constraint intel_nehalem_percore_constraints[] __read_mostly =
{
INTEL_EVENT_CONSTRAINT(0xb7, 0),
EVENT_CONSTRAINT_END
};
-static struct event_constraint intel_westmere_event_constraints[] =
+static struct event_constraint intel_westmere_event_constraints[] __read_mostly =
{
FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */
@@ -110,7 +110,7 @@ static struct event_constraint intel_westmere_event_constraints[] =
EVENT_CONSTRAINT_END
};
-static struct event_constraint intel_snb_event_constraints[] =
+static struct event_constraint intel_snb_event_constraints[] __read_mostly =
{
FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */
@@ -123,21 +123,21 @@ static struct event_constraint intel_snb_event_constraints[] =
EVENT_CONSTRAINT_END
};
-static struct extra_reg intel_westmere_extra_regs[] =
+static struct extra_reg intel_westmere_extra_regs[] __read_mostly =
{
INTEL_EVENT_EXTRA_REG(0xb7, MSR_OFFCORE_RSP_0, 0xffff),
INTEL_EVENT_EXTRA_REG(0xbb, MSR_OFFCORE_RSP_1, 0xffff),
EVENT_EXTRA_END
};
-static struct event_constraint intel_westmere_percore_constraints[] =
+static struct event_constraint intel_westmere_percore_constraints[] __read_mostly =
{
INTEL_EVENT_CONSTRAINT(0xb7, 0),
INTEL_EVENT_CONSTRAINT(0xbb, 0),
EVENT_CONSTRAINT_END
};
-static struct event_constraint intel_gen_event_constraints[] =
+static struct event_constraint intel_gen_event_constraints[] __read_mostly =
{
FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */
@@ -1440,6 +1440,11 @@ static __init int intel_pmu_init(void)
x86_pmu.enable_all = intel_pmu_nhm_enable_all;
x86_pmu.extra_regs = intel_nehalem_extra_regs;
+ /* UOPS_ISSUED.STALLED_CYCLES */
+ intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x180010e;
+ /* UOPS_EXECUTED.CORE_ACTIVE_CYCLES,c=1,i=1 */
+ intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x1803fb1;
+
if (ebx & 0x40) {
/*
* Erratum AAJ80 detected, we work it around by using
@@ -1480,6 +1485,12 @@ static __init int intel_pmu_init(void)
x86_pmu.enable_all = intel_pmu_nhm_enable_all;
x86_pmu.pebs_constraints = intel_westmere_pebs_event_constraints;
x86_pmu.extra_regs = intel_westmere_extra_regs;
+
+ /* UOPS_ISSUED.STALLED_CYCLES */
+ intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x180010e;
+ /* UOPS_EXECUTED.CORE_ACTIVE_CYCLES,c=1,i=1 */
+ intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x1803fb1;
+
pr_cont("Westmere events, ");
break;
@@ -1491,6 +1502,12 @@ static __init int intel_pmu_init(void)
x86_pmu.event_constraints = intel_snb_event_constraints;
x86_pmu.pebs_constraints = intel_snb_pebs_events;
+
+ /* UOPS_ISSUED.ANY,c=1,i=1 to count stall cycles */
+ intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = 0x180010e;
+ /* UOPS_DISPATCHED.THREAD,c=1,i=1 to count stall cycles*/
+ intel_perfmon_event_map[PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = 0x18001b1;
+
pr_cont("SandyBridge events, ");
break;
diff --git a/arch/x86/kernel/cpu/perf_event_p4.c b/arch/x86/kernel/cpu/perf_event_p4.c
index e93fcd55fae1..ead584fb6a7d 100644
--- a/arch/x86/kernel/cpu/perf_event_p4.c
+++ b/arch/x86/kernel/cpu/perf_event_p4.c
@@ -468,7 +468,7 @@ static struct p4_event_bind p4_event_bind_map[] = {
.opcode = P4_OPCODE(P4_EVENT_MISPRED_BRANCH_RETIRED),
.escr_msr = { MSR_P4_CRU_ESCR0, MSR_P4_CRU_ESCR1 },
.escr_emask =
- P4_ESCR_EMASK_BIT(P4_EVENT_MISPRED_BRANCH_RETIRED, NBOGUS),
+ P4_ESCR_EMASK_BIT(P4_EVENT_MISPRED_BRANCH_RETIRED, NBOGUS),
.cntr = { {12, 13, 16}, {14, 15, 17} },
},
[P4_EVENT_X87_ASSIST] = {
@@ -912,8 +912,7 @@ static int p4_pmu_handle_irq(struct pt_regs *regs)
int idx, handled = 0;
u64 val;
- data.addr = 0;
- data.raw = NULL;
+ perf_sample_data_init(&data, 0);
cpuc = &__get_cpu_var(cpu_hw_events);
@@ -1197,7 +1196,7 @@ static __init int p4_pmu_init(void)
{
unsigned int low, high;
- /* If we get stripped -- indexig fails */
+ /* If we get stripped -- indexing fails */
BUILD_BUG_ON(ARCH_P4_MAX_CCCR > X86_PMC_MAX_GENERIC);
rdmsr(MSR_IA32_MISC_ENABLE, low, high);
diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c
index e90f08458e6b..690bc8461835 100644
--- a/arch/x86/kernel/devicetree.c
+++ b/arch/x86/kernel/devicetree.c
@@ -369,6 +369,7 @@ static struct of_ioapic_type of_ioapic_type[] =
static int ioapic_xlate(struct irq_domain *id, const u32 *intspec, u32 intsize,
u32 *out_hwirq, u32 *out_type)
{
+ struct mp_ioapic_gsi *gsi_cfg;
struct io_apic_irq_attr attr;
struct of_ioapic_type *it;
u32 line, idx, type;
@@ -378,7 +379,8 @@ static int ioapic_xlate(struct irq_domain *id, const u32 *intspec, u32 intsize,
line = *intspec;
idx = (u32) id->priv;
- *out_hwirq = line + mp_gsi_routing[idx].gsi_base;
+ gsi_cfg = mp_ioapic_gsi_routing(idx);
+ *out_hwirq = line + gsi_cfg->gsi_base;
intspec++;
type = *intspec;
@@ -407,7 +409,7 @@ static void __init ioapic_add_ofnode(struct device_node *np)
}
for (i = 0; i < nr_ioapics; i++) {
- if (r.start == mp_ioapics[i].apicaddr) {
+ if (r.start == mpc_ioapic_addr(i)) {
struct irq_domain *id;
id = kzalloc(sizeof(*id), GFP_KERNEL);
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
index e2a3f0606da4..1aae78f775fc 100644
--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c
@@ -135,20 +135,6 @@ print_context_stack_bp(struct thread_info *tinfo,
}
EXPORT_SYMBOL_GPL(print_context_stack_bp);
-
-static void
-print_trace_warning_symbol(void *data, char *msg, unsigned long symbol)
-{
- printk(data);
- print_symbol(msg, symbol);
- printk("\n");
-}
-
-static void print_trace_warning(void *data, char *msg)
-{
- printk("%s%s\n", (char *)data, msg);
-}
-
static int print_trace_stack(void *data, char *name)
{
printk("%s <%s> ", (char *)data, name);
@@ -166,8 +152,6 @@ static void print_trace_address(void *data, unsigned long addr, int reliable)
}
static const struct stacktrace_ops print_trace_ops = {
- .warning = print_trace_warning,
- .warning_symbol = print_trace_warning_symbol,
.stack = print_trace_stack,
.address = print_trace_address,
.walk_stack = print_context_stack,
@@ -279,7 +263,6 @@ int __kprobes __die(const char *str, struct pt_regs *regs, long err)
printk("DEBUG_PAGEALLOC");
#endif
printk("\n");
- sysfs_printk_last_file();
if (notify_die(DIE_OOPS, str, regs, err,
current->thread.trap_no, SIGSEGV) == NOTIFY_STOP)
return 1;
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index a93742a57468..0ba15a6cc57e 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -260,9 +260,9 @@ do_ftrace_mod_code(unsigned long ip, void *new_code)
return mod_code_status;
}
-static unsigned char *ftrace_nop_replace(void)
+static const unsigned char *ftrace_nop_replace(void)
{
- return ideal_nop5;
+ return ideal_nops[NOP_ATOMIC5];
}
static int
diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c
index d6d6bb361931..3bb08509a7a1 100644
--- a/arch/x86/kernel/head32.c
+++ b/arch/x86/kernel/head32.c
@@ -23,7 +23,6 @@
static void __init i386_default_early_setup(void)
{
/* 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/hpet.c b/arch/x86/kernel/hpet.c
index bfe8f729e086..6781765b3a0d 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -217,7 +217,7 @@ static void hpet_reserve_platform_timers(unsigned int id) { }
/*
* Common hpet info
*/
-static unsigned long hpet_period;
+static unsigned long hpet_freq;
static void hpet_legacy_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt);
@@ -232,7 +232,6 @@ static struct clock_event_device hpet_clockevent = {
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.set_mode = hpet_legacy_set_mode,
.set_next_event = hpet_legacy_next_event,
- .shift = 32,
.irq = 0,
.rating = 50,
};
@@ -290,28 +289,12 @@ static void hpet_legacy_clockevent_register(void)
hpet_enable_legacy_int();
/*
- * The mult factor is defined as (include/linux/clockchips.h)
- * mult/2^shift = cyc/ns (in contrast to ns/cyc in clocksource.h)
- * hpet_period is in units of femtoseconds (per cycle), so
- * mult/2^shift = cyc/ns = 10^6/hpet_period
- * mult = (10^6 * 2^shift)/hpet_period
- * mult = (FSEC_PER_NSEC << hpet_clockevent.shift)/hpet_period
- */
- hpet_clockevent.mult = div_sc((unsigned long) FSEC_PER_NSEC,
- hpet_period, hpet_clockevent.shift);
- /* Calculate the min / max delta */
- hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF,
- &hpet_clockevent);
- /* Setup minimum reprogramming delta. */
- hpet_clockevent.min_delta_ns = clockevent_delta2ns(HPET_MIN_PROG_DELTA,
- &hpet_clockevent);
-
- /*
* Start hpet with the boot cpu mask and make it
* global after the IO_APIC has been initialized.
*/
hpet_clockevent.cpumask = cpumask_of(smp_processor_id());
- clockevents_register_device(&hpet_clockevent);
+ clockevents_config_and_register(&hpet_clockevent, hpet_freq,
+ HPET_MIN_PROG_DELTA, 0x7FFFFFFF);
global_clock_event = &hpet_clockevent;
printk(KERN_DEBUG "hpet clockevent registered\n");
}
@@ -549,7 +532,6 @@ static int hpet_setup_irq(struct hpet_dev *dev)
static void init_one_hpet_msi_clockevent(struct hpet_dev *hdev, int cpu)
{
struct clock_event_device *evt = &hdev->evt;
- uint64_t hpet_freq;
WARN_ON(cpu != smp_processor_id());
if (!(hdev->flags & HPET_DEV_VALID))
@@ -571,24 +553,10 @@ static void init_one_hpet_msi_clockevent(struct hpet_dev *hdev, int cpu)
evt->set_mode = hpet_msi_set_mode;
evt->set_next_event = hpet_msi_next_event;
- evt->shift = 32;
-
- /*
- * The period is a femto seconds value. We need to calculate the
- * scaled math multiplication factor for nanosecond to hpet tick
- * conversion.
- */
- hpet_freq = FSEC_PER_SEC;
- do_div(hpet_freq, hpet_period);
- evt->mult = div_sc((unsigned long) hpet_freq,
- NSEC_PER_SEC, evt->shift);
- /* Calculate the max delta */
- evt->max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, evt);
- /* 5 usec minimum reprogramming delta. */
- evt->min_delta_ns = 5000;
-
evt->cpumask = cpumask_of(hdev->cpu);
- clockevents_register_device(evt);
+
+ clockevents_config_and_register(evt, hpet_freq, HPET_MIN_PROG_DELTA,
+ 0x7FFFFFFF);
}
#ifdef CONFIG_HPET
@@ -792,7 +760,6 @@ static struct clocksource clocksource_hpet = {
static int hpet_clocksource_register(void)
{
u64 start, now;
- u64 hpet_freq;
cycle_t t1;
/* Start the counter */
@@ -819,24 +786,7 @@ static int hpet_clocksource_register(void)
return -ENODEV;
}
- /*
- * The definition of mult is (include/linux/clocksource.h)
- * mult/2^shift = ns/cyc and hpet_period is in units of fsec/cyc
- * so we first need to convert hpet_period to ns/cyc units:
- * mult/2^shift = ns/cyc = hpet_period/10^6
- * mult = (hpet_period * 2^shift)/10^6
- * mult = (hpet_period << shift)/FSEC_PER_NSEC
- */
-
- /* 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_SEC;
- do_div(hpet_freq, hpet_period);
clocksource_register_hz(&clocksource_hpet, (u32)hpet_freq);
-
return 0;
}
@@ -845,7 +795,9 @@ static int hpet_clocksource_register(void)
*/
int __init hpet_enable(void)
{
+ unsigned long hpet_period;
unsigned int id;
+ u64 freq;
int i;
if (!is_hpet_capable())
@@ -884,6 +836,14 @@ int __init hpet_enable(void)
goto out_nohpet;
/*
+ * The period is a femto seconds value. Convert it to a
+ * frequency.
+ */
+ freq = FSEC_PER_SEC;
+ do_div(freq, hpet_period);
+ hpet_freq = freq;
+
+ /*
* Read the HPET ID register to retrieve the IRQ routing
* information and the number of channels
*/
diff --git a/arch/x86/kernel/i8253.c b/arch/x86/kernel/i8253.c
index 2dfd31597443..fb66dc9e36cb 100644
--- a/arch/x86/kernel/i8253.c
+++ b/arch/x86/kernel/i8253.c
@@ -93,7 +93,6 @@ static struct clock_event_device pit_ce = {
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.set_mode = init_pit_timer,
.set_next_event = pit_next_event,
- .shift = 32,
.irq = 0,
};
@@ -108,90 +107,12 @@ void __init setup_pit_timer(void)
* IO_APIC has been initialized.
*/
pit_ce.cpumask = cpumask_of(smp_processor_id());
- pit_ce.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, pit_ce.shift);
- pit_ce.max_delta_ns = clockevent_delta2ns(0x7FFF, &pit_ce);
- pit_ce.min_delta_ns = clockevent_delta2ns(0xF, &pit_ce);
- clockevents_register_device(&pit_ce);
+ clockevents_config_and_register(&pit_ce, CLOCK_TICK_RATE, 0xF, 0x7FFF);
global_clock_event = &pit_ce;
}
#ifndef CONFIG_X86_64
-/*
- * Since the PIT overflows every tick, its not very useful
- * to just read by itself. So use jiffies to emulate a free
- * running counter:
- */
-static cycle_t pit_read(struct clocksource *cs)
-{
- static int old_count;
- static u32 old_jifs;
- unsigned long flags;
- int count;
- u32 jifs;
-
- raw_spin_lock_irqsave(&i8253_lock, flags);
- /*
- * Although our caller may have the read side of xtime_lock,
- * this is now a seqlock, and we are cheating in this routine
- * by having side effects on state that we cannot undo if
- * there is a collision on the seqlock and our caller has to
- * retry. (Namely, old_jifs and old_count.) So we must treat
- * jiffies as volatile despite the lock. We read jiffies
- * before latching the timer count to guarantee that although
- * the jiffies value might be older than the count (that is,
- * the counter may underflow between the last point where
- * jiffies was incremented and the point where we latch the
- * count), it cannot be newer.
- */
- jifs = jiffies;
- outb_pit(0x00, PIT_MODE); /* latch the count ASAP */
- count = inb_pit(PIT_CH0); /* read the latched count */
- count |= inb_pit(PIT_CH0) << 8;
-
- /* VIA686a test code... reset the latch if count > max + 1 */
- if (count > LATCH) {
- outb_pit(0x34, PIT_MODE);
- outb_pit(LATCH & 0xff, PIT_CH0);
- outb_pit(LATCH >> 8, PIT_CH0);
- count = LATCH - 1;
- }
-
- /*
- * It's possible for count to appear to go the wrong way for a
- * couple of reasons:
- *
- * 1. The timer counter underflows, but we haven't handled the
- * resulting interrupt and incremented jiffies yet.
- * 2. Hardware problem with the timer, not giving us continuous time,
- * the counter does small "jumps" upwards on some Pentium systems,
- * (see c't 95/10 page 335 for Neptun bug.)
- *
- * Previous attempts to handle these cases intelligently were
- * buggy, so we just do the simple thing now.
- */
- if (count > old_count && jifs == old_jifs)
- count = old_count;
-
- old_count = count;
- old_jifs = jifs;
-
- raw_spin_unlock_irqrestore(&i8253_lock, flags);
-
- count = (LATCH - 1) - count;
-
- return (cycle_t)(jifs * LATCH) + count;
-}
-
-static struct clocksource pit_cs = {
- .name = "pit",
- .rating = 110,
- .read = pit_read,
- .mask = CLOCKSOURCE_MASK(32),
- .mult = 0,
- .shift = 20,
-};
-
static int __init init_pit_clocksource(void)
{
/*
@@ -205,10 +126,7 @@ static int __init init_pit_clocksource(void)
pit_ce.mode != CLOCK_EVT_MODE_PERIODIC)
return 0;
- pit_cs.mult = clocksource_hz2mult(CLOCK_TICK_RATE, pit_cs.shift);
-
- return clocksource_register(&pit_cs);
+ return clocksource_i8253_init();
}
arch_initcall(init_pit_clocksource);
-
#endif /* !CONFIG_X86_64 */
diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
index 1cb0b9fc78dc..6c0802eb2f7f 100644
--- a/arch/x86/kernel/irq.c
+++ b/arch/x86/kernel/irq.c
@@ -249,7 +249,7 @@ void fixup_irqs(void)
data = irq_desc_get_irq_data(desc);
affinity = data->affinity;
- if (!irq_has_action(irq) ||
+ if (!irq_has_action(irq) || irqd_is_per_cpu(data) ||
cpumask_subset(affinity, cpu_online_mask)) {
raw_spin_unlock(&desc->lock);
continue;
@@ -276,7 +276,8 @@ void fixup_irqs(void)
else if (!(warned++))
set_affinity = 0;
- if (!irqd_can_move_in_process_context(data) && chip->irq_unmask)
+ if (!irqd_can_move_in_process_context(data) &&
+ !irqd_irq_disabled(data) && chip->irq_unmask)
chip->irq_unmask(data);
raw_spin_unlock(&desc->lock);
diff --git a/arch/x86/kernel/jump_label.c b/arch/x86/kernel/jump_label.c
index 961b6b30ba90..3fee346ef545 100644
--- a/arch/x86/kernel/jump_label.c
+++ b/arch/x86/kernel/jump_label.c
@@ -34,7 +34,7 @@ void arch_jump_label_transform(struct jump_entry *entry,
code.offset = entry->target -
(entry->code + JUMP_LABEL_NOP_SIZE);
} else
- memcpy(&code, ideal_nop5, JUMP_LABEL_NOP_SIZE);
+ memcpy(&code, ideal_nops[NOP_ATOMIC5], JUMP_LABEL_NOP_SIZE);
get_online_cpus();
mutex_lock(&text_mutex);
text_poke_smp((void *)entry->code, &code, JUMP_LABEL_NOP_SIZE);
@@ -44,7 +44,8 @@ void arch_jump_label_transform(struct jump_entry *entry,
void arch_jump_label_text_poke_early(jump_label_t addr)
{
- text_poke_early((void *)addr, ideal_nop5, JUMP_LABEL_NOP_SIZE);
+ text_poke_early((void *)addr, ideal_nops[NOP_ATOMIC5],
+ JUMP_LABEL_NOP_SIZE);
}
#endif
diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c
index f98d3eafe07a..6389a6bca11b 100644
--- a/arch/x86/kernel/kvmclock.c
+++ b/arch/x86/kernel/kvmclock.c
@@ -26,8 +26,6 @@
#include <asm/x86_init.h>
#include <asm/reboot.h>
-#define KVM_SCALE 22
-
static int kvmclock = 1;
static int msr_kvm_system_time = MSR_KVM_SYSTEM_TIME;
static int msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK;
@@ -120,8 +118,6 @@ static struct clocksource kvm_clock = {
.read = kvm_clock_get_cycles,
.rating = 400,
.mask = CLOCKSOURCE_MASK(64),
- .mult = 1 << KVM_SCALE,
- .shift = KVM_SCALE,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
@@ -203,7 +199,7 @@ void __init kvmclock_init(void)
machine_ops.crash_shutdown = kvm_crash_shutdown;
#endif
kvm_get_preset_lpj();
- clocksource_register(&kvm_clock);
+ clocksource_register_hz(&kvm_clock, NSEC_PER_SEC);
pv_info.paravirt_enabled = 1;
pv_info.name = "KVM";
diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c
index ab23f1ad4bf1..52f256f2cc81 100644
--- a/arch/x86/kernel/module.c
+++ b/arch/x86/kernel/module.c
@@ -24,6 +24,7 @@
#include <linux/bug.h>
#include <linux/mm.h>
#include <linux/gfp.h>
+#include <linux/jump_label.h>
#include <asm/system.h>
#include <asm/page.h>
diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c
index 5a532ce646bf..9103b89c145a 100644
--- a/arch/x86/kernel/mpparse.c
+++ b/arch/x86/kernel/mpparse.c
@@ -285,7 +285,7 @@ static void __init construct_default_ioirq_mptable(int mpc_default_type)
intsrc.type = MP_INTSRC;
intsrc.irqflag = 0; /* conforming */
intsrc.srcbus = 0;
- intsrc.dstapic = mp_ioapics[0].apicid;
+ intsrc.dstapic = mpc_ioapic_id(0);
intsrc.irqtype = mp_INT;
@@ -715,17 +715,15 @@ static void __init check_irq_src(struct mpc_intsrc *m, int *nr_m_spare)
}
}
-static int
+static int __init
check_slot(unsigned long mpc_new_phys, unsigned long mpc_new_length, int count)
{
- int ret = 0;
-
if (!mpc_new_phys || count <= mpc_new_length) {
WARN(1, "update_mptable: No spare slots (length: %x)\n", count);
return -1;
}
- return ret;
+ return 0;
}
#else /* CONFIG_X86_IO_APIC */
static
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index 9ea999a4dcc1..b49d00da2aed 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -68,74 +68,10 @@ int dma_set_mask(struct device *dev, u64 mask)
}
EXPORT_SYMBOL(dma_set_mask);
-#if defined(CONFIG_X86_64) && !defined(CONFIG_NUMA)
-static __initdata void *dma32_bootmem_ptr;
-static unsigned long dma32_bootmem_size __initdata = (128ULL<<20);
-
-static int __init parse_dma32_size_opt(char *p)
-{
- if (!p)
- return -EINVAL;
- dma32_bootmem_size = memparse(p, &p);
- return 0;
-}
-early_param("dma32_size", parse_dma32_size_opt);
-
-void __init dma32_reserve_bootmem(void)
-{
- unsigned long size, align;
- if (max_pfn <= MAX_DMA32_PFN)
- return;
-
- /*
- * check aperture_64.c allocate_aperture() for reason about
- * using 512M as goal
- */
- align = 64ULL<<20;
- size = roundup(dma32_bootmem_size, align);
- dma32_bootmem_ptr = __alloc_bootmem_nopanic(size, align,
- 512ULL<<20);
- /*
- * Kmemleak should not scan this block as it may not be mapped via the
- * kernel direct mapping.
- */
- kmemleak_ignore(dma32_bootmem_ptr);
- if (dma32_bootmem_ptr)
- dma32_bootmem_size = size;
- else
- dma32_bootmem_size = 0;
-}
-static void __init dma32_free_bootmem(void)
-{
-
- if (max_pfn <= MAX_DMA32_PFN)
- return;
-
- if (!dma32_bootmem_ptr)
- return;
-
- free_bootmem(__pa(dma32_bootmem_ptr), dma32_bootmem_size);
-
- dma32_bootmem_ptr = NULL;
- dma32_bootmem_size = 0;
-}
-#else
-void __init dma32_reserve_bootmem(void)
-{
-}
-static void __init dma32_free_bootmem(void)
-{
-}
-
-#endif
-
void __init pci_iommu_alloc(void)
{
struct iommu_table_entry *p;
- /* free the range so iommu could get some range less than 4G */
- dma32_free_bootmem();
-
sort_iommu_table(__iommu_table, __iommu_table_end);
check_iommu_entries(__iommu_table, __iommu_table_end);
diff --git a/arch/x86/kernel/pci-iommu_table.c b/arch/x86/kernel/pci-iommu_table.c
index 55d745ec1181..35ccf75696eb 100644
--- a/arch/x86/kernel/pci-iommu_table.c
+++ b/arch/x86/kernel/pci-iommu_table.c
@@ -50,20 +50,14 @@ void __init check_iommu_entries(struct iommu_table_entry *start,
struct iommu_table_entry *finish)
{
struct iommu_table_entry *p, *q, *x;
- char sym_p[KSYM_SYMBOL_LEN];
- char sym_q[KSYM_SYMBOL_LEN];
/* Simple cyclic dependency checker. */
for (p = start; p < finish; p++) {
q = find_dependents_of(start, finish, p);
x = find_dependents_of(start, finish, q);
if (p == x) {
- sprint_symbol(sym_p, (unsigned long)p->detect);
- sprint_symbol(sym_q, (unsigned long)q->detect);
-
- printk(KERN_ERR "CYCLIC DEPENDENCY FOUND! %s depends" \
- " on %s and vice-versa. BREAKING IT.\n",
- sym_p, sym_q);
+ printk(KERN_ERR "CYCLIC DEPENDENCY FOUND! %pS depends on %pS and vice-versa. BREAKING IT.\n",
+ p->detect, q->detect);
/* Heavy handed way..*/
x->depend = 0;
}
@@ -72,12 +66,8 @@ void __init check_iommu_entries(struct iommu_table_entry *start,
for (p = start; p < finish; p++) {
q = find_dependents_of(p, finish, p);
if (q && q > p) {
- sprint_symbol(sym_p, (unsigned long)p->detect);
- sprint_symbol(sym_q, (unsigned long)q->detect);
-
- printk(KERN_ERR "EXECUTION ORDER INVALID! %s "\
- "should be called before %s!\n",
- sym_p, sym_q);
+ printk(KERN_ERR "EXECUTION ORDER INVALID! %pS should be called before %pS!\n",
+ p->detect, q->detect);
}
}
}
diff --git a/arch/x86/kernel/probe_roms_32.c b/arch/x86/kernel/probe_roms.c
index 071e7fea42e5..ba0a4cce53be 100644
--- a/arch/x86/kernel/probe_roms_32.c
+++ b/arch/x86/kernel/probe_roms.c
@@ -73,6 +73,107 @@ static struct resource video_rom_resource = {
.flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
};
+/* does this oprom support the given pci device, or any of the devices
+ * that the driver supports?
+ */
+static bool match_id(struct pci_dev *pdev, unsigned short vendor, unsigned short device)
+{
+ struct pci_driver *drv = pdev->driver;
+ const struct pci_device_id *id;
+
+ if (pdev->vendor == vendor && pdev->device == device)
+ return true;
+
+ for (id = drv ? drv->id_table : NULL; id && id->vendor; id++)
+ if (id->vendor == vendor && id->device == device)
+ break;
+
+ return id && id->vendor;
+}
+
+static bool probe_list(struct pci_dev *pdev, unsigned short vendor,
+ const unsigned char *rom_list)
+{
+ unsigned short device;
+
+ do {
+ if (probe_kernel_address(rom_list, device) != 0)
+ device = 0;
+
+ if (device && match_id(pdev, vendor, device))
+ break;
+
+ rom_list += 2;
+ } while (device);
+
+ return !!device;
+}
+
+static struct resource *find_oprom(struct pci_dev *pdev)
+{
+ struct resource *oprom = NULL;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(adapter_rom_resources); i++) {
+ struct resource *res = &adapter_rom_resources[i];
+ unsigned short offset, vendor, device, list, rev;
+ const unsigned char *rom;
+
+ if (res->end == 0)
+ break;
+
+ rom = isa_bus_to_virt(res->start);
+ if (probe_kernel_address(rom + 0x18, offset) != 0)
+ continue;
+
+ if (probe_kernel_address(rom + offset + 0x4, vendor) != 0)
+ continue;
+
+ if (probe_kernel_address(rom + offset + 0x6, device) != 0)
+ continue;
+
+ if (match_id(pdev, vendor, device)) {
+ oprom = res;
+ break;
+ }
+
+ if (probe_kernel_address(rom + offset + 0x8, list) == 0 &&
+ probe_kernel_address(rom + offset + 0xc, rev) == 0 &&
+ rev >= 3 && list &&
+ probe_list(pdev, vendor, rom + offset + list)) {
+ oprom = res;
+ break;
+ }
+ }
+
+ return oprom;
+}
+
+void *pci_map_biosrom(struct pci_dev *pdev)
+{
+ struct resource *oprom = find_oprom(pdev);
+
+ if (!oprom)
+ return NULL;
+
+ return ioremap(oprom->start, resource_size(oprom));
+}
+EXPORT_SYMBOL(pci_map_biosrom);
+
+void pci_unmap_biosrom(void __iomem *image)
+{
+ iounmap(image);
+}
+EXPORT_SYMBOL(pci_unmap_biosrom);
+
+size_t pci_biosrom_size(struct pci_dev *pdev)
+{
+ struct resource *oprom = find_oprom(pdev);
+
+ return oprom ? resource_size(oprom) : 0;
+}
+EXPORT_SYMBOL(pci_biosrom_size);
+
#define ROMSIGNATURE 0xaa55
static int __init romsignature(const unsigned char *rom)
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index d46cbe46b7ab..88a90a977f8e 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -449,7 +449,7 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait);
void mwait_idle_with_hints(unsigned long ax, unsigned long cx)
{
if (!need_resched()) {
- if (cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_CLFLUSH_MONITOR))
+ if (this_cpu_has(X86_FEATURE_CLFLUSH_MONITOR))
clflush((void *)&current_thread_info()->flags);
__monitor((void *)&current_thread_info()->flags, 0, 0);
@@ -465,7 +465,7 @@ static void mwait_idle(void)
if (!need_resched()) {
trace_power_start(POWER_CSTATE, 1, smp_processor_id());
trace_cpu_idle(1, smp_processor_id());
- if (cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_CLFLUSH_MONITOR))
+ if (this_cpu_has(X86_FEATURE_CLFLUSH_MONITOR))
clflush((void *)&current_thread_info()->flags);
__monitor((void *)&current_thread_info()->flags, 0, 0);
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index f65e5b521dbd..807c2a2b80f1 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -1363,7 +1363,7 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
* We must return the syscall number to actually look up in the table.
* This can be -1L to skip running any syscall at all.
*/
-asmregparm long syscall_trace_enter(struct pt_regs *regs)
+long syscall_trace_enter(struct pt_regs *regs)
{
long ret = 0;
@@ -1408,7 +1408,7 @@ asmregparm long syscall_trace_enter(struct pt_regs *regs)
return ret ?: regs->orig_ax;
}
-asmregparm void syscall_trace_leave(struct pt_regs *regs)
+void syscall_trace_leave(struct pt_regs *regs)
{
bool step;
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 08c44b08bf5b..0c016f727695 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -36,7 +36,7 @@ EXPORT_SYMBOL(pm_power_off);
static const struct desc_ptr no_idt = {};
static int reboot_mode;
-enum reboot_type reboot_type = BOOT_KBD;
+enum reboot_type reboot_type = BOOT_ACPI;
int reboot_force;
#if defined(CONFIG_X86_32) && defined(CONFIG_SMP)
@@ -478,9 +478,24 @@ void __attribute__((weak)) mach_reboot_fixups(void)
{
}
+/*
+ * Windows compatible x86 hardware expects the following on reboot:
+ *
+ * 1) If the FADT has the ACPI reboot register flag set, try it
+ * 2) If still alive, write to the keyboard controller
+ * 3) If still alive, write to the ACPI reboot register again
+ * 4) If still alive, write to the keyboard controller again
+ *
+ * If the machine is still alive at this stage, it gives up. We default to
+ * following the same pattern, except that if we're still alive after (4) we'll
+ * try to force a triple fault and then cycle between hitting the keyboard
+ * controller and doing that
+ */
static void native_machine_emergency_restart(void)
{
int i;
+ int attempt = 0;
+ int orig_reboot_type = reboot_type;
if (reboot_emergency)
emergency_vmx_disable_all();
@@ -502,6 +517,13 @@ static void native_machine_emergency_restart(void)
outb(0xfe, 0x64); /* pulse reset low */
udelay(50);
}
+ if (attempt == 0 && orig_reboot_type == BOOT_ACPI) {
+ attempt = 1;
+ reboot_type = BOOT_ACPI;
+ } else {
+ reboot_type = BOOT_TRIPLE;
+ }
+ break;
case BOOT_TRIPLE:
load_idt(&no_idt);
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 4be9b398470e..a3e5948670c2 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -691,8 +691,6 @@ early_param("reservelow", parse_reservelow);
void __init setup_arch(char **cmdline_p)
{
- unsigned long flags;
-
#ifdef CONFIG_X86_32
memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data));
visws_early_detect();
@@ -948,6 +946,8 @@ void __init setup_arch(char **cmdline_p)
if (init_ohci1394_dma_early)
init_ohci1394_dma_on_all_controllers();
#endif
+ /* Allocate bigger log buffer */
+ setup_log_buf(1);
reserve_initrd();
@@ -966,7 +966,6 @@ void __init setup_arch(char **cmdline_p)
initmem_init();
memblock_find_dma_reserve();
- dma32_reserve_bootmem();
#ifdef CONFIG_KVM_CLOCK
kvmclock_init();
@@ -1041,9 +1040,7 @@ void __init setup_arch(char **cmdline_p)
mcheck_init();
- local_irq_save(flags);
- arch_init_ideal_nop5();
- local_irq_restore(flags);
+ arch_init_ideal_nops();
}
#ifdef CONFIG_X86_32
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index 4fd173cd8e57..40a24932a8a1 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -601,10 +601,7 @@ long sys_rt_sigreturn(struct pt_regs *regs)
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = set;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ set_current_blocked(&set);
if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &ax))
goto badframe;
@@ -682,6 +679,7 @@ static int
handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
sigset_t *oldset, struct pt_regs *regs)
{
+ sigset_t blocked;
int ret;
/* Are we from a system call? */
@@ -741,12 +739,10 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
*/
regs->flags &= ~X86_EFLAGS_TF;
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
+ sigorsets(&blocked, &current->blocked, &ka->sa.sa_mask);
if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(&current->blocked, sig);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ sigaddset(&blocked, sig);
+ set_current_blocked(&blocked);
tracehook_signal_handler(sig, info, ka, regs,
test_thread_flag(TIF_SINGLESTEP));
diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c
index 513deac7228d..013e7eba83bb 100644
--- a/arch/x86/kernel/smp.c
+++ b/arch/x86/kernel/smp.c
@@ -194,14 +194,13 @@ static void native_stop_other_cpus(int wait)
}
/*
- * Reschedule call back. Nothing to do,
- * all the work is done automatically when
- * we return from the interrupt.
+ * Reschedule call back.
*/
void smp_reschedule_interrupt(struct pt_regs *regs)
{
ack_APIC_irq();
inc_irq_stat(irq_resched_count);
+ scheduler_ipi();
/*
* KVM uses this interrupt to force a cpu out of guest mode
*/
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index c2871d3c71b6..a3c430bdfb60 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -1332,9 +1332,9 @@ static inline void mwait_play_dead(void)
void *mwait_ptr;
struct cpuinfo_x86 *c = __this_cpu_ptr(&cpu_info);
- if (!(cpu_has(c, X86_FEATURE_MWAIT) && mwait_usable(c)))
+ if (!this_cpu_has(X86_FEATURE_MWAIT) && mwait_usable(c))
return;
- if (!cpu_has(__this_cpu_ptr(&cpu_info), X86_FEATURE_CLFLSH))
+ if (!this_cpu_has(X86_FEATURE_CLFLSH))
return;
if (__this_cpu_read(cpu_info.cpuid_level) < CPUID_MWAIT_LEAF)
return;
diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c
index 6515733a289d..55d9bc03f696 100644
--- a/arch/x86/kernel/stacktrace.c
+++ b/arch/x86/kernel/stacktrace.c
@@ -9,15 +9,6 @@
#include <linux/uaccess.h>
#include <asm/stacktrace.h>
-static void save_stack_warning(void *data, char *msg)
-{
-}
-
-static void
-save_stack_warning_symbol(void *data, char *msg, unsigned long symbol)
-{
-}
-
static int save_stack_stack(void *data, char *name)
{
return 0;
@@ -53,16 +44,12 @@ save_stack_address_nosched(void *data, unsigned long addr, int reliable)
}
static const struct stacktrace_ops save_stack_ops = {
- .warning = save_stack_warning,
- .warning_symbol = save_stack_warning_symbol,
.stack = save_stack_stack,
.address = save_stack_address,
.walk_stack = print_context_stack,
};
static const struct stacktrace_ops save_stack_ops_nosched = {
- .warning = save_stack_warning,
- .warning_symbol = save_stack_warning_symbol,
.stack = save_stack_stack,
.address = save_stack_address_nosched,
.walk_stack = print_context_stack,
diff --git a/arch/x86/kernel/syscall_table_32.S b/arch/x86/kernel/syscall_table_32.S
index abce34d5c79d..32cbffb0c494 100644
--- a/arch/x86/kernel/syscall_table_32.S
+++ b/arch/x86/kernel/syscall_table_32.S
@@ -344,3 +344,4 @@ ENTRY(sys_call_table)
.long sys_open_by_handle_at
.long sys_clock_adjtime
.long sys_syncfs
+ .long sys_sendmmsg /* 345 */
diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c
index 998e972f3b1a..30ac65df7d4e 100644
--- a/arch/x86/kernel/tboot.c
+++ b/arch/x86/kernel/tboot.c
@@ -110,7 +110,6 @@ static struct mm_struct tboot_mm = {
.mmap_sem = __RWSEM_INITIALIZER(init_mm.mmap_sem),
.page_table_lock = __SPIN_LOCK_UNLOCKED(init_mm.page_table_lock),
.mmlist = LIST_HEAD_INIT(init_mm.mmlist),
- .cpu_vm_mask = CPU_MASK_ALL,
};
static inline void switch_to_tboot_pt(void)
diff --git a/arch/x86/kernel/test_nx.c b/arch/x86/kernel/test_nx.c
index 787a5e499dd1..3f92ce07e525 100644
--- a/arch/x86/kernel/test_nx.c
+++ b/arch/x86/kernel/test_nx.c
@@ -161,7 +161,7 @@ static int test_NX(void)
}
#endif
- return 0;
+ return ret;
}
static void test_exit(void)
diff --git a/arch/x86/kernel/time.c b/arch/x86/kernel/time.c
index 25a28a245937..00cbb272627f 100644
--- a/arch/x86/kernel/time.c
+++ b/arch/x86/kernel/time.c
@@ -23,7 +23,7 @@
#include <asm/time.h>
#ifdef CONFIG_X86_64
-volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES;
+DEFINE_VVAR(volatile unsigned long, jiffies) = INITIAL_JIFFIES;
#endif
unsigned long profile_pc(struct pt_regs *regs)
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index 9335bf7dd2e7..6cc6922262af 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -763,25 +763,6 @@ static cycle_t read_tsc(struct clocksource *cs)
ret : clocksource_tsc.cycle_last;
}
-#ifdef CONFIG_X86_64
-static cycle_t __vsyscall_fn vread_tsc(void)
-{
- cycle_t ret;
-
- /*
- * Surround the RDTSC by barriers, to make sure it's not
- * speculated to outside the seqlock critical section and
- * does not cause time warps:
- */
- rdtsc_barrier();
- ret = (cycle_t)vget_cycles();
- rdtsc_barrier();
-
- return ret >= __vsyscall_gtod_data.clock.cycle_last ?
- ret : __vsyscall_gtod_data.clock.cycle_last;
-}
-#endif
-
static void resume_tsc(struct clocksource *cs)
{
clocksource_tsc.cycle_last = 0;
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index 624a2016198e..89aed99aafce 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -161,6 +161,12 @@ SECTIONS
#define VVIRT_OFFSET (VSYSCALL_ADDR - __vsyscall_0)
#define VVIRT(x) (ADDR(x) - VVIRT_OFFSET)
+#define EMIT_VVAR(x, offset) .vsyscall_var_ ## x \
+ ADDR(.vsyscall_0) + offset \
+ : AT(VLOAD(.vsyscall_var_ ## x)) { \
+ *(.vsyscall_var_ ## x) \
+ } \
+ x = VVIRT(.vsyscall_var_ ## x);
. = ALIGN(4096);
__vsyscall_0 = .;
@@ -175,18 +181,6 @@ SECTIONS
*(.vsyscall_fn)
}
- . = ALIGN(L1_CACHE_BYTES);
- .vsyscall_gtod_data : AT(VLOAD(.vsyscall_gtod_data)) {
- *(.vsyscall_gtod_data)
- }
-
- vsyscall_gtod_data = VVIRT(.vsyscall_gtod_data);
- .vsyscall_clock : AT(VLOAD(.vsyscall_clock)) {
- *(.vsyscall_clock)
- }
- vsyscall_clock = VVIRT(.vsyscall_clock);
-
-
.vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1)) {
*(.vsyscall_1)
}
@@ -194,21 +188,14 @@ SECTIONS
*(.vsyscall_2)
}
- .vgetcpu_mode : AT(VLOAD(.vgetcpu_mode)) {
- *(.vgetcpu_mode)
- }
- vgetcpu_mode = VVIRT(.vgetcpu_mode);
-
- . = ALIGN(L1_CACHE_BYTES);
- .jiffies : AT(VLOAD(.jiffies)) {
- *(.jiffies)
- }
- jiffies = VVIRT(.jiffies);
-
.vsyscall_3 ADDR(.vsyscall_0) + 3072: AT(VLOAD(.vsyscall_3)) {
*(.vsyscall_3)
}
+#define __VVAR_KERNEL_LDS
+#include <asm/vvar.h>
+#undef __VVAR_KERNEL_LDS
+
. = __vsyscall_0 + PAGE_SIZE;
#undef VSYSCALL_ADDR
@@ -216,6 +203,7 @@ SECTIONS
#undef VLOAD
#undef VVIRT_OFFSET
#undef VVIRT
+#undef EMIT_VVAR
#endif /* CONFIG_X86_64 */
@@ -306,6 +294,13 @@ SECTIONS
}
. = ALIGN(8);
+ .apicdrivers : AT(ADDR(.apicdrivers) - LOAD_OFFSET) {
+ __apicdrivers = .;
+ *(.apicdrivers);
+ __apicdrivers_end = .;
+ }
+
+ . = ALIGN(8);
/*
* .exit.text is discard at runtime, not link time, to deal with
* references from .altinstructions and .eh_frame
@@ -319,7 +314,7 @@ SECTIONS
}
#if !defined(CONFIG_X86_64) || !defined(CONFIG_SMP)
- PERCPU(INTERNODE_CACHE_BYTES, PAGE_SIZE)
+ PERCPU_SECTION(INTERNODE_CACHE_BYTES)
#endif
. = ALIGN(PAGE_SIZE);
diff --git a/arch/x86/kernel/vread_tsc_64.c b/arch/x86/kernel/vread_tsc_64.c
new file mode 100644
index 000000000000..a81aa9e9894c
--- /dev/null
+++ b/arch/x86/kernel/vread_tsc_64.c
@@ -0,0 +1,36 @@
+/* This code runs in userspace. */
+
+#define DISABLE_BRANCH_PROFILING
+#include <asm/vgtod.h>
+
+notrace cycle_t __vsyscall_fn vread_tsc(void)
+{
+ cycle_t ret;
+ u64 last;
+
+ /*
+ * Empirically, a fence (of type that depends on the CPU)
+ * before rdtsc is enough to ensure that rdtsc is ordered
+ * with respect to loads. The various CPU manuals are unclear
+ * as to whether rdtsc can be reordered with later loads,
+ * but no one has ever seen it happen.
+ */
+ rdtsc_barrier();
+ ret = (cycle_t)vget_cycles();
+
+ last = VVAR(vsyscall_gtod_data).clock.cycle_last;
+
+ if (likely(ret >= last))
+ return ret;
+
+ /*
+ * GCC likes to generate cmov here, but this branch is extremely
+ * predictable (it's just a funciton of time and the likely is
+ * very likely) and there's a data dependence, so force GCC
+ * to generate a branch instead. I don't barrier() because
+ * we don't actually need a barrier, and if this function
+ * ever gets inlined it will generate worse code.
+ */
+ asm volatile ("");
+ return last;
+}
diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c
index dcbb28c4b694..3e682184d76c 100644
--- a/arch/x86/kernel/vsyscall_64.c
+++ b/arch/x86/kernel/vsyscall_64.c
@@ -49,17 +49,10 @@
__attribute__ ((unused, __section__(".vsyscall_" #nr))) notrace
#define __syscall_clobber "r11","cx","memory"
-/*
- * vsyscall_gtod_data contains data that is :
- * - readonly from vsyscalls
- * - written by timer interrupt or systcl (/proc/sys/kernel/vsyscall64)
- * Try to keep this structure as small as possible to avoid cache line ping pongs
- */
-int __vgetcpu_mode __section_vgetcpu_mode;
-
-struct vsyscall_gtod_data __vsyscall_gtod_data __section_vsyscall_gtod_data =
+DEFINE_VVAR(int, vgetcpu_mode);
+DEFINE_VVAR(struct vsyscall_gtod_data, vsyscall_gtod_data) =
{
- .lock = SEQLOCK_UNLOCKED,
+ .lock = __SEQLOCK_UNLOCKED(__vsyscall_gtod_data.lock),
.sysctl_enabled = 1,
};
@@ -97,7 +90,7 @@ void update_vsyscall(struct timespec *wall_time, struct timespec *wtm,
*/
static __always_inline void do_get_tz(struct timezone * tz)
{
- *tz = __vsyscall_gtod_data.sys_tz;
+ *tz = VVAR(vsyscall_gtod_data).sys_tz;
}
static __always_inline int gettimeofday(struct timeval *tv, struct timezone *tz)
@@ -126,23 +119,24 @@ static __always_inline void do_vgettimeofday(struct timeval * tv)
unsigned long mult, shift, nsec;
cycle_t (*vread)(void);
do {
- seq = read_seqbegin(&__vsyscall_gtod_data.lock);
+ seq = read_seqbegin(&VVAR(vsyscall_gtod_data).lock);
- vread = __vsyscall_gtod_data.clock.vread;
- if (unlikely(!__vsyscall_gtod_data.sysctl_enabled || !vread)) {
+ vread = VVAR(vsyscall_gtod_data).clock.vread;
+ if (unlikely(!VVAR(vsyscall_gtod_data).sysctl_enabled ||
+ !vread)) {
gettimeofday(tv,NULL);
return;
}
now = vread();
- base = __vsyscall_gtod_data.clock.cycle_last;
- mask = __vsyscall_gtod_data.clock.mask;
- mult = __vsyscall_gtod_data.clock.mult;
- shift = __vsyscall_gtod_data.clock.shift;
+ base = VVAR(vsyscall_gtod_data).clock.cycle_last;
+ mask = VVAR(vsyscall_gtod_data).clock.mask;
+ mult = VVAR(vsyscall_gtod_data).clock.mult;
+ shift = VVAR(vsyscall_gtod_data).clock.shift;
- tv->tv_sec = __vsyscall_gtod_data.wall_time_sec;
- nsec = __vsyscall_gtod_data.wall_time_nsec;
- } while (read_seqretry(&__vsyscall_gtod_data.lock, seq));
+ tv->tv_sec = VVAR(vsyscall_gtod_data).wall_time_sec;
+ nsec = VVAR(vsyscall_gtod_data).wall_time_nsec;
+ } while (read_seqretry(&VVAR(vsyscall_gtod_data).lock, seq));
/* calculate interval: */
cycle_delta = (now - base) & mask;
@@ -171,15 +165,15 @@ time_t __vsyscall(1) vtime(time_t *t)
{
unsigned seq;
time_t result;
- if (unlikely(!__vsyscall_gtod_data.sysctl_enabled))
+ if (unlikely(!VVAR(vsyscall_gtod_data).sysctl_enabled))
return time_syscall(t);
do {
- seq = read_seqbegin(&__vsyscall_gtod_data.lock);
+ seq = read_seqbegin(&VVAR(vsyscall_gtod_data).lock);
- result = __vsyscall_gtod_data.wall_time_sec;
+ result = VVAR(vsyscall_gtod_data).wall_time_sec;
- } while (read_seqretry(&__vsyscall_gtod_data.lock, seq));
+ } while (read_seqretry(&VVAR(vsyscall_gtod_data).lock, seq));
if (t)
*t = result;
@@ -208,9 +202,9 @@ vgetcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache)
We do this here because otherwise user space would do it on
its own in a likely inferior way (no access to jiffies).
If you don't like it pass NULL. */
- if (tcache && tcache->blob[0] == (j = __jiffies)) {
+ if (tcache && tcache->blob[0] == (j = VVAR(jiffies))) {
p = tcache->blob[1];
- } else if (__vgetcpu_mode == VGETCPU_RDTSCP) {
+ } else if (VVAR(vgetcpu_mode) == VGETCPU_RDTSCP) {
/* Load per CPU data from RDTSCP */
native_read_tscp(&p);
} else {
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index 75ef4b18e9b7..6f164bd5e14d 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -35,7 +35,7 @@ void iommu_shutdown_noop(void) { }
struct x86_init_ops x86_init __initdata = {
.resources = {
- .probe_roms = x86_init_noop,
+ .probe_roms = probe_roms,
.reserve_resources = reserve_standard_io_resources,
.memory_setup = default_machine_specific_memory_setup,
},
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 0ad47b819a8b..d6e2477feb18 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -73,9 +73,14 @@
#define MemAbs (1<<11) /* Memory operand is absolute displacement */
#define String (1<<12) /* String instruction (rep capable) */
#define Stack (1<<13) /* Stack instruction (push/pop) */
+#define GroupMask (7<<14) /* Opcode uses one of the group mechanisms */
#define Group (1<<14) /* Bits 3:5 of modrm byte extend opcode */
-#define GroupDual (1<<15) /* Alternate decoding of mod == 3 */
+#define GroupDual (2<<14) /* Alternate decoding of mod == 3 */
+#define Prefix (3<<14) /* Instruction varies with 66/f2/f3 prefix */
+#define RMExt (4<<14) /* Opcode extension in ModRM r/m if mod == 3 */
+#define Sse (1<<17) /* SSE Vector instruction */
/* Misc flags */
+#define Prot (1<<21) /* instruction generates #UD if not in prot-mode */
#define VendorSpecific (1<<22) /* Vendor specific instruction */
#define NoAccess (1<<23) /* Don't access memory (lea/invlpg/verr etc) */
#define Op3264 (1<<24) /* Operand is 64b in long mode, 32b otherwise */
@@ -102,11 +107,14 @@
struct opcode {
u32 flags;
+ u8 intercept;
union {
int (*execute)(struct x86_emulate_ctxt *ctxt);
struct opcode *group;
struct group_dual *gdual;
+ struct gprefix *gprefix;
} u;
+ int (*check_perm)(struct x86_emulate_ctxt *ctxt);
};
struct group_dual {
@@ -114,6 +122,13 @@ struct group_dual {
struct opcode mod3[8];
};
+struct gprefix {
+ struct opcode pfx_no;
+ struct opcode pfx_66;
+ struct opcode pfx_f2;
+ struct opcode pfx_f3;
+};
+
/* EFLAGS bit definitions. */
#define EFLG_ID (1<<21)
#define EFLG_VIP (1<<20)
@@ -248,42 +263,42 @@ struct group_dual {
"w", "r", _LO32, "r", "", "r")
/* Instruction has three operands and one operand is stored in ECX register */
-#define __emulate_2op_cl(_op, _cl, _src, _dst, _eflags, _suffix, _type) \
- do { \
- unsigned long _tmp; \
- _type _clv = (_cl).val; \
- _type _srcv = (_src).val; \
- _type _dstv = (_dst).val; \
- \
- __asm__ __volatile__ ( \
- _PRE_EFLAGS("0", "5", "2") \
- _op _suffix " %4,%1 \n" \
- _POST_EFLAGS("0", "5", "2") \
- : "=m" (_eflags), "+r" (_dstv), "=&r" (_tmp) \
- : "c" (_clv) , "r" (_srcv), "i" (EFLAGS_MASK) \
- ); \
- \
- (_cl).val = (unsigned long) _clv; \
- (_src).val = (unsigned long) _srcv; \
- (_dst).val = (unsigned long) _dstv; \
+#define __emulate_2op_cl(_op, _cl, _src, _dst, _eflags, _suffix, _type) \
+ do { \
+ unsigned long _tmp; \
+ _type _clv = (_cl).val; \
+ _type _srcv = (_src).val; \
+ _type _dstv = (_dst).val; \
+ \
+ __asm__ __volatile__ ( \
+ _PRE_EFLAGS("0", "5", "2") \
+ _op _suffix " %4,%1 \n" \
+ _POST_EFLAGS("0", "5", "2") \
+ : "=m" (_eflags), "+r" (_dstv), "=&r" (_tmp) \
+ : "c" (_clv) , "r" (_srcv), "i" (EFLAGS_MASK) \
+ ); \
+ \
+ (_cl).val = (unsigned long) _clv; \
+ (_src).val = (unsigned long) _srcv; \
+ (_dst).val = (unsigned long) _dstv; \
} while (0)
-#define emulate_2op_cl(_op, _cl, _src, _dst, _eflags) \
- do { \
- switch ((_dst).bytes) { \
- case 2: \
- __emulate_2op_cl(_op, _cl, _src, _dst, _eflags, \
- "w", unsigned short); \
- break; \
- case 4: \
- __emulate_2op_cl(_op, _cl, _src, _dst, _eflags, \
- "l", unsigned int); \
- break; \
- case 8: \
- ON64(__emulate_2op_cl(_op, _cl, _src, _dst, _eflags, \
- "q", unsigned long)); \
- break; \
- } \
+#define emulate_2op_cl(_op, _cl, _src, _dst, _eflags) \
+ do { \
+ switch ((_dst).bytes) { \
+ case 2: \
+ __emulate_2op_cl(_op, _cl, _src, _dst, _eflags, \
+ "w", unsigned short); \
+ break; \
+ case 4: \
+ __emulate_2op_cl(_op, _cl, _src, _dst, _eflags, \
+ "l", unsigned int); \
+ break; \
+ case 8: \
+ ON64(__emulate_2op_cl(_op, _cl, _src, _dst, _eflags, \
+ "q", unsigned long)); \
+ break; \
+ } \
} while (0)
#define __emulate_1op(_op, _dst, _eflags, _suffix) \
@@ -346,13 +361,25 @@ struct group_dual {
} while (0)
/* instruction has only one source operand, destination is implicit (e.g. mul, div, imul, idiv) */
-#define emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags) \
- do { \
- switch((_src).bytes) { \
- case 1: __emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags, "b"); break; \
- case 2: __emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags, "w"); break; \
- case 4: __emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags, "l"); break; \
- case 8: ON64(__emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags, "q")); break; \
+#define emulate_1op_rax_rdx(_op, _src, _rax, _rdx, _eflags) \
+ do { \
+ switch((_src).bytes) { \
+ case 1: \
+ __emulate_1op_rax_rdx(_op, _src, _rax, _rdx, \
+ _eflags, "b"); \
+ break; \
+ case 2: \
+ __emulate_1op_rax_rdx(_op, _src, _rax, _rdx, \
+ _eflags, "w"); \
+ break; \
+ case 4: \
+ __emulate_1op_rax_rdx(_op, _src, _rax, _rdx, \
+ _eflags, "l"); \
+ break; \
+ case 8: \
+ ON64(__emulate_1op_rax_rdx(_op, _src, _rax, _rdx, \
+ _eflags, "q")); \
+ break; \
} \
} while (0)
@@ -388,13 +415,33 @@ struct group_dual {
(_type)_x; \
})
-#define insn_fetch_arr(_arr, _size, _eip) \
+#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 int emulator_check_intercept(struct x86_emulate_ctxt *ctxt,
+ enum x86_intercept intercept,
+ enum x86_intercept_stage stage)
+{
+ struct x86_instruction_info info = {
+ .intercept = intercept,
+ .rep_prefix = ctxt->decode.rep_prefix,
+ .modrm_mod = ctxt->decode.modrm_mod,
+ .modrm_reg = ctxt->decode.modrm_reg,
+ .modrm_rm = ctxt->decode.modrm_rm,
+ .src_val = ctxt->decode.src.val64,
+ .src_bytes = ctxt->decode.src.bytes,
+ .dst_bytes = ctxt->decode.dst.bytes,
+ .ad_bytes = ctxt->decode.ad_bytes,
+ .next_rip = ctxt->eip,
+ };
+
+ return ctxt->ops->intercept(ctxt, &info, stage);
+}
+
static inline unsigned long ad_mask(struct decode_cache *c)
{
return (1UL << (c->ad_bytes << 3)) - 1;
@@ -430,6 +477,13 @@ static inline void jmp_rel(struct decode_cache *c, int rel)
register_address_increment(c, &c->eip, rel);
}
+static u32 desc_limit_scaled(struct desc_struct *desc)
+{
+ u32 limit = get_desc_limit(desc);
+
+ return desc->g ? (limit << 12) | 0xfff : limit;
+}
+
static void set_seg_override(struct decode_cache *c, int seg)
{
c->has_seg_override = true;
@@ -442,11 +496,10 @@ static unsigned long seg_base(struct x86_emulate_ctxt *ctxt,
if (ctxt->mode == X86EMUL_MODE_PROT64 && seg < VCPU_SREG_FS)
return 0;
- return ops->get_cached_segment_base(seg, ctxt->vcpu);
+ return ops->get_cached_segment_base(ctxt, seg);
}
static unsigned seg_override(struct x86_emulate_ctxt *ctxt,
- struct x86_emulate_ops *ops,
struct decode_cache *c)
{
if (!c->has_seg_override)
@@ -455,18 +508,6 @@ static unsigned seg_override(struct x86_emulate_ctxt *ctxt,
return c->seg_override;
}
-static ulong linear(struct x86_emulate_ctxt *ctxt,
- struct segmented_address addr)
-{
- struct decode_cache *c = &ctxt->decode;
- ulong la;
-
- la = seg_base(ctxt, ctxt->ops, addr.seg) + addr.ea;
- if (c->ad_bytes != 8)
- la &= (u32)-1;
- return la;
-}
-
static int emulate_exception(struct x86_emulate_ctxt *ctxt, int vec,
u32 error, bool valid)
{
@@ -476,11 +517,21 @@ static int emulate_exception(struct x86_emulate_ctxt *ctxt, int vec,
return X86EMUL_PROPAGATE_FAULT;
}
+static int emulate_db(struct x86_emulate_ctxt *ctxt)
+{
+ return emulate_exception(ctxt, DB_VECTOR, 0, false);
+}
+
static int emulate_gp(struct x86_emulate_ctxt *ctxt, int err)
{
return emulate_exception(ctxt, GP_VECTOR, err, true);
}
+static int emulate_ss(struct x86_emulate_ctxt *ctxt, int err)
+{
+ return emulate_exception(ctxt, SS_VECTOR, err, true);
+}
+
static int emulate_ud(struct x86_emulate_ctxt *ctxt)
{
return emulate_exception(ctxt, UD_VECTOR, 0, false);
@@ -496,6 +547,128 @@ static int emulate_de(struct x86_emulate_ctxt *ctxt)
return emulate_exception(ctxt, DE_VECTOR, 0, false);
}
+static int emulate_nm(struct x86_emulate_ctxt *ctxt)
+{
+ return emulate_exception(ctxt, NM_VECTOR, 0, false);
+}
+
+static u16 get_segment_selector(struct x86_emulate_ctxt *ctxt, unsigned seg)
+{
+ u16 selector;
+ struct desc_struct desc;
+
+ ctxt->ops->get_segment(ctxt, &selector, &desc, NULL, seg);
+ return selector;
+}
+
+static void set_segment_selector(struct x86_emulate_ctxt *ctxt, u16 selector,
+ unsigned seg)
+{
+ u16 dummy;
+ u32 base3;
+ struct desc_struct desc;
+
+ ctxt->ops->get_segment(ctxt, &dummy, &desc, &base3, seg);
+ ctxt->ops->set_segment(ctxt, selector, &desc, base3, seg);
+}
+
+static int __linearize(struct x86_emulate_ctxt *ctxt,
+ struct segmented_address addr,
+ unsigned size, bool write, bool fetch,
+ ulong *linear)
+{
+ struct decode_cache *c = &ctxt->decode;
+ struct desc_struct desc;
+ bool usable;
+ ulong la;
+ u32 lim;
+ u16 sel;
+ unsigned cpl, rpl;
+
+ la = seg_base(ctxt, ctxt->ops, addr.seg) + addr.ea;
+ switch (ctxt->mode) {
+ case X86EMUL_MODE_REAL:
+ break;
+ case X86EMUL_MODE_PROT64:
+ if (((signed long)la << 16) >> 16 != la)
+ return emulate_gp(ctxt, 0);
+ break;
+ default:
+ usable = ctxt->ops->get_segment(ctxt, &sel, &desc, NULL,
+ addr.seg);
+ if (!usable)
+ goto bad;
+ /* code segment or read-only data segment */
+ if (((desc.type & 8) || !(desc.type & 2)) && write)
+ goto bad;
+ /* unreadable code segment */
+ if (!fetch && (desc.type & 8) && !(desc.type & 2))
+ goto bad;
+ lim = desc_limit_scaled(&desc);
+ if ((desc.type & 8) || !(desc.type & 4)) {
+ /* expand-up segment */
+ if (addr.ea > lim || (u32)(addr.ea + size - 1) > lim)
+ goto bad;
+ } else {
+ /* exapand-down segment */
+ if (addr.ea <= lim || (u32)(addr.ea + size - 1) <= lim)
+ goto bad;
+ lim = desc.d ? 0xffffffff : 0xffff;
+ if (addr.ea > lim || (u32)(addr.ea + size - 1) > lim)
+ goto bad;
+ }
+ cpl = ctxt->ops->cpl(ctxt);
+ rpl = sel & 3;
+ cpl = max(cpl, rpl);
+ if (!(desc.type & 8)) {
+ /* data segment */
+ if (cpl > desc.dpl)
+ goto bad;
+ } else if ((desc.type & 8) && !(desc.type & 4)) {
+ /* nonconforming code segment */
+ if (cpl != desc.dpl)
+ goto bad;
+ } else if ((desc.type & 8) && (desc.type & 4)) {
+ /* conforming code segment */
+ if (cpl < desc.dpl)
+ goto bad;
+ }
+ break;
+ }
+ if (fetch ? ctxt->mode != X86EMUL_MODE_PROT64 : c->ad_bytes != 8)
+ la &= (u32)-1;
+ *linear = la;
+ return X86EMUL_CONTINUE;
+bad:
+ if (addr.seg == VCPU_SREG_SS)
+ return emulate_ss(ctxt, addr.seg);
+ else
+ return emulate_gp(ctxt, addr.seg);
+}
+
+static int linearize(struct x86_emulate_ctxt *ctxt,
+ struct segmented_address addr,
+ unsigned size, bool write,
+ ulong *linear)
+{
+ return __linearize(ctxt, addr, size, write, false, linear);
+}
+
+
+static int segmented_read_std(struct x86_emulate_ctxt *ctxt,
+ struct segmented_address addr,
+ void *data,
+ unsigned size)
+{
+ int rc;
+ ulong linear;
+
+ rc = linearize(ctxt, addr, size, false, &linear);
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+ return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception);
+}
+
static int do_fetch_insn_byte(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops,
unsigned long eip, u8 *dest)
@@ -505,10 +678,15 @@ static int do_fetch_insn_byte(struct x86_emulate_ctxt *ctxt,
int size, cur_size;
if (eip == fc->end) {
+ unsigned long linear;
+ struct segmented_address addr = { .seg=VCPU_SREG_CS, .ea=eip};
cur_size = fc->end - fc->start;
size = min(15UL - cur_size, PAGE_SIZE - offset_in_page(eip));
- rc = ops->fetch(ctxt->cs_base + eip, fc->data + cur_size,
- size, ctxt->vcpu, &ctxt->exception);
+ rc = __linearize(ctxt, addr, size, false, true, &linear);
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+ rc = ops->fetch(ctxt, linear, fc->data + cur_size,
+ size, &ctxt->exception);
if (rc != X86EMUL_CONTINUE)
return rc;
fc->end += size;
@@ -551,7 +729,6 @@ static void *decode_register(u8 modrm_reg, unsigned long *regs,
}
static int read_descriptor(struct x86_emulate_ctxt *ctxt,
- struct x86_emulate_ops *ops,
struct segmented_address addr,
u16 *size, unsigned long *address, int op_bytes)
{
@@ -560,13 +737,11 @@ static int read_descriptor(struct x86_emulate_ctxt *ctxt,
if (op_bytes == 2)
op_bytes = 3;
*address = 0;
- rc = ops->read_std(linear(ctxt, addr), (unsigned long *)size, 2,
- ctxt->vcpu, &ctxt->exception);
+ rc = segmented_read_std(ctxt, addr, size, 2);
if (rc != X86EMUL_CONTINUE)
return rc;
addr.ea += 2;
- rc = ops->read_std(linear(ctxt, addr), address, op_bytes,
- ctxt->vcpu, &ctxt->exception);
+ rc = segmented_read_std(ctxt, addr, address, op_bytes);
return rc;
}
@@ -623,7 +798,63 @@ static void fetch_register_operand(struct operand *op)
}
}
-static void decode_register_operand(struct operand *op,
+static void read_sse_reg(struct x86_emulate_ctxt *ctxt, sse128_t *data, int reg)
+{
+ ctxt->ops->get_fpu(ctxt);
+ switch (reg) {
+ case 0: asm("movdqu %%xmm0, %0" : "=m"(*data)); break;
+ case 1: asm("movdqu %%xmm1, %0" : "=m"(*data)); break;
+ case 2: asm("movdqu %%xmm2, %0" : "=m"(*data)); break;
+ case 3: asm("movdqu %%xmm3, %0" : "=m"(*data)); break;
+ case 4: asm("movdqu %%xmm4, %0" : "=m"(*data)); break;
+ case 5: asm("movdqu %%xmm5, %0" : "=m"(*data)); break;
+ case 6: asm("movdqu %%xmm6, %0" : "=m"(*data)); break;
+ case 7: asm("movdqu %%xmm7, %0" : "=m"(*data)); break;
+#ifdef CONFIG_X86_64
+ case 8: asm("movdqu %%xmm8, %0" : "=m"(*data)); break;
+ case 9: asm("movdqu %%xmm9, %0" : "=m"(*data)); break;
+ case 10: asm("movdqu %%xmm10, %0" : "=m"(*data)); break;
+ case 11: asm("movdqu %%xmm11, %0" : "=m"(*data)); break;
+ case 12: asm("movdqu %%xmm12, %0" : "=m"(*data)); break;
+ case 13: asm("movdqu %%xmm13, %0" : "=m"(*data)); break;
+ case 14: asm("movdqu %%xmm14, %0" : "=m"(*data)); break;
+ case 15: asm("movdqu %%xmm15, %0" : "=m"(*data)); break;
+#endif
+ default: BUG();
+ }
+ ctxt->ops->put_fpu(ctxt);
+}
+
+static void write_sse_reg(struct x86_emulate_ctxt *ctxt, sse128_t *data,
+ int reg)
+{
+ ctxt->ops->get_fpu(ctxt);
+ switch (reg) {
+ case 0: asm("movdqu %0, %%xmm0" : : "m"(*data)); break;
+ case 1: asm("movdqu %0, %%xmm1" : : "m"(*data)); break;
+ case 2: asm("movdqu %0, %%xmm2" : : "m"(*data)); break;
+ case 3: asm("movdqu %0, %%xmm3" : : "m"(*data)); break;
+ case 4: asm("movdqu %0, %%xmm4" : : "m"(*data)); break;
+ case 5: asm("movdqu %0, %%xmm5" : : "m"(*data)); break;
+ case 6: asm("movdqu %0, %%xmm6" : : "m"(*data)); break;
+ case 7: asm("movdqu %0, %%xmm7" : : "m"(*data)); break;
+#ifdef CONFIG_X86_64
+ case 8: asm("movdqu %0, %%xmm8" : : "m"(*data)); break;
+ case 9: asm("movdqu %0, %%xmm9" : : "m"(*data)); break;
+ case 10: asm("movdqu %0, %%xmm10" : : "m"(*data)); break;
+ case 11: asm("movdqu %0, %%xmm11" : : "m"(*data)); break;
+ case 12: asm("movdqu %0, %%xmm12" : : "m"(*data)); break;
+ case 13: asm("movdqu %0, %%xmm13" : : "m"(*data)); break;
+ case 14: asm("movdqu %0, %%xmm14" : : "m"(*data)); break;
+ case 15: asm("movdqu %0, %%xmm15" : : "m"(*data)); break;
+#endif
+ default: BUG();
+ }
+ ctxt->ops->put_fpu(ctxt);
+}
+
+static void decode_register_operand(struct x86_emulate_ctxt *ctxt,
+ struct operand *op,
struct decode_cache *c,
int inhibit_bytereg)
{
@@ -632,6 +863,15 @@ static void decode_register_operand(struct operand *op,
if (!(c->d & ModRM))
reg = (c->b & 7) | ((c->rex_prefix & 1) << 3);
+
+ if (c->d & Sse) {
+ op->type = OP_XMM;
+ op->bytes = 16;
+ op->addr.xmm = reg;
+ read_sse_reg(ctxt, &op->vec_val, reg);
+ return;
+ }
+
op->type = OP_REG;
if ((c->d & ByteOp) && !inhibit_bytereg) {
op->addr.reg = decode_register(reg, c->regs, highbyte_regs);
@@ -671,6 +911,13 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt,
op->bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
op->addr.reg = decode_register(c->modrm_rm,
c->regs, c->d & ByteOp);
+ if (c->d & Sse) {
+ op->type = OP_XMM;
+ op->bytes = 16;
+ op->addr.xmm = c->modrm_rm;
+ read_sse_reg(ctxt, &op->vec_val, c->modrm_rm);
+ return rc;
+ }
fetch_register_operand(op);
return rc;
}
@@ -819,8 +1066,8 @@ static int read_emulated(struct x86_emulate_ctxt *ctxt,
if (mc->pos < mc->end)
goto read_cached;
- rc = ops->read_emulated(addr, mc->data + mc->end, n,
- &ctxt->exception, ctxt->vcpu);
+ rc = ops->read_emulated(ctxt, addr, mc->data + mc->end, n,
+ &ctxt->exception);
if (rc != X86EMUL_CONTINUE)
return rc;
mc->end += n;
@@ -834,6 +1081,50 @@ static int read_emulated(struct x86_emulate_ctxt *ctxt,
return X86EMUL_CONTINUE;
}
+static int segmented_read(struct x86_emulate_ctxt *ctxt,
+ struct segmented_address addr,
+ void *data,
+ unsigned size)
+{
+ int rc;
+ ulong linear;
+
+ rc = linearize(ctxt, addr, size, false, &linear);
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+ return read_emulated(ctxt, ctxt->ops, linear, data, size);
+}
+
+static int segmented_write(struct x86_emulate_ctxt *ctxt,
+ struct segmented_address addr,
+ const void *data,
+ unsigned size)
+{
+ int rc;
+ ulong linear;
+
+ rc = linearize(ctxt, addr, size, true, &linear);
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+ return ctxt->ops->write_emulated(ctxt, linear, data, size,
+ &ctxt->exception);
+}
+
+static int segmented_cmpxchg(struct x86_emulate_ctxt *ctxt,
+ struct segmented_address addr,
+ const void *orig_data, const void *data,
+ unsigned size)
+{
+ int rc;
+ ulong linear;
+
+ rc = linearize(ctxt, addr, size, true, &linear);
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+ return ctxt->ops->cmpxchg_emulated(ctxt, linear, orig_data, data,
+ size, &ctxt->exception);
+}
+
static int pio_in_emulated(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops,
unsigned int size, unsigned short port,
@@ -854,7 +1145,7 @@ static int pio_in_emulated(struct x86_emulate_ctxt *ctxt,
if (n == 0)
n = 1;
rc->pos = rc->end = 0;
- if (!ops->pio_in_emulated(size, port, rc->data, n, ctxt->vcpu))
+ if (!ops->pio_in_emulated(ctxt, size, port, rc->data, n))
return 0;
rc->end = n * size;
}
@@ -864,28 +1155,22 @@ static int pio_in_emulated(struct x86_emulate_ctxt *ctxt,
return 1;
}
-static u32 desc_limit_scaled(struct desc_struct *desc)
-{
- u32 limit = get_desc_limit(desc);
-
- return desc->g ? (limit << 12) | 0xfff : limit;
-}
-
static void get_descriptor_table_ptr(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops,
u16 selector, struct desc_ptr *dt)
{
if (selector & 1 << 2) {
struct desc_struct desc;
+ u16 sel;
+
memset (dt, 0, sizeof *dt);
- if (!ops->get_cached_descriptor(&desc, NULL, VCPU_SREG_LDTR,
- ctxt->vcpu))
+ if (!ops->get_segment(ctxt, &sel, &desc, NULL, VCPU_SREG_LDTR))
return;
dt->size = desc_limit_scaled(&desc); /* what if limit > 65535? */
dt->address = get_desc_base(&desc);
} else
- ops->get_gdt(dt, ctxt->vcpu);
+ ops->get_gdt(ctxt, dt);
}
/* allowed just for 8 bytes segments */
@@ -903,8 +1188,7 @@ static int read_segment_descriptor(struct x86_emulate_ctxt *ctxt,
if (dt.size < index * 8 + 7)
return emulate_gp(ctxt, selector & 0xfffc);
addr = dt.address + index * 8;
- ret = ops->read_std(addr, desc, sizeof *desc, ctxt->vcpu,
- &ctxt->exception);
+ ret = ops->read_std(ctxt, addr, desc, sizeof *desc, &ctxt->exception);
return ret;
}
@@ -925,8 +1209,7 @@ static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt,
return emulate_gp(ctxt, selector & 0xfffc);
addr = dt.address + index * 8;
- ret = ops->write_std(addr, desc, sizeof *desc, ctxt->vcpu,
- &ctxt->exception);
+ ret = ops->write_std(ctxt, addr, desc, sizeof *desc, &ctxt->exception);
return ret;
}
@@ -986,7 +1269,7 @@ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
rpl = selector & 3;
dpl = seg_desc.dpl;
- cpl = ops->cpl(ctxt->vcpu);
+ cpl = ops->cpl(ctxt);
switch (seg) {
case VCPU_SREG_SS:
@@ -1042,8 +1325,7 @@ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
return ret;
}
load:
- ops->set_segment_selector(selector, seg, ctxt->vcpu);
- ops->set_cached_descriptor(&seg_desc, 0, seg, ctxt->vcpu);
+ ops->set_segment(ctxt, selector, &seg_desc, 0, seg);
return X86EMUL_CONTINUE;
exception:
emulate_exception(ctxt, err_vec, err_code, true);
@@ -1069,8 +1351,7 @@ static void write_register_operand(struct operand *op)
}
}
-static inline int writeback(struct x86_emulate_ctxt *ctxt,
- struct x86_emulate_ops *ops)
+static int writeback(struct x86_emulate_ctxt *ctxt)
{
int rc;
struct decode_cache *c = &ctxt->decode;
@@ -1081,23 +1362,22 @@ static inline int writeback(struct x86_emulate_ctxt *ctxt,
break;
case OP_MEM:
if (c->lock_prefix)
- rc = ops->cmpxchg_emulated(
- linear(ctxt, c->dst.addr.mem),
- &c->dst.orig_val,
- &c->dst.val,
- c->dst.bytes,
- &ctxt->exception,
- ctxt->vcpu);
+ rc = segmented_cmpxchg(ctxt,
+ c->dst.addr.mem,
+ &c->dst.orig_val,
+ &c->dst.val,
+ c->dst.bytes);
else
- rc = ops->write_emulated(
- linear(ctxt, c->dst.addr.mem),
- &c->dst.val,
- c->dst.bytes,
- &ctxt->exception,
- ctxt->vcpu);
+ rc = segmented_write(ctxt,
+ c->dst.addr.mem,
+ &c->dst.val,
+ c->dst.bytes);
if (rc != X86EMUL_CONTINUE)
return rc;
break;
+ case OP_XMM:
+ write_sse_reg(ctxt, &c->dst.vec_val, c->dst.addr.xmm);
+ break;
case OP_NONE:
/* no writeback */
break;
@@ -1107,21 +1387,21 @@ static inline int writeback(struct x86_emulate_ctxt *ctxt,
return X86EMUL_CONTINUE;
}
-static inline void emulate_push(struct x86_emulate_ctxt *ctxt,
- struct x86_emulate_ops *ops)
+static int em_push(struct x86_emulate_ctxt *ctxt)
{
struct decode_cache *c = &ctxt->decode;
+ struct segmented_address addr;
- c->dst.type = OP_MEM;
- 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.addr.mem.ea = register_address(c, c->regs[VCPU_REGS_RSP]);
- c->dst.addr.mem.seg = VCPU_SREG_SS;
+ addr.ea = register_address(c, c->regs[VCPU_REGS_RSP]);
+ addr.seg = VCPU_SREG_SS;
+
+ /* Disable writeback. */
+ c->dst.type = OP_NONE;
+ return segmented_write(ctxt, addr, &c->src.val, c->op_bytes);
}
static int emulate_pop(struct x86_emulate_ctxt *ctxt,
- struct x86_emulate_ops *ops,
void *dest, int len)
{
struct decode_cache *c = &ctxt->decode;
@@ -1130,7 +1410,7 @@ static int emulate_pop(struct x86_emulate_ctxt *ctxt,
addr.ea = register_address(c, c->regs[VCPU_REGS_RSP]);
addr.seg = VCPU_SREG_SS;
- rc = read_emulated(ctxt, ops, linear(ctxt, addr), dest, len);
+ rc = segmented_read(ctxt, addr, dest, len);
if (rc != X86EMUL_CONTINUE)
return rc;
@@ -1138,6 +1418,13 @@ static int emulate_pop(struct x86_emulate_ctxt *ctxt,
return rc;
}
+static int em_pop(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+
+ return emulate_pop(ctxt, &c->dst.val, c->op_bytes);
+}
+
static int emulate_popf(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops,
void *dest, int len)
@@ -1145,9 +1432,9 @@ static int emulate_popf(struct x86_emulate_ctxt *ctxt,
int rc;
unsigned long val, change_mask;
int iopl = (ctxt->eflags & X86_EFLAGS_IOPL) >> IOPL_SHIFT;
- int cpl = ops->cpl(ctxt->vcpu);
+ int cpl = ops->cpl(ctxt);
- rc = emulate_pop(ctxt, ops, &val, len);
+ rc = emulate_pop(ctxt, &val, len);
if (rc != X86EMUL_CONTINUE)
return rc;
@@ -1179,14 +1466,24 @@ static int emulate_popf(struct x86_emulate_ctxt *ctxt,
return rc;
}
-static void emulate_push_sreg(struct x86_emulate_ctxt *ctxt,
- struct x86_emulate_ops *ops, int seg)
+static int em_popf(struct x86_emulate_ctxt *ctxt)
{
struct decode_cache *c = &ctxt->decode;
- c->src.val = ops->get_segment_selector(seg, ctxt->vcpu);
+ c->dst.type = OP_REG;
+ c->dst.addr.reg = &ctxt->eflags;
+ c->dst.bytes = c->op_bytes;
+ return emulate_popf(ctxt, ctxt->ops, &c->dst.val, c->op_bytes);
+}
- emulate_push(ctxt, ops);
+static int emulate_push_sreg(struct x86_emulate_ctxt *ctxt,
+ struct x86_emulate_ops *ops, int seg)
+{
+ struct decode_cache *c = &ctxt->decode;
+
+ c->src.val = get_segment_selector(ctxt, seg);
+
+ return em_push(ctxt);
}
static int emulate_pop_sreg(struct x86_emulate_ctxt *ctxt,
@@ -1196,7 +1493,7 @@ static int emulate_pop_sreg(struct x86_emulate_ctxt *ctxt,
unsigned long selector;
int rc;
- rc = emulate_pop(ctxt, ops, &selector, c->op_bytes);
+ rc = emulate_pop(ctxt, &selector, c->op_bytes);
if (rc != X86EMUL_CONTINUE)
return rc;
@@ -1204,8 +1501,7 @@ static int emulate_pop_sreg(struct x86_emulate_ctxt *ctxt,
return rc;
}
-static int emulate_pusha(struct x86_emulate_ctxt *ctxt,
- struct x86_emulate_ops *ops)
+static int em_pusha(struct x86_emulate_ctxt *ctxt)
{
struct decode_cache *c = &ctxt->decode;
unsigned long old_esp = c->regs[VCPU_REGS_RSP];
@@ -1216,23 +1512,25 @@ static int emulate_pusha(struct x86_emulate_ctxt *ctxt,
(reg == VCPU_REGS_RSP) ?
(c->src.val = old_esp) : (c->src.val = c->regs[reg]);
- emulate_push(ctxt, ops);
-
- rc = writeback(ctxt, ops);
+ rc = em_push(ctxt);
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,
- struct x86_emulate_ops *ops)
+static int em_pushf(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+
+ c->src.val = (unsigned long)ctxt->eflags;
+ return em_push(ctxt);
+}
+
+static int em_popa(struct x86_emulate_ctxt *ctxt)
{
struct decode_cache *c = &ctxt->decode;
int rc = X86EMUL_CONTINUE;
@@ -1245,7 +1543,7 @@ static int emulate_popa(struct x86_emulate_ctxt *ctxt,
--reg;
}
- rc = emulate_pop(ctxt, ops, &c->regs[reg], c->op_bytes);
+ rc = emulate_pop(ctxt, &c->regs[reg], c->op_bytes);
if (rc != X86EMUL_CONTINUE)
break;
--reg;
@@ -1265,37 +1563,32 @@ int emulate_int_real(struct x86_emulate_ctxt *ctxt,
/* TODO: Add limit checks */
c->src.val = ctxt->eflags;
- emulate_push(ctxt, ops);
- rc = writeback(ctxt, ops);
+ rc = em_push(ctxt);
if (rc != X86EMUL_CONTINUE)
return rc;
ctxt->eflags &= ~(EFLG_IF | EFLG_TF | EFLG_AC);
- c->src.val = ops->get_segment_selector(VCPU_SREG_CS, ctxt->vcpu);
- emulate_push(ctxt, ops);
- rc = writeback(ctxt, ops);
+ c->src.val = get_segment_selector(ctxt, VCPU_SREG_CS);
+ rc = em_push(ctxt);
if (rc != X86EMUL_CONTINUE)
return rc;
c->src.val = c->eip;
- emulate_push(ctxt, ops);
- rc = writeback(ctxt, ops);
+ rc = em_push(ctxt);
if (rc != X86EMUL_CONTINUE)
return rc;
- c->dst.type = OP_NONE;
-
- ops->get_idt(&dt, ctxt->vcpu);
+ ops->get_idt(ctxt, &dt);
eip_addr = dt.address + (irq << 2);
cs_addr = dt.address + (irq << 2) + 2;
- rc = ops->read_std(cs_addr, &cs, 2, ctxt->vcpu, &ctxt->exception);
+ rc = ops->read_std(ctxt, cs_addr, &cs, 2, &ctxt->exception);
if (rc != X86EMUL_CONTINUE)
return rc;
- rc = ops->read_std(eip_addr, &eip, 2, ctxt->vcpu, &ctxt->exception);
+ rc = ops->read_std(ctxt, eip_addr, &eip, 2, &ctxt->exception);
if (rc != X86EMUL_CONTINUE)
return rc;
@@ -1339,7 +1632,7 @@ static int emulate_iret_real(struct x86_emulate_ctxt *ctxt,
/* TODO: Add stack limit check */
- rc = emulate_pop(ctxt, ops, &temp_eip, c->op_bytes);
+ rc = emulate_pop(ctxt, &temp_eip, c->op_bytes);
if (rc != X86EMUL_CONTINUE)
return rc;
@@ -1347,12 +1640,12 @@ static int emulate_iret_real(struct x86_emulate_ctxt *ctxt,
if (temp_eip & ~0xffff)
return emulate_gp(ctxt, 0);
- rc = emulate_pop(ctxt, ops, &cs, c->op_bytes);
+ rc = emulate_pop(ctxt, &cs, c->op_bytes);
if (rc != X86EMUL_CONTINUE)
return rc;
- rc = emulate_pop(ctxt, ops, &temp_eflags, c->op_bytes);
+ rc = emulate_pop(ctxt, &temp_eflags, c->op_bytes);
if (rc != X86EMUL_CONTINUE)
return rc;
@@ -1394,15 +1687,31 @@ static inline int emulate_iret(struct x86_emulate_ctxt *ctxt,
}
}
-static inline int emulate_grp1a(struct x86_emulate_ctxt *ctxt,
- struct x86_emulate_ops *ops)
+static int em_jmp_far(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+ int rc;
+ unsigned short sel;
+
+ memcpy(&sel, c->src.valptr + c->op_bytes, 2);
+
+ rc = load_segment_descriptor(ctxt, ctxt->ops, sel, VCPU_SREG_CS);
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+
+ c->eip = 0;
+ memcpy(&c->eip, c->src.valptr, c->op_bytes);
+ return X86EMUL_CONTINUE;
+}
+
+static int em_grp1a(struct x86_emulate_ctxt *ctxt)
{
struct decode_cache *c = &ctxt->decode;
- return emulate_pop(ctxt, ops, &c->dst.val, c->dst.bytes);
+ return emulate_pop(ctxt, &c->dst.val, c->dst.bytes);
}
-static inline void emulate_grp2(struct x86_emulate_ctxt *ctxt)
+static int em_grp2(struct x86_emulate_ctxt *ctxt)
{
struct decode_cache *c = &ctxt->decode;
switch (c->modrm_reg) {
@@ -1429,10 +1738,10 @@ static inline void emulate_grp2(struct x86_emulate_ctxt *ctxt)
emulate_2op_SrcB("sar", c->src, c->dst, ctxt->eflags);
break;
}
+ return X86EMUL_CONTINUE;
}
-static inline int emulate_grp3(struct x86_emulate_ctxt *ctxt,
- struct x86_emulate_ops *ops)
+static int em_grp3(struct x86_emulate_ctxt *ctxt)
{
struct decode_cache *c = &ctxt->decode;
unsigned long *rax = &c->regs[VCPU_REGS_RAX];
@@ -1471,10 +1780,10 @@ static inline int emulate_grp3(struct x86_emulate_ctxt *ctxt,
return X86EMUL_CONTINUE;
}
-static inline int emulate_grp45(struct x86_emulate_ctxt *ctxt,
- struct x86_emulate_ops *ops)
+static int em_grp45(struct x86_emulate_ctxt *ctxt)
{
struct decode_cache *c = &ctxt->decode;
+ int rc = X86EMUL_CONTINUE;
switch (c->modrm_reg) {
case 0: /* inc */
@@ -1488,21 +1797,23 @@ 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, ops);
+ rc = em_push(ctxt);
break;
}
case 4: /* jmp abs */
c->eip = c->src.val;
break;
+ case 5: /* jmp far */
+ rc = em_jmp_far(ctxt);
+ break;
case 6: /* push */
- emulate_push(ctxt, ops);
+ rc = em_push(ctxt);
break;
}
- return X86EMUL_CONTINUE;
+ return rc;
}
-static inline int emulate_grp9(struct x86_emulate_ctxt *ctxt,
- struct x86_emulate_ops *ops)
+static int em_grp9(struct x86_emulate_ctxt *ctxt)
{
struct decode_cache *c = &ctxt->decode;
u64 old = c->dst.orig_val64;
@@ -1528,12 +1839,12 @@ static int emulate_ret_far(struct x86_emulate_ctxt *ctxt,
int rc;
unsigned long cs;
- rc = emulate_pop(ctxt, ops, &c->eip, c->op_bytes);
+ rc = emulate_pop(ctxt, &c->eip, c->op_bytes);
if (rc != X86EMUL_CONTINUE)
return rc;
if (c->op_bytes == 4)
c->eip = (u32)c->eip;
- rc = emulate_pop(ctxt, ops, &cs, c->op_bytes);
+ rc = emulate_pop(ctxt, &cs, c->op_bytes);
if (rc != X86EMUL_CONTINUE)
return rc;
rc = load_segment_descriptor(ctxt, ops, (u16)cs, VCPU_SREG_CS);
@@ -1562,8 +1873,10 @@ setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
struct x86_emulate_ops *ops, struct desc_struct *cs,
struct desc_struct *ss)
{
+ u16 selector;
+
memset(cs, 0, sizeof(struct desc_struct));
- ops->get_cached_descriptor(cs, NULL, VCPU_SREG_CS, ctxt->vcpu);
+ ops->get_segment(ctxt, &selector, cs, NULL, VCPU_SREG_CS);
memset(ss, 0, sizeof(struct desc_struct));
cs->l = 0; /* will be adjusted later */
@@ -1593,44 +1906,44 @@ emulate_syscall(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
struct desc_struct cs, ss;
u64 msr_data;
u16 cs_sel, ss_sel;
+ u64 efer = 0;
/* syscall is not available in real mode */
if (ctxt->mode == X86EMUL_MODE_REAL ||
ctxt->mode == X86EMUL_MODE_VM86)
return emulate_ud(ctxt);
+ ops->get_msr(ctxt, MSR_EFER, &efer);
setup_syscalls_segments(ctxt, ops, &cs, &ss);
- ops->get_msr(ctxt->vcpu, MSR_STAR, &msr_data);
+ ops->get_msr(ctxt, MSR_STAR, &msr_data);
msr_data >>= 32;
cs_sel = (u16)(msr_data & 0xfffc);
ss_sel = (u16)(msr_data + 8);
- if (is_long_mode(ctxt->vcpu)) {
+ if (efer & EFER_LMA) {
cs.d = 0;
cs.l = 1;
}
- ops->set_cached_descriptor(&cs, 0, VCPU_SREG_CS, ctxt->vcpu);
- ops->set_segment_selector(cs_sel, VCPU_SREG_CS, ctxt->vcpu);
- ops->set_cached_descriptor(&ss, 0, VCPU_SREG_SS, ctxt->vcpu);
- ops->set_segment_selector(ss_sel, VCPU_SREG_SS, ctxt->vcpu);
+ ops->set_segment(ctxt, cs_sel, &cs, 0, VCPU_SREG_CS);
+ ops->set_segment(ctxt, ss_sel, &ss, 0, VCPU_SREG_SS);
c->regs[VCPU_REGS_RCX] = c->eip;
- if (is_long_mode(ctxt->vcpu)) {
+ if (efer & EFER_LMA) {
#ifdef CONFIG_X86_64
c->regs[VCPU_REGS_R11] = ctxt->eflags & ~EFLG_RF;
- ops->get_msr(ctxt->vcpu,
+ ops->get_msr(ctxt,
ctxt->mode == X86EMUL_MODE_PROT64 ?
MSR_LSTAR : MSR_CSTAR, &msr_data);
c->eip = msr_data;
- ops->get_msr(ctxt->vcpu, MSR_SYSCALL_MASK, &msr_data);
+ ops->get_msr(ctxt, MSR_SYSCALL_MASK, &msr_data);
ctxt->eflags &= ~(msr_data | EFLG_RF);
#endif
} else {
/* legacy mode */
- ops->get_msr(ctxt->vcpu, MSR_STAR, &msr_data);
+ ops->get_msr(ctxt, MSR_STAR, &msr_data);
c->eip = (u32)msr_data;
ctxt->eflags &= ~(EFLG_VM | EFLG_IF | EFLG_RF);
@@ -1646,7 +1959,9 @@ emulate_sysenter(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
struct desc_struct cs, ss;
u64 msr_data;
u16 cs_sel, ss_sel;
+ u64 efer = 0;
+ ctxt->ops->get_msr(ctxt, MSR_EFER, &efer);
/* inject #GP if in real mode */
if (ctxt->mode == X86EMUL_MODE_REAL)
return emulate_gp(ctxt, 0);
@@ -1659,7 +1974,7 @@ emulate_sysenter(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
setup_syscalls_segments(ctxt, ops, &cs, &ss);
- ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_CS, &msr_data);
+ ops->get_msr(ctxt, MSR_IA32_SYSENTER_CS, &msr_data);
switch (ctxt->mode) {
case X86EMUL_MODE_PROT32:
if ((msr_data & 0xfffc) == 0x0)
@@ -1676,21 +1991,18 @@ emulate_sysenter(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
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)) {
+ if (ctxt->mode == X86EMUL_MODE_PROT64 || (efer & EFER_LMA)) {
cs.d = 0;
cs.l = 1;
}
- ops->set_cached_descriptor(&cs, 0, VCPU_SREG_CS, ctxt->vcpu);
- ops->set_segment_selector(cs_sel, VCPU_SREG_CS, ctxt->vcpu);
- ops->set_cached_descriptor(&ss, 0, VCPU_SREG_SS, ctxt->vcpu);
- ops->set_segment_selector(ss_sel, VCPU_SREG_SS, ctxt->vcpu);
+ ops->set_segment(ctxt, cs_sel, &cs, 0, VCPU_SREG_CS);
+ ops->set_segment(ctxt, ss_sel, &ss, 0, VCPU_SREG_SS);
- ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_EIP, &msr_data);
+ ops->get_msr(ctxt, MSR_IA32_SYSENTER_EIP, &msr_data);
c->eip = msr_data;
- ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_ESP, &msr_data);
+ ops->get_msr(ctxt, MSR_IA32_SYSENTER_ESP, &msr_data);
c->regs[VCPU_REGS_RSP] = msr_data;
return X86EMUL_CONTINUE;
@@ -1719,7 +2031,7 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
cs.dpl = 3;
ss.dpl = 3;
- ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_CS, &msr_data);
+ ops->get_msr(ctxt, MSR_IA32_SYSENTER_CS, &msr_data);
switch (usermode) {
case X86EMUL_MODE_PROT32:
cs_sel = (u16)(msr_data + 16);
@@ -1739,10 +2051,8 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
cs_sel |= SELECTOR_RPL_MASK;
ss_sel |= SELECTOR_RPL_MASK;
- ops->set_cached_descriptor(&cs, 0, VCPU_SREG_CS, ctxt->vcpu);
- ops->set_segment_selector(cs_sel, VCPU_SREG_CS, ctxt->vcpu);
- ops->set_cached_descriptor(&ss, 0, VCPU_SREG_SS, ctxt->vcpu);
- ops->set_segment_selector(ss_sel, VCPU_SREG_SS, ctxt->vcpu);
+ ops->set_segment(ctxt, cs_sel, &cs, 0, VCPU_SREG_CS);
+ ops->set_segment(ctxt, ss_sel, &ss, 0, VCPU_SREG_SS);
c->eip = c->regs[VCPU_REGS_RDX];
c->regs[VCPU_REGS_RSP] = c->regs[VCPU_REGS_RCX];
@@ -1759,7 +2069,7 @@ static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt,
if (ctxt->mode == X86EMUL_MODE_VM86)
return true;
iopl = (ctxt->eflags & X86_EFLAGS_IOPL) >> IOPL_SHIFT;
- return ops->cpl(ctxt->vcpu) > iopl;
+ return ops->cpl(ctxt) > iopl;
}
static bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt,
@@ -1769,11 +2079,11 @@ static bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt,
struct desc_struct tr_seg;
u32 base3;
int r;
- u16 io_bitmap_ptr, perm, bit_idx = port & 0x7;
+ u16 tr, io_bitmap_ptr, perm, bit_idx = port & 0x7;
unsigned mask = (1 << len) - 1;
unsigned long base;
- ops->get_cached_descriptor(&tr_seg, &base3, VCPU_SREG_TR, ctxt->vcpu);
+ ops->get_segment(ctxt, &tr, &tr_seg, &base3, VCPU_SREG_TR);
if (!tr_seg.p)
return false;
if (desc_limit_scaled(&tr_seg) < 103)
@@ -1782,13 +2092,12 @@ static bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt,
#ifdef CONFIG_X86_64
base |= ((u64)base3) << 32;
#endif
- r = ops->read_std(base + 102, &io_bitmap_ptr, 2, ctxt->vcpu, NULL);
+ r = ops->read_std(ctxt, base + 102, &io_bitmap_ptr, 2, NULL);
if (r != X86EMUL_CONTINUE)
return false;
if (io_bitmap_ptr + port/8 > desc_limit_scaled(&tr_seg))
return false;
- r = ops->read_std(base + io_bitmap_ptr + port/8, &perm, 2, ctxt->vcpu,
- NULL);
+ r = ops->read_std(ctxt, base + io_bitmap_ptr + port/8, &perm, 2, NULL);
if (r != X86EMUL_CONTINUE)
return false;
if ((perm >> bit_idx) & mask)
@@ -1829,11 +2138,11 @@ static void save_state_to_tss16(struct x86_emulate_ctxt *ctxt,
tss->si = c->regs[VCPU_REGS_RSI];
tss->di = c->regs[VCPU_REGS_RDI];
- tss->es = ops->get_segment_selector(VCPU_SREG_ES, ctxt->vcpu);
- tss->cs = ops->get_segment_selector(VCPU_SREG_CS, ctxt->vcpu);
- tss->ss = ops->get_segment_selector(VCPU_SREG_SS, ctxt->vcpu);
- tss->ds = ops->get_segment_selector(VCPU_SREG_DS, ctxt->vcpu);
- tss->ldt = ops->get_segment_selector(VCPU_SREG_LDTR, ctxt->vcpu);
+ tss->es = get_segment_selector(ctxt, VCPU_SREG_ES);
+ tss->cs = get_segment_selector(ctxt, VCPU_SREG_CS);
+ tss->ss = get_segment_selector(ctxt, VCPU_SREG_SS);
+ tss->ds = get_segment_selector(ctxt, VCPU_SREG_DS);
+ tss->ldt = get_segment_selector(ctxt, VCPU_SREG_LDTR);
}
static int load_state_from_tss16(struct x86_emulate_ctxt *ctxt,
@@ -1858,11 +2167,11 @@ static int load_state_from_tss16(struct x86_emulate_ctxt *ctxt,
* SDM says that segment selectors are loaded before segment
* descriptors
*/
- ops->set_segment_selector(tss->ldt, VCPU_SREG_LDTR, ctxt->vcpu);
- ops->set_segment_selector(tss->es, VCPU_SREG_ES, ctxt->vcpu);
- ops->set_segment_selector(tss->cs, VCPU_SREG_CS, ctxt->vcpu);
- ops->set_segment_selector(tss->ss, VCPU_SREG_SS, ctxt->vcpu);
- ops->set_segment_selector(tss->ds, VCPU_SREG_DS, ctxt->vcpu);
+ set_segment_selector(ctxt, tss->ldt, VCPU_SREG_LDTR);
+ set_segment_selector(ctxt, tss->es, VCPU_SREG_ES);
+ set_segment_selector(ctxt, tss->cs, VCPU_SREG_CS);
+ set_segment_selector(ctxt, tss->ss, VCPU_SREG_SS);
+ set_segment_selector(ctxt, tss->ds, VCPU_SREG_DS);
/*
* Now load segment descriptors. If fault happenes at this stage
@@ -1896,7 +2205,7 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt,
int ret;
u32 new_tss_base = get_desc_base(new_desc);
- ret = ops->read_std(old_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu,
+ ret = ops->read_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg,
&ctxt->exception);
if (ret != X86EMUL_CONTINUE)
/* FIXME: need to provide precise fault address */
@@ -1904,13 +2213,13 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt,
save_state_to_tss16(ctxt, ops, &tss_seg);
- ret = ops->write_std(old_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu,
+ ret = ops->write_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg,
&ctxt->exception);
if (ret != X86EMUL_CONTINUE)
/* FIXME: need to provide precise fault address */
return ret;
- ret = ops->read_std(new_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu,
+ ret = ops->read_std(ctxt, new_tss_base, &tss_seg, sizeof tss_seg,
&ctxt->exception);
if (ret != X86EMUL_CONTINUE)
/* FIXME: need to provide precise fault address */
@@ -1919,10 +2228,10 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt,
if (old_tss_sel != 0xffff) {
tss_seg.prev_task_link = old_tss_sel;
- ret = ops->write_std(new_tss_base,
+ ret = ops->write_std(ctxt, new_tss_base,
&tss_seg.prev_task_link,
sizeof tss_seg.prev_task_link,
- ctxt->vcpu, &ctxt->exception);
+ &ctxt->exception);
if (ret != X86EMUL_CONTINUE)
/* FIXME: need to provide precise fault address */
return ret;
@@ -1937,7 +2246,7 @@ static void save_state_to_tss32(struct x86_emulate_ctxt *ctxt,
{
struct decode_cache *c = &ctxt->decode;
- tss->cr3 = ops->get_cr(3, ctxt->vcpu);
+ tss->cr3 = ops->get_cr(ctxt, 3);
tss->eip = c->eip;
tss->eflags = ctxt->eflags;
tss->eax = c->regs[VCPU_REGS_RAX];
@@ -1949,13 +2258,13 @@ static void save_state_to_tss32(struct x86_emulate_ctxt *ctxt,
tss->esi = c->regs[VCPU_REGS_RSI];
tss->edi = c->regs[VCPU_REGS_RDI];
- tss->es = ops->get_segment_selector(VCPU_SREG_ES, ctxt->vcpu);
- tss->cs = ops->get_segment_selector(VCPU_SREG_CS, ctxt->vcpu);
- tss->ss = ops->get_segment_selector(VCPU_SREG_SS, ctxt->vcpu);
- tss->ds = ops->get_segment_selector(VCPU_SREG_DS, ctxt->vcpu);
- tss->fs = ops->get_segment_selector(VCPU_SREG_FS, ctxt->vcpu);
- tss->gs = ops->get_segment_selector(VCPU_SREG_GS, ctxt->vcpu);
- tss->ldt_selector = ops->get_segment_selector(VCPU_SREG_LDTR, ctxt->vcpu);
+ tss->es = get_segment_selector(ctxt, VCPU_SREG_ES);
+ tss->cs = get_segment_selector(ctxt, VCPU_SREG_CS);
+ tss->ss = get_segment_selector(ctxt, VCPU_SREG_SS);
+ tss->ds = get_segment_selector(ctxt, VCPU_SREG_DS);
+ tss->fs = get_segment_selector(ctxt, VCPU_SREG_FS);
+ tss->gs = get_segment_selector(ctxt, VCPU_SREG_GS);
+ tss->ldt_selector = get_segment_selector(ctxt, VCPU_SREG_LDTR);
}
static int load_state_from_tss32(struct x86_emulate_ctxt *ctxt,
@@ -1965,7 +2274,7 @@ static int load_state_from_tss32(struct x86_emulate_ctxt *ctxt,
struct decode_cache *c = &ctxt->decode;
int ret;
- if (ops->set_cr(3, tss->cr3, ctxt->vcpu))
+ if (ops->set_cr(ctxt, 3, tss->cr3))
return emulate_gp(ctxt, 0);
c->eip = tss->eip;
ctxt->eflags = tss->eflags | 2;
@@ -1982,13 +2291,13 @@ static int load_state_from_tss32(struct x86_emulate_ctxt *ctxt,
* SDM says that segment selectors are loaded before segment
* descriptors
*/
- ops->set_segment_selector(tss->ldt_selector, VCPU_SREG_LDTR, ctxt->vcpu);
- ops->set_segment_selector(tss->es, VCPU_SREG_ES, ctxt->vcpu);
- ops->set_segment_selector(tss->cs, VCPU_SREG_CS, ctxt->vcpu);
- ops->set_segment_selector(tss->ss, VCPU_SREG_SS, ctxt->vcpu);
- ops->set_segment_selector(tss->ds, VCPU_SREG_DS, ctxt->vcpu);
- ops->set_segment_selector(tss->fs, VCPU_SREG_FS, ctxt->vcpu);
- ops->set_segment_selector(tss->gs, VCPU_SREG_GS, ctxt->vcpu);
+ set_segment_selector(ctxt, tss->ldt_selector, VCPU_SREG_LDTR);
+ set_segment_selector(ctxt, tss->es, VCPU_SREG_ES);
+ set_segment_selector(ctxt, tss->cs, VCPU_SREG_CS);
+ set_segment_selector(ctxt, tss->ss, VCPU_SREG_SS);
+ set_segment_selector(ctxt, tss->ds, VCPU_SREG_DS);
+ set_segment_selector(ctxt, tss->fs, VCPU_SREG_FS);
+ set_segment_selector(ctxt, tss->gs, VCPU_SREG_GS);
/*
* Now load segment descriptors. If fault happenes at this stage
@@ -2028,7 +2337,7 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt,
int ret;
u32 new_tss_base = get_desc_base(new_desc);
- ret = ops->read_std(old_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu,
+ ret = ops->read_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg,
&ctxt->exception);
if (ret != X86EMUL_CONTINUE)
/* FIXME: need to provide precise fault address */
@@ -2036,13 +2345,13 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt,
save_state_to_tss32(ctxt, ops, &tss_seg);
- ret = ops->write_std(old_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu,
+ ret = ops->write_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg,
&ctxt->exception);
if (ret != X86EMUL_CONTINUE)
/* FIXME: need to provide precise fault address */
return ret;
- ret = ops->read_std(new_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu,
+ ret = ops->read_std(ctxt, new_tss_base, &tss_seg, sizeof tss_seg,
&ctxt->exception);
if (ret != X86EMUL_CONTINUE)
/* FIXME: need to provide precise fault address */
@@ -2051,10 +2360,10 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt,
if (old_tss_sel != 0xffff) {
tss_seg.prev_task_link = old_tss_sel;
- ret = ops->write_std(new_tss_base,
+ ret = ops->write_std(ctxt, new_tss_base,
&tss_seg.prev_task_link,
sizeof tss_seg.prev_task_link,
- ctxt->vcpu, &ctxt->exception);
+ &ctxt->exception);
if (ret != X86EMUL_CONTINUE)
/* FIXME: need to provide precise fault address */
return ret;
@@ -2070,9 +2379,9 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
{
struct desc_struct curr_tss_desc, next_tss_desc;
int ret;
- u16 old_tss_sel = ops->get_segment_selector(VCPU_SREG_TR, ctxt->vcpu);
+ u16 old_tss_sel = get_segment_selector(ctxt, VCPU_SREG_TR);
ulong old_tss_base =
- ops->get_cached_segment_base(VCPU_SREG_TR, ctxt->vcpu);
+ ops->get_cached_segment_base(ctxt, VCPU_SREG_TR);
u32 desc_limit;
/* FIXME: old_tss_base == ~0 ? */
@@ -2088,7 +2397,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)
+ ops->cpl(ctxt) > next_tss_desc.dpl)
return emulate_gp(ctxt, 0);
}
@@ -2132,9 +2441,8 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
&next_tss_desc);
}
- ops->set_cr(0, ops->get_cr(0, ctxt->vcpu) | X86_CR0_TS, ctxt->vcpu);
- ops->set_cached_descriptor(&next_tss_desc, 0, VCPU_SREG_TR, ctxt->vcpu);
- ops->set_segment_selector(tss_selector, VCPU_SREG_TR, ctxt->vcpu);
+ ops->set_cr(ctxt, 0, ops->get_cr(ctxt, 0) | X86_CR0_TS);
+ ops->set_segment(ctxt, tss_selector, &next_tss_desc, 0, VCPU_SREG_TR);
if (has_error_code) {
struct decode_cache *c = &ctxt->decode;
@@ -2142,7 +2450,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, ops);
+ ret = em_push(ctxt);
}
return ret;
@@ -2162,13 +2470,10 @@ int emulator_task_switch(struct x86_emulate_ctxt *ctxt,
rc = emulator_do_task_switch(ctxt, ops, tss_selector, reason,
has_error_code, error_code);
- if (rc == X86EMUL_CONTINUE) {
- rc = writeback(ctxt, ops);
- if (rc == X86EMUL_CONTINUE)
- ctxt->eip = c->eip;
- }
+ if (rc == X86EMUL_CONTINUE)
+ ctxt->eip = c->eip;
- return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
+ return (rc == X86EMUL_UNHANDLEABLE) ? EMULATION_FAILED : EMULATION_OK;
}
static void string_addr_inc(struct x86_emulate_ctxt *ctxt, unsigned seg,
@@ -2182,12 +2487,6 @@ static void string_addr_inc(struct x86_emulate_ctxt *ctxt, unsigned seg,
op->addr.mem.seg = seg;
}
-static int em_push(struct x86_emulate_ctxt *ctxt)
-{
- emulate_push(ctxt, ctxt->ops);
- return X86EMUL_CONTINUE;
-}
-
static int em_das(struct x86_emulate_ctxt *ctxt)
{
struct decode_cache *c = &ctxt->decode;
@@ -2234,7 +2533,7 @@ static int em_call_far(struct x86_emulate_ctxt *ctxt)
ulong old_eip;
int rc;
- old_cs = ctxt->ops->get_segment_selector(VCPU_SREG_CS, ctxt->vcpu);
+ old_cs = get_segment_selector(ctxt, VCPU_SREG_CS);
old_eip = c->eip;
memcpy(&sel, c->src.valptr + c->op_bytes, 2);
@@ -2245,20 +2544,12 @@ static int em_call_far(struct x86_emulate_ctxt *ctxt)
memcpy(&c->eip, c->src.valptr, c->op_bytes);
c->src.val = old_cs;
- emulate_push(ctxt, ctxt->ops);
- rc = writeback(ctxt, ctxt->ops);
+ rc = em_push(ctxt);
if (rc != X86EMUL_CONTINUE)
return rc;
c->src.val = old_eip;
- emulate_push(ctxt, ctxt->ops);
- rc = writeback(ctxt, ctxt->ops);
- if (rc != X86EMUL_CONTINUE)
- return rc;
-
- c->dst.type = OP_NONE;
-
- return X86EMUL_CONTINUE;
+ return em_push(ctxt);
}
static int em_ret_near_imm(struct x86_emulate_ctxt *ctxt)
@@ -2269,13 +2560,79 @@ static int em_ret_near_imm(struct x86_emulate_ctxt *ctxt)
c->dst.type = OP_REG;
c->dst.addr.reg = &c->eip;
c->dst.bytes = c->op_bytes;
- rc = emulate_pop(ctxt, ctxt->ops, &c->dst.val, c->op_bytes);
+ rc = emulate_pop(ctxt, &c->dst.val, c->op_bytes);
if (rc != X86EMUL_CONTINUE)
return rc;
register_address_increment(c, &c->regs[VCPU_REGS_RSP], c->src.val);
return X86EMUL_CONTINUE;
}
+static int em_add(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+
+ emulate_2op_SrcV("add", c->src, c->dst, ctxt->eflags);
+ return X86EMUL_CONTINUE;
+}
+
+static int em_or(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+
+ emulate_2op_SrcV("or", c->src, c->dst, ctxt->eflags);
+ return X86EMUL_CONTINUE;
+}
+
+static int em_adc(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+
+ emulate_2op_SrcV("adc", c->src, c->dst, ctxt->eflags);
+ return X86EMUL_CONTINUE;
+}
+
+static int em_sbb(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+
+ emulate_2op_SrcV("sbb", c->src, c->dst, ctxt->eflags);
+ return X86EMUL_CONTINUE;
+}
+
+static int em_and(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+
+ emulate_2op_SrcV("and", c->src, c->dst, ctxt->eflags);
+ return X86EMUL_CONTINUE;
+}
+
+static int em_sub(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+
+ emulate_2op_SrcV("sub", c->src, c->dst, ctxt->eflags);
+ return X86EMUL_CONTINUE;
+}
+
+static int em_xor(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+
+ emulate_2op_SrcV("xor", c->src, c->dst, ctxt->eflags);
+ return X86EMUL_CONTINUE;
+}
+
+static int em_cmp(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+
+ emulate_2op_SrcV("cmp", c->src, c->dst, ctxt->eflags);
+ /* Disable writeback. */
+ c->dst.type = OP_NONE;
+ return X86EMUL_CONTINUE;
+}
+
static int em_imul(struct x86_emulate_ctxt *ctxt)
{
struct decode_cache *c = &ctxt->decode;
@@ -2306,13 +2663,10 @@ static int em_cwd(struct x86_emulate_ctxt *ctxt)
static int em_rdtsc(struct x86_emulate_ctxt *ctxt)
{
- unsigned cpl = ctxt->ops->cpl(ctxt->vcpu);
struct decode_cache *c = &ctxt->decode;
u64 tsc = 0;
- if (cpl > 0 && (ctxt->ops->get_cr(4, ctxt->vcpu) & X86_CR4_TSD))
- return emulate_gp(ctxt, 0);
- ctxt->ops->get_msr(ctxt->vcpu, MSR_IA32_TSC, &tsc);
+ ctxt->ops->get_msr(ctxt, MSR_IA32_TSC, &tsc);
c->regs[VCPU_REGS_RAX] = (u32)tsc;
c->regs[VCPU_REGS_RDX] = tsc >> 32;
return X86EMUL_CONTINUE;
@@ -2325,22 +2679,375 @@ static int em_mov(struct x86_emulate_ctxt *ctxt)
return X86EMUL_CONTINUE;
}
+static int em_movdqu(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+ memcpy(&c->dst.vec_val, &c->src.vec_val, c->op_bytes);
+ return X86EMUL_CONTINUE;
+}
+
+static int em_invlpg(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+ int rc;
+ ulong linear;
+
+ rc = linearize(ctxt, c->src.addr.mem, 1, false, &linear);
+ if (rc == X86EMUL_CONTINUE)
+ ctxt->ops->invlpg(ctxt, linear);
+ /* Disable writeback. */
+ c->dst.type = OP_NONE;
+ return X86EMUL_CONTINUE;
+}
+
+static int em_clts(struct x86_emulate_ctxt *ctxt)
+{
+ ulong cr0;
+
+ cr0 = ctxt->ops->get_cr(ctxt, 0);
+ cr0 &= ~X86_CR0_TS;
+ ctxt->ops->set_cr(ctxt, 0, cr0);
+ return X86EMUL_CONTINUE;
+}
+
+static int em_vmcall(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+ int rc;
+
+ if (c->modrm_mod != 3 || c->modrm_rm != 1)
+ return X86EMUL_UNHANDLEABLE;
+
+ rc = ctxt->ops->fix_hypercall(ctxt);
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+
+ /* Let the processor re-execute the fixed hypercall */
+ c->eip = ctxt->eip;
+ /* Disable writeback. */
+ c->dst.type = OP_NONE;
+ return X86EMUL_CONTINUE;
+}
+
+static int em_lgdt(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+ struct desc_ptr desc_ptr;
+ int rc;
+
+ rc = read_descriptor(ctxt, c->src.addr.mem,
+ &desc_ptr.size, &desc_ptr.address,
+ c->op_bytes);
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+ ctxt->ops->set_gdt(ctxt, &desc_ptr);
+ /* Disable writeback. */
+ c->dst.type = OP_NONE;
+ return X86EMUL_CONTINUE;
+}
+
+static int em_vmmcall(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+ int rc;
+
+ rc = ctxt->ops->fix_hypercall(ctxt);
+
+ /* Disable writeback. */
+ c->dst.type = OP_NONE;
+ return rc;
+}
+
+static int em_lidt(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+ struct desc_ptr desc_ptr;
+ int rc;
+
+ rc = read_descriptor(ctxt, c->src.addr.mem,
+ &desc_ptr.size, &desc_ptr.address,
+ c->op_bytes);
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+ ctxt->ops->set_idt(ctxt, &desc_ptr);
+ /* Disable writeback. */
+ c->dst.type = OP_NONE;
+ return X86EMUL_CONTINUE;
+}
+
+static int em_smsw(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+
+ c->dst.bytes = 2;
+ c->dst.val = ctxt->ops->get_cr(ctxt, 0);
+ return X86EMUL_CONTINUE;
+}
+
+static int em_lmsw(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+ ctxt->ops->set_cr(ctxt, 0, (ctxt->ops->get_cr(ctxt, 0) & ~0x0eul)
+ | (c->src.val & 0x0f));
+ c->dst.type = OP_NONE;
+ return X86EMUL_CONTINUE;
+}
+
+static bool valid_cr(int nr)
+{
+ switch (nr) {
+ case 0:
+ case 2 ... 4:
+ case 8:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int check_cr_read(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+
+ if (!valid_cr(c->modrm_reg))
+ return emulate_ud(ctxt);
+
+ return X86EMUL_CONTINUE;
+}
+
+static int check_cr_write(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+ u64 new_val = c->src.val64;
+ int cr = c->modrm_reg;
+ u64 efer = 0;
+
+ static u64 cr_reserved_bits[] = {
+ 0xffffffff00000000ULL,
+ 0, 0, 0, /* CR3 checked later */
+ CR4_RESERVED_BITS,
+ 0, 0, 0,
+ CR8_RESERVED_BITS,
+ };
+
+ if (!valid_cr(cr))
+ return emulate_ud(ctxt);
+
+ if (new_val & cr_reserved_bits[cr])
+ return emulate_gp(ctxt, 0);
+
+ switch (cr) {
+ case 0: {
+ u64 cr4;
+ if (((new_val & X86_CR0_PG) && !(new_val & X86_CR0_PE)) ||
+ ((new_val & X86_CR0_NW) && !(new_val & X86_CR0_CD)))
+ return emulate_gp(ctxt, 0);
+
+ cr4 = ctxt->ops->get_cr(ctxt, 4);
+ ctxt->ops->get_msr(ctxt, MSR_EFER, &efer);
+
+ if ((new_val & X86_CR0_PG) && (efer & EFER_LME) &&
+ !(cr4 & X86_CR4_PAE))
+ return emulate_gp(ctxt, 0);
+
+ break;
+ }
+ case 3: {
+ u64 rsvd = 0;
+
+ ctxt->ops->get_msr(ctxt, MSR_EFER, &efer);
+ if (efer & EFER_LMA)
+ rsvd = CR3_L_MODE_RESERVED_BITS;
+ else if (ctxt->ops->get_cr(ctxt, 4) & X86_CR4_PAE)
+ rsvd = CR3_PAE_RESERVED_BITS;
+ else if (ctxt->ops->get_cr(ctxt, 0) & X86_CR0_PG)
+ rsvd = CR3_NONPAE_RESERVED_BITS;
+
+ if (new_val & rsvd)
+ return emulate_gp(ctxt, 0);
+
+ break;
+ }
+ case 4: {
+ u64 cr4;
+
+ cr4 = ctxt->ops->get_cr(ctxt, 4);
+ ctxt->ops->get_msr(ctxt, MSR_EFER, &efer);
+
+ if ((efer & EFER_LMA) && !(new_val & X86_CR4_PAE))
+ return emulate_gp(ctxt, 0);
+
+ break;
+ }
+ }
+
+ return X86EMUL_CONTINUE;
+}
+
+static int check_dr7_gd(struct x86_emulate_ctxt *ctxt)
+{
+ unsigned long dr7;
+
+ ctxt->ops->get_dr(ctxt, 7, &dr7);
+
+ /* Check if DR7.Global_Enable is set */
+ return dr7 & (1 << 13);
+}
+
+static int check_dr_read(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+ int dr = c->modrm_reg;
+ u64 cr4;
+
+ if (dr > 7)
+ return emulate_ud(ctxt);
+
+ cr4 = ctxt->ops->get_cr(ctxt, 4);
+ if ((cr4 & X86_CR4_DE) && (dr == 4 || dr == 5))
+ return emulate_ud(ctxt);
+
+ if (check_dr7_gd(ctxt))
+ return emulate_db(ctxt);
+
+ return X86EMUL_CONTINUE;
+}
+
+static int check_dr_write(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+ u64 new_val = c->src.val64;
+ int dr = c->modrm_reg;
+
+ if ((dr == 6 || dr == 7) && (new_val & 0xffffffff00000000ULL))
+ return emulate_gp(ctxt, 0);
+
+ return check_dr_read(ctxt);
+}
+
+static int check_svme(struct x86_emulate_ctxt *ctxt)
+{
+ u64 efer;
+
+ ctxt->ops->get_msr(ctxt, MSR_EFER, &efer);
+
+ if (!(efer & EFER_SVME))
+ return emulate_ud(ctxt);
+
+ return X86EMUL_CONTINUE;
+}
+
+static int check_svme_pa(struct x86_emulate_ctxt *ctxt)
+{
+ u64 rax = ctxt->decode.regs[VCPU_REGS_RAX];
+
+ /* Valid physical address? */
+ if (rax & 0xffff000000000000ULL)
+ return emulate_gp(ctxt, 0);
+
+ return check_svme(ctxt);
+}
+
+static int check_rdtsc(struct x86_emulate_ctxt *ctxt)
+{
+ u64 cr4 = ctxt->ops->get_cr(ctxt, 4);
+
+ if (cr4 & X86_CR4_TSD && ctxt->ops->cpl(ctxt))
+ return emulate_ud(ctxt);
+
+ return X86EMUL_CONTINUE;
+}
+
+static int check_rdpmc(struct x86_emulate_ctxt *ctxt)
+{
+ u64 cr4 = ctxt->ops->get_cr(ctxt, 4);
+ u64 rcx = ctxt->decode.regs[VCPU_REGS_RCX];
+
+ if ((!(cr4 & X86_CR4_PCE) && ctxt->ops->cpl(ctxt)) ||
+ (rcx > 3))
+ return emulate_gp(ctxt, 0);
+
+ return X86EMUL_CONTINUE;
+}
+
+static int check_perm_in(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+
+ c->dst.bytes = min(c->dst.bytes, 4u);
+ if (!emulator_io_permited(ctxt, ctxt->ops, c->src.val, c->dst.bytes))
+ return emulate_gp(ctxt, 0);
+
+ return X86EMUL_CONTINUE;
+}
+
+static int check_perm_out(struct x86_emulate_ctxt *ctxt)
+{
+ struct decode_cache *c = &ctxt->decode;
+
+ c->src.bytes = min(c->src.bytes, 4u);
+ if (!emulator_io_permited(ctxt, ctxt->ops, c->dst.val, c->src.bytes))
+ return emulate_gp(ctxt, 0);
+
+ return X86EMUL_CONTINUE;
+}
+
#define D(_y) { .flags = (_y) }
+#define DI(_y, _i) { .flags = (_y), .intercept = x86_intercept_##_i }
+#define DIP(_y, _i, _p) { .flags = (_y), .intercept = x86_intercept_##_i, \
+ .check_perm = (_p) }
#define N D(0)
+#define EXT(_f, _e) { .flags = ((_f) | RMExt), .u.group = (_e) }
#define G(_f, _g) { .flags = ((_f) | Group), .u.group = (_g) }
-#define GD(_f, _g) { .flags = ((_f) | Group | GroupDual), .u.gdual = (_g) }
+#define GD(_f, _g) { .flags = ((_f) | GroupDual), .u.gdual = (_g) }
#define I(_f, _e) { .flags = (_f), .u.execute = (_e) }
+#define II(_f, _e, _i) \
+ { .flags = (_f), .u.execute = (_e), .intercept = x86_intercept_##_i }
+#define IIP(_f, _e, _i, _p) \
+ { .flags = (_f), .u.execute = (_e), .intercept = x86_intercept_##_i, \
+ .check_perm = (_p) }
+#define GP(_f, _g) { .flags = ((_f) | Prefix), .u.gprefix = (_g) }
#define D2bv(_f) D((_f) | ByteOp), D(_f)
+#define D2bvIP(_f, _i, _p) DIP((_f) | ByteOp, _i, _p), DIP(_f, _i, _p)
#define I2bv(_f, _e) I((_f) | ByteOp, _e), I(_f, _e)
-#define D6ALU(_f) D2bv((_f) | DstMem | SrcReg | ModRM), \
- D2bv(((_f) | DstReg | SrcMem | ModRM) & ~Lock), \
- D2bv(((_f) & ~Lock) | DstAcc | SrcImm)
+#define I6ALU(_f, _e) I2bv((_f) | DstMem | SrcReg | ModRM, _e), \
+ I2bv(((_f) | DstReg | SrcMem | ModRM) & ~Lock, _e), \
+ I2bv(((_f) & ~Lock) | DstAcc | SrcImm, _e)
+static struct opcode group7_rm1[] = {
+ DI(SrcNone | ModRM | Priv, monitor),
+ DI(SrcNone | ModRM | Priv, mwait),
+ N, N, N, N, N, N,
+};
+
+static struct opcode group7_rm3[] = {
+ DIP(SrcNone | ModRM | Prot | Priv, vmrun, check_svme_pa),
+ II(SrcNone | ModRM | Prot | VendorSpecific, em_vmmcall, vmmcall),
+ DIP(SrcNone | ModRM | Prot | Priv, vmload, check_svme_pa),
+ DIP(SrcNone | ModRM | Prot | Priv, vmsave, check_svme_pa),
+ DIP(SrcNone | ModRM | Prot | Priv, stgi, check_svme),
+ DIP(SrcNone | ModRM | Prot | Priv, clgi, check_svme),
+ DIP(SrcNone | ModRM | Prot | Priv, skinit, check_svme),
+ DIP(SrcNone | ModRM | Prot | Priv, invlpga, check_svme),
+};
+
+static struct opcode group7_rm7[] = {
+ N,
+ DIP(SrcNone | ModRM, rdtscp, check_rdtsc),
+ N, N, N, N, N, N,
+};
static struct opcode group1[] = {
- X7(D(Lock)), N
+ I(Lock, em_add),
+ I(Lock, em_or),
+ I(Lock, em_adc),
+ I(Lock, em_sbb),
+ I(Lock, em_and),
+ I(Lock, em_sub),
+ I(Lock, em_xor),
+ I(0, em_cmp),
};
static struct opcode group1A[] = {
@@ -2366,16 +3073,28 @@ static struct opcode group5[] = {
D(SrcMem | ModRM | Stack), N,
};
+static struct opcode group6[] = {
+ DI(ModRM | Prot, sldt),
+ DI(ModRM | Prot, str),
+ DI(ModRM | Prot | Priv, lldt),
+ DI(ModRM | Prot | Priv, ltr),
+ N, N, N, N,
+};
+
static struct group_dual group7 = { {
- N, N, D(ModRM | SrcMem | Priv), D(ModRM | SrcMem | Priv),
- D(SrcNone | ModRM | DstMem | Mov), N,
- D(SrcMem16 | ModRM | Mov | Priv),
- D(SrcMem | ModRM | ByteOp | Priv | NoAccess),
+ DI(ModRM | Mov | DstMem | Priv, sgdt),
+ DI(ModRM | Mov | DstMem | Priv, sidt),
+ II(ModRM | SrcMem | Priv, em_lgdt, lgdt),
+ II(ModRM | SrcMem | Priv, em_lidt, lidt),
+ II(SrcNone | ModRM | DstMem | Mov, em_smsw, smsw), N,
+ II(SrcMem16 | ModRM | Mov | Priv, em_lmsw, lmsw),
+ II(SrcMem | ModRM | ByteOp | Priv | NoAccess, em_invlpg, invlpg),
}, {
- D(SrcNone | ModRM | Priv | VendorSpecific), N,
- N, D(SrcNone | ModRM | Priv | VendorSpecific),
- D(SrcNone | ModRM | DstMem | Mov), N,
- D(SrcMem16 | ModRM | Mov | Priv), N,
+ I(SrcNone | ModRM | Priv | VendorSpecific, em_vmcall),
+ EXT(0, group7_rm1),
+ N, EXT(0, group7_rm3),
+ II(SrcNone | ModRM | DstMem | Mov, em_smsw, smsw), N,
+ II(SrcMem16 | ModRM | Mov | Priv, em_lmsw, lmsw), EXT(0, group7_rm7),
} };
static struct opcode group8[] = {
@@ -2394,35 +3113,40 @@ static struct opcode group11[] = {
I(DstMem | SrcImm | ModRM | Mov, em_mov), X7(D(Undefined)),
};
+static struct gprefix pfx_0f_6f_0f_7f = {
+ N, N, N, I(Sse, em_movdqu),
+};
+
static struct opcode opcode_table[256] = {
/* 0x00 - 0x07 */
- D6ALU(Lock),
+ I6ALU(Lock, em_add),
D(ImplicitOps | Stack | No64), D(ImplicitOps | Stack | No64),
/* 0x08 - 0x0F */
- D6ALU(Lock),
+ I6ALU(Lock, em_or),
D(ImplicitOps | Stack | No64), N,
/* 0x10 - 0x17 */
- D6ALU(Lock),
+ I6ALU(Lock, em_adc),
D(ImplicitOps | Stack | No64), D(ImplicitOps | Stack | No64),
/* 0x18 - 0x1F */
- D6ALU(Lock),
+ I6ALU(Lock, em_sbb),
D(ImplicitOps | Stack | No64), D(ImplicitOps | Stack | No64),
/* 0x20 - 0x27 */
- D6ALU(Lock), N, N,
+ I6ALU(Lock, em_and), N, N,
/* 0x28 - 0x2F */
- D6ALU(Lock), N, I(ByteOp | DstAcc | No64, em_das),
+ I6ALU(Lock, em_sub), N, I(ByteOp | DstAcc | No64, em_das),
/* 0x30 - 0x37 */
- D6ALU(Lock), N, N,
+ I6ALU(Lock, em_xor), N, N,
/* 0x38 - 0x3F */
- D6ALU(0), N, N,
+ I6ALU(0, em_cmp), N, N,
/* 0x40 - 0x4F */
X16(D(DstReg)),
/* 0x50 - 0x57 */
X8(I(SrcReg | Stack, em_push)),
/* 0x58 - 0x5F */
- X8(D(DstReg | Stack)),
+ X8(I(DstReg | Stack, em_pop)),
/* 0x60 - 0x67 */
- D(ImplicitOps | Stack | No64), D(ImplicitOps | Stack | No64),
+ I(ImplicitOps | Stack | No64, em_pusha),
+ I(ImplicitOps | Stack | No64, em_popa),
N, D(DstReg | SrcMem32 | ModRM | Mov) /* movsxd (x86/64) */ ,
N, N, N, N,
/* 0x68 - 0x6F */
@@ -2430,8 +3154,8 @@ static struct opcode opcode_table[256] = {
I(DstReg | SrcMem | ModRM | Src2Imm, em_imul_3op),
I(SrcImmByte | Mov | Stack, em_push),
I(DstReg | SrcMem | ModRM | Src2ImmByte, em_imul_3op),
- D2bv(DstDI | Mov | String), /* insb, insw/insd */
- D2bv(SrcSI | ImplicitOps | String), /* outsb, outsw/outsd */
+ D2bvIP(DstDI | Mov | String, ins, check_perm_in), /* insb, insw/insd */
+ D2bvIP(SrcSI | ImplicitOps | String, outs, check_perm_out), /* outsb, outsw/outsd */
/* 0x70 - 0x7F */
X16(D(SrcImmByte)),
/* 0x80 - 0x87 */
@@ -2446,21 +3170,22 @@ static struct opcode opcode_table[256] = {
D(DstMem | SrcNone | ModRM | Mov), D(ModRM | SrcMem | NoAccess | DstReg),
D(ImplicitOps | SrcMem16 | ModRM), G(0, group1A),
/* 0x90 - 0x97 */
- X8(D(SrcAcc | DstReg)),
+ DI(SrcAcc | DstReg, pause), X7(D(SrcAcc | DstReg)),
/* 0x98 - 0x9F */
D(DstAcc | SrcNone), I(ImplicitOps | SrcAcc, em_cwd),
I(SrcImmFAddr | No64, em_call_far), N,
- D(ImplicitOps | Stack), D(ImplicitOps | Stack), N, N,
+ II(ImplicitOps | Stack, em_pushf, pushf),
+ II(ImplicitOps | Stack, em_popf, popf), N, N,
/* 0xA0 - 0xA7 */
I2bv(DstAcc | SrcMem | Mov | MemAbs, em_mov),
I2bv(DstMem | SrcAcc | Mov | MemAbs, em_mov),
I2bv(SrcSI | DstDI | Mov | String, em_mov),
- D2bv(SrcSI | DstDI | String),
+ I2bv(SrcSI | DstDI | String, em_cmp),
/* 0xA8 - 0xAF */
D2bv(DstAcc | SrcImm),
I2bv(SrcAcc | DstDI | Mov | String, em_mov),
I2bv(SrcSI | DstAcc | Mov | String, em_mov),
- D2bv(SrcAcc | DstDI | String),
+ I2bv(SrcAcc | DstDI | String, em_cmp),
/* 0xB0 - 0xB7 */
X8(I(ByteOp | DstReg | SrcImm | Mov, em_mov)),
/* 0xB8 - 0xBF */
@@ -2473,7 +3198,8 @@ static struct opcode opcode_table[256] = {
G(ByteOp, group11), G(0, group11),
/* 0xC8 - 0xCF */
N, N, N, D(ImplicitOps | Stack),
- D(ImplicitOps), D(SrcImmByte), D(ImplicitOps | No64), D(ImplicitOps),
+ D(ImplicitOps), DI(SrcImmByte, intn),
+ D(ImplicitOps | No64), DI(ImplicitOps, iret),
/* 0xD0 - 0xD7 */
D2bv(DstMem | SrcOne | ModRM), D2bv(DstMem | ModRM),
N, N, N, N,
@@ -2481,14 +3207,17 @@ static struct opcode opcode_table[256] = {
N, N, N, N, N, N, N, N,
/* 0xE0 - 0xE7 */
X4(D(SrcImmByte)),
- D2bv(SrcImmUByte | DstAcc), D2bv(SrcAcc | DstImmUByte),
+ D2bvIP(SrcImmUByte | DstAcc, in, check_perm_in),
+ D2bvIP(SrcAcc | DstImmUByte, out, check_perm_out),
/* 0xE8 - 0xEF */
D(SrcImm | Stack), D(SrcImm | ImplicitOps),
D(SrcImmFAddr | No64), D(SrcImmByte | ImplicitOps),
- D2bv(SrcNone | DstAcc), D2bv(SrcAcc | ImplicitOps),
+ D2bvIP(SrcNone | DstAcc, in, check_perm_in),
+ D2bvIP(SrcAcc | ImplicitOps, out, check_perm_out),
/* 0xF0 - 0xF7 */
- N, N, N, N,
- D(ImplicitOps | Priv), D(ImplicitOps), G(ByteOp, group3), G(0, group3),
+ N, DI(ImplicitOps, icebp), N, N,
+ DI(ImplicitOps | Priv, hlt), D(ImplicitOps),
+ G(ByteOp, group3), G(0, group3),
/* 0xF8 - 0xFF */
D(ImplicitOps), D(ImplicitOps), D(ImplicitOps), D(ImplicitOps),
D(ImplicitOps), D(ImplicitOps), G(0, group4), G(0, group5),
@@ -2496,20 +3225,24 @@ static struct opcode opcode_table[256] = {
static struct opcode twobyte_table[256] = {
/* 0x00 - 0x0F */
- N, GD(0, &group7), N, N,
- N, D(ImplicitOps | VendorSpecific), D(ImplicitOps | Priv), N,
- D(ImplicitOps | Priv), D(ImplicitOps | Priv), N, N,
+ G(0, group6), GD(0, &group7), N, N,
+ N, D(ImplicitOps | VendorSpecific), DI(ImplicitOps | Priv, clts), N,
+ DI(ImplicitOps | Priv, invd), DI(ImplicitOps | Priv, wbinvd), N, N,
N, D(ImplicitOps | ModRM), N, N,
/* 0x10 - 0x1F */
N, N, N, N, N, N, N, N, D(ImplicitOps | ModRM), N, N, N, N, N, N, N,
/* 0x20 - 0x2F */
- D(ModRM | DstMem | Priv | Op3264), D(ModRM | DstMem | Priv | Op3264),
- D(ModRM | SrcMem | Priv | Op3264), D(ModRM | SrcMem | Priv | Op3264),
+ DIP(ModRM | DstMem | Priv | Op3264, cr_read, check_cr_read),
+ DIP(ModRM | DstMem | Priv | Op3264, dr_read, check_dr_read),
+ DIP(ModRM | SrcMem | Priv | Op3264, cr_write, check_cr_write),
+ DIP(ModRM | SrcMem | Priv | Op3264, dr_write, check_dr_write),
N, N, N, N,
N, N, N, N, N, N, N, N,
/* 0x30 - 0x3F */
- D(ImplicitOps | Priv), I(ImplicitOps, em_rdtsc),
- D(ImplicitOps | Priv), N,
+ DI(ImplicitOps | Priv, wrmsr),
+ IIP(ImplicitOps, em_rdtsc, rdtsc, check_rdtsc),
+ DI(ImplicitOps | Priv, rdmsr),
+ DIP(ImplicitOps | Priv, rdpmc, check_rdpmc),
D(ImplicitOps | VendorSpecific), D(ImplicitOps | Priv | VendorSpecific),
N, N,
N, N, N, N, N, N, N, N,
@@ -2518,21 +3251,27 @@ static struct opcode twobyte_table[256] = {
/* 0x50 - 0x5F */
N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
/* 0x60 - 0x6F */
- N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+ N, N, N, N,
+ N, N, N, N,
+ N, N, N, N,
+ N, N, N, GP(SrcMem | DstReg | ModRM | Mov, &pfx_0f_6f_0f_7f),
/* 0x70 - 0x7F */
- N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N,
+ N, N, N, N,
+ N, N, N, N,
+ N, N, N, N,
+ N, N, N, GP(SrcReg | DstMem | ModRM | Mov, &pfx_0f_6f_0f_7f),
/* 0x80 - 0x8F */
X16(D(SrcImm)),
/* 0x90 - 0x9F */
X16(D(ByteOp | DstMem | SrcNone | ModRM| Mov)),
/* 0xA0 - 0xA7 */
D(ImplicitOps | Stack), D(ImplicitOps | Stack),
- N, D(DstMem | SrcReg | ModRM | BitOp),
+ DI(ImplicitOps, cpuid), D(DstMem | SrcReg | ModRM | BitOp),
D(DstMem | SrcReg | Src2ImmByte | ModRM),
D(DstMem | SrcReg | Src2CL | ModRM), N, N,
/* 0xA8 - 0xAF */
D(ImplicitOps | Stack), D(ImplicitOps | Stack),
- N, D(DstMem | SrcReg | ModRM | BitOp | Lock),
+ DI(ImplicitOps, rsm), D(DstMem | SrcReg | ModRM | BitOp | Lock),
D(DstMem | SrcReg | Src2ImmByte | ModRM),
D(DstMem | SrcReg | Src2CL | ModRM),
D(ModRM), I(DstReg | SrcMem | ModRM, em_imul),
@@ -2564,10 +3303,13 @@ static struct opcode twobyte_table[256] = {
#undef G
#undef GD
#undef I
+#undef GP
+#undef EXT
#undef D2bv
+#undef D2bvIP
#undef I2bv
-#undef D6ALU
+#undef I6ALU
static unsigned imm_size(struct decode_cache *c)
{
@@ -2625,8 +3367,9 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len)
struct decode_cache *c = &ctxt->decode;
int rc = X86EMUL_CONTINUE;
int mode = ctxt->mode;
- int def_op_bytes, def_ad_bytes, dual, goffset;
- struct opcode opcode, *g_mod012, *g_mod3;
+ int def_op_bytes, def_ad_bytes, goffset, simd_prefix;
+ bool op_prefix = false;
+ struct opcode opcode;
struct operand memop = { .type = OP_NONE };
c->eip = ctxt->eip;
@@ -2634,7 +3377,6 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len)
c->fetch.end = c->fetch.start + insn_len;
if (insn_len > 0)
memcpy(c->fetch.data, insn, insn_len);
- ctxt->cs_base = seg_base(ctxt, ops, VCPU_SREG_CS);
switch (mode) {
case X86EMUL_MODE_REAL:
@@ -2662,6 +3404,7 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len)
for (;;) {
switch (c->b = insn_fetch(u8, 1, c->eip)) {
case 0x66: /* operand-size override */
+ op_prefix = true;
/* switch between 2/4 bytes */
c->op_bytes = def_op_bytes ^ 6;
break;
@@ -2692,10 +3435,8 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len)
c->lock_prefix = 1;
break;
case 0xf2: /* REPNE/REPNZ */
- c->rep_prefix = REPNE_PREFIX;
- break;
case 0xf3: /* REP/REPE/REPZ */
- c->rep_prefix = REPE_PREFIX;
+ c->rep_prefix = c->b;
break;
default:
goto done_prefixes;
@@ -2722,29 +3463,49 @@ done_prefixes:
}
c->d = opcode.flags;
- if (c->d & Group) {
- dual = c->d & GroupDual;
- c->modrm = insn_fetch(u8, 1, c->eip);
- --c->eip;
-
- if (c->d & GroupDual) {
- g_mod012 = opcode.u.gdual->mod012;
- g_mod3 = opcode.u.gdual->mod3;
- } else
- g_mod012 = g_mod3 = opcode.u.group;
-
- c->d &= ~(Group | GroupDual);
-
- goffset = (c->modrm >> 3) & 7;
+ while (c->d & GroupMask) {
+ switch (c->d & GroupMask) {
+ case Group:
+ c->modrm = insn_fetch(u8, 1, c->eip);
+ --c->eip;
+ goffset = (c->modrm >> 3) & 7;
+ opcode = opcode.u.group[goffset];
+ break;
+ case GroupDual:
+ c->modrm = insn_fetch(u8, 1, c->eip);
+ --c->eip;
+ goffset = (c->modrm >> 3) & 7;
+ if ((c->modrm >> 6) == 3)
+ opcode = opcode.u.gdual->mod3[goffset];
+ else
+ opcode = opcode.u.gdual->mod012[goffset];
+ break;
+ case RMExt:
+ goffset = c->modrm & 7;
+ opcode = opcode.u.group[goffset];
+ break;
+ case Prefix:
+ if (c->rep_prefix && op_prefix)
+ return X86EMUL_UNHANDLEABLE;
+ simd_prefix = op_prefix ? 0x66 : c->rep_prefix;
+ switch (simd_prefix) {
+ case 0x00: opcode = opcode.u.gprefix->pfx_no; break;
+ case 0x66: opcode = opcode.u.gprefix->pfx_66; break;
+ case 0xf2: opcode = opcode.u.gprefix->pfx_f2; break;
+ case 0xf3: opcode = opcode.u.gprefix->pfx_f3; break;
+ }
+ break;
+ default:
+ return X86EMUL_UNHANDLEABLE;
+ }
- if ((c->modrm >> 6) == 3)
- opcode = g_mod3[goffset];
- else
- opcode = g_mod012[goffset];
+ c->d &= ~GroupMask;
c->d |= opcode.flags;
}
c->execute = opcode.u.execute;
+ c->check_perm = opcode.check_perm;
+ c->intercept = opcode.intercept;
/* Unrecognised? */
if (c->d == 0 || (c->d & Undefined))
@@ -2763,6 +3524,9 @@ done_prefixes:
c->op_bytes = 4;
}
+ if (c->d & Sse)
+ c->op_bytes = 16;
+
/* ModRM and SIB bytes. */
if (c->d & ModRM) {
rc = decode_modrm(ctxt, ops, &memop);
@@ -2776,7 +3540,7 @@ done_prefixes:
if (!c->has_seg_override)
set_seg_override(c, VCPU_SREG_DS);
- memop.addr.mem.seg = seg_override(ctxt, ops, c);
+ memop.addr.mem.seg = seg_override(ctxt, c);
if (memop.type == OP_MEM && c->ad_bytes != 8)
memop.addr.mem.ea = (u32)memop.addr.mem.ea;
@@ -2792,7 +3556,7 @@ done_prefixes:
case SrcNone:
break;
case SrcReg:
- decode_register_operand(&c->src, c, 0);
+ decode_register_operand(ctxt, &c->src, c, 0);
break;
case SrcMem16:
memop.bytes = 2;
@@ -2836,7 +3600,7 @@ done_prefixes:
c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
c->src.addr.mem.ea =
register_address(c, c->regs[VCPU_REGS_RSI]);
- c->src.addr.mem.seg = seg_override(ctxt, ops, c),
+ c->src.addr.mem.seg = seg_override(ctxt, c);
c->src.val = 0;
break;
case SrcImmFAddr:
@@ -2883,7 +3647,7 @@ done_prefixes:
/* Decode and fetch the destination operand: register or memory. */
switch (c->d & DstMask) {
case DstReg:
- decode_register_operand(&c->dst, c,
+ decode_register_operand(ctxt, &c->dst, c,
c->twobyte && (c->b == 0xb6 || c->b == 0xb7));
break;
case DstImmUByte:
@@ -2926,7 +3690,7 @@ done_prefixes:
}
done:
- return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
+ return (rc == X86EMUL_UNHANDLEABLE) ? EMULATION_FAILED : EMULATION_OK;
}
static bool string_insn_completed(struct x86_emulate_ctxt *ctxt)
@@ -2979,12 +3743,51 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
goto done;
}
+ if ((c->d & Sse)
+ && ((ops->get_cr(ctxt, 0) & X86_CR0_EM)
+ || !(ops->get_cr(ctxt, 4) & X86_CR4_OSFXSR))) {
+ rc = emulate_ud(ctxt);
+ goto done;
+ }
+
+ if ((c->d & Sse) && (ops->get_cr(ctxt, 0) & X86_CR0_TS)) {
+ rc = emulate_nm(ctxt);
+ goto done;
+ }
+
+ if (unlikely(ctxt->guest_mode) && c->intercept) {
+ rc = emulator_check_intercept(ctxt, c->intercept,
+ X86_ICPT_PRE_EXCEPT);
+ if (rc != X86EMUL_CONTINUE)
+ goto done;
+ }
+
/* Privileged instruction can be executed only in CPL=0 */
- if ((c->d & Priv) && ops->cpl(ctxt->vcpu)) {
+ if ((c->d & Priv) && ops->cpl(ctxt)) {
rc = emulate_gp(ctxt, 0);
goto done;
}
+ /* Instruction can only be executed in protected mode */
+ if ((c->d & Prot) && !(ctxt->mode & X86EMUL_MODE_PROT)) {
+ rc = emulate_ud(ctxt);
+ goto done;
+ }
+
+ /* Do instruction specific permission checks */
+ if (c->check_perm) {
+ rc = c->check_perm(ctxt);
+ if (rc != X86EMUL_CONTINUE)
+ goto done;
+ }
+
+ if (unlikely(ctxt->guest_mode) && c->intercept) {
+ rc = emulator_check_intercept(ctxt, c->intercept,
+ X86_ICPT_POST_EXCEPT);
+ if (rc != X86EMUL_CONTINUE)
+ goto done;
+ }
+
if (c->rep_prefix && (c->d & String)) {
/* All REP prefixes have the same first termination condition */
if (address_mask(c, c->regs[VCPU_REGS_RCX]) == 0) {
@@ -2994,16 +3797,16 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
}
if ((c->src.type == OP_MEM) && !(c->d & NoAccess)) {
- rc = read_emulated(ctxt, ops, linear(ctxt, c->src.addr.mem),
- c->src.valptr, c->src.bytes);
+ rc = segmented_read(ctxt, c->src.addr.mem,
+ c->src.valptr, c->src.bytes);
if (rc != X86EMUL_CONTINUE)
goto done;
c->src.orig_val64 = c->src.val64;
}
if (c->src2.type == OP_MEM) {
- rc = read_emulated(ctxt, ops, linear(ctxt, c->src2.addr.mem),
- &c->src2.val, c->src2.bytes);
+ rc = segmented_read(ctxt, c->src2.addr.mem,
+ &c->src2.val, c->src2.bytes);
if (rc != X86EMUL_CONTINUE)
goto done;
}
@@ -3014,7 +3817,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
if ((c->dst.type == OP_MEM) && !(c->d & Mov)) {
/* optimisation - avoid slow emulated read if Mov */
- rc = read_emulated(ctxt, ops, linear(ctxt, c->dst.addr.mem),
+ rc = segmented_read(ctxt, c->dst.addr.mem,
&c->dst.val, c->dst.bytes);
if (rc != X86EMUL_CONTINUE)
goto done;
@@ -3023,6 +3826,13 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
special_insn:
+ if (unlikely(ctxt->guest_mode) && c->intercept) {
+ rc = emulator_check_intercept(ctxt, c->intercept,
+ X86_ICPT_POST_MEMACCESS);
+ if (rc != X86EMUL_CONTINUE)
+ goto done;
+ }
+
if (c->execute) {
rc = c->execute(ctxt);
if (rc != X86EMUL_CONTINUE)
@@ -3034,75 +3844,33 @@ special_insn:
goto twobyte_insn;
switch (c->b) {
- case 0x00 ... 0x05:
- add: /* add */
- emulate_2op_SrcV("add", c->src, c->dst, ctxt->eflags);
- break;
case 0x06: /* push es */
- emulate_push_sreg(ctxt, ops, VCPU_SREG_ES);
+ rc = emulate_push_sreg(ctxt, ops, VCPU_SREG_ES);
break;
case 0x07: /* pop es */
rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_ES);
break;
- case 0x08 ... 0x0d:
- or: /* or */
- emulate_2op_SrcV("or", c->src, c->dst, ctxt->eflags);
- break;
case 0x0e: /* push 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);
+ rc = emulate_push_sreg(ctxt, ops, VCPU_SREG_CS);
break;
case 0x16: /* push ss */
- emulate_push_sreg(ctxt, ops, VCPU_SREG_SS);
+ rc = emulate_push_sreg(ctxt, ops, VCPU_SREG_SS);
break;
case 0x17: /* pop ss */
rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_SS);
break;
- case 0x18 ... 0x1d:
- sbb: /* sbb */
- emulate_2op_SrcV("sbb", c->src, c->dst, ctxt->eflags);
- break;
case 0x1e: /* push ds */
- emulate_push_sreg(ctxt, ops, VCPU_SREG_DS);
+ rc = emulate_push_sreg(ctxt, ops, VCPU_SREG_DS);
break;
case 0x1f: /* pop ds */
rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_DS);
break;
- case 0x20 ... 0x25:
- and: /* and */
- emulate_2op_SrcV("and", c->src, c->dst, ctxt->eflags);
- break;
- case 0x28 ... 0x2d:
- sub: /* sub */
- emulate_2op_SrcV("sub", c->src, c->dst, ctxt->eflags);
- break;
- case 0x30 ... 0x35:
- xor: /* xor */
- emulate_2op_SrcV("xor", c->src, c->dst, ctxt->eflags);
- break;
- case 0x38 ... 0x3d:
- cmp: /* cmp */
- emulate_2op_SrcV("cmp", c->src, c->dst, ctxt->eflags);
- break;
case 0x40 ... 0x47: /* inc r16/r32 */
emulate_1op("inc", c->dst, ctxt->eflags);
break;
case 0x48 ... 0x4f: /* dec r16/r32 */
emulate_1op("dec", c->dst, ctxt->eflags);
break;
- case 0x58 ... 0x5f: /* pop reg */
- pop_instruction:
- rc = emulate_pop(ctxt, ops, &c->dst.val, c->op_bytes);
- break;
- case 0x60: /* pusha */
- rc = emulate_pusha(ctxt, ops);
- break;
- case 0x61: /* popa */
- rc = emulate_popa(ctxt, ops);
- break;
case 0x63: /* movsxd */
if (ctxt->mode != X86EMUL_MODE_PROT64)
goto cannot_emulate;
@@ -3121,26 +3889,6 @@ special_insn:
if (test_cc(c->b, ctxt->eflags))
jmp_rel(c, c->src.val);
break;
- case 0x80 ... 0x83: /* Grp1 */
- switch (c->modrm_reg) {
- case 0:
- goto add;
- case 1:
- goto or;
- case 2:
- goto adc;
- case 3:
- goto sbb;
- case 4:
- goto and;
- case 5:
- goto sub;
- case 6:
- goto xor;
- case 7:
- goto cmp;
- }
- break;
case 0x84 ... 0x85:
test:
emulate_2op_SrcV("test", c->src, c->dst, ctxt->eflags);
@@ -3162,7 +3910,7 @@ special_insn:
rc = emulate_ud(ctxt);
goto done;
}
- c->dst.val = ops->get_segment_selector(c->modrm_reg, ctxt->vcpu);
+ c->dst.val = get_segment_selector(ctxt, c->modrm_reg);
break;
case 0x8d: /* lea r16/r32, m */
c->dst.val = c->src.addr.mem.ea;
@@ -3187,7 +3935,7 @@ special_insn:
break;
}
case 0x8f: /* pop (sole member of Grp1a) */
- rc = emulate_grp1a(ctxt, ops);
+ rc = em_grp1a(ctxt);
break;
case 0x90 ... 0x97: /* nop / xchg reg, rax */
if (c->dst.addr.reg == &c->regs[VCPU_REGS_RAX])
@@ -3200,31 +3948,17 @@ special_insn:
case 8: c->dst.val = (s32)c->dst.val; break;
}
break;
- case 0x9c: /* pushf */
- c->src.val = (unsigned long) ctxt->eflags;
- emulate_push(ctxt, ops);
- break;
- case 0x9d: /* popf */
- c->dst.type = OP_REG;
- c->dst.addr.reg = &ctxt->eflags;
- c->dst.bytes = c->op_bytes;
- rc = emulate_popf(ctxt, ops, &c->dst.val, c->op_bytes);
- break;
- case 0xa6 ... 0xa7: /* cmps */
- c->dst.type = OP_NONE; /* Disable writeback. */
- goto cmp;
case 0xa8 ... 0xa9: /* test ax, imm */
goto test;
- case 0xae ... 0xaf: /* scas */
- goto cmp;
case 0xc0 ... 0xc1:
- emulate_grp2(ctxt);
+ rc = em_grp2(ctxt);
break;
case 0xc3: /* ret */
c->dst.type = OP_REG;
c->dst.addr.reg = &c->eip;
c->dst.bytes = c->op_bytes;
- goto pop_instruction;
+ rc = em_pop(ctxt);
+ break;
case 0xc4: /* les */
rc = emulate_load_segment(ctxt, ops, VCPU_SREG_ES);
break;
@@ -3252,11 +3986,11 @@ special_insn:
rc = emulate_iret(ctxt, ops);
break;
case 0xd0 ... 0xd1: /* Grp2 */
- emulate_grp2(ctxt);
+ rc = em_grp2(ctxt);
break;
case 0xd2 ... 0xd3: /* Grp2 */
c->src.val = c->regs[VCPU_REGS_RCX];
- emulate_grp2(ctxt);
+ rc = em_grp2(ctxt);
break;
case 0xe0 ... 0xe2: /* loop/loopz/loopnz */
register_address_increment(c, &c->regs[VCPU_REGS_RCX], -1);
@@ -3278,23 +4012,14 @@ special_insn:
long int rel = c->src.val;
c->src.val = (unsigned long) c->eip;
jmp_rel(c, rel);
- emulate_push(ctxt, ops);
+ rc = em_push(ctxt);
break;
}
case 0xe9: /* jmp rel */
goto jmp;
- case 0xea: { /* jmp far */
- unsigned short sel;
- jump_far:
- memcpy(&sel, c->src.valptr + c->op_bytes, 2);
-
- if (load_segment_descriptor(ctxt, ops, sel, VCPU_SREG_CS))
- goto done;
-
- c->eip = 0;
- memcpy(&c->eip, c->src.valptr, c->op_bytes);
+ case 0xea: /* jmp far */
+ rc = em_jmp_far(ctxt);
break;
- }
case 0xeb:
jmp: /* jmp rel short */
jmp_rel(c, c->src.val);
@@ -3304,11 +4029,6 @@ special_insn:
case 0xed: /* in (e/r)ax,dx */
c->src.val = c->regs[VCPU_REGS_RDX];
do_io_in:
- c->dst.bytes = min(c->dst.bytes, 4u);
- if (!emulator_io_permited(ctxt, ops, c->src.val, c->dst.bytes)) {
- rc = 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 */
@@ -3317,25 +4037,19 @@ special_insn:
case 0xef: /* out dx,(e/r)ax */
c->dst.val = c->regs[VCPU_REGS_RDX];
do_io_out:
- c->src.bytes = min(c->src.bytes, 4u);
- if (!emulator_io_permited(ctxt, ops, c->dst.val,
- c->src.bytes)) {
- rc = emulate_gp(ctxt, 0);
- goto done;
- }
- ops->pio_out_emulated(c->src.bytes, c->dst.val,
- &c->src.val, 1, ctxt->vcpu);
+ ops->pio_out_emulated(ctxt, c->src.bytes, c->dst.val,
+ &c->src.val, 1);
c->dst.type = OP_NONE; /* Disable writeback. */
break;
case 0xf4: /* hlt */
- ctxt->vcpu->arch.halt_request = 1;
+ ctxt->ops->halt(ctxt);
break;
case 0xf5: /* cmc */
/* complement carry flag from eflags reg */
ctxt->eflags ^= EFLG_CF;
break;
case 0xf6 ... 0xf7: /* Grp3 */
- rc = emulate_grp3(ctxt, ops);
+ rc = em_grp3(ctxt);
break;
case 0xf8: /* clc */
ctxt->eflags &= ~EFLG_CF;
@@ -3366,13 +4080,11 @@ special_insn:
ctxt->eflags |= EFLG_DF;
break;
case 0xfe: /* Grp4 */
- grp45:
- rc = emulate_grp45(ctxt, ops);
+ rc = em_grp45(ctxt);
break;
case 0xff: /* Grp5 */
- if (c->modrm_reg == 5)
- goto jump_far;
- goto grp45;
+ rc = em_grp45(ctxt);
+ break;
default:
goto cannot_emulate;
}
@@ -3381,7 +4093,7 @@ special_insn:
goto done;
writeback:
- rc = writeback(ctxt, ops);
+ rc = writeback(ctxt);
if (rc != X86EMUL_CONTINUE)
goto done;
@@ -3392,7 +4104,7 @@ writeback:
c->dst.type = saved_dst_type;
if ((c->d & SrcMask) == SrcSI)
- string_addr_inc(ctxt, seg_override(ctxt, ops, c),
+ string_addr_inc(ctxt, seg_override(ctxt, c),
VCPU_REGS_RSI, &c->src);
if ((c->d & DstMask) == DstDI)
@@ -3427,115 +4139,34 @@ writeback:
done:
if (rc == X86EMUL_PROPAGATE_FAULT)
ctxt->have_exception = true;
+ if (rc == X86EMUL_INTERCEPTED)
+ return EMULATION_INTERCEPTED;
+
return (rc == X86EMUL_UNHANDLEABLE) ? EMULATION_FAILED : EMULATION_OK;
twobyte_insn:
switch (c->b) {
- case 0x01: /* lgdt, lidt, lmsw */
- switch (c->modrm_reg) {
- u16 size;
- unsigned long address;
-
- case 0: /* vmcall */
- if (c->modrm_mod != 3 || c->modrm_rm != 1)
- goto cannot_emulate;
-
- rc = kvm_fix_hypercall(ctxt->vcpu);
- if (rc != X86EMUL_CONTINUE)
- goto done;
-
- /* Let the processor re-execute the fixed hypercall */
- c->eip = ctxt->eip;
- /* Disable writeback. */
- c->dst.type = OP_NONE;
- break;
- case 2: /* lgdt */
- rc = read_descriptor(ctxt, ops, c->src.addr.mem,
- &size, &address, c->op_bytes);
- if (rc != X86EMUL_CONTINUE)
- goto done;
- realmode_lgdt(ctxt->vcpu, size, address);
- /* Disable writeback. */
- c->dst.type = OP_NONE;
- break;
- case 3: /* lidt/vmmcall */
- if (c->modrm_mod == 3) {
- switch (c->modrm_rm) {
- case 1:
- rc = kvm_fix_hypercall(ctxt->vcpu);
- break;
- default:
- goto cannot_emulate;
- }
- } else {
- rc = read_descriptor(ctxt, ops, c->src.addr.mem,
- &size, &address,
- c->op_bytes);
- if (rc != X86EMUL_CONTINUE)
- goto done;
- realmode_lidt(ctxt->vcpu, size, address);
- }
- /* Disable writeback. */
- c->dst.type = OP_NONE;
- break;
- case 4: /* smsw */
- c->dst.bytes = 2;
- c->dst.val = ops->get_cr(0, ctxt->vcpu);
- break;
- case 6: /* lmsw */
- ops->set_cr(0, (ops->get_cr(0, ctxt->vcpu) & ~0x0eul) |
- (c->src.val & 0x0f), ctxt->vcpu);
- c->dst.type = OP_NONE;
- break;
- case 5: /* not defined */
- emulate_ud(ctxt);
- rc = X86EMUL_PROPAGATE_FAULT;
- goto done;
- case 7: /* invlpg*/
- emulate_invlpg(ctxt->vcpu,
- linear(ctxt, c->src.addr.mem));
- /* Disable writeback. */
- c->dst.type = OP_NONE;
- break;
- default:
- goto cannot_emulate;
- }
- break;
case 0x05: /* syscall */
rc = emulate_syscall(ctxt, ops);
break;
case 0x06:
- emulate_clts(ctxt->vcpu);
+ rc = em_clts(ctxt);
break;
case 0x09: /* wbinvd */
- kvm_emulate_wbinvd(ctxt->vcpu);
+ (ctxt->ops->wbinvd)(ctxt);
break;
case 0x08: /* invd */
case 0x0d: /* GrpP (prefetch) */
case 0x18: /* Grp16 (prefetch/nop) */
break;
case 0x20: /* mov cr, reg */
- switch (c->modrm_reg) {
- case 1:
- case 5 ... 7:
- case 9 ... 15:
- emulate_ud(ctxt);
- rc = X86EMUL_PROPAGATE_FAULT;
- goto done;
- }
- c->dst.val = ops->get_cr(c->modrm_reg, ctxt->vcpu);
+ c->dst.val = ops->get_cr(ctxt, c->modrm_reg);
break;
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)) {
- emulate_ud(ctxt);
- rc = X86EMUL_PROPAGATE_FAULT;
- goto done;
- }
- ops->get_dr(c->modrm_reg, &c->dst.val, ctxt->vcpu);
+ ops->get_dr(ctxt, c->modrm_reg, &c->dst.val);
break;
case 0x22: /* mov reg, cr */
- if (ops->set_cr(c->modrm_reg, c->src.val, ctxt->vcpu)) {
+ if (ops->set_cr(ctxt, c->modrm_reg, c->src.val)) {
emulate_gp(ctxt, 0);
rc = X86EMUL_PROPAGATE_FAULT;
goto done;
@@ -3543,16 +4174,9 @@ twobyte_insn:
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)) {
- emulate_ud(ctxt);
- rc = X86EMUL_PROPAGATE_FAULT;
- goto done;
- }
-
- if (ops->set_dr(c->modrm_reg, c->src.val &
+ if (ops->set_dr(ctxt, c->modrm_reg, c->src.val &
((ctxt->mode == X86EMUL_MODE_PROT64) ?
- ~0ULL : ~0U), ctxt->vcpu) < 0) {
+ ~0ULL : ~0U)) < 0) {
/* #UD condition is already handled by the code above */
emulate_gp(ctxt, 0);
rc = X86EMUL_PROPAGATE_FAULT;
@@ -3565,7 +4189,7 @@ twobyte_insn:
/* wrmsr */
msr_data = (u32)c->regs[VCPU_REGS_RAX]
| ((u64)c->regs[VCPU_REGS_RDX] << 32);
- if (ops->set_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], msr_data)) {
+ if (ops->set_msr(ctxt, c->regs[VCPU_REGS_RCX], msr_data)) {
emulate_gp(ctxt, 0);
rc = X86EMUL_PROPAGATE_FAULT;
goto done;
@@ -3574,7 +4198,7 @@ twobyte_insn:
break;
case 0x32:
/* rdmsr */
- if (ops->get_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], &msr_data)) {
+ if (ops->get_msr(ctxt, c->regs[VCPU_REGS_RCX], &msr_data)) {
emulate_gp(ctxt, 0);
rc = X86EMUL_PROPAGATE_FAULT;
goto done;
@@ -3603,7 +4227,7 @@ twobyte_insn:
c->dst.val = test_cc(c->b, ctxt->eflags);
break;
case 0xa0: /* push fs */
- emulate_push_sreg(ctxt, ops, VCPU_SREG_FS);
+ rc = emulate_push_sreg(ctxt, ops, VCPU_SREG_FS);
break;
case 0xa1: /* pop fs */
rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_FS);
@@ -3620,7 +4244,7 @@ twobyte_insn:
emulate_2op_cl("shld", c->src2, c->src, c->dst, ctxt->eflags);
break;
case 0xa8: /* push gs */
- emulate_push_sreg(ctxt, ops, VCPU_SREG_GS);
+ rc = emulate_push_sreg(ctxt, ops, VCPU_SREG_GS);
break;
case 0xa9: /* pop gs */
rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_GS);
@@ -3727,7 +4351,7 @@ twobyte_insn:
(u64) c->src.val;
break;
case 0xc7: /* Grp9 (cmpxchg8b) */
- rc = emulate_grp9(ctxt, ops);
+ rc = em_grp9(ctxt);
break;
default:
goto cannot_emulate;
@@ -3739,5 +4363,5 @@ twobyte_insn:
goto writeback;
cannot_emulate:
- return -1;
+ return EMULATION_FAILED;
}
diff --git a/arch/x86/kvm/i8254.h b/arch/x86/kvm/i8254.h
index 46d08ca0b48f..51a97426e791 100644
--- a/arch/x86/kvm/i8254.h
+++ b/arch/x86/kvm/i8254.h
@@ -33,7 +33,6 @@ struct kvm_kpit_state {
};
struct kvm_pit {
- unsigned long base_addresss;
struct kvm_io_device dev;
struct kvm_io_device speaker_dev;
struct kvm *kvm;
@@ -51,7 +50,6 @@ struct kvm_pit {
#define KVM_MAX_PIT_INTR_INTERVAL HZ / 100
#define KVM_PIT_CHANNEL_MASK 0x3
-void kvm_inject_pit_timer_irqs(struct kvm_vcpu *vcpu);
void kvm_pit_load_count(struct kvm *kvm, int channel, u32 val, int hpet_legacy_start);
struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags);
void kvm_free_pit(struct kvm *kvm);
diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h
index ba910d149410..53e2d084bffb 100644
--- a/arch/x86/kvm/irq.h
+++ b/arch/x86/kvm/irq.h
@@ -75,7 +75,6 @@ struct kvm_pic *kvm_create_pic(struct kvm *kvm);
void kvm_destroy_pic(struct kvm *kvm);
int kvm_pic_read_irq(struct kvm *kvm);
void kvm_pic_update_irq(struct kvm_pic *s);
-void kvm_pic_clear_isr_ack(struct kvm *kvm);
static inline struct kvm_pic *pic_irqchip(struct kvm *kvm)
{
@@ -100,7 +99,6 @@ void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu);
void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu);
void __kvm_migrate_timers(struct kvm_vcpu *vcpu);
-int pit_has_pending_timer(struct kvm_vcpu *vcpu);
int apic_has_pending_timer(struct kvm_vcpu *vcpu);
#endif
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 22fae7593ee7..bd14bb4c8594 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -1206,7 +1206,7 @@ static void nonpaging_invlpg(struct kvm_vcpu *vcpu, gva_t gva)
static void nonpaging_update_pte(struct kvm_vcpu *vcpu,
struct kvm_mmu_page *sp, u64 *spte,
- const void *pte, unsigned long mmu_seq)
+ const void *pte)
{
WARN_ON(1);
}
@@ -3163,9 +3163,8 @@ static void mmu_pte_write_zap_pte(struct kvm_vcpu *vcpu,
}
static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu,
- struct kvm_mmu_page *sp,
- u64 *spte,
- const void *new, unsigned long mmu_seq)
+ struct kvm_mmu_page *sp, u64 *spte,
+ const void *new)
{
if (sp->role.level != PT_PAGE_TABLE_LEVEL) {
++vcpu->kvm->stat.mmu_pde_zapped;
@@ -3173,7 +3172,7 @@ static void mmu_pte_write_new_pte(struct kvm_vcpu *vcpu,
}
++vcpu->kvm->stat.mmu_pte_updated;
- vcpu->arch.mmu.update_pte(vcpu, sp, spte, new, mmu_seq);
+ vcpu->arch.mmu.update_pte(vcpu, sp, spte, new);
}
static bool need_remote_flush(u64 old, u64 new)
@@ -3229,7 +3228,6 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
struct kvm_mmu_page *sp;
struct hlist_node *node;
LIST_HEAD(invalid_list);
- unsigned long mmu_seq;
u64 entry, gentry, *spte;
unsigned pte_size, page_offset, misaligned, quadrant, offset;
int level, npte, invlpg_counter, r, flooded = 0;
@@ -3271,9 +3269,6 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
break;
}
- mmu_seq = vcpu->kvm->mmu_notifier_seq;
- smp_rmb();
-
spin_lock(&vcpu->kvm->mmu_lock);
if (atomic_read(&vcpu->kvm->arch.invlpg_counter) != invlpg_counter)
gentry = 0;
@@ -3345,8 +3340,7 @@ void kvm_mmu_pte_write(struct kvm_vcpu *vcpu, gpa_t gpa,
if (gentry &&
!((sp->role.word ^ vcpu->arch.mmu.base_role.word)
& mask.word))
- mmu_pte_write_new_pte(vcpu, sp, spte, &gentry,
- mmu_seq);
+ mmu_pte_write_new_pte(vcpu, sp, spte, &gentry);
if (!remote_flush && need_remote_flush(entry, *spte))
remote_flush = true;
++spte;
@@ -3551,10 +3545,11 @@ static int kvm_mmu_remove_some_alloc_mmu_pages(struct kvm *kvm,
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)
+static int mmu_shrink(struct shrinker *shrink, struct shrink_control *sc)
{
struct kvm *kvm;
struct kvm *kvm_freed = NULL;
+ int nr_to_scan = sc->nr_to_scan;
if (nr_to_scan == 0)
goto out;
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index c6397795d865..6c4dc010c4cb 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -78,15 +78,19 @@ static gfn_t gpte_to_gfn_lvl(pt_element_t gpte, int lvl)
return (gpte & PT_LVL_ADDR_MASK(lvl)) >> PAGE_SHIFT;
}
-static bool FNAME(cmpxchg_gpte)(struct kvm *kvm,
- gfn_t table_gfn, unsigned index,
- pt_element_t orig_pte, pt_element_t new_pte)
+static int FNAME(cmpxchg_gpte)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu,
+ pt_element_t __user *ptep_user, unsigned index,
+ pt_element_t orig_pte, pt_element_t new_pte)
{
+ int npages;
pt_element_t ret;
pt_element_t *table;
struct page *page;
- page = gfn_to_page(kvm, table_gfn);
+ npages = get_user_pages_fast((unsigned long)ptep_user, 1, 1, &page);
+ /* Check if the user is doing something meaningless. */
+ if (unlikely(npages != 1))
+ return -EFAULT;
table = kmap_atomic(page, KM_USER0);
ret = CMPXCHG(&table[index], orig_pte, new_pte);
@@ -117,6 +121,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
gva_t addr, u32 access)
{
pt_element_t pte;
+ pt_element_t __user *ptep_user;
gfn_t table_gfn;
unsigned index, pt_access, uninitialized_var(pte_access);
gpa_t pte_gpa;
@@ -152,6 +157,9 @@ walk:
pt_access = ACC_ALL;
for (;;) {
+ gfn_t real_gfn;
+ unsigned long host_addr;
+
index = PT_INDEX(addr, walker->level);
table_gfn = gpte_to_gfn(pte);
@@ -160,43 +168,64 @@ walk:
walker->table_gfn[walker->level - 1] = table_gfn;
walker->pte_gpa[walker->level - 1] = pte_gpa;
- if (kvm_read_guest_page_mmu(vcpu, mmu, table_gfn, &pte,
- offset, sizeof(pte),
- PFERR_USER_MASK|PFERR_WRITE_MASK)) {
+ real_gfn = mmu->translate_gpa(vcpu, gfn_to_gpa(table_gfn),
+ PFERR_USER_MASK|PFERR_WRITE_MASK);
+ if (unlikely(real_gfn == UNMAPPED_GVA)) {
+ present = false;
+ break;
+ }
+ real_gfn = gpa_to_gfn(real_gfn);
+
+ host_addr = gfn_to_hva(vcpu->kvm, real_gfn);
+ if (unlikely(kvm_is_error_hva(host_addr))) {
+ present = false;
+ break;
+ }
+
+ ptep_user = (pt_element_t __user *)((void *)host_addr + offset);
+ if (unlikely(__copy_from_user(&pte, ptep_user, sizeof(pte)))) {
present = false;
break;
}
trace_kvm_mmu_paging_element(pte, walker->level);
- if (!is_present_gpte(pte)) {
+ if (unlikely(!is_present_gpte(pte))) {
present = false;
break;
}
- if (is_rsvd_bits_set(&vcpu->arch.mmu, pte, walker->level)) {
+ if (unlikely(is_rsvd_bits_set(&vcpu->arch.mmu, pte,
+ walker->level))) {
rsvd_fault = true;
break;
}
- if (write_fault && !is_writable_pte(pte))
- if (user_fault || is_write_protection(vcpu))
- eperm = true;
+ if (unlikely(write_fault && !is_writable_pte(pte)
+ && (user_fault || is_write_protection(vcpu))))
+ eperm = true;
- if (user_fault && !(pte & PT_USER_MASK))
+ if (unlikely(user_fault && !(pte & PT_USER_MASK)))
eperm = true;
#if PTTYPE == 64
- if (fetch_fault && (pte & PT64_NX_MASK))
+ if (unlikely(fetch_fault && (pte & PT64_NX_MASK)))
eperm = true;
#endif
- if (!eperm && !rsvd_fault && !(pte & PT_ACCESSED_MASK)) {
+ if (!eperm && !rsvd_fault
+ && unlikely(!(pte & PT_ACCESSED_MASK))) {
+ int ret;
trace_kvm_mmu_set_accessed_bit(table_gfn, index,
sizeof(pte));
- if (FNAME(cmpxchg_gpte)(vcpu->kvm, table_gfn,
- index, pte, pte|PT_ACCESSED_MASK))
+ ret = FNAME(cmpxchg_gpte)(vcpu, mmu, ptep_user, index,
+ pte, pte|PT_ACCESSED_MASK);
+ if (unlikely(ret < 0)) {
+ present = false;
+ break;
+ } else if (ret)
goto walk;
+
mark_page_dirty(vcpu->kvm, table_gfn);
pte |= PT_ACCESSED_MASK;
}
@@ -241,17 +270,21 @@ walk:
--walker->level;
}
- if (!present || eperm || rsvd_fault)
+ if (unlikely(!present || eperm || rsvd_fault))
goto error;
- if (write_fault && !is_dirty_gpte(pte)) {
- bool ret;
+ if (write_fault && unlikely(!is_dirty_gpte(pte))) {
+ int ret;
trace_kvm_mmu_set_dirty_bit(table_gfn, index, sizeof(pte));
- ret = FNAME(cmpxchg_gpte)(vcpu->kvm, table_gfn, index, pte,
- pte|PT_DIRTY_MASK);
- if (ret)
+ ret = FNAME(cmpxchg_gpte)(vcpu, mmu, ptep_user, index,
+ pte, pte|PT_DIRTY_MASK);
+ if (unlikely(ret < 0)) {
+ present = false;
+ goto error;
+ } else if (ret)
goto walk;
+
mark_page_dirty(vcpu->kvm, table_gfn);
pte |= PT_DIRTY_MASK;
walker->ptes[walker->level - 1] = pte;
@@ -325,7 +358,7 @@ no_present:
}
static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
- u64 *spte, const void *pte, unsigned long mmu_seq)
+ u64 *spte, const void *pte)
{
pt_element_t gpte;
unsigned pte_access;
@@ -342,8 +375,6 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
kvm_release_pfn_clean(pfn);
return;
}
- if (mmu_notifier_retry(vcpu, mmu_seq))
- return;
/*
* we call mmu_set_spte() with host_writable = true because that
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 6bb15d583e47..506e4fe23adc 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -63,6 +63,10 @@ MODULE_LICENSE("GPL");
#define DEBUGCTL_RESERVED_BITS (~(0x3fULL))
+#define TSC_RATIO_RSVD 0xffffff0000000000ULL
+#define TSC_RATIO_MIN 0x0000000000000001ULL
+#define TSC_RATIO_MAX 0x000000ffffffffffULL
+
static bool erratum_383_found __read_mostly;
static const u32 host_save_user_msrs[] = {
@@ -93,14 +97,6 @@ struct nested_state {
/* A VMEXIT is required but not yet emulated */
bool exit_required;
- /*
- * If we vmexit during an instruction emulation we need this to restore
- * the l1 guest rip after the emulation
- */
- unsigned long vmexit_rip;
- unsigned long vmexit_rsp;
- unsigned long vmexit_rax;
-
/* cache for intercepts of the guest */
u32 intercept_cr;
u32 intercept_dr;
@@ -144,8 +140,13 @@ struct vcpu_svm {
unsigned int3_injected;
unsigned long int3_rip;
u32 apf_reason;
+
+ u64 tsc_ratio;
};
+static DEFINE_PER_CPU(u64, current_tsc_ratio);
+#define TSC_RATIO_DEFAULT 0x0100000000ULL
+
#define MSR_INVALID 0xffffffffU
static struct svm_direct_access_msrs {
@@ -190,6 +191,7 @@ static int nested_svm_intercept(struct vcpu_svm *svm);
static int nested_svm_vmexit(struct vcpu_svm *svm);
static int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr,
bool has_error_code, u32 error_code);
+static u64 __scale_tsc(u64 ratio, u64 tsc);
enum {
VMCB_INTERCEPTS, /* Intercept vectors, TSC offset,
@@ -376,7 +378,6 @@ struct svm_cpu_data {
};
static DEFINE_PER_CPU(struct svm_cpu_data *, svm_data);
-static uint32_t svm_features;
struct svm_init_data {
int cpu;
@@ -569,6 +570,10 @@ static int has_svm(void)
static void svm_hardware_disable(void *garbage)
{
+ /* Make sure we clean up behind us */
+ if (static_cpu_has(X86_FEATURE_TSCRATEMSR))
+ wrmsrl(MSR_AMD64_TSC_RATIO, TSC_RATIO_DEFAULT);
+
cpu_svm_disable();
}
@@ -610,6 +615,11 @@ static int svm_hardware_enable(void *garbage)
wrmsrl(MSR_VM_HSAVE_PA, page_to_pfn(sd->save_area) << PAGE_SHIFT);
+ if (static_cpu_has(X86_FEATURE_TSCRATEMSR)) {
+ wrmsrl(MSR_AMD64_TSC_RATIO, TSC_RATIO_DEFAULT);
+ __get_cpu_var(current_tsc_ratio) = TSC_RATIO_DEFAULT;
+ }
+
svm_init_erratum_383();
return 0;
@@ -791,6 +801,23 @@ static __init int svm_hardware_setup(void)
if (boot_cpu_has(X86_FEATURE_FXSR_OPT))
kvm_enable_efer_bits(EFER_FFXSR);
+ if (boot_cpu_has(X86_FEATURE_TSCRATEMSR)) {
+ u64 max;
+
+ kvm_has_tsc_control = true;
+
+ /*
+ * Make sure the user can only configure tsc_khz values that
+ * fit into a signed integer.
+ * A min value is not calculated needed because it will always
+ * be 1 on all machines and a value of 0 is used to disable
+ * tsc-scaling for the vcpu.
+ */
+ max = min(0x7fffffffULL, __scale_tsc(tsc_khz, TSC_RATIO_MAX));
+
+ kvm_max_guest_tsc_khz = max;
+ }
+
if (nested) {
printk(KERN_INFO "kvm: Nested Virtualization enabled\n");
kvm_enable_efer_bits(EFER_SVME | EFER_LMSLE);
@@ -802,8 +829,6 @@ static __init int svm_hardware_setup(void)
goto err;
}
- svm_features = cpuid_edx(SVM_CPUID_FUNC);
-
if (!boot_cpu_has(X86_FEATURE_NPT))
npt_enabled = false;
@@ -854,6 +879,64 @@ static void init_sys_seg(struct vmcb_seg *seg, uint32_t type)
seg->base = 0;
}
+static u64 __scale_tsc(u64 ratio, u64 tsc)
+{
+ u64 mult, frac, _tsc;
+
+ mult = ratio >> 32;
+ frac = ratio & ((1ULL << 32) - 1);
+
+ _tsc = tsc;
+ _tsc *= mult;
+ _tsc += (tsc >> 32) * frac;
+ _tsc += ((tsc & ((1ULL << 32) - 1)) * frac) >> 32;
+
+ return _tsc;
+}
+
+static u64 svm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ u64 _tsc = tsc;
+
+ if (svm->tsc_ratio != TSC_RATIO_DEFAULT)
+ _tsc = __scale_tsc(svm->tsc_ratio, tsc);
+
+ return _tsc;
+}
+
+static void svm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ u64 ratio;
+ u64 khz;
+
+ /* TSC scaling supported? */
+ if (!boot_cpu_has(X86_FEATURE_TSCRATEMSR))
+ return;
+
+ /* TSC-Scaling disabled or guest TSC same frequency as host TSC? */
+ if (user_tsc_khz == 0) {
+ vcpu->arch.virtual_tsc_khz = 0;
+ svm->tsc_ratio = TSC_RATIO_DEFAULT;
+ return;
+ }
+
+ khz = user_tsc_khz;
+
+ /* TSC scaling required - calculate ratio */
+ ratio = khz << 32;
+ do_div(ratio, tsc_khz);
+
+ if (ratio == 0 || ratio & TSC_RATIO_RSVD) {
+ WARN_ONCE(1, "Invalid TSC ratio - virtual-tsc-khz=%u\n",
+ user_tsc_khz);
+ return;
+ }
+ vcpu->arch.virtual_tsc_khz = user_tsc_khz;
+ svm->tsc_ratio = ratio;
+}
+
static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -880,6 +963,15 @@ static void svm_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment)
mark_dirty(svm->vmcb, VMCB_INTERCEPTS);
}
+static u64 svm_compute_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc)
+{
+ u64 tsc;
+
+ tsc = svm_scale_tsc(vcpu, native_read_tsc());
+
+ return target_tsc - tsc;
+}
+
static void init_vmcb(struct vcpu_svm *svm)
{
struct vmcb_control_area *control = &svm->vmcb->control;
@@ -975,7 +1067,7 @@ static void init_vmcb(struct vcpu_svm *svm)
svm_set_efer(&svm->vcpu, 0);
save->dr6 = 0xffff0ff0;
save->dr7 = 0x400;
- save->rflags = 2;
+ kvm_set_rflags(&svm->vcpu, 2);
save->rip = 0x0000fff0;
svm->vcpu.arch.regs[VCPU_REGS_RIP] = save->rip;
@@ -1048,6 +1140,8 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
goto out;
}
+ svm->tsc_ratio = TSC_RATIO_DEFAULT;
+
err = kvm_vcpu_init(&svm->vcpu, kvm, id);
if (err)
goto free_svm;
@@ -1141,6 +1235,12 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
rdmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
+
+ if (static_cpu_has(X86_FEATURE_TSCRATEMSR) &&
+ svm->tsc_ratio != __get_cpu_var(current_tsc_ratio)) {
+ __get_cpu_var(current_tsc_ratio) = svm->tsc_ratio;
+ wrmsrl(MSR_AMD64_TSC_RATIO, svm->tsc_ratio);
+ }
}
static void svm_vcpu_put(struct kvm_vcpu *vcpu)
@@ -1365,31 +1465,6 @@ static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
{
struct vcpu_svm *svm = to_svm(vcpu);
- if (is_guest_mode(vcpu)) {
- /*
- * We are here because we run in nested mode, the host kvm
- * intercepts cr0 writes but the l1 hypervisor does not.
- * But the L1 hypervisor may intercept selective cr0 writes.
- * This needs to be checked here.
- */
- unsigned long old, new;
-
- /* Remove bits that would trigger a real cr0 write intercept */
- old = vcpu->arch.cr0 & SVM_CR0_SELECTIVE_MASK;
- new = cr0 & SVM_CR0_SELECTIVE_MASK;
-
- if (old == new) {
- /* cr0 write with ts and mp unchanged */
- svm->vmcb->control.exit_code = SVM_EXIT_CR0_SEL_WRITE;
- if (nested_svm_exit_handled(svm) == NESTED_EXIT_DONE) {
- svm->nested.vmexit_rip = kvm_rip_read(vcpu);
- svm->nested.vmexit_rsp = kvm_register_read(vcpu, VCPU_REGS_RSP);
- svm->nested.vmexit_rax = kvm_register_read(vcpu, VCPU_REGS_RAX);
- return;
- }
- }
- }
-
#ifdef CONFIG_X86_64
if (vcpu->arch.efer & EFER_LME) {
if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) {
@@ -2127,7 +2202,7 @@ static int nested_svm_vmexit(struct vcpu_svm *svm)
nested_vmcb->save.cr3 = kvm_read_cr3(&svm->vcpu);
nested_vmcb->save.cr2 = vmcb->save.cr2;
nested_vmcb->save.cr4 = svm->vcpu.arch.cr4;
- nested_vmcb->save.rflags = vmcb->save.rflags;
+ nested_vmcb->save.rflags = kvm_get_rflags(&svm->vcpu);
nested_vmcb->save.rip = vmcb->save.rip;
nested_vmcb->save.rsp = vmcb->save.rsp;
nested_vmcb->save.rax = vmcb->save.rax;
@@ -2184,7 +2259,7 @@ static int nested_svm_vmexit(struct vcpu_svm *svm)
svm->vmcb->save.ds = hsave->save.ds;
svm->vmcb->save.gdtr = hsave->save.gdtr;
svm->vmcb->save.idtr = hsave->save.idtr;
- svm->vmcb->save.rflags = hsave->save.rflags;
+ kvm_set_rflags(&svm->vcpu, hsave->save.rflags);
svm_set_efer(&svm->vcpu, hsave->save.efer);
svm_set_cr0(&svm->vcpu, hsave->save.cr0 | X86_CR0_PE);
svm_set_cr4(&svm->vcpu, hsave->save.cr4);
@@ -2312,7 +2387,7 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
hsave->save.efer = svm->vcpu.arch.efer;
hsave->save.cr0 = kvm_read_cr0(&svm->vcpu);
hsave->save.cr4 = svm->vcpu.arch.cr4;
- hsave->save.rflags = vmcb->save.rflags;
+ hsave->save.rflags = kvm_get_rflags(&svm->vcpu);
hsave->save.rip = kvm_rip_read(&svm->vcpu);
hsave->save.rsp = vmcb->save.rsp;
hsave->save.rax = vmcb->save.rax;
@@ -2323,7 +2398,7 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
copy_vmcb_control_area(hsave, vmcb);
- if (svm->vmcb->save.rflags & X86_EFLAGS_IF)
+ if (kvm_get_rflags(&svm->vcpu) & X86_EFLAGS_IF)
svm->vcpu.arch.hflags |= HF_HIF_MASK;
else
svm->vcpu.arch.hflags &= ~HF_HIF_MASK;
@@ -2341,7 +2416,7 @@ static bool nested_svm_vmrun(struct vcpu_svm *svm)
svm->vmcb->save.ds = nested_vmcb->save.ds;
svm->vmcb->save.gdtr = nested_vmcb->save.gdtr;
svm->vmcb->save.idtr = nested_vmcb->save.idtr;
- svm->vmcb->save.rflags = nested_vmcb->save.rflags;
+ kvm_set_rflags(&svm->vcpu, nested_vmcb->save.rflags);
svm_set_efer(&svm->vcpu, nested_vmcb->save.efer);
svm_set_cr0(&svm->vcpu, nested_vmcb->save.cr0);
svm_set_cr4(&svm->vcpu, nested_vmcb->save.cr4);
@@ -2443,13 +2518,13 @@ static int vmload_interception(struct vcpu_svm *svm)
if (nested_svm_check_permissions(svm))
return 1;
- svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
- skip_emulated_instruction(&svm->vcpu);
-
nested_vmcb = nested_svm_map(svm, svm->vmcb->save.rax, &page);
if (!nested_vmcb)
return 1;
+ svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
+ skip_emulated_instruction(&svm->vcpu);
+
nested_svm_vmloadsave(nested_vmcb, svm->vmcb);
nested_svm_unmap(page);
@@ -2464,13 +2539,13 @@ static int vmsave_interception(struct vcpu_svm *svm)
if (nested_svm_check_permissions(svm))
return 1;
- svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
- skip_emulated_instruction(&svm->vcpu);
-
nested_vmcb = nested_svm_map(svm, svm->vmcb->save.rax, &page);
if (!nested_vmcb)
return 1;
+ svm->next_rip = kvm_rip_read(&svm->vcpu) + 3;
+ skip_emulated_instruction(&svm->vcpu);
+
nested_svm_vmloadsave(svm->vmcb, nested_vmcb);
nested_svm_unmap(page);
@@ -2676,6 +2751,29 @@ static int emulate_on_interception(struct vcpu_svm *svm)
return emulate_instruction(&svm->vcpu, 0) == EMULATE_DONE;
}
+bool check_selective_cr0_intercepted(struct vcpu_svm *svm, unsigned long val)
+{
+ unsigned long cr0 = svm->vcpu.arch.cr0;
+ bool ret = false;
+ u64 intercept;
+
+ intercept = svm->nested.intercept;
+
+ if (!is_guest_mode(&svm->vcpu) ||
+ (!(intercept & (1ULL << INTERCEPT_SELECTIVE_CR0))))
+ return false;
+
+ cr0 &= ~SVM_CR0_SELECTIVE_MASK;
+ val &= ~SVM_CR0_SELECTIVE_MASK;
+
+ if (cr0 ^ val) {
+ svm->vmcb->control.exit_code = SVM_EXIT_CR0_SEL_WRITE;
+ ret = (nested_svm_exit_handled(svm) == NESTED_EXIT_DONE);
+ }
+
+ return ret;
+}
+
#define CR_VALID (1ULL << 63)
static int cr_interception(struct vcpu_svm *svm)
@@ -2699,7 +2797,11 @@ static int cr_interception(struct vcpu_svm *svm)
val = kvm_register_read(&svm->vcpu, reg);
switch (cr) {
case 0:
- err = kvm_set_cr0(&svm->vcpu, val);
+ if (!check_selective_cr0_intercepted(svm, val))
+ err = kvm_set_cr0(&svm->vcpu, val);
+ else
+ return 1;
+
break;
case 3:
err = kvm_set_cr3(&svm->vcpu, val);
@@ -2744,23 +2846,6 @@ static int cr_interception(struct vcpu_svm *svm)
return 1;
}
-static int cr0_write_interception(struct vcpu_svm *svm)
-{
- struct kvm_vcpu *vcpu = &svm->vcpu;
- int r;
-
- r = cr_interception(svm);
-
- if (svm->nested.vmexit_rip) {
- kvm_register_write(vcpu, VCPU_REGS_RIP, svm->nested.vmexit_rip);
- kvm_register_write(vcpu, VCPU_REGS_RSP, svm->nested.vmexit_rsp);
- kvm_register_write(vcpu, VCPU_REGS_RAX, svm->nested.vmexit_rax);
- svm->nested.vmexit_rip = 0;
- }
-
- return r;
-}
-
static int dr_interception(struct vcpu_svm *svm)
{
int reg, dr;
@@ -2813,7 +2898,9 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
case MSR_IA32_TSC: {
struct vmcb *vmcb = get_host_vmcb(svm);
- *data = vmcb->control.tsc_offset + native_read_tsc();
+ *data = vmcb->control.tsc_offset +
+ svm_scale_tsc(vcpu, native_read_tsc());
+
break;
}
case MSR_STAR:
@@ -3048,7 +3135,7 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm) = {
[SVM_EXIT_READ_CR4] = cr_interception,
[SVM_EXIT_READ_CR8] = cr_interception,
[SVM_EXIT_CR0_SEL_WRITE] = emulate_on_interception,
- [SVM_EXIT_WRITE_CR0] = cr0_write_interception,
+ [SVM_EXIT_WRITE_CR0] = cr_interception,
[SVM_EXIT_WRITE_CR3] = cr_interception,
[SVM_EXIT_WRITE_CR4] = cr_interception,
[SVM_EXIT_WRITE_CR8] = cr8_write_interception,
@@ -3104,97 +3191,109 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm) = {
[SVM_EXIT_NPF] = pf_interception,
};
-void dump_vmcb(struct kvm_vcpu *vcpu)
+static 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 & 0xffff);
- pr_err("cr_write: %04x\n", control->intercept_cr >> 16);
- pr_err("dr_read: %04x\n", control->intercept_dr & 0xffff);
- pr_err("dr_write: %04x\n", control->intercept_dr >> 16);
- 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("%-20s%04x\n", "cr_read:", control->intercept_cr & 0xffff);
+ pr_err("%-20s%04x\n", "cr_write:", control->intercept_cr >> 16);
+ pr_err("%-20s%04x\n", "dr_read:", control->intercept_dr & 0xffff);
+ pr_err("%-20s%04x\n", "dr_write:", control->intercept_dr >> 16);
+ pr_err("%-20s%08x\n", "exceptions:", control->intercept_exceptions);
+ pr_err("%-20s%016llx\n", "intercepts:", control->intercept);
+ pr_err("%-20s%d\n", "pause filter count:", control->pause_filter_count);
+ pr_err("%-20s%016llx\n", "iopm_base_pa:", control->iopm_base_pa);
+ pr_err("%-20s%016llx\n", "msrpm_base_pa:", control->msrpm_base_pa);
+ pr_err("%-20s%016llx\n", "tsc_offset:", control->tsc_offset);
+ pr_err("%-20s%d\n", "asid:", control->asid);
+ pr_err("%-20s%d\n", "tlb_ctl:", control->tlb_ctl);
+ pr_err("%-20s%08x\n", "int_ctl:", control->int_ctl);
+ pr_err("%-20s%08x\n", "int_vector:", control->int_vector);
+ pr_err("%-20s%08x\n", "int_state:", control->int_state);
+ pr_err("%-20s%08x\n", "exit_code:", control->exit_code);
+ pr_err("%-20s%016llx\n", "exit_info1:", control->exit_info_1);
+ pr_err("%-20s%016llx\n", "exit_info2:", control->exit_info_2);
+ pr_err("%-20s%08x\n", "exit_int_info:", control->exit_int_info);
+ pr_err("%-20s%08x\n", "exit_int_info_err:", control->exit_int_info_err);
+ pr_err("%-20s%lld\n", "nested_ctl:", control->nested_ctl);
+ pr_err("%-20s%016llx\n", "nested_cr3:", control->nested_cr3);
+ pr_err("%-20s%08x\n", "event_inj:", control->event_inj);
+ pr_err("%-20s%08x\n", "event_inj_err:", control->event_inj_err);
+ pr_err("%-20s%lld\n", "lbr_ctl:", control->lbr_ctl);
+ pr_err("%-20s%016llx\n", "next_rip:", 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("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
+ "es:",
+ save->es.selector, save->es.attrib,
+ save->es.limit, save->es.base);
+ pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
+ "cs:",
+ save->cs.selector, save->cs.attrib,
+ save->cs.limit, save->cs.base);
+ pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
+ "ss:",
+ save->ss.selector, save->ss.attrib,
+ save->ss.limit, save->ss.base);
+ pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
+ "ds:",
+ save->ds.selector, save->ds.attrib,
+ save->ds.limit, save->ds.base);
+ pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
+ "fs:",
+ save->fs.selector, save->fs.attrib,
+ save->fs.limit, save->fs.base);
+ pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
+ "gs:",
+ save->gs.selector, save->gs.attrib,
+ save->gs.limit, save->gs.base);
+ pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
+ "gdtr:",
+ save->gdtr.selector, save->gdtr.attrib,
+ save->gdtr.limit, save->gdtr.base);
+ pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
+ "ldtr:",
+ save->ldtr.selector, save->ldtr.attrib,
+ save->ldtr.limit, save->ldtr.base);
+ pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
+ "idtr:",
+ save->idtr.selector, save->idtr.attrib,
+ save->idtr.limit, save->idtr.base);
+ pr_err("%-5s s: %04x a: %04x l: %08x b: %016llx\n",
+ "tr:",
+ 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);
-
+ pr_err("%-15s %016llx %-13s %016llx\n",
+ "cr0:", save->cr0, "cr2:", save->cr2);
+ pr_err("%-15s %016llx %-13s %016llx\n",
+ "cr3:", save->cr3, "cr4:", save->cr4);
+ pr_err("%-15s %016llx %-13s %016llx\n",
+ "dr6:", save->dr6, "dr7:", save->dr7);
+ pr_err("%-15s %016llx %-13s %016llx\n",
+ "rip:", save->rip, "rflags:", save->rflags);
+ pr_err("%-15s %016llx %-13s %016llx\n",
+ "rsp:", save->rsp, "rax:", save->rax);
+ pr_err("%-15s %016llx %-13s %016llx\n",
+ "star:", save->star, "lstar:", save->lstar);
+ pr_err("%-15s %016llx %-13s %016llx\n",
+ "cstar:", save->cstar, "sfmask:", save->sfmask);
+ pr_err("%-15s %016llx %-13s %016llx\n",
+ "kernel_gs_base:", save->kernel_gs_base,
+ "sysenter_cs:", save->sysenter_cs);
+ pr_err("%-15s %016llx %-13s %016llx\n",
+ "sysenter_esp:", save->sysenter_esp,
+ "sysenter_eip:", save->sysenter_eip);
+ pr_err("%-15s %016llx %-13s %016llx\n",
+ "gpat:", save->g_pat, "dbgctl:", save->dbgctl);
+ pr_err("%-15s %016llx %-13s %016llx\n",
+ "br_from:", save->br_from, "br_to:", save->br_to);
+ pr_err("%-15s %016llx %-13s %016llx\n",
+ "excp_from:", save->last_excp_from,
+ "excp_to:", save->last_excp_to);
}
static void svm_get_exit_info(struct kvm_vcpu *vcpu, u64 *info1, u64 *info2)
@@ -3384,7 +3483,7 @@ static int svm_interrupt_allowed(struct kvm_vcpu *vcpu)
(vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK))
return 0;
- ret = !!(vmcb->save.rflags & X86_EFLAGS_IF);
+ ret = !!(kvm_get_rflags(vcpu) & X86_EFLAGS_IF);
if (is_guest_mode(vcpu))
return ret && !(svm->vcpu.arch.hflags & HF_VINTR_MASK);
@@ -3871,6 +3970,186 @@ static void svm_fpu_deactivate(struct kvm_vcpu *vcpu)
update_cr0_intercept(svm);
}
+#define PRE_EX(exit) { .exit_code = (exit), \
+ .stage = X86_ICPT_PRE_EXCEPT, }
+#define POST_EX(exit) { .exit_code = (exit), \
+ .stage = X86_ICPT_POST_EXCEPT, }
+#define POST_MEM(exit) { .exit_code = (exit), \
+ .stage = X86_ICPT_POST_MEMACCESS, }
+
+static struct __x86_intercept {
+ u32 exit_code;
+ enum x86_intercept_stage stage;
+} x86_intercept_map[] = {
+ [x86_intercept_cr_read] = POST_EX(SVM_EXIT_READ_CR0),
+ [x86_intercept_cr_write] = POST_EX(SVM_EXIT_WRITE_CR0),
+ [x86_intercept_clts] = POST_EX(SVM_EXIT_WRITE_CR0),
+ [x86_intercept_lmsw] = POST_EX(SVM_EXIT_WRITE_CR0),
+ [x86_intercept_smsw] = POST_EX(SVM_EXIT_READ_CR0),
+ [x86_intercept_dr_read] = POST_EX(SVM_EXIT_READ_DR0),
+ [x86_intercept_dr_write] = POST_EX(SVM_EXIT_WRITE_DR0),
+ [x86_intercept_sldt] = POST_EX(SVM_EXIT_LDTR_READ),
+ [x86_intercept_str] = POST_EX(SVM_EXIT_TR_READ),
+ [x86_intercept_lldt] = POST_EX(SVM_EXIT_LDTR_WRITE),
+ [x86_intercept_ltr] = POST_EX(SVM_EXIT_TR_WRITE),
+ [x86_intercept_sgdt] = POST_EX(SVM_EXIT_GDTR_READ),
+ [x86_intercept_sidt] = POST_EX(SVM_EXIT_IDTR_READ),
+ [x86_intercept_lgdt] = POST_EX(SVM_EXIT_GDTR_WRITE),
+ [x86_intercept_lidt] = POST_EX(SVM_EXIT_IDTR_WRITE),
+ [x86_intercept_vmrun] = POST_EX(SVM_EXIT_VMRUN),
+ [x86_intercept_vmmcall] = POST_EX(SVM_EXIT_VMMCALL),
+ [x86_intercept_vmload] = POST_EX(SVM_EXIT_VMLOAD),
+ [x86_intercept_vmsave] = POST_EX(SVM_EXIT_VMSAVE),
+ [x86_intercept_stgi] = POST_EX(SVM_EXIT_STGI),
+ [x86_intercept_clgi] = POST_EX(SVM_EXIT_CLGI),
+ [x86_intercept_skinit] = POST_EX(SVM_EXIT_SKINIT),
+ [x86_intercept_invlpga] = POST_EX(SVM_EXIT_INVLPGA),
+ [x86_intercept_rdtscp] = POST_EX(SVM_EXIT_RDTSCP),
+ [x86_intercept_monitor] = POST_MEM(SVM_EXIT_MONITOR),
+ [x86_intercept_mwait] = POST_EX(SVM_EXIT_MWAIT),
+ [x86_intercept_invlpg] = POST_EX(SVM_EXIT_INVLPG),
+ [x86_intercept_invd] = POST_EX(SVM_EXIT_INVD),
+ [x86_intercept_wbinvd] = POST_EX(SVM_EXIT_WBINVD),
+ [x86_intercept_wrmsr] = POST_EX(SVM_EXIT_MSR),
+ [x86_intercept_rdtsc] = POST_EX(SVM_EXIT_RDTSC),
+ [x86_intercept_rdmsr] = POST_EX(SVM_EXIT_MSR),
+ [x86_intercept_rdpmc] = POST_EX(SVM_EXIT_RDPMC),
+ [x86_intercept_cpuid] = PRE_EX(SVM_EXIT_CPUID),
+ [x86_intercept_rsm] = PRE_EX(SVM_EXIT_RSM),
+ [x86_intercept_pause] = PRE_EX(SVM_EXIT_PAUSE),
+ [x86_intercept_pushf] = PRE_EX(SVM_EXIT_PUSHF),
+ [x86_intercept_popf] = PRE_EX(SVM_EXIT_POPF),
+ [x86_intercept_intn] = PRE_EX(SVM_EXIT_SWINT),
+ [x86_intercept_iret] = PRE_EX(SVM_EXIT_IRET),
+ [x86_intercept_icebp] = PRE_EX(SVM_EXIT_ICEBP),
+ [x86_intercept_hlt] = POST_EX(SVM_EXIT_HLT),
+ [x86_intercept_in] = POST_EX(SVM_EXIT_IOIO),
+ [x86_intercept_ins] = POST_EX(SVM_EXIT_IOIO),
+ [x86_intercept_out] = POST_EX(SVM_EXIT_IOIO),
+ [x86_intercept_outs] = POST_EX(SVM_EXIT_IOIO),
+};
+
+#undef PRE_EX
+#undef POST_EX
+#undef POST_MEM
+
+static int svm_check_intercept(struct kvm_vcpu *vcpu,
+ struct x86_instruction_info *info,
+ enum x86_intercept_stage stage)
+{
+ struct vcpu_svm *svm = to_svm(vcpu);
+ int vmexit, ret = X86EMUL_CONTINUE;
+ struct __x86_intercept icpt_info;
+ struct vmcb *vmcb = svm->vmcb;
+
+ if (info->intercept >= ARRAY_SIZE(x86_intercept_map))
+ goto out;
+
+ icpt_info = x86_intercept_map[info->intercept];
+
+ if (stage != icpt_info.stage)
+ goto out;
+
+ switch (icpt_info.exit_code) {
+ case SVM_EXIT_READ_CR0:
+ if (info->intercept == x86_intercept_cr_read)
+ icpt_info.exit_code += info->modrm_reg;
+ break;
+ case SVM_EXIT_WRITE_CR0: {
+ unsigned long cr0, val;
+ u64 intercept;
+
+ if (info->intercept == x86_intercept_cr_write)
+ icpt_info.exit_code += info->modrm_reg;
+
+ if (icpt_info.exit_code != SVM_EXIT_WRITE_CR0)
+ break;
+
+ intercept = svm->nested.intercept;
+
+ if (!(intercept & (1ULL << INTERCEPT_SELECTIVE_CR0)))
+ break;
+
+ cr0 = vcpu->arch.cr0 & ~SVM_CR0_SELECTIVE_MASK;
+ val = info->src_val & ~SVM_CR0_SELECTIVE_MASK;
+
+ if (info->intercept == x86_intercept_lmsw) {
+ cr0 &= 0xfUL;
+ val &= 0xfUL;
+ /* lmsw can't clear PE - catch this here */
+ if (cr0 & X86_CR0_PE)
+ val |= X86_CR0_PE;
+ }
+
+ if (cr0 ^ val)
+ icpt_info.exit_code = SVM_EXIT_CR0_SEL_WRITE;
+
+ break;
+ }
+ case SVM_EXIT_READ_DR0:
+ case SVM_EXIT_WRITE_DR0:
+ icpt_info.exit_code += info->modrm_reg;
+ break;
+ case SVM_EXIT_MSR:
+ if (info->intercept == x86_intercept_wrmsr)
+ vmcb->control.exit_info_1 = 1;
+ else
+ vmcb->control.exit_info_1 = 0;
+ break;
+ case SVM_EXIT_PAUSE:
+ /*
+ * We get this for NOP only, but pause
+ * is rep not, check this here
+ */
+ if (info->rep_prefix != REPE_PREFIX)
+ goto out;
+ case SVM_EXIT_IOIO: {
+ u64 exit_info;
+ u32 bytes;
+
+ exit_info = (vcpu->arch.regs[VCPU_REGS_RDX] & 0xffff) << 16;
+
+ if (info->intercept == x86_intercept_in ||
+ info->intercept == x86_intercept_ins) {
+ exit_info |= SVM_IOIO_TYPE_MASK;
+ bytes = info->src_bytes;
+ } else {
+ bytes = info->dst_bytes;
+ }
+
+ if (info->intercept == x86_intercept_outs ||
+ info->intercept == x86_intercept_ins)
+ exit_info |= SVM_IOIO_STR_MASK;
+
+ if (info->rep_prefix)
+ exit_info |= SVM_IOIO_REP_MASK;
+
+ bytes = min(bytes, 4u);
+
+ exit_info |= bytes << SVM_IOIO_SIZE_SHIFT;
+
+ exit_info |= (u32)info->ad_bytes << (SVM_IOIO_ASIZE_SHIFT - 1);
+
+ vmcb->control.exit_info_1 = exit_info;
+ vmcb->control.exit_info_2 = info->next_rip;
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ vmcb->control.next_rip = info->next_rip;
+ vmcb->control.exit_code = icpt_info.exit_code;
+ vmexit = nested_svm_exit_handled(svm);
+
+ ret = (vmexit == NESTED_EXIT_DONE) ? X86EMUL_INTERCEPTED
+ : X86EMUL_CONTINUE;
+
+out:
+ return ret;
+}
+
static struct kvm_x86_ops svm_x86_ops = {
.cpu_has_kvm_support = has_svm,
.disabled_by_bios = is_disabled,
@@ -3952,10 +4231,14 @@ static struct kvm_x86_ops svm_x86_ops = {
.has_wbinvd_exit = svm_has_wbinvd_exit,
+ .set_tsc_khz = svm_set_tsc_khz,
.write_tsc_offset = svm_write_tsc_offset,
.adjust_tsc_offset = svm_adjust_tsc_offset,
+ .compute_tsc_offset = svm_compute_tsc_offset,
.set_tdp_cr3 = set_tdp_cr3,
+
+ .check_intercept = svm_check_intercept,
};
static int __init svm_init(void)
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 5b4cdcbd154c..4c3fa0f67469 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -128,8 +128,11 @@ struct vcpu_vmx {
unsigned long host_rsp;
int launched;
u8 fail;
+ u8 cpl;
+ bool nmi_known_unmasked;
u32 exit_intr_info;
u32 idt_vectoring_info;
+ ulong rflags;
struct shared_msr_entry *guest_msrs;
int nmsrs;
int save_nmsrs;
@@ -159,6 +162,10 @@ struct vcpu_vmx {
u32 ar;
} tr, es, ds, fs, gs;
} rmode;
+ struct {
+ u32 bitmask; /* 4 bits per segment (1 bit per field) */
+ struct kvm_save_segment seg[8];
+ } segment_cache;
int vpid;
bool emulation_required;
@@ -171,6 +178,15 @@ struct vcpu_vmx {
bool rdtscp_enabled;
};
+enum segment_cache_field {
+ SEG_FIELD_SEL = 0,
+ SEG_FIELD_BASE = 1,
+ SEG_FIELD_LIMIT = 2,
+ SEG_FIELD_AR = 3,
+
+ SEG_FIELD_NR = 4
+};
+
static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu)
{
return container_of(vcpu, struct vcpu_vmx, vcpu);
@@ -643,6 +659,62 @@ static void vmcs_set_bits(unsigned long field, u32 mask)
vmcs_writel(field, vmcs_readl(field) | mask);
}
+static void vmx_segment_cache_clear(struct vcpu_vmx *vmx)
+{
+ vmx->segment_cache.bitmask = 0;
+}
+
+static bool vmx_segment_cache_test_set(struct vcpu_vmx *vmx, unsigned seg,
+ unsigned field)
+{
+ bool ret;
+ u32 mask = 1 << (seg * SEG_FIELD_NR + field);
+
+ if (!(vmx->vcpu.arch.regs_avail & (1 << VCPU_EXREG_SEGMENTS))) {
+ vmx->vcpu.arch.regs_avail |= (1 << VCPU_EXREG_SEGMENTS);
+ vmx->segment_cache.bitmask = 0;
+ }
+ ret = vmx->segment_cache.bitmask & mask;
+ vmx->segment_cache.bitmask |= mask;
+ return ret;
+}
+
+static u16 vmx_read_guest_seg_selector(struct vcpu_vmx *vmx, unsigned seg)
+{
+ u16 *p = &vmx->segment_cache.seg[seg].selector;
+
+ if (!vmx_segment_cache_test_set(vmx, seg, SEG_FIELD_SEL))
+ *p = vmcs_read16(kvm_vmx_segment_fields[seg].selector);
+ return *p;
+}
+
+static ulong vmx_read_guest_seg_base(struct vcpu_vmx *vmx, unsigned seg)
+{
+ ulong *p = &vmx->segment_cache.seg[seg].base;
+
+ if (!vmx_segment_cache_test_set(vmx, seg, SEG_FIELD_BASE))
+ *p = vmcs_readl(kvm_vmx_segment_fields[seg].base);
+ return *p;
+}
+
+static u32 vmx_read_guest_seg_limit(struct vcpu_vmx *vmx, unsigned seg)
+{
+ u32 *p = &vmx->segment_cache.seg[seg].limit;
+
+ if (!vmx_segment_cache_test_set(vmx, seg, SEG_FIELD_LIMIT))
+ *p = vmcs_read32(kvm_vmx_segment_fields[seg].limit);
+ return *p;
+}
+
+static u32 vmx_read_guest_seg_ar(struct vcpu_vmx *vmx, unsigned seg)
+{
+ u32 *p = &vmx->segment_cache.seg[seg].ar;
+
+ if (!vmx_segment_cache_test_set(vmx, seg, SEG_FIELD_AR))
+ *p = vmcs_read32(kvm_vmx_segment_fields[seg].ar_bytes);
+ return *p;
+}
+
static void update_exception_bitmap(struct kvm_vcpu *vcpu)
{
u32 eb;
@@ -970,17 +1042,24 @@ static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu)
{
unsigned long rflags, save_rflags;
- rflags = vmcs_readl(GUEST_RFLAGS);
- if (to_vmx(vcpu)->rmode.vm86_active) {
- rflags &= RMODE_GUEST_OWNED_EFLAGS_BITS;
- save_rflags = to_vmx(vcpu)->rmode.save_rflags;
- rflags |= save_rflags & ~RMODE_GUEST_OWNED_EFLAGS_BITS;
+ if (!test_bit(VCPU_EXREG_RFLAGS, (ulong *)&vcpu->arch.regs_avail)) {
+ __set_bit(VCPU_EXREG_RFLAGS, (ulong *)&vcpu->arch.regs_avail);
+ rflags = vmcs_readl(GUEST_RFLAGS);
+ if (to_vmx(vcpu)->rmode.vm86_active) {
+ rflags &= RMODE_GUEST_OWNED_EFLAGS_BITS;
+ save_rflags = to_vmx(vcpu)->rmode.save_rflags;
+ rflags |= save_rflags & ~RMODE_GUEST_OWNED_EFLAGS_BITS;
+ }
+ to_vmx(vcpu)->rflags = rflags;
}
- return rflags;
+ return to_vmx(vcpu)->rflags;
}
static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
{
+ __set_bit(VCPU_EXREG_RFLAGS, (ulong *)&vcpu->arch.regs_avail);
+ __clear_bit(VCPU_EXREG_CPL, (ulong *)&vcpu->arch.regs_avail);
+ to_vmx(vcpu)->rflags = rflags;
if (to_vmx(vcpu)->rmode.vm86_active) {
to_vmx(vcpu)->rmode.save_rflags = rflags;
rflags |= X86_EFLAGS_IOPL | X86_EFLAGS_VM;
@@ -1053,7 +1132,10 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr,
}
if (vmx->rmode.vm86_active) {
- if (kvm_inject_realmode_interrupt(vcpu, nr) != EMULATE_DONE)
+ int inc_eip = 0;
+ if (kvm_exception_is_soft(nr))
+ inc_eip = vcpu->arch.event_exit_inst_len;
+ if (kvm_inject_realmode_interrupt(vcpu, nr, inc_eip) != EMULATE_DONE)
kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
return;
}
@@ -1151,6 +1233,16 @@ static u64 guest_read_tsc(void)
}
/*
+ * Empty call-back. Needs to be implemented when VMX enables the SET_TSC_KHZ
+ * ioctl. In this case the call-back should update internal vmx state to make
+ * the changes effective.
+ */
+static void vmx_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)
+{
+ /* Nothing to do here */
+}
+
+/*
* writes 'offset' into guest's timestamp counter offset register
*/
static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
@@ -1164,6 +1256,11 @@ static void vmx_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment)
vmcs_write64(TSC_OFFSET, offset + adjustment);
}
+static u64 vmx_compute_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc)
+{
+ return target_tsc - native_read_tsc();
+}
+
/*
* Reads an msr value (of 'msr_index') into 'pdata'.
* Returns 0 on success, non-0 otherwise.
@@ -1243,9 +1340,11 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
break;
#ifdef CONFIG_X86_64
case MSR_FS_BASE:
+ vmx_segment_cache_clear(vmx);
vmcs_writel(GUEST_FS_BASE, data);
break;
case MSR_GS_BASE:
+ vmx_segment_cache_clear(vmx);
vmcs_writel(GUEST_GS_BASE, data);
break;
case MSR_KERNEL_GS_BASE:
@@ -1689,6 +1788,8 @@ static void enter_pmode(struct kvm_vcpu *vcpu)
vmx->emulation_required = 1;
vmx->rmode.vm86_active = 0;
+ vmx_segment_cache_clear(vmx);
+
vmcs_write16(GUEST_TR_SELECTOR, vmx->rmode.tr.selector);
vmcs_writel(GUEST_TR_BASE, vmx->rmode.tr.base);
vmcs_write32(GUEST_TR_LIMIT, vmx->rmode.tr.limit);
@@ -1712,6 +1813,8 @@ static void enter_pmode(struct kvm_vcpu *vcpu)
fix_pmode_dataseg(VCPU_SREG_GS, &vmx->rmode.gs);
fix_pmode_dataseg(VCPU_SREG_FS, &vmx->rmode.fs);
+ vmx_segment_cache_clear(vmx);
+
vmcs_write16(GUEST_SS_SELECTOR, 0);
vmcs_write32(GUEST_SS_AR_BYTES, 0x93);
@@ -1775,6 +1878,8 @@ static void enter_rmode(struct kvm_vcpu *vcpu)
vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
}
+ vmx_segment_cache_clear(vmx);
+
vmx->rmode.tr.selector = vmcs_read16(GUEST_TR_SELECTOR);
vmx->rmode.tr.base = vmcs_readl(GUEST_TR_BASE);
vmcs_writel(GUEST_TR_BASE, rmode_tss_base(vcpu->kvm));
@@ -1851,6 +1956,8 @@ static void enter_lmode(struct kvm_vcpu *vcpu)
{
u32 guest_tr_ar;
+ vmx_segment_cache_clear(to_vmx(vcpu));
+
guest_tr_ar = vmcs_read32(GUEST_TR_AR_BYTES);
if ((guest_tr_ar & AR_TYPE_MASK) != AR_TYPE_BUSY_64_TSS) {
printk(KERN_DEBUG "%s: tss fixup for long mode. \n",
@@ -1998,6 +2105,7 @@ static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
vmcs_writel(CR0_READ_SHADOW, cr0);
vmcs_writel(GUEST_CR0, hw_cr0);
vcpu->arch.cr0 = cr0;
+ __clear_bit(VCPU_EXREG_CPL, (ulong *)&vcpu->arch.regs_avail);
}
static u64 construct_eptp(unsigned long root_hpa)
@@ -2053,7 +2161,6 @@ static void vmx_get_segment(struct kvm_vcpu *vcpu,
struct kvm_segment *var, int seg)
{
struct vcpu_vmx *vmx = to_vmx(vcpu);
- struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
struct kvm_save_segment *save;
u32 ar;
@@ -2075,13 +2182,13 @@ static void vmx_get_segment(struct kvm_vcpu *vcpu,
var->limit = save->limit;
ar = save->ar;
if (seg == VCPU_SREG_TR
- || var->selector == vmcs_read16(sf->selector))
+ || var->selector == vmx_read_guest_seg_selector(vmx, seg))
goto use_saved_rmode_seg;
}
- var->base = vmcs_readl(sf->base);
- var->limit = vmcs_read32(sf->limit);
- var->selector = vmcs_read16(sf->selector);
- ar = vmcs_read32(sf->ar_bytes);
+ var->base = vmx_read_guest_seg_base(vmx, seg);
+ var->limit = vmx_read_guest_seg_limit(vmx, seg);
+ var->selector = vmx_read_guest_seg_selector(vmx, seg);
+ ar = vmx_read_guest_seg_ar(vmx, seg);
use_saved_rmode_seg:
if ((ar & AR_UNUSABLE_MASK) && !emulate_invalid_guest_state)
ar = 0;
@@ -2098,27 +2205,37 @@ use_saved_rmode_seg:
static u64 vmx_get_segment_base(struct kvm_vcpu *vcpu, int seg)
{
- struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
struct kvm_segment s;
if (to_vmx(vcpu)->rmode.vm86_active) {
vmx_get_segment(vcpu, &s, seg);
return s.base;
}
- return vmcs_readl(sf->base);
+ return vmx_read_guest_seg_base(to_vmx(vcpu), seg);
}
-static int vmx_get_cpl(struct kvm_vcpu *vcpu)
+static int __vmx_get_cpl(struct kvm_vcpu *vcpu)
{
if (!is_protmode(vcpu))
return 0;
- if (vmx_get_rflags(vcpu) & X86_EFLAGS_VM) /* if virtual 8086 */
+ if (!is_long_mode(vcpu)
+ && (kvm_get_rflags(vcpu) & X86_EFLAGS_VM)) /* if virtual 8086 */
return 3;
- return vmcs_read16(GUEST_CS_SELECTOR) & 3;
+ return vmx_read_guest_seg_selector(to_vmx(vcpu), VCPU_SREG_CS) & 3;
}
+static int vmx_get_cpl(struct kvm_vcpu *vcpu)
+{
+ if (!test_bit(VCPU_EXREG_CPL, (ulong *)&vcpu->arch.regs_avail)) {
+ __set_bit(VCPU_EXREG_CPL, (ulong *)&vcpu->arch.regs_avail);
+ to_vmx(vcpu)->cpl = __vmx_get_cpl(vcpu);
+ }
+ return to_vmx(vcpu)->cpl;
+}
+
+
static u32 vmx_segment_access_rights(struct kvm_segment *var)
{
u32 ar;
@@ -2148,6 +2265,8 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu,
struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg];
u32 ar;
+ vmx_segment_cache_clear(vmx);
+
if (vmx->rmode.vm86_active && seg == VCPU_SREG_TR) {
vmcs_write16(sf->selector, var->selector);
vmx->rmode.tr.selector = var->selector;
@@ -2184,11 +2303,12 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu,
ar |= 0x1; /* Accessed */
vmcs_write32(sf->ar_bytes, ar);
+ __clear_bit(VCPU_EXREG_CPL, (ulong *)&vcpu->arch.regs_avail);
}
static void vmx_get_cs_db_l_bits(struct kvm_vcpu *vcpu, int *db, int *l)
{
- u32 ar = vmcs_read32(GUEST_CS_AR_BYTES);
+ u32 ar = vmx_read_guest_seg_ar(to_vmx(vcpu), VCPU_SREG_CS);
*db = (ar >> 14) & 1;
*l = (ar >> 13) & 1;
@@ -2775,6 +2895,8 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)
if (ret != 0)
goto out;
+ vmx_segment_cache_clear(vmx);
+
seg_setup(VCPU_SREG_CS);
/*
* GUEST_CS_BASE should really be 0xffff0000, but VT vm86 mode
@@ -2904,7 +3026,10 @@ static void vmx_inject_irq(struct kvm_vcpu *vcpu)
++vcpu->stat.irq_injections;
if (vmx->rmode.vm86_active) {
- if (kvm_inject_realmode_interrupt(vcpu, irq) != EMULATE_DONE)
+ int inc_eip = 0;
+ if (vcpu->arch.interrupt.soft)
+ inc_eip = vcpu->arch.event_exit_inst_len;
+ if (kvm_inject_realmode_interrupt(vcpu, irq, inc_eip) != EMULATE_DONE)
kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
return;
}
@@ -2937,8 +3062,9 @@ static void vmx_inject_nmi(struct kvm_vcpu *vcpu)
}
++vcpu->stat.nmi_injections;
+ vmx->nmi_known_unmasked = false;
if (vmx->rmode.vm86_active) {
- if (kvm_inject_realmode_interrupt(vcpu, NMI_VECTOR) != EMULATE_DONE)
+ if (kvm_inject_realmode_interrupt(vcpu, NMI_VECTOR, 0) != EMULATE_DONE)
kvm_make_request(KVM_REQ_TRIPLE_FAULT, vcpu);
return;
}
@@ -2961,6 +3087,8 @@ static bool vmx_get_nmi_mask(struct kvm_vcpu *vcpu)
{
if (!cpu_has_virtual_nmis())
return to_vmx(vcpu)->soft_vnmi_blocked;
+ if (to_vmx(vcpu)->nmi_known_unmasked)
+ return false;
return vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & GUEST_INTR_STATE_NMI;
}
@@ -2974,6 +3102,7 @@ static void vmx_set_nmi_mask(struct kvm_vcpu *vcpu, bool masked)
vmx->vnmi_blocked_time = 0;
}
} else {
+ vmx->nmi_known_unmasked = !masked;
if (masked)
vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO,
GUEST_INTR_STATE_NMI);
@@ -3091,7 +3220,7 @@ static int handle_exception(struct kvm_vcpu *vcpu)
enum emulation_result er;
vect_info = vmx->idt_vectoring_info;
- intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
+ intr_info = vmx->exit_intr_info;
if (is_machine_check(intr_info))
return handle_machine_check(vcpu);
@@ -3122,7 +3251,6 @@ static int handle_exception(struct kvm_vcpu *vcpu)
}
error_code = 0;
- rip = kvm_rip_read(vcpu);
if (intr_info & INTR_INFO_DELIVER_CODE_MASK)
error_code = vmcs_read32(VM_EXIT_INTR_ERROR_CODE);
if (is_page_fault(intr_info)) {
@@ -3169,6 +3297,7 @@ static int handle_exception(struct kvm_vcpu *vcpu)
vmx->vcpu.arch.event_exit_inst_len =
vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
kvm_run->exit_reason = KVM_EXIT_DEBUG;
+ rip = kvm_rip_read(vcpu);
kvm_run->debug.arch.pc = vmcs_readl(GUEST_CS_BASE) + rip;
kvm_run->debug.arch.exception = ex_no;
break;
@@ -3505,9 +3634,7 @@ static int handle_task_switch(struct kvm_vcpu *vcpu)
switch (type) {
case INTR_TYPE_NMI_INTR:
vcpu->arch.nmi_injected = false;
- if (cpu_has_virtual_nmis())
- vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO,
- GUEST_INTR_STATE_NMI);
+ vmx_set_nmi_mask(vcpu, true);
break;
case INTR_TYPE_EXT_INTR:
case INTR_TYPE_SOFT_INTR:
@@ -3867,12 +3994,17 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu, int tpr, int irr)
static void vmx_complete_atomic_exit(struct vcpu_vmx *vmx)
{
- u32 exit_intr_info = vmx->exit_intr_info;
+ u32 exit_intr_info;
+
+ if (!(vmx->exit_reason == EXIT_REASON_MCE_DURING_VMENTRY
+ || vmx->exit_reason == EXIT_REASON_EXCEPTION_NMI))
+ return;
+
+ vmx->exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
+ exit_intr_info = vmx->exit_intr_info;
/* Handle machine checks before interrupts are enabled */
- if ((vmx->exit_reason == EXIT_REASON_MCE_DURING_VMENTRY)
- || (vmx->exit_reason == EXIT_REASON_EXCEPTION_NMI
- && is_machine_check(exit_intr_info)))
+ if (is_machine_check(exit_intr_info))
kvm_machine_check();
/* We need to handle NMIs before interrupts are enabled */
@@ -3886,7 +4018,7 @@ static void vmx_complete_atomic_exit(struct vcpu_vmx *vmx)
static void vmx_recover_nmi_blocking(struct vcpu_vmx *vmx)
{
- u32 exit_intr_info = vmx->exit_intr_info;
+ u32 exit_intr_info;
bool unblock_nmi;
u8 vector;
bool idtv_info_valid;
@@ -3894,6 +4026,13 @@ static void vmx_recover_nmi_blocking(struct vcpu_vmx *vmx)
idtv_info_valid = vmx->idt_vectoring_info & VECTORING_INFO_VALID_MASK;
if (cpu_has_virtual_nmis()) {
+ if (vmx->nmi_known_unmasked)
+ return;
+ /*
+ * Can't use vmx->exit_intr_info since we're not sure what
+ * the exit reason is.
+ */
+ exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
unblock_nmi = (exit_intr_info & INTR_INFO_UNBLOCK_NMI) != 0;
vector = exit_intr_info & INTR_INFO_VECTOR_MASK;
/*
@@ -3910,6 +4049,10 @@ static void vmx_recover_nmi_blocking(struct vcpu_vmx *vmx)
vector != DF_VECTOR && !idtv_info_valid)
vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO,
GUEST_INTR_STATE_NMI);
+ else
+ vmx->nmi_known_unmasked =
+ !(vmcs_read32(GUEST_INTERRUPTIBILITY_INFO)
+ & GUEST_INTR_STATE_NMI);
} else if (unlikely(vmx->soft_vnmi_blocked))
vmx->vnmi_blocked_time +=
ktime_to_ns(ktime_sub(ktime_get(), vmx->entry_time));
@@ -3946,8 +4089,7 @@ static void __vmx_complete_interrupts(struct vcpu_vmx *vmx,
* Clear bit "block by NMI" before VM entry if a NMI
* delivery faulted.
*/
- vmcs_clear_bits(GUEST_INTERRUPTIBILITY_INFO,
- GUEST_INTR_STATE_NMI);
+ vmx_set_nmi_mask(&vmx->vcpu, false);
break;
case INTR_TYPE_SOFT_EXCEPTION:
vmx->vcpu.arch.event_exit_inst_len =
@@ -4124,7 +4266,10 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
);
vcpu->arch.regs_avail = ~((1 << VCPU_REGS_RIP) | (1 << VCPU_REGS_RSP)
+ | (1 << VCPU_EXREG_RFLAGS)
+ | (1 << VCPU_EXREG_CPL)
| (1 << VCPU_EXREG_PDPTR)
+ | (1 << VCPU_EXREG_SEGMENTS)
| (1 << VCPU_EXREG_CR3));
vcpu->arch.regs_dirty = 0;
@@ -4134,7 +4279,6 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
vmx->launched = 1;
vmx->exit_reason = vmcs_read32(VM_EXIT_REASON);
- vmx->exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
vmx_complete_atomic_exit(vmx);
vmx_recover_nmi_blocking(vmx);
@@ -4195,8 +4339,8 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
goto free_vcpu;
vmx->guest_msrs = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ err = -ENOMEM;
if (!vmx->guest_msrs) {
- err = -ENOMEM;
goto uninit_vcpu;
}
@@ -4215,7 +4359,8 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
if (err)
goto free_vmcs;
if (vm_need_virtualize_apic_accesses(kvm))
- if (alloc_apic_access_page(kvm) != 0)
+ err = alloc_apic_access_page(kvm);
+ if (err)
goto free_vmcs;
if (enable_ept) {
@@ -4368,6 +4513,13 @@ static void vmx_set_supported_cpuid(u32 func, struct kvm_cpuid_entry2 *entry)
{
}
+static int vmx_check_intercept(struct kvm_vcpu *vcpu,
+ struct x86_instruction_info *info,
+ enum x86_intercept_stage stage)
+{
+ return X86EMUL_CONTINUE;
+}
+
static struct kvm_x86_ops vmx_x86_ops = {
.cpu_has_kvm_support = cpu_has_kvm_support,
.disabled_by_bios = vmx_disabled_by_bios,
@@ -4449,10 +4601,14 @@ static struct kvm_x86_ops vmx_x86_ops = {
.has_wbinvd_exit = cpu_has_vmx_wbinvd_exit,
+ .set_tsc_khz = vmx_set_tsc_khz,
.write_tsc_offset = vmx_write_tsc_offset,
.adjust_tsc_offset = vmx_adjust_tsc_offset,
+ .compute_tsc_offset = vmx_compute_tsc_offset,
.set_tdp_cr3 = vmx_set_cr3,
+
+ .check_intercept = vmx_check_intercept,
};
static int __init vmx_init(void)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 934b4c6b0bf9..77c9d8673dc4 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -60,22 +60,12 @@
#include <asm/div64.h>
#define MAX_IO_MSRS 256
-#define CR0_RESERVED_BITS \
- (~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \
- | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM \
- | X86_CR0_NW | X86_CR0_CD | X86_CR0_PG))
-#define CR4_RESERVED_BITS \
- (~(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)
-
#define KVM_MAX_MCE_BANKS 32
#define KVM_MCE_CAP_SUPPORTED (MCG_CTL_P | MCG_SER_P)
+#define emul_to_vcpu(ctxt) \
+ container_of(ctxt, struct kvm_vcpu, arch.emulate_ctxt)
+
/* EFER defaults:
* - enable syscall per default because its emulated by KVM
* - enable LME and LMA per default on 64 bit KVM
@@ -100,6 +90,11 @@ EXPORT_SYMBOL_GPL(kvm_x86_ops);
int ignore_msrs = 0;
module_param_named(ignore_msrs, ignore_msrs, bool, S_IRUGO | S_IWUSR);
+bool kvm_has_tsc_control;
+EXPORT_SYMBOL_GPL(kvm_has_tsc_control);
+u32 kvm_max_guest_tsc_khz;
+EXPORT_SYMBOL_GPL(kvm_max_guest_tsc_khz);
+
#define KVM_NR_SHARED_MSRS 16
struct kvm_shared_msrs_global {
@@ -157,6 +152,8 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
u64 __read_mostly host_xcr0;
+int emulator_fix_hypercall(struct x86_emulate_ctxt *ctxt);
+
static inline void kvm_async_pf_hash_reset(struct kvm_vcpu *vcpu)
{
int i;
@@ -361,8 +358,8 @@ void kvm_propagate_fault(struct kvm_vcpu *vcpu, struct x86_exception *fault)
void kvm_inject_nmi(struct kvm_vcpu *vcpu)
{
- kvm_make_request(KVM_REQ_NMI, vcpu);
kvm_make_request(KVM_REQ_EVENT, vcpu);
+ vcpu->arch.nmi_pending = 1;
}
EXPORT_SYMBOL_GPL(kvm_inject_nmi);
@@ -982,7 +979,15 @@ static inline int kvm_tsc_changes_freq(void)
return ret;
}
-static inline u64 nsec_to_cycles(u64 nsec)
+static u64 vcpu_tsc_khz(struct kvm_vcpu *vcpu)
+{
+ if (vcpu->arch.virtual_tsc_khz)
+ return vcpu->arch.virtual_tsc_khz;
+ else
+ return __this_cpu_read(cpu_tsc_khz);
+}
+
+static inline u64 nsec_to_cycles(struct kvm_vcpu *vcpu, u64 nsec)
{
u64 ret;
@@ -990,25 +995,24 @@ static inline u64 nsec_to_cycles(u64 nsec)
if (kvm_tsc_changes_freq())
printk_once(KERN_WARNING
"kvm: unreliable cycle conversion on adjustable rate TSC\n");
- ret = nsec * __this_cpu_read(cpu_tsc_khz);
+ ret = nsec * vcpu_tsc_khz(vcpu);
do_div(ret, USEC_PER_SEC);
return ret;
}
-static void kvm_arch_set_tsc_khz(struct kvm *kvm, u32 this_tsc_khz)
+static void kvm_init_tsc_catchup(struct kvm_vcpu *vcpu, u32 this_tsc_khz)
{
/* Compute a scale to convert nanoseconds in TSC cycles */
kvm_get_time_scale(this_tsc_khz, NSEC_PER_SEC / 1000,
- &kvm->arch.virtual_tsc_shift,
- &kvm->arch.virtual_tsc_mult);
- kvm->arch.virtual_tsc_khz = this_tsc_khz;
+ &vcpu->arch.tsc_catchup_shift,
+ &vcpu->arch.tsc_catchup_mult);
}
static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns)
{
u64 tsc = pvclock_scale_delta(kernel_ns-vcpu->arch.last_tsc_nsec,
- vcpu->kvm->arch.virtual_tsc_mult,
- vcpu->kvm->arch.virtual_tsc_shift);
+ vcpu->arch.tsc_catchup_mult,
+ vcpu->arch.tsc_catchup_shift);
tsc += vcpu->arch.last_tsc_write;
return tsc;
}
@@ -1021,7 +1025,7 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, u64 data)
s64 sdiff;
raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);
- offset = data - native_read_tsc();
+ offset = kvm_x86_ops->compute_tsc_offset(vcpu, data);
ns = get_kernel_ns();
elapsed = ns - kvm->arch.last_tsc_nsec;
sdiff = data - kvm->arch.last_tsc_write;
@@ -1037,13 +1041,13 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, u64 data)
* In that case, for a reliable TSC, we can match TSC offsets,
* or make a best guest using elapsed value.
*/
- if (sdiff < nsec_to_cycles(5ULL * NSEC_PER_SEC) &&
+ if (sdiff < nsec_to_cycles(vcpu, 5ULL * NSEC_PER_SEC) &&
elapsed < 5ULL * NSEC_PER_SEC) {
if (!check_tsc_unstable()) {
offset = kvm->arch.last_tsc_offset;
pr_debug("kvm: matched tsc offset for %llu\n", data);
} else {
- u64 delta = nsec_to_cycles(elapsed);
+ u64 delta = nsec_to_cycles(vcpu, elapsed);
offset += delta;
pr_debug("kvm: adjusted tsc offset by %llu\n", delta);
}
@@ -1075,8 +1079,7 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
local_irq_save(flags);
kvm_get_msr(v, MSR_IA32_TSC, &tsc_timestamp);
kernel_ns = get_kernel_ns();
- this_tsc_khz = __this_cpu_read(cpu_tsc_khz);
-
+ this_tsc_khz = vcpu_tsc_khz(v);
if (unlikely(this_tsc_khz == 0)) {
local_irq_restore(flags);
kvm_make_request(KVM_REQ_CLOCK_UPDATE, v);
@@ -1993,6 +1996,7 @@ int kvm_dev_ioctl_check_extension(long ext)
case KVM_CAP_X86_ROBUST_SINGLESTEP:
case KVM_CAP_XSAVE:
case KVM_CAP_ASYNC_PF:
+ case KVM_CAP_GET_TSC_KHZ:
r = 1;
break;
case KVM_CAP_COALESCED_MMIO:
@@ -2019,6 +2023,9 @@ int kvm_dev_ioctl_check_extension(long ext)
case KVM_CAP_XCRS:
r = cpu_has_xsave;
break;
+ case KVM_CAP_TSC_CONTROL:
+ r = kvm_has_tsc_control;
+ break;
default:
r = 0;
break;
@@ -2120,8 +2127,13 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
kvm_x86_ops->vcpu_load(vcpu, cpu);
if (unlikely(vcpu->cpu != cpu) || check_tsc_unstable()) {
/* Make sure TSC doesn't go backwards */
- s64 tsc_delta = !vcpu->arch.last_host_tsc ? 0 :
- native_read_tsc() - vcpu->arch.last_host_tsc;
+ s64 tsc_delta;
+ u64 tsc;
+
+ kvm_get_msr(vcpu, MSR_IA32_TSC, &tsc);
+ tsc_delta = !vcpu->arch.last_guest_tsc ? 0 :
+ tsc - vcpu->arch.last_guest_tsc;
+
if (tsc_delta < 0)
mark_tsc_unstable("KVM discovered backwards TSC");
if (check_tsc_unstable()) {
@@ -2139,7 +2151,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
{
kvm_x86_ops->vcpu_put(vcpu);
kvm_put_guest_fpu(vcpu);
- vcpu->arch.last_host_tsc = native_read_tsc();
+ kvm_get_msr(vcpu, MSR_IA32_TSC, &vcpu->arch.last_guest_tsc);
}
static int is_efer_nx(void)
@@ -2324,6 +2336,12 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
F(3DNOWPREFETCH) | 0 /* OSVW */ | 0 /* IBS */ | F(XOP) |
0 /* SKINIT, WDT, LWP */ | F(FMA4) | F(TBM);
+ /* cpuid 0xC0000001.edx */
+ const u32 kvm_supported_word5_x86_features =
+ F(XSTORE) | F(XSTORE_EN) | F(XCRYPT) | F(XCRYPT_EN) |
+ F(ACE2) | F(ACE2_EN) | F(PHE) | F(PHE_EN) |
+ F(PMM) | F(PMM_EN);
+
/* all calls to cpuid_count() should be made on the same cpu */
get_cpu();
do_cpuid_1_ent(entry, function, index);
@@ -2418,6 +2436,7 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
entry->eax = (1 << KVM_FEATURE_CLOCKSOURCE) |
(1 << KVM_FEATURE_NOP_IO_DELAY) |
(1 << KVM_FEATURE_CLOCKSOURCE2) |
+ (1 << KVM_FEATURE_ASYNC_PF) |
(1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT);
entry->ebx = 0;
entry->ecx = 0;
@@ -2432,6 +2451,20 @@ static void do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
entry->ecx &= kvm_supported_word6_x86_features;
cpuid_mask(&entry->ecx, 6);
break;
+ /*Add support for Centaur's CPUID instruction*/
+ case 0xC0000000:
+ /*Just support up to 0xC0000004 now*/
+ entry->eax = min(entry->eax, 0xC0000004);
+ break;
+ case 0xC0000001:
+ entry->edx &= kvm_supported_word5_x86_features;
+ cpuid_mask(&entry->edx, 5);
+ break;
+ case 0xC0000002:
+ case 0xC0000003:
+ case 0xC0000004:
+ /*Now nothing to do, reserved for the future*/
+ break;
}
kvm_x86_ops->set_supported_cpuid(function, entry);
@@ -2478,6 +2511,26 @@ static int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid,
if (nent >= cpuid->nent)
goto out_free;
+ /* Add support for Centaur's CPUID instruction. */
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR) {
+ do_cpuid_ent(&cpuid_entries[nent], 0xC0000000, 0,
+ &nent, cpuid->nent);
+
+ r = -E2BIG;
+ if (nent >= cpuid->nent)
+ goto out_free;
+
+ limit = cpuid_entries[nent - 1].eax;
+ for (func = 0xC0000001;
+ func <= limit && nent < cpuid->nent; ++func)
+ do_cpuid_ent(&cpuid_entries[nent], func, 0,
+ &nent, cpuid->nent);
+
+ r = -E2BIG;
+ if (nent >= cpuid->nent)
+ goto out_free;
+ }
+
do_cpuid_ent(&cpuid_entries[nent], KVM_CPUID_SIGNATURE, 0, &nent,
cpuid->nent);
@@ -3046,6 +3099,32 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
r = kvm_vcpu_ioctl_x86_set_xcrs(vcpu, u.xcrs);
break;
}
+ case KVM_SET_TSC_KHZ: {
+ u32 user_tsc_khz;
+
+ r = -EINVAL;
+ if (!kvm_has_tsc_control)
+ break;
+
+ user_tsc_khz = (u32)arg;
+
+ if (user_tsc_khz >= kvm_max_guest_tsc_khz)
+ goto out;
+
+ kvm_x86_ops->set_tsc_khz(vcpu, user_tsc_khz);
+
+ r = 0;
+ goto out;
+ }
+ case KVM_GET_TSC_KHZ: {
+ r = -EIO;
+ if (check_tsc_unstable())
+ goto out;
+
+ r = vcpu_tsc_khz(vcpu);
+
+ goto out;
+ }
default:
r = -EINVAL;
}
@@ -3595,20 +3674,43 @@ static void kvm_init_msr_list(void)
static int vcpu_mmio_write(struct kvm_vcpu *vcpu, gpa_t addr, int len,
const void *v)
{
- if (vcpu->arch.apic &&
- !kvm_iodevice_write(&vcpu->arch.apic->dev, addr, len, v))
- return 0;
+ int handled = 0;
+ int n;
- return kvm_io_bus_write(vcpu->kvm, KVM_MMIO_BUS, addr, len, v);
+ do {
+ n = min(len, 8);
+ if (!(vcpu->arch.apic &&
+ !kvm_iodevice_write(&vcpu->arch.apic->dev, addr, n, v))
+ && kvm_io_bus_write(vcpu->kvm, KVM_MMIO_BUS, addr, n, v))
+ break;
+ handled += n;
+ addr += n;
+ len -= n;
+ v += n;
+ } while (len);
+
+ return handled;
}
static int vcpu_mmio_read(struct kvm_vcpu *vcpu, gpa_t addr, int len, void *v)
{
- if (vcpu->arch.apic &&
- !kvm_iodevice_read(&vcpu->arch.apic->dev, addr, len, v))
- return 0;
+ int handled = 0;
+ int n;
+
+ do {
+ n = min(len, 8);
+ if (!(vcpu->arch.apic &&
+ !kvm_iodevice_read(&vcpu->arch.apic->dev, addr, n, v))
+ && kvm_io_bus_read(vcpu->kvm, KVM_MMIO_BUS, addr, n, v))
+ break;
+ trace_kvm_mmio(KVM_TRACE_MMIO_READ, n, addr, *(u64 *)v);
+ handled += n;
+ addr += n;
+ len -= n;
+ v += n;
+ } while (len);
- return kvm_io_bus_read(vcpu->kvm, KVM_MMIO_BUS, addr, len, v);
+ return handled;
}
static void kvm_set_segment(struct kvm_vcpu *vcpu,
@@ -3703,37 +3805,43 @@ out:
}
/* used for instruction fetching */
-static int kvm_fetch_guest_virt(gva_t addr, void *val, unsigned int bytes,
- struct kvm_vcpu *vcpu,
+static int kvm_fetch_guest_virt(struct x86_emulate_ctxt *ctxt,
+ gva_t addr, void *val, unsigned int bytes,
struct x86_exception *exception)
{
+ struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
+
return kvm_read_guest_virt_helper(addr, val, bytes, vcpu,
access | PFERR_FETCH_MASK,
exception);
}
-static int kvm_read_guest_virt(gva_t addr, void *val, unsigned int bytes,
- struct kvm_vcpu *vcpu,
+static int kvm_read_guest_virt(struct x86_emulate_ctxt *ctxt,
+ gva_t addr, void *val, unsigned int bytes,
struct x86_exception *exception)
{
+ struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0;
+
return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, access,
exception);
}
-static int kvm_read_guest_virt_system(gva_t addr, void *val, unsigned int bytes,
- struct kvm_vcpu *vcpu,
+static int kvm_read_guest_virt_system(struct x86_emulate_ctxt *ctxt,
+ gva_t addr, void *val, unsigned int bytes,
struct x86_exception *exception)
{
+ struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, 0, exception);
}
-static int kvm_write_guest_virt_system(gva_t addr, void *val,
+static int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt,
+ gva_t addr, void *val,
unsigned int bytes,
- struct kvm_vcpu *vcpu,
struct x86_exception *exception)
{
+ struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
void *data = val;
int r = X86EMUL_CONTINUE;
@@ -3761,13 +3869,15 @@ out:
return r;
}
-static int emulator_read_emulated(unsigned long addr,
+static int emulator_read_emulated(struct x86_emulate_ctxt *ctxt,
+ unsigned long addr,
void *val,
unsigned int bytes,
- struct x86_exception *exception,
- struct kvm_vcpu *vcpu)
+ struct x86_exception *exception)
{
+ struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
gpa_t gpa;
+ int handled;
if (vcpu->mmio_read_completed) {
memcpy(val, vcpu->mmio_data, bytes);
@@ -3786,7 +3896,7 @@ static int emulator_read_emulated(unsigned long addr,
if ((gpa & PAGE_MASK) == APIC_DEFAULT_PHYS_BASE)
goto mmio;
- if (kvm_read_guest_virt(addr, val, bytes, vcpu, exception)
+ if (kvm_read_guest_virt(ctxt, addr, val, bytes, exception)
== X86EMUL_CONTINUE)
return X86EMUL_CONTINUE;
@@ -3794,18 +3904,24 @@ mmio:
/*
* Is this MMIO handled locally?
*/
- if (!vcpu_mmio_read(vcpu, gpa, bytes, val)) {
- trace_kvm_mmio(KVM_TRACE_MMIO_READ, bytes, gpa, *(u64 *)val);
+ handled = vcpu_mmio_read(vcpu, gpa, bytes, val);
+
+ if (handled == bytes)
return X86EMUL_CONTINUE;
- }
+
+ gpa += handled;
+ bytes -= handled;
+ val += handled;
trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, bytes, gpa, 0);
vcpu->mmio_needed = 1;
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->mmio_size = bytes;
+ vcpu->run->mmio.len = min(vcpu->mmio_size, 8);
vcpu->run->mmio.is_write = vcpu->mmio_is_write = 0;
+ vcpu->mmio_index = 0;
return X86EMUL_IO_NEEDED;
}
@@ -3829,6 +3945,7 @@ static int emulator_write_emulated_onepage(unsigned long addr,
struct kvm_vcpu *vcpu)
{
gpa_t gpa;
+ int handled;
gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, exception);
@@ -3847,25 +3964,35 @@ mmio:
/*
* Is this MMIO handled locally?
*/
- if (!vcpu_mmio_write(vcpu, gpa, bytes, val))
+ handled = vcpu_mmio_write(vcpu, gpa, bytes, val);
+ if (handled == bytes)
return X86EMUL_CONTINUE;
+ gpa += handled;
+ bytes -= handled;
+ val += handled;
+
vcpu->mmio_needed = 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->mmio_size = bytes;
+ vcpu->run->mmio.len = min(vcpu->mmio_size, 8);
vcpu->run->mmio.is_write = vcpu->mmio_is_write = 1;
- memcpy(vcpu->run->mmio.data, val, bytes);
+ memcpy(vcpu->run->mmio.data, vcpu->mmio_data, 8);
+ vcpu->mmio_index = 0;
return X86EMUL_CONTINUE;
}
-int emulator_write_emulated(unsigned long addr,
+int emulator_write_emulated(struct x86_emulate_ctxt *ctxt,
+ unsigned long addr,
const void *val,
unsigned int bytes,
- struct x86_exception *exception,
- struct kvm_vcpu *vcpu)
+ struct x86_exception *exception)
{
+ struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
+
/* Crossing a page boundary? */
if (((addr + bytes - 1) ^ addr) & PAGE_MASK) {
int rc, now;
@@ -3893,13 +4020,14 @@ int emulator_write_emulated(unsigned long addr,
(cmpxchg64((u64 *)(ptr), *(u64 *)(old), *(u64 *)(new)) == *(u64 *)(old))
#endif
-static int emulator_cmpxchg_emulated(unsigned long addr,
+static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt,
+ unsigned long addr,
const void *old,
const void *new,
unsigned int bytes,
- struct x86_exception *exception,
- struct kvm_vcpu *vcpu)
+ struct x86_exception *exception)
{
+ struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
gpa_t gpa;
struct page *page;
char *kaddr;
@@ -3955,7 +4083,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, exception, vcpu);
+ return emulator_write_emulated(ctxt, addr, new, bytes, exception);
}
static int kernel_pio(struct kvm_vcpu *vcpu, void *pd)
@@ -3974,9 +4102,12 @@ static int kernel_pio(struct kvm_vcpu *vcpu, void *pd)
}
-static int emulator_pio_in_emulated(int size, unsigned short port, void *val,
- unsigned int count, struct kvm_vcpu *vcpu)
+static int emulator_pio_in_emulated(struct x86_emulate_ctxt *ctxt,
+ int size, unsigned short port, void *val,
+ unsigned int count)
{
+ struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
+
if (vcpu->arch.pio.count)
goto data_avail;
@@ -4004,10 +4135,12 @@ static int emulator_pio_in_emulated(int size, unsigned short port, void *val,
return 0;
}
-static int emulator_pio_out_emulated(int size, unsigned short port,
- const void *val, unsigned int count,
- struct kvm_vcpu *vcpu)
+static int emulator_pio_out_emulated(struct x86_emulate_ctxt *ctxt,
+ int size, unsigned short port,
+ const void *val, unsigned int count)
{
+ struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
+
trace_kvm_pio(1, port, size, count);
vcpu->arch.pio.port = port;
@@ -4037,10 +4170,9 @@ static unsigned long get_segment_base(struct kvm_vcpu *vcpu, int seg)
return kvm_x86_ops->get_segment_base(vcpu, seg);
}
-int emulate_invlpg(struct kvm_vcpu *vcpu, gva_t address)
+static void emulator_invlpg(struct x86_emulate_ctxt *ctxt, ulong address)
{
- kvm_mmu_invlpg(vcpu, address);
- return X86EMUL_CONTINUE;
+ kvm_mmu_invlpg(emul_to_vcpu(ctxt), address);
}
int kvm_emulate_wbinvd(struct kvm_vcpu *vcpu)
@@ -4062,22 +4194,20 @@ int kvm_emulate_wbinvd(struct kvm_vcpu *vcpu)
}
EXPORT_SYMBOL_GPL(kvm_emulate_wbinvd);
-int emulate_clts(struct kvm_vcpu *vcpu)
+static void emulator_wbinvd(struct x86_emulate_ctxt *ctxt)
{
- kvm_x86_ops->set_cr0(vcpu, kvm_read_cr0_bits(vcpu, ~X86_CR0_TS));
- kvm_x86_ops->fpu_activate(vcpu);
- return X86EMUL_CONTINUE;
+ kvm_emulate_wbinvd(emul_to_vcpu(ctxt));
}
-int emulator_get_dr(int dr, unsigned long *dest, struct kvm_vcpu *vcpu)
+int emulator_get_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long *dest)
{
- return _kvm_get_dr(vcpu, dr, dest);
+ return _kvm_get_dr(emul_to_vcpu(ctxt), dr, dest);
}
-int emulator_set_dr(int dr, unsigned long value, struct kvm_vcpu *vcpu)
+int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value)
{
- return __kvm_set_dr(vcpu, dr, value);
+ return __kvm_set_dr(emul_to_vcpu(ctxt), dr, value);
}
static u64 mk_cr_64(u64 curr_cr, u32 new_val)
@@ -4085,8 +4215,9 @@ static u64 mk_cr_64(u64 curr_cr, u32 new_val)
return (curr_cr & ~((1ULL << 32) - 1)) | new_val;
}
-static unsigned long emulator_get_cr(int cr, struct kvm_vcpu *vcpu)
+static unsigned long emulator_get_cr(struct x86_emulate_ctxt *ctxt, int cr)
{
+ struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
unsigned long value;
switch (cr) {
@@ -4113,8 +4244,9 @@ static unsigned long emulator_get_cr(int cr, struct kvm_vcpu *vcpu)
return value;
}
-static int emulator_set_cr(int cr, unsigned long val, struct kvm_vcpu *vcpu)
+static int emulator_set_cr(struct x86_emulate_ctxt *ctxt, int cr, ulong val)
{
+ struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
int res = 0;
switch (cr) {
@@ -4141,33 +4273,45 @@ static int emulator_set_cr(int cr, unsigned long val, struct kvm_vcpu *vcpu)
return res;
}
-static int emulator_get_cpl(struct kvm_vcpu *vcpu)
+static int emulator_get_cpl(struct x86_emulate_ctxt *ctxt)
+{
+ return kvm_x86_ops->get_cpl(emul_to_vcpu(ctxt));
+}
+
+static void emulator_get_gdt(struct x86_emulate_ctxt *ctxt, struct desc_ptr *dt)
+{
+ kvm_x86_ops->get_gdt(emul_to_vcpu(ctxt), dt);
+}
+
+static void emulator_get_idt(struct x86_emulate_ctxt *ctxt, struct desc_ptr *dt)
{
- return kvm_x86_ops->get_cpl(vcpu);
+ kvm_x86_ops->get_idt(emul_to_vcpu(ctxt), dt);
}
-static void emulator_get_gdt(struct desc_ptr *dt, struct kvm_vcpu *vcpu)
+static void emulator_set_gdt(struct x86_emulate_ctxt *ctxt, struct desc_ptr *dt)
{
- kvm_x86_ops->get_gdt(vcpu, dt);
+ kvm_x86_ops->set_gdt(emul_to_vcpu(ctxt), dt);
}
-static void emulator_get_idt(struct desc_ptr *dt, struct kvm_vcpu *vcpu)
+static void emulator_set_idt(struct x86_emulate_ctxt *ctxt, struct desc_ptr *dt)
{
- kvm_x86_ops->get_idt(vcpu, dt);
+ kvm_x86_ops->set_idt(emul_to_vcpu(ctxt), dt);
}
-static unsigned long emulator_get_cached_segment_base(int seg,
- struct kvm_vcpu *vcpu)
+static unsigned long emulator_get_cached_segment_base(
+ struct x86_emulate_ctxt *ctxt, int seg)
{
- return get_segment_base(vcpu, seg);
+ return get_segment_base(emul_to_vcpu(ctxt), seg);
}
-static bool emulator_get_cached_descriptor(struct desc_struct *desc, u32 *base3,
- int seg, struct kvm_vcpu *vcpu)
+static bool emulator_get_segment(struct x86_emulate_ctxt *ctxt, u16 *selector,
+ struct desc_struct *desc, u32 *base3,
+ int seg)
{
struct kvm_segment var;
- kvm_get_segment(vcpu, &var, seg);
+ kvm_get_segment(emul_to_vcpu(ctxt), &var, seg);
+ *selector = var.selector;
if (var.unusable)
return false;
@@ -4192,14 +4336,14 @@ static bool emulator_get_cached_descriptor(struct desc_struct *desc, u32 *base3,
return true;
}
-static void emulator_set_cached_descriptor(struct desc_struct *desc, u32 base3,
- int seg, struct kvm_vcpu *vcpu)
+static void emulator_set_segment(struct x86_emulate_ctxt *ctxt, u16 selector,
+ struct desc_struct *desc, u32 base3,
+ int seg)
{
+ struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
struct kvm_segment var;
- /* needed to preserve selector */
- kvm_get_segment(vcpu, &var, seg);
-
+ var.selector = selector;
var.base = get_desc_base(desc);
#ifdef CONFIG_X86_64
var.base |= ((u64)base3) << 32;
@@ -4223,22 +4367,44 @@ static void emulator_set_cached_descriptor(struct desc_struct *desc, u32 base3,
return;
}
-static u16 emulator_get_segment_selector(int seg, struct kvm_vcpu *vcpu)
+static int emulator_get_msr(struct x86_emulate_ctxt *ctxt,
+ u32 msr_index, u64 *pdata)
{
- struct kvm_segment kvm_seg;
+ return kvm_get_msr(emul_to_vcpu(ctxt), msr_index, pdata);
+}
- kvm_get_segment(vcpu, &kvm_seg, seg);
- return kvm_seg.selector;
+static int emulator_set_msr(struct x86_emulate_ctxt *ctxt,
+ u32 msr_index, u64 data)
+{
+ return kvm_set_msr(emul_to_vcpu(ctxt), msr_index, data);
}
-static void emulator_set_segment_selector(u16 sel, int seg,
- struct kvm_vcpu *vcpu)
+static void emulator_halt(struct x86_emulate_ctxt *ctxt)
{
- struct kvm_segment kvm_seg;
+ emul_to_vcpu(ctxt)->arch.halt_request = 1;
+}
- kvm_get_segment(vcpu, &kvm_seg, seg);
- kvm_seg.selector = sel;
- kvm_set_segment(vcpu, &kvm_seg, seg);
+static void emulator_get_fpu(struct x86_emulate_ctxt *ctxt)
+{
+ preempt_disable();
+ kvm_load_guest_fpu(emul_to_vcpu(ctxt));
+ /*
+ * CR0.TS may reference the host fpu state, not the guest fpu state,
+ * so it may be clear at this point.
+ */
+ clts();
+}
+
+static void emulator_put_fpu(struct x86_emulate_ctxt *ctxt)
+{
+ preempt_enable();
+}
+
+static int emulator_intercept(struct x86_emulate_ctxt *ctxt,
+ struct x86_instruction_info *info,
+ enum x86_intercept_stage stage)
+{
+ return kvm_x86_ops->check_intercept(emul_to_vcpu(ctxt), info, stage);
}
static struct x86_emulate_ops emulate_ops = {
@@ -4248,22 +4414,29 @@ static struct x86_emulate_ops emulate_ops = {
.read_emulated = emulator_read_emulated,
.write_emulated = emulator_write_emulated,
.cmpxchg_emulated = emulator_cmpxchg_emulated,
+ .invlpg = emulator_invlpg,
.pio_in_emulated = emulator_pio_in_emulated,
.pio_out_emulated = emulator_pio_out_emulated,
- .get_cached_descriptor = emulator_get_cached_descriptor,
- .set_cached_descriptor = emulator_set_cached_descriptor,
- .get_segment_selector = emulator_get_segment_selector,
- .set_segment_selector = emulator_set_segment_selector,
+ .get_segment = emulator_get_segment,
+ .set_segment = emulator_set_segment,
.get_cached_segment_base = emulator_get_cached_segment_base,
.get_gdt = emulator_get_gdt,
.get_idt = emulator_get_idt,
+ .set_gdt = emulator_set_gdt,
+ .set_idt = emulator_set_idt,
.get_cr = emulator_get_cr,
.set_cr = emulator_set_cr,
.cpl = emulator_get_cpl,
.get_dr = emulator_get_dr,
.set_dr = emulator_set_dr,
- .set_msr = kvm_set_msr,
- .get_msr = kvm_get_msr,
+ .set_msr = emulator_set_msr,
+ .get_msr = emulator_get_msr,
+ .halt = emulator_halt,
+ .wbinvd = emulator_wbinvd,
+ .fix_hypercall = emulator_fix_hypercall,
+ .get_fpu = emulator_get_fpu,
+ .put_fpu = emulator_put_fpu,
+ .intercept = emulator_intercept,
};
static void cache_all_regs(struct kvm_vcpu *vcpu)
@@ -4305,12 +4478,17 @@ static void init_emulate_ctxt(struct kvm_vcpu *vcpu)
struct decode_cache *c = &vcpu->arch.emulate_ctxt.decode;
int cs_db, cs_l;
+ /*
+ * TODO: fix emulate.c to use guest_read/write_register
+ * instead of direct ->regs accesses, can save hundred cycles
+ * on Intel for instructions that don't read/change RSP, for
+ * for example.
+ */
cache_all_regs(vcpu);
kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l);
- vcpu->arch.emulate_ctxt.vcpu = vcpu;
- vcpu->arch.emulate_ctxt.eflags = kvm_x86_ops->get_rflags(vcpu);
+ vcpu->arch.emulate_ctxt.eflags = kvm_get_rflags(vcpu);
vcpu->arch.emulate_ctxt.eip = kvm_rip_read(vcpu);
vcpu->arch.emulate_ctxt.mode =
(!is_protmode(vcpu)) ? X86EMUL_MODE_REAL :
@@ -4318,11 +4496,13 @@ static void init_emulate_ctxt(struct kvm_vcpu *vcpu)
? X86EMUL_MODE_VM86 : cs_l
? X86EMUL_MODE_PROT64 : cs_db
? X86EMUL_MODE_PROT32 : X86EMUL_MODE_PROT16;
+ vcpu->arch.emulate_ctxt.guest_mode = is_guest_mode(vcpu);
memset(c, 0, sizeof(struct decode_cache));
memcpy(c->regs, vcpu->arch.regs, sizeof c->regs);
+ vcpu->arch.emulate_regs_need_sync_from_vcpu = false;
}
-int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq)
+int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq, int inc_eip)
{
struct decode_cache *c = &vcpu->arch.emulate_ctxt.decode;
int ret;
@@ -4331,7 +4511,8 @@ int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq)
vcpu->arch.emulate_ctxt.decode.op_bytes = 2;
vcpu->arch.emulate_ctxt.decode.ad_bytes = 2;
- vcpu->arch.emulate_ctxt.decode.eip = vcpu->arch.emulate_ctxt.eip;
+ vcpu->arch.emulate_ctxt.decode.eip = vcpu->arch.emulate_ctxt.eip +
+ inc_eip;
ret = emulate_int_real(&vcpu->arch.emulate_ctxt, &emulate_ops, irq);
if (ret != X86EMUL_CONTINUE)
@@ -4340,7 +4521,7 @@ int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq)
vcpu->arch.emulate_ctxt.eip = c->eip;
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);
+ kvm_set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags);
if (irq == NMI_VECTOR)
vcpu->arch.nmi_pending = false;
@@ -4402,16 +4583,9 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu,
{
int r;
struct decode_cache *c = &vcpu->arch.emulate_ctxt.decode;
+ bool writeback = true;
kvm_clear_exception_queue(vcpu);
- vcpu->arch.mmio_fault_cr2 = cr2;
- /*
- * TODO: fix emulate.c to use guest_read/write_register
- * instead of direct ->regs accesses, can save hundred cycles
- * on Intel for instructions that don't read/change RSP, for
- * for example.
- */
- cache_all_regs(vcpu);
if (!(emulation_type & EMULTYPE_NO_DECODE)) {
init_emulate_ctxt(vcpu);
@@ -4442,13 +4616,19 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu,
return EMULATE_DONE;
}
- /* this is needed for vmware backdor interface to work since it
+ /* this is needed for vmware backdoor interface to work since it
changes registers values during IO operation */
- memcpy(c->regs, vcpu->arch.regs, sizeof c->regs);
+ if (vcpu->arch.emulate_regs_need_sync_from_vcpu) {
+ vcpu->arch.emulate_regs_need_sync_from_vcpu = false;
+ memcpy(c->regs, vcpu->arch.regs, sizeof c->regs);
+ }
restart:
r = x86_emulate_insn(&vcpu->arch.emulate_ctxt);
+ if (r == EMULATION_INTERCEPTED)
+ return EMULATE_DONE;
+
if (r == EMULATION_FAILED) {
if (reexecute_instruction(vcpu, cr2))
return EMULATE_DONE;
@@ -4462,21 +4642,28 @@ restart:
} else if (vcpu->arch.pio.count) {
if (!vcpu->arch.pio.in)
vcpu->arch.pio.count = 0;
+ else
+ writeback = false;
r = EMULATE_DO_MMIO;
} else if (vcpu->mmio_needed) {
- if (vcpu->mmio_is_write)
- vcpu->mmio_needed = 0;
+ if (!vcpu->mmio_is_write)
+ writeback = false;
r = EMULATE_DO_MMIO;
} else if (r == EMULATION_RESTART)
goto restart;
else
r = EMULATE_DONE;
- toggle_interruptibility(vcpu, vcpu->arch.emulate_ctxt.interruptibility);
- kvm_x86_ops->set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags);
- kvm_make_request(KVM_REQ_EVENT, vcpu);
- memcpy(vcpu->arch.regs, c->regs, sizeof c->regs);
- kvm_rip_write(vcpu, vcpu->arch.emulate_ctxt.eip);
+ if (writeback) {
+ toggle_interruptibility(vcpu,
+ vcpu->arch.emulate_ctxt.interruptibility);
+ kvm_set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags);
+ kvm_make_request(KVM_REQ_EVENT, vcpu);
+ memcpy(vcpu->arch.regs, c->regs, sizeof c->regs);
+ vcpu->arch.emulate_regs_need_sync_to_vcpu = false;
+ kvm_rip_write(vcpu, vcpu->arch.emulate_ctxt.eip);
+ } else
+ vcpu->arch.emulate_regs_need_sync_to_vcpu = true;
return r;
}
@@ -4485,7 +4672,8 @@ EXPORT_SYMBOL_GPL(x86_emulate_instruction);
int kvm_fast_pio_out(struct kvm_vcpu *vcpu, int size, unsigned short port)
{
unsigned long val = kvm_register_read(vcpu, VCPU_REGS_RAX);
- int ret = emulator_pio_out_emulated(size, port, &val, 1, vcpu);
+ int ret = emulator_pio_out_emulated(&vcpu->arch.emulate_ctxt,
+ size, port, &val, 1);
/* do not return to emulator after return from userspace */
vcpu->arch.pio.count = 0;
return ret;
@@ -4879,8 +5067,9 @@ out:
}
EXPORT_SYMBOL_GPL(kvm_emulate_hypercall);
-int kvm_fix_hypercall(struct kvm_vcpu *vcpu)
+int emulator_fix_hypercall(struct x86_emulate_ctxt *ctxt)
{
+ struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt);
char instruction[3];
unsigned long rip = kvm_rip_read(vcpu);
@@ -4893,21 +5082,8 @@ int kvm_fix_hypercall(struct kvm_vcpu *vcpu)
kvm_x86_ops->patch_hypercall(vcpu, instruction);
- return emulator_write_emulated(rip, instruction, 3, NULL, vcpu);
-}
-
-void realmode_lgdt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
-{
- struct desc_ptr dt = { limit, base };
-
- kvm_x86_ops->set_gdt(vcpu, &dt);
-}
-
-void realmode_lidt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base)
-{
- struct desc_ptr dt = { limit, base };
-
- kvm_x86_ops->set_idt(vcpu, &dt);
+ return emulator_write_emulated(&vcpu->arch.emulate_ctxt,
+ rip, instruction, 3, NULL);
}
static int move_to_next_stateful_cpuid_entry(struct kvm_vcpu *vcpu, int i)
@@ -5170,6 +5346,7 @@ static void kvm_put_guest_xcr0(struct kvm_vcpu *vcpu)
static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
{
int r;
+ bool nmi_pending;
bool req_int_win = !irqchip_in_kernel(vcpu->kvm) &&
vcpu->run->request_interrupt_window;
@@ -5207,19 +5384,25 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
r = 1;
goto out;
}
- if (kvm_check_request(KVM_REQ_NMI, vcpu))
- vcpu->arch.nmi_pending = true;
}
r = kvm_mmu_reload(vcpu);
if (unlikely(r))
goto out;
+ /*
+ * An NMI can be injected between local nmi_pending read and
+ * vcpu->arch.nmi_pending read inside inject_pending_event().
+ * But in that case, KVM_REQ_EVENT will be set, which makes
+ * the race described above benign.
+ */
+ nmi_pending = ACCESS_ONCE(vcpu->arch.nmi_pending);
+
if (kvm_check_request(KVM_REQ_EVENT, vcpu) || req_int_win) {
inject_pending_event(vcpu);
/* enable NMI/IRQ window open exits if needed */
- if (vcpu->arch.nmi_pending)
+ if (nmi_pending)
kvm_x86_ops->enable_nmi_window(vcpu);
else if (kvm_cpu_has_interrupt(vcpu) || req_int_win)
kvm_x86_ops->enable_irq_window(vcpu);
@@ -5399,6 +5582,41 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
return r;
}
+static int complete_mmio(struct kvm_vcpu *vcpu)
+{
+ struct kvm_run *run = vcpu->run;
+ int r;
+
+ if (!(vcpu->arch.pio.count || vcpu->mmio_needed))
+ return 1;
+
+ if (vcpu->mmio_needed) {
+ vcpu->mmio_needed = 0;
+ if (!vcpu->mmio_is_write)
+ memcpy(vcpu->mmio_data + vcpu->mmio_index,
+ run->mmio.data, 8);
+ vcpu->mmio_index += 8;
+ if (vcpu->mmio_index < vcpu->mmio_size) {
+ run->exit_reason = KVM_EXIT_MMIO;
+ run->mmio.phys_addr = vcpu->mmio_phys_addr + vcpu->mmio_index;
+ memcpy(run->mmio.data, vcpu->mmio_data + vcpu->mmio_index, 8);
+ run->mmio.len = min(vcpu->mmio_size - vcpu->mmio_index, 8);
+ run->mmio.is_write = vcpu->mmio_is_write;
+ vcpu->mmio_needed = 1;
+ return 0;
+ }
+ if (vcpu->mmio_is_write)
+ return 1;
+ vcpu->mmio_read_completed = 1;
+ }
+ vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
+ r = emulate_instruction(vcpu, EMULTYPE_NO_DECODE);
+ srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
+ if (r != EMULATE_DONE)
+ return 0;
+ return 1;
+}
+
int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
{
int r;
@@ -5425,20 +5643,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
}
}
- if (vcpu->arch.pio.count || vcpu->mmio_needed) {
- if (vcpu->mmio_needed) {
- memcpy(vcpu->mmio_data, kvm_run->mmio.data, 8);
- vcpu->mmio_read_completed = 1;
- vcpu->mmio_needed = 0;
- }
- vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
- r = emulate_instruction(vcpu, EMULTYPE_NO_DECODE);
- srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
- if (r != EMULATE_DONE) {
- r = 0;
- goto out;
- }
- }
+ r = complete_mmio(vcpu);
+ if (r <= 0)
+ goto out;
+
if (kvm_run->exit_reason == KVM_EXIT_HYPERCALL)
kvm_register_write(vcpu, VCPU_REGS_RAX,
kvm_run->hypercall.ret);
@@ -5455,6 +5663,18 @@ out:
int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
{
+ if (vcpu->arch.emulate_regs_need_sync_to_vcpu) {
+ /*
+ * We are here if userspace calls get_regs() in the middle of
+ * instruction emulation. Registers state needs to be copied
+ * back from emulation context to vcpu. Usrapace shouldn't do
+ * that usually, but some bad designed PV devices (vmware
+ * backdoor interface) need this to work
+ */
+ struct decode_cache *c = &vcpu->arch.emulate_ctxt.decode;
+ memcpy(vcpu->arch.regs, c->regs, sizeof c->regs);
+ vcpu->arch.emulate_regs_need_sync_to_vcpu = false;
+ }
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);
@@ -5482,6 +5702,9 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
{
+ vcpu->arch.emulate_regs_need_sync_from_vcpu = true;
+ vcpu->arch.emulate_regs_need_sync_to_vcpu = false;
+
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);
@@ -5592,7 +5815,7 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int reason,
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);
+ kvm_set_rflags(vcpu, vcpu->arch.emulate_ctxt.eflags);
kvm_make_request(KVM_REQ_EVENT, vcpu);
return EMULATE_DONE;
}
@@ -5974,8 +6197,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
}
vcpu->arch.pio_data = page_address(page);
- if (!kvm->arch.virtual_tsc_khz)
- kvm_arch_set_tsc_khz(kvm, max_tsc_khz);
+ kvm_init_tsc_catchup(vcpu, max_tsc_khz);
r = kvm_mmu_create(vcpu);
if (r < 0)
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index c600da830ce0..e407ed3df817 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -77,7 +77,7 @@ static inline u32 bit(int bitno)
void kvm_before_handle_nmi(struct kvm_vcpu *vcpu);
void kvm_after_handle_nmi(struct kvm_vcpu *vcpu);
-int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq);
+int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq, int inc_eip);
void kvm_write_tsc(struct kvm_vcpu *vcpu, u64 data);
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c
index 395bf0114aad..e191c096ab90 100644
--- a/arch/x86/lguest/boot.c
+++ b/arch/x86/lguest/boot.c
@@ -913,8 +913,6 @@ static struct clocksource lguest_clock = {
.rating = 200,
.read = lguest_clock_read,
.mask = CLOCKSOURCE_MASK(64),
- .mult = 1 << 22,
- .shift = 22,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
@@ -997,7 +995,7 @@ static void lguest_time_init(void)
/* Set up the timer interrupt (0) to go to our simple timer routine */
irq_set_handler(0, lguest_time_irq);
- clocksource_register(&lguest_clock);
+ clocksource_register_hz(&lguest_clock, NSEC_PER_SEC);
/* We can't set cpumask in the initializer: damn C limitations! Set it
* here and register our timer device. */
diff --git a/arch/x86/lib/clear_page_64.S b/arch/x86/lib/clear_page_64.S
index aa4326bfb24a..f2145cfa12a6 100644
--- a/arch/x86/lib/clear_page_64.S
+++ b/arch/x86/lib/clear_page_64.S
@@ -1,5 +1,6 @@
#include <linux/linkage.h>
#include <asm/dwarf2.h>
+#include <asm/alternative-asm.h>
/*
* Zero a page.
@@ -14,6 +15,15 @@ ENTRY(clear_page_c)
CFI_ENDPROC
ENDPROC(clear_page_c)
+ENTRY(clear_page_c_e)
+ CFI_STARTPROC
+ movl $4096,%ecx
+ xorl %eax,%eax
+ rep stosb
+ ret
+ CFI_ENDPROC
+ENDPROC(clear_page_c_e)
+
ENTRY(clear_page)
CFI_STARTPROC
xorl %eax,%eax
@@ -38,21 +48,26 @@ ENTRY(clear_page)
.Lclear_page_end:
ENDPROC(clear_page)
- /* Some CPUs run faster using the string instructions.
- It is also a lot simpler. Use this when possible */
+ /*
+ * Some CPUs support enhanced REP MOVSB/STOSB instructions.
+ * It is recommended to use this when possible.
+ * If enhanced REP MOVSB/STOSB is not available, try to use fast string.
+ * Otherwise, use original function.
+ *
+ */
#include <asm/cpufeature.h>
.section .altinstr_replacement,"ax"
1: .byte 0xeb /* jmp <disp8> */
.byte (clear_page_c - clear_page) - (2f - 1b) /* offset */
-2:
+2: .byte 0xeb /* jmp <disp8> */
+ .byte (clear_page_c_e - clear_page) - (3f - 2b) /* offset */
+3:
.previous
.section .altinstructions,"a"
- .align 8
- .quad clear_page
- .quad 1b
- .word X86_FEATURE_REP_GOOD
- .byte .Lclear_page_end - clear_page
- .byte 2b - 1b
+ altinstruction_entry clear_page,1b,X86_FEATURE_REP_GOOD,\
+ .Lclear_page_end-clear_page, 2b-1b
+ altinstruction_entry clear_page,2b,X86_FEATURE_ERMS, \
+ .Lclear_page_end-clear_page,3b-2b
.previous
diff --git a/arch/x86/lib/copy_user_64.S b/arch/x86/lib/copy_user_64.S
index 99e482615195..024840266ba0 100644
--- a/arch/x86/lib/copy_user_64.S
+++ b/arch/x86/lib/copy_user_64.S
@@ -15,23 +15,30 @@
#include <asm/asm-offsets.h>
#include <asm/thread_info.h>
#include <asm/cpufeature.h>
+#include <asm/alternative-asm.h>
- .macro ALTERNATIVE_JUMP feature,orig,alt
+/*
+ * By placing feature2 after feature1 in altinstructions section, we logically
+ * implement:
+ * If CPU has feature2, jmp to alt2 is used
+ * else if CPU has feature1, jmp to alt1 is used
+ * else jmp to orig is used.
+ */
+ .macro ALTERNATIVE_JUMP feature1,feature2,orig,alt1,alt2
0:
.byte 0xe9 /* 32bit jump */
.long \orig-1f /* by default jump to orig */
1:
.section .altinstr_replacement,"ax"
2: .byte 0xe9 /* near jump with 32bit immediate */
- .long \alt-1b /* offset */ /* or alternatively to alt */
+ .long \alt1-1b /* offset */ /* or alternatively to alt1 */
+3: .byte 0xe9 /* near jump with 32bit immediate */
+ .long \alt2-1b /* offset */ /* or alternatively to alt2 */
.previous
+
.section .altinstructions,"a"
- .align 8
- .quad 0b
- .quad 2b
- .word \feature /* when feature is set */
- .byte 5
- .byte 5
+ altinstruction_entry 0b,2b,\feature1,5,5
+ altinstruction_entry 0b,3b,\feature2,5,5
.previous
.endm
@@ -72,8 +79,10 @@ ENTRY(_copy_to_user)
addq %rdx,%rcx
jc bad_to_user
cmpq TI_addr_limit(%rax),%rcx
- jae bad_to_user
- ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
+ ja bad_to_user
+ ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,X86_FEATURE_ERMS, \
+ copy_user_generic_unrolled,copy_user_generic_string, \
+ copy_user_enhanced_fast_string
CFI_ENDPROC
ENDPROC(_copy_to_user)
@@ -85,8 +94,10 @@ ENTRY(_copy_from_user)
addq %rdx,%rcx
jc bad_from_user
cmpq TI_addr_limit(%rax),%rcx
- jae bad_from_user
- ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,copy_user_generic_unrolled,copy_user_generic_string
+ ja bad_from_user
+ ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,X86_FEATURE_ERMS, \
+ copy_user_generic_unrolled,copy_user_generic_string, \
+ copy_user_enhanced_fast_string
CFI_ENDPROC
ENDPROC(_copy_from_user)
@@ -255,3 +266,37 @@ ENTRY(copy_user_generic_string)
.previous
CFI_ENDPROC
ENDPROC(copy_user_generic_string)
+
+/*
+ * Some CPUs are adding enhanced REP MOVSB/STOSB instructions.
+ * It's recommended to use enhanced REP MOVSB/STOSB if it's enabled.
+ *
+ * Input:
+ * rdi destination
+ * rsi source
+ * rdx count
+ *
+ * Output:
+ * eax uncopied bytes or 0 if successful.
+ */
+ENTRY(copy_user_enhanced_fast_string)
+ CFI_STARTPROC
+ andl %edx,%edx
+ jz 2f
+ movl %edx,%ecx
+1: rep
+ movsb
+2: xorl %eax,%eax
+ ret
+
+ .section .fixup,"ax"
+12: movl %ecx,%edx /* ecx is zerorest also */
+ jmp copy_user_handle_tail
+ .previous
+
+ .section __ex_table,"a"
+ .align 8
+ .quad 1b,12b
+ .previous
+ CFI_ENDPROC
+ENDPROC(copy_user_enhanced_fast_string)
diff --git a/arch/x86/lib/memcpy_64.S b/arch/x86/lib/memcpy_64.S
index 75ef61e35e38..efbf2a0ecdea 100644
--- a/arch/x86/lib/memcpy_64.S
+++ b/arch/x86/lib/memcpy_64.S
@@ -4,6 +4,7 @@
#include <asm/cpufeature.h>
#include <asm/dwarf2.h>
+#include <asm/alternative-asm.h>
/*
* memcpy - Copy a memory block.
@@ -37,6 +38,23 @@
.Lmemcpy_e:
.previous
+/*
+ * memcpy_c_e() - enhanced fast string memcpy. This is faster and simpler than
+ * memcpy_c. Use memcpy_c_e when possible.
+ *
+ * This gets patched over the unrolled variant (below) via the
+ * alternative instructions framework:
+ */
+ .section .altinstr_replacement, "ax", @progbits
+.Lmemcpy_c_e:
+ movq %rdi, %rax
+
+ movl %edx, %ecx
+ rep movsb
+ ret
+.Lmemcpy_e_e:
+ .previous
+
ENTRY(__memcpy)
ENTRY(memcpy)
CFI_STARTPROC
@@ -49,7 +67,7 @@ ENTRY(memcpy)
jb .Lhandle_tail
/*
- * We check whether memory false dependece could occur,
+ * We check whether memory false dependence could occur,
* then jump to corresponding copy mode.
*/
cmp %dil, %sil
@@ -171,21 +189,22 @@ ENDPROC(memcpy)
ENDPROC(__memcpy)
/*
- * Some CPUs run faster using the string copy instructions.
- * It is also a lot simpler. Use this when possible:
- */
-
- .section .altinstructions, "a"
- .align 8
- .quad memcpy
- .quad .Lmemcpy_c
- .word X86_FEATURE_REP_GOOD
-
- /*
+ * Some CPUs are adding enhanced REP MOVSB/STOSB feature
+ * If the feature is supported, memcpy_c_e() is the first choice.
+ * If enhanced rep movsb copy is not available, use fast string copy
+ * memcpy_c() when possible. This is faster and code is simpler than
+ * original memcpy().
+ * Otherwise, original memcpy() is used.
+ * In .altinstructions section, ERMS feature is placed after REG_GOOD
+ * feature to implement the right patch order.
+ *
* Replace only beginning, memcpy is used to apply alternatives,
* so it is silly to overwrite itself with nops - reboot is the
* only outcome...
*/
- .byte .Lmemcpy_e - .Lmemcpy_c
- .byte .Lmemcpy_e - .Lmemcpy_c
+ .section .altinstructions, "a"
+ altinstruction_entry memcpy,.Lmemcpy_c,X86_FEATURE_REP_GOOD,\
+ .Lmemcpy_e-.Lmemcpy_c,.Lmemcpy_e-.Lmemcpy_c
+ altinstruction_entry memcpy,.Lmemcpy_c_e,X86_FEATURE_ERMS, \
+ .Lmemcpy_e_e-.Lmemcpy_c_e,.Lmemcpy_e_e-.Lmemcpy_c_e
.previous
diff --git a/arch/x86/lib/memmove_64.S b/arch/x86/lib/memmove_64.S
index 0ecb8433e5a8..d0ec9c2936d7 100644
--- a/arch/x86/lib/memmove_64.S
+++ b/arch/x86/lib/memmove_64.S
@@ -8,6 +8,7 @@
#define _STRING_C
#include <linux/linkage.h>
#include <asm/dwarf2.h>
+#include <asm/cpufeature.h>
#undef memmove
@@ -24,6 +25,7 @@
*/
ENTRY(memmove)
CFI_STARTPROC
+
/* Handle more 32bytes in loop */
mov %rdi, %rax
cmp $0x20, %rdx
@@ -31,8 +33,13 @@ ENTRY(memmove)
/* Decide forward/backward copy mode */
cmp %rdi, %rsi
- jb 2f
+ jge .Lmemmove_begin_forward
+ mov %rsi, %r8
+ add %rdx, %r8
+ cmp %rdi, %r8
+ jg 2f
+.Lmemmove_begin_forward:
/*
* movsq instruction have many startup latency
* so we handle small size by general register.
@@ -78,6 +85,8 @@ ENTRY(memmove)
rep movsq
movq %r11, (%r10)
jmp 13f
+.Lmemmove_end_forward:
+
/*
* Handle data backward by movsq.
*/
@@ -194,4 +203,22 @@ ENTRY(memmove)
13:
retq
CFI_ENDPROC
+
+ .section .altinstr_replacement,"ax"
+.Lmemmove_begin_forward_efs:
+ /* Forward moving data. */
+ movq %rdx, %rcx
+ rep movsb
+ retq
+.Lmemmove_end_forward_efs:
+ .previous
+
+ .section .altinstructions,"a"
+ .align 8
+ .quad .Lmemmove_begin_forward
+ .quad .Lmemmove_begin_forward_efs
+ .word X86_FEATURE_ERMS
+ .byte .Lmemmove_end_forward-.Lmemmove_begin_forward
+ .byte .Lmemmove_end_forward_efs-.Lmemmove_begin_forward_efs
+ .previous
ENDPROC(memmove)
diff --git a/arch/x86/lib/memset_64.S b/arch/x86/lib/memset_64.S
index 09d344269652..79bd454b78a3 100644
--- a/arch/x86/lib/memset_64.S
+++ b/arch/x86/lib/memset_64.S
@@ -2,9 +2,13 @@
#include <linux/linkage.h>
#include <asm/dwarf2.h>
+#include <asm/cpufeature.h>
+#include <asm/alternative-asm.h>
/*
- * ISO C memset - set a memory block to a byte value.
+ * ISO C memset - set a memory block to a byte value. This function uses fast
+ * string to get better performance than the original function. The code is
+ * simpler and shorter than the orignal function as well.
*
* rdi destination
* rsi value (char)
@@ -31,6 +35,28 @@
.Lmemset_e:
.previous
+/*
+ * ISO C memset - set a memory block to a byte value. This function uses
+ * enhanced rep stosb to override the fast string function.
+ * The code is simpler and shorter than the fast string function as well.
+ *
+ * rdi destination
+ * rsi value (char)
+ * rdx count (bytes)
+ *
+ * rax original destination
+ */
+ .section .altinstr_replacement, "ax", @progbits
+.Lmemset_c_e:
+ movq %rdi,%r9
+ movb %sil,%al
+ movl %edx,%ecx
+ rep stosb
+ movq %r9,%rax
+ ret
+.Lmemset_e_e:
+ .previous
+
ENTRY(memset)
ENTRY(__memset)
CFI_STARTPROC
@@ -112,16 +138,20 @@ ENTRY(__memset)
ENDPROC(memset)
ENDPROC(__memset)
- /* Some CPUs run faster using the string instructions.
- It is also a lot simpler. Use this when possible */
-
-#include <asm/cpufeature.h>
-
+ /* Some CPUs support enhanced REP MOVSB/STOSB feature.
+ * It is recommended to use this when possible.
+ *
+ * If enhanced REP MOVSB/STOSB feature is not available, use fast string
+ * instructions.
+ *
+ * Otherwise, use original memset function.
+ *
+ * In .altinstructions section, ERMS feature is placed after REG_GOOD
+ * feature to implement the right patch order.
+ */
.section .altinstructions,"a"
- .align 8
- .quad memset
- .quad .Lmemset_c
- .word X86_FEATURE_REP_GOOD
- .byte .Lfinal - memset
- .byte .Lmemset_e - .Lmemset_c
+ altinstruction_entry memset,.Lmemset_c,X86_FEATURE_REP_GOOD,\
+ .Lfinal-memset,.Lmemset_e-.Lmemset_c
+ altinstruction_entry memset,.Lmemset_c_e,X86_FEATURE_ERMS, \
+ .Lfinal-memset,.Lmemset_e_e-.Lmemset_c_e
.previous
diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile
index 3e608edf9958..3d11327c9ab4 100644
--- a/arch/x86/mm/Makefile
+++ b/arch/x86/mm/Makefile
@@ -23,8 +23,8 @@ mmiotrace-y := kmmio.o pf_in.o mmio-mod.o
obj-$(CONFIG_MMIOTRACE_TEST) += testmmiotrace.o
obj-$(CONFIG_NUMA) += numa.o numa_$(BITS).o
-obj-$(CONFIG_AMD_NUMA) += amdtopology_64.o
-obj-$(CONFIG_ACPI_NUMA) += srat_$(BITS).o
+obj-$(CONFIG_AMD_NUMA) += amdtopology.o
+obj-$(CONFIG_ACPI_NUMA) += srat.o
obj-$(CONFIG_NUMA_EMU) += numa_emulation.o
obj-$(CONFIG_HAVE_MEMBLOCK) += memblock.o
diff --git a/arch/x86/mm/amdtopology_64.c b/arch/x86/mm/amdtopology.c
index 0919c26820d4..5247d01329ca 100644
--- a/arch/x86/mm/amdtopology_64.c
+++ b/arch/x86/mm/amdtopology.c
@@ -12,6 +12,7 @@
#include <linux/module.h>
#include <linux/nodemask.h>
#include <linux/memblock.h>
+#include <linux/bootmem.h>
#include <asm/io.h>
#include <linux/pci_ids.h>
@@ -69,10 +70,10 @@ static __init void early_get_boot_cpu_id(void)
int __init amd_numa_init(void)
{
- unsigned long start = PFN_PHYS(0);
- unsigned long end = PFN_PHYS(max_pfn);
+ u64 start = PFN_PHYS(0);
+ u64 end = PFN_PHYS(max_pfn);
unsigned numnodes;
- unsigned long prevbase;
+ u64 prevbase;
int i, j, nb;
u32 nodeid, reg;
unsigned int bits, cores, apicid_base;
@@ -95,7 +96,7 @@ int __init amd_numa_init(void)
prevbase = 0;
for (i = 0; i < 8; i++) {
- unsigned long base, limit;
+ u64 base, limit;
base = read_pci_config(0, nb, 1, 0x40 + i*8);
limit = read_pci_config(0, nb, 1, 0x44 + i*8);
@@ -107,18 +108,18 @@ int __init amd_numa_init(void)
continue;
}
if (nodeid >= numnodes) {
- pr_info("Ignoring excess node %d (%lx:%lx)\n", nodeid,
+ pr_info("Ignoring excess node %d (%Lx:%Lx)\n", nodeid,
base, limit);
continue;
}
if (!limit) {
- pr_info("Skipping node entry %d (base %lx)\n",
+ pr_info("Skipping node entry %d (base %Lx)\n",
i, base);
continue;
}
if ((base >> 8) & 3 || (limit >> 8) & 3) {
- pr_err("Node %d using interleaving mode %lx/%lx\n",
+ pr_err("Node %d using interleaving mode %Lx/%Lx\n",
nodeid, (base >> 8) & 3, (limit >> 8) & 3);
return -EINVAL;
}
@@ -150,19 +151,19 @@ int __init amd_numa_init(void)
continue;
}
if (limit < base) {
- pr_err("Node %d bogus settings %lx-%lx.\n",
+ pr_err("Node %d bogus settings %Lx-%Lx.\n",
nodeid, base, limit);
continue;
}
/* Could sort here, but pun for now. Should not happen anyroads. */
if (prevbase > base) {
- pr_err("Node map not sorted %lx,%lx\n",
+ pr_err("Node map not sorted %Lx,%Lx\n",
prevbase, base);
return -EINVAL;
}
- pr_info("Node %d MemBase %016lx Limit %016lx\n",
+ pr_info("Node %d MemBase %016Lx Limit %016Lx\n",
nodeid, base, limit);
prevbase = base;
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 20e3f8702d1e..f7a2a054a3c0 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -12,6 +12,7 @@
#include <linux/mmiotrace.h> /* kmmio_handler, ... */
#include <linux/perf_event.h> /* perf_sw_event */
#include <linux/hugetlb.h> /* hstate_index_to_shift */
+#include <linux/prefetch.h> /* prefetchw */
#include <asm/traps.h> /* dotraplinkage, ... */
#include <asm/pgalloc.h> /* pgd_*(), ... */
@@ -964,7 +965,7 @@ do_page_fault(struct pt_regs *regs, unsigned long error_code)
struct mm_struct *mm;
int fault;
int write = error_code & PF_WRITE;
- unsigned int flags = FAULT_FLAG_ALLOW_RETRY |
+ unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
(write ? FAULT_FLAG_WRITE : 0);
tsk = current;
@@ -1138,6 +1139,16 @@ good_area:
}
/*
+ * Pagefault was interrupted by SIGKILL. We have no reason to
+ * continue pagefault.
+ */
+ if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) {
+ if (!(error_code & PF_USER))
+ no_context(regs, error_code, address);
+ return;
+ }
+
+ /*
* Major/minor page fault accounting is only done on the
* initial attempt. If we go through a retry, it is extremely
* likely that the page will be found in page cache at that point.
diff --git a/arch/x86/mm/hugetlbpage.c b/arch/x86/mm/hugetlbpage.c
index d4203988504a..f581a18c0d4d 100644
--- a/arch/x86/mm/hugetlbpage.c
+++ b/arch/x86/mm/hugetlbpage.c
@@ -72,7 +72,7 @@ static void huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud)
if (!vma_shareable(vma, addr))
return;
- spin_lock(&mapping->i_mmap_lock);
+ mutex_lock(&mapping->i_mmap_mutex);
vma_prio_tree_foreach(svma, &iter, &mapping->i_mmap, idx, idx) {
if (svma == vma)
continue;
@@ -97,7 +97,7 @@ static void huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud)
put_page(virt_to_page(spte));
spin_unlock(&mm->page_table_lock);
out:
- spin_unlock(&mapping->i_mmap_lock);
+ mutex_unlock(&mapping->i_mmap_mutex);
}
/*
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index 37b8b0fe8320..30326443ab81 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -16,8 +16,6 @@
#include <asm/tlb.h>
#include <asm/proto.h>
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
unsigned long __initdata pgt_buf_start;
unsigned long __meminitdata pgt_buf_end;
unsigned long __meminitdata pgt_buf_top;
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index 80088f994193..29f7c6d98179 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -678,8 +678,10 @@ static void __init zone_sizes_init(void)
{
unsigned long max_zone_pfns[MAX_NR_ZONES];
memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+#ifdef CONFIG_ZONE_DMA
max_zone_pfns[ZONE_DMA] =
virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+#endif
max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
#ifdef CONFIG_HIGHMEM
max_zone_pfns[ZONE_HIGHMEM] = highend_pfn;
@@ -716,6 +718,7 @@ void __init paging_init(void)
* NOTE: at this point the bootmem allocator is fully available.
*/
olpc_dt_build_devicetree();
+ sparse_memory_present_with_active_regions(MAX_NUMNODES);
sparse_init();
zone_sizes_init();
}
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index 794233587287..d865c4aeec55 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -616,7 +616,9 @@ void __init paging_init(void)
unsigned long max_zone_pfns[MAX_NR_ZONES];
memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+#ifdef CONFIG_ZONE_DMA
max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN;
+#endif
max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN;
max_zone_pfns[ZONE_NORMAL] = max_pfn;
@@ -679,14 +681,6 @@ int arch_add_memory(int nid, u64 start, u64 size)
}
EXPORT_SYMBOL_GPL(arch_add_memory);
-#if !defined(CONFIG_ACPI_NUMA) && defined(CONFIG_NUMA)
-int memory_add_physaddr_to_nid(u64 start)
-{
- return 0;
-}
-EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
-#endif
-
#endif /* CONFIG_MEMORY_HOTPLUG */
static struct kcore_list kcore_vsyscall;
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index 0369843511dc..be1ef574ce9a 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -91,13 +91,6 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
return (__force void __iomem *)phys_to_virt(phys_addr);
/*
- * Check if the request spans more than any BAR in the iomem resource
- * tree.
- */
- WARN_ONCE(iomem_map_sanity_check(phys_addr, size),
- KERN_INFO "Info: mapping multiple BARs. Your kernel is fine.");
-
- /*
* Don't allow anybody to remap normal RAM that we're using..
*/
last_pfn = last_addr >> PAGE_SHIFT;
@@ -170,6 +163,13 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
ret_addr = (void __iomem *) (vaddr + offset);
mmiotrace_ioremap(unaligned_phys_addr, unaligned_size, ret_addr);
+ /*
+ * Check if the request spans more than any BAR in the iomem resource
+ * tree.
+ */
+ WARN_ONCE(iomem_map_sanity_check(unaligned_phys_addr, unaligned_size),
+ KERN_INFO "Info: mapping multiple BARs. Your kernel is fine.");
+
return ret_addr;
err_free_area:
free_vm_area(area);
diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c
index 745258dfc4dc..f5510d889a22 100644
--- a/arch/x86/mm/numa.c
+++ b/arch/x86/mm/numa.c
@@ -1,11 +1,39 @@
/* Common code for 32 and 64-bit NUMA */
-#include <linux/topology.h>
-#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/init.h>
#include <linux/bootmem.h>
-#include <asm/numa.h>
+#include <linux/memblock.h>
+#include <linux/mmzone.h>
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/nodemask.h>
+#include <linux/sched.h>
+#include <linux/topology.h>
+
+#include <asm/e820.h>
+#include <asm/proto.h>
+#include <asm/dma.h>
#include <asm/acpi.h>
+#include <asm/amd_nb.h>
+
+#include "numa_internal.h"
int __initdata numa_off;
+nodemask_t numa_nodes_parsed __initdata;
+
+struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
+EXPORT_SYMBOL(node_data);
+
+static struct numa_meminfo numa_meminfo
+#ifndef CONFIG_MEMORY_HOTPLUG
+__initdata
+#endif
+;
+
+static int numa_distance_cnt;
+static u8 *numa_distance;
static __init int numa_setup(char *opt)
{
@@ -32,6 +60,15 @@ s16 __apicid_to_node[MAX_LOCAL_APIC] __cpuinitdata = {
[0 ... MAX_LOCAL_APIC-1] = NUMA_NO_NODE
};
+int __cpuinit numa_cpu_node(int cpu)
+{
+ int apicid = early_per_cpu(x86_cpu_to_apicid, cpu);
+
+ if (apicid != BAD_APICID)
+ return __apicid_to_node[apicid];
+ return NUMA_NO_NODE;
+}
+
cpumask_var_t node_to_cpumask_map[MAX_NUMNODES];
EXPORT_SYMBOL(node_to_cpumask_map);
@@ -95,6 +132,407 @@ void __init setup_node_to_cpumask_map(void)
pr_debug("Node to cpumask map for %d nodes\n", nr_node_ids);
}
+static int __init numa_add_memblk_to(int nid, u64 start, u64 end,
+ struct numa_meminfo *mi)
+{
+ /* ignore zero length blks */
+ if (start == end)
+ return 0;
+
+ /* whine about and ignore invalid blks */
+ if (start > end || nid < 0 || nid >= MAX_NUMNODES) {
+ pr_warning("NUMA: Warning: invalid memblk node %d (%Lx-%Lx)\n",
+ nid, start, end);
+ return 0;
+ }
+
+ if (mi->nr_blks >= NR_NODE_MEMBLKS) {
+ pr_err("NUMA: too many memblk ranges\n");
+ return -EINVAL;
+ }
+
+ mi->blk[mi->nr_blks].start = start;
+ mi->blk[mi->nr_blks].end = end;
+ mi->blk[mi->nr_blks].nid = nid;
+ mi->nr_blks++;
+ return 0;
+}
+
+/**
+ * numa_remove_memblk_from - Remove one numa_memblk from a numa_meminfo
+ * @idx: Index of memblk to remove
+ * @mi: numa_meminfo to remove memblk from
+ *
+ * Remove @idx'th numa_memblk from @mi by shifting @mi->blk[] and
+ * decrementing @mi->nr_blks.
+ */
+void __init numa_remove_memblk_from(int idx, struct numa_meminfo *mi)
+{
+ mi->nr_blks--;
+ memmove(&mi->blk[idx], &mi->blk[idx + 1],
+ (mi->nr_blks - idx) * sizeof(mi->blk[0]));
+}
+
+/**
+ * numa_add_memblk - Add one numa_memblk to numa_meminfo
+ * @nid: NUMA node ID of the new memblk
+ * @start: Start address of the new memblk
+ * @end: End address of the new memblk
+ *
+ * Add a new memblk to the default numa_meminfo.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int __init numa_add_memblk(int nid, u64 start, u64 end)
+{
+ return numa_add_memblk_to(nid, start, end, &numa_meminfo);
+}
+
+/* Initialize NODE_DATA for a node on the local memory */
+static void __init setup_node_data(int nid, u64 start, u64 end)
+{
+ const u64 nd_low = PFN_PHYS(MAX_DMA_PFN);
+ const u64 nd_high = PFN_PHYS(max_pfn_mapped);
+ const size_t nd_size = roundup(sizeof(pg_data_t), PAGE_SIZE);
+ bool remapped = false;
+ u64 nd_pa;
+ void *nd;
+ int tnid;
+
+ /*
+ * Don't confuse VM with a node that doesn't have the
+ * minimum amount of memory:
+ */
+ if (end && (end - start) < NODE_MIN_SIZE)
+ return;
+
+ /* initialize remap allocator before aligning to ZONE_ALIGN */
+ init_alloc_remap(nid, start, end);
+
+ start = roundup(start, ZONE_ALIGN);
+
+ printk(KERN_INFO "Initmem setup node %d %016Lx-%016Lx\n",
+ nid, start, end);
+
+ /*
+ * Allocate node data. Try remap allocator first, node-local
+ * memory and then any node. Never allocate in DMA zone.
+ */
+ nd = alloc_remap(nid, nd_size);
+ if (nd) {
+ nd_pa = __pa(nd);
+ remapped = true;
+ } else {
+ nd_pa = memblock_x86_find_in_range_node(nid, nd_low, nd_high,
+ nd_size, SMP_CACHE_BYTES);
+ if (nd_pa == MEMBLOCK_ERROR)
+ nd_pa = memblock_find_in_range(nd_low, nd_high,
+ nd_size, SMP_CACHE_BYTES);
+ if (nd_pa == MEMBLOCK_ERROR) {
+ pr_err("Cannot find %zu bytes in node %d\n",
+ nd_size, nid);
+ return;
+ }
+ memblock_x86_reserve_range(nd_pa, nd_pa + nd_size, "NODE_DATA");
+ nd = __va(nd_pa);
+ }
+
+ /* report and initialize */
+ printk(KERN_INFO " NODE_DATA [%016Lx - %016Lx]%s\n",
+ nd_pa, nd_pa + nd_size - 1, remapped ? " (remapped)" : "");
+ tnid = early_pfn_to_nid(nd_pa >> PAGE_SHIFT);
+ if (!remapped && tnid != nid)
+ printk(KERN_INFO " NODE_DATA(%d) on node %d\n", nid, tnid);
+
+ node_data[nid] = nd;
+ memset(NODE_DATA(nid), 0, sizeof(pg_data_t));
+ NODE_DATA(nid)->node_id = nid;
+ NODE_DATA(nid)->node_start_pfn = start >> PAGE_SHIFT;
+ NODE_DATA(nid)->node_spanned_pages = (end - start) >> PAGE_SHIFT;
+
+ node_set_online(nid);
+}
+
+/**
+ * numa_cleanup_meminfo - Cleanup a numa_meminfo
+ * @mi: numa_meminfo to clean up
+ *
+ * Sanitize @mi by merging and removing unncessary memblks. Also check for
+ * conflicts and clear unused memblks.
+ *
+ * RETURNS:
+ * 0 on success, -errno on failure.
+ */
+int __init numa_cleanup_meminfo(struct numa_meminfo *mi)
+{
+ const u64 low = 0;
+ const u64 high = PFN_PHYS(max_pfn);
+ int i, j, k;
+
+ /* first, trim all entries */
+ for (i = 0; i < mi->nr_blks; i++) {
+ struct numa_memblk *bi = &mi->blk[i];
+
+ /* make sure all blocks are inside the limits */
+ bi->start = max(bi->start, low);
+ bi->end = min(bi->end, high);
+
+ /* and there's no empty block */
+ if (bi->start >= bi->end)
+ numa_remove_memblk_from(i--, mi);
+ }
+
+ /* merge neighboring / overlapping entries */
+ for (i = 0; i < mi->nr_blks; i++) {
+ struct numa_memblk *bi = &mi->blk[i];
+
+ for (j = i + 1; j < mi->nr_blks; j++) {
+ struct numa_memblk *bj = &mi->blk[j];
+ u64 start, end;
+
+ /*
+ * See whether there are overlapping blocks. Whine
+ * about but allow overlaps of the same nid. They
+ * will be merged below.
+ */
+ if (bi->end > bj->start && bi->start < bj->end) {
+ if (bi->nid != bj->nid) {
+ pr_err("NUMA: node %d (%Lx-%Lx) overlaps with node %d (%Lx-%Lx)\n",
+ bi->nid, bi->start, bi->end,
+ bj->nid, bj->start, bj->end);
+ return -EINVAL;
+ }
+ pr_warning("NUMA: Warning: node %d (%Lx-%Lx) overlaps with itself (%Lx-%Lx)\n",
+ bi->nid, bi->start, bi->end,
+ bj->start, bj->end);
+ }
+
+ /*
+ * Join together blocks on the same node, holes
+ * between which don't overlap with memory on other
+ * nodes.
+ */
+ if (bi->nid != bj->nid)
+ continue;
+ start = min(bi->start, bj->start);
+ end = max(bi->end, bj->end);
+ for (k = 0; k < mi->nr_blks; k++) {
+ struct numa_memblk *bk = &mi->blk[k];
+
+ if (bi->nid == bk->nid)
+ continue;
+ if (start < bk->end && end > bk->start)
+ break;
+ }
+ if (k < mi->nr_blks)
+ continue;
+ printk(KERN_INFO "NUMA: Node %d [%Lx,%Lx) + [%Lx,%Lx) -> [%Lx,%Lx)\n",
+ bi->nid, bi->start, bi->end, bj->start, bj->end,
+ start, end);
+ bi->start = start;
+ bi->end = end;
+ numa_remove_memblk_from(j--, mi);
+ }
+ }
+
+ /* clear unused ones */
+ for (i = mi->nr_blks; i < ARRAY_SIZE(mi->blk); i++) {
+ mi->blk[i].start = mi->blk[i].end = 0;
+ mi->blk[i].nid = NUMA_NO_NODE;
+ }
+
+ return 0;
+}
+
+/*
+ * Set nodes, which have memory in @mi, in *@nodemask.
+ */
+static void __init numa_nodemask_from_meminfo(nodemask_t *nodemask,
+ const struct numa_meminfo *mi)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mi->blk); i++)
+ if (mi->blk[i].start != mi->blk[i].end &&
+ mi->blk[i].nid != NUMA_NO_NODE)
+ node_set(mi->blk[i].nid, *nodemask);
+}
+
+/**
+ * numa_reset_distance - Reset NUMA distance table
+ *
+ * The current table is freed. The next numa_set_distance() call will
+ * create a new one.
+ */
+void __init numa_reset_distance(void)
+{
+ size_t size = numa_distance_cnt * numa_distance_cnt * sizeof(numa_distance[0]);
+
+ /* numa_distance could be 1LU marking allocation failure, test cnt */
+ if (numa_distance_cnt)
+ memblock_x86_free_range(__pa(numa_distance),
+ __pa(numa_distance) + size);
+ numa_distance_cnt = 0;
+ numa_distance = NULL; /* enable table creation */
+}
+
+static int __init numa_alloc_distance(void)
+{
+ nodemask_t nodes_parsed;
+ size_t size;
+ int i, j, cnt = 0;
+ u64 phys;
+
+ /* size the new table and allocate it */
+ nodes_parsed = numa_nodes_parsed;
+ numa_nodemask_from_meminfo(&nodes_parsed, &numa_meminfo);
+
+ for_each_node_mask(i, nodes_parsed)
+ cnt = i;
+ cnt++;
+ size = cnt * cnt * sizeof(numa_distance[0]);
+
+ phys = memblock_find_in_range(0, PFN_PHYS(max_pfn_mapped),
+ size, PAGE_SIZE);
+ if (phys == MEMBLOCK_ERROR) {
+ pr_warning("NUMA: Warning: can't allocate distance table!\n");
+ /* don't retry until explicitly reset */
+ numa_distance = (void *)1LU;
+ return -ENOMEM;
+ }
+ memblock_x86_reserve_range(phys, phys + size, "NUMA DIST");
+
+ numa_distance = __va(phys);
+ numa_distance_cnt = cnt;
+
+ /* fill with the default distances */
+ for (i = 0; i < cnt; i++)
+ for (j = 0; j < cnt; j++)
+ numa_distance[i * cnt + j] = i == j ?
+ LOCAL_DISTANCE : REMOTE_DISTANCE;
+ printk(KERN_DEBUG "NUMA: Initialized distance table, cnt=%d\n", cnt);
+
+ return 0;
+}
+
+/**
+ * numa_set_distance - Set NUMA distance from one NUMA to another
+ * @from: the 'from' node to set distance
+ * @to: the 'to' node to set distance
+ * @distance: NUMA distance
+ *
+ * Set the distance from node @from to @to to @distance. If distance table
+ * doesn't exist, one which is large enough to accommodate all the currently
+ * known nodes will be created.
+ *
+ * If such table cannot be allocated, a warning is printed and further
+ * calls are ignored until the distance table is reset with
+ * numa_reset_distance().
+ *
+ * If @from or @to is higher than the highest known node at the time of
+ * table creation or @distance doesn't make sense, the call is ignored.
+ * This is to allow simplification of specific NUMA config implementations.
+ */
+void __init numa_set_distance(int from, int to, int distance)
+{
+ if (!numa_distance && numa_alloc_distance() < 0)
+ return;
+
+ if (from >= numa_distance_cnt || to >= numa_distance_cnt) {
+ printk_once(KERN_DEBUG "NUMA: Debug: distance out of bound, from=%d to=%d distance=%d\n",
+ from, to, distance);
+ return;
+ }
+
+ if ((u8)distance != distance ||
+ (from == to && distance != LOCAL_DISTANCE)) {
+ pr_warn_once("NUMA: Warning: invalid distance parameter, from=%d to=%d distance=%d\n",
+ from, to, distance);
+ return;
+ }
+
+ numa_distance[from * numa_distance_cnt + to] = distance;
+}
+
+int __node_distance(int from, int to)
+{
+ if (from >= numa_distance_cnt || to >= numa_distance_cnt)
+ return from == to ? LOCAL_DISTANCE : REMOTE_DISTANCE;
+ return numa_distance[from * numa_distance_cnt + to];
+}
+EXPORT_SYMBOL(__node_distance);
+
+/*
+ * Sanity check to catch more bad NUMA configurations (they are amazingly
+ * common). Make sure the nodes cover all memory.
+ */
+static bool __init numa_meminfo_cover_memory(const struct numa_meminfo *mi)
+{
+ u64 numaram, e820ram;
+ int i;
+
+ numaram = 0;
+ for (i = 0; i < mi->nr_blks; i++) {
+ u64 s = mi->blk[i].start >> PAGE_SHIFT;
+ u64 e = mi->blk[i].end >> PAGE_SHIFT;
+ numaram += e - s;
+ numaram -= __absent_pages_in_range(mi->blk[i].nid, s, e);
+ if ((s64)numaram < 0)
+ numaram = 0;
+ }
+
+ e820ram = max_pfn - (memblock_x86_hole_size(0,
+ PFN_PHYS(max_pfn)) >> PAGE_SHIFT);
+ /* We seem to lose 3 pages somewhere. Allow 1M of slack. */
+ if ((s64)(e820ram - numaram) >= (1 << (20 - PAGE_SHIFT))) {
+ printk(KERN_ERR "NUMA: nodes only cover %LuMB of your %LuMB e820 RAM. Not used.\n",
+ (numaram << PAGE_SHIFT) >> 20,
+ (e820ram << PAGE_SHIFT) >> 20);
+ return false;
+ }
+ return true;
+}
+
+static int __init numa_register_memblks(struct numa_meminfo *mi)
+{
+ int i, nid;
+
+ /* Account for nodes with cpus and no memory */
+ node_possible_map = numa_nodes_parsed;
+ numa_nodemask_from_meminfo(&node_possible_map, mi);
+ if (WARN_ON(nodes_empty(node_possible_map)))
+ return -EINVAL;
+
+ for (i = 0; i < mi->nr_blks; i++)
+ memblock_x86_register_active_regions(mi->blk[i].nid,
+ mi->blk[i].start >> PAGE_SHIFT,
+ mi->blk[i].end >> PAGE_SHIFT);
+
+ /* for out of order entries */
+ sort_node_map();
+ if (!numa_meminfo_cover_memory(mi))
+ return -EINVAL;
+
+ /* Finally register nodes. */
+ for_each_node_mask(nid, node_possible_map) {
+ u64 start = PFN_PHYS(max_pfn);
+ u64 end = 0;
+
+ for (i = 0; i < mi->nr_blks; i++) {
+ if (nid != mi->blk[i].nid)
+ continue;
+ start = min(mi->blk[i].start, start);
+ end = max(mi->blk[i].end, end);
+ }
+
+ if (start < end)
+ setup_node_data(nid, start, end);
+ }
+
+ return 0;
+}
+
/*
* There are unfortunately some poorly designed mainboards around that
* only connect memory to a single CPU. This breaks the 1:1 cpu->node
@@ -102,7 +540,7 @@ void __init setup_node_to_cpumask_map(void)
* as the number of CPUs is not known yet. We round robin the existing
* nodes.
*/
-void __init numa_init_array(void)
+static void __init numa_init_array(void)
{
int rr, i;
@@ -117,6 +555,95 @@ void __init numa_init_array(void)
}
}
+static int __init numa_init(int (*init_func)(void))
+{
+ int i;
+ int ret;
+
+ for (i = 0; i < MAX_LOCAL_APIC; i++)
+ set_apicid_to_node(i, NUMA_NO_NODE);
+
+ nodes_clear(numa_nodes_parsed);
+ nodes_clear(node_possible_map);
+ nodes_clear(node_online_map);
+ memset(&numa_meminfo, 0, sizeof(numa_meminfo));
+ remove_all_active_ranges();
+ numa_reset_distance();
+
+ ret = init_func();
+ if (ret < 0)
+ return ret;
+ ret = numa_cleanup_meminfo(&numa_meminfo);
+ if (ret < 0)
+ return ret;
+
+ numa_emulation(&numa_meminfo, numa_distance_cnt);
+
+ ret = numa_register_memblks(&numa_meminfo);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < nr_cpu_ids; i++) {
+ int nid = early_cpu_to_node(i);
+
+ if (nid == NUMA_NO_NODE)
+ continue;
+ if (!node_online(nid))
+ numa_clear_node(i);
+ }
+ numa_init_array();
+ return 0;
+}
+
+/**
+ * dummy_numa_init - Fallback dummy NUMA init
+ *
+ * Used if there's no underlying NUMA architecture, NUMA initialization
+ * fails, or NUMA is disabled on the command line.
+ *
+ * Must online at least one node and add memory blocks that cover all
+ * allowed memory. This function must not fail.
+ */
+static int __init dummy_numa_init(void)
+{
+ printk(KERN_INFO "%s\n",
+ numa_off ? "NUMA turned off" : "No NUMA configuration found");
+ printk(KERN_INFO "Faking a node at %016Lx-%016Lx\n",
+ 0LLU, PFN_PHYS(max_pfn));
+
+ node_set(0, numa_nodes_parsed);
+ numa_add_memblk(0, 0, PFN_PHYS(max_pfn));
+
+ return 0;
+}
+
+/**
+ * x86_numa_init - Initialize NUMA
+ *
+ * Try each configured NUMA initialization method until one succeeds. The
+ * last fallback is dummy single node config encomapssing whole memory and
+ * never fails.
+ */
+void __init x86_numa_init(void)
+{
+ if (!numa_off) {
+#ifdef CONFIG_X86_NUMAQ
+ if (!numa_init(numaq_numa_init))
+ return;
+#endif
+#ifdef CONFIG_ACPI_NUMA
+ if (!numa_init(x86_acpi_numa_init))
+ return;
+#endif
+#ifdef CONFIG_AMD_NUMA
+ if (!numa_init(amd_numa_init))
+ return;
+#endif
+ }
+
+ numa_init(dummy_numa_init);
+}
+
static __init int find_near_online_node(int node)
{
int n, val;
@@ -282,3 +809,18 @@ const struct cpumask *cpumask_of_node(int node)
EXPORT_SYMBOL(cpumask_of_node);
#endif /* !CONFIG_DEBUG_PER_CPU_MAPS */
+
+#ifdef CONFIG_MEMORY_HOTPLUG
+int memory_add_physaddr_to_nid(u64 start)
+{
+ struct numa_meminfo *mi = &numa_meminfo;
+ int nid = mi->blk[0].nid;
+ int i;
+
+ for (i = 0; i < mi->nr_blks; i++)
+ if (mi->blk[i].start <= start && mi->blk[i].end > start)
+ nid = mi->blk[i].nid;
+ return nid;
+}
+EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
+#endif
diff --git a/arch/x86/mm/numa_32.c b/arch/x86/mm/numa_32.c
index bde3906420df..849a975d3fa0 100644
--- a/arch/x86/mm/numa_32.c
+++ b/arch/x86/mm/numa_32.c
@@ -22,39 +22,11 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/mm.h>
#include <linux/bootmem.h>
#include <linux/memblock.h>
-#include <linux/mmzone.h>
-#include <linux/highmem.h>
-#include <linux/initrd.h>
-#include <linux/nodemask.h>
#include <linux/module.h>
-#include <linux/kexec.h>
-#include <linux/pfn.h>
-#include <linux/swap.h>
-#include <linux/acpi.h>
-
-#include <asm/e820.h>
-#include <asm/setup.h>
-#include <asm/mmzone.h>
-#include <asm/bios_ebda.h>
-#include <asm/proto.h>
-
-struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
-EXPORT_SYMBOL(node_data);
-
-/*
- * numa interface - we expect the numa architecture specific code to have
- * populated the following initialisation.
- *
- * 1) node_online_map - the map of all nodes configured (online) in the system
- * 2) node_start_pfn - the starting page frame number for a node
- * 3) node_end_pfn - the ending page fram number for a node
- */
-unsigned long node_start_pfn[MAX_NUMNODES] __read_mostly;
-unsigned long node_end_pfn[MAX_NUMNODES] __read_mostly;
+#include "numa_internal.h"
#ifdef CONFIG_DISCONTIGMEM
/*
@@ -99,108 +71,46 @@ unsigned long node_memmap_size_bytes(int nid, unsigned long start_pfn,
}
#endif
-extern unsigned long find_max_low_pfn(void);
extern unsigned long highend_pfn, highstart_pfn;
#define LARGE_PAGE_BYTES (PTRS_PER_PTE * PAGE_SIZE)
-unsigned long node_remap_size[MAX_NUMNODES];
static void *node_remap_start_vaddr[MAX_NUMNODES];
void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);
-static unsigned long kva_start_pfn;
-static unsigned long kva_pages;
-
-int __cpuinit numa_cpu_node(int cpu)
-{
- return apic->x86_32_numa_cpu_node(cpu);
-}
-
-/*
- * FLAT - support for basic PC memory model with discontig enabled, essentially
- * a single node with all available processors in it with a flat
- * memory map.
- */
-int __init get_memcfg_numa_flat(void)
-{
- printk(KERN_DEBUG "NUMA - single node, flat memory mode\n");
-
- node_start_pfn[0] = 0;
- node_end_pfn[0] = max_pfn;
- memblock_x86_register_active_regions(0, 0, max_pfn);
- memory_present(0, 0, max_pfn);
- node_remap_size[0] = node_memmap_size_bytes(0, 0, max_pfn);
-
- /* Indicate there is one node available. */
- nodes_clear(node_online_map);
- node_set_online(0);
- return 1;
-}
-
-/*
- * Find the highest page frame number we have available for the node
- */
-static void __init propagate_e820_map_node(int nid)
-{
- if (node_end_pfn[nid] > max_pfn)
- node_end_pfn[nid] = max_pfn;
- /*
- * if a user has given mem=XXXX, then we need to make sure
- * that the node _starts_ before that, too, not just ends
- */
- if (node_start_pfn[nid] > max_pfn)
- node_start_pfn[nid] = max_pfn;
- BUG_ON(node_start_pfn[nid] > node_end_pfn[nid]);
-}
-
-/*
- * Allocate memory for the pg_data_t for this node via a crude pre-bootmem
- * method. For node zero take this from the bottom of memory, for
- * subsequent nodes place them at node_remap_start_vaddr which contains
- * node local data in physically node local memory. See setup_memory()
- * for details.
- */
-static void __init allocate_pgdat(int nid)
-{
- char buf[16];
-
- if (node_has_online_mem(nid) && node_remap_start_vaddr[nid])
- NODE_DATA(nid) = (pg_data_t *)node_remap_start_vaddr[nid];
- else {
- unsigned long pgdat_phys;
- pgdat_phys = memblock_find_in_range(min_low_pfn<<PAGE_SHIFT,
- max_pfn_mapped<<PAGE_SHIFT,
- sizeof(pg_data_t),
- PAGE_SIZE);
- NODE_DATA(nid) = (pg_data_t *)(pfn_to_kaddr(pgdat_phys>>PAGE_SHIFT));
- memset(buf, 0, sizeof(buf));
- sprintf(buf, "NODE_DATA %d", nid);
- memblock_x86_reserve_range(pgdat_phys, pgdat_phys + sizeof(pg_data_t), buf);
- }
- printk(KERN_DEBUG "allocate_pgdat: node %d NODE_DATA %08lx\n",
- nid, (unsigned long)NODE_DATA(nid));
-}
-
/*
- * In the DISCONTIGMEM and SPARSEMEM memory model, a portion of the kernel
- * virtual address space (KVA) is reserved and portions of nodes are mapped
- * using it. This is to allow node-local memory to be allocated for
- * structures that would normally require ZONE_NORMAL. The memory is
- * allocated with alloc_remap() and callers should be prepared to allocate
- * from the bootmem allocator instead.
+ * Remap memory allocator
*/
static unsigned long node_remap_start_pfn[MAX_NUMNODES];
static void *node_remap_end_vaddr[MAX_NUMNODES];
static void *node_remap_alloc_vaddr[MAX_NUMNODES];
-static unsigned long node_remap_offset[MAX_NUMNODES];
+/**
+ * alloc_remap - Allocate remapped memory
+ * @nid: NUMA node to allocate memory from
+ * @size: The size of allocation
+ *
+ * Allocate @size bytes from the remap area of NUMA node @nid. The
+ * size of the remap area is predetermined by init_alloc_remap() and
+ * only the callers considered there should call this function. For
+ * more info, please read the comment on top of init_alloc_remap().
+ *
+ * The caller must be ready to handle allocation failure from this
+ * function and fall back to regular memory allocator in such cases.
+ *
+ * CONTEXT:
+ * Single CPU early boot context.
+ *
+ * RETURNS:
+ * Pointer to the allocated memory on success, %NULL on failure.
+ */
void *alloc_remap(int nid, unsigned long size)
{
void *allocation = node_remap_alloc_vaddr[nid];
size = ALIGN(size, L1_CACHE_BYTES);
- if (!allocation || (allocation + size) >= node_remap_end_vaddr[nid])
+ if (!allocation || (allocation + size) > node_remap_end_vaddr[nid])
return NULL;
node_remap_alloc_vaddr[nid] += size;
@@ -209,26 +119,6 @@ void *alloc_remap(int nid, unsigned long size)
return allocation;
}
-static void __init remap_numa_kva(void)
-{
- void *vaddr;
- unsigned long pfn;
- int node;
-
- for_each_online_node(node) {
- printk(KERN_DEBUG "remap_numa_kva: node %d\n", node);
- for (pfn=0; pfn < node_remap_size[node]; pfn += PTRS_PER_PTE) {
- vaddr = node_remap_start_vaddr[node]+(pfn<<PAGE_SHIFT);
- printk(KERN_DEBUG "remap_numa_kva: %08lx to pfn %08lx\n",
- (unsigned long)vaddr,
- node_remap_start_pfn[node] + pfn);
- set_pmd_pfn((ulong) vaddr,
- node_remap_start_pfn[node] + pfn,
- PAGE_KERNEL_LARGE);
- }
- }
-}
-
#ifdef CONFIG_HIBERNATION
/**
* resume_map_numa_kva - add KVA mapping to the temporary page tables created
@@ -240,15 +130,16 @@ void resume_map_numa_kva(pgd_t *pgd_base)
int node;
for_each_online_node(node) {
- unsigned long start_va, start_pfn, size, pfn;
+ unsigned long start_va, start_pfn, nr_pages, pfn;
start_va = (unsigned long)node_remap_start_vaddr[node];
start_pfn = node_remap_start_pfn[node];
- size = node_remap_size[node];
+ nr_pages = (node_remap_end_vaddr[node] -
+ node_remap_start_vaddr[node]) >> PAGE_SHIFT;
printk(KERN_DEBUG "%s: node %d\n", __func__, node);
- for (pfn = 0; pfn < size; pfn += PTRS_PER_PTE) {
+ for (pfn = 0; pfn < nr_pages; pfn += PTRS_PER_PTE) {
unsigned long vaddr = start_va + (pfn << PAGE_SHIFT);
pgd_t *pgd = pgd_base + pgd_index(vaddr);
pud_t *pud = pud_offset(pgd, vaddr);
@@ -264,132 +155,89 @@ void resume_map_numa_kva(pgd_t *pgd_base)
}
#endif
-static __init unsigned long calculate_numa_remap_pages(void)
+/**
+ * init_alloc_remap - Initialize remap allocator for a NUMA node
+ * @nid: NUMA node to initizlie remap allocator for
+ *
+ * NUMA nodes may end up without any lowmem. As allocating pgdat and
+ * memmap on a different node with lowmem is inefficient, a special
+ * remap allocator is implemented which can be used by alloc_remap().
+ *
+ * For each node, the amount of memory which will be necessary for
+ * pgdat and memmap is calculated and two memory areas of the size are
+ * allocated - one in the node and the other in lowmem; then, the area
+ * in the node is remapped to the lowmem area.
+ *
+ * As pgdat and memmap must be allocated in lowmem anyway, this
+ * doesn't waste lowmem address space; however, the actual lowmem
+ * which gets remapped over is wasted. The amount shouldn't be
+ * problematic on machines this feature will be used.
+ *
+ * Initialization failure isn't fatal. alloc_remap() is used
+ * opportunistically and the callers will fall back to other memory
+ * allocation mechanisms on failure.
+ */
+void __init init_alloc_remap(int nid, u64 start, u64 end)
{
- int nid;
- unsigned long size, reserve_pages = 0;
-
- for_each_online_node(nid) {
- u64 node_kva_target;
- u64 node_kva_final;
-
- /*
- * The acpi/srat node info can show hot-add memroy zones
- * where memory could be added but not currently present.
- */
- printk(KERN_DEBUG "node %d pfn: [%lx - %lx]\n",
- nid, node_start_pfn[nid], node_end_pfn[nid]);
- if (node_start_pfn[nid] > max_pfn)
- continue;
- if (!node_end_pfn[nid])
- continue;
- if (node_end_pfn[nid] > max_pfn)
- node_end_pfn[nid] = max_pfn;
-
- /* ensure the remap includes space for the pgdat. */
- size = node_remap_size[nid] + sizeof(pg_data_t);
-
- /* convert size to large (pmd size) pages, rounding up */
- size = (size + LARGE_PAGE_BYTES - 1) / LARGE_PAGE_BYTES;
- /* now the roundup is correct, convert to PAGE_SIZE pages */
- size = size * PTRS_PER_PTE;
-
- node_kva_target = round_down(node_end_pfn[nid] - size,
- PTRS_PER_PTE);
- node_kva_target <<= PAGE_SHIFT;
- do {
- node_kva_final = memblock_find_in_range(node_kva_target,
- ((u64)node_end_pfn[nid])<<PAGE_SHIFT,
- ((u64)size)<<PAGE_SHIFT,
- LARGE_PAGE_BYTES);
- node_kva_target -= LARGE_PAGE_BYTES;
- } while (node_kva_final == MEMBLOCK_ERROR &&
- (node_kva_target>>PAGE_SHIFT) > (node_start_pfn[nid]));
-
- if (node_kva_final == MEMBLOCK_ERROR)
- panic("Can not get kva ram\n");
-
- node_remap_size[nid] = size;
- node_remap_offset[nid] = reserve_pages;
- reserve_pages += size;
- printk(KERN_DEBUG "Reserving %ld pages of KVA for lmem_map of"
- " node %d at %llx\n",
- size, nid, node_kva_final>>PAGE_SHIFT);
-
- /*
- * prevent kva address below max_low_pfn want it on system
- * with less memory later.
- * layout will be: KVA address , KVA RAM
- *
- * we are supposed to only record the one less then max_low_pfn
- * but we could have some hole in high memory, and it will only
- * check page_is_ram(pfn) && !page_is_reserved_early(pfn) to decide
- * to use it as free.
- * So memblock_x86_reserve_range here, hope we don't run out of that array
- */
- memblock_x86_reserve_range(node_kva_final,
- node_kva_final+(((u64)size)<<PAGE_SHIFT),
- "KVA RAM");
-
- node_remap_start_pfn[nid] = node_kva_final>>PAGE_SHIFT;
- }
- printk(KERN_INFO "Reserving total of %lx pages for numa KVA remap\n",
- reserve_pages);
- return reserve_pages;
-}
+ unsigned long start_pfn = start >> PAGE_SHIFT;
+ unsigned long end_pfn = end >> PAGE_SHIFT;
+ unsigned long size, pfn;
+ u64 node_pa, remap_pa;
+ void *remap_va;
-static void init_remap_allocator(int nid)
-{
- node_remap_start_vaddr[nid] = pfn_to_kaddr(
- kva_start_pfn + node_remap_offset[nid]);
- node_remap_end_vaddr[nid] = node_remap_start_vaddr[nid] +
- (node_remap_size[nid] * PAGE_SIZE);
- node_remap_alloc_vaddr[nid] = node_remap_start_vaddr[nid] +
- ALIGN(sizeof(pg_data_t), PAGE_SIZE);
-
- printk(KERN_DEBUG "node %d will remap to vaddr %08lx - %08lx\n", nid,
- (ulong) node_remap_start_vaddr[nid],
- (ulong) node_remap_end_vaddr[nid]);
+ /*
+ * The acpi/srat node info can show hot-add memroy zones where
+ * memory could be added but not currently present.
+ */
+ printk(KERN_DEBUG "node %d pfn: [%lx - %lx]\n",
+ nid, start_pfn, end_pfn);
+
+ /* calculate the necessary space aligned to large page size */
+ size = node_memmap_size_bytes(nid, start_pfn, end_pfn);
+ size += ALIGN(sizeof(pg_data_t), PAGE_SIZE);
+ size = ALIGN(size, LARGE_PAGE_BYTES);
+
+ /* allocate node memory and the lowmem remap area */
+ node_pa = memblock_find_in_range(start, end, size, LARGE_PAGE_BYTES);
+ if (node_pa == MEMBLOCK_ERROR) {
+ pr_warning("remap_alloc: failed to allocate %lu bytes for node %d\n",
+ size, nid);
+ return;
+ }
+ memblock_x86_reserve_range(node_pa, node_pa + size, "KVA RAM");
+
+ remap_pa = memblock_find_in_range(min_low_pfn << PAGE_SHIFT,
+ max_low_pfn << PAGE_SHIFT,
+ size, LARGE_PAGE_BYTES);
+ if (remap_pa == MEMBLOCK_ERROR) {
+ pr_warning("remap_alloc: failed to allocate %lu bytes remap area for node %d\n",
+ size, nid);
+ memblock_x86_free_range(node_pa, node_pa + size);
+ return;
+ }
+ memblock_x86_reserve_range(remap_pa, remap_pa + size, "KVA PG");
+ remap_va = phys_to_virt(remap_pa);
+
+ /* perform actual remap */
+ for (pfn = 0; pfn < size >> PAGE_SHIFT; pfn += PTRS_PER_PTE)
+ set_pmd_pfn((unsigned long)remap_va + (pfn << PAGE_SHIFT),
+ (node_pa >> PAGE_SHIFT) + pfn,
+ PAGE_KERNEL_LARGE);
+
+ /* initialize remap allocator parameters */
+ node_remap_start_pfn[nid] = node_pa >> PAGE_SHIFT;
+ node_remap_start_vaddr[nid] = remap_va;
+ node_remap_end_vaddr[nid] = remap_va + size;
+ node_remap_alloc_vaddr[nid] = remap_va;
+
+ printk(KERN_DEBUG "remap_alloc: node %d [%08llx-%08llx) -> [%p-%p)\n",
+ nid, node_pa, node_pa + size, remap_va, remap_va + size);
}
void __init initmem_init(void)
{
- int nid;
- long kva_target_pfn;
-
- /*
- * When mapping a NUMA machine we allocate the node_mem_map arrays
- * from node local memory. They are then mapped directly into KVA
- * between zone normal and vmalloc space. Calculate the size of
- * this space and use it to adjust the boundary between ZONE_NORMAL
- * and ZONE_HIGHMEM.
- */
-
- get_memcfg_numa();
- numa_init_array();
-
- kva_pages = roundup(calculate_numa_remap_pages(), PTRS_PER_PTE);
+ x86_numa_init();
- kva_target_pfn = round_down(max_low_pfn - kva_pages, PTRS_PER_PTE);
- do {
- kva_start_pfn = memblock_find_in_range(kva_target_pfn<<PAGE_SHIFT,
- max_low_pfn<<PAGE_SHIFT,
- kva_pages<<PAGE_SHIFT,
- PTRS_PER_PTE<<PAGE_SHIFT) >> PAGE_SHIFT;
- kva_target_pfn -= PTRS_PER_PTE;
- } while (kva_start_pfn == MEMBLOCK_ERROR && kva_target_pfn > min_low_pfn);
-
- if (kva_start_pfn == MEMBLOCK_ERROR)
- panic("Can not get kva space\n");
-
- printk(KERN_INFO "kva_start_pfn ~ %lx max_low_pfn ~ %lx\n",
- kva_start_pfn, max_low_pfn);
- printk(KERN_INFO "max_pfn = %lx\n", max_pfn);
-
- /* avoid clash with initrd */
- memblock_x86_reserve_range(kva_start_pfn<<PAGE_SHIFT,
- (kva_start_pfn + kva_pages)<<PAGE_SHIFT,
- "KVA PG");
#ifdef CONFIG_HIGHMEM
highstart_pfn = highend_pfn = max_pfn;
if (max_pfn > max_low_pfn)
@@ -409,51 +257,9 @@ void __init initmem_init(void)
printk(KERN_DEBUG "Low memory ends at vaddr %08lx\n",
(ulong) pfn_to_kaddr(max_low_pfn));
- for_each_online_node(nid) {
- init_remap_allocator(nid);
-
- allocate_pgdat(nid);
- }
- remap_numa_kva();
printk(KERN_DEBUG "High memory starts at vaddr %08lx\n",
(ulong) pfn_to_kaddr(highstart_pfn));
- for_each_online_node(nid)
- propagate_e820_map_node(nid);
-
- for_each_online_node(nid) {
- memset(NODE_DATA(nid), 0, sizeof(struct pglist_data));
- NODE_DATA(nid)->node_id = nid;
- }
setup_bootmem_allocator();
}
-
-#ifdef CONFIG_MEMORY_HOTPLUG
-static int paddr_to_nid(u64 addr)
-{
- int nid;
- unsigned long pfn = PFN_DOWN(addr);
-
- for_each_node(nid)
- if (node_start_pfn[nid] <= pfn &&
- pfn < node_end_pfn[nid])
- return nid;
-
- return -1;
-}
-
-/*
- * This function is used to ask node id BEFORE memmap and mem_section's
- * initialization (pfn_to_nid() can't be used yet).
- * If _PXM is not defined on ACPI's DSDT, node id must be found by this.
- */
-int memory_add_physaddr_to_nid(u64 addr)
-{
- int nid = paddr_to_nid(addr);
- return (nid >= 0) ? nid : 0;
-}
-
-EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
-#endif
-
diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c
index 85b52fc03084..dd27f401f0a0 100644
--- a/arch/x86/mm/numa_64.c
+++ b/arch/x86/mm/numa_64.c
@@ -2,646 +2,13 @@
* Generic VM initialization for x86-64 NUMA setups.
* Copyright 2002,2003 Andi Kleen, SuSE Labs.
*/
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/init.h>
#include <linux/bootmem.h>
-#include <linux/memblock.h>
-#include <linux/mmzone.h>
-#include <linux/ctype.h>
-#include <linux/module.h>
-#include <linux/nodemask.h>
-#include <linux/sched.h>
-#include <linux/acpi.h>
-
-#include <asm/e820.h>
-#include <asm/proto.h>
-#include <asm/dma.h>
-#include <asm/acpi.h>
-#include <asm/amd_nb.h>
#include "numa_internal.h"
-struct pglist_data *node_data[MAX_NUMNODES] __read_mostly;
-EXPORT_SYMBOL(node_data);
-
-nodemask_t numa_nodes_parsed __initdata;
-
-struct memnode memnode;
-
-static unsigned long __initdata nodemap_addr;
-static unsigned long __initdata nodemap_size;
-
-static struct numa_meminfo numa_meminfo __initdata;
-
-static int numa_distance_cnt;
-static u8 *numa_distance;
-
-/*
- * Given a shift value, try to populate memnodemap[]
- * Returns :
- * 1 if OK
- * 0 if memnodmap[] too small (of shift too small)
- * -1 if node overlap or lost ram (shift too big)
- */
-static int __init populate_memnodemap(const struct numa_meminfo *mi, int shift)
-{
- unsigned long addr, end;
- int i, res = -1;
-
- memset(memnodemap, 0xff, sizeof(s16)*memnodemapsize);
- for (i = 0; i < mi->nr_blks; i++) {
- addr = mi->blk[i].start;
- end = mi->blk[i].end;
- if (addr >= end)
- continue;
- if ((end >> shift) >= memnodemapsize)
- return 0;
- do {
- if (memnodemap[addr >> shift] != NUMA_NO_NODE)
- return -1;
- memnodemap[addr >> shift] = mi->blk[i].nid;
- addr += (1UL << shift);
- } while (addr < end);
- res = 1;
- }
- return res;
-}
-
-static int __init allocate_cachealigned_memnodemap(void)
-{
- unsigned long addr;
-
- memnodemap = memnode.embedded_map;
- if (memnodemapsize <= ARRAY_SIZE(memnode.embedded_map))
- return 0;
-
- addr = 0x8000;
- nodemap_size = roundup(sizeof(s16) * memnodemapsize, L1_CACHE_BYTES);
- nodemap_addr = memblock_find_in_range(addr, get_max_mapped(),
- nodemap_size, L1_CACHE_BYTES);
- if (nodemap_addr == MEMBLOCK_ERROR) {
- printk(KERN_ERR
- "NUMA: Unable to allocate Memory to Node hash map\n");
- nodemap_addr = nodemap_size = 0;
- return -1;
- }
- memnodemap = phys_to_virt(nodemap_addr);
- memblock_x86_reserve_range(nodemap_addr, nodemap_addr + nodemap_size, "MEMNODEMAP");
-
- printk(KERN_DEBUG "NUMA: Allocated memnodemap from %lx - %lx\n",
- nodemap_addr, nodemap_addr + nodemap_size);
- return 0;
-}
-
-/*
- * The LSB of all start and end addresses in the node map is the value of the
- * maximum possible shift.
- */
-static int __init extract_lsb_from_nodes(const struct numa_meminfo *mi)
-{
- int i, nodes_used = 0;
- unsigned long start, end;
- unsigned long bitfield = 0, memtop = 0;
-
- for (i = 0; i < mi->nr_blks; i++) {
- start = mi->blk[i].start;
- end = mi->blk[i].end;
- if (start >= end)
- continue;
- bitfield |= start;
- nodes_used++;
- if (end > memtop)
- memtop = end;
- }
- if (nodes_used <= 1)
- i = 63;
- else
- i = find_first_bit(&bitfield, sizeof(unsigned long)*8);
- memnodemapsize = (memtop >> i)+1;
- return i;
-}
-
-static int __init compute_hash_shift(const struct numa_meminfo *mi)
-{
- int shift;
-
- shift = extract_lsb_from_nodes(mi);
- if (allocate_cachealigned_memnodemap())
- return -1;
- printk(KERN_DEBUG "NUMA: Using %d for the hash shift.\n",
- shift);
-
- if (populate_memnodemap(mi, shift) != 1) {
- printk(KERN_INFO "Your memory is not aligned you need to "
- "rebuild your kernel with a bigger NODEMAPSIZE "
- "shift=%d\n", shift);
- return -1;
- }
- return shift;
-}
-
-int __meminit __early_pfn_to_nid(unsigned long pfn)
-{
- return phys_to_nid(pfn << PAGE_SHIFT);
-}
-
-static void * __init early_node_mem(int nodeid, unsigned long start,
- unsigned long end, unsigned long size,
- unsigned long align)
-{
- unsigned long mem;
-
- /*
- * put it on high as possible
- * something will go with NODE_DATA
- */
- if (start < (MAX_DMA_PFN<<PAGE_SHIFT))
- start = MAX_DMA_PFN<<PAGE_SHIFT;
- if (start < (MAX_DMA32_PFN<<PAGE_SHIFT) &&
- end > (MAX_DMA32_PFN<<PAGE_SHIFT))
- start = MAX_DMA32_PFN<<PAGE_SHIFT;
- mem = memblock_x86_find_in_range_node(nodeid, start, end, size, align);
- if (mem != MEMBLOCK_ERROR)
- return __va(mem);
-
- /* extend the search scope */
- end = max_pfn_mapped << PAGE_SHIFT;
- start = MAX_DMA_PFN << PAGE_SHIFT;
- mem = memblock_find_in_range(start, end, size, align);
- if (mem != MEMBLOCK_ERROR)
- return __va(mem);
-
- printk(KERN_ERR "Cannot find %lu bytes in node %d\n",
- size, nodeid);
-
- return NULL;
-}
-
-static int __init numa_add_memblk_to(int nid, u64 start, u64 end,
- struct numa_meminfo *mi)
-{
- /* ignore zero length blks */
- if (start == end)
- return 0;
-
- /* whine about and ignore invalid blks */
- if (start > end || nid < 0 || nid >= MAX_NUMNODES) {
- pr_warning("NUMA: Warning: invalid memblk node %d (%Lx-%Lx)\n",
- nid, start, end);
- return 0;
- }
-
- if (mi->nr_blks >= NR_NODE_MEMBLKS) {
- pr_err("NUMA: too many memblk ranges\n");
- return -EINVAL;
- }
-
- mi->blk[mi->nr_blks].start = start;
- mi->blk[mi->nr_blks].end = end;
- mi->blk[mi->nr_blks].nid = nid;
- mi->nr_blks++;
- return 0;
-}
-
-/**
- * numa_remove_memblk_from - Remove one numa_memblk from a numa_meminfo
- * @idx: Index of memblk to remove
- * @mi: numa_meminfo to remove memblk from
- *
- * Remove @idx'th numa_memblk from @mi by shifting @mi->blk[] and
- * decrementing @mi->nr_blks.
- */
-void __init numa_remove_memblk_from(int idx, struct numa_meminfo *mi)
-{
- mi->nr_blks--;
- memmove(&mi->blk[idx], &mi->blk[idx + 1],
- (mi->nr_blks - idx) * sizeof(mi->blk[0]));
-}
-
-/**
- * numa_add_memblk - Add one numa_memblk to numa_meminfo
- * @nid: NUMA node ID of the new memblk
- * @start: Start address of the new memblk
- * @end: End address of the new memblk
- *
- * Add a new memblk to the default numa_meminfo.
- *
- * RETURNS:
- * 0 on success, -errno on failure.
- */
-int __init numa_add_memblk(int nid, u64 start, u64 end)
-{
- return numa_add_memblk_to(nid, start, end, &numa_meminfo);
-}
-
-/* Initialize bootmem allocator for a node */
-void __init
-setup_node_bootmem(int nodeid, unsigned long start, unsigned long end)
-{
- unsigned long start_pfn, last_pfn, nodedata_phys;
- const int pgdat_size = roundup(sizeof(pg_data_t), PAGE_SIZE);
- int nid;
-
- if (!end)
- return;
-
- /*
- * Don't confuse VM with a node that doesn't have the
- * minimum amount of memory:
- */
- if (end && (end - start) < NODE_MIN_SIZE)
- return;
-
- start = roundup(start, ZONE_ALIGN);
-
- printk(KERN_INFO "Initmem setup node %d %016lx-%016lx\n", nodeid,
- start, end);
-
- start_pfn = start >> PAGE_SHIFT;
- last_pfn = end >> PAGE_SHIFT;
-
- node_data[nodeid] = early_node_mem(nodeid, start, end, pgdat_size,
- SMP_CACHE_BYTES);
- if (node_data[nodeid] == NULL)
- return;
- nodedata_phys = __pa(node_data[nodeid]);
- memblock_x86_reserve_range(nodedata_phys, nodedata_phys + pgdat_size, "NODE_DATA");
- printk(KERN_INFO " NODE_DATA [%016lx - %016lx]\n", nodedata_phys,
- nodedata_phys + pgdat_size - 1);
- nid = phys_to_nid(nodedata_phys);
- if (nid != nodeid)
- printk(KERN_INFO " NODE_DATA(%d) on node %d\n", nodeid, nid);
-
- memset(NODE_DATA(nodeid), 0, sizeof(pg_data_t));
- NODE_DATA(nodeid)->node_id = nodeid;
- NODE_DATA(nodeid)->node_start_pfn = start_pfn;
- NODE_DATA(nodeid)->node_spanned_pages = last_pfn - start_pfn;
-
- node_set_online(nodeid);
-}
-
-/**
- * numa_cleanup_meminfo - Cleanup a numa_meminfo
- * @mi: numa_meminfo to clean up
- *
- * Sanitize @mi by merging and removing unncessary memblks. Also check for
- * conflicts and clear unused memblks.
- *
- * RETURNS:
- * 0 on success, -errno on failure.
- */
-int __init numa_cleanup_meminfo(struct numa_meminfo *mi)
-{
- const u64 low = 0;
- const u64 high = (u64)max_pfn << PAGE_SHIFT;
- int i, j, k;
-
- for (i = 0; i < mi->nr_blks; i++) {
- struct numa_memblk *bi = &mi->blk[i];
-
- /* make sure all blocks are inside the limits */
- bi->start = max(bi->start, low);
- bi->end = min(bi->end, high);
-
- /* and there's no empty block */
- if (bi->start >= bi->end) {
- numa_remove_memblk_from(i--, mi);
- continue;
- }
-
- for (j = i + 1; j < mi->nr_blks; j++) {
- struct numa_memblk *bj = &mi->blk[j];
- unsigned long start, end;
-
- /*
- * See whether there are overlapping blocks. Whine
- * about but allow overlaps of the same nid. They
- * will be merged below.
- */
- if (bi->end > bj->start && bi->start < bj->end) {
- if (bi->nid != bj->nid) {
- pr_err("NUMA: node %d (%Lx-%Lx) overlaps with node %d (%Lx-%Lx)\n",
- bi->nid, bi->start, bi->end,
- bj->nid, bj->start, bj->end);
- return -EINVAL;
- }
- pr_warning("NUMA: Warning: node %d (%Lx-%Lx) overlaps with itself (%Lx-%Lx)\n",
- bi->nid, bi->start, bi->end,
- bj->start, bj->end);
- }
-
- /*
- * Join together blocks on the same node, holes
- * between which don't overlap with memory on other
- * nodes.
- */
- if (bi->nid != bj->nid)
- continue;
- start = max(min(bi->start, bj->start), low);
- end = min(max(bi->end, bj->end), high);
- for (k = 0; k < mi->nr_blks; k++) {
- struct numa_memblk *bk = &mi->blk[k];
-
- if (bi->nid == bk->nid)
- continue;
- if (start < bk->end && end > bk->start)
- break;
- }
- if (k < mi->nr_blks)
- continue;
- printk(KERN_INFO "NUMA: Node %d [%Lx,%Lx) + [%Lx,%Lx) -> [%lx,%lx)\n",
- bi->nid, bi->start, bi->end, bj->start, bj->end,
- start, end);
- bi->start = start;
- bi->end = end;
- numa_remove_memblk_from(j--, mi);
- }
- }
-
- for (i = mi->nr_blks; i < ARRAY_SIZE(mi->blk); i++) {
- mi->blk[i].start = mi->blk[i].end = 0;
- mi->blk[i].nid = NUMA_NO_NODE;
- }
-
- return 0;
-}
-
-/*
- * Set nodes, which have memory in @mi, in *@nodemask.
- */
-static void __init numa_nodemask_from_meminfo(nodemask_t *nodemask,
- const struct numa_meminfo *mi)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(mi->blk); i++)
- if (mi->blk[i].start != mi->blk[i].end &&
- mi->blk[i].nid != NUMA_NO_NODE)
- node_set(mi->blk[i].nid, *nodemask);
-}
-
-/**
- * numa_reset_distance - Reset NUMA distance table
- *
- * The current table is freed. The next numa_set_distance() call will
- * create a new one.
- */
-void __init numa_reset_distance(void)
-{
- size_t size = numa_distance_cnt * numa_distance_cnt * sizeof(numa_distance[0]);
-
- /* numa_distance could be 1LU marking allocation failure, test cnt */
- if (numa_distance_cnt)
- memblock_x86_free_range(__pa(numa_distance),
- __pa(numa_distance) + size);
- numa_distance_cnt = 0;
- numa_distance = NULL; /* enable table creation */
-}
-
-static int __init numa_alloc_distance(void)
-{
- nodemask_t nodes_parsed;
- size_t size;
- int i, j, cnt = 0;
- u64 phys;
-
- /* size the new table and allocate it */
- nodes_parsed = numa_nodes_parsed;
- numa_nodemask_from_meminfo(&nodes_parsed, &numa_meminfo);
-
- for_each_node_mask(i, nodes_parsed)
- cnt = i;
- cnt++;
- size = cnt * cnt * sizeof(numa_distance[0]);
-
- phys = memblock_find_in_range(0, (u64)max_pfn_mapped << PAGE_SHIFT,
- size, PAGE_SIZE);
- if (phys == MEMBLOCK_ERROR) {
- pr_warning("NUMA: Warning: can't allocate distance table!\n");
- /* don't retry until explicitly reset */
- numa_distance = (void *)1LU;
- return -ENOMEM;
- }
- memblock_x86_reserve_range(phys, phys + size, "NUMA DIST");
-
- numa_distance = __va(phys);
- numa_distance_cnt = cnt;
-
- /* fill with the default distances */
- for (i = 0; i < cnt; i++)
- for (j = 0; j < cnt; j++)
- numa_distance[i * cnt + j] = i == j ?
- LOCAL_DISTANCE : REMOTE_DISTANCE;
- printk(KERN_DEBUG "NUMA: Initialized distance table, cnt=%d\n", cnt);
-
- return 0;
-}
-
-/**
- * numa_set_distance - Set NUMA distance from one NUMA to another
- * @from: the 'from' node to set distance
- * @to: the 'to' node to set distance
- * @distance: NUMA distance
- *
- * Set the distance from node @from to @to to @distance. If distance table
- * doesn't exist, one which is large enough to accommodate all the currently
- * known nodes will be created.
- *
- * If such table cannot be allocated, a warning is printed and further
- * calls are ignored until the distance table is reset with
- * numa_reset_distance().
- *
- * If @from or @to is higher than the highest known node at the time of
- * table creation or @distance doesn't make sense, the call is ignored.
- * This is to allow simplification of specific NUMA config implementations.
- */
-void __init numa_set_distance(int from, int to, int distance)
-{
- if (!numa_distance && numa_alloc_distance() < 0)
- return;
-
- if (from >= numa_distance_cnt || to >= numa_distance_cnt) {
- printk_once(KERN_DEBUG "NUMA: Debug: distance out of bound, from=%d to=%d distance=%d\n",
- from, to, distance);
- return;
- }
-
- if ((u8)distance != distance ||
- (from == to && distance != LOCAL_DISTANCE)) {
- pr_warn_once("NUMA: Warning: invalid distance parameter, from=%d to=%d distance=%d\n",
- from, to, distance);
- return;
- }
-
- numa_distance[from * numa_distance_cnt + to] = distance;
-}
-
-int __node_distance(int from, int to)
-{
- if (from >= numa_distance_cnt || to >= numa_distance_cnt)
- return from == to ? LOCAL_DISTANCE : REMOTE_DISTANCE;
- return numa_distance[from * numa_distance_cnt + to];
-}
-EXPORT_SYMBOL(__node_distance);
-
-/*
- * Sanity check to catch more bad NUMA configurations (they are amazingly
- * common). Make sure the nodes cover all memory.
- */
-static bool __init numa_meminfo_cover_memory(const struct numa_meminfo *mi)
-{
- unsigned long numaram, e820ram;
- int i;
-
- numaram = 0;
- for (i = 0; i < mi->nr_blks; i++) {
- unsigned long s = mi->blk[i].start >> PAGE_SHIFT;
- unsigned long e = mi->blk[i].end >> PAGE_SHIFT;
- numaram += e - s;
- numaram -= __absent_pages_in_range(mi->blk[i].nid, s, e);
- if ((long)numaram < 0)
- numaram = 0;
- }
-
- e820ram = max_pfn - (memblock_x86_hole_size(0,
- max_pfn << PAGE_SHIFT) >> PAGE_SHIFT);
- /* We seem to lose 3 pages somewhere. Allow 1M of slack. */
- if ((long)(e820ram - numaram) >= (1 << (20 - PAGE_SHIFT))) {
- printk(KERN_ERR "NUMA: nodes only cover %luMB of your %luMB e820 RAM. Not used.\n",
- (numaram << PAGE_SHIFT) >> 20,
- (e820ram << PAGE_SHIFT) >> 20);
- return false;
- }
- return true;
-}
-
-static int __init numa_register_memblks(struct numa_meminfo *mi)
-{
- int i, nid;
-
- /* Account for nodes with cpus and no memory */
- node_possible_map = numa_nodes_parsed;
- numa_nodemask_from_meminfo(&node_possible_map, mi);
- if (WARN_ON(nodes_empty(node_possible_map)))
- return -EINVAL;
-
- memnode_shift = compute_hash_shift(mi);
- if (memnode_shift < 0) {
- printk(KERN_ERR "NUMA: No NUMA node hash function found. Contact maintainer\n");
- return -EINVAL;
- }
-
- for (i = 0; i < mi->nr_blks; i++)
- memblock_x86_register_active_regions(mi->blk[i].nid,
- mi->blk[i].start >> PAGE_SHIFT,
- mi->blk[i].end >> PAGE_SHIFT);
-
- /* for out of order entries */
- sort_node_map();
- if (!numa_meminfo_cover_memory(mi))
- return -EINVAL;
-
- /* Finally register nodes. */
- for_each_node_mask(nid, node_possible_map) {
- u64 start = (u64)max_pfn << PAGE_SHIFT;
- u64 end = 0;
-
- for (i = 0; i < mi->nr_blks; i++) {
- if (nid != mi->blk[i].nid)
- continue;
- start = min(mi->blk[i].start, start);
- end = max(mi->blk[i].end, end);
- }
-
- if (start < end)
- setup_node_bootmem(nid, start, end);
- }
-
- return 0;
-}
-
-/**
- * dummy_numma_init - Fallback dummy NUMA init
- *
- * Used if there's no underlying NUMA architecture, NUMA initialization
- * fails, or NUMA is disabled on the command line.
- *
- * Must online at least one node and add memory blocks that cover all
- * allowed memory. This function must not fail.
- */
-static int __init dummy_numa_init(void)
-{
- printk(KERN_INFO "%s\n",
- numa_off ? "NUMA turned off" : "No NUMA configuration found");
- printk(KERN_INFO "Faking a node at %016lx-%016lx\n",
- 0LU, max_pfn << PAGE_SHIFT);
-
- node_set(0, numa_nodes_parsed);
- numa_add_memblk(0, 0, (u64)max_pfn << PAGE_SHIFT);
-
- return 0;
-}
-
-static int __init numa_init(int (*init_func)(void))
-{
- int i;
- int ret;
-
- for (i = 0; i < MAX_LOCAL_APIC; i++)
- set_apicid_to_node(i, NUMA_NO_NODE);
-
- nodes_clear(numa_nodes_parsed);
- nodes_clear(node_possible_map);
- nodes_clear(node_online_map);
- memset(&numa_meminfo, 0, sizeof(numa_meminfo));
- remove_all_active_ranges();
- numa_reset_distance();
-
- ret = init_func();
- if (ret < 0)
- return ret;
- ret = numa_cleanup_meminfo(&numa_meminfo);
- if (ret < 0)
- return ret;
-
- numa_emulation(&numa_meminfo, numa_distance_cnt);
-
- ret = numa_register_memblks(&numa_meminfo);
- if (ret < 0)
- return ret;
-
- for (i = 0; i < nr_cpu_ids; i++) {
- int nid = early_cpu_to_node(i);
-
- if (nid == NUMA_NO_NODE)
- continue;
- if (!node_online(nid))
- numa_clear_node(i);
- }
- numa_init_array();
- return 0;
-}
-
void __init initmem_init(void)
{
- int ret;
-
- if (!numa_off) {
-#ifdef CONFIG_ACPI_NUMA
- ret = numa_init(x86_acpi_numa_init);
- if (!ret)
- return;
-#endif
-#ifdef CONFIG_AMD_NUMA
- ret = numa_init(amd_numa_init);
- if (!ret)
- return;
-#endif
- }
-
- numa_init(dummy_numa_init);
+ x86_numa_init();
}
unsigned long __init numa_free_all_bootmem(void)
@@ -656,12 +23,3 @@ unsigned long __init numa_free_all_bootmem(void)
return pages;
}
-
-int __cpuinit numa_cpu_node(int cpu)
-{
- int apicid = early_per_cpu(x86_cpu_to_apicid, cpu);
-
- if (apicid != BAD_APICID)
- return __apicid_to_node[apicid];
- return NUMA_NO_NODE;
-}
diff --git a/arch/x86/mm/numa_emulation.c b/arch/x86/mm/numa_emulation.c
index de84cc140379..d0ed086b6247 100644
--- a/arch/x86/mm/numa_emulation.c
+++ b/arch/x86/mm/numa_emulation.c
@@ -5,6 +5,7 @@
#include <linux/errno.h>
#include <linux/topology.h>
#include <linux/memblock.h>
+#include <linux/bootmem.h>
#include <asm/dma.h>
#include "numa_internal.h"
@@ -84,7 +85,13 @@ static int __init split_nodes_interleave(struct numa_meminfo *ei,
nr_nodes = MAX_NUMNODES;
}
- size = (max_addr - addr - memblock_x86_hole_size(addr, max_addr)) / nr_nodes;
+ /*
+ * Calculate target node size. x86_32 freaks on __udivdi3() so do
+ * the division in ulong number of pages and convert back.
+ */
+ size = max_addr - addr - memblock_x86_hole_size(addr, max_addr);
+ size = PFN_PHYS((unsigned long)(size >> PAGE_SHIFT) / nr_nodes);
+
/*
* Calculate the number of big nodes that can be allocated as a result
* of consolidating the remainder.
@@ -226,7 +233,7 @@ static int __init split_nodes_size_interleave(struct numa_meminfo *ei,
*/
while (nodes_weight(physnode_mask)) {
for_each_node_mask(i, physnode_mask) {
- u64 dma32_end = MAX_DMA32_PFN << PAGE_SHIFT;
+ u64 dma32_end = PFN_PHYS(MAX_DMA32_PFN);
u64 start, limit, end;
int phys_blk;
@@ -298,7 +305,7 @@ void __init numa_emulation(struct numa_meminfo *numa_meminfo, int numa_dist_cnt)
{
static struct numa_meminfo ei __initdata;
static struct numa_meminfo pi __initdata;
- const u64 max_addr = max_pfn << PAGE_SHIFT;
+ const u64 max_addr = PFN_PHYS(max_pfn);
u8 *phys_dist = NULL;
size_t phys_size = numa_dist_cnt * numa_dist_cnt * sizeof(phys_dist[0]);
int max_emu_nid, dfl_phys_nid;
@@ -342,8 +349,7 @@ void __init numa_emulation(struct numa_meminfo *numa_meminfo, int numa_dist_cnt)
if (numa_dist_cnt) {
u64 phys;
- phys = memblock_find_in_range(0,
- (u64)max_pfn_mapped << PAGE_SHIFT,
+ phys = memblock_find_in_range(0, PFN_PHYS(max_pfn_mapped),
phys_size, PAGE_SIZE);
if (phys == MEMBLOCK_ERROR) {
pr_warning("NUMA: Warning: can't allocate copy of distance table, disabling emulation\n");
diff --git a/arch/x86/mm/numa_internal.h b/arch/x86/mm/numa_internal.h
index ef2d97377d7c..7178c3afe05e 100644
--- a/arch/x86/mm/numa_internal.h
+++ b/arch/x86/mm/numa_internal.h
@@ -19,6 +19,14 @@ void __init numa_remove_memblk_from(int idx, struct numa_meminfo *mi);
int __init numa_cleanup_meminfo(struct numa_meminfo *mi);
void __init numa_reset_distance(void);
+void __init x86_numa_init(void);
+
+#ifdef CONFIG_X86_64
+static inline void init_alloc_remap(int nid, u64 start, u64 end) { }
+#else
+void __init init_alloc_remap(int nid, u64 start, u64 end);
+#endif
+
#ifdef CONFIG_NUMA_EMU
void __init numa_emulation(struct numa_meminfo *numa_meminfo,
int numa_dist_cnt);
diff --git a/arch/x86/mm/pf_in.c b/arch/x86/mm/pf_in.c
index 38e6d174c497..9f0614daea85 100644
--- a/arch/x86/mm/pf_in.c
+++ b/arch/x86/mm/pf_in.c
@@ -414,22 +414,17 @@ unsigned long get_ins_reg_val(unsigned long ins_addr, struct pt_regs *regs)
unsigned char *p;
struct prefix_bits prf;
int i;
- unsigned long rv;
p = (unsigned char *)ins_addr;
p += skip_prefix(p, &prf);
p += get_opcode(p, &opcode);
for (i = 0; i < ARRAY_SIZE(reg_rop); i++)
- if (reg_rop[i] == opcode) {
- rv = REG_READ;
+ if (reg_rop[i] == opcode)
goto do_work;
- }
for (i = 0; i < ARRAY_SIZE(reg_wop); i++)
- if (reg_wop[i] == opcode) {
- rv = REG_WRITE;
+ if (reg_wop[i] == opcode)
goto do_work;
- }
printk(KERN_ERR "mmiotrace: Not a register instruction, opcode "
"0x%02x\n", opcode);
@@ -474,16 +469,13 @@ unsigned long get_ins_imm_val(unsigned long ins_addr)
unsigned char *p;
struct prefix_bits prf;
int i;
- unsigned long rv;
p = (unsigned char *)ins_addr;
p += skip_prefix(p, &prf);
p += get_opcode(p, &opcode);
for (i = 0; i < ARRAY_SIZE(imm_wop); i++)
- if (imm_wop[i] == opcode) {
- rv = IMM_WRITE;
+ if (imm_wop[i] == opcode)
goto do_work;
- }
printk(KERN_ERR "mmiotrace: Not an immediate instruction, opcode "
"0x%02x\n", opcode);
diff --git a/arch/x86/mm/srat_64.c b/arch/x86/mm/srat.c
index 8e9d3394f6d4..81dbfdeb080d 100644
--- a/arch/x86/mm/srat_64.c
+++ b/arch/x86/mm/srat.c
@@ -26,8 +26,6 @@
int acpi_numa __initdata;
-static struct bootnode nodes_add[MAX_NUMNODES];
-
static __init int setup_node(int pxm)
{
return acpi_map_pxm_to_node(pxm);
@@ -37,7 +35,6 @@ static __init void bad_srat(void)
{
printk(KERN_ERR "SRAT: SRAT not used.\n");
acpi_numa = -1;
- memset(nodes_add, 0, sizeof(nodes_add));
}
static __init inline int srat_disabled(void)
@@ -131,73 +128,17 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
pxm, apic_id, node);
}
-#ifdef CONFIG_MEMORY_HOTPLUG_SPARSE
+#ifdef CONFIG_MEMORY_HOTPLUG
static inline int save_add_info(void) {return 1;}
#else
static inline int save_add_info(void) {return 0;}
#endif
-/*
- * Update nodes_add[]
- * This code supports one contiguous hot add area per node
- */
-static void __init
-update_nodes_add(int node, unsigned long start, unsigned long end)
-{
- unsigned long s_pfn = start >> PAGE_SHIFT;
- unsigned long e_pfn = end >> PAGE_SHIFT;
- int changed = 0;
- struct bootnode *nd = &nodes_add[node];
-
- /* I had some trouble with strange memory hotadd regions breaking
- the boot. Be very strict here and reject anything unexpected.
- If you want working memory hotadd write correct SRATs.
-
- The node size check is a basic sanity check to guard against
- mistakes */
- if ((signed long)(end - start) < NODE_MIN_SIZE) {
- printk(KERN_ERR "SRAT: Hotplug area too small\n");
- return;
- }
-
- /* This check might be a bit too strict, but I'm keeping it for now. */
- if (absent_pages_in_range(s_pfn, e_pfn) != e_pfn - s_pfn) {
- printk(KERN_ERR
- "SRAT: Hotplug area %lu -> %lu has existing memory\n",
- s_pfn, e_pfn);
- return;
- }
-
- /* Looks good */
-
- if (nd->start == nd->end) {
- nd->start = start;
- nd->end = end;
- changed = 1;
- } else {
- if (nd->start == end) {
- nd->start = start;
- changed = 1;
- }
- if (nd->end == start) {
- nd->end = end;
- changed = 1;
- }
- if (!changed)
- printk(KERN_ERR "SRAT: Hotplug zone not continuous. Partly ignored\n");
- }
-
- if (changed) {
- node_set(node, numa_nodes_parsed);
- printk(KERN_INFO "SRAT: hot plug zone found %Lx - %Lx\n",
- nd->start, nd->end);
- }
-}
/* Callback for parsing of the Proximity Domain <-> Memory Area mappings */
void __init
acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
{
- unsigned long start, end;
+ u64 start, end;
int node, pxm;
if (srat_disabled())
@@ -226,11 +167,8 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
return;
}
- printk(KERN_INFO "SRAT: Node %u PXM %u %lx-%lx\n", node, pxm,
+ printk(KERN_INFO "SRAT: Node %u PXM %u %Lx-%Lx\n", node, pxm,
start, end);
-
- if (ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE)
- update_nodes_add(node, start, end);
}
void __init acpi_numa_arch_fixup(void) {}
@@ -244,17 +182,3 @@ int __init x86_acpi_numa_init(void)
return ret;
return srat_disabled() ? -EINVAL : 0;
}
-
-#if defined(CONFIG_MEMORY_HOTPLUG_SPARSE) || defined(CONFIG_ACPI_HOTPLUG_MEMORY)
-int memory_add_physaddr_to_nid(u64 start)
-{
- int i, ret = 0;
-
- for_each_node(i)
- if (nodes_add[i].start <= start && nodes_add[i].end > start)
- ret = i;
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
-#endif
diff --git a/arch/x86/mm/srat_32.c b/arch/x86/mm/srat_32.c
deleted file mode 100644
index 364f36bdfad8..000000000000
--- a/arch/x86/mm/srat_32.c
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Some of the code in this file has been gleaned from the 64 bit
- * discontigmem support code base.
- *
- * Copyright (C) 2002, IBM Corp.
- *
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Send feedback to Pat Gaughen <gone@us.ibm.com>
- */
-#include <linux/mm.h>
-#include <linux/bootmem.h>
-#include <linux/memblock.h>
-#include <linux/mmzone.h>
-#include <linux/acpi.h>
-#include <linux/nodemask.h>
-#include <asm/srat.h>
-#include <asm/topology.h>
-#include <asm/smp.h>
-#include <asm/e820.h>
-
-/*
- * proximity macros and definitions
- */
-#define NODE_ARRAY_INDEX(x) ((x) / 8) /* 8 bits/char */
-#define NODE_ARRAY_OFFSET(x) ((x) % 8) /* 8 bits/char */
-#define BMAP_SET(bmap, bit) ((bmap)[NODE_ARRAY_INDEX(bit)] |= 1 << NODE_ARRAY_OFFSET(bit))
-#define BMAP_TEST(bmap, bit) ((bmap)[NODE_ARRAY_INDEX(bit)] & (1 << NODE_ARRAY_OFFSET(bit)))
-/* bitmap length; _PXM is at most 255 */
-#define PXM_BITMAP_LEN (MAX_PXM_DOMAINS / 8)
-static u8 __initdata pxm_bitmap[PXM_BITMAP_LEN]; /* bitmap of proximity domains */
-
-#define MAX_CHUNKS_PER_NODE 3
-#define MAXCHUNKS (MAX_CHUNKS_PER_NODE * MAX_NUMNODES)
-struct node_memory_chunk_s {
- unsigned long start_pfn;
- unsigned long end_pfn;
- u8 pxm; // proximity domain of node
- u8 nid; // which cnode contains this chunk?
- u8 bank; // which mem bank on this node
-};
-static struct node_memory_chunk_s __initdata node_memory_chunk[MAXCHUNKS];
-
-static int __initdata num_memory_chunks; /* total number of memory chunks */
-static u8 __initdata apicid_to_pxm[MAX_LOCAL_APIC];
-
-int acpi_numa __initdata;
-
-static __init void bad_srat(void)
-{
- printk(KERN_ERR "SRAT: SRAT not used.\n");
- acpi_numa = -1;
- num_memory_chunks = 0;
-}
-
-static __init inline int srat_disabled(void)
-{
- return numa_off || acpi_numa < 0;
-}
-
-/* Identify CPU proximity domains */
-void __init
-acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *cpu_affinity)
-{
- if (srat_disabled())
- return;
- if (cpu_affinity->header.length !=
- sizeof(struct acpi_srat_cpu_affinity)) {
- bad_srat();
- return;
- }
-
- if ((cpu_affinity->flags & ACPI_SRAT_CPU_ENABLED) == 0)
- return; /* empty entry */
-
- /* mark this node as "seen" in node bitmap */
- BMAP_SET(pxm_bitmap, cpu_affinity->proximity_domain_lo);
-
- /* don't need to check apic_id here, because it is always 8 bits */
- apicid_to_pxm[cpu_affinity->apic_id] = cpu_affinity->proximity_domain_lo;
-
- printk(KERN_DEBUG "CPU %02x in proximity domain %02x\n",
- cpu_affinity->apic_id, cpu_affinity->proximity_domain_lo);
-}
-
-/*
- * Identify memory proximity domains and hot-remove capabilities.
- * Fill node memory chunk list structure.
- */
-void __init
-acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *memory_affinity)
-{
- unsigned long long paddr, size;
- unsigned long start_pfn, end_pfn;
- u8 pxm;
- struct node_memory_chunk_s *p, *q, *pend;
-
- if (srat_disabled())
- return;
- if (memory_affinity->header.length !=
- sizeof(struct acpi_srat_mem_affinity)) {
- bad_srat();
- return;
- }
-
- if ((memory_affinity->flags & ACPI_SRAT_MEM_ENABLED) == 0)
- return; /* empty entry */
-
- pxm = memory_affinity->proximity_domain & 0xff;
-
- /* mark this node as "seen" in node bitmap */
- BMAP_SET(pxm_bitmap, pxm);
-
- /* calculate info for memory chunk structure */
- paddr = memory_affinity->base_address;
- size = memory_affinity->length;
-
- start_pfn = paddr >> PAGE_SHIFT;
- end_pfn = (paddr + size) >> PAGE_SHIFT;
-
-
- if (num_memory_chunks >= MAXCHUNKS) {
- printk(KERN_WARNING "Too many mem chunks in SRAT."
- " Ignoring %lld MBytes at %llx\n",
- size/(1024*1024), paddr);
- return;
- }
-
- /* Insertion sort based on base address */
- pend = &node_memory_chunk[num_memory_chunks];
- for (p = &node_memory_chunk[0]; p < pend; p++) {
- if (start_pfn < p->start_pfn)
- break;
- }
- if (p < pend) {
- for (q = pend; q >= p; q--)
- *(q + 1) = *q;
- }
- p->start_pfn = start_pfn;
- p->end_pfn = end_pfn;
- p->pxm = pxm;
-
- num_memory_chunks++;
-
- printk(KERN_DEBUG "Memory range %08lx to %08lx"
- " in proximity domain %02x %s\n",
- start_pfn, end_pfn,
- pxm,
- ((memory_affinity->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) ?
- "enabled and removable" : "enabled" ) );
-}
-
-/* Callback for SLIT parsing */
-void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
-{
-}
-
-void acpi_numa_arch_fixup(void)
-{
-}
-/*
- * The SRAT table always lists ascending addresses, so can always
- * assume that the first "start" address that you see is the real
- * start of the node, and that the current "end" address is after
- * the previous one.
- */
-static __init int node_read_chunk(int nid, struct node_memory_chunk_s *memory_chunk)
-{
- /*
- * Only add present memory as told by the e820.
- * There is no guarantee from the SRAT that the memory it
- * enumerates is present at boot time because it represents
- * *possible* memory hotplug areas the same as normal RAM.
- */
- if (memory_chunk->start_pfn >= max_pfn) {
- printk(KERN_INFO "Ignoring SRAT pfns: %08lx - %08lx\n",
- memory_chunk->start_pfn, memory_chunk->end_pfn);
- return -1;
- }
- if (memory_chunk->nid != nid)
- return -1;
-
- if (!node_has_online_mem(nid))
- node_start_pfn[nid] = memory_chunk->start_pfn;
-
- if (node_start_pfn[nid] > memory_chunk->start_pfn)
- node_start_pfn[nid] = memory_chunk->start_pfn;
-
- if (node_end_pfn[nid] < memory_chunk->end_pfn)
- node_end_pfn[nid] = memory_chunk->end_pfn;
-
- return 0;
-}
-
-int __init get_memcfg_from_srat(void)
-{
- int i, j, nid;
-
- if (srat_disabled())
- goto out_fail;
-
- if (acpi_numa_init() < 0)
- goto out_fail;
-
- if (num_memory_chunks == 0) {
- printk(KERN_DEBUG
- "could not find any ACPI SRAT memory areas.\n");
- goto out_fail;
- }
-
- /* Calculate total number of nodes in system from PXM bitmap and create
- * a set of sequential node IDs starting at zero. (ACPI doesn't seem
- * to specify the range of _PXM values.)
- */
- /*
- * MCD - we no longer HAVE to number nodes sequentially. PXM domain
- * numbers could go as high as 256, and MAX_NUMNODES for i386 is typically
- * 32, so we will continue numbering them in this manner until MAX_NUMNODES
- * approaches MAX_PXM_DOMAINS for i386.
- */
- nodes_clear(node_online_map);
- for (i = 0; i < MAX_PXM_DOMAINS; i++) {
- if (BMAP_TEST(pxm_bitmap, i)) {
- int nid = acpi_map_pxm_to_node(i);
- node_set_online(nid);
- }
- }
- BUG_ON(num_online_nodes() == 0);
-
- /* set cnode id in memory chunk structure */
- for (i = 0; i < num_memory_chunks; i++)
- node_memory_chunk[i].nid = pxm_to_node(node_memory_chunk[i].pxm);
-
- printk(KERN_DEBUG "pxm bitmap: ");
- for (i = 0; i < sizeof(pxm_bitmap); i++) {
- printk(KERN_CONT "%02x ", pxm_bitmap[i]);
- }
- printk(KERN_CONT "\n");
- printk(KERN_DEBUG "Number of logical nodes in system = %d\n",
- num_online_nodes());
- printk(KERN_DEBUG "Number of memory chunks in system = %d\n",
- num_memory_chunks);
-
- for (i = 0; i < MAX_LOCAL_APIC; i++)
- set_apicid_to_node(i, pxm_to_node(apicid_to_pxm[i]));
-
- for (j = 0; j < num_memory_chunks; j++){
- struct node_memory_chunk_s * chunk = &node_memory_chunk[j];
- printk(KERN_DEBUG
- "chunk %d nid %d start_pfn %08lx end_pfn %08lx\n",
- j, chunk->nid, chunk->start_pfn, chunk->end_pfn);
- if (node_read_chunk(chunk->nid, chunk))
- continue;
-
- memblock_x86_register_active_regions(chunk->nid, chunk->start_pfn,
- min(chunk->end_pfn, max_pfn));
- }
- /* for out of order entries in SRAT */
- sort_node_map();
-
- for_each_online_node(nid) {
- unsigned long start = node_start_pfn[nid];
- unsigned long end = min(node_end_pfn[nid], max_pfn);
-
- memory_present(nid, start, end);
- node_remap_size[nid] = node_memmap_size_bytes(nid, start, end);
- }
- return 1;
-out_fail:
- printk(KERN_DEBUG "failed to get NUMA memory information from SRAT"
- " table\n");
- return 0;
-}
diff --git a/arch/x86/net/Makefile b/arch/x86/net/Makefile
new file mode 100644
index 000000000000..90568c33ddb0
--- /dev/null
+++ b/arch/x86/net/Makefile
@@ -0,0 +1,4 @@
+#
+# Arch-specific network modules
+#
+obj-$(CONFIG_BPF_JIT) += bpf_jit.o bpf_jit_comp.o
diff --git a/arch/x86/net/bpf_jit.S b/arch/x86/net/bpf_jit.S
new file mode 100644
index 000000000000..66870223f8c5
--- /dev/null
+++ b/arch/x86/net/bpf_jit.S
@@ -0,0 +1,140 @@
+/* bpf_jit.S : BPF JIT helper functions
+ *
+ * Copyright (C) 2011 Eric Dumazet (eric.dumazet@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/linkage.h>
+#include <asm/dwarf2.h>
+
+/*
+ * Calling convention :
+ * rdi : skb pointer
+ * esi : offset of byte(s) to fetch in skb (can be scratched)
+ * r8 : copy of skb->data
+ * r9d : hlen = skb->len - skb->data_len
+ */
+#define SKBDATA %r8
+
+sk_load_word_ind:
+ .globl sk_load_word_ind
+
+ add %ebx,%esi /* offset += X */
+# test %esi,%esi /* if (offset < 0) goto bpf_error; */
+ js bpf_error
+
+sk_load_word:
+ .globl sk_load_word
+
+ mov %r9d,%eax # hlen
+ sub %esi,%eax # hlen - offset
+ cmp $3,%eax
+ jle bpf_slow_path_word
+ mov (SKBDATA,%rsi),%eax
+ bswap %eax /* ntohl() */
+ ret
+
+
+sk_load_half_ind:
+ .globl sk_load_half_ind
+
+ add %ebx,%esi /* offset += X */
+ js bpf_error
+
+sk_load_half:
+ .globl sk_load_half
+
+ mov %r9d,%eax
+ sub %esi,%eax # hlen - offset
+ cmp $1,%eax
+ jle bpf_slow_path_half
+ movzwl (SKBDATA,%rsi),%eax
+ rol $8,%ax # ntohs()
+ ret
+
+sk_load_byte_ind:
+ .globl sk_load_byte_ind
+ add %ebx,%esi /* offset += X */
+ js bpf_error
+
+sk_load_byte:
+ .globl sk_load_byte
+
+ cmp %esi,%r9d /* if (offset >= hlen) goto bpf_slow_path_byte */
+ jle bpf_slow_path_byte
+ movzbl (SKBDATA,%rsi),%eax
+ ret
+
+/**
+ * sk_load_byte_msh - BPF_S_LDX_B_MSH helper
+ *
+ * Implements BPF_S_LDX_B_MSH : ldxb 4*([offset]&0xf)
+ * Must preserve A accumulator (%eax)
+ * Inputs : %esi is the offset value, already known positive
+ */
+ENTRY(sk_load_byte_msh)
+ CFI_STARTPROC
+ cmp %esi,%r9d /* if (offset >= hlen) goto bpf_slow_path_byte_msh */
+ jle bpf_slow_path_byte_msh
+ movzbl (SKBDATA,%rsi),%ebx
+ and $15,%bl
+ shl $2,%bl
+ ret
+ CFI_ENDPROC
+ENDPROC(sk_load_byte_msh)
+
+bpf_error:
+# force a return 0 from jit handler
+ xor %eax,%eax
+ mov -8(%rbp),%rbx
+ leaveq
+ ret
+
+/* rsi contains offset and can be scratched */
+#define bpf_slow_path_common(LEN) \
+ push %rdi; /* save skb */ \
+ push %r9; \
+ push SKBDATA; \
+/* rsi already has offset */ \
+ mov $LEN,%ecx; /* len */ \
+ lea -12(%rbp),%rdx; \
+ call skb_copy_bits; \
+ test %eax,%eax; \
+ pop SKBDATA; \
+ pop %r9; \
+ pop %rdi
+
+
+bpf_slow_path_word:
+ bpf_slow_path_common(4)
+ js bpf_error
+ mov -12(%rbp),%eax
+ bswap %eax
+ ret
+
+bpf_slow_path_half:
+ bpf_slow_path_common(2)
+ js bpf_error
+ mov -12(%rbp),%ax
+ rol $8,%ax
+ movzwl %ax,%eax
+ ret
+
+bpf_slow_path_byte:
+ bpf_slow_path_common(1)
+ js bpf_error
+ movzbl -12(%rbp),%eax
+ ret
+
+bpf_slow_path_byte_msh:
+ xchg %eax,%ebx /* dont lose A , X is about to be scratched */
+ bpf_slow_path_common(1)
+ js bpf_error
+ movzbl -12(%rbp),%eax
+ and $15,%al
+ shl $2,%al
+ xchg %eax,%ebx
+ ret
diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
new file mode 100644
index 000000000000..bfab3fa10edc
--- /dev/null
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -0,0 +1,654 @@
+/* bpf_jit_comp.c : BPF JIT compiler
+ *
+ * Copyright (C) 2011 Eric Dumazet (eric.dumazet@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/moduleloader.h>
+#include <asm/cacheflush.h>
+#include <linux/netdevice.h>
+#include <linux/filter.h>
+
+/*
+ * Conventions :
+ * EAX : BPF A accumulator
+ * EBX : BPF X accumulator
+ * RDI : pointer to skb (first argument given to JIT function)
+ * RBP : frame pointer (even if CONFIG_FRAME_POINTER=n)
+ * ECX,EDX,ESI : scratch registers
+ * r9d : skb->len - skb->data_len (headlen)
+ * r8 : skb->data
+ * -8(RBP) : saved RBX value
+ * -16(RBP)..-80(RBP) : BPF_MEMWORDS values
+ */
+int bpf_jit_enable __read_mostly;
+
+/*
+ * assembly code in arch/x86/net/bpf_jit.S
+ */
+extern u8 sk_load_word[], sk_load_half[], sk_load_byte[], sk_load_byte_msh[];
+extern u8 sk_load_word_ind[], sk_load_half_ind[], sk_load_byte_ind[];
+
+static inline u8 *emit_code(u8 *ptr, u32 bytes, unsigned int len)
+{
+ if (len == 1)
+ *ptr = bytes;
+ else if (len == 2)
+ *(u16 *)ptr = bytes;
+ else {
+ *(u32 *)ptr = bytes;
+ barrier();
+ }
+ return ptr + len;
+}
+
+#define EMIT(bytes, len) do { prog = emit_code(prog, bytes, len); } while (0)
+
+#define EMIT1(b1) EMIT(b1, 1)
+#define EMIT2(b1, b2) EMIT((b1) + ((b2) << 8), 2)
+#define EMIT3(b1, b2, b3) EMIT((b1) + ((b2) << 8) + ((b3) << 16), 3)
+#define EMIT4(b1, b2, b3, b4) EMIT((b1) + ((b2) << 8) + ((b3) << 16) + ((b4) << 24), 4)
+#define EMIT1_off32(b1, off) do { EMIT1(b1); EMIT(off, 4);} while (0)
+
+#define CLEAR_A() EMIT2(0x31, 0xc0) /* xor %eax,%eax */
+#define CLEAR_X() EMIT2(0x31, 0xdb) /* xor %ebx,%ebx */
+
+static inline bool is_imm8(int value)
+{
+ return value <= 127 && value >= -128;
+}
+
+static inline bool is_near(int offset)
+{
+ return offset <= 127 && offset >= -128;
+}
+
+#define EMIT_JMP(offset) \
+do { \
+ if (offset) { \
+ if (is_near(offset)) \
+ EMIT2(0xeb, offset); /* jmp .+off8 */ \
+ else \
+ EMIT1_off32(0xe9, offset); /* jmp .+off32 */ \
+ } \
+} while (0)
+
+/* list of x86 cond jumps opcodes (. + s8)
+ * Add 0x10 (and an extra 0x0f) to generate far jumps (. + s32)
+ */
+#define X86_JB 0x72
+#define X86_JAE 0x73
+#define X86_JE 0x74
+#define X86_JNE 0x75
+#define X86_JBE 0x76
+#define X86_JA 0x77
+
+#define EMIT_COND_JMP(op, offset) \
+do { \
+ if (is_near(offset)) \
+ EMIT2(op, offset); /* jxx .+off8 */ \
+ else { \
+ EMIT2(0x0f, op + 0x10); \
+ EMIT(offset, 4); /* jxx .+off32 */ \
+ } \
+} while (0)
+
+#define COND_SEL(CODE, TOP, FOP) \
+ case CODE: \
+ t_op = TOP; \
+ f_op = FOP; \
+ goto cond_branch
+
+
+#define SEEN_DATAREF 1 /* might call external helpers */
+#define SEEN_XREG 2 /* ebx is used */
+#define SEEN_MEM 4 /* use mem[] for temporary storage */
+
+static inline void bpf_flush_icache(void *start, void *end)
+{
+ mm_segment_t old_fs = get_fs();
+
+ set_fs(KERNEL_DS);
+ smp_wmb();
+ flush_icache_range((unsigned long)start, (unsigned long)end);
+ set_fs(old_fs);
+}
+
+
+void bpf_jit_compile(struct sk_filter *fp)
+{
+ u8 temp[64];
+ u8 *prog;
+ unsigned int proglen, oldproglen = 0;
+ int ilen, i;
+ int t_offset, f_offset;
+ u8 t_op, f_op, seen = 0, pass;
+ u8 *image = NULL;
+ u8 *func;
+ int pc_ret0 = -1; /* bpf index of first RET #0 instruction (if any) */
+ unsigned int cleanup_addr; /* epilogue code offset */
+ unsigned int *addrs;
+ const struct sock_filter *filter = fp->insns;
+ int flen = fp->len;
+
+ if (!bpf_jit_enable)
+ return;
+
+ addrs = kmalloc(flen * sizeof(*addrs), GFP_KERNEL);
+ if (addrs == NULL)
+ return;
+
+ /* Before first pass, make a rough estimation of addrs[]
+ * each bpf instruction is translated to less than 64 bytes
+ */
+ for (proglen = 0, i = 0; i < flen; i++) {
+ proglen += 64;
+ addrs[i] = proglen;
+ }
+ cleanup_addr = proglen; /* epilogue address */
+
+ for (pass = 0; pass < 10; pass++) {
+ /* no prologue/epilogue for trivial filters (RET something) */
+ proglen = 0;
+ prog = temp;
+
+ if (seen) {
+ EMIT4(0x55, 0x48, 0x89, 0xe5); /* push %rbp; mov %rsp,%rbp */
+ EMIT4(0x48, 0x83, 0xec, 96); /* subq $96,%rsp */
+ /* note : must save %rbx in case bpf_error is hit */
+ if (seen & (SEEN_XREG | SEEN_DATAREF))
+ EMIT4(0x48, 0x89, 0x5d, 0xf8); /* mov %rbx, -8(%rbp) */
+ if (seen & SEEN_XREG)
+ CLEAR_X(); /* make sure we dont leek kernel memory */
+
+ /*
+ * If this filter needs to access skb data,
+ * loads r9 and r8 with :
+ * r9 = skb->len - skb->data_len
+ * r8 = skb->data
+ */
+ if (seen & SEEN_DATAREF) {
+ if (offsetof(struct sk_buff, len) <= 127)
+ /* mov off8(%rdi),%r9d */
+ EMIT4(0x44, 0x8b, 0x4f, offsetof(struct sk_buff, len));
+ else {
+ /* mov off32(%rdi),%r9d */
+ EMIT3(0x44, 0x8b, 0x8f);
+ EMIT(offsetof(struct sk_buff, len), 4);
+ }
+ if (is_imm8(offsetof(struct sk_buff, data_len)))
+ /* sub off8(%rdi),%r9d */
+ EMIT4(0x44, 0x2b, 0x4f, offsetof(struct sk_buff, data_len));
+ else {
+ EMIT3(0x44, 0x2b, 0x8f);
+ EMIT(offsetof(struct sk_buff, data_len), 4);
+ }
+
+ if (is_imm8(offsetof(struct sk_buff, data)))
+ /* mov off8(%rdi),%r8 */
+ EMIT4(0x4c, 0x8b, 0x47, offsetof(struct sk_buff, data));
+ else {
+ /* mov off32(%rdi),%r8 */
+ EMIT3(0x4c, 0x8b, 0x87);
+ EMIT(offsetof(struct sk_buff, data), 4);
+ }
+ }
+ }
+
+ switch (filter[0].code) {
+ case BPF_S_RET_K:
+ case BPF_S_LD_W_LEN:
+ case BPF_S_ANC_PROTOCOL:
+ case BPF_S_ANC_IFINDEX:
+ case BPF_S_ANC_MARK:
+ case BPF_S_ANC_RXHASH:
+ case BPF_S_ANC_CPU:
+ case BPF_S_ANC_QUEUE:
+ case BPF_S_LD_W_ABS:
+ case BPF_S_LD_H_ABS:
+ case BPF_S_LD_B_ABS:
+ /* first instruction sets A register (or is RET 'constant') */
+ break;
+ default:
+ /* make sure we dont leak kernel information to user */
+ CLEAR_A(); /* A = 0 */
+ }
+
+ for (i = 0; i < flen; i++) {
+ unsigned int K = filter[i].k;
+
+ switch (filter[i].code) {
+ case BPF_S_ALU_ADD_X: /* A += X; */
+ seen |= SEEN_XREG;
+ EMIT2(0x01, 0xd8); /* add %ebx,%eax */
+ break;
+ case BPF_S_ALU_ADD_K: /* A += K; */
+ if (!K)
+ break;
+ if (is_imm8(K))
+ EMIT3(0x83, 0xc0, K); /* add imm8,%eax */
+ else
+ EMIT1_off32(0x05, K); /* add imm32,%eax */
+ break;
+ case BPF_S_ALU_SUB_X: /* A -= X; */
+ seen |= SEEN_XREG;
+ EMIT2(0x29, 0xd8); /* sub %ebx,%eax */
+ break;
+ case BPF_S_ALU_SUB_K: /* A -= K */
+ if (!K)
+ break;
+ if (is_imm8(K))
+ EMIT3(0x83, 0xe8, K); /* sub imm8,%eax */
+ else
+ EMIT1_off32(0x2d, K); /* sub imm32,%eax */
+ break;
+ case BPF_S_ALU_MUL_X: /* A *= X; */
+ seen |= SEEN_XREG;
+ EMIT3(0x0f, 0xaf, 0xc3); /* imul %ebx,%eax */
+ break;
+ case BPF_S_ALU_MUL_K: /* A *= K */
+ if (is_imm8(K))
+ EMIT3(0x6b, 0xc0, K); /* imul imm8,%eax,%eax */
+ else {
+ EMIT2(0x69, 0xc0); /* imul imm32,%eax */
+ EMIT(K, 4);
+ }
+ break;
+ case BPF_S_ALU_DIV_X: /* A /= X; */
+ seen |= SEEN_XREG;
+ EMIT2(0x85, 0xdb); /* test %ebx,%ebx */
+ if (pc_ret0 != -1)
+ EMIT_COND_JMP(X86_JE, addrs[pc_ret0] - (addrs[i] - 4));
+ else {
+ EMIT_COND_JMP(X86_JNE, 2 + 5);
+ CLEAR_A();
+ EMIT1_off32(0xe9, cleanup_addr - (addrs[i] - 4)); /* jmp .+off32 */
+ }
+ EMIT4(0x31, 0xd2, 0xf7, 0xf3); /* xor %edx,%edx; div %ebx */
+ break;
+ case BPF_S_ALU_DIV_K: /* A = reciprocal_divide(A, K); */
+ EMIT3(0x48, 0x69, 0xc0); /* imul imm32,%rax,%rax */
+ EMIT(K, 4);
+ EMIT4(0x48, 0xc1, 0xe8, 0x20); /* shr $0x20,%rax */
+ break;
+ case BPF_S_ALU_AND_X:
+ seen |= SEEN_XREG;
+ EMIT2(0x21, 0xd8); /* and %ebx,%eax */
+ break;
+ case BPF_S_ALU_AND_K:
+ if (K >= 0xFFFFFF00) {
+ EMIT2(0x24, K & 0xFF); /* and imm8,%al */
+ } else if (K >= 0xFFFF0000) {
+ EMIT2(0x66, 0x25); /* and imm16,%ax */
+ EMIT2(K, 2);
+ } else {
+ EMIT1_off32(0x25, K); /* and imm32,%eax */
+ }
+ break;
+ case BPF_S_ALU_OR_X:
+ seen |= SEEN_XREG;
+ EMIT2(0x09, 0xd8); /* or %ebx,%eax */
+ break;
+ case BPF_S_ALU_OR_K:
+ if (is_imm8(K))
+ EMIT3(0x83, 0xc8, K); /* or imm8,%eax */
+ else
+ EMIT1_off32(0x0d, K); /* or imm32,%eax */
+ break;
+ case BPF_S_ALU_LSH_X: /* A <<= X; */
+ seen |= SEEN_XREG;
+ EMIT4(0x89, 0xd9, 0xd3, 0xe0); /* mov %ebx,%ecx; shl %cl,%eax */
+ break;
+ case BPF_S_ALU_LSH_K:
+ if (K == 0)
+ break;
+ else if (K == 1)
+ EMIT2(0xd1, 0xe0); /* shl %eax */
+ else
+ EMIT3(0xc1, 0xe0, K);
+ break;
+ case BPF_S_ALU_RSH_X: /* A >>= X; */
+ seen |= SEEN_XREG;
+ EMIT4(0x89, 0xd9, 0xd3, 0xe8); /* mov %ebx,%ecx; shr %cl,%eax */
+ break;
+ case BPF_S_ALU_RSH_K: /* A >>= K; */
+ if (K == 0)
+ break;
+ else if (K == 1)
+ EMIT2(0xd1, 0xe8); /* shr %eax */
+ else
+ EMIT3(0xc1, 0xe8, K);
+ break;
+ case BPF_S_ALU_NEG:
+ EMIT2(0xf7, 0xd8); /* neg %eax */
+ break;
+ case BPF_S_RET_K:
+ if (!K) {
+ if (pc_ret0 == -1)
+ pc_ret0 = i;
+ CLEAR_A();
+ } else {
+ EMIT1_off32(0xb8, K); /* mov $imm32,%eax */
+ }
+ /* fallinto */
+ case BPF_S_RET_A:
+ if (seen) {
+ if (i != flen - 1) {
+ EMIT_JMP(cleanup_addr - addrs[i]);
+ break;
+ }
+ if (seen & SEEN_XREG)
+ EMIT4(0x48, 0x8b, 0x5d, 0xf8); /* mov -8(%rbp),%rbx */
+ EMIT1(0xc9); /* leaveq */
+ }
+ EMIT1(0xc3); /* ret */
+ break;
+ case BPF_S_MISC_TAX: /* X = A */
+ seen |= SEEN_XREG;
+ EMIT2(0x89, 0xc3); /* mov %eax,%ebx */
+ break;
+ case BPF_S_MISC_TXA: /* A = X */
+ seen |= SEEN_XREG;
+ EMIT2(0x89, 0xd8); /* mov %ebx,%eax */
+ break;
+ case BPF_S_LD_IMM: /* A = K */
+ if (!K)
+ CLEAR_A();
+ else
+ EMIT1_off32(0xb8, K); /* mov $imm32,%eax */
+ break;
+ case BPF_S_LDX_IMM: /* X = K */
+ seen |= SEEN_XREG;
+ if (!K)
+ CLEAR_X();
+ else
+ EMIT1_off32(0xbb, K); /* mov $imm32,%ebx */
+ break;
+ case BPF_S_LD_MEM: /* A = mem[K] : mov off8(%rbp),%eax */
+ seen |= SEEN_MEM;
+ EMIT3(0x8b, 0x45, 0xf0 - K*4);
+ break;
+ case BPF_S_LDX_MEM: /* X = mem[K] : mov off8(%rbp),%ebx */
+ seen |= SEEN_XREG | SEEN_MEM;
+ EMIT3(0x8b, 0x5d, 0xf0 - K*4);
+ break;
+ case BPF_S_ST: /* mem[K] = A : mov %eax,off8(%rbp) */
+ seen |= SEEN_MEM;
+ EMIT3(0x89, 0x45, 0xf0 - K*4);
+ break;
+ case BPF_S_STX: /* mem[K] = X : mov %ebx,off8(%rbp) */
+ seen |= SEEN_XREG | SEEN_MEM;
+ EMIT3(0x89, 0x5d, 0xf0 - K*4);
+ break;
+ case BPF_S_LD_W_LEN: /* A = skb->len; */
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4);
+ if (is_imm8(offsetof(struct sk_buff, len)))
+ /* mov off8(%rdi),%eax */
+ EMIT3(0x8b, 0x47, offsetof(struct sk_buff, len));
+ else {
+ EMIT2(0x8b, 0x87);
+ EMIT(offsetof(struct sk_buff, len), 4);
+ }
+ break;
+ case BPF_S_LDX_W_LEN: /* X = skb->len; */
+ seen |= SEEN_XREG;
+ if (is_imm8(offsetof(struct sk_buff, len)))
+ /* mov off8(%rdi),%ebx */
+ EMIT3(0x8b, 0x5f, offsetof(struct sk_buff, len));
+ else {
+ EMIT2(0x8b, 0x9f);
+ EMIT(offsetof(struct sk_buff, len), 4);
+ }
+ break;
+ case BPF_S_ANC_PROTOCOL: /* A = ntohs(skb->protocol); */
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, protocol) != 2);
+ if (is_imm8(offsetof(struct sk_buff, protocol))) {
+ /* movzwl off8(%rdi),%eax */
+ EMIT4(0x0f, 0xb7, 0x47, offsetof(struct sk_buff, protocol));
+ } else {
+ EMIT3(0x0f, 0xb7, 0x87); /* movzwl off32(%rdi),%eax */
+ EMIT(offsetof(struct sk_buff, protocol), 4);
+ }
+ EMIT2(0x86, 0xc4); /* ntohs() : xchg %al,%ah */
+ break;
+ case BPF_S_ANC_IFINDEX:
+ if (is_imm8(offsetof(struct sk_buff, dev))) {
+ /* movq off8(%rdi),%rax */
+ EMIT4(0x48, 0x8b, 0x47, offsetof(struct sk_buff, dev));
+ } else {
+ EMIT3(0x48, 0x8b, 0x87); /* movq off32(%rdi),%rax */
+ EMIT(offsetof(struct sk_buff, dev), 4);
+ }
+ EMIT3(0x48, 0x85, 0xc0); /* test %rax,%rax */
+ EMIT_COND_JMP(X86_JE, cleanup_addr - (addrs[i] - 6));
+ BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, ifindex) != 4);
+ EMIT2(0x8b, 0x80); /* mov off32(%rax),%eax */
+ EMIT(offsetof(struct net_device, ifindex), 4);
+ break;
+ case BPF_S_ANC_MARK:
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4);
+ if (is_imm8(offsetof(struct sk_buff, mark))) {
+ /* mov off8(%rdi),%eax */
+ EMIT3(0x8b, 0x47, offsetof(struct sk_buff, mark));
+ } else {
+ EMIT2(0x8b, 0x87);
+ EMIT(offsetof(struct sk_buff, mark), 4);
+ }
+ break;
+ case BPF_S_ANC_RXHASH:
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4);
+ if (is_imm8(offsetof(struct sk_buff, rxhash))) {
+ /* mov off8(%rdi),%eax */
+ EMIT3(0x8b, 0x47, offsetof(struct sk_buff, rxhash));
+ } else {
+ EMIT2(0x8b, 0x87);
+ EMIT(offsetof(struct sk_buff, rxhash), 4);
+ }
+ break;
+ case BPF_S_ANC_QUEUE:
+ BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, queue_mapping) != 2);
+ if (is_imm8(offsetof(struct sk_buff, queue_mapping))) {
+ /* movzwl off8(%rdi),%eax */
+ EMIT4(0x0f, 0xb7, 0x47, offsetof(struct sk_buff, queue_mapping));
+ } else {
+ EMIT3(0x0f, 0xb7, 0x87); /* movzwl off32(%rdi),%eax */
+ EMIT(offsetof(struct sk_buff, queue_mapping), 4);
+ }
+ break;
+ case BPF_S_ANC_CPU:
+#ifdef CONFIG_SMP
+ EMIT4(0x65, 0x8b, 0x04, 0x25); /* mov %gs:off32,%eax */
+ EMIT((u32)(unsigned long)&cpu_number, 4); /* A = smp_processor_id(); */
+#else
+ CLEAR_A();
+#endif
+ break;
+ case BPF_S_LD_W_ABS:
+ func = sk_load_word;
+common_load: seen |= SEEN_DATAREF;
+ if ((int)K < 0)
+ goto out;
+ t_offset = func - (image + addrs[i]);
+ EMIT1_off32(0xbe, K); /* mov imm32,%esi */
+ EMIT1_off32(0xe8, t_offset); /* call */
+ break;
+ case BPF_S_LD_H_ABS:
+ func = sk_load_half;
+ goto common_load;
+ case BPF_S_LD_B_ABS:
+ func = sk_load_byte;
+ goto common_load;
+ case BPF_S_LDX_B_MSH:
+ if ((int)K < 0) {
+ if (pc_ret0 != -1) {
+ EMIT_JMP(addrs[pc_ret0] - addrs[i]);
+ break;
+ }
+ CLEAR_A();
+ EMIT_JMP(cleanup_addr - addrs[i]);
+ break;
+ }
+ seen |= SEEN_DATAREF | SEEN_XREG;
+ t_offset = sk_load_byte_msh - (image + addrs[i]);
+ EMIT1_off32(0xbe, K); /* mov imm32,%esi */
+ EMIT1_off32(0xe8, t_offset); /* call sk_load_byte_msh */
+ break;
+ case BPF_S_LD_W_IND:
+ func = sk_load_word_ind;
+common_load_ind: seen |= SEEN_DATAREF | SEEN_XREG;
+ t_offset = func - (image + addrs[i]);
+ EMIT1_off32(0xbe, K); /* mov imm32,%esi */
+ EMIT1_off32(0xe8, t_offset); /* call sk_load_xxx_ind */
+ break;
+ case BPF_S_LD_H_IND:
+ func = sk_load_half_ind;
+ goto common_load_ind;
+ case BPF_S_LD_B_IND:
+ func = sk_load_byte_ind;
+ goto common_load_ind;
+ case BPF_S_JMP_JA:
+ t_offset = addrs[i + K] - addrs[i];
+ EMIT_JMP(t_offset);
+ break;
+ COND_SEL(BPF_S_JMP_JGT_K, X86_JA, X86_JBE);
+ COND_SEL(BPF_S_JMP_JGE_K, X86_JAE, X86_JB);
+ COND_SEL(BPF_S_JMP_JEQ_K, X86_JE, X86_JNE);
+ COND_SEL(BPF_S_JMP_JSET_K,X86_JNE, X86_JE);
+ COND_SEL(BPF_S_JMP_JGT_X, X86_JA, X86_JBE);
+ COND_SEL(BPF_S_JMP_JGE_X, X86_JAE, X86_JB);
+ COND_SEL(BPF_S_JMP_JEQ_X, X86_JE, X86_JNE);
+ COND_SEL(BPF_S_JMP_JSET_X,X86_JNE, X86_JE);
+
+cond_branch: f_offset = addrs[i + filter[i].jf] - addrs[i];
+ t_offset = addrs[i + filter[i].jt] - addrs[i];
+
+ /* same targets, can avoid doing the test :) */
+ if (filter[i].jt == filter[i].jf) {
+ EMIT_JMP(t_offset);
+ break;
+ }
+
+ switch (filter[i].code) {
+ case BPF_S_JMP_JGT_X:
+ case BPF_S_JMP_JGE_X:
+ case BPF_S_JMP_JEQ_X:
+ seen |= SEEN_XREG;
+ EMIT2(0x39, 0xd8); /* cmp %ebx,%eax */
+ break;
+ case BPF_S_JMP_JSET_X:
+ seen |= SEEN_XREG;
+ EMIT2(0x85, 0xd8); /* test %ebx,%eax */
+ break;
+ case BPF_S_JMP_JEQ_K:
+ if (K == 0) {
+ EMIT2(0x85, 0xc0); /* test %eax,%eax */
+ break;
+ }
+ case BPF_S_JMP_JGT_K:
+ case BPF_S_JMP_JGE_K:
+ if (K <= 127)
+ EMIT3(0x83, 0xf8, K); /* cmp imm8,%eax */
+ else
+ EMIT1_off32(0x3d, K); /* cmp imm32,%eax */
+ break;
+ case BPF_S_JMP_JSET_K:
+ if (K <= 0xFF)
+ EMIT2(0xa8, K); /* test imm8,%al */
+ else if (!(K & 0xFFFF00FF))
+ EMIT3(0xf6, 0xc4, K >> 8); /* test imm8,%ah */
+ else if (K <= 0xFFFF) {
+ EMIT2(0x66, 0xa9); /* test imm16,%ax */
+ EMIT(K, 2);
+ } else {
+ EMIT1_off32(0xa9, K); /* test imm32,%eax */
+ }
+ break;
+ }
+ if (filter[i].jt != 0) {
+ if (filter[i].jf)
+ t_offset += is_near(f_offset) ? 2 : 6;
+ EMIT_COND_JMP(t_op, t_offset);
+ if (filter[i].jf)
+ EMIT_JMP(f_offset);
+ break;
+ }
+ EMIT_COND_JMP(f_op, f_offset);
+ break;
+ default:
+ /* hmm, too complex filter, give up with jit compiler */
+ goto out;
+ }
+ ilen = prog - temp;
+ if (image) {
+ if (unlikely(proglen + ilen > oldproglen)) {
+ pr_err("bpb_jit_compile fatal error\n");
+ kfree(addrs);
+ module_free(NULL, image);
+ return;
+ }
+ memcpy(image + proglen, temp, ilen);
+ }
+ proglen += ilen;
+ addrs[i] = proglen;
+ prog = temp;
+ }
+ /* last bpf instruction is always a RET :
+ * use it to give the cleanup instruction(s) addr
+ */
+ cleanup_addr = proglen - 1; /* ret */
+ if (seen)
+ cleanup_addr -= 1; /* leaveq */
+ if (seen & SEEN_XREG)
+ cleanup_addr -= 4; /* mov -8(%rbp),%rbx */
+
+ if (image) {
+ WARN_ON(proglen != oldproglen);
+ break;
+ }
+ if (proglen == oldproglen) {
+ image = module_alloc(max_t(unsigned int,
+ proglen,
+ sizeof(struct work_struct)));
+ if (!image)
+ goto out;
+ }
+ oldproglen = proglen;
+ }
+ if (bpf_jit_enable > 1)
+ pr_err("flen=%d proglen=%u pass=%d image=%p\n",
+ flen, proglen, pass, image);
+
+ if (image) {
+ if (bpf_jit_enable > 1)
+ print_hex_dump(KERN_ERR, "JIT code: ", DUMP_PREFIX_ADDRESS,
+ 16, 1, image, proglen, false);
+
+ bpf_flush_icache(image, image + proglen);
+
+ fp->bpf_func = (void *)image;
+ }
+out:
+ kfree(addrs);
+ return;
+}
+
+static void jit_free_defer(struct work_struct *arg)
+{
+ module_free(NULL, arg);
+}
+
+/* run from softirq, we must use a work_struct to call
+ * module_free() from process context
+ */
+void bpf_jit_free(struct sk_filter *fp)
+{
+ if (fp->bpf_func != sk_run_filter) {
+ struct work_struct *work = (struct work_struct *)fp->bpf_func;
+
+ INIT_WORK(work, jit_free_defer);
+ schedule_work(work);
+ }
+}
diff --git a/arch/x86/oprofile/backtrace.c b/arch/x86/oprofile/backtrace.c
index 2d49d4e19a36..a5b64ab4cd6e 100644
--- a/arch/x86/oprofile/backtrace.c
+++ b/arch/x86/oprofile/backtrace.c
@@ -16,17 +16,6 @@
#include <asm/stacktrace.h>
#include <linux/compat.h>
-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)
{
/* Yes, we want all stacks */
@@ -42,8 +31,6 @@ static void backtrace_address(void *data, unsigned long addr, int reliable)
}
static struct stacktrace_ops backtrace_ops = {
- .warning = backtrace_warning,
- .warning_symbol = backtrace_warning_symbol,
.stack = backtrace_stack,
.address = backtrace_address,
.walk_stack = print_context_stack,
diff --git a/arch/x86/pci/direct.c b/arch/x86/pci/direct.c
index bd33620b0071..e6fd8473fb7b 100644
--- a/arch/x86/pci/direct.c
+++ b/arch/x86/pci/direct.c
@@ -280,12 +280,9 @@ void __init pci_direct_init(int type)
int __init pci_direct_probe(void)
{
- struct resource *region, *region2;
-
if ((pci_probe & PCI_PROBE_CONF1) == 0)
goto type2;
- region = request_region(0xCF8, 8, "PCI conf1");
- if (!region)
+ if (!request_region(0xCF8, 8, "PCI conf1"))
goto type2;
if (pci_check_type1()) {
@@ -293,16 +290,14 @@ int __init pci_direct_probe(void)
port_cf9_safe = true;
return 1;
}
- release_resource(region);
+ release_region(0xCF8, 8);
type2:
if ((pci_probe & PCI_PROBE_CONF2) == 0)
return 0;
- region = request_region(0xCF8, 4, "PCI conf2");
- if (!region)
+ if (!request_region(0xCF8, 4, "PCI conf2"))
return 0;
- region2 = request_region(0xC000, 0x1000, "PCI conf2");
- if (!region2)
+ if (!request_region(0xC000, 0x1000, "PCI conf2"))
goto fail2;
if (pci_check_type2()) {
@@ -311,8 +306,8 @@ int __init pci_direct_probe(void)
return 2;
}
- release_resource(region2);
+ release_region(0xC000, 0x1000);
fail2:
- release_resource(region);
+ release_region(0xCF8, 4);
return 0;
}
diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c
index 8201165bae28..372e9b8989b3 100644
--- a/arch/x86/pci/irq.c
+++ b/arch/x86/pci/irq.c
@@ -602,7 +602,9 @@ static __init int intel_router_probe(struct irq_router *r, struct pci_dev *route
|| (device >= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN &&
device <= PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX)
|| (device >= PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MIN &&
- device <= PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MAX)) {
+ device <= PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MAX)
+ || (device >= PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MIN &&
+ device <= PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MAX)) {
r->name = "PIIX/ICH";
r->get = pirq_piix_get;
r->set = pirq_piix_set;
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c
index e282886616a0..750c346ef50a 100644
--- a/arch/x86/pci/mmconfig-shared.c
+++ b/arch/x86/pci/mmconfig-shared.c
@@ -606,6 +606,16 @@ static void __init __pci_mmcfg_init(int early)
if (list_empty(&pci_mmcfg_list))
return;
+ if (pcibios_last_bus < 0) {
+ const struct pci_mmcfg_region *cfg;
+
+ list_for_each_entry(cfg, &pci_mmcfg_list, list) {
+ if (cfg->segment)
+ break;
+ pcibios_last_bus = cfg->end_bus;
+ }
+ }
+
if (pci_mmcfg_arch_init())
pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
else {
diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
index e37b407a0ee8..8214724ce54d 100644
--- a/arch/x86/pci/xen.c
+++ b/arch/x86/pci/xen.c
@@ -108,7 +108,8 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
}
irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq, 0,
(type == PCI_CAP_ID_MSIX) ?
- "msi-x" : "msi");
+ "msi-x" : "msi",
+ DOMID_SELF);
if (irq < 0)
goto error;
dev_dbg(&dev->dev,
@@ -148,7 +149,8 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i], 0,
(type == PCI_CAP_ID_MSIX) ?
"pcifront-msi-x" :
- "pcifront-msi");
+ "pcifront-msi",
+ DOMID_SELF);
if (irq < 0)
goto free;
i++;
@@ -190,9 +192,16 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
list_for_each_entry(msidesc, &dev->msi_list, list) {
struct physdev_map_pirq map_irq;
+ domid_t domid;
+
+ domid = ret = xen_find_device_domain_owner(dev);
+ /* N.B. Casting int's -ENODEV to uint16_t results in 0xFFED,
+ * hence check ret value for < 0. */
+ if (ret < 0)
+ domid = DOMID_SELF;
memset(&map_irq, 0, sizeof(map_irq));
- map_irq.domid = DOMID_SELF;
+ map_irq.domid = domid;
map_irq.type = MAP_PIRQ_TYPE_MSI;
map_irq.index = -1;
map_irq.pirq = -1;
@@ -215,14 +224,16 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
if (ret) {
- dev_warn(&dev->dev, "xen map irq failed %d\n", ret);
+ dev_warn(&dev->dev, "xen map irq failed %d for %d domain\n",
+ ret, domid);
goto out;
}
ret = xen_bind_pirq_msi_to_irq(dev, msidesc,
map_irq.pirq, map_irq.index,
(type == PCI_CAP_ID_MSIX) ?
- "msi-x" : "msi");
+ "msi-x" : "msi",
+ domid);
if (ret < 0)
goto out;
}
@@ -461,3 +472,78 @@ void __init xen_setup_pirqs(void)
}
}
#endif
+
+#ifdef CONFIG_XEN_DOM0
+struct xen_device_domain_owner {
+ domid_t domain;
+ struct pci_dev *dev;
+ struct list_head list;
+};
+
+static DEFINE_SPINLOCK(dev_domain_list_spinlock);
+static struct list_head dev_domain_list = LIST_HEAD_INIT(dev_domain_list);
+
+static struct xen_device_domain_owner *find_device(struct pci_dev *dev)
+{
+ struct xen_device_domain_owner *owner;
+
+ list_for_each_entry(owner, &dev_domain_list, list) {
+ if (owner->dev == dev)
+ return owner;
+ }
+ return NULL;
+}
+
+int xen_find_device_domain_owner(struct pci_dev *dev)
+{
+ struct xen_device_domain_owner *owner;
+ int domain = -ENODEV;
+
+ spin_lock(&dev_domain_list_spinlock);
+ owner = find_device(dev);
+ if (owner)
+ domain = owner->domain;
+ spin_unlock(&dev_domain_list_spinlock);
+ return domain;
+}
+EXPORT_SYMBOL_GPL(xen_find_device_domain_owner);
+
+int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain)
+{
+ struct xen_device_domain_owner *owner;
+
+ owner = kzalloc(sizeof(struct xen_device_domain_owner), GFP_KERNEL);
+ if (!owner)
+ return -ENODEV;
+
+ spin_lock(&dev_domain_list_spinlock);
+ if (find_device(dev)) {
+ spin_unlock(&dev_domain_list_spinlock);
+ kfree(owner);
+ return -EEXIST;
+ }
+ owner->domain = domain;
+ owner->dev = dev;
+ list_add_tail(&owner->list, &dev_domain_list);
+ spin_unlock(&dev_domain_list_spinlock);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xen_register_device_domain_owner);
+
+int xen_unregister_device_domain_owner(struct pci_dev *dev)
+{
+ struct xen_device_domain_owner *owner;
+
+ spin_lock(&dev_domain_list_spinlock);
+ owner = find_device(dev);
+ if (!owner) {
+ spin_unlock(&dev_domain_list_spinlock);
+ return -ENODEV;
+ }
+ list_del(&owner->list);
+ spin_unlock(&dev_domain_list_spinlock);
+ kfree(owner);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xen_unregister_device_domain_owner);
+#endif
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 0fe27d7c6258..b30aa26a8df2 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -145,17 +145,6 @@ static void virt_efi_reset_system(int reset_type,
data_size, data);
}
-static efi_status_t virt_efi_set_virtual_address_map(
- unsigned long memory_map_size,
- unsigned long descriptor_size,
- u32 descriptor_version,
- efi_memory_desc_t *virtual_map)
-{
- return efi_call_virt4(set_virtual_address_map,
- memory_map_size, descriptor_size,
- descriptor_version, virtual_map);
-}
-
static efi_status_t __init phys_efi_set_virtual_address_map(
unsigned long memory_map_size,
unsigned long descriptor_size,
@@ -468,11 +457,25 @@ void __init efi_init(void)
#endif
}
+void __init efi_set_executable(efi_memory_desc_t *md, bool executable)
+{
+ u64 addr, npages;
+
+ addr = md->virt_addr;
+ npages = md->num_pages;
+
+ memrange_efi_to_native(&addr, &npages);
+
+ if (executable)
+ set_memory_x(addr, npages);
+ else
+ set_memory_nx(addr, npages);
+}
+
static void __init runtime_code_page_mkexec(void)
{
efi_memory_desc_t *md;
void *p;
- u64 addr, npages;
/* Make EFI runtime service code area executable */
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
@@ -481,10 +484,7 @@ static void __init runtime_code_page_mkexec(void)
if (md->type != EFI_RUNTIME_SERVICES_CODE)
continue;
- addr = md->virt_addr;
- npages = md->num_pages;
- memrange_efi_to_native(&addr, &npages);
- set_memory_x(addr, npages);
+ efi_set_executable(md, true);
}
}
@@ -498,13 +498,42 @@ static void __init runtime_code_page_mkexec(void)
*/
void __init efi_enter_virtual_mode(void)
{
- efi_memory_desc_t *md;
+ efi_memory_desc_t *md, *prev_md = NULL;
efi_status_t status;
unsigned long size;
u64 end, systab, addr, npages, end_pfn;
- void *p, *va;
+ void *p, *va, *new_memmap = NULL;
+ int count = 0;
efi.systab = NULL;
+
+ /* Merge contiguous regions of the same type and attribute */
+ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+ u64 prev_size;
+ md = p;
+
+ if (!prev_md) {
+ prev_md = md;
+ continue;
+ }
+
+ if (prev_md->type != md->type ||
+ prev_md->attribute != md->attribute) {
+ prev_md = md;
+ continue;
+ }
+
+ prev_size = prev_md->num_pages << EFI_PAGE_SHIFT;
+
+ if (md->phys_addr == (prev_md->phys_addr + prev_size)) {
+ prev_md->num_pages += md->num_pages;
+ md->type = EFI_RESERVED_TYPE;
+ md->attribute = 0;
+ continue;
+ }
+ prev_md = md;
+ }
+
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
md = p;
if (!(md->attribute & EFI_MEMORY_RUNTIME))
@@ -541,15 +570,21 @@ void __init efi_enter_virtual_mode(void)
systab += md->virt_addr - md->phys_addr;
efi.systab = (efi_system_table_t *) (unsigned long) systab;
}
+ new_memmap = krealloc(new_memmap,
+ (count + 1) * memmap.desc_size,
+ GFP_KERNEL);
+ memcpy(new_memmap + (count * memmap.desc_size), md,
+ memmap.desc_size);
+ count++;
}
BUG_ON(!efi.systab);
status = phys_efi_set_virtual_address_map(
- memmap.desc_size * memmap.nr_map,
+ memmap.desc_size * count,
memmap.desc_size,
memmap.desc_version,
- memmap.phys_map);
+ (efi_memory_desc_t *)__pa(new_memmap));
if (status != EFI_SUCCESS) {
printk(KERN_ALERT "Unable to switch EFI into virtual mode "
@@ -572,11 +607,12 @@ void __init efi_enter_virtual_mode(void)
efi.set_variable = virt_efi_set_variable;
efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
efi.reset_system = virt_efi_reset_system;
- efi.set_virtual_address_map = virt_efi_set_virtual_address_map;
+ efi.set_virtual_address_map = NULL;
if (__supported_pte_mask & _PAGE_NX)
runtime_code_page_mkexec();
early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size);
memmap.map = NULL;
+ kfree(new_memmap);
}
/*
diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c
index ac0621a7ac3d..2649426a7905 100644
--- a/arch/x86/platform/efi/efi_64.c
+++ b/arch/x86/platform/efi/efi_64.c
@@ -41,22 +41,7 @@
static pgd_t save_pgd __initdata;
static unsigned long efi_flags __initdata;
-static void __init early_mapping_set_exec(unsigned long start,
- unsigned long end,
- int executable)
-{
- unsigned long num_pages;
-
- start &= PMD_MASK;
- end = (end + PMD_SIZE - 1) & PMD_MASK;
- num_pages = (end - start) >> PAGE_SHIFT;
- if (executable)
- set_memory_x((unsigned long)__va(start), num_pages);
- else
- set_memory_nx((unsigned long)__va(start), num_pages);
-}
-
-static void __init early_runtime_code_mapping_set_exec(int executable)
+static void __init early_code_mapping_set_exec(int executable)
{
efi_memory_desc_t *md;
void *p;
@@ -67,11 +52,8 @@ static void __init early_runtime_code_mapping_set_exec(int executable)
/* Make EFI runtime service code area executable */
for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
md = p;
- if (md->type == EFI_RUNTIME_SERVICES_CODE) {
- unsigned long end;
- end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT);
- early_mapping_set_exec(md->phys_addr, end, executable);
- }
+ if (md->type == EFI_RUNTIME_SERVICES_CODE)
+ efi_set_executable(md, executable);
}
}
@@ -79,7 +61,7 @@ void __init efi_call_phys_prelog(void)
{
unsigned long vaddress;
- early_runtime_code_mapping_set_exec(1);
+ early_code_mapping_set_exec(1);
local_irq_save(efi_flags);
vaddress = (unsigned long)__va(0x0UL);
save_pgd = *pgd_offset_k(0x0UL);
@@ -95,7 +77,7 @@ void __init efi_call_phys_epilog(void)
set_pgd(pgd_offset_k(0x0UL), save_pgd);
__flush_tlb_all();
local_irq_restore(efi_flags);
- early_runtime_code_mapping_set_exec(0);
+ early_code_mapping_set_exec(0);
}
void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size,
@@ -107,8 +89,10 @@ void __iomem *__init efi_ioremap(unsigned long phys_addr, unsigned long size,
return ioremap(phys_addr, size);
last_map_pfn = init_memory_mapping(phys_addr, phys_addr + size);
- if ((last_map_pfn << PAGE_SHIFT) < phys_addr + size)
- return NULL;
+ if ((last_map_pfn << PAGE_SHIFT) < phys_addr + size) {
+ unsigned long top = last_map_pfn << PAGE_SHIFT;
+ efi_ioremap(top, size - (top - phys_addr), type);
+ }
return (void __iomem *)__va(phys_addr);
}
diff --git a/arch/x86/platform/mrst/mrst.c b/arch/x86/platform/mrst/mrst.c
index 275dbc19e2cf..7000e74b3087 100644
--- a/arch/x86/platform/mrst/mrst.c
+++ b/arch/x86/platform/mrst/mrst.c
@@ -194,7 +194,7 @@ static unsigned long __init mrst_calibrate_tsc(void)
return 0;
}
-void __init mrst_time_init(void)
+static void __init mrst_time_init(void)
{
sfi_table_parse(SFI_SIG_MTMR, NULL, NULL, sfi_parse_mtmr);
switch (mrst_timer_options) {
@@ -216,7 +216,7 @@ void __init mrst_time_init(void)
apbt_time_init();
}
-void __cpuinit mrst_arch_setup(void)
+static void __cpuinit mrst_arch_setup(void)
{
if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x27)
__mrst_cpu_chip = MRST_CPU_CHIP_PENWELL;
diff --git a/arch/x86/platform/olpc/Makefile b/arch/x86/platform/olpc/Makefile
index c2a8cab65e5d..81c5e2165c24 100644
--- a/arch/x86/platform/olpc/Makefile
+++ b/arch/x86/platform/olpc/Makefile
@@ -1,4 +1,2 @@
-obj-$(CONFIG_OLPC) += olpc.o
+obj-$(CONFIG_OLPC) += olpc.o olpc_ofw.o olpc_dt.o
obj-$(CONFIG_OLPC_XO1) += olpc-xo1.o
-obj-$(CONFIG_OLPC) += olpc_ofw.o
-obj-$(CONFIG_OF_PROMTREE) += olpc_dt.o
diff --git a/arch/x86/platform/olpc/olpc.c b/arch/x86/platform/olpc/olpc.c
index edaf3fe8dc5e..0060fd59ea00 100644
--- a/arch/x86/platform/olpc/olpc.c
+++ b/arch/x86/platform/olpc/olpc.c
@@ -18,6 +18,7 @@
#include <linux/io.h>
#include <linux/string.h>
#include <linux/platform_device.h>
+#include <linux/of.h>
#include <asm/geode.h>
#include <asm/setup.h>
@@ -187,41 +188,43 @@ err:
}
EXPORT_SYMBOL_GPL(olpc_ec_cmd);
-static bool __init check_ofw_architecture(void)
+static bool __init check_ofw_architecture(struct device_node *root)
{
- size_t propsize;
- char olpc_arch[5];
- const void *args[] = { NULL, "architecture", olpc_arch, (void *)5 };
- void *res[] = { &propsize };
+ const char *olpc_arch;
+ int propsize;
- if (olpc_ofw("getprop", args, res)) {
- printk(KERN_ERR "ofw: getprop call failed!\n");
- return false;
- }
+ olpc_arch = of_get_property(root, "architecture", &propsize);
return propsize == 5 && strncmp("OLPC", olpc_arch, 5) == 0;
}
-static u32 __init get_board_revision(void)
+static u32 __init get_board_revision(struct device_node *root)
{
- size_t propsize;
- __be32 rev;
- const void *args[] = { NULL, "board-revision-int", &rev, (void *)4 };
- void *res[] = { &propsize };
-
- if (olpc_ofw("getprop", args, res) || propsize != 4) {
- printk(KERN_ERR "ofw: getprop call failed!\n");
- return cpu_to_be32(0);
- }
- return be32_to_cpu(rev);
+ int propsize;
+ const __be32 *rev;
+
+ rev = of_get_property(root, "board-revision-int", &propsize);
+ if (propsize != 4)
+ return 0;
+
+ return be32_to_cpu(*rev);
}
static bool __init platform_detect(void)
{
- if (!check_ofw_architecture())
+ struct device_node *root = of_find_node_by_path("/");
+ bool success;
+
+ if (!root)
return false;
- olpc_platform_info.flags |= OLPC_F_PRESENT;
- olpc_platform_info.boardrev = get_board_revision();
- return true;
+
+ success = check_ofw_architecture(root);
+ if (success) {
+ olpc_platform_info.boardrev = get_board_revision(root);
+ olpc_platform_info.flags |= OLPC_F_PRESENT;
+ }
+
+ of_node_put(root);
+ return success;
}
static int __init add_xo1_platform_devices(void)
diff --git a/arch/x86/platform/olpc/olpc_dt.c b/arch/x86/platform/olpc/olpc_dt.c
index 044bda5b3174..d39f63d017d2 100644
--- a/arch/x86/platform/olpc/olpc_dt.c
+++ b/arch/x86/platform/olpc/olpc_dt.c
@@ -19,7 +19,9 @@
#include <linux/kernel.h>
#include <linux/bootmem.h>
#include <linux/of.h>
+#include <linux/of_platform.h>
#include <linux/of_pdt.h>
+#include <asm/olpc.h>
#include <asm/olpc_ofw.h>
static phandle __init olpc_dt_getsibling(phandle node)
@@ -180,3 +182,20 @@ void __init olpc_dt_build_devicetree(void)
pr_info("PROM DT: Built device tree with %u bytes of memory.\n",
prom_early_allocated);
}
+
+/* A list of DT node/bus matches that we want to expose as platform devices */
+static struct of_device_id __initdata of_ids[] = {
+ { .compatible = "olpc,xo1-battery" },
+ { .compatible = "olpc,xo1-dcon" },
+ { .compatible = "olpc,xo1-rtc" },
+ {},
+};
+
+static int __init olpc_create_platform_devices(void)
+{
+ if (machine_is_olpc())
+ return of_platform_bus_probe(NULL, of_ids, NULL);
+ else
+ return 0;
+}
+device_initcall(olpc_create_platform_devices);
diff --git a/arch/x86/platform/uv/uv_time.c b/arch/x86/platform/uv/uv_time.c
index 9daf5d1af9f1..0eb90184515f 100644
--- a/arch/x86/platform/uv/uv_time.c
+++ b/arch/x86/platform/uv/uv_time.c
@@ -40,7 +40,6 @@ static struct clocksource clocksource_uv = {
.rating = 400,
.read = uv_read_rtc,
.mask = (cycle_t)UVH_RTC_REAL_TIME_CLOCK_MASK,
- .shift = 10,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
@@ -372,14 +371,11 @@ static __init int uv_rtc_setup_clock(void)
if (!is_uv_system())
return -ENODEV;
- clocksource_uv.mult = clocksource_hz2mult(sn_rtc_cycles_per_second,
- clocksource_uv.shift);
-
/* If single blade, prefer tsc */
if (uv_num_possible_blades() == 1)
clocksource_uv.rating = 250;
- rc = clocksource_register(&clocksource_uv);
+ rc = clocksource_register_hz(&clocksource_uv, sn_rtc_cycles_per_second);
if (rc)
printk(KERN_INFO "UV RTC clocksource failed rc %d\n", rc);
else
diff --git a/arch/x86/vdso/Makefile b/arch/x86/vdso/Makefile
index b6552b189bcd..bef0bc962400 100644
--- a/arch/x86/vdso/Makefile
+++ b/arch/x86/vdso/Makefile
@@ -11,7 +11,7 @@ vdso-install-$(VDSO32-y) += $(vdso32-images)
# files to link into the vdso
-vobjs-y := vdso-note.o vclock_gettime.o vgetcpu.o vvar.o
+vobjs-y := vdso-note.o vclock_gettime.o vgetcpu.o
# files to link into kernel
obj-$(VDSO64-y) += vma.o vdso.o
@@ -37,11 +37,24 @@ $(obj)/%.so: OBJCOPYFLAGS := -S
$(obj)/%.so: $(obj)/%.so.dbg FORCE
$(call if_changed,objcopy)
+#
+# Don't omit frame pointers for ease of userspace debugging, but do
+# optimize sibling calls.
+#
CFL := $(PROFILING) -mcmodel=small -fPIC -O2 -fasynchronous-unwind-tables -m64 \
- $(filter -g%,$(KBUILD_CFLAGS)) $(call cc-option, -fno-stack-protector)
+ $(filter -g%,$(KBUILD_CFLAGS)) $(call cc-option, -fno-stack-protector) \
+ -fno-omit-frame-pointer -foptimize-sibling-calls
$(vobjs): KBUILD_CFLAGS += $(CFL)
+#
+# vDSO code runs in userspace and -pg doesn't help with profiling anyway.
+#
+CFLAGS_REMOVE_vdso-note.o = -pg
+CFLAGS_REMOVE_vclock_gettime.o = -pg
+CFLAGS_REMOVE_vgetcpu.o = -pg
+CFLAGS_REMOVE_vvar.o = -pg
+
targets += vdso-syms.lds
obj-$(VDSO64-y) += vdso-syms.lds
diff --git a/arch/x86/vdso/vclock_gettime.c b/arch/x86/vdso/vclock_gettime.c
index ee55754cc3c5..a724905fdae7 100644
--- a/arch/x86/vdso/vclock_gettime.c
+++ b/arch/x86/vdso/vclock_gettime.c
@@ -2,7 +2,7 @@
* Copyright 2006 Andi Kleen, SUSE Labs.
* Subject to the GNU Public License, v.2
*
- * Fast user context implementation of clock_gettime and gettimeofday.
+ * Fast user context implementation of clock_gettime, gettimeofday, and time.
*
* The code should have no internal unresolved relocations.
* Check with readelf after changing.
@@ -22,9 +22,8 @@
#include <asm/hpet.h>
#include <asm/unistd.h>
#include <asm/io.h>
-#include "vextern.h"
-#define gtod vdso_vsyscall_gtod_data
+#define gtod (&VVAR(vsyscall_gtod_data))
notrace static long vdso_fallback_gettime(long clock, struct timespec *ts)
{
@@ -56,22 +55,6 @@ notrace static noinline int do_realtime(struct timespec *ts)
return 0;
}
-/* Copy of the version in kernel/time.c which we cannot directly access */
-notrace static void
-vset_normalized_timespec(struct timespec *ts, long sec, long nsec)
-{
- while (nsec >= NSEC_PER_SEC) {
- nsec -= NSEC_PER_SEC;
- ++sec;
- }
- while (nsec < 0) {
- nsec += NSEC_PER_SEC;
- --sec;
- }
- ts->tv_sec = sec;
- ts->tv_nsec = nsec;
-}
-
notrace static noinline int do_monotonic(struct timespec *ts)
{
unsigned long seq, ns, secs;
@@ -82,7 +65,17 @@ notrace static noinline int do_monotonic(struct timespec *ts)
secs += gtod->wall_to_monotonic.tv_sec;
ns += gtod->wall_to_monotonic.tv_nsec;
} while (unlikely(read_seqretry(&gtod->lock, seq)));
- vset_normalized_timespec(ts, secs, ns);
+
+ /* wall_time_nsec, vgetns(), and wall_to_monotonic.tv_nsec
+ * are all guaranteed to be nonnegative.
+ */
+ while (ns >= NSEC_PER_SEC) {
+ ns -= NSEC_PER_SEC;
+ ++secs;
+ }
+ ts->tv_sec = secs;
+ ts->tv_nsec = ns;
+
return 0;
}
@@ -107,7 +100,17 @@ notrace static noinline int do_monotonic_coarse(struct timespec *ts)
secs += gtod->wall_to_monotonic.tv_sec;
ns += gtod->wall_to_monotonic.tv_nsec;
} while (unlikely(read_seqretry(&gtod->lock, seq)));
- vset_normalized_timespec(ts, secs, ns);
+
+ /* wall_time_nsec and wall_to_monotonic.tv_nsec are
+ * guaranteed to be between 0 and NSEC_PER_SEC.
+ */
+ if (ns >= NSEC_PER_SEC) {
+ ns -= NSEC_PER_SEC;
+ ++secs;
+ }
+ ts->tv_sec = secs;
+ ts->tv_nsec = ns;
+
return 0;
}
@@ -157,3 +160,32 @@ notrace int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
}
int gettimeofday(struct timeval *, struct timezone *)
__attribute__((weak, alias("__vdso_gettimeofday")));
+
+/* This will break when the xtime seconds get inaccurate, but that is
+ * unlikely */
+
+static __always_inline long time_syscall(long *t)
+{
+ long secs;
+ asm volatile("syscall"
+ : "=a" (secs)
+ : "0" (__NR_time), "D" (t) : "cc", "r11", "cx", "memory");
+ return secs;
+}
+
+notrace time_t __vdso_time(time_t *t)
+{
+ time_t result;
+
+ if (unlikely(!VVAR(vsyscall_gtod_data).sysctl_enabled))
+ return time_syscall(t);
+
+ /* This is atomic on x86_64 so we don't need any locks. */
+ result = ACCESS_ONCE(VVAR(vsyscall_gtod_data).wall_time_sec);
+
+ if (t)
+ *t = result;
+ return result;
+}
+int time(time_t *t)
+ __attribute__((weak, alias("__vdso_time")));
diff --git a/arch/x86/vdso/vdso.lds.S b/arch/x86/vdso/vdso.lds.S
index 4e5dd3b4de7f..b96b2677cad8 100644
--- a/arch/x86/vdso/vdso.lds.S
+++ b/arch/x86/vdso/vdso.lds.S
@@ -23,15 +23,10 @@ VERSION {
__vdso_gettimeofday;
getcpu;
__vdso_getcpu;
+ time;
+ __vdso_time;
local: *;
};
}
VDSO64_PRELINK = VDSO_PRELINK;
-
-/*
- * Define VDSO64_x for each VEXTERN(x), for use via VDSO64_SYMBOL.
- */
-#define VEXTERN(x) VDSO64_ ## x = vdso_ ## x;
-#include "vextern.h"
-#undef VEXTERN
diff --git a/arch/x86/vdso/vextern.h b/arch/x86/vdso/vextern.h
deleted file mode 100644
index 1683ba2ae3e8..000000000000
--- a/arch/x86/vdso/vextern.h
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifndef VEXTERN
-#include <asm/vsyscall.h>
-#define VEXTERN(x) \
- extern typeof(x) *vdso_ ## x __attribute__((visibility("hidden")));
-#endif
-
-#define VMAGIC 0xfeedbabeabcdefabUL
-
-/* Any kernel variables used in the vDSO must be exported in the main
- kernel's vmlinux.lds.S/vsyscall.h/proper __section and
- put into vextern.h and be referenced as a pointer with vdso prefix.
- The main kernel later fills in the values. */
-
-VEXTERN(jiffies)
-VEXTERN(vgetcpu_mode)
-VEXTERN(vsyscall_gtod_data)
diff --git a/arch/x86/vdso/vgetcpu.c b/arch/x86/vdso/vgetcpu.c
index 9fbc6b20026b..5463ad558573 100644
--- a/arch/x86/vdso/vgetcpu.c
+++ b/arch/x86/vdso/vgetcpu.c
@@ -11,14 +11,13 @@
#include <linux/time.h>
#include <asm/vsyscall.h>
#include <asm/vgtod.h>
-#include "vextern.h"
notrace long
__vdso_getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *unused)
{
unsigned int p;
- if (*vdso_vgetcpu_mode == VGETCPU_RDTSCP) {
+ if (VVAR(vgetcpu_mode) == VGETCPU_RDTSCP) {
/* Load per CPU data from RDTSCP */
native_read_tscp(&p);
} else {
diff --git a/arch/x86/vdso/vma.c b/arch/x86/vdso/vma.c
index 4b5d26f108bb..7abd2be0f9b9 100644
--- a/arch/x86/vdso/vma.c
+++ b/arch/x86/vdso/vma.c
@@ -15,9 +15,6 @@
#include <asm/proto.h>
#include <asm/vdso.h>
-#include "vextern.h" /* Just for VMAGIC. */
-#undef VEXTERN
-
unsigned int __read_mostly vdso_enabled = 1;
extern char vdso_start[], vdso_end[];
@@ -26,20 +23,10 @@ extern unsigned short vdso_sync_cpuid;
static struct page **vdso_pages;
static unsigned vdso_size;
-static inline void *var_ref(void *p, char *name)
-{
- if (*(void **)p != (void *)VMAGIC) {
- printk("VDSO: variable %s broken\n", name);
- vdso_enabled = 0;
- }
- return p;
-}
-
static int __init init_vdso_vars(void)
{
int npages = (vdso_end - vdso_start + PAGE_SIZE - 1) / PAGE_SIZE;
int i;
- char *vbase;
vdso_size = npages << PAGE_SHIFT;
vdso_pages = kmalloc(sizeof(struct page *) * npages, GFP_KERNEL);
@@ -54,20 +41,6 @@ static int __init init_vdso_vars(void)
copy_page(page_address(p), vdso_start + i*PAGE_SIZE);
}
- vbase = vmap(vdso_pages, npages, 0, PAGE_KERNEL);
- if (!vbase)
- goto oom;
-
- if (memcmp(vbase, "\177ELF", 4)) {
- printk("VDSO: I'm broken; not ELF\n");
- vdso_enabled = 0;
- }
-
-#define VEXTERN(x) \
- *(typeof(__ ## x) **) var_ref(VDSO64_SYMBOL(vbase, x), #x) = &__ ## x;
-#include "vextern.h"
-#undef VEXTERN
- vunmap(vbase);
return 0;
oom:
diff --git a/arch/x86/vdso/vvar.c b/arch/x86/vdso/vvar.c
deleted file mode 100644
index 1b7e703684f9..000000000000
--- a/arch/x86/vdso/vvar.c
+++ /dev/null
@@ -1,12 +0,0 @@
-/* Define pointer to external vDSO variables.
- These are part of the vDSO. The kernel fills in the real addresses
- at boot time. This is done because when the vdso is linked the
- kernel isn't yet and we don't know the final addresses. */
-#include <linux/kernel.h>
-#include <linux/time.h>
-#include <asm/vsyscall.h>
-#include <asm/timex.h>
-#include <asm/vgtod.h>
-
-#define VEXTERN(x) typeof (__ ## x) *const vdso_ ## x = (void *)VMAGIC;
-#include "vextern.h"
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index e3c6a06cf725..dd7b88f2ec7a 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -235,7 +235,7 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx,
*dx &= maskedx;
}
-static __init void xen_init_cpuid_mask(void)
+static void __init xen_init_cpuid_mask(void)
{
unsigned int ax, bx, cx, dx;
unsigned int xsave_mask;
@@ -400,7 +400,7 @@ static void xen_load_gdt(const struct desc_ptr *dtr)
/*
* load_gdt for early boot, when the gdt is only mapped once
*/
-static __init void xen_load_gdt_boot(const struct desc_ptr *dtr)
+static void __init xen_load_gdt_boot(const struct desc_ptr *dtr)
{
unsigned long va = dtr->address;
unsigned int size = dtr->size + 1;
@@ -662,7 +662,7 @@ static void xen_write_gdt_entry(struct desc_struct *dt, int entry,
* Version of write_gdt_entry for use at early boot-time needed to
* update an entry as simply as possible.
*/
-static __init void xen_write_gdt_entry_boot(struct desc_struct *dt, int entry,
+static void __init xen_write_gdt_entry_boot(struct desc_struct *dt, int entry,
const void *desc, int type)
{
switch (type) {
@@ -933,18 +933,18 @@ static unsigned xen_patch(u8 type, u16 clobbers, void *insnbuf,
return ret;
}
-static const struct pv_info xen_info __initdata = {
+static const struct pv_info xen_info __initconst = {
.paravirt_enabled = 1,
.shared_kernel_pmd = 0,
.name = "Xen",
};
-static const struct pv_init_ops xen_init_ops __initdata = {
+static const struct pv_init_ops xen_init_ops __initconst = {
.patch = xen_patch,
};
-static const struct pv_cpu_ops xen_cpu_ops __initdata = {
+static const struct pv_cpu_ops xen_cpu_ops __initconst = {
.cpuid = xen_cpuid,
.set_debugreg = xen_set_debugreg,
@@ -1004,7 +1004,7 @@ static const struct pv_cpu_ops xen_cpu_ops __initdata = {
.end_context_switch = xen_end_context_switch,
};
-static const struct pv_apic_ops xen_apic_ops __initdata = {
+static const struct pv_apic_ops xen_apic_ops __initconst = {
#ifdef CONFIG_X86_LOCAL_APIC
.startup_ipi_hook = paravirt_nop,
#endif
@@ -1055,7 +1055,7 @@ int xen_panic_handler_init(void)
return 0;
}
-static const struct machine_ops __initdata xen_machine_ops = {
+static const struct machine_ops xen_machine_ops __initconst = {
.restart = xen_restart,
.halt = xen_machine_halt,
.power_off = xen_machine_halt,
@@ -1332,7 +1332,7 @@ static int __cpuinit xen_hvm_cpu_notify(struct notifier_block *self,
return NOTIFY_OK;
}
-static struct notifier_block __cpuinitdata xen_hvm_cpu_notifier = {
+static struct notifier_block xen_hvm_cpu_notifier __cpuinitdata = {
.notifier_call = xen_hvm_cpu_notify,
};
@@ -1381,7 +1381,7 @@ bool xen_hvm_need_lapic(void)
}
EXPORT_SYMBOL_GPL(xen_hvm_need_lapic);
-const __refconst struct hypervisor_x86 x86_hyper_xen_hvm = {
+const struct hypervisor_x86 x86_hyper_xen_hvm __refconst = {
.name = "Xen HVM",
.detect = xen_hvm_platform,
.init_platform = xen_hvm_guest_init,
diff --git a/arch/x86/xen/irq.c b/arch/x86/xen/irq.c
index 6a6fe8939645..8bbb465b6f0a 100644
--- a/arch/x86/xen/irq.c
+++ b/arch/x86/xen/irq.c
@@ -113,7 +113,7 @@ static void xen_halt(void)
xen_safe_halt();
}
-static const struct pv_irq_ops xen_irq_ops __initdata = {
+static const struct pv_irq_ops xen_irq_ops __initconst = {
.save_fl = PV_CALLEE_SAVE(xen_save_fl),
.restore_fl = PV_CALLEE_SAVE(xen_restore_fl),
.irq_disable = PV_CALLEE_SAVE(xen_irq_disable),
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index 0684f3c74d53..dc708dcc62f1 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -75,67 +75,12 @@
#include "mmu.h"
#include "debugfs.h"
-#define MMU_UPDATE_HISTO 30
-
/*
* Protects atomic reservation decrease/increase against concurrent increases.
* Also protects non-atomic updates of current_pages and balloon lists.
*/
DEFINE_SPINLOCK(xen_reservation_lock);
-#ifdef CONFIG_XEN_DEBUG_FS
-
-static struct {
- u32 pgd_update;
- u32 pgd_update_pinned;
- u32 pgd_update_batched;
-
- u32 pud_update;
- u32 pud_update_pinned;
- u32 pud_update_batched;
-
- u32 pmd_update;
- u32 pmd_update_pinned;
- u32 pmd_update_batched;
-
- u32 pte_update;
- u32 pte_update_pinned;
- u32 pte_update_batched;
-
- u32 mmu_update;
- u32 mmu_update_extended;
- u32 mmu_update_histo[MMU_UPDATE_HISTO];
-
- u32 prot_commit;
- u32 prot_commit_batched;
-
- u32 set_pte_at;
- u32 set_pte_at_batched;
- u32 set_pte_at_pinned;
- u32 set_pte_at_current;
- u32 set_pte_at_kernel;
-} mmu_stats;
-
-static u8 zero_stats;
-
-static inline void check_zero(void)
-{
- if (unlikely(zero_stats)) {
- memset(&mmu_stats, 0, sizeof(mmu_stats));
- zero_stats = 0;
- }
-}
-
-#define ADD_STATS(elem, val) \
- do { check_zero(); mmu_stats.elem += (val); } while(0)
-
-#else /* !CONFIG_XEN_DEBUG_FS */
-
-#define ADD_STATS(elem, val) do { (void)(val); } while(0)
-
-#endif /* CONFIG_XEN_DEBUG_FS */
-
-
/*
* Identity map, in addition to plain kernel map. This needs to be
* large enough to allocate page table pages to allocate the rest.
@@ -243,11 +188,6 @@ static bool xen_page_pinned(void *ptr)
return PagePinned(page);
}
-static bool xen_iomap_pte(pte_t pte)
-{
- return pte_flags(pte) & _PAGE_IOMAP;
-}
-
void xen_set_domain_pte(pte_t *ptep, pte_t pteval, unsigned domid)
{
struct multicall_space mcs;
@@ -257,7 +197,7 @@ void xen_set_domain_pte(pte_t *ptep, pte_t pteval, unsigned domid)
u = mcs.args;
/* ptep might be kmapped when using 32-bit HIGHPTE */
- u->ptr = arbitrary_virt_to_machine(ptep).maddr;
+ u->ptr = virt_to_machine(ptep).maddr;
u->val = pte_val_ma(pteval);
MULTI_mmu_update(mcs.mc, mcs.args, 1, NULL, domid);
@@ -266,11 +206,6 @@ void xen_set_domain_pte(pte_t *ptep, pte_t pteval, unsigned domid)
}
EXPORT_SYMBOL_GPL(xen_set_domain_pte);
-static void xen_set_iomap_pte(pte_t *ptep, pte_t pteval)
-{
- xen_set_domain_pte(ptep, pteval, DOMID_IO);
-}
-
static void xen_extend_mmu_update(const struct mmu_update *update)
{
struct multicall_space mcs;
@@ -279,27 +214,17 @@ static void xen_extend_mmu_update(const struct mmu_update *update)
mcs = xen_mc_extend_args(__HYPERVISOR_mmu_update, sizeof(*u));
if (mcs.mc != NULL) {
- ADD_STATS(mmu_update_extended, 1);
- ADD_STATS(mmu_update_histo[mcs.mc->args[1]], -1);
-
mcs.mc->args[1]++;
-
- if (mcs.mc->args[1] < MMU_UPDATE_HISTO)
- ADD_STATS(mmu_update_histo[mcs.mc->args[1]], 1);
- else
- ADD_STATS(mmu_update_histo[0], 1);
} else {
- ADD_STATS(mmu_update, 1);
mcs = __xen_mc_entry(sizeof(*u));
MULTI_mmu_update(mcs.mc, mcs.args, 1, NULL, DOMID_SELF);
- ADD_STATS(mmu_update_histo[1], 1);
}
u = mcs.args;
*u = *update;
}
-void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val)
+static void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val)
{
struct mmu_update u;
@@ -312,17 +237,13 @@ void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val)
u.val = pmd_val_ma(val);
xen_extend_mmu_update(&u);
- ADD_STATS(pmd_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
-
xen_mc_issue(PARAVIRT_LAZY_MMU);
preempt_enable();
}
-void xen_set_pmd(pmd_t *ptr, pmd_t val)
+static void xen_set_pmd(pmd_t *ptr, pmd_t val)
{
- ADD_STATS(pmd_update, 1);
-
/* If page is not pinned, we can just update the entry
directly */
if (!xen_page_pinned(ptr)) {
@@ -330,8 +251,6 @@ void xen_set_pmd(pmd_t *ptr, pmd_t val)
return;
}
- ADD_STATS(pmd_update_pinned, 1);
-
xen_set_pmd_hyper(ptr, val);
}
@@ -344,35 +263,34 @@ void set_pte_mfn(unsigned long vaddr, unsigned long mfn, pgprot_t flags)
set_pte_vaddr(vaddr, mfn_pte(mfn, flags));
}
-void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
- pte_t *ptep, pte_t pteval)
+static bool xen_batched_set_pte(pte_t *ptep, pte_t pteval)
{
- if (xen_iomap_pte(pteval)) {
- xen_set_iomap_pte(ptep, pteval);
- goto out;
- }
+ struct mmu_update u;
- ADD_STATS(set_pte_at, 1);
-// ADD_STATS(set_pte_at_pinned, xen_page_pinned(ptep));
- ADD_STATS(set_pte_at_current, mm == current->mm);
- ADD_STATS(set_pte_at_kernel, mm == &init_mm);
+ if (paravirt_get_lazy_mode() != PARAVIRT_LAZY_MMU)
+ return false;
- if (mm == current->mm || mm == &init_mm) {
- if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) {
- struct multicall_space mcs;
- mcs = xen_mc_entry(0);
+ xen_mc_batch();
- MULTI_update_va_mapping(mcs.mc, addr, pteval, 0);
- ADD_STATS(set_pte_at_batched, 1);
- xen_mc_issue(PARAVIRT_LAZY_MMU);
- goto out;
- } else
- if (HYPERVISOR_update_va_mapping(addr, pteval, 0) == 0)
- goto out;
- }
- xen_set_pte(ptep, pteval);
+ u.ptr = virt_to_machine(ptep).maddr | MMU_NORMAL_PT_UPDATE;
+ u.val = pte_val_ma(pteval);
+ xen_extend_mmu_update(&u);
+
+ xen_mc_issue(PARAVIRT_LAZY_MMU);
-out: return;
+ return true;
+}
+
+static void xen_set_pte(pte_t *ptep, pte_t pteval)
+{
+ if (!xen_batched_set_pte(ptep, pteval))
+ native_set_pte(ptep, pteval);
+}
+
+static void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pteval)
+{
+ xen_set_pte(ptep, pteval);
}
pte_t xen_ptep_modify_prot_start(struct mm_struct *mm,
@@ -389,13 +307,10 @@ void xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr,
xen_mc_batch();
- u.ptr = arbitrary_virt_to_machine(ptep).maddr | MMU_PT_UPDATE_PRESERVE_AD;
+ u.ptr = virt_to_machine(ptep).maddr | MMU_PT_UPDATE_PRESERVE_AD;
u.val = pte_val_ma(pte);
xen_extend_mmu_update(&u);
- ADD_STATS(prot_commit, 1);
- ADD_STATS(prot_commit_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
-
xen_mc_issue(PARAVIRT_LAZY_MMU);
}
@@ -463,7 +378,7 @@ static pteval_t iomap_pte(pteval_t val)
return val;
}
-pteval_t xen_pte_val(pte_t pte)
+static pteval_t xen_pte_val(pte_t pte)
{
pteval_t pteval = pte.pte;
@@ -480,7 +395,7 @@ pteval_t xen_pte_val(pte_t pte)
}
PV_CALLEE_SAVE_REGS_THUNK(xen_pte_val);
-pgdval_t xen_pgd_val(pgd_t pgd)
+static pgdval_t xen_pgd_val(pgd_t pgd)
{
return pte_mfn_to_pfn(pgd.pgd);
}
@@ -511,7 +426,7 @@ void xen_set_pat(u64 pat)
WARN_ON(pat != 0x0007010600070106ull);
}
-pte_t xen_make_pte(pteval_t pte)
+static pte_t xen_make_pte(pteval_t pte)
{
phys_addr_t addr = (pte & PTE_PFN_MASK);
@@ -581,20 +496,20 @@ pte_t xen_make_pte_debug(pteval_t pte)
PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte_debug);
#endif
-pgd_t xen_make_pgd(pgdval_t pgd)
+static pgd_t xen_make_pgd(pgdval_t pgd)
{
pgd = pte_pfn_to_mfn(pgd);
return native_make_pgd(pgd);
}
PV_CALLEE_SAVE_REGS_THUNK(xen_make_pgd);
-pmdval_t xen_pmd_val(pmd_t pmd)
+static pmdval_t xen_pmd_val(pmd_t pmd)
{
return pte_mfn_to_pfn(pmd.pmd);
}
PV_CALLEE_SAVE_REGS_THUNK(xen_pmd_val);
-void xen_set_pud_hyper(pud_t *ptr, pud_t val)
+static void xen_set_pud_hyper(pud_t *ptr, pud_t val)
{
struct mmu_update u;
@@ -607,17 +522,13 @@ void xen_set_pud_hyper(pud_t *ptr, pud_t val)
u.val = pud_val_ma(val);
xen_extend_mmu_update(&u);
- ADD_STATS(pud_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
-
xen_mc_issue(PARAVIRT_LAZY_MMU);
preempt_enable();
}
-void xen_set_pud(pud_t *ptr, pud_t val)
+static void xen_set_pud(pud_t *ptr, pud_t val)
{
- ADD_STATS(pud_update, 1);
-
/* If page is not pinned, we can just update the entry
directly */
if (!xen_page_pinned(ptr)) {
@@ -625,56 +536,28 @@ void xen_set_pud(pud_t *ptr, pud_t val)
return;
}
- ADD_STATS(pud_update_pinned, 1);
-
xen_set_pud_hyper(ptr, val);
}
-void xen_set_pte(pte_t *ptep, pte_t pte)
-{
- if (xen_iomap_pte(pte)) {
- xen_set_iomap_pte(ptep, pte);
- return;
- }
-
- ADD_STATS(pte_update, 1);
-// ADD_STATS(pte_update_pinned, xen_page_pinned(ptep));
- ADD_STATS(pte_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
-
#ifdef CONFIG_X86_PAE
- ptep->pte_high = pte.pte_high;
- smp_wmb();
- ptep->pte_low = pte.pte_low;
-#else
- *ptep = pte;
-#endif
-}
-
-#ifdef CONFIG_X86_PAE
-void xen_set_pte_atomic(pte_t *ptep, pte_t pte)
+static void xen_set_pte_atomic(pte_t *ptep, pte_t pte)
{
- if (xen_iomap_pte(pte)) {
- xen_set_iomap_pte(ptep, pte);
- return;
- }
-
set_64bit((u64 *)ptep, native_pte_val(pte));
}
-void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+static void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{
- ptep->pte_low = 0;
- smp_wmb(); /* make sure low gets written first */
- ptep->pte_high = 0;
+ if (!xen_batched_set_pte(ptep, native_make_pte(0)))
+ native_pte_clear(mm, addr, ptep);
}
-void xen_pmd_clear(pmd_t *pmdp)
+static void xen_pmd_clear(pmd_t *pmdp)
{
set_pmd(pmdp, __pmd(0));
}
#endif /* CONFIG_X86_PAE */
-pmd_t xen_make_pmd(pmdval_t pmd)
+static pmd_t xen_make_pmd(pmdval_t pmd)
{
pmd = pte_pfn_to_mfn(pmd);
return native_make_pmd(pmd);
@@ -682,13 +565,13 @@ pmd_t xen_make_pmd(pmdval_t pmd)
PV_CALLEE_SAVE_REGS_THUNK(xen_make_pmd);
#if PAGETABLE_LEVELS == 4
-pudval_t xen_pud_val(pud_t pud)
+static pudval_t xen_pud_val(pud_t pud)
{
return pte_mfn_to_pfn(pud.pud);
}
PV_CALLEE_SAVE_REGS_THUNK(xen_pud_val);
-pud_t xen_make_pud(pudval_t pud)
+static pud_t xen_make_pud(pudval_t pud)
{
pud = pte_pfn_to_mfn(pud);
@@ -696,7 +579,7 @@ pud_t xen_make_pud(pudval_t pud)
}
PV_CALLEE_SAVE_REGS_THUNK(xen_make_pud);
-pgd_t *xen_get_user_pgd(pgd_t *pgd)
+static pgd_t *xen_get_user_pgd(pgd_t *pgd)
{
pgd_t *pgd_page = (pgd_t *)(((unsigned long)pgd) & PAGE_MASK);
unsigned offset = pgd - pgd_page;
@@ -728,7 +611,7 @@ static void __xen_set_pgd_hyper(pgd_t *ptr, pgd_t val)
* 2. It is always pinned
* 3. It has no user pagetable attached to it
*/
-void __init xen_set_pgd_hyper(pgd_t *ptr, pgd_t val)
+static void __init xen_set_pgd_hyper(pgd_t *ptr, pgd_t val)
{
preempt_disable();
@@ -741,12 +624,10 @@ void __init xen_set_pgd_hyper(pgd_t *ptr, pgd_t val)
preempt_enable();
}
-void xen_set_pgd(pgd_t *ptr, pgd_t val)
+static void xen_set_pgd(pgd_t *ptr, pgd_t val)
{
pgd_t *user_ptr = xen_get_user_pgd(ptr);
- ADD_STATS(pgd_update, 1);
-
/* If page is not pinned, we can just update the entry
directly */
if (!xen_page_pinned(ptr)) {
@@ -758,9 +639,6 @@ void xen_set_pgd(pgd_t *ptr, pgd_t val)
return;
}
- ADD_STATS(pgd_update_pinned, 1);
- ADD_STATS(pgd_update_batched, paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU);
-
/* If it's pinned, then we can at least batch the kernel and
user updates together. */
xen_mc_batch();
@@ -1054,7 +932,7 @@ void xen_mm_pin_all(void)
* that's before we have page structures to store the bits. So do all
* the book-keeping now.
*/
-static __init int xen_mark_pinned(struct mm_struct *mm, struct page *page,
+static int __init xen_mark_pinned(struct mm_struct *mm, struct page *page,
enum pt_level level)
{
SetPagePinned(page);
@@ -1162,14 +1040,14 @@ void xen_mm_unpin_all(void)
spin_unlock(&pgd_lock);
}
-void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next)
+static void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next)
{
spin_lock(&next->page_table_lock);
xen_pgd_pin(next);
spin_unlock(&next->page_table_lock);
}
-void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
+static void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
{
spin_lock(&mm->page_table_lock);
xen_pgd_pin(mm);
@@ -1187,7 +1065,7 @@ static void drop_other_mm_ref(void *info)
active_mm = percpu_read(cpu_tlbstate.active_mm);
- if (active_mm == mm)
+ if (active_mm == mm && percpu_read(cpu_tlbstate.state) != TLBSTATE_OK)
leave_mm(smp_processor_id());
/* If this cpu still has a stale cr3 reference, then make sure
@@ -1256,7 +1134,7 @@ static void xen_drop_mm_ref(struct mm_struct *mm)
* pagetable because of lazy tlb flushing. This means we need need to
* switch all CPUs off this pagetable before we can unpin it.
*/
-void xen_exit_mmap(struct mm_struct *mm)
+static void xen_exit_mmap(struct mm_struct *mm)
{
get_cpu(); /* make sure we don't move around */
xen_drop_mm_ref(mm);
@@ -1271,7 +1149,7 @@ void xen_exit_mmap(struct mm_struct *mm)
spin_unlock(&mm->page_table_lock);
}
-static __init void xen_pagetable_setup_start(pgd_t *base)
+static void __init xen_pagetable_setup_start(pgd_t *base)
{
}
@@ -1291,7 +1169,7 @@ static __init void xen_mapping_pagetable_reserve(u64 start, u64 end)
static void xen_post_allocator_init(void);
-static __init void xen_pagetable_setup_done(pgd_t *base)
+static void __init xen_pagetable_setup_done(pgd_t *base)
{
xen_setup_shared_info();
xen_post_allocator_init();
@@ -1488,7 +1366,7 @@ static void xen_pgd_free(struct mm_struct *mm, pgd_t *pgd)
}
#ifdef CONFIG_X86_32
-static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
+static pte_t __init mask_rw_pte(pte_t *ptep, pte_t pte)
{
/* If there's an existing pte, then don't allow _PAGE_RW to be set */
if (pte_val_ma(*ptep) & _PAGE_PRESENT)
@@ -1498,7 +1376,7 @@ static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
return pte;
}
#else /* CONFIG_X86_64 */
-static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
+static pte_t __init mask_rw_pte(pte_t *ptep, pte_t pte)
{
unsigned long pfn = pte_pfn(pte);
@@ -1519,7 +1397,7 @@ static __init pte_t mask_rw_pte(pte_t *ptep, pte_t pte)
/* Init-time set_pte while constructing initial pagetables, which
doesn't allow RO pagetable pages to be remapped RW */
-static __init void xen_set_pte_init(pte_t *ptep, pte_t pte)
+static void __init xen_set_pte_init(pte_t *ptep, pte_t pte)
{
pte = mask_rw_pte(ptep, pte);
@@ -1537,7 +1415,7 @@ static void pin_pagetable_pfn(unsigned cmd, unsigned long pfn)
/* Early in boot, while setting up the initial pagetable, assume
everything is pinned. */
-static __init void xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn)
+static void __init xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn)
{
#ifdef CONFIG_FLATMEM
BUG_ON(mem_map); /* should only be used early */
@@ -1547,7 +1425,7 @@ static __init void xen_alloc_pte_init(struct mm_struct *mm, unsigned long pfn)
}
/* Used for pmd and pud */
-static __init void xen_alloc_pmd_init(struct mm_struct *mm, unsigned long pfn)
+static void __init xen_alloc_pmd_init(struct mm_struct *mm, unsigned long pfn)
{
#ifdef CONFIG_FLATMEM
BUG_ON(mem_map); /* should only be used early */
@@ -1557,13 +1435,13 @@ static __init void xen_alloc_pmd_init(struct mm_struct *mm, unsigned long pfn)
/* Early release_pte assumes that all pts are pinned, since there's
only init_mm and anything attached to that is pinned. */
-static __init void xen_release_pte_init(unsigned long pfn)
+static void __init xen_release_pte_init(unsigned long pfn)
{
pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, pfn);
make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
}
-static __init void xen_release_pmd_init(unsigned long pfn)
+static void __init xen_release_pmd_init(unsigned long pfn)
{
make_lowmem_page_readwrite(__va(PFN_PHYS(pfn)));
}
@@ -1689,7 +1567,7 @@ static void set_page_prot(void *addr, pgprot_t prot)
BUG();
}
-static __init void xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn)
+static void __init xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn)
{
unsigned pmdidx, pteidx;
unsigned ident_pte;
@@ -1772,7 +1650,7 @@ static void convert_pfn_mfn(void *v)
* of the physical mapping once some sort of allocator has been set
* up.
*/
-__init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
+pgd_t * __init xen_setup_kernel_pagetable(pgd_t *pgd,
unsigned long max_pfn)
{
pud_t *l3;
@@ -1843,7 +1721,7 @@ __init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
static RESERVE_BRK_ARRAY(pmd_t, initial_kernel_pmd, PTRS_PER_PMD);
static RESERVE_BRK_ARRAY(pmd_t, swapper_kernel_pmd, PTRS_PER_PMD);
-static __init void xen_write_cr3_init(unsigned long cr3)
+static void __init xen_write_cr3_init(unsigned long cr3)
{
unsigned long pfn = PFN_DOWN(__pa(swapper_pg_dir));
@@ -1880,7 +1758,7 @@ static __init void xen_write_cr3_init(unsigned long cr3)
pv_mmu_ops.write_cr3 = &xen_write_cr3;
}
-__init pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd,
+pgd_t * __init xen_setup_kernel_pagetable(pgd_t *pgd,
unsigned long max_pfn)
{
pmd_t *kernel_pmd;
@@ -1986,7 +1864,7 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
#endif
}
-__init void xen_ident_map_ISA(void)
+void __init xen_ident_map_ISA(void)
{
unsigned long pa;
@@ -2009,7 +1887,7 @@ __init void xen_ident_map_ISA(void)
xen_flush_tlb();
}
-static __init void xen_post_allocator_init(void)
+static void __init xen_post_allocator_init(void)
{
#ifdef CONFIG_XEN_DEBUG
pv_mmu_ops.make_pte = PV_CALLEE_SAVE(xen_make_pte_debug);
@@ -2046,7 +1924,7 @@ static void xen_leave_lazy_mmu(void)
preempt_enable();
}
-static const struct pv_mmu_ops xen_mmu_ops __initdata = {
+static const struct pv_mmu_ops xen_mmu_ops __initconst = {
.read_cr2 = xen_read_cr2,
.write_cr2 = xen_write_cr2,
@@ -2371,7 +2249,7 @@ static int remap_area_mfn_pte_fn(pte_t *ptep, pgtable_t token,
struct remap_data *rmd = data;
pte_t pte = pte_mkspecial(pfn_pte(rmd->mfn++, rmd->prot));
- rmd->mmu_update->ptr = arbitrary_virt_to_machine(ptep).maddr;
+ rmd->mmu_update->ptr = virt_to_machine(ptep).maddr;
rmd->mmu_update->val = pte_val_ma(pte);
rmd->mmu_update++;
@@ -2425,7 +2303,6 @@ out:
EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range);
#ifdef CONFIG_XEN_DEBUG_FS
-
static int p2m_dump_open(struct inode *inode, struct file *filp)
{
return single_open(filp, p2m_dump_show, NULL);
@@ -2437,65 +2314,4 @@ static const struct file_operations p2m_dump_fops = {
.llseek = seq_lseek,
.release = single_release,
};
-
-static struct dentry *d_mmu_debug;
-
-static int __init xen_mmu_debugfs(void)
-{
- struct dentry *d_xen = xen_init_debugfs();
-
- if (d_xen == NULL)
- return -ENOMEM;
-
- d_mmu_debug = debugfs_create_dir("mmu", d_xen);
-
- debugfs_create_u8("zero_stats", 0644, d_mmu_debug, &zero_stats);
-
- debugfs_create_u32("pgd_update", 0444, d_mmu_debug, &mmu_stats.pgd_update);
- debugfs_create_u32("pgd_update_pinned", 0444, d_mmu_debug,
- &mmu_stats.pgd_update_pinned);
- debugfs_create_u32("pgd_update_batched", 0444, d_mmu_debug,
- &mmu_stats.pgd_update_pinned);
-
- debugfs_create_u32("pud_update", 0444, d_mmu_debug, &mmu_stats.pud_update);
- debugfs_create_u32("pud_update_pinned", 0444, d_mmu_debug,
- &mmu_stats.pud_update_pinned);
- debugfs_create_u32("pud_update_batched", 0444, d_mmu_debug,
- &mmu_stats.pud_update_pinned);
-
- debugfs_create_u32("pmd_update", 0444, d_mmu_debug, &mmu_stats.pmd_update);
- debugfs_create_u32("pmd_update_pinned", 0444, d_mmu_debug,
- &mmu_stats.pmd_update_pinned);
- debugfs_create_u32("pmd_update_batched", 0444, d_mmu_debug,
- &mmu_stats.pmd_update_pinned);
-
- debugfs_create_u32("pte_update", 0444, d_mmu_debug, &mmu_stats.pte_update);
-// debugfs_create_u32("pte_update_pinned", 0444, d_mmu_debug,
-// &mmu_stats.pte_update_pinned);
- debugfs_create_u32("pte_update_batched", 0444, d_mmu_debug,
- &mmu_stats.pte_update_pinned);
-
- debugfs_create_u32("mmu_update", 0444, d_mmu_debug, &mmu_stats.mmu_update);
- debugfs_create_u32("mmu_update_extended", 0444, d_mmu_debug,
- &mmu_stats.mmu_update_extended);
- xen_debugfs_create_u32_array("mmu_update_histo", 0444, d_mmu_debug,
- mmu_stats.mmu_update_histo, 20);
-
- debugfs_create_u32("set_pte_at", 0444, d_mmu_debug, &mmu_stats.set_pte_at);
- debugfs_create_u32("set_pte_at_batched", 0444, d_mmu_debug,
- &mmu_stats.set_pte_at_batched);
- debugfs_create_u32("set_pte_at_current", 0444, d_mmu_debug,
- &mmu_stats.set_pte_at_current);
- debugfs_create_u32("set_pte_at_kernel", 0444, d_mmu_debug,
- &mmu_stats.set_pte_at_kernel);
-
- debugfs_create_u32("prot_commit", 0444, d_mmu_debug, &mmu_stats.prot_commit);
- debugfs_create_u32("prot_commit_batched", 0444, d_mmu_debug,
- &mmu_stats.prot_commit_batched);
-
- debugfs_create_file("p2m", 0600, d_mmu_debug, NULL, &p2m_dump_fops);
- return 0;
-}
-fs_initcall(xen_mmu_debugfs);
-
-#endif /* CONFIG_XEN_DEBUG_FS */
+#endif /* CONFIG_XEN_DEBUG_FS */
diff --git a/arch/x86/xen/mmu.h b/arch/x86/xen/mmu.h
index 537bb9aab777..73809bb951b4 100644
--- a/arch/x86/xen/mmu.h
+++ b/arch/x86/xen/mmu.h
@@ -15,43 +15,6 @@ bool __set_phys_to_machine(unsigned long pfn, unsigned long mfn);
void set_pte_mfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);
-
-void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next);
-void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm);
-void xen_exit_mmap(struct mm_struct *mm);
-
-pteval_t xen_pte_val(pte_t);
-pmdval_t xen_pmd_val(pmd_t);
-pgdval_t xen_pgd_val(pgd_t);
-
-pte_t xen_make_pte(pteval_t);
-pmd_t xen_make_pmd(pmdval_t);
-pgd_t xen_make_pgd(pgdval_t);
-
-void xen_set_pte(pte_t *ptep, pte_t pteval);
-void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
- pte_t *ptep, pte_t pteval);
-
-#ifdef CONFIG_X86_PAE
-void xen_set_pte_atomic(pte_t *ptep, pte_t pte);
-void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
-void xen_pmd_clear(pmd_t *pmdp);
-#endif /* CONFIG_X86_PAE */
-
-void xen_set_pmd(pmd_t *pmdp, pmd_t pmdval);
-void xen_set_pud(pud_t *ptr, pud_t val);
-void xen_set_pmd_hyper(pmd_t *pmdp, pmd_t pmdval);
-void xen_set_pud_hyper(pud_t *ptr, pud_t val);
-
-#if PAGETABLE_LEVELS == 4
-pudval_t xen_pud_val(pud_t pud);
-pud_t xen_make_pud(pudval_t pudval);
-void xen_set_pgd(pgd_t *pgdp, pgd_t pgd);
-void xen_set_pgd_hyper(pgd_t *pgdp, pgd_t pgd);
-#endif
-
-pgd_t *xen_get_user_pgd(pgd_t *pgd);
-
pte_t xen_ptep_modify_prot_start(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
void xen_ptep_modify_prot_commit(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pte);
diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c
index 141eb0de8b06..58efeb9d5440 100644
--- a/arch/x86/xen/p2m.c
+++ b/arch/x86/xen/p2m.c
@@ -522,11 +522,20 @@ static bool __init __early_alloc_p2m(unsigned long pfn)
/* Boundary cross-over for the edges: */
if (idx) {
unsigned long *p2m = extend_brk(PAGE_SIZE, PAGE_SIZE);
+ unsigned long *mid_mfn_p;
p2m_init(p2m);
p2m_top[topidx][mididx] = p2m;
+ /* For save/restore we need to MFN of the P2M saved */
+
+ mid_mfn_p = p2m_top_mfn_p[topidx];
+ WARN(mid_mfn_p[mididx] != virt_to_mfn(p2m_missing),
+ "P2M_TOP_P[%d][%d] != MFN of p2m_missing!\n",
+ topidx, mididx);
+ mid_mfn_p[mididx] = virt_to_mfn(p2m);
+
}
return idx != 0;
}
@@ -549,12 +558,29 @@ unsigned long __init set_phys_range_identity(unsigned long pfn_s,
pfn += P2M_MID_PER_PAGE * P2M_PER_PAGE)
{
unsigned topidx = p2m_top_index(pfn);
- if (p2m_top[topidx] == p2m_mid_missing) {
- unsigned long **mid = extend_brk(PAGE_SIZE, PAGE_SIZE);
+ unsigned long *mid_mfn_p;
+ unsigned long **mid;
+
+ mid = p2m_top[topidx];
+ mid_mfn_p = p2m_top_mfn_p[topidx];
+ if (mid == p2m_mid_missing) {
+ mid = extend_brk(PAGE_SIZE, PAGE_SIZE);
p2m_mid_init(mid);
p2m_top[topidx] = mid;
+
+ BUG_ON(mid_mfn_p != p2m_mid_missing_mfn);
+ }
+ /* And the save/restore P2M tables.. */
+ if (mid_mfn_p == p2m_mid_missing_mfn) {
+ mid_mfn_p = extend_brk(PAGE_SIZE, PAGE_SIZE);
+ p2m_mid_mfn_init(mid_mfn_p);
+
+ p2m_top_mfn_p[topidx] = mid_mfn_p;
+ p2m_top_mfn[topidx] = virt_to_mfn(mid_mfn_p);
+ /* Note: we don't set mid_mfn_p[midix] here,
+ * look in __early_alloc_p2m */
}
}
@@ -650,7 +676,7 @@ static unsigned long mfn_hash(unsigned long mfn)
}
/* Add an MFN override for a particular page */
-int m2p_add_override(unsigned long mfn, struct page *page)
+int m2p_add_override(unsigned long mfn, struct page *page, bool clear_pte)
{
unsigned long flags;
unsigned long pfn;
@@ -662,7 +688,6 @@ int m2p_add_override(unsigned long mfn, struct page *page)
if (!PageHighMem(page)) {
address = (unsigned long)__va(pfn << PAGE_SHIFT);
ptep = lookup_address(address, &level);
-
if (WARN(ptep == NULL || level != PG_LEVEL_4K,
"m2p_add_override: pfn %lx not mapped", pfn))
return -EINVAL;
@@ -674,18 +699,17 @@ int m2p_add_override(unsigned long mfn, struct page *page)
if (unlikely(!set_phys_to_machine(pfn, FOREIGN_FRAME(mfn))))
return -ENOMEM;
- if (!PageHighMem(page))
+ if (clear_pte && !PageHighMem(page))
/* Just zap old mapping for now */
pte_clear(&init_mm, address, ptep);
-
spin_lock_irqsave(&m2p_override_lock, flags);
list_add(&page->lru, &m2p_overrides[mfn_hash(mfn)]);
spin_unlock_irqrestore(&m2p_override_lock, flags);
return 0;
}
-
-int m2p_remove_override(struct page *page)
+EXPORT_SYMBOL_GPL(m2p_add_override);
+int m2p_remove_override(struct page *page, bool clear_pte)
{
unsigned long flags;
unsigned long mfn;
@@ -713,7 +737,7 @@ int m2p_remove_override(struct page *page)
spin_unlock_irqrestore(&m2p_override_lock, flags);
set_phys_to_machine(pfn, page->index);
- if (!PageHighMem(page))
+ if (clear_pte && !PageHighMem(page))
set_pte_at(&init_mm, address, ptep,
pfn_pte(pfn, PAGE_KERNEL));
/* No tlb flush necessary because the caller already
@@ -721,6 +745,7 @@ int m2p_remove_override(struct page *page)
return 0;
}
+EXPORT_SYMBOL_GPL(m2p_remove_override);
struct page *m2p_find_override(unsigned long mfn)
{
diff --git a/arch/x86/xen/pci-swiotlb-xen.c b/arch/x86/xen/pci-swiotlb-xen.c
index bfd0632fe65e..b480d4207a4c 100644
--- a/arch/x86/xen/pci-swiotlb-xen.c
+++ b/arch/x86/xen/pci-swiotlb-xen.c
@@ -36,7 +36,7 @@ int __init pci_xen_swiotlb_detect(void)
/* If running as PV guest, either iommu=soft, or swiotlb=force will
* activate this IOMMU. If running as PV privileged, activate it
- * irregardlesss.
+ * irregardless.
*/
if ((xen_initial_domain() || swiotlb || swiotlb_force) &&
(xen_pv_domain()))
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
index 90bac0aac3a5..be1a464f6d66 100644
--- a/arch/x86/xen/setup.c
+++ b/arch/x86/xen/setup.c
@@ -50,7 +50,7 @@ phys_addr_t xen_extra_mem_start, xen_extra_mem_size;
*/
#define EXTRA_MEM_RATIO (10)
-static __init void xen_add_extra_mem(unsigned long pages)
+static void __init xen_add_extra_mem(unsigned long pages)
{
unsigned long pfn;
@@ -166,7 +166,7 @@ static unsigned long __init xen_set_identity(const struct e820entry *list,
if (last > end)
continue;
- if (entry->type == E820_RAM) {
+ if ((entry->type == E820_RAM) || (entry->type == E820_UNUSABLE)) {
if (start > start_pci)
identity += set_phys_range_identity(
PFN_UP(start_pci), PFN_DOWN(start));
@@ -227,7 +227,11 @@ char * __init xen_memory_setup(void)
memcpy(map_raw, map, sizeof(map));
e820.nr_map = 0;
+#ifdef CONFIG_X86_32
+ xen_extra_mem_start = mem_end;
+#else
xen_extra_mem_start = max((1ULL << 32), mem_end);
+#endif
for (i = 0; i < memmap.nr_entries; i++) {
unsigned long long end;
@@ -336,7 +340,7 @@ static void __init fiddle_vdso(void)
#endif
}
-static __cpuinit int register_callback(unsigned type, const void *func)
+static int __cpuinit register_callback(unsigned type, const void *func)
{
struct callback_register callback = {
.type = type,
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index 30612441ed99..41038c01de40 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -46,18 +46,17 @@ static irqreturn_t xen_call_function_interrupt(int irq, void *dev_id);
static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id);
/*
- * Reschedule call back. Nothing to do,
- * all the work is done automatically when
- * we return from the interrupt.
+ * Reschedule call back.
*/
static irqreturn_t xen_reschedule_interrupt(int irq, void *dev_id)
{
inc_irq_stat(irq_resched_count);
+ scheduler_ipi();
return IRQ_HANDLED;
}
-static __cpuinit void cpu_bringup(void)
+static void __cpuinit cpu_bringup(void)
{
int cpu = smp_processor_id();
@@ -85,7 +84,7 @@ static __cpuinit void cpu_bringup(void)
wmb(); /* make sure everything is out */
}
-static __cpuinit void cpu_bringup_and_idle(void)
+static void __cpuinit cpu_bringup_and_idle(void)
{
cpu_bringup();
cpu_idle();
@@ -242,7 +241,7 @@ static void __init xen_smp_prepare_cpus(unsigned int max_cpus)
}
}
-static __cpuinit int
+static int __cpuinit
cpu_initialize_context(unsigned int cpu, struct task_struct *idle)
{
struct vcpu_guest_context *ctxt;
@@ -486,7 +485,7 @@ static irqreturn_t xen_call_function_single_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static const struct smp_ops xen_smp_ops __initdata = {
+static const struct smp_ops xen_smp_ops __initconst = {
.smp_prepare_boot_cpu = xen_smp_prepare_boot_cpu,
.smp_prepare_cpus = xen_smp_prepare_cpus,
.smp_cpus_done = xen_smp_cpus_done,
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
index 2e2d370a47b1..5158c505bef9 100644
--- a/arch/x86/xen/time.c
+++ b/arch/x86/xen/time.c
@@ -26,8 +26,6 @@
#include "xen-ops.h"
-#define XEN_SHIFT 22
-
/* Xen may fire a timer up to this many ns early */
#define TIMER_SLOP 100000
#define NS_PER_TICK (1000000000LL / HZ)
@@ -211,8 +209,6 @@ static struct clocksource xen_clocksource __read_mostly = {
.rating = 400,
.read = xen_clocksource_get_cycles,
.mask = ~0,
- .mult = 1<<XEN_SHIFT, /* time directly in nanoseconds */
- .shift = XEN_SHIFT,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
@@ -439,16 +435,16 @@ void xen_timer_resume(void)
}
}
-static const struct pv_time_ops xen_time_ops __initdata = {
+static const struct pv_time_ops xen_time_ops __initconst = {
.sched_clock = xen_clocksource_read,
};
-static __init void xen_time_init(void)
+static void __init xen_time_init(void)
{
int cpu = smp_processor_id();
struct timespec tp;
- clocksource_register(&xen_clocksource);
+ clocksource_register_hz(&xen_clocksource, NSEC_PER_SEC);
if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL) == 0) {
/* Successfully turned off 100Hz tick, so we have the
@@ -468,7 +464,7 @@ static __init void xen_time_init(void)
xen_setup_cpu_clockevents();
}
-__init void xen_init_time_ops(void)
+void __init xen_init_time_ops(void)
{
pv_time_ops = xen_time_ops;
@@ -490,7 +486,7 @@ static void xen_hvm_setup_cpu_clockevents(void)
xen_setup_cpu_clockevents();
}
-__init void xen_hvm_init_time_ops(void)
+void __init xen_hvm_init_time_ops(void)
{
/* vector callback is needed otherwise we cannot receive interrupts
* on cpu > 0 and at this point we don't know how many cpus are
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
index 3112f55638c4..97dfdc8757b3 100644
--- a/arch/x86/xen/xen-ops.h
+++ b/arch/x86/xen/xen-ops.h
@@ -74,7 +74,7 @@ static inline void xen_hvm_smp_init(void) {}
#ifdef CONFIG_PARAVIRT_SPINLOCKS
void __init xen_init_spinlocks(void);
-__cpuinit void xen_init_lock_cpu(int cpu);
+void __cpuinit xen_init_lock_cpu(int cpu);
void xen_uninit_lock_cpu(int cpu);
#else
static inline void xen_init_spinlocks(void)
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index 7c275f5d0df0..5d43c1f8ada8 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -20,12 +20,6 @@ config XTENSA
config RWSEM_XCHGADD_ALGORITHM
def_bool y
-config GENERIC_FIND_NEXT_BIT
- def_bool y
-
-config GENERIC_FIND_BIT_LE
- def_bool y
-
config GENERIC_HWEIGHT
def_bool y
diff --git a/arch/xtensa/configs/s6105_defconfig b/arch/xtensa/configs/s6105_defconfig
index 42b7feba71b7..4891abbf16bc 100644
--- a/arch/xtensa/configs/s6105_defconfig
+++ b/arch/xtensa/configs/s6105_defconfig
@@ -23,7 +23,6 @@ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_ON_SMP=y
-CONFIG_LOCK_KERNEL=y
CONFIG_INIT_ENV_ARG_LIMIT=32
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
diff --git a/arch/xtensa/include/asm/page.h b/arch/xtensa/include/asm/page.h
index 161bb89e98c8..7a5591a71f85 100644
--- a/arch/xtensa/include/asm/page.h
+++ b/arch/xtensa/include/asm/page.h
@@ -171,10 +171,6 @@ extern void copy_user_page(void*, void*, unsigned long, struct page*);
#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
-#ifdef CONFIG_MMU
-#define WANT_PAGE_VIRTUAL
-#endif
-
#endif /* __ASSEMBLY__ */
#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
diff --git a/arch/xtensa/kernel/vmlinux.lds.S b/arch/xtensa/kernel/vmlinux.lds.S
index a2820065927e..88ecea3facb4 100644
--- a/arch/xtensa/kernel/vmlinux.lds.S
+++ b/arch/xtensa/kernel/vmlinux.lds.S
@@ -155,7 +155,7 @@ SECTIONS
INIT_RAM_FS
}
- PERCPU(XCHAL_ICACHE_LINESIZE, PAGE_SIZE)
+ PERCPU_SECTION(XCHAL_ICACHE_LINESIZE)
/* We need this dummy segment here */
diff --git a/arch/xtensa/mm/mmu.c b/arch/xtensa/mm/mmu.c
index 4bb91a970f1f..ca81654f3ec2 100644
--- a/arch/xtensa/mm/mmu.c
+++ b/arch/xtensa/mm/mmu.c
@@ -14,8 +14,6 @@
#include <asm/mmu_context.h>
#include <asm/page.h>
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-
void __init paging_init(void)
{
memset(swapper_pg_dir, 0, PAGE_SIZE);
diff --git a/arch/xtensa/mm/pgtable.c b/arch/xtensa/mm/pgtable.c
deleted file mode 100644
index 697992738205..000000000000
--- a/arch/xtensa/mm/pgtable.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * arch/xtensa/mm/pgtable.c
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001 - 2005 Tensilica Inc.
- *
- * Chris Zankel <chris@zankel.net>
- */
-
-#if (DCACHE_SIZE > PAGE_SIZE)
-
-pte_t* pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
-{
- pte_t *pte = NULL, *p;
- int color = ADDR_COLOR(address);
- int i;
-
- p = (pte_t*) __get_free_pages(GFP_KERNEL|__GFP_REPEAT, COLOR_ORDER);
-
- if (likely(p)) {
- split_page(virt_to_page(p), COLOR_ORDER);
-
- for (i = 0; i < COLOR_SIZE; i++) {
- if (ADDR_COLOR(p) == color)
- pte = p;
- else
- free_page(p);
- p += PTRS_PER_PTE;
- }
- clear_page(pte);
- }
- return pte;
-}
-
-#ifdef PROFILING
-
-int mask;
-int hit;
-int flush;
-
-#endif
-
-struct page* pte_alloc_one(struct mm_struct *mm, unsigned long address)
-{
- struct page *page = NULL, *p;
- int color = ADDR_COLOR(address);
-
- p = alloc_pages(GFP_KERNEL | __GFP_REPEAT, PTE_ORDER);
-
- if (likely(p)) {
- split_page(p, COLOR_ORDER);
-
- for (i = 0; i < PAGE_ORDER; i++) {
- if (PADDR_COLOR(page_address(p)) == color)
- page = p;
- else
- __free_page(p);
- p++;
- }
- clear_highpage(page);
- }
-
- return page;
-}
-
-#endif
-
-
-
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index 471fdcc5df85..bcaf16ee6ad1 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -30,10 +30,8 @@ EXPORT_SYMBOL_GPL(blkio_root_cgroup);
static struct cgroup_subsys_state *blkiocg_create(struct cgroup_subsys *,
struct cgroup *);
-static int blkiocg_can_attach(struct cgroup_subsys *, struct cgroup *,
- struct task_struct *, bool);
-static void blkiocg_attach(struct cgroup_subsys *, struct cgroup *,
- struct cgroup *, struct task_struct *, bool);
+static int blkiocg_can_attach_task(struct cgroup *, struct task_struct *);
+static void blkiocg_attach_task(struct cgroup *, struct task_struct *);
static void blkiocg_destroy(struct cgroup_subsys *, struct cgroup *);
static int blkiocg_populate(struct cgroup_subsys *, struct cgroup *);
@@ -46,8 +44,8 @@ static int blkiocg_populate(struct cgroup_subsys *, struct cgroup *);
struct cgroup_subsys blkio_subsys = {
.name = "blkio",
.create = blkiocg_create,
- .can_attach = blkiocg_can_attach,
- .attach = blkiocg_attach,
+ .can_attach_task = blkiocg_can_attach_task,
+ .attach_task = blkiocg_attach_task,
.destroy = blkiocg_destroy,
.populate = blkiocg_populate,
#ifdef CONFIG_BLK_CGROUP
@@ -385,25 +383,40 @@ void blkiocg_update_timeslice_used(struct blkio_group *blkg, unsigned long time,
spin_lock_irqsave(&blkg->stats_lock, flags);
blkg->stats.time += time;
+#ifdef CONFIG_DEBUG_BLK_CGROUP
blkg->stats.unaccounted_time += unaccounted_time;
+#endif
spin_unlock_irqrestore(&blkg->stats_lock, flags);
}
EXPORT_SYMBOL_GPL(blkiocg_update_timeslice_used);
+/*
+ * should be called under rcu read lock or queue lock to make sure blkg pointer
+ * is valid.
+ */
void blkiocg_update_dispatch_stats(struct blkio_group *blkg,
uint64_t bytes, bool direction, bool sync)
{
- struct blkio_group_stats *stats;
+ struct blkio_group_stats_cpu *stats_cpu;
unsigned long flags;
- spin_lock_irqsave(&blkg->stats_lock, flags);
- stats = &blkg->stats;
- stats->sectors += bytes >> 9;
- blkio_add_stat(stats->stat_arr[BLKIO_STAT_SERVICED], 1, direction,
- sync);
- blkio_add_stat(stats->stat_arr[BLKIO_STAT_SERVICE_BYTES], bytes,
- direction, sync);
- spin_unlock_irqrestore(&blkg->stats_lock, flags);
+ /*
+ * Disabling interrupts to provide mutual exclusion between two
+ * writes on same cpu. It probably is not needed for 64bit. Not
+ * optimizing that case yet.
+ */
+ local_irq_save(flags);
+
+ stats_cpu = this_cpu_ptr(blkg->stats_cpu);
+
+ u64_stats_update_begin(&stats_cpu->syncp);
+ stats_cpu->sectors += bytes >> 9;
+ blkio_add_stat(stats_cpu->stat_arr_cpu[BLKIO_STAT_CPU_SERVICED],
+ 1, direction, sync);
+ blkio_add_stat(stats_cpu->stat_arr_cpu[BLKIO_STAT_CPU_SERVICE_BYTES],
+ bytes, direction, sync);
+ u64_stats_update_end(&stats_cpu->syncp);
+ local_irq_restore(flags);
}
EXPORT_SYMBOL_GPL(blkiocg_update_dispatch_stats);
@@ -426,18 +439,44 @@ void blkiocg_update_completion_stats(struct blkio_group *blkg,
}
EXPORT_SYMBOL_GPL(blkiocg_update_completion_stats);
+/* Merged stats are per cpu. */
void blkiocg_update_io_merged_stats(struct blkio_group *blkg, bool direction,
bool sync)
{
+ struct blkio_group_stats_cpu *stats_cpu;
unsigned long flags;
- spin_lock_irqsave(&blkg->stats_lock, flags);
- blkio_add_stat(blkg->stats.stat_arr[BLKIO_STAT_MERGED], 1, direction,
- sync);
- spin_unlock_irqrestore(&blkg->stats_lock, flags);
+ /*
+ * Disabling interrupts to provide mutual exclusion between two
+ * writes on same cpu. It probably is not needed for 64bit. Not
+ * optimizing that case yet.
+ */
+ local_irq_save(flags);
+
+ stats_cpu = this_cpu_ptr(blkg->stats_cpu);
+
+ u64_stats_update_begin(&stats_cpu->syncp);
+ blkio_add_stat(stats_cpu->stat_arr_cpu[BLKIO_STAT_CPU_MERGED], 1,
+ direction, sync);
+ u64_stats_update_end(&stats_cpu->syncp);
+ local_irq_restore(flags);
}
EXPORT_SYMBOL_GPL(blkiocg_update_io_merged_stats);
+/*
+ * This function allocates the per cpu stats for blkio_group. Should be called
+ * from sleepable context as alloc_per_cpu() requires that.
+ */
+int blkio_alloc_blkg_stats(struct blkio_group *blkg)
+{
+ /* Allocate memory for per cpu stats */
+ blkg->stats_cpu = alloc_percpu(struct blkio_group_stats_cpu);
+ if (!blkg->stats_cpu)
+ return -ENOMEM;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(blkio_alloc_blkg_stats);
+
void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
struct blkio_group *blkg, void *key, dev_t dev,
enum blkio_policy_id plid)
@@ -508,6 +547,30 @@ struct blkio_group *blkiocg_lookup_group(struct blkio_cgroup *blkcg, void *key)
}
EXPORT_SYMBOL_GPL(blkiocg_lookup_group);
+static void blkio_reset_stats_cpu(struct blkio_group *blkg)
+{
+ struct blkio_group_stats_cpu *stats_cpu;
+ int i, j, k;
+ /*
+ * Note: On 64 bit arch this should not be an issue. This has the
+ * possibility of returning some inconsistent value on 32bit arch
+ * as 64bit update on 32bit is non atomic. Taking care of this
+ * corner case makes code very complicated, like sending IPIs to
+ * cpus, taking care of stats of offline cpus etc.
+ *
+ * reset stats is anyway more of a debug feature and this sounds a
+ * corner case. So I am not complicating the code yet until and
+ * unless this becomes a real issue.
+ */
+ for_each_possible_cpu(i) {
+ stats_cpu = per_cpu_ptr(blkg->stats_cpu, i);
+ stats_cpu->sectors = 0;
+ for(j = 0; j < BLKIO_STAT_CPU_NR; j++)
+ for (k = 0; k < BLKIO_STAT_TOTAL; k++)
+ stats_cpu->stat_arr_cpu[j][k] = 0;
+ }
+}
+
static int
blkiocg_reset_stats(struct cgroup *cgroup, struct cftype *cftype, u64 val)
{
@@ -552,7 +615,11 @@ blkiocg_reset_stats(struct cgroup *cgroup, struct cftype *cftype, u64 val)
}
#endif
spin_unlock(&blkg->stats_lock);
+
+ /* Reset Per cpu stats which don't take blkg->stats_lock */
+ blkio_reset_stats_cpu(blkg);
}
+
spin_unlock_irq(&blkcg->lock);
return 0;
}
@@ -598,6 +665,59 @@ static uint64_t blkio_fill_stat(char *str, int chars_left, uint64_t val,
return val;
}
+
+static uint64_t blkio_read_stat_cpu(struct blkio_group *blkg,
+ enum stat_type_cpu type, enum stat_sub_type sub_type)
+{
+ int cpu;
+ struct blkio_group_stats_cpu *stats_cpu;
+ u64 val = 0, tval;
+
+ for_each_possible_cpu(cpu) {
+ unsigned int start;
+ stats_cpu = per_cpu_ptr(blkg->stats_cpu, cpu);
+
+ do {
+ start = u64_stats_fetch_begin(&stats_cpu->syncp);
+ if (type == BLKIO_STAT_CPU_SECTORS)
+ tval = stats_cpu->sectors;
+ else
+ tval = stats_cpu->stat_arr_cpu[type][sub_type];
+ } while(u64_stats_fetch_retry(&stats_cpu->syncp, start));
+
+ val += tval;
+ }
+
+ return val;
+}
+
+static uint64_t blkio_get_stat_cpu(struct blkio_group *blkg,
+ struct cgroup_map_cb *cb, dev_t dev, enum stat_type_cpu type)
+{
+ uint64_t disk_total, val;
+ char key_str[MAX_KEY_LEN];
+ enum stat_sub_type sub_type;
+
+ if (type == BLKIO_STAT_CPU_SECTORS) {
+ val = blkio_read_stat_cpu(blkg, type, 0);
+ return blkio_fill_stat(key_str, MAX_KEY_LEN - 1, val, cb, dev);
+ }
+
+ for (sub_type = BLKIO_STAT_READ; sub_type < BLKIO_STAT_TOTAL;
+ sub_type++) {
+ blkio_get_key_name(sub_type, dev, key_str, MAX_KEY_LEN, false);
+ val = blkio_read_stat_cpu(blkg, type, sub_type);
+ cb->fill(cb, key_str, val);
+ }
+
+ disk_total = blkio_read_stat_cpu(blkg, type, BLKIO_STAT_READ) +
+ blkio_read_stat_cpu(blkg, type, BLKIO_STAT_WRITE);
+
+ blkio_get_key_name(BLKIO_STAT_TOTAL, dev, key_str, MAX_KEY_LEN, false);
+ cb->fill(cb, key_str, disk_total);
+ return disk_total;
+}
+
/* This should be called with blkg->stats_lock held */
static uint64_t blkio_get_stat(struct blkio_group *blkg,
struct cgroup_map_cb *cb, dev_t dev, enum stat_type type)
@@ -609,9 +729,6 @@ static uint64_t blkio_get_stat(struct blkio_group *blkg,
if (type == BLKIO_STAT_TIME)
return blkio_fill_stat(key_str, MAX_KEY_LEN - 1,
blkg->stats.time, cb, dev);
- if (type == BLKIO_STAT_SECTORS)
- return blkio_fill_stat(key_str, MAX_KEY_LEN - 1,
- blkg->stats.sectors, cb, dev);
#ifdef CONFIG_DEBUG_BLK_CGROUP
if (type == BLKIO_STAT_UNACCOUNTED_TIME)
return blkio_fill_stat(key_str, MAX_KEY_LEN - 1,
@@ -1075,8 +1192,8 @@ static int blkiocg_file_read(struct cgroup *cgrp, struct cftype *cft,
}
static int blkio_read_blkg_stats(struct blkio_cgroup *blkcg,
- struct cftype *cft, struct cgroup_map_cb *cb, enum stat_type type,
- bool show_total)
+ struct cftype *cft, struct cgroup_map_cb *cb,
+ enum stat_type type, bool show_total, bool pcpu)
{
struct blkio_group *blkg;
struct hlist_node *n;
@@ -1087,10 +1204,15 @@ static int blkio_read_blkg_stats(struct blkio_cgroup *blkcg,
if (blkg->dev) {
if (!cftype_blkg_same_policy(cft, blkg))
continue;
- spin_lock_irq(&blkg->stats_lock);
- cgroup_total += blkio_get_stat(blkg, cb, blkg->dev,
- type);
- spin_unlock_irq(&blkg->stats_lock);
+ if (pcpu)
+ cgroup_total += blkio_get_stat_cpu(blkg, cb,
+ blkg->dev, type);
+ else {
+ spin_lock_irq(&blkg->stats_lock);
+ cgroup_total += blkio_get_stat(blkg, cb,
+ blkg->dev, type);
+ spin_unlock_irq(&blkg->stats_lock);
+ }
}
}
if (show_total)
@@ -1114,47 +1236,47 @@ static int blkiocg_file_read_map(struct cgroup *cgrp, struct cftype *cft,
switch(name) {
case BLKIO_PROP_time:
return blkio_read_blkg_stats(blkcg, cft, cb,
- BLKIO_STAT_TIME, 0);
+ BLKIO_STAT_TIME, 0, 0);
case BLKIO_PROP_sectors:
return blkio_read_blkg_stats(blkcg, cft, cb,
- BLKIO_STAT_SECTORS, 0);
+ BLKIO_STAT_CPU_SECTORS, 0, 1);
case BLKIO_PROP_io_service_bytes:
return blkio_read_blkg_stats(blkcg, cft, cb,
- BLKIO_STAT_SERVICE_BYTES, 1);
+ BLKIO_STAT_CPU_SERVICE_BYTES, 1, 1);
case BLKIO_PROP_io_serviced:
return blkio_read_blkg_stats(blkcg, cft, cb,
- BLKIO_STAT_SERVICED, 1);
+ BLKIO_STAT_CPU_SERVICED, 1, 1);
case BLKIO_PROP_io_service_time:
return blkio_read_blkg_stats(blkcg, cft, cb,
- BLKIO_STAT_SERVICE_TIME, 1);
+ BLKIO_STAT_SERVICE_TIME, 1, 0);
case BLKIO_PROP_io_wait_time:
return blkio_read_blkg_stats(blkcg, cft, cb,
- BLKIO_STAT_WAIT_TIME, 1);
+ BLKIO_STAT_WAIT_TIME, 1, 0);
case BLKIO_PROP_io_merged:
return blkio_read_blkg_stats(blkcg, cft, cb,
- BLKIO_STAT_MERGED, 1);
+ BLKIO_STAT_CPU_MERGED, 1, 1);
case BLKIO_PROP_io_queued:
return blkio_read_blkg_stats(blkcg, cft, cb,
- BLKIO_STAT_QUEUED, 1);
+ BLKIO_STAT_QUEUED, 1, 0);
#ifdef CONFIG_DEBUG_BLK_CGROUP
case BLKIO_PROP_unaccounted_time:
return blkio_read_blkg_stats(blkcg, cft, cb,
- BLKIO_STAT_UNACCOUNTED_TIME, 0);
+ BLKIO_STAT_UNACCOUNTED_TIME, 0, 0);
case BLKIO_PROP_dequeue:
return blkio_read_blkg_stats(blkcg, cft, cb,
- BLKIO_STAT_DEQUEUE, 0);
+ BLKIO_STAT_DEQUEUE, 0, 0);
case BLKIO_PROP_avg_queue_size:
return blkio_read_blkg_stats(blkcg, cft, cb,
- BLKIO_STAT_AVG_QUEUE_SIZE, 0);
+ BLKIO_STAT_AVG_QUEUE_SIZE, 0, 0);
case BLKIO_PROP_group_wait_time:
return blkio_read_blkg_stats(blkcg, cft, cb,
- BLKIO_STAT_GROUP_WAIT_TIME, 0);
+ BLKIO_STAT_GROUP_WAIT_TIME, 0, 0);
case BLKIO_PROP_idle_time:
return blkio_read_blkg_stats(blkcg, cft, cb,
- BLKIO_STAT_IDLE_TIME, 0);
+ BLKIO_STAT_IDLE_TIME, 0, 0);
case BLKIO_PROP_empty_time:
return blkio_read_blkg_stats(blkcg, cft, cb,
- BLKIO_STAT_EMPTY_TIME, 0);
+ BLKIO_STAT_EMPTY_TIME, 0, 0);
#endif
default:
BUG();
@@ -1164,10 +1286,10 @@ static int blkiocg_file_read_map(struct cgroup *cgrp, struct cftype *cft,
switch(name){
case BLKIO_THROTL_io_service_bytes:
return blkio_read_blkg_stats(blkcg, cft, cb,
- BLKIO_STAT_SERVICE_BYTES, 1);
+ BLKIO_STAT_CPU_SERVICE_BYTES, 1, 1);
case BLKIO_THROTL_io_serviced:
return blkio_read_blkg_stats(blkcg, cft, cb,
- BLKIO_STAT_SERVICED, 1);
+ BLKIO_STAT_CPU_SERVICED, 1, 1);
default:
BUG();
}
@@ -1492,9 +1614,7 @@ done:
* of the main cic data structures. For now we allow a task to change
* its cgroup only if it's the only owner of its ioc.
*/
-static int blkiocg_can_attach(struct cgroup_subsys *subsys,
- struct cgroup *cgroup, struct task_struct *tsk,
- bool threadgroup)
+static int blkiocg_can_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
{
struct io_context *ioc;
int ret = 0;
@@ -1509,9 +1629,7 @@ static int blkiocg_can_attach(struct cgroup_subsys *subsys,
return ret;
}
-static void blkiocg_attach(struct cgroup_subsys *subsys, struct cgroup *cgroup,
- struct cgroup *prev, struct task_struct *tsk,
- bool threadgroup)
+static void blkiocg_attach_task(struct cgroup *cgrp, struct task_struct *tsk)
{
struct io_context *ioc;
diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h
index c774930cc206..a71d2904ffb9 100644
--- a/block/blk-cgroup.h
+++ b/block/blk-cgroup.h
@@ -14,6 +14,7 @@
*/
#include <linux/cgroup.h>
+#include <linux/u64_stats_sync.h>
enum blkio_policy_id {
BLKIO_POLICY_PROP = 0, /* Proportional Bandwidth division */
@@ -36,22 +37,15 @@ enum stat_type {
* request completion for IOs doen by this cgroup. This may not be
* accurate when NCQ is turned on. */
BLKIO_STAT_SERVICE_TIME = 0,
- /* Total bytes transferred */
- BLKIO_STAT_SERVICE_BYTES,
- /* Total IOs serviced, post merge */
- BLKIO_STAT_SERVICED,
/* Total time spent waiting in scheduler queue in ns */
BLKIO_STAT_WAIT_TIME,
- /* Number of IOs merged */
- BLKIO_STAT_MERGED,
/* Number of IOs queued up */
BLKIO_STAT_QUEUED,
/* All the single valued stats go below this */
BLKIO_STAT_TIME,
- BLKIO_STAT_SECTORS,
+#ifdef CONFIG_DEBUG_BLK_CGROUP
/* Time not charged to this cgroup */
BLKIO_STAT_UNACCOUNTED_TIME,
-#ifdef CONFIG_DEBUG_BLK_CGROUP
BLKIO_STAT_AVG_QUEUE_SIZE,
BLKIO_STAT_IDLE_TIME,
BLKIO_STAT_EMPTY_TIME,
@@ -60,6 +54,18 @@ enum stat_type {
#endif
};
+/* Per cpu stats */
+enum stat_type_cpu {
+ BLKIO_STAT_CPU_SECTORS,
+ /* Total bytes transferred */
+ BLKIO_STAT_CPU_SERVICE_BYTES,
+ /* Total IOs serviced, post merge */
+ BLKIO_STAT_CPU_SERVICED,
+ /* Number of IOs merged */
+ BLKIO_STAT_CPU_MERGED,
+ BLKIO_STAT_CPU_NR
+};
+
enum stat_sub_type {
BLKIO_STAT_READ = 0,
BLKIO_STAT_WRITE,
@@ -116,11 +122,11 @@ struct blkio_cgroup {
struct blkio_group_stats {
/* total disk time and nr sectors dispatched by this group */
uint64_t time;
- uint64_t sectors;
- /* Time not charged to this cgroup */
- uint64_t unaccounted_time;
uint64_t stat_arr[BLKIO_STAT_QUEUED + 1][BLKIO_STAT_TOTAL];
#ifdef CONFIG_DEBUG_BLK_CGROUP
+ /* Time not charged to this cgroup */
+ uint64_t unaccounted_time;
+
/* Sum of number of IOs queued across all samples */
uint64_t avg_queue_size_sum;
/* Count of samples taken for average */
@@ -145,6 +151,13 @@ struct blkio_group_stats {
#endif
};
+/* Per cpu blkio group stats */
+struct blkio_group_stats_cpu {
+ uint64_t sectors;
+ uint64_t stat_arr_cpu[BLKIO_STAT_CPU_NR][BLKIO_STAT_TOTAL];
+ struct u64_stats_sync syncp;
+};
+
struct blkio_group {
/* An rcu protected unique identifier for the group */
void *key;
@@ -160,6 +173,8 @@ struct blkio_group {
/* Need to serialize the stats in the case of reset/update */
spinlock_t stats_lock;
struct blkio_group_stats stats;
+ /* Per cpu stats pointer */
+ struct blkio_group_stats_cpu __percpu *stats_cpu;
};
struct blkio_policy_node {
@@ -295,6 +310,7 @@ extern struct blkio_cgroup *task_blkio_cgroup(struct task_struct *tsk);
extern void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
struct blkio_group *blkg, void *key, dev_t dev,
enum blkio_policy_id plid);
+extern int blkio_alloc_blkg_stats(struct blkio_group *blkg);
extern int blkiocg_del_blkio_group(struct blkio_group *blkg);
extern struct blkio_group *blkiocg_lookup_group(struct blkio_cgroup *blkcg,
void *key);
@@ -322,6 +338,8 @@ static inline void blkiocg_add_blkio_group(struct blkio_cgroup *blkcg,
struct blkio_group *blkg, void *key, dev_t dev,
enum blkio_policy_id plid) {}
+static inline int blkio_alloc_blkg_stats(struct blkio_group *blkg) { return 0; }
+
static inline int
blkiocg_del_blkio_group(struct blkio_group *blkg) { return 0; }
diff --git a/block/blk-core.c b/block/blk-core.c
index 3fe00a14822a..d2f8f4049abd 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -345,6 +345,7 @@ void blk_put_queue(struct request_queue *q)
{
kobject_put(&q->kobj);
}
+EXPORT_SYMBOL(blk_put_queue);
/*
* Note: If a driver supplied the queue lock, it should not zap that lock
@@ -566,11 +567,10 @@ int blk_get_queue(struct request_queue *q)
return 1;
}
+EXPORT_SYMBOL(blk_get_queue);
static inline void blk_free_request(struct request_queue *q, struct request *rq)
{
- BUG_ON(rq->cmd_flags & REQ_ON_PLUG);
-
if (rq->cmd_flags & REQ_ELVPRIV)
elv_put_request(q, rq);
mempool_free(rq, q->rq.rq_pool);
@@ -1110,14 +1110,6 @@ static bool bio_attempt_back_merge(struct request_queue *q, struct request *req,
{
const int ff = bio->bi_rw & REQ_FAILFAST_MASK;
- /*
- * Debug stuff, kill later
- */
- if (!rq_mergeable(req)) {
- blk_dump_rq_flags(req, "back");
- return false;
- }
-
if (!ll_back_merge_fn(q, req, bio))
return false;
@@ -1132,6 +1124,7 @@ static bool bio_attempt_back_merge(struct request_queue *q, struct request *req,
req->ioprio = ioprio_best(req->ioprio, bio_prio(bio));
drive_stat_acct(req, 0);
+ elv_bio_merged(q, req, bio);
return true;
}
@@ -1139,15 +1132,6 @@ static bool bio_attempt_front_merge(struct request_queue *q,
struct request *req, struct bio *bio)
{
const int ff = bio->bi_rw & REQ_FAILFAST_MASK;
- sector_t sector;
-
- /*
- * Debug stuff, kill later
- */
- if (!rq_mergeable(req)) {
- blk_dump_rq_flags(req, "front");
- return false;
- }
if (!ll_front_merge_fn(q, req, bio))
return false;
@@ -1157,8 +1141,6 @@ static bool bio_attempt_front_merge(struct request_queue *q,
if ((req->cmd_flags & REQ_FAILFAST_MASK) != ff)
blk_rq_set_mixed_merge(req);
- sector = bio->bi_sector;
-
bio->bi_next = req->bio;
req->bio = bio;
@@ -1173,6 +1155,7 @@ static bool bio_attempt_front_merge(struct request_queue *q,
req->ioprio = ioprio_best(req->ioprio, bio_prio(bio));
drive_stat_acct(req, 0);
+ elv_bio_merged(q, req, bio);
return true;
}
@@ -1258,14 +1241,12 @@ static int __make_request(struct request_queue *q, struct bio *bio)
el_ret = elv_merge(q, &req, bio);
if (el_ret == ELEVATOR_BACK_MERGE) {
- BUG_ON(req->cmd_flags & REQ_ON_PLUG);
if (bio_attempt_back_merge(q, req, bio)) {
if (!attempt_back_merge(q, req))
elv_merged_request(q, req, el_ret);
goto out_unlock;
}
} else if (el_ret == ELEVATOR_FRONT_MERGE) {
- BUG_ON(req->cmd_flags & REQ_ON_PLUG);
if (bio_attempt_front_merge(q, req, bio)) {
if (!attempt_front_merge(q, req))
elv_merged_request(q, req, el_ret);
@@ -1320,10 +1301,6 @@ get_rq:
if (__rq->q != q)
plug->should_sort = 1;
}
- /*
- * Debug flag, kill later
- */
- req->cmd_flags |= REQ_ON_PLUG;
list_add_tail(&req->queuelist, &plug->list);
drive_stat_acct(req, 1);
} else {
@@ -1550,7 +1527,8 @@ static inline void __generic_make_request(struct bio *bio)
goto end_io;
}
- blk_throtl_bio(q, &bio);
+ if (blk_throtl_bio(q, &bio))
+ goto end_io;
/*
* If bio = NULL, bio has been throttled and will be submitted
@@ -2748,7 +2726,6 @@ void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule)
while (!list_empty(&list)) {
rq = list_entry_rq(list.next);
list_del_init(&rq->queuelist);
- BUG_ON(!(rq->cmd_flags & REQ_ON_PLUG));
BUG_ON(!rq->q);
if (rq->q != q) {
/*
@@ -2760,8 +2737,6 @@ void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule)
depth = 0;
spin_lock(q->queue_lock);
}
- rq->cmd_flags &= ~REQ_ON_PLUG;
-
/*
* rq is already accounted, so use raw insert
*/
diff --git a/block/blk-exec.c b/block/blk-exec.c
index 81e31819a597..8a0e7ec056e7 100644
--- a/block/blk-exec.c
+++ b/block/blk-exec.c
@@ -56,7 +56,7 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
spin_lock_irq(q->queue_lock);
__elv_add_request(q, rq, where);
__blk_run_queue(q);
- /* the queue is stopped so it won't be plugged+unplugged */
+ /* the queue is stopped so it won't be run */
if (rq->cmd_type == REQ_TYPE_PM_RESUME)
q->request_fn(q);
spin_unlock_irq(q->queue_lock);
diff --git a/block/blk-flush.c b/block/blk-flush.c
index 6c9b5e189e62..bb21e4c36f70 100644
--- a/block/blk-flush.c
+++ b/block/blk-flush.c
@@ -212,13 +212,19 @@ static void flush_end_io(struct request *flush_rq, int error)
}
/*
- * Moving a request silently to empty queue_head may stall the
- * queue. Kick the queue in those cases. This function is called
- * from request completion path and calling directly into
- * request_fn may confuse the driver. Always use kblockd.
+ * Kick the queue to avoid stall for two cases:
+ * 1. Moving a request silently to empty queue_head may stall the
+ * queue.
+ * 2. When flush request is running in non-queueable queue, the
+ * queue is hold. Restart the queue after flush request is finished
+ * to avoid stall.
+ * This function is called from request completion path and calling
+ * directly into request_fn may confuse the driver. Always use
+ * kblockd.
*/
- if (queued)
+ if (queued || q->flush_queue_delayed)
blk_run_queue_async(q);
+ q->flush_queue_delayed = 0;
}
/**
diff --git a/block/blk-ioc.c b/block/blk-ioc.c
index b791022beef3..c898049dafd5 100644
--- a/block/blk-ioc.c
+++ b/block/blk-ioc.c
@@ -96,6 +96,9 @@ struct io_context *alloc_io_context(gfp_t gfp_flags, int node)
INIT_RADIX_TREE(&ret->radix_root, GFP_ATOMIC | __GFP_HIGH);
INIT_HLIST_HEAD(&ret->cic_list);
ret->ioc_data = NULL;
+#if defined(CONFIG_BLK_CGROUP) || defined(CONFIG_BLK_CGROUP_MODULE)
+ ret->cgroup_changed = 0;
+#endif
}
return ret;
diff --git a/block/blk-lib.c b/block/blk-lib.c
index 25de73e4759b..78e627e2581d 100644
--- a/block/blk-lib.c
+++ b/block/blk-lib.c
@@ -9,17 +9,20 @@
#include "blk.h"
-static void blkdev_discard_end_io(struct bio *bio, int err)
-{
- if (err) {
- if (err == -EOPNOTSUPP)
- set_bit(BIO_EOPNOTSUPP, &bio->bi_flags);
- clear_bit(BIO_UPTODATE, &bio->bi_flags);
- }
+struct bio_batch {
+ atomic_t done;
+ unsigned long flags;
+ struct completion *wait;
+};
- if (bio->bi_private)
- complete(bio->bi_private);
+static void bio_batch_end_io(struct bio *bio, int err)
+{
+ struct bio_batch *bb = bio->bi_private;
+ if (err && (err != -EOPNOTSUPP))
+ clear_bit(BIO_UPTODATE, &bb->flags);
+ if (atomic_dec_and_test(&bb->done))
+ complete(bb->wait);
bio_put(bio);
}
@@ -41,6 +44,7 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
struct request_queue *q = bdev_get_queue(bdev);
int type = REQ_WRITE | REQ_DISCARD;
unsigned int max_discard_sectors;
+ struct bio_batch bb;
struct bio *bio;
int ret = 0;
@@ -67,7 +71,11 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
type |= REQ_SECURE;
}
- while (nr_sects && !ret) {
+ atomic_set(&bb.done, 1);
+ bb.flags = 1 << BIO_UPTODATE;
+ bb.wait = &wait;
+
+ while (nr_sects) {
bio = bio_alloc(gfp_mask, 1);
if (!bio) {
ret = -ENOMEM;
@@ -75,9 +83,9 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
}
bio->bi_sector = sector;
- bio->bi_end_io = blkdev_discard_end_io;
+ bio->bi_end_io = bio_batch_end_io;
bio->bi_bdev = bdev;
- bio->bi_private = &wait;
+ bio->bi_private = &bb;
if (nr_sects > max_discard_sectors) {
bio->bi_size = max_discard_sectors << 9;
@@ -88,45 +96,21 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
nr_sects = 0;
}
- bio_get(bio);
+ atomic_inc(&bb.done);
submit_bio(type, bio);
+ }
+ /* Wait for bios in-flight */
+ if (!atomic_dec_and_test(&bb.done))
wait_for_completion(&wait);
- if (bio_flagged(bio, BIO_EOPNOTSUPP))
- ret = -EOPNOTSUPP;
- else if (!bio_flagged(bio, BIO_UPTODATE))
- ret = -EIO;
- bio_put(bio);
- }
+ if (!test_bit(BIO_UPTODATE, &bb.flags))
+ ret = -EIO;
return ret;
}
EXPORT_SYMBOL(blkdev_issue_discard);
-struct bio_batch
-{
- atomic_t done;
- unsigned long flags;
- struct completion *wait;
-};
-
-static void bio_batch_end_io(struct bio *bio, int err)
-{
- struct bio_batch *bb = bio->bi_private;
-
- if (err) {
- if (err == -EOPNOTSUPP)
- set_bit(BIO_EOPNOTSUPP, &bb->flags);
- else
- clear_bit(BIO_UPTODATE, &bb->flags);
- }
- if (bb)
- if (atomic_dec_and_test(&bb->done))
- complete(bb->wait);
- bio_put(bio);
-}
-
/**
* blkdev_issue_zeroout - generate number of zero filed write bios
* @bdev: blockdev to issue
@@ -151,7 +135,6 @@ int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
bb.flags = 1 << BIO_UPTODATE;
bb.wait = &wait;
-submit:
ret = 0;
while (nr_sects != 0) {
bio = bio_alloc(gfp_mask,
@@ -168,9 +151,6 @@ submit:
while (nr_sects != 0) {
sz = min((sector_t) PAGE_SIZE >> 9 , nr_sects);
- if (sz == 0)
- /* bio has maximum size possible */
- break;
ret = bio_add_page(bio, ZERO_PAGE(0), sz << 9, 0);
nr_sects -= ret >> 9;
sector += ret >> 9;
@@ -190,16 +170,6 @@ submit:
/* One of bios in the batch was completed with error.*/
ret = -EIO;
- if (ret)
- goto out;
-
- if (test_bit(BIO_EOPNOTSUPP, &bb.flags)) {
- ret = -EOPNOTSUPP;
- goto out;
- }
- if (nr_sects != 0)
- goto submit;
-out:
return ret;
}
EXPORT_SYMBOL(blkdev_issue_zeroout);
diff --git a/block/blk-settings.c b/block/blk-settings.c
index 1fa769293597..fa1eb0449a05 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -120,7 +120,7 @@ void blk_set_default_limits(struct queue_limits *lim)
lim->discard_granularity = 0;
lim->discard_alignment = 0;
lim->discard_misaligned = 0;
- lim->discard_zeroes_data = -1;
+ lim->discard_zeroes_data = 1;
lim->logical_block_size = lim->physical_block_size = lim->io_min = 512;
lim->bounce_pfn = (unsigned long)(BLK_BOUNCE_ANY >> PAGE_SHIFT);
lim->alignment_offset = 0;
@@ -166,6 +166,7 @@ void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn)
blk_set_default_limits(&q->limits);
blk_queue_max_hw_sectors(q, BLK_SAFE_MAX_SECTORS);
+ q->limits.discard_zeroes_data = 0;
/*
* by default assume old behaviour and bounce for any highmem page
@@ -790,6 +791,12 @@ void blk_queue_flush(struct request_queue *q, unsigned int flush)
}
EXPORT_SYMBOL_GPL(blk_queue_flush);
+void blk_queue_flush_queueable(struct request_queue *q, bool queueable)
+{
+ q->flush_not_queueable = !queueable;
+}
+EXPORT_SYMBOL_GPL(blk_queue_flush_queueable);
+
static int __init blk_settings_init(void)
{
blk_max_low_pfn = max_low_pfn - 1;
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index bd236313f35d..d935bd859c87 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -152,7 +152,8 @@ static ssize_t queue_discard_granularity_show(struct request_queue *q, char *pag
static ssize_t queue_discard_max_show(struct request_queue *q, char *page)
{
- return queue_var_show(q->limits.max_discard_sectors << 9, page);
+ return sprintf(page, "%llu\n",
+ (unsigned long long)q->limits.max_discard_sectors << 9);
}
static ssize_t queue_discard_zeroes_data_show(struct request_queue *q, char *page)
diff --git a/block/blk-throttle.c b/block/blk-throttle.c
index 252a81a306f7..a62be8d0dc1b 100644
--- a/block/blk-throttle.c
+++ b/block/blk-throttle.c
@@ -78,6 +78,8 @@ struct throtl_grp {
/* Some throttle limits got updated for the group */
int limits_changed;
+
+ struct rcu_head rcu_head;
};
struct throtl_data
@@ -88,7 +90,7 @@ struct throtl_data
/* service tree for active throtl groups */
struct throtl_rb_root tg_service_tree;
- struct throtl_grp root_tg;
+ struct throtl_grp *root_tg;
struct request_queue *queue;
/* Total Number of queued bios on READ and WRITE lists */
@@ -151,56 +153,44 @@ static inline struct throtl_grp *throtl_ref_get_tg(struct throtl_grp *tg)
return tg;
}
-static void throtl_put_tg(struct throtl_grp *tg)
+static void throtl_free_tg(struct rcu_head *head)
{
- BUG_ON(atomic_read(&tg->ref) <= 0);
- if (!atomic_dec_and_test(&tg->ref))
- return;
+ struct throtl_grp *tg;
+
+ tg = container_of(head, struct throtl_grp, rcu_head);
+ free_percpu(tg->blkg.stats_cpu);
kfree(tg);
}
-static struct throtl_grp * throtl_find_alloc_tg(struct throtl_data *td,
- struct blkio_cgroup *blkcg)
+static void throtl_put_tg(struct throtl_grp *tg)
{
- struct throtl_grp *tg = NULL;
- void *key = td;
- struct backing_dev_info *bdi = &td->queue->backing_dev_info;
- unsigned int major, minor;
+ BUG_ON(atomic_read(&tg->ref) <= 0);
+ if (!atomic_dec_and_test(&tg->ref))
+ return;
/*
- * TODO: Speed up blkiocg_lookup_group() by maintaining a radix
- * tree of blkg (instead of traversing through hash list all
- * the time.
+ * A group is freed in rcu manner. But having an rcu lock does not
+ * mean that one can access all the fields of blkg and assume these
+ * are valid. For example, don't try to follow throtl_data and
+ * request queue links.
+ *
+ * Having a reference to blkg under an rcu allows acess to only
+ * values local to groups like group stats and group rate limits
*/
+ call_rcu(&tg->rcu_head, throtl_free_tg);
+}
- /*
- * This is the common case when there are no blkio cgroups.
- * Avoid lookup in this case
- */
- if (blkcg == &blkio_root_cgroup)
- tg = &td->root_tg;
- else
- tg = tg_of_blkg(blkiocg_lookup_group(blkcg, key));
-
- /* Fill in device details for root group */
- if (tg && !tg->blkg.dev && bdi->dev && dev_name(bdi->dev)) {
- sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
- tg->blkg.dev = MKDEV(major, minor);
- goto done;
- }
-
- if (tg)
- goto done;
-
- tg = kzalloc_node(sizeof(*tg), GFP_ATOMIC, td->queue->node);
- if (!tg)
- goto done;
-
+static void throtl_init_group(struct throtl_grp *tg)
+{
INIT_HLIST_NODE(&tg->tg_node);
RB_CLEAR_NODE(&tg->rb_node);
bio_list_init(&tg->bio_lists[0]);
bio_list_init(&tg->bio_lists[1]);
- td->limits_changed = false;
+ tg->limits_changed = false;
+
+ /* Practically unlimited BW */
+ tg->bps[0] = tg->bps[1] = -1;
+ tg->iops[0] = tg->iops[1] = -1;
/*
* Take the initial reference that will be released on destroy
@@ -209,33 +199,181 @@ static struct throtl_grp * throtl_find_alloc_tg(struct throtl_data *td,
* exit or cgroup deletion path depending on who is exiting first.
*/
atomic_set(&tg->ref, 1);
+}
+
+/* Should be called with rcu read lock held (needed for blkcg) */
+static void
+throtl_add_group_to_td_list(struct throtl_data *td, struct throtl_grp *tg)
+{
+ hlist_add_head(&tg->tg_node, &td->tg_list);
+ td->nr_undestroyed_grps++;
+}
+
+static void
+__throtl_tg_fill_dev_details(struct throtl_data *td, struct throtl_grp *tg)
+{
+ struct backing_dev_info *bdi = &td->queue->backing_dev_info;
+ unsigned int major, minor;
+
+ if (!tg || tg->blkg.dev)
+ return;
+
+ /*
+ * Fill in device details for a group which might not have been
+ * filled at group creation time as queue was being instantiated
+ * and driver had not attached a device yet
+ */
+ if (bdi->dev && dev_name(bdi->dev)) {
+ sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
+ tg->blkg.dev = MKDEV(major, minor);
+ }
+}
+
+/*
+ * Should be called with without queue lock held. Here queue lock will be
+ * taken rarely. It will be taken only once during life time of a group
+ * if need be
+ */
+static void
+throtl_tg_fill_dev_details(struct throtl_data *td, struct throtl_grp *tg)
+{
+ if (!tg || tg->blkg.dev)
+ return;
+
+ spin_lock_irq(td->queue->queue_lock);
+ __throtl_tg_fill_dev_details(td, tg);
+ spin_unlock_irq(td->queue->queue_lock);
+}
+
+static void throtl_init_add_tg_lists(struct throtl_data *td,
+ struct throtl_grp *tg, struct blkio_cgroup *blkcg)
+{
+ __throtl_tg_fill_dev_details(td, tg);
/* Add group onto cgroup list */
- sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
blkiocg_add_blkio_group(blkcg, &tg->blkg, (void *)td,
- MKDEV(major, minor), BLKIO_POLICY_THROTL);
+ tg->blkg.dev, BLKIO_POLICY_THROTL);
tg->bps[READ] = blkcg_get_read_bps(blkcg, tg->blkg.dev);
tg->bps[WRITE] = blkcg_get_write_bps(blkcg, tg->blkg.dev);
tg->iops[READ] = blkcg_get_read_iops(blkcg, tg->blkg.dev);
tg->iops[WRITE] = blkcg_get_write_iops(blkcg, tg->blkg.dev);
- hlist_add_head(&tg->tg_node, &td->tg_list);
- td->nr_undestroyed_grps++;
-done:
+ throtl_add_group_to_td_list(td, tg);
+}
+
+/* Should be called without queue lock and outside of rcu period */
+static struct throtl_grp *throtl_alloc_tg(struct throtl_data *td)
+{
+ struct throtl_grp *tg = NULL;
+ int ret;
+
+ tg = kzalloc_node(sizeof(*tg), GFP_ATOMIC, td->queue->node);
+ if (!tg)
+ return NULL;
+
+ ret = blkio_alloc_blkg_stats(&tg->blkg);
+
+ if (ret) {
+ kfree(tg);
+ return NULL;
+ }
+
+ throtl_init_group(tg);
return tg;
}
-static struct throtl_grp * throtl_get_tg(struct throtl_data *td)
+static struct
+throtl_grp *throtl_find_tg(struct throtl_data *td, struct blkio_cgroup *blkcg)
{
struct throtl_grp *tg = NULL;
+ void *key = td;
+
+ /*
+ * This is the common case when there are no blkio cgroups.
+ * Avoid lookup in this case
+ */
+ if (blkcg == &blkio_root_cgroup)
+ tg = td->root_tg;
+ else
+ tg = tg_of_blkg(blkiocg_lookup_group(blkcg, key));
+
+ __throtl_tg_fill_dev_details(td, tg);
+ return tg;
+}
+
+/*
+ * This function returns with queue lock unlocked in case of error, like
+ * request queue is no more
+ */
+static struct throtl_grp * throtl_get_tg(struct throtl_data *td)
+{
+ struct throtl_grp *tg = NULL, *__tg = NULL;
struct blkio_cgroup *blkcg;
+ struct request_queue *q = td->queue;
rcu_read_lock();
blkcg = task_blkio_cgroup(current);
- tg = throtl_find_alloc_tg(td, blkcg);
- if (!tg)
- tg = &td->root_tg;
+ tg = throtl_find_tg(td, blkcg);
+ if (tg) {
+ rcu_read_unlock();
+ return tg;
+ }
+
+ /*
+ * Need to allocate a group. Allocation of group also needs allocation
+ * of per cpu stats which in-turn takes a mutex() and can block. Hence
+ * we need to drop rcu lock and queue_lock before we call alloc
+ *
+ * Take the request queue reference to make sure queue does not
+ * go away once we return from allocation.
+ */
+ blk_get_queue(q);
+ rcu_read_unlock();
+ spin_unlock_irq(q->queue_lock);
+
+ tg = throtl_alloc_tg(td);
+ /*
+ * We might have slept in group allocation. Make sure queue is not
+ * dead
+ */
+ if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) {
+ blk_put_queue(q);
+ if (tg)
+ kfree(tg);
+
+ return ERR_PTR(-ENODEV);
+ }
+ blk_put_queue(q);
+
+ /* Group allocated and queue is still alive. take the lock */
+ spin_lock_irq(q->queue_lock);
+
+ /*
+ * Initialize the new group. After sleeping, read the blkcg again.
+ */
+ rcu_read_lock();
+ blkcg = task_blkio_cgroup(current);
+
+ /*
+ * If some other thread already allocated the group while we were
+ * not holding queue lock, free up the group
+ */
+ __tg = throtl_find_tg(td, blkcg);
+
+ if (__tg) {
+ kfree(tg);
+ rcu_read_unlock();
+ return __tg;
+ }
+
+ /* Group allocation failed. Account the IO to root group */
+ if (!tg) {
+ tg = td->root_tg;
+ return tg;
+ }
+
+ throtl_init_add_tg_lists(td, tg, blkcg);
rcu_read_unlock();
return tg;
}
@@ -544,6 +682,12 @@ static bool tg_with_in_bps_limit(struct throtl_data *td, struct throtl_grp *tg,
return 0;
}
+static bool tg_no_rule_group(struct throtl_grp *tg, bool rw) {
+ if (tg->bps[rw] == -1 && tg->iops[rw] == -1)
+ return 1;
+ return 0;
+}
+
/*
* Returns whether one can dispatch a bio or not. Also returns approx number
* of jiffies to wait before this bio is with-in IO rate and can be dispatched
@@ -608,10 +752,6 @@ static void throtl_charge_bio(struct throtl_grp *tg, struct bio *bio)
tg->bytes_disp[rw] += bio->bi_size;
tg->io_disp[rw]++;
- /*
- * TODO: This will take blkg->stats_lock. Figure out a way
- * to avoid this cost.
- */
blkiocg_update_dispatch_stats(&tg->blkg, bio->bi_size, rw, sync);
}
@@ -989,15 +1129,51 @@ int blk_throtl_bio(struct request_queue *q, struct bio **biop)
struct throtl_grp *tg;
struct bio *bio = *biop;
bool rw = bio_data_dir(bio), update_disptime = true;
+ struct blkio_cgroup *blkcg;
if (bio->bi_rw & REQ_THROTTLED) {
bio->bi_rw &= ~REQ_THROTTLED;
return 0;
}
+ /*
+ * A throtl_grp pointer retrieved under rcu can be used to access
+ * basic fields like stats and io rates. If a group has no rules,
+ * just update the dispatch stats in lockless manner and return.
+ */
+
+ rcu_read_lock();
+ blkcg = task_blkio_cgroup(current);
+ tg = throtl_find_tg(td, blkcg);
+ if (tg) {
+ throtl_tg_fill_dev_details(td, tg);
+
+ if (tg_no_rule_group(tg, rw)) {
+ blkiocg_update_dispatch_stats(&tg->blkg, bio->bi_size,
+ rw, bio->bi_rw & REQ_SYNC);
+ rcu_read_unlock();
+ return 0;
+ }
+ }
+ rcu_read_unlock();
+
+ /*
+ * Either group has not been allocated yet or it is not an unlimited
+ * IO group
+ */
+
spin_lock_irq(q->queue_lock);
tg = throtl_get_tg(td);
+ if (IS_ERR(tg)) {
+ if (PTR_ERR(tg) == -ENODEV) {
+ /*
+ * Queue is gone. No queue lock held here.
+ */
+ return -ENODEV;
+ }
+ }
+
if (tg->nr_queued[rw]) {
/*
* There is already another bio queued in same dir. No
@@ -1060,39 +1236,24 @@ int blk_throtl_init(struct request_queue *q)
INIT_HLIST_HEAD(&td->tg_list);
td->tg_service_tree = THROTL_RB_ROOT;
td->limits_changed = false;
+ INIT_DELAYED_WORK(&td->throtl_work, blk_throtl_work);
- /* Init root group */
- tg = &td->root_tg;
- INIT_HLIST_NODE(&tg->tg_node);
- RB_CLEAR_NODE(&tg->rb_node);
- bio_list_init(&tg->bio_lists[0]);
- bio_list_init(&tg->bio_lists[1]);
-
- /* Practically unlimited BW */
- tg->bps[0] = tg->bps[1] = -1;
- tg->iops[0] = tg->iops[1] = -1;
- td->limits_changed = false;
+ /* alloc and Init root group. */
+ td->queue = q;
+ tg = throtl_alloc_tg(td);
- /*
- * Set root group reference to 2. One reference will be dropped when
- * all groups on tg_list are being deleted during queue exit. Other
- * reference will remain there as we don't want to delete this group
- * as it is statically allocated and gets destroyed when throtl_data
- * goes away.
- */
- atomic_set(&tg->ref, 2);
- hlist_add_head(&tg->tg_node, &td->tg_list);
- td->nr_undestroyed_grps++;
+ if (!tg) {
+ kfree(td);
+ return -ENOMEM;
+ }
- INIT_DELAYED_WORK(&td->throtl_work, blk_throtl_work);
+ td->root_tg = tg;
rcu_read_lock();
- blkiocg_add_blkio_group(&blkio_root_cgroup, &tg->blkg, (void *)td,
- 0, BLKIO_POLICY_THROTL);
+ throtl_init_add_tg_lists(td, tg, &blkio_root_cgroup);
rcu_read_unlock();
/* Attach throtl data to request queue */
- td->queue = q;
q->td = td;
return 0;
}
diff --git a/block/blk.h b/block/blk.h
index 61263463e38e..d6586287adc9 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -62,7 +62,28 @@ static inline struct request *__elv_next_request(struct request_queue *q)
return rq;
}
- if (!q->elevator->ops->elevator_dispatch_fn(q, 0))
+ /*
+ * Flush request is running and flush request isn't queueable
+ * in the drive, we can hold the queue till flush request is
+ * finished. Even we don't do this, driver can't dispatch next
+ * requests and will requeue them. And this can improve
+ * throughput too. For example, we have request flush1, write1,
+ * flush 2. flush1 is dispatched, then queue is hold, write1
+ * isn't inserted to queue. After flush1 is finished, flush2
+ * will be dispatched. Since disk cache is already clean,
+ * flush2 will be finished very soon, so looks like flush2 is
+ * folded to flush1.
+ * Since the queue is hold, a flag is set to indicate the queue
+ * should be restarted later. Please see flush_end_io() for
+ * details.
+ */
+ if (q->flush_pending_idx != q->flush_running_idx &&
+ !queue_flush_queueable(q)) {
+ q->flush_queue_delayed = 1;
+ return NULL;
+ }
+ if (test_bit(QUEUE_FLAG_DEAD, &q->queue_flags) ||
+ !q->elevator->ops->elevator_dispatch_fn(q, 0))
return NULL;
}
}
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index ab7a9e6a9b1c..7c52d6888924 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -300,7 +300,9 @@ struct cfq_data {
/* List of cfq groups being managed on this device*/
struct hlist_head cfqg_list;
- struct rcu_head rcu;
+
+ /* Number of groups which are on blkcg->blkg_list */
+ unsigned int nr_blkcg_linked_grps;
};
static struct cfq_group *cfq_get_next_cfqg(struct cfq_data *cfqd);
@@ -665,15 +667,11 @@ cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2,
if (rq2 == NULL)
return rq1;
- if (rq_is_sync(rq1) && !rq_is_sync(rq2))
- return rq1;
- else if (rq_is_sync(rq2) && !rq_is_sync(rq1))
- return rq2;
- if ((rq1->cmd_flags & REQ_META) && !(rq2->cmd_flags & REQ_META))
- return rq1;
- else if ((rq2->cmd_flags & REQ_META) &&
- !(rq1->cmd_flags & REQ_META))
- return rq2;
+ if (rq_is_sync(rq1) != rq_is_sync(rq2))
+ return rq_is_sync(rq1) ? rq1 : rq2;
+
+ if ((rq1->cmd_flags ^ rq2->cmd_flags) & REQ_META)
+ return rq1->cmd_flags & REQ_META ? rq1 : rq2;
s1 = blk_rq_pos(rq1);
s2 = blk_rq_pos(rq2);
@@ -1014,28 +1012,47 @@ void cfq_update_blkio_group_weight(void *key, struct blkio_group *blkg,
cfqg->needs_update = true;
}
-static struct cfq_group * cfq_find_alloc_cfqg(struct cfq_data *cfqd,
- struct blkio_cgroup *blkcg, int create)
+static void cfq_init_add_cfqg_lists(struct cfq_data *cfqd,
+ struct cfq_group *cfqg, struct blkio_cgroup *blkcg)
{
- struct cfq_group *cfqg = NULL;
- void *key = cfqd;
- int i, j;
- struct cfq_rb_root *st;
struct backing_dev_info *bdi = &cfqd->queue->backing_dev_info;
unsigned int major, minor;
- cfqg = cfqg_of_blkg(blkiocg_lookup_group(blkcg, key));
- if (cfqg && !cfqg->blkg.dev && bdi->dev && dev_name(bdi->dev)) {
+ /*
+ * Add group onto cgroup list. It might happen that bdi->dev is
+ * not initialized yet. Initialize this new group without major
+ * and minor info and this info will be filled in once a new thread
+ * comes for IO.
+ */
+ if (bdi->dev) {
sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
- cfqg->blkg.dev = MKDEV(major, minor);
- goto done;
- }
- if (cfqg || !create)
- goto done;
+ cfq_blkiocg_add_blkio_group(blkcg, &cfqg->blkg,
+ (void *)cfqd, MKDEV(major, minor));
+ } else
+ cfq_blkiocg_add_blkio_group(blkcg, &cfqg->blkg,
+ (void *)cfqd, 0);
+
+ cfqd->nr_blkcg_linked_grps++;
+ cfqg->weight = blkcg_get_weight(blkcg, cfqg->blkg.dev);
+
+ /* Add group on cfqd list */
+ hlist_add_head(&cfqg->cfqd_node, &cfqd->cfqg_list);
+}
+
+/*
+ * Should be called from sleepable context. No request queue lock as per
+ * cpu stats are allocated dynamically and alloc_percpu needs to be called
+ * from sleepable context.
+ */
+static struct cfq_group * cfq_alloc_cfqg(struct cfq_data *cfqd)
+{
+ struct cfq_group *cfqg = NULL;
+ int i, j, ret;
+ struct cfq_rb_root *st;
cfqg = kzalloc_node(sizeof(*cfqg), GFP_ATOMIC, cfqd->queue->node);
if (!cfqg)
- goto done;
+ return NULL;
for_each_cfqg_st(cfqg, i, j, st)
*st = CFQ_RB_ROOT;
@@ -1049,43 +1066,94 @@ static struct cfq_group * cfq_find_alloc_cfqg(struct cfq_data *cfqd,
*/
cfqg->ref = 1;
+ ret = blkio_alloc_blkg_stats(&cfqg->blkg);
+ if (ret) {
+ kfree(cfqg);
+ return NULL;
+ }
+
+ return cfqg;
+}
+
+static struct cfq_group *
+cfq_find_cfqg(struct cfq_data *cfqd, struct blkio_cgroup *blkcg)
+{
+ struct cfq_group *cfqg = NULL;
+ void *key = cfqd;
+ struct backing_dev_info *bdi = &cfqd->queue->backing_dev_info;
+ unsigned int major, minor;
+
/*
- * Add group onto cgroup list. It might happen that bdi->dev is
- * not initialized yet. Initialize this new group without major
- * and minor info and this info will be filled in once a new thread
- * comes for IO. See code above.
+ * This is the common case when there are no blkio cgroups.
+ * Avoid lookup in this case
*/
- if (bdi->dev) {
- sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
- cfq_blkiocg_add_blkio_group(blkcg, &cfqg->blkg, (void *)cfqd,
- MKDEV(major, minor));
- } else
- cfq_blkiocg_add_blkio_group(blkcg, &cfqg->blkg, (void *)cfqd,
- 0);
-
- cfqg->weight = blkcg_get_weight(blkcg, cfqg->blkg.dev);
+ if (blkcg == &blkio_root_cgroup)
+ cfqg = &cfqd->root_group;
+ else
+ cfqg = cfqg_of_blkg(blkiocg_lookup_group(blkcg, key));
- /* Add group on cfqd list */
- hlist_add_head(&cfqg->cfqd_node, &cfqd->cfqg_list);
+ if (cfqg && !cfqg->blkg.dev && bdi->dev && dev_name(bdi->dev)) {
+ sscanf(dev_name(bdi->dev), "%u:%u", &major, &minor);
+ cfqg->blkg.dev = MKDEV(major, minor);
+ }
-done:
return cfqg;
}
/*
- * Search for the cfq group current task belongs to. If create = 1, then also
- * create the cfq group if it does not exist. request_queue lock must be held.
+ * Search for the cfq group current task belongs to. request_queue lock must
+ * be held.
*/
-static struct cfq_group *cfq_get_cfqg(struct cfq_data *cfqd, int create)
+static struct cfq_group *cfq_get_cfqg(struct cfq_data *cfqd)
{
struct blkio_cgroup *blkcg;
- struct cfq_group *cfqg = NULL;
+ struct cfq_group *cfqg = NULL, *__cfqg = NULL;
+ struct request_queue *q = cfqd->queue;
rcu_read_lock();
blkcg = task_blkio_cgroup(current);
- cfqg = cfq_find_alloc_cfqg(cfqd, blkcg, create);
- if (!cfqg && create)
+ cfqg = cfq_find_cfqg(cfqd, blkcg);
+ if (cfqg) {
+ rcu_read_unlock();
+ return cfqg;
+ }
+
+ /*
+ * Need to allocate a group. Allocation of group also needs allocation
+ * of per cpu stats which in-turn takes a mutex() and can block. Hence
+ * we need to drop rcu lock and queue_lock before we call alloc.
+ *
+ * Not taking any queue reference here and assuming that queue is
+ * around by the time we return. CFQ queue allocation code does
+ * the same. It might be racy though.
+ */
+
+ rcu_read_unlock();
+ spin_unlock_irq(q->queue_lock);
+
+ cfqg = cfq_alloc_cfqg(cfqd);
+
+ spin_lock_irq(q->queue_lock);
+
+ rcu_read_lock();
+ blkcg = task_blkio_cgroup(current);
+
+ /*
+ * If some other thread already allocated the group while we were
+ * not holding queue lock, free up the group
+ */
+ __cfqg = cfq_find_cfqg(cfqd, blkcg);
+
+ if (__cfqg) {
+ kfree(cfqg);
+ rcu_read_unlock();
+ return __cfqg;
+ }
+
+ if (!cfqg)
cfqg = &cfqd->root_group;
+
+ cfq_init_add_cfqg_lists(cfqd, cfqg, blkcg);
rcu_read_unlock();
return cfqg;
}
@@ -1118,6 +1186,7 @@ static void cfq_put_cfqg(struct cfq_group *cfqg)
return;
for_each_cfqg_st(cfqg, i, j, st)
BUG_ON(!RB_EMPTY_ROOT(&st->rb));
+ free_percpu(cfqg->blkg.stats_cpu);
kfree(cfqg);
}
@@ -1176,7 +1245,7 @@ void cfq_unlink_blkio_group(void *key, struct blkio_group *blkg)
}
#else /* GROUP_IOSCHED */
-static struct cfq_group *cfq_get_cfqg(struct cfq_data *cfqd, int create)
+static struct cfq_group *cfq_get_cfqg(struct cfq_data *cfqd)
{
return &cfqd->root_group;
}
@@ -1210,7 +1279,6 @@ static void cfq_service_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq,
struct cfq_rb_root *service_tree;
int left;
int new_cfqq = 1;
- int group_changed = 0;
service_tree = service_tree_for(cfqq->cfqg, cfqq_prio(cfqq),
cfqq_type(cfqq));
@@ -1281,7 +1349,7 @@ static void cfq_service_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq,
rb_link_node(&cfqq->rb_node, parent, p);
rb_insert_color(&cfqq->rb_node, &service_tree->rb);
service_tree->count++;
- if ((add_front || !new_cfqq) && !group_changed)
+ if (add_front || !new_cfqq)
return;
cfq_group_notify_queue_add(cfqd, cfqq->cfqg);
}
@@ -2029,7 +2097,7 @@ cfq_prio_to_maxrq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
WARN_ON(cfqq->ioprio >= IOPRIO_BE_NR);
- return 2 * (base_rq + base_rq * (CFQ_PRIO_LISTS - 1 - cfqq->ioprio));
+ return 2 * base_rq * (IOPRIO_BE_NR - cfqq->ioprio);
}
/*
@@ -2911,7 +2979,7 @@ cfq_find_alloc_queue(struct cfq_data *cfqd, bool is_sync,
struct cfq_group *cfqg;
retry:
- cfqg = cfq_get_cfqg(cfqd, 1);
+ cfqg = cfq_get_cfqg(cfqd);
cic = cfq_cic_lookup(cfqd, ioc);
/* cic always exists here */
cfqq = cic_to_cfqq(cic, is_sync);
@@ -3815,15 +3883,11 @@ static void cfq_put_async_queues(struct cfq_data *cfqd)
cfq_put_queue(cfqd->async_idle_cfqq);
}
-static void cfq_cfqd_free(struct rcu_head *head)
-{
- kfree(container_of(head, struct cfq_data, rcu));
-}
-
static void cfq_exit_queue(struct elevator_queue *e)
{
struct cfq_data *cfqd = e->elevator_data;
struct request_queue *q = cfqd->queue;
+ bool wait = false;
cfq_shutdown_timer_wq(cfqd);
@@ -3842,7 +3906,13 @@ static void cfq_exit_queue(struct elevator_queue *e)
cfq_put_async_queues(cfqd);
cfq_release_cfq_groups(cfqd);
- cfq_blkiocg_del_blkio_group(&cfqd->root_group.blkg);
+
+ /*
+ * If there are groups which we could not unlink from blkcg list,
+ * wait for a rcu period for them to be freed.
+ */
+ if (cfqd->nr_blkcg_linked_grps)
+ wait = true;
spin_unlock_irq(q->queue_lock);
@@ -3852,8 +3922,25 @@ static void cfq_exit_queue(struct elevator_queue *e)
ida_remove(&cic_index_ida, cfqd->cic_index);
spin_unlock(&cic_index_lock);
- /* Wait for cfqg->blkg->key accessors to exit their grace periods. */
- call_rcu(&cfqd->rcu, cfq_cfqd_free);
+ /*
+ * Wait for cfqg->blkg->key accessors to exit their grace periods.
+ * Do this wait only if there are other unlinked groups out
+ * there. This can happen if cgroup deletion path claimed the
+ * responsibility of cleaning up a group before queue cleanup code
+ * get to the group.
+ *
+ * Do not call synchronize_rcu() unconditionally as there are drivers
+ * which create/delete request queue hundreds of times during scan/boot
+ * and synchronize_rcu() can take significant time and slow down boot.
+ */
+ if (wait)
+ synchronize_rcu();
+
+#ifdef CONFIG_CFQ_GROUP_IOSCHED
+ /* Free up per cpu stats for root group */
+ free_percpu(cfqd->root_group.blkg.stats_cpu);
+#endif
+ kfree(cfqd);
}
static int cfq_alloc_cic_index(void)
@@ -3886,8 +3973,12 @@ static void *cfq_init_queue(struct request_queue *q)
return NULL;
cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL | __GFP_ZERO, q->node);
- if (!cfqd)
+ if (!cfqd) {
+ spin_lock(&cic_index_lock);
+ ida_remove(&cic_index_ida, i);
+ spin_unlock(&cic_index_lock);
return NULL;
+ }
/*
* Don't need take queue_lock in the routine, since we are
@@ -3909,14 +4000,29 @@ static void *cfq_init_queue(struct request_queue *q)
#ifdef CONFIG_CFQ_GROUP_IOSCHED
/*
- * Take a reference to root group which we never drop. This is just
- * to make sure that cfq_put_cfqg() does not try to kfree root group
+ * Set root group reference to 2. One reference will be dropped when
+ * all groups on cfqd->cfqg_list are being deleted during queue exit.
+ * Other reference will remain there as we don't want to delete this
+ * group as it is statically allocated and gets destroyed when
+ * throtl_data goes away.
*/
- cfqg->ref = 1;
+ cfqg->ref = 2;
+
+ if (blkio_alloc_blkg_stats(&cfqg->blkg)) {
+ kfree(cfqg);
+ kfree(cfqd);
+ return NULL;
+ }
+
rcu_read_lock();
+
cfq_blkiocg_add_blkio_group(&blkio_root_cgroup, &cfqg->blkg,
(void *)cfqd, 0);
rcu_read_unlock();
+ cfqd->nr_blkcg_linked_grps++;
+
+ /* Add group on cfqd->cfqg_list */
+ hlist_add_head(&cfqg->cfqd_node, &cfqd->cfqg_list);
#endif
/*
* Not strictly needed (since RB_ROOT just clears the node and we
diff --git a/block/elevator.c b/block/elevator.c
index 45ca1e34f582..b0b38ce0dcb6 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -155,13 +155,8 @@ static struct elevator_type *elevator_get(const char *name)
e = elevator_find(name);
if (!e) {
- char elv[ELV_NAME_MAX + strlen("-iosched")];
-
spin_unlock(&elv_list_lock);
-
- snprintf(elv, sizeof(elv), "%s-iosched", name);
-
- request_module("%s", elv);
+ request_module("%s-iosched", name);
spin_lock(&elv_list_lock);
e = elevator_find(name);
}
@@ -421,8 +416,6 @@ void elv_dispatch_sort(struct request_queue *q, struct request *rq)
struct list_head *entry;
int stop_flags;
- BUG_ON(rq->cmd_flags & REQ_ON_PLUG);
-
if (q->last_merge == rq)
q->last_merge = NULL;
@@ -661,8 +654,6 @@ void __elv_add_request(struct request_queue *q, struct request *rq, int where)
rq->q = q;
- BUG_ON(rq->cmd_flags & REQ_ON_PLUG);
-
if (rq->cmd_flags & REQ_SOFTBARRIER) {
/* barriers are scheduling boundary, update end_sector */
if (rq->cmd_type == REQ_TYPE_FS ||
diff --git a/block/genhd.c b/block/genhd.c
index 2dd988723d73..95822ae25cfe 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -1728,7 +1728,7 @@ static void disk_add_events(struct gendisk *disk)
{
struct disk_events *ev;
- if (!disk->fops->check_events || !(disk->events | disk->async_events))
+ if (!disk->fops->check_events)
return;
ev = kzalloc(sizeof(*ev), GFP_KERNEL);
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 4b7cb0e691cd..87b22ca9c223 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -264,11 +264,6 @@ config CRYPTO_XTS
key size 256, 384 or 512 bits. This implementation currently
can't handle a sectorsize which is not a multiple of 16 bytes.
-config CRYPTO_FPU
- tristate
- select CRYPTO_BLKCIPHER
- select CRYPTO_MANAGER
-
comment "Hash modes"
config CRYPTO_HMAC
@@ -543,7 +538,6 @@ config CRYPTO_AES_NI_INTEL
select CRYPTO_AES_586 if !64BIT
select CRYPTO_CRYPTD
select CRYPTO_ALGAPI
- select CRYPTO_FPU
help
Use Intel AES-NI instructions for AES algorithm.
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index e912ea5def3d..2222617b3bed 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -1009,6 +1009,10 @@ static int do_test(int m)
speed_template_32_48_64);
test_cipher_speed("xts(aes)", DECRYPT, sec, NULL, 0,
speed_template_32_48_64);
+ test_cipher_speed("ctr(aes)", ENCRYPT, sec, NULL, 0,
+ speed_template_16_24_32);
+ test_cipher_speed("ctr(aes)", DECRYPT, sec, NULL, 0,
+ speed_template_16_24_32);
break;
case 201:
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 2854865f2434..b6b93d416351 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -2219,6 +2219,22 @@ static const struct alg_test_desc alg_test_descs[] = {
}
}
}, {
+ .alg = "ofb(aes)",
+ .test = alg_test_skcipher,
+ .fips_allowed = 1,
+ .suite = {
+ .cipher = {
+ .enc = {
+ .vecs = aes_ofb_enc_tv_template,
+ .count = AES_OFB_ENC_TEST_VECTORS
+ },
+ .dec = {
+ .vecs = aes_ofb_dec_tv_template,
+ .count = AES_OFB_DEC_TEST_VECTORS
+ }
+ }
+ }
+ }, {
.alg = "pcbc(fcrypt)",
.test = alg_test_skcipher,
.suite = {
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index aa6dac05f843..27e60619538e 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -2980,6 +2980,8 @@ static struct cipher_testvec cast6_dec_tv_template[] = {
#define AES_XTS_DEC_TEST_VECTORS 4
#define AES_CTR_ENC_TEST_VECTORS 3
#define AES_CTR_DEC_TEST_VECTORS 3
+#define AES_OFB_ENC_TEST_VECTORS 1
+#define AES_OFB_DEC_TEST_VECTORS 1
#define AES_CTR_3686_ENC_TEST_VECTORS 7
#define AES_CTR_3686_DEC_TEST_VECTORS 6
#define AES_GCM_ENC_TEST_VECTORS 9
@@ -5506,6 +5508,64 @@ static struct cipher_testvec aes_ctr_rfc3686_dec_tv_template[] = {
},
};
+static struct cipher_testvec aes_ofb_enc_tv_template[] = {
+ /* From NIST Special Publication 800-38A, Appendix F.5 */
+ {
+ .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6"
+ "\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+ .klen = 16,
+ .iv = "\x00\x01\x02\x03\x04\x05\x06\x07\x08"
+ "\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ .input = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+ "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+ "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+ "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+ "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+ "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+ "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+ .ilen = 64,
+ .result = "\x3b\x3f\xd9\x2e\xb7\x2d\xad\x20"
+ "\x33\x34\x49\xf8\xe8\x3c\xfb\x4a"
+ "\x77\x89\x50\x8d\x16\x91\x8f\x03\xf5"
+ "\x3c\x52\xda\xc5\x4e\xd8\x25"
+ "\x97\x40\x05\x1e\x9c\x5f\xec\xf6\x43"
+ "\x44\xf7\xa8\x22\x60\xed\xcc"
+ "\x30\x4c\x65\x28\xf6\x59\xc7\x78"
+ "\x66\xa5\x10\xd9\xc1\xd6\xae\x5e",
+ .rlen = 64,
+ }
+};
+
+static struct cipher_testvec aes_ofb_dec_tv_template[] = {
+ /* From NIST Special Publication 800-38A, Appendix F.5 */
+ {
+ .key = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6"
+ "\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+ .klen = 16,
+ .iv = "\x00\x01\x02\x03\x04\x05\x06\x07\x08"
+ "\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+ .input = "\x3b\x3f\xd9\x2e\xb7\x2d\xad\x20"
+ "\x33\x34\x49\xf8\xe8\x3c\xfb\x4a"
+ "\x77\x89\x50\x8d\x16\x91\x8f\x03\xf5"
+ "\x3c\x52\xda\xc5\x4e\xd8\x25"
+ "\x97\x40\x05\x1e\x9c\x5f\xec\xf6\x43"
+ "\x44\xf7\xa8\x22\x60\xed\xcc"
+ "\x30\x4c\x65\x28\xf6\x59\xc7\x78"
+ "\x66\xa5\x10\xd9\xc1\xd6\xae\x5e",
+ .ilen = 64,
+ .result = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96"
+ "\xe9\x3d\x7e\x11\x73\x93\x17\x2a"
+ "\xae\x2d\x8a\x57\x1e\x03\xac\x9c"
+ "\x9e\xb7\x6f\xac\x45\xaf\x8e\x51"
+ "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11"
+ "\xe5\xfb\xc1\x19\x1a\x0a\x52\xef"
+ "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17"
+ "\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+ .rlen = 64,
+ }
+};
+
static struct aead_testvec aes_gcm_enc_tv_template[] = {
{ /* From McGrew & Viega - http://citeseer.ist.psu.edu/656989.html */
.key = zeroed_string,
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 177c7d156933..3bb154d8c8cc 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -54,6 +54,8 @@ source "drivers/spi/Kconfig"
source "drivers/pps/Kconfig"
+source "drivers/ptp/Kconfig"
+
source "drivers/gpio/Kconfig"
source "drivers/w1/Kconfig"
@@ -68,6 +70,8 @@ source "drivers/watchdog/Kconfig"
source "drivers/ssb/Kconfig"
+source "drivers/bcma/Kconfig"
+
source "drivers/mfd/Kconfig"
source "drivers/regulator/Kconfig"
@@ -119,4 +123,7 @@ source "drivers/platform/Kconfig"
source "drivers/clk/Kconfig"
source "drivers/hwspinlock/Kconfig"
+
+source "drivers/clocksource/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 3f135b6fb014..6b17f5864340 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -64,11 +64,10 @@ obj-$(CONFIG_ATA_OVER_ETH) += block/aoe/
obj-$(CONFIG_PARIDE) += block/paride/
obj-$(CONFIG_TC) += tc/
obj-$(CONFIG_UWB) += uwb/
-obj-$(CONFIG_USB_OTG_UTILS) += usb/otg/
+obj-$(CONFIG_USB_OTG_UTILS) += usb/
obj-$(CONFIG_USB) += usb/
-obj-$(CONFIG_USB_MUSB_HDRC) += usb/musb/
obj-$(CONFIG_PCI) += usb/
-obj-$(CONFIG_USB_GADGET) += usb/gadget/
+obj-$(CONFIG_USB_GADGET) += usb/
obj-$(CONFIG_SERIO) += input/serio/
obj-$(CONFIG_GAMEPORT) += input/gameport/
obj-$(CONFIG_INPUT) += input/
@@ -76,6 +75,7 @@ obj-$(CONFIG_I2O) += message/
obj-$(CONFIG_RTC_LIB) += rtc/
obj-y += i2c/ media/
obj-$(CONFIG_PPS) += pps/
+obj-$(CONFIG_PTP_1588_CLOCK) += ptp/
obj-$(CONFIG_W1) += w1/
obj-$(CONFIG_POWER_SUPPLY) += power/
obj-$(CONFIG_HWMON) += hwmon/
@@ -95,7 +95,7 @@ obj-$(CONFIG_CPU_IDLE) += cpuidle/
obj-$(CONFIG_DMA_ENGINE) += dma/
obj-$(CONFIG_MMC) += mmc/
obj-$(CONFIG_MEMSTICK) += memstick/
-obj-$(CONFIG_NEW_LEDS) += leds/
+obj-y += leds/
obj-$(CONFIG_INFINIBAND) += infiniband/
obj-$(CONFIG_SGI_SN) += sn/
obj-y += firmware/
@@ -110,6 +110,7 @@ obj-$(CONFIG_HID) += hid/
obj-$(CONFIG_PPC_PS3) += ps3/
obj-$(CONFIG_OF) += of/
obj-$(CONFIG_SSB) += ssb/
+obj-$(CONFIG_BCMA) += bcma/
obj-$(CONFIG_VHOST_NET) += vhost/
obj-$(CONFIG_VLYNQ) += vlynq/
obj-$(CONFIG_STAGING) += staging/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 3a17ca5fff6f..bc2218db5ba9 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -73,17 +73,6 @@ config ACPI_PROCFS_POWER
Say N to delete power /proc/acpi/ directories that have moved to /sys/
-config ACPI_POWER_METER
- tristate "ACPI 4.0 power meter"
- depends on HWMON
- help
- This driver exposes ACPI 4.0 power meters as hardware monitoring
- devices. Say Y (or M) if you have a computer with ACPI 4.0 firmware
- and a power meter.
-
- To compile this driver as a module, choose M here:
- the module will be called power-meter.
-
config ACPI_EC_DEBUGFS
tristate "EC read/write access through /sys/kernel/debug/ec"
default n
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index d113fa5100b2..b66fbb2fc85f 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -59,7 +59,6 @@ obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o
obj-$(CONFIG_ACPI_BATTERY) += battery.o
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
diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c
index 84e051844247..6ffd3a8bdaa5 100644
--- a/drivers/acpi/acpica/utresrc.c
+++ b/drivers/acpi/acpica/utresrc.c
@@ -50,7 +50,7 @@ ACPI_MODULE_NAME("utresrc")
#if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER)
/*
* Strings used to decode resource descriptors.
- * Used by both the disasssembler and the debugger resource dump routines
+ * Used by both the disassembler and the debugger resource dump routines
*/
const char *acpi_gbl_bm_decode[] = {
"NotBusMaster",
diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig
index 66a03caa2ad9..f739a70b1c70 100644
--- a/drivers/acpi/apei/Kconfig
+++ b/drivers/acpi/apei/Kconfig
@@ -1,5 +1,6 @@
config ACPI_APEI
bool "ACPI Platform Error Interface (APEI)"
+ select MISC_FILESYSTEMS
select PSTORE
depends on X86
help
diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c
index 096aebfe7f32..f74b2ea11f21 100644
--- a/drivers/acpi/apei/einj.c
+++ b/drivers/acpi/apei/einj.c
@@ -101,6 +101,14 @@ static DEFINE_MUTEX(einj_mutex);
static struct einj_parameter *einj_param;
+#ifndef writeq
+static inline void writeq(__u64 val, volatile void __iomem *addr)
+{
+ writel(val, addr);
+ writel(val >> 32, addr+4);
+}
+#endif
+
static void einj_exec_ctx_init(struct apei_exec_context *ctx)
{
apei_exec_ctx_init(ctx, einj_ins_type, ARRAY_SIZE(einj_ins_type),
diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c
index d6cb0ff6988e..e6cef8e1b534 100644
--- a/drivers/acpi/apei/erst.c
+++ b/drivers/acpi/apei/erst.c
@@ -929,13 +929,17 @@ static int erst_check_table(struct acpi_table_erst *erst_tab)
return 0;
}
-static size_t erst_reader(u64 *id, enum pstore_type_id *type,
+static int erst_open_pstore(struct pstore_info *psi);
+static int erst_close_pstore(struct pstore_info *psi);
+static ssize_t erst_reader(u64 *id, enum pstore_type_id *type,
struct timespec *time);
static u64 erst_writer(enum pstore_type_id type, size_t size);
static struct pstore_info erst_info = {
.owner = THIS_MODULE,
.name = "erst",
+ .open = erst_open_pstore,
+ .close = erst_close_pstore,
.read = erst_reader,
.write = erst_writer,
.erase = erst_clear
@@ -957,12 +961,32 @@ struct cper_pstore_record {
char data[];
} __packed;
-static size_t erst_reader(u64 *id, enum pstore_type_id *type,
+static int reader_pos;
+
+static int erst_open_pstore(struct pstore_info *psi)
+{
+ int rc;
+
+ if (erst_disable)
+ return -ENODEV;
+
+ rc = erst_get_record_id_begin(&reader_pos);
+
+ return rc;
+}
+
+static int erst_close_pstore(struct pstore_info *psi)
+{
+ erst_get_record_id_end();
+
+ return 0;
+}
+
+static ssize_t erst_reader(u64 *id, enum pstore_type_id *type,
struct timespec *time)
{
int rc;
- ssize_t len;
- unsigned long flags;
+ ssize_t len = 0;
u64 record_id;
struct cper_pstore_record *rcd = (struct cper_pstore_record *)
(erst_info.buf - sizeof(*rcd));
@@ -970,24 +994,28 @@ static size_t erst_reader(u64 *id, enum pstore_type_id *type,
if (erst_disable)
return -ENODEV;
- raw_spin_lock_irqsave(&erst_lock, flags);
skip:
- rc = __erst_get_next_record_id(&record_id);
- if (rc) {
- raw_spin_unlock_irqrestore(&erst_lock, flags);
- return rc;
- }
+ rc = erst_get_record_id_next(&reader_pos, &record_id);
+ if (rc)
+ goto out;
+
/* no more record */
if (record_id == APEI_ERST_INVALID_RECORD_ID) {
- raw_spin_unlock_irqrestore(&erst_lock, flags);
- return 0;
+ rc = -1;
+ goto out;
}
- len = __erst_read(record_id, &rcd->hdr, sizeof(*rcd) +
- erst_erange.size);
+ len = erst_read(record_id, &rcd->hdr, sizeof(*rcd) +
+ erst_info.bufsize);
+ /* The record may be cleared by others, try read next record */
+ if (len == -ENOENT)
+ goto skip;
+ else if (len < 0) {
+ rc = -1;
+ goto out;
+ }
if (uuid_le_cmp(rcd->hdr.creator_id, CPER_CREATOR_PSTORE) != 0)
goto skip;
- raw_spin_unlock_irqrestore(&erst_lock, flags);
*id = record_id;
if (uuid_le_cmp(rcd->sec_hdr.section_type,
@@ -1005,7 +1033,8 @@ skip:
time->tv_sec = 0;
time->tv_nsec = 0;
- return len - sizeof(*rcd);
+out:
+ return (rc < 0) ? rc : (len - sizeof(*rcd));
}
static u64 erst_writer(enum pstore_type_id type, size_t size)
diff --git a/drivers/acpi/atomicio.c b/drivers/acpi/atomicio.c
index 542e53903891..7489b89c300f 100644
--- a/drivers/acpi/atomicio.c
+++ b/drivers/acpi/atomicio.c
@@ -280,9 +280,11 @@ static int acpi_atomic_read_mem(u64 paddr, u64 *val, u32 width)
case 32:
*val = readl(addr);
break;
+#ifdef readq
case 64:
*val = readq(addr);
break;
+#endif
default:
return -EINVAL;
}
@@ -307,9 +309,11 @@ static int acpi_atomic_write_mem(u64 paddr, u64 val, u32 width)
case 32:
writel(val, addr);
break;
+#ifdef writeq
case 64:
writeq(val, addr);
break;
+#endif
default:
return -EINVAL;
}
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index f911a2f8cc34..d06078d660ad 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -596,12 +596,18 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
dev_info(root->bus->bridge,
"ACPI _OSC control (0x%02x) granted\n", flags);
} else {
- dev_dbg(root->bus->bridge,
- "ACPI _OSC request failed (code %d)\n", status);
- printk(KERN_INFO "Unable to assume _OSC PCIe control. "
- "Disabling ASPM\n");
+ dev_info(root->bus->bridge,
+ "ACPI _OSC request failed (%s), "
+ "returned control mask: 0x%02x\n",
+ acpi_format_exception(status), flags);
+ pr_info("ACPI _OSC control for PCIe not granted, "
+ "disabling ASPM\n");
pcie_no_aspm();
}
+ } else {
+ dev_info(root->bus->bridge,
+ "Unable to request _OSC control "
+ "(_OSC support mask: 0x%02x)\n", flags);
}
pci_acpi_add_bus_pm_notifier(device, root->bus);
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index 3a73a93596e8..85b32376dad7 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -49,10 +49,6 @@ ACPI_MODULE_NAME("processor_perflib");
static DEFINE_MUTEX(performance_mutex);
-/* Use cpufreq debug layer for _PPC changes. */
-#define cpufreq_printk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, \
- "cpufreq-core", msg)
-
/*
* _PPC support is implemented as a CPUfreq policy notifier:
* This means each time a CPUfreq driver registered also with
@@ -145,7 +141,7 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
return -ENODEV;
}
- cpufreq_printk("CPU %d: _PPC is %d - frequency %s limited\n", pr->id,
+ pr_debug("CPU %d: _PPC is %d - frequency %s limited\n", pr->id,
(int)ppc, ppc ? "" : "not");
pr->performance_platform_limit = (int)ppc;
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index ad3501739563..605a2954ef17 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -710,20 +710,14 @@ static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr)
}
#ifdef CONFIG_X86
-static int acpi_throttling_rdmsr(struct acpi_processor *pr,
- u64 *value)
+static int acpi_throttling_rdmsr(u64 *value)
{
- struct cpuinfo_x86 *c;
u64 msr_high, msr_low;
- unsigned int cpu;
u64 msr = 0;
int ret = -1;
- cpu = pr->id;
- c = &cpu_data(cpu);
-
- if ((c->x86_vendor != X86_VENDOR_INTEL) ||
- !cpu_has(c, X86_FEATURE_ACPI)) {
+ if ((this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_INTEL) ||
+ !this_cpu_has(X86_FEATURE_ACPI)) {
printk(KERN_ERR PREFIX
"HARDWARE addr space,NOT supported yet\n");
} else {
@@ -738,18 +732,13 @@ static int acpi_throttling_rdmsr(struct acpi_processor *pr,
return ret;
}
-static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value)
+static int acpi_throttling_wrmsr(u64 value)
{
- struct cpuinfo_x86 *c;
- unsigned int cpu;
int ret = -1;
u64 msr;
- cpu = pr->id;
- c = &cpu_data(cpu);
-
- if ((c->x86_vendor != X86_VENDOR_INTEL) ||
- !cpu_has(c, X86_FEATURE_ACPI)) {
+ if ((this_cpu_read(cpu_info.x86_vendor) != X86_VENDOR_INTEL) ||
+ !this_cpu_has(X86_FEATURE_ACPI)) {
printk(KERN_ERR PREFIX
"HARDWARE addr space,NOT supported yet\n");
} else {
@@ -761,15 +750,14 @@ static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value)
return ret;
}
#else
-static int acpi_throttling_rdmsr(struct acpi_processor *pr,
- u64 *value)
+static int acpi_throttling_rdmsr(u64 *value)
{
printk(KERN_ERR PREFIX
"HARDWARE addr space,NOT supported yet\n");
return -1;
}
-static int acpi_throttling_wrmsr(struct acpi_processor *pr, u64 value)
+static int acpi_throttling_wrmsr(u64 value)
{
printk(KERN_ERR PREFIX
"HARDWARE addr space,NOT supported yet\n");
@@ -801,7 +789,7 @@ static int acpi_read_throttling_status(struct acpi_processor *pr,
ret = 0;
break;
case ACPI_ADR_SPACE_FIXED_HARDWARE:
- ret = acpi_throttling_rdmsr(pr, value);
+ ret = acpi_throttling_rdmsr(value);
break;
default:
printk(KERN_ERR PREFIX "Unknown addr space %d\n",
@@ -834,7 +822,7 @@ static int acpi_write_throttling_state(struct acpi_processor *pr,
ret = 0;
break;
case ACPI_ADR_SPACE_FIXED_HARDWARE:
- ret = acpi_throttling_wrmsr(pr, value);
+ ret = acpi_throttling_wrmsr(value);
break;
default:
printk(KERN_ERR PREFIX "Unknown addr space %d\n",
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index ec574fc8fbc6..db39e9e607d8 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -1521,7 +1521,7 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
acpi_bus_generate_proc_event(device, event, 0);
keycode = KEY_BRIGHTNESSDOWN;
break;
- case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightnesss */
+ case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightness */
if (brightness_switch_enabled)
acpi_video_switch_brightness(video_device, event);
acpi_bus_generate_proc_event(device, event, 0);
diff --git a/drivers/ata/acard-ahci.c b/drivers/ata/acard-ahci.c
index 339c210f03a6..ae22be4157b5 100644
--- a/drivers/ata/acard-ahci.c
+++ b/drivers/ata/acard-ahci.c
@@ -417,7 +417,7 @@ static int acard_ahci_init_one(struct pci_dev *pdev, const struct pci_device_id
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/libata-core.c b/drivers/ata/libata-core.c
index 76c3c15cb1e6..736bee5dafeb 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -3619,8 +3619,14 @@ int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
scontrol |= (0x2 << 8);
break;
case ATA_LPM_MIN_POWER:
- /* no restrictions on LPM transitions */
- scontrol &= ~(0x3 << 8);
+ if (ata_link_nr_enabled(link) > 0)
+ /* no restrictions on LPM transitions */
+ scontrol &= ~(0x3 << 8);
+ else {
+ /* empty port, power off */
+ scontrol &= ~0xf;
+ scontrol |= (0x1 << 2);
+ }
break;
default:
WARN_ON(1);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index dad9fd660f37..dfb6e9d3d759 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -3423,7 +3423,7 @@ fail:
return rc;
}
-static int ata_link_nr_enabled(struct ata_link *link)
+int ata_link_nr_enabled(struct ata_link *link)
{
struct ata_device *dev;
int cnt = 0;
diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c
index 3120596d4afc..f06b7ea590d3 100644
--- a/drivers/ata/libata-pmp.c
+++ b/drivers/ata/libata-pmp.c
@@ -449,6 +449,16 @@ static void sata_pmp_quirks(struct ata_port *ap)
* otherwise. Don't try hard to recover it.
*/
ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY;
+ } else if (vendor == 0x197b && devid == 0x2352) {
+ /* chip found in Thermaltake BlackX Duet, jmicron JMB350? */
+ ata_for_each_link(link, ap, EDGE) {
+ /* SRST breaks detection and disks get misclassified
+ * LPM disabled to avoid potential problems
+ */
+ link->flags |= ATA_LFLAG_NO_LPM |
+ ATA_LFLAG_NO_SRST |
+ ATA_LFLAG_ASSUME_ATA;
+ }
}
}
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index e2f57e9e12f0..d51f9795c064 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -1089,21 +1089,21 @@ static int atapi_drain_needed(struct request *rq)
static int ata_scsi_dev_config(struct scsi_device *sdev,
struct ata_device *dev)
{
+ struct request_queue *q = sdev->request_queue;
+
if (!ata_id_has_unload(dev->id))
dev->flags |= ATA_DFLAG_NO_UNLOAD;
/* configure max sectors */
- blk_queue_max_hw_sectors(sdev->request_queue, dev->max_sectors);
+ blk_queue_max_hw_sectors(q, dev->max_sectors);
if (dev->class == ATA_DEV_ATAPI) {
- struct request_queue *q = sdev->request_queue;
void *buf;
sdev->sector_size = ATA_SECT_SIZE;
/* set DMA padding */
- blk_queue_update_dma_pad(sdev->request_queue,
- ATA_DMA_PAD_SZ - 1);
+ blk_queue_update_dma_pad(q, ATA_DMA_PAD_SZ - 1);
/* configure draining */
buf = kmalloc(ATAPI_MAX_DRAIN, q->bounce_gfp | GFP_KERNEL);
@@ -1131,8 +1131,7 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
"sector_size=%u > PAGE_SIZE, PIO may malfunction\n",
sdev->sector_size);
- blk_queue_update_dma_alignment(sdev->request_queue,
- sdev->sector_size - 1);
+ blk_queue_update_dma_alignment(q, sdev->sector_size - 1);
if (dev->flags & ATA_DFLAG_AN)
set_bit(SDEV_EVT_MEDIA_CHANGE, sdev->supported_events);
@@ -1145,6 +1144,8 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);
}
+ blk_queue_flush_queueable(q, false);
+
dev->sdev = sdev;
return 0;
}
@@ -2138,7 +2139,7 @@ static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf)
* with the unmap bit set.
*/
if (ata_id_has_trim(args->id)) {
- put_unaligned_be32(65535 * 512 / 8, &rbuf[20]);
+ put_unaligned_be64(65535 * 512 / 8, &rbuf[36]);
put_unaligned_be32(1, &rbuf[28]);
}
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index f8380ce0f4d1..b1b926c55a72 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -2447,13 +2447,18 @@ int ata_pci_sff_activate_host(struct ata_host *host,
return -ENOMEM;
if (!legacy_mode && pdev->irq) {
+ int i;
+
rc = devm_request_irq(dev, pdev->irq, irq_handler,
IRQF_SHARED, drv_name, host);
if (rc)
goto out;
- ata_port_desc(host->ports[0], "irq %d", pdev->irq);
- ata_port_desc(host->ports[1], "irq %d", pdev->irq);
+ for (i = 0; i < 2; i++) {
+ if (ata_port_is_dummy(host->ports[i]))
+ continue;
+ ata_port_desc(host->ports[i], "irq %d", pdev->irq);
+ }
} else if (legacy_mode) {
if (!ata_port_is_dummy(host->ports[0])) {
rc = devm_request_irq(dev, ATA_PRIMARY_IRQ(pdev),
diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c
index a5fdbdcb0faf..960c72571395 100644
--- a/drivers/ata/pata_at91.c
+++ b/drivers/ata/pata_at91.c
@@ -3,6 +3,7 @@
* with CompactFlash interface in True IDE mode
*
* Copyright (C) 2009 Matyukevich Sergey
+ * 2011 Igor Plyatov
*
* Based on:
* * generic platform driver by Paul Mundt: drivers/ata/pata_platform.c
@@ -31,38 +32,150 @@
#include <mach/board.h>
#include <mach/gpio.h>
+#define DRV_NAME "pata_at91"
+#define DRV_VERSION "0.3"
-#define DRV_NAME "pata_at91"
-#define DRV_VERSION "0.2"
-
-#define CF_IDE_OFFSET 0x00c00000
-#define CF_ALT_IDE_OFFSET 0x00e00000
-#define CF_IDE_RES_SIZE 0x08
-#define NCS_RD_PULSE_LIMIT 0x3f /* maximal value for pulse bitfields */
+#define CF_IDE_OFFSET 0x00c00000
+#define CF_ALT_IDE_OFFSET 0x00e00000
+#define CF_IDE_RES_SIZE 0x08
+#define CS_PULSE_MAXIMUM 319
+#define ER_SMC_CALC 1
+#define ER_SMC_RECALC 2
struct at91_ide_info {
unsigned long mode;
unsigned int cs;
-
struct clk *mck;
-
void __iomem *ide_addr;
void __iomem *alt_addr;
};
-static const struct ata_timing initial_timing = {
- .mode = XFER_PIO_0,
- .setup = 70,
- .act8b = 290,
- .rec8b = 240,
- .cyc8b = 600,
- .active = 165,
- .recover = 150,
- .dmack_hold = 0,
- .cycle = 600,
- .udma = 0
+/**
+ * struct smc_range - range of valid values for SMC register.
+ */
+struct smc_range {
+ int min;
+ int max;
};
+/**
+ * adjust_smc_value - adjust value for one of SMC registers.
+ * @value: adjusted value
+ * @range: array of SMC ranges with valid values
+ * @size: SMC ranges array size
+ *
+ * This returns the difference between input and output value or negative
+ * in case of invalid input value.
+ * If negative returned, then output value = maximal possible from ranges.
+ */
+static int adjust_smc_value(int *value, struct smc_range *range, int size)
+{
+ int maximum = (range + size - 1)->max;
+ int remainder;
+
+ do {
+ if (*value < range->min) {
+ remainder = range->min - *value;
+ *value = range->min; /* nearest valid value */
+ return remainder;
+ } else if ((range->min <= *value) && (*value <= range->max))
+ return 0;
+
+ range++;
+ } while (--size);
+ *value = maximum;
+
+ return -1; /* invalid value */
+}
+
+/**
+ * calc_smc_vals - calculate SMC register values
+ * @dev: ATA device
+ * @setup: SMC_SETUP register value
+ * @pulse: SMC_PULSE register value
+ * @cycle: SMC_CYCLE register value
+ *
+ * This returns negative in case of invalid values for SMC registers:
+ * -ER_SMC_RECALC - recalculation required for SMC values,
+ * -ER_SMC_CALC - calculation failed (invalid input values).
+ *
+ * SMC use special coding scheme, see "Coding and Range of Timing
+ * Parameters" table from AT91SAM9 datasheets.
+ *
+ * SMC_SETUP = 128*setup[5] + setup[4:0]
+ * SMC_PULSE = 256*pulse[6] + pulse[5:0]
+ * SMC_CYCLE = 256*cycle[8:7] + cycle[6:0]
+ */
+static int calc_smc_vals(struct device *dev,
+ int *setup, int *pulse, int *cycle, int *cs_pulse)
+{
+ int ret_val;
+ int err = 0;
+ struct smc_range range_setup[] = { /* SMC_SETUP valid values */
+ {.min = 0, .max = 31}, /* first range */
+ {.min = 128, .max = 159} /* second range */
+ };
+ struct smc_range range_pulse[] = { /* SMC_PULSE valid values */
+ {.min = 0, .max = 63}, /* first range */
+ {.min = 256, .max = 319} /* second range */
+ };
+ struct smc_range range_cycle[] = { /* SMC_CYCLE valid values */
+ {.min = 0, .max = 127}, /* first range */
+ {.min = 256, .max = 383}, /* second range */
+ {.min = 512, .max = 639}, /* third range */
+ {.min = 768, .max = 895} /* fourth range */
+ };
+
+ ret_val = adjust_smc_value(setup, range_setup, ARRAY_SIZE(range_setup));
+ if (ret_val < 0)
+ dev_warn(dev, "maximal SMC Setup value\n");
+ else
+ *cycle += ret_val;
+
+ ret_val = adjust_smc_value(pulse, range_pulse, ARRAY_SIZE(range_pulse));
+ if (ret_val < 0)
+ dev_warn(dev, "maximal SMC Pulse value\n");
+ else
+ *cycle += ret_val;
+
+ ret_val = adjust_smc_value(cycle, range_cycle, ARRAY_SIZE(range_cycle));
+ if (ret_val < 0)
+ dev_warn(dev, "maximal SMC Cycle value\n");
+
+ *cs_pulse = *cycle;
+ if (*cs_pulse > CS_PULSE_MAXIMUM) {
+ dev_err(dev, "unable to calculate valid SMC settings\n");
+ return -ER_SMC_CALC;
+ }
+
+ ret_val = adjust_smc_value(cs_pulse, range_pulse,
+ ARRAY_SIZE(range_pulse));
+ if (ret_val < 0) {
+ dev_warn(dev, "maximal SMC CS Pulse value\n");
+ } else if (ret_val != 0) {
+ *cycle = *cs_pulse;
+ dev_warn(dev, "SMC Cycle extended\n");
+ err = -ER_SMC_RECALC;
+ }
+
+ return err;
+}
+
+/**
+ * to_smc_format - convert values into SMC format
+ * @setup: SETUP value of SMC Setup Register
+ * @pulse: PULSE value of SMC Pulse Register
+ * @cycle: CYCLE value of SMC Cycle Register
+ * @cs_pulse: NCS_PULSE value of SMC Pulse Register
+ */
+static void to_smc_format(int *setup, int *pulse, int *cycle, int *cs_pulse)
+{
+ *setup = (*setup & 0x1f) | ((*setup & 0x80) >> 2);
+ *pulse = (*pulse & 0x3f) | ((*pulse & 0x100) >> 2);
+ *cycle = (*cycle & 0x7f) | ((*cycle & 0x300) >> 1);
+ *cs_pulse = (*cs_pulse & 0x3f) | ((*cs_pulse & 0x100) >> 2);
+}
+
static unsigned long calc_mck_cycles(unsigned long ns, unsigned long mck_hz)
{
unsigned long mul;
@@ -80,85 +193,77 @@ static unsigned long calc_mck_cycles(unsigned long ns, unsigned long mck_hz)
return (ns * mul + 65536) >> 16; /* rounding */
}
-static void set_smc_mode(struct at91_ide_info *info)
-{
- at91_sys_write(AT91_SMC_MODE(info->cs), info->mode);
- return;
-}
-
-static void set_smc_timing(struct device *dev,
+/**
+ * set_smc_timing - SMC timings setup.
+ * @dev: device
+ * @info: AT91 IDE info
+ * @ata: ATA timings
+ *
+ * Its assumed that write timings are same as read timings,
+ * cs_setup = 0 and cs_pulse = cycle.
+ */
+static void set_smc_timing(struct device *dev, struct ata_device *adev,
struct at91_ide_info *info, const struct ata_timing *ata)
{
- unsigned long read_cycle, write_cycle, active, recover;
- unsigned long nrd_setup, nrd_pulse, nrd_recover;
- unsigned long nwe_setup, nwe_pulse;
-
- unsigned long ncs_write_setup, ncs_write_pulse;
- unsigned long ncs_read_setup, ncs_read_pulse;
-
- unsigned long mck_hz;
-
- read_cycle = ata->cyc8b;
- nrd_setup = ata->setup;
- nrd_pulse = ata->act8b;
- nrd_recover = ata->rec8b;
-
+ int ret = 0;
+ int use_iordy;
+ unsigned int t6z; /* data tristate time in ns */
+ unsigned int cycle; /* SMC Cycle width in MCK ticks */
+ unsigned int setup; /* SMC Setup width in MCK ticks */
+ unsigned int pulse; /* CFIOR and CFIOW pulse width in MCK ticks */
+ unsigned int cs_setup = 0;/* CS4 or CS5 setup width in MCK ticks */
+ unsigned int cs_pulse; /* CS4 or CS5 pulse width in MCK ticks*/
+ unsigned int tdf_cycles; /* SMC TDF MCK ticks */
+ unsigned long mck_hz; /* MCK frequency in Hz */
+
+ t6z = (ata->mode < XFER_PIO_5) ? 30 : 20;
mck_hz = clk_get_rate(info->mck);
-
- read_cycle = calc_mck_cycles(read_cycle, mck_hz);
- nrd_setup = calc_mck_cycles(nrd_setup, mck_hz);
- nrd_pulse = calc_mck_cycles(nrd_pulse, mck_hz);
- nrd_recover = calc_mck_cycles(nrd_recover, mck_hz);
-
- active = nrd_setup + nrd_pulse;
- recover = read_cycle - active;
-
- /* Need at least two cycles recovery */
- if (recover < 2)
- read_cycle = active + 2;
-
- /* (CS0, CS1, DIR, OE) <= (CFCE1, CFCE2, CFRNW, NCSX) timings */
- ncs_read_setup = 1;
- ncs_read_pulse = read_cycle - 2;
- if (ncs_read_pulse > NCS_RD_PULSE_LIMIT) {
- ncs_read_pulse = NCS_RD_PULSE_LIMIT;
- dev_warn(dev, "ncs_read_pulse limited to maximal value %lu\n",
- ncs_read_pulse);
+ cycle = calc_mck_cycles(ata->cyc8b, mck_hz);
+ setup = calc_mck_cycles(ata->setup, mck_hz);
+ pulse = calc_mck_cycles(ata->act8b, mck_hz);
+ tdf_cycles = calc_mck_cycles(t6z, mck_hz);
+
+ do {
+ ret = calc_smc_vals(dev, &setup, &pulse, &cycle, &cs_pulse);
+ } while (ret == -ER_SMC_RECALC);
+
+ if (ret == -ER_SMC_CALC)
+ dev_err(dev, "Interface may not operate correctly\n");
+
+ dev_dbg(dev, "SMC Setup=%u, Pulse=%u, Cycle=%u, CS Pulse=%u\n",
+ setup, pulse, cycle, cs_pulse);
+ to_smc_format(&setup, &pulse, &cycle, &cs_pulse);
+ /* disable or enable waiting for IORDY signal */
+ use_iordy = ata_pio_need_iordy(adev);
+ if (use_iordy)
+ info->mode |= AT91_SMC_EXNWMODE_READY;
+
+ if (tdf_cycles > 15) {
+ tdf_cycles = 15;
+ dev_warn(dev, "maximal SMC TDF Cycles value\n");
}
- /* Write timings same as read timings */
- write_cycle = read_cycle;
- nwe_setup = nrd_setup;
- nwe_pulse = nrd_pulse;
- ncs_write_setup = ncs_read_setup;
- ncs_write_pulse = ncs_read_pulse;
-
- dev_dbg(dev, "ATA timings: nrd_setup = %lu nrd_pulse = %lu nrd_cycle = %lu\n",
- nrd_setup, nrd_pulse, read_cycle);
- dev_dbg(dev, "ATA timings: nwe_setup = %lu nwe_pulse = %lu nwe_cycle = %lu\n",
- nwe_setup, nwe_pulse, write_cycle);
- dev_dbg(dev, "ATA timings: ncs_read_setup = %lu ncs_read_pulse = %lu\n",
- ncs_read_setup, ncs_read_pulse);
- dev_dbg(dev, "ATA timings: ncs_write_setup = %lu ncs_write_pulse = %lu\n",
- ncs_write_setup, ncs_write_pulse);
+ dev_dbg(dev, "Use IORDY=%u, TDF Cycles=%u\n", use_iordy, tdf_cycles);
+ info->mode |= AT91_SMC_TDF_(tdf_cycles);
+ /* write SMC Setup Register */
at91_sys_write(AT91_SMC_SETUP(info->cs),
- AT91_SMC_NWESETUP_(nwe_setup) |
- AT91_SMC_NRDSETUP_(nrd_setup) |
- AT91_SMC_NCS_WRSETUP_(ncs_write_setup) |
- AT91_SMC_NCS_RDSETUP_(ncs_read_setup));
-
+ AT91_SMC_NWESETUP_(setup) |
+ AT91_SMC_NRDSETUP_(setup) |
+ AT91_SMC_NCS_WRSETUP_(cs_setup) |
+ AT91_SMC_NCS_RDSETUP_(cs_setup));
+ /* write SMC Pulse Register */
at91_sys_write(AT91_SMC_PULSE(info->cs),
- AT91_SMC_NWEPULSE_(nwe_pulse) |
- AT91_SMC_NRDPULSE_(nrd_pulse) |
- AT91_SMC_NCS_WRPULSE_(ncs_write_pulse) |
- AT91_SMC_NCS_RDPULSE_(ncs_read_pulse));
-
+ AT91_SMC_NWEPULSE_(pulse) |
+ AT91_SMC_NRDPULSE_(pulse) |
+ AT91_SMC_NCS_WRPULSE_(cs_pulse) |
+ AT91_SMC_NCS_RDPULSE_(cs_pulse));
+ /* write SMC Cycle Register */
at91_sys_write(AT91_SMC_CYCLE(info->cs),
- AT91_SMC_NWECYCLE_(write_cycle) |
- AT91_SMC_NRDCYCLE_(read_cycle));
-
- return;
+ AT91_SMC_NWECYCLE_(cycle) |
+ AT91_SMC_NRDCYCLE_(cycle));
+ /* write SMC Mode Register*/
+ at91_sys_write(AT91_SMC_MODE(info->cs), info->mode);
}
static void pata_at91_set_piomode(struct ata_port *ap, struct ata_device *adev)
@@ -172,15 +277,9 @@ static void pata_at91_set_piomode(struct ata_port *ap, struct ata_device *adev)
if (ret) {
dev_warn(ap->dev, "Failed to compute ATA timing %d, "
"set PIO_0 timing\n", ret);
- set_smc_timing(ap->dev, info, &initial_timing);
- } else {
- set_smc_timing(ap->dev, info, &timing);
+ timing = *ata_timing_find_mode(XFER_PIO_0);
}
-
- /* Setup SMC mode */
- set_smc_mode(info);
-
- return;
+ set_smc_timing(ap->dev, adev, info, &timing);
}
static unsigned int pata_at91_data_xfer_noirq(struct ata_device *dev,
@@ -346,7 +445,7 @@ static int __devexit pata_at91_remove(struct platform_device *pdev)
static struct platform_driver pata_at91_driver = {
.probe = pata_at91_probe,
.remove = __devexit_p(pata_at91_remove),
- .driver = {
+ .driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
index 905ff76d3cbb..7bafc16cf5e0 100644
--- a/drivers/ata/pata_cmd64x.c
+++ b/drivers/ata/pata_cmd64x.c
@@ -41,6 +41,9 @@
enum {
CFR = 0x50,
CFR_INTR_CH0 = 0x04,
+ CNTRL = 0x51,
+ CNTRL_CH0 = 0x04,
+ CNTRL_CH1 = 0x08,
CMDTIM = 0x52,
ARTTIM0 = 0x53,
DRWTIM0 = 0x54,
@@ -328,9 +331,19 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
.port_ops = &cmd648_port_ops
}
};
- const struct ata_port_info *ppi[] = { &cmd_info[id->driver_data], NULL };
- u8 mrdmode;
+ const struct ata_port_info *ppi[] = {
+ &cmd_info[id->driver_data],
+ &cmd_info[id->driver_data],
+ NULL
+ };
+ u8 mrdmode, reg;
int rc;
+ struct pci_dev *bridge = pdev->bus->self;
+ /* mobility split bridges don't report enabled ports correctly */
+ int port_ok = !(bridge && bridge->vendor ==
+ PCI_VENDOR_ID_MOBILITY_ELECTRONICS);
+ /* all (with exceptions below) apart from 643 have CNTRL_CH0 bit */
+ int cntrl_ch0_ok = (id->driver_data != 0);
rc = pcim_enable_device(pdev);
if (rc)
@@ -341,11 +354,18 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (pdev->device == PCI_DEVICE_ID_CMD_646) {
/* Does UDMA work ? */
- if (pdev->revision > 4)
+ if (pdev->revision > 4) {
ppi[0] = &cmd_info[2];
+ ppi[1] = &cmd_info[2];
+ }
/* Early rev with other problems ? */
- else if (pdev->revision == 1)
+ else if (pdev->revision == 1) {
ppi[0] = &cmd_info[3];
+ ppi[1] = &cmd_info[3];
+ }
+ /* revs 1,2 have no CNTRL_CH0 */
+ if (pdev->revision < 3)
+ cntrl_ch0_ok = 0;
}
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
@@ -354,6 +374,20 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
mrdmode |= 0x02; /* Memory read line enable */
pci_write_config_byte(pdev, MRDMODE, mrdmode);
+ /* check for enabled ports */
+ pci_read_config_byte(pdev, CNTRL, &reg);
+ if (!port_ok)
+ dev_printk(KERN_NOTICE, &pdev->dev, "Mobility Bridge detected, ignoring CNTRL port enable/disable\n");
+ if (port_ok && cntrl_ch0_ok && !(reg & CNTRL_CH0)) {
+ dev_printk(KERN_NOTICE, &pdev->dev, "Primary port is disabled\n");
+ ppi[0] = &ata_dummy_port_info;
+
+ }
+ if (port_ok && !(reg & CNTRL_CH1)) {
+ dev_printk(KERN_NOTICE, &pdev->dev, "Secondary port is disabled\n");
+ ppi[1] = &ata_dummy_port_info;
+ }
+
/* Force PIO 0 here.. */
/* PPC specific fixup copied from old driver */
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 29af660d968b..021abe6d8527 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -309,7 +309,7 @@ static void pcmcia_remove_one(struct pcmcia_device *pdev)
pcmcia_disable_device(pdev);
}
-static struct pcmcia_device_id pcmcia_devices[] = {
+static const struct pcmcia_device_id pcmcia_devices[] = {
PCMCIA_DEVICE_FUNC_ID(4),
PCMCIA_DEVICE_MANF_CARD(0x0000, 0x0000), /* Corsair */
PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000), /* Hitachi */
diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c
index 03b6d69d6197..b3e0c9432283 100644
--- a/drivers/ata/pata_triflex.c
+++ b/drivers/ata/pata_triflex.c
@@ -210,13 +210,34 @@ static const struct pci_device_id triflex[] = {
{ },
};
+#ifdef CONFIG_PM
+static int triflex_ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ int rc = 0;
+
+ rc = ata_host_suspend(host, mesg);
+ if (rc)
+ return rc;
+
+ /*
+ * We must not disable or powerdown the device.
+ * APM bios refuses to suspend if IDE is not accessible.
+ */
+ pci_save_state(pdev);
+
+ return 0;
+}
+
+#endif
+
static struct pci_driver triflex_pci_driver = {
.name = DRV_NAME,
.id_table = triflex,
.probe = triflex_init_one,
.remove = ata_pci_remove_one,
#ifdef CONFIG_PM
- .suspend = ata_pci_device_suspend,
+ .suspend = triflex_ata_pci_device_suspend,
.resume = ata_pci_device_resume,
#endif
};
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index c495fae74200..3230ea0df83c 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -1469,10 +1469,7 @@ if (eni_boards) printk(KERN_INFO "loss: %ld\n",ENI_DEV(eni_boards)->lost);
static void bug_int(struct atm_dev *dev,unsigned long reason)
{
- struct eni_dev *eni_dev;
-
DPRINTK(">bug_int\n");
- eni_dev = ENI_DEV(dev);
if (reason & MID_DMA_ERR_ACK)
printk(KERN_CRIT DEV_LABEL "(itf %d): driver error - DMA "
"error\n",dev->number);
@@ -1900,7 +1897,6 @@ static void eni_close(struct atm_vcc *vcc)
static int eni_open(struct atm_vcc *vcc)
{
- struct eni_dev *eni_dev;
struct eni_vcc *eni_vcc;
int error;
short vpi = vcc->vpi;
@@ -1910,7 +1906,6 @@ static int eni_open(struct atm_vcc *vcc)
EVENT("eni_open\n",0,0);
if (!test_bit(ATM_VF_PARTIAL,&vcc->flags))
vcc->dev_data = NULL;
- eni_dev = ENI_DEV(vcc->dev);
if (vci != ATM_VPI_UNSPEC && vpi != ATM_VCI_UNSPEC)
set_bit(ATM_VF_ADDR,&vcc->flags);
if (vcc->qos.aal != ATM_AAL0 && vcc->qos.aal != ATM_AAL5)
diff --git a/drivers/atm/he.c b/drivers/atm/he.c
index 6cf59bf281dc..9a51df4f5b74 100644
--- a/drivers/atm/he.c
+++ b/drivers/atm/he.c
@@ -1801,7 +1801,7 @@ return_host_buffers:
next_rbrq_entry:
he_dev->rbrq_head = (struct he_rbrq *)
((unsigned long) he_dev->rbrq_base |
- RBRQ_MASK(++he_dev->rbrq_head));
+ RBRQ_MASK(he_dev->rbrq_head + 1));
}
read_unlock(&vcc_sklist_lock);
@@ -1884,7 +1884,7 @@ next_tbrq_entry:
pci_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status));
he_dev->tbrq_head = (struct he_tbrq *)
((unsigned long) he_dev->tbrq_base |
- TBRQ_MASK(++he_dev->tbrq_head));
+ TBRQ_MASK(he_dev->tbrq_head + 1));
}
if (updated) {
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
index 048f99fe6f83..1f8d724a18bf 100644
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -1261,14 +1261,13 @@ idt77252_rx_raw(struct idt77252_dev *card)
PCI_DMA_FROMDEVICE);
while (head != tail) {
- unsigned int vpi, vci, pti;
+ unsigned int vpi, vci;
u32 header;
header = le32_to_cpu(*(u32 *) &queue->data[0]);
vpi = (header & ATM_HDR_VPI_MASK) >> ATM_HDR_VPI_SHIFT;
vci = (header & ATM_HDR_VCI_MASK) >> ATM_HDR_VCI_SHIFT;
- pti = (header & ATM_HDR_PTI_MASK) >> ATM_HDR_PTI_SHIFT;
#ifdef CONFIG_ATM_IDT77252_DEBUG
if (debug & DBG_RAW_CELL) {
@@ -2709,53 +2708,10 @@ idt77252_proc_read(struct atm_dev *dev, loff_t * pos, char *page)
static void
idt77252_collect_stat(struct idt77252_dev *card)
{
- u32 cdc, vpec, icc;
+ (void) readl(SAR_REG_CDC);
+ (void) readl(SAR_REG_VPEC);
+ (void) readl(SAR_REG_ICC);
- cdc = readl(SAR_REG_CDC);
- vpec = readl(SAR_REG_VPEC);
- icc = readl(SAR_REG_ICC);
-
-#ifdef NOTDEF
- printk("%s:", card->name);
-
- if (cdc & 0x7f0000) {
- char *s = "";
-
- printk(" [");
- if (cdc & (1 << 22)) {
- printk("%sRM ID", s);
- s = " | ";
- }
- if (cdc & (1 << 21)) {
- printk("%sCON TAB", s);
- s = " | ";
- }
- if (cdc & (1 << 20)) {
- printk("%sNO FB", s);
- s = " | ";
- }
- if (cdc & (1 << 19)) {
- printk("%sOAM CRC", s);
- s = " | ";
- }
- if (cdc & (1 << 18)) {
- printk("%sRM CRC", s);
- s = " | ";
- }
- if (cdc & (1 << 17)) {
- printk("%sRM FIFO", s);
- s = " | ";
- }
- if (cdc & (1 << 16)) {
- printk("%sRX FIFO", s);
- s = " | ";
- }
- printk("]");
- }
-
- printk(" CDC %04x, VPEC %04x, ICC: %04x\n",
- cdc & 0xffff, vpec & 0xffff, icc & 0xffff);
-#endif
}
static irqreturn_t
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index 1c674a91f146..dee4f01a64d8 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -613,7 +613,6 @@ static int ia_que_tx (IADEV *iadev) {
struct sk_buff *skb;
int num_desc;
struct atm_vcc *vcc;
- struct ia_vcc *iavcc;
num_desc = ia_avail_descs(iadev);
while (num_desc && (skb = skb_dequeue(&iadev->tx_backlog))) {
@@ -627,7 +626,6 @@ static int ia_que_tx (IADEV *iadev) {
printk("Free the SKB on closed vci %d \n", vcc->vci);
break;
}
- iavcc = INPH_IA_VCC(vcc);
if (ia_pkt_tx (vcc, skb)) {
skb_queue_head(&iadev->tx_backlog, skb);
}
@@ -823,8 +821,6 @@ static void IaFrontEndIntr(IADEV *iadev) {
volatile IA_SUNI *suni;
volatile ia_mb25_t *mb25;
volatile suni_pm7345_t *suni_pm7345;
- u32 intr_status;
- u_int frmr_intr;
if(iadev->phy_type & FE_25MBIT_PHY) {
mb25 = (ia_mb25_t*)iadev->phy;
@@ -832,18 +828,18 @@ static void IaFrontEndIntr(IADEV *iadev) {
} else if (iadev->phy_type & FE_DS3_PHY) {
suni_pm7345 = (suni_pm7345_t *)iadev->phy;
/* clear FRMR interrupts */
- frmr_intr = suni_pm7345->suni_ds3_frm_intr_stat;
+ (void) suni_pm7345->suni_ds3_frm_intr_stat;
iadev->carrier_detect =
Boolean(!(suni_pm7345->suni_ds3_frm_stat & SUNI_DS3_LOSV));
} else if (iadev->phy_type & FE_E3_PHY ) {
suni_pm7345 = (suni_pm7345_t *)iadev->phy;
- frmr_intr = suni_pm7345->suni_e3_frm_maint_intr_ind;
+ (void) suni_pm7345->suni_e3_frm_maint_intr_ind;
iadev->carrier_detect =
Boolean(!(suni_pm7345->suni_e3_frm_fram_intr_ind_stat&SUNI_E3_LOS));
}
else {
suni = (IA_SUNI *)iadev->phy;
- intr_status = suni->suni_rsop_status & 0xff;
+ (void) suni->suni_rsop_status;
iadev->carrier_detect = Boolean(!(suni->suni_rsop_status & SUNI_LOSV));
}
if (iadev->carrier_detect)
@@ -2660,7 +2656,6 @@ static void ia_close(struct atm_vcc *vcc)
static int ia_open(struct atm_vcc *vcc)
{
- IADEV *iadev;
struct ia_vcc *ia_vcc;
int error;
if (!test_bit(ATM_VF_PARTIAL,&vcc->flags))
@@ -2668,7 +2663,6 @@ static int ia_open(struct atm_vcc *vcc)
IF_EVENT(printk("ia: not partially allocated resources\n");)
vcc->dev_data = NULL;
}
- iadev = INPH_IA_DEV(vcc->dev);
if (vcc->vci != ATM_VPI_UNSPEC && vcc->vpi != ATM_VCI_UNSPEC)
{
IF_EVENT(printk("iphase open: unspec part\n");)
@@ -3052,11 +3046,9 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) {
static int ia_send(struct atm_vcc *vcc, struct sk_buff *skb)
{
IADEV *iadev;
- struct ia_vcc *iavcc;
unsigned long flags;
iadev = INPH_IA_DEV(vcc->dev);
- iavcc = INPH_IA_VCC(vcc);
if ((!skb)||(skb->len>(iadev->tx_buf_sz-sizeof(struct cpcs_trailer))))
{
if (!skb)
diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index cd0ff66469b2..5d1d07645132 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -527,7 +527,6 @@ static int flash_upgrade(struct solos_card *card, int chip)
{
const struct firmware *fw;
const char *fw_name;
- uint32_t data32 = 0;
int blocksize = 0;
int numblocks = 0;
int offset;
@@ -576,7 +575,7 @@ static int flash_upgrade(struct solos_card *card, int chip)
dev_info(&card->dev->dev, "Changing FPGA to Update mode\n");
iowrite32(1, card->config_regs + FPGA_MODE);
- data32 = ioread32(card->config_regs + FPGA_MODE);
+ (void) ioread32(card->config_regs + FPGA_MODE);
/* Set mode to Chip Erase */
if(chip == 0 || chip == 2)
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index e9e5238f3106..d57e8d0fb823 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -168,11 +168,4 @@ config SYS_HYPERVISOR
bool
default n
-config ARCH_NO_SYSDEV_OPS
- bool
- ---help---
- To be selected by architectures that don't use sysdev class or
- sysdev driver power management (suspend/resume) and shutdown
- operations.
-
endmenu
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 19f49e41ce5d..a34dca0ad041 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -111,8 +111,6 @@ static inline int driver_match_device(struct device_driver *drv,
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}
-extern void sysdev_shutdown(void);
-
extern char *make_class_name(const char *name, struct kobject *kobj);
extern int devres_release_all(struct device *dev);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 81b78ede37c4..bc8729d603a7 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -400,7 +400,7 @@ static void device_remove_groups(struct device *dev,
static int device_add_attrs(struct device *dev)
{
struct class *class = dev->class;
- struct device_type *type = dev->type;
+ const struct device_type *type = dev->type;
int error;
if (class) {
@@ -440,7 +440,7 @@ static int device_add_attrs(struct device *dev)
static void device_remove_attrs(struct device *dev)
{
struct class *class = dev->class;
- struct device_type *type = dev->type;
+ const struct device_type *type = dev->type;
device_remove_groups(dev, dev->groups);
@@ -1314,8 +1314,7 @@ EXPORT_SYMBOL_GPL(put_device);
EXPORT_SYMBOL_GPL(device_create_file);
EXPORT_SYMBOL_GPL(device_remove_file);
-struct root_device
-{
+struct root_device {
struct device dev;
struct module *owner;
};
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index da57ee9d63fe..6658da743c3a 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -245,6 +245,10 @@ int device_attach(struct device *dev)
device_lock(dev);
if (dev->driver) {
+ if (klist_node_attached(&dev->p->knode_driver)) {
+ ret = 1;
+ goto out_unlock;
+ }
ret = device_bind_driver(dev);
if (ret == 0)
ret = 1;
@@ -257,6 +261,7 @@ int device_attach(struct device *dev)
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
pm_runtime_put_sync(dev);
}
+out_unlock:
device_unlock(dev);
return ret;
}
@@ -316,8 +321,7 @@ static void __device_release_driver(struct device *dev)
drv = dev->driver;
if (drv) {
- pm_runtime_get_noresume(dev);
- pm_runtime_barrier(dev);
+ pm_runtime_get_sync(dev);
driver_sysfs_remove(dev);
@@ -326,6 +330,8 @@ static void __device_release_driver(struct device *dev)
BUS_NOTIFY_UNBIND_DRIVER,
dev);
+ pm_runtime_put_sync(dev);
+
if (dev->bus && dev->bus->remove)
dev->bus->remove(dev);
else if (drv->remove)
@@ -338,7 +344,6 @@ static void __device_release_driver(struct device *dev)
BUS_NOTIFY_UNBOUND_DRIVER,
dev);
- pm_runtime_put_sync(dev);
}
}
@@ -408,17 +413,16 @@ void *dev_get_drvdata(const struct device *dev)
}
EXPORT_SYMBOL(dev_get_drvdata);
-void dev_set_drvdata(struct device *dev, void *data)
+int dev_set_drvdata(struct device *dev, void *data)
{
int error;
- if (!dev)
- return;
if (!dev->p) {
error = device_private_init(dev);
if (error)
- return;
+ return error;
}
dev->p->driver_data = data;
+ return 0;
}
EXPORT_SYMBOL(dev_set_drvdata);
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 8c798ef7f13f..bbb03e6f7255 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -521,6 +521,11 @@ static int _request_firmware(const struct firmware **firmware_p,
if (!firmware_p)
return -EINVAL;
+ if (WARN_ON(usermodehelper_is_disabled())) {
+ dev_err(device, "firmware: %s will not be loaded\n", name);
+ return -EBUSY;
+ }
+
*firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
if (!firmware) {
dev_err(device, "%s: kmalloc(struct firmware) failed\n",
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 3da6a43b7756..9f9b2359f718 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -48,7 +48,8 @@ static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj)
return MEMORY_CLASS_NAME;
}
-static int memory_uevent(struct kset *kset, struct kobject *obj, struct kobj_uevent_env *env)
+static int memory_uevent(struct kset *kset, struct kobject *obj,
+ struct kobj_uevent_env *env)
{
int retval = 0;
@@ -228,10 +229,11 @@ int memory_isolate_notify(unsigned long val, void *v)
* OK to have direct references to sparsemem variables in here.
*/
static int
-memory_section_action(unsigned long phys_index, unsigned long action)
+memory_block_action(unsigned long phys_index, unsigned long action)
{
int i;
unsigned long start_pfn, start_paddr;
+ unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block;
struct page *first_page;
int ret;
@@ -243,7 +245,7 @@ memory_section_action(unsigned long phys_index, unsigned long action)
* that way.
*/
if (action == MEM_ONLINE) {
- for (i = 0; i < PAGES_PER_SECTION; i++) {
+ for (i = 0; i < nr_pages; i++) {
if (PageReserved(first_page+i))
continue;
@@ -257,12 +259,12 @@ memory_section_action(unsigned long phys_index, unsigned long action)
switch (action) {
case MEM_ONLINE:
start_pfn = page_to_pfn(first_page);
- ret = online_pages(start_pfn, PAGES_PER_SECTION);
+ ret = online_pages(start_pfn, nr_pages);
break;
case MEM_OFFLINE:
start_paddr = page_to_pfn(first_page) << PAGE_SHIFT;
ret = remove_memory(start_paddr,
- PAGES_PER_SECTION << PAGE_SHIFT);
+ nr_pages << PAGE_SHIFT);
break;
default:
WARN(1, KERN_WARNING "%s(%ld, %ld) unknown action: "
@@ -276,7 +278,7 @@ memory_section_action(unsigned long phys_index, unsigned long action)
static int memory_block_change_state(struct memory_block *mem,
unsigned long to_state, unsigned long from_state_req)
{
- int i, ret = 0;
+ int ret = 0;
mutex_lock(&mem->state_mutex);
@@ -288,20 +290,11 @@ static int memory_block_change_state(struct memory_block *mem,
if (to_state == MEM_OFFLINE)
mem->state = MEM_GOING_OFFLINE;
- for (i = 0; i < sections_per_block; i++) {
- ret = memory_section_action(mem->start_section_nr + i,
- to_state);
- if (ret)
- break;
- }
-
- if (ret) {
- for (i = 0; i < sections_per_block; i++)
- memory_section_action(mem->start_section_nr + i,
- from_state_req);
+ ret = memory_block_action(mem->start_section_nr, to_state);
+ if (ret)
mem->state = from_state_req;
- } else
+ else
mem->state = to_state;
out:
@@ -396,15 +389,14 @@ memory_probe_store(struct class *class, struct class_attribute *attr,
ret = add_memory(nid, phys_addr,
PAGES_PER_SECTION << PAGE_SHIFT);
if (ret)
- break;
+ goto out;
phys_addr += MIN_MEMORY_BLOCK_SIZE;
}
- if (ret)
- count = ret;
-
- return count;
+ ret = count;
+out:
+ return ret;
}
static CLASS_ATTR(probe, S_IWUSR, NULL, memory_probe_store);
diff --git a/drivers/base/node.c b/drivers/base/node.c
index b3b72d64e805..793f796c4da3 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -7,6 +7,7 @@
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/memory.h>
+#include <linux/vmstat.h>
#include <linux/node.h>
#include <linux/hugetlb.h>
#include <linux/compaction.h>
@@ -179,11 +180,14 @@ static ssize_t node_read_vmstat(struct sys_device *dev,
struct sysdev_attribute *attr, char *buf)
{
int nid = dev->id;
- return sprintf(buf,
- "nr_written %lu\n"
- "nr_dirtied %lu\n",
- node_page_state(nid, NR_WRITTEN),
- node_page_state(nid, NR_DIRTIED));
+ int i;
+ int n = 0;
+
+ for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
+ n += sprintf(buf+n, "%s %lu\n", vmstat_text[i],
+ node_page_state(nid, i));
+
+ return n;
}
static SYSDEV_ATTR(vmstat, S_IRUGO, node_read_vmstat, NULL);
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 9e0e4fc24c46..1c291af637b3 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -192,18 +192,18 @@ EXPORT_SYMBOL_GPL(platform_device_alloc);
int platform_device_add_resources(struct platform_device *pdev,
const struct resource *res, unsigned int num)
{
- struct resource *r;
+ struct resource *r = NULL;
- if (!res)
- return 0;
-
- r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL);
- if (r) {
- pdev->resource = r;
- pdev->num_resources = num;
- return 0;
+ if (res) {
+ r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL);
+ if (!r)
+ return -ENOMEM;
}
- return -ENOMEM;
+
+ kfree(pdev->resource);
+ pdev->resource = r;
+ pdev->num_resources = num;
+ return 0;
}
EXPORT_SYMBOL_GPL(platform_device_add_resources);
@@ -220,17 +220,17 @@ EXPORT_SYMBOL_GPL(platform_device_add_resources);
int platform_device_add_data(struct platform_device *pdev, const void *data,
size_t size)
{
- void *d;
+ void *d = NULL;
- if (!data)
- return 0;
-
- d = kmemdup(data, size, GFP_KERNEL);
- if (d) {
- pdev->dev.platform_data = d;
- return 0;
+ if (data) {
+ d = kmemdup(data, size, GFP_KERNEL);
+ if (!d)
+ return -ENOMEM;
}
- return -ENOMEM;
+
+ kfree(pdev->dev.platform_data);
+ pdev->dev.platform_data = d;
+ return 0;
}
EXPORT_SYMBOL_GPL(platform_device_add_data);
@@ -667,7 +667,7 @@ static int platform_legacy_resume(struct device *dev)
return ret;
}
-static int platform_pm_prepare(struct device *dev)
+int platform_pm_prepare(struct device *dev)
{
struct device_driver *drv = dev->driver;
int ret = 0;
@@ -678,7 +678,7 @@ static int platform_pm_prepare(struct device *dev)
return ret;
}
-static void platform_pm_complete(struct device *dev)
+void platform_pm_complete(struct device *dev)
{
struct device_driver *drv = dev->driver;
@@ -686,16 +686,11 @@ static void platform_pm_complete(struct device *dev)
drv->pm->complete(dev);
}
-#else /* !CONFIG_PM_SLEEP */
-
-#define platform_pm_prepare NULL
-#define platform_pm_complete NULL
-
-#endif /* !CONFIG_PM_SLEEP */
+#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_SUSPEND
-int __weak platform_pm_suspend(struct device *dev)
+int platform_pm_suspend(struct device *dev)
{
struct device_driver *drv = dev->driver;
int ret = 0;
@@ -713,7 +708,7 @@ int __weak platform_pm_suspend(struct device *dev)
return ret;
}
-int __weak platform_pm_suspend_noirq(struct device *dev)
+int platform_pm_suspend_noirq(struct device *dev)
{
struct device_driver *drv = dev->driver;
int ret = 0;
@@ -729,7 +724,7 @@ int __weak platform_pm_suspend_noirq(struct device *dev)
return ret;
}
-int __weak platform_pm_resume(struct device *dev)
+int platform_pm_resume(struct device *dev)
{
struct device_driver *drv = dev->driver;
int ret = 0;
@@ -747,7 +742,7 @@ int __weak platform_pm_resume(struct device *dev)
return ret;
}
-int __weak platform_pm_resume_noirq(struct device *dev)
+int platform_pm_resume_noirq(struct device *dev)
{
struct device_driver *drv = dev->driver;
int ret = 0;
@@ -763,18 +758,11 @@ int __weak platform_pm_resume_noirq(struct device *dev)
return ret;
}
-#else /* !CONFIG_SUSPEND */
-
-#define platform_pm_suspend NULL
-#define platform_pm_resume NULL
-#define platform_pm_suspend_noirq NULL
-#define platform_pm_resume_noirq NULL
-
-#endif /* !CONFIG_SUSPEND */
+#endif /* CONFIG_SUSPEND */
#ifdef CONFIG_HIBERNATE_CALLBACKS
-static int platform_pm_freeze(struct device *dev)
+int platform_pm_freeze(struct device *dev)
{
struct device_driver *drv = dev->driver;
int ret = 0;
@@ -792,7 +780,7 @@ static int platform_pm_freeze(struct device *dev)
return ret;
}
-static int platform_pm_freeze_noirq(struct device *dev)
+int platform_pm_freeze_noirq(struct device *dev)
{
struct device_driver *drv = dev->driver;
int ret = 0;
@@ -808,7 +796,7 @@ static int platform_pm_freeze_noirq(struct device *dev)
return ret;
}
-static int platform_pm_thaw(struct device *dev)
+int platform_pm_thaw(struct device *dev)
{
struct device_driver *drv = dev->driver;
int ret = 0;
@@ -826,7 +814,7 @@ static int platform_pm_thaw(struct device *dev)
return ret;
}
-static int platform_pm_thaw_noirq(struct device *dev)
+int platform_pm_thaw_noirq(struct device *dev)
{
struct device_driver *drv = dev->driver;
int ret = 0;
@@ -842,7 +830,7 @@ static int platform_pm_thaw_noirq(struct device *dev)
return ret;
}
-static int platform_pm_poweroff(struct device *dev)
+int platform_pm_poweroff(struct device *dev)
{
struct device_driver *drv = dev->driver;
int ret = 0;
@@ -860,7 +848,7 @@ static int platform_pm_poweroff(struct device *dev)
return ret;
}
-static int platform_pm_poweroff_noirq(struct device *dev)
+int platform_pm_poweroff_noirq(struct device *dev)
{
struct device_driver *drv = dev->driver;
int ret = 0;
@@ -876,7 +864,7 @@ static int platform_pm_poweroff_noirq(struct device *dev)
return ret;
}
-static int platform_pm_restore(struct device *dev)
+int platform_pm_restore(struct device *dev)
{
struct device_driver *drv = dev->driver;
int ret = 0;
@@ -894,7 +882,7 @@ static int platform_pm_restore(struct device *dev)
return ret;
}
-static int platform_pm_restore_noirq(struct device *dev)
+int platform_pm_restore_noirq(struct device *dev)
{
struct device_driver *drv = dev->driver;
int ret = 0;
@@ -910,62 +898,13 @@ static int platform_pm_restore_noirq(struct device *dev)
return ret;
}
-#else /* !CONFIG_HIBERNATE_CALLBACKS */
-
-#define platform_pm_freeze NULL
-#define platform_pm_thaw NULL
-#define platform_pm_poweroff NULL
-#define platform_pm_restore NULL
-#define platform_pm_freeze_noirq NULL
-#define platform_pm_thaw_noirq NULL
-#define platform_pm_poweroff_noirq NULL
-#define platform_pm_restore_noirq NULL
-
-#endif /* !CONFIG_HIBERNATE_CALLBACKS */
-
-#ifdef CONFIG_PM_RUNTIME
-
-int __weak platform_pm_runtime_suspend(struct device *dev)
-{
- return pm_generic_runtime_suspend(dev);
-};
-
-int __weak platform_pm_runtime_resume(struct device *dev)
-{
- return pm_generic_runtime_resume(dev);
-};
-
-int __weak platform_pm_runtime_idle(struct device *dev)
-{
- return pm_generic_runtime_idle(dev);
-};
-
-#else /* !CONFIG_PM_RUNTIME */
-
-#define platform_pm_runtime_suspend NULL
-#define platform_pm_runtime_resume NULL
-#define platform_pm_runtime_idle NULL
-
-#endif /* !CONFIG_PM_RUNTIME */
+#endif /* CONFIG_HIBERNATE_CALLBACKS */
static const struct dev_pm_ops platform_dev_pm_ops = {
- .prepare = platform_pm_prepare,
- .complete = platform_pm_complete,
- .suspend = platform_pm_suspend,
- .resume = platform_pm_resume,
- .freeze = platform_pm_freeze,
- .thaw = platform_pm_thaw,
- .poweroff = platform_pm_poweroff,
- .restore = platform_pm_restore,
- .suspend_noirq = platform_pm_suspend_noirq,
- .resume_noirq = platform_pm_resume_noirq,
- .freeze_noirq = platform_pm_freeze_noirq,
- .thaw_noirq = platform_pm_thaw_noirq,
- .poweroff_noirq = platform_pm_poweroff_noirq,
- .restore_noirq = platform_pm_restore_noirq,
- .runtime_suspend = platform_pm_runtime_suspend,
- .runtime_resume = platform_pm_runtime_resume,
- .runtime_idle = platform_pm_runtime_idle,
+ .runtime_suspend = pm_generic_runtime_suspend,
+ .runtime_resume = pm_generic_runtime_resume,
+ .runtime_idle = pm_generic_runtime_idle,
+ USE_PLATFORM_PM_SLEEP_OPS
};
struct bus_type platform_bus_type = {
@@ -977,41 +916,6 @@ struct bus_type platform_bus_type = {
};
EXPORT_SYMBOL_GPL(platform_bus_type);
-/**
- * platform_bus_get_pm_ops() - return pointer to busses dev_pm_ops
- *
- * This function can be used by platform code to get the current
- * set of dev_pm_ops functions used by the platform_bus_type.
- */
-const struct dev_pm_ops * __init platform_bus_get_pm_ops(void)
-{
- return platform_bus_type.pm;
-}
-
-/**
- * platform_bus_set_pm_ops() - update dev_pm_ops for the platform_bus_type
- *
- * @pm: pointer to new dev_pm_ops struct to be used for platform_bus_type
- *
- * Platform code can override the dev_pm_ops methods of
- * platform_bus_type by using this function. It is expected that
- * platform code will first do a platform_bus_get_pm_ops(), then
- * kmemdup it, then customize selected methods and pass a pointer to
- * the new struct dev_pm_ops to this function.
- *
- * Since platform-specific code is customizing methods for *all*
- * devices (not just platform-specific devices) it is expected that
- * any custom overrides of these functions will keep existing behavior
- * and simply extend it. For example, any customization of the
- * runtime PM methods should continue to call the pm_generic_*
- * functions as the default ones do in addition to the
- * platform-specific behavior.
- */
-void __init platform_bus_set_pm_ops(const struct dev_pm_ops *pm)
-{
- platform_bus_type.pm = pm;
-}
-
int __init platform_bus_init(void)
{
int error;
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index 118c1b92a511..3647e114d0e7 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -3,6 +3,6 @@ obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o
obj-$(CONFIG_PM_RUNTIME) += runtime.o
obj-$(CONFIG_PM_TRACE_RTC) += trace.o
obj-$(CONFIG_PM_OPP) += opp.o
+obj-$(CONFIG_HAVE_CLK) += clock_ops.o
-ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG
-ccflags-$(CONFIG_PM_VERBOSE) += -DDEBUG
+ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG \ No newline at end of file
diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c
new file mode 100644
index 000000000000..c0dd09df7be8
--- /dev/null
+++ b/drivers/base/power/clock_ops.c
@@ -0,0 +1,431 @@
+/*
+ * drivers/base/power/clock_ops.c - Generic clock manipulation PM callbacks
+ *
+ * Copyright (c) 2011 Rafael J. Wysocki <rjw@sisk.pl>, Renesas Electronics Corp.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+
+#ifdef CONFIG_PM_RUNTIME
+
+struct pm_runtime_clk_data {
+ struct list_head clock_list;
+ struct mutex lock;
+};
+
+enum pce_status {
+ PCE_STATUS_NONE = 0,
+ PCE_STATUS_ACQUIRED,
+ PCE_STATUS_ENABLED,
+ PCE_STATUS_ERROR,
+};
+
+struct pm_clock_entry {
+ struct list_head node;
+ char *con_id;
+ struct clk *clk;
+ enum pce_status status;
+};
+
+static struct pm_runtime_clk_data *__to_prd(struct device *dev)
+{
+ return dev ? dev->power.subsys_data : NULL;
+}
+
+/**
+ * pm_runtime_clk_add - Start using a device clock for runtime PM.
+ * @dev: Device whose clock is going to be used for runtime PM.
+ * @con_id: Connection ID of the clock.
+ *
+ * Add the clock represented by @con_id to the list of clocks used for
+ * the runtime PM of @dev.
+ */
+int pm_runtime_clk_add(struct device *dev, const char *con_id)
+{
+ struct pm_runtime_clk_data *prd = __to_prd(dev);
+ struct pm_clock_entry *ce;
+
+ if (!prd)
+ return -EINVAL;
+
+ ce = kzalloc(sizeof(*ce), GFP_KERNEL);
+ if (!ce) {
+ dev_err(dev, "Not enough memory for clock entry.\n");
+ return -ENOMEM;
+ }
+
+ if (con_id) {
+ ce->con_id = kstrdup(con_id, GFP_KERNEL);
+ if (!ce->con_id) {
+ dev_err(dev,
+ "Not enough memory for clock connection ID.\n");
+ kfree(ce);
+ return -ENOMEM;
+ }
+ }
+
+ mutex_lock(&prd->lock);
+ list_add_tail(&ce->node, &prd->clock_list);
+ mutex_unlock(&prd->lock);
+ return 0;
+}
+
+/**
+ * __pm_runtime_clk_remove - Destroy runtime PM clock entry.
+ * @ce: Runtime PM clock entry to destroy.
+ *
+ * This routine must be called under the mutex protecting the runtime PM list
+ * of clocks corresponding the the @ce's device.
+ */
+static void __pm_runtime_clk_remove(struct pm_clock_entry *ce)
+{
+ if (!ce)
+ return;
+
+ list_del(&ce->node);
+
+ if (ce->status < PCE_STATUS_ERROR) {
+ if (ce->status == PCE_STATUS_ENABLED)
+ clk_disable(ce->clk);
+
+ if (ce->status >= PCE_STATUS_ACQUIRED)
+ clk_put(ce->clk);
+ }
+
+ if (ce->con_id)
+ kfree(ce->con_id);
+
+ kfree(ce);
+}
+
+/**
+ * pm_runtime_clk_remove - Stop using a device clock for runtime PM.
+ * @dev: Device whose clock should not be used for runtime PM any more.
+ * @con_id: Connection ID of the clock.
+ *
+ * Remove the clock represented by @con_id from the list of clocks used for
+ * the runtime PM of @dev.
+ */
+void pm_runtime_clk_remove(struct device *dev, const char *con_id)
+{
+ struct pm_runtime_clk_data *prd = __to_prd(dev);
+ struct pm_clock_entry *ce;
+
+ if (!prd)
+ return;
+
+ mutex_lock(&prd->lock);
+
+ list_for_each_entry(ce, &prd->clock_list, node) {
+ if (!con_id && !ce->con_id) {
+ __pm_runtime_clk_remove(ce);
+ break;
+ } else if (!con_id || !ce->con_id) {
+ continue;
+ } else if (!strcmp(con_id, ce->con_id)) {
+ __pm_runtime_clk_remove(ce);
+ break;
+ }
+ }
+
+ mutex_unlock(&prd->lock);
+}
+
+/**
+ * pm_runtime_clk_init - Initialize a device's list of runtime PM clocks.
+ * @dev: Device to initialize the list of runtime PM clocks for.
+ *
+ * Allocate a struct pm_runtime_clk_data object, initialize its lock member and
+ * make the @dev's power.subsys_data field point to it.
+ */
+int pm_runtime_clk_init(struct device *dev)
+{
+ struct pm_runtime_clk_data *prd;
+
+ prd = kzalloc(sizeof(*prd), GFP_KERNEL);
+ if (!prd) {
+ dev_err(dev, "Not enough memory fo runtime PM data.\n");
+ return -ENOMEM;
+ }
+
+ INIT_LIST_HEAD(&prd->clock_list);
+ mutex_init(&prd->lock);
+ dev->power.subsys_data = prd;
+ return 0;
+}
+
+/**
+ * pm_runtime_clk_destroy - Destroy a device's list of runtime PM clocks.
+ * @dev: Device to destroy the list of runtime PM clocks for.
+ *
+ * Clear the @dev's power.subsys_data field, remove the list of clock entries
+ * from the struct pm_runtime_clk_data object pointed to by it before and free
+ * that object.
+ */
+void pm_runtime_clk_destroy(struct device *dev)
+{
+ struct pm_runtime_clk_data *prd = __to_prd(dev);
+ struct pm_clock_entry *ce, *c;
+
+ if (!prd)
+ return;
+
+ dev->power.subsys_data = NULL;
+
+ mutex_lock(&prd->lock);
+
+ list_for_each_entry_safe_reverse(ce, c, &prd->clock_list, node)
+ __pm_runtime_clk_remove(ce);
+
+ mutex_unlock(&prd->lock);
+
+ kfree(prd);
+}
+
+/**
+ * pm_runtime_clk_acquire - Acquire a device clock.
+ * @dev: Device whose clock is to be acquired.
+ * @con_id: Connection ID of the clock.
+ */
+static void pm_runtime_clk_acquire(struct device *dev,
+ struct pm_clock_entry *ce)
+{
+ ce->clk = clk_get(dev, ce->con_id);
+ if (IS_ERR(ce->clk)) {
+ ce->status = PCE_STATUS_ERROR;
+ } else {
+ ce->status = PCE_STATUS_ACQUIRED;
+ dev_dbg(dev, "Clock %s managed by runtime PM.\n", ce->con_id);
+ }
+}
+
+/**
+ * pm_runtime_clk_suspend - Disable clocks in a device's runtime PM clock list.
+ * @dev: Device to disable the clocks for.
+ */
+int pm_runtime_clk_suspend(struct device *dev)
+{
+ struct pm_runtime_clk_data *prd = __to_prd(dev);
+ struct pm_clock_entry *ce;
+
+ dev_dbg(dev, "%s()\n", __func__);
+
+ if (!prd)
+ return 0;
+
+ mutex_lock(&prd->lock);
+
+ list_for_each_entry_reverse(ce, &prd->clock_list, node) {
+ if (ce->status == PCE_STATUS_NONE)
+ pm_runtime_clk_acquire(dev, ce);
+
+ if (ce->status < PCE_STATUS_ERROR) {
+ clk_disable(ce->clk);
+ ce->status = PCE_STATUS_ACQUIRED;
+ }
+ }
+
+ mutex_unlock(&prd->lock);
+
+ return 0;
+}
+
+/**
+ * pm_runtime_clk_resume - Enable clocks in a device's runtime PM clock list.
+ * @dev: Device to enable the clocks for.
+ */
+int pm_runtime_clk_resume(struct device *dev)
+{
+ struct pm_runtime_clk_data *prd = __to_prd(dev);
+ struct pm_clock_entry *ce;
+
+ dev_dbg(dev, "%s()\n", __func__);
+
+ if (!prd)
+ return 0;
+
+ mutex_lock(&prd->lock);
+
+ list_for_each_entry(ce, &prd->clock_list, node) {
+ if (ce->status == PCE_STATUS_NONE)
+ pm_runtime_clk_acquire(dev, ce);
+
+ if (ce->status < PCE_STATUS_ERROR) {
+ clk_enable(ce->clk);
+ ce->status = PCE_STATUS_ENABLED;
+ }
+ }
+
+ mutex_unlock(&prd->lock);
+
+ return 0;
+}
+
+/**
+ * pm_runtime_clk_notify - Notify routine for device addition and removal.
+ * @nb: Notifier block object this function is a member of.
+ * @action: Operation being carried out by the caller.
+ * @data: Device the routine is being run for.
+ *
+ * For this function to work, @nb must be a member of an object of type
+ * struct pm_clk_notifier_block containing all of the requisite data.
+ * Specifically, the pwr_domain member of that object is copied to the device's
+ * pwr_domain field and its con_ids member is used to populate the device's list
+ * of runtime PM clocks, depending on @action.
+ *
+ * If the device's pwr_domain field is already populated with a value different
+ * from the one stored in the struct pm_clk_notifier_block object, the function
+ * does nothing.
+ */
+static int pm_runtime_clk_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct pm_clk_notifier_block *clknb;
+ struct device *dev = data;
+ char *con_id;
+ int error;
+
+ dev_dbg(dev, "%s() %ld\n", __func__, action);
+
+ clknb = container_of(nb, struct pm_clk_notifier_block, nb);
+
+ switch (action) {
+ case BUS_NOTIFY_ADD_DEVICE:
+ if (dev->pwr_domain)
+ break;
+
+ error = pm_runtime_clk_init(dev);
+ if (error)
+ break;
+
+ dev->pwr_domain = clknb->pwr_domain;
+ if (clknb->con_ids[0]) {
+ for (con_id = clknb->con_ids[0]; *con_id; con_id++)
+ pm_runtime_clk_add(dev, con_id);
+ } else {
+ pm_runtime_clk_add(dev, NULL);
+ }
+
+ break;
+ case BUS_NOTIFY_DEL_DEVICE:
+ if (dev->pwr_domain != clknb->pwr_domain)
+ break;
+
+ dev->pwr_domain = NULL;
+ pm_runtime_clk_destroy(dev);
+ break;
+ }
+
+ return 0;
+}
+
+#else /* !CONFIG_PM_RUNTIME */
+
+/**
+ * enable_clock - Enable a device clock.
+ * @dev: Device whose clock is to be enabled.
+ * @con_id: Connection ID of the clock.
+ */
+static void enable_clock(struct device *dev, const char *con_id)
+{
+ struct clk *clk;
+
+ clk = clk_get(dev, con_id);
+ if (!IS_ERR(clk)) {
+ clk_enable(clk);
+ clk_put(clk);
+ dev_info(dev, "Runtime PM disabled, clock forced on.\n");
+ }
+}
+
+/**
+ * disable_clock - Disable a device clock.
+ * @dev: Device whose clock is to be disabled.
+ * @con_id: Connection ID of the clock.
+ */
+static void disable_clock(struct device *dev, const char *con_id)
+{
+ struct clk *clk;
+
+ clk = clk_get(dev, con_id);
+ if (!IS_ERR(clk)) {
+ clk_disable(clk);
+ clk_put(clk);
+ dev_info(dev, "Runtime PM disabled, clock forced off.\n");
+ }
+}
+
+/**
+ * pm_runtime_clk_notify - Notify routine for device addition and removal.
+ * @nb: Notifier block object this function is a member of.
+ * @action: Operation being carried out by the caller.
+ * @data: Device the routine is being run for.
+ *
+ * For this function to work, @nb must be a member of an object of type
+ * struct pm_clk_notifier_block containing all of the requisite data.
+ * Specifically, the con_ids member of that object is used to enable or disable
+ * the device's clocks, depending on @action.
+ */
+static int pm_runtime_clk_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct pm_clk_notifier_block *clknb;
+ struct device *dev = data;
+ char *con_id;
+
+ dev_dbg(dev, "%s() %ld\n", __func__, action);
+
+ clknb = container_of(nb, struct pm_clk_notifier_block, nb);
+
+ switch (action) {
+ case BUS_NOTIFY_ADD_DEVICE:
+ if (clknb->con_ids[0]) {
+ for (con_id = clknb->con_ids[0]; *con_id; con_id++)
+ enable_clock(dev, con_id);
+ } else {
+ enable_clock(dev, NULL);
+ }
+ break;
+ case BUS_NOTIFY_DEL_DEVICE:
+ if (clknb->con_ids[0]) {
+ for (con_id = clknb->con_ids[0]; *con_id; con_id++)
+ disable_clock(dev, con_id);
+ } else {
+ disable_clock(dev, NULL);
+ }
+ break;
+ }
+
+ return 0;
+}
+
+#endif /* !CONFIG_PM_RUNTIME */
+
+/**
+ * pm_runtime_clk_add_notifier - Add bus type notifier for runtime PM clocks.
+ * @bus: Bus type to add the notifier to.
+ * @clknb: Notifier to be added to the given bus type.
+ *
+ * The nb member of @clknb is not expected to be initialized and its
+ * notifier_call member will be replaced with pm_runtime_clk_notify(). However,
+ * the remaining members of @clknb should be populated prior to calling this
+ * routine.
+ */
+void pm_runtime_clk_add_notifier(struct bus_type *bus,
+ struct pm_clk_notifier_block *clknb)
+{
+ if (!bus || !clknb)
+ return;
+
+ clknb->nb.notifier_call = pm_runtime_clk_notify;
+ bus_register_notifier(bus, &clknb->nb);
+}
diff --git a/drivers/base/power/generic_ops.c b/drivers/base/power/generic_ops.c
index 42f97f925629..cb3bb368681c 100644
--- a/drivers/base/power/generic_ops.c
+++ b/drivers/base/power/generic_ops.c
@@ -74,6 +74,23 @@ EXPORT_SYMBOL_GPL(pm_generic_runtime_resume);
#ifdef CONFIG_PM_SLEEP
/**
+ * pm_generic_prepare - Generic routine preparing a device for power transition.
+ * @dev: Device to prepare.
+ *
+ * Prepare a device for a system-wide power transition.
+ */
+int pm_generic_prepare(struct device *dev)
+{
+ struct device_driver *drv = dev->driver;
+ int ret = 0;
+
+ if (drv && drv->pm && drv->pm->prepare)
+ ret = drv->pm->prepare(dev);
+
+ return ret;
+}
+
+/**
* __pm_generic_call - Generic suspend/freeze/poweroff/thaw subsystem callback.
* @dev: Device to handle.
* @event: PM transition of the system under way.
@@ -213,16 +230,38 @@ int pm_generic_restore(struct device *dev)
return __pm_generic_resume(dev, PM_EVENT_RESTORE);
}
EXPORT_SYMBOL_GPL(pm_generic_restore);
+
+/**
+ * pm_generic_complete - Generic routine competing a device power transition.
+ * @dev: Device to handle.
+ *
+ * Complete a device power transition during a system-wide power transition.
+ */
+void pm_generic_complete(struct device *dev)
+{
+ struct device_driver *drv = dev->driver;
+
+ if (drv && drv->pm && drv->pm->complete)
+ drv->pm->complete(dev);
+
+ /*
+ * Let runtime PM try to suspend devices that haven't been in use before
+ * going into the system-wide sleep state we're resuming from.
+ */
+ pm_runtime_idle(dev);
+}
#endif /* CONFIG_PM_SLEEP */
struct dev_pm_ops generic_subsys_pm_ops = {
#ifdef CONFIG_PM_SLEEP
+ .prepare = pm_generic_prepare,
.suspend = pm_generic_suspend,
.resume = pm_generic_resume,
.freeze = pm_generic_freeze,
.thaw = pm_generic_thaw,
.poweroff = pm_generic_poweroff,
.restore = pm_generic_restore,
+ .complete = pm_generic_complete,
#endif
#ifdef CONFIG_PM_RUNTIME
.runtime_suspend = pm_generic_runtime_suspend,
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index abe3ab709e87..aa6320207745 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -426,10 +426,8 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
if (dev->pwr_domain) {
pm_dev_dbg(dev, state, "EARLY power domain ");
- pm_noirq_op(dev, &dev->pwr_domain->ops, state);
- }
-
- if (dev->type && dev->type->pm) {
+ error = pm_noirq_op(dev, &dev->pwr_domain->ops, state);
+ } else if (dev->type && dev->type->pm) {
pm_dev_dbg(dev, state, "EARLY type ");
error = pm_noirq_op(dev, dev->type->pm, state);
} else if (dev->class && dev->class->pm) {
@@ -517,7 +515,8 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
if (dev->pwr_domain) {
pm_dev_dbg(dev, state, "power domain ");
- pm_op(dev, &dev->pwr_domain->ops, state);
+ error = pm_op(dev, &dev->pwr_domain->ops, state);
+ goto End;
}
if (dev->type && dev->type->pm) {
@@ -580,11 +579,13 @@ static bool is_async(struct device *dev)
* Execute the appropriate "resume" callback for all devices whose status
* indicates that they are suspended.
*/
-static void dpm_resume(pm_message_t state)
+void dpm_resume(pm_message_t state)
{
struct device *dev;
ktime_t starttime = ktime_get();
+ might_sleep();
+
mutex_lock(&dpm_list_mtx);
pm_transition = state;
async_error = 0;
@@ -629,12 +630,11 @@ static void device_complete(struct device *dev, pm_message_t state)
{
device_lock(dev);
- if (dev->pwr_domain && dev->pwr_domain->ops.complete) {
+ if (dev->pwr_domain) {
pm_dev_dbg(dev, state, "completing power domain ");
- dev->pwr_domain->ops.complete(dev);
- }
-
- if (dev->type && dev->type->pm) {
+ if (dev->pwr_domain->ops.complete)
+ dev->pwr_domain->ops.complete(dev);
+ } else if (dev->type && dev->type->pm) {
pm_dev_dbg(dev, state, "completing type ");
if (dev->type->pm->complete)
dev->type->pm->complete(dev);
@@ -658,10 +658,12 @@ static void device_complete(struct device *dev, pm_message_t state)
* Execute the ->complete() callbacks for all devices whose PM status is not
* DPM_ON (this allows new devices to be registered).
*/
-static void dpm_complete(pm_message_t state)
+void dpm_complete(pm_message_t state)
{
struct list_head list;
+ might_sleep();
+
INIT_LIST_HEAD(&list);
mutex_lock(&dpm_list_mtx);
while (!list_empty(&dpm_prepared_list)) {
@@ -690,7 +692,6 @@ static void dpm_complete(pm_message_t state)
*/
void dpm_resume_end(pm_message_t state)
{
- might_sleep();
dpm_resume(state);
dpm_complete(state);
}
@@ -732,7 +733,12 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state)
{
int error;
- if (dev->type && dev->type->pm) {
+ if (dev->pwr_domain) {
+ pm_dev_dbg(dev, state, "LATE power domain ");
+ error = pm_noirq_op(dev, &dev->pwr_domain->ops, state);
+ if (error)
+ return error;
+ } else if (dev->type && dev->type->pm) {
pm_dev_dbg(dev, state, "LATE type ");
error = pm_noirq_op(dev, dev->type->pm, state);
if (error)
@@ -749,11 +755,6 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state)
return error;
}
- if (dev->pwr_domain) {
- pm_dev_dbg(dev, state, "LATE power domain ");
- pm_noirq_op(dev, &dev->pwr_domain->ops, state);
- }
-
return 0;
}
@@ -841,21 +842,27 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
goto End;
}
+ if (dev->pwr_domain) {
+ pm_dev_dbg(dev, state, "power domain ");
+ error = pm_op(dev, &dev->pwr_domain->ops, state);
+ goto End;
+ }
+
if (dev->type && dev->type->pm) {
pm_dev_dbg(dev, state, "type ");
error = pm_op(dev, dev->type->pm, state);
- goto Domain;
+ goto End;
}
if (dev->class) {
if (dev->class->pm) {
pm_dev_dbg(dev, state, "class ");
error = pm_op(dev, dev->class->pm, state);
- goto Domain;
+ goto End;
} else if (dev->class->suspend) {
pm_dev_dbg(dev, state, "legacy class ");
error = legacy_suspend(dev, state, dev->class->suspend);
- goto Domain;
+ goto End;
}
}
@@ -869,12 +876,6 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
}
}
- Domain:
- if (!error && dev->pwr_domain) {
- pm_dev_dbg(dev, state, "power domain ");
- pm_op(dev, &dev->pwr_domain->ops, state);
- }
-
End:
device_unlock(dev);
complete_all(&dev->power.completion);
@@ -914,11 +915,13 @@ static int device_suspend(struct device *dev)
* dpm_suspend - Execute "suspend" callbacks for all non-sysdev devices.
* @state: PM transition of the system being carried out.
*/
-static int dpm_suspend(pm_message_t state)
+int dpm_suspend(pm_message_t state)
{
ktime_t starttime = ktime_get();
int error = 0;
+ might_sleep();
+
mutex_lock(&dpm_list_mtx);
pm_transition = state;
async_error = 0;
@@ -965,7 +968,14 @@ static int device_prepare(struct device *dev, pm_message_t state)
device_lock(dev);
- if (dev->type && dev->type->pm) {
+ if (dev->pwr_domain) {
+ pm_dev_dbg(dev, state, "preparing power domain ");
+ if (dev->pwr_domain->ops.prepare)
+ error = dev->pwr_domain->ops.prepare(dev);
+ suspend_report_result(dev->pwr_domain->ops.prepare, error);
+ if (error)
+ goto End;
+ } else if (dev->type && dev->type->pm) {
pm_dev_dbg(dev, state, "preparing type ");
if (dev->type->pm->prepare)
error = dev->type->pm->prepare(dev);
@@ -984,13 +994,6 @@ static int device_prepare(struct device *dev, pm_message_t state)
if (dev->bus->pm->prepare)
error = dev->bus->pm->prepare(dev);
suspend_report_result(dev->bus->pm->prepare, error);
- if (error)
- goto End;
- }
-
- if (dev->pwr_domain && dev->pwr_domain->ops.prepare) {
- pm_dev_dbg(dev, state, "preparing power domain ");
- dev->pwr_domain->ops.prepare(dev);
}
End:
@@ -1005,10 +1008,12 @@ static int device_prepare(struct device *dev, pm_message_t state)
*
* Execute the ->prepare() callback(s) for all devices.
*/
-static int dpm_prepare(pm_message_t state)
+int dpm_prepare(pm_message_t state)
{
int error = 0;
+ might_sleep();
+
mutex_lock(&dpm_list_mtx);
while (!list_empty(&dpm_list)) {
struct device *dev = to_device(dpm_list.next);
@@ -1057,7 +1062,6 @@ int dpm_suspend_start(pm_message_t state)
{
int error;
- might_sleep();
error = dpm_prepare(state);
if (!error)
error = dpm_suspend(state);
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 3172c60d23a9..0d4587b15c55 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -168,7 +168,6 @@ static int rpm_check_suspend_allowed(struct device *dev)
static int rpm_idle(struct device *dev, int rpmflags)
{
int (*callback)(struct device *);
- int (*domain_callback)(struct device *);
int retval;
retval = rpm_check_suspend_allowed(dev);
@@ -214,7 +213,9 @@ static int rpm_idle(struct device *dev, int rpmflags)
dev->power.idle_notification = true;
- if (dev->type && dev->type->pm)
+ if (dev->pwr_domain)
+ callback = dev->pwr_domain->ops.runtime_idle;
+ else if (dev->type && dev->type->pm)
callback = dev->type->pm->runtime_idle;
else if (dev->class && dev->class->pm)
callback = dev->class->pm->runtime_idle;
@@ -223,19 +224,10 @@ static int rpm_idle(struct device *dev, int rpmflags)
else
callback = NULL;
- if (dev->pwr_domain)
- domain_callback = dev->pwr_domain->ops.runtime_idle;
- else
- domain_callback = NULL;
-
- if (callback || domain_callback) {
+ if (callback) {
spin_unlock_irq(&dev->power.lock);
- if (domain_callback)
- retval = domain_callback(dev);
-
- if (!retval && callback)
- callback(dev);
+ callback(dev);
spin_lock_irq(&dev->power.lock);
}
@@ -382,7 +374,9 @@ static int rpm_suspend(struct device *dev, int rpmflags)
__update_runtime_status(dev, RPM_SUSPENDING);
- if (dev->type && dev->type->pm)
+ if (dev->pwr_domain)
+ callback = dev->pwr_domain->ops.runtime_suspend;
+ else if (dev->type && dev->type->pm)
callback = dev->type->pm->runtime_suspend;
else if (dev->class && dev->class->pm)
callback = dev->class->pm->runtime_suspend;
@@ -400,8 +394,6 @@ static int rpm_suspend(struct device *dev, int rpmflags)
else
pm_runtime_cancel_pending(dev);
} else {
- if (dev->pwr_domain)
- rpm_callback(dev->pwr_domain->ops.runtime_suspend, dev);
no_callback:
__update_runtime_status(dev, RPM_SUSPENDED);
pm_runtime_deactivate_timer(dev);
@@ -582,9 +574,8 @@ static int rpm_resume(struct device *dev, int rpmflags)
__update_runtime_status(dev, RPM_RESUMING);
if (dev->pwr_domain)
- rpm_callback(dev->pwr_domain->ops.runtime_resume, dev);
-
- if (dev->type && dev->type->pm)
+ callback = dev->pwr_domain->ops.runtime_resume;
+ else if (dev->type && dev->type->pm)
callback = dev->type->pm->runtime_resume;
else if (dev->class && dev->class->pm)
callback = dev->class->pm->runtime_resume;
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index fff49bee781d..a9f5b8979611 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -212,8 +212,9 @@ static ssize_t autosuspend_delay_ms_store(struct device *dev,
static DEVICE_ATTR(autosuspend_delay_ms, 0644, autosuspend_delay_ms_show,
autosuspend_delay_ms_store);
-#endif
+#endif /* CONFIG_PM_RUNTIME */
+#ifdef CONFIG_PM_SLEEP
static ssize_t
wake_show(struct device * dev, struct device_attribute *attr, char * buf)
{
@@ -248,7 +249,6 @@ 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)
{
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index abbbd33e8d8a..84f7c7d5a098 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -110,7 +110,6 @@ void wakeup_source_add(struct wakeup_source *ws)
spin_lock_irq(&events_lock);
list_add_rcu(&ws->entry, &wakeup_sources);
spin_unlock_irq(&events_lock);
- synchronize_rcu();
}
EXPORT_SYMBOL_GPL(wakeup_source_add);
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
index acde9b5ee131..9dff77bfe1e3 100644
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -328,203 +328,8 @@ void sysdev_unregister(struct sys_device *sysdev)
kobject_put(&sysdev->kobj);
}
-
-#ifndef CONFIG_ARCH_NO_SYSDEV_OPS
-/**
- * sysdev_shutdown - Shut down all system devices.
- *
- * Loop over each class of system devices, and the devices in each
- * of those classes. For each device, we call the shutdown method for
- * each driver registered for the device - the auxiliaries,
- * and the class driver.
- *
- * Note: The list is iterated in reverse order, so that we shut down
- * child devices before we shut down their parents. The list ordering
- * is guaranteed by virtue of the fact that child devices are registered
- * after their parents.
- */
-void sysdev_shutdown(void)
-{
- struct sysdev_class *cls;
-
- pr_debug("Shutting Down System Devices\n");
-
- mutex_lock(&sysdev_drivers_lock);
- list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) {
- struct sys_device *sysdev;
-
- pr_debug("Shutting down type '%s':\n",
- kobject_name(&cls->kset.kobj));
-
- list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
- struct sysdev_driver *drv;
- pr_debug(" %s\n", kobject_name(&sysdev->kobj));
-
- /* Call auxiliary drivers first */
- list_for_each_entry(drv, &cls->drivers, entry) {
- if (drv->shutdown)
- drv->shutdown(sysdev);
- }
-
- /* Now call the generic one */
- if (cls->shutdown)
- cls->shutdown(sysdev);
- }
- }
- mutex_unlock(&sysdev_drivers_lock);
-}
-
-static void __sysdev_resume(struct sys_device *dev)
-{
- struct sysdev_class *cls = dev->cls;
- struct sysdev_driver *drv;
-
- /* First, call the class-specific one */
- if (cls->resume)
- cls->resume(dev);
- WARN_ONCE(!irqs_disabled(),
- "Interrupts enabled after %pF\n", cls->resume);
-
- /* Call auxiliary drivers next. */
- list_for_each_entry(drv, &cls->drivers, entry) {
- if (drv->resume)
- drv->resume(dev);
- WARN_ONCE(!irqs_disabled(),
- "Interrupts enabled after %pF\n", drv->resume);
- }
-}
-
-/**
- * sysdev_suspend - Suspend all system devices.
- * @state: Power state to enter.
- *
- * We perform an almost identical operation as sysdev_shutdown()
- * above, though calling ->suspend() instead. Interrupts are disabled
- * when this called. Devices are responsible for both saving state and
- * quiescing or powering down the device.
- *
- * This is only called by the device PM core, so we let them handle
- * all synchronization.
- */
-int sysdev_suspend(pm_message_t state)
-{
- struct sysdev_class *cls;
- struct sys_device *sysdev, *err_dev;
- struct sysdev_driver *drv, *err_drv;
- int ret;
-
- pr_debug("Checking wake-up interrupts\n");
-
- /* Return error code if there are any wake-up interrupts pending */
- ret = check_wakeup_irqs();
- if (ret)
- return ret;
-
- WARN_ONCE(!irqs_disabled(),
- "Interrupts enabled while suspending system devices\n");
-
- pr_debug("Suspending System Devices\n");
-
- list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) {
- pr_debug("Suspending type '%s':\n",
- kobject_name(&cls->kset.kobj));
-
- list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
- pr_debug(" %s\n", kobject_name(&sysdev->kobj));
-
- /* Call auxiliary drivers first */
- list_for_each_entry(drv, &cls->drivers, entry) {
- if (drv->suspend) {
- ret = drv->suspend(sysdev, state);
- if (ret)
- goto aux_driver;
- }
- WARN_ONCE(!irqs_disabled(),
- "Interrupts enabled after %pF\n",
- drv->suspend);
- }
-
- /* Now call the generic one */
- if (cls->suspend) {
- ret = cls->suspend(sysdev, state);
- if (ret)
- goto cls_driver;
- WARN_ONCE(!irqs_disabled(),
- "Interrupts enabled after %pF\n",
- cls->suspend);
- }
- }
- }
- return 0;
- /* resume current sysdev */
-cls_driver:
- drv = NULL;
- printk(KERN_ERR "Class suspend failed for %s: %d\n",
- kobject_name(&sysdev->kobj), ret);
-
-aux_driver:
- if (drv)
- printk(KERN_ERR "Class driver suspend failed for %s: %d\n",
- kobject_name(&sysdev->kobj), ret);
- list_for_each_entry(err_drv, &cls->drivers, entry) {
- if (err_drv == drv)
- break;
- if (err_drv->resume)
- err_drv->resume(sysdev);
- }
-
- /* resume other sysdevs in current class */
- list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {
- if (err_dev == sysdev)
- break;
- pr_debug(" %s\n", kobject_name(&err_dev->kobj));
- __sysdev_resume(err_dev);
- }
-
- /* resume other classes */
- list_for_each_entry_continue(cls, &system_kset->list, kset.kobj.entry) {
- list_for_each_entry(err_dev, &cls->kset.list, kobj.entry) {
- pr_debug(" %s\n", kobject_name(&err_dev->kobj));
- __sysdev_resume(err_dev);
- }
- }
- return ret;
-}
-EXPORT_SYMBOL_GPL(sysdev_suspend);
-
-/**
- * sysdev_resume - Bring system devices back to life.
- *
- * Similar to sysdev_suspend(), but we iterate the list forwards
- * to guarantee that parent devices are resumed before their children.
- *
- * Note: Interrupts are disabled when called.
- */
-int sysdev_resume(void)
-{
- struct sysdev_class *cls;
-
- WARN_ONCE(!irqs_disabled(),
- "Interrupts enabled while resuming system devices\n");
-
- pr_debug("Resuming System Devices\n");
-
- list_for_each_entry(cls, &system_kset->list, kset.kobj.entry) {
- struct sys_device *sysdev;
-
- pr_debug("Resuming type '%s':\n",
- kobject_name(&cls->kset.kobj));
-
- list_for_each_entry(sysdev, &cls->kset.list, kobj.entry) {
- pr_debug(" %s\n", kobject_name(&sysdev->kobj));
-
- __sysdev_resume(sysdev);
- }
- }
- return 0;
-}
-EXPORT_SYMBOL_GPL(sysdev_resume);
-#endif /* CONFIG_ARCH_NO_SYSDEV_OPS */
+EXPORT_SYMBOL_GPL(sysdev_register);
+EXPORT_SYMBOL_GPL(sysdev_unregister);
int __init system_bus_init(void)
{
@@ -534,9 +339,6 @@ int __init system_bus_init(void)
return 0;
}
-EXPORT_SYMBOL_GPL(sysdev_register);
-EXPORT_SYMBOL_GPL(sysdev_unregister);
-
#define to_ext_attr(x) container_of(x, struct sysdev_ext_attribute, attr)
ssize_t sysdev_store_ulong(struct sys_device *sysdev,
diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig
new file mode 100644
index 000000000000..353781b5b78b
--- /dev/null
+++ b/drivers/bcma/Kconfig
@@ -0,0 +1,33 @@
+config BCMA_POSSIBLE
+ bool
+ depends on HAS_IOMEM && HAS_DMA
+ default y
+
+menu "Broadcom specific AMBA"
+ depends on BCMA_POSSIBLE
+
+config BCMA
+ tristate "BCMA support"
+ depends on BCMA_POSSIBLE
+ help
+ Bus driver for Broadcom specific Advanced Microcontroller Bus
+ Architecture.
+
+config BCMA_HOST_PCI_POSSIBLE
+ bool
+ depends on BCMA && PCI = y
+ default y
+
+config BCMA_HOST_PCI
+ bool "Support for BCMA on PCI-host bus"
+ depends on BCMA_HOST_PCI_POSSIBLE
+
+config BCMA_DEBUG
+ bool "BCMA debugging"
+ depends on BCMA
+ help
+ This turns on additional debugging messages.
+
+ If unsure, say N
+
+endmenu
diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile
new file mode 100644
index 000000000000..0d56245bcb79
--- /dev/null
+++ b/drivers/bcma/Makefile
@@ -0,0 +1,7 @@
+bcma-y += main.o scan.o core.o
+bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
+bcma-y += driver_pci.o
+bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o
+obj-$(CONFIG_BCMA) += bcma.o
+
+ccflags-$(CONFIG_BCMA_DEBUG) := -DDEBUG
diff --git a/drivers/bcma/README b/drivers/bcma/README
new file mode 100644
index 000000000000..f7e7ce46c603
--- /dev/null
+++ b/drivers/bcma/README
@@ -0,0 +1,19 @@
+Broadcom introduced new bus as replacement for older SSB. It is based on AMBA,
+however from programming point of view there is nothing AMBA specific we use.
+
+Standard AMBA drivers are platform specific, have hardcoded addresses and use
+AMBA standard fields like CID and PID.
+
+In case of Broadcom's cards every device consists of:
+1) Broadcom specific AMBA device. It is put on AMBA bus, but can not be treated
+ as standard AMBA device. Reading it's CID or PID can cause machine lockup.
+2) AMBA standard devices called ports or wrappers. They have CIDs (AMBA_CID)
+ and PIDs (0x103BB369), but we do not use that info for anything. One of that
+ devices is used for managing Broadcom specific core.
+
+Addresses of AMBA devices are not hardcoded in driver and have to be read from
+EPROM.
+
+In this situation we decided to introduce separated bus. It can contain up to
+16 devices identified by Broadcom specific fields: manufacturer, id, revision
+and class.
diff --git a/drivers/bcma/TODO b/drivers/bcma/TODO
new file mode 100644
index 000000000000..da7aa99fe81c
--- /dev/null
+++ b/drivers/bcma/TODO
@@ -0,0 +1,3 @@
+- Interrupts
+- Defines for PCI core driver
+- Create kernel Documentation (use info from README)
diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
new file mode 100644
index 000000000000..2f72e9c585fd
--- /dev/null
+++ b/drivers/bcma/bcma_private.h
@@ -0,0 +1,28 @@
+#ifndef LINUX_BCMA_PRIVATE_H_
+#define LINUX_BCMA_PRIVATE_H_
+
+#ifndef pr_fmt
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#endif
+
+#include <linux/bcma/bcma.h>
+#include <linux/delay.h>
+
+#define BCMA_CORE_SIZE 0x1000
+
+struct bcma_bus;
+
+/* main.c */
+extern int bcma_bus_register(struct bcma_bus *bus);
+extern void bcma_bus_unregister(struct bcma_bus *bus);
+
+/* scan.c */
+int bcma_bus_scan(struct bcma_bus *bus);
+
+#ifdef CONFIG_BCMA_HOST_PCI
+/* host_pci.c */
+extern int __init bcma_host_pci_init(void);
+extern void __exit bcma_host_pci_exit(void);
+#endif /* CONFIG_BCMA_HOST_PCI */
+
+#endif
diff --git a/drivers/bcma/core.c b/drivers/bcma/core.c
new file mode 100644
index 000000000000..ced379f7b371
--- /dev/null
+++ b/drivers/bcma/core.c
@@ -0,0 +1,51 @@
+/*
+ * Broadcom specific AMBA
+ * Core ops
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+#include <linux/bcma/bcma.h>
+
+bool bcma_core_is_enabled(struct bcma_device *core)
+{
+ if ((bcma_aread32(core, BCMA_IOCTL) & (BCMA_IOCTL_CLK | BCMA_IOCTL_FGC))
+ != BCMA_IOCTL_CLK)
+ return false;
+ if (bcma_aread32(core, BCMA_RESET_CTL) & BCMA_RESET_CTL_RESET)
+ return false;
+ return true;
+}
+EXPORT_SYMBOL_GPL(bcma_core_is_enabled);
+
+static void bcma_core_disable(struct bcma_device *core, u32 flags)
+{
+ if (bcma_aread32(core, BCMA_RESET_CTL) & BCMA_RESET_CTL_RESET)
+ return;
+
+ bcma_awrite32(core, BCMA_IOCTL, flags);
+ bcma_aread32(core, BCMA_IOCTL);
+ udelay(10);
+
+ bcma_awrite32(core, BCMA_RESET_CTL, BCMA_RESET_CTL_RESET);
+ udelay(1);
+}
+
+int bcma_core_enable(struct bcma_device *core, u32 flags)
+{
+ bcma_core_disable(core, flags);
+
+ bcma_awrite32(core, BCMA_IOCTL, (BCMA_IOCTL_CLK | BCMA_IOCTL_FGC | flags));
+ bcma_aread32(core, BCMA_IOCTL);
+
+ bcma_awrite32(core, BCMA_RESET_CTL, 0);
+ udelay(1);
+
+ bcma_awrite32(core, BCMA_IOCTL, (BCMA_IOCTL_CLK | flags));
+ bcma_aread32(core, BCMA_IOCTL);
+ udelay(1);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(bcma_core_enable);
diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c
new file mode 100644
index 000000000000..606102256b44
--- /dev/null
+++ b/drivers/bcma/driver_chipcommon.c
@@ -0,0 +1,89 @@
+/*
+ * Broadcom specific AMBA
+ * ChipCommon core driver
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+#include <linux/bcma/bcma.h>
+
+static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
+ u32 mask, u32 value)
+{
+ value &= mask;
+ value |= bcma_cc_read32(cc, offset) & ~mask;
+ bcma_cc_write32(cc, offset, value);
+
+ return value;
+}
+
+void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
+{
+ if (cc->core->id.rev >= 11)
+ cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
+ cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
+ if (cc->core->id.rev >= 35)
+ cc->capabilities_ext = bcma_cc_read32(cc, BCMA_CC_CAP_EXT);
+
+ if (cc->core->id.rev >= 20) {
+ bcma_cc_write32(cc, BCMA_CC_GPIOPULLUP, 0);
+ bcma_cc_write32(cc, BCMA_CC_GPIOPULLDOWN, 0);
+ }
+
+ if (cc->capabilities & BCMA_CC_CAP_PMU)
+ bcma_pmu_init(cc);
+ if (cc->capabilities & BCMA_CC_CAP_PCTL)
+ pr_err("Power control not implemented!\n");
+}
+
+/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
+void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks)
+{
+ /* instant NMI */
+ bcma_cc_write32(cc, BCMA_CC_WATCHDOG, ticks);
+}
+
+void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value)
+{
+ bcma_cc_write32_masked(cc, BCMA_CC_IRQMASK, mask, value);
+}
+
+u32 bcma_chipco_irq_status(struct bcma_drv_cc *cc, u32 mask)
+{
+ return bcma_cc_read32(cc, BCMA_CC_IRQSTAT) & mask;
+}
+
+u32 bcma_chipco_gpio_in(struct bcma_drv_cc *cc, u32 mask)
+{
+ return bcma_cc_read32(cc, BCMA_CC_GPIOIN) & mask;
+}
+
+u32 bcma_chipco_gpio_out(struct bcma_drv_cc *cc, u32 mask, u32 value)
+{
+ return bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUT, mask, value);
+}
+
+u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value)
+{
+ return bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUTEN, mask, value);
+}
+
+u32 bcma_chipco_gpio_control(struct bcma_drv_cc *cc, u32 mask, u32 value)
+{
+ return bcma_cc_write32_masked(cc, BCMA_CC_GPIOCTL, mask, value);
+}
+EXPORT_SYMBOL_GPL(bcma_chipco_gpio_control);
+
+u32 bcma_chipco_gpio_intmask(struct bcma_drv_cc *cc, u32 mask, u32 value)
+{
+ return bcma_cc_write32_masked(cc, BCMA_CC_GPIOIRQ, mask, value);
+}
+
+u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value)
+{
+ return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
+}
diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c
new file mode 100644
index 000000000000..f44177a644c7
--- /dev/null
+++ b/drivers/bcma/driver_chipcommon_pmu.c
@@ -0,0 +1,134 @@
+/*
+ * Broadcom specific AMBA
+ * ChipCommon Power Management Unit driver
+ *
+ * Copyright 2009, Michael Buesch <mb@bu3sch.de>
+ * Copyright 2007, Broadcom Corporation
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+#include <linux/bcma/bcma.h>
+
+static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
+ u32 offset, u32 mask, u32 set)
+{
+ u32 value;
+
+ bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
+ bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset);
+ bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
+ value = bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
+ value &= mask;
+ value |= set;
+ bcma_cc_write32(cc, BCMA_CC_CHIPCTL_DATA, value);
+ bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
+}
+
+static void bcma_pmu_pll_init(struct bcma_drv_cc *cc)
+{
+ struct bcma_bus *bus = cc->core->bus;
+
+ switch (bus->chipinfo.id) {
+ case 0x4313:
+ case 0x4331:
+ case 43224:
+ case 43225:
+ break;
+ default:
+ pr_err("PLL init unknown for device 0x%04X\n",
+ bus->chipinfo.id);
+ }
+}
+
+static void bcma_pmu_resources_init(struct bcma_drv_cc *cc)
+{
+ struct bcma_bus *bus = cc->core->bus;
+ u32 min_msk = 0, max_msk = 0;
+
+ switch (bus->chipinfo.id) {
+ case 0x4313:
+ min_msk = 0x200D;
+ max_msk = 0xFFFF;
+ break;
+ case 43224:
+ break;
+ default:
+ pr_err("PMU resource config unknown for device 0x%04X\n",
+ bus->chipinfo.id);
+ }
+
+ /* Set the resource masks. */
+ if (min_msk)
+ bcma_cc_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk);
+ if (max_msk)
+ bcma_cc_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
+}
+
+void bcma_pmu_swreg_init(struct bcma_drv_cc *cc)
+{
+ struct bcma_bus *bus = cc->core->bus;
+
+ switch (bus->chipinfo.id) {
+ case 0x4313:
+ case 0x4331:
+ case 43224:
+ break;
+ default:
+ pr_err("PMU switch/regulators init unknown for device "
+ "0x%04X\n", bus->chipinfo.id);
+ }
+}
+
+void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
+{
+ struct bcma_bus *bus = cc->core->bus;
+
+ switch (bus->chipinfo.id) {
+ case 0x4313:
+ bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7);
+ break;
+ case 0x4331:
+ pr_err("Enabling Ext PA lines not implemented\n");
+ break;
+ case 43224:
+ if (bus->chipinfo.rev == 0) {
+ pr_err("Workarounds for 43224 rev 0 not fully "
+ "implemented\n");
+ bcma_chipco_chipctl_maskset(cc, 0, ~0, 0xF0);
+ } else {
+ bcma_chipco_chipctl_maskset(cc, 0, ~0, 0xF0);
+ }
+ break;
+ default:
+ pr_err("Workarounds unknown for device 0x%04X\n",
+ bus->chipinfo.id);
+ }
+}
+
+void bcma_pmu_init(struct bcma_drv_cc *cc)
+{
+ u32 pmucap;
+
+ pmucap = bcma_cc_read32(cc, BCMA_CC_PMU_CAP);
+ cc->pmu.rev = (pmucap & BCMA_CC_PMU_CAP_REVISION);
+
+ pr_debug("Found rev %u PMU (capabilities 0x%08X)\n", cc->pmu.rev,
+ pmucap);
+
+ if (cc->pmu.rev == 1)
+ bcma_cc_mask32(cc, BCMA_CC_PMU_CTL,
+ ~BCMA_CC_PMU_CTL_NOILPONW);
+ else
+ bcma_cc_set32(cc, BCMA_CC_PMU_CTL,
+ BCMA_CC_PMU_CTL_NOILPONW);
+
+ if (cc->core->id.id == 0x4329 && cc->core->id.rev == 2)
+ pr_err("Fix for 4329b0 bad LPOM state not implemented!\n");
+
+ bcma_pmu_pll_init(cc);
+ bcma_pmu_resources_init(cc);
+ bcma_pmu_swreg_init(cc);
+ bcma_pmu_workarounds(cc);
+}
diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c
new file mode 100644
index 000000000000..e757e4e3c7e2
--- /dev/null
+++ b/drivers/bcma/driver_pci.c
@@ -0,0 +1,163 @@
+/*
+ * Broadcom specific AMBA
+ * PCI Core
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+#include <linux/bcma/bcma.h>
+
+/**************************************************
+ * R/W ops.
+ **************************************************/
+
+static u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address)
+{
+ pcicore_write32(pc, 0x130, address);
+ pcicore_read32(pc, 0x130);
+ return pcicore_read32(pc, 0x134);
+}
+
+#if 0
+static void bcma_pcie_write(struct bcma_drv_pci *pc, u32 address, u32 data)
+{
+ pcicore_write32(pc, 0x130, address);
+ pcicore_read32(pc, 0x130);
+ pcicore_write32(pc, 0x134, data);
+}
+#endif
+
+static void bcma_pcie_mdio_set_phy(struct bcma_drv_pci *pc, u8 phy)
+{
+ const u16 mdio_control = 0x128;
+ const u16 mdio_data = 0x12C;
+ u32 v;
+ int i;
+
+ v = (1 << 30); /* Start of Transaction */
+ v |= (1 << 28); /* Write Transaction */
+ v |= (1 << 17); /* Turnaround */
+ v |= (0x1F << 18);
+ v |= (phy << 4);
+ pcicore_write32(pc, mdio_data, v);
+
+ udelay(10);
+ for (i = 0; i < 200; i++) {
+ v = pcicore_read32(pc, mdio_control);
+ if (v & 0x100 /* Trans complete */)
+ break;
+ msleep(1);
+ }
+}
+
+static u16 bcma_pcie_mdio_read(struct bcma_drv_pci *pc, u8 device, u8 address)
+{
+ const u16 mdio_control = 0x128;
+ const u16 mdio_data = 0x12C;
+ int max_retries = 10;
+ u16 ret = 0;
+ u32 v;
+ int i;
+
+ v = 0x80; /* Enable Preamble Sequence */
+ v |= 0x2; /* MDIO Clock Divisor */
+ pcicore_write32(pc, mdio_control, v);
+
+ if (pc->core->id.rev >= 10) {
+ max_retries = 200;
+ bcma_pcie_mdio_set_phy(pc, device);
+ }
+
+ v = (1 << 30); /* Start of Transaction */
+ v |= (1 << 29); /* Read Transaction */
+ v |= (1 << 17); /* Turnaround */
+ if (pc->core->id.rev < 10)
+ v |= (u32)device << 22;
+ v |= (u32)address << 18;
+ pcicore_write32(pc, mdio_data, v);
+ /* Wait for the device to complete the transaction */
+ udelay(10);
+ for (i = 0; i < max_retries; i++) {
+ v = pcicore_read32(pc, mdio_control);
+ if (v & 0x100 /* Trans complete */) {
+ udelay(10);
+ ret = pcicore_read32(pc, mdio_data);
+ break;
+ }
+ msleep(1);
+ }
+ pcicore_write32(pc, mdio_control, 0);
+ return ret;
+}
+
+static void bcma_pcie_mdio_write(struct bcma_drv_pci *pc, u8 device,
+ u8 address, u16 data)
+{
+ const u16 mdio_control = 0x128;
+ const u16 mdio_data = 0x12C;
+ int max_retries = 10;
+ u32 v;
+ int i;
+
+ v = 0x80; /* Enable Preamble Sequence */
+ v |= 0x2; /* MDIO Clock Divisor */
+ pcicore_write32(pc, mdio_control, v);
+
+ if (pc->core->id.rev >= 10) {
+ max_retries = 200;
+ bcma_pcie_mdio_set_phy(pc, device);
+ }
+
+ v = (1 << 30); /* Start of Transaction */
+ v |= (1 << 28); /* Write Transaction */
+ v |= (1 << 17); /* Turnaround */
+ if (pc->core->id.rev < 10)
+ v |= (u32)device << 22;
+ v |= (u32)address << 18;
+ v |= data;
+ pcicore_write32(pc, mdio_data, v);
+ /* Wait for the device to complete the transaction */
+ udelay(10);
+ for (i = 0; i < max_retries; i++) {
+ v = pcicore_read32(pc, mdio_control);
+ if (v & 0x100 /* Trans complete */)
+ break;
+ msleep(1);
+ }
+ pcicore_write32(pc, mdio_control, 0);
+}
+
+/**************************************************
+ * Workarounds.
+ **************************************************/
+
+static u8 bcma_pcicore_polarity_workaround(struct bcma_drv_pci *pc)
+{
+ return (bcma_pcie_read(pc, 0x204) & 0x10) ? 0xC0 : 0x80;
+}
+
+static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc)
+{
+ const u8 serdes_pll_device = 0x1D;
+ const u8 serdes_rx_device = 0x1F;
+ u16 tmp;
+
+ bcma_pcie_mdio_write(pc, serdes_rx_device, 1 /* Control */,
+ bcma_pcicore_polarity_workaround(pc));
+ tmp = bcma_pcie_mdio_read(pc, serdes_pll_device, 1 /* Control */);
+ if (tmp & 0x4000)
+ bcma_pcie_mdio_write(pc, serdes_pll_device, 1, tmp & ~0x4000);
+}
+
+/**************************************************
+ * Init.
+ **************************************************/
+
+void bcma_core_pci_init(struct bcma_drv_pci *pc)
+{
+ bcma_pcicore_serdes_workaround(pc);
+}
diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c
new file mode 100644
index 000000000000..471a04013fe0
--- /dev/null
+++ b/drivers/bcma/host_pci.c
@@ -0,0 +1,198 @@
+/*
+ * Broadcom specific AMBA
+ * PCI Host
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+#include <linux/slab.h>
+#include <linux/bcma/bcma.h>
+#include <linux/pci.h>
+
+static void bcma_host_pci_switch_core(struct bcma_device *core)
+{
+ pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN,
+ core->addr);
+ pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN2,
+ core->wrap);
+ core->bus->mapped_core = core;
+ pr_debug("Switched to core: 0x%X\n", core->id.id);
+}
+
+static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
+{
+ if (core->bus->mapped_core != core)
+ bcma_host_pci_switch_core(core);
+ return ioread8(core->bus->mmio + offset);
+}
+
+static u16 bcma_host_pci_read16(struct bcma_device *core, u16 offset)
+{
+ if (core->bus->mapped_core != core)
+ bcma_host_pci_switch_core(core);
+ return ioread16(core->bus->mmio + offset);
+}
+
+static u32 bcma_host_pci_read32(struct bcma_device *core, u16 offset)
+{
+ if (core->bus->mapped_core != core)
+ bcma_host_pci_switch_core(core);
+ return ioread32(core->bus->mmio + offset);
+}
+
+static void bcma_host_pci_write8(struct bcma_device *core, u16 offset,
+ u8 value)
+{
+ if (core->bus->mapped_core != core)
+ bcma_host_pci_switch_core(core);
+ iowrite8(value, core->bus->mmio + offset);
+}
+
+static void bcma_host_pci_write16(struct bcma_device *core, u16 offset,
+ u16 value)
+{
+ if (core->bus->mapped_core != core)
+ bcma_host_pci_switch_core(core);
+ iowrite16(value, core->bus->mmio + offset);
+}
+
+static void bcma_host_pci_write32(struct bcma_device *core, u16 offset,
+ u32 value)
+{
+ if (core->bus->mapped_core != core)
+ bcma_host_pci_switch_core(core);
+ iowrite32(value, core->bus->mmio + offset);
+}
+
+static u32 bcma_host_pci_aread32(struct bcma_device *core, u16 offset)
+{
+ if (core->bus->mapped_core != core)
+ bcma_host_pci_switch_core(core);
+ return ioread32(core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset);
+}
+
+static void bcma_host_pci_awrite32(struct bcma_device *core, u16 offset,
+ u32 value)
+{
+ if (core->bus->mapped_core != core)
+ bcma_host_pci_switch_core(core);
+ iowrite32(value, core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset);
+}
+
+const struct bcma_host_ops bcma_host_pci_ops = {
+ .read8 = bcma_host_pci_read8,
+ .read16 = bcma_host_pci_read16,
+ .read32 = bcma_host_pci_read32,
+ .write8 = bcma_host_pci_write8,
+ .write16 = bcma_host_pci_write16,
+ .write32 = bcma_host_pci_write32,
+ .aread32 = bcma_host_pci_aread32,
+ .awrite32 = bcma_host_pci_awrite32,
+};
+
+static int bcma_host_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ struct bcma_bus *bus;
+ int err = -ENOMEM;
+ const char *name;
+ u32 val;
+
+ /* Alloc */
+ bus = kzalloc(sizeof(*bus), GFP_KERNEL);
+ if (!bus)
+ goto out;
+
+ /* Basic PCI configuration */
+ err = pci_enable_device(dev);
+ if (err)
+ goto err_kfree_bus;
+
+ name = dev_name(&dev->dev);
+ if (dev->driver && dev->driver->name)
+ name = dev->driver->name;
+ err = pci_request_regions(dev, name);
+ if (err)
+ goto err_pci_disable;
+ pci_set_master(dev);
+
+ /* Disable the RETRY_TIMEOUT register (0x41) to keep
+ * PCI Tx retries from interfering with C3 CPU state */
+ pci_read_config_dword(dev, 0x40, &val);
+ if ((val & 0x0000ff00) != 0)
+ pci_write_config_dword(dev, 0x40, val & 0xffff00ff);
+
+ /* SSB needed additional powering up, do we have any AMBA PCI cards? */
+ if (!pci_is_pcie(dev))
+ pr_err("PCI card detected, report problems.\n");
+
+ /* Map MMIO */
+ err = -ENOMEM;
+ bus->mmio = pci_iomap(dev, 0, ~0UL);
+ if (!bus->mmio)
+ goto err_pci_release_regions;
+
+ /* Host specific */
+ bus->host_pci = dev;
+ bus->hosttype = BCMA_HOSTTYPE_PCI;
+ bus->ops = &bcma_host_pci_ops;
+
+ /* Register */
+ err = bcma_bus_register(bus);
+ if (err)
+ goto err_pci_unmap_mmio;
+
+ pci_set_drvdata(dev, bus);
+
+out:
+ return err;
+
+err_pci_unmap_mmio:
+ pci_iounmap(dev, bus->mmio);
+err_pci_release_regions:
+ pci_release_regions(dev);
+err_pci_disable:
+ pci_disable_device(dev);
+err_kfree_bus:
+ kfree(bus);
+ return err;
+}
+
+static void bcma_host_pci_remove(struct pci_dev *dev)
+{
+ struct bcma_bus *bus = pci_get_drvdata(dev);
+
+ bcma_bus_unregister(bus);
+ pci_iounmap(dev, bus->mmio);
+ pci_release_regions(dev);
+ pci_disable_device(dev);
+ kfree(bus);
+ pci_set_drvdata(dev, NULL);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, bcma_pci_bridge_tbl);
+
+static struct pci_driver bcma_pci_bridge_driver = {
+ .name = "bcma-pci-bridge",
+ .id_table = bcma_pci_bridge_tbl,
+ .probe = bcma_host_pci_probe,
+ .remove = bcma_host_pci_remove,
+};
+
+int __init bcma_host_pci_init(void)
+{
+ return pci_register_driver(&bcma_pci_bridge_driver);
+}
+
+void __exit bcma_host_pci_exit(void)
+{
+ pci_unregister_driver(&bcma_pci_bridge_driver);
+}
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
new file mode 100644
index 000000000000..be52344ed19d
--- /dev/null
+++ b/drivers/bcma/main.c
@@ -0,0 +1,247 @@
+/*
+ * Broadcom specific AMBA
+ * Bus subsystem
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+#include <linux/bcma/bcma.h>
+
+MODULE_DESCRIPTION("Broadcom's specific AMBA driver");
+MODULE_LICENSE("GPL");
+
+static int bcma_bus_match(struct device *dev, struct device_driver *drv);
+static int bcma_device_probe(struct device *dev);
+static int bcma_device_remove(struct device *dev);
+
+static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+ return sprintf(buf, "0x%03X\n", core->id.manuf);
+}
+static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+ return sprintf(buf, "0x%03X\n", core->id.id);
+}
+static ssize_t rev_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+ return sprintf(buf, "0x%02X\n", core->id.rev);
+}
+static ssize_t class_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+ return sprintf(buf, "0x%X\n", core->id.class);
+}
+static struct device_attribute bcma_device_attrs[] = {
+ __ATTR_RO(manuf),
+ __ATTR_RO(id),
+ __ATTR_RO(rev),
+ __ATTR_RO(class),
+ __ATTR_NULL,
+};
+
+static struct bus_type bcma_bus_type = {
+ .name = "bcma",
+ .match = bcma_bus_match,
+ .probe = bcma_device_probe,
+ .remove = bcma_device_remove,
+ .dev_attrs = bcma_device_attrs,
+};
+
+static struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid)
+{
+ struct bcma_device *core;
+
+ list_for_each_entry(core, &bus->cores, list) {
+ if (core->id.id == coreid)
+ return core;
+ }
+ return NULL;
+}
+
+static void bcma_release_core_dev(struct device *dev)
+{
+ struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+ kfree(core);
+}
+
+static int bcma_register_cores(struct bcma_bus *bus)
+{
+ struct bcma_device *core;
+ int err, dev_id = 0;
+
+ list_for_each_entry(core, &bus->cores, list) {
+ /* We support that cores ourself */
+ switch (core->id.id) {
+ case BCMA_CORE_CHIPCOMMON:
+ case BCMA_CORE_PCI:
+ case BCMA_CORE_PCIE:
+ continue;
+ }
+
+ core->dev.release = bcma_release_core_dev;
+ core->dev.bus = &bcma_bus_type;
+ dev_set_name(&core->dev, "bcma%d:%d", 0/*bus->num*/, dev_id);
+
+ switch (bus->hosttype) {
+ case BCMA_HOSTTYPE_PCI:
+ core->dev.parent = &bus->host_pci->dev;
+ break;
+ case BCMA_HOSTTYPE_NONE:
+ case BCMA_HOSTTYPE_SDIO:
+ break;
+ }
+
+ err = device_register(&core->dev);
+ if (err) {
+ pr_err("Could not register dev for core 0x%03X\n",
+ core->id.id);
+ continue;
+ }
+ core->dev_registered = true;
+ dev_id++;
+ }
+
+ return 0;
+}
+
+static void bcma_unregister_cores(struct bcma_bus *bus)
+{
+ struct bcma_device *core;
+
+ list_for_each_entry(core, &bus->cores, list) {
+ if (core->dev_registered)
+ device_unregister(&core->dev);
+ }
+}
+
+int bcma_bus_register(struct bcma_bus *bus)
+{
+ int err;
+ struct bcma_device *core;
+
+ /* Scan for devices (cores) */
+ err = bcma_bus_scan(bus);
+ if (err) {
+ pr_err("Failed to scan: %d\n", err);
+ return -1;
+ }
+
+ /* Init CC core */
+ core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
+ if (core) {
+ bus->drv_cc.core = core;
+ bcma_core_chipcommon_init(&bus->drv_cc);
+ }
+
+ /* Init PCIE core */
+ core = bcma_find_core(bus, BCMA_CORE_PCIE);
+ if (core) {
+ bus->drv_pci.core = core;
+ bcma_core_pci_init(&bus->drv_pci);
+ }
+
+ /* Register found cores */
+ bcma_register_cores(bus);
+
+ pr_info("Bus registered\n");
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(bcma_bus_register);
+
+void bcma_bus_unregister(struct bcma_bus *bus)
+{
+ bcma_unregister_cores(bus);
+}
+EXPORT_SYMBOL_GPL(bcma_bus_unregister);
+
+int __bcma_driver_register(struct bcma_driver *drv, struct module *owner)
+{
+ drv->drv.name = drv->name;
+ drv->drv.bus = &bcma_bus_type;
+ drv->drv.owner = owner;
+
+ return driver_register(&drv->drv);
+}
+EXPORT_SYMBOL_GPL(__bcma_driver_register);
+
+void bcma_driver_unregister(struct bcma_driver *drv)
+{
+ driver_unregister(&drv->drv);
+}
+EXPORT_SYMBOL_GPL(bcma_driver_unregister);
+
+static int bcma_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+ struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv);
+ const struct bcma_device_id *cid = &core->id;
+ const struct bcma_device_id *did;
+
+ for (did = adrv->id_table; did->manuf || did->id || did->rev; did++) {
+ if ((did->manuf == cid->manuf || did->manuf == BCMA_ANY_MANUF) &&
+ (did->id == cid->id || did->id == BCMA_ANY_ID) &&
+ (did->rev == cid->rev || did->rev == BCMA_ANY_REV) &&
+ (did->class == cid->class || did->class == BCMA_ANY_CLASS))
+ return 1;
+ }
+ return 0;
+}
+
+static int bcma_device_probe(struct device *dev)
+{
+ struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+ struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver,
+ drv);
+ int err = 0;
+
+ if (adrv->probe)
+ err = adrv->probe(core);
+
+ return err;
+}
+
+static int bcma_device_remove(struct device *dev)
+{
+ struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+ struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver,
+ drv);
+
+ if (adrv->remove)
+ adrv->remove(core);
+
+ return 0;
+}
+
+static int __init bcma_modinit(void)
+{
+ int err;
+
+ err = bus_register(&bcma_bus_type);
+ if (err)
+ return err;
+
+#ifdef CONFIG_BCMA_HOST_PCI
+ err = bcma_host_pci_init();
+ if (err) {
+ pr_err("PCI host initialization failed\n");
+ err = 0;
+ }
+#endif
+
+ return err;
+}
+fs_initcall(bcma_modinit);
+
+static void __exit bcma_modexit(void)
+{
+#ifdef CONFIG_BCMA_HOST_PCI
+ bcma_host_pci_exit();
+#endif
+ bus_unregister(&bcma_bus_type);
+}
+module_exit(bcma_modexit)
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
new file mode 100644
index 000000000000..40d7dcce8933
--- /dev/null
+++ b/drivers/bcma/scan.c
@@ -0,0 +1,360 @@
+/*
+ * Broadcom specific AMBA
+ * Bus scanning
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "scan.h"
+#include "bcma_private.h"
+
+#include <linux/bcma/bcma.h>
+#include <linux/bcma/bcma_regs.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+
+struct bcma_device_id_name {
+ u16 id;
+ const char *name;
+};
+struct bcma_device_id_name bcma_device_names[] = {
+ { BCMA_CORE_OOB_ROUTER, "OOB Router" },
+ { BCMA_CORE_INVALID, "Invalid" },
+ { BCMA_CORE_CHIPCOMMON, "ChipCommon" },
+ { BCMA_CORE_ILINE20, "ILine 20" },
+ { BCMA_CORE_SRAM, "SRAM" },
+ { BCMA_CORE_SDRAM, "SDRAM" },
+ { BCMA_CORE_PCI, "PCI" },
+ { BCMA_CORE_MIPS, "MIPS" },
+ { BCMA_CORE_ETHERNET, "Fast Ethernet" },
+ { BCMA_CORE_V90, "V90" },
+ { BCMA_CORE_USB11_HOSTDEV, "USB 1.1 Hostdev" },
+ { BCMA_CORE_ADSL, "ADSL" },
+ { BCMA_CORE_ILINE100, "ILine 100" },
+ { BCMA_CORE_IPSEC, "IPSEC" },
+ { BCMA_CORE_UTOPIA, "UTOPIA" },
+ { BCMA_CORE_PCMCIA, "PCMCIA" },
+ { BCMA_CORE_INTERNAL_MEM, "Internal Memory" },
+ { BCMA_CORE_MEMC_SDRAM, "MEMC SDRAM" },
+ { BCMA_CORE_OFDM, "OFDM" },
+ { BCMA_CORE_EXTIF, "EXTIF" },
+ { BCMA_CORE_80211, "IEEE 802.11" },
+ { BCMA_CORE_PHY_A, "PHY A" },
+ { BCMA_CORE_PHY_B, "PHY B" },
+ { BCMA_CORE_PHY_G, "PHY G" },
+ { BCMA_CORE_MIPS_3302, "MIPS 3302" },
+ { BCMA_CORE_USB11_HOST, "USB 1.1 Host" },
+ { BCMA_CORE_USB11_DEV, "USB 1.1 Device" },
+ { BCMA_CORE_USB20_HOST, "USB 2.0 Host" },
+ { BCMA_CORE_USB20_DEV, "USB 2.0 Device" },
+ { BCMA_CORE_SDIO_HOST, "SDIO Host" },
+ { BCMA_CORE_ROBOSWITCH, "Roboswitch" },
+ { BCMA_CORE_PARA_ATA, "PATA" },
+ { BCMA_CORE_SATA_XORDMA, "SATA XOR-DMA" },
+ { BCMA_CORE_ETHERNET_GBIT, "GBit Ethernet" },
+ { BCMA_CORE_PCIE, "PCIe" },
+ { BCMA_CORE_PHY_N, "PHY N" },
+ { BCMA_CORE_SRAM_CTL, "SRAM Controller" },
+ { BCMA_CORE_MINI_MACPHY, "Mini MACPHY" },
+ { BCMA_CORE_ARM_1176, "ARM 1176" },
+ { BCMA_CORE_ARM_7TDMI, "ARM 7TDMI" },
+ { BCMA_CORE_PHY_LP, "PHY LP" },
+ { BCMA_CORE_PMU, "PMU" },
+ { BCMA_CORE_PHY_SSN, "PHY SSN" },
+ { BCMA_CORE_SDIO_DEV, "SDIO Device" },
+ { BCMA_CORE_ARM_CM3, "ARM CM3" },
+ { BCMA_CORE_PHY_HT, "PHY HT" },
+ { BCMA_CORE_MIPS_74K, "MIPS 74K" },
+ { BCMA_CORE_MAC_GBIT, "GBit MAC" },
+ { BCMA_CORE_DDR12_MEM_CTL, "DDR1/DDR2 Memory Controller" },
+ { BCMA_CORE_PCIE_RC, "PCIe Root Complex" },
+ { BCMA_CORE_OCP_OCP_BRIDGE, "OCP to OCP Bridge" },
+ { BCMA_CORE_SHARED_COMMON, "Common Shared" },
+ { BCMA_CORE_OCP_AHB_BRIDGE, "OCP to AHB Bridge" },
+ { BCMA_CORE_SPI_HOST, "SPI Host" },
+ { BCMA_CORE_I2S, "I2S" },
+ { BCMA_CORE_SDR_DDR1_MEM_CTL, "SDR/DDR1 Memory Controller" },
+ { BCMA_CORE_SHIM, "SHIM" },
+ { BCMA_CORE_DEFAULT, "Default" },
+};
+const char *bcma_device_name(struct bcma_device_id *id)
+{
+ int i;
+
+ if (id->manuf == BCMA_MANUF_BCM) {
+ for (i = 0; i < ARRAY_SIZE(bcma_device_names); i++) {
+ if (bcma_device_names[i].id == id->id)
+ return bcma_device_names[i].name;
+ }
+ }
+ return "UNKNOWN";
+}
+
+static u32 bcma_scan_read32(struct bcma_bus *bus, u8 current_coreidx,
+ u16 offset)
+{
+ return readl(bus->mmio + offset);
+}
+
+static void bcma_scan_switch_core(struct bcma_bus *bus, u32 addr)
+{
+ if (bus->hosttype == BCMA_HOSTTYPE_PCI)
+ pci_write_config_dword(bus->host_pci, BCMA_PCI_BAR0_WIN,
+ addr);
+}
+
+static u32 bcma_erom_get_ent(struct bcma_bus *bus, u32 **eromptr)
+{
+ u32 ent = readl(*eromptr);
+ (*eromptr)++;
+ return ent;
+}
+
+static void bcma_erom_push_ent(u32 **eromptr)
+{
+ (*eromptr)--;
+}
+
+static s32 bcma_erom_get_ci(struct bcma_bus *bus, u32 **eromptr)
+{
+ u32 ent = bcma_erom_get_ent(bus, eromptr);
+ if (!(ent & SCAN_ER_VALID))
+ return -ENOENT;
+ if ((ent & SCAN_ER_TAG) != SCAN_ER_TAG_CI)
+ return -ENOENT;
+ return ent;
+}
+
+static bool bcma_erom_is_end(struct bcma_bus *bus, u32 **eromptr)
+{
+ u32 ent = bcma_erom_get_ent(bus, eromptr);
+ bcma_erom_push_ent(eromptr);
+ return (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID));
+}
+
+static bool bcma_erom_is_bridge(struct bcma_bus *bus, u32 **eromptr)
+{
+ u32 ent = bcma_erom_get_ent(bus, eromptr);
+ bcma_erom_push_ent(eromptr);
+ return (((ent & SCAN_ER_VALID)) &&
+ ((ent & SCAN_ER_TAGX) == SCAN_ER_TAG_ADDR) &&
+ ((ent & SCAN_ADDR_TYPE) == SCAN_ADDR_TYPE_BRIDGE));
+}
+
+static void bcma_erom_skip_component(struct bcma_bus *bus, u32 **eromptr)
+{
+ u32 ent;
+ while (1) {
+ ent = bcma_erom_get_ent(bus, eromptr);
+ if ((ent & SCAN_ER_VALID) &&
+ ((ent & SCAN_ER_TAG) == SCAN_ER_TAG_CI))
+ break;
+ if (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID))
+ break;
+ }
+ bcma_erom_push_ent(eromptr);
+}
+
+static s32 bcma_erom_get_mst_port(struct bcma_bus *bus, u32 **eromptr)
+{
+ u32 ent = bcma_erom_get_ent(bus, eromptr);
+ if (!(ent & SCAN_ER_VALID))
+ return -ENOENT;
+ if ((ent & SCAN_ER_TAG) != SCAN_ER_TAG_MP)
+ return -ENOENT;
+ return ent;
+}
+
+static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr,
+ u32 type, u8 port)
+{
+ u32 addrl, addrh, sizel, sizeh = 0;
+ u32 size;
+
+ u32 ent = bcma_erom_get_ent(bus, eromptr);
+ if ((!(ent & SCAN_ER_VALID)) ||
+ ((ent & SCAN_ER_TAGX) != SCAN_ER_TAG_ADDR) ||
+ ((ent & SCAN_ADDR_TYPE) != type) ||
+ (((ent & SCAN_ADDR_PORT) >> SCAN_ADDR_PORT_SHIFT) != port)) {
+ bcma_erom_push_ent(eromptr);
+ return -EINVAL;
+ }
+
+ addrl = ent & SCAN_ADDR_ADDR;
+ if (ent & SCAN_ADDR_AG32)
+ addrh = bcma_erom_get_ent(bus, eromptr);
+ else
+ addrh = 0;
+
+ if ((ent & SCAN_ADDR_SZ) == SCAN_ADDR_SZ_SZD) {
+ size = bcma_erom_get_ent(bus, eromptr);
+ sizel = size & SCAN_SIZE_SZ;
+ if (size & SCAN_SIZE_SG32)
+ sizeh = bcma_erom_get_ent(bus, eromptr);
+ } else
+ sizel = SCAN_ADDR_SZ_BASE <<
+ ((ent & SCAN_ADDR_SZ) >> SCAN_ADDR_SZ_SHIFT);
+
+ return addrl;
+}
+
+int bcma_bus_scan(struct bcma_bus *bus)
+{
+ u32 erombase;
+ u32 __iomem *eromptr, *eromend;
+
+ s32 cia, cib;
+ u8 ports[2], wrappers[2];
+
+ s32 tmp;
+ u8 i, j;
+
+ int err;
+
+ INIT_LIST_HEAD(&bus->cores);
+ bus->nr_cores = 0;
+
+ bcma_scan_switch_core(bus, BCMA_ADDR_BASE);
+
+ tmp = bcma_scan_read32(bus, 0, BCMA_CC_ID);
+ bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
+ bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
+ bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
+
+ erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
+ eromptr = bus->mmio;
+ eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
+
+ bcma_scan_switch_core(bus, erombase);
+
+ while (eromptr < eromend) {
+ struct bcma_device *core = kzalloc(sizeof(*core), GFP_KERNEL);
+ if (!core)
+ return -ENOMEM;
+ INIT_LIST_HEAD(&core->list);
+ core->bus = bus;
+
+ /* get CIs */
+ cia = bcma_erom_get_ci(bus, &eromptr);
+ if (cia < 0) {
+ bcma_erom_push_ent(&eromptr);
+ if (bcma_erom_is_end(bus, &eromptr))
+ break;
+ err= -EILSEQ;
+ goto out;
+ }
+ cib = bcma_erom_get_ci(bus, &eromptr);
+ if (cib < 0) {
+ err= -EILSEQ;
+ goto out;
+ }
+
+ /* parse CIs */
+ core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
+ core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
+ core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
+ ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
+ ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
+ wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
+ wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
+ core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
+
+ if (((core->id.manuf == BCMA_MANUF_ARM) &&
+ (core->id.id == 0xFFF)) ||
+ (ports[1] == 0)) {
+ bcma_erom_skip_component(bus, &eromptr);
+ continue;
+ }
+
+ /* check if component is a core at all */
+ if (wrappers[0] + wrappers[1] == 0) {
+ /* we could save addrl of the router
+ if (cid == BCMA_CORE_OOB_ROUTER)
+ */
+ bcma_erom_skip_component(bus, &eromptr);
+ continue;
+ }
+
+ if (bcma_erom_is_bridge(bus, &eromptr)) {
+ bcma_erom_skip_component(bus, &eromptr);
+ continue;
+ }
+
+ /* get & parse master ports */
+ for (i = 0; i < ports[0]; i++) {
+ u32 mst_port_d = bcma_erom_get_mst_port(bus, &eromptr);
+ if (mst_port_d < 0) {
+ err= -EILSEQ;
+ goto out;
+ }
+ }
+
+ /* get & parse slave ports */
+ for (i = 0; i < ports[1]; i++) {
+ for (j = 0; ; j++) {
+ tmp = bcma_erom_get_addr_desc(bus, &eromptr,
+ SCAN_ADDR_TYPE_SLAVE, i);
+ if (tmp < 0) {
+ /* no more entries for port _i_ */
+ /* pr_debug("erom: slave port %d "
+ * "has %d descriptors\n", i, j); */
+ break;
+ } else {
+ if (i == 0 && j == 0)
+ core->addr = tmp;
+ }
+ }
+ }
+
+ /* get & parse master wrappers */
+ for (i = 0; i < wrappers[0]; i++) {
+ for (j = 0; ; j++) {
+ tmp = bcma_erom_get_addr_desc(bus, &eromptr,
+ SCAN_ADDR_TYPE_MWRAP, i);
+ if (tmp < 0) {
+ /* no more entries for port _i_ */
+ /* pr_debug("erom: master wrapper %d "
+ * "has %d descriptors\n", i, j); */
+ break;
+ } else {
+ if (i == 0 && j == 0)
+ core->wrap = tmp;
+ }
+ }
+ }
+
+ /* get & parse slave wrappers */
+ for (i = 0; i < wrappers[1]; i++) {
+ u8 hack = (ports[1] == 1) ? 0 : 1;
+ for (j = 0; ; j++) {
+ tmp = bcma_erom_get_addr_desc(bus, &eromptr,
+ SCAN_ADDR_TYPE_SWRAP, i + hack);
+ if (tmp < 0) {
+ /* no more entries for port _i_ */
+ /* pr_debug("erom: master wrapper %d "
+ * has %d descriptors\n", i, j); */
+ break;
+ } else {
+ if (wrappers[0] == 0 && !i && !j)
+ core->wrap = tmp;
+ }
+ }
+ }
+
+ pr_info("Core %d found: %s "
+ "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
+ bus->nr_cores, bcma_device_name(&core->id),
+ core->id.manuf, core->id.id, core->id.rev,
+ core->id.class);
+
+ core->core_index = bus->nr_cores++;
+ list_add(&core->list, &bus->cores);
+ continue;
+out:
+ return err;
+ }
+
+ return 0;
+}
diff --git a/drivers/bcma/scan.h b/drivers/bcma/scan.h
new file mode 100644
index 000000000000..113e6a66884c
--- /dev/null
+++ b/drivers/bcma/scan.h
@@ -0,0 +1,56 @@
+#ifndef BCMA_SCAN_H_
+#define BCMA_SCAN_H_
+
+#define BCMA_ADDR_BASE 0x18000000
+#define BCMA_WRAP_BASE 0x18100000
+
+#define SCAN_ER_VALID 0x00000001
+#define SCAN_ER_TAGX 0x00000006 /* we have to ignore 0x8 bit when checking tag for SCAN_ER_TAG_ADDR */
+#define SCAN_ER_TAG 0x0000000E
+#define SCAN_ER_TAG_CI 0x00000000
+#define SCAN_ER_TAG_MP 0x00000002
+#define SCAN_ER_TAG_ADDR 0x00000004
+#define SCAN_ER_TAG_END 0x0000000E
+#define SCAN_ER_BAD 0xFFFFFFFF
+
+#define SCAN_CIA_CLASS 0x000000F0
+#define SCAN_CIA_CLASS_SHIFT 4
+#define SCAN_CIA_ID 0x000FFF00
+#define SCAN_CIA_ID_SHIFT 8
+#define SCAN_CIA_MANUF 0xFFF00000
+#define SCAN_CIA_MANUF_SHIFT 20
+
+#define SCAN_CIB_NMP 0x000001F0
+#define SCAN_CIB_NMP_SHIFT 4
+#define SCAN_CIB_NSP 0x00003E00
+#define SCAN_CIB_NSP_SHIFT 9
+#define SCAN_CIB_NMW 0x0007C000
+#define SCAN_CIB_NMW_SHIFT 14
+#define SCAN_CIB_NSW 0x00F80000
+#define SCAN_CIB_NSW_SHIFT 17
+#define SCAN_CIB_REV 0xFF000000
+#define SCAN_CIB_REV_SHIFT 24
+
+#define SCAN_ADDR_AG32 0x00000008
+#define SCAN_ADDR_SZ 0x00000030
+#define SCAN_ADDR_SZ_SHIFT 4
+#define SCAN_ADDR_SZ_4K 0x00000000
+#define SCAN_ADDR_SZ_8K 0x00000010
+#define SCAN_ADDR_SZ_16K 0x00000020
+#define SCAN_ADDR_SZ_SZD 0x00000030
+#define SCAN_ADDR_TYPE 0x000000C0
+#define SCAN_ADDR_TYPE_SLAVE 0x00000000
+#define SCAN_ADDR_TYPE_BRIDGE 0x00000040
+#define SCAN_ADDR_TYPE_SWRAP 0x00000080
+#define SCAN_ADDR_TYPE_MWRAP 0x000000C0
+#define SCAN_ADDR_PORT 0x00000F00
+#define SCAN_ADDR_PORT_SHIFT 8
+#define SCAN_ADDR_ADDR 0xFFFFF000
+
+#define SCAN_ADDR_SZ_BASE 0x00001000 /* 4KB */
+
+#define SCAN_SIZE_SZ_ALIGN 0x00000FFF
+#define SCAN_SIZE_SZ 0xFFFFF000
+#define SCAN_SIZE_SG32 0x00000008
+
+#endif /* BCMA_SCAN_H_ */
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 83c32cb72582..717d6e4e18d3 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -470,6 +470,27 @@ config XEN_BLKDEV_FRONTEND
block device driver. It communicates with a back-end driver
in another domain which drives the actual block device.
+config XEN_BLKDEV_BACKEND
+ tristate "Block-device backend driver"
+ depends on XEN_BACKEND
+ help
+ The block-device backend driver allows the kernel to export its
+ block devices to other guests via a high-performance shared-memory
+ interface.
+
+ The corresponding Linux frontend driver is enabled by the
+ CONFIG_XEN_BLKDEV_FRONTEND configuration option.
+
+ The backend driver attaches itself to a any block device specified
+ in the XenBus configuration. There are no limits to what the block
+ device as long as it has a major and minor.
+
+ If you are compiling a kernel to run in a Xen block backend driver
+ domain (often this is domain 0) you should say Y here. To
+ compile this driver as a module, chose M here: the module
+ will be called xen-blkback.
+
+
config VIRTIO_BLK
tristate "Virtio block driver (EXPERIMENTAL)"
depends on EXPERIMENTAL && VIRTIO
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 40528ba56d1b..76646e9a1c91 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_BLK_DEV_UB) += ub.o
obj-$(CONFIG_BLK_DEV_HD) += hd.o
obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o
+obj-$(CONFIG_XEN_BLKDEV_BACKEND) += xen-blkback/
obj-$(CONFIG_BLK_DEV_DRBD) += drbd/
obj-$(CONFIG_BLK_DEV_RBD) += rbd.o
diff --git a/drivers/block/brd.c b/drivers/block/brd.c
index b7f51e4594f8..dba1c32e1ddf 100644
--- a/drivers/block/brd.c
+++ b/drivers/block/brd.c
@@ -35,10 +35,6 @@
*/
struct brd_device {
int brd_number;
- int brd_refcnt;
- loff_t brd_offset;
- loff_t brd_sizelimit;
- unsigned brd_blocksize;
struct request_queue *brd_queue;
struct gendisk *brd_disk;
@@ -440,11 +436,11 @@ static int rd_nr;
int rd_size = CONFIG_BLK_DEV_RAM_SIZE;
static int max_part;
static int part_shift;
-module_param(rd_nr, int, 0);
+module_param(rd_nr, int, S_IRUGO);
MODULE_PARM_DESC(rd_nr, "Maximum number of brd devices");
-module_param(rd_size, int, 0);
+module_param(rd_size, int, S_IRUGO);
MODULE_PARM_DESC(rd_size, "Size of each RAM disk in kbytes.");
-module_param(max_part, int, 0);
+module_param(max_part, int, S_IRUGO);
MODULE_PARM_DESC(max_part, "Maximum number of partitions per RAM disk");
MODULE_LICENSE("GPL");
MODULE_ALIAS_BLOCKDEV_MAJOR(RAMDISK_MAJOR);
@@ -552,7 +548,7 @@ static struct kobject *brd_probe(dev_t dev, int *part, void *data)
struct kobject *kobj;
mutex_lock(&brd_devices_mutex);
- brd = brd_init_one(dev & MINORMASK);
+ brd = brd_init_one(MINOR(dev) >> part_shift);
kobj = brd ? get_disk(brd->brd_disk) : ERR_PTR(-ENOMEM);
mutex_unlock(&brd_devices_mutex);
@@ -575,25 +571,39 @@ static int __init brd_init(void)
*
* (1) if rd_nr is specified, create that many upfront, and this
* also becomes a hard limit.
- * (2) if rd_nr is not specified, create 1 rd device on module
- * load, user can further extend brd device by create dev node
- * themselves and have kernel automatically instantiate actual
- * device on-demand.
+ * (2) if rd_nr is not specified, create CONFIG_BLK_DEV_RAM_COUNT
+ * (default 16) rd device on module load, user can further
+ * extend brd device by create dev node themselves and have
+ * kernel automatically instantiate actual device on-demand.
*/
part_shift = 0;
- if (max_part > 0)
+ if (max_part > 0) {
part_shift = fls(max_part);
+ /*
+ * Adjust max_part according to part_shift as it is exported
+ * to user space so that user can decide correct minor number
+ * if [s]he want to create more devices.
+ *
+ * Note that -1 is required because partition 0 is reserved
+ * for the whole disk.
+ */
+ max_part = (1UL << part_shift) - 1;
+ }
+
+ if ((1UL << part_shift) > DISK_MAX_PARTS)
+ return -EINVAL;
+
if (rd_nr > 1UL << (MINORBITS - part_shift))
return -EINVAL;
if (rd_nr) {
nr = rd_nr;
- range = rd_nr;
+ range = rd_nr << part_shift;
} else {
nr = CONFIG_BLK_DEV_RAM_COUNT;
- range = 1UL << (MINORBITS - part_shift);
+ range = 1UL << MINORBITS;
}
if (register_blkdev(RAMDISK_MAJOR, "ramdisk"))
@@ -632,7 +642,7 @@ static void __exit brd_exit(void)
unsigned long range;
struct brd_device *brd, *next;
- range = rd_nr ? rd_nr : 1UL << (MINORBITS - part_shift);
+ range = rd_nr ? rd_nr << part_shift : 1UL << MINORBITS;
list_for_each_entry_safe(brd, next, &brd_devices, brd_list)
brd_del_one(brd);
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 9bf13988f1a2..8f4ef656a1af 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -64,6 +64,10 @@ MODULE_DESCRIPTION("Driver for HP Smart Array Controllers");
MODULE_SUPPORTED_DEVICE("HP Smart Array Controllers");
MODULE_VERSION("3.6.26");
MODULE_LICENSE("GPL");
+static int cciss_tape_cmds = 6;
+module_param(cciss_tape_cmds, int, 0644);
+MODULE_PARM_DESC(cciss_tape_cmds,
+ "number of commands to allocate for tape devices (default: 6)");
static DEFINE_MUTEX(cciss_mutex);
static struct proc_dir_entry *proc_cciss;
@@ -194,6 +198,8 @@ static int __devinit cciss_find_cfg_addrs(struct pci_dev *pdev,
static int __devinit cciss_pci_find_memory_BAR(struct pci_dev *pdev,
unsigned long *memory_bar);
static inline u32 cciss_tag_discard_error_bits(ctlr_info_t *h, u32 tag);
+static __devinit int write_driver_ver_to_cfgtable(
+ CfgTable_struct __iomem *cfgtable);
/* performant mode helper functions */
static void calc_bucket_map(int *bucket, int num_buckets, int nsgs,
@@ -556,7 +562,7 @@ static void __devinit cciss_procinit(ctlr_info_t *h)
#define to_hba(n) container_of(n, struct ctlr_info, dev)
#define to_drv(n) container_of(n, drive_info_struct, dev)
-/* List of controllers which cannot be reset on kexec with reset_devices */
+/* List of controllers which cannot be hard reset on kexec with reset_devices */
static u32 unresettable_controller[] = {
0x324a103C, /* Smart Array P712m */
0x324b103C, /* SmartArray P711m */
@@ -574,23 +580,45 @@ static u32 unresettable_controller[] = {
0x409D0E11, /* Smart Array 6400 EM */
};
-static int ctlr_is_resettable(struct ctlr_info *h)
+/* List of controllers which cannot even be soft reset */
+static u32 soft_unresettable_controller[] = {
+ 0x409C0E11, /* Smart Array 6400 */
+ 0x409D0E11, /* Smart Array 6400 EM */
+};
+
+static int ctlr_is_hard_resettable(u32 board_id)
{
int i;
for (i = 0; i < ARRAY_SIZE(unresettable_controller); i++)
- if (unresettable_controller[i] == h->board_id)
+ if (unresettable_controller[i] == board_id)
return 0;
return 1;
}
+static int ctlr_is_soft_resettable(u32 board_id)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(soft_unresettable_controller); i++)
+ if (soft_unresettable_controller[i] == board_id)
+ return 0;
+ return 1;
+}
+
+static int ctlr_is_resettable(u32 board_id)
+{
+ return ctlr_is_hard_resettable(board_id) ||
+ ctlr_is_soft_resettable(board_id);
+}
+
static ssize_t host_show_resettable(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct ctlr_info *h = to_hba(dev);
- return snprintf(buf, 20, "%d\n", ctlr_is_resettable(h));
+ return snprintf(buf, 20, "%d\n", ctlr_is_resettable(h->board_id));
}
static DEVICE_ATTR(resettable, S_IRUGO, host_show_resettable, NULL);
@@ -2567,7 +2595,7 @@ static int fill_cmd(ctlr_info_t *h, CommandList_struct *c, __u8 cmd, void *buff,
}
} else if (cmd_type == TYPE_MSG) {
switch (cmd) {
- case 0: /* ABORT message */
+ case CCISS_ABORT_MSG:
c->Request.CDBLen = 12;
c->Request.Type.Attribute = ATTR_SIMPLE;
c->Request.Type.Direction = XFER_WRITE;
@@ -2577,16 +2605,16 @@ static int fill_cmd(ctlr_info_t *h, CommandList_struct *c, __u8 cmd, void *buff,
/* buff contains the tag of the command to abort */
memcpy(&c->Request.CDB[4], buff, 8);
break;
- case 1: /* RESET message */
+ case CCISS_RESET_MSG:
c->Request.CDBLen = 16;
c->Request.Type.Attribute = ATTR_SIMPLE;
c->Request.Type.Direction = XFER_NONE;
c->Request.Timeout = 0;
memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB));
c->Request.CDB[0] = cmd; /* reset */
- c->Request.CDB[1] = 0x03; /* reset a target */
+ c->Request.CDB[1] = CCISS_RESET_TYPE_TARGET;
break;
- case 3: /* No-Op message */
+ case CCISS_NOOP_MSG:
c->Request.CDBLen = 1;
c->Request.Type.Attribute = ATTR_SIMPLE;
c->Request.Type.Direction = XFER_WRITE;
@@ -2615,6 +2643,31 @@ static int fill_cmd(ctlr_info_t *h, CommandList_struct *c, __u8 cmd, void *buff,
return status;
}
+static int __devinit cciss_send_reset(ctlr_info_t *h, unsigned char *scsi3addr,
+ u8 reset_type)
+{
+ CommandList_struct *c;
+ int return_status;
+
+ c = cmd_alloc(h);
+ if (!c)
+ return -ENOMEM;
+ return_status = fill_cmd(h, c, CCISS_RESET_MSG, NULL, 0, 0,
+ CTLR_LUNID, TYPE_MSG);
+ c->Request.CDB[1] = reset_type; /* fill_cmd defaults to target reset */
+ if (return_status != IO_OK) {
+ cmd_special_free(h, c);
+ return return_status;
+ }
+ c->waiting = NULL;
+ enqueue_cmd_and_start_io(h, c);
+ /* Don't wait for completion, the reset won't complete. Don't free
+ * the command either. This is the last command we will send before
+ * re-initializing everything, so it doesn't matter and won't leak.
+ */
+ return 0;
+}
+
static int check_target_status(ctlr_info_t *h, CommandList_struct *c)
{
switch (c->err_info->ScsiStatus) {
@@ -3461,6 +3514,63 @@ static inline u32 process_nonindexed_cmd(ctlr_info_t *h, u32 raw_tag)
return next_command(h);
}
+/* Some controllers, like p400, will give us one interrupt
+ * after a soft reset, even if we turned interrupts off.
+ * Only need to check for this in the cciss_xxx_discard_completions
+ * functions.
+ */
+static int ignore_bogus_interrupt(ctlr_info_t *h)
+{
+ if (likely(!reset_devices))
+ return 0;
+
+ if (likely(h->interrupts_enabled))
+ return 0;
+
+ dev_info(&h->pdev->dev, "Received interrupt while interrupts disabled "
+ "(known firmware bug.) Ignoring.\n");
+
+ return 1;
+}
+
+static irqreturn_t cciss_intx_discard_completions(int irq, void *dev_id)
+{
+ ctlr_info_t *h = dev_id;
+ unsigned long flags;
+ u32 raw_tag;
+
+ if (ignore_bogus_interrupt(h))
+ return IRQ_NONE;
+
+ 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)
+ raw_tag = next_command(h);
+ }
+ spin_unlock_irqrestore(&h->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t cciss_msix_discard_completions(int irq, void *dev_id)
+{
+ ctlr_info_t *h = dev_id;
+ unsigned long flags;
+ u32 raw_tag;
+
+ if (ignore_bogus_interrupt(h))
+ return IRQ_NONE;
+
+ spin_lock_irqsave(&h->lock, flags);
+ raw_tag = get_next_completion(h);
+ while (raw_tag != FIFO_EMPTY)
+ raw_tag = next_command(h);
+ spin_unlock_irqrestore(&h->lock, flags);
+ return IRQ_HANDLED;
+}
+
static irqreturn_t do_cciss_intx(int irq, void *dev_id)
{
ctlr_info_t *h = dev_id;
@@ -4078,6 +4188,9 @@ static int __devinit cciss_find_cfgtables(ctlr_info_t *h)
cfg_base_addr_index) + cfg_offset, sizeof(h->cfgtable));
if (!h->cfgtable)
return -ENOMEM;
+ rc = write_driver_ver_to_cfgtable(h->cfgtable);
+ if (rc)
+ return rc;
/* Find performant mode table. */
trans_offset = readl(&h->cfgtable->TransMethodOffset);
h->transtable = remap_pci_mem(pci_resource_start(h->pdev,
@@ -4112,7 +4225,7 @@ static void __devinit cciss_get_max_perf_mode_cmds(struct ctlr_info *h)
static void __devinit cciss_find_board_params(ctlr_info_t *h)
{
cciss_get_max_perf_mode_cmds(h);
- h->nr_cmds = h->max_commands - 4; /* Allow room for some ioctls */
+ h->nr_cmds = h->max_commands - 4 - cciss_tape_cmds;
h->maxsgentries = readl(&(h->cfgtable->MaxSGElements));
/*
* Limit in-command s/g elements to 32 save dma'able memory.
@@ -4348,7 +4461,7 @@ static __devinit int cciss_message(struct pci_dev *pdev, unsigned char opcode, u
tag = readl(vaddr + SA5_REPLY_PORT_OFFSET);
if ((tag & ~3) == paddr32)
break;
- schedule_timeout_uninterruptible(HZ);
+ msleep(CCISS_POST_RESET_NOOP_TIMEOUT_MSECS);
}
iounmap(vaddr);
@@ -4375,11 +4488,10 @@ static __devinit int cciss_message(struct pci_dev *pdev, unsigned char opcode, u
return 0;
}
-#define cciss_soft_reset_controller(p) cciss_message(p, 1, 0)
#define cciss_noop(p) cciss_message(p, 3, 0)
static int cciss_controller_hard_reset(struct pci_dev *pdev,
- void * __iomem vaddr, bool use_doorbell)
+ void * __iomem vaddr, u32 use_doorbell)
{
u16 pmcsr;
int pos;
@@ -4390,8 +4502,7 @@ static int cciss_controller_hard_reset(struct pci_dev *pdev,
* 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);
+ writel(use_doorbell, vaddr + SA5_DOORBELL);
} else { /* Try to do it the PCI power state way */
/* Quoting from the Open CISS Specification: "The Power
@@ -4422,12 +4533,64 @@ static int cciss_controller_hard_reset(struct pci_dev *pdev,
pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
pmcsr |= PCI_D0;
pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
-
- msleep(500);
}
return 0;
}
+static __devinit void init_driver_version(char *driver_version, int len)
+{
+ memset(driver_version, 0, len);
+ strncpy(driver_version, "cciss " DRIVER_NAME, len - 1);
+}
+
+static __devinit int write_driver_ver_to_cfgtable(
+ CfgTable_struct __iomem *cfgtable)
+{
+ char *driver_version;
+ int i, size = sizeof(cfgtable->driver_version);
+
+ driver_version = kmalloc(size, GFP_KERNEL);
+ if (!driver_version)
+ return -ENOMEM;
+
+ init_driver_version(driver_version, size);
+ for (i = 0; i < size; i++)
+ writeb(driver_version[i], &cfgtable->driver_version[i]);
+ kfree(driver_version);
+ return 0;
+}
+
+static __devinit void read_driver_ver_from_cfgtable(
+ CfgTable_struct __iomem *cfgtable, unsigned char *driver_ver)
+{
+ int i;
+
+ for (i = 0; i < sizeof(cfgtable->driver_version); i++)
+ driver_ver[i] = readb(&cfgtable->driver_version[i]);
+}
+
+static __devinit int controller_reset_failed(
+ CfgTable_struct __iomem *cfgtable)
+{
+
+ char *driver_ver, *old_driver_ver;
+ int rc, size = sizeof(cfgtable->driver_version);
+
+ old_driver_ver = kmalloc(2 * size, GFP_KERNEL);
+ if (!old_driver_ver)
+ return -ENOMEM;
+ driver_ver = old_driver_ver + size;
+
+ /* After a reset, the 32 bytes of "driver version" in the cfgtable
+ * should have been changed, otherwise we know the reset failed.
+ */
+ init_driver_version(old_driver_ver, size);
+ read_driver_ver_from_cfgtable(cfgtable, driver_ver);
+ rc = !memcmp(driver_ver, old_driver_ver, size);
+ kfree(old_driver_ver);
+ return rc;
+}
+
/* This does a hard reset of the controller using PCI power management
* states or using the doorbell register. */
static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
@@ -4437,10 +4600,10 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
u64 cfg_base_addr_index;
void __iomem *vaddr;
unsigned long paddr;
- u32 misc_fw_support, active_transport;
+ u32 misc_fw_support;
int rc;
CfgTable_struct __iomem *cfgtable;
- bool use_doorbell;
+ u32 use_doorbell;
u32 board_id;
u16 command_register;
@@ -4464,12 +4627,16 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
* likely not be happy. Just forbid resetting this conjoined mess.
*/
cciss_lookup_board_id(pdev, &board_id);
- if (board_id == 0x409C0E11 || board_id == 0x409D0E11) {
+ if (!ctlr_is_resettable(board_id)) {
dev_warn(&pdev->dev, "Cannot reset Smart Array 640x "
"due to shared cache module.");
return -ENODEV;
}
+ /* if controller is soft- but not hard resettable... */
+ if (!ctlr_is_hard_resettable(board_id))
+ return -ENOTSUPP; /* try soft reset later. */
+
/* Save the PCI command register */
pci_read_config_word(pdev, 4, &command_register);
/* Turn the board off. This is so that later pci_restore_state()
@@ -4497,16 +4664,28 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
rc = -ENOMEM;
goto unmap_vaddr;
}
+ rc = write_driver_ver_to_cfgtable(cfgtable);
+ if (rc)
+ goto unmap_vaddr;
- /* 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;
-
- /* The doorbell reset seems to cause lockups on some Smart
- * Arrays (e.g. P410, P410i, maybe others). Until this is
- * fixed or at least isolated, avoid the doorbell reset.
+ /* If reset via doorbell register is supported, use that.
+ * There are two such methods. Favor the newest method.
*/
- use_doorbell = 0;
+ misc_fw_support = readl(&cfgtable->misc_fw_support);
+ use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET2;
+ if (use_doorbell) {
+ use_doorbell = DOORBELL_CTLR_RESET2;
+ } else {
+ use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET;
+ if (use_doorbell) {
+ dev_warn(&pdev->dev, "Controller claims that "
+ "'Bit 2 doorbell reset' is "
+ "supported, but not 'bit 5 doorbell reset'. "
+ "Firmware update is recommended.\n");
+ rc = -ENOTSUPP; /* use the soft reset */
+ goto unmap_cfgtable;
+ }
+ }
rc = cciss_controller_hard_reset(pdev, vaddr, use_doorbell);
if (rc)
@@ -4524,30 +4703,31 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
msleep(CCISS_POST_RESET_PAUSE_MSECS);
/* Wait for board to become not ready, then ready. */
- dev_info(&pdev->dev, "Waiting for board to become ready.\n");
+ dev_info(&pdev->dev, "Waiting for board to reset.\n");
rc = cciss_wait_for_board_state(pdev, vaddr, BOARD_NOT_READY);
- if (rc) /* Don't bail, might be E500, etc. which can't be reset */
- dev_warn(&pdev->dev,
- "failed waiting for board to become not ready\n");
+ if (rc) {
+ dev_warn(&pdev->dev, "Failed waiting for board to hard reset."
+ " Will try soft reset.\n");
+ rc = -ENOTSUPP; /* Not expected, but try soft reset later */
+ goto unmap_cfgtable;
+ }
rc = cciss_wait_for_board_state(pdev, vaddr, BOARD_READY);
if (rc) {
dev_warn(&pdev->dev,
- "failed waiting for board to become ready\n");
+ "failed waiting for board to become ready "
+ "after hard reset\n");
goto unmap_cfgtable;
}
- dev_info(&pdev->dev, "board ready.\n");
- /* 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, don't try to proceed, as it generally doesn't work.
- */
- active_transport = readl(&cfgtable->TransportActive);
- if (active_transport & PERFORMANT_MODE) {
- dev_warn(&pdev->dev, "Unable to successfully reset controller,"
- " Ignoring controller.\n");
- rc = -ENODEV;
+ rc = controller_reset_failed(vaddr);
+ if (rc < 0)
+ goto unmap_cfgtable;
+ if (rc) {
+ dev_warn(&pdev->dev, "Unable to successfully hard reset "
+ "controller. Will try soft reset.\n");
+ rc = -ENOTSUPP; /* Not expected, but try soft reset later */
+ } else {
+ dev_info(&pdev->dev, "Board ready after hard reset.\n");
}
unmap_cfgtable:
@@ -4574,11 +4754,12 @@ static __devinit int cciss_init_reset_devices(struct pci_dev *pdev)
* due to concerns about shared bbwc between 6402/6404 pair.
*/
if (rc == -ENOTSUPP)
- return 0; /* just try to do the kdump anyhow. */
+ return rc; /* just try to do the kdump anyhow. */
if (rc)
return -ENODEV;
/* Now try to get the controller to respond to a no-op */
+ dev_warn(&pdev->dev, "Waiting for controller to respond to no-op\n");
for (i = 0; i < CCISS_POST_RESET_NOOP_RETRIES; i++) {
if (cciss_noop(pdev) == 0)
break;
@@ -4591,6 +4772,148 @@ static __devinit int cciss_init_reset_devices(struct pci_dev *pdev)
return 0;
}
+static __devinit int cciss_allocate_cmd_pool(ctlr_info_t *h)
+{
+ h->cmd_pool_bits = kmalloc(
+ DIV_ROUND_UP(h->nr_cmds, BITS_PER_LONG) *
+ sizeof(unsigned long), GFP_KERNEL);
+ h->cmd_pool = pci_alloc_consistent(h->pdev,
+ h->nr_cmds * sizeof(CommandList_struct),
+ &(h->cmd_pool_dhandle));
+ h->errinfo_pool = pci_alloc_consistent(h->pdev,
+ h->nr_cmds * sizeof(ErrorInfo_struct),
+ &(h->errinfo_pool_dhandle));
+ if ((h->cmd_pool_bits == NULL)
+ || (h->cmd_pool == NULL)
+ || (h->errinfo_pool == NULL)) {
+ dev_err(&h->pdev->dev, "out of memory");
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static __devinit int cciss_allocate_scatterlists(ctlr_info_t *h)
+{
+ int i;
+
+ /* zero it, so that on free we need not know how many were alloc'ed */
+ h->scatter_list = kzalloc(h->max_commands *
+ sizeof(struct scatterlist *), GFP_KERNEL);
+ if (!h->scatter_list)
+ return -ENOMEM;
+
+ for (i = 0; i < h->nr_cmds; i++) {
+ h->scatter_list[i] = kmalloc(sizeof(struct scatterlist) *
+ h->maxsgentries, GFP_KERNEL);
+ if (h->scatter_list[i] == NULL) {
+ dev_err(&h->pdev->dev, "could not allocate "
+ "s/g lists\n");
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
+static void cciss_free_scatterlists(ctlr_info_t *h)
+{
+ int i;
+
+ if (h->scatter_list) {
+ for (i = 0; i < h->nr_cmds; i++)
+ kfree(h->scatter_list[i]);
+ kfree(h->scatter_list);
+ }
+}
+
+static void cciss_free_cmd_pool(ctlr_info_t *h)
+{
+ kfree(h->cmd_pool_bits);
+ if (h->cmd_pool)
+ pci_free_consistent(h->pdev,
+ h->nr_cmds * sizeof(CommandList_struct),
+ h->cmd_pool, h->cmd_pool_dhandle);
+ if (h->errinfo_pool)
+ pci_free_consistent(h->pdev,
+ h->nr_cmds * sizeof(ErrorInfo_struct),
+ h->errinfo_pool, h->errinfo_pool_dhandle);
+}
+
+static int cciss_request_irq(ctlr_info_t *h,
+ irqreturn_t (*msixhandler)(int, void *),
+ irqreturn_t (*intxhandler)(int, void *))
+{
+ if (h->msix_vector || h->msi_vector) {
+ if (!request_irq(h->intr[PERF_MODE_INT], msixhandler,
+ IRQF_DISABLED, h->devname, h))
+ return 0;
+ dev_err(&h->pdev->dev, "Unable to get msi irq %d"
+ " for %s\n", h->intr[PERF_MODE_INT],
+ h->devname);
+ return -1;
+ }
+
+ if (!request_irq(h->intr[PERF_MODE_INT], intxhandler,
+ IRQF_DISABLED, h->devname, h))
+ return 0;
+ dev_err(&h->pdev->dev, "Unable to get irq %d for %s\n",
+ h->intr[PERF_MODE_INT], h->devname);
+ return -1;
+}
+
+static int __devinit cciss_kdump_soft_reset(ctlr_info_t *h)
+{
+ if (cciss_send_reset(h, CTLR_LUNID, CCISS_RESET_TYPE_CONTROLLER)) {
+ dev_warn(&h->pdev->dev, "Resetting array controller failed.\n");
+ return -EIO;
+ }
+
+ dev_info(&h->pdev->dev, "Waiting for board to soft reset.\n");
+ if (cciss_wait_for_board_state(h->pdev, h->vaddr, BOARD_NOT_READY)) {
+ dev_warn(&h->pdev->dev, "Soft reset had no effect.\n");
+ return -1;
+ }
+
+ dev_info(&h->pdev->dev, "Board reset, awaiting READY status.\n");
+ if (cciss_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY)) {
+ dev_warn(&h->pdev->dev, "Board failed to become ready "
+ "after soft reset.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void cciss_undo_allocations_after_kdump_soft_reset(ctlr_info_t *h)
+{
+ int ctlr = h->ctlr;
+
+ free_irq(h->intr[PERF_MODE_INT], h);
+#ifdef CONFIG_PCI_MSI
+ if (h->msix_vector)
+ pci_disable_msix(h->pdev);
+ else if (h->msi_vector)
+ pci_disable_msi(h->pdev);
+#endif /* CONFIG_PCI_MSI */
+ cciss_free_sg_chain_blocks(h->cmd_sg_list, h->nr_cmds);
+ cciss_free_scatterlists(h);
+ cciss_free_cmd_pool(h);
+ kfree(h->blockFetchTable);
+ if (h->reply_pool)
+ pci_free_consistent(h->pdev, h->max_commands * sizeof(__u64),
+ h->reply_pool, h->reply_pool_dhandle);
+ if (h->transtable)
+ iounmap(h->transtable);
+ if (h->cfgtable)
+ iounmap(h->cfgtable);
+ if (h->vaddr)
+ iounmap(h->vaddr);
+ unregister_blkdev(h->major, h->devname);
+ cciss_destroy_hba_sysfs_entry(h);
+ pci_release_regions(h->pdev);
+ kfree(h);
+ hba[ctlr] = NULL;
+}
+
/*
* This is it. Find all the controllers and register them. I really hate
* stealing all these major device numbers.
@@ -4601,15 +4924,28 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
{
int i;
int j = 0;
- int k = 0;
int rc;
+ int try_soft_reset = 0;
int dac, return_code;
InquiryData_struct *inq_buff;
ctlr_info_t *h;
+ unsigned long flags;
rc = cciss_init_reset_devices(pdev);
- if (rc)
- return rc;
+ if (rc) {
+ if (rc != -ENOTSUPP)
+ return rc;
+ /* If the reset fails in a particular way (it has no way to do
+ * a proper hard reset, so returns -ENOTSUPP) we can try to do
+ * a soft reset once we get the controller configured up to the
+ * point that it can accept a command.
+ */
+ try_soft_reset = 1;
+ rc = 0;
+ }
+
+reinit_after_soft_reset:
+
i = alloc_cciss_hba(pdev);
if (i < 0)
return -1;
@@ -4627,6 +4963,11 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
sprintf(h->devname, "cciss%d", i);
h->ctlr = i;
+ if (cciss_tape_cmds < 2)
+ cciss_tape_cmds = 2;
+ if (cciss_tape_cmds > 16)
+ cciss_tape_cmds = 16;
+
init_completion(&h->scan_wait);
if (cciss_create_hba_sysfs_entry(h))
@@ -4662,62 +5003,20 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
/* make sure the board interrupts are off */
h->access.set_intr_mask(h, CCISS_INTR_OFF);
- if (h->msi_vector || h->msix_vector) {
- if (request_irq(h->intr[PERF_MODE_INT],
- do_cciss_msix_intr,
- IRQF_DISABLED, h->devname, h)) {
- dev_err(&h->pdev->dev, "Unable to get irq %d for %s\n",
- h->intr[PERF_MODE_INT], h->devname);
- goto clean2;
- }
- } else {
- if (request_irq(h->intr[PERF_MODE_INT], do_cciss_intx,
- IRQF_DISABLED, h->devname, h)) {
- dev_err(&h->pdev->dev, "Unable to get irq %d for %s\n",
- h->intr[PERF_MODE_INT], h->devname);
- goto clean2;
- }
- }
+ rc = cciss_request_irq(h, do_cciss_msix_intr, do_cciss_intx);
+ if (rc)
+ goto clean2;
dev_info(&h->pdev->dev, "%s: <0x%x> at PCI %s IRQ %d%s using DAC\n",
h->devname, pdev->device, pci_name(pdev),
h->intr[PERF_MODE_INT], dac ? "" : " not");
- h->cmd_pool_bits =
- kmalloc(DIV_ROUND_UP(h->nr_cmds, BITS_PER_LONG)
- * sizeof(unsigned long), GFP_KERNEL);
- h->cmd_pool = (CommandList_struct *)
- pci_alloc_consistent(h->pdev,
- h->nr_cmds * sizeof(CommandList_struct),
- &(h->cmd_pool_dhandle));
- h->errinfo_pool = (ErrorInfo_struct *)
- pci_alloc_consistent(h->pdev,
- h->nr_cmds * sizeof(ErrorInfo_struct),
- &(h->errinfo_pool_dhandle));
- if ((h->cmd_pool_bits == NULL)
- || (h->cmd_pool == NULL)
- || (h->errinfo_pool == NULL)) {
- dev_err(&h->pdev->dev, "out of memory");
+ if (cciss_allocate_cmd_pool(h))
goto clean4;
- }
- /* Need space for temp scatter list */
- h->scatter_list = kmalloc(h->max_commands *
- sizeof(struct scatterlist *),
- GFP_KERNEL);
- if (!h->scatter_list)
+ if (cciss_allocate_scatterlists(h))
goto clean4;
- for (k = 0; k < h->nr_cmds; k++) {
- h->scatter_list[k] = kmalloc(sizeof(struct scatterlist) *
- h->maxsgentries,
- GFP_KERNEL);
- if (h->scatter_list[k] == NULL) {
- dev_err(&h->pdev->dev,
- "could not allocate s/g lists\n");
- goto clean4;
- }
- }
h->cmd_sg_list = cciss_allocate_sg_chain_blocks(h,
h->chainsize, h->nr_cmds);
if (!h->cmd_sg_list && h->chainsize > 0)
@@ -4741,6 +5040,62 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
h->gendisk[j] = NULL;
}
+ /* At this point, the controller is ready to take commands.
+ * Now, if reset_devices and the hard reset didn't work, try
+ * the soft reset and see if that works.
+ */
+ if (try_soft_reset) {
+
+ /* This is kind of gross. We may or may not get a completion
+ * from the soft reset command, and if we do, then the value
+ * from the fifo may or may not be valid. So, we wait 10 secs
+ * after the reset throwing away any completions we get during
+ * that time. Unregister the interrupt handler and register
+ * fake ones to scoop up any residual completions.
+ */
+ spin_lock_irqsave(&h->lock, flags);
+ h->access.set_intr_mask(h, CCISS_INTR_OFF);
+ spin_unlock_irqrestore(&h->lock, flags);
+ free_irq(h->intr[PERF_MODE_INT], h);
+ rc = cciss_request_irq(h, cciss_msix_discard_completions,
+ cciss_intx_discard_completions);
+ if (rc) {
+ dev_warn(&h->pdev->dev, "Failed to request_irq after "
+ "soft reset.\n");
+ goto clean4;
+ }
+
+ rc = cciss_kdump_soft_reset(h);
+ if (rc) {
+ dev_warn(&h->pdev->dev, "Soft reset failed.\n");
+ goto clean4;
+ }
+
+ dev_info(&h->pdev->dev, "Board READY.\n");
+ dev_info(&h->pdev->dev,
+ "Waiting for stale completions to drain.\n");
+ h->access.set_intr_mask(h, CCISS_INTR_ON);
+ msleep(10000);
+ h->access.set_intr_mask(h, CCISS_INTR_OFF);
+
+ rc = controller_reset_failed(h->cfgtable);
+ if (rc)
+ dev_info(&h->pdev->dev,
+ "Soft reset appears to have failed.\n");
+
+ /* since the controller's reset, we have to go back and re-init
+ * everything. Easiest to just forget what we've done and do it
+ * all over again.
+ */
+ cciss_undo_allocations_after_kdump_soft_reset(h);
+ try_soft_reset = 0;
+ if (rc)
+ /* don't go to clean4, we already unallocated */
+ return -ENODEV;
+
+ goto reinit_after_soft_reset;
+ }
+
cciss_scsi_setup(h);
/* Turn the interrupts on so we can service requests */
@@ -4775,21 +5130,9 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
return 1;
clean4:
- kfree(h->cmd_pool_bits);
- /* Free up sg elements */
- for (k-- ; k >= 0; k--)
- kfree(h->scatter_list[k]);
- kfree(h->scatter_list);
+ cciss_free_cmd_pool(h);
+ cciss_free_scatterlists(h);
cciss_free_sg_chain_blocks(h->cmd_sg_list, h->nr_cmds);
- if (h->cmd_pool)
- pci_free_consistent(h->pdev,
- h->nr_cmds * sizeof(CommandList_struct),
- h->cmd_pool, h->cmd_pool_dhandle);
- if (h->errinfo_pool)
- pci_free_consistent(h->pdev,
- h->nr_cmds * sizeof(ErrorInfo_struct),
- h->errinfo_pool,
- h->errinfo_pool_dhandle);
free_irq(h->intr[PERF_MODE_INT], h);
clean2:
unregister_blkdev(h->major, h->devname);
@@ -4887,16 +5230,16 @@ static void __devexit cciss_remove_one(struct pci_dev *pdev)
iounmap(h->cfgtable);
iounmap(h->vaddr);
- pci_free_consistent(h->pdev, h->nr_cmds * sizeof(CommandList_struct),
- h->cmd_pool, h->cmd_pool_dhandle);
- pci_free_consistent(h->pdev, h->nr_cmds * sizeof(ErrorInfo_struct),
- h->errinfo_pool, h->errinfo_pool_dhandle);
- kfree(h->cmd_pool_bits);
+ cciss_free_cmd_pool(h);
/* Free up sg elements */
for (j = 0; j < h->nr_cmds; j++)
kfree(h->scatter_list[j]);
kfree(h->scatter_list);
cciss_free_sg_chain_blocks(h->cmd_sg_list, h->nr_cmds);
+ kfree(h->blockFetchTable);
+ if (h->reply_pool)
+ pci_free_consistent(h->pdev, h->max_commands * sizeof(__u64),
+ h->reply_pool, h->reply_pool_dhandle);
/*
* Deliberately omit pci_disable_device(): it does something nasty to
* Smart Array controllers that pci_enable_device does not undo
diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h
index 554bbd907d14..16b4d58d84dd 100644
--- a/drivers/block/cciss.h
+++ b/drivers/block/cciss.h
@@ -200,7 +200,7 @@ struct ctlr_info
* the above.
*/
#define CCISS_BOARD_READY_WAIT_SECS (120)
-#define CCISS_BOARD_NOT_READY_WAIT_SECS (10)
+#define CCISS_BOARD_NOT_READY_WAIT_SECS (100)
#define CCISS_BOARD_READY_POLL_INTERVAL_MSECS (100)
#define CCISS_BOARD_READY_ITERATIONS \
((CCISS_BOARD_READY_WAIT_SECS * 1000) / \
@@ -209,8 +209,9 @@ struct ctlr_info
((CCISS_BOARD_NOT_READY_WAIT_SECS * 1000) / \
CCISS_BOARD_READY_POLL_INTERVAL_MSECS)
#define CCISS_POST_RESET_PAUSE_MSECS (3000)
-#define CCISS_POST_RESET_NOOP_INTERVAL_MSECS (1000)
+#define CCISS_POST_RESET_NOOP_INTERVAL_MSECS (4000)
#define CCISS_POST_RESET_NOOP_RETRIES (12)
+#define CCISS_POST_RESET_NOOP_TIMEOUT_MSECS (10000)
/*
Send the command to the hardware
@@ -239,11 +240,13 @@ static void SA5_intr_mask(ctlr_info_t *h, unsigned long val)
{ /* Turn interrupts on */
h->interrupts_enabled = 1;
writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+ (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
} else /* Turn them off */
{
h->interrupts_enabled = 0;
writel( SA5_INTR_OFF,
h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+ (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
}
}
/*
@@ -257,11 +260,13 @@ static void SA5B_intr_mask(ctlr_info_t *h, unsigned long val)
{ /* Turn interrupts on */
h->interrupts_enabled = 1;
writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+ (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
} else /* Turn them off */
{
h->interrupts_enabled = 0;
writel( SA5B_INTR_OFF,
h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+ (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
}
}
@@ -271,10 +276,12 @@ static void SA5_performant_intr_mask(ctlr_info_t *h, unsigned long val)
if (val) { /* turn on interrupts */
h->interrupts_enabled = 1;
writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+ (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
} else {
h->interrupts_enabled = 0;
writel(SA5_PERF_INTR_OFF,
h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+ (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
}
}
diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h
index cd441bef031f..d9be6b4d49a6 100644
--- a/drivers/block/cciss_cmd.h
+++ b/drivers/block/cciss_cmd.h
@@ -53,6 +53,7 @@
#define CFGTBL_ChangeReq 0x00000001l
#define CFGTBL_AccCmds 0x00000001l
#define DOORBELL_CTLR_RESET 0x00000004l
+#define DOORBELL_CTLR_RESET2 0x00000020l
#define CFGTBL_Trans_Simple 0x00000002l
#define CFGTBL_Trans_Performant 0x00000004l
@@ -142,6 +143,14 @@ typedef struct _ReadCapdata_struct_16
#define BMIC_CACHE_FLUSH 0xc2
#define CCISS_CACHE_FLUSH 0x01 /* C2 was already being used by CCISS */
+#define CCISS_ABORT_MSG 0x00
+#define CCISS_RESET_MSG 0x01
+#define CCISS_RESET_TYPE_CONTROLLER 0x00
+#define CCISS_RESET_TYPE_BUS 0x01
+#define CCISS_RESET_TYPE_TARGET 0x03
+#define CCISS_RESET_TYPE_LUN 0x04
+#define CCISS_NOOP_MSG 0x03
+
/* Command List Structure */
#define CTLR_LUNID "\0\0\0\0\0\0\0\0"
@@ -235,6 +244,8 @@ typedef struct _CfgTable_struct {
u8 reserved[0x78 - 0x58];
u32 misc_fw_support; /* offset 0x78 */
#define MISC_FW_DOORBELL_RESET (0x02)
+#define MISC_FW_DOORBELL_RESET2 (0x10)
+ u8 driver_version[32];
} CfgTable_struct;
struct TransTable_struct {
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
index df793803f5ae..696100241a6f 100644
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -84,7 +84,6 @@ static struct scsi_host_template cciss_driver_template = {
.proc_name = "cciss",
.proc_info = cciss_scsi_proc_info,
.queuecommand = cciss_scsi_queue_command,
- .can_queue = SCSI_CCISS_CAN_QUEUE,
.this_id = 7,
.cmd_per_lun = 1,
.use_clustering = DISABLE_CLUSTERING,
@@ -108,16 +107,13 @@ struct cciss_scsi_cmd_stack_elem_t {
#pragma pack()
-#define CMD_STACK_SIZE (SCSI_CCISS_CAN_QUEUE * \
- CCISS_MAX_SCSI_DEVS_PER_HBA + 2)
- // plus two for init time usage
-
#pragma pack(1)
struct cciss_scsi_cmd_stack_t {
struct cciss_scsi_cmd_stack_elem_t *pool;
- struct cciss_scsi_cmd_stack_elem_t *elem[CMD_STACK_SIZE];
+ struct cciss_scsi_cmd_stack_elem_t **elem;
dma_addr_t cmd_pool_handle;
int top;
+ int nelems;
};
#pragma pack()
@@ -191,7 +187,7 @@ scsi_cmd_free(ctlr_info_t *h, CommandList_struct *c)
sa = h->scsi_ctlr;
stk = &sa->cmd_stack;
stk->top++;
- if (stk->top >= CMD_STACK_SIZE) {
+ if (stk->top >= stk->nelems) {
dev_err(&h->pdev->dev,
"scsi_cmd_free called too many times.\n");
BUG();
@@ -206,13 +202,14 @@ scsi_cmd_stack_setup(ctlr_info_t *h, struct cciss_scsi_adapter_data_t *sa)
struct cciss_scsi_cmd_stack_t *stk;
size_t size;
+ stk = &sa->cmd_stack;
+ stk->nelems = cciss_tape_cmds + 2;
sa->cmd_sg_list = cciss_allocate_sg_chain_blocks(h,
- h->chainsize, CMD_STACK_SIZE);
+ h->chainsize, stk->nelems);
if (!sa->cmd_sg_list && h->chainsize > 0)
return -ENOMEM;
- stk = &sa->cmd_stack;
- size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
+ size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * stk->nelems;
/* Check alignment, see cciss_cmd.h near CommandList_struct def. */
BUILD_BUG_ON((sizeof(*stk->pool) % COMMANDLIST_ALIGNMENT) != 0);
@@ -221,18 +218,23 @@ scsi_cmd_stack_setup(ctlr_info_t *h, struct cciss_scsi_adapter_data_t *sa)
pci_alloc_consistent(h->pdev, size, &stk->cmd_pool_handle);
if (stk->pool == NULL) {
- cciss_free_sg_chain_blocks(sa->cmd_sg_list, CMD_STACK_SIZE);
+ cciss_free_sg_chain_blocks(sa->cmd_sg_list, stk->nelems);
sa->cmd_sg_list = NULL;
return -ENOMEM;
}
-
- for (i=0; i<CMD_STACK_SIZE; i++) {
+ stk->elem = kmalloc(sizeof(stk->elem[0]) * stk->nelems, GFP_KERNEL);
+ if (!stk->elem) {
+ pci_free_consistent(h->pdev, size, stk->pool,
+ stk->cmd_pool_handle);
+ return -1;
+ }
+ for (i = 0; i < stk->nelems; i++) {
stk->elem[i] = &stk->pool[i];
stk->elem[i]->busaddr = (__u32) (stk->cmd_pool_handle +
(sizeof(struct cciss_scsi_cmd_stack_elem_t) * i));
stk->elem[i]->cmdindex = i;
}
- stk->top = CMD_STACK_SIZE-1;
+ stk->top = stk->nelems-1;
return 0;
}
@@ -245,16 +247,18 @@ scsi_cmd_stack_free(ctlr_info_t *h)
sa = h->scsi_ctlr;
stk = &sa->cmd_stack;
- if (stk->top != CMD_STACK_SIZE-1) {
+ if (stk->top != stk->nelems-1) {
dev_warn(&h->pdev->dev,
"bug: %d scsi commands are still outstanding.\n",
- CMD_STACK_SIZE - stk->top);
+ stk->nelems - stk->top);
}
- size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE;
+ size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * stk->nelems;
pci_free_consistent(h->pdev, size, stk->pool, stk->cmd_pool_handle);
stk->pool = NULL;
- cciss_free_sg_chain_blocks(sa->cmd_sg_list, CMD_STACK_SIZE);
+ cciss_free_sg_chain_blocks(sa->cmd_sg_list, stk->nelems);
+ kfree(stk->elem);
+ stk->elem = NULL;
}
#if 0
@@ -859,6 +863,7 @@ cciss_scsi_detect(ctlr_info_t *h)
sh->io_port = 0; // good enough? FIXME,
sh->n_io_port = 0; // I don't think we use these two...
sh->this_id = SELF_SCSI_ID;
+ sh->can_queue = cciss_tape_cmds;
sh->sg_tablesize = h->maxsgentries;
sh->max_cmd_len = MAX_COMMAND_SIZE;
diff --git a/drivers/block/cciss_scsi.h b/drivers/block/cciss_scsi.h
index 6d5822fe851a..e71d986727ca 100644
--- a/drivers/block/cciss_scsi.h
+++ b/drivers/block/cciss_scsi.h
@@ -36,13 +36,9 @@
addressible natively, and may in fact turn
out to be not scsi at all. */
-#define SCSI_CCISS_CAN_QUEUE 2
/*
-Note, cmd_per_lun could give us some trouble, so I'm setting it very low.
-Likewise, SCSI_CCISS_CAN_QUEUE is set very conservatively.
-
If the upper scsi layer tries to track how many commands we have
outstanding, it will be operating under the misapprehension that it is
the only one sending us requests. We also have the block interface,
diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c
index c6828b68d77b..09ef9a878ef0 100644
--- a/drivers/block/drbd/drbd_actlog.c
+++ b/drivers/block/drbd/drbd_actlog.c
@@ -28,7 +28,7 @@
#include "drbd_int.h"
#include "drbd_wrappers.h"
-/* We maintain a trivial check sum in our on disk activity log.
+/* We maintain a trivial checksum in our on disk activity log.
* With that we can ensure correct operation even when the storage
* device might do a partial (last) sector write while losing power.
*/
diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c
index 76210ba401ac..f440a02dfdb1 100644
--- a/drivers/block/drbd/drbd_bitmap.c
+++ b/drivers/block/drbd/drbd_bitmap.c
@@ -74,7 +74,7 @@
* as we are "attached" to a local disk, which at 32 GiB for 1PiB storage
* seems excessive.
*
- * We plan to reduce the amount of in-core bitmap pages by pageing them in
+ * We plan to reduce the amount of in-core bitmap pages by paging them in
* and out against their on-disk location as necessary, but need to make
* sure we don't cause too much meta data IO, and must not deadlock in
* tight memory situations. This needs some more work.
@@ -200,7 +200,7 @@ void drbd_bm_unlock(struct drbd_conf *mdev)
* we if bits have been cleared since last IO. */
#define BM_PAGE_LAZY_WRITEOUT 28
-/* store_page_idx uses non-atomic assingment. It is only used directly after
+/* store_page_idx uses non-atomic assignment. It is only used directly after
* allocating the page. All other bm_set_page_* and bm_clear_page_* need to
* use atomic bit manipulation, as set_out_of_sync (and therefore bitmap
* changes) may happen from various contexts, and wait_on_bit/wake_up_bit
@@ -318,7 +318,7 @@ static void bm_unmap(unsigned long *p_addr)
/* word offset from start of bitmap to word number _in_page_
* modulo longs per page
#define MLPP(X) ((X) % (PAGE_SIZE/sizeof(long))
- hm, well, Philipp thinks gcc might not optimze the % into & (... - 1)
+ hm, well, Philipp thinks gcc might not optimize the % into & (... - 1)
so do it explicitly:
*/
#define MLPP(X) ((X) & ((PAGE_SIZE/sizeof(long))-1))
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
index b2699bb2e530..ef2ceed3be4b 100644
--- a/drivers/block/drbd/drbd_int.h
+++ b/drivers/block/drbd/drbd_int.h
@@ -42,6 +42,7 @@
#include <linux/genhd.h>
#include <net/tcp.h>
#include <linux/lru_cache.h>
+#include <linux/prefetch.h>
#ifdef __CHECKER__
# define __protected_by(x) __attribute__((require_context(x,1,999,"rdwr")))
@@ -699,7 +700,7 @@ struct drbd_request {
* see drbd_endio_pri(). */
struct bio *private_bio;
- struct hlist_node colision;
+ struct hlist_node collision;
sector_t sector;
unsigned int size;
unsigned int epoch; /* barrier_nr */
@@ -765,7 +766,7 @@ struct digest_info {
struct drbd_epoch_entry {
struct drbd_work w;
- struct hlist_node colision;
+ struct hlist_node collision;
struct drbd_epoch *epoch; /* for writes */
struct drbd_conf *mdev;
struct page *pages;
@@ -1128,6 +1129,8 @@ struct drbd_conf {
int rs_in_flight; /* resync sectors in flight (to proxy, in proxy and from proxy) */
int rs_planed; /* resync sectors already planned */
atomic_t ap_in_flight; /* App sectors in flight (waiting for ack) */
+ int peer_max_bio_size;
+ int local_max_bio_size;
};
static inline struct drbd_conf *minor_to_mdev(unsigned int minor)
@@ -1217,8 +1220,6 @@ extern void drbd_free_resources(struct drbd_conf *mdev);
extern void tl_release(struct drbd_conf *mdev, unsigned int barrier_nr,
unsigned int set_size);
extern void tl_clear(struct drbd_conf *mdev);
-enum drbd_req_event;
-extern void tl_restart(struct drbd_conf *mdev, enum drbd_req_event what);
extern void _tl_add_barrier(struct drbd_conf *, struct drbd_tl_epoch *);
extern void drbd_free_sock(struct drbd_conf *mdev);
extern int drbd_send(struct drbd_conf *mdev, struct socket *sock,
@@ -1433,6 +1434,7 @@ struct bm_extent {
* hash table. */
#define HT_SHIFT 8
#define DRBD_MAX_BIO_SIZE (1U<<(9+HT_SHIFT))
+#define DRBD_MAX_BIO_SIZE_SAFE (1 << 12) /* Works always = 4k */
#define DRBD_MAX_SIZE_H80_PACKET (1 << 15) /* The old header only allows packets up to 32Kib data */
@@ -1517,9 +1519,9 @@ extern void drbd_resume_io(struct drbd_conf *mdev);
extern char *ppsize(char *buf, unsigned long long size);
extern sector_t drbd_new_dev_size(struct drbd_conf *, struct drbd_backing_dev *, int);
enum determine_dev_size { dev_size_error = -1, unchanged = 0, shrunk = 1, grew = 2 };
-extern enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *, enum dds_flags) __must_hold(local);
+extern enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *, enum dds_flags) __must_hold(local);
extern void resync_after_online_grow(struct drbd_conf *);
-extern void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int) __must_hold(local);
+extern void drbd_reconsider_max_bio_size(struct drbd_conf *mdev);
extern enum drbd_state_rv drbd_set_role(struct drbd_conf *mdev,
enum drbd_role new_role,
int force);
@@ -1827,6 +1829,8 @@ static inline void __drbd_chk_io_error_(struct drbd_conf *mdev, int forcedetach,
if (!forcedetach) {
if (__ratelimit(&drbd_ratelimit_state))
dev_err(DEV, "Local IO failed in %s.\n", where);
+ if (mdev->state.disk > D_INCONSISTENT)
+ _drbd_set_state(_NS(mdev, disk, D_INCONSISTENT), CS_HARD, NULL);
break;
}
/* NOTE fall through to detach case if forcedetach set */
@@ -2152,6 +2156,10 @@ static inline int get_net_conf(struct drbd_conf *mdev)
static inline void put_ldev(struct drbd_conf *mdev)
{
int i = atomic_dec_return(&mdev->local_cnt);
+
+ /* This may be called from some endio handler,
+ * so we must not sleep here. */
+
__release(local);
D_ASSERT(i >= 0);
if (i == 0) {
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index 5b525c179f39..0358e55356c8 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -745,6 +745,9 @@ is_valid_state(struct drbd_conf *mdev, union drbd_state ns)
mdev->agreed_pro_version < 88)
rv = SS_NOT_SUPPORTED;
+ else if (ns.conn >= C_CONNECTED && ns.pdsk == D_UNKNOWN)
+ rv = SS_CONNECTED_OUTDATES;
+
return rv;
}
@@ -1565,6 +1568,10 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
put_ldev(mdev);
}
+ /* Notify peer that I had a local IO error, and did not detached.. */
+ if (os.disk == D_UP_TO_DATE && ns.disk == D_INCONSISTENT)
+ drbd_send_state(mdev);
+
/* Disks got bigger while they were detached */
if (ns.disk > D_NEGOTIATING && ns.pdsk > D_NEGOTIATING &&
test_and_clear_bit(RESYNC_AFTER_NEG, &mdev->flags)) {
@@ -2064,7 +2071,7 @@ int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags fl
{
struct p_sizes p;
sector_t d_size, u_size;
- int q_order_type;
+ int q_order_type, max_bio_size;
int ok;
if (get_ldev_if_state(mdev, D_NEGOTIATING)) {
@@ -2072,17 +2079,20 @@ int drbd_send_sizes(struct drbd_conf *mdev, int trigger_reply, enum dds_flags fl
d_size = drbd_get_max_capacity(mdev->ldev);
u_size = mdev->ldev->dc.disk_size;
q_order_type = drbd_queue_order_type(mdev);
+ max_bio_size = queue_max_hw_sectors(mdev->ldev->backing_bdev->bd_disk->queue) << 9;
+ max_bio_size = min_t(int, max_bio_size, DRBD_MAX_BIO_SIZE);
put_ldev(mdev);
} else {
d_size = 0;
u_size = 0;
q_order_type = QUEUE_ORDERED_NONE;
+ max_bio_size = DRBD_MAX_BIO_SIZE; /* ... multiple BIOs per peer_request */
}
p.d_size = cpu_to_be64(d_size);
p.u_size = cpu_to_be64(u_size);
p.c_size = cpu_to_be64(trigger_reply ? 0 : drbd_get_capacity(mdev->this_bdev));
- p.max_bio_size = cpu_to_be32(queue_max_hw_sectors(mdev->rq_queue) << 9);
+ p.max_bio_size = cpu_to_be32(max_bio_size);
p.queue_order_type = cpu_to_be16(q_order_type);
p.dds_flags = cpu_to_be16(flags);
@@ -2722,7 +2732,7 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req)
/* double check digest, sometimes buffers have been modified in flight. */
if (dgs > 0 && dgs <= 64) {
- /* 64 byte, 512 bit, is the larges digest size
+ /* 64 byte, 512 bit, is the largest digest size
* currently supported in kernel crypto. */
unsigned char digest[64];
drbd_csum_bio(mdev, mdev->integrity_w_tfm, req->master_bio, digest);
@@ -3041,6 +3051,8 @@ void drbd_init_set_defaults(struct drbd_conf *mdev)
mdev->agreed_pro_version = PRO_VERSION_MAX;
mdev->write_ordering = WO_bdev_flush;
mdev->resync_wenr = LC_FREE;
+ mdev->peer_max_bio_size = DRBD_MAX_BIO_SIZE_SAFE;
+ mdev->local_max_bio_size = DRBD_MAX_BIO_SIZE_SAFE;
}
void drbd_mdev_cleanup(struct drbd_conf *mdev)
@@ -3275,7 +3287,7 @@ static void drbd_delete_device(unsigned int minor)
drbd_release_ee_lists(mdev);
- /* should be free'd on disconnect? */
+ /* should be freed on disconnect? */
kfree(mdev->ee_hash);
/*
mdev->ee_hash_s = 0;
@@ -3415,7 +3427,9 @@ struct drbd_conf *drbd_new_device(unsigned int minor)
q->backing_dev_info.congested_data = mdev;
blk_queue_make_request(q, drbd_make_request);
- blk_queue_max_hw_sectors(q, DRBD_MAX_BIO_SIZE >> 9);
+ /* Setting the max_hw_sectors to an odd value of 8kibyte here
+ This triggers a max_bio_size message upon first attach or connect */
+ blk_queue_max_hw_sectors(q, DRBD_MAX_BIO_SIZE_SAFE >> 8);
blk_queue_bounce_limit(q, BLK_BOUNCE_ANY);
blk_queue_merge_bvec(q, drbd_merge_bvec);
q->queue_lock = &mdev->req_lock;
@@ -3627,7 +3641,8 @@ struct meta_data_on_disk {
/* `-- act_log->nr_elements <-- sync_conf.al_extents */
u32 bm_offset; /* offset to the bitmap, from here */
u32 bm_bytes_per_bit; /* BM_BLOCK_SIZE */
- u32 reserved_u32[4];
+ u32 la_peer_max_bio_size; /* last peer max_bio_size */
+ u32 reserved_u32[3];
} __packed;
@@ -3668,6 +3683,7 @@ void drbd_md_sync(struct drbd_conf *mdev)
buffer->device_uuid = cpu_to_be64(mdev->ldev->md.device_uuid);
buffer->bm_offset = cpu_to_be32(mdev->ldev->md.bm_offset);
+ buffer->la_peer_max_bio_size = cpu_to_be32(mdev->peer_max_bio_size);
D_ASSERT(drbd_md_ss__(mdev, mdev->ldev) == mdev->ldev->md.md_offset);
sector = mdev->ldev->md.md_offset;
@@ -3751,6 +3767,15 @@ int drbd_md_read(struct drbd_conf *mdev, struct drbd_backing_dev *bdev)
mdev->sync_conf.al_extents = be32_to_cpu(buffer->al_nr_extents);
bdev->md.device_uuid = be64_to_cpu(buffer->device_uuid);
+ spin_lock_irq(&mdev->req_lock);
+ if (mdev->state.conn < C_CONNECTED) {
+ int peer;
+ peer = be32_to_cpu(buffer->la_peer_max_bio_size);
+ peer = max_t(int, peer, DRBD_MAX_BIO_SIZE_SAFE);
+ mdev->peer_max_bio_size = peer;
+ }
+ spin_unlock_irq(&mdev->req_lock);
+
if (mdev->sync_conf.al_extents < 7)
mdev->sync_conf.al_extents = 127;
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c
index 03b29f78a37d..515bcd948a43 100644
--- a/drivers/block/drbd/drbd_nl.c
+++ b/drivers/block/drbd/drbd_nl.c
@@ -272,9 +272,28 @@ static int _try_outdate_peer_async(void *data)
{
struct drbd_conf *mdev = (struct drbd_conf *)data;
enum drbd_disk_state nps;
+ union drbd_state ns;
nps = drbd_try_outdate_peer(mdev);
- drbd_request_state(mdev, NS(pdsk, nps));
+
+ /* Not using
+ drbd_request_state(mdev, NS(pdsk, nps));
+ here, because we might were able to re-establish the connection
+ in the meantime. This can only partially be solved in the state's
+ engine is_valid_state() and is_valid_state_transition()
+ functions.
+
+ nps can be D_INCONSISTENT, D_OUTDATED or D_UNKNOWN.
+ pdsk == D_INCONSISTENT while conn >= C_CONNECTED is valid,
+ therefore we have to have the pre state change check here.
+ */
+ spin_lock_irq(&mdev->req_lock);
+ ns = mdev->state;
+ if (ns.conn < C_WF_REPORT_PARAMS) {
+ ns.pdsk = nps;
+ _drbd_set_state(mdev, ns, CS_VERBOSE, NULL);
+ }
+ spin_unlock_irq(&mdev->req_lock);
return 0;
}
@@ -577,7 +596,7 @@ void drbd_resume_io(struct drbd_conf *mdev)
* Returns 0 on success, negative return values indicate errors.
* You should call drbd_md_sync() after calling this function.
*/
-enum determine_dev_size drbd_determin_dev_size(struct drbd_conf *mdev, enum dds_flags flags) __must_hold(local)
+enum determine_dev_size drbd_determine_dev_size(struct drbd_conf *mdev, enum dds_flags flags) __must_hold(local)
{
sector_t prev_first_sect, prev_size; /* previous meta location */
sector_t la_size;
@@ -773,30 +792,78 @@ static int drbd_check_al_size(struct drbd_conf *mdev)
return 0;
}
-void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_bio_size) __must_hold(local)
+static void drbd_setup_queue_param(struct drbd_conf *mdev, unsigned int max_bio_size)
{
struct request_queue * const q = mdev->rq_queue;
- struct request_queue * const b = mdev->ldev->backing_bdev->bd_disk->queue;
- int max_segments = mdev->ldev->dc.max_bio_bvecs;
- int max_hw_sectors = min(queue_max_hw_sectors(b), max_bio_size >> 9);
+ int max_hw_sectors = max_bio_size >> 9;
+ int max_segments = 0;
+
+ if (get_ldev_if_state(mdev, D_ATTACHING)) {
+ struct request_queue * const b = mdev->ldev->backing_bdev->bd_disk->queue;
+
+ max_hw_sectors = min(queue_max_hw_sectors(b), max_bio_size >> 9);
+ max_segments = mdev->ldev->dc.max_bio_bvecs;
+ put_ldev(mdev);
+ }
blk_queue_logical_block_size(q, 512);
blk_queue_max_hw_sectors(q, max_hw_sectors);
/* This is the workaround for "bio would need to, but cannot, be split" */
blk_queue_max_segments(q, max_segments ? max_segments : BLK_MAX_SEGMENTS);
blk_queue_segment_boundary(q, PAGE_CACHE_SIZE-1);
- blk_queue_stack_limits(q, b);
- dev_info(DEV, "max BIO size = %u\n", queue_max_hw_sectors(q) << 9);
+ if (get_ldev_if_state(mdev, D_ATTACHING)) {
+ struct request_queue * const b = mdev->ldev->backing_bdev->bd_disk->queue;
+
+ blk_queue_stack_limits(q, b);
- if (q->backing_dev_info.ra_pages != b->backing_dev_info.ra_pages) {
- dev_info(DEV, "Adjusting my ra_pages to backing device's (%lu -> %lu)\n",
- q->backing_dev_info.ra_pages,
- b->backing_dev_info.ra_pages);
- q->backing_dev_info.ra_pages = b->backing_dev_info.ra_pages;
+ if (q->backing_dev_info.ra_pages != b->backing_dev_info.ra_pages) {
+ dev_info(DEV, "Adjusting my ra_pages to backing device's (%lu -> %lu)\n",
+ q->backing_dev_info.ra_pages,
+ b->backing_dev_info.ra_pages);
+ q->backing_dev_info.ra_pages = b->backing_dev_info.ra_pages;
+ }
+ put_ldev(mdev);
}
}
+void drbd_reconsider_max_bio_size(struct drbd_conf *mdev)
+{
+ int now, new, local, peer;
+
+ now = queue_max_hw_sectors(mdev->rq_queue) << 9;
+ local = mdev->local_max_bio_size; /* Eventually last known value, from volatile memory */
+ peer = mdev->peer_max_bio_size; /* Eventually last known value, from meta data */
+
+ if (get_ldev_if_state(mdev, D_ATTACHING)) {
+ local = queue_max_hw_sectors(mdev->ldev->backing_bdev->bd_disk->queue) << 9;
+ mdev->local_max_bio_size = local;
+ put_ldev(mdev);
+ }
+
+ /* We may ignore peer limits if the peer is modern enough.
+ Because new from 8.3.8 onwards the peer can use multiple
+ BIOs for a single peer_request */
+ if (mdev->state.conn >= C_CONNECTED) {
+ if (mdev->agreed_pro_version < 94)
+ peer = mdev->peer_max_bio_size;
+ else if (mdev->agreed_pro_version == 94)
+ peer = DRBD_MAX_SIZE_H80_PACKET;
+ else /* drbd 8.3.8 onwards */
+ peer = DRBD_MAX_BIO_SIZE;
+ }
+
+ new = min_t(int, local, peer);
+
+ if (mdev->state.role == R_PRIMARY && new < now)
+ dev_err(DEV, "ASSERT FAILED new < now; (%d < %d)\n", new, now);
+
+ if (new != now)
+ dev_info(DEV, "max BIO size = %u\n", new);
+
+ drbd_setup_queue_param(mdev, new);
+}
+
/* serialize deconfig (worker exiting, doing cleanup)
* and reconfig (drbdsetup disk, drbdsetup net)
*
@@ -865,7 +932,6 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
struct block_device *bdev;
struct lru_cache *resync_lru = NULL;
union drbd_state ns, os;
- unsigned int max_bio_size;
enum drbd_state_rv rv;
int cp_discovered = 0;
int logical_block_size;
@@ -1117,20 +1183,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
mdev->read_cnt = 0;
mdev->writ_cnt = 0;
- max_bio_size = DRBD_MAX_BIO_SIZE;
- if (mdev->state.conn == C_CONNECTED) {
- /* We are Primary, Connected, and now attach a new local
- * backing store. We must not increase the user visible maximum
- * bio size on this device to something the peer may not be
- * able to handle. */
- if (mdev->agreed_pro_version < 94)
- max_bio_size = queue_max_hw_sectors(mdev->rq_queue) << 9;
- else if (mdev->agreed_pro_version == 94)
- max_bio_size = DRBD_MAX_SIZE_H80_PACKET;
- /* else: drbd 8.3.9 and later, stay with default */
- }
-
- drbd_setup_queue_param(mdev, max_bio_size);
+ drbd_reconsider_max_bio_size(mdev);
/* If I am currently not R_PRIMARY,
* but meta data primary indicator is set,
@@ -1152,7 +1205,7 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
!drbd_md_test_flag(mdev->ldev, MDF_CONNECTED_IND))
set_bit(USE_DEGR_WFC_T, &mdev->flags);
- dd = drbd_determin_dev_size(mdev, 0);
+ dd = drbd_determine_dev_size(mdev, 0);
if (dd == dev_size_error) {
retcode = ERR_NOMEM_BITMAP;
goto force_diskless_dec;
@@ -1281,11 +1334,19 @@ static int drbd_nl_disk_conf(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp
static int drbd_nl_detach(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
struct drbd_nl_cfg_reply *reply)
{
+ enum drbd_ret_code retcode;
+ int ret;
drbd_suspend_io(mdev); /* so no-one is stuck in drbd_al_begin_io */
- reply->ret_code = drbd_request_state(mdev, NS(disk, D_DISKLESS));
- if (mdev->state.disk == D_DISKLESS)
- wait_event(mdev->misc_wait, !atomic_read(&mdev->local_cnt));
+ retcode = drbd_request_state(mdev, NS(disk, D_FAILED));
+ /* D_FAILED will transition to DISKLESS. */
+ ret = wait_event_interruptible(mdev->misc_wait,
+ mdev->state.disk != D_FAILED);
drbd_resume_io(mdev);
+ if ((int)retcode == (int)SS_IS_DISKLESS)
+ retcode = SS_NOTHING_TO_DO;
+ if (ret)
+ retcode = ERR_INTR;
+ reply->ret_code = retcode;
return 0;
}
@@ -1658,7 +1719,7 @@ static int drbd_nl_resize(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
mdev->ldev->dc.disk_size = (sector_t)rs.resize_size;
ddsf = (rs.resize_force ? DDSF_FORCED : 0) | (rs.no_resync ? DDSF_NO_RESYNC : 0);
- dd = drbd_determin_dev_size(mdev, ddsf);
+ dd = drbd_determine_dev_size(mdev, ddsf);
drbd_md_sync(mdev);
put_ldev(mdev);
if (dd == dev_size_error) {
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index fd26666c0b08..25d32c5aa50a 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -333,7 +333,7 @@ struct drbd_epoch_entry *drbd_alloc_ee(struct drbd_conf *mdev,
if (!page)
goto fail;
- INIT_HLIST_NODE(&e->colision);
+ INIT_HLIST_NODE(&e->collision);
e->epoch = NULL;
e->mdev = mdev;
e->pages = page;
@@ -356,7 +356,7 @@ void drbd_free_some_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e, int i
kfree(e->digest);
drbd_pp_free(mdev, e->pages, is_net);
D_ASSERT(atomic_read(&e->pending_bios) == 0);
- D_ASSERT(hlist_unhashed(&e->colision));
+ D_ASSERT(hlist_unhashed(&e->collision));
mempool_free(e, drbd_ee_mempool);
}
@@ -787,7 +787,7 @@ static int drbd_connect(struct drbd_conf *mdev)
}
if (sock && msock) {
- schedule_timeout_interruptible(HZ / 10);
+ schedule_timeout_interruptible(mdev->net_conf->ping_timeo*HZ/10);
ok = drbd_socket_okay(mdev, &sock);
ok = drbd_socket_okay(mdev, &msock) && ok;
if (ok)
@@ -899,11 +899,6 @@ retry:
drbd_thread_start(&mdev->asender);
- if (mdev->agreed_pro_version < 95 && get_ldev(mdev)) {
- drbd_setup_queue_param(mdev, DRBD_MAX_SIZE_H80_PACKET);
- put_ldev(mdev);
- }
-
if (drbd_send_protocol(mdev) == -1)
return -1;
drbd_send_sync_param(mdev, &mdev->sync_conf);
@@ -1418,7 +1413,7 @@ static int e_end_resync_block(struct drbd_conf *mdev, struct drbd_work *w, int u
sector_t sector = e->sector;
int ok;
- D_ASSERT(hlist_unhashed(&e->colision));
+ D_ASSERT(hlist_unhashed(&e->collision));
if (likely((e->flags & EE_WAS_ERROR) == 0)) {
drbd_set_in_sync(mdev, sector, e->size);
@@ -1487,7 +1482,7 @@ static int receive_DataReply(struct drbd_conf *mdev, enum drbd_packets cmd, unsi
return false;
}
- /* hlist_del(&req->colision) is done in _req_may_be_done, to avoid
+ /* hlist_del(&req->collision) is done in _req_may_be_done, to avoid
* special casing it there for the various failure cases.
* still no race with drbd_fail_pending_reads */
ok = recv_dless_read(mdev, req, sector, data_size);
@@ -1558,11 +1553,11 @@ static int e_end_block(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
* P_WRITE_ACK / P_NEG_ACK, to get the sequence number right. */
if (mdev->net_conf->two_primaries) {
spin_lock_irq(&mdev->req_lock);
- D_ASSERT(!hlist_unhashed(&e->colision));
- hlist_del_init(&e->colision);
+ D_ASSERT(!hlist_unhashed(&e->collision));
+ hlist_del_init(&e->collision);
spin_unlock_irq(&mdev->req_lock);
} else {
- D_ASSERT(hlist_unhashed(&e->colision));
+ D_ASSERT(hlist_unhashed(&e->collision));
}
drbd_may_finish_epoch(mdev, e->epoch, EV_PUT + (cancel ? EV_CLEANUP : 0));
@@ -1579,8 +1574,8 @@ static int e_send_discard_ack(struct drbd_conf *mdev, struct drbd_work *w, int u
ok = drbd_send_ack(mdev, P_DISCARD_ACK, e);
spin_lock_irq(&mdev->req_lock);
- D_ASSERT(!hlist_unhashed(&e->colision));
- hlist_del_init(&e->colision);
+ D_ASSERT(!hlist_unhashed(&e->collision));
+ hlist_del_init(&e->collision);
spin_unlock_irq(&mdev->req_lock);
dec_unacked(mdev);
@@ -1755,7 +1750,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
spin_lock_irq(&mdev->req_lock);
- hlist_add_head(&e->colision, ee_hash_slot(mdev, sector));
+ hlist_add_head(&e->collision, ee_hash_slot(mdev, sector));
#define OVERLAPS overlaps(i->sector, i->size, sector, size)
slot = tl_hash_slot(mdev, sector);
@@ -1765,7 +1760,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
int have_conflict = 0;
prepare_to_wait(&mdev->misc_wait, &wait,
TASK_INTERRUPTIBLE);
- hlist_for_each_entry(i, n, slot, colision) {
+ hlist_for_each_entry(i, n, slot, collision) {
if (OVERLAPS) {
/* only ALERT on first iteration,
* we may be woken up early... */
@@ -1804,7 +1799,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
}
if (signal_pending(current)) {
- hlist_del_init(&e->colision);
+ hlist_del_init(&e->collision);
spin_unlock_irq(&mdev->req_lock);
@@ -1862,7 +1857,7 @@ static int receive_Data(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
dev_err(DEV, "submit failed, triggering re-connect\n");
spin_lock_irq(&mdev->req_lock);
list_del(&e->w.list);
- hlist_del_init(&e->colision);
+ hlist_del_init(&e->collision);
spin_unlock_irq(&mdev->req_lock);
if (e->flags & EE_CALL_AL_COMPLETE_IO)
drbd_al_complete_io(mdev, e->sector);
@@ -2916,12 +2911,6 @@ disconnect:
return false;
}
-static void drbd_setup_order_type(struct drbd_conf *mdev, int peer)
-{
- /* sorry, we currently have no working implementation
- * of distributed TCQ */
-}
-
/* warn if the arguments differ by more than 12.5% */
static void warn_if_differ_considerably(struct drbd_conf *mdev,
const char *s, sector_t a, sector_t b)
@@ -2939,7 +2928,6 @@ static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
{
struct p_sizes *p = &mdev->data.rbuf.sizes;
enum determine_dev_size dd = unchanged;
- unsigned int max_bio_size;
sector_t p_size, p_usize, my_usize;
int ldsc = 0; /* local disk size changed */
enum dds_flags ddsf;
@@ -2994,7 +2982,7 @@ static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
ddsf = be16_to_cpu(p->dds_flags);
if (get_ldev(mdev)) {
- dd = drbd_determin_dev_size(mdev, ddsf);
+ dd = drbd_determine_dev_size(mdev, ddsf);
put_ldev(mdev);
if (dd == dev_size_error)
return false;
@@ -3004,23 +2992,15 @@ static int receive_sizes(struct drbd_conf *mdev, enum drbd_packets cmd, unsigned
drbd_set_my_capacity(mdev, p_size);
}
+ mdev->peer_max_bio_size = be32_to_cpu(p->max_bio_size);
+ drbd_reconsider_max_bio_size(mdev);
+
if (get_ldev(mdev)) {
if (mdev->ldev->known_size != drbd_get_capacity(mdev->ldev->backing_bdev)) {
mdev->ldev->known_size = drbd_get_capacity(mdev->ldev->backing_bdev);
ldsc = 1;
}
- if (mdev->agreed_pro_version < 94)
- max_bio_size = be32_to_cpu(p->max_bio_size);
- else if (mdev->agreed_pro_version == 94)
- max_bio_size = DRBD_MAX_SIZE_H80_PACKET;
- else /* drbd 8.3.8 onwards */
- max_bio_size = DRBD_MAX_BIO_SIZE;
-
- if (max_bio_size != queue_max_hw_sectors(mdev->rq_queue) << 9)
- drbd_setup_queue_param(mdev, max_bio_size);
-
- drbd_setup_order_type(mdev, be16_to_cpu(p->queue_order_type));
put_ldev(mdev);
}
@@ -4275,7 +4255,7 @@ static struct drbd_request *_ack_id_to_req(struct drbd_conf *mdev,
struct hlist_node *n;
struct drbd_request *req;
- hlist_for_each_entry(req, n, slot, colision) {
+ hlist_for_each_entry(req, n, slot, collision) {
if ((unsigned long)req == (unsigned long)id) {
if (req->sector != sector) {
dev_err(DEV, "_ack_id_to_req: found req %p but it has "
@@ -4554,6 +4534,7 @@ int drbd_asender(struct drbd_thread *thi)
int received = 0;
int expect = sizeof(struct p_header80);
int empty;
+ int ping_timeout_active = 0;
sprintf(current->comm, "drbd%d_asender", mdev_to_minor(mdev));
@@ -4566,6 +4547,7 @@ int drbd_asender(struct drbd_thread *thi)
ERR_IF(!drbd_send_ping(mdev)) goto reconnect;
mdev->meta.socket->sk->sk_rcvtimeo =
mdev->net_conf->ping_timeo*HZ/10;
+ ping_timeout_active = 1;
}
/* conditionally cork;
@@ -4620,8 +4602,7 @@ int drbd_asender(struct drbd_thread *thi)
dev_err(DEV, "meta connection shut down by peer.\n");
goto reconnect;
} else if (rv == -EAGAIN) {
- if (mdev->meta.socket->sk->sk_rcvtimeo ==
- mdev->net_conf->ping_timeo*HZ/10) {
+ if (ping_timeout_active) {
dev_err(DEV, "PingAck did not arrive in time.\n");
goto reconnect;
}
@@ -4660,6 +4641,11 @@ int drbd_asender(struct drbd_thread *thi)
if (!cmd->process(mdev, h))
goto reconnect;
+ /* the idle_timeout (ping-int)
+ * has been restored in got_PingAck() */
+ if (cmd == get_asender_cmd(P_PING_ACK))
+ ping_timeout_active = 0;
+
buf = h;
received = 0;
expect = sizeof(struct p_header80);
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c
index 5c0c8be1bb0a..3424d675b769 100644
--- a/drivers/block/drbd/drbd_req.c
+++ b/drivers/block/drbd/drbd_req.c
@@ -163,7 +163,7 @@ static void _about_to_complete_local_write(struct drbd_conf *mdev,
* they must have been failed on the spot */
#define OVERLAPS overlaps(sector, size, i->sector, i->size)
slot = tl_hash_slot(mdev, sector);
- hlist_for_each_entry(i, n, slot, colision) {
+ hlist_for_each_entry(i, n, slot, collision) {
if (OVERLAPS) {
dev_alert(DEV, "LOGIC BUG: completed: %p %llus +%u; "
"other: %p %llus +%u\n",
@@ -187,7 +187,7 @@ static void _about_to_complete_local_write(struct drbd_conf *mdev,
#undef OVERLAPS
#define OVERLAPS overlaps(sector, size, e->sector, e->size)
slot = ee_hash_slot(mdev, req->sector);
- hlist_for_each_entry(e, n, slot, colision) {
+ hlist_for_each_entry(e, n, slot, collision) {
if (OVERLAPS) {
wake_up(&mdev->misc_wait);
break;
@@ -260,8 +260,8 @@ void _req_may_be_done(struct drbd_request *req, struct bio_and_error *m)
/* remove the request from the conflict detection
* respective block_id verification hash */
- if (!hlist_unhashed(&req->colision))
- hlist_del(&req->colision);
+ if (!hlist_unhashed(&req->collision))
+ hlist_del(&req->collision);
else
D_ASSERT((s & (RQ_NET_MASK & ~RQ_NET_DONE)) == 0);
@@ -329,7 +329,7 @@ static int _req_conflicts(struct drbd_request *req)
struct hlist_node *n;
struct hlist_head *slot;
- D_ASSERT(hlist_unhashed(&req->colision));
+ D_ASSERT(hlist_unhashed(&req->collision));
if (!get_net_conf(mdev))
return 0;
@@ -341,7 +341,7 @@ static int _req_conflicts(struct drbd_request *req)
#define OVERLAPS overlaps(i->sector, i->size, sector, size)
slot = tl_hash_slot(mdev, sector);
- hlist_for_each_entry(i, n, slot, colision) {
+ hlist_for_each_entry(i, n, slot, collision) {
if (OVERLAPS) {
dev_alert(DEV, "%s[%u] Concurrent local write detected! "
"[DISCARD L] new: %llus +%u; "
@@ -359,7 +359,7 @@ static int _req_conflicts(struct drbd_request *req)
#undef OVERLAPS
#define OVERLAPS overlaps(e->sector, e->size, sector, size)
slot = ee_hash_slot(mdev, sector);
- hlist_for_each_entry(e, n, slot, colision) {
+ hlist_for_each_entry(e, n, slot, collision) {
if (OVERLAPS) {
dev_alert(DEV, "%s[%u] Concurrent remote write detected!"
" [DISCARD L] new: %llus +%u; "
@@ -491,7 +491,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
/* so we can verify the handle in the answer packet
* corresponding hlist_del is in _req_may_be_done() */
- hlist_add_head(&req->colision, ar_hash_slot(mdev, req->sector));
+ hlist_add_head(&req->collision, ar_hash_slot(mdev, req->sector));
set_bit(UNPLUG_REMOTE, &mdev->flags);
@@ -507,7 +507,7 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
/* assert something? */
/* from drbd_make_request_common only */
- hlist_add_head(&req->colision, tl_hash_slot(mdev, req->sector));
+ hlist_add_head(&req->collision, tl_hash_slot(mdev, req->sector));
/* corresponding hlist_del is in _req_may_be_done() */
/* NOTE
@@ -1033,7 +1033,7 @@ fail_conflicting:
err = 0;
fail_free_complete:
- if (rw == WRITE && local)
+ if (req->rq_state & RQ_IN_ACT_LOG)
drbd_al_complete_io(mdev, sector);
fail_and_free_req:
if (local) {
diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h
index 32e2c3e6a813..68a234a5fdc5 100644
--- a/drivers/block/drbd/drbd_req.h
+++ b/drivers/block/drbd/drbd_req.h
@@ -256,7 +256,7 @@ static inline struct drbd_request *_ar_id_to_req(struct drbd_conf *mdev,
struct hlist_node *n;
struct drbd_request *req;
- hlist_for_each_entry(req, n, slot, colision) {
+ hlist_for_each_entry(req, n, slot, collision) {
if ((unsigned long)req == (unsigned long)id) {
D_ASSERT(req->sector == sector);
return req;
@@ -291,7 +291,7 @@ static inline struct drbd_request *drbd_req_new(struct drbd_conf *mdev,
req->epoch = 0;
req->sector = bio_src->bi_sector;
req->size = bio_src->bi_size;
- INIT_HLIST_NODE(&req->colision);
+ INIT_HLIST_NODE(&req->collision);
INIT_LIST_HEAD(&req->tl_requests);
INIT_LIST_HEAD(&req->w.list);
}
@@ -323,6 +323,7 @@ extern int __req_mod(struct drbd_request *req, enum drbd_req_event what,
extern void complete_master_bio(struct drbd_conf *mdev,
struct bio_and_error *m);
extern void request_timer_fn(unsigned long data);
+extern void tl_restart(struct drbd_conf *mdev, enum drbd_req_event what);
/* use this if you don't want to deal with calling complete_master_bio()
* outside the spinlock, e.g. when walking some list on cleanup. */
diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c
index f7e6c92f8d03..4d76b06b6b20 100644
--- a/drivers/block/drbd/drbd_worker.c
+++ b/drivers/block/drbd/drbd_worker.c
@@ -126,7 +126,7 @@ static void drbd_endio_write_sec_final(struct drbd_epoch_entry *e) __releases(lo
list_del(&e->w.list); /* has been on active_ee or sync_ee */
list_add_tail(&e->w.list, &mdev->done_ee);
- /* No hlist_del_init(&e->colision) here, we did not send the Ack yet,
+ /* No hlist_del_init(&e->collision) here, we did not send the Ack yet,
* neither did we wake possibly waiting conflicting requests.
* done from "drbd_process_done_ee" within the appropriate w.cb
* (e_end_block/e_end_resync_block) or from _drbd_clear_done_ee */
@@ -297,42 +297,48 @@ void drbd_csum_bio(struct drbd_conf *mdev, struct crypto_hash *tfm, struct bio *
crypto_hash_final(&desc, digest);
}
-static int w_e_send_csum(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
+/* TODO merge common code with w_e_end_ov_req */
+int w_e_send_csum(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
{
struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w);
int digest_size;
void *digest;
- int ok;
+ int ok = 1;
D_ASSERT(e->block_id == DRBD_MAGIC + 0xbeef);
- if (unlikely(cancel)) {
- drbd_free_ee(mdev, e);
- return 1;
- }
+ if (unlikely(cancel))
+ goto out;
- if (likely((e->flags & EE_WAS_ERROR) == 0)) {
- digest_size = crypto_hash_digestsize(mdev->csums_tfm);
- digest = kmalloc(digest_size, GFP_NOIO);
- if (digest) {
- drbd_csum_ee(mdev, mdev->csums_tfm, e, digest);
+ if (likely((e->flags & EE_WAS_ERROR) != 0))
+ goto out;
- inc_rs_pending(mdev);
- ok = drbd_send_drequest_csum(mdev,
- e->sector,
- e->size,
- digest,
- digest_size,
- P_CSUM_RS_REQUEST);
- kfree(digest);
- } else {
- dev_err(DEV, "kmalloc() of digest failed.\n");
- ok = 0;
- }
- } else
- ok = 1;
+ digest_size = crypto_hash_digestsize(mdev->csums_tfm);
+ digest = kmalloc(digest_size, GFP_NOIO);
+ if (digest) {
+ sector_t sector = e->sector;
+ unsigned int size = e->size;
+ drbd_csum_ee(mdev, mdev->csums_tfm, e, digest);
+ /* Free e and pages before send.
+ * In case we block on congestion, we could otherwise run into
+ * some distributed deadlock, if the other side blocks on
+ * congestion as well, because our receiver blocks in
+ * drbd_pp_alloc due to pp_in_use > max_buffers. */
+ drbd_free_ee(mdev, e);
+ e = NULL;
+ inc_rs_pending(mdev);
+ ok = drbd_send_drequest_csum(mdev, sector, size,
+ digest, digest_size,
+ P_CSUM_RS_REQUEST);
+ kfree(digest);
+ } else {
+ dev_err(DEV, "kmalloc() of digest failed.\n");
+ ok = 0;
+ }
- drbd_free_ee(mdev, e);
+out:
+ if (e)
+ drbd_free_ee(mdev, e);
if (unlikely(!ok))
dev_err(DEV, "drbd_send_drequest(..., csum) failed\n");
@@ -834,7 +840,7 @@ int drbd_resync_finished(struct drbd_conf *mdev)
const int ratio =
(t == 0) ? 0 :
(t < 100000) ? ((s*100)/t) : (s/(t/100));
- dev_info(DEV, "%u %% had equal check sums, eliminated: %luK; "
+ dev_info(DEV, "%u %% had equal checksums, eliminated: %luK; "
"transferred %luK total %luK\n",
ratio,
Bit2KB(mdev->rs_same_csum),
@@ -1071,9 +1077,12 @@ int w_e_end_csum_rs_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
return ok;
}
+/* TODO merge common code with w_e_send_csum */
int w_e_end_ov_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
{
struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w);
+ sector_t sector = e->sector;
+ unsigned int size = e->size;
int digest_size;
void *digest;
int ok = 1;
@@ -1093,17 +1102,25 @@ int w_e_end_ov_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
else
memset(digest, 0, digest_size);
+ /* Free e and pages before send.
+ * In case we block on congestion, we could otherwise run into
+ * some distributed deadlock, if the other side blocks on
+ * congestion as well, because our receiver blocks in
+ * drbd_pp_alloc due to pp_in_use > max_buffers. */
+ drbd_free_ee(mdev, e);
+ e = NULL;
inc_rs_pending(mdev);
- ok = drbd_send_drequest_csum(mdev, e->sector, e->size,
- digest, digest_size, P_OV_REPLY);
+ ok = drbd_send_drequest_csum(mdev, sector, size,
+ digest, digest_size,
+ P_OV_REPLY);
if (!ok)
dec_rs_pending(mdev);
kfree(digest);
out:
- drbd_free_ee(mdev, e);
+ if (e)
+ drbd_free_ee(mdev, e);
dec_unacked(mdev);
-
return ok;
}
@@ -1122,8 +1139,10 @@ int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
{
struct drbd_epoch_entry *e = container_of(w, struct drbd_epoch_entry, w);
struct digest_info *di;
- int digest_size;
void *digest;
+ sector_t sector = e->sector;
+ unsigned int size = e->size;
+ int digest_size;
int ok, eq = 0;
if (unlikely(cancel)) {
@@ -1153,16 +1172,21 @@ int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
}
}
- dec_unacked(mdev);
+ /* Free e and pages before send.
+ * In case we block on congestion, we could otherwise run into
+ * some distributed deadlock, if the other side blocks on
+ * congestion as well, because our receiver blocks in
+ * drbd_pp_alloc due to pp_in_use > max_buffers. */
+ drbd_free_ee(mdev, e);
if (!eq)
- drbd_ov_oos_found(mdev, e->sector, e->size);
+ drbd_ov_oos_found(mdev, sector, size);
else
ov_oos_print(mdev);
- ok = drbd_send_ack_ex(mdev, P_OV_RESULT, e->sector, e->size,
+ ok = drbd_send_ack_ex(mdev, P_OV_RESULT, sector, size,
eq ? ID_IN_SYNC : ID_OUT_OF_SYNC);
- drbd_free_ee(mdev, e);
+ dec_unacked(mdev);
--mdev->ov_left;
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index a076a14ca72d..76c8da78212b 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -1540,9 +1540,9 @@ static const struct block_device_operations lo_fops = {
* And now the modules code and kernel interface.
*/
static int max_loop;
-module_param(max_loop, int, 0);
+module_param(max_loop, int, S_IRUGO);
MODULE_PARM_DESC(max_loop, "Maximum number of loop devices");
-module_param(max_part, int, 0);
+module_param(max_part, int, S_IRUGO);
MODULE_PARM_DESC(max_part, "Maximum number of partitions per loop device");
MODULE_LICENSE("GPL");
MODULE_ALIAS_BLOCKDEV_MAJOR(LOOP_MAJOR);
@@ -1658,7 +1658,7 @@ static struct kobject *loop_probe(dev_t dev, int *part, void *data)
struct kobject *kobj;
mutex_lock(&loop_devices_mutex);
- lo = loop_init_one(dev & MINORMASK);
+ lo = loop_init_one(MINOR(dev) >> part_shift);
kobj = lo ? get_disk(lo->lo_disk) : ERR_PTR(-ENOMEM);
mutex_unlock(&loop_devices_mutex);
@@ -1688,18 +1688,32 @@ static int __init loop_init(void)
*/
part_shift = 0;
- if (max_part > 0)
+ if (max_part > 0) {
part_shift = fls(max_part);
+ /*
+ * Adjust max_part according to part_shift as it is exported
+ * to user space so that user can decide correct minor number
+ * if [s]he want to create more devices.
+ *
+ * Note that -1 is required because partition 0 is reserved
+ * for the whole disk.
+ */
+ max_part = (1UL << part_shift) - 1;
+ }
+
+ if ((1UL << part_shift) > DISK_MAX_PARTS)
+ return -EINVAL;
+
if (max_loop > 1UL << (MINORBITS - part_shift))
return -EINVAL;
if (max_loop) {
nr = max_loop;
- range = max_loop;
+ range = max_loop << part_shift;
} else {
nr = 8;
- range = 1UL << (MINORBITS - part_shift);
+ range = 1UL << MINORBITS;
}
if (register_blkdev(LOOP_MAJOR, "loop"))
@@ -1738,7 +1752,7 @@ static void __exit loop_exit(void)
unsigned long range;
struct loop_device *lo, *next;
- range = max_loop ? max_loop : 1UL << (MINORBITS - part_shift);
+ range = max_loop ? max_loop << part_shift : 1UL << MINORBITS;
list_for_each_entry_safe(lo, next, &loop_devices, lo_list)
loop_del_one(lo);
diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c
index 8690e31d9932..a0aabd904a51 100644
--- a/drivers/block/paride/pcd.c
+++ b/drivers/block/paride/pcd.c
@@ -320,6 +320,8 @@ static void pcd_init_units(void)
disk->first_minor = unit;
strcpy(disk->disk_name, cd->name); /* umm... */
disk->fops = &pcd_bdops;
+ disk->flags = GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
+ disk->events = DISK_EVENT_MEDIA_CHANGE;
}
}
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 9712fad82bc6..1278098624e6 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -1191,14 +1191,19 @@ static int rbd_req_sync_notify_ack(struct rbd_device *dev,
static void rbd_watch_cb(u64 ver, u64 notify_id, u8 opcode, void *data)
{
struct rbd_device *dev = (struct rbd_device *)data;
+ int rc;
+
if (!dev)
return;
dout("rbd_watch_cb %s notify_id=%lld opcode=%d\n", dev->obj_md_name,
notify_id, (int)opcode);
mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
- __rbd_update_snaps(dev);
+ rc = __rbd_update_snaps(dev);
mutex_unlock(&ctl_mutex);
+ if (rc)
+ pr_warning(DRV_NAME "%d got notification but failed to update"
+ " snaps: %d\n", dev->major, rc);
rbd_req_sync_notify_ack(dev, ver, notify_id, dev->obj_md_name);
}
@@ -1597,7 +1602,7 @@ static int rbd_header_add_snap(struct rbd_device *dev,
int name_len = strlen(snap_name);
u64 new_snapid;
int ret;
- void *data, *data_start, *data_end;
+ void *data, *p, *e;
u64 ver;
/* we should create a snapshot only if we're pointing at the head */
@@ -1614,16 +1619,16 @@ static int rbd_header_add_snap(struct rbd_device *dev,
if (!data)
return -ENOMEM;
- data_start = data;
- data_end = data + name_len + 16;
+ p = data;
+ e = data + name_len + 16;
- ceph_encode_string_safe(&data, data_end, snap_name, name_len, bad);
- ceph_encode_64_safe(&data, data_end, new_snapid, bad);
+ ceph_encode_string_safe(&p, e, snap_name, name_len, bad);
+ ceph_encode_64_safe(&p, e, new_snapid, bad);
ret = rbd_req_sync_exec(dev, dev->obj_md_name, "rbd", "snap_add",
- data_start, data - data_start, &ver);
+ data, p - data, &ver);
- kfree(data_start);
+ kfree(data);
if (ret < 0)
return ret;
@@ -1659,6 +1664,9 @@ static int __rbd_update_snaps(struct rbd_device *rbd_dev)
if (ret < 0)
return ret;
+ /* resized? */
+ set_capacity(rbd_dev->disk, h.image_size / 512ULL);
+
down_write(&rbd_dev->header.snap_rwsem);
snap_seq = rbd_dev->header.snapc->seq;
@@ -1716,7 +1724,8 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
if (!disk)
goto out;
- sprintf(disk->disk_name, DRV_NAME "%d", rbd_dev->id);
+ snprintf(disk->disk_name, sizeof(disk->disk_name), DRV_NAME "%d",
+ rbd_dev->id);
disk->major = rbd_dev->major;
disk->first_minor = 0;
disk->fops = &rbd_bd_ops;
diff --git a/drivers/block/xen-blkback/Makefile b/drivers/block/xen-blkback/Makefile
new file mode 100644
index 000000000000..e491c1b76878
--- /dev/null
+++ b/drivers/block/xen-blkback/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_XEN_BLKDEV_BACKEND) := xen-blkback.o
+
+xen-blkback-y := blkback.o xenbus.o
diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c
new file mode 100644
index 000000000000..c73910cc28c9
--- /dev/null
+++ b/drivers/block/xen-blkback/blkback.c
@@ -0,0 +1,824 @@
+/******************************************************************************
+ *
+ * Back-end of the driver for virtual block devices. This portion of the
+ * driver exports a 'unified' block-device interface that can be accessed
+ * by any operating system that implements a compatible front end. A
+ * reference front-end implementation can be found in:
+ * drivers/block/xen-blkfront.c
+ *
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ * Copyright (c) 2005, Christopher Clark
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/kthread.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/freezer.h>
+
+#include <xen/events.h>
+#include <xen/page.h>
+#include <asm/xen/hypervisor.h>
+#include <asm/xen/hypercall.h>
+#include "common.h"
+
+/*
+ * These are rather arbitrary. They are fairly large because adjacent requests
+ * pulled from a communication ring are quite likely to end up being part of
+ * the same scatter/gather request at the disc.
+ *
+ * ** TRY INCREASING 'xen_blkif_reqs' IF WRITE SPEEDS SEEM TOO LOW **
+ *
+ * This will increase the chances of being able to write whole tracks.
+ * 64 should be enough to keep us competitive with Linux.
+ */
+static int xen_blkif_reqs = 64;
+module_param_named(reqs, xen_blkif_reqs, int, 0);
+MODULE_PARM_DESC(reqs, "Number of blkback requests to allocate");
+
+/* Run-time switchable: /sys/module/blkback/parameters/ */
+static unsigned int log_stats;
+module_param(log_stats, int, 0644);
+
+/*
+ * Each outstanding request that we've passed to the lower device layers has a
+ * 'pending_req' allocated to it. Each buffer_head that completes decrements
+ * the pendcnt towards zero. When it hits zero, the specified domain has a
+ * response queued for it, with the saved 'id' passed back.
+ */
+struct pending_req {
+ struct xen_blkif *blkif;
+ u64 id;
+ int nr_pages;
+ atomic_t pendcnt;
+ unsigned short operation;
+ int status;
+ struct list_head free_list;
+};
+
+#define BLKBACK_INVALID_HANDLE (~0)
+
+struct xen_blkbk {
+ struct pending_req *pending_reqs;
+ /* List of all 'pending_req' available */
+ struct list_head pending_free;
+ /* And its spinlock. */
+ spinlock_t pending_free_lock;
+ wait_queue_head_t pending_free_wq;
+ /* The list of all pages that are available. */
+ struct page **pending_pages;
+ /* And the grant handles that are available. */
+ grant_handle_t *pending_grant_handles;
+};
+
+static struct xen_blkbk *blkbk;
+
+/*
+ * Little helpful macro to figure out the index and virtual address of the
+ * pending_pages[..]. For each 'pending_req' we have have up to
+ * BLKIF_MAX_SEGMENTS_PER_REQUEST (11) pages. The seg would be from 0 through
+ * 10 and would index in the pending_pages[..].
+ */
+static inline int vaddr_pagenr(struct pending_req *req, int seg)
+{
+ return (req - blkbk->pending_reqs) *
+ BLKIF_MAX_SEGMENTS_PER_REQUEST + seg;
+}
+
+#define pending_page(req, seg) pending_pages[vaddr_pagenr(req, seg)]
+
+static inline unsigned long vaddr(struct pending_req *req, int seg)
+{
+ unsigned long pfn = page_to_pfn(blkbk->pending_page(req, seg));
+ return (unsigned long)pfn_to_kaddr(pfn);
+}
+
+#define pending_handle(_req, _seg) \
+ (blkbk->pending_grant_handles[vaddr_pagenr(_req, _seg)])
+
+
+static int do_block_io_op(struct xen_blkif *blkif);
+static int dispatch_rw_block_io(struct xen_blkif *blkif,
+ struct blkif_request *req,
+ struct pending_req *pending_req);
+static void make_response(struct xen_blkif *blkif, u64 id,
+ unsigned short op, int st);
+
+/*
+ * Retrieve from the 'pending_reqs' a free pending_req structure to be used.
+ */
+static struct pending_req *alloc_req(void)
+{
+ struct pending_req *req = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&blkbk->pending_free_lock, flags);
+ if (!list_empty(&blkbk->pending_free)) {
+ req = list_entry(blkbk->pending_free.next, struct pending_req,
+ free_list);
+ list_del(&req->free_list);
+ }
+ spin_unlock_irqrestore(&blkbk->pending_free_lock, flags);
+ return req;
+}
+
+/*
+ * Return the 'pending_req' structure back to the freepool. We also
+ * wake up the thread if it was waiting for a free page.
+ */
+static void free_req(struct pending_req *req)
+{
+ unsigned long flags;
+ int was_empty;
+
+ spin_lock_irqsave(&blkbk->pending_free_lock, flags);
+ was_empty = list_empty(&blkbk->pending_free);
+ list_add(&req->free_list, &blkbk->pending_free);
+ spin_unlock_irqrestore(&blkbk->pending_free_lock, flags);
+ if (was_empty)
+ wake_up(&blkbk->pending_free_wq);
+}
+
+/*
+ * Routines for managing virtual block devices (vbds).
+ */
+static int xen_vbd_translate(struct phys_req *req, struct xen_blkif *blkif,
+ int operation)
+{
+ struct xen_vbd *vbd = &blkif->vbd;
+ int rc = -EACCES;
+
+ if ((operation != READ) && vbd->readonly)
+ goto out;
+
+ if (likely(req->nr_sects)) {
+ blkif_sector_t end = req->sector_number + req->nr_sects;
+
+ if (unlikely(end < req->sector_number))
+ goto out;
+ if (unlikely(end > vbd_sz(vbd)))
+ goto out;
+ }
+
+ req->dev = vbd->pdevice;
+ req->bdev = vbd->bdev;
+ rc = 0;
+
+ out:
+ return rc;
+}
+
+static void xen_vbd_resize(struct xen_blkif *blkif)
+{
+ struct xen_vbd *vbd = &blkif->vbd;
+ struct xenbus_transaction xbt;
+ int err;
+ struct xenbus_device *dev = xen_blkbk_xenbus(blkif->be);
+ unsigned long long new_size = vbd_sz(vbd);
+
+ pr_info(DRV_PFX "VBD Resize: Domid: %d, Device: (%d, %d)\n",
+ blkif->domid, MAJOR(vbd->pdevice), MINOR(vbd->pdevice));
+ pr_info(DRV_PFX "VBD Resize: new size %llu\n", new_size);
+ vbd->size = new_size;
+again:
+ err = xenbus_transaction_start(&xbt);
+ if (err) {
+ pr_warn(DRV_PFX "Error starting transaction");
+ return;
+ }
+ err = xenbus_printf(xbt, dev->nodename, "sectors", "%llu",
+ (unsigned long long)vbd_sz(vbd));
+ if (err) {
+ pr_warn(DRV_PFX "Error writing new size");
+ goto abort;
+ }
+ /*
+ * Write the current state; we will use this to synchronize
+ * the front-end. If the current state is "connected" the
+ * front-end will get the new size information online.
+ */
+ err = xenbus_printf(xbt, dev->nodename, "state", "%d", dev->state);
+ if (err) {
+ pr_warn(DRV_PFX "Error writing the state");
+ goto abort;
+ }
+
+ err = xenbus_transaction_end(xbt, 0);
+ if (err == -EAGAIN)
+ goto again;
+ if (err)
+ pr_warn(DRV_PFX "Error ending transaction");
+ return;
+abort:
+ xenbus_transaction_end(xbt, 1);
+}
+
+/*
+ * Notification from the guest OS.
+ */
+static void blkif_notify_work(struct xen_blkif *blkif)
+{
+ blkif->waiting_reqs = 1;
+ wake_up(&blkif->wq);
+}
+
+irqreturn_t xen_blkif_be_int(int irq, void *dev_id)
+{
+ blkif_notify_work(dev_id);
+ return IRQ_HANDLED;
+}
+
+/*
+ * SCHEDULER FUNCTIONS
+ */
+
+static void print_stats(struct xen_blkif *blkif)
+{
+ pr_info("xen-blkback (%s): oo %3d | rd %4d | wr %4d | f %4d\n",
+ current->comm, blkif->st_oo_req,
+ blkif->st_rd_req, blkif->st_wr_req, blkif->st_f_req);
+ blkif->st_print = jiffies + msecs_to_jiffies(10 * 1000);
+ blkif->st_rd_req = 0;
+ blkif->st_wr_req = 0;
+ blkif->st_oo_req = 0;
+}
+
+int xen_blkif_schedule(void *arg)
+{
+ struct xen_blkif *blkif = arg;
+ struct xen_vbd *vbd = &blkif->vbd;
+
+ xen_blkif_get(blkif);
+
+ while (!kthread_should_stop()) {
+ if (try_to_freeze())
+ continue;
+ if (unlikely(vbd->size != vbd_sz(vbd)))
+ xen_vbd_resize(blkif);
+
+ wait_event_interruptible(
+ blkif->wq,
+ blkif->waiting_reqs || kthread_should_stop());
+ wait_event_interruptible(
+ blkbk->pending_free_wq,
+ !list_empty(&blkbk->pending_free) ||
+ kthread_should_stop());
+
+ blkif->waiting_reqs = 0;
+ smp_mb(); /* clear flag *before* checking for work */
+
+ if (do_block_io_op(blkif))
+ blkif->waiting_reqs = 1;
+
+ if (log_stats && time_after(jiffies, blkif->st_print))
+ print_stats(blkif);
+ }
+
+ if (log_stats)
+ print_stats(blkif);
+
+ blkif->xenblkd = NULL;
+ xen_blkif_put(blkif);
+
+ return 0;
+}
+
+struct seg_buf {
+ unsigned long buf;
+ unsigned int nsec;
+};
+/*
+ * Unmap the grant references, and also remove the M2P over-rides
+ * used in the 'pending_req'.
+ */
+static void xen_blkbk_unmap(struct pending_req *req)
+{
+ struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ unsigned int i, invcount = 0;
+ grant_handle_t handle;
+ int ret;
+
+ for (i = 0; i < req->nr_pages; i++) {
+ handle = pending_handle(req, i);
+ if (handle == BLKBACK_INVALID_HANDLE)
+ continue;
+ gnttab_set_unmap_op(&unmap[invcount], vaddr(req, i),
+ GNTMAP_host_map, handle);
+ pending_handle(req, i) = BLKBACK_INVALID_HANDLE;
+ invcount++;
+ }
+
+ ret = HYPERVISOR_grant_table_op(
+ GNTTABOP_unmap_grant_ref, unmap, invcount);
+ BUG_ON(ret);
+ /*
+ * Note, we use invcount, so nr->pages, so we can't index
+ * using vaddr(req, i).
+ */
+ for (i = 0; i < invcount; i++) {
+ ret = m2p_remove_override(
+ virt_to_page(unmap[i].host_addr), false);
+ if (ret) {
+ pr_alert(DRV_PFX "Failed to remove M2P override for %lx\n",
+ (unsigned long)unmap[i].host_addr);
+ continue;
+ }
+ }
+}
+
+static int xen_blkbk_map(struct blkif_request *req,
+ struct pending_req *pending_req,
+ struct seg_buf seg[])
+{
+ struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ int i;
+ int nseg = req->nr_segments;
+ int ret = 0;
+
+ /*
+ * Fill out preq.nr_sects with proper amount of sectors, and setup
+ * assign map[..] with the PFN of the page in our domain with the
+ * corresponding grant reference for each page.
+ */
+ for (i = 0; i < nseg; i++) {
+ uint32_t flags;
+
+ flags = GNTMAP_host_map;
+ if (pending_req->operation != BLKIF_OP_READ)
+ flags |= GNTMAP_readonly;
+ gnttab_set_map_op(&map[i], vaddr(pending_req, i), flags,
+ req->u.rw.seg[i].gref,
+ pending_req->blkif->domid);
+ }
+
+ ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, nseg);
+ BUG_ON(ret);
+
+ /*
+ * Now swizzle the MFN in our domain with the MFN from the other domain
+ * so that when we access vaddr(pending_req,i) it has the contents of
+ * the page from the other domain.
+ */
+ for (i = 0; i < nseg; i++) {
+ if (unlikely(map[i].status != 0)) {
+ pr_debug(DRV_PFX "invalid buffer -- could not remap it\n");
+ map[i].handle = BLKBACK_INVALID_HANDLE;
+ ret |= 1;
+ }
+
+ pending_handle(pending_req, i) = map[i].handle;
+
+ if (ret)
+ continue;
+
+ ret = m2p_add_override(PFN_DOWN(map[i].dev_bus_addr),
+ blkbk->pending_page(pending_req, i), false);
+ if (ret) {
+ pr_alert(DRV_PFX "Failed to install M2P override for %lx (ret: %d)\n",
+ (unsigned long)map[i].dev_bus_addr, ret);
+ /* We could switch over to GNTTABOP_copy */
+ continue;
+ }
+
+ seg[i].buf = map[i].dev_bus_addr |
+ (req->u.rw.seg[i].first_sect << 9);
+ }
+ return ret;
+}
+
+/*
+ * Completion callback on the bio's. Called as bh->b_end_io()
+ */
+
+static void __end_block_io_op(struct pending_req *pending_req, int error)
+{
+ /* An error fails the entire request. */
+ if ((pending_req->operation == BLKIF_OP_FLUSH_DISKCACHE) &&
+ (error == -EOPNOTSUPP)) {
+ pr_debug(DRV_PFX "flush diskcache op failed, not supported\n");
+ xen_blkbk_flush_diskcache(XBT_NIL, pending_req->blkif->be, 0);
+ pending_req->status = BLKIF_RSP_EOPNOTSUPP;
+ } else if (error) {
+ pr_debug(DRV_PFX "Buffer not up-to-date at end of operation,"
+ " error=%d\n", error);
+ pending_req->status = BLKIF_RSP_ERROR;
+ }
+
+ /*
+ * If all of the bio's have completed it is time to unmap
+ * the grant references associated with 'request' and provide
+ * the proper response on the ring.
+ */
+ if (atomic_dec_and_test(&pending_req->pendcnt)) {
+ xen_blkbk_unmap(pending_req);
+ make_response(pending_req->blkif, pending_req->id,
+ pending_req->operation, pending_req->status);
+ xen_blkif_put(pending_req->blkif);
+ free_req(pending_req);
+ }
+}
+
+/*
+ * bio callback.
+ */
+static void end_block_io_op(struct bio *bio, int error)
+{
+ __end_block_io_op(bio->bi_private, error);
+ bio_put(bio);
+}
+
+
+
+/*
+ * Function to copy the from the ring buffer the 'struct blkif_request'
+ * (which has the sectors we want, number of them, grant references, etc),
+ * and transmute it to the block API to hand it over to the proper block disk.
+ */
+static int do_block_io_op(struct xen_blkif *blkif)
+{
+ union blkif_back_rings *blk_rings = &blkif->blk_rings;
+ struct blkif_request req;
+ struct pending_req *pending_req;
+ RING_IDX rc, rp;
+ int more_to_do = 0;
+
+ rc = blk_rings->common.req_cons;
+ rp = blk_rings->common.sring->req_prod;
+ rmb(); /* Ensure we see queued requests up to 'rp'. */
+
+ while (rc != rp) {
+
+ if (RING_REQUEST_CONS_OVERFLOW(&blk_rings->common, rc))
+ break;
+
+ if (kthread_should_stop()) {
+ more_to_do = 1;
+ break;
+ }
+
+ pending_req = alloc_req();
+ if (NULL == pending_req) {
+ blkif->st_oo_req++;
+ more_to_do = 1;
+ break;
+ }
+
+ switch (blkif->blk_protocol) {
+ case BLKIF_PROTOCOL_NATIVE:
+ memcpy(&req, RING_GET_REQUEST(&blk_rings->native, rc), sizeof(req));
+ break;
+ case BLKIF_PROTOCOL_X86_32:
+ blkif_get_x86_32_req(&req, RING_GET_REQUEST(&blk_rings->x86_32, rc));
+ break;
+ case BLKIF_PROTOCOL_X86_64:
+ blkif_get_x86_64_req(&req, RING_GET_REQUEST(&blk_rings->x86_64, rc));
+ break;
+ default:
+ BUG();
+ }
+ blk_rings->common.req_cons = ++rc; /* before make_response() */
+
+ /* Apply all sanity checks to /private copy/ of request. */
+ barrier();
+
+ if (dispatch_rw_block_io(blkif, &req, pending_req))
+ break;
+
+ /* Yield point for this unbounded loop. */
+ cond_resched();
+ }
+
+ return more_to_do;
+}
+
+/*
+ * Transmutation of the 'struct blkif_request' to a proper 'struct bio'
+ * and call the 'submit_bio' to pass it to the underlying storage.
+ */
+static int dispatch_rw_block_io(struct xen_blkif *blkif,
+ struct blkif_request *req,
+ struct pending_req *pending_req)
+{
+ struct phys_req preq;
+ struct seg_buf seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ unsigned int nseg;
+ struct bio *bio = NULL;
+ struct bio *biolist[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ int i, nbio = 0;
+ int operation;
+ struct blk_plug plug;
+
+ switch (req->operation) {
+ case BLKIF_OP_READ:
+ blkif->st_rd_req++;
+ operation = READ;
+ break;
+ case BLKIF_OP_WRITE:
+ blkif->st_wr_req++;
+ operation = WRITE_ODIRECT;
+ break;
+ case BLKIF_OP_FLUSH_DISKCACHE:
+ blkif->st_f_req++;
+ operation = WRITE_FLUSH;
+ break;
+ case BLKIF_OP_WRITE_BARRIER:
+ default:
+ operation = 0; /* make gcc happy */
+ goto fail_response;
+ break;
+ }
+
+ /* Check that the number of segments is sane. */
+ nseg = req->nr_segments;
+ if (unlikely(nseg == 0 && operation != WRITE_FLUSH) ||
+ unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST)) {
+ pr_debug(DRV_PFX "Bad number of segments in request (%d)\n",
+ nseg);
+ /* Haven't submitted any bio's yet. */
+ goto fail_response;
+ }
+
+ preq.dev = req->handle;
+ preq.sector_number = req->u.rw.sector_number;
+ preq.nr_sects = 0;
+
+ pending_req->blkif = blkif;
+ pending_req->id = req->id;
+ pending_req->operation = req->operation;
+ pending_req->status = BLKIF_RSP_OKAY;
+ pending_req->nr_pages = nseg;
+
+ for (i = 0; i < nseg; i++) {
+ seg[i].nsec = req->u.rw.seg[i].last_sect -
+ req->u.rw.seg[i].first_sect + 1;
+ if ((req->u.rw.seg[i].last_sect >= (PAGE_SIZE >> 9)) ||
+ (req->u.rw.seg[i].last_sect < req->u.rw.seg[i].first_sect))
+ goto fail_response;
+ preq.nr_sects += seg[i].nsec;
+
+ }
+
+ if (xen_vbd_translate(&preq, blkif, operation) != 0) {
+ pr_debug(DRV_PFX "access denied: %s of [%llu,%llu] on dev=%04x\n",
+ operation == READ ? "read" : "write",
+ preq.sector_number,
+ preq.sector_number + preq.nr_sects, preq.dev);
+ goto fail_response;
+ }
+
+ /*
+ * This check _MUST_ be done after xen_vbd_translate as the preq.bdev
+ * is set there.
+ */
+ for (i = 0; i < nseg; i++) {
+ if (((int)preq.sector_number|(int)seg[i].nsec) &
+ ((bdev_logical_block_size(preq.bdev) >> 9) - 1)) {
+ pr_debug(DRV_PFX "Misaligned I/O request from domain %d",
+ blkif->domid);
+ goto fail_response;
+ }
+ }
+
+ /*
+ * If we have failed at this point, we need to undo the M2P override,
+ * set gnttab_set_unmap_op on all of the grant references and perform
+ * the hypercall to unmap the grants - that is all done in
+ * xen_blkbk_unmap.
+ */
+ if (xen_blkbk_map(req, pending_req, seg))
+ goto fail_flush;
+
+ /* This corresponding xen_blkif_put is done in __end_block_io_op */
+ xen_blkif_get(blkif);
+
+ for (i = 0; i < nseg; i++) {
+ while ((bio == NULL) ||
+ (bio_add_page(bio,
+ blkbk->pending_page(pending_req, i),
+ seg[i].nsec << 9,
+ seg[i].buf & ~PAGE_MASK) == 0)) {
+
+ bio = bio_alloc(GFP_KERNEL, nseg-i);
+ if (unlikely(bio == NULL))
+ goto fail_put_bio;
+
+ biolist[nbio++] = bio;
+ bio->bi_bdev = preq.bdev;
+ bio->bi_private = pending_req;
+ bio->bi_end_io = end_block_io_op;
+ bio->bi_sector = preq.sector_number;
+ }
+
+ preq.sector_number += seg[i].nsec;
+ }
+
+ /* This will be hit if the operation was a flush. */
+ if (!bio) {
+ BUG_ON(operation != WRITE_FLUSH);
+
+ bio = bio_alloc(GFP_KERNEL, 0);
+ if (unlikely(bio == NULL))
+ goto fail_put_bio;
+
+ biolist[nbio++] = bio;
+ bio->bi_bdev = preq.bdev;
+ bio->bi_private = pending_req;
+ bio->bi_end_io = end_block_io_op;
+ }
+
+ /*
+ * We set it one so that the last submit_bio does not have to call
+ * atomic_inc.
+ */
+ atomic_set(&pending_req->pendcnt, nbio);
+
+ /* Get a reference count for the disk queue and start sending I/O */
+ blk_start_plug(&plug);
+
+ for (i = 0; i < nbio; i++)
+ submit_bio(operation, biolist[i]);
+
+ /* Let the I/Os go.. */
+ blk_finish_plug(&plug);
+
+ if (operation == READ)
+ blkif->st_rd_sect += preq.nr_sects;
+ else if (operation == WRITE || operation == WRITE_FLUSH)
+ blkif->st_wr_sect += preq.nr_sects;
+
+ return 0;
+
+ fail_flush:
+ xen_blkbk_unmap(pending_req);
+ fail_response:
+ /* Haven't submitted any bio's yet. */
+ make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR);
+ free_req(pending_req);
+ msleep(1); /* back off a bit */
+ return -EIO;
+
+ fail_put_bio:
+ for (i = 0; i < nbio; i++)
+ bio_put(biolist[i]);
+ __end_block_io_op(pending_req, -EINVAL);
+ msleep(1); /* back off a bit */
+ return -EIO;
+}
+
+
+
+/*
+ * Put a response on the ring on how the operation fared.
+ */
+static void make_response(struct xen_blkif *blkif, u64 id,
+ unsigned short op, int st)
+{
+ struct blkif_response resp;
+ unsigned long flags;
+ union blkif_back_rings *blk_rings = &blkif->blk_rings;
+ int more_to_do = 0;
+ int notify;
+
+ resp.id = id;
+ resp.operation = op;
+ resp.status = st;
+
+ spin_lock_irqsave(&blkif->blk_ring_lock, flags);
+ /* Place on the response ring for the relevant domain. */
+ switch (blkif->blk_protocol) {
+ case BLKIF_PROTOCOL_NATIVE:
+ memcpy(RING_GET_RESPONSE(&blk_rings->native, blk_rings->native.rsp_prod_pvt),
+ &resp, sizeof(resp));
+ break;
+ case BLKIF_PROTOCOL_X86_32:
+ memcpy(RING_GET_RESPONSE(&blk_rings->x86_32, blk_rings->x86_32.rsp_prod_pvt),
+ &resp, sizeof(resp));
+ break;
+ case BLKIF_PROTOCOL_X86_64:
+ memcpy(RING_GET_RESPONSE(&blk_rings->x86_64, blk_rings->x86_64.rsp_prod_pvt),
+ &resp, sizeof(resp));
+ break;
+ default:
+ BUG();
+ }
+ blk_rings->common.rsp_prod_pvt++;
+ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&blk_rings->common, notify);
+ if (blk_rings->common.rsp_prod_pvt == blk_rings->common.req_cons) {
+ /*
+ * Tail check for pending requests. Allows frontend to avoid
+ * notifications if requests are already in flight (lower
+ * overheads and promotes batching).
+ */
+ RING_FINAL_CHECK_FOR_REQUESTS(&blk_rings->common, more_to_do);
+
+ } else if (RING_HAS_UNCONSUMED_REQUESTS(&blk_rings->common)) {
+ more_to_do = 1;
+ }
+
+ spin_unlock_irqrestore(&blkif->blk_ring_lock, flags);
+
+ if (more_to_do)
+ blkif_notify_work(blkif);
+ if (notify)
+ notify_remote_via_irq(blkif->irq);
+}
+
+static int __init xen_blkif_init(void)
+{
+ int i, mmap_pages;
+ int rc = 0;
+
+ if (!xen_pv_domain())
+ return -ENODEV;
+
+ blkbk = kzalloc(sizeof(struct xen_blkbk), GFP_KERNEL);
+ if (!blkbk) {
+ pr_alert(DRV_PFX "%s: out of memory!\n", __func__);
+ return -ENOMEM;
+ }
+
+ mmap_pages = xen_blkif_reqs * BLKIF_MAX_SEGMENTS_PER_REQUEST;
+
+ blkbk->pending_reqs = kmalloc(sizeof(blkbk->pending_reqs[0]) *
+ xen_blkif_reqs, GFP_KERNEL);
+ blkbk->pending_grant_handles = kzalloc(sizeof(blkbk->pending_grant_handles[0]) *
+ mmap_pages, GFP_KERNEL);
+ blkbk->pending_pages = kzalloc(sizeof(blkbk->pending_pages[0]) *
+ mmap_pages, GFP_KERNEL);
+
+ if (!blkbk->pending_reqs || !blkbk->pending_grant_handles ||
+ !blkbk->pending_pages) {
+ rc = -ENOMEM;
+ goto out_of_memory;
+ }
+
+ for (i = 0; i < mmap_pages; i++) {
+ blkbk->pending_grant_handles[i] = BLKBACK_INVALID_HANDLE;
+ blkbk->pending_pages[i] = alloc_page(GFP_KERNEL);
+ if (blkbk->pending_pages[i] == NULL) {
+ rc = -ENOMEM;
+ goto out_of_memory;
+ }
+ }
+ rc = xen_blkif_interface_init();
+ if (rc)
+ goto failed_init;
+
+ memset(blkbk->pending_reqs, 0, sizeof(blkbk->pending_reqs));
+
+ INIT_LIST_HEAD(&blkbk->pending_free);
+ spin_lock_init(&blkbk->pending_free_lock);
+ init_waitqueue_head(&blkbk->pending_free_wq);
+
+ for (i = 0; i < xen_blkif_reqs; i++)
+ list_add_tail(&blkbk->pending_reqs[i].free_list,
+ &blkbk->pending_free);
+
+ rc = xen_blkif_xenbus_init();
+ if (rc)
+ goto failed_init;
+
+ return 0;
+
+ out_of_memory:
+ pr_alert(DRV_PFX "%s: out of memory\n", __func__);
+ failed_init:
+ kfree(blkbk->pending_reqs);
+ kfree(blkbk->pending_grant_handles);
+ for (i = 0; i < mmap_pages; i++) {
+ if (blkbk->pending_pages[i])
+ __free_page(blkbk->pending_pages[i]);
+ }
+ kfree(blkbk->pending_pages);
+ kfree(blkbk);
+ blkbk = NULL;
+ return rc;
+}
+
+module_init(xen_blkif_init);
+
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h
new file mode 100644
index 000000000000..9e40b283a468
--- /dev/null
+++ b/drivers/block/xen-blkback/common.h
@@ -0,0 +1,233 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __XEN_BLKIF__BACKEND__COMMON_H__
+#define __XEN_BLKIF__BACKEND__COMMON_H__
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+#include <linux/io.h>
+#include <asm/setup.h>
+#include <asm/pgalloc.h>
+#include <asm/hypervisor.h>
+#include <xen/grant_table.h>
+#include <xen/xenbus.h>
+#include <xen/interface/io/ring.h>
+#include <xen/interface/io/blkif.h>
+#include <xen/interface/io/protocols.h>
+
+#define DRV_PFX "xen-blkback:"
+#define DPRINTK(fmt, args...) \
+ pr_debug(DRV_PFX "(%s:%d) " fmt ".\n", \
+ __func__, __LINE__, ##args)
+
+
+/* Not a real protocol. Used to generate ring structs which contain
+ * the elements common to all protocols only. This way we get a
+ * compiler-checkable way to use common struct elements, so we can
+ * avoid using switch(protocol) in a number of places. */
+struct blkif_common_request {
+ char dummy;
+};
+struct blkif_common_response {
+ char dummy;
+};
+
+/* i386 protocol version */
+#pragma pack(push, 4)
+struct blkif_x86_32_request {
+ uint8_t operation; /* BLKIF_OP_??? */
+ uint8_t nr_segments; /* number of segments */
+ blkif_vdev_t handle; /* only for read/write requests */
+ uint64_t id; /* private guest value, echoed in resp */
+ blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */
+ struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+};
+struct blkif_x86_32_response {
+ uint64_t id; /* copied from request */
+ uint8_t operation; /* copied from request */
+ int16_t status; /* BLKIF_RSP_??? */
+};
+#pragma pack(pop)
+
+/* x86_64 protocol version */
+struct blkif_x86_64_request {
+ uint8_t operation; /* BLKIF_OP_??? */
+ uint8_t nr_segments; /* number of segments */
+ blkif_vdev_t handle; /* only for read/write requests */
+ uint64_t __attribute__((__aligned__(8))) id;
+ blkif_sector_t sector_number;/* start sector idx on disk (r/w only) */
+ struct blkif_request_segment seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+};
+struct blkif_x86_64_response {
+ uint64_t __attribute__((__aligned__(8))) id;
+ uint8_t operation; /* copied from request */
+ int16_t status; /* BLKIF_RSP_??? */
+};
+
+DEFINE_RING_TYPES(blkif_common, struct blkif_common_request,
+ struct blkif_common_response);
+DEFINE_RING_TYPES(blkif_x86_32, struct blkif_x86_32_request,
+ struct blkif_x86_32_response);
+DEFINE_RING_TYPES(blkif_x86_64, struct blkif_x86_64_request,
+ struct blkif_x86_64_response);
+
+union blkif_back_rings {
+ struct blkif_back_ring native;
+ struct blkif_common_back_ring common;
+ struct blkif_x86_32_back_ring x86_32;
+ struct blkif_x86_64_back_ring x86_64;
+};
+
+enum blkif_protocol {
+ BLKIF_PROTOCOL_NATIVE = 1,
+ BLKIF_PROTOCOL_X86_32 = 2,
+ BLKIF_PROTOCOL_X86_64 = 3,
+};
+
+struct xen_vbd {
+ /* What the domain refers to this vbd as. */
+ blkif_vdev_t handle;
+ /* Non-zero -> read-only */
+ unsigned char readonly;
+ /* VDISK_xxx */
+ unsigned char type;
+ /* phys device that this vbd maps to. */
+ u32 pdevice;
+ struct block_device *bdev;
+ /* Cached size parameter. */
+ sector_t size;
+ bool flush_support;
+};
+
+struct backend_info;
+
+struct xen_blkif {
+ /* Unique identifier for this interface. */
+ domid_t domid;
+ unsigned int handle;
+ /* Physical parameters of the comms window. */
+ unsigned int irq;
+ /* Comms information. */
+ enum blkif_protocol blk_protocol;
+ union blkif_back_rings blk_rings;
+ struct vm_struct *blk_ring_area;
+ /* The VBD attached to this interface. */
+ struct xen_vbd vbd;
+ /* Back pointer to the backend_info. */
+ struct backend_info *be;
+ /* Private fields. */
+ spinlock_t blk_ring_lock;
+ atomic_t refcnt;
+
+ wait_queue_head_t wq;
+ /* One thread per one blkif. */
+ struct task_struct *xenblkd;
+ unsigned int waiting_reqs;
+
+ /* statistics */
+ unsigned long st_print;
+ int st_rd_req;
+ int st_wr_req;
+ int st_oo_req;
+ int st_f_req;
+ int st_rd_sect;
+ int st_wr_sect;
+
+ wait_queue_head_t waiting_to_free;
+
+ grant_handle_t shmem_handle;
+ grant_ref_t shmem_ref;
+};
+
+
+#define vbd_sz(_v) ((_v)->bdev->bd_part ? \
+ (_v)->bdev->bd_part->nr_sects : \
+ get_capacity((_v)->bdev->bd_disk))
+
+#define xen_blkif_get(_b) (atomic_inc(&(_b)->refcnt))
+#define xen_blkif_put(_b) \
+ do { \
+ if (atomic_dec_and_test(&(_b)->refcnt)) \
+ wake_up(&(_b)->waiting_to_free);\
+ } while (0)
+
+struct phys_req {
+ unsigned short dev;
+ unsigned short nr_sects;
+ struct block_device *bdev;
+ blkif_sector_t sector_number;
+};
+int xen_blkif_interface_init(void);
+
+int xen_blkif_xenbus_init(void);
+
+irqreturn_t xen_blkif_be_int(int irq, void *dev_id);
+int xen_blkif_schedule(void *arg);
+
+int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt,
+ struct backend_info *be, int state);
+
+struct xenbus_device *xen_blkbk_xenbus(struct backend_info *be);
+
+static inline void blkif_get_x86_32_req(struct blkif_request *dst,
+ struct blkif_x86_32_request *src)
+{
+ int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
+ dst->operation = src->operation;
+ dst->nr_segments = src->nr_segments;
+ dst->handle = src->handle;
+ dst->id = src->id;
+ dst->u.rw.sector_number = src->sector_number;
+ barrier();
+ if (n > dst->nr_segments)
+ n = dst->nr_segments;
+ for (i = 0; i < n; i++)
+ dst->u.rw.seg[i] = src->seg[i];
+}
+
+static inline void blkif_get_x86_64_req(struct blkif_request *dst,
+ struct blkif_x86_64_request *src)
+{
+ int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST;
+ dst->operation = src->operation;
+ dst->nr_segments = src->nr_segments;
+ dst->handle = src->handle;
+ dst->id = src->id;
+ dst->u.rw.sector_number = src->sector_number;
+ barrier();
+ if (n > dst->nr_segments)
+ n = dst->nr_segments;
+ for (i = 0; i < n; i++)
+ dst->u.rw.seg[i] = src->seg[i];
+}
+
+#endif /* __XEN_BLKIF__BACKEND__COMMON_H__ */
diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c
new file mode 100644
index 000000000000..34570823355b
--- /dev/null
+++ b/drivers/block/xen-blkback/xenbus.c
@@ -0,0 +1,768 @@
+/* Xenbus code for blkif backend
+ Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
+ Copyright (C) 2005 XenSource Ltd
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+*/
+
+#include <stdarg.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <xen/events.h>
+#include <xen/grant_table.h>
+#include "common.h"
+
+struct backend_info {
+ struct xenbus_device *dev;
+ struct xen_blkif *blkif;
+ struct xenbus_watch backend_watch;
+ unsigned major;
+ unsigned minor;
+ char *mode;
+};
+
+static struct kmem_cache *xen_blkif_cachep;
+static void connect(struct backend_info *);
+static int connect_ring(struct backend_info *);
+static void backend_changed(struct xenbus_watch *, const char **,
+ unsigned int);
+
+struct xenbus_device *xen_blkbk_xenbus(struct backend_info *be)
+{
+ return be->dev;
+}
+
+static int blkback_name(struct xen_blkif *blkif, char *buf)
+{
+ char *devpath, *devname;
+ struct xenbus_device *dev = blkif->be->dev;
+
+ devpath = xenbus_read(XBT_NIL, dev->nodename, "dev", NULL);
+ if (IS_ERR(devpath))
+ return PTR_ERR(devpath);
+
+ devname = strstr(devpath, "/dev/");
+ if (devname != NULL)
+ devname += strlen("/dev/");
+ else
+ devname = devpath;
+
+ snprintf(buf, TASK_COMM_LEN, "blkback.%d.%s", blkif->domid, devname);
+ kfree(devpath);
+
+ return 0;
+}
+
+static void xen_update_blkif_status(struct xen_blkif *blkif)
+{
+ int err;
+ char name[TASK_COMM_LEN];
+
+ /* Not ready to connect? */
+ if (!blkif->irq || !blkif->vbd.bdev)
+ return;
+
+ /* Already connected? */
+ if (blkif->be->dev->state == XenbusStateConnected)
+ return;
+
+ /* Attempt to connect: exit if we fail to. */
+ connect(blkif->be);
+ if (blkif->be->dev->state != XenbusStateConnected)
+ return;
+
+ err = blkback_name(blkif, name);
+ if (err) {
+ xenbus_dev_error(blkif->be->dev, err, "get blkback dev name");
+ return;
+ }
+
+ err = filemap_write_and_wait(blkif->vbd.bdev->bd_inode->i_mapping);
+ if (err) {
+ xenbus_dev_error(blkif->be->dev, err, "block flush");
+ return;
+ }
+ invalidate_inode_pages2(blkif->vbd.bdev->bd_inode->i_mapping);
+
+ blkif->xenblkd = kthread_run(xen_blkif_schedule, blkif, name);
+ if (IS_ERR(blkif->xenblkd)) {
+ err = PTR_ERR(blkif->xenblkd);
+ blkif->xenblkd = NULL;
+ xenbus_dev_error(blkif->be->dev, err, "start xenblkd");
+ }
+}
+
+static struct xen_blkif *xen_blkif_alloc(domid_t domid)
+{
+ struct xen_blkif *blkif;
+
+ blkif = kmem_cache_alloc(xen_blkif_cachep, GFP_KERNEL);
+ if (!blkif)
+ return ERR_PTR(-ENOMEM);
+
+ memset(blkif, 0, sizeof(*blkif));
+ blkif->domid = domid;
+ spin_lock_init(&blkif->blk_ring_lock);
+ atomic_set(&blkif->refcnt, 1);
+ init_waitqueue_head(&blkif->wq);
+ blkif->st_print = jiffies;
+ init_waitqueue_head(&blkif->waiting_to_free);
+
+ return blkif;
+}
+
+static int map_frontend_page(struct xen_blkif *blkif, unsigned long shared_page)
+{
+ struct gnttab_map_grant_ref op;
+
+ gnttab_set_map_op(&op, (unsigned long)blkif->blk_ring_area->addr,
+ GNTMAP_host_map, shared_page, blkif->domid);
+
+ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
+ BUG();
+
+ if (op.status) {
+ DPRINTK("Grant table operation failure !\n");
+ return op.status;
+ }
+
+ blkif->shmem_ref = shared_page;
+ blkif->shmem_handle = op.handle;
+
+ return 0;
+}
+
+static void unmap_frontend_page(struct xen_blkif *blkif)
+{
+ struct gnttab_unmap_grant_ref op;
+
+ gnttab_set_unmap_op(&op, (unsigned long)blkif->blk_ring_area->addr,
+ GNTMAP_host_map, blkif->shmem_handle);
+
+ if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
+ BUG();
+}
+
+static int xen_blkif_map(struct xen_blkif *blkif, unsigned long shared_page,
+ unsigned int evtchn)
+{
+ int err;
+
+ /* Already connected through? */
+ if (blkif->irq)
+ return 0;
+
+ blkif->blk_ring_area = alloc_vm_area(PAGE_SIZE);
+ if (!blkif->blk_ring_area)
+ return -ENOMEM;
+
+ err = map_frontend_page(blkif, shared_page);
+ if (err) {
+ free_vm_area(blkif->blk_ring_area);
+ return err;
+ }
+
+ switch (blkif->blk_protocol) {
+ case BLKIF_PROTOCOL_NATIVE:
+ {
+ struct blkif_sring *sring;
+ sring = (struct blkif_sring *)blkif->blk_ring_area->addr;
+ BACK_RING_INIT(&blkif->blk_rings.native, sring, PAGE_SIZE);
+ break;
+ }
+ case BLKIF_PROTOCOL_X86_32:
+ {
+ struct blkif_x86_32_sring *sring_x86_32;
+ sring_x86_32 = (struct blkif_x86_32_sring *)blkif->blk_ring_area->addr;
+ BACK_RING_INIT(&blkif->blk_rings.x86_32, sring_x86_32, PAGE_SIZE);
+ break;
+ }
+ case BLKIF_PROTOCOL_X86_64:
+ {
+ struct blkif_x86_64_sring *sring_x86_64;
+ sring_x86_64 = (struct blkif_x86_64_sring *)blkif->blk_ring_area->addr;
+ BACK_RING_INIT(&blkif->blk_rings.x86_64, sring_x86_64, PAGE_SIZE);
+ break;
+ }
+ default:
+ BUG();
+ }
+
+ err = bind_interdomain_evtchn_to_irqhandler(blkif->domid, evtchn,
+ xen_blkif_be_int, 0,
+ "blkif-backend", blkif);
+ if (err < 0) {
+ unmap_frontend_page(blkif);
+ free_vm_area(blkif->blk_ring_area);
+ blkif->blk_rings.common.sring = NULL;
+ return err;
+ }
+ blkif->irq = err;
+
+ return 0;
+}
+
+static void xen_blkif_disconnect(struct xen_blkif *blkif)
+{
+ if (blkif->xenblkd) {
+ kthread_stop(blkif->xenblkd);
+ blkif->xenblkd = NULL;
+ }
+
+ atomic_dec(&blkif->refcnt);
+ wait_event(blkif->waiting_to_free, atomic_read(&blkif->refcnt) == 0);
+ atomic_inc(&blkif->refcnt);
+
+ if (blkif->irq) {
+ unbind_from_irqhandler(blkif->irq, blkif);
+ blkif->irq = 0;
+ }
+
+ if (blkif->blk_rings.common.sring) {
+ unmap_frontend_page(blkif);
+ free_vm_area(blkif->blk_ring_area);
+ blkif->blk_rings.common.sring = NULL;
+ }
+}
+
+void xen_blkif_free(struct xen_blkif *blkif)
+{
+ if (!atomic_dec_and_test(&blkif->refcnt))
+ BUG();
+ kmem_cache_free(xen_blkif_cachep, blkif);
+}
+
+int __init xen_blkif_interface_init(void)
+{
+ xen_blkif_cachep = kmem_cache_create("blkif_cache",
+ sizeof(struct xen_blkif),
+ 0, 0, NULL);
+ if (!xen_blkif_cachep)
+ return -ENOMEM;
+
+ return 0;
+}
+
+/*
+ * sysfs interface for VBD I/O requests
+ */
+
+#define VBD_SHOW(name, format, args...) \
+ static ssize_t show_##name(struct device *_dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+ { \
+ struct xenbus_device *dev = to_xenbus_device(_dev); \
+ struct backend_info *be = dev_get_drvdata(&dev->dev); \
+ \
+ return sprintf(buf, format, ##args); \
+ } \
+ static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+
+VBD_SHOW(oo_req, "%d\n", be->blkif->st_oo_req);
+VBD_SHOW(rd_req, "%d\n", be->blkif->st_rd_req);
+VBD_SHOW(wr_req, "%d\n", be->blkif->st_wr_req);
+VBD_SHOW(f_req, "%d\n", be->blkif->st_f_req);
+VBD_SHOW(rd_sect, "%d\n", be->blkif->st_rd_sect);
+VBD_SHOW(wr_sect, "%d\n", be->blkif->st_wr_sect);
+
+static struct attribute *xen_vbdstat_attrs[] = {
+ &dev_attr_oo_req.attr,
+ &dev_attr_rd_req.attr,
+ &dev_attr_wr_req.attr,
+ &dev_attr_f_req.attr,
+ &dev_attr_rd_sect.attr,
+ &dev_attr_wr_sect.attr,
+ NULL
+};
+
+static struct attribute_group xen_vbdstat_group = {
+ .name = "statistics",
+ .attrs = xen_vbdstat_attrs,
+};
+
+VBD_SHOW(physical_device, "%x:%x\n", be->major, be->minor);
+VBD_SHOW(mode, "%s\n", be->mode);
+
+int xenvbd_sysfs_addif(struct xenbus_device *dev)
+{
+ int error;
+
+ error = device_create_file(&dev->dev, &dev_attr_physical_device);
+ if (error)
+ goto fail1;
+
+ error = device_create_file(&dev->dev, &dev_attr_mode);
+ if (error)
+ goto fail2;
+
+ error = sysfs_create_group(&dev->dev.kobj, &xen_vbdstat_group);
+ if (error)
+ goto fail3;
+
+ return 0;
+
+fail3: sysfs_remove_group(&dev->dev.kobj, &xen_vbdstat_group);
+fail2: device_remove_file(&dev->dev, &dev_attr_mode);
+fail1: device_remove_file(&dev->dev, &dev_attr_physical_device);
+ return error;
+}
+
+void xenvbd_sysfs_delif(struct xenbus_device *dev)
+{
+ sysfs_remove_group(&dev->dev.kobj, &xen_vbdstat_group);
+ device_remove_file(&dev->dev, &dev_attr_mode);
+ device_remove_file(&dev->dev, &dev_attr_physical_device);
+}
+
+
+static void xen_vbd_free(struct xen_vbd *vbd)
+{
+ if (vbd->bdev)
+ blkdev_put(vbd->bdev, vbd->readonly ? FMODE_READ : FMODE_WRITE);
+ vbd->bdev = NULL;
+}
+
+static int xen_vbd_create(struct xen_blkif *blkif, blkif_vdev_t handle,
+ unsigned major, unsigned minor, int readonly,
+ int cdrom)
+{
+ struct xen_vbd *vbd;
+ struct block_device *bdev;
+ struct request_queue *q;
+
+ vbd = &blkif->vbd;
+ vbd->handle = handle;
+ vbd->readonly = readonly;
+ vbd->type = 0;
+
+ vbd->pdevice = MKDEV(major, minor);
+
+ bdev = blkdev_get_by_dev(vbd->pdevice, vbd->readonly ?
+ FMODE_READ : FMODE_WRITE, NULL);
+
+ if (IS_ERR(bdev)) {
+ DPRINTK("xen_vbd_create: device %08x could not be opened.\n",
+ vbd->pdevice);
+ return -ENOENT;
+ }
+
+ vbd->bdev = bdev;
+ vbd->size = vbd_sz(vbd);
+
+ if (vbd->bdev->bd_disk == NULL) {
+ DPRINTK("xen_vbd_create: device %08x doesn't exist.\n",
+ vbd->pdevice);
+ xen_vbd_free(vbd);
+ return -ENOENT;
+ }
+
+ if (vbd->bdev->bd_disk->flags & GENHD_FL_CD || cdrom)
+ vbd->type |= VDISK_CDROM;
+ if (vbd->bdev->bd_disk->flags & GENHD_FL_REMOVABLE)
+ vbd->type |= VDISK_REMOVABLE;
+
+ q = bdev_get_queue(bdev);
+ if (q && q->flush_flags)
+ vbd->flush_support = true;
+
+ DPRINTK("Successful creation of handle=%04x (dom=%u)\n",
+ handle, blkif->domid);
+ return 0;
+}
+static int xen_blkbk_remove(struct xenbus_device *dev)
+{
+ struct backend_info *be = dev_get_drvdata(&dev->dev);
+
+ DPRINTK("");
+
+ if (be->major || be->minor)
+ xenvbd_sysfs_delif(dev);
+
+ if (be->backend_watch.node) {
+ unregister_xenbus_watch(&be->backend_watch);
+ kfree(be->backend_watch.node);
+ be->backend_watch.node = NULL;
+ }
+
+ if (be->blkif) {
+ xen_blkif_disconnect(be->blkif);
+ xen_vbd_free(&be->blkif->vbd);
+ xen_blkif_free(be->blkif);
+ be->blkif = NULL;
+ }
+
+ kfree(be);
+ dev_set_drvdata(&dev->dev, NULL);
+ return 0;
+}
+
+int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt,
+ struct backend_info *be, int state)
+{
+ struct xenbus_device *dev = be->dev;
+ int err;
+
+ err = xenbus_printf(xbt, dev->nodename, "feature-flush-cache",
+ "%d", state);
+ if (err)
+ xenbus_dev_fatal(dev, err, "writing feature-flush-cache");
+
+ return err;
+}
+
+/*
+ * Entry point to this code when a new device is created. Allocate the basic
+ * structures, and watch the store waiting for the hotplug scripts to tell us
+ * the device's physical major and minor numbers. Switch to InitWait.
+ */
+static int xen_blkbk_probe(struct xenbus_device *dev,
+ const struct xenbus_device_id *id)
+{
+ int err;
+ struct backend_info *be = kzalloc(sizeof(struct backend_info),
+ GFP_KERNEL);
+ if (!be) {
+ xenbus_dev_fatal(dev, -ENOMEM,
+ "allocating backend structure");
+ return -ENOMEM;
+ }
+ be->dev = dev;
+ dev_set_drvdata(&dev->dev, be);
+
+ be->blkif = xen_blkif_alloc(dev->otherend_id);
+ if (IS_ERR(be->blkif)) {
+ err = PTR_ERR(be->blkif);
+ be->blkif = NULL;
+ xenbus_dev_fatal(dev, err, "creating block interface");
+ goto fail;
+ }
+
+ /* setup back pointer */
+ be->blkif->be = be;
+
+ err = xenbus_watch_pathfmt(dev, &be->backend_watch, backend_changed,
+ "%s/%s", dev->nodename, "physical-device");
+ if (err)
+ goto fail;
+
+ err = xenbus_switch_state(dev, XenbusStateInitWait);
+ if (err)
+ goto fail;
+
+ return 0;
+
+fail:
+ DPRINTK("failed");
+ xen_blkbk_remove(dev);
+ return err;
+}
+
+
+/*
+ * Callback received when the hotplug scripts have placed the physical-device
+ * node. Read it and the mode node, and create a vbd. If the frontend is
+ * ready, connect.
+ */
+static void backend_changed(struct xenbus_watch *watch,
+ const char **vec, unsigned int len)
+{
+ int err;
+ unsigned major;
+ unsigned minor;
+ struct backend_info *be
+ = container_of(watch, struct backend_info, backend_watch);
+ struct xenbus_device *dev = be->dev;
+ int cdrom = 0;
+ char *device_type;
+
+ DPRINTK("");
+
+ err = xenbus_scanf(XBT_NIL, dev->nodename, "physical-device", "%x:%x",
+ &major, &minor);
+ if (XENBUS_EXIST_ERR(err)) {
+ /*
+ * Since this watch will fire once immediately after it is
+ * registered, we expect this. Ignore it, and wait for the
+ * hotplug scripts.
+ */
+ return;
+ }
+ if (err != 2) {
+ xenbus_dev_fatal(dev, err, "reading physical-device");
+ return;
+ }
+
+ if ((be->major || be->minor) &&
+ ((be->major != major) || (be->minor != minor))) {
+ pr_warn(DRV_PFX "changing physical device (from %x:%x to %x:%x) not supported.\n",
+ be->major, be->minor, major, minor);
+ return;
+ }
+
+ be->mode = xenbus_read(XBT_NIL, dev->nodename, "mode", NULL);
+ if (IS_ERR(be->mode)) {
+ err = PTR_ERR(be->mode);
+ be->mode = NULL;
+ xenbus_dev_fatal(dev, err, "reading mode");
+ return;
+ }
+
+ device_type = xenbus_read(XBT_NIL, dev->otherend, "device-type", NULL);
+ if (!IS_ERR(device_type)) {
+ cdrom = strcmp(device_type, "cdrom") == 0;
+ kfree(device_type);
+ }
+
+ if (be->major == 0 && be->minor == 0) {
+ /* Front end dir is a number, which is used as the handle. */
+
+ char *p = strrchr(dev->otherend, '/') + 1;
+ long handle;
+ err = strict_strtoul(p, 0, &handle);
+ if (err)
+ return;
+
+ be->major = major;
+ be->minor = minor;
+
+ err = xen_vbd_create(be->blkif, handle, major, minor,
+ (NULL == strchr(be->mode, 'w')), cdrom);
+ if (err) {
+ be->major = 0;
+ be->minor = 0;
+ xenbus_dev_fatal(dev, err, "creating vbd structure");
+ return;
+ }
+
+ err = xenvbd_sysfs_addif(dev);
+ if (err) {
+ xen_vbd_free(&be->blkif->vbd);
+ be->major = 0;
+ be->minor = 0;
+ xenbus_dev_fatal(dev, err, "creating sysfs entries");
+ return;
+ }
+
+ /* We're potentially connected now */
+ xen_update_blkif_status(be->blkif);
+ }
+}
+
+
+/*
+ * Callback received when the frontend's state changes.
+ */
+static void frontend_changed(struct xenbus_device *dev,
+ enum xenbus_state frontend_state)
+{
+ struct backend_info *be = dev_get_drvdata(&dev->dev);
+ int err;
+
+ DPRINTK("%s", xenbus_strstate(frontend_state));
+
+ switch (frontend_state) {
+ case XenbusStateInitialising:
+ if (dev->state == XenbusStateClosed) {
+ pr_info(DRV_PFX "%s: prepare for reconnect\n",
+ dev->nodename);
+ xenbus_switch_state(dev, XenbusStateInitWait);
+ }
+ break;
+
+ case XenbusStateInitialised:
+ case XenbusStateConnected:
+ /*
+ * Ensure we connect even when two watches fire in
+ * close successsion and we miss the intermediate value
+ * of frontend_state.
+ */
+ if (dev->state == XenbusStateConnected)
+ break;
+
+ /*
+ * Enforce precondition before potential leak point.
+ * blkif_disconnect() is idempotent.
+ */
+ xen_blkif_disconnect(be->blkif);
+
+ err = connect_ring(be);
+ if (err)
+ break;
+ xen_update_blkif_status(be->blkif);
+ break;
+
+ case XenbusStateClosing:
+ xen_blkif_disconnect(be->blkif);
+ xenbus_switch_state(dev, XenbusStateClosing);
+ break;
+
+ case XenbusStateClosed:
+ xenbus_switch_state(dev, XenbusStateClosed);
+ if (xenbus_dev_is_online(dev))
+ break;
+ /* fall through if not online */
+ case XenbusStateUnknown:
+ /* implies blkif_disconnect() via blkback_remove() */
+ device_unregister(&dev->dev);
+ break;
+
+ default:
+ xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
+ frontend_state);
+ break;
+ }
+}
+
+
+/* ** Connection ** */
+
+
+/*
+ * Write the physical details regarding the block device to the store, and
+ * switch to Connected state.
+ */
+static void connect(struct backend_info *be)
+{
+ struct xenbus_transaction xbt;
+ int err;
+ struct xenbus_device *dev = be->dev;
+
+ DPRINTK("%s", dev->otherend);
+
+ /* Supply the information about the device the frontend needs */
+again:
+ err = xenbus_transaction_start(&xbt);
+ if (err) {
+ xenbus_dev_fatal(dev, err, "starting transaction");
+ return;
+ }
+
+ err = xen_blkbk_flush_diskcache(xbt, be, be->blkif->vbd.flush_support);
+ if (err)
+ goto abort;
+
+ err = xenbus_printf(xbt, dev->nodename, "sectors", "%llu",
+ (unsigned long long)vbd_sz(&be->blkif->vbd));
+ if (err) {
+ xenbus_dev_fatal(dev, err, "writing %s/sectors",
+ dev->nodename);
+ goto abort;
+ }
+
+ /* FIXME: use a typename instead */
+ err = xenbus_printf(xbt, dev->nodename, "info", "%u",
+ be->blkif->vbd.type |
+ (be->blkif->vbd.readonly ? VDISK_READONLY : 0));
+ if (err) {
+ xenbus_dev_fatal(dev, err, "writing %s/info",
+ dev->nodename);
+ goto abort;
+ }
+ err = xenbus_printf(xbt, dev->nodename, "sector-size", "%lu",
+ (unsigned long)
+ bdev_logical_block_size(be->blkif->vbd.bdev));
+ if (err) {
+ xenbus_dev_fatal(dev, err, "writing %s/sector-size",
+ dev->nodename);
+ goto abort;
+ }
+
+ err = xenbus_transaction_end(xbt, 0);
+ if (err == -EAGAIN)
+ goto again;
+ if (err)
+ xenbus_dev_fatal(dev, err, "ending transaction");
+
+ err = xenbus_switch_state(dev, XenbusStateConnected);
+ if (err)
+ xenbus_dev_fatal(dev, err, "switching to Connected state",
+ dev->nodename);
+
+ return;
+ abort:
+ xenbus_transaction_end(xbt, 1);
+}
+
+
+static int connect_ring(struct backend_info *be)
+{
+ struct xenbus_device *dev = be->dev;
+ unsigned long ring_ref;
+ unsigned int evtchn;
+ char protocol[64] = "";
+ int err;
+
+ DPRINTK("%s", dev->otherend);
+
+ err = xenbus_gather(XBT_NIL, dev->otherend, "ring-ref", "%lu",
+ &ring_ref, "event-channel", "%u", &evtchn, NULL);
+ if (err) {
+ xenbus_dev_fatal(dev, err,
+ "reading %s/ring-ref and event-channel",
+ dev->otherend);
+ return err;
+ }
+
+ be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE;
+ err = xenbus_gather(XBT_NIL, dev->otherend, "protocol",
+ "%63s", protocol, NULL);
+ if (err)
+ strcpy(protocol, "unspecified, assuming native");
+ else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE))
+ be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE;
+ else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32))
+ be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_32;
+ else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_64))
+ be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_64;
+ else {
+ xenbus_dev_fatal(dev, err, "unknown fe protocol %s", protocol);
+ return -1;
+ }
+ pr_info(DRV_PFX "ring-ref %ld, event-channel %d, protocol %d (%s)\n",
+ ring_ref, evtchn, be->blkif->blk_protocol, protocol);
+
+ /* Map the shared frame, irq etc. */
+ err = xen_blkif_map(be->blkif, ring_ref, evtchn);
+ if (err) {
+ xenbus_dev_fatal(dev, err, "mapping ring-ref %lu port %u",
+ ring_ref, evtchn);
+ return err;
+ }
+
+ return 0;
+}
+
+
+/* ** Driver Registration ** */
+
+
+static const struct xenbus_device_id xen_blkbk_ids[] = {
+ { "vbd" },
+ { "" }
+};
+
+
+static struct xenbus_driver xen_blkbk = {
+ .name = "vbd",
+ .owner = THIS_MODULE,
+ .ids = xen_blkbk_ids,
+ .probe = xen_blkbk_probe,
+ .remove = xen_blkbk_remove,
+ .otherend_changed = frontend_changed
+};
+
+
+int xen_blkif_xenbus_init(void)
+{
+ return xenbus_register_backend(&xen_blkbk);
+}
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 9cb8668ff5f4..b536a9cef917 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -97,6 +97,7 @@ struct blkfront_info
struct blk_shadow shadow[BLK_RING_SIZE];
unsigned long shadow_free;
unsigned int feature_flush;
+ unsigned int flush_op;
int is_ready;
};
@@ -250,8 +251,7 @@ static int blkif_ioctl(struct block_device *bdev, fmode_t mode,
/*
* Generate a Xen blkfront IO request from a blk layer request. Reads
- * and writes are handled as expected. Since we lack a loose flush
- * request, we map flushes into a full ordered barrier.
+ * and writes are handled as expected.
*
* @req: a request struct
*/
@@ -293,14 +293,13 @@ static int blkif_queue_request(struct request *req)
if (req->cmd_flags & (REQ_FLUSH | REQ_FUA)) {
/*
- * Ideally we could just do an unordered
- * flush-to-disk, but all we have is a full write
- * barrier at the moment. However, a barrier write is
+ * Ideally we can do an unordered flush-to-disk. In case the
+ * backend onlysupports barriers, use that. A barrier request
* a superset of FUA, so we can implement it the same
* way. (It's also a FLUSH+FUA, since it is
* guaranteed ordered WRT previous writes.)
*/
- ring_req->operation = BLKIF_OP_WRITE_BARRIER;
+ ring_req->operation = info->flush_op;
}
ring_req->nr_segments = blk_rq_map_sg(req->q, req, info->sg);
@@ -433,8 +432,11 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
static void xlvbd_flush(struct blkfront_info *info)
{
blk_queue_flush(info->rq, info->feature_flush);
- printk(KERN_INFO "blkfront: %s: barriers %s\n",
+ printk(KERN_INFO "blkfront: %s: %s: %s\n",
info->gd->disk_name,
+ info->flush_op == BLKIF_OP_WRITE_BARRIER ?
+ "barrier" : (info->flush_op == BLKIF_OP_FLUSH_DISKCACHE ?
+ "flush diskcache" : "barrier or flush"),
info->feature_flush ? "enabled" : "disabled");
}
@@ -720,15 +722,20 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
error = (bret->status == BLKIF_RSP_OKAY) ? 0 : -EIO;
switch (bret->operation) {
+ case BLKIF_OP_FLUSH_DISKCACHE:
case BLKIF_OP_WRITE_BARRIER:
if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
- printk(KERN_WARNING "blkfront: %s: write barrier op failed\n",
+ printk(KERN_WARNING "blkfront: %s: write %s op failed\n",
+ info->flush_op == BLKIF_OP_WRITE_BARRIER ?
+ "barrier" : "flush disk cache",
info->gd->disk_name);
error = -EOPNOTSUPP;
}
if (unlikely(bret->status == BLKIF_RSP_ERROR &&
info->shadow[id].req.nr_segments == 0)) {
- printk(KERN_WARNING "blkfront: %s: empty write barrier op failed\n",
+ printk(KERN_WARNING "blkfront: %s: empty write %s op failed\n",
+ info->flush_op == BLKIF_OP_WRITE_BARRIER ?
+ "barrier" : "flush disk cache",
info->gd->disk_name);
error = -EOPNOTSUPP;
}
@@ -736,6 +743,7 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
if (error == -EOPNOTSUPP)
error = 0;
info->feature_flush = 0;
+ info->flush_op = 0;
xlvbd_flush(info);
}
/* fall through */
@@ -1100,7 +1108,7 @@ static void blkfront_connect(struct blkfront_info *info)
unsigned long sector_size;
unsigned int binfo;
int err;
- int barrier;
+ int barrier, flush;
switch (info->connected) {
case BLKIF_STATE_CONNECTED:
@@ -1140,8 +1148,11 @@ static void blkfront_connect(struct blkfront_info *info)
return;
}
+ info->feature_flush = 0;
+ info->flush_op = 0;
+
err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
- "feature-barrier", "%lu", &barrier,
+ "feature-barrier", "%d", &barrier,
NULL);
/*
@@ -1151,11 +1162,23 @@ static void blkfront_connect(struct blkfront_info *info)
*
* If there are barriers, then we use flush.
*/
- info->feature_flush = 0;
-
- if (!err && barrier)
+ if (!err && barrier) {
info->feature_flush = REQ_FLUSH | REQ_FUA;
+ info->flush_op = BLKIF_OP_WRITE_BARRIER;
+ }
+ /*
+ * And if there is "feature-flush-cache" use that above
+ * barriers.
+ */
+ err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
+ "feature-flush-cache", "%d", &flush,
+ NULL);
+ if (!err && flush) {
+ info->feature_flush = REQ_FLUSH;
+ info->flush_op = BLKIF_OP_FLUSH_DISKCACHE;
+ }
+
err = xlvbd_alloc_gendisk(sectors, info, binfo, sector_size);
if (err) {
xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s",
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 8e0de9a05867..11b41fd40c27 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -188,7 +188,7 @@ config BT_MRVL
The core driver to support Marvell Bluetooth devices.
This driver is required if you want to support
- Marvell Bluetooth devices, such as 8688.
+ Marvell Bluetooth devices, such as 8688/8787.
Say Y here to compile Marvell Bluetooth driver
into the kernel or say M to compile it as module.
@@ -201,7 +201,7 @@ config BT_MRVL_SDIO
The driver for Marvell Bluetooth chipsets with SDIO interface.
This driver is required if you want to use Marvell Bluetooth
- devices with SDIO interface. Currently only SD8688 chipset is
+ devices with SDIO interface. Currently SD8688/SD8787 chipsets are
supported.
Say Y here to compile support for Marvell BT-over-SDIO driver
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 5577ed656e2f..6bacef368fab 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -62,6 +62,7 @@ static struct usb_device_id ath3k_table[] = {
/* Atheros AR3011 with sflash firmware*/
{ USB_DEVICE(0x0CF3, 0x3002) },
+ { USB_DEVICE(0x13d3, 0x3304) },
/* Atheros AR9285 Malbec with sflash firmware */
{ USB_DEVICE(0x03F0, 0x311D) },
@@ -138,9 +139,6 @@ static int ath3k_load_firmware(struct usb_device *udev,
count -= size;
}
- kfree(send_buf);
- return 0;
-
error:
kfree(send_buf);
return err;
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
index 4104b7feae67..aed1904ea67b 100644
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -930,7 +930,7 @@ static void bluecard_release(struct pcmcia_device *link)
pcmcia_disable_device(link);
}
-static struct pcmcia_device_id bluecard_ids[] = {
+static const struct pcmcia_device_id bluecard_ids[] = {
PCMCIA_DEVICE_PROD_ID12("BlueCard", "LSE041", 0xbaf16fbf, 0x657cc15e),
PCMCIA_DEVICE_PROD_ID12("BTCFCARD", "LSE139", 0xe3987764, 0x2524b59c),
PCMCIA_DEVICE_PROD_ID12("WSS", "LSE039", 0x0a0736ec, 0x24e6dfab),
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 0c8a65587491..4fc01949d399 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -761,7 +761,7 @@ static void bt3c_release(struct pcmcia_device *link)
}
-static struct pcmcia_device_id bt3c_ids[] = {
+static const struct pcmcia_device_id bt3c_ids[] = {
PCMCIA_DEVICE_PROD_ID13("3COM", "Bluetooth PC Card", 0xefce0a31, 0xd4ce9b02),
PCMCIA_DEVICE_NULL
};
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index dcc2a6ec23f0..7f521d4ac657 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -49,15 +49,59 @@
static u8 user_rmmod;
static u8 sdio_ireg;
+static const struct btmrvl_sdio_card_reg btmrvl_reg_8688 = {
+ .cfg = 0x03,
+ .host_int_mask = 0x04,
+ .host_intstatus = 0x05,
+ .card_status = 0x20,
+ .sq_read_base_addr_a0 = 0x10,
+ .sq_read_base_addr_a1 = 0x11,
+ .card_fw_status0 = 0x40,
+ .card_fw_status1 = 0x41,
+ .card_rx_len = 0x42,
+ .card_rx_unit = 0x43,
+ .io_port_0 = 0x00,
+ .io_port_1 = 0x01,
+ .io_port_2 = 0x02,
+};
+static const struct btmrvl_sdio_card_reg btmrvl_reg_8787 = {
+ .cfg = 0x00,
+ .host_int_mask = 0x02,
+ .host_intstatus = 0x03,
+ .card_status = 0x30,
+ .sq_read_base_addr_a0 = 0x40,
+ .sq_read_base_addr_a1 = 0x41,
+ .card_revision = 0x5c,
+ .card_fw_status0 = 0x60,
+ .card_fw_status1 = 0x61,
+ .card_rx_len = 0x62,
+ .card_rx_unit = 0x63,
+ .io_port_0 = 0x78,
+ .io_port_1 = 0x79,
+ .io_port_2 = 0x7a,
+};
+
static const struct btmrvl_sdio_device btmrvl_sdio_sd6888 = {
.helper = "sd8688_helper.bin",
.firmware = "sd8688.bin",
+ .reg = &btmrvl_reg_8688,
+ .sd_blksz_fw_dl = 64,
+};
+
+static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = {
+ .helper = NULL,
+ .firmware = "mrvl/sd8787_uapsta.bin",
+ .reg = &btmrvl_reg_8787,
+ .sd_blksz_fw_dl = 256,
};
static const struct sdio_device_id btmrvl_sdio_ids[] = {
/* Marvell SD8688 Bluetooth device */
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9105),
.driver_data = (unsigned long) &btmrvl_sdio_sd6888 },
+ /* Marvell SD8787 Bluetooth device */
+ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A),
+ .driver_data = (unsigned long) &btmrvl_sdio_sd8787 },
{ } /* Terminating entry */
};
@@ -69,7 +113,7 @@ static int btmrvl_sdio_get_rx_unit(struct btmrvl_sdio_card *card)
u8 reg;
int ret;
- reg = sdio_readb(card->func, CARD_RX_UNIT_REG, &ret);
+ reg = sdio_readb(card->func, card->reg->card_rx_unit, &ret);
if (!ret)
card->rx_unit = reg;
@@ -83,11 +127,11 @@ 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);
+ fws0 = sdio_readb(card->func, card->reg->card_fw_status0, &ret);
if (ret)
return -EIO;
- fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret);
+ fws1 = sdio_readb(card->func, card->reg->card_fw_status1, &ret);
if (ret)
return -EIO;
@@ -101,7 +145,7 @@ static int btmrvl_sdio_read_rx_len(struct btmrvl_sdio_card *card, u16 *dat)
u8 reg;
int ret;
- reg = sdio_readb(card->func, CARD_RX_LEN_REG, &ret);
+ reg = sdio_readb(card->func, card->reg->card_rx_len, &ret);
if (!ret)
*dat = (u16) reg << card->rx_unit;
@@ -113,7 +157,7 @@ static int btmrvl_sdio_enable_host_int_mask(struct btmrvl_sdio_card *card,
{
int ret;
- sdio_writeb(card->func, mask, HOST_INT_MASK_REG, &ret);
+ sdio_writeb(card->func, mask, card->reg->host_int_mask, &ret);
if (ret) {
BT_ERR("Unable to enable the host interrupt!");
ret = -EIO;
@@ -128,13 +172,13 @@ static int btmrvl_sdio_disable_host_int_mask(struct btmrvl_sdio_card *card,
u8 host_int_mask;
int ret;
- host_int_mask = sdio_readb(card->func, HOST_INT_MASK_REG, &ret);
+ host_int_mask = sdio_readb(card->func, card->reg->host_int_mask, &ret);
if (ret)
return -EIO;
host_int_mask &= ~mask;
- sdio_writeb(card->func, host_int_mask, HOST_INT_MASK_REG, &ret);
+ sdio_writeb(card->func, host_int_mask, card->reg->host_int_mask, &ret);
if (ret < 0) {
BT_ERR("Unable to disable the host interrupt!");
return -EIO;
@@ -150,7 +194,7 @@ static int btmrvl_sdio_poll_card_status(struct btmrvl_sdio_card *card, u8 bits)
int ret;
for (tries = 0; tries < MAX_POLL_TRIES * 1000; tries++) {
- status = sdio_readb(card->func, CARD_STATUS_REG, &ret);
+ status = sdio_readb(card->func, card->reg->card_status, &ret);
if (ret)
goto failed;
if ((status & bits) == bits)
@@ -299,7 +343,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
u8 base0, base1;
void *tmpfwbuf = NULL;
u8 *fwbuf;
- u16 len;
+ u16 len, blksz_dl = card->sd_blksz_fw_dl;
int txlen = 0, tx_blocks = 0, count = 0;
ret = request_firmware(&fw_firmware, card->firmware,
@@ -345,7 +389,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
base0 = sdio_readb(card->func,
- SQ_READ_BASE_ADDRESS_A0_REG, &ret);
+ card->reg->sq_read_base_addr_a0, &ret);
if (ret) {
BT_ERR("BASE0 register read failed:"
" base0 = 0x%04X(%d)."
@@ -355,7 +399,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
goto done;
}
base1 = sdio_readb(card->func,
- SQ_READ_BASE_ADDRESS_A1_REG, &ret);
+ card->reg->sq_read_base_addr_a1, &ret);
if (ret) {
BT_ERR("BASE1 register read failed:"
" base1 = 0x%04X(%d)."
@@ -403,20 +447,19 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
if (firmwarelen - offset < txlen)
txlen = firmwarelen - offset;
- tx_blocks =
- (txlen + SDIO_BLOCK_SIZE - 1) / SDIO_BLOCK_SIZE;
+ tx_blocks = (txlen + blksz_dl - 1) / blksz_dl;
memcpy(fwbuf, &firmware[offset], txlen);
}
ret = sdio_writesb(card->func, card->ioport, fwbuf,
- tx_blocks * SDIO_BLOCK_SIZE);
+ tx_blocks * blksz_dl);
if (ret < 0) {
BT_ERR("FW download, writesb(%d) failed @%d",
count, offset);
- sdio_writeb(card->func, HOST_CMD53_FIN, CONFIG_REG,
- &ret);
+ sdio_writeb(card->func, HOST_CMD53_FIN,
+ card->reg->cfg, &ret);
if (ret)
BT_ERR("writeb failed (CFG)");
}
@@ -597,7 +640,7 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func)
priv = card->priv;
- ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret);
+ ireg = sdio_readb(card->func, card->reg->host_intstatus, &ret);
if (ret) {
BT_ERR("sdio_readb: read int status register failed");
return;
@@ -613,7 +656,7 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func)
sdio_writeb(card->func, ~(ireg) & (DN_LD_HOST_INT_STATUS |
UP_LD_HOST_INT_STATUS),
- HOST_INTSTATUS_REG, &ret);
+ card->reg->host_intstatus, &ret);
if (ret) {
BT_ERR("sdio_writeb: clear int status register failed");
return;
@@ -664,7 +707,7 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
goto release_irq;
}
- reg = sdio_readb(func, IO_PORT_0_REG, &ret);
+ reg = sdio_readb(func, card->reg->io_port_0, &ret);
if (ret < 0) {
ret = -EIO;
goto release_irq;
@@ -672,7 +715,7 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
card->ioport = reg;
- reg = sdio_readb(func, IO_PORT_1_REG, &ret);
+ reg = sdio_readb(func, card->reg->io_port_1, &ret);
if (ret < 0) {
ret = -EIO;
goto release_irq;
@@ -680,7 +723,7 @@ static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card)
card->ioport |= (reg << 8);
- reg = sdio_readb(func, IO_PORT_2_REG, &ret);
+ reg = sdio_readb(func, card->reg->io_port_2, &ret);
if (ret < 0) {
ret = -EIO;
goto release_irq;
@@ -815,6 +858,8 @@ exit:
static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card)
{
int ret = 0;
+ u8 fws0;
+ int pollnum = MAX_POLL_TRIES;
if (!card || !card->func) {
BT_ERR("card or function is NULL!");
@@ -827,20 +872,36 @@ static int btmrvl_sdio_download_fw(struct btmrvl_sdio_card *card)
goto done;
}
- ret = btmrvl_sdio_download_helper(card);
+ /* Check if other function driver is downloading the firmware */
+ fws0 = sdio_readb(card->func, card->reg->card_fw_status0, &ret);
if (ret) {
- BT_ERR("Failed to download helper!");
+ BT_ERR("Failed to read FW downloading status!");
ret = -EIO;
goto done;
}
+ if (fws0) {
+ BT_DBG("BT not the winner (%#x). Skip FW downloading", fws0);
+
+ /* Give other function more time to download the firmware */
+ pollnum *= 10;
+ } else {
+ if (card->helper) {
+ ret = btmrvl_sdio_download_helper(card);
+ if (ret) {
+ BT_ERR("Failed to download helper!");
+ ret = -EIO;
+ goto done;
+ }
+ }
- if (btmrvl_sdio_download_fw_w_helper(card)) {
- BT_ERR("Failed to download firmware!");
- ret = -EIO;
- goto done;
+ if (btmrvl_sdio_download_fw_w_helper(card)) {
+ BT_ERR("Failed to download firmware!");
+ ret = -EIO;
+ goto done;
+ }
}
- if (btmrvl_sdio_verify_fw_download(card, MAX_POLL_TRIES)) {
+ if (btmrvl_sdio_verify_fw_download(card, pollnum)) {
BT_ERR("FW failed to be active in time!");
ret = -ETIMEDOUT;
goto done;
@@ -864,7 +925,7 @@ static int btmrvl_sdio_wakeup_fw(struct btmrvl_private *priv)
sdio_claim_host(card->func);
- sdio_writeb(card->func, HOST_POWER_UP, CONFIG_REG, &ret);
+ sdio_writeb(card->func, HOST_POWER_UP, card->reg->cfg, &ret);
sdio_release_host(card->func);
@@ -893,8 +954,10 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
if (id->driver_data) {
struct btmrvl_sdio_device *data = (void *) id->driver_data;
- card->helper = data->helper;
+ card->helper = data->helper;
card->firmware = data->firmware;
+ card->reg = data->reg;
+ card->sd_blksz_fw_dl = data->sd_blksz_fw_dl;
}
if (btmrvl_sdio_register_dev(card) < 0) {
@@ -1011,3 +1074,4 @@ MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL v2");
MODULE_FIRMWARE("sd8688_helper.bin");
MODULE_FIRMWARE("sd8688.bin");
+MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
diff --git a/drivers/bluetooth/btmrvl_sdio.h b/drivers/bluetooth/btmrvl_sdio.h
index 27329f107e5a..43d35a609ca9 100644
--- a/drivers/bluetooth/btmrvl_sdio.h
+++ b/drivers/bluetooth/btmrvl_sdio.h
@@ -47,44 +47,46 @@
/* Max retry number of CMD53 write */
#define MAX_WRITE_IOMEM_RETRY 2
-/* Host Control Registers */
-#define IO_PORT_0_REG 0x00
-#define IO_PORT_1_REG 0x01
-#define IO_PORT_2_REG 0x02
-
-#define CONFIG_REG 0x03
-#define HOST_POWER_UP BIT(1)
-#define HOST_CMD53_FIN BIT(2)
-
-#define HOST_INT_MASK_REG 0x04
-#define HIM_DISABLE 0xff
-#define HIM_ENABLE (BIT(0) | BIT(1))
-
-#define HOST_INTSTATUS_REG 0x05
-#define UP_LD_HOST_INT_STATUS BIT(0)
-#define DN_LD_HOST_INT_STATUS BIT(1)
-
-/* Card Control Registers */
-#define SQ_READ_BASE_ADDRESS_A0_REG 0x10
-#define SQ_READ_BASE_ADDRESS_A1_REG 0x11
-
-#define CARD_STATUS_REG 0x20
-#define DN_LD_CARD_RDY BIT(0)
-#define CARD_IO_READY BIT(3)
-
-#define CARD_FW_STATUS0_REG 0x40
-#define CARD_FW_STATUS1_REG 0x41
-#define FIRMWARE_READY 0xfedc
-
-#define CARD_RX_LEN_REG 0x42
-#define CARD_RX_UNIT_REG 0x43
-
+/* register bitmasks */
+#define HOST_POWER_UP BIT(1)
+#define HOST_CMD53_FIN BIT(2)
+
+#define HIM_DISABLE 0xff
+#define HIM_ENABLE (BIT(0) | BIT(1))
+
+#define UP_LD_HOST_INT_STATUS BIT(0)
+#define DN_LD_HOST_INT_STATUS BIT(1)
+
+#define DN_LD_CARD_RDY BIT(0)
+#define CARD_IO_READY BIT(3)
+
+#define FIRMWARE_READY 0xfedc
+
+
+struct btmrvl_sdio_card_reg {
+ u8 cfg;
+ u8 host_int_mask;
+ u8 host_intstatus;
+ u8 card_status;
+ u8 sq_read_base_addr_a0;
+ u8 sq_read_base_addr_a1;
+ u8 card_revision;
+ u8 card_fw_status0;
+ u8 card_fw_status1;
+ u8 card_rx_len;
+ u8 card_rx_unit;
+ u8 io_port_0;
+ u8 io_port_1;
+ u8 io_port_2;
+};
struct btmrvl_sdio_card {
struct sdio_func *func;
u32 ioport;
const char *helper;
const char *firmware;
+ const struct btmrvl_sdio_card_reg *reg;
+ u16 sd_blksz_fw_dl;
u8 rx_unit;
struct btmrvl_private *priv;
};
@@ -92,6 +94,8 @@ struct btmrvl_sdio_card {
struct btmrvl_sdio_device {
const char *helper;
const char *firmware;
+ const struct btmrvl_sdio_card_reg *reg;
+ u16 sd_blksz_fw_dl;
};
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index f8a0708e2311..526b61807d94 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -689,7 +689,7 @@ static void btuart_release(struct pcmcia_device *link)
pcmcia_disable_device(link);
}
-static struct pcmcia_device_id btuart_ids[] = {
+static const struct pcmcia_device_id btuart_ids[] = {
/* don't use this driver. Use serial_cs + hci_uart instead */
PCMCIA_DEVICE_NULL
};
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 762a5109c68a..c2de8951e3fb 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -104,6 +104,7 @@ static struct usb_device_id blacklist_table[] = {
/* Atheros 3011 with sflash firmware */
{ USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
+ { USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE },
/* Atheros AR9285 Malbec with sflash firmware */
{ USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index 26ee0cf88d20..5e4c2de9fc3f 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -636,7 +636,7 @@ static void dtl1_release(struct pcmcia_device *link)
}
-static struct pcmcia_device_id dtl1_ids[] = {
+static const struct pcmcia_device_id dtl1_ids[] = {
PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-1", 0xe1bfdd64, 0xe168480d),
PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-4", 0xe1bfdd64, 0x9102bc82),
PCMCIA_DEVICE_PROD_ID12("Socket", "CF", 0xb38bcc2e, 0x44ebf863),
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
index bd34406faaae..4093935ddf42 100644
--- a/drivers/bluetooth/hci_ath.c
+++ b/drivers/bluetooth/hci_ath.c
@@ -201,8 +201,13 @@ static struct sk_buff *ath_dequeue(struct hci_uart *hu)
/* Recv data */
static int ath_recv(struct hci_uart *hu, void *data, int count)
{
- if (hci_recv_stream_fragment(hu->hdev, data, count) < 0)
+ int ret;
+
+ ret = hci_recv_stream_fragment(hu->hdev, data, count);
+ if (ret < 0) {
BT_ERR("Frame Reassembly Failed");
+ return ret;
+ }
return count;
}
diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c
index 7b8ad93e2c36..2fcd8b387d69 100644
--- a/drivers/bluetooth/hci_h4.c
+++ b/drivers/bluetooth/hci_h4.c
@@ -151,8 +151,13 @@ 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)
{
- if (hci_recv_stream_fragment(hu->hdev, data, count) < 0)
+ int ret;
+
+ ret = hci_recv_stream_fragment(hu->hdev, data, count);
+ if (ret < 0) {
BT_ERR("Frame Reassembly Failed");
+ return ret;
+ }
return count;
}
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 48ad2a7ab080..b3f01996318f 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -355,24 +355,29 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty)
* flags pointer to flags for data
* count count of received data in bytes
*
- * Return Value: None
+ * Return Value: Number of bytes received
*/
-static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count)
+static unsigned int hci_uart_tty_receive(struct tty_struct *tty,
+ const u8 *data, char *flags, int count)
{
struct hci_uart *hu = (void *)tty->disc_data;
+ int received;
if (!hu || tty != hu->tty)
- return;
+ return -ENODEV;
if (!test_bit(HCI_UART_PROTO_SET, &hu->flags))
- return;
+ return -EINVAL;
spin_lock(&hu->rx_lock);
- hu->proto->recv(hu, (void *) data, count);
- hu->hdev->stat.byte_rx += count;
+ received = hu->proto->recv(hu, (void *) data, count);
+ if (received > 0)
+ hu->hdev->stat.byte_rx += received;
spin_unlock(&hu->rx_lock);
tty_unthrottle(tty);
+
+ return received;
}
static int hci_uart_register_dev(struct hci_uart *hu)
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c
index e427fbe45999..ae15a4ddaa9b 100644
--- a/drivers/cdrom/viocd.c
+++ b/drivers/cdrom/viocd.c
@@ -625,7 +625,9 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
blk_queue_max_hw_sectors(q, 4096 / 512);
gendisk->queue = q;
gendisk->fops = &viocd_fops;
- gendisk->flags = GENHD_FL_CD|GENHD_FL_REMOVABLE;
+ gendisk->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE |
+ GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
+ gendisk->events = DISK_EVENT_MEDIA_CHANGE;
set_capacity(gendisk, 0);
gendisk->private_data = d;
d->viocd_disk = gendisk;
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index ad59b4e0a9b5..49502bc5360a 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -523,7 +523,7 @@ config RAW_DRIVER
with the O_DIRECT flag.
config MAX_RAW_DEVS
- int "Maximum number of RAW devices to support (1-8192)"
+ int "Maximum number of RAW devices to support (1-65536)"
depends on RAW_DRIVER
default "256"
help
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index b0a0dccc98c1..b427711be4be 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -903,6 +903,9 @@ static struct pci_device_id agp_intel_pci_table[] = {
ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB),
ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB),
ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB),
+ ID(PCI_DEVICE_ID_INTEL_IVYBRIDGE_HB),
+ ID(PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_HB),
+ ID(PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_HB),
{ }
};
diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h
index 5feebe2800e9..999803ce10dc 100644
--- a/drivers/char/agp/intel-agp.h
+++ b/drivers/char/agp/intel-agp.h
@@ -225,6 +225,14 @@
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG 0x0126
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB 0x0108 /* Server */
#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG 0x010A
+#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_HB 0x0150 /* Desktop */
+#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT1_IG 0x0152
+#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT2_IG 0x0162
+#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_HB 0x0154 /* Mobile */
+#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT1_IG 0x0156
+#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT2_IG 0x0166
+#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_HB 0x0158 /* Server */
+#define PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT1_IG 0x015A
int intel_gmch_probe(struct pci_dev *pdev,
struct agp_bridge_data *bridge);
diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
index 0d09b537bb9a..85151019dde1 100644
--- a/drivers/char/agp/intel-gtt.c
+++ b/drivers/char/agp/intel-gtt.c
@@ -1420,6 +1420,16 @@ static const struct intel_gtt_driver_description {
"Sandybridge", &sandybridge_gtt_driver },
{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG,
"Sandybridge", &sandybridge_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT1_IG,
+ "Ivybridge", &sandybridge_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT2_IG,
+ "Ivybridge", &sandybridge_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT1_IG,
+ "Ivybridge", &sandybridge_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT2_IG,
+ "Ivybridge", &sandybridge_gtt_driver },
+ { PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT1_IG,
+ "Ivybridge", &sandybridge_gtt_driver },
{ 0, NULL, NULL }
};
diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
index f845a8f718b3..a32c492baf5c 100644
--- a/drivers/char/agp/uninorth-agp.c
+++ b/drivers/char/agp/uninorth-agp.c
@@ -80,7 +80,7 @@ static void uninorth_tlbflush(struct agp_memory *mem)
ctrl | UNI_N_CFG_GART_INVAL);
pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL, ctrl);
- if (uninorth_rev <= 0x30) {
+ if (!mem && uninorth_rev <= 0x30) {
pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
ctrl | UNI_N_CFG_GART_2xRESET);
pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c
index 45b987c9889e..548708c4b2b8 100644
--- a/drivers/char/apm-emulation.c
+++ b/drivers/char/apm-emulation.c
@@ -126,7 +126,6 @@ struct apm_user {
/*
* Local variables
*/
-static DEFINE_MUTEX(apm_mutex);
static atomic_t suspend_acks_pending = ATOMIC_INIT(0);
static atomic_t userspace_notification_inhibit = ATOMIC_INIT(0);
static int apm_disabled;
@@ -275,7 +274,6 @@ apm_ioctl(struct file *filp, u_int cmd, u_long arg)
if (!as->suser || !as->writer)
return -EPERM;
- mutex_lock(&apm_mutex);
switch (cmd) {
case APM_IOC_SUSPEND:
mutex_lock(&state_lock);
@@ -336,7 +334,6 @@ apm_ioctl(struct file *filp, u_int cmd, u_long arg)
mutex_unlock(&state_lock);
break;
}
- mutex_unlock(&apm_mutex);
return err;
}
@@ -371,7 +368,6 @@ static int apm_open(struct inode * inode, struct file * filp)
{
struct apm_user *as;
- mutex_lock(&apm_mutex);
as = kzalloc(sizeof(*as), GFP_KERNEL);
if (as) {
/*
@@ -391,7 +387,6 @@ static int apm_open(struct inode * inode, struct file * filp)
filp->private_data = as;
}
- mutex_unlock(&apm_mutex);
return as ? 0 : -ENOMEM;
}
diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c
index a4a6c2f044b5..cf39bc08ce08 100644
--- a/drivers/char/bsr.c
+++ b/drivers/char/bsr.c
@@ -295,7 +295,7 @@ static int bsr_create_devs(struct device_node *bn)
static int __init bsr_init(void)
{
struct device_node *np;
- dev_t bsr_dev = MKDEV(bsr_major, 0);
+ dev_t bsr_dev;
int ret = -ENODEV;
int result;
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 7066e801b9d3..051474c65b78 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -84,8 +84,6 @@ static struct clocksource clocksource_hpet = {
.rating = 250,
.read = read_hpet,
.mask = CLOCKSOURCE_MASK(64),
- .mult = 0, /* to be calculated */
- .shift = 10,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
static struct clocksource *hpet_clocksource;
@@ -934,9 +932,7 @@ int hpet_alloc(struct hpet_data *hdp)
if (!hpet_clocksource) {
hpet_mctr = (void __iomem *)&hpetp->hp_hpet->hpet_mc;
CLKSRC_FSYS_MMIO_SET(clocksource_hpet.fsys_mmio, hpet_mctr);
- clocksource_hpet.mult = clocksource_hz2mult(hpetp->hp_tick_freq,
- clocksource_hpet.shift);
- clocksource_register(&clocksource_hpet);
+ clocksource_register_hz(&clocksource_hpet, hpetp->hp_tick_freq);
hpetp->hp_clocksource = &clocksource_hpet;
hpet_clocksource = &clocksource_hpet;
}
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index beecd1cf9b99..a60043b3e409 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -49,7 +49,7 @@ config HW_RANDOM_INTEL
config HW_RANDOM_AMD
tristate "AMD HW Random Number Generator support"
- depends on HW_RANDOM && X86 && PCI
+ depends on HW_RANDOM && (X86 || PPC_MAPLE) && PCI
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c
index 0d8c5788b8e4..c6af038682f1 100644
--- a/drivers/char/hw_random/amd-rng.c
+++ b/drivers/char/hw_random/amd-rng.c
@@ -133,6 +133,12 @@ found:
pmbase &= 0x0000FF00;
if (pmbase == 0)
goto out;
+ if (!request_region(pmbase + 0xF0, 8, "AMD HWRNG")) {
+ dev_err(&pdev->dev, "AMD HWRNG region 0x%x already in use!\n",
+ pmbase + 0xF0);
+ err = -EBUSY;
+ goto out;
+ }
amd_rng.priv = (unsigned long)pmbase;
amd_pdev = pdev;
@@ -141,6 +147,7 @@ found:
if (err) {
printk(KERN_ERR PFX "RNG registering failed (%d)\n",
err);
+ release_region(pmbase + 0xF0, 8);
goto out;
}
out:
@@ -149,6 +156,8 @@ out:
static void __exit mod_exit(void)
{
+ u32 pmbase = (unsigned long)amd_rng.priv;
+ release_region(pmbase + 0xF0, 8);
hwrng_unregister(&amd_rng);
}
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index d72433f2d310..6e40072fbf67 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -5,6 +5,9 @@
*
* Copyright (C) 2001 Massimo Dal Zotto <dz@debian.org>
*
+ * Hwmon integration:
+ * Copyright (C) 2011 Jean Delvare <khali@linux-fr.org>
+ *
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
@@ -24,6 +27,8 @@
#include <linux/dmi.h>
#include <linux/capability.h>
#include <linux/mutex.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -58,6 +63,7 @@
static DEFINE_MUTEX(i8k_mutex);
static char bios_version[4];
+static struct device *i8k_hwmon_dev;
MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)");
MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops");
@@ -139,8 +145,8 @@ static int i8k_smm(struct smm_regs *regs)
"movl %%edi,20(%%rax)\n\t"
"popq %%rdx\n\t"
"movl %%edx,0(%%rax)\n\t"
- "lahf\n\t"
- "shrl $8,%%eax\n\t"
+ "pushfq\n\t"
+ "popq %%rax\n\t"
"andl $1,%%eax\n"
:"=a"(rc)
: "a"(regs)
@@ -455,6 +461,152 @@ static int i8k_open_fs(struct inode *inode, struct file *file)
return single_open(file, i8k_proc_show, NULL);
}
+
+/*
+ * Hwmon interface
+ */
+
+static ssize_t i8k_hwmon_show_temp(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ int cpu_temp;
+
+ cpu_temp = i8k_get_temp(0);
+ if (cpu_temp < 0)
+ return cpu_temp;
+ return sprintf(buf, "%d\n", cpu_temp * 1000);
+}
+
+static ssize_t i8k_hwmon_show_fan(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ int index = to_sensor_dev_attr(devattr)->index;
+ int fan_speed;
+
+ fan_speed = i8k_get_fan_speed(index);
+ if (fan_speed < 0)
+ return fan_speed;
+ return sprintf(buf, "%d\n", fan_speed);
+}
+
+static ssize_t i8k_hwmon_show_label(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ static const char *labels[4] = {
+ "i8k",
+ "CPU",
+ "Left Fan",
+ "Right Fan",
+ };
+ int index = to_sensor_dev_attr(devattr)->index;
+
+ return sprintf(buf, "%s\n", labels[index]);
+}
+
+static DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL,
+ I8K_FAN_LEFT);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL,
+ I8K_FAN_RIGHT);
+static SENSOR_DEVICE_ATTR(name, S_IRUGO, i8k_hwmon_show_label, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_label, NULL, 3);
+
+static void i8k_hwmon_remove_files(struct device *dev)
+{
+ device_remove_file(dev, &dev_attr_temp1_input);
+ device_remove_file(dev, &sensor_dev_attr_fan1_input.dev_attr);
+ device_remove_file(dev, &sensor_dev_attr_fan2_input.dev_attr);
+ device_remove_file(dev, &sensor_dev_attr_temp1_label.dev_attr);
+ device_remove_file(dev, &sensor_dev_attr_fan1_label.dev_attr);
+ device_remove_file(dev, &sensor_dev_attr_fan2_label.dev_attr);
+ device_remove_file(dev, &sensor_dev_attr_name.dev_attr);
+}
+
+static int __init i8k_init_hwmon(void)
+{
+ int err;
+
+ i8k_hwmon_dev = hwmon_device_register(NULL);
+ if (IS_ERR(i8k_hwmon_dev)) {
+ err = PTR_ERR(i8k_hwmon_dev);
+ i8k_hwmon_dev = NULL;
+ printk(KERN_ERR "i8k: hwmon registration failed (%d)\n", err);
+ return err;
+ }
+
+ /* Required name attribute */
+ err = device_create_file(i8k_hwmon_dev,
+ &sensor_dev_attr_name.dev_attr);
+ if (err)
+ goto exit_unregister;
+
+ /* CPU temperature attributes, if temperature reading is OK */
+ err = i8k_get_temp(0);
+ if (err < 0) {
+ dev_dbg(i8k_hwmon_dev,
+ "Not creating temperature attributes (%d)\n", err);
+ } else {
+ err = device_create_file(i8k_hwmon_dev, &dev_attr_temp1_input);
+ if (err)
+ goto exit_remove_files;
+ err = device_create_file(i8k_hwmon_dev,
+ &sensor_dev_attr_temp1_label.dev_attr);
+ if (err)
+ goto exit_remove_files;
+ }
+
+ /* Left fan attributes, if left fan is present */
+ err = i8k_get_fan_status(I8K_FAN_LEFT);
+ if (err < 0) {
+ dev_dbg(i8k_hwmon_dev,
+ "Not creating %s fan attributes (%d)\n", "left", err);
+ } else {
+ err = device_create_file(i8k_hwmon_dev,
+ &sensor_dev_attr_fan1_input.dev_attr);
+ if (err)
+ goto exit_remove_files;
+ err = device_create_file(i8k_hwmon_dev,
+ &sensor_dev_attr_fan1_label.dev_attr);
+ if (err)
+ goto exit_remove_files;
+ }
+
+ /* Right fan attributes, if right fan is present */
+ err = i8k_get_fan_status(I8K_FAN_RIGHT);
+ if (err < 0) {
+ dev_dbg(i8k_hwmon_dev,
+ "Not creating %s fan attributes (%d)\n", "right", err);
+ } else {
+ err = device_create_file(i8k_hwmon_dev,
+ &sensor_dev_attr_fan2_input.dev_attr);
+ if (err)
+ goto exit_remove_files;
+ err = device_create_file(i8k_hwmon_dev,
+ &sensor_dev_attr_fan2_label.dev_attr);
+ if (err)
+ goto exit_remove_files;
+ }
+
+ return 0;
+
+ exit_remove_files:
+ i8k_hwmon_remove_files(i8k_hwmon_dev);
+ exit_unregister:
+ hwmon_device_unregister(i8k_hwmon_dev);
+ return err;
+}
+
+static void __exit i8k_exit_hwmon(void)
+{
+ i8k_hwmon_remove_files(i8k_hwmon_dev);
+ hwmon_device_unregister(i8k_hwmon_dev);
+}
+
static struct dmi_system_id __initdata i8k_dmi_table[] = {
{
.ident = "Dell Inspiron",
@@ -580,6 +732,7 @@ static int __init i8k_probe(void)
static int __init i8k_init(void)
{
struct proc_dir_entry *proc_i8k;
+ int err;
/* Are we running on an supported laptop? */
if (i8k_probe())
@@ -590,15 +743,24 @@ static int __init i8k_init(void)
if (!proc_i8k)
return -ENOENT;
+ err = i8k_init_hwmon();
+ if (err)
+ goto exit_remove_proc;
+
printk(KERN_INFO
"Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n",
I8K_VERSION);
return 0;
+
+ exit_remove_proc:
+ remove_proc_entry("i8k", NULL);
+ return err;
}
static void __exit i8k_exit(void)
{
+ i8k_exit_hwmon();
remove_proc_entry("i8k", NULL);
}
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 38223e93aa98..58c0e6387cf7 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -36,6 +36,7 @@
#include <asm/system.h>
#include <linux/poll.h>
#include <linux/sched.h>
+#include <linux/seq_file.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/slab.h>
@@ -1896,102 +1897,128 @@ int ipmi_request_supply_msgs(ipmi_user_t user,
EXPORT_SYMBOL(ipmi_request_supply_msgs);
#ifdef CONFIG_PROC_FS
-static int ipmb_file_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int smi_ipmb_proc_show(struct seq_file *m, void *v)
{
- char *out = (char *) page;
- ipmi_smi_t intf = data;
+ ipmi_smi_t intf = m->private;
int i;
- int rv = 0;
- for (i = 0; i < IPMI_MAX_CHANNELS; i++)
- rv += sprintf(out+rv, "%x ", intf->channels[i].address);
- out[rv-1] = '\n'; /* Replace the final space with a newline */
- out[rv] = '\0';
- rv++;
- return rv;
+ seq_printf(m, "%x", intf->channels[0].address);
+ for (i = 1; i < IPMI_MAX_CHANNELS; i++)
+ seq_printf(m, " %x", intf->channels[i].address);
+ return seq_putc(m, '\n');
}
-static int version_file_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int smi_ipmb_proc_open(struct inode *inode, struct file *file)
{
- char *out = (char *) page;
- ipmi_smi_t intf = data;
+ return single_open(file, smi_ipmb_proc_show, PDE(inode)->data);
+}
- return sprintf(out, "%u.%u\n",
+static const struct file_operations smi_ipmb_proc_ops = {
+ .open = smi_ipmb_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int smi_version_proc_show(struct seq_file *m, void *v)
+{
+ ipmi_smi_t intf = m->private;
+
+ return seq_printf(m, "%u.%u\n",
ipmi_version_major(&intf->bmc->id),
ipmi_version_minor(&intf->bmc->id));
}
-static int stat_file_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int smi_version_proc_open(struct inode *inode, struct file *file)
{
- char *out = (char *) page;
- ipmi_smi_t intf = data;
+ return single_open(file, smi_version_proc_show, PDE(inode)->data);
+}
+
+static const struct file_operations smi_version_proc_ops = {
+ .open = smi_version_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
- out += sprintf(out, "sent_invalid_commands: %u\n",
+static int smi_stats_proc_show(struct seq_file *m, void *v)
+{
+ ipmi_smi_t intf = m->private;
+
+ seq_printf(m, "sent_invalid_commands: %u\n",
ipmi_get_stat(intf, sent_invalid_commands));
- out += sprintf(out, "sent_local_commands: %u\n",
+ seq_printf(m, "sent_local_commands: %u\n",
ipmi_get_stat(intf, sent_local_commands));
- out += sprintf(out, "handled_local_responses: %u\n",
+ seq_printf(m, "handled_local_responses: %u\n",
ipmi_get_stat(intf, handled_local_responses));
- out += sprintf(out, "unhandled_local_responses: %u\n",
+ seq_printf(m, "unhandled_local_responses: %u\n",
ipmi_get_stat(intf, unhandled_local_responses));
- out += sprintf(out, "sent_ipmb_commands: %u\n",
+ seq_printf(m, "sent_ipmb_commands: %u\n",
ipmi_get_stat(intf, sent_ipmb_commands));
- out += sprintf(out, "sent_ipmb_command_errs: %u\n",
+ seq_printf(m, "sent_ipmb_command_errs: %u\n",
ipmi_get_stat(intf, sent_ipmb_command_errs));
- out += sprintf(out, "retransmitted_ipmb_commands: %u\n",
+ seq_printf(m, "retransmitted_ipmb_commands: %u\n",
ipmi_get_stat(intf, retransmitted_ipmb_commands));
- out += sprintf(out, "timed_out_ipmb_commands: %u\n",
+ seq_printf(m, "timed_out_ipmb_commands: %u\n",
ipmi_get_stat(intf, timed_out_ipmb_commands));
- out += sprintf(out, "timed_out_ipmb_broadcasts: %u\n",
+ seq_printf(m, "timed_out_ipmb_broadcasts: %u\n",
ipmi_get_stat(intf, timed_out_ipmb_broadcasts));
- out += sprintf(out, "sent_ipmb_responses: %u\n",
+ seq_printf(m, "sent_ipmb_responses: %u\n",
ipmi_get_stat(intf, sent_ipmb_responses));
- out += sprintf(out, "handled_ipmb_responses: %u\n",
+ seq_printf(m, "handled_ipmb_responses: %u\n",
ipmi_get_stat(intf, handled_ipmb_responses));
- out += sprintf(out, "invalid_ipmb_responses: %u\n",
+ seq_printf(m, "invalid_ipmb_responses: %u\n",
ipmi_get_stat(intf, invalid_ipmb_responses));
- out += sprintf(out, "unhandled_ipmb_responses: %u\n",
+ seq_printf(m, "unhandled_ipmb_responses: %u\n",
ipmi_get_stat(intf, unhandled_ipmb_responses));
- out += sprintf(out, "sent_lan_commands: %u\n",
+ seq_printf(m, "sent_lan_commands: %u\n",
ipmi_get_stat(intf, sent_lan_commands));
- out += sprintf(out, "sent_lan_command_errs: %u\n",
+ seq_printf(m, "sent_lan_command_errs: %u\n",
ipmi_get_stat(intf, sent_lan_command_errs));
- out += sprintf(out, "retransmitted_lan_commands: %u\n",
+ seq_printf(m, "retransmitted_lan_commands: %u\n",
ipmi_get_stat(intf, retransmitted_lan_commands));
- out += sprintf(out, "timed_out_lan_commands: %u\n",
+ seq_printf(m, "timed_out_lan_commands: %u\n",
ipmi_get_stat(intf, timed_out_lan_commands));
- out += sprintf(out, "sent_lan_responses: %u\n",
+ seq_printf(m, "sent_lan_responses: %u\n",
ipmi_get_stat(intf, sent_lan_responses));
- out += sprintf(out, "handled_lan_responses: %u\n",
+ seq_printf(m, "handled_lan_responses: %u\n",
ipmi_get_stat(intf, handled_lan_responses));
- out += sprintf(out, "invalid_lan_responses: %u\n",
+ seq_printf(m, "invalid_lan_responses: %u\n",
ipmi_get_stat(intf, invalid_lan_responses));
- out += sprintf(out, "unhandled_lan_responses: %u\n",
+ seq_printf(m, "unhandled_lan_responses: %u\n",
ipmi_get_stat(intf, unhandled_lan_responses));
- out += sprintf(out, "handled_commands: %u\n",
+ seq_printf(m, "handled_commands: %u\n",
ipmi_get_stat(intf, handled_commands));
- out += sprintf(out, "invalid_commands: %u\n",
+ seq_printf(m, "invalid_commands: %u\n",
ipmi_get_stat(intf, invalid_commands));
- out += sprintf(out, "unhandled_commands: %u\n",
+ seq_printf(m, "unhandled_commands: %u\n",
ipmi_get_stat(intf, unhandled_commands));
- out += sprintf(out, "invalid_events: %u\n",
+ seq_printf(m, "invalid_events: %u\n",
ipmi_get_stat(intf, invalid_events));
- out += sprintf(out, "events: %u\n",
+ seq_printf(m, "events: %u\n",
ipmi_get_stat(intf, events));
- out += sprintf(out, "failed rexmit LAN msgs: %u\n",
+ seq_printf(m, "failed rexmit LAN msgs: %u\n",
ipmi_get_stat(intf, dropped_rexmit_lan_commands));
- out += sprintf(out, "failed rexmit IPMB msgs: %u\n",
+ seq_printf(m, "failed rexmit IPMB msgs: %u\n",
ipmi_get_stat(intf, dropped_rexmit_ipmb_commands));
+ return 0;
+}
- return (out - ((char *) page));
+static int smi_stats_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, smi_stats_proc_show, PDE(inode)->data);
}
+
+static const struct file_operations smi_stats_proc_ops = {
+ .open = smi_stats_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
#endif /* CONFIG_PROC_FS */
int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
- read_proc_t *read_proc,
+ const struct file_operations *proc_ops,
void *data)
{
int rv = 0;
@@ -2010,15 +2037,12 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
}
strcpy(entry->name, name);
- file = create_proc_entry(name, 0, smi->proc_dir);
+ file = proc_create_data(name, 0, smi->proc_dir, proc_ops, data);
if (!file) {
kfree(entry->name);
kfree(entry);
rv = -ENOMEM;
} else {
- file->data = data;
- file->read_proc = read_proc;
-
mutex_lock(&smi->proc_entry_lock);
/* Stick it on the list. */
entry->next = smi->proc_entries;
@@ -2043,17 +2067,17 @@ static int add_proc_entries(ipmi_smi_t smi, int num)
if (rv == 0)
rv = ipmi_smi_add_proc_entry(smi, "stats",
- stat_file_read_proc,
+ &smi_stats_proc_ops,
smi);
if (rv == 0)
rv = ipmi_smi_add_proc_entry(smi, "ipmb",
- ipmb_file_read_proc,
+ &smi_ipmb_proc_ops,
smi);
if (rv == 0)
rv = ipmi_smi_add_proc_entry(smi, "version",
- version_file_read_proc,
+ &smi_version_proc_ops,
smi);
#endif /* CONFIG_PROC_FS */
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 64c6b8530615..9397ab49b72e 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -43,6 +43,7 @@
#include <linux/moduleparam.h>
#include <asm/system.h>
#include <linux/sched.h>
+#include <linux/seq_file.h>
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/spinlock.h>
@@ -2805,54 +2806,73 @@ static int try_enable_event_buffer(struct smi_info *smi_info)
return rv;
}
-static int type_file_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int smi_type_proc_show(struct seq_file *m, void *v)
{
- struct smi_info *smi = data;
+ struct smi_info *smi = m->private;
- return sprintf(page, "%s\n", si_to_str[smi->si_type]);
+ return seq_printf(m, "%s\n", si_to_str[smi->si_type]);
}
-static int stat_file_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static int smi_type_proc_open(struct inode *inode, struct file *file)
{
- char *out = (char *) page;
- struct smi_info *smi = data;
+ return single_open(file, smi_type_proc_show, PDE(inode)->data);
+}
+
+static const struct file_operations smi_type_proc_ops = {
+ .open = smi_type_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int smi_si_stats_proc_show(struct seq_file *m, void *v)
+{
+ struct smi_info *smi = m->private;
- out += sprintf(out, "interrupts_enabled: %d\n",
+ seq_printf(m, "interrupts_enabled: %d\n",
smi->irq && !smi->interrupt_disabled);
- out += sprintf(out, "short_timeouts: %u\n",
+ seq_printf(m, "short_timeouts: %u\n",
smi_get_stat(smi, short_timeouts));
- out += sprintf(out, "long_timeouts: %u\n",
+ seq_printf(m, "long_timeouts: %u\n",
smi_get_stat(smi, long_timeouts));
- out += sprintf(out, "idles: %u\n",
+ seq_printf(m, "idles: %u\n",
smi_get_stat(smi, idles));
- out += sprintf(out, "interrupts: %u\n",
+ seq_printf(m, "interrupts: %u\n",
smi_get_stat(smi, interrupts));
- out += sprintf(out, "attentions: %u\n",
+ seq_printf(m, "attentions: %u\n",
smi_get_stat(smi, attentions));
- out += sprintf(out, "flag_fetches: %u\n",
+ seq_printf(m, "flag_fetches: %u\n",
smi_get_stat(smi, flag_fetches));
- out += sprintf(out, "hosed_count: %u\n",
+ seq_printf(m, "hosed_count: %u\n",
smi_get_stat(smi, hosed_count));
- out += sprintf(out, "complete_transactions: %u\n",
+ seq_printf(m, "complete_transactions: %u\n",
smi_get_stat(smi, complete_transactions));
- out += sprintf(out, "events: %u\n",
+ seq_printf(m, "events: %u\n",
smi_get_stat(smi, events));
- out += sprintf(out, "watchdog_pretimeouts: %u\n",
+ seq_printf(m, "watchdog_pretimeouts: %u\n",
smi_get_stat(smi, watchdog_pretimeouts));
- out += sprintf(out, "incoming_messages: %u\n",
+ seq_printf(m, "incoming_messages: %u\n",
smi_get_stat(smi, incoming_messages));
+ return 0;
+}
- return out - page;
+static int smi_si_stats_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, smi_si_stats_proc_show, PDE(inode)->data);
}
-static int param_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static const struct file_operations smi_si_stats_proc_ops = {
+ .open = smi_si_stats_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int smi_params_proc_show(struct seq_file *m, void *v)
{
- struct smi_info *smi = data;
+ struct smi_info *smi = m->private;
- return sprintf(page,
+ return seq_printf(m,
"%s,%s,0x%lx,rsp=%d,rsi=%d,rsh=%d,irq=%d,ipmb=%d\n",
si_to_str[smi->si_type],
addr_space_to_str[smi->io.addr_type],
@@ -2864,6 +2884,18 @@ static int param_read_proc(char *page, char **start, off_t off,
smi->slave_addr);
}
+static int smi_params_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, smi_params_proc_show, PDE(inode)->data);
+}
+
+static const struct file_operations smi_params_proc_ops = {
+ .open = smi_params_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
/*
* oem_data_avail_to_receive_msg_avail
* @info - smi_info structure with msg_flags set
@@ -3257,7 +3289,7 @@ static int try_smi_init(struct smi_info *new_smi)
}
rv = ipmi_smi_add_proc_entry(new_smi->intf, "type",
- type_file_read_proc,
+ &smi_type_proc_ops,
new_smi);
if (rv) {
dev_err(new_smi->dev, "Unable to create proc entry: %d\n", rv);
@@ -3265,7 +3297,7 @@ static int try_smi_init(struct smi_info *new_smi)
}
rv = ipmi_smi_add_proc_entry(new_smi->intf, "si_stats",
- stat_file_read_proc,
+ &smi_si_stats_proc_ops,
new_smi);
if (rv) {
dev_err(new_smi->dev, "Unable to create proc entry: %d\n", rv);
@@ -3273,7 +3305,7 @@ static int try_smi_init(struct smi_info *new_smi)
}
rv = ipmi_smi_add_proc_entry(new_smi->intf, "params",
- param_read_proc,
+ &smi_params_proc_ops,
new_smi);
if (rv) {
dev_err(new_smi->dev, "Unable to create proc entry: %d\n", rv);
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 436a99017998..8fc04b4f311f 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -806,29 +806,41 @@ static const struct file_operations oldmem_fops = {
};
#endif
-static ssize_t kmsg_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
+static ssize_t kmsg_writev(struct kiocb *iocb, const struct iovec *iv,
+ unsigned long count, loff_t pos)
{
- char *tmp;
- ssize_t ret;
+ char *line, *p;
+ int i;
+ ssize_t ret = -EFAULT;
+ size_t len = iov_length(iv, count);
- tmp = kmalloc(count + 1, GFP_KERNEL);
- if (tmp == NULL)
+ line = kmalloc(len + 1, GFP_KERNEL);
+ if (line == NULL)
return -ENOMEM;
- ret = -EFAULT;
- if (!copy_from_user(tmp, buf, count)) {
- tmp[count] = 0;
- ret = printk("%s", tmp);
- if (ret > count)
- /* printk can add a prefix */
- ret = count;
+
+ /*
+ * copy all vectors into a single string, to ensure we do
+ * not interleave our log line with other printk calls
+ */
+ p = line;
+ for (i = 0; i < count; i++) {
+ if (copy_from_user(p, iv[i].iov_base, iv[i].iov_len))
+ goto out;
+ p += iv[i].iov_len;
}
- kfree(tmp);
+ p[0] = '\0';
+
+ ret = printk("%s", line);
+ /* printk can add a prefix */
+ if (ret > len)
+ ret = len;
+out:
+ kfree(line);
return ret;
}
static const struct file_operations kmsg_fops = {
- .write = kmsg_write,
+ .aio_write = kmsg_writev,
.llseek = noop_llseek,
};
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c
index 966a95bc974b..25d139c9dbed 100644
--- a/drivers/char/mspec.c
+++ b/drivers/char/mspec.c
@@ -271,14 +271,13 @@ mspec_mmap(struct file *file, struct vm_area_struct *vma,
pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
vdata_size = sizeof(struct vma_data) + pages * sizeof(long);
if (vdata_size <= PAGE_SIZE)
- vdata = kmalloc(vdata_size, GFP_KERNEL);
+ vdata = kzalloc(vdata_size, GFP_KERNEL);
else {
- vdata = vmalloc(vdata_size);
+ vdata = vzalloc(vdata_size);
flags = VMD_VMALLOCED;
}
if (!vdata)
return -ENOMEM;
- memset(vdata, 0, vdata_size);
vdata->vm_start = vma->vm_start;
vdata->vm_end = vma->vm_end;
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index 90bd01671c70..a7584860e9a7 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -1869,7 +1869,7 @@ static const struct file_operations cm4000_fops = {
.llseek = no_llseek,
};
-static struct pcmcia_device_id cm4000_ids[] = {
+static const struct pcmcia_device_id cm4000_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x0223, 0x0002),
PCMCIA_DEVICE_PROD_ID12("CardMan", "4000", 0x2FB368CA, 0xA2BD8C39),
PCMCIA_DEVICE_NULL,
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index 5d8d59e865f4..8dd48a2be911 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -633,7 +633,7 @@ static const struct file_operations reader_fops = {
.llseek = no_llseek,
};
-static struct pcmcia_device_id cm4040_ids[] = {
+static const struct pcmcia_device_id cm4040_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x0223, 0x0200),
PCMCIA_DEVICE_PROD_ID12("OMNIKEY", "CardMan 4040",
0xE32CDD8C, 0x8F23318B),
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index b575411c69b2..15781396af25 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -2758,7 +2758,7 @@ static void mgslpc_remove_device(MGSLPC_INFO *remove_info)
}
}
-static struct pcmcia_device_id mgslpc_ids[] = {
+static const struct pcmcia_device_id mgslpc_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x02c5, 0x0050),
PCMCIA_DEVICE_NULL
};
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index f176dbaeb15a..3fcf80ff12f2 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -457,6 +457,7 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return -ENODEV;
modes = port->modes;
+ parport_put_port(port);
if (copy_to_user (argp, &modes, sizeof (modes))) {
return -EFAULT;
}
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index b4b9d5a47885..b33e8ea314ed 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -21,6 +21,7 @@
#include <linux/mutex.h>
#include <linux/gfp.h>
#include <linux/compat.h>
+#include <linux/vmalloc.h>
#include <asm/uaccess.h>
@@ -30,10 +31,15 @@ struct raw_device_data {
};
static struct class *raw_class;
-static struct raw_device_data raw_devices[MAX_RAW_MINORS];
+static struct raw_device_data *raw_devices;
static DEFINE_MUTEX(raw_mutex);
static const struct file_operations raw_ctl_fops; /* forward declaration */
+static int max_raw_minors = MAX_RAW_MINORS;
+
+module_param(max_raw_minors, int, 0);
+MODULE_PARM_DESC(max_raw_minors, "Maximum number of raw devices (1-65536)");
+
/*
* Open/close code for raw IO.
*
@@ -125,7 +131,7 @@ static int bind_set(int number, u64 major, u64 minor)
struct raw_device_data *rawdev;
int err = 0;
- if (number <= 0 || number >= MAX_RAW_MINORS)
+ if (number <= 0 || number >= max_raw_minors)
return -EINVAL;
if (MAJOR(dev) != major || MINOR(dev) != minor)
@@ -312,14 +318,27 @@ static int __init raw_init(void)
dev_t dev = MKDEV(RAW_MAJOR, 0);
int ret;
- ret = register_chrdev_region(dev, MAX_RAW_MINORS, "raw");
+ if (max_raw_minors < 1 || max_raw_minors > 65536) {
+ printk(KERN_WARNING "raw: invalid max_raw_minors (must be"
+ " between 1 and 65536), using %d\n", MAX_RAW_MINORS);
+ max_raw_minors = MAX_RAW_MINORS;
+ }
+
+ raw_devices = vmalloc(sizeof(struct raw_device_data) * max_raw_minors);
+ if (!raw_devices) {
+ printk(KERN_ERR "Not enough memory for raw device structures\n");
+ ret = -ENOMEM;
+ goto error;
+ }
+ memset(raw_devices, 0, sizeof(struct raw_device_data) * max_raw_minors);
+
+ ret = register_chrdev_region(dev, max_raw_minors, "raw");
if (ret)
goto error;
cdev_init(&raw_cdev, &raw_fops);
- ret = cdev_add(&raw_cdev, dev, MAX_RAW_MINORS);
+ ret = cdev_add(&raw_cdev, dev, max_raw_minors);
if (ret) {
- kobject_put(&raw_cdev.kobj);
goto error_region;
}
@@ -336,8 +355,9 @@ static int __init raw_init(void)
return 0;
error_region:
- unregister_chrdev_region(dev, MAX_RAW_MINORS);
+ unregister_chrdev_region(dev, max_raw_minors);
error:
+ vfree(raw_devices);
return ret;
}
@@ -346,7 +366,7 @@ static void __exit raw_exit(void)
device_destroy(raw_class, MKDEV(RAW_MAJOR, 0));
class_destroy(raw_class);
cdev_del(&raw_cdev);
- unregister_chrdev_region(MKDEV(RAW_MAJOR, 0), MAX_RAW_MINORS);
+ unregister_chrdev_region(MKDEV(RAW_MAJOR, 0), max_raw_minors);
}
module_init(raw_init);
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
new file mode 100644
index 000000000000..96c921910469
--- /dev/null
+++ b/drivers/clocksource/Kconfig
@@ -0,0 +1,5 @@
+config CLKSRC_I8253
+ bool
+
+config CLKSRC_MMIO
+ bool
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index be61ece6330b..b995942a5060 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -6,3 +6,5 @@ obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC) += cs5535-clockevt.o
obj-$(CONFIG_SH_TIMER_CMT) += sh_cmt.o
obj-$(CONFIG_SH_TIMER_MTU2) += sh_mtu2.o
obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o
+obj-$(CONFIG_CLKSRC_I8253) += i8253.o
+obj-$(CONFIG_CLKSRC_MMIO) += mmio.o
diff --git a/drivers/clocksource/cyclone.c b/drivers/clocksource/cyclone.c
index 64e528e8bfa6..72f811f73e9c 100644
--- a/drivers/clocksource/cyclone.c
+++ b/drivers/clocksource/cyclone.c
@@ -29,8 +29,6 @@ static struct clocksource clocksource_cyclone = {
.rating = 250,
.read = read_cyclone,
.mask = CYCLONE_TIMER_MASK,
- .mult = 10,
- .shift = 0,
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
@@ -108,12 +106,8 @@ static int __init init_cyclone_clocksource(void)
}
cyclone_ptr = cyclone_timer;
- /* sort out mult/shift values: */
- clocksource_cyclone.shift = 22;
- clocksource_cyclone.mult = clocksource_hz2mult(CYCLONE_TIMER_FREQ,
- clocksource_cyclone.shift);
-
- return clocksource_register(&clocksource_cyclone);
+ return clocksource_register_hz(&clocksource_cyclone,
+ CYCLONE_TIMER_FREQ);
}
arch_initcall(init_cyclone_clocksource);
diff --git a/drivers/clocksource/i8253.c b/drivers/clocksource/i8253.c
new file mode 100644
index 000000000000..225c1761b372
--- /dev/null
+++ b/drivers/clocksource/i8253.c
@@ -0,0 +1,88 @@
+/*
+ * i8253 PIT clocksource
+ */
+#include <linux/clocksource.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/timex.h>
+
+#include <asm/i8253.h>
+
+/*
+ * Since the PIT overflows every tick, its not very useful
+ * to just read by itself. So use jiffies to emulate a free
+ * running counter:
+ */
+static cycle_t i8253_read(struct clocksource *cs)
+{
+ static int old_count;
+ static u32 old_jifs;
+ unsigned long flags;
+ int count;
+ u32 jifs;
+
+ raw_spin_lock_irqsave(&i8253_lock, flags);
+ /*
+ * Although our caller may have the read side of xtime_lock,
+ * this is now a seqlock, and we are cheating in this routine
+ * by having side effects on state that we cannot undo if
+ * there is a collision on the seqlock and our caller has to
+ * retry. (Namely, old_jifs and old_count.) So we must treat
+ * jiffies as volatile despite the lock. We read jiffies
+ * before latching the timer count to guarantee that although
+ * the jiffies value might be older than the count (that is,
+ * the counter may underflow between the last point where
+ * jiffies was incremented and the point where we latch the
+ * count), it cannot be newer.
+ */
+ jifs = jiffies;
+ outb_pit(0x00, PIT_MODE); /* latch the count ASAP */
+ count = inb_pit(PIT_CH0); /* read the latched count */
+ count |= inb_pit(PIT_CH0) << 8;
+
+ /* VIA686a test code... reset the latch if count > max + 1 */
+ if (count > LATCH) {
+ outb_pit(0x34, PIT_MODE);
+ outb_pit(PIT_LATCH & 0xff, PIT_CH0);
+ outb_pit(PIT_LATCH >> 8, PIT_CH0);
+ count = PIT_LATCH - 1;
+ }
+
+ /*
+ * It's possible for count to appear to go the wrong way for a
+ * couple of reasons:
+ *
+ * 1. The timer counter underflows, but we haven't handled the
+ * resulting interrupt and incremented jiffies yet.
+ * 2. Hardware problem with the timer, not giving us continuous time,
+ * the counter does small "jumps" upwards on some Pentium systems,
+ * (see c't 95/10 page 335 for Neptun bug.)
+ *
+ * Previous attempts to handle these cases intelligently were
+ * buggy, so we just do the simple thing now.
+ */
+ if (count > old_count && jifs == old_jifs)
+ count = old_count;
+
+ old_count = count;
+ old_jifs = jifs;
+
+ raw_spin_unlock_irqrestore(&i8253_lock, flags);
+
+ count = (PIT_LATCH - 1) - count;
+
+ return (cycle_t)(jifs * PIT_LATCH) + count;
+}
+
+static struct clocksource i8253_cs = {
+ .name = "pit",
+ .rating = 110,
+ .read = i8253_read,
+ .mask = CLOCKSOURCE_MASK(32),
+};
+
+int __init clocksource_i8253_init(void)
+{
+ return clocksource_register_hz(&i8253_cs, PIT_TICK_RATE);
+}
diff --git a/drivers/clocksource/mmio.c b/drivers/clocksource/mmio.c
new file mode 100644
index 000000000000..c0e25125a55e
--- /dev/null
+++ b/drivers/clocksource/mmio.c
@@ -0,0 +1,73 @@
+/*
+ * Generic MMIO clocksource support
+ *
+ * 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/clocksource.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+
+struct clocksource_mmio {
+ void __iomem *reg;
+ struct clocksource clksrc;
+};
+
+static inline struct clocksource_mmio *to_mmio_clksrc(struct clocksource *c)
+{
+ return container_of(c, struct clocksource_mmio, clksrc);
+}
+
+cycle_t clocksource_mmio_readl_up(struct clocksource *c)
+{
+ return readl_relaxed(to_mmio_clksrc(c)->reg);
+}
+
+cycle_t clocksource_mmio_readl_down(struct clocksource *c)
+{
+ return ~readl_relaxed(to_mmio_clksrc(c)->reg);
+}
+
+cycle_t clocksource_mmio_readw_up(struct clocksource *c)
+{
+ return readw_relaxed(to_mmio_clksrc(c)->reg);
+}
+
+cycle_t clocksource_mmio_readw_down(struct clocksource *c)
+{
+ return ~(unsigned)readw_relaxed(to_mmio_clksrc(c)->reg);
+}
+
+/**
+ * clocksource_mmio_init - Initialize a simple mmio based clocksource
+ * @base: Virtual address of the clock readout register
+ * @name: Name of the clocksource
+ * @hz: Frequency of the clocksource in Hz
+ * @rating: Rating of the clocksource
+ * @bits: Number of valid bits
+ * @read: One of clocksource_mmio_read*() above
+ */
+int __init clocksource_mmio_init(void __iomem *base, const char *name,
+ unsigned long hz, int rating, unsigned bits,
+ cycle_t (*read)(struct clocksource *))
+{
+ struct clocksource_mmio *cs;
+
+ if (bits > 32 || bits < 16)
+ return -EINVAL;
+
+ cs = kzalloc(sizeof(struct clocksource_mmio), GFP_KERNEL);
+ if (!cs)
+ return -ENOMEM;
+
+ cs->reg = base;
+ cs->clksrc.name = name;
+ cs->clksrc.rating = rating;
+ cs->clksrc.read = read;
+ cs->clksrc.mask = CLOCKSOURCE_MASK(bits);
+ cs->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS;
+
+ return clocksource_register_hz(&cs->clksrc, hz);
+}
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
index f975d24890fa..036e5865eb40 100644
--- a/drivers/clocksource/sh_cmt.c
+++ b/drivers/clocksource/sh_cmt.c
@@ -24,6 +24,7 @@
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/clk.h>
+#include <linux/pm_runtime.h>
#include <linux/irq.h>
#include <linux/err.h>
#include <linux/clocksource.h>
@@ -152,10 +153,12 @@ static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate)
{
int ret;
- /* enable clock */
+ /* wake up device and enable clock */
+ pm_runtime_get_sync(&p->pdev->dev);
ret = clk_enable(p->clk);
if (ret) {
dev_err(&p->pdev->dev, "cannot enable clock\n");
+ pm_runtime_put_sync(&p->pdev->dev);
return ret;
}
@@ -187,8 +190,9 @@ static void sh_cmt_disable(struct sh_cmt_priv *p)
/* disable interrupts in CMT block */
sh_cmt_write(p, CMCSR, 0);
- /* stop clock */
+ /* stop clock and mark device as idle */
clk_disable(p->clk);
+ pm_runtime_put_sync(&p->pdev->dev);
}
/* private flags */
@@ -416,11 +420,15 @@ static cycle_t sh_cmt_clocksource_read(struct clocksource *cs)
static int sh_cmt_clocksource_enable(struct clocksource *cs)
{
+ int ret;
struct sh_cmt_priv *p = cs_to_sh_cmt(cs);
p->total_cycles = 0;
- return sh_cmt_start(p, FLAG_CLOCKSOURCE);
+ ret = sh_cmt_start(p, FLAG_CLOCKSOURCE);
+ if (!ret)
+ __clocksource_updatefreq_hz(cs, p->rate);
+ return ret;
}
static void sh_cmt_clocksource_disable(struct clocksource *cs)
@@ -448,19 +456,10 @@ static int sh_cmt_register_clocksource(struct sh_cmt_priv *p,
cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
- /* clk_get_rate() needs an enabled clock */
- clk_enable(p->clk);
- p->rate = clk_get_rate(p->clk) / ((p->width == 16) ? 512 : 8);
- clk_disable(p->clk);
-
- /* TODO: calculate good shift from rate and counter bit width */
- cs->shift = 0;
- cs->mult = clocksource_hz2mult(p->rate, cs->shift);
-
dev_info(&p->pdev->dev, "used as clock source\n");
- clocksource_register(cs);
-
+ /* Register with dummy 1 Hz value, gets updated in ->enable() */
+ clocksource_register_hz(cs, 1);
return 0;
}
@@ -665,6 +664,7 @@ static int __devinit sh_cmt_probe(struct platform_device *pdev)
if (p) {
dev_info(&pdev->dev, "kept as earlytimer\n");
+ pm_runtime_enable(&pdev->dev);
return 0;
}
@@ -679,6 +679,9 @@ static int __devinit sh_cmt_probe(struct platform_device *pdev)
kfree(p);
platform_set_drvdata(pdev, NULL);
}
+
+ if (!is_early_platform_device(pdev))
+ pm_runtime_enable(&pdev->dev);
return ret;
}
diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c
index 36aba9923060..17296288a205 100644
--- a/drivers/clocksource/sh_tmu.c
+++ b/drivers/clocksource/sh_tmu.c
@@ -25,6 +25,7 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/clk.h>
+#include <linux/pm_runtime.h>
#include <linux/irq.h>
#include <linux/err.h>
#include <linux/clocksource.h>
@@ -109,10 +110,12 @@ static int sh_tmu_enable(struct sh_tmu_priv *p)
{
int ret;
- /* enable clock */
+ /* wake up device and enable clock */
+ pm_runtime_get_sync(&p->pdev->dev);
ret = clk_enable(p->clk);
if (ret) {
dev_err(&p->pdev->dev, "cannot enable clock\n");
+ pm_runtime_put_sync(&p->pdev->dev);
return ret;
}
@@ -141,8 +144,9 @@ static void sh_tmu_disable(struct sh_tmu_priv *p)
/* disable interrupts in TMU block */
sh_tmu_write(p, TCR, 0x0000);
- /* stop clock */
+ /* stop clock and mark device as idle */
clk_disable(p->clk);
+ pm_runtime_put_sync(&p->pdev->dev);
}
static void sh_tmu_set_next(struct sh_tmu_priv *p, unsigned long delta,
@@ -199,8 +203,12 @@ static cycle_t sh_tmu_clocksource_read(struct clocksource *cs)
static int sh_tmu_clocksource_enable(struct clocksource *cs)
{
struct sh_tmu_priv *p = cs_to_sh_tmu(cs);
+ int ret;
- return sh_tmu_enable(p);
+ ret = sh_tmu_enable(p);
+ if (!ret)
+ __clocksource_updatefreq_hz(cs, p->rate);
+ return ret;
}
static void sh_tmu_clocksource_disable(struct clocksource *cs)
@@ -221,17 +229,10 @@ static int sh_tmu_register_clocksource(struct sh_tmu_priv *p,
cs->mask = CLOCKSOURCE_MASK(32);
cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
- /* clk_get_rate() needs an enabled clock */
- clk_enable(p->clk);
- /* channel will be configured at parent clock / 4 */
- p->rate = clk_get_rate(p->clk) / 4;
- clk_disable(p->clk);
- /* TODO: calculate good shift from rate and counter bit width */
- cs->shift = 10;
- cs->mult = clocksource_hz2mult(p->rate, cs->shift);
-
dev_info(&p->pdev->dev, "used as clock source\n");
- clocksource_register(cs);
+
+ /* Register with dummy 1 Hz value, gets updated in ->enable() */
+ clocksource_register_hz(cs, 1);
return 0;
}
@@ -414,6 +415,7 @@ static int __devinit sh_tmu_probe(struct platform_device *pdev)
if (p) {
dev_info(&pdev->dev, "kept as earlytimer\n");
+ pm_runtime_enable(&pdev->dev);
return 0;
}
@@ -428,6 +430,9 @@ static int __devinit sh_tmu_probe(struct platform_device *pdev)
kfree(p);
platform_set_drvdata(pdev, NULL);
}
+
+ if (!is_early_platform_device(pdev))
+ pm_runtime_enable(&pdev->dev);
return ret;
}
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index ca8ee8093d6c..9fb84853d8e3 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -1,3 +1,5 @@
+menu "CPU Frequency scaling"
+
config CPU_FREQ
bool "CPU Frequency scaling"
help
@@ -18,19 +20,6 @@ if CPU_FREQ
config CPU_FREQ_TABLE
tristate
-config CPU_FREQ_DEBUG
- bool "Enable CPUfreq debugging"
- help
- Say Y here to enable CPUfreq subsystem (including drivers)
- debugging. You will need to activate it via the kernel
- command line by passing
- cpufreq.debug=<value>
-
- To get <value>, add
- 1 to activate CPUfreq core debugging,
- 2 to activate CPUfreq drivers debugging, and
- 4 to activate CPUfreq governor debugging
-
config CPU_FREQ_STAT
tristate "CPU frequency translation statistics"
select CPU_FREQ_TABLE
@@ -190,4 +179,10 @@ config CPU_FREQ_GOV_CONSERVATIVE
If in doubt, say N.
-endif # CPU_FREQ
+menu "x86 CPU frequency scaling drivers"
+depends on X86
+source "drivers/cpufreq/Kconfig.x86"
+endmenu
+
+endif
+endmenu
diff --git a/arch/x86/kernel/cpu/cpufreq/Kconfig b/drivers/cpufreq/Kconfig.x86
index 870e6cc6ad28..78ff7ee48951 100644
--- a/arch/x86/kernel/cpu/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig.x86
@@ -1,15 +1,7 @@
#
-# CPU Frequency scaling
+# x86 CPU Frequency scaling drivers
#
-menu "CPU Frequency scaling"
-
-source "drivers/cpufreq/Kconfig"
-
-if CPU_FREQ
-
-comment "CPUFreq processor drivers"
-
config X86_PCC_CPUFREQ
tristate "Processor Clocking Control interface driver"
depends on ACPI && ACPI_PROCESSOR
@@ -43,7 +35,7 @@ config X86_ACPI_CPUFREQ
config ELAN_CPUFREQ
tristate "AMD Elan SC400 and SC410"
select CPU_FREQ_TABLE
- depends on X86_ELAN
+ depends on MELAN
---help---
This adds the CPUFreq driver for AMD Elan SC400 and SC410
processors.
@@ -59,7 +51,7 @@ config ELAN_CPUFREQ
config SC520_CPUFREQ
tristate "AMD Elan SC520"
select CPU_FREQ_TABLE
- depends on X86_ELAN
+ depends on MELAN
---help---
This adds the CPUFreq driver for AMD Elan SC520 processor.
@@ -261,6 +253,3 @@ config X86_SPEEDSTEP_RELAXED_CAP_CHECK
option lets the probing code bypass some of those checks if the
parameter "relaxed_check=1" is passed to the module.
-endif # CPU_FREQ
-
-endmenu
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 71fc3b4173f1..e2fc2d21fa61 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -13,3 +13,31 @@ obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o
# CPUfreq cross-arch helpers
obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o
+##################################################################################d
+# x86 drivers.
+# Link order matters. K8 is preferred to ACPI because of firmware bugs in early
+# K8 systems. ACPI is preferred to all other hardware-specific drivers.
+# speedstep-* is preferred over p4-clockmod.
+
+obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o mperf.o
+obj-$(CONFIG_X86_ACPI_CPUFREQ) += acpi-cpufreq.o mperf.o
+obj-$(CONFIG_X86_PCC_CPUFREQ) += pcc-cpufreq.o
+obj-$(CONFIG_X86_POWERNOW_K6) += powernow-k6.o
+obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o
+obj-$(CONFIG_X86_LONGHAUL) += longhaul.o
+obj-$(CONFIG_X86_E_POWERSAVER) += e_powersaver.o
+obj-$(CONFIG_ELAN_CPUFREQ) += elanfreq.o
+obj-$(CONFIG_SC520_CPUFREQ) += sc520_freq.o
+obj-$(CONFIG_X86_LONGRUN) += longrun.o
+obj-$(CONFIG_X86_GX_SUSPMOD) += gx-suspmod.o
+obj-$(CONFIG_X86_SPEEDSTEP_ICH) += speedstep-ich.o
+obj-$(CONFIG_X86_SPEEDSTEP_LIB) += speedstep-lib.o
+obj-$(CONFIG_X86_SPEEDSTEP_SMI) += speedstep-smi.o
+obj-$(CONFIG_X86_SPEEDSTEP_CENTRINO) += speedstep-centrino.o
+obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o
+obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o
+
+##################################################################################d
+
+# ARM SoC drivers
+obj-$(CONFIG_UX500_SOC_DB8500) += db8500-cpufreq.o
diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index a2baafb2fe6d..4e04e1274388 100644
--- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -47,9 +47,6 @@
#include <asm/cpufeature.h>
#include "mperf.h"
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
- "acpi-cpufreq", msg)
-
MODULE_AUTHOR("Paul Diefenbaugh, Dominik Brodowski");
MODULE_DESCRIPTION("ACPI Processor P-States Driver");
MODULE_LICENSE("GPL");
@@ -233,7 +230,7 @@ static u32 get_cur_val(const struct cpumask *mask)
cmd.mask = mask;
drv_read(&cmd);
- dprintk("get_cur_val = %u\n", cmd.val);
+ pr_debug("get_cur_val = %u\n", cmd.val);
return cmd.val;
}
@@ -244,7 +241,7 @@ static unsigned int get_cur_freq_on_cpu(unsigned int cpu)
unsigned int freq;
unsigned int cached_freq;
- dprintk("get_cur_freq_on_cpu (%d)\n", cpu);
+ pr_debug("get_cur_freq_on_cpu (%d)\n", cpu);
if (unlikely(data == NULL ||
data->acpi_data == NULL || data->freq_table == NULL)) {
@@ -261,7 +258,7 @@ static unsigned int get_cur_freq_on_cpu(unsigned int cpu)
data->resume = 1;
}
- dprintk("cur freq = %u\n", freq);
+ pr_debug("cur freq = %u\n", freq);
return freq;
}
@@ -293,7 +290,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
unsigned int i;
int result = 0;
- dprintk("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu);
+ pr_debug("acpi_cpufreq_target %d (%d)\n", target_freq, policy->cpu);
if (unlikely(data == NULL ||
data->acpi_data == NULL || data->freq_table == NULL)) {
@@ -313,11 +310,11 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
next_perf_state = data->freq_table[next_state].index;
if (perf->state == next_perf_state) {
if (unlikely(data->resume)) {
- dprintk("Called after resume, resetting to P%d\n",
+ pr_debug("Called after resume, resetting to P%d\n",
next_perf_state);
data->resume = 0;
} else {
- dprintk("Already at target state (P%d)\n",
+ pr_debug("Already at target state (P%d)\n",
next_perf_state);
goto out;
}
@@ -357,7 +354,7 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy,
if (acpi_pstate_strict) {
if (!check_freqs(cmd.mask, freqs.new, data)) {
- dprintk("acpi_cpufreq_target failed (%d)\n",
+ pr_debug("acpi_cpufreq_target failed (%d)\n",
policy->cpu);
result = -EAGAIN;
goto out;
@@ -378,7 +375,7 @@ static int acpi_cpufreq_verify(struct cpufreq_policy *policy)
{
struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
- dprintk("acpi_cpufreq_verify\n");
+ pr_debug("acpi_cpufreq_verify\n");
return cpufreq_frequency_table_verify(policy, data->freq_table);
}
@@ -433,11 +430,11 @@ static void free_acpi_perf_data(void)
static int __init acpi_cpufreq_early_init(void)
{
unsigned int i;
- dprintk("acpi_cpufreq_early_init\n");
+ pr_debug("acpi_cpufreq_early_init\n");
acpi_perf_data = alloc_percpu(struct acpi_processor_performance);
if (!acpi_perf_data) {
- dprintk("Memory allocation error for acpi_perf_data.\n");
+ pr_debug("Memory allocation error for acpi_perf_data.\n");
return -ENOMEM;
}
for_each_possible_cpu(i) {
@@ -519,7 +516,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
static int blacklisted;
#endif
- dprintk("acpi_cpufreq_cpu_init\n");
+ pr_debug("acpi_cpufreq_cpu_init\n");
#ifdef CONFIG_SMP
if (blacklisted)
@@ -566,7 +563,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
/* capability check */
if (perf->state_count <= 1) {
- dprintk("No P-States\n");
+ pr_debug("No P-States\n");
result = -ENODEV;
goto err_unreg;
}
@@ -578,11 +575,11 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
switch (perf->control_register.space_id) {
case ACPI_ADR_SPACE_SYSTEM_IO:
- dprintk("SYSTEM IO addr space\n");
+ pr_debug("SYSTEM IO addr space\n");
data->cpu_feature = SYSTEM_IO_CAPABLE;
break;
case ACPI_ADR_SPACE_FIXED_HARDWARE:
- dprintk("HARDWARE addr space\n");
+ pr_debug("HARDWARE addr space\n");
if (!check_est_cpu(cpu)) {
result = -ENODEV;
goto err_unreg;
@@ -590,7 +587,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
data->cpu_feature = SYSTEM_INTEL_MSR_CAPABLE;
break;
default:
- dprintk("Unknown addr space %d\n",
+ pr_debug("Unknown addr space %d\n",
(u32) (perf->control_register.space_id));
result = -ENODEV;
goto err_unreg;
@@ -661,9 +658,9 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
if (cpu_has(c, X86_FEATURE_APERFMPERF))
acpi_cpufreq_driver.getavg = cpufreq_get_measured_perf;
- dprintk("CPU%u - ACPI performance management activated.\n", cpu);
+ pr_debug("CPU%u - ACPI performance management activated.\n", cpu);
for (i = 0; i < perf->state_count; i++)
- dprintk(" %cP%d: %d MHz, %d mW, %d uS\n",
+ pr_debug(" %cP%d: %d MHz, %d mW, %d uS\n",
(i == perf->state ? '*' : ' '), i,
(u32) perf->states[i].core_frequency,
(u32) perf->states[i].power,
@@ -694,7 +691,7 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy)
{
struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
- dprintk("acpi_cpufreq_cpu_exit\n");
+ pr_debug("acpi_cpufreq_cpu_exit\n");
if (data) {
cpufreq_frequency_table_put_attr(policy->cpu);
@@ -712,7 +709,7 @@ static int acpi_cpufreq_resume(struct cpufreq_policy *policy)
{
struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu);
- dprintk("acpi_cpufreq_resume\n");
+ pr_debug("acpi_cpufreq_resume\n");
data->resume = 1;
@@ -743,7 +740,7 @@ static int __init acpi_cpufreq_init(void)
if (acpi_disabled)
return 0;
- dprintk("acpi_cpufreq_init\n");
+ pr_debug("acpi_cpufreq_init\n");
ret = acpi_cpufreq_early_init();
if (ret)
@@ -758,7 +755,7 @@ static int __init acpi_cpufreq_init(void)
static void __exit acpi_cpufreq_exit(void)
{
- dprintk("acpi_cpufreq_exit\n");
+ pr_debug("acpi_cpufreq_exit\n");
cpufreq_unregister_driver(&acpi_cpufreq_driver);
diff --git a/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c b/drivers/cpufreq/cpufreq-nforce2.c
index 141abebc4516..7bac808804f3 100644
--- a/arch/x86/kernel/cpu/cpufreq/cpufreq-nforce2.c
+++ b/drivers/cpufreq/cpufreq-nforce2.c
@@ -57,8 +57,6 @@ MODULE_PARM_DESC(min_fsb,
"Minimum FSB to use, if not defined: current FSB - 50");
#define PFX "cpufreq-nforce2: "
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
- "cpufreq-nforce2", msg)
/**
* nforce2_calc_fsb - calculate FSB
@@ -270,7 +268,7 @@ static int nforce2_target(struct cpufreq_policy *policy,
if (freqs.old == freqs.new)
return 0;
- dprintk("Old CPU frequency %d kHz, new %d kHz\n",
+ pr_debug("Old CPU frequency %d kHz, new %d kHz\n",
freqs.old, freqs.new);
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
@@ -282,7 +280,7 @@ static int nforce2_target(struct cpufreq_policy *policy,
printk(KERN_ERR PFX "Changing FSB to %d failed\n",
target_fsb);
else
- dprintk("Changed FSB successfully to %d\n",
+ pr_debug("Changed FSB successfully to %d\n",
target_fsb);
/* Enable IRQs */
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 2dafc5c38ae7..0a5bea9e3585 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -32,9 +32,6 @@
#include <trace/events/power.h>
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, \
- "cpufreq-core", msg)
-
/**
* The "cpufreq driver" - the arch- or hardware-dependent low
* level driver of CPUFreq support, and its spinlock. This lock
@@ -181,93 +178,6 @@ EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
/*********************************************************************
- * UNIFIED DEBUG HELPERS *
- *********************************************************************/
-#ifdef CONFIG_CPU_FREQ_DEBUG
-
-/* what part(s) of the CPUfreq subsystem are debugged? */
-static unsigned int debug;
-
-/* is the debug output ratelimit'ed using printk_ratelimit? User can
- * set or modify this value.
- */
-static unsigned int debug_ratelimit = 1;
-
-/* is the printk_ratelimit'ing enabled? It's enabled after a successful
- * loading of a cpufreq driver, temporarily disabled when a new policy
- * is set, and disabled upon cpufreq driver removal
- */
-static unsigned int disable_ratelimit = 1;
-static DEFINE_SPINLOCK(disable_ratelimit_lock);
-
-static void cpufreq_debug_enable_ratelimit(void)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&disable_ratelimit_lock, flags);
- if (disable_ratelimit)
- disable_ratelimit--;
- spin_unlock_irqrestore(&disable_ratelimit_lock, flags);
-}
-
-static void cpufreq_debug_disable_ratelimit(void)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&disable_ratelimit_lock, flags);
- disable_ratelimit++;
- spin_unlock_irqrestore(&disable_ratelimit_lock, flags);
-}
-
-void cpufreq_debug_printk(unsigned int type, const char *prefix,
- const char *fmt, ...)
-{
- char s[256];
- va_list args;
- unsigned int len;
- unsigned long flags;
-
- WARN_ON(!prefix);
- if (type & debug) {
- spin_lock_irqsave(&disable_ratelimit_lock, flags);
- if (!disable_ratelimit && debug_ratelimit
- && !printk_ratelimit()) {
- spin_unlock_irqrestore(&disable_ratelimit_lock, flags);
- return;
- }
- spin_unlock_irqrestore(&disable_ratelimit_lock, flags);
-
- len = snprintf(s, 256, KERN_DEBUG "%s: ", prefix);
-
- va_start(args, fmt);
- len += vsnprintf(&s[len], (256 - len), fmt, args);
- va_end(args);
-
- printk(s);
-
- WARN_ON(len < 5);
- }
-}
-EXPORT_SYMBOL(cpufreq_debug_printk);
-
-
-module_param(debug, uint, 0644);
-MODULE_PARM_DESC(debug, "CPUfreq debugging: add 1 to debug core,"
- " 2 to debug drivers, and 4 to debug governors.");
-
-module_param(debug_ratelimit, uint, 0644);
-MODULE_PARM_DESC(debug_ratelimit, "CPUfreq debugging:"
- " set to 0 to disable ratelimiting.");
-
-#else /* !CONFIG_CPU_FREQ_DEBUG */
-
-static inline void cpufreq_debug_enable_ratelimit(void) { return; }
-static inline void cpufreq_debug_disable_ratelimit(void) { return; }
-
-#endif /* CONFIG_CPU_FREQ_DEBUG */
-
-
-/*********************************************************************
* EXTERNALLY AFFECTING FREQUENCY CHANGES *
*********************************************************************/
@@ -291,7 +201,7 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
if (!l_p_j_ref_freq) {
l_p_j_ref = loops_per_jiffy;
l_p_j_ref_freq = ci->old;
- dprintk("saving %lu as reference value for loops_per_jiffy; "
+ pr_debug("saving %lu as reference value for loops_per_jiffy; "
"freq is %u kHz\n", l_p_j_ref, l_p_j_ref_freq);
}
if ((val == CPUFREQ_PRECHANGE && ci->old < ci->new) ||
@@ -299,7 +209,7 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
(val == CPUFREQ_RESUMECHANGE || val == CPUFREQ_SUSPENDCHANGE)) {
loops_per_jiffy = cpufreq_scale(l_p_j_ref, l_p_j_ref_freq,
ci->new);
- dprintk("scaling loops_per_jiffy to %lu "
+ pr_debug("scaling loops_per_jiffy to %lu "
"for frequency %u kHz\n", loops_per_jiffy, ci->new);
}
}
@@ -326,7 +236,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
BUG_ON(irqs_disabled());
freqs->flags = cpufreq_driver->flags;
- dprintk("notification %u of frequency transition to %u kHz\n",
+ pr_debug("notification %u of frequency transition to %u kHz\n",
state, freqs->new);
policy = per_cpu(cpufreq_cpu_data, freqs->cpu);
@@ -340,7 +250,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
if ((policy) && (policy->cpu == freqs->cpu) &&
(policy->cur) && (policy->cur != freqs->old)) {
- dprintk("Warning: CPU frequency is"
+ pr_debug("Warning: CPU frequency is"
" %u, cpufreq assumed %u kHz.\n",
freqs->old, policy->cur);
freqs->old = policy->cur;
@@ -353,7 +263,7 @@ 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,
+ pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new,
(unsigned long)freqs->cpu);
trace_power_frequency(POWER_PSTATE, freqs->new, freqs->cpu);
trace_cpu_frequency(freqs->new, freqs->cpu);
@@ -411,21 +321,14 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy,
t = __find_governor(str_governor);
if (t == NULL) {
- char *name = kasprintf(GFP_KERNEL, "cpufreq_%s",
- str_governor);
-
- if (name) {
- int ret;
+ int ret;
- mutex_unlock(&cpufreq_governor_mutex);
- ret = request_module("%s", name);
- mutex_lock(&cpufreq_governor_mutex);
+ mutex_unlock(&cpufreq_governor_mutex);
+ ret = request_module("cpufreq_%s", str_governor);
+ mutex_lock(&cpufreq_governor_mutex);
- if (ret == 0)
- t = __find_governor(str_governor);
- }
-
- kfree(name);
+ if (ret == 0)
+ t = __find_governor(str_governor);
}
if (t != NULL) {
@@ -753,7 +656,7 @@ no_policy:
static void cpufreq_sysfs_release(struct kobject *kobj)
{
struct cpufreq_policy *policy = to_policy(kobj);
- dprintk("last reference is dropped\n");
+ pr_debug("last reference is dropped\n");
complete(&policy->kobj_unregister);
}
@@ -788,7 +691,7 @@ static int cpufreq_add_dev_policy(unsigned int cpu,
gov = __find_governor(per_cpu(cpufreq_cpu_governor, cpu));
if (gov) {
policy->governor = gov;
- dprintk("Restoring governor %s for cpu %d\n",
+ pr_debug("Restoring governor %s for cpu %d\n",
policy->governor->name, cpu);
}
#endif
@@ -824,7 +727,7 @@ static int cpufreq_add_dev_policy(unsigned int cpu,
per_cpu(cpufreq_cpu_data, cpu) = managed_policy;
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
- dprintk("CPU already managed, adding link\n");
+ pr_debug("CPU already managed, adding link\n");
ret = sysfs_create_link(&sys_dev->kobj,
&managed_policy->kobj,
"cpufreq");
@@ -865,7 +768,7 @@ static int cpufreq_add_dev_symlink(unsigned int cpu,
if (!cpu_online(j))
continue;
- dprintk("CPU %u already managed, adding link\n", j);
+ pr_debug("CPU %u already managed, adding link\n", j);
managed_policy = cpufreq_cpu_get(cpu);
cpu_sys_dev = get_cpu_sysdev(j);
ret = sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj,
@@ -941,7 +844,7 @@ static int cpufreq_add_dev_interface(unsigned int cpu,
policy->user_policy.governor = policy->governor;
if (ret) {
- dprintk("setting policy failed\n");
+ pr_debug("setting policy failed\n");
if (cpufreq_driver->exit)
cpufreq_driver->exit(policy);
}
@@ -977,8 +880,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
if (cpu_is_offline(cpu))
return 0;
- cpufreq_debug_disable_ratelimit();
- dprintk("adding CPU %u\n", cpu);
+ pr_debug("adding CPU %u\n", cpu);
#ifdef CONFIG_SMP
/* check whether a different CPU already registered this
@@ -986,7 +888,6 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
policy = cpufreq_cpu_get(cpu);
if (unlikely(policy)) {
cpufreq_cpu_put(policy);
- cpufreq_debug_enable_ratelimit();
return 0;
}
#endif
@@ -1037,7 +938,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
*/
ret = cpufreq_driver->init(policy);
if (ret) {
- dprintk("initialization failed\n");
+ pr_debug("initialization failed\n");
goto err_unlock_policy;
}
policy->user_policy.min = policy->min;
@@ -1063,8 +964,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
kobject_uevent(&policy->kobj, KOBJ_ADD);
module_put(cpufreq_driver->owner);
- dprintk("initialization complete\n");
- cpufreq_debug_enable_ratelimit();
+ pr_debug("initialization complete\n");
return 0;
@@ -1088,7 +988,6 @@ err_free_policy:
nomem_out:
module_put(cpufreq_driver->owner);
module_out:
- cpufreq_debug_enable_ratelimit();
return ret;
}
@@ -1112,15 +1011,13 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
unsigned int j;
#endif
- cpufreq_debug_disable_ratelimit();
- dprintk("unregistering CPU %u\n", cpu);
+ pr_debug("unregistering CPU %u\n", cpu);
spin_lock_irqsave(&cpufreq_driver_lock, flags);
data = per_cpu(cpufreq_cpu_data, cpu);
if (!data) {
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
- cpufreq_debug_enable_ratelimit();
unlock_policy_rwsem_write(cpu);
return -EINVAL;
}
@@ -1132,12 +1029,11 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
* only need to unlink, put and exit
*/
if (unlikely(cpu != data->cpu)) {
- dprintk("removing link\n");
+ pr_debug("removing link\n");
cpumask_clear_cpu(cpu, data->cpus);
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
kobj = &sys_dev->kobj;
cpufreq_cpu_put(data);
- cpufreq_debug_enable_ratelimit();
unlock_policy_rwsem_write(cpu);
sysfs_remove_link(kobj, "cpufreq");
return 0;
@@ -1170,7 +1066,7 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
for_each_cpu(j, data->cpus) {
if (j == cpu)
continue;
- dprintk("removing link for cpu %u\n", j);
+ pr_debug("removing link for cpu %u\n", j);
#ifdef CONFIG_HOTPLUG_CPU
strncpy(per_cpu(cpufreq_cpu_governor, j),
data->governor->name, CPUFREQ_NAME_LEN);
@@ -1199,21 +1095,35 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
* not referenced anymore by anybody before we proceed with
* unloading.
*/
- dprintk("waiting for dropping of refcount\n");
+ pr_debug("waiting for dropping of refcount\n");
wait_for_completion(cmp);
- dprintk("wait complete\n");
+ pr_debug("wait complete\n");
lock_policy_rwsem_write(cpu);
if (cpufreq_driver->exit)
cpufreq_driver->exit(data);
unlock_policy_rwsem_write(cpu);
+#ifdef CONFIG_HOTPLUG_CPU
+ /* when the CPU which is the parent of the kobj is hotplugged
+ * offline, check for siblings, and create cpufreq sysfs interface
+ * and symlinks
+ */
+ if (unlikely(cpumask_weight(data->cpus) > 1)) {
+ /* first sibling now owns the new sysfs dir */
+ cpumask_clear_cpu(cpu, data->cpus);
+ cpufreq_add_dev(get_cpu_sysdev(cpumask_first(data->cpus)));
+
+ /* finally remove our own symlink */
+ lock_policy_rwsem_write(cpu);
+ __cpufreq_remove_dev(sys_dev);
+ }
+#endif
+
free_cpumask_var(data->related_cpus);
free_cpumask_var(data->cpus);
kfree(data);
- per_cpu(cpufreq_cpu_data, cpu) = NULL;
- cpufreq_debug_enable_ratelimit();
return 0;
}
@@ -1239,7 +1149,7 @@ static void handle_update(struct work_struct *work)
struct cpufreq_policy *policy =
container_of(work, struct cpufreq_policy, update);
unsigned int cpu = policy->cpu;
- dprintk("handle_update for cpu %u called\n", cpu);
+ pr_debug("handle_update for cpu %u called\n", cpu);
cpufreq_update_policy(cpu);
}
@@ -1257,7 +1167,7 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
{
struct cpufreq_freqs freqs;
- dprintk("Warning: CPU frequency out of sync: cpufreq and timing "
+ pr_debug("Warning: CPU frequency out of sync: cpufreq and timing "
"core thinks of %u, is %u kHz.\n", old_freq, new_freq);
freqs.cpu = cpu;
@@ -1360,7 +1270,7 @@ static int cpufreq_bp_suspend(void)
int cpu = smp_processor_id();
struct cpufreq_policy *cpu_policy;
- dprintk("suspending cpu %u\n", cpu);
+ pr_debug("suspending cpu %u\n", cpu);
/* If there's no policy for the boot CPU, we have nothing to do. */
cpu_policy = cpufreq_cpu_get(cpu);
@@ -1398,7 +1308,7 @@ static void cpufreq_bp_resume(void)
int cpu = smp_processor_id();
struct cpufreq_policy *cpu_policy;
- dprintk("resuming cpu %u\n", cpu);
+ pr_debug("resuming cpu %u\n", cpu);
/* If there's no policy for the boot CPU, we have nothing to do. */
cpu_policy = cpufreq_cpu_get(cpu);
@@ -1510,7 +1420,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
{
int retval = -EINVAL;
- dprintk("target for CPU %u: %u kHz, relation %u\n", policy->cpu,
+ pr_debug("target for CPU %u: %u kHz, relation %u\n", policy->cpu,
target_freq, relation);
if (cpu_online(policy->cpu) && cpufreq_driver->target)
retval = cpufreq_driver->target(policy, target_freq, relation);
@@ -1596,7 +1506,7 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
if (!try_module_get(policy->governor->owner))
return -EINVAL;
- dprintk("__cpufreq_governor for CPU %u, event %u\n",
+ pr_debug("__cpufreq_governor for CPU %u, event %u\n",
policy->cpu, event);
ret = policy->governor->governor(policy, event);
@@ -1697,8 +1607,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
{
int ret = 0;
- cpufreq_debug_disable_ratelimit();
- dprintk("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu,
+ pr_debug("setting new policy for CPU %u: %u - %u kHz\n", policy->cpu,
policy->min, policy->max);
memcpy(&policy->cpuinfo, &data->cpuinfo,
@@ -1735,19 +1644,19 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
data->min = policy->min;
data->max = policy->max;
- dprintk("new min and max freqs are %u - %u kHz\n",
+ pr_debug("new min and max freqs are %u - %u kHz\n",
data->min, data->max);
if (cpufreq_driver->setpolicy) {
data->policy = policy->policy;
- dprintk("setting range\n");
+ pr_debug("setting range\n");
ret = cpufreq_driver->setpolicy(policy);
} else {
if (policy->governor != data->governor) {
/* save old, working values */
struct cpufreq_governor *old_gov = data->governor;
- dprintk("governor switch\n");
+ pr_debug("governor switch\n");
/* end old governor */
if (data->governor)
@@ -1757,7 +1666,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
data->governor = policy->governor;
if (__cpufreq_governor(data, CPUFREQ_GOV_START)) {
/* new governor failed, so re-start old one */
- dprintk("starting governor %s failed\n",
+ pr_debug("starting governor %s failed\n",
data->governor->name);
if (old_gov) {
data->governor = old_gov;
@@ -1769,12 +1678,11 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data,
}
/* might be a policy change, too, so fall through */
}
- dprintk("governor: change or update limits\n");
+ pr_debug("governor: change or update limits\n");
__cpufreq_governor(data, CPUFREQ_GOV_LIMITS);
}
error_out:
- cpufreq_debug_enable_ratelimit();
return ret;
}
@@ -1801,7 +1709,7 @@ int cpufreq_update_policy(unsigned int cpu)
goto fail;
}
- dprintk("updating policy for CPU %u\n", cpu);
+ pr_debug("updating policy for CPU %u\n", cpu);
memcpy(&policy, data, sizeof(struct cpufreq_policy));
policy.min = data->user_policy.min;
policy.max = data->user_policy.max;
@@ -1813,7 +1721,7 @@ int cpufreq_update_policy(unsigned int cpu)
if (cpufreq_driver->get) {
policy.cur = cpufreq_driver->get(cpu);
if (!data->cur) {
- dprintk("Driver did not initialize current freq");
+ pr_debug("Driver did not initialize current freq");
data->cur = policy.cur;
} else {
if (data->cur != policy.cur)
@@ -1889,7 +1797,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
((!driver_data->setpolicy) && (!driver_data->target)))
return -EINVAL;
- dprintk("trying to register driver %s\n", driver_data->name);
+ pr_debug("trying to register driver %s\n", driver_data->name);
if (driver_data->setpolicy)
driver_data->flags |= CPUFREQ_CONST_LOOPS;
@@ -1920,15 +1828,14 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
/* if all ->init() calls failed, unregister */
if (ret) {
- dprintk("no CPU initialized for driver %s\n",
+ pr_debug("no CPU initialized for driver %s\n",
driver_data->name);
goto err_sysdev_unreg;
}
}
register_hotcpu_notifier(&cpufreq_cpu_notifier);
- dprintk("driver %s up and running\n", driver_data->name);
- cpufreq_debug_enable_ratelimit();
+ pr_debug("driver %s up and running\n", driver_data->name);
return 0;
err_sysdev_unreg:
@@ -1955,14 +1862,10 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
{
unsigned long flags;
- cpufreq_debug_disable_ratelimit();
-
- if (!cpufreq_driver || (driver != cpufreq_driver)) {
- cpufreq_debug_enable_ratelimit();
+ if (!cpufreq_driver || (driver != cpufreq_driver))
return -EINVAL;
- }
- dprintk("unregistering driver %s\n", driver->name);
+ pr_debug("unregistering driver %s\n", driver->name);
sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver);
unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
diff --git a/drivers/cpufreq/cpufreq_performance.c b/drivers/cpufreq/cpufreq_performance.c
index 7e2e515087f8..f13a8a9af6a1 100644
--- a/drivers/cpufreq/cpufreq_performance.c
+++ b/drivers/cpufreq/cpufreq_performance.c
@@ -15,9 +15,6 @@
#include <linux/cpufreq.h>
#include <linux/init.h>
-#define dprintk(msg...) \
- cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "performance", msg)
-
static int cpufreq_governor_performance(struct cpufreq_policy *policy,
unsigned int event)
@@ -25,7 +22,7 @@ static int cpufreq_governor_performance(struct cpufreq_policy *policy,
switch (event) {
case CPUFREQ_GOV_START:
case CPUFREQ_GOV_LIMITS:
- dprintk("setting to %u kHz because of event %u\n",
+ pr_debug("setting to %u kHz because of event %u\n",
policy->max, event);
__cpufreq_driver_target(policy, policy->max,
CPUFREQ_RELATION_H);
diff --git a/drivers/cpufreq/cpufreq_powersave.c b/drivers/cpufreq/cpufreq_powersave.c
index e6db5faf3eb1..4c2eb512f2bc 100644
--- a/drivers/cpufreq/cpufreq_powersave.c
+++ b/drivers/cpufreq/cpufreq_powersave.c
@@ -15,16 +15,13 @@
#include <linux/cpufreq.h>
#include <linux/init.h>
-#define dprintk(msg...) \
- cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "powersave", msg)
-
static int cpufreq_governor_powersave(struct cpufreq_policy *policy,
unsigned int event)
{
switch (event) {
case CPUFREQ_GOV_START:
case CPUFREQ_GOV_LIMITS:
- dprintk("setting to %u kHz because of event %u\n",
+ pr_debug("setting to %u kHz because of event %u\n",
policy->min, event);
__cpufreq_driver_target(policy, policy->min,
CPUFREQ_RELATION_L);
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 00d73fc8e4e2..b60a4c263686 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -165,17 +165,27 @@ static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
return -1;
}
+/* should be called late in the CPU removal sequence so that the stats
+ * memory is still available in case someone tries to use it.
+ */
static void cpufreq_stats_free_table(unsigned int cpu)
{
struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu);
- struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
- if (policy && policy->cpu == cpu)
- sysfs_remove_group(&policy->kobj, &stats_attr_group);
if (stat) {
kfree(stat->time_in_state);
kfree(stat);
}
per_cpu(cpufreq_stats_table, cpu) = NULL;
+}
+
+/* must be called early in the CPU removal sequence (before
+ * cpufreq_remove_dev) so that policy is still valid.
+ */
+static void cpufreq_stats_free_sysfs(unsigned int cpu)
+{
+ struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
+ if (policy && policy->cpu == cpu)
+ sysfs_remove_group(&policy->kobj, &stats_attr_group);
if (policy)
cpufreq_cpu_put(policy);
}
@@ -316,6 +326,9 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
case CPU_ONLINE_FROZEN:
cpufreq_update_policy(cpu);
break;
+ case CPU_DOWN_PREPARE:
+ cpufreq_stats_free_sysfs(cpu);
+ break;
case CPU_DEAD:
case CPU_DEAD_FROZEN:
cpufreq_stats_free_table(cpu);
@@ -324,9 +337,10 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
return NOTIFY_OK;
}
-static struct notifier_block cpufreq_stat_cpu_notifier __refdata =
-{
+/* priority=1 so this will get called before cpufreq_remove_dev */
+static struct notifier_block cpufreq_stat_cpu_notifier __refdata = {
.notifier_call = cpufreq_stat_cpu_callback,
+ .priority = 1,
};
static struct notifier_block notifier_policy_block = {
diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c
index 66d2d1d6c80f..f231015904c0 100644
--- a/drivers/cpufreq/cpufreq_userspace.c
+++ b/drivers/cpufreq/cpufreq_userspace.c
@@ -37,9 +37,6 @@ static DEFINE_PER_CPU(unsigned int, cpu_is_managed);
static DEFINE_MUTEX(userspace_mutex);
static int cpus_using_userspace_governor;
-#define dprintk(msg...) \
- cpufreq_debug_printk(CPUFREQ_DEBUG_GOVERNOR, "userspace", msg)
-
/* keep track of frequency transitions */
static int
userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
@@ -50,7 +47,7 @@ userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
if (!per_cpu(cpu_is_managed, freq->cpu))
return 0;
- dprintk("saving cpu_cur_freq of cpu %u to be %u kHz\n",
+ pr_debug("saving cpu_cur_freq of cpu %u to be %u kHz\n",
freq->cpu, freq->new);
per_cpu(cpu_cur_freq, freq->cpu) = freq->new;
@@ -73,7 +70,7 @@ static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq)
{
int ret = -EINVAL;
- dprintk("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq);
+ pr_debug("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq);
mutex_lock(&userspace_mutex);
if (!per_cpu(cpu_is_managed, policy->cpu))
@@ -134,7 +131,7 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
per_cpu(cpu_max_freq, cpu) = policy->max;
per_cpu(cpu_cur_freq, cpu) = policy->cur;
per_cpu(cpu_set_freq, cpu) = policy->cur;
- dprintk("managing cpu %u started "
+ pr_debug("managing cpu %u started "
"(%u - %u kHz, currently %u kHz)\n",
cpu,
per_cpu(cpu_min_freq, cpu),
@@ -156,12 +153,12 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
per_cpu(cpu_min_freq, cpu) = 0;
per_cpu(cpu_max_freq, cpu) = 0;
per_cpu(cpu_set_freq, cpu) = 0;
- dprintk("managing cpu %u stopped\n", cpu);
+ pr_debug("managing cpu %u stopped\n", cpu);
mutex_unlock(&userspace_mutex);
break;
case CPUFREQ_GOV_LIMITS:
mutex_lock(&userspace_mutex);
- dprintk("limit event for cpu %u: %u - %u kHz, "
+ pr_debug("limit event for cpu %u: %u - %u kHz, "
"currently %u kHz, last set to %u kHz\n",
cpu, policy->min, policy->max,
per_cpu(cpu_cur_freq, cpu),
diff --git a/drivers/cpufreq/db8500-cpufreq.c b/drivers/cpufreq/db8500-cpufreq.c
new file mode 100644
index 000000000000..d90456a809f9
--- /dev/null
+++ b/drivers/cpufreq/db8500-cpufreq.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com>
+ * Author: Martin Persson <martin.persson@stericsson.com>
+ * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/mfd/db8500-prcmu.h>
+#include <mach/id.h>
+
+static struct cpufreq_frequency_table freq_table[] = {
+ [0] = {
+ .index = 0,
+ .frequency = 300000,
+ },
+ [1] = {
+ .index = 1,
+ .frequency = 600000,
+ },
+ [2] = {
+ /* Used for MAX_OPP, if available */
+ .index = 2,
+ .frequency = CPUFREQ_TABLE_END,
+ },
+ [3] = {
+ .index = 3,
+ .frequency = CPUFREQ_TABLE_END,
+ },
+};
+
+static enum arm_opp idx2opp[] = {
+ ARM_50_OPP,
+ ARM_100_OPP,
+ ARM_MAX_OPP
+};
+
+static struct freq_attr *db8500_cpufreq_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
+static int db8500_cpufreq_verify_speed(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy, freq_table);
+}
+
+static int db8500_cpufreq_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ struct cpufreq_freqs freqs;
+ unsigned int idx;
+
+ /* scale the target frequency to one of the extremes supported */
+ if (target_freq < policy->cpuinfo.min_freq)
+ target_freq = policy->cpuinfo.min_freq;
+ if (target_freq > policy->cpuinfo.max_freq)
+ target_freq = policy->cpuinfo.max_freq;
+
+ /* Lookup the next frequency */
+ if (cpufreq_frequency_table_target
+ (policy, freq_table, target_freq, relation, &idx)) {
+ return -EINVAL;
+ }
+
+ freqs.old = policy->cur;
+ freqs.new = freq_table[idx].frequency;
+ freqs.cpu = policy->cpu;
+
+ if (freqs.old == freqs.new)
+ return 0;
+
+ /* pre-change notification */
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+ /* request the PRCM unit for opp change */
+ if (prcmu_set_arm_opp(idx2opp[idx])) {
+ pr_err("db8500-cpufreq: Failed to set OPP level\n");
+ return -EINVAL;
+ }
+
+ /* post change notification */
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+ return 0;
+}
+
+static unsigned int db8500_cpufreq_getspeed(unsigned int cpu)
+{
+ int i;
+ /* request the prcm to get the current ARM opp */
+ for (i = 0; prcmu_get_arm_opp() != idx2opp[i]; i++)
+ ;
+ return freq_table[i].frequency;
+}
+
+static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy)
+{
+ int res;
+ int i;
+
+ BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table));
+
+ if (cpu_is_u8500v2() && !prcmu_is_u8400()) {
+ freq_table[0].frequency = 400000;
+ freq_table[1].frequency = 800000;
+ if (prcmu_has_arm_maxopp())
+ freq_table[2].frequency = 1000000;
+ }
+
+ /* get policy fields based on the table */
+ res = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+ if (!res)
+ cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
+ else {
+ pr_err("db8500-cpufreq : Failed to read policy table\n");
+ return res;
+ }
+
+ policy->min = policy->cpuinfo.min_freq;
+ policy->max = policy->cpuinfo.max_freq;
+ policy->cur = db8500_cpufreq_getspeed(policy->cpu);
+
+ for (i = 0; freq_table[i].frequency != policy->cur; i++)
+ ;
+
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+
+ /*
+ * FIXME : Need to take time measurement across the target()
+ * function with no/some/all drivers in the notification
+ * list.
+ */
+ policy->cpuinfo.transition_latency = 20 * 1000; /* in ns */
+
+ /* policy sharing between dual CPUs */
+ cpumask_copy(policy->cpus, &cpu_present_map);
+
+ policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
+
+ return 0;
+}
+
+static struct cpufreq_driver db8500_cpufreq_driver = {
+ .flags = CPUFREQ_STICKY,
+ .verify = db8500_cpufreq_verify_speed,
+ .target = db8500_cpufreq_target,
+ .get = db8500_cpufreq_getspeed,
+ .init = db8500_cpufreq_init,
+ .name = "DB8500",
+ .attr = db8500_cpufreq_attr,
+};
+
+static int __init db8500_cpufreq_register(void)
+{
+ if (!cpu_is_u8500v20_or_later())
+ return -ENODEV;
+
+ pr_info("cpufreq for DB8500 started\n");
+ return cpufreq_register_driver(&db8500_cpufreq_driver);
+}
+device_initcall(db8500_cpufreq_register);
diff --git a/arch/x86/kernel/cpu/cpufreq/e_powersaver.c b/drivers/cpufreq/e_powersaver.c
index 35a257dd4bb7..35a257dd4bb7 100644
--- a/arch/x86/kernel/cpu/cpufreq/e_powersaver.c
+++ b/drivers/cpufreq/e_powersaver.c
diff --git a/arch/x86/kernel/cpu/cpufreq/elanfreq.c b/drivers/cpufreq/elanfreq.c
index c587db472a75..c587db472a75 100644
--- a/arch/x86/kernel/cpu/cpufreq/elanfreq.c
+++ b/drivers/cpufreq/elanfreq.c
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index 05432216e224..90431cb92804 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -14,9 +14,6 @@
#include <linux/init.h>
#include <linux/cpufreq.h>
-#define dprintk(msg...) \
- cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, "freq-table", msg)
-
/*********************************************************************
* FREQUENCY TABLE HELPERS *
*********************************************************************/
@@ -31,11 +28,11 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
unsigned int freq = table[i].frequency;
if (freq == CPUFREQ_ENTRY_INVALID) {
- dprintk("table entry %u is invalid, skipping\n", i);
+ pr_debug("table entry %u is invalid, skipping\n", i);
continue;
}
- dprintk("table entry %u: %u kHz, %u index\n",
+ pr_debug("table entry %u: %u kHz, %u index\n",
i, freq, table[i].index);
if (freq < min_freq)
min_freq = freq;
@@ -61,7 +58,7 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
unsigned int i;
unsigned int count = 0;
- dprintk("request for verification of policy (%u - %u kHz) for cpu %u\n",
+ pr_debug("request for verification of policy (%u - %u kHz) for cpu %u\n",
policy->min, policy->max, policy->cpu);
if (!cpu_online(policy->cpu))
@@ -86,7 +83,7 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
policy->cpuinfo.max_freq);
- dprintk("verification lead to (%u - %u kHz) for cpu %u\n",
+ pr_debug("verification lead to (%u - %u kHz) for cpu %u\n",
policy->min, policy->max, policy->cpu);
return 0;
@@ -110,7 +107,7 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
};
unsigned int i;
- dprintk("request for target %u kHz (relation: %u) for cpu %u\n",
+ pr_debug("request for target %u kHz (relation: %u) for cpu %u\n",
target_freq, relation, policy->cpu);
switch (relation) {
@@ -167,7 +164,7 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
} else
*index = optimal.index;
- dprintk("target is %u (%u kHz, %u)\n", *index, table[*index].frequency,
+ pr_debug("target is %u (%u kHz, %u)\n", *index, table[*index].frequency,
table[*index].index);
return 0;
@@ -216,14 +213,14 @@ EXPORT_SYMBOL_GPL(cpufreq_freq_attr_scaling_available_freqs);
void cpufreq_frequency_table_get_attr(struct cpufreq_frequency_table *table,
unsigned int cpu)
{
- dprintk("setting show_table for cpu %u to %p\n", cpu, table);
+ pr_debug("setting show_table for cpu %u to %p\n", cpu, table);
per_cpu(cpufreq_show_table, cpu) = table;
}
EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_attr);
void cpufreq_frequency_table_put_attr(unsigned int cpu)
{
- dprintk("clearing show_table for cpu %u\n", cpu);
+ pr_debug("clearing show_table for cpu %u\n", cpu);
per_cpu(cpufreq_show_table, cpu) = NULL;
}
EXPORT_SYMBOL_GPL(cpufreq_frequency_table_put_attr);
diff --git a/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c b/drivers/cpufreq/gx-suspmod.c
index 32974cf84232..ffe1f2c92ed3 100644
--- a/arch/x86/kernel/cpu/cpufreq/gx-suspmod.c
+++ b/drivers/cpufreq/gx-suspmod.c
@@ -142,9 +142,6 @@ module_param(max_duration, int, 0444);
#define POLICY_MIN_DIV 20
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
- "gx-suspmod", msg)
-
/**
* we can detect a core multipiler from dir0_lsb
* from GX1 datasheet p.56,
@@ -191,7 +188,7 @@ static __init struct pci_dev *gx_detect_chipset(void)
/* check if CPU is a MediaGX or a Geode. */
if ((boot_cpu_data.x86_vendor != X86_VENDOR_NSC) &&
(boot_cpu_data.x86_vendor != X86_VENDOR_CYRIX)) {
- dprintk("error: no MediaGX/Geode processor found!\n");
+ pr_debug("error: no MediaGX/Geode processor found!\n");
return NULL;
}
@@ -201,7 +198,7 @@ static __init struct pci_dev *gx_detect_chipset(void)
return gx_pci;
}
- dprintk("error: no supported chipset found!\n");
+ pr_debug("error: no supported chipset found!\n");
return NULL;
}
@@ -305,14 +302,14 @@ static void gx_set_cpuspeed(unsigned int khz)
break;
default:
local_irq_restore(flags);
- dprintk("fatal: try to set unknown chipset.\n");
+ pr_debug("fatal: try to set unknown chipset.\n");
return;
}
} else {
suscfg = gx_params->pci_suscfg & ~(SUSMOD);
gx_params->off_duration = 0;
gx_params->on_duration = 0;
- dprintk("suspend modulation disabled: cpu runs 100%% speed.\n");
+ pr_debug("suspend modulation disabled: cpu runs 100%% speed.\n");
}
gx_write_byte(PCI_MODOFF, gx_params->off_duration);
@@ -327,9 +324,9 @@ static void gx_set_cpuspeed(unsigned int khz)
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
- dprintk("suspend modulation w/ duration of ON:%d us, OFF:%d us\n",
+ pr_debug("suspend modulation w/ duration of ON:%d us, OFF:%d us\n",
gx_params->on_duration * 32, gx_params->off_duration * 32);
- dprintk("suspend modulation w/ clock speed: %d kHz.\n", freqs.new);
+ pr_debug("suspend modulation w/ clock speed: %d kHz.\n", freqs.new);
}
/****************************************************************
@@ -428,8 +425,8 @@ static int cpufreq_gx_cpu_init(struct cpufreq_policy *policy)
stock_freq = maxfreq;
curfreq = gx_get_cpuspeed(0);
- dprintk("cpu max frequency is %d.\n", maxfreq);
- dprintk("cpu current frequency is %dkHz.\n", curfreq);
+ pr_debug("cpu max frequency is %d.\n", maxfreq);
+ pr_debug("cpu current frequency is %dkHz.\n", curfreq);
/* setup basic struct for cpufreq API */
policy->cpu = 0;
@@ -475,7 +472,7 @@ static int __init cpufreq_gx_init(void)
if (max_duration > 0xff)
max_duration = 0xff;
- dprintk("geode suspend modulation available.\n");
+ pr_debug("geode suspend modulation available.\n");
params = kzalloc(sizeof(struct gxfreq_params), GFP_KERNEL);
if (params == NULL)
diff --git a/arch/x86/kernel/cpu/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c
index cf48cdd6907d..f47d26e2a135 100644
--- a/arch/x86/kernel/cpu/cpufreq/longhaul.c
+++ b/drivers/cpufreq/longhaul.c
@@ -77,9 +77,6 @@ static int scale_voltage;
static int disable_acpi_c3;
static int revid_errata;
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
- "longhaul", msg)
-
/* Clock ratios multiplied by 10 */
static int mults[32];
@@ -87,7 +84,6 @@ static int eblcr[32];
static int longhaul_version;
static struct cpufreq_frequency_table *longhaul_table;
-#ifdef CONFIG_CPU_FREQ_DEBUG
static char speedbuffer[8];
static char *print_speed(int speed)
@@ -106,7 +102,6 @@ static char *print_speed(int speed)
return speedbuffer;
}
-#endif
static unsigned int calc_speed(int mult)
@@ -275,7 +270,7 @@ static void longhaul_setstate(unsigned int table_index)
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
- dprintk("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n",
+ pr_debug("Setting to FSB:%dMHz Mult:%d.%dx (%s)\n",
fsb, mult/10, mult%10, print_speed(speed/1000));
retry_loop:
preempt_disable();
@@ -460,12 +455,12 @@ static int __cpuinit longhaul_get_ranges(void)
break;
}
- dprintk("MinMult:%d.%dx MaxMult:%d.%dx\n",
+ pr_debug("MinMult:%d.%dx MaxMult:%d.%dx\n",
minmult/10, minmult%10, maxmult/10, maxmult%10);
highest_speed = calc_speed(maxmult);
lowest_speed = calc_speed(minmult);
- dprintk("FSB:%dMHz Lowest speed: %s Highest speed:%s\n", fsb,
+ pr_debug("FSB:%dMHz Lowest speed: %s Highest speed:%s\n", fsb,
print_speed(lowest_speed/1000),
print_speed(highest_speed/1000));
diff --git a/arch/x86/kernel/cpu/cpufreq/longhaul.h b/drivers/cpufreq/longhaul.h
index cbf48fbca881..cbf48fbca881 100644
--- a/arch/x86/kernel/cpu/cpufreq/longhaul.h
+++ b/drivers/cpufreq/longhaul.h
diff --git a/arch/x86/kernel/cpu/cpufreq/longrun.c b/drivers/cpufreq/longrun.c
index d9f51367666b..34ea359b370e 100644
--- a/arch/x86/kernel/cpu/cpufreq/longrun.c
+++ b/drivers/cpufreq/longrun.c
@@ -15,9 +15,6 @@
#include <asm/msr.h>
#include <asm/processor.h>
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
- "longrun", msg)
-
static struct cpufreq_driver longrun_driver;
/**
@@ -40,14 +37,14 @@ static void __cpuinit longrun_get_policy(struct cpufreq_policy *policy)
u32 msr_lo, msr_hi;
rdmsr(MSR_TMTA_LONGRUN_FLAGS, msr_lo, msr_hi);
- dprintk("longrun flags are %x - %x\n", msr_lo, msr_hi);
+ pr_debug("longrun flags are %x - %x\n", msr_lo, msr_hi);
if (msr_lo & 0x01)
policy->policy = CPUFREQ_POLICY_PERFORMANCE;
else
policy->policy = CPUFREQ_POLICY_POWERSAVE;
rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
- dprintk("longrun ctrl is %x - %x\n", msr_lo, msr_hi);
+ pr_debug("longrun ctrl is %x - %x\n", msr_lo, msr_hi);
msr_lo &= 0x0000007F;
msr_hi &= 0x0000007F;
@@ -150,7 +147,7 @@ static unsigned int longrun_get(unsigned int cpu)
return 0;
cpuid(0x80860007, &eax, &ebx, &ecx, &edx);
- dprintk("cpuid eax is %u\n", eax);
+ pr_debug("cpuid eax is %u\n", eax);
return eax * 1000;
}
@@ -196,7 +193,7 @@ static int __cpuinit longrun_determine_freqs(unsigned int *low_freq,
rdmsr(MSR_TMTA_LRTI_VOLT_MHZ, msr_lo, msr_hi);
*high_freq = msr_lo * 1000; /* to kHz */
- dprintk("longrun table interface told %u - %u kHz\n",
+ pr_debug("longrun table interface told %u - %u kHz\n",
*low_freq, *high_freq);
if (*low_freq > *high_freq)
@@ -207,7 +204,7 @@ static int __cpuinit longrun_determine_freqs(unsigned int *low_freq,
/* set the upper border to the value determined during TSC init */
*high_freq = (cpu_khz / 1000);
*high_freq = *high_freq * 1000;
- dprintk("high frequency is %u kHz\n", *high_freq);
+ pr_debug("high frequency is %u kHz\n", *high_freq);
/* get current borders */
rdmsr(MSR_TMTA_LONGRUN_CTRL, msr_lo, msr_hi);
@@ -233,7 +230,7 @@ static int __cpuinit longrun_determine_freqs(unsigned int *low_freq,
/* restore values */
wrmsr(MSR_TMTA_LONGRUN_CTRL, save_lo, save_hi);
}
- dprintk("percentage is %u %%, freq is %u MHz\n", ecx, eax);
+ pr_debug("percentage is %u %%, freq is %u MHz\n", ecx, eax);
/* performance_pctg = (current_freq - low_freq)/(high_freq - low_freq)
* eqals
@@ -249,7 +246,7 @@ static int __cpuinit longrun_determine_freqs(unsigned int *low_freq,
edx = ((eax - ebx) * 100) / (100 - ecx);
*low_freq = edx * 1000; /* back to kHz */
- dprintk("low frequency is %u kHz\n", *low_freq);
+ pr_debug("low frequency is %u kHz\n", *low_freq);
if (*low_freq > *high_freq)
*low_freq = *high_freq;
diff --git a/arch/x86/kernel/cpu/cpufreq/mperf.c b/drivers/cpufreq/mperf.c
index 911e193018ae..911e193018ae 100644
--- a/arch/x86/kernel/cpu/cpufreq/mperf.c
+++ b/drivers/cpufreq/mperf.c
diff --git a/arch/x86/kernel/cpu/cpufreq/mperf.h b/drivers/cpufreq/mperf.h
index 5dbf2950dc22..5dbf2950dc22 100644
--- a/arch/x86/kernel/cpu/cpufreq/mperf.h
+++ b/drivers/cpufreq/mperf.h
diff --git a/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c b/drivers/cpufreq/p4-clockmod.c
index 52c93648e492..6be3e0760c26 100644
--- a/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c
+++ b/drivers/cpufreq/p4-clockmod.c
@@ -35,8 +35,6 @@
#include "speedstep-lib.h"
#define PFX "p4-clockmod: "
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
- "p4-clockmod", msg)
/*
* Duty Cycle (3bits), note DC_DISABLE is not specified in
@@ -66,7 +64,7 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate)
rdmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, &l, &h);
if (l & 0x01)
- dprintk("CPU#%d currently thermal throttled\n", cpu);
+ pr_debug("CPU#%d currently thermal throttled\n", cpu);
if (has_N44_O17_errata[cpu] &&
(newstate == DC_25PT || newstate == DC_DFLT))
@@ -74,10 +72,10 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate)
rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h);
if (newstate == DC_DISABLE) {
- dprintk("CPU#%d disabling modulation\n", cpu);
+ pr_debug("CPU#%d disabling modulation\n", cpu);
wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, l & ~(1<<4), h);
} else {
- dprintk("CPU#%d setting duty cycle to %d%%\n",
+ pr_debug("CPU#%d setting duty cycle to %d%%\n",
cpu, ((125 * newstate) / 10));
/* bits 63 - 5 : reserved
* bit 4 : enable/disable
@@ -217,7 +215,7 @@ static int cpufreq_p4_cpu_init(struct cpufreq_policy *policy)
case 0x0f11:
case 0x0f12:
has_N44_O17_errata[policy->cpu] = 1;
- dprintk("has errata -- disabling low frequencies\n");
+ pr_debug("has errata -- disabling low frequencies\n");
}
if (speedstep_detect_processor() == SPEEDSTEP_CPU_P4D &&
diff --git a/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c
index 755a31e0f5b0..7b0603eb0129 100644
--- a/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.c
+++ b/drivers/cpufreq/pcc-cpufreq.c
@@ -39,7 +39,7 @@
#include <acpi/processor.h>
-#define PCC_VERSION "1.00.00"
+#define PCC_VERSION "1.10.00"
#define POLL_LOOPS 300
#define CMD_COMPLETE 0x1
@@ -48,9 +48,6 @@
#define BUF_SZ 4
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
- "pcc-cpufreq", msg)
-
struct pcc_register_resource {
u8 descriptor;
u16 length;
@@ -102,7 +99,7 @@ static struct acpi_generic_address doorbell;
static u64 doorbell_preserve;
static u64 doorbell_write;
-static u8 OSC_UUID[16] = {0x63, 0x9B, 0x2C, 0x9F, 0x70, 0x91, 0x49, 0x1f,
+static u8 OSC_UUID[16] = {0x9F, 0x2C, 0x9B, 0x63, 0x91, 0x70, 0x1f, 0x49,
0xBB, 0x4F, 0xA5, 0x98, 0x2F, 0xA1, 0xB5, 0x46};
struct pcc_cpu {
@@ -152,7 +149,7 @@ static unsigned int pcc_get_freq(unsigned int cpu)
spin_lock(&pcc_lock);
- dprintk("get: get_freq for CPU %d\n", cpu);
+ pr_debug("get: get_freq for CPU %d\n", cpu);
pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu);
input_buffer = 0x1;
@@ -170,7 +167,7 @@ static unsigned int pcc_get_freq(unsigned int cpu)
status = ioread16(&pcch_hdr->status);
if (status != CMD_COMPLETE) {
- dprintk("get: FAILED: for CPU %d, status is %d\n",
+ pr_debug("get: FAILED: for CPU %d, status is %d\n",
cpu, status);
goto cmd_incomplete;
}
@@ -178,14 +175,14 @@ static unsigned int pcc_get_freq(unsigned int cpu)
curr_freq = (((ioread32(&pcch_hdr->nominal) * (output_buffer & 0xff))
/ 100) * 1000);
- dprintk("get: SUCCESS: (virtual) output_offset for cpu %d is "
- "0x%x, contains a value of: 0x%x. Speed is: %d MHz\n",
+ pr_debug("get: SUCCESS: (virtual) output_offset for cpu %d is "
+ "0x%p, contains a value of: 0x%x. Speed is: %d MHz\n",
cpu, (pcch_virt_addr + pcc_cpu_data->output_offset),
output_buffer, curr_freq);
freq_limit = (output_buffer >> 8) & 0xff;
if (freq_limit != 0xff) {
- dprintk("get: frequency for cpu %d is being temporarily"
+ pr_debug("get: frequency for cpu %d is being temporarily"
" capped at %d\n", cpu, curr_freq);
}
@@ -212,8 +209,8 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy,
cpu = policy->cpu;
pcc_cpu_data = per_cpu_ptr(pcc_cpu_info, cpu);
- dprintk("target: CPU %d should go to target freq: %d "
- "(virtual) input_offset is 0x%x\n",
+ pr_debug("target: CPU %d should go to target freq: %d "
+ "(virtual) input_offset is 0x%p\n",
cpu, target_freq,
(pcch_virt_addr + pcc_cpu_data->input_offset));
@@ -234,14 +231,14 @@ static int pcc_cpufreq_target(struct cpufreq_policy *policy,
status = ioread16(&pcch_hdr->status);
if (status != CMD_COMPLETE) {
- dprintk("target: FAILED for cpu %d, with status: 0x%x\n",
+ pr_debug("target: FAILED for cpu %d, with status: 0x%x\n",
cpu, status);
goto cmd_incomplete;
}
iowrite16(0, &pcch_hdr->status);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
- dprintk("target: was SUCCESSFUL for cpu %d\n", cpu);
+ pr_debug("target: was SUCCESSFUL for cpu %d\n", cpu);
spin_unlock(&pcc_lock);
return 0;
@@ -293,7 +290,7 @@ static int pcc_get_offset(int cpu)
memset_io((pcch_virt_addr + pcc_cpu_data->input_offset), 0, BUF_SZ);
memset_io((pcch_virt_addr + pcc_cpu_data->output_offset), 0, BUF_SZ);
- dprintk("pcc_get_offset: for CPU %d: pcc_cpu_data "
+ pr_debug("pcc_get_offset: for CPU %d: pcc_cpu_data "
"input_offset: 0x%x, pcc_cpu_data output_offset: 0x%x\n",
cpu, pcc_cpu_data->input_offset, pcc_cpu_data->output_offset);
out_free:
@@ -410,7 +407,7 @@ static int __init pcc_cpufreq_probe(void)
if (ACPI_SUCCESS(status)) {
ret = pcc_cpufreq_do_osc(&osc_handle);
if (ret)
- dprintk("probe: _OSC evaluation did not succeed\n");
+ pr_debug("probe: _OSC evaluation did not succeed\n");
/* Firmware's use of _OSC is optional */
ret = 0;
}
@@ -433,7 +430,7 @@ static int __init pcc_cpufreq_probe(void)
mem_resource = (struct pcc_memory_resource *)member->buffer.pointer;
- dprintk("probe: mem_resource descriptor: 0x%x,"
+ pr_debug("probe: mem_resource descriptor: 0x%x,"
" length: %d, space_id: %d, resource_usage: %d,"
" type_specific: %d, granularity: 0x%llx,"
" minimum: 0x%llx, maximum: 0x%llx,"
@@ -453,13 +450,13 @@ static int __init pcc_cpufreq_probe(void)
pcch_virt_addr = ioremap_nocache(mem_resource->minimum,
mem_resource->address_length);
if (pcch_virt_addr == NULL) {
- dprintk("probe: could not map shared mem region\n");
+ pr_debug("probe: could not map shared mem region\n");
goto out_free;
}
pcch_hdr = pcch_virt_addr;
- dprintk("probe: PCCH header (virtual) addr: 0x%p\n", pcch_hdr);
- dprintk("probe: PCCH header is at physical address: 0x%llx,"
+ pr_debug("probe: PCCH header (virtual) addr: 0x%p\n", pcch_hdr);
+ pr_debug("probe: PCCH header is at physical address: 0x%llx,"
" signature: 0x%x, length: %d bytes, major: %d, minor: %d,"
" supported features: 0x%x, command field: 0x%x,"
" status field: 0x%x, nominal latency: %d us\n",
@@ -469,7 +466,7 @@ static int __init pcc_cpufreq_probe(void)
ioread16(&pcch_hdr->command), ioread16(&pcch_hdr->status),
ioread32(&pcch_hdr->latency));
- dprintk("probe: min time between commands: %d us,"
+ pr_debug("probe: min time between commands: %d us,"
" max time between commands: %d us,"
" nominal CPU frequency: %d MHz,"
" minimum CPU frequency: %d MHz,"
@@ -494,7 +491,7 @@ static int __init pcc_cpufreq_probe(void)
doorbell.access_width = 64;
doorbell.address = reg_resource->address;
- dprintk("probe: doorbell: space_id is %d, bit_width is %d, "
+ pr_debug("probe: doorbell: space_id is %d, bit_width is %d, "
"bit_offset is %d, access_width is %d, address is 0x%llx\n",
doorbell.space_id, doorbell.bit_width, doorbell.bit_offset,
doorbell.access_width, reg_resource->address);
@@ -515,7 +512,7 @@ static int __init pcc_cpufreq_probe(void)
doorbell_write = member->integer.value;
- dprintk("probe: doorbell_preserve: 0x%llx,"
+ pr_debug("probe: doorbell_preserve: 0x%llx,"
" doorbell_write: 0x%llx\n",
doorbell_preserve, doorbell_write);
@@ -550,7 +547,7 @@ static int pcc_cpufreq_cpu_init(struct cpufreq_policy *policy)
result = pcc_get_offset(cpu);
if (result) {
- dprintk("init: PCCP evaluation failed\n");
+ pr_debug("init: PCCP evaluation failed\n");
goto out;
}
@@ -561,12 +558,12 @@ static int pcc_cpufreq_cpu_init(struct cpufreq_policy *policy)
policy->cur = pcc_get_freq(cpu);
if (!policy->cur) {
- dprintk("init: Unable to get current CPU frequency\n");
+ pr_debug("init: Unable to get current CPU frequency\n");
result = -EINVAL;
goto out;
}
- dprintk("init: policy->max is %d, policy->min is %d\n",
+ pr_debug("init: policy->max is %d, policy->min is %d\n",
policy->max, policy->min);
out:
return result;
@@ -597,7 +594,7 @@ static int __init pcc_cpufreq_init(void)
ret = pcc_cpufreq_probe();
if (ret) {
- dprintk("pcc_cpufreq_init: PCCH evaluation failed\n");
+ pr_debug("pcc_cpufreq_init: PCCH evaluation failed\n");
return ret;
}
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k6.c b/drivers/cpufreq/powernow-k6.c
index b3379d6a5c57..b3379d6a5c57 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k6.c
+++ b/drivers/cpufreq/powernow-k6.c
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c
index 4a45fd6e41ba..d71d9f372359 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k7.c
+++ b/drivers/cpufreq/powernow-k7.c
@@ -68,7 +68,6 @@ union powernow_acpi_control_t {
};
#endif
-#ifdef CONFIG_CPU_FREQ_DEBUG
/* divide by 1000 to get VCore voltage in V. */
static const int mobile_vid_table[32] = {
2000, 1950, 1900, 1850, 1800, 1750, 1700, 1650,
@@ -76,7 +75,6 @@ static const int mobile_vid_table[32] = {
1275, 1250, 1225, 1200, 1175, 1150, 1125, 1100,
1075, 1050, 1025, 1000, 975, 950, 925, 0,
};
-#endif
/* divide by 10 to get FID. */
static const int fid_codes[32] = {
@@ -103,9 +101,6 @@ static unsigned int fsb;
static unsigned int latency;
static char have_a0;
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
- "powernow-k7", msg)
-
static int check_fsb(unsigned int fsbspeed)
{
int delta;
@@ -209,7 +204,7 @@ static int get_ranges(unsigned char *pst)
vid = *pst++;
powernow_table[j].index |= (vid << 8); /* upper 8 bits */
- dprintk(" FID: 0x%x (%d.%dx [%dMHz]) "
+ pr_debug(" FID: 0x%x (%d.%dx [%dMHz]) "
"VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,
fid_codes[fid] % 10, speed/1000, vid,
mobile_vid_table[vid]/1000,
@@ -367,7 +362,7 @@ static int powernow_acpi_init(void)
unsigned int speed, speed_mhz;
pc.val = (unsigned long) state->control;
- dprintk("acpi: P%d: %d MHz %d mW %d uS control %08x SGTC %d\n",
+ pr_debug("acpi: P%d: %d MHz %d mW %d uS control %08x SGTC %d\n",
i,
(u32) state->core_frequency,
(u32) state->power,
@@ -401,7 +396,7 @@ static int powernow_acpi_init(void)
invalidate_entry(i);
}
- dprintk(" FID: 0x%x (%d.%dx [%dMHz]) "
+ pr_debug(" FID: 0x%x (%d.%dx [%dMHz]) "
"VID: 0x%x (%d.%03dV)\n", fid, fid_codes[fid] / 10,
fid_codes[fid] % 10, speed_mhz, vid,
mobile_vid_table[vid]/1000,
@@ -409,7 +404,7 @@ static int powernow_acpi_init(void)
if (state->core_frequency != speed_mhz) {
state->core_frequency = speed_mhz;
- dprintk(" Corrected ACPI frequency to %d\n",
+ pr_debug(" Corrected ACPI frequency to %d\n",
speed_mhz);
}
@@ -453,8 +448,8 @@ static int powernow_acpi_init(void)
static void print_pst_entry(struct pst_s *pst, unsigned int j)
{
- dprintk("PST:%d (@%p)\n", j, pst);
- dprintk(" cpuid: 0x%x fsb: %d maxFID: 0x%x startvid: 0x%x\n",
+ pr_debug("PST:%d (@%p)\n", j, pst);
+ pr_debug(" cpuid: 0x%x fsb: %d maxFID: 0x%x startvid: 0x%x\n",
pst->cpuid, pst->fsbspeed, pst->maxfid, pst->startvid);
}
@@ -474,20 +469,20 @@ static int powernow_decode_bios(int maxfid, int startvid)
p = phys_to_virt(i);
if (memcmp(p, "AMDK7PNOW!", 10) == 0) {
- dprintk("Found PSB header at %p\n", p);
+ pr_debug("Found PSB header at %p\n", p);
psb = (struct psb_s *) p;
- dprintk("Table version: 0x%x\n", psb->tableversion);
+ pr_debug("Table version: 0x%x\n", psb->tableversion);
if (psb->tableversion != 0x12) {
printk(KERN_INFO PFX "Sorry, only v1.2 tables"
" supported right now\n");
return -ENODEV;
}
- dprintk("Flags: 0x%x\n", psb->flags);
+ pr_debug("Flags: 0x%x\n", psb->flags);
if ((psb->flags & 1) == 0)
- dprintk("Mobile voltage regulator\n");
+ pr_debug("Mobile voltage regulator\n");
else
- dprintk("Desktop voltage regulator\n");
+ pr_debug("Desktop voltage regulator\n");
latency = psb->settlingtime;
if (latency < 100) {
@@ -497,9 +492,9 @@ static int powernow_decode_bios(int maxfid, int startvid)
"Correcting.\n", latency);
latency = 100;
}
- dprintk("Settling Time: %d microseconds.\n",
+ pr_debug("Settling Time: %d microseconds.\n",
psb->settlingtime);
- dprintk("Has %d PST tables. (Only dumping ones "
+ pr_debug("Has %d PST tables. (Only dumping ones "
"relevant to this CPU).\n",
psb->numpst);
@@ -650,7 +645,7 @@ static int __cpuinit powernow_cpu_init(struct cpufreq_policy *policy)
printk(KERN_WARNING PFX "can not determine bus frequency\n");
return -EINVAL;
}
- dprintk("FSB: %3dMHz\n", fsb/1000);
+ pr_debug("FSB: %3dMHz\n", fsb/1000);
if (dmi_check_system(powernow_dmi_table) || acpi_force) {
printk(KERN_INFO PFX "PSB/PST known to be broken. "
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k7.h b/drivers/cpufreq/powernow-k7.h
index 35fb4eaf6e1c..35fb4eaf6e1c 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k7.h
+++ b/drivers/cpufreq/powernow-k7.h
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c
index 2368e38327b3..83479b6fb9a1 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
+++ b/drivers/cpufreq/powernow-k8.c
@@ -139,7 +139,7 @@ static int query_current_values_with_pending_wait(struct powernow_k8_data *data)
}
do {
if (i++ > 10000) {
- dprintk("detected change pending stuck\n");
+ pr_debug("detected change pending stuck\n");
return 1;
}
rdmsr(MSR_FIDVID_STATUS, lo, hi);
@@ -176,7 +176,7 @@ static void fidvid_msr_init(void)
fid = lo & MSR_S_LO_CURRENT_FID;
lo = fid | (vid << MSR_C_LO_VID_SHIFT);
hi = MSR_C_HI_STP_GNT_BENIGN;
- dprintk("cpu%d, init lo 0x%x, hi 0x%x\n", smp_processor_id(), lo, hi);
+ pr_debug("cpu%d, init lo 0x%x, hi 0x%x\n", smp_processor_id(), lo, hi);
wrmsr(MSR_FIDVID_CTL, lo, hi);
}
@@ -196,7 +196,7 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid)
lo |= (data->currvid << MSR_C_LO_VID_SHIFT);
lo |= MSR_C_LO_INIT_FID_VID;
- dprintk("writing fid 0x%x, lo 0x%x, hi 0x%x\n",
+ pr_debug("writing fid 0x%x, lo 0x%x, hi 0x%x\n",
fid, lo, data->plllock * PLL_LOCK_CONVERSION);
do {
@@ -244,7 +244,7 @@ static int write_new_vid(struct powernow_k8_data *data, u32 vid)
lo |= (vid << MSR_C_LO_VID_SHIFT);
lo |= MSR_C_LO_INIT_FID_VID;
- dprintk("writing vid 0x%x, lo 0x%x, hi 0x%x\n",
+ pr_debug("writing vid 0x%x, lo 0x%x, hi 0x%x\n",
vid, lo, STOP_GRANT_5NS);
do {
@@ -325,7 +325,7 @@ static int transition_fid_vid(struct powernow_k8_data *data,
return 1;
}
- dprintk("transitioned (cpu%d): new fid 0x%x, vid 0x%x\n",
+ pr_debug("transitioned (cpu%d): new fid 0x%x, vid 0x%x\n",
smp_processor_id(), data->currfid, data->currvid);
return 0;
@@ -339,7 +339,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data,
u32 savefid = data->currfid;
u32 maxvid, lo, rvomult = 1;
- dprintk("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, "
+ pr_debug("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, "
"reqvid 0x%x, rvo 0x%x\n",
smp_processor_id(),
data->currfid, data->currvid, reqvid, data->rvo);
@@ -349,12 +349,12 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data,
rvosteps *= rvomult;
rdmsr(MSR_FIDVID_STATUS, lo, maxvid);
maxvid = 0x1f & (maxvid >> 16);
- dprintk("ph1 maxvid=0x%x\n", maxvid);
+ pr_debug("ph1 maxvid=0x%x\n", maxvid);
if (reqvid < maxvid) /* lower numbers are higher voltages */
reqvid = maxvid;
while (data->currvid > reqvid) {
- dprintk("ph1: curr 0x%x, req vid 0x%x\n",
+ pr_debug("ph1: curr 0x%x, req vid 0x%x\n",
data->currvid, reqvid);
if (decrease_vid_code_by_step(data, reqvid, data->vidmvs))
return 1;
@@ -365,7 +365,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data,
if (data->currvid == maxvid) {
rvosteps = 0;
} else {
- dprintk("ph1: changing vid for rvo, req 0x%x\n",
+ pr_debug("ph1: changing vid for rvo, req 0x%x\n",
data->currvid - 1);
if (decrease_vid_code_by_step(data, data->currvid-1, 1))
return 1;
@@ -382,7 +382,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data,
return 1;
}
- dprintk("ph1 complete, currfid 0x%x, currvid 0x%x\n",
+ pr_debug("ph1 complete, currfid 0x%x, currvid 0x%x\n",
data->currfid, data->currvid);
return 0;
@@ -400,7 +400,7 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid)
return 0;
}
- dprintk("ph2 (cpu%d): starting, currfid 0x%x, currvid 0x%x, "
+ pr_debug("ph2 (cpu%d): starting, currfid 0x%x, currvid 0x%x, "
"reqfid 0x%x\n",
smp_processor_id(),
data->currfid, data->currvid, reqfid);
@@ -457,7 +457,7 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid)
return 1;
}
- dprintk("ph2 complete, currfid 0x%x, currvid 0x%x\n",
+ pr_debug("ph2 complete, currfid 0x%x, currvid 0x%x\n",
data->currfid, data->currvid);
return 0;
@@ -470,7 +470,7 @@ static int core_voltage_post_transition(struct powernow_k8_data *data,
u32 savefid = data->currfid;
u32 savereqvid = reqvid;
- dprintk("ph3 (cpu%d): starting, currfid 0x%x, currvid 0x%x\n",
+ pr_debug("ph3 (cpu%d): starting, currfid 0x%x, currvid 0x%x\n",
smp_processor_id(),
data->currfid, data->currvid);
@@ -498,17 +498,17 @@ static int core_voltage_post_transition(struct powernow_k8_data *data,
return 1;
if (savereqvid != data->currvid) {
- dprintk("ph3 failed, currvid 0x%x\n", data->currvid);
+ pr_debug("ph3 failed, currvid 0x%x\n", data->currvid);
return 1;
}
if (savefid != data->currfid) {
- dprintk("ph3 failed, currfid changed 0x%x\n",
+ pr_debug("ph3 failed, currfid changed 0x%x\n",
data->currfid);
return 1;
}
- dprintk("ph3 complete, currfid 0x%x, currvid 0x%x\n",
+ pr_debug("ph3 complete, currfid 0x%x, currvid 0x%x\n",
data->currfid, data->currvid);
return 0;
@@ -707,7 +707,7 @@ static int fill_powernow_table(struct powernow_k8_data *data,
return -EIO;
}
- dprintk("cfid 0x%x, cvid 0x%x\n", data->currfid, data->currvid);
+ pr_debug("cfid 0x%x, cvid 0x%x\n", data->currfid, data->currvid);
data->powernow_table = powernow_table;
if (cpumask_first(cpu_core_mask(data->cpu)) == data->cpu)
print_basics(data);
@@ -717,7 +717,7 @@ static int fill_powernow_table(struct powernow_k8_data *data,
(pst[j].vid == data->currvid))
return 0;
- dprintk("currfid/vid do not match PST, ignoring\n");
+ pr_debug("currfid/vid do not match PST, ignoring\n");
return 0;
}
@@ -739,36 +739,36 @@ static int find_psb_table(struct powernow_k8_data *data)
if (memcmp(psb, PSB_ID_STRING, PSB_ID_STRING_LEN) != 0)
continue;
- dprintk("found PSB header at 0x%p\n", psb);
+ pr_debug("found PSB header at 0x%p\n", psb);
- dprintk("table vers: 0x%x\n", psb->tableversion);
+ pr_debug("table vers: 0x%x\n", psb->tableversion);
if (psb->tableversion != PSB_VERSION_1_4) {
printk(KERN_ERR FW_BUG PFX "PSB table is not v1.4\n");
return -ENODEV;
}
- dprintk("flags: 0x%x\n", psb->flags1);
+ pr_debug("flags: 0x%x\n", psb->flags1);
if (psb->flags1) {
printk(KERN_ERR FW_BUG PFX "unknown flags\n");
return -ENODEV;
}
data->vstable = psb->vstable;
- dprintk("voltage stabilization time: %d(*20us)\n",
+ pr_debug("voltage stabilization time: %d(*20us)\n",
data->vstable);
- dprintk("flags2: 0x%x\n", psb->flags2);
+ pr_debug("flags2: 0x%x\n", psb->flags2);
data->rvo = psb->flags2 & 3;
data->irt = ((psb->flags2) >> 2) & 3;
mvs = ((psb->flags2) >> 4) & 3;
data->vidmvs = 1 << mvs;
data->batps = ((psb->flags2) >> 6) & 3;
- dprintk("ramp voltage offset: %d\n", data->rvo);
- dprintk("isochronous relief time: %d\n", data->irt);
- dprintk("maximum voltage step: %d - 0x%x\n", mvs, data->vidmvs);
+ pr_debug("ramp voltage offset: %d\n", data->rvo);
+ pr_debug("isochronous relief time: %d\n", data->irt);
+ pr_debug("maximum voltage step: %d - 0x%x\n", mvs, data->vidmvs);
- dprintk("numpst: 0x%x\n", psb->num_tables);
+ pr_debug("numpst: 0x%x\n", psb->num_tables);
cpst = psb->num_tables;
if ((psb->cpuid == 0x00000fc0) ||
(psb->cpuid == 0x00000fe0)) {
@@ -783,13 +783,13 @@ static int find_psb_table(struct powernow_k8_data *data)
}
data->plllock = psb->plllocktime;
- dprintk("plllocktime: 0x%x (units 1us)\n", psb->plllocktime);
- dprintk("maxfid: 0x%x\n", psb->maxfid);
- dprintk("maxvid: 0x%x\n", psb->maxvid);
+ pr_debug("plllocktime: 0x%x (units 1us)\n", psb->plllocktime);
+ pr_debug("maxfid: 0x%x\n", psb->maxfid);
+ pr_debug("maxvid: 0x%x\n", psb->maxvid);
maxvid = psb->maxvid;
data->numps = psb->numps;
- dprintk("numpstates: 0x%x\n", data->numps);
+ pr_debug("numpstates: 0x%x\n", data->numps);
return fill_powernow_table(data,
(struct pst_s *)(psb+1), maxvid);
}
@@ -834,13 +834,13 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
u64 control, status;
if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) {
- dprintk("register performance failed: bad ACPI data\n");
+ pr_debug("register performance failed: bad ACPI data\n");
return -EIO;
}
/* verify the data contained in the ACPI structures */
if (data->acpi_data.state_count <= 1) {
- dprintk("No ACPI P-States\n");
+ pr_debug("No ACPI P-States\n");
goto err_out;
}
@@ -849,7 +849,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
if ((control != ACPI_ADR_SPACE_FIXED_HARDWARE) ||
(status != ACPI_ADR_SPACE_FIXED_HARDWARE)) {
- dprintk("Invalid control/status registers (%x - %x)\n",
+ pr_debug("Invalid control/status registers (%llx - %llx)\n",
control, status);
goto err_out;
}
@@ -858,7 +858,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
powernow_table = kmalloc((sizeof(struct cpufreq_frequency_table)
* (data->acpi_data.state_count + 1)), GFP_KERNEL);
if (!powernow_table) {
- dprintk("powernow_table memory alloc failure\n");
+ pr_debug("powernow_table memory alloc failure\n");
goto err_out;
}
@@ -928,7 +928,7 @@ static int fill_powernow_table_pstate(struct powernow_k8_data *data,
}
rdmsr(MSR_PSTATE_DEF_BASE + index, lo, hi);
if (!(hi & HW_PSTATE_VALID_MASK)) {
- dprintk("invalid pstate %d, ignoring\n", index);
+ pr_debug("invalid pstate %d, ignoring\n", index);
invalidate_entry(powernow_table, i);
continue;
}
@@ -968,7 +968,7 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data,
vid = (control >> VID_SHIFT) & VID_MASK;
}
- dprintk(" %d : fid 0x%x, vid 0x%x\n", i, fid, vid);
+ pr_debug(" %d : fid 0x%x, vid 0x%x\n", i, fid, vid);
index = fid | (vid<<8);
powernow_table[i].index = index;
@@ -978,7 +978,7 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data,
/* verify frequency is OK */
if ((freq > (MAX_FREQ * 1000)) || (freq < (MIN_FREQ * 1000))) {
- dprintk("invalid freq %u kHz, ignoring\n", freq);
+ pr_debug("invalid freq %u kHz, ignoring\n", freq);
invalidate_entry(powernow_table, i);
continue;
}
@@ -986,7 +986,7 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data,
/* verify voltage is OK -
* BIOSs are using "off" to indicate invalid */
if (vid == VID_OFF) {
- dprintk("invalid vid %u, ignoring\n", vid);
+ pr_debug("invalid vid %u, ignoring\n", vid);
invalidate_entry(powernow_table, i);
continue;
}
@@ -1047,7 +1047,7 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data,
int res, i;
struct cpufreq_freqs freqs;
- dprintk("cpu %d transition to index %u\n", smp_processor_id(), index);
+ pr_debug("cpu %d transition to index %u\n", smp_processor_id(), index);
/* fid/vid correctness check for k8 */
/* fid are the lower 8 bits of the index we stored into
@@ -1057,18 +1057,18 @@ static int transition_frequency_fidvid(struct powernow_k8_data *data,
fid = data->powernow_table[index].index & 0xFF;
vid = (data->powernow_table[index].index & 0xFF00) >> 8;
- dprintk("table matched fid 0x%x, giving vid 0x%x\n", fid, vid);
+ pr_debug("table matched fid 0x%x, giving vid 0x%x\n", fid, vid);
if (query_current_values_with_pending_wait(data))
return 1;
if ((data->currvid == vid) && (data->currfid == fid)) {
- dprintk("target matches current values (fid 0x%x, vid 0x%x)\n",
+ pr_debug("target matches current values (fid 0x%x, vid 0x%x)\n",
fid, vid);
return 0;
}
- dprintk("cpu %d, changing to fid 0x%x, vid 0x%x\n",
+ pr_debug("cpu %d, changing to fid 0x%x, vid 0x%x\n",
smp_processor_id(), fid, vid);
freqs.old = find_khz_freq_from_fid(data->currfid);
freqs.new = find_khz_freq_from_fid(fid);
@@ -1096,7 +1096,7 @@ static int transition_frequency_pstate(struct powernow_k8_data *data,
int res, i;
struct cpufreq_freqs freqs;
- dprintk("cpu %d transition to index %u\n", smp_processor_id(), index);
+ pr_debug("cpu %d transition to index %u\n", smp_processor_id(), index);
/* get MSR index for hardware pstate transition */
pstate = index & HW_PSTATE_MASK;
@@ -1156,14 +1156,14 @@ static int powernowk8_target(struct cpufreq_policy *pol,
goto err_out;
}
- dprintk("targ: cpu %d, %d kHz, min %d, max %d, relation %d\n",
+ pr_debug("targ: cpu %d, %d kHz, min %d, max %d, relation %d\n",
pol->cpu, targfreq, pol->min, pol->max, relation);
if (query_current_values_with_pending_wait(data))
goto err_out;
if (cpu_family != CPU_HW_PSTATE) {
- dprintk("targ: curr fid 0x%x, vid 0x%x\n",
+ pr_debug("targ: curr fid 0x%x, vid 0x%x\n",
data->currfid, data->currvid);
if ((checkvid != data->currvid) ||
@@ -1319,7 +1319,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
data->currpstate);
else
pol->cur = find_khz_freq_from_fid(data->currfid);
- dprintk("policy current frequency %d kHz\n", pol->cur);
+ pr_debug("policy current frequency %d kHz\n", pol->cur);
/* min/max the cpu is capable of */
if (cpufreq_frequency_table_cpuinfo(pol, data->powernow_table)) {
@@ -1337,10 +1337,10 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
cpufreq_frequency_table_get_attr(data->powernow_table, pol->cpu);
if (cpu_family == CPU_HW_PSTATE)
- dprintk("cpu_init done, current pstate 0x%x\n",
+ pr_debug("cpu_init done, current pstate 0x%x\n",
data->currpstate);
else
- dprintk("cpu_init done, current fid 0x%x, vid 0x%x\n",
+ pr_debug("cpu_init done, current fid 0x%x, vid 0x%x\n",
data->currfid, data->currvid);
per_cpu(powernow_data, pol->cpu) = data;
@@ -1586,7 +1586,7 @@ static int __cpuinit powernowk8_init(void)
/* driver entry point for term */
static void __exit powernowk8_exit(void)
{
- dprintk("exit\n");
+ pr_debug("exit\n");
if (boot_cpu_has(X86_FEATURE_CPB)) {
msrs_free(msrs);
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.h b/drivers/cpufreq/powernow-k8.h
index df3529b1c02d..3744d26cdc2b 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.h
+++ b/drivers/cpufreq/powernow-k8.h
@@ -211,8 +211,6 @@ struct pst_s {
u8 vid;
};
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "powernow-k8", msg)
-
static int core_voltage_pre_transition(struct powernow_k8_data *data,
u32 reqvid, u32 regfid);
static int core_voltage_post_transition(struct powernow_k8_data *data, u32 reqvid);
diff --git a/arch/x86/kernel/cpu/cpufreq/sc520_freq.c b/drivers/cpufreq/sc520_freq.c
index 435a996a613a..1e205e6b1727 100644
--- a/arch/x86/kernel/cpu/cpufreq/sc520_freq.c
+++ b/drivers/cpufreq/sc520_freq.c
@@ -29,8 +29,6 @@
static __u8 __iomem *cpuctl;
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
- "sc520_freq", msg)
#define PFX "sc520_freq: "
static struct cpufreq_frequency_table sc520_freq_table[] = {
@@ -66,7 +64,7 @@ static void sc520_freq_set_cpu_state(unsigned int state)
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
- dprintk("attempting to set frequency to %i kHz\n",
+ pr_debug("attempting to set frequency to %i kHz\n",
sc520_freq_table[state].frequency);
local_irq_disable();
@@ -161,7 +159,7 @@ static int __init sc520_freq_init(void)
/* Test if we have the right hardware */
if (c->x86_vendor != X86_VENDOR_AMD ||
c->x86 != 4 || c->x86_model != 9) {
- dprintk("no Elan SC520 processor found!\n");
+ pr_debug("no Elan SC520 processor found!\n");
return -ENODEV;
}
cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1);
diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c b/drivers/cpufreq/speedstep-centrino.c
index 9b1ff37de46a..6ea3455def21 100644
--- a/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c
+++ b/drivers/cpufreq/speedstep-centrino.c
@@ -29,9 +29,6 @@
#define PFX "speedstep-centrino: "
#define MAINTAINER "cpufreq@vger.kernel.org"
-#define dprintk(msg...) \
- cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "speedstep-centrino", msg)
-
#define INTEL_MSR_RANGE (0xffff)
struct cpu_id
@@ -244,7 +241,7 @@ static int centrino_cpu_init_table(struct cpufreq_policy *policy)
if (model->cpu_id == NULL) {
/* No match at all */
- dprintk("no support for CPU model \"%s\": "
+ pr_debug("no support for CPU model \"%s\": "
"send /proc/cpuinfo to " MAINTAINER "\n",
cpu->x86_model_id);
return -ENOENT;
@@ -252,15 +249,15 @@ static int centrino_cpu_init_table(struct cpufreq_policy *policy)
if (model->op_points == NULL) {
/* Matched a non-match */
- dprintk("no table support for CPU model \"%s\"\n",
+ pr_debug("no table support for CPU model \"%s\"\n",
cpu->x86_model_id);
- dprintk("try using the acpi-cpufreq driver\n");
+ pr_debug("try using the acpi-cpufreq driver\n");
return -ENOENT;
}
per_cpu(centrino_model, policy->cpu) = model;
- dprintk("found \"%s\": max frequency: %dkHz\n",
+ pr_debug("found \"%s\": max frequency: %dkHz\n",
model->model_name, model->max_freq);
return 0;
@@ -369,7 +366,7 @@ static int centrino_cpu_init(struct cpufreq_policy *policy)
per_cpu(centrino_cpu, policy->cpu) = &cpu_ids[i];
if (!per_cpu(centrino_cpu, policy->cpu)) {
- dprintk("found unsupported CPU with "
+ pr_debug("found unsupported CPU with "
"Enhanced SpeedStep: send /proc/cpuinfo to "
MAINTAINER "\n");
return -ENODEV;
@@ -385,7 +382,7 @@ static int centrino_cpu_init(struct cpufreq_policy *policy)
if (!(l & MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP)) {
l |= MSR_IA32_MISC_ENABLE_ENHANCED_SPEEDSTEP;
- dprintk("trying to enable Enhanced SpeedStep (%x)\n", l);
+ pr_debug("trying to enable Enhanced SpeedStep (%x)\n", l);
wrmsr(MSR_IA32_MISC_ENABLE, l, h);
/* check to see if it stuck */
@@ -402,7 +399,7 @@ static int centrino_cpu_init(struct cpufreq_policy *policy)
/* 10uS transition latency */
policy->cur = freq;
- dprintk("centrino_cpu_init: cur=%dkHz\n", policy->cur);
+ pr_debug("centrino_cpu_init: cur=%dkHz\n", policy->cur);
ret = cpufreq_frequency_table_cpuinfo(policy,
per_cpu(centrino_model, policy->cpu)->op_points);
@@ -498,7 +495,7 @@ static int centrino_target (struct cpufreq_policy *policy,
good_cpu = j;
if (good_cpu >= nr_cpu_ids) {
- dprintk("couldn't limit to CPUs in this domain\n");
+ pr_debug("couldn't limit to CPUs in this domain\n");
retval = -EAGAIN;
if (first_cpu) {
/* We haven't started the transition yet. */
@@ -512,7 +509,7 @@ static int centrino_target (struct cpufreq_policy *policy,
if (first_cpu) {
rdmsr_on_cpu(good_cpu, MSR_IA32_PERF_CTL, &oldmsr, &h);
if (msr == (oldmsr & 0xffff)) {
- dprintk("no change needed - msr was and needs "
+ pr_debug("no change needed - msr was and needs "
"to be %x\n", oldmsr);
retval = 0;
goto out;
@@ -521,7 +518,7 @@ static int centrino_target (struct cpufreq_policy *policy,
freqs.old = extract_clock(oldmsr, cpu, 0);
freqs.new = extract_clock(msr, cpu, 0);
- dprintk("target=%dkHz old=%d new=%d msr=%04x\n",
+ pr_debug("target=%dkHz old=%d new=%d msr=%04x\n",
target_freq, freqs.old, freqs.new, msr);
for_each_cpu(k, policy->cpus) {
diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c b/drivers/cpufreq/speedstep-ich.c
index 561758e95180..a748ce782fee 100644
--- a/arch/x86/kernel/cpu/cpufreq/speedstep-ich.c
+++ b/drivers/cpufreq/speedstep-ich.c
@@ -53,10 +53,6 @@ static struct cpufreq_frequency_table speedstep_freqs[] = {
};
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
- "speedstep-ich", msg)
-
-
/**
* speedstep_find_register - read the PMBASE address
*
@@ -80,7 +76,7 @@ static int speedstep_find_register(void)
return -ENODEV;
}
- dprintk("pmbase is 0x%x\n", pmbase);
+ pr_debug("pmbase is 0x%x\n", pmbase);
return 0;
}
@@ -106,13 +102,13 @@ static void speedstep_set_state(unsigned int state)
/* read state */
value = inb(pmbase + 0x50);
- dprintk("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value);
+ pr_debug("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value);
/* write new state */
value &= 0xFE;
value |= state;
- dprintk("writing 0x%x to pmbase 0x%x + 0x50\n", value, pmbase);
+ pr_debug("writing 0x%x to pmbase 0x%x + 0x50\n", value, pmbase);
/* Disable bus master arbitration */
pm2_blk = inb(pmbase + 0x20);
@@ -132,10 +128,10 @@ static void speedstep_set_state(unsigned int state)
/* Enable IRQs */
local_irq_restore(flags);
- dprintk("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value);
+ pr_debug("read at pmbase 0x%x + 0x50 returned 0x%x\n", pmbase, value);
if (state == (value & 0x1))
- dprintk("change to %u MHz succeeded\n",
+ pr_debug("change to %u MHz succeeded\n",
speedstep_get_frequency(speedstep_processor) / 1000);
else
printk(KERN_ERR "cpufreq: change failed - I/O error\n");
@@ -165,7 +161,7 @@ static int speedstep_activate(void)
pci_read_config_word(speedstep_chipset_dev, 0x00A0, &value);
if (!(value & 0x08)) {
value |= 0x08;
- dprintk("activating SpeedStep (TM) registers\n");
+ pr_debug("activating SpeedStep (TM) registers\n");
pci_write_config_word(speedstep_chipset_dev, 0x00A0, value);
}
@@ -218,7 +214,7 @@ static unsigned int speedstep_detect_chipset(void)
return 2; /* 2-M */
if (hostbridge->revision < 5) {
- dprintk("hostbridge does not support speedstep\n");
+ pr_debug("hostbridge does not support speedstep\n");
speedstep_chipset_dev = NULL;
pci_dev_put(hostbridge);
return 0;
@@ -246,7 +242,7 @@ static unsigned int speedstep_get(unsigned int cpu)
if (smp_call_function_single(cpu, get_freq_data, &speed, 1) != 0)
BUG();
- dprintk("detected %u kHz as current frequency\n", speed);
+ pr_debug("detected %u kHz as current frequency\n", speed);
return speed;
}
@@ -276,7 +272,7 @@ static int speedstep_target(struct cpufreq_policy *policy,
freqs.new = speedstep_freqs[newstate].frequency;
freqs.cpu = policy->cpu;
- dprintk("transiting from %u to %u kHz\n", freqs.old, freqs.new);
+ pr_debug("transiting from %u to %u kHz\n", freqs.old, freqs.new);
/* no transition necessary */
if (freqs.old == freqs.new)
@@ -351,7 +347,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
if (!speed)
return -EIO;
- dprintk("currently at %s speed setting - %i MHz\n",
+ pr_debug("currently at %s speed setting - %i MHz\n",
(speed == speedstep_freqs[SPEEDSTEP_LOW].frequency)
? "low" : "high",
(speed / 1000));
@@ -405,14 +401,14 @@ static int __init speedstep_init(void)
/* detect processor */
speedstep_processor = speedstep_detect_processor();
if (!speedstep_processor) {
- dprintk("Intel(R) SpeedStep(TM) capable processor "
+ pr_debug("Intel(R) SpeedStep(TM) capable processor "
"not found\n");
return -ENODEV;
}
/* detect chipset */
if (!speedstep_detect_chipset()) {
- dprintk("Intel(R) SpeedStep(TM) for this chipset not "
+ pr_debug("Intel(R) SpeedStep(TM) for this chipset not "
"(yet) available.\n");
return -ENODEV;
}
diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c b/drivers/cpufreq/speedstep-lib.c
index a94ec6be69fa..8af2d2fd9d51 100644
--- a/arch/x86/kernel/cpu/cpufreq/speedstep-lib.c
+++ b/drivers/cpufreq/speedstep-lib.c
@@ -18,9 +18,6 @@
#include <asm/tsc.h>
#include "speedstep-lib.h"
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
- "speedstep-lib", msg)
-
#define PFX "speedstep-lib: "
#ifdef CONFIG_X86_SPEEDSTEP_RELAXED_CAP_CHECK
@@ -75,7 +72,7 @@ static unsigned int pentium3_get_frequency(enum speedstep_processor processor)
/* read MSR 0x2a - we only need the low 32 bits */
rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp);
- dprintk("P3 - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp);
+ pr_debug("P3 - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp);
msr_tmp = msr_lo;
/* decode the FSB */
@@ -89,7 +86,7 @@ static unsigned int pentium3_get_frequency(enum speedstep_processor processor)
/* decode the multiplier */
if (processor == SPEEDSTEP_CPU_PIII_C_EARLY) {
- dprintk("workaround for early PIIIs\n");
+ pr_debug("workaround for early PIIIs\n");
msr_lo &= 0x03c00000;
} else
msr_lo &= 0x0bc00000;
@@ -100,7 +97,7 @@ static unsigned int pentium3_get_frequency(enum speedstep_processor processor)
j++;
}
- dprintk("speed is %u\n",
+ pr_debug("speed is %u\n",
(msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100));
return msr_decode_mult[j].ratio * msr_decode_fsb[i].value * 100;
@@ -112,7 +109,7 @@ static unsigned int pentiumM_get_frequency(void)
u32 msr_lo, msr_tmp;
rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp);
- dprintk("PM - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp);
+ pr_debug("PM - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n", msr_lo, msr_tmp);
/* see table B-2 of 24547212.pdf */
if (msr_lo & 0x00040000) {
@@ -122,7 +119,7 @@ static unsigned int pentiumM_get_frequency(void)
}
msr_tmp = (msr_lo >> 22) & 0x1f;
- dprintk("bits 22-26 are 0x%x, speed is %u\n",
+ pr_debug("bits 22-26 are 0x%x, speed is %u\n",
msr_tmp, (msr_tmp * 100 * 1000));
return msr_tmp * 100 * 1000;
@@ -160,11 +157,11 @@ static unsigned int pentium_core_get_frequency(void)
}
rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_tmp);
- dprintk("PCORE - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n",
+ pr_debug("PCORE - MSR_IA32_EBL_CR_POWERON: 0x%x 0x%x\n",
msr_lo, msr_tmp);
msr_tmp = (msr_lo >> 22) & 0x1f;
- dprintk("bits 22-26 are 0x%x, speed is %u\n",
+ pr_debug("bits 22-26 are 0x%x, speed is %u\n",
msr_tmp, (msr_tmp * fsb));
ret = (msr_tmp * fsb);
@@ -190,7 +187,7 @@ static unsigned int pentium4_get_frequency(void)
rdmsr(0x2c, msr_lo, msr_hi);
- dprintk("P4 - MSR_EBC_FREQUENCY_ID: 0x%x 0x%x\n", msr_lo, msr_hi);
+ pr_debug("P4 - MSR_EBC_FREQUENCY_ID: 0x%x 0x%x\n", msr_lo, msr_hi);
/* decode the FSB: see IA-32 Intel (C) Architecture Software
* Developer's Manual, Volume 3: System Prgramming Guide,
@@ -217,7 +214,7 @@ static unsigned int pentium4_get_frequency(void)
/* Multiplier. */
mult = msr_lo >> 24;
- dprintk("P4 - FSB %u kHz; Multiplier %u; Speed %u kHz\n",
+ pr_debug("P4 - FSB %u kHz; Multiplier %u; Speed %u kHz\n",
fsb, mult, (fsb * mult));
ret = (fsb * mult);
@@ -257,7 +254,7 @@ unsigned int speedstep_detect_processor(void)
struct cpuinfo_x86 *c = &cpu_data(0);
u32 ebx, msr_lo, msr_hi;
- dprintk("x86: %x, model: %x\n", c->x86, c->x86_model);
+ pr_debug("x86: %x, model: %x\n", c->x86, c->x86_model);
if ((c->x86_vendor != X86_VENDOR_INTEL) ||
((c->x86 != 6) && (c->x86 != 0xF)))
@@ -272,7 +269,7 @@ unsigned int speedstep_detect_processor(void)
ebx = cpuid_ebx(0x00000001);
ebx &= 0x000000FF;
- dprintk("ebx value is %x, x86_mask is %x\n", ebx, c->x86_mask);
+ pr_debug("ebx value is %x, x86_mask is %x\n", ebx, c->x86_mask);
switch (c->x86_mask) {
case 4:
@@ -327,7 +324,7 @@ unsigned int speedstep_detect_processor(void)
/* cpuid_ebx(1) is 0x04 for desktop PIII,
* 0x06 for mobile PIII-M */
ebx = cpuid_ebx(0x00000001);
- dprintk("ebx is %x\n", ebx);
+ pr_debug("ebx is %x\n", ebx);
ebx &= 0x000000FF;
@@ -344,7 +341,7 @@ unsigned int speedstep_detect_processor(void)
/* all mobile PIII Coppermines have FSB 100 MHz
* ==> sort out a few desktop PIIIs. */
rdmsr(MSR_IA32_EBL_CR_POWERON, msr_lo, msr_hi);
- dprintk("Coppermine: MSR_IA32_EBL_CR_POWERON is 0x%x, 0x%x\n",
+ pr_debug("Coppermine: MSR_IA32_EBL_CR_POWERON is 0x%x, 0x%x\n",
msr_lo, msr_hi);
msr_lo &= 0x00c0000;
if (msr_lo != 0x0080000)
@@ -357,12 +354,12 @@ unsigned int speedstep_detect_processor(void)
* bit 56 or 57 is set
*/
rdmsr(MSR_IA32_PLATFORM_ID, msr_lo, msr_hi);
- dprintk("Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n",
+ pr_debug("Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n",
msr_lo, msr_hi);
if ((msr_hi & (1<<18)) &&
(relaxed_check ? 1 : (msr_hi & (3<<24)))) {
if (c->x86_mask == 0x01) {
- dprintk("early PIII version\n");
+ pr_debug("early PIII version\n");
return SPEEDSTEP_CPU_PIII_C_EARLY;
} else
return SPEEDSTEP_CPU_PIII_C;
@@ -393,14 +390,14 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor,
if ((!processor) || (!low_speed) || (!high_speed) || (!set_state))
return -EINVAL;
- dprintk("trying to determine both speeds\n");
+ pr_debug("trying to determine both speeds\n");
/* get current speed */
prev_speed = speedstep_get_frequency(processor);
if (!prev_speed)
return -EIO;
- dprintk("previous speed is %u\n", prev_speed);
+ pr_debug("previous speed is %u\n", prev_speed);
local_irq_save(flags);
@@ -412,7 +409,7 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor,
goto out;
}
- dprintk("low speed is %u\n", *low_speed);
+ pr_debug("low speed is %u\n", *low_speed);
/* start latency measurement */
if (transition_latency)
@@ -431,7 +428,7 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor,
goto out;
}
- dprintk("high speed is %u\n", *high_speed);
+ pr_debug("high speed is %u\n", *high_speed);
if (*low_speed == *high_speed) {
ret = -ENODEV;
@@ -445,7 +442,7 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor,
if (transition_latency) {
*transition_latency = (tv2.tv_sec - tv1.tv_sec) * USEC_PER_SEC +
tv2.tv_usec - tv1.tv_usec;
- dprintk("transition latency is %u uSec\n", *transition_latency);
+ pr_debug("transition latency is %u uSec\n", *transition_latency);
/* convert uSec to nSec and add 20% for safety reasons */
*transition_latency *= 1200;
diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-lib.h b/drivers/cpufreq/speedstep-lib.h
index 70d9cea1219d..70d9cea1219d 100644
--- a/arch/x86/kernel/cpu/cpufreq/speedstep-lib.h
+++ b/drivers/cpufreq/speedstep-lib.h
diff --git a/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c b/drivers/cpufreq/speedstep-smi.c
index 91bc25b67bc1..c76ead3490bf 100644
--- a/arch/x86/kernel/cpu/cpufreq/speedstep-smi.c
+++ b/drivers/cpufreq/speedstep-smi.c
@@ -55,9 +55,6 @@ static struct cpufreq_frequency_table speedstep_freqs[] = {
* of DMA activity going on? */
#define SMI_TRIES 5
-#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \
- "speedstep-smi", msg)
-
/**
* speedstep_smi_ownership
*/
@@ -70,7 +67,7 @@ static int speedstep_smi_ownership(void)
command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
magic = virt_to_phys(magic_data);
- dprintk("trying to obtain ownership with command %x at port %x\n",
+ pr_debug("trying to obtain ownership with command %x at port %x\n",
command, smi_port);
__asm__ __volatile__(
@@ -85,7 +82,7 @@ static int speedstep_smi_ownership(void)
: "memory"
);
- dprintk("result is %x\n", result);
+ pr_debug("result is %x\n", result);
return result;
}
@@ -106,13 +103,13 @@ static int speedstep_smi_get_freqs(unsigned int *low, unsigned int *high)
u32 function = GET_SPEEDSTEP_FREQS;
if (!(ist_info.event & 0xFFFF)) {
- dprintk("bug #1422 -- can't read freqs from BIOS\n");
+ pr_debug("bug #1422 -- can't read freqs from BIOS\n");
return -ENODEV;
}
command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
- dprintk("trying to determine frequencies with command %x at port %x\n",
+ pr_debug("trying to determine frequencies with command %x at port %x\n",
command, smi_port);
__asm__ __volatile__(
@@ -129,7 +126,7 @@ static int speedstep_smi_get_freqs(unsigned int *low, unsigned int *high)
"d" (smi_port), "S" (0), "D" (0)
);
- dprintk("result %x, low_freq %u, high_freq %u\n",
+ pr_debug("result %x, low_freq %u, high_freq %u\n",
result, low_mhz, high_mhz);
/* abort if results are obviously incorrect... */
@@ -154,7 +151,7 @@ static int speedstep_get_state(void)
command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
- dprintk("trying to determine current setting with command %x "
+ pr_debug("trying to determine current setting with command %x "
"at port %x\n", command, smi_port);
__asm__ __volatile__(
@@ -168,7 +165,7 @@ static int speedstep_get_state(void)
"d" (smi_port), "S" (0), "D" (0)
);
- dprintk("state is %x, result is %x\n", state, result);
+ pr_debug("state is %x, result is %x\n", state, result);
return state & 1;
}
@@ -194,13 +191,13 @@ static void speedstep_set_state(unsigned int state)
command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
- dprintk("trying to set frequency to state %u "
+ pr_debug("trying to set frequency to state %u "
"with command %x at port %x\n",
state, command, smi_port);
do {
if (retry) {
- dprintk("retry %u, previous result %u, waiting...\n",
+ pr_debug("retry %u, previous result %u, waiting...\n",
retry, result);
mdelay(retry * 50);
}
@@ -221,7 +218,7 @@ static void speedstep_set_state(unsigned int state)
local_irq_restore(flags);
if (new_state == state)
- dprintk("change to %u MHz succeeded after %u tries "
+ pr_debug("change to %u MHz succeeded after %u tries "
"with result %u\n",
(speedstep_freqs[new_state].frequency / 1000),
retry, result);
@@ -292,7 +289,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
result = speedstep_smi_ownership();
if (result) {
- dprintk("fails in acquiring ownership of a SMI interface.\n");
+ pr_debug("fails in acquiring ownership of a SMI interface.\n");
return -EINVAL;
}
@@ -304,7 +301,7 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
if (result) {
/* fall back to speedstep_lib.c dection mechanism:
* try both states out */
- dprintk("could not detect low and high frequencies "
+ pr_debug("could not detect low and high frequencies "
"by SMI call.\n");
result = speedstep_get_freqs(speedstep_processor,
low, high,
@@ -312,18 +309,18 @@ static int speedstep_cpu_init(struct cpufreq_policy *policy)
&speedstep_set_state);
if (result) {
- dprintk("could not detect two different speeds"
+ pr_debug("could not detect two different speeds"
" -- aborting.\n");
return result;
} else
- dprintk("workaround worked.\n");
+ pr_debug("workaround worked.\n");
}
/* get current speed setting */
state = speedstep_get_state();
speed = speedstep_freqs[state].frequency;
- dprintk("currently at %s speed setting - %i MHz\n",
+ pr_debug("currently at %s speed setting - %i MHz\n",
(speed == speedstep_freqs[SPEEDSTEP_LOW].frequency)
? "low" : "high",
(speed / 1000));
@@ -360,7 +357,7 @@ static int speedstep_resume(struct cpufreq_policy *policy)
int result = speedstep_smi_ownership();
if (result)
- dprintk("fails in re-acquiring ownership of a SMI interface.\n");
+ pr_debug("fails in re-acquiring ownership of a SMI interface.\n");
return result;
}
@@ -403,12 +400,12 @@ static int __init speedstep_init(void)
}
if (!speedstep_processor) {
- dprintk("No supported Intel CPU detected.\n");
+ pr_debug("No supported Intel CPU detected.\n");
return -ENODEV;
}
- dprintk("signature:0x%.8lx, command:0x%.8lx, "
- "event:0x%.8lx, perf_level:0x%.8lx.\n",
+ pr_debug("signature:0x%.8ulx, command:0x%.8ulx, "
+ "event:0x%.8ulx, perf_level:0x%.8ulx.\n",
ist_info.signature, ist_info.command,
ist_info.event, ist_info.perf_level);
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index e54185223c8c..e0b25de1e339 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -74,6 +74,8 @@ config ZCRYPT
+ PCI-X Cryptographic Coprocessor (PCIXCC)
+ Crypto Express2 Coprocessor (CEX2C)
+ Crypto Express2 Accelerator (CEX2A)
+ + Crypto Express3 Coprocessor (CEX3C)
+ + Crypto Express3 Accelerator (CEX3A)
config ZCRYPT_MONOLITHIC
bool "Monolithic zcrypt module"
@@ -91,6 +93,8 @@ config CRYPTO_SHA1_S390
This is the s390 hardware accelerated implementation of the
SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
+ It is available as of z990.
+
config CRYPTO_SHA256_S390
tristate "SHA256 digest algorithm"
depends on S390
@@ -99,8 +103,7 @@ config CRYPTO_SHA256_S390
This is the s390 hardware accelerated implementation of the
SHA256 secure hash standard (DFIPS 180-2).
- This version of SHA implements a 256 bit hash with 128 bits of
- security against collision attacks.
+ It is available as of z9.
config CRYPTO_SHA512_S390
tristate "SHA384 and SHA512 digest algorithm"
@@ -110,10 +113,7 @@ config CRYPTO_SHA512_S390
This is the s390 hardware accelerated implementation of the
SHA512 secure hash standard.
- This version of SHA implements a 512 bit hash with 256 bits of
- security against collision attacks. The code also includes SHA-384,
- a 384 bit hash with 192 bits of security against collision attacks.
-
+ It is available as of z10.
config CRYPTO_DES_S390
tristate "DES and Triple DES cipher algorithms"
@@ -121,9 +121,12 @@ config CRYPTO_DES_S390
select CRYPTO_ALGAPI
select CRYPTO_BLKCIPHER
help
- This us the s390 hardware accelerated implementation of the
+ This is the s390 hardware accelerated implementation of the
DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
+ As of z990 the ECB and CBC mode are hardware accelerated.
+ As of z196 the CTR mode is hardware accelerated.
+
config CRYPTO_AES_S390
tristate "AES cipher algorithms"
depends on S390
@@ -131,20 +134,15 @@ config CRYPTO_AES_S390
select CRYPTO_BLKCIPHER
help
This is the s390 hardware accelerated implementation of the
- AES cipher algorithms (FIPS-197). AES uses the Rijndael
- algorithm.
-
- Rijndael appears to be consistently a very good performer in
- both hardware and software across a wide range of computing
- environments regardless of its use in feedback or non-feedback
- modes. Its key setup time is excellent, and its key agility is
- good. Rijndael's very low memory requirements make it very well
- suited for restricted-space environments, in which it also
- demonstrates excellent performance. Rijndael's operations are
- among the easiest to defend against power and timing attacks.
+ AES cipher algorithms (FIPS-197).
- On s390 the System z9-109 currently only supports the key size
- of 128 bit.
+ As of z9 the ECB and CBC modes are hardware accelerated
+ for 128 bit keys.
+ As of z10 the ECB and CBC modes are hardware accelerated
+ for all AES key sizes.
+ As of z196 the CTR mode is hardware accelerated for all AES
+ key sizes and XTS mode is hardware accelerated for 256 and
+ 512 bit keys.
config S390_PRNG
tristate "Pseudo random number generator device driver"
@@ -154,8 +152,20 @@ config S390_PRNG
Select this option if you want to use the s390 pseudo random number
generator. The PRNG is part of the cryptographic processor functions
and uses triple-DES to generate secure random numbers like the
- ANSI X9.17 standard. The PRNG is usable via the char device
- /dev/prandom.
+ ANSI X9.17 standard. User-space programs access the
+ pseudo-random-number device through the char device /dev/prandom.
+
+ It is available as of z9.
+
+config CRYPTO_GHASH_S390
+ tristate "GHASH digest algorithm"
+ depends on S390
+ select CRYPTO_HASH
+ help
+ This is the s390 hardware accelerated implementation of the
+ GHASH message digest algorithm for GCM (Galois/Counter Mode).
+
+ It is available as of z196.
config CRYPTO_DEV_MV_CESA
tristate "Marvell's Cryptographic Engine"
@@ -200,6 +210,8 @@ config CRYPTO_DEV_HIFN_795X_RNG
Select this option if you want to enable the random number generator
on the HIFN 795x crypto adapters.
+source drivers/crypto/caam/Kconfig
+
config CRYPTO_DEV_TALITOS
tristate "Talitos Freescale Security Engine (SEC)"
select CRYPTO_ALGAPI
@@ -269,4 +281,15 @@ config CRYPTO_DEV_PICOXCELL
Saying m here will build a module named pipcoxcell_crypto.
+config CRYPTO_DEV_S5P
+ tristate "Support for Samsung S5PV210 crypto accelerator"
+ depends on ARCH_S5PV210
+ select CRYPTO_AES
+ select CRYPTO_ALGAPI
+ select CRYPTO_BLKCIPHER
+ help
+ This option allows you to have support for S5P crypto acceleration.
+ Select this to offload Samsung S5PV210 or S5PC110 from AES
+ algorithms execution.
+
endif # CRYPTO_HW
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 5203e34248d7..53ea50155319 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -6,8 +6,10 @@ n2_crypto-y := n2_core.o n2_asm.o
obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o
obj-$(CONFIG_CRYPTO_DEV_MV_CESA) += mv_cesa.o
obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o
+obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam/
obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o
obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += amcc/
obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o
obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o
obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o
+obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig
new file mode 100644
index 000000000000..2d876bb98ff4
--- /dev/null
+++ b/drivers/crypto/caam/Kconfig
@@ -0,0 +1,72 @@
+config CRYPTO_DEV_FSL_CAAM
+ tristate "Freescale CAAM-Multicore driver backend"
+ depends on FSL_SOC
+ help
+ Enables the driver module for Freescale's Cryptographic Accelerator
+ and Assurance Module (CAAM), also known as the SEC version 4 (SEC4).
+ This module adds a job ring operation interface, and configures h/w
+ to operate as a DPAA component automatically, depending
+ on h/w feature availability.
+
+ To compile this driver as a module, choose M here: the module
+ will be called caam.
+
+config CRYPTO_DEV_FSL_CAAM_RINGSIZE
+ int "Job Ring size"
+ depends on CRYPTO_DEV_FSL_CAAM
+ range 2 9
+ default "9"
+ help
+ Select size of Job Rings as a power of 2, within the
+ range 2-9 (ring size 4-512).
+ Examples:
+ 2 => 4
+ 3 => 8
+ 4 => 16
+ 5 => 32
+ 6 => 64
+ 7 => 128
+ 8 => 256
+ 9 => 512
+
+config CRYPTO_DEV_FSL_CAAM_INTC
+ bool "Job Ring interrupt coalescing"
+ depends on CRYPTO_DEV_FSL_CAAM
+ default y
+ help
+ Enable the Job Ring's interrupt coalescing feature.
+
+config CRYPTO_DEV_FSL_CAAM_INTC_COUNT_THLD
+ int "Job Ring interrupt coalescing count threshold"
+ depends on CRYPTO_DEV_FSL_CAAM_INTC
+ range 1 255
+ default 255
+ help
+ Select number of descriptor completions to queue before
+ raising an interrupt, in the range 1-255. Note that a selection
+ of 1 functionally defeats the coalescing feature, and a selection
+ equal or greater than the job ring size will force timeouts.
+
+config CRYPTO_DEV_FSL_CAAM_INTC_TIME_THLD
+ int "Job Ring interrupt coalescing timer threshold"
+ depends on CRYPTO_DEV_FSL_CAAM_INTC
+ range 1 65535
+ default 2048
+ help
+ Select number of bus clocks/64 to timeout in the case that one or
+ more descriptor completions are queued without reaching the count
+ threshold. Range is 1-65535.
+
+config CRYPTO_DEV_FSL_CAAM_CRYPTO_API
+ tristate "Register algorithm implementations with the Crypto API"
+ depends on CRYPTO_DEV_FSL_CAAM
+ default y
+ select CRYPTO_ALGAPI
+ select CRYPTO_AUTHENC
+ help
+ Selecting this will offload crypto for users of the
+ scatterlist crypto API (such as the linux native IPSec
+ stack) to the SEC4 via job ring.
+
+ To compile this as a module, choose M here: the module
+ will be called caamalg.
diff --git a/drivers/crypto/caam/Makefile b/drivers/crypto/caam/Makefile
new file mode 100644
index 000000000000..ef39011b4505
--- /dev/null
+++ b/drivers/crypto/caam/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the CAAM backend and dependent components
+#
+
+obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam.o
+obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o
+
+caam-objs := ctrl.o jr.o error.o
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
new file mode 100644
index 000000000000..d0e65d6ddc77
--- /dev/null
+++ b/drivers/crypto/caam/caamalg.c
@@ -0,0 +1,1268 @@
+/*
+ * caam - Freescale FSL CAAM support for crypto API
+ *
+ * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ *
+ * Based on talitos crypto API driver.
+ *
+ * relationship of job descriptors to shared descriptors (SteveC Dec 10 2008):
+ *
+ * --------------- ---------------
+ * | JobDesc #1 |-------------------->| ShareDesc |
+ * | *(packet 1) | | (PDB) |
+ * --------------- |------------->| (hashKey) |
+ * . | | (cipherKey) |
+ * . | |-------->| (operation) |
+ * --------------- | | ---------------
+ * | JobDesc #2 |------| |
+ * | *(packet 2) | |
+ * --------------- |
+ * . |
+ * . |
+ * --------------- |
+ * | JobDesc #3 |------------
+ * | *(packet 3) |
+ * ---------------
+ *
+ * The SharedDesc never changes for a connection unless rekeyed, but
+ * each packet will likely be in a different place. So all we need
+ * to know to process the packet is where the input is, where the
+ * output goes, and what context we want to process with. Context is
+ * in the SharedDesc, packet references in the JobDesc.
+ *
+ * So, a job desc looks like:
+ *
+ * ---------------------
+ * | Header |
+ * | ShareDesc Pointer |
+ * | SEQ_OUT_PTR |
+ * | (output buffer) |
+ * | SEQ_IN_PTR |
+ * | (input buffer) |
+ * | LOAD (to DECO) |
+ * ---------------------
+ */
+
+#include "compat.h"
+
+#include "regs.h"
+#include "intern.h"
+#include "desc_constr.h"
+#include "jr.h"
+#include "error.h"
+
+/*
+ * crypto alg
+ */
+#define CAAM_CRA_PRIORITY 3000
+/* max key is sum of AES_MAX_KEY_SIZE, max split key size */
+#define CAAM_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + \
+ SHA512_DIGEST_SIZE * 2)
+/* max IV is max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */
+#define CAAM_MAX_IV_LENGTH 16
+
+/* length of descriptors text */
+#define DESC_AEAD_SHARED_TEXT_LEN 4
+#define DESC_AEAD_ENCRYPT_TEXT_LEN 21
+#define DESC_AEAD_DECRYPT_TEXT_LEN 24
+#define DESC_AEAD_GIVENCRYPT_TEXT_LEN 27
+
+#ifdef DEBUG
+/* for print_hex_dumps with line references */
+#define xstr(s) str(s)
+#define str(s) #s
+#define debug(format, arg...) printk(format, arg)
+#else
+#define debug(format, arg...)
+#endif
+
+/*
+ * per-session context
+ */
+struct caam_ctx {
+ struct device *jrdev;
+ u32 *sh_desc;
+ dma_addr_t shared_desc_phys;
+ u32 class1_alg_type;
+ u32 class2_alg_type;
+ u32 alg_op;
+ u8 *key;
+ dma_addr_t key_phys;
+ unsigned int enckeylen;
+ unsigned int split_key_len;
+ unsigned int split_key_pad_len;
+ unsigned int authsize;
+};
+
+static int aead_authenc_setauthsize(struct crypto_aead *authenc,
+ unsigned int authsize)
+{
+ struct caam_ctx *ctx = crypto_aead_ctx(authenc);
+
+ ctx->authsize = authsize;
+
+ return 0;
+}
+
+struct split_key_result {
+ struct completion completion;
+ int err;
+};
+
+static void split_key_done(struct device *dev, u32 *desc, u32 err,
+ void *context)
+{
+ struct split_key_result *res = context;
+
+#ifdef DEBUG
+ dev_err(dev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
+#endif
+ if (err) {
+ char tmp[CAAM_ERROR_STR_MAX];
+
+ dev_err(dev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err));
+ }
+
+ res->err = err;
+
+ complete(&res->completion);
+}
+
+/*
+get a split ipad/opad key
+
+Split key generation-----------------------------------------------
+
+[00] 0xb0810008 jobdesc: stidx=1 share=never len=8
+[01] 0x04000014 key: class2->keyreg len=20
+ @0xffe01000
+[03] 0x84410014 operation: cls2-op sha1 hmac init dec
+[04] 0x24940000 fifold: class2 msgdata-last2 len=0 imm
+[05] 0xa4000001 jump: class2 local all ->1 [06]
+[06] 0x64260028 fifostr: class2 mdsplit-jdk len=40
+ @0xffe04000
+*/
+static u32 gen_split_key(struct caam_ctx *ctx, const u8 *key_in, u32 authkeylen)
+{
+ struct device *jrdev = ctx->jrdev;
+ u32 *desc;
+ struct split_key_result result;
+ dma_addr_t dma_addr_in, dma_addr_out;
+ int ret = 0;
+
+ desc = kmalloc(CAAM_CMD_SZ * 6 + CAAM_PTR_SZ * 2, GFP_KERNEL | GFP_DMA);
+
+ init_job_desc(desc, 0);
+
+ dma_addr_in = dma_map_single(jrdev, (void *)key_in, authkeylen,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(jrdev, dma_addr_in)) {
+ dev_err(jrdev, "unable to map key input memory\n");
+ kfree(desc);
+ return -ENOMEM;
+ }
+ append_key(desc, dma_addr_in, authkeylen, CLASS_2 |
+ KEY_DEST_CLASS_REG);
+
+ /* Sets MDHA up into an HMAC-INIT */
+ append_operation(desc, ctx->alg_op | OP_ALG_DECRYPT |
+ OP_ALG_AS_INIT);
+
+ /*
+ * do a FIFO_LOAD of zero, this will trigger the internal key expansion
+ into both pads inside MDHA
+ */
+ append_fifo_load_as_imm(desc, NULL, 0, LDST_CLASS_2_CCB |
+ FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST2);
+
+ /*
+ * FIFO_STORE with the explicit split-key content store
+ * (0x26 output type)
+ */
+ dma_addr_out = dma_map_single(jrdev, ctx->key, ctx->split_key_pad_len,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(jrdev, dma_addr_out)) {
+ dev_err(jrdev, "unable to map key output memory\n");
+ kfree(desc);
+ return -ENOMEM;
+ }
+ append_fifo_store(desc, dma_addr_out, ctx->split_key_len,
+ LDST_CLASS_2_CCB | FIFOST_TYPE_SPLIT_KEK);
+
+#ifdef DEBUG
+ print_hex_dump(KERN_ERR, "ctx.key@"xstr(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key_in, authkeylen, 1);
+ print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1);
+#endif
+
+ result.err = 0;
+ init_completion(&result.completion);
+
+ ret = caam_jr_enqueue(jrdev, desc, split_key_done, &result);
+ if (!ret) {
+ /* in progress */
+ wait_for_completion_interruptible(&result.completion);
+ ret = result.err;
+#ifdef DEBUG
+ print_hex_dump(KERN_ERR, "ctx.key@"xstr(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, ctx->key,
+ ctx->split_key_pad_len, 1);
+#endif
+ }
+
+ dma_unmap_single(jrdev, dma_addr_out, ctx->split_key_pad_len,
+ DMA_FROM_DEVICE);
+ dma_unmap_single(jrdev, dma_addr_in, authkeylen, DMA_TO_DEVICE);
+
+ kfree(desc);
+
+ return ret;
+}
+
+static int build_sh_desc_ipsec(struct caam_ctx *ctx)
+{
+ struct device *jrdev = ctx->jrdev;
+ u32 *sh_desc;
+ u32 *jump_cmd;
+ bool keys_fit_inline = 0;
+
+ /*
+ * largest Job Descriptor and its Shared Descriptor
+ * must both fit into the 64-word Descriptor h/w Buffer
+ */
+ if ((DESC_AEAD_GIVENCRYPT_TEXT_LEN +
+ DESC_AEAD_SHARED_TEXT_LEN) * CAAM_CMD_SZ +
+ ctx->split_key_pad_len + ctx->enckeylen <= CAAM_DESC_BYTES_MAX)
+ keys_fit_inline = 1;
+
+ /* build shared descriptor for this session */
+ sh_desc = kmalloc(CAAM_CMD_SZ * DESC_AEAD_SHARED_TEXT_LEN +
+ keys_fit_inline ?
+ ctx->split_key_pad_len + ctx->enckeylen :
+ CAAM_PTR_SZ * 2, GFP_DMA | GFP_KERNEL);
+ if (!sh_desc) {
+ dev_err(jrdev, "could not allocate shared descriptor\n");
+ return -ENOMEM;
+ }
+
+ init_sh_desc(sh_desc, HDR_SAVECTX | HDR_SHARE_SERIAL);
+
+ jump_cmd = append_jump(sh_desc, CLASS_BOTH | JUMP_TEST_ALL |
+ JUMP_COND_SHRD | JUMP_COND_SELF);
+
+ /*
+ * process keys, starting with class 2/authentication.
+ */
+ if (keys_fit_inline) {
+ append_key_as_imm(sh_desc, ctx->key, ctx->split_key_pad_len,
+ ctx->split_key_len,
+ CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC);
+
+ append_key_as_imm(sh_desc, (void *)ctx->key +
+ ctx->split_key_pad_len, ctx->enckeylen,
+ ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG);
+ } else {
+ append_key(sh_desc, ctx->key_phys, ctx->split_key_len, CLASS_2 |
+ KEY_DEST_MDHA_SPLIT | KEY_ENC);
+ append_key(sh_desc, ctx->key_phys + ctx->split_key_pad_len,
+ ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG);
+ }
+
+ /* update jump cmd now that we are at the jump target */
+ set_jump_tgt_here(sh_desc, jump_cmd);
+
+ ctx->shared_desc_phys = dma_map_single(jrdev, sh_desc,
+ desc_bytes(sh_desc),
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(jrdev, ctx->shared_desc_phys)) {
+ dev_err(jrdev, "unable to map shared descriptor\n");
+ kfree(sh_desc);
+ return -ENOMEM;
+ }
+
+ ctx->sh_desc = sh_desc;
+
+ return 0;
+}
+
+static int aead_authenc_setkey(struct crypto_aead *aead,
+ const u8 *key, unsigned int keylen)
+{
+ /* Sizes for MDHA pads (*not* keys): MD5, SHA1, 224, 256, 384, 512 */
+ static const u8 mdpadlen[] = { 16, 20, 32, 32, 64, 64 };
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *jrdev = ctx->jrdev;
+ struct rtattr *rta = (void *)key;
+ struct crypto_authenc_key_param *param;
+ unsigned int authkeylen;
+ unsigned int enckeylen;
+ int ret = 0;
+
+ param = RTA_DATA(rta);
+ enckeylen = be32_to_cpu(param->enckeylen);
+
+ key += RTA_ALIGN(rta->rta_len);
+ keylen -= RTA_ALIGN(rta->rta_len);
+
+ if (keylen < enckeylen)
+ goto badkey;
+
+ authkeylen = keylen - enckeylen;
+
+ if (keylen > CAAM_MAX_KEY_SIZE)
+ goto badkey;
+
+ /* Pick class 2 key length from algorithm submask */
+ ctx->split_key_len = mdpadlen[(ctx->alg_op & OP_ALG_ALGSEL_SUBMASK) >>
+ OP_ALG_ALGSEL_SHIFT] * 2;
+ ctx->split_key_pad_len = ALIGN(ctx->split_key_len, 16);
+
+#ifdef DEBUG
+ printk(KERN_ERR "keylen %d enckeylen %d authkeylen %d\n",
+ keylen, enckeylen, authkeylen);
+ printk(KERN_ERR "split_key_len %d split_key_pad_len %d\n",
+ ctx->split_key_len, ctx->split_key_pad_len);
+ print_hex_dump(KERN_ERR, "key in @"xstr(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1);
+#endif
+ ctx->key = kmalloc(ctx->split_key_pad_len + enckeylen,
+ GFP_KERNEL | GFP_DMA);
+ if (!ctx->key) {
+ dev_err(jrdev, "could not allocate key output memory\n");
+ return -ENOMEM;
+ }
+
+ ret = gen_split_key(ctx, key, authkeylen);
+ if (ret) {
+ kfree(ctx->key);
+ goto badkey;
+ }
+
+ /* postpend encryption key to auth split key */
+ memcpy(ctx->key + ctx->split_key_pad_len, key + authkeylen, enckeylen);
+
+ ctx->key_phys = dma_map_single(jrdev, ctx->key, ctx->split_key_pad_len +
+ enckeylen, DMA_TO_DEVICE);
+ if (dma_mapping_error(jrdev, ctx->key_phys)) {
+ dev_err(jrdev, "unable to map key i/o memory\n");
+ kfree(ctx->key);
+ return -ENOMEM;
+ }
+#ifdef DEBUG
+ print_hex_dump(KERN_ERR, "ctx.key@"xstr(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, ctx->key,
+ ctx->split_key_pad_len + enckeylen, 1);
+#endif
+
+ ctx->enckeylen = enckeylen;
+
+ ret = build_sh_desc_ipsec(ctx);
+ if (ret) {
+ dma_unmap_single(jrdev, ctx->key_phys, ctx->split_key_pad_len +
+ enckeylen, DMA_TO_DEVICE);
+ kfree(ctx->key);
+ }
+
+ return ret;
+badkey:
+ crypto_aead_set_flags(aead, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+}
+
+struct link_tbl_entry {
+ u64 ptr;
+ u32 len;
+ u8 reserved;
+ u8 buf_pool_id;
+ u16 offset;
+};
+
+/*
+ * ipsec_esp_edesc - s/w-extended ipsec_esp descriptor
+ * @src_nents: number of segments in input scatterlist
+ * @dst_nents: number of segments in output scatterlist
+ * @assoc_nents: number of segments in associated data (SPI+Seq) scatterlist
+ * @desc: h/w descriptor (variable length; must not exceed MAX_CAAM_DESCSIZE)
+ * @link_tbl_bytes: length of dma mapped link_tbl space
+ * @link_tbl_dma: bus physical mapped address of h/w link table
+ * @hw_desc: the h/w job descriptor followed by any referenced link tables
+ */
+struct ipsec_esp_edesc {
+ int assoc_nents;
+ int src_nents;
+ int dst_nents;
+ int link_tbl_bytes;
+ dma_addr_t link_tbl_dma;
+ struct link_tbl_entry *link_tbl;
+ u32 hw_desc[0];
+};
+
+static void ipsec_esp_unmap(struct device *dev,
+ struct ipsec_esp_edesc *edesc,
+ struct aead_request *areq)
+{
+ dma_unmap_sg(dev, areq->assoc, edesc->assoc_nents, DMA_TO_DEVICE);
+
+ if (unlikely(areq->dst != areq->src)) {
+ dma_unmap_sg(dev, areq->src, edesc->src_nents,
+ DMA_TO_DEVICE);
+ dma_unmap_sg(dev, areq->dst, edesc->dst_nents,
+ DMA_FROM_DEVICE);
+ } else {
+ dma_unmap_sg(dev, areq->src, edesc->src_nents,
+ DMA_BIDIRECTIONAL);
+ }
+
+ if (edesc->link_tbl_bytes)
+ dma_unmap_single(dev, edesc->link_tbl_dma,
+ edesc->link_tbl_bytes,
+ DMA_TO_DEVICE);
+}
+
+/*
+ * ipsec_esp descriptor callbacks
+ */
+static void ipsec_esp_encrypt_done(struct device *jrdev, u32 *desc, u32 err,
+ void *context)
+{
+ struct aead_request *areq = context;
+ struct ipsec_esp_edesc *edesc;
+#ifdef DEBUG
+ struct crypto_aead *aead = crypto_aead_reqtfm(areq);
+ int ivsize = crypto_aead_ivsize(aead);
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+
+ dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
+#endif
+ edesc = (struct ipsec_esp_edesc *)((char *)desc -
+ offsetof(struct ipsec_esp_edesc, hw_desc));
+
+ if (err) {
+ char tmp[CAAM_ERROR_STR_MAX];
+
+ dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err));
+ }
+
+ ipsec_esp_unmap(jrdev, edesc, areq);
+
+#ifdef DEBUG
+ print_hex_dump(KERN_ERR, "assoc @"xstr(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(areq->assoc),
+ areq->assoclen , 1);
+ print_hex_dump(KERN_ERR, "dstiv @"xstr(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(areq->src) - ivsize,
+ edesc->src_nents ? 100 : ivsize, 1);
+ print_hex_dump(KERN_ERR, "dst @"xstr(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(areq->src),
+ edesc->src_nents ? 100 : areq->cryptlen +
+ ctx->authsize + 4, 1);
+#endif
+
+ kfree(edesc);
+
+ aead_request_complete(areq, err);
+}
+
+static void ipsec_esp_decrypt_done(struct device *jrdev, u32 *desc, u32 err,
+ void *context)
+{
+ struct aead_request *areq = context;
+ struct ipsec_esp_edesc *edesc;
+#ifdef DEBUG
+ struct crypto_aead *aead = crypto_aead_reqtfm(areq);
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+
+ dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
+#endif
+ edesc = (struct ipsec_esp_edesc *)((char *)desc -
+ offsetof(struct ipsec_esp_edesc, hw_desc));
+
+ if (err) {
+ char tmp[CAAM_ERROR_STR_MAX];
+
+ dev_err(jrdev, "%08x: %s\n", err, caam_jr_strstatus(tmp, err));
+ }
+
+ ipsec_esp_unmap(jrdev, edesc, areq);
+
+ /*
+ * verify hw auth check passed else return -EBADMSG
+ */
+ if ((err & JRSTA_CCBERR_ERRID_MASK) == JRSTA_CCBERR_ERRID_ICVCHK)
+ err = -EBADMSG;
+
+#ifdef DEBUG
+ print_hex_dump(KERN_ERR, "iphdrout@"xstr(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4,
+ ((char *)sg_virt(areq->assoc) - sizeof(struct iphdr)),
+ sizeof(struct iphdr) + areq->assoclen +
+ ((areq->cryptlen > 1500) ? 1500 : areq->cryptlen) +
+ ctx->authsize + 36, 1);
+ if (!err && edesc->link_tbl_bytes) {
+ struct scatterlist *sg = sg_last(areq->src, edesc->src_nents);
+ print_hex_dump(KERN_ERR, "sglastout@"xstr(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(sg),
+ sg->length + ctx->authsize + 16, 1);
+ }
+#endif
+ kfree(edesc);
+
+ aead_request_complete(areq, err);
+}
+
+/*
+ * convert scatterlist to h/w link table format
+ * scatterlist must have been previously dma mapped
+ */
+static void sg_to_link_tbl(struct scatterlist *sg, int sg_count,
+ struct link_tbl_entry *link_tbl_ptr, u32 offset)
+{
+ while (sg_count) {
+ link_tbl_ptr->ptr = sg_dma_address(sg);
+ link_tbl_ptr->len = sg_dma_len(sg);
+ link_tbl_ptr->reserved = 0;
+ link_tbl_ptr->buf_pool_id = 0;
+ link_tbl_ptr->offset = offset;
+ link_tbl_ptr++;
+ sg = sg_next(sg);
+ sg_count--;
+ }
+
+ /* set Final bit (marks end of link table) */
+ link_tbl_ptr--;
+ link_tbl_ptr->len |= 0x40000000;
+}
+
+/*
+ * fill in and submit ipsec_esp job descriptor
+ */
+static int ipsec_esp(struct ipsec_esp_edesc *edesc, struct aead_request *areq,
+ u32 encrypt,
+ void (*callback) (struct device *dev, u32 *desc,
+ u32 err, void *context))
+{
+ struct crypto_aead *aead = crypto_aead_reqtfm(areq);
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *jrdev = ctx->jrdev;
+ u32 *desc = edesc->hw_desc, options;
+ int ret, sg_count, assoc_sg_count;
+ int ivsize = crypto_aead_ivsize(aead);
+ int authsize = ctx->authsize;
+ dma_addr_t ptr, dst_dma, src_dma;
+#ifdef DEBUG
+ u32 *sh_desc = ctx->sh_desc;
+
+ debug("assoclen %d cryptlen %d authsize %d\n",
+ areq->assoclen, areq->cryptlen, authsize);
+ print_hex_dump(KERN_ERR, "assoc @"xstr(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(areq->assoc),
+ areq->assoclen , 1);
+ print_hex_dump(KERN_ERR, "presciv@"xstr(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(areq->src) - ivsize,
+ edesc->src_nents ? 100 : ivsize, 1);
+ print_hex_dump(KERN_ERR, "src @"xstr(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, sg_virt(areq->src),
+ edesc->src_nents ? 100 : areq->cryptlen + authsize, 1);
+ print_hex_dump(KERN_ERR, "shrdesc@"xstr(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, sh_desc,
+ desc_bytes(sh_desc), 1);
+#endif
+ assoc_sg_count = dma_map_sg(jrdev, areq->assoc, edesc->assoc_nents ?: 1,
+ DMA_TO_DEVICE);
+ if (areq->src == areq->dst)
+ sg_count = dma_map_sg(jrdev, areq->src, edesc->src_nents ? : 1,
+ DMA_BIDIRECTIONAL);
+ else
+ sg_count = dma_map_sg(jrdev, areq->src, edesc->src_nents ? : 1,
+ DMA_TO_DEVICE);
+
+ /* start auth operation */
+ append_operation(desc, ctx->class2_alg_type | OP_ALG_AS_INITFINAL |
+ (encrypt ? : OP_ALG_ICV_ON));
+
+ /* Load FIFO with data for Class 2 CHA */
+ options = FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG;
+ if (!edesc->assoc_nents) {
+ ptr = sg_dma_address(areq->assoc);
+ } else {
+ sg_to_link_tbl(areq->assoc, edesc->assoc_nents,
+ edesc->link_tbl, 0);
+ ptr = edesc->link_tbl_dma;
+ options |= LDST_SGF;
+ }
+ append_fifo_load(desc, ptr, areq->assoclen, options);
+
+ /* copy iv from cipher/class1 input context to class2 infifo */
+ append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_CLASS2INFIFO | ivsize);
+
+ if (!encrypt) {
+ u32 *jump_cmd, *uncond_jump_cmd;
+
+ /* JUMP if shared */
+ jump_cmd = append_jump(desc, JUMP_TEST_ALL | JUMP_COND_SHRD);
+
+ /* start class 1 (cipher) operation, non-shared version */
+ append_operation(desc, ctx->class1_alg_type |
+ OP_ALG_AS_INITFINAL);
+
+ uncond_jump_cmd = append_jump(desc, 0);
+
+ set_jump_tgt_here(desc, jump_cmd);
+
+ /* start class 1 (cipher) operation, shared version */
+ append_operation(desc, ctx->class1_alg_type |
+ OP_ALG_AS_INITFINAL | OP_ALG_AAI_DK);
+ set_jump_tgt_here(desc, uncond_jump_cmd);
+ } else
+ append_operation(desc, ctx->class1_alg_type |
+ OP_ALG_AS_INITFINAL | encrypt);
+
+ /* load payload & instruct to class2 to snoop class 1 if encrypting */
+ options = 0;
+ if (!edesc->src_nents) {
+ src_dma = sg_dma_address(areq->src);
+ } else {
+ sg_to_link_tbl(areq->src, edesc->src_nents, edesc->link_tbl +
+ edesc->assoc_nents, 0);
+ src_dma = edesc->link_tbl_dma + edesc->assoc_nents *
+ sizeof(struct link_tbl_entry);
+ options |= LDST_SGF;
+ }
+ append_seq_in_ptr(desc, src_dma, areq->cryptlen + authsize, options);
+ append_seq_fifo_load(desc, areq->cryptlen, FIFOLD_CLASS_BOTH |
+ FIFOLD_TYPE_LASTBOTH |
+ (encrypt ? FIFOLD_TYPE_MSG1OUT2
+ : FIFOLD_TYPE_MSG));
+
+ /* specify destination */
+ if (areq->src == areq->dst) {
+ dst_dma = src_dma;
+ } else {
+ sg_count = dma_map_sg(jrdev, areq->dst, edesc->dst_nents ? : 1,
+ DMA_FROM_DEVICE);
+ if (!edesc->dst_nents) {
+ dst_dma = sg_dma_address(areq->dst);
+ options = 0;
+ } else {
+ sg_to_link_tbl(areq->dst, edesc->dst_nents,
+ edesc->link_tbl + edesc->assoc_nents +
+ edesc->src_nents, 0);
+ dst_dma = edesc->link_tbl_dma + (edesc->assoc_nents +
+ edesc->src_nents) *
+ sizeof(struct link_tbl_entry);
+ options = LDST_SGF;
+ }
+ }
+ append_seq_out_ptr(desc, dst_dma, areq->cryptlen + authsize, options);
+ append_seq_fifo_store(desc, areq->cryptlen, FIFOST_TYPE_MESSAGE_DATA);
+
+ /* ICV */
+ if (encrypt)
+ append_seq_store(desc, authsize, LDST_CLASS_2_CCB |
+ LDST_SRCDST_BYTE_CONTEXT);
+ else
+ append_seq_fifo_load(desc, authsize, FIFOLD_CLASS_CLASS2 |
+ FIFOLD_TYPE_LAST2 | FIFOLD_TYPE_ICV);
+
+#ifdef DEBUG
+ debug("job_desc_len %d\n", desc_len(desc));
+ print_hex_dump(KERN_ERR, "jobdesc@"xstr(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc) , 1);
+ print_hex_dump(KERN_ERR, "jdlinkt@"xstr(__LINE__)": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, edesc->link_tbl,
+ edesc->link_tbl_bytes, 1);
+#endif
+
+ ret = caam_jr_enqueue(jrdev, desc, callback, areq);
+ if (!ret)
+ ret = -EINPROGRESS;
+ else {
+ ipsec_esp_unmap(jrdev, edesc, areq);
+ kfree(edesc);
+ }
+
+ return ret;
+}
+
+/*
+ * derive number of elements in scatterlist
+ */
+static int sg_count(struct scatterlist *sg_list, int nbytes, int *chained)
+{
+ struct scatterlist *sg = sg_list;
+ int sg_nents = 0;
+
+ *chained = 0;
+ while (nbytes > 0) {
+ sg_nents++;
+ nbytes -= sg->length;
+ if (!sg_is_last(sg) && (sg + 1)->length == 0)
+ *chained = 1;
+ sg = scatterwalk_sg_next(sg);
+ }
+
+ return sg_nents;
+}
+
+/*
+ * allocate and map the ipsec_esp extended descriptor
+ */
+static struct ipsec_esp_edesc *ipsec_esp_edesc_alloc(struct aead_request *areq,
+ int desc_bytes)
+{
+ struct crypto_aead *aead = crypto_aead_reqtfm(areq);
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *jrdev = ctx->jrdev;
+ gfp_t flags = areq->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL :
+ GFP_ATOMIC;
+ int assoc_nents, src_nents, dst_nents = 0, chained, link_tbl_bytes;
+ struct ipsec_esp_edesc *edesc;
+
+ assoc_nents = sg_count(areq->assoc, areq->assoclen, &chained);
+ BUG_ON(chained);
+ if (likely(assoc_nents == 1))
+ assoc_nents = 0;
+
+ src_nents = sg_count(areq->src, areq->cryptlen + ctx->authsize,
+ &chained);
+ BUG_ON(chained);
+ if (src_nents == 1)
+ src_nents = 0;
+
+ if (unlikely(areq->dst != areq->src)) {
+ dst_nents = sg_count(areq->dst, areq->cryptlen + ctx->authsize,
+ &chained);
+ BUG_ON(chained);
+ if (dst_nents == 1)
+ dst_nents = 0;
+ }
+
+ link_tbl_bytes = (assoc_nents + src_nents + dst_nents) *
+ sizeof(struct link_tbl_entry);
+ debug("link_tbl_bytes %d\n", link_tbl_bytes);
+
+ /* allocate space for base edesc and hw desc commands, link tables */
+ edesc = kmalloc(sizeof(struct ipsec_esp_edesc) + desc_bytes +
+ link_tbl_bytes, GFP_DMA | flags);
+ if (!edesc) {
+ dev_err(jrdev, "could not allocate extended descriptor\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ edesc->assoc_nents = assoc_nents;
+ edesc->src_nents = src_nents;
+ edesc->dst_nents = dst_nents;
+ edesc->link_tbl = (void *)edesc + sizeof(struct ipsec_esp_edesc) +
+ desc_bytes;
+ edesc->link_tbl_dma = dma_map_single(jrdev, edesc->link_tbl,
+ link_tbl_bytes, DMA_TO_DEVICE);
+ edesc->link_tbl_bytes = link_tbl_bytes;
+
+ return edesc;
+}
+
+static int aead_authenc_encrypt(struct aead_request *areq)
+{
+ struct ipsec_esp_edesc *edesc;
+ struct crypto_aead *aead = crypto_aead_reqtfm(areq);
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *jrdev = ctx->jrdev;
+ int ivsize = crypto_aead_ivsize(aead);
+ u32 *desc;
+ dma_addr_t iv_dma;
+
+ /* allocate extended descriptor */
+ edesc = ipsec_esp_edesc_alloc(areq, DESC_AEAD_ENCRYPT_TEXT_LEN *
+ CAAM_CMD_SZ);
+ if (IS_ERR(edesc))
+ return PTR_ERR(edesc);
+
+ desc = edesc->hw_desc;
+
+ /* insert shared descriptor pointer */
+ init_job_desc_shared(desc, ctx->shared_desc_phys,
+ desc_len(ctx->sh_desc), HDR_SHARE_DEFER);
+
+ iv_dma = dma_map_single(jrdev, areq->iv, ivsize, DMA_TO_DEVICE);
+ /* check dma error */
+
+ append_load(desc, iv_dma, ivsize,
+ LDST_CLASS_1_CCB | LDST_SRCDST_BYTE_CONTEXT);
+
+ return ipsec_esp(edesc, areq, OP_ALG_ENCRYPT, ipsec_esp_encrypt_done);
+}
+
+static int aead_authenc_decrypt(struct aead_request *req)
+{
+ struct crypto_aead *aead = crypto_aead_reqtfm(req);
+ int ivsize = crypto_aead_ivsize(aead);
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *jrdev = ctx->jrdev;
+ struct ipsec_esp_edesc *edesc;
+ u32 *desc;
+ dma_addr_t iv_dma;
+
+ req->cryptlen -= ctx->authsize;
+
+ /* allocate extended descriptor */
+ edesc = ipsec_esp_edesc_alloc(req, DESC_AEAD_DECRYPT_TEXT_LEN *
+ CAAM_CMD_SZ);
+ if (IS_ERR(edesc))
+ return PTR_ERR(edesc);
+
+ desc = edesc->hw_desc;
+
+ /* insert shared descriptor pointer */
+ init_job_desc_shared(desc, ctx->shared_desc_phys,
+ desc_len(ctx->sh_desc), HDR_SHARE_DEFER);
+
+ iv_dma = dma_map_single(jrdev, req->iv, ivsize, DMA_TO_DEVICE);
+ /* check dma error */
+
+ append_load(desc, iv_dma, ivsize,
+ LDST_CLASS_1_CCB | LDST_SRCDST_BYTE_CONTEXT);
+
+ return ipsec_esp(edesc, req, !OP_ALG_ENCRYPT, ipsec_esp_decrypt_done);
+}
+
+static int aead_authenc_givencrypt(struct aead_givcrypt_request *req)
+{
+ struct aead_request *areq = &req->areq;
+ struct ipsec_esp_edesc *edesc;
+ struct crypto_aead *aead = crypto_aead_reqtfm(areq);
+ struct caam_ctx *ctx = crypto_aead_ctx(aead);
+ struct device *jrdev = ctx->jrdev;
+ int ivsize = crypto_aead_ivsize(aead);
+ dma_addr_t iv_dma;
+ u32 *desc;
+
+ iv_dma = dma_map_single(jrdev, req->giv, ivsize, DMA_FROM_DEVICE);
+
+ debug("%s: giv %p\n", __func__, req->giv);
+
+ /* allocate extended descriptor */
+ edesc = ipsec_esp_edesc_alloc(areq, DESC_AEAD_GIVENCRYPT_TEXT_LEN *
+ CAAM_CMD_SZ);
+ if (IS_ERR(edesc))
+ return PTR_ERR(edesc);
+
+ desc = edesc->hw_desc;
+
+ /* insert shared descriptor pointer */
+ init_job_desc_shared(desc, ctx->shared_desc_phys,
+ desc_len(ctx->sh_desc), HDR_SHARE_DEFER);
+
+ /*
+ * LOAD IMM Info FIFO
+ * to DECO, Last, Padding, Random, Message, 16 bytes
+ */
+ append_load_imm_u32(desc, NFIFOENTRY_DEST_DECO | NFIFOENTRY_LC1 |
+ NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DTYPE_MSG |
+ NFIFOENTRY_PTYPE_RND | ivsize,
+ LDST_SRCDST_WORD_INFO_FIFO);
+
+ /*
+ * disable info fifo entries since the above serves as the entry
+ * this way, the MOVE command won't generate an entry.
+ * Note that this isn't required in more recent versions of
+ * SEC as a MOVE that doesn't do info FIFO entries is available.
+ */
+ append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO);
+
+ /* MOVE DECO Alignment -> C1 Context 16 bytes */
+ append_move(desc, MOVE_SRC_INFIFO | MOVE_DEST_CLASS1CTX | ivsize);
+
+ /* re-enable info fifo entries */
+ append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO);
+
+ /* MOVE C1 Context -> OFIFO 16 bytes */
+ append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_OUTFIFO | ivsize);
+
+ append_fifo_store(desc, iv_dma, ivsize, FIFOST_TYPE_MESSAGE_DATA);
+
+ return ipsec_esp(edesc, areq, OP_ALG_ENCRYPT, ipsec_esp_encrypt_done);
+}
+
+struct caam_alg_template {
+ char name[CRYPTO_MAX_ALG_NAME];
+ char driver_name[CRYPTO_MAX_ALG_NAME];
+ unsigned int blocksize;
+ struct aead_alg aead;
+ u32 class1_alg_type;
+ u32 class2_alg_type;
+ u32 alg_op;
+};
+
+static struct caam_alg_template driver_algs[] = {
+ /* single-pass ipsec_esp descriptor */
+ {
+ .name = "authenc(hmac(sha1),cbc(aes))",
+ .driver_name = "authenc-hmac-sha1-cbc-aes-caam",
+ .blocksize = AES_BLOCK_SIZE,
+ .aead = {
+ .setkey = aead_authenc_setkey,
+ .setauthsize = aead_authenc_setauthsize,
+ .encrypt = aead_authenc_encrypt,
+ .decrypt = aead_authenc_decrypt,
+ .givencrypt = aead_authenc_givencrypt,
+ .geniv = "<built-in>",
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = SHA1_DIGEST_SIZE,
+ },
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP,
+ .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC,
+ },
+ {
+ .name = "authenc(hmac(sha256),cbc(aes))",
+ .driver_name = "authenc-hmac-sha256-cbc-aes-caam",
+ .blocksize = AES_BLOCK_SIZE,
+ .aead = {
+ .setkey = aead_authenc_setkey,
+ .setauthsize = aead_authenc_setauthsize,
+ .encrypt = aead_authenc_encrypt,
+ .decrypt = aead_authenc_decrypt,
+ .givencrypt = aead_authenc_givencrypt,
+ .geniv = "<built-in>",
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = SHA256_DIGEST_SIZE,
+ },
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA256 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC,
+ },
+ {
+ .name = "authenc(hmac(sha512),cbc(aes))",
+ .driver_name = "authenc-hmac-sha512-cbc-aes-caam",
+ .blocksize = AES_BLOCK_SIZE,
+ .aead = {
+ .setkey = aead_authenc_setkey,
+ .setauthsize = aead_authenc_setauthsize,
+ .encrypt = aead_authenc_encrypt,
+ .decrypt = aead_authenc_decrypt,
+ .givencrypt = aead_authenc_givencrypt,
+ .geniv = "<built-in>",
+ .ivsize = AES_BLOCK_SIZE,
+ .maxauthsize = SHA512_DIGEST_SIZE,
+ },
+ .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA512 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC,
+ },
+ {
+ .name = "authenc(hmac(sha1),cbc(des3_ede))",
+ .driver_name = "authenc-hmac-sha1-cbc-des3_ede-caam",
+ .blocksize = DES3_EDE_BLOCK_SIZE,
+ .aead = {
+ .setkey = aead_authenc_setkey,
+ .setauthsize = aead_authenc_setauthsize,
+ .encrypt = aead_authenc_encrypt,
+ .decrypt = aead_authenc_decrypt,
+ .givencrypt = aead_authenc_givencrypt,
+ .geniv = "<built-in>",
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .maxauthsize = SHA1_DIGEST_SIZE,
+ },
+ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP,
+ .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC,
+ },
+ {
+ .name = "authenc(hmac(sha256),cbc(des3_ede))",
+ .driver_name = "authenc-hmac-sha256-cbc-des3_ede-caam",
+ .blocksize = DES3_EDE_BLOCK_SIZE,
+ .aead = {
+ .setkey = aead_authenc_setkey,
+ .setauthsize = aead_authenc_setauthsize,
+ .encrypt = aead_authenc_encrypt,
+ .decrypt = aead_authenc_decrypt,
+ .givencrypt = aead_authenc_givencrypt,
+ .geniv = "<built-in>",
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .maxauthsize = SHA256_DIGEST_SIZE,
+ },
+ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA256 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC,
+ },
+ {
+ .name = "authenc(hmac(sha512),cbc(des3_ede))",
+ .driver_name = "authenc-hmac-sha512-cbc-des3_ede-caam",
+ .blocksize = DES3_EDE_BLOCK_SIZE,
+ .aead = {
+ .setkey = aead_authenc_setkey,
+ .setauthsize = aead_authenc_setauthsize,
+ .encrypt = aead_authenc_encrypt,
+ .decrypt = aead_authenc_decrypt,
+ .givencrypt = aead_authenc_givencrypt,
+ .geniv = "<built-in>",
+ .ivsize = DES3_EDE_BLOCK_SIZE,
+ .maxauthsize = SHA512_DIGEST_SIZE,
+ },
+ .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA512 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC,
+ },
+ {
+ .name = "authenc(hmac(sha1),cbc(des))",
+ .driver_name = "authenc-hmac-sha1-cbc-des-caam",
+ .blocksize = DES_BLOCK_SIZE,
+ .aead = {
+ .setkey = aead_authenc_setkey,
+ .setauthsize = aead_authenc_setauthsize,
+ .encrypt = aead_authenc_encrypt,
+ .decrypt = aead_authenc_decrypt,
+ .givencrypt = aead_authenc_givencrypt,
+ .geniv = "<built-in>",
+ .ivsize = DES_BLOCK_SIZE,
+ .maxauthsize = SHA1_DIGEST_SIZE,
+ },
+ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP,
+ .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC,
+ },
+ {
+ .name = "authenc(hmac(sha256),cbc(des))",
+ .driver_name = "authenc-hmac-sha256-cbc-des-caam",
+ .blocksize = DES_BLOCK_SIZE,
+ .aead = {
+ .setkey = aead_authenc_setkey,
+ .setauthsize = aead_authenc_setauthsize,
+ .encrypt = aead_authenc_encrypt,
+ .decrypt = aead_authenc_decrypt,
+ .givencrypt = aead_authenc_givencrypt,
+ .geniv = "<built-in>",
+ .ivsize = DES_BLOCK_SIZE,
+ .maxauthsize = SHA256_DIGEST_SIZE,
+ },
+ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA256 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC,
+ },
+ {
+ .name = "authenc(hmac(sha512),cbc(des))",
+ .driver_name = "authenc-hmac-sha512-cbc-des-caam",
+ .blocksize = DES_BLOCK_SIZE,
+ .aead = {
+ .setkey = aead_authenc_setkey,
+ .setauthsize = aead_authenc_setauthsize,
+ .encrypt = aead_authenc_encrypt,
+ .decrypt = aead_authenc_decrypt,
+ .givencrypt = aead_authenc_givencrypt,
+ .geniv = "<built-in>",
+ .ivsize = DES_BLOCK_SIZE,
+ .maxauthsize = SHA512_DIGEST_SIZE,
+ },
+ .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC,
+ .class2_alg_type = OP_ALG_ALGSEL_SHA512 |
+ OP_ALG_AAI_HMAC_PRECOMP,
+ .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC,
+ },
+};
+
+struct caam_crypto_alg {
+ struct list_head entry;
+ struct device *ctrldev;
+ int class1_alg_type;
+ int class2_alg_type;
+ int alg_op;
+ struct crypto_alg crypto_alg;
+};
+
+static int caam_cra_init(struct crypto_tfm *tfm)
+{
+ struct crypto_alg *alg = tfm->__crt_alg;
+ struct caam_crypto_alg *caam_alg =
+ container_of(alg, struct caam_crypto_alg, crypto_alg);
+ struct caam_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct caam_drv_private *priv = dev_get_drvdata(caam_alg->ctrldev);
+ int tgt_jr = atomic_inc_return(&priv->tfm_count);
+
+ /*
+ * distribute tfms across job rings to ensure in-order
+ * crypto request processing per tfm
+ */
+ ctx->jrdev = priv->algapi_jr[(tgt_jr / 2) % priv->num_jrs_for_algapi];
+
+ /* copy descriptor header template value */
+ ctx->class1_alg_type = OP_TYPE_CLASS1_ALG | caam_alg->class1_alg_type;
+ ctx->class2_alg_type = OP_TYPE_CLASS2_ALG | caam_alg->class2_alg_type;
+ ctx->alg_op = OP_TYPE_CLASS2_ALG | caam_alg->alg_op;
+
+ return 0;
+}
+
+static void caam_cra_exit(struct crypto_tfm *tfm)
+{
+ struct caam_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ if (!dma_mapping_error(ctx->jrdev, ctx->shared_desc_phys))
+ dma_unmap_single(ctx->jrdev, ctx->shared_desc_phys,
+ desc_bytes(ctx->sh_desc), DMA_TO_DEVICE);
+ kfree(ctx->sh_desc);
+
+ if (!dma_mapping_error(ctx->jrdev, ctx->key_phys))
+ dma_unmap_single(ctx->jrdev, ctx->key_phys,
+ ctx->split_key_pad_len + ctx->enckeylen,
+ DMA_TO_DEVICE);
+ kfree(ctx->key);
+}
+
+static void __exit caam_algapi_exit(void)
+{
+
+ struct device_node *dev_node;
+ struct platform_device *pdev;
+ struct device *ctrldev;
+ struct caam_drv_private *priv;
+ struct caam_crypto_alg *t_alg, *n;
+ int i, err;
+
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
+ if (!dev_node)
+ return;
+
+ pdev = of_find_device_by_node(dev_node);
+ if (!pdev)
+ return;
+
+ ctrldev = &pdev->dev;
+ of_node_put(dev_node);
+ priv = dev_get_drvdata(ctrldev);
+
+ if (!priv->alg_list.next)
+ return;
+
+ list_for_each_entry_safe(t_alg, n, &priv->alg_list, entry) {
+ crypto_unregister_alg(&t_alg->crypto_alg);
+ list_del(&t_alg->entry);
+ kfree(t_alg);
+ }
+
+ for (i = 0; i < priv->total_jobrs; i++) {
+ err = caam_jr_deregister(priv->algapi_jr[i]);
+ if (err < 0)
+ break;
+ }
+ kfree(priv->algapi_jr);
+}
+
+static struct caam_crypto_alg *caam_alg_alloc(struct device *ctrldev,
+ struct caam_alg_template
+ *template)
+{
+ struct caam_crypto_alg *t_alg;
+ struct crypto_alg *alg;
+
+ t_alg = kzalloc(sizeof(struct caam_crypto_alg), GFP_KERNEL);
+ if (!t_alg) {
+ dev_err(ctrldev, "failed to allocate t_alg\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ alg = &t_alg->crypto_alg;
+
+ snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", template->name);
+ snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s",
+ template->driver_name);
+ alg->cra_module = THIS_MODULE;
+ alg->cra_init = caam_cra_init;
+ alg->cra_exit = caam_cra_exit;
+ alg->cra_priority = CAAM_CRA_PRIORITY;
+ alg->cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC;
+ alg->cra_blocksize = template->blocksize;
+ alg->cra_alignmask = 0;
+ alg->cra_type = &crypto_aead_type;
+ alg->cra_ctxsize = sizeof(struct caam_ctx);
+ alg->cra_u.aead = template->aead;
+
+ t_alg->class1_alg_type = template->class1_alg_type;
+ t_alg->class2_alg_type = template->class2_alg_type;
+ t_alg->alg_op = template->alg_op;
+ t_alg->ctrldev = ctrldev;
+
+ return t_alg;
+}
+
+static int __init caam_algapi_init(void)
+{
+ struct device_node *dev_node;
+ struct platform_device *pdev;
+ struct device *ctrldev, **jrdev;
+ struct caam_drv_private *priv;
+ int i = 0, err = 0;
+
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
+ if (!dev_node)
+ return -ENODEV;
+
+ pdev = of_find_device_by_node(dev_node);
+ if (!pdev)
+ return -ENODEV;
+
+ ctrldev = &pdev->dev;
+ priv = dev_get_drvdata(ctrldev);
+ of_node_put(dev_node);
+
+ INIT_LIST_HEAD(&priv->alg_list);
+
+ jrdev = kmalloc(sizeof(*jrdev) * priv->total_jobrs, GFP_KERNEL);
+ if (!jrdev)
+ return -ENOMEM;
+
+ for (i = 0; i < priv->total_jobrs; i++) {
+ err = caam_jr_register(ctrldev, &jrdev[i]);
+ if (err < 0)
+ break;
+ }
+ if (err < 0 && i == 0) {
+ dev_err(ctrldev, "algapi error in job ring registration: %d\n",
+ err);
+ kfree(jrdev);
+ return err;
+ }
+
+ priv->num_jrs_for_algapi = i;
+ priv->algapi_jr = jrdev;
+ atomic_set(&priv->tfm_count, -1);
+
+ /* register crypto algorithms the device supports */
+ for (i = 0; i < ARRAY_SIZE(driver_algs); i++) {
+ /* TODO: check if h/w supports alg */
+ struct caam_crypto_alg *t_alg;
+
+ t_alg = caam_alg_alloc(ctrldev, &driver_algs[i]);
+ if (IS_ERR(t_alg)) {
+ err = PTR_ERR(t_alg);
+ dev_warn(ctrldev, "%s alg allocation failed\n",
+ driver_algs[i].driver_name);
+ continue;
+ }
+
+ err = crypto_register_alg(&t_alg->crypto_alg);
+ if (err) {
+ dev_warn(ctrldev, "%s alg registration failed\n",
+ t_alg->crypto_alg.cra_driver_name);
+ kfree(t_alg);
+ } else {
+ list_add_tail(&t_alg->entry, &priv->alg_list);
+ dev_info(ctrldev, "%s\n",
+ t_alg->crypto_alg.cra_driver_name);
+ }
+ }
+
+ return err;
+}
+
+module_init(caam_algapi_init);
+module_exit(caam_algapi_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("FSL CAAM support for crypto API");
+MODULE_AUTHOR("Freescale Semiconductor - NMG/STC");
diff --git a/drivers/crypto/caam/compat.h b/drivers/crypto/caam/compat.h
new file mode 100644
index 000000000000..950450346f70
--- /dev/null
+++ b/drivers/crypto/caam/compat.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ */
+
+#ifndef CAAM_COMPAT_H
+#define CAAM_COMPAT_H
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/crypto.h>
+#include <linux/hw_random.h>
+#include <linux/of_platform.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/rtnetlink.h>
+#include <linux/in.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/debugfs.h>
+#include <linux/circ_buf.h>
+#include <net/xfrm.h>
+
+#include <crypto/algapi.h>
+#include <crypto/aes.h>
+#include <crypto/des.h>
+#include <crypto/sha.h>
+#include <crypto/aead.h>
+#include <crypto/authenc.h>
+#include <crypto/scatterwalk.h>
+
+#endif /* !defined(CAAM_COMPAT_H) */
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
new file mode 100644
index 000000000000..9009713a3c2e
--- /dev/null
+++ b/drivers/crypto/caam/ctrl.c
@@ -0,0 +1,269 @@
+/*
+ * CAAM control-plane driver backend
+ * Controller-level driver, kernel property detection, initialization
+ *
+ * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ */
+
+#include "compat.h"
+#include "regs.h"
+#include "intern.h"
+#include "jr.h"
+
+static int caam_remove(struct platform_device *pdev)
+{
+ struct device *ctrldev;
+ struct caam_drv_private *ctrlpriv;
+ struct caam_drv_private_jr *jrpriv;
+ struct caam_full __iomem *topregs;
+ int ring, ret = 0;
+
+ ctrldev = &pdev->dev;
+ ctrlpriv = dev_get_drvdata(ctrldev);
+ topregs = (struct caam_full __iomem *)ctrlpriv->ctrl;
+
+ /* shut down JobRs */
+ for (ring = 0; ring < ctrlpriv->total_jobrs; ring++) {
+ ret |= caam_jr_shutdown(ctrlpriv->jrdev[ring]);
+ jrpriv = dev_get_drvdata(ctrlpriv->jrdev[ring]);
+ irq_dispose_mapping(jrpriv->irq);
+ }
+
+ /* Shut down debug views */
+#ifdef CONFIG_DEBUG_FS
+ debugfs_remove_recursive(ctrlpriv->dfs_root);
+#endif
+
+ /* Unmap controller region */
+ iounmap(&topregs->ctrl);
+
+ kfree(ctrlpriv->jrdev);
+ kfree(ctrlpriv);
+
+ return ret;
+}
+
+/* Probe routine for CAAM top (controller) level */
+static int caam_probe(struct platform_device *pdev)
+{
+ int d, ring, rspec;
+ struct device *dev;
+ struct device_node *nprop, *np;
+ struct caam_ctrl __iomem *ctrl;
+ struct caam_full __iomem *topregs;
+ struct caam_drv_private *ctrlpriv;
+ struct caam_perfmon *perfmon;
+ struct caam_deco **deco;
+ u32 deconum;
+
+ ctrlpriv = kzalloc(sizeof(struct caam_drv_private), GFP_KERNEL);
+ if (!ctrlpriv)
+ return -ENOMEM;
+
+ dev = &pdev->dev;
+ dev_set_drvdata(dev, ctrlpriv);
+ ctrlpriv->pdev = pdev;
+ nprop = pdev->dev.of_node;
+
+ /* Get configuration properties from device tree */
+ /* First, get register page */
+ ctrl = of_iomap(nprop, 0);
+ if (ctrl == NULL) {
+ dev_err(dev, "caam: of_iomap() failed\n");
+ return -ENOMEM;
+ }
+ ctrlpriv->ctrl = (struct caam_ctrl __force *)ctrl;
+
+ /* topregs used to derive pointers to CAAM sub-blocks only */
+ topregs = (struct caam_full __iomem *)ctrl;
+
+ /* Get the IRQ of the controller (for security violations only) */
+ ctrlpriv->secvio_irq = of_irq_to_resource(nprop, 0, NULL);
+
+ /*
+ * Enable DECO watchdogs and, if this is a PHYS_ADDR_T_64BIT kernel,
+ * 36-bit pointers in master configuration register
+ */
+ setbits32(&topregs->ctrl.mcr, MCFGR_WDENABLE |
+ (sizeof(dma_addr_t) == sizeof(u64) ? MCFGR_LONG_PTR : 0));
+
+ if (sizeof(dma_addr_t) == sizeof(u64))
+ dma_set_mask(dev, DMA_BIT_MASK(36));
+
+ /* Find out how many DECOs are present */
+ deconum = (rd_reg64(&topregs->ctrl.perfmon.cha_num) &
+ CHA_NUM_DECONUM_MASK) >> CHA_NUM_DECONUM_SHIFT;
+
+ ctrlpriv->deco = kmalloc(deconum * sizeof(struct caam_deco *),
+ GFP_KERNEL);
+
+ deco = (struct caam_deco __force **)&topregs->deco;
+ for (d = 0; d < deconum; d++)
+ ctrlpriv->deco[d] = deco[d];
+
+ /*
+ * Detect and enable JobRs
+ * First, find out how many ring spec'ed, allocate references
+ * for all, then go probe each one.
+ */
+ rspec = 0;
+ for_each_compatible_node(np, NULL, "fsl,sec-v4.0-job-ring")
+ rspec++;
+ ctrlpriv->jrdev = kzalloc(sizeof(struct device *) * rspec, GFP_KERNEL);
+ if (ctrlpriv->jrdev == NULL) {
+ iounmap(&topregs->ctrl);
+ return -ENOMEM;
+ }
+
+ ring = 0;
+ ctrlpriv->total_jobrs = 0;
+ for_each_compatible_node(np, NULL, "fsl,sec-v4.0-job-ring") {
+ caam_jr_probe(pdev, np, ring);
+ ctrlpriv->total_jobrs++;
+ ring++;
+ }
+
+ /* Check to see if QI present. If so, enable */
+ ctrlpriv->qi_present = !!(rd_reg64(&topregs->ctrl.perfmon.comp_parms) &
+ CTPR_QI_MASK);
+ if (ctrlpriv->qi_present) {
+ ctrlpriv->qi = (struct caam_queue_if __force *)&topregs->qi;
+ /* This is all that's required to physically enable QI */
+ wr_reg32(&topregs->qi.qi_control_lo, QICTL_DQEN);
+ }
+
+ /* If no QI and no rings specified, quit and go home */
+ if ((!ctrlpriv->qi_present) && (!ctrlpriv->total_jobrs)) {
+ dev_err(dev, "no queues configured, terminating\n");
+ caam_remove(pdev);
+ return -ENOMEM;
+ }
+
+ /* NOTE: RTIC detection ought to go here, around Si time */
+
+ /* Initialize queue allocator lock */
+ spin_lock_init(&ctrlpriv->jr_alloc_lock);
+
+ /* Report "alive" for developer to see */
+ dev_info(dev, "device ID = 0x%016llx\n",
+ rd_reg64(&topregs->ctrl.perfmon.caam_id));
+ dev_info(dev, "job rings = %d, qi = %d\n",
+ ctrlpriv->total_jobrs, ctrlpriv->qi_present);
+
+#ifdef CONFIG_DEBUG_FS
+ /*
+ * FIXME: needs better naming distinction, as some amalgamation of
+ * "caam" and nprop->full_name. The OF name isn't distinctive,
+ * but does separate instances
+ */
+ perfmon = (struct caam_perfmon __force *)&ctrl->perfmon;
+
+ ctrlpriv->dfs_root = debugfs_create_dir("caam", NULL);
+ ctrlpriv->ctl = debugfs_create_dir("ctl", ctrlpriv->dfs_root);
+
+ /* Controller-level - performance monitor counters */
+ ctrlpriv->ctl_rq_dequeued =
+ debugfs_create_u64("rq_dequeued",
+ S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH,
+ ctrlpriv->ctl, &perfmon->req_dequeued);
+ ctrlpriv->ctl_ob_enc_req =
+ debugfs_create_u64("ob_rq_encrypted",
+ S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH,
+ ctrlpriv->ctl, &perfmon->ob_enc_req);
+ ctrlpriv->ctl_ib_dec_req =
+ debugfs_create_u64("ib_rq_decrypted",
+ S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH,
+ ctrlpriv->ctl, &perfmon->ib_dec_req);
+ ctrlpriv->ctl_ob_enc_bytes =
+ debugfs_create_u64("ob_bytes_encrypted",
+ S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH,
+ ctrlpriv->ctl, &perfmon->ob_enc_bytes);
+ ctrlpriv->ctl_ob_prot_bytes =
+ debugfs_create_u64("ob_bytes_protected",
+ S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH,
+ ctrlpriv->ctl, &perfmon->ob_prot_bytes);
+ ctrlpriv->ctl_ib_dec_bytes =
+ debugfs_create_u64("ib_bytes_decrypted",
+ S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH,
+ ctrlpriv->ctl, &perfmon->ib_dec_bytes);
+ ctrlpriv->ctl_ib_valid_bytes =
+ debugfs_create_u64("ib_bytes_validated",
+ S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH,
+ ctrlpriv->ctl, &perfmon->ib_valid_bytes);
+
+ /* Controller level - global status values */
+ ctrlpriv->ctl_faultaddr =
+ debugfs_create_u64("fault_addr",
+ S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH,
+ ctrlpriv->ctl, &perfmon->faultaddr);
+ ctrlpriv->ctl_faultdetail =
+ debugfs_create_u32("fault_detail",
+ S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH,
+ ctrlpriv->ctl, &perfmon->faultdetail);
+ ctrlpriv->ctl_faultstatus =
+ debugfs_create_u32("fault_status",
+ S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH,
+ ctrlpriv->ctl, &perfmon->status);
+
+ /* Internal covering keys (useful in non-secure mode only) */
+ ctrlpriv->ctl_kek_wrap.data = &ctrlpriv->ctrl->kek[0];
+ ctrlpriv->ctl_kek_wrap.size = KEK_KEY_SIZE * sizeof(u32);
+ ctrlpriv->ctl_kek = debugfs_create_blob("kek",
+ S_IFCHR | S_IRUSR |
+ S_IRGRP | S_IROTH,
+ ctrlpriv->ctl,
+ &ctrlpriv->ctl_kek_wrap);
+
+ ctrlpriv->ctl_tkek_wrap.data = &ctrlpriv->ctrl->tkek[0];
+ ctrlpriv->ctl_tkek_wrap.size = KEK_KEY_SIZE * sizeof(u32);
+ ctrlpriv->ctl_tkek = debugfs_create_blob("tkek",
+ S_IFCHR | S_IRUSR |
+ S_IRGRP | S_IROTH,
+ ctrlpriv->ctl,
+ &ctrlpriv->ctl_tkek_wrap);
+
+ ctrlpriv->ctl_tdsk_wrap.data = &ctrlpriv->ctrl->tdsk[0];
+ ctrlpriv->ctl_tdsk_wrap.size = KEK_KEY_SIZE * sizeof(u32);
+ ctrlpriv->ctl_tdsk = debugfs_create_blob("tdsk",
+ S_IFCHR | S_IRUSR |
+ S_IRGRP | S_IROTH,
+ ctrlpriv->ctl,
+ &ctrlpriv->ctl_tdsk_wrap);
+#endif
+ return 0;
+}
+
+static struct of_device_id caam_match[] = {
+ {
+ .compatible = "fsl,sec-v4.0",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, caam_match);
+
+static struct platform_driver caam_driver = {
+ .driver = {
+ .name = "caam",
+ .owner = THIS_MODULE,
+ .of_match_table = caam_match,
+ },
+ .probe = caam_probe,
+ .remove = __devexit_p(caam_remove),
+};
+
+static int __init caam_base_init(void)
+{
+ return platform_driver_register(&caam_driver);
+}
+
+static void __exit caam_base_exit(void)
+{
+ return platform_driver_unregister(&caam_driver);
+}
+
+module_init(caam_base_init);
+module_exit(caam_base_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("FSL CAAM request backend");
+MODULE_AUTHOR("Freescale Semiconductor - NMG/STC");
diff --git a/drivers/crypto/caam/desc.h b/drivers/crypto/caam/desc.h
new file mode 100644
index 000000000000..974a75842da9
--- /dev/null
+++ b/drivers/crypto/caam/desc.h
@@ -0,0 +1,1605 @@
+/*
+ * CAAM descriptor composition header
+ * Definitions to support CAAM descriptor instruction generation
+ *
+ * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ */
+
+#ifndef DESC_H
+#define DESC_H
+
+/* Max size of any CAAM descriptor in 32-bit words, inclusive of header */
+#define MAX_CAAM_DESCSIZE 64
+
+/* Block size of any entity covered/uncovered with a KEK/TKEK */
+#define KEK_BLOCKSIZE 16
+
+/*
+ * Supported descriptor command types as they show up
+ * inside a descriptor command word.
+ */
+#define CMD_SHIFT 27
+#define CMD_MASK 0xf8000000
+
+#define CMD_KEY (0x00 << CMD_SHIFT)
+#define CMD_SEQ_KEY (0x01 << CMD_SHIFT)
+#define CMD_LOAD (0x02 << CMD_SHIFT)
+#define CMD_SEQ_LOAD (0x03 << CMD_SHIFT)
+#define CMD_FIFO_LOAD (0x04 << CMD_SHIFT)
+#define CMD_SEQ_FIFO_LOAD (0x05 << CMD_SHIFT)
+#define CMD_STORE (0x0a << CMD_SHIFT)
+#define CMD_SEQ_STORE (0x0b << CMD_SHIFT)
+#define CMD_FIFO_STORE (0x0c << CMD_SHIFT)
+#define CMD_SEQ_FIFO_STORE (0x0d << CMD_SHIFT)
+#define CMD_MOVE_LEN (0x0e << CMD_SHIFT)
+#define CMD_MOVE (0x0f << CMD_SHIFT)
+#define CMD_OPERATION (0x10 << CMD_SHIFT)
+#define CMD_SIGNATURE (0x12 << CMD_SHIFT)
+#define CMD_JUMP (0x14 << CMD_SHIFT)
+#define CMD_MATH (0x15 << CMD_SHIFT)
+#define CMD_DESC_HDR (0x16 << CMD_SHIFT)
+#define CMD_SHARED_DESC_HDR (0x17 << CMD_SHIFT)
+#define CMD_SEQ_IN_PTR (0x1e << CMD_SHIFT)
+#define CMD_SEQ_OUT_PTR (0x1f << CMD_SHIFT)
+
+/* General-purpose class selector for all commands */
+#define CLASS_SHIFT 25
+#define CLASS_MASK (0x03 << CLASS_SHIFT)
+
+#define CLASS_NONE (0x00 << CLASS_SHIFT)
+#define CLASS_1 (0x01 << CLASS_SHIFT)
+#define CLASS_2 (0x02 << CLASS_SHIFT)
+#define CLASS_BOTH (0x03 << CLASS_SHIFT)
+
+/*
+ * Descriptor header command constructs
+ * Covers shared, job, and trusted descriptor headers
+ */
+
+/*
+ * Do Not Run - marks a descriptor inexecutable if there was
+ * a preceding error somewhere
+ */
+#define HDR_DNR 0x01000000
+
+/*
+ * ONE - should always be set. Combination of ONE (always
+ * set) and ZRO (always clear) forms an endianness sanity check
+ */
+#define HDR_ONE 0x00800000
+#define HDR_ZRO 0x00008000
+
+/* Start Index or SharedDesc Length */
+#define HDR_START_IDX_MASK 0x3f
+#define HDR_START_IDX_SHIFT 16
+
+/* If shared descriptor header, 6-bit length */
+#define HDR_DESCLEN_SHR_MASK 0x3f
+
+/* If non-shared header, 7-bit length */
+#define HDR_DESCLEN_MASK 0x7f
+
+/* This is a TrustedDesc (if not SharedDesc) */
+#define HDR_TRUSTED 0x00004000
+
+/* Make into TrustedDesc (if not SharedDesc) */
+#define HDR_MAKE_TRUSTED 0x00002000
+
+/* Save context if self-shared (if SharedDesc) */
+#define HDR_SAVECTX 0x00001000
+
+/* Next item points to SharedDesc */
+#define HDR_SHARED 0x00001000
+
+/*
+ * Reverse Execution Order - execute JobDesc first, then
+ * execute SharedDesc (normally SharedDesc goes first).
+ */
+#define HDR_REVERSE 0x00000800
+
+/* Propogate DNR property to SharedDesc */
+#define HDR_PROP_DNR 0x00000800
+
+/* JobDesc/SharedDesc share property */
+#define HDR_SD_SHARE_MASK 0x03
+#define HDR_SD_SHARE_SHIFT 8
+#define HDR_JD_SHARE_MASK 0x07
+#define HDR_JD_SHARE_SHIFT 8
+
+#define HDR_SHARE_NEVER (0x00 << HDR_SD_SHARE_SHIFT)
+#define HDR_SHARE_WAIT (0x01 << HDR_SD_SHARE_SHIFT)
+#define HDR_SHARE_SERIAL (0x02 << HDR_SD_SHARE_SHIFT)
+#define HDR_SHARE_ALWAYS (0x03 << HDR_SD_SHARE_SHIFT)
+#define HDR_SHARE_DEFER (0x04 << HDR_SD_SHARE_SHIFT)
+
+/* JobDesc/SharedDesc descriptor length */
+#define HDR_JD_LENGTH_MASK 0x7f
+#define HDR_SD_LENGTH_MASK 0x3f
+
+/*
+ * KEY/SEQ_KEY Command Constructs
+ */
+
+/* Key Destination Class: 01 = Class 1, 02 - Class 2 */
+#define KEY_DEST_CLASS_SHIFT 25 /* use CLASS_1 or CLASS_2 */
+#define KEY_DEST_CLASS_MASK (0x03 << KEY_DEST_CLASS_SHIFT)
+
+/* Scatter-Gather Table/Variable Length Field */
+#define KEY_SGF 0x01000000
+#define KEY_VLF 0x01000000
+
+/* Immediate - Key follows command in the descriptor */
+#define KEY_IMM 0x00800000
+
+/*
+ * Encrypted - Key is encrypted either with the KEK, or
+ * with the TDKEK if TK is set
+ */
+#define KEY_ENC 0x00400000
+
+/*
+ * No Write Back - Do not allow key to be FIFO STOREd
+ */
+#define KEY_NWB 0x00200000
+
+/*
+ * Enhanced Encryption of Key
+ */
+#define KEY_EKT 0x00100000
+
+/*
+ * Encrypted with Trusted Key
+ */
+#define KEY_TK 0x00008000
+
+/*
+ * KDEST - Key Destination: 0 - class key register,
+ * 1 - PKHA 'e', 2 - AFHA Sbox, 3 - MDHA split-key
+ */
+#define KEY_DEST_SHIFT 16
+#define KEY_DEST_MASK (0x03 << KEY_DEST_SHIFT)
+
+#define KEY_DEST_CLASS_REG (0x00 << KEY_DEST_SHIFT)
+#define KEY_DEST_PKHA_E (0x01 << KEY_DEST_SHIFT)
+#define KEY_DEST_AFHA_SBOX (0x02 << KEY_DEST_SHIFT)
+#define KEY_DEST_MDHA_SPLIT (0x03 << KEY_DEST_SHIFT)
+
+/* Length in bytes */
+#define KEY_LENGTH_MASK 0x000003ff
+
+/*
+ * LOAD/SEQ_LOAD/STORE/SEQ_STORE Command Constructs
+ */
+
+/*
+ * Load/Store Destination: 0 = class independent CCB,
+ * 1 = class 1 CCB, 2 = class 2 CCB, 3 = DECO
+ */
+#define LDST_CLASS_SHIFT 25
+#define LDST_CLASS_MASK (0x03 << LDST_CLASS_SHIFT)
+#define LDST_CLASS_IND_CCB (0x00 << LDST_CLASS_SHIFT)
+#define LDST_CLASS_1_CCB (0x01 << LDST_CLASS_SHIFT)
+#define LDST_CLASS_2_CCB (0x02 << LDST_CLASS_SHIFT)
+#define LDST_CLASS_DECO (0x03 << LDST_CLASS_SHIFT)
+
+/* Scatter-Gather Table/Variable Length Field */
+#define LDST_SGF 0x01000000
+#define LDST_VLF LDST_SGF
+
+/* Immediate - Key follows this command in descriptor */
+#define LDST_IMM_MASK 1
+#define LDST_IMM_SHIFT 23
+#define LDST_IMM (LDST_IMM_MASK << LDST_IMM_SHIFT)
+
+/* SRC/DST - Destination for LOAD, Source for STORE */
+#define LDST_SRCDST_SHIFT 16
+#define LDST_SRCDST_MASK (0x7f << LDST_SRCDST_SHIFT)
+
+#define LDST_SRCDST_BYTE_CONTEXT (0x20 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_BYTE_KEY (0x40 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_BYTE_INFIFO (0x7c << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_BYTE_OUTFIFO (0x7e << LDST_SRCDST_SHIFT)
+
+#define LDST_SRCDST_WORD_MODE_REG (0x00 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_KEYSZ_REG (0x01 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_DATASZ_REG (0x02 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_ICVSZ_REG (0x03 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_CHACTRL (0x06 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_DECOCTRL (0x06 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_IRQCTRL (0x07 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_DECO_PCLOVRD (0x07 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_CLRW (0x08 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_DECO_MATH0 (0x08 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_STAT (0x09 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_DECO_MATH1 (0x09 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_DECO_MATH2 (0x0a << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_DECO_AAD_SZ (0x0b << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_DECO_MATH3 (0x0b << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_CLASS1_ICV_SZ (0x0c << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_ALTDS_CLASS1 (0x0f << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_PKHA_A_SZ (0x10 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_PKHA_B_SZ (0x11 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_PKHA_N_SZ (0x12 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_PKHA_E_SZ (0x13 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_DESCBUF (0x40 << LDST_SRCDST_SHIFT)
+#define LDST_SRCDST_WORD_INFO_FIFO (0x7a << LDST_SRCDST_SHIFT)
+
+/* Offset in source/destination */
+#define LDST_OFFSET_SHIFT 8
+#define LDST_OFFSET_MASK (0xff << LDST_OFFSET_SHIFT)
+
+/* LDOFF definitions used when DST = LDST_SRCDST_WORD_DECOCTRL */
+/* These could also be shifted by LDST_OFFSET_SHIFT - this reads better */
+#define LDOFF_CHG_SHARE_SHIFT 0
+#define LDOFF_CHG_SHARE_MASK (0x3 << LDOFF_CHG_SHARE_SHIFT)
+#define LDOFF_CHG_SHARE_NEVER (0x1 << LDOFF_CHG_SHARE_SHIFT)
+#define LDOFF_CHG_SHARE_OK_NO_PROP (0x2 << LDOFF_CHG_SHARE_SHIFT)
+#define LDOFF_CHG_SHARE_OK_PROP (0x3 << LDOFF_CHG_SHARE_SHIFT)
+
+#define LDOFF_ENABLE_AUTO_NFIFO (1 << 2)
+#define LDOFF_DISABLE_AUTO_NFIFO (1 << 3)
+
+#define LDOFF_CHG_NONSEQLIODN_SHIFT 4
+#define LDOFF_CHG_NONSEQLIODN_MASK (0x3 << LDOFF_CHG_NONSEQLIODN_SHIFT)
+#define LDOFF_CHG_NONSEQLIODN_SEQ (0x1 << LDOFF_CHG_NONSEQLIODN_SHIFT)
+#define LDOFF_CHG_NONSEQLIODN_NON_SEQ (0x2 << LDOFF_CHG_NONSEQLIODN_SHIFT)
+#define LDOFF_CHG_NONSEQLIODN_TRUSTED (0x3 << LDOFF_CHG_NONSEQLIODN_SHIFT)
+
+#define LDOFF_CHG_SEQLIODN_SHIFT 6
+#define LDOFF_CHG_SEQLIODN_MASK (0x3 << LDOFF_CHG_SEQLIODN_SHIFT)
+#define LDOFF_CHG_SEQLIODN_SEQ (0x1 << LDOFF_CHG_SEQLIODN_SHIFT)
+#define LDOFF_CHG_SEQLIODN_NON_SEQ (0x2 << LDOFF_CHG_SEQLIODN_SHIFT)
+#define LDOFF_CHG_SEQLIODN_TRUSTED (0x3 << LDOFF_CHG_SEQLIODN_SHIFT)
+
+/* Data length in bytes */
+#define LDST_LEN_SHIFT 0
+#define LDST_LEN_MASK (0xff << LDST_LEN_SHIFT)
+
+/* Special Length definitions when dst=deco-ctrl */
+#define LDLEN_ENABLE_OSL_COUNT (1 << 7)
+#define LDLEN_RST_CHA_OFIFO_PTR (1 << 6)
+#define LDLEN_RST_OFIFO (1 << 5)
+#define LDLEN_SET_OFIFO_OFF_VALID (1 << 4)
+#define LDLEN_SET_OFIFO_OFF_RSVD (1 << 3)
+#define LDLEN_SET_OFIFO_OFFSET_SHIFT 0
+#define LDLEN_SET_OFIFO_OFFSET_MASK (3 << LDLEN_SET_OFIFO_OFFSET_SHIFT)
+
+/*
+ * FIFO_LOAD/FIFO_STORE/SEQ_FIFO_LOAD/SEQ_FIFO_STORE
+ * Command Constructs
+ */
+
+/*
+ * Load Destination: 0 = skip (SEQ_FIFO_LOAD only),
+ * 1 = Load for Class1, 2 = Load for Class2, 3 = Load both
+ * Store Source: 0 = normal, 1 = Class1key, 2 = Class2key
+ */
+#define FIFOLD_CLASS_SHIFT 25
+#define FIFOLD_CLASS_MASK (0x03 << FIFOLD_CLASS_SHIFT)
+#define FIFOLD_CLASS_SKIP (0x00 << FIFOLD_CLASS_SHIFT)
+#define FIFOLD_CLASS_CLASS1 (0x01 << FIFOLD_CLASS_SHIFT)
+#define FIFOLD_CLASS_CLASS2 (0x02 << FIFOLD_CLASS_SHIFT)
+#define FIFOLD_CLASS_BOTH (0x03 << FIFOLD_CLASS_SHIFT)
+
+#define FIFOST_CLASS_SHIFT 25
+#define FIFOST_CLASS_MASK (0x03 << FIFOST_CLASS_SHIFT)
+#define FIFOST_CLASS_NORMAL (0x00 << FIFOST_CLASS_SHIFT)
+#define FIFOST_CLASS_CLASS1KEY (0x01 << FIFOST_CLASS_SHIFT)
+#define FIFOST_CLASS_CLASS2KEY (0x02 << FIFOST_CLASS_SHIFT)
+
+/*
+ * Scatter-Gather Table/Variable Length Field
+ * If set for FIFO_LOAD, refers to a SG table. Within
+ * SEQ_FIFO_LOAD, is variable input sequence
+ */
+#define FIFOLDST_SGF_SHIFT 24
+#define FIFOLDST_SGF_MASK (1 << FIFOLDST_SGF_SHIFT)
+#define FIFOLDST_VLF_MASK (1 << FIFOLDST_SGF_SHIFT)
+#define FIFOLDST_SGF (1 << FIFOLDST_SGF_SHIFT)
+#define FIFOLDST_VLF (1 << FIFOLDST_SGF_SHIFT)
+
+/* Immediate - Data follows command in descriptor */
+#define FIFOLD_IMM_SHIFT 23
+#define FIFOLD_IMM_MASK (1 << FIFOLD_IMM_SHIFT)
+#define FIFOLD_IMM (1 << FIFOLD_IMM_SHIFT)
+
+/* Continue - Not the last FIFO store to come */
+#define FIFOST_CONT_SHIFT 23
+#define FIFOST_CONT_MASK (1 << FIFOST_CONT_SHIFT)
+#define FIFOST_CONT_MASK (1 << FIFOST_CONT_SHIFT)
+
+/*
+ * Extended Length - use 32-bit extended length that
+ * follows the pointer field. Illegal with IMM set
+ */
+#define FIFOLDST_EXT_SHIFT 22
+#define FIFOLDST_EXT_MASK (1 << FIFOLDST_EXT_SHIFT)
+#define FIFOLDST_EXT (1 << FIFOLDST_EXT_SHIFT)
+
+/* Input data type.*/
+#define FIFOLD_TYPE_SHIFT 16
+#define FIFOLD_CONT_TYPE_SHIFT 19 /* shift past last-flush bits */
+#define FIFOLD_TYPE_MASK (0x3f << FIFOLD_TYPE_SHIFT)
+
+/* PK types */
+#define FIFOLD_TYPE_PK (0x00 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK_MASK (0x30 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK_TYPEMASK (0x0f << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK_A0 (0x00 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK_A1 (0x01 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK_A2 (0x02 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK_A3 (0x03 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK_B0 (0x04 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK_B1 (0x05 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK_B2 (0x06 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK_B3 (0x07 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK_N (0x08 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK_A (0x0c << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_PK_B (0x0d << FIFOLD_TYPE_SHIFT)
+
+/* Other types. Need to OR in last/flush bits as desired */
+#define FIFOLD_TYPE_MSG_MASK (0x38 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_MSG (0x10 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_MSG1OUT2 (0x18 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_IV (0x20 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_BITDATA (0x28 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_AAD (0x30 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_ICV (0x38 << FIFOLD_TYPE_SHIFT)
+
+/* Last/Flush bits for use with "other" types above */
+#define FIFOLD_TYPE_ACT_MASK (0x07 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_NOACTION (0x00 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_FLUSH1 (0x01 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_LAST1 (0x02 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_LAST2FLUSH (0x03 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_LAST2 (0x04 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_LAST2FLUSH1 (0x05 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_LASTBOTH (0x06 << FIFOLD_TYPE_SHIFT)
+#define FIFOLD_TYPE_LASTBOTHFL (0x07 << FIFOLD_TYPE_SHIFT)
+
+#define FIFOLDST_LEN_MASK 0xffff
+#define FIFOLDST_EXT_LEN_MASK 0xffffffff
+
+/* Output data types */
+#define FIFOST_TYPE_SHIFT 16
+#define FIFOST_TYPE_MASK (0x3f << FIFOST_TYPE_SHIFT)
+
+#define FIFOST_TYPE_PKHA_A0 (0x00 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_PKHA_A1 (0x01 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_PKHA_A2 (0x02 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_PKHA_A3 (0x03 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_PKHA_B0 (0x04 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_PKHA_B1 (0x05 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_PKHA_B2 (0x06 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_PKHA_B3 (0x07 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_PKHA_N (0x08 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_PKHA_A (0x0c << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_PKHA_B (0x0d << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_AF_SBOX_JKEK (0x10 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_AF_SBOX_TKEK (0x21 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_PKHA_E_JKEK (0x22 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_PKHA_E_TKEK (0x23 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_KEY_KEK (0x24 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_KEY_TKEK (0x25 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_SPLIT_KEK (0x26 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_SPLIT_TKEK (0x27 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_OUTFIFO_KEK (0x28 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_OUTFIFO_TKEK (0x29 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_MESSAGE_DATA (0x30 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_RNGSTORE (0x34 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_RNGFIFO (0x35 << FIFOST_TYPE_SHIFT)
+#define FIFOST_TYPE_SKIP (0x3f << FIFOST_TYPE_SHIFT)
+
+/*
+ * OPERATION Command Constructs
+ */
+
+/* Operation type selectors - OP TYPE */
+#define OP_TYPE_SHIFT 24
+#define OP_TYPE_MASK (0x07 << OP_TYPE_SHIFT)
+
+#define OP_TYPE_UNI_PROTOCOL (0x00 << OP_TYPE_SHIFT)
+#define OP_TYPE_PK (0x01 << OP_TYPE_SHIFT)
+#define OP_TYPE_CLASS1_ALG (0x02 << OP_TYPE_SHIFT)
+#define OP_TYPE_CLASS2_ALG (0x04 << OP_TYPE_SHIFT)
+#define OP_TYPE_DECAP_PROTOCOL (0x06 << OP_TYPE_SHIFT)
+#define OP_TYPE_ENCAP_PROTOCOL (0x07 << OP_TYPE_SHIFT)
+
+/* ProtocolID selectors - PROTID */
+#define OP_PCLID_SHIFT 16
+#define OP_PCLID_MASK (0xff << 16)
+
+/* Assuming OP_TYPE = OP_TYPE_UNI_PROTOCOL */
+#define OP_PCLID_IKEV1_PRF (0x01 << OP_PCLID_SHIFT)
+#define OP_PCLID_IKEV2_PRF (0x02 << OP_PCLID_SHIFT)
+#define OP_PCLID_SSL30_PRF (0x08 << OP_PCLID_SHIFT)
+#define OP_PCLID_TLS10_PRF (0x09 << OP_PCLID_SHIFT)
+#define OP_PCLID_TLS11_PRF (0x0a << OP_PCLID_SHIFT)
+#define OP_PCLID_DTLS10_PRF (0x0c << OP_PCLID_SHIFT)
+#define OP_PCLID_PRF (0x06 << OP_PCLID_SHIFT)
+#define OP_PCLID_BLOB (0x0d << OP_PCLID_SHIFT)
+#define OP_PCLID_SECRETKEY (0x11 << OP_PCLID_SHIFT)
+#define OP_PCLID_PUBLICKEYPAIR (0x14 << OP_PCLID_SHIFT)
+#define OP_PCLID_DSASIGN (0x15 << OP_PCLID_SHIFT)
+#define OP_PCLID_DSAVERIFY (0x16 << OP_PCLID_SHIFT)
+
+/* Assuming OP_TYPE = OP_TYPE_DECAP_PROTOCOL/ENCAP_PROTOCOL */
+#define OP_PCLID_IPSEC (0x01 << OP_PCLID_SHIFT)
+#define OP_PCLID_SRTP (0x02 << OP_PCLID_SHIFT)
+#define OP_PCLID_MACSEC (0x03 << OP_PCLID_SHIFT)
+#define OP_PCLID_WIFI (0x04 << OP_PCLID_SHIFT)
+#define OP_PCLID_WIMAX (0x05 << OP_PCLID_SHIFT)
+#define OP_PCLID_SSL30 (0x08 << OP_PCLID_SHIFT)
+#define OP_PCLID_TLS10 (0x09 << OP_PCLID_SHIFT)
+#define OP_PCLID_TLS11 (0x0a << OP_PCLID_SHIFT)
+#define OP_PCLID_TLS12 (0x0b << OP_PCLID_SHIFT)
+#define OP_PCLID_DTLS (0x0c << OP_PCLID_SHIFT)
+
+/*
+ * ProtocolInfo selectors
+ */
+#define OP_PCLINFO_MASK 0xffff
+
+/* for OP_PCLID_IPSEC */
+#define OP_PCL_IPSEC_CIPHER_MASK 0xff00
+#define OP_PCL_IPSEC_AUTH_MASK 0x00ff
+
+#define OP_PCL_IPSEC_DES_IV64 0x0100
+#define OP_PCL_IPSEC_DES 0x0200
+#define OP_PCL_IPSEC_3DES 0x0300
+#define OP_PCL_IPSEC_AES_CBC 0x0c00
+#define OP_PCL_IPSEC_AES_CTR 0x0d00
+#define OP_PCL_IPSEC_AES_XTS 0x1600
+#define OP_PCL_IPSEC_AES_CCM8 0x0e00
+#define OP_PCL_IPSEC_AES_CCM12 0x0f00
+#define OP_PCL_IPSEC_AES_CCM16 0x1000
+#define OP_PCL_IPSEC_AES_GCM8 0x1200
+#define OP_PCL_IPSEC_AES_GCM12 0x1300
+#define OP_PCL_IPSEC_AES_GCM16 0x1400
+
+#define OP_PCL_IPSEC_HMAC_NULL 0x0000
+#define OP_PCL_IPSEC_HMAC_MD5_96 0x0001
+#define OP_PCL_IPSEC_HMAC_SHA1_96 0x0002
+#define OP_PCL_IPSEC_AES_XCBC_MAC_96 0x0005
+#define OP_PCL_IPSEC_HMAC_MD5_128 0x0006
+#define OP_PCL_IPSEC_HMAC_SHA1_160 0x0007
+#define OP_PCL_IPSEC_HMAC_SHA2_256_128 0x000c
+#define OP_PCL_IPSEC_HMAC_SHA2_384_192 0x000d
+#define OP_PCL_IPSEC_HMAC_SHA2_512_256 0x000e
+
+/* For SRTP - OP_PCLID_SRTP */
+#define OP_PCL_SRTP_CIPHER_MASK 0xff00
+#define OP_PCL_SRTP_AUTH_MASK 0x00ff
+
+#define OP_PCL_SRTP_AES_CTR 0x0d00
+
+#define OP_PCL_SRTP_HMAC_SHA1_160 0x0007
+
+/* For SSL 3.0 - OP_PCLID_SSL30 */
+#define OP_PCL_SSL30_AES_128_CBC_SHA 0x002f
+#define OP_PCL_SSL30_AES_128_CBC_SHA_2 0x0030
+#define OP_PCL_SSL30_AES_128_CBC_SHA_3 0x0031
+#define OP_PCL_SSL30_AES_128_CBC_SHA_4 0x0032
+#define OP_PCL_SSL30_AES_128_CBC_SHA_5 0x0033
+#define OP_PCL_SSL30_AES_128_CBC_SHA_6 0x0034
+#define OP_PCL_SSL30_AES_128_CBC_SHA_7 0x008c
+#define OP_PCL_SSL30_AES_128_CBC_SHA_8 0x0090
+#define OP_PCL_SSL30_AES_128_CBC_SHA_9 0x0094
+#define OP_PCL_SSL30_AES_128_CBC_SHA_10 0xc004
+#define OP_PCL_SSL30_AES_128_CBC_SHA_11 0xc009
+#define OP_PCL_SSL30_AES_128_CBC_SHA_12 0xc00e
+#define OP_PCL_SSL30_AES_128_CBC_SHA_13 0xc013
+#define OP_PCL_SSL30_AES_128_CBC_SHA_14 0xc018
+#define OP_PCL_SSL30_AES_128_CBC_SHA_15 0xc01d
+#define OP_PCL_SSL30_AES_128_CBC_SHA_16 0xc01e
+#define OP_PCL_SSL30_AES_128_CBC_SHA_17 0xc01f
+
+#define OP_PCL_SSL30_AES_256_CBC_SHA 0x0035
+#define OP_PCL_SSL30_AES_256_CBC_SHA_2 0x0036
+#define OP_PCL_SSL30_AES_256_CBC_SHA_3 0x0037
+#define OP_PCL_SSL30_AES_256_CBC_SHA_4 0x0038
+#define OP_PCL_SSL30_AES_256_CBC_SHA_5 0x0039
+#define OP_PCL_SSL30_AES_256_CBC_SHA_6 0x003a
+#define OP_PCL_SSL30_AES_256_CBC_SHA_7 0x008d
+#define OP_PCL_SSL30_AES_256_CBC_SHA_8 0x0091
+#define OP_PCL_SSL30_AES_256_CBC_SHA_9 0x0095
+#define OP_PCL_SSL30_AES_256_CBC_SHA_10 0xc005
+#define OP_PCL_SSL30_AES_256_CBC_SHA_11 0xc00a
+#define OP_PCL_SSL30_AES_256_CBC_SHA_12 0xc00f
+#define OP_PCL_SSL30_AES_256_CBC_SHA_13 0xc014
+#define OP_PCL_SSL30_AES_256_CBC_SHA_14 0xc019
+#define OP_PCL_SSL30_AES_256_CBC_SHA_15 0xc020
+#define OP_PCL_SSL30_AES_256_CBC_SHA_16 0xc021
+#define OP_PCL_SSL30_AES_256_CBC_SHA_17 0xc022
+
+#define OP_PCL_SSL30_3DES_EDE_CBC_MD5 0x0023
+
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA 0x001f
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_2 0x008b
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_3 0x008f
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_4 0x0093
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_5 0x000a
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_6 0x000d
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_7 0x0010
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_8 0x0013
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_9 0x0016
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_10 0x001b
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_11 0xc003
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_12 0xc008
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_13 0xc00d
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_14 0xc012
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_15 0xc017
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_16 0xc01a
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_17 0xc01b
+#define OP_PCL_SSL30_3DES_EDE_CBC_SHA_18 0xc01c
+
+#define OP_PCL_SSL30_DES40_CBC_MD5 0x0029
+
+#define OP_PCL_SSL30_DES_CBC_MD5 0x0022
+
+#define OP_PCL_SSL30_DES40_CBC_SHA 0x0008
+#define OP_PCL_SSL30_DES40_CBC_SHA_2 0x000b
+#define OP_PCL_SSL30_DES40_CBC_SHA_3 0x000e
+#define OP_PCL_SSL30_DES40_CBC_SHA_4 0x0011
+#define OP_PCL_SSL30_DES40_CBC_SHA_5 0x0014
+#define OP_PCL_SSL30_DES40_CBC_SHA_6 0x0019
+#define OP_PCL_SSL30_DES40_CBC_SHA_7 0x0026
+
+#define OP_PCL_SSL30_DES_CBC_SHA 0x001e
+#define OP_PCL_SSL30_DES_CBC_SHA_2 0x0009
+#define OP_PCL_SSL30_DES_CBC_SHA_3 0x000c
+#define OP_PCL_SSL30_DES_CBC_SHA_4 0x000f
+#define OP_PCL_SSL30_DES_CBC_SHA_5 0x0012
+#define OP_PCL_SSL30_DES_CBC_SHA_6 0x0015
+#define OP_PCL_SSL30_DES_CBC_SHA_7 0x001a
+
+#define OP_PCL_SSL30_RC4_128_MD5 0x0024
+#define OP_PCL_SSL30_RC4_128_MD5_2 0x0004
+#define OP_PCL_SSL30_RC4_128_MD5_3 0x0018
+
+#define OP_PCL_SSL30_RC4_40_MD5 0x002b
+#define OP_PCL_SSL30_RC4_40_MD5_2 0x0003
+#define OP_PCL_SSL30_RC4_40_MD5_3 0x0017
+
+#define OP_PCL_SSL30_RC4_128_SHA 0x0020
+#define OP_PCL_SSL30_RC4_128_SHA_2 0x008a
+#define OP_PCL_SSL30_RC4_128_SHA_3 0x008e
+#define OP_PCL_SSL30_RC4_128_SHA_4 0x0092
+#define OP_PCL_SSL30_RC4_128_SHA_5 0x0005
+#define OP_PCL_SSL30_RC4_128_SHA_6 0xc002
+#define OP_PCL_SSL30_RC4_128_SHA_7 0xc007
+#define OP_PCL_SSL30_RC4_128_SHA_8 0xc00c
+#define OP_PCL_SSL30_RC4_128_SHA_9 0xc011
+#define OP_PCL_SSL30_RC4_128_SHA_10 0xc016
+
+#define OP_PCL_SSL30_RC4_40_SHA 0x0028
+
+
+/* For TLS 1.0 - OP_PCLID_TLS10 */
+#define OP_PCL_TLS10_AES_128_CBC_SHA 0x002f
+#define OP_PCL_TLS10_AES_128_CBC_SHA_2 0x0030
+#define OP_PCL_TLS10_AES_128_CBC_SHA_3 0x0031
+#define OP_PCL_TLS10_AES_128_CBC_SHA_4 0x0032
+#define OP_PCL_TLS10_AES_128_CBC_SHA_5 0x0033
+#define OP_PCL_TLS10_AES_128_CBC_SHA_6 0x0034
+#define OP_PCL_TLS10_AES_128_CBC_SHA_7 0x008c
+#define OP_PCL_TLS10_AES_128_CBC_SHA_8 0x0090
+#define OP_PCL_TLS10_AES_128_CBC_SHA_9 0x0094
+#define OP_PCL_TLS10_AES_128_CBC_SHA_10 0xc004
+#define OP_PCL_TLS10_AES_128_CBC_SHA_11 0xc009
+#define OP_PCL_TLS10_AES_128_CBC_SHA_12 0xc00e
+#define OP_PCL_TLS10_AES_128_CBC_SHA_13 0xc013
+#define OP_PCL_TLS10_AES_128_CBC_SHA_14 0xc018
+#define OP_PCL_TLS10_AES_128_CBC_SHA_15 0xc01d
+#define OP_PCL_TLS10_AES_128_CBC_SHA_16 0xc01e
+#define OP_PCL_TLS10_AES_128_CBC_SHA_17 0xc01f
+
+#define OP_PCL_TLS10_AES_256_CBC_SHA 0x0035
+#define OP_PCL_TLS10_AES_256_CBC_SHA_2 0x0036
+#define OP_PCL_TLS10_AES_256_CBC_SHA_3 0x0037
+#define OP_PCL_TLS10_AES_256_CBC_SHA_4 0x0038
+#define OP_PCL_TLS10_AES_256_CBC_SHA_5 0x0039
+#define OP_PCL_TLS10_AES_256_CBC_SHA_6 0x003a
+#define OP_PCL_TLS10_AES_256_CBC_SHA_7 0x008d
+#define OP_PCL_TLS10_AES_256_CBC_SHA_8 0x0091
+#define OP_PCL_TLS10_AES_256_CBC_SHA_9 0x0095
+#define OP_PCL_TLS10_AES_256_CBC_SHA_10 0xc005
+#define OP_PCL_TLS10_AES_256_CBC_SHA_11 0xc00a
+#define OP_PCL_TLS10_AES_256_CBC_SHA_12 0xc00f
+#define OP_PCL_TLS10_AES_256_CBC_SHA_13 0xc014
+#define OP_PCL_TLS10_AES_256_CBC_SHA_14 0xc019
+#define OP_PCL_TLS10_AES_256_CBC_SHA_15 0xc020
+#define OP_PCL_TLS10_AES_256_CBC_SHA_16 0xc021
+#define OP_PCL_TLS10_AES_256_CBC_SHA_17 0xc022
+
+/* #define OP_PCL_TLS10_3DES_EDE_CBC_MD5 0x0023 */
+
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA 0x001f
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_2 0x008b
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_3 0x008f
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_4 0x0093
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_5 0x000a
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_6 0x000d
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_7 0x0010
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_8 0x0013
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_9 0x0016
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_10 0x001b
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_11 0xc003
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_12 0xc008
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_13 0xc00d
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_14 0xc012
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_15 0xc017
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_16 0xc01a
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_17 0xc01b
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA_18 0xc01c
+
+#define OP_PCL_TLS10_DES40_CBC_MD5 0x0029
+
+#define OP_PCL_TLS10_DES_CBC_MD5 0x0022
+
+#define OP_PCL_TLS10_DES40_CBC_SHA 0x0008
+#define OP_PCL_TLS10_DES40_CBC_SHA_2 0x000b
+#define OP_PCL_TLS10_DES40_CBC_SHA_3 0x000e
+#define OP_PCL_TLS10_DES40_CBC_SHA_4 0x0011
+#define OP_PCL_TLS10_DES40_CBC_SHA_5 0x0014
+#define OP_PCL_TLS10_DES40_CBC_SHA_6 0x0019
+#define OP_PCL_TLS10_DES40_CBC_SHA_7 0x0026
+
+
+#define OP_PCL_TLS10_DES_CBC_SHA 0x001e
+#define OP_PCL_TLS10_DES_CBC_SHA_2 0x0009
+#define OP_PCL_TLS10_DES_CBC_SHA_3 0x000c
+#define OP_PCL_TLS10_DES_CBC_SHA_4 0x000f
+#define OP_PCL_TLS10_DES_CBC_SHA_5 0x0012
+#define OP_PCL_TLS10_DES_CBC_SHA_6 0x0015
+#define OP_PCL_TLS10_DES_CBC_SHA_7 0x001a
+
+#define OP_PCL_TLS10_RC4_128_MD5 0x0024
+#define OP_PCL_TLS10_RC4_128_MD5_2 0x0004
+#define OP_PCL_TLS10_RC4_128_MD5_3 0x0018
+
+#define OP_PCL_TLS10_RC4_40_MD5 0x002b
+#define OP_PCL_TLS10_RC4_40_MD5_2 0x0003
+#define OP_PCL_TLS10_RC4_40_MD5_3 0x0017
+
+#define OP_PCL_TLS10_RC4_128_SHA 0x0020
+#define OP_PCL_TLS10_RC4_128_SHA_2 0x008a
+#define OP_PCL_TLS10_RC4_128_SHA_3 0x008e
+#define OP_PCL_TLS10_RC4_128_SHA_4 0x0092
+#define OP_PCL_TLS10_RC4_128_SHA_5 0x0005
+#define OP_PCL_TLS10_RC4_128_SHA_6 0xc002
+#define OP_PCL_TLS10_RC4_128_SHA_7 0xc007
+#define OP_PCL_TLS10_RC4_128_SHA_8 0xc00c
+#define OP_PCL_TLS10_RC4_128_SHA_9 0xc011
+#define OP_PCL_TLS10_RC4_128_SHA_10 0xc016
+
+#define OP_PCL_TLS10_RC4_40_SHA 0x0028
+
+#define OP_PCL_TLS10_3DES_EDE_CBC_MD5 0xff23
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA160 0xff30
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA224 0xff34
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA256 0xff36
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA384 0xff33
+#define OP_PCL_TLS10_3DES_EDE_CBC_SHA512 0xff35
+#define OP_PCL_TLS10_AES_128_CBC_SHA160 0xff80
+#define OP_PCL_TLS10_AES_128_CBC_SHA224 0xff84
+#define OP_PCL_TLS10_AES_128_CBC_SHA256 0xff86
+#define OP_PCL_TLS10_AES_128_CBC_SHA384 0xff83
+#define OP_PCL_TLS10_AES_128_CBC_SHA512 0xff85
+#define OP_PCL_TLS10_AES_192_CBC_SHA160 0xff20
+#define OP_PCL_TLS10_AES_192_CBC_SHA224 0xff24
+#define OP_PCL_TLS10_AES_192_CBC_SHA256 0xff26
+#define OP_PCL_TLS10_AES_192_CBC_SHA384 0xff23
+#define OP_PCL_TLS10_AES_192_CBC_SHA512 0xff25
+#define OP_PCL_TLS10_AES_256_CBC_SHA160 0xff60
+#define OP_PCL_TLS10_AES_256_CBC_SHA224 0xff64
+#define OP_PCL_TLS10_AES_256_CBC_SHA256 0xff66
+#define OP_PCL_TLS10_AES_256_CBC_SHA384 0xff63
+#define OP_PCL_TLS10_AES_256_CBC_SHA512 0xff65
+
+
+
+/* For TLS 1.1 - OP_PCLID_TLS11 */
+#define OP_PCL_TLS11_AES_128_CBC_SHA 0x002f
+#define OP_PCL_TLS11_AES_128_CBC_SHA_2 0x0030
+#define OP_PCL_TLS11_AES_128_CBC_SHA_3 0x0031
+#define OP_PCL_TLS11_AES_128_CBC_SHA_4 0x0032
+#define OP_PCL_TLS11_AES_128_CBC_SHA_5 0x0033
+#define OP_PCL_TLS11_AES_128_CBC_SHA_6 0x0034
+#define OP_PCL_TLS11_AES_128_CBC_SHA_7 0x008c
+#define OP_PCL_TLS11_AES_128_CBC_SHA_8 0x0090
+#define OP_PCL_TLS11_AES_128_CBC_SHA_9 0x0094
+#define OP_PCL_TLS11_AES_128_CBC_SHA_10 0xc004
+#define OP_PCL_TLS11_AES_128_CBC_SHA_11 0xc009
+#define OP_PCL_TLS11_AES_128_CBC_SHA_12 0xc00e
+#define OP_PCL_TLS11_AES_128_CBC_SHA_13 0xc013
+#define OP_PCL_TLS11_AES_128_CBC_SHA_14 0xc018
+#define OP_PCL_TLS11_AES_128_CBC_SHA_15 0xc01d
+#define OP_PCL_TLS11_AES_128_CBC_SHA_16 0xc01e
+#define OP_PCL_TLS11_AES_128_CBC_SHA_17 0xc01f
+
+#define OP_PCL_TLS11_AES_256_CBC_SHA 0x0035
+#define OP_PCL_TLS11_AES_256_CBC_SHA_2 0x0036
+#define OP_PCL_TLS11_AES_256_CBC_SHA_3 0x0037
+#define OP_PCL_TLS11_AES_256_CBC_SHA_4 0x0038
+#define OP_PCL_TLS11_AES_256_CBC_SHA_5 0x0039
+#define OP_PCL_TLS11_AES_256_CBC_SHA_6 0x003a
+#define OP_PCL_TLS11_AES_256_CBC_SHA_7 0x008d
+#define OP_PCL_TLS11_AES_256_CBC_SHA_8 0x0091
+#define OP_PCL_TLS11_AES_256_CBC_SHA_9 0x0095
+#define OP_PCL_TLS11_AES_256_CBC_SHA_10 0xc005
+#define OP_PCL_TLS11_AES_256_CBC_SHA_11 0xc00a
+#define OP_PCL_TLS11_AES_256_CBC_SHA_12 0xc00f
+#define OP_PCL_TLS11_AES_256_CBC_SHA_13 0xc014
+#define OP_PCL_TLS11_AES_256_CBC_SHA_14 0xc019
+#define OP_PCL_TLS11_AES_256_CBC_SHA_15 0xc020
+#define OP_PCL_TLS11_AES_256_CBC_SHA_16 0xc021
+#define OP_PCL_TLS11_AES_256_CBC_SHA_17 0xc022
+
+/* #define OP_PCL_TLS11_3DES_EDE_CBC_MD5 0x0023 */
+
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA 0x001f
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_2 0x008b
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_3 0x008f
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_4 0x0093
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_5 0x000a
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_6 0x000d
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_7 0x0010
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_8 0x0013
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_9 0x0016
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_10 0x001b
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_11 0xc003
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_12 0xc008
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_13 0xc00d
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_14 0xc012
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_15 0xc017
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_16 0xc01a
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_17 0xc01b
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA_18 0xc01c
+
+#define OP_PCL_TLS11_DES40_CBC_MD5 0x0029
+
+#define OP_PCL_TLS11_DES_CBC_MD5 0x0022
+
+#define OP_PCL_TLS11_DES40_CBC_SHA 0x0008
+#define OP_PCL_TLS11_DES40_CBC_SHA_2 0x000b
+#define OP_PCL_TLS11_DES40_CBC_SHA_3 0x000e
+#define OP_PCL_TLS11_DES40_CBC_SHA_4 0x0011
+#define OP_PCL_TLS11_DES40_CBC_SHA_5 0x0014
+#define OP_PCL_TLS11_DES40_CBC_SHA_6 0x0019
+#define OP_PCL_TLS11_DES40_CBC_SHA_7 0x0026
+
+#define OP_PCL_TLS11_DES_CBC_SHA 0x001e
+#define OP_PCL_TLS11_DES_CBC_SHA_2 0x0009
+#define OP_PCL_TLS11_DES_CBC_SHA_3 0x000c
+#define OP_PCL_TLS11_DES_CBC_SHA_4 0x000f
+#define OP_PCL_TLS11_DES_CBC_SHA_5 0x0012
+#define OP_PCL_TLS11_DES_CBC_SHA_6 0x0015
+#define OP_PCL_TLS11_DES_CBC_SHA_7 0x001a
+
+#define OP_PCL_TLS11_RC4_128_MD5 0x0024
+#define OP_PCL_TLS11_RC4_128_MD5_2 0x0004
+#define OP_PCL_TLS11_RC4_128_MD5_3 0x0018
+
+#define OP_PCL_TLS11_RC4_40_MD5 0x002b
+#define OP_PCL_TLS11_RC4_40_MD5_2 0x0003
+#define OP_PCL_TLS11_RC4_40_MD5_3 0x0017
+
+#define OP_PCL_TLS11_RC4_128_SHA 0x0020
+#define OP_PCL_TLS11_RC4_128_SHA_2 0x008a
+#define OP_PCL_TLS11_RC4_128_SHA_3 0x008e
+#define OP_PCL_TLS11_RC4_128_SHA_4 0x0092
+#define OP_PCL_TLS11_RC4_128_SHA_5 0x0005
+#define OP_PCL_TLS11_RC4_128_SHA_6 0xc002
+#define OP_PCL_TLS11_RC4_128_SHA_7 0xc007
+#define OP_PCL_TLS11_RC4_128_SHA_8 0xc00c
+#define OP_PCL_TLS11_RC4_128_SHA_9 0xc011
+#define OP_PCL_TLS11_RC4_128_SHA_10 0xc016
+
+#define OP_PCL_TLS11_RC4_40_SHA 0x0028
+
+#define OP_PCL_TLS11_3DES_EDE_CBC_MD5 0xff23
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA160 0xff30
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA224 0xff34
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA256 0xff36
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA384 0xff33
+#define OP_PCL_TLS11_3DES_EDE_CBC_SHA512 0xff35
+#define OP_PCL_TLS11_AES_128_CBC_SHA160 0xff80
+#define OP_PCL_TLS11_AES_128_CBC_SHA224 0xff84
+#define OP_PCL_TLS11_AES_128_CBC_SHA256 0xff86
+#define OP_PCL_TLS11_AES_128_CBC_SHA384 0xff83
+#define OP_PCL_TLS11_AES_128_CBC_SHA512 0xff85
+#define OP_PCL_TLS11_AES_192_CBC_SHA160 0xff20
+#define OP_PCL_TLS11_AES_192_CBC_SHA224 0xff24
+#define OP_PCL_TLS11_AES_192_CBC_SHA256 0xff26
+#define OP_PCL_TLS11_AES_192_CBC_SHA384 0xff23
+#define OP_PCL_TLS11_AES_192_CBC_SHA512 0xff25
+#define OP_PCL_TLS11_AES_256_CBC_SHA160 0xff60
+#define OP_PCL_TLS11_AES_256_CBC_SHA224 0xff64
+#define OP_PCL_TLS11_AES_256_CBC_SHA256 0xff66
+#define OP_PCL_TLS11_AES_256_CBC_SHA384 0xff63
+#define OP_PCL_TLS11_AES_256_CBC_SHA512 0xff65
+
+
+/* For TLS 1.2 - OP_PCLID_TLS12 */
+#define OP_PCL_TLS12_AES_128_CBC_SHA 0x002f
+#define OP_PCL_TLS12_AES_128_CBC_SHA_2 0x0030
+#define OP_PCL_TLS12_AES_128_CBC_SHA_3 0x0031
+#define OP_PCL_TLS12_AES_128_CBC_SHA_4 0x0032
+#define OP_PCL_TLS12_AES_128_CBC_SHA_5 0x0033
+#define OP_PCL_TLS12_AES_128_CBC_SHA_6 0x0034
+#define OP_PCL_TLS12_AES_128_CBC_SHA_7 0x008c
+#define OP_PCL_TLS12_AES_128_CBC_SHA_8 0x0090
+#define OP_PCL_TLS12_AES_128_CBC_SHA_9 0x0094
+#define OP_PCL_TLS12_AES_128_CBC_SHA_10 0xc004
+#define OP_PCL_TLS12_AES_128_CBC_SHA_11 0xc009
+#define OP_PCL_TLS12_AES_128_CBC_SHA_12 0xc00e
+#define OP_PCL_TLS12_AES_128_CBC_SHA_13 0xc013
+#define OP_PCL_TLS12_AES_128_CBC_SHA_14 0xc018
+#define OP_PCL_TLS12_AES_128_CBC_SHA_15 0xc01d
+#define OP_PCL_TLS12_AES_128_CBC_SHA_16 0xc01e
+#define OP_PCL_TLS12_AES_128_CBC_SHA_17 0xc01f
+
+#define OP_PCL_TLS12_AES_256_CBC_SHA 0x0035
+#define OP_PCL_TLS12_AES_256_CBC_SHA_2 0x0036
+#define OP_PCL_TLS12_AES_256_CBC_SHA_3 0x0037
+#define OP_PCL_TLS12_AES_256_CBC_SHA_4 0x0038
+#define OP_PCL_TLS12_AES_256_CBC_SHA_5 0x0039
+#define OP_PCL_TLS12_AES_256_CBC_SHA_6 0x003a
+#define OP_PCL_TLS12_AES_256_CBC_SHA_7 0x008d
+#define OP_PCL_TLS12_AES_256_CBC_SHA_8 0x0091
+#define OP_PCL_TLS12_AES_256_CBC_SHA_9 0x0095
+#define OP_PCL_TLS12_AES_256_CBC_SHA_10 0xc005
+#define OP_PCL_TLS12_AES_256_CBC_SHA_11 0xc00a
+#define OP_PCL_TLS12_AES_256_CBC_SHA_12 0xc00f
+#define OP_PCL_TLS12_AES_256_CBC_SHA_13 0xc014
+#define OP_PCL_TLS12_AES_256_CBC_SHA_14 0xc019
+#define OP_PCL_TLS12_AES_256_CBC_SHA_15 0xc020
+#define OP_PCL_TLS12_AES_256_CBC_SHA_16 0xc021
+#define OP_PCL_TLS12_AES_256_CBC_SHA_17 0xc022
+
+/* #define OP_PCL_TLS12_3DES_EDE_CBC_MD5 0x0023 */
+
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA 0x001f
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_2 0x008b
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_3 0x008f
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_4 0x0093
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_5 0x000a
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_6 0x000d
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_7 0x0010
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_8 0x0013
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_9 0x0016
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_10 0x001b
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_11 0xc003
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_12 0xc008
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_13 0xc00d
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_14 0xc012
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_15 0xc017
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_16 0xc01a
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_17 0xc01b
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA_18 0xc01c
+
+#define OP_PCL_TLS12_DES40_CBC_MD5 0x0029
+
+#define OP_PCL_TLS12_DES_CBC_MD5 0x0022
+
+#define OP_PCL_TLS12_DES40_CBC_SHA 0x0008
+#define OP_PCL_TLS12_DES40_CBC_SHA_2 0x000b
+#define OP_PCL_TLS12_DES40_CBC_SHA_3 0x000e
+#define OP_PCL_TLS12_DES40_CBC_SHA_4 0x0011
+#define OP_PCL_TLS12_DES40_CBC_SHA_5 0x0014
+#define OP_PCL_TLS12_DES40_CBC_SHA_6 0x0019
+#define OP_PCL_TLS12_DES40_CBC_SHA_7 0x0026
+
+#define OP_PCL_TLS12_DES_CBC_SHA 0x001e
+#define OP_PCL_TLS12_DES_CBC_SHA_2 0x0009
+#define OP_PCL_TLS12_DES_CBC_SHA_3 0x000c
+#define OP_PCL_TLS12_DES_CBC_SHA_4 0x000f
+#define OP_PCL_TLS12_DES_CBC_SHA_5 0x0012
+#define OP_PCL_TLS12_DES_CBC_SHA_6 0x0015
+#define OP_PCL_TLS12_DES_CBC_SHA_7 0x001a
+
+#define OP_PCL_TLS12_RC4_128_MD5 0x0024
+#define OP_PCL_TLS12_RC4_128_MD5_2 0x0004
+#define OP_PCL_TLS12_RC4_128_MD5_3 0x0018
+
+#define OP_PCL_TLS12_RC4_40_MD5 0x002b
+#define OP_PCL_TLS12_RC4_40_MD5_2 0x0003
+#define OP_PCL_TLS12_RC4_40_MD5_3 0x0017
+
+#define OP_PCL_TLS12_RC4_128_SHA 0x0020
+#define OP_PCL_TLS12_RC4_128_SHA_2 0x008a
+#define OP_PCL_TLS12_RC4_128_SHA_3 0x008e
+#define OP_PCL_TLS12_RC4_128_SHA_4 0x0092
+#define OP_PCL_TLS12_RC4_128_SHA_5 0x0005
+#define OP_PCL_TLS12_RC4_128_SHA_6 0xc002
+#define OP_PCL_TLS12_RC4_128_SHA_7 0xc007
+#define OP_PCL_TLS12_RC4_128_SHA_8 0xc00c
+#define OP_PCL_TLS12_RC4_128_SHA_9 0xc011
+#define OP_PCL_TLS12_RC4_128_SHA_10 0xc016
+
+#define OP_PCL_TLS12_RC4_40_SHA 0x0028
+
+/* #define OP_PCL_TLS12_AES_128_CBC_SHA256 0x003c */
+#define OP_PCL_TLS12_AES_128_CBC_SHA256_2 0x003e
+#define OP_PCL_TLS12_AES_128_CBC_SHA256_3 0x003f
+#define OP_PCL_TLS12_AES_128_CBC_SHA256_4 0x0040
+#define OP_PCL_TLS12_AES_128_CBC_SHA256_5 0x0067
+#define OP_PCL_TLS12_AES_128_CBC_SHA256_6 0x006c
+
+/* #define OP_PCL_TLS12_AES_256_CBC_SHA256 0x003d */
+#define OP_PCL_TLS12_AES_256_CBC_SHA256_2 0x0068
+#define OP_PCL_TLS12_AES_256_CBC_SHA256_3 0x0069
+#define OP_PCL_TLS12_AES_256_CBC_SHA256_4 0x006a
+#define OP_PCL_TLS12_AES_256_CBC_SHA256_5 0x006b
+#define OP_PCL_TLS12_AES_256_CBC_SHA256_6 0x006d
+
+/* AEAD_AES_xxx_CCM/GCM remain to be defined... */
+
+#define OP_PCL_TLS12_3DES_EDE_CBC_MD5 0xff23
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA160 0xff30
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA224 0xff34
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA256 0xff36
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA384 0xff33
+#define OP_PCL_TLS12_3DES_EDE_CBC_SHA512 0xff35
+#define OP_PCL_TLS12_AES_128_CBC_SHA160 0xff80
+#define OP_PCL_TLS12_AES_128_CBC_SHA224 0xff84
+#define OP_PCL_TLS12_AES_128_CBC_SHA256 0xff86
+#define OP_PCL_TLS12_AES_128_CBC_SHA384 0xff83
+#define OP_PCL_TLS12_AES_128_CBC_SHA512 0xff85
+#define OP_PCL_TLS12_AES_192_CBC_SHA160 0xff20
+#define OP_PCL_TLS12_AES_192_CBC_SHA224 0xff24
+#define OP_PCL_TLS12_AES_192_CBC_SHA256 0xff26
+#define OP_PCL_TLS12_AES_192_CBC_SHA384 0xff23
+#define OP_PCL_TLS12_AES_192_CBC_SHA512 0xff25
+#define OP_PCL_TLS12_AES_256_CBC_SHA160 0xff60
+#define OP_PCL_TLS12_AES_256_CBC_SHA224 0xff64
+#define OP_PCL_TLS12_AES_256_CBC_SHA256 0xff66
+#define OP_PCL_TLS12_AES_256_CBC_SHA384 0xff63
+#define OP_PCL_TLS12_AES_256_CBC_SHA512 0xff65
+
+/* For DTLS - OP_PCLID_DTLS */
+
+#define OP_PCL_DTLS_AES_128_CBC_SHA 0x002f
+#define OP_PCL_DTLS_AES_128_CBC_SHA_2 0x0030
+#define OP_PCL_DTLS_AES_128_CBC_SHA_3 0x0031
+#define OP_PCL_DTLS_AES_128_CBC_SHA_4 0x0032
+#define OP_PCL_DTLS_AES_128_CBC_SHA_5 0x0033
+#define OP_PCL_DTLS_AES_128_CBC_SHA_6 0x0034
+#define OP_PCL_DTLS_AES_128_CBC_SHA_7 0x008c
+#define OP_PCL_DTLS_AES_128_CBC_SHA_8 0x0090
+#define OP_PCL_DTLS_AES_128_CBC_SHA_9 0x0094
+#define OP_PCL_DTLS_AES_128_CBC_SHA_10 0xc004
+#define OP_PCL_DTLS_AES_128_CBC_SHA_11 0xc009
+#define OP_PCL_DTLS_AES_128_CBC_SHA_12 0xc00e
+#define OP_PCL_DTLS_AES_128_CBC_SHA_13 0xc013
+#define OP_PCL_DTLS_AES_128_CBC_SHA_14 0xc018
+#define OP_PCL_DTLS_AES_128_CBC_SHA_15 0xc01d
+#define OP_PCL_DTLS_AES_128_CBC_SHA_16 0xc01e
+#define OP_PCL_DTLS_AES_128_CBC_SHA_17 0xc01f
+
+#define OP_PCL_DTLS_AES_256_CBC_SHA 0x0035
+#define OP_PCL_DTLS_AES_256_CBC_SHA_2 0x0036
+#define OP_PCL_DTLS_AES_256_CBC_SHA_3 0x0037
+#define OP_PCL_DTLS_AES_256_CBC_SHA_4 0x0038
+#define OP_PCL_DTLS_AES_256_CBC_SHA_5 0x0039
+#define OP_PCL_DTLS_AES_256_CBC_SHA_6 0x003a
+#define OP_PCL_DTLS_AES_256_CBC_SHA_7 0x008d
+#define OP_PCL_DTLS_AES_256_CBC_SHA_8 0x0091
+#define OP_PCL_DTLS_AES_256_CBC_SHA_9 0x0095
+#define OP_PCL_DTLS_AES_256_CBC_SHA_10 0xc005
+#define OP_PCL_DTLS_AES_256_CBC_SHA_11 0xc00a
+#define OP_PCL_DTLS_AES_256_CBC_SHA_12 0xc00f
+#define OP_PCL_DTLS_AES_256_CBC_SHA_13 0xc014
+#define OP_PCL_DTLS_AES_256_CBC_SHA_14 0xc019
+#define OP_PCL_DTLS_AES_256_CBC_SHA_15 0xc020
+#define OP_PCL_DTLS_AES_256_CBC_SHA_16 0xc021
+#define OP_PCL_DTLS_AES_256_CBC_SHA_17 0xc022
+
+/* #define OP_PCL_DTLS_3DES_EDE_CBC_MD5 0x0023 */
+
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA 0x001f
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_2 0x008b
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_3 0x008f
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_4 0x0093
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_5 0x000a
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_6 0x000d
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_7 0x0010
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_8 0x0013
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_9 0x0016
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_10 0x001b
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_11 0xc003
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_12 0xc008
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_13 0xc00d
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_14 0xc012
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_15 0xc017
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_16 0xc01a
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_17 0xc01b
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA_18 0xc01c
+
+#define OP_PCL_DTLS_DES40_CBC_MD5 0x0029
+
+#define OP_PCL_DTLS_DES_CBC_MD5 0x0022
+
+#define OP_PCL_DTLS_DES40_CBC_SHA 0x0008
+#define OP_PCL_DTLS_DES40_CBC_SHA_2 0x000b
+#define OP_PCL_DTLS_DES40_CBC_SHA_3 0x000e
+#define OP_PCL_DTLS_DES40_CBC_SHA_4 0x0011
+#define OP_PCL_DTLS_DES40_CBC_SHA_5 0x0014
+#define OP_PCL_DTLS_DES40_CBC_SHA_6 0x0019
+#define OP_PCL_DTLS_DES40_CBC_SHA_7 0x0026
+
+
+#define OP_PCL_DTLS_DES_CBC_SHA 0x001e
+#define OP_PCL_DTLS_DES_CBC_SHA_2 0x0009
+#define OP_PCL_DTLS_DES_CBC_SHA_3 0x000c
+#define OP_PCL_DTLS_DES_CBC_SHA_4 0x000f
+#define OP_PCL_DTLS_DES_CBC_SHA_5 0x0012
+#define OP_PCL_DTLS_DES_CBC_SHA_6 0x0015
+#define OP_PCL_DTLS_DES_CBC_SHA_7 0x001a
+
+
+#define OP_PCL_DTLS_3DES_EDE_CBC_MD5 0xff23
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA160 0xff30
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA224 0xff34
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA256 0xff36
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA384 0xff33
+#define OP_PCL_DTLS_3DES_EDE_CBC_SHA512 0xff35
+#define OP_PCL_DTLS_AES_128_CBC_SHA160 0xff80
+#define OP_PCL_DTLS_AES_128_CBC_SHA224 0xff84
+#define OP_PCL_DTLS_AES_128_CBC_SHA256 0xff86
+#define OP_PCL_DTLS_AES_128_CBC_SHA384 0xff83
+#define OP_PCL_DTLS_AES_128_CBC_SHA512 0xff85
+#define OP_PCL_DTLS_AES_192_CBC_SHA160 0xff20
+#define OP_PCL_DTLS_AES_192_CBC_SHA224 0xff24
+#define OP_PCL_DTLS_AES_192_CBC_SHA256 0xff26
+#define OP_PCL_DTLS_AES_192_CBC_SHA384 0xff23
+#define OP_PCL_DTLS_AES_192_CBC_SHA512 0xff25
+#define OP_PCL_DTLS_AES_256_CBC_SHA160 0xff60
+#define OP_PCL_DTLS_AES_256_CBC_SHA224 0xff64
+#define OP_PCL_DTLS_AES_256_CBC_SHA256 0xff66
+#define OP_PCL_DTLS_AES_256_CBC_SHA384 0xff63
+#define OP_PCL_DTLS_AES_256_CBC_SHA512 0xff65
+
+/* 802.16 WiMAX protinfos */
+#define OP_PCL_WIMAX_OFDM 0x0201
+#define OP_PCL_WIMAX_OFDMA 0x0231
+
+/* 802.11 WiFi protinfos */
+#define OP_PCL_WIFI 0xac04
+
+/* MacSec protinfos */
+#define OP_PCL_MACSEC 0x0001
+
+/* PKI unidirectional protocol protinfo bits */
+#define OP_PCL_PKPROT_TEST 0x0008
+#define OP_PCL_PKPROT_DECRYPT 0x0004
+#define OP_PCL_PKPROT_ECC 0x0002
+#define OP_PCL_PKPROT_F2M 0x0001
+
+/* For non-protocol/alg-only op commands */
+#define OP_ALG_TYPE_SHIFT 24
+#define OP_ALG_TYPE_MASK (0x7 << OP_ALG_TYPE_SHIFT)
+#define OP_ALG_TYPE_CLASS1 2
+#define OP_ALG_TYPE_CLASS2 4
+
+#define OP_ALG_ALGSEL_SHIFT 16
+#define OP_ALG_ALGSEL_MASK (0xff << OP_ALG_ALGSEL_SHIFT)
+#define OP_ALG_ALGSEL_SUBMASK (0x0f << OP_ALG_ALGSEL_SHIFT)
+#define OP_ALG_ALGSEL_AES (0x10 << OP_ALG_ALGSEL_SHIFT)
+#define OP_ALG_ALGSEL_DES (0x20 << OP_ALG_ALGSEL_SHIFT)
+#define OP_ALG_ALGSEL_3DES (0x21 << OP_ALG_ALGSEL_SHIFT)
+#define OP_ALG_ALGSEL_ARC4 (0x30 << OP_ALG_ALGSEL_SHIFT)
+#define OP_ALG_ALGSEL_MD5 (0x40 << OP_ALG_ALGSEL_SHIFT)
+#define OP_ALG_ALGSEL_SHA1 (0x41 << OP_ALG_ALGSEL_SHIFT)
+#define OP_ALG_ALGSEL_SHA224 (0x42 << OP_ALG_ALGSEL_SHIFT)
+#define OP_ALG_ALGSEL_SHA256 (0x43 << OP_ALG_ALGSEL_SHIFT)
+#define OP_ALG_ALGSEL_SHA384 (0x44 << OP_ALG_ALGSEL_SHIFT)
+#define OP_ALG_ALGSEL_SHA512 (0x45 << OP_ALG_ALGSEL_SHIFT)
+#define OP_ALG_ALGSEL_RNG (0x50 << OP_ALG_ALGSEL_SHIFT)
+#define OP_ALG_ALGSEL_SNOW (0x60 << OP_ALG_ALGSEL_SHIFT)
+#define OP_ALG_ALGSEL_SNOW_F8 (0x60 << OP_ALG_ALGSEL_SHIFT)
+#define OP_ALG_ALGSEL_KASUMI (0x70 << OP_ALG_ALGSEL_SHIFT)
+#define OP_ALG_ALGSEL_CRC (0x90 << OP_ALG_ALGSEL_SHIFT)
+#define OP_ALG_ALGSEL_SNOW_F9 (0xA0 << OP_ALG_ALGSEL_SHIFT)
+
+#define OP_ALG_AAI_SHIFT 4
+#define OP_ALG_AAI_MASK (0x1ff << OP_ALG_AAI_SHIFT)
+
+/* blockcipher AAI set */
+#define OP_ALG_AAI_CTR_MOD128 (0x00 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_CTR_MOD8 (0x01 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_CTR_MOD16 (0x02 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_CTR_MOD24 (0x03 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_CTR_MOD32 (0x04 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_CTR_MOD40 (0x05 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_CTR_MOD48 (0x06 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_CTR_MOD56 (0x07 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_CTR_MOD64 (0x08 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_CTR_MOD72 (0x09 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_CTR_MOD80 (0x0a << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_CTR_MOD88 (0x0b << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_CTR_MOD96 (0x0c << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_CTR_MOD104 (0x0d << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_CTR_MOD112 (0x0e << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_CTR_MOD120 (0x0f << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_CBC (0x10 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_ECB (0x20 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_CFB (0x30 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_OFB (0x40 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_XTS (0x50 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_CMAC (0x60 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_XCBC_MAC (0x70 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_CCM (0x80 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_GCM (0x90 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_CBC_XCBCMAC (0xa0 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_CTR_XCBCMAC (0xb0 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_CHECKODD (0x80 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_DK (0x100 << OP_ALG_AAI_SHIFT)
+
+/* randomizer AAI set */
+#define OP_ALG_AAI_RNG (0x00 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_RNG_NOZERO (0x10 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_RNG_ODD (0x20 << OP_ALG_AAI_SHIFT)
+
+/* hmac/smac AAI set */
+#define OP_ALG_AAI_HASH (0x00 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_HMAC (0x01 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_SMAC (0x02 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_HMAC_PRECOMP (0x04 << OP_ALG_AAI_SHIFT)
+
+/* CRC AAI set*/
+#define OP_ALG_AAI_802 (0x01 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_3385 (0x02 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_CUST_POLY (0x04 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_DIS (0x10 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_DOS (0x20 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_DOC (0x40 << OP_ALG_AAI_SHIFT)
+
+/* Kasumi/SNOW AAI set */
+#define OP_ALG_AAI_F8 (0xc0 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_F9 (0xc8 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_GSM (0x10 << OP_ALG_AAI_SHIFT)
+#define OP_ALG_AAI_EDGE (0x20 << OP_ALG_AAI_SHIFT)
+
+
+#define OP_ALG_AS_SHIFT 2
+#define OP_ALG_AS_MASK (0x3 << OP_ALG_AS_SHIFT)
+#define OP_ALG_AS_UPDATE (0 << OP_ALG_AS_SHIFT)
+#define OP_ALG_AS_INIT (1 << OP_ALG_AS_SHIFT)
+#define OP_ALG_AS_FINALIZE (2 << OP_ALG_AS_SHIFT)
+#define OP_ALG_AS_INITFINAL (3 << OP_ALG_AS_SHIFT)
+
+#define OP_ALG_ICV_SHIFT 1
+#define OP_ALG_ICV_MASK (1 << OP_ALG_ICV_SHIFT)
+#define OP_ALG_ICV_OFF (0 << OP_ALG_ICV_SHIFT)
+#define OP_ALG_ICV_ON (1 << OP_ALG_ICV_SHIFT)
+
+#define OP_ALG_DIR_SHIFT 0
+#define OP_ALG_DIR_MASK 1
+#define OP_ALG_DECRYPT 0
+#define OP_ALG_ENCRYPT 1
+
+/* PKHA algorithm type set */
+#define OP_ALG_PK 0x00800000
+#define OP_ALG_PK_FUN_MASK 0x3f /* clrmem, modmath, or cpymem */
+
+/* PKHA mode clear memory functions */
+#define OP_ALG_PKMODE_A_RAM 0x80000
+#define OP_ALG_PKMODE_B_RAM 0x40000
+#define OP_ALG_PKMODE_E_RAM 0x20000
+#define OP_ALG_PKMODE_N_RAM 0x10000
+#define OP_ALG_PKMODE_CLEARMEM 0x00001
+
+/* PKHA mode modular-arithmetic functions */
+#define OP_ALG_PKMODE_MOD_IN_MONTY 0x80000
+#define OP_ALG_PKMODE_MOD_OUT_MONTY 0x40000
+#define OP_ALG_PKMODE_MOD_F2M 0x20000
+#define OP_ALG_PKMODE_MOD_R2_IN 0x10000
+#define OP_ALG_PKMODE_PRJECTV 0x00800
+#define OP_ALG_PKMODE_TIME_EQ 0x400
+#define OP_ALG_PKMODE_OUT_B 0x000
+#define OP_ALG_PKMODE_OUT_A 0x100
+#define OP_ALG_PKMODE_MOD_ADD 0x002
+#define OP_ALG_PKMODE_MOD_SUB_AB 0x003
+#define OP_ALG_PKMODE_MOD_SUB_BA 0x004
+#define OP_ALG_PKMODE_MOD_MULT 0x005
+#define OP_ALG_PKMODE_MOD_EXPO 0x006
+#define OP_ALG_PKMODE_MOD_REDUCT 0x007
+#define OP_ALG_PKMODE_MOD_INV 0x008
+#define OP_ALG_PKMODE_MOD_ECC_ADD 0x009
+#define OP_ALG_PKMODE_MOD_ECC_DBL 0x00a
+#define OP_ALG_PKMODE_MOD_ECC_MULT 0x00b
+#define OP_ALG_PKMODE_MOD_MONT_CNST 0x00c
+#define OP_ALG_PKMODE_MOD_CRT_CNST 0x00d
+#define OP_ALG_PKMODE_MOD_GCD 0x00e
+#define OP_ALG_PKMODE_MOD_PRIMALITY 0x00f
+
+/* PKHA mode copy-memory functions */
+#define OP_ALG_PKMODE_SRC_REG_SHIFT 13
+#define OP_ALG_PKMODE_SRC_REG_MASK (7 << OP_ALG_PKMODE_SRC_REG_SHIFT)
+#define OP_ALG_PKMODE_DST_REG_SHIFT 10
+#define OP_ALG_PKMODE_DST_REG_MASK (7 << OP_ALG_PKMODE_DST_REG_SHIFT)
+#define OP_ALG_PKMODE_SRC_SEG_SHIFT 8
+#define OP_ALG_PKMODE_SRC_SEG_MASK (3 << OP_ALG_PKMODE_SRC_SEG_SHIFT)
+#define OP_ALG_PKMODE_DST_SEG_SHIFT 6
+#define OP_ALG_PKMODE_DST_SEG_MASK (3 << OP_ALG_PKMODE_DST_SEG_SHIFT)
+
+#define OP_ALG_PKMODE_SRC_REG_A (0 << OP_ALG_PKMODE_SRC_REG_SHIFT)
+#define OP_ALG_PKMODE_SRC_REG_B (1 << OP_ALG_PKMODE_SRC_REG_SHIFT)
+#define OP_ALG_PKMODE_SRC_REG_N (3 << OP_ALG_PKMODE_SRC_REG_SHIFT)
+#define OP_ALG_PKMODE_DST_REG_A (0 << OP_ALG_PKMODE_DST_REG_SHIFT)
+#define OP_ALG_PKMODE_DST_REG_B (1 << OP_ALG_PKMODE_DST_REG_SHIFT)
+#define OP_ALG_PKMODE_DST_REG_E (2 << OP_ALG_PKMODE_DST_REG_SHIFT)
+#define OP_ALG_PKMODE_DST_REG_N (3 << OP_ALG_PKMODE_DST_REG_SHIFT)
+#define OP_ALG_PKMODE_SRC_SEG_0 (0 << OP_ALG_PKMODE_SRC_SEG_SHIFT)
+#define OP_ALG_PKMODE_SRC_SEG_1 (1 << OP_ALG_PKMODE_SRC_SEG_SHIFT)
+#define OP_ALG_PKMODE_SRC_SEG_2 (2 << OP_ALG_PKMODE_SRC_SEG_SHIFT)
+#define OP_ALG_PKMODE_SRC_SEG_3 (3 << OP_ALG_PKMODE_SRC_SEG_SHIFT)
+#define OP_ALG_PKMODE_DST_SEG_0 (0 << OP_ALG_PKMODE_DST_SEG_SHIFT)
+#define OP_ALG_PKMODE_DST_SEG_1 (1 << OP_ALG_PKMODE_DST_SEG_SHIFT)
+#define OP_ALG_PKMODE_DST_SEG_2 (2 << OP_ALG_PKMODE_DST_SEG_SHIFT)
+#define OP_ALG_PKMODE_DST_SEG_3 (3 << OP_ALG_PKMODE_DST_SEG_SHIFT)
+#define OP_ALG_PKMODE_CPYMEM_N_SZ 0x80
+#define OP_ALG_PKMODE_CPYMEM_SRC_SZ 0x81
+
+/*
+ * SEQ_IN_PTR Command Constructs
+ */
+
+/* Release Buffers */
+#define SQIN_RBS 0x04000000
+
+/* Sequence pointer is really a descriptor */
+#define SQIN_INL 0x02000000
+
+/* Sequence pointer is a scatter-gather table */
+#define SQIN_SGF 0x01000000
+
+/* Appends to a previous pointer */
+#define SQIN_PRE 0x00800000
+
+/* Use extended length following pointer */
+#define SQIN_EXT 0x00400000
+
+/* Restore sequence with pointer/length */
+#define SQIN_RTO 0x00200000
+
+/* Replace job descriptor */
+#define SQIN_RJD 0x00100000
+
+#define SQIN_LEN_SHIFT 0
+#define SQIN_LEN_MASK (0xffff << SQIN_LEN_SHIFT)
+
+/*
+ * SEQ_OUT_PTR Command Constructs
+ */
+
+/* Sequence pointer is a scatter-gather table */
+#define SQOUT_SGF 0x01000000
+
+/* Appends to a previous pointer */
+#define SQOUT_PRE 0x00800000
+
+/* Restore sequence with pointer/length */
+#define SQOUT_RTO 0x00200000
+
+/* Use extended length following pointer */
+#define SQOUT_EXT 0x00400000
+
+#define SQOUT_LEN_SHIFT 0
+#define SQOUT_LEN_MASK (0xffff << SQOUT_LEN_SHIFT)
+
+
+/*
+ * SIGNATURE Command Constructs
+ */
+
+/* TYPE field is all that's relevant */
+#define SIGN_TYPE_SHIFT 16
+#define SIGN_TYPE_MASK (0x0f << SIGN_TYPE_SHIFT)
+
+#define SIGN_TYPE_FINAL (0x00 << SIGN_TYPE_SHIFT)
+#define SIGN_TYPE_FINAL_RESTORE (0x01 << SIGN_TYPE_SHIFT)
+#define SIGN_TYPE_FINAL_NONZERO (0x02 << SIGN_TYPE_SHIFT)
+#define SIGN_TYPE_IMM_2 (0x0a << SIGN_TYPE_SHIFT)
+#define SIGN_TYPE_IMM_3 (0x0b << SIGN_TYPE_SHIFT)
+#define SIGN_TYPE_IMM_4 (0x0c << SIGN_TYPE_SHIFT)
+
+/*
+ * MOVE Command Constructs
+ */
+
+#define MOVE_AUX_SHIFT 25
+#define MOVE_AUX_MASK (3 << MOVE_AUX_SHIFT)
+#define MOVE_AUX_MS (2 << MOVE_AUX_SHIFT)
+#define MOVE_AUX_LS (1 << MOVE_AUX_SHIFT)
+
+#define MOVE_WAITCOMP_SHIFT 24
+#define MOVE_WAITCOMP_MASK (1 << MOVE_WAITCOMP_SHIFT)
+#define MOVE_WAITCOMP (1 << MOVE_WAITCOMP_SHIFT)
+
+#define MOVE_SRC_SHIFT 20
+#define MOVE_SRC_MASK (0x0f << MOVE_SRC_SHIFT)
+#define MOVE_SRC_CLASS1CTX (0x00 << MOVE_SRC_SHIFT)
+#define MOVE_SRC_CLASS2CTX (0x01 << MOVE_SRC_SHIFT)
+#define MOVE_SRC_OUTFIFO (0x02 << MOVE_SRC_SHIFT)
+#define MOVE_SRC_DESCBUF (0x03 << MOVE_SRC_SHIFT)
+#define MOVE_SRC_MATH0 (0x04 << MOVE_SRC_SHIFT)
+#define MOVE_SRC_MATH1 (0x05 << MOVE_SRC_SHIFT)
+#define MOVE_SRC_MATH2 (0x06 << MOVE_SRC_SHIFT)
+#define MOVE_SRC_MATH3 (0x07 << MOVE_SRC_SHIFT)
+#define MOVE_SRC_INFIFO (0x08 << MOVE_SRC_SHIFT)
+#define MOVE_SRC_INFIFO_CL (0x09 << MOVE_SRC_SHIFT)
+
+#define MOVE_DEST_SHIFT 16
+#define MOVE_DEST_MASK (0x0f << MOVE_DEST_SHIFT)
+#define MOVE_DEST_CLASS1CTX (0x00 << MOVE_DEST_SHIFT)
+#define MOVE_DEST_CLASS2CTX (0x01 << MOVE_DEST_SHIFT)
+#define MOVE_DEST_OUTFIFO (0x02 << MOVE_DEST_SHIFT)
+#define MOVE_DEST_DESCBUF (0x03 << MOVE_DEST_SHIFT)
+#define MOVE_DEST_MATH0 (0x04 << MOVE_DEST_SHIFT)
+#define MOVE_DEST_MATH1 (0x05 << MOVE_DEST_SHIFT)
+#define MOVE_DEST_MATH2 (0x06 << MOVE_DEST_SHIFT)
+#define MOVE_DEST_MATH3 (0x07 << MOVE_DEST_SHIFT)
+#define MOVE_DEST_CLASS1INFIFO (0x08 << MOVE_DEST_SHIFT)
+#define MOVE_DEST_CLASS2INFIFO (0x09 << MOVE_DEST_SHIFT)
+#define MOVE_DEST_PK_A (0x0c << MOVE_DEST_SHIFT)
+#define MOVE_DEST_CLASS1KEY (0x0d << MOVE_DEST_SHIFT)
+#define MOVE_DEST_CLASS2KEY (0x0e << MOVE_DEST_SHIFT)
+
+#define MOVE_OFFSET_SHIFT 8
+#define MOVE_OFFSET_MASK (0xff << MOVE_OFFSET_SHIFT)
+
+#define MOVE_LEN_SHIFT 0
+#define MOVE_LEN_MASK (0xff << MOVE_LEN_SHIFT)
+
+#define MOVELEN_MRSEL_SHIFT 0
+#define MOVELEN_MRSEL_MASK (0x3 << MOVE_LEN_SHIFT)
+
+/*
+ * MATH Command Constructs
+ */
+
+#define MATH_IFB_SHIFT 26
+#define MATH_IFB_MASK (1 << MATH_IFB_SHIFT)
+#define MATH_IFB (1 << MATH_IFB_SHIFT)
+
+#define MATH_NFU_SHIFT 25
+#define MATH_NFU_MASK (1 << MATH_NFU_SHIFT)
+#define MATH_NFU (1 << MATH_NFU_SHIFT)
+
+#define MATH_STL_SHIFT 24
+#define MATH_STL_MASK (1 << MATH_STL_SHIFT)
+#define MATH_STL (1 << MATH_STL_SHIFT)
+
+/* Function selectors */
+#define MATH_FUN_SHIFT 20
+#define MATH_FUN_MASK (0x0f << MATH_FUN_SHIFT)
+#define MATH_FUN_ADD (0x00 << MATH_FUN_SHIFT)
+#define MATH_FUN_ADDC (0x01 << MATH_FUN_SHIFT)
+#define MATH_FUN_SUB (0x02 << MATH_FUN_SHIFT)
+#define MATH_FUN_SUBB (0x03 << MATH_FUN_SHIFT)
+#define MATH_FUN_OR (0x04 << MATH_FUN_SHIFT)
+#define MATH_FUN_AND (0x05 << MATH_FUN_SHIFT)
+#define MATH_FUN_XOR (0x06 << MATH_FUN_SHIFT)
+#define MATH_FUN_LSHIFT (0x07 << MATH_FUN_SHIFT)
+#define MATH_FUN_RSHIFT (0x08 << MATH_FUN_SHIFT)
+#define MATH_FUN_SHLD (0x09 << MATH_FUN_SHIFT)
+#define MATH_FUN_ZBYT (0x0a << MATH_FUN_SHIFT)
+
+/* Source 0 selectors */
+#define MATH_SRC0_SHIFT 16
+#define MATH_SRC0_MASK (0x0f << MATH_SRC0_SHIFT)
+#define MATH_SRC0_REG0 (0x00 << MATH_SRC0_SHIFT)
+#define MATH_SRC0_REG1 (0x01 << MATH_SRC0_SHIFT)
+#define MATH_SRC0_REG2 (0x02 << MATH_SRC0_SHIFT)
+#define MATH_SRC0_REG3 (0x03 << MATH_SRC0_SHIFT)
+#define MATH_SRC0_IMM (0x04 << MATH_SRC0_SHIFT)
+#define MATH_SRC0_SEQINLEN (0x08 << MATH_SRC0_SHIFT)
+#define MATH_SRC0_SEQOUTLEN (0x09 << MATH_SRC0_SHIFT)
+#define MATH_SRC0_VARSEQINLEN (0x0a << MATH_SRC0_SHIFT)
+#define MATH_SRC0_VARSEQOUTLEN (0x0b << MATH_SRC0_SHIFT)
+#define MATH_SRC0_ZERO (0x0c << MATH_SRC0_SHIFT)
+
+/* Source 1 selectors */
+#define MATH_SRC1_SHIFT 12
+#define MATH_SRC1_MASK (0x0f << MATH_SRC1_SHIFT)
+#define MATH_SRC1_REG0 (0x00 << MATH_SRC1_SHIFT)
+#define MATH_SRC1_REG1 (0x01 << MATH_SRC1_SHIFT)
+#define MATH_SRC1_REG2 (0x02 << MATH_SRC1_SHIFT)
+#define MATH_SRC1_REG3 (0x03 << MATH_SRC1_SHIFT)
+#define MATH_SRC1_IMM (0x04 << MATH_SRC1_SHIFT)
+#define MATH_SRC1_INFIFO (0x0a << MATH_SRC1_SHIFT)
+#define MATH_SRC1_OUTFIFO (0x0b << MATH_SRC1_SHIFT)
+#define MATH_SRC1_ONE (0x0c << MATH_SRC1_SHIFT)
+
+/* Destination selectors */
+#define MATH_DEST_SHIFT 8
+#define MATH_DEST_MASK (0x0f << MATH_DEST_SHIFT)
+#define MATH_DEST_REG0 (0x00 << MATH_DEST_SHIFT)
+#define MATH_DEST_REG1 (0x01 << MATH_DEST_SHIFT)
+#define MATH_DEST_REG2 (0x02 << MATH_DEST_SHIFT)
+#define MATH_DEST_REG3 (0x03 << MATH_DEST_SHIFT)
+#define MATH_DEST_SEQINLEN (0x08 << MATH_DEST_SHIFT)
+#define MATH_DEST_SEQOUTLEN (0x09 << MATH_DEST_SHIFT)
+#define MATH_DEST_VARSEQINLEN (0x0a << MATH_DEST_SHIFT)
+#define MATH_DEST_VARSEQOUTLEN (0x0b << MATH_DEST_SHIFT)
+#define MATH_DEST_NONE (0x0f << MATH_DEST_SHIFT)
+
+/* Length selectors */
+#define MATH_LEN_SHIFT 0
+#define MATH_LEN_MASK (0x0f << MATH_LEN_SHIFT)
+#define MATH_LEN_1BYTE 0x01
+#define MATH_LEN_2BYTE 0x02
+#define MATH_LEN_4BYTE 0x04
+#define MATH_LEN_8BYTE 0x08
+
+/*
+ * JUMP Command Constructs
+ */
+
+#define JUMP_CLASS_SHIFT 25
+#define JUMP_CLASS_MASK (3 << JUMP_CLASS_SHIFT)
+#define JUMP_CLASS_NONE 0
+#define JUMP_CLASS_CLASS1 (1 << JUMP_CLASS_SHIFT)
+#define JUMP_CLASS_CLASS2 (2 << JUMP_CLASS_SHIFT)
+#define JUMP_CLASS_BOTH (3 << JUMP_CLASS_SHIFT)
+
+#define JUMP_JSL_SHIFT 24
+#define JUMP_JSL_MASK (1 << JUMP_JSL_SHIFT)
+#define JUMP_JSL (1 << JUMP_JSL_SHIFT)
+
+#define JUMP_TYPE_SHIFT 22
+#define JUMP_TYPE_MASK (0x03 << JUMP_TYPE_SHIFT)
+#define JUMP_TYPE_LOCAL (0x00 << JUMP_TYPE_SHIFT)
+#define JUMP_TYPE_NONLOCAL (0x01 << JUMP_TYPE_SHIFT)
+#define JUMP_TYPE_HALT (0x02 << JUMP_TYPE_SHIFT)
+#define JUMP_TYPE_HALT_USER (0x03 << JUMP_TYPE_SHIFT)
+
+#define JUMP_TEST_SHIFT 16
+#define JUMP_TEST_MASK (0x03 << JUMP_TEST_SHIFT)
+#define JUMP_TEST_ALL (0x00 << JUMP_TEST_SHIFT)
+#define JUMP_TEST_INVALL (0x01 << JUMP_TEST_SHIFT)
+#define JUMP_TEST_ANY (0x02 << JUMP_TEST_SHIFT)
+#define JUMP_TEST_INVANY (0x03 << JUMP_TEST_SHIFT)
+
+/* Condition codes. JSL bit is factored in */
+#define JUMP_COND_SHIFT 8
+#define JUMP_COND_MASK (0x100ff << JUMP_COND_SHIFT)
+#define JUMP_COND_PK_0 (0x80 << JUMP_COND_SHIFT)
+#define JUMP_COND_PK_GCD_1 (0x40 << JUMP_COND_SHIFT)
+#define JUMP_COND_PK_PRIME (0x20 << JUMP_COND_SHIFT)
+#define JUMP_COND_MATH_N (0x08 << JUMP_COND_SHIFT)
+#define JUMP_COND_MATH_Z (0x04 << JUMP_COND_SHIFT)
+#define JUMP_COND_MATH_C (0x02 << JUMP_COND_SHIFT)
+#define JUMP_COND_MATH_NV (0x01 << JUMP_COND_SHIFT)
+
+#define JUMP_COND_JRP ((0x80 << JUMP_COND_SHIFT) | JUMP_JSL)
+#define JUMP_COND_SHRD ((0x40 << JUMP_COND_SHIFT) | JUMP_JSL)
+#define JUMP_COND_SELF ((0x20 << JUMP_COND_SHIFT) | JUMP_JSL)
+#define JUMP_COND_CALM ((0x10 << JUMP_COND_SHIFT) | JUMP_JSL)
+#define JUMP_COND_NIP ((0x08 << JUMP_COND_SHIFT) | JUMP_JSL)
+#define JUMP_COND_NIFP ((0x04 << JUMP_COND_SHIFT) | JUMP_JSL)
+#define JUMP_COND_NOP ((0x02 << JUMP_COND_SHIFT) | JUMP_JSL)
+#define JUMP_COND_NCP ((0x01 << JUMP_COND_SHIFT) | JUMP_JSL)
+
+#define JUMP_OFFSET_SHIFT 0
+#define JUMP_OFFSET_MASK (0xff << JUMP_OFFSET_SHIFT)
+
+/*
+ * NFIFO ENTRY
+ * Data Constructs
+ *
+ */
+#define NFIFOENTRY_DEST_SHIFT 30
+#define NFIFOENTRY_DEST_MASK (3 << NFIFOENTRY_DEST_SHIFT)
+#define NFIFOENTRY_DEST_DECO (0 << NFIFOENTRY_DEST_SHIFT)
+#define NFIFOENTRY_DEST_CLASS1 (1 << NFIFOENTRY_DEST_SHIFT)
+#define NFIFOENTRY_DEST_CLASS2 (2 << NFIFOENTRY_DEST_SHIFT)
+#define NFIFOENTRY_DEST_BOTH (3 << NFIFOENTRY_DEST_SHIFT)
+
+#define NFIFOENTRY_LC2_SHIFT 29
+#define NFIFOENTRY_LC2_MASK (1 << NFIFOENTRY_LC2_SHIFT)
+#define NFIFOENTRY_LC2 (1 << NFIFOENTRY_LC2_SHIFT)
+
+#define NFIFOENTRY_LC1_SHIFT 28
+#define NFIFOENTRY_LC1_MASK (1 << NFIFOENTRY_LC1_SHIFT)
+#define NFIFOENTRY_LC1 (1 << NFIFOENTRY_LC1_SHIFT)
+
+#define NFIFOENTRY_FC2_SHIFT 27
+#define NFIFOENTRY_FC2_MASK (1 << NFIFOENTRY_FC2_SHIFT)
+#define NFIFOENTRY_FC2 (1 << NFIFOENTRY_FC2_SHIFT)
+
+#define NFIFOENTRY_FC1_SHIFT 26
+#define NFIFOENTRY_FC1_MASK (1 << NFIFOENTRY_FC1_SHIFT)
+#define NFIFOENTRY_FC1 (1 << NFIFOENTRY_FC1_SHIFT)
+
+#define NFIFOENTRY_STYPE_SHIFT 24
+#define NFIFOENTRY_STYPE_MASK (3 << NFIFOENTRY_STYPE_SHIFT)
+#define NFIFOENTRY_STYPE_DFIFO (0 << NFIFOENTRY_STYPE_SHIFT)
+#define NFIFOENTRY_STYPE_OFIFO (1 << NFIFOENTRY_STYPE_SHIFT)
+#define NFIFOENTRY_STYPE_PAD (2 << NFIFOENTRY_STYPE_SHIFT)
+#define NFIFOENTRY_STYPE_SNOOP (3 << NFIFOENTRY_STYPE_SHIFT)
+
+#define NFIFOENTRY_DTYPE_SHIFT 20
+#define NFIFOENTRY_DTYPE_MASK (0xF << NFIFOENTRY_DTYPE_SHIFT)
+
+#define NFIFOENTRY_DTYPE_SBOX (0x0 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_AAD (0x1 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_IV (0x2 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_SAD (0x3 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_ICV (0xA << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_SKIP (0xE << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_MSG (0xF << NFIFOENTRY_DTYPE_SHIFT)
+
+#define NFIFOENTRY_DTYPE_PK_A0 (0x0 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_PK_A1 (0x1 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_PK_A2 (0x2 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_PK_A3 (0x3 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_PK_B0 (0x4 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_PK_B1 (0x5 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_PK_B2 (0x6 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_PK_B3 (0x7 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_PK_N (0x8 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_PK_E (0x9 << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_PK_A (0xC << NFIFOENTRY_DTYPE_SHIFT)
+#define NFIFOENTRY_DTYPE_PK_B (0xD << NFIFOENTRY_DTYPE_SHIFT)
+
+
+#define NFIFOENTRY_BND_SHIFT 19
+#define NFIFOENTRY_BND_MASK (1 << NFIFOENTRY_BND_SHIFT)
+#define NFIFOENTRY_BND (1 << NFIFOENTRY_BND_SHIFT)
+
+#define NFIFOENTRY_PTYPE_SHIFT 16
+#define NFIFOENTRY_PTYPE_MASK (0x7 << NFIFOENTRY_PTYPE_SHIFT)
+
+#define NFIFOENTRY_PTYPE_ZEROS (0x0 << NFIFOENTRY_PTYPE_SHIFT)
+#define NFIFOENTRY_PTYPE_RND_NOZEROS (0x1 << NFIFOENTRY_PTYPE_SHIFT)
+#define NFIFOENTRY_PTYPE_INCREMENT (0x2 << NFIFOENTRY_PTYPE_SHIFT)
+#define NFIFOENTRY_PTYPE_RND (0x3 << NFIFOENTRY_PTYPE_SHIFT)
+#define NFIFOENTRY_PTYPE_ZEROS_NZ (0x4 << NFIFOENTRY_PTYPE_SHIFT)
+#define NFIFOENTRY_PTYPE_RND_NZ_LZ (0x5 << NFIFOENTRY_PTYPE_SHIFT)
+#define NFIFOENTRY_PTYPE_N (0x6 << NFIFOENTRY_PTYPE_SHIFT)
+#define NFIFOENTRY_PTYPE_RND_NZ_N (0x7 << NFIFOENTRY_PTYPE_SHIFT)
+
+#define NFIFOENTRY_OC_SHIFT 15
+#define NFIFOENTRY_OC_MASK (1 << NFIFOENTRY_OC_SHIFT)
+#define NFIFOENTRY_OC (1 << NFIFOENTRY_OC_SHIFT)
+
+#define NFIFOENTRY_AST_SHIFT 14
+#define NFIFOENTRY_AST_MASK (1 << NFIFOENTRY_OC_SHIFT)
+#define NFIFOENTRY_AST (1 << NFIFOENTRY_OC_SHIFT)
+
+#define NFIFOENTRY_BM_SHIFT 11
+#define NFIFOENTRY_BM_MASK (1 << NFIFOENTRY_BM_SHIFT)
+#define NFIFOENTRY_BM (1 << NFIFOENTRY_BM_SHIFT)
+
+#define NFIFOENTRY_PS_SHIFT 10
+#define NFIFOENTRY_PS_MASK (1 << NFIFOENTRY_PS_SHIFT)
+#define NFIFOENTRY_PS (1 << NFIFOENTRY_PS_SHIFT)
+
+
+#define NFIFOENTRY_DLEN_SHIFT 0
+#define NFIFOENTRY_DLEN_MASK (0xFFF << NFIFOENTRY_DLEN_SHIFT)
+
+#define NFIFOENTRY_PLEN_SHIFT 0
+#define NFIFOENTRY_PLEN_MASK (0xFF << NFIFOENTRY_PLEN_SHIFT)
+
+/*
+ * PDB internal definitions
+ */
+
+/* IPSec ESP CBC Encap/Decap Options */
+#define PDBOPTS_ESPCBC_ARSNONE 0x00 /* no antireplay window */
+#define PDBOPTS_ESPCBC_ARS32 0x40 /* 32-entry antireplay window */
+#define PDBOPTS_ESPCBC_ARS64 0xc0 /* 64-entry antireplay window */
+#define PDBOPTS_ESPCBC_IVSRC 0x20 /* IV comes from internal random gen */
+#define PDBOPTS_ESPCBC_ESN 0x10 /* extended sequence included */
+#define PDBOPTS_ESPCBC_OUTFMT 0x08 /* output only decapsulation (decap) */
+#define PDBOPTS_ESPCBC_IPHDRSRC 0x08 /* IP header comes from PDB (encap) */
+#define PDBOPTS_ESPCBC_INCIPHDR 0x04 /* Prepend IP header to output frame */
+#define PDBOPTS_ESPCBC_IPVSN 0x02 /* process IPv6 header */
+#define PDBOPTS_ESPCBC_TUNNEL 0x01 /* tunnel mode next-header byte */
+
+#endif /* DESC_H */
diff --git a/drivers/crypto/caam/desc_constr.h b/drivers/crypto/caam/desc_constr.h
new file mode 100644
index 000000000000..46915800c26f
--- /dev/null
+++ b/drivers/crypto/caam/desc_constr.h
@@ -0,0 +1,205 @@
+/*
+ * caam descriptor construction helper functions
+ *
+ * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ */
+
+#include "desc.h"
+
+#define IMMEDIATE (1 << 23)
+#define CAAM_CMD_SZ sizeof(u32)
+#define CAAM_PTR_SZ sizeof(dma_addr_t)
+#define CAAM_DESC_BYTES_MAX (CAAM_CMD_SZ * 64)
+
+#ifdef DEBUG
+#define PRINT_POS do { printk(KERN_DEBUG "%02d: %s\n", desc_len(desc),\
+ &__func__[sizeof("append")]); } while (0)
+#else
+#define PRINT_POS
+#endif
+
+#define DISABLE_AUTO_INFO_FIFO (IMMEDIATE | LDST_CLASS_DECO | \
+ LDST_SRCDST_WORD_DECOCTRL | \
+ (LDOFF_DISABLE_AUTO_NFIFO << LDST_OFFSET_SHIFT))
+#define ENABLE_AUTO_INFO_FIFO (IMMEDIATE | LDST_CLASS_DECO | \
+ LDST_SRCDST_WORD_DECOCTRL | \
+ (LDOFF_ENABLE_AUTO_NFIFO << LDST_OFFSET_SHIFT))
+
+static inline int desc_len(u32 *desc)
+{
+ return *desc & HDR_DESCLEN_MASK;
+}
+
+static inline int desc_bytes(void *desc)
+{
+ return desc_len(desc) * CAAM_CMD_SZ;
+}
+
+static inline u32 *desc_end(u32 *desc)
+{
+ return desc + desc_len(desc);
+}
+
+static inline void *sh_desc_pdb(u32 *desc)
+{
+ return desc + 1;
+}
+
+static inline void init_desc(u32 *desc, u32 options)
+{
+ *desc = options | HDR_ONE | 1;
+}
+
+static inline void init_sh_desc(u32 *desc, u32 options)
+{
+ PRINT_POS;
+ init_desc(desc, CMD_SHARED_DESC_HDR | options);
+}
+
+static inline void init_sh_desc_pdb(u32 *desc, u32 options, size_t pdb_bytes)
+{
+ u32 pdb_len = pdb_bytes / CAAM_CMD_SZ + 1;
+
+ init_sh_desc(desc, ((pdb_len << HDR_START_IDX_SHIFT) + pdb_len) |
+ options);
+}
+
+static inline void init_job_desc(u32 *desc, u32 options)
+{
+ init_desc(desc, CMD_DESC_HDR | options);
+}
+
+static inline void append_ptr(u32 *desc, dma_addr_t ptr)
+{
+ dma_addr_t *offset = (dma_addr_t *)desc_end(desc);
+
+ *offset = ptr;
+
+ (*desc) += CAAM_PTR_SZ / CAAM_CMD_SZ;
+}
+
+static inline void init_job_desc_shared(u32 *desc, dma_addr_t ptr, int len,
+ u32 options)
+{
+ PRINT_POS;
+ init_job_desc(desc, HDR_SHARED | options |
+ (len << HDR_START_IDX_SHIFT));
+ append_ptr(desc, ptr);
+}
+
+static inline void append_data(u32 *desc, void *data, int len)
+{
+ u32 *offset = desc_end(desc);
+
+ if (len) /* avoid sparse warning: memcpy with byte count of 0 */
+ memcpy(offset, data, len);
+
+ (*desc) += (len + CAAM_CMD_SZ - 1) / CAAM_CMD_SZ;
+}
+
+static inline void append_cmd(u32 *desc, u32 command)
+{
+ u32 *cmd = desc_end(desc);
+
+ *cmd = command;
+
+ (*desc)++;
+}
+
+static inline void append_cmd_ptr(u32 *desc, dma_addr_t ptr, int len,
+ u32 command)
+{
+ append_cmd(desc, command | len);
+ append_ptr(desc, ptr);
+}
+
+static inline void append_cmd_data(u32 *desc, void *data, int len,
+ u32 command)
+{
+ append_cmd(desc, command | IMMEDIATE | len);
+ append_data(desc, data, len);
+}
+
+static inline u32 *append_jump(u32 *desc, u32 options)
+{
+ u32 *cmd = desc_end(desc);
+
+ PRINT_POS;
+ append_cmd(desc, CMD_JUMP | options);
+
+ return cmd;
+}
+
+static inline void set_jump_tgt_here(u32 *desc, u32 *jump_cmd)
+{
+ *jump_cmd = *jump_cmd | (desc_len(desc) - (jump_cmd - desc));
+}
+
+#define APPEND_CMD(cmd, op) \
+static inline void append_##cmd(u32 *desc, u32 options) \
+{ \
+ PRINT_POS; \
+ append_cmd(desc, CMD_##op | options); \
+}
+APPEND_CMD(operation, OPERATION)
+APPEND_CMD(move, MOVE)
+
+#define APPEND_CMD_LEN(cmd, op) \
+static inline void append_##cmd(u32 *desc, unsigned int len, u32 options) \
+{ \
+ PRINT_POS; \
+ append_cmd(desc, CMD_##op | len | options); \
+}
+APPEND_CMD_LEN(seq_store, SEQ_STORE)
+APPEND_CMD_LEN(seq_fifo_load, SEQ_FIFO_LOAD)
+APPEND_CMD_LEN(seq_fifo_store, SEQ_FIFO_STORE)
+
+#define APPEND_CMD_PTR(cmd, op) \
+static inline void append_##cmd(u32 *desc, dma_addr_t ptr, unsigned int len, \
+ u32 options) \
+{ \
+ PRINT_POS; \
+ append_cmd_ptr(desc, ptr, len, CMD_##op | options); \
+}
+APPEND_CMD_PTR(key, KEY)
+APPEND_CMD_PTR(seq_in_ptr, SEQ_IN_PTR)
+APPEND_CMD_PTR(seq_out_ptr, SEQ_OUT_PTR)
+APPEND_CMD_PTR(load, LOAD)
+APPEND_CMD_PTR(store, STORE)
+APPEND_CMD_PTR(fifo_load, FIFO_LOAD)
+APPEND_CMD_PTR(fifo_store, FIFO_STORE)
+
+#define APPEND_CMD_PTR_TO_IMM(cmd, op) \
+static inline void append_##cmd##_as_imm(u32 *desc, void *data, \
+ unsigned int len, u32 options) \
+{ \
+ PRINT_POS; \
+ append_cmd_data(desc, data, len, CMD_##op | options); \
+}
+APPEND_CMD_PTR_TO_IMM(load, LOAD);
+APPEND_CMD_PTR_TO_IMM(fifo_load, FIFO_LOAD);
+
+/*
+ * 2nd variant for commands whose specified immediate length differs
+ * from length of immediate data provided, e.g., split keys
+ */
+#define APPEND_CMD_PTR_TO_IMM2(cmd, op) \
+static inline void append_##cmd##_as_imm(u32 *desc, void *data, \
+ unsigned int data_len, \
+ unsigned int len, u32 options) \
+{ \
+ PRINT_POS; \
+ append_cmd(desc, CMD_##op | IMMEDIATE | len | options); \
+ append_data(desc, data, data_len); \
+}
+APPEND_CMD_PTR_TO_IMM2(key, KEY);
+
+#define APPEND_CMD_RAW_IMM(cmd, op, type) \
+static inline void append_##cmd##_imm_##type(u32 *desc, type immediate, \
+ u32 options) \
+{ \
+ PRINT_POS; \
+ append_cmd(desc, CMD_##op | IMMEDIATE | options | sizeof(type)); \
+ append_cmd(desc, immediate); \
+}
+APPEND_CMD_RAW_IMM(load, LOAD, u32);
diff --git a/drivers/crypto/caam/error.c b/drivers/crypto/caam/error.c
new file mode 100644
index 000000000000..7e2d54bffad6
--- /dev/null
+++ b/drivers/crypto/caam/error.c
@@ -0,0 +1,248 @@
+/*
+ * CAAM Error Reporting
+ *
+ * Copyright 2009-2011 Freescale Semiconductor, Inc.
+ */
+
+#include "compat.h"
+#include "regs.h"
+#include "intern.h"
+#include "desc.h"
+#include "jr.h"
+#include "error.h"
+
+#define SPRINTFCAT(str, format, param, max_alloc) \
+{ \
+ char *tmp; \
+ \
+ tmp = kmalloc(sizeof(format) + max_alloc, GFP_ATOMIC); \
+ sprintf(tmp, format, param); \
+ strcat(str, tmp); \
+ kfree(tmp); \
+}
+
+static void report_jump_idx(u32 status, char *outstr)
+{
+ u8 idx = (status & JRSTA_DECOERR_INDEX_MASK) >>
+ JRSTA_DECOERR_INDEX_SHIFT;
+
+ if (status & JRSTA_DECOERR_JUMP)
+ strcat(outstr, "jump tgt desc idx ");
+ else
+ strcat(outstr, "desc idx ");
+
+ SPRINTFCAT(outstr, "%d: ", idx, sizeof("255"));
+}
+
+static void report_ccb_status(u32 status, char *outstr)
+{
+ char *cha_id_list[] = {
+ "",
+ "AES",
+ "DES, 3DES",
+ "ARC4",
+ "MD5, SHA-1, SH-224, SHA-256, SHA-384, SHA-512",
+ "RNG",
+ "SNOW f8",
+ "Kasumi f8, f9",
+ "All Public Key Algorithms",
+ "CRC",
+ "SNOW f9",
+ };
+ char *err_id_list[] = {
+ "None. No error.",
+ "Mode error.",
+ "Data size error.",
+ "Key size error.",
+ "PKHA A memory size error.",
+ "PKHA B memory size error.",
+ "Data arrived out of sequence error.",
+ "PKHA divide-by-zero error.",
+ "PKHA modulus even error.",
+ "DES key parity error.",
+ "ICV check failed.",
+ "Hardware error.",
+ "Unsupported CCM AAD size.",
+ "Class 1 CHA is not reset",
+ "Invalid CHA combination was selected",
+ "Invalid CHA selected.",
+ };
+ u8 cha_id = (status & JRSTA_CCBERR_CHAID_MASK) >>
+ JRSTA_CCBERR_CHAID_SHIFT;
+ u8 err_id = status & JRSTA_CCBERR_ERRID_MASK;
+
+ report_jump_idx(status, outstr);
+
+ if (cha_id < ARRAY_SIZE(cha_id_list)) {
+ SPRINTFCAT(outstr, "%s: ", cha_id_list[cha_id],
+ strlen(cha_id_list[cha_id]));
+ } else {
+ SPRINTFCAT(outstr, "unidentified cha_id value 0x%02x: ",
+ cha_id, sizeof("ff"));
+ }
+
+ if (err_id < ARRAY_SIZE(err_id_list)) {
+ SPRINTFCAT(outstr, "%s", err_id_list[err_id],
+ strlen(err_id_list[err_id]));
+ } else {
+ SPRINTFCAT(outstr, "unidentified err_id value 0x%02x",
+ err_id, sizeof("ff"));
+ }
+}
+
+static void report_jump_status(u32 status, char *outstr)
+{
+ SPRINTFCAT(outstr, "%s() not implemented", __func__, sizeof(__func__));
+}
+
+static void report_deco_status(u32 status, char *outstr)
+{
+ const struct {
+ u8 value;
+ char *error_text;
+ } desc_error_list[] = {
+ { 0x00, "None. No error." },
+ { 0x01, "SGT Length Error. The descriptor is trying to read "
+ "more data than is contained in the SGT table." },
+ { 0x02, "Reserved." },
+ { 0x03, "Job Ring Control Error. There is a bad value in the "
+ "Job Ring Control register." },
+ { 0x04, "Invalid Descriptor Command. The Descriptor Command "
+ "field is invalid." },
+ { 0x05, "Reserved." },
+ { 0x06, "Invalid KEY Command" },
+ { 0x07, "Invalid LOAD Command" },
+ { 0x08, "Invalid STORE Command" },
+ { 0x09, "Invalid OPERATION Command" },
+ { 0x0A, "Invalid FIFO LOAD Command" },
+ { 0x0B, "Invalid FIFO STORE Command" },
+ { 0x0C, "Invalid MOVE Command" },
+ { 0x0D, "Invalid JUMP Command. A nonlocal JUMP Command is "
+ "invalid because the target is not a Job Header "
+ "Command, or the jump is from a Trusted Descriptor to "
+ "a Job Descriptor, or because the target Descriptor "
+ "contains a Shared Descriptor." },
+ { 0x0E, "Invalid MATH Command" },
+ { 0x0F, "Invalid SIGNATURE Command" },
+ { 0x10, "Invalid Sequence Command. A SEQ IN PTR OR SEQ OUT PTR "
+ "Command is invalid or a SEQ KEY, SEQ LOAD, SEQ FIFO "
+ "LOAD, or SEQ FIFO STORE decremented the input or "
+ "output sequence length below 0. This error may result "
+ "if a built-in PROTOCOL Command has encountered a "
+ "malformed PDU." },
+ { 0x11, "Skip data type invalid. The type must be 0xE or 0xF."},
+ { 0x12, "Shared Descriptor Header Error" },
+ { 0x13, "Header Error. Invalid length or parity, or certain "
+ "other problems." },
+ { 0x14, "Burster Error. Burster has gotten to an illegal "
+ "state" },
+ { 0x15, "Context Register Length Error. The descriptor is "
+ "trying to read or write past the end of the Context "
+ "Register. A SEQ LOAD or SEQ STORE with the VLF bit "
+ "set was executed with too large a length in the "
+ "variable length register (VSOL for SEQ STORE or VSIL "
+ "for SEQ LOAD)." },
+ { 0x16, "DMA Error" },
+ { 0x17, "Reserved." },
+ { 0x1A, "Job failed due to JR reset" },
+ { 0x1B, "Job failed due to Fail Mode" },
+ { 0x1C, "DECO Watchdog timer timeout error" },
+ { 0x1D, "DECO tried to copy a key from another DECO but the "
+ "other DECO's Key Registers were locked" },
+ { 0x1E, "DECO attempted to copy data from a DECO that had an "
+ "unmasked Descriptor error" },
+ { 0x1F, "LIODN error. DECO was trying to share from itself or "
+ "from another DECO but the two Non-SEQ LIODN values "
+ "didn't match or the 'shared from' DECO's Descriptor "
+ "required that the SEQ LIODNs be the same and they "
+ "aren't." },
+ { 0x20, "DECO has completed a reset initiated via the DRR "
+ "register" },
+ { 0x21, "Nonce error. When using EKT (CCM) key encryption "
+ "option in the FIFO STORE Command, the Nonce counter "
+ "reached its maximum value and this encryption mode "
+ "can no longer be used." },
+ { 0x22, "Meta data is too large (> 511 bytes) for TLS decap "
+ "(input frame; block ciphers) and IPsec decap (output "
+ "frame, when doing the next header byte update) and "
+ "DCRC (output frame)." },
+ { 0x80, "DNR (do not run) error" },
+ { 0x81, "undefined protocol command" },
+ { 0x82, "invalid setting in PDB" },
+ { 0x83, "Anti-replay LATE error" },
+ { 0x84, "Anti-replay REPLAY error" },
+ { 0x85, "Sequence number overflow" },
+ { 0x86, "Sigver invalid signature" },
+ { 0x87, "DSA Sign Illegal test descriptor" },
+ { 0x88, "Protocol Format Error - A protocol has seen an error "
+ "in the format of data received. When running RSA, "
+ "this means that formatting with random padding was "
+ "used, and did not follow the form: 0x00, 0x02, 8-to-N "
+ "bytes of non-zero pad, 0x00, F data." },
+ { 0x89, "Protocol Size Error - A protocol has seen an error in "
+ "size. When running RSA, pdb size N < (size of F) when "
+ "no formatting is used; or pdb size N < (F + 11) when "
+ "formatting is used." },
+ { 0xC1, "Blob Command error: Undefined mode" },
+ { 0xC2, "Blob Command error: Secure Memory Blob mode error" },
+ { 0xC4, "Blob Command error: Black Blob key or input size "
+ "error" },
+ { 0xC5, "Blob Command error: Invalid key destination" },
+ { 0xC8, "Blob Command error: Trusted/Secure mode error" },
+ { 0xF0, "IPsec TTL or hop limit field either came in as 0, "
+ "or was decremented to 0" },
+ { 0xF1, "3GPP HFN matches or exceeds the Threshold" },
+ };
+ u8 desc_error = status & JRSTA_DECOERR_ERROR_MASK;
+ int i;
+
+ report_jump_idx(status, outstr);
+
+ for (i = 0; i < ARRAY_SIZE(desc_error_list); i++)
+ if (desc_error_list[i].value == desc_error)
+ break;
+
+ if (i != ARRAY_SIZE(desc_error_list) && desc_error_list[i].error_text) {
+ SPRINTFCAT(outstr, "%s", desc_error_list[i].error_text,
+ strlen(desc_error_list[i].error_text));
+ } else {
+ SPRINTFCAT(outstr, "unidentified error value 0x%02x",
+ desc_error, sizeof("ff"));
+ }
+}
+
+static void report_jr_status(u32 status, char *outstr)
+{
+ SPRINTFCAT(outstr, "%s() not implemented", __func__, sizeof(__func__));
+}
+
+static void report_cond_code_status(u32 status, char *outstr)
+{
+ SPRINTFCAT(outstr, "%s() not implemented", __func__, sizeof(__func__));
+}
+
+char *caam_jr_strstatus(char *outstr, u32 status)
+{
+ struct stat_src {
+ void (*report_ssed)(u32 status, char *outstr);
+ char *error;
+ } status_src[] = {
+ { NULL, "No error" },
+ { NULL, NULL },
+ { report_ccb_status, "CCB" },
+ { report_jump_status, "Jump" },
+ { report_deco_status, "DECO" },
+ { NULL, NULL },
+ { report_jr_status, "Job Ring" },
+ { report_cond_code_status, "Condition Code" },
+ };
+ u32 ssrc = status >> JRSTA_SSRC_SHIFT;
+
+ sprintf(outstr, "%s: ", status_src[ssrc].error);
+
+ if (status_src[ssrc].report_ssed)
+ status_src[ssrc].report_ssed(status, outstr);
+
+ return outstr;
+}
+EXPORT_SYMBOL(caam_jr_strstatus);
diff --git a/drivers/crypto/caam/error.h b/drivers/crypto/caam/error.h
new file mode 100644
index 000000000000..02c7baa1748e
--- /dev/null
+++ b/drivers/crypto/caam/error.h
@@ -0,0 +1,11 @@
+/*
+ * CAAM Error Reporting code header
+ *
+ * Copyright 2009-2011 Freescale Semiconductor, Inc.
+ */
+
+#ifndef CAAM_ERROR_H
+#define CAAM_ERROR_H
+#define CAAM_ERROR_STR_MAX 302
+extern char *caam_jr_strstatus(char *outstr, u32 status);
+#endif /* CAAM_ERROR_H */
diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h
new file mode 100644
index 000000000000..a34be01b0b29
--- /dev/null
+++ b/drivers/crypto/caam/intern.h
@@ -0,0 +1,113 @@
+/*
+ * CAAM/SEC 4.x driver backend
+ * Private/internal definitions between modules
+ *
+ * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ *
+ */
+
+#ifndef INTERN_H
+#define INTERN_H
+
+#define JOBR_UNASSIGNED 0
+#define JOBR_ASSIGNED 1
+
+/* Currently comes from Kconfig param as a ^2 (driver-required) */
+#define JOBR_DEPTH (1 << CONFIG_CRYPTO_DEV_FSL_CAAM_RINGSIZE)
+
+/* Kconfig params for interrupt coalescing if selected (else zero) */
+#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_INTC
+#define JOBR_INTC JRCFG_ICEN
+#define JOBR_INTC_TIME_THLD CONFIG_CRYPTO_DEV_FSL_CAAM_INTC_TIME_THLD
+#define JOBR_INTC_COUNT_THLD CONFIG_CRYPTO_DEV_FSL_CAAM_INTC_COUNT_THLD
+#else
+#define JOBR_INTC 0
+#define JOBR_INTC_TIME_THLD 0
+#define JOBR_INTC_COUNT_THLD 0
+#endif
+
+/*
+ * Storage for tracking each in-process entry moving across a ring
+ * Each entry on an output ring needs one of these
+ */
+struct caam_jrentry_info {
+ void (*callbk)(struct device *dev, u32 *desc, u32 status, void *arg);
+ void *cbkarg; /* Argument per ring entry */
+ u32 *desc_addr_virt; /* Stored virt addr for postprocessing */
+ dma_addr_t desc_addr_dma; /* Stored bus addr for done matching */
+ u32 desc_size; /* Stored size for postprocessing, header derived */
+};
+
+/* Private sub-storage for a single JobR */
+struct caam_drv_private_jr {
+ struct device *parentdev; /* points back to controller dev */
+ int ridx;
+ struct caam_job_ring __iomem *rregs; /* JobR's register space */
+ struct tasklet_struct irqtask[NR_CPUS];
+ int irq; /* One per queue */
+ int assign; /* busy/free */
+
+ /* Job ring info */
+ int ringsize; /* Size of rings (assume input = output) */
+ struct caam_jrentry_info *entinfo; /* Alloc'ed 1 per ring entry */
+ spinlock_t inplock ____cacheline_aligned; /* Input ring index lock */
+ int inp_ring_write_index; /* Input index "tail" */
+ int head; /* entinfo (s/w ring) head index */
+ dma_addr_t *inpring; /* Base of input ring, alloc DMA-safe */
+ spinlock_t outlock ____cacheline_aligned; /* Output ring index lock */
+ int out_ring_read_index; /* Output index "tail" */
+ int tail; /* entinfo (s/w ring) tail index */
+ struct jr_outentry *outring; /* Base of output ring, DMA-safe */
+};
+
+/*
+ * Driver-private storage for a single CAAM block instance
+ */
+struct caam_drv_private {
+
+ struct device *dev;
+ struct device **jrdev; /* Alloc'ed array per sub-device */
+ spinlock_t jr_alloc_lock;
+ struct platform_device *pdev;
+
+ /* Physical-presence section */
+ struct caam_ctrl *ctrl; /* controller region */
+ struct caam_deco **deco; /* DECO/CCB views */
+ struct caam_assurance *ac;
+ struct caam_queue_if *qi; /* QI control region */
+
+ /*
+ * Detected geometry block. Filled in from device tree if powerpc,
+ * or from register-based version detection code
+ */
+ u8 total_jobrs; /* Total Job Rings in device */
+ u8 qi_present; /* Nonzero if QI present in device */
+ int secvio_irq; /* Security violation interrupt number */
+
+ /* which jr allocated to scatterlist crypto */
+ atomic_t tfm_count ____cacheline_aligned;
+ int num_jrs_for_algapi;
+ struct device **algapi_jr;
+ /* list of registered crypto algorithms (mk generic context handle?) */
+ struct list_head alg_list;
+
+ /*
+ * debugfs entries for developer view into driver/device
+ * variables at runtime.
+ */
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *dfs_root;
+ struct dentry *ctl; /* controller dir */
+ struct dentry *ctl_rq_dequeued, *ctl_ob_enc_req, *ctl_ib_dec_req;
+ struct dentry *ctl_ob_enc_bytes, *ctl_ob_prot_bytes;
+ struct dentry *ctl_ib_dec_bytes, *ctl_ib_valid_bytes;
+ struct dentry *ctl_faultaddr, *ctl_faultdetail, *ctl_faultstatus;
+
+ struct debugfs_blob_wrapper ctl_kek_wrap, ctl_tkek_wrap, ctl_tdsk_wrap;
+ struct dentry *ctl_kek, *ctl_tkek, *ctl_tdsk;
+#endif
+};
+
+void caam_jr_algapi_init(struct device *dev);
+void caam_jr_algapi_remove(struct device *dev);
+#endif /* INTERN_H */
diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c
new file mode 100644
index 000000000000..340fa322c0f0
--- /dev/null
+++ b/drivers/crypto/caam/jr.c
@@ -0,0 +1,517 @@
+/*
+ * CAAM/SEC 4.x transport/backend driver
+ * JobR backend functionality
+ *
+ * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ */
+
+#include "compat.h"
+#include "regs.h"
+#include "jr.h"
+#include "desc.h"
+#include "intern.h"
+
+/* Main per-ring interrupt handler */
+static irqreturn_t caam_jr_interrupt(int irq, void *st_dev)
+{
+ struct device *dev = st_dev;
+ struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
+ u32 irqstate;
+
+ /*
+ * Check the output ring for ready responses, kick
+ * tasklet if jobs done.
+ */
+ irqstate = rd_reg32(&jrp->rregs->jrintstatus);
+ if (!irqstate)
+ return IRQ_NONE;
+
+ /*
+ * If JobR error, we got more development work to do
+ * Flag a bug now, but we really need to shut down and
+ * restart the queue (and fix code).
+ */
+ if (irqstate & JRINT_JR_ERROR) {
+ dev_err(dev, "job ring error: irqstate: %08x\n", irqstate);
+ BUG();
+ }
+
+ /* mask valid interrupts */
+ setbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK);
+
+ /* Have valid interrupt at this point, just ACK and trigger */
+ wr_reg32(&jrp->rregs->jrintstatus, irqstate);
+
+ preempt_disable();
+ tasklet_schedule(&jrp->irqtask[smp_processor_id()]);
+ preempt_enable();
+
+ return IRQ_HANDLED;
+}
+
+/* Deferred service handler, run as interrupt-fired tasklet */
+static void caam_jr_dequeue(unsigned long devarg)
+{
+ int hw_idx, sw_idx, i, head, tail;
+ struct device *dev = (struct device *)devarg;
+ struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
+ void (*usercall)(struct device *dev, u32 *desc, u32 status, void *arg);
+ u32 *userdesc, userstatus;
+ void *userarg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&jrp->outlock, flags);
+
+ head = ACCESS_ONCE(jrp->head);
+ sw_idx = tail = jrp->tail;
+
+ while (CIRC_CNT(head, tail, JOBR_DEPTH) >= 1 &&
+ rd_reg32(&jrp->rregs->outring_used)) {
+
+ hw_idx = jrp->out_ring_read_index;
+ for (i = 0; CIRC_CNT(head, tail + i, JOBR_DEPTH) >= 1; i++) {
+ sw_idx = (tail + i) & (JOBR_DEPTH - 1);
+
+ smp_read_barrier_depends();
+
+ if (jrp->outring[hw_idx].desc ==
+ jrp->entinfo[sw_idx].desc_addr_dma)
+ break; /* found */
+ }
+ /* we should never fail to find a matching descriptor */
+ BUG_ON(CIRC_CNT(head, tail + i, JOBR_DEPTH) <= 0);
+
+ /* Unmap just-run descriptor so we can post-process */
+ dma_unmap_single(dev, jrp->outring[hw_idx].desc,
+ jrp->entinfo[sw_idx].desc_size,
+ DMA_TO_DEVICE);
+
+ /* mark completed, avoid matching on a recycled desc addr */
+ jrp->entinfo[sw_idx].desc_addr_dma = 0;
+
+ /* Stash callback params for use outside of lock */
+ usercall = jrp->entinfo[sw_idx].callbk;
+ userarg = jrp->entinfo[sw_idx].cbkarg;
+ userdesc = jrp->entinfo[sw_idx].desc_addr_virt;
+ userstatus = jrp->outring[hw_idx].jrstatus;
+
+ smp_mb();
+
+ jrp->out_ring_read_index = (jrp->out_ring_read_index + 1) &
+ (JOBR_DEPTH - 1);
+
+ /*
+ * if this job completed out-of-order, do not increment
+ * the tail. Otherwise, increment tail by 1 plus the
+ * number of subsequent jobs already completed out-of-order
+ */
+ if (sw_idx == tail) {
+ do {
+ tail = (tail + 1) & (JOBR_DEPTH - 1);
+ smp_read_barrier_depends();
+ } while (CIRC_CNT(head, tail, JOBR_DEPTH) >= 1 &&
+ jrp->entinfo[tail].desc_addr_dma == 0);
+
+ jrp->tail = tail;
+ }
+
+ /* set done */
+ wr_reg32(&jrp->rregs->outring_rmvd, 1);
+
+ spin_unlock_irqrestore(&jrp->outlock, flags);
+
+ /* Finally, execute user's callback */
+ usercall(dev, userdesc, userstatus, userarg);
+
+ spin_lock_irqsave(&jrp->outlock, flags);
+
+ head = ACCESS_ONCE(jrp->head);
+ sw_idx = tail = jrp->tail;
+ }
+
+ spin_unlock_irqrestore(&jrp->outlock, flags);
+
+ /* reenable / unmask IRQs */
+ clrbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK);
+}
+
+/**
+ * caam_jr_register() - Alloc a ring for someone to use as needed. Returns
+ * an ordinal of the rings allocated, else returns -ENODEV if no rings
+ * are available.
+ * @ctrldev: points to the controller level dev (parent) that
+ * owns rings available for use.
+ * @dev: points to where a pointer to the newly allocated queue's
+ * dev can be written to if successful.
+ **/
+int caam_jr_register(struct device *ctrldev, struct device **rdev)
+{
+ struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev);
+ struct caam_drv_private_jr *jrpriv = NULL;
+ unsigned long flags;
+ int ring;
+
+ /* Lock, if free ring - assign, unlock */
+ spin_lock_irqsave(&ctrlpriv->jr_alloc_lock, flags);
+ for (ring = 0; ring < ctrlpriv->total_jobrs; ring++) {
+ jrpriv = dev_get_drvdata(ctrlpriv->jrdev[ring]);
+ if (jrpriv->assign == JOBR_UNASSIGNED) {
+ jrpriv->assign = JOBR_ASSIGNED;
+ *rdev = ctrlpriv->jrdev[ring];
+ spin_unlock_irqrestore(&ctrlpriv->jr_alloc_lock, flags);
+ return ring;
+ }
+ }
+
+ /* If assigned, write dev where caller needs it */
+ spin_unlock_irqrestore(&ctrlpriv->jr_alloc_lock, flags);
+ *rdev = NULL;
+
+ return -ENODEV;
+}
+EXPORT_SYMBOL(caam_jr_register);
+
+/**
+ * caam_jr_deregister() - Deregister an API and release the queue.
+ * Returns 0 if OK, -EBUSY if queue still contains pending entries
+ * or unprocessed results at the time of the call
+ * @dev - points to the dev that identifies the queue to
+ * be released.
+ **/
+int caam_jr_deregister(struct device *rdev)
+{
+ struct caam_drv_private_jr *jrpriv = dev_get_drvdata(rdev);
+ struct caam_drv_private *ctrlpriv;
+ unsigned long flags;
+
+ /* Get the owning controller's private space */
+ ctrlpriv = dev_get_drvdata(jrpriv->parentdev);
+
+ /*
+ * Make sure ring empty before release
+ */
+ if (rd_reg32(&jrpriv->rregs->outring_used) ||
+ (rd_reg32(&jrpriv->rregs->inpring_avail) != JOBR_DEPTH))
+ return -EBUSY;
+
+ /* Release ring */
+ spin_lock_irqsave(&ctrlpriv->jr_alloc_lock, flags);
+ jrpriv->assign = JOBR_UNASSIGNED;
+ spin_unlock_irqrestore(&ctrlpriv->jr_alloc_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(caam_jr_deregister);
+
+/**
+ * caam_jr_enqueue() - Enqueue a job descriptor head. Returns 0 if OK,
+ * -EBUSY if the queue is full, -EIO if it cannot map the caller's
+ * descriptor.
+ * @dev: device of the job ring to be used. This device should have
+ * been assigned prior by caam_jr_register().
+ * @desc: points to a job descriptor that execute our request. All
+ * descriptors (and all referenced data) must be in a DMAable
+ * region, and all data references must be physical addresses
+ * accessible to CAAM (i.e. within a PAMU window granted
+ * to it).
+ * @cbk: pointer to a callback function to be invoked upon completion
+ * of this request. This has the form:
+ * callback(struct device *dev, u32 *desc, u32 stat, void *arg)
+ * where:
+ * @dev: contains the job ring device that processed this
+ * response.
+ * @desc: descriptor that initiated the request, same as
+ * "desc" being argued to caam_jr_enqueue().
+ * @status: untranslated status received from CAAM. See the
+ * reference manual for a detailed description of
+ * error meaning, or see the JRSTA definitions in the
+ * register header file
+ * @areq: optional pointer to an argument passed with the
+ * original request
+ * @areq: optional pointer to a user argument for use at callback
+ * time.
+ **/
+int caam_jr_enqueue(struct device *dev, u32 *desc,
+ void (*cbk)(struct device *dev, u32 *desc,
+ u32 status, void *areq),
+ void *areq)
+{
+ struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
+ struct caam_jrentry_info *head_entry;
+ unsigned long flags;
+ int head, tail, desc_size;
+ dma_addr_t desc_dma;
+
+ desc_size = (*desc & HDR_JD_LENGTH_MASK) * sizeof(u32);
+ desc_dma = dma_map_single(dev, desc, desc_size, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, desc_dma)) {
+ dev_err(dev, "caam_jr_enqueue(): can't map jobdesc\n");
+ return -EIO;
+ }
+
+ spin_lock_irqsave(&jrp->inplock, flags);
+
+ head = jrp->head;
+ tail = ACCESS_ONCE(jrp->tail);
+
+ if (!rd_reg32(&jrp->rregs->inpring_avail) ||
+ CIRC_SPACE(head, tail, JOBR_DEPTH) <= 0) {
+ spin_unlock_irqrestore(&jrp->inplock, flags);
+ dma_unmap_single(dev, desc_dma, desc_size, DMA_TO_DEVICE);
+ return -EBUSY;
+ }
+
+ head_entry = &jrp->entinfo[head];
+ head_entry->desc_addr_virt = desc;
+ head_entry->desc_size = desc_size;
+ head_entry->callbk = (void *)cbk;
+ head_entry->cbkarg = areq;
+ head_entry->desc_addr_dma = desc_dma;
+
+ jrp->inpring[jrp->inp_ring_write_index] = desc_dma;
+
+ smp_wmb();
+
+ jrp->inp_ring_write_index = (jrp->inp_ring_write_index + 1) &
+ (JOBR_DEPTH - 1);
+ jrp->head = (head + 1) & (JOBR_DEPTH - 1);
+
+ wmb();
+
+ wr_reg32(&jrp->rregs->inpring_jobadd, 1);
+
+ spin_unlock_irqrestore(&jrp->inplock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(caam_jr_enqueue);
+
+static int caam_reset_hw_jr(struct device *dev)
+{
+ struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
+ unsigned int timeout = 100000;
+
+ /*
+ * mask interrupts since we are going to poll
+ * for reset completion status
+ */
+ setbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK);
+
+ /* initiate flush (required prior to reset) */
+ wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET);
+ while (((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) ==
+ JRINT_ERR_HALT_INPROGRESS) && --timeout)
+ cpu_relax();
+
+ if ((rd_reg32(&jrp->rregs->jrintstatus) & JRINT_ERR_HALT_MASK) !=
+ JRINT_ERR_HALT_COMPLETE || timeout == 0) {
+ dev_err(dev, "failed to flush job ring %d\n", jrp->ridx);
+ return -EIO;
+ }
+
+ /* initiate reset */
+ timeout = 100000;
+ wr_reg32(&jrp->rregs->jrcommand, JRCR_RESET);
+ while ((rd_reg32(&jrp->rregs->jrcommand) & JRCR_RESET) && --timeout)
+ cpu_relax();
+
+ if (timeout == 0) {
+ dev_err(dev, "failed to reset job ring %d\n", jrp->ridx);
+ return -EIO;
+ }
+
+ /* unmask interrupts */
+ clrbits32(&jrp->rregs->rconfig_lo, JRCFG_IMSK);
+
+ return 0;
+}
+
+/*
+ * Init JobR independent of platform property detection
+ */
+static int caam_jr_init(struct device *dev)
+{
+ struct caam_drv_private_jr *jrp;
+ dma_addr_t inpbusaddr, outbusaddr;
+ int i, error;
+
+ jrp = dev_get_drvdata(dev);
+
+ /* Connect job ring interrupt handler. */
+ for_each_possible_cpu(i)
+ tasklet_init(&jrp->irqtask[i], caam_jr_dequeue,
+ (unsigned long)dev);
+
+ error = request_irq(jrp->irq, caam_jr_interrupt, IRQF_SHARED,
+ "caam-jobr", dev);
+ if (error) {
+ dev_err(dev, "can't connect JobR %d interrupt (%d)\n",
+ jrp->ridx, jrp->irq);
+ irq_dispose_mapping(jrp->irq);
+ jrp->irq = 0;
+ return -EINVAL;
+ }
+
+ error = caam_reset_hw_jr(dev);
+ if (error)
+ return error;
+
+ jrp->inpring = kzalloc(sizeof(dma_addr_t) * JOBR_DEPTH,
+ GFP_KERNEL | GFP_DMA);
+ jrp->outring = kzalloc(sizeof(struct jr_outentry) *
+ JOBR_DEPTH, GFP_KERNEL | GFP_DMA);
+
+ jrp->entinfo = kzalloc(sizeof(struct caam_jrentry_info) * JOBR_DEPTH,
+ GFP_KERNEL);
+
+ if ((jrp->inpring == NULL) || (jrp->outring == NULL) ||
+ (jrp->entinfo == NULL)) {
+ dev_err(dev, "can't allocate job rings for %d\n",
+ jrp->ridx);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < JOBR_DEPTH; i++)
+ jrp->entinfo[i].desc_addr_dma = !0;
+
+ /* Setup rings */
+ inpbusaddr = dma_map_single(dev, jrp->inpring,
+ sizeof(u32 *) * JOBR_DEPTH,
+ DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(dev, inpbusaddr)) {
+ dev_err(dev, "caam_jr_init(): can't map input ring\n");
+ kfree(jrp->inpring);
+ kfree(jrp->outring);
+ kfree(jrp->entinfo);
+ return -EIO;
+ }
+
+ outbusaddr = dma_map_single(dev, jrp->outring,
+ sizeof(struct jr_outentry) * JOBR_DEPTH,
+ DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(dev, outbusaddr)) {
+ dev_err(dev, "caam_jr_init(): can't map output ring\n");
+ dma_unmap_single(dev, inpbusaddr,
+ sizeof(u32 *) * JOBR_DEPTH,
+ DMA_BIDIRECTIONAL);
+ kfree(jrp->inpring);
+ kfree(jrp->outring);
+ kfree(jrp->entinfo);
+ return -EIO;
+ }
+
+ jrp->inp_ring_write_index = 0;
+ jrp->out_ring_read_index = 0;
+ jrp->head = 0;
+ jrp->tail = 0;
+
+ wr_reg64(&jrp->rregs->inpring_base, inpbusaddr);
+ wr_reg64(&jrp->rregs->outring_base, outbusaddr);
+ wr_reg32(&jrp->rregs->inpring_size, JOBR_DEPTH);
+ wr_reg32(&jrp->rregs->outring_size, JOBR_DEPTH);
+
+ jrp->ringsize = JOBR_DEPTH;
+
+ spin_lock_init(&jrp->inplock);
+ spin_lock_init(&jrp->outlock);
+
+ /* Select interrupt coalescing parameters */
+ setbits32(&jrp->rregs->rconfig_lo, JOBR_INTC |
+ (JOBR_INTC_COUNT_THLD << JRCFG_ICDCT_SHIFT) |
+ (JOBR_INTC_TIME_THLD << JRCFG_ICTT_SHIFT));
+
+ jrp->assign = JOBR_UNASSIGNED;
+ return 0;
+}
+
+/*
+ * Shutdown JobR independent of platform property code
+ */
+int caam_jr_shutdown(struct device *dev)
+{
+ struct caam_drv_private_jr *jrp = dev_get_drvdata(dev);
+ dma_addr_t inpbusaddr, outbusaddr;
+ int ret, i;
+
+ ret = caam_reset_hw_jr(dev);
+
+ for_each_possible_cpu(i)
+ tasklet_kill(&jrp->irqtask[i]);
+
+ /* Release interrupt */
+ free_irq(jrp->irq, dev);
+
+ /* Free rings */
+ inpbusaddr = rd_reg64(&jrp->rregs->inpring_base);
+ outbusaddr = rd_reg64(&jrp->rregs->outring_base);
+ dma_unmap_single(dev, outbusaddr,
+ sizeof(struct jr_outentry) * JOBR_DEPTH,
+ DMA_BIDIRECTIONAL);
+ dma_unmap_single(dev, inpbusaddr, sizeof(u32 *) * JOBR_DEPTH,
+ DMA_BIDIRECTIONAL);
+ kfree(jrp->outring);
+ kfree(jrp->inpring);
+ kfree(jrp->entinfo);
+
+ return ret;
+}
+
+/*
+ * Probe routine for each detected JobR subsystem. It assumes that
+ * property detection was picked up externally.
+ */
+int caam_jr_probe(struct platform_device *pdev, struct device_node *np,
+ int ring)
+{
+ struct device *ctrldev, *jrdev;
+ struct platform_device *jr_pdev;
+ struct caam_drv_private *ctrlpriv;
+ struct caam_drv_private_jr *jrpriv;
+ u32 *jroffset;
+ int error;
+
+ ctrldev = &pdev->dev;
+ ctrlpriv = dev_get_drvdata(ctrldev);
+
+ jrpriv = kmalloc(sizeof(struct caam_drv_private_jr),
+ GFP_KERNEL);
+ if (jrpriv == NULL) {
+ dev_err(ctrldev, "can't alloc private mem for job ring %d\n",
+ ring);
+ return -ENOMEM;
+ }
+ jrpriv->parentdev = ctrldev; /* point back to parent */
+ jrpriv->ridx = ring; /* save ring identity relative to detection */
+
+ /*
+ * Derive a pointer to the detected JobRs regs
+ * Driver has already iomapped the entire space, we just
+ * need to add in the offset to this JobR. Don't know if I
+ * like this long-term, but it'll run
+ */
+ jroffset = (u32 *)of_get_property(np, "reg", NULL);
+ jrpriv->rregs = (struct caam_job_ring __iomem *)((void *)ctrlpriv->ctrl
+ + *jroffset);
+
+ /* Build a local dev for each detected queue */
+ jr_pdev = of_platform_device_create(np, NULL, ctrldev);
+ if (jr_pdev == NULL) {
+ kfree(jrpriv);
+ return -EINVAL;
+ }
+ jrdev = &jr_pdev->dev;
+ dev_set_drvdata(jrdev, jrpriv);
+ ctrlpriv->jrdev[ring] = jrdev;
+
+ /* Identify the interrupt */
+ jrpriv->irq = of_irq_to_resource(np, 0, NULL);
+
+ /* Now do the platform independent part */
+ error = caam_jr_init(jrdev); /* now turn on hardware */
+ if (error) {
+ kfree(jrpriv);
+ return error;
+ }
+
+ return error;
+}
diff --git a/drivers/crypto/caam/jr.h b/drivers/crypto/caam/jr.h
new file mode 100644
index 000000000000..c23df395b622
--- /dev/null
+++ b/drivers/crypto/caam/jr.h
@@ -0,0 +1,21 @@
+/*
+ * CAAM public-level include definitions for the JobR backend
+ *
+ * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ */
+
+#ifndef JR_H
+#define JR_H
+
+/* Prototypes for backend-level services exposed to APIs */
+int caam_jr_register(struct device *ctrldev, struct device **rdev);
+int caam_jr_deregister(struct device *rdev);
+int caam_jr_enqueue(struct device *dev, u32 *desc,
+ void (*cbk)(struct device *dev, u32 *desc, u32 status,
+ void *areq),
+ void *areq);
+
+extern int caam_jr_probe(struct platform_device *pdev, struct device_node *np,
+ int ring);
+extern int caam_jr_shutdown(struct device *dev);
+#endif /* JR_H */
diff --git a/drivers/crypto/caam/regs.h b/drivers/crypto/caam/regs.h
new file mode 100644
index 000000000000..aee394e39056
--- /dev/null
+++ b/drivers/crypto/caam/regs.h
@@ -0,0 +1,663 @@
+/*
+ * CAAM hardware register-level view
+ *
+ * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ */
+
+#ifndef REGS_H
+#define REGS_H
+
+#include <linux/types.h>
+#include <linux/io.h>
+
+/*
+ * Architecture-specific register access methods
+ *
+ * CAAM's bus-addressable registers are 64 bits internally.
+ * They have been wired to be safely accessible on 32-bit
+ * architectures, however. Registers were organized such
+ * that (a) they can be contained in 32 bits, (b) if not, then they
+ * can be treated as two 32-bit entities, or finally (c) if they
+ * must be treated as a single 64-bit value, then this can safely
+ * be done with two 32-bit cycles.
+ *
+ * For 32-bit operations on 64-bit values, CAAM follows the same
+ * 64-bit register access conventions as it's predecessors, in that
+ * writes are "triggered" by a write to the register at the numerically
+ * higher address, thus, a full 64-bit write cycle requires a write
+ * to the lower address, followed by a write to the higher address,
+ * which will latch/execute the write cycle.
+ *
+ * For example, let's assume a SW reset of CAAM through the master
+ * configuration register.
+ * - SWRST is in bit 31 of MCFG.
+ * - MCFG begins at base+0x0000.
+ * - Bits 63-32 are a 32-bit word at base+0x0000 (numerically-lower)
+ * - Bits 31-0 are a 32-bit word at base+0x0004 (numerically-higher)
+ *
+ * (and on Power, the convention is 0-31, 32-63, I know...)
+ *
+ * Assuming a 64-bit write to this MCFG to perform a software reset
+ * would then require a write of 0 to base+0x0000, followed by a
+ * write of 0x80000000 to base+0x0004, which would "execute" the
+ * reset.
+ *
+ * Of course, since MCFG 63-32 is all zero, we could cheat and simply
+ * write 0x8000000 to base+0x0004, and the reset would work fine.
+ * However, since CAAM does contain some write-and-read-intended
+ * 64-bit registers, this code defines 64-bit access methods for
+ * the sake of internal consistency and simplicity, and so that a
+ * clean transition to 64-bit is possible when it becomes necessary.
+ *
+ * There are limitations to this that the developer must recognize.
+ * 32-bit architectures cannot enforce an atomic-64 operation,
+ * Therefore:
+ *
+ * - On writes, since the HW is assumed to latch the cycle on the
+ * write of the higher-numeric-address word, then ordered
+ * writes work OK.
+ *
+ * - For reads, where a register contains a relevant value of more
+ * that 32 bits, the hardware employs logic to latch the other
+ * "half" of the data until read, ensuring an accurate value.
+ * This is of particular relevance when dealing with CAAM's
+ * performance counters.
+ *
+ */
+
+#ifdef __BIG_ENDIAN
+#define wr_reg32(reg, data) out_be32(reg, data)
+#define rd_reg32(reg) in_be32(reg)
+#ifdef CONFIG_64BIT
+#define wr_reg64(reg, data) out_be64(reg, data)
+#define rd_reg64(reg) in_be64(reg)
+#endif
+#else
+#ifdef __LITTLE_ENDIAN
+#define wr_reg32(reg, data) __raw_writel(reg, data)
+#define rd_reg32(reg) __raw_readl(reg)
+#ifdef CONFIG_64BIT
+#define wr_reg64(reg, data) __raw_writeq(reg, data)
+#define rd_reg64(reg) __raw_readq(reg)
+#endif
+#endif
+#endif
+
+#ifndef CONFIG_64BIT
+static inline void wr_reg64(u64 __iomem *reg, u64 data)
+{
+ wr_reg32((u32 __iomem *)reg, (data & 0xffffffff00000000ull) >> 32);
+ wr_reg32((u32 __iomem *)reg + 1, data & 0x00000000ffffffffull);
+}
+
+static inline u64 rd_reg64(u64 __iomem *reg)
+{
+ return (((u64)rd_reg32((u32 __iomem *)reg)) << 32) |
+ ((u64)rd_reg32((u32 __iomem *)reg + 1));
+}
+#endif
+
+/*
+ * jr_outentry
+ * Represents each entry in a JobR output ring
+ */
+struct jr_outentry {
+ dma_addr_t desc;/* Pointer to completed descriptor */
+ u32 jrstatus; /* Status for completed descriptor */
+} __packed;
+
+/*
+ * caam_perfmon - Performance Monitor/Secure Memory Status/
+ * CAAM Global Status/Component Version IDs
+ *
+ * Spans f00-fff wherever instantiated
+ */
+
+/* Number of DECOs */
+#define CHA_NUM_DECONUM_SHIFT 56
+#define CHA_NUM_DECONUM_MASK (0xfull << CHA_NUM_DECONUM_SHIFT)
+
+struct caam_perfmon {
+ /* Performance Monitor Registers f00-f9f */
+ u64 req_dequeued; /* PC_REQ_DEQ - Dequeued Requests */
+ u64 ob_enc_req; /* PC_OB_ENC_REQ - Outbound Encrypt Requests */
+ u64 ib_dec_req; /* PC_IB_DEC_REQ - Inbound Decrypt Requests */
+ u64 ob_enc_bytes; /* PC_OB_ENCRYPT - Outbound Bytes Encrypted */
+ u64 ob_prot_bytes; /* PC_OB_PROTECT - Outbound Bytes Protected */
+ u64 ib_dec_bytes; /* PC_IB_DECRYPT - Inbound Bytes Decrypted */
+ u64 ib_valid_bytes; /* PC_IB_VALIDATED Inbound Bytes Validated */
+ u64 rsvd[13];
+
+ /* CAAM Hardware Instantiation Parameters fa0-fbf */
+ u64 cha_rev; /* CRNR - CHA Revision Number */
+#define CTPR_QI_SHIFT 57
+#define CTPR_QI_MASK (0x1ull << CTPR_QI_SHIFT)
+ u64 comp_parms; /* CTPR - Compile Parameters Register */
+ u64 rsvd1[2];
+
+ /* CAAM Global Status fc0-fdf */
+ u64 faultaddr; /* FAR - Fault Address */
+ u32 faultliodn; /* FALR - Fault Address LIODN */
+ u32 faultdetail; /* FADR - Fault Addr Detail */
+ u32 rsvd2;
+ u32 status; /* CSTA - CAAM Status */
+ u64 rsvd3;
+
+ /* Component Instantiation Parameters fe0-fff */
+ u32 rtic_id; /* RVID - RTIC Version ID */
+ u32 ccb_id; /* CCBVID - CCB Version ID */
+ u64 cha_id; /* CHAVID - CHA Version ID */
+ u64 cha_num; /* CHANUM - CHA Number */
+ u64 caam_id; /* CAAMVID - CAAM Version ID */
+};
+
+/* LIODN programming for DMA configuration */
+#define MSTRID_LOCK_LIODN 0x80000000
+#define MSTRID_LOCK_MAKETRUSTED 0x00010000 /* only for JR masterid */
+
+#define MSTRID_LIODN_MASK 0x0fff
+struct masterid {
+ u32 liodn_ms; /* lock and make-trusted control bits */
+ u32 liodn_ls; /* LIODN for non-sequence and seq access */
+};
+
+/* Partition ID for DMA configuration */
+struct partid {
+ u32 rsvd1;
+ u32 pidr; /* partition ID, DECO */
+};
+
+/* RNG test mode (replicated twice in some configurations) */
+/* Padded out to 0x100 */
+struct rngtst {
+ u32 mode; /* RTSTMODEx - Test mode */
+ u32 rsvd1[3];
+ u32 reset; /* RTSTRESETx - Test reset control */
+ u32 rsvd2[3];
+ u32 status; /* RTSTSSTATUSx - Test status */
+ u32 rsvd3;
+ u32 errstat; /* RTSTERRSTATx - Test error status */
+ u32 rsvd4;
+ u32 errctl; /* RTSTERRCTLx - Test error control */
+ u32 rsvd5;
+ u32 entropy; /* RTSTENTROPYx - Test entropy */
+ u32 rsvd6[15];
+ u32 verifctl; /* RTSTVERIFCTLx - Test verification control */
+ u32 rsvd7;
+ u32 verifstat; /* RTSTVERIFSTATx - Test verification status */
+ u32 rsvd8;
+ u32 verifdata; /* RTSTVERIFDx - Test verification data */
+ u32 rsvd9;
+ u32 xkey; /* RTSTXKEYx - Test XKEY */
+ u32 rsvd10;
+ u32 oscctctl; /* RTSTOSCCTCTLx - Test osc. counter control */
+ u32 rsvd11;
+ u32 oscct; /* RTSTOSCCTx - Test oscillator counter */
+ u32 rsvd12;
+ u32 oscctstat; /* RTSTODCCTSTATx - Test osc counter status */
+ u32 rsvd13[2];
+ u32 ofifo[4]; /* RTSTOFIFOx - Test output FIFO */
+ u32 rsvd14[15];
+};
+
+/*
+ * caam_ctrl - basic core configuration
+ * starts base + 0x0000 padded out to 0x1000
+ */
+
+#define KEK_KEY_SIZE 8
+#define TKEK_KEY_SIZE 8
+#define TDSK_KEY_SIZE 8
+
+#define DECO_RESET 1 /* Use with DECO reset/availability regs */
+#define DECO_RESET_0 (DECO_RESET << 0)
+#define DECO_RESET_1 (DECO_RESET << 1)
+#define DECO_RESET_2 (DECO_RESET << 2)
+#define DECO_RESET_3 (DECO_RESET << 3)
+#define DECO_RESET_4 (DECO_RESET << 4)
+
+struct caam_ctrl {
+ /* Basic Configuration Section 000-01f */
+ /* Read/Writable */
+ u32 rsvd1;
+ u32 mcr; /* MCFG Master Config Register */
+ u32 rsvd2[2];
+
+ /* Bus Access Configuration Section 010-11f */
+ /* Read/Writable */
+ struct masterid jr_mid[4]; /* JRxLIODNR - JobR LIODN setup */
+ u32 rsvd3[12];
+ struct masterid rtic_mid[4]; /* RTICxLIODNR - RTIC LIODN setup */
+ u32 rsvd4[7];
+ u32 deco_rq; /* DECORR - DECO Request */
+ struct partid deco_mid[5]; /* DECOxLIODNR - 1 per DECO */
+ u32 rsvd5[22];
+
+ /* DECO Availability/Reset Section 120-3ff */
+ u32 deco_avail; /* DAR - DECO availability */
+ u32 deco_reset; /* DRR - DECO reset */
+ u32 rsvd6[182];
+
+ /* Key Encryption/Decryption Configuration 400-5ff */
+ /* Read/Writable only while in Non-secure mode */
+ u32 kek[KEK_KEY_SIZE]; /* JDKEKR - Key Encryption Key */
+ u32 tkek[TKEK_KEY_SIZE]; /* TDKEKR - Trusted Desc KEK */
+ u32 tdsk[TDSK_KEY_SIZE]; /* TDSKR - Trusted Desc Signing Key */
+ u32 rsvd7[32];
+ u64 sknonce; /* SKNR - Secure Key Nonce */
+ u32 rsvd8[70];
+
+ /* RNG Test/Verification/Debug Access 600-7ff */
+ /* (Useful in Test/Debug modes only...) */
+ struct rngtst rtst[2];
+
+ u32 rsvd9[448];
+
+ /* Performance Monitor f00-fff */
+ struct caam_perfmon perfmon;
+};
+
+/*
+ * Controller master config register defs
+ */
+#define MCFGR_SWRESET 0x80000000 /* software reset */
+#define MCFGR_WDENABLE 0x40000000 /* DECO watchdog enable */
+#define MCFGR_WDFAIL 0x20000000 /* DECO watchdog force-fail */
+#define MCFGR_DMA_RESET 0x10000000
+#define MCFGR_LONG_PTR 0x00010000 /* Use >32-bit desc addressing */
+
+/* AXI read cache control */
+#define MCFGR_ARCACHE_SHIFT 12
+#define MCFGR_ARCACHE_MASK (0xf << MCFGR_ARCACHE_SHIFT)
+
+/* AXI write cache control */
+#define MCFGR_AWCACHE_SHIFT 8
+#define MCFGR_AWCACHE_MASK (0xf << MCFGR_AWCACHE_SHIFT)
+
+/* AXI pipeline depth */
+#define MCFGR_AXIPIPE_SHIFT 4
+#define MCFGR_AXIPIPE_MASK (0xf << MCFGR_AXIPIPE_SHIFT)
+
+#define MCFGR_AXIPRI 0x00000008 /* Assert AXI priority sideband */
+#define MCFGR_BURST_64 0x00000001 /* Max burst size */
+
+/*
+ * caam_job_ring - direct job ring setup
+ * 1-4 possible per instantiation, base + 1000/2000/3000/4000
+ * Padded out to 0x1000
+ */
+struct caam_job_ring {
+ /* Input ring */
+ u64 inpring_base; /* IRBAx - Input desc ring baseaddr */
+ u32 rsvd1;
+ u32 inpring_size; /* IRSx - Input ring size */
+ u32 rsvd2;
+ u32 inpring_avail; /* IRSAx - Input ring room remaining */
+ u32 rsvd3;
+ u32 inpring_jobadd; /* IRJAx - Input ring jobs added */
+
+ /* Output Ring */
+ u64 outring_base; /* ORBAx - Output status ring base addr */
+ u32 rsvd4;
+ u32 outring_size; /* ORSx - Output ring size */
+ u32 rsvd5;
+ u32 outring_rmvd; /* ORJRx - Output ring jobs removed */
+ u32 rsvd6;
+ u32 outring_used; /* ORSFx - Output ring slots full */
+
+ /* Status/Configuration */
+ u32 rsvd7;
+ u32 jroutstatus; /* JRSTAx - JobR output status */
+ u32 rsvd8;
+ u32 jrintstatus; /* JRINTx - JobR interrupt status */
+ u32 rconfig_hi; /* JRxCFG - Ring configuration */
+ u32 rconfig_lo;
+
+ /* Indices. CAAM maintains as "heads" of each queue */
+ u32 rsvd9;
+ u32 inp_rdidx; /* IRRIx - Input ring read index */
+ u32 rsvd10;
+ u32 out_wtidx; /* ORWIx - Output ring write index */
+
+ /* Command/control */
+ u32 rsvd11;
+ u32 jrcommand; /* JRCRx - JobR command */
+
+ u32 rsvd12[932];
+
+ /* Performance Monitor f00-fff */
+ struct caam_perfmon perfmon;
+};
+
+#define JR_RINGSIZE_MASK 0x03ff
+/*
+ * jrstatus - Job Ring Output Status
+ * All values in lo word
+ * Also note, same values written out as status through QI
+ * in the command/status field of a frame descriptor
+ */
+#define JRSTA_SSRC_SHIFT 28
+#define JRSTA_SSRC_MASK 0xf0000000
+
+#define JRSTA_SSRC_NONE 0x00000000
+#define JRSTA_SSRC_CCB_ERROR 0x20000000
+#define JRSTA_SSRC_JUMP_HALT_USER 0x30000000
+#define JRSTA_SSRC_DECO 0x40000000
+#define JRSTA_SSRC_JRERROR 0x60000000
+#define JRSTA_SSRC_JUMP_HALT_CC 0x70000000
+
+#define JRSTA_DECOERR_JUMP 0x08000000
+#define JRSTA_DECOERR_INDEX_SHIFT 8
+#define JRSTA_DECOERR_INDEX_MASK 0xff00
+#define JRSTA_DECOERR_ERROR_MASK 0x00ff
+
+#define JRSTA_DECOERR_NONE 0x00
+#define JRSTA_DECOERR_LINKLEN 0x01
+#define JRSTA_DECOERR_LINKPTR 0x02
+#define JRSTA_DECOERR_JRCTRL 0x03
+#define JRSTA_DECOERR_DESCCMD 0x04
+#define JRSTA_DECOERR_ORDER 0x05
+#define JRSTA_DECOERR_KEYCMD 0x06
+#define JRSTA_DECOERR_LOADCMD 0x07
+#define JRSTA_DECOERR_STORECMD 0x08
+#define JRSTA_DECOERR_OPCMD 0x09
+#define JRSTA_DECOERR_FIFOLDCMD 0x0a
+#define JRSTA_DECOERR_FIFOSTCMD 0x0b
+#define JRSTA_DECOERR_MOVECMD 0x0c
+#define JRSTA_DECOERR_JUMPCMD 0x0d
+#define JRSTA_DECOERR_MATHCMD 0x0e
+#define JRSTA_DECOERR_SHASHCMD 0x0f
+#define JRSTA_DECOERR_SEQCMD 0x10
+#define JRSTA_DECOERR_DECOINTERNAL 0x11
+#define JRSTA_DECOERR_SHDESCHDR 0x12
+#define JRSTA_DECOERR_HDRLEN 0x13
+#define JRSTA_DECOERR_BURSTER 0x14
+#define JRSTA_DECOERR_DESCSIGNATURE 0x15
+#define JRSTA_DECOERR_DMA 0x16
+#define JRSTA_DECOERR_BURSTFIFO 0x17
+#define JRSTA_DECOERR_JRRESET 0x1a
+#define JRSTA_DECOERR_JOBFAIL 0x1b
+#define JRSTA_DECOERR_DNRERR 0x80
+#define JRSTA_DECOERR_UNDEFPCL 0x81
+#define JRSTA_DECOERR_PDBERR 0x82
+#define JRSTA_DECOERR_ANRPLY_LATE 0x83
+#define JRSTA_DECOERR_ANRPLY_REPLAY 0x84
+#define JRSTA_DECOERR_SEQOVF 0x85
+#define JRSTA_DECOERR_INVSIGN 0x86
+#define JRSTA_DECOERR_DSASIGN 0x87
+
+#define JRSTA_CCBERR_JUMP 0x08000000
+#define JRSTA_CCBERR_INDEX_MASK 0xff00
+#define JRSTA_CCBERR_INDEX_SHIFT 8
+#define JRSTA_CCBERR_CHAID_MASK 0x00f0
+#define JRSTA_CCBERR_CHAID_SHIFT 4
+#define JRSTA_CCBERR_ERRID_MASK 0x000f
+
+#define JRSTA_CCBERR_CHAID_AES (0x01 << JRSTA_CCBERR_CHAID_SHIFT)
+#define JRSTA_CCBERR_CHAID_DES (0x02 << JRSTA_CCBERR_CHAID_SHIFT)
+#define JRSTA_CCBERR_CHAID_ARC4 (0x03 << JRSTA_CCBERR_CHAID_SHIFT)
+#define JRSTA_CCBERR_CHAID_MD (0x04 << JRSTA_CCBERR_CHAID_SHIFT)
+#define JRSTA_CCBERR_CHAID_RNG (0x05 << JRSTA_CCBERR_CHAID_SHIFT)
+#define JRSTA_CCBERR_CHAID_SNOW (0x06 << JRSTA_CCBERR_CHAID_SHIFT)
+#define JRSTA_CCBERR_CHAID_KASUMI (0x07 << JRSTA_CCBERR_CHAID_SHIFT)
+#define JRSTA_CCBERR_CHAID_PK (0x08 << JRSTA_CCBERR_CHAID_SHIFT)
+#define JRSTA_CCBERR_CHAID_CRC (0x09 << JRSTA_CCBERR_CHAID_SHIFT)
+
+#define JRSTA_CCBERR_ERRID_NONE 0x00
+#define JRSTA_CCBERR_ERRID_MODE 0x01
+#define JRSTA_CCBERR_ERRID_DATASIZ 0x02
+#define JRSTA_CCBERR_ERRID_KEYSIZ 0x03
+#define JRSTA_CCBERR_ERRID_PKAMEMSZ 0x04
+#define JRSTA_CCBERR_ERRID_PKBMEMSZ 0x05
+#define JRSTA_CCBERR_ERRID_SEQUENCE 0x06
+#define JRSTA_CCBERR_ERRID_PKDIVZRO 0x07
+#define JRSTA_CCBERR_ERRID_PKMODEVN 0x08
+#define JRSTA_CCBERR_ERRID_KEYPARIT 0x09
+#define JRSTA_CCBERR_ERRID_ICVCHK 0x0a
+#define JRSTA_CCBERR_ERRID_HARDWARE 0x0b
+#define JRSTA_CCBERR_ERRID_CCMAAD 0x0c
+#define JRSTA_CCBERR_ERRID_INVCHA 0x0f
+
+#define JRINT_ERR_INDEX_MASK 0x3fff0000
+#define JRINT_ERR_INDEX_SHIFT 16
+#define JRINT_ERR_TYPE_MASK 0xf00
+#define JRINT_ERR_TYPE_SHIFT 8
+#define JRINT_ERR_HALT_MASK 0xc
+#define JRINT_ERR_HALT_SHIFT 2
+#define JRINT_ERR_HALT_INPROGRESS 0x4
+#define JRINT_ERR_HALT_COMPLETE 0x8
+#define JRINT_JR_ERROR 0x02
+#define JRINT_JR_INT 0x01
+
+#define JRINT_ERR_TYPE_WRITE 1
+#define JRINT_ERR_TYPE_BAD_INPADDR 3
+#define JRINT_ERR_TYPE_BAD_OUTADDR 4
+#define JRINT_ERR_TYPE_INV_INPWRT 5
+#define JRINT_ERR_TYPE_INV_OUTWRT 6
+#define JRINT_ERR_TYPE_RESET 7
+#define JRINT_ERR_TYPE_REMOVE_OFL 8
+#define JRINT_ERR_TYPE_ADD_OFL 9
+
+#define JRCFG_SOE 0x04
+#define JRCFG_ICEN 0x02
+#define JRCFG_IMSK 0x01
+#define JRCFG_ICDCT_SHIFT 8
+#define JRCFG_ICTT_SHIFT 16
+
+#define JRCR_RESET 0x01
+
+/*
+ * caam_assurance - Assurance Controller View
+ * base + 0x6000 padded out to 0x1000
+ */
+
+struct rtic_element {
+ u64 address;
+ u32 rsvd;
+ u32 length;
+};
+
+struct rtic_block {
+ struct rtic_element element[2];
+};
+
+struct rtic_memhash {
+ u32 memhash_be[32];
+ u32 memhash_le[32];
+};
+
+struct caam_assurance {
+ /* Status/Command/Watchdog */
+ u32 rsvd1;
+ u32 status; /* RSTA - Status */
+ u32 rsvd2;
+ u32 cmd; /* RCMD - Command */
+ u32 rsvd3;
+ u32 ctrl; /* RCTL - Control */
+ u32 rsvd4;
+ u32 throttle; /* RTHR - Throttle */
+ u32 rsvd5[2];
+ u64 watchdog; /* RWDOG - Watchdog Timer */
+ u32 rsvd6;
+ u32 rend; /* REND - Endian corrections */
+ u32 rsvd7[50];
+
+ /* Block access/configuration @ 100/110/120/130 */
+ struct rtic_block memblk[4]; /* Memory Blocks A-D */
+ u32 rsvd8[32];
+
+ /* Block hashes @ 200/300/400/500 */
+ struct rtic_memhash hash[4]; /* Block hash values A-D */
+ u32 rsvd_3[640];
+};
+
+/*
+ * caam_queue_if - QI configuration and control
+ * starts base + 0x7000, padded out to 0x1000 long
+ */
+
+struct caam_queue_if {
+ u32 qi_control_hi; /* QICTL - QI Control */
+ u32 qi_control_lo;
+ u32 rsvd1;
+ u32 qi_status; /* QISTA - QI Status */
+ u32 qi_deq_cfg_hi; /* QIDQC - QI Dequeue Configuration */
+ u32 qi_deq_cfg_lo;
+ u32 qi_enq_cfg_hi; /* QISEQC - QI Enqueue Command */
+ u32 qi_enq_cfg_lo;
+ u32 rsvd2[1016];
+};
+
+/* QI control bits - low word */
+#define QICTL_DQEN 0x01 /* Enable frame pop */
+#define QICTL_STOP 0x02 /* Stop dequeue/enqueue */
+#define QICTL_SOE 0x04 /* Stop on error */
+
+/* QI control bits - high word */
+#define QICTL_MBSI 0x01
+#define QICTL_MHWSI 0x02
+#define QICTL_MWSI 0x04
+#define QICTL_MDWSI 0x08
+#define QICTL_CBSI 0x10 /* CtrlDataByteSwapInput */
+#define QICTL_CHWSI 0x20 /* CtrlDataHalfSwapInput */
+#define QICTL_CWSI 0x40 /* CtrlDataWordSwapInput */
+#define QICTL_CDWSI 0x80 /* CtrlDataDWordSwapInput */
+#define QICTL_MBSO 0x0100
+#define QICTL_MHWSO 0x0200
+#define QICTL_MWSO 0x0400
+#define QICTL_MDWSO 0x0800
+#define QICTL_CBSO 0x1000 /* CtrlDataByteSwapOutput */
+#define QICTL_CHWSO 0x2000 /* CtrlDataHalfSwapOutput */
+#define QICTL_CWSO 0x4000 /* CtrlDataWordSwapOutput */
+#define QICTL_CDWSO 0x8000 /* CtrlDataDWordSwapOutput */
+#define QICTL_DMBS 0x010000
+#define QICTL_EPO 0x020000
+
+/* QI status bits */
+#define QISTA_PHRDERR 0x01 /* PreHeader Read Error */
+#define QISTA_CFRDERR 0x02 /* Compound Frame Read Error */
+#define QISTA_OFWRERR 0x04 /* Output Frame Read Error */
+#define QISTA_BPDERR 0x08 /* Buffer Pool Depleted */
+#define QISTA_BTSERR 0x10 /* Buffer Undersize */
+#define QISTA_CFWRERR 0x20 /* Compound Frame Write Err */
+#define QISTA_STOPD 0x80000000 /* QI Stopped (see QICTL) */
+
+/* deco_sg_table - DECO view of scatter/gather table */
+struct deco_sg_table {
+ u64 addr; /* Segment Address */
+ u32 elen; /* E, F bits + 30-bit length */
+ u32 bpid_offset; /* Buffer Pool ID + 16-bit length */
+};
+
+/*
+ * caam_deco - descriptor controller - CHA cluster block
+ *
+ * Only accessible when direct DECO access is turned on
+ * (done in DECORR, via MID programmed in DECOxMID
+ *
+ * 5 typical, base + 0x8000/9000/a000/b000
+ * Padded out to 0x1000 long
+ */
+struct caam_deco {
+ u32 rsvd1;
+ u32 cls1_mode; /* CxC1MR - Class 1 Mode */
+ u32 rsvd2;
+ u32 cls1_keysize; /* CxC1KSR - Class 1 Key Size */
+ u32 cls1_datasize_hi; /* CxC1DSR - Class 1 Data Size */
+ u32 cls1_datasize_lo;
+ u32 rsvd3;
+ u32 cls1_icvsize; /* CxC1ICVSR - Class 1 ICV size */
+ u32 rsvd4[5];
+ u32 cha_ctrl; /* CCTLR - CHA control */
+ u32 rsvd5;
+ u32 irq_crtl; /* CxCIRQ - CCB interrupt done/error/clear */
+ u32 rsvd6;
+ u32 clr_written; /* CxCWR - Clear-Written */
+ u32 ccb_status_hi; /* CxCSTA - CCB Status/Error */
+ u32 ccb_status_lo;
+ u32 rsvd7[3];
+ u32 aad_size; /* CxAADSZR - Current AAD Size */
+ u32 rsvd8;
+ u32 cls1_iv_size; /* CxC1IVSZR - Current Class 1 IV Size */
+ u32 rsvd9[7];
+ u32 pkha_a_size; /* PKASZRx - Size of PKHA A */
+ u32 rsvd10;
+ u32 pkha_b_size; /* PKBSZRx - Size of PKHA B */
+ u32 rsvd11;
+ u32 pkha_n_size; /* PKNSZRx - Size of PKHA N */
+ u32 rsvd12;
+ u32 pkha_e_size; /* PKESZRx - Size of PKHA E */
+ u32 rsvd13[24];
+ u32 cls1_ctx[16]; /* CxC1CTXR - Class 1 Context @100 */
+ u32 rsvd14[48];
+ u32 cls1_key[8]; /* CxC1KEYR - Class 1 Key @200 */
+ u32 rsvd15[121];
+ u32 cls2_mode; /* CxC2MR - Class 2 Mode */
+ u32 rsvd16;
+ u32 cls2_keysize; /* CxX2KSR - Class 2 Key Size */
+ u32 cls2_datasize_hi; /* CxC2DSR - Class 2 Data Size */
+ u32 cls2_datasize_lo;
+ u32 rsvd17;
+ u32 cls2_icvsize; /* CxC2ICVSZR - Class 2 ICV Size */
+ u32 rsvd18[56];
+ u32 cls2_ctx[18]; /* CxC2CTXR - Class 2 Context @500 */
+ u32 rsvd19[46];
+ u32 cls2_key[32]; /* CxC2KEYR - Class2 Key @600 */
+ u32 rsvd20[84];
+ u32 inp_infofifo_hi; /* CxIFIFO - Input Info FIFO @7d0 */
+ u32 inp_infofifo_lo;
+ u32 rsvd21[2];
+ u64 inp_datafifo; /* CxDFIFO - Input Data FIFO */
+ u32 rsvd22[2];
+ u64 out_datafifo; /* CxOFIFO - Output Data FIFO */
+ u32 rsvd23[2];
+ u32 jr_ctl_hi; /* CxJRR - JobR Control Register @800 */
+ u32 jr_ctl_lo;
+ u64 jr_descaddr; /* CxDADR - JobR Descriptor Address */
+ u32 op_status_hi; /* DxOPSTA - DECO Operation Status */
+ u32 op_status_lo;
+ u32 rsvd24[2];
+ u32 liodn; /* DxLSR - DECO LIODN Status - non-seq */
+ u32 td_liodn; /* DxLSR - DECO LIODN Status - trustdesc */
+ u32 rsvd26[6];
+ u64 math[4]; /* DxMTH - Math register */
+ u32 rsvd27[8];
+ struct deco_sg_table gthr_tbl[4]; /* DxGTR - Gather Tables */
+ u32 rsvd28[16];
+ struct deco_sg_table sctr_tbl[4]; /* DxSTR - Scatter Tables */
+ u32 rsvd29[48];
+ u32 descbuf[64]; /* DxDESB - Descriptor buffer */
+ u32 rsvd30[320];
+};
+
+/*
+ * Current top-level view of memory map is:
+ *
+ * 0x0000 - 0x0fff - CAAM Top-Level Control
+ * 0x1000 - 0x1fff - Job Ring 0
+ * 0x2000 - 0x2fff - Job Ring 1
+ * 0x3000 - 0x3fff - Job Ring 2
+ * 0x4000 - 0x4fff - Job Ring 3
+ * 0x5000 - 0x5fff - (unused)
+ * 0x6000 - 0x6fff - Assurance Controller
+ * 0x7000 - 0x7fff - Queue Interface
+ * 0x8000 - 0x8fff - DECO-CCB 0
+ * 0x9000 - 0x9fff - DECO-CCB 1
+ * 0xa000 - 0xafff - DECO-CCB 2
+ * 0xb000 - 0xbfff - DECO-CCB 3
+ * 0xc000 - 0xcfff - DECO-CCB 4
+ *
+ * caam_full describes the full register view of CAAM if useful,
+ * although many configurations may choose to implement parts of
+ * the register map separately, in differing privilege regions
+ */
+struct caam_full {
+ struct caam_ctrl __iomem ctrl;
+ struct caam_job_ring jr[4];
+ u64 rsvd[512];
+ struct caam_assurance assure;
+ struct caam_queue_if qi;
+ struct caam_deco *deco;
+};
+
+#endif /* REGS_H */
diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c
index c99305afa58a..3cf303ee3fe3 100644
--- a/drivers/crypto/mv_cesa.c
+++ b/drivers/crypto/mv_cesa.c
@@ -133,7 +133,6 @@ struct mv_req_hash_ctx {
int extra_bytes; /* unprocessed bytes in buffer */
enum hash_op op;
int count_add;
- struct scatterlist dummysg;
};
static void compute_aes_dec_key(struct mv_ctx *ctx)
@@ -187,9 +186,9 @@ static void copy_src_to_buf(struct req_progress *p, char *dbuf, int len)
{
int ret;
void *sbuf;
- int copied = 0;
+ int copy_len;
- while (1) {
+ while (len) {
if (!p->sg_src_left) {
ret = sg_miter_next(&p->src_sg_it);
BUG_ON(!ret);
@@ -199,19 +198,14 @@ static void copy_src_to_buf(struct req_progress *p, char *dbuf, int len)
sbuf = p->src_sg_it.addr + p->src_start;
- if (p->sg_src_left <= len - copied) {
- memcpy(dbuf + copied, sbuf, p->sg_src_left);
- copied += p->sg_src_left;
- p->sg_src_left = 0;
- if (copied >= len)
- break;
- } else {
- int copy_len = len - copied;
- memcpy(dbuf + copied, sbuf, copy_len);
- p->src_start += copy_len;
- p->sg_src_left -= copy_len;
- break;
- }
+ copy_len = min(p->sg_src_left, len);
+ memcpy(dbuf, sbuf, copy_len);
+
+ p->src_start += copy_len;
+ p->sg_src_left -= copy_len;
+
+ len -= copy_len;
+ dbuf += copy_len;
}
}
@@ -275,7 +269,6 @@ static void mv_process_current_q(int first_block)
memcpy(cpg->sram + SRAM_CONFIG, &op,
sizeof(struct sec_accel_config));
- writel(SRAM_CONFIG, cpg->reg + SEC_ACCEL_DESC_P0);
/* GO */
writel(SEC_CMD_EN_SEC_ACCL0, cpg->reg + SEC_ACCEL_CMD);
@@ -302,6 +295,7 @@ static void mv_crypto_algo_completion(void)
static void mv_process_hash_current(int first_block)
{
struct ahash_request *req = ahash_request_cast(cpg->cur_req);
+ const struct mv_tfm_hash_ctx *tfm_ctx = crypto_tfm_ctx(req->base.tfm);
struct mv_req_hash_ctx *req_ctx = ahash_request_ctx(req);
struct req_progress *p = &cpg->p;
struct sec_accel_config op = { 0 };
@@ -314,6 +308,8 @@ static void mv_process_hash_current(int first_block)
break;
case COP_HMAC_SHA1:
op.config = CFG_OP_MAC_ONLY | CFG_MACM_HMAC_SHA1;
+ memcpy(cpg->sram + SRAM_HMAC_IV_IN,
+ tfm_ctx->ivs, sizeof(tfm_ctx->ivs));
break;
}
@@ -345,11 +341,16 @@ static void mv_process_hash_current(int first_block)
op.config |= CFG_LAST_FRAG;
else
op.config |= CFG_MID_FRAG;
+
+ writel(req_ctx->state[0], cpg->reg + DIGEST_INITIAL_VAL_A);
+ writel(req_ctx->state[1], cpg->reg + DIGEST_INITIAL_VAL_B);
+ writel(req_ctx->state[2], cpg->reg + DIGEST_INITIAL_VAL_C);
+ writel(req_ctx->state[3], cpg->reg + DIGEST_INITIAL_VAL_D);
+ writel(req_ctx->state[4], cpg->reg + DIGEST_INITIAL_VAL_E);
}
memcpy(cpg->sram + SRAM_CONFIG, &op, sizeof(struct sec_accel_config));
- writel(SRAM_CONFIG, cpg->reg + SEC_ACCEL_DESC_P0);
/* GO */
writel(SEC_CMD_EN_SEC_ACCL0, cpg->reg + SEC_ACCEL_CMD);
@@ -409,12 +410,6 @@ static void mv_hash_algo_completion(void)
copy_src_to_buf(&cpg->p, ctx->buffer, ctx->extra_bytes);
sg_miter_stop(&cpg->p.src_sg_it);
- ctx->state[0] = readl(cpg->reg + DIGEST_INITIAL_VAL_A);
- ctx->state[1] = readl(cpg->reg + DIGEST_INITIAL_VAL_B);
- ctx->state[2] = readl(cpg->reg + DIGEST_INITIAL_VAL_C);
- ctx->state[3] = readl(cpg->reg + DIGEST_INITIAL_VAL_D);
- ctx->state[4] = readl(cpg->reg + DIGEST_INITIAL_VAL_E);
-
if (likely(ctx->last_chunk)) {
if (likely(ctx->count <= MAX_HW_HASH_SIZE)) {
memcpy(req->result, cpg->sram + SRAM_DIGEST_BUF,
@@ -422,6 +417,12 @@ static void mv_hash_algo_completion(void)
(req)));
} else
mv_hash_final_fallback(req);
+ } else {
+ ctx->state[0] = readl(cpg->reg + DIGEST_INITIAL_VAL_A);
+ ctx->state[1] = readl(cpg->reg + DIGEST_INITIAL_VAL_B);
+ ctx->state[2] = readl(cpg->reg + DIGEST_INITIAL_VAL_C);
+ ctx->state[3] = readl(cpg->reg + DIGEST_INITIAL_VAL_D);
+ ctx->state[4] = readl(cpg->reg + DIGEST_INITIAL_VAL_E);
}
}
@@ -480,7 +481,7 @@ static int count_sgs(struct scatterlist *sl, unsigned int total_bytes)
int i = 0;
size_t cur_len;
- while (1) {
+ while (sl) {
cur_len = sl[i].length;
++i;
if (total_bytes > cur_len)
@@ -517,29 +518,12 @@ static void mv_start_new_hash_req(struct ahash_request *req)
{
struct req_progress *p = &cpg->p;
struct mv_req_hash_ctx *ctx = ahash_request_ctx(req);
- const struct mv_tfm_hash_ctx *tfm_ctx = crypto_tfm_ctx(req->base.tfm);
int num_sgs, hw_bytes, old_extra_bytes, rc;
cpg->cur_req = &req->base;
memset(p, 0, sizeof(struct req_progress));
hw_bytes = req->nbytes + ctx->extra_bytes;
old_extra_bytes = ctx->extra_bytes;
- if (unlikely(ctx->extra_bytes)) {
- memcpy(cpg->sram + SRAM_DATA_IN_START, ctx->buffer,
- ctx->extra_bytes);
- p->crypt_len = ctx->extra_bytes;
- }
-
- memcpy(cpg->sram + SRAM_HMAC_IV_IN, tfm_ctx->ivs, sizeof(tfm_ctx->ivs));
-
- if (unlikely(!ctx->first_hash)) {
- writel(ctx->state[0], cpg->reg + DIGEST_INITIAL_VAL_A);
- writel(ctx->state[1], cpg->reg + DIGEST_INITIAL_VAL_B);
- writel(ctx->state[2], cpg->reg + DIGEST_INITIAL_VAL_C);
- writel(ctx->state[3], cpg->reg + DIGEST_INITIAL_VAL_D);
- writel(ctx->state[4], cpg->reg + DIGEST_INITIAL_VAL_E);
- }
-
ctx->extra_bytes = hw_bytes % SHA1_BLOCK_SIZE;
if (ctx->extra_bytes != 0
&& (!ctx->last_chunk || ctx->count > MAX_HW_HASH_SIZE))
@@ -555,6 +539,12 @@ static void mv_start_new_hash_req(struct ahash_request *req)
p->complete = mv_hash_algo_completion;
p->process = mv_process_hash_current;
+ if (unlikely(old_extra_bytes)) {
+ memcpy(cpg->sram + SRAM_DATA_IN_START, ctx->buffer,
+ old_extra_bytes);
+ p->crypt_len = old_extra_bytes;
+ }
+
mv_process_hash_current(1);
} else {
copy_src_to_buf(p, ctx->buffer + old_extra_bytes,
@@ -603,9 +593,7 @@ static int queue_manag(void *data)
if (async_req->tfm->__crt_alg->cra_type !=
&crypto_ahash_type) {
struct ablkcipher_request *req =
- container_of(async_req,
- struct ablkcipher_request,
- base);
+ ablkcipher_request_cast(async_req);
mv_start_new_crypt_req(req);
} else {
struct ahash_request *req =
@@ -722,19 +710,13 @@ static int mv_hash_update(struct ahash_request *req)
static int mv_hash_final(struct ahash_request *req)
{
struct mv_req_hash_ctx *ctx = ahash_request_ctx(req);
- /* dummy buffer of 4 bytes */
- sg_init_one(&ctx->dummysg, ctx->buffer, 4);
- /* I think I'm allowed to do that... */
- ahash_request_set_crypt(req, &ctx->dummysg, req->result, 0);
+
mv_update_hash_req_ctx(ctx, 1, 0);
return mv_handle_req(&req->base);
}
static int mv_hash_finup(struct ahash_request *req)
{
- if (!req->nbytes)
- return mv_hash_final(req);
-
mv_update_hash_req_ctx(ahash_request_ctx(req), 1, req->nbytes);
return mv_handle_req(&req->base);
}
@@ -1065,14 +1047,21 @@ static int mv_probe(struct platform_device *pdev)
writel(SEC_INT_ACCEL0_DONE, cpg->reg + SEC_ACCEL_INT_MASK);
writel(SEC_CFG_STOP_DIG_ERR, cpg->reg + SEC_ACCEL_CFG);
+ writel(SRAM_CONFIG, cpg->reg + SEC_ACCEL_DESC_P0);
ret = crypto_register_alg(&mv_aes_alg_ecb);
- if (ret)
+ if (ret) {
+ printk(KERN_WARNING MV_CESA
+ "Could not register aes-ecb driver\n");
goto err_irq;
+ }
ret = crypto_register_alg(&mv_aes_alg_cbc);
- if (ret)
+ if (ret) {
+ printk(KERN_WARNING MV_CESA
+ "Could not register aes-cbc driver\n");
goto err_unreg_ecb;
+ }
ret = crypto_register_ahash(&mv_sha1_alg);
if (ret == 0)
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index 465cde3e4f60..ba8f1ea84c5e 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -78,7 +78,6 @@
#define FLAGS_SHA1 0x0010
#define FLAGS_DMA_ACTIVE 0x0020
#define FLAGS_OUTPUT_READY 0x0040
-#define FLAGS_CLEAN 0x0080
#define FLAGS_INIT 0x0100
#define FLAGS_CPU 0x0200
#define FLAGS_HMAC 0x0400
@@ -511,26 +510,6 @@ static int omap_sham_update_dma_stop(struct omap_sham_dev *dd)
return 0;
}
-static void omap_sham_cleanup(struct ahash_request *req)
-{
- struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
- struct omap_sham_dev *dd = ctx->dd;
- unsigned long flags;
-
- spin_lock_irqsave(&dd->lock, flags);
- if (ctx->flags & FLAGS_CLEAN) {
- spin_unlock_irqrestore(&dd->lock, flags);
- return;
- }
- ctx->flags |= FLAGS_CLEAN;
- spin_unlock_irqrestore(&dd->lock, flags);
-
- if (ctx->digcnt)
- omap_sham_copy_ready_hash(req);
-
- dev_dbg(dd->dev, "digcnt: %d, bufcnt: %d\n", ctx->digcnt, ctx->bufcnt);
-}
-
static int omap_sham_init(struct ahash_request *req)
{
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
@@ -618,9 +597,8 @@ static int omap_sham_final_req(struct omap_sham_dev *dd)
return err;
}
-static int omap_sham_finish_req_hmac(struct ahash_request *req)
+static int omap_sham_finish_hmac(struct ahash_request *req)
{
- struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
struct omap_sham_ctx *tctx = crypto_tfm_ctx(req->base.tfm);
struct omap_sham_hmac_ctx *bctx = tctx->base;
int bs = crypto_shash_blocksize(bctx->shash);
@@ -635,7 +613,24 @@ static int omap_sham_finish_req_hmac(struct ahash_request *req)
return crypto_shash_init(&desc.shash) ?:
crypto_shash_update(&desc.shash, bctx->opad, bs) ?:
- crypto_shash_finup(&desc.shash, ctx->digest, ds, ctx->digest);
+ crypto_shash_finup(&desc.shash, req->result, ds, req->result);
+}
+
+static int omap_sham_finish(struct ahash_request *req)
+{
+ struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
+ struct omap_sham_dev *dd = ctx->dd;
+ int err = 0;
+
+ if (ctx->digcnt) {
+ omap_sham_copy_ready_hash(req);
+ if (ctx->flags & FLAGS_HMAC)
+ err = omap_sham_finish_hmac(req);
+ }
+
+ dev_dbg(dd->dev, "digcnt: %d, bufcnt: %d\n", ctx->digcnt, ctx->bufcnt);
+
+ return err;
}
static void omap_sham_finish_req(struct ahash_request *req, int err)
@@ -645,15 +640,12 @@ static void omap_sham_finish_req(struct ahash_request *req, int err)
if (!err) {
omap_sham_copy_hash(ctx->dd->req, 1);
- if (ctx->flags & FLAGS_HMAC)
- err = omap_sham_finish_req_hmac(req);
+ if (ctx->flags & FLAGS_FINAL)
+ err = omap_sham_finish(req);
} else {
ctx->flags |= FLAGS_ERROR;
}
- if ((ctx->flags & FLAGS_FINAL) || err)
- omap_sham_cleanup(req);
-
clk_disable(dd->iclk);
dd->flags &= ~FLAGS_BUSY;
@@ -809,22 +801,21 @@ static int omap_sham_final_shash(struct ahash_request *req)
static int omap_sham_final(struct ahash_request *req)
{
struct omap_sham_reqctx *ctx = ahash_request_ctx(req);
- int err = 0;
ctx->flags |= FLAGS_FINUP;
- if (!(ctx->flags & FLAGS_ERROR)) {
- /* OMAP HW accel works only with buffers >= 9 */
- /* HMAC is always >= 9 because of ipad */
- if ((ctx->digcnt + ctx->bufcnt) < 9)
- err = omap_sham_final_shash(req);
- else if (ctx->bufcnt)
- return omap_sham_enqueue(req, OP_FINAL);
- }
+ if (ctx->flags & FLAGS_ERROR)
+ return 0; /* uncompleted hash is not needed */
- omap_sham_cleanup(req);
+ /* OMAP HW accel works only with buffers >= 9 */
+ /* HMAC is always >= 9 because ipad == block size */
+ if ((ctx->digcnt + ctx->bufcnt) < 9)
+ return omap_sham_final_shash(req);
+ else if (ctx->bufcnt)
+ return omap_sham_enqueue(req, OP_FINAL);
- return err;
+ /* copy ready hash (+ finalize hmac) */
+ return omap_sham_finish(req);
}
static int omap_sham_finup(struct ahash_request *req)
@@ -835,7 +826,7 @@ static int omap_sham_finup(struct ahash_request *req)
ctx->flags |= FLAGS_FINUP;
err1 = omap_sham_update(req);
- if (err1 == -EINPROGRESS)
+ if (err1 == -EINPROGRESS || err1 == -EBUSY)
return err1;
/*
* final() has to be always called to cleanup resources
@@ -890,8 +881,6 @@ static int omap_sham_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base)
struct omap_sham_ctx *tctx = crypto_tfm_ctx(tfm);
const char *alg_name = crypto_tfm_alg_name(tfm);
- pr_info("enter\n");
-
/* Allocate a fallback and abort if it failed. */
tctx->fallback = crypto_alloc_shash(alg_name, 0,
CRYPTO_ALG_NEED_FALLBACK);
@@ -1297,7 +1286,8 @@ static int __init omap_sham_mod_init(void)
pr_info("loading %s driver\n", "omap-sham");
if (!cpu_class_is_omap2() ||
- omap_type() != OMAP2_DEVICE_TYPE_SEC) {
+ (omap_type() != OMAP2_DEVICE_TYPE_SEC &&
+ omap_type() != OMAP2_DEVICE_TYPE_EMU)) {
pr_err("Unsupported cpu\n");
return -ENODEV;
}
diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c
index adf075b6b9a8..06bdb4b2c6a6 100644
--- a/drivers/crypto/padlock-sha.c
+++ b/drivers/crypto/padlock-sha.c
@@ -288,9 +288,250 @@ static struct shash_alg sha256_alg = {
}
};
+/* Add two shash_alg instance for hardware-implemented *
+* multiple-parts hash supported by VIA Nano Processor.*/
+static int padlock_sha1_init_nano(struct shash_desc *desc)
+{
+ struct sha1_state *sctx = shash_desc_ctx(desc);
+
+ *sctx = (struct sha1_state){
+ .state = { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 },
+ };
+
+ return 0;
+}
+
+static int padlock_sha1_update_nano(struct shash_desc *desc,
+ const u8 *data, unsigned int len)
+{
+ struct sha1_state *sctx = shash_desc_ctx(desc);
+ unsigned int partial, done;
+ const u8 *src;
+ /*The PHE require the out buffer must 128 bytes and 16-bytes aligned*/
+ u8 buf[128 + PADLOCK_ALIGNMENT - STACK_ALIGN] __attribute__
+ ((aligned(STACK_ALIGN)));
+ u8 *dst = PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT);
+ int ts_state;
+
+ partial = sctx->count & 0x3f;
+ sctx->count += len;
+ done = 0;
+ src = data;
+ memcpy(dst, (u8 *)(sctx->state), SHA1_DIGEST_SIZE);
+
+ if ((partial + len) >= SHA1_BLOCK_SIZE) {
+
+ /* Append the bytes in state's buffer to a block to handle */
+ if (partial) {
+ done = -partial;
+ memcpy(sctx->buffer + partial, data,
+ done + SHA1_BLOCK_SIZE);
+ src = sctx->buffer;
+ ts_state = irq_ts_save();
+ asm volatile (".byte 0xf3,0x0f,0xa6,0xc8"
+ : "+S"(src), "+D"(dst) \
+ : "a"((long)-1), "c"((unsigned long)1));
+ irq_ts_restore(ts_state);
+ done += SHA1_BLOCK_SIZE;
+ src = data + done;
+ }
+
+ /* Process the left bytes from the input data */
+ if (len - done >= SHA1_BLOCK_SIZE) {
+ ts_state = irq_ts_save();
+ asm volatile (".byte 0xf3,0x0f,0xa6,0xc8"
+ : "+S"(src), "+D"(dst)
+ : "a"((long)-1),
+ "c"((unsigned long)((len - done) / SHA1_BLOCK_SIZE)));
+ irq_ts_restore(ts_state);
+ done += ((len - done) - (len - done) % SHA1_BLOCK_SIZE);
+ src = data + done;
+ }
+ partial = 0;
+ }
+ memcpy((u8 *)(sctx->state), dst, SHA1_DIGEST_SIZE);
+ memcpy(sctx->buffer + partial, src, len - done);
+
+ return 0;
+}
+
+static int padlock_sha1_final_nano(struct shash_desc *desc, u8 *out)
+{
+ struct sha1_state *state = (struct sha1_state *)shash_desc_ctx(desc);
+ unsigned int partial, padlen;
+ __be64 bits;
+ static const u8 padding[64] = { 0x80, };
+
+ bits = cpu_to_be64(state->count << 3);
+
+ /* Pad out to 56 mod 64 */
+ partial = state->count & 0x3f;
+ padlen = (partial < 56) ? (56 - partial) : ((64+56) - partial);
+ padlock_sha1_update_nano(desc, padding, padlen);
+
+ /* Append length field bytes */
+ padlock_sha1_update_nano(desc, (const u8 *)&bits, sizeof(bits));
+
+ /* Swap to output */
+ padlock_output_block((uint32_t *)(state->state), (uint32_t *)out, 5);
+
+ return 0;
+}
+
+static int padlock_sha256_init_nano(struct shash_desc *desc)
+{
+ struct sha256_state *sctx = shash_desc_ctx(desc);
+
+ *sctx = (struct sha256_state){
+ .state = { SHA256_H0, SHA256_H1, SHA256_H2, SHA256_H3, \
+ SHA256_H4, SHA256_H5, SHA256_H6, SHA256_H7},
+ };
+
+ return 0;
+}
+
+static int padlock_sha256_update_nano(struct shash_desc *desc, const u8 *data,
+ unsigned int len)
+{
+ struct sha256_state *sctx = shash_desc_ctx(desc);
+ unsigned int partial, done;
+ const u8 *src;
+ /*The PHE require the out buffer must 128 bytes and 16-bytes aligned*/
+ u8 buf[128 + PADLOCK_ALIGNMENT - STACK_ALIGN] __attribute__
+ ((aligned(STACK_ALIGN)));
+ u8 *dst = PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT);
+ int ts_state;
+
+ partial = sctx->count & 0x3f;
+ sctx->count += len;
+ done = 0;
+ src = data;
+ memcpy(dst, (u8 *)(sctx->state), SHA256_DIGEST_SIZE);
+
+ if ((partial + len) >= SHA256_BLOCK_SIZE) {
+
+ /* Append the bytes in state's buffer to a block to handle */
+ if (partial) {
+ done = -partial;
+ memcpy(sctx->buf + partial, data,
+ done + SHA256_BLOCK_SIZE);
+ src = sctx->buf;
+ ts_state = irq_ts_save();
+ asm volatile (".byte 0xf3,0x0f,0xa6,0xd0"
+ : "+S"(src), "+D"(dst)
+ : "a"((long)-1), "c"((unsigned long)1));
+ irq_ts_restore(ts_state);
+ done += SHA256_BLOCK_SIZE;
+ src = data + done;
+ }
+
+ /* Process the left bytes from input data*/
+ if (len - done >= SHA256_BLOCK_SIZE) {
+ ts_state = irq_ts_save();
+ asm volatile (".byte 0xf3,0x0f,0xa6,0xd0"
+ : "+S"(src), "+D"(dst)
+ : "a"((long)-1),
+ "c"((unsigned long)((len - done) / 64)));
+ irq_ts_restore(ts_state);
+ done += ((len - done) - (len - done) % 64);
+ src = data + done;
+ }
+ partial = 0;
+ }
+ memcpy((u8 *)(sctx->state), dst, SHA256_DIGEST_SIZE);
+ memcpy(sctx->buf + partial, src, len - done);
+
+ return 0;
+}
+
+static int padlock_sha256_final_nano(struct shash_desc *desc, u8 *out)
+{
+ struct sha256_state *state =
+ (struct sha256_state *)shash_desc_ctx(desc);
+ unsigned int partial, padlen;
+ __be64 bits;
+ static const u8 padding[64] = { 0x80, };
+
+ bits = cpu_to_be64(state->count << 3);
+
+ /* Pad out to 56 mod 64 */
+ partial = state->count & 0x3f;
+ padlen = (partial < 56) ? (56 - partial) : ((64+56) - partial);
+ padlock_sha256_update_nano(desc, padding, padlen);
+
+ /* Append length field bytes */
+ padlock_sha256_update_nano(desc, (const u8 *)&bits, sizeof(bits));
+
+ /* Swap to output */
+ padlock_output_block((uint32_t *)(state->state), (uint32_t *)out, 8);
+
+ return 0;
+}
+
+static int padlock_sha_export_nano(struct shash_desc *desc,
+ void *out)
+{
+ int statesize = crypto_shash_statesize(desc->tfm);
+ void *sctx = shash_desc_ctx(desc);
+
+ memcpy(out, sctx, statesize);
+ return 0;
+}
+
+static int padlock_sha_import_nano(struct shash_desc *desc,
+ const void *in)
+{
+ int statesize = crypto_shash_statesize(desc->tfm);
+ void *sctx = shash_desc_ctx(desc);
+
+ memcpy(sctx, in, statesize);
+ return 0;
+}
+
+static struct shash_alg sha1_alg_nano = {
+ .digestsize = SHA1_DIGEST_SIZE,
+ .init = padlock_sha1_init_nano,
+ .update = padlock_sha1_update_nano,
+ .final = padlock_sha1_final_nano,
+ .export = padlock_sha_export_nano,
+ .import = padlock_sha_import_nano,
+ .descsize = sizeof(struct sha1_state),
+ .statesize = sizeof(struct sha1_state),
+ .base = {
+ .cra_name = "sha1",
+ .cra_driver_name = "sha1-padlock-nano",
+ .cra_priority = PADLOCK_CRA_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
+ .cra_blocksize = SHA1_BLOCK_SIZE,
+ .cra_module = THIS_MODULE,
+ }
+};
+
+static struct shash_alg sha256_alg_nano = {
+ .digestsize = SHA256_DIGEST_SIZE,
+ .init = padlock_sha256_init_nano,
+ .update = padlock_sha256_update_nano,
+ .final = padlock_sha256_final_nano,
+ .export = padlock_sha_export_nano,
+ .import = padlock_sha_import_nano,
+ .descsize = sizeof(struct sha256_state),
+ .statesize = sizeof(struct sha256_state),
+ .base = {
+ .cra_name = "sha256",
+ .cra_driver_name = "sha256-padlock-nano",
+ .cra_priority = PADLOCK_CRA_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
+ .cra_blocksize = SHA256_BLOCK_SIZE,
+ .cra_module = THIS_MODULE,
+ }
+};
+
static int __init padlock_init(void)
{
int rc = -ENODEV;
+ struct cpuinfo_x86 *c = &cpu_data(0);
+ struct shash_alg *sha1;
+ struct shash_alg *sha256;
if (!cpu_has_phe) {
printk(KERN_NOTICE PFX "VIA PadLock Hash Engine not detected.\n");
@@ -302,11 +543,21 @@ static int __init padlock_init(void)
return -ENODEV;
}
- rc = crypto_register_shash(&sha1_alg);
+ /* Register the newly added algorithm module if on *
+ * VIA Nano processor, or else just do as before */
+ if (c->x86_model < 0x0f) {
+ sha1 = &sha1_alg;
+ sha256 = &sha256_alg;
+ } else {
+ sha1 = &sha1_alg_nano;
+ sha256 = &sha256_alg_nano;
+ }
+
+ rc = crypto_register_shash(sha1);
if (rc)
goto out;
- rc = crypto_register_shash(&sha256_alg);
+ rc = crypto_register_shash(sha256);
if (rc)
goto out_unreg1;
@@ -315,7 +566,8 @@ static int __init padlock_init(void)
return 0;
out_unreg1:
- crypto_unregister_shash(&sha1_alg);
+ crypto_unregister_shash(sha1);
+
out:
printk(KERN_ERR PFX "VIA PadLock SHA1/SHA256 initialization failed.\n");
return rc;
@@ -323,8 +575,15 @@ out:
static void __exit padlock_fini(void)
{
- crypto_unregister_shash(&sha1_alg);
- crypto_unregister_shash(&sha256_alg);
+ struct cpuinfo_x86 *c = &cpu_data(0);
+
+ if (c->x86_model >= 0x0f) {
+ crypto_unregister_shash(&sha1_alg_nano);
+ crypto_unregister_shash(&sha256_alg_nano);
+ } else {
+ crypto_unregister_shash(&sha1_alg);
+ crypto_unregister_shash(&sha256_alg);
+ }
}
module_init(padlock_init);
diff --git a/drivers/crypto/picoxcell_crypto.c b/drivers/crypto/picoxcell_crypto.c
index b092d0a65837..230b5b8cda1f 100644
--- a/drivers/crypto/picoxcell_crypto.c
+++ b/drivers/crypto/picoxcell_crypto.c
@@ -176,6 +176,8 @@ struct spacc_aead_ctx {
u8 salt[AES_BLOCK_SIZE];
};
+static int spacc_ablk_submit(struct spacc_req *req);
+
static inline struct spacc_alg *to_spacc_alg(struct crypto_alg *alg)
{
return alg ? container_of(alg, struct spacc_alg, alg) : NULL;
@@ -666,6 +668,24 @@ static int spacc_aead_submit(struct spacc_req *req)
return -EINPROGRESS;
}
+static int spacc_req_submit(struct spacc_req *req);
+
+static void spacc_push(struct spacc_engine *engine)
+{
+ struct spacc_req *req;
+
+ while (!list_empty(&engine->pending) &&
+ engine->in_flight + 1 <= engine->fifo_sz) {
+
+ ++engine->in_flight;
+ req = list_first_entry(&engine->pending, struct spacc_req,
+ list);
+ list_move_tail(&req->list, &engine->in_progress);
+
+ req->result = spacc_req_submit(req);
+ }
+}
+
/*
* Setup an AEAD request for processing. This will configure the engine, load
* the context and then start the packet processing.
@@ -698,7 +718,8 @@ static int spacc_aead_setup(struct aead_request *req, u8 *giv,
err = -EINPROGRESS;
spin_lock_irqsave(&engine->hw_lock, flags);
- if (unlikely(spacc_fifo_cmd_full(engine))) {
+ if (unlikely(spacc_fifo_cmd_full(engine)) ||
+ engine->in_flight + 1 > engine->fifo_sz) {
if (!(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
err = -EBUSY;
spin_unlock_irqrestore(&engine->hw_lock, flags);
@@ -706,9 +727,8 @@ static int spacc_aead_setup(struct aead_request *req, u8 *giv,
}
list_add_tail(&dev_req->list, &engine->pending);
} else {
- ++engine->in_flight;
- list_add_tail(&dev_req->list, &engine->in_progress);
- spacc_aead_submit(dev_req);
+ list_add_tail(&dev_req->list, &engine->pending);
+ spacc_push(engine);
}
spin_unlock_irqrestore(&engine->hw_lock, flags);
@@ -1041,7 +1061,8 @@ static int spacc_ablk_setup(struct ablkcipher_request *req, unsigned alg_type,
* we either stick it on the end of a pending list if we can backlog,
* or bailout with an error if not.
*/
- if (unlikely(spacc_fifo_cmd_full(engine))) {
+ if (unlikely(spacc_fifo_cmd_full(engine)) ||
+ engine->in_flight + 1 > engine->fifo_sz) {
if (!(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) {
err = -EBUSY;
spin_unlock_irqrestore(&engine->hw_lock, flags);
@@ -1049,9 +1070,8 @@ static int spacc_ablk_setup(struct ablkcipher_request *req, unsigned alg_type,
}
list_add_tail(&dev_req->list, &engine->pending);
} else {
- ++engine->in_flight;
- list_add_tail(&dev_req->list, &engine->in_progress);
- spacc_ablk_submit(dev_req);
+ list_add_tail(&dev_req->list, &engine->pending);
+ spacc_push(engine);
}
spin_unlock_irqrestore(&engine->hw_lock, flags);
@@ -1139,6 +1159,7 @@ static void spacc_process_done(struct spacc_engine *engine)
req = list_first_entry(&engine->in_progress, struct spacc_req,
list);
list_move_tail(&req->list, &engine->completed);
+ --engine->in_flight;
/* POP the status register. */
writel(~0, engine->regs + SPA_STAT_POP_REG_OFFSET);
@@ -1208,36 +1229,21 @@ static void spacc_spacc_complete(unsigned long data)
struct spacc_engine *engine = (struct spacc_engine *)data;
struct spacc_req *req, *tmp;
unsigned long flags;
- int num_removed = 0;
LIST_HEAD(completed);
spin_lock_irqsave(&engine->hw_lock, flags);
+
list_splice_init(&engine->completed, &completed);
+ spacc_push(engine);
+ if (engine->in_flight)
+ mod_timer(&engine->packet_timeout, jiffies + PACKET_TIMEOUT);
+
spin_unlock_irqrestore(&engine->hw_lock, flags);
list_for_each_entry_safe(req, tmp, &completed, list) {
- ++num_removed;
req->complete(req);
+ list_del(&req->list);
}
-
- /* Try and fill the engine back up again. */
- spin_lock_irqsave(&engine->hw_lock, flags);
-
- engine->in_flight -= num_removed;
-
- list_for_each_entry_safe(req, tmp, &engine->pending, list) {
- if (spacc_fifo_cmd_full(engine))
- break;
-
- list_move_tail(&req->list, &engine->in_progress);
- ++engine->in_flight;
- req->result = spacc_req_submit(req);
- }
-
- if (engine->in_flight)
- mod_timer(&engine->packet_timeout, jiffies + PACKET_TIMEOUT);
-
- spin_unlock_irqrestore(&engine->hw_lock, flags);
}
#ifdef CONFIG_PM
diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c
new file mode 100644
index 000000000000..8115417a1c93
--- /dev/null
+++ b/drivers/crypto/s5p-sss.c
@@ -0,0 +1,701 @@
+/*
+ * Cryptographic API.
+ *
+ * Support for Samsung S5PV210 HW acceleration.
+ *
+ * Copyright (C) 2011 NetUP Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/crypto.h>
+#include <linux/interrupt.h>
+
+#include <crypto/algapi.h>
+#include <crypto/aes.h>
+#include <crypto/ctr.h>
+
+#include <plat/cpu.h>
+#include <plat/dma.h>
+
+#define _SBF(s, v) ((v) << (s))
+#define _BIT(b) _SBF(b, 1)
+
+/* Feed control registers */
+#define SSS_REG_FCINTSTAT 0x0000
+#define SSS_FCINTSTAT_BRDMAINT _BIT(3)
+#define SSS_FCINTSTAT_BTDMAINT _BIT(2)
+#define SSS_FCINTSTAT_HRDMAINT _BIT(1)
+#define SSS_FCINTSTAT_PKDMAINT _BIT(0)
+
+#define SSS_REG_FCINTENSET 0x0004
+#define SSS_FCINTENSET_BRDMAINTENSET _BIT(3)
+#define SSS_FCINTENSET_BTDMAINTENSET _BIT(2)
+#define SSS_FCINTENSET_HRDMAINTENSET _BIT(1)
+#define SSS_FCINTENSET_PKDMAINTENSET _BIT(0)
+
+#define SSS_REG_FCINTENCLR 0x0008
+#define SSS_FCINTENCLR_BRDMAINTENCLR _BIT(3)
+#define SSS_FCINTENCLR_BTDMAINTENCLR _BIT(2)
+#define SSS_FCINTENCLR_HRDMAINTENCLR _BIT(1)
+#define SSS_FCINTENCLR_PKDMAINTENCLR _BIT(0)
+
+#define SSS_REG_FCINTPEND 0x000C
+#define SSS_FCINTPEND_BRDMAINTP _BIT(3)
+#define SSS_FCINTPEND_BTDMAINTP _BIT(2)
+#define SSS_FCINTPEND_HRDMAINTP _BIT(1)
+#define SSS_FCINTPEND_PKDMAINTP _BIT(0)
+
+#define SSS_REG_FCFIFOSTAT 0x0010
+#define SSS_FCFIFOSTAT_BRFIFOFUL _BIT(7)
+#define SSS_FCFIFOSTAT_BRFIFOEMP _BIT(6)
+#define SSS_FCFIFOSTAT_BTFIFOFUL _BIT(5)
+#define SSS_FCFIFOSTAT_BTFIFOEMP _BIT(4)
+#define SSS_FCFIFOSTAT_HRFIFOFUL _BIT(3)
+#define SSS_FCFIFOSTAT_HRFIFOEMP _BIT(2)
+#define SSS_FCFIFOSTAT_PKFIFOFUL _BIT(1)
+#define SSS_FCFIFOSTAT_PKFIFOEMP _BIT(0)
+
+#define SSS_REG_FCFIFOCTRL 0x0014
+#define SSS_FCFIFOCTRL_DESSEL _BIT(2)
+#define SSS_HASHIN_INDEPENDENT _SBF(0, 0x00)
+#define SSS_HASHIN_CIPHER_INPUT _SBF(0, 0x01)
+#define SSS_HASHIN_CIPHER_OUTPUT _SBF(0, 0x02)
+
+#define SSS_REG_FCBRDMAS 0x0020
+#define SSS_REG_FCBRDMAL 0x0024
+#define SSS_REG_FCBRDMAC 0x0028
+#define SSS_FCBRDMAC_BYTESWAP _BIT(1)
+#define SSS_FCBRDMAC_FLUSH _BIT(0)
+
+#define SSS_REG_FCBTDMAS 0x0030
+#define SSS_REG_FCBTDMAL 0x0034
+#define SSS_REG_FCBTDMAC 0x0038
+#define SSS_FCBTDMAC_BYTESWAP _BIT(1)
+#define SSS_FCBTDMAC_FLUSH _BIT(0)
+
+#define SSS_REG_FCHRDMAS 0x0040
+#define SSS_REG_FCHRDMAL 0x0044
+#define SSS_REG_FCHRDMAC 0x0048
+#define SSS_FCHRDMAC_BYTESWAP _BIT(1)
+#define SSS_FCHRDMAC_FLUSH _BIT(0)
+
+#define SSS_REG_FCPKDMAS 0x0050
+#define SSS_REG_FCPKDMAL 0x0054
+#define SSS_REG_FCPKDMAC 0x0058
+#define SSS_FCPKDMAC_BYTESWAP _BIT(3)
+#define SSS_FCPKDMAC_DESCEND _BIT(2)
+#define SSS_FCPKDMAC_TRANSMIT _BIT(1)
+#define SSS_FCPKDMAC_FLUSH _BIT(0)
+
+#define SSS_REG_FCPKDMAO 0x005C
+
+/* AES registers */
+#define SSS_REG_AES_CONTROL 0x4000
+#define SSS_AES_BYTESWAP_DI _BIT(11)
+#define SSS_AES_BYTESWAP_DO _BIT(10)
+#define SSS_AES_BYTESWAP_IV _BIT(9)
+#define SSS_AES_BYTESWAP_CNT _BIT(8)
+#define SSS_AES_BYTESWAP_KEY _BIT(7)
+#define SSS_AES_KEY_CHANGE_MODE _BIT(6)
+#define SSS_AES_KEY_SIZE_128 _SBF(4, 0x00)
+#define SSS_AES_KEY_SIZE_192 _SBF(4, 0x01)
+#define SSS_AES_KEY_SIZE_256 _SBF(4, 0x02)
+#define SSS_AES_FIFO_MODE _BIT(3)
+#define SSS_AES_CHAIN_MODE_ECB _SBF(1, 0x00)
+#define SSS_AES_CHAIN_MODE_CBC _SBF(1, 0x01)
+#define SSS_AES_CHAIN_MODE_CTR _SBF(1, 0x02)
+#define SSS_AES_MODE_DECRYPT _BIT(0)
+
+#define SSS_REG_AES_STATUS 0x4004
+#define SSS_AES_BUSY _BIT(2)
+#define SSS_AES_INPUT_READY _BIT(1)
+#define SSS_AES_OUTPUT_READY _BIT(0)
+
+#define SSS_REG_AES_IN_DATA(s) (0x4010 + (s << 2))
+#define SSS_REG_AES_OUT_DATA(s) (0x4020 + (s << 2))
+#define SSS_REG_AES_IV_DATA(s) (0x4030 + (s << 2))
+#define SSS_REG_AES_CNT_DATA(s) (0x4040 + (s << 2))
+#define SSS_REG_AES_KEY_DATA(s) (0x4080 + (s << 2))
+
+#define SSS_REG(dev, reg) ((dev)->ioaddr + (SSS_REG_##reg))
+#define SSS_READ(dev, reg) __raw_readl(SSS_REG(dev, reg))
+#define SSS_WRITE(dev, reg, val) __raw_writel((val), SSS_REG(dev, reg))
+
+/* HW engine modes */
+#define FLAGS_AES_DECRYPT _BIT(0)
+#define FLAGS_AES_MODE_MASK _SBF(1, 0x03)
+#define FLAGS_AES_CBC _SBF(1, 0x01)
+#define FLAGS_AES_CTR _SBF(1, 0x02)
+
+#define AES_KEY_LEN 16
+#define CRYPTO_QUEUE_LEN 1
+
+struct s5p_aes_reqctx {
+ unsigned long mode;
+};
+
+struct s5p_aes_ctx {
+ struct s5p_aes_dev *dev;
+
+ uint8_t aes_key[AES_MAX_KEY_SIZE];
+ uint8_t nonce[CTR_RFC3686_NONCE_SIZE];
+ int keylen;
+};
+
+struct s5p_aes_dev {
+ struct device *dev;
+ struct clk *clk;
+ void __iomem *ioaddr;
+ int irq_hash;
+ int irq_fc;
+
+ struct ablkcipher_request *req;
+ struct s5p_aes_ctx *ctx;
+ struct scatterlist *sg_src;
+ struct scatterlist *sg_dst;
+
+ struct tasklet_struct tasklet;
+ struct crypto_queue queue;
+ bool busy;
+ spinlock_t lock;
+};
+
+static struct s5p_aes_dev *s5p_dev;
+
+static void s5p_set_dma_indata(struct s5p_aes_dev *dev, struct scatterlist *sg)
+{
+ SSS_WRITE(dev, FCBRDMAS, sg_dma_address(sg));
+ SSS_WRITE(dev, FCBRDMAL, sg_dma_len(sg));
+}
+
+static void s5p_set_dma_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg)
+{
+ SSS_WRITE(dev, FCBTDMAS, sg_dma_address(sg));
+ SSS_WRITE(dev, FCBTDMAL, sg_dma_len(sg));
+}
+
+static void s5p_aes_complete(struct s5p_aes_dev *dev, int err)
+{
+ /* holding a lock outside */
+ dev->req->base.complete(&dev->req->base, err);
+ dev->busy = false;
+}
+
+static void s5p_unset_outdata(struct s5p_aes_dev *dev)
+{
+ dma_unmap_sg(dev->dev, dev->sg_dst, 1, DMA_FROM_DEVICE);
+}
+
+static void s5p_unset_indata(struct s5p_aes_dev *dev)
+{
+ dma_unmap_sg(dev->dev, dev->sg_src, 1, DMA_TO_DEVICE);
+}
+
+static int s5p_set_outdata(struct s5p_aes_dev *dev, struct scatterlist *sg)
+{
+ int err;
+
+ if (!IS_ALIGNED(sg_dma_len(sg), AES_BLOCK_SIZE)) {
+ err = -EINVAL;
+ goto exit;
+ }
+ if (!sg_dma_len(sg)) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ err = dma_map_sg(dev->dev, sg, 1, DMA_FROM_DEVICE);
+ if (!err) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ dev->sg_dst = sg;
+ err = 0;
+
+ exit:
+ return err;
+}
+
+static int s5p_set_indata(struct s5p_aes_dev *dev, struct scatterlist *sg)
+{
+ int err;
+
+ if (!IS_ALIGNED(sg_dma_len(sg), AES_BLOCK_SIZE)) {
+ err = -EINVAL;
+ goto exit;
+ }
+ if (!sg_dma_len(sg)) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ err = dma_map_sg(dev->dev, sg, 1, DMA_TO_DEVICE);
+ if (!err) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ dev->sg_src = sg;
+ err = 0;
+
+ exit:
+ return err;
+}
+
+static void s5p_aes_tx(struct s5p_aes_dev *dev)
+{
+ int err = 0;
+
+ s5p_unset_outdata(dev);
+
+ if (!sg_is_last(dev->sg_dst)) {
+ err = s5p_set_outdata(dev, sg_next(dev->sg_dst));
+ if (err) {
+ s5p_aes_complete(dev, err);
+ return;
+ }
+
+ s5p_set_dma_outdata(dev, dev->sg_dst);
+ } else
+ s5p_aes_complete(dev, err);
+}
+
+static void s5p_aes_rx(struct s5p_aes_dev *dev)
+{
+ int err;
+
+ s5p_unset_indata(dev);
+
+ if (!sg_is_last(dev->sg_src)) {
+ err = s5p_set_indata(dev, sg_next(dev->sg_src));
+ if (err) {
+ s5p_aes_complete(dev, err);
+ return;
+ }
+
+ s5p_set_dma_indata(dev, dev->sg_src);
+ }
+}
+
+static irqreturn_t s5p_aes_interrupt(int irq, void *dev_id)
+{
+ struct platform_device *pdev = dev_id;
+ struct s5p_aes_dev *dev = platform_get_drvdata(pdev);
+ uint32_t status;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ if (irq == dev->irq_fc) {
+ status = SSS_READ(dev, FCINTSTAT);
+ if (status & SSS_FCINTSTAT_BRDMAINT)
+ s5p_aes_rx(dev);
+ if (status & SSS_FCINTSTAT_BTDMAINT)
+ s5p_aes_tx(dev);
+
+ SSS_WRITE(dev, FCINTPEND, status);
+ }
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static void s5p_set_aes(struct s5p_aes_dev *dev,
+ uint8_t *key, uint8_t *iv, unsigned int keylen)
+{
+ void __iomem *keystart;
+
+ memcpy(dev->ioaddr + SSS_REG_AES_IV_DATA(0), iv, 0x10);
+
+ if (keylen == AES_KEYSIZE_256)
+ keystart = dev->ioaddr + SSS_REG_AES_KEY_DATA(0);
+ else if (keylen == AES_KEYSIZE_192)
+ keystart = dev->ioaddr + SSS_REG_AES_KEY_DATA(2);
+ else
+ keystart = dev->ioaddr + SSS_REG_AES_KEY_DATA(4);
+
+ memcpy(keystart, key, keylen);
+}
+
+static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode)
+{
+ struct ablkcipher_request *req = dev->req;
+
+ uint32_t aes_control;
+ int err;
+ unsigned long flags;
+
+ aes_control = SSS_AES_KEY_CHANGE_MODE;
+ if (mode & FLAGS_AES_DECRYPT)
+ aes_control |= SSS_AES_MODE_DECRYPT;
+
+ if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC)
+ aes_control |= SSS_AES_CHAIN_MODE_CBC;
+ else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR)
+ aes_control |= SSS_AES_CHAIN_MODE_CTR;
+
+ if (dev->ctx->keylen == AES_KEYSIZE_192)
+ aes_control |= SSS_AES_KEY_SIZE_192;
+ else if (dev->ctx->keylen == AES_KEYSIZE_256)
+ aes_control |= SSS_AES_KEY_SIZE_256;
+
+ aes_control |= SSS_AES_FIFO_MODE;
+
+ /* as a variant it is possible to use byte swapping on DMA side */
+ aes_control |= SSS_AES_BYTESWAP_DI
+ | SSS_AES_BYTESWAP_DO
+ | SSS_AES_BYTESWAP_IV
+ | SSS_AES_BYTESWAP_KEY
+ | SSS_AES_BYTESWAP_CNT;
+
+ spin_lock_irqsave(&dev->lock, flags);
+
+ SSS_WRITE(dev, FCINTENCLR,
+ SSS_FCINTENCLR_BTDMAINTENCLR | SSS_FCINTENCLR_BRDMAINTENCLR);
+ SSS_WRITE(dev, FCFIFOCTRL, 0x00);
+
+ err = s5p_set_indata(dev, req->src);
+ if (err)
+ goto indata_error;
+
+ err = s5p_set_outdata(dev, req->dst);
+ if (err)
+ goto outdata_error;
+
+ SSS_WRITE(dev, AES_CONTROL, aes_control);
+ s5p_set_aes(dev, dev->ctx->aes_key, req->info, dev->ctx->keylen);
+
+ s5p_set_dma_indata(dev, req->src);
+ s5p_set_dma_outdata(dev, req->dst);
+
+ SSS_WRITE(dev, FCINTENSET,
+ SSS_FCINTENSET_BTDMAINTENSET | SSS_FCINTENSET_BRDMAINTENSET);
+
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ return;
+
+ outdata_error:
+ s5p_unset_indata(dev);
+
+ indata_error:
+ s5p_aes_complete(dev, err);
+ spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+static void s5p_tasklet_cb(unsigned long data)
+{
+ struct s5p_aes_dev *dev = (struct s5p_aes_dev *)data;
+ struct crypto_async_request *async_req, *backlog;
+ struct s5p_aes_reqctx *reqctx;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ backlog = crypto_get_backlog(&dev->queue);
+ async_req = crypto_dequeue_request(&dev->queue);
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ if (!async_req)
+ return;
+
+ if (backlog)
+ backlog->complete(backlog, -EINPROGRESS);
+
+ dev->req = ablkcipher_request_cast(async_req);
+ dev->ctx = crypto_tfm_ctx(dev->req->base.tfm);
+ reqctx = ablkcipher_request_ctx(dev->req);
+
+ s5p_aes_crypt_start(dev, reqctx->mode);
+}
+
+static int s5p_aes_handle_req(struct s5p_aes_dev *dev,
+ struct ablkcipher_request *req)
+{
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ if (dev->busy) {
+ err = -EAGAIN;
+ spin_unlock_irqrestore(&dev->lock, flags);
+ goto exit;
+ }
+ dev->busy = true;
+
+ err = ablkcipher_enqueue_request(&dev->queue, req);
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ tasklet_schedule(&dev->tasklet);
+
+ exit:
+ return err;
+}
+
+static int s5p_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
+{
+ struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
+ struct s5p_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+ struct s5p_aes_reqctx *reqctx = ablkcipher_request_ctx(req);
+ struct s5p_aes_dev *dev = ctx->dev;
+
+ if (!IS_ALIGNED(req->nbytes, AES_BLOCK_SIZE)) {
+ pr_err("request size is not exact amount of AES blocks\n");
+ return -EINVAL;
+ }
+
+ reqctx->mode = mode;
+
+ return s5p_aes_handle_req(dev, req);
+}
+
+static int s5p_aes_setkey(struct crypto_ablkcipher *cipher,
+ const uint8_t *key, unsigned int keylen)
+{
+ struct crypto_tfm *tfm = crypto_ablkcipher_tfm(cipher);
+ struct s5p_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ if (keylen != AES_KEYSIZE_128 &&
+ keylen != AES_KEYSIZE_192 &&
+ keylen != AES_KEYSIZE_256)
+ return -EINVAL;
+
+ memcpy(ctx->aes_key, key, keylen);
+ ctx->keylen = keylen;
+
+ return 0;
+}
+
+static int s5p_aes_ecb_encrypt(struct ablkcipher_request *req)
+{
+ return s5p_aes_crypt(req, 0);
+}
+
+static int s5p_aes_ecb_decrypt(struct ablkcipher_request *req)
+{
+ return s5p_aes_crypt(req, FLAGS_AES_DECRYPT);
+}
+
+static int s5p_aes_cbc_encrypt(struct ablkcipher_request *req)
+{
+ return s5p_aes_crypt(req, FLAGS_AES_CBC);
+}
+
+static int s5p_aes_cbc_decrypt(struct ablkcipher_request *req)
+{
+ return s5p_aes_crypt(req, FLAGS_AES_DECRYPT | FLAGS_AES_CBC);
+}
+
+static int s5p_aes_cra_init(struct crypto_tfm *tfm)
+{
+ struct s5p_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ ctx->dev = s5p_dev;
+ tfm->crt_ablkcipher.reqsize = sizeof(struct s5p_aes_reqctx);
+
+ return 0;
+}
+
+static struct crypto_alg algs[] = {
+ {
+ .cra_name = "ecb(aes)",
+ .cra_driver_name = "ecb-aes-s5p",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct s5p_aes_ctx),
+ .cra_alignmask = 0x0f,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = s5p_aes_cra_init,
+ .cra_u.ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = s5p_aes_setkey,
+ .encrypt = s5p_aes_ecb_encrypt,
+ .decrypt = s5p_aes_ecb_decrypt,
+ }
+ },
+ {
+ .cra_name = "cbc(aes)",
+ .cra_driver_name = "cbc-aes-s5p",
+ .cra_priority = 100,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER |
+ CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct s5p_aes_ctx),
+ .cra_alignmask = 0x0f,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = s5p_aes_cra_init,
+ .cra_u.ablkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = s5p_aes_setkey,
+ .encrypt = s5p_aes_cbc_encrypt,
+ .decrypt = s5p_aes_cbc_decrypt,
+ }
+ },
+};
+
+static int s5p_aes_probe(struct platform_device *pdev)
+{
+ int i, j, err = -ENODEV;
+ struct s5p_aes_dev *pdata;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+
+ if (s5p_dev)
+ return -EEXIST;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ if (!devm_request_mem_region(dev, res->start,
+ resource_size(res), pdev->name))
+ return -EBUSY;
+
+ pdata->clk = clk_get(dev, "secss");
+ if (IS_ERR(pdata->clk)) {
+ dev_err(dev, "failed to find secss clock source\n");
+ return -ENOENT;
+ }
+
+ clk_enable(pdata->clk);
+
+ spin_lock_init(&pdata->lock);
+ pdata->ioaddr = devm_ioremap(dev, res->start,
+ resource_size(res));
+
+ pdata->irq_hash = platform_get_irq_byname(pdev, "hash");
+ if (pdata->irq_hash < 0) {
+ err = pdata->irq_hash;
+ dev_warn(dev, "hash interrupt is not available.\n");
+ goto err_irq;
+ }
+ err = devm_request_irq(dev, pdata->irq_hash, s5p_aes_interrupt,
+ IRQF_SHARED, pdev->name, pdev);
+ if (err < 0) {
+ dev_warn(dev, "hash interrupt is not available.\n");
+ goto err_irq;
+ }
+
+ pdata->irq_fc = platform_get_irq_byname(pdev, "feed control");
+ if (pdata->irq_fc < 0) {
+ err = pdata->irq_fc;
+ dev_warn(dev, "feed control interrupt is not available.\n");
+ goto err_irq;
+ }
+ err = devm_request_irq(dev, pdata->irq_fc, s5p_aes_interrupt,
+ IRQF_SHARED, pdev->name, pdev);
+ if (err < 0) {
+ dev_warn(dev, "feed control interrupt is not available.\n");
+ goto err_irq;
+ }
+
+ pdata->dev = dev;
+ platform_set_drvdata(pdev, pdata);
+ s5p_dev = pdata;
+
+ tasklet_init(&pdata->tasklet, s5p_tasklet_cb, (unsigned long)pdata);
+ crypto_init_queue(&pdata->queue, CRYPTO_QUEUE_LEN);
+
+ for (i = 0; i < ARRAY_SIZE(algs); i++) {
+ INIT_LIST_HEAD(&algs[i].cra_list);
+ err = crypto_register_alg(&algs[i]);
+ if (err)
+ goto err_algs;
+ }
+
+ pr_info("s5p-sss driver registered\n");
+
+ return 0;
+
+ err_algs:
+ dev_err(dev, "can't register '%s': %d\n", algs[i].cra_name, err);
+
+ for (j = 0; j < i; j++)
+ crypto_unregister_alg(&algs[j]);
+
+ tasklet_kill(&pdata->tasklet);
+
+ err_irq:
+ clk_disable(pdata->clk);
+ clk_put(pdata->clk);
+
+ s5p_dev = NULL;
+ platform_set_drvdata(pdev, NULL);
+
+ return err;
+}
+
+static int s5p_aes_remove(struct platform_device *pdev)
+{
+ struct s5p_aes_dev *pdata = platform_get_drvdata(pdev);
+ int i;
+
+ if (!pdata)
+ return -ENODEV;
+
+ for (i = 0; i < ARRAY_SIZE(algs); i++)
+ crypto_unregister_alg(&algs[i]);
+
+ tasklet_kill(&pdata->tasklet);
+
+ clk_disable(pdata->clk);
+ clk_put(pdata->clk);
+
+ s5p_dev = NULL;
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver s5p_aes_crypto = {
+ .probe = s5p_aes_probe,
+ .remove = s5p_aes_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "s5p-secss",
+ },
+};
+
+static int __init s5p_aes_mod_init(void)
+{
+ return platform_driver_register(&s5p_aes_crypto);
+}
+
+static void __exit s5p_aes_mod_exit(void)
+{
+ platform_driver_unregister(&s5p_aes_crypto);
+}
+
+module_init(s5p_aes_mod_init);
+module_exit(s5p_aes_mod_exit);
+
+MODULE_DESCRIPTION("S5PV210 AES hw acceleration support.");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Vladimir Zapolskiy <vzapolskiy@gmail.com>");
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index e0888cb538d4..b4f5c32b6a47 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -56,8 +56,8 @@ MODULE_PARM_DESC(pq_sources,
static int timeout = 3000;
module_param(timeout, uint, S_IRUGO);
-MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), \
- Pass -1 for infinite timeout");
+MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), "
+ "Pass -1 for infinite timeout");
/*
* Initialization patterns. All bytes in the source buffer has bit 7
@@ -634,5 +634,5 @@ static void __exit dmatest_exit(void)
}
module_exit(dmatest_exit);
-MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c
index 9c25c7d099e4..2a2e2fa00e91 100644
--- a/drivers/dma/dw_dmac.c
+++ b/drivers/dma/dw_dmac.c
@@ -1486,4 +1486,4 @@ module_exit(dw_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller driver");
-MODULE_AUTHOR("Haavard Skinnemoen <haavard.skinnemoen@atmel.com>");
+MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c
index c9213ead4a26..a4d6cb0c0343 100644
--- a/drivers/dma/ioat/dma.c
+++ b/drivers/dma/ioat/dma.c
@@ -34,6 +34,7 @@
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/workqueue.h>
+#include <linux/prefetch.h>
#include <linux/i7300_idle.h>
#include "dma.h"
#include "registers.h"
diff --git a/drivers/dma/ioat/dma_v2.c b/drivers/dma/ioat/dma_v2.c
index effd140fc042..f4a51d4d0349 100644
--- a/drivers/dma/ioat/dma_v2.c
+++ b/drivers/dma/ioat/dma_v2.c
@@ -34,6 +34,7 @@
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/workqueue.h>
+#include <linux/prefetch.h>
#include <linux/i7300_idle.h>
#include "dma.h"
#include "dma_v2.h"
diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c
index d0f499098479..d845dc4b7103 100644
--- a/drivers/dma/ioat/dma_v3.c
+++ b/drivers/dma/ioat/dma_v3.c
@@ -60,6 +60,7 @@
#include <linux/gfp.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
+#include <linux/prefetch.h>
#include "registers.h"
#include "hw.h"
#include "dma.h"
diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c
index d50da41ac328..636e40925b16 100644
--- a/drivers/dma/shdma.c
+++ b/drivers/dma/shdma.c
@@ -48,7 +48,7 @@ enum sh_dmae_desc_status {
/*
* Used for write-side mutual exclusion for the global device list,
- * read-side synchronization by way of RCU.
+ * read-side synchronization by way of RCU, and per-controller data.
*/
static DEFINE_SPINLOCK(sh_dmae_lock);
static LIST_HEAD(sh_dmae_devices);
@@ -85,22 +85,35 @@ static void dmaor_write(struct sh_dmae_device *shdev, u16 data)
*/
static void sh_dmae_ctl_stop(struct sh_dmae_device *shdev)
{
- unsigned short dmaor = dmaor_read(shdev);
+ unsigned short dmaor;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sh_dmae_lock, flags);
+ dmaor = dmaor_read(shdev);
dmaor_write(shdev, dmaor & ~(DMAOR_NMIF | DMAOR_AE | DMAOR_DME));
+
+ spin_unlock_irqrestore(&sh_dmae_lock, flags);
}
static int sh_dmae_rst(struct sh_dmae_device *shdev)
{
unsigned short dmaor;
+ unsigned long flags;
- sh_dmae_ctl_stop(shdev);
- dmaor = dmaor_read(shdev) | shdev->pdata->dmaor_init;
+ spin_lock_irqsave(&sh_dmae_lock, flags);
- dmaor_write(shdev, dmaor);
- if (dmaor_read(shdev) & (DMAOR_AE | DMAOR_NMIF)) {
- pr_warning("dma-sh: Can't initialize DMAOR.\n");
- return -EINVAL;
+ dmaor = dmaor_read(shdev) & ~(DMAOR_NMIF | DMAOR_AE | DMAOR_DME);
+
+ dmaor_write(shdev, dmaor | shdev->pdata->dmaor_init);
+
+ dmaor = dmaor_read(shdev);
+
+ spin_unlock_irqrestore(&sh_dmae_lock, flags);
+
+ if (dmaor & (DMAOR_AE | DMAOR_NMIF)) {
+ dev_warn(shdev->common.dev, "Can't initialize DMAOR.\n");
+ return -EIO;
}
return 0;
}
@@ -184,7 +197,7 @@ static void dmae_init(struct sh_dmae_chan *sh_chan)
static int dmae_set_chcr(struct sh_dmae_chan *sh_chan, u32 val)
{
- /* When DMA was working, can not set data to CHCR */
+ /* If DMA is active, cannot set CHCR. TODO: remove this superfluous check */
if (dmae_is_busy(sh_chan))
return -EBUSY;
@@ -200,12 +213,17 @@ static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val)
struct sh_dmae_device, common);
struct sh_dmae_pdata *pdata = shdev->pdata;
const struct sh_dmae_channel *chan_pdata = &pdata->channel[sh_chan->id];
- u16 __iomem *addr = shdev->dmars + chan_pdata->dmars / sizeof(u16);
+ u16 __iomem *addr = shdev->dmars;
int shift = chan_pdata->dmars_bit;
if (dmae_is_busy(sh_chan))
return -EBUSY;
+ /* in the case of a missing DMARS resource use first memory window */
+ if (!addr)
+ addr = (u16 __iomem *)shdev->chan_reg;
+ addr += chan_pdata->dmars / sizeof(u16);
+
__raw_writew((__raw_readw(addr) & (0xff00 >> shift)) | (val << shift),
addr);
@@ -374,7 +392,12 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan)
LIST_HEAD(list);
int descs = sh_chan->descs_allocated;
+ /* Protect against ISR */
+ spin_lock_irq(&sh_chan->desc_lock);
dmae_halt(sh_chan);
+ spin_unlock_irq(&sh_chan->desc_lock);
+
+ /* Now no new interrupts will occur */
/* Prepared and not submitted descriptors can still be on the queue */
if (!list_empty(&sh_chan->ld_queue))
@@ -384,6 +407,7 @@ static void sh_dmae_free_chan_resources(struct dma_chan *chan)
/* The caller is holding dma_list_mutex */
struct sh_dmae_slave *param = chan->private;
clear_bit(param->slave_id, sh_dmae_slave_used);
+ chan->private = NULL;
}
spin_lock_bh(&sh_chan->desc_lock);
@@ -563,8 +587,6 @@ static struct dma_async_tx_descriptor *sh_dmae_prep_memcpy(
if (!chan || !len)
return NULL;
- chan->private = NULL;
-
sh_chan = to_sh_chan(chan);
sg_init_table(&sg, 1);
@@ -620,9 +642,9 @@ static int sh_dmae_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
if (!chan)
return -EINVAL;
+ spin_lock_bh(&sh_chan->desc_lock);
dmae_halt(sh_chan);
- spin_lock_bh(&sh_chan->desc_lock);
if (!list_empty(&sh_chan->ld_queue)) {
/* Record partial transfer */
struct sh_desc *desc = list_entry(sh_chan->ld_queue.next,
@@ -716,6 +738,14 @@ static dma_async_tx_callback __ld_cleanup(struct sh_dmae_chan *sh_chan, bool all
list_move(&desc->node, &sh_chan->ld_free);
}
}
+
+ if (all && !callback)
+ /*
+ * Terminating and the loop completed normally: forgive
+ * uncompleted cookies
+ */
+ sh_chan->completed_cookie = sh_chan->common.cookie;
+
spin_unlock_bh(&sh_chan->desc_lock);
if (callback)
@@ -733,10 +763,6 @@ static void sh_dmae_chan_ld_cleanup(struct sh_dmae_chan *sh_chan, bool all)
{
while (__ld_cleanup(sh_chan, all))
;
-
- if (all)
- /* Terminating - forgive uncompleted cookies */
- sh_chan->completed_cookie = sh_chan->common.cookie;
}
static void sh_chan_xfer_ld_queue(struct sh_dmae_chan *sh_chan)
@@ -782,8 +808,10 @@ static enum dma_status sh_dmae_tx_status(struct dma_chan *chan,
sh_dmae_chan_ld_cleanup(sh_chan, false);
- last_used = chan->cookie;
+ /* First read completed cookie to avoid a skew */
last_complete = sh_chan->completed_cookie;
+ rmb();
+ last_used = chan->cookie;
BUG_ON(last_complete < 0);
dma_set_tx_state(txstate, last_complete, last_used, 0);
@@ -813,8 +841,12 @@ static enum dma_status sh_dmae_tx_status(struct dma_chan *chan,
static irqreturn_t sh_dmae_interrupt(int irq, void *data)
{
irqreturn_t ret = IRQ_NONE;
- struct sh_dmae_chan *sh_chan = (struct sh_dmae_chan *)data;
- u32 chcr = sh_dmae_readl(sh_chan, CHCR);
+ struct sh_dmae_chan *sh_chan = data;
+ u32 chcr;
+
+ spin_lock(&sh_chan->desc_lock);
+
+ chcr = sh_dmae_readl(sh_chan, CHCR);
if (chcr & CHCR_TE) {
/* DMA stop */
@@ -824,10 +856,13 @@ static irqreturn_t sh_dmae_interrupt(int irq, void *data)
tasklet_schedule(&sh_chan->tasklet);
}
+ spin_unlock(&sh_chan->desc_lock);
+
return ret;
}
-static unsigned int sh_dmae_reset(struct sh_dmae_device *shdev)
+/* Called from error IRQ or NMI */
+static bool sh_dmae_reset(struct sh_dmae_device *shdev)
{
unsigned int handled = 0;
int i;
@@ -839,22 +874,32 @@ static unsigned int sh_dmae_reset(struct sh_dmae_device *shdev)
for (i = 0; i < SH_DMAC_MAX_CHANNELS; i++) {
struct sh_dmae_chan *sh_chan = shdev->chan[i];
struct sh_desc *desc;
+ LIST_HEAD(dl);
if (!sh_chan)
continue;
+ spin_lock(&sh_chan->desc_lock);
+
/* Stop the channel */
dmae_halt(sh_chan);
+ list_splice_init(&sh_chan->ld_queue, &dl);
+
+ spin_unlock(&sh_chan->desc_lock);
+
/* Complete all */
- list_for_each_entry(desc, &sh_chan->ld_queue, node) {
+ list_for_each_entry(desc, &dl, node) {
struct dma_async_tx_descriptor *tx = &desc->async_tx;
desc->mark = DESC_IDLE;
if (tx->callback)
tx->callback(tx->callback_param);
}
- list_splice_init(&sh_chan->ld_queue, &sh_chan->ld_free);
+ spin_lock(&sh_chan->desc_lock);
+ list_splice(&dl, &sh_chan->ld_free);
+ spin_unlock(&sh_chan->desc_lock);
+
handled++;
}
@@ -867,10 +912,11 @@ static irqreturn_t sh_dmae_err(int irq, void *data)
{
struct sh_dmae_device *shdev = data;
- if (dmaor_read(shdev) & DMAOR_AE)
- return IRQ_RETVAL(sh_dmae_reset(data));
- else
+ if (!(dmaor_read(shdev) & DMAOR_AE))
return IRQ_NONE;
+
+ sh_dmae_reset(data);
+ return IRQ_HANDLED;
}
static void dmae_do_tasklet(unsigned long data)
@@ -902,17 +948,11 @@ static void dmae_do_tasklet(unsigned long data)
static bool sh_dmae_nmi_notify(struct sh_dmae_device *shdev)
{
- unsigned int handled;
-
/* Fast path out if NMIF is not asserted for this controller */
if ((dmaor_read(shdev) & DMAOR_NMIF) == 0)
return false;
- handled = sh_dmae_reset(shdev);
- if (handled)
- return true;
-
- return false;
+ return sh_dmae_reset(shdev);
}
static int sh_dmae_nmi_handler(struct notifier_block *self,
@@ -982,9 +1022,6 @@ static int __devinit sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
tasklet_init(&new_sh_chan->tasklet, dmae_do_tasklet,
(unsigned long)new_sh_chan);
- /* Init the channel */
- dmae_init(new_sh_chan);
-
spin_lock_init(&new_sh_chan->desc_lock);
/* Init descripter manage list */
@@ -1045,9 +1082,8 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
struct sh_dmae_pdata *pdata = pdev->dev.platform_data;
unsigned long irqflags = IRQF_DISABLED,
chan_flag[SH_DMAC_MAX_CHANNELS] = {};
- unsigned long flags;
int errirq, chan_irq[SH_DMAC_MAX_CHANNELS];
- int err, i, irq_cnt = 0, irqres = 0;
+ int err, i, irq_cnt = 0, irqres = 0, irq_cap = 0;
struct sh_dmae_device *shdev;
struct resource *chan, *dmars, *errirq_res, *chanirq_res;
@@ -1056,7 +1092,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
return -ENODEV;
chan = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- /* DMARS area is optional, if absent, this controller cannot do slave DMA */
+ /* DMARS area is optional */
dmars = platform_get_resource(pdev, IORESOURCE_MEM, 1);
/*
* IRQ resources:
@@ -1111,11 +1147,11 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
- spin_lock_irqsave(&sh_dmae_lock, flags);
+ spin_lock_irq(&sh_dmae_lock);
list_add_tail_rcu(&shdev->node, &sh_dmae_devices);
- spin_unlock_irqrestore(&sh_dmae_lock, flags);
+ spin_unlock_irq(&sh_dmae_lock);
- /* reset dma controller */
+ /* reset dma controller - only needed as a test */
err = sh_dmae_rst(shdev);
if (err)
goto rst_err;
@@ -1123,7 +1159,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&shdev->common.channels);
dma_cap_set(DMA_MEMCPY, shdev->common.cap_mask);
- if (dmars)
+ if (pdata->slave && pdata->slave_num)
dma_cap_set(DMA_SLAVE, shdev->common.cap_mask);
shdev->common.device_alloc_chan_resources
@@ -1172,8 +1208,13 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
!platform_get_resource(pdev, IORESOURCE_IRQ, 1)) {
/* Special case - all multiplexed */
for (; irq_cnt < pdata->channel_num; irq_cnt++) {
- chan_irq[irq_cnt] = chanirq_res->start;
- chan_flag[irq_cnt] = IRQF_SHARED;
+ if (irq_cnt < SH_DMAC_MAX_CHANNELS) {
+ chan_irq[irq_cnt] = chanirq_res->start;
+ chan_flag[irq_cnt] = IRQF_SHARED;
+ } else {
+ irq_cap = 1;
+ break;
+ }
}
} else {
do {
@@ -1187,22 +1228,32 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
"Found IRQ %d for channel %d\n",
i, irq_cnt);
chan_irq[irq_cnt++] = i;
+
+ if (irq_cnt >= SH_DMAC_MAX_CHANNELS)
+ break;
+ }
+
+ if (irq_cnt >= SH_DMAC_MAX_CHANNELS) {
+ irq_cap = 1;
+ break;
}
chanirq_res = platform_get_resource(pdev,
IORESOURCE_IRQ, ++irqres);
} while (irq_cnt < pdata->channel_num && chanirq_res);
}
- if (irq_cnt < pdata->channel_num)
- goto eirqres;
-
/* Create DMA Channel */
- for (i = 0; i < pdata->channel_num; i++) {
+ for (i = 0; i < irq_cnt; i++) {
err = sh_dmae_chan_probe(shdev, i, chan_irq[i], chan_flag[i]);
if (err)
goto chan_probe_err;
}
+ if (irq_cap)
+ dev_notice(&pdev->dev, "Attempting to register %d DMA "
+ "channels when a maximum of %d are supported.\n",
+ pdata->channel_num, SH_DMAC_MAX_CHANNELS);
+
pm_runtime_put(&pdev->dev);
platform_set_drvdata(pdev, shdev);
@@ -1212,21 +1263,24 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
chan_probe_err:
sh_dmae_chan_remove(shdev);
-eirqres:
+
#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
free_irq(errirq, shdev);
eirq_err:
#endif
rst_err:
- spin_lock_irqsave(&sh_dmae_lock, flags);
+ spin_lock_irq(&sh_dmae_lock);
list_del_rcu(&shdev->node);
- spin_unlock_irqrestore(&sh_dmae_lock, flags);
+ spin_unlock_irq(&sh_dmae_lock);
pm_runtime_put(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
if (dmars)
iounmap(shdev->dmars);
emapdmars:
iounmap(shdev->chan_reg);
+ synchronize_rcu();
emapchan:
kfree(shdev);
ealloc:
@@ -1242,7 +1296,6 @@ static int __exit sh_dmae_remove(struct platform_device *pdev)
{
struct sh_dmae_device *shdev = platform_get_drvdata(pdev);
struct resource *res;
- unsigned long flags;
int errirq = platform_get_irq(pdev, 0);
dma_async_device_unregister(&shdev->common);
@@ -1250,9 +1303,9 @@ static int __exit sh_dmae_remove(struct platform_device *pdev)
if (errirq > 0)
free_irq(errirq, shdev);
- spin_lock_irqsave(&sh_dmae_lock, flags);
+ spin_lock_irq(&sh_dmae_lock);
list_del_rcu(&shdev->node);
- spin_unlock_irqrestore(&sh_dmae_lock, flags);
+ spin_unlock_irq(&sh_dmae_lock);
/* channel data remove */
sh_dmae_chan_remove(shdev);
@@ -1263,6 +1316,7 @@ static int __exit sh_dmae_remove(struct platform_device *pdev)
iounmap(shdev->dmars);
iounmap(shdev->chan_reg);
+ synchronize_rcu();
kfree(shdev);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1281,12 +1335,78 @@ static void sh_dmae_shutdown(struct platform_device *pdev)
sh_dmae_ctl_stop(shdev);
}
+static int sh_dmae_runtime_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int sh_dmae_runtime_resume(struct device *dev)
+{
+ struct sh_dmae_device *shdev = dev_get_drvdata(dev);
+
+ return sh_dmae_rst(shdev);
+}
+
+#ifdef CONFIG_PM
+static int sh_dmae_suspend(struct device *dev)
+{
+ struct sh_dmae_device *shdev = dev_get_drvdata(dev);
+ int i;
+
+ for (i = 0; i < shdev->pdata->channel_num; i++) {
+ struct sh_dmae_chan *sh_chan = shdev->chan[i];
+ if (sh_chan->descs_allocated)
+ sh_chan->pm_error = pm_runtime_put_sync(dev);
+ }
+
+ return 0;
+}
+
+static int sh_dmae_resume(struct device *dev)
+{
+ struct sh_dmae_device *shdev = dev_get_drvdata(dev);
+ int i;
+
+ for (i = 0; i < shdev->pdata->channel_num; i++) {
+ struct sh_dmae_chan *sh_chan = shdev->chan[i];
+ struct sh_dmae_slave *param = sh_chan->common.private;
+
+ if (!sh_chan->descs_allocated)
+ continue;
+
+ if (!sh_chan->pm_error)
+ pm_runtime_get_sync(dev);
+
+ if (param) {
+ const struct sh_dmae_slave_config *cfg = param->config;
+ dmae_set_dmars(sh_chan, cfg->mid_rid);
+ dmae_set_chcr(sh_chan, cfg->chcr);
+ } else {
+ dmae_init(sh_chan);
+ }
+ }
+
+ return 0;
+}
+#else
+#define sh_dmae_suspend NULL
+#define sh_dmae_resume NULL
+#endif
+
+const struct dev_pm_ops sh_dmae_pm = {
+ .suspend = sh_dmae_suspend,
+ .resume = sh_dmae_resume,
+ .runtime_suspend = sh_dmae_runtime_suspend,
+ .runtime_resume = sh_dmae_runtime_resume,
+};
+
static struct platform_driver sh_dmae_driver = {
.remove = __exit_p(sh_dmae_remove),
.shutdown = sh_dmae_shutdown,
.driver = {
.owner = THIS_MODULE,
.name = "sh-dma-engine",
+ .pm = &sh_dmae_pm,
},
};
diff --git a/drivers/dma/shdma.h b/drivers/dma/shdma.h
index 52e4fb173805..5ae9fc512180 100644
--- a/drivers/dma/shdma.h
+++ b/drivers/dma/shdma.h
@@ -17,7 +17,7 @@
#include <linux/interrupt.h>
#include <linux/list.h>
-#define SH_DMAC_MAX_CHANNELS 6
+#define SH_DMAC_MAX_CHANNELS 20
#define SH_DMA_SLAVE_NUMBER 256
#define SH_DMA_TCR_MAX 0x00FFFFFF /* 16MB */
@@ -37,6 +37,7 @@ struct sh_dmae_chan {
int id; /* Raw id of this channel */
u32 __iomem *base;
char dev_id[16]; /* unique name per DMAC of channel */
+ int pm_error;
};
struct sh_dmae_device {
diff --git a/drivers/dma/timb_dma.c b/drivers/dma/timb_dma.c
index d2c75feff7df..f69f90a61873 100644
--- a/drivers/dma/timb_dma.c
+++ b/drivers/dma/timb_dma.c
@@ -27,7 +27,6 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/mfd/core.h>
#include <linux/slab.h>
#include <linux/timb_dma.h>
@@ -685,7 +684,7 @@ static irqreturn_t td_irq(int irq, void *devid)
static int __devinit td_probe(struct platform_device *pdev)
{
- struct timb_dma_platform_data *pdata = mfd_get_data(pdev);
+ struct timb_dma_platform_data *pdata = pdev->dev.platform_data;
struct timb_dma *td;
struct resource *iomem;
int irq;
diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c
index cace0a7b707a..e47e73bbbcc5 100644
--- a/drivers/edac/amd76x_edac.c
+++ b/drivers/edac/amd76x_edac.c
@@ -19,7 +19,7 @@
#include <linux/edac.h>
#include "edac_core.h"
-#define AMD76X_REVISION " Ver: 2.0.2 " __DATE__
+#define AMD76X_REVISION " Ver: 2.0.2"
#define EDAC_MOD_STR "amd76x_edac"
#define amd76x_printk(level, fmt, arg...) \
diff --git a/drivers/edac/amd8111_edac.c b/drivers/edac/amd8111_edac.c
index 35b78d04bbfa..ddd890052ce2 100644
--- a/drivers/edac/amd8111_edac.c
+++ b/drivers/edac/amd8111_edac.c
@@ -33,7 +33,7 @@
#include "edac_module.h"
#include "amd8111_edac.h"
-#define AMD8111_EDAC_REVISION " Ver: 1.0.0 " __DATE__
+#define AMD8111_EDAC_REVISION " Ver: 1.0.0"
#define AMD8111_EDAC_MOD_STR "amd8111_edac"
#define PCI_DEVICE_ID_AMD_8111_PCI 0x7460
diff --git a/drivers/edac/amd8131_edac.c b/drivers/edac/amd8131_edac.c
index b432d60c622a..a5c680561c73 100644
--- a/drivers/edac/amd8131_edac.c
+++ b/drivers/edac/amd8131_edac.c
@@ -33,7 +33,7 @@
#include "edac_module.h"
#include "amd8131_edac.h"
-#define AMD8131_EDAC_REVISION " Ver: 1.0.0 " __DATE__
+#define AMD8131_EDAC_REVISION " Ver: 1.0.0"
#define AMD8131_EDAC_MOD_STR "amd8131_edac"
/* Wrapper functions for accessing PCI configuration space */
diff --git a/drivers/edac/cpc925_edac.c b/drivers/edac/cpc925_edac.c
index 837ad8f85b48..a687a0d16962 100644
--- a/drivers/edac/cpc925_edac.c
+++ b/drivers/edac/cpc925_edac.c
@@ -30,7 +30,7 @@
#include "edac_core.h"
#include "edac_module.h"
-#define CPC925_EDAC_REVISION " Ver: 1.0.0 " __DATE__
+#define CPC925_EDAC_REVISION " Ver: 1.0.0"
#define CPC925_EDAC_MOD_STR "cpc925_edac"
#define cpc925_printk(level, fmt, arg...) \
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index ec302d426589..1af531a11d21 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
@@ -24,7 +24,7 @@
#include <linux/edac.h>
#include "edac_core.h"
-#define E752X_REVISION " Ver: 2.0.2 " __DATE__
+#define E752X_REVISION " Ver: 2.0.2"
#define EDAC_MOD_STR "e752x_edac"
static int report_non_memory_errors;
diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c
index 1731d7245816..6ffb6d23281f 100644
--- a/drivers/edac/e7xxx_edac.c
+++ b/drivers/edac/e7xxx_edac.c
@@ -29,7 +29,7 @@
#include <linux/edac.h>
#include "edac_core.h"
-#define E7XXX_REVISION " Ver: 2.0.2 " __DATE__
+#define E7XXX_REVISION " Ver: 2.0.2"
#define EDAC_MOD_STR "e7xxx_edac"
#define e7xxx_printk(level, fmt, arg...) \
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h
index eefa3501916b..55b8278bb172 100644
--- a/drivers/edac/edac_core.h
+++ b/drivers/edac/edac_core.h
@@ -421,10 +421,6 @@ struct mem_ctl_info {
u32 ce_count; /* Total Correctable Errors for this MC */
unsigned long start_time; /* mci load start time (in jiffies) */
- /* this stuff is for safe removal of mc devices from global list while
- * NMI handlers may be traversing list
- */
- struct rcu_head rcu;
struct completion complete;
/* edac sysfs device control */
@@ -620,10 +616,6 @@ struct edac_device_ctl_info {
unsigned long start_time; /* edac_device load start time (jiffies) */
- /* these are for safe removal of mc devices from global list while
- * NMI handlers may be traversing list
- */
- struct rcu_head rcu;
struct completion removal_complete;
/* sysfs top name under 'edac' directory
@@ -722,10 +714,6 @@ struct edac_pci_ctl_info {
unsigned long start_time; /* edac_pci load start time (jiffies) */
- /* these are for safe removal of devices from global list while
- * NMI handlers may be traversing list
- */
- struct rcu_head rcu;
struct completion complete;
/* sysfs top name under 'edac' directory
diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c
index a7408cf86f37..c3f67437afb6 100644
--- a/drivers/edac/edac_device.c
+++ b/drivers/edac/edac_device.c
@@ -346,30 +346,18 @@ fail1:
}
/*
- * complete_edac_device_list_del
- *
- * callback function when reference count is zero
- */
-static void complete_edac_device_list_del(struct rcu_head *head)
-{
- struct edac_device_ctl_info *edac_dev;
-
- edac_dev = container_of(head, struct edac_device_ctl_info, rcu);
- INIT_LIST_HEAD(&edac_dev->link);
-}
-
-/*
* del_edac_device_from_global_list
- *
- * remove the RCU, setup for a callback call,
- * then wait for the callback to occur
*/
static void del_edac_device_from_global_list(struct edac_device_ctl_info
*edac_device)
{
list_del_rcu(&edac_device->link);
- call_rcu(&edac_device->rcu, complete_edac_device_list_del);
- rcu_barrier();
+
+ /* these are for safe removal of devices from global list while
+ * NMI handlers may be traversing list
+ */
+ synchronize_rcu();
+ INIT_LIST_HEAD(&edac_device->link);
}
/*
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 1d8056049072..d69144a09043 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -447,20 +447,16 @@ fail1:
return 1;
}
-static void complete_mc_list_del(struct rcu_head *head)
-{
- struct mem_ctl_info *mci;
-
- mci = container_of(head, struct mem_ctl_info, rcu);
- INIT_LIST_HEAD(&mci->link);
-}
-
static void del_mc_from_global_list(struct mem_ctl_info *mci)
{
atomic_dec(&edac_handlers);
list_del_rcu(&mci->link);
- call_rcu(&mci->rcu, complete_mc_list_del);
- rcu_barrier();
+
+ /* these are for safe removal of devices from global list while
+ * NMI handlers may be traversing list
+ */
+ synchronize_rcu();
+ INIT_LIST_HEAD(&mci->link);
}
/**
diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c
index be4b075c3098..5ddaa86d6a6e 100644
--- a/drivers/edac/edac_module.c
+++ b/drivers/edac/edac_module.c
@@ -15,7 +15,7 @@
#include "edac_core.h"
#include "edac_module.h"
-#define EDAC_VERSION "Ver: 2.1.0 " __DATE__
+#define EDAC_VERSION "Ver: 2.1.0"
#ifdef CONFIG_EDAC_DEBUG
/* Values of 0 to 4 will generate output */
diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c
index efb5d5650783..2b378207d571 100644
--- a/drivers/edac/edac_pci.c
+++ b/drivers/edac/edac_pci.c
@@ -164,19 +164,6 @@ fail1:
}
/*
- * complete_edac_pci_list_del
- *
- * RCU completion callback to indicate item is deleted
- */
-static void complete_edac_pci_list_del(struct rcu_head *head)
-{
- struct edac_pci_ctl_info *pci;
-
- pci = container_of(head, struct edac_pci_ctl_info, rcu);
- INIT_LIST_HEAD(&pci->link);
-}
-
-/*
* del_edac_pci_from_global_list
*
* remove the PCI control struct from the global list
@@ -184,8 +171,12 @@ static void complete_edac_pci_list_del(struct rcu_head *head)
static void del_edac_pci_from_global_list(struct edac_pci_ctl_info *pci)
{
list_del_rcu(&pci->link);
- call_rcu(&pci->rcu, complete_edac_pci_list_del);
- rcu_barrier();
+
+ /* these are for safe removal of devices from global list while
+ * NMI handlers may be traversing list
+ */
+ synchronize_rcu();
+ INIT_LIST_HEAD(&pci->link);
}
#if 0
diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c
index d41f9002da45..aa08497a075a 100644
--- a/drivers/edac/i3200_edac.c
+++ b/drivers/edac/i3200_edac.c
@@ -101,6 +101,19 @@ struct i3200_priv {
static int nr_channels;
+#ifndef readq
+static inline __u64 readq(const volatile void __iomem *addr)
+{
+ const volatile u32 __iomem *p = addr;
+ u32 low, high;
+
+ low = readl(p);
+ high = readl(p + 1);
+
+ return low + ((u64)high << 32);
+}
+#endif
+
static int how_many_channels(struct pci_dev *pdev)
{
unsigned char capid0_8b; /* 8th byte of CAPID0 */
diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c
index 87f427c2ce5c..4dc3ac25a422 100644
--- a/drivers/edac/i5000_edac.c
+++ b/drivers/edac/i5000_edac.c
@@ -27,7 +27,7 @@
/*
* Alter this version for the I5000 module when modifications are made
*/
-#define I5000_REVISION " Ver: 2.0.12 " __DATE__
+#define I5000_REVISION " Ver: 2.0.12"
#define EDAC_MOD_STR "i5000_edac"
#define i5000_printk(level, fmt, arg...) \
diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c
index 80a465efbae8..74d6ec342afb 100644
--- a/drivers/edac/i5400_edac.c
+++ b/drivers/edac/i5400_edac.c
@@ -33,7 +33,7 @@
/*
* Alter this version for the I5400 module when modifications are made
*/
-#define I5400_REVISION " Ver: 1.0.0 " __DATE__
+#define I5400_REVISION " Ver: 1.0.0"
#define EDAC_MOD_STR "i5400_edac"
diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c
index 363cc1602944..a76fe8366b68 100644
--- a/drivers/edac/i7300_edac.c
+++ b/drivers/edac/i7300_edac.c
@@ -31,7 +31,7 @@
/*
* Alter this version for the I7300 module when modifications are made
*/
-#define I7300_REVISION " Ver: 1.0.0 " __DATE__
+#define I7300_REVISION " Ver: 1.0.0"
#define EDAC_MOD_STR "i7300_edac"
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
index 465cbc25149f..04f1e7ce02b1 100644
--- a/drivers/edac/i7core_edac.c
+++ b/drivers/edac/i7core_edac.c
@@ -59,7 +59,7 @@ MODULE_PARM_DESC(use_pci_fixup, "Enable PCI fixup to seek for hidden devices");
/*
* Alter this version for the module when modifications are made
*/
-#define I7CORE_REVISION " Ver: 1.0.0 " __DATE__
+#define I7CORE_REVISION " Ver: 1.0.0"
#define EDAC_MOD_STR "i7core_edac"
/*
diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c
index b8a95cf50718..931a05775049 100644
--- a/drivers/edac/i82860_edac.c
+++ b/drivers/edac/i82860_edac.c
@@ -16,7 +16,7 @@
#include <linux/edac.h>
#include "edac_core.h"
-#define I82860_REVISION " Ver: 2.0.2 " __DATE__
+#define I82860_REVISION " Ver: 2.0.2"
#define EDAC_MOD_STR "i82860_edac"
#define i82860_printk(level, fmt, arg...) \
diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c
index b2fd1e899142..33864c63c684 100644
--- a/drivers/edac/i82875p_edac.c
+++ b/drivers/edac/i82875p_edac.c
@@ -20,7 +20,7 @@
#include <linux/edac.h>
#include "edac_core.h"
-#define I82875P_REVISION " Ver: 2.0.2 " __DATE__
+#define I82875P_REVISION " Ver: 2.0.2"
#define EDAC_MOD_STR "i82875p_edac"
#define i82875p_printk(level, fmt, arg...) \
diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c
index 92e65e7038e9..a5da732fe5b2 100644
--- a/drivers/edac/i82975x_edac.c
+++ b/drivers/edac/i82975x_edac.c
@@ -16,7 +16,7 @@
#include <linux/edac.h>
#include "edac_core.h"
-#define I82975X_REVISION " Ver: 1.0.0 " __DATE__
+#define I82975X_REVISION " Ver: 1.0.0"
#define EDAC_MOD_STR "i82975x_edac"
#define i82975x_printk(level, fmt, arg...) \
diff --git a/drivers/edac/mpc85xx_edac.h b/drivers/edac/mpc85xx_edac.h
index cb24df839460..932016f2cf06 100644
--- a/drivers/edac/mpc85xx_edac.h
+++ b/drivers/edac/mpc85xx_edac.h
@@ -11,7 +11,7 @@
#ifndef _MPC85XX_EDAC_H_
#define _MPC85XX_EDAC_H_
-#define MPC85XX_REVISION " Ver: 2.0.0 " __DATE__
+#define MPC85XX_REVISION " Ver: 2.0.0"
#define EDAC_MOD_STR "MPC85xx_edac"
#define mpc85xx_printk(level, fmt, arg...) \
diff --git a/drivers/edac/mv64x60_edac.h b/drivers/edac/mv64x60_edac.h
index e042e2daa8f4..c7f209c92a1a 100644
--- a/drivers/edac/mv64x60_edac.h
+++ b/drivers/edac/mv64x60_edac.h
@@ -12,7 +12,7 @@
#ifndef _MV64X60_EDAC_H_
#define _MV64X60_EDAC_H_
-#define MV64x60_REVISION " Ver: 2.0.0 " __DATE__
+#define MV64x60_REVISION " Ver: 2.0.0"
#define EDAC_MOD_STR "MV64x60_edac"
#define mv64x60_printk(level, fmt, arg...) \
diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c
index af8e7b1aa290..0de7d8770891 100644
--- a/drivers/edac/ppc4xx_edac.c
+++ b/drivers/edac/ppc4xx_edac.c
@@ -113,7 +113,7 @@
#define EDAC_OPSTATE_UNKNOWN_STR "unknown"
#define PPC4XX_EDAC_MODULE_NAME "ppc4xx_edac"
-#define PPC4XX_EDAC_MODULE_REVISION "v1.0.0 " __DATE__
+#define PPC4XX_EDAC_MODULE_REVISION "v1.0.0"
#define PPC4XX_EDAC_MESSAGE_SIZE 256
diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c
index 678513738c33..b153674431f1 100644
--- a/drivers/edac/r82600_edac.c
+++ b/drivers/edac/r82600_edac.c
@@ -22,7 +22,7 @@
#include <linux/edac.h>
#include "edac_core.h"
-#define R82600_REVISION " Ver: 2.0.2 " __DATE__
+#define R82600_REVISION " Ver: 2.0.2"
#define EDAC_MOD_STR "r82600_edac"
#define r82600_printk(level, fmt, arg...) \
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
index 3c44fbc81acb..29d2423fae6d 100644
--- a/drivers/firewire/core-card.c
+++ b/drivers/firewire/core-card.c
@@ -228,8 +228,8 @@ void fw_schedule_bus_reset(struct fw_card *card, bool delayed, bool 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))
+ if (!queue_delayed_work(fw_workqueue, &card->br_work,
+ delayed ? DIV_ROUND_UP(HZ, 100) : 0))
fw_card_put(card);
}
EXPORT_SYMBOL(fw_schedule_bus_reset);
@@ -241,7 +241,7 @@ static void br_work(struct work_struct *work)
/* Delay for 2s after last reset per IEEE 1394 clause 8.2.1. */
if (card->reset_jiffies != 0 &&
time_before64(get_jiffies_64(), card->reset_jiffies + 2 * HZ)) {
- if (!schedule_delayed_work(&card->br_work, 2 * HZ))
+ if (!queue_delayed_work(fw_workqueue, &card->br_work, 2 * HZ))
fw_card_put(card);
return;
}
@@ -258,8 +258,7 @@ static void allocate_broadcast_channel(struct fw_card *card, int generation)
if (!card->broadcast_channel_allocated) {
fw_iso_resource_manage(card, generation, 1ULL << 31,
- &channel, &bandwidth, true,
- card->bm_transaction_data);
+ &channel, &bandwidth, true);
if (channel != 31) {
fw_notify("failed to allocate broadcast channel\n");
return;
@@ -294,6 +293,7 @@ static void bm_work(struct work_struct *work)
bool root_device_is_cmc;
bool irm_is_1394_1995_only;
bool keep_this_irm;
+ __be32 transaction_data[2];
spin_lock_irq(&card->lock);
@@ -355,21 +355,21 @@ static void bm_work(struct work_struct *work)
goto pick_me;
}
- card->bm_transaction_data[0] = cpu_to_be32(0x3f);
- card->bm_transaction_data[1] = cpu_to_be32(local_id);
+ transaction_data[0] = cpu_to_be32(0x3f);
+ transaction_data[1] = cpu_to_be32(local_id);
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, 8);
+ transaction_data, 8);
if (rcode == RCODE_GENERATION)
/* Another bus reset, BM work has been rescheduled. */
goto out;
- bm_id = be32_to_cpu(card->bm_transaction_data[0]);
+ bm_id = be32_to_cpu(transaction_data[0]);
spin_lock_irq(&card->lock);
if (rcode == RCODE_COMPLETE && generation == card->generation)
@@ -490,11 +490,11 @@ static void bm_work(struct work_struct *work)
/*
* Make sure that the cycle master sends cycle start packets.
*/
- card->bm_transaction_data[0] = cpu_to_be32(CSR_STATE_BIT_CMSTR);
+ 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);
+ transaction_data, 4);
if (rcode == RCODE_GENERATION)
goto out;
}
@@ -630,6 +630,10 @@ static int dummy_queue_iso(struct fw_iso_context *ctx, struct fw_iso_packet *p,
return -ENODEV;
}
+static void dummy_flush_queue_iso(struct fw_iso_context *ctx)
+{
+}
+
static const struct fw_card_driver dummy_driver_template = {
.read_phy_reg = dummy_read_phy_reg,
.update_phy_reg = dummy_update_phy_reg,
@@ -641,6 +645,7 @@ static const struct fw_card_driver dummy_driver_template = {
.start_iso = dummy_start_iso,
.set_iso_channels = dummy_set_iso_channels,
.queue_iso = dummy_queue_iso,
+ .flush_queue_iso = dummy_flush_queue_iso,
};
void fw_card_release(struct kref *kref)
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index 62ac111af243..b1c11775839c 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -141,7 +141,6 @@ struct iso_resource {
int generation;
u64 channels;
s32 bandwidth;
- __be32 transaction_data[2];
struct iso_resource_event *e_alloc, *e_dealloc;
};
@@ -150,7 +149,7 @@ static void release_iso_resource(struct client *, struct client_resource *);
static void schedule_iso_resource(struct iso_resource *r, unsigned long delay)
{
client_get(r->client);
- if (!schedule_delayed_work(&r->work, delay))
+ if (!queue_delayed_work(fw_workqueue, &r->work, delay))
client_put(r->client);
}
@@ -1108,6 +1107,7 @@ static int ioctl_queue_iso(struct client *client, union ioctl_arg *arg)
payload += u.packet.payload_length;
count++;
}
+ fw_iso_context_queue_flush(ctx);
a->size -= uptr_to_u64(p) - a->packets;
a->packets = uptr_to_u64(p);
@@ -1229,8 +1229,7 @@ static void iso_resource_work(struct work_struct *work)
r->channels, &channel, &bandwidth,
todo == ISO_RES_ALLOC ||
todo == ISO_RES_REALLOC ||
- todo == ISO_RES_ALLOC_ONCE,
- r->transaction_data);
+ todo == ISO_RES_ALLOC_ONCE);
/*
* Is this generation outdated already? As long as this resource sticks
* in the idr, it will be scheduled again for a newer generation or at
diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c
index 9a262439e3a7..95a471401892 100644
--- a/drivers/firewire/core-device.c
+++ b/drivers/firewire/core-device.c
@@ -725,6 +725,15 @@ struct fw_device *fw_device_get_by_devt(dev_t devt)
return device;
}
+struct workqueue_struct *fw_workqueue;
+EXPORT_SYMBOL(fw_workqueue);
+
+static void fw_schedule_device_work(struct fw_device *device,
+ unsigned long delay)
+{
+ queue_delayed_work(fw_workqueue, &device->work, delay);
+}
+
/*
* These defines control the retry behavior for reading the config
* rom. It shouldn't be necessary to tweak these; if the device
@@ -750,7 +759,7 @@ static void fw_device_shutdown(struct work_struct *work)
if (time_before64(get_jiffies_64(),
device->card->reset_jiffies + SHUTDOWN_DELAY)
&& !list_empty(&device->card->link)) {
- schedule_delayed_work(&device->work, SHUTDOWN_DELAY);
+ fw_schedule_device_work(device, SHUTDOWN_DELAY);
return;
}
@@ -862,7 +871,7 @@ static int lookup_existing_device(struct device *dev, void *data)
fw_notify("rediscovered device %s\n", dev_name(dev));
PREPARE_DELAYED_WORK(&old->work, fw_device_update);
- schedule_delayed_work(&old->work, 0);
+ fw_schedule_device_work(old, 0);
if (current_node == card->root_node)
fw_schedule_bm_work(card, 0);
@@ -953,7 +962,7 @@ static void fw_device_init(struct work_struct *work)
if (device->config_rom_retries < MAX_RETRIES &&
atomic_read(&device->state) == FW_DEVICE_INITIALIZING) {
device->config_rom_retries++;
- schedule_delayed_work(&device->work, RETRY_DELAY);
+ fw_schedule_device_work(device, RETRY_DELAY);
} else {
if (device->node->link_on)
fw_notify("giving up on config rom for node id %x\n",
@@ -1019,7 +1028,7 @@ static void fw_device_init(struct work_struct *work)
FW_DEVICE_INITIALIZING,
FW_DEVICE_RUNNING) == FW_DEVICE_GONE) {
PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
- schedule_delayed_work(&device->work, SHUTDOWN_DELAY);
+ fw_schedule_device_work(device, SHUTDOWN_DELAY);
} else {
if (device->config_rom_retries)
fw_notify("created device %s: GUID %08x%08x, S%d00, "
@@ -1098,7 +1107,7 @@ static void fw_device_refresh(struct work_struct *work)
if (device->config_rom_retries < MAX_RETRIES / 2 &&
atomic_read(&device->state) == FW_DEVICE_INITIALIZING) {
device->config_rom_retries++;
- schedule_delayed_work(&device->work, RETRY_DELAY / 2);
+ fw_schedule_device_work(device, RETRY_DELAY / 2);
return;
}
@@ -1131,7 +1140,7 @@ static void fw_device_refresh(struct work_struct *work)
if (device->config_rom_retries < MAX_RETRIES &&
atomic_read(&device->state) == FW_DEVICE_INITIALIZING) {
device->config_rom_retries++;
- schedule_delayed_work(&device->work, RETRY_DELAY);
+ fw_schedule_device_work(device, RETRY_DELAY);
return;
}
@@ -1158,7 +1167,7 @@ static void fw_device_refresh(struct work_struct *work)
gone:
atomic_set(&device->state, FW_DEVICE_GONE);
PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
- schedule_delayed_work(&device->work, SHUTDOWN_DELAY);
+ fw_schedule_device_work(device, SHUTDOWN_DELAY);
out:
if (node_id == card->root_node->node_id)
fw_schedule_bm_work(card, 0);
@@ -1214,7 +1223,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
* first config rom scan half a second after bus reset.
*/
INIT_DELAYED_WORK(&device->work, fw_device_init);
- schedule_delayed_work(&device->work, INITIAL_DELAY);
+ fw_schedule_device_work(device, INITIAL_DELAY);
break;
case FW_NODE_INITIATED_RESET:
@@ -1230,7 +1239,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
FW_DEVICE_RUNNING,
FW_DEVICE_INITIALIZING) == FW_DEVICE_RUNNING) {
PREPARE_DELAYED_WORK(&device->work, fw_device_refresh);
- schedule_delayed_work(&device->work,
+ fw_schedule_device_work(device,
device->is_local ? 0 : INITIAL_DELAY);
}
break;
@@ -1245,7 +1254,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
device->generation = card->generation;
if (atomic_read(&device->state) == FW_DEVICE_RUNNING) {
PREPARE_DELAYED_WORK(&device->work, fw_device_update);
- schedule_delayed_work(&device->work, 0);
+ fw_schedule_device_work(device, 0);
}
break;
@@ -1270,7 +1279,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
if (atomic_xchg(&device->state,
FW_DEVICE_GONE) == FW_DEVICE_RUNNING) {
PREPARE_DELAYED_WORK(&device->work, fw_device_shutdown);
- schedule_delayed_work(&device->work,
+ fw_schedule_device_work(device,
list_empty(&card->link) ? 0 : SHUTDOWN_DELAY);
}
break;
diff --git a/drivers/firewire/core-iso.c b/drivers/firewire/core-iso.c
index 481056df9268..57c3973093ad 100644
--- a/drivers/firewire/core-iso.c
+++ b/drivers/firewire/core-iso.c
@@ -185,6 +185,12 @@ int fw_iso_context_queue(struct fw_iso_context *ctx,
}
EXPORT_SYMBOL(fw_iso_context_queue);
+void fw_iso_context_queue_flush(struct fw_iso_context *ctx)
+{
+ ctx->card->driver->flush_queue_iso(ctx);
+}
+EXPORT_SYMBOL(fw_iso_context_queue_flush);
+
int fw_iso_context_stop(struct fw_iso_context *ctx)
{
return ctx->card->driver->stop_iso(ctx);
@@ -196,9 +202,10 @@ EXPORT_SYMBOL(fw_iso_context_stop);
*/
static int manage_bandwidth(struct fw_card *card, int irm_id, int generation,
- int bandwidth, bool allocate, __be32 data[2])
+ int bandwidth, bool allocate)
{
int try, new, old = allocate ? BANDWIDTH_AVAILABLE_INITIAL : 0;
+ __be32 data[2];
/*
* On a 1394a IRM with low contention, try < 1 is enough.
@@ -233,9 +240,10 @@ static int manage_bandwidth(struct fw_card *card, int irm_id, int generation,
}
static int manage_channel(struct fw_card *card, int irm_id, int generation,
- u32 channels_mask, u64 offset, bool allocate, __be32 data[2])
+ u32 channels_mask, u64 offset, bool allocate)
{
__be32 bit, all, old;
+ __be32 data[2];
int channel, ret = -EIO, retry = 5;
old = all = allocate ? cpu_to_be32(~0) : 0;
@@ -284,7 +292,7 @@ static int manage_channel(struct fw_card *card, int irm_id, int generation,
}
static void deallocate_channel(struct fw_card *card, int irm_id,
- int generation, int channel, __be32 buffer[2])
+ int generation, int channel)
{
u32 mask;
u64 offset;
@@ -293,7 +301,7 @@ static void deallocate_channel(struct fw_card *card, int irm_id,
offset = channel < 32 ? CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI :
CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO;
- manage_channel(card, irm_id, generation, mask, offset, false, buffer);
+ manage_channel(card, irm_id, generation, mask, offset, false);
}
/**
@@ -322,7 +330,7 @@ static void deallocate_channel(struct fw_card *card, int irm_id,
*/
void fw_iso_resource_manage(struct fw_card *card, int generation,
u64 channels_mask, int *channel, int *bandwidth,
- bool allocate, __be32 buffer[2])
+ bool allocate)
{
u32 channels_hi = channels_mask; /* channels 31...0 */
u32 channels_lo = channels_mask >> 32; /* channels 63...32 */
@@ -335,11 +343,11 @@ void fw_iso_resource_manage(struct fw_card *card, int generation,
if (channels_hi)
c = manage_channel(card, irm_id, generation, channels_hi,
CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_HI,
- allocate, buffer);
+ allocate);
if (channels_lo && c < 0) {
c = manage_channel(card, irm_id, generation, channels_lo,
CSR_REGISTER_BASE + CSR_CHANNELS_AVAILABLE_LO,
- allocate, buffer);
+ allocate);
if (c >= 0)
c += 32;
}
@@ -351,14 +359,13 @@ void fw_iso_resource_manage(struct fw_card *card, int generation,
if (*bandwidth == 0)
return;
- ret = manage_bandwidth(card, irm_id, generation, *bandwidth,
- allocate, buffer);
+ ret = manage_bandwidth(card, irm_id, generation, *bandwidth, allocate);
if (ret < 0)
*bandwidth = 0;
if (allocate && ret < 0) {
if (c >= 0)
- deallocate_channel(card, irm_id, generation, c, buffer);
+ deallocate_channel(card, irm_id, generation, c);
*channel = ret;
}
}
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index d00f8ce902cc..334b82a3542c 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -36,6 +36,7 @@
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/types.h>
+#include <linux/workqueue.h>
#include <asm/byteorder.h>
@@ -326,8 +327,8 @@ static int allocate_tlabel(struct fw_card *card)
* 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
+ * @length <= 8 or of local (loopback) requests. Hence make sure that the
+ * buffer complies with the restrictions of the streaming DMA mapping API.
* @payload must not be freed before the @callback is called.
*
* In case of request types without payload, @data is NULL and @length is 0.
@@ -411,7 +412,8 @@ static void transaction_callback(struct fw_card *card, int 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.
+ * to the payload of the response. DMA mapping restrictions apply to outbound
+ * request payloads of >= 8 bytes but not to inbound response payloads.
*/
int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
int generation, int speed, unsigned long long offset,
@@ -1212,13 +1214,21 @@ static int __init fw_core_init(void)
{
int ret;
+ fw_workqueue = alloc_workqueue("firewire",
+ WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0);
+ if (!fw_workqueue)
+ return -ENOMEM;
+
ret = bus_register(&fw_bus_type);
- if (ret < 0)
+ if (ret < 0) {
+ destroy_workqueue(fw_workqueue);
return ret;
+ }
fw_cdev_major = register_chrdev(0, "firewire", &fw_device_ops);
if (fw_cdev_major < 0) {
bus_unregister(&fw_bus_type);
+ destroy_workqueue(fw_workqueue);
return fw_cdev_major;
}
@@ -1234,6 +1244,7 @@ static void __exit fw_core_cleanup(void)
{
unregister_chrdev(fw_cdev_major, "firewire");
bus_unregister(&fw_bus_type);
+ destroy_workqueue(fw_workqueue);
idr_destroy(&fw_device_idr);
}
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h
index 25e729cde2f7..0fe4e4e6eda7 100644
--- a/drivers/firewire/core.h
+++ b/drivers/firewire/core.h
@@ -97,6 +97,8 @@ struct fw_card_driver {
struct fw_iso_buffer *buffer,
unsigned long payload);
+ void (*flush_queue_iso)(struct fw_iso_context *ctx);
+
int (*stop_iso)(struct fw_iso_context *ctx);
};
diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c
index 3f04dd3681cf..b9762d07198d 100644
--- a/drivers/firewire/net.c
+++ b/drivers/firewire/net.c
@@ -881,7 +881,9 @@ static void fwnet_receive_broadcast(struct fw_iso_context *context,
spin_unlock_irqrestore(&dev->lock, flags);
- if (retval < 0)
+ if (retval >= 0)
+ fw_iso_context_queue_flush(dev->broadcast_rcv_context);
+ else
fw_error("requeue failed\n");
}
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 23d1468ad253..438e6c831170 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -1006,13 +1006,12 @@ static void ar_context_run(struct ar_context *ctx)
static struct descriptor *find_branch_descriptor(struct descriptor *d, int z)
{
- int b, key;
+ __le16 branch;
- b = (le16_to_cpu(d->control) & DESCRIPTOR_BRANCH_ALWAYS) >> 2;
- key = (le16_to_cpu(d->control) & DESCRIPTOR_KEY_IMMEDIATE) >> 8;
+ branch = d->control & cpu_to_le16(DESCRIPTOR_BRANCH_ALWAYS);
/* figure out which descriptor the branch address goes in */
- if (z == 2 && (b == 3 || key == 2))
+ if (z == 2 && branch == cpu_to_le16(DESCRIPTOR_BRANCH_ALWAYS))
return d;
else
return d + z - 1;
@@ -1193,9 +1192,6 @@ static void context_append(struct context *ctx,
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);
-
- reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
- flush_writes(ctx->ohci);
}
static void context_stop(struct context *ctx)
@@ -1218,6 +1214,7 @@ static void context_stop(struct context *ctx)
}
struct driver_data {
+ u8 inline_data[8];
struct fw_packet *packet;
};
@@ -1301,20 +1298,28 @@ static int at_context_queue_packet(struct context *ctx,
return -1;
}
+ BUILD_BUG_ON(sizeof(struct driver_data) > sizeof(struct descriptor));
driver_data = (struct driver_data *) &d[3];
driver_data->packet = packet;
packet->driver_data = driver_data;
if (packet->payload_length > 0) {
- payload_bus =
- dma_map_single(ohci->card.device, packet->payload,
- packet->payload_length, DMA_TO_DEVICE);
- if (dma_mapping_error(ohci->card.device, payload_bus)) {
- packet->ack = RCODE_SEND_ERROR;
- return -1;
+ if (packet->payload_length > sizeof(driver_data->inline_data)) {
+ payload_bus = dma_map_single(ohci->card.device,
+ packet->payload,
+ packet->payload_length,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(ohci->card.device, payload_bus)) {
+ packet->ack = RCODE_SEND_ERROR;
+ return -1;
+ }
+ packet->payload_bus = payload_bus;
+ packet->payload_mapped = true;
+ } else {
+ memcpy(driver_data->inline_data, packet->payload,
+ packet->payload_length);
+ payload_bus = d_bus + 3 * sizeof(*d);
}
- packet->payload_bus = payload_bus;
- packet->payload_mapped = true;
d[2].req_count = cpu_to_le16(packet->payload_length);
d[2].data_address = cpu_to_le32(payload_bus);
@@ -1340,8 +1345,12 @@ static int at_context_queue_packet(struct context *ctx,
context_append(ctx, d, z, 4 - z);
- if (!ctx->running)
+ if (ctx->running) {
+ reg_write(ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
+ flush_writes(ohci);
+ } else {
context_run(ctx, 0);
+ }
return 0;
}
@@ -2066,8 +2075,6 @@ static int ohci_enable(struct fw_card *card,
reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->self_id_bus);
reg_write(ohci, OHCI1394_LinkControlSet,
- OHCI1394_LinkControl_rcvSelfID |
- OHCI1394_LinkControl_rcvPhyPkt |
OHCI1394_LinkControl_cycleTimerEnable |
OHCI1394_LinkControl_cycleMaster);
@@ -2094,9 +2101,6 @@ static int ohci_enable(struct fw_card *card,
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);
-
reg_write(ohci, OHCI1394_PhyUpperBound, 0x00010000);
reg_write(ohci, OHCI1394_IntEventClear, ~0);
reg_write(ohci, OHCI1394_IntMaskClear, ~0);
@@ -2186,7 +2190,13 @@ static int ohci_enable(struct fw_card *card,
reg_write(ohci, OHCI1394_HCControlSet,
OHCI1394_HCControl_linkEnable |
OHCI1394_HCControl_BIBimageValid);
- flush_writes(ohci);
+
+ reg_write(ohci, OHCI1394_LinkControlSet,
+ OHCI1394_LinkControl_rcvSelfID |
+ OHCI1394_LinkControl_rcvPhyPkt);
+
+ ar_context_run(&ohci->ar_request_ctx);
+ ar_context_run(&ohci->ar_response_ctx); /* also flushes writes */
/* We are ready to go, reset bus to finish initialization. */
fw_schedule_bus_reset(&ohci->card, false, true);
@@ -3112,6 +3122,15 @@ static int ohci_queue_iso(struct fw_iso_context *base,
return ret;
}
+static void ohci_flush_queue_iso(struct fw_iso_context *base)
+{
+ struct context *ctx =
+ &container_of(base, struct iso_context, base)->context;
+
+ reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE);
+ flush_writes(ctx->ohci);
+}
+
static const struct fw_card_driver ohci_driver = {
.enable = ohci_enable,
.read_phy_reg = ohci_read_phy_reg,
@@ -3128,6 +3147,7 @@ static const struct fw_card_driver ohci_driver = {
.free_iso_context = ohci_free_iso_context,
.set_iso_channels = ohci_set_iso_channels,
.queue_iso = ohci_queue_iso,
+ .flush_queue_iso = ohci_flush_queue_iso,
.start_iso = ohci_start_iso,
.stop_iso = ohci_stop_iso,
};
diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c
index 77ed589b360d..41841a3e3f99 100644
--- a/drivers/firewire/sbp2.c
+++ b/drivers/firewire/sbp2.c
@@ -125,9 +125,6 @@ MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0"
", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)
", or a combination)");
-/* I don't know why the SCSI stack doesn't define something like this... */
-typedef void (*scsi_done_fn_t)(struct scsi_cmnd *);
-
static const char sbp2_driver_name[] = "sbp2";
/*
@@ -261,7 +258,6 @@ struct sbp2_orb {
struct kref kref;
dma_addr_t request_bus;
int rcode;
- struct sbp2_pointer pointer;
void (*callback)(struct sbp2_orb * orb, struct sbp2_status * status);
struct list_head link;
};
@@ -314,7 +310,6 @@ struct sbp2_command_orb {
u8 command_block[SBP2_MAX_CDB_SIZE];
} request;
struct scsi_cmnd *cmd;
- scsi_done_fn_t done;
struct sbp2_logical_unit *lu;
struct sbp2_pointer page_table[SG_ALL] __attribute__((aligned(8)));
@@ -494,10 +489,11 @@ static void sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu,
int node_id, int generation, u64 offset)
{
struct fw_device *device = target_device(lu->tgt);
+ struct sbp2_pointer orb_pointer;
unsigned long flags;
- orb->pointer.high = 0;
- orb->pointer.low = cpu_to_be32(orb->request_bus);
+ orb_pointer.high = 0;
+ orb_pointer.low = cpu_to_be32(orb->request_bus);
spin_lock_irqsave(&device->card->lock, flags);
list_add_tail(&orb->link, &lu->orb_list);
@@ -508,7 +504,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, 8, complete_transaction, orb);
+ &orb_pointer, 8, complete_transaction, orb);
}
static int sbp2_cancel_orbs(struct sbp2_logical_unit *lu)
@@ -830,8 +826,6 @@ static void sbp2_target_put(struct sbp2_target *tgt)
kref_put(&tgt->kref, sbp2_release_target);
}
-static struct workqueue_struct *sbp2_wq;
-
/*
* Always get the target's kref when scheduling work on one its units.
* Each workqueue job is responsible to call sbp2_target_put() upon return.
@@ -839,7 +833,7 @@ static struct workqueue_struct *sbp2_wq;
static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay)
{
sbp2_target_get(lu->tgt);
- if (!queue_delayed_work(sbp2_wq, &lu->work, delay))
+ if (!queue_delayed_work(fw_workqueue, &lu->work, delay))
sbp2_target_put(lu->tgt);
}
@@ -1398,7 +1392,7 @@ static void complete_command_orb(struct sbp2_orb *base_orb,
sbp2_unmap_scatterlist(device->card->device, orb);
orb->cmd->result = result;
- orb->done(orb->cmd);
+ orb->cmd->scsi_done(orb->cmd);
}
static int sbp2_map_scatterlist(struct sbp2_command_orb *orb,
@@ -1463,7 +1457,8 @@ static int sbp2_map_scatterlist(struct sbp2_command_orb *orb,
/* SCSI stack integration */
-static int sbp2_scsi_queuecommand_lck(struct scsi_cmnd *cmd, scsi_done_fn_t done)
+static int sbp2_scsi_queuecommand(struct Scsi_Host *shost,
+ struct scsi_cmnd *cmd)
{
struct sbp2_logical_unit *lu = cmd->device->hostdata;
struct fw_device *device = target_device(lu->tgt);
@@ -1477,7 +1472,7 @@ static int sbp2_scsi_queuecommand_lck(struct scsi_cmnd *cmd, scsi_done_fn_t done
if (cmd->sc_data_direction == DMA_BIDIRECTIONAL) {
fw_error("Can't handle DMA_BIDIRECTIONAL, rejecting command\n");
cmd->result = DID_ERROR << 16;
- done(cmd);
+ cmd->scsi_done(cmd);
return 0;
}
@@ -1490,11 +1485,8 @@ static int sbp2_scsi_queuecommand_lck(struct scsi_cmnd *cmd, scsi_done_fn_t done
/* Initialize rcode to something not RCODE_COMPLETE. */
orb->base.rcode = -1;
kref_init(&orb->base.kref);
-
- orb->lu = lu;
- orb->done = done;
- orb->cmd = cmd;
-
+ orb->lu = lu;
+ orb->cmd = cmd;
orb->request.next.high = cpu_to_be32(SBP2_ORB_NULL);
orb->request.misc = cpu_to_be32(
COMMAND_ORB_MAX_PAYLOAD(lu->tgt->max_payload) |
@@ -1529,8 +1521,6 @@ static int sbp2_scsi_queuecommand_lck(struct scsi_cmnd *cmd, scsi_done_fn_t done
return retval;
}
-static DEF_SCSI_QCMD(sbp2_scsi_queuecommand)
-
static int sbp2_scsi_slave_alloc(struct scsi_device *sdev)
{
struct sbp2_logical_unit *lu = sdev->hostdata;
@@ -1653,17 +1643,12 @@ MODULE_ALIAS("sbp2");
static int __init sbp2_init(void)
{
- sbp2_wq = create_singlethread_workqueue(KBUILD_MODNAME);
- if (!sbp2_wq)
- return -ENOMEM;
-
return driver_register(&sbp2_driver.driver);
}
static void __exit sbp2_cleanup(void)
{
driver_unregister(&sbp2_driver.driver);
- destroy_workqueue(sbp2_wq);
}
module_init(sbp2_init);
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index b3a25a55ba23..efba163595db 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -157,4 +157,6 @@ config SIGMA
If unsure, say N here. Drivers that need these helpers will select
this option automatically.
+source "drivers/firmware/google/Kconfig"
+
endmenu
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 00bb0b80a79f..47338c979126 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -13,3 +13,5 @@ obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o
obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o
obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o
obj-$(CONFIG_SIGMA) += sigma.o
+
+obj-$(CONFIG_GOOGLE_FIRMWARE) += google/
diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c
index 96c25d93eed1..f1b7f659d3c9 100644
--- a/drivers/firmware/edd.c
+++ b/drivers/firmware/edd.c
@@ -531,8 +531,8 @@ static int
edd_has_edd30(struct edd_device *edev)
{
struct edd_info *info;
- int i, nonzero_path = 0;
- char c;
+ int i;
+ u8 csum = 0;
if (!edev)
return 0;
@@ -544,16 +544,16 @@ edd_has_edd30(struct edd_device *edev)
return 0;
}
- for (i = 30; i <= 73; i++) {
- c = *(((uint8_t *) info) + i + 4);
- if (c) {
- nonzero_path++;
- break;
- }
- }
- if (!nonzero_path) {
+
+ /* We support only T13 spec */
+ if (info->params.device_path_info_length != 44)
+ return 0;
+
+ for (i = 30; i < info->params.device_path_info_length + 30; i++)
+ csum += *(((u8 *)&info->params) + i);
+
+ if (csum)
return 0;
- }
return 1;
}
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index ff0c373e3bbf..5f29aafd4462 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -321,7 +321,7 @@ efivar_show_raw(struct efivar_entry *entry, char *buf)
/*
* Generic read/write functions that call the specific functions of
- * the atttributes...
+ * the attributes...
*/
static ssize_t efivar_attr_show(struct kobject *kobj, struct attribute *attr,
char *buf)
@@ -677,8 +677,8 @@ create_efivars_bin_attributes(struct efivars *efivars)
return 0;
out_free:
- kfree(efivars->new_var);
- efivars->new_var = NULL;
+ kfree(efivars->del_var);
+ efivars->del_var = NULL;
kfree(efivars->new_var);
efivars->new_var = NULL;
return error;
@@ -803,6 +803,8 @@ efivars_init(void)
ops.set_variable = efi.set_variable;
ops.get_next_variable = efi.get_next_variable;
error = register_efivars(&__efivars, &ops, efi_kobj);
+ if (error)
+ goto err_put;
/* Don't forget the systab entry */
error = sysfs_create_group(efi_kobj, &efi_subsys_attr_group);
@@ -810,18 +812,25 @@ efivars_init(void)
printk(KERN_ERR
"efivars: Sysfs attribute export failed with error %d.\n",
error);
- unregister_efivars(&__efivars);
- kobject_put(efi_kobj);
+ goto err_unregister;
}
+ return 0;
+
+err_unregister:
+ unregister_efivars(&__efivars);
+err_put:
+ kobject_put(efi_kobj);
return error;
}
static void __exit
efivars_exit(void)
{
- unregister_efivars(&__efivars);
- kobject_put(efi_kobj);
+ if (efi_enabled) {
+ unregister_efivars(&__efivars);
+ kobject_put(efi_kobj);
+ }
}
module_init(efivars_init);
diff --git a/drivers/firmware/google/Kconfig b/drivers/firmware/google/Kconfig
new file mode 100644
index 000000000000..87096b6ca5c9
--- /dev/null
+++ b/drivers/firmware/google/Kconfig
@@ -0,0 +1,31 @@
+config GOOGLE_FIRMWARE
+ bool "Google Firmware Drivers"
+ depends on X86
+ default n
+ help
+ These firmware drivers are used by Google's servers. They are
+ only useful if you are working directly on one of their
+ proprietary servers. If in doubt, say "N".
+
+menu "Google Firmware Drivers"
+ depends on GOOGLE_FIRMWARE
+
+config GOOGLE_SMI
+ tristate "SMI interface for Google platforms"
+ depends on ACPI && DMI
+ select EFI_VARS
+ help
+ Say Y here if you want to enable SMI callbacks for Google
+ platforms. This provides an interface for writing to and
+ clearing the EFI event log and reading and writing NVRAM
+ variables.
+
+config GOOGLE_MEMCONSOLE
+ tristate "Firmware Memory Console"
+ depends on DMI
+ help
+ This option enables the kernel to search for a firmware log in
+ the EBDA on Google servers. If found, this log is exported to
+ userland in the file /sys/firmware/log.
+
+endmenu
diff --git a/drivers/firmware/google/Makefile b/drivers/firmware/google/Makefile
new file mode 100644
index 000000000000..54a294e3cb61
--- /dev/null
+++ b/drivers/firmware/google/Makefile
@@ -0,0 +1,3 @@
+
+obj-$(CONFIG_GOOGLE_SMI) += gsmi.o
+obj-$(CONFIG_GOOGLE_MEMCONSOLE) += memconsole.o
diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c
new file mode 100644
index 000000000000..fa7f0b3e81dd
--- /dev/null
+++ b/drivers/firmware/google/gsmi.c
@@ -0,0 +1,940 @@
+/*
+ * Copyright 2010 Google Inc. All Rights Reserved.
+ * Author: dlaurie@google.com (Duncan Laurie)
+ *
+ * Re-worked to expose sysfs APIs by mikew@google.com (Mike Waychison)
+ *
+ * EFI SMI interface for Google platforms
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/ioctl.h>
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/dmi.h>
+#include <linux/kdebug.h>
+#include <linux/reboot.h>
+#include <linux/efi.h>
+
+#define GSMI_SHUTDOWN_CLEAN 0 /* Clean Shutdown */
+/* TODO(mikew@google.com): Tie in HARDLOCKUP_DETECTOR with NMIWDT */
+#define GSMI_SHUTDOWN_NMIWDT 1 /* NMI Watchdog */
+#define GSMI_SHUTDOWN_PANIC 2 /* Panic */
+#define GSMI_SHUTDOWN_OOPS 3 /* Oops */
+#define GSMI_SHUTDOWN_DIE 4 /* Die -- No longer meaningful */
+#define GSMI_SHUTDOWN_MCE 5 /* Machine Check */
+#define GSMI_SHUTDOWN_SOFTWDT 6 /* Software Watchdog */
+#define GSMI_SHUTDOWN_MBE 7 /* Uncorrected ECC */
+#define GSMI_SHUTDOWN_TRIPLE 8 /* Triple Fault */
+
+#define DRIVER_VERSION "1.0"
+#define GSMI_GUID_SIZE 16
+#define GSMI_BUF_SIZE 1024
+#define GSMI_BUF_ALIGN sizeof(u64)
+#define GSMI_CALLBACK 0xef
+
+/* SMI return codes */
+#define GSMI_SUCCESS 0x00
+#define GSMI_UNSUPPORTED2 0x03
+#define GSMI_LOG_FULL 0x0b
+#define GSMI_VAR_NOT_FOUND 0x0e
+#define GSMI_HANDSHAKE_SPIN 0x7d
+#define GSMI_HANDSHAKE_CF 0x7e
+#define GSMI_HANDSHAKE_NONE 0x7f
+#define GSMI_INVALID_PARAMETER 0x82
+#define GSMI_UNSUPPORTED 0x83
+#define GSMI_BUFFER_TOO_SMALL 0x85
+#define GSMI_NOT_READY 0x86
+#define GSMI_DEVICE_ERROR 0x87
+#define GSMI_NOT_FOUND 0x8e
+
+#define QUIRKY_BOARD_HASH 0x78a30a50
+
+/* Internally used commands passed to the firmware */
+#define GSMI_CMD_GET_NVRAM_VAR 0x01
+#define GSMI_CMD_GET_NEXT_VAR 0x02
+#define GSMI_CMD_SET_NVRAM_VAR 0x03
+#define GSMI_CMD_SET_EVENT_LOG 0x08
+#define GSMI_CMD_CLEAR_EVENT_LOG 0x09
+#define GSMI_CMD_CLEAR_CONFIG 0x20
+#define GSMI_CMD_HANDSHAKE_TYPE 0xC1
+
+/* Magic entry type for kernel events */
+#define GSMI_LOG_ENTRY_TYPE_KERNEL 0xDEAD
+
+/* SMI buffers must be in 32bit physical address space */
+struct gsmi_buf {
+ u8 *start; /* start of buffer */
+ size_t length; /* length of buffer */
+ dma_addr_t handle; /* dma allocation handle */
+ u32 address; /* physical address of buffer */
+};
+
+struct gsmi_device {
+ struct platform_device *pdev; /* platform device */
+ struct gsmi_buf *name_buf; /* variable name buffer */
+ struct gsmi_buf *data_buf; /* generic data buffer */
+ struct gsmi_buf *param_buf; /* parameter buffer */
+ spinlock_t lock; /* serialize access to SMIs */
+ u16 smi_cmd; /* SMI command port */
+ int handshake_type; /* firmware handler interlock type */
+ struct dma_pool *dma_pool; /* DMA buffer pool */
+} gsmi_dev;
+
+/* Packed structures for communicating with the firmware */
+struct gsmi_nvram_var_param {
+ efi_guid_t guid;
+ u32 name_ptr;
+ u32 attributes;
+ u32 data_len;
+ u32 data_ptr;
+} __packed;
+
+struct gsmi_get_next_var_param {
+ u8 guid[GSMI_GUID_SIZE];
+ u32 name_ptr;
+ u32 name_len;
+} __packed;
+
+struct gsmi_set_eventlog_param {
+ u32 data_ptr;
+ u32 data_len;
+ u32 type;
+} __packed;
+
+/* Event log formats */
+struct gsmi_log_entry_type_1 {
+ u16 type;
+ u32 instance;
+} __packed;
+
+
+/*
+ * Some platforms don't have explicit SMI handshake
+ * and need to wait for SMI to complete.
+ */
+#define GSMI_DEFAULT_SPINCOUNT 0x10000
+static unsigned int spincount = GSMI_DEFAULT_SPINCOUNT;
+module_param(spincount, uint, 0600);
+MODULE_PARM_DESC(spincount,
+ "The number of loop iterations to use when using the spin handshake.");
+
+static struct gsmi_buf *gsmi_buf_alloc(void)
+{
+ struct gsmi_buf *smibuf;
+
+ smibuf = kzalloc(sizeof(*smibuf), GFP_KERNEL);
+ if (!smibuf) {
+ printk(KERN_ERR "gsmi: out of memory\n");
+ return NULL;
+ }
+
+ /* allocate buffer in 32bit address space */
+ smibuf->start = dma_pool_alloc(gsmi_dev.dma_pool, GFP_KERNEL,
+ &smibuf->handle);
+ if (!smibuf->start) {
+ printk(KERN_ERR "gsmi: failed to allocate name buffer\n");
+ kfree(smibuf);
+ return NULL;
+ }
+
+ /* fill in the buffer handle */
+ smibuf->length = GSMI_BUF_SIZE;
+ smibuf->address = (u32)virt_to_phys(smibuf->start);
+
+ return smibuf;
+}
+
+static void gsmi_buf_free(struct gsmi_buf *smibuf)
+{
+ if (smibuf) {
+ if (smibuf->start)
+ dma_pool_free(gsmi_dev.dma_pool, smibuf->start,
+ smibuf->handle);
+ kfree(smibuf);
+ }
+}
+
+/*
+ * Make a call to gsmi func(sub). GSMI error codes are translated to
+ * in-kernel errnos (0 on success, -ERRNO on error).
+ */
+static int gsmi_exec(u8 func, u8 sub)
+{
+ u16 cmd = (sub << 8) | func;
+ u16 result = 0;
+ int rc = 0;
+
+ /*
+ * AH : Subfunction number
+ * AL : Function number
+ * EBX : Parameter block address
+ * DX : SMI command port
+ *
+ * Three protocols here. See also the comment in gsmi_init().
+ */
+ if (gsmi_dev.handshake_type == GSMI_HANDSHAKE_CF) {
+ /*
+ * If handshake_type == HANDSHAKE_CF then set CF on the
+ * way in and wait for the handler to clear it; this avoids
+ * corrupting register state on those chipsets which have
+ * a delay between writing the SMI trigger register and
+ * entering SMM.
+ */
+ asm volatile (
+ "stc\n"
+ "outb %%al, %%dx\n"
+ "1: jc 1b\n"
+ : "=a" (result)
+ : "0" (cmd),
+ "d" (gsmi_dev.smi_cmd),
+ "b" (gsmi_dev.param_buf->address)
+ : "memory", "cc"
+ );
+ } else if (gsmi_dev.handshake_type == GSMI_HANDSHAKE_SPIN) {
+ /*
+ * If handshake_type == HANDSHAKE_SPIN we spin a
+ * hundred-ish usecs to ensure the SMI has triggered.
+ */
+ asm volatile (
+ "outb %%al, %%dx\n"
+ "1: loop 1b\n"
+ : "=a" (result)
+ : "0" (cmd),
+ "d" (gsmi_dev.smi_cmd),
+ "b" (gsmi_dev.param_buf->address),
+ "c" (spincount)
+ : "memory", "cc"
+ );
+ } else {
+ /*
+ * If handshake_type == HANDSHAKE_NONE we do nothing;
+ * either we don't need to or it's legacy firmware that
+ * doesn't understand the CF protocol.
+ */
+ asm volatile (
+ "outb %%al, %%dx\n\t"
+ : "=a" (result)
+ : "0" (cmd),
+ "d" (gsmi_dev.smi_cmd),
+ "b" (gsmi_dev.param_buf->address)
+ : "memory", "cc"
+ );
+ }
+
+ /* check return code from SMI handler */
+ switch (result) {
+ case GSMI_SUCCESS:
+ break;
+ case GSMI_VAR_NOT_FOUND:
+ /* not really an error, but let the caller know */
+ rc = 1;
+ break;
+ case GSMI_INVALID_PARAMETER:
+ printk(KERN_ERR "gsmi: exec 0x%04x: Invalid parameter\n", cmd);
+ rc = -EINVAL;
+ break;
+ case GSMI_BUFFER_TOO_SMALL:
+ printk(KERN_ERR "gsmi: exec 0x%04x: Buffer too small\n", cmd);
+ rc = -ENOMEM;
+ break;
+ case GSMI_UNSUPPORTED:
+ case GSMI_UNSUPPORTED2:
+ if (sub != GSMI_CMD_HANDSHAKE_TYPE)
+ printk(KERN_ERR "gsmi: exec 0x%04x: Not supported\n",
+ cmd);
+ rc = -ENOSYS;
+ break;
+ case GSMI_NOT_READY:
+ printk(KERN_ERR "gsmi: exec 0x%04x: Not ready\n", cmd);
+ rc = -EBUSY;
+ break;
+ case GSMI_DEVICE_ERROR:
+ printk(KERN_ERR "gsmi: exec 0x%04x: Device error\n", cmd);
+ rc = -EFAULT;
+ break;
+ case GSMI_NOT_FOUND:
+ printk(KERN_ERR "gsmi: exec 0x%04x: Data not found\n", cmd);
+ rc = -ENOENT;
+ break;
+ case GSMI_LOG_FULL:
+ printk(KERN_ERR "gsmi: exec 0x%04x: Log full\n", cmd);
+ rc = -ENOSPC;
+ break;
+ case GSMI_HANDSHAKE_CF:
+ case GSMI_HANDSHAKE_SPIN:
+ case GSMI_HANDSHAKE_NONE:
+ rc = result;
+ break;
+ default:
+ printk(KERN_ERR "gsmi: exec 0x%04x: Unknown error 0x%04x\n",
+ cmd, result);
+ rc = -ENXIO;
+ }
+
+ return rc;
+}
+
+/* Return the number of unicode characters in data */
+static size_t
+utf16_strlen(efi_char16_t *data, unsigned long maxlength)
+{
+ unsigned long length = 0;
+
+ while (*data++ != 0 && length < maxlength)
+ length++;
+ return length;
+}
+
+static efi_status_t gsmi_get_variable(efi_char16_t *name,
+ efi_guid_t *vendor, u32 *attr,
+ unsigned long *data_size,
+ void *data)
+{
+ struct gsmi_nvram_var_param param = {
+ .name_ptr = gsmi_dev.name_buf->address,
+ .data_ptr = gsmi_dev.data_buf->address,
+ .data_len = (u32)*data_size,
+ };
+ efi_status_t ret = EFI_SUCCESS;
+ unsigned long flags;
+ size_t name_len = utf16_strlen(name, GSMI_BUF_SIZE / 2);
+ int rc;
+
+ if (name_len >= GSMI_BUF_SIZE / 2)
+ return EFI_BAD_BUFFER_SIZE;
+
+ spin_lock_irqsave(&gsmi_dev.lock, flags);
+
+ /* Vendor guid */
+ memcpy(&param.guid, vendor, sizeof(param.guid));
+
+ /* variable name, already in UTF-16 */
+ memset(gsmi_dev.name_buf->start, 0, gsmi_dev.name_buf->length);
+ memcpy(gsmi_dev.name_buf->start, name, name_len * 2);
+
+ /* data pointer */
+ memset(gsmi_dev.data_buf->start, 0, gsmi_dev.data_buf->length);
+
+ /* parameter buffer */
+ memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length);
+ memcpy(gsmi_dev.param_buf->start, &param, sizeof(param));
+
+ rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_GET_NVRAM_VAR);
+ if (rc < 0) {
+ printk(KERN_ERR "gsmi: Get Variable failed\n");
+ ret = EFI_LOAD_ERROR;
+ } else if (rc == 1) {
+ /* variable was not found */
+ ret = EFI_NOT_FOUND;
+ } else {
+ /* Get the arguments back */
+ memcpy(&param, gsmi_dev.param_buf->start, sizeof(param));
+
+ /* The size reported is the min of all of our buffers */
+ *data_size = min(*data_size, gsmi_dev.data_buf->length);
+ *data_size = min_t(unsigned long, *data_size, param.data_len);
+
+ /* Copy data back to return buffer. */
+ memcpy(data, gsmi_dev.data_buf->start, *data_size);
+
+ /* All variables are have the following attributes */
+ *attr = EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS;
+ }
+
+ spin_unlock_irqrestore(&gsmi_dev.lock, flags);
+
+ return ret;
+}
+
+static efi_status_t gsmi_get_next_variable(unsigned long *name_size,
+ efi_char16_t *name,
+ efi_guid_t *vendor)
+{
+ struct gsmi_get_next_var_param param = {
+ .name_ptr = gsmi_dev.name_buf->address,
+ .name_len = gsmi_dev.name_buf->length,
+ };
+ efi_status_t ret = EFI_SUCCESS;
+ int rc;
+ unsigned long flags;
+
+ /* For the moment, only support buffers that exactly match in size */
+ if (*name_size != GSMI_BUF_SIZE)
+ return EFI_BAD_BUFFER_SIZE;
+
+ /* Let's make sure the thing is at least null-terminated */
+ if (utf16_strlen(name, GSMI_BUF_SIZE / 2) == GSMI_BUF_SIZE / 2)
+ return EFI_INVALID_PARAMETER;
+
+ spin_lock_irqsave(&gsmi_dev.lock, flags);
+
+ /* guid */
+ memcpy(&param.guid, vendor, sizeof(param.guid));
+
+ /* variable name, already in UTF-16 */
+ memcpy(gsmi_dev.name_buf->start, name, *name_size);
+
+ /* parameter buffer */
+ memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length);
+ memcpy(gsmi_dev.param_buf->start, &param, sizeof(param));
+
+ rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_GET_NEXT_VAR);
+ if (rc < 0) {
+ printk(KERN_ERR "gsmi: Get Next Variable Name failed\n");
+ ret = EFI_LOAD_ERROR;
+ } else if (rc == 1) {
+ /* variable not found -- end of list */
+ ret = EFI_NOT_FOUND;
+ } else {
+ /* copy variable data back to return buffer */
+ memcpy(&param, gsmi_dev.param_buf->start, sizeof(param));
+
+ /* Copy the name back */
+ memcpy(name, gsmi_dev.name_buf->start, GSMI_BUF_SIZE);
+ *name_size = utf16_strlen(name, GSMI_BUF_SIZE / 2) * 2;
+
+ /* copy guid to return buffer */
+ memcpy(vendor, &param.guid, sizeof(param.guid));
+ ret = EFI_SUCCESS;
+ }
+
+ spin_unlock_irqrestore(&gsmi_dev.lock, flags);
+
+ return ret;
+}
+
+static efi_status_t gsmi_set_variable(efi_char16_t *name,
+ efi_guid_t *vendor,
+ unsigned long attr,
+ unsigned long data_size,
+ void *data)
+{
+ struct gsmi_nvram_var_param param = {
+ .name_ptr = gsmi_dev.name_buf->address,
+ .data_ptr = gsmi_dev.data_buf->address,
+ .data_len = (u32)data_size,
+ .attributes = EFI_VARIABLE_NON_VOLATILE |
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS,
+ };
+ size_t name_len = utf16_strlen(name, GSMI_BUF_SIZE / 2);
+ efi_status_t ret = EFI_SUCCESS;
+ int rc;
+ unsigned long flags;
+
+ if (name_len >= GSMI_BUF_SIZE / 2)
+ return EFI_BAD_BUFFER_SIZE;
+
+ spin_lock_irqsave(&gsmi_dev.lock, flags);
+
+ /* guid */
+ memcpy(&param.guid, vendor, sizeof(param.guid));
+
+ /* variable name, already in UTF-16 */
+ memset(gsmi_dev.name_buf->start, 0, gsmi_dev.name_buf->length);
+ memcpy(gsmi_dev.name_buf->start, name, name_len * 2);
+
+ /* data pointer */
+ memset(gsmi_dev.data_buf->start, 0, gsmi_dev.data_buf->length);
+ memcpy(gsmi_dev.data_buf->start, data, data_size);
+
+ /* parameter buffer */
+ memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length);
+ memcpy(gsmi_dev.param_buf->start, &param, sizeof(param));
+
+ rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_SET_NVRAM_VAR);
+ if (rc < 0) {
+ printk(KERN_ERR "gsmi: Set Variable failed\n");
+ ret = EFI_INVALID_PARAMETER;
+ }
+
+ spin_unlock_irqrestore(&gsmi_dev.lock, flags);
+
+ return ret;
+}
+
+static const struct efivar_operations efivar_ops = {
+ .get_variable = gsmi_get_variable,
+ .set_variable = gsmi_set_variable,
+ .get_next_variable = gsmi_get_next_variable,
+};
+
+static ssize_t eventlog_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t pos, size_t count)
+{
+ struct gsmi_set_eventlog_param param = {
+ .data_ptr = gsmi_dev.data_buf->address,
+ };
+ int rc = 0;
+ unsigned long flags;
+
+ /* Pull the type out */
+ if (count < sizeof(u32))
+ return -EINVAL;
+ param.type = *(u32 *)buf;
+ count -= sizeof(u32);
+ buf += sizeof(u32);
+
+ /* The remaining buffer is the data payload */
+ if (count > gsmi_dev.data_buf->length)
+ return -EINVAL;
+ param.data_len = count - sizeof(u32);
+
+ spin_lock_irqsave(&gsmi_dev.lock, flags);
+
+ /* data pointer */
+ memset(gsmi_dev.data_buf->start, 0, gsmi_dev.data_buf->length);
+ memcpy(gsmi_dev.data_buf->start, buf, param.data_len);
+
+ /* parameter buffer */
+ memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length);
+ memcpy(gsmi_dev.param_buf->start, &param, sizeof(param));
+
+ rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_SET_EVENT_LOG);
+ if (rc < 0)
+ printk(KERN_ERR "gsmi: Set Event Log failed\n");
+
+ spin_unlock_irqrestore(&gsmi_dev.lock, flags);
+
+ return rc;
+
+}
+
+static struct bin_attribute eventlog_bin_attr = {
+ .attr = {.name = "append_to_eventlog", .mode = 0200},
+ .write = eventlog_write,
+};
+
+static ssize_t gsmi_clear_eventlog_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int rc;
+ unsigned long flags;
+ unsigned long val;
+ struct {
+ u32 percentage;
+ u32 data_type;
+ } param;
+
+ rc = strict_strtoul(buf, 0, &val);
+ if (rc)
+ return rc;
+
+ /*
+ * Value entered is a percentage, 0 through 100, anything else
+ * is invalid.
+ */
+ if (val > 100)
+ return -EINVAL;
+
+ /* data_type here selects the smbios event log. */
+ param.percentage = val;
+ param.data_type = 0;
+
+ spin_lock_irqsave(&gsmi_dev.lock, flags);
+
+ /* parameter buffer */
+ memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length);
+ memcpy(gsmi_dev.param_buf->start, &param, sizeof(param));
+
+ rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_CLEAR_EVENT_LOG);
+
+ spin_unlock_irqrestore(&gsmi_dev.lock, flags);
+
+ if (rc)
+ return rc;
+ return count;
+}
+
+static struct kobj_attribute gsmi_clear_eventlog_attr = {
+ .attr = {.name = "clear_eventlog", .mode = 0200},
+ .store = gsmi_clear_eventlog_store,
+};
+
+static ssize_t gsmi_clear_config_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int rc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gsmi_dev.lock, flags);
+
+ /* clear parameter buffer */
+ memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length);
+
+ rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_CLEAR_CONFIG);
+
+ spin_unlock_irqrestore(&gsmi_dev.lock, flags);
+
+ if (rc)
+ return rc;
+ return count;
+}
+
+static struct kobj_attribute gsmi_clear_config_attr = {
+ .attr = {.name = "clear_config", .mode = 0200},
+ .store = gsmi_clear_config_store,
+};
+
+static const struct attribute *gsmi_attrs[] = {
+ &gsmi_clear_config_attr.attr,
+ &gsmi_clear_eventlog_attr.attr,
+ NULL,
+};
+
+static int gsmi_shutdown_reason(int reason)
+{
+ struct gsmi_log_entry_type_1 entry = {
+ .type = GSMI_LOG_ENTRY_TYPE_KERNEL,
+ .instance = reason,
+ };
+ struct gsmi_set_eventlog_param param = {
+ .data_len = sizeof(entry),
+ .type = 1,
+ };
+ static int saved_reason;
+ int rc = 0;
+ unsigned long flags;
+
+ /* avoid duplicate entries in the log */
+ if (saved_reason & (1 << reason))
+ return 0;
+
+ spin_lock_irqsave(&gsmi_dev.lock, flags);
+
+ saved_reason |= (1 << reason);
+
+ /* data pointer */
+ memset(gsmi_dev.data_buf->start, 0, gsmi_dev.data_buf->length);
+ memcpy(gsmi_dev.data_buf->start, &entry, sizeof(entry));
+
+ /* parameter buffer */
+ param.data_ptr = gsmi_dev.data_buf->address;
+ memset(gsmi_dev.param_buf->start, 0, gsmi_dev.param_buf->length);
+ memcpy(gsmi_dev.param_buf->start, &param, sizeof(param));
+
+ rc = gsmi_exec(GSMI_CALLBACK, GSMI_CMD_SET_EVENT_LOG);
+
+ spin_unlock_irqrestore(&gsmi_dev.lock, flags);
+
+ if (rc < 0)
+ printk(KERN_ERR "gsmi: Log Shutdown Reason failed\n");
+ else
+ printk(KERN_EMERG "gsmi: Log Shutdown Reason 0x%02x\n",
+ reason);
+
+ return rc;
+}
+
+static int gsmi_reboot_callback(struct notifier_block *nb,
+ unsigned long reason, void *arg)
+{
+ gsmi_shutdown_reason(GSMI_SHUTDOWN_CLEAN);
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block gsmi_reboot_notifier = {
+ .notifier_call = gsmi_reboot_callback
+};
+
+static int gsmi_die_callback(struct notifier_block *nb,
+ unsigned long reason, void *arg)
+{
+ if (reason == DIE_OOPS)
+ gsmi_shutdown_reason(GSMI_SHUTDOWN_OOPS);
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block gsmi_die_notifier = {
+ .notifier_call = gsmi_die_callback
+};
+
+static int gsmi_panic_callback(struct notifier_block *nb,
+ unsigned long reason, void *arg)
+{
+ gsmi_shutdown_reason(GSMI_SHUTDOWN_PANIC);
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block gsmi_panic_notifier = {
+ .notifier_call = gsmi_panic_callback,
+};
+
+/*
+ * This hash function was blatantly copied from include/linux/hash.h.
+ * It is used by this driver to obfuscate a board name that requires a
+ * quirk within this driver.
+ *
+ * Please do not remove this copy of the function as any changes to the
+ * global utility hash_64() function would break this driver's ability
+ * to identify a board and provide the appropriate quirk -- mikew@google.com
+ */
+static u64 __init local_hash_64(u64 val, unsigned bits)
+{
+ u64 hash = val;
+
+ /* Sigh, gcc can't optimise this alone like it does for 32 bits. */
+ u64 n = hash;
+ n <<= 18;
+ hash -= n;
+ n <<= 33;
+ hash -= n;
+ n <<= 3;
+ hash += n;
+ n <<= 3;
+ hash -= n;
+ n <<= 4;
+ hash += n;
+ n <<= 2;
+ hash += n;
+
+ /* High bits are more random, so use them. */
+ return hash >> (64 - bits);
+}
+
+static u32 __init hash_oem_table_id(char s[8])
+{
+ u64 input;
+ memcpy(&input, s, 8);
+ return local_hash_64(input, 32);
+}
+
+static struct dmi_system_id gsmi_dmi_table[] __initdata = {
+ {
+ .ident = "Google Board",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Google, Inc."),
+ },
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(dmi, gsmi_dmi_table);
+
+static __init int gsmi_system_valid(void)
+{
+ u32 hash;
+
+ if (!dmi_check_system(gsmi_dmi_table))
+ return -ENODEV;
+
+ /*
+ * Only newer firmware supports the gsmi interface. All older
+ * firmware that didn't support this interface used to plug the
+ * table name in the first four bytes of the oem_table_id field.
+ * Newer firmware doesn't do that though, so use that as the
+ * discriminant factor. We have to do this in order to
+ * whitewash our board names out of the public driver.
+ */
+ if (!strncmp(acpi_gbl_FADT.header.oem_table_id, "FACP", 4)) {
+ printk(KERN_INFO "gsmi: Board is too old\n");
+ return -ENODEV;
+ }
+
+ /* Disable on board with 1.0 BIOS due to Google bug 2602657 */
+ hash = hash_oem_table_id(acpi_gbl_FADT.header.oem_table_id);
+ if (hash == QUIRKY_BOARD_HASH) {
+ const char *bios_ver = dmi_get_system_info(DMI_BIOS_VERSION);
+ if (strncmp(bios_ver, "1.0", 3) == 0) {
+ pr_info("gsmi: disabled on this board's BIOS %s\n",
+ bios_ver);
+ return -ENODEV;
+ }
+ }
+
+ /* check for valid SMI command port in ACPI FADT */
+ if (acpi_gbl_FADT.smi_command == 0) {
+ pr_info("gsmi: missing smi_command\n");
+ return -ENODEV;
+ }
+
+ /* Found */
+ return 0;
+}
+
+static struct kobject *gsmi_kobj;
+static struct efivars efivars;
+
+static __init int gsmi_init(void)
+{
+ unsigned long flags;
+ int ret;
+
+ ret = gsmi_system_valid();
+ if (ret)
+ return ret;
+
+ gsmi_dev.smi_cmd = acpi_gbl_FADT.smi_command;
+
+ /* register device */
+ gsmi_dev.pdev = platform_device_register_simple("gsmi", -1, NULL, 0);
+ if (IS_ERR(gsmi_dev.pdev)) {
+ printk(KERN_ERR "gsmi: unable to register platform device\n");
+ return PTR_ERR(gsmi_dev.pdev);
+ }
+
+ /* SMI access needs to be serialized */
+ spin_lock_init(&gsmi_dev.lock);
+
+ /* SMI callbacks require 32bit addresses */
+ gsmi_dev.pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+ gsmi_dev.pdev->dev.dma_mask =
+ &gsmi_dev.pdev->dev.coherent_dma_mask;
+ ret = -ENOMEM;
+ gsmi_dev.dma_pool = dma_pool_create("gsmi", &gsmi_dev.pdev->dev,
+ GSMI_BUF_SIZE, GSMI_BUF_ALIGN, 0);
+ if (!gsmi_dev.dma_pool)
+ goto out_err;
+
+ /*
+ * pre-allocate buffers because sometimes we are called when
+ * this is not feasible: oops, panic, die, mce, etc
+ */
+ gsmi_dev.name_buf = gsmi_buf_alloc();
+ if (!gsmi_dev.name_buf) {
+ printk(KERN_ERR "gsmi: failed to allocate name buffer\n");
+ goto out_err;
+ }
+
+ gsmi_dev.data_buf = gsmi_buf_alloc();
+ if (!gsmi_dev.data_buf) {
+ printk(KERN_ERR "gsmi: failed to allocate data buffer\n");
+ goto out_err;
+ }
+
+ gsmi_dev.param_buf = gsmi_buf_alloc();
+ if (!gsmi_dev.param_buf) {
+ printk(KERN_ERR "gsmi: failed to allocate param buffer\n");
+ goto out_err;
+ }
+
+ /*
+ * Determine type of handshake used to serialize the SMI
+ * entry. See also gsmi_exec().
+ *
+ * There's a "behavior" present on some chipsets where writing the
+ * SMI trigger register in the southbridge doesn't result in an
+ * immediate SMI. Rather, the processor can execute "a few" more
+ * instructions before the SMI takes effect. To ensure synchronous
+ * behavior, implement a handshake between the kernel driver and the
+ * firmware handler to spin until released. This ioctl determines
+ * the type of handshake.
+ *
+ * NONE: The firmware handler does not implement any
+ * handshake. Either it doesn't need to, or it's legacy firmware
+ * that doesn't know it needs to and never will.
+ *
+ * CF: The firmware handler will clear the CF in the saved
+ * state before returning. The driver may set the CF and test for
+ * it to clear before proceeding.
+ *
+ * SPIN: The firmware handler does not implement any handshake
+ * but the driver should spin for a hundred or so microseconds
+ * to ensure the SMI has triggered.
+ *
+ * Finally, the handler will return -ENOSYS if
+ * GSMI_CMD_HANDSHAKE_TYPE is unimplemented, which implies
+ * HANDSHAKE_NONE.
+ */
+ spin_lock_irqsave(&gsmi_dev.lock, flags);
+ gsmi_dev.handshake_type = GSMI_HANDSHAKE_SPIN;
+ gsmi_dev.handshake_type =
+ gsmi_exec(GSMI_CALLBACK, GSMI_CMD_HANDSHAKE_TYPE);
+ if (gsmi_dev.handshake_type == -ENOSYS)
+ gsmi_dev.handshake_type = GSMI_HANDSHAKE_NONE;
+ spin_unlock_irqrestore(&gsmi_dev.lock, flags);
+
+ /* Remove and clean up gsmi if the handshake could not complete. */
+ if (gsmi_dev.handshake_type == -ENXIO) {
+ printk(KERN_INFO "gsmi version " DRIVER_VERSION
+ " failed to load\n");
+ ret = -ENODEV;
+ goto out_err;
+ }
+
+ printk(KERN_INFO "gsmi version " DRIVER_VERSION " loaded\n");
+
+ /* Register in the firmware directory */
+ ret = -ENOMEM;
+ gsmi_kobj = kobject_create_and_add("gsmi", firmware_kobj);
+ if (!gsmi_kobj) {
+ printk(KERN_INFO "gsmi: Failed to create firmware kobj\n");
+ goto out_err;
+ }
+
+ /* Setup eventlog access */
+ ret = sysfs_create_bin_file(gsmi_kobj, &eventlog_bin_attr);
+ if (ret) {
+ printk(KERN_INFO "gsmi: Failed to setup eventlog");
+ goto out_err;
+ }
+
+ /* Other attributes */
+ ret = sysfs_create_files(gsmi_kobj, gsmi_attrs);
+ if (ret) {
+ printk(KERN_INFO "gsmi: Failed to add attrs");
+ goto out_err;
+ }
+
+ if (register_efivars(&efivars, &efivar_ops, gsmi_kobj)) {
+ printk(KERN_INFO "gsmi: Failed to register efivars\n");
+ goto out_err;
+ }
+
+ register_reboot_notifier(&gsmi_reboot_notifier);
+ register_die_notifier(&gsmi_die_notifier);
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &gsmi_panic_notifier);
+
+ return 0;
+
+ out_err:
+ kobject_put(gsmi_kobj);
+ gsmi_buf_free(gsmi_dev.param_buf);
+ gsmi_buf_free(gsmi_dev.data_buf);
+ gsmi_buf_free(gsmi_dev.name_buf);
+ if (gsmi_dev.dma_pool)
+ dma_pool_destroy(gsmi_dev.dma_pool);
+ platform_device_unregister(gsmi_dev.pdev);
+ pr_info("gsmi: failed to load: %d\n", ret);
+ return ret;
+}
+
+static void __exit gsmi_exit(void)
+{
+ unregister_reboot_notifier(&gsmi_reboot_notifier);
+ unregister_die_notifier(&gsmi_die_notifier);
+ atomic_notifier_chain_unregister(&panic_notifier_list,
+ &gsmi_panic_notifier);
+ unregister_efivars(&efivars);
+
+ kobject_put(gsmi_kobj);
+ gsmi_buf_free(gsmi_dev.param_buf);
+ gsmi_buf_free(gsmi_dev.data_buf);
+ gsmi_buf_free(gsmi_dev.name_buf);
+ dma_pool_destroy(gsmi_dev.dma_pool);
+ platform_device_unregister(gsmi_dev.pdev);
+}
+
+module_init(gsmi_init);
+module_exit(gsmi_exit);
+
+MODULE_AUTHOR("Google, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/google/memconsole.c b/drivers/firmware/google/memconsole.c
new file mode 100644
index 000000000000..2a90ba613613
--- /dev/null
+++ b/drivers/firmware/google/memconsole.c
@@ -0,0 +1,166 @@
+/*
+ * memconsole.c
+ *
+ * Infrastructure for importing the BIOS memory based console
+ * into the kernel log ringbuffer.
+ *
+ * Copyright 2010 Google Inc. All rights reserved.
+ */
+
+#include <linux/ctype.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include <linux/module.h>
+#include <linux/dmi.h>
+#include <asm/bios_ebda.h>
+
+#define BIOS_MEMCONSOLE_V1_MAGIC 0xDEADBABE
+#define BIOS_MEMCONSOLE_V2_MAGIC (('M')|('C'<<8)|('O'<<16)|('N'<<24))
+
+struct biosmemcon_ebda {
+ u32 signature;
+ union {
+ struct {
+ u8 enabled;
+ u32 buffer_addr;
+ u16 start;
+ u16 end;
+ u16 num_chars;
+ u8 wrapped;
+ } __packed v1;
+ struct {
+ u32 buffer_addr;
+ /* Misdocumented as number of pages! */
+ u16 num_bytes;
+ u16 start;
+ u16 end;
+ } __packed v2;
+ };
+} __packed;
+
+static char *memconsole_baseaddr;
+static size_t memconsole_length;
+
+static ssize_t memconsole_read(struct file *filp, struct kobject *kobp,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t pos, size_t count)
+{
+ return memory_read_from_buffer(buf, count, &pos, memconsole_baseaddr,
+ memconsole_length);
+}
+
+static struct bin_attribute memconsole_bin_attr = {
+ .attr = {.name = "log", .mode = 0444},
+ .read = memconsole_read,
+};
+
+
+static void found_v1_header(struct biosmemcon_ebda *hdr)
+{
+ printk(KERN_INFO "BIOS console v1 EBDA structure found at %p\n", hdr);
+ printk(KERN_INFO "BIOS console buffer at 0x%.8x, "
+ "start = %d, end = %d, num = %d\n",
+ hdr->v1.buffer_addr, hdr->v1.start,
+ hdr->v1.end, hdr->v1.num_chars);
+
+ memconsole_length = hdr->v1.num_chars;
+ memconsole_baseaddr = phys_to_virt(hdr->v1.buffer_addr);
+}
+
+static void found_v2_header(struct biosmemcon_ebda *hdr)
+{
+ printk(KERN_INFO "BIOS console v2 EBDA structure found at %p\n", hdr);
+ printk(KERN_INFO "BIOS console buffer at 0x%.8x, "
+ "start = %d, end = %d, num_bytes = %d\n",
+ hdr->v2.buffer_addr, hdr->v2.start,
+ hdr->v2.end, hdr->v2.num_bytes);
+
+ memconsole_length = hdr->v2.end - hdr->v2.start;
+ memconsole_baseaddr = phys_to_virt(hdr->v2.buffer_addr
+ + hdr->v2.start);
+}
+
+/*
+ * Search through the EBDA for the BIOS Memory Console, and
+ * set the global variables to point to it. Return true if found.
+ */
+static bool found_memconsole(void)
+{
+ unsigned int address;
+ size_t length, cur;
+
+ address = get_bios_ebda();
+ if (!address) {
+ printk(KERN_INFO "BIOS EBDA non-existent.\n");
+ return false;
+ }
+
+ /* EBDA length is byte 0 of EBDA (in KB) */
+ length = *(u8 *)phys_to_virt(address);
+ length <<= 10; /* convert to bytes */
+
+ /*
+ * Search through EBDA for BIOS memory console structure
+ * note: signature is not necessarily dword-aligned
+ */
+ for (cur = 0; cur < length; cur++) {
+ struct biosmemcon_ebda *hdr = phys_to_virt(address + cur);
+
+ /* memconsole v1 */
+ if (hdr->signature == BIOS_MEMCONSOLE_V1_MAGIC) {
+ found_v1_header(hdr);
+ return true;
+ }
+
+ /* memconsole v2 */
+ if (hdr->signature == BIOS_MEMCONSOLE_V2_MAGIC) {
+ found_v2_header(hdr);
+ return true;
+ }
+ }
+
+ printk(KERN_INFO "BIOS console EBDA structure not found!\n");
+ return false;
+}
+
+static struct dmi_system_id memconsole_dmi_table[] __initdata = {
+ {
+ .ident = "Google Board",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Google, Inc."),
+ },
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(dmi, memconsole_dmi_table);
+
+static int __init memconsole_init(void)
+{
+ int ret;
+
+ if (!dmi_check_system(memconsole_dmi_table))
+ return -ENODEV;
+
+ if (!found_memconsole())
+ return -ENODEV;
+
+ memconsole_bin_attr.size = memconsole_length;
+
+ ret = sysfs_create_bin_file(firmware_kobj, &memconsole_bin_attr);
+
+ return ret;
+}
+
+static void __exit memconsole_exit(void)
+{
+ sysfs_remove_bin_file(firmware_kobj, &memconsole_bin_attr);
+}
+
+module_init(memconsole_init);
+module_exit(memconsole_exit);
+
+MODULE_AUTHOR("Google, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c
index 6148a1c67895..ce33f4626957 100644
--- a/drivers/firmware/iscsi_ibft.c
+++ b/drivers/firmware/iscsi_ibft.c
@@ -87,8 +87,8 @@
#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>");
+MODULE_AUTHOR("Peter Jones <pjones@redhat.com> and "
+ "Konrad Rzeszutek <ketuzsezr@darnok.org>");
MODULE_DESCRIPTION("sysfs interface to BIOS iBFT information");
MODULE_LICENSE("GPL");
MODULE_VERSION(IBFT_ISCSI_VERSION);
diff --git a/drivers/firmware/iscsi_ibft_find.c b/drivers/firmware/iscsi_ibft_find.c
index 2192456dfd68..f032e446fc11 100644
--- a/drivers/firmware/iscsi_ibft_find.c
+++ b/drivers/firmware/iscsi_ibft_find.c
@@ -42,7 +42,20 @@
struct acpi_table_ibft *ibft_addr;
EXPORT_SYMBOL_GPL(ibft_addr);
-#define IBFT_SIGN "iBFT"
+static const struct {
+ char *sign;
+} ibft_signs[] = {
+#ifdef CONFIG_ACPI
+ /*
+ * One spec says "IBFT", the other says "iBFT". We have to check
+ * for both.
+ */
+ { ACPI_SIG_IBFT },
+#endif
+ { "iBFT" },
+ { "BIFT" }, /* Broadcom iSCSI Offload */
+};
+
#define IBFT_SIGN_LEN 4
#define IBFT_START 0x80000 /* 512kB */
#define IBFT_END 0x100000 /* 1MB */
@@ -62,6 +75,7 @@ static int __init find_ibft_in_mem(void)
unsigned long pos;
unsigned int len = 0;
void *virt;
+ int i;
for (pos = IBFT_START; pos < IBFT_END; pos += 16) {
/* The table can't be inside the VGA BIOS reserved space,
@@ -69,18 +83,23 @@ static int __init find_ibft_in_mem(void)
if (pos == VGA_MEM)
pos += VGA_SIZE;
virt = isa_bus_to_virt(pos);
- if (memcmp(virt, IBFT_SIGN, IBFT_SIGN_LEN) == 0) {
- unsigned long *addr =
- (unsigned long *)isa_bus_to_virt(pos + 4);
- len = *addr;
- /* if the length of the table extends past 1M,
- * the table cannot be valid. */
- if (pos + len <= (IBFT_END-1)) {
- ibft_addr = (struct acpi_table_ibft *)virt;
- break;
+
+ for (i = 0; i < ARRAY_SIZE(ibft_signs); i++) {
+ if (memcmp(virt, ibft_signs[i].sign, IBFT_SIGN_LEN) ==
+ 0) {
+ unsigned long *addr =
+ (unsigned long *)isa_bus_to_virt(pos + 4);
+ len = *addr;
+ /* if the length of the table extends past 1M,
+ * the table cannot be valid. */
+ if (pos + len <= (IBFT_END-1)) {
+ ibft_addr = (struct acpi_table_ibft *)virt;
+ goto done;
+ }
}
}
}
+done:
return len;
}
/*
@@ -89,18 +108,12 @@ static int __init find_ibft_in_mem(void)
*/
unsigned long __init find_ibft_region(unsigned long *sizep)
{
-
+ int i;
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);
+ for (i = 0; i < ARRAY_SIZE(ibft_signs) && !ibft_addr; i++)
+ acpi_table_parse(ibft_signs[i].sign, acpi_find_ibft);
#endif /* CONFIG_ACPI */
/* iBFT 1.03 section 1.4.3.1 mandates that UEFI machines will
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index d3b295305542..d21364603755 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -1,5 +1,5 @@
#
-# platform-neutral GPIO infrastructure and expanders
+# GPIO infrastructure and drivers
#
config ARCH_WANT_OPTIONAL_GPIOLIB
@@ -31,7 +31,7 @@ menuconfig GPIOLIB
help
This enables GPIO support through the generic GPIO library.
You only need to enable this, if you also want to enable
- one or more of the GPIO expansion card drivers below.
+ one or more of the GPIO drivers below.
If unsure, say N.
@@ -63,21 +63,26 @@ config GPIO_SYSFS
Kernel drivers may also request that a particular GPIO be
exported to userspace; this can be useful when debugging.
-# put expanders in the right section, in alphabetical order
+# put drivers in the right section, in alphabetical order
config GPIO_MAX730X
tristate
-comment "Memory mapped GPIO expanders:"
+comment "Memory mapped GPIO drivers:"
+
+config GPIO_BASIC_MMIO_CORE
+ tristate
+ help
+ Provides core functionality for basic memory-mapped GPIO controllers.
config GPIO_BASIC_MMIO
tristate "Basic memory-mapped GPIO controllers support"
+ select GPIO_BASIC_MMIO_CORE
help
Say yes here to support basic memory-mapped GPIO controllers.
config GPIO_IT8761E
tristate "IT8761E GPIO support"
- depends on GPIOLIB
help
Say yes here to support GPIO functionality of IT8761E super I/O chip.
@@ -101,7 +106,7 @@ config GPIO_VR41XX
config GPIO_SCH
tristate "Intel SCH/TunnelCreek GPIO"
- depends on GPIOLIB && PCI && X86
+ depends on PCI && X86
select MFD_CORE
select LPC_SCH
help
@@ -121,7 +126,7 @@ config GPIO_SCH
config GPIO_VX855
tristate "VIA VX855/VX875 GPIO"
- depends on GPIOLIB && MFD_SUPPORT && PCI
+ depends on MFD_SUPPORT && PCI
select MFD_CORE
select MFD_VX855
help
@@ -347,13 +352,13 @@ config GPIO_ML_IOH
config GPIO_TIMBERDALE
bool "Support for timberdale GPIO IP"
- depends on MFD_TIMBERDALE && GPIOLIB && HAS_IOMEM
+ depends on MFD_TIMBERDALE && HAS_IOMEM
---help---
Add support for the GPIO IP in the timberdale FPGA.
config GPIO_RDC321X
tristate "RDC R-321x GPIO support"
- depends on PCI && GPIOLIB
+ depends on PCI
select MFD_SUPPORT
select MFD_CORE
select MFD_RDC321X
@@ -419,4 +424,11 @@ config AB8500_GPIO
depends on AB8500_CORE && BROKEN
help
Select this to enable the AB8500 IC GPIO driver
+
+config GPIO_TPS65910
+ bool "TPS65910 GPIO"
+ depends on MFD_TPS65910
+ help
+ Select this option to enable GPIO driver for the TPS65910
+ chip family.
endif
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index becef5954356..6a3387acc0e5 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -1,8 +1,4 @@
-# generic gpio support: dedicated expander chips, etc
-#
-# NOTE: platform-specific GPIO drivers don't belong in the
-# drivers/gpio directory; put them with other platform setup
-# code, IRQ controllers, board init, etc.
+# generic gpio support: platform drivers, dedicated expander chips, etc
ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG
@@ -10,6 +6,7 @@ obj-$(CONFIG_GPIOLIB) += gpiolib.o
obj-$(CONFIG_GPIO_ADP5520) += adp5520-gpio.o
obj-$(CONFIG_GPIO_ADP5588) += adp5588-gpio.o
+obj-$(CONFIG_GPIO_BASIC_MMIO_CORE) += basic_mmio_gpio.o
obj-$(CONFIG_GPIO_BASIC_MMIO) += basic_mmio_gpio.o
obj-$(CONFIG_GPIO_LANGWELL) += langwell_gpio.o
obj-$(CONFIG_GPIO_MAX730X) += max730x.o
@@ -43,3 +40,4 @@ obj-$(CONFIG_GPIO_SX150X) += sx150x.o
obj-$(CONFIG_GPIO_VX855) += vx855_gpio.o
obj-$(CONFIG_GPIO_ML_IOH) += ml_ioh_gpio.o
obj-$(CONFIG_AB8500_GPIO) += ab8500-gpio.o
+obj-$(CONFIG_GPIO_TPS65910) += tps65910-gpio.o
diff --git a/drivers/gpio/ab8500-gpio.c b/drivers/gpio/ab8500-gpio.c
index e7b834d054b7..970053c89ff7 100644
--- a/drivers/gpio/ab8500-gpio.c
+++ b/drivers/gpio/ab8500-gpio.c
@@ -482,8 +482,8 @@ static int __devexit ab8500_gpio_remove(struct platform_device *pdev)
ret = gpiochip_remove(&ab8500_gpio->chip);
if (ret < 0) {
- dev_err(ab8500_gpio->dev, "unable to remove gpiochip:\
- %d\n", ret);
+ dev_err(ab8500_gpio->dev, "unable to remove gpiochip: %d\n",
+ ret);
return ret;
}
@@ -516,7 +516,6 @@ static void __exit ab8500_gpio_exit(void)
module_exit(ab8500_gpio_exit);
MODULE_AUTHOR("BIBEK BASU <bibek.basu@stericsson.com>");
-MODULE_DESCRIPTION("Driver allows to use AB8500 unused pins\
- to be used as GPIO");
+MODULE_DESCRIPTION("Driver allows to use AB8500 unused pins to be used as GPIO");
MODULE_ALIAS("AB8500 GPIO driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpio/basic_mmio_gpio.c b/drivers/gpio/basic_mmio_gpio.c
index 3addea65894e..8152e9f516b0 100644
--- a/drivers/gpio/basic_mmio_gpio.c
+++ b/drivers/gpio/basic_mmio_gpio.c
@@ -45,6 +45,7 @@ o ` ~~~~\___/~~~~ ` controller in FPGA is ,.`
*/
#include <linux/init.h>
+#include <linux/err.h>
#include <linux/bug.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -61,102 +62,101 @@ o ` ~~~~\___/~~~~ ` controller in FPGA is ,.`
#include <linux/mod_devicetable.h>
#include <linux/basic_mmio_gpio.h>
-struct bgpio_chip {
- struct gpio_chip gc;
- void __iomem *reg_dat;
- void __iomem *reg_set;
- void __iomem *reg_clr;
-
- /* Number of bits (GPIOs): <register width> * 8. */
- int bits;
-
- /*
- * Some GPIO controllers work with the big-endian bits notation,
- * e.g. in a 8-bits register, GPIO7 is the least significant bit.
- */
- int big_endian_bits;
-
- /*
- * Used to lock bgpio_chip->data. Also, this is needed to keep
- * shadowed and real data registers writes together.
- */
- spinlock_t lock;
-
- /* Shadowed data register to clear/set bits safely. */
- unsigned long data;
-};
+static void bgpio_write8(void __iomem *reg, unsigned long data)
+{
+ writeb(data, reg);
+}
-static struct bgpio_chip *to_bgpio_chip(struct gpio_chip *gc)
+static unsigned long bgpio_read8(void __iomem *reg)
{
- return container_of(gc, struct bgpio_chip, gc);
+ return readb(reg);
}
-static unsigned long bgpio_in(struct bgpio_chip *bgc)
+static void bgpio_write16(void __iomem *reg, unsigned long data)
{
- switch (bgc->bits) {
- case 8:
- return __raw_readb(bgc->reg_dat);
- case 16:
- return __raw_readw(bgc->reg_dat);
- case 32:
- return __raw_readl(bgc->reg_dat);
-#if BITS_PER_LONG >= 64
- case 64:
- return __raw_readq(bgc->reg_dat);
-#endif
- }
- return -EINVAL;
+ writew(data, reg);
}
-static void bgpio_out(struct bgpio_chip *bgc, void __iomem *reg,
- unsigned long data)
+static unsigned long bgpio_read16(void __iomem *reg)
{
- switch (bgc->bits) {
- case 8:
- __raw_writeb(data, reg);
- return;
- case 16:
- __raw_writew(data, reg);
- return;
- case 32:
- __raw_writel(data, reg);
- return;
+ return readw(reg);
+}
+
+static void bgpio_write32(void __iomem *reg, unsigned long data)
+{
+ writel(data, reg);
+}
+
+static unsigned long bgpio_read32(void __iomem *reg)
+{
+ return readl(reg);
+}
+
#if BITS_PER_LONG >= 64
- case 64:
- __raw_writeq(data, reg);
- return;
-#endif
- }
+static void bgpio_write64(void __iomem *reg, unsigned long data)
+{
+ writeq(data, reg);
}
+static unsigned long bgpio_read64(void __iomem *reg)
+{
+ return readq(reg);
+}
+#endif /* BITS_PER_LONG >= 64 */
+
static unsigned long bgpio_pin2mask(struct bgpio_chip *bgc, unsigned int pin)
{
- if (bgc->big_endian_bits)
- return 1 << (bgc->bits - 1 - pin);
- else
- return 1 << pin;
+ return 1 << pin;
+}
+
+static unsigned long bgpio_pin2mask_be(struct bgpio_chip *bgc,
+ unsigned int pin)
+{
+ return 1 << (bgc->bits - 1 - pin);
}
static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
- return bgpio_in(bgc) & bgpio_pin2mask(bgc, gpio);
+ return bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio);
}
static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct bgpio_chip *bgc = to_bgpio_chip(gc);
- unsigned long mask = bgpio_pin2mask(bgc, gpio);
+ unsigned long mask = bgc->pin2mask(bgc, gpio);
unsigned long flags;
- if (bgc->reg_set) {
- if (val)
- bgpio_out(bgc, bgc->reg_set, mask);
- else
- bgpio_out(bgc, bgc->reg_clr, mask);
- return;
- }
+ spin_lock_irqsave(&bgc->lock, flags);
+
+ if (val)
+ bgc->data |= mask;
+ else
+ bgc->data &= ~mask;
+
+ bgc->write_reg(bgc->reg_dat, bgc->data);
+
+ spin_unlock_irqrestore(&bgc->lock, flags);
+}
+
+static void bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio,
+ int val)
+{
+ struct bgpio_chip *bgc = to_bgpio_chip(gc);
+ unsigned long mask = bgc->pin2mask(bgc, gpio);
+
+ if (val)
+ bgc->write_reg(bgc->reg_set, mask);
+ else
+ bgc->write_reg(bgc->reg_clr, mask);
+}
+
+static void bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct bgpio_chip *bgc = to_bgpio_chip(gc);
+ unsigned long mask = bgc->pin2mask(bgc, gpio);
+ unsigned long flags;
spin_lock_irqsave(&bgc->lock, flags);
@@ -165,103 +165,352 @@ static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
else
bgc->data &= ~mask;
- bgpio_out(bgc, bgc->reg_dat, bgc->data);
+ bgc->write_reg(bgc->reg_set, bgc->data);
spin_unlock_irqrestore(&bgc->lock, flags);
}
+static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+ return 0;
+}
+
+static int bgpio_simple_dir_out(struct gpio_chip *gc, unsigned int gpio,
+ int val)
+{
+ gc->set(gc, gpio, val);
+
+ return 0;
+}
+
static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
+ struct bgpio_chip *bgc = to_bgpio_chip(gc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&bgc->lock, flags);
+
+ bgc->dir &= ~bgc->pin2mask(bgc, gpio);
+ bgc->write_reg(bgc->reg_dir, bgc->dir);
+
+ spin_unlock_irqrestore(&bgc->lock, flags);
+
return 0;
}
static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
- bgpio_set(gc, gpio, val);
+ struct bgpio_chip *bgc = to_bgpio_chip(gc);
+ unsigned long flags;
+
+ gc->set(gc, gpio, val);
+
+ spin_lock_irqsave(&bgc->lock, flags);
+
+ bgc->dir |= bgc->pin2mask(bgc, gpio);
+ bgc->write_reg(bgc->reg_dir, bgc->dir);
+
+ spin_unlock_irqrestore(&bgc->lock, flags);
+
return 0;
}
-static int __devinit bgpio_probe(struct platform_device *pdev)
+static int bgpio_dir_in_inv(struct gpio_chip *gc, unsigned int gpio)
{
- const struct platform_device_id *platid = platform_get_device_id(pdev);
- struct device *dev = &pdev->dev;
- struct bgpio_pdata *pdata = dev_get_platdata(dev);
- struct bgpio_chip *bgc;
- struct resource *res_dat;
- struct resource *res_set;
- struct resource *res_clr;
- resource_size_t dat_sz;
- int bits;
- int ret;
+ struct bgpio_chip *bgc = to_bgpio_chip(gc);
+ unsigned long flags;
- res_dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
- if (!res_dat)
- return -EINVAL;
+ spin_lock_irqsave(&bgc->lock, flags);
- dat_sz = resource_size(res_dat);
- if (!is_power_of_2(dat_sz))
- return -EINVAL;
+ bgc->dir |= bgc->pin2mask(bgc, gpio);
+ bgc->write_reg(bgc->reg_dir, bgc->dir);
+
+ spin_unlock_irqrestore(&bgc->lock, flags);
+
+ return 0;
+}
- bits = dat_sz * 8;
- if (bits > BITS_PER_LONG)
+static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct bgpio_chip *bgc = to_bgpio_chip(gc);
+ unsigned long flags;
+
+ gc->set(gc, gpio, val);
+
+ spin_lock_irqsave(&bgc->lock, flags);
+
+ bgc->dir &= ~bgc->pin2mask(bgc, gpio);
+ bgc->write_reg(bgc->reg_dir, bgc->dir);
+
+ spin_unlock_irqrestore(&bgc->lock, flags);
+
+ return 0;
+}
+
+static int bgpio_setup_accessors(struct device *dev,
+ struct bgpio_chip *bgc,
+ bool be)
+{
+
+ switch (bgc->bits) {
+ case 8:
+ bgc->read_reg = bgpio_read8;
+ bgc->write_reg = bgpio_write8;
+ break;
+ case 16:
+ bgc->read_reg = bgpio_read16;
+ bgc->write_reg = bgpio_write16;
+ break;
+ case 32:
+ bgc->read_reg = bgpio_read32;
+ bgc->write_reg = bgpio_write32;
+ break;
+#if BITS_PER_LONG >= 64
+ case 64:
+ bgc->read_reg = bgpio_read64;
+ bgc->write_reg = bgpio_write64;
+ break;
+#endif /* BITS_PER_LONG >= 64 */
+ default:
+ dev_err(dev, "unsupported data width %u bits\n", bgc->bits);
return -EINVAL;
+ }
- bgc = devm_kzalloc(dev, sizeof(*bgc), GFP_KERNEL);
- if (!bgc)
- return -ENOMEM;
+ bgc->pin2mask = be ? bgpio_pin2mask_be : bgpio_pin2mask;
+
+ return 0;
+}
+
+/*
+ * Create the device and allocate the resources. For setting GPIO's there are
+ * three supported configurations:
+ *
+ * - single input/output register resource (named "dat").
+ * - set/clear pair (named "set" and "clr").
+ * - single output register resource and single input resource ("set" and
+ * dat").
+ *
+ * For the single output register, this drives a 1 by setting a bit and a zero
+ * by clearing a bit. For the set clr pair, this drives a 1 by setting a bit
+ * in the set register and clears it by setting a bit in the clear register.
+ * The configuration is detected by which resources are present.
+ *
+ * For setting the GPIO direction, there are three supported configurations:
+ *
+ * - simple bidirection GPIO that requires no configuration.
+ * - an output direction register (named "dirout") where a 1 bit
+ * indicates the GPIO is an output.
+ * - an input direction register (named "dirin") where a 1 bit indicates
+ * the GPIO is an input.
+ */
+static int bgpio_setup_io(struct bgpio_chip *bgc,
+ void __iomem *dat,
+ void __iomem *set,
+ void __iomem *clr)
+{
- bgc->reg_dat = devm_ioremap(dev, res_dat->start, dat_sz);
+ bgc->reg_dat = dat;
if (!bgc->reg_dat)
- return -ENOMEM;
+ return -EINVAL;
+
+ if (set && clr) {
+ bgc->reg_set = set;
+ bgc->reg_clr = clr;
+ bgc->gc.set = bgpio_set_with_clear;
+ } else if (set && !clr) {
+ bgc->reg_set = set;
+ bgc->gc.set = bgpio_set_set;
+ } else {
+ bgc->gc.set = bgpio_set;
+ }
+
+ bgc->gc.get = bgpio_get;
+
+ return 0;
+}
- res_set = platform_get_resource_byname(pdev, IORESOURCE_MEM, "set");
- res_clr = platform_get_resource_byname(pdev, IORESOURCE_MEM, "clr");
- if (res_set && res_clr) {
- if (resource_size(res_set) != resource_size(res_clr) ||
- resource_size(res_set) != dat_sz)
- return -EINVAL;
-
- bgc->reg_set = devm_ioremap(dev, res_set->start, dat_sz);
- bgc->reg_clr = devm_ioremap(dev, res_clr->start, dat_sz);
- if (!bgc->reg_set || !bgc->reg_clr)
- return -ENOMEM;
- } else if (res_set || res_clr) {
+static int bgpio_setup_direction(struct bgpio_chip *bgc,
+ void __iomem *dirout,
+ void __iomem *dirin)
+{
+ if (dirout && dirin) {
return -EINVAL;
+ } else if (dirout) {
+ bgc->reg_dir = dirout;
+ bgc->gc.direction_output = bgpio_dir_out;
+ bgc->gc.direction_input = bgpio_dir_in;
+ } else if (dirin) {
+ bgc->reg_dir = dirin;
+ bgc->gc.direction_output = bgpio_dir_out_inv;
+ bgc->gc.direction_input = bgpio_dir_in_inv;
+ } else {
+ bgc->gc.direction_output = bgpio_simple_dir_out;
+ bgc->gc.direction_input = bgpio_simple_dir_in;
}
- spin_lock_init(&bgc->lock);
+ return 0;
+}
- bgc->bits = bits;
- bgc->big_endian_bits = !strcmp(platid->name, "basic-mmio-gpio-be");
- bgc->data = bgpio_in(bgc);
+int __devexit bgpio_remove(struct bgpio_chip *bgc)
+{
+ int err = gpiochip_remove(&bgc->gc);
- bgc->gc.ngpio = bits;
- bgc->gc.direction_input = bgpio_dir_in;
- bgc->gc.direction_output = bgpio_dir_out;
- bgc->gc.get = bgpio_get;
- bgc->gc.set = bgpio_set;
+ kfree(bgc);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(bgpio_remove);
+
+int __devinit bgpio_init(struct bgpio_chip *bgc,
+ struct device *dev,
+ unsigned long sz,
+ void __iomem *dat,
+ void __iomem *set,
+ void __iomem *clr,
+ void __iomem *dirout,
+ void __iomem *dirin,
+ bool big_endian)
+{
+ int ret;
+
+ if (!is_power_of_2(sz))
+ return -EINVAL;
+
+ bgc->bits = sz * 8;
+ if (bgc->bits > BITS_PER_LONG)
+ return -EINVAL;
+
+ spin_lock_init(&bgc->lock);
bgc->gc.dev = dev;
bgc->gc.label = dev_name(dev);
+ bgc->gc.base = -1;
+ bgc->gc.ngpio = bgc->bits;
- if (pdata)
- bgc->gc.base = pdata->base;
- else
- bgc->gc.base = -1;
+ ret = bgpio_setup_io(bgc, dat, set, clr);
+ if (ret)
+ return ret;
- dev_set_drvdata(dev, bgc);
+ ret = bgpio_setup_accessors(dev, bgc, big_endian);
+ if (ret)
+ return ret;
- ret = gpiochip_add(&bgc->gc);
+ ret = bgpio_setup_direction(bgc, dirout, dirin);
if (ret)
- dev_err(dev, "gpiochip_add() failed: %d\n", ret);
+ return ret;
+
+ bgc->data = bgc->read_reg(bgc->reg_dat);
return ret;
}
+EXPORT_SYMBOL_GPL(bgpio_init);
+
+#ifdef CONFIG_GPIO_BASIC_MMIO
-static int __devexit bgpio_remove(struct platform_device *pdev)
+static void __iomem *bgpio_map(struct platform_device *pdev,
+ const char *name,
+ resource_size_t sane_sz,
+ int *err)
{
- struct bgpio_chip *bgc = dev_get_drvdata(&pdev->dev);
+ struct device *dev = &pdev->dev;
+ struct resource *r;
+ resource_size_t start;
+ resource_size_t sz;
+ void __iomem *ret;
+
+ *err = 0;
+
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
+ if (!r)
+ return NULL;
- return gpiochip_remove(&bgc->gc);
+ sz = resource_size(r);
+ if (sz != sane_sz) {
+ *err = -EINVAL;
+ return NULL;
+ }
+
+ start = r->start;
+ if (!devm_request_mem_region(dev, start, sz, r->name)) {
+ *err = -EBUSY;
+ return NULL;
+ }
+
+ ret = devm_ioremap(dev, start, sz);
+ if (!ret) {
+ *err = -ENOMEM;
+ return NULL;
+ }
+
+ return ret;
+}
+
+static int __devinit bgpio_pdev_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *r;
+ void __iomem *dat;
+ void __iomem *set;
+ void __iomem *clr;
+ void __iomem *dirout;
+ void __iomem *dirin;
+ unsigned long sz;
+ bool be;
+ int err;
+ struct bgpio_chip *bgc;
+ struct bgpio_pdata *pdata = dev_get_platdata(dev);
+
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
+ if (!r)
+ return -EINVAL;
+
+ sz = resource_size(r);
+
+ dat = bgpio_map(pdev, "dat", sz, &err);
+ if (!dat)
+ return err ? err : -EINVAL;
+
+ set = bgpio_map(pdev, "set", sz, &err);
+ if (err)
+ return err;
+
+ clr = bgpio_map(pdev, "clr", sz, &err);
+ if (err)
+ return err;
+
+ dirout = bgpio_map(pdev, "dirout", sz, &err);
+ if (err)
+ return err;
+
+ dirin = bgpio_map(pdev, "dirin", sz, &err);
+ if (err)
+ return err;
+
+ be = !strcmp(platform_get_device_id(pdev)->name, "basic-mmio-gpio-be");
+
+ bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL);
+ if (!bgc)
+ return -ENOMEM;
+
+ err = bgpio_init(bgc, dev, sz, dat, set, clr, dirout, dirin, be);
+ if (err)
+ return err;
+
+ if (pdata) {
+ bgc->gc.base = pdata->base;
+ if (pdata->ngpio > 0)
+ bgc->gc.ngpio = pdata->ngpio;
+ }
+
+ platform_set_drvdata(pdev, bgc);
+
+ return gpiochip_add(&bgc->gc);
+}
+
+static int __devexit bgpio_pdev_remove(struct platform_device *pdev)
+{
+ struct bgpio_chip *bgc = platform_get_drvdata(pdev);
+
+ return bgpio_remove(bgc);
}
static const struct platform_device_id bgpio_id_table[] = {
@@ -276,21 +525,23 @@ static struct platform_driver bgpio_driver = {
.name = "basic-mmio-gpio",
},
.id_table = bgpio_id_table,
- .probe = bgpio_probe,
- .remove = __devexit_p(bgpio_remove),
+ .probe = bgpio_pdev_probe,
+ .remove = __devexit_p(bgpio_pdev_remove),
};
-static int __init bgpio_init(void)
+static int __init bgpio_platform_init(void)
{
return platform_driver_register(&bgpio_driver);
}
-module_init(bgpio_init);
+module_init(bgpio_platform_init);
-static void __exit bgpio_exit(void)
+static void __exit bgpio_platform_exit(void)
{
platform_driver_unregister(&bgpio_driver);
}
-module_exit(bgpio_exit);
+module_exit(bgpio_platform_exit);
+
+#endif /* CONFIG_GPIO_BASIC_MMIO */
MODULE_DESCRIPTION("Driver for basic memory-mapped GPIO controllers");
MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>");
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 36a2974815b7..137a8ca67822 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -12,6 +12,8 @@
#include <linux/idr.h>
#include <linux/slab.h>
+#define CREATE_TRACE_POINTS
+#include <trace/events/gpio.h>
/* Optional implementation infrastructure for GPIO interfaces.
*
@@ -1165,6 +1167,7 @@ struct gpio_chip *gpiochip_find(void *data,
return chip;
}
+EXPORT_SYMBOL_GPL(gpiochip_find);
/* These "optional" allocation calls help prevent drivers from stomping
* on each other, and help provide better diagnostics in debugfs.
@@ -1404,6 +1407,8 @@ int gpio_direction_input(unsigned gpio)
status = chip->direction_input(chip, gpio);
if (status == 0)
clear_bit(FLAG_IS_OUT, &desc->flags);
+
+ trace_gpio_direction(chip->base + gpio, 1, status);
lose:
return status;
fail:
@@ -1457,6 +1462,8 @@ int gpio_direction_output(unsigned gpio, int value)
status = chip->direction_output(chip, gpio, value);
if (status == 0)
set_bit(FLAG_IS_OUT, &desc->flags);
+ trace_gpio_value(chip->base + gpio, 0, value);
+ trace_gpio_direction(chip->base + gpio, 0, status);
lose:
return status;
fail:
@@ -1546,10 +1553,13 @@ EXPORT_SYMBOL_GPL(gpio_set_debounce);
int __gpio_get_value(unsigned gpio)
{
struct gpio_chip *chip;
+ int value;
chip = gpio_to_chip(gpio);
WARN_ON(chip->can_sleep);
- return chip->get ? chip->get(chip, gpio - chip->base) : 0;
+ value = chip->get ? chip->get(chip, gpio - chip->base) : 0;
+ trace_gpio_value(gpio, 1, value);
+ return value;
}
EXPORT_SYMBOL_GPL(__gpio_get_value);
@@ -1568,6 +1578,7 @@ void __gpio_set_value(unsigned gpio, int value)
chip = gpio_to_chip(gpio);
WARN_ON(chip->can_sleep);
+ trace_gpio_value(gpio, 0, value);
chip->set(chip, gpio - chip->base, value);
}
EXPORT_SYMBOL_GPL(__gpio_set_value);
@@ -1618,10 +1629,13 @@ EXPORT_SYMBOL_GPL(__gpio_to_irq);
int gpio_get_value_cansleep(unsigned gpio)
{
struct gpio_chip *chip;
+ int value;
might_sleep_if(extra_checks);
chip = gpio_to_chip(gpio);
- return chip->get ? chip->get(chip, gpio - chip->base) : 0;
+ value = chip->get ? chip->get(chip, gpio - chip->base) : 0;
+ trace_gpio_value(gpio, 1, value);
+ return value;
}
EXPORT_SYMBOL_GPL(gpio_get_value_cansleep);
@@ -1631,6 +1645,7 @@ void gpio_set_value_cansleep(unsigned gpio, int value)
might_sleep_if(extra_checks);
chip = gpio_to_chip(gpio);
+ trace_gpio_value(gpio, 0, value);
chip->set(chip, gpio - chip->base, value);
}
EXPORT_SYMBOL_GPL(gpio_set_value_cansleep);
diff --git a/drivers/gpio/janz-ttl.c b/drivers/gpio/janz-ttl.c
index 2514fb075f4a..813ac077e5d7 100644
--- a/drivers/gpio/janz-ttl.c
+++ b/drivers/gpio/janz-ttl.c
@@ -15,7 +15,6 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
-#include <linux/mfd/core.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/slab.h>
@@ -150,7 +149,7 @@ static int __devinit ttl_probe(struct platform_device *pdev)
struct resource *res;
int ret;
- pdata = mfd_get_data(pdev);
+ pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(dev, "no platform data\n");
ret = -ENXIO;
diff --git a/drivers/gpio/langwell_gpio.c b/drivers/gpio/langwell_gpio.c
index 560ab648cf18..1b06f67e1f69 100644
--- a/drivers/gpio/langwell_gpio.c
+++ b/drivers/gpio/langwell_gpio.c
@@ -122,7 +122,7 @@ static int lnw_gpio_direction_output(struct gpio_chip *chip,
lnw_gpio_set(chip, offset, value);
spin_lock_irqsave(&lnw->lock, flags);
value = readl(gpdr);
- value |= BIT(offset % 32);;
+ value |= BIT(offset % 32);
writel(value, gpdr);
spin_unlock_irqrestore(&lnw->lock, flags);
return 0;
diff --git a/drivers/gpio/ml_ioh_gpio.c b/drivers/gpio/ml_ioh_gpio.c
index 0a775f7987c2..1bc621ac3536 100644
--- a/drivers/gpio/ml_ioh_gpio.c
+++ b/drivers/gpio/ml_ioh_gpio.c
@@ -15,6 +15,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*/
#include <linux/kernel.h>
+#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/gpio.h>
@@ -138,6 +139,7 @@ static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
return 0;
}
+#ifdef CONFIG_PM
/*
* Save register configuration and disable interrupts.
*/
@@ -157,6 +159,7 @@ static void ioh_gpio_restore_reg_conf(struct ioh_gpio *chip)
/* to store contents of PM register */
iowrite32(chip->ioh_gpio_reg.pm_reg, &chip->reg->regs[chip->ch].pm);
}
+#endif
static void ioh_gpio_setup(struct ioh_gpio *chip, int num_port)
{
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
index 7630ab7b9bec..78a843947d82 100644
--- a/drivers/gpio/pca953x.c
+++ b/drivers/gpio/pca953x.c
@@ -397,7 +397,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
irq_set_chip_data(irq, chip);
irq_set_chip_and_handler(irq, &pca953x_irq_chip,
- handle_edge_irq);
+ handle_simple_irq);
#ifdef CONFIG_ARM
set_irq_flags(irq, IRQF_VALID);
#else
diff --git a/drivers/gpio/rdc321x-gpio.c b/drivers/gpio/rdc321x-gpio.c
index a9bda881935a..2762698e0204 100644
--- a/drivers/gpio/rdc321x-gpio.c
+++ b/drivers/gpio/rdc321x-gpio.c
@@ -27,7 +27,6 @@
#include <linux/pci.h>
#include <linux/gpio.h>
#include <linux/mfd/rdc321x.h>
-#include <linux/mfd/core.h>
#include <linux/slab.h>
struct rdc321x_gpio {
@@ -136,7 +135,7 @@ static int __devinit rdc321x_gpio_probe(struct platform_device *pdev)
struct rdc321x_gpio *rdc321x_gpio_dev;
struct rdc321x_gpio_pdata *pdata;
- pdata = mfd_get_data(pdev);
+ pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(&pdev->dev, "no platform data supplied\n");
return -ENODEV;
diff --git a/drivers/gpio/timbgpio.c b/drivers/gpio/timbgpio.c
index edbe1eae531f..0265872e57d1 100644
--- a/drivers/gpio/timbgpio.c
+++ b/drivers/gpio/timbgpio.c
@@ -23,7 +23,6 @@
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
-#include <linux/mfd/core.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/timb_gpio.h>
@@ -229,7 +228,7 @@ static int __devinit timbgpio_probe(struct platform_device *pdev)
struct gpio_chip *gc;
struct timbgpio *tgpio;
struct resource *iomem;
- struct timbgpio_platform_data *pdata = mfd_get_data(pdev);
+ struct timbgpio_platform_data *pdata = pdev->dev.platform_data;
int irq = platform_get_irq(pdev, 0);
if (!pdata || pdata->nr_pins > 32) {
@@ -320,13 +319,14 @@ err_mem:
static int __devexit timbgpio_remove(struct platform_device *pdev)
{
int err;
+ struct timbgpio_platform_data *pdata = pdev->dev.platform_data;
struct timbgpio *tgpio = platform_get_drvdata(pdev);
struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
int irq = platform_get_irq(pdev, 0);
if (irq >= 0 && tgpio->irq_base > 0) {
int i;
- for (i = 0; i < tgpio->gpio.ngpio; i++) {
+ for (i = 0; i < pdata->nr_pins; i++) {
irq_set_chip(tgpio->irq_base + i, NULL);
irq_set_chip_data(tgpio->irq_base + i, NULL);
}
diff --git a/drivers/gpio/tps65910-gpio.c b/drivers/gpio/tps65910-gpio.c
new file mode 100644
index 000000000000..8d1ddfdd63eb
--- /dev/null
+++ b/drivers/gpio/tps65910-gpio.c
@@ -0,0 +1,100 @@
+/*
+ * tps65910-gpio.c -- TI TPS6591x
+ *
+ * Copyright 2010 Texas Instruments Inc.
+ *
+ * Author: Graeme Gregory <gg@slimlogic.co.uk>
+ * Author: Jorge Eduardo Candelaria jedu@slimlogic.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/mfd/tps65910.h>
+
+static int tps65910_gpio_get(struct gpio_chip *gc, unsigned offset)
+{
+ struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
+ uint8_t val;
+
+ tps65910->read(tps65910, TPS65910_GPIO0 + offset, 1, &val);
+
+ if (val & GPIO_STS_MASK)
+ return 1;
+
+ return 0;
+}
+
+static void tps65910_gpio_set(struct gpio_chip *gc, unsigned offset,
+ int value)
+{
+ struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
+
+ if (value)
+ tps65910_set_bits(tps65910, TPS65910_GPIO0 + offset,
+ GPIO_SET_MASK);
+ else
+ tps65910_clear_bits(tps65910, TPS65910_GPIO0 + offset,
+ GPIO_SET_MASK);
+}
+
+static int tps65910_gpio_output(struct gpio_chip *gc, unsigned offset,
+ int value)
+{
+ struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
+
+ /* Set the initial value */
+ tps65910_gpio_set(gc, 0, value);
+
+ return tps65910_set_bits(tps65910, TPS65910_GPIO0 + offset,
+ GPIO_CFG_MASK);
+}
+
+static int tps65910_gpio_input(struct gpio_chip *gc, unsigned offset)
+{
+ struct tps65910 *tps65910 = container_of(gc, struct tps65910, gpio);
+
+ return tps65910_clear_bits(tps65910, TPS65910_GPIO0 + offset,
+ GPIO_CFG_MASK);
+}
+
+void tps65910_gpio_init(struct tps65910 *tps65910, int gpio_base)
+{
+ int ret;
+
+ if (!gpio_base)
+ return;
+
+ tps65910->gpio.owner = THIS_MODULE;
+ tps65910->gpio.label = tps65910->i2c_client->name;
+ tps65910->gpio.dev = tps65910->dev;
+ tps65910->gpio.base = gpio_base;
+
+ switch(tps65910_chip_id(tps65910)) {
+ case TPS65910:
+ tps65910->gpio.ngpio = 6;
+ case TPS65911:
+ tps65910->gpio.ngpio = 9;
+ default:
+ return;
+ }
+ tps65910->gpio.can_sleep = 1;
+
+ tps65910->gpio.direction_input = tps65910_gpio_input;
+ tps65910->gpio.direction_output = tps65910_gpio_output;
+ tps65910->gpio.set = tps65910_gpio_set;
+ tps65910->gpio.get = tps65910_gpio_get;
+
+ ret = gpiochip_add(&tps65910->gpio);
+
+ if (ret)
+ dev_warn(tps65910->dev, "GPIO registration failed: %d\n", ret);
+}
diff --git a/drivers/gpio/vx855_gpio.c b/drivers/gpio/vx855_gpio.c
index 8a98ee5d5f6c..ef5aabd8b8b7 100644
--- a/drivers/gpio/vx855_gpio.c
+++ b/drivers/gpio/vx855_gpio.c
@@ -26,6 +26,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/gpio.h>
+#include <linux/slab.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/pci.h>
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index adc9358c9bec..0a9357c66ff8 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -1413,6 +1413,64 @@ end:
EXPORT_SYMBOL(drm_detect_monitor_audio);
/**
+ * drm_add_display_info - pull display info out if present
+ * @edid: EDID data
+ * @info: display info (attached to connector)
+ *
+ * Grab any available display info and stuff it into the drm_display_info
+ * structure that's part of the connector. Useful for tracking bpp and
+ * color spaces.
+ */
+static void drm_add_display_info(struct edid *edid,
+ struct drm_display_info *info)
+{
+ info->width_mm = edid->width_cm * 10;
+ info->height_mm = edid->height_cm * 10;
+
+ /* driver figures it out in this case */
+ info->bpc = 0;
+ info->color_formats = 0;
+
+ /* Only defined for 1.4 with digital displays */
+ if (edid->revision < 4)
+ return;
+
+ if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
+ return;
+
+ switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) {
+ case DRM_EDID_DIGITAL_DEPTH_6:
+ info->bpc = 6;
+ break;
+ case DRM_EDID_DIGITAL_DEPTH_8:
+ info->bpc = 8;
+ break;
+ case DRM_EDID_DIGITAL_DEPTH_10:
+ info->bpc = 10;
+ break;
+ case DRM_EDID_DIGITAL_DEPTH_12:
+ info->bpc = 12;
+ break;
+ case DRM_EDID_DIGITAL_DEPTH_14:
+ info->bpc = 14;
+ break;
+ case DRM_EDID_DIGITAL_DEPTH_16:
+ info->bpc = 16;
+ break;
+ case DRM_EDID_DIGITAL_DEPTH_UNDEF:
+ default:
+ info->bpc = 0;
+ break;
+ }
+
+ info->color_formats = DRM_COLOR_FORMAT_RGB444;
+ if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB444)
+ info->color_formats = DRM_COLOR_FORMAT_YCRCB444;
+ if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB422)
+ info->color_formats = DRM_COLOR_FORMAT_YCRCB422;
+}
+
+/**
* drm_add_edid_modes - add modes from EDID data, if available
* @connector: connector we're probing
* @edid: edid data
@@ -1460,8 +1518,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
edid_fixup_preferred(connector, quirks);
- connector->display_info.width_mm = edid->width_cm * 10;
- connector->display_info.height_mm = edid->height_cm * 10;
+ drm_add_display_info(edid, &connector->display_info);
return num_modes;
}
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 140b9525b48a..802b61ac3139 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -70,174 +70,50 @@ fail:
}
EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
-/**
- * drm_fb_helper_connector_parse_command_line - parse command line for connector
- * @connector - connector to parse line for
- * @mode_option - per connector mode option
- *
- * This parses the connector specific then generic command lines for
- * modes and options to configure the connector.
- *
- * This uses the same parameters as the fb modedb.c, except for extra
- * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
- *
- * enable/enable Digital/disable bit at the end
- */
-static bool drm_fb_helper_connector_parse_command_line(struct drm_fb_helper_connector *fb_helper_conn,
- const char *mode_option)
-{
- const char *name;
- unsigned int namelen;
- int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
- unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
- int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
- int i;
- enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
- struct drm_fb_helper_cmdline_mode *cmdline_mode;
- struct drm_connector *connector;
-
- if (!fb_helper_conn)
- return false;
- connector = fb_helper_conn->connector;
-
- cmdline_mode = &fb_helper_conn->cmdline_mode;
- if (!mode_option)
- mode_option = fb_mode_option;
-
- if (!mode_option) {
- cmdline_mode->specified = false;
- return false;
- }
-
- name = mode_option;
- namelen = strlen(name);
- for (i = namelen-1; i >= 0; i--) {
- switch (name[i]) {
- case '@':
- namelen = i;
- if (!refresh_specified && !bpp_specified &&
- !yres_specified) {
- refresh = simple_strtol(&name[i+1], NULL, 10);
- refresh_specified = 1;
- if (cvt || rb)
- cvt = 0;
- } else
- goto done;
- break;
- case '-':
- namelen = i;
- if (!bpp_specified && !yres_specified) {
- bpp = simple_strtol(&name[i+1], NULL, 10);
- bpp_specified = 1;
- if (cvt || rb)
- cvt = 0;
- } else
- goto done;
- break;
- case 'x':
- if (!yres_specified) {
- yres = simple_strtol(&name[i+1], NULL, 10);
- yres_specified = 1;
- } else
- goto done;
- case '0' ... '9':
- break;
- case 'M':
- if (!yres_specified)
- cvt = 1;
- break;
- case 'R':
- if (cvt)
- rb = 1;
- break;
- case 'm':
- if (!cvt)
- margins = 1;
- break;
- case 'i':
- if (!cvt)
- interlace = 1;
- break;
- case 'e':
- force = DRM_FORCE_ON;
- break;
- case 'D':
- if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
- (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
- force = DRM_FORCE_ON;
- else
- force = DRM_FORCE_ON_DIGITAL;
- break;
- case 'd':
- force = DRM_FORCE_OFF;
- break;
- default:
- goto done;
- }
- }
- if (i < 0 && yres_specified) {
- xres = simple_strtol(name, NULL, 10);
- res_specified = 1;
- }
-done:
-
- DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
- drm_get_connector_name(connector), xres, yres,
- (refresh) ? refresh : 60, (rb) ? " reduced blanking" :
- "", (margins) ? " with margins" : "", (interlace) ?
- " interlaced" : "");
-
- if (force) {
- const char *s;
- switch (force) {
- case DRM_FORCE_OFF: s = "OFF"; break;
- case DRM_FORCE_ON_DIGITAL: s = "ON - dig"; break;
- default:
- case DRM_FORCE_ON: s = "ON"; break;
- }
-
- DRM_INFO("forcing %s connector %s\n",
- drm_get_connector_name(connector), s);
- connector->force = force;
- }
-
- if (res_specified) {
- cmdline_mode->specified = true;
- cmdline_mode->xres = xres;
- cmdline_mode->yres = yres;
- }
-
- if (refresh_specified) {
- cmdline_mode->refresh_specified = true;
- cmdline_mode->refresh = refresh;
- }
-
- if (bpp_specified) {
- cmdline_mode->bpp_specified = true;
- cmdline_mode->bpp = bpp;
- }
- cmdline_mode->rb = rb ? true : false;
- cmdline_mode->cvt = cvt ? true : false;
- cmdline_mode->interlace = interlace ? true : false;
-
- return true;
-}
-
static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper)
{
struct drm_fb_helper_connector *fb_helper_conn;
int i;
for (i = 0; i < fb_helper->connector_count; i++) {
+ struct drm_cmdline_mode *mode;
+ struct drm_connector *connector;
char *option = NULL;
fb_helper_conn = fb_helper->connector_info[i];
+ connector = fb_helper_conn->connector;
+ mode = &fb_helper_conn->cmdline_mode;
/* do something on return - turn off connector maybe */
- if (fb_get_options(drm_get_connector_name(fb_helper_conn->connector), &option))
+ if (fb_get_options(drm_get_connector_name(connector), &option))
continue;
- drm_fb_helper_connector_parse_command_line(fb_helper_conn, option);
+ if (drm_mode_parse_command_line_for_connector(option,
+ connector,
+ mode)) {
+ if (mode->force) {
+ const char *s;
+ switch (mode->force) {
+ case DRM_FORCE_OFF: s = "OFF"; break;
+ case DRM_FORCE_ON_DIGITAL: s = "ON - dig"; break;
+ default:
+ case DRM_FORCE_ON: s = "ON"; break;
+ }
+
+ DRM_INFO("forcing %s connector %s\n",
+ drm_get_connector_name(connector), s);
+ connector->force = mode->force;
+ }
+
+ DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
+ drm_get_connector_name(connector),
+ mode->xres, mode->yres,
+ mode->refresh_specified ? mode->refresh : 60,
+ mode->rb ? " reduced blanking" : "",
+ mode->margins ? " with margins" : "",
+ mode->interlace ? " interlaced" : "");
+ }
+
}
return 0;
}
@@ -901,7 +777,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
/* first up get a count of crtcs now in use and new min/maxes width/heights */
for (i = 0; i < fb_helper->connector_count; i++) {
struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
- struct drm_fb_helper_cmdline_mode *cmdline_mode;
+ struct drm_cmdline_mode *cmdline_mode;
cmdline_mode = &fb_helper_conn->cmdline_mode;
@@ -1123,7 +999,7 @@ static struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_conn
static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
{
- struct drm_fb_helper_cmdline_mode *cmdline_mode;
+ struct drm_cmdline_mode *cmdline_mode;
cmdline_mode = &fb_connector->cmdline_mode;
return cmdline_mode->specified;
}
@@ -1131,7 +1007,7 @@ static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
int width, int height)
{
- struct drm_fb_helper_cmdline_mode *cmdline_mode;
+ struct drm_cmdline_mode *cmdline_mode;
struct drm_display_mode *mode = NULL;
cmdline_mode = &fb_helper_conn->cmdline_mode;
@@ -1163,19 +1039,8 @@ static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_conne
}
create_mode:
- if (cmdline_mode->cvt)
- mode = drm_cvt_mode(fb_helper_conn->connector->dev,
- cmdline_mode->xres, cmdline_mode->yres,
- cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
- cmdline_mode->rb, cmdline_mode->interlace,
- cmdline_mode->margins);
- else
- mode = drm_gtf_mode(fb_helper_conn->connector->dev,
- cmdline_mode->xres, cmdline_mode->yres,
- cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
- cmdline_mode->interlace,
- cmdline_mode->margins);
- drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+ mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev,
+ cmdline_mode);
list_add(&mode->head, &fb_helper_conn->connector->modes);
return mode;
}
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index a1f12cb043de..2022a5c966bb 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -684,10 +684,11 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
*/
*vblank_time = ns_to_timeval(timeval_to_ns(&raw_time) - delta_ns);
- DRM_DEBUG("crtc %d : v %d p(%d,%d)@ %d.%d -> %d.%d [e %d us, %d rep]\n",
- crtc, (int) vbl_status, hpos, vpos, raw_time.tv_sec,
- raw_time.tv_usec, vblank_time->tv_sec, vblank_time->tv_usec,
- (int) duration_ns/1000, i);
+ DRM_DEBUG("crtc %d : v %d p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n",
+ crtc, (int)vbl_status, hpos, vpos,
+ (long)raw_time.tv_sec, (long)raw_time.tv_usec,
+ (long)vblank_time->tv_sec, (long)vblank_time->tv_usec,
+ (int)duration_ns/1000, i);
vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD;
if (invbl)
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 25bf87390f53..c2d32f20e2fb 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -974,3 +974,159 @@ void drm_mode_connector_list_update(struct drm_connector *connector)
}
}
EXPORT_SYMBOL(drm_mode_connector_list_update);
+
+/**
+ * drm_mode_parse_command_line_for_connector - parse command line for connector
+ * @mode_option - per connector mode option
+ * @connector - connector to parse line for
+ *
+ * This parses the connector specific then generic command lines for
+ * modes and options to configure the connector.
+ *
+ * This uses the same parameters as the fb modedb.c, except for extra
+ * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
+ *
+ * enable/enable Digital/disable bit at the end
+ */
+bool drm_mode_parse_command_line_for_connector(const char *mode_option,
+ struct drm_connector *connector,
+ struct drm_cmdline_mode *mode)
+{
+ const char *name;
+ unsigned int namelen;
+ int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
+ unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
+ int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
+ int i;
+ enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
+
+#ifdef CONFIG_FB
+ if (!mode_option)
+ mode_option = fb_mode_option;
+#endif
+
+ if (!mode_option) {
+ mode->specified = false;
+ return false;
+ }
+
+ name = mode_option;
+ namelen = strlen(name);
+ for (i = namelen-1; i >= 0; i--) {
+ switch (name[i]) {
+ case '@':
+ namelen = i;
+ if (!refresh_specified && !bpp_specified &&
+ !yres_specified) {
+ refresh = simple_strtol(&name[i+1], NULL, 10);
+ refresh_specified = 1;
+ if (cvt || rb)
+ cvt = 0;
+ } else
+ goto done;
+ break;
+ case '-':
+ namelen = i;
+ if (!bpp_specified && !yres_specified) {
+ bpp = simple_strtol(&name[i+1], NULL, 10);
+ bpp_specified = 1;
+ if (cvt || rb)
+ cvt = 0;
+ } else
+ goto done;
+ break;
+ case 'x':
+ if (!yres_specified) {
+ yres = simple_strtol(&name[i+1], NULL, 10);
+ yres_specified = 1;
+ } else
+ goto done;
+ case '0' ... '9':
+ break;
+ case 'M':
+ if (!yres_specified)
+ cvt = 1;
+ break;
+ case 'R':
+ if (cvt)
+ rb = 1;
+ break;
+ case 'm':
+ if (!cvt)
+ margins = 1;
+ break;
+ case 'i':
+ if (!cvt)
+ interlace = 1;
+ break;
+ case 'e':
+ force = DRM_FORCE_ON;
+ break;
+ case 'D':
+ if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
+ (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
+ force = DRM_FORCE_ON;
+ else
+ force = DRM_FORCE_ON_DIGITAL;
+ break;
+ case 'd':
+ force = DRM_FORCE_OFF;
+ break;
+ default:
+ goto done;
+ }
+ }
+ if (i < 0 && yres_specified) {
+ xres = simple_strtol(name, NULL, 10);
+ res_specified = 1;
+ }
+done:
+ if (res_specified) {
+ mode->specified = true;
+ mode->xres = xres;
+ mode->yres = yres;
+ }
+
+ if (refresh_specified) {
+ mode->refresh_specified = true;
+ mode->refresh = refresh;
+ }
+
+ if (bpp_specified) {
+ mode->bpp_specified = true;
+ mode->bpp = bpp;
+ }
+ mode->rb = rb ? true : false;
+ mode->cvt = cvt ? true : false;
+ mode->interlace = interlace ? true : false;
+ mode->force = force;
+
+ return true;
+}
+EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector);
+
+struct drm_display_mode *
+drm_mode_create_from_cmdline_mode(struct drm_device *dev,
+ struct drm_cmdline_mode *cmd)
+{
+ struct drm_display_mode *mode;
+
+ if (cmd->cvt)
+ mode = drm_cvt_mode(dev,
+ cmd->xres, cmd->yres,
+ cmd->refresh_specified ? cmd->refresh : 60,
+ cmd->rb, cmd->interlace,
+ cmd->margins);
+ else
+ mode = drm_gtf_mode(dev,
+ cmd->xres, cmd->yres,
+ cmd->refresh_specified ? cmd->refresh : 60,
+ cmd->interlace,
+ cmd->margins);
+ if (!mode)
+ return NULL;
+
+ drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+ return mode;
+}
+EXPORT_SYMBOL(drm_mode_create_from_cmdline_mode);
diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c
index 001273d57f2d..6d7b083c5b77 100644
--- a/drivers/gpu/drm/drm_stub.c
+++ b/drivers/gpu/drm/drm_stub.c
@@ -62,6 +62,26 @@ struct idr drm_minors_idr;
struct class *drm_class;
struct proc_dir_entry *drm_proc_root;
struct dentry *drm_debugfs_root;
+
+int drm_err(const char *func, const char *format, ...)
+{
+ struct va_format vaf;
+ va_list args;
+ int r;
+
+ va_start(args, format);
+
+ vaf.fmt = format;
+ vaf.va = &args;
+
+ r = printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* %pV", func, &vaf);
+
+ va_end(args);
+
+ return r;
+}
+EXPORT_SYMBOL(drm_err);
+
void drm_ut_debug_printk(unsigned int request_level,
const char *prefix,
const char *function_name,
@@ -78,6 +98,7 @@ void drm_ut_debug_printk(unsigned int request_level,
}
}
EXPORT_SYMBOL(drm_ut_debug_printk);
+
static int drm_minor_get_id(struct drm_device *dev, int type)
{
int new_id;
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 87c8e29465e3..51c2257b11e6 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -106,11 +106,12 @@ static const char *get_tiling_flag(struct drm_i915_gem_object *obj)
}
}
-static const char *agp_type_str(int type)
+static const char *cache_level_str(int type)
{
switch (type) {
- case 0: return " uncached";
- case 1: return " snooped";
+ case I915_CACHE_NONE: return " uncached";
+ case I915_CACHE_LLC: return " snooped (LLC)";
+ case I915_CACHE_LLC_MLC: return " snooped (LLC+MLC)";
default: return "";
}
}
@@ -127,7 +128,7 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
obj->base.write_domain,
obj->last_rendering_seqno,
obj->last_fenced_seqno,
- agp_type_str(obj->agp_type == AGP_USER_CACHED_MEMORY),
+ cache_level_str(obj->cache_level),
obj->dirty ? " dirty" : "",
obj->madv == I915_MADV_DONTNEED ? " purgeable" : "");
if (obj->base.name)
@@ -714,7 +715,7 @@ static void print_error_buffers(struct seq_file *m,
dirty_flag(err->dirty),
purgeable_flag(err->purgeable),
ring_str(err->ring),
- agp_type_str(err->agp_type));
+ cache_level_str(err->cache_level));
if (err->name)
seq_printf(m, " (name: %d)", err->name);
@@ -852,6 +853,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
+ int ret;
if (IS_GEN5(dev)) {
u16 rgvswctl = I915_READ16(MEMSWCTL);
@@ -873,7 +875,11 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
int max_freq;
/* RPSTAT1 is in the GT power well */
- __gen6_gt_force_wake_get(dev_priv);
+ ret = mutex_lock_interruptible(&dev->struct_mutex);
+ if (ret)
+ return ret;
+
+ gen6_gt_force_wake_get(dev_priv);
rpstat = I915_READ(GEN6_RPSTAT1);
rpupei = I915_READ(GEN6_RP_CUR_UP_EI);
@@ -883,6 +889,9 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
rpcurdown = I915_READ(GEN6_RP_CUR_DOWN);
rpprevdown = I915_READ(GEN6_RP_PREV_DOWN);
+ gen6_gt_force_wake_put(dev_priv);
+ mutex_unlock(&dev->struct_mutex);
+
seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status);
seq_printf(m, "RPSTAT1: 0x%08x\n", rpstat);
seq_printf(m, "Render p-state ratio: %d\n",
@@ -917,8 +926,6 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
max_freq = rp_state_cap & 0xff;
seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n",
max_freq * 50);
-
- __gen6_gt_force_wake_put(dev_priv);
} else {
seq_printf(m, "no P-state info available\n");
}
@@ -1058,6 +1065,9 @@ static int i915_fbc_status(struct seq_file *m, void *unused)
case FBC_MULTIPLE_PIPES:
seq_printf(m, "multiple pipes are enabled");
break;
+ case FBC_MODULE_PARAM:
+ seq_printf(m, "disabled per module param (default off)");
+ break;
default:
seq_printf(m, "unknown reason");
}
@@ -1186,6 +1196,42 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
return 0;
}
+static int i915_context_status(struct seq_file *m, void *unused)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ int ret;
+
+ ret = mutex_lock_interruptible(&dev->mode_config.mutex);
+ if (ret)
+ return ret;
+
+ seq_printf(m, "power context ");
+ describe_obj(m, dev_priv->pwrctx);
+ seq_printf(m, "\n");
+
+ seq_printf(m, "render context ");
+ describe_obj(m, dev_priv->renderctx);
+ seq_printf(m, "\n");
+
+ mutex_unlock(&dev->mode_config.mutex);
+
+ return 0;
+}
+
+static int i915_gen6_forcewake_count_info(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ seq_printf(m, "forcewake count = %d\n",
+ atomic_read(&dev_priv->forcewake_count));
+
+ return 0;
+}
+
static int
i915_wedged_open(struct inode *inode,
struct file *filp)
@@ -1288,6 +1334,67 @@ static int i915_wedged_create(struct dentry *root, struct drm_minor *minor)
return drm_add_fake_info_node(minor, ent, &i915_wedged_fops);
}
+static int i915_forcewake_open(struct inode *inode, struct file *file)
+{
+ struct drm_device *dev = inode->i_private;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int ret;
+
+ if (!IS_GEN6(dev))
+ return 0;
+
+ ret = mutex_lock_interruptible(&dev->struct_mutex);
+ if (ret)
+ return ret;
+ gen6_gt_force_wake_get(dev_priv);
+ mutex_unlock(&dev->struct_mutex);
+
+ return 0;
+}
+
+int i915_forcewake_release(struct inode *inode, struct file *file)
+{
+ struct drm_device *dev = inode->i_private;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (!IS_GEN6(dev))
+ return 0;
+
+ /*
+ * It's bad that we can potentially hang userspace if struct_mutex gets
+ * forever stuck. However, if we cannot acquire this lock it means that
+ * almost certainly the driver has hung, is not unload-able. Therefore
+ * hanging here is probably a minor inconvenience not to be seen my
+ * almost every user.
+ */
+ mutex_lock(&dev->struct_mutex);
+ gen6_gt_force_wake_put(dev_priv);
+ mutex_unlock(&dev->struct_mutex);
+
+ return 0;
+}
+
+static const struct file_operations i915_forcewake_fops = {
+ .owner = THIS_MODULE,
+ .open = i915_forcewake_open,
+ .release = i915_forcewake_release,
+};
+
+static int i915_forcewake_create(struct dentry *root, struct drm_minor *minor)
+{
+ struct drm_device *dev = minor->dev;
+ struct dentry *ent;
+
+ ent = debugfs_create_file("i915_forcewake_user",
+ S_IRUSR,
+ root, dev,
+ &i915_forcewake_fops);
+ if (IS_ERR(ent))
+ return PTR_ERR(ent);
+
+ return drm_add_fake_info_node(minor, ent, &i915_forcewake_fops);
+}
+
static struct drm_info_list i915_debugfs_list[] = {
{"i915_capabilities", i915_capabilities, 0},
{"i915_gem_objects", i915_gem_object_info, 0},
@@ -1324,6 +1431,8 @@ static struct drm_info_list i915_debugfs_list[] = {
{"i915_sr_status", i915_sr_status, 0},
{"i915_opregion", i915_opregion, 0},
{"i915_gem_framebuffer", i915_gem_framebuffer_info, 0},
+ {"i915_context_status", i915_context_status, 0},
+ {"i915_gen6_forcewake_count", i915_gen6_forcewake_count_info, 0},
};
#define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
@@ -1335,6 +1444,10 @@ int i915_debugfs_init(struct drm_minor *minor)
if (ret)
return ret;
+ ret = i915_forcewake_create(minor->debugfs_root, minor);
+ if (ret)
+ return ret;
+
return drm_debugfs_create_files(i915_debugfs_list,
I915_DEBUGFS_ENTRIES,
minor->debugfs_root, minor);
@@ -1344,6 +1457,8 @@ void i915_debugfs_cleanup(struct drm_minor *minor)
{
drm_debugfs_remove_files(i915_debugfs_list,
I915_DEBUGFS_ENTRIES, minor);
+ drm_debugfs_remove_files((struct drm_info_list *) &i915_forcewake_fops,
+ 1, minor);
drm_debugfs_remove_files((struct drm_info_list *) &i915_wedged_fops,
1, minor);
}
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 12876f2795d2..0239e9974bf2 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -571,7 +571,7 @@ static int i915_quiescent(struct drm_device *dev)
struct intel_ring_buffer *ring = LP_RING(dev->dev_private);
i915_kernel_lost_context(dev);
- return intel_wait_ring_buffer(ring, ring->size - 8);
+ return intel_wait_ring_idle(ring);
}
static int i915_flush_ioctl(struct drm_device *dev, void *data,
@@ -1176,11 +1176,11 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
return can_switch;
}
-static int i915_load_modeset_init(struct drm_device *dev)
+static int i915_load_gem_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long prealloc_size, gtt_size, mappable_size;
- int ret = 0;
+ int ret;
prealloc_size = dev_priv->mm.gtt->stolen_size;
gtt_size = dev_priv->mm.gtt->gtt_total_entries << PAGE_SHIFT;
@@ -1204,7 +1204,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
ret = i915_gem_init_ringbuffer(dev);
mutex_unlock(&dev->struct_mutex);
if (ret)
- goto out;
+ return ret;
/* Try to set up FBC with a reasonable compressed buffer size */
if (I915_HAS_FBC(dev) && i915_powersave) {
@@ -1222,6 +1222,13 @@ static int i915_load_modeset_init(struct drm_device *dev)
/* Allow hardware batchbuffers unless told otherwise. */
dev_priv->allow_batchbuffer = 1;
+ return 0;
+}
+
+static int i915_load_modeset_init(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int ret;
ret = intel_parse_bios(dev);
if (ret)
@@ -1236,7 +1243,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
*/
ret = vga_client_register(dev->pdev, dev, NULL, i915_vga_set_decode);
if (ret && ret != -ENODEV)
- goto cleanup_ringbuffer;
+ goto out;
intel_register_dsm_handler();
@@ -1253,10 +1260,40 @@ static int i915_load_modeset_init(struct drm_device *dev)
intel_modeset_init(dev);
- ret = drm_irq_install(dev);
+ ret = i915_load_gem_init(dev);
if (ret)
goto cleanup_vga_switcheroo;
+ intel_modeset_gem_init(dev);
+
+ if (IS_IVYBRIDGE(dev)) {
+ /* Share pre & uninstall handlers with ILK/SNB */
+ dev->driver->irq_handler = ivybridge_irq_handler;
+ dev->driver->irq_preinstall = ironlake_irq_preinstall;
+ dev->driver->irq_postinstall = ivybridge_irq_postinstall;
+ dev->driver->irq_uninstall = ironlake_irq_uninstall;
+ dev->driver->enable_vblank = ivybridge_enable_vblank;
+ dev->driver->disable_vblank = ivybridge_disable_vblank;
+ } else if (HAS_PCH_SPLIT(dev)) {
+ dev->driver->irq_handler = ironlake_irq_handler;
+ dev->driver->irq_preinstall = ironlake_irq_preinstall;
+ dev->driver->irq_postinstall = ironlake_irq_postinstall;
+ dev->driver->irq_uninstall = ironlake_irq_uninstall;
+ dev->driver->enable_vblank = ironlake_enable_vblank;
+ dev->driver->disable_vblank = ironlake_disable_vblank;
+ } else {
+ dev->driver->irq_preinstall = i915_driver_irq_preinstall;
+ dev->driver->irq_postinstall = i915_driver_irq_postinstall;
+ dev->driver->irq_uninstall = i915_driver_irq_uninstall;
+ dev->driver->irq_handler = i915_driver_irq_handler;
+ dev->driver->enable_vblank = i915_enable_vblank;
+ dev->driver->disable_vblank = i915_disable_vblank;
+ }
+
+ ret = drm_irq_install(dev);
+ if (ret)
+ goto cleanup_gem;
+
/* Always safe in the mode setting case. */
/* FIXME: do pre/post-mode set stuff in core KMS code */
dev->vblank_disable_allowed = 1;
@@ -1274,14 +1311,14 @@ static int i915_load_modeset_init(struct drm_device *dev)
cleanup_irq:
drm_irq_uninstall(dev);
+cleanup_gem:
+ mutex_lock(&dev->struct_mutex);
+ i915_gem_cleanup_ringbuffer(dev);
+ mutex_unlock(&dev->struct_mutex);
cleanup_vga_switcheroo:
vga_switcheroo_unregister_client(dev->pdev);
cleanup_vga_client:
vga_client_register(dev->pdev, NULL, NULL, NULL);
-cleanup_ringbuffer:
- mutex_lock(&dev->struct_mutex);
- i915_gem_cleanup_ringbuffer(dev);
- mutex_unlock(&dev->struct_mutex);
out:
return ret;
}
@@ -1982,7 +2019,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
dev->driver->get_vblank_counter = i915_get_vblank_counter;
dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
- if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev)) {
+ if (IS_G4X(dev) || IS_GEN5(dev) || IS_GEN6(dev) || IS_IVYBRIDGE(dev)) {
dev->max_vblank_count = 0xffffffff; /* full 32 bit counter */
dev->driver->get_vblank_counter = gm45_get_vblank_counter;
}
@@ -2025,6 +2062,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
spin_lock_init(&dev_priv->irq_lock);
spin_lock_init(&dev_priv->error_lock);
+ spin_lock_init(&dev_priv->rps_lock);
if (IS_MOBILE(dev) || !IS_GEN2(dev))
dev_priv->num_pipe = 2;
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 32d1b3e829c8..0defd4270594 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -52,9 +52,12 @@ module_param_named(powersave, i915_powersave, int, 0600);
unsigned int i915_semaphores = 0;
module_param_named(semaphores, i915_semaphores, int, 0600);
-unsigned int i915_enable_rc6 = 0;
+unsigned int i915_enable_rc6 = 1;
module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0600);
+unsigned int i915_enable_fbc = 0;
+module_param_named(i915_enable_fbc, i915_enable_fbc, int, 0600);
+
unsigned int i915_lvds_downclock = 0;
module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
@@ -169,7 +172,7 @@ static const struct intel_device_info intel_ironlake_d_info = {
static const struct intel_device_info intel_ironlake_m_info = {
.gen = 5, .is_mobile = 1,
.need_gfx_hws = 1, .has_hotplug = 1,
- .has_fbc = 0, /* disabled due to buggy hardware */
+ .has_fbc = 1,
.has_bsd_ring = 1,
};
@@ -188,6 +191,21 @@ static const struct intel_device_info intel_sandybridge_m_info = {
.has_blt_ring = 1,
};
+static const struct intel_device_info intel_ivybridge_d_info = {
+ .is_ivybridge = 1, .gen = 7,
+ .need_gfx_hws = 1, .has_hotplug = 1,
+ .has_bsd_ring = 1,
+ .has_blt_ring = 1,
+};
+
+static const struct intel_device_info intel_ivybridge_m_info = {
+ .is_ivybridge = 1, .gen = 7, .is_mobile = 1,
+ .need_gfx_hws = 1, .has_hotplug = 1,
+ .has_fbc = 0, /* FBC is not enabled on Ivybridge mobile yet */
+ .has_bsd_ring = 1,
+ .has_blt_ring = 1,
+};
+
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 */
@@ -227,6 +245,11 @@ static const struct pci_device_id pciidlist[] = { /* aka */
INTEL_VGA_DEVICE(0x0116, &intel_sandybridge_m_info),
INTEL_VGA_DEVICE(0x0126, &intel_sandybridge_m_info),
INTEL_VGA_DEVICE(0x010A, &intel_sandybridge_d_info),
+ INTEL_VGA_DEVICE(0x0156, &intel_ivybridge_m_info), /* GT1 mobile */
+ INTEL_VGA_DEVICE(0x0166, &intel_ivybridge_m_info), /* GT2 mobile */
+ INTEL_VGA_DEVICE(0x0152, &intel_ivybridge_d_info), /* GT1 desktop */
+ INTEL_VGA_DEVICE(0x0162, &intel_ivybridge_d_info), /* GT2 desktop */
+ INTEL_VGA_DEVICE(0x015a, &intel_ivybridge_d_info), /* GT1 server */
{0, 0, 0}
};
@@ -235,7 +258,9 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
#endif
#define INTEL_PCH_DEVICE_ID_MASK 0xff00
+#define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00
#define INTEL_PCH_CPT_DEVICE_ID_TYPE 0x1c00
+#define INTEL_PCH_PPT_DEVICE_ID_TYPE 0x1e00
void intel_detect_pch (struct drm_device *dev)
{
@@ -254,16 +279,23 @@ void intel_detect_pch (struct drm_device *dev)
int id;
id = pch->device & INTEL_PCH_DEVICE_ID_MASK;
- if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) {
+ if (id == INTEL_PCH_IBX_DEVICE_ID_TYPE) {
+ dev_priv->pch_type = PCH_IBX;
+ DRM_DEBUG_KMS("Found Ibex Peak PCH\n");
+ } else if (id == INTEL_PCH_CPT_DEVICE_ID_TYPE) {
dev_priv->pch_type = PCH_CPT;
DRM_DEBUG_KMS("Found CougarPoint PCH\n");
+ } else if (id == INTEL_PCH_PPT_DEVICE_ID_TYPE) {
+ /* PantherPoint is CPT compatible */
+ dev_priv->pch_type = PCH_CPT;
+ DRM_DEBUG_KMS("Found PatherPoint PCH\n");
}
}
pci_dev_put(pch);
}
}
-void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
+static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
{
int count;
@@ -279,12 +311,38 @@ void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
udelay(10);
}
-void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
+/*
+ * Generally this is called implicitly by the register read function. However,
+ * if some sequence requires the GT to not power down then this function should
+ * be called at the beginning of the sequence followed by a call to
+ * gen6_gt_force_wake_put() at the end of the sequence.
+ */
+void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
+{
+ WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
+
+ /* Forcewake is atomic in case we get in here without the lock */
+ if (atomic_add_return(1, &dev_priv->forcewake_count) == 1)
+ __gen6_gt_force_wake_get(dev_priv);
+}
+
+static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
{
I915_WRITE_NOTRACE(FORCEWAKE, 0);
POSTING_READ(FORCEWAKE);
}
+/*
+ * see gen6_gt_force_wake_get()
+ */
+void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
+{
+ WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
+
+ if (atomic_dec_and_test(&dev_priv->forcewake_count))
+ __gen6_gt_force_wake_put(dev_priv);
+}
+
void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
{
int loop = 500;
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 1c1b27c97e5c..ee660355ae68 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -188,7 +188,7 @@ struct drm_i915_error_state {
u32 dirty:1;
u32 purgeable:1;
u32 ring:4;
- u32 agp_type:1;
+ u32 cache_level:2;
} *active_bo, *pinned_bo;
u32 active_bo_count, pinned_bo_count;
struct intel_overlay_error_state *overlay;
@@ -203,12 +203,19 @@ 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 (*crtc_mode_set)(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode,
+ int x, int y,
+ struct drm_framebuffer *old_fb);
+ void (*fdi_link_train)(struct drm_crtc *crtc);
+ void (*init_clock_gating)(struct drm_device *dev);
+ void (*init_pch_clock_gating)(struct drm_device *dev);
/* clock updates for mode set */
/* cursor updates */
/* render clock increase/decrease */
/* display clock increase/decrease */
/* pll clock increase/decrease */
- /* clock gating init */
};
struct intel_device_info {
@@ -223,6 +230,7 @@ struct intel_device_info {
u8 is_pineview : 1;
u8 is_broadwater : 1;
u8 is_crestline : 1;
+ u8 is_ivybridge : 1;
u8 has_fbc : 1;
u8 has_pipe_cxsr : 1;
u8 has_hotplug : 1;
@@ -242,6 +250,7 @@ enum no_fbc_reason {
FBC_BAD_PLANE, /* fbc not supported on plane */
FBC_NOT_TILED, /* buffer not tiled */
FBC_MULTIPLE_PIPES, /* more than one pipe active */
+ FBC_MODULE_PARAM,
};
enum intel_pch {
@@ -676,6 +685,10 @@ typedef struct drm_i915_private {
bool mchbar_need_disable;
+ struct work_struct rps_work;
+ spinlock_t rps_lock;
+ u32 pm_iir;
+
u8 cur_delay;
u8 min_delay;
u8 max_delay;
@@ -703,8 +716,16 @@ typedef struct drm_i915_private {
struct intel_fbdev *fbdev;
struct drm_property *broadcast_rgb_property;
+
+ atomic_t forcewake_count;
} drm_i915_private_t;
+enum i915_cache_level {
+ I915_CACHE_NONE,
+ I915_CACHE_LLC,
+ I915_CACHE_LLC_MLC, /* gen6+ */
+};
+
struct drm_i915_gem_object {
struct drm_gem_object base;
@@ -791,6 +812,8 @@ struct drm_i915_gem_object {
unsigned int pending_fenced_gpu_access:1;
unsigned int fenced_gpu_access:1;
+ unsigned int cache_level:2;
+
struct page **pages;
/**
@@ -827,8 +850,6 @@ struct drm_i915_gem_object {
/** Record of address bit 17 of each page at last unbind. */
unsigned long *bit_17;
- /** AGP mapping type (AGP_USER_MEMORY or AGP_USER_CACHED_MEMORY */
- uint32_t agp_type;
/**
* If present, while GEM_DOMAIN_CPU is in the read domain this array
@@ -915,13 +936,21 @@ enum intel_chip_family {
#define IS_G33(dev) (INTEL_INFO(dev)->is_g33)
#define IS_IRONLAKE_D(dev) ((dev)->pci_device == 0x0042)
#define IS_IRONLAKE_M(dev) ((dev)->pci_device == 0x0046)
+#define IS_IVYBRIDGE(dev) (INTEL_INFO(dev)->is_ivybridge)
#define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile)
+/*
+ * The genX designation typically refers to the render engine, so render
+ * capability related checks should use IS_GEN, while display and other checks
+ * have their own (e.g. HAS_PCH_SPLIT for ILK+ display, IS_foo for particular
+ * chips, etc.).
+ */
#define IS_GEN2(dev) (INTEL_INFO(dev)->gen == 2)
#define IS_GEN3(dev) (INTEL_INFO(dev)->gen == 3)
#define IS_GEN4(dev) (INTEL_INFO(dev)->gen == 4)
#define IS_GEN5(dev) (INTEL_INFO(dev)->gen == 5)
#define IS_GEN6(dev) (INTEL_INFO(dev)->gen == 6)
+#define IS_GEN7(dev) (INTEL_INFO(dev)->gen == 7)
#define HAS_BSD(dev) (INTEL_INFO(dev)->has_bsd_ring)
#define HAS_BLT(dev) (INTEL_INFO(dev)->has_blt_ring)
@@ -948,8 +977,8 @@ enum intel_chip_family {
#define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr)
#define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc)
-#define HAS_PCH_SPLIT(dev) (IS_GEN5(dev) || IS_GEN6(dev))
-#define HAS_PIPE_CONTROL(dev) (IS_GEN5(dev) || IS_GEN6(dev))
+#define HAS_PCH_SPLIT(dev) (IS_GEN5(dev) || IS_GEN6(dev) || IS_IVYBRIDGE(dev))
+#define HAS_PIPE_CONTROL(dev) (INTEL_INFO(dev)->gen >= 5)
#define INTEL_PCH_TYPE(dev) (((struct drm_i915_private *)(dev)->dev_private)->pch_type)
#define HAS_PCH_CPT(dev) (INTEL_PCH_TYPE(dev) == PCH_CPT)
@@ -967,6 +996,7 @@ extern unsigned int i915_lvds_downclock;
extern unsigned int i915_panel_use_ssc;
extern int i915_vbt_sdvo_panel_type;
extern unsigned int i915_enable_rc6;
+extern unsigned int i915_enable_fbc;
extern int i915_suspend(struct drm_device *dev, pm_message_t state);
extern int i915_resume(struct drm_device *dev);
@@ -1010,12 +1040,27 @@ extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
extern void i915_driver_irq_preinstall(struct drm_device * dev);
extern int i915_driver_irq_postinstall(struct drm_device *dev);
extern void i915_driver_irq_uninstall(struct drm_device * dev);
+
+extern irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS);
+extern void ironlake_irq_preinstall(struct drm_device *dev);
+extern int ironlake_irq_postinstall(struct drm_device *dev);
+extern void ironlake_irq_uninstall(struct drm_device *dev);
+
+extern irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS);
+extern void ivybridge_irq_preinstall(struct drm_device *dev);
+extern int ivybridge_irq_postinstall(struct drm_device *dev);
+extern void ivybridge_irq_uninstall(struct drm_device *dev);
+
extern int i915_vblank_pipe_set(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int i915_vblank_pipe_get(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int i915_enable_vblank(struct drm_device *dev, int crtc);
extern void i915_disable_vblank(struct drm_device *dev, int crtc);
+extern int ironlake_enable_vblank(struct drm_device *dev, int crtc);
+extern void ironlake_disable_vblank(struct drm_device *dev, int crtc);
+extern int ivybridge_enable_vblank(struct drm_device *dev, int crtc);
+extern void ivybridge_disable_vblank(struct drm_device *dev, int crtc);
extern u32 i915_get_vblank_counter(struct drm_device *dev, int crtc);
extern u32 gm45_get_vblank_counter(struct drm_device *dev, int crtc);
extern int i915_vblank_swap(struct drm_device *dev, void *data,
@@ -1265,6 +1310,7 @@ static inline void intel_unregister_dsm_handler(void) { return; }
/* modesetting */
extern void intel_modeset_init(struct drm_device *dev);
+extern void intel_modeset_gem_init(struct drm_device *dev);
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);
@@ -1312,13 +1358,34 @@ extern void intel_display_print_error_state(struct seq_file *m,
LOCK_TEST_WITH_RETURN(dev, file); \
} while (0)
+/* On SNB platform, before reading ring registers forcewake bit
+ * must be set to prevent GT core from power down and stale values being
+ * returned.
+ */
+void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv);
+void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv);
+void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv);
+
+/* We give fast paths for the really cool registers */
+#define NEEDS_FORCE_WAKE(dev_priv, reg) \
+ (((dev_priv)->info->gen >= 6) && \
+ ((reg) < 0x40000) && \
+ ((reg) != FORCEWAKE))
#define __i915_read(x, y) \
static inline u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \
- u##x val = read##y(dev_priv->regs + reg); \
+ u##x val = 0; \
+ if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
+ gen6_gt_force_wake_get(dev_priv); \
+ val = read##y(dev_priv->regs + reg); \
+ gen6_gt_force_wake_put(dev_priv); \
+ } else { \
+ val = read##y(dev_priv->regs + reg); \
+ } \
trace_i915_reg_rw(false, reg, val, sizeof(val)); \
return val; \
}
+
__i915_read(8, b)
__i915_read(16, w)
__i915_read(32, l)
@@ -1328,6 +1395,9 @@ __i915_read(64, q)
#define __i915_write(x, y) \
static inline void i915_write##x(struct drm_i915_private *dev_priv, u32 reg, u##x val) { \
trace_i915_reg_rw(true, reg, val, sizeof(val)); \
+ if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
+ __gen6_gt_wait_for_fifo(dev_priv); \
+ } \
write##y(val, dev_priv->regs + reg); \
}
__i915_write(8, b)
@@ -1356,33 +1426,4 @@ __i915_write(64, q)
#define POSTING_READ16(reg) (void)I915_READ16_NOTRACE(reg)
-/* On SNB platform, before reading ring registers forcewake bit
- * must be set to prevent GT core from power down and stale values being
- * returned.
- */
-void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv);
-void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv);
-void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv);
-
-static inline u32 i915_gt_read(struct drm_i915_private *dev_priv, u32 reg)
-{
- u32 val;
-
- if (dev_priv->info->gen >= 6) {
- __gen6_gt_force_wake_get(dev_priv);
- val = I915_READ(reg);
- __gen6_gt_force_wake_put(dev_priv);
- } else
- val = I915_READ(reg);
-
- return val;
-}
-
-static inline void i915_gt_write(struct drm_i915_private *dev_priv,
- u32 reg, u32 val)
-{
- if (dev_priv->info->gen >= 6)
- __gen6_gt_wait_for_fifo(dev_priv);
- I915_WRITE(reg, val);
-}
#endif
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 7ce3f353af33..0b2e167d2bce 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -56,9 +56,7 @@ static int i915_gem_phys_pwrite(struct drm_device *dev,
static void i915_gem_free_object_tail(struct drm_i915_gem_object *obj);
static int i915_gem_inactive_shrink(struct shrinker *shrinker,
- int nr_to_scan,
- gfp_t gfp_mask);
-
+ struct shrink_control *sc);
/* some bookkeeping */
static void i915_gem_info_add_obj(struct drm_i915_private *dev_priv,
@@ -2673,6 +2671,7 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj,
update:
obj->tiling_changed = false;
switch (INTEL_INFO(dev)->gen) {
+ case 7:
case 6:
ret = sandybridge_write_fence_reg(obj, pipelined);
break;
@@ -2706,6 +2705,7 @@ i915_gem_clear_fence_reg(struct drm_device *dev,
uint32_t fence_reg = reg - dev_priv->fence_regs;
switch (INTEL_INFO(dev)->gen) {
+ case 7:
case 6:
I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + fence_reg*8, 0);
break;
@@ -2878,6 +2878,17 @@ i915_gem_clflush_object(struct drm_i915_gem_object *obj)
if (obj->pages == NULL)
return;
+ /* If the GPU is snooping the contents of the CPU cache,
+ * we do not need to manually clear the CPU cache lines. However,
+ * the caches are only snooped when the render cache is
+ * flushed/invalidated. As we always have to emit invalidations
+ * and flushes when moving into and out of the RENDER domain, correct
+ * snooping behaviour occurs naturally as the result of our domain
+ * tracking.
+ */
+ if (obj->cache_level != I915_CACHE_NONE)
+ return;
+
trace_i915_gem_object_clflush(obj);
drm_clflush_pages(obj->pages, obj->base.size / PAGE_SIZE);
@@ -3569,7 +3580,7 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
obj->base.write_domain = I915_GEM_DOMAIN_CPU;
obj->base.read_domains = I915_GEM_DOMAIN_CPU;
- obj->agp_type = AGP_USER_MEMORY;
+ obj->cache_level = I915_CACHE_NONE;
obj->base.driver_private = NULL;
obj->fence_reg = I915_FENCE_REG_NONE;
INIT_LIST_HEAD(&obj->mm_list);
@@ -3845,25 +3856,10 @@ i915_gem_load(struct drm_device *dev)
dev_priv->num_fence_regs = 8;
/* Initialize fence registers to zero */
- switch (INTEL_INFO(dev)->gen) {
- case 6:
- for (i = 0; i < 16; i++)
- I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), 0);
- break;
- case 5:
- case 4:
- for (i = 0; i < 16; i++)
- I915_WRITE64(FENCE_REG_965_0 + (i * 8), 0);
- break;
- case 3:
- if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
- for (i = 0; i < 8; i++)
- I915_WRITE(FENCE_REG_945_8 + (i * 4), 0);
- case 2:
- for (i = 0; i < 8; i++)
- I915_WRITE(FENCE_REG_830_0 + (i * 4), 0);
- break;
+ for (i = 0; i < dev_priv->num_fence_regs; i++) {
+ i915_gem_clear_fence_reg(dev, &dev_priv->fence_regs[i]);
}
+
i915_gem_detect_bit_6_swizzle(dev);
init_waitqueue_head(&dev_priv->pending_flip_queue);
@@ -4094,9 +4090,7 @@ i915_gpu_is_active(struct drm_device *dev)
}
static int
-i915_gem_inactive_shrink(struct shrinker *shrinker,
- int nr_to_scan,
- gfp_t gfp_mask)
+i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc)
{
struct drm_i915_private *dev_priv =
container_of(shrinker,
@@ -4104,6 +4098,7 @@ i915_gem_inactive_shrink(struct shrinker *shrinker,
mm.inactive_shrinker);
struct drm_device *dev = dev_priv->dev;
struct drm_i915_gem_object *obj, *next;
+ int nr_to_scan = sc->nr_to_scan;
int cnt;
if (!mutex_trylock(&dev->struct_mutex))
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index b0abdc64aa9f..e46b645773cf 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -29,6 +29,26 @@
#include "i915_trace.h"
#include "intel_drv.h"
+/* XXX kill agp_type! */
+static unsigned int cache_level_to_agp_type(struct drm_device *dev,
+ enum i915_cache_level cache_level)
+{
+ switch (cache_level) {
+ case I915_CACHE_LLC_MLC:
+ if (INTEL_INFO(dev)->gen >= 6)
+ return AGP_USER_CACHED_MEMORY_LLC_MLC;
+ /* Older chipsets do not have this extra level of CPU
+ * cacheing, so fallthrough and request the PTE simply
+ * as cached.
+ */
+ case I915_CACHE_LLC:
+ return AGP_USER_CACHED_MEMORY;
+ default:
+ case I915_CACHE_NONE:
+ return AGP_USER_MEMORY;
+ }
+}
+
void i915_gem_restore_gtt_mappings(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -39,6 +59,9 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
(dev_priv->mm.gtt_end - dev_priv->mm.gtt_start) / PAGE_SIZE);
list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list) {
+ unsigned int agp_type =
+ cache_level_to_agp_type(dev, obj->cache_level);
+
i915_gem_clflush_object(obj);
if (dev_priv->mm.gtt->needs_dmar) {
@@ -46,15 +69,14 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
intel_gtt_insert_sg_entries(obj->sg_list,
obj->num_sg,
- obj->gtt_space->start
- >> PAGE_SHIFT,
- obj->agp_type);
+ obj->gtt_space->start >> PAGE_SHIFT,
+ agp_type);
} else
intel_gtt_insert_pages(obj->gtt_space->start
>> PAGE_SHIFT,
obj->base.size >> PAGE_SHIFT,
obj->pages,
- obj->agp_type);
+ agp_type);
}
intel_gtt_chipset_flush();
@@ -64,6 +86,7 @@ int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj)
{
struct drm_device *dev = obj->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
+ unsigned int agp_type = cache_level_to_agp_type(dev, obj->cache_level);
int ret;
if (dev_priv->mm.gtt->needs_dmar) {
@@ -77,12 +100,12 @@ int i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj)
intel_gtt_insert_sg_entries(obj->sg_list,
obj->num_sg,
obj->gtt_space->start >> PAGE_SHIFT,
- obj->agp_type);
+ agp_type);
} else
intel_gtt_insert_pages(obj->gtt_space->start >> PAGE_SHIFT,
obj->base.size >> PAGE_SHIFT,
obj->pages,
- obj->agp_type);
+ agp_type);
return 0;
}
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index 281ad3d6115d..82d70fd9e933 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -92,7 +92,7 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
- if (IS_GEN5(dev) || IS_GEN6(dev)) {
+ if (INTEL_INFO(dev)->gen >= 5) {
/* On Ironlake whatever DRAM config, GPU always do
* same swizzling setup.
*/
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 188b497e5076..b79619a7b788 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -367,22 +367,30 @@ static void notify_ring(struct drm_device *dev,
jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
}
-static void gen6_pm_irq_handler(struct drm_device *dev)
+static void gen6_pm_rps_work(struct work_struct *work)
{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
+ rps_work);
u8 new_delay = dev_priv->cur_delay;
- u32 pm_iir;
+ u32 pm_iir, pm_imr;
+
+ spin_lock_irq(&dev_priv->rps_lock);
+ pm_iir = dev_priv->pm_iir;
+ dev_priv->pm_iir = 0;
+ pm_imr = I915_READ(GEN6_PMIMR);
+ spin_unlock_irq(&dev_priv->rps_lock);
- pm_iir = I915_READ(GEN6_PMIIR);
if (!pm_iir)
return;
+ mutex_lock(&dev_priv->dev->struct_mutex);
if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) {
if (dev_priv->cur_delay != dev_priv->max_delay)
new_delay = dev_priv->cur_delay + 1;
if (new_delay > dev_priv->max_delay)
new_delay = dev_priv->max_delay;
} else if (pm_iir & (GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT)) {
+ gen6_gt_force_wake_get(dev_priv);
if (dev_priv->cur_delay != dev_priv->min_delay)
new_delay = dev_priv->cur_delay - 1;
if (new_delay < dev_priv->min_delay) {
@@ -396,13 +404,19 @@ static void gen6_pm_irq_handler(struct drm_device *dev)
I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
I915_READ(GEN6_RP_INTERRUPT_LIMITS) & ~0x3f0000);
}
-
+ gen6_gt_force_wake_put(dev_priv);
}
- gen6_set_rps(dev, new_delay);
+ gen6_set_rps(dev_priv->dev, new_delay);
dev_priv->cur_delay = new_delay;
- I915_WRITE(GEN6_PMIIR, pm_iir);
+ /*
+ * rps_lock not held here because clearing is non-destructive. There is
+ * an *extremely* unlikely race with gen6_rps_enable() that is prevented
+ * by holding struct_mutex for the duration of the write.
+ */
+ I915_WRITE(GEN6_PMIMR, pm_imr & ~pm_iir);
+ mutex_unlock(&dev_priv->dev->struct_mutex);
}
static void pch_irq_handler(struct drm_device *dev)
@@ -448,8 +462,97 @@ static void pch_irq_handler(struct drm_device *dev)
DRM_DEBUG_DRIVER("PCH transcoder A underrun interrupt\n");
}
-static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
+irqreturn_t ivybridge_irq_handler(DRM_IRQ_ARGS)
+{
+ struct drm_device *dev = (struct drm_device *) arg;
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ int ret = IRQ_NONE;
+ u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir;
+ struct drm_i915_master_private *master_priv;
+
+ atomic_inc(&dev_priv->irq_received);
+
+ /* disable master interrupt before clearing iir */
+ de_ier = I915_READ(DEIER);
+ I915_WRITE(DEIER, de_ier & ~DE_MASTER_IRQ_CONTROL);
+ POSTING_READ(DEIER);
+
+ de_iir = I915_READ(DEIIR);
+ gt_iir = I915_READ(GTIIR);
+ pch_iir = I915_READ(SDEIIR);
+ pm_iir = I915_READ(GEN6_PMIIR);
+
+ if (de_iir == 0 && gt_iir == 0 && pch_iir == 0 && pm_iir == 0)
+ goto done;
+
+ ret = IRQ_HANDLED;
+
+ if (dev->primary->master) {
+ master_priv = dev->primary->master->driver_priv;
+ if (master_priv->sarea_priv)
+ master_priv->sarea_priv->last_dispatch =
+ READ_BREADCRUMB(dev_priv);
+ }
+
+ if (gt_iir & (GT_USER_INTERRUPT | GT_PIPE_NOTIFY))
+ notify_ring(dev, &dev_priv->ring[RCS]);
+ if (gt_iir & GT_GEN6_BSD_USER_INTERRUPT)
+ notify_ring(dev, &dev_priv->ring[VCS]);
+ if (gt_iir & GT_BLT_USER_INTERRUPT)
+ notify_ring(dev, &dev_priv->ring[BCS]);
+
+ if (de_iir & DE_GSE_IVB)
+ intel_opregion_gse_intr(dev);
+
+ if (de_iir & DE_PLANEA_FLIP_DONE_IVB) {
+ intel_prepare_page_flip(dev, 0);
+ intel_finish_page_flip_plane(dev, 0);
+ }
+
+ if (de_iir & DE_PLANEB_FLIP_DONE_IVB) {
+ intel_prepare_page_flip(dev, 1);
+ intel_finish_page_flip_plane(dev, 1);
+ }
+
+ if (de_iir & DE_PIPEA_VBLANK_IVB)
+ drm_handle_vblank(dev, 0);
+
+ if (de_iir & DE_PIPEB_VBLANK_IVB);
+ drm_handle_vblank(dev, 1);
+
+ /* check event from PCH */
+ if (de_iir & DE_PCH_EVENT_IVB) {
+ if (pch_iir & SDE_HOTPLUG_MASK_CPT)
+ queue_work(dev_priv->wq, &dev_priv->hotplug_work);
+ pch_irq_handler(dev);
+ }
+
+ if (pm_iir & GEN6_PM_DEFERRED_EVENTS) {
+ unsigned long flags;
+ spin_lock_irqsave(&dev_priv->rps_lock, flags);
+ WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n");
+ I915_WRITE(GEN6_PMIMR, pm_iir);
+ dev_priv->pm_iir |= pm_iir;
+ spin_unlock_irqrestore(&dev_priv->rps_lock, flags);
+ queue_work(dev_priv->wq, &dev_priv->rps_work);
+ }
+
+ /* should clear PCH hotplug event before clear CPU irq */
+ I915_WRITE(SDEIIR, pch_iir);
+ I915_WRITE(GTIIR, gt_iir);
+ I915_WRITE(DEIIR, de_iir);
+ I915_WRITE(GEN6_PMIIR, pm_iir);
+
+done:
+ I915_WRITE(DEIER, de_ier);
+ POSTING_READ(DEIER);
+
+ return ret;
+}
+
+irqreturn_t ironlake_irq_handler(DRM_IRQ_ARGS)
{
+ struct drm_device *dev = (struct drm_device *) arg;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
int ret = IRQ_NONE;
u32 de_iir, gt_iir, de_ier, pch_iir, pm_iir;
@@ -457,6 +560,8 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
struct drm_i915_master_private *master_priv;
u32 bsd_usr_interrupt = GT_BSD_USER_INTERRUPT;
+ atomic_inc(&dev_priv->irq_received);
+
if (IS_GEN6(dev))
bsd_usr_interrupt = GT_GEN6_BSD_USER_INTERRUPT;
@@ -526,13 +631,30 @@ static irqreturn_t ironlake_irq_handler(struct drm_device *dev)
i915_handle_rps_change(dev);
}
- if (IS_GEN6(dev))
- gen6_pm_irq_handler(dev);
+ if (IS_GEN6(dev) && pm_iir & GEN6_PM_DEFERRED_EVENTS) {
+ /*
+ * IIR bits should never already be set because IMR should
+ * prevent an interrupt from being shown in IIR. The warning
+ * displays a case where we've unsafely cleared
+ * dev_priv->pm_iir. Although missing an interrupt of the same
+ * type is not a problem, it displays a problem in the logic.
+ *
+ * The mask bit in IMR is cleared by rps_work.
+ */
+ unsigned long flags;
+ spin_lock_irqsave(&dev_priv->rps_lock, flags);
+ WARN(dev_priv->pm_iir & pm_iir, "Missed a PM interrupt\n");
+ I915_WRITE(GEN6_PMIMR, pm_iir);
+ dev_priv->pm_iir |= pm_iir;
+ spin_unlock_irqrestore(&dev_priv->rps_lock, flags);
+ queue_work(dev_priv->wq, &dev_priv->rps_work);
+ }
/* should clear PCH hotplug event before clear CPU irq */
I915_WRITE(SDEIIR, pch_iir);
I915_WRITE(GTIIR, gt_iir);
I915_WRITE(DEIIR, de_iir);
+ I915_WRITE(GEN6_PMIIR, pm_iir);
done:
I915_WRITE(DEIER, de_ier);
@@ -676,7 +798,7 @@ static u32 capture_bo_list(struct drm_i915_error_buffer *err,
err->dirty = obj->dirty;
err->purgeable = obj->madv != I915_MADV_WILLNEED;
err->ring = obj->ring ? obj->ring->id : 0;
- err->agp_type = obj->agp_type == AGP_USER_CACHED_MEMORY;
+ err->cache_level = obj->cache_level;
if (++i == count)
break;
@@ -1103,9 +1225,6 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
atomic_inc(&dev_priv->irq_received);
- if (HAS_PCH_SPLIT(dev))
- return ironlake_irq_handler(dev);
-
iir = I915_READ(IIR);
if (INTEL_INFO(dev)->gen >= 4)
@@ -1344,10 +1463,7 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
return -EINVAL;
spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
- if (HAS_PCH_SPLIT(dev))
- ironlake_enable_display_irq(dev_priv, (pipe == 0) ?
- DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
- else if (INTEL_INFO(dev)->gen >= 4)
+ if (INTEL_INFO(dev)->gen >= 4)
i915_enable_pipestat(dev_priv, pipe,
PIPE_START_VBLANK_INTERRUPT_ENABLE);
else
@@ -1362,6 +1478,38 @@ int i915_enable_vblank(struct drm_device *dev, int pipe)
return 0;
}
+int ironlake_enable_vblank(struct drm_device *dev, int pipe)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ unsigned long irqflags;
+
+ if (!i915_pipe_enabled(dev, pipe))
+ return -EINVAL;
+
+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+ ironlake_enable_display_irq(dev_priv, (pipe == 0) ?
+ DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
+ return 0;
+}
+
+int ivybridge_enable_vblank(struct drm_device *dev, int pipe)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ unsigned long irqflags;
+
+ if (!i915_pipe_enabled(dev, pipe))
+ return -EINVAL;
+
+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+ ironlake_enable_display_irq(dev_priv, (pipe == 0) ?
+ DE_PIPEA_VBLANK_IVB : DE_PIPEB_VBLANK_IVB);
+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
+ return 0;
+}
+
/* Called from drm generic code, passed 'crtc' which
* we use as a pipe index
*/
@@ -1375,13 +1523,31 @@ void i915_disable_vblank(struct drm_device *dev, int pipe)
I915_WRITE(INSTPM,
INSTPM_AGPBUSY_DIS << 16 | INSTPM_AGPBUSY_DIS);
- if (HAS_PCH_SPLIT(dev))
- ironlake_disable_display_irq(dev_priv, (pipe == 0) ?
- DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
- else
- i915_disable_pipestat(dev_priv, pipe,
- PIPE_VBLANK_INTERRUPT_ENABLE |
- PIPE_START_VBLANK_INTERRUPT_ENABLE);
+ i915_disable_pipestat(dev_priv, pipe,
+ PIPE_VBLANK_INTERRUPT_ENABLE |
+ PIPE_START_VBLANK_INTERRUPT_ENABLE);
+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+}
+
+void ironlake_disable_vblank(struct drm_device *dev, int pipe)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+ ironlake_disable_display_irq(dev_priv, (pipe == 0) ?
+ DE_PIPEA_VBLANK: DE_PIPEB_VBLANK);
+ spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+}
+
+void ivybridge_disable_vblank(struct drm_device *dev, int pipe)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+ ironlake_disable_display_irq(dev_priv, (pipe == 0) ?
+ DE_PIPEA_VBLANK_IVB : DE_PIPEB_VBLANK_IVB);
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
}
@@ -1562,10 +1728,17 @@ repeat:
/* drm_dma.h hooks
*/
-static void ironlake_irq_preinstall(struct drm_device *dev)
+void ironlake_irq_preinstall(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ atomic_set(&dev_priv->irq_received, 0);
+
+ INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
+ INIT_WORK(&dev_priv->error_work, i915_error_work_func);
+ if (IS_GEN6(dev) || IS_IVYBRIDGE(dev))
+ INIT_WORK(&dev_priv->rps_work, gen6_pm_rps_work);
+
I915_WRITE(HWSTAM, 0xeffe);
/* XXX hotplug from PCH */
@@ -1585,7 +1758,7 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
POSTING_READ(SDEIER);
}
-static int ironlake_irq_postinstall(struct drm_device *dev)
+int ironlake_irq_postinstall(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
/* enable kind of interrupts always enabled */
@@ -1594,6 +1767,13 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
u32 render_irqs;
u32 hotplug_mask;
+ DRM_INIT_WAITQUEUE(&dev_priv->ring[RCS].irq_queue);
+ if (HAS_BSD(dev))
+ DRM_INIT_WAITQUEUE(&dev_priv->ring[VCS].irq_queue);
+ if (HAS_BLT(dev))
+ DRM_INIT_WAITQUEUE(&dev_priv->ring[BCS].irq_queue);
+
+ dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
dev_priv->irq_mask = ~display_mask;
/* should always can generate irq */
@@ -1650,6 +1830,56 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
return 0;
}
+int ivybridge_irq_postinstall(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ /* enable kind of interrupts always enabled */
+ u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE_IVB |
+ DE_PCH_EVENT_IVB | DE_PLANEA_FLIP_DONE_IVB |
+ DE_PLANEB_FLIP_DONE_IVB;
+ u32 render_irqs;
+ u32 hotplug_mask;
+
+ DRM_INIT_WAITQUEUE(&dev_priv->ring[RCS].irq_queue);
+ if (HAS_BSD(dev))
+ DRM_INIT_WAITQUEUE(&dev_priv->ring[VCS].irq_queue);
+ if (HAS_BLT(dev))
+ DRM_INIT_WAITQUEUE(&dev_priv->ring[BCS].irq_queue);
+
+ dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
+ dev_priv->irq_mask = ~display_mask;
+
+ /* should always can generate irq */
+ I915_WRITE(DEIIR, I915_READ(DEIIR));
+ I915_WRITE(DEIMR, dev_priv->irq_mask);
+ I915_WRITE(DEIER, display_mask | DE_PIPEA_VBLANK_IVB |
+ DE_PIPEB_VBLANK_IVB);
+ POSTING_READ(DEIER);
+
+ dev_priv->gt_irq_mask = ~0;
+
+ I915_WRITE(GTIIR, I915_READ(GTIIR));
+ I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
+
+ render_irqs = GT_USER_INTERRUPT | GT_GEN6_BSD_USER_INTERRUPT |
+ GT_BLT_USER_INTERRUPT;
+ I915_WRITE(GTIER, render_irqs);
+ POSTING_READ(GTIER);
+
+ hotplug_mask = (SDE_CRT_HOTPLUG_CPT |
+ SDE_PORTB_HOTPLUG_CPT |
+ SDE_PORTC_HOTPLUG_CPT |
+ SDE_PORTD_HOTPLUG_CPT);
+ dev_priv->pch_irq_mask = ~hotplug_mask;
+
+ I915_WRITE(SDEIIR, I915_READ(SDEIIR));
+ I915_WRITE(SDEIMR, dev_priv->pch_irq_mask);
+ I915_WRITE(SDEIER, hotplug_mask);
+ POSTING_READ(SDEIER);
+
+ return 0;
+}
+
void i915_driver_irq_preinstall(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -1660,11 +1890,6 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
INIT_WORK(&dev_priv->error_work, i915_error_work_func);
- if (HAS_PCH_SPLIT(dev)) {
- ironlake_irq_preinstall(dev);
- return;
- }
-
if (I915_HAS_HOTPLUG(dev)) {
I915_WRITE(PORT_HOTPLUG_EN, 0);
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
@@ -1688,17 +1913,8 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR;
u32 error_mask;
- DRM_INIT_WAITQUEUE(&dev_priv->ring[RCS].irq_queue);
- if (HAS_BSD(dev))
- DRM_INIT_WAITQUEUE(&dev_priv->ring[VCS].irq_queue);
- if (HAS_BLT(dev))
- DRM_INIT_WAITQUEUE(&dev_priv->ring[BCS].irq_queue);
-
dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
- if (HAS_PCH_SPLIT(dev))
- return ironlake_irq_postinstall(dev);
-
/* Unmask the interrupts that we always want on. */
dev_priv->irq_mask = ~I915_INTERRUPT_ENABLE_FIX;
@@ -1767,9 +1983,15 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
return 0;
}
-static void ironlake_irq_uninstall(struct drm_device *dev)
+void ironlake_irq_uninstall(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+ if (!dev_priv)
+ return;
+
+ dev_priv->vblank_pipe = 0;
+
I915_WRITE(HWSTAM, 0xffffffff);
I915_WRITE(DEIMR, 0xffffffff);
@@ -1791,11 +2013,6 @@ void i915_driver_irq_uninstall(struct drm_device * dev)
dev_priv->vblank_pipe = 0;
- if (HAS_PCH_SPLIT(dev)) {
- ironlake_irq_uninstall(dev);
- return;
- }
-
if (I915_HAS_HOTPLUG(dev)) {
I915_WRITE(PORT_HOTPLUG_EN, 0);
I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index f39ac3a0fa93..2f967af8e62e 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -291,6 +291,9 @@
#define RING_MAX_IDLE(base) ((base)+0x54)
#define RING_HWS_PGA(base) ((base)+0x80)
#define RING_HWS_PGA_GEN6(base) ((base)+0x2080)
+#define RENDER_HWS_PGA_GEN7 (0x04080)
+#define BSD_HWS_PGA_GEN7 (0x04180)
+#define BLT_HWS_PGA_GEN7 (0x04280)
#define RING_ACTHD(base) ((base)+0x74)
#define RING_NOPID(base) ((base)+0x94)
#define RING_IMR(base) ((base)+0xa8)
@@ -2778,6 +2781,19 @@
#define DE_PIPEA_VSYNC (1 << 3)
#define DE_PIPEA_FIFO_UNDERRUN (1 << 0)
+/* More Ivybridge lolz */
+#define DE_ERR_DEBUG_IVB (1<<30)
+#define DE_GSE_IVB (1<<29)
+#define DE_PCH_EVENT_IVB (1<<28)
+#define DE_DP_A_HOTPLUG_IVB (1<<27)
+#define DE_AUX_CHANNEL_A_IVB (1<<26)
+#define DE_SPRITEB_FLIP_DONE_IVB (1<<9)
+#define DE_SPRITEA_FLIP_DONE_IVB (1<<4)
+#define DE_PLANEB_FLIP_DONE_IVB (1<<8)
+#define DE_PLANEA_FLIP_DONE_IVB (1<<3)
+#define DE_PIPEB_VBLANK_IVB (1<<5)
+#define DE_PIPEA_VBLANK_IVB (1<<0)
+
#define DEISR 0x44000
#define DEIMR 0x44004
#define DEIIR 0x44008
@@ -2809,6 +2825,7 @@
#define ILK_eDP_A_DISABLE (1<<24)
#define ILK_DESKTOP (1<<23)
#define ILK_DSPCLK_GATE 0x42020
+#define IVB_VRHUNIT_CLK_GATE (1<<28)
#define ILK_DPARB_CLK_GATE (1<<5)
#define ILK_DPFD_CLK_GATE (1<<7)
@@ -3057,6 +3074,9 @@
#define TRANS_6BPC (2<<5)
#define TRANS_12BPC (3<<5)
+#define SOUTH_CHICKEN2 0xc2004
+#define DPLS_EDP_PPS_FIX_DIS (1<<0)
+
#define _FDI_RXA_CHICKEN 0xc200c
#define _FDI_RXB_CHICKEN 0xc2010
#define FDI_RX_PHASE_SYNC_POINTER_OVR (1<<1)
@@ -3104,7 +3124,15 @@
#define FDI_TX_ENHANCE_FRAME_ENABLE (1<<18)
/* Ironlake: hardwired to 1 */
#define FDI_TX_PLL_ENABLE (1<<14)
+
+/* Ivybridge has different bits for lolz */
+#define FDI_LINK_TRAIN_PATTERN_1_IVB (0<<8)
+#define FDI_LINK_TRAIN_PATTERN_2_IVB (1<<8)
+#define FDI_LINK_TRAIN_PATTERN_IDLE_IVB (2<<8)
+#define FDI_LINK_TRAIN_NONE_IVB (3<<8)
+
/* both Tx and Rx */
+#define FDI_LINK_TRAIN_AUTO (1<<10)
#define FDI_SCRAMBLING_ENABLE (0<<7)
#define FDI_SCRAMBLING_DISABLE (1<<7)
@@ -3114,6 +3142,8 @@
#define FDI_RX_CTL(pipe) _PIPE(pipe, _FDI_RXA_CTL, _FDI_RXB_CTL)
#define FDI_RX_ENABLE (1<<31)
/* train, dp width same as FDI_TX */
+#define FDI_FS_ERRC_ENABLE (1<<27)
+#define FDI_FE_ERRC_ENABLE (1<<26)
#define FDI_DP_PORT_WIDTH_X8 (7<<19)
#define FDI_8BPC (0<<16)
#define FDI_10BPC (1<<16)
@@ -3386,7 +3416,7 @@
#define GEN6_PMINTRMSK 0xA168
#define GEN6_PMISR 0x44020
-#define GEN6_PMIMR 0x44024
+#define GEN6_PMIMR 0x44024 /* rps_lock */
#define GEN6_PMIIR 0x44028
#define GEN6_PMIER 0x4402C
#define GEN6_PM_MBOX_EVENT (1<<25)
@@ -3396,6 +3426,9 @@
#define GEN6_PM_RP_DOWN_THRESHOLD (1<<4)
#define GEN6_PM_RP_UP_EI_EXPIRED (1<<2)
#define GEN6_PM_RP_DOWN_EI_EXPIRED (1<<1)
+#define GEN6_PM_DEFERRED_EVENTS (GEN6_PM_RP_UP_THRESHOLD | \
+ GEN6_PM_RP_DOWN_THRESHOLD | \
+ GEN6_PM_RP_DOWN_TIMEOUT)
#define GEN6_PCODE_MAILBOX 0x138124
#define GEN6_PCODE_READY (1<<31)
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index da474153a0a2..60a94d2b5264 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -863,8 +863,7 @@ int i915_restore_state(struct drm_device *dev)
I915_WRITE(IMR, dev_priv->saveIMR);
}
- /* Clock gating state */
- intel_enable_clock_gating(dev);
+ intel_init_clock_gating(dev);
if (IS_IRONLAKE_M(dev)) {
ironlake_enable_drps(dev);
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index fb5b4d426ae0..927442a11925 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -214,9 +214,9 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
i915_lvds_downclock) {
dev_priv->lvds_downclock_avail = 1;
dev_priv->lvds_downclock = temp_downclock;
- DRM_DEBUG_KMS("LVDS downclock is found in VBT. ",
- "Normal Clock %dKHz, downclock %dKHz\n",
- temp_downclock, panel_fixed_mode->clock);
+ DRM_DEBUG_KMS("LVDS downclock is found in VBT. "
+ "Normal Clock %dKHz, downclock %dKHz\n",
+ temp_downclock, panel_fixed_mode->clock);
}
return;
}
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index d03fc05b39c0..e93f93cc7e78 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -305,13 +305,11 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector)
}
static enum drm_connector_status
-intel_crt_load_detect(struct drm_crtc *crtc, struct intel_crt *crt)
+intel_crt_load_detect(struct intel_crt *crt)
{
- struct drm_encoder *encoder = &crt->base.base;
- struct drm_device *dev = encoder->dev;
+ struct drm_device *dev = crt->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- uint32_t pipe = intel_crtc->pipe;
+ uint32_t pipe = to_intel_crtc(crt->base.base.crtc)->pipe;
uint32_t save_bclrpat;
uint32_t save_vtotal;
uint32_t vtotal, vactive;
@@ -432,7 +430,6 @@ intel_crt_detect(struct drm_connector *connector, bool force)
struct drm_device *dev = connector->dev;
struct intel_crt *crt = intel_attached_crt(connector);
struct drm_crtc *crtc;
- int dpms_mode;
enum drm_connector_status status;
if (I915_HAS_HOTPLUG(dev)) {
@@ -454,17 +451,18 @@ intel_crt_detect(struct drm_connector *connector, bool force)
/* for pre-945g platforms use load detect */
crtc = crt->base.base.crtc;
if (crtc && crtc->enabled) {
- status = intel_crt_load_detect(crtc, crt);
+ status = intel_crt_load_detect(crt);
} else {
- crtc = intel_get_load_detect_pipe(&crt->base, connector,
- NULL, &dpms_mode);
- if (crtc) {
+ struct intel_load_detect_pipe tmp;
+
+ if (intel_get_load_detect_pipe(&crt->base, connector, NULL,
+ &tmp)) {
if (intel_crt_detect_ddc(connector))
status = connector_status_connected;
else
- status = intel_crt_load_detect(crtc, crt);
- intel_release_load_detect_pipe(&crt->base,
- connector, dpms_mode);
+ status = intel_crt_load_detect(crt);
+ intel_release_load_detect_pipe(&crt->base, connector,
+ &tmp);
} else
status = connector_status_unknown;
}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 2166ee071ddb..f553ddfdc168 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -76,255 +76,6 @@ struct intel_limit {
int, int, intel_clock_t *);
};
-#define I8XX_DOT_MIN 25000
-#define I8XX_DOT_MAX 350000
-#define I8XX_VCO_MIN 930000
-#define I8XX_VCO_MAX 1400000
-#define I8XX_N_MIN 3
-#define I8XX_N_MAX 16
-#define I8XX_M_MIN 96
-#define I8XX_M_MAX 140
-#define I8XX_M1_MIN 18
-#define I8XX_M1_MAX 26
-#define I8XX_M2_MIN 6
-#define I8XX_M2_MAX 16
-#define I8XX_P_MIN 4
-#define I8XX_P_MAX 128
-#define I8XX_P1_MIN 2
-#define I8XX_P1_MAX 33
-#define I8XX_P1_LVDS_MIN 1
-#define I8XX_P1_LVDS_MAX 6
-#define I8XX_P2_SLOW 4
-#define I8XX_P2_FAST 2
-#define I8XX_P2_LVDS_SLOW 14
-#define I8XX_P2_LVDS_FAST 7
-#define I8XX_P2_SLOW_LIMIT 165000
-
-#define I9XX_DOT_MIN 20000
-#define I9XX_DOT_MAX 400000
-#define I9XX_VCO_MIN 1400000
-#define I9XX_VCO_MAX 2800000
-#define PINEVIEW_VCO_MIN 1700000
-#define PINEVIEW_VCO_MAX 3500000
-#define I9XX_N_MIN 1
-#define I9XX_N_MAX 6
-/* Pineview's Ncounter is a ring counter */
-#define PINEVIEW_N_MIN 3
-#define PINEVIEW_N_MAX 6
-#define I9XX_M_MIN 70
-#define I9XX_M_MAX 120
-#define PINEVIEW_M_MIN 2
-#define PINEVIEW_M_MAX 256
-#define I9XX_M1_MIN 10
-#define I9XX_M1_MAX 22
-#define I9XX_M2_MIN 5
-#define I9XX_M2_MAX 9
-/* Pineview M1 is reserved, and must be 0 */
-#define PINEVIEW_M1_MIN 0
-#define PINEVIEW_M1_MAX 0
-#define PINEVIEW_M2_MIN 0
-#define PINEVIEW_M2_MAX 254
-#define I9XX_P_SDVO_DAC_MIN 5
-#define I9XX_P_SDVO_DAC_MAX 80
-#define I9XX_P_LVDS_MIN 7
-#define I9XX_P_LVDS_MAX 98
-#define PINEVIEW_P_LVDS_MIN 7
-#define PINEVIEW_P_LVDS_MAX 112
-#define I9XX_P1_MIN 1
-#define I9XX_P1_MAX 8
-#define I9XX_P2_SDVO_DAC_SLOW 10
-#define I9XX_P2_SDVO_DAC_FAST 5
-#define I9XX_P2_SDVO_DAC_SLOW_LIMIT 200000
-#define I9XX_P2_LVDS_SLOW 14
-#define I9XX_P2_LVDS_FAST 7
-#define I9XX_P2_LVDS_SLOW_LIMIT 112000
-
-/*The parameter is for SDVO on G4x platform*/
-#define G4X_DOT_SDVO_MIN 25000
-#define G4X_DOT_SDVO_MAX 270000
-#define G4X_VCO_MIN 1750000
-#define G4X_VCO_MAX 3500000
-#define G4X_N_SDVO_MIN 1
-#define G4X_N_SDVO_MAX 4
-#define G4X_M_SDVO_MIN 104
-#define G4X_M_SDVO_MAX 138
-#define G4X_M1_SDVO_MIN 17
-#define G4X_M1_SDVO_MAX 23
-#define G4X_M2_SDVO_MIN 5
-#define G4X_M2_SDVO_MAX 11
-#define G4X_P_SDVO_MIN 10
-#define G4X_P_SDVO_MAX 30
-#define G4X_P1_SDVO_MIN 1
-#define G4X_P1_SDVO_MAX 3
-#define G4X_P2_SDVO_SLOW 10
-#define G4X_P2_SDVO_FAST 10
-#define G4X_P2_SDVO_LIMIT 270000
-
-/*The parameter is for HDMI_DAC on G4x platform*/
-#define G4X_DOT_HDMI_DAC_MIN 22000
-#define G4X_DOT_HDMI_DAC_MAX 400000
-#define G4X_N_HDMI_DAC_MIN 1
-#define G4X_N_HDMI_DAC_MAX 4
-#define G4X_M_HDMI_DAC_MIN 104
-#define G4X_M_HDMI_DAC_MAX 138
-#define G4X_M1_HDMI_DAC_MIN 16
-#define G4X_M1_HDMI_DAC_MAX 23
-#define G4X_M2_HDMI_DAC_MIN 5
-#define G4X_M2_HDMI_DAC_MAX 11
-#define G4X_P_HDMI_DAC_MIN 5
-#define G4X_P_HDMI_DAC_MAX 80
-#define G4X_P1_HDMI_DAC_MIN 1
-#define G4X_P1_HDMI_DAC_MAX 8
-#define G4X_P2_HDMI_DAC_SLOW 10
-#define G4X_P2_HDMI_DAC_FAST 5
-#define G4X_P2_HDMI_DAC_LIMIT 165000
-
-/*The parameter is for SINGLE_CHANNEL_LVDS on G4x platform*/
-#define G4X_DOT_SINGLE_CHANNEL_LVDS_MIN 20000
-#define G4X_DOT_SINGLE_CHANNEL_LVDS_MAX 115000
-#define G4X_N_SINGLE_CHANNEL_LVDS_MIN 1
-#define G4X_N_SINGLE_CHANNEL_LVDS_MAX 3
-#define G4X_M_SINGLE_CHANNEL_LVDS_MIN 104
-#define G4X_M_SINGLE_CHANNEL_LVDS_MAX 138
-#define G4X_M1_SINGLE_CHANNEL_LVDS_MIN 17
-#define G4X_M1_SINGLE_CHANNEL_LVDS_MAX 23
-#define G4X_M2_SINGLE_CHANNEL_LVDS_MIN 5
-#define G4X_M2_SINGLE_CHANNEL_LVDS_MAX 11
-#define G4X_P_SINGLE_CHANNEL_LVDS_MIN 28
-#define G4X_P_SINGLE_CHANNEL_LVDS_MAX 112
-#define G4X_P1_SINGLE_CHANNEL_LVDS_MIN 2
-#define G4X_P1_SINGLE_CHANNEL_LVDS_MAX 8
-#define G4X_P2_SINGLE_CHANNEL_LVDS_SLOW 14
-#define G4X_P2_SINGLE_CHANNEL_LVDS_FAST 14
-#define G4X_P2_SINGLE_CHANNEL_LVDS_LIMIT 0
-
-/*The parameter is for DUAL_CHANNEL_LVDS on G4x platform*/
-#define G4X_DOT_DUAL_CHANNEL_LVDS_MIN 80000
-#define G4X_DOT_DUAL_CHANNEL_LVDS_MAX 224000
-#define G4X_N_DUAL_CHANNEL_LVDS_MIN 1
-#define G4X_N_DUAL_CHANNEL_LVDS_MAX 3
-#define G4X_M_DUAL_CHANNEL_LVDS_MIN 104
-#define G4X_M_DUAL_CHANNEL_LVDS_MAX 138
-#define G4X_M1_DUAL_CHANNEL_LVDS_MIN 17
-#define G4X_M1_DUAL_CHANNEL_LVDS_MAX 23
-#define G4X_M2_DUAL_CHANNEL_LVDS_MIN 5
-#define G4X_M2_DUAL_CHANNEL_LVDS_MAX 11
-#define G4X_P_DUAL_CHANNEL_LVDS_MIN 14
-#define G4X_P_DUAL_CHANNEL_LVDS_MAX 42
-#define G4X_P1_DUAL_CHANNEL_LVDS_MIN 2
-#define G4X_P1_DUAL_CHANNEL_LVDS_MAX 6
-#define G4X_P2_DUAL_CHANNEL_LVDS_SLOW 7
-#define G4X_P2_DUAL_CHANNEL_LVDS_FAST 7
-#define G4X_P2_DUAL_CHANNEL_LVDS_LIMIT 0
-
-/*The parameter is for DISPLAY PORT on G4x platform*/
-#define G4X_DOT_DISPLAY_PORT_MIN 161670
-#define G4X_DOT_DISPLAY_PORT_MAX 227000
-#define G4X_N_DISPLAY_PORT_MIN 1
-#define G4X_N_DISPLAY_PORT_MAX 2
-#define G4X_M_DISPLAY_PORT_MIN 97
-#define G4X_M_DISPLAY_PORT_MAX 108
-#define G4X_M1_DISPLAY_PORT_MIN 0x10
-#define G4X_M1_DISPLAY_PORT_MAX 0x12
-#define G4X_M2_DISPLAY_PORT_MIN 0x05
-#define G4X_M2_DISPLAY_PORT_MAX 0x06
-#define G4X_P_DISPLAY_PORT_MIN 10
-#define G4X_P_DISPLAY_PORT_MAX 20
-#define G4X_P1_DISPLAY_PORT_MIN 1
-#define G4X_P1_DISPLAY_PORT_MAX 2
-#define G4X_P2_DISPLAY_PORT_SLOW 10
-#define G4X_P2_DISPLAY_PORT_FAST 10
-#define G4X_P2_DISPLAY_PORT_LIMIT 0
-
-/* Ironlake / Sandybridge */
-/* as we calculate clock using (register_value + 2) for
- N/M1/M2, so here the range value for them is (actual_value-2).
- */
-#define IRONLAKE_DOT_MIN 25000
-#define IRONLAKE_DOT_MAX 350000
-#define IRONLAKE_VCO_MIN 1760000
-#define IRONLAKE_VCO_MAX 3510000
-#define IRONLAKE_M1_MIN 12
-#define IRONLAKE_M1_MAX 22
-#define IRONLAKE_M2_MIN 5
-#define IRONLAKE_M2_MAX 9
-#define IRONLAKE_P2_DOT_LIMIT 225000 /* 225Mhz */
-
-/* We have parameter ranges for different type of outputs. */
-
-/* DAC & HDMI Refclk 120Mhz */
-#define IRONLAKE_DAC_N_MIN 1
-#define IRONLAKE_DAC_N_MAX 5
-#define IRONLAKE_DAC_M_MIN 79
-#define IRONLAKE_DAC_M_MAX 127
-#define IRONLAKE_DAC_P_MIN 5
-#define IRONLAKE_DAC_P_MAX 80
-#define IRONLAKE_DAC_P1_MIN 1
-#define IRONLAKE_DAC_P1_MAX 8
-#define IRONLAKE_DAC_P2_SLOW 10
-#define IRONLAKE_DAC_P2_FAST 5
-
-/* LVDS single-channel 120Mhz refclk */
-#define IRONLAKE_LVDS_S_N_MIN 1
-#define IRONLAKE_LVDS_S_N_MAX 3
-#define IRONLAKE_LVDS_S_M_MIN 79
-#define IRONLAKE_LVDS_S_M_MAX 118
-#define IRONLAKE_LVDS_S_P_MIN 28
-#define IRONLAKE_LVDS_S_P_MAX 112
-#define IRONLAKE_LVDS_S_P1_MIN 2
-#define IRONLAKE_LVDS_S_P1_MAX 8
-#define IRONLAKE_LVDS_S_P2_SLOW 14
-#define IRONLAKE_LVDS_S_P2_FAST 14
-
-/* LVDS dual-channel 120Mhz refclk */
-#define IRONLAKE_LVDS_D_N_MIN 1
-#define IRONLAKE_LVDS_D_N_MAX 3
-#define IRONLAKE_LVDS_D_M_MIN 79
-#define IRONLAKE_LVDS_D_M_MAX 127
-#define IRONLAKE_LVDS_D_P_MIN 14
-#define IRONLAKE_LVDS_D_P_MAX 56
-#define IRONLAKE_LVDS_D_P1_MIN 2
-#define IRONLAKE_LVDS_D_P1_MAX 8
-#define IRONLAKE_LVDS_D_P2_SLOW 7
-#define IRONLAKE_LVDS_D_P2_FAST 7
-
-/* LVDS single-channel 100Mhz refclk */
-#define IRONLAKE_LVDS_S_SSC_N_MIN 1
-#define IRONLAKE_LVDS_S_SSC_N_MAX 2
-#define IRONLAKE_LVDS_S_SSC_M_MIN 79
-#define IRONLAKE_LVDS_S_SSC_M_MAX 126
-#define IRONLAKE_LVDS_S_SSC_P_MIN 28
-#define IRONLAKE_LVDS_S_SSC_P_MAX 112
-#define IRONLAKE_LVDS_S_SSC_P1_MIN 2
-#define IRONLAKE_LVDS_S_SSC_P1_MAX 8
-#define IRONLAKE_LVDS_S_SSC_P2_SLOW 14
-#define IRONLAKE_LVDS_S_SSC_P2_FAST 14
-
-/* LVDS dual-channel 100Mhz refclk */
-#define IRONLAKE_LVDS_D_SSC_N_MIN 1
-#define IRONLAKE_LVDS_D_SSC_N_MAX 3
-#define IRONLAKE_LVDS_D_SSC_M_MIN 79
-#define IRONLAKE_LVDS_D_SSC_M_MAX 126
-#define IRONLAKE_LVDS_D_SSC_P_MIN 14
-#define IRONLAKE_LVDS_D_SSC_P_MAX 42
-#define IRONLAKE_LVDS_D_SSC_P1_MIN 2
-#define IRONLAKE_LVDS_D_SSC_P1_MAX 6
-#define IRONLAKE_LVDS_D_SSC_P2_SLOW 7
-#define IRONLAKE_LVDS_D_SSC_P2_FAST 7
-
-/* DisplayPort */
-#define IRONLAKE_DP_N_MIN 1
-#define IRONLAKE_DP_N_MAX 2
-#define IRONLAKE_DP_M_MIN 81
-#define IRONLAKE_DP_M_MAX 90
-#define IRONLAKE_DP_P_MIN 10
-#define IRONLAKE_DP_P_MAX 20
-#define IRONLAKE_DP_P2_FAST 10
-#define IRONLAKE_DP_P2_SLOW 10
-#define IRONLAKE_DP_P2_LIMIT 0
-#define IRONLAKE_DP_P1_MIN 1
-#define IRONLAKE_DP_P1_MAX 2
-
/* FDI */
#define IRONLAKE_FDI_FREQ 2700000 /* in kHz for mode->clock */
@@ -353,292 +104,253 @@ intel_fdi_link_freq(struct drm_device *dev)
}
static const intel_limit_t intel_limits_i8xx_dvo = {
- .dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX },
- .vco = { .min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX },
- .n = { .min = I8XX_N_MIN, .max = I8XX_N_MAX },
- .m = { .min = I8XX_M_MIN, .max = I8XX_M_MAX },
- .m1 = { .min = I8XX_M1_MIN, .max = I8XX_M1_MAX },
- .m2 = { .min = I8XX_M2_MIN, .max = I8XX_M2_MAX },
- .p = { .min = I8XX_P_MIN, .max = I8XX_P_MAX },
- .p1 = { .min = I8XX_P1_MIN, .max = I8XX_P1_MAX },
- .p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT,
- .p2_slow = I8XX_P2_SLOW, .p2_fast = I8XX_P2_FAST },
+ .dot = { .min = 25000, .max = 350000 },
+ .vco = { .min = 930000, .max = 1400000 },
+ .n = { .min = 3, .max = 16 },
+ .m = { .min = 96, .max = 140 },
+ .m1 = { .min = 18, .max = 26 },
+ .m2 = { .min = 6, .max = 16 },
+ .p = { .min = 4, .max = 128 },
+ .p1 = { .min = 2, .max = 33 },
+ .p2 = { .dot_limit = 165000,
+ .p2_slow = 4, .p2_fast = 2 },
.find_pll = intel_find_best_PLL,
};
static const intel_limit_t intel_limits_i8xx_lvds = {
- .dot = { .min = I8XX_DOT_MIN, .max = I8XX_DOT_MAX },
- .vco = { .min = I8XX_VCO_MIN, .max = I8XX_VCO_MAX },
- .n = { .min = I8XX_N_MIN, .max = I8XX_N_MAX },
- .m = { .min = I8XX_M_MIN, .max = I8XX_M_MAX },
- .m1 = { .min = I8XX_M1_MIN, .max = I8XX_M1_MAX },
- .m2 = { .min = I8XX_M2_MIN, .max = I8XX_M2_MAX },
- .p = { .min = I8XX_P_MIN, .max = I8XX_P_MAX },
- .p1 = { .min = I8XX_P1_LVDS_MIN, .max = I8XX_P1_LVDS_MAX },
- .p2 = { .dot_limit = I8XX_P2_SLOW_LIMIT,
- .p2_slow = I8XX_P2_LVDS_SLOW, .p2_fast = I8XX_P2_LVDS_FAST },
+ .dot = { .min = 25000, .max = 350000 },
+ .vco = { .min = 930000, .max = 1400000 },
+ .n = { .min = 3, .max = 16 },
+ .m = { .min = 96, .max = 140 },
+ .m1 = { .min = 18, .max = 26 },
+ .m2 = { .min = 6, .max = 16 },
+ .p = { .min = 4, .max = 128 },
+ .p1 = { .min = 1, .max = 6 },
+ .p2 = { .dot_limit = 165000,
+ .p2_slow = 14, .p2_fast = 7 },
.find_pll = intel_find_best_PLL,
};
-
+
static const intel_limit_t intel_limits_i9xx_sdvo = {
- .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX },
- .vco = { .min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX },
- .n = { .min = I9XX_N_MIN, .max = I9XX_N_MAX },
- .m = { .min = I9XX_M_MIN, .max = I9XX_M_MAX },
- .m1 = { .min = I9XX_M1_MIN, .max = I9XX_M1_MAX },
- .m2 = { .min = I9XX_M2_MIN, .max = I9XX_M2_MAX },
- .p = { .min = I9XX_P_SDVO_DAC_MIN, .max = I9XX_P_SDVO_DAC_MAX },
- .p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX },
- .p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
- .p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST },
+ .dot = { .min = 20000, .max = 400000 },
+ .vco = { .min = 1400000, .max = 2800000 },
+ .n = { .min = 1, .max = 6 },
+ .m = { .min = 70, .max = 120 },
+ .m1 = { .min = 10, .max = 22 },
+ .m2 = { .min = 5, .max = 9 },
+ .p = { .min = 5, .max = 80 },
+ .p1 = { .min = 1, .max = 8 },
+ .p2 = { .dot_limit = 200000,
+ .p2_slow = 10, .p2_fast = 5 },
.find_pll = intel_find_best_PLL,
};
static const intel_limit_t intel_limits_i9xx_lvds = {
- .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX },
- .vco = { .min = I9XX_VCO_MIN, .max = I9XX_VCO_MAX },
- .n = { .min = I9XX_N_MIN, .max = I9XX_N_MAX },
- .m = { .min = I9XX_M_MIN, .max = I9XX_M_MAX },
- .m1 = { .min = I9XX_M1_MIN, .max = I9XX_M1_MAX },
- .m2 = { .min = I9XX_M2_MIN, .max = I9XX_M2_MAX },
- .p = { .min = I9XX_P_LVDS_MIN, .max = I9XX_P_LVDS_MAX },
- .p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX },
- /* The single-channel range is 25-112Mhz, and dual-channel
- * is 80-224Mhz. Prefer single channel as much as possible.
- */
- .p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
- .p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_FAST },
+ .dot = { .min = 20000, .max = 400000 },
+ .vco = { .min = 1400000, .max = 2800000 },
+ .n = { .min = 1, .max = 6 },
+ .m = { .min = 70, .max = 120 },
+ .m1 = { .min = 10, .max = 22 },
+ .m2 = { .min = 5, .max = 9 },
+ .p = { .min = 7, .max = 98 },
+ .p1 = { .min = 1, .max = 8 },
+ .p2 = { .dot_limit = 112000,
+ .p2_slow = 14, .p2_fast = 7 },
.find_pll = intel_find_best_PLL,
};
- /* below parameter and function is for G4X Chipset Family*/
+
static const intel_limit_t intel_limits_g4x_sdvo = {
- .dot = { .min = G4X_DOT_SDVO_MIN, .max = G4X_DOT_SDVO_MAX },
- .vco = { .min = G4X_VCO_MIN, .max = G4X_VCO_MAX},
- .n = { .min = G4X_N_SDVO_MIN, .max = G4X_N_SDVO_MAX },
- .m = { .min = G4X_M_SDVO_MIN, .max = G4X_M_SDVO_MAX },
- .m1 = { .min = G4X_M1_SDVO_MIN, .max = G4X_M1_SDVO_MAX },
- .m2 = { .min = G4X_M2_SDVO_MIN, .max = G4X_M2_SDVO_MAX },
- .p = { .min = G4X_P_SDVO_MIN, .max = G4X_P_SDVO_MAX },
- .p1 = { .min = G4X_P1_SDVO_MIN, .max = G4X_P1_SDVO_MAX},
- .p2 = { .dot_limit = G4X_P2_SDVO_LIMIT,
- .p2_slow = G4X_P2_SDVO_SLOW,
- .p2_fast = G4X_P2_SDVO_FAST
+ .dot = { .min = 25000, .max = 270000 },
+ .vco = { .min = 1750000, .max = 3500000},
+ .n = { .min = 1, .max = 4 },
+ .m = { .min = 104, .max = 138 },
+ .m1 = { .min = 17, .max = 23 },
+ .m2 = { .min = 5, .max = 11 },
+ .p = { .min = 10, .max = 30 },
+ .p1 = { .min = 1, .max = 3},
+ .p2 = { .dot_limit = 270000,
+ .p2_slow = 10,
+ .p2_fast = 10
},
.find_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_g4x_hdmi = {
- .dot = { .min = G4X_DOT_HDMI_DAC_MIN, .max = G4X_DOT_HDMI_DAC_MAX },
- .vco = { .min = G4X_VCO_MIN, .max = G4X_VCO_MAX},
- .n = { .min = G4X_N_HDMI_DAC_MIN, .max = G4X_N_HDMI_DAC_MAX },
- .m = { .min = G4X_M_HDMI_DAC_MIN, .max = G4X_M_HDMI_DAC_MAX },
- .m1 = { .min = G4X_M1_HDMI_DAC_MIN, .max = G4X_M1_HDMI_DAC_MAX },
- .m2 = { .min = G4X_M2_HDMI_DAC_MIN, .max = G4X_M2_HDMI_DAC_MAX },
- .p = { .min = G4X_P_HDMI_DAC_MIN, .max = G4X_P_HDMI_DAC_MAX },
- .p1 = { .min = G4X_P1_HDMI_DAC_MIN, .max = G4X_P1_HDMI_DAC_MAX},
- .p2 = { .dot_limit = G4X_P2_HDMI_DAC_LIMIT,
- .p2_slow = G4X_P2_HDMI_DAC_SLOW,
- .p2_fast = G4X_P2_HDMI_DAC_FAST
- },
+ .dot = { .min = 22000, .max = 400000 },
+ .vco = { .min = 1750000, .max = 3500000},
+ .n = { .min = 1, .max = 4 },
+ .m = { .min = 104, .max = 138 },
+ .m1 = { .min = 16, .max = 23 },
+ .m2 = { .min = 5, .max = 11 },
+ .p = { .min = 5, .max = 80 },
+ .p1 = { .min = 1, .max = 8},
+ .p2 = { .dot_limit = 165000,
+ .p2_slow = 10, .p2_fast = 5 },
.find_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_g4x_single_channel_lvds = {
- .dot = { .min = G4X_DOT_SINGLE_CHANNEL_LVDS_MIN,
- .max = G4X_DOT_SINGLE_CHANNEL_LVDS_MAX },
- .vco = { .min = G4X_VCO_MIN,
- .max = G4X_VCO_MAX },
- .n = { .min = G4X_N_SINGLE_CHANNEL_LVDS_MIN,
- .max = G4X_N_SINGLE_CHANNEL_LVDS_MAX },
- .m = { .min = G4X_M_SINGLE_CHANNEL_LVDS_MIN,
- .max = G4X_M_SINGLE_CHANNEL_LVDS_MAX },
- .m1 = { .min = G4X_M1_SINGLE_CHANNEL_LVDS_MIN,
- .max = G4X_M1_SINGLE_CHANNEL_LVDS_MAX },
- .m2 = { .min = G4X_M2_SINGLE_CHANNEL_LVDS_MIN,
- .max = G4X_M2_SINGLE_CHANNEL_LVDS_MAX },
- .p = { .min = G4X_P_SINGLE_CHANNEL_LVDS_MIN,
- .max = G4X_P_SINGLE_CHANNEL_LVDS_MAX },
- .p1 = { .min = G4X_P1_SINGLE_CHANNEL_LVDS_MIN,
- .max = G4X_P1_SINGLE_CHANNEL_LVDS_MAX },
- .p2 = { .dot_limit = G4X_P2_SINGLE_CHANNEL_LVDS_LIMIT,
- .p2_slow = G4X_P2_SINGLE_CHANNEL_LVDS_SLOW,
- .p2_fast = G4X_P2_SINGLE_CHANNEL_LVDS_FAST
+ .dot = { .min = 20000, .max = 115000 },
+ .vco = { .min = 1750000, .max = 3500000 },
+ .n = { .min = 1, .max = 3 },
+ .m = { .min = 104, .max = 138 },
+ .m1 = { .min = 17, .max = 23 },
+ .m2 = { .min = 5, .max = 11 },
+ .p = { .min = 28, .max = 112 },
+ .p1 = { .min = 2, .max = 8 },
+ .p2 = { .dot_limit = 0,
+ .p2_slow = 14, .p2_fast = 14
},
.find_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_g4x_dual_channel_lvds = {
- .dot = { .min = G4X_DOT_DUAL_CHANNEL_LVDS_MIN,
- .max = G4X_DOT_DUAL_CHANNEL_LVDS_MAX },
- .vco = { .min = G4X_VCO_MIN,
- .max = G4X_VCO_MAX },
- .n = { .min = G4X_N_DUAL_CHANNEL_LVDS_MIN,
- .max = G4X_N_DUAL_CHANNEL_LVDS_MAX },
- .m = { .min = G4X_M_DUAL_CHANNEL_LVDS_MIN,
- .max = G4X_M_DUAL_CHANNEL_LVDS_MAX },
- .m1 = { .min = G4X_M1_DUAL_CHANNEL_LVDS_MIN,
- .max = G4X_M1_DUAL_CHANNEL_LVDS_MAX },
- .m2 = { .min = G4X_M2_DUAL_CHANNEL_LVDS_MIN,
- .max = G4X_M2_DUAL_CHANNEL_LVDS_MAX },
- .p = { .min = G4X_P_DUAL_CHANNEL_LVDS_MIN,
- .max = G4X_P_DUAL_CHANNEL_LVDS_MAX },
- .p1 = { .min = G4X_P1_DUAL_CHANNEL_LVDS_MIN,
- .max = G4X_P1_DUAL_CHANNEL_LVDS_MAX },
- .p2 = { .dot_limit = G4X_P2_DUAL_CHANNEL_LVDS_LIMIT,
- .p2_slow = G4X_P2_DUAL_CHANNEL_LVDS_SLOW,
- .p2_fast = G4X_P2_DUAL_CHANNEL_LVDS_FAST
+ .dot = { .min = 80000, .max = 224000 },
+ .vco = { .min = 1750000, .max = 3500000 },
+ .n = { .min = 1, .max = 3 },
+ .m = { .min = 104, .max = 138 },
+ .m1 = { .min = 17, .max = 23 },
+ .m2 = { .min = 5, .max = 11 },
+ .p = { .min = 14, .max = 42 },
+ .p1 = { .min = 2, .max = 6 },
+ .p2 = { .dot_limit = 0,
+ .p2_slow = 7, .p2_fast = 7
},
.find_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_g4x_display_port = {
- .dot = { .min = G4X_DOT_DISPLAY_PORT_MIN,
- .max = G4X_DOT_DISPLAY_PORT_MAX },
- .vco = { .min = G4X_VCO_MIN,
- .max = G4X_VCO_MAX},
- .n = { .min = G4X_N_DISPLAY_PORT_MIN,
- .max = G4X_N_DISPLAY_PORT_MAX },
- .m = { .min = G4X_M_DISPLAY_PORT_MIN,
- .max = G4X_M_DISPLAY_PORT_MAX },
- .m1 = { .min = G4X_M1_DISPLAY_PORT_MIN,
- .max = G4X_M1_DISPLAY_PORT_MAX },
- .m2 = { .min = G4X_M2_DISPLAY_PORT_MIN,
- .max = G4X_M2_DISPLAY_PORT_MAX },
- .p = { .min = G4X_P_DISPLAY_PORT_MIN,
- .max = G4X_P_DISPLAY_PORT_MAX },
- .p1 = { .min = G4X_P1_DISPLAY_PORT_MIN,
- .max = G4X_P1_DISPLAY_PORT_MAX},
- .p2 = { .dot_limit = G4X_P2_DISPLAY_PORT_LIMIT,
- .p2_slow = G4X_P2_DISPLAY_PORT_SLOW,
- .p2_fast = G4X_P2_DISPLAY_PORT_FAST },
+ .dot = { .min = 161670, .max = 227000 },
+ .vco = { .min = 1750000, .max = 3500000},
+ .n = { .min = 1, .max = 2 },
+ .m = { .min = 97, .max = 108 },
+ .m1 = { .min = 0x10, .max = 0x12 },
+ .m2 = { .min = 0x05, .max = 0x06 },
+ .p = { .min = 10, .max = 20 },
+ .p1 = { .min = 1, .max = 2},
+ .p2 = { .dot_limit = 0,
+ .p2_slow = 10, .p2_fast = 10 },
.find_pll = intel_find_pll_g4x_dp,
};
static const intel_limit_t intel_limits_pineview_sdvo = {
- .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX},
- .vco = { .min = PINEVIEW_VCO_MIN, .max = PINEVIEW_VCO_MAX },
- .n = { .min = PINEVIEW_N_MIN, .max = PINEVIEW_N_MAX },
- .m = { .min = PINEVIEW_M_MIN, .max = PINEVIEW_M_MAX },
- .m1 = { .min = PINEVIEW_M1_MIN, .max = PINEVIEW_M1_MAX },
- .m2 = { .min = PINEVIEW_M2_MIN, .max = PINEVIEW_M2_MAX },
- .p = { .min = I9XX_P_SDVO_DAC_MIN, .max = I9XX_P_SDVO_DAC_MAX },
- .p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX },
- .p2 = { .dot_limit = I9XX_P2_SDVO_DAC_SLOW_LIMIT,
- .p2_slow = I9XX_P2_SDVO_DAC_SLOW, .p2_fast = I9XX_P2_SDVO_DAC_FAST },
+ .dot = { .min = 20000, .max = 400000},
+ .vco = { .min = 1700000, .max = 3500000 },
+ /* Pineview's Ncounter is a ring counter */
+ .n = { .min = 3, .max = 6 },
+ .m = { .min = 2, .max = 256 },
+ /* Pineview only has one combined m divider, which we treat as m2. */
+ .m1 = { .min = 0, .max = 0 },
+ .m2 = { .min = 0, .max = 254 },
+ .p = { .min = 5, .max = 80 },
+ .p1 = { .min = 1, .max = 8 },
+ .p2 = { .dot_limit = 200000,
+ .p2_slow = 10, .p2_fast = 5 },
.find_pll = intel_find_best_PLL,
};
static const intel_limit_t intel_limits_pineview_lvds = {
- .dot = { .min = I9XX_DOT_MIN, .max = I9XX_DOT_MAX },
- .vco = { .min = PINEVIEW_VCO_MIN, .max = PINEVIEW_VCO_MAX },
- .n = { .min = PINEVIEW_N_MIN, .max = PINEVIEW_N_MAX },
- .m = { .min = PINEVIEW_M_MIN, .max = PINEVIEW_M_MAX },
- .m1 = { .min = PINEVIEW_M1_MIN, .max = PINEVIEW_M1_MAX },
- .m2 = { .min = PINEVIEW_M2_MIN, .max = PINEVIEW_M2_MAX },
- .p = { .min = PINEVIEW_P_LVDS_MIN, .max = PINEVIEW_P_LVDS_MAX },
- .p1 = { .min = I9XX_P1_MIN, .max = I9XX_P1_MAX },
- /* Pineview only supports single-channel mode. */
- .p2 = { .dot_limit = I9XX_P2_LVDS_SLOW_LIMIT,
- .p2_slow = I9XX_P2_LVDS_SLOW, .p2_fast = I9XX_P2_LVDS_SLOW },
+ .dot = { .min = 20000, .max = 400000 },
+ .vco = { .min = 1700000, .max = 3500000 },
+ .n = { .min = 3, .max = 6 },
+ .m = { .min = 2, .max = 256 },
+ .m1 = { .min = 0, .max = 0 },
+ .m2 = { .min = 0, .max = 254 },
+ .p = { .min = 7, .max = 112 },
+ .p1 = { .min = 1, .max = 8 },
+ .p2 = { .dot_limit = 112000,
+ .p2_slow = 14, .p2_fast = 14 },
.find_pll = intel_find_best_PLL,
};
+/* Ironlake / Sandybridge
+ *
+ * We calculate clock using (register_value + 2) for N/M1/M2, so here
+ * the range value for them is (actual_value - 2).
+ */
static const intel_limit_t intel_limits_ironlake_dac = {
- .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX },
- .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX },
- .n = { .min = IRONLAKE_DAC_N_MIN, .max = IRONLAKE_DAC_N_MAX },
- .m = { .min = IRONLAKE_DAC_M_MIN, .max = IRONLAKE_DAC_M_MAX },
- .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX },
- .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX },
- .p = { .min = IRONLAKE_DAC_P_MIN, .max = IRONLAKE_DAC_P_MAX },
- .p1 = { .min = IRONLAKE_DAC_P1_MIN, .max = IRONLAKE_DAC_P1_MAX },
- .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
- .p2_slow = IRONLAKE_DAC_P2_SLOW,
- .p2_fast = IRONLAKE_DAC_P2_FAST },
+ .dot = { .min = 25000, .max = 350000 },
+ .vco = { .min = 1760000, .max = 3510000 },
+ .n = { .min = 1, .max = 5 },
+ .m = { .min = 79, .max = 127 },
+ .m1 = { .min = 12, .max = 22 },
+ .m2 = { .min = 5, .max = 9 },
+ .p = { .min = 5, .max = 80 },
+ .p1 = { .min = 1, .max = 8 },
+ .p2 = { .dot_limit = 225000,
+ .p2_slow = 10, .p2_fast = 5 },
.find_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_ironlake_single_lvds = {
- .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX },
- .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX },
- .n = { .min = IRONLAKE_LVDS_S_N_MIN, .max = IRONLAKE_LVDS_S_N_MAX },
- .m = { .min = IRONLAKE_LVDS_S_M_MIN, .max = IRONLAKE_LVDS_S_M_MAX },
- .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX },
- .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX },
- .p = { .min = IRONLAKE_LVDS_S_P_MIN, .max = IRONLAKE_LVDS_S_P_MAX },
- .p1 = { .min = IRONLAKE_LVDS_S_P1_MIN, .max = IRONLAKE_LVDS_S_P1_MAX },
- .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
- .p2_slow = IRONLAKE_LVDS_S_P2_SLOW,
- .p2_fast = IRONLAKE_LVDS_S_P2_FAST },
+ .dot = { .min = 25000, .max = 350000 },
+ .vco = { .min = 1760000, .max = 3510000 },
+ .n = { .min = 1, .max = 3 },
+ .m = { .min = 79, .max = 118 },
+ .m1 = { .min = 12, .max = 22 },
+ .m2 = { .min = 5, .max = 9 },
+ .p = { .min = 28, .max = 112 },
+ .p1 = { .min = 2, .max = 8 },
+ .p2 = { .dot_limit = 225000,
+ .p2_slow = 14, .p2_fast = 14 },
.find_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_ironlake_dual_lvds = {
- .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX },
- .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX },
- .n = { .min = IRONLAKE_LVDS_D_N_MIN, .max = IRONLAKE_LVDS_D_N_MAX },
- .m = { .min = IRONLAKE_LVDS_D_M_MIN, .max = IRONLAKE_LVDS_D_M_MAX },
- .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX },
- .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX },
- .p = { .min = IRONLAKE_LVDS_D_P_MIN, .max = IRONLAKE_LVDS_D_P_MAX },
- .p1 = { .min = IRONLAKE_LVDS_D_P1_MIN, .max = IRONLAKE_LVDS_D_P1_MAX },
- .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
- .p2_slow = IRONLAKE_LVDS_D_P2_SLOW,
- .p2_fast = IRONLAKE_LVDS_D_P2_FAST },
+ .dot = { .min = 25000, .max = 350000 },
+ .vco = { .min = 1760000, .max = 3510000 },
+ .n = { .min = 1, .max = 3 },
+ .m = { .min = 79, .max = 127 },
+ .m1 = { .min = 12, .max = 22 },
+ .m2 = { .min = 5, .max = 9 },
+ .p = { .min = 14, .max = 56 },
+ .p1 = { .min = 2, .max = 8 },
+ .p2 = { .dot_limit = 225000,
+ .p2_slow = 7, .p2_fast = 7 },
.find_pll = intel_g4x_find_best_PLL,
};
+/* LVDS 100mhz refclk limits. */
static const intel_limit_t intel_limits_ironlake_single_lvds_100m = {
- .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX },
- .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX },
- .n = { .min = IRONLAKE_LVDS_S_SSC_N_MIN, .max = IRONLAKE_LVDS_S_SSC_N_MAX },
- .m = { .min = IRONLAKE_LVDS_S_SSC_M_MIN, .max = IRONLAKE_LVDS_S_SSC_M_MAX },
- .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX },
- .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX },
- .p = { .min = IRONLAKE_LVDS_S_SSC_P_MIN, .max = IRONLAKE_LVDS_S_SSC_P_MAX },
- .p1 = { .min = IRONLAKE_LVDS_S_SSC_P1_MIN,.max = IRONLAKE_LVDS_S_SSC_P1_MAX },
- .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
- .p2_slow = IRONLAKE_LVDS_S_SSC_P2_SLOW,
- .p2_fast = IRONLAKE_LVDS_S_SSC_P2_FAST },
+ .dot = { .min = 25000, .max = 350000 },
+ .vco = { .min = 1760000, .max = 3510000 },
+ .n = { .min = 1, .max = 2 },
+ .m = { .min = 79, .max = 126 },
+ .m1 = { .min = 12, .max = 22 },
+ .m2 = { .min = 5, .max = 9 },
+ .p = { .min = 28, .max = 112 },
+ .p1 = { .min = 2,.max = 8 },
+ .p2 = { .dot_limit = 225000,
+ .p2_slow = 14, .p2_fast = 14 },
.find_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_ironlake_dual_lvds_100m = {
- .dot = { .min = IRONLAKE_DOT_MIN, .max = IRONLAKE_DOT_MAX },
- .vco = { .min = IRONLAKE_VCO_MIN, .max = IRONLAKE_VCO_MAX },
- .n = { .min = IRONLAKE_LVDS_D_SSC_N_MIN, .max = IRONLAKE_LVDS_D_SSC_N_MAX },
- .m = { .min = IRONLAKE_LVDS_D_SSC_M_MIN, .max = IRONLAKE_LVDS_D_SSC_M_MAX },
- .m1 = { .min = IRONLAKE_M1_MIN, .max = IRONLAKE_M1_MAX },
- .m2 = { .min = IRONLAKE_M2_MIN, .max = IRONLAKE_M2_MAX },
- .p = { .min = IRONLAKE_LVDS_D_SSC_P_MIN, .max = IRONLAKE_LVDS_D_SSC_P_MAX },
- .p1 = { .min = IRONLAKE_LVDS_D_SSC_P1_MIN,.max = IRONLAKE_LVDS_D_SSC_P1_MAX },
- .p2 = { .dot_limit = IRONLAKE_P2_DOT_LIMIT,
- .p2_slow = IRONLAKE_LVDS_D_SSC_P2_SLOW,
- .p2_fast = IRONLAKE_LVDS_D_SSC_P2_FAST },
+ .dot = { .min = 25000, .max = 350000 },
+ .vco = { .min = 1760000, .max = 3510000 },
+ .n = { .min = 1, .max = 3 },
+ .m = { .min = 79, .max = 126 },
+ .m1 = { .min = 12, .max = 22 },
+ .m2 = { .min = 5, .max = 9 },
+ .p = { .min = 14, .max = 42 },
+ .p1 = { .min = 2,.max = 6 },
+ .p2 = { .dot_limit = 225000,
+ .p2_slow = 7, .p2_fast = 7 },
.find_pll = intel_g4x_find_best_PLL,
};
static const intel_limit_t intel_limits_ironlake_display_port = {
- .dot = { .min = IRONLAKE_DOT_MIN,
- .max = IRONLAKE_DOT_MAX },
- .vco = { .min = IRONLAKE_VCO_MIN,
- .max = IRONLAKE_VCO_MAX},
- .n = { .min = IRONLAKE_DP_N_MIN,
- .max = IRONLAKE_DP_N_MAX },
- .m = { .min = IRONLAKE_DP_M_MIN,
- .max = IRONLAKE_DP_M_MAX },
- .m1 = { .min = IRONLAKE_M1_MIN,
- .max = IRONLAKE_M1_MAX },
- .m2 = { .min = IRONLAKE_M2_MIN,
- .max = IRONLAKE_M2_MAX },
- .p = { .min = IRONLAKE_DP_P_MIN,
- .max = IRONLAKE_DP_P_MAX },
- .p1 = { .min = IRONLAKE_DP_P1_MIN,
- .max = IRONLAKE_DP_P1_MAX},
- .p2 = { .dot_limit = IRONLAKE_DP_P2_LIMIT,
- .p2_slow = IRONLAKE_DP_P2_SLOW,
- .p2_fast = IRONLAKE_DP_P2_FAST },
+ .dot = { .min = 25000, .max = 350000 },
+ .vco = { .min = 1760000, .max = 3510000},
+ .n = { .min = 1, .max = 2 },
+ .m = { .min = 81, .max = 90 },
+ .m1 = { .min = 12, .max = 22 },
+ .m2 = { .min = 5, .max = 9 },
+ .p = { .min = 10, .max = 20 },
+ .p1 = { .min = 1, .max = 2},
+ .p2 = { .dot_limit = 0,
+ .p2_slow = 10, .p2_fast = 10 },
.find_pll = intel_find_pll_ironlake_dp,
};
@@ -1828,7 +1540,7 @@ static void sandybridge_blit_fbc_update(struct drm_device *dev)
u32 blt_ecoskpd;
/* Make sure blitter notifies FBC of writes */
- __gen6_gt_force_wake_get(dev_priv);
+ gen6_gt_force_wake_get(dev_priv);
blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD);
blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY <<
GEN6_BLITTER_LOCK_SHIFT;
@@ -1839,7 +1551,7 @@ static void sandybridge_blit_fbc_update(struct drm_device *dev)
GEN6_BLITTER_LOCK_SHIFT);
I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
POSTING_READ(GEN6_BLITTER_ECOSKPD);
- __gen6_gt_force_wake_put(dev_priv);
+ gen6_gt_force_wake_put(dev_priv);
}
static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
@@ -2019,6 +1731,11 @@ static void intel_update_fbc(struct drm_device *dev)
intel_fb = to_intel_framebuffer(fb);
obj = intel_fb->obj;
+ if (!i915_enable_fbc) {
+ DRM_DEBUG_KMS("fbc disabled per module param (default off)\n");
+ dev_priv->no_fbc_reason = FBC_MODULE_PARAM;
+ goto out_disable;
+ }
if (intel_fb->obj->base.size > dev_priv->cfb_size) {
DRM_DEBUG_KMS("framebuffer too large, disabling "
"compression\n");
@@ -2339,8 +2056,13 @@ static void intel_fdi_normal_train(struct drm_crtc *crtc)
/* enable normal train */
reg = FDI_TX_CTL(pipe);
temp = I915_READ(reg);
- temp &= ~FDI_LINK_TRAIN_NONE;
- temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
+ if (IS_IVYBRIDGE(dev)) {
+ temp &= ~FDI_LINK_TRAIN_NONE_IVB;
+ temp |= FDI_LINK_TRAIN_NONE_IVB | FDI_TX_ENHANCE_FRAME_ENABLE;
+ } else {
+ temp &= ~FDI_LINK_TRAIN_NONE;
+ temp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE;
+ }
I915_WRITE(reg, temp);
reg = FDI_RX_CTL(pipe);
@@ -2357,6 +2079,11 @@ static void intel_fdi_normal_train(struct drm_crtc *crtc)
/* wait one idle pattern time */
POSTING_READ(reg);
udelay(1000);
+
+ /* IVB wants error correction enabled */
+ if (IS_IVYBRIDGE(dev))
+ I915_WRITE(reg, I915_READ(reg) | FDI_FS_ERRC_ENABLE |
+ FDI_FE_ERRC_ENABLE);
}
/* The FDI link training functions for ILK/Ibexpeak. */
@@ -2584,7 +2311,116 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
DRM_DEBUG_KMS("FDI train done.\n");
}
-static void ironlake_fdi_enable(struct drm_crtc *crtc)
+/* Manual link training for Ivy Bridge A0 parts */
+static void ivb_manual_fdi_link_train(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;
+ u32 reg, temp, i;
+
+ /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
+ for train result */
+ reg = FDI_RX_IMR(pipe);
+ temp = I915_READ(reg);
+ temp &= ~FDI_RX_SYMBOL_LOCK;
+ temp &= ~FDI_RX_BIT_LOCK;
+ I915_WRITE(reg, temp);
+
+ POSTING_READ(reg);
+ udelay(150);
+
+ /* enable CPU FDI TX and PCH FDI RX */
+ reg = FDI_TX_CTL(pipe);
+ temp = I915_READ(reg);
+ temp &= ~(7 << 19);
+ temp |= (intel_crtc->fdi_lanes - 1) << 19;
+ temp &= ~(FDI_LINK_TRAIN_AUTO | FDI_LINK_TRAIN_NONE_IVB);
+ temp |= FDI_LINK_TRAIN_PATTERN_1_IVB;
+ temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+ temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
+ I915_WRITE(reg, temp | FDI_TX_ENABLE);
+
+ reg = FDI_RX_CTL(pipe);
+ temp = I915_READ(reg);
+ temp &= ~FDI_LINK_TRAIN_AUTO;
+ temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+ temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
+ I915_WRITE(reg, temp | FDI_RX_ENABLE);
+
+ POSTING_READ(reg);
+ udelay(150);
+
+ for (i = 0; i < 4; i++ ) {
+ reg = FDI_TX_CTL(pipe);
+ temp = I915_READ(reg);
+ temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+ temp |= snb_b_fdi_train_param[i];
+ I915_WRITE(reg, temp);
+
+ POSTING_READ(reg);
+ udelay(500);
+
+ reg = FDI_RX_IIR(pipe);
+ temp = I915_READ(reg);
+ DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
+
+ if (temp & FDI_RX_BIT_LOCK ||
+ (I915_READ(reg) & FDI_RX_BIT_LOCK)) {
+ I915_WRITE(reg, temp | FDI_RX_BIT_LOCK);
+ DRM_DEBUG_KMS("FDI train 1 done.\n");
+ break;
+ }
+ }
+ if (i == 4)
+ DRM_ERROR("FDI train 1 fail!\n");
+
+ /* Train 2 */
+ reg = FDI_TX_CTL(pipe);
+ temp = I915_READ(reg);
+ temp &= ~FDI_LINK_TRAIN_NONE_IVB;
+ temp |= FDI_LINK_TRAIN_PATTERN_2_IVB;
+ temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+ temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
+ I915_WRITE(reg, temp);
+
+ reg = FDI_RX_CTL(pipe);
+ temp = I915_READ(reg);
+ temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
+ temp |= FDI_LINK_TRAIN_PATTERN_2_CPT;
+ I915_WRITE(reg, temp);
+
+ POSTING_READ(reg);
+ udelay(150);
+
+ for (i = 0; i < 4; i++ ) {
+ reg = FDI_TX_CTL(pipe);
+ temp = I915_READ(reg);
+ temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
+ temp |= snb_b_fdi_train_param[i];
+ I915_WRITE(reg, temp);
+
+ POSTING_READ(reg);
+ udelay(500);
+
+ reg = FDI_RX_IIR(pipe);
+ temp = I915_READ(reg);
+ DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
+
+ if (temp & FDI_RX_SYMBOL_LOCK) {
+ I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK);
+ DRM_DEBUG_KMS("FDI train 2 done.\n");
+ break;
+ }
+ }
+ if (i == 4)
+ DRM_ERROR("FDI train 2 fail!\n");
+
+ DRM_DEBUG_KMS("FDI train done.\n");
+}
+
+static void ironlake_fdi_pll_enable(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2757,10 +2593,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
u32 reg, temp;
/* For PCH output, training FDI link */
- if (IS_GEN6(dev))
- gen6_fdi_link_train(crtc);
- else
- ironlake_fdi_link_train(crtc);
+ dev_priv->display.fdi_link_train(crtc);
intel_enable_pch_pll(dev_priv, pipe);
@@ -2850,7 +2683,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
is_pch_port = intel_crtc_driving_pch(crtc);
if (is_pch_port)
- ironlake_fdi_enable(crtc);
+ ironlake_fdi_pll_enable(crtc);
else
ironlake_fdi_disable(crtc);
@@ -2873,7 +2706,11 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
ironlake_pch_enable(crtc);
intel_crtc_load_lut(crtc);
+
+ mutex_lock(&dev->struct_mutex);
intel_update_fbc(dev);
+ mutex_unlock(&dev->struct_mutex);
+
intel_crtc_update_cursor(crtc, true);
}
@@ -2969,8 +2806,11 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
intel_crtc->active = false;
intel_update_watermarks(dev);
+
+ mutex_lock(&dev->struct_mutex);
intel_update_fbc(dev);
intel_clear_scanline_wait(dev);
+ mutex_unlock(&dev->struct_mutex);
}
static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
@@ -3497,11 +3337,11 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
1000;
entries_required = DIV_ROUND_UP(entries_required, wm->cacheline_size);
- DRM_DEBUG_KMS("FIFO entries required for mode: %d\n", entries_required);
+ DRM_DEBUG_KMS("FIFO entries required for mode: %ld\n", entries_required);
wm_size = fifo_size - (entries_required + wm->guard_size);
- DRM_DEBUG_KMS("FIFO watermark level: %d\n", wm_size);
+ DRM_DEBUG_KMS("FIFO watermark level: %ld\n", wm_size);
/* Don't promote wm_size to unsigned... */
if (wm_size > (long)wm->max_wm)
@@ -3823,13 +3663,13 @@ static bool g4x_check_srwm(struct drm_device *dev,
display_wm, cursor_wm);
if (display_wm > display->max_wm) {
- DRM_DEBUG_KMS("display watermark is too large(%d), disabling\n",
+ DRM_DEBUG_KMS("display watermark is too large(%d/%ld), disabling\n",
display_wm, display->max_wm);
return false;
}
if (cursor_wm > cursor->max_wm) {
- DRM_DEBUG_KMS("cursor watermark is too large(%d), disabling\n",
+ DRM_DEBUG_KMS("cursor watermark is too large(%d/%ld), disabling\n",
cursor_wm, cursor->max_wm);
return false;
}
@@ -4516,34 +4356,28 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
return dev_priv->lvds_use_ssc && i915_panel_use_ssc;
}
-static int intel_crtc_mode_set(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode,
- int x, int y,
- struct drm_framebuffer *old_fb)
+static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode,
+ int x, int y,
+ struct drm_framebuffer *old_fb)
{
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 plane = intel_crtc->plane;
- u32 fp_reg, dpll_reg;
int refclk, num_connectors = 0;
intel_clock_t clock, reduced_clock;
u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf;
bool ok, has_reduced_clock = false, is_sdvo = false, is_dvo = false;
bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
- struct intel_encoder *has_edp_encoder = NULL;
struct drm_mode_config *mode_config = &dev->mode_config;
struct intel_encoder *encoder;
const intel_limit_t *limit;
int ret;
- struct fdi_m_n m_n = {0};
- u32 reg, temp;
+ u32 temp;
u32 lvds_sync = 0;
- int target_clock;
-
- drm_vblank_pre_modeset(dev, pipe);
list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
if (encoder->base.crtc != crtc)
@@ -4571,9 +4405,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
case INTEL_OUTPUT_DISPLAYPORT:
is_dp = true;
break;
- case INTEL_OUTPUT_EDP:
- has_edp_encoder = encoder;
- break;
}
num_connectors++;
@@ -4585,9 +4416,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
refclk / 1000);
} else if (!IS_GEN2(dev)) {
refclk = 96000;
- if (HAS_PCH_SPLIT(dev) &&
- (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)))
- refclk = 120000; /* 120Mhz refclk */
} else {
refclk = 48000;
}
@@ -4601,7 +4429,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock);
if (!ok) {
DRM_ERROR("Couldn't find PLL settings for mode!\n");
- drm_vblank_post_modeset(dev, pipe);
return -EINVAL;
}
@@ -4645,143 +4472,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
}
}
- /* FDI link */
- if (HAS_PCH_SPLIT(dev)) {
- int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
- int lane = 0, link_bw, bpp;
- /* CPU eDP doesn't require FDI link, so just set DP M/N
- according to current link config */
- if (has_edp_encoder && !intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
- target_clock = mode->clock;
- intel_edp_link_config(has_edp_encoder,
- &lane, &link_bw);
- } else {
- /* [e]DP over FDI requires target mode clock
- instead of link clock */
- if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base))
- target_clock = mode->clock;
- else
- target_clock = adjusted_mode->clock;
-
- /* FDI is a binary signal running at ~2.7GHz, encoding
- * each output octet as 10 bits. The actual frequency
- * is stored as a divider into a 100MHz clock, and the
- * mode pixel clock is stored in units of 1KHz.
- * Hence the bw of each lane in terms of the mode signal
- * is:
- */
- link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10;
- }
-
- /* determine panel color depth */
- temp = I915_READ(PIPECONF(pipe));
- temp &= ~PIPE_BPC_MASK;
- if (is_lvds) {
- /* the BPC will be 6 if it is 18-bit LVDS panel */
- if ((I915_READ(PCH_LVDS) & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP)
- temp |= PIPE_8BPC;
- else
- temp |= PIPE_6BPC;
- } else if (has_edp_encoder) {
- switch (dev_priv->edp.bpp/3) {
- case 8:
- temp |= PIPE_8BPC;
- break;
- case 10:
- temp |= PIPE_10BPC;
- break;
- case 6:
- temp |= PIPE_6BPC;
- break;
- case 12:
- temp |= PIPE_12BPC;
- break;
- }
- } else
- temp |= PIPE_8BPC;
- I915_WRITE(PIPECONF(pipe), temp);
-
- switch (temp & PIPE_BPC_MASK) {
- case PIPE_8BPC:
- bpp = 24;
- break;
- case PIPE_10BPC:
- bpp = 30;
- break;
- case PIPE_6BPC:
- bpp = 18;
- break;
- case PIPE_12BPC:
- bpp = 36;
- break;
- default:
- DRM_ERROR("unknown pipe bpc value\n");
- bpp = 24;
- }
-
- if (!lane) {
- /*
- * Account for spread spectrum to avoid
- * oversubscribing the link. Max center spread
- * is 2.5%; use 5% for safety's sake.
- */
- u32 bps = target_clock * bpp * 21 / 20;
- lane = bps / (link_bw * 8) + 1;
- }
-
- intel_crtc->fdi_lanes = lane;
-
- if (pixel_multiplier > 1)
- link_bw *= pixel_multiplier;
- ironlake_compute_m_n(bpp, lane, target_clock, link_bw, &m_n);
- }
-
- /* Ironlake: try to setup display ref clock before DPLL
- * enabling. This is only under driver's control after
- * PCH B stepping, previous chipset stepping should be
- * ignoring this setting.
- */
- if (HAS_PCH_SPLIT(dev)) {
- temp = I915_READ(PCH_DREF_CONTROL);
- /* Always enable nonspread source */
- temp &= ~DREF_NONSPREAD_SOURCE_MASK;
- temp |= DREF_NONSPREAD_SOURCE_ENABLE;
- temp &= ~DREF_SSC_SOURCE_MASK;
- temp |= DREF_SSC_SOURCE_ENABLE;
- I915_WRITE(PCH_DREF_CONTROL, temp);
-
- POSTING_READ(PCH_DREF_CONTROL);
- udelay(200);
-
- if (has_edp_encoder) {
- if (intel_panel_use_ssc(dev_priv)) {
- temp |= DREF_SSC1_ENABLE;
- I915_WRITE(PCH_DREF_CONTROL, temp);
-
- POSTING_READ(PCH_DREF_CONTROL);
- udelay(200);
- }
- temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
-
- /* Enable CPU source on CPU attached eDP */
- if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
- if (intel_panel_use_ssc(dev_priv))
- temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
- else
- temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
- } else {
- /* Enable SSC on PCH eDP if needed */
- if (intel_panel_use_ssc(dev_priv)) {
- DRM_ERROR("enabling SSC on PCH\n");
- temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
- }
- }
- I915_WRITE(PCH_DREF_CONTROL, temp);
- POSTING_READ(PCH_DREF_CONTROL);
- udelay(200);
- }
- }
-
if (IS_PINEVIEW(dev)) {
fp = (1 << clock.n) << 16 | clock.m1 << 8 | clock.m2;
if (has_reduced_clock)
@@ -4794,25 +4484,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
reduced_clock.m2;
}
- /* Enable autotuning of the PLL clock (if permissible) */
- if (HAS_PCH_SPLIT(dev)) {
- int factor = 21;
-
- if (is_lvds) {
- if ((intel_panel_use_ssc(dev_priv) &&
- dev_priv->lvds_ssc_freq == 100) ||
- (I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP)
- factor = 25;
- } else if (is_sdvo && is_tv)
- factor = 20;
-
- if (clock.m1 < factor * clock.n)
- fp |= FP_CB_TUNE;
- }
-
- dpll = 0;
- if (!HAS_PCH_SPLIT(dev))
- dpll = DPLL_VGA_MODE_DIS;
+ dpll = DPLL_VGA_MODE_DIS;
if (!IS_GEN2(dev)) {
if (is_lvds)
@@ -4824,12 +4496,10 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
if (pixel_multiplier > 1) {
if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
dpll |= (pixel_multiplier - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
- else if (HAS_PCH_SPLIT(dev))
- dpll |= (pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
}
dpll |= DPLL_DVO_HIGH_SPEED;
}
- if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base))
+ if (is_dp)
dpll |= DPLL_DVO_HIGH_SPEED;
/* compute bitmask from p1 value */
@@ -4837,9 +4507,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT_PINEVIEW;
else {
dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
- /* also FPA1 */
- if (HAS_PCH_SPLIT(dev))
- dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
if (IS_G4X(dev) && has_reduced_clock)
dpll |= (1 << (reduced_clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
}
@@ -4857,7 +4524,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
break;
}
- if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
+ if (INTEL_INFO(dev)->gen >= 4)
dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
} else {
if (is_lvds) {
@@ -4891,12 +4558,10 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
/* Ironlake's plane is forced to pipe, bit 24 is to
enable color space conversion */
- if (!HAS_PCH_SPLIT(dev)) {
- if (pipe == 0)
- dspcntr &= ~DISPPLANE_SEL_PIPE_MASK;
- else
- dspcntr |= DISPPLANE_SEL_PIPE_B;
- }
+ if (pipe == 0)
+ dspcntr &= ~DISPPLANE_SEL_PIPE_MASK;
+ else
+ dspcntr |= DISPPLANE_SEL_PIPE_B;
if (pipe == 0 && INTEL_INFO(dev)->gen < 4) {
/* Enable pixel doubling when the dot clock is > 90% of the (display)
@@ -4912,27 +4577,506 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
pipeconf &= ~PIPECONF_DOUBLE_WIDE;
}
- if (!HAS_PCH_SPLIT(dev))
- dpll |= DPLL_VCO_ENABLE;
+ dpll |= DPLL_VCO_ENABLE;
DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
drm_mode_debug_printmodeline(mode);
- /* assign to Ironlake registers */
- if (HAS_PCH_SPLIT(dev)) {
- fp_reg = PCH_FP0(pipe);
- dpll_reg = PCH_DPLL(pipe);
+ I915_WRITE(FP0(pipe), fp);
+ I915_WRITE(DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);
+
+ POSTING_READ(DPLL(pipe));
+ udelay(150);
+
+ /* 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.
+ */
+ if (is_lvds) {
+ temp = I915_READ(LVDS);
+ temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
+ if (pipe == 1) {
+ temp |= LVDS_PIPEB_SELECT;
+ } else {
+ temp &= ~LVDS_PIPEB_SELECT;
+ }
+ /* set the corresponsding LVDS_BORDER bit */
+ temp |= dev_priv->lvds_border_bits;
+ /* Set the B0-B3 data pairs corresponding to whether we're going to
+ * set the DPLLs for dual-channel mode or not.
+ */
+ if (clock.p2 == 7)
+ temp |= LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP;
+ else
+ temp &= ~(LVDS_B0B3_POWER_UP | LVDS_CLKB_POWER_UP);
+
+ /* It would be nice to set 24 vs 18-bit mode (LVDS_A3_POWER_UP)
+ * appropriately here, but we need to look more thoroughly into how
+ * panels behave in the two modes.
+ */
+ /* set the dithering flag on LVDS as needed */
+ if (INTEL_INFO(dev)->gen >= 4) {
+ if (dev_priv->lvds_dither)
+ temp |= LVDS_ENABLE_DITHER;
+ else
+ temp &= ~LVDS_ENABLE_DITHER;
+ }
+ if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
+ lvds_sync |= LVDS_HSYNC_POLARITY;
+ if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
+ lvds_sync |= LVDS_VSYNC_POLARITY;
+ if ((temp & (LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY))
+ != lvds_sync) {
+ char flags[2] = "-+";
+ DRM_INFO("Changing LVDS panel from "
+ "(%chsync, %cvsync) to (%chsync, %cvsync)\n",
+ flags[!(temp & LVDS_HSYNC_POLARITY)],
+ flags[!(temp & LVDS_VSYNC_POLARITY)],
+ flags[!(lvds_sync & LVDS_HSYNC_POLARITY)],
+ flags[!(lvds_sync & LVDS_VSYNC_POLARITY)]);
+ temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
+ temp |= lvds_sync;
+ }
+ I915_WRITE(LVDS, temp);
+ }
+
+ if (is_dp) {
+ intel_dp_set_m_n(crtc, mode, adjusted_mode);
+ }
+
+ I915_WRITE(DPLL(pipe), dpll);
+
+ /* Wait for the clocks to stabilize. */
+ POSTING_READ(DPLL(pipe));
+ udelay(150);
+
+ if (INTEL_INFO(dev)->gen >= 4) {
+ temp = 0;
+ if (is_sdvo) {
+ temp = intel_mode_get_pixel_multiplier(adjusted_mode);
+ if (temp > 1)
+ temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
+ else
+ temp = 0;
+ }
+ I915_WRITE(DPLL_MD(pipe), temp);
+ } else {
+ /* The pixel multiplier can only be updated once the
+ * DPLL is enabled and the clocks are stable.
+ *
+ * So write it again.
+ */
+ I915_WRITE(DPLL(pipe), dpll);
+ }
+
+ intel_crtc->lowfreq_avail = false;
+ if (is_lvds && has_reduced_clock && i915_powersave) {
+ I915_WRITE(FP1(pipe), fp2);
+ intel_crtc->lowfreq_avail = true;
+ if (HAS_PIPE_CXSR(dev)) {
+ DRM_DEBUG_KMS("enabling CxSR downclocking\n");
+ pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
+ }
+ } else {
+ I915_WRITE(FP1(pipe), fp);
+ if (HAS_PIPE_CXSR(dev)) {
+ DRM_DEBUG_KMS("disabling CxSR downclocking\n");
+ pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
+ }
+ }
+
+ if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
+ pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
+ /* the chip adds 2 halflines automatically */
+ adjusted_mode->crtc_vdisplay -= 1;
+ adjusted_mode->crtc_vtotal -= 1;
+ adjusted_mode->crtc_vblank_start -= 1;
+ adjusted_mode->crtc_vblank_end -= 1;
+ adjusted_mode->crtc_vsync_end -= 1;
+ adjusted_mode->crtc_vsync_start -= 1;
+ } else
+ pipeconf &= ~PIPECONF_INTERLACE_W_FIELD_INDICATION; /* progressive */
+
+ I915_WRITE(HTOTAL(pipe),
+ (adjusted_mode->crtc_hdisplay - 1) |
+ ((adjusted_mode->crtc_htotal - 1) << 16));
+ I915_WRITE(HBLANK(pipe),
+ (adjusted_mode->crtc_hblank_start - 1) |
+ ((adjusted_mode->crtc_hblank_end - 1) << 16));
+ I915_WRITE(HSYNC(pipe),
+ (adjusted_mode->crtc_hsync_start - 1) |
+ ((adjusted_mode->crtc_hsync_end - 1) << 16));
+
+ I915_WRITE(VTOTAL(pipe),
+ (adjusted_mode->crtc_vdisplay - 1) |
+ ((adjusted_mode->crtc_vtotal - 1) << 16));
+ I915_WRITE(VBLANK(pipe),
+ (adjusted_mode->crtc_vblank_start - 1) |
+ ((adjusted_mode->crtc_vblank_end - 1) << 16));
+ I915_WRITE(VSYNC(pipe),
+ (adjusted_mode->crtc_vsync_start - 1) |
+ ((adjusted_mode->crtc_vsync_end - 1) << 16));
+
+ /* pipesrc and dspsize control the size that is scaled from,
+ * which should always be the user's requested size.
+ */
+ I915_WRITE(DSPSIZE(plane),
+ ((mode->vdisplay - 1) << 16) |
+ (mode->hdisplay - 1));
+ I915_WRITE(DSPPOS(plane), 0);
+ I915_WRITE(PIPESRC(pipe),
+ ((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
+
+ I915_WRITE(PIPECONF(pipe), pipeconf);
+ POSTING_READ(PIPECONF(pipe));
+ intel_enable_pipe(dev_priv, pipe, false);
+
+ intel_wait_for_vblank(dev, pipe);
+
+ I915_WRITE(DSPCNTR(plane), dspcntr);
+ POSTING_READ(DSPCNTR(plane));
+
+ ret = intel_pipe_set_base(crtc, x, y, old_fb);
+
+ intel_update_watermarks(dev);
+
+ return ret;
+}
+
+static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode,
+ int x, int y,
+ struct drm_framebuffer *old_fb)
+{
+ 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 plane = intel_crtc->plane;
+ int refclk, num_connectors = 0;
+ intel_clock_t clock, reduced_clock;
+ u32 dpll, fp = 0, fp2 = 0, dspcntr, pipeconf;
+ bool ok, has_reduced_clock = false, is_sdvo = false;
+ bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
+ struct intel_encoder *has_edp_encoder = NULL;
+ struct drm_mode_config *mode_config = &dev->mode_config;
+ struct intel_encoder *encoder;
+ const intel_limit_t *limit;
+ int ret;
+ struct fdi_m_n m_n = {0};
+ u32 temp;
+ u32 lvds_sync = 0;
+ int target_clock, pixel_multiplier, lane, link_bw, bpp, factor;
+
+ list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
+ if (encoder->base.crtc != crtc)
+ continue;
+
+ switch (encoder->type) {
+ case INTEL_OUTPUT_LVDS:
+ is_lvds = true;
+ break;
+ case INTEL_OUTPUT_SDVO:
+ case INTEL_OUTPUT_HDMI:
+ is_sdvo = true;
+ if (encoder->needs_tv_clock)
+ is_tv = true;
+ break;
+ case INTEL_OUTPUT_TVOUT:
+ is_tv = true;
+ break;
+ case INTEL_OUTPUT_ANALOG:
+ is_crt = true;
+ break;
+ case INTEL_OUTPUT_DISPLAYPORT:
+ is_dp = true;
+ break;
+ case INTEL_OUTPUT_EDP:
+ has_edp_encoder = encoder;
+ break;
+ }
+
+ num_connectors++;
+ }
+
+ if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
+ refclk = dev_priv->lvds_ssc_freq * 1000;
+ DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
+ refclk / 1000);
+ } else {
+ refclk = 96000;
+ if (!has_edp_encoder ||
+ intel_encoder_is_pch_edp(&has_edp_encoder->base))
+ refclk = 120000; /* 120Mhz refclk */
+ }
+
+ /*
+ * Returns a set of divisors for the desired target clock with the given
+ * refclk, or FALSE. The returned values represent the clock equation:
+ * reflck * (5 * (m1 + 2) + (m2 + 2)) / (n + 2) / p1 / p2.
+ */
+ limit = intel_limit(crtc, refclk);
+ ok = limit->find_pll(limit, crtc, adjusted_mode->clock, refclk, &clock);
+ if (!ok) {
+ DRM_ERROR("Couldn't find PLL settings for mode!\n");
+ return -EINVAL;
+ }
+
+ /* Ensure that the cursor is valid for the new mode before changing... */
+ intel_crtc_update_cursor(crtc, true);
+
+ if (is_lvds && dev_priv->lvds_downclock_avail) {
+ has_reduced_clock = limit->find_pll(limit, crtc,
+ dev_priv->lvds_downclock,
+ refclk,
+ &reduced_clock);
+ if (has_reduced_clock && (clock.p != reduced_clock.p)) {
+ /*
+ * If the different P is found, it means that we can't
+ * switch the display clock by using the FP0/FP1.
+ * In such case we will disable the LVDS downclock
+ * feature.
+ */
+ DRM_DEBUG_KMS("Different P is found for "
+ "LVDS clock/downclock\n");
+ has_reduced_clock = 0;
+ }
+ }
+ /* SDVO TV has fixed PLL values depend on its clock range,
+ this mirrors vbios setting. */
+ if (is_sdvo && is_tv) {
+ if (adjusted_mode->clock >= 100000
+ && adjusted_mode->clock < 140500) {
+ clock.p1 = 2;
+ clock.p2 = 10;
+ clock.n = 3;
+ clock.m1 = 16;
+ clock.m2 = 8;
+ } else if (adjusted_mode->clock >= 140500
+ && adjusted_mode->clock <= 200000) {
+ clock.p1 = 1;
+ clock.p2 = 10;
+ clock.n = 6;
+ clock.m1 = 12;
+ clock.m2 = 8;
+ }
+ }
+
+ /* FDI link */
+ pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
+ lane = 0;
+ /* CPU eDP doesn't require FDI link, so just set DP M/N
+ according to current link config */
+ if (has_edp_encoder &&
+ !intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+ target_clock = mode->clock;
+ intel_edp_link_config(has_edp_encoder,
+ &lane, &link_bw);
} else {
- fp_reg = FP0(pipe);
- dpll_reg = DPLL(pipe);
+ /* [e]DP over FDI requires target mode clock
+ instead of link clock */
+ if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base))
+ target_clock = mode->clock;
+ else
+ target_clock = adjusted_mode->clock;
+
+ /* FDI is a binary signal running at ~2.7GHz, encoding
+ * each output octet as 10 bits. The actual frequency
+ * is stored as a divider into a 100MHz clock, and the
+ * mode pixel clock is stored in units of 1KHz.
+ * Hence the bw of each lane in terms of the mode signal
+ * is:
+ */
+ link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10;
+ }
+
+ /* determine panel color depth */
+ temp = I915_READ(PIPECONF(pipe));
+ temp &= ~PIPE_BPC_MASK;
+ if (is_lvds) {
+ /* the BPC will be 6 if it is 18-bit LVDS panel */
+ if ((I915_READ(PCH_LVDS) & LVDS_A3_POWER_MASK) == LVDS_A3_POWER_UP)
+ temp |= PIPE_8BPC;
+ else
+ temp |= PIPE_6BPC;
+ } else if (has_edp_encoder) {
+ switch (dev_priv->edp.bpp/3) {
+ case 8:
+ temp |= PIPE_8BPC;
+ break;
+ case 10:
+ temp |= PIPE_10BPC;
+ break;
+ case 6:
+ temp |= PIPE_6BPC;
+ break;
+ case 12:
+ temp |= PIPE_12BPC;
+ break;
+ }
+ } else
+ temp |= PIPE_8BPC;
+ I915_WRITE(PIPECONF(pipe), temp);
+
+ switch (temp & PIPE_BPC_MASK) {
+ case PIPE_8BPC:
+ bpp = 24;
+ break;
+ case PIPE_10BPC:
+ bpp = 30;
+ break;
+ case PIPE_6BPC:
+ bpp = 18;
+ break;
+ case PIPE_12BPC:
+ bpp = 36;
+ break;
+ default:
+ DRM_ERROR("unknown pipe bpc value\n");
+ bpp = 24;
+ }
+
+ if (!lane) {
+ /*
+ * Account for spread spectrum to avoid
+ * oversubscribing the link. Max center spread
+ * is 2.5%; use 5% for safety's sake.
+ */
+ u32 bps = target_clock * bpp * 21 / 20;
+ lane = bps / (link_bw * 8) + 1;
}
+ intel_crtc->fdi_lanes = lane;
+
+ if (pixel_multiplier > 1)
+ link_bw *= pixel_multiplier;
+ ironlake_compute_m_n(bpp, lane, target_clock, link_bw, &m_n);
+
+ /* Ironlake: try to setup display ref clock before DPLL
+ * enabling. This is only under driver's control after
+ * PCH B stepping, previous chipset stepping should be
+ * ignoring this setting.
+ */
+ temp = I915_READ(PCH_DREF_CONTROL);
+ /* Always enable nonspread source */
+ temp &= ~DREF_NONSPREAD_SOURCE_MASK;
+ temp |= DREF_NONSPREAD_SOURCE_ENABLE;
+ temp &= ~DREF_SSC_SOURCE_MASK;
+ temp |= DREF_SSC_SOURCE_ENABLE;
+ I915_WRITE(PCH_DREF_CONTROL, temp);
+
+ POSTING_READ(PCH_DREF_CONTROL);
+ udelay(200);
+
+ if (has_edp_encoder) {
+ if (intel_panel_use_ssc(dev_priv)) {
+ temp |= DREF_SSC1_ENABLE;
+ I915_WRITE(PCH_DREF_CONTROL, temp);
+
+ POSTING_READ(PCH_DREF_CONTROL);
+ udelay(200);
+ }
+ temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
+
+ /* Enable CPU source on CPU attached eDP */
+ if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+ if (intel_panel_use_ssc(dev_priv))
+ temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
+ else
+ temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
+ } else {
+ /* Enable SSC on PCH eDP if needed */
+ if (intel_panel_use_ssc(dev_priv)) {
+ DRM_ERROR("enabling SSC on PCH\n");
+ temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
+ }
+ }
+ I915_WRITE(PCH_DREF_CONTROL, temp);
+ POSTING_READ(PCH_DREF_CONTROL);
+ udelay(200);
+ }
+
+ fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
+ if (has_reduced_clock)
+ fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 |
+ reduced_clock.m2;
+
+ /* Enable autotuning of the PLL clock (if permissible) */
+ factor = 21;
+ if (is_lvds) {
+ if ((intel_panel_use_ssc(dev_priv) &&
+ dev_priv->lvds_ssc_freq == 100) ||
+ (I915_READ(PCH_LVDS) & LVDS_CLKB_POWER_MASK) == LVDS_CLKB_POWER_UP)
+ factor = 25;
+ } else if (is_sdvo && is_tv)
+ factor = 20;
+
+ if (clock.m1 < factor * clock.n)
+ fp |= FP_CB_TUNE;
+
+ dpll = 0;
+
+ if (is_lvds)
+ dpll |= DPLLB_MODE_LVDS;
+ else
+ dpll |= DPLLB_MODE_DAC_SERIAL;
+ if (is_sdvo) {
+ int pixel_multiplier = intel_mode_get_pixel_multiplier(adjusted_mode);
+ if (pixel_multiplier > 1) {
+ dpll |= (pixel_multiplier - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
+ }
+ dpll |= DPLL_DVO_HIGH_SPEED;
+ }
+ if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base))
+ dpll |= DPLL_DVO_HIGH_SPEED;
+
+ /* compute bitmask from p1 value */
+ dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
+ /* also FPA1 */
+ dpll |= (1 << (clock.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
+
+ switch (clock.p2) {
+ case 5:
+ dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
+ break;
+ case 7:
+ dpll |= DPLLB_LVDS_P2_CLOCK_DIV_7;
+ break;
+ case 10:
+ dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_10;
+ break;
+ case 14:
+ dpll |= DPLLB_LVDS_P2_CLOCK_DIV_14;
+ break;
+ }
+
+ if (is_sdvo && is_tv)
+ dpll |= PLL_REF_INPUT_TVCLKINBC;
+ else if (is_tv)
+ /* XXX: just matching BIOS for now */
+ /* dpll |= PLL_REF_INPUT_TVCLKINBC; */
+ dpll |= 3;
+ else if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2)
+ dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
+ else
+ dpll |= PLL_REF_INPUT_DREFCLK;
+
+ /* setup pipeconf */
+ pipeconf = I915_READ(PIPECONF(pipe));
+
+ /* Set up the display plane register */
+ dspcntr = DISPPLANE_GAMMA_ENABLE;
+
+ DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
+ drm_mode_debug_printmodeline(mode);
+
/* PCH eDP needs FDI, but CPU eDP does not */
if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
- I915_WRITE(fp_reg, fp);
- I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE);
+ I915_WRITE(PCH_FP0(pipe), fp);
+ I915_WRITE(PCH_DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);
- POSTING_READ(dpll_reg);
+ POSTING_READ(PCH_DPLL(pipe));
udelay(150);
}
@@ -4964,11 +5108,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
* things on.
*/
if (is_lvds) {
- reg = LVDS;
- if (HAS_PCH_SPLIT(dev))
- reg = PCH_LVDS;
-
- temp = I915_READ(reg);
+ temp = I915_READ(PCH_LVDS);
temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
if (pipe == 1) {
if (HAS_PCH_CPT(dev))
@@ -4995,13 +5135,6 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
* appropriately here, but we need to look more thoroughly into how
* panels behave in the two modes.
*/
- /* set the dithering flag on non-PCH LVDS as needed */
- if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
- if (dev_priv->lvds_dither)
- temp |= LVDS_ENABLE_DITHER;
- else
- temp &= ~LVDS_ENABLE_DITHER;
- }
if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
lvds_sync |= LVDS_HSYNC_POLARITY;
if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
@@ -5018,22 +5151,20 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
temp |= lvds_sync;
}
- I915_WRITE(reg, temp);
+ I915_WRITE(PCH_LVDS, temp);
}
/* set the dithering flag and clear for anything other than a panel. */
- if (HAS_PCH_SPLIT(dev)) {
- pipeconf &= ~PIPECONF_DITHER_EN;
- pipeconf &= ~PIPECONF_DITHER_TYPE_MASK;
- if (dev_priv->lvds_dither && (is_lvds || has_edp_encoder)) {
- pipeconf |= PIPECONF_DITHER_EN;
- pipeconf |= PIPECONF_DITHER_TYPE_ST1;
- }
+ pipeconf &= ~PIPECONF_DITHER_EN;
+ pipeconf &= ~PIPECONF_DITHER_TYPE_MASK;
+ if (dev_priv->lvds_dither && (is_lvds || has_edp_encoder)) {
+ pipeconf |= PIPECONF_DITHER_EN;
+ pipeconf |= PIPECONF_DITHER_TYPE_ST1;
}
if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
intel_dp_set_m_n(crtc, mode, adjusted_mode);
- } else if (HAS_PCH_SPLIT(dev)) {
+ } else {
/* For non-DP output, clear any trans DP clock recovery setting.*/
I915_WRITE(TRANSDATA_M1(pipe), 0);
I915_WRITE(TRANSDATA_N1(pipe), 0);
@@ -5041,43 +5172,32 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
I915_WRITE(TRANSDPLINK_N1(pipe), 0);
}
- if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
- I915_WRITE(dpll_reg, dpll);
+ if (!has_edp_encoder ||
+ intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+ I915_WRITE(PCH_DPLL(pipe), dpll);
/* Wait for the clocks to stabilize. */
- POSTING_READ(dpll_reg);
+ POSTING_READ(PCH_DPLL(pipe));
udelay(150);
- if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev)) {
- temp = 0;
- if (is_sdvo) {
- temp = intel_mode_get_pixel_multiplier(adjusted_mode);
- if (temp > 1)
- temp = (temp - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT;
- else
- temp = 0;
- }
- I915_WRITE(DPLL_MD(pipe), temp);
- } else {
- /* The pixel multiplier can only be updated once the
- * DPLL is enabled and the clocks are stable.
- *
- * So write it again.
- */
- I915_WRITE(dpll_reg, dpll);
- }
+ /* The pixel multiplier can only be updated once the
+ * DPLL is enabled and the clocks are stable.
+ *
+ * So write it again.
+ */
+ I915_WRITE(PCH_DPLL(pipe), dpll);
}
intel_crtc->lowfreq_avail = false;
if (is_lvds && has_reduced_clock && i915_powersave) {
- I915_WRITE(fp_reg + 4, fp2);
+ I915_WRITE(PCH_FP1(pipe), fp2);
intel_crtc->lowfreq_avail = true;
if (HAS_PIPE_CXSR(dev)) {
DRM_DEBUG_KMS("enabling CxSR downclocking\n");
pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
}
} else {
- I915_WRITE(fp_reg + 4, fp);
+ I915_WRITE(PCH_FP1(pipe), fp);
if (HAS_PIPE_CXSR(dev)) {
DRM_DEBUG_KMS("disabling CxSR downclocking\n");
pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
@@ -5116,33 +5236,24 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
(adjusted_mode->crtc_vsync_start - 1) |
((adjusted_mode->crtc_vsync_end - 1) << 16));
- /* pipesrc and dspsize control the size that is scaled from,
- * which should always be the user's requested size.
+ /* pipesrc controls the size that is scaled from, which should
+ * always be the user's requested size.
*/
- if (!HAS_PCH_SPLIT(dev)) {
- I915_WRITE(DSPSIZE(plane),
- ((mode->vdisplay - 1) << 16) |
- (mode->hdisplay - 1));
- I915_WRITE(DSPPOS(plane), 0);
- }
I915_WRITE(PIPESRC(pipe),
((mode->hdisplay - 1) << 16) | (mode->vdisplay - 1));
- if (HAS_PCH_SPLIT(dev)) {
- I915_WRITE(PIPE_DATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m);
- I915_WRITE(PIPE_DATA_N1(pipe), m_n.gmch_n);
- I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m);
- I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n);
+ I915_WRITE(PIPE_DATA_M1(pipe), TU_SIZE(m_n.tu) | m_n.gmch_m);
+ I915_WRITE(PIPE_DATA_N1(pipe), m_n.gmch_n);
+ I915_WRITE(PIPE_LINK_M1(pipe), m_n.link_m);
+ I915_WRITE(PIPE_LINK_N1(pipe), m_n.link_n);
- if (has_edp_encoder && !intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
- ironlake_set_pll_edp(crtc, adjusted_mode->clock);
- }
+ if (has_edp_encoder &&
+ !intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+ ironlake_set_pll_edp(crtc, adjusted_mode->clock);
}
I915_WRITE(PIPECONF(pipe), pipeconf);
POSTING_READ(PIPECONF(pipe));
- if (!HAS_PCH_SPLIT(dev))
- intel_enable_pipe(dev_priv, pipe, false);
intel_wait_for_vblank(dev, pipe);
@@ -5161,6 +5272,26 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
intel_update_watermarks(dev);
+ return ret;
+}
+
+static int intel_crtc_mode_set(struct drm_crtc *crtc,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode,
+ int x, int y,
+ struct drm_framebuffer *old_fb)
+{
+ 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 ret;
+
+ drm_vblank_pre_modeset(dev, pipe);
+
+ ret = dev_priv->display.crtc_mode_set(crtc, mode, adjusted_mode,
+ x, y, old_fb);
+
drm_vblank_post_modeset(dev, pipe);
return ret;
@@ -5483,43 +5614,140 @@ static struct drm_display_mode load_detect_mode = {
704, 832, 0, 480, 489, 491, 520, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
};
-struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
- struct drm_connector *connector,
- struct drm_display_mode *mode,
- int *dpms_mode)
+static struct drm_framebuffer *
+intel_framebuffer_create(struct drm_device *dev,
+ struct drm_mode_fb_cmd *mode_cmd,
+ struct drm_i915_gem_object *obj)
+{
+ struct intel_framebuffer *intel_fb;
+ int ret;
+
+ intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
+ if (!intel_fb) {
+ drm_gem_object_unreference_unlocked(&obj->base);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj);
+ if (ret) {
+ drm_gem_object_unreference_unlocked(&obj->base);
+ kfree(intel_fb);
+ return ERR_PTR(ret);
+ }
+
+ return &intel_fb->base;
+}
+
+static u32
+intel_framebuffer_pitch_for_width(int width, int bpp)
+{
+ u32 pitch = DIV_ROUND_UP(width * bpp, 8);
+ return ALIGN(pitch, 64);
+}
+
+static u32
+intel_framebuffer_size_for_mode(struct drm_display_mode *mode, int bpp)
+{
+ u32 pitch = intel_framebuffer_pitch_for_width(mode->hdisplay, bpp);
+ return ALIGN(pitch * mode->vdisplay, PAGE_SIZE);
+}
+
+static struct drm_framebuffer *
+intel_framebuffer_create_for_mode(struct drm_device *dev,
+ struct drm_display_mode *mode,
+ int depth, int bpp)
+{
+ struct drm_i915_gem_object *obj;
+ struct drm_mode_fb_cmd mode_cmd;
+
+ obj = i915_gem_alloc_object(dev,
+ intel_framebuffer_size_for_mode(mode, bpp));
+ if (obj == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ mode_cmd.width = mode->hdisplay;
+ mode_cmd.height = mode->vdisplay;
+ mode_cmd.depth = depth;
+ mode_cmd.bpp = bpp;
+ mode_cmd.pitch = intel_framebuffer_pitch_for_width(mode_cmd.width, bpp);
+
+ return intel_framebuffer_create(dev, &mode_cmd, obj);
+}
+
+static struct drm_framebuffer *
+mode_fits_in_fbdev(struct drm_device *dev,
+ struct drm_display_mode *mode)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_gem_object *obj;
+ struct drm_framebuffer *fb;
+
+ if (dev_priv->fbdev == NULL)
+ return NULL;
+
+ obj = dev_priv->fbdev->ifb.obj;
+ if (obj == NULL)
+ return NULL;
+
+ fb = &dev_priv->fbdev->ifb.base;
+ if (fb->pitch < intel_framebuffer_pitch_for_width(mode->hdisplay,
+ fb->bits_per_pixel))
+ return NULL;
+
+ if (obj->base.size < mode->vdisplay * fb->pitch)
+ return NULL;
+
+ return fb;
+}
+
+bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
+ struct drm_connector *connector,
+ struct drm_display_mode *mode,
+ struct intel_load_detect_pipe *old)
{
struct intel_crtc *intel_crtc;
struct drm_crtc *possible_crtc;
- struct drm_crtc *supported_crtc =NULL;
struct drm_encoder *encoder = &intel_encoder->base;
struct drm_crtc *crtc = NULL;
struct drm_device *dev = encoder->dev;
- struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
- struct drm_crtc_helper_funcs *crtc_funcs;
+ struct drm_framebuffer *old_fb;
int i = -1;
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
+ connector->base.id, drm_get_connector_name(connector),
+ encoder->base.id, drm_get_encoder_name(encoder));
+
/*
* Algorithm gets a little messy:
+ *
* - if the connector already has an assigned crtc, use it (but make
* sure it's on first)
+ *
* - try to find the first unused crtc that can drive this connector,
* and use that if we find one
- * - if there are no unused crtcs available, try to use the first
- * one we found that supports the connector
*/
/* See if we already have a CRTC for this connector */
if (encoder->crtc) {
crtc = encoder->crtc;
- /* Make sure the crtc and connector are running */
+
intel_crtc = to_intel_crtc(crtc);
- *dpms_mode = intel_crtc->dpms_mode;
+ old->dpms_mode = intel_crtc->dpms_mode;
+ old->load_detect_temp = false;
+
+ /* Make sure the crtc and connector are running */
if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) {
+ struct drm_encoder_helper_funcs *encoder_funcs;
+ struct drm_crtc_helper_funcs *crtc_funcs;
+
crtc_funcs = crtc->helper_private;
crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
+
+ encoder_funcs = encoder->helper_private;
encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
}
- return crtc;
+
+ return true;
}
/* Find an unused one (if possible) */
@@ -5531,46 +5759,66 @@ struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
crtc = possible_crtc;
break;
}
- if (!supported_crtc)
- supported_crtc = possible_crtc;
}
/*
* If we didn't find an unused CRTC, don't use any.
*/
if (!crtc) {
- return NULL;
+ DRM_DEBUG_KMS("no pipe available for load-detect\n");
+ return false;
}
encoder->crtc = crtc;
connector->encoder = encoder;
- intel_encoder->load_detect_temp = true;
intel_crtc = to_intel_crtc(crtc);
- *dpms_mode = intel_crtc->dpms_mode;
+ old->dpms_mode = intel_crtc->dpms_mode;
+ old->load_detect_temp = true;
+ old->release_fb = NULL;
- if (!crtc->enabled) {
- if (!mode)
- mode = &load_detect_mode;
- drm_crtc_helper_set_mode(crtc, mode, 0, 0, crtc->fb);
- } else {
- if (intel_crtc->dpms_mode != DRM_MODE_DPMS_ON) {
- crtc_funcs = crtc->helper_private;
- crtc_funcs->dpms(crtc, DRM_MODE_DPMS_ON);
- }
+ if (!mode)
+ mode = &load_detect_mode;
- /* Add this connector to the crtc */
- encoder_funcs->mode_set(encoder, &crtc->mode, &crtc->mode);
- encoder_funcs->commit(encoder);
+ old_fb = crtc->fb;
+
+ /* We need a framebuffer large enough to accommodate all accesses
+ * that the plane may generate whilst we perform load detection.
+ * We can not rely on the fbcon either being present (we get called
+ * during its initialisation to detect all boot displays, or it may
+ * not even exist) or that it is large enough to satisfy the
+ * requested mode.
+ */
+ crtc->fb = mode_fits_in_fbdev(dev, mode);
+ if (crtc->fb == NULL) {
+ DRM_DEBUG_KMS("creating tmp fb for load-detection\n");
+ crtc->fb = intel_framebuffer_create_for_mode(dev, mode, 24, 32);
+ old->release_fb = crtc->fb;
+ } else
+ DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n");
+ if (IS_ERR(crtc->fb)) {
+ DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n");
+ crtc->fb = old_fb;
+ return false;
+ }
+
+ if (!drm_crtc_helper_set_mode(crtc, mode, 0, 0, old_fb)) {
+ DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n");
+ if (old->release_fb)
+ old->release_fb->funcs->destroy(old->release_fb);
+ crtc->fb = old_fb;
+ return false;
}
+
/* let the connector get through one full cycle before testing */
intel_wait_for_vblank(dev, intel_crtc->pipe);
- return crtc;
+ return true;
}
void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
- struct drm_connector *connector, int dpms_mode)
+ struct drm_connector *connector,
+ struct intel_load_detect_pipe *old)
{
struct drm_encoder *encoder = &intel_encoder->base;
struct drm_device *dev = encoder->dev;
@@ -5578,19 +5826,24 @@ void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
- if (intel_encoder->load_detect_temp) {
- encoder->crtc = NULL;
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
+ connector->base.id, drm_get_connector_name(connector),
+ encoder->base.id, drm_get_encoder_name(encoder));
+
+ if (old->load_detect_temp) {
connector->encoder = NULL;
- intel_encoder->load_detect_temp = false;
- crtc->enabled = drm_helper_crtc_in_use(crtc);
drm_helper_disable_unused_functions(dev);
+
+ if (old->release_fb)
+ old->release_fb->funcs->destroy(old->release_fb);
+
+ return;
}
/* Switch crtc and encoder back off if necessary */
- if (crtc->enabled && dpms_mode != DRM_MODE_DPMS_ON) {
- if (encoder->crtc == crtc)
- encoder_funcs->dpms(encoder, dpms_mode);
- crtc_funcs->dpms(crtc, dpms_mode);
+ if (old->dpms_mode != DRM_MODE_DPMS_ON) {
+ encoder_funcs->dpms(encoder, old->dpms_mode);
+ crtc_funcs->dpms(crtc, old->dpms_mode);
}
}
@@ -6185,6 +6438,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
break;
case 6:
+ case 7:
OUT_RING(MI_DISPLAY_FLIP |
MI_DISPLAY_FLIP_PLANE(intel_crtc->plane));
OUT_RING(fb->pitch | obj->tiling_mode);
@@ -6504,6 +6758,9 @@ static void intel_setup_outputs(struct drm_device *dev)
}
intel_panel_setup_backlight(dev);
+
+ /* disable all the possible outputs/crtcs before entering KMS mode */
+ drm_helper_disable_unused_functions(dev);
}
static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
@@ -6571,27 +6828,12 @@ intel_user_framebuffer_create(struct drm_device *dev,
struct drm_mode_fb_cmd *mode_cmd)
{
struct drm_i915_gem_object *obj;
- struct intel_framebuffer *intel_fb;
- int ret;
obj = to_intel_bo(drm_gem_object_lookup(dev, filp, mode_cmd->handle));
if (&obj->base == NULL)
return ERR_PTR(-ENOENT);
- intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
- if (!intel_fb) {
- drm_gem_object_unreference_unlocked(&obj->base);
- return ERR_PTR(-ENOMEM);
- }
-
- ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj);
- if (ret) {
- drm_gem_object_unreference_unlocked(&obj->base);
- kfree(intel_fb);
- return ERR_PTR(ret);
- }
-
- return &intel_fb->base;
+ return intel_framebuffer_create(dev, mode_cmd, obj);
}
static const struct drm_mode_config_funcs intel_mode_funcs = {
@@ -6605,13 +6847,14 @@ intel_alloc_context_page(struct drm_device *dev)
struct drm_i915_gem_object *ctx;
int ret;
+ WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
ctx = i915_gem_alloc_object(dev, 4096);
if (!ctx) {
DRM_DEBUG("failed to alloc power context, RC6 disabled\n");
return NULL;
}
- mutex_lock(&dev->struct_mutex);
ret = i915_gem_object_pin(ctx, 4096, true);
if (ret) {
DRM_ERROR("failed to pin power context: %d\n", ret);
@@ -6623,7 +6866,6 @@ intel_alloc_context_page(struct drm_device *dev)
DRM_ERROR("failed to set-domain on power context: %d\n", ret);
goto err_unpin;
}
- mutex_unlock(&dev->struct_mutex);
return ctx;
@@ -6758,6 +7000,11 @@ void gen6_disable_rps(struct drm_device *dev)
I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
I915_WRITE(GEN6_PMIER, 0);
+
+ spin_lock_irq(&dev_priv->rps_lock);
+ dev_priv->pm_iir = 0;
+ spin_unlock_irq(&dev_priv->rps_lock);
+
I915_WRITE(GEN6_PMIIR, I915_READ(GEN6_PMIIR));
}
@@ -6851,7 +7098,7 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
{
u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
- u32 pcu_mbox;
+ u32 pcu_mbox, rc6_mask = 0;
int cur_freq, min_freq, max_freq;
int i;
@@ -6862,7 +7109,8 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
* userspace...
*/
I915_WRITE(GEN6_RC_STATE, 0);
- __gen6_gt_force_wake_get(dev_priv);
+ mutex_lock(&dev_priv->dev->struct_mutex);
+ gen6_gt_force_wake_get(dev_priv);
/* disable the counters and set deterministic thresholds */
I915_WRITE(GEN6_RC_CONTROL, 0);
@@ -6882,9 +7130,12 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
I915_WRITE(GEN6_RC6p_THRESHOLD, 100000);
I915_WRITE(GEN6_RC6pp_THRESHOLD, 64000); /* unused */
+ if (i915_enable_rc6)
+ rc6_mask = GEN6_RC_CTL_RC6p_ENABLE |
+ GEN6_RC_CTL_RC6_ENABLE;
+
I915_WRITE(GEN6_RC_CONTROL,
- GEN6_RC_CTL_RC6p_ENABLE |
- GEN6_RC_CTL_RC6_ENABLE |
+ rc6_mask |
GEN6_RC_CTL_EI_MODE(1) |
GEN6_RC_CTL_HW_ENABLE);
@@ -6956,168 +7207,237 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
GEN6_PM_RP_DOWN_THRESHOLD |
GEN6_PM_RP_UP_EI_EXPIRED |
GEN6_PM_RP_DOWN_EI_EXPIRED);
+ spin_lock_irq(&dev_priv->rps_lock);
+ WARN_ON(dev_priv->pm_iir != 0);
I915_WRITE(GEN6_PMIMR, 0);
+ spin_unlock_irq(&dev_priv->rps_lock);
/* enable all PM interrupts */
I915_WRITE(GEN6_PMINTRMSK, 0);
- __gen6_gt_force_wake_put(dev_priv);
+ gen6_gt_force_wake_put(dev_priv);
+ mutex_unlock(&dev_priv->dev->struct_mutex);
}
-void intel_enable_clock_gating(struct drm_device *dev)
+static void ironlake_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
+
+ /* Required for FBC */
+ dspclk_gate |= DPFCUNIT_CLOCK_GATE_DISABLE |
+ DPFCRUNIT_CLOCK_GATE_DISABLE |
+ DPFDUNIT_CLOCK_GATE_DISABLE;
+ /* Required for CxSR */
+ dspclk_gate |= DPARBUNIT_CLOCK_GATE_DISABLE;
+
+ I915_WRITE(PCH_3DCGDIS0,
+ MARIUNIT_CLOCK_GATE_DISABLE |
+ SVSMUNIT_CLOCK_GATE_DISABLE);
+ I915_WRITE(PCH_3DCGDIS1,
+ VFMUNIT_CLOCK_GATE_DISABLE);
+
+ I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
+
+ /*
+ * According to the spec the following bits should be set in
+ * order to enable memory self-refresh
+ * The bit 22/21 of 0x42004
+ * The bit 5 of 0x42020
+ * The bit 15 of 0x45000
+ */
+ I915_WRITE(ILK_DISPLAY_CHICKEN2,
+ (I915_READ(ILK_DISPLAY_CHICKEN2) |
+ ILK_DPARB_GATE | ILK_VSDPFD_FULL));
+ I915_WRITE(ILK_DSPCLK_GATE,
+ (I915_READ(ILK_DSPCLK_GATE) |
+ ILK_DPARB_CLK_GATE));
+ I915_WRITE(DISP_ARB_CTL,
+ (I915_READ(DISP_ARB_CTL) |
+ DISP_FBC_WM_DIS));
+ I915_WRITE(WM3_LP_ILK, 0);
+ I915_WRITE(WM2_LP_ILK, 0);
+ I915_WRITE(WM1_LP_ILK, 0);
+
+ /*
+ * 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);
+ }
+
+ I915_WRITE(ILK_DISPLAY_CHICKEN2,
+ I915_READ(ILK_DISPLAY_CHICKEN2) |
+ ILK_ELPIN_409_SELECT);
+ I915_WRITE(_3D_CHICKEN2,
+ _3D_CHICKEN2_WM_READ_PIPELINED << 16 |
+ _3D_CHICKEN2_WM_READ_PIPELINED);
+}
+
+static void gen6_init_clock_gating(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
int pipe;
+ uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
+
+ I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
+
+ I915_WRITE(ILK_DISPLAY_CHICKEN2,
+ I915_READ(ILK_DISPLAY_CHICKEN2) |
+ ILK_ELPIN_409_SELECT);
+
+ I915_WRITE(WM3_LP_ILK, 0);
+ I915_WRITE(WM2_LP_ILK, 0);
+ I915_WRITE(WM1_LP_ILK, 0);
/*
- * Disable clock gating reported to work incorrectly according to the
- * specs, but enable as much else as we can.
+ * According to the spec the following bits should be
+ * set in order to enable memory self-refresh and fbc:
+ * The bit21 and bit22 of 0x42000
+ * The bit21 and bit22 of 0x42004
+ * The bit5 and bit7 of 0x42020
+ * The bit14 of 0x70180
+ * The bit14 of 0x71180
*/
- if (HAS_PCH_SPLIT(dev)) {
- uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
+ I915_WRITE(ILK_DISPLAY_CHICKEN1,
+ I915_READ(ILK_DISPLAY_CHICKEN1) |
+ ILK_FBCQ_DIS | ILK_PABSTRETCH_DIS);
+ I915_WRITE(ILK_DISPLAY_CHICKEN2,
+ I915_READ(ILK_DISPLAY_CHICKEN2) |
+ ILK_DPARB_GATE | ILK_VSDPFD_FULL);
+ I915_WRITE(ILK_DSPCLK_GATE,
+ I915_READ(ILK_DSPCLK_GATE) |
+ ILK_DPARB_CLK_GATE |
+ ILK_DPFD_CLK_GATE);
- if (IS_GEN5(dev)) {
- /* Required for FBC */
- dspclk_gate |= DPFCUNIT_CLOCK_GATE_DISABLE |
- DPFCRUNIT_CLOCK_GATE_DISABLE |
- DPFDUNIT_CLOCK_GATE_DISABLE;
- /* Required for CxSR */
- dspclk_gate |= DPARBUNIT_CLOCK_GATE_DISABLE;
-
- I915_WRITE(PCH_3DCGDIS0,
- MARIUNIT_CLOCK_GATE_DISABLE |
- SVSMUNIT_CLOCK_GATE_DISABLE);
- I915_WRITE(PCH_3DCGDIS1,
- VFMUNIT_CLOCK_GATE_DISABLE);
- }
+ for_each_pipe(pipe)
+ I915_WRITE(DSPCNTR(pipe),
+ I915_READ(DSPCNTR(pipe)) |
+ DISPPLANE_TRICKLE_FEED_DISABLE);
+}
- I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
+static void ivybridge_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int pipe;
+ uint32_t dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE;
- /*
- * On Ibex Peak and Cougar Point, we need to disable clock
- * gating for the panel power sequencer or it will fail to
- * start up when no ports are active.
- */
- I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
+ I915_WRITE(PCH_DSPCLK_GATE_D, dspclk_gate);
- /*
- * According to the spec the following bits should be set in
- * order to enable memory self-refresh
- * The bit 22/21 of 0x42004
- * The bit 5 of 0x42020
- * The bit 15 of 0x45000
- */
- if (IS_GEN5(dev)) {
- I915_WRITE(ILK_DISPLAY_CHICKEN2,
- (I915_READ(ILK_DISPLAY_CHICKEN2) |
- ILK_DPARB_GATE | ILK_VSDPFD_FULL));
- I915_WRITE(ILK_DSPCLK_GATE,
- (I915_READ(ILK_DSPCLK_GATE) |
- ILK_DPARB_CLK_GATE));
- I915_WRITE(DISP_ARB_CTL,
- (I915_READ(DISP_ARB_CTL) |
- DISP_FBC_WM_DIS));
- I915_WRITE(WM3_LP_ILK, 0);
- I915_WRITE(WM2_LP_ILK, 0);
- I915_WRITE(WM1_LP_ILK, 0);
- }
- /*
- * 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);
- }
+ I915_WRITE(WM3_LP_ILK, 0);
+ I915_WRITE(WM2_LP_ILK, 0);
+ I915_WRITE(WM1_LP_ILK, 0);
- I915_WRITE(ILK_DISPLAY_CHICKEN2,
- I915_READ(ILK_DISPLAY_CHICKEN2) |
- ILK_ELPIN_409_SELECT);
+ I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE);
- if (IS_GEN5(dev)) {
- I915_WRITE(_3D_CHICKEN2,
- _3D_CHICKEN2_WM_READ_PIPELINED << 16 |
- _3D_CHICKEN2_WM_READ_PIPELINED);
- }
+ for_each_pipe(pipe)
+ I915_WRITE(DSPCNTR(pipe),
+ I915_READ(DSPCNTR(pipe)) |
+ DISPPLANE_TRICKLE_FEED_DISABLE);
+}
- if (IS_GEN6(dev)) {
- I915_WRITE(WM3_LP_ILK, 0);
- I915_WRITE(WM2_LP_ILK, 0);
- I915_WRITE(WM1_LP_ILK, 0);
+static void g4x_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t dspclk_gate;
- /*
- * According to the spec the following bits should be
- * set in order to enable memory self-refresh and fbc:
- * The bit21 and bit22 of 0x42000
- * The bit21 and bit22 of 0x42004
- * The bit5 and bit7 of 0x42020
- * The bit14 of 0x70180
- * The bit14 of 0x71180
- */
- I915_WRITE(ILK_DISPLAY_CHICKEN1,
- I915_READ(ILK_DISPLAY_CHICKEN1) |
- ILK_FBCQ_DIS | ILK_PABSTRETCH_DIS);
- I915_WRITE(ILK_DISPLAY_CHICKEN2,
- I915_READ(ILK_DISPLAY_CHICKEN2) |
- ILK_DPARB_GATE | ILK_VSDPFD_FULL);
- I915_WRITE(ILK_DSPCLK_GATE,
- I915_READ(ILK_DSPCLK_GATE) |
- ILK_DPARB_CLK_GATE |
- ILK_DPFD_CLK_GATE);
-
- for_each_pipe(pipe)
- I915_WRITE(DSPCNTR(pipe),
- I915_READ(DSPCNTR(pipe)) |
- DISPPLANE_TRICKLE_FEED_DISABLE);
- }
- } else if (IS_G4X(dev)) {
- uint32_t dspclk_gate;
- I915_WRITE(RENCLK_GATE_D1, 0);
- I915_WRITE(RENCLK_GATE_D2, VF_UNIT_CLOCK_GATE_DISABLE |
- GS_UNIT_CLOCK_GATE_DISABLE |
- CL_UNIT_CLOCK_GATE_DISABLE);
- I915_WRITE(RAMCLK_GATE_D, 0);
- dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE |
- OVRUNIT_CLOCK_GATE_DISABLE |
- OVCUNIT_CLOCK_GATE_DISABLE;
- if (IS_GM45(dev))
- dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE;
- I915_WRITE(DSPCLK_GATE_D, dspclk_gate);
- } else if (IS_CRESTLINE(dev)) {
- I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE);
- I915_WRITE(RENCLK_GATE_D2, 0);
- I915_WRITE(DSPCLK_GATE_D, 0);
- I915_WRITE(RAMCLK_GATE_D, 0);
- I915_WRITE16(DEUC, 0);
- } else if (IS_BROADWATER(dev)) {
- I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE |
- I965_RCC_CLOCK_GATE_DISABLE |
- I965_RCPB_CLOCK_GATE_DISABLE |
- I965_ISC_CLOCK_GATE_DISABLE |
- I965_FBC_CLOCK_GATE_DISABLE);
- I915_WRITE(RENCLK_GATE_D2, 0);
- } else if (IS_GEN3(dev)) {
- u32 dstate = I915_READ(D_STATE);
+ I915_WRITE(RENCLK_GATE_D1, 0);
+ I915_WRITE(RENCLK_GATE_D2, VF_UNIT_CLOCK_GATE_DISABLE |
+ GS_UNIT_CLOCK_GATE_DISABLE |
+ CL_UNIT_CLOCK_GATE_DISABLE);
+ I915_WRITE(RAMCLK_GATE_D, 0);
+ dspclk_gate = VRHUNIT_CLOCK_GATE_DISABLE |
+ OVRUNIT_CLOCK_GATE_DISABLE |
+ OVCUNIT_CLOCK_GATE_DISABLE;
+ if (IS_GM45(dev))
+ dspclk_gate |= DSSUNIT_CLOCK_GATE_DISABLE;
+ I915_WRITE(DSPCLK_GATE_D, dspclk_gate);
+}
- dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING |
- DSTATE_DOT_CLOCK_GATING;
- I915_WRITE(D_STATE, dstate);
- } else if (IS_I85X(dev) || IS_I865G(dev)) {
- I915_WRITE(RENCLK_GATE_D1, SV_CLOCK_GATE_DISABLE);
- } else if (IS_I830(dev)) {
- I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE);
- }
+static void crestline_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE);
+ I915_WRITE(RENCLK_GATE_D2, 0);
+ I915_WRITE(DSPCLK_GATE_D, 0);
+ I915_WRITE(RAMCLK_GATE_D, 0);
+ I915_WRITE16(DEUC, 0);
+}
+
+static void broadwater_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE |
+ I965_RCC_CLOCK_GATE_DISABLE |
+ I965_RCPB_CLOCK_GATE_DISABLE |
+ I965_ISC_CLOCK_GATE_DISABLE |
+ I965_FBC_CLOCK_GATE_DISABLE);
+ I915_WRITE(RENCLK_GATE_D2, 0);
+}
+
+static void gen3_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 dstate = I915_READ(D_STATE);
+
+ dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING |
+ DSTATE_DOT_CLOCK_GATING;
+ I915_WRITE(D_STATE, dstate);
+}
+
+static void i85x_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ I915_WRITE(RENCLK_GATE_D1, SV_CLOCK_GATE_DISABLE);
+}
+
+static void i830_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE);
+}
+
+static void ibx_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ /*
+ * On Ibex Peak and Cougar Point, we need to disable clock
+ * gating for the panel power sequencer or it will fail to
+ * start up when no ports are active.
+ */
+ I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
+}
+
+static void cpt_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ /*
+ * On Ibex Peak and Cougar Point, we need to disable clock
+ * gating for the panel power sequencer or it will fail to
+ * start up when no ports are active.
+ */
+ I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
+ I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) |
+ DPLS_EDP_PPS_FIX_DIS);
}
static void ironlake_teardown_rc6(struct drm_device *dev)
@@ -7187,9 +7507,12 @@ void ironlake_enable_rc6(struct drm_device *dev)
if (!i915_enable_rc6)
return;
+ mutex_lock(&dev->struct_mutex);
ret = ironlake_setup_rc6(dev);
- if (ret)
+ if (ret) {
+ mutex_unlock(&dev->struct_mutex);
return;
+ }
/*
* GPU can automatically power down the render unit if given a page
@@ -7198,6 +7521,7 @@ void ironlake_enable_rc6(struct drm_device *dev)
ret = BEGIN_LP_RING(6);
if (ret) {
ironlake_teardown_rc6(dev);
+ mutex_unlock(&dev->struct_mutex);
return;
}
@@ -7213,10 +7537,33 @@ void ironlake_enable_rc6(struct drm_device *dev)
OUT_RING(MI_FLUSH);
ADVANCE_LP_RING();
+ /*
+ * Wait for the command parser to advance past MI_SET_CONTEXT. The HW
+ * does an implicit flush, combined with MI_FLUSH above, it should be
+ * safe to assume that renderctx is valid
+ */
+ ret = intel_wait_ring_idle(LP_RING(dev_priv));
+ if (ret) {
+ DRM_ERROR("failed to enable ironlake power power savings\n");
+ ironlake_teardown_rc6(dev);
+ mutex_unlock(&dev->struct_mutex);
+ return;
+ }
+
I915_WRITE(PWRCTXA, dev_priv->pwrctx->gtt_offset | PWRCTX_EN);
I915_WRITE(RSTDBYCTL, I915_READ(RSTDBYCTL) & ~RCX_SW_EXIT);
+ mutex_unlock(&dev->struct_mutex);
}
+void intel_init_clock_gating(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ dev_priv->display.init_clock_gating(dev);
+
+ if (dev_priv->display.init_pch_clock_gating)
+ dev_priv->display.init_pch_clock_gating(dev);
+}
/* Set up chip specific display functions */
static void intel_init_display(struct drm_device *dev)
@@ -7224,10 +7571,13 @@ static void intel_init_display(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
/* We always want a DPMS function */
- if (HAS_PCH_SPLIT(dev))
+ if (HAS_PCH_SPLIT(dev)) {
dev_priv->display.dpms = ironlake_crtc_dpms;
- else
+ dev_priv->display.crtc_mode_set = ironlake_crtc_mode_set;
+ } else {
dev_priv->display.dpms = i9xx_crtc_dpms;
+ dev_priv->display.crtc_mode_set = i9xx_crtc_mode_set;
+ }
if (I915_HAS_FBC(dev)) {
if (HAS_PCH_SPLIT(dev)) {
@@ -7271,6 +7621,11 @@ static void intel_init_display(struct drm_device *dev)
/* For FIFO watermark updates */
if (HAS_PCH_SPLIT(dev)) {
+ if (HAS_PCH_IBX(dev))
+ dev_priv->display.init_pch_clock_gating = ibx_init_clock_gating;
+ else if (HAS_PCH_CPT(dev))
+ dev_priv->display.init_pch_clock_gating = cpt_init_clock_gating;
+
if (IS_GEN5(dev)) {
if (I915_READ(MLTR_ILK) & ILK_SRLT_MASK)
dev_priv->display.update_wm = ironlake_update_wm;
@@ -7279,6 +7634,8 @@ static void intel_init_display(struct drm_device *dev)
"Disable CxSR\n");
dev_priv->display.update_wm = NULL;
}
+ dev_priv->display.fdi_link_train = ironlake_fdi_link_train;
+ dev_priv->display.init_clock_gating = ironlake_init_clock_gating;
} else if (IS_GEN6(dev)) {
if (SNB_READ_WM0_LATENCY()) {
dev_priv->display.update_wm = sandybridge_update_wm;
@@ -7287,6 +7644,20 @@ static void intel_init_display(struct drm_device *dev)
"Disable CxSR\n");
dev_priv->display.update_wm = NULL;
}
+ dev_priv->display.fdi_link_train = gen6_fdi_link_train;
+ dev_priv->display.init_clock_gating = gen6_init_clock_gating;
+ } else if (IS_IVYBRIDGE(dev)) {
+ /* FIXME: detect B0+ stepping and use auto training */
+ dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
+ if (SNB_READ_WM0_LATENCY()) {
+ dev_priv->display.update_wm = sandybridge_update_wm;
+ } else {
+ DRM_DEBUG_KMS("Failed to read display plane latency. "
+ "Disable CxSR\n");
+ dev_priv->display.update_wm = NULL;
+ }
+ dev_priv->display.init_clock_gating = ivybridge_init_clock_gating;
+
} else
dev_priv->display.update_wm = NULL;
} else if (IS_PINEVIEW(dev)) {
@@ -7304,18 +7675,30 @@ static void intel_init_display(struct drm_device *dev)
dev_priv->display.update_wm = NULL;
} else
dev_priv->display.update_wm = pineview_update_wm;
- } else if (IS_G4X(dev))
+ } else if (IS_G4X(dev)) {
dev_priv->display.update_wm = g4x_update_wm;
- else if (IS_GEN4(dev))
+ dev_priv->display.init_clock_gating = g4x_init_clock_gating;
+ } else if (IS_GEN4(dev)) {
dev_priv->display.update_wm = i965_update_wm;
- else if (IS_GEN3(dev)) {
+ if (IS_CRESTLINE(dev))
+ dev_priv->display.init_clock_gating = crestline_init_clock_gating;
+ else if (IS_BROADWATER(dev))
+ dev_priv->display.init_clock_gating = broadwater_init_clock_gating;
+ } else if (IS_GEN3(dev)) {
dev_priv->display.update_wm = i9xx_update_wm;
dev_priv->display.get_fifo_size = i9xx_get_fifo_size;
+ dev_priv->display.init_clock_gating = gen3_init_clock_gating;
+ } else if (IS_I865G(dev)) {
+ dev_priv->display.update_wm = i830_update_wm;
+ dev_priv->display.init_clock_gating = i85x_init_clock_gating;
+ dev_priv->display.get_fifo_size = i830_get_fifo_size;
} else if (IS_I85X(dev)) {
dev_priv->display.update_wm = i9xx_update_wm;
dev_priv->display.get_fifo_size = i85x_get_fifo_size;
+ dev_priv->display.init_clock_gating = i85x_init_clock_gating;
} else {
dev_priv->display.update_wm = i830_update_wm;
+ dev_priv->display.init_clock_gating = i830_init_clock_gating;
if (IS_845G(dev))
dev_priv->display.get_fifo_size = i845_get_fifo_size;
else
@@ -7441,12 +7824,11 @@ void intel_modeset_init(struct drm_device *dev)
intel_crtc_init(dev, i);
}
- intel_setup_outputs(dev);
-
- intel_enable_clock_gating(dev);
-
/* Just disable it once at startup */
i915_disable_vga(dev);
+ intel_setup_outputs(dev);
+
+ intel_init_clock_gating(dev);
if (IS_IRONLAKE_M(dev)) {
ironlake_enable_drps(dev);
@@ -7456,12 +7838,15 @@ void intel_modeset_init(struct drm_device *dev)
if (IS_GEN6(dev))
gen6_enable_rps(dev_priv);
- if (IS_IRONLAKE_M(dev))
- ironlake_enable_rc6(dev);
-
INIT_WORK(&dev_priv->idle_work, intel_idle_update);
setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
(unsigned long)dev);
+}
+
+void intel_modeset_gem_init(struct drm_device *dev)
+{
+ if (IS_IRONLAKE_M(dev))
+ ironlake_enable_rc6(dev);
intel_setup_overlay(dev);
}
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 1d20712d527f..831d7a4a0d18 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -140,7 +140,6 @@ struct intel_fbdev {
struct intel_encoder {
struct drm_encoder base;
int type;
- bool load_detect_temp;
bool needs_tv_clock;
void (*hot_plug)(struct intel_encoder *);
int crtc_mask;
@@ -291,13 +290,19 @@ int intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern void intel_wait_for_vblank(struct drm_device *dev, int pipe);
extern void intel_wait_for_pipe_off(struct drm_device *dev, int pipe);
-extern struct drm_crtc *intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
- struct drm_connector *connector,
- struct drm_display_mode *mode,
- int *dpms_mode);
+
+struct intel_load_detect_pipe {
+ struct drm_framebuffer *release_fb;
+ bool load_detect_temp;
+ int dpms_mode;
+};
+extern bool intel_get_load_detect_pipe(struct intel_encoder *intel_encoder,
+ struct drm_connector *connector,
+ struct drm_display_mode *mode,
+ struct intel_load_detect_pipe *old);
extern void intel_release_load_detect_pipe(struct intel_encoder *intel_encoder,
struct drm_connector *connector,
- int dpms_mode);
+ struct intel_load_detect_pipe *old);
extern struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB);
extern int intel_sdvo_supports_hotplug(struct drm_connector *connector);
@@ -339,4 +344,6 @@ extern int intel_overlay_attrs(struct drm_device *dev, void *data,
extern void intel_fb_output_poll_changed(struct drm_device *dev);
extern void intel_fb_restore_mode(struct drm_device *dev);
+
+extern void intel_init_clock_gating(struct drm_device *dev);
#endif /* __INTEL_DRV_H__ */
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index e9e6f71418a4..95c4b1429935 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -236,7 +236,7 @@ init_pipe_control(struct intel_ring_buffer *ring)
ret = -ENOMEM;
goto err;
}
- obj->agp_type = AGP_USER_CACHED_MEMORY;
+ obj->cache_level = I915_CACHE_LLC;
ret = i915_gem_object_pin(obj, 4096, true);
if (ret)
@@ -286,7 +286,7 @@ static int init_render_ring(struct intel_ring_buffer *ring)
if (INTEL_INFO(dev)->gen > 3) {
int mode = VS_TIMER_DISPATCH << 16 | VS_TIMER_DISPATCH;
- if (IS_GEN6(dev))
+ if (IS_GEN6(dev) || IS_GEN7(dev))
mode |= MI_FLUSH_ENABLE << 16 | MI_FLUSH_ENABLE;
I915_WRITE(MI_MODE, mode);
}
@@ -551,10 +551,31 @@ render_ring_put_irq(struct intel_ring_buffer *ring)
void intel_ring_setup_status_page(struct intel_ring_buffer *ring)
{
+ struct drm_device *dev = ring->dev;
drm_i915_private_t *dev_priv = ring->dev->dev_private;
- u32 mmio = IS_GEN6(ring->dev) ?
- RING_HWS_PGA_GEN6(ring->mmio_base) :
- RING_HWS_PGA(ring->mmio_base);
+ u32 mmio = 0;
+
+ /* The ring status page addresses are no longer next to the rest of
+ * the ring registers as of gen7.
+ */
+ if (IS_GEN7(dev)) {
+ switch (ring->id) {
+ case RING_RENDER:
+ mmio = RENDER_HWS_PGA_GEN7;
+ break;
+ case RING_BLT:
+ mmio = BLT_HWS_PGA_GEN7;
+ break;
+ case RING_BSD:
+ mmio = BSD_HWS_PGA_GEN7;
+ break;
+ }
+ } else if (IS_GEN6(ring->dev)) {
+ mmio = RING_HWS_PGA_GEN6(ring->mmio_base);
+ } else {
+ mmio = RING_HWS_PGA(ring->mmio_base);
+ }
+
I915_WRITE(mmio, (u32)ring->status_page.gfx_addr);
POSTING_READ(mmio);
}
@@ -600,7 +621,7 @@ ring_add_request(struct intel_ring_buffer *ring,
}
static bool
-ring_get_irq(struct intel_ring_buffer *ring, u32 flag)
+gen6_ring_get_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
{
struct drm_device *dev = ring->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
@@ -609,71 +630,67 @@ ring_get_irq(struct intel_ring_buffer *ring, u32 flag)
return false;
spin_lock(&ring->irq_lock);
- if (ring->irq_refcount++ == 0)
- ironlake_enable_irq(dev_priv, flag);
+ if (ring->irq_refcount++ == 0) {
+ ring->irq_mask &= ~rflag;
+ I915_WRITE_IMR(ring, ring->irq_mask);
+ ironlake_enable_irq(dev_priv, gflag);
+ }
spin_unlock(&ring->irq_lock);
return true;
}
static void
-ring_put_irq(struct intel_ring_buffer *ring, u32 flag)
+gen6_ring_put_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
{
struct drm_device *dev = ring->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
spin_lock(&ring->irq_lock);
- if (--ring->irq_refcount == 0)
- ironlake_disable_irq(dev_priv, flag);
+ if (--ring->irq_refcount == 0) {
+ ring->irq_mask |= rflag;
+ I915_WRITE_IMR(ring, ring->irq_mask);
+ ironlake_disable_irq(dev_priv, gflag);
+ }
spin_unlock(&ring->irq_lock);
}
static bool
-gen6_ring_get_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
+bsd_ring_get_irq(struct intel_ring_buffer *ring)
{
struct drm_device *dev = ring->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
if (!dev->irq_enabled)
- return false;
+ return false;
spin_lock(&ring->irq_lock);
if (ring->irq_refcount++ == 0) {
- ring->irq_mask &= ~rflag;
- I915_WRITE_IMR(ring, ring->irq_mask);
- ironlake_enable_irq(dev_priv, gflag);
+ if (IS_G4X(dev))
+ i915_enable_irq(dev_priv, I915_BSD_USER_INTERRUPT);
+ else
+ ironlake_enable_irq(dev_priv, GT_BSD_USER_INTERRUPT);
}
spin_unlock(&ring->irq_lock);
return true;
}
-
static void
-gen6_ring_put_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
+bsd_ring_put_irq(struct intel_ring_buffer *ring)
{
struct drm_device *dev = ring->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
spin_lock(&ring->irq_lock);
if (--ring->irq_refcount == 0) {
- ring->irq_mask |= rflag;
- I915_WRITE_IMR(ring, ring->irq_mask);
- ironlake_disable_irq(dev_priv, gflag);
+ if (IS_G4X(dev))
+ i915_disable_irq(dev_priv, I915_BSD_USER_INTERRUPT);
+ else
+ ironlake_disable_irq(dev_priv, GT_BSD_USER_INTERRUPT);
}
spin_unlock(&ring->irq_lock);
}
-static bool
-bsd_ring_get_irq(struct intel_ring_buffer *ring)
-{
- return ring_get_irq(ring, GT_BSD_USER_INTERRUPT);
-}
-static void
-bsd_ring_put_irq(struct intel_ring_buffer *ring)
-{
- ring_put_irq(ring, GT_BSD_USER_INTERRUPT);
-}
-
static int
ring_dispatch_execbuffer(struct intel_ring_buffer *ring, u32 offset, u32 length)
{
@@ -759,7 +776,7 @@ static int init_status_page(struct intel_ring_buffer *ring)
ret = -ENOMEM;
goto err;
}
- obj->agp_type = AGP_USER_CACHED_MEMORY;
+ obj->cache_level = I915_CACHE_LLC;
ret = i915_gem_object_pin(obj, 4096, true);
if (ret != 0) {
@@ -800,6 +817,7 @@ int intel_init_ring_buffer(struct drm_device *dev,
INIT_LIST_HEAD(&ring->request_list);
INIT_LIST_HEAD(&ring->gpu_write_list);
+ init_waitqueue_head(&ring->irq_queue);
spin_lock_init(&ring->irq_lock);
ring->irq_mask = ~0;
@@ -872,7 +890,7 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring)
/* Disable the ring buffer. The ring must be idle at this point */
dev_priv = ring->dev->dev_private;
- ret = intel_wait_ring_buffer(ring, ring->size - 8);
+ ret = intel_wait_ring_idle(ring);
if (ret)
DRM_ERROR("failed to quiesce %s whilst cleaning up: %d\n",
ring->name, ret);
@@ -1333,7 +1351,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev)
drm_i915_private_t *dev_priv = dev->dev_private;
struct intel_ring_buffer *ring = &dev_priv->ring[VCS];
- if (IS_GEN6(dev))
+ if (IS_GEN6(dev) || IS_GEN7(dev))
*ring = gen6_bsd_ring;
else
*ring = bsd_ring;
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index f23cc5f037a6..c0e0ee63fbf4 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -14,27 +14,24 @@ struct intel_hw_status_page {
struct drm_i915_gem_object *obj;
};
-#define I915_RING_READ(reg) i915_gt_read(dev_priv, reg)
-#define I915_RING_WRITE(reg, val) i915_gt_write(dev_priv, reg, val)
+#define I915_READ_TAIL(ring) I915_READ(RING_TAIL((ring)->mmio_base))
+#define I915_WRITE_TAIL(ring, val) I915_WRITE(RING_TAIL((ring)->mmio_base), val)
-#define I915_READ_TAIL(ring) I915_RING_READ(RING_TAIL((ring)->mmio_base))
-#define I915_WRITE_TAIL(ring, val) I915_RING_WRITE(RING_TAIL((ring)->mmio_base), val)
+#define I915_READ_START(ring) I915_READ(RING_START((ring)->mmio_base))
+#define I915_WRITE_START(ring, val) I915_WRITE(RING_START((ring)->mmio_base), val)
-#define I915_READ_START(ring) I915_RING_READ(RING_START((ring)->mmio_base))
-#define I915_WRITE_START(ring, val) I915_RING_WRITE(RING_START((ring)->mmio_base), val)
+#define I915_READ_HEAD(ring) I915_READ(RING_HEAD((ring)->mmio_base))
+#define I915_WRITE_HEAD(ring, val) I915_WRITE(RING_HEAD((ring)->mmio_base), val)
-#define I915_READ_HEAD(ring) I915_RING_READ(RING_HEAD((ring)->mmio_base))
-#define I915_WRITE_HEAD(ring, val) I915_RING_WRITE(RING_HEAD((ring)->mmio_base), val)
+#define I915_READ_CTL(ring) I915_READ(RING_CTL((ring)->mmio_base))
+#define I915_WRITE_CTL(ring, val) I915_WRITE(RING_CTL((ring)->mmio_base), val)
-#define I915_READ_CTL(ring) I915_RING_READ(RING_CTL((ring)->mmio_base))
-#define I915_WRITE_CTL(ring, val) I915_RING_WRITE(RING_CTL((ring)->mmio_base), val)
+#define I915_READ_IMR(ring) I915_READ(RING_IMR((ring)->mmio_base))
+#define I915_WRITE_IMR(ring, val) I915_WRITE(RING_IMR((ring)->mmio_base), val)
-#define I915_READ_IMR(ring) I915_RING_READ(RING_IMR((ring)->mmio_base))
-#define I915_WRITE_IMR(ring, val) I915_RING_WRITE(RING_IMR((ring)->mmio_base), val)
-
-#define I915_READ_NOPID(ring) I915_RING_READ(RING_NOPID((ring)->mmio_base))
-#define I915_READ_SYNC_0(ring) I915_RING_READ(RING_SYNC_0((ring)->mmio_base))
-#define I915_READ_SYNC_1(ring) I915_RING_READ(RING_SYNC_1((ring)->mmio_base))
+#define I915_READ_NOPID(ring) I915_READ(RING_NOPID((ring)->mmio_base))
+#define I915_READ_SYNC_0(ring) I915_READ(RING_SYNC_0((ring)->mmio_base))
+#define I915_READ_SYNC_1(ring) I915_READ(RING_SYNC_1((ring)->mmio_base))
struct intel_ring_buffer {
const char *name;
@@ -164,7 +161,13 @@ intel_read_status_page(struct intel_ring_buffer *ring,
#define I915_BREADCRUMB_INDEX 0x21
void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring);
+
int __must_check intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n);
+static inline int intel_wait_ring_idle(struct intel_ring_buffer *ring)
+{
+ return intel_wait_ring_buffer(ring, ring->space - 8);
+}
+
int __must_check intel_ring_begin(struct intel_ring_buffer *ring, int n);
static inline void intel_ring_emit(struct intel_ring_buffer *ring,
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 4324f33212d6..754086f83941 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -2544,21 +2544,19 @@ bool intel_sdvo_init(struct drm_device *dev, int sdvo_reg)
if (!intel_sdvo)
return false;
+ intel_sdvo->sdvo_reg = sdvo_reg;
+ intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg) >> 1;
+ intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo, sdvo_reg);
if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev)) {
kfree(intel_sdvo);
return false;
}
- intel_sdvo->sdvo_reg = sdvo_reg;
-
+ /* encoder type will be decided later */
intel_encoder = &intel_sdvo->base;
intel_encoder->type = INTEL_OUTPUT_SDVO;
- /* encoder type will be decided later */
drm_encoder_init(dev, &intel_encoder->base, &intel_sdvo_enc_funcs, 0);
- intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, sdvo_reg) >> 1;
- intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo, sdvo_reg);
-
/* Read the regs to test if we can talk to the device */
for (i = 0; i < 0x40; i++) {
u8 byte;
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 6b22c1dcc015..113e4e7264cd 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1361,15 +1361,14 @@ intel_tv_detect(struct drm_connector *connector, bool force)
if (intel_tv->base.base.crtc && intel_tv->base.base.crtc->enabled) {
type = intel_tv_detect_type(intel_tv, connector);
} else if (force) {
- struct drm_crtc *crtc;
- int dpms_mode;
+ struct intel_load_detect_pipe tmp;
- crtc = intel_get_load_detect_pipe(&intel_tv->base, connector,
- &mode, &dpms_mode);
- if (crtc) {
+ if (intel_get_load_detect_pipe(&intel_tv->base, connector,
+ &mode, &tmp)) {
type = intel_tv_detect_type(intel_tv, connector);
- intel_release_load_detect_pipe(&intel_tv->base, connector,
- dpms_mode);
+ intel_release_load_detect_pipe(&intel_tv->base,
+ connector,
+ &tmp);
} else
return connector_status_unknown;
} else
diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig
index de70959b9ed5..ca1639918f57 100644
--- a/drivers/gpu/drm/nouveau/Kconfig
+++ b/drivers/gpu/drm/nouveau/Kconfig
@@ -11,6 +11,8 @@ config DRM_NOUVEAU
select FRAMEBUFFER_CONSOLE if !EXPERT
select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT
select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && INPUT
+ select ACPI_WMI if ACPI
+ select MXM_WMI if ACPI
help
Choose this option for open-source nVidia support.
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
index e12c97fd8db8..0583677e4581 100644
--- a/drivers/gpu/drm/nouveau/Makefile
+++ b/drivers/gpu/drm/nouveau/Makefile
@@ -20,6 +20,8 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
nv40_graph.o nv50_graph.o nvc0_graph.o \
nv40_grctx.o nv50_grctx.o nvc0_grctx.o \
nv84_crypt.o \
+ nva3_copy.o nvc0_copy.o \
+ nv40_mpeg.o nv50_mpeg.o \
nv04_instmem.o nv50_instmem.o nvc0_instmem.o \
nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \
nv50_cursor.o nv50_display.o \
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index a54238058dc5..f0d459bb46e4 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -4,6 +4,8 @@
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h>
#include <acpi/video.h>
+#include <acpi/acpi.h>
+#include <linux/mxm-wmi.h>
#include "drmP.h"
#include "drm.h"
@@ -35,15 +37,71 @@
static struct nouveau_dsm_priv {
bool dsm_detected;
+ bool optimus_detected;
acpi_handle dhandle;
acpi_handle rom_handle;
} nouveau_dsm_priv;
+#define NOUVEAU_DSM_HAS_MUX 0x1
+#define NOUVEAU_DSM_HAS_OPT 0x2
+
static const char nouveau_dsm_muid[] = {
0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D,
0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
};
+static const char nouveau_op_dsm_muid[] = {
+ 0xF8, 0xD8, 0x86, 0xA4, 0xDA, 0x0B, 0x1B, 0x47,
+ 0xA7, 0x2B, 0x60, 0x42, 0xA6, 0xB5, 0xBE, 0xE0,
+};
+
+static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
+{
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_object_list input;
+ union acpi_object params[4];
+ union acpi_object *obj;
+ int err;
+
+ input.count = 4;
+ input.pointer = params;
+ params[0].type = ACPI_TYPE_BUFFER;
+ params[0].buffer.length = sizeof(nouveau_op_dsm_muid);
+ params[0].buffer.pointer = (char *)nouveau_op_dsm_muid;
+ params[1].type = ACPI_TYPE_INTEGER;
+ params[1].integer.value = 0x00000100;
+ params[2].type = ACPI_TYPE_INTEGER;
+ params[2].integer.value = func;
+ params[3].type = ACPI_TYPE_BUFFER;
+ params[3].buffer.length = 0;
+
+ err = acpi_evaluate_object(handle, "_DSM", &input, &output);
+ if (err) {
+ printk(KERN_INFO "failed to evaluate _DSM: %d\n", err);
+ return err;
+ }
+
+ obj = (union acpi_object *)output.pointer;
+
+ if (obj->type == ACPI_TYPE_INTEGER)
+ if (obj->integer.value == 0x80000002) {
+ return -ENODEV;
+ }
+
+ if (obj->type == ACPI_TYPE_BUFFER) {
+ if (obj->buffer.length == 4 && result) {
+ *result = 0;
+ *result |= obj->buffer.pointer[0];
+ *result |= (obj->buffer.pointer[1] << 8);
+ *result |= (obj->buffer.pointer[2] << 16);
+ *result |= (obj->buffer.pointer[3] << 24);
+ }
+ }
+
+ kfree(output.pointer);
+ return 0;
+}
+
static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
{
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -92,6 +150,8 @@ static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id)
{
+ mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0);
+ mxm_wmi_call_mxds(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0);
return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id, NULL);
}
@@ -148,11 +208,11 @@ static struct vga_switcheroo_handler nouveau_dsm_handler = {
.get_client_id = nouveau_dsm_get_client_id,
};
-static bool nouveau_dsm_pci_probe(struct pci_dev *pdev)
+static int nouveau_dsm_pci_probe(struct pci_dev *pdev)
{
acpi_handle dhandle, nvidia_handle;
acpi_status status;
- int ret;
+ int ret, retval = 0;
uint32_t result;
dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
@@ -166,11 +226,17 @@ static bool nouveau_dsm_pci_probe(struct pci_dev *pdev)
ret = nouveau_dsm(dhandle, NOUVEAU_DSM_SUPPORTED,
NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result);
- if (ret < 0)
- return false;
+ if (ret == 0)
+ retval |= NOUVEAU_DSM_HAS_MUX;
- nouveau_dsm_priv.dhandle = dhandle;
- return true;
+ ret = nouveau_optimus_dsm(dhandle, 0, 0, &result);
+ if (ret == 0)
+ retval |= NOUVEAU_DSM_HAS_OPT;
+
+ if (retval)
+ nouveau_dsm_priv.dhandle = dhandle;
+
+ return retval;
}
static bool nouveau_dsm_detect(void)
@@ -179,22 +245,42 @@ static bool nouveau_dsm_detect(void)
struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
struct pci_dev *pdev = NULL;
int has_dsm = 0;
+ int has_optimus;
int vga_count = 0;
+ bool guid_valid;
+ int retval;
+ bool ret = false;
+
+ /* lookup the MXM GUID */
+ guid_valid = mxm_wmi_supported();
+ if (guid_valid)
+ printk("MXM: GUID detected in BIOS\n");
+
+ /* now do DSM detection */
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
vga_count++;
- has_dsm |= (nouveau_dsm_pci_probe(pdev) == true);
+ retval = nouveau_dsm_pci_probe(pdev);
+ printk("ret val is %d\n", retval);
+ if (retval & NOUVEAU_DSM_HAS_MUX)
+ has_dsm |= 1;
+ if (retval & NOUVEAU_DSM_HAS_OPT)
+ has_optimus = 1;
}
- if (vga_count == 2 && has_dsm) {
+ if (vga_count == 2 && has_dsm && guid_valid) {
acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer);
printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n",
acpi_method_name);
nouveau_dsm_priv.dsm_detected = true;
- return true;
+ ret = true;
}
- return false;
+
+ if (has_optimus == 1)
+ nouveau_dsm_priv.optimus_detected = true;
+
+ return ret;
}
void nouveau_register_dsm_handler(void)
@@ -247,7 +333,7 @@ bool nouveau_acpi_rom_supported(struct pci_dev *pdev)
acpi_status status;
acpi_handle dhandle, rom_handle;
- if (!nouveau_dsm_priv.dsm_detected)
+ if (!nouveau_dsm_priv.dsm_detected && !nouveau_dsm_priv.optimus_detected)
return false;
dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index 90aef64b76f2..729d5fd7c88d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -5049,11 +5049,7 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
pll_lim->vco1.max_n = record[11];
pll_lim->min_p = record[12];
pll_lim->max_p = record[13];
- /* where did this go to?? */
- if ((entry[0] & 0xf0) == 0x80)
- pll_lim->refclk = 27000;
- else
- pll_lim->refclk = 100000;
+ pll_lim->refclk = ROM16(entry[9]) * 1000;
}
/*
@@ -6035,6 +6031,7 @@ parse_dcb_connector_table(struct nvbios *bios)
case DCB_CONNECTOR_DVI_I:
case DCB_CONNECTOR_DVI_D:
case DCB_CONNECTOR_LVDS:
+ case DCB_CONNECTOR_LVDS_SPWG:
case DCB_CONNECTOR_DP:
case DCB_CONNECTOR_eDP:
case DCB_CONNECTOR_HDMI_0:
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.h b/drivers/gpu/drm/nouveau/nouveau_bios.h
index 8a54fa7edf5c..050c314119df 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.h
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.h
@@ -82,6 +82,7 @@ enum dcb_connector_type {
DCB_CONNECTOR_DVI_I = 0x30,
DCB_CONNECTOR_DVI_D = 0x31,
DCB_CONNECTOR_LVDS = 0x40,
+ DCB_CONNECTOR_LVDS_SPWG = 0x41,
DCB_CONNECTOR_DP = 0x46,
DCB_CONNECTOR_eDP = 0x47,
DCB_CONNECTOR_HDMI_0 = 0x60,
diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c
index 4cea35c57d15..a7583a8ddb01 100644
--- a/drivers/gpu/drm/nouveau/nouveau_channel.c
+++ b/drivers/gpu/drm/nouveau/nouveau_channel.c
@@ -268,9 +268,8 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan)
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
unsigned long flags;
+ int i;
/* decrement the refcount, and we're done if there's still refs */
if (likely(!atomic_dec_and_test(&chan->users))) {
@@ -294,19 +293,12 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan)
/* boot it off the hardware */
pfifo->reassign(dev, false);
- /* We want to give pgraph a chance to idle and get rid of all
- * potential errors. We need to do this without the context
- * switch lock held, otherwise the irq handler is unable to
- * process them.
- */
- if (pgraph->channel(dev) == chan)
- nouveau_wait_for_idle(dev);
-
/* destroy the engine specific contexts */
pfifo->destroy_context(chan);
- pgraph->destroy_context(chan);
- if (pcrypt->destroy_context)
- pcrypt->destroy_context(chan);
+ for (i = 0; i < NVOBJ_ENGINE_NR; i++) {
+ if (chan->engctx[i])
+ dev_priv->eng[i]->context_del(chan, i);
+ }
pfifo->reassign(dev, true);
@@ -414,7 +406,7 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data,
struct nouveau_channel *chan;
int ret;
- if (dev_priv->engine.graph.accel_blocked)
+ if (!dev_priv->eng[NVOBJ_ENGINE_GR])
return -ENODEV;
if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0)
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 7ae151109a66..1595d0b6e815 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -442,7 +442,7 @@ nouveau_connector_set_property(struct drm_connector *connector,
}
/* LVDS always needs gpu scaling */
- if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS &&
+ if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS &&
value == DRM_MODE_SCALE_NONE)
return -EINVAL;
@@ -650,6 +650,7 @@ nouveau_connector_get_modes(struct drm_connector *connector)
ret = get_slave_funcs(encoder)->get_modes(encoder, connector);
if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS ||
+ nv_connector->dcb->type == DCB_CONNECTOR_LVDS_SPWG ||
nv_connector->dcb->type == DCB_CONNECTOR_eDP)
ret += nouveau_connector_scaler_modes_add(connector);
@@ -810,6 +811,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
type = DRM_MODE_CONNECTOR_HDMIA;
break;
case DCB_CONNECTOR_LVDS:
+ case DCB_CONNECTOR_LVDS_SPWG:
type = DRM_MODE_CONNECTOR_LVDS;
funcs = &nouveau_connector_funcs_lvds;
break;
@@ -838,7 +840,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
drm_connector_helper_add(connector, &nouveau_connector_helper_funcs);
/* Check if we need dithering enabled */
- if (dcb->type == DCB_CONNECTOR_LVDS) {
+ if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
bool dummy, is_24bit = false;
ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &is_24bit);
@@ -883,7 +885,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
nv_connector->use_dithering ?
DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF);
- if (dcb->type != DCB_CONNECTOR_LVDS) {
+ if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS) {
if (dev_priv->card_type >= NV_50)
connector->polled = DRM_CONNECTOR_POLL_HPD;
else
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 764c15d537ba..eb514ea29377 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -276,7 +276,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
struct nouveau_fence *fence;
int ret;
- if (dev_priv->engine.graph.accel_blocked)
+ if (!dev_priv->channel)
return -ENODEV;
s = kzalloc(sizeof(*s), GFP_KERNEL);
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
index 155ebdcbf06f..02c6f37d8bd7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -162,11 +162,10 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
struct drm_device *dev = pci_get_drvdata(pdev);
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
struct nouveau_channel *chan;
struct drm_crtc *crtc;
- int ret, i;
+ int ret, i, e;
if (pm_state.event == PM_EVENT_PRETHAW)
return 0;
@@ -206,12 +205,17 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
nouveau_channel_idle(chan);
}
- pgraph->fifo_access(dev, false);
- nouveau_wait_for_idle(dev);
pfifo->reassign(dev, false);
pfifo->disable(dev);
pfifo->unload_context(dev);
- pgraph->unload_context(dev);
+
+ for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {
+ if (dev_priv->eng[e]) {
+ ret = dev_priv->eng[e]->fini(dev, e);
+ if (ret)
+ goto out_abort;
+ }
+ }
ret = pinstmem->suspend(dev);
if (ret) {
@@ -242,9 +246,12 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
out_abort:
NV_INFO(dev, "Re-enabling acceleration..\n");
+ for (e = e + 1; e < NVOBJ_ENGINE_NR; e++) {
+ if (dev_priv->eng[e])
+ dev_priv->eng[e]->init(dev, e);
+ }
pfifo->enable(dev);
pfifo->reassign(dev, true);
- pgraph->fifo_access(dev, true);
return ret;
}
@@ -299,8 +306,10 @@ nouveau_pci_resume(struct pci_dev *pdev)
engine->mc.init(dev);
engine->timer.init(dev);
engine->fb.init(dev);
- engine->graph.init(dev);
- engine->crypt.init(dev);
+ for (i = 0; i < NVOBJ_ENGINE_NR; i++) {
+ if (dev_priv->eng[i])
+ dev_priv->eng[i]->init(dev, i);
+ }
engine->fifo.init(dev);
nouveau_irq_postinstall(dev);
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index a76514a209b3..9c56331941e2 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -150,13 +150,12 @@ enum nouveau_flags {
#define NVOBJ_ENGINE_SW 0
#define NVOBJ_ENGINE_GR 1
-#define NVOBJ_ENGINE_PPP 2
-#define NVOBJ_ENGINE_COPY 3
-#define NVOBJ_ENGINE_VP 4
-#define NVOBJ_ENGINE_CRYPT 5
-#define NVOBJ_ENGINE_BSP 6
-#define NVOBJ_ENGINE_DISPLAY 0xcafe0001
-#define NVOBJ_ENGINE_INT 0xdeadbeef
+#define NVOBJ_ENGINE_CRYPT 2
+#define NVOBJ_ENGINE_COPY0 3
+#define NVOBJ_ENGINE_COPY1 4
+#define NVOBJ_ENGINE_MPEG 5
+#define NVOBJ_ENGINE_DISPLAY 15
+#define NVOBJ_ENGINE_NR 16
#define NVOBJ_FLAG_DONT_MAP (1 << 0)
#define NVOBJ_FLAG_ZERO_ALLOC (1 << 1)
@@ -245,11 +244,8 @@ struct nouveau_channel {
struct nouveau_gpuobj *cache;
void *fifo_priv;
- /* PGRAPH context */
- /* XXX may be merge 2 pointers as private data ??? */
- struct nouveau_gpuobj *ramin_grctx;
- struct nouveau_gpuobj *crypt_ctx;
- void *pgraph_ctx;
+ /* Execution engine contexts */
+ void *engctx[NVOBJ_ENGINE_NR];
/* NV50 VM */
struct nouveau_vm *vm;
@@ -298,6 +294,18 @@ struct nouveau_channel {
} debugfs;
};
+struct nouveau_exec_engine {
+ void (*destroy)(struct drm_device *, int engine);
+ int (*init)(struct drm_device *, int engine);
+ int (*fini)(struct drm_device *, int engine);
+ int (*context_new)(struct nouveau_channel *, int engine);
+ void (*context_del)(struct nouveau_channel *, int engine);
+ int (*object_new)(struct nouveau_channel *, int engine,
+ u32 handle, u16 class);
+ void (*set_tile_region)(struct drm_device *dev, int i);
+ void (*tlb_flush)(struct drm_device *, int engine);
+};
+
struct nouveau_instmem_engine {
void *priv;
@@ -364,30 +372,6 @@ struct nouveau_fifo_engine {
void (*tlb_flush)(struct drm_device *dev);
};
-struct nouveau_pgraph_engine {
- bool accel_blocked;
- bool registered;
- int grctx_size;
- void *priv;
-
- /* NV2x/NV3x context table (0x400780) */
- struct nouveau_gpuobj *ctx_table;
-
- int (*init)(struct drm_device *);
- void (*takedown)(struct drm_device *);
-
- void (*fifo_access)(struct drm_device *, bool);
-
- struct nouveau_channel *(*channel)(struct drm_device *);
- int (*create_context)(struct nouveau_channel *);
- void (*destroy_context)(struct nouveau_channel *);
- int (*load_context)(struct nouveau_channel *);
- int (*unload_context)(struct drm_device *);
- void (*tlb_flush)(struct drm_device *dev);
-
- void (*set_tile_region)(struct drm_device *dev, int i);
-};
-
struct nouveau_display_engine {
void *priv;
int (*early_init)(struct drm_device *);
@@ -426,6 +410,19 @@ struct nouveau_pm_voltage {
int nr_level;
};
+struct nouveau_pm_memtiming {
+ int id;
+ u32 reg_100220;
+ u32 reg_100224;
+ u32 reg_100228;
+ u32 reg_10022c;
+ u32 reg_100230;
+ u32 reg_100234;
+ u32 reg_100238;
+ u32 reg_10023c;
+ u32 reg_100240;
+};
+
#define NOUVEAU_PM_MAX_LEVEL 8
struct nouveau_pm_level {
struct device_attribute dev_attr;
@@ -436,11 +433,13 @@ struct nouveau_pm_level {
u32 memory;
u32 shader;
u32 unk05;
+ u32 unk0a;
u8 voltage;
u8 fanspeed;
u16 memscript;
+ struct nouveau_pm_memtiming *timing;
};
struct nouveau_pm_temp_sensor_constants {
@@ -457,17 +456,6 @@ struct nouveau_pm_threshold_temp {
s16 fan_boost;
};
-struct nouveau_pm_memtiming {
- u32 reg_100220;
- u32 reg_100224;
- u32 reg_100228;
- u32 reg_10022c;
- u32 reg_100230;
- u32 reg_100234;
- u32 reg_100238;
- u32 reg_10023c;
-};
-
struct nouveau_pm_memtimings {
bool supported;
struct nouveau_pm_memtiming *timing;
@@ -499,16 +487,6 @@ struct nouveau_pm_engine {
int (*temp_get)(struct drm_device *);
};
-struct nouveau_crypt_engine {
- bool registered;
-
- int (*init)(struct drm_device *);
- void (*takedown)(struct drm_device *);
- int (*create_context)(struct nouveau_channel *);
- void (*destroy_context)(struct nouveau_channel *);
- void (*tlb_flush)(struct drm_device *dev);
-};
-
struct nouveau_vram_engine {
int (*init)(struct drm_device *);
int (*get)(struct drm_device *, u64, u32 align, u32 size_nc,
@@ -523,12 +501,10 @@ struct nouveau_engine {
struct nouveau_mc_engine mc;
struct nouveau_timer_engine timer;
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_pm_engine pm;
- struct nouveau_crypt_engine crypt;
struct nouveau_vram_engine vram;
};
@@ -637,6 +613,7 @@ struct drm_nouveau_private {
enum nouveau_card_type card_type;
/* exact chipset, derived from NV_PMC_BOOT_0 */
int chipset;
+ int stepping;
int flags;
void __iomem *mmio;
@@ -647,6 +624,7 @@ struct drm_nouveau_private {
u32 ramin_base;
bool ramin_available;
struct drm_mm ramin_heap;
+ struct nouveau_exec_engine *eng[NVOBJ_ENGINE_NR];
struct list_head gpuobj_list;
struct list_head classes;
@@ -745,10 +723,6 @@ struct drm_nouveau_private {
uint32_t crtc_owner;
uint32_t dac_users[4];
- struct nouveau_suspend_resume {
- uint32_t *ramin_copy;
- } susres;
-
struct backlight_device *backlight;
struct {
@@ -757,8 +731,6 @@ struct drm_nouveau_private {
struct nouveau_fbdev *nfbdev;
struct apertures_struct *apertures;
-
- bool powered_down;
};
static inline struct drm_nouveau_private *
@@ -883,17 +855,27 @@ extern void nouveau_channel_ref(struct nouveau_channel *chan,
extern void nouveau_channel_idle(struct nouveau_channel *chan);
/* nouveau_object.c */
-#define NVOBJ_CLASS(d,c,e) do { \
+#define NVOBJ_ENGINE_ADD(d, e, p) do { \
+ struct drm_nouveau_private *dev_priv = (d)->dev_private; \
+ dev_priv->eng[NVOBJ_ENGINE_##e] = (p); \
+} while (0)
+
+#define NVOBJ_ENGINE_DEL(d, e) do { \
+ struct drm_nouveau_private *dev_priv = (d)->dev_private; \
+ dev_priv->eng[NVOBJ_ENGINE_##e] = NULL; \
+} while (0)
+
+#define NVOBJ_CLASS(d, c, e) do { \
int ret = nouveau_gpuobj_class_new((d), (c), NVOBJ_ENGINE_##e); \
if (ret) \
return ret; \
-} while(0)
+} while (0)
-#define NVOBJ_MTHD(d,c,m,e) do { \
+#define NVOBJ_MTHD(d, c, m, e) do { \
int ret = nouveau_gpuobj_mthd_new((d), (c), (m), (e)); \
if (ret) \
return ret; \
-} while(0)
+} while (0)
extern int nouveau_gpuobj_early_init(struct drm_device *);
extern int nouveau_gpuobj_init(struct drm_device *);
@@ -903,7 +885,7 @@ extern void nouveau_gpuobj_resume(struct drm_device *dev);
extern int nouveau_gpuobj_class_new(struct drm_device *, u32 class, u32 eng);
extern int nouveau_gpuobj_mthd_new(struct drm_device *, u32 class, u32 mthd,
int (*exec)(struct nouveau_channel *,
- u32 class, u32 mthd, u32 data));
+ u32 class, u32 mthd, u32 data));
extern int nouveau_gpuobj_mthd_call(struct nouveau_channel *, u32, u32, u32);
extern int nouveau_gpuobj_mthd_call2(struct drm_device *, int, u32, u32, u32);
extern int nouveau_gpuobj_channel_init(struct nouveau_channel *,
@@ -1137,81 +1119,50 @@ extern int nvc0_fifo_load_context(struct nouveau_channel *);
extern int nvc0_fifo_unload_context(struct drm_device *);
/* nv04_graph.c */
-extern int nv04_graph_init(struct drm_device *);
-extern void nv04_graph_takedown(struct drm_device *);
+extern int nv04_graph_create(struct drm_device *);
extern void nv04_graph_fifo_access(struct drm_device *, bool);
-extern struct nouveau_channel *nv04_graph_channel(struct drm_device *);
-extern int nv04_graph_create_context(struct nouveau_channel *);
-extern void nv04_graph_destroy_context(struct nouveau_channel *);
-extern int nv04_graph_load_context(struct nouveau_channel *);
-extern int nv04_graph_unload_context(struct drm_device *);
+extern int nv04_graph_object_new(struct nouveau_channel *, int, u32, u16);
extern int nv04_graph_mthd_page_flip(struct nouveau_channel *chan,
u32 class, u32 mthd, u32 data);
extern struct nouveau_bitfield nv04_graph_nsource[];
/* nv10_graph.c */
-extern int nv10_graph_init(struct drm_device *);
-extern void nv10_graph_takedown(struct drm_device *);
+extern int nv10_graph_create(struct drm_device *);
extern struct nouveau_channel *nv10_graph_channel(struct drm_device *);
-extern int nv10_graph_create_context(struct nouveau_channel *);
-extern void nv10_graph_destroy_context(struct nouveau_channel *);
-extern int nv10_graph_load_context(struct nouveau_channel *);
-extern int nv10_graph_unload_context(struct drm_device *);
-extern void nv10_graph_set_tile_region(struct drm_device *dev, int i);
extern struct nouveau_bitfield nv10_graph_intr[];
extern struct nouveau_bitfield nv10_graph_nstatus[];
/* nv20_graph.c */
-extern int nv20_graph_create_context(struct nouveau_channel *);
-extern void nv20_graph_destroy_context(struct nouveau_channel *);
-extern int nv20_graph_load_context(struct nouveau_channel *);
-extern int nv20_graph_unload_context(struct drm_device *);
-extern int nv20_graph_init(struct drm_device *);
-extern void nv20_graph_takedown(struct drm_device *);
-extern int nv30_graph_init(struct drm_device *);
-extern void nv20_graph_set_tile_region(struct drm_device *dev, int i);
+extern int nv20_graph_create(struct drm_device *);
/* nv40_graph.c */
-extern int nv40_graph_init(struct drm_device *);
-extern void nv40_graph_takedown(struct drm_device *);
-extern struct nouveau_channel *nv40_graph_channel(struct drm_device *);
-extern int nv40_graph_create_context(struct nouveau_channel *);
-extern void nv40_graph_destroy_context(struct nouveau_channel *);
-extern int nv40_graph_load_context(struct nouveau_channel *);
-extern int nv40_graph_unload_context(struct drm_device *);
+extern int nv40_graph_create(struct drm_device *);
extern void nv40_grctx_init(struct nouveau_grctx *);
-extern void nv40_graph_set_tile_region(struct drm_device *dev, int i);
/* nv50_graph.c */
-extern int nv50_graph_init(struct drm_device *);
-extern void nv50_graph_takedown(struct drm_device *);
-extern void nv50_graph_fifo_access(struct drm_device *, bool);
-extern struct nouveau_channel *nv50_graph_channel(struct drm_device *);
-extern int nv50_graph_create_context(struct nouveau_channel *);
-extern void nv50_graph_destroy_context(struct nouveau_channel *);
-extern int nv50_graph_load_context(struct nouveau_channel *);
-extern int nv50_graph_unload_context(struct drm_device *);
+extern int nv50_graph_create(struct drm_device *);
extern int nv50_grctx_init(struct nouveau_grctx *);
-extern void nv50_graph_tlb_flush(struct drm_device *dev);
-extern void nv84_graph_tlb_flush(struct drm_device *dev);
extern struct nouveau_enum nv50_data_error_names[];
+extern int nv50_graph_isr_chid(struct drm_device *dev, u64 inst);
/* nvc0_graph.c */
-extern int nvc0_graph_init(struct drm_device *);
-extern void nvc0_graph_takedown(struct drm_device *);
-extern void nvc0_graph_fifo_access(struct drm_device *, bool);
-extern struct nouveau_channel *nvc0_graph_channel(struct drm_device *);
-extern int nvc0_graph_create_context(struct nouveau_channel *);
-extern void nvc0_graph_destroy_context(struct nouveau_channel *);
-extern int nvc0_graph_load_context(struct nouveau_channel *);
-extern int nvc0_graph_unload_context(struct drm_device *);
+extern int nvc0_graph_create(struct drm_device *);
+extern int nvc0_graph_isr_chid(struct drm_device *dev, u64 inst);
/* nv84_crypt.c */
-extern int nv84_crypt_init(struct drm_device *dev);
-extern void nv84_crypt_fini(struct drm_device *dev);
-extern int nv84_crypt_create_context(struct nouveau_channel *);
-extern void nv84_crypt_destroy_context(struct nouveau_channel *);
-extern void nv84_crypt_tlb_flush(struct drm_device *dev);
+extern int nv84_crypt_create(struct drm_device *);
+
+/* nva3_copy.c */
+extern int nva3_copy_create(struct drm_device *dev);
+
+/* nvc0_copy.c */
+extern int nvc0_copy_create(struct drm_device *dev, int engine);
+
+/* nv40_mpeg.c */
+extern int nv40_mpeg_create(struct drm_device *dev);
+
+/* nv50_mpeg.c */
+extern int nv50_mpeg_create(struct drm_device *dev);
/* nv04_instmem.c */
extern int nv04_instmem_init(struct drm_device *);
@@ -1402,8 +1353,8 @@ bool 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,
int *N1, int *M1, int *N2, int *M2, int *P);
-int nv50_calc_pll2(struct drm_device *, struct pll_lims *,
- int clk, int *N, int *fN, int *M, int *P);
+int nva3_calc_pll(struct drm_device *, struct pll_lims *,
+ int clk, int *N, int *fN, int *M, int *P);
#ifndef ioread32_native
#ifdef __BIG_ENDIAN
@@ -1579,6 +1530,13 @@ nv_match_device(struct drm_device *dev, unsigned device,
dev->pdev->subsystem_device == sub_device;
}
+static inline void *
+nv_engine(struct drm_device *dev, int engine)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ return (void *)dev_priv->eng[engine];
+}
+
/* returns 1 if device is one of the nv4x using the 0x4497 object class,
* helpful to determine a number of other hardware features
*/
diff --git a/drivers/gpu/drm/nouveau/nouveau_grctx.h b/drivers/gpu/drm/nouveau/nouveau_grctx.h
index 4a8ad1307fa4..86c2e374e938 100644
--- a/drivers/gpu/drm/nouveau/nouveau_grctx.h
+++ b/drivers/gpu/drm/nouveau/nouveau_grctx.h
@@ -87,10 +87,10 @@ _cp_bra(struct nouveau_grctx *ctx, u32 mod, int flag, int state, int name)
cp_out(ctx, CP_BRA | (mod << 18) | ip | flag |
(state ? 0 : CP_BRA_IF_CLEAR));
}
-#define cp_bra(c,f,s,n) _cp_bra((c), 0, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
+#define cp_bra(c, f, s, n) _cp_bra((c), 0, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
#ifdef CP_BRA_MOD
-#define cp_cal(c,f,s,n) _cp_bra((c), 1, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
-#define cp_ret(c,f,s) _cp_bra((c), 2, CP_FLAG_##f, CP_FLAG_##f##_##s, 0)
+#define cp_cal(c, f, s, n) _cp_bra((c), 1, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
+#define cp_ret(c, f, s) _cp_bra((c), 2, CP_FLAG_##f, CP_FLAG_##f##_##s, 0)
#endif
static inline void
@@ -98,14 +98,14 @@ _cp_wait(struct nouveau_grctx *ctx, int flag, int state)
{
cp_out(ctx, CP_WAIT | flag | (state ? CP_WAIT_SET : 0));
}
-#define cp_wait(c,f,s) _cp_wait((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
+#define cp_wait(c, f, s) _cp_wait((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
static inline void
_cp_set(struct nouveau_grctx *ctx, int flag, int state)
{
cp_out(ctx, CP_SET | flag | (state ? CP_SET_1 : 0));
}
-#define cp_set(c,f,s) _cp_set((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
+#define cp_set(c, f, s) _cp_set((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
static inline void
cp_pos(struct nouveau_grctx *ctx, int offset)
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
index c3e953b08992..2960f583dc38 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
@@ -51,8 +51,7 @@ nv10_mem_update_tile_region(struct drm_device *dev,
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- int i = tile - dev_priv->tile.reg;
+ int i = tile - dev_priv->tile.reg, j;
unsigned long save;
nouveau_fence_unref(&tile->fence);
@@ -70,7 +69,10 @@ nv10_mem_update_tile_region(struct drm_device *dev,
nouveau_wait_for_idle(dev);
pfb->set_tile_region(dev, i);
- pgraph->set_tile_region(dev, i);
+ for (j = 0; j < NVOBJ_ENGINE_NR; j++) {
+ if (dev_priv->eng[j] && dev_priv->eng[j]->set_tile_region)
+ dev_priv->eng[j]->set_tile_region(dev, i);
+ }
pfifo->cache_pull(dev, true);
pfifo->reassign(dev, true);
@@ -595,10 +597,10 @@ nouveau_mem_timing_init(struct drm_device *dev)
if (!memtimings->timing)
return;
- /* Get "some number" from the timing reg for NV_40
+ /* Get "some number" from the timing reg for NV_40 and NV_50
* Used in calculations later */
- if(dev_priv->card_type == NV_40) {
- magic_number = (nv_rd32(dev,0x100228) & 0x0f000000) >> 24;
+ if (dev_priv->card_type >= NV_40 && dev_priv->chipset < 0x98) {
+ magic_number = (nv_rd32(dev, 0x100228) & 0x0f000000) >> 24;
}
entry = mem + mem[1];
@@ -641,51 +643,68 @@ nouveau_mem_timing_init(struct drm_device *dev)
/* XXX: I don't trust the -1's and +1's... they must come
* from somewhere! */
timing->reg_100224 = (tUNK_0 + tUNK_19 + 1 + magic_number) << 24 |
- tUNK_18 << 16 |
+ max(tUNK_18, (u8) 1) << 16 |
(tUNK_1 + tUNK_19 + 1 + magic_number) << 8;
- if(dev_priv->chipset == 0xa8) {
+ if (dev_priv->chipset == 0xa8) {
timing->reg_100224 |= (tUNK_2 - 1);
} else {
timing->reg_100224 |= (tUNK_2 + 2 - magic_number);
}
timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10);
- if(dev_priv->chipset >= 0xa3 && dev_priv->chipset < 0xaa) {
+ if (dev_priv->chipset >= 0xa3 && dev_priv->chipset < 0xaa)
timing->reg_100228 |= (tUNK_19 - 1) << 24;
- }
+ else
+ timing->reg_100228 |= magic_number << 24;
- if(dev_priv->card_type == NV_40) {
+ if (dev_priv->card_type == NV_40) {
/* NV40: don't know what the rest of the regs are..
* And don't need to know either */
- timing->reg_100228 |= 0x20200000 | magic_number << 24;
- } else if(dev_priv->card_type >= NV_50) {
- /* XXX: reg_10022c */
- timing->reg_10022c = tUNK_2 - 1;
+ timing->reg_100228 |= 0x20200000;
+ } else if (dev_priv->card_type >= NV_50) {
+ if (dev_priv->chipset < 0x98 ||
+ (dev_priv->chipset == 0x98 &&
+ dev_priv->stepping <= 0xa1)) {
+ timing->reg_10022c = (0x14 + tUNK_2) << 24 |
+ 0x16 << 16 |
+ (tUNK_2 - 1) << 8 |
+ (tUNK_2 - 1);
+ } else {
+ /* XXX: reg_10022c for recentish cards */
+ timing->reg_10022c = tUNK_2 - 1;
+ }
timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 |
tUNK_13 << 8 | tUNK_13);
timing->reg_100234 = (tRAS << 24 | tRC);
- timing->reg_100234 += max(tUNK_10,tUNK_11) << 16;
+ timing->reg_100234 += max(tUNK_10, tUNK_11) << 16;
- if(dev_priv->chipset < 0xa3) {
+ if (dev_priv->chipset < 0x98 ||
+ (dev_priv->chipset == 0x98 &&
+ dev_priv->stepping <= 0xa1)) {
timing->reg_100234 |= (tUNK_2 + 2) << 8;
} else {
/* XXX: +6? */
timing->reg_100234 |= (tUNK_19 + 6) << 8;
}
- /* XXX; reg_100238, reg_10023c
- * reg_100238: 0x00??????
- * reg_10023c: 0x!!??0202 for NV50+ cards (empirical evidence) */
+ /* XXX; reg_100238
+ * reg_100238: 0x00?????? */
timing->reg_10023c = 0x202;
- if(dev_priv->chipset < 0xa3) {
+ if (dev_priv->chipset < 0x98 ||
+ (dev_priv->chipset == 0x98 &&
+ dev_priv->stepping <= 0xa1)) {
timing->reg_10023c |= 0x4000000 | (tUNK_2 - 1) << 16;
} else {
- /* currently unknown
+ /* XXX: reg_10023c
+ * currently unknown
* 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */
}
+
+ /* XXX: reg_100240? */
}
+ timing->id = i;
NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i,
timing->reg_100220, timing->reg_100224,
@@ -693,10 +712,11 @@ nouveau_mem_timing_init(struct drm_device *dev)
NV_DEBUG(dev, " 230: %08x %08x %08x %08x\n",
timing->reg_100230, timing->reg_100234,
timing->reg_100238, timing->reg_10023c);
+ NV_DEBUG(dev, " 240: %08x\n", timing->reg_100240);
}
memtimings->nr_timing = entries;
- memtimings->supported = true;
+ memtimings->supported = (dev_priv->chipset <= 0x98);
}
void
diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c
index 67a16e01ffa6..8f97016f5b26 100644
--- a/drivers/gpu/drm/nouveau/nouveau_object.c
+++ b/drivers/gpu/drm/nouveau/nouveau_object.c
@@ -361,20 +361,6 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, u32 pinst, u64 vinst,
return 0;
}
-
-static uint32_t
-nouveau_gpuobj_class_instmem_size(struct drm_device *dev, int class)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- /*XXX: dodgy hack for now */
- if (dev_priv->card_type >= NV_50)
- return 24;
- if (dev_priv->card_type >= NV_40)
- return 32;
- return 16;
-}
-
/*
DMA objects are used to reference a piece of memory in the
framebuffer, PCI or AGP address space. Each object is 16 bytes big
@@ -606,11 +592,11 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, u64 base,
set to 0?
*/
static int
-nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class,
- struct nouveau_gpuobj **gpuobj_ret)
+nouveau_gpuobj_sw_new(struct nouveau_channel *chan, u32 handle, u16 class)
{
struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
struct nouveau_gpuobj *gpuobj;
+ int ret;
gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL);
if (!gpuobj)
@@ -624,8 +610,10 @@ nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class,
spin_lock(&dev_priv->ramin_lock);
list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
spin_unlock(&dev_priv->ramin_lock);
- *gpuobj_ret = gpuobj;
- return 0;
+
+ ret = nouveau_ramht_insert(chan, handle, gpuobj);
+ nouveau_gpuobj_ref(NULL, &gpuobj);
+ return ret;
}
int
@@ -634,101 +622,30 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, u32 handle, int class)
struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
struct drm_device *dev = chan->dev;
struct nouveau_gpuobj_class *oc;
- struct nouveau_gpuobj *gpuobj;
int ret;
NV_DEBUG(dev, "ch%d class=0x%04x\n", chan->id, class);
list_for_each_entry(oc, &dev_priv->classes, head) {
- if (oc->id == class)
- goto found;
- }
-
- NV_ERROR(dev, "illegal object class: 0x%x\n", class);
- return -EINVAL;
+ struct nouveau_exec_engine *eng = dev_priv->eng[oc->engine];
-found:
- switch (oc->engine) {
- case NVOBJ_ENGINE_SW:
- if (dev_priv->card_type < NV_C0) {
- ret = nouveau_gpuobj_sw_new(chan, class, &gpuobj);
- if (ret)
- return ret;
- goto insert;
- }
- break;
- case NVOBJ_ENGINE_GR:
- if ((dev_priv->card_type >= NV_20 && !chan->ramin_grctx) ||
- (dev_priv->card_type < NV_20 && !chan->pgraph_ctx)) {
- struct nouveau_pgraph_engine *pgraph =
- &dev_priv->engine.graph;
+ if (oc->id != class)
+ continue;
- ret = pgraph->create_context(chan);
- if (ret)
- return ret;
- }
- break;
- case NVOBJ_ENGINE_CRYPT:
- if (!chan->crypt_ctx) {
- struct nouveau_crypt_engine *pcrypt =
- &dev_priv->engine.crypt;
+ if (oc->engine == NVOBJ_ENGINE_SW)
+ return nouveau_gpuobj_sw_new(chan, handle, class);
- ret = pcrypt->create_context(chan);
+ if (!chan->engctx[oc->engine]) {
+ ret = eng->context_new(chan, oc->engine);
if (ret)
return ret;
}
- break;
- }
-
- /* we're done if this is fermi */
- if (dev_priv->card_type >= NV_C0)
- return 0;
-
- ret = nouveau_gpuobj_new(dev, chan,
- nouveau_gpuobj_class_instmem_size(dev, class),
- 16,
- NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE,
- &gpuobj);
- if (ret) {
- NV_ERROR(dev, "error creating gpuobj: %d\n", ret);
- return ret;
- }
- if (dev_priv->card_type >= NV_50) {
- nv_wo32(gpuobj, 0, class);
- nv_wo32(gpuobj, 20, 0x00010000);
- } else {
- switch (class) {
- case NV_CLASS_NULL:
- nv_wo32(gpuobj, 0, 0x00001030);
- nv_wo32(gpuobj, 4, 0xFFFFFFFF);
- break;
- default:
- if (dev_priv->card_type >= NV_40) {
- nv_wo32(gpuobj, 0, class);
-#ifdef __BIG_ENDIAN
- nv_wo32(gpuobj, 8, 0x01000000);
-#endif
- } else {
-#ifdef __BIG_ENDIAN
- nv_wo32(gpuobj, 0, class | 0x00080000);
-#else
- nv_wo32(gpuobj, 0, class);
-#endif
- }
- }
+ return eng->object_new(chan, oc->engine, handle, class);
}
- dev_priv->engine.instmem.flush(dev);
-
- gpuobj->engine = oc->engine;
- gpuobj->class = oc->id;
-insert:
- ret = nouveau_ramht_insert(chan, handle, gpuobj);
- if (ret)
- NV_ERROR(dev, "error adding gpuobj to RAMHT: %d\n", ret);
- nouveau_gpuobj_ref(NULL, &gpuobj);
- return ret;
+ NV_ERROR(dev, "illegal object class: 0x%x\n", class);
+ return -EINVAL;
}
static int
@@ -746,9 +663,6 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
size = 0x2000;
base = 0;
- /* PGRAPH context */
- size += dev_priv->engine.graph.grctx_size;
-
if (dev_priv->card_type == NV_50) {
/* Various fixed table thingos */
size += 0x1400; /* mostly unknown stuff */
diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c
index 670e3cb697ec..922fb6b664ed 100644
--- a/drivers/gpu/drm/nouveau/nouveau_perf.c
+++ b/drivers/gpu/drm/nouveau/nouveau_perf.c
@@ -72,6 +72,68 @@ legacy_perf_init(struct drm_device *dev)
pm->nr_perflvl = 1;
}
+static struct nouveau_pm_memtiming *
+nouveau_perf_timing(struct drm_device *dev, struct bit_entry *P,
+ u16 memclk, u8 *entry, u8 recordlen, u8 entries)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+ struct nvbios *bios = &dev_priv->vbios;
+ u8 ramcfg;
+ int i;
+
+ /* perf v2 has a separate "timing map" table, we have to match
+ * the target memory clock to a specific entry, *then* use
+ * ramcfg to select the correct subentry
+ */
+ if (P->version == 2) {
+ u8 *tmap = ROMPTR(bios, P->data[4]);
+ if (!tmap) {
+ NV_DEBUG(dev, "no timing map pointer\n");
+ return NULL;
+ }
+
+ if (tmap[0] != 0x10) {
+ NV_WARN(dev, "timing map 0x%02x unknown\n", tmap[0]);
+ return NULL;
+ }
+
+ entry = tmap + tmap[1];
+ recordlen = tmap[2] + (tmap[4] * tmap[3]);
+ for (i = 0; i < tmap[5]; i++, entry += recordlen) {
+ if (memclk >= ROM16(entry[0]) &&
+ memclk <= ROM16(entry[2]))
+ break;
+ }
+
+ if (i == tmap[5]) {
+ NV_WARN(dev, "no match in timing map table\n");
+ return NULL;
+ }
+
+ entry += tmap[2];
+ recordlen = tmap[3];
+ entries = tmap[4];
+ }
+
+ ramcfg = (nv_rd32(dev, NV_PEXTDEV_BOOT_0) & 0x0000003c) >> 2;
+ if (bios->ram_restrict_tbl_ptr)
+ ramcfg = bios->data[bios->ram_restrict_tbl_ptr + ramcfg];
+
+ if (ramcfg >= entries) {
+ NV_WARN(dev, "ramcfg strap out of bounds!\n");
+ return NULL;
+ }
+
+ entry += ramcfg * recordlen;
+ if (entry[1] >= pm->memtimings.nr_timing) {
+ NV_WARN(dev, "timingset %d does not exist\n", entry[1]);
+ return NULL;
+ }
+
+ return &pm->memtimings.timing[entry[1]];
+}
+
void
nouveau_perf_init(struct drm_device *dev)
{
@@ -124,6 +186,8 @@ nouveau_perf_init(struct drm_device *dev)
for (i = 0; i < entries; i++) {
struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl];
+ perflvl->timing = NULL;
+
if (entry[0] == 0xff) {
entry += recordlen;
continue;
@@ -174,9 +238,21 @@ nouveau_perf_init(struct drm_device *dev)
#define subent(n) entry[perf[2] + ((n) * perf[3])]
perflvl->fanspeed = 0; /*XXX*/
perflvl->voltage = entry[2];
- perflvl->core = (ROM16(subent(0)) & 0xfff) * 1000;
- perflvl->shader = (ROM16(subent(1)) & 0xfff) * 1000;
- perflvl->memory = (ROM16(subent(2)) & 0xfff) * 1000;
+ if (dev_priv->card_type == NV_50) {
+ perflvl->core = ROM16(subent(0)) & 0xfff;
+ perflvl->shader = ROM16(subent(1)) & 0xfff;
+ perflvl->memory = ROM16(subent(2)) & 0xfff;
+ } else {
+ perflvl->shader = ROM16(subent(3)) & 0xfff;
+ perflvl->core = perflvl->shader / 2;
+ perflvl->unk0a = ROM16(subent(4)) & 0xfff;
+ perflvl->memory = ROM16(subent(5)) & 0xfff;
+ }
+
+ perflvl->core *= 1000;
+ perflvl->shader *= 1000;
+ perflvl->memory *= 1000;
+ perflvl->unk0a *= 1000;
break;
}
@@ -190,6 +266,16 @@ nouveau_perf_init(struct drm_device *dev)
}
}
+ /* get the corresponding memory timings */
+ if (version > 0x15) {
+ /* last 3 args are for < 0x40, ignored for >= 0x40 */
+ perflvl->timing =
+ nouveau_perf_timing(dev, &P,
+ perflvl->memory / 1000,
+ entry + perf[3],
+ perf[5], perf[4]);
+ }
+
snprintf(perflvl->name, sizeof(perflvl->name),
"performance_level_%d", i);
perflvl->id = i;
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c
index 4399e2f34db4..da8d994d5e8a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.c
@@ -156,7 +156,7 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
static void
nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len)
{
- char c[16], s[16], v[16], f[16];
+ char c[16], s[16], v[16], f[16], t[16];
c[0] = '\0';
if (perflvl->core)
@@ -174,8 +174,12 @@ nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len)
if (perflvl->fanspeed)
snprintf(f, sizeof(f), " fanspeed %d%%", perflvl->fanspeed);
- snprintf(ptr, len, "memory %dMHz%s%s%s%s\n", perflvl->memory / 1000,
- c, s, v, f);
+ t[0] = '\0';
+ if (perflvl->timing)
+ snprintf(t, sizeof(t), " timing %d", perflvl->timing->id);
+
+ snprintf(ptr, len, "memory %dMHz%s%s%s%s%s\n", perflvl->memory / 1000,
+ c, s, v, f, t);
}
static ssize_t
@@ -449,7 +453,7 @@ nouveau_hwmon_fini(struct drm_device *dev)
#endif
}
-#ifdef CONFIG_ACPI
+#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY)
static int
nouveau_pm_acpi_event(struct notifier_block *nb, unsigned long val, void *data)
{
@@ -476,10 +480,10 @@ nouveau_pm_init(struct drm_device *dev)
char info[256];
int ret, i;
+ nouveau_mem_timing_init(dev);
nouveau_volt_init(dev);
nouveau_perf_init(dev);
nouveau_temp_init(dev);
- nouveau_mem_timing_init(dev);
NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl);
for (i = 0; i < pm->nr_perflvl; i++) {
@@ -490,6 +494,7 @@ nouveau_pm_init(struct drm_device *dev)
/* determine current ("boot") performance level */
ret = nouveau_pm_perflvl_get(dev, &pm->boot);
if (ret == 0) {
+ strncpy(pm->boot.name, "boot", 4);
pm->cur = &pm->boot;
nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info));
@@ -507,7 +512,7 @@ nouveau_pm_init(struct drm_device *dev)
nouveau_sysfs_init(dev);
nouveau_hwmon_init(dev);
-#ifdef CONFIG_ACPI
+#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY)
pm->acpi_nb.notifier_call = nouveau_pm_acpi_event;
register_acpi_notifier(&pm->acpi_nb);
#endif
@@ -524,12 +529,12 @@ nouveau_pm_fini(struct drm_device *dev)
if (pm->cur != &pm->boot)
nouveau_pm_perflvl_set(dev, &pm->boot);
- nouveau_mem_timing_fini(dev);
nouveau_temp_fini(dev);
nouveau_perf_fini(dev);
nouveau_volt_fini(dev);
+ nouveau_mem_timing_fini(dev);
-#ifdef CONFIG_ACPI
+#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY)
unregister_acpi_notifier(&pm->acpi_nb);
#endif
nouveau_hwmon_fini(dev);
diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h
index 04e8fb795269..f18cdfc3400f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_reg.h
+++ b/drivers/gpu/drm/nouveau/nouveau_reg.h
@@ -639,9 +639,9 @@
# define NV50_PCONNECTOR_I2C_PORT_4 0x0000e240
# define NV50_PCONNECTOR_I2C_PORT_5 0x0000e258
-#define NV50_AUXCH_DATA_OUT(i,n) ((n) * 4 + (i) * 0x50 + 0x0000e4c0)
+#define NV50_AUXCH_DATA_OUT(i, n) ((n) * 4 + (i) * 0x50 + 0x0000e4c0)
#define NV50_AUXCH_DATA_OUT__SIZE 4
-#define NV50_AUXCH_DATA_IN(i,n) ((n) * 4 + (i) * 0x50 + 0x0000e4d0)
+#define NV50_AUXCH_DATA_IN(i, n) ((n) * 4 + (i) * 0x50 + 0x0000e4d0)
#define NV50_AUXCH_DATA_IN__SIZE 4
#define NV50_AUXCH_ADDR(i) ((i) * 0x50 + 0x0000e4e0)
#define NV50_AUXCH_CTRL(i) ((i) * 0x50 + 0x0000e4e4)
@@ -829,7 +829,7 @@
#define NV50_PDISPLAY_SOR_BACKLIGHT 0x0061c084
#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(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
@@ -841,10 +841,10 @@
#define NV50_SOR_DP_CTRL_TRAINING_PATTERN_DISABLED 0x00000000
#define NV50_SOR_DP_CTRL_TRAINING_PATTERN_1 0x01000000
#define NV50_SOR_DP_CTRL_TRAINING_PATTERN_2 0x02000000
-#define NV50_SOR_DP_UNK118(i,l) (0x0061c118 + (i) * 0x800 + (l) * 0x80)
-#define NV50_SOR_DP_UNK120(i,l) (0x0061c120 + (i) * 0x800 + (l) * 0x80)
-#define NV50_SOR_DP_UNK128(i,l) (0x0061c128 + (i) * 0x800 + (l) * 0x80)
-#define NV50_SOR_DP_UNK130(i,l) (0x0061c130 + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_UNK118(i, l) (0x0061c118 + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_UNK120(i, l) (0x0061c120 + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_UNK128(i, l) (0x0061c128 + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_UNK130(i, l) (0x0061c130 + (i) * 0x800 + (l) * 0x80)
#define NV50_PDISPLAY_USER(i) ((i) * 0x1000 + 0x00640000)
#define NV50_PDISPLAY_USER_PUT(i) ((i) * 0x1000 + 0x00640000)
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index 915fbce89595..38ea662568c1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -65,14 +65,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->timer.takedown = nv04_timer_takedown;
engine->fb.init = nv04_fb_init;
engine->fb.takedown = nv04_fb_takedown;
- engine->graph.init = nv04_graph_init;
- engine->graph.takedown = nv04_graph_takedown;
- engine->graph.fifo_access = nv04_graph_fifo_access;
- engine->graph.channel = nv04_graph_channel;
- engine->graph.create_context = nv04_graph_create_context;
- engine->graph.destroy_context = nv04_graph_destroy_context;
- engine->graph.load_context = nv04_graph_load_context;
- engine->graph.unload_context = nv04_graph_unload_context;
engine->fifo.channels = 16;
engine->fifo.init = nv04_fifo_init;
engine->fifo.takedown = nv04_fifo_fini;
@@ -98,8 +90,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.clock_get = nv04_pm_clock_get;
engine->pm.clock_pre = nv04_pm_clock_pre;
engine->pm.clock_set = nv04_pm_clock_set;
- engine->crypt.init = nouveau_stub_init;
- engine->crypt.takedown = nouveau_stub_takedown;
engine->vram.init = nouveau_mem_detect;
engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
@@ -123,15 +113,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fb.init_tile_region = nv10_fb_init_tile_region;
engine->fb.set_tile_region = nv10_fb_set_tile_region;
engine->fb.free_tile_region = nv10_fb_free_tile_region;
- engine->graph.init = nv10_graph_init;
- engine->graph.takedown = nv10_graph_takedown;
- engine->graph.channel = nv10_graph_channel;
- engine->graph.create_context = nv10_graph_create_context;
- engine->graph.destroy_context = nv10_graph_destroy_context;
- engine->graph.fifo_access = nv04_graph_fifo_access;
- engine->graph.load_context = nv10_graph_load_context;
- engine->graph.unload_context = nv10_graph_unload_context;
- engine->graph.set_tile_region = nv10_graph_set_tile_region;
engine->fifo.channels = 32;
engine->fifo.init = nv10_fifo_init;
engine->fifo.takedown = nv04_fifo_fini;
@@ -157,8 +138,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.clock_get = nv04_pm_clock_get;
engine->pm.clock_pre = nv04_pm_clock_pre;
engine->pm.clock_set = nv04_pm_clock_set;
- engine->crypt.init = nouveau_stub_init;
- engine->crypt.takedown = nouveau_stub_takedown;
engine->vram.init = nouveau_mem_detect;
engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
@@ -182,15 +161,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fb.init_tile_region = nv10_fb_init_tile_region;
engine->fb.set_tile_region = nv10_fb_set_tile_region;
engine->fb.free_tile_region = nv10_fb_free_tile_region;
- engine->graph.init = nv20_graph_init;
- engine->graph.takedown = nv20_graph_takedown;
- engine->graph.channel = nv10_graph_channel;
- engine->graph.create_context = nv20_graph_create_context;
- engine->graph.destroy_context = nv20_graph_destroy_context;
- engine->graph.fifo_access = nv04_graph_fifo_access;
- engine->graph.load_context = nv20_graph_load_context;
- engine->graph.unload_context = nv20_graph_unload_context;
- engine->graph.set_tile_region = nv20_graph_set_tile_region;
engine->fifo.channels = 32;
engine->fifo.init = nv10_fifo_init;
engine->fifo.takedown = nv04_fifo_fini;
@@ -216,8 +186,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.clock_get = nv04_pm_clock_get;
engine->pm.clock_pre = nv04_pm_clock_pre;
engine->pm.clock_set = nv04_pm_clock_set;
- engine->crypt.init = nouveau_stub_init;
- engine->crypt.takedown = nouveau_stub_takedown;
engine->vram.init = nouveau_mem_detect;
engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
@@ -241,15 +209,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fb.init_tile_region = nv30_fb_init_tile_region;
engine->fb.set_tile_region = nv10_fb_set_tile_region;
engine->fb.free_tile_region = nv30_fb_free_tile_region;
- engine->graph.init = nv30_graph_init;
- engine->graph.takedown = nv20_graph_takedown;
- engine->graph.fifo_access = nv04_graph_fifo_access;
- engine->graph.channel = nv10_graph_channel;
- engine->graph.create_context = nv20_graph_create_context;
- engine->graph.destroy_context = nv20_graph_destroy_context;
- engine->graph.load_context = nv20_graph_load_context;
- engine->graph.unload_context = nv20_graph_unload_context;
- engine->graph.set_tile_region = nv20_graph_set_tile_region;
engine->fifo.channels = 32;
engine->fifo.init = nv10_fifo_init;
engine->fifo.takedown = nv04_fifo_fini;
@@ -277,8 +236,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.clock_set = nv04_pm_clock_set;
engine->pm.voltage_get = nouveau_voltage_gpio_get;
engine->pm.voltage_set = nouveau_voltage_gpio_set;
- engine->crypt.init = nouveau_stub_init;
- engine->crypt.takedown = nouveau_stub_takedown;
engine->vram.init = nouveau_mem_detect;
engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
@@ -303,15 +260,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->fb.init_tile_region = nv30_fb_init_tile_region;
engine->fb.set_tile_region = nv40_fb_set_tile_region;
engine->fb.free_tile_region = nv30_fb_free_tile_region;
- engine->graph.init = nv40_graph_init;
- engine->graph.takedown = nv40_graph_takedown;
- engine->graph.fifo_access = nv04_graph_fifo_access;
- engine->graph.channel = nv40_graph_channel;
- engine->graph.create_context = nv40_graph_create_context;
- engine->graph.destroy_context = nv40_graph_destroy_context;
- engine->graph.load_context = nv40_graph_load_context;
- engine->graph.unload_context = nv40_graph_unload_context;
- engine->graph.set_tile_region = nv40_graph_set_tile_region;
engine->fifo.channels = 32;
engine->fifo.init = nv40_fifo_init;
engine->fifo.takedown = nv04_fifo_fini;
@@ -340,8 +288,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.voltage_get = nouveau_voltage_gpio_get;
engine->pm.voltage_set = nouveau_voltage_gpio_set;
engine->pm.temp_get = nv40_temp_get;
- engine->crypt.init = nouveau_stub_init;
- engine->crypt.takedown = nouveau_stub_takedown;
engine->vram.init = nouveau_mem_detect;
engine->vram.flags_valid = nouveau_mem_flags_valid;
break;
@@ -368,19 +314,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->timer.takedown = nv04_timer_takedown;
engine->fb.init = nv50_fb_init;
engine->fb.takedown = nv50_fb_takedown;
- engine->graph.init = nv50_graph_init;
- engine->graph.takedown = nv50_graph_takedown;
- engine->graph.fifo_access = nv50_graph_fifo_access;
- engine->graph.channel = nv50_graph_channel;
- engine->graph.create_context = nv50_graph_create_context;
- engine->graph.destroy_context = nv50_graph_destroy_context;
- engine->graph.load_context = nv50_graph_load_context;
- engine->graph.unload_context = nv50_graph_unload_context;
- if (dev_priv->chipset == 0x50 ||
- dev_priv->chipset == 0xac)
- engine->graph.tlb_flush = nv50_graph_tlb_flush;
- else
- engine->graph.tlb_flush = nv84_graph_tlb_flush;
engine->fifo.channels = 128;
engine->fifo.init = nv50_fifo_init;
engine->fifo.takedown = nv50_fifo_takedown;
@@ -432,24 +365,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->pm.temp_get = nv84_temp_get;
else
engine->pm.temp_get = nv40_temp_get;
- switch (dev_priv->chipset) {
- case 0x84:
- case 0x86:
- case 0x92:
- case 0x94:
- case 0x96:
- case 0xa0:
- engine->crypt.init = nv84_crypt_init;
- engine->crypt.takedown = nv84_crypt_fini;
- engine->crypt.create_context = nv84_crypt_create_context;
- engine->crypt.destroy_context = nv84_crypt_destroy_context;
- engine->crypt.tlb_flush = nv84_crypt_tlb_flush;
- break;
- default:
- engine->crypt.init = nouveau_stub_init;
- engine->crypt.takedown = nouveau_stub_takedown;
- break;
- }
engine->vram.init = nv50_vram_init;
engine->vram.get = nv50_vram_new;
engine->vram.put = nv50_vram_del;
@@ -472,14 +387,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->timer.takedown = nv04_timer_takedown;
engine->fb.init = nvc0_fb_init;
engine->fb.takedown = nvc0_fb_takedown;
- engine->graph.init = nvc0_graph_init;
- engine->graph.takedown = nvc0_graph_takedown;
- engine->graph.fifo_access = nvc0_graph_fifo_access;
- engine->graph.channel = nvc0_graph_channel;
- engine->graph.create_context = nvc0_graph_create_context;
- engine->graph.destroy_context = nvc0_graph_destroy_context;
- engine->graph.load_context = nvc0_graph_load_context;
- engine->graph.unload_context = nvc0_graph_unload_context;
engine->fifo.channels = 128;
engine->fifo.init = nvc0_fifo_init;
engine->fifo.takedown = nvc0_fifo_takedown;
@@ -503,8 +410,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
engine->gpio.irq_register = nv50_gpio_irq_register;
engine->gpio.irq_unregister = nv50_gpio_irq_unregister;
engine->gpio.irq_enable = nv50_gpio_irq_enable;
- engine->crypt.init = nouveau_stub_init;
- engine->crypt.takedown = nouveau_stub_takedown;
engine->vram.init = nvc0_vram_init;
engine->vram.get = nvc0_vram_new;
engine->vram.put = nv50_vram_del;
@@ -593,7 +498,7 @@ nouveau_card_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_engine *engine;
- int ret;
+ int ret, e = 0;
vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode);
vga_switcheroo_register_client(dev->pdev, nouveau_switcheroo_set_state,
@@ -658,23 +563,80 @@ nouveau_card_init(struct drm_device *dev)
if (ret)
goto out_timer;
- if (nouveau_noaccel)
- engine->graph.accel_blocked = true;
- else {
- /* PGRAPH */
- ret = engine->graph.init(dev);
- if (ret)
- goto out_fb;
+ switch (dev_priv->card_type) {
+ case NV_04:
+ nv04_graph_create(dev);
+ break;
+ case NV_10:
+ nv10_graph_create(dev);
+ break;
+ case NV_20:
+ case NV_30:
+ nv20_graph_create(dev);
+ break;
+ case NV_40:
+ nv40_graph_create(dev);
+ break;
+ case NV_50:
+ nv50_graph_create(dev);
+ break;
+ case NV_C0:
+ nvc0_graph_create(dev);
+ break;
+ default:
+ break;
+ }
- /* PCRYPT */
- ret = engine->crypt.init(dev);
- if (ret)
- goto out_graph;
+ switch (dev_priv->chipset) {
+ case 0x84:
+ case 0x86:
+ case 0x92:
+ case 0x94:
+ case 0x96:
+ case 0xa0:
+ nv84_crypt_create(dev);
+ break;
+ }
+
+ switch (dev_priv->card_type) {
+ case NV_50:
+ switch (dev_priv->chipset) {
+ case 0xa3:
+ case 0xa5:
+ case 0xa8:
+ case 0xaf:
+ nva3_copy_create(dev);
+ break;
+ }
+ break;
+ case NV_C0:
+ nvc0_copy_create(dev, 0);
+ nvc0_copy_create(dev, 1);
+ break;
+ default:
+ break;
+ }
+
+ if (dev_priv->card_type == NV_40)
+ nv40_mpeg_create(dev);
+ else
+ if (dev_priv->card_type == NV_50 &&
+ (dev_priv->chipset < 0x98 || dev_priv->chipset == 0xa0))
+ nv50_mpeg_create(dev);
+
+ if (!nouveau_noaccel) {
+ for (e = 0; e < NVOBJ_ENGINE_NR; e++) {
+ if (dev_priv->eng[e]) {
+ ret = dev_priv->eng[e]->init(dev, e);
+ if (ret)
+ goto out_engine;
+ }
+ }
/* PFIFO */
ret = engine->fifo.init(dev);
if (ret)
- goto out_crypt;
+ goto out_engine;
}
ret = engine->display.create(dev);
@@ -691,7 +653,7 @@ nouveau_card_init(struct drm_device *dev)
/* what about PVIDEO/PCRTC/PRAMDAC etc? */
- if (!engine->graph.accel_blocked) {
+ if (dev_priv->eng[NVOBJ_ENGINE_GR]) {
ret = nouveau_fence_init(dev);
if (ret)
goto out_irq;
@@ -715,13 +677,16 @@ out_vblank:
out_fifo:
if (!nouveau_noaccel)
engine->fifo.takedown(dev);
-out_crypt:
- if (!nouveau_noaccel)
- engine->crypt.takedown(dev);
-out_graph:
- if (!nouveau_noaccel)
- engine->graph.takedown(dev);
-out_fb:
+out_engine:
+ if (!nouveau_noaccel) {
+ for (e = e - 1; e >= 0; e--) {
+ if (!dev_priv->eng[e])
+ continue;
+ dev_priv->eng[e]->fini(dev, e);
+ dev_priv->eng[e]->destroy(dev,e );
+ }
+ }
+
engine->fb.takedown(dev);
out_timer:
engine->timer.takedown(dev);
@@ -751,16 +716,21 @@ 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;
+ int e;
- if (!engine->graph.accel_blocked) {
+ if (dev_priv->channel) {
nouveau_fence_fini(dev);
nouveau_channel_put_unlocked(&dev_priv->channel);
}
if (!nouveau_noaccel) {
engine->fifo.takedown(dev);
- engine->crypt.takedown(dev);
- engine->graph.takedown(dev);
+ for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {
+ if (dev_priv->eng[e]) {
+ dev_priv->eng[e]->fini(dev, e);
+ dev_priv->eng[e]->destroy(dev,e );
+ }
+ }
}
engine->fb.takedown(dev);
engine->timer.takedown(dev);
@@ -866,7 +836,7 @@ static int nouveau_remove_conflicting_drivers(struct drm_device *dev)
#ifdef CONFIG_X86
primary = dev->pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
#endif
-
+
remove_conflicting_framebuffers(dev_priv->apertures, "nouveaufb", primary);
return 0;
}
@@ -918,11 +888,13 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
/* Time to determine the card architecture */
reg0 = nv_rd32(dev, NV03_PMC_BOOT_0);
+ dev_priv->stepping = 0; /* XXX: add stepping for pre-NV10? */
/* We're dealing with >=NV10 */
if ((reg0 & 0x0f000000) > 0) {
/* Bit 27-20 contain the architecture in hex */
dev_priv->chipset = (reg0 & 0xff00000) >> 20;
+ dev_priv->stepping = (reg0 & 0xff);
/* NV04 or NV05 */
} else if ((reg0 & 0xff00fff0) == 0x20004000) {
if (reg0 & 0x00f00000)
diff --git a/drivers/gpu/drm/nouveau/nouveau_vm.h b/drivers/gpu/drm/nouveau/nouveau_vm.h
index 2e06b55cfdc1..c48a9fc2b47b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_vm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_vm.h
@@ -53,8 +53,7 @@ struct nouveau_vm {
int refcount;
struct list_head pgd_list;
- atomic_t pgraph_refs;
- atomic_t pcrypt_refs;
+ atomic_t engref[16];
struct nouveau_vm_pgt *pgt;
u32 fpde;
diff --git a/drivers/gpu/drm/nouveau/nouveau_volt.c b/drivers/gpu/drm/nouveau/nouveau_volt.c
index 04fdc00a67d5..75e872741d92 100644
--- a/drivers/gpu/drm/nouveau/nouveau_volt.c
+++ b/drivers/gpu/drm/nouveau/nouveau_volt.c
@@ -159,8 +159,16 @@ nouveau_volt_init(struct drm_device *dev)
headerlen = volt[1];
recordlen = volt[2];
entries = volt[3];
- vidshift = hweight8(volt[5]);
vidmask = volt[4];
+ /* no longer certain what volt[5] is, if it's related to
+ * the vid shift then it's definitely not a function of
+ * how many bits are set.
+ *
+ * after looking at a number of nva3+ vbios images, they
+ * all seem likely to have a static shift of 2.. lets
+ * go with that for now until proven otherwise.
+ */
+ vidshift = 2;
break;
default:
NV_WARN(dev, "voltage table 0x%02x unknown\n", volt[0]);
diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c
index 748b9d9c2949..3c78bc81357e 100644
--- a/drivers/gpu/drm/nouveau/nv04_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv04_crtc.c
@@ -790,8 +790,7 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
if (atomic) {
drm_fb = passed_fb;
fb = nouveau_framebuffer(passed_fb);
- }
- else {
+ } else {
/* If not atomic, we can go ahead and pin, and unpin the
* old fb we were passed.
*/
@@ -944,14 +943,14 @@ nv04_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
struct drm_gem_object *gem;
int ret = 0;
- if (width != 64 || height != 64)
- return -EINVAL;
-
if (!buffer_handle) {
nv_crtc->cursor.hide(nv_crtc, true);
return 0;
}
+ if (width != 64 || height != 64)
+ return -EINVAL;
+
gem = drm_gem_object_lookup(dev, file_priv, buffer_handle);
if (!gem)
return -ENOENT;
diff --git a/drivers/gpu/drm/nouveau/nv04_graph.c b/drivers/gpu/drm/nouveau/nv04_graph.c
index af75015068d6..3626ee7db3ba 100644
--- a/drivers/gpu/drm/nouveau/nv04_graph.c
+++ b/drivers/gpu/drm/nouveau/nv04_graph.c
@@ -28,9 +28,11 @@
#include "nouveau_drv.h"
#include "nouveau_hw.h"
#include "nouveau_util.h"
+#include "nouveau_ramht.h"
-static int nv04_graph_register(struct drm_device *dev);
-static void nv04_graph_isr(struct drm_device *dev);
+struct nv04_graph_engine {
+ struct nouveau_exec_engine base;
+};
static uint32_t nv04_graph_ctx_regs[] = {
0x0040053c,
@@ -350,7 +352,7 @@ struct graph_state {
uint32_t nv04[ARRAY_SIZE(nv04_graph_ctx_regs)];
};
-struct nouveau_channel *
+static struct nouveau_channel *
nv04_graph_channel(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -365,26 +367,6 @@ nv04_graph_channel(struct drm_device *dev)
return dev_priv->channels.ptr[chid];
}
-static void
-nv04_graph_context_switch(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct nouveau_channel *chan = NULL;
- int chid;
-
- nouveau_wait_for_idle(dev);
-
- /* If previous context is valid, we need to save it */
- pgraph->unload_context(dev);
-
- /* Load context for next channel */
- chid = dev_priv->engine.fifo.channel_id(dev);
- chan = dev_priv->channels.ptr[chid];
- if (chan)
- nv04_graph_load_context(chan);
-}
-
static uint32_t *ctx_reg(struct graph_state *ctx, uint32_t reg)
{
int i;
@@ -397,48 +379,11 @@ static uint32_t *ctx_reg(struct graph_state *ctx, uint32_t reg)
return NULL;
}
-int nv04_graph_create_context(struct nouveau_channel *chan)
-{
- struct graph_state *pgraph_ctx;
- NV_DEBUG(chan->dev, "nv04_graph_context_create %d\n", chan->id);
-
- chan->pgraph_ctx = pgraph_ctx = kzalloc(sizeof(*pgraph_ctx),
- GFP_KERNEL);
- if (pgraph_ctx == NULL)
- return -ENOMEM;
-
- *ctx_reg(pgraph_ctx, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31;
-
- return 0;
-}
-
-void nv04_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;
- struct graph_state *pgraph_ctx = chan->pgraph_ctx;
- unsigned long flags;
-
- spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
- pgraph->fifo_access(dev, false);
-
- /* Unload the context if it's the currently active one */
- if (pgraph->channel(dev) == chan)
- pgraph->unload_context(dev);
-
- /* Free the context resources */
- kfree(pgraph_ctx);
- chan->pgraph_ctx = NULL;
-
- pgraph->fifo_access(dev, true);
- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-}
-
-int nv04_graph_load_context(struct nouveau_channel *chan)
+static int
+nv04_graph_load_context(struct nouveau_channel *chan)
{
+ struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
struct drm_device *dev = chan->dev;
- struct graph_state *pgraph_ctx = chan->pgraph_ctx;
uint32_t tmp;
int i;
@@ -456,20 +401,19 @@ int nv04_graph_load_context(struct nouveau_channel *chan)
return 0;
}
-int
+static int
nv04_graph_unload_context(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
struct nouveau_channel *chan = NULL;
struct graph_state *ctx;
uint32_t tmp;
int i;
- chan = pgraph->channel(dev);
+ chan = nv04_graph_channel(dev);
if (!chan)
return 0;
- ctx = chan->pgraph_ctx;
+ ctx = chan->engctx[NVOBJ_ENGINE_GR];
for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++)
ctx->nv04[i] = nv_rd32(dev, nv04_graph_ctx_regs[i]);
@@ -481,23 +425,85 @@ nv04_graph_unload_context(struct drm_device *dev)
return 0;
}
-int nv04_graph_init(struct drm_device *dev)
+static int
+nv04_graph_context_new(struct nouveau_channel *chan, int engine)
{
+ struct graph_state *pgraph_ctx;
+ NV_DEBUG(chan->dev, "nv04_graph_context_create %d\n", chan->id);
+
+ pgraph_ctx = kzalloc(sizeof(*pgraph_ctx), GFP_KERNEL);
+ if (pgraph_ctx == NULL)
+ return -ENOMEM;
+
+ *ctx_reg(pgraph_ctx, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31;
+
+ chan->engctx[engine] = pgraph_ctx;
+ return 0;
+}
+
+static void
+nv04_graph_context_del(struct nouveau_channel *chan, int engine)
+{
+ struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t tmp;
+ struct graph_state *pgraph_ctx = chan->engctx[engine];
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ nv04_graph_fifo_access(dev, false);
+
+ /* Unload the context if it's the currently active one */
+ if (nv04_graph_channel(dev) == chan)
+ nv04_graph_unload_context(dev);
+
+ nv04_graph_fifo_access(dev, true);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+ /* Free the context resources */
+ kfree(pgraph_ctx);
+ chan->engctx[engine] = NULL;
+}
+
+int
+nv04_graph_object_new(struct nouveau_channel *chan, int engine,
+ u32 handle, u16 class)
+{
+ struct drm_device *dev = chan->dev;
+ struct nouveau_gpuobj *obj = NULL;
int ret;
+ ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+ if (ret)
+ return ret;
+ obj->engine = 1;
+ obj->class = class;
+
+#ifdef __BIG_ENDIAN
+ nv_wo32(obj, 0x00, 0x00080000 | class);
+#else
+ nv_wo32(obj, 0x00, class);
+#endif
+ nv_wo32(obj, 0x04, 0x00000000);
+ nv_wo32(obj, 0x08, 0x00000000);
+ nv_wo32(obj, 0x0c, 0x00000000);
+
+ ret = nouveau_ramht_insert(chan, handle, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
+ return ret;
+}
+
+static int
+nv04_graph_init(struct drm_device *dev, int engine)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ uint32_t tmp;
+
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);
- ret = nv04_graph_register(dev);
- if (ret)
- return ret;
-
/* Enable PGRAPH interrupts */
- nouveau_irq_register(dev, 12, nv04_graph_isr);
nv_wr32(dev, NV03_PGRAPH_INTR, 0xFFFFFFFF);
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
@@ -507,7 +513,7 @@ int nv04_graph_init(struct drm_device *dev)
nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/
nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x1231c000);
/*1231C000 blob, 001 haiku*/
- //*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/
+ /*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/
nv_wr32(dev, NV04_PGRAPH_DEBUG_1, 0x72111100);
/*0x72111100 blob , 01 haiku*/
/*nv_wr32(dev, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/
@@ -531,10 +537,12 @@ int nv04_graph_init(struct drm_device *dev)
return 0;
}
-void nv04_graph_takedown(struct drm_device *dev)
+static int
+nv04_graph_fini(struct drm_device *dev, int engine)
{
+ nv04_graph_unload_context(dev);
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
- nouveau_irq_unregister(dev, 12);
+ return 0;
}
void
@@ -969,13 +977,138 @@ nv04_graph_mthd_bind_chroma(struct nouveau_channel *chan,
return 1;
}
-static int
-nv04_graph_register(struct drm_device *dev)
+static struct nouveau_bitfield nv04_graph_intr[] = {
+ { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
+ {}
+};
+
+static struct nouveau_bitfield nv04_graph_nstatus[] = {
+ { NV04_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" },
+ { NV04_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" },
+ { NV04_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" },
+ { NV04_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" },
+ {}
+};
+
+struct nouveau_bitfield nv04_graph_nsource[] = {
+ { NV03_PGRAPH_NSOURCE_NOTIFICATION, "NOTIFICATION" },
+ { NV03_PGRAPH_NSOURCE_DATA_ERROR, "DATA_ERROR" },
+ { NV03_PGRAPH_NSOURCE_PROTECTION_ERROR, "PROTECTION_ERROR" },
+ { NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION, "RANGE_EXCEPTION" },
+ { NV03_PGRAPH_NSOURCE_LIMIT_COLOR, "LIMIT_COLOR" },
+ { NV03_PGRAPH_NSOURCE_LIMIT_ZETA, "LIMIT_ZETA" },
+ { NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD, "ILLEGAL_MTHD" },
+ { NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION, "DMA_R_PROTECTION" },
+ { NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION, "DMA_W_PROTECTION" },
+ { NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION, "FORMAT_EXCEPTION" },
+ { NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION, "PATCH_EXCEPTION" },
+ { NV03_PGRAPH_NSOURCE_STATE_INVALID, "STATE_INVALID" },
+ { NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY, "DOUBLE_NOTIFY" },
+ { NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE, "NOTIFY_IN_USE" },
+ { NV03_PGRAPH_NSOURCE_METHOD_CNT, "METHOD_CNT" },
+ { NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION, "BFR_NOTIFICATION" },
+ { NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" },
+ { NV03_PGRAPH_NSOURCE_DMA_WIDTH_A, "DMA_WIDTH_A" },
+ { NV03_PGRAPH_NSOURCE_DMA_WIDTH_B, "DMA_WIDTH_B" },
+ {}
+};
+
+static void
+nv04_graph_context_switch(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_channel *chan = NULL;
+ int chid;
- if (dev_priv->engine.graph.registered)
- return 0;
+ nouveau_wait_for_idle(dev);
+
+ /* If previous context is valid, we need to save it */
+ nv04_graph_unload_context(dev);
+
+ /* Load context for next channel */
+ chid = dev_priv->engine.fifo.channel_id(dev);
+ chan = dev_priv->channels.ptr[chid];
+ if (chan)
+ nv04_graph_load_context(chan);
+}
+
+static void
+nv04_graph_isr(struct drm_device *dev)
+{
+ u32 stat;
+
+ while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) {
+ u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
+ u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
+ u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
+ u32 chid = (addr & 0x0f000000) >> 24;
+ u32 subc = (addr & 0x0000e000) >> 13;
+ u32 mthd = (addr & 0x00001ffc);
+ u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
+ u32 class = nv_rd32(dev, 0x400180 + subc * 4) & 0xff;
+ u32 show = stat;
+
+ if (stat & NV_PGRAPH_INTR_NOTIFY) {
+ if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
+ if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data))
+ show &= ~NV_PGRAPH_INTR_NOTIFY;
+ }
+ }
+
+ if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
+ nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
+ stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+ show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+ nv04_graph_context_switch(dev);
+ }
+
+ nv_wr32(dev, NV03_PGRAPH_INTR, stat);
+ nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001);
+
+ if (show && nouveau_ratelimit()) {
+ NV_INFO(dev, "PGRAPH -");
+ nouveau_bitfield_print(nv04_graph_intr, show);
+ printk(" nsource:");
+ nouveau_bitfield_print(nv04_graph_nsource, nsource);
+ printk(" nstatus:");
+ nouveau_bitfield_print(nv04_graph_nstatus, nstatus);
+ printk("\n");
+ NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x "
+ "mthd 0x%04x data 0x%08x\n",
+ chid, subc, class, mthd, data);
+ }
+ }
+}
+
+static void
+nv04_graph_destroy(struct drm_device *dev, int engine)
+{
+ struct nv04_graph_engine *pgraph = nv_engine(dev, engine);
+
+ nouveau_irq_unregister(dev, 12);
+
+ NVOBJ_ENGINE_DEL(dev, GR);
+ kfree(pgraph);
+}
+
+int
+nv04_graph_create(struct drm_device *dev)
+{
+ struct nv04_graph_engine *pgraph;
+
+ pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
+ if (!pgraph)
+ return -ENOMEM;
+
+ pgraph->base.destroy = nv04_graph_destroy;
+ pgraph->base.init = nv04_graph_init;
+ pgraph->base.fini = nv04_graph_fini;
+ pgraph->base.context_new = nv04_graph_context_new;
+ pgraph->base.context_del = nv04_graph_context_del;
+ pgraph->base.object_new = nv04_graph_object_new;
+
+ NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
+ nouveau_irq_register(dev, 12, nv04_graph_isr);
/* dvd subpicture */
NVOBJ_CLASS(dev, 0x0038, GR);
@@ -1222,93 +1355,5 @@ nv04_graph_register(struct drm_device *dev)
NVOBJ_CLASS(dev, 0x506e, SW);
NVOBJ_MTHD (dev, 0x506e, 0x0150, nv04_graph_mthd_set_ref);
NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
- dev_priv->engine.graph.registered = true;
return 0;
-};
-
-static struct nouveau_bitfield nv04_graph_intr[] = {
- { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
- {}
-};
-
-static struct nouveau_bitfield nv04_graph_nstatus[] =
-{
- { NV04_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" },
- { NV04_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" },
- { NV04_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" },
- { NV04_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" },
- {}
-};
-
-struct nouveau_bitfield nv04_graph_nsource[] =
-{
- { NV03_PGRAPH_NSOURCE_NOTIFICATION, "NOTIFICATION" },
- { NV03_PGRAPH_NSOURCE_DATA_ERROR, "DATA_ERROR" },
- { NV03_PGRAPH_NSOURCE_PROTECTION_ERROR, "PROTECTION_ERROR" },
- { NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION, "RANGE_EXCEPTION" },
- { NV03_PGRAPH_NSOURCE_LIMIT_COLOR, "LIMIT_COLOR" },
- { NV03_PGRAPH_NSOURCE_LIMIT_ZETA, "LIMIT_ZETA" },
- { NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD, "ILLEGAL_MTHD" },
- { NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION, "DMA_R_PROTECTION" },
- { NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION, "DMA_W_PROTECTION" },
- { NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION, "FORMAT_EXCEPTION" },
- { NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION, "PATCH_EXCEPTION" },
- { NV03_PGRAPH_NSOURCE_STATE_INVALID, "STATE_INVALID" },
- { NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY, "DOUBLE_NOTIFY" },
- { NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE, "NOTIFY_IN_USE" },
- { NV03_PGRAPH_NSOURCE_METHOD_CNT, "METHOD_CNT" },
- { NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION, "BFR_NOTIFICATION" },
- { NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" },
- { NV03_PGRAPH_NSOURCE_DMA_WIDTH_A, "DMA_WIDTH_A" },
- { NV03_PGRAPH_NSOURCE_DMA_WIDTH_B, "DMA_WIDTH_B" },
- {}
-};
-
-static void
-nv04_graph_isr(struct drm_device *dev)
-{
- u32 stat;
-
- while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) {
- u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
- u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
- u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
- u32 chid = (addr & 0x0f000000) >> 24;
- u32 subc = (addr & 0x0000e000) >> 13;
- u32 mthd = (addr & 0x00001ffc);
- u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
- u32 class = nv_rd32(dev, 0x400180 + subc * 4) & 0xff;
- u32 show = stat;
-
- if (stat & NV_PGRAPH_INTR_NOTIFY) {
- if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
- if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data))
- show &= ~NV_PGRAPH_INTR_NOTIFY;
- }
- }
-
- if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
- nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
- stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
- show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
- nv04_graph_context_switch(dev);
- }
-
- nv_wr32(dev, NV03_PGRAPH_INTR, stat);
- nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001);
-
- if (show && nouveau_ratelimit()) {
- NV_INFO(dev, "PGRAPH -");
- nouveau_bitfield_print(nv04_graph_intr, show);
- printk(" nsource:");
- nouveau_bitfield_print(nv04_graph_nsource, nsource);
- printk(" nstatus:");
- nouveau_bitfield_print(nv04_graph_nstatus, nstatus);
- printk("\n");
- NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x "
- "mthd 0x%04x data 0x%08x\n",
- chid, subc, class, mthd, data);
- }
- }
}
diff --git a/drivers/gpu/drm/nouveau/nv04_instmem.c b/drivers/gpu/drm/nouveau/nv04_instmem.c
index b8e3edb5c063..b8611b955313 100644
--- a/drivers/gpu/drm/nouveau/nv04_instmem.c
+++ b/drivers/gpu/drm/nouveau/nv04_instmem.c
@@ -95,6 +95,9 @@ nv04_instmem_takedown(struct drm_device *dev)
nouveau_ramht_ref(NULL, &dev_priv->ramht, NULL);
nouveau_gpuobj_ref(NULL, &dev_priv->ramro);
nouveau_gpuobj_ref(NULL, &dev_priv->ramfc);
+
+ if (drm_mm_initialized(&dev_priv->ramin_heap))
+ drm_mm_takedown(&dev_priv->ramin_heap);
}
int
diff --git a/drivers/gpu/drm/nouveau/nv10_graph.c b/drivers/gpu/drm/nouveau/nv10_graph.c
index 8c92edb7bbcd..0930c6cb88e0 100644
--- a/drivers/gpu/drm/nouveau/nv10_graph.c
+++ b/drivers/gpu/drm/nouveau/nv10_graph.c
@@ -28,10 +28,9 @@
#include "nouveau_drv.h"
#include "nouveau_util.h"
-static int nv10_graph_register(struct drm_device *);
-static void nv10_graph_isr(struct drm_device *);
-
-#define NV10_FIFO_NUMBER 32
+struct nv10_graph_engine {
+ struct nouveau_exec_engine base;
+};
struct pipe_state {
uint32_t pipe_0x0000[0x040/4];
@@ -414,9 +413,9 @@ struct graph_state {
static void nv10_graph_save_pipe(struct nouveau_channel *chan)
{
- struct drm_device *dev = chan->dev;
- struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+ struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
struct pipe_state *pipe = &pgraph_ctx->pipe_state;
+ struct drm_device *dev = chan->dev;
PIPE_SAVE(dev, pipe->pipe_0x4400, 0x4400);
PIPE_SAVE(dev, pipe->pipe_0x0200, 0x0200);
@@ -432,9 +431,9 @@ static void nv10_graph_save_pipe(struct nouveau_channel *chan)
static void nv10_graph_load_pipe(struct nouveau_channel *chan)
{
- struct drm_device *dev = chan->dev;
- struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+ struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
struct pipe_state *pipe = &pgraph_ctx->pipe_state;
+ struct drm_device *dev = chan->dev;
uint32_t xfmode0, xfmode1;
int i;
@@ -482,9 +481,9 @@ static void nv10_graph_load_pipe(struct nouveau_channel *chan)
static void nv10_graph_create_pipe(struct nouveau_channel *chan)
{
- struct drm_device *dev = chan->dev;
- struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+ struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
struct pipe_state *fifo_pipe_state = &pgraph_ctx->pipe_state;
+ struct drm_device *dev = chan->dev;
uint32_t *fifo_pipe_state_addr;
int i;
#define PIPE_INIT(addr) \
@@ -661,8 +660,6 @@ static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
uint32_t inst)
{
struct drm_device *dev = chan->dev;
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
uint32_t st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4];
uint32_t ctx_user, ctx_switch[5];
int i, subchan = -1;
@@ -711,8 +708,8 @@ static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
0x2c000000 | chan->id << 20 | subchan << 16 | 0x18c);
nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, inst);
nv_mask(dev, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000);
- pgraph->fifo_access(dev, true);
- pgraph->fifo_access(dev, false);
+ nv04_graph_fifo_access(dev, true);
+ nv04_graph_fifo_access(dev, false);
/* Restore the FIFO state */
for (i = 0; i < ARRAY_SIZE(fifo); i++)
@@ -729,11 +726,12 @@ static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
nv_wr32(dev, NV10_PGRAPH_CTX_USER, ctx_user);
}
-int nv10_graph_load_context(struct nouveau_channel *chan)
+static int
+nv10_graph_load_context(struct nouveau_channel *chan)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+ struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
uint32_t tmp;
int i;
@@ -757,21 +755,20 @@ int nv10_graph_load_context(struct nouveau_channel *chan)
return 0;
}
-int
+static int
nv10_graph_unload_context(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
struct nouveau_channel *chan;
struct graph_state *ctx;
uint32_t tmp;
int i;
- chan = pgraph->channel(dev);
+ chan = nv10_graph_channel(dev);
if (!chan)
return 0;
- ctx = chan->pgraph_ctx;
+ ctx = chan->engctx[NVOBJ_ENGINE_GR];
for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++)
ctx->nv10[i] = nv_rd32(dev, nv10_graph_ctx_regs[i]);
@@ -805,7 +802,7 @@ nv10_graph_context_switch(struct drm_device *dev)
/* Load context for next channel */
chid = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f;
chan = dev_priv->channels.ptr[chid];
- if (chan && chan->pgraph_ctx)
+ if (chan && chan->engctx[NVOBJ_ENGINE_GR])
nv10_graph_load_context(chan);
}
@@ -836,7 +833,8 @@ nv10_graph_channel(struct drm_device *dev)
return dev_priv->channels.ptr[chid];
}
-int nv10_graph_create_context(struct nouveau_channel *chan)
+static int
+nv10_graph_context_new(struct nouveau_channel *chan, int engine)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -844,11 +842,10 @@ int nv10_graph_create_context(struct nouveau_channel *chan)
NV_DEBUG(dev, "nv10_graph_context_create %d\n", chan->id);
- chan->pgraph_ctx = pgraph_ctx = kzalloc(sizeof(*pgraph_ctx),
- GFP_KERNEL);
+ pgraph_ctx = kzalloc(sizeof(*pgraph_ctx), GFP_KERNEL);
if (pgraph_ctx == NULL)
return -ENOMEM;
-
+ chan->engctx[engine] = pgraph_ctx;
NV_WRITE_CTX(0x00400e88, 0x08000000);
NV_WRITE_CTX(0x00400e9c, 0x4b7fffff);
@@ -873,30 +870,30 @@ int nv10_graph_create_context(struct nouveau_channel *chan)
return 0;
}
-void nv10_graph_destroy_context(struct nouveau_channel *chan)
+static void
+nv10_graph_context_del(struct nouveau_channel *chan, int engine)
{
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 graph_state *pgraph_ctx = chan->pgraph_ctx;
+ struct graph_state *pgraph_ctx = chan->engctx[engine];
unsigned long flags;
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
- pgraph->fifo_access(dev, false);
+ nv04_graph_fifo_access(dev, false);
/* Unload the context if it's the currently active one */
- if (pgraph->channel(dev) == chan)
- pgraph->unload_context(dev);
+ if (nv10_graph_channel(dev) == chan)
+ nv10_graph_unload_context(dev);
+
+ nv04_graph_fifo_access(dev, true);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
/* Free the context resources */
+ chan->engctx[engine] = NULL;
kfree(pgraph_ctx);
- chan->pgraph_ctx = NULL;
-
- pgraph->fifo_access(dev, true);
- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
}
-void
+static void
nv10_graph_set_tile_region(struct drm_device *dev, int i)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -907,22 +904,18 @@ nv10_graph_set_tile_region(struct drm_device *dev, int i)
nv_wr32(dev, NV10_PGRAPH_TILE(i), tile->addr);
}
-int nv10_graph_init(struct drm_device *dev)
+static int
+nv10_graph_init(struct drm_device *dev, int engine)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t tmp;
- int ret, i;
+ u32 tmp;
+ int i;
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);
- ret = nv10_graph_register(dev);
- if (ret)
- return ret;
-
- nouveau_irq_register(dev, 12, nv10_graph_isr);
nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF);
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
@@ -963,18 +956,20 @@ int nv10_graph_init(struct drm_device *dev)
return 0;
}
-void nv10_graph_takedown(struct drm_device *dev)
+static int
+nv10_graph_fini(struct drm_device *dev, int engine)
{
+ nv10_graph_unload_context(dev);
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
- nouveau_irq_unregister(dev, 12);
+ return 0;
}
static int
nv17_graph_mthd_lma_window(struct nouveau_channel *chan,
u32 class, u32 mthd, u32 data)
{
+ struct graph_state *ctx = chan->engctx[NVOBJ_ENGINE_GR];
struct drm_device *dev = chan->dev;
- struct graph_state *ctx = chan->pgraph_ctx;
struct pipe_state *pipe = &ctx->pipe_state;
uint32_t pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3];
uint32_t xfmode0, xfmode1;
@@ -1061,64 +1056,13 @@ nv17_graph_mthd_lma_enable(struct nouveau_channel *chan,
return 0;
}
-static int
-nv10_graph_register(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- if (dev_priv->engine.graph.registered)
- return 0;
-
- NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
- NVOBJ_CLASS(dev, 0x0030, GR); /* null */
- NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
- NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
- NVOBJ_CLASS(dev, 0x005f, GR); /* imageblit */
- NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
- NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
- NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
- NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
- NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
- NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
- NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
- NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
- NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
- NVOBJ_CLASS(dev, 0x0052, GR); /* swzsurf */
- NVOBJ_CLASS(dev, 0x0093, GR); /* surf3d */
- NVOBJ_CLASS(dev, 0x0094, GR); /* tex_tri */
- NVOBJ_CLASS(dev, 0x0095, GR); /* multitex_tri */
-
- /* celcius */
- if (dev_priv->chipset <= 0x10) {
- NVOBJ_CLASS(dev, 0x0056, GR);
- } else
- if (dev_priv->chipset < 0x17 || dev_priv->chipset == 0x1a) {
- NVOBJ_CLASS(dev, 0x0096, GR);
- } else {
- NVOBJ_CLASS(dev, 0x0099, GR);
- NVOBJ_MTHD (dev, 0x0099, 0x1638, nv17_graph_mthd_lma_window);
- NVOBJ_MTHD (dev, 0x0099, 0x163c, nv17_graph_mthd_lma_window);
- NVOBJ_MTHD (dev, 0x0099, 0x1640, nv17_graph_mthd_lma_window);
- NVOBJ_MTHD (dev, 0x0099, 0x1644, nv17_graph_mthd_lma_window);
- NVOBJ_MTHD (dev, 0x0099, 0x1658, nv17_graph_mthd_lma_enable);
- }
-
- /* nvsw */
- NVOBJ_CLASS(dev, 0x506e, SW);
- NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
- dev_priv->engine.graph.registered = true;
- return 0;
-}
-
struct nouveau_bitfield nv10_graph_intr[] = {
{ NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
{ NV_PGRAPH_INTR_ERROR, "ERROR" },
{}
};
-struct nouveau_bitfield nv10_graph_nstatus[] =
-{
+struct nouveau_bitfield nv10_graph_nstatus[] = {
{ NV10_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" },
{ NV10_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" },
{ NV10_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" },
@@ -1173,3 +1117,73 @@ nv10_graph_isr(struct drm_device *dev)
}
}
}
+
+static void
+nv10_graph_destroy(struct drm_device *dev, int engine)
+{
+ struct nv10_graph_engine *pgraph = nv_engine(dev, engine);
+
+ nouveau_irq_unregister(dev, 12);
+ kfree(pgraph);
+}
+
+int
+nv10_graph_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv10_graph_engine *pgraph;
+
+ pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
+ if (!pgraph)
+ return -ENOMEM;
+
+ pgraph->base.destroy = nv10_graph_destroy;
+ pgraph->base.init = nv10_graph_init;
+ pgraph->base.fini = nv10_graph_fini;
+ pgraph->base.context_new = nv10_graph_context_new;
+ pgraph->base.context_del = nv10_graph_context_del;
+ pgraph->base.object_new = nv04_graph_object_new;
+ pgraph->base.set_tile_region = nv10_graph_set_tile_region;
+
+ NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
+ nouveau_irq_register(dev, 12, nv10_graph_isr);
+
+ /* nvsw */
+ NVOBJ_CLASS(dev, 0x506e, SW);
+ NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
+
+ NVOBJ_CLASS(dev, 0x0030, GR); /* null */
+ NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
+ NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
+ NVOBJ_CLASS(dev, 0x005f, GR); /* imageblit */
+ NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
+ NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
+ NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
+ NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
+ NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
+ NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
+ NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
+ NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
+ NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
+ NVOBJ_CLASS(dev, 0x0052, GR); /* swzsurf */
+ NVOBJ_CLASS(dev, 0x0093, GR); /* surf3d */
+ NVOBJ_CLASS(dev, 0x0094, GR); /* tex_tri */
+ NVOBJ_CLASS(dev, 0x0095, GR); /* multitex_tri */
+
+ /* celcius */
+ if (dev_priv->chipset <= 0x10) {
+ NVOBJ_CLASS(dev, 0x0056, GR);
+ } else
+ if (dev_priv->chipset < 0x17 || dev_priv->chipset == 0x1a) {
+ NVOBJ_CLASS(dev, 0x0096, GR);
+ } else {
+ NVOBJ_CLASS(dev, 0x0099, GR);
+ NVOBJ_MTHD (dev, 0x0099, 0x1638, nv17_graph_mthd_lma_window);
+ NVOBJ_MTHD (dev, 0x0099, 0x163c, nv17_graph_mthd_lma_window);
+ NVOBJ_MTHD (dev, 0x0099, 0x1640, nv17_graph_mthd_lma_window);
+ NVOBJ_MTHD (dev, 0x0099, 0x1644, nv17_graph_mthd_lma_window);
+ NVOBJ_MTHD (dev, 0x0099, 0x1658, nv17_graph_mthd_lma_enable);
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nv20_graph.c b/drivers/gpu/drm/nouveau/nv20_graph.c
index 8464b76798d5..affc7d7dd029 100644
--- a/drivers/gpu/drm/nouveau/nv20_graph.c
+++ b/drivers/gpu/drm/nouveau/nv20_graph.c
@@ -24,6 +24,14 @@
*
*/
+struct nv20_graph_engine {
+ struct nouveau_exec_engine base;
+ struct nouveau_gpuobj *ctxtab;
+ void (*grctx_init)(struct nouveau_gpuobj *);
+ u32 grctx_size;
+ u32 grctx_user;
+};
+
#define NV20_GRCTX_SIZE (3580*4)
#define NV25_GRCTX_SIZE (3529*4)
#define NV2A_GRCTX_SIZE (3500*4)
@@ -32,12 +40,54 @@
#define NV34_GRCTX_SIZE (18140)
#define NV35_36_GRCTX_SIZE (22396)
-static int nv20_graph_register(struct drm_device *);
-static int nv30_graph_register(struct drm_device *);
-static void nv20_graph_isr(struct drm_device *);
+int
+nv20_graph_unload_context(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
+ struct nouveau_channel *chan;
+ struct nouveau_gpuobj *grctx;
+ u32 tmp;
+
+ chan = nv10_graph_channel(dev);
+ if (!chan)
+ return 0;
+ grctx = chan->engctx[NVOBJ_ENGINE_GR];
+
+ nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, grctx->pinst >> 4);
+ nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
+ NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE);
+
+ nouveau_wait_for_idle(dev);
+
+ nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
+ tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;
+ tmp |= (pfifo->channels - 1) << 24;
+ nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp);
+ return 0;
+}
+
+static void
+nv20_graph_rdi(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ int i, writecount = 32;
+ uint32_t rdi_index = 0x2c80000;
+
+ if (dev_priv->chipset == 0x20) {
+ rdi_index = 0x3d0000;
+ writecount = 15;
+ }
+
+ nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, rdi_index);
+ for (i = 0; i < writecount; i++)
+ nv_wr32(dev, NV10_PGRAPH_RDI_DATA, 0);
+
+ nouveau_wait_for_idle(dev);
+}
static void
-nv20_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv20_graph_context_init(struct nouveau_gpuobj *ctx)
{
int i;
@@ -87,7 +137,7 @@ nv20_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
}
static void
-nv25_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv25_graph_context_init(struct nouveau_gpuobj *ctx)
{
int i;
@@ -146,7 +196,7 @@ nv25_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
}
static void
-nv2a_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv2a_graph_context_init(struct nouveau_gpuobj *ctx)
{
int i;
@@ -196,7 +246,7 @@ nv2a_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
}
static void
-nv30_31_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv30_31_graph_context_init(struct nouveau_gpuobj *ctx)
{
int i;
@@ -254,7 +304,7 @@ nv30_31_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
}
static void
-nv34_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv34_graph_context_init(struct nouveau_gpuobj *ctx)
{
int i;
@@ -312,7 +362,7 @@ nv34_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
}
static void
-nv35_36_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv35_36_graph_context_init(struct nouveau_gpuobj *ctx)
{
int i;
@@ -370,148 +420,57 @@ nv35_36_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
}
int
-nv20_graph_create_context(struct nouveau_channel *chan)
+nv20_graph_context_new(struct nouveau_channel *chan, int engine)
{
+ struct nv20_graph_engine *pgraph = nv_engine(chan->dev, engine);
+ struct nouveau_gpuobj *grctx = NULL;
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 idoffs = 0x28;
int ret;
- switch (dev_priv->chipset) {
- case 0x20:
- ctx_init = nv20_graph_context_init;
- idoffs = 0;
- break;
- case 0x25:
- case 0x28:
- ctx_init = nv25_graph_context_init;
- break;
- case 0x2a:
- ctx_init = nv2a_graph_context_init;
- idoffs = 0;
- break;
- case 0x30:
- case 0x31:
- ctx_init = nv30_31_graph_context_init;
- break;
- case 0x34:
- ctx_init = nv34_graph_context_init;
- break;
- case 0x35:
- case 0x36:
- ctx_init = nv35_36_graph_context_init;
- break;
- default:
- BUG_ON(1);
- }
-
- ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 16,
- NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx);
+ ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 16,
+ NVOBJ_FLAG_ZERO_ALLOC, &grctx);
if (ret)
return ret;
/* Initialise default context values */
- ctx_init(dev, chan->ramin_grctx);
+ pgraph->grctx_init(grctx);
/* nv20: nv_wo32(dev, chan->ramin_grctx->gpuobj, 10, chan->id<<24); */
- nv_wo32(chan->ramin_grctx, idoffs,
- (chan->id << 24) | 0x1); /* CTX_USER */
+ /* CTX_USER */
+ nv_wo32(grctx, pgraph->grctx_user, (chan->id << 24) | 0x1);
- nv_wo32(pgraph->ctx_table, chan->id * 4, chan->ramin_grctx->pinst >> 4);
+ nv_wo32(pgraph->ctxtab, chan->id * 4, grctx->pinst >> 4);
+ chan->engctx[engine] = grctx;
return 0;
}
void
-nv20_graph_destroy_context(struct nouveau_channel *chan)
+nv20_graph_context_del(struct nouveau_channel *chan, int engine)
{
+ struct nv20_graph_engine *pgraph = nv_engine(chan->dev, engine);
+ struct nouveau_gpuobj *grctx = chan->engctx[engine];
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
unsigned long flags;
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
- pgraph->fifo_access(dev, false);
+ nv04_graph_fifo_access(dev, false);
/* Unload the context if it's the currently active one */
- if (pgraph->channel(dev) == chan)
- pgraph->unload_context(dev);
+ if (nv10_graph_channel(dev) == chan)
+ nv20_graph_unload_context(dev);
- pgraph->fifo_access(dev, true);
+ nv04_graph_fifo_access(dev, true);
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
/* Free the context resources */
- nv_wo32(pgraph->ctx_table, chan->id * 4, 0);
- nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
-}
-
-int
-nv20_graph_load_context(struct nouveau_channel *chan)
-{
- struct drm_device *dev = chan->dev;
- uint32_t inst;
+ nv_wo32(pgraph->ctxtab, chan->id * 4, 0);
- if (!chan->ramin_grctx)
- return -EINVAL;
- inst = chan->ramin_grctx->pinst >> 4;
-
- nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
- nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
- NV20_PGRAPH_CHANNEL_CTX_XFER_LOAD);
- nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
-
- nouveau_wait_for_idle(dev);
- return 0;
-}
-
-int
-nv20_graph_unload_context(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- struct nouveau_channel *chan;
- uint32_t inst, tmp;
-
- chan = pgraph->channel(dev);
- if (!chan)
- return 0;
- inst = chan->ramin_grctx->pinst >> 4;
-
- nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
- nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
- NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE);
-
- nouveau_wait_for_idle(dev);
-
- nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
- tmp = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;
- tmp |= (pfifo->channels - 1) << 24;
- nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp);
- return 0;
+ nouveau_gpuobj_ref(NULL, &grctx);
+ chan->engctx[engine] = NULL;
}
static void
-nv20_graph_rdi(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- int i, writecount = 32;
- uint32_t rdi_index = 0x2c80000;
-
- if (dev_priv->chipset == 0x20) {
- rdi_index = 0x3d0000;
- writecount = 15;
- }
-
- nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, rdi_index);
- for (i = 0; i < writecount; i++)
- nv_wr32(dev, NV10_PGRAPH_RDI_DATA, 0);
-
- nouveau_wait_for_idle(dev);
-}
-
-void
nv20_graph_set_tile_region(struct drm_device *dev, int i)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -536,56 +495,22 @@ nv20_graph_set_tile_region(struct drm_device *dev, int i)
}
int
-nv20_graph_init(struct drm_device *dev)
+nv20_graph_init(struct drm_device *dev, int engine)
{
+ struct nv20_graph_engine *pgraph = nv_engine(dev, engine);
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;
- }
+ int i;
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 (!pgraph->ctx_table) {
- /* Create Context Pointer Table */
- ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16,
- NVOBJ_FLAG_ZERO_ALLOC,
- &pgraph->ctx_table);
- if (ret)
- return ret;
- }
-
- nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
- pgraph->ctx_table->pinst >> 4);
+ nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, pgraph->ctxtab->pinst >> 4);
nv20_graph_rdi(dev);
- ret = nv20_graph_register(dev);
- if (ret) {
- nouveau_gpuobj_ref(NULL, &pgraph->ctx_table);
- return ret;
- }
-
- nouveau_irq_register(dev, 12, nv20_graph_isr);
nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF);
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
@@ -657,67 +582,20 @@ nv20_graph_init(struct drm_device *dev)
return 0;
}
-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;
-
- nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
- nouveau_irq_unregister(dev, 12);
-
- nouveau_gpuobj_ref(NULL, &pgraph->ctx_table);
-}
-
int
-nv30_graph_init(struct drm_device *dev)
+nv30_graph_init(struct drm_device *dev, int engine)
{
+ struct nv20_graph_engine *pgraph = nv_engine(dev, engine);
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;
- }
+ int i;
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 (!pgraph->ctx_table) {
- /* Create Context Pointer Table */
- ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16,
- NVOBJ_FLAG_ZERO_ALLOC,
- &pgraph->ctx_table);
- if (ret)
- return ret;
- }
-
- ret = nv30_graph_register(dev);
- if (ret) {
- nouveau_gpuobj_ref(NULL, &pgraph->ctx_table);
- return ret;
- }
+ nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, pgraph->ctxtab->pinst >> 4);
- nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
- pgraph->ctx_table->pinst >> 4);
-
- nouveau_irq_register(dev, 12, nv20_graph_isr);
nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF);
nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
@@ -775,85 +653,11 @@ nv30_graph_init(struct drm_device *dev)
return 0;
}
-static int
-nv20_graph_register(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- if (dev_priv->engine.graph.registered)
- return 0;
-
- NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
- NVOBJ_CLASS(dev, 0x0030, GR); /* null */
- NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
- NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
- NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
- NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
- NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
- NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
- NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
- NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
- NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
- NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
- NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
- NVOBJ_CLASS(dev, 0x009e, GR); /* swzsurf */
- NVOBJ_CLASS(dev, 0x0096, GR); /* celcius */
-
- /* kelvin */
- if (dev_priv->chipset < 0x25)
- NVOBJ_CLASS(dev, 0x0097, GR);
- else
- NVOBJ_CLASS(dev, 0x0597, GR);
-
- /* nvsw */
- NVOBJ_CLASS(dev, 0x506e, SW);
- NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
- dev_priv->engine.graph.registered = true;
- return 0;
-}
-
-static int
-nv30_graph_register(struct drm_device *dev)
+int
+nv20_graph_fini(struct drm_device *dev, int engine)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- if (dev_priv->engine.graph.registered)
- return 0;
-
- NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
- NVOBJ_CLASS(dev, 0x0030, GR); /* null */
- NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
- NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
- NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
- NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
- NVOBJ_CLASS(dev, 0x038a, GR); /* ifc (nv30) */
- NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
- NVOBJ_CLASS(dev, 0x0389, GR); /* sifm (nv30) */
- NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
- NVOBJ_CLASS(dev, 0x0362, GR); /* surf2d (nv30) */
- NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
- NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
- NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
- NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
- NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
- NVOBJ_CLASS(dev, 0x039e, GR); /* swzsurf */
-
- /* rankine */
- if (0x00000003 & (1 << (dev_priv->chipset & 0x0f)))
- NVOBJ_CLASS(dev, 0x0397, GR);
- else
- if (0x00000010 & (1 << (dev_priv->chipset & 0x0f)))
- NVOBJ_CLASS(dev, 0x0697, GR);
- else
- if (0x000001e0 & (1 << (dev_priv->chipset & 0x0f)))
- NVOBJ_CLASS(dev, 0x0497, GR);
-
- /* nvsw */
- NVOBJ_CLASS(dev, 0x506e, SW);
- NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
- dev_priv->engine.graph.registered = true;
+ nv20_graph_unload_context(dev);
+ nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
return 0;
}
@@ -897,3 +701,135 @@ nv20_graph_isr(struct drm_device *dev)
}
}
}
+
+static void
+nv20_graph_destroy(struct drm_device *dev, int engine)
+{
+ struct nv20_graph_engine *pgraph = nv_engine(dev, engine);
+
+ nouveau_irq_unregister(dev, 12);
+ nouveau_gpuobj_ref(NULL, &pgraph->ctxtab);
+
+ NVOBJ_ENGINE_DEL(dev, GR);
+ kfree(pgraph);
+}
+
+int
+nv20_graph_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv20_graph_engine *pgraph;
+ int ret;
+
+ pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
+ if (!pgraph)
+ return -ENOMEM;
+
+ pgraph->base.destroy = nv20_graph_destroy;
+ pgraph->base.fini = nv20_graph_fini;
+ pgraph->base.context_new = nv20_graph_context_new;
+ pgraph->base.context_del = nv20_graph_context_del;
+ pgraph->base.object_new = nv04_graph_object_new;
+ pgraph->base.set_tile_region = nv20_graph_set_tile_region;
+
+ pgraph->grctx_user = 0x0028;
+ if (dev_priv->card_type == NV_20) {
+ pgraph->base.init = nv20_graph_init;
+ switch (dev_priv->chipset) {
+ case 0x20:
+ pgraph->grctx_init = nv20_graph_context_init;
+ pgraph->grctx_size = NV20_GRCTX_SIZE;
+ pgraph->grctx_user = 0x0000;
+ break;
+ case 0x25:
+ case 0x28:
+ pgraph->grctx_init = nv25_graph_context_init;
+ pgraph->grctx_size = NV25_GRCTX_SIZE;
+ break;
+ case 0x2a:
+ pgraph->grctx_init = nv2a_graph_context_init;
+ pgraph->grctx_size = NV2A_GRCTX_SIZE;
+ pgraph->grctx_user = 0x0000;
+ break;
+ default:
+ NV_ERROR(dev, "PGRAPH: unknown chipset\n");
+ return 0;
+ }
+ } else {
+ pgraph->base.init = nv30_graph_init;
+ switch (dev_priv->chipset) {
+ case 0x30:
+ case 0x31:
+ pgraph->grctx_init = nv30_31_graph_context_init;
+ pgraph->grctx_size = NV30_31_GRCTX_SIZE;
+ break;
+ case 0x34:
+ pgraph->grctx_init = nv34_graph_context_init;
+ pgraph->grctx_size = NV34_GRCTX_SIZE;
+ break;
+ case 0x35:
+ case 0x36:
+ pgraph->grctx_init = nv35_36_graph_context_init;
+ pgraph->grctx_size = NV35_36_GRCTX_SIZE;
+ break;
+ default:
+ NV_ERROR(dev, "PGRAPH: unknown chipset\n");
+ return 0;
+ }
+ }
+
+ /* Create Context Pointer Table */
+ ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC,
+ &pgraph->ctxtab);
+ if (ret) {
+ kfree(pgraph);
+ return ret;
+ }
+
+ NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
+ nouveau_irq_register(dev, 12, nv20_graph_isr);
+
+ /* nvsw */
+ NVOBJ_CLASS(dev, 0x506e, SW);
+ NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
+
+ NVOBJ_CLASS(dev, 0x0030, GR); /* null */
+ NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
+ NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
+ NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
+ NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
+ NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
+ NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
+ NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
+ NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
+ NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
+ NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
+ NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
+ if (dev_priv->card_type == NV_20) {
+ NVOBJ_CLASS(dev, 0x009e, GR); /* swzsurf */
+ NVOBJ_CLASS(dev, 0x0096, GR); /* celcius */
+
+ /* kelvin */
+ if (dev_priv->chipset < 0x25)
+ NVOBJ_CLASS(dev, 0x0097, GR);
+ else
+ NVOBJ_CLASS(dev, 0x0597, GR);
+ } else {
+ NVOBJ_CLASS(dev, 0x038a, GR); /* ifc (nv30) */
+ NVOBJ_CLASS(dev, 0x0389, GR); /* sifm (nv30) */
+ NVOBJ_CLASS(dev, 0x0362, GR); /* surf2d (nv30) */
+ NVOBJ_CLASS(dev, 0x039e, GR); /* swzsurf */
+
+ /* rankine */
+ if (0x00000003 & (1 << (dev_priv->chipset & 0x0f)))
+ NVOBJ_CLASS(dev, 0x0397, GR);
+ else
+ if (0x00000010 & (1 << (dev_priv->chipset & 0x0f)))
+ NVOBJ_CLASS(dev, 0x0697, GR);
+ else
+ if (0x000001e0 & (1 << (dev_priv->chipset & 0x0f)))
+ NVOBJ_CLASS(dev, 0x0497, GR);
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nv40_fifo.c b/drivers/gpu/drm/nouveau/nv40_fifo.c
index 49b9a35a9cd6..68cb2d991c88 100644
--- a/drivers/gpu/drm/nouveau/nv40_fifo.c
+++ b/drivers/gpu/drm/nouveau/nv40_fifo.c
@@ -115,6 +115,7 @@ nv40_fifo_do_load_context(struct drm_device *dev, int chid)
nv_wr32(dev, 0x32e8, nv_ri32(dev, fc + 68));
nv_wr32(dev, 0x2088, nv_ri32(dev, fc + 76));
nv_wr32(dev, 0x3300, nv_ri32(dev, fc + 80));
+ nv_wr32(dev, 0x330c, nv_ri32(dev, fc + 84));
nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
@@ -186,6 +187,7 @@ nv40_fifo_unload_context(struct drm_device *dev)
tmp |= (nv_rd32(dev, NV04_PFIFO_CACHE1_PUT) << 16);
nv_wi32(dev, fc + 72, tmp);
#endif
+ nv_wi32(dev, fc + 84, nv_rd32(dev, 0x330c));
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 fceb44c0ec74..5beb01b8ace1 100644
--- a/drivers/gpu/drm/nouveau/nv40_graph.c
+++ b/drivers/gpu/drm/nouveau/nv40_graph.c
@@ -28,14 +28,18 @@
#include "drm.h"
#include "nouveau_drv.h"
#include "nouveau_grctx.h"
+#include "nouveau_ramht.h"
-static int nv40_graph_register(struct drm_device *);
-static void nv40_graph_isr(struct drm_device *);
+struct nv40_graph_engine {
+ struct nouveau_exec_engine base;
+ u32 grctx_size;
+};
-struct nouveau_channel *
+static struct nouveau_channel *
nv40_graph_channel(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *grctx;
uint32_t inst;
int i;
@@ -45,74 +49,17 @@ nv40_graph_channel(struct drm_device *dev)
inst = (inst & NV40_PGRAPH_CTXCTL_CUR_INSTANCE) << 4;
for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
- struct nouveau_channel *chan = dev_priv->channels.ptr[i];
+ if (!dev_priv->channels.ptr[i])
+ continue;
- if (chan && chan->ramin_grctx &&
- chan->ramin_grctx->pinst == inst)
- return chan;
+ grctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_GR];
+ if (grctx && grctx->pinst == inst)
+ return dev_priv->channels.ptr[i];
}
return NULL;
}
-int
-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 = {};
- unsigned long flags;
- int ret;
-
- ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 16,
- NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx);
- if (ret)
- return ret;
-
- /* Initialise default context values */
- ctx.dev = chan->dev;
- ctx.mode = NOUVEAU_GRCTX_VALS;
- ctx.data = chan->ramin_grctx;
- nv40_grctx_init(&ctx);
-
- nv_wo32(chan->ramin_grctx, 0, chan->ramin_grctx->pinst);
-
- /* init grctx pointer in ramfc, and on PFIFO if channel is
- * already active there
- */
- spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
- nv_wo32(chan->ramfc, 0x38, chan->ramin_grctx->pinst >> 4);
- nv_mask(dev, 0x002500, 0x00000001, 0x00000000);
- if ((nv_rd32(dev, 0x003204) & 0x0000001f) == chan->id)
- nv_wr32(dev, 0x0032e0, chan->ramin_grctx->pinst >> 4);
- nv_mask(dev, 0x002500, 0x00000001, 0x00000001);
- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
- return 0;
-}
-
-void
-nv40_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;
- unsigned long flags;
-
- spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
- pgraph->fifo_access(dev, false);
-
- /* Unload the context if it's the currently active one */
- if (pgraph->channel(dev) == chan)
- pgraph->unload_context(dev);
-
- pgraph->fifo_access(dev, true);
- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
- /* Free the context resources */
- nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
-}
-
static int
nv40_graph_transfer_context(struct drm_device *dev, uint32_t inst, int save)
{
@@ -154,57 +101,115 @@ nv40_graph_transfer_context(struct drm_device *dev, uint32_t inst, int save)
return 0;
}
-/* Restore the context for a specific channel into PGRAPH */
-int
-nv40_graph_load_context(struct nouveau_channel *chan)
+static int
+nv40_graph_unload_context(struct drm_device *dev)
{
- struct drm_device *dev = chan->dev;
uint32_t inst;
int ret;
- if (!chan->ramin_grctx)
- return -EINVAL;
- inst = chan->ramin_grctx->pinst >> 4;
+ inst = nv_rd32(dev, NV40_PGRAPH_CTXCTL_CUR);
+ if (!(inst & NV40_PGRAPH_CTXCTL_CUR_LOADED))
+ return 0;
+ inst &= NV40_PGRAPH_CTXCTL_CUR_INSTANCE;
+
+ ret = nv40_graph_transfer_context(dev, inst, 1);
+
+ nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, inst);
+ return ret;
+}
+
+static int
+nv40_graph_context_new(struct nouveau_channel *chan, int engine)
+{
+ struct nv40_graph_engine *pgraph = nv_engine(chan->dev, engine);
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *grctx = NULL;
+ struct nouveau_grctx ctx = {};
+ unsigned long flags;
+ int ret;
- ret = nv40_graph_transfer_context(dev, inst, 0);
+ ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 16,
+ NVOBJ_FLAG_ZERO_ALLOC, &grctx);
if (ret)
return ret;
- /* 0x40032C, no idea of it's exact function. Could simply be a
- * record of the currently active PGRAPH context. It's currently
- * unknown as to what bit 24 does. The nv ddx has it set, so we will
- * set it here too.
- */
- nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR,
- (inst & NV40_PGRAPH_CTXCTL_CUR_INSTANCE) |
- NV40_PGRAPH_CTXCTL_CUR_LOADED);
- /* 0x32E0 records the instance address of the active FIFO's PGRAPH
- * context. If at any time this doesn't match 0x40032C, you will
- * receive PGRAPH_INTR_CONTEXT_SWITCH
+ /* Initialise default context values */
+ ctx.dev = chan->dev;
+ ctx.mode = NOUVEAU_GRCTX_VALS;
+ ctx.data = grctx;
+ nv40_grctx_init(&ctx);
+
+ nv_wo32(grctx, 0, grctx->vinst);
+
+ /* init grctx pointer in ramfc, and on PFIFO if channel is
+ * already active there
*/
- nv_wr32(dev, NV40_PFIFO_GRCTX_INSTANCE, inst);
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ nv_wo32(chan->ramfc, 0x38, grctx->vinst >> 4);
+ nv_mask(dev, 0x002500, 0x00000001, 0x00000000);
+ if ((nv_rd32(dev, 0x003204) & 0x0000001f) == chan->id)
+ nv_wr32(dev, 0x0032e0, grctx->vinst >> 4);
+ nv_mask(dev, 0x002500, 0x00000001, 0x00000001);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+ chan->engctx[engine] = grctx;
return 0;
}
-int
-nv40_graph_unload_context(struct drm_device *dev)
+static void
+nv40_graph_context_del(struct nouveau_channel *chan, int engine)
{
- uint32_t inst;
- int ret;
+ struct nouveau_gpuobj *grctx = chan->engctx[engine];
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ unsigned long flags;
- inst = nv_rd32(dev, NV40_PGRAPH_CTXCTL_CUR);
- if (!(inst & NV40_PGRAPH_CTXCTL_CUR_LOADED))
- return 0;
- inst &= NV40_PGRAPH_CTXCTL_CUR_INSTANCE;
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ nv04_graph_fifo_access(dev, false);
- ret = nv40_graph_transfer_context(dev, inst, 1);
+ /* Unload the context if it's the currently active one */
+ if (nv40_graph_channel(dev) == chan)
+ nv40_graph_unload_context(dev);
- nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, inst);
+ nv04_graph_fifo_access(dev, true);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+ /* Free the context resources */
+ nouveau_gpuobj_ref(NULL, &grctx);
+ chan->engctx[engine] = NULL;
+}
+
+int
+nv40_graph_object_new(struct nouveau_channel *chan, int engine,
+ u32 handle, u16 class)
+{
+ struct drm_device *dev = chan->dev;
+ struct nouveau_gpuobj *obj = NULL;
+ int ret;
+
+ ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+ if (ret)
+ return ret;
+ obj->engine = 1;
+ obj->class = class;
+
+ nv_wo32(obj, 0x00, class);
+ nv_wo32(obj, 0x04, 0x00000000);
+#ifndef __BIG_ENDIAN
+ nv_wo32(obj, 0x08, 0x00000000);
+#else
+ nv_wo32(obj, 0x08, 0x01000000);
+#endif
+ nv_wo32(obj, 0x0c, 0x00000000);
+ nv_wo32(obj, 0x10, 0x00000000);
+
+ ret = nouveau_ramht_insert(chan, handle, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
return ret;
}
-void
+static void
nv40_graph_set_tile_region(struct drm_device *dev, int i)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -257,14 +262,14 @@ nv40_graph_set_tile_region(struct drm_device *dev, int i)
* C51 0x4e
*/
int
-nv40_graph_init(struct drm_device *dev)
+nv40_graph_init(struct drm_device *dev, int engine)
{
- struct drm_nouveau_private *dev_priv =
- (struct drm_nouveau_private *)dev->dev_private;
+ struct nv40_graph_engine *pgraph = nv_engine(dev, engine);
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
struct nouveau_grctx ctx = {};
uint32_t vramsz, *cp;
- int ret, i, j;
+ int i, j;
nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
~NV_PMC_ENABLE_PGRAPH);
@@ -280,7 +285,7 @@ nv40_graph_init(struct drm_device *dev)
ctx.data = cp;
ctx.ctxprog_max = 256;
nv40_grctx_init(&ctx);
- dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
+ pgraph->grctx_size = ctx.ctxvals_pos * 4;
nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
for (i = 0; i < ctx.ctxprog_len; i++)
@@ -288,14 +293,9 @@ nv40_graph_init(struct drm_device *dev)
kfree(cp);
- ret = nv40_graph_register(dev);
- if (ret)
- return ret;
-
/* No context present currently */
nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
- nouveau_irq_register(dev, 12, nv40_graph_isr);
nv_wr32(dev, NV03_PGRAPH_INTR , 0xFFFFFFFF);
nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF);
@@ -428,47 +428,10 @@ nv40_graph_init(struct drm_device *dev)
return 0;
}
-void nv40_graph_takedown(struct drm_device *dev)
-{
- nouveau_irq_unregister(dev, 12);
-}
-
static int
-nv40_graph_register(struct drm_device *dev)
+nv40_graph_fini(struct drm_device *dev, int engine)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- if (dev_priv->engine.graph.registered)
- return 0;
-
- NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
- NVOBJ_CLASS(dev, 0x0030, GR); /* null */
- NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
- NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
- NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
- NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
- NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
- NVOBJ_CLASS(dev, 0x3089, GR); /* sifm (nv40) */
- NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
- NVOBJ_CLASS(dev, 0x3062, GR); /* surf2d (nv40) */
- NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
- NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
- NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
- NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
- NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
- NVOBJ_CLASS(dev, 0x309e, GR); /* swzsurf */
-
- /* curie */
- if (nv44_graph_class(dev))
- NVOBJ_CLASS(dev, 0x4497, GR);
- else
- NVOBJ_CLASS(dev, 0x4097, GR);
-
- /* nvsw */
- NVOBJ_CLASS(dev, 0x506e, SW);
- NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
- dev_priv->engine.graph.registered = true;
+ nv40_graph_unload_context(dev);
return 0;
}
@@ -476,17 +439,17 @@ static int
nv40_graph_isr_chid(struct drm_device *dev, u32 inst)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_channel *chan;
+ struct nouveau_gpuobj *grctx;
unsigned long flags;
int i;
spin_lock_irqsave(&dev_priv->channels.lock, flags);
for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
- chan = dev_priv->channels.ptr[i];
- if (!chan || !chan->ramin_grctx)
+ if (!dev_priv->channels.ptr[i])
continue;
+ grctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_GR];
- if (inst == chan->ramin_grctx->pinst)
+ if (grctx && grctx->pinst == inst)
break;
}
spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
@@ -537,3 +500,63 @@ nv40_graph_isr(struct drm_device *dev)
}
}
}
+
+static void
+nv40_graph_destroy(struct drm_device *dev, int engine)
+{
+ struct nv40_graph_engine *pgraph = nv_engine(dev, engine);
+
+ nouveau_irq_unregister(dev, 12);
+
+ NVOBJ_ENGINE_DEL(dev, GR);
+ kfree(pgraph);
+}
+
+int
+nv40_graph_create(struct drm_device *dev)
+{
+ struct nv40_graph_engine *pgraph;
+
+ pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
+ if (!pgraph)
+ return -ENOMEM;
+
+ pgraph->base.destroy = nv40_graph_destroy;
+ pgraph->base.init = nv40_graph_init;
+ pgraph->base.fini = nv40_graph_fini;
+ pgraph->base.context_new = nv40_graph_context_new;
+ pgraph->base.context_del = nv40_graph_context_del;
+ pgraph->base.object_new = nv40_graph_object_new;
+ pgraph->base.set_tile_region = nv40_graph_set_tile_region;
+
+ NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
+ nouveau_irq_register(dev, 12, nv40_graph_isr);
+
+ NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
+ NVOBJ_CLASS(dev, 0x0030, GR); /* null */
+ NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
+ NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
+ NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
+ NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
+ NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
+ NVOBJ_CLASS(dev, 0x3089, GR); /* sifm (nv40) */
+ NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
+ NVOBJ_CLASS(dev, 0x3062, GR); /* surf2d (nv40) */
+ NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
+ NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
+ NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
+ NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
+ NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
+ NVOBJ_CLASS(dev, 0x309e, GR); /* swzsurf */
+
+ /* curie */
+ if (nv44_graph_class(dev))
+ NVOBJ_CLASS(dev, 0x4497, GR);
+ else
+ NVOBJ_CLASS(dev, 0x4097, GR);
+
+ /* nvsw */
+ NVOBJ_CLASS(dev, 0x506e, SW);
+ NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nv40_mpeg.c b/drivers/gpu/drm/nouveau/nv40_mpeg.c
new file mode 100644
index 000000000000..6d2af292a2e3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv40_mpeg.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2011 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 "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_ramht.h"
+
+struct nv40_mpeg_engine {
+ struct nouveau_exec_engine base;
+};
+
+static int
+nv40_mpeg_context_new(struct nouveau_channel *chan, int engine)
+{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *ctx = NULL;
+ unsigned long flags;
+ int ret;
+
+ NV_DEBUG(dev, "ch%d\n", chan->id);
+
+ ret = nouveau_gpuobj_new(dev, NULL, 264 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ZERO_FREE, &ctx);
+ if (ret)
+ return ret;
+
+ nv_wo32(ctx, 0x78, 0x02001ec1);
+
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ nv_mask(dev, 0x002500, 0x00000001, 0x00000000);
+ if ((nv_rd32(dev, 0x003204) & 0x1f) == chan->id)
+ nv_wr32(dev, 0x00330c, ctx->pinst >> 4);
+ nv_wo32(chan->ramfc, 0x54, ctx->pinst >> 4);
+ nv_mask(dev, 0x002500, 0x00000001, 0x00000001);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+ chan->engctx[engine] = ctx;
+ return 0;
+}
+
+static void
+nv40_mpeg_context_del(struct nouveau_channel *chan, int engine)
+{
+ struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+ struct nouveau_gpuobj *ctx = chan->engctx[engine];
+ struct drm_device *dev = chan->dev;
+ unsigned long flags;
+ u32 inst = 0x80000000 | (ctx->pinst >> 4);
+
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
+ if (nv_rd32(dev, 0x00b318) == inst)
+ nv_mask(dev, 0x00b318, 0x80000000, 0x00000000);
+ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+ nouveau_gpuobj_ref(NULL, &ctx);
+ chan->engctx[engine] = NULL;
+}
+
+static int
+nv40_mpeg_object_new(struct nouveau_channel *chan, int engine,
+ u32 handle, u16 class)
+{
+ struct drm_device *dev = chan->dev;
+ struct nouveau_gpuobj *obj = NULL;
+ int ret;
+
+ ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ZERO_FREE, &obj);
+ if (ret)
+ return ret;
+ obj->engine = 2;
+ obj->class = class;
+
+ nv_wo32(obj, 0x00, class);
+
+ ret = nouveau_ramht_insert(chan, handle, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
+ return ret;
+}
+
+static int
+nv40_mpeg_init(struct drm_device *dev, int engine)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv40_mpeg_engine *pmpeg = nv_engine(dev, engine);
+ int i;
+
+ /* VPE init */
+ nv_mask(dev, 0x000200, 0x00000002, 0x00000000);
+ nv_mask(dev, 0x000200, 0x00000002, 0x00000002);
+ nv_wr32(dev, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
+ nv_wr32(dev, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
+
+ for (i = 0; i < dev_priv->engine.fb.num_tiles; i++)
+ pmpeg->base.set_tile_region(dev, i);
+
+ /* PMPEG init */
+ nv_wr32(dev, 0x00b32c, 0x00000000);
+ nv_wr32(dev, 0x00b314, 0x00000100);
+ nv_wr32(dev, 0x00b220, 0x00000044);
+ nv_wr32(dev, 0x00b300, 0x02001ec1);
+ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
+
+ nv_wr32(dev, 0x00b100, 0xffffffff);
+ nv_wr32(dev, 0x00b140, 0xffffffff);
+
+ if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) {
+ NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200));
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int
+nv40_mpeg_fini(struct drm_device *dev, int engine)
+{
+ /*XXX: context save? */
+ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
+ nv_wr32(dev, 0x00b140, 0x00000000);
+ return 0;
+}
+
+static int
+nv40_mpeg_mthd_dma(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
+{
+ struct drm_device *dev = chan->dev;
+ u32 inst = data << 4;
+ u32 dma0 = nv_ri32(dev, inst + 0);
+ u32 dma1 = nv_ri32(dev, inst + 4);
+ u32 dma2 = nv_ri32(dev, inst + 8);
+ u32 base = (dma2 & 0xfffff000) | (dma0 >> 20);
+ u32 size = dma1 + 1;
+
+ /* only allow linear DMA objects */
+ if (!(dma0 & 0x00002000))
+ return -EINVAL;
+
+ if (mthd == 0x0190) {
+ /* DMA_CMD */
+ nv_mask(dev, 0x00b300, 0x00030000, (dma0 & 0x00030000));
+ nv_wr32(dev, 0x00b334, base);
+ nv_wr32(dev, 0x00b324, size);
+ } else
+ if (mthd == 0x01a0) {
+ /* DMA_DATA */
+ nv_mask(dev, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2);
+ nv_wr32(dev, 0x00b360, base);
+ nv_wr32(dev, 0x00b364, size);
+ } else {
+ /* DMA_IMAGE, VRAM only */
+ if (dma0 & 0x000c0000)
+ return -EINVAL;
+
+ nv_wr32(dev, 0x00b370, base);
+ nv_wr32(dev, 0x00b374, size);
+ }
+
+ return 0;
+}
+
+static int
+nv40_mpeg_isr_chid(struct drm_device *dev, u32 inst)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *ctx;
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&dev_priv->channels.lock, flags);
+ for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
+ if (!dev_priv->channels.ptr[i])
+ continue;
+
+ ctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_MPEG];
+ if (ctx && ctx->pinst == inst)
+ break;
+ }
+ spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
+ return i;
+}
+
+static void
+nv40_vpe_set_tile_region(struct drm_device *dev, int i)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
+
+ nv_wr32(dev, 0x00b008 + (i * 0x10), tile->pitch);
+ nv_wr32(dev, 0x00b004 + (i * 0x10), tile->limit);
+ nv_wr32(dev, 0x00b000 + (i * 0x10), tile->addr);
+}
+
+static void
+nv40_mpeg_isr(struct drm_device *dev)
+{
+ u32 inst = (nv_rd32(dev, 0x00b318) & 0x000fffff) << 4;
+ u32 chid = nv40_mpeg_isr_chid(dev, inst);
+ u32 stat = nv_rd32(dev, 0x00b100);
+ u32 type = nv_rd32(dev, 0x00b230);
+ u32 mthd = nv_rd32(dev, 0x00b234);
+ u32 data = nv_rd32(dev, 0x00b238);
+ u32 show = stat;
+
+ if (stat & 0x01000000) {
+ /* happens on initial binding of the object */
+ if (type == 0x00000020 && mthd == 0x0000) {
+ nv_mask(dev, 0x00b308, 0x00000000, 0x00000000);
+ show &= ~0x01000000;
+ }
+
+ if (type == 0x00000010) {
+ if (!nouveau_gpuobj_mthd_call2(dev, chid, 0x3174, mthd, data))
+ show &= ~0x01000000;
+ }
+ }
+
+ nv_wr32(dev, 0x00b100, stat);
+ nv_wr32(dev, 0x00b230, 0x00000001);
+
+ if (show && nouveau_ratelimit()) {
+ NV_INFO(dev, "PMPEG: Ch %d [0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ chid, inst, stat, type, mthd, data);
+ }
+}
+
+static void
+nv40_vpe_isr(struct drm_device *dev)
+{
+ if (nv_rd32(dev, 0x00b100))
+ nv40_mpeg_isr(dev);
+
+ if (nv_rd32(dev, 0x00b800)) {
+ u32 stat = nv_rd32(dev, 0x00b800);
+ NV_INFO(dev, "PMSRCH: 0x%08x\n", stat);
+ nv_wr32(dev, 0xb800, stat);
+ }
+}
+
+static void
+nv40_mpeg_destroy(struct drm_device *dev, int engine)
+{
+ struct nv40_mpeg_engine *pmpeg = nv_engine(dev, engine);
+
+ nouveau_irq_unregister(dev, 0);
+
+ NVOBJ_ENGINE_DEL(dev, MPEG);
+ kfree(pmpeg);
+}
+
+int
+nv40_mpeg_create(struct drm_device *dev)
+{
+ struct nv40_mpeg_engine *pmpeg;
+
+ pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL);
+ if (!pmpeg)
+ return -ENOMEM;
+
+ pmpeg->base.destroy = nv40_mpeg_destroy;
+ pmpeg->base.init = nv40_mpeg_init;
+ pmpeg->base.fini = nv40_mpeg_fini;
+ pmpeg->base.context_new = nv40_mpeg_context_new;
+ pmpeg->base.context_del = nv40_mpeg_context_del;
+ pmpeg->base.object_new = nv40_mpeg_object_new;
+
+ /* ISR vector, PMC_ENABLE bit, and TILE regs are shared between
+ * all VPE engines, for this driver's purposes the PMPEG engine
+ * will be treated as the "master" and handle the global VPE
+ * bits too
+ */
+ pmpeg->base.set_tile_region = nv40_vpe_set_tile_region;
+ nouveau_irq_register(dev, 0, nv40_vpe_isr);
+
+ NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base);
+ NVOBJ_CLASS(dev, 0x3174, MPEG);
+ NVOBJ_MTHD (dev, 0x3174, 0x0190, nv40_mpeg_mthd_dma);
+ NVOBJ_MTHD (dev, 0x3174, 0x01a0, nv40_mpeg_mthd_dma);
+ NVOBJ_MTHD (dev, 0x3174, 0x01b0, nv40_mpeg_mthd_dma);
+
+#if 0
+ NVOBJ_ENGINE_ADD(dev, ME, &pme->base);
+ NVOBJ_CLASS(dev, 0x4075, ME);
+#endif
+ return 0;
+
+}
diff --git a/drivers/gpu/drm/nouveau/nv50_calc.c b/drivers/gpu/drm/nouveau/nv50_calc.c
index de81151648f8..8cf63a8b30cd 100644
--- a/drivers/gpu/drm/nouveau/nv50_calc.c
+++ b/drivers/gpu/drm/nouveau/nv50_calc.c
@@ -23,7 +23,6 @@
*/
#include "drmP.h"
-#include "drm_fixed.h"
#include "nouveau_drv.h"
#include "nouveau_hw.h"
@@ -47,45 +46,52 @@ nv50_calc_pll(struct drm_device *dev, struct pll_lims *pll, int clk,
}
int
-nv50_calc_pll2(struct drm_device *dev, struct pll_lims *pll, int clk,
- int *N, int *fN, int *M, int *P)
+nva3_calc_pll(struct drm_device *dev, struct pll_lims *pll, int clk,
+ int *pN, int *pfN, int *pM, int *P)
{
- fixed20_12 fb_div, a, b;
- u32 refclk = pll->refclk / 10;
- u32 max_vco_freq = pll->vco1.maxfreq / 10;
- u32 max_vco_inputfreq = pll->vco1.max_inputfreq / 10;
- clk /= 10;
+ u32 best_err = ~0, err;
+ int M, lM, hM, N, fN;
- *P = max_vco_freq / clk;
+ *P = pll->vco1.maxfreq / clk;
if (*P > pll->max_p)
*P = pll->max_p;
if (*P < pll->min_p)
*P = pll->min_p;
- /* *M = floor((refclk + max_vco_inputfreq) / max_vco_inputfreq); */
- a.full = dfixed_const(refclk + max_vco_inputfreq);
- b.full = dfixed_const(max_vco_inputfreq);
- a.full = dfixed_div(a, b);
- a.full = dfixed_floor(a);
- *M = dfixed_trunc(a);
+ lM = (pll->refclk + pll->vco1.max_inputfreq) / pll->vco1.max_inputfreq;
+ lM = max(lM, (int)pll->vco1.min_m);
+ hM = (pll->refclk + pll->vco1.min_inputfreq) / pll->vco1.min_inputfreq;
+ hM = min(hM, (int)pll->vco1.max_m);
- /* fb_div = (vco * *M) / refclk; */
- fb_div.full = dfixed_const(clk * *P);
- fb_div.full = dfixed_mul(fb_div, a);
- a.full = dfixed_const(refclk);
- fb_div.full = dfixed_div(fb_div, a);
+ for (M = lM; M <= hM; M++) {
+ u32 tmp = clk * *P * M;
+ N = tmp / pll->refclk;
+ fN = tmp % pll->refclk;
+ if (!pfN && fN >= pll->refclk / 2)
+ N++;
- /* *N = floor(fb_div); */
- a.full = dfixed_floor(fb_div);
- *N = dfixed_trunc(fb_div);
+ if (N < pll->vco1.min_n)
+ continue;
+ if (N > pll->vco1.max_n)
+ break;
- /* *fN = (fmod(fb_div, 1.0) * 8192) - 4096; */
- b.full = dfixed_const(8192);
- a.full = dfixed_mul(a, b);
- fb_div.full = dfixed_mul(fb_div, b);
- fb_div.full = fb_div.full - a.full;
- *fN = dfixed_trunc(fb_div) - 4096;
- *fN &= 0xffff;
+ err = abs(clk - (pll->refclk * N / M / *P));
+ if (err < best_err) {
+ best_err = err;
+ *pN = N;
+ *pM = M;
+ }
- return clk;
+ if (pfN) {
+ *pfN = (((fN << 13) / pll->refclk) - 4096) & 0xffff;
+ return clk;
+ }
+ }
+
+ if (unlikely(best_err == ~0)) {
+ NV_ERROR(dev, "unable to find matching pll values\n");
+ return -EINVAL;
+ }
+
+ return pll->refclk * *pN / *pM / *P;
}
diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
index a19ccaa025b3..ebabacf38da9 100644
--- a/drivers/gpu/drm/nouveau/nv50_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
@@ -286,7 +286,7 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
nv_wr32(dev, pll.reg + 8, reg2 | (P << 28) | (M2 << 16) | N2);
} else
if (dev_priv->chipset < NV_C0) {
- ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
+ ret = nva3_calc_pll(dev, &pll, pclk, &N1, &N2, &M1, &P);
if (ret <= 0)
return 0;
@@ -298,7 +298,7 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
nv_wr32(dev, pll.reg + 4, reg1 | (P << 16) | (M1 << 8) | N1);
nv_wr32(dev, pll.reg + 8, N2);
} else {
- ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
+ ret = nva3_calc_pll(dev, &pll, pclk, &N1, &N2, &M1, &P);
if (ret <= 0)
return 0;
@@ -349,14 +349,14 @@ nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
struct drm_gem_object *gem;
int ret = 0, i;
- if (width != 64 || height != 64)
- return -EINVAL;
-
if (!buffer_handle) {
nv_crtc->cursor.hide(nv_crtc, true);
return 0;
}
+ if (width != 64 || height != 64)
+ return -EINVAL;
+
gem = drm_gem_object_lookup(dev, file_priv, buffer_handle);
if (!gem)
return -ENOENT;
@@ -532,8 +532,7 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
if (atomic) {
drm_fb = passed_fb;
fb = nouveau_framebuffer(passed_fb);
- }
- else {
+ } else {
/* If not atomic, we can go ahead and pin, and unpin the
* old fb we were passed.
*/
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 75a376cc342a..74a3f6872701 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -517,13 +517,25 @@ nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcb,
if (bios->fp.if_is_24bit)
script |= 0x0200;
} else {
+ /* determine number of lvds links */
+ if (nv_connector && nv_connector->edid &&
+ nv_connector->dcb->type == DCB_CONNECTOR_LVDS_SPWG) {
+ /* http://www.spwg.org */
+ if (((u8 *)nv_connector->edid)[121] == 2)
+ script |= 0x0100;
+ } else
if (pxclk >= bios->fp.duallink_transition_clk) {
script |= 0x0100;
+ }
+
+ /* determine panel depth */
+ if (script & 0x0100) {
if (bios->fp.strapless_is_24bit & 2)
script |= 0x0200;
- } else
- if (bios->fp.strapless_is_24bit & 1)
- script |= 0x0200;
+ } else {
+ if (bios->fp.strapless_is_24bit & 1)
+ script |= 0x0200;
+ }
if (nv_connector && nv_connector->edid &&
(nv_connector->edid->revision >= 4) &&
diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c
index b02a5b1e7d37..e25cbb46789a 100644
--- a/drivers/gpu/drm/nouveau/nv50_graph.c
+++ b/drivers/gpu/drm/nouveau/nv50_graph.c
@@ -31,10 +31,95 @@
#include "nouveau_grctx.h"
#include "nouveau_dma.h"
#include "nouveau_vm.h"
+#include "nouveau_ramht.h"
#include "nv50_evo.h"
-static int nv50_graph_register(struct drm_device *);
-static void nv50_graph_isr(struct drm_device *);
+struct nv50_graph_engine {
+ struct nouveau_exec_engine base;
+ u32 ctxprog[512];
+ u32 ctxprog_size;
+ u32 grctx_size;
+};
+
+static void
+nv50_graph_fifo_access(struct drm_device *dev, bool enabled)
+{
+ const uint32_t mask = 0x00010001;
+
+ if (enabled)
+ nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) | mask);
+ else
+ nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) & ~mask);
+}
+
+static struct nouveau_channel *
+nv50_graph_channel(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ uint32_t inst;
+ int i;
+
+ /* Be sure we're not in the middle of a context switch or bad things
+ * will happen, such as unloading the wrong pgraph context.
+ */
+ if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000))
+ NV_ERROR(dev, "Ctxprog is still running\n");
+
+ inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
+ if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED))
+ return NULL;
+ inst = (inst & NV50_PGRAPH_CTXCTL_CUR_INSTANCE) << 12;
+
+ for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
+ struct nouveau_channel *chan = dev_priv->channels.ptr[i];
+
+ if (chan && chan->ramin && chan->ramin->vinst == inst)
+ return chan;
+ }
+
+ return NULL;
+}
+
+static int
+nv50_graph_do_load_context(struct drm_device *dev, uint32_t inst)
+{
+ uint32_t fifo = nv_rd32(dev, 0x400500);
+
+ nv_wr32(dev, 0x400500, fifo & ~1);
+ nv_wr32(dev, 0x400784, inst);
+ nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x40);
+ nv_wr32(dev, 0x400320, nv_rd32(dev, 0x400320) | 0x11);
+ nv_wr32(dev, 0x400040, 0xffffffff);
+ (void)nv_rd32(dev, 0x400040);
+ nv_wr32(dev, 0x400040, 0x00000000);
+ nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 1);
+
+ if (nouveau_wait_for_idle(dev))
+ nv_wr32(dev, 0x40032c, inst | (1<<31));
+ nv_wr32(dev, 0x400500, fifo);
+
+ return 0;
+}
+
+static int
+nv50_graph_unload_context(struct drm_device *dev)
+{
+ uint32_t inst;
+
+ inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
+ if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED))
+ return 0;
+ inst &= NV50_PGRAPH_CTXCTL_CUR_INSTANCE;
+
+ nouveau_wait_for_idle(dev);
+ nv_wr32(dev, 0x400784, inst);
+ nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x20);
+ nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 0x01);
+ nouveau_wait_for_idle(dev);
+
+ nv_wr32(dev, NV50_PGRAPH_CTXCTL_CUR, inst);
+ return 0;
+}
static void
nv50_graph_init_reset(struct drm_device *dev)
@@ -52,7 +137,6 @@ nv50_graph_init_intr(struct drm_device *dev)
{
NV_DEBUG(dev, "\n");
- nouveau_irq_register(dev, 12, nv50_graph_isr);
nv_wr32(dev, NV03_PGRAPH_INTR, 0xffffffff);
nv_wr32(dev, 0x400138, 0xffffffff);
nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xffffffff);
@@ -135,34 +219,14 @@ nv50_graph_init_zcull(struct drm_device *dev)
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;
+ struct nv50_graph_engine *pgraph = nv_engine(dev, NVOBJ_ENGINE_GR);
int i;
NV_DEBUG(dev, "\n");
- 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;
- }
-
- 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, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
+ for (i = 0; i < pgraph->ctxprog_size; i++)
+ nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, pgraph->ctxprog[i]);
nv_wr32(dev, 0x40008c, 0x00000004); /* HW_CTX_SWITCH_ENABLED */
nv_wr32(dev, 0x400320, 4);
@@ -171,8 +235,8 @@ nv50_graph_init_ctxctl(struct drm_device *dev)
return 0;
}
-int
-nv50_graph_init(struct drm_device *dev)
+static int
+nv50_graph_init(struct drm_device *dev, int engine)
{
int ret;
@@ -186,105 +250,66 @@ nv50_graph_init(struct drm_device *dev)
if (ret)
return ret;
- ret = nv50_graph_register(dev);
- if (ret)
- return ret;
nv50_graph_init_intr(dev);
return 0;
}
-void
-nv50_graph_takedown(struct drm_device *dev)
+static int
+nv50_graph_fini(struct drm_device *dev, int engine)
{
NV_DEBUG(dev, "\n");
+ nv50_graph_unload_context(dev);
nv_wr32(dev, 0x40013c, 0x00000000);
- nouveau_irq_unregister(dev, 12);
-}
-
-void
-nv50_graph_fifo_access(struct drm_device *dev, bool enabled)
-{
- const uint32_t mask = 0x00010001;
-
- if (enabled)
- nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) | mask);
- else
- nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) & ~mask);
-}
-
-struct nouveau_channel *
-nv50_graph_channel(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- uint32_t inst;
- int i;
-
- /* Be sure we're not in the middle of a context switch or bad things
- * will happen, such as unloading the wrong pgraph context.
- */
- if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000))
- NV_ERROR(dev, "Ctxprog is still running\n");
-
- inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
- if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED))
- return NULL;
- inst = (inst & NV50_PGRAPH_CTXCTL_CUR_INSTANCE) << 12;
-
- for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
- struct nouveau_channel *chan = dev_priv->channels.ptr[i];
-
- if (chan && chan->ramin && chan->ramin->vinst == inst)
- return chan;
- }
-
- return NULL;
+ return 0;
}
-int
-nv50_graph_create_context(struct nouveau_channel *chan)
+static int
+nv50_graph_context_new(struct nouveau_channel *chan, int engine)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *ramin = chan->ramin;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+ struct nouveau_gpuobj *grctx = NULL;
+ struct nv50_graph_engine *pgraph = nv_engine(dev, engine);
struct nouveau_grctx ctx = {};
int hdr, ret;
NV_DEBUG(dev, "ch%d\n", chan->id);
- ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 0,
+ ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 0,
NVOBJ_FLAG_ZERO_ALLOC |
- NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx);
+ NVOBJ_FLAG_ZERO_FREE, &grctx);
if (ret)
return ret;
hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
nv_wo32(ramin, hdr + 0x00, 0x00190002);
- nv_wo32(ramin, hdr + 0x04, chan->ramin_grctx->vinst +
- pgraph->grctx_size - 1);
- nv_wo32(ramin, hdr + 0x08, chan->ramin_grctx->vinst);
+ nv_wo32(ramin, hdr + 0x04, grctx->vinst + grctx->size - 1);
+ nv_wo32(ramin, hdr + 0x08, grctx->vinst);
nv_wo32(ramin, hdr + 0x0c, 0);
nv_wo32(ramin, hdr + 0x10, 0);
nv_wo32(ramin, hdr + 0x14, 0x00010000);
ctx.dev = chan->dev;
ctx.mode = NOUVEAU_GRCTX_VALS;
- ctx.data = chan->ramin_grctx;
+ ctx.data = grctx;
nv50_grctx_init(&ctx);
- nv_wo32(chan->ramin_grctx, 0x00000, chan->ramin->vinst >> 12);
+ nv_wo32(grctx, 0x00000, chan->ramin->vinst >> 12);
dev_priv->engine.instmem.flush(dev);
- atomic_inc(&chan->vm->pgraph_refs);
+
+ atomic_inc(&chan->vm->engref[NVOBJ_ENGINE_GR]);
+ chan->engctx[NVOBJ_ENGINE_GR] = grctx;
return 0;
}
-void
-nv50_graph_destroy_context(struct nouveau_channel *chan)
+static void
+nv50_graph_context_del(struct nouveau_channel *chan, int engine)
{
+ struct nouveau_gpuobj *grctx = chan->engctx[engine];
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_fifo_engine *pfifo = &dev_priv->engine.fifo;
int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
unsigned long flags;
@@ -296,72 +321,49 @@ nv50_graph_destroy_context(struct nouveau_channel *chan)
spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
pfifo->reassign(dev, false);
- pgraph->fifo_access(dev, false);
+ nv50_graph_fifo_access(dev, false);
- if (pgraph->channel(dev) == chan)
- pgraph->unload_context(dev);
+ if (nv50_graph_channel(dev) == chan)
+ nv50_graph_unload_context(dev);
for (i = hdr; i < hdr + 24; i += 4)
nv_wo32(chan->ramin, i, 0);
dev_priv->engine.instmem.flush(dev);
- pgraph->fifo_access(dev, true);
+ nv50_graph_fifo_access(dev, true);
pfifo->reassign(dev, true);
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
- nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
+ nouveau_gpuobj_ref(NULL, &grctx);
- atomic_dec(&chan->vm->pgraph_refs);
+ atomic_dec(&chan->vm->engref[engine]);
+ chan->engctx[engine] = NULL;
}
static int
-nv50_graph_do_load_context(struct drm_device *dev, uint32_t inst)
-{
- uint32_t fifo = nv_rd32(dev, 0x400500);
-
- nv_wr32(dev, 0x400500, fifo & ~1);
- nv_wr32(dev, 0x400784, inst);
- nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x40);
- nv_wr32(dev, 0x400320, nv_rd32(dev, 0x400320) | 0x11);
- nv_wr32(dev, 0x400040, 0xffffffff);
- (void)nv_rd32(dev, 0x400040);
- nv_wr32(dev, 0x400040, 0x00000000);
- nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 1);
-
- if (nouveau_wait_for_idle(dev))
- nv_wr32(dev, 0x40032c, inst | (1<<31));
- nv_wr32(dev, 0x400500, fifo);
-
- return 0;
-}
-
-int
-nv50_graph_load_context(struct nouveau_channel *chan)
-{
- uint32_t inst = chan->ramin->vinst >> 12;
-
- NV_DEBUG(chan->dev, "ch%d\n", chan->id);
- return nv50_graph_do_load_context(chan->dev, inst);
-}
-
-int
-nv50_graph_unload_context(struct drm_device *dev)
+nv50_graph_object_new(struct nouveau_channel *chan, int engine,
+ u32 handle, u16 class)
{
- uint32_t inst;
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *obj = NULL;
+ int ret;
- inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
- if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED))
- return 0;
- inst &= NV50_PGRAPH_CTXCTL_CUR_INSTANCE;
+ ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+ if (ret)
+ return ret;
+ obj->engine = 1;
+ obj->class = class;
- nouveau_wait_for_idle(dev);
- nv_wr32(dev, 0x400784, inst);
- nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x20);
- nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 0x01);
- nouveau_wait_for_idle(dev);
+ nv_wo32(obj, 0x00, class);
+ nv_wo32(obj, 0x04, 0x00000000);
+ nv_wo32(obj, 0x08, 0x00000000);
+ nv_wo32(obj, 0x0c, 0x00000000);
+ dev_priv->engine.instmem.flush(dev);
- nv_wr32(dev, NV50_PGRAPH_CTXCTL_CUR, inst);
- return 0;
+ ret = nouveau_ramht_insert(chan, handle, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
+ return ret;
}
static void
@@ -442,68 +444,15 @@ nv50_graph_nvsw_mthd_page_flip(struct nouveau_channel *chan,
return 0;
}
-static int
-nv50_graph_register(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
-
- if (dev_priv->engine.graph.registered)
- return 0;
-
- NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
- NVOBJ_MTHD (dev, 0x506e, 0x018c, nv50_graph_nvsw_dma_vblsem);
- NVOBJ_MTHD (dev, 0x506e, 0x0400, nv50_graph_nvsw_vblsem_offset);
- NVOBJ_MTHD (dev, 0x506e, 0x0404, nv50_graph_nvsw_vblsem_release_val);
- NVOBJ_MTHD (dev, 0x506e, 0x0408, nv50_graph_nvsw_vblsem_release);
- NVOBJ_MTHD (dev, 0x506e, 0x0500, nv50_graph_nvsw_mthd_page_flip);
-
- NVOBJ_CLASS(dev, 0x0030, GR); /* null */
- NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */
- NVOBJ_CLASS(dev, 0x502d, GR); /* 2d */
-
- /* tesla */
- if (dev_priv->chipset == 0x50)
- NVOBJ_CLASS(dev, 0x5097, GR); /* tesla (nv50) */
- else
- if (dev_priv->chipset < 0xa0)
- NVOBJ_CLASS(dev, 0x8297, GR); /* tesla (nv8x/nv9x) */
- else {
- switch (dev_priv->chipset) {
- case 0xa0:
- case 0xaa:
- case 0xac:
- NVOBJ_CLASS(dev, 0x8397, GR);
- break;
- case 0xa3:
- case 0xa5:
- case 0xa8:
- NVOBJ_CLASS(dev, 0x8597, GR);
- break;
- case 0xaf:
- NVOBJ_CLASS(dev, 0x8697, GR);
- break;
- }
- }
-
- /* compute */
- NVOBJ_CLASS(dev, 0x50c0, GR);
- if (dev_priv->chipset > 0xa0 &&
- dev_priv->chipset != 0xaa &&
- dev_priv->chipset != 0xac)
- NVOBJ_CLASS(dev, 0x85c0, GR);
-
- dev_priv->engine.graph.registered = true;
- return 0;
-}
-void
-nv50_graph_tlb_flush(struct drm_device *dev)
+static void
+nv50_graph_tlb_flush(struct drm_device *dev, int engine)
{
nv50_vm_flush_engine(dev, 0);
}
-void
-nv84_graph_tlb_flush(struct drm_device *dev)
+static void
+nv84_graph_tlb_flush(struct drm_device *dev, int engine)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
@@ -548,8 +497,7 @@ nv84_graph_tlb_flush(struct drm_device *dev)
spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
}
-static struct nouveau_enum nv50_mp_exec_error_names[] =
-{
+static struct nouveau_enum nv50_mp_exec_error_names[] = {
{ 3, "STACK_UNDERFLOW", NULL },
{ 4, "QUADON_ACTIVE", NULL },
{ 8, "TIMEOUT", NULL },
@@ -663,7 +611,7 @@ nv50_pgraph_mp_trap(struct drm_device *dev, int tpid, int display)
nv_rd32(dev, addr + 0x20);
pc = nv_rd32(dev, addr + 0x24);
oplow = nv_rd32(dev, addr + 0x70);
- ophigh= nv_rd32(dev, addr + 0x74);
+ ophigh = nv_rd32(dev, addr + 0x74);
NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - "
"TP %d MP %d: ", tpid, i);
nouveau_enum_print(nv50_mp_exec_error_names, status);
@@ -991,7 +939,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev, u32 display, u64 inst, u32 chid
return 1;
}
-static int
+int
nv50_graph_isr_chid(struct drm_device *dev, u64 inst)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -1073,3 +1021,101 @@ nv50_graph_isr(struct drm_device *dev)
if (nv_rd32(dev, 0x400824) & (1 << 31))
nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31));
}
+
+static void
+nv50_graph_destroy(struct drm_device *dev, int engine)
+{
+ struct nv50_graph_engine *pgraph = nv_engine(dev, engine);
+
+ NVOBJ_ENGINE_DEL(dev, GR);
+
+ nouveau_irq_unregister(dev, 12);
+ kfree(pgraph);
+}
+
+int
+nv50_graph_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv50_graph_engine *pgraph;
+ struct nouveau_grctx ctx = {};
+ int ret;
+
+ pgraph = kzalloc(sizeof(*pgraph),GFP_KERNEL);
+ if (!pgraph)
+ return -ENOMEM;
+
+ ctx.dev = dev;
+ ctx.mode = NOUVEAU_GRCTX_PROG;
+ ctx.data = pgraph->ctxprog;
+ ctx.ctxprog_max = ARRAY_SIZE(pgraph->ctxprog);
+
+ ret = nv50_grctx_init(&ctx);
+ if (ret) {
+ NV_ERROR(dev, "PGRAPH: ctxprog build failed\n");
+ kfree(pgraph);
+ return 0;
+ }
+
+ pgraph->grctx_size = ctx.ctxvals_pos * 4;
+ pgraph->ctxprog_size = ctx.ctxprog_len;
+
+ pgraph->base.destroy = nv50_graph_destroy;
+ pgraph->base.init = nv50_graph_init;
+ pgraph->base.fini = nv50_graph_fini;
+ pgraph->base.context_new = nv50_graph_context_new;
+ pgraph->base.context_del = nv50_graph_context_del;
+ pgraph->base.object_new = nv50_graph_object_new;
+ if (dev_priv->chipset == 0x50 || dev_priv->chipset == 0xac)
+ pgraph->base.tlb_flush = nv50_graph_tlb_flush;
+ else
+ pgraph->base.tlb_flush = nv84_graph_tlb_flush;
+
+ nouveau_irq_register(dev, 12, nv50_graph_isr);
+
+ /* NVSW really doesn't live here... */
+ NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
+ NVOBJ_MTHD (dev, 0x506e, 0x018c, nv50_graph_nvsw_dma_vblsem);
+ NVOBJ_MTHD (dev, 0x506e, 0x0400, nv50_graph_nvsw_vblsem_offset);
+ NVOBJ_MTHD (dev, 0x506e, 0x0404, nv50_graph_nvsw_vblsem_release_val);
+ NVOBJ_MTHD (dev, 0x506e, 0x0408, nv50_graph_nvsw_vblsem_release);
+ NVOBJ_MTHD (dev, 0x506e, 0x0500, nv50_graph_nvsw_mthd_page_flip);
+
+ NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
+ NVOBJ_CLASS(dev, 0x0030, GR); /* null */
+ NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */
+ NVOBJ_CLASS(dev, 0x502d, GR); /* 2d */
+
+ /* tesla */
+ if (dev_priv->chipset == 0x50)
+ NVOBJ_CLASS(dev, 0x5097, GR); /* tesla (nv50) */
+ else
+ if (dev_priv->chipset < 0xa0)
+ NVOBJ_CLASS(dev, 0x8297, GR); /* tesla (nv8x/nv9x) */
+ else {
+ switch (dev_priv->chipset) {
+ case 0xa0:
+ case 0xaa:
+ case 0xac:
+ NVOBJ_CLASS(dev, 0x8397, GR);
+ break;
+ case 0xa3:
+ case 0xa5:
+ case 0xa8:
+ NVOBJ_CLASS(dev, 0x8597, GR);
+ break;
+ case 0xaf:
+ NVOBJ_CLASS(dev, 0x8697, GR);
+ break;
+ }
+ }
+
+ /* compute */
+ NVOBJ_CLASS(dev, 0x50c0, GR);
+ if (dev_priv->chipset > 0xa0 &&
+ dev_priv->chipset != 0xaa &&
+ dev_priv->chipset != 0xac)
+ NVOBJ_CLASS(dev, 0x85c0, GR);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nv50_grctx.c b/drivers/gpu/drm/nouveau/nv50_grctx.c
index 336aab2a24a6..de9abff12b90 100644
--- a/drivers/gpu/drm/nouveau/nv50_grctx.c
+++ b/drivers/gpu/drm/nouveau/nv50_grctx.c
@@ -747,7 +747,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
gr_def(ctx, offset + 0x64, 0x0000001f);
gr_def(ctx, offset + 0x68, 0x0000000f);
gr_def(ctx, offset + 0x6c, 0x0000000f);
- } else if(dev_priv->chipset < 0xa0) {
+ } else if (dev_priv->chipset < 0xa0) {
cp_ctx(ctx, offset + 0x50, 1);
cp_ctx(ctx, offset + 0x70, 1);
} else {
@@ -924,7 +924,7 @@ nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx)
dd_emit(ctx, 1, 0); /* 0000007f MULTISAMPLE_SAMPLES_LOG2 */
} else {
dd_emit(ctx, 1, 0); /* 0000000f MULTISAMPLE_SAMPLES_LOG2 */
- }
+ }
dd_emit(ctx, 1, 0xc); /* 000000ff SEMANTIC_COLOR.BFC0_ID */
if (dev_priv->chipset != 0x50)
dd_emit(ctx, 1, 0); /* 00000001 SEMANTIC_COLOR.CLMP_EN */
@@ -1803,9 +1803,7 @@ nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx)
xf_emit(ctx, 1, 0); /* 1ff */
xf_emit(ctx, 8, 0); /* 0? */
xf_emit(ctx, 9, 0); /* ffffffff, 7ff */
- }
- else
- {
+ } else {
xf_emit(ctx, 0xc, 0); /* RO */
/* SEEK */
xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
@@ -2836,7 +2834,7 @@ nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx)
xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */
if (IS_NVA3F(dev_priv->chipset))
xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
- if(dev_priv->chipset == 0x50)
+ if (dev_priv->chipset == 0x50)
xf_emit(ctx, 1, 0); /* ff */
else
xf_emit(ctx, 3, 0); /* 1, 7, 3ff */
diff --git a/drivers/gpu/drm/nouveau/nv50_mpeg.c b/drivers/gpu/drm/nouveau/nv50_mpeg.c
new file mode 100644
index 000000000000..1dc5913f78c5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nv50_mpeg.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2011 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 "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_ramht.h"
+
+struct nv50_mpeg_engine {
+ struct nouveau_exec_engine base;
+};
+
+static inline u32
+CTX_PTR(struct drm_device *dev, u32 offset)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+ if (dev_priv->chipset == 0x50)
+ offset += 0x0260;
+ else
+ offset += 0x0060;
+
+ return offset;
+}
+
+static int
+nv50_mpeg_context_new(struct nouveau_channel *chan, int engine)
+{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *ramin = chan->ramin;
+ struct nouveau_gpuobj *ctx = NULL;
+ int ret;
+
+ NV_DEBUG(dev, "ch%d\n", chan->id);
+
+ ret = nouveau_gpuobj_new(dev, chan, 128 * 4, 0, NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ZERO_FREE, &ctx);
+ if (ret)
+ return ret;
+
+ nv_wo32(ramin, CTX_PTR(dev, 0x00), 0x80190002);
+ nv_wo32(ramin, CTX_PTR(dev, 0x04), ctx->vinst + ctx->size - 1);
+ nv_wo32(ramin, CTX_PTR(dev, 0x08), ctx->vinst);
+ nv_wo32(ramin, CTX_PTR(dev, 0x0c), 0);
+ nv_wo32(ramin, CTX_PTR(dev, 0x10), 0);
+ nv_wo32(ramin, CTX_PTR(dev, 0x14), 0x00010000);
+
+ nv_wo32(ctx, 0x70, 0x00801ec1);
+ nv_wo32(ctx, 0x7c, 0x0000037c);
+ dev_priv->engine.instmem.flush(dev);
+
+ chan->engctx[engine] = ctx;
+ return 0;
+}
+
+static void
+nv50_mpeg_context_del(struct nouveau_channel *chan, int engine)
+{
+ struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+ struct nouveau_gpuobj *ctx = chan->engctx[engine];
+ struct drm_device *dev = chan->dev;
+ unsigned long flags;
+ u32 inst, i;
+
+ if (!chan->ramin)
+ return;
+
+ inst = chan->ramin->vinst >> 12;
+ inst |= 0x80000000;
+
+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
+ if (nv_rd32(dev, 0x00b318) == inst)
+ nv_mask(dev, 0x00b318, 0x80000000, 0x00000000);
+ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+ for (i = 0x00; i <= 0x14; i += 4)
+ nv_wo32(chan->ramin, CTX_PTR(dev, i), 0x00000000);
+ nouveau_gpuobj_ref(NULL, &ctx);
+ chan->engctx[engine] = NULL;
+}
+
+static int
+nv50_mpeg_object_new(struct nouveau_channel *chan, int engine,
+ u32 handle, u16 class)
+{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *obj = NULL;
+ int ret;
+
+ ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+ if (ret)
+ return ret;
+ obj->engine = 2;
+ obj->class = class;
+
+ nv_wo32(obj, 0x00, class);
+ nv_wo32(obj, 0x04, 0x00000000);
+ nv_wo32(obj, 0x08, 0x00000000);
+ nv_wo32(obj, 0x0c, 0x00000000);
+ dev_priv->engine.instmem.flush(dev);
+
+ ret = nouveau_ramht_insert(chan, handle, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
+ return ret;
+}
+
+static void
+nv50_mpeg_tlb_flush(struct drm_device *dev, int engine)
+{
+ nv50_vm_flush_engine(dev, 0x08);
+}
+
+static int
+nv50_mpeg_init(struct drm_device *dev, int engine)
+{
+ nv_wr32(dev, 0x00b32c, 0x00000000);
+ nv_wr32(dev, 0x00b314, 0x00000100);
+ nv_wr32(dev, 0x00b0e0, 0x0000001a);
+
+ nv_wr32(dev, 0x00b220, 0x00000044);
+ nv_wr32(dev, 0x00b300, 0x00801ec1);
+ nv_wr32(dev, 0x00b390, 0x00000000);
+ nv_wr32(dev, 0x00b394, 0x00000000);
+ nv_wr32(dev, 0x00b398, 0x00000000);
+ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
+
+ nv_wr32(dev, 0x00b100, 0xffffffff);
+ nv_wr32(dev, 0x00b140, 0xffffffff);
+
+ if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) {
+ NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200));
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int
+nv50_mpeg_fini(struct drm_device *dev, int engine)
+{
+ /*XXX: context save for s/r */
+ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
+ nv_wr32(dev, 0x00b140, 0x00000000);
+ return 0;
+}
+
+static void
+nv50_mpeg_isr(struct drm_device *dev)
+{
+ u32 stat = nv_rd32(dev, 0x00b100);
+ u32 type = nv_rd32(dev, 0x00b230);
+ u32 mthd = nv_rd32(dev, 0x00b234);
+ u32 data = nv_rd32(dev, 0x00b238);
+ u32 show = stat;
+
+ if (stat & 0x01000000) {
+ /* happens on initial binding of the object */
+ if (type == 0x00000020 && mthd == 0x0000) {
+ nv_wr32(dev, 0x00b308, 0x00000100);
+ show &= ~0x01000000;
+ }
+ }
+
+ if (show && nouveau_ratelimit()) {
+ NV_INFO(dev, "PMPEG - 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ stat, type, mthd, data);
+ }
+
+ nv_wr32(dev, 0x00b100, stat);
+ nv_wr32(dev, 0x00b230, 0x00000001);
+ nv50_fb_vm_trap(dev, 1);
+}
+
+static void
+nv50_vpe_isr(struct drm_device *dev)
+{
+ if (nv_rd32(dev, 0x00b100))
+ nv50_mpeg_isr(dev);
+
+ if (nv_rd32(dev, 0x00b800)) {
+ u32 stat = nv_rd32(dev, 0x00b800);
+ NV_INFO(dev, "PMSRCH: 0x%08x\n", stat);
+ nv_wr32(dev, 0xb800, stat);
+ }
+}
+
+static void
+nv50_mpeg_destroy(struct drm_device *dev, int engine)
+{
+ struct nv50_mpeg_engine *pmpeg = nv_engine(dev, engine);
+
+ nouveau_irq_unregister(dev, 0);
+
+ NVOBJ_ENGINE_DEL(dev, MPEG);
+ kfree(pmpeg);
+}
+
+int
+nv50_mpeg_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nv50_mpeg_engine *pmpeg;
+
+ pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL);
+ if (!pmpeg)
+ return -ENOMEM;
+
+ pmpeg->base.destroy = nv50_mpeg_destroy;
+ pmpeg->base.init = nv50_mpeg_init;
+ pmpeg->base.fini = nv50_mpeg_fini;
+ pmpeg->base.context_new = nv50_mpeg_context_new;
+ pmpeg->base.context_del = nv50_mpeg_context_del;
+ pmpeg->base.object_new = nv50_mpeg_object_new;
+ pmpeg->base.tlb_flush = nv50_mpeg_tlb_flush;
+
+ if (dev_priv->chipset == 0x50) {
+ nouveau_irq_register(dev, 0, nv50_vpe_isr);
+ NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base);
+ NVOBJ_CLASS(dev, 0x3174, MPEG);
+#if 0
+ NVOBJ_ENGINE_ADD(dev, ME, &pme->base);
+ NVOBJ_CLASS(dev, 0x4075, ME);
+#endif
+ } else {
+ nouveau_irq_register(dev, 0, nv50_mpeg_isr);
+ NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base);
+ NVOBJ_CLASS(dev, 0x8274, MPEG);
+ }
+
+ return 0;
+
+}
diff --git a/drivers/gpu/drm/nouveau/nv50_pm.c b/drivers/gpu/drm/nouveau/nv50_pm.c
index 7dbb305d7e63..8a2810011bda 100644
--- a/drivers/gpu/drm/nouveau/nv50_pm.c
+++ b/drivers/gpu/drm/nouveau/nv50_pm.c
@@ -47,6 +47,21 @@ nv50_pm_clock_get(struct drm_device *dev, u32 id)
reg0 = nv_rd32(dev, pll.reg + 0);
reg1 = nv_rd32(dev, pll.reg + 4);
+
+ if ((reg0 & 0x80000000) == 0) {
+ if (id == PLL_SHADER) {
+ NV_DEBUG(dev, "Shader PLL is disabled. "
+ "Shader clock is twice the core\n");
+ ret = nv50_pm_clock_get(dev, PLL_CORE);
+ if (ret > 0)
+ return ret << 1;
+ } else if (id == PLL_MEMORY) {
+ NV_DEBUG(dev, "Memory PLL is disabled. "
+ "Memory clock is equal to the ref_clk\n");
+ return pll.refclk;
+ }
+ }
+
P = (reg0 & 0x00070000) >> 16;
N = (reg1 & 0x0000ff00) >> 8;
M = (reg1 & 0x000000ff);
diff --git a/drivers/gpu/drm/nouveau/nv50_vm.c b/drivers/gpu/drm/nouveau/nv50_vm.c
index 6c2694490741..1a0dd491a0e4 100644
--- a/drivers/gpu/drm/nouveau/nv50_vm.c
+++ b/drivers/gpu/drm/nouveau/nv50_vm.c
@@ -151,8 +151,7 @@ nv50_vm_flush(struct nouveau_vm *vm)
struct drm_nouveau_private *dev_priv = vm->dev->dev_private;
struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
+ int i;
pinstmem->flush(vm->dev);
@@ -163,11 +162,10 @@ nv50_vm_flush(struct nouveau_vm *vm)
}
pfifo->tlb_flush(vm->dev);
-
- if (atomic_read(&vm->pgraph_refs))
- pgraph->tlb_flush(vm->dev);
- if (atomic_read(&vm->pcrypt_refs))
- pcrypt->tlb_flush(vm->dev);
+ for (i = 0; i < NVOBJ_ENGINE_NR; i++) {
+ if (atomic_read(&vm->engref[i]))
+ dev_priv->eng[i]->tlb_flush(vm->dev, i);
+ }
}
void
diff --git a/drivers/gpu/drm/nouveau/nv84_crypt.c b/drivers/gpu/drm/nouveau/nv84_crypt.c
index fabc7fd30b1d..75b809a51748 100644
--- a/drivers/gpu/drm/nouveau/nv84_crypt.c
+++ b/drivers/gpu/drm/nouveau/nv84_crypt.c
@@ -26,46 +26,48 @@
#include "nouveau_drv.h"
#include "nouveau_util.h"
#include "nouveau_vm.h"
+#include "nouveau_ramht.h"
-static void nv84_crypt_isr(struct drm_device *);
+struct nv84_crypt_engine {
+ struct nouveau_exec_engine base;
+};
-int
-nv84_crypt_create_context(struct nouveau_channel *chan)
+static int
+nv84_crypt_context_new(struct nouveau_channel *chan, int engine)
{
struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_gpuobj *ramin = chan->ramin;
+ struct nouveau_gpuobj *ctx;
int ret;
NV_DEBUG(dev, "ch%d\n", chan->id);
- ret = nouveau_gpuobj_new(dev, chan, 256, 0,
- NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE,
- &chan->crypt_ctx);
+ ret = nouveau_gpuobj_new(dev, chan, 256, 0, NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ZERO_FREE, &ctx);
if (ret)
return ret;
nv_wo32(ramin, 0xa0, 0x00190000);
- nv_wo32(ramin, 0xa4, chan->crypt_ctx->vinst + 0xff);
- nv_wo32(ramin, 0xa8, chan->crypt_ctx->vinst);
+ nv_wo32(ramin, 0xa4, ctx->vinst + ctx->size - 1);
+ nv_wo32(ramin, 0xa8, ctx->vinst);
nv_wo32(ramin, 0xac, 0);
nv_wo32(ramin, 0xb0, 0);
nv_wo32(ramin, 0xb4, 0);
-
dev_priv->engine.instmem.flush(dev);
- atomic_inc(&chan->vm->pcrypt_refs);
+
+ atomic_inc(&chan->vm->engref[engine]);
+ chan->engctx[engine] = ctx;
return 0;
}
-void
-nv84_crypt_destroy_context(struct nouveau_channel *chan)
+static void
+nv84_crypt_context_del(struct nouveau_channel *chan, int engine)
{
+ struct nouveau_gpuobj *ctx = chan->engctx[engine];
struct drm_device *dev = chan->dev;
u32 inst;
- if (!chan->crypt_ctx)
- return;
-
inst = (chan->ramin->vinst >> 12);
inst |= 0x80000000;
@@ -80,43 +82,39 @@ nv84_crypt_destroy_context(struct nouveau_channel *chan)
nv_mask(dev, 0x10218c, 0x80000000, 0x00000000);
nv_wr32(dev, 0x10200c, 0x00000010);
- nouveau_gpuobj_ref(NULL, &chan->crypt_ctx);
- atomic_dec(&chan->vm->pcrypt_refs);
-}
+ nouveau_gpuobj_ref(NULL, &ctx);
-void
-nv84_crypt_tlb_flush(struct drm_device *dev)
-{
- nv50_vm_flush_engine(dev, 0x0a);
+ atomic_dec(&chan->vm->engref[engine]);
+ chan->engctx[engine] = NULL;
}
-int
-nv84_crypt_init(struct drm_device *dev)
+static int
+nv84_crypt_object_new(struct nouveau_channel *chan, int engine,
+ u32 handle, u16 class)
{
+ struct drm_device *dev = chan->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
-
- if (!pcrypt->registered) {
- NVOBJ_CLASS(dev, 0x74c1, CRYPT);
- pcrypt->registered = true;
- }
+ struct nouveau_gpuobj *obj = NULL;
+ int ret;
- nv_mask(dev, 0x000200, 0x00004000, 0x00000000);
- nv_mask(dev, 0x000200, 0x00004000, 0x00004000);
+ ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+ if (ret)
+ return ret;
+ obj->engine = 5;
+ obj->class = class;
- nouveau_irq_register(dev, 14, nv84_crypt_isr);
- nv_wr32(dev, 0x102130, 0xffffffff);
- nv_wr32(dev, 0x102140, 0xffffffbf);
+ nv_wo32(obj, 0x00, class);
+ dev_priv->engine.instmem.flush(dev);
- nv_wr32(dev, 0x10200c, 0x00000010);
- return 0;
+ ret = nouveau_ramht_insert(chan, handle, obj);
+ nouveau_gpuobj_ref(NULL, &obj);
+ return ret;
}
-void
-nv84_crypt_fini(struct drm_device *dev)
+static void
+nv84_crypt_tlb_flush(struct drm_device *dev, int engine)
{
- nv_wr32(dev, 0x102140, 0x00000000);
- nouveau_irq_unregister(dev, 14);
+ nv50_vm_flush_engine(dev, 0x0a);
}
static void
@@ -138,3 +136,58 @@ nv84_crypt_isr(struct drm_device *dev)
nv50_fb_vm_trap(dev, show);
}
+
+static int
+nv84_crypt_fini(struct drm_device *dev, int engine)
+{
+ nv_wr32(dev, 0x102140, 0x00000000);
+ return 0;
+}
+
+static int
+nv84_crypt_init(struct drm_device *dev, int engine)
+{
+ nv_mask(dev, 0x000200, 0x00004000, 0x00000000);
+ nv_mask(dev, 0x000200, 0x00004000, 0x00004000);
+
+ nv_wr32(dev, 0x102130, 0xffffffff);
+ nv_wr32(dev, 0x102140, 0xffffffbf);
+
+ nv_wr32(dev, 0x10200c, 0x00000010);
+ return 0;
+}
+
+static void
+nv84_crypt_destroy(struct drm_device *dev, int engine)
+{
+ struct nv84_crypt_engine *pcrypt = nv_engine(dev, engine);
+
+ NVOBJ_ENGINE_DEL(dev, CRYPT);
+
+ nouveau_irq_unregister(dev, 14);
+ kfree(pcrypt);
+}
+
+int
+nv84_crypt_create(struct drm_device *dev)
+{
+ struct nv84_crypt_engine *pcrypt;
+
+ pcrypt = kzalloc(sizeof(*pcrypt), GFP_KERNEL);
+ if (!pcrypt)
+ return -ENOMEM;
+
+ pcrypt->base.destroy = nv84_crypt_destroy;
+ pcrypt->base.init = nv84_crypt_init;
+ pcrypt->base.fini = nv84_crypt_fini;
+ pcrypt->base.context_new = nv84_crypt_context_new;
+ pcrypt->base.context_del = nv84_crypt_context_del;
+ pcrypt->base.object_new = nv84_crypt_object_new;
+ pcrypt->base.tlb_flush = nv84_crypt_tlb_flush;
+
+ nouveau_irq_register(dev, 14, nv84_crypt_isr);
+
+ NVOBJ_ENGINE_ADD(dev, CRYPT, &pcrypt->base);
+ NVOBJ_CLASS (dev, 0x74c1, CRYPT);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nva3_copy.c b/drivers/gpu/drm/nouveau/nva3_copy.c
new file mode 100644
index 000000000000..b86820a61220
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nva3_copy.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2011 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 "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_util.h"
+#include "nouveau_vm.h"
+#include "nouveau_ramht.h"
+#include "nva3_copy.fuc.h"
+
+struct nva3_copy_engine {
+ struct nouveau_exec_engine base;
+};
+
+static int
+nva3_copy_context_new(struct nouveau_channel *chan, int engine)
+{
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *ramin = chan->ramin;
+ struct nouveau_gpuobj *ctx = NULL;
+ int ret;
+
+ NV_DEBUG(dev, "ch%d\n", chan->id);
+
+ ret = nouveau_gpuobj_new(dev, chan, 256, 0, NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_ZERO_FREE, &ctx);
+ if (ret)
+ return ret;
+
+ nv_wo32(ramin, 0xc0, 0x00190000);
+ nv_wo32(ramin, 0xc4, ctx->vinst + ctx->size - 1);
+ nv_wo32(ramin, 0xc8, ctx->vinst);
+ nv_wo32(ramin, 0xcc, 0x00000000);
+ nv_wo32(ramin, 0xd0, 0x00000000);
+ nv_wo32(ramin, 0xd4, 0x00000000);
+ dev_priv->engine.instmem.flush(dev);
+
+ atomic_inc(&chan->vm->engref[engine]);
+ chan->engctx[engine] = ctx;
+ return 0;
+}
+
+static int
+nva3_copy_object_new(struct nouveau_channel *chan, int engine,
+ u32 handle, u16 class)
+{
+ struct nouveau_gpuobj *ctx = chan->engctx[engine];
+
+ /* fuc engine doesn't need an object, our ramht code does.. */
+ ctx->engine = 3;
+ ctx->class = class;
+ return nouveau_ramht_insert(chan, handle, ctx);
+}
+
+static void
+nva3_copy_context_del(struct nouveau_channel *chan, int engine)
+{
+ struct nouveau_gpuobj *ctx = chan->engctx[engine];
+ struct drm_device *dev = chan->dev;
+ u32 inst;
+
+ inst = (chan->ramin->vinst >> 12);
+ inst |= 0x40000000;
+
+ /* disable fifo access */
+ nv_wr32(dev, 0x104048, 0x00000000);
+ /* mark channel as unloaded if it's currently active */
+ if (nv_rd32(dev, 0x104050) == inst)
+ nv_mask(dev, 0x104050, 0x40000000, 0x00000000);
+ /* mark next channel as invalid if it's about to be loaded */
+ if (nv_rd32(dev, 0x104054) == inst)
+ nv_mask(dev, 0x104054, 0x40000000, 0x00000000);
+ /* restore fifo access */
+ nv_wr32(dev, 0x104048, 0x00000003);
+
+ for (inst = 0xc0; inst <= 0xd4; inst += 4)
+ nv_wo32(chan->ramin, inst, 0x00000000);
+
+ nouveau_gpuobj_ref(NULL, &ctx);
+
+ atomic_dec(&chan->vm->engref[engine]);
+ chan->engctx[engine] = ctx;
+}
+
+static void
+nva3_copy_tlb_flush(struct drm_device *dev, int engine)
+{
+ nv50_vm_flush_engine(dev, 0x0d);
+}
+
+static int
+nva3_copy_init(struct drm_device *dev, int engine)
+{
+ int i;
+
+ nv_mask(dev, 0x000200, 0x00002000, 0x00000000);
+ nv_mask(dev, 0x000200, 0x00002000, 0x00002000);
+ nv_wr32(dev, 0x104014, 0xffffffff); /* disable all interrupts */
+
+ /* upload ucode */
+ nv_wr32(dev, 0x1041c0, 0x01000000);
+ for (i = 0; i < sizeof(nva3_pcopy_data) / 4; i++)
+ nv_wr32(dev, 0x1041c4, nva3_pcopy_data[i]);
+
+ nv_wr32(dev, 0x104180, 0x01000000);
+ for (i = 0; i < sizeof(nva3_pcopy_code) / 4; i++) {
+ if ((i & 0x3f) == 0)
+ nv_wr32(dev, 0x104188, i >> 6);
+ nv_wr32(dev, 0x104184, nva3_pcopy_code[i]);
+ }
+
+ /* start it running */
+ nv_wr32(dev, 0x10410c, 0x00000000);
+ nv_wr32(dev, 0x104104, 0x00000000); /* ENTRY */
+ nv_wr32(dev, 0x104100, 0x00000002); /* TRIGGER */
+ return 0;
+}
+
+static int
+nva3_copy_fini(struct drm_device *dev, int engine)
+{
+ nv_mask(dev, 0x104048, 0x00000003, 0x00000000);
+
+ /* trigger fuc context unload */
+ nv_wait(dev, 0x104008, 0x0000000c, 0x00000000);
+ nv_mask(dev, 0x104054, 0x40000000, 0x00000000);
+ nv_wr32(dev, 0x104000, 0x00000008);
+ nv_wait(dev, 0x104008, 0x00000008, 0x00000000);
+
+ nv_wr32(dev, 0x104014, 0xffffffff);
+ return 0;
+}
+
+static struct nouveau_enum nva3_copy_isr_error_name[] = {
+ { 0x0001, "ILLEGAL_MTHD" },
+ { 0x0002, "INVALID_ENUM" },
+ { 0x0003, "INVALID_BITFIELD" },
+ {}
+};
+
+static void
+nva3_copy_isr(struct drm_device *dev)
+{
+ u32 dispatch = nv_rd32(dev, 0x10401c);
+ u32 stat = nv_rd32(dev, 0x104008) & dispatch & ~(dispatch >> 16);
+ u32 inst = nv_rd32(dev, 0x104050) & 0x3fffffff;
+ u32 ssta = nv_rd32(dev, 0x104040) & 0x0000ffff;
+ u32 addr = nv_rd32(dev, 0x104040) >> 16;
+ u32 mthd = (addr & 0x07ff) << 2;
+ u32 subc = (addr & 0x3800) >> 11;
+ u32 data = nv_rd32(dev, 0x104044);
+ int chid = nv50_graph_isr_chid(dev, inst);
+
+ if (stat & 0x00000040) {
+ NV_INFO(dev, "PCOPY: DISPATCH_ERROR [");
+ nouveau_enum_print(nva3_copy_isr_error_name, ssta);
+ printk("] ch %d [0x%08x] subc %d mthd 0x%04x data 0x%08x\n",
+ chid, inst, subc, mthd, data);
+ nv_wr32(dev, 0x104004, 0x00000040);
+ stat &= ~0x00000040;
+ }
+
+ if (stat) {
+ NV_INFO(dev, "PCOPY: unhandled intr 0x%08x\n", stat);
+ nv_wr32(dev, 0x104004, stat);
+ }
+ nv50_fb_vm_trap(dev, 1);
+}
+
+static void
+nva3_copy_destroy(struct drm_device *dev, int engine)
+{
+ struct nva3_copy_engine *pcopy = nv_engine(dev, engine);
+
+ nouveau_irq_unregister(dev, 22);
+
+ NVOBJ_ENGINE_DEL(dev, COPY0);
+ kfree(pcopy);
+}
+
+int
+nva3_copy_create(struct drm_device *dev)
+{
+ struct nva3_copy_engine *pcopy;
+
+ pcopy = kzalloc(sizeof(*pcopy), GFP_KERNEL);
+ if (!pcopy)
+ return -ENOMEM;
+
+ pcopy->base.destroy = nva3_copy_destroy;
+ pcopy->base.init = nva3_copy_init;
+ pcopy->base.fini = nva3_copy_fini;
+ pcopy->base.context_new = nva3_copy_context_new;
+ pcopy->base.context_del = nva3_copy_context_del;
+ pcopy->base.object_new = nva3_copy_object_new;
+ pcopy->base.tlb_flush = nva3_copy_tlb_flush;
+
+ nouveau_irq_register(dev, 22, nva3_copy_isr);
+
+ NVOBJ_ENGINE_ADD(dev, COPY0, &pcopy->base);
+ NVOBJ_CLASS(dev, 0x85b5, COPY0);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nva3_copy.fuc b/drivers/gpu/drm/nouveau/nva3_copy.fuc
new file mode 100644
index 000000000000..eaf35f8321ee
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nva3_copy.fuc
@@ -0,0 +1,870 @@
+/* fuc microcode for copy engine on nva3- chipsets
+ *
+ * Copyright 2011 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
+ */
+
+/* To build for nva3:nvc0
+ * m4 -DNVA3 nva3_copy.fuc | envyas -a -w -m fuc -V nva3 -o nva3_copy.fuc.h
+ *
+ * To build for nvc0-
+ * m4 -DNVC0 nva3_copy.fuc | envyas -a -w -m fuc -V nva3 -o nvc0_copy.fuc.h
+ */
+
+ifdef(`NVA3',
+.section nva3_pcopy_data,
+.section nvc0_pcopy_data
+)
+
+ctx_object: .b32 0
+ifdef(`NVA3',
+ctx_dma:
+ctx_dma_query: .b32 0
+ctx_dma_src: .b32 0
+ctx_dma_dst: .b32 0
+,)
+.equ ctx_dma_count 3
+ctx_query_address_high: .b32 0
+ctx_query_address_low: .b32 0
+ctx_query_counter: .b32 0
+ctx_src_address_high: .b32 0
+ctx_src_address_low: .b32 0
+ctx_src_pitch: .b32 0
+ctx_src_tile_mode: .b32 0
+ctx_src_xsize: .b32 0
+ctx_src_ysize: .b32 0
+ctx_src_zsize: .b32 0
+ctx_src_zoff: .b32 0
+ctx_src_xoff: .b32 0
+ctx_src_yoff: .b32 0
+ctx_src_cpp: .b32 0
+ctx_dst_address_high: .b32 0
+ctx_dst_address_low: .b32 0
+ctx_dst_pitch: .b32 0
+ctx_dst_tile_mode: .b32 0
+ctx_dst_xsize: .b32 0
+ctx_dst_ysize: .b32 0
+ctx_dst_zsize: .b32 0
+ctx_dst_zoff: .b32 0
+ctx_dst_xoff: .b32 0
+ctx_dst_yoff: .b32 0
+ctx_dst_cpp: .b32 0
+ctx_format: .b32 0
+ctx_swz_const0: .b32 0
+ctx_swz_const1: .b32 0
+ctx_xcnt: .b32 0
+ctx_ycnt: .b32 0
+.align 256
+
+dispatch_table:
+// mthd 0x0000, NAME
+.b16 0x000 1
+.b32 ctx_object ~0xffffffff
+// mthd 0x0100, NOP
+.b16 0x040 1
+.b32 0x00010000 + cmd_nop ~0xffffffff
+// mthd 0x0140, PM_TRIGGER
+.b16 0x050 1
+.b32 0x00010000 + cmd_pm_trigger ~0xffffffff
+ifdef(`NVA3', `
+// mthd 0x0180-0x018c, DMA_
+.b16 0x060 ctx_dma_count
+dispatch_dma:
+.b32 0x00010000 + cmd_dma ~0xffffffff
+.b32 0x00010000 + cmd_dma ~0xffffffff
+.b32 0x00010000 + cmd_dma ~0xffffffff
+',)
+// mthd 0x0200-0x0218, SRC_TILE
+.b16 0x80 7
+.b32 ctx_src_tile_mode ~0x00000fff
+.b32 ctx_src_xsize ~0x0007ffff
+.b32 ctx_src_ysize ~0x00001fff
+.b32 ctx_src_zsize ~0x000007ff
+.b32 ctx_src_zoff ~0x00000fff
+.b32 ctx_src_xoff ~0x0007ffff
+.b32 ctx_src_yoff ~0x00001fff
+// mthd 0x0220-0x0238, DST_TILE
+.b16 0x88 7
+.b32 ctx_dst_tile_mode ~0x00000fff
+.b32 ctx_dst_xsize ~0x0007ffff
+.b32 ctx_dst_ysize ~0x00001fff
+.b32 ctx_dst_zsize ~0x000007ff
+.b32 ctx_dst_zoff ~0x00000fff
+.b32 ctx_dst_xoff ~0x0007ffff
+.b32 ctx_dst_yoff ~0x00001fff
+// mthd 0x0300-0x0304, EXEC, WRCACHE_FLUSH
+.b16 0xc0 2
+.b32 0x00010000 + cmd_exec ~0xffffffff
+.b32 0x00010000 + cmd_wrcache_flush ~0xffffffff
+// mthd 0x030c-0x0340, various stuff
+.b16 0xc3 14
+.b32 ctx_src_address_high ~0x000000ff
+.b32 ctx_src_address_low ~0xfffffff0
+.b32 ctx_dst_address_high ~0x000000ff
+.b32 ctx_dst_address_low ~0xfffffff0
+.b32 ctx_src_pitch ~0x0007ffff
+.b32 ctx_dst_pitch ~0x0007ffff
+.b32 ctx_xcnt ~0x0000ffff
+.b32 ctx_ycnt ~0x00001fff
+.b32 ctx_format ~0x0333ffff
+.b32 ctx_swz_const0 ~0xffffffff
+.b32 ctx_swz_const1 ~0xffffffff
+.b32 ctx_query_address_high ~0x000000ff
+.b32 ctx_query_address_low ~0xffffffff
+.b32 ctx_query_counter ~0xffffffff
+.b16 0x800 0
+
+ifdef(`NVA3',
+.section nva3_pcopy_code,
+.section nvc0_pcopy_code
+)
+
+main:
+ clear b32 $r0
+ mov $sp $r0
+
+ // setup i0 handler and route fifo and ctxswitch to it
+ mov $r1 ih
+ mov $iv0 $r1
+ mov $r1 0x400
+ movw $r2 0xfff3
+ sethi $r2 0
+ iowr I[$r2 + 0x300] $r2
+
+ // enable interrupts
+ or $r2 0xc
+ iowr I[$r1] $r2
+ bset $flags ie0
+
+ // enable fifo access and context switching
+ mov $r1 0x1200
+ mov $r2 3
+ iowr I[$r1] $r2
+
+ // sleep forever, waking for interrupts
+ bset $flags $p0
+ spin:
+ sleep $p0
+ bra spin
+
+// i0 handler
+ih:
+ iord $r1 I[$r0 + 0x200]
+
+ and $r2 $r1 0x00000008
+ bra e ih_no_chsw
+ call chsw
+ ih_no_chsw:
+ and $r2 $r1 0x00000004
+ bra e ih_no_cmd
+ call dispatch
+
+ ih_no_cmd:
+ and $r1 $r1 0x0000000c
+ iowr I[$r0 + 0x100] $r1
+ iret
+
+// $p1 direction (0 = unload, 1 = load)
+// $r3 channel
+swctx:
+ mov $r4 0x7700
+ mov $xtargets $r4
+ifdef(`NVA3', `
+ // target 7 hardcoded to ctx dma object
+ mov $xdbase $r0
+', ` // NVC0
+ // read SCRATCH3 to decide if we are PCOPY0 or PCOPY1
+ mov $r4 0x2100
+ iord $r4 I[$r4 + 0]
+ and $r4 1
+ shl b32 $r4 4
+ add b32 $r4 0x30
+
+ // channel is in vram
+ mov $r15 0x61c
+ shl b32 $r15 6
+ mov $r5 0x114
+ iowrs I[$r15] $r5
+
+ // read 16-byte PCOPYn info, containing context pointer, from channel
+ shl b32 $r5 $r3 4
+ add b32 $r5 2
+ mov $xdbase $r5
+ mov $r5 $sp
+ // get a chunk of stack space, aligned to 256 byte boundary
+ sub b32 $r5 0x100
+ mov $r6 0xff
+ not b32 $r6
+ and $r5 $r6
+ sethi $r5 0x00020000
+ xdld $r4 $r5
+ xdwait
+ sethi $r5 0
+
+ // set context pointer, from within channel VM
+ mov $r14 0
+ iowrs I[$r15] $r14
+ ld b32 $r4 D[$r5 + 0]
+ shr b32 $r4 8
+ ld b32 $r6 D[$r5 + 4]
+ shl b32 $r6 24
+ or $r4 $r6
+ mov $xdbase $r4
+')
+ // 256-byte context, at start of data segment
+ mov b32 $r4 $r0
+ sethi $r4 0x60000
+
+ // swap!
+ bra $p1 swctx_load
+ xdst $r0 $r4
+ bra swctx_done
+ swctx_load:
+ xdld $r0 $r4
+ swctx_done:
+ xdwait
+ ret
+
+chsw:
+ // read current channel
+ mov $r2 0x1400
+ iord $r3 I[$r2]
+
+ // if it's active, unload it and return
+ xbit $r15 $r3 0x1e
+ bra e chsw_no_unload
+ bclr $flags $p1
+ call swctx
+ bclr $r3 0x1e
+ iowr I[$r2] $r3
+ mov $r4 1
+ iowr I[$r2 + 0x200] $r4
+ ret
+
+ // read next channel
+ chsw_no_unload:
+ iord $r3 I[$r2 + 0x100]
+
+ // is there a channel waiting to be loaded?
+ xbit $r13 $r3 0x1e
+ bra e chsw_finish_load
+ bset $flags $p1
+ call swctx
+ifdef(`NVA3',
+ // load dma objects back into TARGET regs
+ mov $r5 ctx_dma
+ mov $r6 ctx_dma_count
+ chsw_load_ctx_dma:
+ ld b32 $r7 D[$r5 + $r6 * 4]
+ add b32 $r8 $r6 0x180
+ shl b32 $r8 8
+ iowr I[$r8] $r7
+ sub b32 $r6 1
+ bra nc chsw_load_ctx_dma
+,)
+
+ chsw_finish_load:
+ mov $r3 2
+ iowr I[$r2 + 0x200] $r3
+ ret
+
+dispatch:
+ // read incoming fifo command
+ mov $r3 0x1900
+ iord $r2 I[$r3 + 0x100]
+ iord $r3 I[$r3 + 0x000]
+ and $r4 $r2 0x7ff
+ // $r2 will be used to store exception data
+ shl b32 $r2 0x10
+
+ // lookup method in the dispatch table, ILLEGAL_MTHD if not found
+ mov $r5 dispatch_table
+ clear b32 $r6
+ clear b32 $r7
+ dispatch_loop:
+ ld b16 $r6 D[$r5 + 0]
+ ld b16 $r7 D[$r5 + 2]
+ add b32 $r5 4
+ cmpu b32 $r4 $r6
+ bra c dispatch_illegal_mthd
+ add b32 $r7 $r6
+ cmpu b32 $r4 $r7
+ bra c dispatch_valid_mthd
+ sub b32 $r7 $r6
+ shl b32 $r7 3
+ add b32 $r5 $r7
+ bra dispatch_loop
+
+ // ensure no bits set in reserved fields, INVALID_BITFIELD
+ dispatch_valid_mthd:
+ sub b32 $r4 $r6
+ shl b32 $r4 3
+ add b32 $r4 $r5
+ ld b32 $r5 D[$r4 + 4]
+ and $r5 $r3
+ cmpu b32 $r5 0
+ bra ne dispatch_invalid_bitfield
+
+ // depending on dispatch flags: execute method, or save data as state
+ ld b16 $r5 D[$r4 + 0]
+ ld b16 $r6 D[$r4 + 2]
+ cmpu b32 $r6 0
+ bra ne dispatch_cmd
+ st b32 D[$r5] $r3
+ bra dispatch_done
+ dispatch_cmd:
+ bclr $flags $p1
+ call $r5
+ bra $p1 dispatch_error
+ bra dispatch_done
+
+ dispatch_invalid_bitfield:
+ or $r2 2
+ dispatch_illegal_mthd:
+ or $r2 1
+
+ // store exception data in SCRATCH0/SCRATCH1, signal hostirq
+ dispatch_error:
+ mov $r4 0x1000
+ iowr I[$r4 + 0x000] $r2
+ iowr I[$r4 + 0x100] $r3
+ mov $r2 0x40
+ iowr I[$r0] $r2
+ hostirq_wait:
+ iord $r2 I[$r0 + 0x200]
+ and $r2 0x40
+ cmpu b32 $r2 0
+ bra ne hostirq_wait
+
+ dispatch_done:
+ mov $r2 0x1d00
+ mov $r3 1
+ iowr I[$r2] $r3
+ ret
+
+// No-operation
+//
+// Inputs:
+// $r1: irqh state
+// $r2: hostirq state
+// $r3: data
+// $r4: dispatch table entry
+// Outputs:
+// $r1: irqh state
+// $p1: set on error
+// $r2: hostirq state
+// $r3: data
+cmd_nop:
+ ret
+
+// PM_TRIGGER
+//
+// Inputs:
+// $r1: irqh state
+// $r2: hostirq state
+// $r3: data
+// $r4: dispatch table entry
+// Outputs:
+// $r1: irqh state
+// $p1: set on error
+// $r2: hostirq state
+// $r3: data
+cmd_pm_trigger:
+ mov $r2 0x2200
+ clear b32 $r3
+ sethi $r3 0x20000
+ iowr I[$r2] $r3
+ ret
+
+ifdef(`NVA3',
+// SET_DMA_* method handler
+//
+// Inputs:
+// $r1: irqh state
+// $r2: hostirq state
+// $r3: data
+// $r4: dispatch table entry
+// Outputs:
+// $r1: irqh state
+// $p1: set on error
+// $r2: hostirq state
+// $r3: data
+cmd_dma:
+ sub b32 $r4 dispatch_dma
+ shr b32 $r4 1
+ bset $r3 0x1e
+ st b32 D[$r4 + ctx_dma] $r3
+ add b32 $r4 0x600
+ shl b32 $r4 6
+ iowr I[$r4] $r3
+ ret
+,)
+
+// Calculates the hw swizzle mask and adjusts the surface's xcnt to match
+//
+cmd_exec_set_format:
+ // zero out a chunk of the stack to store the swizzle into
+ add $sp -0x10
+ st b32 D[$sp + 0x00] $r0
+ st b32 D[$sp + 0x04] $r0
+ st b32 D[$sp + 0x08] $r0
+ st b32 D[$sp + 0x0c] $r0
+
+ // extract cpp, src_ncomp and dst_ncomp from FORMAT
+ ld b32 $r4 D[$r0 + ctx_format]
+ extr $r5 $r4 16:17
+ add b32 $r5 1
+ extr $r6 $r4 20:21
+ add b32 $r6 1
+ extr $r7 $r4 24:25
+ add b32 $r7 1
+
+ // convert FORMAT swizzle mask to hw swizzle mask
+ bclr $flags $p2
+ clear b32 $r8
+ clear b32 $r9
+ ncomp_loop:
+ and $r10 $r4 0xf
+ shr b32 $r4 4
+ clear b32 $r11
+ bpc_loop:
+ cmpu b8 $r10 4
+ bra nc cmp_c0
+ mulu $r12 $r10 $r5
+ add b32 $r12 $r11
+ bset $flags $p2
+ bra bpc_next
+ cmp_c0:
+ bra ne cmp_c1
+ mov $r12 0x10
+ add b32 $r12 $r11
+ bra bpc_next
+ cmp_c1:
+ cmpu b8 $r10 6
+ bra nc cmp_zero
+ mov $r12 0x14
+ add b32 $r12 $r11
+ bra bpc_next
+ cmp_zero:
+ mov $r12 0x80
+ bpc_next:
+ st b8 D[$sp + $r8] $r12
+ add b32 $r8 1
+ add b32 $r11 1
+ cmpu b32 $r11 $r5
+ bra c bpc_loop
+ add b32 $r9 1
+ cmpu b32 $r9 $r7
+ bra c ncomp_loop
+
+ // SRC_XCNT = (xcnt * src_cpp), or 0 if no src ref in swz (hw will hang)
+ mulu $r6 $r5
+ st b32 D[$r0 + ctx_src_cpp] $r6
+ ld b32 $r8 D[$r0 + ctx_xcnt]
+ mulu $r6 $r8
+ bra $p2 dst_xcnt
+ clear b32 $r6
+
+ dst_xcnt:
+ mulu $r7 $r5
+ st b32 D[$r0 + ctx_dst_cpp] $r7
+ mulu $r7 $r8
+
+ mov $r5 0x810
+ shl b32 $r5 6
+ iowr I[$r5 + 0x000] $r6
+ iowr I[$r5 + 0x100] $r7
+ add b32 $r5 0x800
+ ld b32 $r6 D[$r0 + ctx_dst_cpp]
+ sub b32 $r6 1
+ shl b32 $r6 8
+ ld b32 $r7 D[$r0 + ctx_src_cpp]
+ sub b32 $r7 1
+ or $r6 $r7
+ iowr I[$r5 + 0x000] $r6
+ add b32 $r5 0x100
+ ld b32 $r6 D[$sp + 0x00]
+ iowr I[$r5 + 0x000] $r6
+ ld b32 $r6 D[$sp + 0x04]
+ iowr I[$r5 + 0x100] $r6
+ ld b32 $r6 D[$sp + 0x08]
+ iowr I[$r5 + 0x200] $r6
+ ld b32 $r6 D[$sp + 0x0c]
+ iowr I[$r5 + 0x300] $r6
+ add b32 $r5 0x400
+ ld b32 $r6 D[$r0 + ctx_swz_const0]
+ iowr I[$r5 + 0x000] $r6
+ ld b32 $r6 D[$r0 + ctx_swz_const1]
+ iowr I[$r5 + 0x100] $r6
+ add $sp 0x10
+ ret
+
+// Setup to handle a tiled surface
+//
+// Calculates a number of parameters the hardware requires in order
+// to correctly handle tiling.
+//
+// Offset calculation is performed as follows (Tp/Th/Td from TILE_MODE):
+// nTx = round_up(w * cpp, 1 << Tp) >> Tp
+// nTy = round_up(h, 1 << Th) >> Th
+// Txo = (x * cpp) & ((1 << Tp) - 1)
+// Tx = (x * cpp) >> Tp
+// Tyo = y & ((1 << Th) - 1)
+// Ty = y >> Th
+// Tzo = z & ((1 << Td) - 1)
+// Tz = z >> Td
+//
+// off = (Tzo << Tp << Th) + (Tyo << Tp) + Txo
+// off += ((Tz * nTy * nTx)) + (Ty * nTx) + Tx) << Td << Th << Tp;
+//
+// Inputs:
+// $r4: hw command (0x104800)
+// $r5: ctx offset adjustment for src/dst selection
+// $p2: set if dst surface
+//
+cmd_exec_set_surface_tiled:
+ // translate TILE_MODE into Tp, Th, Td shift values
+ ld b32 $r7 D[$r5 + ctx_src_tile_mode]
+ extr $r9 $r7 8:11
+ extr $r8 $r7 4:7
+ifdef(`NVA3',
+ add b32 $r8 2
+,
+ add b32 $r8 3
+)
+ extr $r7 $r7 0:3
+ cmp b32 $r7 0xe
+ bra ne xtile64
+ mov $r7 4
+ bra xtileok
+ xtile64:
+ xbit $r7 $flags $p2
+ add b32 $r7 17
+ bset $r4 $r7
+ mov $r7 6
+ xtileok:
+
+ // Op = (x * cpp) & ((1 << Tp) - 1)
+ // Tx = (x * cpp) >> Tp
+ ld b32 $r10 D[$r5 + ctx_src_xoff]
+ ld b32 $r11 D[$r5 + ctx_src_cpp]
+ mulu $r10 $r11
+ mov $r11 1
+ shl b32 $r11 $r7
+ sub b32 $r11 1
+ and $r12 $r10 $r11
+ shr b32 $r10 $r7
+
+ // Tyo = y & ((1 << Th) - 1)
+ // Ty = y >> Th
+ ld b32 $r13 D[$r5 + ctx_src_yoff]
+ mov $r14 1
+ shl b32 $r14 $r8
+ sub b32 $r14 1
+ and $r11 $r13 $r14
+ shr b32 $r13 $r8
+
+ // YTILE = ((1 << Th) << 12) | ((1 << Th) - Tyo)
+ add b32 $r14 1
+ shl b32 $r15 $r14 12
+ sub b32 $r14 $r11
+ or $r15 $r14
+ xbit $r6 $flags $p2
+ add b32 $r6 0x208
+ shl b32 $r6 8
+ iowr I[$r6 + 0x000] $r15
+
+ // Op += Tyo << Tp
+ shl b32 $r11 $r7
+ add b32 $r12 $r11
+
+ // nTx = ((w * cpp) + ((1 << Tp) - 1) >> Tp)
+ ld b32 $r15 D[$r5 + ctx_src_xsize]
+ ld b32 $r11 D[$r5 + ctx_src_cpp]
+ mulu $r15 $r11
+ mov $r11 1
+ shl b32 $r11 $r7
+ sub b32 $r11 1
+ add b32 $r15 $r11
+ shr b32 $r15 $r7
+ push $r15
+
+ // nTy = (h + ((1 << Th) - 1)) >> Th
+ ld b32 $r15 D[$r5 + ctx_src_ysize]
+ mov $r11 1
+ shl b32 $r11 $r8
+ sub b32 $r11 1
+ add b32 $r15 $r11
+ shr b32 $r15 $r8
+ push $r15
+
+ // Tys = Tp + Th
+ // CFG_YZ_TILE_SIZE = ((1 << Th) >> 2) << Td
+ add b32 $r7 $r8
+ sub b32 $r8 2
+ mov $r11 1
+ shl b32 $r11 $r8
+ shl b32 $r11 $r9
+
+ // Tzo = z & ((1 << Td) - 1)
+ // Tz = z >> Td
+ // Op += Tzo << Tys
+ // Ts = Tys + Td
+ ld b32 $r8 D[$r5 + ctx_src_zoff]
+ mov $r14 1
+ shl b32 $r14 $r9
+ sub b32 $r14 1
+ and $r15 $r8 $r14
+ shl b32 $r15 $r7
+ add b32 $r12 $r15
+ add b32 $r7 $r9
+ shr b32 $r8 $r9
+
+ // Ot = ((Tz * nTy * nTx) + (Ty * nTx) + Tx) << Ts
+ pop $r15
+ pop $r9
+ mulu $r13 $r9
+ add b32 $r10 $r13
+ mulu $r8 $r9
+ mulu $r8 $r15
+ add b32 $r10 $r8
+ shl b32 $r10 $r7
+
+ // PITCH = (nTx - 1) << Ts
+ sub b32 $r9 1
+ shl b32 $r9 $r7
+ iowr I[$r6 + 0x200] $r9
+
+ // SRC_ADDRESS_LOW = (Ot + Op) & 0xffffffff
+ // CFG_ADDRESS_HIGH |= ((Ot + Op) >> 32) << 16
+ ld b32 $r7 D[$r5 + ctx_src_address_low]
+ ld b32 $r8 D[$r5 + ctx_src_address_high]
+ add b32 $r10 $r12
+ add b32 $r7 $r10
+ adc b32 $r8 0
+ shl b32 $r8 16
+ or $r8 $r11
+ sub b32 $r6 0x600
+ iowr I[$r6 + 0x000] $r7
+ add b32 $r6 0x400
+ iowr I[$r6 + 0x000] $r8
+ ret
+
+// Setup to handle a linear surface
+//
+// Nothing to see here.. Sets ADDRESS and PITCH, pretty non-exciting
+//
+cmd_exec_set_surface_linear:
+ xbit $r6 $flags $p2
+ add b32 $r6 0x202
+ shl b32 $r6 8
+ ld b32 $r7 D[$r5 + ctx_src_address_low]
+ iowr I[$r6 + 0x000] $r7
+ add b32 $r6 0x400
+ ld b32 $r7 D[$r5 + ctx_src_address_high]
+ shl b32 $r7 16
+ iowr I[$r6 + 0x000] $r7
+ add b32 $r6 0x400
+ ld b32 $r7 D[$r5 + ctx_src_pitch]
+ iowr I[$r6 + 0x000] $r7
+ ret
+
+// wait for regs to be available for use
+cmd_exec_wait:
+ push $r0
+ push $r1
+ mov $r0 0x800
+ shl b32 $r0 6
+ loop:
+ iord $r1 I[$r0]
+ and $r1 1
+ bra ne loop
+ pop $r1
+ pop $r0
+ ret
+
+cmd_exec_query:
+ // if QUERY_SHORT not set, write out { -, 0, TIME_LO, TIME_HI }
+ xbit $r4 $r3 13
+ bra ne query_counter
+ call cmd_exec_wait
+ mov $r4 0x80c
+ shl b32 $r4 6
+ ld b32 $r5 D[$r0 + ctx_query_address_low]
+ add b32 $r5 4
+ iowr I[$r4 + 0x000] $r5
+ iowr I[$r4 + 0x100] $r0
+ mov $r5 0xc
+ iowr I[$r4 + 0x200] $r5
+ add b32 $r4 0x400
+ ld b32 $r5 D[$r0 + ctx_query_address_high]
+ shl b32 $r5 16
+ iowr I[$r4 + 0x000] $r5
+ add b32 $r4 0x500
+ mov $r5 0x00000b00
+ sethi $r5 0x00010000
+ iowr I[$r4 + 0x000] $r5
+ mov $r5 0x00004040
+ shl b32 $r5 1
+ sethi $r5 0x80800000
+ iowr I[$r4 + 0x100] $r5
+ mov $r5 0x00001110
+ sethi $r5 0x13120000
+ iowr I[$r4 + 0x200] $r5
+ mov $r5 0x00001514
+ sethi $r5 0x17160000
+ iowr I[$r4 + 0x300] $r5
+ mov $r5 0x00002601
+ sethi $r5 0x00010000
+ mov $r4 0x800
+ shl b32 $r4 6
+ iowr I[$r4 + 0x000] $r5
+
+ // write COUNTER
+ query_counter:
+ call cmd_exec_wait
+ mov $r4 0x80c
+ shl b32 $r4 6
+ ld b32 $r5 D[$r0 + ctx_query_address_low]
+ iowr I[$r4 + 0x000] $r5
+ iowr I[$r4 + 0x100] $r0
+ mov $r5 0x4
+ iowr I[$r4 + 0x200] $r5
+ add b32 $r4 0x400
+ ld b32 $r5 D[$r0 + ctx_query_address_high]
+ shl b32 $r5 16
+ iowr I[$r4 + 0x000] $r5
+ add b32 $r4 0x500
+ mov $r5 0x00000300
+ iowr I[$r4 + 0x000] $r5
+ mov $r5 0x00001110
+ sethi $r5 0x13120000
+ iowr I[$r4 + 0x100] $r5
+ ld b32 $r5 D[$r0 + ctx_query_counter]
+ add b32 $r4 0x500
+ iowr I[$r4 + 0x000] $r5
+ mov $r5 0x00002601
+ sethi $r5 0x00010000
+ mov $r4 0x800
+ shl b32 $r4 6
+ iowr I[$r4 + 0x000] $r5
+ ret
+
+// Execute a copy operation
+//
+// Inputs:
+// $r1: irqh state
+// $r2: hostirq state
+// $r3: data
+// 000002000 QUERY_SHORT
+// 000001000 QUERY
+// 000000100 DST_LINEAR
+// 000000010 SRC_LINEAR
+// 000000001 FORMAT
+// $r4: dispatch table entry
+// Outputs:
+// $r1: irqh state
+// $p1: set on error
+// $r2: hostirq state
+// $r3: data
+cmd_exec:
+ call cmd_exec_wait
+
+ // if format requested, call function to calculate it, otherwise
+ // fill in cpp/xcnt for both surfaces as if (cpp == 1)
+ xbit $r15 $r3 0
+ bra e cmd_exec_no_format
+ call cmd_exec_set_format
+ mov $r4 0x200
+ bra cmd_exec_init_src_surface
+ cmd_exec_no_format:
+ mov $r6 0x810
+ shl b32 $r6 6
+ mov $r7 1
+ st b32 D[$r0 + ctx_src_cpp] $r7
+ st b32 D[$r0 + ctx_dst_cpp] $r7
+ ld b32 $r7 D[$r0 + ctx_xcnt]
+ iowr I[$r6 + 0x000] $r7
+ iowr I[$r6 + 0x100] $r7
+ clear b32 $r4
+
+ cmd_exec_init_src_surface:
+ bclr $flags $p2
+ clear b32 $r5
+ xbit $r15 $r3 4
+ bra e src_tiled
+ call cmd_exec_set_surface_linear
+ bra cmd_exec_init_dst_surface
+ src_tiled:
+ call cmd_exec_set_surface_tiled
+ bset $r4 7
+
+ cmd_exec_init_dst_surface:
+ bset $flags $p2
+ mov $r5 ctx_dst_address_high - ctx_src_address_high
+ xbit $r15 $r3 8
+ bra e dst_tiled
+ call cmd_exec_set_surface_linear
+ bra cmd_exec_kick
+ dst_tiled:
+ call cmd_exec_set_surface_tiled
+ bset $r4 8
+
+ cmd_exec_kick:
+ mov $r5 0x800
+ shl b32 $r5 6
+ ld b32 $r6 D[$r0 + ctx_ycnt]
+ iowr I[$r5 + 0x100] $r6
+ mov $r6 0x0041
+ // SRC_TARGET = 1, DST_TARGET = 2
+ sethi $r6 0x44000000
+ or $r4 $r6
+ iowr I[$r5] $r4
+
+ // if requested, queue up a QUERY write after the copy has completed
+ xbit $r15 $r3 12
+ bra e cmd_exec_done
+ call cmd_exec_query
+
+ cmd_exec_done:
+ ret
+
+// Flush write cache
+//
+// Inputs:
+// $r1: irqh state
+// $r2: hostirq state
+// $r3: data
+// $r4: dispatch table entry
+// Outputs:
+// $r1: irqh state
+// $p1: set on error
+// $r2: hostirq state
+// $r3: data
+cmd_wrcache_flush:
+ mov $r2 0x2200
+ clear b32 $r3
+ sethi $r3 0x10000
+ iowr I[$r2] $r3
+ ret
+
+.align 0x100
diff --git a/drivers/gpu/drm/nouveau/nva3_copy.fuc.h b/drivers/gpu/drm/nouveau/nva3_copy.fuc.h
new file mode 100644
index 000000000000..2731de22ebe9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nva3_copy.fuc.h
@@ -0,0 +1,534 @@
+uint32_t nva3_pcopy_data[] = {
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00010000,
+ 0x00000000,
+ 0x00000000,
+ 0x00010040,
+ 0x00010160,
+ 0x00000000,
+ 0x00010050,
+ 0x00010162,
+ 0x00000000,
+ 0x00030060,
+ 0x00010170,
+ 0x00000000,
+ 0x00010170,
+ 0x00000000,
+ 0x00010170,
+ 0x00000000,
+ 0x00070080,
+ 0x00000028,
+ 0xfffff000,
+ 0x0000002c,
+ 0xfff80000,
+ 0x00000030,
+ 0xffffe000,
+ 0x00000034,
+ 0xfffff800,
+ 0x00000038,
+ 0xfffff000,
+ 0x0000003c,
+ 0xfff80000,
+ 0x00000040,
+ 0xffffe000,
+ 0x00070088,
+ 0x00000054,
+ 0xfffff000,
+ 0x00000058,
+ 0xfff80000,
+ 0x0000005c,
+ 0xffffe000,
+ 0x00000060,
+ 0xfffff800,
+ 0x00000064,
+ 0xfffff000,
+ 0x00000068,
+ 0xfff80000,
+ 0x0000006c,
+ 0xffffe000,
+ 0x000200c0,
+ 0x00010492,
+ 0x00000000,
+ 0x0001051b,
+ 0x00000000,
+ 0x000e00c3,
+ 0x0000001c,
+ 0xffffff00,
+ 0x00000020,
+ 0x0000000f,
+ 0x00000048,
+ 0xffffff00,
+ 0x0000004c,
+ 0x0000000f,
+ 0x00000024,
+ 0xfff80000,
+ 0x00000050,
+ 0xfff80000,
+ 0x00000080,
+ 0xffff0000,
+ 0x00000084,
+ 0xffffe000,
+ 0x00000074,
+ 0xfccc0000,
+ 0x00000078,
+ 0x00000000,
+ 0x0000007c,
+ 0x00000000,
+ 0x00000010,
+ 0xffffff00,
+ 0x00000014,
+ 0x00000000,
+ 0x00000018,
+ 0x00000000,
+ 0x00000800,
+};
+
+uint32_t nva3_pcopy_code[] = {
+ 0x04fe04bd,
+ 0x3517f000,
+ 0xf10010fe,
+ 0xf1040017,
+ 0xf0fff327,
+ 0x22d00023,
+ 0x0c25f0c0,
+ 0xf40012d0,
+ 0x17f11031,
+ 0x27f01200,
+ 0x0012d003,
+ 0xf40031f4,
+ 0x0ef40028,
+ 0x8001cffd,
+ 0xf40812c4,
+ 0x21f4060b,
+ 0x0412c472,
+ 0xf4060bf4,
+ 0x11c4c321,
+ 0x4001d00c,
+ 0x47f101f8,
+ 0x4bfe7700,
+ 0x0007fe00,
+ 0xf00204b9,
+ 0x01f40643,
+ 0x0604fa09,
+ 0xfa060ef4,
+ 0x03f80504,
+ 0x27f100f8,
+ 0x23cf1400,
+ 0x1e3fc800,
+ 0xf4170bf4,
+ 0x21f40132,
+ 0x1e3af052,
+ 0xf00023d0,
+ 0x24d00147,
+ 0xcf00f880,
+ 0x3dc84023,
+ 0x220bf41e,
+ 0xf40131f4,
+ 0x57f05221,
+ 0x0367f004,
+ 0xa07856bc,
+ 0xb6018068,
+ 0x87d00884,
+ 0x0162b600,
+ 0xf0f018f4,
+ 0x23d00237,
+ 0xf100f880,
+ 0xcf190037,
+ 0x33cf4032,
+ 0xff24e400,
+ 0x1024b607,
+ 0x010057f1,
+ 0x74bd64bd,
+ 0x58005658,
+ 0x50b60157,
+ 0x0446b804,
+ 0xbb4d08f4,
+ 0x47b80076,
+ 0x0f08f404,
+ 0xb60276bb,
+ 0x57bb0374,
+ 0xdf0ef400,
+ 0xb60246bb,
+ 0x45bb0344,
+ 0x01459800,
+ 0xb00453fd,
+ 0x1bf40054,
+ 0x00455820,
+ 0xb0014658,
+ 0x1bf40064,
+ 0x00538009,
+ 0xf4300ef4,
+ 0x55f90132,
+ 0xf40c01f4,
+ 0x25f0250e,
+ 0x0125f002,
+ 0x100047f1,
+ 0xd00042d0,
+ 0x27f04043,
+ 0x0002d040,
+ 0xf08002cf,
+ 0x24b04024,
+ 0xf71bf400,
+ 0x1d0027f1,
+ 0xd00137f0,
+ 0x00f80023,
+ 0x27f100f8,
+ 0x34bd2200,
+ 0xd00233f0,
+ 0x00f80023,
+ 0x012842b7,
+ 0xf00145b6,
+ 0x43801e39,
+ 0x0040b701,
+ 0x0644b606,
+ 0xf80043d0,
+ 0xf030f400,
+ 0xb00001b0,
+ 0x01b00101,
+ 0x0301b002,
+ 0xc71d0498,
+ 0x50b63045,
+ 0x3446c701,
+ 0xc70160b6,
+ 0x70b63847,
+ 0x0232f401,
+ 0x94bd84bd,
+ 0xb60f4ac4,
+ 0xb4bd0445,
+ 0xf404a430,
+ 0xa5ff0f18,
+ 0x00cbbbc0,
+ 0xf40231f4,
+ 0x1bf4220e,
+ 0x10c7f00c,
+ 0xf400cbbb,
+ 0xa430160e,
+ 0x0c18f406,
+ 0xbb14c7f0,
+ 0x0ef400cb,
+ 0x80c7f107,
+ 0x01c83800,
+ 0xb60180b6,
+ 0xb5b801b0,
+ 0xc308f404,
+ 0xb80190b6,
+ 0x08f40497,
+ 0x0065fdb2,
+ 0x98110680,
+ 0x68fd2008,
+ 0x0502f400,
+ 0x75fd64bd,
+ 0x1c078000,
+ 0xf10078fd,
+ 0xb6081057,
+ 0x56d00654,
+ 0x4057d000,
+ 0x080050b7,
+ 0xb61c0698,
+ 0x64b60162,
+ 0x11079808,
+ 0xfd0172b6,
+ 0x56d00567,
+ 0x0050b700,
+ 0x0060b401,
+ 0xb40056d0,
+ 0x56d00160,
+ 0x0260b440,
+ 0xb48056d0,
+ 0x56d00360,
+ 0x0050b7c0,
+ 0x1e069804,
+ 0x980056d0,
+ 0x56d01f06,
+ 0x1030f440,
+ 0x579800f8,
+ 0x6879c70a,
+ 0xb66478c7,
+ 0x77c70280,
+ 0x0e76b060,
+ 0xf0091bf4,
+ 0x0ef40477,
+ 0x027cf00f,
+ 0xfd1170b6,
+ 0x77f00947,
+ 0x0f5a9806,
+ 0xfd115b98,
+ 0xb7f000ab,
+ 0x04b7bb01,
+ 0xff01b2b6,
+ 0xa7bbc4ab,
+ 0x105d9805,
+ 0xbb01e7f0,
+ 0xe2b604e8,
+ 0xb4deff01,
+ 0xb605d8bb,
+ 0xef9401e0,
+ 0x02ebbb0c,
+ 0xf005fefd,
+ 0x60b7026c,
+ 0x64b60208,
+ 0x006fd008,
+ 0xbb04b7bb,
+ 0x5f9800cb,
+ 0x115b980b,
+ 0xf000fbfd,
+ 0xb7bb01b7,
+ 0x01b2b604,
+ 0xbb00fbbb,
+ 0xf0f905f7,
+ 0xf00c5f98,
+ 0xb8bb01b7,
+ 0x01b2b604,
+ 0xbb00fbbb,
+ 0xf0f905f8,
+ 0xb60078bb,
+ 0xb7f00282,
+ 0x04b8bb01,
+ 0x9804b9bb,
+ 0xe7f00e58,
+ 0x04e9bb01,
+ 0xff01e2b6,
+ 0xf7bbf48e,
+ 0x00cfbb04,
+ 0xbb0079bb,
+ 0xf0fc0589,
+ 0xd9fd90fc,
+ 0x00adbb00,
+ 0xfd0089fd,
+ 0xa8bb008f,
+ 0x04a7bb00,
+ 0xbb0192b6,
+ 0x69d00497,
+ 0x08579880,
+ 0xbb075898,
+ 0x7abb00ac,
+ 0x0081b600,
+ 0xfd1084b6,
+ 0x62b7058b,
+ 0x67d00600,
+ 0x0060b700,
+ 0x0068d004,
+ 0x6cf000f8,
+ 0x0260b702,
+ 0x0864b602,
+ 0xd0085798,
+ 0x60b70067,
+ 0x57980400,
+ 0x1074b607,
+ 0xb70067d0,
+ 0x98040060,
+ 0x67d00957,
+ 0xf900f800,
+ 0xf110f900,
+ 0xb6080007,
+ 0x01cf0604,
+ 0x0114f000,
+ 0xfcfa1bf4,
+ 0xf800fc10,
+ 0x0d34c800,
+ 0xf5701bf4,
+ 0xf103ab21,
+ 0xb6080c47,
+ 0x05980644,
+ 0x0450b605,
+ 0xd00045d0,
+ 0x57f04040,
+ 0x8045d00c,
+ 0x040040b7,
+ 0xb6040598,
+ 0x45d01054,
+ 0x0040b700,
+ 0x0057f105,
+ 0x0153f00b,
+ 0xf10045d0,
+ 0xb6404057,
+ 0x53f10154,
+ 0x45d08080,
+ 0x1057f140,
+ 0x1253f111,
+ 0x8045d013,
+ 0x151457f1,
+ 0x171653f1,
+ 0xf1c045d0,
+ 0xf0260157,
+ 0x47f10153,
+ 0x44b60800,
+ 0x0045d006,
+ 0x03ab21f5,
+ 0x080c47f1,
+ 0x980644b6,
+ 0x45d00505,
+ 0x4040d000,
+ 0xd00457f0,
+ 0x40b78045,
+ 0x05980400,
+ 0x1054b604,
+ 0xb70045d0,
+ 0xf1050040,
+ 0xd0030057,
+ 0x57f10045,
+ 0x53f11110,
+ 0x45d01312,
+ 0x06059840,
+ 0x050040b7,
+ 0xf10045d0,
+ 0xf0260157,
+ 0x47f10153,
+ 0x44b60800,
+ 0x0045d006,
+ 0x21f500f8,
+ 0x3fc803ab,
+ 0x0e0bf400,
+ 0x018921f5,
+ 0x020047f1,
+ 0xf11e0ef4,
+ 0xb6081067,
+ 0x77f00664,
+ 0x11078001,
+ 0x981c0780,
+ 0x67d02007,
+ 0x4067d000,
+ 0x32f444bd,
+ 0xc854bd02,
+ 0x0bf4043f,
+ 0x8221f50a,
+ 0x0a0ef403,
+ 0x027621f5,
+ 0xf40749f0,
+ 0x57f00231,
+ 0x083fc82c,
+ 0xf50a0bf4,
+ 0xf4038221,
+ 0x21f50a0e,
+ 0x49f00276,
+ 0x0057f108,
+ 0x0654b608,
+ 0xd0210698,
+ 0x67f04056,
+ 0x0063f141,
+ 0x0546fd44,
+ 0xc80054d0,
+ 0x0bf40c3f,
+ 0xc521f507,
+ 0xf100f803,
+ 0xbd220027,
+ 0x0133f034,
+ 0xf80023d0,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nva3_pm.c b/drivers/gpu/drm/nouveau/nva3_pm.c
index dbbafed36406..e4b2b9e934b2 100644
--- a/drivers/gpu/drm/nouveau/nva3_pm.c
+++ b/drivers/gpu/drm/nouveau/nva3_pm.c
@@ -27,32 +27,74 @@
#include "nouveau_bios.h"
#include "nouveau_pm.h"
-/*XXX: boards using limits 0x40 need fixing, the register layout
- * is correct here, but, there's some other funny magic
- * that modifies things, so it's not likely we'll set/read
- * the correct timings yet.. working on it...
+/* This is actually a lot more complex than it appears here, but hopefully
+ * this should be able to deal with what the VBIOS leaves for us..
+ *
+ * If not, well, I'll jump off that bridge when I come to it.
*/
struct nva3_pm_state {
- struct pll_lims pll;
- int N, M, P;
+ enum pll_types type;
+ u32 src0;
+ u32 src1;
+ u32 ctrl;
+ u32 coef;
+ u32 old_pnm;
+ u32 new_pnm;
+ u32 new_div;
};
+static int
+nva3_pm_pll_offset(u32 id)
+{
+ static const u32 pll_map[] = {
+ 0x00, PLL_CORE,
+ 0x01, PLL_SHADER,
+ 0x02, PLL_MEMORY,
+ 0x00, 0x00
+ };
+ const u32 *map = pll_map;
+
+ while (map[1]) {
+ if (id == map[1])
+ return map[0];
+ map += 2;
+ }
+
+ return -ENOENT;
+}
+
int
nva3_pm_clock_get(struct drm_device *dev, u32 id)
{
+ u32 src0, src1, ctrl, coef;
struct pll_lims pll;
- int P, N, M, ret;
- u32 reg;
+ int ret, off;
+ int P, N, M;
ret = get_pll_limits(dev, id, &pll);
if (ret)
return ret;
- reg = nv_rd32(dev, pll.reg + 4);
- P = (reg & 0x003f0000) >> 16;
- N = (reg & 0x0000ff00) >> 8;
- M = (reg & 0x000000ff);
+ off = nva3_pm_pll_offset(id);
+ if (off < 0)
+ return off;
+
+ src0 = nv_rd32(dev, 0x4120 + (off * 4));
+ src1 = nv_rd32(dev, 0x4160 + (off * 4));
+ ctrl = nv_rd32(dev, pll.reg + 0);
+ coef = nv_rd32(dev, pll.reg + 4);
+ NV_DEBUG(dev, "PLL %02x: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ id, src0, src1, ctrl, coef);
+
+ if (ctrl & 0x00000008) {
+ u32 div = ((src1 & 0x003c0000) >> 18) + 1;
+ return (pll.refclk * 2) / div;
+ }
+
+ P = (coef & 0x003f0000) >> 16;
+ N = (coef & 0x0000ff00) >> 8;
+ M = (coef & 0x000000ff);
return pll.refclk * N / M / P;
}
@@ -60,36 +102,103 @@ void *
nva3_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl,
u32 id, int khz)
{
- struct nva3_pm_state *state;
- int dummy, ret;
+ struct nva3_pm_state *pll;
+ struct pll_lims limits;
+ int N, M, P, diff;
+ int ret, off;
+
+ ret = get_pll_limits(dev, id, &limits);
+ if (ret < 0)
+ return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
+
+ off = nva3_pm_pll_offset(id);
+ if (id < 0)
+ return ERR_PTR(-EINVAL);
- state = kzalloc(sizeof(*state), GFP_KERNEL);
- if (!state)
+
+ pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+ if (!pll)
return ERR_PTR(-ENOMEM);
+ pll->type = id;
+ pll->src0 = 0x004120 + (off * 4);
+ pll->src1 = 0x004160 + (off * 4);
+ pll->ctrl = limits.reg + 0;
+ pll->coef = limits.reg + 4;
- ret = get_pll_limits(dev, id, &state->pll);
- if (ret < 0) {
- kfree(state);
- return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
+ /* If target clock is within [-2, 3) MHz of a divisor, we'll
+ * use that instead of calculating MNP values
+ */
+ pll->new_div = min((limits.refclk * 2) / (khz - 2999), 16);
+ if (pll->new_div) {
+ diff = khz - ((limits.refclk * 2) / pll->new_div);
+ if (diff < -2000 || diff >= 3000)
+ pll->new_div = 0;
}
- ret = nv50_calc_pll2(dev, &state->pll, khz, &state->N, &dummy,
- &state->M, &state->P);
- if (ret < 0) {
- kfree(state);
- return ERR_PTR(ret);
+ if (!pll->new_div) {
+ ret = nva3_calc_pll(dev, &limits, khz, &N, NULL, &M, &P);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ pll->new_pnm = (P << 16) | (N << 8) | M;
+ pll->new_div = 2 - 1;
+ } else {
+ pll->new_pnm = 0;
+ pll->new_div--;
}
- return state;
+ if ((nv_rd32(dev, pll->src1) & 0x00000101) != 0x00000101)
+ pll->old_pnm = nv_rd32(dev, pll->coef);
+ return pll;
}
void
nva3_pm_clock_set(struct drm_device *dev, void *pre_state)
{
- struct nva3_pm_state *state = pre_state;
- u32 reg = state->pll.reg;
+ struct nva3_pm_state *pll = pre_state;
+ u32 ctrl = 0;
+
+ /* For the memory clock, NVIDIA will build a "script" describing
+ * the reclocking process and ask PDAEMON to execute it.
+ */
+ if (pll->type == PLL_MEMORY) {
+ nv_wr32(dev, 0x100210, 0);
+ nv_wr32(dev, 0x1002dc, 1);
+ nv_wr32(dev, 0x004018, 0x00001000);
+ ctrl = 0x18000100;
+ }
+
+ if (pll->old_pnm || !pll->new_pnm) {
+ nv_mask(dev, pll->src1, 0x003c0101, 0x00000101 |
+ (pll->new_div << 18));
+ nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl);
+ nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000);
+ }
+
+ if (pll->new_pnm) {
+ nv_mask(dev, pll->src0, 0x00000101, 0x00000101);
+ nv_wr32(dev, pll->coef, pll->new_pnm);
+ nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl);
+ nv_mask(dev, pll->ctrl, 0x00000010, 0x00000000);
+ nv_mask(dev, pll->ctrl, 0x00020010, 0x00020010);
+ nv_wr32(dev, pll->ctrl, 0x00010015 | ctrl);
+ nv_mask(dev, pll->src1, 0x00000100, 0x00000000);
+ nv_mask(dev, pll->src1, 0x00000001, 0x00000000);
+ if (pll->type == PLL_MEMORY)
+ nv_wr32(dev, 0x4018, 0x10005000);
+ } else {
+ nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000);
+ nv_mask(dev, pll->src0, 0x00000100, 0x00000000);
+ nv_mask(dev, pll->src0, 0x00000001, 0x00000000);
+ if (pll->type == PLL_MEMORY)
+ nv_wr32(dev, 0x4018, 0x1000d000);
+ }
+
+ if (pll->type == PLL_MEMORY) {
+ nv_wr32(dev, 0x1002dc, 0);
+ nv_wr32(dev, 0x100210, 0x80000000);
+ }
- nv_wr32(dev, reg + 4, (state->P << 16) | (state->N << 8) | state->M);
- kfree(state);
+ kfree(pll);
}
diff --git a/drivers/gpu/drm/nouveau/nvc0_copy.c b/drivers/gpu/drm/nouveau/nvc0_copy.c
new file mode 100644
index 000000000000..208fa7ab3f42
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvc0_copy.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2011 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 "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_util.h"
+#include "nouveau_vm.h"
+#include "nouveau_ramht.h"
+#include "nvc0_copy.fuc.h"
+
+struct nvc0_copy_engine {
+ struct nouveau_exec_engine base;
+ u32 irq;
+ u32 pmc;
+ u32 fuc;
+ u32 ctx;
+};
+
+static int
+nvc0_copy_context_new(struct nouveau_channel *chan, int engine)
+{
+ struct nvc0_copy_engine *pcopy = nv_engine(chan->dev, engine);
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nouveau_gpuobj *ramin = chan->ramin;
+ struct nouveau_gpuobj *ctx = NULL;
+ int ret;
+
+ ret = nouveau_gpuobj_new(dev, NULL, 256, 256,
+ NVOBJ_FLAG_VM | NVOBJ_FLAG_VM_USER |
+ NVOBJ_FLAG_ZERO_ALLOC, &ctx);
+ if (ret)
+ return ret;
+
+ nv_wo32(ramin, pcopy->ctx + 0, lower_32_bits(ctx->vinst));
+ nv_wo32(ramin, pcopy->ctx + 4, upper_32_bits(ctx->vinst));
+ dev_priv->engine.instmem.flush(dev);
+
+ chan->engctx[engine] = ctx;
+ return 0;
+}
+
+static int
+nvc0_copy_object_new(struct nouveau_channel *chan, int engine,
+ u32 handle, u16 class)
+{
+ return 0;
+}
+
+static void
+nvc0_copy_context_del(struct nouveau_channel *chan, int engine)
+{
+ struct nvc0_copy_engine *pcopy = nv_engine(chan->dev, engine);
+ struct nouveau_gpuobj *ctx = chan->engctx[engine];
+ struct drm_device *dev = chan->dev;
+ u32 inst;
+
+ inst = (chan->ramin->vinst >> 12);
+ inst |= 0x40000000;
+
+ /* disable fifo access */
+ nv_wr32(dev, pcopy->fuc + 0x048, 0x00000000);
+ /* mark channel as unloaded if it's currently active */
+ if (nv_rd32(dev, pcopy->fuc + 0x050) == inst)
+ nv_mask(dev, pcopy->fuc + 0x050, 0x40000000, 0x00000000);
+ /* mark next channel as invalid if it's about to be loaded */
+ if (nv_rd32(dev, pcopy->fuc + 0x054) == inst)
+ nv_mask(dev, pcopy->fuc + 0x054, 0x40000000, 0x00000000);
+ /* restore fifo access */
+ nv_wr32(dev, pcopy->fuc + 0x048, 0x00000003);
+
+ nv_wo32(chan->ramin, pcopy->ctx + 0, 0x00000000);
+ nv_wo32(chan->ramin, pcopy->ctx + 4, 0x00000000);
+ nouveau_gpuobj_ref(NULL, &ctx);
+
+ chan->engctx[engine] = ctx;
+}
+
+static int
+nvc0_copy_init(struct drm_device *dev, int engine)
+{
+ struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
+ int i;
+
+ nv_mask(dev, 0x000200, pcopy->pmc, 0x00000000);
+ nv_mask(dev, 0x000200, pcopy->pmc, pcopy->pmc);
+ nv_wr32(dev, pcopy->fuc + 0x014, 0xffffffff);
+
+ nv_wr32(dev, pcopy->fuc + 0x1c0, 0x01000000);
+ for (i = 0; i < sizeof(nvc0_pcopy_data) / 4; i++)
+ nv_wr32(dev, pcopy->fuc + 0x1c4, nvc0_pcopy_data[i]);
+
+ nv_wr32(dev, pcopy->fuc + 0x180, 0x01000000);
+ for (i = 0; i < sizeof(nvc0_pcopy_code) / 4; i++) {
+ if ((i & 0x3f) == 0)
+ nv_wr32(dev, pcopy->fuc + 0x188, i >> 6);
+ nv_wr32(dev, pcopy->fuc + 0x184, nvc0_pcopy_code[i]);
+ }
+
+ nv_wr32(dev, pcopy->fuc + 0x084, engine - NVOBJ_ENGINE_COPY0);
+ nv_wr32(dev, pcopy->fuc + 0x10c, 0x00000000);
+ nv_wr32(dev, pcopy->fuc + 0x104, 0x00000000); /* ENTRY */
+ nv_wr32(dev, pcopy->fuc + 0x100, 0x00000002); /* TRIGGER */
+ return 0;
+}
+
+static int
+nvc0_copy_fini(struct drm_device *dev, int engine)
+{
+ struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
+
+ nv_mask(dev, pcopy->fuc + 0x048, 0x00000003, 0x00000000);
+
+ /* trigger fuc context unload */
+ nv_wait(dev, pcopy->fuc + 0x008, 0x0000000c, 0x00000000);
+ nv_mask(dev, pcopy->fuc + 0x054, 0x40000000, 0x00000000);
+ nv_wr32(dev, pcopy->fuc + 0x000, 0x00000008);
+ nv_wait(dev, pcopy->fuc + 0x008, 0x00000008, 0x00000000);
+
+ nv_wr32(dev, pcopy->fuc + 0x014, 0xffffffff);
+ return 0;
+}
+
+static struct nouveau_enum nvc0_copy_isr_error_name[] = {
+ { 0x0001, "ILLEGAL_MTHD" },
+ { 0x0002, "INVALID_ENUM" },
+ { 0x0003, "INVALID_BITFIELD" },
+ {}
+};
+
+static void
+nvc0_copy_isr(struct drm_device *dev, int engine)
+{
+ struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
+ u32 disp = nv_rd32(dev, pcopy->fuc + 0x01c);
+ u32 stat = nv_rd32(dev, pcopy->fuc + 0x008) & disp & ~(disp >> 16);
+ u64 inst = (u64)(nv_rd32(dev, pcopy->fuc + 0x050) & 0x0fffffff) << 12;
+ u32 chid = nvc0_graph_isr_chid(dev, inst);
+ u32 ssta = nv_rd32(dev, pcopy->fuc + 0x040) & 0x0000ffff;
+ u32 addr = nv_rd32(dev, pcopy->fuc + 0x040) >> 16;
+ u32 mthd = (addr & 0x07ff) << 2;
+ u32 subc = (addr & 0x3800) >> 11;
+ u32 data = nv_rd32(dev, pcopy->fuc + 0x044);
+
+ if (stat & 0x00000040) {
+ NV_INFO(dev, "PCOPY: DISPATCH_ERROR [");
+ nouveau_enum_print(nvc0_copy_isr_error_name, ssta);
+ printk("] ch %d [0x%010llx] subc %d mthd 0x%04x data 0x%08x\n",
+ chid, inst, subc, mthd, data);
+ nv_wr32(dev, pcopy->fuc + 0x004, 0x00000040);
+ stat &= ~0x00000040;
+ }
+
+ if (stat) {
+ NV_INFO(dev, "PCOPY: unhandled intr 0x%08x\n", stat);
+ nv_wr32(dev, pcopy->fuc + 0x004, stat);
+ }
+}
+
+static void
+nvc0_copy_isr_0(struct drm_device *dev)
+{
+ nvc0_copy_isr(dev, NVOBJ_ENGINE_COPY0);
+}
+
+static void
+nvc0_copy_isr_1(struct drm_device *dev)
+{
+ nvc0_copy_isr(dev, NVOBJ_ENGINE_COPY1);
+}
+
+static void
+nvc0_copy_destroy(struct drm_device *dev, int engine)
+{
+ struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
+
+ nouveau_irq_unregister(dev, pcopy->irq);
+
+ if (engine == NVOBJ_ENGINE_COPY0)
+ NVOBJ_ENGINE_DEL(dev, COPY0);
+ else
+ NVOBJ_ENGINE_DEL(dev, COPY1);
+ kfree(pcopy);
+}
+
+int
+nvc0_copy_create(struct drm_device *dev, int engine)
+{
+ struct nvc0_copy_engine *pcopy;
+
+ pcopy = kzalloc(sizeof(*pcopy), GFP_KERNEL);
+ if (!pcopy)
+ return -ENOMEM;
+
+ pcopy->base.destroy = nvc0_copy_destroy;
+ pcopy->base.init = nvc0_copy_init;
+ pcopy->base.fini = nvc0_copy_fini;
+ pcopy->base.context_new = nvc0_copy_context_new;
+ pcopy->base.context_del = nvc0_copy_context_del;
+ pcopy->base.object_new = nvc0_copy_object_new;
+
+ if (engine == 0) {
+ pcopy->irq = 5;
+ pcopy->pmc = 0x00000040;
+ pcopy->fuc = 0x104000;
+ pcopy->ctx = 0x0230;
+ nouveau_irq_register(dev, pcopy->irq, nvc0_copy_isr_0);
+ NVOBJ_ENGINE_ADD(dev, COPY0, &pcopy->base);
+ NVOBJ_CLASS(dev, 0x90b5, COPY0);
+ } else {
+ pcopy->irq = 6;
+ pcopy->pmc = 0x00000080;
+ pcopy->fuc = 0x105000;
+ pcopy->ctx = 0x0240;
+ nouveau_irq_register(dev, pcopy->irq, nvc0_copy_isr_1);
+ NVOBJ_ENGINE_ADD(dev, COPY1, &pcopy->base);
+ NVOBJ_CLASS(dev, 0x90b8, COPY1);
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvc0_copy.fuc.h b/drivers/gpu/drm/nouveau/nvc0_copy.fuc.h
new file mode 100644
index 000000000000..419903880e9d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvc0_copy.fuc.h
@@ -0,0 +1,527 @@
+uint32_t nvc0_pcopy_data[] = {
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00010000,
+ 0x00000000,
+ 0x00000000,
+ 0x00010040,
+ 0x0001019f,
+ 0x00000000,
+ 0x00010050,
+ 0x000101a1,
+ 0x00000000,
+ 0x00070080,
+ 0x0000001c,
+ 0xfffff000,
+ 0x00000020,
+ 0xfff80000,
+ 0x00000024,
+ 0xffffe000,
+ 0x00000028,
+ 0xfffff800,
+ 0x0000002c,
+ 0xfffff000,
+ 0x00000030,
+ 0xfff80000,
+ 0x00000034,
+ 0xffffe000,
+ 0x00070088,
+ 0x00000048,
+ 0xfffff000,
+ 0x0000004c,
+ 0xfff80000,
+ 0x00000050,
+ 0xffffe000,
+ 0x00000054,
+ 0xfffff800,
+ 0x00000058,
+ 0xfffff000,
+ 0x0000005c,
+ 0xfff80000,
+ 0x00000060,
+ 0xffffe000,
+ 0x000200c0,
+ 0x000104b8,
+ 0x00000000,
+ 0x00010541,
+ 0x00000000,
+ 0x000e00c3,
+ 0x00000010,
+ 0xffffff00,
+ 0x00000014,
+ 0x0000000f,
+ 0x0000003c,
+ 0xffffff00,
+ 0x00000040,
+ 0x0000000f,
+ 0x00000018,
+ 0xfff80000,
+ 0x00000044,
+ 0xfff80000,
+ 0x00000074,
+ 0xffff0000,
+ 0x00000078,
+ 0xffffe000,
+ 0x00000068,
+ 0xfccc0000,
+ 0x0000006c,
+ 0x00000000,
+ 0x00000070,
+ 0x00000000,
+ 0x00000004,
+ 0xffffff00,
+ 0x00000008,
+ 0x00000000,
+ 0x0000000c,
+ 0x00000000,
+ 0x00000800,
+};
+
+uint32_t nvc0_pcopy_code[] = {
+ 0x04fe04bd,
+ 0x3517f000,
+ 0xf10010fe,
+ 0xf1040017,
+ 0xf0fff327,
+ 0x22d00023,
+ 0x0c25f0c0,
+ 0xf40012d0,
+ 0x17f11031,
+ 0x27f01200,
+ 0x0012d003,
+ 0xf40031f4,
+ 0x0ef40028,
+ 0x8001cffd,
+ 0xf40812c4,
+ 0x21f4060b,
+ 0x0412c4ca,
+ 0xf5070bf4,
+ 0xc4010221,
+ 0x01d00c11,
+ 0xf101f840,
+ 0xfe770047,
+ 0x47f1004b,
+ 0x44cf2100,
+ 0x0144f000,
+ 0xb60444b6,
+ 0xf7f13040,
+ 0xf4b6061c,
+ 0x1457f106,
+ 0x00f5d101,
+ 0xb6043594,
+ 0x57fe0250,
+ 0x0145fe00,
+ 0x010052b7,
+ 0x00ff67f1,
+ 0x56fd60bd,
+ 0x0253f004,
+ 0xf80545fa,
+ 0x0053f003,
+ 0xd100e7f0,
+ 0x549800fe,
+ 0x0845b600,
+ 0xb6015698,
+ 0x46fd1864,
+ 0x0047fe05,
+ 0xf00204b9,
+ 0x01f40643,
+ 0x0604fa09,
+ 0xfa060ef4,
+ 0x03f80504,
+ 0x27f100f8,
+ 0x23cf1400,
+ 0x1e3fc800,
+ 0xf4170bf4,
+ 0x21f40132,
+ 0x1e3af053,
+ 0xf00023d0,
+ 0x24d00147,
+ 0xcf00f880,
+ 0x3dc84023,
+ 0x090bf41e,
+ 0xf40131f4,
+ 0x37f05321,
+ 0x8023d002,
+ 0x37f100f8,
+ 0x32cf1900,
+ 0x0033cf40,
+ 0x07ff24e4,
+ 0xf11024b6,
+ 0xbd010057,
+ 0x5874bd64,
+ 0x57580056,
+ 0x0450b601,
+ 0xf40446b8,
+ 0x76bb4d08,
+ 0x0447b800,
+ 0xbb0f08f4,
+ 0x74b60276,
+ 0x0057bb03,
+ 0xbbdf0ef4,
+ 0x44b60246,
+ 0x0045bb03,
+ 0xfd014598,
+ 0x54b00453,
+ 0x201bf400,
+ 0x58004558,
+ 0x64b00146,
+ 0x091bf400,
+ 0xf4005380,
+ 0x32f4300e,
+ 0xf455f901,
+ 0x0ef40c01,
+ 0x0225f025,
+ 0xf10125f0,
+ 0xd0100047,
+ 0x43d00042,
+ 0x4027f040,
+ 0xcf0002d0,
+ 0x24f08002,
+ 0x0024b040,
+ 0xf1f71bf4,
+ 0xf01d0027,
+ 0x23d00137,
+ 0xf800f800,
+ 0x0027f100,
+ 0xf034bd22,
+ 0x23d00233,
+ 0xf400f800,
+ 0x01b0f030,
+ 0x0101b000,
+ 0xb00201b0,
+ 0x04980301,
+ 0x3045c71a,
+ 0xc70150b6,
+ 0x60b63446,
+ 0x3847c701,
+ 0xf40170b6,
+ 0x84bd0232,
+ 0x4ac494bd,
+ 0x0445b60f,
+ 0xa430b4bd,
+ 0x0f18f404,
+ 0xbbc0a5ff,
+ 0x31f400cb,
+ 0x220ef402,
+ 0xf00c1bf4,
+ 0xcbbb10c7,
+ 0x160ef400,
+ 0xf406a430,
+ 0xc7f00c18,
+ 0x00cbbb14,
+ 0xf1070ef4,
+ 0x380080c7,
+ 0x80b601c8,
+ 0x01b0b601,
+ 0xf404b5b8,
+ 0x90b6c308,
+ 0x0497b801,
+ 0xfdb208f4,
+ 0x06800065,
+ 0x1d08980e,
+ 0xf40068fd,
+ 0x64bd0502,
+ 0x800075fd,
+ 0x78fd1907,
+ 0x1057f100,
+ 0x0654b608,
+ 0xd00056d0,
+ 0x50b74057,
+ 0x06980800,
+ 0x0162b619,
+ 0x980864b6,
+ 0x72b60e07,
+ 0x0567fd01,
+ 0xb70056d0,
+ 0xb4010050,
+ 0x56d00060,
+ 0x0160b400,
+ 0xb44056d0,
+ 0x56d00260,
+ 0x0360b480,
+ 0xb7c056d0,
+ 0x98040050,
+ 0x56d01b06,
+ 0x1c069800,
+ 0xf44056d0,
+ 0x00f81030,
+ 0xc7075798,
+ 0x78c76879,
+ 0x0380b664,
+ 0xb06077c7,
+ 0x1bf40e76,
+ 0x0477f009,
+ 0xf00f0ef4,
+ 0x70b6027c,
+ 0x0947fd11,
+ 0x980677f0,
+ 0x5b980c5a,
+ 0x00abfd0e,
+ 0xbb01b7f0,
+ 0xb2b604b7,
+ 0xc4abff01,
+ 0x9805a7bb,
+ 0xe7f00d5d,
+ 0x04e8bb01,
+ 0xff01e2b6,
+ 0xd8bbb4de,
+ 0x01e0b605,
+ 0xbb0cef94,
+ 0xfefd02eb,
+ 0x026cf005,
+ 0x020860b7,
+ 0xd00864b6,
+ 0xb7bb006f,
+ 0x00cbbb04,
+ 0x98085f98,
+ 0xfbfd0e5b,
+ 0x01b7f000,
+ 0xb604b7bb,
+ 0xfbbb01b2,
+ 0x05f7bb00,
+ 0x5f98f0f9,
+ 0x01b7f009,
+ 0xb604b8bb,
+ 0xfbbb01b2,
+ 0x05f8bb00,
+ 0x78bbf0f9,
+ 0x0282b600,
+ 0xbb01b7f0,
+ 0xb9bb04b8,
+ 0x0b589804,
+ 0xbb01e7f0,
+ 0xe2b604e9,
+ 0xf48eff01,
+ 0xbb04f7bb,
+ 0x79bb00cf,
+ 0x0589bb00,
+ 0x90fcf0fc,
+ 0xbb00d9fd,
+ 0x89fd00ad,
+ 0x008ffd00,
+ 0xbb00a8bb,
+ 0x92b604a7,
+ 0x0497bb01,
+ 0x988069d0,
+ 0x58980557,
+ 0x00acbb04,
+ 0xb6007abb,
+ 0x84b60081,
+ 0x058bfd10,
+ 0x060062b7,
+ 0xb70067d0,
+ 0xd0040060,
+ 0x00f80068,
+ 0xb7026cf0,
+ 0xb6020260,
+ 0x57980864,
+ 0x0067d005,
+ 0x040060b7,
+ 0xb6045798,
+ 0x67d01074,
+ 0x0060b700,
+ 0x06579804,
+ 0xf80067d0,
+ 0xf900f900,
+ 0x0007f110,
+ 0x0604b608,
+ 0xf00001cf,
+ 0x1bf40114,
+ 0xfc10fcfa,
+ 0xc800f800,
+ 0x1bf40d34,
+ 0xd121f570,
+ 0x0c47f103,
+ 0x0644b608,
+ 0xb6020598,
+ 0x45d00450,
+ 0x4040d000,
+ 0xd00c57f0,
+ 0x40b78045,
+ 0x05980400,
+ 0x1054b601,
+ 0xb70045d0,
+ 0xf1050040,
+ 0xf00b0057,
+ 0x45d00153,
+ 0x4057f100,
+ 0x0154b640,
+ 0x808053f1,
+ 0xf14045d0,
+ 0xf1111057,
+ 0xd0131253,
+ 0x57f18045,
+ 0x53f11514,
+ 0x45d01716,
+ 0x0157f1c0,
+ 0x0153f026,
+ 0x080047f1,
+ 0xd00644b6,
+ 0x21f50045,
+ 0x47f103d1,
+ 0x44b6080c,
+ 0x02059806,
+ 0xd00045d0,
+ 0x57f04040,
+ 0x8045d004,
+ 0x040040b7,
+ 0xb6010598,
+ 0x45d01054,
+ 0x0040b700,
+ 0x0057f105,
+ 0x0045d003,
+ 0x111057f1,
+ 0x131253f1,
+ 0x984045d0,
+ 0x40b70305,
+ 0x45d00500,
+ 0x0157f100,
+ 0x0153f026,
+ 0x080047f1,
+ 0xd00644b6,
+ 0x00f80045,
+ 0x03d121f5,
+ 0xf4003fc8,
+ 0x21f50e0b,
+ 0x47f101af,
+ 0x0ef40200,
+ 0x1067f11e,
+ 0x0664b608,
+ 0x800177f0,
+ 0x07800e07,
+ 0x1d079819,
+ 0xd00067d0,
+ 0x44bd4067,
+ 0xbd0232f4,
+ 0x043fc854,
+ 0xf50a0bf4,
+ 0xf403a821,
+ 0x21f50a0e,
+ 0x49f0029c,
+ 0x0231f407,
+ 0xc82c57f0,
+ 0x0bf4083f,
+ 0xa821f50a,
+ 0x0a0ef403,
+ 0x029c21f5,
+ 0xf10849f0,
+ 0xb6080057,
+ 0x06980654,
+ 0x4056d01e,
+ 0xf14167f0,
+ 0xfd440063,
+ 0x54d00546,
+ 0x0c3fc800,
+ 0xf5070bf4,
+ 0xf803eb21,
+ 0x0027f100,
+ 0xf034bd22,
+ 0x23d00133,
+ 0x0000f800,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvc0_fifo.c b/drivers/gpu/drm/nouveau/nvc0_fifo.c
index 2886f2726a9e..fb4f5943e01b 100644
--- a/drivers/gpu/drm/nouveau/nvc0_fifo.c
+++ b/drivers/gpu/drm/nouveau/nvc0_fifo.c
@@ -37,7 +37,7 @@ struct nvc0_fifo_priv {
};
struct nvc0_fifo_chan {
- struct nouveau_bo *user;
+ struct nouveau_gpuobj *user;
struct nouveau_gpuobj *ramfc;
};
@@ -106,7 +106,7 @@ nvc0_fifo_create_context(struct nouveau_channel *chan)
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
struct nvc0_fifo_priv *priv = pfifo->priv;
struct nvc0_fifo_chan *fifoch;
- u64 ib_virt, user_vinst;
+ u64 ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4;
int ret;
chan->fifo_priv = kzalloc(sizeof(*fifoch), GFP_KERNEL);
@@ -115,28 +115,13 @@ nvc0_fifo_create_context(struct nouveau_channel *chan)
fifoch = chan->fifo_priv;
/* allocate vram for control regs, map into polling area */
- ret = nouveau_bo_new(dev, NULL, 0x1000, 0, TTM_PL_FLAG_VRAM,
- 0, 0, &fifoch->user);
+ ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0x1000,
+ NVOBJ_FLAG_ZERO_ALLOC, &fifoch->user);
if (ret)
goto error;
- ret = nouveau_bo_pin(fifoch->user, TTM_PL_FLAG_VRAM);
- if (ret) {
- nouveau_bo_ref(NULL, &fifoch->user);
- goto error;
- }
-
- user_vinst = fifoch->user->bo.mem.start << PAGE_SHIFT;
-
- ret = nouveau_bo_map(fifoch->user);
- if (ret) {
- nouveau_bo_unpin(fifoch->user);
- nouveau_bo_ref(NULL, &fifoch->user);
- goto error;
- }
-
nouveau_vm_map_at(&priv->user_vma, chan->id * 0x1000,
- fifoch->user->bo.mem.mm_node);
+ *(struct nouveau_mem **)fifoch->user->node);
chan->user = ioremap_wc(pci_resource_start(dev->pdev, 1) +
priv->user_vma.offset + (chan->id * 0x1000),
@@ -146,20 +131,6 @@ nvc0_fifo_create_context(struct nouveau_channel *chan)
goto error;
}
- ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4;
-
- /* zero channel regs */
- nouveau_bo_wr32(fifoch->user, 0x0040/4, 0);
- nouveau_bo_wr32(fifoch->user, 0x0044/4, 0);
- nouveau_bo_wr32(fifoch->user, 0x0048/4, 0);
- nouveau_bo_wr32(fifoch->user, 0x004c/4, 0);
- nouveau_bo_wr32(fifoch->user, 0x0050/4, 0);
- nouveau_bo_wr32(fifoch->user, 0x0058/4, 0);
- nouveau_bo_wr32(fifoch->user, 0x005c/4, 0);
- nouveau_bo_wr32(fifoch->user, 0x0060/4, 0);
- nouveau_bo_wr32(fifoch->user, 0x0088/4, 0);
- nouveau_bo_wr32(fifoch->user, 0x008c/4, 0);
-
/* ramfc */
ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst,
chan->ramin->vinst, 0x100,
@@ -167,8 +138,8 @@ nvc0_fifo_create_context(struct nouveau_channel *chan)
if (ret)
goto error;
- nv_wo32(fifoch->ramfc, 0x08, lower_32_bits(user_vinst));
- nv_wo32(fifoch->ramfc, 0x0c, upper_32_bits(user_vinst));
+ nv_wo32(fifoch->ramfc, 0x08, lower_32_bits(fifoch->user->vinst));
+ nv_wo32(fifoch->ramfc, 0x0c, upper_32_bits(fifoch->user->vinst));
nv_wo32(fifoch->ramfc, 0x10, 0x0000face);
nv_wo32(fifoch->ramfc, 0x30, 0xfffff902);
nv_wo32(fifoch->ramfc, 0x48, lower_32_bits(ib_virt));
@@ -223,11 +194,7 @@ nvc0_fifo_destroy_context(struct nouveau_channel *chan)
return;
nouveau_gpuobj_ref(NULL, &fifoch->ramfc);
- if (fifoch->user) {
- nouveau_bo_unmap(fifoch->user);
- nouveau_bo_unpin(fifoch->user);
- nouveau_bo_ref(NULL, &fifoch->user);
- }
+ nouveau_gpuobj_ref(NULL, &fifoch->user);
kfree(fifoch);
}
@@ -240,6 +207,21 @@ nvc0_fifo_load_context(struct nouveau_channel *chan)
int
nvc0_fifo_unload_context(struct drm_device *dev)
{
+ int i;
+
+ for (i = 0; i < 128; i++) {
+ if (!(nv_rd32(dev, 0x003004 + (i * 4)) & 1))
+ continue;
+
+ nv_mask(dev, 0x003004 + (i * 4), 0x00000001, 0x00000000);
+ nv_wr32(dev, 0x002634, i);
+ if (!nv_wait(dev, 0x002634, 0xffffffff, i)) {
+ NV_INFO(dev, "PFIFO: kick ch %d failed: 0x%08x\n",
+ i, nv_rd32(dev, 0x002634));
+ return -EBUSY;
+ }
+ }
+
return 0;
}
@@ -309,6 +291,7 @@ nvc0_fifo_init(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
+ struct nouveau_channel *chan;
struct nvc0_fifo_priv *priv;
int ret, i;
@@ -351,23 +334,74 @@ nvc0_fifo_init(struct drm_device *dev)
nv_wr32(dev, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */
nv_wr32(dev, 0x002100, 0xffffffff);
nv_wr32(dev, 0x002140, 0xbfffffff);
+
+ /* restore PFIFO context table */
+ for (i = 0; i < 128; i++) {
+ chan = dev_priv->channels.ptr[i];
+ if (!chan || !chan->fifo_priv)
+ continue;
+
+ nv_wr32(dev, 0x003000 + (i * 8), 0xc0000000 |
+ (chan->ramin->vinst >> 12));
+ nv_wr32(dev, 0x003004 + (i * 8), 0x001f0001);
+ }
+ nvc0_fifo_playlist_update(dev);
+
return 0;
}
struct nouveau_enum nvc0_fifo_fault_unit[] = {
- { 0, "PGRAPH" },
- { 3, "PEEPHOLE" },
- { 4, "BAR1" },
- { 5, "BAR3" },
- { 7, "PFIFO" },
+ { 0x00, "PGRAPH" },
+ { 0x03, "PEEPHOLE" },
+ { 0x04, "BAR1" },
+ { 0x05, "BAR3" },
+ { 0x07, "PFIFO" },
+ { 0x10, "PBSP" },
+ { 0x11, "PPPP" },
+ { 0x13, "PCOUNTER" },
+ { 0x14, "PVP" },
+ { 0x15, "PCOPY0" },
+ { 0x16, "PCOPY1" },
+ { 0x17, "PDAEMON" },
{}
};
struct nouveau_enum nvc0_fifo_fault_reason[] = {
- { 0, "PT_NOT_PRESENT" },
- { 1, "PT_TOO_SHORT" },
- { 2, "PAGE_NOT_PRESENT" },
- { 3, "VM_LIMIT_EXCEEDED" },
+ { 0x00, "PT_NOT_PRESENT" },
+ { 0x01, "PT_TOO_SHORT" },
+ { 0x02, "PAGE_NOT_PRESENT" },
+ { 0x03, "VM_LIMIT_EXCEEDED" },
+ { 0x04, "NO_CHANNEL" },
+ { 0x05, "PAGE_SYSTEM_ONLY" },
+ { 0x06, "PAGE_READ_ONLY" },
+ { 0x0a, "COMPRESSED_SYSRAM" },
+ { 0x0c, "INVALID_STORAGE_TYPE" },
+ {}
+};
+
+struct nouveau_enum nvc0_fifo_fault_hubclient[] = {
+ { 0x01, "PCOPY0" },
+ { 0x02, "PCOPY1" },
+ { 0x04, "DISPATCH" },
+ { 0x05, "CTXCTL" },
+ { 0x06, "PFIFO" },
+ { 0x07, "BAR_READ" },
+ { 0x08, "BAR_WRITE" },
+ { 0x0b, "PVP" },
+ { 0x0c, "PPPP" },
+ { 0x0d, "PBSP" },
+ { 0x11, "PCOUNTER" },
+ { 0x12, "PDAEMON" },
+ { 0x14, "CCACHE" },
+ { 0x15, "CCACHE_POST" },
+ {}
+};
+
+struct nouveau_enum nvc0_fifo_fault_gpcclient[] = {
+ { 0x01, "TEX" },
+ { 0x0c, "ESETUP" },
+ { 0x0e, "CTXCTL" },
+ { 0x0f, "PROP" },
{}
};
@@ -385,12 +419,20 @@ nvc0_fifo_isr_vm_fault(struct drm_device *dev, int unit)
u32 valo = nv_rd32(dev, 0x2804 + (unit * 0x10));
u32 vahi = nv_rd32(dev, 0x2808 + (unit * 0x10));
u32 stat = nv_rd32(dev, 0x280c + (unit * 0x10));
+ u32 client = (stat & 0x00001f00) >> 8;
NV_INFO(dev, "PFIFO: %s fault at 0x%010llx [",
(stat & 0x00000080) ? "write" : "read", (u64)vahi << 32 | valo);
nouveau_enum_print(nvc0_fifo_fault_reason, stat & 0x0000000f);
printk("] from ");
nouveau_enum_print(nvc0_fifo_fault_unit, unit);
+ if (stat & 0x00000040) {
+ printk("/");
+ nouveau_enum_print(nvc0_fifo_fault_hubclient, client);
+ } else {
+ printk("/GPC%d/", (stat & 0x1f000000) >> 24);
+ nouveau_enum_print(nvc0_fifo_fault_gpcclient, client);
+ }
printk(" on channel 0x%010llx\n", (u64)inst << 12);
}
diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c
index 3de9b721d8db..ca6db204d644 100644
--- a/drivers/gpu/drm/nouveau/nvc0_graph.c
+++ b/drivers/gpu/drm/nouveau/nvc0_graph.c
@@ -30,27 +30,40 @@
#include "nouveau_mm.h"
#include "nvc0_graph.h"
-static void nvc0_graph_isr(struct drm_device *);
-static void nvc0_runk140_isr(struct drm_device *);
-static int nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan);
-
-void
-nvc0_graph_fifo_access(struct drm_device *dev, bool enabled)
+static int
+nvc0_graph_load_context(struct nouveau_channel *chan)
{
+ struct drm_device *dev = chan->dev;
+
+ nv_wr32(dev, 0x409840, 0x00000030);
+ nv_wr32(dev, 0x409500, 0x80000000 | chan->ramin->vinst >> 12);
+ nv_wr32(dev, 0x409504, 0x00000003);
+ if (!nv_wait(dev, 0x409800, 0x00000010, 0x00000010))
+ NV_ERROR(dev, "PGRAPH: load_ctx timeout\n");
+
+ return 0;
}
-struct nouveau_channel *
-nvc0_graph_channel(struct drm_device *dev)
+static int
+nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan)
{
- return NULL;
+ nv_wr32(dev, 0x409840, 0x00000003);
+ nv_wr32(dev, 0x409500, 0x80000000 | chan >> 12);
+ nv_wr32(dev, 0x409504, 0x00000009);
+ if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000000)) {
+ NV_ERROR(dev, "PGRAPH: unload_ctx timeout\n");
+ return -EBUSY;
+ }
+
+ return 0;
}
static int
nvc0_graph_construct_context(struct nouveau_channel *chan)
{
struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
- struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
- struct nvc0_graph_chan *grch = chan->pgraph_ctx;
+ struct nvc0_graph_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_GR);
+ struct nvc0_graph_chan *grch = chan->engctx[NVOBJ_ENGINE_GR];
struct drm_device *dev = chan->dev;
int ret, i;
u32 *ctx;
@@ -89,9 +102,8 @@ nvc0_graph_construct_context(struct nouveau_channel *chan)
static int
nvc0_graph_create_context_mmio_list(struct nouveau_channel *chan)
{
- struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
- struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
- struct nvc0_graph_chan *grch = chan->pgraph_ctx;
+ struct nvc0_graph_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_GR);
+ struct nvc0_graph_chan *grch = chan->engctx[NVOBJ_ENGINE_GR];
struct drm_device *dev = chan->dev;
int i = 0, gpc, tp, ret;
u32 magic;
@@ -158,29 +170,27 @@ nvc0_graph_create_context_mmio_list(struct nouveau_channel *chan)
return 0;
}
-int
-nvc0_graph_create_context(struct nouveau_channel *chan)
+static int
+nvc0_graph_context_new(struct nouveau_channel *chan, int engine)
{
- struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+ struct drm_device *dev = chan->dev;
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct nvc0_graph_priv *priv = pgraph->priv;
+ struct nvc0_graph_priv *priv = nv_engine(dev, engine);
struct nvc0_graph_chan *grch;
- struct drm_device *dev = chan->dev;
struct nouveau_gpuobj *grctx;
int ret, i;
- chan->pgraph_ctx = kzalloc(sizeof(*grch), GFP_KERNEL);
- if (!chan->pgraph_ctx)
+ grch = kzalloc(sizeof(*grch), GFP_KERNEL);
+ if (!grch)
return -ENOMEM;
- grch = chan->pgraph_ctx;
+ chan->engctx[NVOBJ_ENGINE_GR] = grch;
ret = nouveau_gpuobj_new(dev, NULL, priv->grctx_size, 256,
NVOBJ_FLAG_VM | NVOBJ_FLAG_ZERO_ALLOC,
&grch->grctx);
if (ret)
goto error;
- chan->ramin_grctx = grch->grctx;
grctx = grch->grctx;
ret = nvc0_graph_create_context_mmio_list(chan);
@@ -200,104 +210,49 @@ nvc0_graph_create_context(struct nouveau_channel *chan)
for (i = 0; i < priv->grctx_size; i += 4)
nv_wo32(grctx, i, priv->grctx_vals[i / 4]);
- nv_wo32(grctx, 0xf4, 0);
- nv_wo32(grctx, 0xf8, 0);
- nv_wo32(grctx, 0x10, grch->mmio_nr);
- nv_wo32(grctx, 0x14, lower_32_bits(grch->mmio->vinst));
- nv_wo32(grctx, 0x18, upper_32_bits(grch->mmio->vinst));
- nv_wo32(grctx, 0x1c, 1);
- nv_wo32(grctx, 0x20, 0);
- nv_wo32(grctx, 0x28, 0);
- nv_wo32(grctx, 0x2c, 0);
+ nv_wo32(grctx, 0xf4, 0);
+ nv_wo32(grctx, 0xf8, 0);
+ nv_wo32(grctx, 0x10, grch->mmio_nr);
+ nv_wo32(grctx, 0x14, lower_32_bits(grch->mmio->vinst));
+ nv_wo32(grctx, 0x18, upper_32_bits(grch->mmio->vinst));
+ nv_wo32(grctx, 0x1c, 1);
+ nv_wo32(grctx, 0x20, 0);
+ nv_wo32(grctx, 0x28, 0);
+ nv_wo32(grctx, 0x2c, 0);
pinstmem->flush(dev);
return 0;
error:
- pgraph->destroy_context(chan);
+ priv->base.context_del(chan, engine);
return ret;
}
-void
-nvc0_graph_destroy_context(struct nouveau_channel *chan)
+static void
+nvc0_graph_context_del(struct nouveau_channel *chan, int engine)
{
- struct nvc0_graph_chan *grch;
-
- grch = chan->pgraph_ctx;
- chan->pgraph_ctx = NULL;
- if (!grch)
- return;
+ struct nvc0_graph_chan *grch = chan->engctx[engine];
nouveau_gpuobj_ref(NULL, &grch->mmio);
nouveau_gpuobj_ref(NULL, &grch->unk418810);
nouveau_gpuobj_ref(NULL, &grch->unk40800c);
nouveau_gpuobj_ref(NULL, &grch->unk408004);
nouveau_gpuobj_ref(NULL, &grch->grctx);
- chan->ramin_grctx = NULL;
+ chan->engctx[engine] = NULL;
}
-int
-nvc0_graph_load_context(struct nouveau_channel *chan)
+static int
+nvc0_graph_object_new(struct nouveau_channel *chan, int engine,
+ u32 handle, u16 class)
{
- struct drm_device *dev = chan->dev;
-
- nv_wr32(dev, 0x409840, 0x00000030);
- nv_wr32(dev, 0x409500, 0x80000000 | chan->ramin->vinst >> 12);
- nv_wr32(dev, 0x409504, 0x00000003);
- if (!nv_wait(dev, 0x409800, 0x00000010, 0x00000010))
- NV_ERROR(dev, "PGRAPH: load_ctx timeout\n");
-
return 0;
}
static int
-nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan)
+nvc0_graph_fini(struct drm_device *dev, int engine)
{
- nv_wr32(dev, 0x409840, 0x00000003);
- nv_wr32(dev, 0x409500, 0x80000000 | chan >> 12);
- nv_wr32(dev, 0x409504, 0x00000009);
- if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000000)) {
- NV_ERROR(dev, "PGRAPH: unload_ctx timeout\n");
- return -EBUSY;
- }
-
return 0;
}
-int
-nvc0_graph_unload_context(struct drm_device *dev)
-{
- u64 inst = (u64)(nv_rd32(dev, 0x409b00) & 0x0fffffff) << 12;
- return nvc0_graph_unload_context_to(dev, inst);
-}
-
-static void
-nvc0_graph_destroy(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct nvc0_graph_priv *priv;
-
- priv = pgraph->priv;
- if (!priv)
- return;
-
- nouveau_irq_unregister(dev, 12);
- nouveau_irq_unregister(dev, 25);
-
- nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
- nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
-
- if (priv->grctx_vals)
- kfree(priv->grctx_vals);
- kfree(priv);
-}
-
-void
-nvc0_graph_takedown(struct drm_device *dev)
-{
- nvc0_graph_destroy(dev);
-}
-
static int
nvc0_graph_mthd_page_flip(struct nouveau_channel *chan,
u32 class, u32 mthd, u32 data)
@@ -306,119 +261,10 @@ nvc0_graph_mthd_page_flip(struct nouveau_channel *chan,
return 0;
}
-static int
-nvc0_graph_create(struct drm_device *dev)
-{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct nvc0_graph_priv *priv;
- int ret, gpc, i;
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
- pgraph->priv = priv;
-
- ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4);
- if (ret)
- goto error;
-
- ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b8);
- if (ret)
- goto error;
-
- for (i = 0; i < 0x1000; i += 4) {
- nv_wo32(priv->unk4188b4, i, 0x00000010);
- nv_wo32(priv->unk4188b8, i, 0x00000010);
- }
-
- priv->gpc_nr = nv_rd32(dev, 0x409604) & 0x0000001f;
- priv->rop_nr = (nv_rd32(dev, 0x409604) & 0x001f0000) >> 16;
- for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
- priv->tp_nr[gpc] = nv_rd32(dev, GPC_UNIT(gpc, 0x2608));
- priv->tp_total += priv->tp_nr[gpc];
- }
-
- /*XXX: these need figuring out... */
- switch (dev_priv->chipset) {
- case 0xc0:
- if (priv->tp_total == 11) { /* 465, 3/4/4/0, 4 */
- priv->magic_not_rop_nr = 0x07;
- /* filled values up to tp_total, the rest 0 */
- priv->magicgpc980[0] = 0x22111000;
- priv->magicgpc980[1] = 0x00000233;
- priv->magicgpc980[2] = 0x00000000;
- priv->magicgpc980[3] = 0x00000000;
- priv->magicgpc918 = 0x000ba2e9;
- } else
- if (priv->tp_total == 14) { /* 470, 3/3/4/4, 5 */
- priv->magic_not_rop_nr = 0x05;
- priv->magicgpc980[0] = 0x11110000;
- priv->magicgpc980[1] = 0x00233222;
- priv->magicgpc980[2] = 0x00000000;
- priv->magicgpc980[3] = 0x00000000;
- priv->magicgpc918 = 0x00092493;
- } else
- if (priv->tp_total == 15) { /* 480, 3/4/4/4, 6 */
- priv->magic_not_rop_nr = 0x06;
- priv->magicgpc980[0] = 0x11110000;
- priv->magicgpc980[1] = 0x03332222;
- priv->magicgpc980[2] = 0x00000000;
- priv->magicgpc980[3] = 0x00000000;
- priv->magicgpc918 = 0x00088889;
- }
- break;
- case 0xc3: /* 450, 4/0/0/0, 2 */
- priv->magic_not_rop_nr = 0x03;
- priv->magicgpc980[0] = 0x00003210;
- priv->magicgpc980[1] = 0x00000000;
- priv->magicgpc980[2] = 0x00000000;
- priv->magicgpc980[3] = 0x00000000;
- priv->magicgpc918 = 0x00200000;
- break;
- case 0xc4: /* 460, 3/4/0/0, 4 */
- priv->magic_not_rop_nr = 0x01;
- priv->magicgpc980[0] = 0x02321100;
- priv->magicgpc980[1] = 0x00000000;
- priv->magicgpc980[2] = 0x00000000;
- priv->magicgpc980[3] = 0x00000000;
- priv->magicgpc918 = 0x00124925;
- break;
- }
-
- if (!priv->magic_not_rop_nr) {
- NV_ERROR(dev, "PGRAPH: unknown config: %d/%d/%d/%d, %d\n",
- priv->tp_nr[0], priv->tp_nr[1], priv->tp_nr[2],
- priv->tp_nr[3], priv->rop_nr);
- /* use 0xc3's values... */
- priv->magic_not_rop_nr = 0x03;
- priv->magicgpc980[0] = 0x00003210;
- priv->magicgpc980[1] = 0x00000000;
- priv->magicgpc980[2] = 0x00000000;
- priv->magicgpc980[3] = 0x00000000;
- priv->magicgpc918 = 0x00200000;
- }
-
- nouveau_irq_register(dev, 12, nvc0_graph_isr);
- nouveau_irq_register(dev, 25, nvc0_runk140_isr);
- NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */
- NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */
- NVOBJ_MTHD (dev, 0x9039, 0x0500, nvc0_graph_mthd_page_flip);
- NVOBJ_CLASS(dev, 0x9097, GR); /* 3D */
- NVOBJ_CLASS(dev, 0x90c0, GR); /* COMPUTE */
- return 0;
-
-error:
- nvc0_graph_destroy(dev);
- return ret;
-}
-
static void
nvc0_graph_init_obj418880(struct drm_device *dev)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
- struct nvc0_graph_priv *priv = pgraph->priv;
+ struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
int i;
nv_wr32(dev, GPC_BCAST(0x0880), 0x00000000);
@@ -449,35 +295,42 @@ nvc0_graph_init_regs(struct drm_device *dev)
static void
nvc0_graph_init_gpc_0(struct drm_device *dev)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
- int gpc;
-
- // TP ROP UNKVAL(magic_not_rop_nr)
- // 450: 4/0/0/0 2 3
- // 460: 3/4/0/0 4 1
- // 465: 3/4/4/0 4 7
- // 470: 3/3/4/4 5 5
- // 480: 3/4/4/4 6 6
-
- // magicgpc918
- // 450: 00200000 00000000001000000000000000000000
- // 460: 00124925 00000000000100100100100100100101
- // 465: 000ba2e9 00000000000010111010001011101001
- // 470: 00092493 00000000000010010010010010010011
- // 480: 00088889 00000000000010001000100010001001
-
- /* filled values up to tp_total, remainder 0 */
- // 450: 00003210 00000000 00000000 00000000
- // 460: 02321100 00000000 00000000 00000000
- // 465: 22111000 00000233 00000000 00000000
- // 470: 11110000 00233222 00000000 00000000
- // 480: 11110000 03332222 00000000 00000000
-
- nv_wr32(dev, GPC_BCAST(0x0980), priv->magicgpc980[0]);
- nv_wr32(dev, GPC_BCAST(0x0984), priv->magicgpc980[1]);
- nv_wr32(dev, GPC_BCAST(0x0988), priv->magicgpc980[2]);
- nv_wr32(dev, GPC_BCAST(0x098c), priv->magicgpc980[3]);
+ struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
+ u32 data[TP_MAX / 8];
+ u8 tpnr[GPC_MAX];
+ int i, gpc, tpc;
+
+ /*
+ * TP ROP UNKVAL(magic_not_rop_nr)
+ * 450: 4/0/0/0 2 3
+ * 460: 3/4/0/0 4 1
+ * 465: 3/4/4/0 4 7
+ * 470: 3/3/4/4 5 5
+ * 480: 3/4/4/4 6 6
+ *
+ * magicgpc918
+ * 450: 00200000 00000000001000000000000000000000
+ * 460: 00124925 00000000000100100100100100100101
+ * 465: 000ba2e9 00000000000010111010001011101001
+ * 470: 00092493 00000000000010010010010010010011
+ * 480: 00088889 00000000000010001000100010001001
+ */
+
+ memset(data, 0x00, sizeof(data));
+ memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr));
+ for (i = 0, gpc = -1; i < priv->tp_total; i++) {
+ do {
+ gpc = (gpc + 1) % priv->gpc_nr;
+ } while (!tpnr[gpc]);
+ tpc = priv->tp_nr[gpc] - tpnr[gpc]--;
+
+ data[i / 8] |= tpc << ((i % 8) * 4);
+ }
+
+ nv_wr32(dev, GPC_BCAST(0x0980), data[0]);
+ nv_wr32(dev, GPC_BCAST(0x0984), data[1]);
+ nv_wr32(dev, GPC_BCAST(0x0988), data[2]);
+ nv_wr32(dev, GPC_BCAST(0x098c), data[3]);
for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
nv_wr32(dev, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 |
@@ -509,8 +362,7 @@ nvc0_graph_init_units(struct drm_device *dev)
static void
nvc0_graph_init_gpc_1(struct drm_device *dev)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
+ struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
int gpc, tp;
for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
@@ -535,8 +387,7 @@ nvc0_graph_init_gpc_1(struct drm_device *dev)
static void
nvc0_graph_init_rop(struct drm_device *dev)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
+ struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
int rop;
for (rop = 0; rop < priv->rop_nr; rop++) {
@@ -547,62 +398,36 @@ nvc0_graph_init_rop(struct drm_device *dev)
}
}
-static int
-nvc0_fuc_load_fw(struct drm_device *dev, u32 fuc_base,
- const char *code_fw, const char *data_fw)
+static void
+nvc0_graph_init_fuc(struct drm_device *dev, u32 fuc_base,
+ struct nvc0_graph_fuc *code, struct nvc0_graph_fuc *data)
{
- const struct firmware *fw;
- char name[32];
- int ret, i;
-
- snprintf(name, sizeof(name), "nouveau/%s", data_fw);
- ret = request_firmware(&fw, name, &dev->pdev->dev);
- if (ret) {
- NV_ERROR(dev, "failed to load %s\n", data_fw);
- return ret;
- }
+ int i;
nv_wr32(dev, fuc_base + 0x01c0, 0x01000000);
- for (i = 0; i < fw->size / 4; i++)
- nv_wr32(dev, fuc_base + 0x01c4, ((u32 *)fw->data)[i]);
- release_firmware(fw);
-
- snprintf(name, sizeof(name), "nouveau/%s", code_fw);
- ret = request_firmware(&fw, name, &dev->pdev->dev);
- if (ret) {
- NV_ERROR(dev, "failed to load %s\n", code_fw);
- return ret;
- }
+ for (i = 0; i < data->size / 4; i++)
+ nv_wr32(dev, fuc_base + 0x01c4, data->data[i]);
nv_wr32(dev, fuc_base + 0x0180, 0x01000000);
- for (i = 0; i < fw->size / 4; i++) {
+ for (i = 0; i < code->size / 4; i++) {
if ((i & 0x3f) == 0)
nv_wr32(dev, fuc_base + 0x0188, i >> 6);
- nv_wr32(dev, fuc_base + 0x0184, ((u32 *)fw->data)[i]);
+ nv_wr32(dev, fuc_base + 0x0184, code->data[i]);
}
- release_firmware(fw);
-
- return 0;
}
static int
nvc0_graph_init_ctxctl(struct drm_device *dev)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
+ struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
u32 r000260;
- int ret;
/* load fuc microcode */
r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000);
- ret = nvc0_fuc_load_fw(dev, 0x409000, "fuc409c", "fuc409d");
- if (ret == 0)
- ret = nvc0_fuc_load_fw(dev, 0x41a000, "fuc41ac", "fuc41ad");
+ nvc0_graph_init_fuc(dev, 0x409000, &priv->fuc409c, &priv->fuc409d);
+ nvc0_graph_init_fuc(dev, 0x41a000, &priv->fuc41ac, &priv->fuc41ad);
nv_wr32(dev, 0x000260, r000260);
- if (ret)
- return ret;
-
/* start both of them running */
nv_wr32(dev, 0x409840, 0xffffffff);
nv_wr32(dev, 0x41a10c, 0x00000000);
@@ -644,41 +469,19 @@ nvc0_graph_init_ctxctl(struct drm_device *dev)
return 0;
}
-int
-nvc0_graph_init(struct drm_device *dev)
+static int
+nvc0_graph_init(struct drm_device *dev, int engine)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
int ret;
- dev_priv->engine.graph.accel_blocked = true;
-
- switch (dev_priv->chipset) {
- case 0xc0:
- case 0xc3:
- case 0xc4:
- break;
- default:
- NV_ERROR(dev, "PGRAPH: unsupported chipset, please report!\n");
- if (nouveau_noaccel != 0)
- return 0;
- break;
- }
-
nv_mask(dev, 0x000200, 0x18001000, 0x00000000);
nv_mask(dev, 0x000200, 0x18001000, 0x18001000);
- if (!pgraph->priv) {
- ret = nvc0_graph_create(dev);
- if (ret)
- return ret;
- }
-
nvc0_graph_init_obj418880(dev);
nvc0_graph_init_regs(dev);
- //nvc0_graph_init_unitplemented_magics(dev);
+ /*nvc0_graph_init_unitplemented_magics(dev);*/
nvc0_graph_init_gpc_0(dev);
- //nvc0_graph_init_unitplemented_c242(dev);
+ /*nvc0_graph_init_unitplemented_c242(dev);*/
nv_wr32(dev, 0x400500, 0x00010001);
nv_wr32(dev, 0x400100, 0xffffffff);
@@ -697,12 +500,13 @@ nvc0_graph_init(struct drm_device *dev)
nv_wr32(dev, 0x400054, 0x34ce3464);
ret = nvc0_graph_init_ctxctl(dev);
- if (ret == 0)
- dev_priv->engine.graph.accel_blocked = false;
+ if (ret)
+ return ret;
+
return 0;
}
-static int
+int
nvc0_graph_isr_chid(struct drm_device *dev, u64 inst)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -806,3 +610,187 @@ nvc0_runk140_isr(struct drm_device *dev)
units &= ~(1 << unit);
}
}
+
+static int
+nvc0_graph_create_fw(struct drm_device *dev, const char *fwname,
+ struct nvc0_graph_fuc *fuc)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ const struct firmware *fw;
+ char f[32];
+ int ret;
+
+ snprintf(f, sizeof(f), "nouveau/nv%02x_%s", dev_priv->chipset, fwname);
+ ret = request_firmware(&fw, f, &dev->pdev->dev);
+ if (ret) {
+ snprintf(f, sizeof(f), "nouveau/%s", fwname);
+ ret = request_firmware(&fw, f, &dev->pdev->dev);
+ if (ret) {
+ NV_ERROR(dev, "failed to load %s\n", fwname);
+ return ret;
+ }
+ }
+
+ fuc->size = fw->size;
+ fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL);
+ release_firmware(fw);
+ return (fuc->data != NULL) ? 0 : -ENOMEM;
+}
+
+static void
+nvc0_graph_destroy_fw(struct nvc0_graph_fuc *fuc)
+{
+ if (fuc->data) {
+ kfree(fuc->data);
+ fuc->data = NULL;
+ }
+}
+
+static void
+nvc0_graph_destroy(struct drm_device *dev, int engine)
+{
+ struct nvc0_graph_priv *priv = nv_engine(dev, engine);
+
+ nvc0_graph_destroy_fw(&priv->fuc409c);
+ nvc0_graph_destroy_fw(&priv->fuc409d);
+ nvc0_graph_destroy_fw(&priv->fuc41ac);
+ nvc0_graph_destroy_fw(&priv->fuc41ad);
+
+ nouveau_irq_unregister(dev, 12);
+ nouveau_irq_unregister(dev, 25);
+
+ nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
+ nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
+
+ if (priv->grctx_vals)
+ kfree(priv->grctx_vals);
+
+ NVOBJ_ENGINE_DEL(dev, GR);
+ kfree(priv);
+}
+
+int
+nvc0_graph_create(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ struct nvc0_graph_priv *priv;
+ int ret, gpc, i;
+
+ switch (dev_priv->chipset) {
+ case 0xc0:
+ case 0xc3:
+ case 0xc4:
+ break;
+ default:
+ NV_ERROR(dev, "PGRAPH: unsupported chipset, please report!\n");
+ return 0;
+ }
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base.destroy = nvc0_graph_destroy;
+ priv->base.init = nvc0_graph_init;
+ priv->base.fini = nvc0_graph_fini;
+ priv->base.context_new = nvc0_graph_context_new;
+ priv->base.context_del = nvc0_graph_context_del;
+ priv->base.object_new = nvc0_graph_object_new;
+
+ NVOBJ_ENGINE_ADD(dev, GR, &priv->base);
+ nouveau_irq_register(dev, 12, nvc0_graph_isr);
+ nouveau_irq_register(dev, 25, nvc0_runk140_isr);
+
+ if (nvc0_graph_create_fw(dev, "fuc409c", &priv->fuc409c) ||
+ nvc0_graph_create_fw(dev, "fuc409d", &priv->fuc409d) ||
+ nvc0_graph_create_fw(dev, "fuc41ac", &priv->fuc41ac) ||
+ nvc0_graph_create_fw(dev, "fuc41ad", &priv->fuc41ad)) {
+ ret = 0;
+ goto error;
+ }
+
+
+ ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4);
+ if (ret)
+ goto error;
+
+ ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b8);
+ if (ret)
+ goto error;
+
+ for (i = 0; i < 0x1000; i += 4) {
+ nv_wo32(priv->unk4188b4, i, 0x00000010);
+ nv_wo32(priv->unk4188b8, i, 0x00000010);
+ }
+
+ priv->gpc_nr = nv_rd32(dev, 0x409604) & 0x0000001f;
+ priv->rop_nr = (nv_rd32(dev, 0x409604) & 0x001f0000) >> 16;
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ priv->tp_nr[gpc] = nv_rd32(dev, GPC_UNIT(gpc, 0x2608));
+ priv->tp_total += priv->tp_nr[gpc];
+ }
+
+ /*XXX: these need figuring out... */
+ switch (dev_priv->chipset) {
+ case 0xc0:
+ if (priv->tp_total == 11) { /* 465, 3/4/4/0, 4 */
+ priv->magic_not_rop_nr = 0x07;
+ /* filled values up to tp_total, the rest 0 */
+ priv->magicgpc918 = 0x000ba2e9;
+ } else
+ if (priv->tp_total == 14) { /* 470, 3/3/4/4, 5 */
+ priv->magic_not_rop_nr = 0x05;
+ priv->magicgpc918 = 0x00092493;
+ } else
+ if (priv->tp_total == 15) { /* 480, 3/4/4/4, 6 */
+ priv->magic_not_rop_nr = 0x06;
+ priv->magicgpc918 = 0x00088889;
+ }
+ break;
+ case 0xc3: /* 450, 4/0/0/0, 2 */
+ priv->magic_not_rop_nr = 0x03;
+ priv->magicgpc918 = 0x00200000;
+ break;
+ case 0xc4: /* 460, 3/4/0/0, 4 */
+ priv->magic_not_rop_nr = 0x01;
+ priv->magicgpc918 = 0x00124925;
+ break;
+ }
+
+ if (!priv->magic_not_rop_nr) {
+ NV_ERROR(dev, "PGRAPH: unknown config: %d/%d/%d/%d, %d\n",
+ priv->tp_nr[0], priv->tp_nr[1], priv->tp_nr[2],
+ priv->tp_nr[3], priv->rop_nr);
+ /* use 0xc3's values... */
+ priv->magic_not_rop_nr = 0x03;
+ priv->magicgpc918 = 0x00200000;
+ }
+
+ NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */
+ NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */
+ NVOBJ_MTHD (dev, 0x9039, 0x0500, nvc0_graph_mthd_page_flip);
+ NVOBJ_CLASS(dev, 0x9097, GR); /* 3D */
+ NVOBJ_CLASS(dev, 0x90c0, GR); /* COMPUTE */
+ return 0;
+
+error:
+ nvc0_graph_destroy(dev, NVOBJ_ENGINE_GR);
+ return ret;
+}
+
+MODULE_FIRMWARE("nouveau/nvc0_fuc409c");
+MODULE_FIRMWARE("nouveau/nvc0_fuc409d");
+MODULE_FIRMWARE("nouveau/nvc0_fuc41ac");
+MODULE_FIRMWARE("nouveau/nvc0_fuc41ad");
+MODULE_FIRMWARE("nouveau/nvc3_fuc409c");
+MODULE_FIRMWARE("nouveau/nvc3_fuc409d");
+MODULE_FIRMWARE("nouveau/nvc3_fuc41ac");
+MODULE_FIRMWARE("nouveau/nvc3_fuc41ad");
+MODULE_FIRMWARE("nouveau/nvc4_fuc409c");
+MODULE_FIRMWARE("nouveau/nvc4_fuc409d");
+MODULE_FIRMWARE("nouveau/nvc4_fuc41ac");
+MODULE_FIRMWARE("nouveau/nvc4_fuc41ad");
+MODULE_FIRMWARE("nouveau/fuc409c");
+MODULE_FIRMWARE("nouveau/fuc409d");
+MODULE_FIRMWARE("nouveau/fuc41ac");
+MODULE_FIRMWARE("nouveau/fuc41ad");
diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.h b/drivers/gpu/drm/nouveau/nvc0_graph.h
index 40e26f9c56c4..f5d184e0689d 100644
--- a/drivers/gpu/drm/nouveau/nvc0_graph.h
+++ b/drivers/gpu/drm/nouveau/nvc0_graph.h
@@ -28,13 +28,25 @@
#define GPC_MAX 4
#define TP_MAX 32
-#define ROP_BCAST(r) (0x408800 + (r))
-#define ROP_UNIT(u,r) (0x410000 + (u) * 0x400 + (r))
-#define GPC_BCAST(r) (0x418000 + (r))
-#define GPC_UNIT(t,r) (0x500000 + (t) * 0x8000 + (r))
-#define TP_UNIT(t,m,r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r))
+#define ROP_BCAST(r) (0x408800 + (r))
+#define ROP_UNIT(u, r) (0x410000 + (u) * 0x400 + (r))
+#define GPC_BCAST(r) (0x418000 + (r))
+#define GPC_UNIT(t, r) (0x500000 + (t) * 0x8000 + (r))
+#define TP_UNIT(t, m, r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r))
+
+struct nvc0_graph_fuc {
+ u32 *data;
+ u32 size;
+};
struct nvc0_graph_priv {
+ struct nouveau_exec_engine base;
+
+ struct nvc0_graph_fuc fuc409c;
+ struct nvc0_graph_fuc fuc409d;
+ struct nvc0_graph_fuc fuc41ac;
+ struct nvc0_graph_fuc fuc41ad;
+
u8 gpc_nr;
u8 rop_nr;
u8 tp_nr[GPC_MAX];
@@ -46,15 +58,14 @@ struct nvc0_graph_priv {
struct nouveau_gpuobj *unk4188b8;
u8 magic_not_rop_nr;
- u32 magicgpc980[4];
u32 magicgpc918;
};
struct nvc0_graph_chan {
struct nouveau_gpuobj *grctx;
- struct nouveau_gpuobj *unk408004; // 0x418810 too
- struct nouveau_gpuobj *unk40800c; // 0x419004 too
- struct nouveau_gpuobj *unk418810; // 0x419848 too
+ struct nouveau_gpuobj *unk408004; /* 0x418810 too */
+ struct nouveau_gpuobj *unk40800c; /* 0x419004 too */
+ struct nouveau_gpuobj *unk418810; /* 0x419848 too */
struct nouveau_gpuobj *mmio;
int mmio_nr;
};
diff --git a/drivers/gpu/drm/nouveau/nvc0_grctx.c b/drivers/gpu/drm/nouveau/nvc0_grctx.c
index f880ff776db8..6df066114133 100644
--- a/drivers/gpu/drm/nouveau/nvc0_grctx.c
+++ b/drivers/gpu/drm/nouveau/nvc0_grctx.c
@@ -1623,7 +1623,7 @@ nvc0_grctx_generate_rop(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- // ROPC_BROADCAST
+ /* ROPC_BROADCAST */
nv_wr32(dev, 0x408800, 0x02802a3c);
nv_wr32(dev, 0x408804, 0x00000040);
nv_wr32(dev, 0x408808, 0x0003e00d);
@@ -1647,7 +1647,7 @@ nvc0_grctx_generate_gpc(struct drm_device *dev)
{
int i;
- // GPC_BROADCAST
+ /* GPC_BROADCAST */
nv_wr32(dev, 0x418380, 0x00000016);
nv_wr32(dev, 0x418400, 0x38004e00);
nv_wr32(dev, 0x418404, 0x71e0ffff);
@@ -1728,7 +1728,7 @@ nvc0_grctx_generate_tp(struct drm_device *dev)
{
struct drm_nouveau_private *dev_priv = dev->dev_private;
- // GPC_BROADCAST.TP_BROADCAST
+ /* GPC_BROADCAST.TP_BROADCAST */
nv_wr32(dev, 0x419848, 0x00000000);
nv_wr32(dev, 0x419864, 0x0000012a);
nv_wr32(dev, 0x419888, 0x00000000);
@@ -1741,7 +1741,7 @@ nvc0_grctx_generate_tp(struct drm_device *dev)
nv_wr32(dev, 0x419a1c, 0x00000000);
nv_wr32(dev, 0x419a20, 0x00000800);
if (dev_priv->chipset != 0xc0)
- nv_wr32(dev, 0x00419ac4, 0x0007f440); // 0xc3
+ nv_wr32(dev, 0x00419ac4, 0x0007f440); /* 0xc3 */
nv_wr32(dev, 0x419b00, 0x0a418820);
nv_wr32(dev, 0x419b04, 0x062080e6);
nv_wr32(dev, 0x419b08, 0x020398a4);
@@ -1797,8 +1797,8 @@ int
nvc0_grctx_generate(struct nouveau_channel *chan)
{
struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
- struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
- struct nvc0_graph_chan *grch = chan->pgraph_ctx;
+ struct nvc0_graph_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_GR);
+ struct nvc0_graph_chan *grch = chan->engctx[NVOBJ_ENGINE_GR];
struct drm_device *dev = chan->dev;
int i, gpc, tp, id;
u32 r000260, tmp;
@@ -1912,13 +1912,13 @@ nvc0_grctx_generate(struct nouveau_channel *chan)
for (i = 1; i < 7; i++)
data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
- // GPC_BROADCAST
+ /* GPC_BROADCAST */
nv_wr32(dev, 0x418bb8, (priv->tp_total << 8) |
priv->magic_not_rop_nr);
for (i = 0; i < 6; i++)
nv_wr32(dev, 0x418b08 + (i * 4), data[i]);
- // GPC_BROADCAST.TP_BROADCAST
+ /* GPC_BROADCAST.TP_BROADCAST */
nv_wr32(dev, 0x419bd0, (priv->tp_total << 8) |
priv->magic_not_rop_nr |
data2[0]);
@@ -1926,7 +1926,7 @@ nvc0_grctx_generate(struct nouveau_channel *chan)
for (i = 0; i < 6; i++)
nv_wr32(dev, 0x419b00 + (i * 4), data[i]);
- // UNK78xx
+ /* UNK78xx */
nv_wr32(dev, 0x4078bc, (priv->tp_total << 8) |
priv->magic_not_rop_nr);
for (i = 0; i < 6; i++)
@@ -1944,7 +1944,7 @@ nvc0_grctx_generate(struct nouveau_channel *chan)
gpc = -1;
for (i = 0, gpc = -1; i < 32; i++) {
int ltp = i * (priv->tp_total - 1) / 32;
-
+
do {
gpc = (gpc + 1) % priv->gpc_nr;
} while (!tpnr[gpc]);
diff --git a/drivers/gpu/drm/radeon/atom.c b/drivers/gpu/drm/radeon/atom.c
index 7bd745689097..ebdb0fdb8348 100644
--- a/drivers/gpu/drm/radeon/atom.c
+++ b/drivers/gpu/drm/radeon/atom.c
@@ -652,12 +652,12 @@ static void atom_op_compare(atom_exec_context *ctx, int *ptr, int arg)
static void atom_op_delay(atom_exec_context *ctx, int *ptr, int arg)
{
- uint8_t count = U8((*ptr)++);
+ unsigned count = U8((*ptr)++);
SDEBUG(" count: %d\n", count);
if (arg == ATOM_UNIT_MICROSEC)
udelay(count);
else
- schedule_timeout_uninterruptible(msecs_to_jiffies(count));
+ msleep(count);
}
static void atom_op_div(atom_exec_context *ctx, int *ptr, int arg)
diff --git a/drivers/gpu/drm/radeon/atombios.h b/drivers/gpu/drm/radeon/atombios.h
index 7fd88497b930..49611e2365d9 100644
--- a/drivers/gpu/drm/radeon/atombios.h
+++ b/drivers/gpu/drm/radeon/atombios.h
@@ -726,6 +726,7 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V2
#define ATOM_ENCODER_CMD_DP_VIDEO_ON 0x0d
#define ATOM_ENCODER_CMD_QUERY_DP_LINK_TRAINING_STATUS 0x0e
#define ATOM_ENCODER_CMD_SETUP 0x0f
+#define ATOM_ENCODER_CMD_SETUP_PANEL_MODE 0x10
// ucStatus
#define ATOM_ENCODER_STATUS_LINK_TRAINING_COMPLETE 0x10
@@ -765,13 +766,19 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V3
USHORT usPixelClock; // in 10KHz; for bios convenient
ATOM_DIG_ENCODER_CONFIG_V3 acConfig;
UCHAR ucAction;
- UCHAR ucEncoderMode;
+ union {
+ UCHAR ucEncoderMode;
// =0: DP encoder
// =1: LVDS encoder
// =2: DVI encoder
// =3: HDMI encoder
// =4: SDVO encoder
// =5: DP audio
+ UCHAR ucPanelMode; // only valid when ucAction == ATOM_ENCODER_CMD_SETUP_PANEL_MODE
+ // =0: external DP
+ // =1: internal DP2
+ // =0x11: internal DP1 for NutMeg/Travis DP translator
+ };
UCHAR ucLaneNum; // how many lanes to enable
UCHAR ucBitPerColor; // only valid for DP mode when ucAction = ATOM_ENCODER_CMD_SETUP
UCHAR ucReserved;
@@ -816,13 +823,19 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V4
UCHAR ucConfig;
};
UCHAR ucAction;
- UCHAR ucEncoderMode;
+ union {
+ UCHAR ucEncoderMode;
// =0: DP encoder
// =1: LVDS encoder
// =2: DVI encoder
// =3: HDMI encoder
// =4: SDVO encoder
// =5: DP audio
+ UCHAR ucPanelMode; // only valid when ucAction == ATOM_ENCODER_CMD_SETUP_PANEL_MODE
+ // =0: external DP
+ // =1: internal DP2
+ // =0x11: internal DP1 for NutMeg/Travis DP translator
+ };
UCHAR ucLaneNum; // how many lanes to enable
UCHAR ucBitPerColor; // only valid for DP mode when ucAction = ATOM_ENCODER_CMD_SETUP
UCHAR ucHPD_ID; // HPD ID (1-6). =0 means to skip HDP programming. New comparing to previous version
@@ -836,6 +849,11 @@ typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V4
#define PANEL_12BIT_PER_COLOR 0x04
#define PANEL_16BIT_PER_COLOR 0x05
+//define ucPanelMode
+#define DP_PANEL_MODE_EXTERNAL_DP_MODE 0x00
+#define DP_PANEL_MODE_INTERNAL_DP2_MODE 0x01
+#define DP_PANEL_MODE_INTERNAL_DP1_MODE 0x11
+
/****************************************************************************/
// Structures used by UNIPHYTransmitterControlTable
// LVTMATransmitterControlTable
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 529a3a704731..ec848787d7d9 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -420,7 +420,7 @@ static void atombios_crtc_program_ss(struct drm_crtc *crtc,
if (ASIC_IS_DCE5(rdev)) {
args.v3.usSpreadSpectrumAmountFrac = cpu_to_le16(0);
- args.v3.ucSpreadSpectrumType = ss->type;
+ args.v3.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
switch (pll_id) {
case ATOM_PPLL1:
args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL;
@@ -440,10 +440,12 @@ static void atombios_crtc_program_ss(struct drm_crtc *crtc,
case ATOM_PPLL_INVALID:
return;
}
- args.v2.ucEnable = enable;
+ args.v3.ucEnable = enable;
+ if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK))
+ args.v3.ucEnable = ATOM_DISABLE;
} else if (ASIC_IS_DCE4(rdev)) {
args.v2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
- args.v2.ucSpreadSpectrumType = ss->type;
+ args.v2.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
switch (pll_id) {
case ATOM_PPLL1:
args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL;
@@ -464,32 +466,36 @@ static void atombios_crtc_program_ss(struct drm_crtc *crtc,
return;
}
args.v2.ucEnable = enable;
+ if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK))
+ args.v2.ucEnable = ATOM_DISABLE;
} else if (ASIC_IS_DCE3(rdev)) {
args.v1.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
- args.v1.ucSpreadSpectrumType = ss->type;
+ args.v1.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
args.v1.ucSpreadSpectrumStep = ss->step;
args.v1.ucSpreadSpectrumDelay = ss->delay;
args.v1.ucSpreadSpectrumRange = ss->range;
args.v1.ucPpll = pll_id;
args.v1.ucEnable = enable;
} else if (ASIC_IS_AVIVO(rdev)) {
- if (enable == ATOM_DISABLE) {
+ if ((enable == ATOM_DISABLE) || (ss->percentage == 0) ||
+ (ss->type & ATOM_EXTERNAL_SS_MASK)) {
atombios_disable_ss(crtc);
return;
}
args.lvds_ss_2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
- args.lvds_ss_2.ucSpreadSpectrumType = ss->type;
+ args.lvds_ss_2.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
args.lvds_ss_2.ucSpreadSpectrumStep = ss->step;
args.lvds_ss_2.ucSpreadSpectrumDelay = ss->delay;
args.lvds_ss_2.ucSpreadSpectrumRange = ss->range;
args.lvds_ss_2.ucEnable = enable;
} else {
- if (enable == ATOM_DISABLE) {
+ if ((enable == ATOM_DISABLE) || (ss->percentage == 0) ||
+ (ss->type & ATOM_EXTERNAL_SS_MASK)) {
atombios_disable_ss(crtc);
return;
}
args.lvds_ss.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
- args.lvds_ss.ucSpreadSpectrumType = ss->type;
+ args.lvds_ss.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
args.lvds_ss.ucSpreadSpectrumStepSize_Delay = (ss->step & 3) << 2;
args.lvds_ss.ucSpreadSpectrumStepSize_Delay |= (ss->delay & 7) << 4;
args.lvds_ss.ucEnable = enable;
@@ -512,6 +518,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
struct radeon_device *rdev = dev->dev_private;
struct drm_encoder *encoder = NULL;
struct radeon_encoder *radeon_encoder = NULL;
+ struct drm_connector *connector = NULL;
u32 adjusted_clock = mode->clock;
int encoder_mode = 0;
u32 dp_clock = mode->clock;
@@ -546,9 +553,12 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
if (encoder->crtc == crtc) {
radeon_encoder = to_radeon_encoder(encoder);
+ connector = radeon_get_connector_for_encoder(encoder);
+ if (connector)
+ bpc = connector->display_info.bpc;
encoder_mode = atombios_get_encoder_mode(encoder);
- if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) {
- struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+ if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
+ radeon_encoder_is_dp_bridge(encoder)) {
if (connector) {
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
struct radeon_connector_atom_dig *dig_connector =
@@ -612,7 +622,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
args.v1.usPixelClock = cpu_to_le16(mode->clock / 10);
args.v1.ucTransmitterID = radeon_encoder->encoder_id;
args.v1.ucEncodeMode = encoder_mode;
- if (ss_enabled)
+ if (ss_enabled && ss->percentage)
args.v1.ucConfig |=
ADJUST_DISPLAY_CONFIG_SS_ENABLE;
@@ -625,10 +635,11 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id;
args.v3.sInput.ucEncodeMode = encoder_mode;
args.v3.sInput.ucDispPllConfig = 0;
- if (ss_enabled)
+ if (ss_enabled && ss->percentage)
args.v3.sInput.ucDispPllConfig |=
DISPPLL_CONFIG_SS_ENABLE;
- if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
+ if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT) ||
+ radeon_encoder_is_dp_bridge(encoder)) {
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
if (encoder_mode == ATOM_ENCODER_MODE_DP) {
args.v3.sInput.ucDispPllConfig |=
@@ -754,7 +765,10 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc,
u32 ref_div,
u32 fb_div,
u32 frac_fb_div,
- u32 post_div)
+ u32 post_div,
+ int bpc,
+ bool ss_enabled,
+ struct radeon_atom_ss *ss)
{
struct drm_device *dev = crtc->dev;
struct radeon_device *rdev = dev->dev_private;
@@ -801,6 +815,8 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc,
args.v3.ucPostDiv = post_div;
args.v3.ucPpll = pll_id;
args.v3.ucMiscInfo = (pll_id << 2);
+ if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
+ args.v3.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC;
args.v3.ucTransmitterId = encoder_id;
args.v3.ucEncoderMode = encoder_mode;
break;
@@ -812,6 +828,17 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc,
args.v5.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
args.v5.ucPostDiv = post_div;
args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */
+ if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
+ args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC;
+ switch (bpc) {
+ case 8:
+ default:
+ args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP;
+ break;
+ case 10:
+ args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP;
+ break;
+ }
args.v5.ucTransmitterID = encoder_id;
args.v5.ucEncoderMode = encoder_mode;
args.v5.ucPpll = pll_id;
@@ -824,6 +851,23 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc,
args.v6.ulFbDivDecFrac = cpu_to_le32(frac_fb_div * 100000);
args.v6.ucPostDiv = post_div;
args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */
+ if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK))
+ args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC;
+ switch (bpc) {
+ case 8:
+ default:
+ args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP;
+ break;
+ case 10:
+ args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP;
+ break;
+ case 12:
+ args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP;
+ break;
+ case 16:
+ args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP;
+ break;
+ }
args.v6.ucTransmitterID = encoder_id;
args.v6.ucEncoderMode = encoder_mode;
args.v6.ucPpll = pll_id;
@@ -855,6 +899,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
int encoder_mode = 0;
struct radeon_atom_ss ss;
bool ss_enabled = false;
+ int bpc = 8;
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
if (encoder->crtc == crtc) {
@@ -891,41 +936,30 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
struct radeon_connector_atom_dig *dig_connector =
radeon_connector->con_priv;
int dp_clock;
+ bpc = connector->display_info.bpc;
switch (encoder_mode) {
case ATOM_ENCODER_MODE_DP:
/* DP/eDP */
dp_clock = dig_connector->dp_clock / 10;
- if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
- if (ASIC_IS_DCE4(rdev))
- ss_enabled =
- radeon_atombios_get_asic_ss_info(rdev, &ss,
- dig->lcd_ss_id,
- dp_clock);
- else
+ if (ASIC_IS_DCE4(rdev))
+ ss_enabled =
+ radeon_atombios_get_asic_ss_info(rdev, &ss,
+ ASIC_INTERNAL_SS_ON_DP,
+ dp_clock);
+ else {
+ if (dp_clock == 16200) {
ss_enabled =
radeon_atombios_get_ppll_ss_info(rdev, &ss,
- dig->lcd_ss_id);
- } else {
- if (ASIC_IS_DCE4(rdev))
- ss_enabled =
- radeon_atombios_get_asic_ss_info(rdev, &ss,
- ASIC_INTERNAL_SS_ON_DP,
- dp_clock);
- else {
- if (dp_clock == 16200) {
- ss_enabled =
- radeon_atombios_get_ppll_ss_info(rdev, &ss,
- ATOM_DP_SS_ID2);
- if (!ss_enabled)
- ss_enabled =
- radeon_atombios_get_ppll_ss_info(rdev, &ss,
- ATOM_DP_SS_ID1);
- } else
+ ATOM_DP_SS_ID2);
+ if (!ss_enabled)
ss_enabled =
radeon_atombios_get_ppll_ss_info(rdev, &ss,
ATOM_DP_SS_ID1);
- }
+ } else
+ ss_enabled =
+ radeon_atombios_get_ppll_ss_info(rdev, &ss,
+ ATOM_DP_SS_ID1);
}
break;
case ATOM_ENCODER_MODE_LVDS:
@@ -974,7 +1008,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
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);
+ ref_div, fb_div, frac_fb_div, post_div, bpc, ss_enabled, &ss);
if (ss_enabled) {
/* calculate ss amount and step size */
@@ -982,7 +1016,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
u32 step_size;
u32 amount = (((fb_div * 10) + frac_fb_div) * ss.percentage) / 10000;
ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK;
- ss.amount |= ((amount - (ss.amount * 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) &
+ ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) &
ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK;
if (ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD)
step_size = (4 * amount * ref_div * (ss.rate * 2048)) /
@@ -1395,11 +1429,19 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
uint32_t pll_in_use = 0;
if (ASIC_IS_DCE4(rdev)) {
- /* if crtc is driving DP and we have an ext clock, use that */
list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) {
if (test_encoder->crtc && (test_encoder->crtc == crtc)) {
+ /* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock,
+ * depending on the asic:
+ * DCE4: PPLL or ext clock
+ * DCE5: DCPLL or ext clock
+ *
+ * Setting ATOM_PPLL_INVALID will cause SetPixelClock to skip
+ * PPLL/DCPLL programming and only program the DP DTO for the
+ * crtc virtual pixel clock.
+ */
if (atombios_get_encoder_mode(test_encoder) == ATOM_ENCODER_MODE_DP) {
- if (rdev->clock.dp_extclk)
+ if (ASIC_IS_DCE5(rdev) || rdev->clock.dp_extclk)
return ATOM_PPLL_INVALID;
}
}
@@ -1515,6 +1557,8 @@ static void atombios_crtc_commit(struct drm_crtc *crtc)
static void atombios_crtc_disable(struct drm_crtc *crtc)
{
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+ struct radeon_atom_ss ss;
+
atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
switch (radeon_crtc->pll_id) {
@@ -1522,7 +1566,7 @@ static void atombios_crtc_disable(struct drm_crtc *crtc)
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);
+ 0, 0, ATOM_DISABLE, 0, 0, 0, 0, 0, false, &ss);
break;
default:
break;
diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c
index 695de9a38506..8c0f9e36ff8e 100644
--- a/drivers/gpu/drm/radeon/atombios_dp.c
+++ b/drivers/gpu/drm/radeon/atombios_dp.c
@@ -43,158 +43,242 @@ static char *pre_emph_names[] = {
"0dB", "3.5dB", "6dB", "9.5dB"
};
-static const int dp_clocks[] = {
- 54000, /* 1 lane, 1.62 Ghz */
- 90000, /* 1 lane, 2.70 Ghz */
- 108000, /* 2 lane, 1.62 Ghz */
- 180000, /* 2 lane, 2.70 Ghz */
- 216000, /* 4 lane, 1.62 Ghz */
- 360000, /* 4 lane, 2.70 Ghz */
+/***** radeon AUX functions *****/
+union aux_channel_transaction {
+ PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1;
+ PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2;
};
-static const int num_dp_clocks = sizeof(dp_clocks) / sizeof(int);
+static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
+ u8 *send, int send_bytes,
+ u8 *recv, int recv_size,
+ u8 delay, u8 *ack)
+{
+ struct drm_device *dev = chan->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ union aux_channel_transaction args;
+ int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction);
+ unsigned char *base;
+ int recv_bytes;
+
+ memset(&args, 0, sizeof(args));
-/* common helper functions */
-static int dp_lanes_for_mode_clock(u8 dpcd[DP_DPCD_SIZE], int mode_clock)
+ base = (unsigned char *)rdev->mode_info.atom_context->scratch;
+
+ memcpy(base, send, send_bytes);
+
+ args.v1.lpAuxRequest = 0;
+ args.v1.lpDataOut = 16;
+ args.v1.ucDataOutLen = 0;
+ args.v1.ucChannelID = chan->rec.i2c_id;
+ args.v1.ucDelay = delay / 10;
+ if (ASIC_IS_DCE4(rdev))
+ args.v2.ucHPD_ID = chan->rec.hpd;
+
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+ *ack = args.v1.ucReplyStatus;
+
+ /* timeout */
+ if (args.v1.ucReplyStatus == 1) {
+ DRM_DEBUG_KMS("dp_aux_ch timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ /* flags not zero */
+ if (args.v1.ucReplyStatus == 2) {
+ DRM_DEBUG_KMS("dp_aux_ch flags not zero\n");
+ return -EBUSY;
+ }
+
+ /* error */
+ if (args.v1.ucReplyStatus == 3) {
+ DRM_DEBUG_KMS("dp_aux_ch error\n");
+ return -EIO;
+ }
+
+ recv_bytes = args.v1.ucDataOutLen;
+ if (recv_bytes > recv_size)
+ recv_bytes = recv_size;
+
+ if (recv && recv_size)
+ memcpy(recv, base + 16, recv_bytes);
+
+ return recv_bytes;
+}
+
+static int radeon_dp_aux_native_write(struct radeon_connector *radeon_connector,
+ u16 address, u8 *send, u8 send_bytes, u8 delay)
{
- int i;
- u8 max_link_bw;
- u8 max_lane_count;
+ struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
+ int ret;
+ u8 msg[20];
+ int msg_bytes = send_bytes + 4;
+ u8 ack;
- if (!dpcd)
- return 0;
+ if (send_bytes > 16)
+ return -1;
- max_link_bw = dpcd[DP_MAX_LINK_RATE];
- max_lane_count = dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK;
+ msg[0] = address;
+ msg[1] = address >> 8;
+ msg[2] = AUX_NATIVE_WRITE << 4;
+ msg[3] = (msg_bytes << 4) | (send_bytes - 1);
+ memcpy(&msg[4], send, send_bytes);
- switch (max_link_bw) {
- case DP_LINK_BW_1_62:
- default:
- for (i = 0; i < num_dp_clocks; i++) {
- if (i % 2)
- continue;
- switch (max_lane_count) {
- case 1:
- if (i > 1)
- return 0;
- break;
- case 2:
- if (i > 3)
- return 0;
- break;
- case 4:
- default:
- break;
- }
- if (dp_clocks[i] > mode_clock) {
- if (i < 2)
- return 1;
- else if (i < 4)
- return 2;
- else
- return 4;
- }
- }
- break;
- case DP_LINK_BW_2_7:
- for (i = 0; i < num_dp_clocks; i++) {
- switch (max_lane_count) {
- case 1:
- if (i > 1)
- return 0;
- break;
- case 2:
- if (i > 3)
- return 0;
- break;
- case 4:
- default:
- break;
- }
- if (dp_clocks[i] > mode_clock) {
- if (i < 2)
- return 1;
- else if (i < 4)
- return 2;
- else
- return 4;
- }
- }
- break;
+ while (1) {
+ ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus,
+ msg, msg_bytes, NULL, 0, delay, &ack);
+ if (ret < 0)
+ return ret;
+ if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
+ break;
+ else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
+ udelay(400);
+ else
+ return -EIO;
}
- return 0;
+ return send_bytes;
}
-static int dp_link_clock_for_mode_clock(u8 dpcd[DP_DPCD_SIZE], int mode_clock)
+static int radeon_dp_aux_native_read(struct radeon_connector *radeon_connector,
+ u16 address, u8 *recv, int recv_bytes, u8 delay)
{
- int i;
- u8 max_link_bw;
- u8 max_lane_count;
+ struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
+ u8 msg[4];
+ int msg_bytes = 4;
+ u8 ack;
+ int ret;
- if (!dpcd)
- return 0;
+ msg[0] = address;
+ msg[1] = address >> 8;
+ msg[2] = AUX_NATIVE_READ << 4;
+ msg[3] = (msg_bytes << 4) | (recv_bytes - 1);
+
+ while (1) {
+ ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus,
+ msg, msg_bytes, recv, recv_bytes, delay, &ack);
+ if (ret == 0)
+ return -EPROTO;
+ if (ret < 0)
+ return ret;
+ if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
+ return ret;
+ else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
+ udelay(400);
+ else
+ return -EIO;
+ }
+}
- max_link_bw = dpcd[DP_MAX_LINK_RATE];
- max_lane_count = dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK;
+static void radeon_write_dpcd_reg(struct radeon_connector *radeon_connector,
+ u16 reg, u8 val)
+{
+ radeon_dp_aux_native_write(radeon_connector, reg, &val, 1, 0);
+}
- switch (max_link_bw) {
- case DP_LINK_BW_1_62:
+static u8 radeon_read_dpcd_reg(struct radeon_connector *radeon_connector,
+ u16 reg)
+{
+ u8 val = 0;
+
+ radeon_dp_aux_native_read(radeon_connector, reg, &val, 1, 0);
+
+ return val;
+}
+
+int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
+ u8 write_byte, u8 *read_byte)
+{
+ struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
+ struct radeon_i2c_chan *auxch = (struct radeon_i2c_chan *)adapter;
+ u16 address = algo_data->address;
+ u8 msg[5];
+ u8 reply[2];
+ unsigned retry;
+ int msg_bytes;
+ int reply_bytes = 1;
+ int ret;
+ u8 ack;
+
+ /* Set up the command byte */
+ if (mode & MODE_I2C_READ)
+ msg[2] = AUX_I2C_READ << 4;
+ else
+ msg[2] = AUX_I2C_WRITE << 4;
+
+ if (!(mode & MODE_I2C_STOP))
+ msg[2] |= AUX_I2C_MOT << 4;
+
+ msg[0] = address;
+ msg[1] = address >> 8;
+
+ switch (mode) {
+ case MODE_I2C_WRITE:
+ msg_bytes = 5;
+ msg[3] = msg_bytes << 4;
+ msg[4] = write_byte;
+ break;
+ case MODE_I2C_READ:
+ msg_bytes = 4;
+ msg[3] = msg_bytes << 4;
+ break;
default:
- for (i = 0; i < num_dp_clocks; i++) {
- if (i % 2)
- continue;
- switch (max_lane_count) {
- case 1:
- if (i > 1)
- return 0;
- break;
- case 2:
- if (i > 3)
- return 0;
- break;
- case 4:
- default:
- break;
- }
- if (dp_clocks[i] > mode_clock)
- return 162000;
- }
+ msg_bytes = 4;
+ msg[3] = 3 << 4;
break;
- case DP_LINK_BW_2_7:
- for (i = 0; i < num_dp_clocks; i++) {
- switch (max_lane_count) {
- case 1:
- if (i > 1)
- return 0;
- break;
- case 2:
- if (i > 3)
- return 0;
- break;
- case 4:
- default:
- break;
- }
- if (dp_clocks[i] > mode_clock)
- return (i % 2) ? 270000 : 162000;
- }
}
- return 0;
-}
+ for (retry = 0; retry < 4; retry++) {
+ ret = radeon_process_aux_ch(auxch,
+ msg, msg_bytes, reply, reply_bytes, 0, &ack);
+ if (ret < 0) {
+ DRM_DEBUG_KMS("aux_ch failed %d\n", ret);
+ return ret;
+ }
-int dp_mode_valid(u8 dpcd[DP_DPCD_SIZE], int mode_clock)
-{
- int lanes = dp_lanes_for_mode_clock(dpcd, mode_clock);
- int dp_clock = dp_link_clock_for_mode_clock(dpcd, mode_clock);
+ switch (ack & AUX_NATIVE_REPLY_MASK) {
+ case AUX_NATIVE_REPLY_ACK:
+ /* I2C-over-AUX Reply field is only valid
+ * when paired with AUX ACK.
+ */
+ break;
+ case AUX_NATIVE_REPLY_NACK:
+ DRM_DEBUG_KMS("aux_ch native nack\n");
+ return -EREMOTEIO;
+ case AUX_NATIVE_REPLY_DEFER:
+ DRM_DEBUG_KMS("aux_ch native defer\n");
+ udelay(400);
+ continue;
+ default:
+ DRM_ERROR("aux_ch invalid native reply 0x%02x\n", ack);
+ return -EREMOTEIO;
+ }
- if ((lanes == 0) || (dp_clock == 0))
- return MODE_CLOCK_HIGH;
+ switch (ack & AUX_I2C_REPLY_MASK) {
+ case AUX_I2C_REPLY_ACK:
+ if (mode == MODE_I2C_READ)
+ *read_byte = reply[0];
+ return ret;
+ case AUX_I2C_REPLY_NACK:
+ DRM_DEBUG_KMS("aux_i2c nack\n");
+ return -EREMOTEIO;
+ case AUX_I2C_REPLY_DEFER:
+ DRM_DEBUG_KMS("aux_i2c defer\n");
+ udelay(400);
+ break;
+ default:
+ DRM_ERROR("aux_i2c invalid reply 0x%02x\n", ack);
+ return -EREMOTEIO;
+ }
+ }
- return MODE_OK;
+ DRM_ERROR("aux i2c too many retries, giving up\n");
+ return -EREMOTEIO;
}
+/***** general DP utility functions *****/
+
static u8 dp_link_status(u8 link_status[DP_LINK_STATUS_SIZE], int r)
{
return link_status[r - DP_LANE0_1_STATUS];
@@ -242,7 +326,7 @@ static bool dp_channel_eq_ok(u8 link_status[DP_LINK_STATUS_SIZE],
return true;
}
-static u8 dp_get_adjust_request_voltage(uint8_t link_status[DP_LINK_STATUS_SIZE],
+static u8 dp_get_adjust_request_voltage(u8 link_status[DP_LINK_STATUS_SIZE],
int lane)
{
@@ -255,7 +339,7 @@ static u8 dp_get_adjust_request_voltage(uint8_t link_status[DP_LINK_STATUS_SIZE]
return ((l >> s) & 0x3) << DP_TRAIN_VOLTAGE_SWING_SHIFT;
}
-static u8 dp_get_adjust_request_pre_emphasis(uint8_t link_status[DP_LINK_STATUS_SIZE],
+static u8 dp_get_adjust_request_pre_emphasis(u8 link_status[DP_LINK_STATUS_SIZE],
int lane)
{
int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1);
@@ -267,22 +351,8 @@ static u8 dp_get_adjust_request_pre_emphasis(uint8_t link_status[DP_LINK_STATUS_
return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT;
}
-/* XXX fix me -- chip specific */
#define DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_1200
-static u8 dp_pre_emphasis_max(u8 voltage_swing)
-{
- switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
- case DP_TRAIN_VOLTAGE_SWING_400:
- return DP_TRAIN_PRE_EMPHASIS_6;
- case DP_TRAIN_VOLTAGE_SWING_600:
- return DP_TRAIN_PRE_EMPHASIS_6;
- case DP_TRAIN_VOLTAGE_SWING_800:
- return DP_TRAIN_PRE_EMPHASIS_3_5;
- case DP_TRAIN_VOLTAGE_SWING_1200:
- default:
- return DP_TRAIN_PRE_EMPHASIS_0;
- }
-}
+#define DP_PRE_EMPHASIS_MAX DP_TRAIN_PRE_EMPHASIS_9_5
static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE],
int lane_count,
@@ -308,10 +378,10 @@ static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE],
}
if (v >= DP_VOLTAGE_MAX)
- v = DP_VOLTAGE_MAX | DP_TRAIN_MAX_SWING_REACHED;
+ v |= DP_TRAIN_MAX_SWING_REACHED;
- if (p >= dp_pre_emphasis_max(v))
- p = dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
+ if (p >= DP_PRE_EMPHASIS_MAX)
+ p |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
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],
@@ -321,110 +391,109 @@ static void dp_get_adjust_train(u8 link_status[DP_LINK_STATUS_SIZE],
train_set[lane] = v | p;
}
-union aux_channel_transaction {
- PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1;
- PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2;
-};
-
-/* radeon aux chan functions */
-bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes,
- int num_bytes, u8 *read_byte,
- u8 read_buf_len, u8 delay)
+/* convert bits per color to bits per pixel */
+/* get bpc from the EDID */
+static int convert_bpc_to_bpp(int bpc)
{
- struct drm_device *dev = chan->dev;
- struct radeon_device *rdev = dev->dev_private;
- union aux_channel_transaction args;
- int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction);
- unsigned char *base;
- int retry_count = 0;
-
- memset(&args, 0, sizeof(args));
-
- base = (unsigned char *)rdev->mode_info.atom_context->scratch;
-
-retry:
- memcpy(base, req_bytes, num_bytes);
-
- args.v1.lpAuxRequest = 0;
- args.v1.lpDataOut = 16;
- args.v1.ucDataOutLen = 0;
- args.v1.ucChannelID = chan->rec.i2c_id;
- args.v1.ucDelay = delay / 10;
- if (ASIC_IS_DCE4(rdev))
- args.v2.ucHPD_ID = chan->rec.hpd;
+ if (bpc == 0)
+ return 24;
+ else
+ return bpc * 3;
+}
- atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+/* get the max pix clock supported by the link rate and lane num */
+static int dp_get_max_dp_pix_clock(int link_rate,
+ int lane_num,
+ int bpp)
+{
+ return (link_rate * lane_num * 8) / bpp;
+}
- if (args.v1.ucReplyStatus && !args.v1.ucDataOutLen) {
- if (args.v1.ucReplyStatus == 0x20 && retry_count++ < 10)
- goto retry;
- 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;
+static int dp_get_max_link_rate(u8 dpcd[DP_DPCD_SIZE])
+{
+ switch (dpcd[DP_MAX_LINK_RATE]) {
+ case DP_LINK_BW_1_62:
+ default:
+ return 162000;
+ case DP_LINK_BW_2_7:
+ return 270000;
+ case DP_LINK_BW_5_4:
+ return 540000;
}
+}
- if (args.v1.ucDataOutLen && read_byte && read_buf_len) {
- if (read_buf_len < args.v1.ucDataOutLen) {
- DRM_ERROR("Buffer to small for return answer %d %d\n",
- read_buf_len, args.v1.ucDataOutLen);
- return false;
- }
- {
- int len = min(read_buf_len, args.v1.ucDataOutLen);
- memcpy(read_byte, base + 16, len);
- }
- }
- return true;
+static u8 dp_get_max_lane_number(u8 dpcd[DP_DPCD_SIZE])
+{
+ return dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK;
}
-bool radeon_dp_aux_native_write(struct radeon_connector *radeon_connector, uint16_t address,
- uint8_t send_bytes, uint8_t *send)
+static u8 dp_get_dp_link_rate_coded(int link_rate)
{
- struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
- u8 msg[20];
- u8 msg_len, dp_msg_len;
- bool ret;
+ switch (link_rate) {
+ case 162000:
+ default:
+ return DP_LINK_BW_1_62;
+ case 270000:
+ return DP_LINK_BW_2_7;
+ case 540000:
+ return DP_LINK_BW_5_4;
+ }
+}
- dp_msg_len = 4;
- msg[0] = address;
- msg[1] = address >> 8;
- msg[2] = AUX_NATIVE_WRITE << 4;
- dp_msg_len += send_bytes;
- msg[3] = (dp_msg_len << 4) | (send_bytes - 1);
+/***** radeon specific DP functions *****/
- if (send_bytes > 16)
- return false;
+/* First get the min lane# when low rate is used according to pixel clock
+ * (prefer low rate), second check max lane# supported by DP panel,
+ * if the max lane# < low rate lane# then use max lane# instead.
+ */
+static int radeon_dp_get_dp_lane_number(struct drm_connector *connector,
+ u8 dpcd[DP_DPCD_SIZE],
+ int pix_clock)
+{
+ int bpp = convert_bpc_to_bpp(connector->display_info.bpc);
+ int max_link_rate = dp_get_max_link_rate(dpcd);
+ int max_lane_num = dp_get_max_lane_number(dpcd);
+ int lane_num;
+ int max_dp_pix_clock;
+
+ for (lane_num = 1; lane_num < max_lane_num; lane_num <<= 1) {
+ max_dp_pix_clock = dp_get_max_dp_pix_clock(max_link_rate, lane_num, bpp);
+ if (pix_clock <= max_dp_pix_clock)
+ break;
+ }
- memcpy(&msg[4], send, send_bytes);
- msg_len = 4 + send_bytes;
- ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus, msg, msg_len, NULL, 0, 0);
- return ret;
+ return lane_num;
}
-bool radeon_dp_aux_native_read(struct radeon_connector *radeon_connector, uint16_t address,
- uint8_t delay, uint8_t expected_bytes,
- uint8_t *read_p)
+static int radeon_dp_get_dp_link_clock(struct drm_connector *connector,
+ u8 dpcd[DP_DPCD_SIZE],
+ int pix_clock)
{
- struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
- u8 msg[20];
- u8 msg_len, dp_msg_len;
- bool ret = false;
- msg_len = 4;
- dp_msg_len = 4;
- msg[0] = address;
- msg[1] = address >> 8;
- msg[2] = AUX_NATIVE_READ << 4;
- msg[3] = (dp_msg_len) << 4;
- msg[3] |= expected_bytes - 1;
+ int bpp = convert_bpc_to_bpp(connector->display_info.bpc);
+ int lane_num, max_pix_clock;
+
+ if (radeon_connector_encoder_is_dp_bridge(connector))
+ return 270000;
+
+ lane_num = radeon_dp_get_dp_lane_number(connector, dpcd, pix_clock);
+ max_pix_clock = dp_get_max_dp_pix_clock(162000, lane_num, bpp);
+ if (pix_clock <= max_pix_clock)
+ return 162000;
+ max_pix_clock = dp_get_max_dp_pix_clock(270000, lane_num, bpp);
+ if (pix_clock <= max_pix_clock)
+ return 270000;
+ if (radeon_connector_is_dp12_capable(connector)) {
+ max_pix_clock = dp_get_max_dp_pix_clock(540000, lane_num, bpp);
+ if (pix_clock <= max_pix_clock)
+ return 540000;
+ }
- ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus, msg, msg_len, read_p, expected_bytes, delay);
- return ret;
+ return dp_get_max_link_rate(dpcd);
}
-/* radeon dp functions */
-static u8 radeon_dp_encoder_service(struct radeon_device *rdev, int action, int dp_clock,
- uint8_t ucconfig, uint8_t lane_num)
+static u8 radeon_dp_encoder_service(struct radeon_device *rdev,
+ int action, int dp_clock,
+ u8 ucconfig, u8 lane_num)
{
DP_ENCODER_SERVICE_PARAMETERS args;
int index = GetIndexIntoMasterTable(COMMAND, DPEncoderService);
@@ -454,60 +523,86 @@ bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector)
{
struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
u8 msg[25];
- int ret;
+ int ret, i;
- ret = radeon_dp_aux_native_read(radeon_connector, DP_DPCD_REV, 0, 8, msg);
- if (ret) {
+ ret = radeon_dp_aux_native_read(radeon_connector, DP_DPCD_REV, msg, 8, 0);
+ if (ret > 0) {
memcpy(dig_connector->dpcd, msg, 8);
- {
- int i;
- DRM_DEBUG_KMS("DPCD: ");
- for (i = 0; i < 8; i++)
- DRM_DEBUG_KMS("%02x ", msg[i]);
- DRM_DEBUG_KMS("\n");
- }
+ DRM_DEBUG_KMS("DPCD: ");
+ for (i = 0; i < 8; i++)
+ DRM_DEBUG_KMS("%02x ", msg[i]);
+ DRM_DEBUG_KMS("\n");
return true;
}
dig_connector->dpcd[0] = 0;
return false;
}
+static void radeon_dp_set_panel_mode(struct drm_encoder *encoder,
+ struct drm_connector *connector)
+{
+ struct drm_device *dev = encoder->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ int panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE;
+
+ if (!ASIC_IS_DCE4(rdev))
+ return;
+
+ if (radeon_connector_encoder_is_dp_bridge(connector))
+ panel_mode = DP_PANEL_MODE_INTERNAL_DP1_MODE;
+
+ atombios_dig_encoder_setup(encoder,
+ ATOM_ENCODER_CMD_SETUP_PANEL_MODE,
+ panel_mode);
+}
+
void radeon_dp_set_link_config(struct drm_connector *connector,
struct drm_display_mode *mode)
{
- struct radeon_connector *radeon_connector;
+ struct radeon_connector *radeon_connector = to_radeon_connector(connector);
struct radeon_connector_atom_dig *dig_connector;
- if ((connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) &&
- (connector->connector_type != DRM_MODE_CONNECTOR_eDP))
- return;
-
- radeon_connector = to_radeon_connector(connector);
if (!radeon_connector->con_priv)
return;
dig_connector = radeon_connector->con_priv;
- dig_connector->dp_clock =
- dp_link_clock_for_mode_clock(dig_connector->dpcd, mode->clock);
- dig_connector->dp_lane_count =
- dp_lanes_for_mode_clock(dig_connector->dpcd, mode->clock);
+ if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
+ (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
+ dig_connector->dp_clock =
+ radeon_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
+ dig_connector->dp_lane_count =
+ radeon_dp_get_dp_lane_number(connector, dig_connector->dpcd, mode->clock);
+ }
}
-int radeon_dp_mode_valid_helper(struct radeon_connector *radeon_connector,
+int radeon_dp_mode_valid_helper(struct drm_connector *connector,
struct drm_display_mode *mode)
{
- struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
+ struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+ struct radeon_connector_atom_dig *dig_connector;
+ int dp_clock;
+
+ if (!radeon_connector->con_priv)
+ return MODE_CLOCK_HIGH;
+ dig_connector = radeon_connector->con_priv;
+
+ dp_clock =
+ radeon_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock);
+
+ if ((dp_clock == 540000) &&
+ (!radeon_connector_is_dp12_capable(connector)))
+ return MODE_CLOCK_HIGH;
- return dp_mode_valid(dig_connector->dpcd, mode->clock);
+ return MODE_OK;
}
-static bool atom_dp_get_link_status(struct radeon_connector *radeon_connector,
- u8 link_status[DP_LINK_STATUS_SIZE])
+static bool radeon_dp_get_link_status(struct radeon_connector *radeon_connector,
+ u8 link_status[DP_LINK_STATUS_SIZE])
{
int ret;
- ret = radeon_dp_aux_native_read(radeon_connector, DP_LANE0_1_STATUS, 100,
- DP_LINK_STATUS_SIZE, link_status);
- if (!ret) {
+ ret = radeon_dp_aux_native_read(radeon_connector, DP_LANE0_1_STATUS,
+ link_status, DP_LINK_STATUS_SIZE, 100);
+ if (ret <= 0) {
DRM_ERROR("displayport link status failed\n");
return false;
}
@@ -518,292 +613,309 @@ static bool atom_dp_get_link_status(struct radeon_connector *radeon_connector,
return true;
}
-bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector)
-{
- struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
+struct radeon_dp_link_train_info {
+ struct radeon_device *rdev;
+ struct drm_encoder *encoder;
+ struct drm_connector *connector;
+ struct radeon_connector *radeon_connector;
+ int enc_id;
+ int dp_clock;
+ int dp_lane_count;
+ int rd_interval;
+ bool tp3_supported;
+ u8 dpcd[8];
+ u8 train_set[4];
u8 link_status[DP_LINK_STATUS_SIZE];
+ u8 tries;
+};
- if (!atom_dp_get_link_status(radeon_connector, link_status))
- return false;
- if (dp_channel_eq_ok(link_status, dig_connector->dp_lane_count))
- return false;
- return true;
+static void radeon_dp_update_vs_emph(struct radeon_dp_link_train_info *dp_info)
+{
+ /* set the initial vs/emph on the source */
+ atombios_dig_transmitter_setup(dp_info->encoder,
+ ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH,
+ 0, dp_info->train_set[0]); /* sets all lanes at once */
+
+ /* set the vs/emph on the sink */
+ radeon_dp_aux_native_write(dp_info->radeon_connector, DP_TRAINING_LANE0_SET,
+ dp_info->train_set, dp_info->dp_lane_count, 0);
}
-static void dp_set_power(struct radeon_connector *radeon_connector, u8 power_state)
+static void radeon_dp_set_tp(struct radeon_dp_link_train_info *dp_info, int tp)
{
- struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
+ int rtp = 0;
- if (dig_connector->dpcd[0] >= 0x11) {
- radeon_dp_aux_native_write(radeon_connector, DP_SET_POWER, 1,
- &power_state);
+ /* set training pattern on the source */
+ if (ASIC_IS_DCE4(dp_info->rdev)) {
+ switch (tp) {
+ case DP_TRAINING_PATTERN_1:
+ rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1;
+ break;
+ case DP_TRAINING_PATTERN_2:
+ rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2;
+ break;
+ case DP_TRAINING_PATTERN_3:
+ rtp = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN3;
+ break;
+ }
+ atombios_dig_encoder_setup(dp_info->encoder, rtp, 0);
+ } else {
+ switch (tp) {
+ case DP_TRAINING_PATTERN_1:
+ rtp = 0;
+ break;
+ case DP_TRAINING_PATTERN_2:
+ rtp = 1;
+ break;
+ }
+ radeon_dp_encoder_service(dp_info->rdev, ATOM_DP_ACTION_TRAINING_PATTERN_SEL,
+ dp_info->dp_clock, dp_info->enc_id, rtp);
}
-}
-static void dp_set_downspread(struct radeon_connector *radeon_connector, u8 downspread)
-{
- radeon_dp_aux_native_write(radeon_connector, DP_DOWNSPREAD_CTRL, 1,
- &downspread);
+ /* enable training pattern on the sink */
+ radeon_write_dpcd_reg(dp_info->radeon_connector, DP_TRAINING_PATTERN_SET, tp);
}
-static void dp_set_link_bw_lanes(struct radeon_connector *radeon_connector,
- u8 link_configuration[DP_LINK_CONFIGURATION_SIZE])
+static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info)
{
- radeon_dp_aux_native_write(radeon_connector, DP_LINK_BW_SET, 2,
- link_configuration);
-}
+ u8 tmp;
-static void dp_update_dpvs_emph(struct radeon_connector *radeon_connector,
- struct drm_encoder *encoder,
- u8 train_set[4])
-{
- struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
- int i;
+ /* power up the sink */
+ if (dp_info->dpcd[0] >= 0x11)
+ radeon_write_dpcd_reg(dp_info->radeon_connector,
+ DP_SET_POWER, DP_SET_POWER_D0);
+
+ /* possibly enable downspread on the sink */
+ if (dp_info->dpcd[3] & 0x1)
+ radeon_write_dpcd_reg(dp_info->radeon_connector,
+ DP_DOWNSPREAD_CTRL, DP_SPREAD_AMP_0_5);
+ else
+ radeon_write_dpcd_reg(dp_info->radeon_connector,
+ DP_DOWNSPREAD_CTRL, 0);
- for (i = 0; i < dig_connector->dp_lane_count; i++)
- atombios_dig_transmitter_setup(encoder,
- ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH,
- i, train_set[i]);
+ radeon_dp_set_panel_mode(dp_info->encoder, dp_info->connector);
- radeon_dp_aux_native_write(radeon_connector, DP_TRAINING_LANE0_SET,
- dig_connector->dp_lane_count, train_set);
-}
+ /* set the lane count on the sink */
+ tmp = dp_info->dp_lane_count;
+ if (dp_info->dpcd[0] >= 0x11)
+ tmp |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
+ radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LANE_COUNT_SET, tmp);
-static void dp_set_training(struct radeon_connector *radeon_connector,
- u8 training)
-{
- radeon_dp_aux_native_write(radeon_connector, DP_TRAINING_PATTERN_SET,
- 1, &training);
-}
+ /* set the link rate on the sink */
+ tmp = dp_get_dp_link_rate_coded(dp_info->dp_clock);
+ radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LINK_BW_SET, tmp);
-void dp_link_train(struct drm_encoder *encoder,
- struct drm_connector *connector)
-{
- struct drm_device *dev = encoder->dev;
- struct radeon_device *rdev = dev->dev_private;
- struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- struct radeon_encoder_atom_dig *dig;
- struct radeon_connector *radeon_connector;
- struct radeon_connector_atom_dig *dig_connector;
- int enc_id = 0;
- bool clock_recovery, channel_eq;
- u8 link_status[DP_LINK_STATUS_SIZE];
- u8 link_configuration[DP_LINK_CONFIGURATION_SIZE];
- u8 tries, voltage;
- u8 train_set[4];
- int i;
+ /* start training on the source */
+ if (ASIC_IS_DCE4(dp_info->rdev))
+ atombios_dig_encoder_setup(dp_info->encoder,
+ ATOM_ENCODER_CMD_DP_LINK_TRAINING_START, 0);
+ else
+ radeon_dp_encoder_service(dp_info->rdev, ATOM_DP_ACTION_TRAINING_START,
+ dp_info->dp_clock, dp_info->enc_id, 0);
- if ((connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) &&
- (connector->connector_type != DRM_MODE_CONNECTOR_eDP))
- return;
+ /* disable the training pattern on the sink */
+ radeon_write_dpcd_reg(dp_info->radeon_connector,
+ DP_TRAINING_PATTERN_SET,
+ DP_TRAINING_PATTERN_DISABLE);
- if (!radeon_encoder->enc_priv)
- return;
- dig = radeon_encoder->enc_priv;
+ return 0;
+}
- radeon_connector = to_radeon_connector(connector);
- if (!radeon_connector->con_priv)
- return;
- dig_connector = radeon_connector->con_priv;
+static int radeon_dp_link_train_finish(struct radeon_dp_link_train_info *dp_info)
+{
+ udelay(400);
- if (dig->dig_encoder)
- enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER;
- else
- enc_id |= ATOM_DP_CONFIG_DIG1_ENCODER;
- if (dig->linkb)
- enc_id |= ATOM_DP_CONFIG_LINK_B;
- else
- enc_id |= ATOM_DP_CONFIG_LINK_A;
+ /* disable the training pattern on the sink */
+ radeon_write_dpcd_reg(dp_info->radeon_connector,
+ DP_TRAINING_PATTERN_SET,
+ DP_TRAINING_PATTERN_DISABLE);
- memset(link_configuration, 0, DP_LINK_CONFIGURATION_SIZE);
- if (dig_connector->dp_clock == 270000)
- link_configuration[0] = DP_LINK_BW_2_7;
+ /* disable the training pattern on the source */
+ if (ASIC_IS_DCE4(dp_info->rdev))
+ atombios_dig_encoder_setup(dp_info->encoder,
+ ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE, 0);
else
- link_configuration[0] = DP_LINK_BW_1_62;
- link_configuration[1] = dig_connector->dp_lane_count;
- if (dig_connector->dpcd[0] >= 0x11)
- link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
+ radeon_dp_encoder_service(dp_info->rdev, ATOM_DP_ACTION_TRAINING_COMPLETE,
+ dp_info->dp_clock, dp_info->enc_id, 0);
- /* power up the sink */
- dp_set_power(radeon_connector, DP_SET_POWER_D0);
- /* disable the training pattern on the sink */
- dp_set_training(radeon_connector, DP_TRAINING_PATTERN_DISABLE);
- /* set link bw and lanes on the sink */
- dp_set_link_bw_lanes(radeon_connector, link_configuration);
- /* disable downspread on the sink */
- dp_set_downspread(radeon_connector, 0);
- if (ASIC_IS_DCE4(rdev)) {
- /* start training on the source */
- atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_LINK_TRAINING_START);
- /* set training pattern 1 on the source */
- atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1);
- } else {
- /* start training on the source */
- radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_START,
- dig_connector->dp_clock, enc_id, 0);
- /* set training pattern 1 on the source */
- radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_PATTERN_SEL,
- dig_connector->dp_clock, enc_id, 0);
- }
+ return 0;
+}
- /* set initial vs/emph */
- memset(train_set, 0, 4);
- udelay(400);
- /* set training pattern 1 on the sink */
- dp_set_training(radeon_connector, DP_TRAINING_PATTERN_1);
+static int radeon_dp_link_train_cr(struct radeon_dp_link_train_info *dp_info)
+{
+ bool clock_recovery;
+ u8 voltage;
+ int i;
- dp_update_dpvs_emph(radeon_connector, encoder, train_set);
+ radeon_dp_set_tp(dp_info, DP_TRAINING_PATTERN_1);
+ memset(dp_info->train_set, 0, 4);
+ radeon_dp_update_vs_emph(dp_info);
+
+ udelay(400);
/* clock recovery loop */
clock_recovery = false;
- tries = 0;
+ dp_info->tries = 0;
voltage = 0xff;
- for (;;) {
- udelay(100);
- if (!atom_dp_get_link_status(radeon_connector, link_status))
+ while (1) {
+ if (dp_info->rd_interval == 0)
+ udelay(100);
+ else
+ mdelay(dp_info->rd_interval * 4);
+
+ if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status))
break;
- if (dp_clock_recovery_ok(link_status, dig_connector->dp_lane_count)) {
+ if (dp_clock_recovery_ok(dp_info->link_status, dp_info->dp_lane_count)) {
clock_recovery = true;
break;
}
- for (i = 0; i < dig_connector->dp_lane_count; i++) {
- if ((train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
+ for (i = 0; i < dp_info->dp_lane_count; i++) {
+ if ((dp_info->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
break;
}
- if (i == dig_connector->dp_lane_count) {
+ if (i == dp_info->dp_lane_count) {
DRM_ERROR("clock recovery reached max voltage\n");
break;
}
- if ((train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
- ++tries;
- if (tries == 5) {
+ if ((dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
+ ++dp_info->tries;
+ if (dp_info->tries == 5) {
DRM_ERROR("clock recovery tried 5 times\n");
break;
}
} else
- tries = 0;
+ dp_info->tries = 0;
- voltage = train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
+ voltage = dp_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
/* Compute new train_set as requested by sink */
- dp_get_adjust_train(link_status, dig_connector->dp_lane_count, train_set);
- dp_update_dpvs_emph(radeon_connector, encoder, train_set);
+ dp_get_adjust_train(dp_info->link_status, dp_info->dp_lane_count, dp_info->train_set);
+
+ radeon_dp_update_vs_emph(dp_info);
}
- if (!clock_recovery)
+ if (!clock_recovery) {
DRM_ERROR("clock recovery failed\n");
- else
+ return -1;
+ } else {
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_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
+ (dp_info->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK) >>
DP_TRAIN_PRE_EMPHASIS_SHIFT);
+ return 0;
+ }
+}
+static int radeon_dp_link_train_ce(struct radeon_dp_link_train_info *dp_info)
+{
+ bool channel_eq;
- /* set training pattern 2 on the sink */
- dp_set_training(radeon_connector, DP_TRAINING_PATTERN_2);
- /* set training pattern 2 on the source */
- if (ASIC_IS_DCE4(rdev))
- atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2);
+ if (dp_info->tp3_supported)
+ radeon_dp_set_tp(dp_info, DP_TRAINING_PATTERN_3);
else
- radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_PATTERN_SEL,
- dig_connector->dp_clock, enc_id, 1);
+ radeon_dp_set_tp(dp_info, DP_TRAINING_PATTERN_2);
/* channel equalization loop */
- tries = 0;
+ dp_info->tries = 0;
channel_eq = false;
- for (;;) {
- udelay(400);
- if (!atom_dp_get_link_status(radeon_connector, link_status))
+ while (1) {
+ if (dp_info->rd_interval == 0)
+ udelay(400);
+ else
+ mdelay(dp_info->rd_interval * 4);
+
+ if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status))
break;
- if (dp_channel_eq_ok(link_status, dig_connector->dp_lane_count)) {
+ if (dp_channel_eq_ok(dp_info->link_status, dp_info->dp_lane_count)) {
channel_eq = true;
break;
}
/* Try 5 times */
- if (tries > 5) {
+ if (dp_info->tries > 5) {
DRM_ERROR("channel eq failed: 5 tries\n");
break;
}
/* Compute new train_set as requested by sink */
- dp_get_adjust_train(link_status, dig_connector->dp_lane_count, train_set);
- dp_update_dpvs_emph(radeon_connector, encoder, train_set);
+ dp_get_adjust_train(dp_info->link_status, dp_info->dp_lane_count, dp_info->train_set);
- tries++;
+ radeon_dp_update_vs_emph(dp_info);
+ dp_info->tries++;
}
- if (!channel_eq)
+ if (!channel_eq) {
DRM_ERROR("channel eq failed\n");
- else
+ return -1;
+ } else {
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_info->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK,
+ (dp_info->train_set[0] & DP_TRAIN_PRE_EMPHASIS_MASK)
>> DP_TRAIN_PRE_EMPHASIS_SHIFT);
-
- /* disable the training pattern on the sink */
- dp_set_training(radeon_connector, DP_TRAINING_PATTERN_DISABLE);
-
- /* disable the training pattern on the source */
- if (ASIC_IS_DCE4(rdev))
- atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE);
- else
- radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_TRAINING_COMPLETE,
- dig_connector->dp_clock, enc_id, 0);
+ return 0;
+ }
}
-int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
- uint8_t write_byte, uint8_t *read_byte)
+void radeon_dp_link_train(struct drm_encoder *encoder,
+ struct drm_connector *connector)
{
- struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
- struct radeon_i2c_chan *auxch = (struct radeon_i2c_chan *)adapter;
- int ret = 0;
- uint16_t address = algo_data->address;
- uint8_t msg[5];
- uint8_t reply[2];
- int msg_len, dp_msg_len;
- int reply_bytes;
-
- /* Set up the command byte */
- if (mode & MODE_I2C_READ)
- msg[2] = AUX_I2C_READ << 4;
- else
- msg[2] = AUX_I2C_WRITE << 4;
-
- if (!(mode & MODE_I2C_STOP))
- msg[2] |= AUX_I2C_MOT << 4;
+ struct drm_device *dev = encoder->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig;
+ struct radeon_connector *radeon_connector;
+ struct radeon_connector_atom_dig *dig_connector;
+ struct radeon_dp_link_train_info dp_info;
+ u8 tmp;
- msg[0] = address;
- msg[1] = address >> 8;
+ if (!radeon_encoder->enc_priv)
+ return;
+ dig = radeon_encoder->enc_priv;
- reply_bytes = 1;
+ radeon_connector = to_radeon_connector(connector);
+ if (!radeon_connector->con_priv)
+ return;
+ dig_connector = radeon_connector->con_priv;
- msg_len = 4;
- dp_msg_len = 3;
- switch (mode) {
- case MODE_I2C_WRITE:
- msg[4] = write_byte;
- msg_len++;
- dp_msg_len += 2;
- break;
- case MODE_I2C_READ:
- dp_msg_len += 1;
- break;
- default:
- break;
- }
+ if ((dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_DISPLAYPORT) &&
+ (dig_connector->dp_sink_type != CONNECTOR_OBJECT_ID_eDP))
+ return;
- msg[3] = (dp_msg_len) << 4;
- ret = radeon_process_aux_ch(auxch, msg, msg_len, reply, reply_bytes, 0);
+ dp_info.enc_id = 0;
+ if (dig->dig_encoder)
+ dp_info.enc_id |= ATOM_DP_CONFIG_DIG2_ENCODER;
+ else
+ dp_info.enc_id |= ATOM_DP_CONFIG_DIG1_ENCODER;
+ if (dig->linkb)
+ dp_info.enc_id |= ATOM_DP_CONFIG_LINK_B;
+ else
+ dp_info.enc_id |= ATOM_DP_CONFIG_LINK_A;
- if (ret) {
- if (read_byte)
- *read_byte = reply[0];
- return reply_bytes;
- }
- return -EREMOTEIO;
+ dp_info.rd_interval = radeon_read_dpcd_reg(radeon_connector, DP_TRAINING_AUX_RD_INTERVAL);
+ tmp = radeon_read_dpcd_reg(radeon_connector, DP_MAX_LANE_COUNT);
+ if (ASIC_IS_DCE5(rdev) && (tmp & DP_TPS3_SUPPORTED))
+ dp_info.tp3_supported = true;
+ else
+ dp_info.tp3_supported = false;
+
+ memcpy(dp_info.dpcd, dig_connector->dpcd, 8);
+ dp_info.rdev = rdev;
+ dp_info.encoder = encoder;
+ dp_info.connector = connector;
+ dp_info.radeon_connector = radeon_connector;
+ dp_info.dp_lane_count = dig_connector->dp_lane_count;
+ dp_info.dp_clock = dig_connector->dp_clock;
+
+ if (radeon_dp_link_train_init(&dp_info))
+ goto done;
+ if (radeon_dp_link_train_cr(&dp_info))
+ goto done;
+ if (radeon_dp_link_train_ce(&dp_info))
+ goto done;
+done:
+ if (radeon_dp_link_train_finish(&dp_info))
+ return;
}
-
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 9073e3bfb08c..7c37638095f7 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -1578,7 +1578,7 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
u32 sq_stack_resource_mgmt_2;
u32 sq_stack_resource_mgmt_3;
u32 vgt_cache_invalidation;
- u32 hdp_host_path_cntl;
+ u32 hdp_host_path_cntl, tmp;
int i, j, num_shader_engines, ps_thread_count;
switch (rdev->family) {
@@ -1936,8 +1936,12 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
rdev->config.evergreen.tile_config |= (3 << 0);
break;
}
- rdev->config.evergreen.tile_config |=
- ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4;
+ /* num banks is 8 on all fusion asics */
+ if (rdev->flags & RADEON_IS_IGP)
+ rdev->config.evergreen.tile_config |= 8 << 4;
+ else
+ rdev->config.evergreen.tile_config |=
+ ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4;
rdev->config.evergreen.tile_config |=
((mc_arb_ramcfg & BURSTLENGTH_MASK) >> BURSTLENGTH_SHIFT) << 8;
rdev->config.evergreen.tile_config |=
@@ -2141,6 +2145,10 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
for (i = SQ_ALU_CONST_BUFFER_SIZE_HS_0; i < 0x29000; i += 4)
WREG32(i, 0);
+ tmp = RREG32(HDP_MISC_CNTL);
+ tmp |= HDP_FLUSH_INVALIDATE_CACHE;
+ WREG32(HDP_MISC_CNTL, tmp);
+
hdp_host_path_cntl = RREG32(HDP_HOST_PATH_CNTL);
WREG32(HDP_HOST_PATH_CNTL, hdp_host_path_cntl);
diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h
index fc40e0cc3451..f37e91ee8a11 100644
--- a/drivers/gpu/drm/radeon/evergreend.h
+++ b/drivers/gpu/drm/radeon/evergreend.h
@@ -64,6 +64,8 @@
#define GB_BACKEND_MAP 0x98FC
#define DMIF_ADDR_CONFIG 0xBD4
#define HDP_ADDR_CONFIG 0x2F48
+#define HDP_MISC_CNTL 0x2F4C
+#define HDP_FLUSH_INVALIDATE_CACHE (1 << 0)
#define CC_SYS_RB_BACKEND_DISABLE 0x3F88
#define GC_USER_RB_BACKEND_DISABLE 0x9B7C
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index 3d8a7634bbe9..b205ba1cdd8f 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -417,7 +417,7 @@ static u32 cayman_get_tile_pipe_to_backend_map(struct radeon_device *rdev,
num_shader_engines = 1;
if (num_shader_engines > rdev->config.cayman.max_shader_engines)
num_shader_engines = rdev->config.cayman.max_shader_engines;
- if (num_backends_per_asic > num_shader_engines)
+ if (num_backends_per_asic < num_shader_engines)
num_backends_per_asic = num_shader_engines;
if (num_backends_per_asic > (rdev->config.cayman.max_backends_per_se * num_shader_engines))
num_backends_per_asic = rdev->config.cayman.max_backends_per_se * num_shader_engines;
@@ -829,7 +829,7 @@ static void cayman_gpu_init(struct radeon_device *rdev)
rdev->config.cayman.tile_config |=
((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) << 4;
rdev->config.cayman.tile_config |=
- (gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT;
+ ((gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT) << 8;
rdev->config.cayman.tile_config |=
((gb_addr_config & ROW_SIZE_MASK) >> ROW_SIZE_SHIFT) << 12;
@@ -931,6 +931,10 @@ static void cayman_gpu_init(struct radeon_device *rdev)
WREG32(CB_PERF_CTR3_SEL_0, 0);
WREG32(CB_PERF_CTR3_SEL_1, 0);
+ tmp = RREG32(HDP_MISC_CNTL);
+ tmp |= HDP_FLUSH_INVALIDATE_CACHE;
+ WREG32(HDP_MISC_CNTL, tmp);
+
hdp_host_path_cntl = RREG32(HDP_HOST_PATH_CNTL);
WREG32(HDP_HOST_PATH_CNTL, hdp_host_path_cntl);
diff --git a/drivers/gpu/drm/radeon/nid.h b/drivers/gpu/drm/radeon/nid.h
index 0f9a08b53fbd..9736746da2d6 100644
--- a/drivers/gpu/drm/radeon/nid.h
+++ b/drivers/gpu/drm/radeon/nid.h
@@ -136,6 +136,8 @@
#define HDP_NONSURFACE_INFO 0x2C08
#define HDP_NONSURFACE_SIZE 0x2C0C
#define HDP_ADDR_CONFIG 0x2F48
+#define HDP_MISC_CNTL 0x2F4C
+#define HDP_FLUSH_INVALIDATE_CACHE (1 << 0)
#define CC_SYS_RB_BACKEND_DISABLE 0x3F88
#define GC_USER_SYS_RB_BACKEND_DISABLE 0x3F8C
@@ -351,7 +353,7 @@
#define MULTI_GPU_TILE_SIZE_MASK 0x03000000
#define MULTI_GPU_TILE_SIZE_SHIFT 24
#define ROW_SIZE(x) ((x) << 28)
-#define ROW_SIZE_MASK 0x30000007
+#define ROW_SIZE_MASK 0x30000000
#define ROW_SIZE_SHIFT 28
#define NUM_LOWER_PIPES(x) ((x) << 30)
#define NUM_LOWER_PIPES_MASK 0x40000000
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index ca576191d058..d948265db87e 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -782,6 +782,7 @@ static struct radeon_asic evergreen_asic = {
.hpd_fini = &evergreen_hpd_fini,
.hpd_sense = &evergreen_hpd_sense,
.hpd_set_polarity = &evergreen_hpd_set_polarity,
+ .ioctl_wait_idle = r600_ioctl_wait_idle,
.gui_idle = &r600_gui_idle,
.pm_misc = &evergreen_pm_misc,
.pm_prepare = &evergreen_pm_prepare,
@@ -828,6 +829,7 @@ static struct radeon_asic sumo_asic = {
.hpd_fini = &evergreen_hpd_fini,
.hpd_sense = &evergreen_hpd_sense,
.hpd_set_polarity = &evergreen_hpd_set_polarity,
+ .ioctl_wait_idle = r600_ioctl_wait_idle,
.gui_idle = &r600_gui_idle,
.pm_misc = &evergreen_pm_misc,
.pm_prepare = &evergreen_pm_prepare,
@@ -874,6 +876,7 @@ static struct radeon_asic btc_asic = {
.hpd_fini = &evergreen_hpd_fini,
.hpd_sense = &evergreen_hpd_sense,
.hpd_set_polarity = &evergreen_hpd_set_polarity,
+ .ioctl_wait_idle = r600_ioctl_wait_idle,
.gui_idle = &r600_gui_idle,
.pm_misc = &evergreen_pm_misc,
.pm_prepare = &evergreen_pm_prepare,
@@ -920,6 +923,7 @@ static struct radeon_asic cayman_asic = {
.hpd_fini = &evergreen_hpd_fini,
.hpd_sense = &evergreen_hpd_sense,
.hpd_set_polarity = &evergreen_hpd_set_polarity,
+ .ioctl_wait_idle = r600_ioctl_wait_idle,
.gui_idle = &r600_gui_idle,
.pm_misc = &evergreen_pm_misc,
.pm_prepare = &evergreen_pm_prepare,
diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c
index 8caf546c8e92..5b991f7c6e2a 100644
--- a/drivers/gpu/drm/radeon/radeon_combios.c
+++ b/drivers/gpu/drm/radeon/radeon_combios.c
@@ -505,12 +505,18 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
* DDC_VGA = RADEON_GPIO_VGA_DDC
* DDC_LCD = RADEON_GPIOPAD_MASK
* DDC_GPIO = RADEON_MDGPIO_MASK
- * r1xx/r2xx
+ * r1xx
* DDC_MONID = RADEON_GPIO_MONID
* DDC_CRT2 = RADEON_GPIO_CRT2_DDC
- * r3xx
+ * r200
* DDC_MONID = RADEON_GPIO_MONID
* DDC_CRT2 = RADEON_GPIO_DVI_DDC
+ * r300/r350
+ * DDC_MONID = RADEON_GPIO_DVI_DDC
+ * DDC_CRT2 = RADEON_GPIO_DVI_DDC
+ * rv2xx/rv3xx
+ * DDC_MONID = RADEON_GPIO_MONID
+ * DDC_CRT2 = RADEON_GPIO_MONID
* rs3xx/rs4xx
* DDC_MONID = RADEON_GPIOPAD_MASK
* DDC_CRT2 = RADEON_GPIO_MONID
@@ -537,17 +543,26 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
rdev->family == CHIP_RS400 ||
rdev->family == CHIP_RS480)
ddc_line = RADEON_GPIOPAD_MASK;
- else
+ else if (rdev->family == CHIP_R300 ||
+ rdev->family == CHIP_R350) {
+ ddc_line = RADEON_GPIO_DVI_DDC;
+ ddc = DDC_DVI;
+ } else
ddc_line = RADEON_GPIO_MONID;
break;
case DDC_CRT2:
- if (rdev->family == CHIP_RS300 ||
- rdev->family == CHIP_RS400 ||
- rdev->family == CHIP_RS480)
- ddc_line = RADEON_GPIO_MONID;
- else if (rdev->family >= CHIP_R300) {
+ if (rdev->family == CHIP_R200 ||
+ rdev->family == CHIP_R300 ||
+ rdev->family == CHIP_R350) {
ddc_line = RADEON_GPIO_DVI_DDC;
ddc = DDC_DVI;
+ } else if (rdev->family == CHIP_RS300 ||
+ rdev->family == CHIP_RS400 ||
+ rdev->family == CHIP_RS480)
+ ddc_line = RADEON_GPIO_MONID;
+ else if (rdev->family >= CHIP_RV350) {
+ ddc_line = RADEON_GPIO_MONID;
+ ddc = DDC_MONID;
} else
ddc_line = RADEON_GPIO_CRT2_DDC;
break;
@@ -709,26 +724,42 @@ void radeon_combios_i2c_init(struct radeon_device *rdev)
struct drm_device *dev = rdev->ddev;
struct radeon_i2c_bus_rec i2c;
+ /* actual hw pads
+ * r1xx/rs2xx/rs3xx
+ * 0x60, 0x64, 0x68, 0x6c, gpiopads, mm
+ * r200
+ * 0x60, 0x64, 0x68, mm
+ * r300/r350
+ * 0x60, 0x64, mm
+ * rv2xx/rv3xx/rs4xx
+ * 0x60, 0x64, 0x68, gpiopads, mm
+ */
+ /* 0x60 */
i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
rdev->i2c_bus[0] = radeon_i2c_create(dev, &i2c, "DVI_DDC");
-
+ /* 0x64 */
i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
rdev->i2c_bus[1] = radeon_i2c_create(dev, &i2c, "VGA_DDC");
+ /* mm i2c */
i2c.valid = true;
i2c.hw_capable = true;
i2c.mm_i2c = true;
i2c.i2c_id = 0xa0;
rdev->i2c_bus[2] = radeon_i2c_create(dev, &i2c, "MM_I2C");
- if (rdev->family == CHIP_RS300 ||
- rdev->family == CHIP_RS400 ||
- rdev->family == CHIP_RS480) {
+ if (rdev->family == CHIP_R300 ||
+ rdev->family == CHIP_R350) {
+ /* only 2 sw i2c pads */
+ } else if (rdev->family == CHIP_RS300 ||
+ rdev->family == CHIP_RS400 ||
+ rdev->family == CHIP_RS480) {
u16 offset;
u8 id, blocks, clk, data;
int i;
+ /* 0x68 */
i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0);
rdev->i2c_bus[3] = radeon_i2c_create(dev, &i2c, "MONID");
@@ -740,6 +771,7 @@ void radeon_combios_i2c_init(struct radeon_device *rdev)
if (id == 136) {
clk = RBIOS8(offset + 3 + (i * 5) + 3);
data = RBIOS8(offset + 3 + (i * 5) + 4);
+ /* gpiopad */
i2c = combios_setup_i2c_bus(rdev, DDC_MONID,
(1 << clk), (1 << data));
rdev->i2c_bus[4] = radeon_i2c_create(dev, &i2c, "GPIOPAD_MASK");
@@ -747,14 +779,15 @@ void radeon_combios_i2c_init(struct radeon_device *rdev)
}
}
}
-
- } else if (rdev->family >= CHIP_R300) {
+ } else if (rdev->family >= CHIP_R200) {
+ /* 0x68 */
i2c = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0);
rdev->i2c_bus[3] = radeon_i2c_create(dev, &i2c, "MONID");
} else {
+ /* 0x68 */
i2c = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0);
rdev->i2c_bus[3] = radeon_i2c_create(dev, &i2c, "MONID");
-
+ /* 0x6c */
i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0);
rdev->i2c_bus[4] = radeon_i2c_create(dev, &i2c, "CRT2_DDC");
}
@@ -2504,6 +2537,12 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
return true;
}
+static const char *thermal_controller_names[] = {
+ "NONE",
+ "lm63",
+ "adm1032",
+};
+
void radeon_combios_get_power_modes(struct radeon_device *rdev)
{
struct drm_device *dev = rdev->ddev;
@@ -2524,6 +2563,54 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev)
return;
}
+ /* check for a thermal chip */
+ offset = combios_get_table_offset(dev, COMBIOS_OVERDRIVE_INFO_TABLE);
+ if (offset) {
+ u8 thermal_controller = 0, gpio = 0, i2c_addr = 0, clk_bit = 0, data_bit = 0;
+ struct radeon_i2c_bus_rec i2c_bus;
+
+ rev = RBIOS8(offset);
+
+ if (rev == 0) {
+ thermal_controller = RBIOS8(offset + 3);
+ gpio = RBIOS8(offset + 4) & 0x3f;
+ i2c_addr = RBIOS8(offset + 5);
+ } else if (rev == 1) {
+ thermal_controller = RBIOS8(offset + 4);
+ gpio = RBIOS8(offset + 5) & 0x3f;
+ i2c_addr = RBIOS8(offset + 6);
+ } else if (rev == 2) {
+ thermal_controller = RBIOS8(offset + 4);
+ gpio = RBIOS8(offset + 5) & 0x3f;
+ i2c_addr = RBIOS8(offset + 6);
+ clk_bit = RBIOS8(offset + 0xa);
+ data_bit = RBIOS8(offset + 0xb);
+ }
+ if ((thermal_controller > 0) && (thermal_controller < 3)) {
+ DRM_INFO("Possible %s thermal controller at 0x%02x\n",
+ thermal_controller_names[thermal_controller],
+ i2c_addr >> 1);
+ if (gpio == DDC_LCD) {
+ /* MM i2c */
+ i2c_bus.valid = true;
+ i2c_bus.hw_capable = true;
+ i2c_bus.mm_i2c = true;
+ i2c_bus.i2c_id = 0xa0;
+ } else if (gpio == DDC_GPIO)
+ i2c_bus = combios_setup_i2c_bus(rdev, gpio, 1 << clk_bit, 1 << data_bit);
+ else
+ i2c_bus = combios_setup_i2c_bus(rdev, gpio, 0, 0);
+ rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
+ if (rdev->pm.i2c_bus) {
+ struct i2c_board_info info = { };
+ const char *name = thermal_controller_names[thermal_controller];
+ info.addr = i2c_addr >> 1;
+ strlcpy(info.type, name, sizeof(info.type));
+ i2c_new_device(&rdev->pm.i2c_bus->adapter, &info);
+ }
+ }
+ }
+
if (rdev->flags & RADEON_IS_MOBILITY) {
offset = combios_get_table_offset(dev, COMBIOS_POWERPLAY_INFO_TABLE);
if (offset) {
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 5f45fa12bb8b..ee1dccb3fec9 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -50,20 +50,21 @@ void radeon_connector_hotplug(struct drm_connector *connector)
struct radeon_device *rdev = dev->dev_private;
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
- if (radeon_connector->hpd.hpd != RADEON_HPD_NONE)
- radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
-
- if ((connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
- (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) {
- if ((radeon_dp_getsinktype(radeon_connector) == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
- (radeon_dp_getsinktype(radeon_connector) == CONNECTOR_OBJECT_ID_eDP)) {
- if (radeon_dp_needs_link_train(radeon_connector)) {
- if (connector->encoder)
- dp_link_train(connector->encoder, connector);
- }
- }
- }
+ radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd);
+
+ /* powering up/down the eDP panel generates hpd events which
+ * can interfere with modesetting.
+ */
+ if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
+ return;
+ /* pre-r600 did not always have the hpd pins mapped accurately to connectors */
+ if (rdev->family >= CHIP_R600) {
+ if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd))
+ drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
+ else
+ drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+ }
}
static void radeon_property_change_mode(struct drm_encoder *encoder)
@@ -1054,23 +1055,124 @@ static int radeon_dp_get_modes(struct drm_connector *connector)
int ret;
if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+ struct drm_encoder *encoder;
+ struct drm_display_mode *mode;
+
if (!radeon_dig_connector->edp_on)
atombios_set_edp_panel_power(connector,
ATOM_TRANSMITTER_ACTION_POWER_ON);
- }
- ret = radeon_ddc_get_modes(radeon_connector);
- if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+ ret = radeon_ddc_get_modes(radeon_connector);
if (!radeon_dig_connector->edp_on)
atombios_set_edp_panel_power(connector,
ATOM_TRANSMITTER_ACTION_POWER_OFF);
- }
+
+ if (ret > 0) {
+ encoder = radeon_best_single_encoder(connector);
+ if (encoder) {
+ radeon_fixup_lvds_native_mode(encoder, connector);
+ /* add scaled modes */
+ radeon_add_common_modes(encoder, connector);
+ }
+ return ret;
+ }
+
+ encoder = radeon_best_single_encoder(connector);
+ if (!encoder)
+ return 0;
+
+ /* we have no EDID modes */
+ mode = radeon_fp_native_mode(encoder);
+ if (mode) {
+ ret = 1;
+ drm_mode_probed_add(connector, mode);
+ /* add the width/height from vbios tables if available */
+ connector->display_info.width_mm = mode->width_mm;
+ connector->display_info.height_mm = mode->height_mm;
+ /* add scaled modes */
+ radeon_add_common_modes(encoder, connector);
+ }
+ } else
+ ret = radeon_ddc_get_modes(radeon_connector);
return ret;
}
+bool radeon_connector_encoder_is_dp_bridge(struct drm_connector *connector)
+{
+ struct drm_mode_object *obj;
+ struct drm_encoder *encoder;
+ struct radeon_encoder *radeon_encoder;
+ int i;
+ bool found = false;
+
+ for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+ if (connector->encoder_ids[i] == 0)
+ break;
+
+ obj = drm_mode_object_find(connector->dev, connector->encoder_ids[i], DRM_MODE_OBJECT_ENCODER);
+ if (!obj)
+ continue;
+
+ encoder = obj_to_encoder(obj);
+ radeon_encoder = to_radeon_encoder(encoder);
+
+ switch (radeon_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_TRAVIS:
+ case ENCODER_OBJECT_ID_NUTMEG:
+ found = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return found;
+}
+
+bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector)
+{
+ struct drm_mode_object *obj;
+ struct drm_encoder *encoder;
+ struct radeon_encoder *radeon_encoder;
+ int i;
+ bool found = false;
+
+ for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
+ if (connector->encoder_ids[i] == 0)
+ break;
+
+ obj = drm_mode_object_find(connector->dev, connector->encoder_ids[i], DRM_MODE_OBJECT_ENCODER);
+ if (!obj)
+ continue;
+
+ encoder = obj_to_encoder(obj);
+ radeon_encoder = to_radeon_encoder(encoder);
+ if (radeon_encoder->caps & ATOM_ENCODER_CAP_RECORD_HBR2)
+ found = true;
+ }
+
+ return found;
+}
+
+bool radeon_connector_is_dp12_capable(struct drm_connector *connector)
+{
+ struct drm_device *dev = connector->dev;
+ struct radeon_device *rdev = dev->dev_private;
+
+ if (ASIC_IS_DCE5(rdev) &&
+ (rdev->clock.dp_extclk >= 53900) &&
+ radeon_connector_encoder_is_hbr2(connector)) {
+ return true;
+ }
+
+ return false;
+}
+
static enum drm_connector_status
radeon_dp_detect(struct drm_connector *connector, bool force)
{
+ struct drm_device *dev = connector->dev;
+ struct radeon_device *rdev = dev->dev_private;
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
enum drm_connector_status ret = connector_status_disconnected;
struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
@@ -1081,6 +1183,15 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
}
if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+ struct drm_encoder *encoder = radeon_best_single_encoder(connector);
+ if (encoder) {
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
+
+ /* check if panel is valid */
+ if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240)
+ ret = connector_status_connected;
+ }
/* eDP is always DP */
radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
if (!radeon_dig_connector->edp_on)
@@ -1093,12 +1204,18 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
ATOM_TRANSMITTER_ACTION_POWER_OFF);
} else {
radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector);
- if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
- if (radeon_dp_getdpcd(radeon_connector))
- ret = connector_status_connected;
+ if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
+ ret = connector_status_connected;
+ if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT)
+ radeon_dp_getdpcd(radeon_connector);
} else {
- if (radeon_ddc_probe(radeon_connector))
- ret = connector_status_connected;
+ if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
+ if (radeon_dp_getdpcd(radeon_connector))
+ ret = connector_status_connected;
+ } else {
+ if (radeon_ddc_probe(radeon_connector))
+ ret = connector_status_connected;
+ }
}
}
@@ -1114,11 +1231,38 @@ static int radeon_dp_mode_valid(struct drm_connector *connector,
/* XXX check mode bandwidth */
- if ((radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
- (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))
- return radeon_dp_mode_valid_helper(radeon_connector, mode);
- else
+ if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+ struct drm_encoder *encoder = radeon_best_single_encoder(connector);
+
+ if ((mode->hdisplay < 320) || (mode->vdisplay < 240))
+ return MODE_PANEL;
+
+ if (encoder) {
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct drm_display_mode *native_mode = &radeon_encoder->native_mode;
+
+ /* AVIVO hardware supports downscaling modes larger than the panel
+ * to the panel size, but I'm not sure this is desirable.
+ */
+ if ((mode->hdisplay > native_mode->hdisplay) ||
+ (mode->vdisplay > native_mode->vdisplay))
+ return MODE_PANEL;
+
+ /* if scaling is disabled, block non-native modes */
+ if (radeon_encoder->rmx_type == RMX_OFF) {
+ if ((mode->hdisplay != native_mode->hdisplay) ||
+ (mode->vdisplay != native_mode->vdisplay))
+ return MODE_PANEL;
+ }
+ }
return MODE_OK;
+ } else {
+ if ((radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
+ (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))
+ return radeon_dp_mode_valid_helper(connector, mode);
+ else
+ return MODE_OK;
+ }
}
struct drm_connector_helper_funcs radeon_dp_connector_helper_funcs = {
@@ -1151,8 +1295,11 @@ radeon_add_atom_connector(struct drm_device *dev,
struct drm_connector *connector;
struct radeon_connector *radeon_connector;
struct radeon_connector_atom_dig *radeon_dig_connector;
+ struct drm_encoder *encoder;
+ struct radeon_encoder *radeon_encoder;
uint32_t subpixel_order = SubPixelNone;
bool shared_ddc = false;
+ bool is_dp_bridge = false;
if (connector_type == DRM_MODE_CONNECTOR_Unknown)
return;
@@ -1184,6 +1331,21 @@ radeon_add_atom_connector(struct drm_device *dev,
}
}
+ /* check if it's a dp bridge */
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+ radeon_encoder = to_radeon_encoder(encoder);
+ if (radeon_encoder->devices & supported_device) {
+ switch (radeon_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_TRAVIS:
+ case ENCODER_OBJECT_ID_NUTMEG:
+ is_dp_bridge = true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
radeon_connector = kzalloc(sizeof(struct radeon_connector), GFP_KERNEL);
if (!radeon_connector)
return;
@@ -1201,61 +1363,39 @@ radeon_add_atom_connector(struct drm_device *dev,
if (!radeon_connector->router_bus)
DRM_ERROR("Failed to assign router i2c bus! Check dmesg for i2c errors.\n");
}
- switch (connector_type) {
- case DRM_MODE_CONNECTOR_VGA:
- drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
- drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
- if (i2c_bus->valid) {
- radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
- if (!radeon_connector->ddc_bus)
- DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
- }
- radeon_connector->dac_load_detect = true;
- 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;
- connector->interlace_allowed = true;
- connector->doublescan_allowed = true;
- break;
- case DRM_MODE_CONNECTOR_DVIA:
- drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
- drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
- if (i2c_bus->valid) {
- radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
- if (!radeon_connector->ddc_bus)
- DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
- }
- radeon_connector->dac_load_detect = true;
- 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->interlace_allowed = true;
- connector->doublescan_allowed = true;
- break;
- case DRM_MODE_CONNECTOR_DVII:
- case DRM_MODE_CONNECTOR_DVID:
+
+ if (is_dp_bridge) {
radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
if (!radeon_dig_connector)
goto failed;
radeon_dig_connector->igp_lane_info = igp_lane_info;
radeon_connector->con_priv = radeon_dig_connector;
- drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
- drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
+ drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);
+ drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
if (i2c_bus->valid) {
+ /* add DP i2c bus */
+ if (connector_type == DRM_MODE_CONNECTOR_eDP)
+ radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch");
+ else
+ radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch");
+ if (!radeon_dig_connector->dp_i2c_bus)
+ DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");
radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
if (!radeon_connector->ddc_bus)
- DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+ DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
}
- subpixel_order = SubPixelHorizontalRGB;
- drm_connector_attach_property(&radeon_connector->base,
- rdev->mode_info.coherent_mode_property,
- 1);
- if (ASIC_IS_AVIVO(rdev)) {
+ switch (connector_type) {
+ case DRM_MODE_CONNECTOR_VGA:
+ case DRM_MODE_CONNECTOR_DVIA:
+ default:
+ connector->interlace_allowed = true;
+ connector->doublescan_allowed = true;
+ break;
+ case DRM_MODE_CONNECTOR_DVII:
+ case DRM_MODE_CONNECTOR_DVID:
+ case DRM_MODE_CONNECTOR_HDMIA:
+ case DRM_MODE_CONNECTOR_HDMIB:
+ case DRM_MODE_CONNECTOR_DisplayPort:
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.underscan_property,
UNDERSCAN_OFF);
@@ -1265,131 +1405,234 @@ radeon_add_atom_connector(struct drm_device *dev,
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.underscan_vborder_property,
0);
+ subpixel_order = SubPixelHorizontalRGB;
+ connector->interlace_allowed = true;
+ if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
+ connector->doublescan_allowed = true;
+ else
+ connector->doublescan_allowed = false;
+ break;
+ case DRM_MODE_CONNECTOR_LVDS:
+ case DRM_MODE_CONNECTOR_eDP:
+ drm_connector_attach_property(&radeon_connector->base,
+ dev->mode_config.scaling_mode_property,
+ DRM_MODE_SCALE_FULLSCREEN);
+ subpixel_order = SubPixelHorizontalRGB;
+ connector->interlace_allowed = false;
+ connector->doublescan_allowed = false;
+ break;
}
- if (connector_type == DRM_MODE_CONNECTOR_DVII) {
+ } else {
+ switch (connector_type) {
+ case DRM_MODE_CONNECTOR_VGA:
+ drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
+ drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
+ if (i2c_bus->valid) {
+ radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
+ if (!radeon_connector->ddc_bus)
+ DRM_ERROR("VGA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+ }
radeon_connector->dac_load_detect = true;
drm_connector_attach_property(&radeon_connector->base,
rdev->mode_info.load_detect_property,
1);
- }
- connector->interlace_allowed = true;
- if (connector_type == DRM_MODE_CONNECTOR_DVII)
+ /* no HPD on analog connectors */
+ radeon_connector->hpd.hpd = RADEON_HPD_NONE;
+ connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+ connector->interlace_allowed = true;
connector->doublescan_allowed = true;
- else
- connector->doublescan_allowed = false;
- break;
- case DRM_MODE_CONNECTOR_HDMIA:
- case DRM_MODE_CONNECTOR_HDMIB:
- radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
- if (!radeon_dig_connector)
- goto failed;
- radeon_dig_connector->igp_lane_info = igp_lane_info;
- radeon_connector->con_priv = radeon_dig_connector;
- drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
- drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
- if (i2c_bus->valid) {
- radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
- if (!radeon_connector->ddc_bus)
- DRM_ERROR("HDMI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
- }
- drm_connector_attach_property(&radeon_connector->base,
- rdev->mode_info.coherent_mode_property,
- 1);
- if (ASIC_IS_AVIVO(rdev)) {
+ break;
+ case DRM_MODE_CONNECTOR_DVIA:
+ drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
+ drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
+ if (i2c_bus->valid) {
+ radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
+ if (!radeon_connector->ddc_bus)
+ DRM_ERROR("DVIA: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+ }
+ radeon_connector->dac_load_detect = true;
drm_connector_attach_property(&radeon_connector->base,
- rdev->mode_info.underscan_property,
- UNDERSCAN_OFF);
+ rdev->mode_info.load_detect_property,
+ 1);
+ /* no HPD on analog connectors */
+ radeon_connector->hpd.hpd = RADEON_HPD_NONE;
+ connector->interlace_allowed = true;
+ connector->doublescan_allowed = true;
+ break;
+ case DRM_MODE_CONNECTOR_DVII:
+ case DRM_MODE_CONNECTOR_DVID:
+ radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
+ if (!radeon_dig_connector)
+ goto failed;
+ radeon_dig_connector->igp_lane_info = igp_lane_info;
+ radeon_connector->con_priv = radeon_dig_connector;
+ drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
+ drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
+ if (i2c_bus->valid) {
+ radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
+ if (!radeon_connector->ddc_bus)
+ DRM_ERROR("DVI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+ }
+ subpixel_order = SubPixelHorizontalRGB;
drm_connector_attach_property(&radeon_connector->base,
- rdev->mode_info.underscan_hborder_property,
- 0);
+ 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_OFF);
+ drm_connector_attach_property(&radeon_connector->base,
+ rdev->mode_info.underscan_hborder_property,
+ 0);
+ drm_connector_attach_property(&radeon_connector->base,
+ rdev->mode_info.underscan_vborder_property,
+ 0);
+ }
+ if (connector_type == DRM_MODE_CONNECTOR_DVII) {
+ radeon_connector->dac_load_detect = true;
+ drm_connector_attach_property(&radeon_connector->base,
+ rdev->mode_info.load_detect_property,
+ 1);
+ }
+ connector->interlace_allowed = true;
+ if (connector_type == DRM_MODE_CONNECTOR_DVII)
+ connector->doublescan_allowed = true;
+ else
+ connector->doublescan_allowed = false;
+ break;
+ case DRM_MODE_CONNECTOR_HDMIA:
+ case DRM_MODE_CONNECTOR_HDMIB:
+ radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
+ if (!radeon_dig_connector)
+ goto failed;
+ radeon_dig_connector->igp_lane_info = igp_lane_info;
+ radeon_connector->con_priv = radeon_dig_connector;
+ drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
+ drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
+ if (i2c_bus->valid) {
+ radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
+ if (!radeon_connector->ddc_bus)
+ DRM_ERROR("HDMI: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+ }
drm_connector_attach_property(&radeon_connector->base,
- rdev->mode_info.underscan_vborder_property,
- 0);
- }
- subpixel_order = SubPixelHorizontalRGB;
- connector->interlace_allowed = true;
- if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
- connector->doublescan_allowed = true;
- else
- connector->doublescan_allowed = false;
- break;
- case DRM_MODE_CONNECTOR_DisplayPort:
- case DRM_MODE_CONNECTOR_eDP:
- radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
- if (!radeon_dig_connector)
- goto failed;
- radeon_dig_connector->igp_lane_info = igp_lane_info;
- radeon_connector->con_priv = radeon_dig_connector;
- drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);
- drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
- if (i2c_bus->valid) {
- /* add DP i2c bus */
- if (connector_type == DRM_MODE_CONNECTOR_eDP)
- radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch");
+ 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_OFF);
+ drm_connector_attach_property(&radeon_connector->base,
+ rdev->mode_info.underscan_hborder_property,
+ 0);
+ drm_connector_attach_property(&radeon_connector->base,
+ rdev->mode_info.underscan_vborder_property,
+ 0);
+ }
+ subpixel_order = SubPixelHorizontalRGB;
+ connector->interlace_allowed = true;
+ if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
+ connector->doublescan_allowed = true;
else
+ connector->doublescan_allowed = false;
+ break;
+ case DRM_MODE_CONNECTOR_DisplayPort:
+ radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
+ if (!radeon_dig_connector)
+ goto failed;
+ radeon_dig_connector->igp_lane_info = igp_lane_info;
+ radeon_connector->con_priv = radeon_dig_connector;
+ drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);
+ drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
+ if (i2c_bus->valid) {
+ /* add DP i2c bus */
radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch");
- if (!radeon_dig_connector->dp_i2c_bus)
- DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");
- radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
- if (!radeon_connector->ddc_bus)
- DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
- }
- subpixel_order = SubPixelHorizontalRGB;
- drm_connector_attach_property(&radeon_connector->base,
- rdev->mode_info.coherent_mode_property,
- 1);
- if (ASIC_IS_AVIVO(rdev)) {
+ if (!radeon_dig_connector->dp_i2c_bus)
+ DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");
+ radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
+ if (!radeon_connector->ddc_bus)
+ DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+ }
+ subpixel_order = SubPixelHorizontalRGB;
drm_connector_attach_property(&radeon_connector->base,
- rdev->mode_info.underscan_property,
- UNDERSCAN_OFF);
+ 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_OFF);
+ drm_connector_attach_property(&radeon_connector->base,
+ rdev->mode_info.underscan_hborder_property,
+ 0);
+ drm_connector_attach_property(&radeon_connector->base,
+ rdev->mode_info.underscan_vborder_property,
+ 0);
+ }
+ connector->interlace_allowed = true;
+ /* in theory with a DP to VGA converter... */
+ connector->doublescan_allowed = false;
+ break;
+ case DRM_MODE_CONNECTOR_eDP:
+ radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
+ if (!radeon_dig_connector)
+ goto failed;
+ radeon_dig_connector->igp_lane_info = igp_lane_info;
+ radeon_connector->con_priv = radeon_dig_connector;
+ drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);
+ drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
+ if (i2c_bus->valid) {
+ /* add DP i2c bus */
+ radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch");
+ if (!radeon_dig_connector->dp_i2c_bus)
+ DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");
+ radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
+ if (!radeon_connector->ddc_bus)
+ DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+ }
drm_connector_attach_property(&radeon_connector->base,
- rdev->mode_info.underscan_hborder_property,
- 0);
+ dev->mode_config.scaling_mode_property,
+ DRM_MODE_SCALE_FULLSCREEN);
+ subpixel_order = SubPixelHorizontalRGB;
+ connector->interlace_allowed = false;
+ connector->doublescan_allowed = false;
+ break;
+ case DRM_MODE_CONNECTOR_SVIDEO:
+ case DRM_MODE_CONNECTOR_Composite:
+ case DRM_MODE_CONNECTOR_9PinDIN:
+ drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type);
+ drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
+ radeon_connector->dac_load_detect = true;
drm_connector_attach_property(&radeon_connector->base,
- rdev->mode_info.underscan_vborder_property,
- 0);
- }
- connector->interlace_allowed = true;
- /* in theory with a DP to VGA converter... */
- connector->doublescan_allowed = false;
- break;
- case DRM_MODE_CONNECTOR_SVIDEO:
- case DRM_MODE_CONNECTOR_Composite:
- case DRM_MODE_CONNECTOR_9PinDIN:
- drm_connector_init(dev, &radeon_connector->base, &radeon_tv_connector_funcs, connector_type);
- drm_connector_helper_add(&radeon_connector->base, &radeon_tv_connector_helper_funcs);
- radeon_connector->dac_load_detect = true;
- drm_connector_attach_property(&radeon_connector->base,
- rdev->mode_info.load_detect_property,
- 1);
- 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;
- connector->interlace_allowed = false;
- connector->doublescan_allowed = false;
- break;
- case DRM_MODE_CONNECTOR_LVDS:
- radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
- if (!radeon_dig_connector)
- goto failed;
- radeon_dig_connector->igp_lane_info = igp_lane_info;
- radeon_connector->con_priv = radeon_dig_connector;
- drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
- drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
- if (i2c_bus->valid) {
- radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
- if (!radeon_connector->ddc_bus)
- DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+ rdev->mode_info.load_detect_property,
+ 1);
+ 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;
+ connector->interlace_allowed = false;
+ connector->doublescan_allowed = false;
+ break;
+ case DRM_MODE_CONNECTOR_LVDS:
+ radeon_dig_connector = kzalloc(sizeof(struct radeon_connector_atom_dig), GFP_KERNEL);
+ if (!radeon_dig_connector)
+ goto failed;
+ radeon_dig_connector->igp_lane_info = igp_lane_info;
+ radeon_connector->con_priv = radeon_dig_connector;
+ drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
+ drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
+ if (i2c_bus->valid) {
+ radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
+ if (!radeon_connector->ddc_bus)
+ DRM_ERROR("LVDS: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
+ }
+ drm_connector_attach_property(&radeon_connector->base,
+ dev->mode_config.scaling_mode_property,
+ DRM_MODE_SCALE_FULLSCREEN);
+ subpixel_order = SubPixelHorizontalRGB;
+ connector->interlace_allowed = false;
+ connector->doublescan_allowed = false;
+ break;
}
- drm_connector_attach_property(&radeon_connector->base,
- dev->mode_config.scaling_mode_property,
- DRM_MODE_SCALE_FULLSCREEN);
- subpixel_order = SubPixelHorizontalRGB;
- connector->interlace_allowed = false;
- connector->doublescan_allowed = false;
- break;
}
if (radeon_connector->hpd.hpd == RADEON_HPD_NONE) {
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 890217e678d3..5b61364e31f4 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -923,6 +923,9 @@ int radeon_resume_kms(struct drm_device *dev)
radeon_fbdev_set_suspend(rdev, 0);
console_unlock();
+ /* init dig PHYs */
+ if (rdev->is_atom_bios)
+ radeon_atom_encoder_init(rdev);
/* reset hpd state */
radeon_hpd_init(rdev);
/* blat the mode back in */
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index bdbab5c43bdc..ae247eec87c0 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -1087,8 +1087,9 @@ void radeon_compute_pll_legacy(struct radeon_pll *pll,
*frac_fb_div_p = best_frac_feedback_div;
*ref_div_p = best_ref_div;
*post_div_p = best_post_div;
- DRM_DEBUG_KMS("%d %d, pll dividers - fb: %d.%d ref: %d, post %d\n",
- freq, best_freq / 1000, best_feedback_div, best_frac_feedback_div,
+ DRM_DEBUG_KMS("%lld %d, pll dividers - fb: %d.%d ref: %d, post %d\n",
+ (long long)freq,
+ best_freq / 1000, best_feedback_div, best_frac_feedback_div,
best_ref_div, best_post_div);
}
@@ -1344,6 +1345,11 @@ int radeon_modeset_init(struct radeon_device *rdev)
if (!ret) {
return ret;
}
+
+ /* init dig PHYs */
+ if (rdev->is_atom_bios)
+ radeon_atom_encoder_init(rdev);
+
/* initialize hpd */
radeon_hpd_init(rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 63d2de8771dc..1d330606292f 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -50,9 +50,10 @@
* 2.7.0 - fixups for r600 2D tiling support. (no external ABI change), add eg dyn gpr regs
* 2.8.0 - pageflip support, r500 US_FORMAT regs. r500 ARGB2101010 colorbuf, r300->r500 CMASK, clock crystal query
* 2.9.0 - r600 tiling (s3tc,rgtc) working, SET_PREDICATION packet 3 on r600 + eg, backend query
+ * 2.10.0 - fusion 2D tiling
*/
#define KMS_DRIVER_MAJOR 2
-#define KMS_DRIVER_MINOR 9
+#define KMS_DRIVER_MINOR 10
#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);
diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c
index b4274883227f..1b557554696e 100644
--- a/drivers/gpu/drm/radeon/radeon_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_encoders.c
@@ -229,6 +229,22 @@ radeon_get_connector_for_encoder(struct drm_encoder *encoder)
return NULL;
}
+static struct drm_connector *
+radeon_get_connector_for_encoder_init(struct drm_encoder *encoder)
+{
+ struct drm_device *dev = encoder->dev;
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct drm_connector *connector;
+ struct radeon_connector *radeon_connector;
+
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ radeon_connector = to_radeon_connector(connector);
+ if (radeon_encoder->devices & radeon_connector->devices)
+ return connector;
+ }
+ return NULL;
+}
+
struct drm_encoder *radeon_atom_get_external_encoder(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
@@ -250,6 +266,25 @@ struct drm_encoder *radeon_atom_get_external_encoder(struct drm_encoder *encoder
return NULL;
}
+bool radeon_encoder_is_dp_bridge(struct drm_encoder *encoder)
+{
+ struct drm_encoder *other_encoder = radeon_atom_get_external_encoder(encoder);
+
+ if (other_encoder) {
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(other_encoder);
+
+ switch (radeon_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_TRAVIS:
+ case ENCODER_OBJECT_ID_NUTMEG:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ return false;
+}
+
void radeon_panel_mode_fixup(struct drm_encoder *encoder,
struct drm_display_mode *adjusted_mode)
{
@@ -621,6 +656,10 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
struct radeon_connector *radeon_connector;
struct radeon_connector_atom_dig *dig_connector;
+ /* dp bridges are always DP */
+ if (radeon_encoder_is_dp_bridge(encoder))
+ return ATOM_ENCODER_MODE_DP;
+
connector = radeon_get_connector_for_encoder(encoder);
if (!connector) {
switch (radeon_encoder->encoder_id) {
@@ -668,7 +707,6 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
return ATOM_ENCODER_MODE_LVDS;
break;
case DRM_MODE_CONNECTOR_DisplayPort:
- case DRM_MODE_CONNECTOR_eDP:
dig_connector = radeon_connector->con_priv;
if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
(dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))
@@ -682,6 +720,8 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
} else
return ATOM_ENCODER_MODE_DVI;
break;
+ case DRM_MODE_CONNECTOR_eDP:
+ return ATOM_ENCODER_MODE_DP;
case DRM_MODE_CONNECTOR_DVIA:
case DRM_MODE_CONNECTOR_VGA:
return ATOM_ENCODER_MODE_CRT;
@@ -747,7 +787,7 @@ union dig_encoder_control {
};
void
-atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
+atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
@@ -760,6 +800,7 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
int dp_clock = 0;
int dp_lane_count = 0;
int hpd_id = RADEON_HPD_NONE;
+ int bpc = 8;
if (connector) {
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -769,6 +810,7 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
dp_clock = dig_connector->dp_clock;
dp_lane_count = dig_connector->dp_lane_count;
hpd_id = radeon_connector->hpd.hpd;
+ bpc = connector->display_info.bpc;
}
/* no dig encoder assigned */
@@ -791,7 +833,10 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
args.v1.ucAction = action;
args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
- args.v1.ucEncoderMode = atombios_get_encoder_mode(encoder);
+ if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE)
+ args.v3.ucPanelMode = panel_mode;
+ else
+ args.v1.ucEncoderMode = atombios_get_encoder_mode(encoder);
if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) ||
(args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP_MST))
@@ -810,7 +855,27 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ;
}
args.v4.acConfig.ucDigSel = dig->dig_encoder;
- args.v4.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+ switch (bpc) {
+ case 0:
+ args.v4.ucBitPerColor = PANEL_BPC_UNDEFINE;
+ break;
+ case 6:
+ args.v4.ucBitPerColor = PANEL_6BIT_PER_COLOR;
+ break;
+ case 8:
+ default:
+ args.v4.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+ break;
+ case 10:
+ args.v4.ucBitPerColor = PANEL_10BIT_PER_COLOR;
+ break;
+ case 12:
+ args.v4.ucBitPerColor = PANEL_12BIT_PER_COLOR;
+ break;
+ case 16:
+ args.v4.ucBitPerColor = PANEL_16BIT_PER_COLOR;
+ break;
+ }
if (hpd_id == RADEON_HPD_NONE)
args.v4.ucHPD_ID = 0;
else
@@ -819,7 +884,27 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) && (dp_clock == 270000))
args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ;
args.v3.acConfig.ucDigSel = dig->dig_encoder;
- args.v3.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+ switch (bpc) {
+ case 0:
+ args.v3.ucBitPerColor = PANEL_BPC_UNDEFINE;
+ break;
+ case 6:
+ args.v3.ucBitPerColor = PANEL_6BIT_PER_COLOR;
+ break;
+ case 8:
+ default:
+ args.v3.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+ break;
+ case 10:
+ args.v3.ucBitPerColor = PANEL_10BIT_PER_COLOR;
+ break;
+ case 12:
+ args.v3.ucBitPerColor = PANEL_12BIT_PER_COLOR;
+ break;
+ case 16:
+ args.v3.ucBitPerColor = PANEL_16BIT_PER_COLOR;
+ break;
+ }
} else {
if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) && (dp_clock == 270000))
args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
@@ -859,7 +944,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
- struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+ struct drm_connector *connector;
union dig_transmitter_control args;
int index = 0;
uint8_t frev, crev;
@@ -870,6 +955,11 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
int connector_object_id = 0;
int igp_lane_info = 0;
+ if (action == ATOM_TRANSMITTER_ACTION_INIT)
+ connector = radeon_get_connector_for_encoder_init(encoder);
+ else
+ connector = radeon_get_connector_for_encoder(encoder);
+
if (connector) {
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
struct radeon_connector_atom_dig *dig_connector =
@@ -931,10 +1021,10 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
else
args.v3.ucLaneNum = 4;
- if (dig->linkb) {
+ if (dig->linkb)
args.v3.acConfig.ucLinkSel = 1;
+ if (dig->dig_encoder & 1)
args.v3.acConfig.ucEncoderSel = 1;
- }
/* Select the PLL for the PHY
* DP PHY should be clocked from external src if there is
@@ -946,11 +1036,16 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
}
if (ASIC_IS_DCE5(rdev)) {
- if (is_dp && rdev->clock.dp_extclk)
- args.v4.acConfig.ucRefClkSource = 3; /* external src */
- else
+ /* On DCE5 DCPLL usually generates the DP ref clock */
+ if (is_dp) {
+ if (rdev->clock.dp_extclk)
+ args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_EXTCLK;
+ else
+ args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_DCPLL;
+ } else
args.v4.acConfig.ucRefClkSource = pll_id;
} else {
+ /* On DCE4, if there is an external clock, it generates the DP ref clock */
if (is_dp && rdev->clock.dp_extclk)
args.v3.acConfig.ucRefClkSource = 2; /* external src */
else
@@ -1047,7 +1142,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
}
-void
+bool
atombios_set_edp_panel_power(struct drm_connector *connector, int action)
{
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -1058,23 +1153,37 @@ atombios_set_edp_panel_power(struct drm_connector *connector, int action)
uint8_t frev, crev;
if (connector->connector_type != DRM_MODE_CONNECTOR_eDP)
- return;
+ goto done;
if (!ASIC_IS_DCE4(rdev))
- return;
+ goto done;
if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) &&
(action != ATOM_TRANSMITTER_ACTION_POWER_OFF))
- return;
+ goto done;
if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
- return;
+ goto done;
memset(&args, 0, sizeof(args));
args.v1.ucAction = action;
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+ /* wait for the panel to power up */
+ if (action == ATOM_TRANSMITTER_ACTION_POWER_ON) {
+ int i;
+
+ for (i = 0; i < 300; i++) {
+ if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd))
+ return true;
+ mdelay(1);
+ }
+ return false;
+ }
+done:
+ return true;
}
union external_encoder_control {
@@ -1092,13 +1201,19 @@ atombios_external_encoder_setup(struct drm_encoder *encoder,
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder *ext_radeon_encoder = to_radeon_encoder(ext_encoder);
union external_encoder_control args;
- struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+ struct drm_connector *connector;
int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl);
u8 frev, crev;
int dp_clock = 0;
int dp_lane_count = 0;
int connector_object_id = 0;
u32 ext_enum = (ext_radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
+ int bpc = 8;
+
+ if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT)
+ connector = radeon_get_connector_for_encoder_init(encoder);
+ else
+ connector = radeon_get_connector_for_encoder(encoder);
if (connector) {
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -1109,6 +1224,7 @@ atombios_external_encoder_setup(struct drm_encoder *encoder,
dp_lane_count = dig_connector->dp_lane_count;
connector_object_id =
(radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
+ bpc = connector->display_info.bpc;
}
memset(&args, 0, sizeof(args));
@@ -1166,7 +1282,27 @@ atombios_external_encoder_setup(struct drm_encoder *encoder,
args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER3;
break;
}
- args.v3.sExtEncoder.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+ switch (bpc) {
+ case 0:
+ args.v3.sExtEncoder.ucBitPerColor = PANEL_BPC_UNDEFINE;
+ break;
+ case 6:
+ args.v3.sExtEncoder.ucBitPerColor = PANEL_6BIT_PER_COLOR;
+ break;
+ case 8:
+ default:
+ args.v3.sExtEncoder.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+ break;
+ case 10:
+ args.v3.sExtEncoder.ucBitPerColor = PANEL_10BIT_PER_COLOR;
+ break;
+ case 12:
+ args.v3.sExtEncoder.ucBitPerColor = PANEL_12BIT_PER_COLOR;
+ break;
+ case 16:
+ args.v3.sExtEncoder.ucBitPerColor = PANEL_16BIT_PER_COLOR;
+ break;
+ }
break;
default:
DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
@@ -1307,9 +1443,11 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
ATOM_TRANSMITTER_ACTION_POWER_ON);
radeon_dig_connector->edp_on = true;
}
- dp_link_train(encoder, connector);
if (ASIC_IS_DCE4(rdev))
- atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON);
+ atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0);
+ radeon_dp_link_train(encoder, connector);
+ if (ASIC_IS_DCE4(rdev))
+ atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0);
}
if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0);
@@ -1322,7 +1460,7 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
if (ASIC_IS_DCE4(rdev))
- atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF);
+ atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0);
if (connector &&
(connector->connector_type == DRM_MODE_CONNECTOR_eDP)) {
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -1601,12 +1739,9 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
/* DCE4/5 */
if (ASIC_IS_DCE4(rdev)) {
dig = radeon_encoder->enc_priv;
- if (ASIC_IS_DCE41(rdev)) {
- if (dig->linkb)
- return 1;
- else
- return 0;
- } else {
+ if (ASIC_IS_DCE41(rdev))
+ return radeon_crtc->crtc_id;
+ else {
switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
if (dig->linkb)
@@ -1662,6 +1797,34 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
return 1;
}
+/* This only needs to be called once at startup */
+void
+radeon_atom_encoder_init(struct radeon_device *rdev)
+{
+ struct drm_device *dev = rdev->ddev;
+ struct drm_encoder *encoder;
+
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder);
+
+ switch (radeon_encoder->encoder_id) {
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+ atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0);
+ break;
+ default:
+ break;
+ }
+
+ if (ext_encoder && ASIC_IS_DCE41(rdev))
+ atombios_external_encoder_setup(encoder, ext_encoder,
+ EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT);
+ }
+}
+
static void
radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
@@ -1696,19 +1859,17 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
/* disable the transmitter */
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
/* setup and enable the encoder */
- atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP);
+ atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0);
- /* init and enable the transmitter */
- atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0);
+ /* enable the transmitter */
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
} else {
/* disable the encoder and transmitter */
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
- atombios_dig_encoder_setup(encoder, ATOM_DISABLE);
+ atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0);
/* setup and enable the encoder and transmitter */
- atombios_dig_encoder_setup(encoder, ATOM_ENABLE);
- atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0);
+ atombios_dig_encoder_setup(encoder, ATOM_ENABLE, 0);
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0);
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
}
@@ -1733,12 +1894,10 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
}
if (ext_encoder) {
- if (ASIC_IS_DCE41(rdev)) {
- atombios_external_encoder_setup(encoder, ext_encoder,
- EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT);
+ if (ASIC_IS_DCE41(rdev))
atombios_external_encoder_setup(encoder, ext_encoder,
EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP);
- } else
+ else
atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE);
}
@@ -1845,8 +2004,9 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
- if (radeon_encoder->active_device &
- (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) {
+ if ((radeon_encoder->active_device &
+ (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) ||
+ radeon_encoder_is_dp_bridge(encoder)) {
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
if (dig)
dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder);
@@ -1855,11 +2015,17 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
radeon_atom_output_lock(encoder, true);
radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
- /* select the clock/data port if it uses a router */
if (connector) {
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+
+ /* select the clock/data port if it uses a router */
if (radeon_connector->router.cd_valid)
radeon_router_select_cd_port(radeon_connector);
+
+ /* turn eDP panel on for mode set */
+ if (connector->connector_type == DRM_MODE_CONNECTOR_eDP)
+ atombios_set_edp_panel_power(connector,
+ ATOM_TRANSMITTER_ACTION_POWER_ON);
}
/* this is needed for the pll/ss setup to work correctly in some cases */
@@ -1914,7 +2080,7 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
else {
/* disable the encoder and transmitter */
atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
- atombios_dig_encoder_setup(encoder, ATOM_DISABLE);
+ atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0);
}
break;
case ENCODER_OBJECT_ID_INTERNAL_DDI:
@@ -2116,8 +2282,6 @@ radeon_add_atom_encoder(struct drm_device *dev,
} 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;
@@ -2150,8 +2314,6 @@ radeon_add_atom_encoder(struct drm_device *dev,
} 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_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c
index bbcd1dd7bac0..1f8229436570 100644
--- a/drivers/gpu/drm/radeon/radeon_fence.c
+++ b/drivers/gpu/drm/radeon/radeon_fence.c
@@ -322,7 +322,7 @@ void radeon_fence_unref(struct radeon_fence **fence)
*fence = NULL;
if (tmp) {
- kref_put(&tmp->kref, &radeon_fence_destroy);
+ kref_put(&tmp->kref, radeon_fence_destroy);
}
}
diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c
index 983cbac75af0..781196db792f 100644
--- a/drivers/gpu/drm/radeon/radeon_i2c.c
+++ b/drivers/gpu/drm/radeon/radeon_i2c.c
@@ -888,6 +888,7 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
i2c->rec = *rec;
i2c->adapter.owner = THIS_MODULE;
+ i2c->adapter.class = I2C_CLASS_DDC;
i2c->dev = dev;
i2c_set_adapdata(&i2c->adapter, i2c);
if (rec->mm_i2c ||
@@ -947,6 +948,7 @@ struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev,
i2c->rec = *rec;
i2c->adapter.owner = THIS_MODULE;
+ i2c->adapter.class = I2C_CLASS_DDC;
i2c->dev = dev;
snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
"Radeon aux bus %s", name);
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 9c57538231d5..977a341266b6 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -464,22 +464,27 @@ radeon_atombios_get_tv_info(struct radeon_device *rdev);
extern struct drm_connector *
radeon_get_connector_for_encoder(struct drm_encoder *encoder);
+extern bool radeon_encoder_is_dp_bridge(struct drm_encoder *encoder);
+extern bool radeon_connector_encoder_is_dp_bridge(struct drm_connector *connector);
+extern bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector);
+extern bool radeon_connector_is_dp12_capable(struct drm_connector *connector);
+
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,
+extern int radeon_dp_mode_valid_helper(struct drm_connector *connector,
struct drm_display_mode *mode);
extern void radeon_dp_set_link_config(struct drm_connector *connector,
struct drm_display_mode *mode);
-extern void dp_link_train(struct drm_encoder *encoder,
- struct drm_connector *connector);
+extern void radeon_dp_link_train(struct drm_encoder *encoder,
+ struct drm_connector *connector);
extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector);
extern bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector);
-extern void atombios_dig_encoder_setup(struct drm_encoder *encoder, int action);
+extern void atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode);
+extern void radeon_atom_encoder_init(struct radeon_device *rdev);
extern void atombios_dig_transmitter_setup(struct drm_encoder *encoder,
int action, uint8_t lane_num,
uint8_t lane_set);
extern int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
- uint8_t write_byte, uint8_t *read_byte);
+ u8 write_byte, u8 *read_byte);
extern void radeon_i2c_init(struct radeon_device *rdev);
extern void radeon_i2c_fini(struct radeon_device *rdev);
@@ -545,7 +550,7 @@ struct drm_encoder *radeon_encoder_legacy_tmds_ext_add(struct drm_device *dev, i
extern void atombios_dvo_setup(struct drm_encoder *encoder, int action);
extern void atombios_digital_setup(struct drm_encoder *encoder, int action);
extern int atombios_get_encoder_mode(struct drm_encoder *encoder);
-extern void atombios_set_edp_panel_power(struct drm_connector *connector, int action);
+extern bool atombios_set_edp_panel_power(struct drm_connector *connector, int action);
extern void radeon_encoder_set_active_device(struct drm_encoder *encoder);
extern void radeon_crtc_load_lut(struct drm_crtc *crtc);
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c
index c6776e48fdde..08c0233db1b8 100644
--- a/drivers/gpu/drm/radeon/radeon_ring.c
+++ b/drivers/gpu/drm/radeon/radeon_ring.c
@@ -194,7 +194,7 @@ int radeon_ib_pool_init(struct radeon_device *rdev)
r = radeon_bo_kmap(rdev->ib_pool.robj, &ptr);
radeon_bo_unreserve(rdev->ib_pool.robj);
if (r) {
- DRM_ERROR("radeon: failed to map ib poll (%d).\n", r);
+ DRM_ERROR("radeon: failed to map ib pool (%d).\n", r);
return r;
}
for (i = 0; i < RADEON_IB_POOL_SIZE; i++) {
diff --git a/drivers/gpu/drm/ttm/ttm_object.c b/drivers/gpu/drm/ttm/ttm_object.c
index 75e9d6f86ba4..ebddd443d91a 100644
--- a/drivers/gpu/drm/ttm/ttm_object.c
+++ b/drivers/gpu/drm/ttm/ttm_object.c
@@ -206,7 +206,7 @@ void ttm_base_object_unref(struct ttm_base_object **p_base)
*/
write_lock(&tdev->object_lock);
- (void)kref_put(&base->refcount, &ttm_release_base);
+ kref_put(&base->refcount, ttm_release_base);
write_unlock(&tdev->object_lock);
}
EXPORT_SYMBOL(ttm_base_object_unref);
diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c
index 9d9d92945f8c..d948575717bf 100644
--- a/drivers/gpu/drm/ttm/ttm_page_alloc.c
+++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c
@@ -395,12 +395,14 @@ static int ttm_pool_get_num_unused_pages(void)
/**
* Callback for mm to request pool to reduce number of page held.
*/
-static int ttm_pool_mm_shrink(struct shrinker *shrink, int shrink_pages, gfp_t gfp_mask)
+static int ttm_pool_mm_shrink(struct shrinker *shrink,
+ struct shrink_control *sc)
{
static atomic_t start_pool = ATOMIC_INIT(0);
unsigned i;
unsigned pool_offset = atomic_add_return(1, &start_pool);
struct ttm_page_pool *pool;
+ int shrink_pages = sc->nr_to_scan;
pool_offset = pool_offset % NUM_POOLS;
/* select start pool in round robin fashion */
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index 498b284e5ef9..58434e804d91 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -215,7 +215,6 @@ static int vga_switchoff(struct vga_switcheroo_client *client)
/* stage one happens before delay */
static int vga_switchto_stage1(struct vga_switcheroo_client *new_client)
{
- int ret;
int i;
struct vga_switcheroo_client *active = NULL;
@@ -228,11 +227,6 @@ static int vga_switchto_stage1(struct vga_switcheroo_client *new_client)
if (!active)
return 0;
- /* power up the first device */
- ret = pci_enable_device(new_client->pdev);
- if (ret)
- return ret;
-
if (new_client->pwr_state == VGA_SWITCHEROO_OFF)
vga_switchon(new_client);
diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c
index be8d4cb5861c..8a1021f2e319 100644
--- a/drivers/gpu/vga/vgaarb.c
+++ b/drivers/gpu/vga/vgaarb.c
@@ -61,7 +61,7 @@ struct vga_device {
unsigned int mem_lock_cnt; /* legacy MEM lock count */
unsigned int io_norm_cnt; /* normal IO count */
unsigned int mem_norm_cnt; /* normal MEM count */
-
+ bool bridge_has_one_vga;
/* allow IRQ enable/disable hook */
void *cookie;
void (*irq_set_state)(void *cookie, bool enable);
@@ -165,6 +165,8 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev,
unsigned int wants, legacy_wants, match;
struct vga_device *conflict;
unsigned int pci_bits;
+ u32 flags = 0;
+
/* Account for "normal" resources to lock. If we decode the legacy,
* counterpart, we need to request it as well
*/
@@ -237,16 +239,23 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev,
/* looks like he doesn't have a lock, we can steal
* them from him
*/
- vga_irq_set_state(conflict, false);
+ flags = 0;
pci_bits = 0;
- if (lwants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
- pci_bits |= PCI_COMMAND_MEMORY;
- if (lwants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
- pci_bits |= PCI_COMMAND_IO;
- pci_set_vga_state(conflict->pdev, false, pci_bits,
- change_bridge);
+ if (!conflict->bridge_has_one_vga) {
+ vga_irq_set_state(conflict, false);
+ flags |= PCI_VGA_STATE_CHANGE_DECODES;
+ if (lwants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
+ pci_bits |= PCI_COMMAND_MEMORY;
+ if (lwants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
+ pci_bits |= PCI_COMMAND_IO;
+ }
+
+ if (change_bridge)
+ flags |= PCI_VGA_STATE_CHANGE_BRIDGE;
+
+ pci_set_vga_state(conflict->pdev, false, pci_bits, flags);
conflict->owns &= ~lwants;
/* If he also owned non-legacy, that is no longer the case */
if (lwants & VGA_RSRC_LEGACY_MEM)
@@ -261,14 +270,24 @@ enable_them:
* also have in "decodes". We can lock resources we don't decode but
* not own them.
*/
+ flags = 0;
pci_bits = 0;
- if (wants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
- pci_bits |= PCI_COMMAND_MEMORY;
- if (wants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
- pci_bits |= PCI_COMMAND_IO;
- pci_set_vga_state(vgadev->pdev, true, pci_bits, !!(wants & VGA_RSRC_LEGACY_MASK));
- vga_irq_set_state(vgadev, true);
+ if (!vgadev->bridge_has_one_vga) {
+ flags |= PCI_VGA_STATE_CHANGE_DECODES;
+ if (wants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
+ pci_bits |= PCI_COMMAND_MEMORY;
+ if (wants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
+ pci_bits |= PCI_COMMAND_IO;
+ }
+ if (!!(wants & VGA_RSRC_LEGACY_MASK))
+ flags |= PCI_VGA_STATE_CHANGE_BRIDGE;
+
+ pci_set_vga_state(vgadev->pdev, true, pci_bits, flags);
+
+ if (!vgadev->bridge_has_one_vga) {
+ vga_irq_set_state(vgadev, true);
+ }
vgadev->owns |= (wants & vgadev->decodes);
lock_them:
vgadev->locks |= (rsrc & VGA_RSRC_LEGACY_MASK);
@@ -421,6 +440,62 @@ bail:
}
EXPORT_SYMBOL(vga_put);
+/* Rules for using a bridge to control a VGA descendant decoding:
+ if a bridge has only one VGA descendant then it can be used
+ to control the VGA routing for that device.
+ It should always use the bridge closest to the device to control it.
+ If a bridge has a direct VGA descendant, but also have a sub-bridge
+ VGA descendant then we cannot use that bridge to control the direct VGA descendant.
+ So for every device we register, we need to iterate all its parent bridges
+ so we can invalidate any devices using them properly.
+*/
+static void vga_arbiter_check_bridge_sharing(struct vga_device *vgadev)
+{
+ struct vga_device *same_bridge_vgadev;
+ struct pci_bus *new_bus, *bus;
+ struct pci_dev *new_bridge, *bridge;
+
+ vgadev->bridge_has_one_vga = true;
+
+ if (list_empty(&vga_list))
+ return;
+
+ /* okay iterate the new devices bridge hierarachy */
+ new_bus = vgadev->pdev->bus;
+ while (new_bus) {
+ new_bridge = new_bus->self;
+
+ if (new_bridge) {
+ /* go through list of devices already registered */
+ list_for_each_entry(same_bridge_vgadev, &vga_list, list) {
+ bus = same_bridge_vgadev->pdev->bus;
+ bridge = bus->self;
+
+ /* see if the share a bridge with this device */
+ if (new_bridge == bridge) {
+ /* if their direct parent bridge is the same
+ as any bridge of this device then it can't be used
+ for that device */
+ same_bridge_vgadev->bridge_has_one_vga = false;
+ }
+
+ /* now iterate the previous devices bridge hierarchy */
+ /* if the new devices parent bridge is in the other devices
+ hierarchy then we can't use it to control this device */
+ while (bus) {
+ bridge = bus->self;
+ if (bridge) {
+ if (bridge == vgadev->pdev->bus->self)
+ vgadev->bridge_has_one_vga = false;
+ }
+ bus = bus->parent;
+ }
+ }
+ }
+ new_bus = new_bus->parent;
+ }
+}
+
/*
* Currently, we assume that the "initial" setup of the system is
* not sane, that is we come up with conflicting devices and let
@@ -500,6 +575,8 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev)
vga_default = pci_dev_get(pdev);
#endif
+ vga_arbiter_check_bridge_sharing(vgadev);
+
/* Add to the list */
list_add(&vgadev->list, &vga_list);
vga_count++;
@@ -1222,6 +1299,7 @@ static int __init vga_arb_device_init(void)
{
int rc;
struct pci_dev *pdev;
+ struct vga_device *vgadev;
rc = misc_register(&vga_arb_device);
if (rc < 0)
@@ -1238,6 +1316,13 @@ static int __init vga_arb_device_init(void)
vga_arbiter_add_pci_device(pdev);
pr_info("vgaarb: loaded\n");
+
+ list_for_each_entry(vgadev, &vga_list, list) {
+ if (vgadev->bridge_has_one_vga)
+ pr_info("vgaarb: bridge control possible %s\n", pci_name(vgadev->pdev));
+ else
+ pr_info("vgaarb: no bridge control possible %s\n", pci_name(vgadev->pdev));
+ }
return rc;
}
subsys_initcall(vga_arb_device_init);
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 9de9e97149ec..67d2a7585934 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -55,12 +55,6 @@ source "drivers/hid/usbhid/Kconfig"
menu "Special HID drivers"
depends on HID
-config HID_3M_PCT
- tristate "3M PCT touchscreen"
- depends on USB_HID
- ---help---
- Support for 3M PCT touch screens.
-
config HID_A4TECH
tristate "A4 tech mice" if EXPERT
depends on USB_HID
@@ -100,12 +94,6 @@ config HID_BELKIN
---help---
Support for Belkin Flip KVM and Wireless keyboard.
-config HID_CANDO
- tristate "Cando dual touch panel"
- depends on USB_HID
- ---help---
- Support for Cando dual touch panel.
-
config HID_CHERRY
tristate "Cherry Cymotion keyboard" if EXPERT
depends on USB_HID
@@ -300,12 +288,6 @@ config HID_MICROSOFT
---help---
Support for Microsoft devices that are not fully compliant with HID standard.
-config HID_MOSART
- tristate "MosArt dual-touch panels"
- depends on USB_HID
- ---help---
- Support for MosArt dual-touch panels.
-
config HID_MONTEREY
tristate "Monterey Genius KB29E keyboard" if EXPERT
depends on USB_HID
@@ -320,13 +302,25 @@ config HID_MULTITOUCH
Generic support for HID multitouch panels.
Say Y here if you have one of the following devices:
+ - 3M PCT touch screens
+ - ActionStar dual touch panels
+ - Cando dual touch panels
+ - CVTouch panels
- Cypress TrueTouch panels
+ - Elo TouchSystems IntelliTouch Plus panels
+ - GeneralTouch 'Sensing Win7-TwoFinger' panels
+ - GoodTouch panels
- Hanvon dual touch panels
+ - Ilitek dual touch panels
- IrTouch Infrared USB panels
+ - Lumio CrystalTouch panels
+ - MosArt dual-touch panels
+ - PenMount dual touch panels
- Pixcir dual touch panels
- - 'Sensing Win7-TwoFinger' panel by GeneralTouch
- - eGalax dual-touch panels, including the
- Joojoo and Wetab tablets
+ - eGalax dual-touch panels, including the Joojoo and Wetab tablets
+ - Stantum multitouch panels
+ - Touch International Panels
+ - Unitec Panels
If unsure, say N.
@@ -500,12 +494,6 @@ config HID_SONY
---help---
Support for Sony PS3 controller.
-config HID_STANTUM
- tristate "Stantum multitouch panel"
- depends on USB_HID
- ---help---
- Support for Stantum multitouch panel.
-
config HID_SUNPLUS
tristate "Sunplus wireless desktop"
depends on USB_HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 06c68ae3abee..f8cc4ea7335a 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -25,12 +25,10 @@ ifdef CONFIG_LOGIWII_FF
hid-logitech-y += hid-lg4ff.o
endif
-obj-$(CONFIG_HID_3M_PCT) += hid-3m-pct.o
obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
obj-$(CONFIG_HID_ACRUX) += hid-axff.o
obj-$(CONFIG_HID_APPLE) += hid-apple.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
-obj-$(CONFIG_HID_CANDO) += hid-cando.o
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o
@@ -47,7 +45,6 @@ obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o
obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o
obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o
obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o
-obj-$(CONFIG_HID_MOSART) += hid-mosart.o
obj-$(CONFIG_HID_MULTITOUCH) += hid-multitouch.o
obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o
obj-$(CONFIG_HID_ORTEK) += hid-ortek.o
@@ -66,7 +63,6 @@ obj-$(CONFIG_HID_ROCCAT_PYRA) += hid-roccat-pyra.o
obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o
obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
obj-$(CONFIG_HID_SONY) += hid-sony.o
-obj-$(CONFIG_HID_STANTUM) += hid-stantum.o
obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o
obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o
obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o
diff --git a/drivers/hid/hid-3m-pct.c b/drivers/hid/hid-3m-pct.c
deleted file mode 100644
index 5243ae2d3730..000000000000
--- a/drivers/hid/hid-3m-pct.c
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * HID driver for 3M PCT multitouch panels
- *
- * Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
- * Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se>
- * Copyright (c) 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; 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 <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/input/mt.h>
-
-MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
-MODULE_DESCRIPTION("3M PCT multitouch panels");
-MODULE_LICENSE("GPL");
-
-#include "hid-ids.h"
-
-#define MAX_SLOTS 60
-
-/* estimated signal-to-noise ratios */
-#define SN_MOVE 2048
-#define SN_WIDTH 128
-
-struct mmm_finger {
- __s32 x, y, w, h;
- bool touch, valid;
-};
-
-struct mmm_data {
- struct mmm_finger f[MAX_SLOTS];
- __u8 curid;
- __u8 nexp, nreal;
- bool touch, valid;
-};
-
-static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
- struct hid_field *field, struct hid_usage *usage,
- unsigned long **bit, int *max)
-{
- int f1 = field->logical_minimum;
- int f2 = field->logical_maximum;
- int df = f2 - f1;
-
- switch (usage->hid & HID_USAGE_PAGE) {
-
- case HID_UP_BUTTON:
- return -1;
-
- case HID_UP_GENDESK:
- switch (usage->hid) {
- case HID_GD_X:
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_POSITION_X);
- input_set_abs_params(hi->input, ABS_MT_POSITION_X,
- f1, f2, df / SN_MOVE, 0);
- /* touchscreen emulation */
- input_set_abs_params(hi->input, ABS_X,
- f1, f2, df / SN_MOVE, 0);
- return 1;
- case HID_GD_Y:
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_POSITION_Y);
- input_set_abs_params(hi->input, ABS_MT_POSITION_Y,
- f1, f2, df / SN_MOVE, 0);
- /* touchscreen emulation */
- input_set_abs_params(hi->input, ABS_Y,
- f1, f2, df / SN_MOVE, 0);
- return 1;
- }
- return 0;
-
- case HID_UP_DIGITIZER:
- switch (usage->hid) {
- /* we do not want to map these: no input-oriented meaning */
- case 0x14:
- case 0x23:
- case HID_DG_INPUTMODE:
- case HID_DG_DEVICEINDEX:
- case HID_DG_CONTACTCOUNT:
- case HID_DG_CONTACTMAX:
- case HID_DG_INRANGE:
- case HID_DG_CONFIDENCE:
- return -1;
- case HID_DG_TIPSWITCH:
- /* touchscreen emulation */
- hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
- input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
- return 1;
- case HID_DG_WIDTH:
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_TOUCH_MAJOR);
- input_set_abs_params(hi->input, ABS_MT_TOUCH_MAJOR,
- f1, f2, df / SN_WIDTH, 0);
- return 1;
- case HID_DG_HEIGHT:
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_TOUCH_MINOR);
- input_set_abs_params(hi->input, ABS_MT_TOUCH_MINOR,
- f1, f2, df / SN_WIDTH, 0);
- input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
- 0, 1, 0, 0);
- return 1;
- case HID_DG_CONTACTID:
- input_mt_init_slots(hi->input, MAX_SLOTS);
- return 1;
- }
- /* let hid-input decide for the others */
- return 0;
-
- case 0xff000000:
- /* we do not want to map these: no input-oriented meaning */
- return -1;
- }
-
- return 0;
-}
-
-static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi,
- struct hid_field *field, struct hid_usage *usage,
- unsigned long **bit, int *max)
-{
- /* tell hid-input to skip setup of these event types */
- if (usage->type == EV_KEY || usage->type == EV_ABS)
- set_bit(usage->type, hi->input->evbit);
- return -1;
-}
-
-/*
- * this function is called when a whole packet has been received and processed,
- * so that it can decide what to send to the input layer.
- */
-static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
-{
- int i;
- for (i = 0; i < MAX_SLOTS; ++i) {
- struct mmm_finger *f = &md->f[i];
- if (!f->valid) {
- /* this finger is just placeholder data, ignore */
- continue;
- }
- input_mt_slot(input, i);
- input_mt_report_slot_state(input, MT_TOOL_FINGER, f->touch);
- if (f->touch) {
- /* this finger is on the screen */
- int wide = (f->w > f->h);
- /* divided by two to match visual scale of touch */
- int major = max(f->w, f->h) >> 1;
- int minor = min(f->w, f->h) >> 1;
-
- input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x);
- input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y);
- input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
- input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
- input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
- }
- f->valid = 0;
- }
-
- input_mt_report_pointer_emulation(input, true);
- input_sync(input);
-}
-
-/*
- * this function is called upon all reports
- * so that we can accumulate contact point information,
- * and call input_mt_sync after each point.
- */
-static int mmm_event(struct hid_device *hid, struct hid_field *field,
- struct hid_usage *usage, __s32 value)
-{
- struct mmm_data *md = hid_get_drvdata(hid);
- /*
- * strangely, this function can be called before
- * field->hidinput is initialized!
- */
- if (hid->claimed & HID_CLAIMED_INPUT) {
- struct input_dev *input = field->hidinput->input;
- switch (usage->hid) {
- case HID_DG_TIPSWITCH:
- md->touch = value;
- break;
- case HID_DG_CONFIDENCE:
- md->valid = value;
- break;
- case HID_DG_WIDTH:
- if (md->valid)
- md->f[md->curid].w = value;
- break;
- case HID_DG_HEIGHT:
- if (md->valid)
- md->f[md->curid].h = value;
- break;
- case HID_DG_CONTACTID:
- value = clamp_val(value, 0, MAX_SLOTS - 1);
- if (md->valid) {
- md->curid = value;
- md->f[value].touch = md->touch;
- md->f[value].valid = 1;
- md->nreal++;
- }
- break;
- case HID_GD_X:
- if (md->valid)
- md->f[md->curid].x = value;
- break;
- case HID_GD_Y:
- if (md->valid)
- md->f[md->curid].y = value;
- break;
- case HID_DG_CONTACTCOUNT:
- if (value)
- md->nexp = value;
- if (md->nreal >= md->nexp) {
- mmm_filter_event(md, input);
- md->nreal = 0;
- }
- break;
- }
- }
-
- /* we have handled the hidinput part, now remains hiddev */
- if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
- hid->hiddev_hid_event(hid, field, usage, value);
-
- return 1;
-}
-
-static int mmm_probe(struct hid_device *hdev, const struct hid_device_id *id)
-{
- int ret;
- struct mmm_data *md;
-
- hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
-
- md = kzalloc(sizeof(struct mmm_data), GFP_KERNEL);
- if (!md) {
- hid_err(hdev, "cannot allocate 3M data\n");
- return -ENOMEM;
- }
- hid_set_drvdata(hdev, md);
-
- ret = hid_parse(hdev);
- if (!ret)
- ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
-
- if (ret)
- kfree(md);
- return ret;
-}
-
-static void mmm_remove(struct hid_device *hdev)
-{
- hid_hw_stop(hdev);
- kfree(hid_get_drvdata(hdev));
- hid_set_drvdata(hdev, NULL);
-}
-
-static const struct hid_device_id mmm_devices[] = {
- { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
- { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) },
- { }
-};
-MODULE_DEVICE_TABLE(hid, mmm_devices);
-
-static const struct hid_usage_id mmm_grabbed_usages[] = {
- { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
- { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
-};
-
-static struct hid_driver mmm_driver = {
- .name = "3m-pct",
- .id_table = mmm_devices,
- .probe = mmm_probe,
- .remove = mmm_remove,
- .input_mapping = mmm_input_mapping,
- .input_mapped = mmm_input_mapped,
- .usage_table = mmm_grabbed_usages,
- .event = mmm_event,
-};
-
-static int __init mmm_init(void)
-{
- return hid_register_driver(&mmm_driver);
-}
-
-static void __exit mmm_exit(void)
-{
- hid_unregister_driver(&mmm_driver);
-}
-
-module_init(mmm_init);
-module_exit(mmm_exit);
-
diff --git a/drivers/hid/hid-cando.c b/drivers/hid/hid-cando.c
deleted file mode 100644
index 1ea066c55201..000000000000
--- a/drivers/hid/hid-cando.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * HID driver for Cando dual-touch panels
- *
- * Copyright (c) 2010 Stephane Chatty <chatty@enac.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.
- */
-
-#include <linux/device.h>
-#include <linux/hid.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-
-MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
-MODULE_DESCRIPTION("Cando dual-touch panel");
-MODULE_LICENSE("GPL");
-
-#include "hid-ids.h"
-
-struct cando_data {
- __u16 x, y;
- __u8 id;
- __s8 oldest; /* id of the oldest finger in previous frame */
- bool valid; /* valid finger data, or just placeholder? */
- bool first; /* is this the first finger in this frame? */
- __s8 firstid; /* id of the first finger in the frame */
- __u16 firstx, firsty; /* (x, y) of the first finger in the frame */
-};
-
-static int cando_input_mapping(struct hid_device *hdev, struct hid_input *hi,
- struct hid_field *field, struct hid_usage *usage,
- unsigned long **bit, int *max)
-{
- switch (usage->hid & HID_USAGE_PAGE) {
-
- case HID_UP_GENDESK:
- switch (usage->hid) {
- case HID_GD_X:
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_POSITION_X);
- /* touchscreen emulation */
- input_set_abs_params(hi->input, ABS_X,
- field->logical_minimum,
- field->logical_maximum, 0, 0);
- return 1;
- case HID_GD_Y:
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_POSITION_Y);
- /* touchscreen emulation */
- input_set_abs_params(hi->input, ABS_Y,
- field->logical_minimum,
- field->logical_maximum, 0, 0);
- return 1;
- }
- return 0;
-
- case HID_UP_DIGITIZER:
- switch (usage->hid) {
- case HID_DG_TIPSWITCH:
- case HID_DG_CONTACTMAX:
- return -1;
- case HID_DG_INRANGE:
- /* touchscreen emulation */
- hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
- return 1;
- case HID_DG_CONTACTID:
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_TRACKING_ID);
- return 1;
- }
- return 0;
- }
-
- return 0;
-}
-
-static int cando_input_mapped(struct hid_device *hdev, struct hid_input *hi,
- struct hid_field *field, struct hid_usage *usage,
- unsigned long **bit, int *max)
-{
- if (usage->type == EV_KEY || usage->type == EV_ABS)
- clear_bit(usage->code, *bit);
-
- return 0;
-}
-
-/*
- * this function is called when a whole finger has been parsed,
- * so that it can decide what to send to the input layer.
- */
-static void cando_filter_event(struct cando_data *td, struct input_dev *input)
-{
- td->first = !td->first; /* touchscreen emulation */
-
- if (!td->valid) {
- /*
- * touchscreen emulation: if this is the second finger and
- * the first was valid, the first was the oldest; if the
- * first was not valid and there was a valid finger in the
- * previous frame, this is a release.
- */
- if (td->first) {
- td->firstid = -1;
- } else if (td->firstid >= 0) {
- input_event(input, EV_ABS, ABS_X, td->firstx);
- input_event(input, EV_ABS, ABS_Y, td->firsty);
- td->oldest = td->firstid;
- } else if (td->oldest >= 0) {
- input_event(input, EV_KEY, BTN_TOUCH, 0);
- td->oldest = -1;
- }
-
- return;
- }
-
- input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
- input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
- input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
-
- input_mt_sync(input);
-
- /*
- * touchscreen emulation: if there was no touching finger previously,
- * emit touch event
- */
- if (td->oldest < 0) {
- input_event(input, EV_KEY, BTN_TOUCH, 1);
- td->oldest = td->id;
- }
-
- /*
- * touchscreen emulation: if this is the first finger, wait for the
- * second; the oldest is then the second if it was the oldest already
- * or if there was no first, the first otherwise.
- */
- if (td->first) {
- td->firstx = td->x;
- td->firsty = td->y;
- td->firstid = td->id;
- } else {
- int x, y, oldest;
- if (td->id == td->oldest || td->firstid < 0) {
- x = td->x;
- y = td->y;
- oldest = td->id;
- } else {
- x = td->firstx;
- y = td->firsty;
- oldest = td->firstid;
- }
- input_event(input, EV_ABS, ABS_X, x);
- input_event(input, EV_ABS, ABS_Y, y);
- td->oldest = oldest;
- }
-}
-
-
-static int cando_event(struct hid_device *hid, struct hid_field *field,
- struct hid_usage *usage, __s32 value)
-{
- struct cando_data *td = hid_get_drvdata(hid);
-
- if (hid->claimed & HID_CLAIMED_INPUT) {
- struct input_dev *input = field->hidinput->input;
-
- switch (usage->hid) {
- case HID_DG_INRANGE:
- td->valid = value;
- break;
- case HID_DG_CONTACTID:
- td->id = value;
- break;
- case HID_GD_X:
- td->x = value;
- break;
- case HID_GD_Y:
- td->y = value;
- cando_filter_event(td, input);
- break;
- case HID_DG_TIPSWITCH:
- /* avoid interference from generic hidinput handling */
- break;
-
- default:
- /* fallback to the generic hidinput handling */
- return 0;
- }
- }
-
- /* we have handled the hidinput part, now remains hiddev */
- if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
- hid->hiddev_hid_event(hid, field, usage, value);
-
- return 1;
-}
-
-static int cando_probe(struct hid_device *hdev, const struct hid_device_id *id)
-{
- int ret;
- struct cando_data *td;
-
- td = kmalloc(sizeof(struct cando_data), GFP_KERNEL);
- if (!td) {
- hid_err(hdev, "cannot allocate Cando Touch data\n");
- return -ENOMEM;
- }
- hid_set_drvdata(hdev, td);
- td->first = false;
- td->oldest = -1;
- td->valid = false;
-
- ret = hid_parse(hdev);
- if (!ret)
- ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
-
- if (ret)
- kfree(td);
-
- return ret;
-}
-
-static void cando_remove(struct hid_device *hdev)
-{
- hid_hw_stop(hdev);
- kfree(hid_get_drvdata(hdev));
- hid_set_drvdata(hdev, NULL);
-}
-
-static const struct hid_device_id cando_devices[] = {
- { HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
- USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
- { HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
- USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) },
- { HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
- USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) },
- { HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
- USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
- { }
-};
-MODULE_DEVICE_TABLE(hid, cando_devices);
-
-static const struct hid_usage_id cando_grabbed_usages[] = {
- { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
- { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
-};
-
-static struct hid_driver cando_driver = {
- .name = "cando-touch",
- .id_table = cando_devices,
- .probe = cando_probe,
- .remove = cando_remove,
- .input_mapping = cando_input_mapping,
- .input_mapped = cando_input_mapped,
- .usage_table = cando_grabbed_usages,
- .event = cando_event,
-};
-
-static int __init cando_init(void)
-{
- return hid_register_driver(&cando_driver);
-}
-
-static void __exit cando_exit(void)
-{
- hid_unregister_driver(&cando_driver);
-}
-
-module_init(cando_init);
-module_exit(cando_exit);
-
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 408c4bea4d8d..c957c4b4fe70 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1045,6 +1045,9 @@ void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
rsize = ((report->size - 1) >> 3) + 1;
+ if (rsize > HID_MAX_BUFFER_SIZE)
+ rsize = HID_MAX_BUFFER_SIZE;
+
if (csize < rsize) {
dbg_hid("report %d is too short, (%d < %d)\n", report->id,
csize, rsize);
@@ -1290,6 +1293,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR, USB_DEVICE_ID_ACTIONSTAR_1011) },
{ 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) },
@@ -1356,6 +1360,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, USB_DEVICE_ID_CVTOUCH_SCREEN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) },
@@ -1369,17 +1374,20 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2515) },
{ HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) },
{ 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) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH, USB_DEVICE_ID_GOODTOUCH_000f) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0012) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HANVON, USB_DEVICE_ID_HANVON_MULTITOUCH) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ILITEK, USB_DEVICE_ID_ILITEK_MULTITOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
@@ -1408,10 +1416,12 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, USB_DEVICE_ID_CRYSTALTOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) },
@@ -1441,6 +1451,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_PCI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
@@ -1454,6 +1465,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) },
@@ -1470,12 +1482,15 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb65a) },
{ 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_TOUCH_INTL, USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) },
{ 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_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) },
@@ -1760,19 +1775,37 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_GPEN_560) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_KYE, 0x0058) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYVOLTAGE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYCURRENT) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTIME) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYPH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP) },
- { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY1) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIC) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIB) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_VIDEOCOM) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOTOR) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_COM3LAB) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_TELEPORT) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_NETWORKANALYSER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERCONTROL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETEST) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOSTANALYSER) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOSTANALYSER2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_ABSESP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_AUTODATABUS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MCT) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HYBRID) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HEATCONTROL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 00a94b535d28..0b374a6d6db0 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -37,6 +37,9 @@
#define USB_VENDOR_ID_ACRUX 0x1a34
+#define USB_VENDOR_ID_ACTIONSTAR 0x2101
+#define USB_DEVICE_ID_ACTIONSTAR_1011 0x1011
+
#define USB_VENDOR_ID_ADS_TECH 0x06e1
#define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X 0xa155
@@ -182,6 +185,9 @@
#define USB_VENDOR_ID_CREATIVELABS 0x041e
#define USB_DEVICE_ID_PRODIKEYS_PCMIDI 0x2801
+#define USB_VENDOR_ID_CVTOUCH 0x1ff7
+#define USB_DEVICE_ID_CVTOUCH_SCREEN 0x0013
+
#define USB_VENDOR_ID_CYGNAL 0x10c4
#define USB_DEVICE_ID_CYGNAL_RADIO_SI470X 0x818a
@@ -220,6 +226,7 @@
#define USB_VENDOR_ID_DREAM_CHEEKY 0x1d34
#define USB_VENDOR_ID_ELO 0x04E7
+#define USB_DEVICE_ID_ELO_TS2515 0x0022
#define USB_DEVICE_ID_ELO_TS2700 0x0020
#define USB_VENDOR_ID_EMS 0x2006
@@ -255,6 +262,9 @@
#define USB_DEVICE_ID_0_8_8_IF_KIT 0x0053
#define USB_DEVICE_ID_PHIDGET_MOTORCONTROL 0x0058
+#define USB_VENDOR_ID_GOODTOUCH 0x1aad
+#define USB_DEVICE_ID_GOODTOUCH_000f 0x000f
+
#define USB_VENDOR_ID_GOTOP 0x08f2
#define USB_DEVICE_ID_SUPER_Q2 0x007f
#define USB_DEVICE_ID_GOGOPEN 0x00ce
@@ -334,6 +344,9 @@
#define USB_DEVICE_ID_UGCI_FLYING 0x0020
#define USB_DEVICE_ID_UGCI_FIGHTING 0x0030
+#define USB_VENDOR_ID_ILITEK 0x222a
+#define USB_DEVICE_ID_ILITEK_MULTITOUCH 0x0001
+
#define USB_VENDOR_ID_IMATION 0x0718
#define USB_DEVICE_ID_DISC_STAKKA 0xd000
@@ -367,19 +380,38 @@
#define USB_VENDOR_ID_LD 0x0f11
#define USB_DEVICE_ID_LD_CASSY 0x1000
+#define USB_DEVICE_ID_LD_CASSY2 0x1001
#define USB_DEVICE_ID_LD_POCKETCASSY 0x1010
+#define USB_DEVICE_ID_LD_POCKETCASSY2 0x1011
#define USB_DEVICE_ID_LD_MOBILECASSY 0x1020
+#define USB_DEVICE_ID_LD_MOBILECASSY2 0x1021
+#define USB_DEVICE_ID_LD_MICROCASSYVOLTAGE 0x1031
+#define USB_DEVICE_ID_LD_MICROCASSYCURRENT 0x1032
+#define USB_DEVICE_ID_LD_MICROCASSYTIME 0x1033
+#define USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE 0x1035
+#define USB_DEVICE_ID_LD_MICROCASSYPH 0x1038
#define USB_DEVICE_ID_LD_JWM 0x1080
#define USB_DEVICE_ID_LD_DMMP 0x1081
#define USB_DEVICE_ID_LD_UMIP 0x1090
-#define USB_DEVICE_ID_LD_XRAY1 0x1100
+#define USB_DEVICE_ID_LD_UMIC 0x10A0
+#define USB_DEVICE_ID_LD_UMIB 0x10B0
+#define USB_DEVICE_ID_LD_XRAY 0x1100
#define USB_DEVICE_ID_LD_XRAY2 0x1101
+#define USB_DEVICE_ID_LD_XRAYCT 0x1110
#define USB_DEVICE_ID_LD_VIDEOCOM 0x1200
+#define USB_DEVICE_ID_LD_MOTOR 0x1210
#define USB_DEVICE_ID_LD_COM3LAB 0x2000
#define USB_DEVICE_ID_LD_TELEPORT 0x2010
#define USB_DEVICE_ID_LD_NETWORKANALYSER 0x2020
#define USB_DEVICE_ID_LD_POWERCONTROL 0x2030
#define USB_DEVICE_ID_LD_MACHINETEST 0x2040
+#define USB_DEVICE_ID_LD_MOSTANALYSER 0x2050
+#define USB_DEVICE_ID_LD_MOSTANALYSER2 0x2051
+#define USB_DEVICE_ID_LD_ABSESP 0x2060
+#define USB_DEVICE_ID_LD_AUTODATABUS 0x2070
+#define USB_DEVICE_ID_LD_MCT 0x2080
+#define USB_DEVICE_ID_LD_HYBRID 0x2090
+#define USB_DEVICE_ID_LD_HEATCONTROL 0x20A0
#define USB_VENDOR_ID_LOGITECH 0x046d
#define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101
@@ -398,6 +430,7 @@
#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295
#define USB_DEVICE_ID_LOGITECH_DFP_WHEEL 0xc298
#define USB_DEVICE_ID_LOGITECH_G25_WHEEL 0xc299
+#define USB_DEVICE_ID_LOGITECH_G27_WHEEL 0xc29b
#define USB_DEVICE_ID_LOGITECH_WII_WHEEL 0xc29c
#define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a
#define USB_DEVICE_ID_S510_RECEIVER 0xc50c
@@ -411,6 +444,9 @@
#define USB_DEVICE_ID_DINOVO_MINI 0xc71f
#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2 0xca03
+#define USB_VENDOR_ID_LUMIO 0x202e
+#define USB_DEVICE_ID_CRYSTALTOUCH 0x0006
+
#define USB_VENDOR_ID_MCC 0x09db
#define USB_DEVICE_ID_MCC_PMD1024LS 0x0076
#define USB_DEVICE_ID_MCC_PMD1208LS 0x007a
@@ -488,6 +524,9 @@
#define USB_VENDOR_ID_PANTHERLORD 0x0810
#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK 0x0001
+#define USB_VENDOR_ID_PENMOUNT 0x14e1
+#define USB_DEVICE_ID_PENMOUNT_PCI 0x3500
+
#define USB_VENDOR_ID_PETALYNX 0x18b1
#define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037
@@ -531,6 +570,7 @@
#define USB_VENDOR_ID_SONY 0x054c
#define USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE 0x024b
#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268
+#define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f
#define USB_VENDOR_ID_SOUNDGRAPH 0x15c2
#define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST 0x0034
@@ -551,6 +591,10 @@
#define USB_VENDOR_ID_SUNPLUS 0x04fc
#define USB_DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8
+#define USB_VENDOR_ID_SYMBOL 0x05e0
+#define USB_DEVICE_ID_SYMBOL_SCANNER_1 0x0800
+#define USB_DEVICE_ID_SYMBOL_SCANNER_2 0x1300
+
#define USB_VENDOR_ID_THRUSTMASTER 0x044f
#define USB_VENDOR_ID_TOPSEED 0x0766
@@ -562,6 +606,9 @@
#define USB_VENDOR_ID_TOPMAX 0x0663
#define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103
+#define USB_VENDOR_ID_TOUCH_INTL 0x1e5e
+#define USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH 0x0313
+
#define USB_VENDOR_ID_TOUCHPACK 0x1bfd
#define USB_DEVICE_ID_TOUCHPACK_RTS 0x1688
@@ -579,6 +626,10 @@
#define USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U 0x0004
#define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U 0x0005
+#define USB_VENDOR_ID_UNITEC 0x227d
+#define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709 0x0709
+#define USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19 0x0a19
+
#define USB_VENDOR_ID_VERNIER 0x08f7
#define USB_DEVICE_ID_VERNIER_LABPRO 0x0001
#define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 33dde8724e02..6559e2e3364e 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -44,11 +44,11 @@ static const unsigned char hid_keyboard[256] = {
72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk,
- 122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
+ 122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk,
unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
unk,unk,unk,unk,unk,unk,179,180,unk,unk,unk,unk,unk,unk,unk,unk,
unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
- unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
+ unk,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk,unk,unk,unk,unk,
29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk
};
@@ -357,6 +357,18 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x1: map_key_clear(KEY_POWER); break;
case 0x2: map_key_clear(KEY_SLEEP); break;
case 0x3: map_key_clear(KEY_WAKEUP); break;
+ case 0x4: map_key_clear(KEY_CONTEXT_MENU); break;
+ case 0x5: map_key_clear(KEY_MENU); break;
+ case 0x6: map_key_clear(KEY_PROG1); break;
+ case 0x7: map_key_clear(KEY_HELP); break;
+ case 0x8: map_key_clear(KEY_EXIT); break;
+ case 0x9: map_key_clear(KEY_SELECT); break;
+ case 0xa: map_key_clear(KEY_RIGHT); break;
+ case 0xb: map_key_clear(KEY_LEFT); break;
+ case 0xc: map_key_clear(KEY_UP); break;
+ case 0xd: map_key_clear(KEY_DOWN); break;
+ case 0xe: map_key_clear(KEY_POWER2); break;
+ case 0xf: map_key_clear(KEY_RESTART); break;
default: goto unknown;
}
break;
@@ -466,16 +478,39 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
}
break;
- case HID_UP_CONSUMER: /* USB HUT v1.1, pages 56-62 */
+ case HID_UP_CONSUMER: /* USB HUT v1.12, pages 75-84 */
switch (usage->hid & HID_USAGE) {
case 0x000: goto ignore;
+ case 0x030: map_key_clear(KEY_POWER); break;
+ case 0x031: map_key_clear(KEY_RESTART); break;
+ case 0x032: map_key_clear(KEY_SLEEP); break;
case 0x034: map_key_clear(KEY_SLEEP); break;
+ case 0x035: map_key_clear(KEY_KBDILLUMTOGGLE); break;
case 0x036: map_key_clear(BTN_MISC); break;
- case 0x040: map_key_clear(KEY_MENU); break;
- case 0x045: map_key_clear(KEY_RADIO); break;
-
+ case 0x040: map_key_clear(KEY_MENU); break; /* Menu */
+ case 0x041: map_key_clear(KEY_SELECT); break; /* Menu Pick */
+ case 0x042: map_key_clear(KEY_UP); break; /* Menu Up */
+ case 0x043: map_key_clear(KEY_DOWN); break; /* Menu Down */
+ case 0x044: map_key_clear(KEY_LEFT); break; /* Menu Left */
+ case 0x045: map_key_clear(KEY_RIGHT); break; /* Menu Right */
+ case 0x046: map_key_clear(KEY_ESC); break; /* Menu Escape */
+ case 0x047: map_key_clear(KEY_KPPLUS); break; /* Menu Value Increase */
+ case 0x048: map_key_clear(KEY_KPMINUS); break; /* Menu Value Decrease */
+
+ case 0x060: map_key_clear(KEY_INFO); break; /* Data On Screen */
+ case 0x061: map_key_clear(KEY_SUBTITLE); break; /* Closed Caption */
+ case 0x063: map_key_clear(KEY_VCR); break; /* VCR/TV */
+ case 0x065: map_key_clear(KEY_CAMERA); break; /* Snapshot */
+ case 0x069: map_key_clear(KEY_RED); break;
+ case 0x06a: map_key_clear(KEY_GREEN); break;
+ case 0x06b: map_key_clear(KEY_BLUE); break;
+ case 0x06c: map_key_clear(KEY_YELLOW); break;
+ case 0x06d: map_key_clear(KEY_ZOOM); break;
+
+ case 0x082: map_key_clear(KEY_VIDEO_NEXT); break;
case 0x083: map_key_clear(KEY_LAST); break;
+ case 0x084: map_key_clear(KEY_ENTER); break;
case 0x088: map_key_clear(KEY_PC); break;
case 0x089: map_key_clear(KEY_TV); break;
case 0x08a: map_key_clear(KEY_WWW); break;
@@ -509,6 +544,8 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x0b7: map_key_clear(KEY_STOPCD); break;
case 0x0b8: map_key_clear(KEY_EJECTCD); break;
case 0x0bc: map_key_clear(KEY_MEDIA_REPEAT); break;
+ case 0x0b9: map_key_clear(KEY_SHUFFLE); break;
+ case 0x0bf: map_key_clear(KEY_SLOW); break;
case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break;
case 0x0e0: map_abs_clear(ABS_VOLUME); break;
@@ -516,6 +553,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x0e5: map_key_clear(KEY_BASSBOOST); break;
case 0x0e9: map_key_clear(KEY_VOLUMEUP); break;
case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break;
+ case 0x0f5: map_key_clear(KEY_SLOW); break;
case 0x182: map_key_clear(KEY_BOOKMARKS); break;
case 0x183: map_key_clear(KEY_CONFIG); break;
@@ -532,6 +570,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x18e: map_key_clear(KEY_CALENDAR); break;
case 0x191: map_key_clear(KEY_FINANCE); break;
case 0x192: map_key_clear(KEY_CALC); break;
+ case 0x193: map_key_clear(KEY_PLAYER); break;
case 0x194: map_key_clear(KEY_FILE); break;
case 0x196: map_key_clear(KEY_WWW); break;
case 0x199: map_key_clear(KEY_CHAT); break;
@@ -540,8 +579,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x1a6: map_key_clear(KEY_HELP); break;
case 0x1a7: map_key_clear(KEY_DOCUMENTS); break;
case 0x1ab: map_key_clear(KEY_SPELLCHECK); break;
- case 0x1b6: map_key_clear(KEY_MEDIA); break;
- case 0x1b7: map_key_clear(KEY_SOUND); break;
+ case 0x1ae: map_key_clear(KEY_KEYBOARD); break;
+ case 0x1b6: map_key_clear(KEY_IMAGES); break;
+ case 0x1b7: map_key_clear(KEY_AUDIO); break;
+ case 0x1b8: map_key_clear(KEY_VIDEO); break;
case 0x1bc: map_key_clear(KEY_MESSENGER); break;
case 0x1bd: map_key_clear(KEY_INFO); break;
case 0x201: map_key_clear(KEY_NEW); break;
@@ -570,7 +611,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x233: map_key_clear(KEY_SCROLLUP); break;
case 0x234: map_key_clear(KEY_SCROLLDOWN); break;
case 0x238: map_rel(REL_HWHEEL); break;
+ case 0x23d: map_key_clear(KEY_EDIT); break;
case 0x25f: map_key_clear(KEY_CANCEL); break;
+ case 0x269: map_key_clear(KEY_INSERT); break;
+ case 0x26a: map_key_clear(KEY_DELETE); break;
case 0x279: map_key_clear(KEY_REDO); break;
case 0x289: map_key_clear(KEY_REPLY); break;
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index 3da90402ee81..21f205f09250 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -377,6 +377,8 @@ static const struct hid_device_id lg_devices[] = {
.driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
.driver_data = LG_FF },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL),
+ .driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
.driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
diff --git a/drivers/hid/hid-lgff.c b/drivers/hid/hid-lgff.c
index f099079ca6b9..088f85049290 100644
--- a/drivers/hid/hid-lgff.c
+++ b/drivers/hid/hid-lgff.c
@@ -72,6 +72,9 @@ static const struct dev_type devices[] = {
{ 0x046d, 0xc287, ff_joystick_ac },
{ 0x046d, 0xc293, ff_joystick },
{ 0x046d, 0xc294, ff_wheel },
+ { 0x046d, 0xc298, ff_wheel },
+ { 0x046d, 0xc299, ff_wheel },
+ { 0x046d, 0xc29b, ff_wheel },
{ 0x046d, 0xc295, ff_joystick },
{ 0x046d, 0xc298, ff_wheel },
{ 0x046d, 0xc299, ff_wheel },
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index 0ec91c18a421..a5eda4c8127a 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -501,9 +501,17 @@ static int magicmouse_probe(struct hid_device *hdev,
}
report->size = 6;
+ /*
+ * The device reponds with 'invalid report id' when feature
+ * report switching it into multitouch mode is sent to it.
+ *
+ * This results in -EIO from the _raw low-level transport callback,
+ * but there seems to be no other way of switching the mode.
+ * Thus the super-ugly hacky success check below.
+ */
ret = hdev->hid_output_raw_report(hdev, feature, sizeof(feature),
HID_FEATURE_REPORT);
- if (ret != sizeof(feature)) {
+ if (ret != -EIO) {
hid_err(hdev, "unable to request touch data (%d)\n", ret);
goto err_stop_hw;
}
diff --git a/drivers/hid/hid-mosart.c b/drivers/hid/hid-mosart.c
deleted file mode 100644
index aed7ffe36283..000000000000
--- a/drivers/hid/hid-mosart.c
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * HID driver for the multitouch panel on the ASUS EeePC T91MT
- *
- * Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
- * Copyright (c) 2010 Teemu Tuominen <teemu.tuominen@cybercom.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 <linux/slab.h>
-#include <linux/usb.h>
-#include "usbhid/usbhid.h"
-
-MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
-MODULE_DESCRIPTION("MosArt dual-touch panel");
-MODULE_LICENSE("GPL");
-
-#include "hid-ids.h"
-
-struct mosart_data {
- __u16 x, y;
- __u8 id;
- bool valid; /* valid finger data, or just placeholder? */
- bool first; /* is this the first finger in this frame? */
- bool activity_now; /* at least one active finger in this frame? */
- bool activity; /* at least one active finger previously? */
-};
-
-static int mosart_input_mapping(struct hid_device *hdev, struct hid_input *hi,
- struct hid_field *field, struct hid_usage *usage,
- unsigned long **bit, int *max)
-{
- switch (usage->hid & HID_USAGE_PAGE) {
-
- case HID_UP_GENDESK:
- switch (usage->hid) {
- case HID_GD_X:
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_POSITION_X);
- /* touchscreen emulation */
- input_set_abs_params(hi->input, ABS_X,
- field->logical_minimum,
- field->logical_maximum, 0, 0);
- return 1;
- case HID_GD_Y:
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_POSITION_Y);
- /* touchscreen emulation */
- input_set_abs_params(hi->input, ABS_Y,
- field->logical_minimum,
- field->logical_maximum, 0, 0);
- return 1;
- }
- return 0;
-
- case HID_UP_DIGITIZER:
- switch (usage->hid) {
- case HID_DG_CONFIDENCE:
- case HID_DG_TIPSWITCH:
- case HID_DG_INPUTMODE:
- case HID_DG_DEVICEINDEX:
- case HID_DG_CONTACTCOUNT:
- case HID_DG_CONTACTMAX:
- case HID_DG_TIPPRESSURE:
- case HID_DG_WIDTH:
- case HID_DG_HEIGHT:
- return -1;
- case HID_DG_INRANGE:
- /* touchscreen emulation */
- hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
- return 1;
-
- case HID_DG_CONTACTID:
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_TRACKING_ID);
- return 1;
-
- }
- return 0;
-
- case 0xff000000:
- /* ignore HID features */
- return -1;
-
- case HID_UP_BUTTON:
- /* ignore buttons */
- return -1;
- }
-
- return 0;
-}
-
-static int mosart_input_mapped(struct hid_device *hdev, struct hid_input *hi,
- struct hid_field *field, struct hid_usage *usage,
- unsigned long **bit, int *max)
-{
- if (usage->type == EV_KEY || usage->type == EV_ABS)
- clear_bit(usage->code, *bit);
-
- return 0;
-}
-
-/*
- * this function is called when a whole finger has been parsed,
- * so that it can decide what to send to the input layer.
- */
-static void mosart_filter_event(struct mosart_data *td, struct input_dev *input)
-{
- td->first = !td->first; /* touchscreen emulation */
-
- if (!td->valid) {
- /*
- * touchscreen emulation: if no finger in this frame is valid
- * and there previously was finger activity, this is a release
- */
- if (!td->first && !td->activity_now && td->activity) {
- input_event(input, EV_KEY, BTN_TOUCH, 0);
- td->activity = false;
- }
- return;
- }
-
- input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
- input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
- input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
-
- input_mt_sync(input);
- td->valid = false;
-
- /* touchscreen emulation: if first active finger in this frame... */
- if (!td->activity_now) {
- /* if there was no previous activity, emit touch event */
- if (!td->activity) {
- input_event(input, EV_KEY, BTN_TOUCH, 1);
- td->activity = true;
- }
- td->activity_now = true;
- /* and in any case this is our preferred finger */
- input_event(input, EV_ABS, ABS_X, td->x);
- input_event(input, EV_ABS, ABS_Y, td->y);
- }
-}
-
-
-static int mosart_event(struct hid_device *hid, struct hid_field *field,
- struct hid_usage *usage, __s32 value)
-{
- struct mosart_data *td = hid_get_drvdata(hid);
-
- if (hid->claimed & HID_CLAIMED_INPUT) {
- struct input_dev *input = field->hidinput->input;
- switch (usage->hid) {
- case HID_DG_INRANGE:
- td->valid = !!value;
- break;
- case HID_GD_X:
- td->x = value;
- break;
- case HID_GD_Y:
- td->y = value;
- mosart_filter_event(td, input);
- break;
- case HID_DG_CONTACTID:
- td->id = value;
- break;
- case HID_DG_CONTACTCOUNT:
- /* touch emulation: this is the last field in a frame */
- td->first = false;
- td->activity_now = false;
- break;
- case HID_DG_CONFIDENCE:
- case HID_DG_TIPSWITCH:
- /* avoid interference from generic hidinput handling */
- break;
-
- default:
- /* fallback to the generic hidinput handling */
- return 0;
- }
- }
-
- /* we have handled the hidinput part, now remains hiddev */
- if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
- hid->hiddev_hid_event(hid, field, usage, value);
-
- return 1;
-}
-
-static int mosart_probe(struct hid_device *hdev, const struct hid_device_id *id)
-{
- int ret;
- struct mosart_data *td;
-
-
- td = kmalloc(sizeof(struct mosart_data), GFP_KERNEL);
- if (!td) {
- hid_err(hdev, "cannot allocate MosArt data\n");
- return -ENOMEM;
- }
- td->valid = false;
- td->activity = false;
- td->activity_now = false;
- td->first = false;
- hid_set_drvdata(hdev, td);
-
- /* currently, it's better to have one evdev device only */
-#if 0
- hdev->quirks |= HID_QUIRK_MULTI_INPUT;
-#endif
-
- ret = hid_parse(hdev);
- if (ret == 0)
- ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
-
- if (ret == 0) {
- struct hid_report_enum *re = hdev->report_enum
- + HID_FEATURE_REPORT;
- struct hid_report *r = re->report_id_hash[7];
-
- r->field[0]->value[0] = 0x02;
- usbhid_submit_report(hdev, r, USB_DIR_OUT);
- } else
- kfree(td);
-
- return ret;
-}
-
-#ifdef CONFIG_PM
-static int mosart_reset_resume(struct hid_device *hdev)
-{
- struct hid_report_enum *re = hdev->report_enum
- + HID_FEATURE_REPORT;
- struct hid_report *r = re->report_id_hash[7];
-
- r->field[0]->value[0] = 0x02;
- usbhid_submit_report(hdev, r, USB_DIR_OUT);
- return 0;
-}
-#endif
-
-static void mosart_remove(struct hid_device *hdev)
-{
- hid_hw_stop(hdev);
- kfree(hid_get_drvdata(hdev));
- hid_set_drvdata(hdev, NULL);
-}
-
-static const struct hid_device_id mosart_devices[] = {
- { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) },
- { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) },
- { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
- { }
-};
-MODULE_DEVICE_TABLE(hid, mosart_devices);
-
-static const struct hid_usage_id mosart_grabbed_usages[] = {
- { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
- { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
-};
-
-static struct hid_driver mosart_driver = {
- .name = "mosart",
- .id_table = mosart_devices,
- .probe = mosart_probe,
- .remove = mosart_remove,
- .input_mapping = mosart_input_mapping,
- .input_mapped = mosart_input_mapped,
- .usage_table = mosart_grabbed_usages,
- .event = mosart_event,
-#ifdef CONFIG_PM
- .reset_resume = mosart_reset_resume,
-#endif
-};
-
-static int __init mosart_init(void)
-{
- return hid_register_driver(&mosart_driver);
-}
-
-static void __exit mosart_exit(void)
-{
- hid_unregister_driver(&mosart_driver);
-}
-
-module_init(mosart_init);
-module_exit(mosart_exit);
-
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index ee01e65e22d6..ecd4d2db9e80 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -11,6 +11,12 @@
* Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se>
* Copyright (c) 2010 Canonical, Ltd.
*
+ * This code is partly based on hid-3m-pct.c:
+ *
+ * Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
+ * Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se>
+ * Copyright (c) 2010 Canonical, Ltd.
+ *
*/
/*
@@ -44,6 +50,7 @@ MODULE_LICENSE("GPL");
#define MT_QUIRK_VALID_IS_INRANGE (1 << 4)
#define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 5)
#define MT_QUIRK_EGALAX_XYZ_FIXUP (1 << 6)
+#define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE (1 << 7)
struct mt_slot {
__s32 x, y, p, w, h;
@@ -60,24 +67,36 @@ struct mt_device {
__s8 inputmode; /* InputMode HID feature, -1 if non-existent */
__u8 num_received; /* how many contacts we received */
__u8 num_expected; /* expected last contact index */
+ __u8 maxcontacts;
bool curvalid; /* is the current contact valid? */
- struct mt_slot slots[0]; /* first slot */
+ struct mt_slot *slots;
};
struct mt_class {
__s32 name; /* MT_CLS */
__s32 quirks;
__s32 sn_move; /* Signal/noise ratio for move events */
+ __s32 sn_width; /* Signal/noise ratio for width events */
+ __s32 sn_height; /* Signal/noise ratio for height events */
__s32 sn_pressure; /* Signal/noise ratio for pressure events */
__u8 maxcontacts;
};
/* classes of device behavior */
-#define MT_CLS_DEFAULT 1
-#define MT_CLS_DUAL_INRANGE_CONTACTID 2
-#define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 3
-#define MT_CLS_CYPRESS 4
-#define MT_CLS_EGALAX 5
+#define MT_CLS_DEFAULT 0x0001
+
+#define MT_CLS_CONFIDENCE 0x0002
+#define MT_CLS_CONFIDENCE_MINUS_ONE 0x0003
+#define MT_CLS_DUAL_INRANGE_CONTACTID 0x0004
+#define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 0x0005
+#define MT_CLS_DUAL_NSMU_CONTACTID 0x0006
+
+/* vendor specific classes */
+#define MT_CLS_3M 0x0101
+#define MT_CLS_CYPRESS 0x0102
+#define MT_CLS_EGALAX 0x0103
+
+#define MT_DEFAULT_MAXCONTACT 10
/*
* these device-dependent functions determine what slot corresponds
@@ -95,12 +114,12 @@ static int cypress_compute_slot(struct mt_device *td)
static int find_slot_from_contactid(struct mt_device *td)
{
int i;
- for (i = 0; i < td->mtclass->maxcontacts; ++i) {
+ for (i = 0; i < td->maxcontacts; ++i) {
if (td->slots[i].contactid == td->curdata.contactid &&
td->slots[i].touch_state)
return i;
}
- for (i = 0; i < td->mtclass->maxcontacts; ++i) {
+ for (i = 0; i < td->maxcontacts; ++i) {
if (!td->slots[i].seen_in_this_frame &&
!td->slots[i].touch_state)
return i;
@@ -113,8 +132,12 @@ static int find_slot_from_contactid(struct mt_device *td)
struct mt_class mt_classes[] = {
{ .name = MT_CLS_DEFAULT,
- .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP,
- .maxcontacts = 10 },
+ .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP },
+ { .name = MT_CLS_CONFIDENCE,
+ .quirks = MT_QUIRK_VALID_IS_CONFIDENCE },
+ { .name = MT_CLS_CONFIDENCE_MINUS_ONE,
+ .quirks = MT_QUIRK_VALID_IS_CONFIDENCE |
+ MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE },
{ .name = MT_CLS_DUAL_INRANGE_CONTACTID,
.quirks = MT_QUIRK_VALID_IS_INRANGE |
MT_QUIRK_SLOT_IS_CONTACTID,
@@ -123,11 +146,24 @@ struct mt_class mt_classes[] = {
.quirks = MT_QUIRK_VALID_IS_INRANGE |
MT_QUIRK_SLOT_IS_CONTACTNUMBER,
.maxcontacts = 2 },
+ { .name = MT_CLS_DUAL_NSMU_CONTACTID,
+ .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
+ MT_QUIRK_SLOT_IS_CONTACTID,
+ .maxcontacts = 2 },
+
+ /*
+ * vendor specific classes
+ */
+ { .name = MT_CLS_3M,
+ .quirks = MT_QUIRK_VALID_IS_CONFIDENCE |
+ MT_QUIRK_SLOT_IS_CONTACTID,
+ .sn_move = 2048,
+ .sn_width = 128,
+ .sn_height = 128 },
{ .name = MT_CLS_CYPRESS,
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
MT_QUIRK_CYPRESS,
.maxcontacts = 10 },
-
{ .name = MT_CLS_EGALAX,
.quirks = MT_QUIRK_SLOT_IS_CONTACTID |
MT_QUIRK_VALID_IS_INRANGE |
@@ -136,15 +172,26 @@ struct mt_class mt_classes[] = {
.sn_move = 4096,
.sn_pressure = 32,
},
+
{ }
};
static void mt_feature_mapping(struct hid_device *hdev,
struct hid_field *field, struct hid_usage *usage)
{
- if (usage->hid == HID_DG_INPUTMODE) {
- struct mt_device *td = hid_get_drvdata(hdev);
+ struct mt_device *td = hid_get_drvdata(hdev);
+
+ switch (usage->hid) {
+ case HID_DG_INPUTMODE:
td->inputmode = field->report->id;
+ break;
+ case HID_DG_CONTACTMAX:
+ td->maxcontacts = field->value[0];
+ if (td->mtclass->maxcontacts)
+ /* check if the maxcontacts is given by the class */
+ td->maxcontacts = td->mtclass->maxcontacts;
+
+ break;
}
}
@@ -179,6 +226,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
/* touchscreen emulation */
set_abs(hi->input, ABS_X, field, cls->sn_move);
td->last_slot_field = usage->hid;
+ td->last_field_index = field->index;
return 1;
case HID_GD_Y:
if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP)
@@ -190,6 +238,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
/* touchscreen emulation */
set_abs(hi->input, ABS_Y, field, cls->sn_move);
td->last_slot_field = usage->hid;
+ td->last_field_index = field->index;
return 1;
}
return 0;
@@ -198,32 +247,40 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
switch (usage->hid) {
case HID_DG_INRANGE:
td->last_slot_field = usage->hid;
+ td->last_field_index = field->index;
return 1;
case HID_DG_CONFIDENCE:
td->last_slot_field = usage->hid;
+ td->last_field_index = field->index;
return 1;
case HID_DG_TIPSWITCH:
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
td->last_slot_field = usage->hid;
+ td->last_field_index = field->index;
return 1;
case HID_DG_CONTACTID:
- input_mt_init_slots(hi->input,
- td->mtclass->maxcontacts);
+ input_mt_init_slots(hi->input, td->maxcontacts);
td->last_slot_field = usage->hid;
+ td->last_field_index = field->index;
return 1;
case HID_DG_WIDTH:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TOUCH_MAJOR);
+ set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
+ cls->sn_width);
td->last_slot_field = usage->hid;
+ td->last_field_index = field->index;
return 1;
case HID_DG_HEIGHT:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TOUCH_MINOR);
- field->logical_maximum = 1;
- field->logical_minimum = 0;
- set_abs(hi->input, ABS_MT_ORIENTATION, field, 0);
+ set_abs(hi->input, ABS_MT_TOUCH_MINOR, field,
+ cls->sn_height);
+ input_set_abs_params(hi->input,
+ ABS_MT_ORIENTATION, 0, 1, 0, 0);
td->last_slot_field = usage->hid;
+ td->last_field_index = field->index;
return 1;
case HID_DG_TIPPRESSURE:
if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP)
@@ -236,13 +293,15 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
set_abs(hi->input, ABS_PRESSURE, field,
cls->sn_pressure);
td->last_slot_field = usage->hid;
+ td->last_field_index = field->index;
return 1;
case HID_DG_CONTACTCOUNT:
- td->last_field_index = field->report->maxfield - 1;
+ td->last_field_index = field->index;
return 1;
case HID_DG_CONTACTMAX:
/* we don't set td->last_slot_field as contactcount and
* contact max are global to the report */
+ td->last_field_index = field->index;
return -1;
}
/* let hid-input decide for the others */
@@ -279,6 +338,9 @@ static int mt_compute_slot(struct mt_device *td)
if (quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER)
return td->num_received;
+ if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE)
+ return td->curdata.contactid - 1;
+
return find_slot_from_contactid(td);
}
@@ -292,7 +354,7 @@ static void mt_complete_slot(struct mt_device *td)
if (td->curvalid) {
int slotnum = mt_compute_slot(td);
- if (slotnum >= 0 && slotnum < td->mtclass->maxcontacts)
+ if (slotnum >= 0 && slotnum < td->maxcontacts)
td->slots[slotnum] = td->curdata;
}
td->num_received++;
@@ -307,7 +369,7 @@ static void mt_emit_event(struct mt_device *td, struct input_dev *input)
{
int i;
- for (i = 0; i < td->mtclass->maxcontacts; ++i) {
+ for (i = 0; i < td->maxcontacts; ++i) {
struct mt_slot *s = &(td->slots[i]);
if ((td->mtclass->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) &&
!s->seen_in_this_frame) {
@@ -318,11 +380,18 @@ static void mt_emit_event(struct mt_device *td, struct input_dev *input)
input_mt_report_slot_state(input, MT_TOOL_FINGER,
s->touch_state);
if (s->touch_state) {
+ /* this finger is on the screen */
+ int wide = (s->w > s->h);
+ /* divided by two to match visual scale of touch */
+ int major = max(s->w, s->h) >> 1;
+ int minor = min(s->w, s->h) >> 1;
+
input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x);
input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y);
+ input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p);
- input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, s->w);
- input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, s->h);
+ input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
+ input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
}
s->seen_in_this_frame = false;
@@ -341,7 +410,7 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
struct mt_device *td = hid_get_drvdata(hid);
__s32 quirks = td->mtclass->quirks;
- if (hid->claimed & HID_CLAIMED_INPUT) {
+ if (hid->claimed & HID_CLAIMED_INPUT && td->slots) {
switch (usage->hid) {
case HID_DG_INRANGE:
if (quirks & MT_QUIRK_VALID_IS_INRANGE)
@@ -390,8 +459,6 @@ static int mt_event(struct hid_device *hid, struct hid_field *field,
if (usage->hid == td->last_slot_field) {
mt_complete_slot(td);
- if (!td->last_field_index)
- mt_emit_event(td, field->hidinput->input);
}
if (field->index == td->last_field_index
@@ -442,9 +509,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
*/
hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
- td = kzalloc(sizeof(struct mt_device) +
- mtclass->maxcontacts * sizeof(struct mt_slot),
- GFP_KERNEL);
+ td = kzalloc(sizeof(struct mt_device), GFP_KERNEL);
if (!td) {
dev_err(&hdev->dev, "cannot allocate multitouch data\n");
return -ENOMEM;
@@ -461,6 +526,18 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (ret)
goto fail;
+ if (!td->maxcontacts)
+ td->maxcontacts = MT_DEFAULT_MAXCONTACT;
+
+ td->slots = kzalloc(td->maxcontacts * sizeof(struct mt_slot),
+ GFP_KERNEL);
+ if (!td->slots) {
+ dev_err(&hdev->dev, "cannot allocate multitouch slots\n");
+ hid_hw_stop(hdev);
+ ret = -ENOMEM;
+ goto fail;
+ }
+
mt_set_input_mode(hdev);
return 0;
@@ -482,27 +559,115 @@ static void mt_remove(struct hid_device *hdev)
{
struct mt_device *td = hid_get_drvdata(hdev);
hid_hw_stop(hdev);
+ kfree(td->slots);
kfree(td);
hid_set_drvdata(hdev, NULL);
}
static const struct hid_device_id mt_devices[] = {
+ /* 3M panels */
+ { .driver_data = MT_CLS_3M,
+ HID_USB_DEVICE(USB_VENDOR_ID_3M,
+ USB_DEVICE_ID_3M1968) },
+ { .driver_data = MT_CLS_3M,
+ HID_USB_DEVICE(USB_VENDOR_ID_3M,
+ USB_DEVICE_ID_3M2256) },
+
+ /* ActionStar panels */
+ { .driver_data = MT_CLS_DEFAULT,
+ HID_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR,
+ USB_DEVICE_ID_ACTIONSTAR_1011) },
+
+ /* Cando panels */
+ { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
+ HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+ USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
+ { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
+ HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+ USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) },
+ { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
+ HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+ USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) },
+ { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
+ HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+ USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
+
+ /* CVTouch panels */
+ { .driver_data = MT_CLS_DEFAULT,
+ HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH,
+ USB_DEVICE_ID_CVTOUCH_SCREEN) },
+
/* Cypress panel */
{ .driver_data = MT_CLS_CYPRESS,
HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS,
USB_DEVICE_ID_CYPRESS_TRUETOUCH) },
+ /* eGalax devices (resistive) */
+ { .driver_data = MT_CLS_EGALAX,
+ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) },
+ { .driver_data = MT_CLS_EGALAX,
+ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) },
+
+ /* eGalax devices (capacitive) */
+ { .driver_data = MT_CLS_EGALAX,
+ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) },
+ { .driver_data = MT_CLS_EGALAX,
+ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) },
+ { .driver_data = MT_CLS_EGALAX,
+ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) },
+
+ /* Elo TouchSystems IntelliTouch Plus panel */
+ { .driver_data = MT_CLS_DUAL_NSMU_CONTACTID,
+ HID_USB_DEVICE(USB_VENDOR_ID_ELO,
+ USB_DEVICE_ID_ELO_TS2515) },
+
/* GeneralTouch panel */
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) },
+ /* GoodTouch panels */
+ { .driver_data = MT_CLS_DEFAULT,
+ HID_USB_DEVICE(USB_VENDOR_ID_GOODTOUCH,
+ USB_DEVICE_ID_GOODTOUCH_000f) },
+
+ /* Ilitek dual touch panel */
+ { .driver_data = MT_CLS_DEFAULT,
+ HID_USB_DEVICE(USB_VENDOR_ID_ILITEK,
+ USB_DEVICE_ID_ILITEK_MULTITOUCH) },
+
/* IRTOUCH panels */
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS,
USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
+ /* Lumio panels */
+ { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
+ HID_USB_DEVICE(USB_VENDOR_ID_LUMIO,
+ USB_DEVICE_ID_CRYSTALTOUCH) },
+
+ /* MosArt panels */
+ { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
+ HID_USB_DEVICE(USB_VENDOR_ID_ASUS,
+ USB_DEVICE_ID_ASUS_T91MT)},
+ { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
+ HID_USB_DEVICE(USB_VENDOR_ID_ASUS,
+ USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) },
+ { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE,
+ HID_USB_DEVICE(USB_VENDOR_ID_TURBOX,
+ USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
+
+ /* PenMount panels */
+ { .driver_data = MT_CLS_CONFIDENCE,
+ HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT,
+ USB_DEVICE_ID_PENMOUNT_PCI) },
+
/* PixCir-based panels */
{ .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
HID_USB_DEVICE(USB_VENDOR_ID_HANVON,
@@ -511,24 +676,29 @@ static const struct hid_device_id mt_devices[] = {
HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) },
- /* Resistive eGalax devices */
- { .driver_data = MT_CLS_EGALAX,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
- USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) },
- { .driver_data = MT_CLS_EGALAX,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
- USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) },
-
- /* Capacitive eGalax devices */
- { .driver_data = MT_CLS_EGALAX,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
- USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) },
- { .driver_data = MT_CLS_EGALAX,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
- USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) },
- { .driver_data = MT_CLS_EGALAX,
- HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
- USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) },
+ /* Stantum panels */
+ { .driver_data = MT_CLS_CONFIDENCE,
+ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM,
+ USB_DEVICE_ID_MTP)},
+ { .driver_data = MT_CLS_CONFIDENCE,
+ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM,
+ USB_DEVICE_ID_MTP_STM)},
+ { .driver_data = MT_CLS_CONFIDENCE,
+ HID_USB_DEVICE(USB_VENDOR_ID_STANTUM,
+ USB_DEVICE_ID_MTP_SITRONIX)},
+
+ /* Touch International panels */
+ { .driver_data = MT_CLS_DEFAULT,
+ HID_USB_DEVICE(USB_VENDOR_ID_TOUCH_INTL,
+ USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH) },
+
+ /* Unitec panels */
+ { .driver_data = MT_CLS_DEFAULT,
+ HID_USB_DEVICE(USB_VENDOR_ID_UNITEC,
+ USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) },
+ { .driver_data = MT_CLS_DEFAULT,
+ HID_USB_DEVICE(USB_VENDOR_ID_UNITEC,
+ USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) },
{ }
};
diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c
index b2f56a13bcf5..9d8710f8bc79 100644
--- a/drivers/hid/hid-picolcd.c
+++ b/drivers/hid/hid-picolcd.c
@@ -1585,11 +1585,11 @@ static ssize_t picolcd_debug_eeprom_write(struct file *f, const char __user *u,
memset(raw_data, 0, sizeof(raw_data));
raw_data[0] = *off & 0xff;
raw_data[1] = (*off >> 8) & 0xff;
- raw_data[2] = s < 20 ? s : 20;
+ raw_data[2] = min((size_t)20, s);
if (*off + raw_data[2] > 0xff)
raw_data[2] = 0x100 - *off;
- if (copy_from_user(raw_data+3, u, raw_data[2]))
+ if (copy_from_user(raw_data+3, u, min((u8)20, raw_data[2])))
return -EFAULT;
resp = picolcd_send_and_wait(data->hdev, REPORT_EE_WRITE, raw_data,
sizeof(raw_data));
diff --git a/drivers/hid/hid-roccat-koneplus.c b/drivers/hid/hid-roccat-koneplus.c
index 33eec74e0615..5b640a7a15a7 100644
--- a/drivers/hid/hid-roccat-koneplus.c
+++ b/drivers/hid/hid-roccat-koneplus.c
@@ -167,28 +167,28 @@ static int koneplus_set_profile_buttons(struct usb_device *usb_dev,
}
/* retval is 0-4 on success, < 0 on error */
-static int koneplus_get_startup_profile(struct usb_device *usb_dev)
+static int koneplus_get_actual_profile(struct usb_device *usb_dev)
{
- struct koneplus_startup_profile buf;
+ struct koneplus_actual_profile buf;
int retval;
- retval = roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_STARTUP_PROFILE,
- &buf, sizeof(struct koneplus_startup_profile));
+ retval = roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_ACTUAL_PROFILE,
+ &buf, sizeof(struct koneplus_actual_profile));
- return retval ? retval : buf.startup_profile;
+ return retval ? retval : buf.actual_profile;
}
-static int koneplus_set_startup_profile(struct usb_device *usb_dev,
- int startup_profile)
+static int koneplus_set_actual_profile(struct usb_device *usb_dev,
+ int new_profile)
{
- struct koneplus_startup_profile buf;
+ struct koneplus_actual_profile buf;
- buf.command = KONEPLUS_COMMAND_STARTUP_PROFILE;
- buf.size = sizeof(struct koneplus_startup_profile);
- buf.startup_profile = startup_profile;
+ buf.command = KONEPLUS_COMMAND_ACTUAL_PROFILE;
+ buf.size = sizeof(struct koneplus_actual_profile);
+ buf.actual_profile = new_profile;
- return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_STARTUP_PROFILE,
- &buf, sizeof(struct koneplus_profile_buttons));
+ return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_ACTUAL_PROFILE,
+ &buf, sizeof(struct koneplus_actual_profile));
}
static ssize_t koneplus_sysfs_read(struct file *fp, struct kobject *kobj,
@@ -398,21 +398,22 @@ static ssize_t koneplus_sysfs_write_profile_buttons(struct file *fp,
return sizeof(struct koneplus_profile_buttons);
}
-static ssize_t koneplus_sysfs_show_startup_profile(struct device *dev,
+static ssize_t koneplus_sysfs_show_actual_profile(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct koneplus_device *koneplus =
hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
- return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->startup_profile);
+ return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->actual_profile);
}
-static ssize_t koneplus_sysfs_set_startup_profile(struct device *dev,
+static ssize_t koneplus_sysfs_set_actual_profile(struct device *dev,
struct device_attribute *attr, char const *buf, size_t size)
{
struct koneplus_device *koneplus;
struct usb_device *usb_dev;
unsigned long profile;
int retval;
+ struct koneplus_roccat_report roccat_report;
dev = dev->parent->parent;
koneplus = hid_get_drvdata(dev_get_drvdata(dev));
@@ -423,20 +424,25 @@ static ssize_t koneplus_sysfs_set_startup_profile(struct device *dev,
return retval;
mutex_lock(&koneplus->koneplus_lock);
- retval = koneplus_set_startup_profile(usb_dev, profile);
- mutex_unlock(&koneplus->koneplus_lock);
- if (retval)
+
+ retval = koneplus_set_actual_profile(usb_dev, profile);
+ if (retval) {
+ mutex_unlock(&koneplus->koneplus_lock);
return retval;
+ }
- return size;
-}
+ koneplus->actual_profile = profile;
-static ssize_t koneplus_sysfs_show_actual_profile(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct koneplus_device *koneplus =
- hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
- return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->actual_profile);
+ roccat_report.type = KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE;
+ roccat_report.data1 = profile + 1;
+ roccat_report.data2 = 0;
+ roccat_report.profile = profile + 1;
+ roccat_report_event(koneplus->chrdev_minor,
+ (uint8_t const *)&roccat_report);
+
+ mutex_unlock(&koneplus->koneplus_lock);
+
+ return size;
}
static ssize_t koneplus_sysfs_show_firmware_version(struct device *dev,
@@ -448,11 +454,12 @@ static ssize_t koneplus_sysfs_show_firmware_version(struct device *dev,
}
static struct device_attribute koneplus_attributes[] = {
+ __ATTR(actual_profile, 0660,
+ koneplus_sysfs_show_actual_profile,
+ koneplus_sysfs_set_actual_profile),
__ATTR(startup_profile, 0660,
- koneplus_sysfs_show_startup_profile,
- koneplus_sysfs_set_startup_profile),
- __ATTR(actual_profile, 0440,
- koneplus_sysfs_show_actual_profile, NULL),
+ koneplus_sysfs_show_actual_profile,
+ koneplus_sysfs_set_actual_profile),
__ATTR(firmware_version, 0440,
koneplus_sysfs_show_firmware_version, NULL),
__ATTR_NULL
@@ -557,15 +564,10 @@ static int koneplus_init_koneplus_device_struct(struct usb_device *usb_dev,
struct koneplus_device *koneplus)
{
int retval, i;
- static uint wait = 100; /* device will freeze with just 60 */
+ static uint wait = 200;
mutex_init(&koneplus->koneplus_lock);
- koneplus->startup_profile = koneplus_get_startup_profile(usb_dev);
- if (koneplus->startup_profile < 0)
- return koneplus->startup_profile;
-
- msleep(wait);
retval = koneplus_get_info(usb_dev, &koneplus->info);
if (retval)
return retval;
@@ -584,7 +586,11 @@ static int koneplus_init_koneplus_device_struct(struct usb_device *usb_dev,
return retval;
}
- koneplus_profile_activated(koneplus, koneplus->startup_profile);
+ msleep(wait);
+ retval = koneplus_get_actual_profile(usb_dev);
+ if (retval < 0)
+ return retval;
+ koneplus_profile_activated(koneplus, retval);
return 0;
}
diff --git a/drivers/hid/hid-roccat-koneplus.h b/drivers/hid/hid-roccat-koneplus.h
index 57a5c1ab7b05..c57a376ab8ae 100644
--- a/drivers/hid/hid-roccat-koneplus.h
+++ b/drivers/hid/hid-roccat-koneplus.h
@@ -40,10 +40,10 @@ enum koneplus_control_values {
KONEPLUS_CONTROL_REQUEST_STATUS_WAIT = 3,
};
-struct koneplus_startup_profile {
- uint8_t command; /* KONEPLUS_COMMAND_STARTUP_PROFILE */
+struct koneplus_actual_profile {
+ uint8_t command; /* KONEPLUS_COMMAND_ACTUAL_PROFILE */
uint8_t size; /* always 3 */
- uint8_t startup_profile; /* Range 0-4! */
+ uint8_t actual_profile; /* Range 0-4! */
} __attribute__ ((__packed__));
struct koneplus_profile_settings {
@@ -132,7 +132,7 @@ struct koneplus_tcu_image {
enum koneplus_commands {
KONEPLUS_COMMAND_CONTROL = 0x4,
- KONEPLUS_COMMAND_STARTUP_PROFILE = 0x5,
+ KONEPLUS_COMMAND_ACTUAL_PROFILE = 0x5,
KONEPLUS_COMMAND_PROFILE_SETTINGS = 0x6,
KONEPLUS_COMMAND_PROFILE_BUTTONS = 0x7,
KONEPLUS_COMMAND_MACRO = 0x8,
@@ -145,7 +145,7 @@ enum koneplus_commands {
enum koneplus_usb_commands {
KONEPLUS_USB_COMMAND_CONTROL = 0x304,
- KONEPLUS_USB_COMMAND_STARTUP_PROFILE = 0x305,
+ KONEPLUS_USB_COMMAND_ACTUAL_PROFILE = 0x305,
KONEPLUS_USB_COMMAND_PROFILE_SETTINGS = 0x306,
KONEPLUS_USB_COMMAND_PROFILE_BUTTONS = 0x307,
KONEPLUS_USB_COMMAND_MACRO = 0x308,
@@ -215,7 +215,6 @@ struct koneplus_device {
struct mutex koneplus_lock;
- int startup_profile;
struct koneplus_info info;
struct koneplus_profile_settings profile_settings[5];
struct koneplus_profile_buttons profile_buttons[5];
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 93819a08121a..936c911fdca6 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -178,6 +178,8 @@ static void sony_remove(struct hid_device *hdev)
static const struct hid_device_id sony_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER),
.driver_data = SIXAXIS_CONTROLLER_USB },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER),
+ .driver_data = SIXAXIS_CONTROLLER_USB },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER),
.driver_data = SIXAXIS_CONTROLLER_BT },
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE),
diff --git a/drivers/hid/hid-stantum.c b/drivers/hid/hid-stantum.c
deleted file mode 100644
index b2be1d11916b..000000000000
--- a/drivers/hid/hid-stantum.c
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * HID driver for Stantum multitouch panels
- *
- * Copyright (c) 2009 Stephane Chatty <chatty@enac.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.
- */
-
-#include <linux/device.h>
-#include <linux/hid.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-
-MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
-MODULE_DESCRIPTION("Stantum HID multitouch panels");
-MODULE_LICENSE("GPL");
-
-#include "hid-ids.h"
-
-struct stantum_data {
- __s32 x, y, z, w, h; /* x, y, pressure, width, height */
- __u16 id; /* touch id */
- bool valid; /* valid finger data, or just placeholder? */
- bool first; /* first finger in the HID packet? */
- bool activity; /* at least one active finger so far? */
-};
-
-static int stantum_input_mapping(struct hid_device *hdev, struct hid_input *hi,
- struct hid_field *field, struct hid_usage *usage,
- unsigned long **bit, int *max)
-{
- switch (usage->hid & HID_USAGE_PAGE) {
-
- case HID_UP_GENDESK:
- switch (usage->hid) {
- case HID_GD_X:
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_POSITION_X);
- /* touchscreen emulation */
- input_set_abs_params(hi->input, ABS_X,
- field->logical_minimum,
- field->logical_maximum, 0, 0);
- return 1;
- case HID_GD_Y:
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_POSITION_Y);
- /* touchscreen emulation */
- input_set_abs_params(hi->input, ABS_Y,
- field->logical_minimum,
- field->logical_maximum, 0, 0);
- return 1;
- }
- return 0;
-
- case HID_UP_DIGITIZER:
- switch (usage->hid) {
- case HID_DG_INRANGE:
- case HID_DG_CONFIDENCE:
- case HID_DG_INPUTMODE:
- case HID_DG_DEVICEINDEX:
- case HID_DG_CONTACTCOUNT:
- case HID_DG_CONTACTMAX:
- return -1;
-
- case HID_DG_TIPSWITCH:
- /* touchscreen emulation */
- hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
- return 1;
-
- case HID_DG_WIDTH:
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_TOUCH_MAJOR);
- return 1;
- case HID_DG_HEIGHT:
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_TOUCH_MINOR);
- input_set_abs_params(hi->input, ABS_MT_ORIENTATION,
- 1, 1, 0, 0);
- return 1;
- case HID_DG_TIPPRESSURE:
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_PRESSURE);
- return 1;
-
- case HID_DG_CONTACTID:
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_TRACKING_ID);
- return 1;
-
- }
- return 0;
-
- case 0xff000000:
- /* no input-oriented meaning */
- return -1;
- }
-
- return 0;
-}
-
-static int stantum_input_mapped(struct hid_device *hdev, struct hid_input *hi,
- struct hid_field *field, struct hid_usage *usage,
- unsigned long **bit, int *max)
-{
- if (usage->type == EV_KEY || usage->type == EV_ABS)
- clear_bit(usage->code, *bit);
-
- return 0;
-}
-
-/*
- * this function is called when a whole finger has been parsed,
- * so that it can decide what to send to the input layer.
- */
-static void stantum_filter_event(struct stantum_data *sd,
- struct input_dev *input)
-{
- bool wide;
-
- if (!sd->valid) {
- /*
- * touchscreen emulation: if the first finger is not valid and
- * there previously was finger activity, this is a release
- */
- if (sd->first && sd->activity) {
- input_event(input, EV_KEY, BTN_TOUCH, 0);
- sd->activity = false;
- }
- return;
- }
-
- input_event(input, EV_ABS, ABS_MT_TRACKING_ID, sd->id);
- input_event(input, EV_ABS, ABS_MT_POSITION_X, sd->x);
- input_event(input, EV_ABS, ABS_MT_POSITION_Y, sd->y);
-
- wide = (sd->w > sd->h);
- input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
- input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, wide ? sd->w : sd->h);
- input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, wide ? sd->h : sd->w);
-
- input_event(input, EV_ABS, ABS_MT_PRESSURE, sd->z);
-
- input_mt_sync(input);
- sd->valid = false;
-
- /* touchscreen emulation */
- if (sd->first) {
- if (!sd->activity) {
- input_event(input, EV_KEY, BTN_TOUCH, 1);
- sd->activity = true;
- }
- input_event(input, EV_ABS, ABS_X, sd->x);
- input_event(input, EV_ABS, ABS_Y, sd->y);
- }
- sd->first = false;
-}
-
-
-static int stantum_event(struct hid_device *hid, struct hid_field *field,
- struct hid_usage *usage, __s32 value)
-{
- struct stantum_data *sd = hid_get_drvdata(hid);
-
- if (hid->claimed & HID_CLAIMED_INPUT) {
- struct input_dev *input = field->hidinput->input;
-
- switch (usage->hid) {
- case HID_DG_INRANGE:
- /* this is the last field in a finger */
- stantum_filter_event(sd, input);
- break;
- case HID_DG_WIDTH:
- sd->w = value;
- break;
- case HID_DG_HEIGHT:
- sd->h = value;
- break;
- case HID_GD_X:
- sd->x = value;
- break;
- case HID_GD_Y:
- sd->y = value;
- break;
- case HID_DG_TIPPRESSURE:
- sd->z = value;
- break;
- case HID_DG_CONTACTID:
- sd->id = value;
- break;
- case HID_DG_CONFIDENCE:
- sd->valid = !!value;
- break;
- case 0xff000002:
- /* this comes only before the first finger */
- sd->first = true;
- break;
-
- default:
- /* ignore the others */
- return 1;
- }
- }
-
- /* we have handled the hidinput part, now remains hiddev */
- if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
- hid->hiddev_hid_event(hid, field, usage, value);
-
- return 1;
-}
-
-static int stantum_probe(struct hid_device *hdev,
- const struct hid_device_id *id)
-{
- int ret;
- struct stantum_data *sd;
-
- sd = kmalloc(sizeof(struct stantum_data), GFP_KERNEL);
- if (!sd) {
- hid_err(hdev, "cannot allocate Stantum data\n");
- return -ENOMEM;
- }
- sd->valid = false;
- sd->first = false;
- sd->activity = false;
- hid_set_drvdata(hdev, sd);
-
- ret = hid_parse(hdev);
- if (!ret)
- ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
-
- if (ret)
- kfree(sd);
-
- return ret;
-}
-
-static void stantum_remove(struct hid_device *hdev)
-{
- hid_hw_stop(hdev);
- kfree(hid_get_drvdata(hdev));
- hid_set_drvdata(hdev, NULL);
-}
-
-static const struct hid_device_id stantum_devices[] = {
- { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM, USB_DEVICE_ID_MTP) },
- { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_MTP_STM) },
- { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX, USB_DEVICE_ID_MTP_SITRONIX) },
- { }
-};
-MODULE_DEVICE_TABLE(hid, stantum_devices);
-
-static const struct hid_usage_id stantum_grabbed_usages[] = {
- { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
- { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
-};
-
-static struct hid_driver stantum_driver = {
- .name = "stantum",
- .id_table = stantum_devices,
- .probe = stantum_probe,
- .remove = stantum_remove,
- .input_mapping = stantum_input_mapping,
- .input_mapped = stantum_input_mapped,
- .usage_table = stantum_grabbed_usages,
- .event = stantum_event,
-};
-
-static int __init stantum_init(void)
-{
- return hid_register_driver(&stantum_driver);
-}
-
-static void __exit stantum_exit(void)
-{
- hid_unregister_driver(&stantum_driver);
-}
-
-module_init(stantum_init);
-module_exit(stantum_exit);
-
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 54409cba018c..c79578b5a788 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -101,8 +101,8 @@ out:
return ret;
}
-/* the first byte is expected to be a report number */
-/* This function is to be called with the minors_lock mutex held */
+/* The first byte is expected to be a report number.
+ * This function is to be called with the minors_lock mutex held */
static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, size_t count, unsigned char report_type)
{
unsigned int minor = iminor(file->f_path.dentry->d_inode);
@@ -166,11 +166,11 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t
/* This function performs a Get_Report transfer over the control endpoint
- per section 7.2.1 of the HID specification, version 1.1. The first byte
- of buffer is the report number to request, or 0x0 if the defice does not
- use numbered reports. The report_type parameter can be HID_FEATURE_REPORT
- or HID_INPUT_REPORT. This function is to be called with the minors_lock
- mutex held. */
+ * per section 7.2.1 of the HID specification, version 1.1. The first byte
+ * of buffer is the report number to request, or 0x0 if the defice does not
+ * use numbered reports. The report_type parameter can be HID_FEATURE_REPORT
+ * or HID_INPUT_REPORT. This function is to be called with the minors_lock
+ * mutex held. */
static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t count, unsigned char report_type)
{
unsigned int minor = iminor(file->f_path.dentry->d_inode);
@@ -207,7 +207,7 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t
}
/* Read the first byte from the user. This is the report number,
- which is passed to dev->hid_get_raw_report(). */
+ * which is passed to dev->hid_get_raw_report(). */
if (copy_from_user(&report_number, buffer, 1)) {
ret = -EFAULT;
goto out_free;
@@ -395,12 +395,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
}
if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWNAME(0))) {
- int len;
- if (!hid->name) {
- ret = 0;
- break;
- }
- len = strlen(hid->name) + 1;
+ int len = strlen(hid->name) + 1;
if (len > _IOC_SIZE(cmd))
len = _IOC_SIZE(cmd);
ret = copy_to_user(user_arg, hid->name, len) ?
@@ -409,12 +404,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
}
if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWPHYS(0))) {
- int len;
- if (!hid->phys) {
- ret = 0;
- break;
- }
- len = strlen(hid->phys) + 1;
+ int len = strlen(hid->phys) + 1;
if (len > _IOC_SIZE(cmd))
len = _IOC_SIZE(cmd);
ret = copy_to_user(user_arg, hid->phys, len) ?
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index a8426f15e9ab..0e30b140edca 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -68,6 +68,8 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_1, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_2, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U, HID_QUIRK_MULTI_INPUT },
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index af0a7c1002af..ff3c644888b1 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -242,6 +242,7 @@ static int hiddev_release(struct inode * inode, struct file * file)
list_del(&list->node);
spin_unlock_irqrestore(&list->hiddev->list_lock, flags);
+ mutex_lock(&list->hiddev->existancelock);
if (!--list->hiddev->open) {
if (list->hiddev->exist) {
usbhid_close(list->hiddev->hid);
@@ -252,6 +253,7 @@ static int hiddev_release(struct inode * inode, struct file * file)
}
kfree(list);
+ mutex_unlock(&list->hiddev->existancelock);
return 0;
}
@@ -300,17 +302,21 @@ static int hiddev_open(struct inode *inode, struct file *file)
list_add_tail(&list->node, &hiddev->list);
spin_unlock_irq(&list->hiddev->list_lock);
+ mutex_lock(&hiddev->existancelock);
if (!list->hiddev->open++)
if (list->hiddev->exist) {
struct hid_device *hid = hiddev->hid;
res = usbhid_get_power(hid);
if (res < 0) {
res = -EIO;
- goto bail;
+ goto bail_unlock;
}
usbhid_open(hid);
}
+ mutex_unlock(&hiddev->existancelock);
return 0;
+bail_unlock:
+ mutex_unlock(&hiddev->existancelock);
bail:
file->private_data = NULL;
kfree(list);
@@ -367,8 +373,10 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun
/* let O_NONBLOCK tasks run */
mutex_unlock(&list->thread_lock);
schedule();
- if (mutex_lock_interruptible(&list->thread_lock))
+ if (mutex_lock_interruptible(&list->thread_lock)) {
+ finish_wait(&list->hiddev->wait, &wait);
return -EINTR;
+ }
set_current_state(TASK_INTERRUPTIBLE);
}
finish_wait(&list->hiddev->wait, &wait);
@@ -509,7 +517,7 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd,
(uref_multi->num_values > HID_MAX_MULTI_USAGES ||
uref->usage_index + uref_multi->num_values > field->report_count))
goto inval;
- }
+ }
switch (cmd) {
case HIDIOCGUSAGE:
@@ -801,14 +809,7 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) {
- int len;
-
- if (!hid->name) {
- r = 0;
- break;
- }
-
- len = strlen(hid->name) + 1;
+ int len = strlen(hid->name) + 1;
if (len > _IOC_SIZE(cmd))
len = _IOC_SIZE(cmd);
r = copy_to_user(user_arg, hid->name, len) ?
@@ -817,14 +818,7 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) {
- int len;
-
- if (!hid->phys) {
- r = 0;
- break;
- }
-
- len = strlen(hid->phys) + 1;
+ int len = strlen(hid->phys) + 1;
if (len > _IOC_SIZE(cmd))
len = _IOC_SIZE(cmd);
r = copy_to_user(user_arg, hid->phys, len) ?
@@ -925,7 +919,6 @@ void hiddev_disconnect(struct hid_device *hid)
mutex_lock(&hiddev->existancelock);
hiddev->exist = 0;
- mutex_unlock(&hiddev->existancelock);
usb_deregister_dev(usbhid->intf, &hiddev_class);
@@ -935,4 +928,5 @@ void hiddev_disconnect(struct hid_device *hid)
} else {
kfree(hiddev);
}
+ mutex_unlock(&hiddev->existancelock);
}
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 50e40dbd8bb6..16db83c83c8b 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -41,7 +41,7 @@ comment "Native drivers"
config SENSORS_ABITUGURU
tristate "Abit uGuru (rev 1 & 2)"
- depends on X86 && EXPERIMENTAL
+ depends on X86 && DMI && EXPERIMENTAL
help
If you say yes here you get support for the sensor part of the first
and second revision of the Abit uGuru chip. The voltage and frequency
@@ -56,7 +56,7 @@ config SENSORS_ABITUGURU
config SENSORS_ABITUGURU3
tristate "Abit uGuru (rev 3)"
- depends on X86 && EXPERIMENTAL
+ depends on X86 && DMI && EXPERIMENTAL
help
If you say yes here you get support for the sensor part of the
third revision of the Abit uGuru chip. Only reading the sensors
@@ -213,7 +213,7 @@ config SENSORS_ADT7475
config SENSORS_ASC7621
tristate "Andigilog aSC7621"
- depends on HWMON && I2C
+ depends on I2C
help
If you say yes here you get support for the aSC7621
family of SMBus sensors chip found on most Intel X38, X48, X58,
@@ -237,17 +237,27 @@ config SENSORS_K8TEMP
will be called k8temp.
config SENSORS_K10TEMP
- tristate "AMD Family 10h/11h/12h/14h temperature sensor"
+ tristate "AMD Family 10h+ temperature sensor"
depends on X86 && PCI
help
If you say yes here you get support for the temperature
sensor(s) inside your CPU. Supported are later revisions of
the AMD Family 10h and all revisions of the AMD Family 11h,
- 12h (Llano), and 14h (Brazos) microarchitectures.
+ 12h (Llano), 14h (Brazos) and 15h (Bulldozer) microarchitectures.
This driver can also be built as a module. If so, the module
will be called k10temp.
+config SENSORS_FAM15H_POWER
+ tristate "AMD Family 15h processor power"
+ depends on X86 && PCI
+ help
+ If you say yes here you get support for processor power
+ information of your AMD family 15h CPU.
+
+ This driver can also be built as a module. If so, the module
+ will be called fam15h_power.
+
config SENSORS_ASB100
tristate "Asus ASB100 Bach"
depends on X86 && I2C && EXPERIMENTAL
@@ -319,7 +329,7 @@ config SENSORS_F71882FG
If you say yes here you get support for hardware monitoring
features of many Fintek Super-I/O (LPC) chips. The currently
supported chips are:
- F71808E
+ F71808E/A
F71858FG
F71862FG
F71863FG
@@ -408,13 +418,6 @@ config SENSORS_CORETEMP
sensor inside your CPU. Most of the family 6 CPUs
are supported. Check Documentation/hwmon/coretemp for details.
-config SENSORS_PKGTEMP
- tristate "Intel processor package temperature sensor"
- depends on X86 && 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
@@ -708,6 +711,22 @@ config SENSORS_MAX1111
This driver can also be built as a module. If so, the module
will be called max1111.
+config SENSORS_MAX16065
+ tristate "Maxim MAX16065 System Manager and compatibles"
+ depends on I2C
+ help
+ If you say yes here you get support for hardware monitoring
+ capabilities of the following Maxim System Manager chips.
+ MAX16065
+ MAX16066
+ MAX16067
+ MAX16068
+ MAX16070
+ MAX16071
+
+ This driver can also be built as a module. If so, the module
+ will be called max16065.
+
config SENSORS_MAX1619
tristate "Maxim MAX1619 sensor chip"
depends on I2C
@@ -727,6 +746,17 @@ config SENSORS_MAX6639
This driver can also be built as a module. If so, the module
will be called max6639.
+config SENSORS_MAX6642
+ tristate "Maxim MAX6642 sensor chip"
+ depends on I2C && EXPERIMENTAL
+ help
+ If you say yes here you get support for MAX6642 sensor chip.
+ MAX6642 is a SMBus-Compatible Remote/Local Temperature Sensor
+ with Overtemperature Alarm from Maxim.
+
+ This driver can also be built as a module. If so, the module
+ will be called max6642.
+
config SENSORS_MAX6650
tristate "Maxim MAX6650 sensor chip"
depends on I2C && EXPERIMENTAL
@@ -800,6 +830,16 @@ config SENSORS_PMBUS
This driver can also be built as a module. If so, the module will
be called pmbus.
+config SENSORS_ADM1275
+ tristate "Analog Devices ADM1275"
+ default n
+ help
+ If you say yes here you get hardware monitoring support for Analog
+ Devices ADM1275 Hot-Swap Controller and Digital Power Monitor.
+
+ This driver can also be built as a module. If so, the module will
+ be called adm1275.
+
config SENSORS_MAX16064
tristate "Maxim MAX16064"
default n
@@ -830,6 +870,28 @@ config SENSORS_MAX8688
This driver can also be built as a module. If so, the module will
be called max8688.
+config SENSORS_UCD9000
+ tristate "TI UCD90120, UCD90124, UCD9090, UCD90910"
+ default n
+ help
+ If you say yes here you get hardware monitoring support for TI
+ UCD90120, UCD90124, UCD9090, UCD90910 Sequencer and System Health
+ Controllers.
+
+ This driver can also be built as a module. If so, the module will
+ be called ucd9000.
+
+config SENSORS_UCD9200
+ tristate "TI UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, UCD9248"
+ default n
+ help
+ If you say yes here you get hardware monitoring support for TI
+ UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, and UCD9248
+ Digital PWM System Controllers.
+
+ This driver can also be built as a module. If so, the module will
+ be called ucd9200.
+
endif # PMBUS
config SENSORS_SHT15
@@ -926,6 +988,16 @@ config SENSORS_EMC2103
This driver can also be built as a module. If so, the module
will be called emc2103.
+config SENSORS_EMC6W201
+ tristate "SMSC EMC6W201"
+ depends on I2C
+ help
+ If you say yes here you get support for the SMSC EMC6W201
+ hardware monitoring chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called emc6w201.
+
config SENSORS_SMSC47M1
tristate "SMSC LPC47M10x and compatibles"
help
@@ -1289,6 +1361,16 @@ if ACPI
comment "ACPI drivers"
+config SENSORS_ACPI_POWER
+ tristate "ACPI 4.0 power meter"
+ help
+ This driver exposes ACPI 4.0 power meters as hardware monitoring
+ devices. Say Y (or M) if you have a computer with ACPI 4.0 firmware
+ and a power meter.
+
+ To compile this driver as a module, choose M here:
+ the module will be called acpi_power_meter.
+
config SENSORS_ATK0110
tristate "ASUS ATK0110"
depends on X86 && EXPERIMENTAL
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 967d0ea9447f..28061cfa0cdb 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_HWMON) += hwmon.o
obj-$(CONFIG_HWMON_VID) += hwmon-vid.o
# APCI drivers
+obj-$(CONFIG_SENSORS_ACPI_POWER) += acpi_power_meter.o
obj-$(CONFIG_SENSORS_ATK0110) += asus_atk0110.o
# Native drivers
@@ -40,15 +41,16 @@ obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
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_DS620) += ds620.o
obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o
obj-$(CONFIG_SENSORS_EMC2103) += emc2103.o
+obj-$(CONFIG_SENSORS_EMC6W201) += emc6w201.o
obj-$(CONFIG_SENSORS_F71805F) += f71805f.o
obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o
obj-$(CONFIG_SENSORS_F75375S) += f75375s.o
+obj-$(CONFIG_SENSORS_FAM15H_POWER) += fam15h_power.o
obj-$(CONFIG_SENSORS_FSCHMD) += fschmd.o
obj-$(CONFIG_SENSORS_G760A) += g760a.o
obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
@@ -83,8 +85,10 @@ obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o
obj-$(CONFIG_SENSORS_LTC4245) += ltc4245.o
obj-$(CONFIG_SENSORS_LTC4261) += ltc4261.o
obj-$(CONFIG_SENSORS_MAX1111) += max1111.o
+obj-$(CONFIG_SENSORS_MAX16065) += max16065.o
obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
obj-$(CONFIG_SENSORS_MAX6639) += max6639.o
+obj-$(CONFIG_SENSORS_MAX6642) += max6642.o
obj-$(CONFIG_SENSORS_MAX6650) += max6650.o
obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
@@ -118,9 +122,12 @@ obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o
# PMBus drivers
obj-$(CONFIG_PMBUS) += pmbus_core.o
obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o
+obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o
obj-$(CONFIG_SENSORS_MAX16064) += max16064.o
obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
obj-$(CONFIG_SENSORS_MAX8688) += max8688.o
+obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o
+obj-$(CONFIG_SENSORS_UCD9200) += ucd9200.o
ccflags-$(CONFIG_HWMON_DEBUG_CHIP) := -DDEBUG
diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c
index e7d4c4687f02..65a35cf5b3c5 100644
--- a/drivers/hwmon/abituguru.c
+++ b/drivers/hwmon/abituguru.c
@@ -1448,15 +1448,12 @@ static int __init abituguru_init(void)
{
int address, err;
struct resource res = { .flags = IORESOURCE_IO };
-
-#ifdef CONFIG_DMI
const char *board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
/* safety check, refuse to load on non Abit motherboards */
if (!force && (!board_vendor ||
strcmp(board_vendor, "http://www.abit.com.tw/")))
return -ENODEV;
-#endif
address = abituguru_detect();
if (address < 0)
diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c
index e89d572e3320..d30855a75786 100644
--- a/drivers/hwmon/abituguru3.c
+++ b/drivers/hwmon/abituguru3.c
@@ -1119,8 +1119,6 @@ static struct platform_driver abituguru3_driver = {
.resume = abituguru3_resume
};
-#ifdef CONFIG_DMI
-
static int __init abituguru3_dmi_detect(void)
{
const char *board_vendor, *board_name;
@@ -1159,15 +1157,6 @@ static int __init abituguru3_dmi_detect(void)
return 1;
}
-#else /* !CONFIG_DMI */
-
-static inline int abituguru3_dmi_detect(void)
-{
- return 1;
-}
-
-#endif /* CONFIG_DMI */
-
/* FIXME: Manual detection should die eventually; we need to collect stable
* DMI model names first before we can rely entirely on CONFIG_DMI.
*/
@@ -1216,10 +1205,8 @@ static int __init abituguru3_init(void)
if (err)
return err;
-#ifdef CONFIG_DMI
pr_warn("this motherboard was not detected using DMI. "
"Please send the output of \"dmidecode\" to the abituguru3 maintainer (see MAINTAINERS)\n");
-#endif
}
err = platform_driver_register(&abituguru3_driver);
diff --git a/drivers/acpi/power_meter.c b/drivers/hwmon/acpi_power_meter.c
index 66f67293341e..66f67293341e 100644
--- a/drivers/acpi/power_meter.c
+++ b/drivers/hwmon/acpi_power_meter.c
diff --git a/drivers/hwmon/adcxx.c b/drivers/hwmon/adcxx.c
index fbdc7655303b..b2cacbe707a8 100644
--- a/drivers/hwmon/adcxx.c
+++ b/drivers/hwmon/adcxx.c
@@ -62,7 +62,7 @@ static ssize_t adcxx_read(struct device *dev,
{
struct spi_device *spi = to_spi_device(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct adcxx *adc = dev_get_drvdata(&spi->dev);
+ struct adcxx *adc = spi_get_drvdata(spi);
u8 tx_buf[2];
u8 rx_buf[2];
int status;
@@ -105,7 +105,7 @@ static ssize_t adcxx_show_max(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct spi_device *spi = to_spi_device(dev);
- struct adcxx *adc = dev_get_drvdata(&spi->dev);
+ struct adcxx *adc = spi_get_drvdata(spi);
u32 reference;
if (mutex_lock_interruptible(&adc->lock))
@@ -122,7 +122,7 @@ static ssize_t adcxx_set_max(struct device *dev,
struct device_attribute *devattr, const char *buf, size_t count)
{
struct spi_device *spi = to_spi_device(dev);
- struct adcxx *adc = dev_get_drvdata(&spi->dev);
+ struct adcxx *adc = spi_get_drvdata(spi);
unsigned long value;
if (strict_strtoul(buf, 10, &value))
@@ -142,7 +142,7 @@ static ssize_t adcxx_show_name(struct device *dev, struct device_attribute
*devattr, char *buf)
{
struct spi_device *spi = to_spi_device(dev);
- struct adcxx *adc = dev_get_drvdata(&spi->dev);
+ struct adcxx *adc = spi_get_drvdata(spi);
return sprintf(buf, "adcxx%ds\n", adc->channels);
}
@@ -182,7 +182,7 @@ static int __devinit adcxx_probe(struct spi_device *spi)
mutex_lock(&adc->lock);
- dev_set_drvdata(&spi->dev, adc);
+ spi_set_drvdata(spi, adc);
for (i = 0; i < 3 + adc->channels; i++) {
status = device_create_file(&spi->dev, &ad_input[i].dev_attr);
@@ -206,7 +206,7 @@ out_err:
for (i--; i >= 0; i--)
device_remove_file(&spi->dev, &ad_input[i].dev_attr);
- dev_set_drvdata(&spi->dev, NULL);
+ spi_set_drvdata(spi, NULL);
mutex_unlock(&adc->lock);
kfree(adc);
return status;
@@ -214,7 +214,7 @@ out_err:
static int __devexit adcxx_remove(struct spi_device *spi)
{
- struct adcxx *adc = dev_get_drvdata(&spi->dev);
+ struct adcxx *adc = spi_get_drvdata(spi);
int i;
mutex_lock(&adc->lock);
@@ -222,7 +222,7 @@ static int __devexit adcxx_remove(struct spi_device *spi)
for (i = 0; i < 3 + adc->channels; i++)
device_remove_file(&spi->dev, &ad_input[i].dev_attr);
- dev_set_drvdata(&spi->dev, NULL);
+ spi_set_drvdata(spi, NULL);
mutex_unlock(&adc->lock);
kfree(adc);
diff --git a/drivers/hwmon/adm1275.c b/drivers/hwmon/adm1275.c
new file mode 100644
index 000000000000..c2ee2048ab91
--- /dev/null
+++ b/drivers/hwmon/adm1275.c
@@ -0,0 +1,121 @@
+/*
+ * Hardware monitoring driver for Analog Devices ADM1275 Hot-Swap Controller
+ * and Digital Power Monitor
+ *
+ * Copyright (c) 2011 Ericsson AB.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include "pmbus.h"
+
+#define ADM1275_PMON_CONFIG 0xd4
+
+#define ADM1275_VIN_VOUT_SELECT (1 << 6)
+#define ADM1275_VRANGE (1 << 5)
+
+static int adm1275_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int config;
+ struct pmbus_driver_info *info;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_BYTE_DATA))
+ return -ENODEV;
+
+ info = kzalloc(sizeof(struct pmbus_driver_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ config = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG);
+ if (config < 0)
+ return config;
+
+ info->pages = 1;
+ info->direct[PSC_VOLTAGE_IN] = true;
+ info->direct[PSC_VOLTAGE_OUT] = true;
+ info->direct[PSC_CURRENT_OUT] = true;
+ info->m[PSC_CURRENT_OUT] = 800;
+ info->b[PSC_CURRENT_OUT] = 20475;
+ info->R[PSC_CURRENT_OUT] = -1;
+ info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
+
+ if (config & ADM1275_VRANGE) {
+ info->m[PSC_VOLTAGE_IN] = 19045;
+ info->b[PSC_VOLTAGE_IN] = 0;
+ info->R[PSC_VOLTAGE_IN] = -2;
+ info->m[PSC_VOLTAGE_OUT] = 19045;
+ info->b[PSC_VOLTAGE_OUT] = 0;
+ info->R[PSC_VOLTAGE_OUT] = -2;
+ } else {
+ info->m[PSC_VOLTAGE_IN] = 6666;
+ info->b[PSC_VOLTAGE_IN] = 0;
+ info->R[PSC_VOLTAGE_IN] = -1;
+ info->m[PSC_VOLTAGE_OUT] = 6666;
+ info->b[PSC_VOLTAGE_OUT] = 0;
+ info->R[PSC_VOLTAGE_OUT] = -1;
+ }
+
+ if (config & ADM1275_VIN_VOUT_SELECT)
+ info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
+ else
+ info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT;
+
+ return pmbus_do_probe(client, id, info);
+}
+
+static int adm1275_remove(struct i2c_client *client)
+{
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
+ int ret;
+
+ ret = pmbus_do_remove(client);
+ kfree(info);
+ return ret;
+}
+
+static const struct i2c_device_id adm1275_id[] = {
+ {"adm1275", 0},
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, adm1275_id);
+
+static struct i2c_driver adm1275_driver = {
+ .driver = {
+ .name = "adm1275",
+ },
+ .probe = adm1275_probe,
+ .remove = adm1275_remove,
+ .id_table = adm1275_id,
+};
+
+static int __init adm1275_init(void)
+{
+ return i2c_add_driver(&adm1275_driver);
+}
+
+static void __exit adm1275_exit(void)
+{
+ i2c_del_driver(&adm1275_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275");
+MODULE_LICENSE("GPL");
+module_init(adm1275_init);
+module_exit(adm1275_exit);
diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c
index 194ca0aa8b0c..de3d2465fe24 100644
--- a/drivers/hwmon/coretemp.c
+++ b/drivers/hwmon/coretemp.c
@@ -35,128 +35,154 @@
#include <linux/platform_device.h>
#include <linux/cpu.h>
#include <linux/pci.h>
+#include <linux/smp.h>
#include <asm/msr.h>
#include <asm/processor.h>
-#include <asm/smp.h>
#define DRVNAME "coretemp"
-typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_TTARGET, SHOW_LABEL,
- SHOW_NAME } SHOW;
+#define BASE_SYSFS_ATTR_NO 2 /* Sysfs Base attr no for coretemp */
+#define NUM_REAL_CORES 16 /* Number of Real cores per cpu */
+#define CORETEMP_NAME_LENGTH 17 /* String Length of attrs */
+#define MAX_ATTRS 5 /* Maximum no of per-core attrs */
+#define MAX_CORE_DATA (NUM_REAL_CORES + BASE_SYSFS_ATTR_NO)
+
+#ifdef CONFIG_SMP
+#define TO_PHYS_ID(cpu) cpu_data(cpu).phys_proc_id
+#define TO_CORE_ID(cpu) cpu_data(cpu).cpu_core_id
+#define TO_ATTR_NO(cpu) (TO_CORE_ID(cpu) + BASE_SYSFS_ATTR_NO)
+#define for_each_sibling(i, cpu) for_each_cpu(i, cpu_sibling_mask(cpu))
+#else
+#define TO_PHYS_ID(cpu) (cpu)
+#define TO_CORE_ID(cpu) (cpu)
+#define TO_ATTR_NO(cpu) (cpu)
+#define for_each_sibling(i, cpu) for (i = 0; false; )
+#endif
/*
- * Functions declaration
+ * Per-Core Temperature Data
+ * @last_updated: The time when the current temperature value was updated
+ * earlier (in jiffies).
+ * @cpu_core_id: The CPU Core from which temperature values should be read
+ * This value is passed as "id" field to rdmsr/wrmsr functions.
+ * @status_reg: One of IA32_THERM_STATUS or IA32_PACKAGE_THERM_STATUS,
+ * from where the temperature values should be read.
+ * @is_pkg_data: If this is 1, the temp_data holds pkgtemp data.
+ * Otherwise, temp_data holds coretemp data.
+ * @valid: If this is 1, the current temperature is valid.
*/
-
-static struct coretemp_data *coretemp_update_device(struct device *dev);
-
-struct coretemp_data {
- struct device *hwmon_dev;
- struct mutex update_lock;
- const char *name;
- u32 id;
- u16 core_id;
- char valid; /* zero until following fields are valid */
- unsigned long last_updated; /* in jiffies */
+struct temp_data {
int temp;
- int tjmax;
int ttarget;
- u8 alarm;
+ int tjmax;
+ unsigned long last_updated;
+ unsigned int cpu;
+ u32 cpu_core_id;
+ u32 status_reg;
+ bool is_pkg_data;
+ bool valid;
+ struct sensor_device_attribute sd_attrs[MAX_ATTRS];
+ char attr_name[MAX_ATTRS][CORETEMP_NAME_LENGTH];
+ struct mutex update_lock;
};
-/*
- * Sysfs stuff
- */
+/* Platform Data per Physical CPU */
+struct platform_data {
+ struct device *hwmon_dev;
+ u16 phys_proc_id;
+ struct temp_data *core_data[MAX_CORE_DATA];
+ struct device_attribute name_attr;
+};
-static ssize_t show_name(struct device *dev, struct device_attribute
- *devattr, char *buf)
+struct pdev_entry {
+ struct list_head list;
+ struct platform_device *pdev;
+ unsigned int cpu;
+ u16 phys_proc_id;
+ u16 cpu_core_id;
+};
+
+static LIST_HEAD(pdev_list);
+static DEFINE_MUTEX(pdev_list_mutex);
+
+static ssize_t show_name(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ return sprintf(buf, "%s\n", DRVNAME);
+}
+
+static ssize_t show_label(struct device *dev,
+ struct device_attribute *devattr, char *buf)
{
- int ret;
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct coretemp_data *data = dev_get_drvdata(dev);
+ struct platform_data *pdata = dev_get_drvdata(dev);
+ struct temp_data *tdata = pdata->core_data[attr->index];
- if (attr->index == SHOW_NAME)
- ret = sprintf(buf, "%s\n", data->name);
- else /* show label */
- ret = sprintf(buf, "Core %d\n", data->core_id);
- return ret;
+ if (tdata->is_pkg_data)
+ return sprintf(buf, "Physical id %u\n", pdata->phys_proc_id);
+
+ return sprintf(buf, "Core %u\n", tdata->cpu_core_id);
}
-static ssize_t show_alarm(struct device *dev, struct device_attribute
- *devattr, char *buf)
+static ssize_t show_crit_alarm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
{
- struct coretemp_data *data = coretemp_update_device(dev);
- /* read the Out-of-spec log, never clear */
- return sprintf(buf, "%d\n", data->alarm);
+ u32 eax, edx;
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct platform_data *pdata = dev_get_drvdata(dev);
+ struct temp_data *tdata = pdata->core_data[attr->index];
+
+ rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx);
+
+ return sprintf(buf, "%d\n", (eax >> 5) & 1);
}
-static ssize_t show_temp(struct device *dev,
- struct device_attribute *devattr, char *buf)
+static ssize_t show_tjmax(struct device *dev,
+ struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- struct coretemp_data *data = coretemp_update_device(dev);
- int err;
+ struct platform_data *pdata = dev_get_drvdata(dev);
- 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;
+ return sprintf(buf, "%d\n", pdata->core_data[attr->index]->tjmax);
}
-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 *coretemp_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 ssize_t show_ttarget(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct platform_data *pdata = dev_get_drvdata(dev);
-static const struct attribute_group coretemp_group = {
- .attrs = coretemp_attributes,
-};
+ return sprintf(buf, "%d\n", pdata->core_data[attr->index]->ttarget);
+}
-static struct coretemp_data *coretemp_update_device(struct device *dev)
+static ssize_t show_temp(struct device *dev,
+ struct device_attribute *devattr, char *buf)
{
- struct coretemp_data *data = dev_get_drvdata(dev);
-
- mutex_lock(&data->update_lock);
+ u32 eax, edx;
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct platform_data *pdata = dev_get_drvdata(dev);
+ struct temp_data *tdata = pdata->core_data[attr->index];
- if (!data->valid || time_after(jiffies, data->last_updated + HZ)) {
- u32 eax, edx;
+ mutex_lock(&tdata->update_lock);
- data->valid = 0;
- rdmsr_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx);
- data->alarm = (eax >> 5) & 1;
- /* update only if data has been valid */
+ /* Check whether the time interval has elapsed */
+ if (!tdata->valid || time_after(jiffies, tdata->last_updated + HZ)) {
+ rdmsr_on_cpu(tdata->cpu, tdata->status_reg, &eax, &edx);
+ tdata->valid = 0;
+ /* Check whether the data is valid */
if (eax & 0x80000000) {
- data->temp = data->tjmax - (((eax >> 16)
- & 0x7f) * 1000);
- data->valid = 1;
- } else {
- dev_dbg(dev, "Temperature data invalid (0x%x)\n", eax);
+ tdata->temp = tdata->tjmax -
+ ((eax >> 16) & 0x7f) * 1000;
+ tdata->valid = 1;
}
- data->last_updated = jiffies;
+ tdata->last_updated = jiffies;
}
- mutex_unlock(&data->update_lock);
- return data;
+ mutex_unlock(&tdata->update_lock);
+ return tdata->valid ? sprintf(buf, "%d\n", tdata->temp) : -EAGAIN;
}
-static int __devinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
+static int adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
{
/* The 100C is default for both mobile and non mobile CPUs */
@@ -169,9 +195,8 @@ static int __devinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *
/* Early chips have no MSR for TjMax */
- if ((c->x86_model == 0xf) && (c->x86_mask < 4)) {
+ if (c->x86_model == 0xf && c->x86_mask < 4)
usemsr_ee = 0;
- }
/* Atom CPUs */
@@ -190,14 +215,14 @@ static int __devinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *
pci_dev_put(host_bridge);
}
- if ((c->x86_model > 0xe) && (usemsr_ee)) {
+ if (c->x86_model > 0xe && usemsr_ee) {
u8 platform_id;
- /* Now we can detect the mobile CPU using Intel provided table
- http://softwarecommunity.intel.com/Wiki/Mobility/720.htm
- For Core2 cores, check MSR 0x17, bit 28 1 = Mobile CPU
- */
-
+ /*
+ * Now we can detect the mobile CPU using Intel provided table
+ * http://softwarecommunity.intel.com/Wiki/Mobility/720.htm
+ * For Core2 cores, check MSR 0x17, bit 28 1 = Mobile CPU
+ */
err = rdmsr_safe_on_cpu(id, 0x17, &eax, &edx);
if (err) {
dev_warn(dev,
@@ -205,20 +230,26 @@ static int __devinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *
" CPU\n");
usemsr_ee = 0;
} else if (c->x86_model < 0x17 && !(eax & 0x10000000)) {
- /* Trust bit 28 up to Penryn, I could not find any
- documentation on that; if you happen to know
- someone at Intel please ask */
+ /*
+ * Trust bit 28 up to Penryn, I could not find any
+ * documentation on that; if you happen to know
+ * someone at Intel please ask
+ */
usemsr_ee = 0;
} else {
/* Platform ID bits 52:50 (EDX starts at bit 32) */
platform_id = (edx >> 18) & 0x7;
- /* Mobile Penryn CPU seems to be platform ID 7 or 5
- (guesswork) */
- if ((c->x86_model == 0x17) &&
- ((platform_id == 5) || (platform_id == 7))) {
- /* If MSR EE bit is set, set it to 90 degrees C,
- otherwise 105 degrees C */
+ /*
+ * Mobile Penryn CPU seems to be platform ID 7 or 5
+ * (guesswork)
+ */
+ if (c->x86_model == 0x17 &&
+ (platform_id == 5 || platform_id == 7)) {
+ /*
+ * If MSR EE bit is set, set it to 90 degrees C,
+ * otherwise 105 degrees C
+ */
tjmax_ee = 90000;
tjmax = 105000;
}
@@ -226,7 +257,6 @@ static int __devinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *
}
if (usemsr_ee) {
-
err = rdmsr_safe_on_cpu(id, 0xee, &eax, &edx);
if (err) {
dev_warn(dev,
@@ -235,25 +265,28 @@ static int __devinit adjust_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *
} else if (eax & 0x40000000) {
tjmax = tjmax_ee;
}
- /* if we dont use msr EE it means we are desktop CPU (with exeception
- of Atom) */
} else if (tjmax == 100000) {
+ /*
+ * If we don't use msr EE it means we are desktop CPU
+ * (with exeception of Atom)
+ */
dev_warn(dev, "Using relative temperature scale!\n");
}
return tjmax;
}
-static int __devinit get_tjmax(struct cpuinfo_x86 *c, u32 id,
- struct device *dev)
+static int get_tjmax(struct cpuinfo_x86 *c, u32 id, struct device *dev)
{
/* The 100C is default for both mobile and non mobile CPUs */
int err;
u32 eax, edx;
u32 val;
- /* A new feature of current Intel(R) processors, the
- IA32_TEMPERATURE_TARGET contains the TjMax value */
+ /*
+ * A new feature of current Intel(R) processors, the
+ * IA32_TEMPERATURE_TARGET contains the TjMax value
+ */
err = rdmsr_safe_on_cpu(id, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
if (err) {
dev_warn(dev, "Unable to read TjMax from CPU.\n");
@@ -263,7 +296,7 @@ static int __devinit get_tjmax(struct cpuinfo_x86 *c, u32 id,
* If the TjMax is not plausible, an assumption
* will be used
*/
- if ((val > 80) && (val < 120)) {
+ if (val > 80 && val < 120) {
dev_info(dev, "TjMax is %d C.\n", val);
return val * 1000;
}
@@ -300,115 +333,301 @@ static void __devinit get_ucode_rev_on_cpu(void *edx)
rdmsr(MSR_IA32_UCODE_REV, eax, *(u32 *)edx);
}
-static int __devinit coretemp_probe(struct platform_device *pdev)
+static int get_pkg_tjmax(unsigned int cpu, struct device *dev)
{
- struct coretemp_data *data;
- struct cpuinfo_x86 *c = &cpu_data(pdev->id);
int err;
- u32 eax, edx;
+ u32 eax, edx, val;
- if (!(data = kzalloc(sizeof(struct coretemp_data), GFP_KERNEL))) {
- err = -ENOMEM;
- dev_err(&pdev->dev, "Out of memory\n");
- goto exit;
+ err = rdmsr_safe_on_cpu(cpu, MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
+ if (!err) {
+ val = (eax >> 16) & 0xff;
+ if (val > 80 && val < 120)
+ return val * 1000;
}
+ dev_warn(dev, "Unable to read Pkg-TjMax from CPU:%u\n", cpu);
+ return 100000; /* Default TjMax: 100 degree celsius */
+}
- data->id = pdev->id;
-#ifdef CONFIG_SMP
- data->core_id = c->cpu_core_id;
-#endif
- data->name = "coretemp";
- mutex_init(&data->update_lock);
+static int create_name_attr(struct platform_data *pdata, struct device *dev)
+{
+ sysfs_attr_init(&pdata->name_attr.attr);
+ pdata->name_attr.attr.name = "name";
+ pdata->name_attr.attr.mode = S_IRUGO;
+ pdata->name_attr.show = show_name;
+ return device_create_file(dev, &pdata->name_attr);
+}
- /* test if we can access the THERM_STATUS MSR */
- err = rdmsr_safe_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx);
- if (err) {
- dev_err(&pdev->dev,
- "Unable to access THERM_STATUS MSR, giving up\n");
- goto exit_free;
+static int create_core_attrs(struct temp_data *tdata, struct device *dev,
+ int attr_no)
+{
+ int err, i;
+ static ssize_t (*rd_ptr[MAX_ATTRS]) (struct device *dev,
+ struct device_attribute *devattr, char *buf) = {
+ show_label, show_crit_alarm, show_ttarget,
+ show_temp, show_tjmax };
+ static const char *names[MAX_ATTRS] = {
+ "temp%d_label", "temp%d_crit_alarm",
+ "temp%d_max", "temp%d_input",
+ "temp%d_crit" };
+
+ for (i = 0; i < MAX_ATTRS; i++) {
+ snprintf(tdata->attr_name[i], CORETEMP_NAME_LENGTH, names[i],
+ attr_no);
+ sysfs_attr_init(&tdata->sd_attrs[i].dev_attr.attr);
+ tdata->sd_attrs[i].dev_attr.attr.name = tdata->attr_name[i];
+ tdata->sd_attrs[i].dev_attr.attr.mode = S_IRUGO;
+ tdata->sd_attrs[i].dev_attr.show = rd_ptr[i];
+ tdata->sd_attrs[i].dev_attr.store = NULL;
+ tdata->sd_attrs[i].index = attr_no;
+ err = device_create_file(dev, &tdata->sd_attrs[i].dev_attr);
+ if (err)
+ goto exit_free;
}
+ return 0;
+
+exit_free:
+ while (--i >= 0)
+ device_remove_file(dev, &tdata->sd_attrs[i].dev_attr);
+ return err;
+}
+
+static void update_ttarget(__u8 cpu_model, struct temp_data *tdata,
+ struct device *dev)
+{
+ int err;
+ u32 eax, edx;
+
+ /*
+ * Initialize ttarget value. Eventually this will be
+ * initialized with the value from MSR_IA32_THERM_INTERRUPT
+ * register. If IA32_TEMPERATURE_TARGET is supported, this
+ * value will be over written below.
+ * To Do: Patch to initialize ttarget from MSR_IA32_THERM_INTERRUPT
+ */
+ tdata->ttarget = tdata->tjmax - 20000;
- /* Check if we have problem with errata AE18 of Core processors:
- Readings might stop update when processor visited too deep sleep,
- fixed for stepping D0 (6EC).
- */
+ /*
+ * Read the still undocumented IA32_TEMPERATURE_TARGET. It exists
+ * on older CPUs but not in this register,
+ * Atoms don't have it either.
+ */
+ if (cpu_model > 0xe && cpu_model != 0x1c) {
+ err = rdmsr_safe_on_cpu(tdata->cpu,
+ MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
+ if (err) {
+ dev_warn(dev,
+ "Unable to read IA32_TEMPERATURE_TARGET MSR\n");
+ } else {
+ tdata->ttarget = tdata->tjmax -
+ ((eax >> 8) & 0xff) * 1000;
+ }
+ }
+}
- if ((c->x86_model == 0xe) && (c->x86_mask < 0xc)) {
+static int __devinit chk_ucode_version(struct platform_device *pdev)
+{
+ struct cpuinfo_x86 *c = &cpu_data(pdev->id);
+ int err;
+ u32 edx;
+
+ /*
+ * Check if we have problem with errata AE18 of Core processors:
+ * Readings might stop update when processor visited too deep sleep,
+ * fixed for stepping D0 (6EC).
+ */
+ if (c->x86_model == 0xe && c->x86_mask < 0xc) {
/* check for microcode update */
- err = smp_call_function_single(data->id, get_ucode_rev_on_cpu,
+ err = smp_call_function_single(pdev->id, get_ucode_rev_on_cpu,
&edx, 1);
if (err) {
dev_err(&pdev->dev,
"Cannot determine microcode revision of "
- "CPU#%u (%d)!\n", data->id, err);
- err = -ENODEV;
- goto exit_free;
+ "CPU#%u (%d)!\n", pdev->id, err);
+ return -ENODEV;
} else if (edx < 0x39) {
- err = -ENODEV;
dev_err(&pdev->dev,
"Errata AE18 not fixed, update BIOS or "
"microcode of the CPU!\n");
- goto exit_free;
+ return -ENODEV;
}
}
+ return 0;
+}
+
+static struct platform_device *coretemp_get_pdev(unsigned int cpu)
+{
+ u16 phys_proc_id = TO_PHYS_ID(cpu);
+ struct pdev_entry *p;
+
+ mutex_lock(&pdev_list_mutex);
- data->tjmax = get_tjmax(c, data->id, &pdev->dev);
- platform_set_drvdata(pdev, data);
+ list_for_each_entry(p, &pdev_list, list)
+ if (p->phys_proc_id == phys_proc_id) {
+ mutex_unlock(&pdev_list_mutex);
+ return p->pdev;
+ }
+
+ mutex_unlock(&pdev_list_mutex);
+ return NULL;
+}
+
+static struct temp_data *init_temp_data(unsigned int cpu, int pkg_flag)
+{
+ struct temp_data *tdata;
+
+ tdata = kzalloc(sizeof(struct temp_data), GFP_KERNEL);
+ if (!tdata)
+ return NULL;
+
+ tdata->status_reg = pkg_flag ? MSR_IA32_PACKAGE_THERM_STATUS :
+ MSR_IA32_THERM_STATUS;
+ tdata->is_pkg_data = pkg_flag;
+ tdata->cpu = cpu;
+ tdata->cpu_core_id = TO_CORE_ID(cpu);
+ mutex_init(&tdata->update_lock);
+ return tdata;
+}
+
+static int create_core_data(struct platform_data *pdata,
+ struct platform_device *pdev,
+ unsigned int cpu, int pkg_flag)
+{
+ struct temp_data *tdata;
+ struct cpuinfo_x86 *c = &cpu_data(cpu);
+ u32 eax, edx;
+ int err, attr_no;
/*
- * read the still undocumented IA32_TEMPERATURE_TARGET. It exists
- * on older CPUs but not in this register,
- * Atoms don't have it either.
+ * Find attr number for sysfs:
+ * We map the attr number to core id of the CPU
+ * The attr number is always core id + 2
+ * The Pkgtemp will always show up as temp1_*, if available
*/
+ attr_no = pkg_flag ? 1 : TO_ATTR_NO(cpu);
- if ((c->x86_model > 0xe) && (c->x86_model != 0x1c)) {
- 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;
- }
- }
+ if (attr_no > MAX_CORE_DATA - 1)
+ return -ERANGE;
+
+ /*
+ * Provide a single set of attributes for all HT siblings of a core
+ * to avoid duplicate sensors (the processor ID and core ID of all
+ * HT siblings of a core are the same).
+ * Skip if a HT sibling of this core is already registered.
+ * This is not an error.
+ */
+ if (pdata->core_data[attr_no] != NULL)
+ return 0;
- if ((err = sysfs_create_group(&pdev->dev.kobj, &coretemp_group)))
- goto exit_dev;
+ tdata = init_temp_data(cpu, pkg_flag);
+ if (!tdata)
+ return -ENOMEM;
- 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;
- }
+ /* Test if we can access the status register */
+ err = rdmsr_safe_on_cpu(cpu, tdata->status_reg, &eax, &edx);
+ if (err)
+ goto exit_free;
+
+ /* We can access status register. Get Critical Temperature */
+ if (pkg_flag)
+ tdata->tjmax = get_pkg_tjmax(pdev->id, &pdev->dev);
+ else
+ tdata->tjmax = get_tjmax(c, cpu, &pdev->dev);
+
+ update_ttarget(c->x86_model, tdata, &pdev->dev);
+ pdata->core_data[attr_no] = tdata;
+
+ /* Create sysfs interfaces */
+ err = create_core_attrs(tdata, &pdev->dev, attr_no);
+ if (err)
+ goto exit_free;
+
+ return 0;
+exit_free:
+ kfree(tdata);
+ return err;
+}
+
+static void coretemp_add_core(unsigned int cpu, int pkg_flag)
+{
+ struct platform_data *pdata;
+ struct platform_device *pdev = coretemp_get_pdev(cpu);
+ int err;
+
+ if (!pdev)
+ return;
+
+ pdata = platform_get_drvdata(pdev);
+
+ err = create_core_data(pdata, pdev, cpu, pkg_flag);
+ if (err)
+ dev_err(&pdev->dev, "Adding Core %u failed\n", cpu);
+}
+
+static void coretemp_remove_core(struct platform_data *pdata,
+ struct device *dev, int indx)
+{
+ int i;
+ struct temp_data *tdata = pdata->core_data[indx];
+
+ /* Remove the sysfs attributes */
+ for (i = 0; i < MAX_ATTRS; i++)
+ device_remove_file(dev, &tdata->sd_attrs[i].dev_attr);
+
+ kfree(pdata->core_data[indx]);
+ pdata->core_data[indx] = NULL;
+}
+
+static int __devinit coretemp_probe(struct platform_device *pdev)
+{
+ struct platform_data *pdata;
+ int err;
+
+ /* Check the microcode version of the CPU */
+ err = chk_ucode_version(pdev);
+ if (err)
+ return err;
+
+ /* Initialize the per-package data structures */
+ pdata = kzalloc(sizeof(struct platform_data), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+ err = create_name_attr(pdata, &pdev->dev);
+ if (err)
+ goto exit_free;
+
+ pdata->phys_proc_id = TO_PHYS_ID(pdev->id);
+ platform_set_drvdata(pdev, pdata);
+
+ pdata->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(pdata->hwmon_dev)) {
+ err = PTR_ERR(pdata->hwmon_dev);
+ dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
+ goto exit_name;
+ }
return 0;
-exit_class:
- sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
-exit_dev:
- device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr);
+exit_name:
+ device_remove_file(&pdev->dev, &pdata->name_attr);
+ platform_set_drvdata(pdev, NULL);
exit_free:
- kfree(data);
-exit:
+ kfree(pdata);
return err;
}
static int __devexit coretemp_remove(struct platform_device *pdev)
{
- struct coretemp_data *data = platform_get_drvdata(pdev);
+ struct platform_data *pdata = platform_get_drvdata(pdev);
+ int i;
+
+ for (i = MAX_CORE_DATA - 1; i >= 0; --i)
+ if (pdata->core_data[i])
+ coretemp_remove_core(pdata, &pdev->dev, i);
- hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
- device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr);
+ device_remove_file(&pdev->dev, &pdata->name_attr);
+ hwmon_device_unregister(pdata->hwmon_dev);
platform_set_drvdata(pdev, NULL);
- kfree(data);
+ kfree(pdata);
return 0;
}
@@ -421,50 +640,14 @@ static struct platform_driver coretemp_driver = {
.remove = __devexit_p(coretemp_remove),
};
-struct pdev_entry {
- struct list_head list;
- struct platform_device *pdev;
- unsigned int cpu;
-#ifdef CONFIG_SMP
- u16 phys_proc_id;
- u16 cpu_core_id;
-#endif
-};
-
-static LIST_HEAD(pdev_list);
-static DEFINE_MUTEX(pdev_list_mutex);
-
static int __cpuinit coretemp_device_add(unsigned int cpu)
{
int err;
struct platform_device *pdev;
struct pdev_entry *pdev_entry;
- struct cpuinfo_x86 *c = &cpu_data(cpu);
-
- /*
- * CPUID.06H.EAX[0] indicates whether the CPU has thermal
- * sensors. We check this bit only, all the early CPUs
- * without thermal sensors will be filtered out.
- */
- if (!cpu_has(c, X86_FEATURE_DTS)) {
- pr_info("CPU (model=0x%x) has no thermal sensor\n",
- c->x86_model);
- return 0;
- }
mutex_lock(&pdev_list_mutex);
-#ifdef CONFIG_SMP
- /* Skip second HT entry of each core */
- list_for_each_entry(pdev_entry, &pdev_list, list) {
- if (c->phys_proc_id == pdev_entry->phys_proc_id &&
- c->cpu_core_id == pdev_entry->cpu_core_id) {
- err = 0; /* Not an error */
- goto exit;
- }
- }
-#endif
-
pdev = platform_device_alloc(DRVNAME, cpu);
if (!pdev) {
err = -ENOMEM;
@@ -486,10 +669,9 @@ static int __cpuinit coretemp_device_add(unsigned int cpu)
pdev_entry->pdev = pdev;
pdev_entry->cpu = cpu;
-#ifdef CONFIG_SMP
- pdev_entry->phys_proc_id = c->phys_proc_id;
- pdev_entry->cpu_core_id = c->cpu_core_id;
-#endif
+ pdev_entry->phys_proc_id = TO_PHYS_ID(cpu);
+ pdev_entry->cpu_core_id = TO_CORE_ID(cpu);
+
list_add_tail(&pdev_entry->list, &pdev_list);
mutex_unlock(&pdev_list_mutex);
@@ -504,28 +686,118 @@ exit:
return err;
}
-static void __cpuinit coretemp_device_remove(unsigned int cpu)
+static void coretemp_device_remove(unsigned int cpu)
{
- struct pdev_entry *p;
- unsigned int i;
+ struct pdev_entry *p, *n;
+ u16 phys_proc_id = TO_PHYS_ID(cpu);
mutex_lock(&pdev_list_mutex);
- list_for_each_entry(p, &pdev_list, list) {
- if (p->cpu != cpu)
+ list_for_each_entry_safe(p, n, &pdev_list, list) {
+ if (p->phys_proc_id != phys_proc_id)
continue;
-
platform_device_unregister(p->pdev);
list_del(&p->list);
- mutex_unlock(&pdev_list_mutex);
kfree(p);
- for_each_cpu(i, cpu_sibling_mask(cpu))
- if (i != cpu && !coretemp_device_add(i))
- break;
- return;
}
mutex_unlock(&pdev_list_mutex);
}
+static bool is_any_core_online(struct platform_data *pdata)
+{
+ int i;
+
+ /* Find online cores, except pkgtemp data */
+ for (i = MAX_CORE_DATA - 1; i >= 0; --i) {
+ if (pdata->core_data[i] &&
+ !pdata->core_data[i]->is_pkg_data) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void __cpuinit get_core_online(unsigned int cpu)
+{
+ struct cpuinfo_x86 *c = &cpu_data(cpu);
+ struct platform_device *pdev = coretemp_get_pdev(cpu);
+ int err;
+
+ /*
+ * CPUID.06H.EAX[0] indicates whether the CPU has thermal
+ * sensors. We check this bit only, all the early CPUs
+ * without thermal sensors will be filtered out.
+ */
+ if (!cpu_has(c, X86_FEATURE_DTS))
+ return;
+
+ if (!pdev) {
+ /*
+ * Alright, we have DTS support.
+ * We are bringing the _first_ core in this pkg
+ * online. So, initialize per-pkg data structures and
+ * then bring this core online.
+ */
+ err = coretemp_device_add(cpu);
+ if (err)
+ return;
+ /*
+ * Check whether pkgtemp support is available.
+ * If so, add interfaces for pkgtemp.
+ */
+ if (cpu_has(c, X86_FEATURE_PTS))
+ coretemp_add_core(cpu, 1);
+ }
+ /*
+ * Physical CPU device already exists.
+ * So, just add interfaces for this core.
+ */
+ coretemp_add_core(cpu, 0);
+}
+
+static void __cpuinit put_core_offline(unsigned int cpu)
+{
+ int i, indx;
+ struct platform_data *pdata;
+ struct platform_device *pdev = coretemp_get_pdev(cpu);
+
+ /* If the physical CPU device does not exist, just return */
+ if (!pdev)
+ return;
+
+ pdata = platform_get_drvdata(pdev);
+
+ indx = TO_ATTR_NO(cpu);
+
+ if (pdata->core_data[indx] && pdata->core_data[indx]->cpu == cpu)
+ coretemp_remove_core(pdata, &pdev->dev, indx);
+
+ /*
+ * If a HT sibling of a core is taken offline, but another HT sibling
+ * of the same core is still online, register the alternate sibling.
+ * This ensures that exactly one set of attributes is provided as long
+ * as at least one HT sibling of a core is online.
+ */
+ for_each_sibling(i, cpu) {
+ if (i != cpu) {
+ get_core_online(i);
+ /*
+ * Display temperature sensor data for one HT sibling
+ * per core only, so abort the loop after one such
+ * sibling has been found.
+ */
+ break;
+ }
+ }
+ /*
+ * If all cores in this pkg are offline, remove the device.
+ * coretemp_device_remove calls unregister_platform_device,
+ * which in turn calls coretemp_remove. This removes the
+ * pkgtemp entry and does other clean ups.
+ */
+ if (!is_any_core_online(pdata))
+ coretemp_device_remove(cpu);
+}
+
static int __cpuinit coretemp_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
@@ -534,10 +806,10 @@ static int __cpuinit coretemp_cpu_callback(struct notifier_block *nfb,
switch (action) {
case CPU_ONLINE:
case CPU_DOWN_FAILED:
- coretemp_device_add(cpu);
+ get_core_online(cpu);
break;
case CPU_DOWN_PREPARE:
- coretemp_device_remove(cpu);
+ put_core_offline(cpu);
break;
}
return NOTIFY_OK;
@@ -560,7 +832,7 @@ static int __init coretemp_init(void)
goto exit;
for_each_online_cpu(i)
- coretemp_device_add(i);
+ get_core_online(i);
#ifndef CONFIG_HOTPLUG_CPU
if (list_empty(&pdev_list)) {
diff --git a/drivers/hwmon/emc6w201.c b/drivers/hwmon/emc6w201.c
new file mode 100644
index 000000000000..e0ef32378ac6
--- /dev/null
+++ b/drivers/hwmon/emc6w201.c
@@ -0,0 +1,539 @@
+/*
+ * emc6w201.c - Hardware monitoring driver for the SMSC EMC6W201
+ * Copyright (C) 2011 Jean Delvare <khali@linux-fr.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+/*
+ * Addresses to scan
+ */
+
+static const unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, I2C_CLIENT_END };
+
+/*
+ * The EMC6W201 registers
+ */
+
+#define EMC6W201_REG_IN(nr) (0x20 + (nr))
+#define EMC6W201_REG_TEMP(nr) (0x26 + (nr))
+#define EMC6W201_REG_FAN(nr) (0x2C + (nr) * 2)
+#define EMC6W201_REG_COMPANY 0x3E
+#define EMC6W201_REG_VERSTEP 0x3F
+#define EMC6W201_REG_CONFIG 0x40
+#define EMC6W201_REG_IN_LOW(nr) (0x4A + (nr) * 2)
+#define EMC6W201_REG_IN_HIGH(nr) (0x4B + (nr) * 2)
+#define EMC6W201_REG_TEMP_LOW(nr) (0x56 + (nr) * 2)
+#define EMC6W201_REG_TEMP_HIGH(nr) (0x57 + (nr) * 2)
+#define EMC6W201_REG_FAN_MIN(nr) (0x62 + (nr) * 2)
+
+enum { input, min, max } subfeature;
+
+/*
+ * Per-device data
+ */
+
+struct emc6w201_data {
+ struct device *hwmon_dev;
+ struct mutex update_lock;
+ char valid; /* zero until following fields are valid */
+ unsigned long last_updated; /* in jiffies */
+
+ /* registers values */
+ u8 in[3][6];
+ s8 temp[3][6];
+ u16 fan[2][5];
+};
+
+/*
+ * Combine LSB and MSB registers in a single value
+ * Locking: must be called with data->update_lock held
+ */
+static u16 emc6w201_read16(struct i2c_client *client, u8 reg)
+{
+ int lsb, msb;
+
+ lsb = i2c_smbus_read_byte_data(client, reg);
+ msb = i2c_smbus_read_byte_data(client, reg + 1);
+ if (lsb < 0 || msb < 0) {
+ dev_err(&client->dev, "16-bit read failed at 0x%02x\n", reg);
+ return 0xFFFF; /* Arbitrary value */
+ }
+
+ return (msb << 8) | lsb;
+}
+
+/*
+ * Write 16-bit value to LSB and MSB registers
+ * Locking: must be called with data->update_lock held
+ */
+static int emc6w201_write16(struct i2c_client *client, u8 reg, u16 val)
+{
+ int err;
+
+ err = i2c_smbus_write_byte_data(client, reg, val & 0xff);
+ if (!err)
+ err = i2c_smbus_write_byte_data(client, reg + 1, val >> 8);
+ if (err < 0)
+ dev_err(&client->dev, "16-bit write failed at 0x%02x\n", reg);
+
+ return err;
+}
+
+static struct emc6w201_data *emc6w201_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct emc6w201_data *data = i2c_get_clientdata(client);
+ int nr;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+ for (nr = 0; nr < 6; nr++) {
+ data->in[input][nr] =
+ i2c_smbus_read_byte_data(client,
+ EMC6W201_REG_IN(nr));
+ data->in[min][nr] =
+ i2c_smbus_read_byte_data(client,
+ EMC6W201_REG_IN_LOW(nr));
+ data->in[max][nr] =
+ i2c_smbus_read_byte_data(client,
+ EMC6W201_REG_IN_HIGH(nr));
+ }
+
+ for (nr = 0; nr < 6; nr++) {
+ data->temp[input][nr] =
+ i2c_smbus_read_byte_data(client,
+ EMC6W201_REG_TEMP(nr));
+ data->temp[min][nr] =
+ i2c_smbus_read_byte_data(client,
+ EMC6W201_REG_TEMP_LOW(nr));
+ data->temp[max][nr] =
+ i2c_smbus_read_byte_data(client,
+ EMC6W201_REG_TEMP_HIGH(nr));
+ }
+
+ for (nr = 0; nr < 5; nr++) {
+ data->fan[input][nr] =
+ emc6w201_read16(client,
+ EMC6W201_REG_FAN(nr));
+ data->fan[min][nr] =
+ emc6w201_read16(client,
+ EMC6W201_REG_FAN_MIN(nr));
+ }
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
+/*
+ * Sysfs callback functions
+ */
+
+static const u16 nominal_mv[6] = { 2500, 1500, 3300, 5000, 1500, 1500 };
+
+static ssize_t show_in(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct emc6w201_data *data = emc6w201_update_device(dev);
+ int sf = to_sensor_dev_attr_2(devattr)->index;
+ int nr = to_sensor_dev_attr_2(devattr)->nr;
+
+ return sprintf(buf, "%u\n",
+ (unsigned)data->in[sf][nr] * nominal_mv[nr] / 0xC0);
+}
+
+static ssize_t set_in(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct emc6w201_data *data = i2c_get_clientdata(client);
+ int sf = to_sensor_dev_attr_2(devattr)->index;
+ int nr = to_sensor_dev_attr_2(devattr)->nr;
+ int err;
+ long val;
+ u8 reg;
+
+ err = strict_strtol(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ val = DIV_ROUND_CLOSEST(val * 0xC0, nominal_mv[nr]);
+ reg = (sf == min) ? EMC6W201_REG_IN_LOW(nr)
+ : EMC6W201_REG_IN_HIGH(nr);
+
+ mutex_lock(&data->update_lock);
+ data->in[sf][nr] = SENSORS_LIMIT(val, 0, 255);
+ err = i2c_smbus_write_byte_data(client, reg, data->in[sf][nr]);
+ mutex_unlock(&data->update_lock);
+
+ return err < 0 ? err : count;
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct emc6w201_data *data = emc6w201_update_device(dev);
+ int sf = to_sensor_dev_attr_2(devattr)->index;
+ int nr = to_sensor_dev_attr_2(devattr)->nr;
+
+ return sprintf(buf, "%d\n", (int)data->temp[sf][nr] * 1000);
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct emc6w201_data *data = i2c_get_clientdata(client);
+ int sf = to_sensor_dev_attr_2(devattr)->index;
+ int nr = to_sensor_dev_attr_2(devattr)->nr;
+ int err;
+ long val;
+ u8 reg;
+
+ err = strict_strtol(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ val /= 1000;
+ reg = (sf == min) ? EMC6W201_REG_TEMP_LOW(nr)
+ : EMC6W201_REG_TEMP_HIGH(nr);
+
+ mutex_lock(&data->update_lock);
+ data->temp[sf][nr] = SENSORS_LIMIT(val, -127, 128);
+ err = i2c_smbus_write_byte_data(client, reg, data->temp[sf][nr]);
+ mutex_unlock(&data->update_lock);
+
+ return err < 0 ? err : count;
+}
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct emc6w201_data *data = emc6w201_update_device(dev);
+ int sf = to_sensor_dev_attr_2(devattr)->index;
+ int nr = to_sensor_dev_attr_2(devattr)->nr;
+ unsigned rpm;
+
+ if (data->fan[sf][nr] == 0 || data->fan[sf][nr] == 0xFFFF)
+ rpm = 0;
+ else
+ rpm = 5400000U / data->fan[sf][nr];
+
+ return sprintf(buf, "%u\n", rpm);
+}
+
+static ssize_t set_fan(struct device *dev, struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct emc6w201_data *data = i2c_get_clientdata(client);
+ int sf = to_sensor_dev_attr_2(devattr)->index;
+ int nr = to_sensor_dev_attr_2(devattr)->nr;
+ int err;
+ unsigned long val;
+
+ err = strict_strtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ if (val == 0) {
+ val = 0xFFFF;
+ } else {
+ val = DIV_ROUND_CLOSEST(5400000U, val);
+ val = SENSORS_LIMIT(val, 0, 0xFFFE);
+ }
+
+ mutex_lock(&data->update_lock);
+ data->fan[sf][nr] = val;
+ err = emc6w201_write16(client, EMC6W201_REG_FAN_MIN(nr),
+ data->fan[sf][nr]);
+ mutex_unlock(&data->update_lock);
+
+ return err < 0 ? err : count;
+}
+
+static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, input);
+static SENSOR_DEVICE_ATTR_2(in0_min, S_IRUGO | S_IWUSR, show_in, set_in,
+ 0, min);
+static SENSOR_DEVICE_ATTR_2(in0_max, S_IRUGO | S_IWUSR, show_in, set_in,
+ 0, max);
+static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 1, input);
+static SENSOR_DEVICE_ATTR_2(in1_min, S_IRUGO | S_IWUSR, show_in, set_in,
+ 1, min);
+static SENSOR_DEVICE_ATTR_2(in1_max, S_IRUGO | S_IWUSR, show_in, set_in,
+ 1, max);
+static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 2, input);
+static SENSOR_DEVICE_ATTR_2(in2_min, S_IRUGO | S_IWUSR, show_in, set_in,
+ 2, min);
+static SENSOR_DEVICE_ATTR_2(in2_max, S_IRUGO | S_IWUSR, show_in, set_in,
+ 2, max);
+static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 3, input);
+static SENSOR_DEVICE_ATTR_2(in3_min, S_IRUGO | S_IWUSR, show_in, set_in,
+ 3, min);
+static SENSOR_DEVICE_ATTR_2(in3_max, S_IRUGO | S_IWUSR, show_in, set_in,
+ 3, max);
+static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 4, input);
+static SENSOR_DEVICE_ATTR_2(in4_min, S_IRUGO | S_IWUSR, show_in, set_in,
+ 4, min);
+static SENSOR_DEVICE_ATTR_2(in4_max, S_IRUGO | S_IWUSR, show_in, set_in,
+ 4, max);
+static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in, NULL, 5, input);
+static SENSOR_DEVICE_ATTR_2(in5_min, S_IRUGO | S_IWUSR, show_in, set_in,
+ 5, min);
+static SENSOR_DEVICE_ATTR_2(in5_max, S_IRUGO | S_IWUSR, show_in, set_in,
+ 5, max);
+
+static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, input);
+static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 0, min);
+static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 0, max);
+static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 1, input);
+static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 1, min);
+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 1, max);
+static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 2, input);
+static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 2, min);
+static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 2, max);
+static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 3, input);
+static SENSOR_DEVICE_ATTR_2(temp4_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 3, min);
+static SENSOR_DEVICE_ATTR_2(temp4_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 3, max);
+static SENSOR_DEVICE_ATTR_2(temp5_input, S_IRUGO, show_temp, NULL, 4, input);
+static SENSOR_DEVICE_ATTR_2(temp5_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 4, min);
+static SENSOR_DEVICE_ATTR_2(temp5_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 4, max);
+static SENSOR_DEVICE_ATTR_2(temp6_input, S_IRUGO, show_temp, NULL, 5, input);
+static SENSOR_DEVICE_ATTR_2(temp6_min, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 5, min);
+static SENSOR_DEVICE_ATTR_2(temp6_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
+ 5, max);
+
+static SENSOR_DEVICE_ATTR_2(fan1_input, S_IRUGO, show_fan, NULL, 0, input);
+static SENSOR_DEVICE_ATTR_2(fan1_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+ 0, min);
+static SENSOR_DEVICE_ATTR_2(fan2_input, S_IRUGO, show_fan, NULL, 1, input);
+static SENSOR_DEVICE_ATTR_2(fan2_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+ 1, min);
+static SENSOR_DEVICE_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 2, input);
+static SENSOR_DEVICE_ATTR_2(fan3_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+ 2, min);
+static SENSOR_DEVICE_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 3, input);
+static SENSOR_DEVICE_ATTR_2(fan4_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+ 3, min);
+static SENSOR_DEVICE_ATTR_2(fan5_input, S_IRUGO, show_fan, NULL, 4, input);
+static SENSOR_DEVICE_ATTR_2(fan5_min, S_IRUGO | S_IWUSR, show_fan, set_fan,
+ 4, min);
+
+static struct attribute *emc6w201_attributes[] = {
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
+
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp4_input.dev_attr.attr,
+ &sensor_dev_attr_temp4_min.dev_attr.attr,
+ &sensor_dev_attr_temp4_max.dev_attr.attr,
+ &sensor_dev_attr_temp5_input.dev_attr.attr,
+ &sensor_dev_attr_temp5_min.dev_attr.attr,
+ &sensor_dev_attr_temp5_max.dev_attr.attr,
+ &sensor_dev_attr_temp6_input.dev_attr.attr,
+ &sensor_dev_attr_temp6_min.dev_attr.attr,
+ &sensor_dev_attr_temp6_max.dev_attr.attr,
+
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_min.dev_attr.attr,
+ &sensor_dev_attr_fan4_input.dev_attr.attr,
+ &sensor_dev_attr_fan4_min.dev_attr.attr,
+ &sensor_dev_attr_fan5_input.dev_attr.attr,
+ &sensor_dev_attr_fan5_min.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group emc6w201_group = {
+ .attrs = emc6w201_attributes,
+};
+
+/*
+ * Driver interface
+ */
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int emc6w201_detect(struct i2c_client *client,
+ struct i2c_board_info *info)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ int company, verstep, config;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
+
+ /* Identification */
+ company = i2c_smbus_read_byte_data(client, EMC6W201_REG_COMPANY);
+ if (company != 0x5C)
+ return -ENODEV;
+ verstep = i2c_smbus_read_byte_data(client, EMC6W201_REG_VERSTEP);
+ if (verstep < 0 || (verstep & 0xF0) != 0xB0)
+ return -ENODEV;
+ if ((verstep & 0x0F) > 2) {
+ dev_dbg(&client->dev, "Unknwown EMC6W201 stepping %d\n",
+ verstep & 0x0F);
+ return -ENODEV;
+ }
+
+ /* Check configuration */
+ config = i2c_smbus_read_byte_data(client, EMC6W201_REG_CONFIG);
+ if ((config & 0xF4) != 0x04)
+ return -ENODEV;
+ if (!(config & 0x01)) {
+ dev_err(&client->dev, "Monitoring not enabled\n");
+ return -ENODEV;
+ }
+
+ strlcpy(info->type, "emc6w201", I2C_NAME_SIZE);
+
+ return 0;
+}
+
+static int emc6w201_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct emc6w201_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct emc6w201_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+
+ /* Create sysfs attribute */
+ err = sysfs_create_group(&client->dev.kobj, &emc6w201_group);
+ if (err)
+ goto exit_free;
+
+ /* Expose as a hwmon device */
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ goto exit_remove;
+ }
+
+ return 0;
+
+ exit_remove:
+ sysfs_remove_group(&client->dev.kobj, &emc6w201_group);
+ exit_free:
+ kfree(data);
+ exit:
+ return err;
+}
+
+static int emc6w201_remove(struct i2c_client *client)
+{
+ struct emc6w201_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &emc6w201_group);
+ kfree(data);
+
+ return 0;
+}
+
+static const struct i2c_device_id emc6w201_id[] = {
+ { "emc6w201", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, emc6w201_id);
+
+static struct i2c_driver emc6w201_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "emc6w201",
+ },
+ .probe = emc6w201_probe,
+ .remove = emc6w201_remove,
+ .id_table = emc6w201_id,
+ .detect = emc6w201_detect,
+ .address_list = normal_i2c,
+};
+
+static int __init sensors_emc6w201_init(void)
+{
+ return i2c_add_driver(&emc6w201_driver);
+}
+module_init(sensors_emc6w201_init);
+
+static void __exit sensors_emc6w201_exit(void)
+{
+ i2c_del_driver(&emc6w201_driver);
+}
+module_exit(sensors_emc6w201_exit);
+
+MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("SMSC EMC6W201 hardware monitoring driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c
index ca07a32447c2..a4a94a096c90 100644
--- a/drivers/hwmon/f71882fg.c
+++ b/drivers/hwmon/f71882fg.c
@@ -48,6 +48,7 @@
#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */
#define SIO_F71808E_ID 0x0901 /* Chipset ID */
+#define SIO_F71808A_ID 0x1001 /* Chipset ID */
#define SIO_F71858_ID 0x0507 /* Chipset ID */
#define SIO_F71862_ID 0x0601 /* Chipset ID */
#define SIO_F71869_ID 0x0814 /* Chipset ID */
@@ -107,11 +108,12 @@ static unsigned short force_id;
module_param(force_id, ushort, 0);
MODULE_PARM_DESC(force_id, "Override the detected device ID");
-enum chips { f71808e, f71858fg, f71862fg, f71869, f71882fg, f71889fg,
+enum chips { f71808e, f71808a, f71858fg, f71862fg, f71869, f71882fg, f71889fg,
f71889ed, f71889a, f8000, f81865f };
static const char *f71882fg_names[] = {
"f71808e",
+ "f71808a",
"f71858fg",
"f71862fg",
"f71869", /* Both f71869f and f71869e, reg. compatible and same id */
@@ -125,6 +127,7 @@ static const char *f71882fg_names[] = {
static const char f71882fg_has_in[][F71882FG_MAX_INS] = {
[f71808e] = { 1, 1, 1, 1, 1, 1, 0, 1, 1 },
+ [f71808a] = { 1, 1, 1, 1, 0, 0, 0, 1, 1 },
[f71858fg] = { 1, 1, 1, 0, 0, 0, 0, 0, 0 },
[f71862fg] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
[f71869] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 },
@@ -138,6 +141,7 @@ static const char f71882fg_has_in[][F71882FG_MAX_INS] = {
static const char f71882fg_has_in1_alarm[] = {
[f71808e] = 0,
+ [f71808a] = 0,
[f71858fg] = 0,
[f71862fg] = 0,
[f71869] = 0,
@@ -149,8 +153,9 @@ static const char f71882fg_has_in1_alarm[] = {
[f81865f] = 1,
};
-static const char f71882fg_has_beep[] = {
+static const char f71882fg_fan_has_beep[] = {
[f71808e] = 0,
+ [f71808a] = 0,
[f71858fg] = 0,
[f71862fg] = 1,
[f71869] = 1,
@@ -164,6 +169,7 @@ static const char f71882fg_has_beep[] = {
static const char f71882fg_nr_fans[] = {
[f71808e] = 3,
+ [f71808a] = 2, /* +1 fan which is monitor + simple pwm only */
[f71858fg] = 3,
[f71862fg] = 3,
[f71869] = 3,
@@ -171,12 +177,27 @@ static const char f71882fg_nr_fans[] = {
[f71889fg] = 3,
[f71889ed] = 3,
[f71889a] = 3,
- [f8000] = 3,
+ [f8000] = 3, /* +1 fan which is monitor only */
[f81865f] = 2,
};
+static const char f71882fg_temp_has_beep[] = {
+ [f71808e] = 0,
+ [f71808a] = 1,
+ [f71858fg] = 0,
+ [f71862fg] = 1,
+ [f71869] = 1,
+ [f71882fg] = 1,
+ [f71889fg] = 1,
+ [f71889ed] = 1,
+ [f71889a] = 1,
+ [f8000] = 0,
+ [f81865f] = 1,
+};
+
static const char f71882fg_nr_temps[] = {
[f71808e] = 2,
+ [f71808a] = 2,
[f71858fg] = 3,
[f71862fg] = 3,
[f71869] = 3,
@@ -301,6 +322,10 @@ static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr,
char *buf);
static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr,
const char *buf, size_t count);
+static ssize_t show_simple_pwm(struct device *dev,
+ struct device_attribute *devattr, char *buf);
+static ssize_t store_simple_pwm(struct device *dev,
+ struct device_attribute *devattr, const char *buf, size_t count);
static ssize_t show_pwm_enable(struct device *dev,
struct device_attribute *devattr, char *buf);
static ssize_t store_pwm_enable(struct device *dev,
@@ -550,6 +575,14 @@ static struct sensor_device_attribute_2 fxxxx_fan_attr[4][6] = { {
show_pwm_interpolate, store_pwm_interpolate, 0, 3),
} };
+/* Attr for the third fan of the f71808a, which only has manual pwm */
+static struct sensor_device_attribute_2 f71808a_fan3_attr[] = {
+ SENSOR_ATTR_2(fan3_input, S_IRUGO, show_fan, NULL, 0, 2),
+ SENSOR_ATTR_2(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 2),
+ SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR,
+ show_simple_pwm, store_simple_pwm, 0, 2),
+};
+
/* Attr for models which can beep on Fan alarm */
static struct sensor_device_attribute_2 fxxxx_fan_beep_attr[] = {
SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep,
@@ -1146,12 +1179,13 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
data->temp_type[3] = (reg & 0x08) ? 2 : 4;
}
- if (f71882fg_has_beep[data->type]) {
+ if (f71882fg_fan_has_beep[data->type])
data->fan_beep = f71882fg_read8(data,
F71882FG_REG_FAN_BEEP);
+
+ if (f71882fg_temp_has_beep[data->type])
data->temp_beep = f71882fg_read8(data,
F71882FG_REG_TEMP_BEEP);
- }
data->pwm_enable = f71882fg_read8(data,
F71882FG_REG_PWM_ENABLE);
@@ -1232,7 +1266,13 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev)
data->pwm[nr] =
f71882fg_read8(data, F71882FG_REG_PWM(nr));
}
- /* The f8000 can monitor 1 more fan, but has no pwm for it */
+ /* Some models have 1 more fan with limited capabilities */
+ if (data->type == f71808a) {
+ data->fan[2] = f71882fg_read16(data,
+ F71882FG_REG_FAN(2));
+ data->pwm[2] = f71882fg_read8(data,
+ F71882FG_REG_PWM(2));
+ }
if (data->type == f8000)
data->fan[3] = f71882fg_read16(data,
F71882FG_REG_FAN(3));
@@ -1722,6 +1762,38 @@ leave:
return count;
}
+static ssize_t show_simple_pwm(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct f71882fg_data *data = f71882fg_update_device(dev);
+ int val, nr = to_sensor_dev_attr_2(devattr)->index;
+
+ val = data->pwm[nr];
+ return sprintf(buf, "%d\n", val);
+}
+
+static ssize_t store_simple_pwm(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ struct f71882fg_data *data = dev_get_drvdata(dev);
+ int err, nr = to_sensor_dev_attr_2(devattr)->index;
+ long val;
+
+ err = strict_strtol(buf, 10, &val);
+ if (err)
+ return err;
+
+ val = SENSORS_LIMIT(val, 0, 255);
+
+ mutex_lock(&data->update_lock);
+ f71882fg_write8(data, F71882FG_REG_PWM(nr), val);
+ data->pwm[nr] = val;
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
static ssize_t show_pwm_enable(struct device *dev,
struct device_attribute *devattr, char *buf)
{
@@ -2140,7 +2212,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
if (err)
goto exit_unregister_sysfs;
- if (f71882fg_has_beep[data->type]) {
+ if (f71882fg_temp_has_beep[data->type]) {
err = f71882fg_create_sysfs_files(pdev,
&fxxxx_temp_beep_attr[0][0],
ARRAY_SIZE(fxxxx_temp_beep_attr[0])
@@ -2169,6 +2241,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
if (start_reg & 0x02) {
switch (data->type) {
case f71808e:
+ case f71808a:
case f71869:
/* These always have signed auto point temps */
data->auto_point_temp_signed = 1;
@@ -2221,7 +2294,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
if (err)
goto exit_unregister_sysfs;
- if (f71882fg_has_beep[data->type]) {
+ if (f71882fg_fan_has_beep[data->type]) {
err = f71882fg_create_sysfs_files(pdev,
fxxxx_fan_beep_attr, nr_fans);
if (err)
@@ -2230,6 +2303,7 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
switch (data->type) {
case f71808e:
+ case f71808a:
case f71869:
case f71889fg:
case f71889ed:
@@ -2255,6 +2329,16 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
}
switch (data->type) {
+ case f71808a:
+ err = f71882fg_create_sysfs_files(pdev,
+ &fxxxx_auto_pwm_attr[0][0],
+ ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
+ if (err)
+ goto exit_unregister_sysfs;
+ err = f71882fg_create_sysfs_files(pdev,
+ f71808a_fan3_attr,
+ ARRAY_SIZE(f71808a_fan3_attr));
+ break;
case f71862fg:
err = f71882fg_create_sysfs_files(pdev,
f71862fg_auto_pwm_attr,
@@ -2343,7 +2427,7 @@ static int f71882fg_remove(struct platform_device *pdev)
&fxxxx_temp_attr[0][0],
ARRAY_SIZE(fxxxx_temp_attr[0]) * nr_temps);
}
- if (f71882fg_has_beep[data->type]) {
+ if (f71882fg_temp_has_beep[data->type]) {
f71882fg_remove_sysfs_files(pdev,
&fxxxx_temp_beep_attr[0][0],
ARRAY_SIZE(fxxxx_temp_beep_attr[0]) * nr_temps);
@@ -2366,12 +2450,20 @@ static int f71882fg_remove(struct platform_device *pdev)
f71882fg_remove_sysfs_files(pdev, &fxxxx_fan_attr[0][0],
ARRAY_SIZE(fxxxx_fan_attr[0]) * nr_fans);
- if (f71882fg_has_beep[data->type]) {
+ if (f71882fg_fan_has_beep[data->type]) {
f71882fg_remove_sysfs_files(pdev,
fxxxx_fan_beep_attr, nr_fans);
}
switch (data->type) {
+ case f71808a:
+ f71882fg_remove_sysfs_files(pdev,
+ &fxxxx_auto_pwm_attr[0][0],
+ ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
+ f71882fg_remove_sysfs_files(pdev,
+ f71808a_fan3_attr,
+ ARRAY_SIZE(f71808a_fan3_attr));
+ break;
case f71862fg:
f71882fg_remove_sysfs_files(pdev,
f71862fg_auto_pwm_attr,
@@ -2424,6 +2516,9 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
case SIO_F71808E_ID:
sio_data->type = f71808e;
break;
+ case SIO_F71808A_ID:
+ sio_data->type = f71808a;
+ break;
case SIO_F71858_ID:
sio_data->type = f71858fg;
break;
diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c
new file mode 100644
index 000000000000..523f8fb9e7d9
--- /dev/null
+++ b/drivers/hwmon/fam15h_power.c
@@ -0,0 +1,229 @@
+/*
+ * fam15h_power.c - AMD Family 15h processor power monitoring
+ *
+ * Copyright (c) 2011 Advanced Micro Devices, Inc.
+ * Author: Andreas Herrmann <andreas.herrmann3@amd.com>
+ *
+ *
+ * This driver is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This 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 this driver; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/bitops.h>
+#include <asm/processor.h>
+
+MODULE_DESCRIPTION("AMD Family 15h CPU processor power monitor");
+MODULE_AUTHOR("Andreas Herrmann <andreas.herrmann3@amd.com>");
+MODULE_LICENSE("GPL");
+
+/* D18F3 */
+#define REG_NORTHBRIDGE_CAP 0xe8
+
+/* D18F4 */
+#define REG_PROCESSOR_TDP 0x1b8
+
+/* D18F5 */
+#define REG_TDP_RUNNING_AVERAGE 0xe0
+#define REG_TDP_LIMIT3 0xe8
+
+struct fam15h_power_data {
+ struct device *hwmon_dev;
+ unsigned int tdp_to_watts;
+ unsigned int base_tdp;
+ unsigned int processor_pwr_watts;
+};
+
+static ssize_t show_power(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u32 val, tdp_limit, running_avg_range;
+ s32 running_avg_capture;
+ u64 curr_pwr_watts;
+ struct pci_dev *f4 = to_pci_dev(dev);
+ struct fam15h_power_data *data = dev_get_drvdata(dev);
+
+ pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5),
+ REG_TDP_RUNNING_AVERAGE, &val);
+ running_avg_capture = (val >> 4) & 0x3fffff;
+ running_avg_capture = sign_extend32(running_avg_capture, 22);
+ running_avg_range = val & 0xf;
+
+ pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5),
+ REG_TDP_LIMIT3, &val);
+
+ tdp_limit = val >> 16;
+ curr_pwr_watts = tdp_limit + data->base_tdp -
+ (s32)(running_avg_capture >> (running_avg_range + 1));
+ curr_pwr_watts *= data->tdp_to_watts;
+
+ /*
+ * Convert to microWatt
+ *
+ * power is in Watt provided as fixed point integer with
+ * scaling factor 1/(2^16). For conversion we use
+ * (10^6)/(2^16) = 15625/(2^10)
+ */
+ curr_pwr_watts = (curr_pwr_watts * 15625) >> 10;
+ return sprintf(buf, "%u\n", (unsigned int) curr_pwr_watts);
+}
+static DEVICE_ATTR(power1_input, S_IRUGO, show_power, NULL);
+
+static ssize_t show_power_crit(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fam15h_power_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%u\n", data->processor_pwr_watts);
+}
+static DEVICE_ATTR(power1_crit, S_IRUGO, show_power_crit, NULL);
+
+static ssize_t show_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "fam15h_power\n");
+}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static struct attribute *fam15h_power_attrs[] = {
+ &dev_attr_power1_input.attr,
+ &dev_attr_power1_crit.attr,
+ &dev_attr_name.attr,
+ NULL
+};
+
+static const struct attribute_group fam15h_power_attr_group = {
+ .attrs = fam15h_power_attrs,
+};
+
+static bool __devinit fam15h_power_is_internal_node0(struct pci_dev *f4)
+{
+ u32 val;
+
+ pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 3),
+ REG_NORTHBRIDGE_CAP, &val);
+ if ((val & BIT(29)) && ((val >> 30) & 3))
+ return false;
+
+ return true;
+}
+
+static void __devinit fam15h_power_init_data(struct pci_dev *f4,
+ struct fam15h_power_data *data)
+{
+ u32 val;
+ u64 tmp;
+
+ pci_read_config_dword(f4, REG_PROCESSOR_TDP, &val);
+ data->base_tdp = val >> 16;
+ tmp = val & 0xffff;
+
+ pci_bus_read_config_dword(f4->bus, PCI_DEVFN(PCI_SLOT(f4->devfn), 5),
+ REG_TDP_LIMIT3, &val);
+
+ data->tdp_to_watts = ((val & 0x3ff) << 6) | ((val >> 10) & 0x3f);
+ tmp *= data->tdp_to_watts;
+
+ /* result not allowed to be >= 256W */
+ if ((tmp >> 16) >= 256)
+ dev_warn(&f4->dev, "Bogus value for ProcessorPwrWatts "
+ "(processor_pwr_watts>=%u)\n",
+ (unsigned int) (tmp >> 16));
+
+ /* convert to microWatt */
+ data->processor_pwr_watts = (tmp * 15625) >> 10;
+}
+
+static int __devinit fam15h_power_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct fam15h_power_data *data;
+ struct device *dev;
+ int err;
+
+ if (!fam15h_power_is_internal_node0(pdev)) {
+ err = -ENODEV;
+ goto exit;
+ }
+
+ data = kzalloc(sizeof(struct fam15h_power_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ fam15h_power_init_data(pdev, data);
+ dev = &pdev->dev;
+
+ dev_set_drvdata(dev, data);
+ err = sysfs_create_group(&dev->kobj, &fam15h_power_attr_group);
+ if (err)
+ goto exit_free_data;
+
+ data->hwmon_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ goto exit_remove_group;
+ }
+
+ return 0;
+
+exit_remove_group:
+ sysfs_remove_group(&dev->kobj, &fam15h_power_attr_group);
+exit_free_data:
+ kfree(data);
+exit:
+ return err;
+}
+
+static void __devexit fam15h_power_remove(struct pci_dev *pdev)
+{
+ struct device *dev;
+ struct fam15h_power_data *data;
+
+ dev = &pdev->dev;
+ data = dev_get_drvdata(dev);
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&dev->kobj, &fam15h_power_attr_group);
+ dev_set_drvdata(dev, NULL);
+ kfree(data);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(fam15h_power_id_table) = {
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
+ {}
+};
+MODULE_DEVICE_TABLE(pci, fam15h_power_id_table);
+
+static struct pci_driver fam15h_power_driver = {
+ .name = "fam15h_power",
+ .id_table = fam15h_power_id_table,
+ .probe = fam15h_power_probe,
+ .remove = __devexit_p(fam15h_power_remove),
+};
+
+static int __init fam15h_power_init(void)
+{
+ return pci_register_driver(&fam15h_power_driver);
+}
+
+static void __exit fam15h_power_exit(void)
+{
+ pci_unregister_driver(&fam15h_power_driver);
+}
+
+module_init(fam15h_power_init)
+module_exit(fam15h_power_exit)
diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c
index bc6e2ab3a361..537409d07ee7 100644
--- a/drivers/hwmon/ibmaem.c
+++ b/drivers/hwmon/ibmaem.c
@@ -523,7 +523,7 @@ static void aem_delete(struct aem_data *data)
aem_remove_sensors(data);
hwmon_device_unregister(data->hwmon_dev);
ipmi_destroy_user(data->ipmi.user);
- dev_set_drvdata(&data->pdev->dev, NULL);
+ platform_set_drvdata(data->pdev, NULL);
platform_device_unregister(data->pdev);
aem_idr_put(data->id);
kfree(data);
@@ -594,7 +594,7 @@ static int aem_init_aem1_inst(struct aem_ipmi_data *probe, u8 module_handle)
if (res)
goto ipmi_err;
- dev_set_drvdata(&data->pdev->dev, data);
+ platform_set_drvdata(data->pdev, data);
/* Set up IPMI interface */
if (aem_init_ipmi_data(&data->ipmi, probe->interface,
@@ -630,7 +630,7 @@ sensor_err:
hwmon_reg_err:
ipmi_destroy_user(data->ipmi.user);
ipmi_err:
- dev_set_drvdata(&data->pdev->dev, NULL);
+ platform_set_drvdata(data->pdev, NULL);
platform_device_unregister(data->pdev);
dev_err:
aem_idr_put(data->id);
@@ -727,7 +727,7 @@ static int aem_init_aem2_inst(struct aem_ipmi_data *probe,
if (res)
goto ipmi_err;
- dev_set_drvdata(&data->pdev->dev, data);
+ platform_set_drvdata(data->pdev, data);
/* Set up IPMI interface */
if (aem_init_ipmi_data(&data->ipmi, probe->interface,
@@ -763,7 +763,7 @@ sensor_err:
hwmon_reg_err:
ipmi_destroy_user(data->ipmi.user);
ipmi_err:
- dev_set_drvdata(&data->pdev->dev, NULL);
+ platform_set_drvdata(data->pdev, NULL);
platform_device_unregister(data->pdev);
dev_err:
aem_idr_put(data->id);
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 316b64823f7b..bb6405b92007 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -77,15 +77,13 @@ static struct platform_device *pdev;
#define DEVID 0x20 /* Register: Device ID */
#define DEVREV 0x22 /* Register: Device Revision */
-static inline int
-superio_inb(int reg)
+static inline int superio_inb(int reg)
{
outb(reg, REG);
return inb(VAL);
}
-static inline void
-superio_outb(int reg, int val)
+static inline void superio_outb(int reg, int val)
{
outb(reg, REG);
outb(val, VAL);
@@ -101,27 +99,32 @@ static int superio_inw(int reg)
return val;
}
-static inline void
-superio_select(int ldn)
+static inline void superio_select(int ldn)
{
outb(DEV, REG);
outb(ldn, VAL);
}
-static inline void
-superio_enter(void)
+static inline int superio_enter(void)
{
+ /*
+ * Try to reserve REG and REG + 1 for exclusive access.
+ */
+ if (!request_muxed_region(REG, 2, DRVNAME))
+ return -EBUSY;
+
outb(0x87, REG);
outb(0x01, REG);
outb(0x55, REG);
outb(0x55, REG);
+ return 0;
}
-static inline void
-superio_exit(void)
+static inline void superio_exit(void)
{
outb(0x02, REG);
outb(0x02, VAL);
+ release_region(REG, 2);
}
/* Logical device 4 registers */
@@ -1542,11 +1545,15 @@ static const struct attribute_group it87_group_label = {
static int __init it87_find(unsigned short *address,
struct it87_sio_data *sio_data)
{
- int err = -ENODEV;
+ int err;
u16 chip_type;
const char *board_vendor, *board_name;
- superio_enter();
+ err = superio_enter();
+ if (err)
+ return err;
+
+ err = -ENODEV;
chip_type = force_id ? force_id : superio_inw(DEVID);
switch (chip_type) {
diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c
index 934991237061..02cebb74e206 100644
--- a/drivers/hwmon/jc42.c
+++ b/drivers/hwmon/jc42.c
@@ -213,7 +213,7 @@ static const struct dev_pm_ops jc42_dev_pm_ops = {
/* This is the driver that will be inserted */
static struct i2c_driver jc42_driver = {
- .class = I2C_CLASS_HWMON,
+ .class = I2C_CLASS_SPD,
.driver = {
.name = "jc42",
.pm = JC42_DEV_PM_OPS,
diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
index 82bf65aa2968..41aa6a319870 100644
--- a/drivers/hwmon/k10temp.c
+++ b/drivers/hwmon/k10temp.c
@@ -1,5 +1,5 @@
/*
- * k10temp.c - AMD Family 10h/11h/12h/14h processor hardware monitoring
+ * k10temp.c - AMD Family 10h/11h/12h/14h/15h processor hardware monitoring
*
* Copyright (c) 2009 Clemens Ladisch <clemens@ladisch.de>
*
@@ -25,7 +25,7 @@
#include <linux/pci.h>
#include <asm/processor.h>
-MODULE_DESCRIPTION("AMD Family 10h/11h/12h/14h CPU core temperature monitor");
+MODULE_DESCRIPTION("AMD Family 10h+ CPU core temperature monitor");
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
MODULE_LICENSE("GPL");
@@ -173,7 +173,7 @@ static int __devinit k10temp_probe(struct pci_dev *pdev,
err = PTR_ERR(hwmon_dev);
goto exit_remove;
}
- dev_set_drvdata(&pdev->dev, hwmon_dev);
+ pci_set_drvdata(pdev, hwmon_dev);
if (unreliable && force)
dev_warn(&pdev->dev,
@@ -194,7 +194,7 @@ exit:
static void __devexit k10temp_remove(struct pci_dev *pdev)
{
- hwmon_device_unregister(dev_get_drvdata(&pdev->dev));
+ hwmon_device_unregister(pci_get_drvdata(pdev));
device_remove_file(&pdev->dev, &dev_attr_name);
device_remove_file(&pdev->dev, &dev_attr_temp1_input);
device_remove_file(&pdev->dev, &dev_attr_temp1_max);
@@ -202,13 +202,14 @@ static void __devexit k10temp_remove(struct pci_dev *pdev)
&sensor_dev_attr_temp1_crit.dev_attr);
device_remove_file(&pdev->dev,
&sensor_dev_attr_temp1_crit_hyst.dev_attr);
- dev_set_drvdata(&pdev->dev, NULL);
+ pci_set_drvdata(pdev, NULL);
}
static const struct pci_device_id k10temp_id_table[] = {
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_11H_NB_MISC) },
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CNB17H_F3) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
{}
};
MODULE_DEVICE_TABLE(pci, k10temp_id_table);
diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c
index 418496f13020..b923bc2307ad 100644
--- a/drivers/hwmon/k8temp.c
+++ b/drivers/hwmon/k8temp.c
@@ -252,7 +252,7 @@ static int __devinit k8temp_probe(struct pci_dev *pdev,
data->name = "k8temp";
mutex_init(&data->update_lock);
- dev_set_drvdata(&pdev->dev, data);
+ pci_set_drvdata(pdev, data);
/* Register sysfs hooks */
err = device_create_file(&pdev->dev,
@@ -307,7 +307,7 @@ exit_remove:
&sensor_dev_attr_temp4_input.dev_attr);
device_remove_file(&pdev->dev, &dev_attr_name);
exit_free:
- dev_set_drvdata(&pdev->dev, NULL);
+ pci_set_drvdata(pdev, NULL);
kfree(data);
exit:
return err;
@@ -315,7 +315,7 @@ exit:
static void __devexit k8temp_remove(struct pci_dev *pdev)
{
- struct k8temp_data *data = dev_get_drvdata(&pdev->dev);
+ struct k8temp_data *data = pci_get_drvdata(pdev);
hwmon_device_unregister(data->hwmon_dev);
device_remove_file(&pdev->dev,
@@ -327,7 +327,7 @@ static void __devexit k8temp_remove(struct pci_dev *pdev)
device_remove_file(&pdev->dev,
&sensor_dev_attr_temp4_input.dev_attr);
device_remove_file(&pdev->dev, &dev_attr_name);
- dev_set_drvdata(&pdev->dev, NULL);
+ pci_set_drvdata(pdev, NULL);
kfree(data);
}
diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c
index 3b84fb503053..c274ea25d899 100644
--- a/drivers/hwmon/lm70.c
+++ b/drivers/hwmon/lm70.c
@@ -58,7 +58,7 @@ static ssize_t lm70_sense_temp(struct device *dev,
int status, val = 0;
u8 rxbuf[2];
s16 raw=0;
- struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev);
+ struct lm70 *p_lm70 = spi_get_drvdata(spi);
if (mutex_lock_interruptible(&p_lm70->lock))
return -ERESTARTSYS;
@@ -163,7 +163,7 @@ static int __devinit lm70_probe(struct spi_device *spi)
status = PTR_ERR(p_lm70->hwmon_dev);
goto out_dev_reg_failed;
}
- dev_set_drvdata(&spi->dev, p_lm70);
+ spi_set_drvdata(spi, p_lm70);
if ((status = device_create_file(&spi->dev, &dev_attr_temp1_input))
|| (status = device_create_file(&spi->dev, &dev_attr_name))) {
@@ -177,19 +177,19 @@ out_dev_create_file_failed:
device_remove_file(&spi->dev, &dev_attr_temp1_input);
hwmon_device_unregister(p_lm70->hwmon_dev);
out_dev_reg_failed:
- dev_set_drvdata(&spi->dev, NULL);
+ spi_set_drvdata(spi, NULL);
kfree(p_lm70);
return status;
}
static int __devexit lm70_remove(struct spi_device *spi)
{
- struct lm70 *p_lm70 = dev_get_drvdata(&spi->dev);
+ struct lm70 *p_lm70 = spi_get_drvdata(spi);
device_remove_file(&spi->dev, &dev_attr_temp1_input);
device_remove_file(&spi->dev, &dev_attr_name);
hwmon_device_unregister(p_lm70->hwmon_dev);
- dev_set_drvdata(&spi->dev, NULL);
+ spi_set_drvdata(spi, NULL);
kfree(p_lm70);
return 0;
diff --git a/drivers/hwmon/max16065.c b/drivers/hwmon/max16065.c
new file mode 100644
index 000000000000..d94a24fdf4ba
--- /dev/null
+++ b/drivers/hwmon/max16065.c
@@ -0,0 +1,717 @@
+/*
+ * Driver for
+ * Maxim MAX16065/MAX16066 12-Channel/8-Channel, Flash-Configurable
+ * System Managers with Nonvolatile Fault Registers
+ * Maxim MAX16067/MAX16068 6-Channel, Flash-Configurable System Managers
+ * with Nonvolatile Fault Registers
+ * Maxim MAX16070/MAX16071 12-Channel/8-Channel, Flash-Configurable System
+ * Monitors with Nonvolatile Fault Registers
+ *
+ * Copyright (C) 2011 Ericsson AB.
+ *
+ * This program is free software; 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+
+enum chips { max16065, max16066, max16067, max16068, max16070, max16071 };
+
+/*
+ * Registers
+ */
+#define MAX16065_ADC(x) ((x) * 2)
+
+#define MAX16065_CURR_SENSE 0x18
+#define MAX16065_CSP_ADC 0x19
+#define MAX16065_FAULT(x) (0x1b + (x))
+#define MAX16065_SCALE(x) (0x43 + (x))
+#define MAX16065_CURR_CONTROL 0x47
+#define MAX16065_LIMIT(l, x) (0x48 + (l) + (x) * 3) /*
+ * l: limit
+ * 0: min/max
+ * 1: crit
+ * 2: lcrit
+ * x: ADC index
+ */
+
+#define MAX16065_SW_ENABLE 0x73
+
+#define MAX16065_WARNING_OV (1 << 3) /* Set if secondary threshold is OV
+ warning */
+
+#define MAX16065_CURR_ENABLE (1 << 0)
+
+#define MAX16065_NUM_LIMIT 3
+#define MAX16065_NUM_ADC 12 /* maximum number of ADC channels */
+
+static const int max16065_num_adc[] = {
+ [max16065] = 12,
+ [max16066] = 8,
+ [max16067] = 6,
+ [max16068] = 6,
+ [max16070] = 12,
+ [max16071] = 8,
+};
+
+static const bool max16065_have_secondary[] = {
+ [max16065] = true,
+ [max16066] = true,
+ [max16067] = false,
+ [max16068] = false,
+ [max16070] = true,
+ [max16071] = true,
+};
+
+static const bool max16065_have_current[] = {
+ [max16065] = true,
+ [max16066] = true,
+ [max16067] = false,
+ [max16068] = false,
+ [max16070] = true,
+ [max16071] = true,
+};
+
+struct max16065_data {
+ enum chips type;
+ struct device *hwmon_dev;
+ struct mutex update_lock;
+ bool valid;
+ unsigned long last_updated; /* in jiffies */
+ int num_adc;
+ bool have_current;
+ int curr_gain;
+ /* limits are in mV */
+ int limit[MAX16065_NUM_LIMIT][MAX16065_NUM_ADC];
+ int range[MAX16065_NUM_ADC + 1];/* voltage range */
+ int adc[MAX16065_NUM_ADC + 1]; /* adc values (raw) including csp_adc */
+ int curr_sense;
+ int fault[2];
+};
+
+static const int max16065_adc_range[] = { 5560, 2780, 1390, 0 };
+static const int max16065_csp_adc_range[] = { 7000, 14000 };
+
+/* ADC registers have 10 bit resolution. */
+static inline int ADC_TO_MV(int adc, int range)
+{
+ return (adc * range) / 1024;
+}
+
+/*
+ * Limit registers have 8 bit resolution and match upper 8 bits of ADC
+ * registers.
+ */
+static inline int LIMIT_TO_MV(int limit, int range)
+{
+ return limit * range / 256;
+}
+
+static inline int MV_TO_LIMIT(int mv, int range)
+{
+ return SENSORS_LIMIT(DIV_ROUND_CLOSEST(mv * 256, range), 0, 255);
+}
+
+static inline int ADC_TO_CURR(int adc, int gain)
+{
+ return adc * 1400000 / gain * 255;
+}
+
+/*
+ * max16065_read_adc()
+ *
+ * Read 16 bit value from <reg>, <reg+1>.
+ * Upper 8 bits are in <reg>, lower 2 bits are in bits 7:6 of <reg+1>.
+ */
+static int max16065_read_adc(struct i2c_client *client, int reg)
+{
+ int rv;
+
+ rv = i2c_smbus_read_word_data(client, reg);
+ if (unlikely(rv < 0))
+ return rv;
+ return ((rv & 0xff) << 2) | ((rv >> 14) & 0x03);
+}
+
+static struct max16065_data *max16065_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct max16065_data *data = i2c_get_clientdata(client);
+
+ mutex_lock(&data->update_lock);
+ if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+ int i;
+
+ for (i = 0; i < data->num_adc; i++)
+ data->adc[i]
+ = max16065_read_adc(client, MAX16065_ADC(i));
+
+ if (data->have_current) {
+ data->adc[MAX16065_NUM_ADC]
+ = max16065_read_adc(client, MAX16065_CSP_ADC);
+ data->curr_sense
+ = i2c_smbus_read_byte_data(client,
+ MAX16065_CURR_SENSE);
+ }
+
+ for (i = 0; i < DIV_ROUND_UP(data->num_adc, 8); i++)
+ data->fault[i]
+ = i2c_smbus_read_byte_data(client, MAX16065_FAULT(i));
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+ mutex_unlock(&data->update_lock);
+ return data;
+}
+
+static ssize_t max16065_show_alarm(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(da);
+ struct max16065_data *data = max16065_update_device(dev);
+ int val = data->fault[attr2->nr];
+
+ if (val < 0)
+ return val;
+
+ val &= (1 << attr2->index);
+ if (val)
+ i2c_smbus_write_byte_data(to_i2c_client(dev),
+ MAX16065_FAULT(attr2->nr), val);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", !!val);
+}
+
+static ssize_t max16065_show_input(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct max16065_data *data = max16065_update_device(dev);
+ int adc = data->adc[attr->index];
+
+ if (unlikely(adc < 0))
+ return adc;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ ADC_TO_MV(adc, data->range[attr->index]));
+}
+
+static ssize_t max16065_show_current(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct max16065_data *data = max16065_update_device(dev);
+
+ if (unlikely(data->curr_sense < 0))
+ return data->curr_sense;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ ADC_TO_CURR(data->curr_sense, data->curr_gain));
+}
+
+static ssize_t max16065_set_limit(struct device *dev,
+ struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(da);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct max16065_data *data = i2c_get_clientdata(client);
+ unsigned long val;
+ int err;
+ int limit;
+
+ err = strict_strtoul(buf, 10, &val);
+ if (unlikely(err < 0))
+ return err;
+
+ limit = MV_TO_LIMIT(val, data->range[attr2->index]);
+
+ mutex_lock(&data->update_lock);
+ data->limit[attr2->nr][attr2->index]
+ = LIMIT_TO_MV(limit, data->range[attr2->index]);
+ i2c_smbus_write_byte_data(client,
+ MAX16065_LIMIT(attr2->nr, attr2->index),
+ limit);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+static ssize_t max16065_show_limit(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(da);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct max16065_data *data = i2c_get_clientdata(client);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ data->limit[attr2->nr][attr2->index]);
+}
+
+/* Construct a sensor_device_attribute structure for each register */
+
+/* Input voltages */
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, max16065_show_input, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, max16065_show_input, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, max16065_show_input, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, max16065_show_input, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, max16065_show_input, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, max16065_show_input, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, max16065_show_input, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, max16065_show_input, NULL, 7);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, max16065_show_input, NULL, 8);
+static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, max16065_show_input, NULL, 9);
+static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, max16065_show_input, NULL, 10);
+static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, max16065_show_input, NULL, 11);
+static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, max16065_show_input, NULL, 12);
+
+/* Input voltages lcrit */
+static SENSOR_DEVICE_ATTR_2(in0_lcrit, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 2, 0);
+static SENSOR_DEVICE_ATTR_2(in1_lcrit, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 2, 1);
+static SENSOR_DEVICE_ATTR_2(in2_lcrit, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 2, 2);
+static SENSOR_DEVICE_ATTR_2(in3_lcrit, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 2, 3);
+static SENSOR_DEVICE_ATTR_2(in4_lcrit, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 2, 4);
+static SENSOR_DEVICE_ATTR_2(in5_lcrit, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 2, 5);
+static SENSOR_DEVICE_ATTR_2(in6_lcrit, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 2, 6);
+static SENSOR_DEVICE_ATTR_2(in7_lcrit, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 2, 7);
+static SENSOR_DEVICE_ATTR_2(in8_lcrit, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 2, 8);
+static SENSOR_DEVICE_ATTR_2(in9_lcrit, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 2, 9);
+static SENSOR_DEVICE_ATTR_2(in10_lcrit, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 2, 10);
+static SENSOR_DEVICE_ATTR_2(in11_lcrit, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 2, 11);
+
+/* Input voltages crit */
+static SENSOR_DEVICE_ATTR_2(in0_crit, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 1, 0);
+static SENSOR_DEVICE_ATTR_2(in1_crit, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 1, 1);
+static SENSOR_DEVICE_ATTR_2(in2_crit, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 1, 2);
+static SENSOR_DEVICE_ATTR_2(in3_crit, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 1, 3);
+static SENSOR_DEVICE_ATTR_2(in4_crit, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 1, 4);
+static SENSOR_DEVICE_ATTR_2(in5_crit, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 1, 5);
+static SENSOR_DEVICE_ATTR_2(in6_crit, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 1, 6);
+static SENSOR_DEVICE_ATTR_2(in7_crit, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 1, 7);
+static SENSOR_DEVICE_ATTR_2(in8_crit, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 1, 8);
+static SENSOR_DEVICE_ATTR_2(in9_crit, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 1, 9);
+static SENSOR_DEVICE_ATTR_2(in10_crit, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 1, 10);
+static SENSOR_DEVICE_ATTR_2(in11_crit, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 1, 11);
+
+/* Input voltages min */
+static SENSOR_DEVICE_ATTR_2(in0_min, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 0, 0);
+static SENSOR_DEVICE_ATTR_2(in1_min, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 0, 1);
+static SENSOR_DEVICE_ATTR_2(in2_min, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 0, 2);
+static SENSOR_DEVICE_ATTR_2(in3_min, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 0, 3);
+static SENSOR_DEVICE_ATTR_2(in4_min, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 0, 4);
+static SENSOR_DEVICE_ATTR_2(in5_min, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 0, 5);
+static SENSOR_DEVICE_ATTR_2(in6_min, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 0, 6);
+static SENSOR_DEVICE_ATTR_2(in7_min, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 0, 7);
+static SENSOR_DEVICE_ATTR_2(in8_min, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 0, 8);
+static SENSOR_DEVICE_ATTR_2(in9_min, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 0, 9);
+static SENSOR_DEVICE_ATTR_2(in10_min, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 0, 10);
+static SENSOR_DEVICE_ATTR_2(in11_min, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 0, 11);
+
+/* Input voltages max */
+static SENSOR_DEVICE_ATTR_2(in0_max, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 0, 0);
+static SENSOR_DEVICE_ATTR_2(in1_max, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 0, 1);
+static SENSOR_DEVICE_ATTR_2(in2_max, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 0, 2);
+static SENSOR_DEVICE_ATTR_2(in3_max, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 0, 3);
+static SENSOR_DEVICE_ATTR_2(in4_max, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 0, 4);
+static SENSOR_DEVICE_ATTR_2(in5_max, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 0, 5);
+static SENSOR_DEVICE_ATTR_2(in6_max, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 0, 6);
+static SENSOR_DEVICE_ATTR_2(in7_max, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 0, 7);
+static SENSOR_DEVICE_ATTR_2(in8_max, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 0, 8);
+static SENSOR_DEVICE_ATTR_2(in9_max, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 0, 9);
+static SENSOR_DEVICE_ATTR_2(in10_max, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 0, 10);
+static SENSOR_DEVICE_ATTR_2(in11_max, S_IWUSR | S_IRUGO, max16065_show_limit,
+ max16065_set_limit, 0, 11);
+
+/* alarms */
+static SENSOR_DEVICE_ATTR_2(in0_alarm, S_IRUGO, max16065_show_alarm, NULL,
+ 0, 0);
+static SENSOR_DEVICE_ATTR_2(in1_alarm, S_IRUGO, max16065_show_alarm, NULL,
+ 0, 1);
+static SENSOR_DEVICE_ATTR_2(in2_alarm, S_IRUGO, max16065_show_alarm, NULL,
+ 0, 2);
+static SENSOR_DEVICE_ATTR_2(in3_alarm, S_IRUGO, max16065_show_alarm, NULL,
+ 0, 3);
+static SENSOR_DEVICE_ATTR_2(in4_alarm, S_IRUGO, max16065_show_alarm, NULL,
+ 0, 4);
+static SENSOR_DEVICE_ATTR_2(in5_alarm, S_IRUGO, max16065_show_alarm, NULL,
+ 0, 5);
+static SENSOR_DEVICE_ATTR_2(in6_alarm, S_IRUGO, max16065_show_alarm, NULL,
+ 0, 6);
+static SENSOR_DEVICE_ATTR_2(in7_alarm, S_IRUGO, max16065_show_alarm, NULL,
+ 0, 7);
+static SENSOR_DEVICE_ATTR_2(in8_alarm, S_IRUGO, max16065_show_alarm, NULL,
+ 1, 0);
+static SENSOR_DEVICE_ATTR_2(in9_alarm, S_IRUGO, max16065_show_alarm, NULL,
+ 1, 1);
+static SENSOR_DEVICE_ATTR_2(in10_alarm, S_IRUGO, max16065_show_alarm, NULL,
+ 1, 2);
+static SENSOR_DEVICE_ATTR_2(in11_alarm, S_IRUGO, max16065_show_alarm, NULL,
+ 1, 3);
+
+/* Current and alarm */
+static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, max16065_show_current, NULL, 0);
+static SENSOR_DEVICE_ATTR_2(curr1_alarm, S_IRUGO, max16065_show_alarm, NULL,
+ 1, 4);
+
+/*
+ * Finally, construct an array of pointers to members of the above objects,
+ * as required for sysfs_create_group()
+ */
+static struct attribute *max16065_basic_attributes[] = {
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in0_lcrit.dev_attr.attr,
+ &sensor_dev_attr_in0_crit.dev_attr.attr,
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_lcrit.dev_attr.attr,
+ &sensor_dev_attr_in1_crit.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_lcrit.dev_attr.attr,
+ &sensor_dev_attr_in2_crit.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_lcrit.dev_attr.attr,
+ &sensor_dev_attr_in3_crit.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_lcrit.dev_attr.attr,
+ &sensor_dev_attr_in4_crit.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in5_lcrit.dev_attr.attr,
+ &sensor_dev_attr_in5_crit.dev_attr.attr,
+ &sensor_dev_attr_in5_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in6_lcrit.dev_attr.attr,
+ &sensor_dev_attr_in6_crit.dev_attr.attr,
+ &sensor_dev_attr_in6_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_in7_input.dev_attr.attr,
+ &sensor_dev_attr_in7_lcrit.dev_attr.attr,
+ &sensor_dev_attr_in7_crit.dev_attr.attr,
+ &sensor_dev_attr_in7_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_in8_input.dev_attr.attr,
+ &sensor_dev_attr_in8_lcrit.dev_attr.attr,
+ &sensor_dev_attr_in8_crit.dev_attr.attr,
+ &sensor_dev_attr_in8_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_in9_input.dev_attr.attr,
+ &sensor_dev_attr_in9_lcrit.dev_attr.attr,
+ &sensor_dev_attr_in9_crit.dev_attr.attr,
+ &sensor_dev_attr_in9_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_in10_input.dev_attr.attr,
+ &sensor_dev_attr_in10_lcrit.dev_attr.attr,
+ &sensor_dev_attr_in10_crit.dev_attr.attr,
+ &sensor_dev_attr_in10_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_in11_input.dev_attr.attr,
+ &sensor_dev_attr_in11_lcrit.dev_attr.attr,
+ &sensor_dev_attr_in11_crit.dev_attr.attr,
+ &sensor_dev_attr_in11_alarm.dev_attr.attr,
+
+ NULL
+};
+
+static struct attribute *max16065_current_attributes[] = {
+ &sensor_dev_attr_in12_input.dev_attr.attr,
+ &sensor_dev_attr_curr1_input.dev_attr.attr,
+ &sensor_dev_attr_curr1_alarm.dev_attr.attr,
+ NULL
+};
+
+static struct attribute *max16065_min_attributes[] = {
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in6_min.dev_attr.attr,
+ &sensor_dev_attr_in7_min.dev_attr.attr,
+ &sensor_dev_attr_in8_min.dev_attr.attr,
+ &sensor_dev_attr_in9_min.dev_attr.attr,
+ &sensor_dev_attr_in10_min.dev_attr.attr,
+ &sensor_dev_attr_in11_min.dev_attr.attr,
+ NULL
+};
+
+static struct attribute *max16065_max_attributes[] = {
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
+ &sensor_dev_attr_in6_max.dev_attr.attr,
+ &sensor_dev_attr_in7_max.dev_attr.attr,
+ &sensor_dev_attr_in8_max.dev_attr.attr,
+ &sensor_dev_attr_in9_max.dev_attr.attr,
+ &sensor_dev_attr_in10_max.dev_attr.attr,
+ &sensor_dev_attr_in11_max.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group max16065_basic_group = {
+ .attrs = max16065_basic_attributes,
+};
+
+static const struct attribute_group max16065_current_group = {
+ .attrs = max16065_current_attributes,
+};
+
+static const struct attribute_group max16065_min_group = {
+ .attrs = max16065_min_attributes,
+};
+
+static const struct attribute_group max16065_max_group = {
+ .attrs = max16065_max_attributes,
+};
+
+static void max16065_cleanup(struct i2c_client *client)
+{
+ sysfs_remove_group(&client->dev.kobj, &max16065_max_group);
+ sysfs_remove_group(&client->dev.kobj, &max16065_min_group);
+ sysfs_remove_group(&client->dev.kobj, &max16065_current_group);
+ sysfs_remove_group(&client->dev.kobj, &max16065_basic_group);
+}
+
+static int max16065_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct max16065_data *data;
+ int i, j, val, ret;
+ bool have_secondary; /* true if chip has secondary limits */
+ bool secondary_is_max = false; /* secondary limits reflect max */
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA
+ | I2C_FUNC_SMBUS_READ_WORD_DATA))
+ return -ENODEV;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (unlikely(!data))
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, data);
+ mutex_init(&data->update_lock);
+
+ data->num_adc = max16065_num_adc[id->driver_data];
+ data->have_current = max16065_have_current[id->driver_data];
+ have_secondary = max16065_have_secondary[id->driver_data];
+
+ if (have_secondary) {
+ val = i2c_smbus_read_byte_data(client, MAX16065_SW_ENABLE);
+ if (unlikely(val < 0)) {
+ ret = val;
+ goto out_free;
+ }
+ secondary_is_max = val & MAX16065_WARNING_OV;
+ }
+
+ /* Read scale registers, convert to range */
+ for (i = 0; i < DIV_ROUND_UP(data->num_adc, 4); i++) {
+ val = i2c_smbus_read_byte_data(client, MAX16065_SCALE(i));
+ if (unlikely(val < 0)) {
+ ret = val;
+ goto out_free;
+ }
+ for (j = 0; j < 4 && i * 4 + j < data->num_adc; j++) {
+ data->range[i * 4 + j] =
+ max16065_adc_range[(val >> (j * 2)) & 0x3];
+ }
+ }
+
+ /* Read limits */
+ for (i = 0; i < MAX16065_NUM_LIMIT; i++) {
+ if (i == 0 && !have_secondary)
+ continue;
+
+ for (j = 0; j < data->num_adc; j++) {
+ val = i2c_smbus_read_byte_data(client,
+ MAX16065_LIMIT(i, j));
+ if (unlikely(val < 0)) {
+ ret = val;
+ goto out_free;
+ }
+ data->limit[i][j] = LIMIT_TO_MV(val, data->range[j]);
+ }
+ }
+
+ /* Register sysfs hooks */
+ for (i = 0; i < data->num_adc * 4; i++) {
+ /* Do not create sysfs entry if channel is disabled */
+ if (!data->range[i / 4])
+ continue;
+
+ ret = sysfs_create_file(&client->dev.kobj,
+ max16065_basic_attributes[i]);
+ if (unlikely(ret))
+ goto out;
+ }
+
+ if (have_secondary) {
+ struct attribute **attr = secondary_is_max ?
+ max16065_max_attributes : max16065_min_attributes;
+
+ for (i = 0; i < data->num_adc; i++) {
+ if (!data->range[i])
+ continue;
+
+ ret = sysfs_create_file(&client->dev.kobj, attr[i]);
+ if (unlikely(ret))
+ goto out;
+ }
+ }
+
+ if (data->have_current) {
+ val = i2c_smbus_read_byte_data(client, MAX16065_CURR_CONTROL);
+ if (unlikely(val < 0)) {
+ ret = val;
+ goto out;
+ }
+ if (val & MAX16065_CURR_ENABLE) {
+ /*
+ * Current gain is 6, 12, 24, 48 based on values in
+ * bit 2,3.
+ */
+ data->curr_gain = 6 << ((val >> 2) & 0x03);
+ data->range[MAX16065_NUM_ADC]
+ = max16065_csp_adc_range[(val >> 1) & 0x01];
+ ret = sysfs_create_group(&client->dev.kobj,
+ &max16065_current_group);
+ if (unlikely(ret))
+ goto out;
+ } else {
+ data->have_current = false;
+ }
+ }
+
+ data->hwmon_dev = hwmon_device_register(&client->dev);
+ if (unlikely(IS_ERR(data->hwmon_dev))) {
+ ret = PTR_ERR(data->hwmon_dev);
+ goto out;
+ }
+ return 0;
+
+out:
+ max16065_cleanup(client);
+out_free:
+ kfree(data);
+ return ret;
+}
+
+static int max16065_remove(struct i2c_client *client)
+{
+ struct max16065_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ max16065_cleanup(client);
+ kfree(data);
+
+ return 0;
+}
+
+static const struct i2c_device_id max16065_id[] = {
+ { "max16065", max16065 },
+ { "max16066", max16066 },
+ { "max16067", max16067 },
+ { "max16068", max16068 },
+ { "max16070", max16070 },
+ { "max16071", max16071 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, max16065_id);
+
+/* This is the driver that will be inserted */
+static struct i2c_driver max16065_driver = {
+ .driver = {
+ .name = "max16065",
+ },
+ .probe = max16065_probe,
+ .remove = max16065_remove,
+ .id_table = max16065_id,
+};
+
+static int __init max16065_init(void)
+{
+ return i2c_add_driver(&max16065_driver);
+}
+
+static void __exit max16065_exit(void)
+{
+ i2c_del_driver(&max16065_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
+MODULE_DESCRIPTION("MAX16065 driver");
+MODULE_LICENSE("GPL");
+
+module_init(max16065_init);
+module_exit(max16065_exit);
diff --git a/drivers/hwmon/max34440.c b/drivers/hwmon/max34440.c
index 992b701b4c5e..db11e1a175b2 100644
--- a/drivers/hwmon/max34440.c
+++ b/drivers/hwmon/max34440.c
@@ -32,7 +32,7 @@ enum chips { max34440, max34441 };
#define MAX34440_STATUS_OT_FAULT (1 << 5)
#define MAX34440_STATUS_OT_WARN (1 << 6)
-static int max34440_get_status(struct i2c_client *client, int page, int reg)
+static int max34440_read_byte_data(struct i2c_client *client, int page, int reg)
{
int ret;
int mfg_status;
@@ -108,7 +108,7 @@ static struct pmbus_driver_info max34440_info[] = {
.func[11] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
.func[12] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
.func[13] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
- .get_status = max34440_get_status,
+ .read_byte_data = max34440_read_byte_data,
},
[max34441] = {
.pages = 12,
@@ -149,7 +149,7 @@ static struct pmbus_driver_info max34440_info[] = {
.func[9] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
.func[10] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
.func[11] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP,
- .get_status = max34440_get_status,
+ .read_byte_data = max34440_read_byte_data,
},
};
diff --git a/drivers/hwmon/max6642.c b/drivers/hwmon/max6642.c
new file mode 100644
index 000000000000..0f9fc40379cd
--- /dev/null
+++ b/drivers/hwmon/max6642.c
@@ -0,0 +1,356 @@
+/*
+ * Driver for +/-1 degree C, SMBus-Compatible Remote/Local Temperature Sensor
+ * with Overtemperature Alarm
+ *
+ * Copyright (C) 2011 AppearTV AS
+ *
+ * Derived from:
+ *
+ * Based on the max1619 driver.
+ * Copyright (C) 2003-2004 Alexey Fisher <fishor@mail.ru>
+ * Jean Delvare <khali@linux-fr.org>
+ *
+ * The MAX6642 is a sensor chip made by Maxim.
+ * It reports up to two temperatures (its own plus up to
+ * one external one). Complete datasheet can be
+ * obtained from Maxim's website at:
+ * http://datasheets.maxim-ic.com/en/ds/MAX6642.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+
+static const unsigned short normal_i2c[] = {
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
+
+/*
+ * The MAX6642 registers
+ */
+
+#define MAX6642_REG_R_MAN_ID 0xFE
+#define MAX6642_REG_R_CONFIG 0x03
+#define MAX6642_REG_W_CONFIG 0x09
+#define MAX6642_REG_R_STATUS 0x02
+#define MAX6642_REG_R_LOCAL_TEMP 0x00
+#define MAX6642_REG_R_LOCAL_TEMPL 0x11
+#define MAX6642_REG_R_LOCAL_HIGH 0x05
+#define MAX6642_REG_W_LOCAL_HIGH 0x0B
+#define MAX6642_REG_R_REMOTE_TEMP 0x01
+#define MAX6642_REG_R_REMOTE_TEMPL 0x10
+#define MAX6642_REG_R_REMOTE_HIGH 0x07
+#define MAX6642_REG_W_REMOTE_HIGH 0x0D
+
+/*
+ * Conversions
+ */
+
+static int temp_from_reg10(int val)
+{
+ return val * 250;
+}
+
+static int temp_from_reg(int val)
+{
+ return val * 1000;
+}
+
+static int temp_to_reg(int val)
+{
+ return val / 1000;
+}
+
+/*
+ * Client data (each client gets its own)
+ */
+
+struct max6642_data {
+ struct device *hwmon_dev;
+ struct mutex update_lock;
+ bool valid; /* zero until following fields are valid */
+ unsigned long last_updated; /* in jiffies */
+
+ /* registers values */
+ u16 temp_input[2]; /* local/remote */
+ u16 temp_high[2]; /* local/remote */
+ u8 alarms;
+};
+
+/*
+ * Real code
+ */
+
+static void max6642_init_client(struct i2c_client *client)
+{
+ u8 config;
+ struct max6642_data *data = i2c_get_clientdata(client);
+
+ /*
+ * Start the conversions.
+ */
+ config = i2c_smbus_read_byte_data(client, MAX6642_REG_R_CONFIG);
+ if (config & 0x40)
+ i2c_smbus_write_byte_data(client, MAX6642_REG_W_CONFIG,
+ config & 0xBF); /* run */
+
+ data->temp_high[0] = i2c_smbus_read_byte_data(client,
+ MAX6642_REG_R_LOCAL_HIGH);
+ data->temp_high[1] = i2c_smbus_read_byte_data(client,
+ MAX6642_REG_R_REMOTE_HIGH);
+}
+
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int max6642_detect(struct i2c_client *client,
+ struct i2c_board_info *info)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ u8 reg_config, reg_status, man_id;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
+
+ /* identification */
+ man_id = i2c_smbus_read_byte_data(client, MAX6642_REG_R_MAN_ID);
+ if (man_id != 0x4D)
+ return -ENODEV;
+
+ /*
+ * We read the config and status register, the 4 lower bits in the
+ * config register should be zero and bit 5, 3, 1 and 0 should be
+ * zero in the status register.
+ */
+ reg_config = i2c_smbus_read_byte_data(client, MAX6642_REG_R_CONFIG);
+ reg_status = i2c_smbus_read_byte_data(client, MAX6642_REG_R_STATUS);
+ if (((reg_config & 0x0f) != 0x00) ||
+ ((reg_status & 0x2b) != 0x00))
+ return -ENODEV;
+
+ strlcpy(info->type, "max6642", I2C_NAME_SIZE);
+
+ return 0;
+}
+
+static struct max6642_data *max6642_update_device(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct max6642_data *data = i2c_get_clientdata(client);
+ u16 val, tmp;
+
+ mutex_lock(&data->update_lock);
+
+ if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+ dev_dbg(&client->dev, "Updating max6642 data.\n");
+ val = i2c_smbus_read_byte_data(client,
+ MAX6642_REG_R_LOCAL_TEMPL);
+ tmp = (val >> 6) & 3;
+ val = i2c_smbus_read_byte_data(client,
+ MAX6642_REG_R_LOCAL_TEMP);
+ val = (val << 2) | tmp;
+ data->temp_input[0] = val;
+ val = i2c_smbus_read_byte_data(client,
+ MAX6642_REG_R_REMOTE_TEMPL);
+ tmp = (val >> 6) & 3;
+ val = i2c_smbus_read_byte_data(client,
+ MAX6642_REG_R_REMOTE_TEMP);
+ val = (val << 2) | tmp;
+ data->temp_input[1] = val;
+ data->alarms = i2c_smbus_read_byte_data(client,
+ MAX6642_REG_R_STATUS);
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
+/*
+ * Sysfs stuff
+ */
+
+static ssize_t show_temp_max10(struct device *dev,
+ struct device_attribute *dev_attr, char *buf)
+{
+ struct max6642_data *data = max6642_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(dev_attr);
+
+ return sprintf(buf, "%d\n",
+ temp_from_reg10(data->temp_input[attr->index]));
+}
+
+static ssize_t show_temp_max(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct max6642_data *data = max6642_update_device(dev);
+ struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(attr);
+
+ return sprintf(buf, "%d\n", temp_from_reg(data->temp_high[attr2->nr]));
+}
+
+static ssize_t set_temp_max(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long val;
+ int err;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct max6642_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute_2 *attr2 = to_sensor_dev_attr_2(attr);
+
+ err = strict_strtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ mutex_lock(&data->update_lock);
+ data->temp_high[attr2->nr] = SENSORS_LIMIT(temp_to_reg(val), 0, 255);
+ i2c_smbus_write_byte_data(client, attr2->index,
+ data->temp_high[attr2->nr]);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int bitnr = to_sensor_dev_attr(attr)->index;
+ struct max6642_data *data = max6642_update_device(dev);
+ return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_max10, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_max10, NULL, 1);
+static SENSOR_DEVICE_ATTR_2(temp1_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 0, MAX6642_REG_W_LOCAL_HIGH);
+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IWUSR | S_IRUGO, show_temp_max,
+ set_temp_max, 1, MAX6642_REG_W_REMOTE_HIGH);
+static SENSOR_DEVICE_ATTR(temp_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
+
+static struct attribute *max6642_attributes[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+
+ &sensor_dev_attr_temp_fault.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group max6642_group = {
+ .attrs = max6642_attributes,
+};
+
+static int max6642_probe(struct i2c_client *new_client,
+ const struct i2c_device_id *id)
+{
+ struct max6642_data *data;
+ int err;
+
+ data = kzalloc(sizeof(struct max6642_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(new_client, data);
+ mutex_init(&data->update_lock);
+
+ /* Initialize the MAX6642 chip */
+ max6642_init_client(new_client);
+
+ /* Register sysfs hooks */
+ err = sysfs_create_group(&new_client->dev.kobj, &max6642_group);
+ if (err)
+ goto exit_free;
+
+ data->hwmon_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->hwmon_dev)) {
+ err = PTR_ERR(data->hwmon_dev);
+ goto exit_remove_files;
+ }
+
+ return 0;
+
+exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &max6642_group);
+exit_free:
+ kfree(data);
+exit:
+ return err;
+}
+
+static int max6642_remove(struct i2c_client *client)
+{
+ struct max6642_data *data = i2c_get_clientdata(client);
+
+ hwmon_device_unregister(data->hwmon_dev);
+ sysfs_remove_group(&client->dev.kobj, &max6642_group);
+
+ kfree(data);
+ return 0;
+}
+
+/*
+ * Driver data (common to all clients)
+ */
+
+static const struct i2c_device_id max6642_id[] = {
+ { "max6642", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max6642_id);
+
+static struct i2c_driver max6642_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = "max6642",
+ },
+ .probe = max6642_probe,
+ .remove = max6642_remove,
+ .id_table = max6642_id,
+ .detect = max6642_detect,
+ .address_list = normal_i2c,
+};
+
+static int __init max6642_init(void)
+{
+ return i2c_add_driver(&max6642_driver);
+}
+
+static void __exit max6642_exit(void)
+{
+ i2c_del_driver(&max6642_driver);
+}
+
+MODULE_AUTHOR("Per Dalen <per.dalen@appeartv.com>");
+MODULE_DESCRIPTION("MAX6642 sensor driver");
+MODULE_LICENSE("GPL");
+
+module_init(max6642_init);
+module_exit(max6642_exit);
diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c
index 9a11532ecae8..ece3aafa54b3 100644
--- a/drivers/hwmon/max6650.c
+++ b/drivers/hwmon/max6650.c
@@ -41,13 +41,6 @@
#include <linux/err.h>
/*
- * Addresses to scan. There are four disjoint possibilities, by pin config.
- */
-
-static const unsigned short normal_i2c[] = {0x1b, 0x1f, 0x48, 0x4b,
- I2C_CLIENT_END};
-
-/*
* Insmod parameters
*/
@@ -114,8 +107,6 @@ module_param(clock, int, S_IRUGO);
static int max6650_probe(struct i2c_client *client,
const struct i2c_device_id *id);
-static int max6650_detect(struct i2c_client *client,
- struct i2c_board_info *info);
static int max6650_init_client(struct i2c_client *client);
static int max6650_remove(struct i2c_client *client);
static struct max6650_data *max6650_update_device(struct device *dev);
@@ -125,21 +116,19 @@ static struct max6650_data *max6650_update_device(struct device *dev);
*/
static const struct i2c_device_id max6650_id[] = {
- { "max6650", 0 },
+ { "max6650", 1 },
+ { "max6651", 4 },
{ }
};
MODULE_DEVICE_TABLE(i2c, max6650_id);
static struct i2c_driver max6650_driver = {
- .class = I2C_CLASS_HWMON,
.driver = {
.name = "max6650",
},
.probe = max6650_probe,
.remove = max6650_remove,
.id_table = max6650_id,
- .detect = max6650_detect,
- .address_list = normal_i2c,
};
/*
@@ -150,6 +139,7 @@ struct max6650_data
{
struct device *hwmon_dev;
struct mutex update_lock;
+ int nr_fans;
char valid; /* zero until following fields are valid */
unsigned long last_updated; /* in jiffies */
@@ -501,9 +491,6 @@ static mode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a,
static struct attribute *max6650_attrs[] = {
&sensor_dev_attr_fan1_input.dev_attr.attr,
- &sensor_dev_attr_fan2_input.dev_attr.attr,
- &sensor_dev_attr_fan3_input.dev_attr.attr,
- &sensor_dev_attr_fan4_input.dev_attr.attr,
&dev_attr_fan1_target.attr,
&dev_attr_fan1_div.attr,
&dev_attr_pwm1_enable.attr,
@@ -521,42 +508,21 @@ static struct attribute_group max6650_attr_grp = {
.is_visible = max6650_attrs_visible,
};
+static struct attribute *max6651_attrs[] = {
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan4_input.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group max6651_attr_grp = {
+ .attrs = max6651_attrs,
+};
+
/*
* Real code
*/
-/* Return 0 if detection is successful, -ENODEV otherwise */
-static int max6650_detect(struct i2c_client *client,
- struct i2c_board_info *info)
-{
- struct i2c_adapter *adapter = client->adapter;
- int address = client->addr;
-
- dev_dbg(&adapter->dev, "max6650_detect called\n");
-
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
- dev_dbg(&adapter->dev, "max6650: I2C bus doesn't support "
- "byte read mode, skipping.\n");
- return -ENODEV;
- }
-
- if (((i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG) & 0xC0)
- ||(i2c_smbus_read_byte_data(client, MAX6650_REG_GPIO_STAT) & 0xE0)
- ||(i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN) & 0xE0)
- ||(i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM) & 0xE0)
- ||(i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT) & 0xFC))) {
- dev_dbg(&adapter->dev,
- "max6650: detection failed at 0x%02x.\n", address);
- return -ENODEV;
- }
-
- dev_info(&adapter->dev, "max6650: chip found at 0x%02x.\n", address);
-
- strlcpy(info->type, "max6650", I2C_NAME_SIZE);
-
- return 0;
-}
-
static int max6650_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -570,6 +536,7 @@ static int max6650_probe(struct i2c_client *client,
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
+ data->nr_fans = id->driver_data;
/*
* Initialize the max6650 chip
@@ -581,6 +548,12 @@ static int max6650_probe(struct i2c_client *client,
err = sysfs_create_group(&client->dev.kobj, &max6650_attr_grp);
if (err)
goto err_free;
+ /* 3 additional fan inputs for the MAX6651 */
+ if (data->nr_fans == 4) {
+ err = sysfs_create_group(&client->dev.kobj, &max6651_attr_grp);
+ if (err)
+ goto err_remove;
+ }
data->hwmon_dev = hwmon_device_register(&client->dev);
if (!IS_ERR(data->hwmon_dev))
@@ -588,6 +561,9 @@ static int max6650_probe(struct i2c_client *client,
err = PTR_ERR(data->hwmon_dev);
dev_err(&client->dev, "error registering hwmon device.\n");
+ if (data->nr_fans == 4)
+ sysfs_remove_group(&client->dev.kobj, &max6651_attr_grp);
+err_remove:
sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
err_free:
kfree(data);
@@ -598,8 +574,10 @@ static int max6650_remove(struct i2c_client *client)
{
struct max6650_data *data = i2c_get_clientdata(client);
- sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
hwmon_device_unregister(data->hwmon_dev);
+ if (data->nr_fans == 4)
+ sysfs_remove_group(&client->dev.kobj, &max6651_attr_grp);
+ sysfs_remove_group(&client->dev.kobj, &max6650_attr_grp);
kfree(data);
return 0;
}
@@ -712,7 +690,7 @@ static struct max6650_data *max6650_update_device(struct device *dev)
MAX6650_REG_SPEED);
data->config = i2c_smbus_read_byte_data(client,
MAX6650_REG_CONFIG);
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < data->nr_fans; i++) {
data->tach[i] = i2c_smbus_read_byte_data(client,
tach_reg[i]);
}
diff --git a/drivers/hwmon/max8688.c b/drivers/hwmon/max8688.c
index 8ebfef2ecf26..7fb93f4e9f21 100644
--- a/drivers/hwmon/max8688.c
+++ b/drivers/hwmon/max8688.c
@@ -37,7 +37,7 @@
#define MAX8688_STATUS_OT_FAULT (1 << 13)
#define MAX8688_STATUS_OT_WARNING (1 << 14)
-static int max8688_get_status(struct i2c_client *client, int page, int reg)
+static int max8688_read_byte_data(struct i2c_client *client, int page, int reg)
{
int ret = 0;
int mfg_status;
@@ -110,7 +110,7 @@ static struct pmbus_driver_info max8688_info = {
.func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_TEMP
| PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT
| PMBUS_HAVE_STATUS_TEMP,
- .get_status = max8688_get_status,
+ .read_byte_data = max8688_read_byte_data,
};
static int max8688_probe(struct i2c_client *client,
diff --git a/drivers/hwmon/pkgtemp.c b/drivers/hwmon/pkgtemp.c
deleted file mode 100644
index 21c817d98123..000000000000
--- a/drivers/hwmon/pkgtemp.c
+++ /dev/null
@@ -1,444 +0,0 @@
-/*
- * 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.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.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 <asm/msr.h>
-#include <asm/processor.h>
-#include <asm/smp.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_dev;
-
- 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_dev:
- device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr);
-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);
- device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr);
- 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;
- struct cpuinfo_x86 *c = &cpu_data(cpu);
-
- if (!cpu_has(c, X86_FEATURE_PTS))
- return 0;
-
- 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;
- pr_err("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) {
- pr_err("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;
-}
-
-static void __cpuinit pkgtemp_device_remove(unsigned int cpu)
-{
- struct pdev_entry *p;
- unsigned int i;
- int err;
-
- mutex_lock(&pdev_list_mutex);
- list_for_each_entry(p, &pdev_list, list) {
- if (p->cpu != cpu)
- continue;
-
- platform_device_unregister(p->pdev);
- list_del(&p->list);
- mutex_unlock(&pdev_list_mutex);
- kfree(p);
- for_each_cpu(i, cpu_core_mask(cpu)) {
- if (i != cpu) {
- err = pkgtemp_device_add(i);
- if (!err)
- break;
- }
- }
- return;
- }
- 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,
-};
-
-static int __init pkgtemp_init(void)
-{
- int i, err = -ENODEV;
-
- /* 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)
- pkgtemp_device_add(i);
-
-#ifndef CONFIG_HOTPLUG_CPU
- if (list_empty(&pdev_list)) {
- err = -ENODEV;
- goto exit_driver_unreg;
- }
-#endif
-
- register_hotcpu_notifier(&pkgtemp_cpu_notifier);
- return 0;
-
-#ifndef CONFIG_HOTPLUG_CPU
-exit_driver_unreg:
- platform_driver_unregister(&pkgtemp_driver);
-#endif
-exit:
- return err;
-}
-
-static void __exit pkgtemp_exit(void)
-{
- struct pdev_entry *p, *n;
-
- unregister_hotcpu_notifier(&pkgtemp_cpu_notifier);
- 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/pmbus.h b/drivers/hwmon/pmbus.h
index a81f7f228762..50647ab7235a 100644
--- a/drivers/hwmon/pmbus.h
+++ b/drivers/hwmon/pmbus.h
@@ -281,13 +281,11 @@ struct pmbus_driver_info {
u32 func[PMBUS_PAGES]; /* Functionality, per page */
/*
- * The get_status function maps manufacturing specific status values
- * into PMBus standard status values.
- * This function is optional and only necessary if chip specific status
- * register values have to be mapped into standard PMBus status register
- * values.
+ * The following functions map manufacturing specific register values
+ * to PMBus standard register values. Specify only if mapping is
+ * necessary.
*/
- int (*get_status)(struct i2c_client *client, int page, int reg);
+ int (*read_byte_data)(struct i2c_client *client, int page, int reg);
/*
* The identify function determines supported PMBus functionality.
* This function is only necessary if a chip driver supports multiple
diff --git a/drivers/hwmon/pmbus_core.c b/drivers/hwmon/pmbus_core.c
index 196ffafafd88..354770ed3186 100644
--- a/drivers/hwmon/pmbus_core.c
+++ b/drivers/hwmon/pmbus_core.c
@@ -270,18 +270,22 @@ const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client *client)
}
EXPORT_SYMBOL_GPL(pmbus_get_driver_info);
-static int pmbus_get_status(struct i2c_client *client, int page, int reg)
+/*
+ * _pmbus_read_byte_data() is similar to pmbus_read_byte_data(), but checks if
+ * a device specific mapping funcion exists and calls it if necessary.
+ */
+static int _pmbus_read_byte_data(struct i2c_client *client, int page, int reg)
{
struct pmbus_data *data = i2c_get_clientdata(client);
const struct pmbus_driver_info *info = data->info;
int status;
- if (info->get_status) {
- status = info->get_status(client, page, reg);
+ if (info->read_byte_data) {
+ status = info->read_byte_data(client, page, reg);
if (status != -ENODATA)
return status;
}
- return pmbus_read_byte_data(client, page, reg);
+ return pmbus_read_byte_data(client, page, reg);
}
static struct pmbus_data *pmbus_update_device(struct device *dev)
@@ -302,38 +306,41 @@ static struct pmbus_data *pmbus_update_device(struct device *dev)
if (!(info->func[i] & PMBUS_HAVE_STATUS_VOUT))
continue;
data->status[PB_STATUS_VOUT_BASE + i]
- = pmbus_get_status(client, i, PMBUS_STATUS_VOUT);
+ = _pmbus_read_byte_data(client, i, PMBUS_STATUS_VOUT);
}
for (i = 0; i < info->pages; i++) {
if (!(info->func[i] & PMBUS_HAVE_STATUS_IOUT))
continue;
data->status[PB_STATUS_IOUT_BASE + i]
- = pmbus_get_status(client, i, PMBUS_STATUS_IOUT);
+ = _pmbus_read_byte_data(client, i, PMBUS_STATUS_IOUT);
}
for (i = 0; i < info->pages; i++) {
if (!(info->func[i] & PMBUS_HAVE_STATUS_TEMP))
continue;
data->status[PB_STATUS_TEMP_BASE + i]
- = pmbus_get_status(client, i,
- PMBUS_STATUS_TEMPERATURE);
+ = _pmbus_read_byte_data(client, i,
+ PMBUS_STATUS_TEMPERATURE);
}
for (i = 0; i < info->pages; i++) {
if (!(info->func[i] & PMBUS_HAVE_STATUS_FAN12))
continue;
data->status[PB_STATUS_FAN_BASE + i]
- = pmbus_get_status(client, i, PMBUS_STATUS_FAN_12);
+ = _pmbus_read_byte_data(client, i,
+ PMBUS_STATUS_FAN_12);
}
for (i = 0; i < info->pages; i++) {
if (!(info->func[i] & PMBUS_HAVE_STATUS_FAN34))
continue;
data->status[PB_STATUS_FAN34_BASE + i]
- = pmbus_get_status(client, i, PMBUS_STATUS_FAN_34);
+ = _pmbus_read_byte_data(client, i,
+ PMBUS_STATUS_FAN_34);
}
if (info->func[0] & PMBUS_HAVE_STATUS_INPUT)
data->status[PB_STATUS_INPUT_BASE]
- = pmbus_get_status(client, 0, PMBUS_STATUS_INPUT);
+ = _pmbus_read_byte_data(client, 0,
+ PMBUS_STATUS_INPUT);
for (i = 0; i < data->num_sensors; i++) {
struct pmbus_sensor *sensor = &data->sensors[i];
@@ -700,6 +707,7 @@ do { \
struct sensor_device_attribute *a \
= &data->_type##s[data->num_##_type##s].attribute; \
BUG_ON(data->num_attributes >= data->max_attributes); \
+ sysfs_attr_init(&a->dev_attr.attr); \
a->dev_attr.attr.name = _name; \
a->dev_attr.attr.mode = _mode; \
a->dev_attr.show = _show; \
@@ -793,53 +801,6 @@ static void pmbus_add_label(struct pmbus_data *data,
data->num_labels++;
}
-static const int pmbus_temp_registers[] = {
- PMBUS_READ_TEMPERATURE_1,
- PMBUS_READ_TEMPERATURE_2,
- PMBUS_READ_TEMPERATURE_3
-};
-
-static const int pmbus_temp_flags[] = {
- PMBUS_HAVE_TEMP,
- PMBUS_HAVE_TEMP2,
- PMBUS_HAVE_TEMP3
-};
-
-static const int pmbus_fan_registers[] = {
- PMBUS_READ_FAN_SPEED_1,
- PMBUS_READ_FAN_SPEED_2,
- PMBUS_READ_FAN_SPEED_3,
- PMBUS_READ_FAN_SPEED_4
-};
-
-static const int pmbus_fan_config_registers[] = {
- PMBUS_FAN_CONFIG_12,
- PMBUS_FAN_CONFIG_12,
- PMBUS_FAN_CONFIG_34,
- PMBUS_FAN_CONFIG_34
-};
-
-static const int pmbus_fan_status_registers[] = {
- PMBUS_STATUS_FAN_12,
- PMBUS_STATUS_FAN_12,
- PMBUS_STATUS_FAN_34,
- PMBUS_STATUS_FAN_34
-};
-
-static const u32 pmbus_fan_flags[] = {
- PMBUS_HAVE_FAN12,
- PMBUS_HAVE_FAN12,
- PMBUS_HAVE_FAN34,
- PMBUS_HAVE_FAN34
-};
-
-static const u32 pmbus_fan_status_flags[] = {
- PMBUS_HAVE_STATUS_FAN12,
- PMBUS_HAVE_STATUS_FAN12,
- PMBUS_HAVE_STATUS_FAN34,
- PMBUS_HAVE_STATUS_FAN34
-};
-
/*
* Determine maximum number of sensors, booleans, and labels.
* To keep things simple, only make a rough high estimate.
@@ -900,499 +861,431 @@ static void pmbus_find_max_attr(struct i2c_client *client,
/*
* Search for attributes. Allocate sensors, booleans, and labels as needed.
*/
-static void pmbus_find_attributes(struct i2c_client *client,
- struct pmbus_data *data)
-{
- const struct pmbus_driver_info *info = data->info;
- int page, i0, i1, in_index;
- /*
- * Input voltage sensors
- */
- in_index = 1;
- if (info->func[0] & PMBUS_HAVE_VIN) {
- bool have_alarm = false;
-
- i0 = data->num_sensors;
- pmbus_add_label(data, "in", in_index, "vin", 0);
- pmbus_add_sensor(data, "in", "input", in_index, 0,
- PMBUS_READ_VIN, PSC_VOLTAGE_IN, true, true);
- if (pmbus_check_word_register(client, 0,
- PMBUS_VIN_UV_WARN_LIMIT)) {
- i1 = data->num_sensors;
- pmbus_add_sensor(data, "in", "min", in_index,
- 0, PMBUS_VIN_UV_WARN_LIMIT,
- PSC_VOLTAGE_IN, false, false);
- if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) {
- pmbus_add_boolean_reg(data, "in", "min_alarm",
- in_index,
- PB_STATUS_INPUT_BASE,
- PB_VOLTAGE_UV_WARNING);
- have_alarm = true;
- }
- }
- if (pmbus_check_word_register(client, 0,
- PMBUS_VIN_UV_FAULT_LIMIT)) {
- i1 = data->num_sensors;
- pmbus_add_sensor(data, "in", "lcrit", in_index,
- 0, PMBUS_VIN_UV_FAULT_LIMIT,
- PSC_VOLTAGE_IN, false, false);
- if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) {
- pmbus_add_boolean_reg(data, "in", "lcrit_alarm",
- in_index,
- PB_STATUS_INPUT_BASE,
- PB_VOLTAGE_UV_FAULT);
- have_alarm = true;
- }
- }
- if (pmbus_check_word_register(client, 0,
- PMBUS_VIN_OV_WARN_LIMIT)) {
- i1 = data->num_sensors;
- pmbus_add_sensor(data, "in", "max", in_index,
- 0, PMBUS_VIN_OV_WARN_LIMIT,
- PSC_VOLTAGE_IN, false, false);
- if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) {
- pmbus_add_boolean_reg(data, "in", "max_alarm",
- in_index,
- PB_STATUS_INPUT_BASE,
- PB_VOLTAGE_OV_WARNING);
- have_alarm = true;
- }
- }
- if (pmbus_check_word_register(client, 0,
- PMBUS_VIN_OV_FAULT_LIMIT)) {
- i1 = data->num_sensors;
- pmbus_add_sensor(data, "in", "crit", in_index,
- 0, PMBUS_VIN_OV_FAULT_LIMIT,
- PSC_VOLTAGE_IN, false, false);
- if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) {
- pmbus_add_boolean_reg(data, "in", "crit_alarm",
- in_index,
- PB_STATUS_INPUT_BASE,
- PB_VOLTAGE_OV_FAULT);
+/*
+ * The pmbus_limit_attr structure describes a single limit attribute
+ * and its associated alarm attribute.
+ */
+struct pmbus_limit_attr {
+ u8 reg; /* Limit register */
+ const char *attr; /* Attribute name */
+ const char *alarm; /* Alarm attribute name */
+ u32 sbit; /* Alarm attribute status bit */
+};
+
+/*
+ * The pmbus_sensor_attr structure describes one sensor attribute. This
+ * description includes a reference to the associated limit attributes.
+ */
+struct pmbus_sensor_attr {
+ u8 reg; /* sensor register */
+ enum pmbus_sensor_classes class;/* sensor class */
+ const char *label; /* sensor label */
+ bool paged; /* true if paged sensor */
+ bool update; /* true if update needed */
+ bool compare; /* true if compare function needed */
+ u32 func; /* sensor mask */
+ u32 sfunc; /* sensor status mask */
+ int sbase; /* status base register */
+ u32 gbit; /* generic status bit */
+ const struct pmbus_limit_attr *limit;/* limit registers */
+ int nlimit; /* # of limit registers */
+};
+
+/*
+ * Add a set of limit attributes and, if supported, the associated
+ * alarm attributes.
+ */
+static bool pmbus_add_limit_attrs(struct i2c_client *client,
+ struct pmbus_data *data,
+ const struct pmbus_driver_info *info,
+ const char *name, int index, int page,
+ int cbase,
+ const struct pmbus_sensor_attr *attr)
+{
+ const struct pmbus_limit_attr *l = attr->limit;
+ int nlimit = attr->nlimit;
+ bool have_alarm = false;
+ int i, cindex;
+
+ for (i = 0; i < nlimit; i++) {
+ if (pmbus_check_word_register(client, page, l->reg)) {
+ cindex = data->num_sensors;
+ pmbus_add_sensor(data, name, l->attr, index, page,
+ l->reg, attr->class, attr->update,
+ false);
+ if (info->func[page] & attr->sfunc) {
+ if (attr->compare) {
+ pmbus_add_boolean_cmp(data, name,
+ l->alarm, index,
+ cbase, cindex,
+ attr->sbase + page, l->sbit);
+ } else {
+ pmbus_add_boolean_reg(data, name,
+ l->alarm, index,
+ attr->sbase + page, l->sbit);
+ }
have_alarm = true;
}
}
- /*
- * Add generic alarm attribute only if there are no individual
- * attributes.
- */
- if (!have_alarm)
- pmbus_add_boolean_reg(data, "in", "alarm",
- in_index,
- PB_STATUS_BASE,
- PB_STATUS_VIN_UV);
- in_index++;
- }
- if (info->func[0] & PMBUS_HAVE_VCAP) {
- pmbus_add_label(data, "in", in_index, "vcap", 0);
- pmbus_add_sensor(data, "in", "input", in_index, 0,
- PMBUS_READ_VCAP, PSC_VOLTAGE_IN, true, true);
- in_index++;
+ l++;
}
+ return have_alarm;
+}
- /*
- * Output voltage sensors
- */
- for (page = 0; page < info->pages; page++) {
- bool have_alarm = false;
-
- if (!(info->func[page] & PMBUS_HAVE_VOUT))
- continue;
-
- i0 = data->num_sensors;
- pmbus_add_label(data, "in", in_index, "vout", page + 1);
- pmbus_add_sensor(data, "in", "input", in_index, page,
- PMBUS_READ_VOUT, PSC_VOLTAGE_OUT, true, true);
- if (pmbus_check_word_register(client, page,
- PMBUS_VOUT_UV_WARN_LIMIT)) {
- i1 = data->num_sensors;
- pmbus_add_sensor(data, "in", "min", in_index, page,
- PMBUS_VOUT_UV_WARN_LIMIT,
- PSC_VOLTAGE_OUT, false, false);
- if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) {
- pmbus_add_boolean_reg(data, "in", "min_alarm",
- in_index,
- PB_STATUS_VOUT_BASE +
- page,
- PB_VOLTAGE_UV_WARNING);
- have_alarm = true;
- }
- }
- if (pmbus_check_word_register(client, page,
- PMBUS_VOUT_UV_FAULT_LIMIT)) {
- i1 = data->num_sensors;
- pmbus_add_sensor(data, "in", "lcrit", in_index, page,
- PMBUS_VOUT_UV_FAULT_LIMIT,
- PSC_VOLTAGE_OUT, false, false);
- if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) {
- pmbus_add_boolean_reg(data, "in", "lcrit_alarm",
- in_index,
- PB_STATUS_VOUT_BASE +
- page,
- PB_VOLTAGE_UV_FAULT);
- have_alarm = true;
- }
- }
- if (pmbus_check_word_register(client, page,
- PMBUS_VOUT_OV_WARN_LIMIT)) {
- i1 = data->num_sensors;
- pmbus_add_sensor(data, "in", "max", in_index, page,
- PMBUS_VOUT_OV_WARN_LIMIT,
- PSC_VOLTAGE_OUT, false, false);
- if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) {
- pmbus_add_boolean_reg(data, "in", "max_alarm",
- in_index,
- PB_STATUS_VOUT_BASE +
- page,
- PB_VOLTAGE_OV_WARNING);
- have_alarm = true;
- }
- }
- if (pmbus_check_word_register(client, page,
- PMBUS_VOUT_OV_FAULT_LIMIT)) {
- i1 = data->num_sensors;
- pmbus_add_sensor(data, "in", "crit", in_index, page,
- PMBUS_VOUT_OV_FAULT_LIMIT,
- PSC_VOLTAGE_OUT, false, false);
- if (info->func[page] & PMBUS_HAVE_STATUS_VOUT) {
- pmbus_add_boolean_reg(data, "in", "crit_alarm",
- in_index,
- PB_STATUS_VOUT_BASE +
- page,
- PB_VOLTAGE_OV_FAULT);
- have_alarm = true;
- }
- }
+static void pmbus_add_sensor_attrs_one(struct i2c_client *client,
+ struct pmbus_data *data,
+ const struct pmbus_driver_info *info,
+ const char *name,
+ int index, int page,
+ const struct pmbus_sensor_attr *attr)
+{
+ bool have_alarm;
+ int cbase = data->num_sensors;
+
+ if (attr->label)
+ pmbus_add_label(data, name, index, attr->label,
+ attr->paged ? page + 1 : 0);
+ pmbus_add_sensor(data, name, "input", index, page, attr->reg,
+ attr->class, true, true);
+ if (attr->sfunc) {
+ have_alarm = pmbus_add_limit_attrs(client, data, info, name,
+ index, page, cbase, attr);
/*
* Add generic alarm attribute only if there are no individual
- * attributes.
+ * alarm attributes, and if there is a global alarm bit.
*/
- if (!have_alarm)
- pmbus_add_boolean_reg(data, "in", "alarm",
- in_index,
+ if (!have_alarm && attr->gbit)
+ pmbus_add_boolean_reg(data, name, "alarm", index,
PB_STATUS_BASE + page,
- PB_STATUS_VOUT_OV);
- in_index++;
+ attr->gbit);
}
+}
- /*
- * Current sensors
- */
+static void pmbus_add_sensor_attrs(struct i2c_client *client,
+ struct pmbus_data *data,
+ const char *name,
+ const struct pmbus_sensor_attr *attrs,
+ int nattrs)
+{
+ const struct pmbus_driver_info *info = data->info;
+ int index, i;
- /*
- * Input current sensors
- */
- in_index = 1;
- if (info->func[0] & PMBUS_HAVE_IIN) {
- i0 = data->num_sensors;
- pmbus_add_label(data, "curr", in_index, "iin", 0);
- pmbus_add_sensor(data, "curr", "input", in_index, 0,
- PMBUS_READ_IIN, PSC_CURRENT_IN, true, true);
- if (pmbus_check_word_register(client, 0,
- PMBUS_IIN_OC_WARN_LIMIT)) {
- i1 = data->num_sensors;
- pmbus_add_sensor(data, "curr", "max", in_index,
- 0, PMBUS_IIN_OC_WARN_LIMIT,
- PSC_CURRENT_IN, false, false);
- if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) {
- pmbus_add_boolean_reg(data, "curr", "max_alarm",
- in_index,
- PB_STATUS_INPUT_BASE,
- PB_IIN_OC_WARNING);
- }
- }
- if (pmbus_check_word_register(client, 0,
- PMBUS_IIN_OC_FAULT_LIMIT)) {
- i1 = data->num_sensors;
- pmbus_add_sensor(data, "curr", "crit", in_index,
- 0, PMBUS_IIN_OC_FAULT_LIMIT,
- PSC_CURRENT_IN, false, false);
- if (info->func[0] & PMBUS_HAVE_STATUS_INPUT)
- pmbus_add_boolean_reg(data, "curr",
- "crit_alarm",
- in_index,
- PB_STATUS_INPUT_BASE,
- PB_IIN_OC_FAULT);
+ index = 1;
+ for (i = 0; i < nattrs; i++) {
+ int page, pages;
+
+ pages = attrs->paged ? info->pages : 1;
+ for (page = 0; page < pages; page++) {
+ if (!(info->func[page] & attrs->func))
+ continue;
+ pmbus_add_sensor_attrs_one(client, data, info, name,
+ index, page, attrs);
+ index++;
}
- in_index++;
+ attrs++;
}
+}
- /*
- * Output current sensors
- */
- for (page = 0; page < info->pages; page++) {
- bool have_alarm = false;
-
- if (!(info->func[page] & PMBUS_HAVE_IOUT))
- continue;
-
- i0 = data->num_sensors;
- pmbus_add_label(data, "curr", in_index, "iout", page + 1);
- pmbus_add_sensor(data, "curr", "input", in_index, page,
- PMBUS_READ_IOUT, PSC_CURRENT_OUT, true, true);
- if (pmbus_check_word_register(client, page,
- PMBUS_IOUT_OC_WARN_LIMIT)) {
- i1 = data->num_sensors;
- pmbus_add_sensor(data, "curr", "max", in_index, page,
- PMBUS_IOUT_OC_WARN_LIMIT,
- PSC_CURRENT_OUT, false, false);
- if (info->func[page] & PMBUS_HAVE_STATUS_IOUT) {
- pmbus_add_boolean_reg(data, "curr", "max_alarm",
- in_index,
- PB_STATUS_IOUT_BASE +
- page, PB_IOUT_OC_WARNING);
- have_alarm = true;
- }
- }
- if (pmbus_check_word_register(client, page,
- PMBUS_IOUT_UC_FAULT_LIMIT)) {
- i1 = data->num_sensors;
- pmbus_add_sensor(data, "curr", "lcrit", in_index, page,
- PMBUS_IOUT_UC_FAULT_LIMIT,
- PSC_CURRENT_OUT, false, false);
- if (info->func[page] & PMBUS_HAVE_STATUS_IOUT) {
- pmbus_add_boolean_reg(data, "curr",
- "lcrit_alarm",
- in_index,
- PB_STATUS_IOUT_BASE +
- page, PB_IOUT_UC_FAULT);
- have_alarm = true;
- }
- }
- if (pmbus_check_word_register(client, page,
- PMBUS_IOUT_OC_FAULT_LIMIT)) {
- i1 = data->num_sensors;
- pmbus_add_sensor(data, "curr", "crit", in_index, page,
- PMBUS_IOUT_OC_FAULT_LIMIT,
- PSC_CURRENT_OUT, false, false);
- if (info->func[page] & PMBUS_HAVE_STATUS_IOUT) {
- pmbus_add_boolean_reg(data, "curr",
- "crit_alarm",
- in_index,
- PB_STATUS_IOUT_BASE +
- page, PB_IOUT_OC_FAULT);
- have_alarm = true;
- }
- }
- /*
- * Add generic alarm attribute only if there are no individual
- * attributes.
- */
- if (!have_alarm)
- pmbus_add_boolean_reg(data, "curr", "alarm",
- in_index,
- PB_STATUS_BASE + page,
- PB_STATUS_IOUT_OC);
- in_index++;
+static const struct pmbus_limit_attr vin_limit_attrs[] = {
+ {
+ .reg = PMBUS_VIN_UV_WARN_LIMIT,
+ .attr = "min",
+ .alarm = "min_alarm",
+ .sbit = PB_VOLTAGE_UV_WARNING,
+ }, {
+ .reg = PMBUS_VIN_UV_FAULT_LIMIT,
+ .attr = "lcrit",
+ .alarm = "lcrit_alarm",
+ .sbit = PB_VOLTAGE_UV_FAULT,
+ }, {
+ .reg = PMBUS_VIN_OV_WARN_LIMIT,
+ .attr = "max",
+ .alarm = "max_alarm",
+ .sbit = PB_VOLTAGE_OV_WARNING,
+ }, {
+ .reg = PMBUS_VIN_OV_FAULT_LIMIT,
+ .attr = "crit",
+ .alarm = "crit_alarm",
+ .sbit = PB_VOLTAGE_OV_FAULT,
+ },
+};
+
+static const struct pmbus_limit_attr vout_limit_attrs[] = {
+ {
+ .reg = PMBUS_VOUT_UV_WARN_LIMIT,
+ .attr = "min",
+ .alarm = "min_alarm",
+ .sbit = PB_VOLTAGE_UV_WARNING,
+ }, {
+ .reg = PMBUS_VOUT_UV_FAULT_LIMIT,
+ .attr = "lcrit",
+ .alarm = "lcrit_alarm",
+ .sbit = PB_VOLTAGE_UV_FAULT,
+ }, {
+ .reg = PMBUS_VOUT_OV_WARN_LIMIT,
+ .attr = "max",
+ .alarm = "max_alarm",
+ .sbit = PB_VOLTAGE_OV_WARNING,
+ }, {
+ .reg = PMBUS_VOUT_OV_FAULT_LIMIT,
+ .attr = "crit",
+ .alarm = "crit_alarm",
+ .sbit = PB_VOLTAGE_OV_FAULT,
}
+};
- /*
- * Power sensors
- */
- /*
- * Input Power sensors
- */
- in_index = 1;
- if (info->func[0] & PMBUS_HAVE_PIN) {
- i0 = data->num_sensors;
- pmbus_add_label(data, "power", in_index, "pin", 0);
- pmbus_add_sensor(data, "power", "input", in_index,
- 0, PMBUS_READ_PIN, PSC_POWER, true, true);
- if (pmbus_check_word_register(client, 0,
- PMBUS_PIN_OP_WARN_LIMIT)) {
- i1 = data->num_sensors;
- pmbus_add_sensor(data, "power", "max", in_index,
- 0, PMBUS_PIN_OP_WARN_LIMIT, PSC_POWER,
- false, false);
- if (info->func[0] & PMBUS_HAVE_STATUS_INPUT)
- pmbus_add_boolean_reg(data, "power",
- "alarm",
- in_index,
- PB_STATUS_INPUT_BASE,
- PB_PIN_OP_WARNING);
- }
- in_index++;
+static const struct pmbus_sensor_attr voltage_attributes[] = {
+ {
+ .reg = PMBUS_READ_VIN,
+ .class = PSC_VOLTAGE_IN,
+ .label = "vin",
+ .func = PMBUS_HAVE_VIN,
+ .sfunc = PMBUS_HAVE_STATUS_INPUT,
+ .sbase = PB_STATUS_INPUT_BASE,
+ .gbit = PB_STATUS_VIN_UV,
+ .limit = vin_limit_attrs,
+ .nlimit = ARRAY_SIZE(vin_limit_attrs),
+ }, {
+ .reg = PMBUS_READ_VCAP,
+ .class = PSC_VOLTAGE_IN,
+ .label = "vcap",
+ .func = PMBUS_HAVE_VCAP,
+ }, {
+ .reg = PMBUS_READ_VOUT,
+ .class = PSC_VOLTAGE_OUT,
+ .label = "vout",
+ .paged = true,
+ .func = PMBUS_HAVE_VOUT,
+ .sfunc = PMBUS_HAVE_STATUS_VOUT,
+ .sbase = PB_STATUS_VOUT_BASE,
+ .gbit = PB_STATUS_VOUT_OV,
+ .limit = vout_limit_attrs,
+ .nlimit = ARRAY_SIZE(vout_limit_attrs),
}
+};
- /*
- * Output Power sensors
- */
- for (page = 0; page < info->pages; page++) {
- bool need_alarm = false;
+/* Current attributes */
+
+static const struct pmbus_limit_attr iin_limit_attrs[] = {
+ {
+ .reg = PMBUS_IIN_OC_WARN_LIMIT,
+ .attr = "max",
+ .alarm = "max_alarm",
+ .sbit = PB_IIN_OC_WARNING,
+ }, {
+ .reg = PMBUS_IIN_OC_FAULT_LIMIT,
+ .attr = "crit",
+ .alarm = "crit_alarm",
+ .sbit = PB_IIN_OC_FAULT,
+ }
+};
- if (!(info->func[page] & PMBUS_HAVE_POUT))
- continue;
+static const struct pmbus_limit_attr iout_limit_attrs[] = {
+ {
+ .reg = PMBUS_IOUT_OC_WARN_LIMIT,
+ .attr = "max",
+ .alarm = "max_alarm",
+ .sbit = PB_IOUT_OC_WARNING,
+ }, {
+ .reg = PMBUS_IOUT_UC_FAULT_LIMIT,
+ .attr = "lcrit",
+ .alarm = "lcrit_alarm",
+ .sbit = PB_IOUT_UC_FAULT,
+ }, {
+ .reg = PMBUS_IOUT_OC_FAULT_LIMIT,
+ .attr = "crit",
+ .alarm = "crit_alarm",
+ .sbit = PB_IOUT_OC_FAULT,
+ }
+};
- i0 = data->num_sensors;
- pmbus_add_label(data, "power", in_index, "pout", page + 1);
- pmbus_add_sensor(data, "power", "input", in_index, page,
- PMBUS_READ_POUT, PSC_POWER, true, true);
- /*
- * Per hwmon sysfs API, power_cap is to be used to limit output
- * power.
- * We have two registers related to maximum output power,
- * PMBUS_POUT_MAX and PMBUS_POUT_OP_WARN_LIMIT.
- * PMBUS_POUT_MAX matches the powerX_cap attribute definition.
- * There is no attribute in the API to match
- * PMBUS_POUT_OP_WARN_LIMIT. We use powerX_max for now.
- */
- if (pmbus_check_word_register(client, page, PMBUS_POUT_MAX)) {
- i1 = data->num_sensors;
- pmbus_add_sensor(data, "power", "cap", in_index, page,
- PMBUS_POUT_MAX, PSC_POWER,
- false, false);
- need_alarm = true;
- }
- if (pmbus_check_word_register(client, page,
- PMBUS_POUT_OP_WARN_LIMIT)) {
- i1 = data->num_sensors;
- pmbus_add_sensor(data, "power", "max", in_index, page,
- PMBUS_POUT_OP_WARN_LIMIT, PSC_POWER,
- false, false);
- need_alarm = true;
- }
- if (need_alarm && (info->func[page] & PMBUS_HAVE_STATUS_IOUT))
- pmbus_add_boolean_reg(data, "power", "alarm",
- in_index,
- PB_STATUS_IOUT_BASE + page,
- PB_POUT_OP_WARNING
- | PB_POWER_LIMITING);
-
- if (pmbus_check_word_register(client, page,
- PMBUS_POUT_OP_FAULT_LIMIT)) {
- i1 = data->num_sensors;
- pmbus_add_sensor(data, "power", "crit", in_index, page,
- PMBUS_POUT_OP_FAULT_LIMIT, PSC_POWER,
- false, false);
- if (info->func[page] & PMBUS_HAVE_STATUS_IOUT)
- pmbus_add_boolean_reg(data, "power",
- "crit_alarm",
- in_index,
- PB_STATUS_IOUT_BASE
- + page,
- PB_POUT_OP_FAULT);
- }
- in_index++;
+static const struct pmbus_sensor_attr current_attributes[] = {
+ {
+ .reg = PMBUS_READ_IIN,
+ .class = PSC_CURRENT_IN,
+ .label = "iin",
+ .func = PMBUS_HAVE_IIN,
+ .sfunc = PMBUS_HAVE_STATUS_INPUT,
+ .sbase = PB_STATUS_INPUT_BASE,
+ .limit = iin_limit_attrs,
+ .nlimit = ARRAY_SIZE(iin_limit_attrs),
+ }, {
+ .reg = PMBUS_READ_IOUT,
+ .class = PSC_CURRENT_OUT,
+ .label = "iout",
+ .paged = true,
+ .func = PMBUS_HAVE_IOUT,
+ .sfunc = PMBUS_HAVE_STATUS_IOUT,
+ .sbase = PB_STATUS_IOUT_BASE,
+ .gbit = PB_STATUS_IOUT_OC,
+ .limit = iout_limit_attrs,
+ .nlimit = ARRAY_SIZE(iout_limit_attrs),
}
+};
- /*
- * Temperature sensors
- */
- in_index = 1;
- for (page = 0; page < info->pages; page++) {
- int t;
+/* Power attributes */
- for (t = 0; t < ARRAY_SIZE(pmbus_temp_registers); t++) {
- bool have_alarm = false;
+static const struct pmbus_limit_attr pin_limit_attrs[] = {
+ {
+ .reg = PMBUS_PIN_OP_WARN_LIMIT,
+ .attr = "max",
+ .alarm = "alarm",
+ .sbit = PB_PIN_OP_WARNING,
+ }
+};
- /*
- * A PMBus chip may support any combination of
- * temperature registers on any page. So we can not
- * abort after a failure to detect a register, but have
- * to continue checking for all registers on all pages.
- */
- if (!(info->func[page] & pmbus_temp_flags[t]))
- continue;
+static const struct pmbus_limit_attr pout_limit_attrs[] = {
+ {
+ .reg = PMBUS_POUT_MAX,
+ .attr = "cap",
+ .alarm = "cap_alarm",
+ .sbit = PB_POWER_LIMITING,
+ }, {
+ .reg = PMBUS_POUT_OP_WARN_LIMIT,
+ .attr = "max",
+ .alarm = "max_alarm",
+ .sbit = PB_POUT_OP_WARNING,
+ }, {
+ .reg = PMBUS_POUT_OP_FAULT_LIMIT,
+ .attr = "crit",
+ .alarm = "crit_alarm",
+ .sbit = PB_POUT_OP_FAULT,
+ }
+};
- if (!pmbus_check_word_register
- (client, page, pmbus_temp_registers[t]))
- continue;
+static const struct pmbus_sensor_attr power_attributes[] = {
+ {
+ .reg = PMBUS_READ_PIN,
+ .class = PSC_POWER,
+ .label = "pin",
+ .func = PMBUS_HAVE_PIN,
+ .sfunc = PMBUS_HAVE_STATUS_INPUT,
+ .sbase = PB_STATUS_INPUT_BASE,
+ .limit = pin_limit_attrs,
+ .nlimit = ARRAY_SIZE(pin_limit_attrs),
+ }, {
+ .reg = PMBUS_READ_POUT,
+ .class = PSC_POWER,
+ .label = "pout",
+ .paged = true,
+ .func = PMBUS_HAVE_POUT,
+ .sfunc = PMBUS_HAVE_STATUS_IOUT,
+ .sbase = PB_STATUS_IOUT_BASE,
+ .limit = pout_limit_attrs,
+ .nlimit = ARRAY_SIZE(pout_limit_attrs),
+ }
+};
- i0 = data->num_sensors;
- pmbus_add_sensor(data, "temp", "input", in_index, page,
- pmbus_temp_registers[t],
- PSC_TEMPERATURE, true, true);
+/* Temperature atributes */
+
+static const struct pmbus_limit_attr temp_limit_attrs[] = {
+ {
+ .reg = PMBUS_UT_WARN_LIMIT,
+ .attr = "min",
+ .alarm = "min_alarm",
+ .sbit = PB_TEMP_UT_WARNING,
+ }, {
+ .reg = PMBUS_UT_FAULT_LIMIT,
+ .attr = "lcrit",
+ .alarm = "lcrit_alarm",
+ .sbit = PB_TEMP_UT_FAULT,
+ }, {
+ .reg = PMBUS_OT_WARN_LIMIT,
+ .attr = "max",
+ .alarm = "max_alarm",
+ .sbit = PB_TEMP_OT_WARNING,
+ }, {
+ .reg = PMBUS_OT_FAULT_LIMIT,
+ .attr = "crit",
+ .alarm = "crit_alarm",
+ .sbit = PB_TEMP_OT_FAULT,
+ }
+};
- /*
- * PMBus provides only one status register for TEMP1-3.
- * Thus, we can not use the status register to determine
- * which of the three sensors actually caused an alarm.
- * Always compare current temperature against the limit
- * registers to determine alarm conditions for a
- * specific sensor.
- *
- * Since there is only one set of limit registers for
- * up to three temperature sensors, we need to update
- * all limit registers after the limit was changed for
- * one of the sensors. This ensures that correct limits
- * are reported for all temperature sensors.
- */
- if (pmbus_check_word_register
- (client, page, PMBUS_UT_WARN_LIMIT)) {
- i1 = data->num_sensors;
- pmbus_add_sensor(data, "temp", "min", in_index,
- page, PMBUS_UT_WARN_LIMIT,
- PSC_TEMPERATURE, true, false);
- if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) {
- pmbus_add_boolean_cmp(data, "temp",
- "min_alarm", in_index, i1, i0,
- PB_STATUS_TEMP_BASE + page,
- PB_TEMP_UT_WARNING);
- have_alarm = true;
- }
- }
- if (pmbus_check_word_register(client, page,
- PMBUS_UT_FAULT_LIMIT)) {
- i1 = data->num_sensors;
- pmbus_add_sensor(data, "temp", "lcrit",
- in_index, page,
- PMBUS_UT_FAULT_LIMIT,
- PSC_TEMPERATURE, true, false);
- if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) {
- pmbus_add_boolean_cmp(data, "temp",
- "lcrit_alarm", in_index, i1, i0,
- PB_STATUS_TEMP_BASE + page,
- PB_TEMP_UT_FAULT);
- have_alarm = true;
- }
- }
- if (pmbus_check_word_register
- (client, page, PMBUS_OT_WARN_LIMIT)) {
- i1 = data->num_sensors;
- pmbus_add_sensor(data, "temp", "max", in_index,
- page, PMBUS_OT_WARN_LIMIT,
- PSC_TEMPERATURE, true, false);
- if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) {
- pmbus_add_boolean_cmp(data, "temp",
- "max_alarm", in_index, i0, i1,
- PB_STATUS_TEMP_BASE + page,
- PB_TEMP_OT_WARNING);
- have_alarm = true;
- }
- }
- if (pmbus_check_word_register(client, page,
- PMBUS_OT_FAULT_LIMIT)) {
- i1 = data->num_sensors;
- pmbus_add_sensor(data, "temp", "crit", in_index,
- page, PMBUS_OT_FAULT_LIMIT,
- PSC_TEMPERATURE, true, false);
- if (info->func[page] & PMBUS_HAVE_STATUS_TEMP) {
- pmbus_add_boolean_cmp(data, "temp",
- "crit_alarm", in_index, i0, i1,
- PB_STATUS_TEMP_BASE + page,
- PB_TEMP_OT_FAULT);
- have_alarm = true;
- }
- }
- /*
- * Last resort - we were not able to create any alarm
- * registers. Report alarm for all sensors using the
- * status register temperature alarm bit.
- */
- if (!have_alarm)
- pmbus_add_boolean_reg(data, "temp", "alarm",
- in_index,
- PB_STATUS_BASE + page,
- PB_STATUS_TEMPERATURE);
- in_index++;
- }
+static const struct pmbus_sensor_attr temp_attributes[] = {
+ {
+ .reg = PMBUS_READ_TEMPERATURE_1,
+ .class = PSC_TEMPERATURE,
+ .paged = true,
+ .update = true,
+ .compare = true,
+ .func = PMBUS_HAVE_TEMP,
+ .sfunc = PMBUS_HAVE_STATUS_TEMP,
+ .sbase = PB_STATUS_TEMP_BASE,
+ .gbit = PB_STATUS_TEMPERATURE,
+ .limit = temp_limit_attrs,
+ .nlimit = ARRAY_SIZE(temp_limit_attrs),
+ }, {
+ .reg = PMBUS_READ_TEMPERATURE_2,
+ .class = PSC_TEMPERATURE,
+ .paged = true,
+ .update = true,
+ .compare = true,
+ .func = PMBUS_HAVE_TEMP2,
+ .sfunc = PMBUS_HAVE_STATUS_TEMP,
+ .sbase = PB_STATUS_TEMP_BASE,
+ .gbit = PB_STATUS_TEMPERATURE,
+ .limit = temp_limit_attrs,
+ .nlimit = ARRAY_SIZE(temp_limit_attrs),
+ }, {
+ .reg = PMBUS_READ_TEMPERATURE_3,
+ .class = PSC_TEMPERATURE,
+ .paged = true,
+ .update = true,
+ .compare = true,
+ .func = PMBUS_HAVE_TEMP3,
+ .sfunc = PMBUS_HAVE_STATUS_TEMP,
+ .sbase = PB_STATUS_TEMP_BASE,
+ .gbit = PB_STATUS_TEMPERATURE,
+ .limit = temp_limit_attrs,
+ .nlimit = ARRAY_SIZE(temp_limit_attrs),
}
+};
+
+static const int pmbus_fan_registers[] = {
+ PMBUS_READ_FAN_SPEED_1,
+ PMBUS_READ_FAN_SPEED_2,
+ PMBUS_READ_FAN_SPEED_3,
+ PMBUS_READ_FAN_SPEED_4
+};
+
+static const int pmbus_fan_config_registers[] = {
+ PMBUS_FAN_CONFIG_12,
+ PMBUS_FAN_CONFIG_12,
+ PMBUS_FAN_CONFIG_34,
+ PMBUS_FAN_CONFIG_34
+};
+
+static const int pmbus_fan_status_registers[] = {
+ PMBUS_STATUS_FAN_12,
+ PMBUS_STATUS_FAN_12,
+ PMBUS_STATUS_FAN_34,
+ PMBUS_STATUS_FAN_34
+};
+
+static const u32 pmbus_fan_flags[] = {
+ PMBUS_HAVE_FAN12,
+ PMBUS_HAVE_FAN12,
+ PMBUS_HAVE_FAN34,
+ PMBUS_HAVE_FAN34
+};
+
+static const u32 pmbus_fan_status_flags[] = {
+ PMBUS_HAVE_STATUS_FAN12,
+ PMBUS_HAVE_STATUS_FAN12,
+ PMBUS_HAVE_STATUS_FAN34,
+ PMBUS_HAVE_STATUS_FAN34
+};
+
+/* Fans */
+static void pmbus_add_fan_attributes(struct i2c_client *client,
+ struct pmbus_data *data)
+{
+ const struct pmbus_driver_info *info = data->info;
+ int index = 1;
+ int page;
- /*
- * Fans
- */
- in_index = 1;
for (page = 0; page < info->pages; page++) {
int f;
@@ -1403,9 +1296,7 @@ static void pmbus_find_attributes(struct i2c_client *client,
break;
if (!pmbus_check_word_register(client, page,
- pmbus_fan_registers[f])
- || !pmbus_check_byte_register(client, page,
- pmbus_fan_config_registers[f]))
+ pmbus_fan_registers[f]))
break;
/*
@@ -1413,14 +1304,13 @@ static void pmbus_find_attributes(struct i2c_client *client,
* Each fan configuration register covers multiple fans,
* so we have to do some magic.
*/
- regval = pmbus_read_byte_data(client, page,
+ regval = _pmbus_read_byte_data(client, page,
pmbus_fan_config_registers[f]);
if (regval < 0 ||
(!(regval & (PB_FAN_1_INSTALLED >> ((f & 1) * 4)))))
continue;
- i0 = data->num_sensors;
- pmbus_add_sensor(data, "fan", "input", in_index, page,
+ pmbus_add_sensor(data, "fan", "input", index, page,
pmbus_fan_registers[f], PSC_FAN, true,
true);
@@ -1438,17 +1328,40 @@ static void pmbus_find_attributes(struct i2c_client *client,
else
base = PB_STATUS_FAN_BASE + page;
pmbus_add_boolean_reg(data, "fan", "alarm",
- in_index, base,
+ index, base,
PB_FAN_FAN1_WARNING >> (f & 1));
pmbus_add_boolean_reg(data, "fan", "fault",
- in_index, base,
+ index, base,
PB_FAN_FAN1_FAULT >> (f & 1));
}
- in_index++;
+ index++;
}
}
}
+static void pmbus_find_attributes(struct i2c_client *client,
+ struct pmbus_data *data)
+{
+ /* Voltage sensors */
+ pmbus_add_sensor_attrs(client, data, "in", voltage_attributes,
+ ARRAY_SIZE(voltage_attributes));
+
+ /* Current sensors */
+ pmbus_add_sensor_attrs(client, data, "curr", current_attributes,
+ ARRAY_SIZE(current_attributes));
+
+ /* Power sensors */
+ pmbus_add_sensor_attrs(client, data, "power", power_attributes,
+ ARRAY_SIZE(power_attributes));
+
+ /* Temperature sensors */
+ pmbus_add_sensor_attrs(client, data, "temp", temp_attributes,
+ ARRAY_SIZE(temp_attributes));
+
+ /* Fans */
+ pmbus_add_fan_attributes(client, data);
+}
+
/*
* Identify chip parameters.
* This function is called for all chips.
diff --git a/drivers/hwmon/sch5627.c b/drivers/hwmon/sch5627.c
index 9a51dcca9b0d..020c87273ea1 100644
--- a/drivers/hwmon/sch5627.c
+++ b/drivers/hwmon/sch5627.c
@@ -52,6 +52,9 @@
#define SCH5627_COMPANY_ID 0x5c
#define SCH5627_PRIMARY_ID 0xa0
+#define SCH5627_CMD_READ 0x02
+#define SCH5627_CMD_WRITE 0x03
+
#define SCH5627_REG_BUILD_CODE 0x39
#define SCH5627_REG_BUILD_ID 0x3a
#define SCH5627_REG_HWMON_ID 0x3c
@@ -94,11 +97,13 @@ static const char * const SCH5627_IN_LABELS[SCH5627_NO_IN] = {
struct sch5627_data {
unsigned short addr;
struct device *hwmon_dev;
+ u8 control;
u8 temp_max[SCH5627_NO_TEMPS];
u8 temp_crit[SCH5627_NO_TEMPS];
u16 fan_min[SCH5627_NO_FANS];
struct mutex update_lock;
+ unsigned long last_battery; /* In jiffies */
char valid; /* !=0 if following fields are valid */
unsigned long last_updated; /* In jiffies */
u16 temp[SCH5627_NO_TEMPS];
@@ -140,7 +145,7 @@ static inline void superio_exit(int base)
release_region(base, 2);
}
-static int sch5627_read_virtual_reg(struct sch5627_data *data, u16 reg)
+static int sch5627_send_cmd(struct sch5627_data *data, u8 cmd, u16 reg, u8 v)
{
u8 val;
int i;
@@ -163,10 +168,14 @@ static int sch5627_read_virtual_reg(struct sch5627_data *data, u16 reg)
outb(0x80, data->addr + 3);
/* Write Request Packet Header */
- outb(0x02, data->addr + 4); /* Access Type: VREG read */
+ outb(cmd, data->addr + 4); /* VREG Access Type read:0x02 write:0x03 */
outb(0x01, data->addr + 5); /* # of Entries: 1 Byte (8-bit) */
outb(0x04, data->addr + 2); /* Mailbox AP to first data entry loc. */
+ /* Write Value field */
+ if (cmd == SCH5627_CMD_WRITE)
+ outb(v, data->addr + 4);
+
/* Write Address field */
outb(reg & 0xff, data->addr + 6);
outb(reg >> 8, data->addr + 7);
@@ -224,8 +233,22 @@ static int sch5627_read_virtual_reg(struct sch5627_data *data, u16 reg)
* But if we do that things don't work, so let's not.
*/
- /* Read Data from Mailbox */
- return inb(data->addr + 4);
+ /* Read Value field */
+ if (cmd == SCH5627_CMD_READ)
+ return inb(data->addr + 4);
+
+ return 0;
+}
+
+static int sch5627_read_virtual_reg(struct sch5627_data *data, u16 reg)
+{
+ return sch5627_send_cmd(data, SCH5627_CMD_READ, reg, 0);
+}
+
+static int sch5627_write_virtual_reg(struct sch5627_data *data,
+ u16 reg, u8 val)
+{
+ return sch5627_send_cmd(data, SCH5627_CMD_WRITE, reg, val);
}
static int sch5627_read_virtual_reg16(struct sch5627_data *data, u16 reg)
@@ -272,6 +295,13 @@ static struct sch5627_data *sch5627_update_device(struct device *dev)
mutex_lock(&data->update_lock);
+ /* Trigger a Vbat voltage measurement every 5 minutes */
+ if (time_after(jiffies, data->last_battery + 300 * HZ)) {
+ sch5627_write_virtual_reg(data, SCH5627_REG_CTRL,
+ data->control | 0x10);
+ data->last_battery = jiffies;
+ }
+
/* Cache the values for 1 second */
if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
for (i = 0; i < SCH5627_NO_TEMPS; i++) {
@@ -696,11 +726,17 @@ static int __devinit sch5627_probe(struct platform_device *pdev)
err = val;
goto error;
}
- if (!(val & 0x01)) {
+ data->control = val;
+ if (!(data->control & 0x01)) {
pr_err("hardware monitoring not enabled\n");
err = -ENODEV;
goto error;
}
+ /* Trigger a Vbat voltage measurement, so that we get a valid reading
+ the first time we read Vbat */
+ sch5627_write_virtual_reg(data, SCH5627_REG_CTRL,
+ data->control | 0x10);
+ data->last_battery = jiffies;
/*
* Read limits, we do this only once as reading a register on
diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c
index f4e617adb220..cf4330b352ef 100644
--- a/drivers/hwmon/sht15.c
+++ b/drivers/hwmon/sht15.c
@@ -1,6 +1,10 @@
/*
* sht15.c - support for the SHT15 Temperature and Humidity Sensor
*
+ * Portions Copyright (c) 2010-2011 Savoir-faire Linux Inc.
+ * Jerome Oufella <jerome.oufella@savoirfairelinux.com>
+ * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
+ *
* Copyright (c) 2009 Jonathan Cameron
*
* Copyright (c) 2007 Wouter Horre
@@ -9,16 +13,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * Currently ignoring checksum on readings.
- * Default resolution only (14bit temp, 12bit humidity)
- * Ignoring battery status.
- * Heater not enabled.
- * Timings are all conservative.
- *
- * Data sheet available (1/2009) at
- * http://www.sensirion.ch/en/pdf/product_information/Datasheet-humidity-sensor-SHT1x.pdf
- *
- * Regulator supply name = vcc
+ * For further information, see the Documentation/hwmon/sht15 file.
*/
#include <linux/interrupt.h>
@@ -39,17 +34,31 @@
#include <linux/slab.h>
#include <asm/atomic.h>
-#define SHT15_MEASURE_TEMP 3
-#define SHT15_MEASURE_RH 5
-
-#define SHT15_READING_NOTHING 0
-#define SHT15_READING_TEMP 1
-#define SHT15_READING_HUMID 2
-
-/* Min timings in nsecs */
-#define SHT15_TSCKL 100 /* clock low */
-#define SHT15_TSCKH 100 /* clock high */
-#define SHT15_TSU 150 /* data setup time */
+/* Commands */
+#define SHT15_MEASURE_TEMP 0x03
+#define SHT15_MEASURE_RH 0x05
+#define SHT15_WRITE_STATUS 0x06
+#define SHT15_READ_STATUS 0x07
+#define SHT15_SOFT_RESET 0x1E
+
+/* Min timings */
+#define SHT15_TSCKL 100 /* (nsecs) clock low */
+#define SHT15_TSCKH 100 /* (nsecs) clock high */
+#define SHT15_TSU 150 /* (nsecs) data setup time */
+#define SHT15_TSRST 11 /* (msecs) soft reset time */
+
+/* Status Register Bits */
+#define SHT15_STATUS_LOW_RESOLUTION 0x01
+#define SHT15_STATUS_NO_OTP_RELOAD 0x02
+#define SHT15_STATUS_HEATER 0x04
+#define SHT15_STATUS_LOW_BATTERY 0x40
+
+/* Actions the driver may be doing */
+enum sht15_state {
+ SHT15_READING_NOTHING,
+ SHT15_READING_TEMP,
+ SHT15_READING_HUMID
+};
/**
* struct sht15_temppair - elements of voltage dependent temp calc
@@ -61,9 +70,7 @@ struct sht15_temppair {
int d1;
};
-/* Table 9 from data sheet - relates temperature calculation
- * to supply voltage.
- */
+/* Table 9 from datasheet - relates temperature calculation to supply voltage */
static const struct sht15_temppair temppoints[] = {
{ 2500000, -39400 },
{ 3000000, -39600 },
@@ -72,29 +79,70 @@ static const struct sht15_temppair temppoints[] = {
{ 5000000, -40100 },
};
+/* Table from CRC datasheet, section 2.4 */
+static const u8 sht15_crc8_table[] = {
+ 0, 49, 98, 83, 196, 245, 166, 151,
+ 185, 136, 219, 234, 125, 76, 31, 46,
+ 67, 114, 33, 16, 135, 182, 229, 212,
+ 250, 203, 152, 169, 62, 15, 92, 109,
+ 134, 183, 228, 213, 66, 115, 32, 17,
+ 63, 14, 93, 108, 251, 202, 153, 168,
+ 197, 244, 167, 150, 1, 48, 99, 82,
+ 124, 77, 30, 47, 184, 137, 218, 235,
+ 61, 12, 95, 110, 249, 200, 155, 170,
+ 132, 181, 230, 215, 64, 113, 34, 19,
+ 126, 79, 28, 45, 186, 139, 216, 233,
+ 199, 246, 165, 148, 3, 50, 97, 80,
+ 187, 138, 217, 232, 127, 78, 29, 44,
+ 2, 51, 96, 81, 198, 247, 164, 149,
+ 248, 201, 154, 171, 60, 13, 94, 111,
+ 65, 112, 35, 18, 133, 180, 231, 214,
+ 122, 75, 24, 41, 190, 143, 220, 237,
+ 195, 242, 161, 144, 7, 54, 101, 84,
+ 57, 8, 91, 106, 253, 204, 159, 174,
+ 128, 177, 226, 211, 68, 117, 38, 23,
+ 252, 205, 158, 175, 56, 9, 90, 107,
+ 69, 116, 39, 22, 129, 176, 227, 210,
+ 191, 142, 221, 236, 123, 74, 25, 40,
+ 6, 55, 100, 85, 194, 243, 160, 145,
+ 71, 118, 37, 20, 131, 178, 225, 208,
+ 254, 207, 156, 173, 58, 11, 88, 105,
+ 4, 53, 102, 87, 192, 241, 162, 147,
+ 189, 140, 223, 238, 121, 72, 27, 42,
+ 193, 240, 163, 146, 5, 52, 103, 86,
+ 120, 73, 26, 43, 188, 141, 222, 239,
+ 130, 179, 224, 209, 70, 119, 36, 21,
+ 59, 10, 89, 104, 255, 206, 157, 172
+};
+
/**
* struct sht15_data - device instance specific data
- * @pdata: platform data (gpio's etc)
- * @read_work: bh of interrupt handler
- * @wait_queue: wait queue for getting values from device
- * @val_temp: last temperature value read from device
- * @val_humid: last humidity value read from device
- * @flag: status flag used to identify what the last request was
- * @valid: are the current stored values valid (start condition)
- * @last_updat: time of last update
- * @read_lock: mutex to ensure only one read in progress
- * at a time.
- * @dev: associate device structure
- * @hwmon_dev: device associated with hwmon subsystem
- * @reg: associated regulator (if specified)
- * @nb: notifier block to handle notifications of voltage changes
- * @supply_uV: local copy of supply voltage used to allow
- * use of regulator consumer if available
- * @supply_uV_valid: indicates that an updated value has not yet
- * been obtained from the regulator and so any calculations
- * based upon it will be invalid.
- * @update_supply_work: work struct that is used to update the supply_uV
- * @interrupt_handled: flag used to indicate a hander has been scheduled
+ * @pdata: platform data (gpio's etc).
+ * @read_work: bh of interrupt handler.
+ * @wait_queue: wait queue for getting values from device.
+ * @val_temp: last temperature value read from device.
+ * @val_humid: last humidity value read from device.
+ * @val_status: last status register value read from device.
+ * @checksum_ok: last value read from the device passed CRC validation.
+ * @checksumming: flag used to enable the data validation with CRC.
+ * @state: state identifying the action the driver is doing.
+ * @measurements_valid: are the current stored measures valid (start condition).
+ * @status_valid: is the current stored status valid (start condition).
+ * @last_measurement: time of last measure.
+ * @last_status: time of last status reading.
+ * @read_lock: mutex to ensure only one read in progress at a time.
+ * @dev: associate device structure.
+ * @hwmon_dev: device associated with hwmon subsystem.
+ * @reg: associated regulator (if specified).
+ * @nb: notifier block to handle notifications of voltage
+ * changes.
+ * @supply_uV: local copy of supply voltage used to allow use of
+ * regulator consumer if available.
+ * @supply_uV_valid: indicates that an updated value has not yet been
+ * obtained from the regulator and so any calculations
+ * based upon it will be invalid.
+ * @update_supply_work: work struct that is used to update the supply_uV.
+ * @interrupt_handled: flag used to indicate a handler has been scheduled.
*/
struct sht15_data {
struct sht15_platform_data *pdata;
@@ -102,21 +150,60 @@ struct sht15_data {
wait_queue_head_t wait_queue;
uint16_t val_temp;
uint16_t val_humid;
- u8 flag;
- u8 valid;
- unsigned long last_updat;
+ u8 val_status;
+ bool checksum_ok;
+ bool checksumming;
+ enum sht15_state state;
+ bool measurements_valid;
+ bool status_valid;
+ unsigned long last_measurement;
+ unsigned long last_status;
struct mutex read_lock;
struct device *dev;
struct device *hwmon_dev;
struct regulator *reg;
struct notifier_block nb;
int supply_uV;
- int supply_uV_valid;
+ bool supply_uV_valid;
struct work_struct update_supply_work;
atomic_t interrupt_handled;
};
/**
+ * sht15_reverse() - reverse a byte
+ * @byte: byte to reverse.
+ */
+static u8 sht15_reverse(u8 byte)
+{
+ u8 i, c;
+
+ for (c = 0, i = 0; i < 8; i++)
+ c |= (!!(byte & (1 << i))) << (7 - i);
+ return c;
+}
+
+/**
+ * sht15_crc8() - compute crc8
+ * @data: sht15 specific data.
+ * @value: sht15 retrieved data.
+ *
+ * This implements section 2 of the CRC datasheet.
+ */
+static u8 sht15_crc8(struct sht15_data *data,
+ const u8 *value,
+ int len)
+{
+ u8 crc = sht15_reverse(data->val_status & 0x0F);
+
+ while (len--) {
+ crc = sht15_crc8_table[*value ^ crc];
+ value++;
+ }
+
+ return crc;
+}
+
+/**
* sht15_connection_reset() - reset the comms interface
* @data: sht15 specific data
*
@@ -125,6 +212,7 @@ struct sht15_data {
static void sht15_connection_reset(struct sht15_data *data)
{
int i;
+
gpio_direction_output(data->pdata->gpio_data, 1);
ndelay(SHT15_TSCKL);
gpio_set_value(data->pdata->gpio_sck, 0);
@@ -136,14 +224,14 @@ static void sht15_connection_reset(struct sht15_data *data)
ndelay(SHT15_TSCKL);
}
}
+
/**
* sht15_send_bit() - send an individual bit to the device
* @data: device state data
* @val: value of bit to be sent
- **/
+ */
static inline void sht15_send_bit(struct sht15_data *data, int val)
{
-
gpio_set_value(data->pdata->gpio_data, val);
ndelay(SHT15_TSU);
gpio_set_value(data->pdata->gpio_sck, 1);
@@ -154,12 +242,12 @@ static inline void sht15_send_bit(struct sht15_data *data, int val)
/**
* sht15_transmission_start() - specific sequence for new transmission
- *
* @data: device state data
+ *
* Timings for this are not documented on the data sheet, so very
* conservative ones used in implementation. This implements
* figure 12 on the data sheet.
- **/
+ */
static void sht15_transmission_start(struct sht15_data *data)
{
/* ensure data is high and output */
@@ -180,23 +268,26 @@ static void sht15_transmission_start(struct sht15_data *data)
gpio_set_value(data->pdata->gpio_sck, 0);
ndelay(SHT15_TSCKL);
}
+
/**
* sht15_send_byte() - send a single byte to the device
* @data: device state
* @byte: value to be sent
- **/
+ */
static void sht15_send_byte(struct sht15_data *data, u8 byte)
{
int i;
+
for (i = 0; i < 8; i++) {
sht15_send_bit(data, !!(byte & 0x80));
byte <<= 1;
}
}
+
/**
* sht15_wait_for_response() - checks for ack from device
* @data: device state
- **/
+ */
static int sht15_wait_for_response(struct sht15_data *data)
{
gpio_direction_input(data->pdata->gpio_data);
@@ -220,27 +311,199 @@ static int sht15_wait_for_response(struct sht15_data *data)
*
* On entry, sck is output low, data is output pull high
* and the interrupt disabled.
- **/
+ */
static int sht15_send_cmd(struct sht15_data *data, u8 cmd)
{
int ret = 0;
+
sht15_transmission_start(data);
sht15_send_byte(data, cmd);
ret = sht15_wait_for_response(data);
return ret;
}
+
+/**
+ * sht15_soft_reset() - send a soft reset command
+ * @data: sht15 specific data.
+ *
+ * As described in section 3.2 of the datasheet.
+ */
+static int sht15_soft_reset(struct sht15_data *data)
+{
+ int ret;
+
+ ret = sht15_send_cmd(data, SHT15_SOFT_RESET);
+ if (ret)
+ return ret;
+ msleep(SHT15_TSRST);
+ /* device resets default hardware status register value */
+ data->val_status = 0;
+
+ return ret;
+}
+
+/**
+ * sht15_ack() - send a ack
+ * @data: sht15 specific data.
+ *
+ * Each byte of data is acknowledged by pulling the data line
+ * low for one clock pulse.
+ */
+static void sht15_ack(struct sht15_data *data)
+{
+ gpio_direction_output(data->pdata->gpio_data, 0);
+ ndelay(SHT15_TSU);
+ gpio_set_value(data->pdata->gpio_sck, 1);
+ ndelay(SHT15_TSU);
+ gpio_set_value(data->pdata->gpio_sck, 0);
+ ndelay(SHT15_TSU);
+ gpio_set_value(data->pdata->gpio_data, 1);
+
+ gpio_direction_input(data->pdata->gpio_data);
+}
+
+/**
+ * sht15_end_transmission() - notify device of end of transmission
+ * @data: device state.
+ *
+ * This is basically a NAK (single clock pulse, data high).
+ */
+static void sht15_end_transmission(struct sht15_data *data)
+{
+ gpio_direction_output(data->pdata->gpio_data, 1);
+ ndelay(SHT15_TSU);
+ gpio_set_value(data->pdata->gpio_sck, 1);
+ ndelay(SHT15_TSCKH);
+ gpio_set_value(data->pdata->gpio_sck, 0);
+ ndelay(SHT15_TSCKL);
+}
+
+/**
+ * sht15_read_byte() - Read a byte back from the device
+ * @data: device state.
+ */
+static u8 sht15_read_byte(struct sht15_data *data)
+{
+ int i;
+ u8 byte = 0;
+
+ for (i = 0; i < 8; ++i) {
+ byte <<= 1;
+ gpio_set_value(data->pdata->gpio_sck, 1);
+ ndelay(SHT15_TSCKH);
+ byte |= !!gpio_get_value(data->pdata->gpio_data);
+ gpio_set_value(data->pdata->gpio_sck, 0);
+ ndelay(SHT15_TSCKL);
+ }
+ return byte;
+}
+
+/**
+ * sht15_send_status() - write the status register byte
+ * @data: sht15 specific data.
+ * @status: the byte to set the status register with.
+ *
+ * As described in figure 14 and table 5 of the datasheet.
+ */
+static int sht15_send_status(struct sht15_data *data, u8 status)
+{
+ int ret;
+
+ ret = sht15_send_cmd(data, SHT15_WRITE_STATUS);
+ if (ret)
+ return ret;
+ gpio_direction_output(data->pdata->gpio_data, 1);
+ ndelay(SHT15_TSU);
+ sht15_send_byte(data, status);
+ ret = sht15_wait_for_response(data);
+ if (ret)
+ return ret;
+
+ data->val_status = status;
+ return 0;
+}
+
+/**
+ * sht15_update_status() - get updated status register from device if too old
+ * @data: device instance specific data.
+ *
+ * As described in figure 15 and table 5 of the datasheet.
+ */
+static int sht15_update_status(struct sht15_data *data)
+{
+ int ret = 0;
+ u8 status;
+ u8 previous_config;
+ u8 dev_checksum = 0;
+ u8 checksum_vals[2];
+ int timeout = HZ;
+
+ mutex_lock(&data->read_lock);
+ if (time_after(jiffies, data->last_status + timeout)
+ || !data->status_valid) {
+ ret = sht15_send_cmd(data, SHT15_READ_STATUS);
+ if (ret)
+ goto error_ret;
+ status = sht15_read_byte(data);
+
+ if (data->checksumming) {
+ sht15_ack(data);
+ dev_checksum = sht15_reverse(sht15_read_byte(data));
+ checksum_vals[0] = SHT15_READ_STATUS;
+ checksum_vals[1] = status;
+ data->checksum_ok = (sht15_crc8(data, checksum_vals, 2)
+ == dev_checksum);
+ }
+
+ sht15_end_transmission(data);
+
+ /*
+ * Perform checksum validation on the received data.
+ * Specification mentions that in case a checksum verification
+ * fails, a soft reset command must be sent to the device.
+ */
+ if (data->checksumming && !data->checksum_ok) {
+ previous_config = data->val_status & 0x07;
+ ret = sht15_soft_reset(data);
+ if (ret)
+ goto error_ret;
+ if (previous_config) {
+ ret = sht15_send_status(data, previous_config);
+ if (ret) {
+ dev_err(data->dev,
+ "CRC validation failed, unable "
+ "to restore device settings\n");
+ goto error_ret;
+ }
+ }
+ ret = -EAGAIN;
+ goto error_ret;
+ }
+
+ data->val_status = status;
+ data->status_valid = true;
+ data->last_status = jiffies;
+ }
+error_ret:
+ mutex_unlock(&data->read_lock);
+
+ return ret;
+}
+
/**
- * sht15_update_single_val() - get a new value from device
+ * sht15_measurement() - get a new value from device
* @data: device instance specific data
* @command: command sent to request value
* @timeout_msecs: timeout after which comms are assumed
* to have failed are reset.
- **/
-static inline int sht15_update_single_val(struct sht15_data *data,
- int command,
- int timeout_msecs)
+ */
+static int sht15_measurement(struct sht15_data *data,
+ int command,
+ int timeout_msecs)
{
int ret;
+ u8 previous_config;
+
ret = sht15_send_cmd(data, command);
if (ret)
return ret;
@@ -256,38 +519,61 @@ static inline int sht15_update_single_val(struct sht15_data *data,
schedule_work(&data->read_work);
}
ret = wait_event_timeout(data->wait_queue,
- (data->flag == SHT15_READING_NOTHING),
+ (data->state == SHT15_READING_NOTHING),
msecs_to_jiffies(timeout_msecs));
if (ret == 0) {/* timeout occurred */
disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
sht15_connection_reset(data);
return -ETIME;
}
+
+ /*
+ * Perform checksum validation on the received data.
+ * Specification mentions that in case a checksum verification fails,
+ * a soft reset command must be sent to the device.
+ */
+ if (data->checksumming && !data->checksum_ok) {
+ previous_config = data->val_status & 0x07;
+ ret = sht15_soft_reset(data);
+ if (ret)
+ return ret;
+ if (previous_config) {
+ ret = sht15_send_status(data, previous_config);
+ if (ret) {
+ dev_err(data->dev,
+ "CRC validation failed, unable "
+ "to restore device settings\n");
+ return ret;
+ }
+ }
+ return -EAGAIN;
+ }
+
return 0;
}
/**
- * sht15_update_vals() - get updated readings from device if too old
+ * sht15_update_measurements() - get updated measures from device if too old
* @data: device state
- **/
-static int sht15_update_vals(struct sht15_data *data)
+ */
+static int sht15_update_measurements(struct sht15_data *data)
{
int ret = 0;
int timeout = HZ;
mutex_lock(&data->read_lock);
- if (time_after(jiffies, data->last_updat + timeout)
- || !data->valid) {
- data->flag = SHT15_READING_HUMID;
- ret = sht15_update_single_val(data, SHT15_MEASURE_RH, 160);
+ if (time_after(jiffies, data->last_measurement + timeout)
+ || !data->measurements_valid) {
+ data->state = SHT15_READING_HUMID;
+ ret = sht15_measurement(data, SHT15_MEASURE_RH, 160);
if (ret)
goto error_ret;
- data->flag = SHT15_READING_TEMP;
- ret = sht15_update_single_val(data, SHT15_MEASURE_TEMP, 400);
+ data->state = SHT15_READING_TEMP;
+ ret = sht15_measurement(data, SHT15_MEASURE_TEMP, 400);
if (ret)
goto error_ret;
- data->valid = 1;
- data->last_updat = jiffies;
+ data->measurements_valid = true;
+ data->last_measurement = jiffies;
}
error_ret:
mutex_unlock(&data->read_lock);
@@ -300,10 +586,11 @@ error_ret:
* @data: device state
*
* As per section 4.3 of the data sheet.
- **/
+ */
static inline int sht15_calc_temp(struct sht15_data *data)
{
int d1 = temppoints[0].d1;
+ int d2 = (data->val_status & SHT15_STATUS_LOW_RESOLUTION) ? 40 : 10;
int i;
for (i = ARRAY_SIZE(temppoints) - 1; i > 0; i--)
@@ -316,7 +603,7 @@ static inline int sht15_calc_temp(struct sht15_data *data)
break;
}
- return data->val_temp*10 + d1;
+ return data->val_temp * d2 + d1;
}
/**
@@ -325,23 +612,102 @@ static inline int sht15_calc_temp(struct sht15_data *data)
*
* This is the temperature compensated version as per section 4.2 of
* the data sheet.
- **/
+ *
+ * The sensor is assumed to be V3, which is compatible with V4.
+ * Humidity conversion coefficients are shown in table 7 of the datasheet.
+ */
static inline int sht15_calc_humid(struct sht15_data *data)
{
- int RHlinear; /* milli percent */
+ int rh_linear; /* milli percent */
int temp = sht15_calc_temp(data);
-
+ int c2, c3;
+ int t2;
const int c1 = -4;
- const int c2 = 40500; /* x 10 ^ -6 */
- const int c3 = -28; /* x 10 ^ -7 */
- RHlinear = c1*1000
- + c2 * data->val_humid/1000
+ if (data->val_status & SHT15_STATUS_LOW_RESOLUTION) {
+ c2 = 648000; /* x 10 ^ -6 */
+ c3 = -7200; /* x 10 ^ -7 */
+ t2 = 1280;
+ } else {
+ c2 = 40500; /* x 10 ^ -6 */
+ c3 = -28; /* x 10 ^ -7 */
+ t2 = 80;
+ }
+
+ rh_linear = c1 * 1000
+ + c2 * data->val_humid / 1000
+ (data->val_humid * data->val_humid * c3) / 10000;
- return (temp - 25000) * (10000 + 80 * data->val_humid)
- / 1000000 + RHlinear;
+ return (temp - 25000) * (10000 + t2 * data->val_humid)
+ / 1000000 + rh_linear;
+}
+
+/**
+ * sht15_show_status() - show status information in sysfs
+ * @dev: device.
+ * @attr: device attribute.
+ * @buf: sysfs buffer where information is written to.
+ *
+ * Will be called on read access to temp1_fault, humidity1_fault
+ * and heater_enable sysfs attributes.
+ * Returns number of bytes written into buffer, negative errno on error.
+ */
+static ssize_t sht15_show_status(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ struct sht15_data *data = dev_get_drvdata(dev);
+ u8 bit = to_sensor_dev_attr(attr)->index;
+
+ ret = sht15_update_status(data);
+
+ return ret ? ret : sprintf(buf, "%d\n", !!(data->val_status & bit));
+}
+
+/**
+ * sht15_store_heater() - change heater state via sysfs
+ * @dev: device.
+ * @attr: device attribute.
+ * @buf: sysfs buffer to read the new heater state from.
+ * @count: length of the data.
+ *
+ * Will be called on read access to heater_enable sysfs attribute.
+ * Returns number of bytes actually decoded, negative errno on error.
+ */
+static ssize_t sht15_store_heater(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ struct sht15_data *data = dev_get_drvdata(dev);
+ long value;
+ u8 status;
+
+ if (strict_strtol(buf, 10, &value))
+ return -EINVAL;
+
+ mutex_lock(&data->read_lock);
+ status = data->val_status & 0x07;
+ if (!!value)
+ status |= SHT15_STATUS_HEATER;
+ else
+ status &= ~SHT15_STATUS_HEATER;
+
+ ret = sht15_send_status(data, status);
+ mutex_unlock(&data->read_lock);
+
+ return ret ? ret : count;
}
+/**
+ * sht15_show_temp() - show temperature measurement value in sysfs
+ * @dev: device.
+ * @attr: device attribute.
+ * @buf: sysfs buffer where measurement values are written to.
+ *
+ * Will be called on read access to temp1_input sysfs attribute.
+ * Returns number of bytes written into buffer, negative errno on error.
+ */
static ssize_t sht15_show_temp(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -350,12 +716,21 @@ static ssize_t sht15_show_temp(struct device *dev,
struct sht15_data *data = dev_get_drvdata(dev);
/* Technically no need to read humidity as well */
- ret = sht15_update_vals(data);
+ ret = sht15_update_measurements(data);
return ret ? ret : sprintf(buf, "%d\n",
sht15_calc_temp(data));
}
+/**
+ * sht15_show_humidity() - show humidity measurement value in sysfs
+ * @dev: device.
+ * @attr: device attribute.
+ * @buf: sysfs buffer where measurement values are written to.
+ *
+ * Will be called on read access to humidity1_input sysfs attribute.
+ * Returns number of bytes written into buffer, negative errno on error.
+ */
static ssize_t sht15_show_humidity(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -363,11 +738,11 @@ static ssize_t sht15_show_humidity(struct device *dev,
int ret;
struct sht15_data *data = dev_get_drvdata(dev);
- ret = sht15_update_vals(data);
+ ret = sht15_update_measurements(data);
return ret ? ret : sprintf(buf, "%d\n", sht15_calc_humid(data));
+}
-};
static ssize_t show_name(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -376,16 +751,23 @@ static ssize_t show_name(struct device *dev,
return sprintf(buf, "%s\n", pdev->name);
}
-static SENSOR_DEVICE_ATTR(temp1_input,
- S_IRUGO, sht15_show_temp,
- NULL, 0);
-static SENSOR_DEVICE_ATTR(humidity1_input,
- S_IRUGO, sht15_show_humidity,
- NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
+ sht15_show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO,
+ sht15_show_humidity, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, sht15_show_status, NULL,
+ SHT15_STATUS_LOW_BATTERY);
+static SENSOR_DEVICE_ATTR(humidity1_fault, S_IRUGO, sht15_show_status, NULL,
+ SHT15_STATUS_LOW_BATTERY);
+static SENSOR_DEVICE_ATTR(heater_enable, S_IRUGO | S_IWUSR, sht15_show_status,
+ sht15_store_heater, SHT15_STATUS_HEATER);
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
static struct attribute *sht15_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_humidity1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_fault.dev_attr.attr,
+ &sensor_dev_attr_humidity1_fault.dev_attr.attr,
+ &sensor_dev_attr_heater_enable.dev_attr.attr,
&dev_attr_name.attr,
NULL,
};
@@ -397,59 +779,31 @@ static const struct attribute_group sht15_attr_group = {
static irqreturn_t sht15_interrupt_fired(int irq, void *d)
{
struct sht15_data *data = d;
+
/* First disable the interrupt */
disable_irq_nosync(irq);
atomic_inc(&data->interrupt_handled);
/* Then schedule a reading work struct */
- if (data->flag != SHT15_READING_NOTHING)
+ if (data->state != SHT15_READING_NOTHING)
schedule_work(&data->read_work);
return IRQ_HANDLED;
}
-/* Each byte of data is acknowledged by pulling the data line
- * low for one clock pulse.
- */
-static void sht15_ack(struct sht15_data *data)
-{
- gpio_direction_output(data->pdata->gpio_data, 0);
- ndelay(SHT15_TSU);
- gpio_set_value(data->pdata->gpio_sck, 1);
- ndelay(SHT15_TSU);
- gpio_set_value(data->pdata->gpio_sck, 0);
- ndelay(SHT15_TSU);
- gpio_set_value(data->pdata->gpio_data, 1);
-
- gpio_direction_input(data->pdata->gpio_data);
-}
-/**
- * sht15_end_transmission() - notify device of end of transmission
- * @data: device state
- *
- * This is basically a NAK. (single clock pulse, data high)
- **/
-static void sht15_end_transmission(struct sht15_data *data)
-{
- gpio_direction_output(data->pdata->gpio_data, 1);
- ndelay(SHT15_TSU);
- gpio_set_value(data->pdata->gpio_sck, 1);
- ndelay(SHT15_TSCKH);
- gpio_set_value(data->pdata->gpio_sck, 0);
- ndelay(SHT15_TSCKL);
-}
-
static void sht15_bh_read_data(struct work_struct *work_s)
{
- int i;
uint16_t val = 0;
+ u8 dev_checksum = 0;
+ u8 checksum_vals[3];
struct sht15_data *data
= container_of(work_s, struct sht15_data,
read_work);
+
/* Firstly, verify the line is low */
if (gpio_get_value(data->pdata->gpio_data)) {
- /* If not, then start the interrupt again - care
- here as could have gone low in meantime so verify
- it hasn't!
- */
+ /*
+ * If not, then start the interrupt again - care here as could
+ * have gone low in meantime so verify it hasn't!
+ */
atomic_set(&data->interrupt_handled, 0);
enable_irq(gpio_to_irq(data->pdata->gpio_data));
/* If still not occurred or another handler has been scheduled */
@@ -457,30 +811,43 @@ static void sht15_bh_read_data(struct work_struct *work_s)
|| atomic_read(&data->interrupt_handled))
return;
}
+
/* Read the data back from the device */
- for (i = 0; i < 16; ++i) {
- val <<= 1;
- gpio_set_value(data->pdata->gpio_sck, 1);
- ndelay(SHT15_TSCKH);
- val |= !!gpio_get_value(data->pdata->gpio_data);
- gpio_set_value(data->pdata->gpio_sck, 0);
- ndelay(SHT15_TSCKL);
- if (i == 7)
- sht15_ack(data);
+ val = sht15_read_byte(data);
+ val <<= 8;
+ sht15_ack(data);
+ val |= sht15_read_byte(data);
+
+ if (data->checksumming) {
+ /*
+ * Ask the device for a checksum and read it back.
+ * Note: the device sends the checksum byte reversed.
+ */
+ sht15_ack(data);
+ dev_checksum = sht15_reverse(sht15_read_byte(data));
+ checksum_vals[0] = (data->state == SHT15_READING_TEMP) ?
+ SHT15_MEASURE_TEMP : SHT15_MEASURE_RH;
+ checksum_vals[1] = (u8) (val >> 8);
+ checksum_vals[2] = (u8) val;
+ data->checksum_ok
+ = (sht15_crc8(data, checksum_vals, 3) == dev_checksum);
}
+
/* Tell the device we are done */
sht15_end_transmission(data);
- switch (data->flag) {
+ switch (data->state) {
case SHT15_READING_TEMP:
data->val_temp = val;
break;
case SHT15_READING_HUMID:
data->val_humid = val;
break;
+ default:
+ break;
}
- data->flag = SHT15_READING_NOTHING;
+ data->state = SHT15_READING_NOTHING;
wake_up(&data->wait_queue);
}
@@ -500,10 +867,10 @@ static void sht15_update_voltage(struct work_struct *work_s)
*
* Note that as the notification code holds the regulator lock, we have
* to schedule an update of the supply voltage rather than getting it directly.
- **/
+ */
static int sht15_invalidate_voltage(struct notifier_block *nb,
- unsigned long event,
- void *ignored)
+ unsigned long event,
+ void *ignored)
{
struct sht15_data *data = container_of(nb, struct sht15_data, nb);
@@ -518,10 +885,11 @@ static int __devinit sht15_probe(struct platform_device *pdev)
{
int ret = 0;
struct sht15_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
+ u8 status = 0;
if (!data) {
ret = -ENOMEM;
- dev_err(&pdev->dev, "kzalloc failed");
+ dev_err(&pdev->dev, "kzalloc failed\n");
goto error_ret;
}
@@ -533,13 +901,22 @@ static int __devinit sht15_probe(struct platform_device *pdev)
init_waitqueue_head(&data->wait_queue);
if (pdev->dev.platform_data == NULL) {
- dev_err(&pdev->dev, "no platform data supplied");
+ dev_err(&pdev->dev, "no platform data supplied\n");
goto err_free_data;
}
data->pdata = pdev->dev.platform_data;
- data->supply_uV = data->pdata->supply_mv*1000;
-
-/* If a regulator is available, query what the supply voltage actually is!*/
+ data->supply_uV = data->pdata->supply_mv * 1000;
+ if (data->pdata->checksum)
+ data->checksumming = true;
+ if (data->pdata->no_otp_reload)
+ status |= SHT15_STATUS_NO_OTP_RELOAD;
+ if (data->pdata->low_resolution)
+ status |= SHT15_STATUS_LOW_RESOLUTION;
+
+ /*
+ * If a regulator is available,
+ * query what the supply voltage actually is!
+ */
data->reg = regulator_get(data->dev, "vcc");
if (!IS_ERR(data->reg)) {
int voltage;
@@ -549,28 +926,34 @@ static int __devinit sht15_probe(struct platform_device *pdev)
data->supply_uV = voltage;
regulator_enable(data->reg);
- /* setup a notifier block to update this if another device
- * causes the voltage to change */
+ /*
+ * Setup a notifier block to update this if another device
+ * causes the voltage to change
+ */
data->nb.notifier_call = &sht15_invalidate_voltage;
ret = regulator_register_notifier(data->reg, &data->nb);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "regulator notifier request failed\n");
+ regulator_disable(data->reg);
+ regulator_put(data->reg);
+ goto err_free_data;
+ }
}
-/* Try requesting the GPIOs */
+
+ /* Try requesting the GPIOs */
ret = gpio_request(data->pdata->gpio_sck, "SHT15 sck");
if (ret) {
- dev_err(&pdev->dev, "gpio request failed");
- goto err_free_data;
+ dev_err(&pdev->dev, "gpio request failed\n");
+ goto err_release_reg;
}
gpio_direction_output(data->pdata->gpio_sck, 0);
+
ret = gpio_request(data->pdata->gpio_data, "SHT15 data");
if (ret) {
- dev_err(&pdev->dev, "gpio request failed");
+ dev_err(&pdev->dev, "gpio request failed\n");
goto err_release_gpio_sck;
}
- ret = sysfs_create_group(&pdev->dev.kobj, &sht15_attr_group);
- if (ret) {
- dev_err(&pdev->dev, "sysfs create failed");
- goto err_release_gpio_data;
- }
ret = request_irq(gpio_to_irq(data->pdata->gpio_data),
sht15_interrupt_fired,
@@ -578,30 +961,53 @@ static int __devinit sht15_probe(struct platform_device *pdev)
"sht15 data",
data);
if (ret) {
- dev_err(&pdev->dev, "failed to get irq for data line");
+ dev_err(&pdev->dev, "failed to get irq for data line\n");
goto err_release_gpio_data;
}
disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
sht15_connection_reset(data);
- sht15_send_cmd(data, 0x1E);
+ ret = sht15_soft_reset(data);
+ if (ret)
+ goto err_release_irq;
+
+ /* write status with platform data options */
+ if (status) {
+ ret = sht15_send_status(data, status);
+ if (ret)
+ goto err_release_irq;
+ }
+
+ ret = sysfs_create_group(&pdev->dev.kobj, &sht15_attr_group);
+ if (ret) {
+ dev_err(&pdev->dev, "sysfs create failed\n");
+ goto err_release_irq;
+ }
data->hwmon_dev = hwmon_device_register(data->dev);
if (IS_ERR(data->hwmon_dev)) {
ret = PTR_ERR(data->hwmon_dev);
- goto err_release_irq;
+ goto err_release_sysfs_group;
}
+
return 0;
+err_release_sysfs_group:
+ sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
err_release_irq:
free_irq(gpio_to_irq(data->pdata->gpio_data), data);
err_release_gpio_data:
gpio_free(data->pdata->gpio_data);
err_release_gpio_sck:
gpio_free(data->pdata->gpio_sck);
+err_release_reg:
+ if (!IS_ERR(data->reg)) {
+ regulator_unregister_notifier(data->reg, &data->nb);
+ regulator_disable(data->reg);
+ regulator_put(data->reg);
+ }
err_free_data:
kfree(data);
error_ret:
-
return ret;
}
@@ -609,9 +1015,15 @@ static int __devexit sht15_remove(struct platform_device *pdev)
{
struct sht15_data *data = platform_get_drvdata(pdev);
- /* Make sure any reads from the device are done and
- * prevent new ones from beginning */
+ /*
+ * Make sure any reads from the device are done and
+ * prevent new ones beginning
+ */
mutex_lock(&data->read_lock);
+ if (sht15_soft_reset(data)) {
+ mutex_unlock(&data->read_lock);
+ return -EFAULT;
+ }
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
if (!IS_ERR(data->reg)) {
@@ -625,10 +1037,10 @@ static int __devexit sht15_remove(struct platform_device *pdev)
gpio_free(data->pdata->gpio_sck);
mutex_unlock(&data->read_lock);
kfree(data);
+
return 0;
}
-
/*
* sht_drivers simultaneously refers to __devinit and __devexit function
* which causes spurious section mismatch warning. So use __refdata to
@@ -673,7 +1085,6 @@ static struct platform_driver __refdata sht_drivers[] = {
},
};
-
static int __init sht15_init(void)
{
int ret;
diff --git a/drivers/hwmon/ucd9000.c b/drivers/hwmon/ucd9000.c
new file mode 100644
index 000000000000..ace1c7319734
--- /dev/null
+++ b/drivers/hwmon/ucd9000.c
@@ -0,0 +1,278 @@
+/*
+ * Hardware monitoring driver for UCD90xxx Sequencer and System Health
+ * Controller series
+ *
+ * Copyright (C) 2011 Ericsson AB.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c/pmbus.h>
+#include "pmbus.h"
+
+enum chips { ucd9000, ucd90120, ucd90124, ucd9090, ucd90910 };
+
+#define UCD9000_MONITOR_CONFIG 0xd5
+#define UCD9000_NUM_PAGES 0xd6
+#define UCD9000_FAN_CONFIG_INDEX 0xe7
+#define UCD9000_FAN_CONFIG 0xe8
+#define UCD9000_DEVICE_ID 0xfd
+
+#define UCD9000_MON_TYPE(x) (((x) >> 5) & 0x07)
+#define UCD9000_MON_PAGE(x) ((x) & 0x0f)
+
+#define UCD9000_MON_VOLTAGE 1
+#define UCD9000_MON_TEMPERATURE 2
+#define UCD9000_MON_CURRENT 3
+#define UCD9000_MON_VOLTAGE_HW 4
+
+#define UCD9000_NUM_FAN 4
+
+struct ucd9000_data {
+ u8 fan_data[UCD9000_NUM_FAN][I2C_SMBUS_BLOCK_MAX];
+ struct pmbus_driver_info info;
+};
+#define to_ucd9000_data(_info) container_of(_info, struct ucd9000_data, info)
+
+static int ucd9000_get_fan_config(struct i2c_client *client, int fan)
+{
+ int fan_config = 0;
+ struct ucd9000_data *data
+ = to_ucd9000_data(pmbus_get_driver_info(client));
+
+ if (data->fan_data[fan][3] & 1)
+ fan_config |= PB_FAN_2_INSTALLED; /* Use lower bit position */
+
+ /* Pulses/revolution */
+ fan_config |= (data->fan_data[fan][3] & 0x06) >> 1;
+
+ return fan_config;
+}
+
+static int ucd9000_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+ int ret = 0;
+ int fan_config;
+
+ switch (reg) {
+ case PMBUS_FAN_CONFIG_12:
+ if (page)
+ return -EINVAL;
+
+ ret = ucd9000_get_fan_config(client, 0);
+ if (ret < 0)
+ return ret;
+ fan_config = ret << 4;
+ ret = ucd9000_get_fan_config(client, 1);
+ if (ret < 0)
+ return ret;
+ fan_config |= ret;
+ ret = fan_config;
+ break;
+ case PMBUS_FAN_CONFIG_34:
+ if (page)
+ return -EINVAL;
+
+ ret = ucd9000_get_fan_config(client, 2);
+ if (ret < 0)
+ return ret;
+ fan_config = ret << 4;
+ ret = ucd9000_get_fan_config(client, 3);
+ if (ret < 0)
+ return ret;
+ fan_config |= ret;
+ ret = fan_config;
+ break;
+ default:
+ ret = -ENODATA;
+ break;
+ }
+ return ret;
+}
+
+static const struct i2c_device_id ucd9000_id[] = {
+ {"ucd9000", ucd9000},
+ {"ucd90120", ucd90120},
+ {"ucd90124", ucd90124},
+ {"ucd9090", ucd9090},
+ {"ucd90910", ucd90910},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, ucd9000_id);
+
+static int ucd9000_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1];
+ struct ucd9000_data *data;
+ struct pmbus_driver_info *info;
+ const struct i2c_device_id *mid;
+ int i, ret;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA))
+ return -ENODEV;
+
+ ret = i2c_smbus_read_block_data(client, UCD9000_DEVICE_ID,
+ block_buffer);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to read device ID\n");
+ return ret;
+ }
+ block_buffer[ret] = '\0';
+ dev_info(&client->dev, "Device ID %s\n", block_buffer);
+
+ mid = NULL;
+ for (i = 0; i < ARRAY_SIZE(ucd9000_id); i++) {
+ mid = &ucd9000_id[i];
+ if (!strncasecmp(mid->name, block_buffer, strlen(mid->name)))
+ break;
+ }
+ if (!mid || !strlen(mid->name)) {
+ dev_err(&client->dev, "Unsupported device\n");
+ return -ENODEV;
+ }
+
+ if (id->driver_data != ucd9000 && id->driver_data != mid->driver_data)
+ dev_notice(&client->dev,
+ "Device mismatch: Configured %s, detected %s\n",
+ id->name, mid->name);
+
+ data = kzalloc(sizeof(struct ucd9000_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+ info = &data->info;
+
+ ret = i2c_smbus_read_byte_data(client, UCD9000_NUM_PAGES);
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "Failed to read number of active pages\n");
+ goto out;
+ }
+ info->pages = ret;
+ if (!info->pages) {
+ dev_err(&client->dev, "No pages configured\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* The internal temperature sensor is always active */
+ info->func[0] = PMBUS_HAVE_TEMP;
+
+ /* Everything else is configurable */
+ ret = i2c_smbus_read_block_data(client, UCD9000_MONITOR_CONFIG,
+ block_buffer);
+ if (ret <= 0) {
+ dev_err(&client->dev, "Failed to read configuration data\n");
+ ret = -ENODEV;
+ goto out;
+ }
+ for (i = 0; i < ret; i++) {
+ int page = UCD9000_MON_PAGE(block_buffer[i]);
+
+ if (page >= info->pages)
+ continue;
+
+ switch (UCD9000_MON_TYPE(block_buffer[i])) {
+ case UCD9000_MON_VOLTAGE:
+ case UCD9000_MON_VOLTAGE_HW:
+ info->func[page] |= PMBUS_HAVE_VOUT
+ | PMBUS_HAVE_STATUS_VOUT;
+ break;
+ case UCD9000_MON_TEMPERATURE:
+ info->func[page] |= PMBUS_HAVE_TEMP2
+ | PMBUS_HAVE_STATUS_TEMP;
+ break;
+ case UCD9000_MON_CURRENT:
+ info->func[page] |= PMBUS_HAVE_IOUT
+ | PMBUS_HAVE_STATUS_IOUT;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Fan configuration */
+ if (mid->driver_data == ucd90124) {
+ for (i = 0; i < UCD9000_NUM_FAN; i++) {
+ i2c_smbus_write_byte_data(client,
+ UCD9000_FAN_CONFIG_INDEX, i);
+ ret = i2c_smbus_read_block_data(client,
+ UCD9000_FAN_CONFIG,
+ data->fan_data[i]);
+ if (ret < 0)
+ goto out;
+ }
+ i2c_smbus_write_byte_data(client, UCD9000_FAN_CONFIG_INDEX, 0);
+
+ info->read_byte_data = ucd9000_read_byte_data;
+ info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12
+ | PMBUS_HAVE_FAN34 | PMBUS_HAVE_STATUS_FAN34;
+ }
+
+ ret = pmbus_do_probe(client, mid, info);
+ if (ret < 0)
+ goto out;
+ return 0;
+
+out:
+ kfree(data);
+ return ret;
+}
+
+static int ucd9000_remove(struct i2c_client *client)
+{
+ int ret;
+ struct ucd9000_data *data;
+
+ data = to_ucd9000_data(pmbus_get_driver_info(client));
+ ret = pmbus_do_remove(client);
+ kfree(data);
+ return ret;
+}
+
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ucd9000_driver = {
+ .driver = {
+ .name = "ucd9000",
+ },
+ .probe = ucd9000_probe,
+ .remove = ucd9000_remove,
+ .id_table = ucd9000_id,
+};
+
+static int __init ucd9000_init(void)
+{
+ return i2c_add_driver(&ucd9000_driver);
+}
+
+static void __exit ucd9000_exit(void)
+{
+ i2c_del_driver(&ucd9000_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for TI UCD90xxx");
+MODULE_LICENSE("GPL");
+module_init(ucd9000_init);
+module_exit(ucd9000_exit);
diff --git a/drivers/hwmon/ucd9200.c b/drivers/hwmon/ucd9200.c
new file mode 100644
index 000000000000..ffcc1cf3609d
--- /dev/null
+++ b/drivers/hwmon/ucd9200.c
@@ -0,0 +1,210 @@
+/*
+ * Hardware monitoring driver for ucd9200 series Digital PWM System Controllers
+ *
+ * Copyright (C) 2011 Ericsson AB.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c/pmbus.h>
+#include "pmbus.h"
+
+#define UCD9200_PHASE_INFO 0xd2
+#define UCD9200_DEVICE_ID 0xfd
+
+enum chips { ucd9200, ucd9220, ucd9222, ucd9224, ucd9240, ucd9244, ucd9246,
+ ucd9248 };
+
+static const struct i2c_device_id ucd9200_id[] = {
+ {"ucd9200", ucd9200},
+ {"ucd9220", ucd9220},
+ {"ucd9222", ucd9222},
+ {"ucd9224", ucd9224},
+ {"ucd9240", ucd9240},
+ {"ucd9244", ucd9244},
+ {"ucd9246", ucd9246},
+ {"ucd9248", ucd9248},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, ucd9200_id);
+
+static int ucd9200_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1];
+ struct pmbus_driver_info *info;
+ const struct i2c_device_id *mid;
+ int i, j, ret;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA))
+ return -ENODEV;
+
+ ret = i2c_smbus_read_block_data(client, UCD9200_DEVICE_ID,
+ block_buffer);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to read device ID\n");
+ return ret;
+ }
+ block_buffer[ret] = '\0';
+ dev_info(&client->dev, "Device ID %s\n", block_buffer);
+
+ mid = NULL;
+ for (i = 0; i < ARRAY_SIZE(ucd9200_id); i++) {
+ mid = &ucd9200_id[i];
+ if (!strncasecmp(mid->name, block_buffer, strlen(mid->name)))
+ break;
+ }
+ if (!mid || !strlen(mid->name)) {
+ dev_err(&client->dev, "Unsupported device\n");
+ return -ENODEV;
+ }
+ if (id->driver_data != ucd9200 && id->driver_data != mid->driver_data)
+ dev_notice(&client->dev,
+ "Device mismatch: Configured %s, detected %s\n",
+ id->name, mid->name);
+
+ info = kzalloc(sizeof(struct pmbus_driver_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ ret = i2c_smbus_read_block_data(client, UCD9200_PHASE_INFO,
+ block_buffer);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to read phase information\n");
+ goto out;
+ }
+
+ /*
+ * Calculate number of configured pages (rails) from PHASE_INFO
+ * register.
+ * Rails have to be sequential, so we can abort after finding
+ * the first unconfigured rail.
+ */
+ info->pages = 0;
+ for (i = 0; i < ret; i++) {
+ if (!block_buffer[i])
+ break;
+ info->pages++;
+ }
+ if (!info->pages) {
+ dev_err(&client->dev, "No rails configured\n");
+ ret = -ENODEV;
+ goto out;
+ }
+ dev_info(&client->dev, "%d rails configured\n", info->pages);
+
+ /*
+ * Set PHASE registers on all pages to 0xff to ensure that phase
+ * specific commands will apply to all phases of a given page (rail).
+ * This only affects the READ_IOUT and READ_TEMPERATURE2 registers.
+ * READ_IOUT will return the sum of currents of all phases of a rail,
+ * and READ_TEMPERATURE2 will return the maximum temperature detected
+ * for the the phases of the rail.
+ */
+ for (i = 0; i < info->pages; i++) {
+ /*
+ * Setting PAGE & PHASE fails once in a while for no obvious
+ * reason, so we need to retry a couple of times.
+ */
+ for (j = 0; j < 3; j++) {
+ ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i);
+ if (ret < 0)
+ continue;
+ ret = i2c_smbus_write_byte_data(client, PMBUS_PHASE,
+ 0xff);
+ if (ret < 0)
+ continue;
+ break;
+ }
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "Failed to initialize PHASE registers\n");
+ goto out;
+ }
+ }
+ if (info->pages > 1)
+ i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0);
+
+ info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT |
+ PMBUS_HAVE_IIN | PMBUS_HAVE_PIN |
+ PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
+ PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
+ PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP |
+ PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
+
+ for (i = 1; i < info->pages; i++)
+ info->func[i] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
+ PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
+ PMBUS_HAVE_POUT |
+ PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
+
+ /* ucd9240 supports a single fan */
+ if (mid->driver_data == ucd9240)
+ info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12;
+
+ ret = pmbus_do_probe(client, mid, info);
+ if (ret < 0)
+ goto out;
+ return 0;
+out:
+ kfree(info);
+ return ret;
+}
+
+static int ucd9200_remove(struct i2c_client *client)
+{
+ int ret;
+ const struct pmbus_driver_info *info;
+
+ info = pmbus_get_driver_info(client);
+ ret = pmbus_do_remove(client);
+ kfree(info);
+ return ret;
+}
+
+
+/* This is the driver that will be inserted */
+static struct i2c_driver ucd9200_driver = {
+ .driver = {
+ .name = "ucd9200",
+ },
+ .probe = ucd9200_probe,
+ .remove = ucd9200_remove,
+ .id_table = ucd9200_id,
+};
+
+static int __init ucd9200_init(void)
+{
+ return i2c_add_driver(&ucd9200_driver);
+}
+
+static void __exit ucd9200_exit(void)
+{
+ i2c_del_driver(&ucd9200_driver);
+}
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for TI UCD922x, UCD924x");
+MODULE_LICENSE("GPL");
+module_init(ucd9200_init);
+module_exit(ucd9200_exit);
diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c
index 1f36c635d933..27a62711e0a6 100644
--- a/drivers/hwmon/ultra45_env.c
+++ b/drivers/hwmon/ultra45_env.c
@@ -258,7 +258,7 @@ static int __devinit env_probe(struct platform_device *op)
goto out_sysfs_remove_group;
}
- dev_set_drvdata(&op->dev, p);
+ platform_set_drvdata(op, p);
err = 0;
out:
@@ -277,7 +277,7 @@ out_free:
static int __devexit env_remove(struct platform_device *op)
{
- struct env *p = dev_get_drvdata(&op->dev);
+ struct env *p = platform_get_drvdata(op);
if (p) {
sysfs_remove_group(&op->dev.kobj, &env_group);
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 326652f673f7..646068e5100b 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -79,6 +79,7 @@ config I2C_AMD8111
config I2C_I801
tristate "Intel 82801 (ICH/PCH)"
depends on PCI
+ select CHECK_SIGNATURE if X86 && DMI
help
If you say yes to this option, support will be included for the Intel
801 family of mainboard I2C interfaces. Specifically, the following
@@ -101,6 +102,7 @@ config I2C_I801
6 Series (PCH)
Patsburg (PCH)
DH89xxCC (PCH)
+ Panther Point (PCH)
This driver can also be built as a module. If so, the module
will be called i2c-i801.
@@ -671,15 +673,19 @@ config I2C_XILINX
will be called xilinx_i2c.
config I2C_EG20T
- tristate "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH"
+ tristate "Intel EG20T PCH / OKI SEMICONDUCTOR IOH(ML7213/ML7223)"
depends on PCI
help
This driver is for PCH(Platform controller Hub) I2C of EG20T which
is an IOH(Input/Output Hub) for x86 embedded processor.
This driver can access PCH I2C bus device.
- This driver also supports the ML7213, a companion chip for the
- Atom E6xx series and compatible with the Intel EG20T PCH.
+ This driver also can be used for OKI SEMICONDUCTOR IOH(Input/
+ Output Hub), ML7213 and ML7223.
+ ML7213 IOH is for IVI(In-Vehicle Infotainment) use and ML7223 IOH is
+ for MP(Media Phone) use.
+ ML7213/ML7223 is companion chip for Intel Atom E6xx series.
+ ML7213/ML7223 is completely compatible for Intel EG20T PCH.
comment "External I2C/SMBus adapter drivers"
diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c
index 878a12026af2..8abfa4a03ce1 100644
--- a/drivers/i2c/busses/i2c-eg20t.c
+++ b/drivers/i2c/busses/i2c-eg20t.c
@@ -182,10 +182,12 @@ static DEFINE_MUTEX(pch_mutex);
/* Definition for ML7213 by OKI SEMICONDUCTOR */
#define PCI_VENDOR_ID_ROHM 0x10DB
#define PCI_DEVICE_ID_ML7213_I2C 0x802D
+#define PCI_DEVICE_ID_ML7223_I2C 0x8010
static struct pci_device_id __devinitdata pch_pcidev_id[] = {
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C), 1, },
{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, },
+ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), 1, },
{0,}
};
diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c
index d9aa9a649e35..a651779d9ff7 100644
--- a/drivers/i2c/busses/i2c-gpio.c
+++ b/drivers/i2c/busses/i2c-gpio.c
@@ -219,7 +219,7 @@ static void __exit i2c_gpio_exit(void)
}
module_exit(i2c_gpio_exit);
-MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
MODULE_DESCRIPTION("Platform-independent bitbanging I2C driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:i2c-gpio");
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 455e909bc768..ab26840d0c70 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -50,6 +50,7 @@
Patsburg (PCH) IDF 0x1d71 32 hard yes yes yes
Patsburg (PCH) IDF 0x1d72 32 hard yes yes yes
DH89xxCC (PCH) 0x2330 32 hard yes yes yes
+ Panther Point (PCH) 0x1e22 32 hard yes yes yes
Features supported by this driver:
Software PEC no
@@ -141,6 +142,7 @@
#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0 0x1d70
#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1 0x1d71
#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2 0x1d72
+#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22
#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330
#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30
@@ -158,6 +160,8 @@ static struct pci_driver i801_driver;
#define FEATURE_BLOCK_BUFFER (1 << 1)
#define FEATURE_BLOCK_PROC (1 << 2)
#define FEATURE_I2C_BLOCK_READ (1 << 3)
+/* Not really a feature, but it's convenient to handle it as such */
+#define FEATURE_IDF (1 << 15)
static const char *i801_feature_names[] = {
"SMBus PEC",
@@ -628,12 +632,13 @@ static const struct pci_device_id i801_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, i801_ids);
-#if defined CONFIG_INPUT_APANEL || defined CONFIG_INPUT_APANEL_MODULE
+#if defined CONFIG_X86 && defined CONFIG_DMI
static unsigned char apanel_addr;
/* Scan the system ROM for the signature "FJKEYINF" */
@@ -663,11 +668,7 @@ static void __init input_apanel_init(void)
}
iounmap(bios);
}
-#else
-static void __init input_apanel_init(void) {}
-#endif
-#if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE
struct dmi_onboard_device_info {
const char *name;
u8 type;
@@ -733,7 +734,30 @@ static void __devinit dmi_check_onboard_devices(const struct dmi_header *dm,
dmi_check_onboard_device(type, name, adap);
}
}
-#endif
+
+/* Register optional slaves */
+static void __devinit i801_probe_optional_slaves(struct i801_priv *priv)
+{
+ /* Only register slaves on main SMBus channel */
+ if (priv->features & FEATURE_IDF)
+ return;
+
+ if (apanel_addr) {
+ struct i2c_board_info info;
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ info.addr = apanel_addr;
+ strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE);
+ i2c_new_device(&priv->adapter, &info);
+ }
+
+ if (dmi_name_in_vendors("FUJITSU"))
+ dmi_walk(dmi_check_onboard_devices, &priv->adapter);
+}
+#else
+static void __init input_apanel_init(void) {}
+static void __devinit i801_probe_optional_slaves(struct i801_priv *priv) {}
+#endif /* CONFIG_X86 && CONFIG_DMI */
static int __devinit i801_probe(struct pci_dev *dev,
const struct pci_device_id *id)
@@ -753,6 +777,11 @@ static int __devinit i801_probe(struct pci_dev *dev,
priv->pci_dev = dev;
switch (dev->device) {
+ case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0:
+ case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1:
+ case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2:
+ priv->features |= FEATURE_IDF;
+ /* fall through */
default:
priv->features |= FEATURE_I2C_BLOCK_READ;
/* fall through */
@@ -838,21 +867,7 @@ static int __devinit i801_probe(struct pci_dev *dev,
goto exit_release;
}
- /* Register optional slaves */
-#if defined CONFIG_INPUT_APANEL || defined CONFIG_INPUT_APANEL_MODULE
- if (apanel_addr) {
- struct i2c_board_info info;
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- info.addr = apanel_addr;
- strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE);
- i2c_new_device(&priv->adapter, &info);
- }
-#endif
-#if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE
- if (dmi_name_in_vendors("FUJITSU"))
- dmi_walk(dmi_check_onboard_devices, &priv->adapter);
-#endif
+ i801_probe_optional_slaves(priv);
pci_set_drvdata(dev, priv);
return 0;
@@ -912,7 +927,8 @@ static struct pci_driver i801_driver = {
static int __init i2c_i801_init(void)
{
- input_apanel_init();
+ if (dmi_name_in_vendors("FUJITSU"))
+ input_apanel_init();
return pci_register_driver(&i801_driver);
}
diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
index e10e5cf3751a..0c731ca69f15 100644
--- a/drivers/i2c/busses/i2c-nomadik.c
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -15,13 +15,14 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
#include <plat/i2c.h>
@@ -103,9 +104,6 @@
/* maximum threshold value */
#define MAX_I2C_FIFO_THRESHOLD 15
-/* per-transfer delay, required for the hardware to stabilize */
-#define I2C_DELAY 150
-
enum i2c_status {
I2C_NOP,
I2C_ON_GOING,
@@ -120,9 +118,6 @@ enum i2c_operation {
I2C_READ = 0x01
};
-/* controller response timeout in ms */
-#define I2C_TIMEOUT_MS 2000
-
/**
* struct i2c_nmk_client - client specific data
* @slave_adr: 7-bit slave address
@@ -151,6 +146,7 @@ struct i2c_nmk_client {
* @stop: stop condition
* @xfer_complete: acknowledge completion for a I2C message
* @result: controller propogated result
+ * @busy: Busy doing transfer
*/
struct nmk_i2c_dev {
struct platform_device *pdev;
@@ -163,6 +159,8 @@ struct nmk_i2c_dev {
int stop;
struct completion xfer_complete;
int result;
+ struct regulator *regulator;
+ bool busy;
};
/* controller's abort causes */
@@ -209,7 +207,7 @@ static int flush_i2c_fifo(struct nmk_i2c_dev *dev)
writel((I2C_CR_FTX | I2C_CR_FRX), dev->virtbase + I2C_CR);
for (i = 0; i < LOOP_ATTEMPTS; i++) {
- timeout = jiffies + msecs_to_jiffies(I2C_TIMEOUT_MS);
+ timeout = jiffies + dev->adap.timeout;
while (!time_after(jiffies, timeout)) {
if ((readl(dev->virtbase + I2C_CR) &
@@ -253,11 +251,9 @@ static int init_hw(struct nmk_i2c_dev *dev)
{
int stat;
- clk_enable(dev->clk);
-
stat = flush_i2c_fifo(dev);
if (stat)
- return stat;
+ goto exit;
/* disable the controller */
i2c_clr_bit(dev->virtbase + I2C_CR , I2C_CR_PE);
@@ -268,10 +264,8 @@ static int init_hw(struct nmk_i2c_dev *dev)
dev->cli.operation = I2C_NO_OPERATION;
- clk_disable(dev->clk);
-
- udelay(I2C_DELAY);
- return 0;
+exit:
+ return stat;
}
/* enable peripheral, master mode operation */
@@ -424,7 +418,7 @@ static int read_i2c(struct nmk_i2c_dev *dev)
dev->virtbase + I2C_IMSCR);
timeout = wait_for_completion_interruptible_timeout(
- &dev->xfer_complete, msecs_to_jiffies(I2C_TIMEOUT_MS));
+ &dev->xfer_complete, dev->adap.timeout);
if (timeout < 0) {
dev_err(&dev->pdev->dev,
@@ -434,14 +428,32 @@ static int read_i2c(struct nmk_i2c_dev *dev)
}
if (timeout == 0) {
- /* controller has timedout, re-init the h/w */
- dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n");
- (void) init_hw(dev);
+ /* Controller timed out */
+ dev_err(&dev->pdev->dev, "read from slave 0x%x timed out\n",
+ dev->cli.slave_adr);
status = -ETIMEDOUT;
}
return status;
}
+static void fill_tx_fifo(struct nmk_i2c_dev *dev, int no_bytes)
+{
+ int count;
+
+ for (count = (no_bytes - 2);
+ (count > 0) &&
+ (dev->cli.count != 0);
+ count--) {
+ /* write to the Tx FIFO */
+ writeb(*dev->cli.buffer,
+ dev->virtbase + I2C_TFR);
+ dev->cli.buffer++;
+ dev->cli.count--;
+ dev->cli.xfer_bytes++;
+ }
+
+}
+
/**
* write_i2c() - Write data to I2C client.
* @dev: private data of I2C Driver
@@ -469,8 +481,13 @@ static int write_i2c(struct nmk_i2c_dev *dev)
init_completion(&dev->xfer_complete);
/* enable interrupts by settings the masks */
- irq_mask = (I2C_IT_TXFNE | I2C_IT_TXFOVR |
- I2C_IT_MAL | I2C_IT_BERR);
+ irq_mask = (I2C_IT_TXFOVR | I2C_IT_MAL | I2C_IT_BERR);
+
+ /* Fill the TX FIFO with transmit data */
+ fill_tx_fifo(dev, MAX_I2C_FIFO_THRESHOLD);
+
+ if (dev->cli.count != 0)
+ irq_mask |= I2C_IT_TXFNE;
/*
* check if we want to transfer a single or multiple bytes, if so
@@ -488,7 +505,7 @@ static int write_i2c(struct nmk_i2c_dev *dev)
dev->virtbase + I2C_IMSCR);
timeout = wait_for_completion_interruptible_timeout(
- &dev->xfer_complete, msecs_to_jiffies(I2C_TIMEOUT_MS));
+ &dev->xfer_complete, dev->adap.timeout);
if (timeout < 0) {
dev_err(&dev->pdev->dev,
@@ -498,9 +515,9 @@ static int write_i2c(struct nmk_i2c_dev *dev)
}
if (timeout == 0) {
- /* controller has timedout, re-init the h/w */
- dev_err(&dev->pdev->dev, "controller timed out, re-init h/w\n");
- (void) init_hw(dev);
+ /* Controller timed out */
+ dev_err(&dev->pdev->dev, "write to slave 0x%x timed out\n",
+ dev->cli.slave_adr);
status = -ETIMEDOUT;
}
@@ -508,6 +525,51 @@ static int write_i2c(struct nmk_i2c_dev *dev)
}
/**
+ * nmk_i2c_xfer_one() - transmit a single I2C message
+ * @dev: device with a message encoded into it
+ * @flags: message flags
+ */
+static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags)
+{
+ int status;
+
+ if (flags & I2C_M_RD) {
+ /* read operation */
+ dev->cli.operation = I2C_READ;
+ status = read_i2c(dev);
+ } else {
+ /* write operation */
+ dev->cli.operation = I2C_WRITE;
+ status = write_i2c(dev);
+ }
+
+ if (status || (dev->result)) {
+ u32 i2c_sr;
+ u32 cause;
+
+ i2c_sr = readl(dev->virtbase + I2C_SR);
+ /*
+ * Check if the controller I2C operation status
+ * is set to ABORT(11b).
+ */
+ if (((i2c_sr >> 2) & 0x3) == 0x3) {
+ /* get the abort cause */
+ cause = (i2c_sr >> 4) & 0x7;
+ dev_err(&dev->pdev->dev, "%s\n", cause
+ >= ARRAY_SIZE(abort_causes) ?
+ "unknown reason" :
+ abort_causes[cause]);
+ }
+
+ (void) init_hw(dev);
+
+ status = status ? status : dev->result;
+ }
+
+ return status;
+}
+
+/**
* nmk_i2c_xfer() - I2C transfer function used by kernel framework
* @i2c_adap: Adapter pointer to the controller
* @msgs: Pointer to data to be written.
@@ -559,53 +621,55 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
{
int status;
int i;
- u32 cause;
struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap);
+ int j;
+
+ dev->busy = true;
+
+ if (dev->regulator)
+ regulator_enable(dev->regulator);
+ pm_runtime_get_sync(&dev->pdev->dev);
+
+ clk_enable(dev->clk);
status = init_hw(dev);
if (status)
- return status;
+ goto out;
- clk_enable(dev->clk);
+ /* Attempt three times to send the message queue */
+ for (j = 0; j < 3; j++) {
+ /* setup the i2c controller */
+ setup_i2c_controller(dev);
- /* setup the i2c controller */
- setup_i2c_controller(dev);
+ for (i = 0; i < num_msgs; i++) {
+ if (unlikely(msgs[i].flags & I2C_M_TEN)) {
+ dev_err(&dev->pdev->dev, "10 bit addressing"
+ "not supported\n");
- for (i = 0; i < num_msgs; i++) {
- if (unlikely(msgs[i].flags & I2C_M_TEN)) {
- dev_err(&dev->pdev->dev, "10 bit addressing"
- "not supported\n");
- return -EINVAL;
- }
- dev->cli.slave_adr = msgs[i].addr;
- dev->cli.buffer = msgs[i].buf;
- dev->cli.count = msgs[i].len;
- dev->stop = (i < (num_msgs - 1)) ? 0 : 1;
- dev->result = 0;
-
- if (msgs[i].flags & I2C_M_RD) {
- /* it is a read operation */
- dev->cli.operation = I2C_READ;
- status = read_i2c(dev);
- } else {
- /* write operation */
- dev->cli.operation = I2C_WRITE;
- status = write_i2c(dev);
- }
- if (status || (dev->result)) {
- /* get the abort cause */
- cause = (readl(dev->virtbase + I2C_SR) >> 4) & 0x7;
- dev_err(&dev->pdev->dev, "error during I2C"
- "message xfer: %d\n", cause);
- dev_err(&dev->pdev->dev, "%s\n",
- cause >= ARRAY_SIZE(abort_causes)
- ? "unknown reason" : abort_causes[cause]);
- clk_disable(dev->clk);
- return status;
+ status = -EINVAL;
+ goto out;
+ }
+ dev->cli.slave_adr = msgs[i].addr;
+ dev->cli.buffer = msgs[i].buf;
+ dev->cli.count = msgs[i].len;
+ dev->stop = (i < (num_msgs - 1)) ? 0 : 1;
+ dev->result = 0;
+
+ status = nmk_i2c_xfer_one(dev, msgs[i].flags);
+ if (status != 0)
+ break;
}
- udelay(I2C_DELAY);
+ if (status == 0)
+ break;
}
+
+out:
clk_disable(dev->clk);
+ pm_runtime_put_sync(&dev->pdev->dev);
+ if (dev->regulator)
+ regulator_disable(dev->regulator);
+
+ dev->busy = false;
/* return the no. messages processed */
if (status)
@@ -666,17 +730,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
*/
disable_interrupts(dev, I2C_IT_TXFNE);
} else {
- for (count = (MAX_I2C_FIFO_THRESHOLD - tft - 2);
- (count > 0) &&
- (dev->cli.count != 0);
- count--) {
- /* write to the Tx FIFO */
- writeb(*dev->cli.buffer,
- dev->virtbase + I2C_TFR);
- dev->cli.buffer++;
- dev->cli.count--;
- dev->cli.xfer_bytes++;
- }
+ fill_tx_fifo(dev, (MAX_I2C_FIFO_THRESHOLD - tft));
/*
* if done, close the transfer by disabling the
* corresponding TXFNE interrupt
@@ -729,16 +783,11 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
}
}
- i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MTD);
- i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MTDWS);
-
- disable_interrupts(dev,
- (I2C_IT_TXFNE | I2C_IT_TXFE | I2C_IT_TXFF
- | I2C_IT_TXFOVR | I2C_IT_RXFNF
- | I2C_IT_RXFF | I2C_IT_RXFE));
+ disable_all_interrupts(dev);
+ clear_all_interrupts(dev);
if (dev->cli.count) {
- dev->result = -1;
+ dev->result = -EIO;
dev_err(&dev->pdev->dev, "%lu bytes still remain to be"
"xfered\n", dev->cli.count);
(void) init_hw(dev);
@@ -749,7 +798,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
/* Master Arbitration lost interrupt */
case I2C_IT_MAL:
- dev->result = -1;
+ dev->result = -EIO;
(void) init_hw(dev);
i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MAL);
@@ -763,7 +812,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
* during the transaction.
*/
case I2C_IT_BERR:
- dev->result = -1;
+ dev->result = -EIO;
/* get the status */
if (((readl(dev->virtbase + I2C_SR) >> 2) & 0x3) == I2C_ABORT)
(void) init_hw(dev);
@@ -779,7 +828,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
* the Tx FIFO is full.
*/
case I2C_IT_TXFOVR:
- dev->result = -1;
+ dev->result = -EIO;
(void) init_hw(dev);
dev_err(&dev->pdev->dev, "Tx Fifo Over run\n");
@@ -805,6 +854,38 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
return IRQ_HANDLED;
}
+
+#ifdef CONFIG_PM
+static int nmk_i2c_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct nmk_i2c_dev *nmk_i2c = platform_get_drvdata(pdev);
+
+ if (nmk_i2c->busy)
+ return -EBUSY;
+
+ return 0;
+}
+
+static int nmk_i2c_resume(struct device *dev)
+{
+ return 0;
+}
+#else
+#define nmk_i2c_suspend NULL
+#define nmk_i2c_resume NULL
+#endif
+
+/*
+ * We use noirq so that we suspend late and resume before the wakeup interrupt
+ * to ensure that we do the !pm_runtime_suspended() check in resume before
+ * there has been a regular pm runtime resume (via pm_runtime_get_sync()).
+ */
+static const struct dev_pm_ops nmk_i2c_pm = {
+ .suspend_noirq = nmk_i2c_suspend,
+ .resume_noirq = nmk_i2c_resume,
+};
+
static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
@@ -830,7 +911,7 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
ret = -ENOMEM;
goto err_no_mem;
}
-
+ dev->busy = false;
dev->pdev = pdev;
platform_set_drvdata(pdev, dev);
@@ -860,6 +941,15 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
goto err_irq;
}
+ dev->regulator = regulator_get(&pdev->dev, "v-i2c");
+ if (IS_ERR(dev->regulator)) {
+ dev_warn(&pdev->dev, "could not get i2c regulator\n");
+ dev->regulator = NULL;
+ }
+
+ pm_suspend_ignore_children(&pdev->dev, true);
+ pm_runtime_enable(&pdev->dev);
+
dev->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(dev->clk)) {
dev_err(&pdev->dev, "could not get i2c clock\n");
@@ -872,6 +962,8 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
adap->owner = THIS_MODULE;
adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
adap->algo = &nmk_i2c_algo;
+ adap->timeout = pdata->timeout ? msecs_to_jiffies(pdata->timeout) :
+ msecs_to_jiffies(20000);
snprintf(adap->name, sizeof(adap->name),
"Nomadik I2C%d at %lx", pdev->id, (unsigned long)res->start);
@@ -887,12 +979,6 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
i2c_set_adapdata(adap, dev);
- ret = init_hw(dev);
- if (ret != 0) {
- dev_err(&pdev->dev, "error in initializing i2c hardware\n");
- goto err_init_hw;
- }
-
dev_info(&pdev->dev, "initialize %s on virtual "
"base %p\n", adap->name, dev->virtbase);
@@ -904,10 +990,12 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)
return 0;
- err_init_hw:
err_add_adap:
clk_put(dev->clk);
err_no_clk:
+ if (dev->regulator)
+ regulator_put(dev->regulator);
+ pm_runtime_disable(&pdev->dev);
free_irq(dev->irq, dev);
err_irq:
iounmap(dev->virtbase);
@@ -938,6 +1026,9 @@ static int __devexit nmk_i2c_remove(struct platform_device *pdev)
if (res)
release_mem_region(res->start, resource_size(res));
clk_put(dev->clk);
+ if (dev->regulator)
+ regulator_put(dev->regulator);
+ pm_runtime_disable(&pdev->dev);
platform_set_drvdata(pdev, NULL);
kfree(dev);
@@ -948,6 +1039,7 @@ static struct platform_driver nmk_i2c_driver = {
.driver = {
.owner = THIS_MODULE,
.name = DRIVER_NAME,
+ .pm = &nmk_i2c_pm,
},
.probe = nmk_i2c_probe,
.remove = __devexit_p(nmk_i2c_remove),
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index fee1a2613861..1b46a9d9f907 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -49,7 +49,6 @@
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/platform_device.h>
-#include <linux/mfd/core.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
@@ -306,7 +305,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev)
return -EIO;
}
- pdata = mfd_get_data(pdev);
+ pdata = pdev->dev.platform_data;
if (pdata) {
i2c->regstep = pdata->regstep;
i2c->clock_khz = pdata->clock_khz;
diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c
index fc5fbd1012c9..4b95f7a63a3b 100644
--- a/drivers/i2c/busses/i2c-parport-light.c
+++ b/drivers/i2c/busses/i2c-parport-light.c
@@ -2,13 +2,13 @@
* i2c-parport-light.c I2C bus over parallel port *
* ------------------------------------------------------------------------ *
Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org>
-
+
Based on older i2c-velleman.c driver
Copyright (C) 1995-2000 Simon G. Vogl
With some changes from:
Frodo Looijaard <frodol@dds.nl>
Kyösti Mälkki <kmalkki@cc.hut.fi>
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
@@ -114,7 +114,7 @@ static struct i2c_algo_bit_data parport_algo_data = {
.getscl = parport_getscl,
.udelay = 50,
.timeout = HZ,
-};
+};
/* ----- Driver registration ---------------------------------------------- */
@@ -132,7 +132,7 @@ static struct i2c_smbus_alert_setup alert_data = {
static struct i2c_client *ara;
static struct lineop parport_ctrl_irq = {
.val = (1 << 4),
- .port = CTRL,
+ .port = PORT_CTRL,
};
static int __devinit i2c_parport_probe(struct platform_device *pdev)
@@ -245,7 +245,7 @@ static int __init i2c_parport_init(void)
if (irq != 0)
pr_info(DRVNAME ": using irq %d\n", irq);
- if (!adapter_parm[type].getscl.val)
+ if (!adapter_parm[type].getscl.val)
parport_algo_data.getscl = NULL;
/* Sets global pdev as a side effect */
diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c
index 2dbba163b102..24565687ac9b 100644
--- a/drivers/i2c/busses/i2c-parport.c
+++ b/drivers/i2c/busses/i2c-parport.c
@@ -2,13 +2,13 @@
* i2c-parport.c I2C bus over parallel port *
* ------------------------------------------------------------------------ *
Copyright (C) 2003-2011 Jean Delvare <khali@linux-fr.org>
-
+
Based on older i2c-philips-par.c driver
Copyright (C) 1995-2000 Simon G. Vogl
With some changes from:
Frodo Looijaard <frodol@dds.nl>
Kyösti Mälkki <kmalkki@cc.hut.fi>
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
@@ -78,13 +78,13 @@ static unsigned char port_read_control(struct parport *p)
return parport_read_control(p);
}
-static void (*port_write[])(struct parport *, unsigned char) = {
+static void (* const port_write[])(struct parport *, unsigned char) = {
port_write_data,
NULL,
port_write_control,
};
-static unsigned char (*port_read[])(struct parport *) = {
+static unsigned char (* const port_read[])(struct parport *) = {
port_read_data,
port_read_status,
port_read_control,
@@ -147,7 +147,7 @@ static const struct i2c_algo_bit_data parport_algo_data = {
.getscl = parport_getscl,
.udelay = 10, /* ~50 kbps */
.timeout = HZ,
-};
+};
/* ----- I2c and parallel port call-back functions and structures --------- */
@@ -164,10 +164,10 @@ void i2c_parport_irq(void *data)
"SMBus alert received but no ARA client!\n");
}
-static void i2c_parport_attach (struct parport *port)
+static void i2c_parport_attach(struct parport *port)
{
struct i2c_par *adapter;
-
+
adapter = kzalloc(sizeof(struct i2c_par), GFP_KERNEL);
if (adapter == NULL) {
printk(KERN_ERR "i2c-parport: Failed to kzalloc\n");
@@ -180,7 +180,7 @@ static void i2c_parport_attach (struct parport *port)
NULL, NULL, i2c_parport_irq, PARPORT_FLAG_EXCL, adapter);
if (!adapter->pdev) {
printk(KERN_ERR "i2c-parport: Unable to register with parport\n");
- goto ERROR0;
+ goto err_free;
}
/* Fill the rest of the structure */
@@ -200,7 +200,7 @@ static void i2c_parport_attach (struct parport *port)
if (parport_claim_or_block(adapter->pdev) < 0) {
printk(KERN_ERR "i2c-parport: Could not claim parallel port\n");
- goto ERROR1;
+ goto err_unregister;
}
/* Reset hardware to a sane state (SCL and SDA high) */
@@ -215,7 +215,7 @@ static void i2c_parport_attach (struct parport *port)
if (i2c_bit_add_bus(&adapter->adapter) < 0) {
printk(KERN_ERR "i2c-parport: Unable to register with I2C\n");
- goto ERROR1;
+ goto err_unregister;
}
/* Setup SMBus alert if supported */
@@ -234,16 +234,16 @@ static void i2c_parport_attach (struct parport *port)
mutex_lock(&adapter_list_lock);
list_add_tail(&adapter->node, &adapter_list);
mutex_unlock(&adapter_list_lock);
- return;
+ return;
-ERROR1:
+ err_unregister:
parport_release(adapter->pdev);
parport_unregister_device(adapter->pdev);
-ERROR0:
+ err_free:
kfree(adapter);
}
-static void i2c_parport_detach (struct parport *port)
+static void i2c_parport_detach(struct parport *port)
{
struct i2c_par *adapter, *_n;
@@ -260,7 +260,7 @@ static void i2c_parport_detach (struct parport *port)
/* Un-init if needed (power off...) */
if (adapter_parm[type].init.val)
line_set(port, 0, &adapter_parm[type].init);
-
+
parport_release(adapter->pdev);
parport_unregister_device(adapter->pdev);
list_del(&adapter->node);
diff --git a/drivers/i2c/busses/i2c-parport.h b/drivers/i2c/busses/i2c-parport.h
index a9f66816546c..3fe652302ea7 100644
--- a/drivers/i2c/busses/i2c-parport.h
+++ b/drivers/i2c/busses/i2c-parport.h
@@ -2,7 +2,7 @@
* i2c-parport.h I2C bus over parallel port *
* ------------------------------------------------------------------------ *
Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org>
-
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
@@ -18,13 +18,9 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* ------------------------------------------------------------------------ */
-#ifdef DATA
-#undef DATA
-#endif
-
-#define DATA 0
-#define STAT 1
-#define CTRL 2
+#define PORT_DATA 0
+#define PORT_STAT 1
+#define PORT_CTRL 2
struct lineop {
u8 val;
@@ -41,61 +37,61 @@ struct adapter_parm {
unsigned int smbus_alert:1;
};
-static struct adapter_parm adapter_parm[] = {
+static const struct adapter_parm adapter_parm[] = {
/* type 0: Philips adapter */
{
- .setsda = { 0x80, DATA, 1 },
- .setscl = { 0x08, CTRL, 0 },
- .getsda = { 0x80, STAT, 0 },
- .getscl = { 0x08, STAT, 0 },
+ .setsda = { 0x80, PORT_DATA, 1 },
+ .setscl = { 0x08, PORT_CTRL, 0 },
+ .getsda = { 0x80, PORT_STAT, 0 },
+ .getscl = { 0x08, PORT_STAT, 0 },
},
/* type 1: home brew teletext adapter */
{
- .setsda = { 0x02, DATA, 0 },
- .setscl = { 0x01, DATA, 0 },
- .getsda = { 0x80, STAT, 1 },
+ .setsda = { 0x02, PORT_DATA, 0 },
+ .setscl = { 0x01, PORT_DATA, 0 },
+ .getsda = { 0x80, PORT_STAT, 1 },
},
/* type 2: Velleman K8000 adapter */
{
- .setsda = { 0x02, CTRL, 1 },
- .setscl = { 0x08, CTRL, 1 },
- .getsda = { 0x10, STAT, 0 },
+ .setsda = { 0x02, PORT_CTRL, 1 },
+ .setscl = { 0x08, PORT_CTRL, 1 },
+ .getsda = { 0x10, PORT_STAT, 0 },
},
/* type 3: ELV adapter */
{
- .setsda = { 0x02, DATA, 1 },
- .setscl = { 0x01, DATA, 1 },
- .getsda = { 0x40, STAT, 1 },
- .getscl = { 0x08, STAT, 1 },
+ .setsda = { 0x02, PORT_DATA, 1 },
+ .setscl = { 0x01, PORT_DATA, 1 },
+ .getsda = { 0x40, PORT_STAT, 1 },
+ .getscl = { 0x08, PORT_STAT, 1 },
},
/* type 4: ADM1032 evaluation board */
{
- .setsda = { 0x02, DATA, 1 },
- .setscl = { 0x01, DATA, 1 },
- .getsda = { 0x10, STAT, 1 },
- .init = { 0xf0, DATA, 0 },
+ .setsda = { 0x02, PORT_DATA, 1 },
+ .setscl = { 0x01, PORT_DATA, 1 },
+ .getsda = { 0x10, PORT_STAT, 1 },
+ .init = { 0xf0, PORT_DATA, 0 },
.smbus_alert = 1,
},
/* type 5: ADM1025, ADM1030 and ADM1031 evaluation boards */
{
- .setsda = { 0x02, DATA, 1 },
- .setscl = { 0x01, DATA, 1 },
- .getsda = { 0x10, STAT, 1 },
+ .setsda = { 0x02, PORT_DATA, 1 },
+ .setscl = { 0x01, PORT_DATA, 1 },
+ .getsda = { 0x10, PORT_STAT, 1 },
},
/* type 6: Barco LPT->DVI (K5800236) adapter */
{
- .setsda = { 0x02, DATA, 1 },
- .setscl = { 0x01, DATA, 1 },
- .getsda = { 0x20, STAT, 0 },
- .getscl = { 0x40, STAT, 0 },
- .init = { 0xfc, DATA, 0 },
+ .setsda = { 0x02, PORT_DATA, 1 },
+ .setscl = { 0x01, PORT_DATA, 1 },
+ .getsda = { 0x20, PORT_STAT, 0 },
+ .getscl = { 0x40, PORT_STAT, 0 },
+ .init = { 0xfc, PORT_DATA, 0 },
},
/* type 7: One For All JP1 parallel port adapter */
{
- .setsda = { 0x01, DATA, 0 },
- .setscl = { 0x02, DATA, 0 },
- .getsda = { 0x80, STAT, 1 },
- .init = { 0x04, DATA, 1 },
+ .setsda = { 0x01, PORT_DATA, 0 },
+ .setscl = { 0x02, PORT_DATA, 0 },
+ .getsda = { 0x80, PORT_STAT, 1 },
+ .init = { 0x04, PORT_DATA, 1 },
},
};
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index 2707f5e17158..f633a53b6dbe 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -32,6 +32,7 @@
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/i2c/i2c-sh_mobile.h>
/* Transmit operation: */
/* */
@@ -117,7 +118,7 @@ struct sh_mobile_i2c_data {
struct device *dev;
void __iomem *reg;
struct i2c_adapter adap;
-
+ unsigned long bus_speed;
struct clk *clk;
u_int8_t icic;
u_int8_t iccl;
@@ -205,7 +206,7 @@ static void activate_ch(struct sh_mobile_i2c_data *pd)
* We also round off the result.
*/
num = i2c_clk * 5;
- denom = NORMAL_SPEED * 9;
+ denom = pd->bus_speed * 9;
tmp = num * 10 / denom;
if (tmp % 10 >= 5)
pd->iccl = (u_int8_t)((num/denom) + 1);
@@ -574,10 +575,10 @@ static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook)
static int sh_mobile_i2c_probe(struct platform_device *dev)
{
+ struct i2c_sh_mobile_platform_data *pdata = dev->dev.platform_data;
struct sh_mobile_i2c_data *pd;
struct i2c_adapter *adap;
struct resource *res;
- char clk_name[8];
int size;
int ret;
@@ -587,10 +588,9 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
return -ENOMEM;
}
- snprintf(clk_name, sizeof(clk_name), "i2c%d", dev->id);
- pd->clk = clk_get(&dev->dev, clk_name);
+ pd->clk = clk_get(&dev->dev, NULL);
if (IS_ERR(pd->clk)) {
- dev_err(&dev->dev, "cannot get clock \"%s\"\n", clk_name);
+ dev_err(&dev->dev, "cannot get clock\n");
ret = PTR_ERR(pd->clk);
goto err;
}
@@ -620,6 +620,11 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
goto err_irq;
}
+ /* Use platformd data bus speed or NORMAL_SPEED */
+ pd->bus_speed = NORMAL_SPEED;
+ if (pdata && pdata->bus_speed)
+ pd->bus_speed = pdata->bus_speed;
+
/* The IIC blocks on SH-Mobile ARM processors
* come with two new bits in ICIC.
*/
@@ -660,6 +665,8 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
goto err_all;
}
+ dev_info(&dev->dev, "I2C adapter %d with bus speed %lu Hz\n",
+ adap->nr, pd->bus_speed);
return 0;
err_all:
@@ -729,3 +736,4 @@ module_exit(sh_mobile_i2c_adap_exit);
MODULE_DESCRIPTION("SuperH Mobile I2C Bus Controller driver");
MODULE_AUTHOR("Magnus Damm");
MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:i2c-sh_mobile");
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index b4ab39b741eb..4d9319665e32 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -35,8 +35,10 @@
#define BYTES_PER_FIFO_WORD 4
#define I2C_CNFG 0x000
+#define I2C_CNFG_DEBOUNCE_CNT_SHIFT 12
#define I2C_CNFG_PACKET_MODE_EN (1<<10)
#define I2C_CNFG_NEW_MASTER_FSM (1<<11)
+#define I2C_STATUS 0x01C
#define I2C_SL_CNFG 0x020
#define I2C_SL_CNFG_NEWSL (1<<2)
#define I2C_SL_ADDR1 0x02c
@@ -77,6 +79,7 @@
#define I2C_ERR_NONE 0x00
#define I2C_ERR_NO_ACK 0x01
#define I2C_ERR_ARBITRATION_LOST 0x02
+#define I2C_ERR_UNKNOWN_INTERRUPT 0x04
#define PACKET_HEADER0_HEADER_SIZE_SHIFT 28
#define PACKET_HEADER0_PACKET_ID_SHIFT 16
@@ -121,6 +124,7 @@ struct tegra_i2c_dev {
void __iomem *base;
int cont_id;
int irq;
+ bool irq_disabled;
int is_dvc;
struct completion msg_complete;
int msg_err;
@@ -325,11 +329,17 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
if (i2c_dev->is_dvc)
tegra_dvc_init(i2c_dev);
- val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN;
+ val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN |
+ (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT);
i2c_writel(i2c_dev, val, I2C_CNFG);
i2c_writel(i2c_dev, 0, I2C_INT_MASK);
clk_set_rate(i2c_dev->clk, i2c_dev->bus_clk_rate * 8);
+ if (!i2c_dev->is_dvc) {
+ u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG);
+ i2c_writel(i2c_dev, sl_cfg | I2C_SL_CNFG_NEWSL, I2C_SL_CNFG);
+ }
+
val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT |
0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT;
i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL);
@@ -338,6 +348,12 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
err = -ETIMEDOUT;
clk_disable(i2c_dev->clk);
+
+ if (i2c_dev->irq_disabled) {
+ i2c_dev->irq_disabled = 0;
+ enable_irq(i2c_dev->irq);
+ }
+
return err;
}
@@ -350,8 +366,19 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id)
status = i2c_readl(i2c_dev, I2C_INT_STATUS);
if (status == 0) {
- dev_warn(i2c_dev->dev, "interrupt with no status\n");
- return IRQ_NONE;
+ dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n",
+ i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS),
+ i2c_readl(i2c_dev, I2C_STATUS),
+ i2c_readl(i2c_dev, I2C_CNFG));
+ i2c_dev->msg_err |= I2C_ERR_UNKNOWN_INTERRUPT;
+
+ if (!i2c_dev->irq_disabled) {
+ disable_irq_nosync(i2c_dev->irq);
+ i2c_dev->irq_disabled = 1;
+ }
+
+ complete(&i2c_dev->msg_complete);
+ goto err;
}
if (unlikely(status & status_err)) {
@@ -391,6 +418,8 @@ err:
I2C_INT_PACKET_XFER_COMPLETE | I2C_INT_TX_FIFO_DATA_REQ |
I2C_INT_RX_FIFO_DATA_REQ);
i2c_writel(i2c_dev, status, I2C_INT_STATUS);
+ if (i2c_dev->is_dvc)
+ dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS);
return IRQ_HANDLED;
}
@@ -424,12 +453,12 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
packet_header = msg->addr << I2C_HEADER_SLAVE_ADDR_SHIFT;
packet_header |= I2C_HEADER_IE_ENABLE;
+ if (!stop)
+ packet_header |= I2C_HEADER_REPEAT_START;
if (msg->flags & I2C_M_TEN)
packet_header |= I2C_HEADER_10BIT_ADDR;
if (msg->flags & I2C_M_IGNORE_NAK)
packet_header |= I2C_HEADER_CONT_ON_NAK;
- if (msg->flags & I2C_M_NOSTART)
- packet_header |= I2C_HEADER_REPEAT_START;
if (msg->flags & I2C_M_RD)
packet_header |= I2C_HEADER_READ;
i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c
index e9d5ff4d1496..4bb68f35caf2 100644
--- a/drivers/i2c/busses/i2c-xiic.c
+++ b/drivers/i2c/busses/i2c-xiic.c
@@ -34,7 +34,6 @@
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
-#include <linux/mfd/core.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
@@ -705,7 +704,7 @@ static int __devinit xiic_i2c_probe(struct platform_device *pdev)
if (irq < 0)
goto resource_missing;
- pdata = mfd_get_data(pdev);
+ pdata = (struct xiic_i2c_platform_data *) pdev->dev.platform_data;
if (!pdata)
return -EINVAL;
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
index c26c11905ffe..2af8cb460a3b 100644
--- a/drivers/ide/ide-acpi.c
+++ b/drivers/ide/ide-acpi.c
@@ -416,21 +416,21 @@ void ide_acpi_get_timing(ide_hwif_t *hwif)
out_obj = output.pointer;
if (out_obj->type != ACPI_TYPE_BUFFER) {
- kfree(output.pointer);
DEBPRINT("Run _GTM: error: "
"expected object type of ACPI_TYPE_BUFFER, "
"got 0x%x\n", out_obj->type);
+ kfree(output.pointer);
return;
}
if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
out_obj->buffer.length != sizeof(struct GTM_buffer)) {
- kfree(output.pointer);
printk(KERN_ERR
"%s: unexpected _GTM length (0x%x)[should be 0x%zx] or "
"addr (0x%p)\n",
__func__, out_obj->buffer.length,
sizeof(struct GTM_buffer), out_obj->buffer.pointer);
+ kfree(output.pointer);
return;
}
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index a5ec5a7cb381..6e5123b1d341 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -1781,7 +1781,8 @@ static int ide_cd_probe(ide_drive_t *drive)
ide_cd_read_toc(drive, &sense);
g->fops = &idecd_ops;
- g->flags |= GENHD_FL_REMOVABLE;
+ g->flags |= GENHD_FL_REMOVABLE | GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
+ g->events = DISK_EVENT_MEDIA_CHANGE;
add_disk(g);
return 0;
diff --git a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c
index 404843e8611b..d2f3db3cf3ed 100644
--- a/drivers/ide/ide-cs.c
+++ b/drivers/ide/ide-cs.c
@@ -272,7 +272,7 @@ static void ide_release(struct pcmcia_device *link)
} /* ide_release */
-static struct pcmcia_device_id ide_ids[] = {
+static const struct pcmcia_device_id ide_ids[] = {
PCMCIA_DEVICE_FUNC_ID(4),
PCMCIA_DEVICE_MANF_CARD(0x0000, 0x0000), /* Corsair */
PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000), /* Hitachi */
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index 5a702d02c848..61fdf544fbd6 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -73,7 +73,7 @@ static int ide_floppy_callback(ide_drive_t *drive, int dsc)
drive->failed_pc = NULL;
if (pc->c[0] == GPCMD_READ_10 || pc->c[0] == GPCMD_WRITE_10 ||
- (rq && rq->cmd_type == REQ_TYPE_BLOCK_PC))
+ rq->cmd_type == REQ_TYPE_BLOCK_PC)
uptodate = 1; /* FIXME */
else if (pc->c[0] == GPCMD_REQUEST_SENSE) {
diff --git a/drivers/ide/ide-scan-pci.c b/drivers/ide/ide-scan-pci.c
index 0e79efff1deb..c3da53e7bb2b 100644
--- a/drivers/ide/ide-scan-pci.c
+++ b/drivers/ide/ide-scan-pci.c
@@ -88,7 +88,7 @@ static int __init ide_scan_pcibus(void)
struct list_head *l, *n;
pre_init = 0;
- while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)))
+ for_each_pci_dev(dev)
ide_scan_pcidev(dev);
/*
diff --git a/drivers/ide/pmac.c b/drivers/ide/pmac.c
index ebcf8e470a97..1db7c4368dbf 100644
--- a/drivers/ide/pmac.c
+++ b/drivers/ide/pmac.c
@@ -1334,7 +1334,7 @@ out_free_pmif:
static int
pmac_ide_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
- pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)pci_get_drvdata(pdev);
+ pmac_ide_hwif_t *pmif = pci_get_drvdata(pdev);
int rc = 0;
if (mesg.event != pdev->dev.power.power_state.event
@@ -1350,7 +1350,7 @@ pmac_ide_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
static int
pmac_ide_pci_resume(struct pci_dev *pdev)
{
- pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)pci_get_drvdata(pdev);
+ pmac_ide_hwif_t *pmif = pci_get_drvdata(pdev);
int rc = 0;
if (pdev->dev.power.power_state.event != PM_EVENT_ON) {
diff --git a/drivers/ieee802154/fakehard.c b/drivers/ieee802154/fakehard.c
index d9d0e13efe47..a5a49a1baae7 100644
--- a/drivers/ieee802154/fakehard.c
+++ b/drivers/ieee802154/fakehard.c
@@ -393,16 +393,6 @@ static int __devinit ieee802154fake_probe(struct platform_device *pdev)
priv = netdev_priv(dev);
priv->phy = phy;
- /*
- * If the name is a format string the caller wants us to do a
- * name allocation.
- */
- if (strchr(dev->name, '%')) {
- err = dev_alloc_name(dev, dev->name);
- if (err < 0)
- goto out;
- }
-
wpan_phy_set_dev(phy, &pdev->dev);
SET_NETDEV_DEV(dev, &phy->dev);
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
index 6e35eccc9caa..0f9a84c1046a 100644
--- a/drivers/infiniband/Kconfig
+++ b/drivers/infiniband/Kconfig
@@ -2,6 +2,7 @@ menuconfig INFINIBAND
tristate "InfiniBand support"
depends on PCI || BROKEN
depends on HAS_IOMEM
+ depends on NET
---help---
Core support for InfiniBand (IB). Make sure to also select
any protocols you wish to use as well as drivers for your
diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile
index cb1ab3ea4998..c8bbaef1becb 100644
--- a/drivers/infiniband/core/Makefile
+++ b/drivers/infiniband/core/Makefile
@@ -8,7 +8,7 @@ obj-$(CONFIG_INFINIBAND_USER_ACCESS) += ib_uverbs.o ib_ucm.o \
$(user_access-y)
ib_core-y := packer.o ud_header.o verbs.o sysfs.o \
- device.o fmr_pool.o cache.o
+ device.o fmr_pool.o cache.o netlink.o
ib_core-$(CONFIG_INFINIBAND_USER_MEM) += umem.o
ib_mad-y := mad.o smi.o agent.o mad_rmpp.o
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index 4ffc224faa7f..8e21d457b899 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -185,15 +185,20 @@ static int addr4_resolve(struct sockaddr_in *src_in,
__be32 dst_ip = dst_in->sin_addr.s_addr;
struct rtable *rt;
struct neighbour *neigh;
+ struct flowi4 fl4;
int ret;
- rt = ip_route_output(&init_net, dst_ip, src_ip, 0, addr->bound_dev_if);
+ memset(&fl4, 0, sizeof(fl4));
+ fl4.daddr = dst_ip;
+ fl4.saddr = src_ip;
+ fl4.flowi4_oif = addr->bound_dev_if;
+ rt = ip_route_output_key(&init_net, &fl4);
if (IS_ERR(rt)) {
ret = PTR_ERR(rt);
goto out;
}
src_in->sin_family = AF_INET;
- src_in->sin_addr.s_addr = rt->rt_src;
+ src_in->sin_addr.s_addr = fl4.saddr;
if (rt->dst.dev->flags & IFF_LOOPBACK) {
ret = rdma_translate_ip((struct sockaddr *) dst_in, addr);
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index f804e28e1ebb..f62f52fb9ece 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -3639,8 +3639,16 @@ static struct kobj_type cm_port_obj_type = {
.release = cm_release_port_obj
};
+static char *cm_devnode(struct device *dev, mode_t *mode)
+{
+ *mode = 0666;
+ return kasprintf(GFP_KERNEL, "infiniband/%s", dev_name(dev));
+}
+
struct class cm_class = {
+ .owner = THIS_MODULE,
.name = "infiniband_cm",
+ .devnode = cm_devnode,
};
EXPORT_SYMBOL(cm_class);
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 5ed9d25d021a..b6a33b3c516d 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -47,6 +47,7 @@
#include <rdma/rdma_cm.h>
#include <rdma/rdma_cm_ib.h>
+#include <rdma/rdma_netlink.h>
#include <rdma/ib_cache.h>
#include <rdma/ib_cm.h>
#include <rdma/ib_sa.h>
@@ -89,20 +90,6 @@ struct cma_device {
struct list_head id_list;
};
-enum cma_state {
- CMA_IDLE,
- CMA_ADDR_QUERY,
- CMA_ADDR_RESOLVED,
- CMA_ROUTE_QUERY,
- CMA_ROUTE_RESOLVED,
- CMA_CONNECT,
- CMA_DISCONNECT,
- CMA_ADDR_BOUND,
- CMA_LISTEN,
- CMA_DEVICE_REMOVAL,
- CMA_DESTROYING
-};
-
struct rdma_bind_list {
struct idr *ps;
struct hlist_head owners;
@@ -126,7 +113,7 @@ struct rdma_id_private {
struct list_head mc_list;
int internal_id;
- enum cma_state state;
+ enum rdma_cm_state state;
spinlock_t lock;
struct mutex qp_mutex;
@@ -146,8 +133,10 @@ struct rdma_id_private {
u32 seq_num;
u32 qkey;
u32 qp_num;
+ pid_t owner;
u8 srq;
u8 tos;
+ u8 reuseaddr;
};
struct cma_multicast {
@@ -164,8 +153,8 @@ struct cma_multicast {
struct cma_work {
struct work_struct work;
struct rdma_id_private *id;
- enum cma_state old_state;
- enum cma_state new_state;
+ enum rdma_cm_state old_state;
+ enum rdma_cm_state new_state;
struct rdma_cm_event event;
};
@@ -216,7 +205,7 @@ struct sdp_hah {
#define CMA_VERSION 0x00
#define SDP_MAJ_VERSION 0x2
-static int cma_comp(struct rdma_id_private *id_priv, enum cma_state comp)
+static int cma_comp(struct rdma_id_private *id_priv, enum rdma_cm_state comp)
{
unsigned long flags;
int ret;
@@ -228,7 +217,7 @@ static int cma_comp(struct rdma_id_private *id_priv, enum cma_state comp)
}
static int cma_comp_exch(struct rdma_id_private *id_priv,
- enum cma_state comp, enum cma_state exch)
+ enum rdma_cm_state comp, enum rdma_cm_state exch)
{
unsigned long flags;
int ret;
@@ -240,11 +229,11 @@ static int cma_comp_exch(struct rdma_id_private *id_priv,
return ret;
}
-static enum cma_state cma_exch(struct rdma_id_private *id_priv,
- enum cma_state exch)
+static enum rdma_cm_state cma_exch(struct rdma_id_private *id_priv,
+ enum rdma_cm_state exch)
{
unsigned long flags;
- enum cma_state old;
+ enum rdma_cm_state old;
spin_lock_irqsave(&id_priv->lock, flags);
old = id_priv->state;
@@ -278,11 +267,6 @@ static inline void sdp_set_ip_ver(struct sdp_hh *hh, u8 ip_ver)
hh->ip_version = (ip_ver << 4) | (hh->ip_version & 0xF);
}
-static inline int cma_is_ud_ps(enum rdma_port_space ps)
-{
- return (ps == RDMA_PS_UDP || ps == RDMA_PS_IPOIB);
-}
-
static void cma_attach_to_dev(struct rdma_id_private *id_priv,
struct cma_device *cma_dev)
{
@@ -412,7 +396,7 @@ static void cma_deref_id(struct rdma_id_private *id_priv)
}
static int cma_disable_callback(struct rdma_id_private *id_priv,
- enum cma_state state)
+ enum rdma_cm_state state)
{
mutex_lock(&id_priv->handler_mutex);
if (id_priv->state != state) {
@@ -428,7 +412,8 @@ static int cma_has_cm_dev(struct rdma_id_private *id_priv)
}
struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler,
- void *context, enum rdma_port_space ps)
+ void *context, enum rdma_port_space ps,
+ enum ib_qp_type qp_type)
{
struct rdma_id_private *id_priv;
@@ -436,10 +421,12 @@ struct rdma_cm_id *rdma_create_id(rdma_cm_event_handler event_handler,
if (!id_priv)
return ERR_PTR(-ENOMEM);
- id_priv->state = CMA_IDLE;
+ id_priv->owner = task_pid_nr(current);
+ id_priv->state = RDMA_CM_IDLE;
id_priv->id.context = context;
id_priv->id.event_handler = event_handler;
id_priv->id.ps = ps;
+ id_priv->id.qp_type = qp_type;
spin_lock_init(&id_priv->lock);
mutex_init(&id_priv->qp_mutex);
init_completion(&id_priv->comp);
@@ -507,7 +494,7 @@ int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd,
if (IS_ERR(qp))
return PTR_ERR(qp);
- if (cma_is_ud_ps(id_priv->id.ps))
+ if (id->qp_type == IB_QPT_UD)
ret = cma_init_ud_qp(id_priv, qp);
else
ret = cma_init_conn_qp(id_priv, qp);
@@ -635,7 +622,7 @@ static int cma_ib_init_qp_attr(struct rdma_id_private *id_priv,
qp_attr->port_num = id_priv->id.port_num;
*qp_attr_mask = IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT;
- if (cma_is_ud_ps(id_priv->id.ps)) {
+ if (id_priv->id.qp_type == IB_QPT_UD) {
ret = cma_set_qkey(id_priv);
if (ret)
return ret;
@@ -658,7 +645,7 @@ int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr,
id_priv = container_of(id, struct rdma_id_private, id);
switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
case RDMA_TRANSPORT_IB:
- if (!id_priv->cm_id.ib || cma_is_ud_ps(id_priv->id.ps))
+ if (!id_priv->cm_id.ib || (id_priv->id.qp_type == IB_QPT_UD))
ret = cma_ib_init_qp_attr(id_priv, qp_attr, qp_attr_mask);
else
ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr,
@@ -712,6 +699,21 @@ static inline int cma_any_addr(struct sockaddr *addr)
return cma_zero_addr(addr) || cma_loopback_addr(addr);
}
+static int cma_addr_cmp(struct sockaddr *src, struct sockaddr *dst)
+{
+ if (src->sa_family != dst->sa_family)
+ return -1;
+
+ switch (src->sa_family) {
+ case AF_INET:
+ return ((struct sockaddr_in *) src)->sin_addr.s_addr !=
+ ((struct sockaddr_in *) dst)->sin_addr.s_addr;
+ default:
+ return ipv6_addr_cmp(&((struct sockaddr_in6 *) src)->sin6_addr,
+ &((struct sockaddr_in6 *) dst)->sin6_addr);
+ }
+}
+
static inline __be16 cma_port(struct sockaddr *addr)
{
if (addr->sa_family == AF_INET)
@@ -842,16 +844,16 @@ static void cma_cancel_listens(struct rdma_id_private *id_priv)
}
static void cma_cancel_operation(struct rdma_id_private *id_priv,
- enum cma_state state)
+ enum rdma_cm_state state)
{
switch (state) {
- case CMA_ADDR_QUERY:
+ case RDMA_CM_ADDR_QUERY:
rdma_addr_cancel(&id_priv->id.route.addr.dev_addr);
break;
- case CMA_ROUTE_QUERY:
+ case RDMA_CM_ROUTE_QUERY:
cma_cancel_route(id_priv);
break;
- case CMA_LISTEN:
+ case RDMA_CM_LISTEN:
if (cma_any_addr((struct sockaddr *) &id_priv->id.route.addr.src_addr)
&& !id_priv->cma_dev)
cma_cancel_listens(id_priv);
@@ -902,10 +904,10 @@ static void cma_leave_mc_groups(struct rdma_id_private *id_priv)
void rdma_destroy_id(struct rdma_cm_id *id)
{
struct rdma_id_private *id_priv;
- enum cma_state state;
+ enum rdma_cm_state state;
id_priv = container_of(id, struct rdma_id_private, id);
- state = cma_exch(id_priv, CMA_DESTROYING);
+ state = cma_exch(id_priv, RDMA_CM_DESTROYING);
cma_cancel_operation(id_priv, state);
/*
@@ -999,9 +1001,9 @@ static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
int ret = 0;
if ((ib_event->event != IB_CM_TIMEWAIT_EXIT &&
- cma_disable_callback(id_priv, CMA_CONNECT)) ||
+ cma_disable_callback(id_priv, RDMA_CM_CONNECT)) ||
(ib_event->event == IB_CM_TIMEWAIT_EXIT &&
- cma_disable_callback(id_priv, CMA_DISCONNECT)))
+ cma_disable_callback(id_priv, RDMA_CM_DISCONNECT)))
return 0;
memset(&event, 0, sizeof event);
@@ -1032,7 +1034,8 @@ static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
event.status = -ETIMEDOUT; /* fall through */
case IB_CM_DREQ_RECEIVED:
case IB_CM_DREP_RECEIVED:
- if (!cma_comp_exch(id_priv, CMA_CONNECT, CMA_DISCONNECT))
+ if (!cma_comp_exch(id_priv, RDMA_CM_CONNECT,
+ RDMA_CM_DISCONNECT))
goto out;
event.event = RDMA_CM_EVENT_DISCONNECTED;
break;
@@ -1059,7 +1062,7 @@ static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
if (ret) {
/* Destroy the CM ID by returning a non-zero value. */
id_priv->cm_id.ib = NULL;
- cma_exch(id_priv, CMA_DESTROYING);
+ cma_exch(id_priv, RDMA_CM_DESTROYING);
mutex_unlock(&id_priv->handler_mutex);
rdma_destroy_id(&id_priv->id);
return ret;
@@ -1085,7 +1088,7 @@ static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id,
goto err;
id = rdma_create_id(listen_id->event_handler, listen_id->context,
- listen_id->ps);
+ listen_id->ps, ib_event->param.req_rcvd.qp_type);
if (IS_ERR(id))
goto err;
@@ -1116,7 +1119,7 @@ static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id,
rdma_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid);
id_priv = container_of(id, struct rdma_id_private, id);
- id_priv->state = CMA_CONNECT;
+ id_priv->state = RDMA_CM_CONNECT;
return id_priv;
destroy_id:
@@ -1136,7 +1139,7 @@ static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id,
int ret;
id = rdma_create_id(listen_id->event_handler, listen_id->context,
- listen_id->ps);
+ listen_id->ps, IB_QPT_UD);
if (IS_ERR(id))
return NULL;
@@ -1156,7 +1159,7 @@ static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id,
}
id_priv = container_of(id, struct rdma_id_private, id);
- id_priv->state = CMA_CONNECT;
+ id_priv->state = RDMA_CM_CONNECT;
return id_priv;
err:
rdma_destroy_id(id);
@@ -1185,13 +1188,13 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
int offset, ret;
listen_id = cm_id->context;
- if (cma_disable_callback(listen_id, CMA_LISTEN))
+ if (cma_disable_callback(listen_id, RDMA_CM_LISTEN))
return -ECONNABORTED;
memset(&event, 0, sizeof event);
offset = cma_user_data_offset(listen_id->id.ps);
event.event = RDMA_CM_EVENT_CONNECT_REQUEST;
- if (cma_is_ud_ps(listen_id->id.ps)) {
+ if (listen_id->id.qp_type == IB_QPT_UD) {
conn_id = cma_new_udp_id(&listen_id->id, ib_event);
event.param.ud.private_data = ib_event->private_data + offset;
event.param.ud.private_data_len =
@@ -1227,8 +1230,7 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
* while we're accessing the cm_id.
*/
mutex_lock(&lock);
- if (cma_comp(conn_id, CMA_CONNECT) &&
- !cma_is_ud_ps(conn_id->id.ps))
+ if (cma_comp(conn_id, RDMA_CM_CONNECT) && (conn_id->id.qp_type != IB_QPT_UD))
ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0);
mutex_unlock(&lock);
mutex_unlock(&conn_id->handler_mutex);
@@ -1241,7 +1243,7 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
conn_id->cm_id.ib = NULL;
release_conn_id:
- cma_exch(conn_id, CMA_DESTROYING);
+ cma_exch(conn_id, RDMA_CM_DESTROYING);
mutex_unlock(&conn_id->handler_mutex);
rdma_destroy_id(&conn_id->id);
@@ -1312,7 +1314,7 @@ static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event)
struct sockaddr_in *sin;
int ret = 0;
- if (cma_disable_callback(id_priv, CMA_CONNECT))
+ if (cma_disable_callback(id_priv, RDMA_CM_CONNECT))
return 0;
memset(&event, 0, sizeof event);
@@ -1355,7 +1357,7 @@ static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event)
if (ret) {
/* Destroy the CM ID by returning a non-zero value. */
id_priv->cm_id.iw = NULL;
- cma_exch(id_priv, CMA_DESTROYING);
+ cma_exch(id_priv, RDMA_CM_DESTROYING);
mutex_unlock(&id_priv->handler_mutex);
rdma_destroy_id(&id_priv->id);
return ret;
@@ -1377,20 +1379,20 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
struct ib_device_attr attr;
listen_id = cm_id->context;
- if (cma_disable_callback(listen_id, CMA_LISTEN))
+ if (cma_disable_callback(listen_id, RDMA_CM_LISTEN))
return -ECONNABORTED;
/* Create a new RDMA id for the new IW CM ID */
new_cm_id = rdma_create_id(listen_id->id.event_handler,
listen_id->id.context,
- RDMA_PS_TCP);
+ RDMA_PS_TCP, IB_QPT_RC);
if (IS_ERR(new_cm_id)) {
ret = -ENOMEM;
goto out;
}
conn_id = container_of(new_cm_id, struct rdma_id_private, id);
mutex_lock_nested(&conn_id->handler_mutex, SINGLE_DEPTH_NESTING);
- conn_id->state = CMA_CONNECT;
+ conn_id->state = RDMA_CM_CONNECT;
dev = ip_dev_find(&init_net, iw_event->local_addr.sin_addr.s_addr);
if (!dev) {
@@ -1445,7 +1447,7 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
if (ret) {
/* User wants to destroy the CM ID */
conn_id->cm_id.iw = NULL;
- cma_exch(conn_id, CMA_DESTROYING);
+ cma_exch(conn_id, RDMA_CM_DESTROYING);
mutex_unlock(&conn_id->handler_mutex);
cma_deref_id(conn_id);
rdma_destroy_id(&conn_id->id);
@@ -1532,13 +1534,14 @@ static void cma_listen_on_dev(struct rdma_id_private *id_priv,
struct rdma_cm_id *id;
int ret;
- id = rdma_create_id(cma_listen_handler, id_priv, id_priv->id.ps);
+ id = rdma_create_id(cma_listen_handler, id_priv, id_priv->id.ps,
+ id_priv->id.qp_type);
if (IS_ERR(id))
return;
dev_id_priv = container_of(id, struct rdma_id_private, id);
- dev_id_priv->state = CMA_ADDR_BOUND;
+ dev_id_priv->state = RDMA_CM_ADDR_BOUND;
memcpy(&id->route.addr.src_addr, &id_priv->id.route.addr.src_addr,
ip_addr_size((struct sockaddr *) &id_priv->id.route.addr.src_addr));
@@ -1564,50 +1567,6 @@ static void cma_listen_on_all(struct rdma_id_private *id_priv)
mutex_unlock(&lock);
}
-int rdma_listen(struct rdma_cm_id *id, int backlog)
-{
- struct rdma_id_private *id_priv;
- int ret;
-
- id_priv = container_of(id, struct rdma_id_private, id);
- if (id_priv->state == CMA_IDLE) {
- ((struct sockaddr *) &id->route.addr.src_addr)->sa_family = AF_INET;
- ret = rdma_bind_addr(id, (struct sockaddr *) &id->route.addr.src_addr);
- if (ret)
- return ret;
- }
-
- if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_LISTEN))
- return -EINVAL;
-
- id_priv->backlog = backlog;
- if (id->device) {
- switch (rdma_node_get_transport(id->device->node_type)) {
- case RDMA_TRANSPORT_IB:
- ret = cma_ib_listen(id_priv);
- if (ret)
- goto err;
- break;
- case RDMA_TRANSPORT_IWARP:
- ret = cma_iw_listen(id_priv, backlog);
- if (ret)
- goto err;
- break;
- default:
- ret = -ENOSYS;
- goto err;
- }
- } else
- cma_listen_on_all(id_priv);
-
- return 0;
-err:
- id_priv->backlog = 0;
- cma_comp_exch(id_priv, CMA_LISTEN, CMA_ADDR_BOUND);
- return ret;
-}
-EXPORT_SYMBOL(rdma_listen);
-
void rdma_set_service_type(struct rdma_cm_id *id, int tos)
{
struct rdma_id_private *id_priv;
@@ -1629,8 +1588,8 @@ static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec,
route->num_paths = 1;
*route->path_rec = *path_rec;
} else {
- work->old_state = CMA_ROUTE_QUERY;
- work->new_state = CMA_ADDR_RESOLVED;
+ work->old_state = RDMA_CM_ROUTE_QUERY;
+ work->new_state = RDMA_CM_ADDR_RESOLVED;
work->event.event = RDMA_CM_EVENT_ROUTE_ERROR;
work->event.status = status;
}
@@ -1688,7 +1647,7 @@ static void cma_work_handler(struct work_struct *_work)
goto out;
if (id_priv->id.event_handler(&id_priv->id, &work->event)) {
- cma_exch(id_priv, CMA_DESTROYING);
+ cma_exch(id_priv, RDMA_CM_DESTROYING);
destroy = 1;
}
out:
@@ -1706,12 +1665,12 @@ static void cma_ndev_work_handler(struct work_struct *_work)
int destroy = 0;
mutex_lock(&id_priv->handler_mutex);
- if (id_priv->state == CMA_DESTROYING ||
- id_priv->state == CMA_DEVICE_REMOVAL)
+ if (id_priv->state == RDMA_CM_DESTROYING ||
+ id_priv->state == RDMA_CM_DEVICE_REMOVAL)
goto out;
if (id_priv->id.event_handler(&id_priv->id, &work->event)) {
- cma_exch(id_priv, CMA_DESTROYING);
+ cma_exch(id_priv, RDMA_CM_DESTROYING);
destroy = 1;
}
@@ -1735,8 +1694,8 @@ static int cma_resolve_ib_route(struct rdma_id_private *id_priv, int timeout_ms)
work->id = id_priv;
INIT_WORK(&work->work, cma_work_handler);
- work->old_state = CMA_ROUTE_QUERY;
- work->new_state = CMA_ROUTE_RESOLVED;
+ work->old_state = RDMA_CM_ROUTE_QUERY;
+ work->new_state = RDMA_CM_ROUTE_RESOLVED;
work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED;
route->path_rec = kmalloc(sizeof *route->path_rec, GFP_KERNEL);
@@ -1765,7 +1724,8 @@ int rdma_set_ib_paths(struct rdma_cm_id *id,
int ret;
id_priv = container_of(id, struct rdma_id_private, id);
- if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ROUTE_RESOLVED))
+ if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED,
+ RDMA_CM_ROUTE_RESOLVED))
return -EINVAL;
id->route.path_rec = kmemdup(path_rec, sizeof *path_rec * num_paths,
@@ -1778,7 +1738,7 @@ int rdma_set_ib_paths(struct rdma_cm_id *id,
id->route.num_paths = num_paths;
return 0;
err:
- cma_comp_exch(id_priv, CMA_ROUTE_RESOLVED, CMA_ADDR_RESOLVED);
+ cma_comp_exch(id_priv, RDMA_CM_ROUTE_RESOLVED, RDMA_CM_ADDR_RESOLVED);
return ret;
}
EXPORT_SYMBOL(rdma_set_ib_paths);
@@ -1793,8 +1753,8 @@ static int cma_resolve_iw_route(struct rdma_id_private *id_priv, int timeout_ms)
work->id = id_priv;
INIT_WORK(&work->work, cma_work_handler);
- work->old_state = CMA_ROUTE_QUERY;
- work->new_state = CMA_ROUTE_RESOLVED;
+ work->old_state = RDMA_CM_ROUTE_QUERY;
+ work->new_state = RDMA_CM_ROUTE_RESOLVED;
work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED;
queue_work(cma_wq, &work->work);
return 0;
@@ -1858,8 +1818,8 @@ static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
goto err2;
}
- work->old_state = CMA_ROUTE_QUERY;
- work->new_state = CMA_ROUTE_RESOLVED;
+ work->old_state = RDMA_CM_ROUTE_QUERY;
+ work->new_state = RDMA_CM_ROUTE_RESOLVED;
work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED;
work->event.status = 0;
@@ -1881,7 +1841,7 @@ int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms)
int ret;
id_priv = container_of(id, struct rdma_id_private, id);
- if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ROUTE_QUERY))
+ if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED, RDMA_CM_ROUTE_QUERY))
return -EINVAL;
atomic_inc(&id_priv->refcount);
@@ -1910,7 +1870,7 @@ int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms)
return 0;
err:
- cma_comp_exch(id_priv, CMA_ROUTE_QUERY, CMA_ADDR_RESOLVED);
+ cma_comp_exch(id_priv, RDMA_CM_ROUTE_QUERY, RDMA_CM_ADDR_RESOLVED);
cma_deref_id(id_priv);
return ret;
}
@@ -1969,14 +1929,16 @@ static void addr_handler(int status, struct sockaddr *src_addr,
memset(&event, 0, sizeof event);
mutex_lock(&id_priv->handler_mutex);
- if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_RESOLVED))
+ if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY,
+ RDMA_CM_ADDR_RESOLVED))
goto out;
if (!status && !id_priv->cma_dev)
status = cma_acquire_dev(id_priv);
if (status) {
- if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ADDR_BOUND))
+ if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_RESOLVED,
+ RDMA_CM_ADDR_BOUND))
goto out;
event.event = RDMA_CM_EVENT_ADDR_ERROR;
event.status = status;
@@ -1987,7 +1949,7 @@ static void addr_handler(int status, struct sockaddr *src_addr,
}
if (id_priv->id.event_handler(&id_priv->id, &event)) {
- cma_exch(id_priv, CMA_DESTROYING);
+ cma_exch(id_priv, RDMA_CM_DESTROYING);
mutex_unlock(&id_priv->handler_mutex);
cma_deref_id(id_priv);
rdma_destroy_id(&id_priv->id);
@@ -2032,8 +1994,8 @@ static int cma_resolve_loopback(struct rdma_id_private *id_priv)
work->id = id_priv;
INIT_WORK(&work->work, cma_work_handler);
- work->old_state = CMA_ADDR_QUERY;
- work->new_state = CMA_ADDR_RESOLVED;
+ work->old_state = RDMA_CM_ADDR_QUERY;
+ work->new_state = RDMA_CM_ADDR_RESOLVED;
work->event.event = RDMA_CM_EVENT_ADDR_RESOLVED;
queue_work(cma_wq, &work->work);
return 0;
@@ -2062,13 +2024,13 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
int ret;
id_priv = container_of(id, struct rdma_id_private, id);
- if (id_priv->state == CMA_IDLE) {
+ if (id_priv->state == RDMA_CM_IDLE) {
ret = cma_bind_addr(id, src_addr, dst_addr);
if (ret)
return ret;
}
- if (!cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_ADDR_QUERY))
+ if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_ADDR_QUERY))
return -EINVAL;
atomic_inc(&id_priv->refcount);
@@ -2084,12 +2046,31 @@ int rdma_resolve_addr(struct rdma_cm_id *id, struct sockaddr *src_addr,
return 0;
err:
- cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_BOUND);
+ cma_comp_exch(id_priv, RDMA_CM_ADDR_QUERY, RDMA_CM_ADDR_BOUND);
cma_deref_id(id_priv);
return ret;
}
EXPORT_SYMBOL(rdma_resolve_addr);
+int rdma_set_reuseaddr(struct rdma_cm_id *id, int reuse)
+{
+ struct rdma_id_private *id_priv;
+ unsigned long flags;
+ int ret;
+
+ id_priv = container_of(id, struct rdma_id_private, id);
+ spin_lock_irqsave(&id_priv->lock, flags);
+ if (id_priv->state == RDMA_CM_IDLE) {
+ id_priv->reuseaddr = reuse;
+ ret = 0;
+ } else {
+ ret = -EINVAL;
+ }
+ spin_unlock_irqrestore(&id_priv->lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL(rdma_set_reuseaddr);
+
static void cma_bind_port(struct rdma_bind_list *bind_list,
struct rdma_id_private *id_priv)
{
@@ -2165,41 +2146,71 @@ retry:
return -EADDRNOTAVAIL;
}
-static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv)
+/*
+ * Check that the requested port is available. This is called when trying to
+ * bind to a specific port, or when trying to listen on a bound port. In
+ * the latter case, the provided id_priv may already be on the bind_list, but
+ * we still need to check that it's okay to start listening.
+ */
+static int cma_check_port(struct rdma_bind_list *bind_list,
+ struct rdma_id_private *id_priv, uint8_t reuseaddr)
{
struct rdma_id_private *cur_id;
- struct sockaddr_in *sin, *cur_sin;
- struct rdma_bind_list *bind_list;
+ struct sockaddr *addr, *cur_addr;
struct hlist_node *node;
+
+ addr = (struct sockaddr *) &id_priv->id.route.addr.src_addr;
+ if (cma_any_addr(addr) && !reuseaddr)
+ return -EADDRNOTAVAIL;
+
+ hlist_for_each_entry(cur_id, node, &bind_list->owners, node) {
+ if (id_priv == cur_id)
+ continue;
+
+ if ((cur_id->state == RDMA_CM_LISTEN) ||
+ !reuseaddr || !cur_id->reuseaddr) {
+ cur_addr = (struct sockaddr *) &cur_id->id.route.addr.src_addr;
+ if (cma_any_addr(cur_addr))
+ return -EADDRNOTAVAIL;
+
+ if (!cma_addr_cmp(addr, cur_addr))
+ return -EADDRINUSE;
+ }
+ }
+ return 0;
+}
+
+static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv)
+{
+ struct rdma_bind_list *bind_list;
unsigned short snum;
+ int ret;
- sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr;
- snum = ntohs(sin->sin_port);
+ snum = ntohs(cma_port((struct sockaddr *) &id_priv->id.route.addr.src_addr));
if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
return -EACCES;
bind_list = idr_find(ps, snum);
- if (!bind_list)
- return cma_alloc_port(ps, id_priv, snum);
-
- /*
- * We don't support binding to any address if anyone is bound to
- * a specific address on the same port.
- */
- if (cma_any_addr((struct sockaddr *) &id_priv->id.route.addr.src_addr))
- return -EADDRNOTAVAIL;
-
- hlist_for_each_entry(cur_id, node, &bind_list->owners, node) {
- if (cma_any_addr((struct sockaddr *) &cur_id->id.route.addr.src_addr))
- return -EADDRNOTAVAIL;
-
- cur_sin = (struct sockaddr_in *) &cur_id->id.route.addr.src_addr;
- if (sin->sin_addr.s_addr == cur_sin->sin_addr.s_addr)
- return -EADDRINUSE;
+ if (!bind_list) {
+ ret = cma_alloc_port(ps, id_priv, snum);
+ } else {
+ ret = cma_check_port(bind_list, id_priv, id_priv->reuseaddr);
+ if (!ret)
+ cma_bind_port(bind_list, id_priv);
}
+ return ret;
+}
- cma_bind_port(bind_list, id_priv);
- return 0;
+static int cma_bind_listen(struct rdma_id_private *id_priv)
+{
+ struct rdma_bind_list *bind_list = id_priv->bind_list;
+ int ret = 0;
+
+ mutex_lock(&lock);
+ if (bind_list->owners.first->next)
+ ret = cma_check_port(bind_list, id_priv, 0);
+ mutex_unlock(&lock);
+ return ret;
}
static int cma_get_port(struct rdma_id_private *id_priv)
@@ -2253,6 +2264,56 @@ static int cma_check_linklocal(struct rdma_dev_addr *dev_addr,
return 0;
}
+int rdma_listen(struct rdma_cm_id *id, int backlog)
+{
+ struct rdma_id_private *id_priv;
+ int ret;
+
+ id_priv = container_of(id, struct rdma_id_private, id);
+ if (id_priv->state == RDMA_CM_IDLE) {
+ ((struct sockaddr *) &id->route.addr.src_addr)->sa_family = AF_INET;
+ ret = rdma_bind_addr(id, (struct sockaddr *) &id->route.addr.src_addr);
+ if (ret)
+ return ret;
+ }
+
+ if (!cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_LISTEN))
+ return -EINVAL;
+
+ if (id_priv->reuseaddr) {
+ ret = cma_bind_listen(id_priv);
+ if (ret)
+ goto err;
+ }
+
+ id_priv->backlog = backlog;
+ if (id->device) {
+ switch (rdma_node_get_transport(id->device->node_type)) {
+ case RDMA_TRANSPORT_IB:
+ ret = cma_ib_listen(id_priv);
+ if (ret)
+ goto err;
+ break;
+ case RDMA_TRANSPORT_IWARP:
+ ret = cma_iw_listen(id_priv, backlog);
+ if (ret)
+ goto err;
+ break;
+ default:
+ ret = -ENOSYS;
+ goto err;
+ }
+ } else
+ cma_listen_on_all(id_priv);
+
+ return 0;
+err:
+ id_priv->backlog = 0;
+ cma_comp_exch(id_priv, RDMA_CM_LISTEN, RDMA_CM_ADDR_BOUND);
+ return ret;
+}
+EXPORT_SYMBOL(rdma_listen);
+
int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
{
struct rdma_id_private *id_priv;
@@ -2262,7 +2323,7 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
return -EAFNOSUPPORT;
id_priv = container_of(id, struct rdma_id_private, id);
- if (!cma_comp_exch(id_priv, CMA_IDLE, CMA_ADDR_BOUND))
+ if (!cma_comp_exch(id_priv, RDMA_CM_IDLE, RDMA_CM_ADDR_BOUND))
return -EINVAL;
ret = cma_check_linklocal(&id->route.addr.dev_addr, addr);
@@ -2289,7 +2350,7 @@ err2:
if (id_priv->cma_dev)
cma_release_dev(id_priv);
err1:
- cma_comp_exch(id_priv, CMA_ADDR_BOUND, CMA_IDLE);
+ cma_comp_exch(id_priv, RDMA_CM_ADDR_BOUND, RDMA_CM_IDLE);
return ret;
}
EXPORT_SYMBOL(rdma_bind_addr);
@@ -2362,7 +2423,7 @@ static int cma_sidr_rep_handler(struct ib_cm_id *cm_id,
struct ib_cm_sidr_rep_event_param *rep = &ib_event->param.sidr_rep_rcvd;
int ret = 0;
- if (cma_disable_callback(id_priv, CMA_CONNECT))
+ if (cma_disable_callback(id_priv, RDMA_CM_CONNECT))
return 0;
memset(&event, 0, sizeof event);
@@ -2408,7 +2469,7 @@ static int cma_sidr_rep_handler(struct ib_cm_id *cm_id,
if (ret) {
/* Destroy the CM ID by returning a non-zero value. */
id_priv->cm_id.ib = NULL;
- cma_exch(id_priv, CMA_DESTROYING);
+ cma_exch(id_priv, RDMA_CM_DESTROYING);
mutex_unlock(&id_priv->handler_mutex);
rdma_destroy_id(&id_priv->id);
return ret;
@@ -2574,7 +2635,7 @@ int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
int ret;
id_priv = container_of(id, struct rdma_id_private, id);
- if (!cma_comp_exch(id_priv, CMA_ROUTE_RESOLVED, CMA_CONNECT))
+ if (!cma_comp_exch(id_priv, RDMA_CM_ROUTE_RESOLVED, RDMA_CM_CONNECT))
return -EINVAL;
if (!id->qp) {
@@ -2584,7 +2645,7 @@ int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
switch (rdma_node_get_transport(id->device->node_type)) {
case RDMA_TRANSPORT_IB:
- if (cma_is_ud_ps(id->ps))
+ if (id->qp_type == IB_QPT_UD)
ret = cma_resolve_ib_udp(id_priv, conn_param);
else
ret = cma_connect_ib(id_priv, conn_param);
@@ -2601,7 +2662,7 @@ int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
return 0;
err:
- cma_comp_exch(id_priv, CMA_CONNECT, CMA_ROUTE_RESOLVED);
+ cma_comp_exch(id_priv, RDMA_CM_CONNECT, RDMA_CM_ROUTE_RESOLVED);
return ret;
}
EXPORT_SYMBOL(rdma_connect);
@@ -2687,7 +2748,10 @@ int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
int ret;
id_priv = container_of(id, struct rdma_id_private, id);
- if (!cma_comp(id_priv, CMA_CONNECT))
+
+ id_priv->owner = task_pid_nr(current);
+
+ if (!cma_comp(id_priv, RDMA_CM_CONNECT))
return -EINVAL;
if (!id->qp && conn_param) {
@@ -2697,7 +2761,7 @@ int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
switch (rdma_node_get_transport(id->device->node_type)) {
case RDMA_TRANSPORT_IB:
- if (cma_is_ud_ps(id->ps))
+ if (id->qp_type == IB_QPT_UD)
ret = cma_send_sidr_rep(id_priv, IB_SIDR_SUCCESS,
conn_param->private_data,
conn_param->private_data_len);
@@ -2758,7 +2822,7 @@ int rdma_reject(struct rdma_cm_id *id, const void *private_data,
switch (rdma_node_get_transport(id->device->node_type)) {
case RDMA_TRANSPORT_IB:
- if (cma_is_ud_ps(id->ps))
+ if (id->qp_type == IB_QPT_UD)
ret = cma_send_sidr_rep(id_priv, IB_SIDR_REJECT,
private_data, private_data_len);
else
@@ -2816,8 +2880,8 @@ static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast)
int ret;
id_priv = mc->id_priv;
- if (cma_disable_callback(id_priv, CMA_ADDR_BOUND) &&
- cma_disable_callback(id_priv, CMA_ADDR_RESOLVED))
+ if (cma_disable_callback(id_priv, RDMA_CM_ADDR_BOUND) &&
+ cma_disable_callback(id_priv, RDMA_CM_ADDR_RESOLVED))
return 0;
mutex_lock(&id_priv->qp_mutex);
@@ -2841,7 +2905,7 @@ static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast)
ret = id_priv->id.event_handler(&id_priv->id, &event);
if (ret) {
- cma_exch(id_priv, CMA_DESTROYING);
+ cma_exch(id_priv, RDMA_CM_DESTROYING);
mutex_unlock(&id_priv->handler_mutex);
rdma_destroy_id(&id_priv->id);
return 0;
@@ -3024,8 +3088,8 @@ int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
int ret;
id_priv = container_of(id, struct rdma_id_private, id);
- if (!cma_comp(id_priv, CMA_ADDR_BOUND) &&
- !cma_comp(id_priv, CMA_ADDR_RESOLVED))
+ if (!cma_comp(id_priv, RDMA_CM_ADDR_BOUND) &&
+ !cma_comp(id_priv, RDMA_CM_ADDR_RESOLVED))
return -EINVAL;
mc = kmalloc(sizeof *mc, GFP_KERNEL);
@@ -3190,19 +3254,19 @@ static void cma_add_one(struct ib_device *device)
static int cma_remove_id_dev(struct rdma_id_private *id_priv)
{
struct rdma_cm_event event;
- enum cma_state state;
+ enum rdma_cm_state state;
int ret = 0;
/* Record that we want to remove the device */
- state = cma_exch(id_priv, CMA_DEVICE_REMOVAL);
- if (state == CMA_DESTROYING)
+ state = cma_exch(id_priv, RDMA_CM_DEVICE_REMOVAL);
+ if (state == RDMA_CM_DESTROYING)
return 0;
cma_cancel_operation(id_priv, state);
mutex_lock(&id_priv->handler_mutex);
/* Check for destruction from another callback. */
- if (!cma_comp(id_priv, CMA_DEVICE_REMOVAL))
+ if (!cma_comp(id_priv, RDMA_CM_DEVICE_REMOVAL))
goto out;
memset(&event, 0, sizeof event);
@@ -3257,6 +3321,100 @@ static void cma_remove_one(struct ib_device *device)
kfree(cma_dev);
}
+static int cma_get_id_stats(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ struct nlmsghdr *nlh;
+ struct rdma_cm_id_stats *id_stats;
+ struct rdma_id_private *id_priv;
+ struct rdma_cm_id *id = NULL;
+ struct cma_device *cma_dev;
+ int i_dev = 0, i_id = 0;
+
+ /*
+ * We export all of the IDs as a sequence of messages. Each
+ * ID gets its own netlink message.
+ */
+ mutex_lock(&lock);
+
+ list_for_each_entry(cma_dev, &dev_list, list) {
+ if (i_dev < cb->args[0]) {
+ i_dev++;
+ continue;
+ }
+
+ i_id = 0;
+ list_for_each_entry(id_priv, &cma_dev->id_list, list) {
+ if (i_id < cb->args[1]) {
+ i_id++;
+ continue;
+ }
+
+ id_stats = ibnl_put_msg(skb, &nlh, cb->nlh->nlmsg_seq,
+ sizeof *id_stats, RDMA_NL_RDMA_CM,
+ RDMA_NL_RDMA_CM_ID_STATS);
+ if (!id_stats)
+ goto out;
+
+ memset(id_stats, 0, sizeof *id_stats);
+ id = &id_priv->id;
+ id_stats->node_type = id->route.addr.dev_addr.dev_type;
+ id_stats->port_num = id->port_num;
+ id_stats->bound_dev_if =
+ id->route.addr.dev_addr.bound_dev_if;
+
+ if (id->route.addr.src_addr.ss_family == AF_INET) {
+ if (ibnl_put_attr(skb, nlh,
+ sizeof(struct sockaddr_in),
+ &id->route.addr.src_addr,
+ RDMA_NL_RDMA_CM_ATTR_SRC_ADDR)) {
+ goto out;
+ }
+ if (ibnl_put_attr(skb, nlh,
+ sizeof(struct sockaddr_in),
+ &id->route.addr.dst_addr,
+ RDMA_NL_RDMA_CM_ATTR_DST_ADDR)) {
+ goto out;
+ }
+ } else if (id->route.addr.src_addr.ss_family == AF_INET6) {
+ if (ibnl_put_attr(skb, nlh,
+ sizeof(struct sockaddr_in6),
+ &id->route.addr.src_addr,
+ RDMA_NL_RDMA_CM_ATTR_SRC_ADDR)) {
+ goto out;
+ }
+ if (ibnl_put_attr(skb, nlh,
+ sizeof(struct sockaddr_in6),
+ &id->route.addr.dst_addr,
+ RDMA_NL_RDMA_CM_ATTR_DST_ADDR)) {
+ goto out;
+ }
+ }
+
+ id_stats->pid = id_priv->owner;
+ id_stats->port_space = id->ps;
+ id_stats->cm_state = id_priv->state;
+ id_stats->qp_num = id_priv->qp_num;
+ id_stats->qp_type = id->qp_type;
+
+ i_id++;
+ }
+
+ cb->args[1] = 0;
+ i_dev++;
+ }
+
+out:
+ mutex_unlock(&lock);
+ cb->args[0] = i_dev;
+ cb->args[1] = i_id;
+
+ return skb->len;
+}
+
+static const struct ibnl_client_cbs cma_cb_table[] = {
+ [RDMA_NL_RDMA_CM_ID_STATS] = { .dump = cma_get_id_stats },
+};
+
static int __init cma_init(void)
{
int ret;
@@ -3272,6 +3430,10 @@ static int __init cma_init(void)
ret = ib_register_client(&cma_client);
if (ret)
goto err;
+
+ if (ibnl_add_client(RDMA_NL_RDMA_CM, RDMA_NL_RDMA_CM_NUM_OPS, cma_cb_table))
+ printk(KERN_WARNING "RDMA CMA: failed to add netlink callback\n");
+
return 0;
err:
@@ -3284,6 +3446,7 @@ err:
static void __exit cma_cleanup(void)
{
+ ibnl_remove_client(RDMA_NL_RDMA_CM);
ib_unregister_client(&cma_client);
unregister_netdevice_notifier(&cma_nb);
rdma_addr_unregister_client(&addr_client);
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
index f793bf2f5da7..4007f721d25d 100644
--- a/drivers/infiniband/core/device.c
+++ b/drivers/infiniband/core/device.c
@@ -38,6 +38,7 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/mutex.h>
+#include <rdma/rdma_netlink.h>
#include "core_priv.h"
@@ -725,22 +726,40 @@ static int __init ib_core_init(void)
return -ENOMEM;
ret = ib_sysfs_setup();
- if (ret)
+ if (ret) {
printk(KERN_WARNING "Couldn't create InfiniBand device class\n");
+ goto err;
+ }
+
+ ret = ibnl_init();
+ if (ret) {
+ printk(KERN_WARNING "Couldn't init IB netlink interface\n");
+ goto err_sysfs;
+ }
ret = ib_cache_setup();
if (ret) {
printk(KERN_WARNING "Couldn't set up InfiniBand P_Key/GID cache\n");
- ib_sysfs_cleanup();
- destroy_workqueue(ib_wq);
+ goto err_nl;
}
+ return 0;
+
+err_nl:
+ ibnl_cleanup();
+
+err_sysfs:
+ ib_sysfs_cleanup();
+
+err:
+ destroy_workqueue(ib_wq);
return ret;
}
static void __exit ib_core_cleanup(void)
{
ib_cache_cleanup();
+ ibnl_cleanup();
ib_sysfs_cleanup();
/* Make sure that any pending umem accounting work is done. */
destroy_workqueue(ib_wq);
diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c
index 2a1e9ae134b4..a9c042345c6f 100644
--- a/drivers/infiniband/core/iwcm.c
+++ b/drivers/infiniband/core/iwcm.c
@@ -725,7 +725,7 @@ static int cm_conn_rep_handler(struct iwcm_id_private *cm_id_priv,
*/
clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
BUG_ON(cm_id_priv->state != IW_CM_STATE_CONN_SENT);
- if (iw_event->status == IW_CM_EVENT_STATUS_ACCEPTED) {
+ if (iw_event->status == 0) {
cm_id_priv->id.local_addr = iw_event->local_addr;
cm_id_priv->id.remote_addr = iw_event->remote_addr;
cm_id_priv->state = IW_CM_STATE_ESTABLISHED;
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 822cfdcd9f78..b4d8672a3e4e 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -276,6 +276,13 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device,
goto error1;
}
+ /* Verify the QP requested is supported. For example, Ethernet devices
+ * will not have QP0 */
+ if (!port_priv->qp_info[qpn].qp) {
+ ret = ERR_PTR(-EPROTONOSUPPORT);
+ goto error1;
+ }
+
/* Allocate structures */
mad_agent_priv = kzalloc(sizeof *mad_agent_priv, GFP_KERNEL);
if (!mad_agent_priv) {
diff --git a/drivers/infiniband/core/netlink.c b/drivers/infiniband/core/netlink.c
new file mode 100644
index 000000000000..4a5abaf0a25c
--- /dev/null
+++ b/drivers/infiniband/core/netlink.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2010 Voltaire 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.
+ */
+
+#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
+
+#include <net/netlink.h>
+#include <net/net_namespace.h>
+#include <net/sock.h>
+#include <rdma/rdma_netlink.h>
+
+struct ibnl_client {
+ struct list_head list;
+ int index;
+ int nops;
+ const struct ibnl_client_cbs *cb_table;
+};
+
+static DEFINE_MUTEX(ibnl_mutex);
+static struct sock *nls;
+static LIST_HEAD(client_list);
+
+int ibnl_add_client(int index, int nops,
+ const struct ibnl_client_cbs cb_table[])
+{
+ struct ibnl_client *cur;
+ struct ibnl_client *nl_client;
+
+ nl_client = kmalloc(sizeof *nl_client, GFP_KERNEL);
+ if (!nl_client)
+ return -ENOMEM;
+
+ nl_client->index = index;
+ nl_client->nops = nops;
+ nl_client->cb_table = cb_table;
+
+ mutex_lock(&ibnl_mutex);
+
+ list_for_each_entry(cur, &client_list, list) {
+ if (cur->index == index) {
+ pr_warn("Client for %d already exists\n", index);
+ mutex_unlock(&ibnl_mutex);
+ kfree(nl_client);
+ return -EINVAL;
+ }
+ }
+
+ list_add_tail(&nl_client->list, &client_list);
+
+ mutex_unlock(&ibnl_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL(ibnl_add_client);
+
+int ibnl_remove_client(int index)
+{
+ struct ibnl_client *cur, *next;
+
+ mutex_lock(&ibnl_mutex);
+ list_for_each_entry_safe(cur, next, &client_list, list) {
+ if (cur->index == index) {
+ list_del(&(cur->list));
+ mutex_unlock(&ibnl_mutex);
+ kfree(cur);
+ return 0;
+ }
+ }
+ pr_warn("Can't remove callback for client idx %d. Not found\n", index);
+ mutex_unlock(&ibnl_mutex);
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(ibnl_remove_client);
+
+void *ibnl_put_msg(struct sk_buff *skb, struct nlmsghdr **nlh, int seq,
+ int len, int client, int op)
+{
+ unsigned char *prev_tail;
+
+ prev_tail = skb_tail_pointer(skb);
+ *nlh = NLMSG_NEW(skb, 0, seq, RDMA_NL_GET_TYPE(client, op),
+ len, NLM_F_MULTI);
+ (*nlh)->nlmsg_len = skb_tail_pointer(skb) - prev_tail;
+ return NLMSG_DATA(*nlh);
+
+nlmsg_failure:
+ nlmsg_trim(skb, prev_tail);
+ return NULL;
+}
+EXPORT_SYMBOL(ibnl_put_msg);
+
+int ibnl_put_attr(struct sk_buff *skb, struct nlmsghdr *nlh,
+ int len, void *data, int type)
+{
+ unsigned char *prev_tail;
+
+ prev_tail = skb_tail_pointer(skb);
+ NLA_PUT(skb, type, len, data);
+ nlh->nlmsg_len += skb_tail_pointer(skb) - prev_tail;
+ return 0;
+
+nla_put_failure:
+ nlmsg_trim(skb, prev_tail - nlh->nlmsg_len);
+ return -EMSGSIZE;
+}
+EXPORT_SYMBOL(ibnl_put_attr);
+
+static int ibnl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+{
+ struct ibnl_client *client;
+ int type = nlh->nlmsg_type;
+ int index = RDMA_NL_GET_CLIENT(type);
+ int op = RDMA_NL_GET_OP(type);
+
+ list_for_each_entry(client, &client_list, list) {
+ if (client->index == index) {
+ if (op < 0 || op >= client->nops ||
+ !client->cb_table[RDMA_NL_GET_OP(op)].dump)
+ return -EINVAL;
+ return netlink_dump_start(nls, skb, nlh,
+ client->cb_table[op].dump,
+ NULL);
+ }
+ }
+
+ pr_info("Index %d wasn't found in client list\n", index);
+ return -EINVAL;
+}
+
+static void ibnl_rcv(struct sk_buff *skb)
+{
+ mutex_lock(&ibnl_mutex);
+ netlink_rcv_skb(skb, &ibnl_rcv_msg);
+ mutex_unlock(&ibnl_mutex);
+}
+
+int __init ibnl_init(void)
+{
+ nls = netlink_kernel_create(&init_net, NETLINK_RDMA, 0, ibnl_rcv,
+ NULL, THIS_MODULE);
+ if (!nls) {
+ pr_warn("Failed to create netlink socket\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void ibnl_cleanup(void)
+{
+ struct ibnl_client *cur, *next;
+
+ mutex_lock(&ibnl_mutex);
+ list_for_each_entry_safe(cur, next, &client_list, list) {
+ list_del(&(cur->list));
+ kfree(cur);
+ }
+ mutex_unlock(&ibnl_mutex);
+
+ netlink_kernel_release(nls);
+}
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index ec1e9da1488b..71be5eebd683 100644
--- a/drivers/infiniband/core/ucma.c
+++ b/drivers/infiniband/core/ucma.c
@@ -367,13 +367,28 @@ done:
return ret;
}
-static ssize_t ucma_create_id(struct ucma_file *file,
- const char __user *inbuf,
- int in_len, int out_len)
+static int ucma_get_qp_type(struct rdma_ucm_create_id *cmd, enum ib_qp_type *qp_type)
+{
+ switch (cmd->ps) {
+ case RDMA_PS_TCP:
+ *qp_type = IB_QPT_RC;
+ return 0;
+ case RDMA_PS_UDP:
+ case RDMA_PS_IPOIB:
+ *qp_type = IB_QPT_UD;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static ssize_t ucma_create_id(struct ucma_file *file, const char __user *inbuf,
+ int in_len, int out_len)
{
struct rdma_ucm_create_id cmd;
struct rdma_ucm_create_id_resp resp;
struct ucma_context *ctx;
+ enum ib_qp_type qp_type;
int ret;
if (out_len < sizeof(resp))
@@ -382,6 +397,10 @@ static ssize_t ucma_create_id(struct ucma_file *file,
if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
return -EFAULT;
+ ret = ucma_get_qp_type(&cmd, &qp_type);
+ if (ret)
+ return ret;
+
mutex_lock(&file->mut);
ctx = ucma_alloc_ctx(file);
mutex_unlock(&file->mut);
@@ -389,7 +408,7 @@ static ssize_t ucma_create_id(struct ucma_file *file,
return -ENOMEM;
ctx->uid = cmd.uid;
- ctx->cm_id = rdma_create_id(ucma_event_handler, ctx, cmd.ps);
+ ctx->cm_id = rdma_create_id(ucma_event_handler, ctx, cmd.ps, qp_type);
if (IS_ERR(ctx->cm_id)) {
ret = PTR_ERR(ctx->cm_id);
goto err1;
@@ -883,6 +902,13 @@ static int ucma_set_option_id(struct ucma_context *ctx, int optname,
}
rdma_set_service_type(ctx->cm_id, *((u8 *) optval));
break;
+ case RDMA_OPTION_ID_REUSEADDR:
+ if (optlen != sizeof(int)) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = rdma_set_reuseaddr(ctx->cm_id, *((int *) optval) ? 1 : 0);
+ break;
default:
ret = -ENOSYS;
}
@@ -1331,9 +1357,11 @@ static const struct file_operations ucma_fops = {
};
static struct miscdevice ucma_misc = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "rdma_cm",
- .fops = &ucma_fops,
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "rdma_cm",
+ .nodename = "infiniband/rdma_cm",
+ .mode = 0666,
+ .fops = &ucma_fops,
};
static ssize_t show_abi_version(struct device *dev,
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index cd1996d0ad08..8d261b6ea5fe 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -1176,6 +1176,11 @@ static void ib_umad_remove_one(struct ib_device *device)
kref_put(&umad_dev->ref, ib_umad_release_dev);
}
+static char *umad_devnode(struct device *dev, mode_t *mode)
+{
+ return kasprintf(GFP_KERNEL, "infiniband/%s", dev_name(dev));
+}
+
static int __init ib_umad_init(void)
{
int ret;
@@ -1194,6 +1199,8 @@ static int __init ib_umad_init(void)
goto out_chrdev;
}
+ umad_class->devnode = umad_devnode;
+
ret = class_create_file(umad_class, &class_attr_abi_version.attr);
if (ret) {
printk(KERN_ERR "user_mad: couldn't create abi_version attribute\n");
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index ec83e9fe387b..e49a85f8a44d 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -824,6 +824,12 @@ static void ib_uverbs_remove_one(struct ib_device *device)
kfree(uverbs_dev);
}
+static char *uverbs_devnode(struct device *dev, mode_t *mode)
+{
+ *mode = 0666;
+ return kasprintf(GFP_KERNEL, "infiniband/%s", dev_name(dev));
+}
+
static int __init ib_uverbs_init(void)
{
int ret;
@@ -842,6 +848,8 @@ static int __init ib_uverbs_init(void)
goto out_chrdev;
}
+ uverbs_class->devnode = uverbs_devnode;
+
ret = class_create_file(uverbs_class, &class_attr_abi_version.attr);
if (ret) {
printk(KERN_ERR "user_verbs: couldn't create abi_version attribute\n");
diff --git a/drivers/infiniband/hw/amso1100/c2.c b/drivers/infiniband/hw/amso1100/c2.c
index dc85d777578e..0cfc455630d0 100644
--- a/drivers/infiniband/hw/amso1100/c2.c
+++ b/drivers/infiniband/hw/amso1100/c2.c
@@ -47,6 +47,7 @@
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
+#include <linux/prefetch.h>
#include <asm/io.h>
#include <asm/irq.h>
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index 3216bcad7e82..0a5008fbebac 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -338,8 +338,9 @@ static struct rtable *find_route(struct t3cdev *dev, __be32 local_ip,
__be16 peer_port, u8 tos)
{
struct rtable *rt;
+ struct flowi4 fl4;
- rt = ip_route_output_ports(&init_net, NULL, peer_ip, local_ip,
+ rt = ip_route_output_ports(&init_net, &fl4, NULL, peer_ip, local_ip,
peer_port, local_port, IPPROTO_TCP,
tos, 0);
if (IS_ERR(rt))
@@ -913,7 +914,7 @@ static void process_mpa_reply(struct iwch_ep *ep, struct sk_buff *skb)
goto err;
if (peer2peer && iwch_rqes_posted(ep->com.qp) == 0) {
- iwch_post_zb_read(ep->com.qp);
+ iwch_post_zb_read(ep);
}
goto out;
@@ -1077,6 +1078,8 @@ static int tx_ack(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
struct iwch_ep *ep = ctx;
struct cpl_wr_ack *hdr = cplhdr(skb);
unsigned int credits = ntohs(hdr->credits);
+ unsigned long flags;
+ int post_zb = 0;
PDBG("%s ep %p credits %u\n", __func__, ep, credits);
@@ -1086,28 +1089,34 @@ static int tx_ack(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
return CPL_RET_BUF_DONE;
}
+ spin_lock_irqsave(&ep->com.lock, flags);
BUG_ON(credits != 1);
dst_confirm(ep->dst);
if (!ep->mpa_skb) {
PDBG("%s rdma_init wr_ack ep %p state %u\n",
- __func__, ep, state_read(&ep->com));
+ __func__, ep, ep->com.state);
if (ep->mpa_attr.initiator) {
PDBG("%s initiator ep %p state %u\n",
- __func__, ep, state_read(&ep->com));
- if (peer2peer)
- iwch_post_zb_read(ep->com.qp);
+ __func__, ep, ep->com.state);
+ if (peer2peer && ep->com.state == FPDU_MODE)
+ post_zb = 1;
} else {
PDBG("%s responder ep %p state %u\n",
- __func__, ep, state_read(&ep->com));
- ep->com.rpl_done = 1;
- wake_up(&ep->com.waitq);
+ __func__, ep, ep->com.state);
+ if (ep->com.state == MPA_REQ_RCVD) {
+ ep->com.rpl_done = 1;
+ wake_up(&ep->com.waitq);
+ }
}
} else {
PDBG("%s lsm ack ep %p state %u freeing skb\n",
- __func__, ep, state_read(&ep->com));
+ __func__, ep, ep->com.state);
kfree_skb(ep->mpa_skb);
ep->mpa_skb = NULL;
}
+ spin_unlock_irqrestore(&ep->com.lock, flags);
+ if (post_zb)
+ iwch_post_zb_read(ep);
return CPL_RET_BUF_DONE;
}
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.h b/drivers/infiniband/hw/cxgb3/iwch_provider.h
index c5406da3f4cd..9a342c9b220d 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.h
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.h
@@ -332,7 +332,7 @@ int iwch_bind_mw(struct ib_qp *qp,
struct ib_mw_bind *mw_bind);
int iwch_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc);
int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg);
-int iwch_post_zb_read(struct iwch_qp *qhp);
+int iwch_post_zb_read(struct iwch_ep *ep);
int iwch_register_device(struct iwch_dev *dev);
void iwch_unregister_device(struct iwch_dev *dev);
void stop_read_rep_timer(struct iwch_qp *qhp);
diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c
index 1b4cd09f74dc..ecd313f359a4 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_qp.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c
@@ -738,7 +738,7 @@ static inline void build_term_codes(struct respQ_msg_t *rsp_msg,
}
}
-int iwch_post_zb_read(struct iwch_qp *qhp)
+int iwch_post_zb_read(struct iwch_ep *ep)
{
union t3_wr *wqe;
struct sk_buff *skb;
@@ -761,10 +761,10 @@ int iwch_post_zb_read(struct iwch_qp *qhp)
wqe->read.local_len = cpu_to_be32(0);
wqe->read.local_to = cpu_to_be64(1);
wqe->send.wrh.op_seop_flags = cpu_to_be32(V_FW_RIWR_OP(T3_WR_READ));
- wqe->send.wrh.gen_tid_len = cpu_to_be32(V_FW_RIWR_TID(qhp->ep->hwtid)|
+ wqe->send.wrh.gen_tid_len = cpu_to_be32(V_FW_RIWR_TID(ep->hwtid)|
V_FW_RIWR_LEN(flit_cnt));
skb->priority = CPL_PRIORITY_DATA;
- return iwch_cxgb3_ofld_send(qhp->rhp->rdev.t3cdev_p, skb);
+ return iwch_cxgb3_ofld_send(ep->com.qp->rhp->rdev.t3cdev_p, skb);
}
/*
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
index 9d8dcfab2b38..f660cd04ec2f 100644
--- a/drivers/infiniband/hw/cxgb4/cm.c
+++ b/drivers/infiniband/hw/cxgb4/cm.c
@@ -315,8 +315,9 @@ static struct rtable *find_route(struct c4iw_dev *dev, __be32 local_ip,
__be16 peer_port, u8 tos)
{
struct rtable *rt;
+ struct flowi4 fl4;
- rt = ip_route_output_ports(&init_net, NULL, peer_ip, local_ip,
+ rt = ip_route_output_ports(&init_net, &fl4, NULL, peer_ip, local_ip,
peer_port, local_port, IPPROTO_TCP,
tos, 0);
if (IS_ERR(rt))
@@ -1198,9 +1199,7 @@ static int pass_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
}
PDBG("%s ep %p status %d error %d\n", __func__, ep,
rpl->status, status2errno(rpl->status));
- ep->com.wr_wait.ret = status2errno(rpl->status);
- ep->com.wr_wait.done = 1;
- wake_up(&ep->com.wr_wait.wait);
+ c4iw_wake_up(&ep->com.wr_wait, status2errno(rpl->status));
return 0;
}
@@ -1234,9 +1233,7 @@ static int close_listsrv_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
struct c4iw_listen_ep *ep = lookup_stid(t, stid);
PDBG("%s ep %p\n", __func__, ep);
- ep->com.wr_wait.ret = status2errno(rpl->status);
- ep->com.wr_wait.done = 1;
- wake_up(&ep->com.wr_wait.wait);
+ c4iw_wake_up(&ep->com.wr_wait, status2errno(rpl->status));
return 0;
}
@@ -1466,7 +1463,7 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
struct c4iw_qp_attributes attrs;
int disconnect = 1;
int release = 0;
- int closing = 0;
+ int abort = 0;
struct tid_info *t = dev->rdev.lldi.tids;
unsigned int tid = GET_TID(hdr);
@@ -1492,23 +1489,22 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
* in rdma connection migration (see c4iw_accept_cr()).
*/
__state_set(&ep->com, CLOSING);
- ep->com.wr_wait.done = 1;
- ep->com.wr_wait.ret = -ECONNRESET;
PDBG("waking up ep %p tid %u\n", ep, ep->hwtid);
- wake_up(&ep->com.wr_wait.wait);
+ c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
break;
case MPA_REP_SENT:
__state_set(&ep->com, CLOSING);
- ep->com.wr_wait.done = 1;
- ep->com.wr_wait.ret = -ECONNRESET;
PDBG("waking up ep %p tid %u\n", ep, ep->hwtid);
- wake_up(&ep->com.wr_wait.wait);
+ c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
break;
case FPDU_MODE:
start_ep_timer(ep);
__state_set(&ep->com, CLOSING);
- closing = 1;
+ attrs.next_state = C4IW_QP_STATE_CLOSING;
+ abort = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
+ C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
peer_close_upcall(ep);
+ disconnect = 1;
break;
case ABORTING:
disconnect = 0;
@@ -1536,11 +1532,6 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
BUG_ON(1);
}
mutex_unlock(&ep->com.mutex);
- if (closing) {
- attrs.next_state = C4IW_QP_STATE_CLOSING;
- c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
- C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
- }
if (disconnect)
c4iw_ep_disconnect(ep, 0, GFP_KERNEL);
if (release)
@@ -1581,9 +1572,7 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
/*
* Wake up any threads in rdma_init() or rdma_fini().
*/
- ep->com.wr_wait.done = 1;
- ep->com.wr_wait.ret = -ECONNRESET;
- wake_up(&ep->com.wr_wait.wait);
+ c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
mutex_lock(&ep->com.mutex);
switch (ep->com.state) {
@@ -1710,14 +1699,14 @@ static int terminate(struct c4iw_dev *dev, struct sk_buff *skb)
ep = lookup_tid(t, tid);
BUG_ON(!ep);
- if (ep->com.qp) {
+ if (ep && ep->com.qp) {
printk(KERN_WARNING MOD "TERM received tid %u qpid %u\n", tid,
ep->com.qp->wq.sq.qid);
attrs.next_state = C4IW_QP_STATE_TERMINATE;
c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp,
C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
} else
- printk(KERN_WARNING MOD "TERM received tid %u no qp\n", tid);
+ printk(KERN_WARNING MOD "TERM received tid %u no ep/qp\n", tid);
return 0;
}
@@ -2296,14 +2285,8 @@ static int fw6_msg(struct c4iw_dev *dev, struct sk_buff *skb)
ret = (int)((be64_to_cpu(rpl->data[0]) >> 8) & 0xff);
wr_waitp = (struct c4iw_wr_wait *)(__force unsigned long) rpl->data[1];
PDBG("%s wr_waitp %p ret %u\n", __func__, wr_waitp, ret);
- if (wr_waitp) {
- if (ret)
- wr_waitp->ret = -ret;
- else
- wr_waitp->ret = 0;
- wr_waitp->done = 1;
- wake_up(&wr_waitp->wait);
- }
+ if (wr_waitp)
+ c4iw_wake_up(wr_waitp, ret ? -ret : 0);
kfree_skb(skb);
break;
case 2:
diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c
index e29172c2afcb..40a13cc633a3 100644
--- a/drivers/infiniband/hw/cxgb4/device.c
+++ b/drivers/infiniband/hw/cxgb4/device.c
@@ -44,7 +44,7 @@ MODULE_DESCRIPTION("Chelsio T4 RDMA Driver");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(DRV_VERSION);
-static LIST_HEAD(dev_list);
+static LIST_HEAD(uld_ctx_list);
static DEFINE_MUTEX(dev_mutex);
static struct dentry *c4iw_debugfs_root;
@@ -370,18 +370,23 @@ static void c4iw_rdev_close(struct c4iw_rdev *rdev)
c4iw_destroy_resource(&rdev->resource);
}
-static void c4iw_remove(struct c4iw_dev *dev)
+struct uld_ctx {
+ struct list_head entry;
+ struct cxgb4_lld_info lldi;
+ struct c4iw_dev *dev;
+};
+
+static void c4iw_remove(struct uld_ctx *ctx)
{
- PDBG("%s c4iw_dev %p\n", __func__, dev);
- list_del(&dev->entry);
- if (dev->registered)
- c4iw_unregister_device(dev);
- c4iw_rdev_close(&dev->rdev);
- idr_destroy(&dev->cqidr);
- idr_destroy(&dev->qpidr);
- idr_destroy(&dev->mmidr);
- iounmap(dev->rdev.oc_mw_kva);
- ib_dealloc_device(&dev->ibdev);
+ PDBG("%s c4iw_dev %p\n", __func__, ctx->dev);
+ c4iw_unregister_device(ctx->dev);
+ c4iw_rdev_close(&ctx->dev->rdev);
+ idr_destroy(&ctx->dev->cqidr);
+ idr_destroy(&ctx->dev->qpidr);
+ idr_destroy(&ctx->dev->mmidr);
+ iounmap(ctx->dev->rdev.oc_mw_kva);
+ ib_dealloc_device(&ctx->dev->ibdev);
+ ctx->dev = NULL;
}
static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
@@ -392,7 +397,7 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
devp = (struct c4iw_dev *)ib_alloc_device(sizeof(*devp));
if (!devp) {
printk(KERN_ERR MOD "Cannot allocate ib device\n");
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
devp->rdev.lldi = *infop;
@@ -402,27 +407,23 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
devp->rdev.oc_mw_kva = ioremap_wc(devp->rdev.oc_mw_pa,
devp->rdev.lldi.vr->ocq.size);
- printk(KERN_INFO MOD "ocq memory: "
+ PDBG(KERN_INFO MOD "ocq memory: "
"hw_start 0x%x size %u mw_pa 0x%lx mw_kva %p\n",
devp->rdev.lldi.vr->ocq.start, devp->rdev.lldi.vr->ocq.size,
devp->rdev.oc_mw_pa, devp->rdev.oc_mw_kva);
- mutex_lock(&dev_mutex);
-
ret = c4iw_rdev_open(&devp->rdev);
if (ret) {
mutex_unlock(&dev_mutex);
printk(KERN_ERR MOD "Unable to open CXIO rdev err %d\n", ret);
ib_dealloc_device(&devp->ibdev);
- return NULL;
+ return ERR_PTR(ret);
}
idr_init(&devp->cqidr);
idr_init(&devp->qpidr);
idr_init(&devp->mmidr);
spin_lock_init(&devp->lock);
- list_add_tail(&devp->entry, &dev_list);
- mutex_unlock(&dev_mutex);
if (c4iw_debugfs_root) {
devp->debugfs_root = debugfs_create_dir(
@@ -435,7 +436,7 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
static void *c4iw_uld_add(const struct cxgb4_lld_info *infop)
{
- struct c4iw_dev *dev;
+ struct uld_ctx *ctx;
static int vers_printed;
int i;
@@ -443,25 +444,33 @@ static void *c4iw_uld_add(const struct cxgb4_lld_info *infop)
printk(KERN_INFO MOD "Chelsio T4 RDMA Driver - version %s\n",
DRV_VERSION);
- dev = c4iw_alloc(infop);
- if (!dev)
+ ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+ if (!ctx) {
+ ctx = ERR_PTR(-ENOMEM);
goto out;
+ }
+ ctx->lldi = *infop;
PDBG("%s found device %s nchan %u nrxq %u ntxq %u nports %u\n",
- __func__, pci_name(dev->rdev.lldi.pdev),
- dev->rdev.lldi.nchan, dev->rdev.lldi.nrxq,
- dev->rdev.lldi.ntxq, dev->rdev.lldi.nports);
+ __func__, pci_name(ctx->lldi.pdev),
+ ctx->lldi.nchan, ctx->lldi.nrxq,
+ ctx->lldi.ntxq, ctx->lldi.nports);
+
+ mutex_lock(&dev_mutex);
+ list_add_tail(&ctx->entry, &uld_ctx_list);
+ mutex_unlock(&dev_mutex);
- for (i = 0; i < dev->rdev.lldi.nrxq; i++)
- PDBG("rxqid[%u] %u\n", i, dev->rdev.lldi.rxq_ids[i]);
+ for (i = 0; i < ctx->lldi.nrxq; i++)
+ PDBG("rxqid[%u] %u\n", i, ctx->lldi.rxq_ids[i]);
out:
- return dev;
+ return ctx;
}
static int c4iw_uld_rx_handler(void *handle, const __be64 *rsp,
const struct pkt_gl *gl)
{
- struct c4iw_dev *dev = handle;
+ struct uld_ctx *ctx = handle;
+ struct c4iw_dev *dev = ctx->dev;
struct sk_buff *skb;
const struct cpl_act_establish *rpl;
unsigned int opcode;
@@ -503,47 +512,49 @@ nomem:
static int c4iw_uld_state_change(void *handle, enum cxgb4_state new_state)
{
- struct c4iw_dev *dev = handle;
+ struct uld_ctx *ctx = handle;
PDBG("%s new_state %u\n", __func__, new_state);
switch (new_state) {
case CXGB4_STATE_UP:
- printk(KERN_INFO MOD "%s: Up\n", pci_name(dev->rdev.lldi.pdev));
- if (!dev->registered) {
- int ret;
- ret = c4iw_register_device(dev);
- if (ret)
+ printk(KERN_INFO MOD "%s: Up\n", pci_name(ctx->lldi.pdev));
+ if (!ctx->dev) {
+ int ret = 0;
+
+ ctx->dev = c4iw_alloc(&ctx->lldi);
+ if (!IS_ERR(ctx->dev))
+ ret = c4iw_register_device(ctx->dev);
+ if (IS_ERR(ctx->dev) || ret)
printk(KERN_ERR MOD
"%s: RDMA registration failed: %d\n",
- pci_name(dev->rdev.lldi.pdev), ret);
+ pci_name(ctx->lldi.pdev), ret);
}
break;
case CXGB4_STATE_DOWN:
printk(KERN_INFO MOD "%s: Down\n",
- pci_name(dev->rdev.lldi.pdev));
- if (dev->registered)
- c4iw_unregister_device(dev);
+ pci_name(ctx->lldi.pdev));
+ if (ctx->dev)
+ c4iw_remove(ctx);
break;
case CXGB4_STATE_START_RECOVERY:
printk(KERN_INFO MOD "%s: Fatal Error\n",
- pci_name(dev->rdev.lldi.pdev));
- dev->rdev.flags |= T4_FATAL_ERROR;
- if (dev->registered) {
+ pci_name(ctx->lldi.pdev));
+ if (ctx->dev) {
struct ib_event event;
+ ctx->dev->rdev.flags |= T4_FATAL_ERROR;
memset(&event, 0, sizeof event);
event.event = IB_EVENT_DEVICE_FATAL;
- event.device = &dev->ibdev;
+ event.device = &ctx->dev->ibdev;
ib_dispatch_event(&event);
- c4iw_unregister_device(dev);
+ c4iw_remove(ctx);
}
break;
case CXGB4_STATE_DETACH:
printk(KERN_INFO MOD "%s: Detach\n",
- pci_name(dev->rdev.lldi.pdev));
- mutex_lock(&dev_mutex);
- c4iw_remove(dev);
- mutex_unlock(&dev_mutex);
+ pci_name(ctx->lldi.pdev));
+ if (ctx->dev)
+ c4iw_remove(ctx);
break;
}
return 0;
@@ -576,11 +587,13 @@ static int __init c4iw_init_module(void)
static void __exit c4iw_exit_module(void)
{
- struct c4iw_dev *dev, *tmp;
+ struct uld_ctx *ctx, *tmp;
mutex_lock(&dev_mutex);
- list_for_each_entry_safe(dev, tmp, &dev_list, entry) {
- c4iw_remove(dev);
+ list_for_each_entry_safe(ctx, tmp, &uld_ctx_list, entry) {
+ if (ctx->dev)
+ c4iw_remove(ctx);
+ kfree(ctx);
}
mutex_unlock(&dev_mutex);
cxgb4_unregister_uld(CXGB4_ULD_RDMA);
diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
index 9f6166f59268..4f045375c8e2 100644
--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
@@ -35,7 +35,7 @@
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/idr.h>
-#include <linux/workqueue.h>
+#include <linux/completion.h>
#include <linux/netdevice.h>
#include <linux/sched.h>
#include <linux/pci.h>
@@ -132,16 +132,20 @@ static inline int c4iw_num_stags(struct c4iw_rdev *rdev)
#define C4IW_WR_TO (10*HZ)
struct c4iw_wr_wait {
- wait_queue_head_t wait;
- int done;
+ struct completion completion;
int ret;
};
static inline void c4iw_init_wr_wait(struct c4iw_wr_wait *wr_waitp)
{
wr_waitp->ret = 0;
- wr_waitp->done = 0;
- init_waitqueue_head(&wr_waitp->wait);
+ init_completion(&wr_waitp->completion);
+}
+
+static inline void c4iw_wake_up(struct c4iw_wr_wait *wr_waitp, int ret)
+{
+ wr_waitp->ret = ret;
+ complete(&wr_waitp->completion);
}
static inline int c4iw_wait_for_reply(struct c4iw_rdev *rdev,
@@ -150,23 +154,27 @@ static inline int c4iw_wait_for_reply(struct c4iw_rdev *rdev,
const char *func)
{
unsigned to = C4IW_WR_TO;
- do {
+ int ret;
- wait_event_timeout(wr_waitp->wait, wr_waitp->done, to);
- if (!wr_waitp->done) {
+ do {
+ ret = wait_for_completion_timeout(&wr_waitp->completion, to);
+ if (!ret) {
printk(KERN_ERR MOD "%s - Device %s not responding - "
"tid %u qpid %u\n", func,
pci_name(rdev->lldi.pdev), hwtid, qpid);
+ if (c4iw_fatal_error(rdev)) {
+ wr_waitp->ret = -EIO;
+ break;
+ }
to = to << 2;
}
- } while (!wr_waitp->done);
+ } while (!ret);
if (wr_waitp->ret)
- printk(KERN_WARNING MOD "%s: FW reply %d tid %u qpid %u\n",
- pci_name(rdev->lldi.pdev), wr_waitp->ret, hwtid, qpid);
+ PDBG("%s: FW reply %d tid %u qpid %u\n",
+ pci_name(rdev->lldi.pdev), wr_waitp->ret, hwtid, qpid);
return wr_waitp->ret;
}
-
struct c4iw_dev {
struct ib_device ibdev;
struct c4iw_rdev rdev;
@@ -175,9 +183,7 @@ struct c4iw_dev {
struct idr qpidr;
struct idr mmidr;
spinlock_t lock;
- struct list_head entry;
struct dentry *debugfs_root;
- u8 registered;
};
static inline struct c4iw_dev *to_c4iw_dev(struct ib_device *ibdev)
diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c
index f66dd8bf5128..5b9e4220ca08 100644
--- a/drivers/infiniband/hw/cxgb4/provider.c
+++ b/drivers/infiniband/hw/cxgb4/provider.c
@@ -516,7 +516,6 @@ int c4iw_register_device(struct c4iw_dev *dev)
if (ret)
goto bail2;
}
- dev->registered = 1;
return 0;
bail2:
ib_unregister_device(&dev->ibdev);
@@ -535,6 +534,5 @@ void c4iw_unregister_device(struct c4iw_dev *dev)
c4iw_class_attributes[i]);
ib_unregister_device(&dev->ibdev);
kfree(dev->ibdev.iwcm);
- dev->registered = 0;
return;
}
diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c
index 70a5a3c646da..3b773b05a898 100644
--- a/drivers/infiniband/hw/cxgb4/qp.c
+++ b/drivers/infiniband/hw/cxgb4/qp.c
@@ -214,7 +214,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
V_FW_RI_RES_WR_HOSTFCMODE(0) | /* no host cidx updates */
V_FW_RI_RES_WR_CPRIO(0) | /* don't keep in chip cache */
V_FW_RI_RES_WR_PCIECHN(0) | /* set by uP at ri_init time */
- t4_sq_onchip(&wq->sq) ? F_FW_RI_RES_WR_ONCHIP : 0 |
+ (t4_sq_onchip(&wq->sq) ? F_FW_RI_RES_WR_ONCHIP : 0) |
V_FW_RI_RES_WR_IQID(scq->cqid));
res->u.sqrq.dcaen_to_eqsize = cpu_to_be32(
V_FW_RI_RES_WR_DCAEN(0) |
@@ -1210,7 +1210,6 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
if (ret) {
if (internal)
c4iw_get_ep(&qhp->ep->com);
- disconnect = abort = 1;
goto err;
}
break;
diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h
index 24af12fc8228..c0221eec8817 100644
--- a/drivers/infiniband/hw/cxgb4/t4.h
+++ b/drivers/infiniband/hw/cxgb4/t4.h
@@ -269,11 +269,8 @@ struct t4_swsqe {
static inline pgprot_t t4_pgprot_wc(pgprot_t prot)
{
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(CONFIG_PPC64)
return pgprot_writecombine(prot);
-#elif defined(CONFIG_PPC64)
- return __pgprot((pgprot_val(prot) | _PAGE_NO_CACHE) &
- ~(pgprot_t)_PAGE_GUARDED);
#else
return pgprot_noncached(prot);
#endif
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index 58c0e417bc30..be24ac726114 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -398,7 +398,6 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
struct ipath_devdata *dd;
unsigned long long addr;
u32 bar0 = 0, bar1 = 0;
- u8 rev;
dd = ipath_alloc_devdata(pdev);
if (IS_ERR(dd)) {
@@ -540,13 +539,7 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
goto bail_regions;
}
- ret = pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
- if (ret) {
- ipath_dev_err(dd, "Failed to read PCI revision ID unit "
- "%u: err %d\n", dd->ipath_unit, -ret);
- goto bail_regions; /* shouldn't ever happen */
- }
- dd->ipath_pcirev = rev;
+ dd->ipath_pcirev = pdev->revision;
#if defined(__powerpc__)
/* There isn't a generic way to specify writethrough mappings */
diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c
index 13de1192927c..2d668c69f6d9 100644
--- a/drivers/infiniband/hw/nes/nes.c
+++ b/drivers/infiniband/hw/nes/nes.c
@@ -1138,7 +1138,9 @@ static ssize_t nes_store_wqm_quanta(struct device_driver *ddp,
u32 i = 0;
struct nes_device *nesdev;
- strict_strtoul(buf, 0, &wqm_quanta_value);
+ if (kstrtoul(buf, 0, &wqm_quanta_value) < 0)
+ return -EINVAL;
+
list_for_each_entry(nesdev, &nes_dev_list, list) {
if (i == ee_flsh_adapter) {
nesdev->nesadapter->wqm_quanta = wqm_quanta_value;
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index 33c7eedaba6c..e74cdf9ef471 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -2563,7 +2563,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_status disconn_status = IW_CM_EVENT_STATUS_OK;
+ int disconn_status = 0;
int issue_disconn = 0;
int issue_close = 0;
int issue_flush = 0;
@@ -2605,7 +2605,7 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)
(last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
issue_disconn = 1;
if (last_ae == NES_AEQE_AEID_LLP_CONNECTION_RESET)
- disconn_status = IW_CM_EVENT_STATUS_RESET;
+ disconn_status = -ECONNRESET;
}
if (((original_hw_tcp_state == NES_AEQE_TCP_STATE_CLOSED) ||
@@ -2666,7 +2666,7 @@ static int nes_cm_disconn_true(struct nes_qp *nesqp)
cm_id->provider_data = nesqp;
/* Send up the close complete event */
cm_event.event = IW_CM_EVENT_CLOSE;
- cm_event.status = IW_CM_EVENT_STATUS_OK;
+ cm_event.status = 0;
cm_event.provider_data = cm_id->provider_data;
cm_event.local_addr = cm_id->local_addr;
cm_event.remote_addr = cm_id->remote_addr;
@@ -2966,7 +2966,7 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
nes_add_ref(&nesqp->ibqp);
cm_event.event = IW_CM_EVENT_ESTABLISHED;
- cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED;
+ cm_event.status = 0;
cm_event.provider_data = (void *)nesqp;
cm_event.local_addr = cm_id->local_addr;
cm_event.remote_addr = cm_id->remote_addr;
@@ -3377,7 +3377,7 @@ static void cm_event_connected(struct nes_cm_event *event)
/* notify OF layer we successfully created the requested connection */
cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
- cm_event.status = IW_CM_EVENT_STATUS_ACCEPTED;
+ cm_event.status = 0;
cm_event.provider_data = cm_id->provider_data;
cm_event.local_addr.sin_family = AF_INET;
cm_event.local_addr.sin_port = cm_id->local_addr.sin_port;
@@ -3484,7 +3484,7 @@ static void cm_event_reset(struct nes_cm_event *event)
nesqp->cm_id = NULL;
/* cm_id->provider_data = NULL; */
cm_event.event = IW_CM_EVENT_DISCONNECT;
- cm_event.status = IW_CM_EVENT_STATUS_RESET;
+ cm_event.status = -ECONNRESET;
cm_event.provider_data = cm_id->provider_data;
cm_event.local_addr = cm_id->local_addr;
cm_event.remote_addr = cm_id->remote_addr;
@@ -3495,7 +3495,7 @@ static void cm_event_reset(struct nes_cm_event *event)
ret = cm_id->event_handler(cm_id, &cm_event);
atomic_inc(&cm_closes);
cm_event.event = IW_CM_EVENT_CLOSE;
- cm_event.status = IW_CM_EVENT_STATUS_OK;
+ cm_event.status = 0;
cm_event.provider_data = cm_id->provider_data;
cm_event.local_addr = cm_id->local_addr;
cm_event.remote_addr = cm_id->remote_addr;
@@ -3534,7 +3534,7 @@ static void cm_event_mpa_req(struct nes_cm_event *event)
cm_node, cm_id, jiffies);
cm_event.event = IW_CM_EVENT_CONNECT_REQUEST;
- cm_event.status = IW_CM_EVENT_STATUS_OK;
+ cm_event.status = 0;
cm_event.provider_data = (void *)cm_node;
cm_event.local_addr.sin_family = AF_INET;
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c
index 10d0a5ec9add..96fa9a4cafdf 100644
--- a/drivers/infiniband/hw/nes/nes_hw.c
+++ b/drivers/infiniband/hw/nes/nes_hw.c
@@ -2885,9 +2885,8 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
if ((cqe_errv &
(NES_NIC_ERRV_BITS_IPV4_CSUM_ERR | NES_NIC_ERRV_BITS_TCPUDP_CSUM_ERR |
NES_NIC_ERRV_BITS_IPH_ERR | NES_NIC_ERRV_BITS_WQE_OVERRUN)) == 0) {
- if (nesvnic->rx_checksum_disabled == 0) {
+ if (nesvnic->netdev->features & NETIF_F_RXCSUM)
rx_skb->ip_summed = CHECKSUM_UNNECESSARY;
- }
} else
nes_debug(NES_DBG_CQ, "%s: unsuccessfully checksummed TCP or UDP packet."
" errv = 0x%X, pkt_type = 0x%X.\n",
@@ -2897,7 +2896,7 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
if ((cqe_errv &
(NES_NIC_ERRV_BITS_IPV4_CSUM_ERR | NES_NIC_ERRV_BITS_IPH_ERR |
NES_NIC_ERRV_BITS_WQE_OVERRUN)) == 0) {
- if (nesvnic->rx_checksum_disabled == 0) {
+ if (nesvnic->netdev->features & NETIF_F_RXCSUM) {
rx_skb->ip_summed = CHECKSUM_UNNECESSARY;
/* nes_debug(NES_DBG_CQ, "%s: Reporting successfully checksummed IPv4 packet.\n",
nesvnic->netdev->name); */
diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h
index d2abe07133a5..91594116f947 100644
--- a/drivers/infiniband/hw/nes/nes_hw.h
+++ b/drivers/infiniband/hw/nes/nes_hw.h
@@ -1245,7 +1245,6 @@ struct nes_vnic {
u8 next_qp_nic_index;
u8 of_device_registered;
u8 rdma_enabled;
- u8 rx_checksum_disabled;
u32 lro_max_aggr;
struct net_lro_mgr lro_mgr;
struct net_lro_desc lro_desc[NES_MAX_LRO_DESCRIPTORS];
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index e96b8fb5d44c..d3a1c41cfd27 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -1093,34 +1093,6 @@ static const char nes_ethtool_stringset[][ETH_GSTRING_LEN] = {
};
#define NES_ETHTOOL_STAT_COUNT ARRAY_SIZE(nes_ethtool_stringset)
-/**
- * nes_netdev_get_rx_csum
- */
-static u32 nes_netdev_get_rx_csum (struct net_device *netdev)
-{
- struct nes_vnic *nesvnic = netdev_priv(netdev);
-
- if (nesvnic->rx_checksum_disabled)
- return 0;
- else
- return 1;
-}
-
-
-/**
- * nes_netdev_set_rc_csum
- */
-static int nes_netdev_set_rx_csum(struct net_device *netdev, u32 enable)
-{
- struct nes_vnic *nesvnic = netdev_priv(netdev);
-
- if (enable)
- nesvnic->rx_checksum_disabled = 0;
- else
- nesvnic->rx_checksum_disabled = 1;
- return 0;
-}
-
/**
* nes_netdev_get_sset_count
@@ -1521,7 +1493,7 @@ static int nes_netdev_get_settings(struct net_device *netdev, struct ethtool_cmd
et_cmd->maxrxpkt = 511;
if (nesadapter->OneG_Mode) {
- et_cmd->speed = SPEED_1000;
+ ethtool_cmd_speed_set(et_cmd, SPEED_1000);
if (phy_type == NES_PHY_TYPE_PUMA_1G) {
et_cmd->supported = SUPPORTED_1000baseT_Full;
et_cmd->advertising = ADVERTISED_1000baseT_Full;
@@ -1560,7 +1532,7 @@ static int nes_netdev_get_settings(struct net_device *netdev, struct ethtool_cmd
et_cmd->advertising = ADVERTISED_10000baseT_Full;
et_cmd->phy_address = mac_index;
}
- et_cmd->speed = SPEED_10000;
+ ethtool_cmd_speed_set(et_cmd, SPEED_10000);
et_cmd->autoneg = AUTONEG_DISABLE;
return 0;
}
@@ -1598,19 +1570,10 @@ 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,
.set_settings = nes_netdev_set_settings,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .get_rx_csum = nes_netdev_get_rx_csum,
- .get_sg = ethtool_op_get_sg,
.get_strings = nes_netdev_get_strings,
.get_sset_count = nes_netdev_get_sset_count,
.get_ethtool_stats = nes_netdev_get_ethtool_stats,
@@ -1619,13 +1582,6 @@ static const struct ethtool_ops nes_ethtool_ops = {
.set_coalesce = nes_netdev_set_coalesce,
.get_pauseparam = nes_netdev_get_pauseparam,
.set_pauseparam = nes_netdev_set_pauseparam,
- .set_tx_csum = ethtool_op_set_tx_csum,
- .set_rx_csum = nes_netdev_set_rx_csum,
- .set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
- .set_tso = ethtool_op_set_tso,
- .get_flags = ethtool_op_get_flags,
- .set_flags = nes_netdev_set_flags,
};
@@ -1727,12 +1683,11 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
netdev->dev_addr[5] = (u8)u64temp;
memcpy(netdev->perm_addr, netdev->dev_addr, 6);
- if ((nesvnic->logical_port < 2) || (nesdev->nesadapter->hw_rev != NE020_REV)) {
- netdev->features |= NETIF_F_TSO | NETIF_F_SG | NETIF_F_IP_CSUM;
- netdev->features |= NETIF_F_GSO | NETIF_F_TSO | NETIF_F_SG | NETIF_F_IP_CSUM;
- } else {
- netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
- }
+ netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_IP_CSUM;
+ if ((nesvnic->logical_port < 2) || (nesdev->nesadapter->hw_rev != NE020_REV))
+ netdev->hw_features |= NETIF_F_TSO;
+ netdev->features |= netdev->hw_features;
+ netdev->hw_features |= NETIF_F_LRO;
nes_debug(NES_DBG_INIT, "nesvnic = %p, reported features = 0x%lX, QPid = %d,"
" nic_index = %d, logical_port = %d, mac_index = %d.\n",
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c
index 26d8018c0a7c..95ca93ceedac 100644
--- a/drivers/infiniband/hw/nes/nes_verbs.c
+++ b/drivers/infiniband/hw/nes/nes_verbs.c
@@ -1484,7 +1484,7 @@ static int nes_destroy_qp(struct ib_qp *ibqp)
(nesqp->ibqp_state == IB_QPS_RTR)) && (nesqp->cm_id)) {
cm_id = nesqp->cm_id;
cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
- cm_event.status = IW_CM_EVENT_STATUS_TIMEOUT;
+ cm_event.status = -ETIMEDOUT;
cm_event.local_addr = cm_id->local_addr;
cm_event.remote_addr = cm_id->remote_addr;
cm_event.private_data = NULL;
diff --git a/drivers/infiniband/hw/qib/Kconfig b/drivers/infiniband/hw/qib/Kconfig
index 7c03a70c55a2..8349f9c5064c 100644
--- a/drivers/infiniband/hw/qib/Kconfig
+++ b/drivers/infiniband/hw/qib/Kconfig
@@ -1,6 +1,6 @@
config INFINIBAND_QIB
tristate "QLogic PCIe HCA support"
- depends on 64BIT && NET
+ depends on 64BIT
---help---
This is a low-level driver for QLogic PCIe QLE InfiniBand host
channel adapters. This driver does not support the QLogic
diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c
index 6bab3eaea70f..9f53e68a096a 100644
--- a/drivers/infiniband/hw/qib/qib_iba7322.c
+++ b/drivers/infiniband/hw/qib/qib_iba7322.c
@@ -7534,7 +7534,8 @@ static int serdes_7322_init_new(struct qib_pportdata *ppd)
ibsd_wr_allchans(ppd, 4, (1 << 10), BMASK(10, 10));
tstart = get_jiffies_64();
while (chan_done &&
- !time_after64(tstart, tstart + msecs_to_jiffies(500))) {
+ !time_after64(get_jiffies_64(),
+ tstart + msecs_to_jiffies(500))) {
msleep(20);
for (chan = 0; chan < SERDES_CHANS; ++chan) {
rxcaldone = ahb_mod(ppd->dd, IBSD(ppd->hw_pidx),
diff --git a/drivers/infiniband/hw/qib/qib_pcie.c b/drivers/infiniband/hw/qib/qib_pcie.c
index 48b6674cbc49..891cc2ff5f00 100644
--- a/drivers/infiniband/hw/qib/qib_pcie.c
+++ b/drivers/infiniband/hw/qib/qib_pcie.c
@@ -526,11 +526,8 @@ static int qib_tune_pcie_coalesce(struct qib_devdata *dd)
*/
devid = parent->device;
if (devid >= 0x25e2 && devid <= 0x25fa) {
- u8 rev;
-
/* 5000 P/V/X/Z */
- pci_read_config_byte(parent, PCI_REVISION_ID, &rev);
- if (rev <= 0xb2)
+ if (parent->revision <= 0xb2)
bits = 1U << 10;
else
bits = 7U << 10;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index ab97f92fc257..7b6985a2e652 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -91,7 +91,6 @@ enum {
IPOIB_STOP_REAPER = 7,
IPOIB_FLAG_ADMIN_CM = 9,
IPOIB_FLAG_UMCAST = 10,
- IPOIB_FLAG_CSUM = 11,
IPOIB_MAX_BACKOFF_SECONDS = 16,
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 93d55806b967..39913a065f99 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -1463,8 +1463,7 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr,
set_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags);
ipoib_warn(priv, "enabling connected mode "
"will cause multicast packet drops\n");
-
- dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO);
+ netdev_update_features(dev);
rtnl_unlock();
priv->tx_wr.send_flags &= ~IB_SEND_IP_CSUM;
@@ -1474,13 +1473,7 @@ static ssize_t set_mode(struct device *d, struct device_attribute *attr,
if (!strcmp(buf, "datagram\n")) {
clear_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags);
-
- if (test_bit(IPOIB_FLAG_CSUM, &priv->flags)) {
- dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
- priv->dev->features |= NETIF_F_GRO;
- if (priv->hca_caps & IB_DEVICE_UD_TSO)
- dev->features |= NETIF_F_TSO;
- }
+ netdev_update_features(dev);
dev_set_mtu(dev, min(priv->mcast_mtu, dev->mtu));
rtnl_unlock();
ipoib_flush_paths(dev);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
index 19f7f5206f78..29bc7b5724ac 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
@@ -42,32 +42,6 @@ static void ipoib_get_drvinfo(struct net_device *netdev,
strncpy(drvinfo->driver, "ipoib", sizeof(drvinfo->driver) - 1);
}
-static u32 ipoib_get_rx_csum(struct net_device *dev)
-{
- struct ipoib_dev_priv *priv = netdev_priv(dev);
- return test_bit(IPOIB_FLAG_CSUM, &priv->flags) &&
- !test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags);
-}
-
-static int ipoib_set_tso(struct net_device *dev, u32 data)
-{
- struct ipoib_dev_priv *priv = netdev_priv(dev);
-
- if (data) {
- if (!test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags) &&
- (dev->features & NETIF_F_SG) &&
- (priv->hca_caps & IB_DEVICE_UD_TSO)) {
- dev->features |= NETIF_F_TSO;
- } else {
- ipoib_warn(priv, "can't set TSO on\n");
- return -EOPNOTSUPP;
- }
- } else
- dev->features &= ~NETIF_F_TSO;
-
- return 0;
-}
-
static int ipoib_get_coalesce(struct net_device *dev,
struct ethtool_coalesce *coal)
{
@@ -108,8 +82,6 @@ static int ipoib_set_coalesce(struct net_device *dev,
static const struct ethtool_ops ipoib_ethtool_ops = {
.get_drvinfo = ipoib_get_drvinfo,
- .get_rx_csum = ipoib_get_rx_csum,
- .set_tso = ipoib_set_tso,
.get_coalesce = ipoib_get_coalesce,
.set_coalesce = ipoib_set_coalesce,
};
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index 806d0292dc39..81ae61d68a22 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -292,7 +292,7 @@ static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
dev->stats.rx_bytes += skb->len;
skb->dev = dev;
- if (test_bit(IPOIB_FLAG_CSUM, &priv->flags) && likely(wc->csum_ok))
+ if ((dev->features & NETIF_F_RXCSUM) && likely(wc->csum_ok))
skb->ip_summed = CHECKSUM_UNNECESSARY;
napi_gro_receive(&priv->napi, skb);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index aca3b44f7aed..86addca9ddf6 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -171,6 +171,16 @@ static int ipoib_stop(struct net_device *dev)
return 0;
}
+static u32 ipoib_fix_features(struct net_device *dev, u32 features)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+
+ if (test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags))
+ features &= ~(NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
+
+ return features;
+}
+
static int ipoib_change_mtu(struct net_device *dev, int new_mtu)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -970,6 +980,7 @@ static const struct net_device_ops ipoib_netdev_ops = {
.ndo_open = ipoib_open,
.ndo_stop = ipoib_stop,
.ndo_change_mtu = ipoib_change_mtu,
+ .ndo_fix_features = ipoib_fix_features,
.ndo_start_xmit = ipoib_start_xmit,
.ndo_tx_timeout = ipoib_timeout,
.ndo_set_multicast_list = ipoib_set_mcast_list,
@@ -1154,19 +1165,18 @@ int ipoib_set_dev_features(struct ipoib_dev_priv *priv, struct ib_device *hca)
kfree(device_attr);
if (priv->hca_caps & IB_DEVICE_UD_IP_CSUM) {
- set_bit(IPOIB_FLAG_CSUM, &priv->flags);
- priv->dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
- }
+ priv->dev->hw_features = NETIF_F_SG |
+ NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
- priv->dev->features |= NETIF_F_GRO;
+ if (priv->hca_caps & IB_DEVICE_UD_TSO)
+ priv->dev->hw_features |= NETIF_F_TSO;
- if (priv->dev->features & NETIF_F_SG && priv->hca_caps & IB_DEVICE_UD_TSO)
- priv->dev->features |= NETIF_F_TSO;
+ priv->dev->features |= priv->dev->hw_features;
+ }
return 0;
}
-
static struct net_device *ipoib_add_port(const char *format,
struct ib_device *hca, u8 port)
{
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index 9876865732f7..ede1475bee09 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -548,7 +548,7 @@ int iser_connect(struct iser_conn *ib_conn,
iser_conn_get(ib_conn); /* ref ib conn's cma id */
ib_conn->cma_id = rdma_create_id(iser_cma_handler,
(void *)ib_conn,
- RDMA_PS_TCP);
+ RDMA_PS_TCP, IB_QPT_RC);
if (IS_ERR(ib_conn->cma_id)) {
err = PTR_ERR(ib_conn->cma_id);
iser_err("rdma_create_id failed: %d\n", err);
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 376d640487d2..ee165fdcb596 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -1147,7 +1147,7 @@ static void srp_process_aer_req(struct srp_target_port *target,
static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
{
struct ib_device *dev = target->srp_host->srp_dev->dev;
- struct srp_iu *iu = (struct srp_iu *) wc->wr_id;
+ struct srp_iu *iu = (struct srp_iu *) (uintptr_t) wc->wr_id;
int res;
u8 opcode;
@@ -1231,7 +1231,7 @@ static void srp_send_completion(struct ib_cq *cq, void *target_ptr)
break;
}
- iu = (struct srp_iu *) wc.wr_id;
+ iu = (struct srp_iu *) (uintptr_t) wc.wr_id;
list_add(&iu->list, &target->free_tx);
}
}
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 88d8e4cb419a..be0921ef6b52 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -41,6 +41,7 @@ struct evdev {
struct evdev_client {
unsigned int head;
unsigned int tail;
+ unsigned int packet_head; /* [future] position of the first element of next packet */
spinlock_t buffer_lock; /* protects access to buffer, head and tail */
struct fasync_struct *fasync;
struct evdev *evdev;
@@ -72,12 +73,16 @@ static void evdev_pass_event(struct evdev_client *client,
client->buffer[client->tail].type = EV_SYN;
client->buffer[client->tail].code = SYN_DROPPED;
client->buffer[client->tail].value = 0;
- }
- spin_unlock(&client->buffer_lock);
+ client->packet_head = client->tail;
+ }
- if (event->type == EV_SYN)
+ if (event->type == EV_SYN && event->code == SYN_REPORT) {
+ client->packet_head = client->head;
kill_fasync(&client->fasync, SIGIO, POLL_IN);
+ }
+
+ spin_unlock(&client->buffer_lock);
}
/*
@@ -159,7 +164,6 @@ static int evdev_grab(struct evdev *evdev, struct evdev_client *client)
return error;
rcu_assign_pointer(evdev->grab, client);
- synchronize_rcu();
return 0;
}
@@ -182,7 +186,6 @@ static void evdev_attach_client(struct evdev *evdev,
spin_lock(&evdev->client_lock);
list_add_tail_rcu(&client->node, &evdev->client_list);
spin_unlock(&evdev->client_lock);
- synchronize_rcu();
}
static void evdev_detach_client(struct evdev *evdev,
@@ -387,12 +390,12 @@ static ssize_t evdev_read(struct file *file, char __user *buffer,
if (count < input_event_size())
return -EINVAL;
- if (client->head == client->tail && evdev->exist &&
+ if (client->packet_head == client->tail && evdev->exist &&
(file->f_flags & O_NONBLOCK))
return -EAGAIN;
retval = wait_event_interruptible(evdev->wait,
- client->head != client->tail || !evdev->exist);
+ client->packet_head != client->tail || !evdev->exist);
if (retval)
return retval;
@@ -421,7 +424,7 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
poll_wait(file, &evdev->wait, wait);
mask = evdev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR;
- if (client->head != client->tail)
+ if (client->packet_head != client->tail)
mask |= POLLIN | POLLRDNORM;
return mask;
diff --git a/drivers/input/input-compat.h b/drivers/input/input-compat.h
index 4d8ea32e8a00..22be27b424de 100644
--- a/drivers/input/input-compat.h
+++ b/drivers/input/input-compat.h
@@ -19,7 +19,7 @@
/* Note to the author of this code: did it ever occur to
you why the ifdefs are needed? Think about it again. -AK */
-#ifdef CONFIG_X86_64
+#if defined(CONFIG_X86_64) || defined(CONFIG_TILE)
# define INPUT_COMPAT_TEST is_compat_task()
#elif defined(CONFIG_S390)
# define INPUT_COMPAT_TEST test_thread_flag(TIF_31BIT)
diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c
index 3037842a60d8..b1aabde87523 100644
--- a/drivers/input/input-polldev.c
+++ b/drivers/input/input-polldev.c
@@ -13,6 +13,7 @@
#include <linux/jiffies.h>
#include <linux/slab.h>
#include <linux/mutex.h>
+#include <linux/workqueue.h>
#include <linux/input-polldev.h>
MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
@@ -20,44 +21,6 @@ MODULE_DESCRIPTION("Generic implementation of a polled input device");
MODULE_LICENSE("GPL v2");
MODULE_VERSION("0.1");
-static DEFINE_MUTEX(polldev_mutex);
-static int polldev_users;
-static struct workqueue_struct *polldev_wq;
-
-static int input_polldev_start_workqueue(void)
-{
- int retval;
-
- retval = mutex_lock_interruptible(&polldev_mutex);
- if (retval)
- return retval;
-
- if (!polldev_users) {
- polldev_wq = create_singlethread_workqueue("ipolldevd");
- if (!polldev_wq) {
- pr_err("failed to create ipolldevd workqueue\n");
- retval = -ENOMEM;
- goto out;
- }
- }
-
- polldev_users++;
-
- out:
- mutex_unlock(&polldev_mutex);
- return retval;
-}
-
-static void input_polldev_stop_workqueue(void)
-{
- mutex_lock(&polldev_mutex);
-
- if (!--polldev_users)
- destroy_workqueue(polldev_wq);
-
- mutex_unlock(&polldev_mutex);
-}
-
static void input_polldev_queue_work(struct input_polled_dev *dev)
{
unsigned long delay;
@@ -66,7 +29,7 @@ static void input_polldev_queue_work(struct input_polled_dev *dev)
if (delay >= HZ)
delay = round_jiffies_relative(delay);
- queue_delayed_work(polldev_wq, &dev->work, delay);
+ queue_delayed_work(system_freezable_wq, &dev->work, delay);
}
static void input_polled_device_work(struct work_struct *work)
@@ -81,18 +44,13 @@ static void input_polled_device_work(struct work_struct *work)
static int input_open_polled_device(struct input_dev *input)
{
struct input_polled_dev *dev = input_get_drvdata(input);
- int error;
-
- error = input_polldev_start_workqueue();
- if (error)
- return error;
if (dev->open)
dev->open(dev);
/* Only start polling if polling is enabled */
if (dev->poll_interval > 0)
- queue_delayed_work(polldev_wq, &dev->work, 0);
+ queue_delayed_work(system_freezable_wq, &dev->work, 0);
return 0;
}
@@ -102,13 +60,6 @@ static void input_close_polled_device(struct input_dev *input)
struct input_polled_dev *dev = input_get_drvdata(input);
cancel_delayed_work_sync(&dev->work);
- /*
- * Clean up work struct to remove references to the workqueue.
- * It may be destroyed by the next call. This causes problems
- * at next device open-close in case of poll_interval == 0.
- */
- INIT_DELAYED_WORK(&dev->work, dev->work.work.func);
- input_polldev_stop_workqueue();
if (dev->close)
dev->close(dev);
@@ -295,4 +246,3 @@ void input_unregister_polled_device(struct input_polled_dev *dev)
input_unregister_device(dev->input);
}
EXPORT_SYMBOL(input_unregister_polled_device);
-
diff --git a/drivers/input/input.c b/drivers/input/input.c
index ebbceedc92f4..75e11c7b70fd 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -451,7 +451,6 @@ int input_grab_device(struct input_handle *handle)
}
rcu_assign_pointer(dev->grab, handle);
- synchronize_rcu();
out:
mutex_unlock(&dev->mutex);
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index 5688b5c88f24..c24ec2d5f926 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -180,7 +180,6 @@ static void joydev_attach_client(struct joydev *joydev,
spin_lock(&joydev->client_lock);
list_add_tail_rcu(&client->node, &joydev->client_list);
spin_unlock(&joydev->client_lock);
- synchronize_rcu();
}
static void joydev_detach_client(struct joydev *joydev,
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index b16bed038f72..b4dee9d5a055 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -32,6 +32,16 @@ config KEYBOARD_ADP5588
To compile this driver as a module, choose M here: the
module will be called adp5588-keys.
+config KEYBOARD_ADP5589
+ tristate "ADP5589 I2C QWERTY Keypad and IO Expander"
+ depends on I2C
+ help
+ Say Y here if you want to use a ADP5589 attached to your
+ system I2C bus.
+
+ To compile this driver as a module, choose M here: the
+ module will be called adp5589-keys.
+
config KEYBOARD_AMIGA
tristate "Amiga keyboard"
depends on AMIGA
@@ -325,6 +335,18 @@ config KEYBOARD_MCS
To compile this driver as a module, choose M here: the
module will be called mcs_touchkey.
+config KEYBOARD_MPR121
+ tristate "Freescale MPR121 Touchkey"
+ depends on I2C
+ help
+ Say Y here if you have Freescale MPR121 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 mpr121_touchkey.
+
config KEYBOARD_IMX
tristate "IMX keypad support"
depends on ARCH_MXC
@@ -390,6 +412,17 @@ config KEYBOARD_PXA930_ROTARY
To compile this driver as a module, choose M here: the
module will be called pxa930_rotary.
+config KEYBOARD_PMIC8XXX
+ tristate "Qualcomm PMIC8XXX keypad support"
+ depends on MFD_PM8XXX
+ help
+ Say Y here if you want to enable the driver for the PMIC8XXX
+ keypad provided as a reference design from Qualcomm. This is intended
+ to support upto 18x8 matrix based keypad design.
+
+ To compile this driver as a module, choose M here: the module will
+ be called pmic8xxx-keypad.
+
config KEYBOARD_SAMSUNG
tristate "Samsung keypad support"
depends on SAMSUNG_DEV_KEYPAD
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 878e6c20deb0..ddde0fd476f7 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -6,6 +6,7 @@
obj-$(CONFIG_KEYBOARD_ADP5520) += adp5520-keys.o
obj-$(CONFIG_KEYBOARD_ADP5588) += adp5588-keys.o
+obj-$(CONFIG_KEYBOARD_ADP5589) += adp5589-keys.o
obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
@@ -27,11 +28,13 @@ 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_MPR121) += mpr121_touchkey.o
obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
obj-$(CONFIG_KEYBOARD_NOMADIK) += nomadik-ske-keypad.o
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
obj-$(CONFIG_KEYBOARD_OMAP4) += omap4-keypad.o
obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o
+obj-$(CONFIG_KEYBOARD_PMIC8XXX) += pmic8xxx-keypad.o
obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o
obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o
obj-$(CONFIG_KEYBOARD_QT1070) += qt1070.o
diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c
new file mode 100644
index 000000000000..631598663aab
--- /dev/null
+++ b/drivers/input/keyboard/adp5589-keys.c
@@ -0,0 +1,771 @@
+/*
+ * Description: keypad driver for ADP5589
+ * I2C QWERTY Keypad and IO Expander
+ * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Copyright (C) 2010-2011 Analog Devices Inc.
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/workqueue.h>
+#include <linux/errno.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+
+#include <linux/input/adp5589.h>
+
+/* GENERAL_CFG Register */
+#define OSC_EN (1 << 7)
+#define CORE_CLK(x) (((x) & 0x3) << 5)
+#define LCK_TRK_LOGIC (1 << 4)
+#define LCK_TRK_GPI (1 << 3)
+#define INT_CFG (1 << 1)
+#define RST_CFG (1 << 0)
+
+/* INT_EN Register */
+#define LOGIC2_IEN (1 << 5)
+#define LOGIC1_IEN (1 << 4)
+#define LOCK_IEN (1 << 3)
+#define OVRFLOW_IEN (1 << 2)
+#define GPI_IEN (1 << 1)
+#define EVENT_IEN (1 << 0)
+
+/* Interrupt Status Register */
+#define LOGIC2_INT (1 << 5)
+#define LOGIC1_INT (1 << 4)
+#define LOCK_INT (1 << 3)
+#define OVRFLOW_INT (1 << 2)
+#define GPI_INT (1 << 1)
+#define EVENT_INT (1 << 0)
+
+/* STATUS Register */
+
+#define LOGIC2_STAT (1 << 7)
+#define LOGIC1_STAT (1 << 6)
+#define LOCK_STAT (1 << 5)
+#define KEC 0xF
+
+/* PIN_CONFIG_D Register */
+#define C4_EXTEND_CFG (1 << 6) /* RESET2 */
+#define R4_EXTEND_CFG (1 << 5) /* RESET1 */
+
+/* LOCK_CFG */
+#define LOCK_EN (1 << 0)
+
+#define PTIME_MASK 0x3
+#define LTIME_MASK 0x3
+
+/* Key Event Register xy */
+#define KEY_EV_PRESSED (1 << 7)
+#define KEY_EV_MASK (0x7F)
+
+#define KEYP_MAX_EVENT 16
+
+#define MAXGPIO 19
+#define ADP_BANK(offs) ((offs) >> 3)
+#define ADP_BIT(offs) (1u << ((offs) & 0x7))
+
+struct adp5589_kpad {
+ struct i2c_client *client;
+ struct input_dev *input;
+ unsigned short keycode[ADP5589_KEYMAPSIZE];
+ const struct adp5589_gpi_map *gpimap;
+ unsigned short gpimapsize;
+ unsigned extend_cfg;
+#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 adp5589_read(struct i2c_client *client, u8 reg)
+{
+ int ret = i2c_smbus_read_byte_data(client, reg);
+
+ if (ret < 0)
+ dev_err(&client->dev, "Read Error\n");
+
+ return ret;
+}
+
+static int adp5589_write(struct i2c_client *client, u8 reg, u8 val)
+{
+ return i2c_smbus_write_byte_data(client, reg, val);
+}
+
+#ifdef CONFIG_GPIOLIB
+static int adp5589_gpio_get_value(struct gpio_chip *chip, unsigned off)
+{
+ struct adp5589_kpad *kpad = container_of(chip, struct adp5589_kpad, gc);
+ unsigned int bank = ADP_BANK(kpad->gpiomap[off]);
+ unsigned int bit = ADP_BIT(kpad->gpiomap[off]);
+
+ return !!(adp5589_read(kpad->client, ADP5589_GPI_STATUS_A + bank) &
+ bit);
+}
+
+static void adp5589_gpio_set_value(struct gpio_chip *chip,
+ unsigned off, int val)
+{
+ struct adp5589_kpad *kpad = container_of(chip, struct adp5589_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;
+
+ adp5589_write(kpad->client, ADP5589_GPO_DATA_OUT_A + bank,
+ kpad->dat_out[bank]);
+
+ mutex_unlock(&kpad->gpio_lock);
+}
+
+static int adp5589_gpio_direction_input(struct gpio_chip *chip, unsigned off)
+{
+ struct adp5589_kpad *kpad = container_of(chip, struct adp5589_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 = adp5589_write(kpad->client, ADP5589_GPIO_DIRECTION_A + bank,
+ kpad->dir[bank]);
+
+ mutex_unlock(&kpad->gpio_lock);
+
+ return ret;
+}
+
+static int adp5589_gpio_direction_output(struct gpio_chip *chip,
+ unsigned off, int val)
+{
+ struct adp5589_kpad *kpad = container_of(chip, struct adp5589_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 = adp5589_write(kpad->client, ADP5589_GPO_DATA_OUT_A + bank,
+ kpad->dat_out[bank]);
+ ret |= adp5589_write(kpad->client, ADP5589_GPIO_DIRECTION_A + bank,
+ kpad->dir[bank]);
+
+ mutex_unlock(&kpad->gpio_lock);
+
+ return ret;
+}
+
+static int __devinit adp5589_build_gpiomap(struct adp5589_kpad *kpad,
+ const struct adp5589_kpad_platform_data *pdata)
+{
+ bool pin_used[MAXGPIO];
+ int n_unused = 0;
+ int i;
+
+ memset(pin_used, false, sizeof(pin_used));
+
+ for (i = 0; i < MAXGPIO; i++)
+ if (pdata->keypad_en_mask & (1 << i))
+ pin_used[i] = true;
+
+ for (i = 0; i < kpad->gpimapsize; i++)
+ pin_used[kpad->gpimap[i].pin - ADP5589_GPI_PIN_BASE] = true;
+
+ if (kpad->extend_cfg & R4_EXTEND_CFG)
+ pin_used[4] = true;
+
+ if (kpad->extend_cfg & C4_EXTEND_CFG)
+ pin_used[12] = true;
+
+ for (i = 0; i < MAXGPIO; i++)
+ if (!pin_used[i])
+ kpad->gpiomap[n_unused++] = i;
+
+ return n_unused;
+}
+
+static int __devinit adp5589_gpio_add(struct adp5589_kpad *kpad)
+{
+ struct device *dev = &kpad->client->dev;
+ const struct adp5589_kpad_platform_data *pdata = dev->platform_data;
+ const struct adp5589_gpio_platform_data *gpio_data = pdata->gpio_data;
+ int i, error;
+
+ if (!gpio_data)
+ return 0;
+
+ kpad->gc.ngpio = adp5589_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 = adp5589_gpio_direction_input;
+ kpad->gc.direction_output = adp5589_gpio_direction_output;
+ kpad->gc.get = adp5589_gpio_get_value;
+ kpad->gc.set = adp5589_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] = adp5589_read(kpad->client,
+ ADP5589_GPO_DATA_OUT_A + i);
+ kpad->dir[i] = adp5589_read(kpad->client,
+ ADP5589_GPIO_DIRECTION_A + 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 adp5589_gpio_remove(struct adp5589_kpad *kpad)
+{
+ struct device *dev = &kpad->client->dev;
+ const struct adp5589_kpad_platform_data *pdata = dev->platform_data;
+ const struct adp5589_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 adp5589_gpio_add(struct adp5589_kpad *kpad)
+{
+ return 0;
+}
+
+static inline void adp5589_gpio_remove(struct adp5589_kpad *kpad)
+{
+}
+#endif
+
+static void adp5589_report_switches(struct adp5589_kpad *kpad,
+ int key, int key_val)
+{
+ int i;
+
+ for (i = 0; i < kpad->gpimapsize; i++) {
+ if (key_val == kpad->gpimap[i].pin) {
+ input_report_switch(kpad->input,
+ kpad->gpimap[i].sw_evt,
+ key & KEY_EV_PRESSED);
+ break;
+ }
+ }
+}
+
+static void adp5589_report_events(struct adp5589_kpad *kpad, int ev_cnt)
+{
+ int i;
+
+ for (i = 0; i < ev_cnt; i++) {
+ int key = adp5589_read(kpad->client, ADP5589_FIFO_1 + i);
+ int key_val = key & KEY_EV_MASK;
+
+ if (key_val >= ADP5589_GPI_PIN_BASE &&
+ key_val <= ADP5589_GPI_PIN_END) {
+ adp5589_report_switches(kpad, key, key_val);
+ } else {
+ input_report_key(kpad->input,
+ kpad->keycode[key_val - 1],
+ key & KEY_EV_PRESSED);
+ }
+ }
+}
+
+static irqreturn_t adp5589_irq(int irq, void *handle)
+{
+ struct adp5589_kpad *kpad = handle;
+ struct i2c_client *client = kpad->client;
+ int status, ev_cnt;
+
+ status = adp5589_read(client, ADP5589_INT_STATUS);
+
+ if (status & OVRFLOW_INT) /* Unlikely and should never happen */
+ dev_err(&client->dev, "Event Overflow Error\n");
+
+ if (status & EVENT_INT) {
+ ev_cnt = adp5589_read(client, ADP5589_STATUS) & KEC;
+ if (ev_cnt) {
+ adp5589_report_events(kpad, ev_cnt);
+ input_sync(kpad->input);
+ }
+ }
+
+ adp5589_write(client, ADP5589_INT_STATUS, status); /* Status is W1C */
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit adp5589_get_evcode(struct adp5589_kpad *kpad, unsigned short key)
+{
+ int i;
+
+ for (i = 0; i < ADP5589_KEYMAPSIZE; i++)
+ if (key == kpad->keycode[i])
+ return (i + 1) | KEY_EV_PRESSED;
+
+ dev_err(&kpad->client->dev, "RESET/UNLOCK key not in keycode map\n");
+
+ return -EINVAL;
+}
+
+static int __devinit adp5589_setup(struct adp5589_kpad *kpad)
+{
+ struct i2c_client *client = kpad->client;
+ const struct adp5589_kpad_platform_data *pdata =
+ client->dev.platform_data;
+ int i, ret;
+ unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0;
+ unsigned char pull_mask = 0;
+
+ ret = adp5589_write(client, ADP5589_PIN_CONFIG_A,
+ pdata->keypad_en_mask & 0xFF);
+ ret |= adp5589_write(client, ADP5589_PIN_CONFIG_B,
+ (pdata->keypad_en_mask >> 8) & 0xFF);
+ ret |= adp5589_write(client, ADP5589_PIN_CONFIG_C,
+ (pdata->keypad_en_mask >> 16) & 0xFF);
+
+ if (pdata->en_keylock) {
+ ret |= adp5589_write(client, ADP5589_UNLOCK1,
+ pdata->unlock_key1);
+ ret |= adp5589_write(client, ADP5589_UNLOCK2,
+ pdata->unlock_key2);
+ ret |= adp5589_write(client, ADP5589_UNLOCK_TIMERS,
+ pdata->unlock_timer & LTIME_MASK);
+ ret |= adp5589_write(client, ADP5589_LOCK_CFG, LOCK_EN);
+ }
+
+ for (i = 0; i < KEYP_MAX_EVENT; i++)
+ ret |= adp5589_read(client, ADP5589_FIFO_1 + i);
+
+ for (i = 0; i < pdata->gpimapsize; i++) {
+ unsigned short pin = pdata->gpimap[i].pin;
+
+ if (pin <= ADP5589_GPI_PIN_ROW_END) {
+ evt_mode1 |= (1 << (pin - ADP5589_GPI_PIN_ROW_BASE));
+ } else {
+ evt_mode2 |=
+ ((1 << (pin - ADP5589_GPI_PIN_COL_BASE)) & 0xFF);
+ evt_mode3 |=
+ ((1 << (pin - ADP5589_GPI_PIN_COL_BASE)) >> 8);
+ }
+ }
+
+ if (pdata->gpimapsize) {
+ ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_A, evt_mode1);
+ ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_B, evt_mode2);
+ ret |= adp5589_write(client, ADP5589_GPI_EVENT_EN_C, evt_mode3);
+ }
+
+ if (pdata->pull_dis_mask & pdata->pullup_en_100k &
+ pdata->pullup_en_300k & pdata->pulldown_en_300k)
+ dev_warn(&client->dev, "Conflicting pull resistor config\n");
+
+ for (i = 0; i < MAXGPIO; i++) {
+ unsigned val = 0;
+
+ if (pdata->pullup_en_300k & (1 << i))
+ val = 0;
+ else if (pdata->pulldown_en_300k & (1 << i))
+ val = 1;
+ else if (pdata->pullup_en_100k & (1 << i))
+ val = 2;
+ else if (pdata->pull_dis_mask & (1 << i))
+ val = 3;
+
+ pull_mask |= val << (2 * (i & 0x3));
+
+ if ((i & 0x3) == 0x3 || i == MAXGPIO - 1) {
+ ret |= adp5589_write(client,
+ ADP5589_RPULL_CONFIG_A + (i >> 2),
+ pull_mask);
+ pull_mask = 0;
+ }
+ }
+
+ if (pdata->reset1_key_1 && pdata->reset1_key_2 && pdata->reset1_key_3) {
+ ret |= adp5589_write(client, ADP5589_RESET1_EVENT_A,
+ adp5589_get_evcode(kpad,
+ pdata->reset1_key_1));
+ ret |= adp5589_write(client, ADP5589_RESET1_EVENT_B,
+ adp5589_get_evcode(kpad,
+ pdata->reset1_key_2));
+ ret |= adp5589_write(client, ADP5589_RESET1_EVENT_C,
+ adp5589_get_evcode(kpad,
+ pdata->reset1_key_3));
+ kpad->extend_cfg |= R4_EXTEND_CFG;
+ }
+
+ if (pdata->reset2_key_1 && pdata->reset2_key_2) {
+ ret |= adp5589_write(client, ADP5589_RESET2_EVENT_A,
+ adp5589_get_evcode(kpad,
+ pdata->reset2_key_1));
+ ret |= adp5589_write(client, ADP5589_RESET2_EVENT_B,
+ adp5589_get_evcode(kpad,
+ pdata->reset2_key_2));
+ kpad->extend_cfg |= C4_EXTEND_CFG;
+ }
+
+ if (kpad->extend_cfg) {
+ ret |= adp5589_write(client, ADP5589_RESET_CFG,
+ pdata->reset_cfg);
+ ret |= adp5589_write(client, ADP5589_PIN_CONFIG_D,
+ kpad->extend_cfg);
+ }
+
+ for (i = 0; i <= ADP_BANK(MAXGPIO); i++)
+ ret |= adp5589_write(client, ADP5589_DEBOUNCE_DIS_A + i,
+ pdata->debounce_dis_mask >> (i * 8));
+
+ ret |= adp5589_write(client, ADP5589_POLL_PTIME_CFG,
+ pdata->scan_cycle_time & PTIME_MASK);
+ ret |= adp5589_write(client, ADP5589_INT_STATUS, LOGIC2_INT |
+ LOGIC1_INT | OVRFLOW_INT | LOCK_INT |
+ GPI_INT | EVENT_INT); /* Status is W1C */
+
+ ret |= adp5589_write(client, ADP5589_GENERAL_CFG,
+ INT_CFG | OSC_EN | CORE_CLK(3));
+ ret |= adp5589_write(client, ADP5589_INT_EN,
+ OVRFLOW_IEN | GPI_IEN | EVENT_IEN);
+
+ if (ret < 0) {
+ dev_err(&client->dev, "Write Error\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void __devinit adp5589_report_switch_state(struct adp5589_kpad *kpad)
+{
+ int gpi_stat1 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_A);
+ int gpi_stat2 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_B);
+ int gpi_stat3 = adp5589_read(kpad->client, ADP5589_GPI_STATUS_C);
+ int gpi_stat_tmp, pin_loc;
+ int i;
+
+ for (i = 0; i < kpad->gpimapsize; i++) {
+ unsigned short pin = kpad->gpimap[i].pin;
+
+ if (pin <= ADP5589_GPI_PIN_ROW_END) {
+ gpi_stat_tmp = gpi_stat1;
+ pin_loc = pin - ADP5589_GPI_PIN_ROW_BASE;
+ } else if ((pin - ADP5589_GPI_PIN_COL_BASE) < 8) {
+ gpi_stat_tmp = gpi_stat2;
+ pin_loc = pin - ADP5589_GPI_PIN_COL_BASE;
+ } else {
+ gpi_stat_tmp = gpi_stat3;
+ pin_loc = pin - ADP5589_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 adp5589_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct adp5589_kpad *kpad;
+ const struct adp5589_kpad_platform_data *pdata;
+ struct input_dev *input;
+ unsigned int revid;
+ int ret, i;
+ int error;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
+ return -EIO;
+ }
+
+ pdata = client->dev.platform_data;
+ if (!pdata) {
+ dev_err(&client->dev, "no platform data?\n");
+ return -EINVAL;
+ }
+
+ if (!((pdata->keypad_en_mask & 0xFF) &&
+ (pdata->keypad_en_mask >> 8)) || !pdata->keymap) {
+ dev_err(&client->dev, "no rows, cols or keymap from pdata\n");
+ return -EINVAL;
+ }
+
+ if (pdata->keymapsize != ADP5589_KEYMAPSIZE) {
+ dev_err(&client->dev, "invalid keymapsize\n");
+ return -EINVAL;
+ }
+
+ if (!pdata->gpimap && pdata->gpimapsize) {
+ dev_err(&client->dev, "invalid gpimap from pdata\n");
+ return -EINVAL;
+ }
+
+ if (pdata->gpimapsize > ADP5589_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 < ADP5589_GPI_PIN_BASE || pin > ADP5589_GPI_PIN_END) {
+ dev_err(&client->dev, "invalid gpi pin data\n");
+ return -EINVAL;
+ }
+
+ if ((1 << (pin - ADP5589_GPI_PIN_ROW_BASE)) &
+ pdata->keypad_en_mask) {
+ dev_err(&client->dev, "invalid gpi row/col data\n");
+ return -EINVAL;
+ }
+ }
+
+ if (!client->irq) {
+ dev_err(&client->dev, "no IRQ?\n");
+ return -EINVAL;
+ }
+
+ kpad = kzalloc(sizeof(*kpad), GFP_KERNEL);
+ input = input_allocate_device();
+ if (!kpad || !input) {
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ kpad->client = client;
+ kpad->input = input;
+
+ ret = adp5589_read(client, ADP5589_ID);
+ if (ret < 0) {
+ error = ret;
+ goto err_free_mem;
+ }
+
+ revid = (u8) ret & ADP5589_DEVICE_ID_MASK;
+
+ input->name = client->name;
+ input->phys = "adp5589-keys/input0";
+ input->dev.parent = &client->dev;
+
+ input_set_drvdata(input, kpad);
+
+ input->id.bustype = BUS_I2C;
+ input->id.vendor = 0x0001;
+ input->id.product = 0x0001;
+ input->id.version = revid;
+
+ input->keycodesize = sizeof(kpad->keycode[0]);
+ input->keycodemax = pdata->keymapsize;
+ input->keycode = kpad->keycode;
+
+ 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);
+
+ if (pdata->repeat)
+ __set_bit(EV_REP, input->evbit);
+
+ for (i = 0; i < input->keycodemax; i++)
+ __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");
+ goto err_free_mem;
+ }
+
+ error = request_threaded_irq(client->irq, NULL, adp5589_irq,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ client->dev.driver->name, kpad);
+ if (error) {
+ dev_err(&client->dev, "irq %d busy?\n", client->irq);
+ goto err_unreg_dev;
+ }
+
+ error = adp5589_setup(kpad);
+ if (error)
+ goto err_free_irq;
+
+ if (kpad->gpimapsize)
+ adp5589_report_switch_state(kpad);
+
+ error = adp5589_gpio_add(kpad);
+ if (error)
+ goto err_free_irq;
+
+ device_init_wakeup(&client->dev, 1);
+ i2c_set_clientdata(client, kpad);
+
+ dev_info(&client->dev, "Rev.%d keypad, irq %d\n", revid, client->irq);
+ return 0;
+
+err_free_irq:
+ free_irq(client->irq, kpad);
+err_unreg_dev:
+ input_unregister_device(input);
+ input = NULL;
+err_free_mem:
+ input_free_device(input);
+ kfree(kpad);
+
+ return error;
+}
+
+static int __devexit adp5589_remove(struct i2c_client *client)
+{
+ struct adp5589_kpad *kpad = i2c_get_clientdata(client);
+
+ adp5589_write(client, ADP5589_GENERAL_CFG, 0);
+ free_irq(client->irq, kpad);
+ input_unregister_device(kpad->input);
+ adp5589_gpio_remove(kpad);
+ kfree(kpad);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int adp5589_suspend(struct device *dev)
+{
+ struct adp5589_kpad *kpad = dev_get_drvdata(dev);
+ struct i2c_client *client = kpad->client;
+
+ disable_irq(client->irq);
+
+ if (device_may_wakeup(&client->dev))
+ enable_irq_wake(client->irq);
+
+ return 0;
+}
+
+static int adp5589_resume(struct device *dev)
+{
+ struct adp5589_kpad *kpad = dev_get_drvdata(dev);
+ struct i2c_client *client = kpad->client;
+
+ if (device_may_wakeup(&client->dev))
+ disable_irq_wake(client->irq);
+
+ enable_irq(client->irq);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(adp5589_dev_pm_ops, adp5589_suspend, adp5589_resume);
+
+static const struct i2c_device_id adp5589_id[] = {
+ {"adp5589-keys", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, adp5589_id);
+
+static struct i2c_driver adp5589_driver = {
+ .driver = {
+ .name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .pm = &adp5589_dev_pm_ops,
+ },
+ .probe = adp5589_probe,
+ .remove = __devexit_p(adp5589_remove),
+ .id_table = adp5589_id,
+};
+
+static int __init adp5589_init(void)
+{
+ return i2c_add_driver(&adp5589_driver);
+}
+module_init(adp5589_init);
+
+static void __exit adp5589_exit(void)
+{
+ i2c_del_driver(&adp5589_driver);
+}
+module_exit(adp5589_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
+MODULE_DESCRIPTION("ADP5589 Keypad driver");
diff --git a/drivers/input/keyboard/atakbd.c b/drivers/input/keyboard/atakbd.c
index 1839194ea987..10bcd4ae5402 100644
--- a/drivers/input/keyboard/atakbd.c
+++ b/drivers/input/keyboard/atakbd.c
@@ -223,8 +223,9 @@ static int __init atakbd_init(void)
return -ENODEV;
// need to init core driver if not already done so
- if (atari_keyb_init())
- return -ENODEV;
+ error = atari_keyb_init();
+ if (error)
+ return error;
atakbd_dev = input_allocate_device();
if (!atakbd_dev)
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index eb3006361ee4..6e6145b9a4c1 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -324,7 +324,12 @@ static void gpio_keys_report_event(struct gpio_button_data *bdata)
unsigned int type = button->type ?: EV_KEY;
int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low;
- input_event(input, type, button->code, !!state);
+ if (type == EV_ABS) {
+ if (state)
+ input_event(input, type, button->code, button->value);
+ } else {
+ input_event(input, type, button->code, !!state);
+ }
input_sync(input);
}
@@ -363,7 +368,7 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
struct gpio_button_data *bdata,
struct gpio_keys_button *button)
{
- char *desc = button->desc ? button->desc : "gpio_keys";
+ const char *desc = button->desc ? button->desc : "gpio_keys";
struct device *dev = &pdev->dev;
unsigned long irqflags;
int irq, error;
@@ -468,7 +473,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ddata);
input_set_drvdata(input, ddata);
- input->name = pdev->name;
+ input->name = pdata->name ? : pdev->name;
input->phys = "gpio-keys/input0";
input->dev.parent = &pdev->dev;
input->open = gpio_keys_open;
diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c
new file mode 100644
index 000000000000..0a9e81194888
--- /dev/null
+++ b/drivers/input/keyboard/mpr121_touchkey.c
@@ -0,0 +1,339 @@
+/*
+ * Touchkey driver for Freescale MPR121 Controllor
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ * Author: Zhang Jiejing <jiejing.zhang@freescale.com>
+ *
+ * Based on mcs_touchkey.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/i2c/mpr121_touchkey.h>
+
+/* Register definitions */
+#define ELE_TOUCH_STATUS_0_ADDR 0x0
+#define ELE_TOUCH_STATUS_1_ADDR 0X1
+#define MHD_RISING_ADDR 0x2b
+#define NHD_RISING_ADDR 0x2c
+#define NCL_RISING_ADDR 0x2d
+#define FDL_RISING_ADDR 0x2e
+#define MHD_FALLING_ADDR 0x2f
+#define NHD_FALLING_ADDR 0x30
+#define NCL_FALLING_ADDR 0x31
+#define FDL_FALLING_ADDR 0x32
+#define ELE0_TOUCH_THRESHOLD_ADDR 0x41
+#define ELE0_RELEASE_THRESHOLD_ADDR 0x42
+#define AFE_CONF_ADDR 0x5c
+#define FILTER_CONF_ADDR 0x5d
+
+/*
+ * ELECTRODE_CONF_ADDR: This register configures the number of
+ * enabled capacitance sensing inputs and its run/suspend mode.
+ */
+#define ELECTRODE_CONF_ADDR 0x5e
+#define AUTO_CONFIG_CTRL_ADDR 0x7b
+#define AUTO_CONFIG_USL_ADDR 0x7d
+#define AUTO_CONFIG_LSL_ADDR 0x7e
+#define AUTO_CONFIG_TL_ADDR 0x7f
+
+/* Threshold of touch/release trigger */
+#define TOUCH_THRESHOLD 0x0f
+#define RELEASE_THRESHOLD 0x0a
+/* Masks for touch and release triggers */
+#define TOUCH_STATUS_MASK 0xfff
+/* MPR121 has 12 keys */
+#define MPR121_MAX_KEY_COUNT 12
+
+struct mpr121_touchkey {
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+ unsigned int key_val;
+ unsigned int statusbits;
+ unsigned int keycount;
+ u16 keycodes[MPR121_MAX_KEY_COUNT];
+};
+
+struct mpr121_init_register {
+ int addr;
+ u8 val;
+};
+
+static const struct mpr121_init_register init_reg_table[] __devinitconst = {
+ { MHD_RISING_ADDR, 0x1 },
+ { NHD_RISING_ADDR, 0x1 },
+ { MHD_FALLING_ADDR, 0x1 },
+ { NHD_FALLING_ADDR, 0x1 },
+ { NCL_FALLING_ADDR, 0xff },
+ { FDL_FALLING_ADDR, 0x02 },
+ { FILTER_CONF_ADDR, 0x04 },
+ { AFE_CONF_ADDR, 0x0b },
+ { AUTO_CONFIG_CTRL_ADDR, 0x0b },
+};
+
+static irqreturn_t mpr_touchkey_interrupt(int irq, void *dev_id)
+{
+ struct mpr121_touchkey *mpr121 = dev_id;
+ struct i2c_client *client = mpr121->client;
+ struct input_dev *input = mpr121->input_dev;
+ unsigned int key_num, key_val, pressed;
+ int reg;
+
+ reg = i2c_smbus_read_byte_data(client, ELE_TOUCH_STATUS_1_ADDR);
+ if (reg < 0) {
+ dev_err(&client->dev, "i2c read error [%d]\n", reg);
+ goto out;
+ }
+
+ reg <<= 8;
+ reg |= i2c_smbus_read_byte_data(client, ELE_TOUCH_STATUS_0_ADDR);
+ if (reg < 0) {
+ dev_err(&client->dev, "i2c read error [%d]\n", reg);
+ goto out;
+ }
+
+ reg &= TOUCH_STATUS_MASK;
+ /* use old press bit to figure out which bit changed */
+ key_num = ffs(reg ^ mpr121->statusbits) - 1;
+ pressed = reg & (1 << key_num);
+ mpr121->statusbits = reg;
+
+ key_val = mpr121->keycodes[key_num];
+
+ input_event(input, EV_MSC, MSC_SCAN, key_num);
+ input_report_key(input, key_val, pressed);
+ input_sync(input);
+
+ dev_dbg(&client->dev, "key %d %d %s\n", key_num, key_val,
+ pressed ? "pressed" : "released");
+
+out:
+ return IRQ_HANDLED;
+}
+
+static int __devinit mpr121_phys_init(const struct mpr121_platform_data *pdata,
+ struct mpr121_touchkey *mpr121,
+ struct i2c_client *client)
+{
+ const struct mpr121_init_register *reg;
+ unsigned char usl, lsl, tl;
+ int i, t, vdd, ret;
+
+ /* Set up touch/release threshold for ele0-ele11 */
+ for (i = 0; i <= MPR121_MAX_KEY_COUNT; i++) {
+ t = ELE0_TOUCH_THRESHOLD_ADDR + (i * 2);
+ ret = i2c_smbus_write_byte_data(client, t, TOUCH_THRESHOLD);
+ if (ret < 0)
+ goto err_i2c_write;
+ ret = i2c_smbus_write_byte_data(client, t + 1,
+ RELEASE_THRESHOLD);
+ if (ret < 0)
+ goto err_i2c_write;
+ }
+
+ /* Set up init register */
+ for (i = 0; i < ARRAY_SIZE(init_reg_table); i++) {
+ reg = &init_reg_table[i];
+ ret = i2c_smbus_write_byte_data(client, reg->addr, reg->val);
+ if (ret < 0)
+ goto err_i2c_write;
+ }
+
+
+ /*
+ * Capacitance on sensing input varies and needs to be compensated.
+ * The internal MPR121-auto-configuration can do this if it's
+ * registers are set properly (based on pdata->vdd_uv).
+ */
+ vdd = pdata->vdd_uv / 1000;
+ usl = ((vdd - 700) * 256) / vdd;
+ lsl = (usl * 65) / 100;
+ tl = (usl * 90) / 100;
+ ret = i2c_smbus_write_byte_data(client, AUTO_CONFIG_USL_ADDR, usl);
+ ret |= i2c_smbus_write_byte_data(client, AUTO_CONFIG_LSL_ADDR, lsl);
+ ret |= i2c_smbus_write_byte_data(client, AUTO_CONFIG_TL_ADDR, tl);
+ ret |= i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR,
+ mpr121->keycount);
+ if (ret != 0)
+ goto err_i2c_write;
+
+ dev_dbg(&client->dev, "set up with %x keys.\n", mpr121->keycount);
+
+ return 0;
+
+err_i2c_write:
+ dev_err(&client->dev, "i2c write error: %d\n", ret);
+ return ret;
+}
+
+static int __devinit mpr_touchkey_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ const struct mpr121_platform_data *pdata = client->dev.platform_data;
+ struct mpr121_touchkey *mpr121;
+ struct input_dev *input_dev;
+ int error;
+ int i;
+
+ if (!pdata) {
+ dev_err(&client->dev, "no platform data defined\n");
+ return -EINVAL;
+ }
+
+ if (!pdata->keymap || !pdata->keymap_size) {
+ dev_err(&client->dev, "missing keymap data\n");
+ return -EINVAL;
+ }
+
+ if (pdata->keymap_size > MPR121_MAX_KEY_COUNT) {
+ dev_err(&client->dev, "too many keys defined\n");
+ return -EINVAL;
+ }
+
+ if (!client->irq) {
+ dev_err(&client->dev, "irq number should not be zero\n");
+ return -EINVAL;
+ }
+
+ mpr121 = kzalloc(sizeof(struct mpr121_touchkey), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!mpr121 || !input_dev) {
+ dev_err(&client->dev, "Failed to allocate memory\n");
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ mpr121->client = client;
+ mpr121->input_dev = input_dev;
+ mpr121->keycount = pdata->keymap_size;
+
+ input_dev->name = "Freescale MPR121 Touchkey";
+ input_dev->id.bustype = BUS_I2C;
+ input_dev->dev.parent = &client->dev;
+ input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+
+ input_dev->keycode = mpr121->keycodes;
+ input_dev->keycodesize = sizeof(mpr121->keycodes[0]);
+ input_dev->keycodemax = mpr121->keycount;
+
+ for (i = 0; i < pdata->keymap_size; i++) {
+ input_set_capability(input_dev, EV_KEY, pdata->keymap[i]);
+ mpr121->keycodes[i] = pdata->keymap[i];
+ }
+
+ error = mpr121_phys_init(pdata, mpr121, client);
+ if (error) {
+ dev_err(&client->dev, "Failed to init register\n");
+ goto err_free_mem;
+ }
+
+ error = request_threaded_irq(client->irq, NULL,
+ mpr_touchkey_interrupt,
+ IRQF_TRIGGER_FALLING,
+ client->dev.driver->name, mpr121);
+ 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, mpr121);
+ device_init_wakeup(&client->dev, pdata->wakeup);
+
+ return 0;
+
+err_free_irq:
+ free_irq(client->irq, mpr121);
+err_free_mem:
+ input_free_device(input_dev);
+ kfree(mpr121);
+ return error;
+}
+
+static int __devexit mpr_touchkey_remove(struct i2c_client *client)
+{
+ struct mpr121_touchkey *mpr121 = i2c_get_clientdata(client);
+
+ free_irq(client->irq, mpr121);
+ input_unregister_device(mpr121->input_dev);
+ kfree(mpr121);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mpr_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ if (device_may_wakeup(&client->dev))
+ enable_irq_wake(client->irq);
+
+ i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR, 0x00);
+
+ return 0;
+}
+
+static int mpr_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct mpr121_touchkey *mpr121 = i2c_get_clientdata(client);
+
+ if (device_may_wakeup(&client->dev))
+ disable_irq_wake(client->irq);
+
+ i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR,
+ mpr121->keycount);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(mpr121_touchkey_pm_ops, mpr_suspend, mpr_resume);
+
+static const struct i2c_device_id mpr121_id[] = {
+ { "mpr121_touchkey", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mpr121_id);
+
+static struct i2c_driver mpr_touchkey_driver = {
+ .driver = {
+ .name = "mpr121",
+ .owner = THIS_MODULE,
+ .pm = &mpr121_touchkey_pm_ops,
+ },
+ .id_table = mpr121_id,
+ .probe = mpr_touchkey_probe,
+ .remove = __devexit_p(mpr_touchkey_remove),
+};
+
+static int __init mpr_touchkey_init(void)
+{
+ return i2c_add_driver(&mpr_touchkey_driver);
+}
+module_init(mpr_touchkey_init);
+
+static void __exit mpr_touchkey_exit(void)
+{
+ i2c_del_driver(&mpr_touchkey_driver);
+}
+module_exit(mpr_touchkey_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Zhang Jiejing <jiejing.zhang@freescale.com>");
+MODULE_DESCRIPTION("Touch Key driver for Freescale MPR121 Chip");
diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c
index 0e2a19cb43d8..f23a743817db 100644
--- a/drivers/input/keyboard/omap-keypad.c
+++ b/drivers/input/keyboard/omap-keypad.c
@@ -413,7 +413,7 @@ static int __devinit omap_kp_probe(struct platform_device *pdev)
return 0;
err5:
for (i = irq_idx - 1; i >=0; i--)
- free_irq(row_gpios[i], NULL);
+ free_irq(row_gpios[i], omap_kp);
err4:
input_unregister_device(omap_kp->input);
input_dev = NULL;
@@ -444,11 +444,11 @@ static int __devexit omap_kp_remove(struct platform_device *pdev)
gpio_free(col_gpios[i]);
for (i = 0; i < omap_kp->rows; i++) {
gpio_free(row_gpios[i]);
- free_irq(gpio_to_irq(row_gpios[i]), NULL);
+ free_irq(gpio_to_irq(row_gpios[i]), omap_kp);
}
} else {
omap_writew(1, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
- free_irq(omap_kp->irq, NULL);
+ free_irq(omap_kp->irq, omap_kp);
}
del_timer_sync(&omap_kp->timer);
diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c
new file mode 100644
index 000000000000..40b02ae96f86
--- /dev/null
+++ b/drivers/input/keyboard/pmic8xxx-keypad.c
@@ -0,0 +1,799 @@
+/* Copyright (c) 2009-2011, 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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+
+#include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pm8xxx/gpio.h>
+#include <linux/input/pmic8xxx-keypad.h>
+
+#define PM8XXX_MAX_ROWS 18
+#define PM8XXX_MAX_COLS 8
+#define PM8XXX_ROW_SHIFT 3
+#define PM8XXX_MATRIX_MAX_SIZE (PM8XXX_MAX_ROWS * PM8XXX_MAX_COLS)
+
+#define PM8XXX_MIN_ROWS 5
+#define PM8XXX_MIN_COLS 5
+
+#define MAX_SCAN_DELAY 128
+#define MIN_SCAN_DELAY 1
+
+/* in nanoseconds */
+#define MAX_ROW_HOLD_DELAY 122000
+#define MIN_ROW_HOLD_DELAY 30500
+
+#define MAX_DEBOUNCE_TIME 20
+#define MIN_DEBOUNCE_TIME 5
+
+#define KEYP_CTRL 0x148
+
+#define KEYP_CTRL_EVNTS BIT(0)
+#define KEYP_CTRL_EVNTS_MASK 0x3
+
+#define KEYP_CTRL_SCAN_COLS_SHIFT 5
+#define KEYP_CTRL_SCAN_COLS_MIN 5
+#define KEYP_CTRL_SCAN_COLS_BITS 0x3
+
+#define KEYP_CTRL_SCAN_ROWS_SHIFT 2
+#define KEYP_CTRL_SCAN_ROWS_MIN 5
+#define KEYP_CTRL_SCAN_ROWS_BITS 0x7
+
+#define KEYP_CTRL_KEYP_EN BIT(7)
+
+#define KEYP_SCAN 0x149
+
+#define KEYP_SCAN_READ_STATE BIT(0)
+#define KEYP_SCAN_DBOUNCE_SHIFT 1
+#define KEYP_SCAN_PAUSE_SHIFT 3
+#define KEYP_SCAN_ROW_HOLD_SHIFT 6
+
+#define KEYP_TEST 0x14A
+
+#define KEYP_TEST_CLEAR_RECENT_SCAN BIT(6)
+#define KEYP_TEST_CLEAR_OLD_SCAN BIT(5)
+#define KEYP_TEST_READ_RESET BIT(4)
+#define KEYP_TEST_DTEST_EN BIT(3)
+#define KEYP_TEST_ABORT_READ BIT(0)
+
+#define KEYP_TEST_DBG_SELECT_SHIFT 1
+
+/* bits of these registers represent
+ * '0' for key press
+ * '1' for key release
+ */
+#define KEYP_RECENT_DATA 0x14B
+#define KEYP_OLD_DATA 0x14C
+
+#define KEYP_CLOCK_FREQ 32768
+
+/**
+ * struct pmic8xxx_kp - internal keypad data structure
+ * @pdata - keypad platform data pointer
+ * @input - input device pointer for keypad
+ * @key_sense_irq - key press/release irq number
+ * @key_stuck_irq - key stuck notification irq number
+ * @keycodes - array to hold the key codes
+ * @dev - parent device pointer
+ * @keystate - present key press/release state
+ * @stuckstate - present state when key stuck irq
+ * @ctrl_reg - control register value
+ */
+struct pmic8xxx_kp {
+ const struct pm8xxx_keypad_platform_data *pdata;
+ struct input_dev *input;
+ int key_sense_irq;
+ int key_stuck_irq;
+
+ unsigned short keycodes[PM8XXX_MATRIX_MAX_SIZE];
+
+ struct device *dev;
+ u16 keystate[PM8XXX_MAX_ROWS];
+ u16 stuckstate[PM8XXX_MAX_ROWS];
+
+ u8 ctrl_reg;
+};
+
+static int pmic8xxx_kp_write_u8(struct pmic8xxx_kp *kp,
+ u8 data, u16 reg)
+{
+ int rc;
+
+ rc = pm8xxx_writeb(kp->dev->parent, reg, data);
+ return rc;
+}
+
+static int pmic8xxx_kp_read(struct pmic8xxx_kp *kp,
+ u8 *data, u16 reg, unsigned num_bytes)
+{
+ int rc;
+
+ rc = pm8xxx_read_buf(kp->dev->parent, reg, data, num_bytes);
+ return rc;
+}
+
+static int pmic8xxx_kp_read_u8(struct pmic8xxx_kp *kp,
+ u8 *data, u16 reg)
+{
+ int rc;
+
+ rc = pmic8xxx_kp_read(kp, data, reg, 1);
+ return rc;
+}
+
+static u8 pmic8xxx_col_state(struct pmic8xxx_kp *kp, u8 col)
+{
+ /* all keys pressed on that particular row? */
+ if (col == 0x00)
+ return 1 << kp->pdata->num_cols;
+ else
+ return col & ((1 << kp->pdata->num_cols) - 1);
+}
+
+/*
+ * Synchronous read protocol for RevB0 onwards:
+ *
+ * 1. Write '1' to ReadState bit in KEYP_SCAN register
+ * 2. Wait 2*32KHz clocks, so that HW can successfully enter read mode
+ * synchronously
+ * 3. Read rows in old array first if events are more than one
+ * 4. Read rows in recent array
+ * 5. Wait 4*32KHz clocks
+ * 6. Write '0' to ReadState bit of KEYP_SCAN register so that hw can
+ * synchronously exit read mode.
+ */
+static int pmic8xxx_chk_sync_read(struct pmic8xxx_kp *kp)
+{
+ int rc;
+ u8 scan_val;
+
+ rc = pmic8xxx_kp_read_u8(kp, &scan_val, KEYP_SCAN);
+ if (rc < 0) {
+ dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc);
+ return rc;
+ }
+
+ scan_val |= 0x1;
+
+ rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN);
+ if (rc < 0) {
+ dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc);
+ return rc;
+ }
+
+ /* 2 * 32KHz clocks */
+ udelay((2 * DIV_ROUND_UP(USEC_PER_SEC, KEYP_CLOCK_FREQ)) + 1);
+
+ return rc;
+}
+
+static int pmic8xxx_kp_read_data(struct pmic8xxx_kp *kp, u16 *state,
+ u16 data_reg, int read_rows)
+{
+ int rc, row;
+ u8 new_data[PM8XXX_MAX_ROWS];
+
+ rc = pmic8xxx_kp_read(kp, new_data, data_reg, read_rows);
+ if (rc)
+ return rc;
+
+ for (row = 0; row < kp->pdata->num_rows; row++) {
+ dev_dbg(kp->dev, "new_data[%d] = %d\n", row,
+ new_data[row]);
+ state[row] = pmic8xxx_col_state(kp, new_data[row]);
+ }
+
+ return rc;
+}
+
+static int pmic8xxx_kp_read_matrix(struct pmic8xxx_kp *kp, u16 *new_state,
+ u16 *old_state)
+{
+ int rc, read_rows;
+ u8 scan_val;
+
+ if (kp->pdata->num_rows < PM8XXX_MIN_ROWS)
+ read_rows = PM8XXX_MIN_ROWS;
+ else
+ read_rows = kp->pdata->num_rows;
+
+ pmic8xxx_chk_sync_read(kp);
+
+ if (old_state) {
+ rc = pmic8xxx_kp_read_data(kp, old_state, KEYP_OLD_DATA,
+ read_rows);
+ if (rc < 0) {
+ dev_err(kp->dev,
+ "Error reading KEYP_OLD_DATA, rc=%d\n", rc);
+ return rc;
+ }
+ }
+
+ rc = pmic8xxx_kp_read_data(kp, new_state, KEYP_RECENT_DATA,
+ read_rows);
+ if (rc < 0) {
+ dev_err(kp->dev,
+ "Error reading KEYP_RECENT_DATA, rc=%d\n", rc);
+ return rc;
+ }
+
+ /* 4 * 32KHz clocks */
+ udelay((4 * DIV_ROUND_UP(USEC_PER_SEC, KEYP_CLOCK_FREQ)) + 1);
+
+ rc = pmic8xxx_kp_read_u8(kp, &scan_val, KEYP_SCAN);
+ if (rc < 0) {
+ dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc);
+ return rc;
+ }
+
+ scan_val &= 0xFE;
+ rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN);
+ if (rc < 0)
+ dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc);
+
+ return rc;
+}
+
+static void __pmic8xxx_kp_scan_matrix(struct pmic8xxx_kp *kp, u16 *new_state,
+ u16 *old_state)
+{
+ int row, col, code;
+
+ for (row = 0; row < kp->pdata->num_rows; row++) {
+ int bits_changed = new_state[row] ^ old_state[row];
+
+ if (!bits_changed)
+ continue;
+
+ for (col = 0; col < kp->pdata->num_cols; col++) {
+ if (!(bits_changed & (1 << col)))
+ continue;
+
+ dev_dbg(kp->dev, "key [%d:%d] %s\n", row, col,
+ !(new_state[row] & (1 << col)) ?
+ "pressed" : "released");
+
+ code = MATRIX_SCAN_CODE(row, col, PM8XXX_ROW_SHIFT);
+
+ input_event(kp->input, EV_MSC, MSC_SCAN, code);
+ input_report_key(kp->input,
+ kp->keycodes[code],
+ !(new_state[row] & (1 << col)));
+
+ input_sync(kp->input);
+ }
+ }
+}
+
+static bool pmic8xxx_detect_ghost_keys(struct pmic8xxx_kp *kp, u16 *new_state)
+{
+ int row, found_first = -1;
+ u16 check, row_state;
+
+ check = 0;
+ for (row = 0; row < kp->pdata->num_rows; row++) {
+ row_state = (~new_state[row]) &
+ ((1 << kp->pdata->num_cols) - 1);
+
+ if (hweight16(row_state) > 1) {
+ if (found_first == -1)
+ found_first = row;
+ if (check & row_state) {
+ dev_dbg(kp->dev, "detected ghost key on row[%d]"
+ " and row[%d]\n", found_first, row);
+ return true;
+ }
+ }
+ check |= row_state;
+ }
+ return false;
+}
+
+static int pmic8xxx_kp_scan_matrix(struct pmic8xxx_kp *kp, unsigned int events)
+{
+ u16 new_state[PM8XXX_MAX_ROWS];
+ u16 old_state[PM8XXX_MAX_ROWS];
+ int rc;
+
+ switch (events) {
+ case 0x1:
+ rc = pmic8xxx_kp_read_matrix(kp, new_state, NULL);
+ if (rc < 0)
+ return rc;
+
+ /* detecting ghost key is not an error */
+ if (pmic8xxx_detect_ghost_keys(kp, new_state))
+ return 0;
+ __pmic8xxx_kp_scan_matrix(kp, new_state, kp->keystate);
+ memcpy(kp->keystate, new_state, sizeof(new_state));
+ break;
+ case 0x3: /* two events - eventcounter is gray-coded */
+ rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state);
+ if (rc < 0)
+ return rc;
+
+ __pmic8xxx_kp_scan_matrix(kp, old_state, kp->keystate);
+ __pmic8xxx_kp_scan_matrix(kp, new_state, old_state);
+ memcpy(kp->keystate, new_state, sizeof(new_state));
+ break;
+ case 0x2:
+ dev_dbg(kp->dev, "Some key events were lost\n");
+ rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state);
+ if (rc < 0)
+ return rc;
+ __pmic8xxx_kp_scan_matrix(kp, old_state, kp->keystate);
+ __pmic8xxx_kp_scan_matrix(kp, new_state, old_state);
+ memcpy(kp->keystate, new_state, sizeof(new_state));
+ break;
+ default:
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+/*
+ * NOTE: We are reading recent and old data registers blindly
+ * whenever key-stuck interrupt happens, because events counter doesn't
+ * get updated when this interrupt happens due to key stuck doesn't get
+ * considered as key state change.
+ *
+ * We are not using old data register contents after they are being read
+ * because it might report the key which was pressed before the key being stuck
+ * as stuck key because it's pressed status is stored in the old data
+ * register.
+ */
+static irqreturn_t pmic8xxx_kp_stuck_irq(int irq, void *data)
+{
+ u16 new_state[PM8XXX_MAX_ROWS];
+ u16 old_state[PM8XXX_MAX_ROWS];
+ int rc;
+ struct pmic8xxx_kp *kp = data;
+
+ rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state);
+ if (rc < 0) {
+ dev_err(kp->dev, "failed to read keypad matrix\n");
+ return IRQ_HANDLED;
+ }
+
+ __pmic8xxx_kp_scan_matrix(kp, new_state, kp->stuckstate);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t pmic8xxx_kp_irq(int irq, void *data)
+{
+ struct pmic8xxx_kp *kp = data;
+ u8 ctrl_val, events;
+ int rc;
+
+ rc = pmic8xxx_kp_read(kp, &ctrl_val, KEYP_CTRL, 1);
+ if (rc < 0) {
+ dev_err(kp->dev, "failed to read keyp_ctrl register\n");
+ return IRQ_HANDLED;
+ }
+
+ events = ctrl_val & KEYP_CTRL_EVNTS_MASK;
+
+ rc = pmic8xxx_kp_scan_matrix(kp, events);
+ if (rc < 0)
+ dev_err(kp->dev, "failed to scan matrix\n");
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit pmic8xxx_kpd_init(struct pmic8xxx_kp *kp)
+{
+ int bits, rc, cycles;
+ u8 scan_val = 0, ctrl_val = 0;
+ static const u8 row_bits[] = {
+ 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7,
+ };
+
+ /* Find column bits */
+ if (kp->pdata->num_cols < KEYP_CTRL_SCAN_COLS_MIN)
+ bits = 0;
+ else
+ bits = kp->pdata->num_cols - KEYP_CTRL_SCAN_COLS_MIN;
+ ctrl_val = (bits & KEYP_CTRL_SCAN_COLS_BITS) <<
+ KEYP_CTRL_SCAN_COLS_SHIFT;
+
+ /* Find row bits */
+ if (kp->pdata->num_rows < KEYP_CTRL_SCAN_ROWS_MIN)
+ bits = 0;
+ else
+ bits = row_bits[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN];
+
+ ctrl_val |= (bits << KEYP_CTRL_SCAN_ROWS_SHIFT);
+
+ rc = pmic8xxx_kp_write_u8(kp, ctrl_val, KEYP_CTRL);
+ if (rc < 0) {
+ dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc);
+ return rc;
+ }
+
+ bits = (kp->pdata->debounce_ms / 5) - 1;
+
+ scan_val |= (bits << KEYP_SCAN_DBOUNCE_SHIFT);
+
+ bits = fls(kp->pdata->scan_delay_ms) - 1;
+ scan_val |= (bits << KEYP_SCAN_PAUSE_SHIFT);
+
+ /* Row hold time is a multiple of 32KHz cycles. */
+ cycles = (kp->pdata->row_hold_ns * KEYP_CLOCK_FREQ) / NSEC_PER_SEC;
+
+ scan_val |= (cycles << KEYP_SCAN_ROW_HOLD_SHIFT);
+
+ rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN);
+ if (rc)
+ dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc);
+
+ return rc;
+
+}
+
+static int __devinit pmic8xxx_kp_config_gpio(int gpio_start, int num_gpios,
+ struct pmic8xxx_kp *kp, struct pm_gpio *gpio_config)
+{
+ int rc, i;
+
+ if (gpio_start < 0 || num_gpios < 0)
+ return -EINVAL;
+
+ for (i = 0; i < num_gpios; i++) {
+ rc = pm8xxx_gpio_config(gpio_start + i, gpio_config);
+ if (rc) {
+ dev_err(kp->dev, "%s: FAIL pm8xxx_gpio_config():"
+ "for PM GPIO [%d] rc=%d.\n",
+ __func__, gpio_start + i, rc);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+static int pmic8xxx_kp_enable(struct pmic8xxx_kp *kp)
+{
+ int rc;
+
+ kp->ctrl_reg |= KEYP_CTRL_KEYP_EN;
+
+ rc = pmic8xxx_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL);
+ if (rc < 0)
+ dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc);
+
+ return rc;
+}
+
+static int pmic8xxx_kp_disable(struct pmic8xxx_kp *kp)
+{
+ int rc;
+
+ kp->ctrl_reg &= ~KEYP_CTRL_KEYP_EN;
+
+ rc = pmic8xxx_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL);
+ if (rc < 0)
+ return rc;
+
+ return rc;
+}
+
+static int pmic8xxx_kp_open(struct input_dev *dev)
+{
+ struct pmic8xxx_kp *kp = input_get_drvdata(dev);
+
+ return pmic8xxx_kp_enable(kp);
+}
+
+static void pmic8xxx_kp_close(struct input_dev *dev)
+{
+ struct pmic8xxx_kp *kp = input_get_drvdata(dev);
+
+ pmic8xxx_kp_disable(kp);
+}
+
+/*
+ * keypad controller should be initialized in the following sequence
+ * only, otherwise it might get into FSM stuck state.
+ *
+ * - Initialize keypad control parameters, like no. of rows, columns,
+ * timing values etc.,
+ * - configure rows and column gpios pull up/down.
+ * - set irq edge type.
+ * - enable the keypad controller.
+ */
+static int __devinit pmic8xxx_kp_probe(struct platform_device *pdev)
+{
+ const struct pm8xxx_keypad_platform_data *pdata = mfd_get_data(pdev);
+ const struct matrix_keymap_data *keymap_data;
+ struct pmic8xxx_kp *kp;
+ int rc;
+ u8 ctrl_val;
+
+ struct pm_gpio kypd_drv = {
+ .direction = PM_GPIO_DIR_OUT,
+ .output_buffer = PM_GPIO_OUT_BUF_OPEN_DRAIN,
+ .output_value = 0,
+ .pull = PM_GPIO_PULL_NO,
+ .vin_sel = PM_GPIO_VIN_S3,
+ .out_strength = PM_GPIO_STRENGTH_LOW,
+ .function = PM_GPIO_FUNC_1,
+ .inv_int_pol = 1,
+ };
+
+ struct pm_gpio kypd_sns = {
+ .direction = PM_GPIO_DIR_IN,
+ .pull = PM_GPIO_PULL_UP_31P5,
+ .vin_sel = PM_GPIO_VIN_S3,
+ .out_strength = PM_GPIO_STRENGTH_NO,
+ .function = PM_GPIO_FUNC_NORMAL,
+ .inv_int_pol = 1,
+ };
+
+
+ if (!pdata || !pdata->num_cols || !pdata->num_rows ||
+ pdata->num_cols > PM8XXX_MAX_COLS ||
+ pdata->num_rows > PM8XXX_MAX_ROWS ||
+ pdata->num_cols < PM8XXX_MIN_COLS) {
+ dev_err(&pdev->dev, "invalid platform data\n");
+ return -EINVAL;
+ }
+
+ if (!pdata->scan_delay_ms ||
+ pdata->scan_delay_ms > MAX_SCAN_DELAY ||
+ pdata->scan_delay_ms < MIN_SCAN_DELAY ||
+ !is_power_of_2(pdata->scan_delay_ms)) {
+ dev_err(&pdev->dev, "invalid keypad scan time supplied\n");
+ return -EINVAL;
+ }
+
+ if (!pdata->row_hold_ns ||
+ pdata->row_hold_ns > MAX_ROW_HOLD_DELAY ||
+ pdata->row_hold_ns < MIN_ROW_HOLD_DELAY ||
+ ((pdata->row_hold_ns % MIN_ROW_HOLD_DELAY) != 0)) {
+ dev_err(&pdev->dev, "invalid keypad row hold time supplied\n");
+ return -EINVAL;
+ }
+
+ if (!pdata->debounce_ms ||
+ ((pdata->debounce_ms % 5) != 0) ||
+ pdata->debounce_ms > MAX_DEBOUNCE_TIME ||
+ pdata->debounce_ms < MIN_DEBOUNCE_TIME) {
+ dev_err(&pdev->dev, "invalid debounce time supplied\n");
+ return -EINVAL;
+ }
+
+ keymap_data = pdata->keymap_data;
+ if (!keymap_data) {
+ dev_err(&pdev->dev, "no keymap data supplied\n");
+ return -EINVAL;
+ }
+
+ kp = kzalloc(sizeof(*kp), GFP_KERNEL);
+ if (!kp)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, kp);
+
+ kp->pdata = pdata;
+ kp->dev = &pdev->dev;
+
+ kp->input = input_allocate_device();
+ if (!kp->input) {
+ dev_err(&pdev->dev, "unable to allocate input device\n");
+ rc = -ENOMEM;
+ goto err_alloc_device;
+ }
+
+ kp->key_sense_irq = platform_get_irq(pdev, 0);
+ if (kp->key_sense_irq < 0) {
+ dev_err(&pdev->dev, "unable to get keypad sense irq\n");
+ rc = -ENXIO;
+ goto err_get_irq;
+ }
+
+ kp->key_stuck_irq = platform_get_irq(pdev, 1);
+ if (kp->key_stuck_irq < 0) {
+ dev_err(&pdev->dev, "unable to get keypad stuck irq\n");
+ rc = -ENXIO;
+ goto err_get_irq;
+ }
+
+ kp->input->name = pdata->input_name ? : "PMIC8XXX keypad";
+ kp->input->phys = pdata->input_phys_device ? : "pmic8xxx_keypad/input0";
+
+ kp->input->dev.parent = &pdev->dev;
+
+ kp->input->id.bustype = BUS_I2C;
+ kp->input->id.version = 0x0001;
+ kp->input->id.product = 0x0001;
+ kp->input->id.vendor = 0x0001;
+
+ kp->input->evbit[0] = BIT_MASK(EV_KEY);
+
+ if (pdata->rep)
+ __set_bit(EV_REP, kp->input->evbit);
+
+ kp->input->keycode = kp->keycodes;
+ kp->input->keycodemax = PM8XXX_MATRIX_MAX_SIZE;
+ kp->input->keycodesize = sizeof(kp->keycodes);
+ kp->input->open = pmic8xxx_kp_open;
+ kp->input->close = pmic8xxx_kp_close;
+
+ matrix_keypad_build_keymap(keymap_data, PM8XXX_ROW_SHIFT,
+ kp->input->keycode, kp->input->keybit);
+
+ input_set_capability(kp->input, EV_MSC, MSC_SCAN);
+ input_set_drvdata(kp->input, kp);
+
+ /* initialize keypad state */
+ memset(kp->keystate, 0xff, sizeof(kp->keystate));
+ memset(kp->stuckstate, 0xff, sizeof(kp->stuckstate));
+
+ rc = pmic8xxx_kpd_init(kp);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "unable to initialize keypad controller\n");
+ goto err_get_irq;
+ }
+
+ rc = pmic8xxx_kp_config_gpio(pdata->cols_gpio_start,
+ pdata->num_cols, kp, &kypd_sns);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "unable to configure keypad sense lines\n");
+ goto err_gpio_config;
+ }
+
+ rc = pmic8xxx_kp_config_gpio(pdata->rows_gpio_start,
+ pdata->num_rows, kp, &kypd_drv);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "unable to configure keypad drive lines\n");
+ goto err_gpio_config;
+ }
+
+ rc = request_any_context_irq(kp->key_sense_irq, pmic8xxx_kp_irq,
+ IRQF_TRIGGER_RISING, "pmic-keypad", kp);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "failed to request keypad sense irq\n");
+ goto err_get_irq;
+ }
+
+ rc = request_any_context_irq(kp->key_stuck_irq, pmic8xxx_kp_stuck_irq,
+ IRQF_TRIGGER_RISING, "pmic-keypad-stuck", kp);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "failed to request keypad stuck irq\n");
+ goto err_req_stuck_irq;
+ }
+
+ rc = pmic8xxx_kp_read_u8(kp, &ctrl_val, KEYP_CTRL);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "failed to read KEYP_CTRL register\n");
+ goto err_pmic_reg_read;
+ }
+
+ kp->ctrl_reg = ctrl_val;
+
+ rc = input_register_device(kp->input);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "unable to register keypad input device\n");
+ goto err_pmic_reg_read;
+ }
+
+ device_init_wakeup(&pdev->dev, pdata->wakeup);
+
+ return 0;
+
+err_pmic_reg_read:
+ free_irq(kp->key_stuck_irq, NULL);
+err_req_stuck_irq:
+ free_irq(kp->key_sense_irq, NULL);
+err_gpio_config:
+err_get_irq:
+ input_free_device(kp->input);
+err_alloc_device:
+ platform_set_drvdata(pdev, NULL);
+ kfree(kp);
+ return rc;
+}
+
+static int __devexit pmic8xxx_kp_remove(struct platform_device *pdev)
+{
+ struct pmic8xxx_kp *kp = platform_get_drvdata(pdev);
+
+ device_init_wakeup(&pdev->dev, 0);
+ free_irq(kp->key_stuck_irq, NULL);
+ free_irq(kp->key_sense_irq, NULL);
+ input_unregister_device(kp->input);
+ kfree(kp);
+
+ platform_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pmic8xxx_kp_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct pmic8xxx_kp *kp = platform_get_drvdata(pdev);
+ struct input_dev *input_dev = kp->input;
+
+ if (device_may_wakeup(dev)) {
+ enable_irq_wake(kp->key_sense_irq);
+ } else {
+ mutex_lock(&input_dev->mutex);
+
+ if (input_dev->users)
+ pmic8xxx_kp_disable(kp);
+
+ mutex_unlock(&input_dev->mutex);
+ }
+
+ return 0;
+}
+
+static int pmic8xxx_kp_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct pmic8xxx_kp *kp = platform_get_drvdata(pdev);
+ struct input_dev *input_dev = kp->input;
+
+ if (device_may_wakeup(dev)) {
+ disable_irq_wake(kp->key_sense_irq);
+ } else {
+ mutex_lock(&input_dev->mutex);
+
+ if (input_dev->users)
+ pmic8xxx_kp_enable(kp);
+
+ mutex_unlock(&input_dev->mutex);
+ }
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm8xxx_kp_pm_ops,
+ pmic8xxx_kp_suspend, pmic8xxx_kp_resume);
+
+static struct platform_driver pmic8xxx_kp_driver = {
+ .probe = pmic8xxx_kp_probe,
+ .remove = __devexit_p(pmic8xxx_kp_remove),
+ .driver = {
+ .name = PM8XXX_KEYPAD_DEV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &pm8xxx_kp_pm_ops,
+ },
+};
+
+static int __init pmic8xxx_kp_init(void)
+{
+ return platform_driver_register(&pmic8xxx_kp_driver);
+}
+module_init(pmic8xxx_kp_init);
+
+static void __exit pmic8xxx_kp_exit(void)
+{
+ platform_driver_unregister(&pmic8xxx_kp_driver);
+}
+module_exit(pmic8xxx_kp_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PMIC8XXX keypad driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:pmic8xxx_keypad");
+MODULE_AUTHOR("Trilok Soni <tsoni@codeaurora.org>");
diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c
index fba8404c7297..ca7b89196ab7 100644
--- a/drivers/input/keyboard/qt1070.c
+++ b/drivers/input/keyboard/qt1070.c
@@ -248,6 +248,7 @@ static const struct i2c_device_id qt1070_id[] = {
{ "qt1070", 0 },
{ },
};
+MODULE_DEVICE_TABLE(i2c, qt1070_id);
static struct i2c_driver qt1070_driver = {
.driver = {
diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c
index d7dafd9425b6..834cf98e7efb 100644
--- a/drivers/input/keyboard/sh_keysc.c
+++ b/drivers/input/keyboard/sh_keysc.c
@@ -20,7 +20,7 @@
#include <linux/input.h>
#include <linux/input/sh_keysc.h>
#include <linux/bitmap.h>
-#include <linux/clk.h>
+#include <linux/pm_runtime.h>
#include <linux/io.h>
#include <linux/slab.h>
@@ -37,7 +37,6 @@ static const struct {
struct sh_keysc_priv {
void __iomem *iomem_base;
- struct clk *clk;
DECLARE_BITMAP(last_keys, SH_KEYSC_MAXKEYS);
struct input_dev *input;
struct sh_keysc_info pdata;
@@ -169,7 +168,6 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
struct sh_keysc_info *pdata;
struct resource *res;
struct input_dev *input;
- char clk_name[8];
int i;
int irq, error;
@@ -210,19 +208,11 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
goto err1;
}
- snprintf(clk_name, sizeof(clk_name), "keysc%d", pdev->id);
- priv->clk = clk_get(&pdev->dev, clk_name);
- if (IS_ERR(priv->clk)) {
- dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name);
- error = PTR_ERR(priv->clk);
- goto err2;
- }
-
priv->input = input_allocate_device();
if (!priv->input) {
dev_err(&pdev->dev, "failed to allocate input device\n");
error = -ENOMEM;
- goto err3;
+ goto err2;
}
input = priv->input;
@@ -241,10 +231,11 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
input->keycodesize = sizeof(pdata->keycodes[0]);
input->keycodemax = ARRAY_SIZE(pdata->keycodes);
- error = request_irq(irq, sh_keysc_isr, 0, pdev->name, pdev);
+ error = request_threaded_irq(irq, NULL, sh_keysc_isr, IRQF_ONESHOT,
+ dev_name(&pdev->dev), pdev);
if (error) {
dev_err(&pdev->dev, "failed to request IRQ\n");
- goto err4;
+ goto err3;
}
for (i = 0; i < SH_KEYSC_MAXKEYS; i++)
@@ -254,10 +245,11 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
error = input_register_device(input);
if (error) {
dev_err(&pdev->dev, "failed to register input device\n");
- goto err5;
+ goto err4;
}
- clk_enable(priv->clk);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
sh_keysc_write(priv, KYCR1, (sh_keysc_mode[pdata->mode].kymd << 8) |
pdata->scan_timing);
@@ -267,12 +259,10 @@ static int __devinit sh_keysc_probe(struct platform_device *pdev)
return 0;
- err5:
- free_irq(irq, pdev);
err4:
- input_free_device(input);
+ free_irq(irq, pdev);
err3:
- clk_put(priv->clk);
+ input_free_device(input);
err2:
iounmap(priv->iomem_base);
err1:
@@ -292,8 +282,8 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev)
free_irq(platform_get_irq(pdev, 0), pdev);
iounmap(priv->iomem_base);
- clk_disable(priv->clk);
- clk_put(priv->clk);
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
platform_set_drvdata(pdev, NULL);
kfree(priv);
@@ -301,6 +291,7 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev)
return 0;
}
+#if CONFIG_PM_SLEEP
static int sh_keysc_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -311,14 +302,13 @@ static int sh_keysc_suspend(struct device *dev)
value = sh_keysc_read(priv, KYCR1);
if (device_may_wakeup(dev)) {
- value |= 0x80;
+ sh_keysc_write(priv, KYCR1, value | 0x80);
enable_irq_wake(irq);
} else {
- value &= ~0x80;
+ sh_keysc_write(priv, KYCR1, value & ~0x80);
+ pm_runtime_put_sync(dev);
}
- sh_keysc_write(priv, KYCR1, value);
-
return 0;
}
@@ -329,16 +319,17 @@ static int sh_keysc_resume(struct device *dev)
if (device_may_wakeup(dev))
disable_irq_wake(irq);
+ else
+ pm_runtime_get_sync(dev);
return 0;
}
+#endif
-static const struct dev_pm_ops sh_keysc_dev_pm_ops = {
- .suspend = sh_keysc_suspend,
- .resume = sh_keysc_resume,
-};
+static SIMPLE_DEV_PM_OPS(sh_keysc_dev_pm_ops,
+ sh_keysc_suspend, sh_keysc_resume);
-struct platform_driver sh_keysc_device_driver = {
+static struct platform_driver sh_keysc_device_driver = {
.probe = sh_keysc_probe,
.remove = __devexit_p(sh_keysc_remove),
.driver = {
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c
index 99ce9032d08c..2b3b73ec6689 100644
--- a/drivers/input/keyboard/tegra-kbc.c
+++ b/drivers/input/keyboard/tegra-kbc.c
@@ -66,12 +66,11 @@ struct tegra_kbc {
void __iomem *mmio;
struct input_dev *idev;
unsigned int irq;
- unsigned int wake_enable_rows;
- unsigned int wake_enable_cols;
spinlock_t lock;
unsigned int repoll_dly;
unsigned long cp_dly_jiffies;
bool use_fn_map;
+ bool use_ghost_filter;
const struct tegra_kbc_platform_data *pdata;
unsigned short keycode[KBC_MAX_KEY * 2];
unsigned short current_keys[KBC_MAX_KPENT];
@@ -260,6 +259,8 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
unsigned int num_down = 0;
unsigned long flags;
bool fn_keypress = false;
+ bool key_in_same_row = false;
+ bool key_in_same_col = false;
spin_lock_irqsave(&kbc->lock, flags);
for (i = 0; i < KBC_MAX_KPENT; i++) {
@@ -285,6 +286,34 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
}
/*
+ * Matrix keyboard designs are prone to keyboard ghosting.
+ * Ghosting occurs if there are 3 keys such that -
+ * any 2 of the 3 keys share a row, and any 2 of them share a column.
+ * If so ignore the key presses for this iteration.
+ */
+ if ((kbc->use_ghost_filter) && (num_down >= 3)) {
+ for (i = 0; i < num_down; i++) {
+ unsigned int j;
+ u8 curr_col = scancodes[i] & 0x07;
+ u8 curr_row = scancodes[i] >> KBC_ROW_SHIFT;
+
+ /*
+ * Find 2 keys such that one key is in the same row
+ * and the other is in the same column as the i-th key.
+ */
+ for (j = i + 1; j < num_down; j++) {
+ u8 col = scancodes[j] & 0x07;
+ u8 row = scancodes[j] >> KBC_ROW_SHIFT;
+
+ if (col == curr_col)
+ key_in_same_col = true;
+ if (row == curr_row)
+ key_in_same_row = true;
+ }
+ }
+ }
+
+ /*
* If the platform uses Fn keymaps, translate keys on a Fn keypress.
* Function keycodes are KBC_MAX_KEY apart from the plain keycodes.
*/
@@ -297,6 +326,10 @@ static void tegra_kbc_report_keys(struct tegra_kbc *kbc)
spin_unlock_irqrestore(&kbc->lock, flags);
+ /* Ignore the key presses for this iteration? */
+ if (key_in_same_col && key_in_same_row)
+ return;
+
tegra_kbc_report_released_keys(kbc->idev,
kbc->current_keys, kbc->num_pressed_keys,
keycodes, num_down);
@@ -383,21 +416,11 @@ static void tegra_kbc_setup_wakekeys(struct tegra_kbc *kbc, bool filter)
int i;
unsigned int rst_val;
- BUG_ON(pdata->wake_cnt > KBC_MAX_KEY);
- rst_val = (filter && pdata->wake_cnt) ? ~0 : 0;
+ /* Either mask all keys or none. */
+ rst_val = (filter && !pdata->wakeup) ? ~0 : 0;
for (i = 0; i < KBC_MAX_ROW; i++)
writel(rst_val, kbc->mmio + KBC_ROW0_MASK_0 + i * 4);
-
- if (filter) {
- for (i = 0; i < pdata->wake_cnt; i++) {
- u32 val, addr;
- addr = pdata->wake_cfg[i].row * 4 + KBC_ROW0_MASK_0;
- val = readl(kbc->mmio + addr);
- val &= ~(1 << pdata->wake_cfg[i].col);
- writel(val, kbc->mmio + addr);
- }
- }
}
static void tegra_kbc_config_pins(struct tegra_kbc *kbc)
@@ -559,7 +582,6 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
struct resource *res;
int irq;
int err;
- int i;
int num_rows = 0;
unsigned int debounce_cnt;
unsigned int scan_time_rows;
@@ -616,13 +638,6 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
goto err_iounmap;
}
- kbc->wake_enable_rows = 0;
- kbc->wake_enable_cols = 0;
- for (i = 0; i < pdata->wake_cnt; i++) {
- kbc->wake_enable_rows |= (1 << pdata->wake_cfg[i].row);
- kbc->wake_enable_cols |= (1 << pdata->wake_cfg[i].col);
- }
-
/*
* The time delay between two consecutive reads of the FIFO is
* the sum of the repeat time and the time taken for scanning
@@ -652,6 +667,7 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev)
input_dev->keycodemax *= 2;
kbc->use_fn_map = pdata->use_fn_map;
+ kbc->use_ghost_filter = pdata->use_ghost_filter;
keymap_data = pdata->keymap_data ?: &tegra_kbc_default_keymap_data;
matrix_keypad_build_keymap(keymap_data, KBC_ROW_SHIFT,
input_dev->keycode, input_dev->keybit);
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index f9cf0881b0e3..45dc6aa62ba4 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -330,6 +330,17 @@ config INPUT_PWM_BEEPER
To compile this driver as a module, choose M here: the module will be
called pwm-beeper.
+config INPUT_PMIC8XXX_PWRKEY
+ tristate "PMIC8XXX power key support"
+ depends on MFD_PM8XXX
+ help
+ Say Y here if you want support for the PMIC8XXX power key.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called pmic8xxx-pwrkey.
+
config INPUT_GPIO_ROTARY_ENCODER
tristate "Rotary encoders connected to GPIO pins"
depends on GPIOLIB && GENERIC_GPIO
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index e3f7984e6274..38efb2cb182b 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -33,6 +33,7 @@ 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_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.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 c431d09e401a..c3a62c42cd28 100644
--- a/drivers/input/misc/ad714x.c
+++ b/drivers/input/misc/ad714x.c
@@ -79,13 +79,7 @@ struct ad714x_slider_drv {
struct ad714x_wheel_drv {
int abs_pos;
int flt_pos;
- int pre_mean_value;
int pre_highest_stage;
- int pre_mean_value_no_offset;
- int mean_value;
- int mean_value_no_offset;
- int pos_offset;
- int pos_ratio;
int highest_stage;
enum ad714x_device_state state;
struct input_dev *input;
@@ -158,10 +152,10 @@ static void ad714x_use_com_int(struct ad714x_chip *ad714x,
unsigned short data;
unsigned short mask;
- mask = ((1 << (end_stage + 1)) - 1) - (1 << start_stage);
+ mask = ((1 << (end_stage + 1)) - 1) - ((1 << start_stage) - 1);
ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data);
- data |= 1 << start_stage;
+ data |= 1 << end_stage;
ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data);
ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data);
@@ -175,10 +169,10 @@ static void ad714x_use_thr_int(struct ad714x_chip *ad714x,
unsigned short data;
unsigned short mask;
- mask = ((1 << (end_stage + 1)) - 1) - (1 << start_stage);
+ mask = ((1 << (end_stage + 1)) - 1) - ((1 << start_stage) - 1);
ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data);
- data &= ~(1 << start_stage);
+ data &= ~(1 << end_stage);
ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data);
ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data);
@@ -404,7 +398,6 @@ static void ad714x_slider_state_machine(struct ad714x_chip *ad714x, int idx)
ad714x_slider_cal_highest_stage(ad714x, idx);
ad714x_slider_cal_abs_pos(ad714x, idx);
ad714x_slider_cal_flt_pos(ad714x, idx);
-
input_report_abs(sw->input, ABS_X, sw->flt_pos);
input_report_key(sw->input, BTN_TOUCH, 1);
} else {
@@ -468,104 +461,41 @@ static void ad714x_wheel_cal_sensor_val(struct ad714x_chip *ad714x, int idx)
/*
* When the scroll wheel is activated, we compute the absolute position based
* on the sensor values. To calculate the position, we first determine the
- * sensor that has the greatest response among the 8 sensors that constitutes
- * the scrollwheel. Then we determined the 2 sensors on either sides of the
+ * sensor that has the greatest response among the sensors that constitutes
+ * the scrollwheel. Then we determined the sensors on either sides of the
* sensor with the highest response and we apply weights to these sensors. The
- * result of this computation gives us the mean value which defined by the
- * following formula:
- * For i= second_before_highest_stage to i= second_after_highest_stage
- * v += Sensor response(i)*WEIGHT*(i+3)
- * w += Sensor response(i)
- * Mean_Value=v/w
- * pos_on_scrollwheel = (Mean_Value - position_offset) / position_ratio
+ * result of this computation gives us the mean value.
*/
-#define WEIGHT_FACTOR 30
-/* This constant prevents the "PositionOffset" from reaching a big value */
-#define OFFSET_POSITION_CLAMP 120
static void ad714x_wheel_cal_abs_pos(struct ad714x_chip *ad714x, int idx)
{
struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
struct ad714x_wheel_drv *sw = &ad714x->sw->wheel[idx];
int stage_num = hw->end_stage - hw->start_stage + 1;
- int second_before, first_before, highest, first_after, second_after;
+ int first_before, highest, first_after;
int a_param, b_param;
- /* Calculate Mean value */
-
- second_before = (sw->highest_stage + stage_num - 2) % stage_num;
first_before = (sw->highest_stage + stage_num - 1) % stage_num;
highest = sw->highest_stage;
first_after = (sw->highest_stage + stage_num + 1) % stage_num;
- second_after = (sw->highest_stage + stage_num + 2) % stage_num;
-
- if (((sw->highest_stage - hw->start_stage) > 1) &&
- ((hw->end_stage - sw->highest_stage) > 1)) {
- a_param = ad714x->sensor_val[second_before] *
- (second_before - hw->start_stage + 3) +
- ad714x->sensor_val[first_before] *
- (second_before - hw->start_stage + 3) +
- ad714x->sensor_val[highest] *
- (second_before - hw->start_stage + 3) +
- ad714x->sensor_val[first_after] *
- (first_after - hw->start_stage + 3) +
- ad714x->sensor_val[second_after] *
- (second_after - hw->start_stage + 3);
- } else {
- a_param = ad714x->sensor_val[second_before] *
- (second_before - hw->start_stage + 1) +
- ad714x->sensor_val[first_before] *
- (second_before - hw->start_stage + 2) +
- ad714x->sensor_val[highest] *
- (second_before - hw->start_stage + 3) +
- ad714x->sensor_val[first_after] *
- (first_after - hw->start_stage + 4) +
- ad714x->sensor_val[second_after] *
- (second_after - hw->start_stage + 5);
- }
- a_param *= WEIGHT_FACTOR;
- b_param = ad714x->sensor_val[second_before] +
+ a_param = ad714x->sensor_val[highest] *
+ (highest - hw->start_stage) +
+ ad714x->sensor_val[first_before] *
+ (highest - hw->start_stage - 1) +
+ ad714x->sensor_val[first_after] *
+ (highest - hw->start_stage + 1);
+ b_param = ad714x->sensor_val[highest] +
ad714x->sensor_val[first_before] +
- ad714x->sensor_val[highest] +
- ad714x->sensor_val[first_after] +
- ad714x->sensor_val[second_after];
-
- sw->pre_mean_value = sw->mean_value;
- sw->mean_value = a_param / b_param;
-
- /* Calculate the offset */
-
- if ((sw->pre_highest_stage == hw->end_stage) &&
- (sw->highest_stage == hw->start_stage))
- sw->pos_offset = sw->mean_value;
- else if ((sw->pre_highest_stage == hw->start_stage) &&
- (sw->highest_stage == hw->end_stage))
- sw->pos_offset = sw->pre_mean_value;
-
- if (sw->pos_offset > OFFSET_POSITION_CLAMP)
- sw->pos_offset = OFFSET_POSITION_CLAMP;
-
- /* Calculate the mean value without the offset */
-
- sw->pre_mean_value_no_offset = sw->mean_value_no_offset;
- sw->mean_value_no_offset = sw->mean_value - sw->pos_offset;
- if (sw->mean_value_no_offset < 0)
- sw->mean_value_no_offset = 0;
-
- /* Calculate ratio to scale down to NUMBER_OF_WANTED_POSITIONS */
-
- if ((sw->pre_highest_stage == hw->end_stage) &&
- (sw->highest_stage == hw->start_stage))
- sw->pos_ratio = (sw->pre_mean_value_no_offset * 100) /
- hw->max_coord;
- else if ((sw->pre_highest_stage == hw->start_stage) &&
- (sw->highest_stage == hw->end_stage))
- sw->pos_ratio = (sw->mean_value_no_offset * 100) /
- hw->max_coord;
- sw->abs_pos = (sw->mean_value_no_offset * 100) / sw->pos_ratio;
+ ad714x->sensor_val[first_after];
+
+ sw->abs_pos = ((hw->max_coord / (hw->end_stage - hw->start_stage)) *
+ a_param) / b_param;
+
if (sw->abs_pos > hw->max_coord)
sw->abs_pos = hw->max_coord;
+ else if (sw->abs_pos < 0)
+ sw->abs_pos = 0;
}
static void ad714x_wheel_cal_flt_pos(struct ad714x_chip *ad714x, int idx)
@@ -639,9 +569,8 @@ static void ad714x_wheel_state_machine(struct ad714x_chip *ad714x, int idx)
ad714x_wheel_cal_highest_stage(ad714x, idx);
ad714x_wheel_cal_abs_pos(ad714x, idx);
ad714x_wheel_cal_flt_pos(ad714x, idx);
-
input_report_abs(sw->input, ABS_WHEEL,
- sw->abs_pos);
+ sw->flt_pos);
input_report_key(sw->input, BTN_TOUCH, 1);
} else {
/* When the user lifts off the sensor, configure
@@ -1149,6 +1078,8 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
input[alloc_idx]->id.bustype = bus_type;
input[alloc_idx]->id.product = ad714x->product;
input[alloc_idx]->id.version = ad714x->version;
+ input[alloc_idx]->name = "ad714x_captouch_slider";
+ input[alloc_idx]->dev.parent = dev;
error = input_register_device(input[alloc_idx]);
if (error)
@@ -1179,6 +1110,8 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
input[alloc_idx]->id.bustype = bus_type;
input[alloc_idx]->id.product = ad714x->product;
input[alloc_idx]->id.version = ad714x->version;
+ input[alloc_idx]->name = "ad714x_captouch_wheel";
+ input[alloc_idx]->dev.parent = dev;
error = input_register_device(input[alloc_idx]);
if (error)
@@ -1212,6 +1145,8 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
input[alloc_idx]->id.bustype = bus_type;
input[alloc_idx]->id.product = ad714x->product;
input[alloc_idx]->id.version = ad714x->version;
+ input[alloc_idx]->name = "ad714x_captouch_pad";
+ input[alloc_idx]->dev.parent = dev;
error = input_register_device(input[alloc_idx]);
if (error)
@@ -1240,6 +1175,8 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
input[alloc_idx]->id.bustype = bus_type;
input[alloc_idx]->id.product = ad714x->product;
input[alloc_idx]->id.version = ad714x->version;
+ input[alloc_idx]->name = "ad714x_captouch_button";
+ input[alloc_idx]->dev.parent = dev;
error = input_register_device(input[alloc_idx]);
if (error)
@@ -1249,7 +1186,9 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
}
error = request_threaded_irq(ad714x->irq, NULL, ad714x_interrupt_thread,
- IRQF_TRIGGER_FALLING, "ad714x_captouch", ad714x);
+ plat_data->irqflags ?
+ plat_data->irqflags : IRQF_TRIGGER_FALLING,
+ "ad714x_captouch", ad714x);
if (error) {
dev_err(dev, "can't allocate irq %d\n", ad714x->irq);
goto err_unreg_dev;
diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c
index 9ccdb82d869a..1de58e8a1b71 100644
--- a/drivers/input/misc/ati_remote2.c
+++ b/drivers/input/misc/ati_remote2.c
@@ -737,14 +737,17 @@ static ssize_t ati_remote2_store_channel_mask(struct device *dev,
mutex_lock(&ati_remote2_mutex);
- if (mask != ar2->channel_mask && !ati_remote2_setup(ar2, mask))
- ar2->channel_mask = mask;
+ if (mask != ar2->channel_mask) {
+ r = ati_remote2_setup(ar2, mask);
+ if (!r)
+ ar2->channel_mask = mask;
+ }
mutex_unlock(&ati_remote2_mutex);
usb_autopm_put_interface(ar2->intf[0]);
- return count;
+ return r ? r : count;
}
static ssize_t ati_remote2_show_mode_mask(struct device *dev,
diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c
new file mode 100644
index 000000000000..97e07e786e41
--- /dev/null
+++ b/drivers/input/misc/pmic8xxx-pwrkey.c
@@ -0,0 +1,231 @@
+/* Copyright (c) 2010-2011, 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/log2.h>
+
+#include <linux/mfd/pm8xxx/core.h>
+#include <linux/input/pmic8xxx-pwrkey.h>
+
+#define PON_CNTL_1 0x1C
+#define PON_CNTL_PULL_UP BIT(7)
+#define PON_CNTL_TRIG_DELAY_MASK (0x7)
+
+/**
+ * struct pmic8xxx_pwrkey - pmic8xxx pwrkey information
+ * @key_press_irq: key press irq number
+ */
+struct pmic8xxx_pwrkey {
+ struct input_dev *pwr;
+ int key_press_irq;
+};
+
+static irqreturn_t pwrkey_press_irq(int irq, void *_pwrkey)
+{
+ struct pmic8xxx_pwrkey *pwrkey = _pwrkey;
+
+ input_report_key(pwrkey->pwr, KEY_POWER, 1);
+ input_sync(pwrkey->pwr);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t pwrkey_release_irq(int irq, void *_pwrkey)
+{
+ struct pmic8xxx_pwrkey *pwrkey = _pwrkey;
+
+ input_report_key(pwrkey->pwr, KEY_POWER, 0);
+ input_sync(pwrkey->pwr);
+
+ return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pmic8xxx_pwrkey_suspend(struct device *dev)
+{
+ struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(pwrkey->key_press_irq);
+
+ return 0;
+}
+
+static int pmic8xxx_pwrkey_resume(struct device *dev)
+{
+ struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(pwrkey->key_press_irq);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm8xxx_pwr_key_pm_ops,
+ pmic8xxx_pwrkey_suspend, pmic8xxx_pwrkey_resume);
+
+static int __devinit pmic8xxx_pwrkey_probe(struct platform_device *pdev)
+{
+ struct input_dev *pwr;
+ int key_release_irq = platform_get_irq(pdev, 0);
+ int key_press_irq = platform_get_irq(pdev, 1);
+ int err;
+ unsigned int delay;
+ u8 pon_cntl;
+ struct pmic8xxx_pwrkey *pwrkey;
+ const struct pm8xxx_pwrkey_platform_data *pdata = mfd_get_data(pdev);
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "power key platform data not supplied\n");
+ return -EINVAL;
+ }
+
+ if (pdata->kpd_trigger_delay_us > 62500) {
+ dev_err(&pdev->dev, "invalid power key trigger delay\n");
+ return -EINVAL;
+ }
+
+ pwrkey = kzalloc(sizeof(*pwrkey), GFP_KERNEL);
+ if (!pwrkey)
+ return -ENOMEM;
+
+ pwr = input_allocate_device();
+ if (!pwr) {
+ dev_dbg(&pdev->dev, "Can't allocate power button\n");
+ err = -ENOMEM;
+ goto free_pwrkey;
+ }
+
+ input_set_capability(pwr, EV_KEY, KEY_POWER);
+
+ pwr->name = "pmic8xxx_pwrkey";
+ pwr->phys = "pmic8xxx_pwrkey/input0";
+ pwr->dev.parent = &pdev->dev;
+
+ delay = (pdata->kpd_trigger_delay_us << 10) / USEC_PER_SEC;
+ delay = 1 + ilog2(delay);
+
+ err = pm8xxx_readb(pdev->dev.parent, PON_CNTL_1, &pon_cntl);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed reading PON_CNTL_1 err=%d\n", err);
+ goto free_input_dev;
+ }
+
+ pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK;
+ pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK);
+ if (pdata->pull_up)
+ pon_cntl |= PON_CNTL_PULL_UP;
+ else
+ pon_cntl &= ~PON_CNTL_PULL_UP;
+
+ err = pm8xxx_writeb(pdev->dev.parent, PON_CNTL_1, pon_cntl);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed writing PON_CNTL_1 err=%d\n", err);
+ goto free_input_dev;
+ }
+
+ err = input_register_device(pwr);
+ if (err) {
+ dev_dbg(&pdev->dev, "Can't register power key: %d\n", err);
+ goto free_input_dev;
+ }
+
+ pwrkey->key_press_irq = key_press_irq;
+ pwrkey->pwr = pwr;
+
+ platform_set_drvdata(pdev, pwrkey);
+
+ err = request_irq(key_press_irq, pwrkey_press_irq,
+ IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_press", pwrkey);
+ if (err < 0) {
+ dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
+ key_press_irq, err);
+ goto unreg_input_dev;
+ }
+
+ err = request_irq(key_release_irq, pwrkey_release_irq,
+ IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_release", pwrkey);
+ if (err < 0) {
+ dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n",
+ key_release_irq, err);
+
+ goto free_press_irq;
+ }
+
+ device_init_wakeup(&pdev->dev, pdata->wakeup);
+
+ return 0;
+
+free_press_irq:
+ free_irq(key_press_irq, NULL);
+unreg_input_dev:
+ platform_set_drvdata(pdev, NULL);
+ input_unregister_device(pwr);
+ pwr = NULL;
+free_input_dev:
+ input_free_device(pwr);
+free_pwrkey:
+ kfree(pwrkey);
+ return err;
+}
+
+static int __devexit pmic8xxx_pwrkey_remove(struct platform_device *pdev)
+{
+ struct pmic8xxx_pwrkey *pwrkey = platform_get_drvdata(pdev);
+ int key_release_irq = platform_get_irq(pdev, 0);
+ int key_press_irq = platform_get_irq(pdev, 1);
+
+ device_init_wakeup(&pdev->dev, 0);
+
+ free_irq(key_press_irq, pwrkey);
+ free_irq(key_release_irq, pwrkey);
+ input_unregister_device(pwrkey->pwr);
+ platform_set_drvdata(pdev, NULL);
+ kfree(pwrkey);
+
+ return 0;
+}
+
+static struct platform_driver pmic8xxx_pwrkey_driver = {
+ .probe = pmic8xxx_pwrkey_probe,
+ .remove = __devexit_p(pmic8xxx_pwrkey_remove),
+ .driver = {
+ .name = PM8XXX_PWRKEY_DEV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &pm8xxx_pwr_key_pm_ops,
+ },
+};
+
+static int __init pmic8xxx_pwrkey_init(void)
+{
+ return platform_driver_register(&pmic8xxx_pwrkey_driver);
+}
+module_init(pmic8xxx_pwrkey_init);
+
+static void __exit pmic8xxx_pwrkey_exit(void)
+{
+ platform_driver_unregister(&pmic8xxx_pwrkey_driver);
+}
+module_exit(pmic8xxx_pwrkey_exit);
+
+MODULE_ALIAS("platform:pmic8xxx_pwrkey");
+MODULE_DESCRIPTION("PMIC8XXX Power Key driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Trilok Soni <tsoni@codeaurora.org>");
diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c
index 7e64d01da2be..2c8b84dd9dac 100644
--- a/drivers/input/misc/rotary_encoder.c
+++ b/drivers/input/misc/rotary_encoder.c
@@ -2,6 +2,7 @@
* rotary_encoder.c
*
* (c) 2009 Daniel Mack <daniel@caiaq.de>
+ * Copyright (C) 2011 Johan Hovold <jhovold@gmail.com>
*
* state machine code inspired by code from Tim Ruetz
*
@@ -38,52 +39,66 @@ struct rotary_encoder {
bool armed;
unsigned char dir; /* 0 - clockwise, 1 - CCW */
+
+ char last_stable;
};
-static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
+static int rotary_encoder_get_state(struct rotary_encoder_platform_data *pdata)
{
- struct rotary_encoder *encoder = dev_id;
- struct rotary_encoder_platform_data *pdata = encoder->pdata;
int a = !!gpio_get_value(pdata->gpio_a);
int b = !!gpio_get_value(pdata->gpio_b);
- int state;
a ^= pdata->inverted_a;
b ^= pdata->inverted_b;
- state = (a << 1) | b;
- switch (state) {
+ return ((a << 1) | b);
+}
- case 0x0:
- if (!encoder->armed)
- break;
+static void rotary_encoder_report_event(struct rotary_encoder *encoder)
+{
+ struct rotary_encoder_platform_data *pdata = encoder->pdata;
- if (pdata->relative_axis) {
- input_report_rel(encoder->input, pdata->axis,
- encoder->dir ? -1 : 1);
- } else {
- unsigned int pos = encoder->pos;
-
- if (encoder->dir) {
- /* turning counter-clockwise */
- if (pdata->rollover)
- pos += pdata->steps;
- if (pos)
- pos--;
- } else {
- /* turning clockwise */
- if (pdata->rollover || pos < pdata->steps)
- pos++;
- }
+ if (pdata->relative_axis) {
+ input_report_rel(encoder->input,
+ pdata->axis, encoder->dir ? -1 : 1);
+ } else {
+ unsigned int pos = encoder->pos;
+
+ if (encoder->dir) {
+ /* turning counter-clockwise */
if (pdata->rollover)
- pos %= pdata->steps;
- encoder->pos = pos;
- input_report_abs(encoder->input, pdata->axis,
- encoder->pos);
+ pos += pdata->steps;
+ if (pos)
+ pos--;
+ } else {
+ /* turning clockwise */
+ if (pdata->rollover || pos < pdata->steps)
+ pos++;
}
- input_sync(encoder->input);
- encoder->armed = false;
+ if (pdata->rollover)
+ pos %= pdata->steps;
+
+ encoder->pos = pos;
+ input_report_abs(encoder->input, pdata->axis, encoder->pos);
+ }
+
+ input_sync(encoder->input);
+}
+
+static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
+{
+ struct rotary_encoder *encoder = dev_id;
+ int state;
+
+ state = rotary_encoder_get_state(encoder->pdata);
+
+ switch (state) {
+ case 0x0:
+ if (encoder->armed) {
+ rotary_encoder_report_event(encoder);
+ encoder->armed = false;
+ }
break;
case 0x1:
@@ -100,11 +115,37 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
+{
+ struct rotary_encoder *encoder = dev_id;
+ int state;
+
+ state = rotary_encoder_get_state(encoder->pdata);
+
+ switch (state) {
+ case 0x00:
+ case 0x03:
+ if (state != encoder->last_stable) {
+ rotary_encoder_report_event(encoder);
+ encoder->last_stable = state;
+ }
+ break;
+
+ case 0x01:
+ case 0x02:
+ encoder->dir = (encoder->last_stable + state) & 0x01;
+ break;
+ }
+
+ return IRQ_HANDLED;
+}
+
static int __devinit rotary_encoder_probe(struct platform_device *pdev)
{
struct rotary_encoder_platform_data *pdata = pdev->dev.platform_data;
struct rotary_encoder *encoder;
struct input_dev *input;
+ irq_handler_t handler;
int err;
if (!pdata) {
@@ -175,7 +216,14 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
}
/* request the IRQs */
- err = request_irq(encoder->irq_a, &rotary_encoder_irq,
+ if (pdata->half_period) {
+ handler = &rotary_encoder_half_period_irq;
+ encoder->last_stable = rotary_encoder_get_state(pdata);
+ } else {
+ handler = &rotary_encoder_irq;
+ }
+
+ err = request_irq(encoder->irq_a, handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
DRV_NAME, encoder);
if (err) {
@@ -184,7 +232,7 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
goto exit_free_gpio_b;
}
- err = request_irq(encoder->irq_b, &rotary_encoder_irq,
+ err = request_irq(encoder->irq_b, handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
DRV_NAME, encoder);
if (err) {
@@ -252,6 +300,5 @@ module_exit(rotary_encoder_exit);
MODULE_ALIAS("platform:" DRV_NAME);
MODULE_DESCRIPTION("GPIO rotary encoder driver");
-MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
+MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>, Johan Hovold");
MODULE_LICENSE("GPL v2");
-
diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c
index f16972bddca4..38e4b507b94c 100644
--- a/drivers/input/misc/twl4030-pwrbutton.c
+++ b/drivers/input/misc/twl4030-pwrbutton.c
@@ -89,7 +89,7 @@ static int __init twl4030_pwrbutton_probe(struct platform_device *pdev)
return 0;
free_irq:
- free_irq(irq, NULL);
+ free_irq(irq, pwr);
free_input_dev:
input_free_device(pwr);
return err;
diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c
index 6a11694e3fc7..014dd4ad0d4f 100644
--- a/drivers/input/misc/twl4030-vibra.c
+++ b/drivers/input/misc/twl4030-vibra.c
@@ -29,7 +29,6 @@
#include <linux/workqueue.h>
#include <linux/i2c/twl.h>
#include <linux/mfd/twl4030-codec.h>
-#include <linux/mfd/core.h>
#include <linux/input.h>
#include <linux/slab.h>
@@ -197,7 +196,7 @@ static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops,
static int __devinit twl4030_vibra_probe(struct platform_device *pdev)
{
- struct twl4030_codec_vibra_data *pdata = mfd_get_data(pdev);
+ struct twl4030_codec_vibra_data *pdata = pdev->dev.platform_data;
struct vibra_info *info;
int ret;
diff --git a/drivers/input/mouse/atarimouse.c b/drivers/input/mouse/atarimouse.c
index adf45b3040e9..5c4a692bf73a 100644
--- a/drivers/input/mouse/atarimouse.c
+++ b/drivers/input/mouse/atarimouse.c
@@ -77,15 +77,15 @@ static void atamouse_interrupt(char *buf)
#endif
/* only relative events get here */
- dx = buf[1];
- dy = -buf[2];
+ dx = buf[1];
+ dy = buf[2];
input_report_rel(atamouse_dev, REL_X, dx);
input_report_rel(atamouse_dev, REL_Y, dy);
- input_report_key(atamouse_dev, BTN_LEFT, buttons & 0x1);
+ input_report_key(atamouse_dev, BTN_LEFT, buttons & 0x4);
input_report_key(atamouse_dev, BTN_MIDDLE, buttons & 0x2);
- input_report_key(atamouse_dev, BTN_RIGHT, buttons & 0x4);
+ input_report_key(atamouse_dev, BTN_RIGHT, buttons & 0x1);
input_sync(atamouse_dev);
@@ -108,7 +108,7 @@ static int atamouse_open(struct input_dev *dev)
static void atamouse_close(struct input_dev *dev)
{
ikbd_mouse_disable();
- atari_mouse_interrupt_hook = NULL;
+ atari_input_mouse_interrupt_hook = NULL;
}
static int __init atamouse_init(void)
@@ -118,8 +118,9 @@ static int __init atamouse_init(void)
if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP))
return -ENODEV;
- if (!atari_keyb_init())
- return -ENODEV;
+ error = atari_keyb_init();
+ if (error)
+ return error;
atamouse_dev = input_allocate_device();
if (!atamouse_dev)
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 04d9bf320a4f..32503565faf9 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -16,6 +16,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/input.h>
+#include <linux/input/mt.h>
#include <linux/serio.h>
#include <linux/libps2.h>
#include "psmouse.h"
@@ -242,15 +243,37 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse)
input_sync(dev);
}
+static void elantech_set_slot(struct input_dev *dev, int slot, bool active,
+ unsigned int x, unsigned int y)
+{
+ input_mt_slot(dev, slot);
+ input_mt_report_slot_state(dev, MT_TOOL_FINGER, active);
+ if (active) {
+ input_report_abs(dev, ABS_MT_POSITION_X, x);
+ input_report_abs(dev, ABS_MT_POSITION_Y, y);
+ }
+}
+
+/* x1 < x2 and y1 < y2 when two fingers, x = y = 0 when not pressed */
+static void elantech_report_semi_mt_data(struct input_dev *dev,
+ unsigned int num_fingers,
+ unsigned int x1, unsigned int y1,
+ unsigned int x2, unsigned int y2)
+{
+ elantech_set_slot(dev, 0, num_fingers != 0, x1, y1);
+ elantech_set_slot(dev, 1, num_fingers == 2, x2, y2);
+}
+
/*
* Interpret complete data packets and report absolute mode input events for
* hardware version 2. (6 byte packets)
*/
static void elantech_report_absolute_v2(struct psmouse *psmouse)
{
+ struct elantech_data *etd = psmouse->private;
struct input_dev *dev = psmouse->dev;
unsigned char *packet = psmouse->packet;
- int fingers, x1, y1, x2, y2;
+ unsigned int fingers, x1 = 0, y1 = 0, x2 = 0, y2 = 0, width = 0, pres = 0;
/* byte 0: n1 n0 . . . . R L */
fingers = (packet[0] & 0xc0) >> 6;
@@ -270,14 +293,18 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
* byte 1: . . . . . x10 x9 x8
* byte 2: x7 x6 x5 x4 x4 x2 x1 x0
*/
- input_report_abs(dev, ABS_X,
- ((packet[1] & 0x07) << 8) | packet[2]);
+ x1 = ((packet[1] & 0x07) << 8) | packet[2];
/*
* byte 4: . . . . . . y9 y8
* byte 5: y7 y6 y5 y4 y3 y2 y1 y0
*/
- input_report_abs(dev, ABS_Y,
- ETP_YMAX_V2 - (((packet[4] & 0x03) << 8) | packet[5]));
+ y1 = ETP_YMAX_V2 - (((packet[4] & 0x03) << 8) | packet[5]);
+
+ input_report_abs(dev, ABS_X, x1);
+ input_report_abs(dev, ABS_Y, y1);
+
+ pres = (packet[1] & 0xf0) | ((packet[4] & 0xf0) >> 4);
+ width = ((packet[0] & 0x30) >> 2) | ((packet[3] & 0x30) >> 4);
break;
case 2:
@@ -303,23 +330,24 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
*/
input_report_abs(dev, ABS_X, x1 << 2);
input_report_abs(dev, ABS_Y, y1 << 2);
- /*
- * For compatibility with the proprietary X Elantech driver
- * report both coordinates as hat coordinates
- */
- input_report_abs(dev, ABS_HAT0X, x1);
- input_report_abs(dev, ABS_HAT0Y, y1);
- input_report_abs(dev, ABS_HAT1X, x2);
- input_report_abs(dev, ABS_HAT1Y, y2);
+
+ /* Unknown so just report sensible values */
+ pres = 127;
+ width = 7;
break;
}
+ elantech_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
input_report_key(dev, BTN_TOOL_FINGER, fingers == 1);
input_report_key(dev, BTN_TOOL_DOUBLETAP, fingers == 2);
input_report_key(dev, BTN_TOOL_TRIPLETAP, fingers == 3);
input_report_key(dev, BTN_TOOL_QUADTAP, fingers == 4);
input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+ if (etd->reports_pressure) {
+ input_report_abs(dev, ABS_PRESSURE, pres);
+ input_report_abs(dev, ABS_TOOL_WIDTH, width);
+ }
input_sync(dev);
}
@@ -478,10 +506,16 @@ static void elantech_set_input_params(struct psmouse *psmouse)
__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
input_set_abs_params(dev, ABS_X, ETP_XMIN_V2, ETP_XMAX_V2, 0, 0);
input_set_abs_params(dev, ABS_Y, ETP_YMIN_V2, ETP_YMAX_V2, 0, 0);
- input_set_abs_params(dev, ABS_HAT0X, ETP_2FT_XMIN, ETP_2FT_XMAX, 0, 0);
- input_set_abs_params(dev, ABS_HAT0Y, ETP_2FT_YMIN, ETP_2FT_YMAX, 0, 0);
- input_set_abs_params(dev, ABS_HAT1X, ETP_2FT_XMIN, ETP_2FT_XMAX, 0, 0);
- input_set_abs_params(dev, ABS_HAT1Y, ETP_2FT_YMIN, ETP_2FT_YMAX, 0, 0);
+ if (etd->reports_pressure) {
+ input_set_abs_params(dev, ABS_PRESSURE, ETP_PMIN_V2,
+ ETP_PMAX_V2, 0, 0);
+ input_set_abs_params(dev, ABS_TOOL_WIDTH, ETP_WMIN_V2,
+ ETP_WMAX_V2, 0, 0);
+ }
+ __set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
+ input_mt_init_slots(dev, 2);
+ input_set_abs_params(dev, ABS_MT_POSITION_X, ETP_XMIN_V2, ETP_XMAX_V2, 0, 0);
+ input_set_abs_params(dev, ABS_MT_POSITION_Y, ETP_YMIN_V2, ETP_YMAX_V2, 0, 0);
break;
}
}
@@ -725,6 +759,10 @@ int elantech_init(struct psmouse *psmouse)
etd->debug = 1;
/* Don't know how to do parity checking for version 2 */
etd->paritycheck = 0;
+
+ if (etd->fw_version >= 0x020800)
+ etd->reports_pressure = true;
+
} else {
etd->hw_version = 1;
etd->paritycheck = 1;
diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h
index aa4aac5d2198..fabb2b99615c 100644
--- a/drivers/input/mouse/elantech.h
+++ b/drivers/input/mouse/elantech.h
@@ -77,6 +77,11 @@
#define ETP_YMIN_V2 ( 0 + ETP_EDGE_FUZZ_V2)
#define ETP_YMAX_V2 ( 768 - ETP_EDGE_FUZZ_V2)
+#define ETP_PMIN_V2 0
+#define ETP_PMAX_V2 255
+#define ETP_WMIN_V2 0
+#define ETP_WMAX_V2 15
+
/*
* For two finger touches the coordinate of each finger gets reported
* separately but with reduced resolution.
@@ -102,6 +107,7 @@ struct elantech_data {
unsigned char capabilities;
bool paritycheck;
bool jumpy_cursor;
+ bool reports_pressure;
unsigned char hw_version;
unsigned int fw_version;
unsigned int single_finger_reports;
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 7630273e9474..257e033986e4 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -508,7 +508,6 @@ static void mousedev_attach_client(struct mousedev *mousedev,
spin_lock(&mousedev->client_lock);
list_add_tail_rcu(&client->node, &mousedev->client_list);
spin_unlock(&mousedev->client_lock);
- synchronize_rcu();
}
static void mousedev_detach_client(struct mousedev *mousedev,
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
index 8755f5f3ad37..f3698967edf6 100644
--- a/drivers/input/serio/serport.c
+++ b/drivers/input/serio/serport.c
@@ -120,17 +120,21 @@ static void serport_ldisc_close(struct tty_struct *tty)
* 'interrupt' routine.
*/
-static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+static unsigned int serport_ldisc_receive(struct tty_struct *tty,
+ const unsigned char *cp, char *fp, int count)
{
struct serport *serport = (struct serport*) tty->disc_data;
unsigned long flags;
unsigned int ch_flags;
+ int ret = 0;
int i;
spin_lock_irqsave(&serport->lock, flags);
- if (!test_bit(SERPORT_ACTIVE, &serport->flags))
+ if (!test_bit(SERPORT_ACTIVE, &serport->flags)) {
+ ret = -EINVAL;
goto out;
+ }
for (i = 0; i < count; i++) {
switch (fp[i]) {
@@ -152,6 +156,8 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c
out:
spin_unlock_irqrestore(&serport->lock, flags);
+
+ return ret == 0 ? count : ret;
}
/*
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 434fd800cd24..cabd9e54863f 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -248,6 +248,18 @@ config TOUCHSCREEN_LPC32XX
To compile this driver as a module, choose M here: the
module will be called lpc32xx_ts.
+config TOUCHSCREEN_MAX11801
+ tristate "MAX11801 based touchscreens"
+ depends on I2C
+ help
+ Say Y here if you have a MAX11801 based touchscreen
+ controller.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called max11801_ts.
+
config TOUCHSCREEN_MCS5000
tristate "MELFAS MCS-5000 touchscreen"
depends on I2C
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index ca94098d4c92..282d6f76ae26 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o
obj-$(CONFIG_TOUCHSCREEN_LPC32XX) += lpc32xx_ts.o
+obj-$(CONFIG_TOUCHSCREEN_MAX11801) += max11801_ts.o
obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o
obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.o
obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 1de1c19dad30..5196861b86ef 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -109,6 +109,7 @@ struct ads7846 {
u16 pressure_max;
bool swap_xy;
+ bool use_internal;
struct ads7846_packet *packet;
@@ -307,7 +308,6 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
struct ads7846 *ts = dev_get_drvdata(dev);
struct ser_req *req;
int status;
- int use_internal;
req = kzalloc(sizeof *req, GFP_KERNEL);
if (!req)
@@ -315,11 +315,8 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
spi_message_init(&req->msg);
- /* FIXME boards with ads7846 might use external vref instead ... */
- use_internal = (ts->model == 7846);
-
/* maybe turn on internal vREF, and let it settle */
- if (use_internal) {
+ if (ts->use_internal) {
req->ref_on = REF_ON;
req->xfer[0].tx_buf = &req->ref_on;
req->xfer[0].len = 1;
@@ -331,8 +328,14 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
/* for 1uF, settle for 800 usec; no cap, 100 usec. */
req->xfer[1].delay_usecs = ts->vref_delay_usecs;
spi_message_add_tail(&req->xfer[1], &req->msg);
+
+ /* Enable reference voltage */
+ command |= ADS_PD10_REF_ON;
}
+ /* Enable ADC in every case */
+ command |= ADS_PD10_ADC_ON;
+
/* take sample */
req->command = (u8) command;
req->xfer[2].tx_buf = &req->command;
@@ -416,7 +419,7 @@ name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \
{ \
struct ads7846 *ts = dev_get_drvdata(dev); \
ssize_t v = ads7846_read12_ser(dev, \
- READ_12BIT_SER(var) | ADS_PD10_ALL_ON); \
+ READ_12BIT_SER(var)); \
if (v < 0) \
return v; \
return sprintf(buf, "%u\n", adjust(ts, v)); \
@@ -509,6 +512,7 @@ static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)
if (!ts->vref_mv) {
dev_dbg(&spi->dev, "assuming 2.5V internal vREF\n");
ts->vref_mv = 2500;
+ ts->use_internal = true;
}
break;
case 7845:
@@ -969,6 +973,13 @@ static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads784
pdata->gpio_pendown);
return err;
}
+ err = gpio_direction_input(pdata->gpio_pendown);
+ if (err) {
+ dev_err(&spi->dev, "failed to setup pendown GPIO%d\n",
+ pdata->gpio_pendown);
+ gpio_free(pdata->gpio_pendown);
+ return err;
+ }
ts->gpio_pendown = pdata->gpio_pendown;
@@ -1340,8 +1351,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
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);
+ (void) ads7846_read12_ser(&spi->dev, READ_12BIT_SER(vaux));
err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group);
if (err)
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 4012436633b1..1e61387c73ca 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -17,7 +17,7 @@
#include <linux/firmware.h>
#include <linux/i2c.h>
#include <linux/i2c/atmel_mxt_ts.h>
-#include <linux/input.h>
+#include <linux/input/mt.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
@@ -196,9 +196,12 @@
#define MXT_PRESS (1 << 6)
#define MXT_DETECT (1 << 7)
+/* Touch orient bits */
+#define MXT_XY_SWITCH (1 << 0)
+#define MXT_X_INVERT (1 << 1)
+#define MXT_Y_INVERT (1 << 2)
+
/* Touchscreen absolute values */
-#define MXT_MAX_XC 0x3ff
-#define MXT_MAX_YC 0x3ff
#define MXT_MAX_AREA 0xff
#define MXT_MAX_FINGER 10
@@ -246,6 +249,8 @@ struct mxt_data {
struct mxt_info info;
struct mxt_finger finger[MXT_MAX_FINGER];
unsigned int irq;
+ unsigned int max_x;
+ unsigned int max_y;
};
static bool mxt_object_readable(unsigned int type)
@@ -499,19 +504,21 @@ static void mxt_input_report(struct mxt_data *data, int single_id)
if (!finger[id].status)
continue;
- input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,
- finger[id].status != MXT_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);
+ input_mt_slot(input_dev, id);
+ input_mt_report_slot_state(input_dev, MT_TOOL_FINGER,
+ finger[id].status != MXT_RELEASE);
- if (finger[id].status == MXT_RELEASE)
- finger[id].status = 0;
- else
+ if (finger[id].status != MXT_RELEASE) {
finger_num++;
+ input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,
+ finger[id].area);
+ input_report_abs(input_dev, ABS_MT_POSITION_X,
+ finger[id].x);
+ input_report_abs(input_dev, ABS_MT_POSITION_Y,
+ finger[id].y);
+ } else {
+ finger[id].status = 0;
+ }
}
input_report_key(input_dev, BTN_TOUCH, finger_num > 0);
@@ -549,8 +556,13 @@ static void mxt_input_touchevent(struct mxt_data *data,
if (!(status & (MXT_PRESS | MXT_MOVE)))
return;
- x = (message->message[1] << 2) | ((message->message[3] & ~0x3f) >> 6);
- y = (message->message[2] << 2) | ((message->message[3] & ~0xf3) >> 2);
+ x = (message->message[1] << 4) | ((message->message[3] >> 4) & 0xf);
+ y = (message->message[2] << 4) | ((message->message[3] & 0xf));
+ if (data->max_x < 1024)
+ x = x >> 2;
+ if (data->max_y < 1024)
+ y = y >> 2;
+
area = message->message[4];
dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id,
@@ -804,10 +816,6 @@ static int mxt_initialize(struct mxt_data *data)
if (error)
return error;
- error = mxt_make_highchg(data);
- if (error)
- return error;
-
mxt_handle_pdata(data);
/* Backup to memory */
@@ -845,6 +853,20 @@ static int mxt_initialize(struct mxt_data *data)
return 0;
}
+static void mxt_calc_resolution(struct mxt_data *data)
+{
+ unsigned int max_x = data->pdata->x_size - 1;
+ unsigned int max_y = data->pdata->y_size - 1;
+
+ if (data->pdata->orient & MXT_XY_SWITCH) {
+ data->max_x = max_y;
+ data->max_y = max_x;
+ } else {
+ data->max_x = max_x;
+ data->max_y = max_y;
+ }
+}
+
static ssize_t mxt_object_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -981,6 +1003,10 @@ static ssize_t mxt_update_fw_store(struct device *dev,
enable_irq(data->irq);
+ error = mxt_make_highchg(data);
+ if (error)
+ return error;
+
return count;
}
@@ -1052,31 +1078,33 @@ static int __devinit mxt_probe(struct i2c_client *client,
input_dev->open = mxt_input_open;
input_dev->close = mxt_input_close;
+ data->client = client;
+ data->input_dev = input_dev;
+ data->pdata = pdata;
+ data->irq = client->irq;
+
+ mxt_calc_resolution(data);
+
__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, MXT_MAX_XC, 0, 0);
+ 0, data->max_x, 0, 0);
input_set_abs_params(input_dev, ABS_Y,
- 0, MXT_MAX_YC, 0, 0);
+ 0, data->max_y, 0, 0);
/* For multi touch */
+ input_mt_init_slots(input_dev, MXT_MAX_FINGER);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
0, MXT_MAX_AREA, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
- 0, MXT_MAX_XC, 0, 0);
+ 0, data->max_x, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
- 0, MXT_MAX_YC, 0, 0);
+ 0, data->max_y, 0, 0);
input_set_drvdata(input_dev, data);
-
- data->client = client;
- data->input_dev = input_dev;
- data->pdata = pdata;
- data->irq = client->irq;
-
i2c_set_clientdata(client, data);
error = mxt_initialize(data);
@@ -1090,6 +1118,10 @@ static int __devinit mxt_probe(struct i2c_client *client,
goto err_free_object;
}
+ error = mxt_make_highchg(data);
+ if (error)
+ goto err_free_irq;
+
error = input_register_device(input_dev);
if (error)
goto err_free_irq;
diff --git a/drivers/input/touchscreen/atmel_tsadcc.c b/drivers/input/touchscreen/atmel_tsadcc.c
index 3d9b5166ebe9..432c69be6ac6 100644
--- a/drivers/input/touchscreen/atmel_tsadcc.c
+++ b/drivers/input/touchscreen/atmel_tsadcc.c
@@ -317,7 +317,7 @@ err_unmap_regs:
err_release_mem:
release_mem_region(res->start, resource_size(res));
err_free_dev:
- input_free_device(ts_dev->input);
+ input_free_device(input_dev);
err_free_mem:
kfree(ts_dev);
return err;
diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c
index 45f93d0f5592..211811ae5525 100644
--- a/drivers/input/touchscreen/h3600_ts_input.c
+++ b/drivers/input/touchscreen/h3600_ts_input.c
@@ -396,14 +396,14 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
- IRQF_SHARED | IRQF_DISABLED, "h3600_action", &ts->dev)) {
+ IRQF_SHARED | IRQF_DISABLED, "h3600_action", ts->dev)) {
printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
err = -EBUSY;
goto fail1;
}
if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
- IRQF_SHARED | IRQF_DISABLED, "h3600_suspend", &ts->dev)) {
+ IRQF_SHARED | IRQF_DISABLED, "h3600_suspend", ts->dev)) {
printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n");
err = -EBUSY;
goto fail2;
@@ -439,8 +439,8 @@ static void h3600ts_disconnect(struct serio *serio)
{
struct h3600_dev *ts = serio_get_drvdata(serio);
- free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev);
- free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, &ts->dev);
+ free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts->dev);
+ free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts->dev);
input_get_device(ts->dev);
input_unregister_device(ts->dev);
serio_close(serio);
diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c
new file mode 100644
index 000000000000..4f2713d92791
--- /dev/null
+++ b/drivers/input/touchscreen/max11801_ts.c
@@ -0,0 +1,272 @@
+/*
+ * Driver for MAXI MAX11801 - A Resistive touch screen controller with
+ * i2c interface
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ * Author: Zhang Jiejing <jiejing.zhang@freescale.com>
+ *
+ * Based on mcs5000_ts.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.
+ */
+
+/*
+ * This driver aims to support the series of MAXI touch chips max11801
+ * through max11803. The main difference between these 4 chips can be
+ * found in the table below:
+ * -----------------------------------------------------
+ * | CHIP | AUTO MODE SUPPORT(FIFO) | INTERFACE |
+ * |----------------------------------------------------|
+ * | max11800 | YES | SPI |
+ * | max11801 | YES | I2C |
+ * | max11802 | NO | SPI |
+ * | max11803 | NO | I2C |
+ * ------------------------------------------------------
+ *
+ * Currently, this driver only supports max11801.
+ *
+ * Data Sheet:
+ * http://www.maxim-ic.com/datasheet/index.mvp/id/5943
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+
+/* Register Address define */
+#define GENERNAL_STATUS_REG 0x00
+#define GENERNAL_CONF_REG 0x01
+#define MESURE_RES_CONF_REG 0x02
+#define MESURE_AVER_CONF_REG 0x03
+#define ADC_SAMPLE_TIME_CONF_REG 0x04
+#define PANEL_SETUPTIME_CONF_REG 0x05
+#define DELAY_CONVERSION_CONF_REG 0x06
+#define TOUCH_DETECT_PULLUP_CONF_REG 0x07
+#define AUTO_MODE_TIME_CONF_REG 0x08 /* only for max11800/max11801 */
+#define APERTURE_CONF_REG 0x09 /* only for max11800/max11801 */
+#define AUX_MESURE_CONF_REG 0x0a
+#define OP_MODE_CONF_REG 0x0b
+
+/* FIFO is found only in max11800 and max11801 */
+#define FIFO_RD_CMD (0x50 << 1)
+#define MAX11801_FIFO_INT (1 << 2)
+#define MAX11801_FIFO_OVERFLOW (1 << 3)
+
+#define XY_BUFSIZE 4
+#define XY_BUF_OFFSET 4
+
+#define MAX11801_MAX_X 0xfff
+#define MAX11801_MAX_Y 0xfff
+
+#define MEASURE_TAG_OFFSET 2
+#define MEASURE_TAG_MASK (3 << MEASURE_TAG_OFFSET)
+#define EVENT_TAG_OFFSET 0
+#define EVENT_TAG_MASK (3 << EVENT_TAG_OFFSET)
+#define MEASURE_X_TAG (0 << MEASURE_TAG_OFFSET)
+#define MEASURE_Y_TAG (1 << MEASURE_TAG_OFFSET)
+
+/* These are the state of touch event state machine */
+enum {
+ EVENT_INIT,
+ EVENT_MIDDLE,
+ EVENT_RELEASE,
+ EVENT_FIFO_END
+};
+
+struct max11801_data {
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+};
+
+static u8 read_register(struct i2c_client *client, int addr)
+{
+ /* XXX: The chip ignores LSB of register address */
+ return i2c_smbus_read_byte_data(client, addr << 1);
+}
+
+static int max11801_write_reg(struct i2c_client *client, int addr, int data)
+{
+ /* XXX: The chip ignores LSB of register address */
+ return i2c_smbus_write_byte_data(client, addr << 1, data);
+}
+
+static irqreturn_t max11801_ts_interrupt(int irq, void *dev_id)
+{
+ struct max11801_data *data = dev_id;
+ struct i2c_client *client = data->client;
+ int status, i, ret;
+ u8 buf[XY_BUFSIZE];
+ int x = -1;
+ int y = -1;
+
+ status = read_register(data->client, GENERNAL_STATUS_REG);
+
+ if (status & (MAX11801_FIFO_INT | MAX11801_FIFO_OVERFLOW)) {
+ status = read_register(data->client, GENERNAL_STATUS_REG);
+
+ ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_CMD,
+ XY_BUFSIZE, buf);
+
+ /*
+ * We should get 4 bytes buffer that contains X,Y
+ * and event tag
+ */
+ if (ret < XY_BUFSIZE)
+ goto out;
+
+ for (i = 0; i < XY_BUFSIZE; i += XY_BUFSIZE / 2) {
+ if ((buf[i + 1] & MEASURE_TAG_MASK) == MEASURE_X_TAG)
+ x = (buf[i] << XY_BUF_OFFSET) +
+ (buf[i + 1] >> XY_BUF_OFFSET);
+ else if ((buf[i + 1] & MEASURE_TAG_MASK) == MEASURE_Y_TAG)
+ y = (buf[i] << XY_BUF_OFFSET) +
+ (buf[i + 1] >> XY_BUF_OFFSET);
+ }
+
+ if ((buf[1] & EVENT_TAG_MASK) != (buf[3] & EVENT_TAG_MASK))
+ goto out;
+
+ switch (buf[1] & EVENT_TAG_MASK) {
+ case EVENT_INIT:
+ /* fall through */
+ case EVENT_MIDDLE:
+ input_report_abs(data->input_dev, ABS_X, x);
+ input_report_abs(data->input_dev, ABS_Y, y);
+ input_event(data->input_dev, EV_KEY, BTN_TOUCH, 1);
+ input_sync(data->input_dev);
+ break;
+
+ case EVENT_RELEASE:
+ input_event(data->input_dev, EV_KEY, BTN_TOUCH, 0);
+ input_sync(data->input_dev);
+ break;
+
+ case EVENT_FIFO_END:
+ break;
+ }
+ }
+out:
+ return IRQ_HANDLED;
+}
+
+static void __devinit max11801_ts_phy_init(struct max11801_data *data)
+{
+ struct i2c_client *client = data->client;
+
+ /* Average X,Y, take 16 samples, average eight media sample */
+ max11801_write_reg(client, MESURE_AVER_CONF_REG, 0xff);
+ /* X,Y panel setup time set to 20us */
+ max11801_write_reg(client, PANEL_SETUPTIME_CONF_REG, 0x11);
+ /* Rough pullup time (2uS), Fine pullup time (10us) */
+ max11801_write_reg(client, TOUCH_DETECT_PULLUP_CONF_REG, 0x10);
+ /* Auto mode init period = 5ms , scan period = 5ms*/
+ max11801_write_reg(client, AUTO_MODE_TIME_CONF_REG, 0xaa);
+ /* Aperture X,Y set to +- 4LSB */
+ max11801_write_reg(client, APERTURE_CONF_REG, 0x33);
+ /* Enable Power, enable Automode, enable Aperture, enable Average X,Y */
+ max11801_write_reg(client, OP_MODE_CONF_REG, 0x36);
+}
+
+static int __devinit max11801_ts_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct max11801_data *data;
+ struct input_dev *input_dev;
+ int error;
+
+ data = kzalloc(sizeof(struct max11801_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;
+ }
+
+ data->client = client;
+ data->input_dev = input_dev;
+
+ input_dev->name = "max11801_ts";
+ input_dev->id.bustype = BUS_I2C;
+ input_dev->dev.parent = &client->dev;
+
+ __set_bit(EV_ABS, input_dev->evbit);
+ __set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(BTN_TOUCH, input_dev->keybit);
+ input_set_abs_params(input_dev, ABS_X, 0, MAX11801_MAX_X, 0, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0, MAX11801_MAX_Y, 0, 0);
+ input_set_drvdata(input_dev, data);
+
+ max11801_ts_phy_init(data);
+
+ error = request_threaded_irq(client->irq, NULL, max11801_ts_interrupt,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "max11801_ts", data);
+ if (error) {
+ dev_err(&client->dev, "Failed to register interrupt\n");
+ goto err_free_mem;
+ }
+
+ error = input_register_device(data->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 __devexit int max11801_ts_remove(struct i2c_client *client)
+{
+ struct max11801_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 max11801_ts_id[] = {
+ {"max11801", 0},
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, max11801_ts_id);
+
+static struct i2c_driver max11801_ts_driver = {
+ .driver = {
+ .name = "max11801_ts",
+ .owner = THIS_MODULE,
+ },
+ .id_table = max11801_ts_id,
+ .probe = max11801_ts_probe,
+ .remove = __devexit_p(max11801_ts_remove),
+};
+
+static int __init max11801_ts_init(void)
+{
+ return i2c_add_driver(&max11801_ts_driver);
+}
+
+static void __exit max11801_ts_exit(void)
+{
+ i2c_del_driver(&max11801_ts_driver);
+}
+
+module_init(max11801_ts_init);
+module_exit(max11801_ts_exit);
+
+MODULE_AUTHOR("Zhang Jiejing <jiejing.zhang@freescale.com>");
+MODULE_DESCRIPTION("Touchscreen driver for MAXI MAX11801 controller");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c
index 80467f262331..fadc11545b1e 100644
--- a/drivers/input/touchscreen/tsc2007.c
+++ b/drivers/input/touchscreen/tsc2007.c
@@ -27,9 +27,6 @@
#include <linux/i2c.h>
#include <linux/i2c/tsc2007.h>
-#define TS_POLL_DELAY 1 /* ms delay between samples */
-#define TS_POLL_PERIOD 1 /* ms delay between samples */
-
#define TSC2007_MEASURE_TEMP0 (0x0 << 4)
#define TSC2007_MEASURE_AUX (0x2 << 4)
#define TSC2007_MEASURE_TEMP1 (0x4 << 4)
@@ -75,6 +72,9 @@ struct tsc2007 {
u16 model;
u16 x_plate_ohms;
+ u16 max_rt;
+ unsigned long poll_delay;
+ unsigned long poll_period;
bool pendown;
int irq;
@@ -156,6 +156,7 @@ static void tsc2007_work(struct work_struct *work)
{
struct tsc2007 *ts =
container_of(to_delayed_work(work), struct tsc2007, work);
+ bool debounced = false;
struct ts_event tc;
u32 rt;
@@ -184,13 +185,14 @@ static void tsc2007_work(struct work_struct *work)
tsc2007_read_values(ts, &tc);
rt = tsc2007_calculate_pressure(ts, &tc);
- if (rt > MAX_12BIT) {
+ if (rt > ts->max_rt) {
/*
* Sample found inconsistent by debouncing or pressure is
* beyond the maximum. Don't report it to user space,
* repeat at least once more the measurement.
*/
dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt);
+ debounced = true;
goto out;
}
@@ -225,9 +227,9 @@ static void tsc2007_work(struct work_struct *work)
}
out:
- if (ts->pendown)
+ if (ts->pendown || debounced)
schedule_delayed_work(&ts->work,
- msecs_to_jiffies(TS_POLL_PERIOD));
+ msecs_to_jiffies(ts->poll_period));
else
enable_irq(ts->irq);
}
@@ -239,7 +241,7 @@ static irqreturn_t tsc2007_irq(int irq, void *handle)
if (!ts->get_pendown_state || likely(ts->get_pendown_state())) {
disable_irq_nosync(ts->irq);
schedule_delayed_work(&ts->work,
- msecs_to_jiffies(TS_POLL_DELAY));
+ msecs_to_jiffies(ts->poll_delay));
}
if (ts->clear_penirq)
@@ -292,6 +294,9 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
ts->model = pdata->model;
ts->x_plate_ohms = pdata->x_plate_ohms;
+ ts->max_rt = pdata->max_rt ? : MAX_12BIT;
+ ts->poll_delay = pdata->poll_delay ? : 1;
+ ts->poll_period = pdata->poll_period ? : 1;
ts->get_pendown_state = pdata->get_pendown_state;
ts->clear_penirq = pdata->clear_penirq;
@@ -305,9 +310,10 @@ static int __devinit tsc2007_probe(struct i2c_client *client,
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, 0, MAX_12BIT, 0, 0);
- input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);
- input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);
+ input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, pdata->fuzzx, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, pdata->fuzzy, 0);
+ input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT,
+ pdata->fuzzz, 0);
if (pdata->init_platform_hw)
pdata->init_platform_hw();
diff --git a/drivers/isdn/capi/Kconfig b/drivers/isdn/capi/Kconfig
index a168e8a891be..15c3ffd9d860 100644
--- a/drivers/isdn/capi/Kconfig
+++ b/drivers/isdn/capi/Kconfig
@@ -33,21 +33,6 @@ config ISDN_CAPI_CAPI20
standardized libcapi20 to access this functionality. You should say
Y/M here.
-config ISDN_CAPI_CAPIFS_BOOL
- bool "CAPI2.0 filesystem support (DEPRECATED)"
- depends on ISDN_CAPI_MIDDLEWARE && ISDN_CAPI_CAPI20
- help
- This option provides a special file system, similar to /dev/pts with
- device nodes for the special ttys established by using the
- middleware extension above.
- You no longer need this, udev fully replaces it. This feature is
- scheduled for removal.
-
-config ISDN_CAPI_CAPIFS
- tristate
- depends on ISDN_CAPI_CAPIFS_BOOL
- default ISDN_CAPI_CAPI20
-
config ISDN_CAPI_CAPIDRV
tristate "CAPI2.0 capidrv interface support"
depends on ISDN_I4L
diff --git a/drivers/isdn/capi/Makefile b/drivers/isdn/capi/Makefile
index 57123e3e4978..4d5b4b71db1e 100644
--- a/drivers/isdn/capi/Makefile
+++ b/drivers/isdn/capi/Makefile
@@ -7,7 +7,6 @@
obj-$(CONFIG_ISDN_CAPI) += kernelcapi.o
obj-$(CONFIG_ISDN_CAPI_CAPI20) += capi.o
obj-$(CONFIG_ISDN_CAPI_CAPIDRV) += capidrv.o
-obj-$(CONFIG_ISDN_CAPI_CAPIFS) += capifs.o
# Multipart objects.
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 0d7088367038..e44933d58790 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -38,15 +38,10 @@
#include <linux/isdn/capiutil.h>
#include <linux/isdn/capicmd.h>
-#include "capifs.h"
-
MODULE_DESCRIPTION("CAPI4Linux: Userspace /dev/capi20 interface");
MODULE_AUTHOR("Carsten Paeth");
MODULE_LICENSE("GPL");
-#undef _DEBUG_TTYFUNCS /* call to tty_driver */
-#undef _DEBUG_DATAFLOW /* data flow */
-
/* -------- driver information -------------------------------------- */
static DEFINE_MUTEX(capi_mutex);
@@ -85,7 +80,6 @@ struct capiminor {
struct kref kref;
unsigned int minor;
- struct dentry *capifs_dentry;
struct capi20_appl *ap;
u32 ncci;
@@ -300,17 +294,8 @@ static void capiminor_free(struct capiminor *mp)
static void capincci_alloc_minor(struct capidev *cdev, struct capincci *np)
{
- struct capiminor *mp;
- dev_t device;
-
- if (!(cdev->userflags & CAPIFLAG_HIGHJACKING))
- return;
-
- mp = np->minorp = capiminor_alloc(&cdev->ap, np->ncci);
- if (mp) {
- device = MKDEV(capinc_tty_driver->major, mp->minor);
- mp->capifs_dentry = capifs_new_ncci(mp->minor, device);
- }
+ if (cdev->userflags & CAPIFLAG_HIGHJACKING)
+ np->minorp = capiminor_alloc(&cdev->ap, np->ncci);
}
static void capincci_free_minor(struct capincci *np)
@@ -319,8 +304,6 @@ static void capincci_free_minor(struct capincci *np)
struct tty_struct *tty;
if (mp) {
- capifs_free_ncci(mp->capifs_dentry);
-
tty = tty_port_tty_get(&mp->port);
if (tty) {
tty_vhangup(tty);
@@ -432,9 +415,7 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
tty = tty_port_tty_get(&mp->port);
if (!tty) {
-#ifdef _DEBUG_DATAFLOW
- printk(KERN_DEBUG "capi: currently no receiver\n");
-#endif
+ pr_debug("capi: currently no receiver\n");
return -1;
}
@@ -447,23 +428,17 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
}
if (ld->ops->receive_buf == NULL) {
-#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
- printk(KERN_DEBUG "capi: ldisc has no receive_buf function\n");
-#endif
+ pr_debug("capi: ldisc has no receive_buf function\n");
/* fatal error, do not requeue */
goto free_skb;
}
if (mp->ttyinstop) {
-#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
- printk(KERN_DEBUG "capi: recv tty throttled\n");
-#endif
+ pr_debug("capi: recv tty throttled\n");
goto deref_ldisc;
}
if (tty->receive_room < datalen) {
-#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
- printk(KERN_DEBUG "capi: no room in tty\n");
-#endif
+ pr_debug("capi: no room in tty\n");
goto deref_ldisc;
}
@@ -479,10 +454,8 @@ static int handle_recv_skb(struct capiminor *mp, struct sk_buff *skb)
if (errcode == CAPI_NOERROR) {
skb_pull(skb, CAPIMSG_LEN(skb->data));
-#ifdef _DEBUG_DATAFLOW
- printk(KERN_DEBUG "capi: DATA_B3_RESP %u len=%d => ldisc\n",
- datahandle, skb->len);
-#endif
+ pr_debug("capi: DATA_B3_RESP %u len=%d => ldisc\n",
+ datahandle, skb->len);
ld->ops->receive_buf(tty, skb->data, NULL, skb->len);
} else {
printk(KERN_ERR "capi: send DATA_B3_RESP failed=%x\n",
@@ -529,9 +502,7 @@ static void handle_minor_send(struct capiminor *mp)
return;
if (mp->ttyoutstop) {
-#if defined(_DEBUG_DATAFLOW) || defined(_DEBUG_TTYFUNCS)
- printk(KERN_DEBUG "capi: send: tty stopped\n");
-#endif
+ pr_debug("capi: send: tty stopped\n");
tty_kref_put(tty);
return;
}
@@ -573,10 +544,8 @@ static void handle_minor_send(struct capiminor *mp)
}
errcode = capi20_put_message(mp->ap, skb);
if (errcode == CAPI_NOERROR) {
-#ifdef _DEBUG_DATAFLOW
- printk(KERN_DEBUG "capi: DATA_B3_REQ %u len=%u\n",
- datahandle, len);
-#endif
+ pr_debug("capi: DATA_B3_REQ %u len=%u\n",
+ datahandle, len);
continue;
}
capiminor_del_ack(mp, datahandle);
@@ -650,10 +619,8 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
}
if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_IND) {
datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+4+2);
-#ifdef _DEBUG_DATAFLOW
- printk(KERN_DEBUG "capi_signal: DATA_B3_IND %u len=%d\n",
- datahandle, skb->len-CAPIMSG_LEN(skb->data));
-#endif
+ pr_debug("capi_signal: DATA_B3_IND %u len=%d\n",
+ datahandle, skb->len-CAPIMSG_LEN(skb->data));
skb_queue_tail(&mp->inqueue, skb);
handle_minor_recv(mp);
@@ -661,11 +628,9 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
} else if (CAPIMSG_SUBCOMMAND(skb->data) == CAPI_CONF) {
datahandle = CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4);
-#ifdef _DEBUG_DATAFLOW
- printk(KERN_DEBUG "capi_signal: DATA_B3_CONF %u 0x%x\n",
- datahandle,
- CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+2));
-#endif
+ pr_debug("capi_signal: DATA_B3_CONF %u 0x%x\n",
+ datahandle,
+ CAPIMSG_U16(skb->data, CAPIMSG_BASELEN+4+2));
kfree_skb(skb);
capiminor_del_ack(mp, datahandle);
tty = tty_port_tty_get(&mp->port);
@@ -1095,9 +1060,7 @@ static int capinc_tty_write(struct tty_struct *tty,
struct capiminor *mp = tty->driver_data;
struct sk_buff *skb;
-#ifdef _DEBUG_TTYFUNCS
- printk(KERN_DEBUG "capinc_tty_write(count=%d)\n", count);
-#endif
+ pr_debug("capinc_tty_write(count=%d)\n", count);
spin_lock_bh(&mp->outlock);
skb = mp->outskb;
@@ -1133,9 +1096,7 @@ static int capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
struct sk_buff *skb;
int ret = 1;
-#ifdef _DEBUG_TTYFUNCS
- printk(KERN_DEBUG "capinc_put_char(%u)\n", ch);
-#endif
+ pr_debug("capinc_put_char(%u)\n", ch);
spin_lock_bh(&mp->outlock);
skb = mp->outskb;
@@ -1174,9 +1135,7 @@ static void capinc_tty_flush_chars(struct tty_struct *tty)
struct capiminor *mp = tty->driver_data;
struct sk_buff *skb;
-#ifdef _DEBUG_TTYFUNCS
- printk(KERN_DEBUG "capinc_tty_flush_chars\n");
-#endif
+ pr_debug("capinc_tty_flush_chars\n");
spin_lock_bh(&mp->outlock);
skb = mp->outskb;
@@ -1200,9 +1159,7 @@ static int capinc_tty_write_room(struct tty_struct *tty)
room = CAPINC_MAX_SENDQUEUE-skb_queue_len(&mp->outqueue);
room *= CAPI_MAX_BLKSIZE;
-#ifdef _DEBUG_TTYFUNCS
- printk(KERN_DEBUG "capinc_tty_write_room = %d\n", room);
-#endif
+ pr_debug("capinc_tty_write_room = %d\n", room);
return room;
}
@@ -1210,12 +1167,10 @@ static int capinc_tty_chars_in_buffer(struct tty_struct *tty)
{
struct capiminor *mp = tty->driver_data;
-#ifdef _DEBUG_TTYFUNCS
- printk(KERN_DEBUG "capinc_tty_chars_in_buffer = %d nack=%d sq=%d rq=%d\n",
- mp->outbytes, mp->nack,
- skb_queue_len(&mp->outqueue),
- skb_queue_len(&mp->inqueue));
-#endif
+ pr_debug("capinc_tty_chars_in_buffer = %d nack=%d sq=%d rq=%d\n",
+ mp->outbytes, mp->nack,
+ skb_queue_len(&mp->outqueue),
+ skb_queue_len(&mp->inqueue));
return mp->outbytes;
}
@@ -1227,17 +1182,13 @@ static int capinc_tty_ioctl(struct tty_struct *tty,
static void capinc_tty_set_termios(struct tty_struct *tty, struct ktermios * old)
{
-#ifdef _DEBUG_TTYFUNCS
- printk(KERN_DEBUG "capinc_tty_set_termios\n");
-#endif
+ pr_debug("capinc_tty_set_termios\n");
}
static void capinc_tty_throttle(struct tty_struct *tty)
{
struct capiminor *mp = tty->driver_data;
-#ifdef _DEBUG_TTYFUNCS
- printk(KERN_DEBUG "capinc_tty_throttle\n");
-#endif
+ pr_debug("capinc_tty_throttle\n");
mp->ttyinstop = 1;
}
@@ -1245,9 +1196,7 @@ static void capinc_tty_unthrottle(struct tty_struct *tty)
{
struct capiminor *mp = tty->driver_data;
-#ifdef _DEBUG_TTYFUNCS
- printk(KERN_DEBUG "capinc_tty_unthrottle\n");
-#endif
+ pr_debug("capinc_tty_unthrottle\n");
mp->ttyinstop = 0;
handle_minor_recv(mp);
}
@@ -1256,9 +1205,7 @@ static void capinc_tty_stop(struct tty_struct *tty)
{
struct capiminor *mp = tty->driver_data;
-#ifdef _DEBUG_TTYFUNCS
- printk(KERN_DEBUG "capinc_tty_stop\n");
-#endif
+ pr_debug("capinc_tty_stop\n");
mp->ttyoutstop = 1;
}
@@ -1266,9 +1213,7 @@ static void capinc_tty_start(struct tty_struct *tty)
{
struct capiminor *mp = tty->driver_data;
-#ifdef _DEBUG_TTYFUNCS
- printk(KERN_DEBUG "capinc_tty_start\n");
-#endif
+ pr_debug("capinc_tty_start\n");
mp->ttyoutstop = 0;
handle_minor_send(mp);
}
@@ -1277,39 +1222,29 @@ static void capinc_tty_hangup(struct tty_struct *tty)
{
struct capiminor *mp = tty->driver_data;
-#ifdef _DEBUG_TTYFUNCS
- printk(KERN_DEBUG "capinc_tty_hangup\n");
-#endif
+ pr_debug("capinc_tty_hangup\n");
tty_port_hangup(&mp->port);
}
static int capinc_tty_break_ctl(struct tty_struct *tty, int state)
{
-#ifdef _DEBUG_TTYFUNCS
- printk(KERN_DEBUG "capinc_tty_break_ctl(%d)\n", state);
-#endif
+ pr_debug("capinc_tty_break_ctl(%d)\n", state);
return 0;
}
static void capinc_tty_flush_buffer(struct tty_struct *tty)
{
-#ifdef _DEBUG_TTYFUNCS
- printk(KERN_DEBUG "capinc_tty_flush_buffer\n");
-#endif
+ pr_debug("capinc_tty_flush_buffer\n");
}
static void capinc_tty_set_ldisc(struct tty_struct *tty)
{
-#ifdef _DEBUG_TTYFUNCS
- printk(KERN_DEBUG "capinc_tty_set_ldisc\n");
-#endif
+ pr_debug("capinc_tty_set_ldisc\n");
}
static void capinc_tty_send_xchar(struct tty_struct *tty, char ch)
{
-#ifdef _DEBUG_TTYFUNCS
- printk(KERN_DEBUG "capinc_tty_send_xchar(%d)\n", ch);
-#endif
+ pr_debug("capinc_tty_send_xchar(%d)\n", ch);
}
static const struct tty_operations capinc_ops = {
@@ -1514,10 +1449,8 @@ static int __init capi_init(void)
proc_init();
-#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
- compileinfo = " (middleware+capifs)";
-#elif defined(CONFIG_ISDN_CAPI_MIDDLEWARE)
- compileinfo = " (no capifs)";
+#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
+ compileinfo = " (middleware)";
#else
compileinfo = " (no middleware)";
#endif
diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c
deleted file mode 100644
index b4faed7fe0d3..000000000000
--- a/drivers/isdn/capi/capifs.c
+++ /dev/null
@@ -1,239 +0,0 @@
-/* $Id: capifs.c,v 1.1.2.3 2004/01/16 21:09:26 keil Exp $
- *
- * Copyright 2000 by Carsten Paeth <calle@calle.de>
- *
- * Heavily based on devpts filesystem from H. Peter Anvin
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/fs.h>
-#include <linux/mount.h>
-#include <linux/slab.h>
-#include <linux/namei.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/ctype.h>
-#include <linux/sched.h> /* current */
-
-#include "capifs.h"
-
-MODULE_DESCRIPTION("CAPI4Linux: /dev/capi/ filesystem");
-MODULE_AUTHOR("Carsten Paeth");
-MODULE_LICENSE("GPL");
-
-/* ------------------------------------------------------------------ */
-
-#define CAPIFS_SUPER_MAGIC (('C'<<8)|'N')
-
-static struct vfsmount *capifs_mnt;
-static int capifs_mnt_count;
-
-static struct {
- int setuid;
- int setgid;
- uid_t uid;
- gid_t gid;
- umode_t mode;
-} config = {.mode = 0600};
-
-/* ------------------------------------------------------------------ */
-
-static int capifs_remount(struct super_block *s, int *flags, char *data)
-{
- int setuid = 0;
- int setgid = 0;
- uid_t uid = 0;
- gid_t gid = 0;
- umode_t mode = 0600;
- char *this_char;
- char *new_opt = kstrdup(data, GFP_KERNEL);
-
- this_char = NULL;
- while ((this_char = strsep(&data, ",")) != NULL) {
- int n;
- char dummy;
- if (!*this_char)
- continue;
- if (sscanf(this_char, "uid=%i%c", &n, &dummy) == 1) {
- setuid = 1;
- uid = n;
- } else if (sscanf(this_char, "gid=%i%c", &n, &dummy) == 1) {
- setgid = 1;
- gid = n;
- } else if (sscanf(this_char, "mode=%o%c", &n, &dummy) == 1)
- mode = n & ~S_IFMT;
- else {
- kfree(new_opt);
- printk("capifs: called with bogus options\n");
- return -EINVAL;
- }
- }
-
- mutex_lock(&s->s_root->d_inode->i_mutex);
-
- replace_mount_options(s, new_opt);
- config.setuid = setuid;
- config.setgid = setgid;
- config.uid = uid;
- config.gid = gid;
- config.mode = mode;
-
- mutex_unlock(&s->s_root->d_inode->i_mutex);
-
- return 0;
-}
-
-static const struct super_operations capifs_sops =
-{
- .statfs = simple_statfs,
- .remount_fs = capifs_remount,
- .show_options = generic_show_options,
-};
-
-
-static int
-capifs_fill_super(struct super_block *s, void *data, int silent)
-{
- struct inode * inode;
-
- s->s_blocksize = 1024;
- s->s_blocksize_bits = 10;
- s->s_magic = CAPIFS_SUPER_MAGIC;
- s->s_op = &capifs_sops;
- s->s_time_gran = 1;
-
- inode = new_inode(s);
- if (!inode)
- goto fail;
- inode->i_ino = 1;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
- inode->i_op = &simple_dir_inode_operations;
- inode->i_fop = &simple_dir_operations;
- inode->i_nlink = 2;
-
- s->s_root = d_alloc_root(inode);
- if (s->s_root)
- return 0;
-
- printk("capifs: get root dentry failed\n");
- iput(inode);
-fail:
- return -ENOMEM;
-}
-
-static struct dentry *capifs_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
-{
- return mount_single(fs_type, flags, data, capifs_fill_super);
-}
-
-static struct file_system_type capifs_fs_type = {
- .owner = THIS_MODULE,
- .name = "capifs",
- .mount = capifs_mount,
- .kill_sb = kill_anon_super,
-};
-
-static struct dentry *new_ncci(unsigned int number, dev_t device)
-{
- struct super_block *s = capifs_mnt->mnt_sb;
- struct dentry *root = s->s_root;
- struct dentry *dentry;
- struct inode *inode;
- char name[10];
- int namelen;
-
- mutex_lock(&root->d_inode->i_mutex);
-
- namelen = sprintf(name, "%d", number);
- dentry = lookup_one_len(name, root, namelen);
- if (IS_ERR(dentry)) {
- dentry = NULL;
- goto unlock_out;
- }
-
- if (dentry->d_inode) {
- dput(dentry);
- dentry = NULL;
- goto unlock_out;
- }
-
- inode = new_inode(s);
- if (!inode) {
- dput(dentry);
- dentry = NULL;
- goto unlock_out;
- }
-
- /* config contents is protected by root's i_mutex */
- inode->i_uid = config.setuid ? config.uid : current_fsuid();
- inode->i_gid = config.setgid ? config.gid : current_fsgid();
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- inode->i_ino = number + 2;
- init_special_inode(inode, S_IFCHR|config.mode, device);
-
- d_instantiate(dentry, inode);
- dget(dentry);
-
-unlock_out:
- mutex_unlock(&root->d_inode->i_mutex);
-
- return dentry;
-}
-
-struct dentry *capifs_new_ncci(unsigned int number, dev_t device)
-{
- struct dentry *dentry;
-
- if (simple_pin_fs(&capifs_fs_type, &capifs_mnt, &capifs_mnt_count) < 0)
- return NULL;
-
- dentry = new_ncci(number, device);
- if (!dentry)
- simple_release_fs(&capifs_mnt, &capifs_mnt_count);
-
- return dentry;
-}
-
-void capifs_free_ncci(struct dentry *dentry)
-{
- struct dentry *root = capifs_mnt->mnt_sb->s_root;
- struct inode *inode;
-
- if (!dentry)
- return;
-
- mutex_lock(&root->d_inode->i_mutex);
-
- inode = dentry->d_inode;
- if (inode) {
- drop_nlink(inode);
- d_delete(dentry);
- dput(dentry);
- }
- dput(dentry);
-
- mutex_unlock(&root->d_inode->i_mutex);
-
- simple_release_fs(&capifs_mnt, &capifs_mnt_count);
-}
-
-static int __init capifs_init(void)
-{
- return register_filesystem(&capifs_fs_type);
-}
-
-static void __exit capifs_exit(void)
-{
- unregister_filesystem(&capifs_fs_type);
-}
-
-EXPORT_SYMBOL(capifs_new_ncci);
-EXPORT_SYMBOL(capifs_free_ncci);
-
-module_init(capifs_init);
-module_exit(capifs_exit);
diff --git a/drivers/isdn/capi/capifs.h b/drivers/isdn/capi/capifs.h
deleted file mode 100644
index e193d1189531..000000000000
--- a/drivers/isdn/capi/capifs.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* $Id: capifs.h,v 1.1.2.2 2004/01/16 21:09:26 keil Exp $
- *
- * Copyright 2000 by Carsten Paeth <calle@calle.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/dcache.h>
-
-#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
-
-struct dentry *capifs_new_ncci(unsigned int num, dev_t device);
-void capifs_free_ncci(struct dentry *dentry);
-
-#else
-
-static inline struct dentry *capifs_new_ncci(unsigned int num, dev_t device)
-{
- return NULL;
-}
-
-static inline void capifs_free_ncci(struct dentry *dentry)
-{
-}
-
-#endif
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index 8a3c5cfc4fea..3913f47ef86d 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -1157,7 +1157,6 @@ static void write_iso_tasklet(unsigned long data)
struct urb *urb;
int status;
struct usb_iso_packet_descriptor *ifd;
- int offset;
unsigned long flags;
int i;
struct sk_buff *skb;
@@ -1225,7 +1224,6 @@ static void write_iso_tasklet(unsigned long data)
* successfully sent
* - all following frames are not sent at all
*/
- offset = done->limit; /* default (no error) */
for (i = 0; i < BAS_NUMFRAMES; i++) {
ifd = &urb->iso_frame_desc[i];
if (ifd->status ||
@@ -1235,9 +1233,6 @@ static void write_iso_tasklet(unsigned long data)
i, ifd->actual_length,
ifd->length,
get_usb_statmsg(ifd->status));
- offset = (ifd->offset +
- ifd->actual_length)
- % BAS_OUTBUFSIZE;
break;
}
}
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c
index a14187605f5e..ba74646cf0e4 100644
--- a/drivers/isdn/gigaset/ev-layer.c
+++ b/drivers/isdn/gigaset/ev-layer.c
@@ -390,12 +390,12 @@ static const struct zsau_resp_t {
*/
static int cid_of_response(char *s)
{
- unsigned long cid;
+ int cid;
int rc;
if (s[-1] != ';')
return 0; /* no CID separator */
- rc = strict_strtoul(s, 10, &cid);
+ rc = kstrtoint(s, 10, &cid);
if (rc)
return 0; /* CID not numeric */
if (cid < 1 || cid > 65535)
@@ -566,27 +566,19 @@ void gigaset_handle_modem_response(struct cardstate *cs)
case RT_ZCAU:
event->parameter = -1;
if (curarg + 1 < params) {
- unsigned long type, value;
-
- i = strict_strtoul(argv[curarg++], 16, &type);
- j = strict_strtoul(argv[curarg++], 16, &value);
+ u8 type, value;
- if (i == 0 && type < 256 &&
- j == 0 && value < 256)
+ i = kstrtou8(argv[curarg++], 16, &type);
+ j = kstrtou8(argv[curarg++], 16, &value);
+ if (i == 0 && j == 0)
event->parameter = (type << 8) | value;
} else
curarg = params - 1;
break;
case RT_NUMBER:
- event->parameter = -1;
- if (curarg < params) {
- unsigned long res;
- int rc;
-
- rc = strict_strtoul(argv[curarg++], 10, &res);
- if (rc == 0)
- event->parameter = res;
- }
+ if (curarg >= params ||
+ kstrtoint(argv[curarg++], 10, &event->parameter))
+ event->parameter = -1;
gig_dbg(DEBUG_EVENT, "parameter==%d", event->parameter);
break;
}
diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c
index 86a5c4f7775e..1d44d470897c 100644
--- a/drivers/isdn/gigaset/ser-gigaset.c
+++ b/drivers/isdn/gigaset/ser-gigaset.c
@@ -674,7 +674,7 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
* cflags buffer containing error flags for received characters (ignored)
* count number of received characters
*/
-static void
+static unsigned int
gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
char *cflags, int count)
{
@@ -683,12 +683,12 @@ gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
struct inbuf_t *inbuf;
if (!cs)
- return;
+ return -ENODEV;
inbuf = cs->inbuf;
if (!inbuf) {
dev_err(cs->dev, "%s: no inbuf\n", __func__);
cs_put(cs);
- return;
+ return -EINVAL;
}
tail = inbuf->tail;
@@ -725,6 +725,8 @@ gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
gigaset_schedule_event(cs);
cs_put(cs);
+
+ return count;
}
/*
diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c
index 91f06a3ef002..61f516f376dc 100644
--- a/drivers/isdn/hardware/avm/avm_cs.c
+++ b/drivers/isdn/hardware/avm/avm_cs.c
@@ -149,7 +149,7 @@ static void avmcs_release(struct pcmcia_device *link)
} /* avmcs_release */
-static struct pcmcia_device_id avmcs_ids[] = {
+static const struct pcmcia_device_id avmcs_ids[] = {
PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335),
PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M1", 0x95d42008, 0x81e10430),
PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M2", 0x95d42008, 0x18e8558a),
diff --git a/drivers/isdn/hardware/eicon/debug.c b/drivers/isdn/hardware/eicon/debug.c
index 362640120886..7a9894cb4557 100644
--- a/drivers/isdn/hardware/eicon/debug.c
+++ b/drivers/isdn/hardware/eicon/debug.c
@@ -861,7 +861,7 @@ static int diva_get_idi_adapter_info (IDI_CALL request, dword* serial, dword* lo
void diva_mnt_add_xdi_adapter (const DESCRIPTOR* d) {
diva_os_spin_lock_magic_t old_irql, old_irql1;
dword sec, usec, logical, serial, org_mask;
- int id, best_id = 0, free_id = -1;
+ int id, free_id = -1;
char tmp[128];
diva_dbg_entry_head_t* pmsg = NULL;
int len;
@@ -906,7 +906,6 @@ void diva_mnt_add_xdi_adapter (const DESCRIPTOR* d) {
and slot is still free - reuse it
*/
free_id = id;
- best_id = 1;
break;
}
}
diff --git a/drivers/isdn/hardware/eicon/divasfunc.c b/drivers/isdn/hardware/eicon/divasfunc.c
index d36a4c09e25d..0bbee7824d78 100644
--- a/drivers/isdn/hardware/eicon/divasfunc.c
+++ b/drivers/isdn/hardware/eicon/divasfunc.c
@@ -113,9 +113,8 @@ void diva_xdi_didd_remove_adapter(int card)
static void start_dbg(void)
{
DbgRegister("DIVAS", DRIVERRELEASE_DIVAS, (debugmask) ? debugmask : DBG_DEFAULT);
- DBG_LOG(("DIVA ISDNXDI BUILD (%s[%s]-%s-%s)",
- DIVA_BUILD, diva_xdi_common_code_build, __DATE__,
- __TIME__))
+ DBG_LOG(("DIVA ISDNXDI BUILD (%s[%s])",
+ DIVA_BUILD, diva_xdi_common_code_build))
}
/*
diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c
index 8c5c563c4f12..a3395986df3d 100644
--- a/drivers/isdn/hardware/eicon/message.c
+++ b/drivers/isdn/hardware/eicon/message.c
@@ -1198,7 +1198,6 @@ static byte connect_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
word ch;
word i;
word Info;
- word CIP;
byte LinkLayer;
API_PARSE * ai;
API_PARSE * bp;
@@ -1340,7 +1339,6 @@ static byte connect_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
add_s(plci,BC,&parms[6]);
add_s(plci,LLC,&parms[7]);
add_s(plci,HLC,&parms[8]);
- CIP = GET_WORD(parms[0].info);
if (a->Info_Mask[appl->Id-1] & 0x200)
{
/* early B3 connect (CIP mask bit 9) no release after a disc */
@@ -4830,7 +4828,6 @@ static void sig_ind(PLCI *plci)
dword x_Id;
dword Id;
dword rId;
- word Number = 0;
word i;
word cip;
dword cip_mask;
@@ -5106,7 +5103,7 @@ static void sig_ind(PLCI *plci)
}
}
- if(plci->appl) Number = plci->appl->Number++;
+ if(plci->appl) plci->appl->Number++;
switch(plci->Sig.Ind) {
/* Response to Get_Supported_Services request */
@@ -5894,7 +5891,6 @@ static void sig_ind(PLCI *plci)
break;
case TEL_CTRL:
- Number = 0;
ie = multi_fac_parms[0]; /* inspect the facility hook indications */
if(plci->State==ADVANCED_VOICE_SIG && ie[0]){
switch (ie[1]&0x91) {
@@ -10119,14 +10115,12 @@ static byte dtmf_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI
static void dtmf_confirmation (dword Id, PLCI *plci)
{
- word Info;
word i;
byte result[4];
dbug (1, dprintf ("[%06lx] %s,%d: dtmf_confirmation",
UnMapId (Id), (char *)(FILE_), __LINE__));
- Info = GOOD;
result[0] = 2;
PUT_WORD (&result[1], DTMF_SUCCESS);
if (plci->dtmf_send_requests != 0)
@@ -11520,13 +11514,12 @@ static word mixer_restore_config (dword Id, PLCI *plci, byte Rc)
static void mixer_command (dword Id, PLCI *plci, byte Rc)
{
DIVA_CAPI_ADAPTER *a;
- word i, internal_command, Info;
+ word i, internal_command;
dbug (1, dprintf ("[%06lx] %s,%d: mixer_command %02x %04x %04x",
UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command,
plci->li_cmd));
- Info = GOOD;
a = plci->adapter;
internal_command = plci->internal_command;
plci->internal_command = 0;
@@ -11550,7 +11543,6 @@ static void mixer_command (dword Id, PLCI *plci, byte Rc)
{
dbug (1, dprintf ("[%06lx] %s,%d: Load mixer failed",
UnMapId (Id), (char *)(FILE_), __LINE__));
- Info = _FACILITY_NOT_SUPPORTED;
break;
}
if (plci->internal_command)
@@ -11592,7 +11584,6 @@ static void mixer_command (dword Id, PLCI *plci, byte Rc)
} while ((plci->li_plci_b_write_pos != plci->li_plci_b_req_pos)
&& !(plci->li_plci_b_queue[i] & LI_PLCI_B_LAST_FLAG));
}
- Info = _FACILITY_NOT_SUPPORTED;
break;
}
if (plci->internal_command)
@@ -11610,7 +11601,6 @@ static void mixer_command (dword Id, PLCI *plci, byte Rc)
{
dbug (1, dprintf ("[%06lx] %s,%d: Unload mixer failed",
UnMapId (Id), (char *)(FILE_), __LINE__));
- Info = _FACILITY_NOT_SUPPORTED;
break;
}
if (plci->internal_command)
@@ -12448,13 +12438,11 @@ static byte mixer_request (dword Id, word Number, DIVA_CAPI_ADAPTER *a, PLCI
static void mixer_indication_coefs_set (dword Id, PLCI *plci)
{
dword d;
- DIVA_CAPI_ADAPTER *a;
byte result[12];
dbug (1, dprintf ("[%06lx] %s,%d: mixer_indication_coefs_set",
UnMapId (Id), (char *)(FILE_), __LINE__));
- a = plci->adapter;
if (plci->li_plci_b_read_pos != plci->li_plci_b_req_pos)
{
do
@@ -14111,13 +14099,11 @@ static void select_b_command (dword Id, PLCI *plci, byte Rc)
static void fax_connect_ack_command (dword Id, PLCI *plci, byte Rc)
{
- word Info;
word internal_command;
dbug (1, dprintf ("[%06lx] %s,%d: fax_connect_ack_command %02x %04x",
UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
- Info = GOOD;
internal_command = plci->internal_command;
plci->internal_command = 0;
switch (internal_command)
@@ -14160,13 +14146,11 @@ static void fax_connect_ack_command (dword Id, PLCI *plci, byte Rc)
static void fax_edata_ack_command (dword Id, PLCI *plci, byte Rc)
{
- word Info;
word internal_command;
dbug (1, dprintf ("[%06lx] %s,%d: fax_edata_ack_command %02x %04x",
UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
- Info = GOOD;
internal_command = plci->internal_command;
plci->internal_command = 0;
switch (internal_command)
@@ -14395,13 +14379,11 @@ static void rtp_connect_b3_req_command (dword Id, PLCI *plci, byte Rc)
static void rtp_connect_b3_res_command (dword Id, PLCI *plci, byte Rc)
{
- word Info;
word internal_command;
dbug (1, dprintf ("[%06lx] %s,%d: rtp_connect_b3_res_command %02x %04x",
UnMapId (Id), (char *)(FILE_), __LINE__, Rc, plci->internal_command));
- Info = GOOD;
internal_command = plci->internal_command;
plci->internal_command = 0;
switch (internal_command)
@@ -14423,7 +14405,6 @@ static void rtp_connect_b3_res_command (dword Id, PLCI *plci, byte Rc)
{
dbug (1, dprintf ("[%06lx] %s,%d: RTP setting connect resp info failed %02x",
UnMapId (Id), (char *)(FILE_), __LINE__, Rc));
- Info = _WRONG_STATE;
break;
}
if (plci_nl_busy (plci))
diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c
index 4343abac0b13..b01a7be1300f 100644
--- a/drivers/isdn/hardware/mISDN/hfcpci.c
+++ b/drivers/isdn/hardware/mISDN/hfcpci.c
@@ -405,7 +405,7 @@ hfcpci_empty_bfifo(struct bchannel *bch, struct bzfifo *bz,
u_char *bdata, int count)
{
u_char *ptr, *ptr1, new_f2;
- int total, maxlen, new_z2;
+ int maxlen, new_z2;
struct zt *zp;
if ((bch->debug & DEBUG_HW_BCHANNEL) && !(bch->debug & DEBUG_HW_BFIFO))
@@ -431,7 +431,6 @@ hfcpci_empty_bfifo(struct bchannel *bch, struct bzfifo *bz,
printk(KERN_WARNING "HFCPCI: receive out of memory\n");
return;
}
- total = count;
count -= 3;
ptr = skb_put(bch->rx_skb, count);
@@ -968,7 +967,6 @@ static void
ph_state_nt(struct dchannel *dch)
{
struct hfc_pci *hc = dch->hw;
- u_char val;
if (dch->debug)
printk(KERN_DEBUG "%s: NT newstate %x\n",
@@ -982,7 +980,7 @@ ph_state_nt(struct dchannel *dch)
hc->hw.int_m1 &= ~HFCPCI_INTS_TIMER;
Write_hfc(hc, HFCPCI_INT_M1, hc->hw.int_m1);
/* Clear already pending ints */
- val = Read_hfc(hc, HFCPCI_INT_S1);
+ (void) Read_hfc(hc, HFCPCI_INT_S1);
Write_hfc(hc, HFCPCI_STATES, 4 | HFCPCI_LOAD_STATE);
udelay(10);
Write_hfc(hc, HFCPCI_STATES, 4);
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c
index 8700474747e8..3ccbff13eaf2 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.c
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.c
@@ -118,14 +118,12 @@ static void
ctrl_complete(struct urb *urb)
{
struct hfcsusb *hw = (struct hfcsusb *) urb->context;
- struct ctrl_buf *buf;
if (debug & DBG_HFC_CALL_TRACE)
printk(KERN_DEBUG "%s: %s\n", hw->name, __func__);
urb->dev = hw->dev;
if (hw->ctrl_cnt) {
- buf = &hw->ctrl_buff[hw->ctrl_out_idx];
hw->ctrl_cnt--; /* decrement actual count */
if (++hw->ctrl_out_idx >= HFC_CTRL_BUFSIZE)
hw->ctrl_out_idx = 0; /* pointer wrap */
@@ -1726,7 +1724,6 @@ hfcsusb_stop_endpoint(struct hfcsusb *hw, int channel)
static int
setup_hfcsusb(struct hfcsusb *hw)
{
- int err;
u_char b;
if (debug & DBG_HFC_CALL_TRACE)
@@ -1745,7 +1742,7 @@ setup_hfcsusb(struct hfcsusb *hw)
}
/* first set the needed config, interface and alternate */
- err = usb_set_interface(hw->dev, hw->if_used, hw->alt_used);
+ (void) usb_set_interface(hw->dev, hw->if_used, hw->alt_used);
hw->led_state = 0;
diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c
index 54ae71a907f9..db25b6b2ae39 100644
--- a/drivers/isdn/hardware/mISDN/netjet.c
+++ b/drivers/isdn/hardware/mISDN/netjet.c
@@ -1072,6 +1072,12 @@ nj_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return -ENODEV;
}
+ if (pdev->subsystem_vendor == 0xb100 &&
+ pdev->subsystem_device == 0x0003 ) {
+ pr_notice("Netjet: Digium TDM400P not handled yet\n");
+ return -ENODEV;
+ }
+
card = kzalloc(sizeof(struct tiger_hw), GFP_ATOMIC);
if (!card) {
pr_info("No kmem for Netjet\n");
diff --git a/drivers/isdn/hisax/arcofi.c b/drivers/isdn/hisax/arcofi.c
index 85a8fd8dd0b7..21cbbe1d5563 100644
--- a/drivers/isdn/hisax/arcofi.c
+++ b/drivers/isdn/hisax/arcofi.c
@@ -30,8 +30,6 @@ add_arcofi_timer(struct IsdnCardState *cs) {
static void
send_arcofi(struct IsdnCardState *cs) {
- u_char val;
-
add_arcofi_timer(cs);
cs->dc.isac.mon_txp = 0;
cs->dc.isac.mon_txc = cs->dc.isac.arcofi_list->len;
@@ -45,7 +43,7 @@ send_arcofi(struct IsdnCardState *cs) {
cs->dc.isac.mocr &= 0x0f;
cs->dc.isac.mocr |= 0xa0;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
- val = cs->readisac(cs, ISAC_MOSR);
+ (void) cs->readisac(cs, ISAC_MOSR);
cs->writeisac(cs, ISAC_MOX1, cs->dc.isac.mon_tx[cs->dc.isac.mon_txp++]);
cs->dc.isac.mocr |= 0x10;
cs->writeisac(cs, ISAC_MOCR, cs->dc.isac.mocr);
diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c
index ac4dd7857cbd..8f0ad2a52e87 100644
--- a/drivers/isdn/hisax/avma1_cs.c
+++ b/drivers/isdn/hisax/avma1_cs.c
@@ -146,7 +146,7 @@ static void avma1cs_release(struct pcmcia_device *link)
pcmcia_disable_device(link);
} /* avma1cs_release */
-static struct pcmcia_device_id avma1cs_ids[] = {
+static const struct pcmcia_device_id avma1cs_ids[] = {
PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb),
PCMCIA_DEVICE_PROD_ID12("ISDN", "CARD", 0x8d9761c8, 0x01c5aa7b),
PCMCIA_DEVICE_NULL
diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c
index 496d477af0f8..f0b6c0ef99bb 100644
--- a/drivers/isdn/hisax/elsa_cs.c
+++ b/drivers/isdn/hisax/elsa_cs.c
@@ -129,12 +129,10 @@ static int elsa_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data)
static int __devinit elsa_cs_config(struct pcmcia_device *link)
{
- local_info_t *dev;
int i;
IsdnCard_t icard;
dev_dbg(&link->dev, "elsa_config(0x%p)\n", link);
- dev = link->priv;
link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
@@ -202,7 +200,7 @@ static int elsa_resume(struct pcmcia_device *link)
return 0;
}
-static struct pcmcia_device_id elsa_ids[] = {
+static const struct pcmcia_device_id elsa_ids[] = {
PCMCIA_DEVICE_PROD_ID12("ELSA AG (Aachen, Germany)", "MicroLink ISDN/MC ", 0x983de2c4, 0x333ba257),
PCMCIA_DEVICE_PROD_ID12("ELSA GmbH, Aachen", "MicroLink ISDN/MC ", 0x639e5718, 0x333ba257),
PCMCIA_DEVICE_NULL
diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c
index cbda3790a10d..3fa9f6171095 100644
--- a/drivers/isdn/hisax/elsa_ser.c
+++ b/drivers/isdn/hisax/elsa_ser.c
@@ -109,11 +109,10 @@ static void change_speed(struct IsdnCardState *cs, int baud)
{
int quot = 0, baud_base;
unsigned cval, fcr = 0;
- int bits;
/* byte size and parity */
- cval = 0x03; bits = 10;
+ cval = 0x03;
/* Determine divisor based on baud rate */
baud_base = BASE_BAUD;
quot = baud_base / baud;
diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
index ed9527aa5f2c..f407de0e006d 100644
--- a/drivers/isdn/hisax/hfc_usb.c
+++ b/drivers/isdn/hisax/hfc_usb.c
@@ -258,11 +258,9 @@ static void
ctrl_complete(struct urb *urb)
{
hfcusb_data *hfc = (hfcusb_data *) urb->context;
- ctrl_buft *buf;
urb->dev = hfc->dev;
if (hfc->ctrl_cnt) {
- buf = &hfc->ctrl_buff[hfc->ctrl_out_idx];
hfc->ctrl_cnt--; /* decrement actual count */
if (++hfc->ctrl_out_idx >= HFC_CTRL_BUFSIZE)
hfc->ctrl_out_idx = 0; /* pointer wrap */
@@ -1097,7 +1095,7 @@ static int
hfc_usb_init(hfcusb_data * hfc)
{
usb_fifo *fifo;
- int i, err;
+ int i;
u_char b;
struct hisax_b_if *p_b_if[2];
@@ -1112,7 +1110,7 @@ hfc_usb_init(hfcusb_data * hfc)
}
/* first set the needed config, interface and alternate */
- err = usb_set_interface(hfc->dev, hfc->if_used, hfc->alt_used);
+ usb_set_interface(hfc->dev, hfc->if_used, hfc->alt_used);
/* do Chip reset */
write_usb(hfc, HFCUSB_CIRM, 8);
diff --git a/drivers/isdn/hisax/ipacx.c b/drivers/isdn/hisax/ipacx.c
index 332104103e18..690840444184 100644
--- a/drivers/isdn/hisax/ipacx.c
+++ b/drivers/isdn/hisax/ipacx.c
@@ -96,7 +96,7 @@ dch_l2l1(struct PStack *st, int pr, void *arg)
{
struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
struct sk_buff *skb = arg;
- u_char cda1_cr, cda2_cr;
+ u_char cda1_cr;
switch (pr) {
case (PH_DATA |REQUEST):
@@ -163,7 +163,7 @@ dch_l2l1(struct PStack *st, int pr, void *arg)
cs->writeisac(cs, IPACX_CDA_TSDP10, 0x80); // Timeslot 0 is B1
cs->writeisac(cs, IPACX_CDA_TSDP11, 0x81); // Timeslot 0 is B1
cda1_cr = cs->readisac(cs, IPACX_CDA1_CR);
- cda2_cr = cs->readisac(cs, IPACX_CDA2_CR);
+ (void) cs->readisac(cs, IPACX_CDA2_CR);
if ((long)arg &1) { // loop B1
cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr |0x0a);
}
diff --git a/drivers/isdn/hisax/jade.c b/drivers/isdn/hisax/jade.c
index ea8f840871d0..a06cea09158b 100644
--- a/drivers/isdn/hisax/jade.c
+++ b/drivers/isdn/hisax/jade.c
@@ -23,10 +23,9 @@
int
JadeVersion(struct IsdnCardState *cs, char *s)
{
- int ver,i;
+ int ver;
int to = 50;
cs->BC_Write_Reg(cs, -1, 0x50, 0x19);
- i=0;
while (to) {
udelay(1);
ver = cs->BC_Read_Reg(cs, -1, 0x60);
diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c
index 8e2fd02ecce0..b0d9ab1f21c0 100644
--- a/drivers/isdn/hisax/l3dss1.c
+++ b/drivers/isdn/hisax/l3dss1.c
@@ -2943,7 +2943,7 @@ global_handler(struct PStack *st, int mt, struct sk_buff *skb)
static void
dss1up(struct PStack *st, int pr, void *arg)
{
- int i, mt, cr, cause, callState;
+ int i, mt, cr, callState;
char *ptr;
u_char *p;
struct sk_buff *skb = arg;
@@ -3034,12 +3034,10 @@ dss1up(struct PStack *st, int pr, void *arg)
return;
}
} else if (mt == MT_STATUS) {
- cause = 0;
if ((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) {
ptr++;
if (*ptr++ == 2)
ptr++;
- cause = *ptr & 0x7f;
}
callState = 0;
if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) {
diff --git a/drivers/isdn/hisax/l3ni1.c b/drivers/isdn/hisax/l3ni1.c
index 7b229c0ce115..092dcbb39d94 100644
--- a/drivers/isdn/hisax/l3ni1.c
+++ b/drivers/isdn/hisax/l3ni1.c
@@ -2883,7 +2883,7 @@ global_handler(struct PStack *st, int mt, struct sk_buff *skb)
static void
ni1up(struct PStack *st, int pr, void *arg)
{
- int i, mt, cr, cause, callState;
+ int i, mt, cr, callState;
char *ptr;
u_char *p;
struct sk_buff *skb = arg;
@@ -2986,12 +2986,10 @@ ni1up(struct PStack *st, int pr, void *arg)
return;
}
} else if (mt == MT_STATUS) {
- cause = 0;
if ((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) {
ptr++;
if (*ptr++ == 2)
ptr++;
- cause = *ptr & 0x7f;
}
callState = 0;
if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) {
diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c
index 360204bc2777..06473f81f039 100644
--- a/drivers/isdn/hisax/sedlbauer_cs.c
+++ b/drivers/isdn/hisax/sedlbauer_cs.c
@@ -186,7 +186,7 @@ static int sedlbauer_resume(struct pcmcia_device *link)
}
-static struct pcmcia_device_id sedlbauer_ids[] = {
+static const struct pcmcia_device_id sedlbauer_ids[] = {
PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "speed star II", "V 3.1", 0x81fb79f5, 0xf3612e1d, 0x6b95c78a),
PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D67", 0x81fb79f5, 0xe4e9bc12, 0x397b7e90),
PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D98", 0x81fb79f5, 0xe4e9bc12, 0x2e5c7fce),
diff --git a/drivers/isdn/hisax/st5481.h b/drivers/isdn/hisax/st5481.h
index 64f78a8c28c5..b9054cb7a0da 100644
--- a/drivers/isdn/hisax/st5481.h
+++ b/drivers/isdn/hisax/st5481.h
@@ -377,7 +377,6 @@ struct st5481_bcs {
};
struct st5481_adapter {
- struct list_head list;
int number_of_leds;
struct usb_device *usb_dev;
struct hisax_d_if hisax_d_if;
diff --git a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c
index 13751237bfcd..9f7fd18ff773 100644
--- a/drivers/isdn/hisax/st5481_init.c
+++ b/drivers/isdn/hisax/st5481_init.c
@@ -46,8 +46,6 @@ module_param(debug, int, 0);
#endif
int st5481_debug;
-static LIST_HEAD(adapter_list);
-
/* ======================================================================
* registration/deregistration with the USB layer
*/
@@ -86,7 +84,6 @@ static int probe_st5481(struct usb_interface *intf,
adapter->bcs[i].b_if.ifc.priv = &adapter->bcs[i];
adapter->bcs[i].b_if.ifc.l2l1 = st5481_b_l2l1;
}
- list_add(&adapter->list, &adapter_list);
retval = st5481_setup_usb(adapter);
if (retval < 0)
@@ -125,6 +122,7 @@ static int probe_st5481(struct usb_interface *intf,
err_usb:
st5481_release_usb(adapter);
err:
+ kfree(adapter);
return -EIO;
}
@@ -142,8 +140,6 @@ static void disconnect_st5481(struct usb_interface *intf)
if (!adapter)
return;
- list_del(&adapter->list);
-
st5481_stop(adapter);
st5481_release_b(&adapter->bcs[1]);
st5481_release_b(&adapter->bcs[0]);
diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c
index aa25e183bf79..161a1938552e 100644
--- a/drivers/isdn/hisax/teles_cs.c
+++ b/drivers/isdn/hisax/teles_cs.c
@@ -111,12 +111,10 @@ static int teles_cs_configcheck(struct pcmcia_device *p_dev, void *priv_data)
static int __devinit teles_cs_config(struct pcmcia_device *link)
{
- local_info_t *dev;
int i;
IsdnCard_t icard;
dev_dbg(&link->dev, "teles_config(0x%p)\n", link);
- dev = link->priv;
i = pcmcia_loop_config(link, teles_cs_configcheck, NULL);
if (i != 0)
@@ -185,7 +183,7 @@ static int teles_resume(struct pcmcia_device *link)
}
-static struct pcmcia_device_id teles_ids[] = {
+static const struct pcmcia_device_id teles_ids[] = {
PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119),
PCMCIA_DEVICE_NULL,
};
diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c
index 2ee93d04b2dd..236cc7dadfd0 100644
--- a/drivers/isdn/hysdn/hysdn_proclog.c
+++ b/drivers/isdn/hysdn/hysdn_proclog.c
@@ -155,7 +155,6 @@ put_log_buffer(hysdn_card * card, char *cp)
static ssize_t
hysdn_log_write(struct file *file, const char __user *buf, size_t count, loff_t * off)
{
- unsigned long u = 0;
int rc;
unsigned char valbuf[128];
hysdn_card *card = file->private_data;
@@ -167,12 +166,10 @@ hysdn_log_write(struct file *file, const char __user *buf, size_t count, loff_t
valbuf[count] = 0; /* terminating 0 */
- 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);
- }
+ rc = kstrtoul(valbuf, 0, &card->debug_flags);
+ if (rc < 0)
+ return rc;
+ hysdn_addlog(card, "debug set to 0x%lx", card->debug_flags);
return (count);
} /* hysdn_log_write */
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index 15632bd2f643..6ed82add6ffa 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -399,13 +399,8 @@ isdn_all_eaz(int di, int ch)
#include <linux/isdn/capicmd.h>
static int
-isdn_capi_rec_hl_msg(capi_msg *cm) {
-
- int di;
- int ch;
-
- di = (cm->adr.Controller & 0x7f) -1;
- ch = isdn_dc2minor(di, (cm->adr.Controller>>8)& 0x7f);
+isdn_capi_rec_hl_msg(capi_msg *cm)
+{
switch(cm->Command) {
case CAPI_FACILITY:
/* in the moment only handled in tty */
@@ -1278,7 +1273,6 @@ isdn_ioctl(struct file *file, uint cmd, ulong arg)
uint minor = iminor(file->f_path.dentry->d_inode);
isdn_ctrl c;
int drvidx;
- int chidx;
int ret;
int i;
char __user *p;
@@ -1340,7 +1334,6 @@ isdn_ioctl(struct file *file, uint cmd, ulong arg)
drvidx = isdn_minor2drv(minor);
if (drvidx < 0)
return -ENODEV;
- chidx = isdn_minor2chan(minor);
if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
return -ENODEV;
return 0;
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index 2a7d17c19489..97988111e45a 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -1678,7 +1678,6 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
u32 your_seq;
__be32 local;
__be32 *addr, *mask;
- u16 unused;
if (skb->len < 14)
return;
@@ -1722,7 +1721,6 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb)
lp->cisco_last_slarp_in = jiffies;
my_seq = be32_to_cpup((__be32 *)(p + 0));
your_seq = be32_to_cpup((__be32 *)(p + 4));
- unused = be16_to_cpup((__be16 *)(p + 8));
p += 10;
lp->cisco_yourseq = my_seq;
lp->cisco_mineseen = your_seq;
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 607d846ae063..d8504279e502 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -998,7 +998,6 @@ isdn_tty_change_speed(modem_info * info)
{
uint cflag,
cval,
- fcr,
quot;
int i;
@@ -1037,7 +1036,6 @@ isdn_tty_change_speed(modem_info * info)
cval |= UART_LCR_PARITY;
if (!(cflag & PARODD))
cval |= UART_LCR_EPAR;
- fcr = 0;
/* CTS flow control flag and modem status interrupts */
if (cflag & CRTSCTS) {
diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c
index d0aeb44ee7c0..5bc00156315e 100644
--- a/drivers/isdn/mISDN/layer2.c
+++ b/drivers/isdn/mISDN/layer2.c
@@ -1640,7 +1640,7 @@ l2_tei_remove(struct FsmInst *fi, int event, void *arg)
}
static void
-l2_st14_persistant_da(struct FsmInst *fi, int event, void *arg)
+l2_st14_persistent_da(struct FsmInst *fi, int event, void *arg)
{
struct layer2 *l2 = fi->userdata;
struct sk_buff *skb = arg;
@@ -1654,7 +1654,7 @@ l2_st14_persistant_da(struct FsmInst *fi, int event, void *arg)
}
static void
-l2_st5_persistant_da(struct FsmInst *fi, int event, void *arg)
+l2_st5_persistent_da(struct FsmInst *fi, int event, void *arg)
{
struct layer2 *l2 = fi->userdata;
struct sk_buff *skb = arg;
@@ -1671,7 +1671,7 @@ l2_st5_persistant_da(struct FsmInst *fi, int event, void *arg)
}
static void
-l2_st6_persistant_da(struct FsmInst *fi, int event, void *arg)
+l2_st6_persistent_da(struct FsmInst *fi, int event, void *arg)
{
struct layer2 *l2 = fi->userdata;
struct sk_buff *skb = arg;
@@ -1685,7 +1685,7 @@ l2_st6_persistant_da(struct FsmInst *fi, int event, void *arg)
}
static void
-l2_persistant_da(struct FsmInst *fi, int event, void *arg)
+l2_persistent_da(struct FsmInst *fi, int event, void *arg)
{
struct layer2 *l2 = fi->userdata;
struct sk_buff *skb = arg;
@@ -1829,14 +1829,14 @@ static struct FsmNode L2FnList[] =
{ST_L2_6, EV_L2_FRAME_ERROR, l2_frame_error},
{ST_L2_7, EV_L2_FRAME_ERROR, l2_frame_error_reest},
{ST_L2_8, EV_L2_FRAME_ERROR, l2_frame_error_reest},
- {ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistant_da},
+ {ST_L2_1, EV_L1_DEACTIVATE, l2_st14_persistent_da},
{ST_L2_2, EV_L1_DEACTIVATE, l2_st24_tei_remove},
{ST_L2_3, EV_L1_DEACTIVATE, l2_st3_tei_remove},
- {ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistant_da},
- {ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistant_da},
- {ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistant_da},
- {ST_L2_7, EV_L1_DEACTIVATE, l2_persistant_da},
- {ST_L2_8, EV_L1_DEACTIVATE, l2_persistant_da},
+ {ST_L2_4, EV_L1_DEACTIVATE, l2_st14_persistent_da},
+ {ST_L2_5, EV_L1_DEACTIVATE, l2_st5_persistent_da},
+ {ST_L2_6, EV_L1_DEACTIVATE, l2_st6_persistent_da},
+ {ST_L2_7, EV_L1_DEACTIVATE, l2_persistent_da},
+ {ST_L2_8, EV_L1_DEACTIVATE, l2_persistent_da},
};
static int
diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c
index 7446d8b4282d..8e325227b4c0 100644
--- a/drivers/isdn/mISDN/socket.c
+++ b/drivers/isdn/mISDN/socket.c
@@ -457,6 +457,9 @@ static int data_sock_getsockopt(struct socket *sock, int level, int optname,
if (get_user(len, optlen))
return -EFAULT;
+ if (len != sizeof(char))
+ return -EINVAL;
+
switch (optname) {
case MISDN_TIME_STAMP:
if (_pms(sk)->cmask & MISDN_TIME_STAMP)
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 9bec8699b8a3..23f0d5e99f35 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -14,6 +14,13 @@ config LEDS_CLASS
This option enables the led sysfs class in /sys/class/leds. You'll
need this to do anything useful with LEDs. If unsure, say N.
+config LEDS_GPIO_REGISTER
+ bool
+ help
+ This option provides the function gpio_led_register_device.
+ As this function is used by arch code it must not be compiled as a
+ module.
+
if NEW_LEDS
comment "LED drivers"
@@ -115,13 +122,6 @@ config LEDS_ALIX2
This option enables support for the PCEngines ALIX.2 and ALIX.3 LEDs.
You have to set leds-alix2.force=1 for boards with Award BIOS.
-config LEDS_H1940
- tristate "LED Support for iPAQ H1940 device"
- depends on LEDS_CLASS
- depends on ARCH_H1940
- help
- This option enables support for the LEDs on the h1940.
-
config LEDS_COBALT_QUBE
tristate "LED Support for the Cobalt Qube series front LED"
depends on LEDS_CLASS
@@ -162,6 +162,16 @@ config LEDS_PCA9532
LED controller. It is generally only useful
as a platform driver
+config LEDS_PCA9532_GPIO
+ bool "Enable GPIO support for PCA9532"
+ depends on LEDS_PCA9532
+ depends on GPIOLIB
+ help
+ Allow unused pins on PCA9532 to be used as gpio.
+
+ To use a pin as gpio pca9532_type in pca9532_platform data needs to
+ set to PCA9532_TYPE_GPIO.
+
config LEDS_GPIO
tristate "LED Support for GPIO connected LEDs"
depends on LEDS_CLASS
@@ -379,6 +389,16 @@ config LEDS_NETXBIG
and 5Big Network v2 boards. The LEDs are wired to a CPLD and are
controlled through a GPIO extension bus.
+config LEDS_ASIC3
+ bool "LED support for the HTC ASIC3"
+ depends on MFD_ASIC3
+ default y
+ help
+ This option enables support for the LEDs on the HTC ASIC3. The HTC
+ ASIC3 LED GPIOs are inputs, not outputs, thus the leds-gpio driver
+ cannot be used. This driver supports hardware blinking with an on+off
+ period from 62ms to 125s. Say Y to enable LEDs on the HP iPAQ hx4700.
+
config LEDS_TRIGGERS
bool "LED Trigger support"
depends on LEDS_CLASS
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 39c80fca84d2..bbfd2e367dc0 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -17,11 +17,11 @@ obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
obj-$(CONFIG_LEDS_NET5501) += leds-net5501.o
obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o
obj-$(CONFIG_LEDS_ALIX2) += leds-alix2.o
-obj-$(CONFIG_LEDS_H1940) += leds-h1940.o
obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o
obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o
obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o
obj-$(CONFIG_LEDS_PCA9532) += leds-pca9532.o
+obj-$(CONFIG_LEDS_GPIO_REGISTER) += leds-gpio-register.o
obj-$(CONFIG_LEDS_GPIO) += leds-gpio.o
obj-$(CONFIG_LEDS_LP3944) += leds-lp3944.o
obj-$(CONFIG_LEDS_LP5521) += leds-lp5521.o
@@ -42,6 +42,7 @@ obj-$(CONFIG_LEDS_DELL_NETBOOKS) += dell-led.o
obj-$(CONFIG_LEDS_MC13783) += leds-mc13783.o
obj-$(CONFIG_LEDS_NS2) += leds-ns2.o
obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o
+obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o
# LED SPI Drivers
obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index d5a4ade88991..dc3d3d83191a 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -131,7 +131,8 @@ static void led_set_software_blink(struct led_classdev *led_cdev,
if (!led_cdev->blink_brightness)
led_cdev->blink_brightness = led_cdev->max_brightness;
- if (delay_on == led_cdev->blink_delay_on &&
+ if (led_get_trigger_data(led_cdev) &&
+ delay_on == led_cdev->blink_delay_on &&
delay_off == led_cdev->blink_delay_off)
return;
diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c
index 416def84d045..0d4c16678ace 100644
--- a/drivers/leds/leds-88pm860x.c
+++ b/drivers/leds/leds-88pm860x.c
@@ -17,7 +17,6 @@
#include <linux/leds.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
-#include <linux/mfd/core.h>
#include <linux/mfd/88pm860x.h>
#define LED_PWM_SHIFT (3)
@@ -171,7 +170,6 @@ static int pm860x_led_probe(struct platform_device *pdev)
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
struct pm860x_led_pdata *pdata;
struct pm860x_led *data;
- struct mfd_cell *cell;
struct resource *res;
int ret;
@@ -181,10 +179,7 @@ static int pm860x_led_probe(struct platform_device *pdev)
return -EINVAL;
}
- cell = pdev->dev.platform_data;
- if (cell == NULL)
- return -ENODEV;
- pdata = cell->mfd_data;
+ pdata = pdev->dev.platform_data;
if (pdata == NULL) {
dev_err(&pdev->dev, "No platform data!\n");
return -EINVAL;
diff --git a/drivers/leds/leds-asic3.c b/drivers/leds/leds-asic3.c
new file mode 100644
index 000000000000..22f847c890c9
--- /dev/null
+++ b/drivers/leds/leds-asic3.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2011 Paul Parsons <lost.distance@yahoo.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
+
+#include <linux/mfd/asic3.h>
+#include <linux/mfd/core.h>
+
+/*
+ * The HTC ASIC3 LED GPIOs are inputs, not outputs.
+ * Hence we turn the LEDs on/off via the TimeBase register.
+ */
+
+/*
+ * When TimeBase is 4 the clock resolution is about 32Hz.
+ * This driver supports hardware blinking with an on+off
+ * period from 62ms (2 clocks) to 125s (4000 clocks).
+ */
+#define MS_TO_CLK(ms) DIV_ROUND_CLOSEST(((ms)*1024), 32000)
+#define CLK_TO_MS(clk) (((clk)*32000)/1024)
+#define MAX_CLK 4000 /* Fits into 12-bit Time registers */
+#define MAX_MS CLK_TO_MS(MAX_CLK)
+
+static const unsigned int led_n_base[ASIC3_NUM_LEDS] = {
+ [0] = ASIC3_LED_0_Base,
+ [1] = ASIC3_LED_1_Base,
+ [2] = ASIC3_LED_2_Base,
+};
+
+static void brightness_set(struct led_classdev *cdev,
+ enum led_brightness value)
+{
+ struct platform_device *pdev = to_platform_device(cdev->dev->parent);
+ const struct mfd_cell *cell = mfd_get_cell(pdev);
+ struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
+ u32 timebase;
+ unsigned int base;
+
+ timebase = (value == LED_OFF) ? 0 : (LED_EN|0x4);
+
+ base = led_n_base[cell->id];
+ asic3_write_register(asic, (base + ASIC3_LED_PeriodTime), 32);
+ asic3_write_register(asic, (base + ASIC3_LED_DutyTime), 32);
+ asic3_write_register(asic, (base + ASIC3_LED_AutoStopCount), 0);
+ asic3_write_register(asic, (base + ASIC3_LED_TimeBase), timebase);
+}
+
+static int blink_set(struct led_classdev *cdev,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ struct platform_device *pdev = to_platform_device(cdev->dev->parent);
+ const struct mfd_cell *cell = mfd_get_cell(pdev);
+ struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
+ u32 on;
+ u32 off;
+ unsigned int base;
+
+ if (*delay_on > MAX_MS || *delay_off > MAX_MS)
+ return -EINVAL;
+
+ if (*delay_on == 0 && *delay_off == 0) {
+ /* If both are zero then a sensible default should be chosen */
+ on = MS_TO_CLK(500);
+ off = MS_TO_CLK(500);
+ } else {
+ on = MS_TO_CLK(*delay_on);
+ off = MS_TO_CLK(*delay_off);
+ if ((on + off) > MAX_CLK)
+ return -EINVAL;
+ }
+
+ base = led_n_base[cell->id];
+ asic3_write_register(asic, (base + ASIC3_LED_PeriodTime), (on + off));
+ asic3_write_register(asic, (base + ASIC3_LED_DutyTime), on);
+ asic3_write_register(asic, (base + ASIC3_LED_AutoStopCount), 0);
+ asic3_write_register(asic, (base + ASIC3_LED_TimeBase), (LED_EN|0x4));
+
+ *delay_on = CLK_TO_MS(on);
+ *delay_off = CLK_TO_MS(off);
+
+ return 0;
+}
+
+static int __devinit asic3_led_probe(struct platform_device *pdev)
+{
+ struct asic3_led *led = pdev->dev.platform_data;
+ int ret;
+
+ ret = mfd_cell_enable(pdev);
+ if (ret < 0)
+ goto ret0;
+
+ led->cdev = kzalloc(sizeof(struct led_classdev), GFP_KERNEL);
+ if (!led->cdev) {
+ ret = -ENOMEM;
+ goto ret1;
+ }
+
+ led->cdev->name = led->name;
+ led->cdev->default_trigger = led->default_trigger;
+ led->cdev->brightness_set = brightness_set;
+ led->cdev->blink_set = blink_set;
+
+ ret = led_classdev_register(&pdev->dev, led->cdev);
+ if (ret < 0)
+ goto ret2;
+
+ return 0;
+
+ret2:
+ kfree(led->cdev);
+ret1:
+ (void) mfd_cell_disable(pdev);
+ret0:
+ return ret;
+}
+
+static int __devexit asic3_led_remove(struct platform_device *pdev)
+{
+ struct asic3_led *led = pdev->dev.platform_data;
+
+ led_classdev_unregister(led->cdev);
+
+ kfree(led->cdev);
+
+ return mfd_cell_disable(pdev);
+}
+
+static struct platform_driver asic3_led_driver = {
+ .probe = asic3_led_probe,
+ .remove = __devexit_p(asic3_led_remove),
+ .driver = {
+ .name = "leds-asic3",
+ .owner = THIS_MODULE,
+ },
+};
+
+MODULE_ALIAS("platform:leds-asic3");
+
+static int __init asic3_led_init(void)
+{
+ return platform_driver_register(&asic3_led_driver);
+}
+
+static void __exit asic3_led_exit(void)
+{
+ platform_driver_unregister(&asic3_led_driver);
+}
+
+module_init(asic3_led_init);
+module_exit(asic3_led_exit);
+
+MODULE_AUTHOR("Paul Parsons <lost.distance@yahoo.com>");
+MODULE_DESCRIPTION("HTC ASIC3 LED driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/leds-gpio-register.c b/drivers/leds/leds-gpio-register.c
new file mode 100644
index 000000000000..1c4ed5510f35
--- /dev/null
+++ b/drivers/leds/leds-gpio-register.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2011 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.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/err.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
+
+/**
+ * gpio_led_register_device - register a gpio-led device
+ * @pdata: the platform data used for the new device
+ *
+ * Makes a copy of pdata and pdata->leds and registers a new leds-gpio device
+ * with the result. This allows to have pdata and pdata-leds in .init.rodata
+ * and so saves some bytes compared to a static struct platform_device with
+ * static platform data.
+ *
+ * Returns the registered device or an error pointer.
+ */
+struct platform_device *__init gpio_led_register_device(
+ int id, const struct gpio_led_platform_data *pdata)
+{
+ struct platform_device *ret;
+ struct gpio_led_platform_data _pdata = *pdata;
+
+ _pdata.leds = kmemdup(pdata->leds,
+ pdata->num_leds * sizeof(*pdata->leds), GFP_KERNEL);
+ if (!_pdata.leds)
+ return ERR_PTR(-ENOMEM);
+
+ ret = platform_device_register_resndata(NULL, "leds-gpio", id,
+ NULL, 0, &_pdata, sizeof(_pdata));
+ if (IS_ERR(ret))
+ kfree(_pdata.leds);
+
+ return ret;
+}
diff --git a/drivers/leds/leds-h1940.c b/drivers/leds/leds-h1940.c
deleted file mode 100644
index 173d104d9ff2..000000000000
--- a/drivers/leds/leds-h1940.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * drivers/leds/leds-h1940.c
- * Copyright (c) Arnaud Patard <arnaud.patard@rtp-net.org>
- *
- * 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.
- *
- * H1940 leds driver
- *
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/leds.h>
-#include <linux/gpio.h>
-
-#include <mach/regs-gpio.h>
-#include <mach/hardware.h>
-#include <mach/h1940-latch.h>
-
-/*
- * Green led.
- */
-static void h1940_greenled_set(struct led_classdev *led_dev,
- enum led_brightness value)
-{
- switch (value) {
- case LED_HALF:
- h1940_latch_control(0, H1940_LATCH_LED_FLASH);
- s3c2410_gpio_setpin(S3C2410_GPA7, 1);
- break;
- case LED_FULL:
- h1940_latch_control(0, H1940_LATCH_LED_GREEN);
- s3c2410_gpio_setpin(S3C2410_GPA7, 1);
- break;
- default:
- case LED_OFF:
- h1940_latch_control(H1940_LATCH_LED_FLASH, 0);
- h1940_latch_control(H1940_LATCH_LED_GREEN, 0);
- s3c2410_gpio_setpin(S3C2410_GPA7, 0);
- break;
- }
-}
-
-static struct led_classdev h1940_greenled = {
- .name = "h1940:green",
- .brightness_set = h1940_greenled_set,
- .default_trigger = "h1940-charger",
-};
-
-/*
- * Red led.
- */
-static void h1940_redled_set(struct led_classdev *led_dev,
- enum led_brightness value)
-{
- switch (value) {
- case LED_HALF:
- h1940_latch_control(0, H1940_LATCH_LED_FLASH);
- s3c2410_gpio_setpin(S3C2410_GPA1, 1);
- break;
- case LED_FULL:
- h1940_latch_control(0, H1940_LATCH_LED_RED);
- s3c2410_gpio_setpin(S3C2410_GPA1, 1);
- break;
- default:
- case LED_OFF:
- h1940_latch_control(H1940_LATCH_LED_FLASH, 0);
- h1940_latch_control(H1940_LATCH_LED_RED, 0);
- s3c2410_gpio_setpin(S3C2410_GPA1, 0);
- break;
- }
-}
-
-static struct led_classdev h1940_redled = {
- .name = "h1940:red",
- .brightness_set = h1940_redled_set,
- .default_trigger = "h1940-charger",
-};
-
-/*
- * Blue led.
- * (it can only be blue flashing led)
- */
-static void h1940_blueled_set(struct led_classdev *led_dev,
- enum led_brightness value)
-{
- if (value) {
- /* flashing Blue */
- h1940_latch_control(0, H1940_LATCH_LED_FLASH);
- s3c2410_gpio_setpin(S3C2410_GPA3, 1);
- } else {
- h1940_latch_control(H1940_LATCH_LED_FLASH, 0);
- s3c2410_gpio_setpin(S3C2410_GPA3, 0);
- }
-
-}
-
-static struct led_classdev h1940_blueled = {
- .name = "h1940:blue",
- .brightness_set = h1940_blueled_set,
- .default_trigger = "h1940-bluetooth",
-};
-
-static int __devinit h1940leds_probe(struct platform_device *pdev)
-{
- int ret;
-
- ret = led_classdev_register(&pdev->dev, &h1940_greenled);
- if (ret)
- goto err_green;
-
- ret = led_classdev_register(&pdev->dev, &h1940_redled);
- if (ret)
- goto err_red;
-
- ret = led_classdev_register(&pdev->dev, &h1940_blueled);
- if (ret)
- goto err_blue;
-
- return 0;
-
-err_blue:
- led_classdev_unregister(&h1940_redled);
-err_red:
- led_classdev_unregister(&h1940_greenled);
-err_green:
- return ret;
-}
-
-static int h1940leds_remove(struct platform_device *pdev)
-{
- led_classdev_unregister(&h1940_greenled);
- led_classdev_unregister(&h1940_redled);
- led_classdev_unregister(&h1940_blueled);
- return 0;
-}
-
-
-static struct platform_driver h1940leds_driver = {
- .driver = {
- .name = "h1940-leds",
- .owner = THIS_MODULE,
- },
- .probe = h1940leds_probe,
- .remove = h1940leds_remove,
-};
-
-
-static int __init h1940leds_init(void)
-{
- return platform_driver_register(&h1940leds_driver);
-}
-
-static void __exit h1940leds_exit(void)
-{
- platform_driver_unregister(&h1940leds_driver);
-}
-
-module_init(h1940leds_init);
-module_exit(h1940leds_exit);
-
-MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
-MODULE_DESCRIPTION("LED driver for the iPAQ H1940");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:h1940-leds");
diff --git a/drivers/leds/leds-lm3530.c b/drivers/leds/leds-lm3530.c
index b37e6186d0fa..4d7ce7631acf 100644
--- a/drivers/leds/leds-lm3530.c
+++ b/drivers/leds/leds-lm3530.c
@@ -17,6 +17,7 @@
#include <linux/input.h>
#include <linux/led-lm3530.h>
#include <linux/types.h>
+#include <linux/regulator/consumer.h>
#define LM3530_LED_DEV "lcd-backlight"
#define LM3530_NAME "lm3530-led"
@@ -96,12 +97,18 @@ static struct lm3530_mode_map mode_map[] = {
* @client: i2c client
* @pdata: LM3530 platform data
* @mode: mode of operation - manual, ALS, PWM
+ * @regulator: regulator
+ * @brighness: previous brightness value
+ * @enable: regulator is enabled
*/
struct lm3530_data {
struct led_classdev led_dev;
struct i2c_client *client;
struct lm3530_platform_data *pdata;
enum lm3530_mode mode;
+ struct regulator *regulator;
+ enum led_brightness brightness;
+ bool enable;
};
static const u8 lm3530_reg[LM3530_REG_MAX] = {
@@ -172,7 +179,10 @@ static int lm3530_init_registers(struct lm3530_data *drvdata)
brt_ramp = (pltfm->brt_ramp_fall << LM3530_BRT_RAMP_FALL_SHIFT) |
(pltfm->brt_ramp_rise << LM3530_BRT_RAMP_RISE_SHIFT);
- brightness = pltfm->brt_val;
+ if (drvdata->brightness)
+ brightness = drvdata->brightness;
+ else
+ brightness = drvdata->brightness = pltfm->brt_val;
reg_val[0] = gen_config; /* LM3530_GEN_CONFIG */
reg_val[1] = als_config; /* LM3530_ALS_CONFIG */
@@ -190,6 +200,16 @@ static int lm3530_init_registers(struct lm3530_data *drvdata)
reg_val[13] = LM3530_DEF_ZT_3; /* LM3530_ALS_Z3T_REG */
reg_val[14] = LM3530_DEF_ZT_4; /* LM3530_ALS_Z4T_REG */
+ if (!drvdata->enable) {
+ ret = regulator_enable(drvdata->regulator);
+ if (ret) {
+ dev_err(&drvdata->client->dev,
+ "Enable regulator failed\n");
+ return ret;
+ }
+ drvdata->enable = true;
+ }
+
for (i = 0; i < LM3530_REG_MAX; i++) {
ret = i2c_smbus_write_byte_data(client,
lm3530_reg[i], reg_val[i]);
@@ -210,12 +230,31 @@ static void lm3530_brightness_set(struct led_classdev *led_cdev,
switch (drvdata->mode) {
case LM3530_BL_MODE_MANUAL:
+ if (!drvdata->enable) {
+ err = lm3530_init_registers(drvdata);
+ if (err) {
+ dev_err(&drvdata->client->dev,
+ "Register Init failed: %d\n", err);
+ break;
+ }
+ }
+
/* set the brightness in brightness control register*/
err = i2c_smbus_write_byte_data(drvdata->client,
LM3530_BRT_CTRL_REG, brt_val / 2);
if (err)
dev_err(&drvdata->client->dev,
"Unable to set brightness: %d\n", err);
+ else
+ drvdata->brightness = brt_val / 2;
+
+ if (brt_val == 0) {
+ err = regulator_disable(drvdata->regulator);
+ if (err)
+ dev_err(&drvdata->client->dev,
+ "Disable regulator failed\n");
+ drvdata->enable = false;
+ }
break;
case LM3530_BL_MODE_ALS:
break;
@@ -297,20 +336,31 @@ static int __devinit lm3530_probe(struct i2c_client *client,
drvdata->mode = pdata->mode;
drvdata->client = client;
drvdata->pdata = pdata;
+ drvdata->brightness = LED_OFF;
+ drvdata->enable = false;
drvdata->led_dev.name = LM3530_LED_DEV;
drvdata->led_dev.brightness_set = lm3530_brightness_set;
i2c_set_clientdata(client, drvdata);
- err = lm3530_init_registers(drvdata);
- if (err < 0) {
- dev_err(&client->dev, "Register Init failed: %d\n", err);
- err = -ENODEV;
- goto err_reg_init;
+ drvdata->regulator = regulator_get(&client->dev, "vin");
+ if (IS_ERR(drvdata->regulator)) {
+ dev_err(&client->dev, "regulator get failed\n");
+ err = PTR_ERR(drvdata->regulator);
+ drvdata->regulator = NULL;
+ goto err_regulator_get;
}
- err = led_classdev_register((struct device *)
- &client->dev, &drvdata->led_dev);
+ if (drvdata->pdata->brt_val) {
+ err = lm3530_init_registers(drvdata);
+ if (err < 0) {
+ dev_err(&client->dev,
+ "Register Init failed: %d\n", err);
+ err = -ENODEV;
+ goto err_reg_init;
+ }
+ }
+ err = led_classdev_register(&client->dev, &drvdata->led_dev);
if (err < 0) {
dev_err(&client->dev, "Register led class failed: %d\n", err);
err = -ENODEV;
@@ -330,6 +380,9 @@ err_create_file:
led_classdev_unregister(&drvdata->led_dev);
err_class_register:
err_reg_init:
+ regulator_put(drvdata->regulator);
+err_regulator_get:
+ i2c_set_clientdata(client, NULL);
kfree(drvdata);
err_out:
return err;
@@ -340,6 +393,10 @@ static int __devexit lm3530_remove(struct i2c_client *client)
struct lm3530_data *drvdata = i2c_get_clientdata(client);
device_remove_file(drvdata->led_dev.dev, &dev_attr_mode);
+
+ if (drvdata->enable)
+ regulator_disable(drvdata->regulator);
+ regulator_put(drvdata->regulator);
led_classdev_unregister(&drvdata->led_dev);
kfree(drvdata);
return 0;
diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c
index 06a5bb484707..f369e56d6547 100644
--- a/drivers/leds/leds-mc13783.c
+++ b/drivers/leds/leds-mc13783.c
@@ -22,7 +22,6 @@
#include <linux/leds.h>
#include <linux/workqueue.h>
#include <linux/mfd/mc13783.h>
-#include <linux/mfd/core.h>
#include <linux/slab.h>
struct mc13783_led {
@@ -184,7 +183,7 @@ static int __devinit mc13783_led_setup(struct mc13783_led *led, int max_current)
static int __devinit mc13783_leds_prepare(struct platform_device *pdev)
{
- struct mc13783_leds_platform_data *pdata = mfd_get_data(pdev);
+ struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct mc13783 *dev = dev_get_drvdata(pdev->dev.parent);
int ret = 0;
int reg = 0;
@@ -235,7 +234,7 @@ static int __devinit mc13783_leds_prepare(struct platform_device *pdev)
MC13783_LED_Cx_PERIOD;
if (pdata->flags & MC13783_LED_TRIODE_TC3)
- reg |= MC13783_LED_Cx_TRIODE_TC_BIT;;
+ reg |= MC13783_LED_Cx_TRIODE_TC_BIT;
ret = mc13783_reg_write(dev, MC13783_REG_LED_CONTROL_5, reg);
if (ret)
@@ -265,7 +264,7 @@ out:
static int __devinit mc13783_led_probe(struct platform_device *pdev)
{
- struct mc13783_leds_platform_data *pdata = mfd_get_data(pdev);
+ struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct mc13783_led_platform_data *led_cur;
struct mc13783_led *led, *led_dat;
int ret, i;
@@ -352,7 +351,7 @@ err_free:
static int __devexit mc13783_led_remove(struct platform_device *pdev)
{
- struct mc13783_leds_platform_data *pdata = mfd_get_data(pdev);
+ struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct mc13783_led *led = platform_get_drvdata(pdev);
struct mc13783 *dev = dev_get_drvdata(pdev->dev.parent);
int i;
diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c
index 5bf63af09ddf..d8d3a1e910a1 100644
--- a/drivers/leds/leds-pca9532.c
+++ b/drivers/leds/leds-pca9532.c
@@ -1,13 +1,14 @@
/*
* pca9532.c - 16-bit Led dimmer
*
+ * Copyright (C) 2011 Jan Weitzel
* Copyright (C) 2008 Riku Voipio
*
* This program is free software; 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.
*
- * Datasheet: http://www.nxp.com/acrobat/datasheets/PCA9532_3.pdf
+ * Datasheet: http://www.nxp.com/documents/data_sheet/PCA9532.pdf
*
*/
@@ -19,21 +20,32 @@
#include <linux/mutex.h>
#include <linux/workqueue.h>
#include <linux/leds-pca9532.h>
+#include <linux/gpio.h>
-#define PCA9532_REG_PSC(i) (0x2+(i)*2)
-#define PCA9532_REG_PWM(i) (0x3+(i)*2)
-#define PCA9532_REG_LS0 0x6
-#define LED_REG(led) ((led>>2)+PCA9532_REG_LS0)
-#define LED_NUM(led) (led & 0x3)
+/* m = num_leds*/
+#define PCA9532_REG_INPUT(i) ((i) >> 3)
+#define PCA9532_REG_OFFSET(m) ((m) >> 4)
+#define PCA9532_REG_PSC(m, i) (PCA9532_REG_OFFSET(m) + 0x1 + (i) * 2)
+#define PCA9532_REG_PWM(m, i) (PCA9532_REG_OFFSET(m) + 0x2 + (i) * 2)
+#define LED_REG(m, led) (PCA9532_REG_OFFSET(m) + 0x5 + (led >> 2))
+#define LED_NUM(led) (led & 0x3)
#define ldev_to_led(c) container_of(c, struct pca9532_led, ldev)
+struct pca9532_chip_info {
+ u8 num_leds;
+};
+
struct pca9532_data {
struct i2c_client *client;
struct pca9532_led leds[16];
struct mutex update_lock;
struct input_dev *idev;
struct work_struct work;
+#ifdef CONFIG_LEDS_PCA9532_GPIO
+ struct gpio_chip gpio;
+#endif
+ const struct pca9532_chip_info *chip_info;
u8 pwm[2];
u8 psc[2];
};
@@ -42,16 +54,41 @@ static int pca9532_probe(struct i2c_client *client,
const struct i2c_device_id *id);
static int pca9532_remove(struct i2c_client *client);
+enum {
+ pca9530,
+ pca9531,
+ pca9532,
+ pca9533,
+};
+
static const struct i2c_device_id pca9532_id[] = {
- { "pca9532", 0 },
+ { "pca9530", pca9530 },
+ { "pca9531", pca9531 },
+ { "pca9532", pca9532 },
+ { "pca9533", pca9533 },
{ }
};
MODULE_DEVICE_TABLE(i2c, pca9532_id);
+static const struct pca9532_chip_info pca9532_chip_info_tbl[] = {
+ [pca9530] = {
+ .num_leds = 2,
+ },
+ [pca9531] = {
+ .num_leds = 8,
+ },
+ [pca9532] = {
+ .num_leds = 16,
+ },
+ [pca9533] = {
+ .num_leds = 4,
+ },
+};
+
static struct i2c_driver pca9532_driver = {
.driver = {
- .name = "pca9532",
+ .name = "pca953x",
},
.probe = pca9532_probe,
.remove = pca9532_remove,
@@ -68,7 +105,7 @@ static int pca9532_calcpwm(struct i2c_client *client, int pwm, int blink,
{
int a = 0, b = 0, i = 0;
struct pca9532_data *data = i2c_get_clientdata(client);
- for (i = 0; i < 16; i++) {
+ for (i = 0; i < data->chip_info->num_leds; i++) {
if (data->leds[i].type == PCA9532_TYPE_LED &&
data->leds[i].state == PCA9532_PWM0+pwm) {
a++;
@@ -92,10 +129,12 @@ static int pca9532_calcpwm(struct i2c_client *client, int pwm, int blink,
static int pca9532_setpwm(struct i2c_client *client, int pwm)
{
struct pca9532_data *data = i2c_get_clientdata(client);
+ u8 maxleds = data->chip_info->num_leds;
+
mutex_lock(&data->update_lock);
- i2c_smbus_write_byte_data(client, PCA9532_REG_PWM(pwm),
+ i2c_smbus_write_byte_data(client, PCA9532_REG_PWM(maxleds, pwm),
data->pwm[pwm]);
- i2c_smbus_write_byte_data(client, PCA9532_REG_PSC(pwm),
+ i2c_smbus_write_byte_data(client, PCA9532_REG_PSC(maxleds, pwm),
data->psc[pwm]);
mutex_unlock(&data->update_lock);
return 0;
@@ -106,15 +145,16 @@ static void pca9532_setled(struct pca9532_led *led)
{
struct i2c_client *client = led->client;
struct pca9532_data *data = i2c_get_clientdata(client);
+ u8 maxleds = data->chip_info->num_leds;
char reg;
mutex_lock(&data->update_lock);
- reg = i2c_smbus_read_byte_data(client, LED_REG(led->id));
+ reg = i2c_smbus_read_byte_data(client, LED_REG(maxleds, led->id));
/* zero led bits */
reg = reg & ~(0x3<<LED_NUM(led->id)*2);
/* set the new value */
reg = reg | (led->state << LED_NUM(led->id)*2);
- i2c_smbus_write_byte_data(client, LED_REG(led->id), reg);
+ i2c_smbus_write_byte_data(client, LED_REG(maxleds, led->id), reg);
mutex_unlock(&data->update_lock);
}
@@ -183,10 +223,12 @@ static int pca9532_event(struct input_dev *dev, unsigned int type,
static void pca9532_input_work(struct work_struct *work)
{
- struct pca9532_data *data;
- data = container_of(work, struct pca9532_data, work);
+ struct pca9532_data *data =
+ container_of(work, struct pca9532_data, work);
+ u8 maxleds = data->chip_info->num_leds;
+
mutex_lock(&data->update_lock);
- i2c_smbus_write_byte_data(data->client, PCA9532_REG_PWM(1),
+ i2c_smbus_write_byte_data(data->client, PCA9532_REG_PWM(maxleds, 1),
data->pwm[1]);
mutex_unlock(&data->update_lock);
}
@@ -200,16 +242,68 @@ static void pca9532_led_work(struct work_struct *work)
pca9532_setled(led);
}
-static void pca9532_destroy_devices(struct pca9532_data *data, int n_devs)
+#ifdef CONFIG_LEDS_PCA9532_GPIO
+static int pca9532_gpio_request_pin(struct gpio_chip *gc, unsigned offset)
+{
+ struct pca9532_data *data = container_of(gc, struct pca9532_data, gpio);
+ struct pca9532_led *led = &data->leds[offset];
+
+ if (led->type == PCA9532_TYPE_GPIO)
+ return 0;
+
+ return -EBUSY;
+}
+
+static void pca9532_gpio_set_value(struct gpio_chip *gc, unsigned offset, int val)
+{
+ struct pca9532_data *data = container_of(gc, struct pca9532_data, gpio);
+ struct pca9532_led *led = &data->leds[offset];
+
+ if (val)
+ led->state = PCA9532_ON;
+ else
+ led->state = PCA9532_OFF;
+
+ pca9532_setled(led);
+}
+
+static int pca9532_gpio_get_value(struct gpio_chip *gc, unsigned offset)
+{
+ struct pca9532_data *data = container_of(gc, struct pca9532_data, gpio);
+ unsigned char reg;
+
+ reg = i2c_smbus_read_byte_data(data->client, PCA9532_REG_INPUT(offset));
+
+ return !!(reg & (1 << (offset % 8)));
+}
+
+static int pca9532_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
+{
+ /* To use as input ensure pin is not driven */
+ pca9532_gpio_set_value(gc, offset, 0);
+
+ return 0;
+}
+
+static int pca9532_gpio_direction_output(struct gpio_chip *gc, unsigned offset, int val)
+{
+ pca9532_gpio_set_value(gc, offset, val);
+
+ return 0;
+}
+#endif /* CONFIG_LEDS_PCA9532_GPIO */
+
+static int pca9532_destroy_devices(struct pca9532_data *data, int n_devs)
{
int i = n_devs;
if (!data)
- return;
+ return -EINVAL;
while (--i >= 0) {
switch (data->leds[i].type) {
case PCA9532_TYPE_NONE:
+ case PCA9532_TYPE_GPIO:
break;
case PCA9532_TYPE_LED:
led_classdev_unregister(&data->leds[i].ldev);
@@ -224,23 +318,38 @@ static void pca9532_destroy_devices(struct pca9532_data *data, int n_devs)
break;
}
}
+
+#ifdef CONFIG_LEDS_PCA9532_GPIO
+ if (data->gpio.dev) {
+ int err = gpiochip_remove(&data->gpio);
+ if (err) {
+ dev_err(&data->client->dev, "%s failed, %d\n",
+ "gpiochip_remove()", err);
+ return err;
+ }
+ }
+#endif
+
+ return 0;
}
static int pca9532_configure(struct i2c_client *client,
struct pca9532_data *data, struct pca9532_platform_data *pdata)
{
int i, err = 0;
+ int gpios = 0;
+ u8 maxleds = data->chip_info->num_leds;
for (i = 0; i < 2; i++) {
data->pwm[i] = pdata->pwm[i];
data->psc[i] = pdata->psc[i];
- i2c_smbus_write_byte_data(client, PCA9532_REG_PWM(i),
+ i2c_smbus_write_byte_data(client, PCA9532_REG_PWM(maxleds, i),
data->pwm[i]);
- i2c_smbus_write_byte_data(client, PCA9532_REG_PSC(i),
+ i2c_smbus_write_byte_data(client, PCA9532_REG_PSC(maxleds, i),
data->psc[i]);
}
- for (i = 0; i < 16; i++) {
+ for (i = 0; i < data->chip_info->num_leds; i++) {
struct pca9532_led *led = &data->leds[i];
struct pca9532_led *pled = &pdata->leds[i];
led->client = client;
@@ -249,6 +358,9 @@ static int pca9532_configure(struct i2c_client *client,
switch (led->type) {
case PCA9532_TYPE_NONE:
break;
+ case PCA9532_TYPE_GPIO:
+ gpios++;
+ break;
case PCA9532_TYPE_LED:
led->state = pled->state;
led->name = pled->name;
@@ -297,6 +409,34 @@ static int pca9532_configure(struct i2c_client *client,
break;
}
}
+
+#ifdef CONFIG_LEDS_PCA9532_GPIO
+ if (gpios) {
+ data->gpio.label = "gpio-pca9532";
+ data->gpio.direction_input = pca9532_gpio_direction_input;
+ data->gpio.direction_output = pca9532_gpio_direction_output;
+ data->gpio.set = pca9532_gpio_set_value;
+ data->gpio.get = pca9532_gpio_get_value;
+ data->gpio.request = pca9532_gpio_request_pin;
+ data->gpio.can_sleep = 1;
+ data->gpio.base = pdata->gpio_base;
+ data->gpio.ngpio = data->chip_info->num_leds;
+ data->gpio.dev = &client->dev;
+ data->gpio.owner = THIS_MODULE;
+
+ err = gpiochip_add(&data->gpio);
+ if (err) {
+ /* Use data->gpio.dev as a flag for freeing gpiochip */
+ data->gpio.dev = NULL;
+ dev_warn(&client->dev, "could not add gpiochip\n");
+ } else {
+ dev_info(&client->dev, "gpios %i...%i\n",
+ data->gpio.base, data->gpio.base +
+ data->gpio.ngpio - 1);
+ }
+ }
+#endif
+
return 0;
exit:
@@ -322,6 +462,8 @@ static int pca9532_probe(struct i2c_client *client,
if (!data)
return -ENOMEM;
+ data->chip_info = &pca9532_chip_info_tbl[id->driver_data];
+
dev_info(&client->dev, "setting platform data\n");
i2c_set_clientdata(client, data);
data->client = client;
@@ -337,7 +479,12 @@ static int pca9532_probe(struct i2c_client *client,
static int pca9532_remove(struct i2c_client *client)
{
struct pca9532_data *data = i2c_get_clientdata(client);
- pca9532_destroy_devices(data, 16);
+ int err;
+
+ err = pca9532_destroy_devices(data, data->chip_info->num_leds);
+ if (err)
+ return err;
+
kfree(data);
return 0;
}
diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h
index 2dd8ecbfdc31..e77c7f8dcdd4 100644
--- a/drivers/leds/leds.h
+++ b/drivers/leds/leds.h
@@ -40,10 +40,17 @@ void led_trigger_set_default(struct led_classdev *led_cdev);
void led_trigger_set(struct led_classdev *led_cdev,
struct led_trigger *trigger);
void led_trigger_remove(struct led_classdev *led_cdev);
+
+static inline void *led_get_trigger_data(struct led_classdev *led_cdev)
+{
+ return led_cdev->trigger_data;
+}
+
#else
#define led_trigger_set_default(x) do {} while (0)
#define led_trigger_set(x, y) do {} while (0)
#define led_trigger_remove(x) do {} while (0)
+#define led_get_trigger_data(x) (NULL)
#endif
ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr,
diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c
index b09bcbeade9c..d87c9d02f786 100644
--- a/drivers/leds/ledtrig-timer.c
+++ b/drivers/leds/ledtrig-timer.c
@@ -91,6 +91,9 @@ static void timer_trig_activate(struct led_classdev *led_cdev)
if (rc)
goto err_out_delayon;
+ led_blink_set(led_cdev, &led_cdev->blink_delay_on,
+ &led_cdev->blink_delay_off);
+
led_cdev->trigger_data = (void *)1;
return;
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
index bb8b722a9783..0ff92c208005 100644
--- a/drivers/macintosh/therm_pm72.c
+++ b/drivers/macintosh/therm_pm72.c
@@ -44,11 +44,11 @@
* TODO: - Check MPU structure version/signature
* - Add things like /sbin/overtemp for non-critical
* overtemp conditions so userland can take some policy
- * decisions, like slewing down CPUs
+ * decisions, like slowing down CPUs
* - Deal with fan and i2c failures in a better way
* - Maybe do a generic PID based on params used for
* U3 and Drives ? Definitely need to factor code a bit
- * bettter... also make sensor detection more robust using
+ * better... also make sensor detection more robust using
* the device-tree to probe for them
* - Figure out how to get the slots consumption and set the
* slots fan accordingly
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 8b021eb0d48c..6cccd60c594e 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -40,7 +40,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/device.h>
-#include <linux/sysdev.h>
+#include <linux/syscore_ops.h>
#include <linux/freezer.h>
#include <linux/syscalls.h>
#include <linux/suspend.h>
@@ -2527,12 +2527,9 @@ void pmu_blink(int n)
#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32)
int pmu_sys_suspended;
-static int pmu_sys_suspend(struct sys_device *sysdev, pm_message_t state)
+static int pmu_syscore_suspend(void)
{
- if (state.event != PM_EVENT_SUSPEND || pmu_sys_suspended)
- return 0;
-
- /* Suspend PMU event interrupts */\
+ /* Suspend PMU event interrupts */
pmu_suspend();
pmu_sys_suspended = 1;
@@ -2544,12 +2541,12 @@ static int pmu_sys_suspend(struct sys_device *sysdev, pm_message_t state)
return 0;
}
-static int pmu_sys_resume(struct sys_device *sysdev)
+static void pmu_syscore_resume(void)
{
struct adb_request req;
if (!pmu_sys_suspended)
- return 0;
+ return;
/* Tell PMU we are ready */
pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);
@@ -2562,50 +2559,21 @@ static int pmu_sys_resume(struct sys_device *sysdev)
/* Resume PMU event interrupts */
pmu_resume();
pmu_sys_suspended = 0;
-
- return 0;
}
-#endif /* CONFIG_SUSPEND && CONFIG_PPC32 */
-
-static struct sysdev_class pmu_sysclass = {
- .name = "pmu",
-};
-
-static struct sys_device device_pmu = {
- .cls = &pmu_sysclass,
-};
-
-static struct sysdev_driver driver_pmu = {
-#if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32)
- .suspend = &pmu_sys_suspend,
- .resume = &pmu_sys_resume,
-#endif /* CONFIG_SUSPEND && CONFIG_PPC32 */
+static struct syscore_ops pmu_syscore_ops = {
+ .suspend = pmu_syscore_suspend,
+ .resume = pmu_syscore_resume,
};
-static int __init init_pmu_sysfs(void)
+static int pmu_syscore_register(void)
{
- int rc;
+ register_syscore_ops(&pmu_syscore_ops);
- rc = sysdev_class_register(&pmu_sysclass);
- if (rc) {
- printk(KERN_ERR "Failed registering PMU sys class\n");
- return -ENODEV;
- }
- rc = sysdev_register(&device_pmu);
- if (rc) {
- printk(KERN_ERR "Failed registering PMU sys device\n");
- return -ENODEV;
- }
- rc = sysdev_driver_register(&pmu_sysclass, &driver_pmu);
- if (rc) {
- printk(KERN_ERR "Failed registering PMU sys driver\n");
- return -ENODEV;
- }
return 0;
}
-
-subsys_initcall(init_pmu_sysfs);
+subsys_initcall(pmu_syscore_register);
+#endif /* CONFIG_SUSPEND && CONFIG_PPC32 */
EXPORT_SYMBOL(pmu_request);
EXPORT_SYMBOL(pmu_queue_request);
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 5c9362792f1d..70bd738b8b99 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -493,11 +493,11 @@ void bitmap_update_sb(struct bitmap *bitmap)
spin_unlock_irqrestore(&bitmap->lock, flags);
sb = kmap_atomic(bitmap->sb_page, KM_USER0);
sb->events = cpu_to_le64(bitmap->mddev->events);
- if (bitmap->mddev->events < bitmap->events_cleared) {
+ if (bitmap->mddev->events < bitmap->events_cleared)
/* rocking back to read-only */
bitmap->events_cleared = bitmap->mddev->events;
- sb->events_cleared = cpu_to_le64(bitmap->events_cleared);
- }
+ sb->events_cleared = cpu_to_le64(bitmap->events_cleared);
+ sb->state = cpu_to_le32(bitmap->flags);
/* Just in case these have been changed via sysfs: */
sb->daemon_sleep = cpu_to_le32(bitmap->mddev->bitmap_info.daemon_sleep/HZ);
sb->write_behind = cpu_to_le32(bitmap->mddev->bitmap_info.max_write_behind);
@@ -618,7 +618,7 @@ success:
if (le32_to_cpu(sb->version) == BITMAP_MAJOR_HOSTENDIAN)
bitmap->flags |= BITMAP_HOSTENDIAN;
bitmap->events_cleared = le64_to_cpu(sb->events_cleared);
- if (sb->state & cpu_to_le32(BITMAP_STALE))
+ if (bitmap->flags & BITMAP_STALE)
bitmap->events_cleared = bitmap->mddev->events;
err = 0;
out:
@@ -652,9 +652,11 @@ static int bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits,
switch (op) {
case MASK_SET:
sb->state |= cpu_to_le32(bits);
+ bitmap->flags |= bits;
break;
case MASK_UNSET:
sb->state &= cpu_to_le32(~bits);
+ bitmap->flags &= ~bits;
break;
default:
BUG();
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 7d6f7f18a920..aa640a85bb21 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -3324,7 +3324,7 @@ resync_start_store(mddev_t *mddev, const char *buf, size_t len)
char *e;
unsigned long long n = simple_strtoull(buf, &e, 10);
- if (mddev->pers)
+ if (mddev->pers && !test_bit(MD_RECOVERY_FROZEN, &mddev->recovery))
return -EBUSY;
if (cmd_match(buf, "none"))
n = MaxSector;
@@ -4347,13 +4347,19 @@ static int md_alloc(dev_t dev, char *name)
disk->fops = &md_fops;
disk->private_data = mddev;
disk->queue = mddev->queue;
+ blk_queue_flush(mddev->queue, REQ_FLUSH | REQ_FUA);
/* Allow extended partitions. This makes the
* 'mdp' device redundant, but we can't really
* remove it now.
*/
disk->flags |= GENHD_FL_EXT_DEVT;
- add_disk(disk);
mddev->gendisk = disk;
+ /* As soon as we call add_disk(), another thread could get
+ * through to md_open, so make sure it doesn't get too far
+ */
+ mutex_lock(&mddev->open_mutex);
+ add_disk(disk);
+
error = kobject_init_and_add(&mddev->kobj, &md_ktype,
&disk_to_dev(disk)->kobj, "%s", "md");
if (error) {
@@ -4367,8 +4373,7 @@ static int md_alloc(dev_t dev, char *name)
if (mddev->kobj.sd &&
sysfs_create_group(&mddev->kobj, &md_bitmap_group))
printk(KERN_DEBUG "pointless warning\n");
-
- blk_queue_flush(mddev->queue, REQ_FLUSH | REQ_FUA);
+ mutex_unlock(&mddev->open_mutex);
abort:
mutex_unlock(&disks_mutex);
if (!error && mddev->kobj.sd) {
@@ -5211,6 +5216,16 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
} else
super_types[mddev->major_version].
validate_super(mddev, rdev);
+ if ((info->state & (1<<MD_DISK_SYNC)) &&
+ (!test_bit(In_sync, &rdev->flags) ||
+ rdev->raid_disk != info->raid_disk)) {
+ /* This was a hot-add request, but events doesn't
+ * match, so reject it.
+ */
+ export_rdev(rdev);
+ return -EINVAL;
+ }
+
if (test_bit(In_sync, &rdev->flags))
rdev->saved_raid_disk = rdev->raid_disk;
else
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index c35890990985..3535c23af288 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -146,7 +146,7 @@ static void multipath_status (struct seq_file *seq, mddev_t *mddev)
int i;
seq_printf (seq, " [%d/%d] [", conf->raid_disks,
- conf->working_disks);
+ conf->raid_disks - mddev->degraded);
for (i = 0; i < conf->raid_disks; i++)
seq_printf (seq, "%s",
conf->multipaths[i].rdev &&
@@ -186,35 +186,36 @@ static int multipath_congested(void *data, int bits)
static void multipath_error (mddev_t *mddev, mdk_rdev_t *rdev)
{
multipath_conf_t *conf = mddev->private;
+ char b[BDEVNAME_SIZE];
- if (conf->working_disks <= 1) {
+ if (conf->raid_disks - mddev->degraded <= 1) {
/*
* Uh oh, we can do nothing if this is our last path, but
* first check if this is a queued request for a device
* which has just failed.
*/
printk(KERN_ALERT
- "multipath: only one IO path left and IO error.\n");
+ "multipath: only one IO path left and IO error.\n");
/* leave it active... it's all we have */
- } else {
- /*
- * Mark disk as unusable
- */
- if (!test_bit(Faulty, &rdev->flags)) {
- char b[BDEVNAME_SIZE];
- clear_bit(In_sync, &rdev->flags);
- set_bit(Faulty, &rdev->flags);
- set_bit(MD_CHANGE_DEVS, &mddev->flags);
- conf->working_disks--;
- mddev->degraded++;
- printk(KERN_ALERT "multipath: IO failure on %s,"
- " disabling IO path.\n"
- "multipath: Operation continuing"
- " on %d IO paths.\n",
- bdevname (rdev->bdev,b),
- conf->working_disks);
- }
+ return;
+ }
+ /*
+ * Mark disk as unusable
+ */
+ if (test_and_clear_bit(In_sync, &rdev->flags)) {
+ unsigned long flags;
+ spin_lock_irqsave(&conf->device_lock, flags);
+ mddev->degraded++;
+ spin_unlock_irqrestore(&conf->device_lock, flags);
}
+ set_bit(Faulty, &rdev->flags);
+ set_bit(MD_CHANGE_DEVS, &mddev->flags);
+ printk(KERN_ALERT "multipath: IO failure on %s,"
+ " disabling IO path.\n"
+ "multipath: Operation continuing"
+ " on %d IO paths.\n",
+ bdevname(rdev->bdev, b),
+ conf->raid_disks - mddev->degraded);
}
static void print_multipath_conf (multipath_conf_t *conf)
@@ -227,7 +228,7 @@ static void print_multipath_conf (multipath_conf_t *conf)
printk("(conf==NULL)\n");
return;
}
- printk(" --- wd:%d rd:%d\n", conf->working_disks,
+ printk(" --- wd:%d rd:%d\n", conf->raid_disks - conf->mddev->degraded,
conf->raid_disks);
for (i = 0; i < conf->raid_disks; i++) {
@@ -274,10 +275,11 @@ static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
PAGE_CACHE_SIZE - 1);
}
- conf->working_disks++;
+ spin_lock_irq(&conf->device_lock);
mddev->degraded--;
rdev->raid_disk = path;
set_bit(In_sync, &rdev->flags);
+ spin_unlock_irq(&conf->device_lock);
rcu_assign_pointer(p->rdev, rdev);
err = 0;
md_integrity_add_rdev(rdev, mddev);
@@ -391,6 +393,7 @@ static int multipath_run (mddev_t *mddev)
int disk_idx;
struct multipath_info *disk;
mdk_rdev_t *rdev;
+ int working_disks;
if (md_check_no_bitmap(mddev))
return -EINVAL;
@@ -424,7 +427,7 @@ static int multipath_run (mddev_t *mddev)
goto out_free_conf;
}
- conf->working_disks = 0;
+ working_disks = 0;
list_for_each_entry(rdev, &mddev->disks, same_set) {
disk_idx = rdev->raid_disk;
if (disk_idx < 0 ||
@@ -446,7 +449,7 @@ static int multipath_run (mddev_t *mddev)
}
if (!test_bit(Faulty, &rdev->flags))
- conf->working_disks++;
+ working_disks++;
}
conf->raid_disks = mddev->raid_disks;
@@ -454,12 +457,12 @@ static int multipath_run (mddev_t *mddev)
spin_lock_init(&conf->device_lock);
INIT_LIST_HEAD(&conf->retry_list);
- if (!conf->working_disks) {
+ if (!working_disks) {
printk(KERN_ERR "multipath: no operational IO paths for %s\n",
mdname(mddev));
goto out_free_conf;
}
- mddev->degraded = conf->raid_disks - conf->working_disks;
+ mddev->degraded = conf->raid_disks - working_disks;
conf->pool = mempool_create_kmalloc_pool(NR_RESERVED_BUFS,
sizeof(struct multipath_bh));
@@ -481,7 +484,8 @@ static int multipath_run (mddev_t *mddev)
printk(KERN_INFO
"multipath: array %s active with %d out of %d IO paths\n",
- mdname(mddev), conf->working_disks, mddev->raid_disks);
+ mdname(mddev), conf->raid_disks - mddev->degraded,
+ mddev->raid_disks);
/*
* Ok, everything is just fine now
*/
diff --git a/drivers/md/multipath.h b/drivers/md/multipath.h
index d1c2a8d78395..3c5a45eb5f8a 100644
--- a/drivers/md/multipath.h
+++ b/drivers/md/multipath.h
@@ -9,7 +9,6 @@ struct multipath_private_data {
mddev_t *mddev;
struct multipath_info *multipaths;
int raid_disks;
- int working_disks;
spinlock_t device_lock;
struct list_head retry_list;
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 2b7a7ff401dc..5d096096f958 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -297,23 +297,24 @@ static void raid1_end_read_request(struct bio *bio, int error)
rdev_dec_pending(conf->mirrors[mirror].rdev, conf->mddev);
}
-static void r1_bio_write_done(r1bio_t *r1_bio, int vcnt, struct bio_vec *bv,
- int behind)
+static void r1_bio_write_done(r1bio_t *r1_bio)
{
if (atomic_dec_and_test(&r1_bio->remaining))
{
/* it really is the end of this request */
if (test_bit(R1BIO_BehindIO, &r1_bio->state)) {
/* free extra copy of the data pages */
- int i = vcnt;
+ int i = r1_bio->behind_page_count;
while (i--)
- safe_put_page(bv[i].bv_page);
+ safe_put_page(r1_bio->behind_pages[i]);
+ kfree(r1_bio->behind_pages);
+ r1_bio->behind_pages = NULL;
}
/* clear the bitmap if all writes complete successfully */
bitmap_endwrite(r1_bio->mddev->bitmap, r1_bio->sector,
r1_bio->sectors,
!test_bit(R1BIO_Degraded, &r1_bio->state),
- behind);
+ test_bit(R1BIO_BehindIO, &r1_bio->state));
md_write_end(r1_bio->mddev);
raid_end_bio_io(r1_bio);
}
@@ -386,7 +387,7 @@ static void raid1_end_write_request(struct bio *bio, int error)
* Let's see if all mirrored write operations have finished
* already.
*/
- r1_bio_write_done(r1_bio, bio->bi_vcnt, bio->bi_io_vec, behind);
+ r1_bio_write_done(r1_bio);
if (to_put)
bio_put(to_put);
@@ -411,10 +412,10 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio)
{
const sector_t this_sector = r1_bio->sector;
const int sectors = r1_bio->sectors;
- int new_disk = -1;
int start_disk;
+ int best_disk;
int i;
- sector_t new_distance, current_distance;
+ sector_t best_dist;
mdk_rdev_t *rdev;
int choose_first;
@@ -425,6 +426,8 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio)
* We take the first readable disk when above the resync window.
*/
retry:
+ best_disk = -1;
+ best_dist = MaxSector;
if (conf->mddev->recovery_cp < MaxSector &&
(this_sector + sectors >= conf->next_resync)) {
choose_first = 1;
@@ -434,8 +437,8 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio)
start_disk = conf->last_used;
}
- /* make sure the disk is operational */
for (i = 0 ; i < conf->raid_disks ; i++) {
+ sector_t dist;
int disk = start_disk + i;
if (disk >= conf->raid_disks)
disk -= conf->raid_disks;
@@ -443,60 +446,43 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio)
rdev = rcu_dereference(conf->mirrors[disk].rdev);
if (r1_bio->bios[disk] == IO_BLOCKED
|| rdev == NULL
- || !test_bit(In_sync, &rdev->flags))
+ || test_bit(Faulty, &rdev->flags))
continue;
-
- new_disk = disk;
- if (!test_bit(WriteMostly, &rdev->flags))
- break;
- }
-
- if (new_disk < 0 || choose_first)
- goto rb_out;
-
- /*
- * Don't change to another disk for sequential reads:
- */
- if (conf->next_seq_sect == this_sector)
- goto rb_out;
- if (this_sector == conf->mirrors[new_disk].head_position)
- goto rb_out;
-
- current_distance = abs(this_sector
- - conf->mirrors[new_disk].head_position);
-
- /* look for a better disk - i.e. head is closer */
- start_disk = new_disk;
- for (i = 1; i < conf->raid_disks; i++) {
- int disk = start_disk + 1;
- if (disk >= conf->raid_disks)
- disk -= conf->raid_disks;
-
- rdev = rcu_dereference(conf->mirrors[disk].rdev);
- if (r1_bio->bios[disk] == IO_BLOCKED
- || rdev == NULL
- || !test_bit(In_sync, &rdev->flags)
- || test_bit(WriteMostly, &rdev->flags))
+ if (!test_bit(In_sync, &rdev->flags) &&
+ rdev->recovery_offset < this_sector + sectors)
continue;
-
- if (!atomic_read(&rdev->nr_pending)) {
- new_disk = disk;
+ if (test_bit(WriteMostly, &rdev->flags)) {
+ /* Don't balance among write-mostly, just
+ * use the first as a last resort */
+ if (best_disk < 0)
+ best_disk = disk;
+ continue;
+ }
+ /* This is a reasonable device to use. It might
+ * even be best.
+ */
+ dist = abs(this_sector - conf->mirrors[disk].head_position);
+ if (choose_first
+ /* Don't change to another disk for sequential reads */
+ || conf->next_seq_sect == this_sector
+ || dist == 0
+ /* If device is idle, use it */
+ || atomic_read(&rdev->nr_pending) == 0) {
+ best_disk = disk;
break;
}
- new_distance = abs(this_sector - conf->mirrors[disk].head_position);
- if (new_distance < current_distance) {
- current_distance = new_distance;
- new_disk = disk;
+ if (dist < best_dist) {
+ best_dist = dist;
+ best_disk = disk;
}
}
- rb_out:
- if (new_disk >= 0) {
- rdev = rcu_dereference(conf->mirrors[new_disk].rdev);
+ if (best_disk >= 0) {
+ rdev = rcu_dereference(conf->mirrors[best_disk].rdev);
if (!rdev)
goto retry;
atomic_inc(&rdev->nr_pending);
- if (!test_bit(In_sync, &rdev->flags)) {
+ if (test_bit(Faulty, &rdev->flags)) {
/* cannot risk returning a device that failed
* before we inc'ed nr_pending
*/
@@ -504,11 +490,11 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio)
goto retry;
}
conf->next_seq_sect = this_sector + sectors;
- conf->last_used = new_disk;
+ conf->last_used = best_disk;
}
rcu_read_unlock();
- return new_disk;
+ return best_disk;
}
static int raid1_congested(void *data, int bits)
@@ -675,37 +661,36 @@ static void unfreeze_array(conf_t *conf)
/* duplicate the data pages for behind I/O
- * We return a list of bio_vec rather than just page pointers
- * as it makes freeing easier
*/
-static struct bio_vec *alloc_behind_pages(struct bio *bio)
+static void alloc_behind_pages(struct bio *bio, r1bio_t *r1_bio)
{
int i;
struct bio_vec *bvec;
- struct bio_vec *pages = kzalloc(bio->bi_vcnt * sizeof(struct bio_vec),
+ struct page **pages = kzalloc(bio->bi_vcnt * sizeof(struct page*),
GFP_NOIO);
if (unlikely(!pages))
- goto do_sync_io;
+ return;
bio_for_each_segment(bvec, bio, i) {
- pages[i].bv_page = alloc_page(GFP_NOIO);
- if (unlikely(!pages[i].bv_page))
+ pages[i] = alloc_page(GFP_NOIO);
+ if (unlikely(!pages[i]))
goto do_sync_io;
- memcpy(kmap(pages[i].bv_page) + bvec->bv_offset,
+ memcpy(kmap(pages[i]) + bvec->bv_offset,
kmap(bvec->bv_page) + bvec->bv_offset, bvec->bv_len);
- kunmap(pages[i].bv_page);
+ kunmap(pages[i]);
kunmap(bvec->bv_page);
}
-
- return pages;
+ r1_bio->behind_pages = pages;
+ r1_bio->behind_page_count = bio->bi_vcnt;
+ set_bit(R1BIO_BehindIO, &r1_bio->state);
+ return;
do_sync_io:
- if (pages)
- for (i = 0; i < bio->bi_vcnt && pages[i].bv_page; i++)
- put_page(pages[i].bv_page);
+ for (i = 0; i < bio->bi_vcnt; i++)
+ if (pages[i])
+ put_page(pages[i]);
kfree(pages);
PRINTK("%dB behind alloc failed, doing sync I/O\n", bio->bi_size);
- return NULL;
}
static int make_request(mddev_t *mddev, struct bio * bio)
@@ -717,7 +702,6 @@ static int make_request(mddev_t *mddev, struct bio * bio)
int i, targets = 0, disks;
struct bitmap *bitmap;
unsigned long flags;
- struct bio_vec *behind_pages = NULL;
const int rw = bio_data_dir(bio);
const unsigned long do_sync = (bio->bi_rw & REQ_SYNC);
const unsigned long do_flush_fua = (bio->bi_rw & (REQ_FLUSH | REQ_FUA));
@@ -870,9 +854,8 @@ static int make_request(mddev_t *mddev, struct bio * bio)
if (bitmap &&
(atomic_read(&bitmap->behind_writes)
< mddev->bitmap_info.max_write_behind) &&
- !waitqueue_active(&bitmap->behind_wait) &&
- (behind_pages = alloc_behind_pages(bio)) != NULL)
- set_bit(R1BIO_BehindIO, &r1_bio->state);
+ !waitqueue_active(&bitmap->behind_wait))
+ alloc_behind_pages(bio, r1_bio);
atomic_set(&r1_bio->remaining, 1);
atomic_set(&r1_bio->behind_remaining, 0);
@@ -893,7 +876,7 @@ static int make_request(mddev_t *mddev, struct bio * bio)
mbio->bi_rw = WRITE | do_flush_fua | do_sync;
mbio->bi_private = r1_bio;
- if (behind_pages) {
+ if (r1_bio->behind_pages) {
struct bio_vec *bvec;
int j;
@@ -905,7 +888,7 @@ static int make_request(mddev_t *mddev, struct bio * bio)
* them all
*/
__bio_for_each_segment(bvec, mbio, j, 0)
- bvec->bv_page = behind_pages[j].bv_page;
+ bvec->bv_page = r1_bio->behind_pages[j];
if (test_bit(WriteMostly, &conf->mirrors[i].rdev->flags))
atomic_inc(&r1_bio->behind_remaining);
}
@@ -915,8 +898,7 @@ static int make_request(mddev_t *mddev, struct bio * bio)
bio_list_add(&conf->pending_bio_list, mbio);
spin_unlock_irqrestore(&conf->device_lock, flags);
}
- r1_bio_write_done(r1_bio, bio->bi_vcnt, behind_pages, behind_pages != NULL);
- kfree(behind_pages); /* the behind pages are attached to the bios now */
+ r1_bio_write_done(r1_bio);
/* In case raid1d snuck in to freeze_array */
wake_up(&conf->wait_barrier);
@@ -1196,194 +1178,210 @@ static void end_sync_write(struct bio *bio, int error)
}
}
-static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
+static int fix_sync_read_error(r1bio_t *r1_bio)
{
+ /* Try some synchronous reads of other devices to get
+ * good data, much like with normal read errors. Only
+ * read into the pages we already have so we don't
+ * need to re-issue the read request.
+ * We don't need to freeze the array, because being in an
+ * active sync request, there is no normal IO, and
+ * no overlapping syncs.
+ */
+ mddev_t *mddev = r1_bio->mddev;
conf_t *conf = mddev->private;
- int i;
- int disks = conf->raid_disks;
- struct bio *bio, *wbio;
-
- bio = r1_bio->bios[r1_bio->read_disk];
+ struct bio *bio = r1_bio->bios[r1_bio->read_disk];
+ sector_t sect = r1_bio->sector;
+ int sectors = r1_bio->sectors;
+ int idx = 0;
+ while(sectors) {
+ int s = sectors;
+ int d = r1_bio->read_disk;
+ int success = 0;
+ mdk_rdev_t *rdev;
+ int start;
- if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
- /* We have read all readable devices. If we haven't
- * got the block, then there is no hope left.
- * If we have, then we want to do a comparison
- * and skip the write if everything is the same.
- * If any blocks failed to read, then we need to
- * attempt an over-write
- */
- int primary;
- if (!test_bit(R1BIO_Uptodate, &r1_bio->state)) {
- for (i=0; i<mddev->raid_disks; i++)
- if (r1_bio->bios[i]->bi_end_io == end_sync_read)
- md_error(mddev, conf->mirrors[i].rdev);
+ if (s > (PAGE_SIZE>>9))
+ s = PAGE_SIZE >> 9;
+ do {
+ if (r1_bio->bios[d]->bi_end_io == end_sync_read) {
+ /* No rcu protection needed here devices
+ * can only be removed when no resync is
+ * active, and resync is currently active
+ */
+ rdev = conf->mirrors[d].rdev;
+ if (sync_page_io(rdev,
+ sect,
+ s<<9,
+ bio->bi_io_vec[idx].bv_page,
+ READ, false)) {
+ success = 1;
+ break;
+ }
+ }
+ d++;
+ if (d == conf->raid_disks)
+ d = 0;
+ } while (!success && d != r1_bio->read_disk);
- md_done_sync(mddev, r1_bio->sectors, 1);
+ if (!success) {
+ char b[BDEVNAME_SIZE];
+ /* Cannot read from anywhere, array is toast */
+ md_error(mddev, conf->mirrors[r1_bio->read_disk].rdev);
+ printk(KERN_ALERT "md/raid1:%s: %s: unrecoverable I/O read error"
+ " for block %llu\n",
+ mdname(mddev),
+ bdevname(bio->bi_bdev, b),
+ (unsigned long long)r1_bio->sector);
+ md_done_sync(mddev, r1_bio->sectors, 0);
put_buf(r1_bio);
- return;
+ return 0;
}
- for (primary=0; primary<mddev->raid_disks; primary++)
- if (r1_bio->bios[primary]->bi_end_io == end_sync_read &&
- test_bit(BIO_UPTODATE, &r1_bio->bios[primary]->bi_flags)) {
- r1_bio->bios[primary]->bi_end_io = NULL;
- rdev_dec_pending(conf->mirrors[primary].rdev, mddev);
- break;
- }
- r1_bio->read_disk = primary;
- for (i=0; i<mddev->raid_disks; i++)
- if (r1_bio->bios[i]->bi_end_io == end_sync_read) {
- int j;
- int vcnt = r1_bio->sectors >> (PAGE_SHIFT- 9);
- struct bio *pbio = r1_bio->bios[primary];
- struct bio *sbio = r1_bio->bios[i];
-
- if (test_bit(BIO_UPTODATE, &sbio->bi_flags)) {
- for (j = vcnt; j-- ; ) {
- struct page *p, *s;
- p = pbio->bi_io_vec[j].bv_page;
- s = sbio->bi_io_vec[j].bv_page;
- if (memcmp(page_address(p),
- page_address(s),
- PAGE_SIZE))
- break;
- }
- } else
- j = 0;
- if (j >= 0)
- mddev->resync_mismatches += r1_bio->sectors;
- if (j < 0 || (test_bit(MD_RECOVERY_CHECK, &mddev->recovery)
- && test_bit(BIO_UPTODATE, &sbio->bi_flags))) {
- sbio->bi_end_io = NULL;
- rdev_dec_pending(conf->mirrors[i].rdev, mddev);
- } else {
- /* fixup the bio for reuse */
- int size;
- sbio->bi_vcnt = vcnt;
- sbio->bi_size = r1_bio->sectors << 9;
- sbio->bi_idx = 0;
- sbio->bi_phys_segments = 0;
- sbio->bi_flags &= ~(BIO_POOL_MASK - 1);
- sbio->bi_flags |= 1 << BIO_UPTODATE;
- sbio->bi_next = NULL;
- sbio->bi_sector = r1_bio->sector +
- conf->mirrors[i].rdev->data_offset;
- sbio->bi_bdev = conf->mirrors[i].rdev->bdev;
- size = sbio->bi_size;
- for (j = 0; j < vcnt ; j++) {
- struct bio_vec *bi;
- bi = &sbio->bi_io_vec[j];
- bi->bv_offset = 0;
- if (size > PAGE_SIZE)
- bi->bv_len = PAGE_SIZE;
- else
- bi->bv_len = size;
- size -= PAGE_SIZE;
- memcpy(page_address(bi->bv_page),
- page_address(pbio->bi_io_vec[j].bv_page),
- PAGE_SIZE);
- }
- }
- }
+ start = d;
+ /* write it back and re-read */
+ while (d != r1_bio->read_disk) {
+ if (d == 0)
+ d = conf->raid_disks;
+ d--;
+ if (r1_bio->bios[d]->bi_end_io != end_sync_read)
+ continue;
+ rdev = conf->mirrors[d].rdev;
+ if (sync_page_io(rdev,
+ sect,
+ s<<9,
+ bio->bi_io_vec[idx].bv_page,
+ WRITE, false) == 0) {
+ r1_bio->bios[d]->bi_end_io = NULL;
+ rdev_dec_pending(rdev, mddev);
+ md_error(mddev, rdev);
+ } else
+ atomic_add(s, &rdev->corrected_errors);
+ }
+ d = start;
+ while (d != r1_bio->read_disk) {
+ if (d == 0)
+ d = conf->raid_disks;
+ d--;
+ if (r1_bio->bios[d]->bi_end_io != end_sync_read)
+ continue;
+ rdev = conf->mirrors[d].rdev;
+ if (sync_page_io(rdev,
+ sect,
+ s<<9,
+ bio->bi_io_vec[idx].bv_page,
+ READ, false) == 0)
+ md_error(mddev, rdev);
+ }
+ sectors -= s;
+ sect += s;
+ idx ++;
}
- if (!test_bit(R1BIO_Uptodate, &r1_bio->state)) {
- /* ouch - failed to read all of that.
- * Try some synchronous reads of other devices to get
- * good data, much like with normal read errors. Only
- * read into the pages we already have so we don't
- * need to re-issue the read request.
- * We don't need to freeze the array, because being in an
- * active sync request, there is no normal IO, and
- * no overlapping syncs.
- */
- sector_t sect = r1_bio->sector;
- int sectors = r1_bio->sectors;
- int idx = 0;
-
- while(sectors) {
- int s = sectors;
- int d = r1_bio->read_disk;
- int success = 0;
- mdk_rdev_t *rdev;
-
- if (s > (PAGE_SIZE>>9))
- s = PAGE_SIZE >> 9;
- do {
- if (r1_bio->bios[d]->bi_end_io == end_sync_read) {
- /* No rcu protection needed here devices
- * can only be removed when no resync is
- * active, and resync is currently active
- */
- rdev = conf->mirrors[d].rdev;
- if (sync_page_io(rdev,
- sect,
- s<<9,
- bio->bi_io_vec[idx].bv_page,
- READ, false)) {
- success = 1;
- break;
- }
- }
- d++;
- if (d == conf->raid_disks)
- d = 0;
- } while (!success && d != r1_bio->read_disk);
-
- if (success) {
- int start = d;
- /* write it back and re-read */
- set_bit(R1BIO_Uptodate, &r1_bio->state);
- while (d != r1_bio->read_disk) {
- if (d == 0)
- d = conf->raid_disks;
- d--;
- if (r1_bio->bios[d]->bi_end_io != end_sync_read)
- continue;
- rdev = conf->mirrors[d].rdev;
- atomic_add(s, &rdev->corrected_errors);
- if (sync_page_io(rdev,
- sect,
- s<<9,
- bio->bi_io_vec[idx].bv_page,
- WRITE, false) == 0)
- md_error(mddev, rdev);
- }
- d = start;
- while (d != r1_bio->read_disk) {
- if (d == 0)
- d = conf->raid_disks;
- d--;
- if (r1_bio->bios[d]->bi_end_io != end_sync_read)
- continue;
- rdev = conf->mirrors[d].rdev;
- if (sync_page_io(rdev,
- sect,
- s<<9,
- bio->bi_io_vec[idx].bv_page,
- READ, false) == 0)
- md_error(mddev, rdev);
- }
- } else {
- char b[BDEVNAME_SIZE];
- /* Cannot read from anywhere, array is toast */
- md_error(mddev, conf->mirrors[r1_bio->read_disk].rdev);
- printk(KERN_ALERT "md/raid1:%s: %s: unrecoverable I/O read error"
- " for block %llu\n",
- mdname(mddev),
- bdevname(bio->bi_bdev, b),
- (unsigned long long)r1_bio->sector);
- md_done_sync(mddev, r1_bio->sectors, 0);
- put_buf(r1_bio);
- return;
+ set_bit(R1BIO_Uptodate, &r1_bio->state);
+ set_bit(BIO_UPTODATE, &bio->bi_flags);
+ return 1;
+}
+
+static int process_checks(r1bio_t *r1_bio)
+{
+ /* We have read all readable devices. If we haven't
+ * got the block, then there is no hope left.
+ * If we have, then we want to do a comparison
+ * and skip the write if everything is the same.
+ * If any blocks failed to read, then we need to
+ * attempt an over-write
+ */
+ mddev_t *mddev = r1_bio->mddev;
+ conf_t *conf = mddev->private;
+ int primary;
+ int i;
+
+ for (primary = 0; primary < conf->raid_disks; primary++)
+ if (r1_bio->bios[primary]->bi_end_io == end_sync_read &&
+ test_bit(BIO_UPTODATE, &r1_bio->bios[primary]->bi_flags)) {
+ r1_bio->bios[primary]->bi_end_io = NULL;
+ rdev_dec_pending(conf->mirrors[primary].rdev, mddev);
+ break;
+ }
+ r1_bio->read_disk = primary;
+ for (i = 0; i < conf->raid_disks; i++) {
+ int j;
+ int vcnt = r1_bio->sectors >> (PAGE_SHIFT- 9);
+ struct bio *pbio = r1_bio->bios[primary];
+ struct bio *sbio = r1_bio->bios[i];
+ int size;
+
+ if (r1_bio->bios[i]->bi_end_io != end_sync_read)
+ continue;
+
+ if (test_bit(BIO_UPTODATE, &sbio->bi_flags)) {
+ for (j = vcnt; j-- ; ) {
+ struct page *p, *s;
+ p = pbio->bi_io_vec[j].bv_page;
+ s = sbio->bi_io_vec[j].bv_page;
+ if (memcmp(page_address(p),
+ page_address(s),
+ PAGE_SIZE))
+ break;
}
- sectors -= s;
- sect += s;
- idx ++;
+ } else
+ j = 0;
+ if (j >= 0)
+ mddev->resync_mismatches += r1_bio->sectors;
+ if (j < 0 || (test_bit(MD_RECOVERY_CHECK, &mddev->recovery)
+ && test_bit(BIO_UPTODATE, &sbio->bi_flags))) {
+ /* No need to write to this device. */
+ sbio->bi_end_io = NULL;
+ rdev_dec_pending(conf->mirrors[i].rdev, mddev);
+ continue;
+ }
+ /* fixup the bio for reuse */
+ sbio->bi_vcnt = vcnt;
+ sbio->bi_size = r1_bio->sectors << 9;
+ sbio->bi_idx = 0;
+ sbio->bi_phys_segments = 0;
+ sbio->bi_flags &= ~(BIO_POOL_MASK - 1);
+ sbio->bi_flags |= 1 << BIO_UPTODATE;
+ sbio->bi_next = NULL;
+ sbio->bi_sector = r1_bio->sector +
+ conf->mirrors[i].rdev->data_offset;
+ sbio->bi_bdev = conf->mirrors[i].rdev->bdev;
+ size = sbio->bi_size;
+ for (j = 0; j < vcnt ; j++) {
+ struct bio_vec *bi;
+ bi = &sbio->bi_io_vec[j];
+ bi->bv_offset = 0;
+ if (size > PAGE_SIZE)
+ bi->bv_len = PAGE_SIZE;
+ else
+ bi->bv_len = size;
+ size -= PAGE_SIZE;
+ memcpy(page_address(bi->bv_page),
+ page_address(pbio->bi_io_vec[j].bv_page),
+ PAGE_SIZE);
}
}
+ return 0;
+}
+static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
+{
+ conf_t *conf = mddev->private;
+ int i;
+ int disks = conf->raid_disks;
+ struct bio *bio, *wbio;
+
+ bio = r1_bio->bios[r1_bio->read_disk];
+
+ if (!test_bit(R1BIO_Uptodate, &r1_bio->state))
+ /* ouch - failed to read all of that. */
+ if (!fix_sync_read_error(r1_bio))
+ return;
+
+ if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
+ if (process_checks(r1_bio) < 0)
+ return;
/*
* schedule writes
*/
@@ -2063,7 +2061,7 @@ static int raid1_resize(mddev_t *mddev, sector_t sectors)
set_capacity(mddev->gendisk, mddev->array_sectors);
revalidate_disk(mddev->gendisk);
if (sectors > mddev->dev_sectors &&
- mddev->recovery_cp == MaxSector) {
+ mddev->recovery_cp > mddev->dev_sectors) {
mddev->recovery_cp = mddev->dev_sectors;
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
}
diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h
index cbfdf1a6acd9..5fc4ca1af863 100644
--- a/drivers/md/raid1.h
+++ b/drivers/md/raid1.h
@@ -94,7 +94,9 @@ struct r1bio_s {
int read_disk;
struct list_head retry_list;
- struct bitmap_update *bitmap_update;
+ /* Next two are only valid when R1BIO_BehindIO is set */
+ struct page **behind_pages;
+ int behind_page_count;
/*
* if the IO is in WRITE direction, then multiple bios are used.
* We choose the number when they are allocated.
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 8e9462626ec5..6e846688962f 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -271,9 +271,10 @@ static void raid10_end_read_request(struct bio *bio, int error)
*/
set_bit(R10BIO_Uptodate, &r10_bio->state);
raid_end_bio_io(r10_bio);
+ rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev);
} else {
/*
- * oops, read error:
+ * oops, read error - keep the refcount on the rdev
*/
char b[BDEVNAME_SIZE];
if (printk_ratelimit())
@@ -282,8 +283,6 @@ static void raid10_end_read_request(struct bio *bio, int error)
bdevname(conf->mirrors[dev].rdev->bdev,b), (unsigned long long)r10_bio->sector);
reschedule_retry(r10_bio);
}
-
- rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev);
}
static void raid10_end_write_request(struct bio *bio, int error)
@@ -488,13 +487,19 @@ static int raid10_mergeable_bvec(struct request_queue *q,
static int read_balance(conf_t *conf, r10bio_t *r10_bio)
{
const sector_t this_sector = r10_bio->sector;
- int disk, slot, nslot;
+ int disk, slot;
const int sectors = r10_bio->sectors;
- sector_t new_distance, current_distance;
+ sector_t new_distance, best_dist;
mdk_rdev_t *rdev;
+ int do_balance;
+ int best_slot;
raid10_find_phys(conf, r10_bio);
rcu_read_lock();
+retry:
+ best_slot = -1;
+ best_dist = MaxSector;
+ do_balance = 1;
/*
* Check if we can balance. We can balance on the whole
* device if no resync is going on (recovery is ok), or below
@@ -502,86 +507,58 @@ static int read_balance(conf_t *conf, r10bio_t *r10_bio)
* above the resync window.
*/
if (conf->mddev->recovery_cp < MaxSector
- && (this_sector + sectors >= conf->next_resync)) {
- /* make sure that disk is operational */
- slot = 0;
- disk = r10_bio->devs[slot].devnum;
-
- while ((rdev = rcu_dereference(conf->mirrors[disk].rdev)) == NULL ||
- r10_bio->devs[slot].bio == IO_BLOCKED ||
- !test_bit(In_sync, &rdev->flags)) {
- slot++;
- if (slot == conf->copies) {
- slot = 0;
- disk = -1;
- break;
- }
- disk = r10_bio->devs[slot].devnum;
- }
- goto rb_out;
- }
-
+ && (this_sector + sectors >= conf->next_resync))
+ do_balance = 0;
- /* make sure the disk is operational */
- slot = 0;
- disk = r10_bio->devs[slot].devnum;
- while ((rdev=rcu_dereference(conf->mirrors[disk].rdev)) == NULL ||
- r10_bio->devs[slot].bio == IO_BLOCKED ||
- !test_bit(In_sync, &rdev->flags)) {
- slot ++;
- if (slot == conf->copies) {
- disk = -1;
- goto rb_out;
- }
+ for (slot = 0; slot < conf->copies ; slot++) {
+ if (r10_bio->devs[slot].bio == IO_BLOCKED)
+ continue;
disk = r10_bio->devs[slot].devnum;
- }
-
-
- current_distance = abs(r10_bio->devs[slot].addr -
- conf->mirrors[disk].head_position);
-
- /* Find the disk whose head is closest,
- * or - for far > 1 - find the closest to partition beginning */
-
- for (nslot = slot; nslot < conf->copies; nslot++) {
- int ndisk = r10_bio->devs[nslot].devnum;
-
-
- if ((rdev=rcu_dereference(conf->mirrors[ndisk].rdev)) == NULL ||
- r10_bio->devs[nslot].bio == IO_BLOCKED ||
- !test_bit(In_sync, &rdev->flags))
+ rdev = rcu_dereference(conf->mirrors[disk].rdev);
+ if (rdev == NULL)
continue;
+ if (!test_bit(In_sync, &rdev->flags))
+ continue;
+
+ if (!do_balance)
+ break;
/* This optimisation is debatable, and completely destroys
* sequential read speed for 'far copies' arrays. So only
* keep it for 'near' arrays, and review those later.
*/
- if (conf->near_copies > 1 && !atomic_read(&rdev->nr_pending)) {
- disk = ndisk;
- slot = nslot;
+ if (conf->near_copies > 1 && !atomic_read(&rdev->nr_pending))
break;
- }
/* for far > 1 always use the lowest address */
if (conf->far_copies > 1)
- new_distance = r10_bio->devs[nslot].addr;
+ new_distance = r10_bio->devs[slot].addr;
else
- new_distance = abs(r10_bio->devs[nslot].addr -
- conf->mirrors[ndisk].head_position);
- if (new_distance < current_distance) {
- current_distance = new_distance;
- disk = ndisk;
- slot = nslot;
+ new_distance = abs(r10_bio->devs[slot].addr -
+ conf->mirrors[disk].head_position);
+ if (new_distance < best_dist) {
+ best_dist = new_distance;
+ best_slot = slot;
}
}
+ if (slot == conf->copies)
+ slot = best_slot;
-rb_out:
- r10_bio->read_slot = slot;
-/* conf->next_seq_sect = this_sector + sectors;*/
-
- if (disk >= 0 && (rdev=rcu_dereference(conf->mirrors[disk].rdev))!= NULL)
- atomic_inc(&conf->mirrors[disk].rdev->nr_pending);
- else
+ if (slot >= 0) {
+ disk = r10_bio->devs[slot].devnum;
+ rdev = rcu_dereference(conf->mirrors[disk].rdev);
+ if (!rdev)
+ goto retry;
+ atomic_inc(&rdev->nr_pending);
+ if (test_bit(Faulty, &rdev->flags)) {
+ /* Cannot risk returning a device that failed
+ * before we inc'ed nr_pending
+ */
+ rdev_dec_pending(rdev, conf->mddev);
+ goto retry;
+ }
+ r10_bio->read_slot = slot;
+ } else
disk = -1;
rcu_read_unlock();
@@ -1460,40 +1437,33 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
int max_read_errors = atomic_read(&mddev->max_corr_read_errors);
int d = r10_bio->devs[r10_bio->read_slot].devnum;
- rcu_read_lock();
- rdev = rcu_dereference(conf->mirrors[d].rdev);
- if (rdev) { /* If rdev is not NULL */
- char b[BDEVNAME_SIZE];
- int cur_read_error_count = 0;
+ /* still own a reference to this rdev, so it cannot
+ * have been cleared recently.
+ */
+ rdev = conf->mirrors[d].rdev;
- bdevname(rdev->bdev, b);
+ if (test_bit(Faulty, &rdev->flags))
+ /* drive has already been failed, just ignore any
+ more fix_read_error() attempts */
+ return;
- if (test_bit(Faulty, &rdev->flags)) {
- rcu_read_unlock();
- /* drive has already been failed, just ignore any
- more fix_read_error() attempts */
- return;
- }
+ check_decay_read_errors(mddev, rdev);
+ atomic_inc(&rdev->read_errors);
+ if (atomic_read(&rdev->read_errors) > max_read_errors) {
+ char b[BDEVNAME_SIZE];
+ bdevname(rdev->bdev, b);
- check_decay_read_errors(mddev, rdev);
- atomic_inc(&rdev->read_errors);
- cur_read_error_count = atomic_read(&rdev->read_errors);
- if (cur_read_error_count > max_read_errors) {
- rcu_read_unlock();
- printk(KERN_NOTICE
- "md/raid10:%s: %s: Raid device exceeded "
- "read_error threshold "
- "[cur %d:max %d]\n",
- mdname(mddev),
- b, cur_read_error_count, max_read_errors);
- printk(KERN_NOTICE
- "md/raid10:%s: %s: Failing raid "
- "device\n", mdname(mddev), b);
- md_error(mddev, conf->mirrors[d].rdev);
- return;
- }
+ printk(KERN_NOTICE
+ "md/raid10:%s: %s: Raid device exceeded "
+ "read_error threshold [cur %d:max %d]\n",
+ mdname(mddev), b,
+ atomic_read(&rdev->read_errors), max_read_errors);
+ printk(KERN_NOTICE
+ "md/raid10:%s: %s: Failing raid device\n",
+ mdname(mddev), b);
+ md_error(mddev, conf->mirrors[d].rdev);
+ return;
}
- rcu_read_unlock();
while(sectors) {
int s = sectors;
@@ -1562,8 +1532,8 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
"write failed"
" (%d sectors at %llu on %s)\n",
mdname(mddev), s,
- (unsigned long long)(sect+
- rdev->data_offset),
+ (unsigned long long)(
+ sect + rdev->data_offset),
bdevname(rdev->bdev, b));
printk(KERN_NOTICE "md/raid10:%s: %s: failing "
"drive\n",
@@ -1599,8 +1569,8 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
"corrected sectors"
" (%d sectors at %llu on %s)\n",
mdname(mddev), s,
- (unsigned long long)(sect+
- rdev->data_offset),
+ (unsigned long long)(
+ sect + rdev->data_offset),
bdevname(rdev->bdev, b));
printk(KERN_NOTICE "md/raid10:%s: %s: failing drive\n",
mdname(mddev),
@@ -1612,8 +1582,8 @@ static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
"md/raid10:%s: read error corrected"
" (%d sectors at %llu on %s)\n",
mdname(mddev), s,
- (unsigned long long)(sect+
- rdev->data_offset),
+ (unsigned long long)(
+ sect + rdev->data_offset),
bdevname(rdev->bdev, b));
}
@@ -1663,7 +1633,8 @@ static void raid10d(mddev_t *mddev)
else if (test_bit(R10BIO_IsRecover, &r10_bio->state))
recovery_request_write(mddev, r10_bio);
else {
- int mirror;
+ int slot = r10_bio->read_slot;
+ int mirror = r10_bio->devs[slot].devnum;
/* we got a read error. Maybe the drive is bad. Maybe just
* the block and we can fix it.
* We freeze all other IO, and try reading the block from
@@ -1677,9 +1648,10 @@ static void raid10d(mddev_t *mddev)
fix_read_error(conf, mddev, r10_bio);
unfreeze_array(conf);
}
+ rdev_dec_pending(conf->mirrors[mirror].rdev, mddev);
- bio = r10_bio->devs[r10_bio->read_slot].bio;
- r10_bio->devs[r10_bio->read_slot].bio =
+ bio = r10_bio->devs[slot].bio;
+ r10_bio->devs[slot].bio =
mddev->ro ? IO_BLOCKED : NULL;
mirror = read_balance(conf, r10_bio);
if (mirror == -1) {
@@ -1693,6 +1665,7 @@ static void raid10d(mddev_t *mddev)
} else {
const unsigned long do_sync = (r10_bio->master_bio->bi_rw & REQ_SYNC);
bio_put(bio);
+ slot = r10_bio->read_slot;
rdev = conf->mirrors[mirror].rdev;
if (printk_ratelimit())
printk(KERN_ERR "md/raid10:%s: %s: redirecting sector %llu to"
@@ -1702,8 +1675,8 @@ static void raid10d(mddev_t *mddev)
(unsigned long long)r10_bio->sector);
bio = bio_clone_mddev(r10_bio->master_bio,
GFP_NOIO, mddev);
- r10_bio->devs[r10_bio->read_slot].bio = bio;
- bio->bi_sector = r10_bio->devs[r10_bio->read_slot].addr
+ r10_bio->devs[slot].bio = bio;
+ bio->bi_sector = r10_bio->devs[slot].addr
+ rdev->data_offset;
bio->bi_bdev = rdev->bdev;
bio->bi_rw = READ | do_sync;
@@ -1763,13 +1736,13 @@ static int init_resync(conf_t *conf)
*
*/
-static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster)
+static sector_t sync_request(mddev_t *mddev, sector_t sector_nr,
+ int *skipped, int go_faster)
{
conf_t *conf = mddev->private;
r10bio_t *r10_bio;
struct bio *biolist = NULL, *bio;
sector_t max_sector, nr_sectors;
- int disk;
int i;
int max_sync;
sector_t sync_blocks;
@@ -1858,108 +1831,114 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
int j, k;
r10_bio = NULL;
- for (i=0 ; i<conf->raid_disks; i++)
- if (conf->mirrors[i].rdev &&
- !test_bit(In_sync, &conf->mirrors[i].rdev->flags)) {
- int still_degraded = 0;
- /* want to reconstruct this device */
- r10bio_t *rb2 = r10_bio;
- sector_t sect = raid10_find_virt(conf, sector_nr, i);
- int must_sync;
- /* Unless we are doing a full sync, we only need
- * to recover the block if it is set in the bitmap
- */
- must_sync = bitmap_start_sync(mddev->bitmap, sect,
- &sync_blocks, 1);
- if (sync_blocks < max_sync)
- max_sync = sync_blocks;
- if (!must_sync &&
- !conf->fullsync) {
- /* yep, skip the sync_blocks here, but don't assume
- * that there will never be anything to do here
- */
- chunks_skipped = -1;
- continue;
- }
+ for (i=0 ; i<conf->raid_disks; i++) {
+ int still_degraded;
+ r10bio_t *rb2;
+ sector_t sect;
+ int must_sync;
- r10_bio = mempool_alloc(conf->r10buf_pool, GFP_NOIO);
- raise_barrier(conf, rb2 != NULL);
- atomic_set(&r10_bio->remaining, 0);
+ if (conf->mirrors[i].rdev == NULL ||
+ test_bit(In_sync, &conf->mirrors[i].rdev->flags))
+ continue;
- r10_bio->master_bio = (struct bio*)rb2;
- if (rb2)
- atomic_inc(&rb2->remaining);
- r10_bio->mddev = mddev;
- set_bit(R10BIO_IsRecover, &r10_bio->state);
- r10_bio->sector = sect;
+ still_degraded = 0;
+ /* want to reconstruct this device */
+ rb2 = r10_bio;
+ sect = raid10_find_virt(conf, sector_nr, i);
+ /* Unless we are doing a full sync, we only need
+ * to recover the block if it is set in the bitmap
+ */
+ must_sync = bitmap_start_sync(mddev->bitmap, sect,
+ &sync_blocks, 1);
+ if (sync_blocks < max_sync)
+ max_sync = sync_blocks;
+ if (!must_sync &&
+ !conf->fullsync) {
+ /* yep, skip the sync_blocks here, but don't assume
+ * that there will never be anything to do here
+ */
+ chunks_skipped = -1;
+ continue;
+ }
- raid10_find_phys(conf, r10_bio);
+ r10_bio = mempool_alloc(conf->r10buf_pool, GFP_NOIO);
+ raise_barrier(conf, rb2 != NULL);
+ atomic_set(&r10_bio->remaining, 0);
- /* Need to check if the array will still be
- * degraded
- */
- for (j=0; j<conf->raid_disks; j++)
- if (conf->mirrors[j].rdev == NULL ||
- test_bit(Faulty, &conf->mirrors[j].rdev->flags)) {
- still_degraded = 1;
- break;
- }
-
- must_sync = bitmap_start_sync(mddev->bitmap, sect,
- &sync_blocks, still_degraded);
-
- for (j=0; j<conf->copies;j++) {
- int d = r10_bio->devs[j].devnum;
- if (conf->mirrors[d].rdev &&
- test_bit(In_sync, &conf->mirrors[d].rdev->flags)) {
- /* This is where we read from */
- bio = r10_bio->devs[0].bio;
- bio->bi_next = biolist;
- biolist = bio;
- bio->bi_private = r10_bio;
- bio->bi_end_io = end_sync_read;
- bio->bi_rw = READ;
- bio->bi_sector = r10_bio->devs[j].addr +
- conf->mirrors[d].rdev->data_offset;
- bio->bi_bdev = conf->mirrors[d].rdev->bdev;
- atomic_inc(&conf->mirrors[d].rdev->nr_pending);
- atomic_inc(&r10_bio->remaining);
- /* and we write to 'i' */
-
- for (k=0; k<conf->copies; k++)
- if (r10_bio->devs[k].devnum == i)
- break;
- BUG_ON(k == conf->copies);
- bio = r10_bio->devs[1].bio;
- bio->bi_next = biolist;
- biolist = bio;
- bio->bi_private = r10_bio;
- bio->bi_end_io = end_sync_write;
- bio->bi_rw = WRITE;
- bio->bi_sector = r10_bio->devs[k].addr +
- conf->mirrors[i].rdev->data_offset;
- bio->bi_bdev = conf->mirrors[i].rdev->bdev;
-
- r10_bio->devs[0].devnum = d;
- r10_bio->devs[1].devnum = i;
+ r10_bio->master_bio = (struct bio*)rb2;
+ if (rb2)
+ atomic_inc(&rb2->remaining);
+ r10_bio->mddev = mddev;
+ set_bit(R10BIO_IsRecover, &r10_bio->state);
+ r10_bio->sector = sect;
- break;
- }
- }
- if (j == conf->copies) {
- /* Cannot recover, so abort the recovery */
- put_buf(r10_bio);
- if (rb2)
- atomic_dec(&rb2->remaining);
- r10_bio = rb2;
- if (!test_and_set_bit(MD_RECOVERY_INTR,
- &mddev->recovery))
- printk(KERN_INFO "md/raid10:%s: insufficient "
- "working devices for recovery.\n",
- mdname(mddev));
+ raid10_find_phys(conf, r10_bio);
+
+ /* Need to check if the array will still be
+ * degraded
+ */
+ for (j=0; j<conf->raid_disks; j++)
+ if (conf->mirrors[j].rdev == NULL ||
+ test_bit(Faulty, &conf->mirrors[j].rdev->flags)) {
+ still_degraded = 1;
break;
}
+
+ must_sync = bitmap_start_sync(mddev->bitmap, sect,
+ &sync_blocks, still_degraded);
+
+ for (j=0; j<conf->copies;j++) {
+ int d = r10_bio->devs[j].devnum;
+ if (!conf->mirrors[d].rdev ||
+ !test_bit(In_sync, &conf->mirrors[d].rdev->flags))
+ continue;
+ /* This is where we read from */
+ bio = r10_bio->devs[0].bio;
+ bio->bi_next = biolist;
+ biolist = bio;
+ bio->bi_private = r10_bio;
+ bio->bi_end_io = end_sync_read;
+ bio->bi_rw = READ;
+ bio->bi_sector = r10_bio->devs[j].addr +
+ conf->mirrors[d].rdev->data_offset;
+ bio->bi_bdev = conf->mirrors[d].rdev->bdev;
+ atomic_inc(&conf->mirrors[d].rdev->nr_pending);
+ atomic_inc(&r10_bio->remaining);
+ /* and we write to 'i' */
+
+ for (k=0; k<conf->copies; k++)
+ if (r10_bio->devs[k].devnum == i)
+ break;
+ BUG_ON(k == conf->copies);
+ bio = r10_bio->devs[1].bio;
+ bio->bi_next = biolist;
+ biolist = bio;
+ bio->bi_private = r10_bio;
+ bio->bi_end_io = end_sync_write;
+ bio->bi_rw = WRITE;
+ bio->bi_sector = r10_bio->devs[k].addr +
+ conf->mirrors[i].rdev->data_offset;
+ bio->bi_bdev = conf->mirrors[i].rdev->bdev;
+
+ r10_bio->devs[0].devnum = d;
+ r10_bio->devs[1].devnum = i;
+
+ break;
+ }
+ if (j == conf->copies) {
+ /* Cannot recover, so abort the recovery */
+ put_buf(r10_bio);
+ if (rb2)
+ atomic_dec(&rb2->remaining);
+ r10_bio = rb2;
+ if (!test_and_set_bit(MD_RECOVERY_INTR,
+ &mddev->recovery))
+ printk(KERN_INFO "md/raid10:%s: insufficient "
+ "working devices for recovery.\n",
+ mdname(mddev));
+ break;
}
+ }
if (biolist == NULL) {
while (r10_bio) {
r10bio_t *rb2 = r10_bio;
@@ -1977,7 +1956,8 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
if (!bitmap_start_sync(mddev->bitmap, sector_nr,
&sync_blocks, mddev->degraded) &&
- !conf->fullsync && !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
+ !conf->fullsync && !test_bit(MD_RECOVERY_REQUESTED,
+ &mddev->recovery)) {
/* We can skip this block */
*skipped = 1;
return sync_blocks + sectors_skipped;
@@ -2022,7 +2002,8 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
for (i=0; i<conf->copies; i++) {
int d = r10_bio->devs[i].devnum;
if (r10_bio->devs[i].bio->bi_end_io)
- rdev_dec_pending(conf->mirrors[d].rdev, mddev);
+ rdev_dec_pending(conf->mirrors[d].rdev,
+ mddev);
}
put_buf(r10_bio);
biolist = NULL;
@@ -2047,26 +2028,27 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
do {
struct page *page;
int len = PAGE_SIZE;
- disk = 0;
if (sector_nr + (len>>9) > max_sector)
len = (max_sector - sector_nr) << 9;
if (len == 0)
break;
for (bio= biolist ; bio ; bio=bio->bi_next) {
+ struct bio *bio2;
page = bio->bi_io_vec[bio->bi_vcnt].bv_page;
- if (bio_add_page(bio, page, len, 0) == 0) {
- /* stop here */
- struct bio *bio2;
- bio->bi_io_vec[bio->bi_vcnt].bv_page = page;
- for (bio2 = biolist; bio2 && bio2 != bio; bio2 = bio2->bi_next) {
- /* remove last page from this bio */
- bio2->bi_vcnt--;
- bio2->bi_size -= len;
- bio2->bi_flags &= ~(1<< BIO_SEG_VALID);
- }
- goto bio_full;
+ if (bio_add_page(bio, page, len, 0))
+ continue;
+
+ /* stop here */
+ bio->bi_io_vec[bio->bi_vcnt].bv_page = page;
+ for (bio2 = biolist;
+ bio2 && bio2 != bio;
+ bio2 = bio2->bi_next) {
+ /* remove last page from this bio */
+ bio2->bi_vcnt--;
+ bio2->bi_size -= len;
+ bio2->bi_flags &= ~(1<< BIO_SEG_VALID);
}
- disk = i;
+ goto bio_full;
}
nr_sectors += len>>9;
sector_nr += len>>9;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 49bf5f891435..346e69bfdab3 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -1700,27 +1700,25 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
raid5_conf_t *conf = mddev->private;
pr_debug("raid456: error called\n");
- if (!test_bit(Faulty, &rdev->flags)) {
- set_bit(MD_CHANGE_DEVS, &mddev->flags);
- if (test_and_clear_bit(In_sync, &rdev->flags)) {
- unsigned long flags;
- spin_lock_irqsave(&conf->device_lock, flags);
- mddev->degraded++;
- spin_unlock_irqrestore(&conf->device_lock, flags);
- /*
- * if recovery was running, make sure it aborts.
- */
- set_bit(MD_RECOVERY_INTR, &mddev->recovery);
- }
- set_bit(Faulty, &rdev->flags);
- printk(KERN_ALERT
- "md/raid:%s: Disk failure on %s, disabling device.\n"
- "md/raid:%s: Operation continuing on %d devices.\n",
- mdname(mddev),
- bdevname(rdev->bdev, b),
- mdname(mddev),
- conf->raid_disks - mddev->degraded);
+ if (test_and_clear_bit(In_sync, &rdev->flags)) {
+ unsigned long flags;
+ spin_lock_irqsave(&conf->device_lock, flags);
+ mddev->degraded++;
+ spin_unlock_irqrestore(&conf->device_lock, flags);
+ /*
+ * if recovery was running, make sure it aborts.
+ */
+ set_bit(MD_RECOVERY_INTR, &mddev->recovery);
}
+ set_bit(Faulty, &rdev->flags);
+ set_bit(MD_CHANGE_DEVS, &mddev->flags);
+ printk(KERN_ALERT
+ "md/raid:%s: Disk failure on %s, disabling device.\n"
+ "md/raid:%s: Operation continuing on %d devices.\n",
+ mdname(mddev),
+ bdevname(rdev->bdev, b),
+ mdname(mddev),
+ conf->raid_disks - mddev->degraded);
}
/*
@@ -3960,7 +3958,7 @@ static int make_request(mddev_t *mddev, struct bio * bi)
/* spinlock is needed as reshape_progress may be
* 64bit on a 32bit platform, and so it might be
* possible to see a half-updated value
- * Ofcourse reshape_progress could change after
+ * Of course reshape_progress could change after
* the lock is dropped, so once we get a reference
* to the stripe that we think it is, we will have
* to check again.
@@ -5391,7 +5389,8 @@ static int raid5_resize(mddev_t *mddev, sector_t sectors)
return -EINVAL;
set_capacity(mddev->gendisk, mddev->array_sectors);
revalidate_disk(mddev->gendisk);
- if (sectors > mddev->dev_sectors && mddev->recovery_cp == MaxSector) {
+ if (sectors > mddev->dev_sectors &&
+ mddev->recovery_cp > mddev->dev_sectors) {
mddev->recovery_cp = mddev->dev_sectors;
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
}
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
index 9f47e383c57a..9af2140b57a4 100644
--- a/drivers/media/common/saa7146_core.c
+++ b/drivers/media/common/saa7146_core.c
@@ -378,12 +378,7 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
dev->pci = pci;
/* get chip-revision; this is needed to enable bug-fixes */
- err = pci_read_config_dword(pci, PCI_CLASS_REVISION, &dev->revision);
- if (err < 0) {
- ERR(("pci_read_config_dword() failed.\n"));
- goto err_disable;
- }
- dev->revision &= 0xf;
+ dev->revision = pci->revision;
/* remap the memory from virtual to physical address */
diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig
index 6fc79f15dcbc..22d3ca36370e 100644
--- a/drivers/media/common/tuners/Kconfig
+++ b/drivers/media/common/tuners/Kconfig
@@ -186,4 +186,12 @@ config MEDIA_TUNER_TDA18218
default m if MEDIA_TUNER_CUSTOMISE
help
NXP TDA18218 silicon tuner driver.
+
+config MEDIA_TUNER_TDA18212
+ tristate "NXP TDA18212 silicon tuner"
+ depends on VIDEO_MEDIA && I2C
+ default m if MEDIA_TUNER_CUSTOMISE
+ help
+ NXP TDA18212 silicon tuner driver.
+
endmenu
diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile
index 96da03d349ca..2cb4f5327843 100644
--- a/drivers/media/common/tuners/Makefile
+++ b/drivers/media/common/tuners/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o
obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o
obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o
obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o
+obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/common/tuners/mxl5005s.c b/drivers/media/common/tuners/mxl5005s.c
index 0d6e09419044..56fe75c94deb 100644
--- a/drivers/media/common/tuners/mxl5005s.c
+++ b/drivers/media/common/tuners/mxl5005s.c
@@ -4024,6 +4024,8 @@ static int mxl5005s_set_params(struct dvb_frontend *fe,
case BANDWIDTH_8_MHZ:
req_bw = MXL5005S_BANDWIDTH_8MHZ;
break;
+ default:
+ return -EINVAL;
}
}
diff --git a/drivers/media/common/tuners/tda18212.c b/drivers/media/common/tuners/tda18212.c
new file mode 100644
index 000000000000..1f1db20d46b1
--- /dev/null
+++ b/drivers/media/common/tuners/tda18212.c
@@ -0,0 +1,265 @@
+/*
+ * NXP TDA18212HN silicon tuner driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 "tda18212_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+/* write multiple registers */
+static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
+ int len)
+{
+ int ret;
+ u8 buf[len+1];
+ struct i2c_msg msg[1] = {
+ {
+ .addr = priv->cfg->i2c_address,
+ .flags = 0,
+ .len = sizeof(buf),
+ .buf = buf,
+ }
+ };
+
+ buf[0] = reg;
+ memcpy(&buf[1], val, len);
+
+ ret = i2c_transfer(priv->i2c, msg, 1);
+ if (ret == 1) {
+ ret = 0;
+ } else {
+ warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len);
+ ret = -EREMOTEIO;
+ }
+ return ret;
+}
+
+/* read multiple registers */
+static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
+ int len)
+{
+ int ret;
+ u8 buf[len];
+ struct i2c_msg msg[2] = {
+ {
+ .addr = priv->cfg->i2c_address,
+ .flags = 0,
+ .len = 1,
+ .buf = &reg,
+ }, {
+ .addr = priv->cfg->i2c_address,
+ .flags = I2C_M_RD,
+ .len = sizeof(buf),
+ .buf = buf,
+ }
+ };
+
+ ret = i2c_transfer(priv->i2c, msg, 2);
+ if (ret == 2) {
+ memcpy(val, buf, len);
+ ret = 0;
+ } else {
+ warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len);
+ ret = -EREMOTEIO;
+ }
+
+ return ret;
+}
+
+/* write single register */
+static int tda18212_wr_reg(struct tda18212_priv *priv, u8 reg, u8 val)
+{
+ return tda18212_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register */
+static int tda18212_rd_reg(struct tda18212_priv *priv, u8 reg, u8 *val)
+{
+ return tda18212_rd_regs(priv, reg, val, 1);
+}
+
+#if 0 /* keep, useful when developing driver */
+static void tda18212_dump_regs(struct tda18212_priv *priv)
+{
+ int i;
+ u8 buf[256];
+
+ #define TDA18212_RD_LEN 32
+ for (i = 0; i < sizeof(buf); i += TDA18212_RD_LEN)
+ tda18212_rd_regs(priv, i, &buf[i], TDA18212_RD_LEN);
+
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 32, 1, buf,
+ sizeof(buf), true);
+
+ return;
+}
+#endif
+
+static int tda18212_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct tda18212_priv *priv = fe->tuner_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret, i;
+ u32 if_khz;
+ u8 buf[9];
+ static const u8 bw_params[][3] = {
+ /* 0f 13 23 */
+ { 0xb3, 0x20, 0x03 }, /* DVB-T 6 MHz */
+ { 0xb3, 0x31, 0x01 }, /* DVB-T 7 MHz */
+ { 0xb3, 0x22, 0x01 }, /* DVB-T 8 MHz */
+ { 0x92, 0x53, 0x03 }, /* DVB-C */
+ };
+
+ dbg("%s: delsys=%d RF=%d BW=%d", __func__,
+ c->delivery_system, c->frequency, c->bandwidth_hz);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+ switch (c->delivery_system) {
+ case SYS_DVBT:
+ switch (c->bandwidth_hz) {
+ case 6000000:
+ if_khz = priv->cfg->if_dvbt_6;
+ i = 0;
+ break;
+ case 7000000:
+ if_khz = priv->cfg->if_dvbt_7;
+ i = 1;
+ break;
+ case 8000000:
+ if_khz = priv->cfg->if_dvbt_8;
+ i = 2;
+ break;
+ default:
+ ret = -EINVAL;
+ goto error;
+ }
+ break;
+ case SYS_DVBC_ANNEX_AC:
+ if_khz = priv->cfg->if_dvbc;
+ i = 3;
+ break;
+ default:
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = tda18212_wr_reg(priv, 0x23, bw_params[i][2]);
+ if (ret)
+ goto error;
+
+ ret = tda18212_wr_reg(priv, 0x06, 0x00);
+ if (ret)
+ goto error;
+
+ ret = tda18212_wr_reg(priv, 0x0f, bw_params[i][0]);
+ if (ret)
+ goto error;
+
+ buf[0] = 0x02;
+ buf[1] = bw_params[i][1];
+ buf[2] = 0x03; /* default value */
+ buf[3] = if_khz / 50;
+ buf[4] = ((c->frequency / 1000) >> 16) & 0xff;
+ buf[5] = ((c->frequency / 1000) >> 8) & 0xff;
+ buf[6] = ((c->frequency / 1000) >> 0) & 0xff;
+ buf[7] = 0xc1;
+ buf[8] = 0x01;
+ ret = tda18212_wr_regs(priv, 0x12, buf, sizeof(buf));
+ if (ret)
+ goto error;
+
+exit:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+ return ret;
+
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ goto exit;
+}
+
+static int tda18212_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static const struct dvb_tuner_ops tda18212_tuner_ops = {
+ .info = {
+ .name = "NXP TDA18212",
+
+ .frequency_min = 48000000,
+ .frequency_max = 864000000,
+ .frequency_step = 1000,
+ },
+
+ .release = tda18212_release,
+
+ .set_params = tda18212_set_params,
+};
+
+struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, struct tda18212_config *cfg)
+{
+ struct tda18212_priv *priv = NULL;
+ int ret;
+ u8 val;
+
+ priv = kzalloc(sizeof(struct tda18212_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+
+ priv->cfg = cfg;
+ priv->i2c = i2c;
+ fe->tuner_priv = priv;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+ /* check if the tuner is there */
+ ret = tda18212_rd_reg(priv, 0x00, &val);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+ dbg("%s: ret:%d chip ID:%02x", __func__, ret, val);
+ if (ret || val != 0xc7) {
+ kfree(priv);
+ return NULL;
+ }
+
+ info("NXP TDA18212HN successfully identified.");
+
+ memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ return fe;
+}
+EXPORT_SYMBOL(tda18212_attach);
+
+MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/tda18212.h b/drivers/media/common/tuners/tda18212.h
new file mode 100644
index 000000000000..83b497f59e1b
--- /dev/null
+++ b/drivers/media/common/tuners/tda18212.h
@@ -0,0 +1,48 @@
+/*
+ * NXP TDA18212HN silicon tuner driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef TDA18212_H
+#define TDA18212_H
+
+#include "dvb_frontend.h"
+
+struct tda18212_config {
+ u8 i2c_address;
+
+ u16 if_dvbt_6;
+ u16 if_dvbt_7;
+ u16 if_dvbt_8;
+ u16 if_dvbc;
+};
+
+#if defined(CONFIG_MEDIA_TUNER_TDA18212) || \
+ (defined(CONFIG_MEDIA_TUNER_TDA18212_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, struct tda18212_config *cfg);
+#else
+static inline struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, struct tda18212_config *cfg)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/common/tuners/tda18212_priv.h b/drivers/media/common/tuners/tda18212_priv.h
new file mode 100644
index 000000000000..9adff9356b73
--- /dev/null
+++ b/drivers/media/common/tuners/tda18212_priv.h
@@ -0,0 +1,44 @@
+/*
+ * NXP TDA18212HN silicon tuner driver
+ *
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef TDA18212_PRIV_H
+#define TDA18212_PRIV_H
+
+#include "tda18212.h"
+
+#define LOG_PREFIX "tda18212"
+
+#undef dbg
+#define dbg(f, arg...) \
+ if (debug) \
+ printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg)
+#undef err
+#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+struct tda18212_priv {
+ struct tda18212_config *cfg;
+ struct i2c_adapter *i2c;
+};
+
+#endif
diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c
index d884f5eee73c..57022e88e338 100644
--- a/drivers/media/common/tuners/tda18271-fe.c
+++ b/drivers/media/common/tuners/tda18271-fe.c
@@ -976,6 +976,10 @@ static int tda18271_set_params(struct dvb_frontend *fe,
tda_warn("bandwidth not set!\n");
return -EINVAL;
}
+ } else if (fe->ops.info.type == FE_QAM) {
+ /* DVB-C */
+ map = &std_map->qam_8;
+ bw = 8000000;
} else {
tda_warn("modulation type not supported!\n");
return -EINVAL;
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c
index 1e28f7dcb26b..aa1b2e844d32 100644
--- a/drivers/media/common/tuners/xc5000.c
+++ b/drivers/media/common/tuners/xc5000.c
@@ -628,6 +628,15 @@ static void xc_debug_dump(struct xc5000_priv *priv)
dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality);
}
+/*
+ * As defined on EN 300 429, the DVB-C roll-off factor is 0.15.
+ * So, the amount of the needed bandwith is given by:
+ * Bw = Symbol_rate * (1 + 0.15)
+ * As such, the maximum symbol rate supported by 6 MHz is given by:
+ * max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds
+ */
+#define MAX_SYMBOL_RATE_6MHz 5217391
+
static int xc5000_set_params(struct dvb_frontend *fe,
struct dvb_frontend_parameters *params)
{
@@ -688,21 +697,32 @@ static int xc5000_set_params(struct dvb_frontend *fe,
}
priv->rf_mode = XC_RF_MODE_AIR;
} else if (fe->ops.info.type == FE_QAM) {
- dprintk(1, "%s() QAM\n", __func__);
switch (params->u.qam.modulation) {
+ case QAM_256:
+ case QAM_AUTO:
case QAM_16:
case QAM_32:
case QAM_64:
case QAM_128:
- case QAM_256:
- case QAM_AUTO:
dprintk(1, "%s() QAM modulation\n", __func__);
- priv->bandwidth = BANDWIDTH_8_MHZ;
- priv->video_standard = DTV7_8;
- priv->freq_hz = params->frequency - 2750000;
priv->rf_mode = XC_RF_MODE_CABLE;
+ /*
+ * Using a 8MHz bandwidth sometimes fail
+ * with 6MHz-spaced channels, due to inter-carrier
+ * interference. So, use DTV6 firmware
+ */
+ if (params->u.qam.symbol_rate <= MAX_SYMBOL_RATE_6MHz) {
+ priv->bandwidth = BANDWIDTH_6_MHZ;
+ priv->video_standard = DTV6;
+ priv->freq_hz = params->frequency - 1750000;
+ } else {
+ priv->bandwidth = BANDWIDTH_8_MHZ;
+ priv->video_standard = DTV7_8;
+ priv->freq_hz = params->frequency - 2750000;
+ }
break;
default:
+ dprintk(1, "%s() Unsupported QAM type\n", __func__);
return -EINVAL;
}
} else {
diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c
index 03f96d6ca894..44f8fb5f17ff 100644
--- a/drivers/media/dvb/b2c2/flexcop-pci.c
+++ b/drivers/media/dvb/b2c2/flexcop-pci.c
@@ -290,10 +290,8 @@ static void flexcop_pci_dma_exit(struct flexcop_pci *fc_pci)
static int flexcop_pci_init(struct flexcop_pci *fc_pci)
{
int ret;
- u8 card_rev;
- pci_read_config_byte(fc_pci->pdev, PCI_CLASS_REVISION, &card_rev);
- info("card revision %x", card_rev);
+ info("card revision %x", fc_pci->pdev->revision);
if ((ret = pci_enable_device(fc_pci->pdev)) != 0)
return ret;
diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c
index 99d62094f908..b34fa95185e4 100644
--- a/drivers/media/dvb/bt8xx/bt878.c
+++ b/drivers/media/dvb/bt8xx/bt878.c
@@ -460,7 +460,7 @@ static int __devinit bt878_probe(struct pci_dev *dev,
goto fail0;
}
- pci_read_config_byte(dev, PCI_CLASS_REVISION, &bt->revision);
+ bt->revision = dev->revision;
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c
index 2d8b4044be36..b2b0c45f32a9 100644
--- a/drivers/media/dvb/dm1105/dm1105.c
+++ b/drivers/media/dvb/dm1105/dm1105.c
@@ -20,6 +20,7 @@
*/
#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -49,11 +50,12 @@
#define UNSET (-1U)
-#define DM1105_BOARD_NOAUTO UNSET
-#define DM1105_BOARD_UNKNOWN 0
-#define DM1105_BOARD_DVBWORLD_2002 1
-#define DM1105_BOARD_DVBWORLD_2004 2
-#define DM1105_BOARD_AXESS_DM05 3
+#define DM1105_BOARD_NOAUTO UNSET
+#define DM1105_BOARD_UNKNOWN 0
+#define DM1105_BOARD_DVBWORLD_2002 1
+#define DM1105_BOARD_DVBWORLD_2004 2
+#define DM1105_BOARD_AXESS_DM05 3
+#define DM1105_BOARD_UNBRANDED_I2C_ON_GPIO 4
/* ----------------------------------------------- */
/*
@@ -157,22 +159,38 @@
#define DM1105_MAX 0x04
#define DRIVER_NAME "dm1105"
+#define DM1105_I2C_GPIO_NAME "dm1105-gpio"
#define DM1105_DMA_PACKETS 47
#define DM1105_DMA_PACKET_LENGTH (128*4)
#define DM1105_DMA_BYTES (128 * 4 * DM1105_DMA_PACKETS)
+/* */
+#define GPIO08 (1 << 8)
+#define GPIO13 (1 << 13)
+#define GPIO14 (1 << 14)
+#define GPIO15 (1 << 15)
+#define GPIO16 (1 << 16)
+#define GPIO17 (1 << 17)
+#define GPIO_ALL 0x03ffff
+
/* GPIO's for LNB power control */
-#define DM1105_LNB_MASK 0x00000000
-#define DM1105_LNB_OFF 0x00020000
-#define DM1105_LNB_13V 0x00010100
-#define DM1105_LNB_18V 0x00000100
+#define DM1105_LNB_MASK (GPIO_ALL & ~(GPIO14 | GPIO13))
+#define DM1105_LNB_OFF GPIO17
+#define DM1105_LNB_13V (GPIO16 | GPIO08)
+#define DM1105_LNB_18V GPIO08
/* GPIO's for LNB power control for Axess DM05 */
-#define DM05_LNB_MASK 0x00000000
-#define DM05_LNB_OFF 0x00020000/* actually 13v */
-#define DM05_LNB_13V 0x00020000
-#define DM05_LNB_18V 0x00030000
+#define DM05_LNB_MASK (GPIO_ALL & ~(GPIO14 | GPIO13))
+#define DM05_LNB_OFF GPIO17/* actually 13v */
+#define DM05_LNB_13V GPIO17
+#define DM05_LNB_18V (GPIO17 | GPIO16)
+
+/* GPIO's for LNB power control for unbranded with I2C on GPIO */
+#define UNBR_LNB_MASK (GPIO17 | GPIO16)
+#define UNBR_LNB_OFF 0
+#define UNBR_LNB_13V GPIO17
+#define UNBR_LNB_18V (GPIO17 | GPIO16)
static unsigned int card[] = {[0 ... 3] = UNSET };
module_param_array(card, int, NULL, 0444);
@@ -187,7 +205,11 @@ static unsigned int dm1105_devcount;
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
struct dm1105_board {
- char *name;
+ char *name;
+ struct {
+ u32 mask, off, v13, v18;
+ } lnb;
+ u32 gpio_scl, gpio_sda;
};
struct dm1105_subid {
@@ -199,15 +221,50 @@ struct dm1105_subid {
static const struct dm1105_board dm1105_boards[] = {
[DM1105_BOARD_UNKNOWN] = {
.name = "UNKNOWN/GENERIC",
+ .lnb = {
+ .mask = DM1105_LNB_MASK,
+ .off = DM1105_LNB_OFF,
+ .v13 = DM1105_LNB_13V,
+ .v18 = DM1105_LNB_18V,
+ },
},
[DM1105_BOARD_DVBWORLD_2002] = {
.name = "DVBWorld PCI 2002",
+ .lnb = {
+ .mask = DM1105_LNB_MASK,
+ .off = DM1105_LNB_OFF,
+ .v13 = DM1105_LNB_13V,
+ .v18 = DM1105_LNB_18V,
+ },
},
[DM1105_BOARD_DVBWORLD_2004] = {
.name = "DVBWorld PCI 2004",
+ .lnb = {
+ .mask = DM1105_LNB_MASK,
+ .off = DM1105_LNB_OFF,
+ .v13 = DM1105_LNB_13V,
+ .v18 = DM1105_LNB_18V,
+ },
},
[DM1105_BOARD_AXESS_DM05] = {
.name = "Axess/EasyTv DM05",
+ .lnb = {
+ .mask = DM05_LNB_MASK,
+ .off = DM05_LNB_OFF,
+ .v13 = DM05_LNB_13V,
+ .v18 = DM05_LNB_18V,
+ },
+ },
+ [DM1105_BOARD_UNBRANDED_I2C_ON_GPIO] = {
+ .name = "Unbranded DM1105 with i2c on GPIOs",
+ .lnb = {
+ .mask = UNBR_LNB_MASK,
+ .off = UNBR_LNB_OFF,
+ .v13 = UNBR_LNB_13V,
+ .v18 = UNBR_LNB_18V,
+ },
+ .gpio_scl = GPIO14,
+ .gpio_sda = GPIO13,
},
};
@@ -293,6 +350,8 @@ struct dm1105_dev {
/* i2c */
struct i2c_adapter i2c_adap;
+ struct i2c_adapter i2c_bb_adap;
+ struct i2c_algo_bit_data i2c_bit;
/* irq */
struct work_struct work;
@@ -328,6 +387,103 @@ struct dm1105_dev {
#define dm_setl(reg, bit) dm_andorl((reg), (bit), (bit))
#define dm_clearl(reg, bit) dm_andorl((reg), (bit), 0)
+/* The chip has 18 GPIOs. In HOST mode GPIO's used as 15 bit address lines,
+ so we can use only 3 GPIO's from GPIO15 to GPIO17.
+ Here I don't check whether HOST is enebled as it is not implemented yet.
+ */
+static void dm1105_gpio_set(struct dm1105_dev *dev, u32 mask)
+{
+ if (mask & 0xfffc0000)
+ printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
+
+ if (mask & 0x0003ffff)
+ dm_setl(DM1105_GPIOVAL, mask & 0x0003ffff);
+
+}
+
+static void dm1105_gpio_clear(struct dm1105_dev *dev, u32 mask)
+{
+ if (mask & 0xfffc0000)
+ printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
+
+ if (mask & 0x0003ffff)
+ dm_clearl(DM1105_GPIOVAL, mask & 0x0003ffff);
+
+}
+
+static void dm1105_gpio_andor(struct dm1105_dev *dev, u32 mask, u32 val)
+{
+ if (mask & 0xfffc0000)
+ printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
+
+ if (mask & 0x0003ffff)
+ dm_andorl(DM1105_GPIOVAL, mask & 0x0003ffff, val);
+
+}
+
+static u32 dm1105_gpio_get(struct dm1105_dev *dev, u32 mask)
+{
+ if (mask & 0xfffc0000)
+ printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
+
+ if (mask & 0x0003ffff)
+ return dm_readl(DM1105_GPIOVAL) & mask & 0x0003ffff;
+
+ return 0;
+}
+
+static void dm1105_gpio_enable(struct dm1105_dev *dev, u32 mask, int asoutput)
+{
+ if (mask & 0xfffc0000)
+ printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__);
+
+ if ((mask & 0x0003ffff) && asoutput)
+ dm_clearl(DM1105_GPIOCTR, mask & 0x0003ffff);
+ else if ((mask & 0x0003ffff) && !asoutput)
+ dm_setl(DM1105_GPIOCTR, mask & 0x0003ffff);
+
+}
+
+static void dm1105_setline(struct dm1105_dev *dev, u32 line, int state)
+{
+ if (state)
+ dm1105_gpio_enable(dev, line, 0);
+ else {
+ dm1105_gpio_enable(dev, line, 1);
+ dm1105_gpio_clear(dev, line);
+ }
+}
+
+static void dm1105_setsda(void *data, int state)
+{
+ struct dm1105_dev *dev = data;
+
+ dm1105_setline(dev, dm1105_boards[dev->boardnr].gpio_sda, state);
+}
+
+static void dm1105_setscl(void *data, int state)
+{
+ struct dm1105_dev *dev = data;
+
+ dm1105_setline(dev, dm1105_boards[dev->boardnr].gpio_scl, state);
+}
+
+static int dm1105_getsda(void *data)
+{
+ struct dm1105_dev *dev = data;
+
+ return dm1105_gpio_get(dev, dm1105_boards[dev->boardnr].gpio_sda)
+ ? 1 : 0;
+}
+
+static int dm1105_getscl(void *data)
+{
+ struct dm1105_dev *dev = data;
+
+ return dm1105_gpio_get(dev, dm1105_boards[dev->boardnr].gpio_scl)
+ ? 1 : 0;
+}
+
static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg *msgs, int num)
{
@@ -436,31 +592,20 @@ static inline struct dm1105_dev *frontend_to_dm1105_dev(struct dvb_frontend *fe)
static int dm1105_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
{
struct dm1105_dev *dev = frontend_to_dm1105_dev(fe);
- u32 lnb_mask, lnb_13v, lnb_18v, lnb_off;
- switch (dev->boardnr) {
- case DM1105_BOARD_AXESS_DM05:
- lnb_mask = DM05_LNB_MASK;
- lnb_off = DM05_LNB_OFF;
- lnb_13v = DM05_LNB_13V;
- lnb_18v = DM05_LNB_18V;
- break;
- case DM1105_BOARD_DVBWORLD_2002:
- case DM1105_BOARD_DVBWORLD_2004:
- default:
- lnb_mask = DM1105_LNB_MASK;
- lnb_off = DM1105_LNB_OFF;
- lnb_13v = DM1105_LNB_13V;
- lnb_18v = DM1105_LNB_18V;
- }
-
- dm_writel(DM1105_GPIOCTR, lnb_mask);
+ dm1105_gpio_enable(dev, dm1105_boards[dev->boardnr].lnb.mask, 1);
if (voltage == SEC_VOLTAGE_18)
- dm_writel(DM1105_GPIOVAL, lnb_18v);
+ dm1105_gpio_andor(dev,
+ dm1105_boards[dev->boardnr].lnb.mask,
+ dm1105_boards[dev->boardnr].lnb.v18);
else if (voltage == SEC_VOLTAGE_13)
- dm_writel(DM1105_GPIOVAL, lnb_13v);
+ dm1105_gpio_andor(dev,
+ dm1105_boards[dev->boardnr].lnb.mask,
+ dm1105_boards[dev->boardnr].lnb.v13);
else
- dm_writel(DM1105_GPIOVAL, lnb_off);
+ dm1105_gpio_andor(dev,
+ dm1105_boards[dev->boardnr].lnb.mask,
+ dm1105_boards[dev->boardnr].lnb.off);
return 0;
}
@@ -708,6 +853,38 @@ static int __devinit frontend_init(struct dm1105_dev *dev)
int ret;
switch (dev->boardnr) {
+ case DM1105_BOARD_UNBRANDED_I2C_ON_GPIO:
+ dm1105_gpio_enable(dev, GPIO15, 1);
+ dm1105_gpio_clear(dev, GPIO15);
+ msleep(100);
+ dm1105_gpio_set(dev, GPIO15);
+ msleep(200);
+ dev->fe = dvb_attach(
+ stv0299_attach, &sharp_z0194a_config,
+ &dev->i2c_bb_adap);
+ if (dev->fe) {
+ dev->fe->ops.set_voltage = dm1105_set_voltage;
+ dvb_attach(dvb_pll_attach, dev->fe, 0x60,
+ &dev->i2c_bb_adap, DVB_PLL_OPERA1);
+ break;
+ }
+
+ dev->fe = dvb_attach(
+ stv0288_attach, &earda_config,
+ &dev->i2c_bb_adap);
+ if (dev->fe) {
+ dev->fe->ops.set_voltage = dm1105_set_voltage;
+ dvb_attach(stb6000_attach, dev->fe, 0x61,
+ &dev->i2c_bb_adap);
+ break;
+ }
+
+ dev->fe = dvb_attach(
+ si21xx_attach, &serit_config,
+ &dev->i2c_bb_adap);
+ if (dev->fe)
+ dev->fe->ops.set_voltage = dm1105_set_voltage;
+ break;
case DM1105_BOARD_DVBWORLD_2004:
dev->fe = dvb_attach(
cx24116_attach, &serit_sp2633_config,
@@ -870,11 +1047,32 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
if (ret < 0)
goto err_dm1105_hw_exit;
+ i2c_set_adapdata(&dev->i2c_bb_adap, dev);
+ strcpy(dev->i2c_bb_adap.name, DM1105_I2C_GPIO_NAME);
+ dev->i2c_bb_adap.owner = THIS_MODULE;
+ dev->i2c_bb_adap.dev.parent = &pdev->dev;
+ dev->i2c_bb_adap.algo_data = &dev->i2c_bit;
+ dev->i2c_bit.data = dev;
+ dev->i2c_bit.setsda = dm1105_setsda;
+ dev->i2c_bit.setscl = dm1105_setscl;
+ dev->i2c_bit.getsda = dm1105_getsda;
+ dev->i2c_bit.getscl = dm1105_getscl;
+ dev->i2c_bit.udelay = 10;
+ dev->i2c_bit.timeout = 10;
+
+ /* Raise SCL and SDA */
+ dm1105_setsda(dev, 1);
+ dm1105_setscl(dev, 1);
+
+ ret = i2c_bit_add_bus(&dev->i2c_bb_adap);
+ if (ret < 0)
+ goto err_i2c_del_adapter;
+
/* dvb */
ret = dvb_register_adapter(&dev->dvb_adapter, DRIVER_NAME,
THIS_MODULE, &pdev->dev, adapter_nr);
if (ret < 0)
- goto err_i2c_del_adapter;
+ goto err_i2c_del_adapters;
dvb_adapter = &dev->dvb_adapter;
@@ -952,6 +1150,8 @@ err_dvb_dmx_release:
dvb_dmx_release(dvbdemux);
err_dvb_unregister_adapter:
dvb_unregister_adapter(dvb_adapter);
+err_i2c_del_adapters:
+ i2c_del_adapter(&dev->i2c_bb_adap);
err_i2c_del_adapter:
i2c_del_adapter(&dev->i2c_adap);
err_dm1105_hw_exit:
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 4a88a3e4db2b..faa3671b649e 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -478,97 +478,94 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
-void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
+static inline int find_next_packet(const u8 *buf, int pos, size_t count,
+ const int pktsize)
{
- int p = 0, i, j;
+ int start = pos, lost;
- spin_lock(&demux->lock);
-
- if (demux->tsbufp) {
- i = demux->tsbufp;
- j = 188 - i;
- if (count < j) {
- memcpy(&demux->tsbuf[i], buf, count);
- demux->tsbufp += count;
- goto bailout;
- }
- memcpy(&demux->tsbuf[i], buf, j);
- if (demux->tsbuf[0] == 0x47)
- dvb_dmx_swfilter_packet(demux, demux->tsbuf);
- demux->tsbufp = 0;
- p += j;
+ while (pos < count) {
+ if (buf[pos] == 0x47 ||
+ (pktsize == 204 && buf[pos] == 0xB8))
+ break;
+ pos++;
}
- while (p < count) {
- if (buf[p] == 0x47) {
- if (count - p >= 188) {
- dvb_dmx_swfilter_packet(demux, &buf[p]);
- p += 188;
- } else {
- i = count - p;
- memcpy(demux->tsbuf, &buf[p], i);
- demux->tsbufp = i;
- goto bailout;
- }
- } else
- p++;
+ lost = pos - start;
+ if (lost) {
+ /* This garbage is part of a valid packet? */
+ int backtrack = pos - pktsize;
+ if (backtrack >= 0 && (buf[backtrack] == 0x47 ||
+ (pktsize == 204 && buf[backtrack] == 0xB8)))
+ return backtrack;
}
-bailout:
- spin_unlock(&demux->lock);
+ return pos;
}
-EXPORT_SYMBOL(dvb_dmx_swfilter);
-
-void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
+/* Filter all pktsize= 188 or 204 sized packets and skip garbage. */
+static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
+ size_t count, const int pktsize)
{
int p = 0, i, j;
- u8 tmppack[188];
+ const u8 *q;
spin_lock(&demux->lock);
- if (demux->tsbufp) {
+ if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */
i = demux->tsbufp;
- j = 204 - i;
+ j = pktsize - i;
if (count < j) {
memcpy(&demux->tsbuf[i], buf, count);
demux->tsbufp += count;
goto bailout;
}
memcpy(&demux->tsbuf[i], buf, j);
- if ((demux->tsbuf[0] == 0x47) || (demux->tsbuf[0] == 0xB8)) {
- memcpy(tmppack, demux->tsbuf, 188);
- if (tmppack[0] == 0xB8)
- tmppack[0] = 0x47;
- dvb_dmx_swfilter_packet(demux, tmppack);
- }
+ if (demux->tsbuf[0] == 0x47) /* double check */
+ dvb_dmx_swfilter_packet(demux, demux->tsbuf);
demux->tsbufp = 0;
p += j;
}
- while (p < count) {
- if ((buf[p] == 0x47) || (buf[p] == 0xB8)) {
- if (count - p >= 204) {
- memcpy(tmppack, &buf[p], 188);
- if (tmppack[0] == 0xB8)
- tmppack[0] = 0x47;
- dvb_dmx_swfilter_packet(demux, tmppack);
- p += 204;
- } else {
- i = count - p;
- memcpy(demux->tsbuf, &buf[p], i);
- demux->tsbufp = i;
- goto bailout;
- }
- } else {
- p++;
+ while (1) {
+ p = find_next_packet(buf, p, count, pktsize);
+ if (p >= count)
+ break;
+ if (count - p < pktsize)
+ break;
+
+ q = &buf[p];
+
+ if (pktsize == 204 && (*q == 0xB8)) {
+ memcpy(demux->tsbuf, q, 188);
+ demux->tsbuf[0] = 0x47;
+ q = demux->tsbuf;
}
+ dvb_dmx_swfilter_packet(demux, q);
+ p += pktsize;
+ }
+
+ i = count - p;
+ if (i) {
+ memcpy(demux->tsbuf, &buf[p], i);
+ demux->tsbufp = i;
+ if (pktsize == 204 && demux->tsbuf[0] == 0xB8)
+ demux->tsbuf[0] = 0x47;
}
bailout:
spin_unlock(&demux->lock);
}
+void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
+{
+ _dvb_dmx_swfilter(demux, buf, count, 188);
+}
+EXPORT_SYMBOL(dvb_dmx_swfilter);
+
+void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
+{
+ _dvb_dmx_swfilter(demux, buf, count, 204);
+}
EXPORT_SYMBOL(dvb_dmx_swfilter_204);
static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux)
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 31e2c0d45db3..98278041d75f 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -105,7 +105,8 @@ struct dvb_frontend_private {
/* thread/frontend values */
struct dvb_device *dvbdev;
- struct dvb_frontend_parameters parameters;
+ struct dvb_frontend_parameters parameters_in;
+ struct dvb_frontend_parameters parameters_out;
struct dvb_fe_events events;
struct semaphore sem;
struct list_head list_head;
@@ -160,12 +161,11 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
e = &events->events[events->eventw];
- memcpy (&e->parameters, &fepriv->parameters,
- sizeof (struct dvb_frontend_parameters));
-
if (status & FE_HAS_LOCK)
if (fe->ops.get_frontend)
- fe->ops.get_frontend(fe, &e->parameters);
+ fe->ops.get_frontend(fe, &fepriv->parameters_out);
+
+ e->parameters = fepriv->parameters_out;
events->eventw = wp;
@@ -277,12 +277,12 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
int ready = 0;
int fe_set_err = 0;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
- int original_inversion = fepriv->parameters.inversion;
- u32 original_frequency = fepriv->parameters.frequency;
+ int original_inversion = fepriv->parameters_in.inversion;
+ u32 original_frequency = fepriv->parameters_in.frequency;
/* are we using autoinversion? */
autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
- (fepriv->parameters.inversion == INVERSION_AUTO));
+ (fepriv->parameters_in.inversion == INVERSION_AUTO));
/* setup parameters correctly */
while(!ready) {
@@ -348,18 +348,19 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step);
/* set the frontend itself */
- fepriv->parameters.frequency += fepriv->lnb_drift;
+ fepriv->parameters_in.frequency += fepriv->lnb_drift;
if (autoinversion)
- fepriv->parameters.inversion = fepriv->inversion;
+ fepriv->parameters_in.inversion = fepriv->inversion;
if (fe->ops.set_frontend)
- fe_set_err = fe->ops.set_frontend(fe, &fepriv->parameters);
+ fe_set_err = fe->ops.set_frontend(fe, &fepriv->parameters_in);
+ fepriv->parameters_out = fepriv->parameters_in;
if (fe_set_err < 0) {
fepriv->state = FESTATE_ERROR;
return fe_set_err;
}
- fepriv->parameters.frequency = original_frequency;
- fepriv->parameters.inversion = original_inversion;
+ fepriv->parameters_in.frequency = original_frequency;
+ fepriv->parameters_in.inversion = original_inversion;
fepriv->auto_sub_step++;
return 0;
@@ -383,7 +384,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
if (fepriv->state & FESTATE_RETUNE) {
if (fe->ops.set_frontend)
retval = fe->ops.set_frontend(fe,
- &fepriv->parameters);
+ &fepriv->parameters_in);
+ fepriv->parameters_out = fepriv->parameters_in;
if (retval < 0)
fepriv->state = FESTATE_ERROR;
else
@@ -413,8 +415,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
/* if we're tuned, then we have determined the correct inversion */
if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
- (fepriv->parameters.inversion == INVERSION_AUTO)) {
- fepriv->parameters.inversion = fepriv->inversion;
+ (fepriv->parameters_in.inversion == INVERSION_AUTO)) {
+ fepriv->parameters_in.inversion = fepriv->inversion;
}
return;
}
@@ -594,12 +596,14 @@ restart:
if (fepriv->state & FESTATE_RETUNE) {
dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__);
- params = &fepriv->parameters;
+ params = &fepriv->parameters_in;
fepriv->state = FESTATE_TUNED;
}
if (fe->ops.tune)
fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
+ if (params)
+ fepriv->parameters_out = *params;
if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) {
dprintk("%s: state changed, adding current state\n", __func__);
@@ -612,11 +616,9 @@ restart:
dvb_frontend_swzigzag(fe);
break;
case DVBFE_ALGO_CUSTOM:
- params = NULL; /* have we been asked to RETUNE ? */
dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state);
if (fepriv->state & FESTATE_RETUNE) {
dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__);
- params = &fepriv->parameters;
fepriv->state = FESTATE_TUNED;
}
/* Case where we are going to search for a carrier
@@ -625,7 +627,7 @@ restart:
*/
if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) {
if (fe->ops.search) {
- fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters);
+ fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters_in);
/* We did do a search as was requested, the flags are
* now unset as well and has the flags wrt to search.
*/
@@ -636,11 +638,12 @@ restart:
/* Track the carrier if the search was successful */
if (fepriv->algo_status == DVBFE_ALGO_SEARCH_SUCCESS) {
if (fe->ops.track)
- fe->ops.track(fe, &fepriv->parameters);
+ fe->ops.track(fe, &fepriv->parameters_in);
} else {
fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
fepriv->delay = HZ / 2;
}
+ fepriv->parameters_out = fepriv->parameters_in;
fe->ops.read_status(fe, &s);
if (s != fepriv->status) {
dvb_frontend_add_event(fe, s); /* update event list */
@@ -860,34 +863,34 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int i;
- memset(&(fe->dtv_property_cache), 0,
- sizeof(struct dtv_frontend_properties));
-
- fe->dtv_property_cache.state = DTV_CLEAR;
- fe->dtv_property_cache.delivery_system = SYS_UNDEFINED;
- fe->dtv_property_cache.inversion = INVERSION_AUTO;
- fe->dtv_property_cache.fec_inner = FEC_AUTO;
- fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO;
- fe->dtv_property_cache.bandwidth_hz = BANDWIDTH_AUTO;
- fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO;
- fe->dtv_property_cache.hierarchy = HIERARCHY_AUTO;
- fe->dtv_property_cache.symbol_rate = QAM_AUTO;
- fe->dtv_property_cache.code_rate_HP = FEC_AUTO;
- fe->dtv_property_cache.code_rate_LP = FEC_AUTO;
-
- fe->dtv_property_cache.isdbt_partial_reception = -1;
- fe->dtv_property_cache.isdbt_sb_mode = -1;
- fe->dtv_property_cache.isdbt_sb_subchannel = -1;
- fe->dtv_property_cache.isdbt_sb_segment_idx = -1;
- fe->dtv_property_cache.isdbt_sb_segment_count = -1;
- fe->dtv_property_cache.isdbt_layer_enabled = 0x7;
+ memset(c, 0, sizeof(struct dtv_frontend_properties));
+
+ c->state = DTV_CLEAR;
+ c->delivery_system = SYS_UNDEFINED;
+ c->inversion = INVERSION_AUTO;
+ c->fec_inner = FEC_AUTO;
+ c->transmission_mode = TRANSMISSION_MODE_AUTO;
+ c->bandwidth_hz = BANDWIDTH_AUTO;
+ c->guard_interval = GUARD_INTERVAL_AUTO;
+ c->hierarchy = HIERARCHY_AUTO;
+ c->symbol_rate = QAM_AUTO;
+ c->code_rate_HP = FEC_AUTO;
+ c->code_rate_LP = FEC_AUTO;
+
+ c->isdbt_partial_reception = -1;
+ c->isdbt_sb_mode = -1;
+ c->isdbt_sb_subchannel = -1;
+ c->isdbt_sb_segment_idx = -1;
+ c->isdbt_sb_segment_count = -1;
+ c->isdbt_layer_enabled = 0x7;
for (i = 0; i < 3; i++) {
- fe->dtv_property_cache.layer[i].fec = FEC_AUTO;
- fe->dtv_property_cache.layer[i].modulation = QAM_AUTO;
- fe->dtv_property_cache.layer[i].interleaving = -1;
- fe->dtv_property_cache.layer[i].segment_count = -1;
+ c->layer[i].fec = FEC_AUTO;
+ c->layer[i].modulation = QAM_AUTO;
+ c->layer[i].interleaving = -1;
+ c->layer[i].segment_count = -1;
}
return 0;
@@ -1020,10 +1023,9 @@ static int is_legacy_delivery_system(fe_delivery_system_t s)
* it's being used for the legacy or new API, reducing code and complexity.
*/
static void dtv_property_cache_sync(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+ struct dtv_frontend_properties *c,
+ const struct dvb_frontend_parameters *p)
{
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-
c->frequency = p->frequency;
c->inversion = p->inversion;
@@ -1074,9 +1076,9 @@ static void dtv_property_cache_sync(struct dvb_frontend *fe,
*/
static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
{
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
- struct dvb_frontend_parameters *p = &fepriv->parameters;
+ struct dvb_frontend_parameters *p = &fepriv->parameters_in;
p->frequency = c->frequency;
p->inversion = c->inversion;
@@ -1086,14 +1088,12 @@ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
dprintk("%s() Preparing QPSK req\n", __func__);
p->u.qpsk.symbol_rate = c->symbol_rate;
p->u.qpsk.fec_inner = c->fec_inner;
- c->delivery_system = SYS_DVBS;
break;
case FE_QAM:
dprintk("%s() Preparing QAM req\n", __func__);
p->u.qam.symbol_rate = c->symbol_rate;
p->u.qam.fec_inner = c->fec_inner;
p->u.qam.modulation = c->modulation;
- c->delivery_system = SYS_DVBC_ANNEX_AC;
break;
case FE_OFDM:
dprintk("%s() Preparing OFDM req\n", __func__);
@@ -1111,15 +1111,10 @@ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
p->u.ofdm.transmission_mode = c->transmission_mode;
p->u.ofdm.guard_interval = c->guard_interval;
p->u.ofdm.hierarchy_information = c->hierarchy;
- c->delivery_system = SYS_DVBT;
break;
case FE_ATSC:
dprintk("%s() Preparing VSB req\n", __func__);
p->u.vsb.modulation = c->modulation;
- if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
- c->delivery_system = SYS_ATSC;
- else
- c->delivery_system = SYS_DVBC_ANNEX_B;
break;
}
}
@@ -1129,9 +1124,9 @@ static void dtv_property_legacy_params_sync(struct dvb_frontend *fe)
*/
static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
{
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
- struct dvb_frontend_parameters *p = &fepriv->parameters;
+ struct dvb_frontend_parameters *p = &fepriv->parameters_in;
p->frequency = c->frequency;
p->inversion = c->inversion;
@@ -1148,10 +1143,9 @@ static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
break;
}
- if(c->delivery_system == SYS_ISDBT) {
- /* Fake out a generic DVB-T request so we pass validation in the ioctl */
- p->frequency = c->frequency;
- p->inversion = c->inversion;
+ /* Fake out a generic DVB-T request so we pass validation in the ioctl */
+ if ((c->delivery_system == SYS_ISDBT) ||
+ (c->delivery_system == SYS_DVBT2)) {
p->u.ofdm.constellation = QAM_AUTO;
p->u.ofdm.code_rate_HP = FEC_AUTO;
p->u.ofdm.code_rate_LP = FEC_AUTO;
@@ -1171,7 +1165,7 @@ static void dtv_property_adv_params_sync(struct dvb_frontend *fe)
static void dtv_property_cache_submit(struct dvb_frontend *fe)
{
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
/* For legacy delivery systems we don't need the delivery_system to
* be specified, but we populate the older structures from the cache
@@ -1204,133 +1198,149 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
struct dtv_property *tvp,
struct file *file)
{
- int r = 0;
-
- /* Allow the frontend to validate incoming properties */
- if (fe->ops.get_property)
- r = fe->ops.get_property(fe, tvp);
+ const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct dvb_frontend_private *fepriv = fe->frontend_priv;
+ struct dtv_frontend_properties cdetected;
+ int r;
- if (r < 0)
- return r;
+ /*
+ * If the driver implements a get_frontend function, then convert
+ * detected parameters to S2API properties.
+ */
+ if (fe->ops.get_frontend) {
+ cdetected = *c;
+ dtv_property_cache_sync(fe, &cdetected, &fepriv->parameters_out);
+ c = &cdetected;
+ }
switch(tvp->cmd) {
case DTV_FREQUENCY:
- tvp->u.data = fe->dtv_property_cache.frequency;
+ tvp->u.data = c->frequency;
break;
case DTV_MODULATION:
- tvp->u.data = fe->dtv_property_cache.modulation;
+ tvp->u.data = c->modulation;
break;
case DTV_BANDWIDTH_HZ:
- tvp->u.data = fe->dtv_property_cache.bandwidth_hz;
+ tvp->u.data = c->bandwidth_hz;
break;
case DTV_INVERSION:
- tvp->u.data = fe->dtv_property_cache.inversion;
+ tvp->u.data = c->inversion;
break;
case DTV_SYMBOL_RATE:
- tvp->u.data = fe->dtv_property_cache.symbol_rate;
+ tvp->u.data = c->symbol_rate;
break;
case DTV_INNER_FEC:
- tvp->u.data = fe->dtv_property_cache.fec_inner;
+ tvp->u.data = c->fec_inner;
break;
case DTV_PILOT:
- tvp->u.data = fe->dtv_property_cache.pilot;
+ tvp->u.data = c->pilot;
break;
case DTV_ROLLOFF:
- tvp->u.data = fe->dtv_property_cache.rolloff;
+ tvp->u.data = c->rolloff;
break;
case DTV_DELIVERY_SYSTEM:
- tvp->u.data = fe->dtv_property_cache.delivery_system;
+ tvp->u.data = c->delivery_system;
break;
case DTV_VOLTAGE:
- tvp->u.data = fe->dtv_property_cache.voltage;
+ tvp->u.data = c->voltage;
break;
case DTV_TONE:
- tvp->u.data = fe->dtv_property_cache.sectone;
+ tvp->u.data = c->sectone;
break;
case DTV_API_VERSION:
tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR;
break;
case DTV_CODE_RATE_HP:
- tvp->u.data = fe->dtv_property_cache.code_rate_HP;
+ tvp->u.data = c->code_rate_HP;
break;
case DTV_CODE_RATE_LP:
- tvp->u.data = fe->dtv_property_cache.code_rate_LP;
+ tvp->u.data = c->code_rate_LP;
break;
case DTV_GUARD_INTERVAL:
- tvp->u.data = fe->dtv_property_cache.guard_interval;
+ tvp->u.data = c->guard_interval;
break;
case DTV_TRANSMISSION_MODE:
- tvp->u.data = fe->dtv_property_cache.transmission_mode;
+ tvp->u.data = c->transmission_mode;
break;
case DTV_HIERARCHY:
- tvp->u.data = fe->dtv_property_cache.hierarchy;
+ tvp->u.data = c->hierarchy;
break;
/* ISDB-T Support here */
case DTV_ISDBT_PARTIAL_RECEPTION:
- tvp->u.data = fe->dtv_property_cache.isdbt_partial_reception;
+ tvp->u.data = c->isdbt_partial_reception;
break;
case DTV_ISDBT_SOUND_BROADCASTING:
- tvp->u.data = fe->dtv_property_cache.isdbt_sb_mode;
+ tvp->u.data = c->isdbt_sb_mode;
break;
case DTV_ISDBT_SB_SUBCHANNEL_ID:
- tvp->u.data = fe->dtv_property_cache.isdbt_sb_subchannel;
+ tvp->u.data = c->isdbt_sb_subchannel;
break;
case DTV_ISDBT_SB_SEGMENT_IDX:
- tvp->u.data = fe->dtv_property_cache.isdbt_sb_segment_idx;
+ tvp->u.data = c->isdbt_sb_segment_idx;
break;
case DTV_ISDBT_SB_SEGMENT_COUNT:
- tvp->u.data = fe->dtv_property_cache.isdbt_sb_segment_count;
+ tvp->u.data = c->isdbt_sb_segment_count;
break;
case DTV_ISDBT_LAYER_ENABLED:
- tvp->u.data = fe->dtv_property_cache.isdbt_layer_enabled;
+ tvp->u.data = c->isdbt_layer_enabled;
break;
case DTV_ISDBT_LAYERA_FEC:
- tvp->u.data = fe->dtv_property_cache.layer[0].fec;
+ tvp->u.data = c->layer[0].fec;
break;
case DTV_ISDBT_LAYERA_MODULATION:
- tvp->u.data = fe->dtv_property_cache.layer[0].modulation;
+ tvp->u.data = c->layer[0].modulation;
break;
case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
- tvp->u.data = fe->dtv_property_cache.layer[0].segment_count;
+ tvp->u.data = c->layer[0].segment_count;
break;
case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
- tvp->u.data = fe->dtv_property_cache.layer[0].interleaving;
+ tvp->u.data = c->layer[0].interleaving;
break;
case DTV_ISDBT_LAYERB_FEC:
- tvp->u.data = fe->dtv_property_cache.layer[1].fec;
+ tvp->u.data = c->layer[1].fec;
break;
case DTV_ISDBT_LAYERB_MODULATION:
- tvp->u.data = fe->dtv_property_cache.layer[1].modulation;
+ tvp->u.data = c->layer[1].modulation;
break;
case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
- tvp->u.data = fe->dtv_property_cache.layer[1].segment_count;
+ tvp->u.data = c->layer[1].segment_count;
break;
case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
- tvp->u.data = fe->dtv_property_cache.layer[1].interleaving;
+ tvp->u.data = c->layer[1].interleaving;
break;
case DTV_ISDBT_LAYERC_FEC:
- tvp->u.data = fe->dtv_property_cache.layer[2].fec;
+ tvp->u.data = c->layer[2].fec;
break;
case DTV_ISDBT_LAYERC_MODULATION:
- tvp->u.data = fe->dtv_property_cache.layer[2].modulation;
+ tvp->u.data = c->layer[2].modulation;
break;
case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
- tvp->u.data = fe->dtv_property_cache.layer[2].segment_count;
+ tvp->u.data = c->layer[2].segment_count;
break;
case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
- tvp->u.data = fe->dtv_property_cache.layer[2].interleaving;
+ tvp->u.data = c->layer[2].interleaving;
break;
case DTV_ISDBS_TS_ID:
- tvp->u.data = fe->dtv_property_cache.isdbs_ts_id;
+ tvp->u.data = c->isdbs_ts_id;
+ break;
+ case DTV_DVBT2_PLP_ID:
+ tvp->u.data = c->dvbt2_plp_id;
break;
default:
- r = -1;
+ return -EINVAL;
+ }
+
+ /* Allow the frontend to override outgoing properties */
+ if (fe->ops.get_property) {
+ r = fe->ops.get_property(fe, tvp);
+ if (r < 0)
+ return r;
}
dtv_property_dump(tvp);
- return r;
+ return 0;
}
static int dtv_property_process_set(struct dvb_frontend *fe,
@@ -1338,15 +1348,16 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
struct file *file)
{
int r = 0;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
dtv_property_dump(tvp);
/* Allow the frontend to validate incoming properties */
- if (fe->ops.set_property)
+ if (fe->ops.set_property) {
r = fe->ops.set_property(fe, tvp);
-
- if (r < 0)
- return r;
+ if (r < 0)
+ return r;
+ }
switch(tvp->cmd) {
case DTV_CLEAR:
@@ -1361,126 +1372,129 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
* tunerequest so we can pass validation in the FE_SET_FRONTEND
* ioctl.
*/
- fe->dtv_property_cache.state = tvp->cmd;
+ c->state = tvp->cmd;
dprintk("%s() Finalised property cache\n", __func__);
dtv_property_cache_submit(fe);
- r |= dvb_frontend_ioctl_legacy(file, FE_SET_FRONTEND,
- &fepriv->parameters);
+ r = dvb_frontend_ioctl_legacy(file, FE_SET_FRONTEND,
+ &fepriv->parameters_in);
break;
case DTV_FREQUENCY:
- fe->dtv_property_cache.frequency = tvp->u.data;
+ c->frequency = tvp->u.data;
break;
case DTV_MODULATION:
- fe->dtv_property_cache.modulation = tvp->u.data;
+ c->modulation = tvp->u.data;
break;
case DTV_BANDWIDTH_HZ:
- fe->dtv_property_cache.bandwidth_hz = tvp->u.data;
+ c->bandwidth_hz = tvp->u.data;
break;
case DTV_INVERSION:
- fe->dtv_property_cache.inversion = tvp->u.data;
+ c->inversion = tvp->u.data;
break;
case DTV_SYMBOL_RATE:
- fe->dtv_property_cache.symbol_rate = tvp->u.data;
+ c->symbol_rate = tvp->u.data;
break;
case DTV_INNER_FEC:
- fe->dtv_property_cache.fec_inner = tvp->u.data;
+ c->fec_inner = tvp->u.data;
break;
case DTV_PILOT:
- fe->dtv_property_cache.pilot = tvp->u.data;
+ c->pilot = tvp->u.data;
break;
case DTV_ROLLOFF:
- fe->dtv_property_cache.rolloff = tvp->u.data;
+ c->rolloff = tvp->u.data;
break;
case DTV_DELIVERY_SYSTEM:
- fe->dtv_property_cache.delivery_system = tvp->u.data;
+ c->delivery_system = tvp->u.data;
break;
case DTV_VOLTAGE:
- fe->dtv_property_cache.voltage = tvp->u.data;
+ c->voltage = tvp->u.data;
r = dvb_frontend_ioctl_legacy(file, FE_SET_VOLTAGE,
- (void *)fe->dtv_property_cache.voltage);
+ (void *)c->voltage);
break;
case DTV_TONE:
- fe->dtv_property_cache.sectone = tvp->u.data;
+ c->sectone = tvp->u.data;
r = dvb_frontend_ioctl_legacy(file, FE_SET_TONE,
- (void *)fe->dtv_property_cache.sectone);
+ (void *)c->sectone);
break;
case DTV_CODE_RATE_HP:
- fe->dtv_property_cache.code_rate_HP = tvp->u.data;
+ c->code_rate_HP = tvp->u.data;
break;
case DTV_CODE_RATE_LP:
- fe->dtv_property_cache.code_rate_LP = tvp->u.data;
+ c->code_rate_LP = tvp->u.data;
break;
case DTV_GUARD_INTERVAL:
- fe->dtv_property_cache.guard_interval = tvp->u.data;
+ c->guard_interval = tvp->u.data;
break;
case DTV_TRANSMISSION_MODE:
- fe->dtv_property_cache.transmission_mode = tvp->u.data;
+ c->transmission_mode = tvp->u.data;
break;
case DTV_HIERARCHY:
- fe->dtv_property_cache.hierarchy = tvp->u.data;
+ c->hierarchy = tvp->u.data;
break;
/* ISDB-T Support here */
case DTV_ISDBT_PARTIAL_RECEPTION:
- fe->dtv_property_cache.isdbt_partial_reception = tvp->u.data;
+ c->isdbt_partial_reception = tvp->u.data;
break;
case DTV_ISDBT_SOUND_BROADCASTING:
- fe->dtv_property_cache.isdbt_sb_mode = tvp->u.data;
+ c->isdbt_sb_mode = tvp->u.data;
break;
case DTV_ISDBT_SB_SUBCHANNEL_ID:
- fe->dtv_property_cache.isdbt_sb_subchannel = tvp->u.data;
+ c->isdbt_sb_subchannel = tvp->u.data;
break;
case DTV_ISDBT_SB_SEGMENT_IDX:
- fe->dtv_property_cache.isdbt_sb_segment_idx = tvp->u.data;
+ c->isdbt_sb_segment_idx = tvp->u.data;
break;
case DTV_ISDBT_SB_SEGMENT_COUNT:
- fe->dtv_property_cache.isdbt_sb_segment_count = tvp->u.data;
+ c->isdbt_sb_segment_count = tvp->u.data;
break;
case DTV_ISDBT_LAYER_ENABLED:
- fe->dtv_property_cache.isdbt_layer_enabled = tvp->u.data;
+ c->isdbt_layer_enabled = tvp->u.data;
break;
case DTV_ISDBT_LAYERA_FEC:
- fe->dtv_property_cache.layer[0].fec = tvp->u.data;
+ c->layer[0].fec = tvp->u.data;
break;
case DTV_ISDBT_LAYERA_MODULATION:
- fe->dtv_property_cache.layer[0].modulation = tvp->u.data;
+ c->layer[0].modulation = tvp->u.data;
break;
case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
- fe->dtv_property_cache.layer[0].segment_count = tvp->u.data;
+ c->layer[0].segment_count = tvp->u.data;
break;
case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
- fe->dtv_property_cache.layer[0].interleaving = tvp->u.data;
+ c->layer[0].interleaving = tvp->u.data;
break;
case DTV_ISDBT_LAYERB_FEC:
- fe->dtv_property_cache.layer[1].fec = tvp->u.data;
+ c->layer[1].fec = tvp->u.data;
break;
case DTV_ISDBT_LAYERB_MODULATION:
- fe->dtv_property_cache.layer[1].modulation = tvp->u.data;
+ c->layer[1].modulation = tvp->u.data;
break;
case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
- fe->dtv_property_cache.layer[1].segment_count = tvp->u.data;
+ c->layer[1].segment_count = tvp->u.data;
break;
case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
- fe->dtv_property_cache.layer[1].interleaving = tvp->u.data;
+ c->layer[1].interleaving = tvp->u.data;
break;
case DTV_ISDBT_LAYERC_FEC:
- fe->dtv_property_cache.layer[2].fec = tvp->u.data;
+ c->layer[2].fec = tvp->u.data;
break;
case DTV_ISDBT_LAYERC_MODULATION:
- fe->dtv_property_cache.layer[2].modulation = tvp->u.data;
+ c->layer[2].modulation = tvp->u.data;
break;
case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
- fe->dtv_property_cache.layer[2].segment_count = tvp->u.data;
+ c->layer[2].segment_count = tvp->u.data;
break;
case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
- fe->dtv_property_cache.layer[2].interleaving = tvp->u.data;
+ c->layer[2].interleaving = tvp->u.data;
break;
case DTV_ISDBS_TS_ID:
- fe->dtv_property_cache.isdbs_ts_id = tvp->u.data;
+ c->isdbs_ts_id = tvp->u.data;
+ break;
+ case DTV_DVBT2_PLP_ID:
+ c->dvbt2_plp_id = tvp->u.data;
break;
default:
- r = -1;
+ return -EINVAL;
}
return r;
@@ -1491,6 +1505,7 @@ static int dvb_frontend_ioctl(struct file *file,
{
struct dvb_device *dvbdev = file->private_data;
struct dvb_frontend *fe = dvbdev->priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_frontend_private *fepriv = fe->frontend_priv;
int err = -EOPNOTSUPP;
@@ -1510,7 +1525,7 @@ static int dvb_frontend_ioctl(struct file *file,
if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY))
err = dvb_frontend_ioctl_properties(file, cmd, parg);
else {
- fe->dtv_property_cache.state = DTV_UNDEFINED;
+ c->state = DTV_UNDEFINED;
err = dvb_frontend_ioctl_legacy(file, cmd, parg);
}
@@ -1523,6 +1538,7 @@ static int dvb_frontend_ioctl_properties(struct file *file,
{
struct dvb_device *dvbdev = file->private_data;
struct dvb_frontend *fe = dvbdev->priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int err = 0;
struct dtv_properties *tvps = NULL;
@@ -1554,11 +1570,13 @@ static int dvb_frontend_ioctl_properties(struct file *file,
}
for (i = 0; i < tvps->num; i++) {
- (tvp + i)->result = dtv_property_process_set(fe, tvp + i, file);
- err |= (tvp + i)->result;
+ err = dtv_property_process_set(fe, tvp + i, file);
+ if (err < 0)
+ goto out;
+ (tvp + i)->result = err;
}
- if(fe->dtv_property_cache.state == DTV_TUNE)
+ if (c->state == DTV_TUNE)
dprintk("%s() Property cache is full, tuning\n", __func__);
} else
@@ -1586,8 +1604,10 @@ static int dvb_frontend_ioctl_properties(struct file *file,
}
for (i = 0; i < tvps->num; i++) {
- (tvp + i)->result = dtv_property_process_get(fe, tvp + i, file);
- err |= (tvp + i)->result;
+ err = dtv_property_process_get(fe, tvp + i, file);
+ if (err < 0)
+ goto out;
+ (tvp + i)->result = err;
}
if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) {
@@ -1787,10 +1807,11 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
break;
case FE_SET_FRONTEND: {
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct dvb_frontend_tune_settings fetunesettings;
- if(fe->dtv_property_cache.state == DTV_TUNE) {
- if (dvb_frontend_check_parameters(fe, &fepriv->parameters) < 0) {
+ if (c->state == DTV_TUNE) {
+ if (dvb_frontend_check_parameters(fe, &fepriv->parameters_in) < 0) {
err = -EINVAL;
break;
}
@@ -1800,9 +1821,9 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
break;
}
- memcpy (&fepriv->parameters, parg,
+ memcpy (&fepriv->parameters_in, parg,
sizeof (struct dvb_frontend_parameters));
- dtv_property_cache_sync(fe, &fepriv->parameters);
+ dtv_property_cache_sync(fe, c, &fepriv->parameters_in);
}
memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
@@ -1811,15 +1832,15 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
/* force auto frequency inversion if requested */
if (dvb_force_auto_inversion) {
- fepriv->parameters.inversion = INVERSION_AUTO;
+ fepriv->parameters_in.inversion = INVERSION_AUTO;
fetunesettings.parameters.inversion = INVERSION_AUTO;
}
if (fe->ops.info.type == FE_OFDM) {
/* without hierarchical coding code_rate_LP is irrelevant,
* so we tolerate the otherwise invalid FEC_NONE setting */
- if (fepriv->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
- fepriv->parameters.u.ofdm.code_rate_LP == FEC_NONE)
- fepriv->parameters.u.ofdm.code_rate_LP = FEC_AUTO;
+ if (fepriv->parameters_in.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
+ fepriv->parameters_in.u.ofdm.code_rate_LP == FEC_NONE)
+ fepriv->parameters_in.u.ofdm.code_rate_LP = FEC_AUTO;
}
/* get frontend-specific tuning settings */
@@ -1832,8 +1853,8 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
switch(fe->ops.info.type) {
case FE_QPSK:
fepriv->min_delay = HZ/20;
- fepriv->step_size = fepriv->parameters.u.qpsk.symbol_rate / 16000;
- fepriv->max_drift = fepriv->parameters.u.qpsk.symbol_rate / 2000;
+ fepriv->step_size = fepriv->parameters_in.u.qpsk.symbol_rate / 16000;
+ fepriv->max_drift = fepriv->parameters_in.u.qpsk.symbol_rate / 2000;
break;
case FE_QAM:
@@ -1875,8 +1896,8 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
case FE_GET_FRONTEND:
if (fe->ops.get_frontend) {
- memcpy (parg, &fepriv->parameters, sizeof (struct dvb_frontend_parameters));
- err = fe->ops.get_frontend(fe, (struct dvb_frontend_parameters*) parg);
+ err = fe->ops.get_frontend(fe, &fepriv->parameters_out);
+ memcpy(parg, &fepriv->parameters_out, sizeof(struct dvb_frontend_parameters));
}
break;
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index 3b860504bf04..5590eb6eb408 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -358,6 +358,9 @@ struct dtv_frontend_properties {
/* ISDB-T specifics */
u32 isdbs_ts_id;
+
+ /* DVB-T2 specifics */
+ u32 dvbt2_plp_id;
};
struct dvb_frontend {
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index c545039287ad..e85304c59a2b 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -292,6 +292,11 @@ config DVB_USB_ANYSEE
select DVB_MT352 if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
select DVB_TDA10023 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_TDA18212 if !MEDIA_TUNER_CUSTOMISE
+ select DVB_CX24116 if !DVB_FE_CUSTOMISE
+ select DVB_STV0900 if !DVB_FE_CUSTOMISE
+ select DVB_STV6110 if !DVB_FE_CUSTOMISE
+ select DVB_ISL6423 if !DVB_FE_CUSTOMISE
help
Say Y here to support the Anysee E30, Anysee E30 Plus or
Anysee E30 C Plus DVB USB2.0 receiver.
diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c
index f8e9bf116f21..b95a95e17840 100644
--- a/drivers/media/dvb/dvb-usb/a800.c
+++ b/drivers/media/dvb/dvb-usb/a800.c
@@ -78,17 +78,26 @@ static struct rc_map_table rc_map_a800_table[] = {
static int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
- u8 key[5];
+ int ret;
+ u8 *key = kmalloc(5, GFP_KERNEL);
+ if (!key)
+ return -ENOMEM;
+
if (usb_control_msg(d->udev,usb_rcvctrlpipe(d->udev,0),
0x04, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, key, 5,
- 2000) != 5)
- return -ENODEV;
+ 2000) != 5) {
+ ret = -ENODEV;
+ goto out;
+ }
/* call the universal NEC remote processor, to find out the key's state and event */
dvb_usb_nec_rc_key_to_event(d,key,event,state);
if (key[0] != 0)
deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
- return 0;
+ ret = 0;
+out:
+ kfree(key);
+ return ret;
}
/* USB Driver stuff */
diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c
index 6b402e943539..4dc1ca333236 100644
--- a/drivers/media/dvb/dvb-usb/anysee.c
+++ b/drivers/media/dvb/dvb-usb/anysee.c
@@ -36,6 +36,11 @@
#include "mt352.h"
#include "mt352_priv.h"
#include "zl10353.h"
+#include "tda18212.h"
+#include "cx24116.h"
+#include "stv0900.h"
+#include "stv6110.h"
+#include "isl6423.h"
/* debug */
static int dvb_usb_anysee_debug;
@@ -105,6 +110,27 @@ static int anysee_write_reg(struct dvb_usb_device *d, u16 reg, u8 val)
return anysee_ctrl_msg(d, buf, sizeof(buf), NULL, 0);
}
+/* write single register with mask */
+static int anysee_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val,
+ u8 mask)
+{
+ int ret;
+ u8 tmp;
+
+ /* no need for read if whole reg is written */
+ if (mask != 0xff) {
+ ret = anysee_read_reg(d, reg, &tmp);
+ if (ret)
+ return ret;
+
+ val &= mask;
+ tmp &= ~mask;
+ val |= tmp;
+ }
+
+ return anysee_write_reg(d, reg, val);
+}
+
static int anysee_get_hw_info(struct dvb_usb_device *d, u8 *id)
{
u8 buf[] = {CMD_GET_HW_INFO};
@@ -162,18 +188,18 @@ static int anysee_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
u8 buf[6];
buf[0] = CMD_I2C_READ;
- buf[1] = msg[i].addr + 1;
+ buf[1] = (msg[i].addr << 1) | 0x01;
buf[2] = msg[i].buf[0];
- buf[3] = 0x00;
- buf[4] = 0x00;
- buf[5] = 0x01;
+ buf[3] = msg[i].buf[1];
+ buf[4] = msg[i].len-1;
+ buf[5] = msg[i+1].len;
ret = anysee_ctrl_msg(d, buf, sizeof(buf), msg[i+1].buf,
msg[i+1].len);
inc = 2;
} else {
u8 buf[4+msg[i].len];
buf[0] = CMD_I2C_WRITE;
- buf[1] = msg[i].addr;
+ buf[1] = (msg[i].addr << 1);
buf[2] = msg[i].len;
buf[3] = 0x01;
memcpy(&buf[4], msg[i].buf, msg[i].len);
@@ -224,7 +250,7 @@ static int anysee_mt352_demod_init(struct dvb_frontend *fe)
/* Callbacks for DVB USB */
static struct tda10023_config anysee_tda10023_config = {
- .demod_address = 0x1a,
+ .demod_address = (0x1a >> 1),
.invert = 0,
.xtal = 16000000,
.pll_m = 11,
@@ -235,143 +261,539 @@ static struct tda10023_config anysee_tda10023_config = {
};
static struct mt352_config anysee_mt352_config = {
- .demod_address = 0x1e,
+ .demod_address = (0x1e >> 1),
.demod_init = anysee_mt352_demod_init,
};
static struct zl10353_config anysee_zl10353_config = {
- .demod_address = 0x1e,
+ .demod_address = (0x1e >> 1),
.parallel_ts = 1,
};
+static struct zl10353_config anysee_zl10353_tda18212_config2 = {
+ .demod_address = (0x1e >> 1),
+ .parallel_ts = 1,
+ .disable_i2c_gate_ctrl = 1,
+ .no_tuner = 1,
+ .if2 = 41500,
+};
+
+static struct zl10353_config anysee_zl10353_tda18212_config = {
+ .demod_address = (0x18 >> 1),
+ .parallel_ts = 1,
+ .disable_i2c_gate_ctrl = 1,
+ .no_tuner = 1,
+ .if2 = 41500,
+};
+
+static struct tda10023_config anysee_tda10023_tda18212_config = {
+ .demod_address = (0x1a >> 1),
+ .xtal = 16000000,
+ .pll_m = 12,
+ .pll_p = 3,
+ .pll_n = 1,
+ .output_mode = TDA10023_OUTPUT_MODE_PARALLEL_C,
+ .deltaf = 0xba02,
+};
+
+static struct tda18212_config anysee_tda18212_config = {
+ .i2c_address = (0xc0 >> 1),
+ .if_dvbt_6 = 4150,
+ .if_dvbt_7 = 4150,
+ .if_dvbt_8 = 4150,
+ .if_dvbc = 5000,
+};
+
+static struct cx24116_config anysee_cx24116_config = {
+ .demod_address = (0xaa >> 1),
+ .mpg_clk_pos_pol = 0x00,
+ .i2c_wr_max = 48,
+};
+
+static struct stv0900_config anysee_stv0900_config = {
+ .demod_address = (0xd0 >> 1),
+ .demod_mode = 0,
+ .xtal = 8000000,
+ .clkmode = 3,
+ .diseqc_mode = 2,
+ .tun1_maddress = 0,
+ .tun1_adc = 1, /* 1 Vpp */
+ .path1_mode = 3,
+};
+
+static struct stv6110_config anysee_stv6110_config = {
+ .i2c_address = (0xc0 >> 1),
+ .mclk = 16000000,
+ .clk_div = 1,
+};
+
+static struct isl6423_config anysee_isl6423_config = {
+ .current_max = SEC_CURRENT_800m,
+ .curlim = SEC_CURRENT_LIM_OFF,
+ .mod_extern = 1,
+ .addr = (0x10 >> 1),
+};
+
+/*
+ * New USB device strings: Mfr=1, Product=2, SerialNumber=0
+ * Manufacturer: AMT.CO.KR
+ *
+ * E30 VID=04b4 PID=861f HW=2 FW=2.1 Product=????????
+ * PCB: ?
+ * parts: DNOS404ZH102A(MT352, DTT7579(?))
+ *
+ * E30 VID=04b4 PID=861f HW=2 FW=2.1 Product=????????
+ * PCB: ?
+ * parts: DNOS404ZH103A(ZL10353, DTT7579(?))
+ *
+ * E30 Plus VID=04b4 PID=861f HW=6 FW=1.0 "anysee"
+ * PCB: 507CD (rev1.1)
+ * parts: DNOS404ZH103A(ZL10353, DTT7579(?)), CST56I01
+ * OEA=80 OEB=00 OEC=00 OED=ff OEF=fe
+ * IOA=4f IOB=ff IOC=00 IOD=06 IOF=01
+ * IOD[0] ZL10353 1=enabled
+ * IOA[7] TS 0=enabled
+ * tuner is not behind ZL10353 I2C-gate (no care if gate disabled or not)
+ *
+ * E30 C Plus VID=04b4 PID=861f HW=10 FW=1.0 "anysee-DC(LP)"
+ * PCB: 507DC (rev0.2)
+ * parts: TDA10023, DTOS403IH102B TM, CST56I01
+ * OEA=80 OEB=00 OEC=00 OED=ff OEF=fe
+ * IOA=4f IOB=ff IOC=00 IOD=26 IOF=01
+ * IOD[0] TDA10023 1=enabled
+ *
+ * E30 S2 Plus VID=04b4 PID=861f HW=11 FW=0.1 "anysee-S2(LP)"
+ * PCB: 507SI (rev2.1)
+ * parts: BS2N10WCC01(CX24116, CX24118), ISL6423, TDA8024
+ * OEA=80 OEB=00 OEC=ff OED=ff OEF=fe
+ * IOA=4d IOB=ff IOC=00 IOD=26 IOF=01
+ * IOD[0] CX24116 1=enabled
+ *
+ * E30 C Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)"
+ * PCB: 507FA (rev0.4)
+ * parts: TDA10023, DTOS403IH102B TM, TDA8024
+ * OEA=80 OEB=00 OEC=ff OED=ff OEF=ff
+ * IOA=4d IOB=ff IOC=00 IOD=00 IOF=c0
+ * IOD[5] TDA10023 1=enabled
+ * IOE[0] tuner 1=enabled
+ *
+ * E30 Combo Plus VID=1c73 PID=861f HW=15 FW=1.2 "anysee-FA(LP)"
+ * PCB: 507FA (rev1.1)
+ * parts: ZL10353, TDA10023, DTOS403IH102B TM, TDA8024
+ * OEA=80 OEB=00 OEC=ff OED=ff OEF=ff
+ * IOA=4d IOB=ff IOC=00 IOD=00 IOF=c0
+ * DVB-C:
+ * IOD[5] TDA10023 1=enabled
+ * IOE[0] tuner 1=enabled
+ * DVB-T:
+ * IOD[0] ZL10353 1=enabled
+ * IOE[0] tuner 0=enabled
+ * tuner is behind ZL10353 I2C-gate
+ *
+ * E7 TC VID=1c73 PID=861f HW=18 FW=0.7 AMTCI=0.5 "anysee-E7TC(LP)"
+ * PCB: 508TC (rev0.6)
+ * parts: ZL10353, TDA10023, DNOD44CDH086A(TDA18212)
+ * OEA=80 OEB=00 OEC=03 OED=f7 OEF=ff
+ * IOA=4d IOB=00 IOC=cc IOD=48 IOF=e4
+ * IOA[7] TS 1=enabled
+ * IOE[4] TDA18212 1=enabled
+ * DVB-C:
+ * IOD[6] ZL10353 0=disabled
+ * IOD[5] TDA10023 1=enabled
+ * IOE[0] IF 1=enabled
+ * DVB-T:
+ * IOD[5] TDA10023 0=disabled
+ * IOD[6] ZL10353 1=enabled
+ * IOE[0] IF 0=enabled
+ *
+ * E7 S2 VID=1c73 PID=861f HW=19 FW=0.4 AMTCI=0.5 "anysee-E7S2(LP)"
+ * PCB: 508S2 (rev0.7)
+ * parts: DNBU10512IST(STV0903, STV6110), ISL6423
+ * OEA=80 OEB=00 OEC=03 OED=f7 OEF=ff
+ * IOA=4d IOB=00 IOC=c4 IOD=08 IOF=e4
+ * IOA[7] TS 1=enabled
+ * IOE[5] STV0903 1=enabled
+ *
+ */
+
static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
{
int ret;
struct anysee_state *state = adap->dev->priv;
u8 hw_info[3];
- u8 io_d; /* IO port D */
+ u8 tmp;
+ struct i2c_msg msg[2] = {
+ {
+ .addr = anysee_tda18212_config.i2c_address,
+ .flags = 0,
+ .len = 1,
+ .buf = "\x00",
+ }, {
+ .addr = anysee_tda18212_config.i2c_address,
+ .flags = I2C_M_RD,
+ .len = 1,
+ .buf = &tmp,
+ }
+ };
- /* check which hardware we have
- We must do this call two times to get reliable values (hw bug). */
+ /* Check which hardware we have.
+ * We must do this call two times to get reliable values (hw bug).
+ */
ret = anysee_get_hw_info(adap->dev, hw_info);
if (ret)
- return ret;
+ goto error;
+
ret = anysee_get_hw_info(adap->dev, hw_info);
if (ret)
- return ret;
+ goto error;
/* Meaning of these info bytes are guessed. */
- info("firmware version:%d.%d.%d hardware id:%d",
- 0, hw_info[1], hw_info[2], hw_info[0]);
+ info("firmware version:%d.%d hardware id:%d",
+ hw_info[1], hw_info[2], hw_info[0]);
- ret = anysee_read_reg(adap->dev, 0xb0, &io_d); /* IO port D */
- if (ret)
- return ret;
- deb_info("%s: IO port D:%02x\n", __func__, io_d);
-
- /* Select demod using trial and error method. */
-
- /* Try to attach demodulator in following order:
- model demod hw firmware
- 1. E30 MT352 02 0.2.1
- 2. E30 ZL10353 02 0.2.1
- 3. E30 Combo ZL10353 0f 0.1.2 DVB-T/C combo
- 4. E30 Plus ZL10353 06 0.1.0
- 5. E30C Plus TDA10023 0a 0.1.0 rev 0.2
- E30C Plus TDA10023 0f 0.1.2 rev 0.4
- E30 Combo TDA10023 0f 0.1.2 DVB-T/C combo
- */
-
- /* Zarlink MT352 DVB-T demod inside of Samsung DNOS404ZH102A NIM */
- adap->fe = dvb_attach(mt352_attach, &anysee_mt352_config,
- &adap->dev->i2c_adap);
- if (adap->fe != NULL) {
- state->tuner = DVB_PLL_THOMSON_DTT7579;
- return 0;
- }
+ state->hw = hw_info[0];
- /* Zarlink ZL10353 DVB-T demod inside of Samsung DNOS404ZH103A NIM */
- adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
- &adap->dev->i2c_adap);
- if (adap->fe != NULL) {
- state->tuner = DVB_PLL_THOMSON_DTT7579;
- return 0;
- }
+ switch (state->hw) {
+ case ANYSEE_HW_02: /* 2 */
+ /* E30 */
+
+ /* attach demod */
+ adap->fe = dvb_attach(mt352_attach, &anysee_mt352_config,
+ &adap->dev->i2c_adap);
+ if (adap->fe)
+ break;
+
+ /* attach demod */
+ adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
+ &adap->dev->i2c_adap);
+
+ break;
+ case ANYSEE_HW_507CD: /* 6 */
+ /* E30 Plus */
- /* for E30 Combo Plus DVB-T demodulator */
- if (dvb_usb_anysee_delsys) {
- ret = anysee_write_reg(adap->dev, 0xb0, 0x01);
+ /* enable DVB-T demod on IOD[0] */
+ ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01);
if (ret)
- return ret;
+ goto error;
+
+ /* enable transport stream on IOA[7] */
+ ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (0 << 7), 0x80);
+ if (ret)
+ goto error;
- /* Zarlink ZL10353 DVB-T demod */
+ /* attach demod */
adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
- &adap->dev->i2c_adap);
- if (adap->fe != NULL) {
- state->tuner = DVB_PLL_SAMSUNG_DTOS403IH102A;
- return 0;
+ &adap->dev->i2c_adap);
+
+ break;
+ case ANYSEE_HW_507DC: /* 10 */
+ /* E30 C Plus */
+
+ /* enable DVB-C demod on IOD[0] */
+ ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01);
+ if (ret)
+ goto error;
+
+ /* attach demod */
+ adap->fe = dvb_attach(tda10023_attach, &anysee_tda10023_config,
+ &adap->dev->i2c_adap, 0x48);
+
+ break;
+ case ANYSEE_HW_507SI: /* 11 */
+ /* E30 S2 Plus */
+
+ /* enable DVB-S/S2 demod on IOD[0] */
+ ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01);
+ if (ret)
+ goto error;
+
+ /* attach demod */
+ adap->fe = dvb_attach(cx24116_attach, &anysee_cx24116_config,
+ &adap->dev->i2c_adap);
+
+ break;
+ case ANYSEE_HW_507FA: /* 15 */
+ /* E30 Combo Plus */
+ /* E30 C Plus */
+
+ /* enable tuner on IOE[4] */
+ ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10);
+ if (ret)
+ goto error;
+
+ /* probe TDA18212 */
+ tmp = 0;
+ ret = i2c_transfer(&adap->dev->i2c_adap, msg, 2);
+ if (ret == 2 && tmp == 0xc7)
+ deb_info("%s: TDA18212 found\n", __func__);
+ else
+ tmp = 0;
+
+ /* disable tuner on IOE[4] */
+ ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 4), 0x10);
+ if (ret)
+ goto error;
+
+ if (dvb_usb_anysee_delsys) {
+ /* disable DVB-C demod on IOD[5] */
+ ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
+ 0x20);
+ if (ret)
+ goto error;
+
+ /* enable DVB-T demod on IOD[0] */
+ ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0),
+ 0x01);
+ if (ret)
+ goto error;
+
+ /* attach demod */
+ if (tmp == 0xc7) {
+ /* TDA18212 config */
+ adap->fe = dvb_attach(zl10353_attach,
+ &anysee_zl10353_tda18212_config2,
+ &adap->dev->i2c_adap);
+ } else {
+ /* PLL config */
+ adap->fe = dvb_attach(zl10353_attach,
+ &anysee_zl10353_config,
+ &adap->dev->i2c_adap);
+ }
+ } else {
+ /* disable DVB-T demod on IOD[0] */
+ ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 0),
+ 0x01);
+ if (ret)
+ goto error;
+
+ /* enable DVB-C demod on IOD[5] */
+ ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5),
+ 0x20);
+ if (ret)
+ goto error;
+
+ /* attach demod */
+ if (tmp == 0xc7) {
+ /* TDA18212 config */
+ adap->fe = dvb_attach(tda10023_attach,
+ &anysee_tda10023_tda18212_config,
+ &adap->dev->i2c_adap, 0x48);
+ } else {
+ /* PLL config */
+ adap->fe = dvb_attach(tda10023_attach,
+ &anysee_tda10023_config,
+ &adap->dev->i2c_adap, 0x48);
+ }
}
- }
- /* connect demod on IO port D for TDA10023 & ZL10353 */
- ret = anysee_write_reg(adap->dev, 0xb0, 0x25);
- if (ret)
- return ret;
+ break;
+ case ANYSEE_HW_508TC: /* 18 */
+ /* E7 TC */
- /* Zarlink ZL10353 DVB-T demod inside of Samsung DNOS404ZH103A NIM */
- adap->fe = dvb_attach(zl10353_attach, &anysee_zl10353_config,
- &adap->dev->i2c_adap);
- if (adap->fe != NULL) {
- state->tuner = DVB_PLL_THOMSON_DTT7579;
- return 0;
- }
+ /* enable transport stream on IOA[7] */
+ ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80);
+ if (ret)
+ goto error;
+
+ if (dvb_usb_anysee_delsys) {
+ /* disable DVB-C demod on IOD[5] */
+ ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
+ 0x20);
+ if (ret)
+ goto error;
+
+ /* enable DVB-T demod on IOD[6] */
+ ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 6),
+ 0x40);
+ if (ret)
+ goto error;
+
+ /* enable IF route on IOE[0] */
+ ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0),
+ 0x01);
+ if (ret)
+ goto error;
+
+ /* attach demod */
+ adap->fe = dvb_attach(zl10353_attach,
+ &anysee_zl10353_tda18212_config,
+ &adap->dev->i2c_adap);
+ } else {
+ /* disable DVB-T demod on IOD[6] */
+ ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6),
+ 0x40);
+ if (ret)
+ goto error;
+
+ /* enable DVB-C demod on IOD[5] */
+ ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5),
+ 0x20);
+ if (ret)
+ goto error;
+
+ /* enable IF route on IOE[0] */
+ ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0),
+ 0x01);
+ if (ret)
+ goto error;
+
+ /* attach demod */
+ adap->fe = dvb_attach(tda10023_attach,
+ &anysee_tda10023_tda18212_config,
+ &adap->dev->i2c_adap, 0x48);
+ }
- /* IO port E - E30C rev 0.4 board requires this */
- ret = anysee_write_reg(adap->dev, 0xb1, 0xa7);
- if (ret)
- return ret;
+ break;
+ case ANYSEE_HW_508S2: /* 19 */
+ /* E7 S2 */
- /* Philips TDA10023 DVB-C demod */
- adap->fe = dvb_attach(tda10023_attach, &anysee_tda10023_config,
- &adap->dev->i2c_adap, 0x48);
- if (adap->fe != NULL) {
- state->tuner = DVB_PLL_SAMSUNG_DTOS403IH102A;
- return 0;
- }
+ /* enable transport stream on IOA[7] */
+ ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (1 << 7), 0x80);
+ if (ret)
+ goto error;
- /* return IO port D to init value for safe */
- ret = anysee_write_reg(adap->dev, 0xb0, io_d);
- if (ret)
- return ret;
+ /* enable DVB-S/S2 demod on IOE[5] */
+ ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 5), 0x20);
+ if (ret)
+ goto error;
+
+ /* attach demod */
+ adap->fe = dvb_attach(stv0900_attach, &anysee_stv0900_config,
+ &adap->dev->i2c_adap, 0);
- err("Unknown Anysee version: %02x %02x %02x. "\
- "Please report the <linux-dvb@linuxtv.org>.",
- hw_info[0], hw_info[1], hw_info[2]);
+ break;
+ }
- return -ENODEV;
+ if (!adap->fe) {
+ /* we have no frontend :-( */
+ ret = -ENODEV;
+ err("Unsupported Anysee version. " \
+ "Please report the <linux-media@vger.kernel.org>.");
+ }
+error:
+ return ret;
}
static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
{
struct anysee_state *state = adap->dev->priv;
+ struct dvb_frontend *fe;
+ int ret;
deb_info("%s:\n", __func__);
- switch (state->tuner) {
- case DVB_PLL_THOMSON_DTT7579:
- /* Thomson dtt7579 (not sure) PLL inside of:
- Samsung DNOS404ZH102A NIM
- Samsung DNOS404ZH103A NIM */
- dvb_attach(dvb_pll_attach, adap->fe, 0x61,
- NULL, DVB_PLL_THOMSON_DTT7579);
+ switch (state->hw) {
+ case ANYSEE_HW_02: /* 2 */
+ /* E30 */
+
+ /* attach tuner */
+ fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc2 >> 1),
+ NULL, DVB_PLL_THOMSON_DTT7579);
+
+ break;
+ case ANYSEE_HW_507CD: /* 6 */
+ /* E30 Plus */
+
+ /* attach tuner */
+ fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc2 >> 1),
+ &adap->dev->i2c_adap, DVB_PLL_THOMSON_DTT7579);
+
+ break;
+ case ANYSEE_HW_507DC: /* 10 */
+ /* E30 C Plus */
+
+ /* attach tuner */
+ fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc0 >> 1),
+ &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
+
+ break;
+ case ANYSEE_HW_507SI: /* 11 */
+ /* E30 S2 Plus */
+
+ /* attach LNB controller */
+ fe = dvb_attach(isl6423_attach, adap->fe, &adap->dev->i2c_adap,
+ &anysee_isl6423_config);
+
+ break;
+ case ANYSEE_HW_507FA: /* 15 */
+ /* E30 Combo Plus */
+ /* E30 C Plus */
+
+ if (dvb_usb_anysee_delsys) {
+ /* enable DVB-T tuner on IOE[0] */
+ ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0),
+ 0x01);
+ if (ret)
+ goto error;
+ } else {
+ /* enable DVB-C tuner on IOE[0] */
+ ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0),
+ 0x01);
+ if (ret)
+ goto error;
+ }
+
+ /* Try first attach TDA18212 silicon tuner on IOE[4], if that
+ * fails attach old simple PLL. */
+
+ /* enable tuner on IOE[4] */
+ ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10);
+ if (ret)
+ goto error;
+
+ /* attach tuner */
+ fe = dvb_attach(tda18212_attach, adap->fe, &adap->dev->i2c_adap,
+ &anysee_tda18212_config);
+ if (fe)
+ break;
+
+ /* disable tuner on IOE[4] */
+ ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 4), 0x10);
+ if (ret)
+ goto error;
+
+ /* attach tuner */
+ fe = dvb_attach(dvb_pll_attach, adap->fe, (0xc0 >> 1),
+ &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
+
break;
- case DVB_PLL_SAMSUNG_DTOS403IH102A:
- /* Unknown PLL inside of Samsung DTOS403IH102A tuner module */
- dvb_attach(dvb_pll_attach, adap->fe, 0xc0,
- &adap->dev->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
+ case ANYSEE_HW_508TC: /* 18 */
+ /* E7 TC */
+
+ /* enable tuner on IOE[4] */
+ ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10);
+ if (ret)
+ goto error;
+
+ /* attach tuner */
+ fe = dvb_attach(tda18212_attach, adap->fe, &adap->dev->i2c_adap,
+ &anysee_tda18212_config);
+
break;
+ case ANYSEE_HW_508S2: /* 19 */
+ /* E7 S2 */
+
+ /* attach tuner */
+ fe = dvb_attach(stv6110_attach, adap->fe,
+ &anysee_stv6110_config, &adap->dev->i2c_adap);
+
+ if (fe) {
+ /* attach LNB controller */
+ fe = dvb_attach(isl6423_attach, adap->fe,
+ &adap->dev->i2c_adap, &anysee_isl6423_config);
+ }
+
+ break;
+ default:
+ fe = NULL;
}
- return 0;
+ if (fe)
+ ret = 0;
+ else
+ ret = -ENODEV;
+
+error:
+ return ret;
}
static int anysee_rc_query(struct dvb_usb_device *d)
diff --git a/drivers/media/dvb/dvb-usb/anysee.h b/drivers/media/dvb/dvb-usb/anysee.h
index 7ca01ff6e13c..a7673aa1e007 100644
--- a/drivers/media/dvb/dvb-usb/anysee.h
+++ b/drivers/media/dvb/dvb-usb/anysee.h
@@ -57,10 +57,29 @@ enum cmd {
};
struct anysee_state {
- u8 tuner;
+ u8 hw; /* PCB ID */
u8 seq;
};
+#define ANYSEE_HW_02 2 /* E30 */
+#define ANYSEE_HW_507CD 6 /* E30 Plus */
+#define ANYSEE_HW_507DC 10 /* E30 C Plus */
+#define ANYSEE_HW_507SI 11 /* E30 S2 Plus */
+#define ANYSEE_HW_507FA 15 /* E30 Combo Plus / E30 C Plus */
+#define ANYSEE_HW_508TC 18 /* E7 TC */
+#define ANYSEE_HW_508S2 19 /* E7 S2 */
+
+#define REG_IOA 0x80 /* Port A (bit addressable) */
+#define REG_IOB 0x90 /* Port B (bit addressable) */
+#define REG_IOC 0xa0 /* Port C (bit addressable) */
+#define REG_IOD 0xb0 /* Port D (bit addressable) */
+#define REG_IOE 0xb1 /* Port E (NOT bit addressable) */
+#define REG_OEA 0xb2 /* Port A Output Enable */
+#define REG_OEB 0xb3 /* Port B Output Enable */
+#define REG_OEC 0xb4 /* Port C Output Enable */
+#define REG_OED 0xb5 /* Port D Output Enable */
+#define REG_OEE 0xb6 /* Port E Output Enable */
+
#endif
/***************************************************************************
@@ -136,7 +155,7 @@ General reply packet(s) are always used if not own reply defined.
----------------------------------------------------------------------------
| 04 | 0x00
----------------------------------------------------------------------------
-| 05 | 0x01
+| 05 | data length
----------------------------------------------------------------------------
| 06-59 | don't care
----------------------------------------------------------------------------
diff --git a/drivers/media/dvb/dvb-usb/au6610.c b/drivers/media/dvb/dvb-usb/au6610.c
index eb34cc3894e0..2351077ff2b3 100644
--- a/drivers/media/dvb/dvb-usb/au6610.c
+++ b/drivers/media/dvb/dvb-usb/au6610.c
@@ -33,8 +33,16 @@ static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
{
int ret;
u16 index;
- u8 usb_buf[6]; /* enough for all known requests,
- read returns 5 and write 6 bytes */
+ u8 *usb_buf;
+
+ /*
+ * allocate enough for all known requests,
+ * read returns 5 and write 6 bytes
+ */
+ usb_buf = kmalloc(6, GFP_KERNEL);
+ if (!usb_buf)
+ return -ENOMEM;
+
switch (wlen) {
case 1:
index = wbuf[0] << 8;
@@ -45,14 +53,15 @@ static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
break;
default:
warn("wlen = %x, aborting.", wlen);
- return -EINVAL;
+ ret = -EINVAL;
+ goto error;
}
ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation,
USB_TYPE_VENDOR|USB_DIR_IN, addr << 1, index,
- usb_buf, sizeof(usb_buf), AU6610_USB_TIMEOUT);
+ usb_buf, 6, AU6610_USB_TIMEOUT);
if (ret < 0)
- return ret;
+ goto error;
switch (operation) {
case AU6610_REQ_I2C_READ:
@@ -60,7 +69,8 @@ static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
/* requested value is always 5th byte in buffer */
rbuf[0] = usb_buf[4];
}
-
+error:
+ kfree(usb_buf);
return ret;
}
diff --git a/drivers/media/dvb/dvb-usb/ce6230.c b/drivers/media/dvb/dvb-usb/ce6230.c
index 3df2045b7d2d..6d1a3041540d 100644
--- a/drivers/media/dvb/dvb-usb/ce6230.c
+++ b/drivers/media/dvb/dvb-usb/ce6230.c
@@ -39,7 +39,7 @@ static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req)
u8 requesttype;
u16 value;
u16 index;
- u8 buf[req->data_len];
+ u8 *buf;
request = req->cmd;
value = req->value;
@@ -62,6 +62,12 @@ static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req)
goto error;
}
+ buf = kmalloc(req->data_len, GFP_KERNEL);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
/* write */
memcpy(buf, req->data, req->data_len);
@@ -74,7 +80,7 @@ static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req)
msleep(1); /* avoid I2C errors */
ret = usb_control_msg(udev, pipe, request, requesttype, value, index,
- buf, sizeof(buf), CE6230_USB_TIMEOUT);
+ buf, req->data_len, CE6230_USB_TIMEOUT);
ce6230_debug_dump(request, requesttype, value, index, buf,
req->data_len, deb_xfer);
@@ -88,6 +94,7 @@ static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req)
if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
memcpy(req->data, buf, req->data_len);
+ kfree(buf);
error:
return ret;
}
diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h
index b2a87f2c2c3e..9bd6d51b3b93 100644
--- a/drivers/media/dvb/dvb-usb/dib0700.h
+++ b/drivers/media/dvb/dvb-usb/dib0700.h
@@ -46,8 +46,9 @@ struct dib0700_state {
u8 is_dib7000pc;
u8 fw_use_new_i2c_api;
u8 disable_streaming_master_mode;
- u32 fw_version;
- u32 nb_packet_buffer_size;
+ u32 fw_version;
+ u32 nb_packet_buffer_size;
+ u8 buf[255];
};
extern int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index b79af68c54ae..5eb91b4f8fd0 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -27,19 +27,25 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
u32 *romversion, u32 *ramversion, u32 *fwtype)
{
- u8 b[16];
- int ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
+ struct dib0700_state *st = d->priv;
+ int ret;
+
+ ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
REQUEST_GET_VERSION,
USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
- b, sizeof(b), USB_CTRL_GET_TIMEOUT);
+ st->buf, 16, USB_CTRL_GET_TIMEOUT);
if (hwversion != NULL)
- *hwversion = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
+ *hwversion = (st->buf[0] << 24) | (st->buf[1] << 16) |
+ (st->buf[2] << 8) | st->buf[3];
if (romversion != NULL)
- *romversion = (b[4] << 24) | (b[5] << 16) | (b[6] << 8) | b[7];
+ *romversion = (st->buf[4] << 24) | (st->buf[5] << 16) |
+ (st->buf[6] << 8) | st->buf[7];
if (ramversion != NULL)
- *ramversion = (b[8] << 24) | (b[9] << 16) | (b[10] << 8) | b[11];
+ *ramversion = (st->buf[8] << 24) | (st->buf[9] << 16) |
+ (st->buf[10] << 8) | st->buf[11];
if (fwtype != NULL)
- *fwtype = (b[12] << 24) | (b[13] << 16) | (b[14] << 8) | b[15];
+ *fwtype = (st->buf[12] << 24) | (st->buf[13] << 16) |
+ (st->buf[14] << 8) | st->buf[15];
return ret;
}
@@ -101,24 +107,31 @@ 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, sizeof(buf));
+ struct dib0700_state *st = d->priv;
+ s16 ret;
+
+ st->buf[0] = REQUEST_SET_GPIO;
+ st->buf[1] = gpio;
+ st->buf[2] = ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6);
+
+ ret = dib0700_ctrl_wr(d, st->buf, 3);
+
+ return ret;
}
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;
+ st->buf[0] = REQUEST_SET_USB_XFER_LEN;
+ st->buf[1] = (nb_ts_packets >> 8) & 0xff;
+ st->buf[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));
+ ret = dib0700_ctrl_wr(d, st->buf, 3);
} else {
deb_info("this firmware does not allow to change the USB xfer len\n");
ret = -EIO;
@@ -137,11 +150,11 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
properly support i2c read calls not preceded by a write */
struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ struct dib0700_state *st = d->priv;
uint8_t bus_mode = 1; /* 0=eeprom bus, 1=frontend bus */
uint8_t gen_mode = 0; /* 0=master i2c, 1=gpio i2c */
uint8_t en_start = 0;
uint8_t en_stop = 0;
- uint8_t buf[255]; /* TBV: malloc ? */
int result, i;
/* Ensure nobody else hits the i2c bus while we're sending our
@@ -195,24 +208,24 @@ 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[2] = (en_start << 7) | (en_stop << 6) |
+ st->buf[0] = REQUEST_NEW_I2C_WRITE;
+ st->buf[1] = msg[i].addr << 1;
+ st->buf[2] = (en_start << 7) | (en_stop << 6) |
(msg[i].len & 0x3F);
/* I2C ctrl + FE bus; */
- buf[3] = ((gen_mode << 6) & 0xC0) |
+ st->buf[3] = ((gen_mode << 6) & 0xC0) |
((bus_mode << 4) & 0x30);
/* The Actual i2c payload */
- memcpy(&buf[4], msg[i].buf, msg[i].len);
+ memcpy(&st->buf[4], msg[i].buf, msg[i].len);
deb_data(">>> ");
- debug_dump(buf, msg[i].len + 4, deb_data);
+ debug_dump(st->buf, msg[i].len + 4, deb_data);
result = usb_control_msg(d->udev,
usb_sndctrlpipe(d->udev, 0),
REQUEST_NEW_I2C_WRITE,
USB_TYPE_VENDOR | USB_DIR_OUT,
- 0, 0, buf, msg[i].len + 4,
+ 0, 0, st->buf, msg[i].len + 4,
USB_CTRL_GET_TIMEOUT);
if (result < 0) {
deb_info("i2c write error (status = %d)\n", result);
@@ -231,27 +244,29 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
struct i2c_msg *msg, int num)
{
struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ struct dib0700_state *st = d->priv;
int i,len;
- u8 buf[255];
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
return -EAGAIN;
for (i = 0; i < num; i++) {
/* fill in the address */
- buf[1] = msg[i].addr << 1;
+ st->buf[1] = msg[i].addr << 1;
/* fill the buffer */
- memcpy(&buf[2], msg[i].buf, msg[i].len);
+ memcpy(&st->buf[2], msg[i].buf, msg[i].len);
/* write/read request */
if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
- buf[0] = REQUEST_I2C_READ;
- buf[1] |= 1;
+ st->buf[0] = REQUEST_I2C_READ;
+ st->buf[1] |= 1;
/* special thing in the current firmware: when length is zero the read-failed */
- if ((len = dib0700_ctrl_rd(d, buf, msg[i].len + 2, msg[i+1].buf, msg[i+1].len)) <= 0) {
+ len = dib0700_ctrl_rd(d, st->buf, msg[i].len + 2,
+ msg[i+1].buf, msg[i+1].len);
+ if (len <= 0) {
deb_info("I2C read failed on address 0x%02x\n",
- msg[i].addr);
+ msg[i].addr);
break;
}
@@ -259,13 +274,13 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
i++;
} else {
- buf[0] = REQUEST_I2C_WRITE;
- if (dib0700_ctrl_wr(d, buf, msg[i].len + 2) < 0)
+ st->buf[0] = REQUEST_I2C_WRITE;
+ if (dib0700_ctrl_wr(d, st->buf, msg[i].len + 2) < 0)
break;
}
}
-
mutex_unlock(&d->i2c_mutex);
+
return i;
}
@@ -297,15 +312,23 @@ struct i2c_algorithm dib0700_i2c_algo = {
int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
struct dvb_usb_device_description **desc, int *cold)
{
- u8 b[16];
- s16 ret = usb_control_msg(udev, usb_rcvctrlpipe(udev,0),
+ s16 ret;
+ u8 *b;
+
+ b = kmalloc(16, GFP_KERNEL);
+ if (!b)
+ return -ENOMEM;
+
+
+ ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
REQUEST_GET_VERSION, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, b, 16, USB_CTRL_GET_TIMEOUT);
deb_info("FW GET_VERSION length: %d\n",ret);
*cold = ret <= 0;
-
deb_info("cold: %d\n", *cold);
+
+ kfree(b);
return 0;
}
@@ -313,43 +336,50 @@ static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll,
u8 pll_src, u8 pll_range, u8 clock_gpio3, u16 pll_prediv,
u16 pll_loopdiv, u16 free_div, u16 dsuScaler)
{
- u8 b[10];
- b[0] = REQUEST_SET_CLOCK;
- b[1] = (en_pll << 7) | (pll_src << 6) | (pll_range << 5) | (clock_gpio3 << 4);
- b[2] = (pll_prediv >> 8) & 0xff; // MSB
- b[3] = pll_prediv & 0xff; // LSB
- b[4] = (pll_loopdiv >> 8) & 0xff; // MSB
- b[5] = pll_loopdiv & 0xff; // LSB
- b[6] = (free_div >> 8) & 0xff; // MSB
- b[7] = free_div & 0xff; // LSB
- b[8] = (dsuScaler >> 8) & 0xff; // MSB
- b[9] = dsuScaler & 0xff; // LSB
-
- return dib0700_ctrl_wr(d, b, 10);
+ struct dib0700_state *st = d->priv;
+ s16 ret;
+
+ st->buf[0] = REQUEST_SET_CLOCK;
+ st->buf[1] = (en_pll << 7) | (pll_src << 6) |
+ (pll_range << 5) | (clock_gpio3 << 4);
+ st->buf[2] = (pll_prediv >> 8) & 0xff; /* MSB */
+ st->buf[3] = pll_prediv & 0xff; /* LSB */
+ st->buf[4] = (pll_loopdiv >> 8) & 0xff; /* MSB */
+ st->buf[5] = pll_loopdiv & 0xff; /* LSB */
+ st->buf[6] = (free_div >> 8) & 0xff; /* MSB */
+ st->buf[7] = free_div & 0xff; /* LSB */
+ st->buf[8] = (dsuScaler >> 8) & 0xff; /* MSB */
+ st->buf[9] = dsuScaler & 0xff; /* LSB */
+
+ ret = dib0700_ctrl_wr(d, st->buf, 10);
+
+ return ret;
}
int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz)
{
+ struct dib0700_state *st = d->priv;
u16 divider;
- u8 b[8];
if (scl_kHz == 0)
return -EINVAL;
- b[0] = REQUEST_SET_I2C_PARAM;
+ st->buf[0] = REQUEST_SET_I2C_PARAM;
divider = (u16) (30000 / scl_kHz);
- b[2] = (u8) (divider >> 8);
- b[3] = (u8) (divider & 0xff);
+ st->buf[1] = 0;
+ st->buf[2] = (u8) (divider >> 8);
+ st->buf[3] = (u8) (divider & 0xff);
divider = (u16) (72000 / scl_kHz);
- b[4] = (u8) (divider >> 8);
- b[5] = (u8) (divider & 0xff);
+ st->buf[4] = (u8) (divider >> 8);
+ st->buf[5] = (u8) (divider & 0xff);
divider = (u16) (72000 / scl_kHz); /* clock: 72MHz */
- b[6] = (u8) (divider >> 8);
- b[7] = (u8) (divider & 0xff);
+ st->buf[6] = (u8) (divider >> 8);
+ st->buf[7] = (u8) (divider & 0xff);
deb_info("setting I2C speed: %04x %04x %04x (%d kHz).",
- (b[2] << 8) | (b[3]), (b[4] << 8) | b[5], (b[6] << 8) | b[7], scl_kHz);
- return dib0700_ctrl_wr(d, b, 8);
+ (st->buf[2] << 8) | (st->buf[3]), (st->buf[4] << 8) |
+ st->buf[5], (st->buf[6] << 8) | st->buf[7], scl_kHz);
+ return dib0700_ctrl_wr(d, st->buf, 8);
}
@@ -364,32 +394,45 @@ int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3)
static int dib0700_jumpram(struct usb_device *udev, u32 address)
{
- int ret, actlen;
- u8 buf[8] = { REQUEST_JUMPRAM, 0, 0, 0,
- (address >> 24) & 0xff,
- (address >> 16) & 0xff,
- (address >> 8) & 0xff,
- address & 0xff };
+ int ret = 0, actlen;
+ u8 *buf;
+
+ buf = kmalloc(8, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ buf[0] = REQUEST_JUMPRAM;
+ buf[1] = 0;
+ buf[2] = 0;
+ buf[3] = 0;
+ buf[4] = (address >> 24) & 0xff;
+ buf[5] = (address >> 16) & 0xff;
+ buf[6] = (address >> 8) & 0xff;
+ buf[7] = address & 0xff;
if ((ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x01),buf,8,&actlen,1000)) < 0) {
deb_fw("jumpram to 0x%x failed\n",address);
- return ret;
+ goto out;
}
if (actlen != 8) {
deb_fw("jumpram to 0x%x failed\n",address);
- return -EIO;
+ ret = -EIO;
+ goto out;
}
- return 0;
+out:
+ kfree(buf);
+ return ret;
}
int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw)
{
struct hexline hx;
int pos = 0, ret, act_len, i, adap_num;
- u8 b[16];
+ u8 *buf;
u32 fw_version;
- u8 buf[260];
+ buf = kmalloc(260, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
while ((ret = dvb_usb_get_hexline(fw, &hx, &pos)) > 0) {
deb_fwdata("writing to address 0x%08x (buffer: 0x%02x %02x)\n",
@@ -411,7 +454,7 @@ int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw
if (ret < 0) {
err("firmware download failed at %d with %d",pos,ret);
- return ret;
+ goto out;
}
}
@@ -432,8 +475,8 @@ int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw
usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
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];
+ buf, 16, USB_CTRL_GET_TIMEOUT);
+ fw_version = (buf[8] << 24) | (buf[9] << 16) | (buf[10] << 8) | buf[11];
/* set the buffer size - DVB-USB is allocating URB buffers
* only after the firwmare download was successful */
@@ -451,14 +494,14 @@ int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw
}
}
}
-
+out:
+ kfree(buf);
return ret;
}
int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
struct dib0700_state *st = adap->dev->priv;
- u8 b[4];
int ret;
if ((onoff != 0) && (st->fw_version >= 0x10201)) {
@@ -472,15 +515,17 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
}
}
- b[0] = REQUEST_ENABLE_VIDEO;
- b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */
+ st->buf[0] = REQUEST_ENABLE_VIDEO;
+ /* this bit gives a kind of command,
+ * rather than enabling something or not */
+ st->buf[1] = (onoff << 4) | 0x00;
if (st->disable_streaming_master_mode == 1)
- b[2] = 0x00;
+ st->buf[2] = 0x00;
else
- b[2] = 0x01 << 4; /* Master mode */
+ st->buf[2] = 0x01 << 4; /* Master mode */
- b[3] = 0x00;
+ st->buf[3] = 0x00;
deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id);
@@ -499,20 +544,23 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
st->channel_state |= 1 << (3-adap->stream.props.endpoint);
}
- b[2] |= st->channel_state;
+ st->buf[2] |= st->channel_state;
- deb_info("data for streaming: %x %x\n", b[1], b[2]);
+ deb_info("data for streaming: %x %x\n", st->buf[1], st->buf[2]);
- return dib0700_ctrl_wr(adap->dev, b, 4);
+ return dib0700_ctrl_wr(adap->dev, st->buf, 4);
}
int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
{
struct dvb_usb_device *d = rc->priv;
struct dib0700_state *st = d->priv;
- u8 rc_setup[3] = { REQUEST_SET_RC, 0, 0 };
int new_proto, ret;
+ st->buf[0] = REQUEST_SET_RC;
+ st->buf[1] = 0;
+ st->buf[2] = 0;
+
/* Set the IR mode */
if (rc_type == RC_TYPE_RC5)
new_proto = 1;
@@ -526,9 +574,9 @@ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
} else
return -EINVAL;
- rc_setup[1] = new_proto;
+ st->buf[1] = new_proto;
- ret = dib0700_ctrl_wr(d, rc_setup, sizeof(rc_setup));
+ ret = dib0700_ctrl_wr(d, st->buf, 3);
if (ret < 0) {
err("ir protocol setup failed");
return ret;
@@ -561,7 +609,6 @@ struct dib0700_rc_response {
static void dib0700_rc_urb_completion(struct urb *purb)
{
struct dvb_usb_device *d = purb->context;
- struct dib0700_state *st;
struct dib0700_rc_response *poll_reply;
u32 uninitialized_var(keycode);
u8 toggle;
@@ -576,7 +623,6 @@ static void dib0700_rc_urb_completion(struct urb *purb)
return;
}
- st = d->priv;
poll_reply = purb->transfer_buffer;
if (purb->status < 0) {
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index 65214af5cd74..c519ad5eb731 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -2439,7 +2439,6 @@ static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap)
dib0700_set_i2c_speed(adap->dev, 340);
adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]);
-
if (adap->fe == NULL)
return -ENODEV;
@@ -2802,6 +2801,7 @@ struct usb_device_id dib0700_usb_id_table[] = {
{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_NIM7090) },
{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_TFE7090PVR) },
{ USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2) },
+/* 75 */{ USB_DEVICE(USB_VID_MEDION, USB_PID_CREATIX_CTX1921) },
{ 0 } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -3411,7 +3411,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
},
},
- .num_device_descs = 3,
+ .num_device_descs = 4,
.devices = {
{ "DiBcom STK7770P reference design",
{ &dib0700_usb_id_table[59], NULL },
@@ -3427,6 +3427,10 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ &dib0700_usb_id_table[74], NULL },
{ NULL },
},
+ { "Medion CTX1921 DVB-T USB",
+ { &dib0700_usb_id_table[75], NULL },
+ { NULL },
+ },
},
.rc.core = {
diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c
index 956f7ae2e510..4c2a689c820e 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-common.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-common.c
@@ -408,7 +408,7 @@ struct rc_map_table rc_map_dibusb_table[] = {
{ 0x8008, KEY_DVD },
{ 0x8009, KEY_AUDIO },
- { 0x800a, KEY_MEDIA }, /* Pictures */
+ { 0x800a, KEY_IMAGES }, /* Pictures */
{ 0x800b, KEY_VIDEO },
{ 0x800c, KEY_BACK },
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
index df1ec3e69f4a..b3cb626ed56e 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
@@ -12,7 +12,7 @@
static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
{
struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv;
- int newfeedcount,ret;
+ int newfeedcount, ret;
if (adap == NULL)
return -ENODEV;
@@ -24,9 +24,13 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
deb_ts("stop feeding\n");
usb_urb_kill(&adap->stream);
- if (adap->props.streaming_ctrl != NULL)
- if ((ret = adap->props.streaming_ctrl(adap,0)))
+ if (adap->props.streaming_ctrl != NULL) {
+ ret = adap->props.streaming_ctrl(adap, 0);
+ if (ret < 0) {
err("error while stopping stream.");
+ return ret;
+ }
+ }
}
adap->feedcount = newfeedcount;
@@ -49,17 +53,24 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
deb_ts("controlling pid parser\n");
if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER &&
- adap->props.caps & DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF &&
- adap->props.pid_filter_ctrl != NULL)
- if (adap->props.pid_filter_ctrl(adap,adap->pid_filtering) < 0)
+ adap->props.caps &
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF &&
+ adap->props.pid_filter_ctrl != NULL) {
+ ret = adap->props.pid_filter_ctrl(adap,
+ adap->pid_filtering);
+ if (ret < 0) {
err("could not handle pid_parser");
-
+ return ret;
+ }
+ }
deb_ts("start feeding\n");
- if (adap->props.streaming_ctrl != NULL)
- if (adap->props.streaming_ctrl(adap,1)) {
+ if (adap->props.streaming_ctrl != NULL) {
+ ret = adap->props.streaming_ctrl(adap, 1);
+ if (ret < 0) {
err("error while enabling fifo.");
- return -ENODEV;
+ return ret;
}
+ }
}
return 0;
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 3a8b7446b7b0..21b15495d2d7 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -91,6 +91,7 @@
#define USB_PID_COMPRO_VIDEOMATE_U500_PC 0x1e80
#define USB_PID_CONCEPTRONIC_CTVDIGRCU 0xe397
#define USB_PID_CONEXANT_D680_DMB 0x86d6
+#define USB_PID_CREATIX_CTX1921 0x1921
#define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064
#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065
#define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8
diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c
index f5b9da18f611..058b2318abed 100644
--- a/drivers/media/dvb/dvb-usb/dw2102.c
+++ b/drivers/media/dvb/dvb-usb/dw2102.c
@@ -121,12 +121,16 @@ static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
u16 index, u8 * data, u16 len, int flags)
{
int ret;
- u8 u8buf[len];
-
+ u8 *u8buf;
unsigned int pipe = (flags == DW210X_READ_MSG) ?
usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0);
u8 request_type = (flags == DW210X_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
+ u8buf = kmalloc(len, GFP_KERNEL);
+ if (!u8buf)
+ return -ENOMEM;
+
+
if (flags == DW210X_WRITE_MSG)
memcpy(u8buf, data, len);
ret = usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR,
@@ -134,6 +138,8 @@ static int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
if (flags == DW210X_READ_MSG)
memcpy(data, u8buf, len);
+
+ kfree(u8buf);
return ret;
}
@@ -1377,7 +1383,7 @@ static struct rc_map_table rc_map_su3000_table[] = {
{ 0x0f, KEY_BLUE }, /* bottom yellow button */
{ 0x14, KEY_AUDIO }, /* Snapshot */
{ 0x38, KEY_TV }, /* TV/Radio */
- { 0x0c, KEY_ESC } /* upper Red buttton */
+ { 0x0c, KEY_ESC } /* upper Red button */
};
static struct rc_map_dvb_usb_table_table keys_tables[] = {
diff --git a/drivers/media/dvb/dvb-usb/ec168.c b/drivers/media/dvb/dvb-usb/ec168.c
index 52f5d4f0f230..1ba3e5dbee10 100644
--- a/drivers/media/dvb/dvb-usb/ec168.c
+++ b/drivers/media/dvb/dvb-usb/ec168.c
@@ -36,7 +36,9 @@ static int ec168_rw_udev(struct usb_device *udev, struct ec168_req *req)
int ret;
unsigned int pipe;
u8 request, requesttype;
- u8 buf[req->size];
+ u8 *buf;
+
+
switch (req->cmd) {
case DOWNLOAD_FIRMWARE:
@@ -72,6 +74,12 @@ static int ec168_rw_udev(struct usb_device *udev, struct ec168_req *req)
goto error;
}
+ buf = kmalloc(req->size, GFP_KERNEL);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
/* write */
memcpy(buf, req->data, req->size);
@@ -84,13 +92,13 @@ static int ec168_rw_udev(struct usb_device *udev, struct ec168_req *req)
msleep(1); /* avoid I2C errors */
ret = usb_control_msg(udev, pipe, request, requesttype, req->value,
- req->index, buf, sizeof(buf), EC168_USB_TIMEOUT);
+ req->index, buf, req->size, EC168_USB_TIMEOUT);
ec168_debug_dump(request, requesttype, req->value, req->index, buf,
req->size, deb_xfer);
if (ret < 0)
- goto error;
+ goto err_dealloc;
else
ret = 0;
@@ -98,7 +106,11 @@ static int ec168_rw_udev(struct usb_device *udev, struct ec168_req *req)
if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
memcpy(req->data, buf, req->size);
+ kfree(buf);
return ret;
+
+err_dealloc:
+ kfree(buf);
error:
deb_info("%s: failed:%d\n", __func__, ret);
return ret;
diff --git a/drivers/media/dvb/dvb-usb/friio.c b/drivers/media/dvb/dvb-usb/friio.c
index 14a65b4aec07..76159aed9bb0 100644
--- a/drivers/media/dvb/dvb-usb/friio.c
+++ b/drivers/media/dvb/dvb-usb/friio.c
@@ -142,17 +142,20 @@ static u32 gl861_i2c_func(struct i2c_adapter *adapter)
return I2C_FUNC_I2C;
}
-
static int friio_ext_ctl(struct dvb_usb_adapter *adap,
u32 sat_color, int lnb_on)
{
int i;
int ret;
struct i2c_msg msg;
- u8 buf[2];
+ u8 *buf;
u32 mask;
u8 lnb = (lnb_on) ? FRIIO_CTL_LNB : 0;
+ buf = kmalloc(2, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
msg.addr = 0x00;
msg.flags = 0;
msg.len = 2;
@@ -189,6 +192,7 @@ static int friio_ext_ctl(struct dvb_usb_adapter *adap,
buf[1] |= FRIIO_CTL_CLK;
ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
+ kfree(buf);
return (ret == 70);
}
@@ -219,11 +223,20 @@ static int friio_initialize(struct dvb_usb_device *d)
int ret;
int i;
int retry = 0;
- u8 rbuf[2];
- u8 wbuf[3];
+ u8 *rbuf, *wbuf;
deb_info("%s called.\n", __func__);
+ wbuf = kmalloc(3, GFP_KERNEL);
+ if (!wbuf)
+ return -ENOMEM;
+
+ rbuf = kmalloc(2, GFP_KERNEL);
+ if (!rbuf) {
+ kfree(wbuf);
+ return -ENOMEM;
+ }
+
/* use gl861_i2c_msg instead of gl861_i2c_xfer(), */
/* because the i2c device is not set up yet. */
wbuf[0] = 0x11;
@@ -358,6 +371,8 @@ restart:
return 0;
error:
+ kfree(wbuf);
+ kfree(rbuf);
deb_info("%s:ret == %d\n", __func__, ret);
return -EIO;
}
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c
index f2db01212ca1..37b146961ae2 100644
--- a/drivers/media/dvb/dvb-usb/lmedm04.c
+++ b/drivers/media/dvb/dvb-usb/lmedm04.c
@@ -62,8 +62,6 @@
* LME2510: SHARP:BS2F7HZ0194(MV0194) cannot cold reset and share system
* with other tuners. After a cold reset streaming will not start.
*
- * PID functions have been removed from this driver version due to
- * problems with different firmware and application versions.
*/
#define DVB_USB_LOG_PREFIX "LME2510(C)"
#include <linux/usb.h>
@@ -104,6 +102,10 @@ static int dvb_usb_lme2510_firmware;
module_param_named(firmware, dvb_usb_lme2510_firmware, int, 0644);
MODULE_PARM_DESC(firmware, "set default firmware 0=Sharp7395 1=LG");
+static int pid_filter;
+module_param_named(pid, pid_filter, int, 0644);
+MODULE_PARM_DESC(pid, "set default 0=on 1=off");
+
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
@@ -125,6 +127,7 @@ struct lme2510_state {
u8 i2c_tuner_gate_r;
u8 i2c_tuner_addr;
u8 stream_on;
+ u8 pid_size;
void *buffer;
struct urb *lme_urb;
void *usb_buffer;
@@ -167,14 +170,14 @@ static int lme2510_usb_talk(struct dvb_usb_device *d,
}
buff = st->usb_buffer;
- /* the read/write capped at 512 */
- memcpy(buff, wbuf, (wlen > 512) ? 512 : wlen);
-
ret = mutex_lock_interruptible(&d->usb_mutex);
if (ret < 0)
return -EAGAIN;
+ /* the read/write capped at 512 */
+ memcpy(buff, wbuf, (wlen > 512) ? 512 : wlen);
+
ret |= usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, 0x01));
ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01);
@@ -204,16 +207,36 @@ static int lme2510_stream_restart(struct dvb_usb_device *d)
rbuff, sizeof(rbuff));
return ret;
}
-static int lme2510_remote_keypress(struct dvb_usb_adapter *adap, u32 keypress)
+
+static int lme2510_enable_pid(struct dvb_usb_device *d, u8 index, u16 pid_out)
{
- struct dvb_usb_device *d = adap->dev;
+ struct lme2510_state *st = d->priv;
+ static u8 pid_buff[] = LME_ZERO_PID;
+ static u8 rbuf[1];
+ u8 pid_no = index * 2;
+ u8 pid_len = pid_no + 2;
+ int ret = 0;
+ deb_info(1, "PID Setting Pid %04x", pid_out);
- deb_info(1, "INT Key Keypress =%04x", keypress);
+ if (st->pid_size == 0)
+ ret |= lme2510_stream_restart(d);
- if (keypress > 0)
- rc_keydown(d->rc_dev, keypress, 0);
+ pid_buff[2] = pid_no;
+ pid_buff[3] = (u8)pid_out & 0xff;
+ pid_buff[4] = pid_no + 1;
+ pid_buff[5] = (u8)(pid_out >> 8);
- return 0;
+ if (pid_len > st->pid_size)
+ st->pid_size = pid_len;
+ pid_buff[7] = 0x80 + st->pid_size;
+
+ ret |= lme2510_usb_talk(d, pid_buff ,
+ sizeof(pid_buff) , rbuf, sizeof(rbuf));
+
+ if (st->stream_on)
+ ret |= lme2510_stream_restart(d);
+
+ return ret;
}
static void lme2510_int_response(struct urb *lme_urb)
@@ -222,6 +245,7 @@ static void lme2510_int_response(struct urb *lme_urb)
struct lme2510_state *st = adap->dev->priv;
static u8 *ibuf, *rbuf;
int i = 0, offset;
+ u32 key;
switch (lme_urb->status) {
case 0:
@@ -248,10 +272,16 @@ static void lme2510_int_response(struct urb *lme_urb)
switch (ibuf[0]) {
case 0xaa:
- debug_data_snipet(1, "INT Remote data snipet in", ibuf);
- lme2510_remote_keypress(adap,
- (u32)(ibuf[2] << 24) + (ibuf[3] << 16) +
- (ibuf[4] << 8) + ibuf[5]);
+ debug_data_snipet(1, "INT Remote data snipet", ibuf);
+ if ((ibuf[4] + ibuf[5]) == 0xff) {
+ key = ibuf[5];
+ key += (ibuf[3] > 0)
+ ? (ibuf[3] ^ 0xff) << 8 : 0;
+ key += (ibuf[2] ^ 0xff) << 16;
+ deb_info(1, "INT Key =%08x", key);
+ if (adap->dev->rc_dev != NULL)
+ rc_keydown(adap->dev->rc_dev, key, 0);
+ }
break;
case 0xbb:
switch (st->tuner_config) {
@@ -326,16 +356,68 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap)
return 0;
}
+static int lme2510_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+ struct lme2510_state *st = adap->dev->priv;
+ static u8 clear_pid_reg[] = LME_CLEAR_PID;
+ static u8 rbuf[1];
+ int ret;
+
+ deb_info(1, "PID Clearing Filter");
+
+ ret = mutex_lock_interruptible(&adap->dev->i2c_mutex);
+ if (ret < 0)
+ return -EAGAIN;
+
+ if (!onoff)
+ ret |= lme2510_usb_talk(adap->dev, clear_pid_reg,
+ sizeof(clear_pid_reg), rbuf, sizeof(rbuf));
+
+ st->pid_size = 0;
+
+ mutex_unlock(&adap->dev->i2c_mutex);
+
+ return 0;
+}
+
+static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
+ int onoff)
+{
+ int ret = 0;
+
+ deb_info(3, "%s PID=%04x Index=%04x onoff=%02x", __func__,
+ pid, index, onoff);
+
+ if (onoff)
+ if (!pid_filter) {
+ ret = mutex_lock_interruptible(&adap->dev->i2c_mutex);
+ if (ret < 0)
+ return -EAGAIN;
+ ret |= lme2510_enable_pid(adap->dev, index, pid);
+ mutex_unlock(&adap->dev->i2c_mutex);
+ }
+
+
+ return ret;
+}
+
+
static int lme2510_return_status(struct usb_device *dev)
{
int ret = 0;
- u8 data[10] = {0};
+ u8 *data;
+
+ data = kzalloc(10, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
ret |= usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200);
info("Firmware Status: %x (%x)", ret , data[2]);
- return (ret < 0) ? -ENODEV : data[2];
+ ret = (ret < 0) ? -ENODEV : data[2];
+ kfree(data);
+ return ret;
}
static int lme2510_msg(struct dvb_usb_device *d,
@@ -591,9 +673,10 @@ static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
else {
deb_info(1, "STM Steam Off");
/* mutex is here only to avoid collision with I2C */
- ret = mutex_lock_interruptible(&adap->dev->i2c_mutex);
+ if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
+ return -EAGAIN;
- ret |= lme2510_usb_talk(adap->dev, clear_reg_3,
+ ret = lme2510_usb_talk(adap->dev, clear_reg_3,
sizeof(clear_reg_3), rbuf, rlen);
st->stream_on = 0;
st->i2c_talk_onoff = 1;
@@ -604,45 +687,6 @@ static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
return (ret < 0) ? -ENODEV : 0;
}
-static int lme2510_int_service(struct dvb_usb_adapter *adap)
-{
- struct dvb_usb_device *d = adap->dev;
- struct rc_dev *rc;
- int ret;
-
- info("STA Configuring Remote");
-
- rc = rc_allocate_device();
- if (!rc)
- return -ENOMEM;
-
- usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
- strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
-
- rc->input_name = "LME2510 Remote Control";
- rc->input_phys = d->rc_phys;
- rc->map_name = RC_MAP_LME2510;
- rc->driver_name = "LME 2510";
- usb_to_input_id(d->udev, &rc->input_id);
-
- ret = rc_register_device(rc);
- if (ret) {
- rc_free_device(rc);
- return ret;
- }
- d->rc_dev = rc;
-
- /* Start the Interrupt */
- ret = lme2510_int_read(adap);
- if (ret < 0) {
- rc_unregister_device(rc);
- info("INT Unable to start Interrupt Service");
- return -ENODEV;
- }
-
- return 0;
-}
-
static u8 check_sum(u8 *p, u8 len)
{
u8 sum = 0;
@@ -655,7 +699,7 @@ static int lme2510_download_firmware(struct usb_device *dev,
const struct firmware *fw)
{
int ret = 0;
- u8 data[512] = {0};
+ u8 *data;
u16 j, wlen, len_in, start, end;
u8 packet_size, dlen, i;
u8 *fw_data;
@@ -663,6 +707,11 @@ static int lme2510_download_firmware(struct usb_device *dev,
packet_size = 0x31;
len_in = 1;
+ data = kzalloc(512, GFP_KERNEL);
+ if (!data) {
+ info("FRM Could not start Firmware Download (Buffer allocation failed)");
+ return -ENOMEM;
+ }
info("FRM Starting Firmware Download");
@@ -678,15 +727,15 @@ static int lme2510_download_firmware(struct usb_device *dev,
data[0] = i | 0x80;
dlen = (u8)(end - j)-1;
}
- data[1] = dlen;
- memcpy(&data[2], fw_data, dlen+1);
- wlen = (u8) dlen + 4;
- data[wlen-1] = check_sum(fw_data, dlen+1);
- deb_info(1, "Data S=%02x:E=%02x CS= %02x", data[3],
+ data[1] = dlen;
+ memcpy(&data[2], fw_data, dlen+1);
+ wlen = (u8) dlen + 4;
+ data[wlen-1] = check_sum(fw_data, dlen+1);
+ deb_info(1, "Data S=%02x:E=%02x CS= %02x", data[3],
data[dlen+2], data[dlen+3]);
- ret |= lme2510_bulk_write(dev, data, wlen, 1);
- ret |= lme2510_bulk_read(dev, data, len_in , 1);
- ret |= (data[0] == 0x88) ? 0 : -1;
+ ret |= lme2510_bulk_write(dev, data, wlen, 1);
+ ret |= lme2510_bulk_read(dev, data, len_in , 1);
+ ret |= (data[0] == 0x88) ? 0 : -1;
}
}
@@ -706,7 +755,7 @@ static int lme2510_download_firmware(struct usb_device *dev,
else
info("FRM Firmware Download Completed - Resetting Device");
-
+ kfree(data);
return (ret < 0) ? -ENODEV : 0;
}
@@ -739,7 +788,7 @@ static int lme_firmware_switch(struct usb_device *udev, int cold)
cold_fw = !cold;
- if (udev->descriptor.idProduct == 0x1122) {
+ if (le16_to_cpu(udev->descriptor.idProduct) == 0x1122) {
switch (dvb_usb_lme2510_firmware) {
default:
dvb_usb_lme2510_firmware = TUNER_S0194;
@@ -747,7 +796,7 @@ static int lme_firmware_switch(struct usb_device *udev, int cold)
fw_lme = fw_s0194;
ret = request_firmware(&fw, fw_lme, &udev->dev);
if (ret == 0) {
- cold = 0;/*lme2510-s0194 cannot cold reset*/
+ cold = 0;
break;
}
dvb_usb_lme2510_firmware = TUNER_LG;
@@ -769,8 +818,10 @@ static int lme_firmware_switch(struct usb_device *udev, int cold)
case TUNER_S7395:
fw_lme = fw_c_s7395;
ret = request_firmware(&fw, fw_lme, &udev->dev);
- if (ret == 0)
+ if (ret == 0) {
+ cold = 0;
break;
+ }
dvb_usb_lme2510_firmware = TUNER_LG;
case TUNER_LG:
fw_lme = fw_c_lg;
@@ -796,14 +847,14 @@ static int lme_firmware_switch(struct usb_device *udev, int cold)
ret = lme2510_download_firmware(udev, fw);
}
+ release_firmware(fw);
+
if (cold) {
info("FRM Changing to %s firmware", fw_lme);
lme_coldreset(udev);
return -ENODEV;
}
- release_firmware(fw);
-
return ret;
}
@@ -959,8 +1010,11 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
end: if (ret) {
- kfree(adap->fe);
- adap->fe = NULL;
+ if (adap->fe) {
+ dvb_frontend_detach(adap->fe);
+ adap->fe = NULL;
+ }
+ adap->dev->props.rc.core.rc_codes = NULL;
return -ENODEV;
}
@@ -1003,8 +1057,12 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
return -ENODEV;
}
- /* Start the Interrupt & Remote*/
- ret = lme2510_int_service(adap);
+ /* Start the Interrupt*/
+ ret = lme2510_int_read(adap);
+ if (ret < 0) {
+ info("INT Unable to start Interrupt Service");
+ return -ENODEV;
+ }
return ret;
}
@@ -1017,12 +1075,13 @@ static int lme2510_powerup(struct dvb_usb_device *d, int onoff)
static u8 rbuf[1];
int ret, len = 3, rlen = 1;
- ret = mutex_lock_interruptible(&d->i2c_mutex);
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
if (onoff)
- ret |= lme2510_usb_talk(d, lnb_on, len, rbuf, rlen);
+ ret = lme2510_usb_talk(d, lnb_on, len, rbuf, rlen);
else
- ret |= lme2510_usb_talk(d, lnb_off, len, rbuf, rlen);
+ ret = lme2510_usb_talk(d, lnb_off, len, rbuf, rlen);
st->i2c_talk_onoff = 1;
@@ -1086,7 +1145,13 @@ static struct dvb_usb_device_properties lme2510_properties = {
.num_adapters = 1,
.adapter = {
{
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER|
+ DVB_USB_ADAP_NEED_PID_FILTERING|
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
.streaming_ctrl = lme2510_streaming_ctrl,
+ .pid_filter_count = 15,
+ .pid_filter = lme2510_pid_filter,
+ .pid_filter_ctrl = lme2510_pid_filter_ctrl,
.frontend_attach = dm04_lme2510_frontend_attach,
.tuner_attach = dm04_lme2510_tuner,
/* parameter for the MPEG2-data transfer */
@@ -1103,6 +1168,12 @@ static struct dvb_usb_device_properties lme2510_properties = {
}
}
},
+ .rc.core = {
+ .protocol = RC_TYPE_NEC,
+ .module_name = "LME2510 Remote Control",
+ .allowed_protos = RC_TYPE_NEC,
+ .rc_codes = RC_MAP_LME2510,
+ },
.power_ctrl = lme2510_powerup,
.identify_state = lme2510_identify_state,
.i2c_algo = &lme2510_i2c_algo,
@@ -1122,7 +1193,13 @@ static struct dvb_usb_device_properties lme2510c_properties = {
.num_adapters = 1,
.adapter = {
{
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER|
+ DVB_USB_ADAP_NEED_PID_FILTERING|
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
.streaming_ctrl = lme2510_streaming_ctrl,
+ .pid_filter_count = 15,
+ .pid_filter = lme2510_pid_filter,
+ .pid_filter_ctrl = lme2510_pid_filter_ctrl,
.frontend_attach = dm04_lme2510_frontend_attach,
.tuner_attach = dm04_lme2510_tuner,
/* parameter for the MPEG2-data transfer */
@@ -1139,6 +1216,12 @@ static struct dvb_usb_device_properties lme2510c_properties = {
}
}
},
+ .rc.core = {
+ .protocol = RC_TYPE_NEC,
+ .module_name = "LME2510 Remote Control",
+ .allowed_protos = RC_TYPE_NEC,
+ .rc_codes = RC_MAP_LME2510,
+ },
.power_ctrl = lme2510_powerup,
.identify_state = lme2510_identify_state,
.i2c_algo = &lme2510_i2c_algo,
@@ -1151,7 +1234,7 @@ static struct dvb_usb_device_properties lme2510c_properties = {
}
};
-void *lme2510_exit_int(struct dvb_usb_device *d)
+static void *lme2510_exit_int(struct dvb_usb_device *d)
{
struct lme2510_state *st = d->priv;
struct dvb_usb_adapter *adap = &d->adapter[0];
@@ -1162,23 +1245,25 @@ void *lme2510_exit_int(struct dvb_usb_device *d)
adap->feedcount = 0;
}
- if (st->lme_urb != NULL) {
+ if (st->usb_buffer != NULL) {
st->i2c_talk_onoff = 1;
st->signal_lock = 0;
st->signal_level = 0;
st->signal_sn = 0;
buffer = st->usb_buffer;
+ }
+
+ if (st->lme_urb != NULL) {
usb_kill_urb(st->lme_urb);
usb_free_coherent(d->udev, 5000, st->buffer,
st->lme_urb->transfer_dma);
info("Interrupt Service Stopped");
- rc_unregister_device(d->rc_dev);
- info("Remote Stopped");
}
+
return buffer;
}
-void lme2510_exit(struct usb_interface *intf)
+static void lme2510_exit(struct usb_interface *intf)
{
struct dvb_usb_device *d = usb_get_intfdata(intf);
void *usb_buffer;
@@ -1186,7 +1271,8 @@ void lme2510_exit(struct usb_interface *intf)
if (d != NULL) {
usb_buffer = lme2510_exit_int(d);
dvb_usb_device_exit(intf);
- kfree(usb_buffer);
+ if (usb_buffer != NULL)
+ kfree(usb_buffer);
}
}
@@ -1220,5 +1306,5 @@ module_exit(lme2510_module_exit);
MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0");
-MODULE_VERSION("1.80");
+MODULE_VERSION("1.88");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.h b/drivers/media/dvb/dvb-usb/lmedm04.h
index e6af16c1e3e5..ab21e2ef53fa 100644
--- a/drivers/media/dvb/dvb-usb/lmedm04.h
+++ b/drivers/media/dvb/dvb-usb/lmedm04.h
@@ -40,6 +40,7 @@
*/
#define LME_ST_ON_W {0x06, 0x00}
#define LME_CLEAR_PID {0x03, 0x02, 0x20, 0xa0}
+#define LME_ZERO_PID {0x03, 0x06, 0x00, 0x00, 0x01, 0x00, 0x20, 0x9c}
/* LNB Voltage
* 07 XX XX
@@ -108,14 +109,14 @@ static u8 s7395_inittab[] = {
0x3d, 0x30,
0x40, 0x63,
0x41, 0x04,
- 0x42, 0x60,
+ 0x42, 0x20,
0x43, 0x00,
0x44, 0x00,
0x45, 0x00,
0x46, 0x00,
0x47, 0x00,
0x4a, 0x00,
- 0x50, 0x12,
+ 0x50, 0x10,
0x51, 0x36,
0x52, 0x21,
0x53, 0x94,
diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c
index da9dc91ce910..9456792f219b 100644
--- a/drivers/media/dvb/dvb-usb/m920x.c
+++ b/drivers/media/dvb/dvb-usb/m920x.c
@@ -134,13 +134,17 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
struct m920x_state *m = d->priv;
int i, ret = 0;
- u8 rc_state[2];
+ u8 *rc_state;
+
+ rc_state = kmalloc(2, GFP_KERNEL);
+ if (!rc_state)
+ return -ENOMEM;
if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_STATE, rc_state, 1)) != 0)
- goto unlock;
+ goto out;
if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0)
- goto unlock;
+ goto out;
for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
if (rc5_data(&d->props.rc.legacy.rc_map_table[i]) == rc_state[1]) {
@@ -149,7 +153,7 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
switch(rc_state[0]) {
case 0x80:
*state = REMOTE_NO_KEY_PRESSED;
- goto unlock;
+ goto out;
case 0x88: /* framing error or "invalid code" */
case 0x99:
@@ -157,7 +161,7 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
case 0xd8:
*state = REMOTE_NO_KEY_PRESSED;
m->rep_count = 0;
- goto unlock;
+ goto out;
case 0x93:
case 0x92:
@@ -165,7 +169,7 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
case 0x82:
m->rep_count = 0;
*state = REMOTE_KEY_PRESSED;
- goto unlock;
+ goto out;
case 0x91:
case 0x81: /* pinnacle PCTV310e */
@@ -174,12 +178,12 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
*state = REMOTE_KEY_REPEAT;
else
*state = REMOTE_NO_KEY_PRESSED;
- goto unlock;
+ goto out;
default:
deb("Unexpected rc state %02x\n", rc_state[0]);
*state = REMOTE_NO_KEY_PRESSED;
- goto unlock;
+ goto out;
}
}
@@ -188,8 +192,8 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
*state = REMOTE_NO_KEY_PRESSED;
- unlock:
-
+ out:
+ kfree(rc_state);
return ret;
}
@@ -339,13 +343,19 @@ static int m920x_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, in
static int m920x_firmware_download(struct usb_device *udev, const struct firmware *fw)
{
u16 value, index, size;
- u8 read[4], *buff;
+ u8 *read, *buff;
int i, pass, ret = 0;
buff = kmalloc(65536, GFP_KERNEL);
if (buff == NULL)
return -ENOMEM;
+ read = kmalloc(4, GFP_KERNEL);
+ if (!read) {
+ kfree(buff);
+ return -ENOMEM;
+ }
+
if ((ret = m920x_read(udev, M9206_FILTER, 0x0, 0x8000, read, 4)) != 0)
goto done;
deb("%x %x %x %x\n", read[0], read[1], read[2], read[3]);
@@ -396,6 +406,7 @@ static int m920x_firmware_download(struct usb_device *udev, const struct firmwar
deb("firmware uploaded!\n");
done:
+ kfree(read);
kfree(buff);
return ret;
@@ -632,9 +643,9 @@ static struct rc_map_table rc_map_pinnacle310e_table[] = {
{ 0x16, KEY_POWER },
{ 0x17, KEY_FAVORITES },
{ 0x0f, KEY_TEXT },
- { 0x48, KEY_MEDIA }, /* preview */
+ { 0x48, KEY_PROGRAM }, /* preview */
{ 0x1c, KEY_EPG },
- { 0x04, KEY_LIST }, /* record list */
+ { 0x04, KEY_LIST }, /* record list */
{ 0x03, KEY_1 },
{ 0x01, KEY_2 },
{ 0x06, KEY_3 },
@@ -674,14 +685,14 @@ static struct rc_map_table rc_map_pinnacle310e_table[] = {
{ 0x0e, KEY_MUTE },
/* { 0x49, KEY_LR }, */ /* L/R */
{ 0x07, KEY_SLEEP }, /* Hibernate */
- { 0x08, KEY_MEDIA }, /* A/V */
- { 0x0e, KEY_MENU }, /* Recall */
+ { 0x08, KEY_VIDEO }, /* A/V */
+ { 0x0e, KEY_MENU }, /* Recall */
{ 0x45, KEY_ZOOMIN },
{ 0x46, KEY_ZOOMOUT },
- { 0x18, KEY_TV }, /* Red */
- { 0x53, KEY_VCR }, /* Green */
- { 0x5e, KEY_SAT }, /* Yellow */
- { 0x5f, KEY_PLAYER }, /* Blue */
+ { 0x18, KEY_RED }, /* Red */
+ { 0x53, KEY_GREEN }, /* Green */
+ { 0x5e, KEY_YELLOW }, /* Yellow */
+ { 0x5f, KEY_BLUE }, /* Blue */
};
/* DVB USB Driver stuff */
diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
index 9d3cd2de46fc..bc350e982b72 100644
--- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c
+++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
@@ -47,7 +47,7 @@ static struct rc_map_table rc_map_haupp_table[] = {
{ 0x1e17, KEY_RIGHT },
{ 0x1e18, KEY_VIDEO },
{ 0x1e19, KEY_AUDIO },
- { 0x1e1a, KEY_MEDIA },
+ { 0x1e1a, KEY_IMAGES },
{ 0x1e1b, KEY_EPG },
{ 0x1e1c, KEY_TV },
{ 0x1e1e, KEY_NEXT },
diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c
index 7e569f4dd80b..2e4fab7215f5 100644
--- a/drivers/media/dvb/dvb-usb/opera1.c
+++ b/drivers/media/dvb/dvb-usb/opera1.c
@@ -53,27 +53,36 @@ static int opera1_xilinx_rw(struct usb_device *dev, u8 request, u16 value,
u8 * data, u16 len, int flags)
{
int ret;
- u8 r;
- u8 u8buf[len];
-
+ u8 tmp;
+ u8 *buf;
unsigned int pipe = (flags == OPERA_READ_MSG) ?
usb_rcvctrlpipe(dev,0) : usb_sndctrlpipe(dev, 0);
u8 request_type = (flags == OPERA_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
+ buf = kmalloc(len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
if (flags == OPERA_WRITE_MSG)
- memcpy(u8buf, data, len);
- ret =
- usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR,
- value, 0x0, u8buf, len, 2000);
+ memcpy(buf, data, len);
+ ret = usb_control_msg(dev, pipe, request,
+ request_type | USB_TYPE_VENDOR, value, 0x0,
+ buf, len, 2000);
if (request == OPERA_TUNER_REQ) {
+ tmp = buf[0];
if (usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- OPERA_TUNER_REQ, USB_DIR_IN | USB_TYPE_VENDOR,
- 0x01, 0x0, &r, 1, 2000)<1 || r!=0x08)
- return 0;
+ OPERA_TUNER_REQ, USB_DIR_IN | USB_TYPE_VENDOR,
+ 0x01, 0x0, buf, 1, 2000) < 1 || buf[0] != 0x08) {
+ ret = 0;
+ goto out;
+ }
+ buf[0] = tmp;
}
if (flags == OPERA_READ_MSG)
- memcpy(data, u8buf, len);
+ memcpy(data, buf, len);
+out:
+ kfree(buf);
return ret;
}
@@ -189,7 +198,7 @@ static int opera1_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate,
static u8 opera1_inittab[] = {
0x00, 0xa1,
0x01, 0x15,
- 0x02, 0x00,
+ 0x02, 0x30,
0x03, 0x00,
0x04, 0x7d,
0x05, 0x05,
diff --git a/drivers/media/dvb/dvb-usb/vp702x-fe.c b/drivers/media/dvb/dvb-usb/vp702x-fe.c
index ccc7e4452664..2bb8d4cc8d88 100644
--- a/drivers/media/dvb/dvb-usb/vp702x-fe.c
+++ b/drivers/media/dvb/dvb-usb/vp702x-fe.c
@@ -41,14 +41,23 @@ struct vp702x_fe_state {
static int vp702x_fe_refresh_state(struct vp702x_fe_state *st)
{
- u8 buf[10];
- if (time_after(jiffies,st->next_status_check)) {
- vp702x_usb_in_op(st->d,READ_STATUS,0,0,buf,10);
+ struct vp702x_device_state *dst = st->d->priv;
+ u8 *buf;
+ if (time_after(jiffies, st->next_status_check)) {
+ mutex_lock(&dst->buf_mutex);
+ buf = dst->buf;
+
+ vp702x_usb_in_op(st->d, READ_STATUS, 0, 0, buf, 10);
st->lock = buf[4];
- vp702x_usb_in_op(st->d,READ_TUNER_REG_REQ,0x11,0,&st->snr,1);
- vp702x_usb_in_op(st->d,READ_TUNER_REG_REQ,0x15,0,&st->sig,1);
+ vp702x_usb_in_op(st->d, READ_TUNER_REG_REQ, 0x11, 0, buf, 1);
+ st->snr = buf[0];
+
+ vp702x_usb_in_op(st->d, READ_TUNER_REG_REQ, 0x15, 0, buf, 1);
+ st->sig = buf[0];
+
+ mutex_unlock(&dst->buf_mutex);
st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000;
}
return 0;
@@ -130,11 +139,17 @@ static int vp702x_fe_set_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep)
{
struct vp702x_fe_state *st = fe->demodulator_priv;
+ struct vp702x_device_state *dst = st->d->priv;
u32 freq = fep->frequency/1000;
/*CalFrequency*/
/* u16 frequencyRef[16] = { 2, 4, 8, 16, 32, 64, 128, 256, 24, 5, 10, 20, 40, 80, 160, 320 }; */
u64 sr;
- u8 cmd[8] = { 0 },ibuf[10];
+ u8 *cmd;
+
+ mutex_lock(&dst->buf_mutex);
+
+ cmd = dst->buf;
+ memset(cmd, 0, 10);
cmd[0] = (freq >> 8) & 0x7f;
cmd[1] = freq & 0xff;
@@ -170,13 +185,15 @@ static int vp702x_fe_set_frontend(struct dvb_frontend* fe,
st->status_check_interval = 250;
st->next_status_check = jiffies;
- vp702x_usb_inout_op(st->d,cmd,8,ibuf,10,100);
+ vp702x_usb_inout_op(st->d, cmd, 8, cmd, 10, 100);
- if (ibuf[2] == 0 && ibuf[3] == 0)
+ if (cmd[2] == 0 && cmd[3] == 0)
deb_fe("tuning failed.\n");
else
deb_fe("tuning succeeded.\n");
+ mutex_unlock(&dst->buf_mutex);
+
return 0;
}
@@ -204,27 +221,32 @@ static int vp702x_fe_get_frontend(struct dvb_frontend* fe,
static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe,
struct dvb_diseqc_master_cmd *m)
{
+ u8 *cmd;
struct vp702x_fe_state *st = fe->demodulator_priv;
- u8 cmd[8],ibuf[10];
- memset(cmd,0,8);
+ struct vp702x_device_state *dst = st->d->priv;
deb_fe("%s\n",__func__);
if (m->msg_len > 4)
return -EINVAL;
+ mutex_lock(&dst->buf_mutex);
+
+ cmd = dst->buf;
cmd[1] = SET_DISEQC_CMD;
cmd[2] = m->msg_len;
memcpy(&cmd[3], m->msg, m->msg_len);
- cmd[7] = vp702x_chksum(cmd,0,7);
+ cmd[7] = vp702x_chksum(cmd, 0, 7);
- vp702x_usb_inout_op(st->d,cmd,8,ibuf,10,100);
+ vp702x_usb_inout_op(st->d, cmd, 8, cmd, 10, 100);
- if (ibuf[2] == 0 && ibuf[3] == 0)
+ if (cmd[2] == 0 && cmd[3] == 0)
deb_fe("diseqc cmd failed.\n");
else
deb_fe("diseqc cmd succeeded.\n");
+ mutex_unlock(&dst->buf_mutex);
+
return 0;
}
@@ -237,7 +259,9 @@ static int vp702x_fe_send_diseqc_burst (struct dvb_frontend* fe, fe_sec_mini_cmd
static int vp702x_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
{
struct vp702x_fe_state *st = fe->demodulator_priv;
- u8 ibuf[10];
+ struct vp702x_device_state *dst = st->d->priv;
+ u8 *buf;
+
deb_fe("%s\n",__func__);
st->tone_mode = tone;
@@ -247,14 +271,21 @@ static int vp702x_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
else
st->lnb_buf[2] = 0x00;
- st->lnb_buf[7] = vp702x_chksum(st->lnb_buf,0,7);
+ st->lnb_buf[7] = vp702x_chksum(st->lnb_buf, 0, 7);
+
+ mutex_lock(&dst->buf_mutex);
+
+ buf = dst->buf;
+ memcpy(buf, st->lnb_buf, 8);
- vp702x_usb_inout_op(st->d,st->lnb_buf,8,ibuf,10,100);
- if (ibuf[2] == 0 && ibuf[3] == 0)
+ vp702x_usb_inout_op(st->d, buf, 8, buf, 10, 100);
+ if (buf[2] == 0 && buf[3] == 0)
deb_fe("set_tone cmd failed.\n");
else
deb_fe("set_tone cmd succeeded.\n");
+ mutex_unlock(&dst->buf_mutex);
+
return 0;
}
@@ -262,7 +293,8 @@ static int vp702x_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t
voltage)
{
struct vp702x_fe_state *st = fe->demodulator_priv;
- u8 ibuf[10];
+ struct vp702x_device_state *dst = st->d->priv;
+ u8 *buf;
deb_fe("%s\n",__func__);
st->voltage = voltage;
@@ -272,14 +304,20 @@ static int vp702x_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t
else
st->lnb_buf[4] = 0x00;
- st->lnb_buf[7] = vp702x_chksum(st->lnb_buf,0,7);
+ st->lnb_buf[7] = vp702x_chksum(st->lnb_buf, 0, 7);
+
+ mutex_lock(&dst->buf_mutex);
+
+ buf = dst->buf;
+ memcpy(buf, st->lnb_buf, 8);
- vp702x_usb_inout_op(st->d,st->lnb_buf,8,ibuf,10,100);
- if (ibuf[2] == 0 && ibuf[3] == 0)
+ vp702x_usb_inout_op(st->d, buf, 8, buf, 10, 100);
+ if (buf[2] == 0 && buf[3] == 0)
deb_fe("set_voltage cmd failed.\n");
else
deb_fe("set_voltage cmd succeeded.\n");
+ mutex_unlock(&dst->buf_mutex);
return 0;
}
diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c
index 7890e75600df..54355f84a98f 100644
--- a/drivers/media/dvb/dvb-usb/vp702x.c
+++ b/drivers/media/dvb/dvb-usb/vp702x.c
@@ -15,6 +15,7 @@
* see Documentation/dvb/README.dvb-usb for more information
*/
#include "vp702x.h"
+#include <linux/mutex.h>
/* debug */
int dvb_usb_vp702x_debug;
@@ -23,27 +24,23 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DV
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-struct vp702x_state {
+struct vp702x_adapter_state {
int pid_filter_count;
int pid_filter_can_bypass;
u8 pid_filter_state;
};
-struct vp702x_device_state {
- u8 power_state;
-};
-
-/* check for mutex FIXME */
-int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
+static int vp702x_usb_in_op_unlocked(struct dvb_usb_device *d, u8 req,
+ u16 value, u16 index, u8 *b, int blen)
{
- int ret = -1;
+ int ret;
- ret = usb_control_msg(d->udev,
- usb_rcvctrlpipe(d->udev,0),
- req,
- USB_TYPE_VENDOR | USB_DIR_IN,
- value,index,b,blen,
- 2000);
+ ret = usb_control_msg(d->udev,
+ usb_rcvctrlpipe(d->udev, 0),
+ req,
+ USB_TYPE_VENDOR | USB_DIR_IN,
+ value, index, b, blen,
+ 2000);
if (ret < 0) {
warn("usb in operation failed. (%d)", ret);
@@ -58,8 +55,20 @@ int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8
return ret;
}
-static int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
- u16 index, u8 *b, int blen)
+int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value,
+ u16 index, u8 *b, int blen)
+{
+ int ret;
+
+ mutex_lock(&d->usb_mutex);
+ ret = vp702x_usb_in_op_unlocked(d, req, value, index, b, blen);
+ mutex_unlock(&d->usb_mutex);
+
+ return ret;
+}
+
+int vp702x_usb_out_op_unlocked(struct dvb_usb_device *d, u8 req, u16 value,
+ u16 index, u8 *b, int blen)
{
int ret;
deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
@@ -77,6 +86,18 @@ static int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
return 0;
}
+int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
+ u16 index, u8 *b, int blen)
+{
+ int ret;
+
+ mutex_lock(&d->usb_mutex);
+ ret = vp702x_usb_out_op_unlocked(d, req, value, index, b, blen);
+ mutex_unlock(&d->usb_mutex);
+
+ return ret;
+}
+
int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec)
{
int ret;
@@ -84,50 +105,93 @@ int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int il
if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
return ret;
- ret = vp702x_usb_out_op(d,REQUEST_OUT,0,0,o,olen);
+ ret = vp702x_usb_out_op_unlocked(d, REQUEST_OUT, 0, 0, o, olen);
msleep(msec);
- ret = vp702x_usb_in_op(d,REQUEST_IN,0,0,i,ilen);
+ ret = vp702x_usb_in_op_unlocked(d, REQUEST_IN, 0, 0, i, ilen);
mutex_unlock(&d->usb_mutex);
-
return ret;
}
static int vp702x_usb_inout_cmd(struct dvb_usb_device *d, u8 cmd, u8 *o,
int olen, u8 *i, int ilen, int msec)
{
- u8 bout[olen+2];
- u8 bin[ilen+1];
+ struct vp702x_device_state *st = d->priv;
int ret = 0;
+ u8 *buf;
+ int buflen = max(olen + 2, ilen + 1);
+
+ ret = mutex_lock_interruptible(&st->buf_mutex);
+ if (ret < 0)
+ return ret;
+
+ if (buflen > st->buf_len) {
+ buf = kmalloc(buflen, GFP_KERNEL);
+ if (!buf) {
+ mutex_unlock(&st->buf_mutex);
+ return -ENOMEM;
+ }
+ info("successfully reallocated a bigger buffer");
+ kfree(st->buf);
+ st->buf = buf;
+ st->buf_len = buflen;
+ } else {
+ buf = st->buf;
+ }
- bout[0] = 0x00;
- bout[1] = cmd;
- memcpy(&bout[2],o,olen);
+ buf[0] = 0x00;
+ buf[1] = cmd;
+ memcpy(&buf[2], o, olen);
- ret = vp702x_usb_inout_op(d, bout, olen+2, bin, ilen+1,msec);
+ ret = vp702x_usb_inout_op(d, buf, olen+2, buf, ilen+1, msec);
if (ret == 0)
- memcpy(i,&bin[1],ilen);
+ memcpy(i, &buf[1], ilen);
+ mutex_unlock(&st->buf_mutex);
return ret;
}
static int vp702x_set_pld_mode(struct dvb_usb_adapter *adap, u8 bypass)
{
- u8 buf[16] = { 0 };
- return vp702x_usb_in_op(adap->dev, 0xe0, (bypass << 8) | 0x0e, 0, buf, 16);
+ int ret;
+ struct vp702x_device_state *st = adap->dev->priv;
+ u8 *buf;
+
+ mutex_lock(&st->buf_mutex);
+
+ buf = st->buf;
+ memset(buf, 0, 16);
+
+ ret = vp702x_usb_in_op(adap->dev, 0xe0, (bypass << 8) | 0x0e,
+ 0, buf, 16);
+ mutex_unlock(&st->buf_mutex);
+ return ret;
}
static int vp702x_set_pld_state(struct dvb_usb_adapter *adap, u8 state)
{
- u8 buf[16] = { 0 };
- return vp702x_usb_in_op(adap->dev, 0xe0, (state << 8) | 0x0f, 0, buf, 16);
+ int ret;
+ struct vp702x_device_state *st = adap->dev->priv;
+ u8 *buf;
+
+ mutex_lock(&st->buf_mutex);
+
+ buf = st->buf;
+ memset(buf, 0, 16);
+ ret = vp702x_usb_in_op(adap->dev, 0xe0, (state << 8) | 0x0f,
+ 0, buf, 16);
+
+ mutex_unlock(&st->buf_mutex);
+
+ return ret;
}
static int vp702x_set_pid(struct dvb_usb_adapter *adap, u16 pid, u8 id, int onoff)
{
- struct vp702x_state *st = adap->priv;
- u8 buf[16] = { 0 };
+ struct vp702x_adapter_state *st = adap->priv;
+ struct vp702x_device_state *dst = adap->dev->priv;
+ u8 *buf;
if (onoff)
st->pid_filter_state |= (1 << id);
@@ -139,32 +203,45 @@ static int vp702x_set_pid(struct dvb_usb_adapter *adap, u16 pid, u8 id, int onof
id = 0x10 + id*2;
vp702x_set_pld_state(adap, st->pid_filter_state);
+
+ mutex_lock(&dst->buf_mutex);
+
+ buf = dst->buf;
+ memset(buf, 0, 16);
vp702x_usb_in_op(adap->dev, 0xe0, (((pid >> 8) & 0xff) << 8) | (id), 0, buf, 16);
vp702x_usb_in_op(adap->dev, 0xe0, (((pid ) & 0xff) << 8) | (id+1), 0, buf, 16);
+
+ mutex_unlock(&dst->buf_mutex);
+
return 0;
}
static int vp702x_init_pid_filter(struct dvb_usb_adapter *adap)
{
- struct vp702x_state *st = adap->priv;
+ struct vp702x_adapter_state *st = adap->priv;
+ struct vp702x_device_state *dst = adap->dev->priv;
int i;
- u8 b[10] = { 0 };
+ u8 *b;
st->pid_filter_count = 8;
st->pid_filter_can_bypass = 1;
st->pid_filter_state = 0x00;
- vp702x_set_pld_mode(adap, 1); // bypass
+ vp702x_set_pld_mode(adap, 1); /* bypass */
for (i = 0; i < st->pid_filter_count; i++)
vp702x_set_pid(adap, 0xffff, i, 1);
+ mutex_lock(&dst->buf_mutex);
+ b = dst->buf;
+ memset(b, 0, 10);
vp702x_usb_in_op(adap->dev, 0xb5, 3, 0, b, 10);
vp702x_usb_in_op(adap->dev, 0xb5, 0, 0, b, 10);
vp702x_usb_in_op(adap->dev, 0xb5, 1, 0, b, 10);
+ mutex_unlock(&dst->buf_mutex);
+ /*vp702x_set_pld_mode(d, 0); // filter */
- //vp702x_set_pld_mode(d, 0); // filter
return 0;
}
@@ -182,18 +259,23 @@ static struct rc_map_table rc_map_vp702x_table[] = {
/* remote control stuff (does not work with my box) */
static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
- u8 key[10];
+ u8 *key;
int i;
/* remove the following return to enabled remote querying */
return 0;
+ key = kmalloc(10, GFP_KERNEL);
+ if (!key)
+ return -ENOMEM;
+
vp702x_usb_in_op(d,READ_REMOTE_REQ,0,0,key,10);
deb_rc("remote query key: %x %d\n",key[1],key[1]);
if (key[1] == 0x44) {
*state = REMOTE_NO_KEY_PRESSED;
+ kfree(key);
return 0;
}
@@ -203,15 +285,23 @@ static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
*event = rc_map_vp702x_table[i].keycode;
break;
}
+ kfree(key);
return 0;
}
static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
{
- u8 i;
+ u8 i, *buf;
+ struct vp702x_device_state *st = d->priv;
+
+ mutex_lock(&st->buf_mutex);
+ buf = st->buf;
for (i = 6; i < 12; i++)
- vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1, &mac[i - 6], 1);
+ vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1, &buf[i - 6], 1);
+
+ memcpy(mac, buf, 6);
+ mutex_unlock(&st->buf_mutex);
return 0;
}
@@ -221,7 +311,8 @@ static int vp702x_frontend_attach(struct dvb_usb_adapter *adap)
vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 0, 7, NULL, 0);
- if (vp702x_usb_inout_cmd(adap->dev, GET_SYSTEM_STRING, NULL, 0, buf, 10, 10))
+ if (vp702x_usb_inout_cmd(adap->dev, GET_SYSTEM_STRING, NULL, 0,
+ buf, 10, 10))
return -EIO;
buf[9] = '\0';
@@ -240,8 +331,38 @@ static struct dvb_usb_device_properties vp702x_properties;
static int vp702x_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- return dvb_usb_device_init(intf, &vp702x_properties,
- THIS_MODULE, NULL, adapter_nr);
+ struct dvb_usb_device *d;
+ struct vp702x_device_state *st;
+ int ret;
+
+ ret = dvb_usb_device_init(intf, &vp702x_properties,
+ THIS_MODULE, &d, adapter_nr);
+ if (ret)
+ goto out;
+
+ st = d->priv;
+ st->buf_len = 16;
+ st->buf = kmalloc(st->buf_len, GFP_KERNEL);
+ if (!st->buf) {
+ ret = -ENOMEM;
+ dvb_usb_device_exit(intf);
+ goto out;
+ }
+ mutex_init(&st->buf_mutex);
+
+out:
+ return ret;
+
+}
+
+static void vp702x_usb_disconnect(struct usb_interface *intf)
+{
+ struct dvb_usb_device *d = usb_get_intfdata(intf);
+ struct vp702x_device_state *st = d->priv;
+ mutex_lock(&st->buf_mutex);
+ kfree(st->buf);
+ mutex_unlock(&st->buf_mutex);
+ dvb_usb_device_exit(intf);
}
static struct usb_device_id vp702x_usb_table [] = {
@@ -278,7 +399,7 @@ static struct dvb_usb_device_properties vp702x_properties = {
}
}
},
- .size_of_priv = sizeof(struct vp702x_state),
+ .size_of_priv = sizeof(struct vp702x_adapter_state),
}
},
.read_mac_address = vp702x_read_mac_addr,
@@ -307,9 +428,9 @@ static struct dvb_usb_device_properties vp702x_properties = {
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver vp702x_usb_driver = {
.name = "dvb_usb_vp702x",
- .probe = vp702x_usb_probe,
- .disconnect = dvb_usb_device_exit,
- .id_table = vp702x_usb_table,
+ .probe = vp702x_usb_probe,
+ .disconnect = vp702x_usb_disconnect,
+ .id_table = vp702x_usb_table,
};
/* module stuff */
diff --git a/drivers/media/dvb/dvb-usb/vp702x.h b/drivers/media/dvb/dvb-usb/vp702x.h
index c2f97f96c21f..20b90055e7ac 100644
--- a/drivers/media/dvb/dvb-usb/vp702x.h
+++ b/drivers/media/dvb/dvb-usb/vp702x.h
@@ -98,6 +98,13 @@ extern int dvb_usb_vp702x_debug;
#define RESET_TUNER 0xBE
/* IN i: 0, v: 0, no extra buffer */
+struct vp702x_device_state {
+ struct mutex buf_mutex;
+ int buf_len;
+ u8 *buf;
+};
+
+
extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d);
extern int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec);
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
index ab0ab3c35e80..3db89e3cb0bb 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.c
+++ b/drivers/media/dvb/dvb-usb/vp7045.c
@@ -28,9 +28,9 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen, int msec)
{
int ret = 0;
- u8 inbuf[12] = { 0 }, outbuf[20] = { 0 };
+ u8 *buf = d->priv;
- outbuf[0] = cmd;
+ buf[0] = cmd;
if (outlen > 19)
outlen = 19;
@@ -38,19 +38,21 @@ int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in,
if (inlen > 11)
inlen = 11;
+ ret = mutex_lock_interruptible(&d->usb_mutex);
+ if (ret)
+ return ret;
+
if (out != NULL && outlen > 0)
- memcpy(&outbuf[1], out, outlen);
+ memcpy(&buf[1], out, outlen);
deb_xfer("out buffer: ");
- debug_dump(outbuf,outlen+1,deb_xfer);
+ debug_dump(buf, outlen+1, deb_xfer);
- if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
- return ret;
if (usb_control_msg(d->udev,
usb_sndctrlpipe(d->udev,0),
TH_COMMAND_OUT, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0,
- outbuf, 20, 2000) != 20) {
+ buf, 20, 2000) != 20) {
err("USB control message 'out' went wrong.");
ret = -EIO;
goto unlock;
@@ -61,17 +63,17 @@ int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in,
if (usb_control_msg(d->udev,
usb_rcvctrlpipe(d->udev,0),
TH_COMMAND_IN, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
- inbuf, 12, 2000) != 12) {
+ buf, 12, 2000) != 12) {
err("USB control message 'in' went wrong.");
ret = -EIO;
goto unlock;
}
deb_xfer("in buffer: ");
- debug_dump(inbuf,12,deb_xfer);
+ debug_dump(buf, 12, deb_xfer);
if (in != NULL && inlen > 0)
- memcpy(in,&inbuf[1],inlen);
+ memcpy(in, &buf[1], inlen);
unlock:
mutex_unlock(&d->usb_mutex);
@@ -222,8 +224,26 @@ static struct dvb_usb_device_properties vp7045_properties;
static int vp7045_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- return dvb_usb_device_init(intf, &vp7045_properties,
- THIS_MODULE, NULL, adapter_nr);
+ struct dvb_usb_device *d;
+ int ret = dvb_usb_device_init(intf, &vp7045_properties,
+ THIS_MODULE, &d, adapter_nr);
+ if (ret)
+ return ret;
+
+ d->priv = kmalloc(20, GFP_KERNEL);
+ if (!d->priv) {
+ dvb_usb_device_exit(intf);
+ return -ENOMEM;
+ }
+
+ return ret;
+}
+
+static void vp7045_usb_disconnect(struct usb_interface *intf)
+{
+ struct dvb_usb_device *d = usb_get_intfdata(intf);
+ kfree(d->priv);
+ dvb_usb_device_exit(intf);
}
static struct usb_device_id vp7045_usb_table [] = {
@@ -238,6 +258,7 @@ MODULE_DEVICE_TABLE(usb, vp7045_usb_table);
static struct dvb_usb_device_properties vp7045_properties = {
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-vp7045-01.fw",
+ .size_of_priv = sizeof(u8 *),
.num_adapters = 1,
.adapter = {
@@ -284,7 +305,7 @@ static struct dvb_usb_device_properties vp7045_properties = {
static struct usb_driver vp7045_usb_driver = {
.name = "dvb_usb_vp7045",
.probe = vp7045_usb_probe,
- .disconnect = dvb_usb_device_exit,
+ .disconnect = vp7045_usb_disconnect,
.id_table = vp7045_usb_table,
};
diff --git a/drivers/media/dvb/firewire/firedtv-avc.c b/drivers/media/dvb/firewire/firedtv-avc.c
index fc5ccd8c923a..21c52e3b522e 100644
--- a/drivers/media/dvb/firewire/firedtv-avc.c
+++ b/drivers/media/dvb/firewire/firedtv-avc.c
@@ -1320,14 +1320,10 @@ static int cmp_read(struct firedtv *fdtv, u64 addr, __be32 *data)
{
int ret;
- mutex_lock(&fdtv->avc_mutex);
-
ret = fdtv_read(fdtv, addr, data);
if (ret < 0)
dev_err(fdtv->device, "CMP: read I/O error\n");
- mutex_unlock(&fdtv->avc_mutex);
-
return ret;
}
@@ -1335,18 +1331,9 @@ static int cmp_lock(struct firedtv *fdtv, u64 addr, __be32 data[])
{
int ret;
- mutex_lock(&fdtv->avc_mutex);
-
- /* data[] is stack-allocated and should not be DMA-mapped. */
- memcpy(fdtv->avc_data, data, 8);
-
- ret = fdtv_lock(fdtv, addr, fdtv->avc_data);
+ ret = fdtv_lock(fdtv, addr, data);
if (ret < 0)
dev_err(fdtv->device, "CMP: lock I/O error\n");
- else
- memcpy(data, fdtv->avc_data, 8);
-
- mutex_unlock(&fdtv->avc_mutex);
return ret;
}
diff --git a/drivers/media/dvb/firewire/firedtv-fw.c b/drivers/media/dvb/firewire/firedtv-fw.c
index 8022b743af91..864b6274c729 100644
--- a/drivers/media/dvb/firewire/firedtv-fw.c
+++ b/drivers/media/dvb/firewire/firedtv-fw.c
@@ -125,6 +125,7 @@ static void handle_iso(struct fw_iso_context *context, u32 cycle,
i = (i + 1) & (N_PACKETS - 1);
}
+ fw_iso_context_queue_flush(ctx->context);
ctx->current_packet = i;
}
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index 83093d1f4f74..44b816f2601e 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -263,18 +263,16 @@ config DVB_S5H1432
help
A DVB-T tuner module. Say Y when you want to support this frontend.
-config DVB_DRX397XD
- tristate "Micronas DRX3975D/DRX3977D based"
+config DVB_DRXD
+ tristate "Micronas DRXD driver"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
A DVB-T tuner module. Say Y when you want to support this frontend.
- TODO:
- This driver needs external firmware. Please use the command
- "<kerneldir>/Documentation/dvb/get_dvb_firmware drx397xD" to
- download/extract them, and then copy them to /usr/lib/hotplug/firmware
- or /lib/firmware (depending on configuration of firmware hotplug).
+ Note: this driver was based on vendor driver reference code (released
+ under the GPL) as opposed to the existing drx397xd driver, which
+ was written via reverse engineering.
config DVB_L64781
tristate "LSI L64781"
@@ -385,6 +383,13 @@ config DVB_STV0367
help
A DVB-T/C tuner module. Say Y when you want to support this frontend.
+config DVB_CXD2820R
+ tristate "Sony CXD2820R"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ Say Y when you want to support this frontend.
+
comment "DVB-C (cable) frontends"
depends on DVB_CORE
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 3b0c4bdc4b2b..2f3a6f736d64 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -8,6 +8,8 @@ EXTRA_CFLAGS += -Idrivers/media/common/tuners/
stb0899-objs = stb0899_drv.o stb0899_algo.o
stv0900-objs = stv0900_core.o stv0900_sw.o
au8522-objs = au8522_dig.o au8522_decoder.o
+drxd-objs = drxd_firm.o drxd_hard.o
+cxd2820r-objs = cxd2820r_core.o cxd2820r_c.o cxd2820r_t.o cxd2820r_t2.o
obj-$(CONFIG_DVB_PLL) += dvb-pll.o
obj-$(CONFIG_DVB_STV0299) += stv0299.o
@@ -36,7 +38,7 @@ obj-$(CONFIG_DVB_ZL10036) += zl10036.o
obj-$(CONFIG_DVB_ZL10039) += zl10039.o
obj-$(CONFIG_DVB_ZL10353) += zl10353.o
obj-$(CONFIG_DVB_CX22702) += cx22702.o
-obj-$(CONFIG_DVB_DRX397XD) += drx397xD.o
+obj-$(CONFIG_DVB_DRXD) += drxd.o
obj-$(CONFIG_DVB_TDA10021) += tda10021.o
obj-$(CONFIG_DVB_TDA10023) += tda10023.o
obj-$(CONFIG_DVB_STV0297) += stv0297.o
@@ -85,3 +87,5 @@ obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o
obj-$(CONFIG_DVB_IX2505V) += ix2505v.o
obj-$(CONFIG_DVB_STV0367) += stv0367.o
+obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o
+
diff --git a/drivers/media/dvb/frontends/bsbe1-d01a.h b/drivers/media/dvb/frontends/bsbe1-d01a.h
new file mode 100644
index 000000000000..7ed3c424178c
--- /dev/null
+++ b/drivers/media/dvb/frontends/bsbe1-d01a.h
@@ -0,0 +1,146 @@
+/*
+ * bsbe1-d01a.h - ALPS BSBE1-D01A tuner support
+ *
+ * Copyright (C) 2011 Oliver Endriss <o.endriss@gmx.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.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef BSBE1_D01A_H
+#define BSBE1_D01A_H
+
+#include "stb6000.h"
+#include "stv0288.h"
+
+static u8 stv0288_bsbe1_d01a_inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x20,
+ 0x09, 0x0,
+ 0x0a, 0x4,
+ 0x0b, 0x0,
+ 0x0c, 0x0,
+ 0x0d, 0x0,
+ 0x0e, 0xd4,
+ 0x0f, 0x30,
+ 0x11, 0x80,
+ 0x12, 0x03,
+ 0x13, 0x48,
+ 0x14, 0x84,
+ 0x15, 0x45,
+ 0x16, 0xb7,
+ 0x17, 0x9c,
+ 0x18, 0x0,
+ 0x19, 0xa6,
+ 0x1a, 0x88,
+ 0x1b, 0x8f,
+ 0x1c, 0xf0,
+ 0x20, 0x0b,
+ 0x21, 0x54,
+ 0x22, 0x0,
+ 0x23, 0x0,
+ 0x2b, 0xff,
+ 0x2c, 0xf7,
+ 0x30, 0x0,
+ 0x31, 0x1e,
+ 0x32, 0x14,
+ 0x33, 0x0f,
+ 0x34, 0x09,
+ 0x35, 0x0c,
+ 0x36, 0x05,
+ 0x37, 0x2f,
+ 0x38, 0x16,
+ 0x39, 0xbd,
+ 0x3a, 0x03,
+ 0x3b, 0x13,
+ 0x3c, 0x11,
+ 0x3d, 0x30,
+ 0x40, 0x63,
+ 0x41, 0x04,
+ 0x42, 0x60,
+ 0x43, 0x00,
+ 0x44, 0x00,
+ 0x45, 0x00,
+ 0x46, 0x00,
+ 0x47, 0x00,
+ 0x4a, 0x00,
+ 0x50, 0x10,
+ 0x51, 0x36,
+ 0x52, 0x09,
+ 0x53, 0x94,
+ 0x54, 0x62,
+ 0x55, 0x29,
+ 0x56, 0x64,
+ 0x57, 0x2b,
+ 0x58, 0x54,
+ 0x59, 0x86,
+ 0x5a, 0x0,
+ 0x5b, 0x9b,
+ 0x5c, 0x08,
+ 0x5d, 0x7f,
+ 0x5e, 0x0,
+ 0x5f, 0xff,
+ 0x70, 0x0,
+ 0x71, 0x0,
+ 0x72, 0x0,
+ 0x74, 0x0,
+ 0x75, 0x0,
+ 0x76, 0x0,
+ 0x81, 0x0,
+ 0x82, 0x3f,
+ 0x83, 0x3f,
+ 0x84, 0x0,
+ 0x85, 0x0,
+ 0x88, 0x0,
+ 0x89, 0x0,
+ 0x8a, 0x0,
+ 0x8b, 0x0,
+ 0x8c, 0x0,
+ 0x90, 0x0,
+ 0x91, 0x0,
+ 0x92, 0x0,
+ 0x93, 0x0,
+ 0x94, 0x1c,
+ 0x97, 0x0,
+ 0xa0, 0x48,
+ 0xa1, 0x0,
+ 0xb0, 0xb8,
+ 0xb1, 0x3a,
+ 0xb2, 0x10,
+ 0xb3, 0x82,
+ 0xb4, 0x80,
+ 0xb5, 0x82,
+ 0xb6, 0x82,
+ 0xb7, 0x82,
+ 0xb8, 0x20,
+ 0xb9, 0x0,
+ 0xf0, 0x0,
+ 0xf1, 0x0,
+ 0xf2, 0xc0,
+ 0xff, 0xff,
+};
+
+static struct stv0288_config stv0288_bsbe1_d01a_config = {
+ .demod_address = 0x68,
+ .min_delay_ms = 100,
+ .inittab = stv0288_bsbe1_d01a_inittab,
+};
+
+#endif
diff --git a/drivers/media/dvb/frontends/bsru6.h b/drivers/media/dvb/frontends/bsru6.h
index 45a6dfd8ebb5..c480c839b302 100644
--- a/drivers/media/dvb/frontends/bsru6.h
+++ b/drivers/media/dvb/frontends/bsru6.h
@@ -27,7 +27,7 @@
static u8 alps_bsru6_inittab[] = {
0x01, 0x15,
- 0x02, 0x00,
+ 0x02, 0x30,
0x03, 0x00,
0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
diff --git a/drivers/media/dvb/frontends/cx24116.c b/drivers/media/dvb/frontends/cx24116.c
index 2410d8b59b6b..95c6465b87a1 100644
--- a/drivers/media/dvb/frontends/cx24116.c
+++ b/drivers/media/dvb/frontends/cx24116.c
@@ -137,7 +137,7 @@ MODULE_PARM_DESC(toneburst, "DiSEqC toneburst 0=OFF, 1=TONE CACHE, "\
/* SNR measurements */
static int esno_snr;
module_param(esno_snr, int, 0644);
-MODULE_PARM_DESC(debug, "SNR return units, 0=PERCENTAGE 0-100, "\
+MODULE_PARM_DESC(esno_snr, "SNR return units, 0=PERCENTAGE 0-100, "\
"1=ESNO(db * 10) (default:0)");
enum cmds {
@@ -566,7 +566,7 @@ static int cx24116_load_firmware(struct dvb_frontend *fe,
{
struct cx24116_state *state = fe->demodulator_priv;
struct cx24116_cmd cmd;
- int i, ret;
+ int i, ret, len, max, remaining;
unsigned char vers[4];
dprintk("%s\n", __func__);
@@ -603,8 +603,21 @@ static int cx24116_load_firmware(struct dvb_frontend *fe,
cx24116_writereg(state, 0xF5, 0x00);
cx24116_writereg(state, 0xF6, 0x00);
- /* write the entire firmware as one transaction */
- cx24116_writeregN(state, 0xF7, fw->data, fw->size);
+ /* Split firmware to the max I2C write len and write.
+ * Writes whole firmware as one write when i2c_wr_max is set to 0. */
+ if (state->config->i2c_wr_max)
+ max = state->config->i2c_wr_max;
+ else
+ max = INT_MAX; /* enough for 32k firmware */
+
+ for (remaining = fw->size; remaining > 0; remaining -= max - 1) {
+ len = remaining;
+ if (len > max - 1)
+ len = max - 1;
+
+ cx24116_writeregN(state, 0xF7, &fw->data[fw->size - remaining],
+ len);
+ }
cx24116_writereg(state, 0xF4, 0x10);
cx24116_writereg(state, 0xF0, 0x00);
diff --git a/drivers/media/dvb/frontends/cx24116.h b/drivers/media/dvb/frontends/cx24116.h
index b1b76b47a14c..7d90ab949c03 100644
--- a/drivers/media/dvb/frontends/cx24116.h
+++ b/drivers/media/dvb/frontends/cx24116.h
@@ -35,6 +35,9 @@ struct cx24116_config {
/* Need to set MPEG parameters */
u8 mpg_clk_pos_pol:0x02;
+
+ /* max bytes I2C provider can write at once */
+ u16 i2c_wr_max;
};
#if defined(CONFIG_DVB_CX24116) || \
diff --git a/drivers/media/dvb/frontends/cxd2820r.h b/drivers/media/dvb/frontends/cxd2820r.h
new file mode 100644
index 000000000000..ad17845123d9
--- /dev/null
+++ b/drivers/media/dvb/frontends/cxd2820r.h
@@ -0,0 +1,118 @@
+/*
+ * Sony CXD2820R demodulator driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#ifndef CXD2820R_H
+#define CXD2820R_H
+
+#include <linux/dvb/frontend.h>
+
+#define CXD2820R_GPIO_D (0 << 0) /* disable */
+#define CXD2820R_GPIO_E (1 << 0) /* enable */
+#define CXD2820R_GPIO_O (0 << 1) /* output */
+#define CXD2820R_GPIO_I (1 << 1) /* input */
+#define CXD2820R_GPIO_L (0 << 2) /* output low */
+#define CXD2820R_GPIO_H (1 << 2) /* output high */
+
+#define CXD2820R_TS_SERIAL 0x08
+#define CXD2820R_TS_SERIAL_MSB 0x28
+#define CXD2820R_TS_PARALLEL 0x30
+#define CXD2820R_TS_PARALLEL_MSB 0x70
+
+struct cxd2820r_config {
+ /* Demodulator I2C address.
+ * Driver determines DVB-C slave I2C address automatically from master
+ * address.
+ * Default: none, must set
+ * Values: 0x6c, 0x6d
+ */
+ u8 i2c_address;
+
+ /* TS output mode.
+ * Default: none, must set.
+ * Values:
+ */
+ u8 ts_mode;
+
+ /* IF AGC polarity.
+ * Default: 0
+ * Values: 0, 1
+ */
+ int if_agc_polarity:1;
+
+ /* Spectrum inversion.
+ * Default: 0
+ * Values: 0, 1
+ */
+ int spec_inv:1;
+
+ /* IFs for all used modes.
+ * Default: none, must set
+ * Values: <kHz>
+ */
+ u16 if_dvbt_6;
+ u16 if_dvbt_7;
+ u16 if_dvbt_8;
+ u16 if_dvbt2_5;
+ u16 if_dvbt2_6;
+ u16 if_dvbt2_7;
+ u16 if_dvbt2_8;
+ u16 if_dvbc;
+
+ /* GPIOs for all used modes.
+ * Default: none, disabled
+ * Values: <see above>
+ */
+ u8 gpio_dvbt[3];
+ u8 gpio_dvbt2[3];
+ u8 gpio_dvbc[3];
+};
+
+
+#if defined(CONFIG_DVB_CXD2820R) || \
+ (defined(CONFIG_DVB_CXD2820R_MODULE) && defined(MODULE))
+extern struct dvb_frontend *cxd2820r_attach(
+ const struct cxd2820r_config *config,
+ struct i2c_adapter *i2c,
+ struct dvb_frontend *fe
+);
+extern struct i2c_adapter *cxd2820r_get_tuner_i2c_adapter(
+ struct dvb_frontend *fe
+);
+#else
+static inline struct dvb_frontend *cxd2820r_attach(
+ const struct cxd2820r_config *config,
+ struct i2c_adapter *i2c,
+ struct dvb_frontend *fe
+)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+static inline struct i2c_adapter *cxd2820r_get_tuner_i2c_adapter(
+ struct dvb_frontend *fe
+)
+{
+ return NULL;
+}
+
+#endif
+
+#endif /* CXD2820R_H */
diff --git a/drivers/media/dvb/frontends/cxd2820r_c.c b/drivers/media/dvb/frontends/cxd2820r_c.c
new file mode 100644
index 000000000000..3c07d400731d
--- /dev/null
+++ b/drivers/media/dvb/frontends/cxd2820r_c.c
@@ -0,0 +1,338 @@
+/*
+ * Sony CXD2820R demodulator driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 "cxd2820r_priv.h"
+
+int cxd2820r_set_frontend_c(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret, i;
+ u8 buf[2];
+ u16 if_ctl;
+ u64 num;
+ struct reg_val_mask tab[] = {
+ { 0x00080, 0x01, 0xff },
+ { 0x00081, 0x05, 0xff },
+ { 0x00085, 0x07, 0xff },
+ { 0x00088, 0x01, 0xff },
+
+ { 0x00082, 0x20, 0x60 },
+ { 0x1016a, 0x48, 0xff },
+ { 0x100a5, 0x00, 0x01 },
+ { 0x10020, 0x06, 0x07 },
+ { 0x10059, 0x50, 0xff },
+ { 0x10087, 0x0c, 0x3c },
+ { 0x1008b, 0x07, 0xff },
+ { 0x1001f, priv->cfg.if_agc_polarity << 7, 0x80 },
+ { 0x10070, priv->cfg.ts_mode, 0xff },
+ };
+
+ dbg("%s: RF=%d SR=%d", __func__, c->frequency, c->symbol_rate);
+
+ /* update GPIOs */
+ ret = cxd2820r_gpio(fe);
+ if (ret)
+ goto error;
+
+ /* program tuner */
+ if (fe->ops.tuner_ops.set_params)
+ fe->ops.tuner_ops.set_params(fe, params);
+
+ if (priv->delivery_system != SYS_DVBC_ANNEX_AC) {
+ for (i = 0; i < ARRAY_SIZE(tab); i++) {
+ ret = cxd2820r_wr_reg_mask(priv, tab[i].reg,
+ tab[i].val, tab[i].mask);
+ if (ret)
+ goto error;
+ }
+ }
+
+ priv->delivery_system = SYS_DVBC_ANNEX_AC;
+ priv->ber_running = 0; /* tune stops BER counter */
+
+ num = priv->cfg.if_dvbc;
+ num *= 0x4000;
+ if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
+ buf[0] = (if_ctl >> 8) & 0x3f;
+ buf[1] = (if_ctl >> 0) & 0xff;
+
+ ret = cxd2820r_wr_regs(priv, 0x10042, buf, 2);
+ if (ret)
+ goto error;
+
+ ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08);
+ if (ret)
+ goto error;
+
+ ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01);
+ if (ret)
+ goto error;
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_get_frontend_c(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret;
+ u8 buf[2];
+
+ ret = cxd2820r_rd_regs(priv, 0x1001a, buf, 2);
+ if (ret)
+ goto error;
+
+ c->symbol_rate = 2500 * ((buf[0] & 0x0f) << 8 | buf[1]);
+
+ ret = cxd2820r_rd_reg(priv, 0x10019, &buf[0]);
+ if (ret)
+ goto error;
+
+ switch ((buf[0] >> 0) & 0x03) {
+ case 0:
+ c->modulation = QAM_16;
+ break;
+ case 1:
+ c->modulation = QAM_32;
+ break;
+ case 2:
+ c->modulation = QAM_64;
+ break;
+ case 3:
+ c->modulation = QAM_128;
+ break;
+ case 4:
+ c->modulation = QAM_256;
+ break;
+ }
+
+ switch ((buf[0] >> 7) & 0x01) {
+ case 0:
+ c->inversion = INVERSION_OFF;
+ break;
+ case 1:
+ c->inversion = INVERSION_ON;
+ break;
+ }
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_read_ber_c(struct dvb_frontend *fe, u32 *ber)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+ u8 buf[3], start_ber = 0;
+ *ber = 0;
+
+ if (priv->ber_running) {
+ ret = cxd2820r_rd_regs(priv, 0x10076, buf, sizeof(buf));
+ if (ret)
+ goto error;
+
+ if ((buf[2] >> 7) & 0x01 || (buf[2] >> 4) & 0x01) {
+ *ber = (buf[2] & 0x0f) << 16 | buf[1] << 8 | buf[0];
+ start_ber = 1;
+ }
+ } else {
+ priv->ber_running = 1;
+ start_ber = 1;
+ }
+
+ if (start_ber) {
+ /* (re)start BER */
+ ret = cxd2820r_wr_reg(priv, 0x10079, 0x01);
+ if (ret)
+ goto error;
+ }
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_read_signal_strength_c(struct dvb_frontend *fe,
+ u16 *strength)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+ u8 buf[2];
+ u16 tmp;
+
+ ret = cxd2820r_rd_regs(priv, 0x10049, buf, sizeof(buf));
+ if (ret)
+ goto error;
+
+ tmp = (buf[0] & 0x03) << 8 | buf[1];
+ tmp = (~tmp & 0x03ff);
+
+ if (tmp == 512)
+ /* ~no signal */
+ tmp = 0;
+ else if (tmp > 350)
+ tmp = 350;
+
+ /* scale value to 0x0000-0xffff */
+ *strength = tmp * 0xffff / (350-0);
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_read_snr_c(struct dvb_frontend *fe, u16 *snr)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+ u8 tmp;
+ unsigned int A, B;
+ /* report SNR in dB * 10 */
+
+ ret = cxd2820r_rd_reg(priv, 0x10019, &tmp);
+ if (ret)
+ goto error;
+
+ if (((tmp >> 0) & 0x03) % 2) {
+ A = 875;
+ B = 650;
+ } else {
+ A = 950;
+ B = 760;
+ }
+
+ ret = cxd2820r_rd_reg(priv, 0x1004d, &tmp);
+ if (ret)
+ goto error;
+
+ #define CXD2820R_LOG2_E_24 24204406 /* log2(e) << 24 */
+ if (tmp)
+ *snr = A * (intlog2(B / tmp) >> 5) / (CXD2820R_LOG2_E_24 >> 5)
+ / 10;
+ else
+ *snr = 0;
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_read_ucblocks_c(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ *ucblocks = 0;
+ /* no way to read ? */
+ return 0;
+}
+
+int cxd2820r_read_status_c(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+ u8 buf[2];
+ *status = 0;
+
+ ret = cxd2820r_rd_regs(priv, 0x10088, buf, sizeof(buf));
+ if (ret)
+ goto error;
+
+ if (((buf[0] >> 0) & 0x01) == 1) {
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI | FE_HAS_SYNC;
+
+ if (((buf[1] >> 3) & 0x01) == 1) {
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+ }
+ }
+
+ dbg("%s: lock=%02x %02x", __func__, buf[0], buf[1]);
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_init_c(struct dvb_frontend *fe)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+
+ ret = cxd2820r_wr_reg(priv, 0x00085, 0x07);
+ if (ret)
+ goto error;
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_sleep_c(struct dvb_frontend *fe)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret, i;
+ struct reg_val_mask tab[] = {
+ { 0x000ff, 0x1f, 0xff },
+ { 0x00085, 0x00, 0xff },
+ { 0x00088, 0x01, 0xff },
+ { 0x00081, 0x00, 0xff },
+ { 0x00080, 0x00, 0xff },
+ };
+
+ dbg("%s", __func__);
+
+ priv->delivery_system = SYS_UNDEFINED;
+
+ for (i = 0; i < ARRAY_SIZE(tab); i++) {
+ ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val,
+ tab[i].mask);
+ if (ret)
+ goto error;
+ }
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_get_tune_settings_c(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *s)
+{
+ s->min_delay_ms = 500;
+ s->step_size = 0; /* no zigzag */
+ s->max_drift = 0;
+
+ return 0;
+}
+
diff --git a/drivers/media/dvb/frontends/cxd2820r_core.c b/drivers/media/dvb/frontends/cxd2820r_core.c
new file mode 100644
index 000000000000..0779f69db793
--- /dev/null
+++ b/drivers/media/dvb/frontends/cxd2820r_core.c
@@ -0,0 +1,915 @@
+/*
+ * Sony CXD2820R demodulator driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 "cxd2820r_priv.h"
+
+int cxd2820r_debug;
+module_param_named(debug, cxd2820r_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+/* write multiple registers */
+static int cxd2820r_wr_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg,
+ u8 *val, int len)
+{
+ int ret;
+ u8 buf[len+1];
+ struct i2c_msg msg[1] = {
+ {
+ .addr = i2c,
+ .flags = 0,
+ .len = sizeof(buf),
+ .buf = buf,
+ }
+ };
+
+ buf[0] = reg;
+ memcpy(&buf[1], val, len);
+
+ ret = i2c_transfer(priv->i2c, msg, 1);
+ if (ret == 1) {
+ ret = 0;
+ } else {
+ warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len);
+ ret = -EREMOTEIO;
+ }
+ return ret;
+}
+
+/* read multiple registers */
+static int cxd2820r_rd_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg,
+ u8 *val, int len)
+{
+ int ret;
+ u8 buf[len];
+ struct i2c_msg msg[2] = {
+ {
+ .addr = i2c,
+ .flags = 0,
+ .len = 1,
+ .buf = &reg,
+ }, {
+ .addr = i2c,
+ .flags = I2C_M_RD,
+ .len = sizeof(buf),
+ .buf = buf,
+ }
+ };
+
+ ret = i2c_transfer(priv->i2c, msg, 2);
+ if (ret == 2) {
+ memcpy(val, buf, len);
+ ret = 0;
+ } else {
+ warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len);
+ ret = -EREMOTEIO;
+ }
+
+ return ret;
+}
+
+/* write multiple registers */
+int cxd2820r_wr_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
+ int len)
+{
+ int ret;
+ u8 i2c_addr;
+ u8 reg = (reginfo >> 0) & 0xff;
+ u8 bank = (reginfo >> 8) & 0xff;
+ u8 i2c = (reginfo >> 16) & 0x01;
+
+ /* select I2C */
+ if (i2c)
+ i2c_addr = priv->cfg.i2c_address | (1 << 1); /* DVB-C */
+ else
+ i2c_addr = priv->cfg.i2c_address; /* DVB-T/T2 */
+
+ /* switch bank if needed */
+ if (bank != priv->bank[i2c]) {
+ ret = cxd2820r_wr_regs_i2c(priv, i2c_addr, 0x00, &bank, 1);
+ if (ret)
+ return ret;
+ priv->bank[i2c] = bank;
+ }
+ return cxd2820r_wr_regs_i2c(priv, i2c_addr, reg, val, len);
+}
+
+/* read multiple registers */
+int cxd2820r_rd_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
+ int len)
+{
+ int ret;
+ u8 i2c_addr;
+ u8 reg = (reginfo >> 0) & 0xff;
+ u8 bank = (reginfo >> 8) & 0xff;
+ u8 i2c = (reginfo >> 16) & 0x01;
+
+ /* select I2C */
+ if (i2c)
+ i2c_addr = priv->cfg.i2c_address | (1 << 1); /* DVB-C */
+ else
+ i2c_addr = priv->cfg.i2c_address; /* DVB-T/T2 */
+
+ /* switch bank if needed */
+ if (bank != priv->bank[i2c]) {
+ ret = cxd2820r_wr_regs_i2c(priv, i2c_addr, 0x00, &bank, 1);
+ if (ret)
+ return ret;
+ priv->bank[i2c] = bank;
+ }
+ return cxd2820r_rd_regs_i2c(priv, i2c_addr, reg, val, len);
+}
+
+/* write single register */
+int cxd2820r_wr_reg(struct cxd2820r_priv *priv, u32 reg, u8 val)
+{
+ return cxd2820r_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register */
+int cxd2820r_rd_reg(struct cxd2820r_priv *priv, u32 reg, u8 *val)
+{
+ return cxd2820r_rd_regs(priv, reg, val, 1);
+}
+
+/* write single register with mask */
+int cxd2820r_wr_reg_mask(struct cxd2820r_priv *priv, u32 reg, u8 val,
+ u8 mask)
+{
+ int ret;
+ u8 tmp;
+
+ /* no need for read if whole reg is written */
+ if (mask != 0xff) {
+ ret = cxd2820r_rd_reg(priv, reg, &tmp);
+ if (ret)
+ return ret;
+
+ val &= mask;
+ tmp &= ~mask;
+ val |= tmp;
+ }
+
+ return cxd2820r_wr_reg(priv, reg, val);
+}
+
+int cxd2820r_gpio(struct dvb_frontend *fe)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret, i;
+ u8 *gpio, tmp0, tmp1;
+ dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+ switch (fe->dtv_property_cache.delivery_system) {
+ case SYS_DVBT:
+ gpio = priv->cfg.gpio_dvbt;
+ break;
+ case SYS_DVBT2:
+ gpio = priv->cfg.gpio_dvbt2;
+ break;
+ case SYS_DVBC_ANNEX_AC:
+ gpio = priv->cfg.gpio_dvbc;
+ break;
+ default:
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* update GPIOs only when needed */
+ if (!memcmp(gpio, priv->gpio, sizeof(priv->gpio)))
+ return 0;
+
+ tmp0 = 0x00;
+ tmp1 = 0x00;
+ for (i = 0; i < sizeof(priv->gpio); i++) {
+ /* enable / disable */
+ if (gpio[i] & CXD2820R_GPIO_E)
+ tmp0 |= (2 << 6) >> (2 * i);
+ else
+ tmp0 |= (1 << 6) >> (2 * i);
+
+ /* input / output */
+ if (gpio[i] & CXD2820R_GPIO_I)
+ tmp1 |= (1 << (3 + i));
+ else
+ tmp1 |= (0 << (3 + i));
+
+ /* high / low */
+ if (gpio[i] & CXD2820R_GPIO_H)
+ tmp1 |= (1 << (0 + i));
+ else
+ tmp1 |= (0 << (0 + i));
+
+ dbg("%s: GPIO i=%d %02x %02x", __func__, i, tmp0, tmp1);
+ }
+
+ dbg("%s: wr gpio=%02x %02x", __func__, tmp0, tmp1);
+
+ /* write bits [7:2] */
+ ret = cxd2820r_wr_reg_mask(priv, 0x00089, tmp0, 0xfc);
+ if (ret)
+ goto error;
+
+ /* write bits [5:0] */
+ ret = cxd2820r_wr_reg_mask(priv, 0x0008e, tmp1, 0x3f);
+ if (ret)
+ goto error;
+
+ memcpy(priv->gpio, gpio, sizeof(priv->gpio));
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+/* lock FE */
+static int cxd2820r_lock(struct cxd2820r_priv *priv, int active_fe)
+{
+ int ret = 0;
+ dbg("%s: active_fe=%d", __func__, active_fe);
+
+ mutex_lock(&priv->fe_lock);
+
+ /* -1=NONE, 0=DVB-T/T2, 1=DVB-C */
+ if (priv->active_fe == active_fe)
+ ;
+ else if (priv->active_fe == -1)
+ priv->active_fe = active_fe;
+ else
+ ret = -EBUSY;
+
+ mutex_unlock(&priv->fe_lock);
+
+ return ret;
+}
+
+/* unlock FE */
+static void cxd2820r_unlock(struct cxd2820r_priv *priv, int active_fe)
+{
+ dbg("%s: active_fe=%d", __func__, active_fe);
+
+ mutex_lock(&priv->fe_lock);
+
+ /* -1=NONE, 0=DVB-T/T2, 1=DVB-C */
+ if (priv->active_fe == active_fe)
+ priv->active_fe = -1;
+
+ mutex_unlock(&priv->fe_lock);
+
+ return;
+}
+
+/* 64 bit div with round closest, like DIV_ROUND_CLOSEST but 64 bit */
+u32 cxd2820r_div_u64_round_closest(u64 dividend, u32 divisor)
+{
+ return div_u64(dividend + (divisor / 2), divisor);
+}
+
+static int cxd2820r_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret;
+ dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+ if (fe->ops.info.type == FE_OFDM) {
+ /* DVB-T/T2 */
+ ret = cxd2820r_lock(priv, 0);
+ if (ret)
+ return ret;
+
+ switch (priv->delivery_system) {
+ case SYS_UNDEFINED:
+ if (c->delivery_system == SYS_DVBT) {
+ /* SLEEP => DVB-T */
+ ret = cxd2820r_set_frontend_t(fe, p);
+ } else {
+ /* SLEEP => DVB-T2 */
+ ret = cxd2820r_set_frontend_t2(fe, p);
+ }
+ break;
+ case SYS_DVBT:
+ if (c->delivery_system == SYS_DVBT) {
+ /* DVB-T => DVB-T */
+ ret = cxd2820r_set_frontend_t(fe, p);
+ } else if (c->delivery_system == SYS_DVBT2) {
+ /* DVB-T => DVB-T2 */
+ ret = cxd2820r_sleep_t(fe);
+ ret = cxd2820r_set_frontend_t2(fe, p);
+ }
+ break;
+ case SYS_DVBT2:
+ if (c->delivery_system == SYS_DVBT2) {
+ /* DVB-T2 => DVB-T2 */
+ ret = cxd2820r_set_frontend_t2(fe, p);
+ } else if (c->delivery_system == SYS_DVBT) {
+ /* DVB-T2 => DVB-T */
+ ret = cxd2820r_sleep_t2(fe);
+ ret = cxd2820r_set_frontend_t(fe, p);
+ }
+ break;
+ default:
+ dbg("%s: error state=%d", __func__,
+ priv->delivery_system);
+ ret = -EINVAL;
+ }
+ } else {
+ /* DVB-C */
+ ret = cxd2820r_lock(priv, 1);
+ if (ret)
+ return ret;
+
+ ret = cxd2820r_set_frontend_c(fe, p);
+ }
+
+ return ret;
+}
+
+static int cxd2820r_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+ dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+ if (fe->ops.info.type == FE_OFDM) {
+ /* DVB-T/T2 */
+ ret = cxd2820r_lock(priv, 0);
+ if (ret)
+ return ret;
+
+ switch (fe->dtv_property_cache.delivery_system) {
+ case SYS_DVBT:
+ ret = cxd2820r_read_status_t(fe, status);
+ break;
+ case SYS_DVBT2:
+ ret = cxd2820r_read_status_t2(fe, status);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ } else {
+ /* DVB-C */
+ ret = cxd2820r_lock(priv, 1);
+ if (ret)
+ return ret;
+
+ ret = cxd2820r_read_status_c(fe, status);
+ }
+
+ return ret;
+}
+
+static int cxd2820r_get_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+ dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+ if (fe->ops.info.type == FE_OFDM) {
+ /* DVB-T/T2 */
+ ret = cxd2820r_lock(priv, 0);
+ if (ret)
+ return ret;
+
+ switch (fe->dtv_property_cache.delivery_system) {
+ case SYS_DVBT:
+ ret = cxd2820r_get_frontend_t(fe, p);
+ break;
+ case SYS_DVBT2:
+ ret = cxd2820r_get_frontend_t2(fe, p);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ } else {
+ /* DVB-C */
+ ret = cxd2820r_lock(priv, 1);
+ if (ret)
+ return ret;
+
+ ret = cxd2820r_get_frontend_c(fe, p);
+ }
+
+ return ret;
+}
+
+static int cxd2820r_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+ dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+ if (fe->ops.info.type == FE_OFDM) {
+ /* DVB-T/T2 */
+ ret = cxd2820r_lock(priv, 0);
+ if (ret)
+ return ret;
+
+ switch (fe->dtv_property_cache.delivery_system) {
+ case SYS_DVBT:
+ ret = cxd2820r_read_ber_t(fe, ber);
+ break;
+ case SYS_DVBT2:
+ ret = cxd2820r_read_ber_t2(fe, ber);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ } else {
+ /* DVB-C */
+ ret = cxd2820r_lock(priv, 1);
+ if (ret)
+ return ret;
+
+ ret = cxd2820r_read_ber_c(fe, ber);
+ }
+
+ return ret;
+}
+
+static int cxd2820r_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+ dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+ if (fe->ops.info.type == FE_OFDM) {
+ /* DVB-T/T2 */
+ ret = cxd2820r_lock(priv, 0);
+ if (ret)
+ return ret;
+
+ switch (fe->dtv_property_cache.delivery_system) {
+ case SYS_DVBT:
+ ret = cxd2820r_read_signal_strength_t(fe, strength);
+ break;
+ case SYS_DVBT2:
+ ret = cxd2820r_read_signal_strength_t2(fe, strength);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ } else {
+ /* DVB-C */
+ ret = cxd2820r_lock(priv, 1);
+ if (ret)
+ return ret;
+
+ ret = cxd2820r_read_signal_strength_c(fe, strength);
+ }
+
+ return ret;
+}
+
+static int cxd2820r_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+ dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+ if (fe->ops.info.type == FE_OFDM) {
+ /* DVB-T/T2 */
+ ret = cxd2820r_lock(priv, 0);
+ if (ret)
+ return ret;
+
+ switch (fe->dtv_property_cache.delivery_system) {
+ case SYS_DVBT:
+ ret = cxd2820r_read_snr_t(fe, snr);
+ break;
+ case SYS_DVBT2:
+ ret = cxd2820r_read_snr_t2(fe, snr);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ } else {
+ /* DVB-C */
+ ret = cxd2820r_lock(priv, 1);
+ if (ret)
+ return ret;
+
+ ret = cxd2820r_read_snr_c(fe, snr);
+ }
+
+ return ret;
+}
+
+static int cxd2820r_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+ dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+ if (fe->ops.info.type == FE_OFDM) {
+ /* DVB-T/T2 */
+ ret = cxd2820r_lock(priv, 0);
+ if (ret)
+ return ret;
+
+ switch (fe->dtv_property_cache.delivery_system) {
+ case SYS_DVBT:
+ ret = cxd2820r_read_ucblocks_t(fe, ucblocks);
+ break;
+ case SYS_DVBT2:
+ ret = cxd2820r_read_ucblocks_t2(fe, ucblocks);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ } else {
+ /* DVB-C */
+ ret = cxd2820r_lock(priv, 1);
+ if (ret)
+ return ret;
+
+ ret = cxd2820r_read_ucblocks_c(fe, ucblocks);
+ }
+
+ return ret;
+}
+
+static int cxd2820r_init(struct dvb_frontend *fe)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+ dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+ priv->delivery_system = SYS_UNDEFINED;
+ /* delivery system is unknown at that (init) phase */
+
+ if (fe->ops.info.type == FE_OFDM) {
+ /* DVB-T/T2 */
+ ret = cxd2820r_lock(priv, 0);
+ if (ret)
+ return ret;
+
+ ret = cxd2820r_init_t(fe);
+ } else {
+ /* DVB-C */
+ ret = cxd2820r_lock(priv, 1);
+ if (ret)
+ return ret;
+
+ ret = cxd2820r_init_c(fe);
+ }
+
+ return ret;
+}
+
+static int cxd2820r_sleep(struct dvb_frontend *fe)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+ dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+ if (fe->ops.info.type == FE_OFDM) {
+ /* DVB-T/T2 */
+ ret = cxd2820r_lock(priv, 0);
+ if (ret)
+ return ret;
+
+ switch (fe->dtv_property_cache.delivery_system) {
+ case SYS_DVBT:
+ ret = cxd2820r_sleep_t(fe);
+ break;
+ case SYS_DVBT2:
+ ret = cxd2820r_sleep_t2(fe);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ cxd2820r_unlock(priv, 0);
+ } else {
+ /* DVB-C */
+ ret = cxd2820r_lock(priv, 1);
+ if (ret)
+ return ret;
+
+ ret = cxd2820r_sleep_c(fe);
+
+ cxd2820r_unlock(priv, 1);
+ }
+
+ return ret;
+}
+
+static int cxd2820r_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *s)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+ dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+ if (fe->ops.info.type == FE_OFDM) {
+ /* DVB-T/T2 */
+ ret = cxd2820r_lock(priv, 0);
+ if (ret)
+ return ret;
+
+ switch (fe->dtv_property_cache.delivery_system) {
+ case SYS_DVBT:
+ ret = cxd2820r_get_tune_settings_t(fe, s);
+ break;
+ case SYS_DVBT2:
+ ret = cxd2820r_get_tune_settings_t2(fe, s);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ } else {
+ /* DVB-C */
+ ret = cxd2820r_lock(priv, 1);
+ if (ret)
+ return ret;
+
+ ret = cxd2820r_get_tune_settings_c(fe, s);
+ }
+
+ return ret;
+}
+
+static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret, i;
+ fe_status_t status = 0;
+ dbg("%s: delsys=%d", __func__, fe->dtv_property_cache.delivery_system);
+
+ /* switch between DVB-T and DVB-T2 when tune fails */
+ if (priv->last_tune_failed) {
+ if (priv->delivery_system == SYS_DVBT)
+ c->delivery_system = SYS_DVBT2;
+ else
+ c->delivery_system = SYS_DVBT;
+ }
+
+ /* set frontend */
+ ret = cxd2820r_set_frontend(fe, p);
+ if (ret)
+ goto error;
+
+
+ /* frontend lock wait loop count */
+ switch (priv->delivery_system) {
+ case SYS_DVBT:
+ i = 20;
+ break;
+ case SYS_DVBT2:
+ i = 40;
+ break;
+ case SYS_UNDEFINED:
+ default:
+ i = 0;
+ break;
+ }
+
+ /* wait frontend lock */
+ for (; i > 0; i--) {
+ dbg("%s: LOOP=%d", __func__, i);
+ msleep(50);
+ ret = cxd2820r_read_status(fe, &status);
+ if (ret)
+ goto error;
+
+ if (status & FE_HAS_SIGNAL)
+ break;
+ }
+
+ /* check if we have a valid signal */
+ if (status) {
+ priv->last_tune_failed = 0;
+ return DVBFE_ALGO_SEARCH_SUCCESS;
+ } else {
+ priv->last_tune_failed = 1;
+ return DVBFE_ALGO_SEARCH_AGAIN;
+ }
+
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return DVBFE_ALGO_SEARCH_ERROR;
+}
+
+static int cxd2820r_get_frontend_algo(struct dvb_frontend *fe)
+{
+ return DVBFE_ALGO_CUSTOM;
+}
+
+static void cxd2820r_release(struct dvb_frontend *fe)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ dbg("%s", __func__);
+
+ if (fe->ops.info.type == FE_OFDM) {
+ i2c_del_adapter(&priv->tuner_i2c_adapter);
+ kfree(priv);
+ }
+
+ return;
+}
+
+static u32 cxd2820r_tuner_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static int cxd2820r_tuner_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msg[], int num)
+{
+ struct cxd2820r_priv *priv = i2c_get_adapdata(i2c_adap);
+ u8 obuf[msg[0].len + 2];
+ struct i2c_msg msg2[2] = {
+ {
+ .addr = priv->cfg.i2c_address,
+ .flags = 0,
+ .len = sizeof(obuf),
+ .buf = obuf,
+ }, {
+ .addr = priv->cfg.i2c_address,
+ .flags = I2C_M_RD,
+ .len = msg[1].len,
+ .buf = msg[1].buf,
+ }
+ };
+
+ obuf[0] = 0x09;
+ obuf[1] = (msg[0].addr << 1);
+ if (num == 2) { /* I2C read */
+ obuf[1] = (msg[0].addr << 1) | I2C_M_RD; /* I2C RD flag */
+ msg2[0].len = sizeof(obuf) - 1; /* maybe HW bug ? */
+ }
+ memcpy(&obuf[2], msg[0].buf, msg[0].len);
+
+ return i2c_transfer(priv->i2c, msg2, num);
+}
+
+static struct i2c_algorithm cxd2820r_tuner_i2c_algo = {
+ .master_xfer = cxd2820r_tuner_i2c_xfer,
+ .functionality = cxd2820r_tuner_i2c_func,
+};
+
+struct i2c_adapter *cxd2820r_get_tuner_i2c_adapter(struct dvb_frontend *fe)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ return &priv->tuner_i2c_adapter;
+}
+EXPORT_SYMBOL(cxd2820r_get_tuner_i2c_adapter);
+
+static struct dvb_frontend_ops cxd2820r_ops[2];
+
+struct dvb_frontend *cxd2820r_attach(const struct cxd2820r_config *cfg,
+ struct i2c_adapter *i2c, struct dvb_frontend *fe)
+{
+ int ret;
+ struct cxd2820r_priv *priv = NULL;
+ u8 tmp;
+
+ if (fe == NULL) {
+ /* FE0 */
+ /* allocate memory for the internal priv */
+ priv = kzalloc(sizeof(struct cxd2820r_priv), GFP_KERNEL);
+ if (priv == NULL)
+ goto error;
+
+ /* setup the priv */
+ priv->i2c = i2c;
+ memcpy(&priv->cfg, cfg, sizeof(struct cxd2820r_config));
+ mutex_init(&priv->fe_lock);
+
+ priv->active_fe = -1; /* NONE */
+
+ /* check if the demod is there */
+ priv->bank[0] = priv->bank[1] = 0xff;
+ ret = cxd2820r_rd_reg(priv, 0x000fd, &tmp);
+ dbg("%s: chip id=%02x", __func__, tmp);
+ if (ret || tmp != 0xe1)
+ goto error;
+
+ /* create frontends */
+ memcpy(&priv->fe[0].ops, &cxd2820r_ops[0],
+ sizeof(struct dvb_frontend_ops));
+ memcpy(&priv->fe[1].ops, &cxd2820r_ops[1],
+ sizeof(struct dvb_frontend_ops));
+
+ priv->fe[0].demodulator_priv = priv;
+ priv->fe[1].demodulator_priv = priv;
+
+ /* create tuner i2c adapter */
+ strlcpy(priv->tuner_i2c_adapter.name,
+ "CXD2820R tuner I2C adapter",
+ sizeof(priv->tuner_i2c_adapter.name));
+ priv->tuner_i2c_adapter.algo = &cxd2820r_tuner_i2c_algo;
+ priv->tuner_i2c_adapter.algo_data = NULL;
+ i2c_set_adapdata(&priv->tuner_i2c_adapter, priv);
+ if (i2c_add_adapter(&priv->tuner_i2c_adapter) < 0) {
+ err("tuner I2C bus could not be initialized");
+ goto error;
+ }
+
+ return &priv->fe[0];
+
+ } else {
+ /* FE1: FE0 given as pointer, just return FE1 we have
+ * already created */
+ priv = fe->demodulator_priv;
+ return &priv->fe[1];
+ }
+
+error:
+ kfree(priv);
+ return NULL;
+}
+EXPORT_SYMBOL(cxd2820r_attach);
+
+static struct dvb_frontend_ops cxd2820r_ops[2] = {
+ {
+ /* DVB-T/T2 */
+ .info = {
+ .name = "Sony CXD2820R (DVB-T/T2)",
+ .type = FE_OFDM,
+ .caps =
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+ FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 |
+ FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_QAM_16 |
+ FE_CAN_QAM_64 | FE_CAN_QAM_256 |
+ FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO |
+ FE_CAN_MUTE_TS |
+ FE_CAN_2G_MODULATION
+ },
+
+ .release = cxd2820r_release,
+ .init = cxd2820r_init,
+ .sleep = cxd2820r_sleep,
+
+ .get_tune_settings = cxd2820r_get_tune_settings,
+
+ .get_frontend = cxd2820r_get_frontend,
+
+ .get_frontend_algo = cxd2820r_get_frontend_algo,
+ .search = cxd2820r_search,
+
+ .read_status = cxd2820r_read_status,
+ .read_snr = cxd2820r_read_snr,
+ .read_ber = cxd2820r_read_ber,
+ .read_ucblocks = cxd2820r_read_ucblocks,
+ .read_signal_strength = cxd2820r_read_signal_strength,
+ },
+ {
+ /* DVB-C */
+ .info = {
+ .name = "Sony CXD2820R (DVB-C)",
+ .type = FE_QAM,
+ .caps =
+ FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
+ FE_CAN_QAM_128 | FE_CAN_QAM_256 |
+ FE_CAN_FEC_AUTO
+ },
+
+ .release = cxd2820r_release,
+ .init = cxd2820r_init,
+ .sleep = cxd2820r_sleep,
+
+ .get_tune_settings = cxd2820r_get_tune_settings,
+
+ .set_frontend = cxd2820r_set_frontend,
+ .get_frontend = cxd2820r_get_frontend,
+
+ .read_status = cxd2820r_read_status,
+ .read_snr = cxd2820r_read_snr,
+ .read_ber = cxd2820r_read_ber,
+ .read_ucblocks = cxd2820r_read_ucblocks,
+ .read_signal_strength = cxd2820r_read_signal_strength,
+ },
+};
+
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Sony CXD2820R demodulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/cxd2820r_priv.h b/drivers/media/dvb/frontends/cxd2820r_priv.h
new file mode 100644
index 000000000000..25adbeefa6d3
--- /dev/null
+++ b/drivers/media/dvb/frontends/cxd2820r_priv.h
@@ -0,0 +1,166 @@
+/*
+ * Sony CXD2820R demodulator driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#ifndef CXD2820R_PRIV_H
+#define CXD2820R_PRIV_H
+
+#include <linux/dvb/version.h>
+#include "dvb_frontend.h"
+#include "dvb_math.h"
+#include "cxd2820r.h"
+
+#define LOG_PREFIX "cxd2820r"
+
+#undef dbg
+#define dbg(f, arg...) \
+ if (cxd2820r_debug) \
+ printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg)
+#undef err
+#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+struct reg_val_mask {
+ u32 reg;
+ u8 val;
+ u8 mask;
+};
+
+struct cxd2820r_priv {
+ struct i2c_adapter *i2c;
+ struct dvb_frontend fe[2];
+ struct cxd2820r_config cfg;
+ struct i2c_adapter tuner_i2c_adapter;
+
+ struct mutex fe_lock; /* FE lock */
+ int active_fe:2; /* FE lock, -1=NONE, 0=DVB-T/T2, 1=DVB-C */
+
+ int ber_running:1;
+
+ u8 bank[2];
+ u8 gpio[3];
+
+ fe_delivery_system_t delivery_system;
+ int last_tune_failed:1; /* for switch between T and T2 tune */
+};
+
+/* cxd2820r_core.c */
+
+extern int cxd2820r_debug;
+
+int cxd2820r_gpio(struct dvb_frontend *fe);
+
+int cxd2820r_wr_reg_mask(struct cxd2820r_priv *priv, u32 reg, u8 val,
+ u8 mask);
+
+int cxd2820r_wr_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
+ int len);
+
+u32 cxd2820r_div_u64_round_closest(u64 dividend, u32 divisor);
+
+int cxd2820r_wr_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
+ int len);
+
+int cxd2820r_rd_regs(struct cxd2820r_priv *priv, u32 reginfo, u8 *val,
+ int len);
+
+int cxd2820r_wr_reg(struct cxd2820r_priv *priv, u32 reg, u8 val);
+
+int cxd2820r_rd_reg(struct cxd2820r_priv *priv, u32 reg, u8 *val);
+
+/* cxd2820r_c.c */
+
+int cxd2820r_get_frontend_c(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p);
+
+int cxd2820r_set_frontend_c(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params);
+
+int cxd2820r_read_status_c(struct dvb_frontend *fe, fe_status_t *status);
+
+int cxd2820r_read_ber_c(struct dvb_frontend *fe, u32 *ber);
+
+int cxd2820r_read_signal_strength_c(struct dvb_frontend *fe, u16 *strength);
+
+int cxd2820r_read_snr_c(struct dvb_frontend *fe, u16 *snr);
+
+int cxd2820r_read_ucblocks_c(struct dvb_frontend *fe, u32 *ucblocks);
+
+int cxd2820r_init_c(struct dvb_frontend *fe);
+
+int cxd2820r_sleep_c(struct dvb_frontend *fe);
+
+int cxd2820r_get_tune_settings_c(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *s);
+
+/* cxd2820r_t.c */
+
+int cxd2820r_get_frontend_t(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p);
+
+int cxd2820r_set_frontend_t(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params);
+
+int cxd2820r_read_status_t(struct dvb_frontend *fe, fe_status_t *status);
+
+int cxd2820r_read_ber_t(struct dvb_frontend *fe, u32 *ber);
+
+int cxd2820r_read_signal_strength_t(struct dvb_frontend *fe, u16 *strength);
+
+int cxd2820r_read_snr_t(struct dvb_frontend *fe, u16 *snr);
+
+int cxd2820r_read_ucblocks_t(struct dvb_frontend *fe, u32 *ucblocks);
+
+int cxd2820r_init_t(struct dvb_frontend *fe);
+
+int cxd2820r_sleep_t(struct dvb_frontend *fe);
+
+int cxd2820r_get_tune_settings_t(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *s);
+
+/* cxd2820r_t2.c */
+
+int cxd2820r_get_frontend_t2(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p);
+
+int cxd2820r_set_frontend_t2(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params);
+
+int cxd2820r_read_status_t2(struct dvb_frontend *fe, fe_status_t *status);
+
+int cxd2820r_read_ber_t2(struct dvb_frontend *fe, u32 *ber);
+
+int cxd2820r_read_signal_strength_t2(struct dvb_frontend *fe, u16 *strength);
+
+int cxd2820r_read_snr_t2(struct dvb_frontend *fe, u16 *snr);
+
+int cxd2820r_read_ucblocks_t2(struct dvb_frontend *fe, u32 *ucblocks);
+
+int cxd2820r_init_t2(struct dvb_frontend *fe);
+
+int cxd2820r_sleep_t2(struct dvb_frontend *fe);
+
+int cxd2820r_get_tune_settings_t2(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *s);
+
+#endif /* CXD2820R_PRIV_H */
diff --git a/drivers/media/dvb/frontends/cxd2820r_t.c b/drivers/media/dvb/frontends/cxd2820r_t.c
new file mode 100644
index 000000000000..6582564c930c
--- /dev/null
+++ b/drivers/media/dvb/frontends/cxd2820r_t.c
@@ -0,0 +1,449 @@
+/*
+ * Sony CXD2820R demodulator driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 "cxd2820r_priv.h"
+
+int cxd2820r_set_frontend_t(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret, i;
+ u32 if_khz, if_ctl;
+ u64 num;
+ u8 buf[3], bw_param;
+ u8 bw_params1[][5] = {
+ { 0x17, 0xea, 0xaa, 0xaa, 0xaa }, /* 6 MHz */
+ { 0x14, 0x80, 0x00, 0x00, 0x00 }, /* 7 MHz */
+ { 0x11, 0xf0, 0x00, 0x00, 0x00 }, /* 8 MHz */
+ };
+ u8 bw_params2[][2] = {
+ { 0x1f, 0xdc }, /* 6 MHz */
+ { 0x12, 0xf8 }, /* 7 MHz */
+ { 0x01, 0xe0 }, /* 8 MHz */
+ };
+ struct reg_val_mask tab[] = {
+ { 0x00080, 0x00, 0xff },
+ { 0x00081, 0x03, 0xff },
+ { 0x00085, 0x07, 0xff },
+ { 0x00088, 0x01, 0xff },
+
+ { 0x00070, priv->cfg.ts_mode, 0xff },
+ { 0x000cb, priv->cfg.if_agc_polarity << 6, 0x40 },
+ { 0x000a5, 0x00, 0x01 },
+ { 0x00082, 0x20, 0x60 },
+ { 0x000c2, 0xc3, 0xff },
+ { 0x0016a, 0x50, 0xff },
+ { 0x00427, 0x41, 0xff },
+ };
+
+ dbg("%s: RF=%d BW=%d", __func__, c->frequency, c->bandwidth_hz);
+
+ /* update GPIOs */
+ ret = cxd2820r_gpio(fe);
+ if (ret)
+ goto error;
+
+ /* program tuner */
+ if (fe->ops.tuner_ops.set_params)
+ fe->ops.tuner_ops.set_params(fe, p);
+
+ if (priv->delivery_system != SYS_DVBT) {
+ for (i = 0; i < ARRAY_SIZE(tab); i++) {
+ ret = cxd2820r_wr_reg_mask(priv, tab[i].reg,
+ tab[i].val, tab[i].mask);
+ if (ret)
+ goto error;
+ }
+ }
+
+ priv->delivery_system = SYS_DVBT;
+ priv->ber_running = 0; /* tune stops BER counter */
+
+ switch (c->bandwidth_hz) {
+ case 6000000:
+ if_khz = priv->cfg.if_dvbt_6;
+ i = 0;
+ bw_param = 2;
+ break;
+ case 7000000:
+ if_khz = priv->cfg.if_dvbt_7;
+ i = 1;
+ bw_param = 1;
+ break;
+ case 8000000:
+ if_khz = priv->cfg.if_dvbt_8;
+ i = 2;
+ bw_param = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ num = if_khz;
+ num *= 0x1000000;
+ if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
+ buf[0] = ((if_ctl >> 16) & 0xff);
+ buf[1] = ((if_ctl >> 8) & 0xff);
+ buf[2] = ((if_ctl >> 0) & 0xff);
+
+ ret = cxd2820r_wr_regs(priv, 0x000b6, buf, 3);
+ if (ret)
+ goto error;
+
+ ret = cxd2820r_wr_regs(priv, 0x0009f, bw_params1[i], 5);
+ if (ret)
+ goto error;
+
+ ret = cxd2820r_wr_reg_mask(priv, 0x000d7, bw_param << 6, 0xc0);
+ if (ret)
+ goto error;
+
+ ret = cxd2820r_wr_regs(priv, 0x000d9, bw_params2[i], 2);
+ if (ret)
+ goto error;
+
+ ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08);
+ if (ret)
+ goto error;
+
+ ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01);
+ if (ret)
+ goto error;
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_get_frontend_t(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret;
+ u8 buf[2];
+
+ ret = cxd2820r_rd_regs(priv, 0x0002f, buf, sizeof(buf));
+ if (ret)
+ goto error;
+
+ switch ((buf[0] >> 6) & 0x03) {
+ case 0:
+ c->modulation = QPSK;
+ break;
+ case 1:
+ c->modulation = QAM_16;
+ break;
+ case 2:
+ c->modulation = QAM_64;
+ break;
+ }
+
+ switch ((buf[1] >> 1) & 0x03) {
+ case 0:
+ c->transmission_mode = TRANSMISSION_MODE_2K;
+ break;
+ case 1:
+ c->transmission_mode = TRANSMISSION_MODE_8K;
+ break;
+ }
+
+ switch ((buf[1] >> 3) & 0x03) {
+ case 0:
+ c->guard_interval = GUARD_INTERVAL_1_32;
+ break;
+ case 1:
+ c->guard_interval = GUARD_INTERVAL_1_16;
+ break;
+ case 2:
+ c->guard_interval = GUARD_INTERVAL_1_8;
+ break;
+ case 3:
+ c->guard_interval = GUARD_INTERVAL_1_4;
+ break;
+ }
+
+ switch ((buf[0] >> 3) & 0x07) {
+ case 0:
+ c->hierarchy = HIERARCHY_NONE;
+ break;
+ case 1:
+ c->hierarchy = HIERARCHY_1;
+ break;
+ case 2:
+ c->hierarchy = HIERARCHY_2;
+ break;
+ case 3:
+ c->hierarchy = HIERARCHY_4;
+ break;
+ }
+
+ switch ((buf[0] >> 0) & 0x07) {
+ case 0:
+ c->code_rate_HP = FEC_1_2;
+ break;
+ case 1:
+ c->code_rate_HP = FEC_2_3;
+ break;
+ case 2:
+ c->code_rate_HP = FEC_3_4;
+ break;
+ case 3:
+ c->code_rate_HP = FEC_5_6;
+ break;
+ case 4:
+ c->code_rate_HP = FEC_7_8;
+ break;
+ }
+
+ switch ((buf[1] >> 5) & 0x07) {
+ case 0:
+ c->code_rate_LP = FEC_1_2;
+ break;
+ case 1:
+ c->code_rate_LP = FEC_2_3;
+ break;
+ case 2:
+ c->code_rate_LP = FEC_3_4;
+ break;
+ case 3:
+ c->code_rate_LP = FEC_5_6;
+ break;
+ case 4:
+ c->code_rate_LP = FEC_7_8;
+ break;
+ }
+
+ ret = cxd2820r_rd_reg(priv, 0x007c6, &buf[0]);
+ if (ret)
+ goto error;
+
+ switch ((buf[0] >> 0) & 0x01) {
+ case 0:
+ c->inversion = INVERSION_OFF;
+ break;
+ case 1:
+ c->inversion = INVERSION_ON;
+ break;
+ }
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_read_ber_t(struct dvb_frontend *fe, u32 *ber)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+ u8 buf[3], start_ber = 0;
+ *ber = 0;
+
+ if (priv->ber_running) {
+ ret = cxd2820r_rd_regs(priv, 0x00076, buf, sizeof(buf));
+ if (ret)
+ goto error;
+
+ if ((buf[2] >> 7) & 0x01 || (buf[2] >> 4) & 0x01) {
+ *ber = (buf[2] & 0x0f) << 16 | buf[1] << 8 | buf[0];
+ start_ber = 1;
+ }
+ } else {
+ priv->ber_running = 1;
+ start_ber = 1;
+ }
+
+ if (start_ber) {
+ /* (re)start BER */
+ ret = cxd2820r_wr_reg(priv, 0x00079, 0x01);
+ if (ret)
+ goto error;
+ }
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_read_signal_strength_t(struct dvb_frontend *fe,
+ u16 *strength)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+ u8 buf[2];
+ u16 tmp;
+
+ ret = cxd2820r_rd_regs(priv, 0x00026, buf, sizeof(buf));
+ if (ret)
+ goto error;
+
+ tmp = (buf[0] & 0x0f) << 8 | buf[1];
+ tmp = ~tmp & 0x0fff;
+
+ /* scale value to 0x0000-0xffff from 0x0000-0x0fff */
+ *strength = tmp * 0xffff / 0x0fff;
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_read_snr_t(struct dvb_frontend *fe, u16 *snr)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+ u8 buf[2];
+ u16 tmp;
+ /* report SNR in dB * 10 */
+
+ ret = cxd2820r_rd_regs(priv, 0x00028, buf, sizeof(buf));
+ if (ret)
+ goto error;
+
+ tmp = (buf[0] & 0x1f) << 8 | buf[1];
+ #define CXD2820R_LOG10_8_24 15151336 /* log10(8) << 24 */
+ if (tmp)
+ *snr = (intlog10(tmp) - CXD2820R_LOG10_8_24) / ((1 << 24)
+ / 100);
+ else
+ *snr = 0;
+
+ dbg("%s: dBx10=%d val=%04x", __func__, *snr, tmp);
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_read_ucblocks_t(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ *ucblocks = 0;
+ /* no way to read ? */
+ return 0;
+}
+
+int cxd2820r_read_status_t(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+ u8 buf[4];
+ *status = 0;
+
+ ret = cxd2820r_rd_reg(priv, 0x00010, &buf[0]);
+ if (ret)
+ goto error;
+
+ if ((buf[0] & 0x07) == 6) {
+ ret = cxd2820r_rd_reg(priv, 0x00073, &buf[1]);
+ if (ret)
+ goto error;
+
+ if (((buf[1] >> 3) & 0x01) == 1) {
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+ } else {
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI | FE_HAS_SYNC;
+ }
+ } else {
+ ret = cxd2820r_rd_reg(priv, 0x00014, &buf[2]);
+ if (ret)
+ goto error;
+
+ if ((buf[2] & 0x0f) >= 4) {
+ ret = cxd2820r_rd_reg(priv, 0x00a14, &buf[3]);
+ if (ret)
+ goto error;
+
+ if (((buf[3] >> 4) & 0x01) == 1)
+ *status |= FE_HAS_SIGNAL;
+ }
+ }
+
+ dbg("%s: lock=%02x %02x %02x %02x", __func__,
+ buf[0], buf[1], buf[2], buf[3]);
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_init_t(struct dvb_frontend *fe)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+
+ ret = cxd2820r_wr_reg(priv, 0x00085, 0x07);
+ if (ret)
+ goto error;
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_sleep_t(struct dvb_frontend *fe)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret, i;
+ struct reg_val_mask tab[] = {
+ { 0x000ff, 0x1f, 0xff },
+ { 0x00085, 0x00, 0xff },
+ { 0x00088, 0x01, 0xff },
+ { 0x00081, 0x00, 0xff },
+ { 0x00080, 0x00, 0xff },
+ };
+
+ dbg("%s", __func__);
+
+ priv->delivery_system = SYS_UNDEFINED;
+
+ for (i = 0; i < ARRAY_SIZE(tab); i++) {
+ ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val,
+ tab[i].mask);
+ if (ret)
+ goto error;
+ }
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_get_tune_settings_t(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *s)
+{
+ s->min_delay_ms = 500;
+ s->step_size = fe->ops.info.frequency_stepsize * 2;
+ s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
+
+ return 0;
+}
+
diff --git a/drivers/media/dvb/frontends/cxd2820r_t2.c b/drivers/media/dvb/frontends/cxd2820r_t2.c
new file mode 100644
index 000000000000..c47b35c8acf1
--- /dev/null
+++ b/drivers/media/dvb/frontends/cxd2820r_t2.c
@@ -0,0 +1,423 @@
+/*
+ * Sony CXD2820R demodulator driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 "cxd2820r_priv.h"
+
+int cxd2820r_set_frontend_t2(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret, i;
+ u32 if_khz, if_ctl;
+ u64 num;
+ u8 buf[3], bw_param;
+ u8 bw_params1[][5] = {
+ { 0x1c, 0xb3, 0x33, 0x33, 0x33 }, /* 5 MHz */
+ { 0x17, 0xea, 0xaa, 0xaa, 0xaa }, /* 6 MHz */
+ { 0x14, 0x80, 0x00, 0x00, 0x00 }, /* 7 MHz */
+ { 0x11, 0xf0, 0x00, 0x00, 0x00 }, /* 8 MHz */
+ };
+ struct reg_val_mask tab[] = {
+ { 0x00080, 0x02, 0xff },
+ { 0x00081, 0x20, 0xff },
+ { 0x00085, 0x07, 0xff },
+ { 0x00088, 0x01, 0xff },
+ { 0x02069, 0x01, 0xff },
+
+ { 0x0207f, 0x2a, 0xff },
+ { 0x02082, 0x0a, 0xff },
+ { 0x02083, 0x0a, 0xff },
+ { 0x020cb, priv->cfg.if_agc_polarity << 6, 0x40 },
+ { 0x02070, priv->cfg.ts_mode, 0xff },
+ { 0x020b5, priv->cfg.spec_inv << 4, 0x10 },
+ { 0x02567, 0x07, 0x0f },
+ { 0x02569, 0x03, 0x03 },
+ { 0x02595, 0x1a, 0xff },
+ { 0x02596, 0x50, 0xff },
+ { 0x02a8c, 0x00, 0xff },
+ { 0x02a8d, 0x34, 0xff },
+ { 0x02a45, 0x06, 0x07 },
+ { 0x03f10, 0x0d, 0xff },
+ { 0x03f11, 0x02, 0xff },
+ { 0x03f12, 0x01, 0xff },
+ { 0x03f23, 0x2c, 0xff },
+ { 0x03f51, 0x13, 0xff },
+ { 0x03f52, 0x01, 0xff },
+ { 0x03f53, 0x00, 0xff },
+ { 0x027e6, 0x14, 0xff },
+ { 0x02786, 0x02, 0x07 },
+ { 0x02787, 0x40, 0xe0 },
+ { 0x027ef, 0x10, 0x18 },
+ };
+
+ dbg("%s: RF=%d BW=%d", __func__, c->frequency, c->bandwidth_hz);
+
+ /* update GPIOs */
+ ret = cxd2820r_gpio(fe);
+ if (ret)
+ goto error;
+
+ /* program tuner */
+ if (fe->ops.tuner_ops.set_params)
+ fe->ops.tuner_ops.set_params(fe, params);
+
+ if (priv->delivery_system != SYS_DVBT2) {
+ for (i = 0; i < ARRAY_SIZE(tab); i++) {
+ ret = cxd2820r_wr_reg_mask(priv, tab[i].reg,
+ tab[i].val, tab[i].mask);
+ if (ret)
+ goto error;
+ }
+ }
+
+ priv->delivery_system = SYS_DVBT2;
+
+ switch (c->bandwidth_hz) {
+ case 5000000:
+ if_khz = priv->cfg.if_dvbt2_5;
+ i = 0;
+ bw_param = 3;
+ break;
+ case 6000000:
+ if_khz = priv->cfg.if_dvbt2_6;
+ i = 1;
+ bw_param = 2;
+ break;
+ case 7000000:
+ if_khz = priv->cfg.if_dvbt2_7;
+ i = 2;
+ bw_param = 1;
+ break;
+ case 8000000:
+ if_khz = priv->cfg.if_dvbt2_8;
+ i = 3;
+ bw_param = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ num = if_khz;
+ num *= 0x1000000;
+ if_ctl = cxd2820r_div_u64_round_closest(num, 41000);
+ buf[0] = ((if_ctl >> 16) & 0xff);
+ buf[1] = ((if_ctl >> 8) & 0xff);
+ buf[2] = ((if_ctl >> 0) & 0xff);
+
+ ret = cxd2820r_wr_regs(priv, 0x020b6, buf, 3);
+ if (ret)
+ goto error;
+
+ ret = cxd2820r_wr_regs(priv, 0x0209f, bw_params1[i], 5);
+ if (ret)
+ goto error;
+
+ ret = cxd2820r_wr_reg_mask(priv, 0x020d7, bw_param << 6, 0xc0);
+ if (ret)
+ goto error;
+
+ ret = cxd2820r_wr_reg(priv, 0x000ff, 0x08);
+ if (ret)
+ goto error;
+
+ ret = cxd2820r_wr_reg(priv, 0x000fe, 0x01);
+ if (ret)
+ goto error;
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+
+}
+
+int cxd2820r_get_frontend_t2(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret;
+ u8 buf[2];
+
+ ret = cxd2820r_rd_regs(priv, 0x0205c, buf, 2);
+ if (ret)
+ goto error;
+
+ switch ((buf[0] >> 0) & 0x07) {
+ case 0:
+ c->transmission_mode = TRANSMISSION_MODE_2K;
+ break;
+ case 1:
+ c->transmission_mode = TRANSMISSION_MODE_8K;
+ break;
+ case 2:
+ c->transmission_mode = TRANSMISSION_MODE_4K;
+ break;
+ case 3:
+ c->transmission_mode = TRANSMISSION_MODE_1K;
+ break;
+ case 4:
+ c->transmission_mode = TRANSMISSION_MODE_16K;
+ break;
+ case 5:
+ c->transmission_mode = TRANSMISSION_MODE_32K;
+ break;
+ }
+
+ switch ((buf[1] >> 4) & 0x07) {
+ case 0:
+ c->guard_interval = GUARD_INTERVAL_1_32;
+ break;
+ case 1:
+ c->guard_interval = GUARD_INTERVAL_1_16;
+ break;
+ case 2:
+ c->guard_interval = GUARD_INTERVAL_1_8;
+ break;
+ case 3:
+ c->guard_interval = GUARD_INTERVAL_1_4;
+ break;
+ case 4:
+ c->guard_interval = GUARD_INTERVAL_1_128;
+ break;
+ case 5:
+ c->guard_interval = GUARD_INTERVAL_19_128;
+ break;
+ case 6:
+ c->guard_interval = GUARD_INTERVAL_19_256;
+ break;
+ }
+
+ ret = cxd2820r_rd_regs(priv, 0x0225b, buf, 2);
+ if (ret)
+ goto error;
+
+ switch ((buf[0] >> 0) & 0x07) {
+ case 0:
+ c->fec_inner = FEC_1_2;
+ break;
+ case 1:
+ c->fec_inner = FEC_3_5;
+ break;
+ case 2:
+ c->fec_inner = FEC_2_3;
+ break;
+ case 3:
+ c->fec_inner = FEC_3_4;
+ break;
+ case 4:
+ c->fec_inner = FEC_4_5;
+ break;
+ case 5:
+ c->fec_inner = FEC_5_6;
+ break;
+ }
+
+ switch ((buf[1] >> 0) & 0x07) {
+ case 0:
+ c->modulation = QPSK;
+ break;
+ case 1:
+ c->modulation = QAM_16;
+ break;
+ case 2:
+ c->modulation = QAM_64;
+ break;
+ case 3:
+ c->modulation = QAM_256;
+ break;
+ }
+
+ ret = cxd2820r_rd_reg(priv, 0x020b5, &buf[0]);
+ if (ret)
+ goto error;
+
+ switch ((buf[0] >> 4) & 0x01) {
+ case 0:
+ c->inversion = INVERSION_OFF;
+ break;
+ case 1:
+ c->inversion = INVERSION_ON;
+ break;
+ }
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_read_status_t2(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+ u8 buf[1];
+ *status = 0;
+
+ ret = cxd2820r_rd_reg(priv, 0x02010 , &buf[0]);
+ if (ret)
+ goto error;
+
+ if ((buf[0] & 0x07) == 6) {
+ if (((buf[0] >> 5) & 0x01) == 1) {
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+ } else {
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI | FE_HAS_SYNC;
+ }
+ }
+
+ dbg("%s: lock=%02x", __func__, buf[0]);
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_read_ber_t2(struct dvb_frontend *fe, u32 *ber)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+ u8 buf[4];
+ unsigned int errbits;
+ *ber = 0;
+ /* FIXME: correct calculation */
+
+ ret = cxd2820r_rd_regs(priv, 0x02039, buf, sizeof(buf));
+ if (ret)
+ goto error;
+
+ if ((buf[0] >> 4) & 0x01) {
+ errbits = (buf[0] & 0x0f) << 24 | buf[1] << 16 |
+ buf[2] << 8 | buf[3];
+
+ if (errbits)
+ *ber = errbits * 64 / 16588800;
+ }
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_read_signal_strength_t2(struct dvb_frontend *fe,
+ u16 *strength)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+ u8 buf[2];
+ u16 tmp;
+
+ ret = cxd2820r_rd_regs(priv, 0x02026, buf, sizeof(buf));
+ if (ret)
+ goto error;
+
+ tmp = (buf[0] & 0x0f) << 8 | buf[1];
+ tmp = ~tmp & 0x0fff;
+
+ /* scale value to 0x0000-0xffff from 0x0000-0x0fff */
+ *strength = tmp * 0xffff / 0x0fff;
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_read_snr_t2(struct dvb_frontend *fe, u16 *snr)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret;
+ u8 buf[2];
+ u16 tmp;
+ /* report SNR in dB * 10 */
+
+ ret = cxd2820r_rd_regs(priv, 0x02028, buf, sizeof(buf));
+ if (ret)
+ goto error;
+
+ tmp = (buf[0] & 0x0f) << 8 | buf[1];
+ #define CXD2820R_LOG10_8_24 15151336 /* log10(8) << 24 */
+ if (tmp)
+ *snr = (intlog10(tmp) - CXD2820R_LOG10_8_24) / ((1 << 24)
+ / 100);
+ else
+ *snr = 0;
+
+ dbg("%s: dBx10=%d val=%04x", __func__, *snr, tmp);
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_read_ucblocks_t2(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ *ucblocks = 0;
+ /* no way to read ? */
+ return 0;
+}
+
+int cxd2820r_sleep_t2(struct dvb_frontend *fe)
+{
+ struct cxd2820r_priv *priv = fe->demodulator_priv;
+ int ret, i;
+ struct reg_val_mask tab[] = {
+ { 0x000ff, 0x1f, 0xff },
+ { 0x00085, 0x00, 0xff },
+ { 0x00088, 0x01, 0xff },
+ { 0x02069, 0x00, 0xff },
+ { 0x00081, 0x00, 0xff },
+ { 0x00080, 0x00, 0xff },
+ };
+
+ dbg("%s", __func__);
+
+ for (i = 0; i < ARRAY_SIZE(tab); i++) {
+ ret = cxd2820r_wr_reg_mask(priv, tab[i].reg, tab[i].val,
+ tab[i].mask);
+ if (ret)
+ goto error;
+ }
+
+ priv->delivery_system = SYS_UNDEFINED;
+
+ return ret;
+error:
+ dbg("%s: failed:%d", __func__, ret);
+ return ret;
+}
+
+int cxd2820r_get_tune_settings_t2(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *s)
+{
+ s->min_delay_ms = 1500;
+ s->step_size = fe->ops.info.frequency_stepsize * 2;
+ s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
+
+ return 0;
+}
+
diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c
index d4e466a90e43..1d47d4da7d4c 100644
--- a/drivers/media/dvb/frontends/dib0070.c
+++ b/drivers/media/dvb/frontends/dib0070.c
@@ -73,27 +73,47 @@ struct dib0070_state {
u8 wbd_gain_current;
u16 wbd_offset_3_3[2];
+
+ /* for the I2C transfer */
+ struct i2c_msg msg[2];
+ u8 i2c_write_buffer[3];
+ u8 i2c_read_buffer[2];
};
static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg)
{
- u8 b[2];
- struct i2c_msg msg[2] = {
- { .addr = state->cfg->i2c_address, .flags = 0, .buf = &reg, .len = 1 },
- { .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2 },
- };
- if (i2c_transfer(state->i2c, msg, 2) != 2) {
+ state->i2c_write_buffer[0] = reg;
+
+ memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+ state->msg[0].addr = state->cfg->i2c_address;
+ state->msg[0].flags = 0;
+ state->msg[0].buf = state->i2c_write_buffer;
+ state->msg[0].len = 1;
+ state->msg[1].addr = state->cfg->i2c_address;
+ state->msg[1].flags = I2C_M_RD;
+ state->msg[1].buf = state->i2c_read_buffer;
+ state->msg[1].len = 2;
+
+ if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
printk(KERN_WARNING "DiB0070 I2C read failed\n");
return 0;
}
- return (b[0] << 8) | b[1];
+ return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
}
static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
{
- u8 b[3] = { reg, val >> 8, val & 0xff };
- struct i2c_msg msg = { .addr = state->cfg->i2c_address, .flags = 0, .buf = b, .len = 3 };
- if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+ state->i2c_write_buffer[0] = reg;
+ state->i2c_write_buffer[1] = val >> 8;
+ state->i2c_write_buffer[2] = val & 0xff;
+
+ memset(state->msg, 0, sizeof(struct i2c_msg));
+ state->msg[0].addr = state->cfg->i2c_address;
+ state->msg[0].flags = 0;
+ state->msg[0].buf = state->i2c_write_buffer;
+ state->msg[0].len = 3;
+
+ if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
printk(KERN_WARNING "DiB0070 I2C write failed\n");
return -EREMOTEIO;
}
diff --git a/drivers/media/dvb/frontends/dib0090.c b/drivers/media/dvb/frontends/dib0090.c
index 52ff1a252a90..c9c935ae41e4 100644
--- a/drivers/media/dvb/frontends/dib0090.c
+++ b/drivers/media/dvb/frontends/dib0090.c
@@ -191,6 +191,11 @@ struct dib0090_state {
u8 wbd_calibration_gain;
const struct dib0090_wbd_slope *current_wbd_table;
u16 wbdmux;
+
+ /* for the I2C transfer */
+ struct i2c_msg msg[2];
+ u8 i2c_write_buffer[3];
+ u8 i2c_read_buffer[2];
};
struct dib0090_fw_state {
@@ -198,27 +203,48 @@ struct dib0090_fw_state {
struct dvb_frontend *fe;
struct dib0090_identity identity;
const struct dib0090_config *config;
+
+ /* for the I2C transfer */
+ struct i2c_msg msg;
+ u8 i2c_write_buffer[2];
+ u8 i2c_read_buffer[2];
};
static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg)
{
- u8 b[2];
- struct i2c_msg msg[2] = {
- {.addr = state->config->i2c_address, .flags = 0, .buf = &reg, .len = 1},
- {.addr = state->config->i2c_address, .flags = I2C_M_RD, .buf = b, .len = 2},
- };
- if (i2c_transfer(state->i2c, msg, 2) != 2) {
+ state->i2c_write_buffer[0] = reg;
+
+ memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+ state->msg[0].addr = state->config->i2c_address;
+ state->msg[0].flags = 0;
+ state->msg[0].buf = state->i2c_write_buffer;
+ state->msg[0].len = 1;
+ state->msg[1].addr = state->config->i2c_address;
+ state->msg[1].flags = I2C_M_RD;
+ state->msg[1].buf = state->i2c_read_buffer;
+ state->msg[1].len = 2;
+
+ if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
printk(KERN_WARNING "DiB0090 I2C read failed\n");
return 0;
}
- return (b[0] << 8) | b[1];
+
+ return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
}
static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)
{
- u8 b[3] = { reg & 0xff, val >> 8, val & 0xff };
- struct i2c_msg msg = {.addr = state->config->i2c_address, .flags = 0, .buf = b, .len = 3 };
- if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+ state->i2c_write_buffer[0] = reg & 0xff;
+ state->i2c_write_buffer[1] = val >> 8;
+ state->i2c_write_buffer[2] = val & 0xff;
+
+ memset(state->msg, 0, sizeof(struct i2c_msg));
+ state->msg[0].addr = state->config->i2c_address;
+ state->msg[0].flags = 0;
+ state->msg[0].buf = state->i2c_write_buffer;
+ state->msg[0].len = 3;
+
+ if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
printk(KERN_WARNING "DiB0090 I2C write failed\n");
return -EREMOTEIO;
}
@@ -227,20 +253,31 @@ static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)
static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg)
{
- u8 b[2];
- struct i2c_msg msg = {.addr = reg, .flags = I2C_M_RD, .buf = b, .len = 2 };
- if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+ state->i2c_write_buffer[0] = reg;
+
+ memset(&state->msg, 0, sizeof(struct i2c_msg));
+ state->msg.addr = reg;
+ state->msg.flags = I2C_M_RD;
+ state->msg.buf = state->i2c_read_buffer;
+ state->msg.len = 2;
+ if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
printk(KERN_WARNING "DiB0090 I2C read failed\n");
return 0;
}
- return (b[0] << 8) | b[1];
+ return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
}
static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val)
{
- u8 b[2] = { val >> 8, val & 0xff };
- struct i2c_msg msg = {.addr = reg, .flags = 0, .buf = b, .len = 2 };
- if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+ state->i2c_write_buffer[0] = val >> 8;
+ state->i2c_write_buffer[1] = val & 0xff;
+
+ memset(&state->msg, 0, sizeof(struct i2c_msg));
+ state->msg.addr = reg;
+ state->msg.flags = 0;
+ state->msg.buf = state->i2c_write_buffer;
+ state->msg.len = 2;
+ if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
printk(KERN_WARNING "DiB0090 I2C write failed\n");
return -EREMOTEIO;
}
diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c
index 289a79837f24..79cb1c20df24 100644
--- a/drivers/media/dvb/frontends/dib7000m.c
+++ b/drivers/media/dvb/frontends/dib7000m.c
@@ -50,6 +50,11 @@ struct dib7000m_state {
u16 revision;
u8 agc_state;
+
+ /* for the I2C transfer */
+ struct i2c_msg msg[2];
+ u8 i2c_write_buffer[4];
+ u8 i2c_read_buffer[2];
};
enum dib7000m_power_mode {
@@ -64,29 +69,39 @@ enum dib7000m_power_mode {
static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg)
{
- u8 wb[2] = { (reg >> 8) | 0x80, reg & 0xff };
- u8 rb[2];
- struct i2c_msg msg[2] = {
- { .addr = state->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2 },
- { .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 },
- };
-
- if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
+ state->i2c_write_buffer[0] = (reg >> 8) | 0x80;
+ state->i2c_write_buffer[1] = reg & 0xff;
+
+ memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+ state->msg[0].addr = state->i2c_addr >> 1;
+ state->msg[0].flags = 0;
+ state->msg[0].buf = state->i2c_write_buffer;
+ state->msg[0].len = 2;
+ state->msg[1].addr = state->i2c_addr >> 1;
+ state->msg[1].flags = I2C_M_RD;
+ state->msg[1].buf = state->i2c_read_buffer;
+ state->msg[1].len = 2;
+
+ if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
dprintk("i2c read error on %d",reg);
- return (rb[0] << 8) | rb[1];
+ return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
}
static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val)
{
- u8 b[4] = {
- (reg >> 8) & 0xff, reg & 0xff,
- (val >> 8) & 0xff, val & 0xff,
- };
- struct i2c_msg msg = {
- .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
- };
- return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+ state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+ state->i2c_write_buffer[1] = reg & 0xff;
+ state->i2c_write_buffer[2] = (val >> 8) & 0xff;
+ state->i2c_write_buffer[3] = val & 0xff;
+
+ memset(&state->msg[0], 0, sizeof(struct i2c_msg));
+ state->msg[0].addr = state->i2c_addr >> 1;
+ state->msg[0].flags = 0;
+ state->msg[0].buf = state->i2c_write_buffer;
+ state->msg[0].len = 4;
+
+ return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
}
static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf)
{
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
index 900af60b9d36..0c9f40c2a251 100644
--- a/drivers/media/dvb/frontends/dib7000p.c
+++ b/drivers/media/dvb/frontends/dib7000p.c
@@ -63,6 +63,11 @@ struct dib7000p_state {
u16 tuner_enable;
struct i2c_adapter dib7090_tuner_adap;
+
+ /* for the I2C transfer */
+ struct i2c_msg msg[2];
+ u8 i2c_write_buffer[4];
+ u8 i2c_read_buffer[2];
};
enum dib7000p_power_mode {
@@ -76,29 +81,39 @@ static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff);
static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
{
- u8 wb[2] = { reg >> 8, reg & 0xff };
- u8 rb[2];
- struct i2c_msg msg[2] = {
- {.addr = state->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2},
- {.addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2},
- };
+ state->i2c_write_buffer[0] = reg >> 8;
+ state->i2c_write_buffer[1] = reg & 0xff;
+
+ memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+ state->msg[0].addr = state->i2c_addr >> 1;
+ state->msg[0].flags = 0;
+ state->msg[0].buf = state->i2c_write_buffer;
+ state->msg[0].len = 2;
+ state->msg[1].addr = state->i2c_addr >> 1;
+ state->msg[1].flags = I2C_M_RD;
+ state->msg[1].buf = state->i2c_read_buffer;
+ state->msg[1].len = 2;
- if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
+ if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
dprintk("i2c read error on %d", reg);
- return (rb[0] << 8) | rb[1];
+ return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
}
static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
{
- u8 b[4] = {
- (reg >> 8) & 0xff, reg & 0xff,
- (val >> 8) & 0xff, val & 0xff,
- };
- struct i2c_msg msg = {
- .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
- };
- return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+ state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+ state->i2c_write_buffer[1] = reg & 0xff;
+ state->i2c_write_buffer[2] = (val >> 8) & 0xff;
+ state->i2c_write_buffer[3] = val & 0xff;
+
+ memset(&state->msg[0], 0, sizeof(struct i2c_msg));
+ state->msg[0].addr = state->i2c_addr >> 1;
+ state->msg[0].flags = 0;
+ state->msg[0].buf = state->i2c_write_buffer;
+ state->msg[0].len = 4;
+
+ return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
}
static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
@@ -1550,11 +1565,24 @@ static void dib7000p_release(struct dvb_frontend *demod)
int dib7000pc_detection(struct i2c_adapter *i2c_adap)
{
- u8 tx[2], rx[2];
+ u8 *tx, *rx;
struct i2c_msg msg[2] = {
- {.addr = 18 >> 1, .flags = 0, .buf = tx, .len = 2},
- {.addr = 18 >> 1, .flags = I2C_M_RD, .buf = rx, .len = 2},
+ {.addr = 18 >> 1, .flags = 0, .len = 2},
+ {.addr = 18 >> 1, .flags = I2C_M_RD, .len = 2},
};
+ int ret = 0;
+
+ tx = kzalloc(2*sizeof(u8), GFP_KERNEL);
+ if (!tx)
+ return -ENOMEM;
+ rx = kzalloc(2*sizeof(u8), GFP_KERNEL);
+ if (!rx) {
+ goto rx_memory_error;
+ ret = -ENOMEM;
+ }
+
+ msg[0].buf = tx;
+ msg[1].buf = rx;
tx[0] = 0x03;
tx[1] = 0x00;
@@ -1574,7 +1602,11 @@ int dib7000pc_detection(struct i2c_adapter *i2c_adap)
}
dprintk("-D- DiB7000PC not detected");
- return 0;
+
+ kfree(rx);
+rx_memory_error:
+ kfree(tx);
+ return ret;
}
EXPORT_SYMBOL(dib7000pc_detection);
diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb/frontends/dib8000.c
index c1c3e26906e2..7d2ea112ae2b 100644
--- a/drivers/media/dvb/frontends/dib8000.c
+++ b/drivers/media/dvb/frontends/dib8000.c
@@ -35,6 +35,8 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
struct i2c_device {
struct i2c_adapter *adap;
u8 addr;
+ u8 *i2c_write_buffer;
+ u8 *i2c_read_buffer;
};
struct dib8000_state {
@@ -70,6 +72,11 @@ struct dib8000_state {
u32 status;
struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
+
+ /* for the I2C transfer */
+ struct i2c_msg msg[2];
+ u8 i2c_write_buffer[4];
+ u8 i2c_read_buffer[2];
};
enum dib8000_power_mode {
@@ -79,22 +86,41 @@ enum dib8000_power_mode {
static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
{
- u8 wb[2] = { reg >> 8, reg & 0xff };
- u8 rb[2];
struct i2c_msg msg[2] = {
- {.addr = i2c->addr >> 1,.flags = 0,.buf = wb,.len = 2},
- {.addr = i2c->addr >> 1,.flags = I2C_M_RD,.buf = rb,.len = 2},
+ {.addr = i2c->addr >> 1, .flags = 0,
+ .buf = i2c->i2c_write_buffer, .len = 2},
+ {.addr = i2c->addr >> 1, .flags = I2C_M_RD,
+ .buf = i2c->i2c_read_buffer, .len = 2},
};
+ msg[0].buf[0] = reg >> 8;
+ msg[0].buf[1] = reg & 0xff;
+
if (i2c_transfer(i2c->adap, msg, 2) != 2)
dprintk("i2c read error on %d", reg);
- return (rb[0] << 8) | rb[1];
+ return (msg[1].buf[0] << 8) | msg[1].buf[1];
}
static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
{
- return dib8000_i2c_read16(&state->i2c, reg);
+ state->i2c_write_buffer[0] = reg >> 8;
+ state->i2c_write_buffer[1] = reg & 0xff;
+
+ memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+ state->msg[0].addr = state->i2c.addr >> 1;
+ state->msg[0].flags = 0;
+ state->msg[0].buf = state->i2c_write_buffer;
+ state->msg[0].len = 2;
+ state->msg[1].addr = state->i2c.addr >> 1;
+ state->msg[1].flags = I2C_M_RD;
+ state->msg[1].buf = state->i2c_read_buffer;
+ state->msg[1].len = 2;
+
+ if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)
+ dprintk("i2c read error on %d", reg);
+
+ return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
}
static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
@@ -109,19 +135,34 @@ static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
{
- u8 b[4] = {
- (reg >> 8) & 0xff, reg & 0xff,
- (val >> 8) & 0xff, val & 0xff,
- };
- struct i2c_msg msg = {
- .addr = i2c->addr >> 1,.flags = 0,.buf = b,.len = 4
- };
- return i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+ struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0,
+ .buf = i2c->i2c_write_buffer, .len = 4};
+ int ret = 0;
+
+ msg.buf[0] = (reg >> 8) & 0xff;
+ msg.buf[1] = reg & 0xff;
+ msg.buf[2] = (val >> 8) & 0xff;
+ msg.buf[3] = val & 0xff;
+
+ ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+
+ return ret;
}
static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
{
- return dib8000_i2c_write16(&state->i2c, reg, val);
+ state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+ state->i2c_write_buffer[1] = reg & 0xff;
+ state->i2c_write_buffer[2] = (val >> 8) & 0xff;
+ state->i2c_write_buffer[3] = val & 0xff;
+
+ memset(&state->msg[0], 0, sizeof(struct i2c_msg));
+ state->msg[0].addr = state->i2c.addr >> 1;
+ state->msg[0].flags = 0;
+ state->msg[0].buf = state->i2c_write_buffer;
+ state->msg[0].len = 4;
+
+ return i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
}
static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
@@ -980,30 +1021,31 @@ static void dib8000_update_timf(struct dib8000_state *state)
dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default);
}
+static const u16 adc_target_16dB[11] = {
+ (1 << 13) - 825 - 117,
+ (1 << 13) - 837 - 117,
+ (1 << 13) - 811 - 117,
+ (1 << 13) - 766 - 117,
+ (1 << 13) - 737 - 117,
+ (1 << 13) - 693 - 117,
+ (1 << 13) - 648 - 117,
+ (1 << 13) - 619 - 117,
+ (1 << 13) - 575 - 117,
+ (1 << 13) - 531 - 117,
+ (1 << 13) - 501 - 117
+};
+static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
+
static void dib8000_set_channel(struct dib8000_state *state, u8 seq, u8 autosearching)
{
u16 mode, max_constellation, seg_diff_mask = 0, nbseg_diff = 0;
u8 guard, crate, constellation, timeI;
- u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
u16 i, coeff[4], P_cfr_left_edge = 0, P_cfr_right_edge = 0, seg_mask13 = 0x1fff; // All 13 segments enabled
const s16 *ncoeff = NULL, *ana_fe;
u16 tmcc_pow = 0;
u16 coff_pow = 0x2800;
u16 init_prbs = 0xfff;
u16 ana_gain = 0;
- u16 adc_target_16dB[11] = {
- (1 << 13) - 825 - 117,
- (1 << 13) - 837 - 117,
- (1 << 13) - 811 - 117,
- (1 << 13) - 766 - 117,
- (1 << 13) - 737 - 117,
- (1 << 13) - 693 - 117,
- (1 << 13) - 648 - 117,
- (1 << 13) - 619 - 117,
- (1 << 13) - 575 - 117,
- (1 << 13) - 531 - 117,
- (1 << 13) - 501 - 117
- };
if (state->ber_monitored_layer != LAYER_ALL)
dib8000_write_word(state, 285, (dib8000_read_word(state, 285) & 0x60) | state->ber_monitored_layer);
@@ -2379,10 +2421,22 @@ EXPORT_SYMBOL(dib8000_get_slave_frontend);
int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 default_addr, u8 first_addr)
{
- int k = 0;
+ int k = 0, ret = 0;
u8 new_addr = 0;
struct i2c_device client = {.adap = host };
+ client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
+ if (!client.i2c_write_buffer) {
+ dprintk("%s: not enough memory", __func__);
+ return -ENOMEM;
+ }
+ client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
+ if (!client.i2c_read_buffer) {
+ dprintk("%s: not enough memory", __func__);
+ ret = -ENOMEM;
+ goto error_memory;
+ }
+
for (k = no_of_demods - 1; k >= 0; k--) {
/* designated i2c address */
new_addr = first_addr + (k << 1);
@@ -2394,7 +2448,8 @@ int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 defau
client.addr = default_addr;
if (dib8000_identify(&client) == 0) {
dprintk("#%d: not identified", k);
- return -EINVAL;
+ ret = -EINVAL;
+ goto error;
}
}
@@ -2420,7 +2475,12 @@ int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 defau
dib8000_i2c_write16(&client, 1286, 0);
}
- return 0;
+error:
+ kfree(client.i2c_read_buffer);
+error_memory:
+ kfree(client.i2c_write_buffer);
+
+ return ret;
}
EXPORT_SYMBOL(dib8000_i2c_enumeration);
@@ -2519,6 +2579,8 @@ struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, s
memcpy(&state->cfg, cfg, sizeof(struct dib8000_config));
state->i2c.adap = i2c_adap;
state->i2c.addr = i2c_addr;
+ state->i2c.i2c_write_buffer = state->i2c_write_buffer;
+ state->i2c.i2c_read_buffer = state->i2c_read_buffer;
state->gpio_val = cfg->gpio_val;
state->gpio_dir = cfg->gpio_dir;
diff --git a/drivers/media/dvb/frontends/dib9000.c b/drivers/media/dvb/frontends/dib9000.c
index 91518761a2da..a0855883b5ce 100644
--- a/drivers/media/dvb/frontends/dib9000.c
+++ b/drivers/media/dvb/frontends/dib9000.c
@@ -27,6 +27,8 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
struct i2c_device {
struct i2c_adapter *i2c_adap;
u8 i2c_addr;
+ u8 *i2c_read_buffer;
+ u8 *i2c_write_buffer;
};
/* lock */
@@ -92,11 +94,16 @@ struct dib9000_state {
struct dvb_frontend *fe[MAX_NUMBER_OF_FRONTENDS];
u16 component_bus_speed;
+
+ /* for the I2C transfer */
+ struct i2c_msg msg[2];
+ u8 i2c_write_buffer[255];
+ u8 i2c_read_buffer[255];
};
-u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+static const u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0
};
enum dib9000_power_mode {
@@ -217,25 +224,33 @@ static u16 dib9000_read16_attr(struct dib9000_state *state, u16 reg, u8 * b, u32
u32 chunk_size = 126;
u32 l;
int ret;
- u8 wb[2] = { reg >> 8, reg & 0xff };
- struct i2c_msg msg[2] = {
- {.addr = state->i2c.i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2},
- {.addr = state->i2c.i2c_addr >> 1, .flags = I2C_M_RD, .buf = b, .len = len},
- };
if (state->platform.risc.fw_is_running && (reg < 1024))
return dib9000_risc_apb_access_read(state, reg, attribute, NULL, 0, b, len);
+ memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+ state->msg[0].addr = state->i2c.i2c_addr >> 1;
+ state->msg[0].flags = 0;
+ state->msg[0].buf = state->i2c_write_buffer;
+ state->msg[0].len = 2;
+ state->msg[1].addr = state->i2c.i2c_addr >> 1;
+ state->msg[1].flags = I2C_M_RD;
+ state->msg[1].buf = b;
+ state->msg[1].len = len;
+
+ state->i2c_write_buffer[0] = reg >> 8;
+ state->i2c_write_buffer[1] = reg & 0xff;
+
if (attribute & DATA_BUS_ACCESS_MODE_8BIT)
- wb[0] |= (1 << 5);
+ state->i2c_write_buffer[0] |= (1 << 5);
if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
- wb[0] |= (1 << 4);
+ state->i2c_write_buffer[0] |= (1 << 4);
do {
l = len < chunk_size ? len : chunk_size;
- msg[1].len = l;
- msg[1].buf = b;
- ret = i2c_transfer(state->i2c.i2c_adap, msg, 2) != 2 ? -EREMOTEIO : 0;
+ state->msg[1].len = l;
+ state->msg[1].buf = b;
+ ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 2) != 2 ? -EREMOTEIO : 0;
if (ret != 0) {
dprintk("i2c read error on %d", reg);
return -EREMOTEIO;
@@ -253,50 +268,47 @@ static u16 dib9000_read16_attr(struct dib9000_state *state, u16 reg, u8 * b, u32
static u16 dib9000_i2c_read16(struct i2c_device *i2c, u16 reg)
{
- u8 b[2];
- u8 wb[2] = { reg >> 8, reg & 0xff };
struct i2c_msg msg[2] = {
- {.addr = i2c->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2},
- {.addr = i2c->i2c_addr >> 1, .flags = I2C_M_RD, .buf = b, .len = 2},
+ {.addr = i2c->i2c_addr >> 1, .flags = 0,
+ .buf = i2c->i2c_write_buffer, .len = 2},
+ {.addr = i2c->i2c_addr >> 1, .flags = I2C_M_RD,
+ .buf = i2c->i2c_read_buffer, .len = 2},
};
+ i2c->i2c_write_buffer[0] = reg >> 8;
+ i2c->i2c_write_buffer[1] = reg & 0xff;
+
if (i2c_transfer(i2c->i2c_adap, msg, 2) != 2) {
dprintk("read register %x error", reg);
return 0;
}
- return (b[0] << 8) | b[1];
+ return (i2c->i2c_read_buffer[0] << 8) | i2c->i2c_read_buffer[1];
}
static inline u16 dib9000_read_word(struct dib9000_state *state, u16 reg)
{
- u8 b[2];
- if (dib9000_read16_attr(state, reg, b, 2, 0) != 0)
+ if (dib9000_read16_attr(state, reg, state->i2c_read_buffer, 2, 0) != 0)
return 0;
- return (b[0] << 8 | b[1]);
+ return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
}
static inline u16 dib9000_read_word_attr(struct dib9000_state *state, u16 reg, u16 attribute)
{
- u8 b[2];
- if (dib9000_read16_attr(state, reg, b, 2, attribute) != 0)
+ if (dib9000_read16_attr(state, reg, state->i2c_read_buffer, 2,
+ attribute) != 0)
return 0;
- return (b[0] << 8 | b[1]);
+ return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
}
#define dib9000_read16_noinc_attr(state, reg, b, len, attribute) dib9000_read16_attr(state, reg, b, len, (attribute) | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
static u16 dib9000_write16_attr(struct dib9000_state *state, u16 reg, const u8 * buf, u32 len, u16 attribute)
{
- u8 b[255];
u32 chunk_size = 126;
u32 l;
int ret;
- struct i2c_msg msg = {
- .addr = state->i2c.i2c_addr >> 1, .flags = 0, .buf = b, .len = len + 2
- };
-
if (state->platform.risc.fw_is_running && (reg < 1024)) {
if (dib9000_risc_apb_access_write
(state, reg, DATA_BUS_ACCESS_MODE_16BIT | DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT | attribute, buf, len) != 0)
@@ -304,20 +316,26 @@ static u16 dib9000_write16_attr(struct dib9000_state *state, u16 reg, const u8 *
return 0;
}
- b[0] = (reg >> 8) & 0xff;
- b[1] = (reg) & 0xff;
+ memset(&state->msg[0], 0, sizeof(struct i2c_msg));
+ state->msg[0].addr = state->i2c.i2c_addr >> 1;
+ state->msg[0].flags = 0;
+ state->msg[0].buf = state->i2c_write_buffer;
+ state->msg[0].len = len + 2;
+
+ state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+ state->i2c_write_buffer[1] = (reg) & 0xff;
if (attribute & DATA_BUS_ACCESS_MODE_8BIT)
- b[0] |= (1 << 5);
+ state->i2c_write_buffer[0] |= (1 << 5);
if (attribute & DATA_BUS_ACCESS_MODE_NO_ADDRESS_INCREMENT)
- b[0] |= (1 << 4);
+ state->i2c_write_buffer[0] |= (1 << 4);
do {
l = len < chunk_size ? len : chunk_size;
- msg.len = l + 2;
- memcpy(&b[2], buf, l);
+ state->msg[0].len = l + 2;
+ memcpy(&state->i2c_write_buffer[2], buf, l);
- ret = i2c_transfer(state->i2c.i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+ ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
buf += l;
len -= l;
@@ -331,11 +349,16 @@ static u16 dib9000_write16_attr(struct dib9000_state *state, u16 reg, const u8 *
static int dib9000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
{
- u8 b[4] = { (reg >> 8) & 0xff, reg & 0xff, (val >> 8) & 0xff, val & 0xff };
struct i2c_msg msg = {
- .addr = i2c->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
+ .addr = i2c->i2c_addr >> 1, .flags = 0,
+ .buf = i2c->i2c_write_buffer, .len = 4
};
+ i2c->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+ i2c->i2c_write_buffer[1] = reg & 0xff;
+ i2c->i2c_write_buffer[2] = (val >> 8) & 0xff;
+ i2c->i2c_write_buffer[3] = val & 0xff;
+
return i2c_transfer(i2c->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
}
@@ -1015,8 +1038,8 @@ static int dib9000_fw_memmbx_sync(struct dib9000_state *state, u8 i)
return 0;
dib9000_risc_mem_write(state, FE_MM_RW_SYNC, &i);
do {
- dib9000_risc_mem_read(state, FE_MM_RW_SYNC, &i, 1);
- } while (i && index_loop--);
+ dib9000_risc_mem_read(state, FE_MM_RW_SYNC, state->i2c_read_buffer, 1);
+ } while (state->i2c_read_buffer[0] && index_loop--);
if (index_loop > 0)
return 0;
@@ -1139,7 +1162,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
s8 intlv_native;
};
- struct dibDVBTChannel ch;
+ struct dibDVBTChannel *ch;
int ret = 0;
DibAcquireLock(&state->platform.risc.mem_mbx_lock);
@@ -1148,9 +1171,12 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
ret = -EIO;
}
- dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_UNION, (u8 *) &ch, sizeof(struct dibDVBTChannel));
+ dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_UNION,
+ state->i2c_read_buffer, sizeof(struct dibDVBTChannel));
+ ch = (struct dibDVBTChannel *)state->i2c_read_buffer;
+
- switch (ch.spectrum_inversion & 0x7) {
+ switch (ch->spectrum_inversion & 0x7) {
case 1:
state->fe[0]->dtv_property_cache.inversion = INVERSION_ON;
break;
@@ -1162,7 +1188,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
state->fe[0]->dtv_property_cache.inversion = INVERSION_AUTO;
break;
}
- switch (ch.nfft) {
+ switch (ch->nfft) {
case 0:
state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;
break;
@@ -1177,7 +1203,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
state->fe[0]->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO;
break;
}
- switch (ch.guard) {
+ switch (ch->guard) {
case 0:
state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;
break;
@@ -1195,7 +1221,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
state->fe[0]->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO;
break;
}
- switch (ch.constellation) {
+ switch (ch->constellation) {
case 2:
state->fe[0]->dtv_property_cache.modulation = QAM_64;
break;
@@ -1210,7 +1236,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
state->fe[0]->dtv_property_cache.modulation = QAM_AUTO;
break;
}
- switch (ch.hrch) {
+ switch (ch->hrch) {
case 0:
state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_NONE;
break;
@@ -1222,7 +1248,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
state->fe[0]->dtv_property_cache.hierarchy = HIERARCHY_AUTO;
break;
}
- switch (ch.code_rate_hp) {
+ switch (ch->code_rate_hp) {
case 1:
state->fe[0]->dtv_property_cache.code_rate_HP = FEC_1_2;
break;
@@ -1243,7 +1269,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe, struct dvb_frontend_p
state->fe[0]->dtv_property_cache.code_rate_HP = FEC_AUTO;
break;
}
- switch (ch.code_rate_lp) {
+ switch (ch->code_rate_lp) {
case 1:
state->fe[0]->dtv_property_cache.code_rate_LP = FEC_1_2;
break;
@@ -1439,9 +1465,10 @@ static int dib9000_fw_tune(struct dvb_frontend *fe, struct dvb_frontend_paramete
break;
case CT_DEMOD_STEP_1:
if (search)
- dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_SEARCH_STATE, (u8 *) &i, 1);
+ dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_SEARCH_STATE, state->i2c_read_buffer, 1);
else
- dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_TUNE_STATE, (u8 *) &i, 1);
+ dib9000_risc_mem_read(state, FE_MM_R_CHANNEL_TUNE_STATE, state->i2c_read_buffer, 1);
+ i = (s8)state->i2c_read_buffer[0];
switch (i) { /* something happened */
case 0:
break;
@@ -2038,14 +2065,17 @@ static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber)
{
struct dib9000_state *state = fe->demodulator_priv;
- u16 c[16];
+ u16 *c;
DibAcquireLock(&state->platform.risc.mem_mbx_lock);
if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
return -EIO;
- dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c));
+ dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR,
+ state->i2c_read_buffer, 16 * 2);
DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+ c = (u16 *)state->i2c_read_buffer;
+
*ber = c[10] << 16 | c[11];
return 0;
}
@@ -2054,7 +2084,7 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
{
struct dib9000_state *state = fe->demodulator_priv;
u8 index_frontend;
- u16 c[16];
+ u16 *c = (u16 *)state->i2c_read_buffer;
u16 val;
*strength = 0;
@@ -2069,7 +2099,7 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
DibAcquireLock(&state->platform.risc.mem_mbx_lock);
if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
return -EIO;
- dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c));
+ dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
DibReleaseLock(&state->platform.risc.mem_mbx_lock);
val = 65535 - c[4];
@@ -2083,14 +2113,14 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
static u32 dib9000_get_snr(struct dvb_frontend *fe)
{
struct dib9000_state *state = fe->demodulator_priv;
- u16 c[16];
+ u16 *c = (u16 *)state->i2c_read_buffer;
u32 n, s, exp;
u16 val;
DibAcquireLock(&state->platform.risc.mem_mbx_lock);
if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
return -EIO;
- dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c));
+ dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
DibReleaseLock(&state->platform.risc.mem_mbx_lock);
val = c[7];
@@ -2137,12 +2167,12 @@ static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr)
static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
{
struct dib9000_state *state = fe->demodulator_priv;
- u16 c[16];
+ u16 *c = (u16 *)state->i2c_read_buffer;
DibAcquireLock(&state->platform.risc.mem_mbx_lock);
if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
return -EIO;
- dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, sizeof(c));
+ dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
DibReleaseLock(&state->platform.risc.mem_mbx_lock);
*unc = c[12];
@@ -2151,10 +2181,22 @@ static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, u8 first_addr)
{
- int k = 0;
+ int k = 0, ret = 0;
u8 new_addr = 0;
struct i2c_device client = {.i2c_adap = i2c };
+ client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
+ if (!client.i2c_write_buffer) {
+ dprintk("%s: not enough memory", __func__);
+ return -ENOMEM;
+ }
+ client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL);
+ if (!client.i2c_read_buffer) {
+ dprintk("%s: not enough memory", __func__);
+ ret = -ENOMEM;
+ goto error_memory;
+ }
+
client.i2c_addr = default_addr + 16;
dib9000_i2c_write16(&client, 1796, 0x0);
@@ -2178,7 +2220,8 @@ int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defaul
client.i2c_addr = default_addr;
if (dib9000_identify(&client) == 0) {
dprintk("DiB9000 #%d: not identified", k);
- return -EIO;
+ ret = -EIO;
+ goto error;
}
}
@@ -2196,7 +2239,12 @@ int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defaul
dib9000_i2c_write16(&client, 1795, 0);
}
- return 0;
+error:
+ kfree(client.i2c_read_buffer);
+error_memory:
+ kfree(client.i2c_write_buffer);
+
+ return ret;
}
EXPORT_SYMBOL(dib9000_i2c_enumeration);
@@ -2255,12 +2303,16 @@ struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, c
if (st == NULL)
return NULL;
fe = kzalloc(sizeof(struct dvb_frontend), GFP_KERNEL);
- if (fe == NULL)
+ if (fe == NULL) {
+ kfree(st);
return NULL;
+ }
memcpy(&st->chip.d9.cfg, cfg, sizeof(struct dib9000_config));
st->i2c.i2c_adap = i2c_adap;
st->i2c.i2c_addr = i2c_addr;
+ st->i2c.i2c_write_buffer = st->i2c_write_buffer;
+ st->i2c.i2c_read_buffer = st->i2c_read_buffer;
st->gpio_dir = DIB9000_GPIO_DEFAULT_DIRECTIONS;
st->gpio_val = DIB9000_GPIO_DEFAULT_VALUES;
diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c
index f6938f97feb4..dc5d17a67579 100644
--- a/drivers/media/dvb/frontends/dibx000_common.c
+++ b/drivers/media/dvb/frontends/dibx000_common.c
@@ -10,30 +10,39 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val)
{
- u8 b[4] = {
- (reg >> 8) & 0xff, reg & 0xff,
- (val >> 8) & 0xff, val & 0xff,
- };
- struct i2c_msg msg = {
- .addr = mst->i2c_addr,.flags = 0,.buf = b,.len = 4
- };
-
- return i2c_transfer(mst->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+ mst->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+ mst->i2c_write_buffer[1] = reg & 0xff;
+ mst->i2c_write_buffer[2] = (val >> 8) & 0xff;
+ mst->i2c_write_buffer[3] = val & 0xff;
+
+ memset(mst->msg, 0, sizeof(struct i2c_msg));
+ mst->msg[0].addr = mst->i2c_addr;
+ mst->msg[0].flags = 0;
+ mst->msg[0].buf = mst->i2c_write_buffer;
+ mst->msg[0].len = 4;
+
+ return i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0;
}
static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg)
{
- u8 wb[2] = { reg >> 8, reg & 0xff };
- u8 rb[2];
- struct i2c_msg msg[2] = {
- {.addr = mst->i2c_addr, .flags = 0, .buf = wb, .len = 2},
- {.addr = mst->i2c_addr, .flags = I2C_M_RD, .buf = rb, .len = 2},
- };
-
- if (i2c_transfer(mst->i2c_adap, msg, 2) != 2)
+ mst->i2c_write_buffer[0] = reg >> 8;
+ mst->i2c_write_buffer[1] = reg & 0xff;
+
+ memset(mst->msg, 0, 2 * sizeof(struct i2c_msg));
+ mst->msg[0].addr = mst->i2c_addr;
+ mst->msg[0].flags = 0;
+ mst->msg[0].buf = mst->i2c_write_buffer;
+ mst->msg[0].len = 2;
+ mst->msg[1].addr = mst->i2c_addr;
+ mst->msg[1].flags = I2C_M_RD;
+ mst->msg[1].buf = mst->i2c_read_buffer;
+ mst->msg[1].len = 2;
+
+ if (i2c_transfer(mst->i2c_adap, mst->msg, 2) != 2)
dprintk("i2c read error on %d", reg);
- return (rb[0] << 8) | rb[1];
+ return (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1];
}
static int dibx000_is_i2c_done(struct dibx000_i2c_master *mst)
@@ -248,26 +257,32 @@ static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg msg[], int num)
{
struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
- struct i2c_msg m[2 + num];
- u8 tx_open[4], tx_close[4];
- memset(m, 0, sizeof(struct i2c_msg) * (2 + num));
+ if (num > 32) {
+ dprintk("%s: too much I2C message to be transmitted (%i).\
+ Maximum is 32", __func__, num);
+ return -ENOMEM;
+ }
+
+ memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_6_7);
- dibx000_i2c_gate_ctrl(mst, tx_open, msg[0].addr, 1);
- m[0].addr = mst->i2c_addr;
- m[0].buf = tx_open;
- m[0].len = 4;
+ /* open the gate */
+ dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
+ mst->msg[0].addr = mst->i2c_addr;
+ mst->msg[0].buf = &mst->i2c_write_buffer[0];
+ mst->msg[0].len = 4;
- memcpy(&m[1], msg, sizeof(struct i2c_msg) * num);
+ memcpy(&mst->msg[1], msg, sizeof(struct i2c_msg) * num);
- dibx000_i2c_gate_ctrl(mst, tx_close, 0, 0);
- m[num + 1].addr = mst->i2c_addr;
- m[num + 1].buf = tx_close;
- m[num + 1].len = 4;
+ /* close the gate */
+ dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[4], 0, 0);
+ mst->msg[num + 1].addr = mst->i2c_addr;
+ mst->msg[num + 1].buf = &mst->i2c_write_buffer[4];
+ mst->msg[num + 1].len = 4;
- return i2c_transfer(mst->i2c_adap, m, 2 + num) == 2 + num ? num : -EIO;
+ return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO;
}
static struct i2c_algorithm dibx000_i2c_gated_gpio67_algo = {
@@ -279,26 +294,32 @@ static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg msg[], int num)
{
struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
- struct i2c_msg m[2 + num];
- u8 tx_open[4], tx_close[4];
- memset(m, 0, sizeof(struct i2c_msg) * (2 + num));
+ if (num > 32) {
+ dprintk("%s: too much I2C message to be transmitted (%i).\
+ Maximum is 32", __func__, num);
+ return -ENOMEM;
+ }
+
+ memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER);
- dibx000_i2c_gate_ctrl(mst, tx_open, msg[0].addr, 1);
- m[0].addr = mst->i2c_addr;
- m[0].buf = tx_open;
- m[0].len = 4;
+ /* open the gate */
+ dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
+ mst->msg[0].addr = mst->i2c_addr;
+ mst->msg[0].buf = &mst->i2c_write_buffer[0];
+ mst->msg[0].len = 4;
- memcpy(&m[1], msg, sizeof(struct i2c_msg) * num);
+ memcpy(&mst->msg[1], msg, sizeof(struct i2c_msg) * num);
- dibx000_i2c_gate_ctrl(mst, tx_close, 0, 0);
- m[num + 1].addr = mst->i2c_addr;
- m[num + 1].buf = tx_close;
- m[num + 1].len = 4;
+ /* close the gate */
+ dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[4], 0, 0);
+ mst->msg[num + 1].addr = mst->i2c_addr;
+ mst->msg[num + 1].buf = &mst->i2c_write_buffer[4];
+ mst->msg[num + 1].len = 4;
- return i2c_transfer(mst->i2c_adap, m, 2 + num) == 2 + num ? num : -EIO;
+ return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO;
}
static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = {
diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h
index 977d343369aa..f031165c0459 100644
--- a/drivers/media/dvb/frontends/dibx000_common.h
+++ b/drivers/media/dvb/frontends/dibx000_common.h
@@ -28,6 +28,11 @@ struct dibx000_i2c_master {
u8 i2c_addr;
u16 base_reg;
+
+ /* for the I2C transfer */
+ struct i2c_msg msg[34];
+ u8 i2c_write_buffer[8];
+ u8 i2c_read_buffer[2];
};
extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst,
diff --git a/drivers/media/dvb/frontends/drx397xD.c b/drivers/media/dvb/frontends/drx397xD.c
deleted file mode 100644
index 536f02b17338..000000000000
--- a/drivers/media/dvb/frontends/drx397xD.c
+++ /dev/null
@@ -1,1511 +0,0 @@
-/*
- * Driver for Micronas drx397xD demodulator
- *
- * Copyright (C) 2007 Henk Vergonet <Henk.Vergonet@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, see <http://www.gnu.org/licenses/>.
- */
-
-#define DEBUG /* uncomment if you want debugging output */
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/firmware.h>
-#include <linux/slab.h>
-#include <asm/div64.h>
-
-#include "dvb_frontend.h"
-#include "drx397xD.h"
-
-static const char mod_name[] = "drx397xD";
-
-#define MAX_CLOCK_DRIFT 200 /* maximal 200 PPM allowed */
-
-#define F_SET_0D0h 1
-#define F_SET_0D4h 2
-
-enum fw_ix {
-#define _FW_ENTRY(a, b, c) b
-#include "drx397xD_fw.h"
-};
-
-/* chip specifics */
-struct drx397xD_state {
- struct i2c_adapter *i2c;
- struct dvb_frontend frontend;
- struct drx397xD_config config;
- enum fw_ix chip_rev;
- int flags;
- u32 bandwidth_parm; /* internal bandwidth conversions */
- u32 f_osc; /* w90: actual osc frequency [Hz] */
-};
-
-/* Firmware */
-static const char *blob_name[] = {
-#define _BLOB_ENTRY(a, b) a
-#include "drx397xD_fw.h"
-};
-
-enum blob_ix {
-#define _BLOB_ENTRY(a, b) b
-#include "drx397xD_fw.h"
-};
-
-static struct {
- const char *name;
- const struct firmware *file;
- rwlock_t lock;
- int refcnt;
- const u8 *data[ARRAY_SIZE(blob_name)];
-} fw[] = {
-#define _FW_ENTRY(a, b, c) { \
- .name = a, \
- .file = NULL, \
- .lock = __RW_LOCK_UNLOCKED(fw[c].lock), \
- .refcnt = 0, \
- .data = { } }
-#include "drx397xD_fw.h"
-};
-
-/* use only with writer lock acquired */
-static void _drx_release_fw(struct drx397xD_state *s, enum fw_ix ix)
-{
- memset(&fw[ix].data[0], 0, sizeof(fw[0].data));
- if (fw[ix].file)
- release_firmware(fw[ix].file);
-}
-
-static void drx_release_fw(struct drx397xD_state *s)
-{
- enum fw_ix ix = s->chip_rev;
-
- pr_debug("%s\n", __func__);
-
- write_lock(&fw[ix].lock);
- if (fw[ix].refcnt) {
- fw[ix].refcnt--;
- if (fw[ix].refcnt == 0)
- _drx_release_fw(s, ix);
- }
- write_unlock(&fw[ix].lock);
-}
-
-static int drx_load_fw(struct drx397xD_state *s, enum fw_ix ix)
-{
- const u8 *data;
- size_t size, len;
- int i = 0, j, rc = -EINVAL;
-
- pr_debug("%s\n", __func__);
-
- if (ix < 0 || ix >= ARRAY_SIZE(fw))
- return -EINVAL;
- s->chip_rev = ix;
-
- write_lock(&fw[ix].lock);
- if (fw[ix].file) {
- rc = 0;
- goto exit_ok;
- }
- memset(&fw[ix].data[0], 0, sizeof(fw[0].data));
-
- rc = request_firmware(&fw[ix].file, fw[ix].name, s->i2c->dev.parent);
- if (rc != 0) {
- printk(KERN_ERR "%s: Firmware \"%s\" not available\n",
- mod_name, fw[ix].name);
- goto exit_err;
- }
-
- if (!fw[ix].file->data || fw[ix].file->size < 10)
- goto exit_corrupt;
-
- data = fw[ix].file->data;
- size = fw[ix].file->size;
-
- if (data[i++] != 2) /* check firmware version */
- goto exit_corrupt;
-
- do {
- switch (data[i++]) {
- case 0x00: /* bytecode */
- if (i >= size)
- break;
- i += data[i];
- case 0x01: /* reset */
- case 0x02: /* sleep */
- i++;
- break;
- case 0xfe: /* name */
- len = strnlen(&data[i], size - i);
- if (i + len + 1 >= size)
- goto exit_corrupt;
- if (data[i + len + 1] != 0)
- goto exit_corrupt;
- for (j = 0; j < ARRAY_SIZE(blob_name); j++) {
- if (strcmp(blob_name[j], &data[i]) == 0) {
- fw[ix].data[j] = &data[i + len + 1];
- pr_debug("Loading %s\n", blob_name[j]);
- }
- }
- i += len + 1;
- break;
- case 0xff: /* file terminator */
- if (i == size) {
- rc = 0;
- goto exit_ok;
- }
- default:
- goto exit_corrupt;
- }
- } while (i < size);
-
-exit_corrupt:
- printk(KERN_ERR "%s: Firmware is corrupt\n", mod_name);
-exit_err:
- _drx_release_fw(s, ix);
- fw[ix].refcnt--;
-exit_ok:
- fw[ix].refcnt++;
- write_unlock(&fw[ix].lock);
-
- return rc;
-}
-
-/* i2c bus IO */
-static int write_fw(struct drx397xD_state *s, enum blob_ix ix)
-{
- const u8 *data;
- int len, rc = 0, i = 0;
- struct i2c_msg msg = {
- .addr = s->config.demod_address,
- .flags = 0
- };
-
- if (ix < 0 || ix >= ARRAY_SIZE(blob_name)) {
- pr_debug("%s drx_fw_ix_t out of range\n", __func__);
- return -EINVAL;
- }
- pr_debug("%s %s\n", __func__, blob_name[ix]);
-
- read_lock(&fw[s->chip_rev].lock);
- data = fw[s->chip_rev].data[ix];
- if (!data) {
- rc = -EINVAL;
- goto exit_rc;
- }
-
- for (;;) {
- switch (data[i++]) {
- case 0: /* bytecode */
- len = data[i++];
- msg.len = len;
- msg.buf = (__u8 *) &data[i];
- if (i2c_transfer(s->i2c, &msg, 1) != 1) {
- rc = -EIO;
- goto exit_rc;
- }
- i += len;
- break;
- case 1: /* reset */
- case 2: /* sleep */
- i++;
- break;
- default:
- goto exit_rc;
- }
- }
-exit_rc:
- read_unlock(&fw[s->chip_rev].lock);
-
- return rc;
-}
-
-/* Function is not endian safe, use the RD16 wrapper below */
-static int _read16(struct drx397xD_state *s, __le32 i2c_adr)
-{
- int rc;
- u8 a[4];
- __le16 v;
- struct i2c_msg msg[2] = {
- {
- .addr = s->config.demod_address,
- .flags = 0,
- .buf = a,
- .len = sizeof(a)
- }, {
- .addr = s->config.demod_address,
- .flags = I2C_M_RD,
- .buf = (u8 *)&v,
- .len = sizeof(v)
- }
- };
-
- *(__le32 *) a = i2c_adr;
-
- rc = i2c_transfer(s->i2c, msg, 2);
- if (rc != 2)
- return -EIO;
-
- return le16_to_cpu(v);
-}
-
-/* Function is not endian safe, use the WR16.. wrappers below */
-static int _write16(struct drx397xD_state *s, __le32 i2c_adr, __le16 val)
-{
- u8 a[6];
- int rc;
- struct i2c_msg msg = {
- .addr = s->config.demod_address,
- .flags = 0,
- .buf = a,
- .len = sizeof(a)
- };
-
- *(__le32 *)a = i2c_adr;
- *(__le16 *)&a[4] = val;
-
- rc = i2c_transfer(s->i2c, &msg, 1);
- if (rc != 1)
- return -EIO;
-
- return 0;
-}
-
-#define WR16(ss, adr, val) \
- _write16(ss, I2C_ADR_C0(adr), cpu_to_le16(val))
-#define WR16_E0(ss, adr, val) \
- _write16(ss, I2C_ADR_E0(adr), cpu_to_le16(val))
-#define RD16(ss, adr) \
- _read16(ss, I2C_ADR_C0(adr))
-
-#define EXIT_RC(cmd) \
- if ((rc = (cmd)) < 0) \
- goto exit_rc
-
-/* Tuner callback */
-static int PLL_Set(struct drx397xD_state *s,
- struct dvb_frontend_parameters *fep, int *df_tuner)
-{
- struct dvb_frontend *fe = &s->frontend;
- u32 f_tuner, f = fep->frequency;
- int rc;
-
- pr_debug("%s\n", __func__);
-
- if ((f > s->frontend.ops.tuner_ops.info.frequency_max) ||
- (f < s->frontend.ops.tuner_ops.info.frequency_min))
- return -EINVAL;
-
- *df_tuner = 0;
- if (!s->frontend.ops.tuner_ops.set_params ||
- !s->frontend.ops.tuner_ops.get_frequency)
- return -ENOSYS;
-
- rc = s->frontend.ops.tuner_ops.set_params(fe, fep);
- if (rc < 0)
- return rc;
-
- rc = s->frontend.ops.tuner_ops.get_frequency(fe, &f_tuner);
- if (rc < 0)
- return rc;
-
- *df_tuner = f_tuner - f;
- pr_debug("%s requested %d [Hz] tuner %d [Hz]\n", __func__, f,
- f_tuner);
-
- return 0;
-}
-
-/* Demodulator helper functions */
-static int SC_WaitForReady(struct drx397xD_state *s)
-{
- int cnt = 1000;
- int rc;
-
- pr_debug("%s\n", __func__);
-
- while (cnt--) {
- rc = RD16(s, 0x820043);
- if (rc == 0)
- return 0;
- }
-
- return -1;
-}
-
-static int SC_SendCommand(struct drx397xD_state *s, int cmd)
-{
- int rc;
-
- pr_debug("%s\n", __func__);
-
- WR16(s, 0x820043, cmd);
- SC_WaitForReady(s);
- rc = RD16(s, 0x820042);
- if ((rc & 0xffff) == 0xffff)
- return -1;
-
- return 0;
-}
-
-static int HI_Command(struct drx397xD_state *s, u16 cmd)
-{
- int rc, cnt = 1000;
-
- pr_debug("%s\n", __func__);
-
- rc = WR16(s, 0x420032, cmd);
- if (rc < 0)
- return rc;
-
- do {
- rc = RD16(s, 0x420032);
- if (rc == 0) {
- rc = RD16(s, 0x420031);
- return rc;
- }
- if (rc < 0)
- return rc;
- } while (--cnt);
-
- return rc;
-}
-
-static int HI_CfgCommand(struct drx397xD_state *s)
-{
-
- pr_debug("%s\n", __func__);
-
- WR16(s, 0x420033, 0x3973);
- WR16(s, 0x420034, s->config.w50); /* code 4, log 4 */
- WR16(s, 0x420035, s->config.w52); /* code 15, log 9 */
- WR16(s, 0x420036, s->config.demod_address << 1);
- WR16(s, 0x420037, s->config.w56); /* code (set_i2c ?? initX 1 ), log 1 */
- /* WR16(s, 0x420033, 0x3973); */
- if ((s->config.w56 & 8) == 0)
- return HI_Command(s, 3);
-
- return WR16(s, 0x420032, 0x3);
-}
-
-static const u8 fastIncrDecLUT_15273[] = {
- 0x0e, 0x0f, 0x0f, 0x10, 0x11, 0x12, 0x12, 0x13, 0x14,
- 0x15, 0x16, 0x17, 0x18, 0x1a, 0x1b, 0x1c, 0x1d, 0x1f
-};
-
-static const u8 slowIncrDecLUT_15272[] = {
- 3, 4, 4, 5, 6
-};
-
-static int SetCfgIfAgc(struct drx397xD_state *s, struct drx397xD_CfgIfAgc *agc)
-{
- u16 w06 = agc->w06;
- u16 w08 = agc->w08;
- u16 w0A = agc->w0A;
- u16 w0C = agc->w0C;
- int quot, rem, i, rc = -EINVAL;
-
- pr_debug("%s\n", __func__);
-
- if (agc->w04 > 0x3ff)
- goto exit_rc;
-
- if (agc->d00 == 1) {
- EXIT_RC(RD16(s, 0x0c20010));
- rc &= ~0x10;
- EXIT_RC(WR16(s, 0x0c20010, rc));
- return WR16(s, 0x0c20030, agc->w04 & 0x7ff);
- }
-
- if (agc->d00 != 0)
- goto exit_rc;
- if (w0A < w08)
- goto exit_rc;
- if (w0A > 0x3ff)
- goto exit_rc;
- if (w0C > 0x3ff)
- goto exit_rc;
- if (w06 > 0x3ff)
- goto exit_rc;
-
- EXIT_RC(RD16(s, 0x0c20010));
- rc |= 0x10;
- EXIT_RC(WR16(s, 0x0c20010, rc));
-
- EXIT_RC(WR16(s, 0x0c20025, (w06 >> 1) & 0x1ff));
- EXIT_RC(WR16(s, 0x0c20031, (w0A - w08) >> 1));
- EXIT_RC(WR16(s, 0x0c20032, ((w0A + w08) >> 1) - 0x1ff));
-
- quot = w0C / 113;
- rem = w0C % 113;
- if (quot <= 8) {
- quot = 8 - quot;
- } else {
- quot = 0;
- rem += 113;
- }
-
- EXIT_RC(WR16(s, 0x0c20024, quot));
-
- i = fastIncrDecLUT_15273[rem / 8];
- EXIT_RC(WR16(s, 0x0c2002d, i));
- EXIT_RC(WR16(s, 0x0c2002e, i));
-
- i = slowIncrDecLUT_15272[rem / 28];
- EXIT_RC(WR16(s, 0x0c2002b, i));
- rc = WR16(s, 0x0c2002c, i);
-exit_rc:
- return rc;
-}
-
-static int SetCfgRfAgc(struct drx397xD_state *s, struct drx397xD_CfgRfAgc *agc)
-{
- u16 w04 = agc->w04;
- u16 w06 = agc->w06;
- int rc = -1;
-
- pr_debug("%s %d 0x%x 0x%x\n", __func__, agc->d00, w04, w06);
-
- if (w04 > 0x3ff)
- goto exit_rc;
-
- switch (agc->d00) {
- case 1:
- if (w04 == 0x3ff)
- w04 = 0x400;
-
- EXIT_RC(WR16(s, 0x0c20036, w04));
- s->config.w9C &= ~2;
- EXIT_RC(WR16(s, 0x0c20015, s->config.w9C));
- EXIT_RC(RD16(s, 0x0c20010));
- rc &= 0xbfdf;
- EXIT_RC(WR16(s, 0x0c20010, rc));
- EXIT_RC(RD16(s, 0x0c20013));
- rc &= ~2;
- break;
- case 0:
- /* loc_8000659 */
- s->config.w9C &= ~2;
- EXIT_RC(WR16(s, 0x0c20015, s->config.w9C));
- EXIT_RC(RD16(s, 0x0c20010));
- rc &= 0xbfdf;
- rc |= 0x4000;
- EXIT_RC(WR16(s, 0x0c20010, rc));
- EXIT_RC(WR16(s, 0x0c20051, (w06 >> 4) & 0x3f));
- EXIT_RC(RD16(s, 0x0c20013));
- rc &= ~2;
- break;
- default:
- s->config.w9C |= 2;
- EXIT_RC(WR16(s, 0x0c20015, s->config.w9C));
- EXIT_RC(RD16(s, 0x0c20010));
- rc &= 0xbfdf;
- EXIT_RC(WR16(s, 0x0c20010, rc));
-
- EXIT_RC(WR16(s, 0x0c20036, 0));
-
- EXIT_RC(RD16(s, 0x0c20013));
- rc |= 2;
- }
- rc = WR16(s, 0x0c20013, rc);
-
-exit_rc:
- return rc;
-}
-
-static int GetLockStatus(struct drx397xD_state *s, int *lockstat)
-{
- int rc;
-
- *lockstat = 0;
-
- rc = RD16(s, 0x082004b);
- if (rc < 0)
- return rc;
-
- if (s->config.d60 != 2)
- return 0;
-
- if ((rc & 7) == 7)
- *lockstat |= 1;
- if ((rc & 3) == 3)
- *lockstat |= 2;
- if (rc & 1)
- *lockstat |= 4;
- return 0;
-}
-
-static int CorrectSysClockDeviation(struct drx397xD_state *s)
-{
- int rc = -EINVAL;
- int lockstat;
- u32 clk, clk_limit;
-
- pr_debug("%s\n", __func__);
-
- if (s->config.d5C == 0) {
- EXIT_RC(WR16(s, 0x08200e8, 0x010));
- EXIT_RC(WR16(s, 0x08200e9, 0x113));
- s->config.d5C = 1;
- return rc;
- }
- if (s->config.d5C != 1)
- goto exit_rc;
-
- rc = RD16(s, 0x0820048);
-
- rc = GetLockStatus(s, &lockstat);
- if (rc < 0)
- goto exit_rc;
- if ((lockstat & 1) == 0)
- goto exit_rc;
-
- EXIT_RC(WR16(s, 0x0420033, 0x200));
- EXIT_RC(WR16(s, 0x0420034, 0xc5));
- EXIT_RC(WR16(s, 0x0420035, 0x10));
- EXIT_RC(WR16(s, 0x0420036, 0x1));
- EXIT_RC(WR16(s, 0x0420037, 0xa));
- EXIT_RC(HI_Command(s, 6));
- EXIT_RC(RD16(s, 0x0420040));
- clk = rc;
- EXIT_RC(RD16(s, 0x0420041));
- clk |= rc << 16;
-
- if (clk <= 0x26ffff)
- goto exit_rc;
- if (clk > 0x610000)
- goto exit_rc;
-
- if (!s->bandwidth_parm)
- return -EINVAL;
-
- /* round & convert to Hz */
- clk = ((u64) (clk + 0x800000) * s->bandwidth_parm + (1 << 20)) >> 21;
- clk_limit = s->config.f_osc * MAX_CLOCK_DRIFT / 1000;
-
- if (clk - s->config.f_osc * 1000 + clk_limit <= 2 * clk_limit) {
- s->f_osc = clk;
- pr_debug("%s: osc %d %d [Hz]\n", __func__,
- s->config.f_osc * 1000, clk - s->config.f_osc * 1000);
- }
- rc = WR16(s, 0x08200e8, 0);
-
-exit_rc:
- return rc;
-}
-
-static int ConfigureMPEGOutput(struct drx397xD_state *s, int type)
-{
- int rc, si, bp;
-
- pr_debug("%s\n", __func__);
-
- si = s->config.wA0;
- if (s->config.w98 == 0) {
- si |= 1;
- bp = 0;
- } else {
- si &= ~1;
- bp = 0x200;
- }
- if (s->config.w9A == 0)
- si |= 0x80;
- else
- si &= ~0x80;
-
- EXIT_RC(WR16(s, 0x2150045, 0));
- EXIT_RC(WR16(s, 0x2150010, si));
- EXIT_RC(WR16(s, 0x2150011, bp));
- rc = WR16(s, 0x2150012, (type == 0 ? 0xfff : 0));
-
-exit_rc:
- return rc;
-}
-
-static int drx_tune(struct drx397xD_state *s,
- struct dvb_frontend_parameters *fep)
-{
- u16 v22 = 0;
- u16 v1C = 0;
- u16 v1A = 0;
- u16 v18 = 0;
- u32 edi = 0, ebx = 0, ebp = 0, edx = 0;
- u16 v20 = 0, v1E = 0, v16 = 0, v14 = 0, v12 = 0, v10 = 0, v0E = 0;
-
- int rc, df_tuner = 0;
- int a, b, c, d;
- pr_debug("%s %d\n", __func__, s->config.d60);
-
- if (s->config.d60 != 2)
- goto set_tuner;
- rc = CorrectSysClockDeviation(s);
- if (rc < 0)
- goto set_tuner;
-
- s->config.d60 = 1;
- rc = ConfigureMPEGOutput(s, 0);
- if (rc < 0)
- goto set_tuner;
-set_tuner:
-
- rc = PLL_Set(s, fep, &df_tuner);
- if (rc < 0) {
- printk(KERN_ERR "Error in pll_set\n");
- goto exit_rc;
- }
- msleep(200);
-
- a = rc = RD16(s, 0x2150016);
- if (rc < 0)
- goto exit_rc;
- b = rc = RD16(s, 0x2150010);
- if (rc < 0)
- goto exit_rc;
- c = rc = RD16(s, 0x2150034);
- if (rc < 0)
- goto exit_rc;
- d = rc = RD16(s, 0x2150035);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x2150014, c);
- rc = WR16(s, 0x2150015, d);
- rc = WR16(s, 0x2150010, 0);
- rc = WR16(s, 0x2150000, 2);
- rc = WR16(s, 0x2150036, 0x0fff);
- rc = WR16(s, 0x2150016, a);
-
- rc = WR16(s, 0x2150010, 2);
- rc = WR16(s, 0x2150007, 0);
- rc = WR16(s, 0x2150000, 1);
- rc = WR16(s, 0x2110000, 0);
- rc = WR16(s, 0x0800000, 0);
- rc = WR16(s, 0x2800000, 0);
- rc = WR16(s, 0x2110010, 0x664);
-
- rc = write_fw(s, DRXD_ResetECRAM);
- rc = WR16(s, 0x2110000, 1);
-
- rc = write_fw(s, DRXD_InitSC);
- if (rc < 0)
- goto exit_rc;
-
- rc = SetCfgIfAgc(s, &s->config.ifagc);
- if (rc < 0)
- goto exit_rc;
-
- rc = SetCfgRfAgc(s, &s->config.rfagc);
- if (rc < 0)
- goto exit_rc;
-
- if (fep->u.ofdm.transmission_mode != TRANSMISSION_MODE_2K)
- v22 = 1;
- switch (fep->u.ofdm.transmission_mode) {
- case TRANSMISSION_MODE_8K:
- edi = 1;
- if (s->chip_rev == DRXD_FW_B1)
- break;
-
- rc = WR16(s, 0x2010010, 0);
- if (rc < 0)
- break;
- v1C = 0x63;
- v1A = 0x53;
- v18 = 0x43;
- break;
- default:
- edi = 0;
- if (s->chip_rev == DRXD_FW_B1)
- break;
-
- rc = WR16(s, 0x2010010, 1);
- if (rc < 0)
- break;
-
- v1C = 0x61;
- v1A = 0x47;
- v18 = 0x41;
- }
-
- switch (fep->u.ofdm.guard_interval) {
- case GUARD_INTERVAL_1_4:
- edi |= 0x0c;
- break;
- case GUARD_INTERVAL_1_8:
- edi |= 0x08;
- break;
- case GUARD_INTERVAL_1_16:
- edi |= 0x04;
- break;
- case GUARD_INTERVAL_1_32:
- break;
- default:
- v22 |= 2;
- }
-
- ebx = 0;
- ebp = 0;
- v20 = 0;
- v1E = 0;
- v16 = 0;
- v14 = 0;
- v12 = 0;
- v10 = 0;
- v0E = 0;
-
- switch (fep->u.ofdm.hierarchy_information) {
- case HIERARCHY_1:
- edi |= 0x40;
- if (s->chip_rev == DRXD_FW_B1)
- break;
- rc = WR16(s, 0x1c10047, 1);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x2010012, 1);
- if (rc < 0)
- goto exit_rc;
- ebx = 0x19f;
- ebp = 0x1fb;
- v20 = 0x0c0;
- v1E = 0x195;
- v16 = 0x1d6;
- v14 = 0x1ef;
- v12 = 4;
- v10 = 5;
- v0E = 5;
- break;
- case HIERARCHY_2:
- edi |= 0x80;
- if (s->chip_rev == DRXD_FW_B1)
- break;
- rc = WR16(s, 0x1c10047, 2);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x2010012, 2);
- if (rc < 0)
- goto exit_rc;
- ebx = 0x08f;
- ebp = 0x12f;
- v20 = 0x0c0;
- v1E = 0x11e;
- v16 = 0x1d6;
- v14 = 0x15e;
- v12 = 4;
- v10 = 5;
- v0E = 5;
- break;
- case HIERARCHY_4:
- edi |= 0xc0;
- if (s->chip_rev == DRXD_FW_B1)
- break;
- rc = WR16(s, 0x1c10047, 3);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x2010012, 3);
- if (rc < 0)
- goto exit_rc;
- ebx = 0x14d;
- ebp = 0x197;
- v20 = 0x0c0;
- v1E = 0x1ce;
- v16 = 0x1d6;
- v14 = 0x11a;
- v12 = 4;
- v10 = 6;
- v0E = 5;
- break;
- default:
- v22 |= 8;
- if (s->chip_rev == DRXD_FW_B1)
- break;
- rc = WR16(s, 0x1c10047, 0);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x2010012, 0);
- if (rc < 0)
- goto exit_rc;
- /* QPSK QAM16 QAM64 */
- ebx = 0x19f; /* 62 */
- ebp = 0x1fb; /* 15 */
- v20 = 0x16a; /* 62 */
- v1E = 0x195; /* 62 */
- v16 = 0x1bb; /* 15 */
- v14 = 0x1ef; /* 15 */
- v12 = 5; /* 16 */
- v10 = 5; /* 16 */
- v0E = 5; /* 16 */
- }
-
- switch (fep->u.ofdm.constellation) {
- default:
- v22 |= 4;
- case QPSK:
- if (s->chip_rev == DRXD_FW_B1)
- break;
-
- rc = WR16(s, 0x1c10046, 0);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x2010011, 0);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x201001a, 0x10);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x201001b, 0);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x201001c, 0);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x1c10062, v20);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x1c1002a, v1C);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x1c10015, v16);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x1c10016, v12);
- if (rc < 0)
- goto exit_rc;
- break;
- case QAM_16:
- edi |= 0x10;
- if (s->chip_rev == DRXD_FW_B1)
- break;
-
- rc = WR16(s, 0x1c10046, 1);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x2010011, 1);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x201001a, 0x10);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x201001b, 4);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x201001c, 0);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x1c10062, v1E);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x1c1002a, v1A);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x1c10015, v14);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x1c10016, v10);
- if (rc < 0)
- goto exit_rc;
- break;
- case QAM_64:
- edi |= 0x20;
- rc = WR16(s, 0x1c10046, 2);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x2010011, 2);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x201001a, 0x20);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x201001b, 8);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x201001c, 2);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x1c10062, ebx);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x1c1002a, v18);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x1c10015, ebp);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x1c10016, v0E);
- if (rc < 0)
- goto exit_rc;
- break;
- }
-
- if (s->config.s20d24 == 1) {
- rc = WR16(s, 0x2010013, 0);
- } else {
- rc = WR16(s, 0x2010013, 1);
- edi |= 0x1000;
- }
-
- switch (fep->u.ofdm.code_rate_HP) {
- default:
- v22 |= 0x10;
- case FEC_1_2:
- if (s->chip_rev == DRXD_FW_B1)
- break;
- rc = WR16(s, 0x2090011, 0);
- break;
- case FEC_2_3:
- edi |= 0x200;
- if (s->chip_rev == DRXD_FW_B1)
- break;
- rc = WR16(s, 0x2090011, 1);
- break;
- case FEC_3_4:
- edi |= 0x400;
- if (s->chip_rev == DRXD_FW_B1)
- break;
- rc = WR16(s, 0x2090011, 2);
- break;
- case FEC_5_6: /* 5 */
- edi |= 0x600;
- if (s->chip_rev == DRXD_FW_B1)
- break;
- rc = WR16(s, 0x2090011, 3);
- break;
- case FEC_7_8: /* 7 */
- edi |= 0x800;
- if (s->chip_rev == DRXD_FW_B1)
- break;
- rc = WR16(s, 0x2090011, 4);
- break;
- };
- if (rc < 0)
- goto exit_rc;
-
- switch (fep->u.ofdm.bandwidth) {
- default:
- rc = -EINVAL;
- goto exit_rc;
- case BANDWIDTH_8_MHZ: /* 0 */
- case BANDWIDTH_AUTO:
- rc = WR16(s, 0x0c2003f, 0x32);
- s->bandwidth_parm = ebx = 0x8b8249;
- edx = 0;
- break;
- case BANDWIDTH_7_MHZ:
- rc = WR16(s, 0x0c2003f, 0x3b);
- s->bandwidth_parm = ebx = 0x7a1200;
- edx = 0x4807;
- break;
- case BANDWIDTH_6_MHZ:
- rc = WR16(s, 0x0c2003f, 0x47);
- s->bandwidth_parm = ebx = 0x68a1b6;
- edx = 0x0f07;
- break;
- };
-
- if (rc < 0)
- goto exit_rc;
-
- rc = WR16(s, 0x08200ec, edx);
- if (rc < 0)
- goto exit_rc;
-
- rc = RD16(s, 0x0820050);
- if (rc < 0)
- goto exit_rc;
- rc = WR16(s, 0x0820050, rc);
-
- {
- /* Configure bandwidth specific factor */
- ebx = div64_u64(((u64) (s->f_osc) << 21) + (ebx >> 1),
- (u64)ebx) - 0x800000;
- EXIT_RC(WR16(s, 0x0c50010, ebx & 0xffff));
- EXIT_RC(WR16(s, 0x0c50011, ebx >> 16));
-
- /* drx397xD oscillator calibration */
- ebx = div64_u64(((u64) (s->config.f_if + df_tuner) << 28) +
- (s->f_osc >> 1), (u64)s->f_osc);
- }
- ebx &= 0xfffffff;
- if (fep->inversion == INVERSION_ON)
- ebx = 0x10000000 - ebx;
-
- EXIT_RC(WR16(s, 0x0c30010, ebx & 0xffff));
- EXIT_RC(WR16(s, 0x0c30011, ebx >> 16));
-
- EXIT_RC(WR16(s, 0x0800000, 1));
- EXIT_RC(RD16(s, 0x0800000));
-
-
- EXIT_RC(SC_WaitForReady(s));
- EXIT_RC(WR16(s, 0x0820042, 0));
- EXIT_RC(WR16(s, 0x0820041, v22));
- EXIT_RC(WR16(s, 0x0820040, edi));
- EXIT_RC(SC_SendCommand(s, 3));
-
- rc = RD16(s, 0x0800000);
-
- SC_WaitForReady(s);
- WR16(s, 0x0820042, 0);
- WR16(s, 0x0820041, 1);
- WR16(s, 0x0820040, 1);
- SC_SendCommand(s, 1);
-
-
- rc = WR16(s, 0x2150000, 2);
- rc = WR16(s, 0x2150016, a);
- rc = WR16(s, 0x2150010, 4);
- rc = WR16(s, 0x2150036, 0);
- rc = WR16(s, 0x2150000, 1);
- s->config.d60 = 2;
-
-exit_rc:
- return rc;
-}
-
-/*******************************************************************************
- * DVB interface
- ******************************************************************************/
-
-static int drx397x_init(struct dvb_frontend *fe)
-{
- struct drx397xD_state *s = fe->demodulator_priv;
- int rc;
-
- pr_debug("%s\n", __func__);
-
- s->config.rfagc.d00 = 2; /* 0x7c */
- s->config.rfagc.w04 = 0;
- s->config.rfagc.w06 = 0x3ff;
-
- s->config.ifagc.d00 = 0; /* 0x68 */
- s->config.ifagc.w04 = 0;
- s->config.ifagc.w06 = 140;
- s->config.ifagc.w08 = 0;
- s->config.ifagc.w0A = 0x3ff;
- s->config.ifagc.w0C = 0x388;
-
- /* for signal strength calculations */
- s->config.ss76 = 820;
- s->config.ss78 = 2200;
- s->config.ss7A = 150;
-
- /* HI_CfgCommand */
- s->config.w50 = 4;
- s->config.w52 = 9;
-
- s->config.f_if = 42800000; /* d14: intermediate frequency [Hz] */
- s->config.f_osc = 48000; /* s66 : oscillator frequency [kHz] */
- s->config.w92 = 12000;
-
- s->config.w9C = 0x000e;
- s->config.w9E = 0x0000;
-
- /* ConfigureMPEGOutput params */
- s->config.wA0 = 4;
- s->config.w98 = 1;
- s->config.w9A = 1;
-
- /* get chip revision */
- rc = RD16(s, 0x2410019);
- if (rc < 0)
- return -ENODEV;
-
- if (rc == 0) {
- printk(KERN_INFO "%s: chip revision A2\n", mod_name);
- rc = drx_load_fw(s, DRXD_FW_A2);
- } else {
-
- rc = (rc >> 12) - 3;
- switch (rc) {
- case 1:
- s->flags |= F_SET_0D4h;
- case 0:
- case 4:
- s->flags |= F_SET_0D0h;
- break;
- case 2:
- case 5:
- break;
- case 3:
- s->flags |= F_SET_0D4h;
- break;
- default:
- return -ENODEV;
- };
- printk(KERN_INFO "%s: chip revision B1.%d\n", mod_name, rc);
- rc = drx_load_fw(s, DRXD_FW_B1);
- }
- if (rc < 0)
- goto error;
-
- rc = WR16(s, 0x0420033, 0x3973);
- if (rc < 0)
- goto error;
-
- rc = HI_Command(s, 2);
-
- msleep(1);
-
- if (s->chip_rev == DRXD_FW_A2) {
- rc = WR16(s, 0x043012d, 0x47F);
- if (rc < 0)
- goto error;
- }
- rc = WR16_E0(s, 0x0400000, 0);
- if (rc < 0)
- goto error;
-
- if (s->config.w92 > 20000 || s->config.w92 % 4000) {
- printk(KERN_ERR "%s: invalid osc frequency\n", mod_name);
- rc = -1;
- goto error;
- }
-
- rc = WR16(s, 0x2410010, 1);
- if (rc < 0)
- goto error;
- rc = WR16(s, 0x2410011, 0x15);
- if (rc < 0)
- goto error;
- rc = WR16(s, 0x2410012, s->config.w92 / 4000);
- if (rc < 0)
- goto error;
-#ifdef ORIG_FW
- rc = WR16(s, 0x2410015, 2);
- if (rc < 0)
- goto error;
-#endif
- rc = WR16(s, 0x2410017, 0x3973);
- if (rc < 0)
- goto error;
-
- s->f_osc = s->config.f_osc * 1000; /* initial estimator */
-
- s->config.w56 = 1;
-
- rc = HI_CfgCommand(s);
- if (rc < 0)
- goto error;
-
- rc = write_fw(s, DRXD_InitAtomicRead);
- if (rc < 0)
- goto error;
-
- if (s->chip_rev == DRXD_FW_A2) {
- rc = WR16(s, 0x2150013, 0);
- if (rc < 0)
- goto error;
- }
-
- rc = WR16_E0(s, 0x0400002, 0);
- if (rc < 0)
- goto error;
- rc = WR16(s, 0x0400002, 0);
- if (rc < 0)
- goto error;
-
- if (s->chip_rev == DRXD_FW_A2) {
- rc = write_fw(s, DRXD_ResetCEFR);
- if (rc < 0)
- goto error;
- }
- rc = write_fw(s, DRXD_microcode);
- if (rc < 0)
- goto error;
-
- s->config.w9C = 0x0e;
- if (s->flags & F_SET_0D0h) {
- s->config.w9C = 0;
- rc = RD16(s, 0x0c20010);
- if (rc < 0)
- goto write_DRXD_InitFE_1;
-
- rc &= ~0x1000;
- rc = WR16(s, 0x0c20010, rc);
- if (rc < 0)
- goto write_DRXD_InitFE_1;
-
- rc = RD16(s, 0x0c20011);
- if (rc < 0)
- goto write_DRXD_InitFE_1;
-
- rc &= ~0x8;
- rc = WR16(s, 0x0c20011, rc);
- if (rc < 0)
- goto write_DRXD_InitFE_1;
-
- rc = WR16(s, 0x0c20012, 1);
- }
-
-write_DRXD_InitFE_1:
-
- rc = write_fw(s, DRXD_InitFE_1);
- if (rc < 0)
- goto error;
-
- rc = 1;
- if (s->chip_rev == DRXD_FW_B1) {
- if (s->flags & F_SET_0D0h)
- rc = 0;
- } else {
- if (s->flags & F_SET_0D0h)
- rc = 4;
- }
-
- rc = WR16(s, 0x0C20012, rc);
- if (rc < 0)
- goto error;
-
- rc = WR16(s, 0x0C20013, s->config.w9E);
- if (rc < 0)
- goto error;
- rc = WR16(s, 0x0C20015, s->config.w9C);
- if (rc < 0)
- goto error;
-
- rc = write_fw(s, DRXD_InitFE_2);
- if (rc < 0)
- goto error;
- rc = write_fw(s, DRXD_InitFT);
- if (rc < 0)
- goto error;
- rc = write_fw(s, DRXD_InitCP);
- if (rc < 0)
- goto error;
- rc = write_fw(s, DRXD_InitCE);
- if (rc < 0)
- goto error;
- rc = write_fw(s, DRXD_InitEQ);
- if (rc < 0)
- goto error;
- rc = write_fw(s, DRXD_InitEC);
- if (rc < 0)
- goto error;
- rc = write_fw(s, DRXD_InitSC);
- if (rc < 0)
- goto error;
-
- rc = SetCfgIfAgc(s, &s->config.ifagc);
- if (rc < 0)
- goto error;
-
- rc = SetCfgRfAgc(s, &s->config.rfagc);
- if (rc < 0)
- goto error;
-
- rc = ConfigureMPEGOutput(s, 1);
- rc = WR16(s, 0x08201fe, 0x0017);
- rc = WR16(s, 0x08201ff, 0x0101);
-
- s->config.d5C = 0;
- s->config.d60 = 1;
- s->config.d48 = 1;
-
-error:
- return rc;
-}
-
-static int drx397x_get_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
-{
- return 0;
-}
-
-static int drx397x_set_frontend(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
-{
- struct drx397xD_state *s = fe->demodulator_priv;
-
- s->config.s20d24 = 1;
-
- return drx_tune(s, params);
-}
-
-static int drx397x_get_tune_settings(struct dvb_frontend *fe,
- struct dvb_frontend_tune_settings
- *fe_tune_settings)
-{
- fe_tune_settings->min_delay_ms = 10000;
- fe_tune_settings->step_size = 0;
- fe_tune_settings->max_drift = 0;
-
- return 0;
-}
-
-static int drx397x_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
- struct drx397xD_state *s = fe->demodulator_priv;
- int lockstat;
-
- GetLockStatus(s, &lockstat);
-
- *status = 0;
- if (lockstat & 2) {
- CorrectSysClockDeviation(s);
- ConfigureMPEGOutput(s, 1);
- *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI;
- }
- if (lockstat & 4)
- *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
-
- return 0;
-}
-
-static int drx397x_read_ber(struct dvb_frontend *fe, unsigned int *ber)
-{
- *ber = 0;
-
- return 0;
-}
-
-static int drx397x_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
- *snr = 0;
-
- return 0;
-}
-
-static int drx397x_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
- struct drx397xD_state *s = fe->demodulator_priv;
- int rc;
-
- if (s->config.ifagc.d00 == 2) {
- *strength = 0xffff;
- return 0;
- }
- rc = RD16(s, 0x0c20035);
- if (rc < 0) {
- *strength = 0;
- return 0;
- }
- rc &= 0x3ff;
- /* Signal strength is calculated using the following formula:
- *
- * a = 2200 * 150 / (2200 + 150);
- * a = a * 3300 / (a + 820);
- * b = 2200 * 3300 / (2200 + 820);
- * c = (((b-a) * rc) >> 10 + a) << 4;
- * strength = ~c & 0xffff;
- *
- * The following does the same but with less rounding errors:
- */
- *strength = ~(7720 + (rc * 30744 >> 10));
-
- return 0;
-}
-
-static int drx397x_read_ucblocks(struct dvb_frontend *fe,
- unsigned int *ucblocks)
-{
- *ucblocks = 0;
-
- return 0;
-}
-
-static int drx397x_sleep(struct dvb_frontend *fe)
-{
- return 0;
-}
-
-static void drx397x_release(struct dvb_frontend *fe)
-{
- struct drx397xD_state *s = fe->demodulator_priv;
- printk(KERN_INFO "%s: release demodulator\n", mod_name);
- if (s) {
- drx_release_fw(s);
- kfree(s);
- }
-
-}
-
-static struct dvb_frontend_ops drx397x_ops = {
-
- .info = {
- .name = "Micronas DRX397xD DVB-T Frontend",
- .type = FE_OFDM,
- .frequency_min = 47125000,
- .frequency_max = 855250000,
- .frequency_stepsize = 166667,
- .frequency_tolerance = 0,
- .caps = /* 0x0C01B2EAE */
- FE_CAN_FEC_1_2 | /* = 0x2, */
- FE_CAN_FEC_2_3 | /* = 0x4, */
- FE_CAN_FEC_3_4 | /* = 0x8, */
- FE_CAN_FEC_5_6 | /* = 0x20, */
- FE_CAN_FEC_7_8 | /* = 0x80, */
- FE_CAN_FEC_AUTO | /* = 0x200, */
- FE_CAN_QPSK | /* = 0x400, */
- FE_CAN_QAM_16 | /* = 0x800, */
- FE_CAN_QAM_64 | /* = 0x2000, */
- FE_CAN_QAM_AUTO | /* = 0x10000, */
- FE_CAN_TRANSMISSION_MODE_AUTO | /* = 0x20000, */
- FE_CAN_GUARD_INTERVAL_AUTO | /* = 0x80000, */
- FE_CAN_HIERARCHY_AUTO | /* = 0x100000, */
- FE_CAN_RECOVER | /* = 0x40000000, */
- FE_CAN_MUTE_TS /* = 0x80000000 */
- },
-
- .release = drx397x_release,
- .init = drx397x_init,
- .sleep = drx397x_sleep,
-
- .set_frontend = drx397x_set_frontend,
- .get_tune_settings = drx397x_get_tune_settings,
- .get_frontend = drx397x_get_frontend,
-
- .read_status = drx397x_read_status,
- .read_snr = drx397x_read_snr,
- .read_signal_strength = drx397x_read_signal_strength,
- .read_ber = drx397x_read_ber,
- .read_ucblocks = drx397x_read_ucblocks,
-};
-
-struct dvb_frontend *drx397xD_attach(const struct drx397xD_config *config,
- struct i2c_adapter *i2c)
-{
- struct drx397xD_state *state;
-
- /* allocate memory for the internal state */
- state = kzalloc(sizeof(struct drx397xD_state), GFP_KERNEL);
- if (!state)
- goto error;
-
- /* setup the state */
- state->i2c = i2c;
- memcpy(&state->config, config, sizeof(struct drx397xD_config));
-
- /* check if the demod is there */
- if (RD16(state, 0x2410019) < 0)
- goto error;
-
- /* create dvb_frontend */
- memcpy(&state->frontend.ops, &drx397x_ops,
- sizeof(struct dvb_frontend_ops));
- state->frontend.demodulator_priv = state;
-
- return &state->frontend;
-error:
- kfree(state);
-
- return NULL;
-}
-EXPORT_SYMBOL(drx397xD_attach);
-
-MODULE_DESCRIPTION("Micronas DRX397xD DVB-T Frontend");
-MODULE_AUTHOR("Henk Vergonet");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/media/dvb/frontends/drx397xD.h b/drivers/media/dvb/frontends/drx397xD.h
deleted file mode 100644
index ba05d17290c6..000000000000
--- a/drivers/media/dvb/frontends/drx397xD.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Driver for Micronas DVB-T drx397xD demodulator
- *
- * Copyright (C) 2007 Henk vergonet <Henk.Vergonet@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., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#ifndef _DRX397XD_H_INCLUDED
-#define _DRX397XD_H_INCLUDED
-
-#include <linux/dvb/frontend.h>
-
-#define DRX_F_STEPSIZE 166667
-#define DRX_F_OFFSET 36000000
-
-#define I2C_ADR_C0(x) \
-( cpu_to_le32( \
- (u32)( \
- (((u32)(x) & (u32)0x000000ffUL) ) | \
- (((u32)(x) & (u32)0x0000ff00UL) << 16) | \
- (((u32)(x) & (u32)0x0fff0000UL) >> 8) | \
- ( (u32)0x00c00000UL) \
- )) \
-)
-
-#define I2C_ADR_E0(x) \
-( cpu_to_le32( \
- (u32)( \
- (((u32)(x) & (u32)0x000000ffUL) ) | \
- (((u32)(x) & (u32)0x0000ff00UL) << 16) | \
- (((u32)(x) & (u32)0x0fff0000UL) >> 8) | \
- ( (u32)0x00e00000UL) \
- )) \
-)
-
-struct drx397xD_CfgRfAgc /* 0x7c */
-{
- int d00; /* 2 */
- u16 w04;
- u16 w06;
-};
-
-struct drx397xD_CfgIfAgc /* 0x68 */
-{
- int d00; /* 0 */
- u16 w04; /* 0 */
- u16 w06;
- u16 w08;
- u16 w0A;
- u16 w0C;
-};
-
-struct drx397xD_s20 {
- int d04;
- u32 d18;
- u32 d1C;
- u32 d20;
- u32 d14;
- u32 d24;
- u32 d0C;
- u32 d08;
-};
-
-struct drx397xD_config
-{
- /* demodulator's I2C address */
- u8 demod_address; /* 0x0f */
-
- struct drx397xD_CfgIfAgc ifagc; /* 0x68 */
- struct drx397xD_CfgRfAgc rfagc; /* 0x7c */
- u32 s20d24;
-
- /* HI_CfgCommand parameters */
- u16 w50, w52, /* w54, */ w56;
-
- int d5C;
- int d60;
- int d48;
- int d28;
-
- u32 f_if; /* d14: intermediate frequency [Hz] */
- /* 36000000 on Cinergy 2400i DT */
- /* 42800000 on Pinnacle Hybrid PRO 330e */
-
- u16 f_osc; /* s66: 48000 oscillator frequency [kHz] */
-
- u16 w92; /* 20000 */
-
- u16 wA0;
- u16 w98;
- u16 w9A;
-
- u16 w9C; /* 0xe0 */
- u16 w9E; /* 0x00 */
-
- /* used for signal strength calculations in
- drx397x_read_signal_strength
- */
- u16 ss78; // 2200
- u16 ss7A; // 150
- u16 ss76; // 820
-};
-
-#if defined(CONFIG_DVB_DRX397XD) || (defined(CONFIG_DVB_DRX397XD_MODULE) && defined(MODULE))
-extern struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config,
- struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config,
- struct i2c_adapter *i2c)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return NULL;
-}
-#endif /* CONFIG_DVB_DRX397XD */
-
-#endif /* _DRX397XD_H_INCLUDED */
diff --git a/drivers/media/dvb/frontends/drx397xD_fw.h b/drivers/media/dvb/frontends/drx397xD_fw.h
deleted file mode 100644
index c8b44c1e807f..000000000000
--- a/drivers/media/dvb/frontends/drx397xD_fw.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Firmware definitions for Micronas drx397xD
- *
- * Copyright (C) 2007 Henk Vergonet <Henk.Vergonet@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, see <http://www.gnu.org/licenses/>.
- */
-
-#ifdef _FW_ENTRY
- _FW_ENTRY("drx397xD.A2.fw", DRXD_FW_A2 = 0, DRXD_FW_A2 ),
- _FW_ENTRY("drx397xD.B1.fw", DRXD_FW_B1, DRXD_FW_B1 ),
-#undef _FW_ENTRY
-#endif /* _FW_ENTRY */
-
-#ifdef _BLOB_ENTRY
- _BLOB_ENTRY("InitAtomicRead", DRXD_InitAtomicRead = 0 ),
- _BLOB_ENTRY("InitCE", DRXD_InitCE ),
- _BLOB_ENTRY("InitCP", DRXD_InitCP ),
- _BLOB_ENTRY("InitEC", DRXD_InitEC ),
- _BLOB_ENTRY("InitEQ", DRXD_InitEQ ),
- _BLOB_ENTRY("InitFE_1", DRXD_InitFE_1 ),
- _BLOB_ENTRY("InitFE_2", DRXD_InitFE_2 ),
- _BLOB_ENTRY("InitFT", DRXD_InitFT ),
- _BLOB_ENTRY("InitSC", DRXD_InitSC ),
- _BLOB_ENTRY("ResetCEFR", DRXD_ResetCEFR ),
- _BLOB_ENTRY("ResetECRAM", DRXD_ResetECRAM ),
- _BLOB_ENTRY("microcode", DRXD_microcode ),
-#undef _BLOB_ENTRY
-#endif /* _BLOB_ENTRY */
diff --git a/drivers/media/dvb/frontends/drxd.h b/drivers/media/dvb/frontends/drxd.h
new file mode 100644
index 000000000000..7113535844f2
--- /dev/null
+++ b/drivers/media/dvb/frontends/drxd.h
@@ -0,0 +1,61 @@
+/*
+ * drxd.h: DRXD DVB-T demodulator driver
+ *
+ * Copyright (C) 2005-2007 Micronas
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You 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
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef _DRXD_H_
+#define _DRXD_H_
+
+#include <linux/types.h>
+#include <linux/i2c.h>
+
+struct drxd_config {
+ u8 index;
+
+ u8 pll_address;
+ u8 pll_type;
+#define DRXD_PLL_NONE 0
+#define DRXD_PLL_DTT7520X 1
+#define DRXD_PLL_MT3X0823 2
+
+ u32 clock;
+ u8 insert_rs_byte;
+
+ u8 demod_address;
+ u8 demoda_address;
+ u8 demod_revision;
+
+ /* If the tuner is not behind an i2c gate, be sure to flip this bit
+ or else the i2c bus could get wedged */
+ u8 disable_i2c_gate_ctrl;
+
+ u32 IF;
+ int (*pll_set) (void *priv, void *priv_params,
+ u8 pll_addr, u8 demoda_addr, s32 *off);
+ s16(*osc_deviation) (void *priv, s16 dev, int flag);
+};
+
+extern
+struct dvb_frontend *drxd_attach(const struct drxd_config *config,
+ void *priv, struct i2c_adapter *i2c,
+ struct device *dev);
+extern int drxd_config_i2c(struct dvb_frontend *, int);
+#endif
diff --git a/drivers/media/dvb/frontends/drxd_firm.c b/drivers/media/dvb/frontends/drxd_firm.c
new file mode 100644
index 000000000000..5418b0b1dadc
--- /dev/null
+++ b/drivers/media/dvb/frontends/drxd_firm.c
@@ -0,0 +1,929 @@
+/*
+ * drxd_firm.c : DRXD firmware tables
+ *
+ * Copyright (C) 2006-2007 Micronas
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You 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
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+/* TODO: generate this file with a script from a settings file */
+
+/* Contains A2 firmware version: 1.4.2
+ * Contains B1 firmware version: 3.3.33
+ * Contains settings from driver 1.4.23
+*/
+
+#include "drxd_firm.h"
+
+#define ADDRESS(x) ((x) & 0xFF), (((x)>>8) & 0xFF), (((x)>>16) & 0xFF), (((x)>>24) & 0xFF)
+#define LENGTH(x) ((x) & 0xFF), (((x)>>8) & 0xFF)
+
+/* Is written via block write, must be little endian */
+#define DATA16(x) ((x) & 0xFF), (((x)>>8) & 0xFF)
+
+#define WRBLOCK(a, l) ADDRESS(a), LENGTH(l)
+#define WR16(a, d) ADDRESS(a), LENGTH(1), DATA16(d)
+
+#define END_OF_TABLE 0xFF, 0xFF, 0xFF, 0xFF
+
+/* HI firmware patches */
+
+#define HI_TR_FUNC_ADDR HI_IF_RAM_USR_BEGIN__A
+#define HI_TR_FUNC_SIZE 9 /* size of this function in instruction words */
+
+u8 DRXD_InitAtomicRead[] = {
+ WRBLOCK(HI_TR_FUNC_ADDR, HI_TR_FUNC_SIZE),
+ 0x26, 0x00, /* 0 -> ring.rdy; */
+ 0x60, 0x04, /* r0rami.dt -> ring.xba; */
+ 0x61, 0x04, /* r0rami.dt -> ring.xad; */
+ 0xE3, 0x07, /* HI_RA_RAM_USR_BEGIN -> ring.iad; */
+ 0x40, 0x00, /* (long immediate) */
+ 0x64, 0x04, /* r0rami.dt -> ring.len; */
+ 0x65, 0x04, /* r0rami.dt -> ring.ctl; */
+ 0x26, 0x00, /* 0 -> ring.rdy; */
+ 0x38, 0x00, /* 0 -> jumps.ad; */
+ END_OF_TABLE
+};
+
+/* Pins D0 and D1 of the parallel MPEG output can be used
+ to set the I2C address of a device. */
+
+#define HI_RST_FUNC_ADDR (HI_IF_RAM_USR_BEGIN__A + HI_TR_FUNC_SIZE)
+#define HI_RST_FUNC_SIZE 54 /* size of this function in instruction words */
+
+/* D0 Version */
+u8 DRXD_HiI2cPatch_1[] = {
+ WRBLOCK(HI_RST_FUNC_ADDR, HI_RST_FUNC_SIZE),
+ 0xC8, 0x07, 0x01, 0x00, /* MASK -> reg0.dt; */
+ 0xE0, 0x07, 0x15, 0x02, /* (EC__BLK << 6) + EC_OC_REG__BNK -> ring.xba; */
+ 0xE1, 0x07, 0x12, 0x00, /* EC_OC_REG_OC_MPG_SIO__A -> ring.xad; */
+ 0xA2, 0x00, /* M_BNK_ID_DAT -> ring.iba; */
+ 0x23, 0x00, /* &data -> ring.iad; */
+ 0x24, 0x00, /* 0 -> ring.len; */
+ 0xA5, 0x02, /* M_RC_CTR_SWAP | M_RC_CTR_READ -> ring.ctl; */
+ 0x26, 0x00, /* 0 -> ring.rdy; */
+ 0x42, 0x00, /* &data+1 -> w0ram.ad; */
+ 0xC0, 0x07, 0xFF, 0x0F, /* -1 -> w0ram.dt; */
+ 0x63, 0x00, /* &data+1 -> ring.iad; */
+ 0x65, 0x02, /* M_RC_CTR_SWAP | M_RC_CTR_WRITE -> ring.ctl; */
+ 0x26, 0x00, /* 0 -> ring.rdy; */
+ 0xE1, 0x07, 0x38, 0x00, /* EC_OC_REG_OCR_MPG_USR_DAT__A -> ring.xad; */
+ 0xA5, 0x02, /* M_RC_CTR_SWAP | M_RC_CTR_READ -> ring.ctl; */
+ 0x26, 0x00, /* 0 -> ring.rdy; */
+ 0xE1, 0x07, 0x12, 0x00, /* EC_OC_REG_OC_MPG_SIO__A -> ring.xad; */
+ 0x23, 0x00, /* &data -> ring.iad; */
+ 0x65, 0x02, /* M_RC_CTR_SWAP | M_RC_CTR_WRITE -> ring.ctl; */
+ 0x26, 0x00, /* 0 -> ring.rdy; */
+ 0x42, 0x00, /* &data+1 -> w0ram.ad; */
+ 0x0F, 0x04, /* r0ram.dt -> and.op; */
+ 0x1C, 0x06, /* reg0.dt -> and.tr; */
+ 0xCF, 0x04, /* and.rs -> add.op; */
+ 0xD0, 0x07, 0x70, 0x00, /* DEF_DEV_ID -> add.tr; */
+ 0xD0, 0x04, /* add.rs -> add.tr; */
+ 0xC8, 0x04, /* add.rs -> reg0.dt; */
+ 0x60, 0x00, /* reg0.dt -> w0ram.dt; */
+ 0xC2, 0x07, 0x10, 0x00, /* SLV0_BASE -> w0rami.ad; */
+ 0x01, 0x00, /* 0 -> w0rami.dt; */
+ 0x01, 0x06, /* reg0.dt -> w0rami.dt; */
+ 0xC2, 0x07, 0x20, 0x00, /* SLV1_BASE -> w0rami.ad; */
+ 0x01, 0x00, /* 0 -> w0rami.dt; */
+ 0x01, 0x06, /* reg0.dt -> w0rami.dt; */
+ 0xC2, 0x07, 0x30, 0x00, /* CMD_BASE -> w0rami.ad; */
+ 0x01, 0x00, /* 0 -> w0rami.dt; */
+ 0x01, 0x00, /* 0 -> w0rami.dt; */
+ 0x01, 0x00, /* 0 -> w0rami.dt; */
+ 0x68, 0x00, /* M_IC_SEL_PT1 -> i2c.sel; */
+ 0x29, 0x00, /* M_IC_CMD_RESET -> i2c.cmd; */
+ 0x28, 0x00, /* M_IC_SEL_PT0 -> i2c.sel; */
+ 0x29, 0x00, /* M_IC_CMD_RESET -> i2c.cmd; */
+ 0xF8, 0x07, 0x2F, 0x00, /* 0x2F -> jumps.ad; */
+
+ WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 0) + 1)),
+ (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
+ WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 1) + 1)),
+ (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
+ WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 2) + 1)),
+ (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
+ WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 3) + 1)),
+ (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
+
+ /* Force quick and dirty reset */
+ WR16(B_HI_CT_REG_COMM_STATE__A, 0),
+ END_OF_TABLE
+};
+
+/* D0,D1 Version */
+u8 DRXD_HiI2cPatch_3[] = {
+ WRBLOCK(HI_RST_FUNC_ADDR, HI_RST_FUNC_SIZE),
+ 0xC8, 0x07, 0x03, 0x00, /* MASK -> reg0.dt; */
+ 0xE0, 0x07, 0x15, 0x02, /* (EC__BLK << 6) + EC_OC_REG__BNK -> ring.xba; */
+ 0xE1, 0x07, 0x12, 0x00, /* EC_OC_REG_OC_MPG_SIO__A -> ring.xad; */
+ 0xA2, 0x00, /* M_BNK_ID_DAT -> ring.iba; */
+ 0x23, 0x00, /* &data -> ring.iad; */
+ 0x24, 0x00, /* 0 -> ring.len; */
+ 0xA5, 0x02, /* M_RC_CTR_SWAP | M_RC_CTR_READ -> ring.ctl; */
+ 0x26, 0x00, /* 0 -> ring.rdy; */
+ 0x42, 0x00, /* &data+1 -> w0ram.ad; */
+ 0xC0, 0x07, 0xFF, 0x0F, /* -1 -> w0ram.dt; */
+ 0x63, 0x00, /* &data+1 -> ring.iad; */
+ 0x65, 0x02, /* M_RC_CTR_SWAP | M_RC_CTR_WRITE -> ring.ctl; */
+ 0x26, 0x00, /* 0 -> ring.rdy; */
+ 0xE1, 0x07, 0x38, 0x00, /* EC_OC_REG_OCR_MPG_USR_DAT__A -> ring.xad; */
+ 0xA5, 0x02, /* M_RC_CTR_SWAP | M_RC_CTR_READ -> ring.ctl; */
+ 0x26, 0x00, /* 0 -> ring.rdy; */
+ 0xE1, 0x07, 0x12, 0x00, /* EC_OC_REG_OC_MPG_SIO__A -> ring.xad; */
+ 0x23, 0x00, /* &data -> ring.iad; */
+ 0x65, 0x02, /* M_RC_CTR_SWAP | M_RC_CTR_WRITE -> ring.ctl; */
+ 0x26, 0x00, /* 0 -> ring.rdy; */
+ 0x42, 0x00, /* &data+1 -> w0ram.ad; */
+ 0x0F, 0x04, /* r0ram.dt -> and.op; */
+ 0x1C, 0x06, /* reg0.dt -> and.tr; */
+ 0xCF, 0x04, /* and.rs -> add.op; */
+ 0xD0, 0x07, 0x70, 0x00, /* DEF_DEV_ID -> add.tr; */
+ 0xD0, 0x04, /* add.rs -> add.tr; */
+ 0xC8, 0x04, /* add.rs -> reg0.dt; */
+ 0x60, 0x00, /* reg0.dt -> w0ram.dt; */
+ 0xC2, 0x07, 0x10, 0x00, /* SLV0_BASE -> w0rami.ad; */
+ 0x01, 0x00, /* 0 -> w0rami.dt; */
+ 0x01, 0x06, /* reg0.dt -> w0rami.dt; */
+ 0xC2, 0x07, 0x20, 0x00, /* SLV1_BASE -> w0rami.ad; */
+ 0x01, 0x00, /* 0 -> w0rami.dt; */
+ 0x01, 0x06, /* reg0.dt -> w0rami.dt; */
+ 0xC2, 0x07, 0x30, 0x00, /* CMD_BASE -> w0rami.ad; */
+ 0x01, 0x00, /* 0 -> w0rami.dt; */
+ 0x01, 0x00, /* 0 -> w0rami.dt; */
+ 0x01, 0x00, /* 0 -> w0rami.dt; */
+ 0x68, 0x00, /* M_IC_SEL_PT1 -> i2c.sel; */
+ 0x29, 0x00, /* M_IC_CMD_RESET -> i2c.cmd; */
+ 0x28, 0x00, /* M_IC_SEL_PT0 -> i2c.sel; */
+ 0x29, 0x00, /* M_IC_CMD_RESET -> i2c.cmd; */
+ 0xF8, 0x07, 0x2F, 0x00, /* 0x2F -> jumps.ad; */
+
+ WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 0) + 1)),
+ (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
+ WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 1) + 1)),
+ (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
+ WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 2) + 1)),
+ (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
+ WR16((B_HI_IF_RAM_TRP_BPT0__AX + ((2 * 3) + 1)),
+ (u16) (HI_RST_FUNC_ADDR & 0x3FF)),
+
+ /* Force quick and dirty reset */
+ WR16(B_HI_CT_REG_COMM_STATE__A, 0),
+ END_OF_TABLE
+};
+
+u8 DRXD_ResetCEFR[] = {
+ WRBLOCK(CE_REG_FR_TREAL00__A, 57),
+ 0x52, 0x00, /* CE_REG_FR_TREAL00__A */
+ 0x00, 0x00, /* CE_REG_FR_TIMAG00__A */
+ 0x52, 0x00, /* CE_REG_FR_TREAL01__A */
+ 0x00, 0x00, /* CE_REG_FR_TIMAG01__A */
+ 0x52, 0x00, /* CE_REG_FR_TREAL02__A */
+ 0x00, 0x00, /* CE_REG_FR_TIMAG02__A */
+ 0x52, 0x00, /* CE_REG_FR_TREAL03__A */
+ 0x00, 0x00, /* CE_REG_FR_TIMAG03__A */
+ 0x52, 0x00, /* CE_REG_FR_TREAL04__A */
+ 0x00, 0x00, /* CE_REG_FR_TIMAG04__A */
+ 0x52, 0x00, /* CE_REG_FR_TREAL05__A */
+ 0x00, 0x00, /* CE_REG_FR_TIMAG05__A */
+ 0x52, 0x00, /* CE_REG_FR_TREAL06__A */
+ 0x00, 0x00, /* CE_REG_FR_TIMAG06__A */
+ 0x52, 0x00, /* CE_REG_FR_TREAL07__A */
+ 0x00, 0x00, /* CE_REG_FR_TIMAG07__A */
+ 0x52, 0x00, /* CE_REG_FR_TREAL08__A */
+ 0x00, 0x00, /* CE_REG_FR_TIMAG08__A */
+ 0x52, 0x00, /* CE_REG_FR_TREAL09__A */
+ 0x00, 0x00, /* CE_REG_FR_TIMAG09__A */
+ 0x52, 0x00, /* CE_REG_FR_TREAL10__A */
+ 0x00, 0x00, /* CE_REG_FR_TIMAG10__A */
+ 0x52, 0x00, /* CE_REG_FR_TREAL11__A */
+ 0x00, 0x00, /* CE_REG_FR_TIMAG11__A */
+
+ 0x52, 0x00, /* CE_REG_FR_MID_TAP__A */
+
+ 0x0B, 0x00, /* CE_REG_FR_SQS_G00__A */
+ 0x0B, 0x00, /* CE_REG_FR_SQS_G01__A */
+ 0x0B, 0x00, /* CE_REG_FR_SQS_G02__A */
+ 0x0B, 0x00, /* CE_REG_FR_SQS_G03__A */
+ 0x0B, 0x00, /* CE_REG_FR_SQS_G04__A */
+ 0x0B, 0x00, /* CE_REG_FR_SQS_G05__A */
+ 0x0B, 0x00, /* CE_REG_FR_SQS_G06__A */
+ 0x0B, 0x00, /* CE_REG_FR_SQS_G07__A */
+ 0x0B, 0x00, /* CE_REG_FR_SQS_G08__A */
+ 0x0B, 0x00, /* CE_REG_FR_SQS_G09__A */
+ 0x0B, 0x00, /* CE_REG_FR_SQS_G10__A */
+ 0x0B, 0x00, /* CE_REG_FR_SQS_G11__A */
+ 0x0B, 0x00, /* CE_REG_FR_SQS_G12__A */
+
+ 0xFF, 0x01, /* CE_REG_FR_RIO_G00__A */
+ 0x90, 0x01, /* CE_REG_FR_RIO_G01__A */
+ 0x0B, 0x01, /* CE_REG_FR_RIO_G02__A */
+ 0xC8, 0x00, /* CE_REG_FR_RIO_G03__A */
+ 0xA0, 0x00, /* CE_REG_FR_RIO_G04__A */
+ 0x85, 0x00, /* CE_REG_FR_RIO_G05__A */
+ 0x72, 0x00, /* CE_REG_FR_RIO_G06__A */
+ 0x64, 0x00, /* CE_REG_FR_RIO_G07__A */
+ 0x59, 0x00, /* CE_REG_FR_RIO_G08__A */
+ 0x50, 0x00, /* CE_REG_FR_RIO_G09__A */
+ 0x49, 0x00, /* CE_REG_FR_RIO_G10__A */
+
+ 0x10, 0x00, /* CE_REG_FR_MODE__A */
+ 0x78, 0x00, /* CE_REG_FR_SQS_TRH__A */
+ 0x00, 0x00, /* CE_REG_FR_RIO_GAIN__A */
+ 0x00, 0x02, /* CE_REG_FR_BYPASS__A */
+ 0x0D, 0x00, /* CE_REG_FR_PM_SET__A */
+ 0x07, 0x00, /* CE_REG_FR_ERR_SH__A */
+ 0x04, 0x00, /* CE_REG_FR_MAN_SH__A */
+ 0x06, 0x00, /* CE_REG_FR_TAP_SH__A */
+
+ END_OF_TABLE
+};
+
+u8 DRXD_InitFEA2_1[] = {
+ WRBLOCK(FE_AD_REG_PD__A, 3),
+ 0x00, 0x00, /* FE_AD_REG_PD__A */
+ 0x01, 0x00, /* FE_AD_REG_INVEXT__A */
+ 0x00, 0x00, /* FE_AD_REG_CLKNEG__A */
+
+ WRBLOCK(FE_AG_REG_DCE_AUR_CNT__A, 2),
+ 0x10, 0x00, /* FE_AG_REG_DCE_AUR_CNT__A */
+ 0x10, 0x00, /* FE_AG_REG_DCE_RUR_CNT__A */
+
+ WRBLOCK(FE_AG_REG_ACE_AUR_CNT__A, 2),
+ 0x0E, 0x00, /* FE_AG_REG_ACE_AUR_CNT__A */
+ 0x00, 0x00, /* FE_AG_REG_ACE_RUR_CNT__A */
+
+ WRBLOCK(FE_AG_REG_EGC_FLA_RGN__A, 5),
+ 0x04, 0x00, /* FE_AG_REG_EGC_FLA_RGN__A */
+ 0x1F, 0x00, /* FE_AG_REG_EGC_SLO_RGN__A */
+ 0x00, 0x00, /* FE_AG_REG_EGC_JMP_PSN__A */
+ 0x00, 0x00, /* FE_AG_REG_EGC_FLA_INC__A */
+ 0x00, 0x00, /* FE_AG_REG_EGC_FLA_DEC__A */
+
+ WRBLOCK(FE_AG_REG_GC1_AGC_MAX__A, 2),
+ 0xFF, 0x01, /* FE_AG_REG_GC1_AGC_MAX__A */
+ 0x00, 0xFE, /* FE_AG_REG_GC1_AGC_MIN__A */
+
+ WRBLOCK(FE_AG_REG_IND_WIN__A, 29),
+ 0x00, 0x00, /* FE_AG_REG_IND_WIN__A */
+ 0x05, 0x00, /* FE_AG_REG_IND_THD_LOL__A */
+ 0x0F, 0x00, /* FE_AG_REG_IND_THD_HIL__A */
+ 0x00, 0x00, /* FE_AG_REG_IND_DEL__A don't care */
+ 0x1E, 0x00, /* FE_AG_REG_IND_PD1_WRI__A */
+ 0x0C, 0x00, /* FE_AG_REG_PDA_AUR_CNT__A */
+ 0x00, 0x00, /* FE_AG_REG_PDA_RUR_CNT__A */
+ 0x00, 0x00, /* FE_AG_REG_PDA_AVE_DAT__A don't care */
+ 0x00, 0x00, /* FE_AG_REG_PDC_RUR_CNT__A */
+ 0x01, 0x00, /* FE_AG_REG_PDC_SET_LVL__A */
+ 0x02, 0x00, /* FE_AG_REG_PDC_FLA_RGN__A */
+ 0x00, 0x00, /* FE_AG_REG_PDC_JMP_PSN__A don't care */
+ 0xFF, 0xFF, /* FE_AG_REG_PDC_FLA_STP__A */
+ 0xFF, 0xFF, /* FE_AG_REG_PDC_SLO_STP__A */
+ 0x00, 0x1F, /* FE_AG_REG_PDC_PD2_WRI__A don't care */
+ 0x00, 0x00, /* FE_AG_REG_PDC_MAP_DAT__A don't care */
+ 0x02, 0x00, /* FE_AG_REG_PDC_MAX__A */
+ 0x0C, 0x00, /* FE_AG_REG_TGA_AUR_CNT__A */
+ 0x00, 0x00, /* FE_AG_REG_TGA_RUR_CNT__A */
+ 0x00, 0x00, /* FE_AG_REG_TGA_AVE_DAT__A don't care */
+ 0x00, 0x00, /* FE_AG_REG_TGC_RUR_CNT__A */
+ 0x22, 0x00, /* FE_AG_REG_TGC_SET_LVL__A */
+ 0x15, 0x00, /* FE_AG_REG_TGC_FLA_RGN__A */
+ 0x00, 0x00, /* FE_AG_REG_TGC_JMP_PSN__A don't care */
+ 0x01, 0x00, /* FE_AG_REG_TGC_FLA_STP__A */
+ 0x0A, 0x00, /* FE_AG_REG_TGC_SLO_STP__A */
+ 0x00, 0x00, /* FE_AG_REG_TGC_MAP_DAT__A don't care */
+ 0x10, 0x00, /* FE_AG_REG_FGA_AUR_CNT__A */
+ 0x10, 0x00, /* FE_AG_REG_FGA_RUR_CNT__A */
+
+ WRBLOCK(FE_AG_REG_BGC_FGC_WRI__A, 2),
+ 0x00, 0x00, /* FE_AG_REG_BGC_FGC_WRI__A */
+ 0x00, 0x00, /* FE_AG_REG_BGC_CGC_WRI__A */
+
+ WRBLOCK(FE_FD_REG_SCL__A, 3),
+ 0x05, 0x00, /* FE_FD_REG_SCL__A */
+ 0x03, 0x00, /* FE_FD_REG_MAX_LEV__A */
+ 0x05, 0x00, /* FE_FD_REG_NR__A */
+
+ WRBLOCK(FE_CF_REG_SCL__A, 5),
+ 0x16, 0x00, /* FE_CF_REG_SCL__A */
+ 0x04, 0x00, /* FE_CF_REG_MAX_LEV__A */
+ 0x06, 0x00, /* FE_CF_REG_NR__A */
+ 0x00, 0x00, /* FE_CF_REG_IMP_VAL__A */
+ 0x01, 0x00, /* FE_CF_REG_MEAS_VAL__A */
+
+ WRBLOCK(FE_CU_REG_FRM_CNT_RST__A, 2),
+ 0x00, 0x08, /* FE_CU_REG_FRM_CNT_RST__A */
+ 0x00, 0x00, /* FE_CU_REG_FRM_CNT_STR__A */
+
+ END_OF_TABLE
+};
+
+ /* with PGA */
+/* WR16COND( DRXD_WITH_PGA, FE_AG_REG_AG_PGA_MODE__A , 0x0004), */
+ /* without PGA */
+/* WR16COND( DRXD_WITHOUT_PGA, FE_AG_REG_AG_PGA_MODE__A , 0x0001), */
+/* WR16(FE_AG_REG_AG_AGC_SIO__A, (extAttr -> FeAgRegAgAgcSio), 0x0000 );*/
+/* WR16(FE_AG_REG_AG_PWD__A ,(extAttr -> FeAgRegAgPwd), 0x0000 );*/
+
+u8 DRXD_InitFEA2_2[] = {
+ WR16(FE_AG_REG_CDR_RUR_CNT__A, 0x0010),
+ WR16(FE_AG_REG_FGM_WRI__A, 48),
+ /* Activate measurement, activate scale */
+ WR16(FE_FD_REG_MEAS_VAL__A, 0x0001),
+
+ WR16(FE_CU_REG_COMM_EXEC__A, 0x0001),
+ WR16(FE_CF_REG_COMM_EXEC__A, 0x0001),
+ WR16(FE_IF_REG_COMM_EXEC__A, 0x0001),
+ WR16(FE_FD_REG_COMM_EXEC__A, 0x0001),
+ WR16(FE_FS_REG_COMM_EXEC__A, 0x0001),
+ WR16(FE_AD_REG_COMM_EXEC__A, 0x0001),
+ WR16(FE_AG_REG_COMM_EXEC__A, 0x0001),
+ WR16(FE_AG_REG_AG_MODE_LOP__A, 0x895E),
+
+ END_OF_TABLE
+};
+
+u8 DRXD_InitFEB1_1[] = {
+ WR16(B_FE_AD_REG_PD__A, 0x0000),
+ WR16(B_FE_AD_REG_CLKNEG__A, 0x0000),
+ WR16(B_FE_AG_REG_BGC_FGC_WRI__A, 0x0000),
+ WR16(B_FE_AG_REG_BGC_CGC_WRI__A, 0x0000),
+ WR16(B_FE_AG_REG_AG_MODE_LOP__A, 0x000a),
+ WR16(B_FE_AG_REG_IND_PD1_WRI__A, 35),
+ WR16(B_FE_AG_REG_IND_WIN__A, 0),
+ WR16(B_FE_AG_REG_IND_THD_LOL__A, 8),
+ WR16(B_FE_AG_REG_IND_THD_HIL__A, 8),
+ WR16(B_FE_CF_REG_IMP_VAL__A, 1),
+ WR16(B_FE_AG_REG_EGC_FLA_RGN__A, 7),
+ END_OF_TABLE
+};
+
+ /* with PGA */
+/* WR16(B_FE_AG_REG_AG_PGA_MODE__A , 0x0000, 0x0000); */
+ /* without PGA */
+/* WR16(B_FE_AG_REG_AG_PGA_MODE__A ,
+ B_FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN, 0x0000);*/
+ /* WR16(B_FE_AG_REG_AG_AGC_SIO__A,(extAttr -> FeAgRegAgAgcSio), 0x0000 );*//*added HS 23-05-2005 */
+/* WR16(B_FE_AG_REG_AG_PWD__A ,(extAttr -> FeAgRegAgPwd), 0x0000 );*/
+
+u8 DRXD_InitFEB1_2[] = {
+ WR16(B_FE_COMM_EXEC__A, 0x0001),
+
+ /* RF-AGC setup */
+ WR16(B_FE_AG_REG_PDA_AUR_CNT__A, 0x0C),
+ WR16(B_FE_AG_REG_PDC_SET_LVL__A, 0x01),
+ WR16(B_FE_AG_REG_PDC_FLA_RGN__A, 0x02),
+ WR16(B_FE_AG_REG_PDC_FLA_STP__A, 0xFFFF),
+ WR16(B_FE_AG_REG_PDC_SLO_STP__A, 0xFFFF),
+ WR16(B_FE_AG_REG_PDC_MAX__A, 0x02),
+ WR16(B_FE_AG_REG_TGA_AUR_CNT__A, 0x0C),
+ WR16(B_FE_AG_REG_TGC_SET_LVL__A, 0x22),
+ WR16(B_FE_AG_REG_TGC_FLA_RGN__A, 0x15),
+ WR16(B_FE_AG_REG_TGC_FLA_STP__A, 0x01),
+ WR16(B_FE_AG_REG_TGC_SLO_STP__A, 0x0A),
+
+ WR16(B_FE_CU_REG_DIV_NFC_CLP__A, 0),
+ WR16(B_FE_CU_REG_CTR_NFC_OCR__A, 25000),
+ WR16(B_FE_CU_REG_CTR_NFC_ICR__A, 1),
+ END_OF_TABLE
+};
+
+u8 DRXD_InitCPA2[] = {
+ WRBLOCK(CP_REG_BR_SPL_OFFSET__A, 2),
+ 0x07, 0x00, /* CP_REG_BR_SPL_OFFSET__A */
+ 0x0A, 0x00, /* CP_REG_BR_STR_DEL__A */
+
+ WRBLOCK(CP_REG_RT_ANG_INC0__A, 4),
+ 0x00, 0x00, /* CP_REG_RT_ANG_INC0__A */
+ 0x00, 0x00, /* CP_REG_RT_ANG_INC1__A */
+ 0x03, 0x00, /* CP_REG_RT_DETECT_ENA__A */
+ 0x03, 0x00, /* CP_REG_RT_DETECT_TRH__A */
+
+ WRBLOCK(CP_REG_AC_NEXP_OFFS__A, 5),
+ 0x32, 0x00, /* CP_REG_AC_NEXP_OFFS__A */
+ 0x62, 0x00, /* CP_REG_AC_AVER_POW__A */
+ 0x82, 0x00, /* CP_REG_AC_MAX_POW__A */
+ 0x26, 0x00, /* CP_REG_AC_WEIGHT_MAN__A */
+ 0x0F, 0x00, /* CP_REG_AC_WEIGHT_EXP__A */
+
+ WRBLOCK(CP_REG_AC_AMP_MODE__A, 2),
+ 0x02, 0x00, /* CP_REG_AC_AMP_MODE__A */
+ 0x01, 0x00, /* CP_REG_AC_AMP_FIX__A */
+
+ WR16(CP_REG_INTERVAL__A, 0x0005),
+ WR16(CP_REG_RT_EXP_MARG__A, 0x0004),
+ WR16(CP_REG_AC_ANG_MODE__A, 0x0003),
+
+ WR16(CP_REG_COMM_EXEC__A, 0x0001),
+ END_OF_TABLE
+};
+
+u8 DRXD_InitCPB1[] = {
+ WR16(B_CP_REG_BR_SPL_OFFSET__A, 0x0008),
+ WR16(B_CP_COMM_EXEC__A, 0x0001),
+ END_OF_TABLE
+};
+
+u8 DRXD_InitCEA2[] = {
+ WRBLOCK(CE_REG_AVG_POW__A, 4),
+ 0x62, 0x00, /* CE_REG_AVG_POW__A */
+ 0x78, 0x00, /* CE_REG_MAX_POW__A */
+ 0x62, 0x00, /* CE_REG_ATT__A */
+ 0x17, 0x00, /* CE_REG_NRED__A */
+
+ WRBLOCK(CE_REG_NE_ERR_SELECT__A, 2),
+ 0x07, 0x00, /* CE_REG_NE_ERR_SELECT__A */
+ 0xEB, 0xFF, /* CE_REG_NE_TD_CAL__A */
+
+ WRBLOCK(CE_REG_NE_MIXAVG__A, 2),
+ 0x06, 0x00, /* CE_REG_NE_MIXAVG__A */
+ 0x00, 0x00, /* CE_REG_NE_NUPD_OFS__A */
+
+ WRBLOCK(CE_REG_PE_NEXP_OFFS__A, 2),
+ 0x00, 0x00, /* CE_REG_PE_NEXP_OFFS__A */
+ 0x00, 0x00, /* CE_REG_PE_TIMESHIFT__A */
+
+ WRBLOCK(CE_REG_TP_A0_TAP_NEW__A, 3),
+ 0x00, 0x01, /* CE_REG_TP_A0_TAP_NEW__A */
+ 0x01, 0x00, /* CE_REG_TP_A0_TAP_NEW_VALID__A */
+ 0x0E, 0x00, /* CE_REG_TP_A0_MU_LMS_STEP__A */
+
+ WRBLOCK(CE_REG_TP_A1_TAP_NEW__A, 3),
+ 0x00, 0x00, /* CE_REG_TP_A1_TAP_NEW__A */
+ 0x01, 0x00, /* CE_REG_TP_A1_TAP_NEW_VALID__A */
+ 0x0A, 0x00, /* CE_REG_TP_A1_MU_LMS_STEP__A */
+
+ WRBLOCK(CE_REG_FI_SHT_INCR__A, 2),
+ 0x12, 0x00, /* CE_REG_FI_SHT_INCR__A */
+ 0x0C, 0x00, /* CE_REG_FI_EXP_NORM__A */
+
+ WRBLOCK(CE_REG_IR_INPUTSEL__A, 3),
+ 0x00, 0x00, /* CE_REG_IR_INPUTSEL__A */
+ 0x00, 0x00, /* CE_REG_IR_STARTPOS__A */
+ 0xFF, 0x00, /* CE_REG_IR_NEXP_THRES__A */
+
+ WR16(CE_REG_TI_NEXP_OFFS__A, 0x0000),
+
+ END_OF_TABLE
+};
+
+u8 DRXD_InitCEB1[] = {
+ WR16(B_CE_REG_TI_PHN_ENABLE__A, 0x0001),
+ WR16(B_CE_REG_FR_PM_SET__A, 0x000D),
+
+ END_OF_TABLE
+};
+
+u8 DRXD_InitEQA2[] = {
+ WRBLOCK(EQ_REG_OT_QNT_THRES0__A, 4),
+ 0x1E, 0x00, /* EQ_REG_OT_QNT_THRES0__A */
+ 0x1F, 0x00, /* EQ_REG_OT_QNT_THRES1__A */
+ 0x06, 0x00, /* EQ_REG_OT_CSI_STEP__A */
+ 0x02, 0x00, /* EQ_REG_OT_CSI_OFFSET__A */
+
+ WR16(EQ_REG_TD_REQ_SMB_CNT__A, 0x0200),
+ WR16(EQ_REG_IS_CLIP_EXP__A, 0x001F),
+ WR16(EQ_REG_SN_OFFSET__A, (u16) (-7)),
+ WR16(EQ_REG_RC_SEL_CAR__A, 0x0002),
+ WR16(EQ_REG_COMM_EXEC__A, 0x0001),
+ END_OF_TABLE
+};
+
+u8 DRXD_InitEQB1[] = {
+ WR16(B_EQ_REG_COMM_EXEC__A, 0x0001),
+ END_OF_TABLE
+};
+
+u8 DRXD_ResetECRAM[] = {
+ /* Reset packet sync bytes in EC_VD ram */
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (0 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (1 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (2 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (3 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (4 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (5 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (6 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (7 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (8 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (9 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (10 * 17), 0x0000),
+
+ /* Reset packet sync bytes in EC_RS ram */
+ WR16(EC_RS_EC_RAM__A, 0x0000),
+ WR16(EC_RS_EC_RAM__A + 204, 0x0000),
+ END_OF_TABLE
+};
+
+u8 DRXD_InitECA2[] = {
+ WRBLOCK(EC_SB_REG_CSI_HI__A, 6),
+ 0x1F, 0x00, /* EC_SB_REG_CSI_HI__A */
+ 0x1E, 0x00, /* EC_SB_REG_CSI_LO__A */
+ 0x01, 0x00, /* EC_SB_REG_SMB_TGL__A */
+ 0x7F, 0x00, /* EC_SB_REG_SNR_HI__A */
+ 0x7F, 0x00, /* EC_SB_REG_SNR_MID__A */
+ 0x7F, 0x00, /* EC_SB_REG_SNR_LO__A */
+
+ WRBLOCK(EC_RS_REG_REQ_PCK_CNT__A, 2),
+ 0x00, 0x10, /* EC_RS_REG_REQ_PCK_CNT__A */
+ DATA16(EC_RS_REG_VAL_PCK), /* EC_RS_REG_VAL__A */
+
+ WRBLOCK(EC_OC_REG_TMD_TOP_MODE__A, 5),
+ 0x03, 0x00, /* EC_OC_REG_TMD_TOP_MODE__A */
+ 0xF4, 0x01, /* EC_OC_REG_TMD_TOP_CNT__A */
+ 0xC0, 0x03, /* EC_OC_REG_TMD_HIL_MAR__A */
+ 0x40, 0x00, /* EC_OC_REG_TMD_LOL_MAR__A */
+ 0x03, 0x00, /* EC_OC_REG_TMD_CUR_CNT__A */
+
+ WRBLOCK(EC_OC_REG_AVR_ASH_CNT__A, 2),
+ 0x06, 0x00, /* EC_OC_REG_AVR_ASH_CNT__A */
+ 0x02, 0x00, /* EC_OC_REG_AVR_BSH_CNT__A */
+
+ WRBLOCK(EC_OC_REG_RCN_MODE__A, 7),
+ 0x07, 0x00, /* EC_OC_REG_RCN_MODE__A */
+ 0x00, 0x00, /* EC_OC_REG_RCN_CRA_LOP__A */
+ 0xc0, 0x00, /* EC_OC_REG_RCN_CRA_HIP__A */
+ 0x00, 0x10, /* EC_OC_REG_RCN_CST_LOP__A */
+ 0x00, 0x00, /* EC_OC_REG_RCN_CST_HIP__A */
+ 0xFF, 0x01, /* EC_OC_REG_RCN_SET_LVL__A */
+ 0x0D, 0x00, /* EC_OC_REG_RCN_GAI_LVL__A */
+
+ WRBLOCK(EC_OC_REG_RCN_CLP_LOP__A, 2),
+ 0x00, 0x00, /* EC_OC_REG_RCN_CLP_LOP__A */
+ 0xC0, 0x00, /* EC_OC_REG_RCN_CLP_HIP__A */
+
+ WR16(EC_SB_REG_CSI_OFS__A, 0x0001),
+ WR16(EC_VD_REG_FORCE__A, 0x0002),
+ WR16(EC_VD_REG_REQ_SMB_CNT__A, 0x0001),
+ WR16(EC_VD_REG_RLK_ENA__A, 0x0001),
+ WR16(EC_OD_REG_SYNC__A, 0x0664),
+ WR16(EC_OC_REG_OC_MON_SIO__A, 0x0000),
+ WR16(EC_OC_REG_SNC_ISC_LVL__A, 0x0D0C),
+ /* Output zero on monitorbus pads, power saving */
+ WR16(EC_OC_REG_OCR_MON_UOS__A,
+ (EC_OC_REG_OCR_MON_UOS_DAT_0_ENABLE |
+ EC_OC_REG_OCR_MON_UOS_DAT_1_ENABLE |
+ EC_OC_REG_OCR_MON_UOS_DAT_2_ENABLE |
+ EC_OC_REG_OCR_MON_UOS_DAT_3_ENABLE |
+ EC_OC_REG_OCR_MON_UOS_DAT_4_ENABLE |
+ EC_OC_REG_OCR_MON_UOS_DAT_5_ENABLE |
+ EC_OC_REG_OCR_MON_UOS_DAT_6_ENABLE |
+ EC_OC_REG_OCR_MON_UOS_DAT_7_ENABLE |
+ EC_OC_REG_OCR_MON_UOS_DAT_8_ENABLE |
+ EC_OC_REG_OCR_MON_UOS_DAT_9_ENABLE |
+ EC_OC_REG_OCR_MON_UOS_VAL_ENABLE |
+ EC_OC_REG_OCR_MON_UOS_CLK_ENABLE)),
+ WR16(EC_OC_REG_OCR_MON_WRI__A,
+ EC_OC_REG_OCR_MON_WRI_INIT),
+
+/* CHK_ERROR(ResetECRAM(demod)); */
+ /* Reset packet sync bytes in EC_VD ram */
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (0 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (1 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (2 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (3 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (4 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (5 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (6 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (7 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (8 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (9 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (10 * 17), 0x0000),
+
+ /* Reset packet sync bytes in EC_RS ram */
+ WR16(EC_RS_EC_RAM__A, 0x0000),
+ WR16(EC_RS_EC_RAM__A + 204, 0x0000),
+
+ WR16(EC_SB_REG_COMM_EXEC__A, 0x0001),
+ WR16(EC_VD_REG_COMM_EXEC__A, 0x0001),
+ WR16(EC_OD_REG_COMM_EXEC__A, 0x0001),
+ WR16(EC_RS_REG_COMM_EXEC__A, 0x0001),
+ END_OF_TABLE
+};
+
+u8 DRXD_InitECB1[] = {
+ WR16(B_EC_SB_REG_CSI_OFS0__A, 0x0001),
+ WR16(B_EC_SB_REG_CSI_OFS1__A, 0x0001),
+ WR16(B_EC_SB_REG_CSI_OFS2__A, 0x0001),
+ WR16(B_EC_SB_REG_CSI_LO__A, 0x000c),
+ WR16(B_EC_SB_REG_CSI_HI__A, 0x0018),
+ WR16(B_EC_SB_REG_SNR_HI__A, 0x007f),
+ WR16(B_EC_SB_REG_SNR_MID__A, 0x007f),
+ WR16(B_EC_SB_REG_SNR_LO__A, 0x007f),
+
+ WR16(B_EC_OC_REG_DTO_CLKMODE__A, 0x0002),
+ WR16(B_EC_OC_REG_DTO_PER__A, 0x0006),
+ WR16(B_EC_OC_REG_DTO_BUR__A, 0x0001),
+ WR16(B_EC_OC_REG_RCR_CLKMODE__A, 0x0000),
+ WR16(B_EC_OC_REG_RCN_GAI_LVL__A, 0x000D),
+ WR16(B_EC_OC_REG_OC_MPG_SIO__A, 0x0000),
+
+ /* Needed because shadow registers do not have correct default value */
+ WR16(B_EC_OC_REG_RCN_CST_LOP__A, 0x1000),
+ WR16(B_EC_OC_REG_RCN_CST_HIP__A, 0x0000),
+ WR16(B_EC_OC_REG_RCN_CRA_LOP__A, 0x0000),
+ WR16(B_EC_OC_REG_RCN_CRA_HIP__A, 0x00C0),
+ WR16(B_EC_OC_REG_RCN_CLP_LOP__A, 0x0000),
+ WR16(B_EC_OC_REG_RCN_CLP_HIP__A, 0x00C0),
+ WR16(B_EC_OC_REG_DTO_INC_LOP__A, 0x0000),
+ WR16(B_EC_OC_REG_DTO_INC_HIP__A, 0x00C0),
+
+ WR16(B_EC_OD_REG_SYNC__A, 0x0664),
+ WR16(B_EC_RS_REG_REQ_PCK_CNT__A, 0x1000),
+
+/* CHK_ERROR(ResetECRAM(demod)); */
+ /* Reset packet sync bytes in EC_VD ram */
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (0 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (1 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (2 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (3 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (4 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (5 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (6 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (7 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (8 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (9 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (10 * 17), 0x0000),
+
+ /* Reset packet sync bytes in EC_RS ram */
+ WR16(EC_RS_EC_RAM__A, 0x0000),
+ WR16(EC_RS_EC_RAM__A + 204, 0x0000),
+
+ WR16(B_EC_SB_REG_COMM_EXEC__A, 0x0001),
+ WR16(B_EC_VD_REG_COMM_EXEC__A, 0x0001),
+ WR16(B_EC_OD_REG_COMM_EXEC__A, 0x0001),
+ WR16(B_EC_RS_REG_COMM_EXEC__A, 0x0001),
+ END_OF_TABLE
+};
+
+u8 DRXD_ResetECA2[] = {
+
+ WR16(EC_OC_REG_COMM_EXEC__A, 0x0000),
+ WR16(EC_OD_REG_COMM_EXEC__A, 0x0000),
+
+ WRBLOCK(EC_OC_REG_TMD_TOP_MODE__A, 5),
+ 0x03, 0x00, /* EC_OC_REG_TMD_TOP_MODE__A */
+ 0xF4, 0x01, /* EC_OC_REG_TMD_TOP_CNT__A */
+ 0xC0, 0x03, /* EC_OC_REG_TMD_HIL_MAR__A */
+ 0x40, 0x00, /* EC_OC_REG_TMD_LOL_MAR__A */
+ 0x03, 0x00, /* EC_OC_REG_TMD_CUR_CNT__A */
+
+ WRBLOCK(EC_OC_REG_AVR_ASH_CNT__A, 2),
+ 0x06, 0x00, /* EC_OC_REG_AVR_ASH_CNT__A */
+ 0x02, 0x00, /* EC_OC_REG_AVR_BSH_CNT__A */
+
+ WRBLOCK(EC_OC_REG_RCN_MODE__A, 7),
+ 0x07, 0x00, /* EC_OC_REG_RCN_MODE__A */
+ 0x00, 0x00, /* EC_OC_REG_RCN_CRA_LOP__A */
+ 0xc0, 0x00, /* EC_OC_REG_RCN_CRA_HIP__A */
+ 0x00, 0x10, /* EC_OC_REG_RCN_CST_LOP__A */
+ 0x00, 0x00, /* EC_OC_REG_RCN_CST_HIP__A */
+ 0xFF, 0x01, /* EC_OC_REG_RCN_SET_LVL__A */
+ 0x0D, 0x00, /* EC_OC_REG_RCN_GAI_LVL__A */
+
+ WRBLOCK(EC_OC_REG_RCN_CLP_LOP__A, 2),
+ 0x00, 0x00, /* EC_OC_REG_RCN_CLP_LOP__A */
+ 0xC0, 0x00, /* EC_OC_REG_RCN_CLP_HIP__A */
+
+ WR16(EC_OD_REG_SYNC__A, 0x0664),
+ WR16(EC_OC_REG_OC_MON_SIO__A, 0x0000),
+ WR16(EC_OC_REG_SNC_ISC_LVL__A, 0x0D0C),
+ /* Output zero on monitorbus pads, power saving */
+ WR16(EC_OC_REG_OCR_MON_UOS__A,
+ (EC_OC_REG_OCR_MON_UOS_DAT_0_ENABLE |
+ EC_OC_REG_OCR_MON_UOS_DAT_1_ENABLE |
+ EC_OC_REG_OCR_MON_UOS_DAT_2_ENABLE |
+ EC_OC_REG_OCR_MON_UOS_DAT_3_ENABLE |
+ EC_OC_REG_OCR_MON_UOS_DAT_4_ENABLE |
+ EC_OC_REG_OCR_MON_UOS_DAT_5_ENABLE |
+ EC_OC_REG_OCR_MON_UOS_DAT_6_ENABLE |
+ EC_OC_REG_OCR_MON_UOS_DAT_7_ENABLE |
+ EC_OC_REG_OCR_MON_UOS_DAT_8_ENABLE |
+ EC_OC_REG_OCR_MON_UOS_DAT_9_ENABLE |
+ EC_OC_REG_OCR_MON_UOS_VAL_ENABLE |
+ EC_OC_REG_OCR_MON_UOS_CLK_ENABLE)),
+ WR16(EC_OC_REG_OCR_MON_WRI__A,
+ EC_OC_REG_OCR_MON_WRI_INIT),
+
+/* CHK_ERROR(ResetECRAM(demod)); */
+ /* Reset packet sync bytes in EC_VD ram */
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (0 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (1 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (2 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (3 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (4 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (5 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (6 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (7 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (8 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (9 * 17), 0x0000),
+ WR16(EC_OD_DEINT_RAM__A + 0x3b7 + (10 * 17), 0x0000),
+
+ /* Reset packet sync bytes in EC_RS ram */
+ WR16(EC_RS_EC_RAM__A, 0x0000),
+ WR16(EC_RS_EC_RAM__A + 204, 0x0000),
+
+ WR16(EC_OD_REG_COMM_EXEC__A, 0x0001),
+ END_OF_TABLE
+};
+
+u8 DRXD_InitSC[] = {
+ WR16(SC_COMM_EXEC__A, 0),
+ WR16(SC_COMM_STATE__A, 0),
+
+#ifdef COMPILE_FOR_QT
+ WR16(SC_RA_RAM_BE_OPT_DELAY__A, 0x100),
+#endif
+
+ /* SC is not started, this is done in SetChannels() */
+ END_OF_TABLE
+};
+
+/* Diversity settings */
+
+u8 DRXD_InitDiversityFront[] = {
+ /* Start demod ********* RF in , diversity out **************************** */
+ WR16(B_SC_RA_RAM_CONFIG__A, B_SC_RA_RAM_CONFIG_FR_ENABLE__M |
+ B_SC_RA_RAM_CONFIG_FREQSCAN__M),
+
+ WR16(B_SC_RA_RAM_LC_ABS_2K__A, 0x7),
+ WR16(B_SC_RA_RAM_LC_ABS_8K__A, 0x7),
+ WR16(B_SC_RA_RAM_IR_COARSE_8K_LENGTH__A, IRLEN_COARSE_8K),
+ WR16(B_SC_RA_RAM_IR_COARSE_8K_FREQINC__A, 1 << (11 - IRLEN_COARSE_8K)),
+ WR16(B_SC_RA_RAM_IR_COARSE_8K_KAISINC__A, 1 << (17 - IRLEN_COARSE_8K)),
+ WR16(B_SC_RA_RAM_IR_FINE_8K_LENGTH__A, IRLEN_FINE_8K),
+ WR16(B_SC_RA_RAM_IR_FINE_8K_FREQINC__A, 1 << (11 - IRLEN_FINE_8K)),
+ WR16(B_SC_RA_RAM_IR_FINE_8K_KAISINC__A, 1 << (17 - IRLEN_FINE_8K)),
+
+ WR16(B_SC_RA_RAM_IR_COARSE_2K_LENGTH__A, IRLEN_COARSE_2K),
+ WR16(B_SC_RA_RAM_IR_COARSE_2K_FREQINC__A, 1 << (11 - IRLEN_COARSE_2K)),
+ WR16(B_SC_RA_RAM_IR_COARSE_2K_KAISINC__A, 1 << (17 - IRLEN_COARSE_2K)),
+ WR16(B_SC_RA_RAM_IR_FINE_2K_LENGTH__A, IRLEN_FINE_2K),
+ WR16(B_SC_RA_RAM_IR_FINE_2K_FREQINC__A, 1 << (11 - IRLEN_FINE_2K)),
+ WR16(B_SC_RA_RAM_IR_FINE_2K_KAISINC__A, 1 << (17 - IRLEN_FINE_2K)),
+
+ WR16(B_LC_RA_RAM_FILTER_CRMM_A__A, 7),
+ WR16(B_LC_RA_RAM_FILTER_CRMM_B__A, 4),
+ WR16(B_LC_RA_RAM_FILTER_SRMM_A__A, 7),
+ WR16(B_LC_RA_RAM_FILTER_SRMM_B__A, 4),
+ WR16(B_LC_RA_RAM_FILTER_SYM_SET__A, 500),
+
+ WR16(B_CC_REG_DIVERSITY__A, 0x0001),
+ WR16(B_EC_OC_REG_OC_MODE_HIP__A, 0x0010),
+ WR16(B_EQ_REG_RC_SEL_CAR__A, B_EQ_REG_RC_SEL_CAR_PASS_B_CE |
+ B_EQ_REG_RC_SEL_CAR_LOCAL_B_CE | B_EQ_REG_RC_SEL_CAR_MEAS_B_CE),
+
+ /* 0x2a ), *//* CE to PASS mux */
+
+ END_OF_TABLE
+};
+
+u8 DRXD_InitDiversityEnd[] = {
+ /* End demod *********** combining RF in and diversity in, MPEG TS out **** */
+ /* disable near/far; switch on timing slave mode */
+ WR16(B_SC_RA_RAM_CONFIG__A, B_SC_RA_RAM_CONFIG_FR_ENABLE__M |
+ B_SC_RA_RAM_CONFIG_FREQSCAN__M |
+ B_SC_RA_RAM_CONFIG_DIV_ECHO_ENABLE__M |
+ B_SC_RA_RAM_CONFIG_SLAVE__M |
+ B_SC_RA_RAM_CONFIG_DIV_BLANK_ENABLE__M
+/* MV from CtrlDiversity */
+ ),
+#ifdef DRXDDIV_SRMM_SLAVING
+ WR16(SC_RA_RAM_LC_ABS_2K__A, 0x3c7),
+ WR16(SC_RA_RAM_LC_ABS_8K__A, 0x3c7),
+#else
+ WR16(SC_RA_RAM_LC_ABS_2K__A, 0x7),
+ WR16(SC_RA_RAM_LC_ABS_8K__A, 0x7),
+#endif
+
+ WR16(B_SC_RA_RAM_IR_COARSE_8K_LENGTH__A, IRLEN_COARSE_8K),
+ WR16(B_SC_RA_RAM_IR_COARSE_8K_FREQINC__A, 1 << (11 - IRLEN_COARSE_8K)),
+ WR16(B_SC_RA_RAM_IR_COARSE_8K_KAISINC__A, 1 << (17 - IRLEN_COARSE_8K)),
+ WR16(B_SC_RA_RAM_IR_FINE_8K_LENGTH__A, IRLEN_FINE_8K),
+ WR16(B_SC_RA_RAM_IR_FINE_8K_FREQINC__A, 1 << (11 - IRLEN_FINE_8K)),
+ WR16(B_SC_RA_RAM_IR_FINE_8K_KAISINC__A, 1 << (17 - IRLEN_FINE_8K)),
+
+ WR16(B_SC_RA_RAM_IR_COARSE_2K_LENGTH__A, IRLEN_COARSE_2K),
+ WR16(B_SC_RA_RAM_IR_COARSE_2K_FREQINC__A, 1 << (11 - IRLEN_COARSE_2K)),
+ WR16(B_SC_RA_RAM_IR_COARSE_2K_KAISINC__A, 1 << (17 - IRLEN_COARSE_2K)),
+ WR16(B_SC_RA_RAM_IR_FINE_2K_LENGTH__A, IRLEN_FINE_2K),
+ WR16(B_SC_RA_RAM_IR_FINE_2K_FREQINC__A, 1 << (11 - IRLEN_FINE_2K)),
+ WR16(B_SC_RA_RAM_IR_FINE_2K_KAISINC__A, 1 << (17 - IRLEN_FINE_2K)),
+
+ WR16(B_LC_RA_RAM_FILTER_CRMM_A__A, 7),
+ WR16(B_LC_RA_RAM_FILTER_CRMM_B__A, 4),
+ WR16(B_LC_RA_RAM_FILTER_SRMM_A__A, 7),
+ WR16(B_LC_RA_RAM_FILTER_SRMM_B__A, 4),
+ WR16(B_LC_RA_RAM_FILTER_SYM_SET__A, 500),
+
+ WR16(B_CC_REG_DIVERSITY__A, 0x0001),
+ END_OF_TABLE
+};
+
+u8 DRXD_DisableDiversity[] = {
+ WR16(B_SC_RA_RAM_LC_ABS_2K__A, B_SC_RA_RAM_LC_ABS_2K__PRE),
+ WR16(B_SC_RA_RAM_LC_ABS_8K__A, B_SC_RA_RAM_LC_ABS_8K__PRE),
+ WR16(B_SC_RA_RAM_IR_COARSE_8K_LENGTH__A,
+ B_SC_RA_RAM_IR_COARSE_8K_LENGTH__PRE),
+ WR16(B_SC_RA_RAM_IR_COARSE_8K_FREQINC__A,
+ B_SC_RA_RAM_IR_COARSE_8K_FREQINC__PRE),
+ WR16(B_SC_RA_RAM_IR_COARSE_8K_KAISINC__A,
+ B_SC_RA_RAM_IR_COARSE_8K_KAISINC__PRE),
+ WR16(B_SC_RA_RAM_IR_FINE_8K_LENGTH__A,
+ B_SC_RA_RAM_IR_FINE_8K_LENGTH__PRE),
+ WR16(B_SC_RA_RAM_IR_FINE_8K_FREQINC__A,
+ B_SC_RA_RAM_IR_FINE_8K_FREQINC__PRE),
+ WR16(B_SC_RA_RAM_IR_FINE_8K_KAISINC__A,
+ B_SC_RA_RAM_IR_FINE_8K_KAISINC__PRE),
+
+ WR16(B_SC_RA_RAM_IR_COARSE_2K_LENGTH__A,
+ B_SC_RA_RAM_IR_COARSE_2K_LENGTH__PRE),
+ WR16(B_SC_RA_RAM_IR_COARSE_2K_FREQINC__A,
+ B_SC_RA_RAM_IR_COARSE_2K_FREQINC__PRE),
+ WR16(B_SC_RA_RAM_IR_COARSE_2K_KAISINC__A,
+ B_SC_RA_RAM_IR_COARSE_2K_KAISINC__PRE),
+ WR16(B_SC_RA_RAM_IR_FINE_2K_LENGTH__A,
+ B_SC_RA_RAM_IR_FINE_2K_LENGTH__PRE),
+ WR16(B_SC_RA_RAM_IR_FINE_2K_FREQINC__A,
+ B_SC_RA_RAM_IR_FINE_2K_FREQINC__PRE),
+ WR16(B_SC_RA_RAM_IR_FINE_2K_KAISINC__A,
+ B_SC_RA_RAM_IR_FINE_2K_KAISINC__PRE),
+
+ WR16(B_LC_RA_RAM_FILTER_CRMM_A__A, B_LC_RA_RAM_FILTER_CRMM_A__PRE),
+ WR16(B_LC_RA_RAM_FILTER_CRMM_B__A, B_LC_RA_RAM_FILTER_CRMM_B__PRE),
+ WR16(B_LC_RA_RAM_FILTER_SRMM_A__A, B_LC_RA_RAM_FILTER_SRMM_A__PRE),
+ WR16(B_LC_RA_RAM_FILTER_SRMM_B__A, B_LC_RA_RAM_FILTER_SRMM_B__PRE),
+ WR16(B_LC_RA_RAM_FILTER_SYM_SET__A, B_LC_RA_RAM_FILTER_SYM_SET__PRE),
+
+ WR16(B_CC_REG_DIVERSITY__A, 0x0000),
+ WR16(B_EQ_REG_RC_SEL_CAR__A, B_EQ_REG_RC_SEL_CAR_INIT), /* combining disabled */
+
+ END_OF_TABLE
+};
+
+u8 DRXD_StartDiversityFront[] = {
+ /* Start demod, RF in and diversity out, no combining */
+ WR16(B_FE_CF_REG_IMP_VAL__A, 0x0),
+ WR16(B_FE_AD_REG_FDB_IN__A, 0x0),
+ WR16(B_FE_AD_REG_INVEXT__A, 0x0),
+ WR16(B_EQ_REG_COMM_MB__A, 0x12), /* EQ to MB out */
+ WR16(B_EQ_REG_RC_SEL_CAR__A, B_EQ_REG_RC_SEL_CAR_PASS_B_CE | /* CE to PASS mux */
+ B_EQ_REG_RC_SEL_CAR_LOCAL_B_CE | B_EQ_REG_RC_SEL_CAR_MEAS_B_CE),
+
+ WR16(SC_RA_RAM_ECHO_SHIFT_LIM__A, 2),
+
+ END_OF_TABLE
+};
+
+u8 DRXD_StartDiversityEnd[] = {
+ /* End demod, combining RF in and diversity in, MPEG TS out */
+ WR16(B_FE_CF_REG_IMP_VAL__A, 0x0), /* disable impulse noise cruncher */
+ WR16(B_FE_AD_REG_INVEXT__A, 0x0), /* clock inversion (for sohard board) */
+ WR16(B_CP_REG_BR_STR_DEL__A, 10), /* apperently no mb delay matching is best */
+
+ WR16(B_EQ_REG_RC_SEL_CAR__A, B_EQ_REG_RC_SEL_CAR_DIV_ON | /* org = 0x81 combining enabled */
+ B_EQ_REG_RC_SEL_CAR_MEAS_A_CC |
+ B_EQ_REG_RC_SEL_CAR_PASS_A_CC | B_EQ_REG_RC_SEL_CAR_LOCAL_A_CC),
+
+ END_OF_TABLE
+};
+
+u8 DRXD_DiversityDelay8MHZ[] = {
+ WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_32__A, 1150 - 50),
+ WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_16__A, 1100 - 50),
+ WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_8__A, 1000 - 50),
+ WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_4__A, 800 - 50),
+ WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_32__A, 5420 - 50),
+ WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_16__A, 5200 - 50),
+ WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_8__A, 4800 - 50),
+ WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_4__A, 4000 - 50),
+ END_OF_TABLE
+};
+
+u8 DRXD_DiversityDelay6MHZ[] = /* also used ok for 7 MHz */
+{
+ WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_32__A, 1100 - 50),
+ WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_16__A, 1000 - 50),
+ WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_8__A, 900 - 50),
+ WR16(B_SC_RA_RAM_DIVERSITY_DELAY_2K_4__A, 600 - 50),
+ WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_32__A, 5300 - 50),
+ WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_16__A, 5000 - 50),
+ WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_8__A, 4500 - 50),
+ WR16(B_SC_RA_RAM_DIVERSITY_DELAY_8K_4__A, 3500 - 50),
+ END_OF_TABLE
+};
diff --git a/drivers/media/dvb/frontends/drxd_firm.h b/drivers/media/dvb/frontends/drxd_firm.h
new file mode 100644
index 000000000000..41597e89941c
--- /dev/null
+++ b/drivers/media/dvb/frontends/drxd_firm.h
@@ -0,0 +1,115 @@
+/*
+ * drxd_firm.h
+ *
+ * Copyright (C) 2006-2007 Micronas
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You 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
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef _DRXD_FIRM_H_
+#define _DRXD_FIRM_H_
+
+#include <linux/types.h>
+#include "drxd_map_firm.h"
+
+#define VERSION_MAJOR 1
+#define VERSION_MINOR 4
+#define VERSION_PATCH 23
+
+#define HI_TR_FUNC_ADDR HI_IF_RAM_USR_BEGIN__A
+
+#define DRXD_MAX_RETRIES (1000)
+#define HI_I2C_DELAY 84
+#define HI_I2C_BRIDGE_DELAY 750
+
+#define EQ_TD_TPS_PWR_UNKNOWN 0x00C0 /* Unknown configurations */
+#define EQ_TD_TPS_PWR_QPSK 0x016a
+#define EQ_TD_TPS_PWR_QAM16_ALPHAN 0x0195
+#define EQ_TD_TPS_PWR_QAM16_ALPHA1 0x0195
+#define EQ_TD_TPS_PWR_QAM16_ALPHA2 0x011E
+#define EQ_TD_TPS_PWR_QAM16_ALPHA4 0x01CE
+#define EQ_TD_TPS_PWR_QAM64_ALPHAN 0x019F
+#define EQ_TD_TPS_PWR_QAM64_ALPHA1 0x019F
+#define EQ_TD_TPS_PWR_QAM64_ALPHA2 0x00F8
+#define EQ_TD_TPS_PWR_QAM64_ALPHA4 0x014D
+
+#define DRXD_DEF_AG_PWD_CONSUMER 0x000E
+#define DRXD_DEF_AG_PWD_PRO 0x0000
+#define DRXD_DEF_AG_AGC_SIO 0x0000
+
+#define DRXD_FE_CTRL_MAX 1023
+
+#define DRXD_OSCDEV_DO_SCAN (16)
+
+#define DRXD_OSCDEV_DONT_SCAN (0)
+
+#define DRXD_OSCDEV_STEP (275)
+
+#define DRXD_SCAN_TIMEOUT (650)
+
+#define DRXD_BANDWIDTH_8MHZ_IN_HZ (0x8B8249L)
+#define DRXD_BANDWIDTH_7MHZ_IN_HZ (0x7A1200L)
+#define DRXD_BANDWIDTH_6MHZ_IN_HZ (0x68A1B6L)
+
+#define IRLEN_COARSE_8K (10)
+#define IRLEN_FINE_8K (10)
+#define IRLEN_COARSE_2K (7)
+#define IRLEN_FINE_2K (9)
+#define DIFF_INVALID (511)
+#define DIFF_TARGET (4)
+#define DIFF_MARGIN (1)
+
+extern u8 DRXD_InitAtomicRead[];
+extern u8 DRXD_HiI2cPatch_1[];
+extern u8 DRXD_HiI2cPatch_3[];
+
+extern u8 DRXD_InitSC[];
+
+extern u8 DRXD_ResetCEFR[];
+extern u8 DRXD_InitFEA2_1[];
+extern u8 DRXD_InitFEA2_2[];
+extern u8 DRXD_InitCPA2[];
+extern u8 DRXD_InitCEA2[];
+extern u8 DRXD_InitEQA2[];
+extern u8 DRXD_InitECA2[];
+extern u8 DRXD_ResetECA2[];
+extern u8 DRXD_ResetECRAM[];
+
+extern u8 DRXD_A2_microcode[];
+extern u32 DRXD_A2_microcode_length;
+
+extern u8 DRXD_InitFEB1_1[];
+extern u8 DRXD_InitFEB1_2[];
+extern u8 DRXD_InitCPB1[];
+extern u8 DRXD_InitCEB1[];
+extern u8 DRXD_InitEQB1[];
+extern u8 DRXD_InitECB1[];
+
+extern u8 DRXD_InitDiversityFront[];
+extern u8 DRXD_InitDiversityEnd[];
+extern u8 DRXD_DisableDiversity[];
+extern u8 DRXD_StartDiversityFront[];
+extern u8 DRXD_StartDiversityEnd[];
+
+extern u8 DRXD_DiversityDelay8MHZ[];
+extern u8 DRXD_DiversityDelay6MHZ[];
+
+extern u8 DRXD_B1_microcode[];
+extern u32 DRXD_B1_microcode_length;
+
+#endif
diff --git a/drivers/media/dvb/frontends/drxd_hard.c b/drivers/media/dvb/frontends/drxd_hard.c
new file mode 100644
index 000000000000..ea4c1c361d2b
--- /dev/null
+++ b/drivers/media/dvb/frontends/drxd_hard.c
@@ -0,0 +1,3001 @@
+/*
+ * drxd_hard.c: DVB-T Demodulator Micronas DRX3975D-A2,DRX397xD-B1
+ *
+ * Copyright (C) 2003-2007 Micronas
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You 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
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/version.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "drxd.h"
+#include "drxd_firm.h"
+
+#define DRX_FW_FILENAME_A2 "drxd-a2-1.1.fw"
+#define DRX_FW_FILENAME_B1 "drxd-b1-1.1.fw"
+
+#define CHUNK_SIZE 48
+
+#define DRX_I2C_RMW 0x10
+#define DRX_I2C_BROADCAST 0x20
+#define DRX_I2C_CLEARCRC 0x80
+#define DRX_I2C_SINGLE_MASTER 0xC0
+#define DRX_I2C_MODEFLAGS 0xC0
+#define DRX_I2C_FLAGS 0xF0
+
+#ifndef SIZEOF_ARRAY
+#define SIZEOF_ARRAY(array) (sizeof((array))/sizeof((array)[0]))
+#endif
+
+#define DEFAULT_LOCK_TIMEOUT 1100
+
+#define DRX_CHANNEL_AUTO 0
+#define DRX_CHANNEL_HIGH 1
+#define DRX_CHANNEL_LOW 2
+
+#define DRX_LOCK_MPEG 1
+#define DRX_LOCK_FEC 2
+#define DRX_LOCK_DEMOD 4
+
+/****************************************************************************/
+
+enum CSCDState {
+ CSCD_INIT = 0,
+ CSCD_SET,
+ CSCD_SAVED
+};
+
+enum CDrxdState {
+ DRXD_UNINITIALIZED = 0,
+ DRXD_STOPPED,
+ DRXD_STARTED
+};
+
+enum AGC_CTRL_MODE {
+ AGC_CTRL_AUTO = 0,
+ AGC_CTRL_USER,
+ AGC_CTRL_OFF
+};
+
+enum OperationMode {
+ OM_Default,
+ OM_DVBT_Diversity_Front,
+ OM_DVBT_Diversity_End
+};
+
+struct SCfgAgc {
+ enum AGC_CTRL_MODE ctrlMode;
+ u16 outputLevel; /* range [0, ... , 1023], 1/n of fullscale range */
+ u16 settleLevel; /* range [0, ... , 1023], 1/n of fullscale range */
+ u16 minOutputLevel; /* range [0, ... , 1023], 1/n of fullscale range */
+ u16 maxOutputLevel; /* range [0, ... , 1023], 1/n of fullscale range */
+ u16 speed; /* range [0, ... , 1023], 1/n of fullscale range */
+
+ u16 R1;
+ u16 R2;
+ u16 R3;
+};
+
+struct SNoiseCal {
+ int cpOpt;
+ u16 cpNexpOfs;
+ u16 tdCal2k;
+ u16 tdCal8k;
+};
+
+enum app_env {
+ APPENV_STATIC = 0,
+ APPENV_PORTABLE = 1,
+ APPENV_MOBILE = 2
+};
+
+enum EIFFilter {
+ IFFILTER_SAW = 0,
+ IFFILTER_DISCRETE = 1
+};
+
+struct drxd_state {
+ struct dvb_frontend frontend;
+ struct dvb_frontend_ops ops;
+ struct dvb_frontend_parameters param;
+
+ const struct firmware *fw;
+ struct device *dev;
+
+ struct i2c_adapter *i2c;
+ void *priv;
+ struct drxd_config config;
+
+ int i2c_access;
+ int init_done;
+ struct mutex mutex;
+
+ u8 chip_adr;
+ u16 hi_cfg_timing_div;
+ u16 hi_cfg_bridge_delay;
+ u16 hi_cfg_wakeup_key;
+ u16 hi_cfg_ctrl;
+
+ u16 intermediate_freq;
+ u16 osc_clock_freq;
+
+ enum CSCDState cscd_state;
+ enum CDrxdState drxd_state;
+
+ u16 sys_clock_freq;
+ s16 osc_clock_deviation;
+ u16 expected_sys_clock_freq;
+
+ u16 insert_rs_byte;
+ u16 enable_parallel;
+
+ int operation_mode;
+
+ struct SCfgAgc if_agc_cfg;
+ struct SCfgAgc rf_agc_cfg;
+
+ struct SNoiseCal noise_cal;
+
+ u32 fe_fs_add_incr;
+ u32 org_fe_fs_add_incr;
+ u16 current_fe_if_incr;
+
+ u16 m_FeAgRegAgPwd;
+ u16 m_FeAgRegAgAgcSio;
+
+ u16 m_EcOcRegOcModeLop;
+ u16 m_EcOcRegSncSncLvl;
+ u8 *m_InitAtomicRead;
+ u8 *m_HiI2cPatch;
+
+ u8 *m_ResetCEFR;
+ u8 *m_InitFE_1;
+ u8 *m_InitFE_2;
+ u8 *m_InitCP;
+ u8 *m_InitCE;
+ u8 *m_InitEQ;
+ u8 *m_InitSC;
+ u8 *m_InitEC;
+ u8 *m_ResetECRAM;
+ u8 *m_InitDiversityFront;
+ u8 *m_InitDiversityEnd;
+ u8 *m_DisableDiversity;
+ u8 *m_StartDiversityFront;
+ u8 *m_StartDiversityEnd;
+
+ u8 *m_DiversityDelay8MHZ;
+ u8 *m_DiversityDelay6MHZ;
+
+ u8 *microcode;
+ u32 microcode_length;
+
+ int type_A;
+ int PGA;
+ int diversity;
+ int tuner_mirrors;
+
+ enum app_env app_env_default;
+ enum app_env app_env_diversity;
+
+};
+
+/****************************************************************************/
+/* I2C **********************************************************************/
+/****************************************************************************/
+
+static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 * data, int len)
+{
+ struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len };
+
+ if (i2c_transfer(adap, &msg, 1) != 1)
+ return -1;
+ return 0;
+}
+
+static int i2c_read(struct i2c_adapter *adap,
+ u8 adr, u8 *msg, int len, u8 *answ, int alen)
+{
+ struct i2c_msg msgs[2] = {
+ {
+ .addr = adr, .flags = 0,
+ .buf = msg, .len = len
+ }, {
+ .addr = adr, .flags = I2C_M_RD,
+ .buf = answ, .len = alen
+ }
+ };
+ if (i2c_transfer(adap, msgs, 2) != 2)
+ return -1;
+ return 0;
+}
+
+inline u32 MulDiv32(u32 a, u32 b, u32 c)
+{
+ u64 tmp64;
+
+ tmp64 = (u64)a * (u64)b;
+ do_div(tmp64, c);
+
+ return (u32) tmp64;
+}
+
+static int Read16(struct drxd_state *state, u32 reg, u16 *data, u8 flags)
+{
+ u8 adr = state->config.demod_address;
+ u8 mm1[4] = { reg & 0xff, (reg >> 16) & 0xff,
+ flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff
+ };
+ u8 mm2[2];
+ if (i2c_read(state->i2c, adr, mm1, 4, mm2, 2) < 0)
+ return -1;
+ if (data)
+ *data = mm2[0] | (mm2[1] << 8);
+ return mm2[0] | (mm2[1] << 8);
+}
+
+static int Read32(struct drxd_state *state, u32 reg, u32 *data, u8 flags)
+{
+ u8 adr = state->config.demod_address;
+ u8 mm1[4] = { reg & 0xff, (reg >> 16) & 0xff,
+ flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff
+ };
+ u8 mm2[4];
+
+ if (i2c_read(state->i2c, adr, mm1, 4, mm2, 4) < 0)
+ return -1;
+ if (data)
+ *data =
+ mm2[0] | (mm2[1] << 8) | (mm2[2] << 16) | (mm2[3] << 24);
+ return 0;
+}
+
+static int Write16(struct drxd_state *state, u32 reg, u16 data, u8 flags)
+{
+ u8 adr = state->config.demod_address;
+ u8 mm[6] = { reg & 0xff, (reg >> 16) & 0xff,
+ flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff,
+ data & 0xff, (data >> 8) & 0xff
+ };
+
+ if (i2c_write(state->i2c, adr, mm, 6) < 0)
+ return -1;
+ return 0;
+}
+
+static int Write32(struct drxd_state *state, u32 reg, u32 data, u8 flags)
+{
+ u8 adr = state->config.demod_address;
+ u8 mm[8] = { reg & 0xff, (reg >> 16) & 0xff,
+ flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff,
+ data & 0xff, (data >> 8) & 0xff,
+ (data >> 16) & 0xff, (data >> 24) & 0xff
+ };
+
+ if (i2c_write(state->i2c, adr, mm, 8) < 0)
+ return -1;
+ return 0;
+}
+
+static int write_chunk(struct drxd_state *state,
+ u32 reg, u8 *data, u32 len, u8 flags)
+{
+ u8 adr = state->config.demod_address;
+ u8 mm[CHUNK_SIZE + 4] = { reg & 0xff, (reg >> 16) & 0xff,
+ flags | ((reg >> 24) & 0xff), (reg >> 8) & 0xff
+ };
+ int i;
+
+ for (i = 0; i < len; i++)
+ mm[4 + i] = data[i];
+ if (i2c_write(state->i2c, adr, mm, 4 + len) < 0) {
+ printk(KERN_ERR "error in write_chunk\n");
+ return -1;
+ }
+ return 0;
+}
+
+static int WriteBlock(struct drxd_state *state,
+ u32 Address, u16 BlockSize, u8 *pBlock, u8 Flags)
+{
+ while (BlockSize > 0) {
+ u16 Chunk = BlockSize > CHUNK_SIZE ? CHUNK_SIZE : BlockSize;
+
+ if (write_chunk(state, Address, pBlock, Chunk, Flags) < 0)
+ return -1;
+ pBlock += Chunk;
+ Address += (Chunk >> 1);
+ BlockSize -= Chunk;
+ }
+ return 0;
+}
+
+static int WriteTable(struct drxd_state *state, u8 * pTable)
+{
+ int status = 0;
+
+ if (pTable == NULL)
+ return 0;
+
+ while (!status) {
+ u16 Length;
+ u32 Address = pTable[0] | (pTable[1] << 8) |
+ (pTable[2] << 16) | (pTable[3] << 24);
+
+ if (Address == 0xFFFFFFFF)
+ break;
+ pTable += sizeof(u32);
+
+ Length = pTable[0] | (pTable[1] << 8);
+ pTable += sizeof(u16);
+ if (!Length)
+ break;
+ status = WriteBlock(state, Address, Length * 2, pTable, 0);
+ pTable += (Length * 2);
+ }
+ return status;
+}
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+static int ResetCEFR(struct drxd_state *state)
+{
+ return WriteTable(state, state->m_ResetCEFR);
+}
+
+static int InitCP(struct drxd_state *state)
+{
+ return WriteTable(state, state->m_InitCP);
+}
+
+static int InitCE(struct drxd_state *state)
+{
+ int status;
+ enum app_env AppEnv = state->app_env_default;
+
+ do {
+ status = WriteTable(state, state->m_InitCE);
+ if (status < 0)
+ break;
+
+ if (state->operation_mode == OM_DVBT_Diversity_Front ||
+ state->operation_mode == OM_DVBT_Diversity_End) {
+ AppEnv = state->app_env_diversity;
+ }
+ if (AppEnv == APPENV_STATIC) {
+ status = Write16(state, CE_REG_TAPSET__A, 0x0000, 0);
+ if (status < 0)
+ break;
+ } else if (AppEnv == APPENV_PORTABLE) {
+ status = Write16(state, CE_REG_TAPSET__A, 0x0001, 0);
+ if (status < 0)
+ break;
+ } else if (AppEnv == APPENV_MOBILE && state->type_A) {
+ status = Write16(state, CE_REG_TAPSET__A, 0x0002, 0);
+ if (status < 0)
+ break;
+ } else if (AppEnv == APPENV_MOBILE && !state->type_A) {
+ status = Write16(state, CE_REG_TAPSET__A, 0x0006, 0);
+ if (status < 0)
+ break;
+ }
+
+ /* start ce */
+ status = Write16(state, B_CE_REG_COMM_EXEC__A, 0x0001, 0);
+ if (status < 0)
+ break;
+ } while (0);
+ return status;
+}
+
+static int StopOC(struct drxd_state *state)
+{
+ int status = 0;
+ u16 ocSyncLvl = 0;
+ u16 ocModeLop = state->m_EcOcRegOcModeLop;
+ u16 dtoIncLop = 0;
+ u16 dtoIncHip = 0;
+
+ do {
+ /* Store output configuration */
+ status = Read16(state, EC_OC_REG_SNC_ISC_LVL__A, &ocSyncLvl, 0);
+ if (status < 0)
+ break;
+ /* CHK_ERROR(Read16(EC_OC_REG_OC_MODE_LOP__A, &ocModeLop)); */
+ state->m_EcOcRegSncSncLvl = ocSyncLvl;
+ /* m_EcOcRegOcModeLop = ocModeLop; */
+
+ /* Flush FIFO (byte-boundary) at fixed rate */
+ status = Read16(state, EC_OC_REG_RCN_MAP_LOP__A, &dtoIncLop, 0);
+ if (status < 0)
+ break;
+ status = Read16(state, EC_OC_REG_RCN_MAP_HIP__A, &dtoIncHip, 0);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_OC_REG_DTO_INC_LOP__A, dtoIncLop, 0);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_OC_REG_DTO_INC_HIP__A, dtoIncHip, 0);
+ if (status < 0)
+ break;
+ ocModeLop &= ~(EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC__M);
+ ocModeLop |= EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC_STATIC;
+ status = Write16(state, EC_OC_REG_OC_MODE_LOP__A, ocModeLop, 0);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_OC_REG_COMM_EXEC__A, EC_OC_REG_COMM_EXEC_CTL_HOLD, 0);
+ if (status < 0)
+ break;
+
+ msleep(1);
+ /* Output pins to '0' */
+ status = Write16(state, EC_OC_REG_OCR_MPG_UOS__A, EC_OC_REG_OCR_MPG_UOS__M, 0);
+ if (status < 0)
+ break;
+
+ /* Force the OC out of sync */
+ ocSyncLvl &= ~(EC_OC_REG_SNC_ISC_LVL_OSC__M);
+ status = Write16(state, EC_OC_REG_SNC_ISC_LVL__A, ocSyncLvl, 0);
+ if (status < 0)
+ break;
+ ocModeLop &= ~(EC_OC_REG_OC_MODE_LOP_PAR_ENA__M);
+ ocModeLop |= EC_OC_REG_OC_MODE_LOP_PAR_ENA_ENABLE;
+ ocModeLop |= 0x2; /* Magically-out-of-sync */
+ status = Write16(state, EC_OC_REG_OC_MODE_LOP__A, ocModeLop, 0);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_OC_REG_COMM_INT_STA__A, 0x0, 0);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_OC_REG_COMM_EXEC__A, EC_OC_REG_COMM_EXEC_CTL_ACTIVE, 0);
+ if (status < 0)
+ break;
+ } while (0);
+
+ return status;
+}
+
+static int StartOC(struct drxd_state *state)
+{
+ int status = 0;
+
+ do {
+ /* Stop OC */
+ status = Write16(state, EC_OC_REG_COMM_EXEC__A, EC_OC_REG_COMM_EXEC_CTL_HOLD, 0);
+ if (status < 0)
+ break;
+
+ /* Restore output configuration */
+ status = Write16(state, EC_OC_REG_SNC_ISC_LVL__A, state->m_EcOcRegSncSncLvl, 0);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_OC_REG_OC_MODE_LOP__A, state->m_EcOcRegOcModeLop, 0);
+ if (status < 0)
+ break;
+
+ /* Output pins active again */
+ status = Write16(state, EC_OC_REG_OCR_MPG_UOS__A, EC_OC_REG_OCR_MPG_UOS_INIT, 0);
+ if (status < 0)
+ break;
+
+ /* Start OC */
+ status = Write16(state, EC_OC_REG_COMM_EXEC__A, EC_OC_REG_COMM_EXEC_CTL_ACTIVE, 0);
+ if (status < 0)
+ break;
+ } while (0);
+ return status;
+}
+
+static int InitEQ(struct drxd_state *state)
+{
+ return WriteTable(state, state->m_InitEQ);
+}
+
+static int InitEC(struct drxd_state *state)
+{
+ return WriteTable(state, state->m_InitEC);
+}
+
+static int InitSC(struct drxd_state *state)
+{
+ return WriteTable(state, state->m_InitSC);
+}
+
+static int InitAtomicRead(struct drxd_state *state)
+{
+ return WriteTable(state, state->m_InitAtomicRead);
+}
+
+static int CorrectSysClockDeviation(struct drxd_state *state);
+
+static int DRX_GetLockStatus(struct drxd_state *state, u32 * pLockStatus)
+{
+ u16 ScRaRamLock = 0;
+ const u16 mpeg_lock_mask = (SC_RA_RAM_LOCK_MPEG__M |
+ SC_RA_RAM_LOCK_FEC__M |
+ SC_RA_RAM_LOCK_DEMOD__M);
+ const u16 fec_lock_mask = (SC_RA_RAM_LOCK_FEC__M |
+ SC_RA_RAM_LOCK_DEMOD__M);
+ const u16 demod_lock_mask = SC_RA_RAM_LOCK_DEMOD__M;
+
+ int status;
+
+ *pLockStatus = 0;
+
+ status = Read16(state, SC_RA_RAM_LOCK__A, &ScRaRamLock, 0x0000);
+ if (status < 0) {
+ printk(KERN_ERR "Can't read SC_RA_RAM_LOCK__A status = %08x\n", status);
+ return status;
+ }
+
+ if (state->drxd_state != DRXD_STARTED)
+ return 0;
+
+ if ((ScRaRamLock & mpeg_lock_mask) == mpeg_lock_mask) {
+ *pLockStatus |= DRX_LOCK_MPEG;
+ CorrectSysClockDeviation(state);
+ }
+
+ if ((ScRaRamLock & fec_lock_mask) == fec_lock_mask)
+ *pLockStatus |= DRX_LOCK_FEC;
+
+ if ((ScRaRamLock & demod_lock_mask) == demod_lock_mask)
+ *pLockStatus |= DRX_LOCK_DEMOD;
+ return 0;
+}
+
+/****************************************************************************/
+
+static int SetCfgIfAgc(struct drxd_state *state, struct SCfgAgc *cfg)
+{
+ int status;
+
+ if (cfg->outputLevel > DRXD_FE_CTRL_MAX)
+ return -1;
+
+ if (cfg->ctrlMode == AGC_CTRL_USER) {
+ do {
+ u16 FeAgRegPm1AgcWri;
+ u16 FeAgRegAgModeLop;
+
+ status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &FeAgRegAgModeLop, 0);
+ if (status < 0)
+ break;
+ FeAgRegAgModeLop &= (~FE_AG_REG_AG_MODE_LOP_MODE_4__M);
+ FeAgRegAgModeLop |= FE_AG_REG_AG_MODE_LOP_MODE_4_STATIC;
+ status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, FeAgRegAgModeLop, 0);
+ if (status < 0)
+ break;
+
+ FeAgRegPm1AgcWri = (u16) (cfg->outputLevel &
+ FE_AG_REG_PM1_AGC_WRI__M);
+ status = Write16(state, FE_AG_REG_PM1_AGC_WRI__A, FeAgRegPm1AgcWri, 0);
+ if (status < 0)
+ break;
+ } while (0);
+ } else if (cfg->ctrlMode == AGC_CTRL_AUTO) {
+ if (((cfg->maxOutputLevel) < (cfg->minOutputLevel)) ||
+ ((cfg->maxOutputLevel) > DRXD_FE_CTRL_MAX) ||
+ ((cfg->speed) > DRXD_FE_CTRL_MAX) ||
+ ((cfg->settleLevel) > DRXD_FE_CTRL_MAX)
+ )
+ return -1;
+ do {
+ u16 FeAgRegAgModeLop;
+ u16 FeAgRegEgcSetLvl;
+ u16 slope, offset;
+
+ /* == Mode == */
+
+ status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &FeAgRegAgModeLop, 0);
+ if (status < 0)
+ break;
+ FeAgRegAgModeLop &= (~FE_AG_REG_AG_MODE_LOP_MODE_4__M);
+ FeAgRegAgModeLop |=
+ FE_AG_REG_AG_MODE_LOP_MODE_4_DYNAMIC;
+ status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, FeAgRegAgModeLop, 0);
+ if (status < 0)
+ break;
+
+ /* == Settle level == */
+
+ FeAgRegEgcSetLvl = (u16) ((cfg->settleLevel >> 1) &
+ FE_AG_REG_EGC_SET_LVL__M);
+ status = Write16(state, FE_AG_REG_EGC_SET_LVL__A, FeAgRegEgcSetLvl, 0);
+ if (status < 0)
+ break;
+
+ /* == Min/Max == */
+
+ slope = (u16) ((cfg->maxOutputLevel -
+ cfg->minOutputLevel) / 2);
+ offset = (u16) ((cfg->maxOutputLevel +
+ cfg->minOutputLevel) / 2 - 511);
+
+ status = Write16(state, FE_AG_REG_GC1_AGC_RIC__A, slope, 0);
+ if (status < 0)
+ break;
+ status = Write16(state, FE_AG_REG_GC1_AGC_OFF__A, offset, 0);
+ if (status < 0)
+ break;
+
+ /* == Speed == */
+ {
+ const u16 maxRur = 8;
+ const u16 slowIncrDecLUT[] = { 3, 4, 4, 5, 6 };
+ const u16 fastIncrDecLUT[] = { 14, 15, 15, 16,
+ 17, 18, 18, 19,
+ 20, 21, 22, 23,
+ 24, 26, 27, 28,
+ 29, 31
+ };
+
+ u16 fineSteps = (DRXD_FE_CTRL_MAX + 1) /
+ (maxRur + 1);
+ u16 fineSpeed = (u16) (cfg->speed -
+ ((cfg->speed /
+ fineSteps) *
+ fineSteps));
+ u16 invRurCount = (u16) (cfg->speed /
+ fineSteps);
+ u16 rurCount;
+ if (invRurCount > maxRur) {
+ rurCount = 0;
+ fineSpeed += fineSteps;
+ } else {
+ rurCount = maxRur - invRurCount;
+ }
+
+ /*
+ fastInc = default *
+ (2^(fineSpeed/fineSteps))
+ => range[default...2*default>
+ slowInc = default *
+ (2^(fineSpeed/fineSteps))
+ */
+ {
+ u16 fastIncrDec =
+ fastIncrDecLUT[fineSpeed /
+ ((fineSteps /
+ (14 + 1)) + 1)];
+ u16 slowIncrDec =
+ slowIncrDecLUT[fineSpeed /
+ (fineSteps /
+ (3 + 1))];
+
+ status = Write16(state, FE_AG_REG_EGC_RUR_CNT__A, rurCount, 0);
+ if (status < 0)
+ break;
+ status = Write16(state, FE_AG_REG_EGC_FAS_INC__A, fastIncrDec, 0);
+ if (status < 0)
+ break;
+ status = Write16(state, FE_AG_REG_EGC_FAS_DEC__A, fastIncrDec, 0);
+ if (status < 0)
+ break;
+ status = Write16(state, FE_AG_REG_EGC_SLO_INC__A, slowIncrDec, 0);
+ if (status < 0)
+ break;
+ status = Write16(state, FE_AG_REG_EGC_SLO_DEC__A, slowIncrDec, 0);
+ if (status < 0)
+ break;
+ }
+ }
+ } while (0);
+
+ } else {
+ /* No OFF mode for IF control */
+ return -1;
+ }
+ return status;
+}
+
+static int SetCfgRfAgc(struct drxd_state *state, struct SCfgAgc *cfg)
+{
+ int status = 0;
+
+ if (cfg->outputLevel > DRXD_FE_CTRL_MAX)
+ return -1;
+
+ if (cfg->ctrlMode == AGC_CTRL_USER) {
+ do {
+ u16 AgModeLop = 0;
+ u16 level = (cfg->outputLevel);
+
+ if (level == DRXD_FE_CTRL_MAX)
+ level++;
+
+ status = Write16(state, FE_AG_REG_PM2_AGC_WRI__A, level, 0x0000);
+ if (status < 0)
+ break;
+
+ /*==== Mode ====*/
+
+ /* Powerdown PD2, WRI source */
+ state->m_FeAgRegAgPwd &= ~(FE_AG_REG_AG_PWD_PWD_PD2__M);
+ state->m_FeAgRegAgPwd |=
+ FE_AG_REG_AG_PWD_PWD_PD2_DISABLE;
+ status = Write16(state, FE_AG_REG_AG_PWD__A, state->m_FeAgRegAgPwd, 0x0000);
+ if (status < 0)
+ break;
+
+ status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000);
+ if (status < 0)
+ break;
+ AgModeLop &= (~(FE_AG_REG_AG_MODE_LOP_MODE_5__M |
+ FE_AG_REG_AG_MODE_LOP_MODE_E__M));
+ AgModeLop |= (FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC |
+ FE_AG_REG_AG_MODE_LOP_MODE_E_STATIC);
+ status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000);
+ if (status < 0)
+ break;
+
+ /* enable AGC2 pin */
+ {
+ u16 FeAgRegAgAgcSio = 0;
+ status = Read16(state, FE_AG_REG_AG_AGC_SIO__A, &FeAgRegAgAgcSio, 0x0000);
+ if (status < 0)
+ break;
+ FeAgRegAgAgcSio &=
+ ~(FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M);
+ FeAgRegAgAgcSio |=
+ FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_OUTPUT;
+ status = Write16(state, FE_AG_REG_AG_AGC_SIO__A, FeAgRegAgAgcSio, 0x0000);
+ if (status < 0)
+ break;
+ }
+
+ } while (0);
+ } else if (cfg->ctrlMode == AGC_CTRL_AUTO) {
+ u16 AgModeLop = 0;
+
+ do {
+ u16 level;
+ /* Automatic control */
+ /* Powerup PD2, AGC2 as output, TGC source */
+ (state->m_FeAgRegAgPwd) &=
+ ~(FE_AG_REG_AG_PWD_PWD_PD2__M);
+ (state->m_FeAgRegAgPwd) |=
+ FE_AG_REG_AG_PWD_PWD_PD2_DISABLE;
+ status = Write16(state, FE_AG_REG_AG_PWD__A, (state->m_FeAgRegAgPwd), 0x0000);
+ if (status < 0)
+ break;
+
+ status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000);
+ if (status < 0)
+ break;
+ AgModeLop &= (~(FE_AG_REG_AG_MODE_LOP_MODE_5__M |
+ FE_AG_REG_AG_MODE_LOP_MODE_E__M));
+ AgModeLop |= (FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC |
+ FE_AG_REG_AG_MODE_LOP_MODE_E_DYNAMIC);
+ status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000);
+ if (status < 0)
+ break;
+ /* Settle level */
+ level = (((cfg->settleLevel) >> 4) &
+ FE_AG_REG_TGC_SET_LVL__M);
+ status = Write16(state, FE_AG_REG_TGC_SET_LVL__A, level, 0x0000);
+ if (status < 0)
+ break;
+
+ /* Min/max: don't care */
+
+ /* Speed: TODO */
+
+ /* enable AGC2 pin */
+ {
+ u16 FeAgRegAgAgcSio = 0;
+ status = Read16(state, FE_AG_REG_AG_AGC_SIO__A, &FeAgRegAgAgcSio, 0x0000);
+ if (status < 0)
+ break;
+ FeAgRegAgAgcSio &=
+ ~(FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M);
+ FeAgRegAgAgcSio |=
+ FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_OUTPUT;
+ status = Write16(state, FE_AG_REG_AG_AGC_SIO__A, FeAgRegAgAgcSio, 0x0000);
+ if (status < 0)
+ break;
+ }
+
+ } while (0);
+ } else {
+ u16 AgModeLop = 0;
+
+ do {
+ /* No RF AGC control */
+ /* Powerdown PD2, AGC2 as output, WRI source */
+ (state->m_FeAgRegAgPwd) &=
+ ~(FE_AG_REG_AG_PWD_PWD_PD2__M);
+ (state->m_FeAgRegAgPwd) |=
+ FE_AG_REG_AG_PWD_PWD_PD2_ENABLE;
+ status = Write16(state, FE_AG_REG_AG_PWD__A, (state->m_FeAgRegAgPwd), 0x0000);
+ if (status < 0)
+ break;
+
+ status = Read16(state, FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000);
+ if (status < 0)
+ break;
+ AgModeLop &= (~(FE_AG_REG_AG_MODE_LOP_MODE_5__M |
+ FE_AG_REG_AG_MODE_LOP_MODE_E__M));
+ AgModeLop |= (FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC |
+ FE_AG_REG_AG_MODE_LOP_MODE_E_STATIC);
+ status = Write16(state, FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000);
+ if (status < 0)
+ break;
+
+ /* set FeAgRegAgAgcSio AGC2 (RF) as input */
+ {
+ u16 FeAgRegAgAgcSio = 0;
+ status = Read16(state, FE_AG_REG_AG_AGC_SIO__A, &FeAgRegAgAgcSio, 0x0000);
+ if (status < 0)
+ break;
+ FeAgRegAgAgcSio &=
+ ~(FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M);
+ FeAgRegAgAgcSio |=
+ FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_INPUT;
+ status = Write16(state, FE_AG_REG_AG_AGC_SIO__A, FeAgRegAgAgcSio, 0x0000);
+ if (status < 0)
+ break;
+ }
+ } while (0);
+ }
+ return status;
+}
+
+static int ReadIFAgc(struct drxd_state *state, u32 * pValue)
+{
+ int status = 0;
+
+ *pValue = 0;
+ if (state->if_agc_cfg.ctrlMode != AGC_CTRL_OFF) {
+ u16 Value;
+ status = Read16(state, FE_AG_REG_GC1_AGC_DAT__A, &Value, 0);
+ Value &= FE_AG_REG_GC1_AGC_DAT__M;
+ if (status >= 0) {
+ /* 3.3V
+ |
+ R1
+ |
+ Vin - R3 - * -- Vout
+ |
+ R2
+ |
+ GND
+ */
+ u32 R1 = state->if_agc_cfg.R1;
+ u32 R2 = state->if_agc_cfg.R2;
+ u32 R3 = state->if_agc_cfg.R3;
+
+ u32 Vmax = (3300 * R2) / (R1 + R2);
+ u32 Rpar = (R2 * R3) / (R3 + R2);
+ u32 Vmin = (3300 * Rpar) / (R1 + Rpar);
+ u32 Vout = Vmin + ((Vmax - Vmin) * Value) / 1024;
+
+ *pValue = Vout;
+ }
+ }
+ return status;
+}
+
+static int load_firmware(struct drxd_state *state, const char *fw_name)
+{
+ const struct firmware *fw;
+
+ if (request_firmware(&fw, fw_name, state->dev) < 0) {
+ printk(KERN_ERR "drxd: firmware load failure [%s]\n", fw_name);
+ return -EIO;
+ }
+
+ state->microcode = kzalloc(fw->size, GFP_KERNEL);
+ if (state->microcode == NULL) {
+ printk(KERN_ERR "drxd: firmware load failure: nomemory\n");
+ return -ENOMEM;
+ }
+
+ memcpy(state->microcode, fw->data, fw->size);
+ state->microcode_length = fw->size;
+ return 0;
+}
+
+static int DownloadMicrocode(struct drxd_state *state,
+ const u8 *pMCImage, u32 Length)
+{
+ u8 *pSrc;
+ u16 Flags;
+ u32 Address;
+ u16 nBlocks;
+ u16 BlockSize;
+ u16 BlockCRC;
+ u32 offset = 0;
+ int i, status = 0;
+
+ pSrc = (u8 *) pMCImage;
+ Flags = (pSrc[0] << 8) | pSrc[1];
+ pSrc += sizeof(u16);
+ offset += sizeof(u16);
+ nBlocks = (pSrc[0] << 8) | pSrc[1];
+ pSrc += sizeof(u16);
+ offset += sizeof(u16);
+
+ for (i = 0; i < nBlocks; i++) {
+ Address = (pSrc[0] << 24) | (pSrc[1] << 16) |
+ (pSrc[2] << 8) | pSrc[3];
+ pSrc += sizeof(u32);
+ offset += sizeof(u32);
+
+ BlockSize = ((pSrc[0] << 8) | pSrc[1]) * sizeof(u16);
+ pSrc += sizeof(u16);
+ offset += sizeof(u16);
+
+ Flags = (pSrc[0] << 8) | pSrc[1];
+ pSrc += sizeof(u16);
+ offset += sizeof(u16);
+
+ BlockCRC = (pSrc[0] << 8) | pSrc[1];
+ pSrc += sizeof(u16);
+ offset += sizeof(u16);
+
+ status = WriteBlock(state, Address, BlockSize,
+ pSrc, DRX_I2C_CLEARCRC);
+ if (status < 0)
+ break;
+ pSrc += BlockSize;
+ offset += BlockSize;
+ }
+
+ return status;
+}
+
+static int HI_Command(struct drxd_state *state, u16 cmd, u16 * pResult)
+{
+ u32 nrRetries = 0;
+ u16 waitCmd;
+ int status;
+
+ status = Write16(state, HI_RA_RAM_SRV_CMD__A, cmd, 0);
+ if (status < 0)
+ return status;
+
+ do {
+ nrRetries += 1;
+ if (nrRetries > DRXD_MAX_RETRIES) {
+ status = -1;
+ break;
+ };
+ status = Read16(state, HI_RA_RAM_SRV_CMD__A, &waitCmd, 0);
+ } while (waitCmd != 0);
+
+ if (status >= 0)
+ status = Read16(state, HI_RA_RAM_SRV_RES__A, pResult, 0);
+ return status;
+}
+
+static int HI_CfgCommand(struct drxd_state *state)
+{
+ int status = 0;
+
+ mutex_lock(&state->mutex);
+ Write16(state, HI_RA_RAM_SRV_CFG_KEY__A, HI_RA_RAM_SRV_RST_KEY_ACT, 0);
+ Write16(state, HI_RA_RAM_SRV_CFG_DIV__A, state->hi_cfg_timing_div, 0);
+ Write16(state, HI_RA_RAM_SRV_CFG_BDL__A, state->hi_cfg_bridge_delay, 0);
+ Write16(state, HI_RA_RAM_SRV_CFG_WUP__A, state->hi_cfg_wakeup_key, 0);
+ Write16(state, HI_RA_RAM_SRV_CFG_ACT__A, state->hi_cfg_ctrl, 0);
+
+ Write16(state, HI_RA_RAM_SRV_CFG_KEY__A, HI_RA_RAM_SRV_RST_KEY_ACT, 0);
+
+ if ((state->hi_cfg_ctrl & HI_RA_RAM_SRV_CFG_ACT_PWD_EXE) ==
+ HI_RA_RAM_SRV_CFG_ACT_PWD_EXE)
+ status = Write16(state, HI_RA_RAM_SRV_CMD__A,
+ HI_RA_RAM_SRV_CMD_CONFIG, 0);
+ else
+ status = HI_Command(state, HI_RA_RAM_SRV_CMD_CONFIG, 0);
+ mutex_unlock(&state->mutex);
+ return status;
+}
+
+static int InitHI(struct drxd_state *state)
+{
+ state->hi_cfg_wakeup_key = (state->chip_adr);
+ /* port/bridge/power down ctrl */
+ state->hi_cfg_ctrl = HI_RA_RAM_SRV_CFG_ACT_SLV0_ON;
+ return HI_CfgCommand(state);
+}
+
+static int HI_ResetCommand(struct drxd_state *state)
+{
+ int status;
+
+ mutex_lock(&state->mutex);
+ status = Write16(state, HI_RA_RAM_SRV_RST_KEY__A,
+ HI_RA_RAM_SRV_RST_KEY_ACT, 0);
+ if (status == 0)
+ status = HI_Command(state, HI_RA_RAM_SRV_CMD_RESET, 0);
+ mutex_unlock(&state->mutex);
+ msleep(1);
+ return status;
+}
+
+static int DRX_ConfigureI2CBridge(struct drxd_state *state, int bEnableBridge)
+{
+ state->hi_cfg_ctrl &= (~HI_RA_RAM_SRV_CFG_ACT_BRD__M);
+ if (bEnableBridge)
+ state->hi_cfg_ctrl |= HI_RA_RAM_SRV_CFG_ACT_BRD_ON;
+ else
+ state->hi_cfg_ctrl |= HI_RA_RAM_SRV_CFG_ACT_BRD_OFF;
+
+ return HI_CfgCommand(state);
+}
+
+#define HI_TR_WRITE 0x9
+#define HI_TR_READ 0xA
+#define HI_TR_READ_WRITE 0xB
+#define HI_TR_BROADCAST 0x4
+
+#if 0
+static int AtomicReadBlock(struct drxd_state *state,
+ u32 Addr, u16 DataSize, u8 *pData, u8 Flags)
+{
+ int status;
+ int i = 0;
+
+ /* Parameter check */
+ if ((!pData) || ((DataSize & 1) != 0))
+ return -1;
+
+ mutex_lock(&state->mutex);
+
+ do {
+ /* Instruct HI to read n bytes */
+ /* TODO use proper names forthese egisters */
+ status = Write16(state, HI_RA_RAM_SRV_CFG_KEY__A, (HI_TR_FUNC_ADDR & 0xFFFF), 0);
+ if (status < 0)
+ break;
+ status = Write16(state, HI_RA_RAM_SRV_CFG_DIV__A, (u16) (Addr >> 16), 0);
+ if (status < 0)
+ break;
+ status = Write16(state, HI_RA_RAM_SRV_CFG_BDL__A, (u16) (Addr & 0xFFFF), 0);
+ if (status < 0)
+ break;
+ status = Write16(state, HI_RA_RAM_SRV_CFG_WUP__A, (u16) ((DataSize / 2) - 1), 0);
+ if (status < 0)
+ break;
+ status = Write16(state, HI_RA_RAM_SRV_CFG_ACT__A, HI_TR_READ, 0);
+ if (status < 0)
+ break;
+
+ status = HI_Command(state, HI_RA_RAM_SRV_CMD_EXECUTE, 0);
+ if (status < 0)
+ break;
+
+ } while (0);
+
+ if (status >= 0) {
+ for (i = 0; i < (DataSize / 2); i += 1) {
+ u16 word;
+
+ status = Read16(state, (HI_RA_RAM_USR_BEGIN__A + i),
+ &word, 0);
+ if (status < 0)
+ break;
+ pData[2 * i] = (u8) (word & 0xFF);
+ pData[(2 * i) + 1] = (u8) (word >> 8);
+ }
+ }
+ mutex_unlock(&state->mutex);
+ return status;
+}
+
+static int AtomicReadReg32(struct drxd_state *state,
+ u32 Addr, u32 *pData, u8 Flags)
+{
+ u8 buf[sizeof(u32)];
+ int status;
+
+ if (!pData)
+ return -1;
+ status = AtomicReadBlock(state, Addr, sizeof(u32), buf, Flags);
+ *pData = (((u32) buf[0]) << 0) +
+ (((u32) buf[1]) << 8) +
+ (((u32) buf[2]) << 16) + (((u32) buf[3]) << 24);
+ return status;
+}
+#endif
+
+static int StopAllProcessors(struct drxd_state *state)
+{
+ return Write16(state, HI_COMM_EXEC__A,
+ SC_COMM_EXEC_CTL_STOP, DRX_I2C_BROADCAST);
+}
+
+static int EnableAndResetMB(struct drxd_state *state)
+{
+ if (state->type_A) {
+ /* disable? monitor bus observe @ EC_OC */
+ Write16(state, EC_OC_REG_OC_MON_SIO__A, 0x0000, 0x0000);
+ }
+
+ /* do inverse broadcast, followed by explicit write to HI */
+ Write16(state, HI_COMM_MB__A, 0x0000, DRX_I2C_BROADCAST);
+ Write16(state, HI_COMM_MB__A, 0x0000, 0x0000);
+ return 0;
+}
+
+static int InitCC(struct drxd_state *state)
+{
+ if (state->osc_clock_freq == 0 ||
+ state->osc_clock_freq > 20000 ||
+ (state->osc_clock_freq % 4000) != 0) {
+ printk(KERN_ERR "invalid osc frequency %d\n", state->osc_clock_freq);
+ return -1;
+ }
+
+ Write16(state, CC_REG_OSC_MODE__A, CC_REG_OSC_MODE_M20, 0);
+ Write16(state, CC_REG_PLL_MODE__A, CC_REG_PLL_MODE_BYPASS_PLL |
+ CC_REG_PLL_MODE_PUMP_CUR_12, 0);
+ Write16(state, CC_REG_REF_DIVIDE__A, state->osc_clock_freq / 4000, 0);
+ Write16(state, CC_REG_PWD_MODE__A, CC_REG_PWD_MODE_DOWN_PLL, 0);
+ Write16(state, CC_REG_UPDATE__A, CC_REG_UPDATE_KEY, 0);
+
+ return 0;
+}
+
+static int ResetECOD(struct drxd_state *state)
+{
+ int status = 0;
+
+ if (state->type_A)
+ status = Write16(state, EC_OD_REG_SYNC__A, 0x0664, 0);
+ else
+ status = Write16(state, B_EC_OD_REG_SYNC__A, 0x0664, 0);
+
+ if (!(status < 0))
+ status = WriteTable(state, state->m_ResetECRAM);
+ if (!(status < 0))
+ status = Write16(state, EC_OD_REG_COMM_EXEC__A, 0x0001, 0);
+ return status;
+}
+
+/* Configure PGA switch */
+
+static int SetCfgPga(struct drxd_state *state, int pgaSwitch)
+{
+ int status;
+ u16 AgModeLop = 0;
+ u16 AgModeHip = 0;
+ do {
+ if (pgaSwitch) {
+ /* PGA on */
+ /* fine gain */
+ status = Read16(state, B_FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000);
+ if (status < 0)
+ break;
+ AgModeLop &= (~(B_FE_AG_REG_AG_MODE_LOP_MODE_C__M));
+ AgModeLop |= B_FE_AG_REG_AG_MODE_LOP_MODE_C_DYNAMIC;
+ status = Write16(state, B_FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000);
+ if (status < 0)
+ break;
+
+ /* coarse gain */
+ status = Read16(state, B_FE_AG_REG_AG_MODE_HIP__A, &AgModeHip, 0x0000);
+ if (status < 0)
+ break;
+ AgModeHip &= (~(B_FE_AG_REG_AG_MODE_HIP_MODE_J__M));
+ AgModeHip |= B_FE_AG_REG_AG_MODE_HIP_MODE_J_DYNAMIC;
+ status = Write16(state, B_FE_AG_REG_AG_MODE_HIP__A, AgModeHip, 0x0000);
+ if (status < 0)
+ break;
+
+ /* enable fine and coarse gain, enable AAF,
+ no ext resistor */
+ status = Write16(state, B_FE_AG_REG_AG_PGA_MODE__A, B_FE_AG_REG_AG_PGA_MODE_PFY_PCY_AFY_REN, 0x0000);
+ if (status < 0)
+ break;
+ } else {
+ /* PGA off, bypass */
+
+ /* fine gain */
+ status = Read16(state, B_FE_AG_REG_AG_MODE_LOP__A, &AgModeLop, 0x0000);
+ if (status < 0)
+ break;
+ AgModeLop &= (~(B_FE_AG_REG_AG_MODE_LOP_MODE_C__M));
+ AgModeLop |= B_FE_AG_REG_AG_MODE_LOP_MODE_C_STATIC;
+ status = Write16(state, B_FE_AG_REG_AG_MODE_LOP__A, AgModeLop, 0x0000);
+ if (status < 0)
+ break;
+
+ /* coarse gain */
+ status = Read16(state, B_FE_AG_REG_AG_MODE_HIP__A, &AgModeHip, 0x0000);
+ if (status < 0)
+ break;
+ AgModeHip &= (~(B_FE_AG_REG_AG_MODE_HIP_MODE_J__M));
+ AgModeHip |= B_FE_AG_REG_AG_MODE_HIP_MODE_J_STATIC;
+ status = Write16(state, B_FE_AG_REG_AG_MODE_HIP__A, AgModeHip, 0x0000);
+ if (status < 0)
+ break;
+
+ /* disable fine and coarse gain, enable AAF,
+ no ext resistor */
+ status = Write16(state, B_FE_AG_REG_AG_PGA_MODE__A, B_FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN, 0x0000);
+ if (status < 0)
+ break;
+ }
+ } while (0);
+ return status;
+}
+
+static int InitFE(struct drxd_state *state)
+{
+ int status;
+
+ do {
+ status = WriteTable(state, state->m_InitFE_1);
+ if (status < 0)
+ break;
+
+ if (state->type_A) {
+ status = Write16(state, FE_AG_REG_AG_PGA_MODE__A,
+ FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN,
+ 0);
+ } else {
+ if (state->PGA)
+ status = SetCfgPga(state, 0);
+ else
+ status =
+ Write16(state, B_FE_AG_REG_AG_PGA_MODE__A,
+ B_FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN,
+ 0);
+ }
+
+ if (status < 0)
+ break;
+ status = Write16(state, FE_AG_REG_AG_AGC_SIO__A, state->m_FeAgRegAgAgcSio, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, FE_AG_REG_AG_PWD__A, state->m_FeAgRegAgPwd, 0x0000);
+ if (status < 0)
+ break;
+
+ status = WriteTable(state, state->m_InitFE_2);
+ if (status < 0)
+ break;
+
+ } while (0);
+
+ return status;
+}
+
+static int InitFT(struct drxd_state *state)
+{
+ /*
+ norm OFFSET, MB says =2 voor 8K en =3 voor 2K waarschijnlijk
+ SC stuff
+ */
+ return Write16(state, FT_REG_COMM_EXEC__A, 0x0001, 0x0000);
+}
+
+static int SC_WaitForReady(struct drxd_state *state)
+{
+ u16 curCmd;
+ int i;
+
+ for (i = 0; i < DRXD_MAX_RETRIES; i += 1) {
+ int status = Read16(state, SC_RA_RAM_CMD__A, &curCmd, 0);
+ if (status == 0 || curCmd == 0)
+ return status;
+ }
+ return -1;
+}
+
+static int SC_SendCommand(struct drxd_state *state, u16 cmd)
+{
+ int status = 0;
+ u16 errCode;
+
+ Write16(state, SC_RA_RAM_CMD__A, cmd, 0);
+ SC_WaitForReady(state);
+
+ Read16(state, SC_RA_RAM_CMD_ADDR__A, &errCode, 0);
+
+ if (errCode == 0xFFFF) {
+ printk(KERN_ERR "Command Error\n");
+ status = -1;
+ }
+
+ return status;
+}
+
+static int SC_ProcStartCommand(struct drxd_state *state,
+ u16 subCmd, u16 param0, u16 param1)
+{
+ int status = 0;
+ u16 scExec;
+
+ mutex_lock(&state->mutex);
+ do {
+ Read16(state, SC_COMM_EXEC__A, &scExec, 0);
+ if (scExec != 1) {
+ status = -1;
+ break;
+ }
+ SC_WaitForReady(state);
+ Write16(state, SC_RA_RAM_CMD_ADDR__A, subCmd, 0);
+ Write16(state, SC_RA_RAM_PARAM1__A, param1, 0);
+ Write16(state, SC_RA_RAM_PARAM0__A, param0, 0);
+
+ SC_SendCommand(state, SC_RA_RAM_CMD_PROC_START);
+ } while (0);
+ mutex_unlock(&state->mutex);
+ return status;
+}
+
+static int SC_SetPrefParamCommand(struct drxd_state *state,
+ u16 subCmd, u16 param0, u16 param1)
+{
+ int status;
+
+ mutex_lock(&state->mutex);
+ do {
+ status = SC_WaitForReady(state);
+ if (status < 0)
+ break;
+ status = Write16(state, SC_RA_RAM_CMD_ADDR__A, subCmd, 0);
+ if (status < 0)
+ break;
+ status = Write16(state, SC_RA_RAM_PARAM1__A, param1, 0);
+ if (status < 0)
+ break;
+ status = Write16(state, SC_RA_RAM_PARAM0__A, param0, 0);
+ if (status < 0)
+ break;
+
+ status = SC_SendCommand(state, SC_RA_RAM_CMD_SET_PREF_PARAM);
+ if (status < 0)
+ break;
+ } while (0);
+ mutex_unlock(&state->mutex);
+ return status;
+}
+
+#if 0
+static int SC_GetOpParamCommand(struct drxd_state *state, u16 * result)
+{
+ int status = 0;
+
+ mutex_lock(&state->mutex);
+ do {
+ status = SC_WaitForReady(state);
+ if (status < 0)
+ break;
+ status = SC_SendCommand(state, SC_RA_RAM_CMD_GET_OP_PARAM);
+ if (status < 0)
+ break;
+ status = Read16(state, SC_RA_RAM_PARAM0__A, result, 0);
+ if (status < 0)
+ break;
+ } while (0);
+ mutex_unlock(&state->mutex);
+ return status;
+}
+#endif
+
+static int ConfigureMPEGOutput(struct drxd_state *state, int bEnableOutput)
+{
+ int status;
+
+ do {
+ u16 EcOcRegIprInvMpg = 0;
+ u16 EcOcRegOcModeLop = 0;
+ u16 EcOcRegOcModeHip = 0;
+ u16 EcOcRegOcMpgSio = 0;
+
+ /*CHK_ERROR(Read16(state, EC_OC_REG_OC_MODE_LOP__A, &EcOcRegOcModeLop, 0)); */
+
+ if (state->operation_mode == OM_DVBT_Diversity_Front) {
+ if (bEnableOutput) {
+ EcOcRegOcModeHip |=
+ B_EC_OC_REG_OC_MODE_HIP_MPG_BUS_SRC_MONITOR;
+ } else
+ EcOcRegOcMpgSio |= EC_OC_REG_OC_MPG_SIO__M;
+ EcOcRegOcModeLop |=
+ EC_OC_REG_OC_MODE_LOP_PAR_ENA_DISABLE;
+ } else {
+ EcOcRegOcModeLop = state->m_EcOcRegOcModeLop;
+
+ if (bEnableOutput)
+ EcOcRegOcMpgSio &= (~(EC_OC_REG_OC_MPG_SIO__M));
+ else
+ EcOcRegOcMpgSio |= EC_OC_REG_OC_MPG_SIO__M;
+
+ /* Don't Insert RS Byte */
+ if (state->insert_rs_byte) {
+ EcOcRegOcModeLop &=
+ (~(EC_OC_REG_OC_MODE_LOP_PAR_ENA__M));
+ EcOcRegOcModeHip &=
+ (~EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL__M);
+ EcOcRegOcModeHip |=
+ EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_ENABLE;
+ } else {
+ EcOcRegOcModeLop |=
+ EC_OC_REG_OC_MODE_LOP_PAR_ENA_DISABLE;
+ EcOcRegOcModeHip &=
+ (~EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL__M);
+ EcOcRegOcModeHip |=
+ EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_DISABLE;
+ }
+
+ /* Mode = Parallel */
+ if (state->enable_parallel)
+ EcOcRegOcModeLop &=
+ (~(EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE__M));
+ else
+ EcOcRegOcModeLop |=
+ EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE_SERIAL;
+ }
+ /* Invert Data */
+ /* EcOcRegIprInvMpg |= 0x00FF; */
+ EcOcRegIprInvMpg &= (~(0x00FF));
+
+ /* Invert Error ( we don't use the pin ) */
+ /* EcOcRegIprInvMpg |= 0x0100; */
+ EcOcRegIprInvMpg &= (~(0x0100));
+
+ /* Invert Start ( we don't use the pin ) */
+ /* EcOcRegIprInvMpg |= 0x0200; */
+ EcOcRegIprInvMpg &= (~(0x0200));
+
+ /* Invert Valid ( we don't use the pin ) */
+ /* EcOcRegIprInvMpg |= 0x0400; */
+ EcOcRegIprInvMpg &= (~(0x0400));
+
+ /* Invert Clock */
+ /* EcOcRegIprInvMpg |= 0x0800; */
+ EcOcRegIprInvMpg &= (~(0x0800));
+
+ /* EcOcRegOcModeLop =0x05; */
+ status = Write16(state, EC_OC_REG_IPR_INV_MPG__A, EcOcRegIprInvMpg, 0);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_OC_REG_OC_MODE_LOP__A, EcOcRegOcModeLop, 0);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_OC_REG_OC_MODE_HIP__A, EcOcRegOcModeHip, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_OC_REG_OC_MPG_SIO__A, EcOcRegOcMpgSio, 0);
+ if (status < 0)
+ break;
+ } while (0);
+ return status;
+}
+
+static int SetDeviceTypeId(struct drxd_state *state)
+{
+ int status = 0;
+ u16 deviceId = 0;
+
+ do {
+ status = Read16(state, CC_REG_JTAGID_L__A, &deviceId, 0);
+ if (status < 0)
+ break;
+ /* TODO: why twice? */
+ status = Read16(state, CC_REG_JTAGID_L__A, &deviceId, 0);
+ if (status < 0)
+ break;
+ printk(KERN_INFO "drxd: deviceId = %04x\n", deviceId);
+
+ state->type_A = 0;
+ state->PGA = 0;
+ state->diversity = 0;
+ if (deviceId == 0) { /* on A2 only 3975 available */
+ state->type_A = 1;
+ printk(KERN_INFO "DRX3975D-A2\n");
+ } else {
+ deviceId >>= 12;
+ printk(KERN_INFO "DRX397%dD-B1\n", deviceId);
+ switch (deviceId) {
+ case 4:
+ state->diversity = 1;
+ case 3:
+ case 7:
+ state->PGA = 1;
+ break;
+ case 6:
+ state->diversity = 1;
+ case 5:
+ case 8:
+ break;
+ default:
+ status = -1;
+ break;
+ }
+ }
+ } while (0);
+
+ if (status < 0)
+ return status;
+
+ /* Init Table selection */
+ state->m_InitAtomicRead = DRXD_InitAtomicRead;
+ state->m_InitSC = DRXD_InitSC;
+ state->m_ResetECRAM = DRXD_ResetECRAM;
+ if (state->type_A) {
+ state->m_ResetCEFR = DRXD_ResetCEFR;
+ state->m_InitFE_1 = DRXD_InitFEA2_1;
+ state->m_InitFE_2 = DRXD_InitFEA2_2;
+ state->m_InitCP = DRXD_InitCPA2;
+ state->m_InitCE = DRXD_InitCEA2;
+ state->m_InitEQ = DRXD_InitEQA2;
+ state->m_InitEC = DRXD_InitECA2;
+ if (load_firmware(state, DRX_FW_FILENAME_A2))
+ return -EIO;
+ } else {
+ state->m_ResetCEFR = NULL;
+ state->m_InitFE_1 = DRXD_InitFEB1_1;
+ state->m_InitFE_2 = DRXD_InitFEB1_2;
+ state->m_InitCP = DRXD_InitCPB1;
+ state->m_InitCE = DRXD_InitCEB1;
+ state->m_InitEQ = DRXD_InitEQB1;
+ state->m_InitEC = DRXD_InitECB1;
+ if (load_firmware(state, DRX_FW_FILENAME_B1))
+ return -EIO;
+ }
+ if (state->diversity) {
+ state->m_InitDiversityFront = DRXD_InitDiversityFront;
+ state->m_InitDiversityEnd = DRXD_InitDiversityEnd;
+ state->m_DisableDiversity = DRXD_DisableDiversity;
+ state->m_StartDiversityFront = DRXD_StartDiversityFront;
+ state->m_StartDiversityEnd = DRXD_StartDiversityEnd;
+ state->m_DiversityDelay8MHZ = DRXD_DiversityDelay8MHZ;
+ state->m_DiversityDelay6MHZ = DRXD_DiversityDelay6MHZ;
+ } else {
+ state->m_InitDiversityFront = NULL;
+ state->m_InitDiversityEnd = NULL;
+ state->m_DisableDiversity = NULL;
+ state->m_StartDiversityFront = NULL;
+ state->m_StartDiversityEnd = NULL;
+ state->m_DiversityDelay8MHZ = NULL;
+ state->m_DiversityDelay6MHZ = NULL;
+ }
+
+ return status;
+}
+
+static int CorrectSysClockDeviation(struct drxd_state *state)
+{
+ int status;
+ s32 incr = 0;
+ s32 nomincr = 0;
+ u32 bandwidth = 0;
+ u32 sysClockInHz = 0;
+ u32 sysClockFreq = 0; /* in kHz */
+ s16 oscClockDeviation;
+ s16 Diff;
+
+ do {
+ /* Retrieve bandwidth and incr, sanity check */
+
+ /* These accesses should be AtomicReadReg32, but that
+ causes trouble (at least for diversity */
+ status = Read32(state, LC_RA_RAM_IFINCR_NOM_L__A, ((u32 *) &nomincr), 0);
+ if (status < 0)
+ break;
+ status = Read32(state, FE_IF_REG_INCR0__A, (u32 *) &incr, 0);
+ if (status < 0)
+ break;
+
+ if (state->type_A) {
+ if ((nomincr - incr < -500) || (nomincr - incr > 500))
+ break;
+ } else {
+ if ((nomincr - incr < -2000) || (nomincr - incr > 2000))
+ break;
+ }
+
+ switch (state->param.u.ofdm.bandwidth) {
+ case BANDWIDTH_8_MHZ:
+ bandwidth = DRXD_BANDWIDTH_8MHZ_IN_HZ;
+ break;
+ case BANDWIDTH_7_MHZ:
+ bandwidth = DRXD_BANDWIDTH_7MHZ_IN_HZ;
+ break;
+ case BANDWIDTH_6_MHZ:
+ bandwidth = DRXD_BANDWIDTH_6MHZ_IN_HZ;
+ break;
+ default:
+ return -1;
+ break;
+ }
+
+ /* Compute new sysclock value
+ sysClockFreq = (((incr + 2^23)*bandwidth)/2^21)/1000 */
+ incr += (1 << 23);
+ sysClockInHz = MulDiv32(incr, bandwidth, 1 << 21);
+ sysClockFreq = (u32) (sysClockInHz / 1000);
+ /* rounding */
+ if ((sysClockInHz % 1000) > 500)
+ sysClockFreq++;
+
+ /* Compute clock deviation in ppm */
+ oscClockDeviation = (u16) ((((s32) (sysClockFreq) -
+ (s32)
+ (state->expected_sys_clock_freq)) *
+ 1000000L) /
+ (s32)
+ (state->expected_sys_clock_freq));
+
+ Diff = oscClockDeviation - state->osc_clock_deviation;
+ /*printk(KERN_INFO "sysclockdiff=%d\n", Diff); */
+ if (Diff >= -200 && Diff <= 200) {
+ state->sys_clock_freq = (u16) sysClockFreq;
+ if (oscClockDeviation != state->osc_clock_deviation) {
+ if (state->config.osc_deviation) {
+ state->config.osc_deviation(state->priv,
+ oscClockDeviation,
+ 1);
+ state->osc_clock_deviation =
+ oscClockDeviation;
+ }
+ }
+ /* switch OFF SRMM scan in SC */
+ status = Write16(state, SC_RA_RAM_SAMPLE_RATE_COUNT__A, DRXD_OSCDEV_DONT_SCAN, 0);
+ if (status < 0)
+ break;
+ /* overrule FE_IF internal value for
+ proper re-locking */
+ status = Write16(state, SC_RA_RAM_IF_SAVE__AX, state->current_fe_if_incr, 0);
+ if (status < 0)
+ break;
+ state->cscd_state = CSCD_SAVED;
+ }
+ } while (0);
+
+ return status;
+}
+
+static int DRX_Stop(struct drxd_state *state)
+{
+ int status;
+
+ if (state->drxd_state != DRXD_STARTED)
+ return 0;
+
+ do {
+ if (state->cscd_state != CSCD_SAVED) {
+ u32 lock;
+ status = DRX_GetLockStatus(state, &lock);
+ if (status < 0)
+ break;
+ }
+
+ status = StopOC(state);
+ if (status < 0)
+ break;
+
+ state->drxd_state = DRXD_STOPPED;
+
+ status = ConfigureMPEGOutput(state, 0);
+ if (status < 0)
+ break;
+
+ if (state->type_A) {
+ /* Stop relevant processors off the device */
+ status = Write16(state, EC_OD_REG_COMM_EXEC__A, 0x0000, 0x0000);
+ if (status < 0)
+ break;
+
+ status = Write16(state, SC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+ if (status < 0)
+ break;
+ status = Write16(state, LC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+ if (status < 0)
+ break;
+ } else {
+ /* Stop all processors except HI & CC & FE */
+ status = Write16(state, B_SC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+ if (status < 0)
+ break;
+ status = Write16(state, B_LC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+ if (status < 0)
+ break;
+ status = Write16(state, B_FT_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+ if (status < 0)
+ break;
+ status = Write16(state, B_CP_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+ if (status < 0)
+ break;
+ status = Write16(state, B_CE_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+ if (status < 0)
+ break;
+ status = Write16(state, B_EQ_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_OD_REG_COMM_EXEC__A, 0x0000, 0);
+ if (status < 0)
+ break;
+ }
+
+ } while (0);
+ return status;
+}
+
+int SetOperationMode(struct drxd_state *state, int oMode)
+{
+ int status;
+
+ do {
+ if (state->drxd_state != DRXD_STOPPED) {
+ status = -1;
+ break;
+ }
+
+ if (oMode == state->operation_mode) {
+ status = 0;
+ break;
+ }
+
+ if (oMode != OM_Default && !state->diversity) {
+ status = -1;
+ break;
+ }
+
+ switch (oMode) {
+ case OM_DVBT_Diversity_Front:
+ status = WriteTable(state, state->m_InitDiversityFront);
+ break;
+ case OM_DVBT_Diversity_End:
+ status = WriteTable(state, state->m_InitDiversityEnd);
+ break;
+ case OM_Default:
+ /* We need to check how to
+ get DRXD out of diversity */
+ default:
+ status = WriteTable(state, state->m_DisableDiversity);
+ break;
+ }
+ } while (0);
+
+ if (!status)
+ state->operation_mode = oMode;
+ return status;
+}
+
+static int StartDiversity(struct drxd_state *state)
+{
+ int status = 0;
+ u16 rcControl;
+
+ do {
+ if (state->operation_mode == OM_DVBT_Diversity_Front) {
+ status = WriteTable(state, state->m_StartDiversityFront);
+ if (status < 0)
+ break;
+ } else if (state->operation_mode == OM_DVBT_Diversity_End) {
+ status = WriteTable(state, state->m_StartDiversityEnd);
+ if (status < 0)
+ break;
+ if (state->param.u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
+ status = WriteTable(state, state->m_DiversityDelay8MHZ);
+ if (status < 0)
+ break;
+ } else {
+ status = WriteTable(state, state->m_DiversityDelay6MHZ);
+ if (status < 0)
+ break;
+ }
+
+ status = Read16(state, B_EQ_REG_RC_SEL_CAR__A, &rcControl, 0);
+ if (status < 0)
+ break;
+ rcControl &= ~(B_EQ_REG_RC_SEL_CAR_FFTMODE__M);
+ rcControl |= B_EQ_REG_RC_SEL_CAR_DIV_ON |
+ /* combining enabled */
+ B_EQ_REG_RC_SEL_CAR_MEAS_A_CC |
+ B_EQ_REG_RC_SEL_CAR_PASS_A_CC |
+ B_EQ_REG_RC_SEL_CAR_LOCAL_A_CC;
+ status = Write16(state, B_EQ_REG_RC_SEL_CAR__A, rcControl, 0);
+ if (status < 0)
+ break;
+ }
+ } while (0);
+ return status;
+}
+
+static int SetFrequencyShift(struct drxd_state *state,
+ u32 offsetFreq, int channelMirrored)
+{
+ int negativeShift = (state->tuner_mirrors == channelMirrored);
+
+ /* Handle all mirroring
+ *
+ * Note: ADC mirroring (aliasing) is implictly handled by limiting
+ * feFsRegAddInc to 28 bits below
+ * (if the result before masking is more than 28 bits, this means
+ * that the ADC is mirroring.
+ * The masking is in fact the aliasing of the ADC)
+ *
+ */
+
+ /* Compute register value, unsigned computation */
+ state->fe_fs_add_incr = MulDiv32(state->intermediate_freq +
+ offsetFreq,
+ 1 << 28, state->sys_clock_freq);
+ /* Remove integer part */
+ state->fe_fs_add_incr &= 0x0FFFFFFFL;
+ if (negativeShift)
+ state->fe_fs_add_incr = ((1 << 28) - state->fe_fs_add_incr);
+
+ /* Save the frequency shift without tunerOffset compensation
+ for CtrlGetChannel. */
+ state->org_fe_fs_add_incr = MulDiv32(state->intermediate_freq,
+ 1 << 28, state->sys_clock_freq);
+ /* Remove integer part */
+ state->org_fe_fs_add_incr &= 0x0FFFFFFFL;
+ if (negativeShift)
+ state->org_fe_fs_add_incr = ((1L << 28) -
+ state->org_fe_fs_add_incr);
+
+ return Write32(state, FE_FS_REG_ADD_INC_LOP__A,
+ state->fe_fs_add_incr, 0);
+}
+
+static int SetCfgNoiseCalibration(struct drxd_state *state,
+ struct SNoiseCal *noiseCal)
+{
+ u16 beOptEna;
+ int status = 0;
+
+ do {
+ status = Read16(state, SC_RA_RAM_BE_OPT_ENA__A, &beOptEna, 0);
+ if (status < 0)
+ break;
+ if (noiseCal->cpOpt) {
+ beOptEna |= (1 << SC_RA_RAM_BE_OPT_ENA_CP_OPT);
+ } else {
+ beOptEna &= ~(1 << SC_RA_RAM_BE_OPT_ENA_CP_OPT);
+ status = Write16(state, CP_REG_AC_NEXP_OFFS__A, noiseCal->cpNexpOfs, 0);
+ if (status < 0)
+ break;
+ }
+ status = Write16(state, SC_RA_RAM_BE_OPT_ENA__A, beOptEna, 0);
+ if (status < 0)
+ break;
+
+ if (!state->type_A) {
+ status = Write16(state, B_SC_RA_RAM_CO_TD_CAL_2K__A, noiseCal->tdCal2k, 0);
+ if (status < 0)
+ break;
+ status = Write16(state, B_SC_RA_RAM_CO_TD_CAL_8K__A, noiseCal->tdCal8k, 0);
+ if (status < 0)
+ break;
+ }
+ } while (0);
+
+ return status;
+}
+
+static int DRX_Start(struct drxd_state *state, s32 off)
+{
+ struct dvb_ofdm_parameters *p = &state->param.u.ofdm;
+ int status;
+
+ u16 transmissionParams = 0;
+ u16 operationMode = 0;
+ u16 qpskTdTpsPwr = 0;
+ u16 qam16TdTpsPwr = 0;
+ u16 qam64TdTpsPwr = 0;
+ u32 feIfIncr = 0;
+ u32 bandwidth = 0;
+ int mirrorFreqSpect;
+
+ u16 qpskSnCeGain = 0;
+ u16 qam16SnCeGain = 0;
+ u16 qam64SnCeGain = 0;
+ u16 qpskIsGainMan = 0;
+ u16 qam16IsGainMan = 0;
+ u16 qam64IsGainMan = 0;
+ u16 qpskIsGainExp = 0;
+ u16 qam16IsGainExp = 0;
+ u16 qam64IsGainExp = 0;
+ u16 bandwidthParam = 0;
+
+ if (off < 0)
+ off = (off - 500) / 1000;
+ else
+ off = (off + 500) / 1000;
+
+ do {
+ if (state->drxd_state != DRXD_STOPPED)
+ return -1;
+ status = ResetECOD(state);
+ if (status < 0)
+ break;
+ if (state->type_A) {
+ status = InitSC(state);
+ if (status < 0)
+ break;
+ } else {
+ status = InitFT(state);
+ if (status < 0)
+ break;
+ status = InitCP(state);
+ if (status < 0)
+ break;
+ status = InitCE(state);
+ if (status < 0)
+ break;
+ status = InitEQ(state);
+ if (status < 0)
+ break;
+ status = InitSC(state);
+ if (status < 0)
+ break;
+ }
+
+ /* Restore current IF & RF AGC settings */
+
+ status = SetCfgIfAgc(state, &state->if_agc_cfg);
+ if (status < 0)
+ break;
+ status = SetCfgRfAgc(state, &state->rf_agc_cfg);
+ if (status < 0)
+ break;
+
+ mirrorFreqSpect = (state->param.inversion == INVERSION_ON);
+
+ switch (p->transmission_mode) {
+ default: /* Not set, detect it automatically */
+ operationMode |= SC_RA_RAM_OP_AUTO_MODE__M;
+ /* fall through , try first guess DRX_FFTMODE_8K */
+ case TRANSMISSION_MODE_8K:
+ transmissionParams |= SC_RA_RAM_OP_PARAM_MODE_8K;
+ if (state->type_A) {
+ status = Write16(state, EC_SB_REG_TR_MODE__A, EC_SB_REG_TR_MODE_8K, 0x0000);
+ if (status < 0)
+ break;
+ qpskSnCeGain = 99;
+ qam16SnCeGain = 83;
+ qam64SnCeGain = 67;
+ }
+ break;
+ case TRANSMISSION_MODE_2K:
+ transmissionParams |= SC_RA_RAM_OP_PARAM_MODE_2K;
+ if (state->type_A) {
+ status = Write16(state, EC_SB_REG_TR_MODE__A, EC_SB_REG_TR_MODE_2K, 0x0000);
+ if (status < 0)
+ break;
+ qpskSnCeGain = 97;
+ qam16SnCeGain = 71;
+ qam64SnCeGain = 65;
+ }
+ break;
+ }
+
+ switch (p->guard_interval) {
+ case GUARD_INTERVAL_1_4:
+ transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_4;
+ break;
+ case GUARD_INTERVAL_1_8:
+ transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_8;
+ break;
+ case GUARD_INTERVAL_1_16:
+ transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_16;
+ break;
+ case GUARD_INTERVAL_1_32:
+ transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_32;
+ break;
+ default: /* Not set, detect it automatically */
+ operationMode |= SC_RA_RAM_OP_AUTO_GUARD__M;
+ /* try first guess 1/4 */
+ transmissionParams |= SC_RA_RAM_OP_PARAM_GUARD_4;
+ break;
+ }
+
+ switch (p->hierarchy_information) {
+ case HIERARCHY_1:
+ transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_A1;
+ if (state->type_A) {
+ status = Write16(state, EQ_REG_OT_ALPHA__A, 0x0001, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_SB_REG_ALPHA__A, 0x0001, 0x0000);
+ if (status < 0)
+ break;
+
+ qpskTdTpsPwr = EQ_TD_TPS_PWR_UNKNOWN;
+ qam16TdTpsPwr = EQ_TD_TPS_PWR_QAM16_ALPHA1;
+ qam64TdTpsPwr = EQ_TD_TPS_PWR_QAM64_ALPHA1;
+
+ qpskIsGainMan =
+ SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE;
+ qam16IsGainMan =
+ SC_RA_RAM_EQ_IS_GAIN_16QAM_MAN__PRE;
+ qam64IsGainMan =
+ SC_RA_RAM_EQ_IS_GAIN_64QAM_MAN__PRE;
+
+ qpskIsGainExp =
+ SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE;
+ qam16IsGainExp =
+ SC_RA_RAM_EQ_IS_GAIN_16QAM_EXP__PRE;
+ qam64IsGainExp =
+ SC_RA_RAM_EQ_IS_GAIN_64QAM_EXP__PRE;
+ }
+ break;
+
+ case HIERARCHY_2:
+ transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_A2;
+ if (state->type_A) {
+ status = Write16(state, EQ_REG_OT_ALPHA__A, 0x0002, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_SB_REG_ALPHA__A, 0x0002, 0x0000);
+ if (status < 0)
+ break;
+
+ qpskTdTpsPwr = EQ_TD_TPS_PWR_UNKNOWN;
+ qam16TdTpsPwr = EQ_TD_TPS_PWR_QAM16_ALPHA2;
+ qam64TdTpsPwr = EQ_TD_TPS_PWR_QAM64_ALPHA2;
+
+ qpskIsGainMan =
+ SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE;
+ qam16IsGainMan =
+ SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_MAN__PRE;
+ qam64IsGainMan =
+ SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_MAN__PRE;
+
+ qpskIsGainExp =
+ SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE;
+ qam16IsGainExp =
+ SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_EXP__PRE;
+ qam64IsGainExp =
+ SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_EXP__PRE;
+ }
+ break;
+ case HIERARCHY_4:
+ transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_A4;
+ if (state->type_A) {
+ status = Write16(state, EQ_REG_OT_ALPHA__A, 0x0003, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_SB_REG_ALPHA__A, 0x0003, 0x0000);
+ if (status < 0)
+ break;
+
+ qpskTdTpsPwr = EQ_TD_TPS_PWR_UNKNOWN;
+ qam16TdTpsPwr = EQ_TD_TPS_PWR_QAM16_ALPHA4;
+ qam64TdTpsPwr = EQ_TD_TPS_PWR_QAM64_ALPHA4;
+
+ qpskIsGainMan =
+ SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE;
+ qam16IsGainMan =
+ SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_MAN__PRE;
+ qam64IsGainMan =
+ SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_MAN__PRE;
+
+ qpskIsGainExp =
+ SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE;
+ qam16IsGainExp =
+ SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_EXP__PRE;
+ qam64IsGainExp =
+ SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_EXP__PRE;
+ }
+ break;
+ case HIERARCHY_AUTO:
+ default:
+ /* Not set, detect it automatically, start with none */
+ operationMode |= SC_RA_RAM_OP_AUTO_HIER__M;
+ transmissionParams |= SC_RA_RAM_OP_PARAM_HIER_NO;
+ if (state->type_A) {
+ status = Write16(state, EQ_REG_OT_ALPHA__A, 0x0000, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_SB_REG_ALPHA__A, 0x0000, 0x0000);
+ if (status < 0)
+ break;
+
+ qpskTdTpsPwr = EQ_TD_TPS_PWR_QPSK;
+ qam16TdTpsPwr = EQ_TD_TPS_PWR_QAM16_ALPHAN;
+ qam64TdTpsPwr = EQ_TD_TPS_PWR_QAM64_ALPHAN;
+
+ qpskIsGainMan =
+ SC_RA_RAM_EQ_IS_GAIN_QPSK_MAN__PRE;
+ qam16IsGainMan =
+ SC_RA_RAM_EQ_IS_GAIN_16QAM_MAN__PRE;
+ qam64IsGainMan =
+ SC_RA_RAM_EQ_IS_GAIN_64QAM_MAN__PRE;
+
+ qpskIsGainExp =
+ SC_RA_RAM_EQ_IS_GAIN_QPSK_EXP__PRE;
+ qam16IsGainExp =
+ SC_RA_RAM_EQ_IS_GAIN_16QAM_EXP__PRE;
+ qam64IsGainExp =
+ SC_RA_RAM_EQ_IS_GAIN_64QAM_EXP__PRE;
+ }
+ break;
+ }
+ status = status;
+ if (status < 0)
+ break;
+
+ switch (p->constellation) {
+ default:
+ operationMode |= SC_RA_RAM_OP_AUTO_CONST__M;
+ /* fall through , try first guess
+ DRX_CONSTELLATION_QAM64 */
+ case QAM_64:
+ transmissionParams |= SC_RA_RAM_OP_PARAM_CONST_QAM64;
+ if (state->type_A) {
+ status = Write16(state, EQ_REG_OT_CONST__A, 0x0002, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_SB_REG_CONST__A, EC_SB_REG_CONST_64QAM, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_SB_REG_SCALE_MSB__A, 0x0020, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_SB_REG_SCALE_BIT2__A, 0x0008, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_SB_REG_SCALE_LSB__A, 0x0002, 0x0000);
+ if (status < 0)
+ break;
+
+ status = Write16(state, EQ_REG_TD_TPS_PWR_OFS__A, qam64TdTpsPwr, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EQ_REG_SN_CEGAIN__A, qam64SnCeGain, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EQ_REG_IS_GAIN_MAN__A, qam64IsGainMan, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EQ_REG_IS_GAIN_EXP__A, qam64IsGainExp, 0x0000);
+ if (status < 0)
+ break;
+ }
+ break;
+ case QPSK:
+ transmissionParams |= SC_RA_RAM_OP_PARAM_CONST_QPSK;
+ if (state->type_A) {
+ status = Write16(state, EQ_REG_OT_CONST__A, 0x0000, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_SB_REG_CONST__A, EC_SB_REG_CONST_QPSK, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_SB_REG_SCALE_MSB__A, 0x0010, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_SB_REG_SCALE_BIT2__A, 0x0000, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_SB_REG_SCALE_LSB__A, 0x0000, 0x0000);
+ if (status < 0)
+ break;
+
+ status = Write16(state, EQ_REG_TD_TPS_PWR_OFS__A, qpskTdTpsPwr, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EQ_REG_SN_CEGAIN__A, qpskSnCeGain, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EQ_REG_IS_GAIN_MAN__A, qpskIsGainMan, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EQ_REG_IS_GAIN_EXP__A, qpskIsGainExp, 0x0000);
+ if (status < 0)
+ break;
+ }
+ break;
+
+ case QAM_16:
+ transmissionParams |= SC_RA_RAM_OP_PARAM_CONST_QAM16;
+ if (state->type_A) {
+ status = Write16(state, EQ_REG_OT_CONST__A, 0x0001, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_SB_REG_CONST__A, EC_SB_REG_CONST_16QAM, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_SB_REG_SCALE_MSB__A, 0x0010, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_SB_REG_SCALE_BIT2__A, 0x0004, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EC_SB_REG_SCALE_LSB__A, 0x0000, 0x0000);
+ if (status < 0)
+ break;
+
+ status = Write16(state, EQ_REG_TD_TPS_PWR_OFS__A, qam16TdTpsPwr, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EQ_REG_SN_CEGAIN__A, qam16SnCeGain, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EQ_REG_IS_GAIN_MAN__A, qam16IsGainMan, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, EQ_REG_IS_GAIN_EXP__A, qam16IsGainExp, 0x0000);
+ if (status < 0)
+ break;
+ }
+ break;
+
+ }
+ status = status;
+ if (status < 0)
+ break;
+
+ switch (DRX_CHANNEL_HIGH) {
+ default:
+ case DRX_CHANNEL_AUTO:
+ case DRX_CHANNEL_LOW:
+ transmissionParams |= SC_RA_RAM_OP_PARAM_PRIO_LO;
+ status = Write16(state, EC_SB_REG_PRIOR__A, EC_SB_REG_PRIOR_LO, 0x0000);
+ if (status < 0)
+ break;
+ break;
+ case DRX_CHANNEL_HIGH:
+ transmissionParams |= SC_RA_RAM_OP_PARAM_PRIO_HI;
+ status = Write16(state, EC_SB_REG_PRIOR__A, EC_SB_REG_PRIOR_HI, 0x0000);
+ if (status < 0)
+ break;
+ break;
+
+ }
+
+ switch (p->code_rate_HP) {
+ case FEC_1_2:
+ transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_1_2;
+ if (state->type_A) {
+ status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C1_2, 0x0000);
+ if (status < 0)
+ break;
+ }
+ break;
+ default:
+ operationMode |= SC_RA_RAM_OP_AUTO_RATE__M;
+ case FEC_2_3:
+ transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_2_3;
+ if (state->type_A) {
+ status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C2_3, 0x0000);
+ if (status < 0)
+ break;
+ }
+ break;
+ case FEC_3_4:
+ transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_3_4;
+ if (state->type_A) {
+ status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C3_4, 0x0000);
+ if (status < 0)
+ break;
+ }
+ break;
+ case FEC_5_6:
+ transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_5_6;
+ if (state->type_A) {
+ status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C5_6, 0x0000);
+ if (status < 0)
+ break;
+ }
+ break;
+ case FEC_7_8:
+ transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_7_8;
+ if (state->type_A) {
+ status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C7_8, 0x0000);
+ if (status < 0)
+ break;
+ }
+ break;
+ }
+ status = status;
+ if (status < 0)
+ break;
+
+ /* First determine real bandwidth (Hz) */
+ /* Also set delay for impulse noise cruncher (only A2) */
+ /* Also set parameters for EC_OC fix, note
+ EC_OC_REG_TMD_HIL_MAR is changed
+ by SC for fix for some 8K,1/8 guard but is restored by
+ InitEC and ResetEC
+ functions */
+ switch (p->bandwidth) {
+ case BANDWIDTH_AUTO:
+ case BANDWIDTH_8_MHZ:
+ /* (64/7)*(8/8)*1000000 */
+ bandwidth = DRXD_BANDWIDTH_8MHZ_IN_HZ;
+
+ bandwidthParam = 0;
+ status = Write16(state,
+ FE_AG_REG_IND_DEL__A, 50, 0x0000);
+ break;
+ case BANDWIDTH_7_MHZ:
+ /* (64/7)*(7/8)*1000000 */
+ bandwidth = DRXD_BANDWIDTH_7MHZ_IN_HZ;
+ bandwidthParam = 0x4807; /*binary:0100 1000 0000 0111 */
+ status = Write16(state,
+ FE_AG_REG_IND_DEL__A, 59, 0x0000);
+ break;
+ case BANDWIDTH_6_MHZ:
+ /* (64/7)*(6/8)*1000000 */
+ bandwidth = DRXD_BANDWIDTH_6MHZ_IN_HZ;
+ bandwidthParam = 0x0F07; /*binary: 0000 1111 0000 0111 */
+ status = Write16(state,
+ FE_AG_REG_IND_DEL__A, 71, 0x0000);
+ break;
+ default:
+ status = -EINVAL;
+ }
+ if (status < 0)
+ break;
+
+ status = Write16(state, SC_RA_RAM_BAND__A, bandwidthParam, 0x0000);
+ if (status < 0)
+ break;
+
+ {
+ u16 sc_config;
+ status = Read16(state, SC_RA_RAM_CONFIG__A, &sc_config, 0);
+ if (status < 0)
+ break;
+
+ /* enable SLAVE mode in 2k 1/32 to
+ prevent timing change glitches */
+ if ((p->transmission_mode == TRANSMISSION_MODE_2K) &&
+ (p->guard_interval == GUARD_INTERVAL_1_32)) {
+ /* enable slave */
+ sc_config |= SC_RA_RAM_CONFIG_SLAVE__M;
+ } else {
+ /* disable slave */
+ sc_config &= ~SC_RA_RAM_CONFIG_SLAVE__M;
+ }
+ status = Write16(state, SC_RA_RAM_CONFIG__A, sc_config, 0);
+ if (status < 0)
+ break;
+ }
+
+ status = SetCfgNoiseCalibration(state, &state->noise_cal);
+ if (status < 0)
+ break;
+
+ if (state->cscd_state == CSCD_INIT) {
+ /* switch on SRMM scan in SC */
+ status = Write16(state, SC_RA_RAM_SAMPLE_RATE_COUNT__A, DRXD_OSCDEV_DO_SCAN, 0x0000);
+ if (status < 0)
+ break;
+/* CHK_ERROR(Write16(SC_RA_RAM_SAMPLE_RATE_STEP__A, DRXD_OSCDEV_STEP, 0x0000));*/
+ state->cscd_state = CSCD_SET;
+ }
+
+ /* Now compute FE_IF_REG_INCR */
+ /*((( SysFreq/BandWidth)/2)/2) -1) * 2^23) =>
+ ((SysFreq / BandWidth) * (2^21) ) - (2^23) */
+ feIfIncr = MulDiv32(state->sys_clock_freq * 1000,
+ (1ULL << 21), bandwidth) - (1 << 23);
+ status = Write16(state, FE_IF_REG_INCR0__A, (u16) (feIfIncr & FE_IF_REG_INCR0__M), 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, FE_IF_REG_INCR1__A, (u16) ((feIfIncr >> FE_IF_REG_INCR0__W) & FE_IF_REG_INCR1__M), 0x0000);
+ if (status < 0)
+ break;
+ /* Bandwidth setting done */
+
+ /* Mirror & frequency offset */
+ SetFrequencyShift(state, off, mirrorFreqSpect);
+
+ /* Start SC, write channel settings to SC */
+
+ /* Enable SC after setting all other parameters */
+ status = Write16(state, SC_COMM_STATE__A, 0, 0x0000);
+ if (status < 0)
+ break;
+ status = Write16(state, SC_COMM_EXEC__A, 1, 0x0000);
+ if (status < 0)
+ break;
+
+ /* Write SC parameter registers, operation mode */
+#if 1
+ operationMode = (SC_RA_RAM_OP_AUTO_MODE__M |
+ SC_RA_RAM_OP_AUTO_GUARD__M |
+ SC_RA_RAM_OP_AUTO_CONST__M |
+ SC_RA_RAM_OP_AUTO_HIER__M |
+ SC_RA_RAM_OP_AUTO_RATE__M);
+#endif
+ status = SC_SetPrefParamCommand(state, 0x0000, transmissionParams, operationMode);
+ if (status < 0)
+ break;
+
+ /* Start correct processes to get in lock */
+ status = SC_ProcStartCommand(state, SC_RA_RAM_PROC_LOCKTRACK, SC_RA_RAM_SW_EVENT_RUN_NMASK__M, SC_RA_RAM_LOCKTRACK_MIN);
+ if (status < 0)
+ break;
+
+ status = StartOC(state);
+ if (status < 0)
+ break;
+
+ if (state->operation_mode != OM_Default) {
+ status = StartDiversity(state);
+ if (status < 0)
+ break;
+ }
+
+ state->drxd_state = DRXD_STARTED;
+ } while (0);
+
+ return status;
+}
+
+static int CDRXD(struct drxd_state *state, u32 IntermediateFrequency)
+{
+ u32 ulRfAgcOutputLevel = 0xffffffff;
+ u32 ulRfAgcSettleLevel = 528; /* Optimum value for MT2060 */
+ u32 ulRfAgcMinLevel = 0; /* Currently unused */
+ u32 ulRfAgcMaxLevel = DRXD_FE_CTRL_MAX; /* Currently unused */
+ u32 ulRfAgcSpeed = 0; /* Currently unused */
+ u32 ulRfAgcMode = 0; /*2; Off */
+ u32 ulRfAgcR1 = 820;
+ u32 ulRfAgcR2 = 2200;
+ u32 ulRfAgcR3 = 150;
+ u32 ulIfAgcMode = 0; /* Auto */
+ u32 ulIfAgcOutputLevel = 0xffffffff;
+ u32 ulIfAgcSettleLevel = 0xffffffff;
+ u32 ulIfAgcMinLevel = 0xffffffff;
+ u32 ulIfAgcMaxLevel = 0xffffffff;
+ u32 ulIfAgcSpeed = 0xffffffff;
+ u32 ulIfAgcR1 = 820;
+ u32 ulIfAgcR2 = 2200;
+ u32 ulIfAgcR3 = 150;
+ u32 ulClock = state->config.clock;
+ u32 ulSerialMode = 0;
+ u32 ulEcOcRegOcModeLop = 4; /* Dynamic DTO source */
+ u32 ulHiI2cDelay = HI_I2C_DELAY;
+ u32 ulHiI2cBridgeDelay = HI_I2C_BRIDGE_DELAY;
+ u32 ulHiI2cPatch = 0;
+ u32 ulEnvironment = APPENV_PORTABLE;
+ u32 ulEnvironmentDiversity = APPENV_MOBILE;
+ u32 ulIFFilter = IFFILTER_SAW;
+
+ state->if_agc_cfg.ctrlMode = AGC_CTRL_AUTO;
+ state->if_agc_cfg.outputLevel = 0;
+ state->if_agc_cfg.settleLevel = 140;
+ state->if_agc_cfg.minOutputLevel = 0;
+ state->if_agc_cfg.maxOutputLevel = 1023;
+ state->if_agc_cfg.speed = 904;
+
+ if (ulIfAgcMode == 1 && ulIfAgcOutputLevel <= DRXD_FE_CTRL_MAX) {
+ state->if_agc_cfg.ctrlMode = AGC_CTRL_USER;
+ state->if_agc_cfg.outputLevel = (u16) (ulIfAgcOutputLevel);
+ }
+
+ if (ulIfAgcMode == 0 &&
+ ulIfAgcSettleLevel <= DRXD_FE_CTRL_MAX &&
+ ulIfAgcMinLevel <= DRXD_FE_CTRL_MAX &&
+ ulIfAgcMaxLevel <= DRXD_FE_CTRL_MAX &&
+ ulIfAgcSpeed <= DRXD_FE_CTRL_MAX) {
+ state->if_agc_cfg.ctrlMode = AGC_CTRL_AUTO;
+ state->if_agc_cfg.settleLevel = (u16) (ulIfAgcSettleLevel);
+ state->if_agc_cfg.minOutputLevel = (u16) (ulIfAgcMinLevel);
+ state->if_agc_cfg.maxOutputLevel = (u16) (ulIfAgcMaxLevel);
+ state->if_agc_cfg.speed = (u16) (ulIfAgcSpeed);
+ }
+
+ state->if_agc_cfg.R1 = (u16) (ulIfAgcR1);
+ state->if_agc_cfg.R2 = (u16) (ulIfAgcR2);
+ state->if_agc_cfg.R3 = (u16) (ulIfAgcR3);
+
+ state->rf_agc_cfg.R1 = (u16) (ulRfAgcR1);
+ state->rf_agc_cfg.R2 = (u16) (ulRfAgcR2);
+ state->rf_agc_cfg.R3 = (u16) (ulRfAgcR3);
+
+ state->rf_agc_cfg.ctrlMode = AGC_CTRL_AUTO;
+ /* rest of the RFAgcCfg structure currently unused */
+ if (ulRfAgcMode == 1 && ulRfAgcOutputLevel <= DRXD_FE_CTRL_MAX) {
+ state->rf_agc_cfg.ctrlMode = AGC_CTRL_USER;
+ state->rf_agc_cfg.outputLevel = (u16) (ulRfAgcOutputLevel);
+ }
+
+ if (ulRfAgcMode == 0 &&
+ ulRfAgcSettleLevel <= DRXD_FE_CTRL_MAX &&
+ ulRfAgcMinLevel <= DRXD_FE_CTRL_MAX &&
+ ulRfAgcMaxLevel <= DRXD_FE_CTRL_MAX &&
+ ulRfAgcSpeed <= DRXD_FE_CTRL_MAX) {
+ state->rf_agc_cfg.ctrlMode = AGC_CTRL_AUTO;
+ state->rf_agc_cfg.settleLevel = (u16) (ulRfAgcSettleLevel);
+ state->rf_agc_cfg.minOutputLevel = (u16) (ulRfAgcMinLevel);
+ state->rf_agc_cfg.maxOutputLevel = (u16) (ulRfAgcMaxLevel);
+ state->rf_agc_cfg.speed = (u16) (ulRfAgcSpeed);
+ }
+
+ if (ulRfAgcMode == 2)
+ state->rf_agc_cfg.ctrlMode = AGC_CTRL_OFF;
+
+ if (ulEnvironment <= 2)
+ state->app_env_default = (enum app_env)
+ (ulEnvironment);
+ if (ulEnvironmentDiversity <= 2)
+ state->app_env_diversity = (enum app_env)
+ (ulEnvironmentDiversity);
+
+ if (ulIFFilter == IFFILTER_DISCRETE) {
+ /* discrete filter */
+ state->noise_cal.cpOpt = 0;
+ state->noise_cal.cpNexpOfs = 40;
+ state->noise_cal.tdCal2k = -40;
+ state->noise_cal.tdCal8k = -24;
+ } else {
+ /* SAW filter */
+ state->noise_cal.cpOpt = 1;
+ state->noise_cal.cpNexpOfs = 0;
+ state->noise_cal.tdCal2k = -21;
+ state->noise_cal.tdCal8k = -24;
+ }
+ state->m_EcOcRegOcModeLop = (u16) (ulEcOcRegOcModeLop);
+
+ state->chip_adr = (state->config.demod_address << 1) | 1;
+ switch (ulHiI2cPatch) {
+ case 1:
+ state->m_HiI2cPatch = DRXD_HiI2cPatch_1;
+ break;
+ case 3:
+ state->m_HiI2cPatch = DRXD_HiI2cPatch_3;
+ break;
+ default:
+ state->m_HiI2cPatch = NULL;
+ }
+
+ /* modify tuner and clock attributes */
+ state->intermediate_freq = (u16) (IntermediateFrequency / 1000);
+ /* expected system clock frequency in kHz */
+ state->expected_sys_clock_freq = 48000;
+ /* real system clock frequency in kHz */
+ state->sys_clock_freq = 48000;
+ state->osc_clock_freq = (u16) ulClock;
+ state->osc_clock_deviation = 0;
+ state->cscd_state = CSCD_INIT;
+ state->drxd_state = DRXD_UNINITIALIZED;
+
+ state->PGA = 0;
+ state->type_A = 0;
+ state->tuner_mirrors = 0;
+
+ /* modify MPEG output attributes */
+ state->insert_rs_byte = state->config.insert_rs_byte;
+ state->enable_parallel = (ulSerialMode != 1);
+
+ /* Timing div, 250ns/Psys */
+ /* Timing div, = ( delay (nano seconds) * sysclk (kHz) )/ 1000 */
+
+ state->hi_cfg_timing_div = (u16) ((state->sys_clock_freq / 1000) *
+ ulHiI2cDelay) / 1000;
+ /* Bridge delay, uses oscilator clock */
+ /* Delay = ( delay (nano seconds) * oscclk (kHz) )/ 1000 */
+ state->hi_cfg_bridge_delay = (u16) ((state->osc_clock_freq / 1000) *
+ ulHiI2cBridgeDelay) / 1000;
+
+ state->m_FeAgRegAgPwd = DRXD_DEF_AG_PWD_CONSUMER;
+ /* state->m_FeAgRegAgPwd = DRXD_DEF_AG_PWD_PRO; */
+ state->m_FeAgRegAgAgcSio = DRXD_DEF_AG_AGC_SIO;
+ return 0;
+}
+
+int DRXD_init(struct drxd_state *state, const u8 * fw, u32 fw_size)
+{
+ int status = 0;
+ u32 driverVersion;
+
+ if (state->init_done)
+ return 0;
+
+ CDRXD(state, state->config.IF ? state->config.IF : 36000000);
+
+ do {
+ state->operation_mode = OM_Default;
+
+ status = SetDeviceTypeId(state);
+ if (status < 0)
+ break;
+
+ /* Apply I2c address patch to B1 */
+ if (!state->type_A && state->m_HiI2cPatch != NULL)
+ status = WriteTable(state, state->m_HiI2cPatch);
+ if (status < 0)
+ break;
+
+ if (state->type_A) {
+ /* HI firmware patch for UIO readout,
+ avoid clearing of result register */
+ status = Write16(state, 0x43012D, 0x047f, 0);
+ if (status < 0)
+ break;
+ }
+
+ status = HI_ResetCommand(state);
+ if (status < 0)
+ break;
+
+ status = StopAllProcessors(state);
+ if (status < 0)
+ break;
+ status = InitCC(state);
+ if (status < 0)
+ break;
+
+ state->osc_clock_deviation = 0;
+
+ if (state->config.osc_deviation)
+ state->osc_clock_deviation =
+ state->config.osc_deviation(state->priv, 0, 0);
+ {
+ /* Handle clock deviation */
+ s32 devB;
+ s32 devA = (s32) (state->osc_clock_deviation) *
+ (s32) (state->expected_sys_clock_freq);
+ /* deviation in kHz */
+ s32 deviation = (devA / (1000000L));
+ /* rounding, signed */
+ if (devA > 0)
+ devB = (2);
+ else
+ devB = (-2);
+ if ((devB * (devA % 1000000L) > 1000000L)) {
+ /* add +1 or -1 */
+ deviation += (devB / 2);
+ }
+
+ state->sys_clock_freq =
+ (u16) ((state->expected_sys_clock_freq) +
+ deviation);
+ }
+ status = InitHI(state);
+ if (status < 0)
+ break;
+ status = InitAtomicRead(state);
+ if (status < 0)
+ break;
+
+ status = EnableAndResetMB(state);
+ if (status < 0)
+ break;
+ if (state->type_A)
+ status = ResetCEFR(state);
+ if (status < 0)
+ break;
+
+ if (fw) {
+ status = DownloadMicrocode(state, fw, fw_size);
+ if (status < 0)
+ break;
+ } else {
+ status = DownloadMicrocode(state, state->microcode, state->microcode_length);
+ if (status < 0)
+ break;
+ }
+
+ if (state->PGA) {
+ state->m_FeAgRegAgPwd = DRXD_DEF_AG_PWD_PRO;
+ SetCfgPga(state, 0); /* PGA = 0 dB */
+ } else {
+ state->m_FeAgRegAgPwd = DRXD_DEF_AG_PWD_CONSUMER;
+ }
+
+ state->m_FeAgRegAgAgcSio = DRXD_DEF_AG_AGC_SIO;
+
+ status = InitFE(state);
+ if (status < 0)
+ break;
+ status = InitFT(state);
+ if (status < 0)
+ break;
+ status = InitCP(state);
+ if (status < 0)
+ break;
+ status = InitCE(state);
+ if (status < 0)
+ break;
+ status = InitEQ(state);
+ if (status < 0)
+ break;
+ status = InitEC(state);
+ if (status < 0)
+ break;
+ status = InitSC(state);
+ if (status < 0)
+ break;
+
+ status = SetCfgIfAgc(state, &state->if_agc_cfg);
+ if (status < 0)
+ break;
+ status = SetCfgRfAgc(state, &state->rf_agc_cfg);
+ if (status < 0)
+ break;
+
+ state->cscd_state = CSCD_INIT;
+ status = Write16(state, SC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+ if (status < 0)
+ break;
+ status = Write16(state, LC_COMM_EXEC__A, SC_COMM_EXEC_CTL_STOP, 0);
+ if (status < 0)
+ break;
+
+ driverVersion = (((VERSION_MAJOR / 10) << 4) +
+ (VERSION_MAJOR % 10)) << 24;
+ driverVersion += (((VERSION_MINOR / 10) << 4) +
+ (VERSION_MINOR % 10)) << 16;
+ driverVersion += ((VERSION_PATCH / 1000) << 12) +
+ ((VERSION_PATCH / 100) << 8) +
+ ((VERSION_PATCH / 10) << 4) + (VERSION_PATCH % 10);
+
+ status = Write32(state, SC_RA_RAM_DRIVER_VERSION__AX, driverVersion, 0);
+ if (status < 0)
+ break;
+
+ status = StopOC(state);
+ if (status < 0)
+ break;
+
+ state->drxd_state = DRXD_STOPPED;
+ state->init_done = 1;
+ status = 0;
+ } while (0);
+ return status;
+}
+
+int DRXD_status(struct drxd_state *state, u32 * pLockStatus)
+{
+ DRX_GetLockStatus(state, pLockStatus);
+
+ /*if (*pLockStatus&DRX_LOCK_MPEG) */
+ if (*pLockStatus & DRX_LOCK_FEC) {
+ ConfigureMPEGOutput(state, 1);
+ /* Get status again, in case we have MPEG lock now */
+ /*DRX_GetLockStatus(state, pLockStatus); */
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+static int drxd_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
+{
+ struct drxd_state *state = fe->demodulator_priv;
+ u32 value;
+ int res;
+
+ res = ReadIFAgc(state, &value);
+ if (res < 0)
+ *strength = 0;
+ else
+ *strength = 0xffff - (value << 4);
+ return 0;
+}
+
+static int drxd_read_status(struct dvb_frontend *fe, fe_status_t * status)
+{
+ struct drxd_state *state = fe->demodulator_priv;
+ u32 lock;
+
+ DRXD_status(state, &lock);
+ *status = 0;
+ /* No MPEG lock in V255 firmware, bug ? */
+#if 1
+ if (lock & DRX_LOCK_MPEG)
+ *status |= FE_HAS_LOCK;
+#else
+ if (lock & DRX_LOCK_FEC)
+ *status |= FE_HAS_LOCK;
+#endif
+ if (lock & DRX_LOCK_FEC)
+ *status |= FE_HAS_VITERBI | FE_HAS_SYNC;
+ if (lock & DRX_LOCK_DEMOD)
+ *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+
+ return 0;
+}
+
+static int drxd_init(struct dvb_frontend *fe)
+{
+ struct drxd_state *state = fe->demodulator_priv;
+ int err = 0;
+
+/* if (request_firmware(&state->fw, "drxd.fw", state->dev)<0) */
+ return DRXD_init(state, 0, 0);
+
+ err = DRXD_init(state, state->fw->data, state->fw->size);
+ release_firmware(state->fw);
+ return err;
+}
+
+int drxd_config_i2c(struct dvb_frontend *fe, int onoff)
+{
+ struct drxd_state *state = fe->demodulator_priv;
+
+ if (state->config.disable_i2c_gate_ctrl == 1)
+ return 0;
+
+ return DRX_ConfigureI2CBridge(state, onoff);
+}
+EXPORT_SYMBOL(drxd_config_i2c);
+
+static int drxd_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *sets)
+{
+ sets->min_delay_ms = 10000;
+ sets->max_drift = 0;
+ sets->step_size = 0;
+ return 0;
+}
+
+static int drxd_read_ber(struct dvb_frontend *fe, u32 * ber)
+{
+ *ber = 0;
+ return 0;
+}
+
+static int drxd_read_snr(struct dvb_frontend *fe, u16 * snr)
+{
+ *snr = 0;
+ return 0;
+}
+
+static int drxd_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks)
+{
+ *ucblocks = 0;
+ return 0;
+}
+
+static int drxd_sleep(struct dvb_frontend *fe)
+{
+ struct drxd_state *state = fe->demodulator_priv;
+
+ ConfigureMPEGOutput(state, 0);
+ return 0;
+}
+
+static int drxd_get_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *param)
+{
+ return 0;
+}
+
+static int drxd_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+ return drxd_config_i2c(fe, enable);
+}
+
+static int drxd_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *param)
+{
+ struct drxd_state *state = fe->demodulator_priv;
+ s32 off = 0;
+
+ state->param = *param;
+ DRX_Stop(state);
+
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, param);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
+ /* FIXME: move PLL drivers */
+ if (state->config.pll_set &&
+ state->config.pll_set(state->priv, param,
+ state->config.pll_address,
+ state->config.demoda_address, &off) < 0) {
+ printk(KERN_ERR "Error in pll_set\n");
+ return -1;
+ }
+
+ msleep(200);
+
+ return DRX_Start(state, off);
+}
+
+static void drxd_release(struct dvb_frontend *fe)
+{
+ struct drxd_state *state = fe->demodulator_priv;
+
+ kfree(state);
+}
+
+static struct dvb_frontend_ops drxd_ops = {
+
+ .info = {
+ .name = "Micronas DRXD DVB-T",
+ .type = FE_OFDM,
+ .frequency_min = 47125000,
+ .frequency_max = 855250000,
+ .frequency_stepsize = 166667,
+ .frequency_tolerance = 0,
+ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
+ FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
+ FE_CAN_FEC_AUTO |
+ FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+ FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | FE_CAN_MUTE_TS},
+
+ .release = drxd_release,
+ .init = drxd_init,
+ .sleep = drxd_sleep,
+ .i2c_gate_ctrl = drxd_i2c_gate_ctrl,
+
+ .set_frontend = drxd_set_frontend,
+ .get_frontend = drxd_get_frontend,
+ .get_tune_settings = drxd_get_tune_settings,
+
+ .read_status = drxd_read_status,
+ .read_ber = drxd_read_ber,
+ .read_signal_strength = drxd_read_signal_strength,
+ .read_snr = drxd_read_snr,
+ .read_ucblocks = drxd_read_ucblocks,
+};
+
+struct dvb_frontend *drxd_attach(const struct drxd_config *config,
+ void *priv, struct i2c_adapter *i2c,
+ struct device *dev)
+{
+ struct drxd_state *state = NULL;
+
+ state = kmalloc(sizeof(struct drxd_state), GFP_KERNEL);
+ if (!state)
+ return NULL;
+ memset(state, 0, sizeof(*state));
+
+ memcpy(&state->ops, &drxd_ops, sizeof(struct dvb_frontend_ops));
+ state->dev = dev;
+ state->config = *config;
+ state->i2c = i2c;
+ state->priv = priv;
+
+ mutex_init(&state->mutex);
+
+ if (Read16(state, 0, 0, 0) < 0)
+ goto error;
+
+ memcpy(&state->frontend.ops, &drxd_ops,
+ sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+ ConfigureMPEGOutput(state, 0);
+ return &state->frontend;
+
+error:
+ printk(KERN_ERR "drxd: not found\n");
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL(drxd_attach);
+
+MODULE_DESCRIPTION("DRXD driver");
+MODULE_AUTHOR("Micronas");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/drxd_map_firm.h b/drivers/media/dvb/frontends/drxd_map_firm.h
new file mode 100644
index 000000000000..6bc553abf215
--- /dev/null
+++ b/drivers/media/dvb/frontends/drxd_map_firm.h
@@ -0,0 +1,1013 @@
+/*
+ * drx3973d_map_firm.h
+ *
+ * Copyright (C) 2006-2007 Micronas
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You 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
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __DRX3973D_MAP__H__
+#define __DRX3973D_MAP__H__
+
+/*
+ * Note: originally, this file contained 12000+ lines of data
+ * Probably a few lines for every firwmare assembler instruction. However,
+ * only a few defines were actually used. So, removed all uneeded lines.
+ * If ever needed, the other lines can be easily obtained via git history.
+ */
+
+#define HI_COMM_EXEC__A 0x400000
+#define HI_COMM_MB__A 0x400002
+#define HI_CT_REG_COMM_STATE__A 0x410001
+#define HI_RA_RAM_SRV_RES__A 0x420031
+#define HI_RA_RAM_SRV_CMD__A 0x420032
+#define HI_RA_RAM_SRV_CMD_RESET 0x2
+#define HI_RA_RAM_SRV_CMD_CONFIG 0x3
+#define HI_RA_RAM_SRV_CMD_EXECUTE 0x6
+#define HI_RA_RAM_SRV_RST_KEY__A 0x420033
+#define HI_RA_RAM_SRV_RST_KEY_ACT 0x3973
+#define HI_RA_RAM_SRV_CFG_KEY__A 0x420033
+#define HI_RA_RAM_SRV_CFG_DIV__A 0x420034
+#define HI_RA_RAM_SRV_CFG_BDL__A 0x420035
+#define HI_RA_RAM_SRV_CFG_WUP__A 0x420036
+#define HI_RA_RAM_SRV_CFG_ACT__A 0x420037
+#define HI_RA_RAM_SRV_CFG_ACT_SLV0_ON 0x1
+#define HI_RA_RAM_SRV_CFG_ACT_BRD__M 0x4
+#define HI_RA_RAM_SRV_CFG_ACT_BRD_OFF 0x0
+#define HI_RA_RAM_SRV_CFG_ACT_BRD_ON 0x4
+#define HI_RA_RAM_SRV_CFG_ACT_PWD_EXE 0x8
+#define HI_RA_RAM_USR_BEGIN__A 0x420040
+#define HI_IF_RAM_TRP_BPT0__AX 0x430000
+#define HI_IF_RAM_USR_BEGIN__A 0x430200
+#define SC_COMM_EXEC__A 0x800000
+#define SC_COMM_EXEC_CTL_STOP 0x0
+#define SC_COMM_STATE__A 0x800001
+#define SC_RA_RAM_PARAM0__A 0x820040
+#define SC_RA_RAM_PARAM1__A 0x820041
+#define SC_RA_RAM_CMD_ADDR__A 0x820042
+#define SC_RA_RAM_CMD__A 0x820043
+#define SC_RA_RAM_CMD_PROC_START 0x1
+#define SC_RA_RAM_CMD_SET_PREF_PARAM 0x3
+#define SC_RA_RAM_CMD_GET_OP_PARAM 0x5
+#define SC_RA_RAM_SW_EVENT_RUN_NMASK__M 0x1
+#define SC_RA_RAM_LOCKTRACK_MIN 0x1
+#define SC_RA_RAM_OP_PARAM_MODE_2K 0x0
+#define SC_RA_RAM_OP_PARAM_MODE_8K 0x1
+#define SC_RA_RAM_OP_PARAM_GUARD_32 0x0
+#define SC_RA_RAM_OP_PARAM_GUARD_16 0x4
+#define SC_RA_RAM_OP_PARAM_GUARD_8 0x8
+#define SC_RA_RAM_OP_PARAM_GUARD_4 0xC
+#define SC_RA_RAM_OP_PARAM_CONST_QPSK 0x0
+#define SC_RA_RAM_OP_PARAM_CONST_QAM16 0x10
+#define SC_RA_RAM_OP_PARAM_CONST_QAM64 0x20
+#define SC_RA_RAM_OP_PARAM_HIER_NO 0x0
+#define SC_RA_RAM_OP_PARAM_HIER_A1 0x40
+#define SC_RA_RAM_OP_PARAM_HIER_A2 0x80
+#define SC_RA_RAM_OP_PARAM_HIER_A4 0xC0
+#define SC_RA_RAM_OP_PARAM_RATE_1_2 0x0
+#define SC_RA_RAM_OP_PARAM_RATE_2_3 0x200
+#define SC_RA_RAM_OP_PARAM_RATE_3_4 0x400
+#define SC_RA_RAM_OP_PARAM_RATE_5_6 0x600
+#define SC_RA_RAM_OP_PARAM_RATE_7_8 0x800
+#define SC_RA_RAM_OP_PARAM_PRIO_HI 0x0
+#define SC_RA_RAM_OP_PARAM_PRIO_LO 0x1000
+#define SC_RA_RAM_OP_AUTO_MODE__M 0x1
+#define SC_RA_RAM_OP_AUTO_GUARD__M 0x2
+#define SC_RA_RAM_OP_AUTO_CONST__M 0x4
+#define SC_RA_RAM_OP_AUTO_HIER__M 0x8
+#define SC_RA_RAM_OP_AUTO_RATE__M 0x10
+#define SC_RA_RAM_LOCK__A 0x82004B
+#define SC_RA_RAM_LOCK_DEMOD__M 0x1
+#define SC_RA_RAM_LOCK_FEC__M 0x2
+#define SC_RA_RAM_LOCK_MPEG__M 0x4
+#define SC_RA_RAM_BE_OPT_ENA__A 0x82004C
+#define SC_RA_RAM_BE_OPT_ENA_CP_OPT 0x1
+#define SC_RA_RAM_BE_OPT_DELAY__A 0x82004D
+#define SC_RA_RAM_CONFIG__A 0x820050
+#define SC_RA_RAM_CONFIG_FR_ENABLE__M 0x4
+#define SC_RA_RAM_CONFIG_FREQSCAN__M 0x10
+#define SC_RA_RAM_CONFIG_SLAVE__M 0x20
+#define SC_RA_RAM_IF_SAVE__AX 0x82008E
+#define SC_RA_RAM_IR_COARSE_2K_LENGTH__A 0x8200D1
+#define SC_RA_RAM_IR_COARSE_2K_LENGTH__PRE 0x9
+#define SC_RA_RAM_IR_COARSE_2K_FREQINC__A 0x8200D2
+#define SC_RA_RAM_IR_COARSE_2K_FREQINC__PRE 0x4
+#define SC_RA_RAM_IR_COARSE_2K_KAISINC__A 0x8200D3
+#define SC_RA_RAM_IR_COARSE_2K_KAISINC__PRE 0x100
+#define SC_RA_RAM_IR_COARSE_8K_LENGTH__A 0x8200D4
+#define SC_RA_RAM_IR_COARSE_8K_LENGTH__PRE 0x8
+#define SC_RA_RAM_IR_COARSE_8K_FREQINC__A 0x8200D5
+#define SC_RA_RAM_IR_COARSE_8K_FREQINC__PRE 0x8
+#define SC_RA_RAM_IR_COARSE_8K_KAISINC__A 0x8200D6
+#define SC_RA_RAM_IR_COARSE_8K_KAISINC__PRE 0x200
+#define SC_RA_RAM_IR_FINE_2K_LENGTH__A 0x8200D7
+#define SC_RA_RAM_IR_FINE_2K_LENGTH__PRE 0x9
+#define SC_RA_RAM_IR_FINE_2K_FREQINC__A 0x8200D8
+#define SC_RA_RAM_IR_FINE_2K_FREQINC__PRE 0x4
+#define SC_RA_RAM_IR_FINE_2K_KAISINC__A 0x8200D9
+#define SC_RA_RAM_IR_FINE_2K_KAISINC__PRE 0x100
+#define SC_RA_RAM_IR_FINE_8K_LENGTH__A 0x8200DA
+#define SC_RA_RAM_IR_FINE_8K_LENGTH__PRE 0xB
+#define SC_RA_RAM_IR_FINE_8K_FREQINC__A 0x8200DB
+#define SC_RA_RAM_IR_FINE_8K_FREQINC__PRE 0x1
+#define SC_RA_RAM_IR_FINE_8K_KAISINC__A 0x8200DC
+#define SC_RA_RAM_IR_FINE_8K_KAISINC__PRE 0x40
+#define SC_RA_RAM_ECHO_SHIFT_LIM__A 0x8200DD
+#define SC_RA_RAM_SAMPLE_RATE_COUNT__A 0x8200E8
+#define SC_RA_RAM_SAMPLE_RATE_STEP__A 0x8200E9
+#define SC_RA_RAM_BAND__A 0x8200EC
+#define SC_RA_RAM_LC_ABS_2K__A 0x8200F4
+#define SC_RA_RAM_LC_ABS_2K__PRE 0x1F
+#define SC_RA_RAM_LC_ABS_8K__A 0x8200F5
+#define SC_RA_RAM_LC_ABS_8K__PRE 0x1F
+#define SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE 0x1D6
+#define SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE 0x4
+#define SC_RA_RAM_EQ_IS_GAIN_QPSK_MAN__PRE 0x1BB
+#define SC_RA_RAM_EQ_IS_GAIN_QPSK_EXP__PRE 0x5
+#define SC_RA_RAM_EQ_IS_GAIN_16QAM_MAN__PRE 0x1EF
+#define SC_RA_RAM_EQ_IS_GAIN_16QAM_EXP__PRE 0x5
+#define SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_MAN__PRE 0x15E
+#define SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_EXP__PRE 0x5
+#define SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_MAN__PRE 0x11A
+#define SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_EXP__PRE 0x6
+#define SC_RA_RAM_EQ_IS_GAIN_64QAM_MAN__PRE 0x1FB
+#define SC_RA_RAM_EQ_IS_GAIN_64QAM_EXP__PRE 0x5
+#define SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_MAN__PRE 0x12F
+#define SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_EXP__PRE 0x5
+#define SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_MAN__PRE 0x197
+#define SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_EXP__PRE 0x5
+#define SC_RA_RAM_DRIVER_VERSION__AX 0x8201FE
+#define SC_RA_RAM_PROC_LOCKTRACK 0x0
+#define FE_COMM_EXEC__A 0xC00000
+#define FE_AD_REG_COMM_EXEC__A 0xC10000
+#define FE_AD_REG_FDB_IN__A 0xC10012
+#define FE_AD_REG_PD__A 0xC10013
+#define FE_AD_REG_INVEXT__A 0xC10014
+#define FE_AD_REG_CLKNEG__A 0xC10015
+#define FE_AG_REG_COMM_EXEC__A 0xC20000
+#define FE_AG_REG_AG_MODE_LOP__A 0xC20010
+#define FE_AG_REG_AG_MODE_LOP_MODE_4__M 0x10
+#define FE_AG_REG_AG_MODE_LOP_MODE_4_STATIC 0x0
+#define FE_AG_REG_AG_MODE_LOP_MODE_4_DYNAMIC 0x10
+#define FE_AG_REG_AG_MODE_LOP_MODE_5__M 0x20
+#define FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC 0x0
+#define FE_AG_REG_AG_MODE_LOP_MODE_C__M 0x1000
+#define FE_AG_REG_AG_MODE_LOP_MODE_C_STATIC 0x0
+#define FE_AG_REG_AG_MODE_LOP_MODE_C_DYNAMIC 0x1000
+#define FE_AG_REG_AG_MODE_LOP_MODE_E__M 0x4000
+#define FE_AG_REG_AG_MODE_LOP_MODE_E_STATIC 0x0
+#define FE_AG_REG_AG_MODE_LOP_MODE_E_DYNAMIC 0x4000
+#define FE_AG_REG_AG_MODE_HIP__A 0xC20011
+#define FE_AG_REG_AG_PGA_MODE__A 0xC20012
+#define FE_AG_REG_AG_PGA_MODE_PFY_PCY_AFY_REN 0x0
+#define FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN 0x1
+#define FE_AG_REG_AG_AGC_SIO__A 0xC20013
+#define FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M 0x2
+#define FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_OUTPUT 0x0
+#define FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_INPUT 0x2
+#define FE_AG_REG_AG_PWD__A 0xC20015
+#define FE_AG_REG_AG_PWD_PWD_PD2__M 0x2
+#define FE_AG_REG_AG_PWD_PWD_PD2_DISABLE 0x0
+#define FE_AG_REG_AG_PWD_PWD_PD2_ENABLE 0x2
+#define FE_AG_REG_DCE_AUR_CNT__A 0xC20016
+#define FE_AG_REG_DCE_RUR_CNT__A 0xC20017
+#define FE_AG_REG_ACE_AUR_CNT__A 0xC2001A
+#define FE_AG_REG_ACE_RUR_CNT__A 0xC2001B
+#define FE_AG_REG_CDR_RUR_CNT__A 0xC20020
+#define FE_AG_REG_EGC_RUR_CNT__A 0xC20024
+#define FE_AG_REG_EGC_SET_LVL__A 0xC20025
+#define FE_AG_REG_EGC_SET_LVL__M 0x1FF
+#define FE_AG_REG_EGC_FLA_RGN__A 0xC20026
+#define FE_AG_REG_EGC_SLO_RGN__A 0xC20027
+#define FE_AG_REG_EGC_JMP_PSN__A 0xC20028
+#define FE_AG_REG_EGC_FLA_INC__A 0xC20029
+#define FE_AG_REG_EGC_FLA_DEC__A 0xC2002A
+#define FE_AG_REG_EGC_SLO_INC__A 0xC2002B
+#define FE_AG_REG_EGC_SLO_DEC__A 0xC2002C
+#define FE_AG_REG_EGC_FAS_INC__A 0xC2002D
+#define FE_AG_REG_EGC_FAS_DEC__A 0xC2002E
+#define FE_AG_REG_PM1_AGC_WRI__A 0xC20030
+#define FE_AG_REG_PM1_AGC_WRI__M 0x7FF
+#define FE_AG_REG_GC1_AGC_RIC__A 0xC20031
+#define FE_AG_REG_GC1_AGC_OFF__A 0xC20032
+#define FE_AG_REG_GC1_AGC_MAX__A 0xC20033
+#define FE_AG_REG_GC1_AGC_MIN__A 0xC20034
+#define FE_AG_REG_GC1_AGC_DAT__A 0xC20035
+#define FE_AG_REG_GC1_AGC_DAT__M 0x3FF
+#define FE_AG_REG_PM2_AGC_WRI__A 0xC20036
+#define FE_AG_REG_IND_WIN__A 0xC2003C
+#define FE_AG_REG_IND_THD_LOL__A 0xC2003D
+#define FE_AG_REG_IND_THD_HIL__A 0xC2003E
+#define FE_AG_REG_IND_DEL__A 0xC2003F
+#define FE_AG_REG_IND_PD1_WRI__A 0xC20040
+#define FE_AG_REG_PDA_AUR_CNT__A 0xC20041
+#define FE_AG_REG_PDA_RUR_CNT__A 0xC20042
+#define FE_AG_REG_PDA_AVE_DAT__A 0xC20043
+#define FE_AG_REG_PDC_RUR_CNT__A 0xC20044
+#define FE_AG_REG_PDC_SET_LVL__A 0xC20045
+#define FE_AG_REG_PDC_FLA_RGN__A 0xC20046
+#define FE_AG_REG_PDC_JMP_PSN__A 0xC20047
+#define FE_AG_REG_PDC_FLA_STP__A 0xC20048
+#define FE_AG_REG_PDC_SLO_STP__A 0xC20049
+#define FE_AG_REG_PDC_PD2_WRI__A 0xC2004A
+#define FE_AG_REG_PDC_MAP_DAT__A 0xC2004B
+#define FE_AG_REG_PDC_MAX__A 0xC2004C
+#define FE_AG_REG_TGA_AUR_CNT__A 0xC2004D
+#define FE_AG_REG_TGA_RUR_CNT__A 0xC2004E
+#define FE_AG_REG_TGA_AVE_DAT__A 0xC2004F
+#define FE_AG_REG_TGC_RUR_CNT__A 0xC20050
+#define FE_AG_REG_TGC_SET_LVL__A 0xC20051
+#define FE_AG_REG_TGC_SET_LVL__M 0x3F
+#define FE_AG_REG_TGC_FLA_RGN__A 0xC20052
+#define FE_AG_REG_TGC_JMP_PSN__A 0xC20053
+#define FE_AG_REG_TGC_FLA_STP__A 0xC20054
+#define FE_AG_REG_TGC_SLO_STP__A 0xC20055
+#define FE_AG_REG_TGC_MAP_DAT__A 0xC20056
+#define FE_AG_REG_FGA_AUR_CNT__A 0xC20057
+#define FE_AG_REG_FGA_RUR_CNT__A 0xC20058
+#define FE_AG_REG_FGM_WRI__A 0xC20061
+#define FE_AG_REG_BGC_FGC_WRI__A 0xC20068
+#define FE_AG_REG_BGC_CGC_WRI__A 0xC20069
+#define FE_FS_REG_COMM_EXEC__A 0xC30000
+#define FE_FS_REG_ADD_INC_LOP__A 0xC30010
+#define FE_FD_REG_COMM_EXEC__A 0xC40000
+#define FE_FD_REG_SCL__A 0xC40010
+#define FE_FD_REG_MAX_LEV__A 0xC40011
+#define FE_FD_REG_NR__A 0xC40012
+#define FE_FD_REG_MEAS_VAL__A 0xC40014
+#define FE_IF_REG_COMM_EXEC__A 0xC50000
+#define FE_IF_REG_INCR0__A 0xC50010
+#define FE_IF_REG_INCR0__W 16
+#define FE_IF_REG_INCR0__M 0xFFFF
+#define FE_IF_REG_INCR1__A 0xC50011
+#define FE_IF_REG_INCR1__M 0xFF
+#define FE_CF_REG_COMM_EXEC__A 0xC60000
+#define FE_CF_REG_SCL__A 0xC60010
+#define FE_CF_REG_MAX_LEV__A 0xC60011
+#define FE_CF_REG_NR__A 0xC60012
+#define FE_CF_REG_IMP_VAL__A 0xC60013
+#define FE_CF_REG_MEAS_VAL__A 0xC60014
+#define FE_CU_REG_COMM_EXEC__A 0xC70000
+#define FE_CU_REG_FRM_CNT_RST__A 0xC70011
+#define FE_CU_REG_FRM_CNT_STR__A 0xC70012
+#define FT_COMM_EXEC__A 0x1000000
+#define FT_REG_COMM_EXEC__A 0x1010000
+#define CP_COMM_EXEC__A 0x1400000
+#define CP_REG_COMM_EXEC__A 0x1410000
+#define CP_REG_INTERVAL__A 0x1410011
+#define CP_REG_BR_SPL_OFFSET__A 0x1410023
+#define CP_REG_BR_STR_DEL__A 0x1410024
+#define CP_REG_RT_ANG_INC0__A 0x1410030
+#define CP_REG_RT_ANG_INC1__A 0x1410031
+#define CP_REG_RT_DETECT_ENA__A 0x1410032
+#define CP_REG_RT_DETECT_TRH__A 0x1410033
+#define CP_REG_RT_EXP_MARG__A 0x141003E
+#define CP_REG_AC_NEXP_OFFS__A 0x1410040
+#define CP_REG_AC_AVER_POW__A 0x1410041
+#define CP_REG_AC_MAX_POW__A 0x1410042
+#define CP_REG_AC_WEIGHT_MAN__A 0x1410043
+#define CP_REG_AC_WEIGHT_EXP__A 0x1410044
+#define CP_REG_AC_AMP_MODE__A 0x1410047
+#define CP_REG_AC_AMP_FIX__A 0x1410048
+#define CP_REG_AC_ANG_MODE__A 0x141004A
+#define CE_COMM_EXEC__A 0x1800000
+#define CE_REG_COMM_EXEC__A 0x1810000
+#define CE_REG_TAPSET__A 0x1810011
+#define CE_REG_AVG_POW__A 0x1810012
+#define CE_REG_MAX_POW__A 0x1810013
+#define CE_REG_ATT__A 0x1810014
+#define CE_REG_NRED__A 0x1810015
+#define CE_REG_NE_ERR_SELECT__A 0x1810043
+#define CE_REG_NE_TD_CAL__A 0x1810044
+#define CE_REG_NE_MIXAVG__A 0x1810046
+#define CE_REG_NE_NUPD_OFS__A 0x1810047
+#define CE_REG_PE_NEXP_OFFS__A 0x1810050
+#define CE_REG_PE_TIMESHIFT__A 0x1810051
+#define CE_REG_TP_A0_TAP_NEW__A 0x1810064
+#define CE_REG_TP_A0_TAP_NEW_VALID__A 0x1810065
+#define CE_REG_TP_A0_MU_LMS_STEP__A 0x1810066
+#define CE_REG_TP_A1_TAP_NEW__A 0x1810068
+#define CE_REG_TP_A1_TAP_NEW_VALID__A 0x1810069
+#define CE_REG_TP_A1_MU_LMS_STEP__A 0x181006A
+#define CE_REG_TI_NEXP_OFFS__A 0x1810070
+#define CE_REG_FI_SHT_INCR__A 0x1810090
+#define CE_REG_FI_EXP_NORM__A 0x1810091
+#define CE_REG_IR_INPUTSEL__A 0x18100A0
+#define CE_REG_IR_STARTPOS__A 0x18100A1
+#define CE_REG_IR_NEXP_THRES__A 0x18100A2
+#define CE_REG_FR_TREAL00__A 0x1820010
+#define CE_REG_FR_TIMAG00__A 0x1820011
+#define CE_REG_FR_TREAL01__A 0x1820012
+#define CE_REG_FR_TIMAG01__A 0x1820013
+#define CE_REG_FR_TREAL02__A 0x1820014
+#define CE_REG_FR_TIMAG02__A 0x1820015
+#define CE_REG_FR_TREAL03__A 0x1820016
+#define CE_REG_FR_TIMAG03__A 0x1820017
+#define CE_REG_FR_TREAL04__A 0x1820018
+#define CE_REG_FR_TIMAG04__A 0x1820019
+#define CE_REG_FR_TREAL05__A 0x182001A
+#define CE_REG_FR_TIMAG05__A 0x182001B
+#define CE_REG_FR_TREAL06__A 0x182001C
+#define CE_REG_FR_TIMAG06__A 0x182001D
+#define CE_REG_FR_TREAL07__A 0x182001E
+#define CE_REG_FR_TIMAG07__A 0x182001F
+#define CE_REG_FR_TREAL08__A 0x1820020
+#define CE_REG_FR_TIMAG08__A 0x1820021
+#define CE_REG_FR_TREAL09__A 0x1820022
+#define CE_REG_FR_TIMAG09__A 0x1820023
+#define CE_REG_FR_TREAL10__A 0x1820024
+#define CE_REG_FR_TIMAG10__A 0x1820025
+#define CE_REG_FR_TREAL11__A 0x1820026
+#define CE_REG_FR_TIMAG11__A 0x1820027
+#define CE_REG_FR_MID_TAP__A 0x1820028
+#define CE_REG_FR_SQS_G00__A 0x1820029
+#define CE_REG_FR_SQS_G01__A 0x182002A
+#define CE_REG_FR_SQS_G02__A 0x182002B
+#define CE_REG_FR_SQS_G03__A 0x182002C
+#define CE_REG_FR_SQS_G04__A 0x182002D
+#define CE_REG_FR_SQS_G05__A 0x182002E
+#define CE_REG_FR_SQS_G06__A 0x182002F
+#define CE_REG_FR_SQS_G07__A 0x1820030
+#define CE_REG_FR_SQS_G08__A 0x1820031
+#define CE_REG_FR_SQS_G09__A 0x1820032
+#define CE_REG_FR_SQS_G10__A 0x1820033
+#define CE_REG_FR_SQS_G11__A 0x1820034
+#define CE_REG_FR_SQS_G12__A 0x1820035
+#define CE_REG_FR_RIO_G00__A 0x1820036
+#define CE_REG_FR_RIO_G01__A 0x1820037
+#define CE_REG_FR_RIO_G02__A 0x1820038
+#define CE_REG_FR_RIO_G03__A 0x1820039
+#define CE_REG_FR_RIO_G04__A 0x182003A
+#define CE_REG_FR_RIO_G05__A 0x182003B
+#define CE_REG_FR_RIO_G06__A 0x182003C
+#define CE_REG_FR_RIO_G07__A 0x182003D
+#define CE_REG_FR_RIO_G08__A 0x182003E
+#define CE_REG_FR_RIO_G09__A 0x182003F
+#define CE_REG_FR_RIO_G10__A 0x1820040
+#define CE_REG_FR_MODE__A 0x1820041
+#define CE_REG_FR_SQS_TRH__A 0x1820042
+#define CE_REG_FR_RIO_GAIN__A 0x1820043
+#define CE_REG_FR_BYPASS__A 0x1820044
+#define CE_REG_FR_PM_SET__A 0x1820045
+#define CE_REG_FR_ERR_SH__A 0x1820046
+#define CE_REG_FR_MAN_SH__A 0x1820047
+#define CE_REG_FR_TAP_SH__A 0x1820048
+#define EQ_COMM_EXEC__A 0x1C00000
+#define EQ_REG_COMM_EXEC__A 0x1C10000
+#define EQ_REG_COMM_MB__A 0x1C10002
+#define EQ_REG_IS_GAIN_MAN__A 0x1C10015
+#define EQ_REG_IS_GAIN_EXP__A 0x1C10016
+#define EQ_REG_IS_CLIP_EXP__A 0x1C10017
+#define EQ_REG_SN_CEGAIN__A 0x1C1002A
+#define EQ_REG_SN_OFFSET__A 0x1C1002B
+#define EQ_REG_RC_SEL_CAR__A 0x1C10032
+#define EQ_REG_RC_SEL_CAR_INIT 0x0
+#define EQ_REG_RC_SEL_CAR_DIV_ON 0x1
+#define EQ_REG_RC_SEL_CAR_PASS_A_CC 0x0
+#define EQ_REG_RC_SEL_CAR_PASS_B_CE 0x2
+#define EQ_REG_RC_SEL_CAR_LOCAL_A_CC 0x0
+#define EQ_REG_RC_SEL_CAR_LOCAL_B_CE 0x8
+#define EQ_REG_RC_SEL_CAR_MEAS_A_CC 0x0
+#define EQ_REG_RC_SEL_CAR_MEAS_B_CE 0x20
+#define EQ_REG_OT_CONST__A 0x1C10046
+#define EQ_REG_OT_ALPHA__A 0x1C10047
+#define EQ_REG_OT_QNT_THRES0__A 0x1C10048
+#define EQ_REG_OT_QNT_THRES1__A 0x1C10049
+#define EQ_REG_OT_CSI_STEP__A 0x1C1004A
+#define EQ_REG_OT_CSI_OFFSET__A 0x1C1004B
+#define EQ_REG_TD_REQ_SMB_CNT__A 0x1C10061
+#define EQ_REG_TD_TPS_PWR_OFS__A 0x1C10062
+#define EC_SB_REG_COMM_EXEC__A 0x2010000
+#define EC_SB_REG_TR_MODE__A 0x2010010
+#define EC_SB_REG_TR_MODE_8K 0x0
+#define EC_SB_REG_TR_MODE_2K 0x1
+#define EC_SB_REG_CONST__A 0x2010011
+#define EC_SB_REG_CONST_QPSK 0x0
+#define EC_SB_REG_CONST_16QAM 0x1
+#define EC_SB_REG_CONST_64QAM 0x2
+#define EC_SB_REG_ALPHA__A 0x2010012
+#define EC_SB_REG_PRIOR__A 0x2010013
+#define EC_SB_REG_PRIOR_HI 0x0
+#define EC_SB_REG_PRIOR_LO 0x1
+#define EC_SB_REG_CSI_HI__A 0x2010014
+#define EC_SB_REG_CSI_LO__A 0x2010015
+#define EC_SB_REG_SMB_TGL__A 0x2010016
+#define EC_SB_REG_SNR_HI__A 0x2010017
+#define EC_SB_REG_SNR_MID__A 0x2010018
+#define EC_SB_REG_SNR_LO__A 0x2010019
+#define EC_SB_REG_SCALE_MSB__A 0x201001A
+#define EC_SB_REG_SCALE_BIT2__A 0x201001B
+#define EC_SB_REG_SCALE_LSB__A 0x201001C
+#define EC_SB_REG_CSI_OFS__A 0x201001D
+#define EC_VD_REG_COMM_EXEC__A 0x2090000
+#define EC_VD_REG_FORCE__A 0x2090010
+#define EC_VD_REG_SET_CODERATE__A 0x2090011
+#define EC_VD_REG_SET_CODERATE_C1_2 0x0
+#define EC_VD_REG_SET_CODERATE_C2_3 0x1
+#define EC_VD_REG_SET_CODERATE_C3_4 0x2
+#define EC_VD_REG_SET_CODERATE_C5_6 0x3
+#define EC_VD_REG_SET_CODERATE_C7_8 0x4
+#define EC_VD_REG_REQ_SMB_CNT__A 0x2090012
+#define EC_VD_REG_RLK_ENA__A 0x2090014
+#define EC_OD_REG_COMM_EXEC__A 0x2110000
+#define EC_OD_REG_SYNC__A 0x2110010
+#define EC_OD_DEINT_RAM__A 0x2120000
+#define EC_RS_REG_COMM_EXEC__A 0x2130000
+#define EC_RS_REG_REQ_PCK_CNT__A 0x2130010
+#define EC_RS_REG_VAL__A 0x2130011
+#define EC_RS_REG_VAL_PCK 0x1
+#define EC_RS_EC_RAM__A 0x2140000
+#define EC_OC_REG_COMM_EXEC__A 0x2150000
+#define EC_OC_REG_COMM_EXEC_CTL_ACTIVE 0x1
+#define EC_OC_REG_COMM_EXEC_CTL_HOLD 0x2
+#define EC_OC_REG_COMM_INT_STA__A 0x2150007
+#define EC_OC_REG_OC_MODE_LOP__A 0x2150010
+#define EC_OC_REG_OC_MODE_LOP_PAR_ENA__M 0x1
+#define EC_OC_REG_OC_MODE_LOP_PAR_ENA_ENABLE 0x0
+#define EC_OC_REG_OC_MODE_LOP_PAR_ENA_DISABLE 0x1
+#define EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC__M 0x4
+#define EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC_STATIC 0x0
+#define EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE__M 0x80
+#define EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE_SERIAL 0x80
+#define EC_OC_REG_OC_MODE_HIP__A 0x2150011
+#define EC_OC_REG_OC_MODE_HIP_MPG_BUS_SRC_MONITOR 0x10
+#define EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL__M 0x200
+#define EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_DISABLE 0x0
+#define EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_ENABLE 0x200
+#define EC_OC_REG_OC_MPG_SIO__A 0x2150012
+#define EC_OC_REG_OC_MPG_SIO__M 0xFFF
+#define EC_OC_REG_OC_MON_SIO__A 0x2150013
+#define EC_OC_REG_DTO_INC_LOP__A 0x2150014
+#define EC_OC_REG_DTO_INC_HIP__A 0x2150015
+#define EC_OC_REG_SNC_ISC_LVL__A 0x2150016
+#define EC_OC_REG_SNC_ISC_LVL_OSC__M 0xF0
+#define EC_OC_REG_TMD_TOP_MODE__A 0x215001D
+#define EC_OC_REG_TMD_TOP_CNT__A 0x215001E
+#define EC_OC_REG_TMD_HIL_MAR__A 0x215001F
+#define EC_OC_REG_TMD_LOL_MAR__A 0x2150020
+#define EC_OC_REG_TMD_CUR_CNT__A 0x2150021
+#define EC_OC_REG_AVR_ASH_CNT__A 0x2150023
+#define EC_OC_REG_AVR_BSH_CNT__A 0x2150024
+#define EC_OC_REG_RCN_MODE__A 0x2150027
+#define EC_OC_REG_RCN_CRA_LOP__A 0x2150028
+#define EC_OC_REG_RCN_CRA_HIP__A 0x2150029
+#define EC_OC_REG_RCN_CST_LOP__A 0x215002A
+#define EC_OC_REG_RCN_CST_HIP__A 0x215002B
+#define EC_OC_REG_RCN_SET_LVL__A 0x215002C
+#define EC_OC_REG_RCN_GAI_LVL__A 0x215002D
+#define EC_OC_REG_RCN_CLP_LOP__A 0x2150032
+#define EC_OC_REG_RCN_CLP_HIP__A 0x2150033
+#define EC_OC_REG_RCN_MAP_LOP__A 0x2150034
+#define EC_OC_REG_RCN_MAP_HIP__A 0x2150035
+#define EC_OC_REG_OCR_MPG_UOS__A 0x2150036
+#define EC_OC_REG_OCR_MPG_UOS__M 0xFFF
+#define EC_OC_REG_OCR_MPG_UOS_INIT 0x0
+#define EC_OC_REG_OCR_MPG_USR_DAT__A 0x2150038
+#define EC_OC_REG_OCR_MON_UOS__A 0x2150039
+#define EC_OC_REG_OCR_MON_UOS_DAT_0_ENABLE 0x1
+#define EC_OC_REG_OCR_MON_UOS_DAT_1_ENABLE 0x2
+#define EC_OC_REG_OCR_MON_UOS_DAT_2_ENABLE 0x4
+#define EC_OC_REG_OCR_MON_UOS_DAT_3_ENABLE 0x8
+#define EC_OC_REG_OCR_MON_UOS_DAT_4_ENABLE 0x10
+#define EC_OC_REG_OCR_MON_UOS_DAT_5_ENABLE 0x20
+#define EC_OC_REG_OCR_MON_UOS_DAT_6_ENABLE 0x40
+#define EC_OC_REG_OCR_MON_UOS_DAT_7_ENABLE 0x80
+#define EC_OC_REG_OCR_MON_UOS_DAT_8_ENABLE 0x100
+#define EC_OC_REG_OCR_MON_UOS_DAT_9_ENABLE 0x200
+#define EC_OC_REG_OCR_MON_UOS_VAL_ENABLE 0x400
+#define EC_OC_REG_OCR_MON_UOS_CLK_ENABLE 0x800
+#define EC_OC_REG_OCR_MON_WRI__A 0x215003A
+#define EC_OC_REG_OCR_MON_WRI_INIT 0x0
+#define EC_OC_REG_IPR_INV_MPG__A 0x2150045
+#define CC_REG_OSC_MODE__A 0x2410010
+#define CC_REG_OSC_MODE_M20 0x1
+#define CC_REG_PLL_MODE__A 0x2410011
+#define CC_REG_PLL_MODE_BYPASS_PLL 0x1
+#define CC_REG_PLL_MODE_PUMP_CUR_12 0x14
+#define CC_REG_REF_DIVIDE__A 0x2410012
+#define CC_REG_PWD_MODE__A 0x2410015
+#define CC_REG_PWD_MODE_DOWN_PLL 0x2
+#define CC_REG_UPDATE__A 0x2410017
+#define CC_REG_UPDATE_KEY 0x3973
+#define CC_REG_JTAGID_L__A 0x2410019
+#define LC_COMM_EXEC__A 0x2800000
+#define LC_RA_RAM_IFINCR_NOM_L__A 0x282000C
+#define LC_RA_RAM_FILTER_SYM_SET__A 0x282001A
+#define LC_RA_RAM_FILTER_SYM_SET__PRE 0x3E8
+#define LC_RA_RAM_FILTER_CRMM_A__A 0x2820060
+#define LC_RA_RAM_FILTER_CRMM_A__PRE 0x4
+#define LC_RA_RAM_FILTER_CRMM_B__A 0x2820061
+#define LC_RA_RAM_FILTER_CRMM_B__PRE 0x1
+#define LC_RA_RAM_FILTER_SRMM_A__A 0x2820068
+#define LC_RA_RAM_FILTER_SRMM_A__PRE 0x4
+#define LC_RA_RAM_FILTER_SRMM_B__A 0x2820069
+#define LC_RA_RAM_FILTER_SRMM_B__PRE 0x1
+#define B_HI_COMM_EXEC__A 0x400000
+#define B_HI_COMM_MB__A 0x400002
+#define B_HI_CT_REG_COMM_STATE__A 0x410001
+#define B_HI_RA_RAM_SRV_RES__A 0x420031
+#define B_HI_RA_RAM_SRV_CMD__A 0x420032
+#define B_HI_RA_RAM_SRV_CMD_RESET 0x2
+#define B_HI_RA_RAM_SRV_CMD_CONFIG 0x3
+#define B_HI_RA_RAM_SRV_CMD_EXECUTE 0x6
+#define B_HI_RA_RAM_SRV_RST_KEY__A 0x420033
+#define B_HI_RA_RAM_SRV_RST_KEY_ACT 0x3973
+#define B_HI_RA_RAM_SRV_CFG_KEY__A 0x420033
+#define B_HI_RA_RAM_SRV_CFG_DIV__A 0x420034
+#define B_HI_RA_RAM_SRV_CFG_BDL__A 0x420035
+#define B_HI_RA_RAM_SRV_CFG_WUP__A 0x420036
+#define B_HI_RA_RAM_SRV_CFG_ACT__A 0x420037
+#define B_HI_RA_RAM_SRV_CFG_ACT_SLV0_ON 0x1
+#define B_HI_RA_RAM_SRV_CFG_ACT_BRD__M 0x4
+#define B_HI_RA_RAM_SRV_CFG_ACT_BRD_OFF 0x0
+#define B_HI_RA_RAM_SRV_CFG_ACT_BRD_ON 0x4
+#define B_HI_RA_RAM_SRV_CFG_ACT_PWD_EXE 0x8
+#define B_HI_RA_RAM_USR_BEGIN__A 0x420040
+#define B_HI_IF_RAM_TRP_BPT0__AX 0x430000
+#define B_HI_IF_RAM_USR_BEGIN__A 0x430200
+#define B_SC_COMM_EXEC__A 0x800000
+#define B_SC_COMM_EXEC_CTL_STOP 0x0
+#define B_SC_COMM_STATE__A 0x800001
+#define B_SC_RA_RAM_PARAM0__A 0x820040
+#define B_SC_RA_RAM_PARAM1__A 0x820041
+#define B_SC_RA_RAM_CMD_ADDR__A 0x820042
+#define B_SC_RA_RAM_CMD__A 0x820043
+#define B_SC_RA_RAM_CMD_PROC_START 0x1
+#define B_SC_RA_RAM_CMD_SET_PREF_PARAM 0x3
+#define B_SC_RA_RAM_CMD_GET_OP_PARAM 0x5
+#define B_SC_RA_RAM_SW_EVENT_RUN_NMASK__M 0x1
+#define B_SC_RA_RAM_LOCKTRACK_MIN 0x1
+#define B_SC_RA_RAM_OP_PARAM_MODE_2K 0x0
+#define B_SC_RA_RAM_OP_PARAM_MODE_8K 0x1
+#define B_SC_RA_RAM_OP_PARAM_GUARD_32 0x0
+#define B_SC_RA_RAM_OP_PARAM_GUARD_16 0x4
+#define B_SC_RA_RAM_OP_PARAM_GUARD_8 0x8
+#define B_SC_RA_RAM_OP_PARAM_GUARD_4 0xC
+#define B_SC_RA_RAM_OP_PARAM_CONST_QPSK 0x0
+#define B_SC_RA_RAM_OP_PARAM_CONST_QAM16 0x10
+#define B_SC_RA_RAM_OP_PARAM_CONST_QAM64 0x20
+#define B_SC_RA_RAM_OP_PARAM_HIER_NO 0x0
+#define B_SC_RA_RAM_OP_PARAM_HIER_A1 0x40
+#define B_SC_RA_RAM_OP_PARAM_HIER_A2 0x80
+#define B_SC_RA_RAM_OP_PARAM_HIER_A4 0xC0
+#define B_SC_RA_RAM_OP_PARAM_RATE_1_2 0x0
+#define B_SC_RA_RAM_OP_PARAM_RATE_2_3 0x200
+#define B_SC_RA_RAM_OP_PARAM_RATE_3_4 0x400
+#define B_SC_RA_RAM_OP_PARAM_RATE_5_6 0x600
+#define B_SC_RA_RAM_OP_PARAM_RATE_7_8 0x800
+#define B_SC_RA_RAM_OP_PARAM_PRIO_HI 0x0
+#define B_SC_RA_RAM_OP_PARAM_PRIO_LO 0x1000
+#define B_SC_RA_RAM_OP_AUTO_MODE__M 0x1
+#define B_SC_RA_RAM_OP_AUTO_GUARD__M 0x2
+#define B_SC_RA_RAM_OP_AUTO_CONST__M 0x4
+#define B_SC_RA_RAM_OP_AUTO_HIER__M 0x8
+#define B_SC_RA_RAM_OP_AUTO_RATE__M 0x10
+#define B_SC_RA_RAM_LOCK__A 0x82004B
+#define B_SC_RA_RAM_LOCK_DEMOD__M 0x1
+#define B_SC_RA_RAM_LOCK_FEC__M 0x2
+#define B_SC_RA_RAM_LOCK_MPEG__M 0x4
+#define B_SC_RA_RAM_BE_OPT_ENA__A 0x82004C
+#define B_SC_RA_RAM_BE_OPT_ENA_CP_OPT 0x1
+#define B_SC_RA_RAM_BE_OPT_DELAY__A 0x82004D
+#define B_SC_RA_RAM_CONFIG__A 0x820050
+#define B_SC_RA_RAM_CONFIG_FR_ENABLE__M 0x4
+#define B_SC_RA_RAM_CONFIG_FREQSCAN__M 0x10
+#define B_SC_RA_RAM_CONFIG_SLAVE__M 0x20
+#define B_SC_RA_RAM_CONFIG_DIV_BLANK_ENABLE__M 0x200
+#define B_SC_RA_RAM_CONFIG_DIV_ECHO_ENABLE__M 0x400
+#define B_SC_RA_RAM_CO_TD_CAL_2K__A 0x82005D
+#define B_SC_RA_RAM_CO_TD_CAL_8K__A 0x82005E
+#define B_SC_RA_RAM_IF_SAVE__AX 0x82008E
+#define B_SC_RA_RAM_DIVERSITY_DELAY_2K_32__A 0x820098
+#define B_SC_RA_RAM_DIVERSITY_DELAY_2K_16__A 0x820099
+#define B_SC_RA_RAM_DIVERSITY_DELAY_2K_8__A 0x82009A
+#define B_SC_RA_RAM_DIVERSITY_DELAY_2K_4__A 0x82009B
+#define B_SC_RA_RAM_DIVERSITY_DELAY_8K_32__A 0x82009C
+#define B_SC_RA_RAM_DIVERSITY_DELAY_8K_16__A 0x82009D
+#define B_SC_RA_RAM_DIVERSITY_DELAY_8K_8__A 0x82009E
+#define B_SC_RA_RAM_DIVERSITY_DELAY_8K_4__A 0x82009F
+#define B_SC_RA_RAM_IR_COARSE_2K_LENGTH__A 0x8200D1
+#define B_SC_RA_RAM_IR_COARSE_2K_LENGTH__PRE 0x9
+#define B_SC_RA_RAM_IR_COARSE_2K_FREQINC__A 0x8200D2
+#define B_SC_RA_RAM_IR_COARSE_2K_FREQINC__PRE 0x4
+#define B_SC_RA_RAM_IR_COARSE_2K_KAISINC__A 0x8200D3
+#define B_SC_RA_RAM_IR_COARSE_2K_KAISINC__PRE 0x100
+#define B_SC_RA_RAM_IR_COARSE_8K_LENGTH__A 0x8200D4
+#define B_SC_RA_RAM_IR_COARSE_8K_LENGTH__PRE 0x8
+#define B_SC_RA_RAM_IR_COARSE_8K_FREQINC__A 0x8200D5
+#define B_SC_RA_RAM_IR_COARSE_8K_FREQINC__PRE 0x8
+#define B_SC_RA_RAM_IR_COARSE_8K_KAISINC__A 0x8200D6
+#define B_SC_RA_RAM_IR_COARSE_8K_KAISINC__PRE 0x200
+#define B_SC_RA_RAM_IR_FINE_2K_LENGTH__A 0x8200D7
+#define B_SC_RA_RAM_IR_FINE_2K_LENGTH__PRE 0x9
+#define B_SC_RA_RAM_IR_FINE_2K_FREQINC__A 0x8200D8
+#define B_SC_RA_RAM_IR_FINE_2K_FREQINC__PRE 0x4
+#define B_SC_RA_RAM_IR_FINE_2K_KAISINC__A 0x8200D9
+#define B_SC_RA_RAM_IR_FINE_2K_KAISINC__PRE 0x100
+#define B_SC_RA_RAM_IR_FINE_8K_LENGTH__A 0x8200DA
+#define B_SC_RA_RAM_IR_FINE_8K_LENGTH__PRE 0xB
+#define B_SC_RA_RAM_IR_FINE_8K_FREQINC__A 0x8200DB
+#define B_SC_RA_RAM_IR_FINE_8K_FREQINC__PRE 0x1
+#define B_SC_RA_RAM_IR_FINE_8K_KAISINC__A 0x8200DC
+#define B_SC_RA_RAM_IR_FINE_8K_KAISINC__PRE 0x40
+#define B_SC_RA_RAM_ECHO_SHIFT_LIM__A 0x8200DD
+#define B_SC_RA_RAM_SAMPLE_RATE_COUNT__A 0x8200E8
+#define B_SC_RA_RAM_SAMPLE_RATE_STEP__A 0x8200E9
+#define B_SC_RA_RAM_BAND__A 0x8200EC
+#define B_SC_RA_RAM_LC_ABS_2K__A 0x8200F4
+#define B_SC_RA_RAM_LC_ABS_2K__PRE 0x1F
+#define B_SC_RA_RAM_LC_ABS_8K__A 0x8200F5
+#define B_SC_RA_RAM_LC_ABS_8K__PRE 0x1F
+#define B_SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_MAN__PRE 0x100
+#define B_SC_RA_RAM_EQ_IS_GAIN_UNKNOWN_EXP__PRE 0x4
+#define B_SC_RA_RAM_EQ_IS_GAIN_QPSK_MAN__PRE 0x1E2
+#define B_SC_RA_RAM_EQ_IS_GAIN_QPSK_EXP__PRE 0x4
+#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_MAN__PRE 0x10D
+#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_EXP__PRE 0x5
+#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_MAN__PRE 0x17D
+#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_A2_EXP__PRE 0x4
+#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_MAN__PRE 0x133
+#define B_SC_RA_RAM_EQ_IS_GAIN_16QAM_A4_EXP__PRE 0x5
+#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_MAN__PRE 0x114
+#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_EXP__PRE 0x5
+#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_MAN__PRE 0x14A
+#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_A2_EXP__PRE 0x4
+#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_MAN__PRE 0x1BB
+#define B_SC_RA_RAM_EQ_IS_GAIN_64QAM_A4_EXP__PRE 0x4
+#define B_SC_RA_RAM_DRIVER_VERSION__AX 0x8201FE
+#define B_SC_RA_RAM_PROC_LOCKTRACK 0x0
+#define B_FE_COMM_EXEC__A 0xC00000
+#define B_FE_AD_REG_COMM_EXEC__A 0xC10000
+#define B_FE_AD_REG_FDB_IN__A 0xC10012
+#define B_FE_AD_REG_PD__A 0xC10013
+#define B_FE_AD_REG_INVEXT__A 0xC10014
+#define B_FE_AD_REG_CLKNEG__A 0xC10015
+#define B_FE_AG_REG_COMM_EXEC__A 0xC20000
+#define B_FE_AG_REG_AG_MODE_LOP__A 0xC20010
+#define B_FE_AG_REG_AG_MODE_LOP_MODE_4__M 0x10
+#define B_FE_AG_REG_AG_MODE_LOP_MODE_4_STATIC 0x0
+#define B_FE_AG_REG_AG_MODE_LOP_MODE_4_DYNAMIC 0x10
+#define B_FE_AG_REG_AG_MODE_LOP_MODE_5__M 0x20
+#define B_FE_AG_REG_AG_MODE_LOP_MODE_5_STATIC 0x0
+#define B_FE_AG_REG_AG_MODE_LOP_MODE_C__M 0x1000
+#define B_FE_AG_REG_AG_MODE_LOP_MODE_C_STATIC 0x0
+#define B_FE_AG_REG_AG_MODE_LOP_MODE_C_DYNAMIC 0x1000
+#define B_FE_AG_REG_AG_MODE_LOP_MODE_E__M 0x4000
+#define B_FE_AG_REG_AG_MODE_LOP_MODE_E_STATIC 0x0
+#define B_FE_AG_REG_AG_MODE_LOP_MODE_E_DYNAMIC 0x4000
+#define B_FE_AG_REG_AG_MODE_HIP__A 0xC20011
+#define B_FE_AG_REG_AG_MODE_HIP_MODE_J__M 0x8
+#define B_FE_AG_REG_AG_MODE_HIP_MODE_J_STATIC 0x0
+#define B_FE_AG_REG_AG_MODE_HIP_MODE_J_DYNAMIC 0x8
+#define B_FE_AG_REG_AG_PGA_MODE__A 0xC20012
+#define B_FE_AG_REG_AG_PGA_MODE_PFY_PCY_AFY_REN 0x0
+#define B_FE_AG_REG_AG_PGA_MODE_PFN_PCN_AFY_REN 0x1
+#define B_FE_AG_REG_AG_AGC_SIO__A 0xC20013
+#define B_FE_AG_REG_AG_AGC_SIO_AGC_SIO_2__M 0x2
+#define B_FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_OUTPUT 0x0
+#define B_FE_AG_REG_AG_AGC_SIO_AGC_SIO_2_INPUT 0x2
+#define B_FE_AG_REG_AG_PWD__A 0xC20015
+#define B_FE_AG_REG_AG_PWD_PWD_PD2__M 0x2
+#define B_FE_AG_REG_AG_PWD_PWD_PD2_DISABLE 0x0
+#define B_FE_AG_REG_AG_PWD_PWD_PD2_ENABLE 0x2
+#define B_FE_AG_REG_DCE_AUR_CNT__A 0xC20016
+#define B_FE_AG_REG_DCE_RUR_CNT__A 0xC20017
+#define B_FE_AG_REG_ACE_AUR_CNT__A 0xC2001A
+#define B_FE_AG_REG_ACE_RUR_CNT__A 0xC2001B
+#define B_FE_AG_REG_CDR_RUR_CNT__A 0xC20020
+#define B_FE_AG_REG_EGC_RUR_CNT__A 0xC20024
+#define B_FE_AG_REG_EGC_SET_LVL__A 0xC20025
+#define B_FE_AG_REG_EGC_SET_LVL__M 0x1FF
+#define B_FE_AG_REG_EGC_FLA_RGN__A 0xC20026
+#define B_FE_AG_REG_EGC_SLO_RGN__A 0xC20027
+#define B_FE_AG_REG_EGC_JMP_PSN__A 0xC20028
+#define B_FE_AG_REG_EGC_FLA_INC__A 0xC20029
+#define B_FE_AG_REG_EGC_FLA_DEC__A 0xC2002A
+#define B_FE_AG_REG_EGC_SLO_INC__A 0xC2002B
+#define B_FE_AG_REG_EGC_SLO_DEC__A 0xC2002C
+#define B_FE_AG_REG_EGC_FAS_INC__A 0xC2002D
+#define B_FE_AG_REG_EGC_FAS_DEC__A 0xC2002E
+#define B_FE_AG_REG_PM1_AGC_WRI__A 0xC20030
+#define B_FE_AG_REG_PM1_AGC_WRI__M 0x7FF
+#define B_FE_AG_REG_GC1_AGC_RIC__A 0xC20031
+#define B_FE_AG_REG_GC1_AGC_OFF__A 0xC20032
+#define B_FE_AG_REG_GC1_AGC_MAX__A 0xC20033
+#define B_FE_AG_REG_GC1_AGC_MIN__A 0xC20034
+#define B_FE_AG_REG_GC1_AGC_DAT__A 0xC20035
+#define B_FE_AG_REG_GC1_AGC_DAT__M 0x3FF
+#define B_FE_AG_REG_PM2_AGC_WRI__A 0xC20036
+#define B_FE_AG_REG_IND_WIN__A 0xC2003C
+#define B_FE_AG_REG_IND_THD_LOL__A 0xC2003D
+#define B_FE_AG_REG_IND_THD_HIL__A 0xC2003E
+#define B_FE_AG_REG_IND_DEL__A 0xC2003F
+#define B_FE_AG_REG_IND_PD1_WRI__A 0xC20040
+#define B_FE_AG_REG_PDA_AUR_CNT__A 0xC20041
+#define B_FE_AG_REG_PDA_RUR_CNT__A 0xC20042
+#define B_FE_AG_REG_PDA_AVE_DAT__A 0xC20043
+#define B_FE_AG_REG_PDC_RUR_CNT__A 0xC20044
+#define B_FE_AG_REG_PDC_SET_LVL__A 0xC20045
+#define B_FE_AG_REG_PDC_FLA_RGN__A 0xC20046
+#define B_FE_AG_REG_PDC_JMP_PSN__A 0xC20047
+#define B_FE_AG_REG_PDC_FLA_STP__A 0xC20048
+#define B_FE_AG_REG_PDC_SLO_STP__A 0xC20049
+#define B_FE_AG_REG_PDC_PD2_WRI__A 0xC2004A
+#define B_FE_AG_REG_PDC_MAP_DAT__A 0xC2004B
+#define B_FE_AG_REG_PDC_MAX__A 0xC2004C
+#define B_FE_AG_REG_TGA_AUR_CNT__A 0xC2004D
+#define B_FE_AG_REG_TGA_RUR_CNT__A 0xC2004E
+#define B_FE_AG_REG_TGA_AVE_DAT__A 0xC2004F
+#define B_FE_AG_REG_TGC_RUR_CNT__A 0xC20050
+#define B_FE_AG_REG_TGC_SET_LVL__A 0xC20051
+#define B_FE_AG_REG_TGC_SET_LVL__M 0x3F
+#define B_FE_AG_REG_TGC_FLA_RGN__A 0xC20052
+#define B_FE_AG_REG_TGC_JMP_PSN__A 0xC20053
+#define B_FE_AG_REG_TGC_FLA_STP__A 0xC20054
+#define B_FE_AG_REG_TGC_SLO_STP__A 0xC20055
+#define B_FE_AG_REG_TGC_MAP_DAT__A 0xC20056
+#define B_FE_AG_REG_FGM_WRI__A 0xC20061
+#define B_FE_AG_REG_BGC_FGC_WRI__A 0xC20068
+#define B_FE_AG_REG_BGC_CGC_WRI__A 0xC20069
+#define B_FE_FS_REG_COMM_EXEC__A 0xC30000
+#define B_FE_FS_REG_ADD_INC_LOP__A 0xC30010
+#define B_FE_FD_REG_COMM_EXEC__A 0xC40000
+#define B_FE_FD_REG_SCL__A 0xC40010
+#define B_FE_FD_REG_MAX_LEV__A 0xC40011
+#define B_FE_FD_REG_NR__A 0xC40012
+#define B_FE_FD_REG_MEAS_VAL__A 0xC40014
+#define B_FE_IF_REG_COMM_EXEC__A 0xC50000
+#define B_FE_IF_REG_INCR0__A 0xC50010
+#define B_FE_IF_REG_INCR0__W 16
+#define B_FE_IF_REG_INCR0__M 0xFFFF
+#define B_FE_IF_REG_INCR1__A 0xC50011
+#define B_FE_IF_REG_INCR1__M 0xFF
+#define B_FE_CF_REG_COMM_EXEC__A 0xC60000
+#define B_FE_CF_REG_SCL__A 0xC60010
+#define B_FE_CF_REG_MAX_LEV__A 0xC60011
+#define B_FE_CF_REG_NR__A 0xC60012
+#define B_FE_CF_REG_IMP_VAL__A 0xC60013
+#define B_FE_CF_REG_MEAS_VAL__A 0xC60014
+#define B_FE_CU_REG_COMM_EXEC__A 0xC70000
+#define B_FE_CU_REG_FRM_CNT_RST__A 0xC70011
+#define B_FE_CU_REG_FRM_CNT_STR__A 0xC70012
+#define B_FE_CU_REG_CTR_NFC_ICR__A 0xC70020
+#define B_FE_CU_REG_CTR_NFC_OCR__A 0xC70021
+#define B_FE_CU_REG_DIV_NFC_CLP__A 0xC70027
+#define B_FT_COMM_EXEC__A 0x1000000
+#define B_FT_REG_COMM_EXEC__A 0x1010000
+#define B_CP_COMM_EXEC__A 0x1400000
+#define B_CP_REG_COMM_EXEC__A 0x1410000
+#define B_CP_REG_INTERVAL__A 0x1410011
+#define B_CP_REG_BR_SPL_OFFSET__A 0x1410023
+#define B_CP_REG_BR_STR_DEL__A 0x1410024
+#define B_CP_REG_RT_ANG_INC0__A 0x1410030
+#define B_CP_REG_RT_ANG_INC1__A 0x1410031
+#define B_CP_REG_RT_DETECT_TRH__A 0x1410033
+#define B_CP_REG_AC_NEXP_OFFS__A 0x1410040
+#define B_CP_REG_AC_AVER_POW__A 0x1410041
+#define B_CP_REG_AC_MAX_POW__A 0x1410042
+#define B_CP_REG_AC_WEIGHT_MAN__A 0x1410043
+#define B_CP_REG_AC_WEIGHT_EXP__A 0x1410044
+#define B_CP_REG_AC_AMP_MODE__A 0x1410047
+#define B_CP_REG_AC_AMP_FIX__A 0x1410048
+#define B_CP_REG_AC_ANG_MODE__A 0x141004A
+#define B_CE_COMM_EXEC__A 0x1800000
+#define B_CE_REG_COMM_EXEC__A 0x1810000
+#define B_CE_REG_TAPSET__A 0x1810011
+#define B_CE_REG_AVG_POW__A 0x1810012
+#define B_CE_REG_MAX_POW__A 0x1810013
+#define B_CE_REG_ATT__A 0x1810014
+#define B_CE_REG_NRED__A 0x1810015
+#define B_CE_REG_NE_ERR_SELECT__A 0x1810043
+#define B_CE_REG_NE_TD_CAL__A 0x1810044
+#define B_CE_REG_NE_MIXAVG__A 0x1810046
+#define B_CE_REG_NE_NUPD_OFS__A 0x1810047
+#define B_CE_REG_PE_NEXP_OFFS__A 0x1810050
+#define B_CE_REG_PE_TIMESHIFT__A 0x1810051
+#define B_CE_REG_TP_A0_TAP_NEW__A 0x1810064
+#define B_CE_REG_TP_A0_TAP_NEW_VALID__A 0x1810065
+#define B_CE_REG_TP_A0_MU_LMS_STEP__A 0x1810066
+#define B_CE_REG_TP_A1_TAP_NEW__A 0x1810068
+#define B_CE_REG_TP_A1_TAP_NEW_VALID__A 0x1810069
+#define B_CE_REG_TP_A1_MU_LMS_STEP__A 0x181006A
+#define B_CE_REG_TI_PHN_ENABLE__A 0x1810073
+#define B_CE_REG_FI_SHT_INCR__A 0x1810090
+#define B_CE_REG_FI_EXP_NORM__A 0x1810091
+#define B_CE_REG_IR_INPUTSEL__A 0x18100A0
+#define B_CE_REG_IR_STARTPOS__A 0x18100A1
+#define B_CE_REG_IR_NEXP_THRES__A 0x18100A2
+#define B_CE_REG_FR_TREAL00__A 0x1820010
+#define B_CE_REG_FR_TIMAG00__A 0x1820011
+#define B_CE_REG_FR_TREAL01__A 0x1820012
+#define B_CE_REG_FR_TIMAG01__A 0x1820013
+#define B_CE_REG_FR_TREAL02__A 0x1820014
+#define B_CE_REG_FR_TIMAG02__A 0x1820015
+#define B_CE_REG_FR_TREAL03__A 0x1820016
+#define B_CE_REG_FR_TIMAG03__A 0x1820017
+#define B_CE_REG_FR_TREAL04__A 0x1820018
+#define B_CE_REG_FR_TIMAG04__A 0x1820019
+#define B_CE_REG_FR_TREAL05__A 0x182001A
+#define B_CE_REG_FR_TIMAG05__A 0x182001B
+#define B_CE_REG_FR_TREAL06__A 0x182001C
+#define B_CE_REG_FR_TIMAG06__A 0x182001D
+#define B_CE_REG_FR_TREAL07__A 0x182001E
+#define B_CE_REG_FR_TIMAG07__A 0x182001F
+#define B_CE_REG_FR_TREAL08__A 0x1820020
+#define B_CE_REG_FR_TIMAG08__A 0x1820021
+#define B_CE_REG_FR_TREAL09__A 0x1820022
+#define B_CE_REG_FR_TIMAG09__A 0x1820023
+#define B_CE_REG_FR_TREAL10__A 0x1820024
+#define B_CE_REG_FR_TIMAG10__A 0x1820025
+#define B_CE_REG_FR_TREAL11__A 0x1820026
+#define B_CE_REG_FR_TIMAG11__A 0x1820027
+#define B_CE_REG_FR_MID_TAP__A 0x1820028
+#define B_CE_REG_FR_SQS_G00__A 0x1820029
+#define B_CE_REG_FR_SQS_G01__A 0x182002A
+#define B_CE_REG_FR_SQS_G02__A 0x182002B
+#define B_CE_REG_FR_SQS_G03__A 0x182002C
+#define B_CE_REG_FR_SQS_G04__A 0x182002D
+#define B_CE_REG_FR_SQS_G05__A 0x182002E
+#define B_CE_REG_FR_SQS_G06__A 0x182002F
+#define B_CE_REG_FR_SQS_G07__A 0x1820030
+#define B_CE_REG_FR_SQS_G08__A 0x1820031
+#define B_CE_REG_FR_SQS_G09__A 0x1820032
+#define B_CE_REG_FR_SQS_G10__A 0x1820033
+#define B_CE_REG_FR_SQS_G11__A 0x1820034
+#define B_CE_REG_FR_SQS_G12__A 0x1820035
+#define B_CE_REG_FR_RIO_G00__A 0x1820036
+#define B_CE_REG_FR_RIO_G01__A 0x1820037
+#define B_CE_REG_FR_RIO_G02__A 0x1820038
+#define B_CE_REG_FR_RIO_G03__A 0x1820039
+#define B_CE_REG_FR_RIO_G04__A 0x182003A
+#define B_CE_REG_FR_RIO_G05__A 0x182003B
+#define B_CE_REG_FR_RIO_G06__A 0x182003C
+#define B_CE_REG_FR_RIO_G07__A 0x182003D
+#define B_CE_REG_FR_RIO_G08__A 0x182003E
+#define B_CE_REG_FR_RIO_G09__A 0x182003F
+#define B_CE_REG_FR_RIO_G10__A 0x1820040
+#define B_CE_REG_FR_MODE__A 0x1820041
+#define B_CE_REG_FR_SQS_TRH__A 0x1820042
+#define B_CE_REG_FR_RIO_GAIN__A 0x1820043
+#define B_CE_REG_FR_BYPASS__A 0x1820044
+#define B_CE_REG_FR_PM_SET__A 0x1820045
+#define B_CE_REG_FR_ERR_SH__A 0x1820046
+#define B_CE_REG_FR_MAN_SH__A 0x1820047
+#define B_CE_REG_FR_TAP_SH__A 0x1820048
+#define B_EQ_COMM_EXEC__A 0x1C00000
+#define B_EQ_REG_COMM_EXEC__A 0x1C10000
+#define B_EQ_REG_COMM_MB__A 0x1C10002
+#define B_EQ_REG_IS_GAIN_MAN__A 0x1C10015
+#define B_EQ_REG_IS_GAIN_EXP__A 0x1C10016
+#define B_EQ_REG_IS_CLIP_EXP__A 0x1C10017
+#define B_EQ_REG_SN_CEGAIN__A 0x1C1002A
+#define B_EQ_REG_SN_OFFSET__A 0x1C1002B
+#define B_EQ_REG_RC_SEL_CAR__A 0x1C10032
+#define B_EQ_REG_RC_SEL_CAR_INIT 0x2
+#define B_EQ_REG_RC_SEL_CAR_DIV_ON 0x1
+#define B_EQ_REG_RC_SEL_CAR_PASS_A_CC 0x0
+#define B_EQ_REG_RC_SEL_CAR_PASS_B_CE 0x2
+#define B_EQ_REG_RC_SEL_CAR_LOCAL_A_CC 0x0
+#define B_EQ_REG_RC_SEL_CAR_LOCAL_B_CE 0x8
+#define B_EQ_REG_RC_SEL_CAR_MEAS_A_CC 0x0
+#define B_EQ_REG_RC_SEL_CAR_MEAS_B_CE 0x20
+#define B_EQ_REG_RC_SEL_CAR_FFTMODE__M 0x80
+#define B_EQ_REG_OT_CONST__A 0x1C10046
+#define B_EQ_REG_OT_ALPHA__A 0x1C10047
+#define B_EQ_REG_OT_QNT_THRES0__A 0x1C10048
+#define B_EQ_REG_OT_QNT_THRES1__A 0x1C10049
+#define B_EQ_REG_OT_CSI_STEP__A 0x1C1004A
+#define B_EQ_REG_OT_CSI_OFFSET__A 0x1C1004B
+#define B_EQ_REG_TD_REQ_SMB_CNT__A 0x1C10061
+#define B_EQ_REG_TD_TPS_PWR_OFS__A 0x1C10062
+#define B_EC_SB_REG_COMM_EXEC__A 0x2010000
+#define B_EC_SB_REG_TR_MODE__A 0x2010010
+#define B_EC_SB_REG_TR_MODE_8K 0x0
+#define B_EC_SB_REG_TR_MODE_2K 0x1
+#define B_EC_SB_REG_CONST__A 0x2010011
+#define B_EC_SB_REG_CONST_QPSK 0x0
+#define B_EC_SB_REG_CONST_16QAM 0x1
+#define B_EC_SB_REG_CONST_64QAM 0x2
+#define B_EC_SB_REG_ALPHA__A 0x2010012
+#define B_EC_SB_REG_PRIOR__A 0x2010013
+#define B_EC_SB_REG_PRIOR_HI 0x0
+#define B_EC_SB_REG_PRIOR_LO 0x1
+#define B_EC_SB_REG_CSI_HI__A 0x2010014
+#define B_EC_SB_REG_CSI_LO__A 0x2010015
+#define B_EC_SB_REG_SMB_TGL__A 0x2010016
+#define B_EC_SB_REG_SNR_HI__A 0x2010017
+#define B_EC_SB_REG_SNR_MID__A 0x2010018
+#define B_EC_SB_REG_SNR_LO__A 0x2010019
+#define B_EC_SB_REG_SCALE_MSB__A 0x201001A
+#define B_EC_SB_REG_SCALE_BIT2__A 0x201001B
+#define B_EC_SB_REG_SCALE_LSB__A 0x201001C
+#define B_EC_SB_REG_CSI_OFS0__A 0x201001D
+#define B_EC_SB_REG_CSI_OFS1__A 0x201001E
+#define B_EC_SB_REG_CSI_OFS2__A 0x201001F
+#define B_EC_VD_REG_COMM_EXEC__A 0x2090000
+#define B_EC_VD_REG_FORCE__A 0x2090010
+#define B_EC_VD_REG_SET_CODERATE__A 0x2090011
+#define B_EC_VD_REG_SET_CODERATE_C1_2 0x0
+#define B_EC_VD_REG_SET_CODERATE_C2_3 0x1
+#define B_EC_VD_REG_SET_CODERATE_C3_4 0x2
+#define B_EC_VD_REG_SET_CODERATE_C5_6 0x3
+#define B_EC_VD_REG_SET_CODERATE_C7_8 0x4
+#define B_EC_VD_REG_REQ_SMB_CNT__A 0x2090012
+#define B_EC_VD_REG_RLK_ENA__A 0x2090014
+#define B_EC_OD_REG_COMM_EXEC__A 0x2110000
+#define B_EC_OD_REG_SYNC__A 0x2110664
+#define B_EC_OD_DEINT_RAM__A 0x2120000
+#define B_EC_RS_REG_COMM_EXEC__A 0x2130000
+#define B_EC_RS_REG_REQ_PCK_CNT__A 0x2130010
+#define B_EC_RS_REG_VAL__A 0x2130011
+#define B_EC_RS_REG_VAL_PCK 0x1
+#define B_EC_RS_EC_RAM__A 0x2140000
+#define B_EC_OC_REG_COMM_EXEC__A 0x2150000
+#define B_EC_OC_REG_COMM_EXEC_CTL_ACTIVE 0x1
+#define B_EC_OC_REG_COMM_EXEC_CTL_HOLD 0x2
+#define B_EC_OC_REG_COMM_INT_STA__A 0x2150007
+#define B_EC_OC_REG_OC_MODE_LOP__A 0x2150010
+#define B_EC_OC_REG_OC_MODE_LOP_PAR_ENA__M 0x1
+#define B_EC_OC_REG_OC_MODE_LOP_PAR_ENA_ENABLE 0x0
+#define B_EC_OC_REG_OC_MODE_LOP_PAR_ENA_DISABLE 0x1
+#define B_EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC__M 0x4
+#define B_EC_OC_REG_OC_MODE_LOP_DTO_CTR_SRC_STATIC 0x0
+#define B_EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE__M 0x80
+#define B_EC_OC_REG_OC_MODE_LOP_MPG_TRM_MDE_SERIAL 0x80
+#define B_EC_OC_REG_OC_MODE_HIP__A 0x2150011
+#define B_EC_OC_REG_OC_MODE_HIP_MPG_BUS_SRC_MONITOR 0x10
+#define B_EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL__M 0x200
+#define B_EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_DISABLE 0x0
+#define B_EC_OC_REG_OC_MODE_HIP_MPG_PAR_VAL_ENABLE 0x200
+#define B_EC_OC_REG_OC_MPG_SIO__A 0x2150012
+#define B_EC_OC_REG_OC_MPG_SIO__M 0xFFF
+#define B_EC_OC_REG_DTO_INC_LOP__A 0x2150014
+#define B_EC_OC_REG_DTO_INC_HIP__A 0x2150015
+#define B_EC_OC_REG_SNC_ISC_LVL__A 0x2150016
+#define B_EC_OC_REG_SNC_ISC_LVL_OSC__M 0xF0
+#define B_EC_OC_REG_TMD_TOP_MODE__A 0x215001D
+#define B_EC_OC_REG_TMD_TOP_CNT__A 0x215001E
+#define B_EC_OC_REG_TMD_HIL_MAR__A 0x215001F
+#define B_EC_OC_REG_TMD_LOL_MAR__A 0x2150020
+#define B_EC_OC_REG_TMD_CUR_CNT__A 0x2150021
+#define B_EC_OC_REG_AVR_ASH_CNT__A 0x2150023
+#define B_EC_OC_REG_AVR_BSH_CNT__A 0x2150024
+#define B_EC_OC_REG_RCN_MODE__A 0x2150027
+#define B_EC_OC_REG_RCN_CRA_LOP__A 0x2150028
+#define B_EC_OC_REG_RCN_CRA_HIP__A 0x2150029
+#define B_EC_OC_REG_RCN_CST_LOP__A 0x215002A
+#define B_EC_OC_REG_RCN_CST_HIP__A 0x215002B
+#define B_EC_OC_REG_RCN_SET_LVL__A 0x215002C
+#define B_EC_OC_REG_RCN_GAI_LVL__A 0x215002D
+#define B_EC_OC_REG_RCN_CLP_LOP__A 0x2150032
+#define B_EC_OC_REG_RCN_CLP_HIP__A 0x2150033
+#define B_EC_OC_REG_RCN_MAP_LOP__A 0x2150034
+#define B_EC_OC_REG_RCN_MAP_HIP__A 0x2150035
+#define B_EC_OC_REG_OCR_MPG_UOS__A 0x2150036
+#define B_EC_OC_REG_OCR_MPG_UOS__M 0xFFF
+#define B_EC_OC_REG_OCR_MPG_UOS_INIT 0x0
+#define B_EC_OC_REG_OCR_MPG_USR_DAT__A 0x2150038
+#define B_EC_OC_REG_IPR_INV_MPG__A 0x2150045
+#define B_EC_OC_REG_DTO_CLKMODE__A 0x2150047
+#define B_EC_OC_REG_DTO_PER__A 0x2150048
+#define B_EC_OC_REG_DTO_BUR__A 0x2150049
+#define B_EC_OC_REG_RCR_CLKMODE__A 0x215004A
+#define B_CC_REG_OSC_MODE__A 0x2410010
+#define B_CC_REG_OSC_MODE_M20 0x1
+#define B_CC_REG_PLL_MODE__A 0x2410011
+#define B_CC_REG_PLL_MODE_BYPASS_PLL 0x1
+#define B_CC_REG_PLL_MODE_PUMP_CUR_12 0x14
+#define B_CC_REG_REF_DIVIDE__A 0x2410012
+#define B_CC_REG_PWD_MODE__A 0x2410015
+#define B_CC_REG_PWD_MODE_DOWN_PLL 0x2
+#define B_CC_REG_UPDATE__A 0x2410017
+#define B_CC_REG_UPDATE_KEY 0x3973
+#define B_CC_REG_JTAGID_L__A 0x2410019
+#define B_CC_REG_DIVERSITY__A 0x241001B
+#define B_LC_COMM_EXEC__A 0x2800000
+#define B_LC_RA_RAM_IFINCR_NOM_L__A 0x282000C
+#define B_LC_RA_RAM_FILTER_SYM_SET__A 0x282001A
+#define B_LC_RA_RAM_FILTER_SYM_SET__PRE 0x3E8
+#define B_LC_RA_RAM_FILTER_CRMM_A__A 0x2820060
+#define B_LC_RA_RAM_FILTER_CRMM_A__PRE 0x4
+#define B_LC_RA_RAM_FILTER_CRMM_B__A 0x2820061
+#define B_LC_RA_RAM_FILTER_CRMM_B__PRE 0x1
+#define B_LC_RA_RAM_FILTER_SRMM_A__A 0x2820068
+#define B_LC_RA_RAM_FILTER_SRMM_A__PRE 0x4
+#define B_LC_RA_RAM_FILTER_SRMM_B__A 0x2820069
+#define B_LC_RA_RAM_FILTER_SRMM_B__PRE 0x1
+
+#endif
diff --git a/drivers/media/dvb/frontends/eds1547.h b/drivers/media/dvb/frontends/eds1547.h
index fa79b7c83dd2..c983f2f85802 100644
--- a/drivers/media/dvb/frontends/eds1547.h
+++ b/drivers/media/dvb/frontends/eds1547.h
@@ -61,7 +61,7 @@ static u8 stv0288_earda_inittab[] = {
0x3d, 0x30,
0x40, 0x63,
0x41, 0x04,
- 0x42, 0x60,
+ 0x42, 0x20,
0x43, 0x00,
0x44, 0x00,
0x45, 0x00,
diff --git a/drivers/media/dvb/frontends/ix2505v.c b/drivers/media/dvb/frontends/ix2505v.c
index 6c2e929bd79f..9a517a4bf96d 100644
--- a/drivers/media/dvb/frontends/ix2505v.c
+++ b/drivers/media/dvb/frontends/ix2505v.c
@@ -218,11 +218,13 @@ static int ix2505v_set_params(struct dvb_frontend *fe,
fe->ops.i2c_gate_ctrl(fe, 1);
len = sizeof(data);
-
ret |= ix2505v_write(state, data, len);
data[2] |= 0x4; /* set TM = 1 other bits same */
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
len = 1;
ret |= ix2505v_write(state, &data[2], len); /* write byte 4 only */
@@ -233,12 +235,12 @@ static int ix2505v_set_params(struct dvb_frontend *fe,
deb_info("Data 2=[%x%x]\n", data[2], data[3]);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
len = 2;
ret |= ix2505v_write(state, &data[2], len); /* write byte 4 & 5 */
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
-
if (state->config->min_delay_ms)
msleep(state->config->min_delay_ms);
diff --git a/drivers/media/dvb/frontends/stb0899_algo.c b/drivers/media/dvb/frontends/stb0899_algo.c
index 2da55ec20392..d70eee00f33a 100644
--- a/drivers/media/dvb/frontends/stb0899_algo.c
+++ b/drivers/media/dvb/frontends/stb0899_algo.c
@@ -23,7 +23,7 @@
#include "stb0899_priv.h"
#include "stb0899_reg.h"
-inline u32 stb0899_do_div(u64 n, u32 d)
+static inline u32 stb0899_do_div(u64 n, u32 d)
{
/* wrap do_div() for ease of use */
diff --git a/drivers/media/dvb/frontends/stv0288.c b/drivers/media/dvb/frontends/stv0288.c
index e3fe17fd96fb..8e0cfadba688 100644
--- a/drivers/media/dvb/frontends/stv0288.c
+++ b/drivers/media/dvb/frontends/stv0288.c
@@ -253,7 +253,7 @@ static u8 stv0288_inittab[] = {
0x3d, 0x30,
0x40, 0x63,
0x41, 0x04,
- 0x42, 0x60,
+ 0x42, 0x20,
0x43, 0x00,
0x44, 0x00,
0x45, 0x00,
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index 4e3db3a42e06..42684bec8883 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -64,6 +64,7 @@ struct stv0299_state {
fe_code_rate_t fec_inner;
int errmode;
u32 ucblocks;
+ u8 mcr_reg;
};
#define STATUS_BER 0
@@ -457,6 +458,9 @@ static int stv0299_init (struct dvb_frontend* fe)
dprintk("stv0299: init chip\n");
+ stv0299_writeregI(state, 0x02, 0x30 | state->mcr_reg);
+ msleep(50);
+
for (i = 0; ; i += 2) {
reg = state->config->inittab[i];
val = state->config->inittab[i+1];
@@ -464,6 +468,8 @@ static int stv0299_init (struct dvb_frontend* fe)
break;
if (reg == 0x0c && state->config->op0_off)
val &= ~0x10;
+ if (reg == 0x2)
+ state->mcr_reg = val & 0xf;
stv0299_writeregI(state, reg, val);
}
@@ -618,7 +624,7 @@ static int stv0299_sleep(struct dvb_frontend* fe)
{
struct stv0299_state* state = fe->demodulator_priv;
- stv0299_writeregI(state, 0x02, 0x80);
+ stv0299_writeregI(state, 0x02, 0xb0 | state->mcr_reg);
state->initialised = 0;
return 0;
@@ -680,7 +686,7 @@ struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
state->errmode = STATUS_BER;
/* check if the demod is there */
- stv0299_writeregI(state, 0x02, 0x34); /* standby off */
+ stv0299_writeregI(state, 0x02, 0x30); /* standby off */
msleep(200);
id = stv0299_readreg(state, 0x00);
diff --git a/drivers/media/dvb/frontends/tda8261.c b/drivers/media/dvb/frontends/tda8261.c
index 1742056a34e8..53c7d8f1df28 100644
--- a/drivers/media/dvb/frontends/tda8261.c
+++ b/drivers/media/dvb/frontends/tda8261.c
@@ -224,7 +224,6 @@ exit:
}
EXPORT_SYMBOL(tda8261_attach);
-MODULE_PARM_DESC(verbose, "Set verbosity level");
MODULE_AUTHOR("Manu Abraham");
MODULE_DESCRIPTION("TDA8261 8PSK/QPSK Tuner");
diff --git a/drivers/media/dvb/frontends/z0194a.h b/drivers/media/dvb/frontends/z0194a.h
index 07f3fc0998f6..96d86d6eb473 100644
--- a/drivers/media/dvb/frontends/z0194a.h
+++ b/drivers/media/dvb/frontends/z0194a.h
@@ -42,7 +42,7 @@ static int sharp_z0194a_set_symbol_rate(struct dvb_frontend *fe,
static u8 sharp_z0194a_inittab[] = {
0x01, 0x15,
- 0x02, 0x00,
+ 0x02, 0x30,
0x03, 0x00,
0x04, 0x7d, /* F22FR = 0x7d, F22 = f_VCO / 128 / 0x7d = 22 kHz */
0x05, 0x35, /* I2CT = 0, SCLT = 1, SDAT = 1 */
diff --git a/drivers/media/dvb/mantis/hopper_cards.c b/drivers/media/dvb/mantis/hopper_cards.c
index 70e73afefb3d..1402062f2c89 100644
--- a/drivers/media/dvb/mantis/hopper_cards.c
+++ b/drivers/media/dvb/mantis/hopper_cards.c
@@ -44,7 +44,7 @@
static unsigned int verbose;
module_param(verbose, int, 0644);
-MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
+MODULE_PARM_DESC(verbose, "verbose startup messages, default is 0 (no)");
#define DRIVER_NAME "Hopper"
diff --git a/drivers/media/dvb/mantis/mantis_cards.c b/drivers/media/dvb/mantis/mantis_cards.c
index 40da225098cc..05cbb9d95727 100644
--- a/drivers/media/dvb/mantis/mantis_cards.c
+++ b/drivers/media/dvb/mantis/mantis_cards.c
@@ -52,7 +52,7 @@
static unsigned int verbose;
module_param(verbose, int, 0644);
-MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
+MODULE_PARM_DESC(verbose, "verbose startup messages, default is 0 (no)");
static int devs;
diff --git a/drivers/media/dvb/mantis/mantis_pci.c b/drivers/media/dvb/mantis/mantis_pci.c
index 10a432a79d00..371558af2d96 100644
--- a/drivers/media/dvb/mantis/mantis_pci.c
+++ b/drivers/media/dvb/mantis/mantis_pci.c
@@ -48,7 +48,7 @@
int __devinit mantis_pci_init(struct mantis_pci *mantis)
{
- u8 revision, latency;
+ u8 latency;
struct mantis_hwconfig *config = mantis->hwconfig;
struct pci_dev *pdev = mantis->pdev;
int err, ret = 0;
@@ -95,9 +95,8 @@ int __devinit mantis_pci_init(struct mantis_pci *mantis)
}
pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency);
- pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
mantis->latency = latency;
- mantis->revision = revision;
+ mantis->revision = pdev->revision;
dprintk(MANTIS_ERROR, 0, " Mantis Rev %d [%04x:%04x], ",
mantis->revision,
diff --git a/drivers/media/dvb/mantis/mantis_vp1033.c b/drivers/media/dvb/mantis/mantis_vp1033.c
index deec927c7f7a..2ae0afa7756b 100644
--- a/drivers/media/dvb/mantis/mantis_vp1033.c
+++ b/drivers/media/dvb/mantis/mantis_vp1033.c
@@ -37,7 +37,7 @@
u8 lgtdqcs001f_inittab[] = {
0x01, 0x15,
- 0x02, 0x00,
+ 0x02, 0x30,
0x03, 0x00,
0x04, 0x2a,
0x05, 0x85,
diff --git a/drivers/media/dvb/pt1/pt1.c b/drivers/media/dvb/pt1/pt1.c
index 0486919c1d0f..b81df5fafe26 100644
--- a/drivers/media/dvb/pt1/pt1.c
+++ b/drivers/media/dvb/pt1/pt1.c
@@ -1090,6 +1090,7 @@ pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
i2c_adap->algo = &pt1_i2c_algo;
i2c_adap->algo_data = NULL;
i2c_adap->dev.parent = &pdev->dev;
+ strcpy(i2c_adap->name, DRIVER_NAME);
i2c_set_adapdata(i2c_adap, pt1);
ret = i2c_add_adapter(i2c_adap);
if (ret < 0)
@@ -1156,10 +1157,10 @@ err_pt1_disable_ram:
pt1->power = 0;
pt1->reset = 1;
pt1_update_power(pt1);
-err_pt1_cleanup_adapters:
- pt1_cleanup_adapters(pt1);
err_i2c_del_adapter:
i2c_del_adapter(i2c_adap);
+err_pt1_cleanup_adapters:
+ pt1_cleanup_adapters(pt1);
err_kfree:
pci_set_drvdata(pdev, NULL);
kfree(pt1);
diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c
index 0b8da57cf4c3..0c8164a2cc36 100644
--- a/drivers/media/dvb/siano/smsusb.c
+++ b/drivers/media/dvb/siano/smsusb.c
@@ -297,9 +297,8 @@ static void smsusb_term_device(struct usb_interface *intf)
if (dev->coredev)
smscore_unregister_device(dev->coredev);
- kfree(dev);
-
sms_info("device %p destroyed", dev);
+ kfree(dev);
}
usb_set_intfdata(intf, NULL);
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index 44afab2fdc2d..9d83ced69dd6 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -95,6 +95,8 @@ config DVB_BUDGET_CI
select DVB_STB0899 if !DVB_FE_CUSTOMISE
select DVB_STB6100 if !DVB_FE_CUSTOMISE
select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+ select DVB_STV0288 if !DVB_FE_CUSTOMISE
+ select DVB_STB6000 if !DVB_FE_CUSTOMISE
select DVB_TDA10023 if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE
depends on RC_CORE
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index 1d79ada864d6..926f299b5225 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -52,6 +52,7 @@
#include "bsru6.h"
#include "tda1002x.h"
#include "tda827x.h"
+#include "bsbe1-d01a.h"
#define MODULE_NAME "budget_ci"
@@ -224,6 +225,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
case 0x1017:
case 0x1019:
case 0x101a:
+ case 0x101b:
/* for the Technotrend 1500 bundled remote */
dev->map_name = RC_MAP_TT_1500;
break;
@@ -1388,6 +1390,23 @@ static void frontend_init(struct budget_ci *budget_ci)
}
break;
+ case 0x101b: /* TT S-1500B (BSBE1-D01A - STV0288/STB6000/LNBP21) */
+ budget_ci->budget.dvb_frontend = dvb_attach(stv0288_attach, &stv0288_bsbe1_d01a_config, &budget_ci->budget.i2c_adap);
+ if (budget_ci->budget.dvb_frontend) {
+ if (dvb_attach(stb6000_attach, budget_ci->budget.dvb_frontend, 0x63, &budget_ci->budget.i2c_adap)) {
+ if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) {
+ printk(KERN_ERR "%s: No LNBP21 found!\n", __func__);
+ dvb_frontend_detach(budget_ci->budget.dvb_frontend);
+ budget_ci->budget.dvb_frontend = NULL;
+ }
+ } else {
+ printk(KERN_ERR "%s: No STB6000 found!\n", __func__);
+ dvb_frontend_detach(budget_ci->budget.dvb_frontend);
+ budget_ci->budget.dvb_frontend = NULL;
+ }
+ }
+ break;
+
case 0x1019: // TT S2-3200 PCI
/*
* NOTE! on some STB0899 versions, the internal PLL takes a longer time
@@ -1518,6 +1537,7 @@ MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT);
MAKE_BUDGET_INFO(tt3200, "TT-Budget S2-3200 PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(ttbs1500b, "TT-Budget S-1500B PCI", BUDGET_TT);
static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
@@ -1528,6 +1548,7 @@ static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a),
MAKE_EXTENSION_PCI(tt3200, 0x13c2, 0x1019),
+ MAKE_EXTENSION_PCI(ttbs1500b, 0x13c2, 0x101b),
{
.vendor = 0,
}
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index cbe2f0de1442..420bb42d5233 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -52,7 +52,7 @@
my TTUSB, so let it undef'd unless you want to implement another
frontend. never tested.
- DEBUG:
+ debug:
define it to > 3 for really hardcore debugging. you probably don't want
this unless the device doesn't load at all. > 2 for bandwidth statistics.
*/
@@ -134,20 +134,19 @@ struct ttusb {
/* ugly workaround ... don't know why it's necessary to read */
/* all result codes. */
-#define DEBUG 0
static int ttusb_cmd(struct ttusb *ttusb,
const u8 * data, int len, int needresult)
{
int actual_len;
int err;
-#if DEBUG >= 3
int i;
- printk(">");
- for (i = 0; i < len; ++i)
- printk(" %02x", data[i]);
- printk("\n");
-#endif
+ if (debug >= 3) {
+ printk(KERN_DEBUG ">");
+ for (i = 0; i < len; ++i)
+ printk(KERN_CONT " %02x", data[i]);
+ printk(KERN_CONT "\n");
+ }
if (mutex_lock_interruptible(&ttusb->semusb) < 0)
return -EAGAIN;
@@ -176,13 +175,15 @@ static int ttusb_cmd(struct ttusb *ttusb,
mutex_unlock(&ttusb->semusb);
return err;
}
-#if DEBUG >= 3
- actual_len = ttusb->last_result[3] + 4;
- printk("<");
- for (i = 0; i < actual_len; ++i)
- printk(" %02x", ttusb->last_result[i]);
- printk("\n");
-#endif
+
+ if (debug >= 3) {
+ actual_len = ttusb->last_result[3] + 4;
+ printk(KERN_DEBUG "<");
+ for (i = 0; i < actual_len; ++i)
+ printk(KERN_CONT " %02x", ttusb->last_result[i]);
+ printk(KERN_CONT "\n");
+ }
+
if (!needresult)
mutex_unlock(&ttusb->semusb);
return 0;
@@ -636,16 +637,13 @@ static void ttusb_process_frame(struct ttusb *ttusb, u8 * data, int len)
++ttusb->mux_state;
else {
ttusb->mux_state = 0;
-#if DEBUG > 3
- if (ttusb->insync)
- printk("%02x ", data[-1]);
-#else
if (ttusb->insync) {
- printk("%s: lost sync.\n",
+ dprintk("%s: %02x\n",
+ __func__, data[-1]);
+ printk(KERN_INFO "%s: lost sync.\n",
__func__);
ttusb->insync = 0;
}
-#endif
}
break;
case 3:
@@ -744,6 +742,9 @@ static void ttusb_process_frame(struct ttusb *ttusb, u8 * data, int len)
static void ttusb_iso_irq(struct urb *urb)
{
struct ttusb *ttusb = urb->context;
+ struct usb_iso_packet_descriptor *d;
+ u8 *data;
+ int len, i;
if (!ttusb->iso_streaming)
return;
@@ -755,21 +756,14 @@ static void ttusb_iso_irq(struct urb *urb)
#endif
if (!urb->status) {
- int i;
for (i = 0; i < urb->number_of_packets; ++i) {
- struct usb_iso_packet_descriptor *d;
- u8 *data;
- int len;
numpkt++;
if (time_after_eq(jiffies, lastj + HZ)) {
-#if DEBUG > 2
- printk
- ("frames/s: %d (ts: %d, stuff %d, sec: %d, invalid: %d, all: %d)\n",
- numpkt * HZ / (jiffies - lastj),
- numts, numstuff, numsec, numinvalid,
- numts + numstuff + numsec +
- numinvalid);
-#endif
+ dprintk("frames/s: %lu (ts: %d, stuff %d, "
+ "sec: %d, invalid: %d, all: %d)\n",
+ numpkt * HZ / (jiffies - lastj),
+ numts, numstuff, numsec, numinvalid,
+ numts + numstuff + numsec + numinvalid);
numts = numstuff = numsec = numinvalid = 0;
lastj = jiffies;
numpkt = 0;
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 299994c3aa74..e4c97fd6f05a 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -166,21 +166,6 @@ config RADIO_MAXIRADIO
To compile this driver as a module, choose M here: the
module will be called radio-maxiradio.
-config RADIO_MAESTRO
- tristate "Maestro on board radio"
- depends on VIDEO_V4L2 && PCI
- ---help---
- Say Y here to directly support the on-board radio tuner on the
- Maestro 2 or 2E sound card.
-
- In order to control your radio card, you will need to use programs
- that are compatible with the Video For Linux API. Information on
- this API and pointers to "v4l" programs may be found at
- <file:Documentation/video4linux/API.html>.
-
- To compile this driver as a module, choose M here: the
- module will be called radio-maestro.
-
config RADIO_MIROPCM20
tristate "miroSOUND PCM20 radio"
depends on ISA && VIDEO_V4L2 && SND
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index 2faa33371986..f484a6e04eb2 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -16,7 +16,6 @@ obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o
obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o
-obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o
obj-$(CONFIG_USB_DSBR) += dsbr100.o
obj-$(CONFIG_RADIO_SI470X) += si470x/
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
deleted file mode 100644
index 6af61bfeb178..000000000000
--- a/drivers/media/radio/radio-maestro.c
+++ /dev/null
@@ -1,452 +0,0 @@
-/* Maestro PCI sound card radio driver for Linux support
- * (c) 2000 A. Tlalka, atlka@pg.gda.pl
- * Notes on the hardware
- *
- * + Frequency control is done digitally
- * + No volume control - only mute/unmute - you have to use Aux line volume
- * control on Maestro card to set the volume
- * + Radio status (tuned/not_tuned and stereo/mono) is valid some time after
- * frequency setting (>100ms) and only when the radio is unmuted.
- * version 0.02
- * + io port is automatically detected - only the first radio is used
- * version 0.03
- * + thread access locking additions
- * version 0.04
- * + code improvements
- * + VIDEO_TUNER_LOW is permanent
- *
- * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/version.h> /* for KERNEL_VERSION MACRO */
-#include <linux/pci.h>
-#include <linux/videodev2.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-
-MODULE_AUTHOR("Adam Tlalka, atlka@pg.gda.pl");
-MODULE_DESCRIPTION("Radio driver for the Maestro PCI sound card radio.");
-MODULE_LICENSE("GPL");
-
-static int radio_nr = -1;
-module_param(radio_nr, int, 0);
-
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 6)
-#define DRIVER_VERSION "0.06"
-
-#define GPIO_DATA 0x60 /* port offset from ESS_IO_BASE */
-
-#define IO_MASK 4 /* mask register offset from GPIO_DATA
- bits 1=unmask write to given bit */
-#define IO_DIR 8 /* direction register offset from GPIO_DATA
- bits 0/1=read/write direction */
-
-#define GPIO6 0x0040 /* mask bits for GPIO lines */
-#define GPIO7 0x0080
-#define GPIO8 0x0100
-#define GPIO9 0x0200
-
-#define STR_DATA GPIO6 /* radio TEA5757 pins and GPIO bits */
-#define STR_CLK GPIO7
-#define STR_WREN GPIO8
-#define STR_MOST GPIO9
-
-#define FREQ_LO 50*16000
-#define FREQ_HI 150*16000
-
-#define FREQ_IF 171200 /* 10.7*16000 */
-#define FREQ_STEP 200 /* 12.5*16 */
-
-#define FREQ2BITS(x) ((((unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1))\
- /(FREQ_STEP<<2))<<2) /* (x==fmhz*16*1000) -> bits */
-
-#define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF)
-
-struct maestro {
- struct v4l2_device v4l2_dev;
- struct video_device vdev;
- struct pci_dev *pdev;
- struct mutex lock;
-
- u16 io; /* base of Maestro card radio io (GPIO_DATA)*/
- u16 muted; /* VIDEO_AUDIO_MUTE */
- u16 stereo; /* VIDEO_TUNER_STEREO_ON */
- u16 tuned; /* signal strength (0 or 0xffff) */
-};
-
-static inline struct maestro *to_maestro(struct v4l2_device *v4l2_dev)
-{
- return container_of(v4l2_dev, struct maestro, v4l2_dev);
-}
-
-static u32 radio_bits_get(struct maestro *dev)
-{
- u16 io = dev->io, l, rdata;
- u32 data = 0;
- u16 omask;
-
- omask = inw(io + IO_MASK);
- outw(~(STR_CLK | STR_WREN), io + IO_MASK);
- outw(0, io);
- udelay(16);
-
- for (l = 24; l--;) {
- outw(STR_CLK, io); /* HI state */
- udelay(2);
- if (!l)
- dev->tuned = inw(io) & STR_MOST ? 0 : 0xffff;
- outw(0, io); /* LO state */
- udelay(2);
- data <<= 1; /* shift data */
- rdata = inw(io);
- if (!l)
- dev->stereo = (rdata & STR_MOST) ? 0 : 1;
- else if (rdata & STR_DATA)
- data++;
- udelay(2);
- }
-
- if (dev->muted)
- outw(STR_WREN, io);
-
- udelay(4);
- outw(omask, io + IO_MASK);
-
- return data & 0x3ffe;
-}
-
-static void radio_bits_set(struct maestro *dev, u32 data)
-{
- u16 io = dev->io, l, bits;
- u16 omask, odir;
-
- omask = inw(io + IO_MASK);
- odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN);
- outw(odir | STR_DATA, io + IO_DIR);
- outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK);
- udelay(16);
- for (l = 25; l; l--) {
- bits = ((data >> 18) & STR_DATA) | STR_WREN;
- data <<= 1; /* shift data */
- outw(bits, io); /* start strobe */
- udelay(2);
- outw(bits | STR_CLK, io); /* HI level */
- udelay(2);
- outw(bits, io); /* LO level */
- udelay(4);
- }
-
- if (!dev->muted)
- outw(0, io);
-
- udelay(4);
- outw(omask, io + IO_MASK);
- outw(odir, io + IO_DIR);
- msleep(125);
-}
-
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *v)
-{
- struct maestro *dev = video_drvdata(file);
-
- strlcpy(v->driver, "radio-maestro", sizeof(v->driver));
- strlcpy(v->card, "Maestro Radio", sizeof(v->card));
- snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(dev->pdev));
- v->version = RADIO_VERSION;
- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
- return 0;
-}
-
-static int vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
-{
- struct maestro *dev = video_drvdata(file);
-
- if (v->index > 0)
- return -EINVAL;
-
- mutex_lock(&dev->lock);
- radio_bits_get(dev);
-
- strlcpy(v->name, "FM", sizeof(v->name));
- v->type = V4L2_TUNER_RADIO;
- v->rangelow = FREQ_LO;
- v->rangehigh = FREQ_HI;
- v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
- v->capability = V4L2_TUNER_CAP_LOW;
- if (dev->stereo)
- v->audmode = V4L2_TUNER_MODE_STEREO;
- else
- v->audmode = V4L2_TUNER_MODE_MONO;
- v->signal = dev->tuned;
- mutex_unlock(&dev->lock);
- return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
-{
- return v->index ? -EINVAL : 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct maestro *dev = video_drvdata(file);
-
- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
- return -EINVAL;
- if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
- return -EINVAL;
- mutex_lock(&dev->lock);
- radio_bits_set(dev, FREQ2BITS(f->frequency));
- mutex_unlock(&dev->lock);
- return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct maestro *dev = video_drvdata(file);
-
- if (f->tuner != 0)
- return -EINVAL;
- f->type = V4L2_TUNER_RADIO;
- mutex_lock(&dev->lock);
- f->frequency = BITS2FREQ(radio_bits_get(dev));
- mutex_unlock(&dev->lock);
- return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- switch (qc->id) {
- case V4L2_CID_AUDIO_MUTE:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
- }
- return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct maestro *dev = video_drvdata(file);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- ctrl->value = dev->muted;
- return 0;
- }
- return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct maestro *dev = video_drvdata(file);
- u16 io = dev->io;
- u16 omask;
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- mutex_lock(&dev->lock);
- omask = inw(io + IO_MASK);
- outw(~STR_WREN, io + IO_MASK);
- dev->muted = ctrl->value;
- outw(dev->muted ? STR_WREN : 0, io);
- udelay(4);
- outw(omask, io + IO_MASK);
- msleep(125);
- mutex_unlock(&dev->lock);
- return 0;
- }
- return -EINVAL;
-}
-
-static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
-{
- *i = 0;
- return 0;
-}
-
-static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
-{
- return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- a->index = 0;
- strlcpy(a->name, "Radio", sizeof(a->name));
- a->capability = V4L2_AUDCAP_STEREO;
- return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- return a->index ? -EINVAL : 0;
-}
-
-static const struct v4l2_file_operations maestro_fops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops maestro_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
-};
-
-static u16 __devinit radio_power_on(struct maestro *dev)
-{
- register u16 io = dev->io;
- register u32 ofreq;
- u16 omask, odir;
-
- omask = inw(io + IO_MASK);
- odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN);
- outw(odir & ~STR_WREN, io + IO_DIR);
- dev->muted = inw(io) & STR_WREN ? 0 : 1;
- outw(odir, io + IO_DIR);
- outw(~(STR_WREN | STR_CLK), io + IO_MASK);
- outw(dev->muted ? 0 : STR_WREN, io);
- udelay(16);
- outw(omask, io + IO_MASK);
- ofreq = radio_bits_get(dev);
-
- if ((ofreq < FREQ2BITS(FREQ_LO)) || (ofreq > FREQ2BITS(FREQ_HI)))
- ofreq = FREQ2BITS(FREQ_LO);
- radio_bits_set(dev, ofreq);
-
- return (ofreq == radio_bits_get(dev));
-}
-
-static int __devinit maestro_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- struct maestro *dev;
- struct v4l2_device *v4l2_dev;
- int retval;
-
- retval = pci_enable_device(pdev);
- if (retval) {
- dev_err(&pdev->dev, "enabling pci device failed!\n");
- goto err;
- }
-
- retval = -ENOMEM;
-
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (dev == NULL) {
- dev_err(&pdev->dev, "not enough memory\n");
- goto err;
- }
-
- v4l2_dev = &dev->v4l2_dev;
- mutex_init(&dev->lock);
- dev->pdev = pdev;
-
- strlcpy(v4l2_dev->name, "maestro", sizeof(v4l2_dev->name));
-
- retval = v4l2_device_register(&pdev->dev, v4l2_dev);
- if (retval < 0) {
- v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
- goto errfr;
- }
-
- dev->io = pci_resource_start(pdev, 0) + GPIO_DATA;
-
- strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
- dev->vdev.v4l2_dev = v4l2_dev;
- dev->vdev.fops = &maestro_fops;
- dev->vdev.ioctl_ops = &maestro_ioctl_ops;
- dev->vdev.release = video_device_release_empty;
- video_set_drvdata(&dev->vdev, dev);
-
- if (!radio_power_on(dev)) {
- retval = -EIO;
- goto errfr1;
- }
-
- retval = video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr);
- if (retval) {
- v4l2_err(v4l2_dev, "can't register video device!\n");
- goto errfr1;
- }
-
- v4l2_info(v4l2_dev, "version " DRIVER_VERSION "\n");
-
- return 0;
-errfr1:
- v4l2_device_unregister(v4l2_dev);
-errfr:
- kfree(dev);
-err:
- return retval;
-
-}
-
-static void __devexit maestro_remove(struct pci_dev *pdev)
-{
- struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
- struct maestro *dev = to_maestro(v4l2_dev);
-
- video_unregister_device(&dev->vdev);
- v4l2_device_unregister(&dev->v4l2_dev);
-}
-
-static struct pci_device_id maestro_r_pci_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ESS1968),
- .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
- .class_mask = 0xffff00 },
- { PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ESS1978),
- .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8,
- .class_mask = 0xffff00 },
- { 0 }
-};
-MODULE_DEVICE_TABLE(pci, maestro_r_pci_tbl);
-
-static struct pci_driver maestro_r_driver = {
- .name = "maestro_radio",
- .id_table = maestro_r_pci_tbl,
- .probe = maestro_probe,
- .remove = __devexit_p(maestro_remove),
-};
-
-static int __init maestro_radio_init(void)
-{
- int retval = pci_register_driver(&maestro_r_driver);
-
- if (retval)
- printk(KERN_ERR "error during registration pci driver\n");
-
- return retval;
-}
-
-static void __exit maestro_radio_exit(void)
-{
- pci_unregister_driver(&maestro_r_driver);
-}
-
-module_init(maestro_radio_init);
-module_exit(maestro_radio_exit);
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index 5c2a9058c09f..e83e84003025 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -412,8 +412,7 @@ static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_d
goto err_out_free_region;
}
- v4l2_info(v4l2_dev, "version " DRIVER_VERSION
- " time " __TIME__ " " __DATE__ "\n");
+ v4l2_info(v4l2_dev, "version " DRIVER_VERSION "\n");
v4l2_info(v4l2_dev, "found Guillemot MAXI Radio device (io = 0x%x)\n",
dev->io);
diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c
index 1e3a8dd820a4..a185610b376b 100644
--- a/drivers/media/radio/radio-timb.c
+++ b/drivers/media/radio/radio-timb.c
@@ -21,7 +21,6 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
#include <linux/platform_device.h>
-#include <linux/mfd/core.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/i2c.h>
@@ -149,7 +148,7 @@ static const struct v4l2_file_operations timbradio_fops = {
static int __devinit timbradio_probe(struct platform_device *pdev)
{
- struct timb_radio_platform_data *pdata = mfd_get_data(pdev);
+ struct timb_radio_platform_data *pdata = pdev->dev.platform_data;
struct timbradio *tr;
int err;
diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c
index e2550dc2944f..459f7272d326 100644
--- a/drivers/media/radio/radio-wl1273.c
+++ b/drivers/media/radio/radio-wl1273.c
@@ -1382,7 +1382,7 @@ static int wl1273_fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
- ctrl->val = wl1273_fm_get_tx_ctune(radio);
+ ctrl->cur.val = wl1273_fm_get_tx_ctune(radio);
break;
default:
@@ -1990,7 +1990,7 @@ static int wl1273_fm_radio_remove(struct platform_device *pdev)
static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev)
{
- struct wl1273_core **core = mfd_get_data(pdev);
+ struct wl1273_core **core = pdev->dev.platform_data;
struct wl1273_device *radio;
struct v4l2_ctrl *ctrl;
int r = 0;
diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c
index 38ae6cd65790..0e740c98786c 100644
--- a/drivers/media/radio/si470x/radio-si470x-common.c
+++ b/drivers/media/radio/si470x/radio-si470x-common.c
@@ -174,15 +174,27 @@ static int si470x_set_chan(struct si470x_device *radio, unsigned short chan)
if (retval < 0)
goto done;
- /* wait till tune operation has completed */
- timeout = jiffies + msecs_to_jiffies(tune_timeout);
- do {
- retval = si470x_get_register(radio, STATUSRSSI);
- if (retval < 0)
- goto stop;
- timed_out = time_after(jiffies, timeout);
- } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) &&
- (!timed_out));
+ /* currently I2C driver only uses interrupt way to tune */
+ if (radio->stci_enabled) {
+ INIT_COMPLETION(radio->completion);
+
+ /* wait till tune operation has completed */
+ retval = wait_for_completion_timeout(&radio->completion,
+ msecs_to_jiffies(tune_timeout));
+ if (!retval)
+ timed_out = true;
+ } else {
+ /* wait till tune operation has completed */
+ timeout = jiffies + msecs_to_jiffies(tune_timeout);
+ do {
+ retval = si470x_get_register(radio, STATUSRSSI);
+ if (retval < 0)
+ goto stop;
+ timed_out = time_after(jiffies, timeout);
+ } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
+ && (!timed_out));
+ }
+
if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
dev_warn(&radio->videodev->dev, "tune does not complete\n");
if (timed_out)
@@ -310,15 +322,27 @@ static int si470x_set_seek(struct si470x_device *radio,
if (retval < 0)
goto done;
- /* wait till seek operation has completed */
- timeout = jiffies + msecs_to_jiffies(seek_timeout);
- do {
- retval = si470x_get_register(radio, STATUSRSSI);
- if (retval < 0)
- goto stop;
- timed_out = time_after(jiffies, timeout);
- } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) &&
- (!timed_out));
+ /* currently I2C driver only uses interrupt way to seek */
+ if (radio->stci_enabled) {
+ INIT_COMPLETION(radio->completion);
+
+ /* wait till seek operation has completed */
+ retval = wait_for_completion_timeout(&radio->completion,
+ msecs_to_jiffies(seek_timeout));
+ if (!retval)
+ timed_out = true;
+ } else {
+ /* wait till seek operation has completed */
+ timeout = jiffies + msecs_to_jiffies(seek_timeout);
+ do {
+ retval = si470x_get_register(radio, STATUSRSSI);
+ if (retval < 0)
+ goto stop;
+ timed_out = time_after(jiffies, timeout);
+ } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
+ && (!timed_out));
+ }
+
if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0)
dev_warn(&radio->videodev->dev, "seek does not complete\n");
if (radio->registers[STATUSRSSI] & STATUSRSSI_SF)
diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c
index 4ce541a5eb47..a2a67772c42c 100644
--- a/drivers/media/radio/si470x/radio-si470x-i2c.c
+++ b/drivers/media/radio/si470x/radio-si470x-i2c.c
@@ -197,8 +197,9 @@ int si470x_fops_open(struct file *file)
if (retval < 0)
goto done;
- /* enable RDS interrupt */
+ /* enable RDS / STC interrupt */
radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDSIEN;
+ radio->registers[SYSCONFIG1] |= SYSCONFIG1_STCIEN;
radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_GPIO2;
radio->registers[SYSCONFIG1] |= 0x1 << 2;
retval = si470x_set_register(radio, SYSCONFIG1);
@@ -261,12 +262,11 @@ int si470x_vidioc_querycap(struct file *file, void *priv,
**************************************************************************/
/*
- * si470x_i2c_interrupt_work - rds processing function
+ * si470x_i2c_interrupt - interrupt handler
*/
-static void si470x_i2c_interrupt_work(struct work_struct *work)
+static irqreturn_t si470x_i2c_interrupt(int irq, void *dev_id)
{
- struct si470x_device *radio = container_of(work,
- struct si470x_device, radio_work);
+ struct si470x_device *radio = dev_id;
unsigned char regnr;
unsigned char blocknum;
unsigned short bler; /* rds block errors */
@@ -274,21 +274,29 @@ static void si470x_i2c_interrupt_work(struct work_struct *work)
unsigned char tmpbuf[3];
int retval = 0;
+ /* check Seek/Tune Complete */
+ retval = si470x_get_register(radio, STATUSRSSI);
+ if (retval < 0)
+ goto end;
+
+ if (radio->registers[STATUSRSSI] & STATUSRSSI_STC)
+ complete(&radio->completion);
+
/* safety checks */
if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
- return;
+ goto end;
/* Update RDS registers */
- for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) {
+ for (regnr = 1; regnr < RDS_REGISTER_NUM; regnr++) {
retval = si470x_get_register(radio, STATUSRSSI + regnr);
if (retval < 0)
- return;
+ goto end;
}
/* get rds blocks */
if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0)
/* No RDS group ready, better luck next time */
- return;
+ goto end;
for (blocknum = 0; blocknum < 4; blocknum++) {
switch (blocknum) {
@@ -342,19 +350,8 @@ static void si470x_i2c_interrupt_work(struct work_struct *work)
if (radio->wr_index != radio->rd_index)
wake_up_interruptible(&radio->read_queue);
-}
-
-
-/*
- * si470x_i2c_interrupt - interrupt handler
- */
-static irqreturn_t si470x_i2c_interrupt(int irq, void *dev_id)
-{
- struct si470x_device *radio = dev_id;
-
- if (!work_pending(&radio->radio_work))
- schedule_work(&radio->radio_work);
+end:
return IRQ_HANDLED;
}
@@ -376,7 +373,6 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client,
goto err_initial;
}
- INIT_WORK(&radio->radio_work, si470x_i2c_interrupt_work);
radio->users = 0;
radio->client = client;
mutex_init(&radio->lock);
@@ -441,7 +437,11 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client,
radio->rd_index = 0;
init_waitqueue_head(&radio->read_queue);
- retval = request_irq(client->irq, si470x_i2c_interrupt,
+ /* mark Seek/Tune Complete Interrupt enabled */
+ radio->stci_enabled = true;
+ init_completion(&radio->completion);
+
+ retval = request_threaded_irq(client->irq, NULL, si470x_i2c_interrupt,
IRQF_TRIGGER_FALLING, DRIVER_NAME, radio);
if (retval) {
dev_err(&client->dev, "Failed to register interrupt\n");
@@ -479,7 +479,6 @@ static __devexit int si470x_i2c_remove(struct i2c_client *client)
struct si470x_device *radio = i2c_get_clientdata(client);
free_irq(client->irq, radio);
- cancel_work_sync(&radio->radio_work);
video_unregister_device(radio->videodev);
kfree(radio);
@@ -491,8 +490,9 @@ static __devexit int si470x_i2c_remove(struct i2c_client *client)
/*
* si470x_i2c_suspend - suspend the device
*/
-static int si470x_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
+static int si470x_i2c_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct si470x_device *radio = i2c_get_clientdata(client);
/* power down */
@@ -507,8 +507,9 @@ static int si470x_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
/*
* si470x_i2c_resume - resume the device
*/
-static int si470x_i2c_resume(struct i2c_client *client)
+static int si470x_i2c_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct si470x_device *radio = i2c_get_clientdata(client);
/* power up : need 110ms */
@@ -519,9 +520,8 @@ static int si470x_i2c_resume(struct i2c_client *client)
return 0;
}
-#else
-#define si470x_i2c_suspend NULL
-#define si470x_i2c_resume NULL
+
+static SIMPLE_DEV_PM_OPS(si470x_i2c_pm, si470x_i2c_suspend, si470x_i2c_resume);
#endif
@@ -532,11 +532,12 @@ static struct i2c_driver si470x_i2c_driver = {
.driver = {
.name = "si470x",
.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &si470x_i2c_pm,
+#endif
},
.probe = si470x_i2c_probe,
.remove = __devexit_p(si470x_i2c_remove),
- .suspend = si470x_i2c_suspend,
- .resume = si470x_i2c_resume,
.id_table = si470x_i2c_id,
};
diff --git a/drivers/media/radio/si470x/radio-si470x.h b/drivers/media/radio/si470x/radio-si470x.h
index 4a4e908db04c..68da001b09dc 100644
--- a/drivers/media/radio/si470x/radio-si470x.h
+++ b/drivers/media/radio/si470x/radio-si470x.h
@@ -158,6 +158,9 @@ struct si470x_device {
unsigned int rd_index;
unsigned int wr_index;
+ struct completion completion;
+ bool stci_enabled; /* Seek/Tune Complete Interrupt */
+
#if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE)
/* reference to USB and video device */
struct usb_device *usbdev;
@@ -179,7 +182,6 @@ struct si470x_device {
#if defined(CONFIG_I2C_SI470X) || defined(CONFIG_I2C_SI470X_MODULE)
struct i2c_client *client;
- struct work_struct radio_work;
#endif
};
diff --git a/drivers/media/radio/wl128x/fmdrv.h b/drivers/media/radio/wl128x/fmdrv.h
index 5db6fd14cf3c..1a45a5d847b0 100644
--- a/drivers/media/radio/wl128x/fmdrv.h
+++ b/drivers/media/radio/wl128x/fmdrv.h
@@ -55,8 +55,6 @@
#define FM_DRV_TX_TIMEOUT (5*HZ) /* 5 seconds */
#define FM_DRV_RX_SEEK_TIMEOUT (20*HZ) /* 20 seconds */
-#define NO_OF_ENTRIES_IN_ARRAY(array) (sizeof(array) / sizeof(array[0]))
-
#define fmerr(format, ...) \
printk(KERN_ERR "fmdrv: " format, ## __VA_ARGS__)
#define fmwarn(format, ...) \
diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c
index d50e5ac75ab6..87010724f914 100644
--- a/drivers/media/radio/wl128x/fmdrv_v4l2.c
+++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c
@@ -191,7 +191,7 @@ static int fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
- ctrl->val = fm_tx_get_tune_cap_val(fmdev);
+ ctrl->cur.val = fm_tx_get_tune_cap_val(fmdev);
break;
default:
fmwarn("%s: Unknown IOCTL: %d\n", __func__, ctrl->id);
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 7f03142a329f..7d4bbc226d06 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -148,6 +148,18 @@ config IR_ITE_CIR
To compile this driver as a module, choose M here: the
module will be called ite-cir.
+config IR_FINTEK
+ tristate "Fintek Consumer Infrared Transceiver"
+ depends on PNP
+ depends on RC_CORE
+ ---help---
+ Say Y here to enable support for integrated infrared receiver
+ /transciever made by Fintek. This chip is found on assorted
+ Jetway motherboards (and of course, possibly others).
+
+ To compile this driver as a module, choose M here: the
+ module will be called fintek-cir.
+
config IR_NUVOTON
tristate "Nuvoton w836x7hg Consumer Infrared Transceiver"
depends on PNP
@@ -161,6 +173,17 @@ config IR_NUVOTON
To compile this driver as a module, choose M here: the
module will be called nuvoton-cir.
+config IR_REDRAT3
+ tristate "RedRat3 IR Transceiver"
+ depends on USB_ARCH_HAS_HCD
+ depends on RC_CORE
+ select USB
+ ---help---
+ Say Y here if you want to use a RedRat3 Infrared Transceiver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called redrat3.
+
config IR_STREAMZAP
tristate "Streamzap PC Remote IR Receiver"
depends on USB_ARCH_HAS_HCD
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index c6cfe70d862f..52830e5f4eaa 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -16,8 +16,10 @@ obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
obj-$(CONFIG_IR_IMON) += imon.o
obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o
obj-$(CONFIG_IR_MCEUSB) += mceusb.o
+obj-$(CONFIG_IR_FINTEK) += fintek-cir.o
obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o
obj-$(CONFIG_IR_ENE) += ene_ir.o
+obj-$(CONFIG_IR_REDRAT3) += redrat3.o
obj-$(CONFIG_IR_STREAMZAP) += streamzap.o
obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o
obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
new file mode 100644
index 000000000000..8fa539dde1b4
--- /dev/null
+++ b/drivers/media/rc/fintek-cir.c
@@ -0,0 +1,684 @@
+/*
+ * Driver for Feature Integration Technology Inc. (aka Fintek) LPC CIR
+ *
+ * Copyright (C) 2011 Jarod Wilson <jarod@redhat.com>
+ *
+ * Special thanks to Fintek for providing hardware and spec sheets.
+ * This driver is based upon the nuvoton, ite and ene drivers for
+ * similar hardware.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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 <linux/slab.h>
+#include <media/rc-core.h>
+#include <linux/pci_ids.h>
+
+#include "fintek-cir.h"
+
+/* write val to config reg */
+static inline void fintek_cr_write(struct fintek_dev *fintek, u8 val, u8 reg)
+{
+ fit_dbg("%s: reg 0x%02x, val 0x%02x (ip/dp: %02x/%02x)",
+ __func__, reg, val, fintek->cr_ip, fintek->cr_dp);
+ outb(reg, fintek->cr_ip);
+ outb(val, fintek->cr_dp);
+}
+
+/* read val from config reg */
+static inline u8 fintek_cr_read(struct fintek_dev *fintek, u8 reg)
+{
+ u8 val;
+
+ outb(reg, fintek->cr_ip);
+ val = inb(fintek->cr_dp);
+
+ fit_dbg("%s: reg 0x%02x, val 0x%02x (ip/dp: %02x/%02x)",
+ __func__, reg, val, fintek->cr_ip, fintek->cr_dp);
+ return val;
+}
+
+/* update config register bit without changing other bits */
+static inline void fintek_set_reg_bit(struct fintek_dev *fintek, u8 val, u8 reg)
+{
+ u8 tmp = fintek_cr_read(fintek, reg) | val;
+ fintek_cr_write(fintek, tmp, reg);
+}
+
+/* clear config register bit without changing other bits */
+static inline void fintek_clear_reg_bit(struct fintek_dev *fintek, u8 val, u8 reg)
+{
+ u8 tmp = fintek_cr_read(fintek, reg) & ~val;
+ fintek_cr_write(fintek, tmp, reg);
+}
+
+/* enter config mode */
+static inline void fintek_config_mode_enable(struct fintek_dev *fintek)
+{
+ /* Enabling Config Mode explicitly requires writing 2x */
+ outb(CONFIG_REG_ENABLE, fintek->cr_ip);
+ outb(CONFIG_REG_ENABLE, fintek->cr_ip);
+}
+
+/* exit config mode */
+static inline void fintek_config_mode_disable(struct fintek_dev *fintek)
+{
+ outb(CONFIG_REG_DISABLE, fintek->cr_ip);
+}
+
+/*
+ * When you want to address a specific logical device, write its logical
+ * device number to GCR_LOGICAL_DEV_NO
+ */
+static inline void fintek_select_logical_dev(struct fintek_dev *fintek, u8 ldev)
+{
+ fintek_cr_write(fintek, ldev, GCR_LOGICAL_DEV_NO);
+}
+
+/* write val to cir config register */
+static inline void fintek_cir_reg_write(struct fintek_dev *fintek, u8 val, u8 offset)
+{
+ outb(val, fintek->cir_addr + offset);
+}
+
+/* read val from cir config register */
+static u8 fintek_cir_reg_read(struct fintek_dev *fintek, u8 offset)
+{
+ u8 val;
+
+ val = inb(fintek->cir_addr + offset);
+
+ return val;
+}
+
+#define pr_reg(text, ...) \
+ printk(KERN_INFO KBUILD_MODNAME ": " text, ## __VA_ARGS__)
+
+/* dump current cir register contents */
+static void cir_dump_regs(struct fintek_dev *fintek)
+{
+ fintek_config_mode_enable(fintek);
+ fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+
+ pr_reg("%s: Dump CIR logical device registers:\n", FINTEK_DRIVER_NAME);
+ pr_reg(" * CR CIR BASE ADDR: 0x%x\n",
+ (fintek_cr_read(fintek, CIR_CR_BASE_ADDR_HI) << 8) |
+ fintek_cr_read(fintek, CIR_CR_BASE_ADDR_LO));
+ pr_reg(" * CR CIR IRQ NUM: 0x%x\n",
+ fintek_cr_read(fintek, CIR_CR_IRQ_SEL));
+
+ fintek_config_mode_disable(fintek);
+
+ pr_reg("%s: Dump CIR registers:\n", FINTEK_DRIVER_NAME);
+ pr_reg(" * STATUS: 0x%x\n", fintek_cir_reg_read(fintek, CIR_STATUS));
+ pr_reg(" * CONTROL: 0x%x\n", fintek_cir_reg_read(fintek, CIR_CONTROL));
+ pr_reg(" * RX_DATA: 0x%x\n", fintek_cir_reg_read(fintek, CIR_RX_DATA));
+ pr_reg(" * TX_CONTROL: 0x%x\n", fintek_cir_reg_read(fintek, CIR_TX_CONTROL));
+ pr_reg(" * TX_DATA: 0x%x\n", fintek_cir_reg_read(fintek, CIR_TX_DATA));
+}
+
+/* detect hardware features */
+static int fintek_hw_detect(struct fintek_dev *fintek)
+{
+ unsigned long flags;
+ u8 chip_major, chip_minor;
+ u8 vendor_major, vendor_minor;
+ u8 portsel, ir_class;
+ u16 vendor;
+ int ret = 0;
+
+ fintek_config_mode_enable(fintek);
+
+ /* Check if we're using config port 0x4e or 0x2e */
+ portsel = fintek_cr_read(fintek, GCR_CONFIG_PORT_SEL);
+ if (portsel == 0xff) {
+ fit_pr(KERN_INFO, "first portsel read was bunk, trying alt");
+ fintek_config_mode_disable(fintek);
+ fintek->cr_ip = CR_INDEX_PORT2;
+ fintek->cr_dp = CR_DATA_PORT2;
+ fintek_config_mode_enable(fintek);
+ portsel = fintek_cr_read(fintek, GCR_CONFIG_PORT_SEL);
+ }
+ fit_dbg("portsel reg: 0x%02x", portsel);
+
+ ir_class = fintek_cir_reg_read(fintek, CIR_CR_CLASS);
+ fit_dbg("ir_class reg: 0x%02x", ir_class);
+
+ switch (ir_class) {
+ case CLASS_RX_2TX:
+ case CLASS_RX_1TX:
+ fintek->hw_tx_capable = true;
+ break;
+ case CLASS_RX_ONLY:
+ default:
+ fintek->hw_tx_capable = false;
+ break;
+ }
+
+ chip_major = fintek_cr_read(fintek, GCR_CHIP_ID_HI);
+ chip_minor = fintek_cr_read(fintek, GCR_CHIP_ID_LO);
+
+ vendor_major = fintek_cr_read(fintek, GCR_VENDOR_ID_HI);
+ vendor_minor = fintek_cr_read(fintek, GCR_VENDOR_ID_LO);
+ vendor = vendor_major << 8 | vendor_minor;
+
+ if (vendor != VENDOR_ID_FINTEK)
+ fit_pr(KERN_WARNING, "Unknown vendor ID: 0x%04x", vendor);
+ else
+ fit_dbg("Read Fintek vendor ID from chip");
+
+ fintek_config_mode_disable(fintek);
+
+ spin_lock_irqsave(&fintek->fintek_lock, flags);
+ fintek->chip_major = chip_major;
+ fintek->chip_minor = chip_minor;
+ fintek->chip_vendor = vendor;
+ spin_unlock_irqrestore(&fintek->fintek_lock, flags);
+
+ return ret;
+}
+
+static void fintek_cir_ldev_init(struct fintek_dev *fintek)
+{
+ /* Select CIR logical device and enable */
+ fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+ fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN);
+
+ /* Write allocated CIR address and IRQ information to hardware */
+ fintek_cr_write(fintek, fintek->cir_addr >> 8, CIR_CR_BASE_ADDR_HI);
+ fintek_cr_write(fintek, fintek->cir_addr & 0xff, CIR_CR_BASE_ADDR_LO);
+
+ fintek_cr_write(fintek, fintek->cir_irq, CIR_CR_IRQ_SEL);
+
+ fit_dbg("CIR initialized, base io address: 0x%lx, irq: %d (len: %d)",
+ fintek->cir_addr, fintek->cir_irq, fintek->cir_port_len);
+}
+
+/* enable CIR interrupts */
+static void fintek_enable_cir_irq(struct fintek_dev *fintek)
+{
+ fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_EN, CIR_STATUS);
+}
+
+static void fintek_cir_regs_init(struct fintek_dev *fintek)
+{
+ /* clear any and all stray interrupts */
+ fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS);
+
+ /* and finally, enable interrupts */
+ fintek_enable_cir_irq(fintek);
+}
+
+static void fintek_enable_wake(struct fintek_dev *fintek)
+{
+ fintek_config_mode_enable(fintek);
+ fintek_select_logical_dev(fintek, LOGICAL_DEV_ACPI);
+
+ /* Allow CIR PME's to wake system */
+ fintek_set_reg_bit(fintek, ACPI_WAKE_EN_CIR_BIT, LDEV_ACPI_WAKE_EN_REG);
+ /* Enable CIR PME's */
+ fintek_set_reg_bit(fintek, ACPI_PME_CIR_BIT, LDEV_ACPI_PME_EN_REG);
+ /* Clear CIR PME status register */
+ fintek_set_reg_bit(fintek, ACPI_PME_CIR_BIT, LDEV_ACPI_PME_CLR_REG);
+ /* Save state */
+ fintek_set_reg_bit(fintek, ACPI_STATE_CIR_BIT, LDEV_ACPI_STATE_REG);
+
+ fintek_config_mode_disable(fintek);
+}
+
+static int fintek_cmdsize(u8 cmd, u8 subcmd)
+{
+ int datasize = 0;
+
+ switch (cmd) {
+ case BUF_COMMAND_NULL:
+ if (subcmd == BUF_HW_CMD_HEADER)
+ datasize = 1;
+ break;
+ case BUF_HW_CMD_HEADER:
+ if (subcmd == BUF_CMD_G_REVISION)
+ datasize = 2;
+ break;
+ case BUF_COMMAND_HEADER:
+ switch (subcmd) {
+ case BUF_CMD_S_CARRIER:
+ case BUF_CMD_S_TIMEOUT:
+ case BUF_RSP_PULSE_COUNT:
+ datasize = 2;
+ break;
+ case BUF_CMD_SIG_END:
+ case BUF_CMD_S_TXMASK:
+ case BUF_CMD_S_RXSENSOR:
+ datasize = 1;
+ break;
+ }
+ }
+
+ return datasize;
+}
+
+/* process ir data stored in driver buffer */
+static void fintek_process_rx_ir_data(struct fintek_dev *fintek)
+{
+ DEFINE_IR_RAW_EVENT(rawir);
+ u8 sample;
+ int i;
+
+ for (i = 0; i < fintek->pkts; i++) {
+ sample = fintek->buf[i];
+ switch (fintek->parser_state) {
+ case CMD_HEADER:
+ fintek->cmd = sample;
+ if ((fintek->cmd == BUF_COMMAND_HEADER) ||
+ ((fintek->cmd & BUF_COMMAND_MASK) !=
+ BUF_PULSE_BIT)) {
+ fintek->parser_state = SUBCMD;
+ continue;
+ }
+ fintek->rem = (fintek->cmd & BUF_LEN_MASK);
+ fit_dbg("%s: rem: 0x%02x", __func__, fintek->rem);
+ if (fintek->rem)
+ fintek->parser_state = PARSE_IRDATA;
+ else
+ ir_raw_event_reset(fintek->rdev);
+ break;
+ case SUBCMD:
+ fintek->rem = fintek_cmdsize(fintek->cmd, sample);
+ fintek->parser_state = CMD_DATA;
+ break;
+ case CMD_DATA:
+ fintek->rem--;
+ break;
+ case PARSE_IRDATA:
+ fintek->rem--;
+ init_ir_raw_event(&rawir);
+ rawir.pulse = ((sample & BUF_PULSE_BIT) != 0);
+ rawir.duration = US_TO_NS((sample & BUF_SAMPLE_MASK)
+ * CIR_SAMPLE_PERIOD);
+
+ fit_dbg("Storing %s with duration %d",
+ rawir.pulse ? "pulse" : "space",
+ rawir.duration);
+ ir_raw_event_store_with_filter(fintek->rdev, &rawir);
+ break;
+ }
+
+ if ((fintek->parser_state != CMD_HEADER) && !fintek->rem)
+ fintek->parser_state = CMD_HEADER;
+ }
+
+ fintek->pkts = 0;
+
+ fit_dbg("Calling ir_raw_event_handle");
+ ir_raw_event_handle(fintek->rdev);
+}
+
+/* copy data from hardware rx register into driver buffer */
+static void fintek_get_rx_ir_data(struct fintek_dev *fintek, u8 rx_irqs)
+{
+ unsigned long flags;
+ u8 sample, status;
+
+ spin_lock_irqsave(&fintek->fintek_lock, flags);
+
+ /*
+ * We must read data from CIR_RX_DATA until the hardware IR buffer
+ * is empty and clears the RX_TIMEOUT and/or RX_RECEIVE flags in
+ * the CIR_STATUS register
+ */
+ do {
+ sample = fintek_cir_reg_read(fintek, CIR_RX_DATA);
+ fit_dbg("%s: sample: 0x%02x", __func__, sample);
+
+ fintek->buf[fintek->pkts] = sample;
+ fintek->pkts++;
+
+ status = fintek_cir_reg_read(fintek, CIR_STATUS);
+ if (!(status & CIR_STATUS_IRQ_EN))
+ break;
+ } while (status & rx_irqs);
+
+ fintek_process_rx_ir_data(fintek);
+
+ spin_unlock_irqrestore(&fintek->fintek_lock, flags);
+}
+
+static void fintek_cir_log_irqs(u8 status)
+{
+ fit_pr(KERN_INFO, "IRQ 0x%02x:%s%s%s%s%s", status,
+ status & CIR_STATUS_IRQ_EN ? " IRQEN" : "",
+ status & CIR_STATUS_TX_FINISH ? " TXF" : "",
+ status & CIR_STATUS_TX_UNDERRUN ? " TXU" : "",
+ status & CIR_STATUS_RX_TIMEOUT ? " RXTO" : "",
+ status & CIR_STATUS_RX_RECEIVE ? " RXOK" : "");
+}
+
+/* interrupt service routine for incoming and outgoing CIR data */
+static irqreturn_t fintek_cir_isr(int irq, void *data)
+{
+ struct fintek_dev *fintek = data;
+ u8 status, rx_irqs;
+
+ fit_dbg_verbose("%s firing", __func__);
+
+ fintek_config_mode_enable(fintek);
+ fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+ fintek_config_mode_disable(fintek);
+
+ /*
+ * Get IR Status register contents. Write 1 to ack/clear
+ *
+ * bit: reg name - description
+ * 3: TX_FINISH - TX is finished
+ * 2: TX_UNDERRUN - TX underrun
+ * 1: RX_TIMEOUT - RX data timeout
+ * 0: RX_RECEIVE - RX data received
+ */
+ status = fintek_cir_reg_read(fintek, CIR_STATUS);
+ if (!(status & CIR_STATUS_IRQ_MASK) || status == 0xff) {
+ fit_dbg_verbose("%s exiting, IRSTS 0x%02x", __func__, status);
+ fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS);
+ return IRQ_RETVAL(IRQ_NONE);
+ }
+
+ if (debug)
+ fintek_cir_log_irqs(status);
+
+ rx_irqs = status & (CIR_STATUS_RX_RECEIVE | CIR_STATUS_RX_TIMEOUT);
+ if (rx_irqs)
+ fintek_get_rx_ir_data(fintek, rx_irqs);
+
+ /* ack/clear all irq flags we've got */
+ fintek_cir_reg_write(fintek, status, CIR_STATUS);
+
+ fit_dbg_verbose("%s done", __func__);
+ return IRQ_RETVAL(IRQ_HANDLED);
+}
+
+static void fintek_enable_cir(struct fintek_dev *fintek)
+{
+ /* set IRQ enabled */
+ fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_EN, CIR_STATUS);
+
+ fintek_config_mode_enable(fintek);
+
+ /* enable the CIR logical device */
+ fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+ fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN);
+
+ fintek_config_mode_disable(fintek);
+
+ /* clear all pending interrupts */
+ fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS);
+
+ /* enable interrupts */
+ fintek_enable_cir_irq(fintek);
+}
+
+static void fintek_disable_cir(struct fintek_dev *fintek)
+{
+ fintek_config_mode_enable(fintek);
+
+ /* disable the CIR logical device */
+ fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+ fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN);
+
+ fintek_config_mode_disable(fintek);
+}
+
+static int fintek_open(struct rc_dev *dev)
+{
+ struct fintek_dev *fintek = dev->priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&fintek->fintek_lock, flags);
+ fintek_enable_cir(fintek);
+ spin_unlock_irqrestore(&fintek->fintek_lock, flags);
+
+ return 0;
+}
+
+static void fintek_close(struct rc_dev *dev)
+{
+ struct fintek_dev *fintek = dev->priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&fintek->fintek_lock, flags);
+ fintek_disable_cir(fintek);
+ spin_unlock_irqrestore(&fintek->fintek_lock, flags);
+}
+
+/* Allocate memory, probe hardware, and initialize everything */
+static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
+{
+ struct fintek_dev *fintek;
+ struct rc_dev *rdev;
+ int ret = -ENOMEM;
+
+ fintek = kzalloc(sizeof(struct fintek_dev), GFP_KERNEL);
+ if (!fintek)
+ return ret;
+
+ /* input device for IR remote (and tx) */
+ rdev = rc_allocate_device();
+ if (!rdev)
+ goto failure;
+
+ ret = -ENODEV;
+ /* validate pnp resources */
+ if (!pnp_port_valid(pdev, 0)) {
+ dev_err(&pdev->dev, "IR PNP Port not valid!\n");
+ goto failure;
+ }
+
+ if (!pnp_irq_valid(pdev, 0)) {
+ dev_err(&pdev->dev, "IR PNP IRQ not valid!\n");
+ goto failure;
+ }
+
+ fintek->cir_addr = pnp_port_start(pdev, 0);
+ fintek->cir_irq = pnp_irq(pdev, 0);
+ fintek->cir_port_len = pnp_port_len(pdev, 0);
+
+ fintek->cr_ip = CR_INDEX_PORT;
+ fintek->cr_dp = CR_DATA_PORT;
+
+ spin_lock_init(&fintek->fintek_lock);
+
+ ret = -EBUSY;
+ /* now claim resources */
+ if (!request_region(fintek->cir_addr,
+ fintek->cir_port_len, FINTEK_DRIVER_NAME))
+ goto failure;
+
+ if (request_irq(fintek->cir_irq, fintek_cir_isr, IRQF_SHARED,
+ FINTEK_DRIVER_NAME, (void *)fintek))
+ goto failure;
+
+ pnp_set_drvdata(pdev, fintek);
+ fintek->pdev = pdev;
+
+ ret = fintek_hw_detect(fintek);
+ if (ret)
+ goto failure;
+
+ /* Initialize CIR & CIR Wake Logical Devices */
+ fintek_config_mode_enable(fintek);
+ fintek_cir_ldev_init(fintek);
+ fintek_config_mode_disable(fintek);
+
+ /* Initialize CIR & CIR Wake Config Registers */
+ fintek_cir_regs_init(fintek);
+
+ /* Set up the rc device */
+ rdev->priv = fintek;
+ rdev->driver_type = RC_DRIVER_IR_RAW;
+ rdev->allowed_protos = RC_TYPE_ALL;
+ rdev->open = fintek_open;
+ rdev->close = fintek_close;
+ rdev->input_name = FINTEK_DESCRIPTION;
+ rdev->input_phys = "fintek/cir0";
+ rdev->input_id.bustype = BUS_HOST;
+ rdev->input_id.vendor = VENDOR_ID_FINTEK;
+ rdev->input_id.product = fintek->chip_major;
+ rdev->input_id.version = fintek->chip_minor;
+ rdev->dev.parent = &pdev->dev;
+ rdev->driver_name = FINTEK_DRIVER_NAME;
+ rdev->map_name = RC_MAP_RC6_MCE;
+ rdev->timeout = US_TO_NS(1000);
+ /* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */
+ rdev->rx_resolution = US_TO_NS(CIR_SAMPLE_PERIOD);
+
+ ret = rc_register_device(rdev);
+ if (ret)
+ goto failure;
+
+ device_init_wakeup(&pdev->dev, true);
+ fintek->rdev = rdev;
+ fit_pr(KERN_NOTICE, "driver has been successfully loaded\n");
+ if (debug)
+ cir_dump_regs(fintek);
+
+ return 0;
+
+failure:
+ if (fintek->cir_irq)
+ free_irq(fintek->cir_irq, fintek);
+ if (fintek->cir_addr)
+ release_region(fintek->cir_addr, fintek->cir_port_len);
+
+ rc_free_device(rdev);
+ kfree(fintek);
+
+ return ret;
+}
+
+static void __devexit fintek_remove(struct pnp_dev *pdev)
+{
+ struct fintek_dev *fintek = pnp_get_drvdata(pdev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&fintek->fintek_lock, flags);
+ /* disable CIR */
+ fintek_disable_cir(fintek);
+ fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS);
+ /* enable CIR Wake (for IR power-on) */
+ fintek_enable_wake(fintek);
+ spin_unlock_irqrestore(&fintek->fintek_lock, flags);
+
+ /* free resources */
+ free_irq(fintek->cir_irq, fintek);
+ release_region(fintek->cir_addr, fintek->cir_port_len);
+
+ rc_unregister_device(fintek->rdev);
+
+ kfree(fintek);
+}
+
+static int fintek_suspend(struct pnp_dev *pdev, pm_message_t state)
+{
+ struct fintek_dev *fintek = pnp_get_drvdata(pdev);
+
+ fit_dbg("%s called", __func__);
+
+ /* disable all CIR interrupts */
+ fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS);
+
+ fintek_config_mode_enable(fintek);
+
+ /* disable cir logical dev */
+ fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+ fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN);
+
+ fintek_config_mode_disable(fintek);
+
+ /* make sure wake is enabled */
+ fintek_enable_wake(fintek);
+
+ return 0;
+}
+
+static int fintek_resume(struct pnp_dev *pdev)
+{
+ int ret = 0;
+ struct fintek_dev *fintek = pnp_get_drvdata(pdev);
+
+ fit_dbg("%s called", __func__);
+
+ /* open interrupt */
+ fintek_enable_cir_irq(fintek);
+
+ /* Enable CIR logical device */
+ fintek_config_mode_enable(fintek);
+ fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR);
+ fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN);
+
+ fintek_config_mode_disable(fintek);
+
+ fintek_cir_regs_init(fintek);
+
+ return ret;
+}
+
+static void fintek_shutdown(struct pnp_dev *pdev)
+{
+ struct fintek_dev *fintek = pnp_get_drvdata(pdev);
+ fintek_enable_wake(fintek);
+}
+
+static const struct pnp_device_id fintek_ids[] = {
+ { "FIT0002", 0 }, /* CIR */
+ { "", 0 },
+};
+
+static struct pnp_driver fintek_driver = {
+ .name = FINTEK_DRIVER_NAME,
+ .id_table = fintek_ids,
+ .flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
+ .probe = fintek_probe,
+ .remove = __devexit_p(fintek_remove),
+ .suspend = fintek_suspend,
+ .resume = fintek_resume,
+ .shutdown = fintek_shutdown,
+};
+
+int fintek_init(void)
+{
+ return pnp_register_driver(&fintek_driver);
+}
+
+void fintek_exit(void)
+{
+ pnp_unregister_driver(&fintek_driver);
+}
+
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging output");
+
+MODULE_DEVICE_TABLE(pnp, fintek_ids);
+MODULE_DESCRIPTION(FINTEK_DESCRIPTION " driver");
+
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
+MODULE_LICENSE("GPL");
+
+module_init(fintek_init);
+module_exit(fintek_exit);
diff --git a/drivers/media/rc/fintek-cir.h b/drivers/media/rc/fintek-cir.h
new file mode 100644
index 000000000000..1b10b2011f5e
--- /dev/null
+++ b/drivers/media/rc/fintek-cir.h
@@ -0,0 +1,243 @@
+/*
+ * Driver for Feature Integration Technology Inc. (aka Fintek) LPC CIR
+ *
+ * Copyright (C) 2011 Jarod Wilson <jarod@redhat.com>
+ *
+ * Special thanks to Fintek for providing hardware and spec sheets.
+ * This driver is based upon the nuvoton, ite and ene drivers for
+ * similar hardware.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the 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/spinlock.h>
+#include <linux/ioctl.h>
+
+/* platform driver name to register */
+#define FINTEK_DRIVER_NAME "fintek-cir"
+#define FINTEK_DESCRIPTION "Fintek LPC SuperIO Consumer IR Transceiver"
+#define VENDOR_ID_FINTEK 0x1934
+
+
+/* debugging module parameter */
+static int debug;
+
+#define fit_pr(level, text, ...) \
+ printk(level KBUILD_MODNAME ": " text, ## __VA_ARGS__)
+
+#define fit_dbg(text, ...) \
+ if (debug) \
+ printk(KERN_DEBUG \
+ KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
+
+#define fit_dbg_verbose(text, ...) \
+ if (debug > 1) \
+ printk(KERN_DEBUG \
+ KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
+
+#define fit_dbg_wake(text, ...) \
+ if (debug > 2) \
+ printk(KERN_DEBUG \
+ KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
+
+
+#define TX_BUF_LEN 256
+#define RX_BUF_LEN 32
+
+struct fintek_dev {
+ struct pnp_dev *pdev;
+ struct rc_dev *rdev;
+
+ spinlock_t fintek_lock;
+
+ /* for rx */
+ u8 buf[RX_BUF_LEN];
+ unsigned int pkts;
+
+ struct {
+ spinlock_t lock;
+ u8 buf[TX_BUF_LEN];
+ unsigned int buf_count;
+ unsigned int cur_buf_num;
+ wait_queue_head_t queue;
+ } tx;
+
+ /* Config register index/data port pair */
+ u8 cr_ip;
+ u8 cr_dp;
+
+ /* hardware I/O settings */
+ unsigned long cir_addr;
+ int cir_irq;
+ int cir_port_len;
+
+ /* hardware id */
+ u8 chip_major;
+ u8 chip_minor;
+ u16 chip_vendor;
+
+ /* hardware features */
+ bool hw_learning_capable;
+ bool hw_tx_capable;
+
+ /* rx settings */
+ bool learning_enabled;
+ bool carrier_detect_enabled;
+
+ enum {
+ CMD_HEADER = 0,
+ SUBCMD,
+ CMD_DATA,
+ PARSE_IRDATA,
+ } parser_state;
+
+ u8 cmd, rem;
+
+ /* carrier period = 1 / frequency */
+ u32 carrier;
+};
+
+/* buffer packet constants, largely identical to mceusb.c */
+#define BUF_PULSE_BIT 0x80
+#define BUF_LEN_MASK 0x1f
+#define BUF_SAMPLE_MASK 0x7f
+
+#define BUF_COMMAND_HEADER 0x9f
+#define BUF_COMMAND_MASK 0xe0
+#define BUF_COMMAND_NULL 0x00
+#define BUF_HW_CMD_HEADER 0xff
+#define BUF_CMD_G_REVISION 0x0b
+#define BUF_CMD_S_CARRIER 0x06
+#define BUF_CMD_S_TIMEOUT 0x0c
+#define BUF_CMD_SIG_END 0x01
+#define BUF_CMD_S_TXMASK 0x08
+#define BUF_CMD_S_RXSENSOR 0x14
+#define BUF_RSP_PULSE_COUNT 0x15
+
+#define CIR_SAMPLE_PERIOD 50
+
+/*
+ * Configuration Register:
+ * Index Port
+ * Data Port
+ */
+#define CR_INDEX_PORT 0x2e
+#define CR_DATA_PORT 0x2f
+
+/* Possible alternate values, depends on how the chip is wired */
+#define CR_INDEX_PORT2 0x4e
+#define CR_DATA_PORT2 0x4f
+
+/*
+ * GCR_CONFIG_PORT_SEL bit 4 specifies which Index Port value is
+ * active. 1 = 0x4e, 0 = 0x2e
+ */
+#define PORT_SEL_PORT_4E_EN 0x10
+
+/* Extended Function Mode enable/disable magic values */
+#define CONFIG_REG_ENABLE 0x87
+#define CONFIG_REG_DISABLE 0xaa
+
+/* Chip IDs found in CR_CHIP_ID_{HI,LO} */
+#define CHIP_ID_HIGH_F71809U 0x04
+#define CHIP_ID_LOW_F71809U 0x08
+
+/*
+ * Global control regs we need to care about:
+ * Global Control def.
+ * Register name addr val. */
+#define GCR_SOFTWARE_RESET 0x02 /* 0x00 */
+#define GCR_LOGICAL_DEV_NO 0x07 /* 0x00 */
+#define GCR_CHIP_ID_HI 0x20 /* 0x04 */
+#define GCR_CHIP_ID_LO 0x21 /* 0x08 */
+#define GCR_VENDOR_ID_HI 0x23 /* 0x19 */
+#define GCR_VENDOR_ID_LO 0x24 /* 0x34 */
+#define GCR_CONFIG_PORT_SEL 0x25 /* 0x01 */
+#define GCR_KBMOUSE_WAKEUP 0x27
+
+#define LOGICAL_DEV_DISABLE 0x00
+#define LOGICAL_DEV_ENABLE 0x01
+
+/* Logical device number of the CIR function */
+#define LOGICAL_DEV_CIR 0x05
+
+/* CIR Logical Device (LDN 0x08) config registers */
+#define CIR_CR_COMMAND_INDEX 0x04
+#define CIR_CR_IRCS 0x05 /* Before host writes command to IR, host
+ must set to 1. When host finshes write
+ command to IR, host must clear to 0. */
+#define CIR_CR_COMMAND_DATA 0x06 /* Host read or write comand data */
+#define CIR_CR_CLASS 0x07 /* 0xff = rx-only, 0x66 = rx + 2 tx,
+ 0x33 = rx + 1 tx */
+#define CIR_CR_DEV_EN 0x30 /* bit0 = 1 enables CIR */
+#define CIR_CR_BASE_ADDR_HI 0x60 /* MSB of CIR IO base addr */
+#define CIR_CR_BASE_ADDR_LO 0x61 /* LSB of CIR IO base addr */
+#define CIR_CR_IRQ_SEL 0x70 /* bits3-0 store CIR IRQ */
+#define CIR_CR_PSOUT_STATUS 0xf1
+#define CIR_CR_WAKE_KEY3_ADDR 0xf8
+#define CIR_CR_WAKE_KEY3_CODE 0xf9
+#define CIR_CR_WAKE_KEY3_DC 0xfa
+#define CIR_CR_WAKE_CONTROL 0xfb
+#define CIR_CR_WAKE_KEY12_ADDR 0xfc
+#define CIR_CR_WAKE_KEY4_ADDR 0xfd
+#define CIR_CR_WAKE_KEY5_ADDR 0xfe
+
+#define CLASS_RX_ONLY 0xff
+#define CLASS_RX_2TX 0x66
+#define CLASS_RX_1TX 0x33
+
+/* CIR device registers */
+#define CIR_STATUS 0x00
+#define CIR_RX_DATA 0x01
+#define CIR_TX_CONTROL 0x02
+#define CIR_TX_DATA 0x03
+#define CIR_CONTROL 0x04
+
+/* Bits to enable CIR wake */
+#define LOGICAL_DEV_ACPI 0x01
+#define LDEV_ACPI_WAKE_EN_REG 0xe8
+#define ACPI_WAKE_EN_CIR_BIT 0x04
+
+#define LDEV_ACPI_PME_EN_REG 0xf0
+#define LDEV_ACPI_PME_CLR_REG 0xf1
+#define ACPI_PME_CIR_BIT 0x02
+
+#define LDEV_ACPI_STATE_REG 0xf4
+#define ACPI_STATE_CIR_BIT 0x20
+
+/*
+ * CIR status register (0x00):
+ * 7 - CIR_IRQ_EN (1 = enable CIR IRQ, 0 = disable)
+ * 3 - TX_FINISH (1 when TX finished, write 1 to clear)
+ * 2 - TX_UNDERRUN (1 on TX underrun, write 1 to clear)
+ * 1 - RX_TIMEOUT (1 on RX timeout, write 1 to clear)
+ * 0 - RX_RECEIVE (1 on RX receive, write 1 to clear)
+ */
+#define CIR_STATUS_IRQ_EN 0x80
+#define CIR_STATUS_TX_FINISH 0x08
+#define CIR_STATUS_TX_UNDERRUN 0x04
+#define CIR_STATUS_RX_TIMEOUT 0x02
+#define CIR_STATUS_RX_RECEIVE 0x01
+#define CIR_STATUS_IRQ_MASK 0x0f
+
+/*
+ * CIR TX control register (0x02):
+ * 7 - TX_START (1 to indicate TX start, auto-cleared when done)
+ * 6 - TX_END (1 to indicate TX data written to TX fifo)
+ */
+#define CIR_TX_CONTROL_TX_START 0x80
+#define CIR_TX_CONTROL_TX_END 0x40
+
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index 8fc0f081b470..3f3c70716268 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -443,16 +443,6 @@ static int display_close(struct inode *inode, struct file *file)
} else {
ictx->display_isopen = false;
dev_dbg(ictx->dev, "display port closed\n");
- if (!ictx->dev_present_intf0) {
- /*
- * Device disconnected before close and IR port is not
- * open. If IR port is open, context will be deleted by
- * ir_close.
- */
- mutex_unlock(&ictx->lock);
- free_imon_context(ictx);
- return retval;
- }
}
mutex_unlock(&ictx->lock);
@@ -1492,7 +1482,6 @@ static void imon_incoming_packet(struct imon_context *ictx,
struct device *dev = ictx->dev;
unsigned long flags;
u32 kc;
- bool norelease = false;
int i;
u64 scancode;
int press_type = 0;
@@ -1560,7 +1549,6 @@ static void imon_incoming_packet(struct imon_context *ictx,
!(buf[1] & 0x1 || buf[1] >> 2 & 0x1))) {
len = 8;
imon_pad_to_keys(ictx, buf);
- norelease = true;
}
if (debug) {
@@ -1982,7 +1970,7 @@ static struct input_dev *imon_init_touch(struct imon_context *ictx)
return touch;
touch_register_failed:
- input_free_device(ictx->touch);
+ input_free_device(touch);
touch_alloc_failed:
return NULL;
@@ -2274,14 +2262,12 @@ static int __devinit imon_probe(struct usb_interface *interface,
struct usb_host_interface *iface_desc = NULL;
struct usb_interface *first_if;
struct device *dev = &interface->dev;
- int ifnum, code_length, sysfs_err;
+ int ifnum, sysfs_err;
int ret = 0;
struct imon_context *ictx = NULL;
struct imon_context *first_if_ctx = NULL;
u16 vendor, product;
- code_length = BUF_CHUNK_SIZE * 8;
-
usbdev = usb_get_dev(interface_to_usbdev(interface));
iface_desc = interface->cur_altsetting;
ifnum = iface_desc->desc.bInterfaceNumber;
@@ -2366,8 +2352,6 @@ static void __devexit imon_disconnect(struct usb_interface *interface)
dev = ictx->dev;
ifnum = interface->cur_altsetting->desc.bInterfaceNumber;
- mutex_lock(&ictx->lock);
-
/*
* sysfs_remove_group is safe to call even if sysfs_create_group
* hasn't been called
@@ -2391,24 +2375,20 @@ static void __devexit imon_disconnect(struct usb_interface *interface)
if (ictx->display_supported) {
if (ictx->display_type == IMON_DISPLAY_TYPE_LCD)
usb_deregister_dev(interface, &imon_lcd_class);
- else
+ else if (ictx->display_type == IMON_DISPLAY_TYPE_VFD)
usb_deregister_dev(interface, &imon_vfd_class);
}
} else {
ictx->dev_present_intf1 = false;
usb_kill_urb(ictx->rx_urb_intf1);
- if (ictx->display_type == IMON_DISPLAY_TYPE_VGA)
+ if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) {
input_unregister_device(ictx->touch);
+ del_timer_sync(&ictx->ttimer);
+ }
}
- if (!ictx->dev_present_intf0 && !ictx->dev_present_intf1) {
- if (ictx->display_type == IMON_DISPLAY_TYPE_VGA)
- del_timer_sync(&ictx->ttimer);
- mutex_unlock(&ictx->lock);
- if (!ictx->display_isopen)
- free_imon_context(ictx);
- } else
- mutex_unlock(&ictx->lock);
+ if (!ictx->dev_present_intf0 && !ictx->dev_present_intf1)
+ free_imon_context(ictx);
mutex_unlock(&driver_lock);
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
index 43908a70bd8b..e716b931cf7e 100644
--- a/drivers/media/rc/ite-cir.c
+++ b/drivers/media/rc/ite-cir.c
@@ -1250,11 +1250,9 @@ static void it8709_disable(struct ite_dev *dev)
ite_dbg("%s called", __func__);
/* clear out all interrupt enable flags */
- it8709_wr(dev,
- it8709_rr(dev,
- IT85_C0IER) & ~(IT85_IEC | IT85_RFOIE |
- IT85_RDAIE |
- IT85_TLDLIE), IT85_C0IER);
+ it8709_wr(dev, it8709_rr(dev, IT85_C0IER) &
+ ~(IT85_IEC | IT85_RFOIE | IT85_RDAIE | IT85_TLDLIE),
+ IT85_C0IER);
/* disable the receiver */
it8709_disable_rx(dev);
@@ -1270,11 +1268,9 @@ static void it8709_init_hardware(struct ite_dev *dev)
ite_dbg("%s called", __func__);
/* disable all the interrupts */
- it8709_wr(dev,
- it8709_rr(dev,
- IT85_C0IER) & ~(IT85_IEC | IT85_RFOIE |
- IT85_RDAIE |
- IT85_TLDLIE), IT85_C0IER);
+ it8709_wr(dev, it8709_rr(dev, IT85_C0IER) &
+ ~(IT85_IEC | IT85_RFOIE | IT85_RDAIE | IT85_TLDLIE),
+ IT85_C0IER);
/* program the baud rate divisor */
it8709_wr(dev, ITE_BAUDRATE_DIVISOR & 0xff, IT85_C0BDLR);
@@ -1282,28 +1278,22 @@ static void it8709_init_hardware(struct ite_dev *dev)
IT85_C0BDHR);
/* program the C0MSTCR register defaults */
- it8709_wr(dev, (it8709_rr(dev, IT85_C0MSTCR) & ~(IT85_ILSEL |
- IT85_ILE
- | IT85_FIFOTL
- |
- IT85_FIFOCLR
- |
- IT85_RESET))
- | IT85_FIFOTL_DEFAULT, IT85_C0MSTCR);
+ it8709_wr(dev, (it8709_rr(dev, IT85_C0MSTCR) &
+ ~(IT85_ILSEL | IT85_ILE | IT85_FIFOTL
+ | IT85_FIFOCLR | IT85_RESET)) | IT85_FIFOTL_DEFAULT,
+ IT85_C0MSTCR);
/* program the C0RCR register defaults */
- it8709_wr(dev,
- (it8709_rr(dev, IT85_C0RCR) &
- ~(IT85_RXEN | IT85_RDWOS | IT85_RXEND
- | IT85_RXACT | IT85_RXDCR)) |
- ITE_RXDCR_DEFAULT, IT85_C0RCR);
+ it8709_wr(dev, (it8709_rr(dev, IT85_C0RCR) &
+ ~(IT85_RXEN | IT85_RDWOS | IT85_RXEND | IT85_RXACT
+ | IT85_RXDCR)) | ITE_RXDCR_DEFAULT,
+ IT85_C0RCR);
/* program the C0TCR register defaults */
- it8709_wr(dev, (it8709_rr(dev, IT85_C0TCR)
- &~(IT85_TXMPM | IT85_TXMPW))
- |IT85_TXRLE | IT85_TXENDF |
- IT85_TXMPM_DEFAULT |
- IT85_TXMPW_DEFAULT, IT85_C0TCR);
+ it8709_wr(dev, (it8709_rr(dev, IT85_C0TCR) & ~(IT85_TXMPM | IT85_TXMPW))
+ | IT85_TXRLE | IT85_TXENDF | IT85_TXMPM_DEFAULT
+ | IT85_TXMPW_DEFAULT,
+ IT85_C0TCR);
/* program the carrier parameters */
ite_set_carrier_params(dev);
@@ -1660,6 +1650,9 @@ static int ite_suspend(struct pnp_dev *pdev, pm_message_t state)
ite_dbg("%s called", __func__);
+ /* wait for any transmission to end */
+ wait_event_interruptible(dev->tx_ended, !dev->transmitting);
+
spin_lock_irqsave(&dev->lock, flags);
/* disable all interrupts */
@@ -1680,13 +1673,10 @@ static int ite_resume(struct pnp_dev *pdev)
spin_lock_irqsave(&dev->lock, flags);
- if (dev->transmitting) {
- /* wake up the transmitter */
- wake_up_interruptible(&dev->tx_queue);
- } else {
- /* enable the receiver */
- dev->params.enable_rx(dev);
- }
+ /* reinitialize hardware config registers */
+ dev->params.init_hardware(dev);
+ /* enable the receiver */
+ dev->params.enable_rx(dev);
spin_unlock_irqrestore(&dev->lock, flags);
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index 85cac7ddbcec..b57fc83fb4d2 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -77,6 +77,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-terratec-slim.o \
rc-terratec-slim-2.o \
rc-tevii-nec.o \
+ rc-tivo.o \
rc-total-media-in-hand.o \
rc-trekstor.o \
rc-tt-1500.o \
diff --git a/drivers/media/rc/keymaps/rc-avermedia-cardbus.c b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c
index bdf97b74cf90..22f54d413a35 100644
--- a/drivers/media/rc/keymaps/rc-avermedia-cardbus.c
+++ b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c
@@ -52,7 +52,7 @@ static struct rc_map_table avermedia_cardbus[] = {
{ 0x28, KEY_SELECT }, /* Select */
{ 0x29, KEY_BLUE }, /* Blue/Picture */
{ 0x2a, KEY_BACKSPACE }, /* Back */
- { 0x2b, KEY_MEDIA }, /* PIP (Picture-in-picture) */
+ { 0x2b, KEY_VIDEO }, /* PIP (Picture-in-picture) */
{ 0x2c, KEY_DOWN },
{ 0x2e, KEY_DOT },
{ 0x2f, KEY_TV }, /* Live TV */
diff --git a/drivers/media/rc/keymaps/rc-imon-mce.c b/drivers/media/rc/keymaps/rc-imon-mce.c
index 937a81989f00..0ea2aa190d81 100644
--- a/drivers/media/rc/keymaps/rc-imon-mce.c
+++ b/drivers/media/rc/keymaps/rc-imon-mce.c
@@ -111,7 +111,7 @@ static struct rc_map_table imon_mce[] = {
{ 0x800ff44d, KEY_TITLE },
{ 0x800ff40c, KEY_POWER },
- { 0x800ff40d, KEY_LEFTMETA }, /* Windows MCE button */
+ { 0x800ff40d, KEY_MEDIA }, /* Windows MCE button */
};
diff --git a/drivers/media/rc/keymaps/rc-imon-pad.c b/drivers/media/rc/keymaps/rc-imon-pad.c
index 63d42bd24c9e..75d3843fdc30 100644
--- a/drivers/media/rc/keymaps/rc-imon-pad.c
+++ b/drivers/media/rc/keymaps/rc-imon-pad.c
@@ -87,7 +87,7 @@ static struct rc_map_table imon_pad[] = {
{ 0x2b8515b7, KEY_VIDEO },
{ 0x299195b7, KEY_AUDIO },
- { 0x2ba115b7, KEY_CAMERA },
+ { 0x2ba115b7, KEY_IMAGES },
{ 0x28a515b7, KEY_TV },
{ 0x29a395b7, KEY_DVD },
{ 0x29a295b7, KEY_DVD },
@@ -97,7 +97,7 @@ static struct rc_map_table imon_pad[] = {
{ 0x2ba395b7, KEY_MENU },
{ 0x288515b7, KEY_BOOKMARKS },
- { 0x2ab715b7, KEY_MEDIA }, /* Thumbnail */
+ { 0x2ab715b7, KEY_CAMERA }, /* Thumbnail */
{ 0x298595b7, KEY_SUBTITLE },
{ 0x2b8595b7, KEY_LANGUAGE },
@@ -125,7 +125,7 @@ static struct rc_map_table imon_pad[] = {
{ 0x2b8195b7, KEY_CONTEXT_MENU }, /* Left Menu*/
{ 0x02000065, KEY_COMPOSE }, /* RightMenu */
{ 0x28b715b7, KEY_COMPOSE }, /* RightMenu */
- { 0x2ab195b7, KEY_LEFTMETA }, /* Go or MultiMon */
+ { 0x2ab195b7, KEY_MEDIA }, /* Go or MultiMon */
{ 0x29b715b7, KEY_DASHBOARD }, /* AppLauncher */
};
diff --git a/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c
index 08d183120e41..7fa17a369f2d 100644
--- a/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c
+++ b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c
@@ -17,7 +17,7 @@
*/
static struct rc_map_table kworld_plus_tv_analog[] = {
- { 0x0c, KEY_LEFTMETA }, /* Kworld key */
+ { 0x0c, KEY_MEDIA }, /* Kworld key */
{ 0x16, KEY_CLOSECD }, /* -> ) */
{ 0x1d, KEY_POWER2 },
diff --git a/drivers/media/rc/keymaps/rc-lme2510.c b/drivers/media/rc/keymaps/rc-lme2510.c
index afae14fd152e..129d3f9a461d 100644
--- a/drivers/media/rc/keymaps/rc-lme2510.c
+++ b/drivers/media/rc/keymaps/rc-lme2510.c
@@ -14,81 +14,81 @@
static struct rc_map_table lme2510_rc[] = {
/* Type 1 - 26 buttons */
- { 0xef12ba45, KEY_0 },
- { 0xef12a05f, KEY_1 },
- { 0xef12af50, KEY_2 },
- { 0xef12a25d, KEY_3 },
- { 0xef12be41, KEY_4 },
- { 0xef12f50a, KEY_5 },
- { 0xef12bd42, KEY_6 },
- { 0xef12b847, KEY_7 },
- { 0xef12b649, KEY_8 },
- { 0xef12fa05, KEY_9 },
- { 0xef12bc43, KEY_POWER },
- { 0xef12b946, KEY_SUBTITLE },
- { 0xef12f906, KEY_PAUSE },
- { 0xef12fc03, KEY_MEDIA_REPEAT},
- { 0xef12fd02, KEY_PAUSE },
- { 0xef12a15e, KEY_VOLUMEUP },
- { 0xef12a35c, KEY_VOLUMEDOWN },
- { 0xef12f609, KEY_CHANNELUP },
- { 0xef12e51a, KEY_CHANNELDOWN },
- { 0xef12e11e, KEY_PLAY },
- { 0xef12e41b, KEY_ZOOM },
- { 0xef12a659, KEY_MUTE },
- { 0xef12a55a, KEY_TV },
- { 0xef12e718, KEY_RECORD },
- { 0xef12f807, KEY_EPG },
- { 0xef12fe01, KEY_STOP },
+ { 0x10ed45, KEY_0 },
+ { 0x10ed5f, KEY_1 },
+ { 0x10ed50, KEY_2 },
+ { 0x10ed5d, KEY_3 },
+ { 0x10ed41, KEY_4 },
+ { 0x10ed0a, KEY_5 },
+ { 0x10ed42, KEY_6 },
+ { 0x10ed47, KEY_7 },
+ { 0x10ed49, KEY_8 },
+ { 0x10ed05, KEY_9 },
+ { 0x10ed43, KEY_POWER },
+ { 0x10ed46, KEY_SUBTITLE },
+ { 0x10ed06, KEY_PAUSE },
+ { 0x10ed03, KEY_MEDIA_REPEAT},
+ { 0x10ed02, KEY_PAUSE },
+ { 0x10ed5e, KEY_VOLUMEUP },
+ { 0x10ed5c, KEY_VOLUMEDOWN },
+ { 0x10ed09, KEY_CHANNELUP },
+ { 0x10ed1a, KEY_CHANNELDOWN },
+ { 0x10ed1e, KEY_PLAY },
+ { 0x10ed1b, KEY_ZOOM },
+ { 0x10ed59, KEY_MUTE },
+ { 0x10ed5a, KEY_TV },
+ { 0x10ed18, KEY_RECORD },
+ { 0x10ed07, KEY_EPG },
+ { 0x10ed01, KEY_STOP },
/* Type 2 - 20 buttons */
- { 0xff40ea15, KEY_0 },
- { 0xff40f708, KEY_1 },
- { 0xff40f609, KEY_2 },
- { 0xff40f50a, KEY_3 },
- { 0xff40f30c, KEY_4 },
- { 0xff40f20d, KEY_5 },
- { 0xff40f10e, KEY_6 },
- { 0xff40ef10, KEY_7 },
- { 0xff40ee11, KEY_8 },
- { 0xff40ed12, KEY_9 },
- { 0xff40ff00, KEY_POWER },
- { 0xff40fb04, KEY_MEDIA_REPEAT}, /* Recall */
- { 0xff40e51a, KEY_PAUSE }, /* Timeshift */
- { 0xff40fd02, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */
- { 0xff40f906, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/
- { 0xff40fe01, KEY_CHANNELUP },
- { 0xff40fa05, KEY_CHANNELDOWN },
- { 0xff40eb14, KEY_ZOOM },
- { 0xff40e718, KEY_RECORD },
- { 0xff40e916, KEY_STOP },
+ { 0xbf15, KEY_0 },
+ { 0xbf08, KEY_1 },
+ { 0xbf09, KEY_2 },
+ { 0xbf0a, KEY_3 },
+ { 0xbf0c, KEY_4 },
+ { 0xbf0d, KEY_5 },
+ { 0xbf0e, KEY_6 },
+ { 0xbf10, KEY_7 },
+ { 0xbf11, KEY_8 },
+ { 0xbf12, KEY_9 },
+ { 0xbf00, KEY_POWER },
+ { 0xbf04, KEY_MEDIA_REPEAT}, /* Recall */
+ { 0xbf1a, KEY_PAUSE }, /* Timeshift */
+ { 0xbf02, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */
+ { 0xbf06, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/
+ { 0xbf01, KEY_CHANNELUP },
+ { 0xbf05, KEY_CHANNELDOWN },
+ { 0xbf14, KEY_ZOOM },
+ { 0xbf18, KEY_RECORD },
+ { 0xbf16, KEY_STOP },
/* Type 3 - 20 buttons */
- { 0xff00e31c, KEY_0 },
- { 0xff00f807, KEY_1 },
- { 0xff00ea15, KEY_2 },
- { 0xff00f609, KEY_3 },
- { 0xff00e916, KEY_4 },
- { 0xff00e619, KEY_5 },
- { 0xff00f20d, KEY_6 },
- { 0xff00f30c, KEY_7 },
- { 0xff00e718, KEY_8 },
- { 0xff00a15e, KEY_9 },
- { 0xff00ba45, KEY_POWER },
- { 0xff00bb44, KEY_MEDIA_REPEAT}, /* Recall */
- { 0xff00b54a, KEY_PAUSE }, /* Timeshift */
- { 0xff00b847, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */
- { 0xff00bc43, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/
- { 0xff00b946, KEY_CHANNELUP },
- { 0xff00bf40, KEY_CHANNELDOWN },
- { 0xff00f708, KEY_ZOOM },
- { 0xff00bd42, KEY_RECORD },
- { 0xff00a55a, KEY_STOP },
+ { 0x1c, KEY_0 },
+ { 0x07, KEY_1 },
+ { 0x15, KEY_2 },
+ { 0x09, KEY_3 },
+ { 0x16, KEY_4 },
+ { 0x19, KEY_5 },
+ { 0x0d, KEY_6 },
+ { 0x0c, KEY_7 },
+ { 0x18, KEY_8 },
+ { 0x5e, KEY_9 },
+ { 0x45, KEY_POWER },
+ { 0x44, KEY_MEDIA_REPEAT}, /* Recall */
+ { 0x4a, KEY_PAUSE }, /* Timeshift */
+ { 0x47, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */
+ { 0x43, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/
+ { 0x46, KEY_CHANNELUP },
+ { 0x40, KEY_CHANNELDOWN },
+ { 0x08, KEY_ZOOM },
+ { 0x42, KEY_RECORD },
+ { 0x5a, KEY_STOP },
};
static struct rc_map_list lme2510_map = {
.map = {
.scan = lme2510_rc,
.size = ARRAY_SIZE(lme2510_rc),
- .rc_type = RC_TYPE_UNKNOWN,
+ .rc_type = RC_TYPE_NEC,
.name = RC_MAP_LME2510,
}
};
diff --git a/drivers/media/rc/keymaps/rc-rc6-mce.c b/drivers/media/rc/keymaps/rc-rc6-mce.c
index 8dd519ecc58e..01b69bcc8666 100644
--- a/drivers/media/rc/keymaps/rc-rc6-mce.c
+++ b/drivers/media/rc/keymaps/rc-rc6-mce.c
@@ -30,7 +30,7 @@ static struct rc_map_table rc6_mce[] = {
{ 0x800f040a, KEY_DELETE },
{ 0x800f040b, KEY_ENTER },
{ 0x800f040c, KEY_POWER }, /* PC Power */
- { 0x800f040d, KEY_LEFTMETA }, /* Windows MCE button */
+ { 0x800f040d, KEY_MEDIA }, /* Windows MCE button */
{ 0x800f040e, KEY_MUTE },
{ 0x800f040f, KEY_INFO },
@@ -87,7 +87,7 @@ static struct rc_map_table rc6_mce[] = {
{ 0x800f0465, KEY_POWER2 }, /* TV Power */
{ 0x800f046e, KEY_PLAYPAUSE },
- { 0x800f046f, KEY_MEDIA }, /* Start media application (NEW) */
+ { 0x800f046f, KEY_PLAYER }, /* Start media application (NEW) */
{ 0x800f0480, KEY_BRIGHTNESSDOWN },
{ 0x800f0481, KEY_PLAYPAUSE },
diff --git a/drivers/media/rc/keymaps/rc-tivo.c b/drivers/media/rc/keymaps/rc-tivo.c
new file mode 100644
index 000000000000..98ad085531fd
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-tivo.c
@@ -0,0 +1,98 @@
+/* rc-tivo.c - Keytable for TiVo remotes
+ *
+ * Copyright (c) 2011 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>
+
+/*
+ * Initial mapping is for the TiVo remote included in the Nero LiquidTV bundle,
+ * which also ships with a TiVo-branded IR transceiver, supported by the mceusb
+ * driver. Note that the remote uses an NEC-ish protocol, but instead of having
+ * a command/not_command pair, it has a vendor ID of 0xa10c, but some keys, the
+ * NEC extended checksums do pass, so the table presently has the intended
+ * values and the checksum-passed versions for those keys.
+ */
+static struct rc_map_table tivo[] = {
+ { 0xa10c900f, KEY_MEDIA }, /* TiVo Button */
+ { 0xa10c0807, KEY_POWER2 }, /* TV Power */
+ { 0xa10c8807, KEY_TV }, /* Live TV/Swap */
+ { 0xa10c2c03, KEY_VIDEO_NEXT }, /* TV Input */
+ { 0xa10cc807, KEY_INFO },
+ { 0xa10cfa05, KEY_CYCLEWINDOWS }, /* Window */
+ { 0x0085305f, KEY_CYCLEWINDOWS },
+ { 0xa10c6c03, KEY_EPG }, /* Guide */
+
+ { 0xa10c2807, KEY_UP },
+ { 0xa10c6807, KEY_DOWN },
+ { 0xa10ce807, KEY_LEFT },
+ { 0xa10ca807, KEY_RIGHT },
+
+ { 0xa10c1807, KEY_SCROLLDOWN }, /* Red Thumbs Down */
+ { 0xa10c9807, KEY_SELECT },
+ { 0xa10c5807, KEY_SCROLLUP }, /* Green Thumbs Up */
+
+ { 0xa10c3807, KEY_VOLUMEUP },
+ { 0xa10cb807, KEY_VOLUMEDOWN },
+ { 0xa10cd807, KEY_MUTE },
+ { 0xa10c040b, KEY_RECORD },
+ { 0xa10c7807, KEY_CHANNELUP },
+ { 0xa10cf807, KEY_CHANNELDOWN },
+ { 0x0085301f, KEY_CHANNELDOWN },
+
+ { 0xa10c840b, KEY_PLAY },
+ { 0xa10cc40b, KEY_PAUSE },
+ { 0xa10ca40b, KEY_SLOW },
+ { 0xa10c440b, KEY_REWIND },
+ { 0xa10c240b, KEY_FASTFORWARD },
+ { 0xa10c640b, KEY_PREVIOUS },
+ { 0xa10ce40b, KEY_NEXT }, /* ->| */
+
+ { 0xa10c220d, KEY_ZOOM }, /* Aspect */
+ { 0xa10c120d, KEY_STOP },
+ { 0xa10c520d, KEY_DVD }, /* DVD Menu */
+
+ { 0xa10c140b, KEY_NUMERIC_1 },
+ { 0xa10c940b, KEY_NUMERIC_2 },
+ { 0xa10c540b, KEY_NUMERIC_3 },
+ { 0xa10cd40b, KEY_NUMERIC_4 },
+ { 0xa10c340b, KEY_NUMERIC_5 },
+ { 0xa10cb40b, KEY_NUMERIC_6 },
+ { 0xa10c740b, KEY_NUMERIC_7 },
+ { 0xa10cf40b, KEY_NUMERIC_8 },
+ { 0x0085302f, KEY_NUMERIC_8 },
+ { 0xa10c0c03, KEY_NUMERIC_9 },
+ { 0xa10c8c03, KEY_NUMERIC_0 },
+ { 0xa10ccc03, KEY_ENTER },
+ { 0xa10c4c03, KEY_CLEAR },
+};
+
+static struct rc_map_list tivo_map = {
+ .map = {
+ .scan = tivo,
+ .size = ARRAY_SIZE(tivo),
+ .rc_type = RC_TYPE_NEC,
+ .name = RC_MAP_TIVO,
+ }
+};
+
+static int __init init_rc_map_tivo(void)
+{
+ return rc_map_register(&tivo_map);
+}
+
+static void __exit exit_rc_map_tivo(void)
+{
+ rc_map_unregister(&tivo_map);
+}
+
+module_init(init_rc_map_tivo)
+module_exit(exit_rc_map_tivo)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-winfast.c b/drivers/media/rc/keymaps/rc-winfast.c
index 0062ca291959..d8a34c14676a 100644
--- a/drivers/media/rc/keymaps/rc-winfast.c
+++ b/drivers/media/rc/keymaps/rc-winfast.c
@@ -32,8 +32,8 @@ static struct rc_map_table winfast[] = {
{ 0x02, KEY_TUNER }, /* TV/FM, not on Y0400052 */
{ 0x1e, KEY_VIDEO }, /* Video Source */
{ 0x16, KEY_INFO }, /* Display information */
- { 0x04, KEY_LEFT },
- { 0x08, KEY_RIGHT },
+ { 0x04, KEY_RIGHT },
+ { 0x08, KEY_LEFT },
{ 0x0c, KEY_UP },
{ 0x10, KEY_DOWN },
{ 0x03, KEY_ZOOM }, /* fullscreen */
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 0c273ec465c9..ad927fcaa020 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -149,6 +149,8 @@ enum mceusb_model_type {
POLARIS_EVK,
CX_HYBRID_TV,
MULTIFUNCTION,
+ TIVO_KIT,
+ MCE_GEN2_NO_TX,
};
struct mceusb_model {
@@ -172,6 +174,10 @@ static const struct mceusb_model mceusb_model[] = {
[MCE_GEN2] = {
.mce_gen2 = 1,
},
+ [MCE_GEN2_NO_TX] = {
+ .mce_gen2 = 1,
+ .no_tx = 1,
+ },
[MCE_GEN2_TX_INV] = {
.mce_gen2 = 1,
.tx_mask_normal = 1,
@@ -197,6 +203,10 @@ static const struct mceusb_model mceusb_model[] = {
.mce_gen2 = 1,
.ir_intfnum = 2,
},
+ [TIVO_KIT] = {
+ .mce_gen2 = 1,
+ .rc_map = RC_MAP_TIVO,
+ },
};
static struct usb_device_id mceusb_dev_table[] = {
@@ -279,7 +289,8 @@ static struct usb_device_id mceusb_dev_table[] = {
/* Formosa21 / eHome Infrared Receiver */
{ USB_DEVICE(VENDOR_FORMOSA, 0xe016) },
/* Formosa aim / Trust MCE Infrared Receiver */
- { USB_DEVICE(VENDOR_FORMOSA, 0xe017) },
+ { USB_DEVICE(VENDOR_FORMOSA, 0xe017),
+ .driver_info = MCE_GEN2_NO_TX },
/* Formosa Industrial Computing / Beanbag Emulation Device */
{ USB_DEVICE(VENDOR_FORMOSA, 0xe018) },
/* Formosa21 / eHome Infrared Receiver */
@@ -308,7 +319,8 @@ static struct usb_device_id mceusb_dev_table[] = {
/* Northstar Systems, Inc. eHome Infrared Transceiver */
{ USB_DEVICE(VENDOR_NORTHSTAR, 0xe004) },
/* TiVo PC IR Receiver */
- { USB_DEVICE(VENDOR_TIVO, 0x2000) },
+ { USB_DEVICE(VENDOR_TIVO, 0x2000),
+ .driver_info = TIVO_KIT },
/* Conexant Hybrid TV "Shelby" Polaris SDK */
{ USB_DEVICE(VENDOR_CONEXANT, 0x58a1),
.driver_info = POLARIS_EVK },
@@ -603,11 +615,10 @@ static void mce_async_callback(struct urb *urb, struct pt_regs *regs)
}
/* 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)
+static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data,
+ int size, int urb_type)
{
- int res;
+ int res, pipe;
struct urb *async_urb;
struct device *dev = ir->dev;
unsigned char *async_buf;
@@ -627,10 +638,11 @@ static void mce_request_packet(struct mceusb_dev *ir,
}
/* outbound data */
- usb_fill_int_urb(async_urb, ir->usbdev,
- usb_sndintpipe(ir->usbdev, ep->bEndpointAddress),
+ pipe = usb_sndintpipe(ir->usbdev,
+ ir->usb_ep_out->bEndpointAddress);
+ usb_fill_int_urb(async_urb, ir->usbdev, pipe,
async_buf, size, (usb_complete_t)mce_async_callback,
- ir, ep->bInterval);
+ ir, ir->usb_ep_out->bInterval);
memcpy(async_buf, data, size);
} else if (urb_type == MCEUSB_RX) {
@@ -658,12 +670,12 @@ static void mce_request_packet(struct mceusb_dev *ir,
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);
+ mce_request_packet(ir, 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);
+ mce_request_packet(ir, data, size, MCEUSB_RX);
}
/* Send data out the IR blaster port(s) */
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index d4d64492a057..bf3060ea6107 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -37,8 +37,6 @@
#include "nuvoton-cir.h"
-static char *chip_id = "w836x7hg";
-
/* write val to config reg */
static inline void nvt_cr_write(struct nvt_dev *nvt, u8 val, u8 reg)
{
@@ -233,6 +231,8 @@ static int nvt_hw_detect(struct nvt_dev *nvt)
unsigned long flags;
u8 chip_major, chip_minor;
int ret = 0;
+ char chip_id[12];
+ bool chip_unknown = false;
nvt_efm_enable(nvt);
@@ -246,15 +246,39 @@ static int nvt_hw_detect(struct nvt_dev *nvt)
}
chip_minor = nvt_cr_read(nvt, CR_CHIP_ID_LO);
- nvt_dbg("%s: chip id: 0x%02x 0x%02x", chip_id, chip_major, chip_minor);
- if (chip_major != CHIP_ID_HIGH ||
- (chip_minor != CHIP_ID_LOW && chip_minor != CHIP_ID_LOW2)) {
- nvt_pr(KERN_ERR, "%s: unsupported chip, id: 0x%02x 0x%02x",
- chip_id, chip_major, chip_minor);
- ret = -ENODEV;
+ /* these are the known working chip revisions... */
+ switch (chip_major) {
+ case CHIP_ID_HIGH_667:
+ strcpy(chip_id, "w83667hg\0");
+ if (chip_minor != CHIP_ID_LOW_667)
+ chip_unknown = true;
+ break;
+ case CHIP_ID_HIGH_677B:
+ strcpy(chip_id, "w83677hg\0");
+ if (chip_minor != CHIP_ID_LOW_677B2 &&
+ chip_minor != CHIP_ID_LOW_677B3)
+ chip_unknown = true;
+ break;
+ case CHIP_ID_HIGH_677C:
+ strcpy(chip_id, "w83677hg-c\0");
+ if (chip_minor != CHIP_ID_LOW_677C)
+ chip_unknown = true;
+ break;
+ default:
+ strcpy(chip_id, "w836x7hg\0");
+ chip_unknown = true;
+ break;
}
+ /* warn, but still let the driver load, if we don't know this chip */
+ if (chip_unknown)
+ nvt_pr(KERN_WARNING, "%s: unknown chip, id: 0x%02x 0x%02x, "
+ "it may not work...", chip_id, chip_major, chip_minor);
+ else
+ nvt_dbg("%s: chip id: 0x%02x 0x%02x",
+ chip_id, chip_major, chip_minor);
+
nvt_efm_disable(nvt);
spin_lock_irqsave(&nvt->nvt_lock, flags);
@@ -267,13 +291,23 @@ static int nvt_hw_detect(struct nvt_dev *nvt)
static void nvt_cir_ldev_init(struct nvt_dev *nvt)
{
- u8 val;
+ u8 val, psreg, psmask, psval;
+
+ if (nvt->chip_major == CHIP_ID_HIGH_667) {
+ psreg = CR_MULTIFUNC_PIN_SEL;
+ psmask = MULTIFUNC_PIN_SEL_MASK;
+ psval = MULTIFUNC_ENABLE_CIR | MULTIFUNC_ENABLE_CIRWB;
+ } else {
+ psreg = CR_OUTPUT_PIN_SEL;
+ psmask = OUTPUT_PIN_SEL_MASK;
+ psval = OUTPUT_ENABLE_CIR | OUTPUT_ENABLE_CIRWB;
+ }
- /* output pin selection (Pin95=CIRRX, Pin96=CIRTX1, WB enabled */
- val = nvt_cr_read(nvt, CR_OUTPUT_PIN_SEL);
- val &= OUTPUT_PIN_SEL_MASK;
- val |= (OUTPUT_ENABLE_CIR | OUTPUT_ENABLE_CIRWB);
- nvt_cr_write(nvt, val, CR_OUTPUT_PIN_SEL);
+ /* output pin selection: enable CIR, with WB sensor enabled */
+ val = nvt_cr_read(nvt, psreg);
+ val &= psmask;
+ val |= psval;
+ nvt_cr_write(nvt, val, psreg);
/* Select CIR logical device and enable */
nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
@@ -640,7 +674,7 @@ static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
rawir.pulse ? "pulse" : "space",
rawir.duration);
- ir_raw_event_store(nvt->rdev, &rawir);
+ ir_raw_event_store_with_filter(nvt->rdev, &rawir);
}
/*
@@ -1070,18 +1104,20 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
rdev->tx_ir = nvt_tx_ir;
rdev->s_tx_carrier = nvt_set_tx_carrier;
rdev->input_name = "Nuvoton w836x7hg Infrared Remote Transceiver";
+ rdev->input_phys = "nuvoton/cir0";
rdev->input_id.bustype = BUS_HOST;
rdev->input_id.vendor = PCI_VENDOR_ID_WINBOND2;
rdev->input_id.product = nvt->chip_major;
rdev->input_id.version = nvt->chip_minor;
+ rdev->dev.parent = &pdev->dev;
rdev->driver_name = NVT_DRIVER_NAME;
rdev->map_name = RC_MAP_RC6_MCE;
+ rdev->timeout = US_TO_NS(1000);
+ /* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */
+ rdev->rx_resolution = US_TO_NS(CIR_SAMPLE_PERIOD);
#if 0
rdev->min_timeout = XYZ;
rdev->max_timeout = XYZ;
- rdev->timeout = XYZ;
- /* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */
- rdev->rx_resolution = XYZ;
/* tx bits */
rdev->tx_resolution = XYZ;
#endif
@@ -1090,8 +1126,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
if (ret)
goto failure;
- device_set_wakeup_capable(&pdev->dev, 1);
- device_set_wakeup_enable(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, true);
nvt->rdev = rdev;
nvt_pr(KERN_NOTICE, "driver has been successfully loaded\n");
if (debug) {
diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h
index 048135eea702..379795d61ea7 100644
--- a/drivers/media/rc/nuvoton-cir.h
+++ b/drivers/media/rc/nuvoton-cir.h
@@ -330,9 +330,13 @@ struct nvt_dev {
#define EFER_EFM_DISABLE 0xaa
/* Chip IDs found in CR_CHIP_ID_{HI,LO} */
-#define CHIP_ID_HIGH 0xb4
-#define CHIP_ID_LOW 0x72
-#define CHIP_ID_LOW2 0x73
+#define CHIP_ID_HIGH_667 0xa5
+#define CHIP_ID_HIGH_677B 0xb4
+#define CHIP_ID_HIGH_677C 0xc3
+#define CHIP_ID_LOW_667 0x13
+#define CHIP_ID_LOW_677B2 0x72
+#define CHIP_ID_LOW_677B3 0x73
+#define CHIP_ID_LOW_677C 0x33
/* Config regs we need to care about */
#define CR_SOFTWARE_RESET 0x02
@@ -341,6 +345,7 @@ struct nvt_dev {
#define CR_CHIP_ID_LO 0x21
#define CR_DEV_POWER_DOWN 0x22 /* bit 2 is CIR power, default power on */
#define CR_OUTPUT_PIN_SEL 0x27
+#define CR_MULTIFUNC_PIN_SEL 0x2c
#define CR_LOGICAL_DEV_EN 0x30 /* valid for all logical devices */
/* next three regs valid for both the CIR and CIR_WAKE logical devices */
#define CR_CIR_BASE_ADDR_HI 0x60
@@ -364,10 +369,16 @@ struct nvt_dev {
#define CIR_INTR_MOUSE_IRQ_BIT 0x80
#define PME_INTR_CIR_PASS_BIT 0x08
+/* w83677hg CIR pin config */
#define OUTPUT_PIN_SEL_MASK 0xbc
#define OUTPUT_ENABLE_CIR 0x01 /* Pin95=CIRRX, Pin96=CIRTX1 */
#define OUTPUT_ENABLE_CIRWB 0x40 /* enable wide-band sensor */
+/* w83667hg CIR pin config */
+#define MULTIFUNC_PIN_SEL_MASK 0x1f
+#define MULTIFUNC_ENABLE_CIR 0x80 /* Pin75=CIRRX, Pin76=CIRTX1 */
+#define MULTIFUNC_ENABLE_CIRWB 0x20 /* enable wide-band sensor */
+
/* MCE CIR signal length, related on sample period */
/* MCE CIR controller signal length: about 43ms
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index 49cee61d79c6..cc846b2619cf 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -146,6 +146,12 @@ static int loop_tx_ir(struct rc_dev *dev, int *txbuf, u32 n)
if (rawir.duration)
ir_raw_event_store_with_filter(dev, &rawir);
}
+
+ /* Fake a silence long enough to cause us to go idle */
+ rawir.pulse = false;
+ rawir.duration = dev->timeout;
+ ir_raw_event_store_with_filter(dev, &rawir);
+
ir_raw_event_handle(dev);
out:
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index a2706648e365..f57cd5677ac2 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -749,6 +749,9 @@ static struct {
* it is trigged by reading /sys/class/rc/rc?/protocols.
* It returns the protocol names of supported protocols.
* Enabled protocols are printed in brackets.
+ *
+ * dev->lock is taken to guard against races between device
+ * registration, store_protocols and show_protocols.
*/
static ssize_t show_protocols(struct device *device,
struct device_attribute *mattr, char *buf)
@@ -762,6 +765,8 @@ static ssize_t show_protocols(struct device *device,
if (!dev)
return -EINVAL;
+ mutex_lock(&dev->lock);
+
if (dev->driver_type == RC_DRIVER_SCANCODE) {
enabled = dev->rc_map.rc_type;
allowed = dev->allowed_protos;
@@ -784,6 +789,9 @@ static ssize_t show_protocols(struct device *device,
if (tmp != buf)
tmp--;
*tmp = '\n';
+
+ mutex_unlock(&dev->lock);
+
return tmp + 1 - buf;
}
@@ -802,6 +810,9 @@ static ssize_t show_protocols(struct device *device,
* Writing "none" will disable all protocols.
* Returns -EINVAL if an invalid protocol combination or unknown protocol name
* is used, otherwise @len.
+ *
+ * dev->lock is taken to guard against races between device
+ * registration, store_protocols and show_protocols.
*/
static ssize_t store_protocols(struct device *device,
struct device_attribute *mattr,
@@ -815,18 +826,22 @@ static ssize_t store_protocols(struct device *device,
u64 mask;
int rc, i, count = 0;
unsigned long flags;
+ ssize_t ret;
/* Device is being removed */
if (!dev)
return -EINVAL;
+ mutex_lock(&dev->lock);
+
if (dev->driver_type == RC_DRIVER_SCANCODE)
type = dev->rc_map.rc_type;
else if (dev->raw)
type = dev->raw->enabled_protocols;
else {
IR_dprintk(1, "Protocol switching not supported\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
while ((tmp = strsep((char **) &data, " \n")) != NULL) {
@@ -860,7 +875,8 @@ static ssize_t store_protocols(struct device *device,
}
if (i == ARRAY_SIZE(proto_names)) {
IR_dprintk(1, "Unknown protocol: '%s'\n", tmp);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
count++;
}
@@ -875,7 +891,8 @@ static ssize_t store_protocols(struct device *device,
if (!count) {
IR_dprintk(1, "Protocol not specified\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
if (dev->change_protocol) {
@@ -883,7 +900,8 @@ static ssize_t store_protocols(struct device *device,
if (rc < 0) {
IR_dprintk(1, "Error setting protocols to 0x%llx\n",
(long long)type);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
}
@@ -898,7 +916,11 @@ static ssize_t store_protocols(struct device *device,
IR_dprintk(1, "Current protocol(s): 0x%llx\n",
(long long)type);
- return len;
+ ret = len;
+
+out:
+ mutex_unlock(&dev->lock);
+ return ret;
}
static void rc_dev_release(struct device *device)
@@ -974,6 +996,7 @@ struct rc_dev *rc_allocate_device(void)
spin_lock_init(&dev->rc_map.lock);
spin_lock_init(&dev->keylock);
+ mutex_init(&dev->lock);
setup_timer(&dev->timer_keyup, ir_timer_keyup, (unsigned long)dev);
dev->dev.type = &rc_dev_type;
@@ -1019,12 +1042,21 @@ int rc_register_device(struct rc_dev *dev)
if (dev->close)
dev->input_dev->close = ir_close;
+ /*
+ * Take the lock here, as the device sysfs node will appear
+ * when device_add() is called, which may trigger an ir-keytable udev
+ * rule, which will in turn call show_protocols and access either
+ * dev->rc_map.rc_type or dev->raw->enabled_protocols before it has
+ * been initialized.
+ */
+ mutex_lock(&dev->lock);
+
dev->devno = (unsigned long)(atomic_inc_return(&devno) - 1);
dev_set_name(&dev->dev, "rc%ld", dev->devno);
dev_set_drvdata(&dev->dev, dev);
rc = device_add(&dev->dev);
if (rc)
- return rc;
+ goto out_unlock;
rc = ir_setkeytable(dev, rc_map);
if (rc)
@@ -1046,6 +1078,13 @@ int rc_register_device(struct rc_dev *dev)
*/
dev->input_dev->rep[REP_DELAY] = 500;
+ /*
+ * As a repeat event on protocols like RC-5 and NEC take as long as
+ * 110/114ms, using 33ms as a repeat period is not the right thing
+ * to do.
+ */
+ dev->input_dev->rep[REP_PERIOD] = 125;
+
path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
printk(KERN_INFO "%s: %s as %s\n",
dev_name(&dev->dev),
@@ -1058,6 +1097,7 @@ int rc_register_device(struct rc_dev *dev)
if (rc < 0)
goto out_input;
}
+ mutex_unlock(&dev->lock);
if (dev->change_protocol) {
rc = dev->change_protocol(dev, rc_map->rc_type);
@@ -1083,6 +1123,8 @@ out_table:
ir_free_table(&dev->rc_map);
out_dev:
device_del(&dev->dev);
+out_unlock:
+ mutex_unlock(&dev->lock);
return rc;
}
EXPORT_SYMBOL_GPL(rc_register_device);
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
new file mode 100644
index 000000000000..5147767ccb78
--- /dev/null
+++ b/drivers/media/rc/redrat3.c
@@ -0,0 +1,1344 @@
+/*
+ * USB RedRat3 IR Transceiver rc-core driver
+ *
+ * Copyright (c) 2011 by Jarod Wilson <jarod@redhat.com>
+ * based heavily on the work of Stephen Cox, with additional
+ * help from RedRat Ltd.
+ *
+ * This driver began life based an an old version of the first-generation
+ * lirc_mceusb driver from the lirc 0.7.2 distribution. It was then
+ * significantly rewritten by Stephen Cox with the aid of RedRat Ltd's
+ * Chris Dodge.
+ *
+ * The driver was then ported to rc-core and significantly rewritten again,
+ * by Jarod, using the in-kernel mceusb driver as a guide, after an initial
+ * port effort was started by Stephen.
+ *
+ * TODO LIST:
+ * - fix lirc not showing repeats properly
+ * --
+ *
+ * The RedRat3 is a USB transceiver with both send & receive,
+ * with 2 separate sensors available for receive to enable
+ * both good long range reception for general use, and good
+ * short range reception when required for learning a signal.
+ *
+ * http://www.redrat.co.uk/
+ *
+ * It uses its own little protocol to communicate, the required
+ * parts of which are embedded within this 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/device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+#include <media/rc-core.h>
+
+/* Driver Information */
+#define DRIVER_VERSION "0.70"
+#define DRIVER_AUTHOR "Jarod Wilson <jarod@redhat.com>"
+#define DRIVER_AUTHOR2 "The Dweller, Stephen Cox"
+#define DRIVER_DESC "RedRat3 USB IR Transceiver Driver"
+#define DRIVER_NAME "redrat3"
+
+/* module parameters */
+#ifdef CONFIG_USB_DEBUG
+static int debug = 1;
+#else
+static int debug;
+#endif
+
+#define RR3_DEBUG_STANDARD 0x1
+#define RR3_DEBUG_FUNCTION_TRACE 0x2
+
+#define rr3_dbg(dev, fmt, ...) \
+ do { \
+ if (debug & RR3_DEBUG_STANDARD) \
+ dev_info(dev, fmt, ## __VA_ARGS__); \
+ } while (0)
+
+#define rr3_ftr(dev, fmt, ...) \
+ do { \
+ if (debug & RR3_DEBUG_FUNCTION_TRACE) \
+ dev_info(dev, fmt, ## __VA_ARGS__); \
+ } while (0)
+
+/* bulk data transfer types */
+#define RR3_ERROR 0x01
+#define RR3_MOD_SIGNAL_IN 0x20
+#define RR3_MOD_SIGNAL_OUT 0x21
+
+/* Get the RR firmware version */
+#define RR3_FW_VERSION 0xb1
+#define RR3_FW_VERSION_LEN 64
+/* Send encoded signal bulk-sent earlier*/
+#define RR3_TX_SEND_SIGNAL 0xb3
+#define RR3_SET_IR_PARAM 0xb7
+#define RR3_GET_IR_PARAM 0xb8
+/* Blink the red LED on the device */
+#define RR3_BLINK_LED 0xb9
+/* Read serial number of device */
+#define RR3_READ_SER_NO 0xba
+#define RR3_SER_NO_LEN 4
+/* Start capture with the RC receiver */
+#define RR3_RC_DET_ENABLE 0xbb
+/* Stop capture with the RC receiver */
+#define RR3_RC_DET_DISABLE 0xbc
+/* Return the status of RC detector capture */
+#define RR3_RC_DET_STATUS 0xbd
+/* Reset redrat */
+#define RR3_RESET 0xa0
+
+/* Max number of lengths in the signal. */
+#define RR3_IR_IO_MAX_LENGTHS 0x01
+/* Periods to measure mod. freq. */
+#define RR3_IR_IO_PERIODS_MF 0x02
+/* Size of memory for main signal data */
+#define RR3_IR_IO_SIG_MEM_SIZE 0x03
+/* Delta value when measuring lengths */
+#define RR3_IR_IO_LENGTH_FUZZ 0x04
+/* Timeout for end of signal detection */
+#define RR3_IR_IO_SIG_TIMEOUT 0x05
+/* Minumum value for pause recognition. */
+#define RR3_IR_IO_MIN_PAUSE 0x06
+
+/* Clock freq. of EZ-USB chip */
+#define RR3_CLK 24000000
+/* Clock periods per timer count */
+#define RR3_CLK_PER_COUNT 12
+/* (RR3_CLK / RR3_CLK_PER_COUNT) */
+#define RR3_CLK_CONV_FACTOR 2000000
+/* USB bulk-in IR data endpoint address */
+#define RR3_BULK_IN_EP_ADDR 0x82
+
+/* Raw Modulated signal data value offsets */
+#define RR3_PAUSE_OFFSET 0
+#define RR3_FREQ_COUNT_OFFSET 4
+#define RR3_NUM_PERIOD_OFFSET 6
+#define RR3_MAX_LENGTHS_OFFSET 8
+#define RR3_NUM_LENGTHS_OFFSET 9
+#define RR3_MAX_SIGS_OFFSET 10
+#define RR3_NUM_SIGS_OFFSET 12
+#define RR3_REPEATS_OFFSET 14
+
+/* Size of the fixed-length portion of the signal */
+#define RR3_HEADER_LENGTH 15
+#define RR3_DRIVER_MAXLENS 128
+#define RR3_MAX_SIG_SIZE 512
+#define RR3_MAX_BUF_SIZE \
+ ((2 * RR3_HEADER_LENGTH) + RR3_DRIVER_MAXLENS + RR3_MAX_SIG_SIZE)
+#define RR3_TIME_UNIT 50
+#define RR3_END_OF_SIGNAL 0x7f
+#define RR3_TX_HEADER_OFFSET 4
+#define RR3_TX_TRAILER_LEN 2
+#define RR3_RX_MIN_TIMEOUT 5
+#define RR3_RX_MAX_TIMEOUT 2000
+
+/* The 8051's CPUCS Register address */
+#define RR3_CPUCS_REG_ADDR 0x7f92
+
+#define USB_RR3USB_VENDOR_ID 0x112a
+#define USB_RR3USB_PRODUCT_ID 0x0001
+#define USB_RR3IIUSB_PRODUCT_ID 0x0005
+
+/* table of devices that work with this driver */
+static struct usb_device_id redrat3_dev_table[] = {
+ /* Original version of the RedRat3 */
+ {USB_DEVICE(USB_RR3USB_VENDOR_ID, USB_RR3USB_PRODUCT_ID)},
+ /* Second Version/release of the RedRat3 - RetRat3-II */
+ {USB_DEVICE(USB_RR3USB_VENDOR_ID, USB_RR3IIUSB_PRODUCT_ID)},
+ {} /* Terminating entry */
+};
+
+/* Structure to hold all of our device specific stuff */
+struct redrat3_dev {
+ /* core device bits */
+ struct rc_dev *rc;
+ struct device *dev;
+
+ /* save off the usb device pointer */
+ struct usb_device *udev;
+
+ /* the receive endpoint */
+ struct usb_endpoint_descriptor *ep_in;
+ /* the buffer to receive data */
+ unsigned char *bulk_in_buf;
+ /* urb used to read ir data */
+ struct urb *read_urb;
+
+ /* the send endpoint */
+ struct usb_endpoint_descriptor *ep_out;
+ /* the buffer to send data */
+ unsigned char *bulk_out_buf;
+ /* the urb used to send data */
+ struct urb *write_urb;
+
+ /* usb dma */
+ dma_addr_t dma_in;
+ dma_addr_t dma_out;
+
+ /* true if write urb is busy */
+ bool write_busy;
+ /* wait for the write to finish */
+ struct completion write_finished;
+
+ /* locks this structure */
+ struct mutex lock;
+
+ /* rx signal timeout timer */
+ struct timer_list rx_timeout;
+
+ /* Is the device currently receiving? */
+ bool recv_in_progress;
+ /* is the detector enabled*/
+ bool det_enabled;
+ /* Is the device currently transmitting?*/
+ bool transmitting;
+
+ /* store for current packet */
+ char pbuf[RR3_MAX_BUF_SIZE];
+ u16 pktlen;
+ u16 pkttype;
+ u16 bytes_read;
+ /* indicate whether we are going to reprocess
+ * the USB callback with a bigger buffer */
+ int buftoosmall;
+ char *datap;
+
+ u32 carrier;
+
+ char name[128];
+ char phys[64];
+};
+
+/* All incoming data buffers adhere to a very specific data format */
+struct redrat3_signal_header {
+ u16 length; /* Length of data being transferred */
+ u16 transfer_type; /* Type of data transferred */
+ u32 pause; /* Pause between main and repeat signals */
+ u16 mod_freq_count; /* Value of timer on mod. freq. measurement */
+ u16 no_periods; /* No. of periods over which mod. freq. is measured */
+ u8 max_lengths; /* Max no. of lengths (i.e. size of array) */
+ u8 no_lengths; /* Actual no. of elements in lengths array */
+ u16 max_sig_size; /* Max no. of values in signal data array */
+ u16 sig_size; /* Acuto no. of values in signal data array */
+ u8 no_repeats; /* No. of repeats of repeat signal section */
+ /* Here forward is the lengths and signal data */
+};
+
+static void redrat3_dump_signal_header(struct redrat3_signal_header *header)
+{
+ pr_info("%s:\n", __func__);
+ pr_info(" * length: %u, transfer_type: 0x%02x\n",
+ header->length, header->transfer_type);
+ pr_info(" * pause: %u, freq_count: %u, no_periods: %u\n",
+ header->pause, header->mod_freq_count, header->no_periods);
+ pr_info(" * lengths: %u (max: %u)\n",
+ header->no_lengths, header->max_lengths);
+ pr_info(" * sig_size: %u (max: %u)\n",
+ header->sig_size, header->max_sig_size);
+ pr_info(" * repeats: %u\n", header->no_repeats);
+}
+
+static void redrat3_dump_signal_data(char *buffer, u16 len)
+{
+ int offset, i;
+ char *data_vals;
+
+ pr_info("%s:", __func__);
+
+ offset = RR3_TX_HEADER_OFFSET + RR3_HEADER_LENGTH
+ + (RR3_DRIVER_MAXLENS * sizeof(u16));
+
+ /* read RR3_DRIVER_MAXLENS from ctrl msg */
+ data_vals = buffer + offset;
+
+ for (i = 0; i < len; i++) {
+ if (i % 10 == 0)
+ pr_cont("\n * ");
+ pr_cont("%02x ", *data_vals++);
+ }
+
+ pr_cont("\n");
+}
+
+/*
+ * redrat3_issue_async
+ *
+ * Issues an async read to the ir data in port..
+ * sets the callback to be redrat3_handle_async
+ */
+static void redrat3_issue_async(struct redrat3_dev *rr3)
+{
+ int res;
+
+ rr3_ftr(rr3->dev, "Entering %s\n", __func__);
+
+ if (!rr3->det_enabled) {
+ dev_warn(rr3->dev, "not issuing async read, "
+ "detector not enabled\n");
+ return;
+ }
+
+ memset(rr3->bulk_in_buf, 0, rr3->ep_in->wMaxPacketSize);
+ res = usb_submit_urb(rr3->read_urb, GFP_ATOMIC);
+ if (res)
+ rr3_dbg(rr3->dev, "%s: receive request FAILED! "
+ "(res %d, len %d)\n", __func__, res,
+ rr3->read_urb->transfer_buffer_length);
+}
+
+static void redrat3_dump_fw_error(struct redrat3_dev *rr3, int code)
+{
+ if (!rr3->transmitting && (code != 0x40))
+ dev_info(rr3->dev, "fw error code 0x%02x: ", code);
+
+ switch (code) {
+ case 0x00:
+ pr_cont("No Error\n");
+ break;
+
+ /* Codes 0x20 through 0x2f are IR Firmware Errors */
+ case 0x20:
+ pr_cont("Initial signal pulse not long enough "
+ "to measure carrier frequency\n");
+ break;
+ case 0x21:
+ pr_cont("Not enough length values allocated for signal\n");
+ break;
+ case 0x22:
+ pr_cont("Not enough memory allocated for signal data\n");
+ break;
+ case 0x23:
+ pr_cont("Too many signal repeats\n");
+ break;
+ case 0x28:
+ pr_cont("Insufficient memory available for IR signal "
+ "data memory allocation\n");
+ break;
+ case 0x29:
+ pr_cont("Insufficient memory available "
+ "for IrDa signal data memory allocation\n");
+ break;
+
+ /* Codes 0x30 through 0x3f are USB Firmware Errors */
+ case 0x30:
+ pr_cont("Insufficient memory available for bulk "
+ "transfer structure\n");
+ break;
+
+ /*
+ * Other error codes... These are primarily errors that can occur in
+ * the control messages sent to the redrat
+ */
+ case 0x40:
+ if (!rr3->transmitting)
+ pr_cont("Signal capture has been terminated\n");
+ break;
+ case 0x41:
+ pr_cont("Attempt to set/get and unknown signal I/O "
+ "algorithm parameter\n");
+ break;
+ case 0x42:
+ pr_cont("Signal capture already started\n");
+ break;
+
+ default:
+ pr_cont("Unknown Error\n");
+ break;
+ }
+}
+
+static u32 redrat3_val_to_mod_freq(struct redrat3_signal_header *ph)
+{
+ u32 mod_freq = 0;
+
+ if (ph->mod_freq_count != 0)
+ mod_freq = (RR3_CLK * ph->no_periods) /
+ (ph->mod_freq_count * RR3_CLK_PER_COUNT);
+
+ return mod_freq;
+}
+
+/* this function scales down the figures for the same result... */
+static u32 redrat3_len_to_us(u32 length)
+{
+ u32 biglen = length * 1000;
+ u32 divisor = (RR3_CLK_CONV_FACTOR) / 1000;
+ u32 result = (u32) (biglen / divisor);
+
+ /* don't allow zero lengths to go back, breaks lirc */
+ return result ? result : 1;
+}
+
+/*
+ * convert us back into redrat3 lengths
+ *
+ * length * 1000 length * 1000000
+ * ------------- = ---------------- = micro
+ * rr3clk / 1000 rr3clk
+
+ * 6 * 2 4 * 3 micro * rr3clk micro * rr3clk / 1000
+ * ----- = 4 ----- = 6 -------------- = len ---------------------
+ * 3 2 1000000 1000
+ */
+static u32 redrat3_us_to_len(u32 microsec)
+{
+ u32 result;
+ u32 divisor;
+
+ microsec &= IR_MAX_DURATION;
+ divisor = (RR3_CLK_CONV_FACTOR / 1000);
+ result = (u32)(microsec * divisor) / 1000;
+
+ /* don't allow zero lengths to go back, breaks lirc */
+ return result ? result : 1;
+
+}
+
+/* timer callback to send long trailing space on receive timeout */
+static void redrat3_rx_timeout(unsigned long data)
+{
+ struct redrat3_dev *rr3 = (struct redrat3_dev *)data;
+ DEFINE_IR_RAW_EVENT(rawir);
+
+ rawir.pulse = false;
+ rawir.duration = rr3->rc->timeout;
+ rr3_dbg(rr3->dev, "storing trailing space with duration %d\n",
+ rawir.duration);
+ ir_raw_event_store_with_filter(rr3->rc, &rawir);
+
+ rr3_dbg(rr3->dev, "calling ir_raw_event_handle\n");
+ ir_raw_event_handle(rr3->rc);
+
+ rr3_dbg(rr3->dev, "calling ir_raw_event_reset\n");
+ ir_raw_event_reset(rr3->rc);
+}
+
+static void redrat3_process_ir_data(struct redrat3_dev *rr3)
+{
+ DEFINE_IR_RAW_EVENT(rawir);
+ struct redrat3_signal_header header;
+ struct device *dev;
+ int i;
+ unsigned long delay;
+ u32 mod_freq, single_len;
+ u16 *len_vals;
+ u8 *data_vals;
+ u32 tmp32;
+ u16 tmp16;
+ char *sig_data;
+
+ if (!rr3) {
+ pr_err("%s called with no context!\n", __func__);
+ return;
+ }
+
+ rr3_ftr(rr3->dev, "Entered %s\n", __func__);
+
+ dev = rr3->dev;
+ sig_data = rr3->pbuf;
+
+ header.length = rr3->pktlen;
+ header.transfer_type = rr3->pkttype;
+
+ /* Sanity check */
+ if (!(header.length >= RR3_HEADER_LENGTH))
+ dev_warn(dev, "read returned less than rr3 header len\n");
+
+ delay = usecs_to_jiffies(rr3->rc->timeout / 1000);
+ mod_timer(&rr3->rx_timeout, jiffies + delay);
+
+ memcpy(&tmp32, sig_data + RR3_PAUSE_OFFSET, sizeof(tmp32));
+ header.pause = be32_to_cpu(tmp32);
+
+ memcpy(&tmp16, sig_data + RR3_FREQ_COUNT_OFFSET, sizeof(tmp16));
+ header.mod_freq_count = be16_to_cpu(tmp16);
+
+ memcpy(&tmp16, sig_data + RR3_NUM_PERIOD_OFFSET, sizeof(tmp16));
+ header.no_periods = be16_to_cpu(tmp16);
+
+ header.max_lengths = sig_data[RR3_MAX_LENGTHS_OFFSET];
+ header.no_lengths = sig_data[RR3_NUM_LENGTHS_OFFSET];
+
+ memcpy(&tmp16, sig_data + RR3_MAX_SIGS_OFFSET, sizeof(tmp16));
+ header.max_sig_size = be16_to_cpu(tmp16);
+
+ memcpy(&tmp16, sig_data + RR3_NUM_SIGS_OFFSET, sizeof(tmp16));
+ header.sig_size = be16_to_cpu(tmp16);
+
+ header.no_repeats= sig_data[RR3_REPEATS_OFFSET];
+
+ if (debug) {
+ redrat3_dump_signal_header(&header);
+ redrat3_dump_signal_data(sig_data, header.sig_size);
+ }
+
+ mod_freq = redrat3_val_to_mod_freq(&header);
+ rr3_dbg(dev, "Got mod_freq of %u\n", mod_freq);
+
+ /* Here we pull out the 'length' values from the signal */
+ len_vals = (u16 *)(sig_data + RR3_HEADER_LENGTH);
+
+ data_vals = sig_data + RR3_HEADER_LENGTH +
+ (header.max_lengths * sizeof(u16));
+
+ /* process each rr3 encoded byte into an int */
+ for (i = 0; i < header.sig_size; i++) {
+ u16 val = len_vals[data_vals[i]];
+ single_len = redrat3_len_to_us((u32)be16_to_cpu(val));
+
+ /* cap the value to IR_MAX_DURATION */
+ single_len &= IR_MAX_DURATION;
+
+ /* we should always get pulse/space/pulse/space samples */
+ if (i % 2)
+ rawir.pulse = false;
+ else
+ rawir.pulse = true;
+
+ rawir.duration = US_TO_NS(single_len);
+ rr3_dbg(dev, "storing %s with duration %d (i: %d)\n",
+ rawir.pulse ? "pulse" : "space", rawir.duration, i);
+ ir_raw_event_store_with_filter(rr3->rc, &rawir);
+ }
+
+ /* add a trailing space, if need be */
+ if (i % 2) {
+ rawir.pulse = false;
+ /* this duration is made up, and may not be ideal... */
+ rawir.duration = rr3->rc->timeout / 2;
+ rr3_dbg(dev, "storing trailing space with duration %d\n",
+ rawir.duration);
+ ir_raw_event_store_with_filter(rr3->rc, &rawir);
+ }
+
+ rr3_dbg(dev, "calling ir_raw_event_handle\n");
+ ir_raw_event_handle(rr3->rc);
+
+ return;
+}
+
+/* Util fn to send rr3 cmds */
+static u8 redrat3_send_cmd(int cmd, struct redrat3_dev *rr3)
+{
+ struct usb_device *udev;
+ u8 *data;
+ int res;
+
+ data = kzalloc(sizeof(u8), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ udev = rr3->udev;
+ res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), cmd,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0x0000, 0x0000, data, sizeof(u8), HZ * 10);
+
+ if (res < 0) {
+ dev_err(rr3->dev, "%s: Error sending rr3 cmd res %d, data %d",
+ __func__, res, *data);
+ res = -EIO;
+ } else
+ res = (u8)data[0];
+
+ kfree(data);
+
+ return res;
+}
+
+/* Enables the long range detector and starts async receive */
+static int redrat3_enable_detector(struct redrat3_dev *rr3)
+{
+ struct device *dev = rr3->dev;
+ u8 ret;
+
+ rr3_ftr(dev, "Entering %s\n", __func__);
+
+ ret = redrat3_send_cmd(RR3_RC_DET_ENABLE, rr3);
+ if (ret != 0)
+ dev_dbg(dev, "%s: unexpected ret of %d\n",
+ __func__, ret);
+
+ ret = redrat3_send_cmd(RR3_RC_DET_STATUS, rr3);
+ if (ret != 1) {
+ dev_err(dev, "%s: detector status: %d, should be 1\n",
+ __func__, ret);
+ return -EIO;
+ }
+
+ rr3->det_enabled = true;
+ redrat3_issue_async(rr3);
+
+ return 0;
+}
+
+/* Disables the rr3 long range detector */
+static void redrat3_disable_detector(struct redrat3_dev *rr3)
+{
+ struct device *dev = rr3->dev;
+ u8 ret;
+
+ rr3_ftr(dev, "Entering %s\n", __func__);
+
+ ret = redrat3_send_cmd(RR3_RC_DET_DISABLE, rr3);
+ if (ret != 0)
+ dev_err(dev, "%s: failure!\n", __func__);
+
+ ret = redrat3_send_cmd(RR3_RC_DET_STATUS, rr3);
+ if (ret != 0)
+ dev_warn(dev, "%s: detector status: %d, should be 0\n",
+ __func__, ret);
+
+ rr3->det_enabled = false;
+}
+
+static inline void redrat3_delete(struct redrat3_dev *rr3,
+ struct usb_device *udev)
+{
+ rr3_ftr(rr3->dev, "%s cleaning up\n", __func__);
+ usb_kill_urb(rr3->read_urb);
+ usb_kill_urb(rr3->write_urb);
+
+ usb_free_urb(rr3->read_urb);
+ usb_free_urb(rr3->write_urb);
+
+ usb_free_coherent(udev, rr3->ep_in->wMaxPacketSize,
+ rr3->bulk_in_buf, rr3->dma_in);
+ usb_free_coherent(udev, rr3->ep_out->wMaxPacketSize,
+ rr3->bulk_out_buf, rr3->dma_out);
+
+ kfree(rr3);
+}
+
+static u32 redrat3_get_timeout(struct device *dev,
+ struct rc_dev *rc, struct usb_device *udev)
+{
+ u32 *tmp;
+ u32 timeout = MS_TO_NS(150); /* a sane default, if things go haywire */
+ int len, ret, pipe;
+
+ len = sizeof(*tmp);
+ tmp = kzalloc(len, GFP_KERNEL);
+ if (!tmp) {
+ dev_warn(dev, "Memory allocation faillure\n");
+ return timeout;
+ }
+
+ pipe = usb_rcvctrlpipe(udev, 0);
+ ret = usb_control_msg(udev, pipe, RR3_GET_IR_PARAM,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ RR3_IR_IO_SIG_TIMEOUT, 0, tmp, len, HZ * 5);
+ if (ret != len) {
+ dev_warn(dev, "Failed to read timeout from hardware\n");
+ return timeout;
+ }
+
+ timeout = US_TO_NS(redrat3_len_to_us(be32_to_cpu(*tmp)));
+ if (timeout < rc->min_timeout)
+ timeout = rc->min_timeout;
+ else if (timeout > rc->max_timeout)
+ timeout = rc->max_timeout;
+
+ rr3_dbg(dev, "Got timeout of %d ms\n", timeout / (1000 * 1000));
+ return timeout;
+}
+
+static void redrat3_reset(struct redrat3_dev *rr3)
+{
+ struct usb_device *udev = rr3->udev;
+ struct device *dev = rr3->dev;
+ int rc, rxpipe, txpipe;
+ u8 *val;
+ int len = sizeof(u8);
+
+ rr3_ftr(dev, "Entering %s\n", __func__);
+
+ rxpipe = usb_rcvctrlpipe(udev, 0);
+ txpipe = usb_sndctrlpipe(udev, 0);
+
+ val = kzalloc(len, GFP_KERNEL);
+ if (!val) {
+ dev_err(dev, "Memory allocation failure\n");
+ return;
+ }
+
+ *val = 0x01;
+ rc = usb_control_msg(udev, rxpipe, RR3_RESET,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ RR3_CPUCS_REG_ADDR, 0, val, len, HZ * 25);
+ rr3_dbg(dev, "reset returned 0x%02x\n", rc);
+
+ *val = 5;
+ rc = usb_control_msg(udev, txpipe, RR3_SET_IR_PARAM,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ RR3_IR_IO_LENGTH_FUZZ, 0, val, len, HZ * 25);
+ rr3_dbg(dev, "set ir parm len fuzz %d rc 0x%02x\n", *val, rc);
+
+ *val = RR3_DRIVER_MAXLENS;
+ rc = usb_control_msg(udev, txpipe, RR3_SET_IR_PARAM,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ RR3_IR_IO_MAX_LENGTHS, 0, val, len, HZ * 25);
+ rr3_dbg(dev, "set ir parm max lens %d rc 0x%02x\n", *val, rc);
+
+ kfree(val);
+}
+
+static void redrat3_get_firmware_rev(struct redrat3_dev *rr3)
+{
+ int rc = 0;
+ char *buffer;
+
+ rr3_ftr(rr3->dev, "Entering %s\n", __func__);
+
+ buffer = kzalloc(sizeof(char) * (RR3_FW_VERSION_LEN + 1), GFP_KERNEL);
+ if (!buffer) {
+ dev_err(rr3->dev, "Memory allocation failure\n");
+ return;
+ }
+
+ rc = usb_control_msg(rr3->udev, usb_rcvctrlpipe(rr3->udev, 0),
+ RR3_FW_VERSION,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0, 0, buffer, RR3_FW_VERSION_LEN, HZ * 5);
+
+ if (rc >= 0)
+ dev_info(rr3->dev, "Firmware rev: %s", buffer);
+ else
+ dev_err(rr3->dev, "Problem fetching firmware ID\n");
+
+ kfree(buffer);
+ rr3_ftr(rr3->dev, "Exiting %s\n", __func__);
+}
+
+static void redrat3_read_packet_start(struct redrat3_dev *rr3, int len)
+{
+ u16 tx_error;
+ u16 hdrlen;
+
+ rr3_ftr(rr3->dev, "Entering %s\n", __func__);
+
+ /* grab the Length and type of transfer */
+ memcpy(&(rr3->pktlen), (unsigned char *) rr3->bulk_in_buf,
+ sizeof(rr3->pktlen));
+ memcpy(&(rr3->pkttype), ((unsigned char *) rr3->bulk_in_buf +
+ sizeof(rr3->pktlen)),
+ sizeof(rr3->pkttype));
+
+ /*data needs conversion to know what its real values are*/
+ rr3->pktlen = be16_to_cpu(rr3->pktlen);
+ rr3->pkttype = be16_to_cpu(rr3->pkttype);
+
+ switch (rr3->pkttype) {
+ case RR3_ERROR:
+ memcpy(&tx_error, ((unsigned char *)rr3->bulk_in_buf
+ + (sizeof(rr3->pktlen) + sizeof(rr3->pkttype))),
+ sizeof(tx_error));
+ tx_error = be16_to_cpu(tx_error);
+ redrat3_dump_fw_error(rr3, tx_error);
+ break;
+
+ case RR3_MOD_SIGNAL_IN:
+ hdrlen = sizeof(rr3->pktlen) + sizeof(rr3->pkttype);
+ rr3->bytes_read = len;
+ rr3->bytes_read -= hdrlen;
+ rr3->datap = &(rr3->pbuf[0]);
+
+ memcpy(rr3->datap, ((unsigned char *)rr3->bulk_in_buf + hdrlen),
+ rr3->bytes_read);
+ rr3->datap += rr3->bytes_read;
+ rr3_dbg(rr3->dev, "bytes_read %d, pktlen %d\n",
+ rr3->bytes_read, rr3->pktlen);
+ break;
+
+ default:
+ rr3_dbg(rr3->dev, "ignoring packet with type 0x%02x, "
+ "len of %d, 0x%02x\n", rr3->pkttype, len, rr3->pktlen);
+ break;
+ }
+}
+
+static void redrat3_read_packet_continue(struct redrat3_dev *rr3, int len)
+{
+
+ rr3_ftr(rr3->dev, "Entering %s\n", __func__);
+
+ memcpy(rr3->datap, (unsigned char *)rr3->bulk_in_buf, len);
+ rr3->datap += len;
+
+ rr3->bytes_read += len;
+ rr3_dbg(rr3->dev, "bytes_read %d, pktlen %d\n",
+ rr3->bytes_read, rr3->pktlen);
+}
+
+/* gather IR data from incoming urb, process it when we have enough */
+static int redrat3_get_ir_data(struct redrat3_dev *rr3, int len)
+{
+ struct device *dev = rr3->dev;
+ int ret = 0;
+
+ rr3_ftr(dev, "Entering %s\n", __func__);
+
+ if (rr3->pktlen > RR3_MAX_BUF_SIZE) {
+ dev_err(rr3->dev, "error: packet larger than buffer\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if ((rr3->bytes_read == 0) &&
+ (len >= (sizeof(rr3->pkttype) + sizeof(rr3->pktlen)))) {
+ redrat3_read_packet_start(rr3, len);
+ } else if (rr3->bytes_read != 0) {
+ redrat3_read_packet_continue(rr3, len);
+ } else if (rr3->bytes_read == 0) {
+ dev_err(dev, "error: no packet data read\n");
+ ret = -ENODATA;
+ goto out;
+ }
+
+ if (rr3->bytes_read > rr3->pktlen) {
+ dev_err(dev, "bytes_read (%d) greater than pktlen (%d)\n",
+ rr3->bytes_read, rr3->pktlen);
+ ret = -EINVAL;
+ goto out;
+ } else if (rr3->bytes_read < rr3->pktlen)
+ /* we're still accumulating data */
+ return 0;
+
+ /* if we get here, we've got IR data to decode */
+ if (rr3->pkttype == RR3_MOD_SIGNAL_IN)
+ redrat3_process_ir_data(rr3);
+ else
+ rr3_dbg(dev, "discarding non-signal data packet "
+ "(type 0x%02x)\n", rr3->pkttype);
+
+out:
+ rr3->bytes_read = 0;
+ rr3->pktlen = 0;
+ rr3->pkttype = 0;
+ return ret;
+}
+
+/* callback function from USB when async USB request has completed */
+static void redrat3_handle_async(struct urb *urb, struct pt_regs *regs)
+{
+ struct redrat3_dev *rr3;
+
+ if (!urb)
+ return;
+
+ rr3 = urb->context;
+ if (!rr3) {
+ pr_err("%s called with invalid context!\n", __func__);
+ usb_unlink_urb(urb);
+ return;
+ }
+
+ rr3_ftr(rr3->dev, "Entering %s\n", __func__);
+
+ if (!rr3->det_enabled) {
+ rr3_dbg(rr3->dev, "received a read callback but detector "
+ "disabled - ignoring\n");
+ return;
+ }
+
+ switch (urb->status) {
+ case 0:
+ redrat3_get_ir_data(rr3, urb->actual_length);
+ break;
+
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ usb_unlink_urb(urb);
+ return;
+
+ case -EPIPE:
+ default:
+ dev_warn(rr3->dev, "Error: urb status = %d\n", urb->status);
+ rr3->bytes_read = 0;
+ rr3->pktlen = 0;
+ rr3->pkttype = 0;
+ break;
+ }
+
+ if (!rr3->transmitting)
+ redrat3_issue_async(rr3);
+ else
+ rr3_dbg(rr3->dev, "IR transmit in progress\n");
+}
+
+static void redrat3_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
+{
+ struct redrat3_dev *rr3;
+ int len;
+
+ if (!urb)
+ return;
+
+ rr3 = urb->context;
+ if (rr3) {
+ len = urb->actual_length;
+ rr3_ftr(rr3->dev, "%s: called (status=%d len=%d)\n",
+ __func__, urb->status, len);
+ }
+}
+
+static u16 mod_freq_to_val(unsigned int mod_freq)
+{
+ int mult = 6000000;
+
+ /* Clk used in mod. freq. generation is CLK24/4. */
+ return (u16)(65536 - (mult / mod_freq));
+}
+
+static int redrat3_set_tx_carrier(struct rc_dev *dev, u32 carrier)
+{
+ struct redrat3_dev *rr3 = dev->priv;
+
+ rr3->carrier = carrier;
+
+ return carrier;
+}
+
+static int redrat3_transmit_ir(struct rc_dev *rcdev, int *txbuf, u32 n)
+{
+ struct redrat3_dev *rr3 = rcdev->priv;
+ struct device *dev = rr3->dev;
+ struct redrat3_signal_header header;
+ int i, j, count, ret, ret_len, offset;
+ int lencheck, cur_sample_len, pipe;
+ char *buffer = NULL, *sigdata = NULL;
+ int *sample_lens = NULL;
+ u32 tmpi;
+ u16 tmps;
+ u8 *datap;
+ u8 curlencheck = 0;
+ u16 *lengths_ptr;
+ int sendbuf_len;
+
+ rr3_ftr(dev, "Entering %s\n", __func__);
+
+ if (rr3->transmitting) {
+ dev_warn(dev, "%s: transmitter already in use\n", __func__);
+ return -EAGAIN;
+ }
+
+ count = n / sizeof(int);
+ if (count > (RR3_DRIVER_MAXLENS * 2))
+ return -EINVAL;
+
+ rr3->transmitting = true;
+
+ redrat3_disable_detector(rr3);
+
+ if (rr3->det_enabled) {
+ dev_err(dev, "%s: cannot tx while rx is enabled\n", __func__);
+ ret = -EIO;
+ goto out;
+ }
+
+ sample_lens = kzalloc(sizeof(int) * RR3_DRIVER_MAXLENS, GFP_KERNEL);
+ if (!sample_lens) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < count; i++) {
+ for (lencheck = 0; lencheck < curlencheck; lencheck++) {
+ cur_sample_len = redrat3_us_to_len(txbuf[i]);
+ if (sample_lens[lencheck] == cur_sample_len)
+ break;
+ }
+ if (lencheck == curlencheck) {
+ cur_sample_len = redrat3_us_to_len(txbuf[i]);
+ rr3_dbg(dev, "txbuf[%d]=%u, pos %d, enc %u\n",
+ i, txbuf[i], curlencheck, cur_sample_len);
+ if (curlencheck < 255) {
+ /* now convert the value to a proper
+ * rr3 value.. */
+ sample_lens[curlencheck] = cur_sample_len;
+ curlencheck++;
+ } else {
+ dev_err(dev, "signal too long\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+ }
+
+ sigdata = kzalloc((count + RR3_TX_TRAILER_LEN), GFP_KERNEL);
+ if (!sigdata) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ sigdata[count] = RR3_END_OF_SIGNAL;
+ sigdata[count + 1] = RR3_END_OF_SIGNAL;
+ for (i = 0; i < count; i++) {
+ for (j = 0; j < curlencheck; j++) {
+ if (sample_lens[j] == redrat3_us_to_len(txbuf[i]))
+ sigdata[i] = j;
+ }
+ }
+
+ offset = RR3_TX_HEADER_OFFSET;
+ sendbuf_len = RR3_HEADER_LENGTH + (sizeof(u16) * RR3_DRIVER_MAXLENS)
+ + count + RR3_TX_TRAILER_LEN + offset;
+
+ buffer = kzalloc(sendbuf_len, GFP_KERNEL);
+ if (!buffer) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* fill in our packet header */
+ header.length = sendbuf_len - offset;
+ header.transfer_type = RR3_MOD_SIGNAL_OUT;
+ header.pause = redrat3_len_to_us(100);
+ header.mod_freq_count = mod_freq_to_val(rr3->carrier);
+ header.no_periods = 0; /* n/a to transmit */
+ header.max_lengths = RR3_DRIVER_MAXLENS;
+ header.no_lengths = curlencheck;
+ header.max_sig_size = RR3_MAX_SIG_SIZE;
+ header.sig_size = count + RR3_TX_TRAILER_LEN;
+ /* we currently rely on repeat handling in the IR encoding source */
+ header.no_repeats = 0;
+
+ tmps = cpu_to_be16(header.length);
+ memcpy(buffer, &tmps, 2);
+
+ tmps = cpu_to_be16(header.transfer_type);
+ memcpy(buffer + 2, &tmps, 2);
+
+ tmpi = cpu_to_be32(header.pause);
+ memcpy(buffer + offset, &tmpi, sizeof(tmpi));
+
+ tmps = cpu_to_be16(header.mod_freq_count);
+ memcpy(buffer + offset + RR3_FREQ_COUNT_OFFSET, &tmps, 2);
+
+ buffer[offset + RR3_NUM_LENGTHS_OFFSET] = header.no_lengths;
+
+ tmps = cpu_to_be16(header.sig_size);
+ memcpy(buffer + offset + RR3_NUM_SIGS_OFFSET, &tmps, 2);
+
+ buffer[offset + RR3_REPEATS_OFFSET] = header.no_repeats;
+
+ lengths_ptr = (u16 *)(buffer + offset + RR3_HEADER_LENGTH);
+ for (i = 0; i < curlencheck; ++i)
+ lengths_ptr[i] = cpu_to_be16(sample_lens[i]);
+
+ datap = (u8 *)(buffer + offset + RR3_HEADER_LENGTH +
+ (sizeof(u16) * RR3_DRIVER_MAXLENS));
+ memcpy(datap, sigdata, (count + RR3_TX_TRAILER_LEN));
+
+ if (debug) {
+ redrat3_dump_signal_header(&header);
+ redrat3_dump_signal_data(buffer, header.sig_size);
+ }
+
+ pipe = usb_sndbulkpipe(rr3->udev, rr3->ep_out->bEndpointAddress);
+ tmps = usb_bulk_msg(rr3->udev, pipe, buffer,
+ sendbuf_len, &ret_len, 10 * HZ);
+ rr3_dbg(dev, "sent %d bytes, (ret %d)\n", ret_len, tmps);
+
+ /* now tell the hardware to transmit what we sent it */
+ pipe = usb_rcvctrlpipe(rr3->udev, 0);
+ ret = usb_control_msg(rr3->udev, pipe, RR3_TX_SEND_SIGNAL,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0, 0, buffer, 2, HZ * 10);
+
+ if (ret < 0)
+ dev_err(dev, "Error: control msg send failed, rc %d\n", ret);
+ else
+ ret = n;
+
+out:
+ kfree(sample_lens);
+ kfree(buffer);
+ kfree(sigdata);
+
+ rr3->transmitting = false;
+
+ redrat3_enable_detector(rr3);
+
+ return ret;
+}
+
+static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3)
+{
+ struct device *dev = rr3->dev;
+ struct rc_dev *rc;
+ int ret = -ENODEV;
+ u16 prod = le16_to_cpu(rr3->udev->descriptor.idProduct);
+
+ rc = rc_allocate_device();
+ if (!rc) {
+ dev_err(dev, "remote input dev allocation failed\n");
+ goto out;
+ }
+
+ snprintf(rr3->name, sizeof(rr3->name), "RedRat3%s "
+ "Infrared Remote Transceiver (%04x:%04x)",
+ prod == USB_RR3IIUSB_PRODUCT_ID ? "-II" : "",
+ le16_to_cpu(rr3->udev->descriptor.idVendor), prod);
+
+ usb_make_path(rr3->udev, rr3->phys, sizeof(rr3->phys));
+
+ rc->input_name = rr3->name;
+ rc->input_phys = rr3->phys;
+ usb_to_input_id(rr3->udev, &rc->input_id);
+ rc->dev.parent = dev;
+ rc->priv = rr3;
+ rc->driver_type = RC_DRIVER_IR_RAW;
+ rc->allowed_protos = RC_TYPE_ALL;
+ rc->min_timeout = MS_TO_NS(RR3_RX_MIN_TIMEOUT);
+ rc->max_timeout = MS_TO_NS(RR3_RX_MAX_TIMEOUT);
+ rc->timeout = redrat3_get_timeout(dev, rc, rr3->udev);
+ rc->tx_ir = redrat3_transmit_ir;
+ rc->s_tx_carrier = redrat3_set_tx_carrier;
+ rc->driver_name = DRIVER_NAME;
+ rc->map_name = RC_MAP_HAUPPAUGE;
+
+ ret = rc_register_device(rc);
+ if (ret < 0) {
+ dev_err(dev, "remote dev registration failed\n");
+ goto out;
+ }
+
+ return rc;
+
+out:
+ rc_free_device(rc);
+ return NULL;
+}
+
+static int __devinit redrat3_dev_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct device *dev = &intf->dev;
+ struct usb_host_interface *uhi;
+ struct redrat3_dev *rr3;
+ struct usb_endpoint_descriptor *ep;
+ struct usb_endpoint_descriptor *ep_in = NULL;
+ struct usb_endpoint_descriptor *ep_out = NULL;
+ u8 addr, attrs;
+ int pipe, i;
+ int retval = -ENOMEM;
+
+ rr3_ftr(dev, "%s called\n", __func__);
+
+ uhi = intf->cur_altsetting;
+
+ /* find our bulk-in and bulk-out endpoints */
+ for (i = 0; i < uhi->desc.bNumEndpoints; ++i) {
+ ep = &uhi->endpoint[i].desc;
+ addr = ep->bEndpointAddress;
+ attrs = ep->bmAttributes;
+
+ if ((ep_in == NULL) &&
+ ((addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) &&
+ ((attrs & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_BULK)) {
+ rr3_dbg(dev, "found bulk-in endpoint at 0x%02x\n",
+ ep->bEndpointAddress);
+ /* data comes in on 0x82, 0x81 is for other data... */
+ if (ep->bEndpointAddress == RR3_BULK_IN_EP_ADDR)
+ ep_in = ep;
+ }
+
+ if ((ep_out == NULL) &&
+ ((addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) &&
+ ((attrs & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_BULK)) {
+ rr3_dbg(dev, "found bulk-out endpoint at 0x%02x\n",
+ ep->bEndpointAddress);
+ ep_out = ep;
+ }
+ }
+
+ if (!ep_in || !ep_out) {
+ dev_err(dev, "Couldn't find both in and out endpoints\n");
+ retval = -ENODEV;
+ goto no_endpoints;
+ }
+
+ /* allocate memory for our device state and initialize it */
+ rr3 = kzalloc(sizeof(*rr3), GFP_KERNEL);
+ if (rr3 == NULL) {
+ dev_err(dev, "Memory allocation failure\n");
+ goto error;
+ }
+
+ rr3->dev = &intf->dev;
+
+ /* set up bulk-in endpoint */
+ rr3->read_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!rr3->read_urb) {
+ dev_err(dev, "Read urb allocation failure\n");
+ goto error;
+ }
+
+ rr3->ep_in = ep_in;
+ rr3->bulk_in_buf = usb_alloc_coherent(udev, ep_in->wMaxPacketSize,
+ GFP_ATOMIC, &rr3->dma_in);
+ if (!rr3->bulk_in_buf) {
+ dev_err(dev, "Read buffer allocation failure\n");
+ goto error;
+ }
+
+ pipe = usb_rcvbulkpipe(udev, ep_in->bEndpointAddress);
+ usb_fill_bulk_urb(rr3->read_urb, udev, pipe,
+ rr3->bulk_in_buf, ep_in->wMaxPacketSize,
+ (usb_complete_t)redrat3_handle_async, rr3);
+
+ /* set up bulk-out endpoint*/
+ rr3->write_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!rr3->write_urb) {
+ dev_err(dev, "Write urb allocation failure\n");
+ goto error;
+ }
+
+ rr3->ep_out = ep_out;
+ rr3->bulk_out_buf = usb_alloc_coherent(udev, ep_out->wMaxPacketSize,
+ GFP_ATOMIC, &rr3->dma_out);
+ if (!rr3->bulk_out_buf) {
+ dev_err(dev, "Write buffer allocation failure\n");
+ goto error;
+ }
+
+ pipe = usb_sndbulkpipe(udev, ep_out->bEndpointAddress);
+ usb_fill_bulk_urb(rr3->write_urb, udev, pipe,
+ rr3->bulk_out_buf, ep_out->wMaxPacketSize,
+ (usb_complete_t)redrat3_write_bulk_callback, rr3);
+
+ mutex_init(&rr3->lock);
+ rr3->udev = udev;
+
+ redrat3_reset(rr3);
+ redrat3_get_firmware_rev(rr3);
+
+ /* might be all we need to do? */
+ retval = redrat3_enable_detector(rr3);
+ if (retval < 0)
+ goto error;
+
+ /* default.. will get overridden by any sends with a freq defined */
+ rr3->carrier = 38000;
+
+ rr3->rc = redrat3_init_rc_dev(rr3);
+ if (!rr3->rc)
+ goto error;
+
+ setup_timer(&rr3->rx_timeout, redrat3_rx_timeout, (unsigned long)rr3);
+
+ /* we can register the device now, as it is ready */
+ usb_set_intfdata(intf, rr3);
+
+ rr3_ftr(dev, "Exiting %s\n", __func__);
+ return 0;
+
+error:
+ redrat3_delete(rr3, rr3->udev);
+
+no_endpoints:
+ dev_err(dev, "%s: retval = %x", __func__, retval);
+
+ return retval;
+}
+
+static void __devexit redrat3_dev_disconnect(struct usb_interface *intf)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct redrat3_dev *rr3 = usb_get_intfdata(intf);
+
+ rr3_ftr(&intf->dev, "Entering %s\n", __func__);
+
+ if (!rr3)
+ return;
+
+ redrat3_disable_detector(rr3);
+
+ usb_set_intfdata(intf, NULL);
+ rc_unregister_device(rr3->rc);
+ redrat3_delete(rr3, udev);
+
+ rr3_ftr(&intf->dev, "RedRat3 IR Transceiver now disconnected\n");
+}
+
+static int redrat3_dev_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct redrat3_dev *rr3 = usb_get_intfdata(intf);
+ rr3_ftr(rr3->dev, "suspend\n");
+ usb_kill_urb(rr3->read_urb);
+ return 0;
+}
+
+static int redrat3_dev_resume(struct usb_interface *intf)
+{
+ struct redrat3_dev *rr3 = usb_get_intfdata(intf);
+ rr3_ftr(rr3->dev, "resume\n");
+ if (usb_submit_urb(rr3->read_urb, GFP_ATOMIC))
+ return -EIO;
+ return 0;
+}
+
+static struct usb_driver redrat3_dev_driver = {
+ .name = DRIVER_NAME,
+ .probe = redrat3_dev_probe,
+ .disconnect = redrat3_dev_disconnect,
+ .suspend = redrat3_dev_suspend,
+ .resume = redrat3_dev_resume,
+ .reset_resume = redrat3_dev_resume,
+ .id_table = redrat3_dev_table
+};
+
+static int __init redrat3_dev_init(void)
+{
+ int ret;
+
+ ret = usb_register(&redrat3_dev_driver);
+ if (ret < 0)
+ pr_err(DRIVER_NAME
+ ": usb register failed, result = %d\n", ret);
+
+ return ret;
+}
+
+static void __exit redrat3_dev_exit(void)
+{
+ usb_deregister(&redrat3_dev_driver);
+}
+
+module_init(redrat3_dev_init);
+module_exit(redrat3_dev_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_AUTHOR(DRIVER_AUTHOR2);
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(usb, redrat3_dev_table);
+
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable module debug spew. 0 = no debugging (default) "
+ "0x1 = standard debug messages, 0x2 = function tracing debug. "
+ "Flag bits are addative (i.e., 0x3 for both debug types).");
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
index 186de5522001..5d06b899e859 100644
--- a/drivers/media/rc/winbond-cir.c
+++ b/drivers/media/rc/winbond-cir.c
@@ -19,11 +19,12 @@
* o DSDT dumps
*
* Supported features:
+ * o IR Receive
+ * o IR Transmit
* o Wake-On-CIR functionality
*
* To do:
* o Learning
- * o IR Transmit
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -50,6 +51,8 @@
#include <linux/io.h>
#include <linux/bitrev.h>
#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
#include <media/rc-core.h>
#define DRVNAME "winbond-cir"
@@ -118,14 +121,24 @@
#define WBCIR_IRQ_NONE 0x00
/* RX data bit for WBCIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */
#define WBCIR_IRQ_RX 0x01
+/* TX data low bit for WBCIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */
+#define WBCIR_IRQ_TX_LOW 0x02
/* Over/Under-flow bit for WBCIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */
#define WBCIR_IRQ_ERR 0x04
+/* TX data empty bit for WBCEIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */
+#define WBCIR_IRQ_TX_EMPTY 0x20
/* Led enable/disable bit for WBCIR_REG_ECEIR_CTS */
#define WBCIR_LED_ENABLE 0x80
/* RX data available bit for WBCIR_REG_SP3_LSR */
#define WBCIR_RX_AVAIL 0x01
+/* RX data overrun error bit for WBCIR_REG_SP3_LSR */
+#define WBCIR_RX_OVERRUN 0x02
+/* TX End-Of-Transmission bit for WBCIR_REG_SP3_ASCR */
+#define WBCIR_TX_EOT 0x04
/* RX disable bit for WBCIR_REG_SP3_ASCR */
#define WBCIR_RX_DISABLE 0x20
+/* TX data underrun error bit for WBCIR_REG_SP3_ASCR */
+#define WBCIR_TX_UNDERRUN 0x40
/* Extended mode enable bit for WBCIR_REG_SP3_EXCR1 */
#define WBCIR_EXT_ENABLE 0x01
/* Select compare register in WBCIR_REG_WCEIR_INDEX (bits 5 & 6) */
@@ -154,6 +167,21 @@ enum wbcir_protocol {
IR_PROTOCOL_RC6 = 0x2,
};
+/* Possible states for IR reception */
+enum wbcir_rxstate {
+ WBCIR_RXSTATE_INACTIVE = 0,
+ WBCIR_RXSTATE_ACTIVE,
+ WBCIR_RXSTATE_ERROR
+};
+
+/* Possible states for IR transmission */
+enum wbcir_txstate {
+ WBCIR_TXSTATE_INACTIVE = 0,
+ WBCIR_TXSTATE_ACTIVE,
+ WBCIR_TXSTATE_DONE,
+ WBCIR_TXSTATE_ERROR
+};
+
/* Misc */
#define WBCIR_NAME "Winbond CIR"
#define WBCIR_ID_FAMILY 0xF1 /* Family ID for the WPCD376I */
@@ -166,22 +194,29 @@ enum wbcir_protocol {
/* Per-device data */
struct wbcir_data {
spinlock_t spinlock;
+ struct rc_dev *dev;
+ struct led_classdev led;
unsigned long wbase; /* Wake-Up Baseaddr */
unsigned long ebase; /* Enhanced Func. Baseaddr */
unsigned long sbase; /* Serial Port Baseaddr */
unsigned int irq; /* Serial Port IRQ */
+ u8 irqmask;
- struct rc_dev *dev;
-
+ /* RX state */
+ enum wbcir_rxstate rxstate;
struct led_trigger *rxtrigger;
- struct led_trigger *txtrigger;
- struct led_classdev led;
+ struct ir_raw_event rxev;
- /* RX irdata state */
- bool irdata_active;
- bool irdata_error;
- struct ir_raw_event ev;
+ /* TX state */
+ enum wbcir_txstate txstate;
+ struct led_trigger *txtrigger;
+ u32 txlen;
+ u32 txoff;
+ u32 *txbuf;
+ wait_queue_head_t txwaitq;
+ u8 txmask;
+ u32 txcarrier;
};
static enum wbcir_protocol protocol = IR_PROTOCOL_RC6;
@@ -193,6 +228,10 @@ static int invert; /* default = 0 */
module_param(invert, bool, 0444);
MODULE_PARM_DESC(invert, "Invert the signal from the IR receiver");
+static int txandrx; /* default = 0 */
+module_param(txandrx, bool, 0444);
+MODULE_PARM_DESC(invert, "Allow simultaneous TX and RX");
+
static unsigned int wake_sc = 0x800F040C;
module_param(wake_sc, uint, 0644);
MODULE_PARM_DESC(wake_sc, "Scancode of the power-on IR command");
@@ -228,6 +267,17 @@ wbcir_select_bank(struct wbcir_data *data, enum wbcir_bank bank)
outb(bank, data->sbase + WBCIR_REG_SP3_BSR);
}
+static inline void
+wbcir_set_irqmask(struct wbcir_data *data, u8 irqmask)
+{
+ if (data->irqmask == irqmask)
+ return;
+
+ wbcir_select_bank(data, WBCIR_BANK_0);
+ outb(irqmask, data->sbase + WBCIR_REG_SP3_IER);
+ data->irqmask = irqmask;
+}
+
static enum led_brightness
wbcir_led_brightness_get(struct led_classdev *led_cdev)
{
@@ -279,97 +329,297 @@ wbcir_to_rc6cells(u8 val)
*
*****************************************************************************/
+static void
+wbcir_idle_rx(struct rc_dev *dev, bool idle)
+{
+ struct wbcir_data *data = dev->priv;
+
+ if (!idle && data->rxstate == WBCIR_RXSTATE_INACTIVE) {
+ data->rxstate = WBCIR_RXSTATE_ACTIVE;
+ led_trigger_event(data->rxtrigger, LED_FULL);
+ }
+
+ if (idle && data->rxstate != WBCIR_RXSTATE_INACTIVE)
+ /* Tell hardware to go idle by setting RXINACTIVE */
+ outb(WBCIR_RX_DISABLE, data->sbase + WBCIR_REG_SP3_ASCR);
+}
+
+static void
+wbcir_irq_rx(struct wbcir_data *data, struct pnp_dev *device)
+{
+ u8 irdata;
+ DEFINE_IR_RAW_EVENT(rawir);
+
+ /* Since RXHDLEV is set, at least 8 bytes are in the FIFO */
+ while (inb(data->sbase + WBCIR_REG_SP3_LSR) & WBCIR_RX_AVAIL) {
+ irdata = inb(data->sbase + WBCIR_REG_SP3_RXDATA);
+ if (data->rxstate == WBCIR_RXSTATE_ERROR)
+ continue;
+ rawir.pulse = irdata & 0x80 ? false : true;
+ rawir.duration = US_TO_NS((irdata & 0x7F) * 10);
+ ir_raw_event_store_with_filter(data->dev, &rawir);
+ }
+
+ /* Check if we should go idle */
+ if (data->dev->idle) {
+ led_trigger_event(data->rxtrigger, LED_OFF);
+ data->rxstate = WBCIR_RXSTATE_INACTIVE;
+ }
+
+ ir_raw_event_handle(data->dev);
+}
+
+static void
+wbcir_irq_tx(struct wbcir_data *data)
+{
+ unsigned int space;
+ unsigned int used;
+ u8 bytes[16];
+ u8 byte;
+
+ if (!data->txbuf)
+ return;
+
+ switch (data->txstate) {
+ case WBCIR_TXSTATE_INACTIVE:
+ /* TX FIFO empty */
+ space = 16;
+ led_trigger_event(data->txtrigger, LED_FULL);
+ break;
+ case WBCIR_TXSTATE_ACTIVE:
+ /* TX FIFO low (3 bytes or less) */
+ space = 13;
+ break;
+ case WBCIR_TXSTATE_ERROR:
+ space = 0;
+ break;
+ default:
+ return;
+ }
+
+ /*
+ * TX data is run-length coded in bytes: YXXXXXXX
+ * Y = space (1) or pulse (0)
+ * X = duration, encoded as (X + 1) * 10us (i.e 10 to 1280 us)
+ */
+ for (used = 0; used < space && data->txoff != data->txlen; used++) {
+ if (data->txbuf[data->txoff] == 0) {
+ data->txoff++;
+ continue;
+ }
+ byte = min((u32)0x80, data->txbuf[data->txoff]);
+ data->txbuf[data->txoff] -= byte;
+ byte--;
+ byte |= (data->txoff % 2 ? 0x80 : 0x00); /* pulse/space */
+ bytes[used] = byte;
+ }
+
+ while (data->txbuf[data->txoff] == 0 && data->txoff != data->txlen)
+ data->txoff++;
+
+ if (used == 0) {
+ /* Finished */
+ if (data->txstate == WBCIR_TXSTATE_ERROR)
+ /* Clear TX underrun bit */
+ outb(WBCIR_TX_UNDERRUN, data->sbase + WBCIR_REG_SP3_ASCR);
+ else
+ data->txstate = WBCIR_TXSTATE_DONE;
+ wbcir_set_irqmask(data, WBCIR_IRQ_RX | WBCIR_IRQ_ERR);
+ led_trigger_event(data->txtrigger, LED_OFF);
+ wake_up(&data->txwaitq);
+ } else if (data->txoff == data->txlen) {
+ /* At the end of transmission, tell the hw before last byte */
+ outsb(data->sbase + WBCIR_REG_SP3_TXDATA, bytes, used - 1);
+ outb(WBCIR_TX_EOT, data->sbase + WBCIR_REG_SP3_ASCR);
+ outb(bytes[used - 1], data->sbase + WBCIR_REG_SP3_TXDATA);
+ wbcir_set_irqmask(data, WBCIR_IRQ_RX | WBCIR_IRQ_ERR |
+ WBCIR_IRQ_TX_EMPTY);
+ } else {
+ /* More data to follow... */
+ outsb(data->sbase + WBCIR_REG_SP3_RXDATA, bytes, used);
+ if (data->txstate == WBCIR_TXSTATE_INACTIVE) {
+ wbcir_set_irqmask(data, WBCIR_IRQ_RX | WBCIR_IRQ_ERR |
+ WBCIR_IRQ_TX_LOW);
+ data->txstate = WBCIR_TXSTATE_ACTIVE;
+ }
+ }
+}
+
static irqreturn_t
wbcir_irq_handler(int irqno, void *cookie)
{
struct pnp_dev *device = cookie;
struct wbcir_data *data = pnp_get_drvdata(device);
unsigned long flags;
- u8 irdata[8];
- u8 disable = true;
u8 status;
- int i;
spin_lock_irqsave(&data->spinlock, flags);
-
wbcir_select_bank(data, WBCIR_BANK_0);
-
status = inb(data->sbase + WBCIR_REG_SP3_EIR);
+ status &= data->irqmask;
- if (!(status & (WBCIR_IRQ_RX | WBCIR_IRQ_ERR))) {
+ if (!status) {
spin_unlock_irqrestore(&data->spinlock, flags);
return IRQ_NONE;
}
- /* Check for e.g. buffer overflow */
if (status & WBCIR_IRQ_ERR) {
- data->irdata_error = true;
- ir_raw_event_reset(data->dev);
- }
-
- if (!(status & WBCIR_IRQ_RX))
- goto out;
+ /* RX overflow? (read clears bit) */
+ if (inb(data->sbase + WBCIR_REG_SP3_LSR) & WBCIR_RX_OVERRUN) {
+ data->rxstate = WBCIR_RXSTATE_ERROR;
+ ir_raw_event_reset(data->dev);
+ }
- if (!data->irdata_active) {
- data->irdata_active = true;
- led_trigger_event(data->rxtrigger, LED_FULL);
+ /* TX underflow? */
+ if (inb(data->sbase + WBCIR_REG_SP3_ASCR) & WBCIR_TX_UNDERRUN)
+ data->txstate = WBCIR_TXSTATE_ERROR;
}
- /* Since RXHDLEV is set, at least 8 bytes are in the FIFO */
- insb(data->sbase + WBCIR_REG_SP3_RXDATA, &irdata[0], 8);
+ if (status & WBCIR_IRQ_RX)
+ wbcir_irq_rx(data, device);
- for (i = 0; i < 8; i++) {
- u8 pulse;
- u32 duration;
+ if (status & (WBCIR_IRQ_TX_LOW | WBCIR_IRQ_TX_EMPTY))
+ wbcir_irq_tx(data);
- if (irdata[i] != 0xFF && irdata[i] != 0x00)
- disable = false;
-
- if (data->irdata_error)
- continue;
+ spin_unlock_irqrestore(&data->spinlock, flags);
+ return IRQ_HANDLED;
+}
- pulse = irdata[i] & 0x80 ? false : true;
- duration = (irdata[i] & 0x7F) * 10000; /* ns */
+/*****************************************************************************
+ *
+ * RC-CORE INTERFACE FUNCTIONS
+ *
+ *****************************************************************************/
- if (data->ev.pulse != pulse) {
- if (data->ev.duration != 0) {
- ir_raw_event_store(data->dev, &data->ev);
- data->ev.duration = 0;
- }
+static int
+wbcir_txcarrier(struct rc_dev *dev, u32 carrier)
+{
+ struct wbcir_data *data = dev->priv;
+ unsigned long flags;
+ u8 val;
+ u32 freq;
+
+ freq = DIV_ROUND_CLOSEST(carrier, 1000);
+ if (freq < 30 || freq > 60)
+ return -EINVAL;
+
+ switch (freq) {
+ case 58:
+ case 59:
+ case 60:
+ val = freq - 58;
+ freq *= 1000;
+ break;
+ case 57:
+ val = freq - 27;
+ freq = 56900;
+ break;
+ default:
+ val = freq - 27;
+ freq *= 1000;
+ break;
+ }
- data->ev.pulse = pulse;
- }
+ spin_lock_irqsave(&data->spinlock, flags);
+ if (data->txstate != WBCIR_TXSTATE_INACTIVE) {
+ spin_unlock_irqrestore(&data->spinlock, flags);
+ return -EBUSY;
+ }
- data->ev.duration += duration;
+ if (data->txcarrier != freq) {
+ wbcir_select_bank(data, WBCIR_BANK_7);
+ wbcir_set_bits(data->sbase + WBCIR_REG_SP3_IRTXMC, val, 0x1F);
+ data->txcarrier = freq;
}
- if (disable) {
- if (data->ev.duration != 0 && !data->irdata_error) {
- ir_raw_event_store(data->dev, &data->ev);
- data->ev.duration = 0;
- }
+ spin_unlock_irqrestore(&data->spinlock, flags);
+ return 0;
+}
- /* Set RXINACTIVE */
- outb(WBCIR_RX_DISABLE, data->sbase + WBCIR_REG_SP3_ASCR);
+static int
+wbcir_txmask(struct rc_dev *dev, u32 mask)
+{
+ struct wbcir_data *data = dev->priv;
+ unsigned long flags;
+ u8 val;
- /* Drain the FIFO */
- while (inb(data->sbase + WBCIR_REG_SP3_LSR) & WBCIR_RX_AVAIL)
- inb(data->sbase + WBCIR_REG_SP3_RXDATA);
+ /* Four outputs, only one output can be enabled at a time */
+ switch (mask) {
+ case 0x1:
+ val = 0x0;
+ break;
+ case 0x2:
+ val = 0x1;
+ break;
+ case 0x4:
+ val = 0x2;
+ break;
+ case 0x8:
+ val = 0x3;
+ break;
+ default:
+ return -EINVAL;
+ }
- ir_raw_event_reset(data->dev);
- data->irdata_error = false;
- data->irdata_active = false;
- led_trigger_event(data->rxtrigger, LED_OFF);
+ spin_lock_irqsave(&data->spinlock, flags);
+ if (data->txstate != WBCIR_TXSTATE_INACTIVE) {
+ spin_unlock_irqrestore(&data->spinlock, flags);
+ return -EBUSY;
}
- ir_raw_event_handle(data->dev);
+ if (data->txmask != mask) {
+ wbcir_set_bits(data->ebase + WBCIR_REG_ECEIR_CTS, val, 0x0c);
+ data->txmask = mask;
+ }
-out:
spin_unlock_irqrestore(&data->spinlock, flags);
- return IRQ_HANDLED;
+ return 0;
}
+static int
+wbcir_tx(struct rc_dev *dev, int *buf, u32 bufsize)
+{
+ struct wbcir_data *data = dev->priv;
+ u32 count;
+ unsigned i;
+ unsigned long flags;
+
+ /* bufsize has been sanity checked by the caller */
+ count = bufsize / sizeof(int);
+ /* Not sure if this is possible, but better safe than sorry */
+ spin_lock_irqsave(&data->spinlock, flags);
+ if (data->txstate != WBCIR_TXSTATE_INACTIVE) {
+ spin_unlock_irqrestore(&data->spinlock, flags);
+ return -EBUSY;
+ }
+
+ /* Convert values to multiples of 10us */
+ for (i = 0; i < count; i++)
+ buf[i] = DIV_ROUND_CLOSEST(buf[i], 10);
+
+ /* Fill the TX fifo once, the irq handler will do the rest */
+ data->txbuf = buf;
+ data->txlen = count;
+ data->txoff = 0;
+ wbcir_irq_tx(data);
+
+ /* Wait for the TX to complete */
+ while (data->txstate == WBCIR_TXSTATE_ACTIVE) {
+ spin_unlock_irqrestore(&data->spinlock, flags);
+ wait_event(data->txwaitq, data->txstate != WBCIR_TXSTATE_ACTIVE);
+ spin_lock_irqsave(&data->spinlock, flags);
+ }
+
+ /* We're done */
+ if (data->txstate == WBCIR_TXSTATE_ERROR)
+ count = -EAGAIN;
+ data->txstate = WBCIR_TXSTATE_INACTIVE;
+ data->txbuf = NULL;
+ spin_unlock_irqrestore(&data->spinlock, flags);
+
+ return count;
+}
/*****************************************************************************
*
@@ -382,7 +632,7 @@ wbcir_shutdown(struct pnp_dev *device)
{
struct device *dev = &device->dev;
struct wbcir_data *data = pnp_get_drvdata(device);
- int do_wake = 1;
+ bool do_wake = true;
u8 match[11];
u8 mask[11];
u8 rc6_csl = 0;
@@ -392,14 +642,14 @@ wbcir_shutdown(struct pnp_dev *device)
memset(mask, 0, sizeof(mask));
if (wake_sc == INVALID_SCANCODE || !device_may_wakeup(dev)) {
- do_wake = 0;
+ do_wake = false;
goto finish;
}
switch (protocol) {
case IR_PROTOCOL_RC5:
if (wake_sc > 0xFFF) {
- do_wake = 0;
+ do_wake = false;
dev_err(dev, "RC5 - Invalid wake scancode\n");
break;
}
@@ -418,7 +668,7 @@ wbcir_shutdown(struct pnp_dev *device)
case IR_PROTOCOL_NEC:
if (wake_sc > 0xFFFFFF) {
- do_wake = 0;
+ do_wake = false;
dev_err(dev, "NEC - Invalid wake scancode\n");
break;
}
@@ -440,7 +690,7 @@ wbcir_shutdown(struct pnp_dev *device)
if (wake_rc6mode == 0) {
if (wake_sc > 0xFFFF) {
- do_wake = 0;
+ do_wake = false;
dev_err(dev, "RC6 - Invalid wake scancode\n");
break;
}
@@ -496,7 +746,7 @@ wbcir_shutdown(struct pnp_dev *device)
} else if (wake_sc <= 0x007FFFFF) {
rc6_csl = 60;
} else {
- do_wake = 0;
+ do_wake = false;
dev_err(dev, "RC6 - Invalid wake scancode\n");
break;
}
@@ -508,14 +758,14 @@ wbcir_shutdown(struct pnp_dev *device)
mask[i++] = 0x0F;
} else {
- do_wake = 0;
+ do_wake = false;
dev_err(dev, "RC6 - Invalid wake mode\n");
}
break;
default:
- do_wake = 0;
+ do_wake = false;
break;
}
@@ -551,21 +801,18 @@ finish:
wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x00, 0x01);
}
- /* Disable interrupts */
- wbcir_select_bank(data, WBCIR_BANK_0);
- outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
-
- /* Disable LED */
- data->irdata_active = false;
- led_trigger_event(data->rxtrigger, LED_OFF);
-
/*
* ACPI will set the HW disable bit for SP3 which means that the
* output signals are left in an undefined state which may cause
* spurious interrupts which we need to ignore until the hardware
* is reinitialized.
*/
+ wbcir_set_irqmask(data, WBCIR_IRQ_NONE);
disable_irq(data->irq);
+
+ /* Disable LED */
+ led_trigger_event(data->rxtrigger, LED_OFF);
+ led_trigger_event(data->txtrigger, LED_OFF);
}
static int
@@ -581,8 +828,7 @@ wbcir_init_hw(struct wbcir_data *data)
u8 tmp;
/* Disable interrupts */
- wbcir_select_bank(data, WBCIR_BANK_0);
- outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
+ wbcir_set_irqmask(data, WBCIR_IRQ_NONE);
/* Set PROT_SEL, RX_INV, Clear CEIR_EN (needed for the led) */
tmp = protocol << 4;
@@ -606,10 +852,11 @@ wbcir_init_hw(struct wbcir_data *data)
outb(0x00, data->ebase + WBCIR_REG_ECEIR_CCTL);
/*
- * Clear IR LED, set SP3 clock to 24Mhz
+ * Clear IR LED, set SP3 clock to 24Mhz, set TX mask to IRTX1,
* set SP3_IRRX_SW to binary 01, helpfully not documented
*/
outb(0x10, data->ebase + WBCIR_REG_ECEIR_CTS);
+ data->txmask = 0x1;
/* Enable extended mode */
wbcir_select_bank(data, WBCIR_BANK_2);
@@ -657,18 +904,21 @@ wbcir_init_hw(struct wbcir_data *data)
wbcir_select_bank(data, WBCIR_BANK_4);
outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR1);
- /* Enable MSR interrupt, Clear AUX_IRX */
+ /* Disable MSR interrupt, clear AUX_IRX, mask RX during TX? */
wbcir_select_bank(data, WBCIR_BANK_5);
- outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR2);
+ outb(txandrx ? 0x03 : 0x02, data->sbase + WBCIR_REG_SP3_IRCR2);
/* Disable CRC */
wbcir_select_bank(data, WBCIR_BANK_6);
outb(0x20, data->sbase + WBCIR_REG_SP3_IRCR3);
- /* Set RX/TX (de)modulation freq, not really used */
+ /* Set RX demodulation freq, not really used */
wbcir_select_bank(data, WBCIR_BANK_7);
outb(0xF2, data->sbase + WBCIR_REG_SP3_IRRXDC);
+
+ /* Set TX modulation, 36kHz, 7us pulse width */
outb(0x69, data->sbase + WBCIR_REG_SP3_IRTXMC);
+ data->txcarrier = 36000;
/* Set invert and pin direction */
if (invert)
@@ -683,16 +933,23 @@ wbcir_init_hw(struct wbcir_data *data)
/* Clear AUX status bits */
outb(0xE0, data->sbase + WBCIR_REG_SP3_ASCR);
- /* Clear IR decoding state */
- data->irdata_active = false;
- led_trigger_event(data->rxtrigger, LED_OFF);
- data->irdata_error = false;
- data->ev.duration = 0;
+ /* Clear RX state */
+ data->rxstate = WBCIR_RXSTATE_INACTIVE;
+ data->rxev.duration = 0;
ir_raw_event_reset(data->dev);
ir_raw_event_handle(data->dev);
+ /*
+ * Check TX state, if we did a suspend/resume cycle while TX was
+ * active, we will have a process waiting in txwaitq.
+ */
+ if (data->txstate == WBCIR_TXSTATE_ACTIVE) {
+ data->txstate = WBCIR_TXSTATE_ERROR;
+ wake_up(&data->txwaitq);
+ }
+
/* Enable interrupts */
- outb(WBCIR_IRQ_RX | WBCIR_IRQ_ERR, data->sbase + WBCIR_REG_SP3_IER);
+ wbcir_set_irqmask(data, WBCIR_IRQ_RX | WBCIR_IRQ_ERR);
}
static int
@@ -729,6 +986,7 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
pnp_set_drvdata(device, data);
spin_lock_init(&data->spinlock);
+ init_waitqueue_head(&data->txwaitq);
data->ebase = pnp_port_start(device, 0);
data->wbase = pnp_port_start(device, 1);
data->sbase = pnp_port_start(device, 2);
@@ -807,6 +1065,11 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
data->dev->input_id.vendor = PCI_VENDOR_ID_WINBOND;
data->dev->input_id.product = WBCIR_ID_FAMILY;
data->dev->input_id.version = WBCIR_ID_CHIP;
+ data->dev->map_name = RC_MAP_RC6_MCE;
+ data->dev->s_idle = wbcir_idle_rx;
+ data->dev->s_tx_mask = wbcir_txmask;
+ data->dev->s_tx_carrier = wbcir_txcarrier;
+ data->dev->tx_ir = wbcir_tx;
data->dev->priv = data;
data->dev->dev.parent = &device->dev;
@@ -849,9 +1112,7 @@ wbcir_remove(struct pnp_dev *device)
struct wbcir_data *data = pnp_get_drvdata(device);
/* Disable interrupts */
- wbcir_select_bank(data, WBCIR_BANK_0);
- outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
-
+ wbcir_set_irqmask(data, WBCIR_IRQ_NONE);
free_irq(data->irq, device);
/* Clear status bits NEC_REP, BUFF, MSG_END, MATCH */
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 00f51dd121f3..bb53de7fe408 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -128,10 +128,10 @@ config VIDEO_IR_I2C
# Encoder / Decoder module configuration
#
-menu "Encoders/decoders and other helper chips"
+menu "Encoders, decoders, sensors and other helper chips"
visible if !VIDEO_HELPER_CHIPS_AUTO
-comment "Audio decoders"
+comment "Audio decoders, processors and mixers"
config VIDEO_TVAUDIO
tristate "Simple audio decoder chips"
@@ -210,15 +210,6 @@ config VIDEO_CS53L32A
To compile this driver as a module, choose M here: the
module will be called cs53l32a.
-config VIDEO_M52790
- tristate "Mitsubishi M52790 A/V switch"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for the Mitsubishi M52790 A/V switch.
-
- To compile this driver as a module, choose M here: the
- module will be called m52790.
-
config VIDEO_TLV320AIC23B
tristate "Texas Instruments TLV320AIC23B audio codec"
depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
@@ -321,29 +312,6 @@ config VIDEO_KS0127
To compile this driver as a module, choose M here: the
module will be called ks0127.
-config VIDEO_OV7670
- tristate "OmniVision OV7670 sensor support"
- depends on I2C && VIDEO_V4L2
- ---help---
- This is a Video4Linux2 sensor-level driver for the OmniVision
- OV7670 VGA camera. It currently only works with the M88ALP01
- controller.
-
-config VIDEO_MT9V011
- tristate "Micron mt9v011 sensor support"
- depends on I2C && VIDEO_V4L2
- ---help---
- This is a Video4Linux2 sensor-level driver for the Micron
- mt0v011 1.3 Mpixel camera. It currently only works with the
- em28xx driver.
-
-config VIDEO_TCM825X
- tristate "TCM825x camera sensor support"
- depends on I2C && VIDEO_V4L2
- ---help---
- This is a driver for the Toshiba TCM825x VGA camera sensor.
- It is used for example in Nokia N800.
-
config VIDEO_SAA7110
tristate "Philips SAA7110 video decoder"
depends on VIDEO_V4L2 && I2C
@@ -362,15 +330,6 @@ config VIDEO_SAA711X
To compile this driver as a module, choose M here: the
module will be called saa7115.
-config VIDEO_SAA717X
- tristate "Philips SAA7171/3/4 audio/video decoders"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for the Philips SAA7171/3/4 audio/video decoders.
-
- To compile this driver as a module, choose M here: the
- module will be called saa717x.
-
config VIDEO_SAA7191
tristate "Philips SAA7191 video decoder"
depends on VIDEO_V4L2 && I2C
@@ -420,6 +379,15 @@ config VIDEO_VPX3220
comment "Video and audio decoders"
+config VIDEO_SAA717X
+ tristate "Philips SAA7171/3/4 audio/video decoders"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Philips SAA7171/3/4 audio/video decoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa717x.
+
source "drivers/media/video/cx25840/Kconfig"
comment "MPEG video encoders"
@@ -474,15 +442,6 @@ config VIDEO_ADV7175
To compile this driver as a module, choose M here: the
module will be called adv7175.
-config VIDEO_THS7303
- tristate "THS7303 Video Amplifier"
- depends on I2C
- help
- Support for TI THS7303 video amplifier
-
- To compile this driver as a module, choose M here: the
- module will be called ths7303.
-
config VIDEO_ADV7343
tristate "ADV7343 video encoder"
depends on I2C
@@ -498,6 +457,38 @@ config VIDEO_AK881X
help
Video output driver for AKM AK8813 and AK8814 TV encoders
+comment "Camera sensor devices"
+
+config VIDEO_OV7670
+ tristate "OmniVision OV7670 sensor support"
+ depends on I2C && VIDEO_V4L2
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the OmniVision
+ OV7670 VGA camera. It currently only works with the M88ALP01
+ controller.
+
+config VIDEO_MT9V011
+ tristate "Micron mt9v011 sensor support"
+ depends on I2C && VIDEO_V4L2
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the Micron
+ mt0v011 1.3 Mpixel camera. It currently only works with the
+ em28xx driver.
+
+config VIDEO_MT9V032
+ tristate "Micron MT9V032 sensor support"
+ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+ ---help---
+ This is a Video4Linux2 sensor-level driver for the Micron
+ MT9V032 752x480 CMOS sensor.
+
+config VIDEO_TCM825X
+ tristate "TCM825x camera sensor support"
+ depends on I2C && VIDEO_V4L2
+ ---help---
+ This is a driver for the Toshiba TCM825x VGA camera sensor.
+ It is used for example in Nokia N800.
+
comment "Video improvement chips"
config VIDEO_UPD64031A
@@ -523,6 +514,26 @@ config VIDEO_UPD64083
To compile this driver as a module, choose M here: the
module will be called upd64083.
+comment "Miscelaneous helper chips"
+
+config VIDEO_THS7303
+ tristate "THS7303 Video Amplifier"
+ depends on I2C
+ help
+ Support for TI THS7303 video amplifier
+
+ To compile this driver as a module, choose M here: the
+ module will be called ths7303.
+
+config VIDEO_M52790
+ tristate "Mitsubishi M52790 A/V switch"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Mitsubishi M52790 A/V switch.
+
+ To compile this driver as a module, choose M here: the
+ module will be called m52790.
+
endmenu # encoder / decoder chips
config VIDEO_SH_VOU
@@ -676,13 +687,13 @@ config VIDEO_HEXIUM_GEMINI
config VIDEO_TIMBERDALE
tristate "Support for timberdale Video In/LogiWIN"
- depends on VIDEO_V4L2 && I2C
+ depends on VIDEO_V4L2 && I2C && DMADEVICES
select DMA_ENGINE
select TIMB_DMA
select VIDEO_ADV7180
select VIDEOBUF_DMA_CONTIG
---help---
- Add support for the Video In peripherial of the timberdale FPGA.
+ Add support for the Video In peripherial of the timberdale FPGA.
source "drivers/media/video/cx88/Kconfig"
@@ -746,6 +757,8 @@ config VIDEO_NOON010PC30
---help---
This driver supports NOON010PC30 CIF camera from Siliconfile
+source "drivers/media/video/m5mols/Kconfig"
+
config VIDEO_OMAP3
tristate "OMAP 3 Camera support (EXPERIMENTAL)"
select OMAP_IOMMU
@@ -916,7 +929,7 @@ config VIDEO_OMAP2
This is a v4l2 driver for the TI OMAP2 camera capture interface
config VIDEO_MX2_HOSTSUPPORT
- bool
+ bool
config VIDEO_MX2
tristate "i.MX27/i.MX25 Camera Sensor Interface driver"
@@ -927,6 +940,26 @@ config VIDEO_MX2
This is a v4l2 driver for the i.MX27 and the i.MX25 Camera Sensor
Interface
+config VIDEO_SAMSUNG_S5P_FIMC
+ tristate "Samsung S5P and EXYNOS4 camera host interface driver"
+ depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P
+ select VIDEOBUF2_DMA_CONTIG
+ select V4L2_MEM2MEM_DEV
+ ---help---
+ This is a v4l2 driver for Samsung S5P and EXYNOS4 camera
+ host interface and video postprocessor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called s5p-fimc.
+
+config VIDEO_S5P_MIPI_CSIS
+ tristate "Samsung S5P and EXYNOS4 MIPI CSI receiver driver"
+ depends on VIDEO_V4L2 && PM_RUNTIME && PLAT_S5P && VIDEO_V4L2_SUBDEV_API
+ ---help---
+ This is a v4l2 driver for Samsung S5P/EXYNOS4 MIPI-CSI receiver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called s5p-csis.
#
# USB Multimedia device configuration
@@ -983,7 +1016,7 @@ config USB_STKWEBCAM
Supported devices are typically found in some Asus laptops,
with USB id 174f:a311 and 05e1:0501. Other Syntek cameras
may be supported by the stk11xx driver, from which this is
- derived, see <http://sourceforge.net/projects/syntekdriver/>
+ derived, see <http://sourceforge.net/projects/syntekdriver/>
To compile this driver as a module, choose M here: the
module will be called stkwebcam.
@@ -1022,13 +1055,5 @@ config VIDEO_MEM2MEM_TESTDEV
This is a virtual test device for the memory-to-memory driver
framework.
-config VIDEO_SAMSUNG_S5P_FIMC
- tristate "Samsung S5P FIMC (video postprocessor) driver"
- depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P
- select VIDEOBUF2_DMA_CONTIG
- select V4L2_MEM2MEM_DEV
- help
- This is a v4l2 driver for the S5P camera interface
- (video postprocessor)
endif # V4L_MEM2MEM_DRIVERS
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index ace5d8b57221..f0fecd6f6a33 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -66,8 +66,10 @@ obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
+obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o
obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o
obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o
+obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/
obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o
obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
@@ -164,6 +166,7 @@ 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_VIDEO_OMAP1) += omap1_camera.o
+
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/
obj-$(CONFIG_ARCH_DAVINCI) += davinci/
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 91399c94cd18..a97cf2750bd9 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -4303,7 +4303,7 @@ static int __devinit bttv_probe(struct pci_dev *dev,
goto fail0;
}
- pci_read_config_byte(dev, PCI_CLASS_REVISION, &btv->revision);
+ btv->revision = dev->revision;
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
printk(KERN_INFO "bttv%d: Bt%d (rev %d) at %s, ",
bttv_num,btv->id, btv->revision, pci_name(dev));
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
index 5111bbcefad5..40eb6326e48a 100644
--- a/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -438,7 +438,7 @@ static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *v
strcat(vc->card, " (676/");
break;
default:
- strcat(vc->card, " (???/");
+ strcat(vc->card, " (XXX/");
break;
}
switch (cam->params.version.sensor_flags) {
@@ -458,7 +458,7 @@ static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *v
strcat(vc->card, "500)");
break;
default:
- strcat(vc->card, "???)");
+ strcat(vc->card, "XXX)");
break;
}
@@ -1313,7 +1313,7 @@ static int cpia2_g_priority(struct file *file, void *_fh, enum v4l2_priority *p)
static int cpia2_s_priority(struct file *file, void *_fh, enum v4l2_priority prio)
{
struct camera_data *cam = video_drvdata(file);
- struct cpia2_fh *fh = fh;
+ struct cpia2_fh *fh = _fh;
if (cam->streaming && prio != fh->prio &&
fh->prio == V4L2_PRIORITY_RECORD)
diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig
index d9d2f6ad6ffb..53b3c7702573 100644
--- a/drivers/media/video/cx18/Kconfig
+++ b/drivers/media/video/cx18/Kconfig
@@ -2,6 +2,7 @@ config VIDEO_CX18
tristate "Conexant cx23418 MPEG encoder support"
depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL
select I2C_ALGOBIT
+ select VIDEOBUF_VMALLOC
depends on RC_CORE
select VIDEO_TUNER
select VIDEO_TVEEPROM
@@ -9,6 +10,9 @@ config VIDEO_CX18
select VIDEO_CS5345
select DVB_S5H1409 if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
+ select DVB_S5H1411 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE
---help---
This is a video4linux driver for Conexant cx23418 based
PCI combo video recorder devices.
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c
index 68ad1963f421..c07c849b1aaf 100644
--- a/drivers/media/video/cx18/cx18-cards.c
+++ b/drivers/media/video/cx18/cx18-cards.c
@@ -39,6 +39,16 @@ static struct cx18_card_tuner_i2c cx18_i2c_std = {
.tv = { 0x61, 0x60, I2C_CLIENT_END },
};
+/*
+ * usual i2c tuner addresses to probe with additional demod address for
+ * an NXP TDA8295 at 0x42 (N.B. it can possibly be at 0x4b or 0x4c too).
+ */
+static struct cx18_card_tuner_i2c cx18_i2c_nxp = {
+ .radio = { I2C_CLIENT_END },
+ .demod = { 0x42, 0x43, I2C_CLIENT_END },
+ .tv = { 0x61, 0x60, I2C_CLIENT_END },
+};
+
/* Please add new PCI IDs to: http://pci-ids.ucw.cz/
This keeps the PCI ID database up to date. Note that the entries
must be added under vendor 0x4444 (Conexant) as subsystem IDs.
@@ -131,15 +141,15 @@ static const struct cx18_card cx18_card_hvr1600_s5h1411 = {
.tune_lane = 0,
.initial_emrs = 0,
},
- .gpio_init.initial_value = 0x3001,
- .gpio_init.direction = 0x3001,
+ .gpio_init.initial_value = 0x3801,
+ .gpio_init.direction = 0x3801,
.gpio_i2c_slave_reset = {
- .active_lo_mask = 0x3001,
+ .active_lo_mask = 0x3801,
.msecs_asserted = 10,
.msecs_recovery = 40,
.ir_reset_mask = 0x0001,
},
- .i2c = &cx18_i2c_std,
+ .i2c = &cx18_i2c_nxp,
};
static const struct cx18_card cx18_card_hvr1600_samsung = {
diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h
index 3e750068f275..add7391ecaba 100644
--- a/drivers/media/video/cx18/cx18-cards.h
+++ b/drivers/media/video/cx18/cx18-cards.h
@@ -109,7 +109,7 @@ struct cx18_card_tuner {
struct cx18_card_tuner_i2c {
unsigned short radio[2];/* radio tuner i2c address to probe */
- unsigned short demod[2];/* demodulator i2c address to probe */
+ unsigned short demod[3];/* demodulator i2c address to probe */
unsigned short tv[4]; /* tv tuner i2c addresses to probe */
};
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 321c1b79794c..9e2f870f4258 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -423,7 +423,16 @@ static void cx18_process_eeprom(struct cx18 *cx)
return;
/* autodetect tuner standard */
- if (tv.tuner_formats & V4L2_STD_PAL) {
+#define TVEEPROM_TUNER_FORMAT_ALL (V4L2_STD_B | V4L2_STD_GH | \
+ V4L2_STD_MN | \
+ V4L2_STD_PAL_I | \
+ V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC | \
+ V4L2_STD_DK)
+ if ((tv.tuner_formats & TVEEPROM_TUNER_FORMAT_ALL)
+ == TVEEPROM_TUNER_FORMAT_ALL) {
+ CX18_DEBUG_INFO("Worldwide tuner detected\n");
+ cx->std = V4L2_STD_ALL;
+ } else if (tv.tuner_formats & V4L2_STD_PAL) {
CX18_DEBUG_INFO("PAL tuner detected\n");
cx->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
} else if (tv.tuner_formats & V4L2_STD_NTSC) {
@@ -818,7 +827,7 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev,
cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
pci_write_config_word(pci_dev, PCI_COMMAND, cmd);
- pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &cx->card_rev);
+ cx->card_rev = pci_dev->revision;
pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency);
if (pci_latency < 64 && cx18_pci_latency) {
@@ -1001,7 +1010,15 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
if (cx->card->hw_all & CX18_HW_TVEEPROM) {
/* Based on the model number the cardtype may be changed.
The PCI IDs are not always reliable. */
+ const struct cx18_card *orig_card = cx->card;
cx18_process_eeprom(cx);
+
+ if (cx->card != orig_card) {
+ /* Changed the cardtype; re-reset the I2C chips */
+ cx18_gpio_init(cx);
+ cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL,
+ core, reset, (u32) CX18_GPIO_RESET_I2C);
+ }
}
if (cx->card->comment)
CX18_INFO("%s", cx->card->comment);
@@ -1087,6 +1104,8 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
/* The tuner is fixed to the standard. The other inputs (e.g. S-Video)
are not. */
cx->tuner_std = cx->std;
+ if (cx->std == V4L2_STD_ALL)
+ cx->std = V4L2_STD_NTSC_M;
retval = cx18_streams_setup(cx);
if (retval) {
@@ -1133,6 +1152,7 @@ int cx18_init_on_first_open(struct cx18 *cx)
int fw_retry_count = 3;
struct v4l2_frequency vf;
struct cx18_open_id fh;
+ v4l2_std_id std;
fh.cx = cx;
@@ -1220,7 +1240,8 @@ int cx18_init_on_first_open(struct cx18 *cx)
/* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
in one place. */
cx->std++; /* Force full standard initialization */
- cx18_s_std(NULL, &fh, &cx->tuner_std);
+ std = (cx->tuner_std == V4L2_STD_ALL) ? V4L2_STD_NTSC_M : cx->tuner_std;
+ cx18_s_std(NULL, &fh, &std);
cx18_s_frequency(NULL, &fh, &vf);
return 0;
}
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index b86a740c68df..086427288de8 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -65,6 +65,10 @@
#include "dvb_net.h"
#include "dvbdev.h"
+/* Videobuf / YUV support */
+#include <media/videobuf-core.h>
+#include <media/videobuf-vmalloc.h>
+
#ifndef CONFIG_PCI
# error "This driver requires kernel PCI support."
#endif
@@ -403,6 +407,23 @@ struct cx18_stream {
struct cx18_queue q_idle; /* idle - not in rotation */
struct work_struct out_work_order;
+
+ /* Videobuf for YUV video */
+ u32 pixelformat;
+ struct list_head vb_capture; /* video capture queue */
+ spinlock_t vb_lock;
+ struct timer_list vb_timeout;
+
+ struct videobuf_queue vbuf_q;
+ spinlock_t vbuf_q_lock; /* Protect vbuf_q */
+ enum v4l2_buf_type vb_type;
+};
+
+struct cx18_videobuf_buffer {
+ /* Common video buffer sub-system struct */
+ struct videobuf_buffer vb;
+ v4l2_std_id tvnorm; /* selected tv norm */
+ u32 bytes_used;
};
struct cx18_open_id {
@@ -410,6 +431,10 @@ struct cx18_open_id {
u32 open_id;
int type;
struct cx18 *cx;
+
+ struct videobuf_queue vbuf_q;
+ spinlock_t s_lock; /* Protect vbuf_q */
+ enum v4l2_buf_type vb_type;
};
static inline struct cx18_open_id *fh2id(struct v4l2_fh *fh)
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c
index e9802d99439b..07411f34885a 100644
--- a/drivers/media/video/cx18/cx18-fileops.c
+++ b/drivers/media/video/cx18/cx18-fileops.c
@@ -597,6 +597,13 @@ ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count,
mutex_unlock(&cx->serialize_lock);
if (rc)
return rc;
+
+ if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (id->type == CX18_ENC_STREAM_TYPE_YUV)) {
+ return videobuf_read_stream(&s->vbuf_q, buf, count, pos, 0,
+ filp->f_flags & O_NONBLOCK);
+ }
+
return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
}
@@ -622,6 +629,15 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
CX18_DEBUG_FILE("Encoder poll started capture\n");
}
+ if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (id->type == CX18_ENC_STREAM_TYPE_YUV)) {
+ int videobuf_poll = videobuf_poll_stream(filp, &s->vbuf_q, wait);
+ if (eof && videobuf_poll == POLLERR)
+ return POLLHUP;
+ else
+ return videobuf_poll;
+ }
+
/* add stream's waitq to the poll list */
CX18_DEBUG_HI_FILE("Encoder poll\n");
poll_wait(filp, &s->waitq, wait);
@@ -633,6 +649,58 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
return 0;
}
+int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct cx18_open_id *id = file->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+ int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags);
+
+ if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (id->type == CX18_ENC_STREAM_TYPE_YUV)) {
+
+ /* Start a capture if there is none */
+ if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
+ int rc;
+
+ mutex_lock(&cx->serialize_lock);
+ rc = cx18_start_capture(id);
+ mutex_unlock(&cx->serialize_lock);
+ if (rc) {
+ CX18_DEBUG_INFO(
+ "Could not start capture for %s (%d)\n",
+ s->name, rc);
+ return -EINVAL;
+ }
+ CX18_DEBUG_FILE("Encoder mmap started capture\n");
+ }
+
+ return videobuf_mmap_mapper(&s->vbuf_q, vma);
+ }
+
+ return -EINVAL;
+}
+
+void cx18_vb_timeout(unsigned long data)
+{
+ struct cx18_stream *s = (struct cx18_stream *)data;
+ struct cx18_videobuf_buffer *buf;
+ unsigned long flags;
+
+ /* Return all of the buffers in error state, so the vbi/vid inode
+ * can return from blocking.
+ */
+ spin_lock_irqsave(&s->vb_lock, flags);
+ while (!list_empty(&s->vb_capture)) {
+ buf = list_entry(s->vb_capture.next,
+ struct cx18_videobuf_buffer, vb.queue);
+ list_del(&buf->vb.queue);
+ buf->vb.state = VIDEOBUF_ERROR;
+ wake_up(&buf->vb.done);
+ }
+ spin_unlock_irqrestore(&s->vb_lock, flags);
+}
+
void cx18_stop_capture(struct cx18_open_id *id, int gop_end)
{
struct cx18 *cx = id->cx;
@@ -716,6 +784,8 @@ int cx18_v4l2_close(struct file *filp)
cx18_release_stream(s);
} else {
cx18_stop_capture(id, 0);
+ if (id->type == CX18_ENC_STREAM_TYPE_YUV)
+ videobuf_mmap_free(&id->vbuf_q);
}
kfree(id);
mutex_unlock(&cx->serialize_lock);
diff --git a/drivers/media/video/cx18/cx18-fileops.h b/drivers/media/video/cx18/cx18-fileops.h
index 5c8fcb884f0a..b9e5110ad043 100644
--- a/drivers/media/video/cx18/cx18-fileops.h
+++ b/drivers/media/video/cx18/cx18-fileops.h
@@ -33,6 +33,8 @@ int cx18_start_capture(struct cx18_open_id *id);
void cx18_stop_capture(struct cx18_open_id *id, int gop_end);
void cx18_mute(struct cx18 *cx);
void cx18_unmute(struct cx18 *cx);
+int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma);
+void cx18_vb_timeout(unsigned long data);
/* Shared with cx18-alsa module */
int cx18_claim_stream(struct cx18_open_id *id, int type);
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index 4f041c033c54..1933d4d11bf2 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -150,6 +150,7 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
{
struct cx18_open_id *id = fh2id(fh);
struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
pixfmt->width = cx->cxhdl.width;
@@ -158,9 +159,13 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
pixfmt->field = V4L2_FIELD_INTERLACED;
pixfmt->priv = 0;
if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
- pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
- /* YUV size is (Y=(h*720) + UV=(h*(720/2))) */
- pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2;
+ pixfmt->pixelformat = s->pixelformat;
+ /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2)))
+ UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */
+ if (s->pixelformat == V4L2_PIX_FMT_HM12)
+ pixfmt->sizeimage = pixfmt->height * 720 * 3 / 2;
+ else
+ pixfmt->sizeimage = pixfmt->height * 720 * 2;
pixfmt->bytesperline = 720;
} else {
pixfmt->pixelformat = V4L2_PIX_FMT_MPEG;
@@ -237,7 +242,6 @@ static int cx18_try_fmt_vid_cap(struct file *file, void *fh,
h = min(h, cx->is_50hz ? 576 : 480);
h = max(h, min_h);
- cx18_g_fmt_vid_cap(file, fh, fmt);
fmt->fmt.pix.width = w;
fmt->fmt.pix.height = h;
return 0;
@@ -274,6 +278,7 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
struct cx18_open_id *id = fh2id(fh);
struct cx18 *cx = id->cx;
struct v4l2_mbus_framefmt mbus_fmt;
+ struct cx18_stream *s = &cx->streams[id->type];
int ret;
int w, h;
@@ -283,12 +288,15 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
w = fmt->fmt.pix.width;
h = fmt->fmt.pix.height;
- if (cx->cxhdl.width == w && cx->cxhdl.height == h)
+ if (cx->cxhdl.width == w && cx->cxhdl.height == h &&
+ s->pixelformat == fmt->fmt.pix.pixelformat)
return 0;
if (atomic_read(&cx->ana_capturing) > 0)
return -EBUSY;
+ s->pixelformat = fmt->fmt.pix.pixelformat;
+
mbus_fmt.width = cx->cxhdl.width = w;
mbus_fmt.height = cx->cxhdl.height = h;
mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
@@ -540,16 +548,19 @@ static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
static int cx18_enum_fmt_vid_cap(struct file *file, void *fh,
struct v4l2_fmtdesc *fmt)
{
- static struct v4l2_fmtdesc formats[] = {
+ static const struct v4l2_fmtdesc formats[] = {
{ 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0,
"HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 }
},
{ 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FMT_FLAG_COMPRESSED,
"MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 }
- }
+ },
+ { 2, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0,
+ "UYVY 4:2:2", V4L2_PIX_FMT_UYVY, { 0, 0, 0, 0 }
+ },
};
- if (fmt->index > 1)
+ if (fmt->index > ARRAY_SIZE(formats) - 1)
return -EINVAL;
*fmt = formats[fmt->index];
return 0;
@@ -863,6 +874,117 @@ static int cx18_g_enc_index(struct file *file, void *fh,
return 0;
}
+static struct videobuf_queue *cx18_vb_queue(struct cx18_open_id *id)
+{
+ struct videobuf_queue *q = NULL;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ switch (s->vb_type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ q = &s->vbuf_q;
+ break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ break;
+ default:
+ break;
+ }
+ return q;
+}
+
+static int cx18_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct cx18_open_id *id = file->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ /* Start the hardware only if we're the video device */
+ if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+ return -EINVAL;
+
+ if (id->type != CX18_ENC_STREAM_TYPE_YUV)
+ return -EINVAL;
+
+ /* Establish a buffer timeout */
+ mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies);
+
+ return videobuf_streamon(cx18_vb_queue(id));
+}
+
+static int cx18_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct cx18_open_id *id = file->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ /* Start the hardware only if we're the video device */
+ if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+ return -EINVAL;
+
+ if (id->type != CX18_ENC_STREAM_TYPE_YUV)
+ return -EINVAL;
+
+ return videobuf_streamoff(cx18_vb_queue(id));
+}
+
+static int cx18_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *rb)
+{
+ struct cx18_open_id *id = file->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+ return -EINVAL;
+
+ return videobuf_reqbufs(cx18_vb_queue(id), rb);
+}
+
+static int cx18_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *b)
+{
+ struct cx18_open_id *id = file->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+ return -EINVAL;
+
+ return videobuf_querybuf(cx18_vb_queue(id), b);
+}
+
+static int cx18_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct cx18_open_id *id = file->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+ return -EINVAL;
+
+ return videobuf_qbuf(cx18_vb_queue(id), b);
+}
+
+static int cx18_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct cx18_open_id *id = file->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE))
+ return -EINVAL;
+
+ return videobuf_dqbuf(cx18_vb_queue(id), b, file->f_flags & O_NONBLOCK);
+}
+
static int cx18_encoder_cmd(struct file *file, void *fh,
struct v4l2_encoder_cmd *enc)
{
@@ -1081,6 +1203,12 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = {
.vidioc_s_register = cx18_s_register,
#endif
.vidioc_default = cx18_default,
+ .vidioc_streamon = cx18_streamon,
+ .vidioc_streamoff = cx18_streamoff,
+ .vidioc_reqbufs = cx18_reqbufs,
+ .vidioc_querybuf = cx18_querybuf,
+ .vidioc_qbuf = cx18_qbuf,
+ .vidioc_dqbuf = cx18_dqbuf,
};
void cx18_set_funcs(struct video_device *vdev)
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
index 9605d54bd083..c07191e09fcb 100644
--- a/drivers/media/video/cx18/cx18-mailbox.c
+++ b/drivers/media/video/cx18/cx18-mailbox.c
@@ -81,6 +81,7 @@ static const struct cx18_api_info api_info[] = {
API_ENTRY(CPU, CX18_CPU_SET_SLICED_VBI_PARAM, 0),
API_ENTRY(CPU, CX18_CPU_SET_USERDATA_PLACE_HOLDER, 0),
API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_VFC_PARAM, 0),
API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0),
API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST),
API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, API_SLOW),
@@ -158,6 +159,60 @@ static void cx18_mdl_send_to_dvb(struct cx18_stream *s, struct cx18_mdl *mdl)
}
}
+static void cx18_mdl_send_to_videobuf(struct cx18_stream *s,
+ struct cx18_mdl *mdl)
+{
+ struct cx18_videobuf_buffer *vb_buf;
+ struct cx18_buffer *buf;
+ u8 *p;
+ u32 offset = 0;
+ int dispatch = 0;
+
+ if (mdl->bytesused == 0)
+ return;
+
+ /* Acquire a videobuf buffer, clone to and and release it */
+ spin_lock(&s->vb_lock);
+ if (list_empty(&s->vb_capture))
+ goto out;
+
+ vb_buf = list_first_entry(&s->vb_capture, struct cx18_videobuf_buffer,
+ vb.queue);
+
+ p = videobuf_to_vmalloc(&vb_buf->vb);
+ if (!p)
+ goto out;
+
+ offset = vb_buf->bytes_used;
+ list_for_each_entry(buf, &mdl->buf_list, list) {
+ if (buf->bytesused == 0)
+ break;
+
+ if ((offset + buf->bytesused) <= vb_buf->vb.bsize) {
+ memcpy(p + offset, buf->buf, buf->bytesused);
+ offset += buf->bytesused;
+ vb_buf->bytes_used += buf->bytesused;
+ }
+ }
+
+ /* If we've filled the buffer as per the callers res then dispatch it */
+ if (vb_buf->bytes_used >= (vb_buf->vb.width * vb_buf->vb.height * 2)) {
+ dispatch = 1;
+ vb_buf->bytes_used = 0;
+ }
+
+ if (dispatch) {
+ vb_buf->vb.ts = ktime_to_timeval(ktime_get());
+ list_del(&vb_buf->vb.queue);
+ vb_buf->vb.state = VIDEOBUF_DONE;
+ wake_up(&vb_buf->vb.done);
+ }
+
+ mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies);
+
+out:
+ spin_unlock(&s->vb_lock);
+}
static void cx18_mdl_send_to_alsa(struct cx18 *cx, struct cx18_stream *s,
struct cx18_mdl *mdl)
@@ -263,6 +318,9 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order)
} else {
cx18_enqueue(s, mdl, &s->q_full);
}
+ } else if (s->type == CX18_ENC_STREAM_TYPE_YUV) {
+ cx18_mdl_send_to_videobuf(s, mdl);
+ cx18_enqueue(s, mdl, &s->q_free);
} else {
cx18_enqueue(s, mdl, &s->q_full);
if (s->type == CX18_ENC_STREAM_TYPE_IDX)
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index 6fbc356113c1..852f420fd271 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -44,6 +44,7 @@ static struct v4l2_file_operations cx18_v4l2_enc_fops = {
.unlocked_ioctl = cx18_v4l2_ioctl,
.release = cx18_v4l2_close,
.poll = cx18_v4l2_enc_poll,
+ .mmap = cx18_v4l2_mmap,
};
/* offset from 0 to register ts v4l2 minors on */
@@ -97,6 +98,141 @@ static struct {
},
};
+
+void cx18_dma_free(struct videobuf_queue *q,
+ struct cx18_stream *s, struct cx18_videobuf_buffer *buf)
+{
+ videobuf_waiton(q, &buf->vb, 0, 0);
+ videobuf_vmalloc_free(&buf->vb);
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int cx18_prepare_buffer(struct videobuf_queue *q,
+ struct cx18_stream *s,
+ struct cx18_videobuf_buffer *buf,
+ u32 pixelformat,
+ unsigned int width, unsigned int height,
+ enum v4l2_field field)
+{
+ struct cx18 *cx = s->cx;
+ int rc = 0;
+
+ /* check settings */
+ buf->bytes_used = 0;
+
+ if ((width < 48) || (height < 32))
+ return -EINVAL;
+
+ buf->vb.size = (width * height * 2);
+ if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size))
+ return -EINVAL;
+
+ /* alloc + fill struct (if changed) */
+ if (buf->vb.width != width || buf->vb.height != height ||
+ buf->vb.field != field || s->pixelformat != pixelformat ||
+ buf->tvnorm != cx->std) {
+
+ buf->vb.width = width;
+ buf->vb.height = height;
+ buf->vb.field = field;
+ buf->tvnorm = cx->std;
+ s->pixelformat = pixelformat;
+
+ cx18_dma_free(q, s, buf);
+ }
+
+ if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size))
+ return -EINVAL;
+
+ if (buf->vb.field == 0)
+ buf->vb.field = V4L2_FIELD_INTERLACED;
+
+ if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ buf->vb.width = width;
+ buf->vb.height = height;
+ buf->vb.field = field;
+ buf->tvnorm = cx->std;
+ s->pixelformat = pixelformat;
+
+ rc = videobuf_iolock(q, &buf->vb, NULL);
+ if (rc != 0)
+ goto fail;
+ }
+ buf->vb.state = VIDEOBUF_PREPARED;
+ return 0;
+
+fail:
+ cx18_dma_free(q, s, buf);
+ return rc;
+
+}
+
+/* VB_MIN_BUFSIZE is lcm(1440 * 480, 1440 * 576)
+ 1440 is a single line of 4:2:2 YUV at 720 luma samples wide
+*/
+#define VB_MIN_BUFFERS 32
+#define VB_MIN_BUFSIZE 4147200
+
+static int buffer_setup(struct videobuf_queue *q,
+ unsigned int *count, unsigned int *size)
+{
+ struct cx18_stream *s = q->priv_data;
+ struct cx18 *cx = s->cx;
+
+ *size = 2 * cx->cxhdl.width * cx->cxhdl.height;
+ if (*count == 0)
+ *count = VB_MIN_BUFFERS;
+
+ while (*size * *count > VB_MIN_BUFFERS * VB_MIN_BUFSIZE)
+ (*count)--;
+
+ q->field = V4L2_FIELD_INTERLACED;
+ q->last = V4L2_FIELD_INTERLACED;
+
+ return 0;
+}
+
+static int buffer_prepare(struct videobuf_queue *q,
+ struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct cx18_videobuf_buffer *buf =
+ container_of(vb, struct cx18_videobuf_buffer, vb);
+ struct cx18_stream *s = q->priv_data;
+ struct cx18 *cx = s->cx;
+
+ return cx18_prepare_buffer(q, s, buf, s->pixelformat,
+ cx->cxhdl.width, cx->cxhdl.height, field);
+}
+
+static void buffer_release(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct cx18_videobuf_buffer *buf =
+ container_of(vb, struct cx18_videobuf_buffer, vb);
+ struct cx18_stream *s = q->priv_data;
+
+ cx18_dma_free(q, s, buf);
+}
+
+static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+ struct cx18_videobuf_buffer *buf =
+ container_of(vb, struct cx18_videobuf_buffer, vb);
+ struct cx18_stream *s = q->priv_data;
+
+ buf->vb.state = VIDEOBUF_QUEUED;
+
+ list_add_tail(&buf->vb.queue, &s->vb_capture);
+}
+
+static struct videobuf_queue_ops cx18_videobuf_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
static void cx18_stream_init(struct cx18 *cx, int type)
{
struct cx18_stream *s = &cx->streams[type];
@@ -132,6 +268,26 @@ static void cx18_stream_init(struct cx18 *cx, int type)
cx18_queue_init(&s->q_idle);
INIT_WORK(&s->out_work_order, cx18_out_work_handler);
+
+ INIT_LIST_HEAD(&s->vb_capture);
+ s->vb_timeout.function = cx18_vb_timeout;
+ s->vb_timeout.data = (unsigned long)s;
+ init_timer(&s->vb_timeout);
+ spin_lock_init(&s->vb_lock);
+ if (type == CX18_ENC_STREAM_TYPE_YUV) {
+ spin_lock_init(&s->vbuf_q_lock);
+
+ s->vb_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ videobuf_queue_vmalloc_init(&s->vbuf_q, &cx18_videobuf_qops,
+ &cx->pci_dev->dev, &s->vbuf_q_lock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_INTERLACED,
+ sizeof(struct cx18_videobuf_buffer),
+ s, &cx->serialize_lock);
+
+ /* Assume the previous pixel default */
+ s->pixelformat = V4L2_PIX_FMT_HM12;
+ }
}
static int cx18_prep_dev(struct cx18 *cx, int type)
@@ -372,6 +528,9 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister)
if (vdev == NULL)
continue;
+ if (type == CX18_ENC_STREAM_TYPE_YUV)
+ videobuf_mmap_free(&cx->streams[type].vbuf_q);
+
cx18_stream_free(&cx->streams[type]);
/* Unregister or release device */
@@ -581,7 +740,10 @@ static void cx18_stream_configure_mdls(struct cx18_stream *s)
* Set the MDL size to the exact size needed for one frame.
* Use enough buffers per MDL to cover the MDL size
*/
- s->mdl_size = 720 * s->cx->cxhdl.height * 3 / 2;
+ if (s->pixelformat == V4L2_PIX_FMT_HM12)
+ s->mdl_size = 720 * s->cx->cxhdl.height * 3 / 2;
+ else
+ s->mdl_size = 720 * s->cx->cxhdl.height * 2;
s->bufs_per_mdl = s->mdl_size / s->buf_size;
if (s->mdl_size % s->buf_size)
s->bufs_per_mdl++;
@@ -729,6 +891,19 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
test_bit(CX18_F_I_RADIO_USER, &cx->i_flags))
cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
(v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8) | 1);
+
+ /* Enable the Video Format Converter for UYVY 4:2:2 support,
+ * rather than the default HM12 Macroblovk 4:2:0 support.
+ */
+ if (captype == CAPTURE_CHANNEL_TYPE_YUV) {
+ if (s->pixelformat == V4L2_PIX_FMT_UYVY)
+ cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2,
+ s->handle, 1);
+ else
+ /* If in doubt, default to HM12 */
+ cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2,
+ s->handle, 0);
+ }
}
if (atomic_read(&cx->tot_capturing) == 0) {
diff --git a/drivers/media/video/cx18/cx18-version.h b/drivers/media/video/cx18/cx18-version.h
index 3e1aec4bcfde..cd189b6bbe20 100644
--- a/drivers/media/video/cx18/cx18-version.h
+++ b/drivers/media/video/cx18/cx18-version.h
@@ -24,7 +24,7 @@
#define CX18_DRIVER_NAME "cx18"
#define CX18_DRIVER_VERSION_MAJOR 1
-#define CX18_DRIVER_VERSION_MINOR 4
+#define CX18_DRIVER_VERSION_MINOR 5
#define CX18_DRIVER_VERSION_PATCHLEVEL 0
#define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL)
diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h
index 935f557acbd0..767a8d23e3f2 100644
--- a/drivers/media/video/cx18/cx23418.h
+++ b/drivers/media/video/cx18/cx23418.h
@@ -342,6 +342,12 @@
ReturnCode */
#define CX18_CPU_GET_ENC_PTS (CPU_CMD_MASK_CAPTURE | 0x0022)
+/* Description: Set VFC parameters
+ IN[0] - task handle
+ IN[1] - VFC enable flag, 1 - enable, 0 - disable
+*/
+#define CX18_CPU_SET_VFC_PARAM (CPU_CMD_MASK_CAPTURE | 0x0023)
+
/* Below is the list of commands related to the data exchange */
#define CPU_CMD_MASK_DE (CPU_CMD_MASK | 0x040000)
diff --git a/drivers/media/video/cx231xx/cx231xx-avcore.c b/drivers/media/video/cx231xx/cx231xx-avcore.c
index 280df43ca446..8d7813415760 100644
--- a/drivers/media/video/cx231xx/cx231xx-avcore.c
+++ b/drivers/media/video/cx231xx/cx231xx-avcore.c
@@ -1354,7 +1354,7 @@ void cx231xx_dump_SC_reg(struct cx231xx *dev)
{
u8 value[4] = { 0, 0, 0, 0 };
int status = 0;
- cx231xx_info("cx231xx_dump_SC_reg %s!\n", __TIME__);
+ cx231xx_info("cx231xx_dump_SC_reg!\n");
status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, BOARD_CFG_STAT,
value, 4);
diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c
index f49230d170e6..22703815a31f 100644
--- a/drivers/media/video/cx231xx/cx231xx-cards.c
+++ b/drivers/media/video/cx231xx/cx231xx-cards.c
@@ -401,6 +401,44 @@ struct cx231xx_board cx231xx_boards[] = {
.gpio = NULL,
} },
},
+ [CX231XX_BOARD_KWORLD_UB430_USB_HYBRID] = {
+ .name = "Kworld UB430 USB Hybrid",
+ .tuner_type = TUNER_NXP_TDA18271,
+ .tuner_addr = 0x60,
+ .decoder = CX231XX_AVDECODER,
+ .output_mode = OUT_MODE_VIP11,
+ .demod_xfer_mode = 0,
+ .ctl_pin_status_mask = 0xFFFFFFC4,
+ .agc_analog_digital_select_gpio = 0x11, /* According with PV cxPolaris.inf file */
+ .tuner_sif_gpio = -1,
+ .tuner_scl_gpio = -1,
+ .tuner_sda_gpio = -1,
+ .gpio_pin_status_mask = 0x4001000,
+ .tuner_i2c_master = 2,
+ .demod_i2c_master = 1,
+ .ir_i2c_master = 2,
+ .has_dvb = 1,
+ .demod_addr = 0x10,
+ .norm = V4L2_STD_PAL_M,
+ .input = {{
+ .type = CX231XX_VMUX_TELEVISION,
+ .vmux = CX231XX_VIN_3_1,
+ .amux = CX231XX_AMUX_VIDEO,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_COMPOSITE1,
+ .vmux = CX231XX_VIN_2_1,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_SVIDEO,
+ .vmux = CX231XX_VIN_1_1 |
+ (CX231XX_VIN_1_2 << 8) |
+ CX25840_SVIDEO_ON,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ } },
+ },
[CX231XX_BOARD_PV_PLAYTV_USB_HYBRID] = {
.name = "Pixelview PlayTV USB Hybrid",
.tuner_type = TUNER_NXP_TDA18271,
@@ -469,6 +507,31 @@ struct cx231xx_board cx231xx_boards[] = {
}
},
},
+
+ [CX231XX_BOARD_ICONBIT_U100] = {
+ .name = "Iconbit Analog Stick U100 FM",
+ .tuner_type = TUNER_ABSENT,
+ .decoder = CX231XX_AVDECODER,
+ .output_mode = OUT_MODE_VIP11,
+ .demod_xfer_mode = 0,
+ .ctl_pin_status_mask = 0xFFFFFFC4,
+ .agc_analog_digital_select_gpio = 0x1C,
+ .gpio_pin_status_mask = 0x4001000,
+
+ .input = {{
+ .type = CX231XX_VMUX_COMPOSITE1,
+ .vmux = CX231XX_VIN_2_1,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_SVIDEO,
+ .vmux = CX231XX_VIN_1_1 |
+ (CX231XX_VIN_1_2 << 8) |
+ CX25840_SVIDEO_ON,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ } },
+ },
};
const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
@@ -500,6 +563,10 @@ struct usb_device_id cx231xx_id_table[] = {
.driver_info = CX231XX_BOARD_PV_PLAYTV_USB_HYBRID},
{USB_DEVICE(USB_VID_PIXELVIEW, 0x5014),
.driver_info = CX231XX_BOARD_PV_XCAPTURE_USB},
+ {USB_DEVICE(0x1b80, 0xe424),
+ .driver_info = CX231XX_BOARD_KWORLD_UB430_USB_HYBRID},
+ {USB_DEVICE(0x1f4d, 0x0237),
+ .driver_info = CX231XX_BOARD_ICONBIT_U100},
{},
};
diff --git a/drivers/media/video/cx231xx/cx231xx-dvb.c b/drivers/media/video/cx231xx/cx231xx-dvb.c
index 363aa6004221..da9a4a0aab79 100644
--- a/drivers/media/video/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/video/cx231xx/cx231xx-dvb.c
@@ -704,6 +704,7 @@ static int dvb_init(struct cx231xx *dev)
break;
case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
+ case CX231XX_BOARD_KWORLD_UB430_USB_HYBRID:
printk(KERN_INFO "%s: looking for demod on i2c bus: %d\n",
__func__, i2c_adapter_id(&dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap));
diff --git a/drivers/media/video/cx231xx/cx231xx.h b/drivers/media/video/cx231xx/cx231xx.h
index bd4a9cf29577..46dd84067816 100644
--- a/drivers/media/video/cx231xx/cx231xx.h
+++ b/drivers/media/video/cx231xx/cx231xx.h
@@ -65,6 +65,8 @@
#define CX231XX_BOARD_HAUPPAUGE_USBLIVE2 9
#define CX231XX_BOARD_PV_PLAYTV_USB_HYBRID 10
#define CX231XX_BOARD_PV_XCAPTURE_USB 11
+#define CX231XX_BOARD_KWORLD_UB430_USB_HYBRID 12
+#define CX231XX_BOARD_ICONBIT_U100 13
/* Limits minimum and default number of buffers */
#define CX231XX_MIN_BUF 4
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index ea88722cb4ab..2354336862cf 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -1399,6 +1399,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
else
altera_init(&netup_config, fw);
+ release_firmware(fw);
break;
}
}
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
index 9933810b4e33..64d9b2136ff6 100644
--- a/drivers/media/video/cx23885/cx23885-core.c
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -2045,7 +2045,7 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
}
/* print pci info */
- pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
+ dev->pci_rev = pci_dev->revision;
pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
"latency: %d, mmio: 0x%llx\n", dev->name,
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index bca307eb1e24..11e49bbc4a66 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -1060,18 +1060,21 @@ static int mpeg_open(struct file *file)
/* Make sure we can acquire the hardware */
drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
- if (drv) {
- err = drv->request_acquire(drv);
- if(err != 0) {
- dprintk(1,"%s: Unable to acquire hardware, %d\n", __func__, err);
- mutex_unlock(&dev->core->lock);
- return err;
- }
+ if (!drv) {
+ dprintk(1, "%s: blackbird driver is not loaded\n", __func__);
+ mutex_unlock(&dev->core->lock);
+ return -ENODEV;
+ }
+
+ err = drv->request_acquire(drv);
+ if (err != 0) {
+ dprintk(1,"%s: Unable to acquire hardware, %d\n", __func__, err);
+ mutex_unlock(&dev->core->lock);
+ return err;
}
- if (!atomic_read(&dev->core->mpeg_users) && blackbird_initialize_codec(dev) < 0) {
- if (drv)
- drv->request_release(drv);
+ if (!dev->core->mpeg_users && blackbird_initialize_codec(dev) < 0) {
+ drv->request_release(drv);
mutex_unlock(&dev->core->lock);
return -EINVAL;
}
@@ -1080,8 +1083,7 @@ static int mpeg_open(struct file *file)
/* allocate + initialize per filehandle data */
fh = kzalloc(sizeof(*fh),GFP_KERNEL);
if (NULL == fh) {
- if (drv)
- drv->request_release(drv);
+ drv->request_release(drv);
mutex_unlock(&dev->core->lock);
return -ENOMEM;
}
@@ -1099,7 +1101,7 @@ static int mpeg_open(struct file *file)
cx88_set_scale(dev->core, dev->width, dev->height,
fh->mpegq.field);
- atomic_inc(&dev->core->mpeg_users);
+ dev->core->mpeg_users++;
mutex_unlock(&dev->core->lock);
return 0;
}
@@ -1110,7 +1112,9 @@ static int mpeg_release(struct file *file)
struct cx8802_dev *dev = fh->dev;
struct cx8802_driver *drv = NULL;
- if (dev->mpeg_active && atomic_read(&dev->core->mpeg_users) == 1)
+ mutex_lock(&dev->core->lock);
+
+ if (dev->mpeg_active && dev->core->mpeg_users == 1)
blackbird_stop_codec(dev);
cx8802_cancel_buffers(fh->dev);
@@ -1119,17 +1123,18 @@ static int mpeg_release(struct file *file)
videobuf_mmap_free(&fh->mpegq);
- mutex_lock(&dev->core->lock);
file->private_data = NULL;
kfree(fh);
- mutex_unlock(&dev->core->lock);
/* Make sure we release the hardware */
drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
+ WARN_ON(!drv);
if (drv)
drv->request_release(drv);
- atomic_dec(&dev->core->mpeg_users);
+ dev->core->mpeg_users--;
+
+ mutex_unlock(&dev->core->lock);
return 0;
}
@@ -1334,11 +1339,9 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
blackbird_register_video(dev);
/* initial device configuration: needed ? */
- mutex_lock(&dev->core->lock);
// init_controls(core);
cx88_set_tvnorm(core,core->tvnorm);
cx88_video_mux(core,0);
- mutex_unlock(&dev->core->lock);
return 0;
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 7b8c9d3b6efc..c69df7ebb6a7 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -133,6 +133,7 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire)
return -EINVAL;
}
+ mutex_lock(&dev->core->lock);
drv = cx8802_get_driver(dev, CX88_MPEG_DVB);
if (drv) {
if (acquire){
@@ -143,6 +144,7 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire)
dev->frontends.active_fe_id = 0;
}
}
+ mutex_unlock(&dev->core->lock);
return ret;
}
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index addf9545e9bf..1a7b983f8297 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -78,6 +78,7 @@ static void flush_request_modules(struct cx8802_dev *dev)
static LIST_HEAD(cx8802_devlist);
+static DEFINE_MUTEX(cx8802_mutex);
/* ------------------------------------------------------------------ */
static int cx8802_start_dma(struct cx8802_dev *dev,
@@ -474,7 +475,7 @@ static int cx8802_init_common(struct cx8802_dev *dev)
return -EIO;
}
- pci_read_config_byte(dev->pci, PCI_CLASS_REVISION, &dev->pci_rev);
+ dev->pci_rev = dev->pci->revision;
pci_read_config_byte(dev->pci, PCI_LATENCY_TIMER, &dev->pci_lat);
printk(KERN_INFO "%s/2: found at %s, rev: %d, irq: %d, "
"latency: %d, mmio: 0x%llx\n", dev->core->name,
@@ -624,13 +625,11 @@ static int cx8802_request_acquire(struct cx8802_driver *drv)
if (drv->advise_acquire)
{
- mutex_lock(&drv->core->lock);
core->active_ref++;
if (core->active_type_id == CX88_BOARD_NONE) {
core->active_type_id = drv->type_id;
drv->advise_acquire(drv);
}
- mutex_unlock(&drv->core->lock);
mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __func__, cx_read(MO_GP0_IO));
}
@@ -643,14 +642,12 @@ static int cx8802_request_release(struct cx8802_driver *drv)
{
struct cx88_core *core = drv->core;
- mutex_lock(&drv->core->lock);
if (drv->advise_release && --core->active_ref == 0)
{
drv->advise_release(drv);
core->active_type_id = CX88_BOARD_NONE;
mpeg_dbg(1,"%s() Post release GPIO=%x\n", __func__, cx_read(MO_GP0_IO));
}
- mutex_unlock(&drv->core->lock);
return 0;
}
@@ -693,6 +690,8 @@ int cx8802_register_driver(struct cx8802_driver *drv)
return err;
}
+ mutex_lock(&cx8802_mutex);
+
list_for_each_entry(dev, &cx8802_devlist, devlist) {
printk(KERN_INFO
"%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n",
@@ -702,8 +701,10 @@ int cx8802_register_driver(struct cx8802_driver *drv)
/* Bring up a new struct for each driver instance */
driver = kzalloc(sizeof(*drv),GFP_KERNEL);
- if (driver == NULL)
- return -ENOMEM;
+ if (driver == NULL) {
+ err = -ENOMEM;
+ goto out;
+ }
/* Snapshot of the driver registration data */
drv->core = dev->core;
@@ -713,21 +714,23 @@ int cx8802_register_driver(struct cx8802_driver *drv)
drv->request_release = cx8802_request_release;
memcpy(driver, drv, sizeof(*driver));
+ mutex_lock(&drv->core->lock);
err = drv->probe(driver);
if (err == 0) {
i++;
- mutex_lock(&drv->core->lock);
list_add_tail(&driver->drvlist, &dev->drvlist);
- mutex_unlock(&drv->core->lock);
} else {
printk(KERN_ERR
"%s/2: cx8802 probe failed, err = %d\n",
dev->core->name, err);
}
-
+ mutex_unlock(&drv->core->lock);
}
- return i ? 0 : -ENODEV;
+ err = i ? 0 : -ENODEV;
+out:
+ mutex_unlock(&cx8802_mutex);
+ return err;
}
int cx8802_unregister_driver(struct cx8802_driver *drv)
@@ -741,6 +744,8 @@ int cx8802_unregister_driver(struct cx8802_driver *drv)
drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird",
drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive");
+ mutex_lock(&cx8802_mutex);
+
list_for_each_entry(dev, &cx8802_devlist, devlist) {
printk(KERN_INFO
"%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n",
@@ -748,6 +753,8 @@ int cx8802_unregister_driver(struct cx8802_driver *drv)
dev->pci->subsystem_device, dev->core->board.name,
dev->core->boardnr);
+ mutex_lock(&dev->core->lock);
+
list_for_each_entry_safe(d, dtmp, &dev->drvlist, drvlist) {
/* only unregister the correct driver type */
if (d->type_id != drv->type_id)
@@ -755,17 +762,18 @@ int cx8802_unregister_driver(struct cx8802_driver *drv)
err = d->remove(d);
if (err == 0) {
- mutex_lock(&drv->core->lock);
list_del(&d->drvlist);
- mutex_unlock(&drv->core->lock);
kfree(d);
} else
printk(KERN_ERR "%s/2: cx8802 driver remove "
"failed (%d)\n", dev->core->name, err);
}
+ mutex_unlock(&dev->core->lock);
}
+ mutex_unlock(&cx8802_mutex);
+
return err;
}
@@ -803,7 +811,9 @@ static int __devinit cx8802_probe(struct pci_dev *pci_dev,
goto fail_free;
INIT_LIST_HEAD(&dev->drvlist);
+ mutex_lock(&cx8802_mutex);
list_add_tail(&dev->devlist,&cx8802_devlist);
+ mutex_unlock(&cx8802_mutex);
/* now autoload cx88-dvb or cx88-blackbird */
request_modules(dev);
@@ -827,6 +837,8 @@ static void __devexit cx8802_remove(struct pci_dev *pci_dev)
flush_request_modules(dev);
+ mutex_lock(&dev->core->lock);
+
if (!list_empty(&dev->drvlist)) {
struct cx8802_driver *drv, *tmp;
int err;
@@ -838,9 +850,7 @@ static void __devexit cx8802_remove(struct pci_dev *pci_dev)
list_for_each_entry_safe(drv, tmp, &dev->drvlist, drvlist) {
err = drv->remove(drv);
if (err == 0) {
- mutex_lock(&drv->core->lock);
list_del(&drv->drvlist);
- mutex_unlock(&drv->core->lock);
} else
printk(KERN_ERR "%s/2: cx8802 driver remove "
"failed (%d)\n", dev->core->name, err);
@@ -848,6 +858,8 @@ static void __devexit cx8802_remove(struct pci_dev *pci_dev)
}
}
+ mutex_unlock(&dev->core->lock);
+
/* Destroy any 8802 reference. */
dev->core->dvbdev = NULL;
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 287a41ee1c4f..cef4f282e5aa 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -824,7 +824,7 @@ static int video_open(struct file *file)
call_all(core, tuner, s_radio);
}
- atomic_inc(&core->users);
+ core->users++;
mutex_unlock(&core->lock);
return 0;
@@ -922,7 +922,8 @@ static int video_release(struct file *file)
file->private_data = NULL;
kfree(fh);
- if(atomic_dec_and_test(&dev->core->users))
+ dev->core->users--;
+ if (!dev->core->users)
call_all(dev->core, core, s_power, 0);
mutex_unlock(&dev->core->lock);
@@ -1832,7 +1833,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
dev->core = core;
/* print pci info */
- pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
+ dev->pci_rev = pci_dev->revision;
pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
"latency: %d, mmio: 0x%llx\n", core->name,
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index 9b3742a7746c..a399a8b086ba 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -389,8 +389,8 @@ struct cx88_core {
struct mutex lock;
/* various v4l controls */
u32 freq;
- atomic_t users;
- atomic_t mpeg_users;
+ int users;
+ int mpeg_users;
/* cx88-video needs to access cx8802 for hybrid tuner pll access. */
struct cx8802_dev *dvbdev;
@@ -505,6 +505,8 @@ struct cx8802_driver {
int (*suspend)(struct pci_dev *pci_dev, pm_message_t state);
int (*resume)(struct pci_dev *pci_dev);
+ /* Callers to the following functions must hold core->lock */
+
/* MPEG 8802 -> mini driver - Driver probe and configuration */
int (*probe)(struct cx8802_driver *drv);
int (*remove)(struct cx8802_driver *drv);
@@ -561,8 +563,9 @@ struct cx8802_dev {
/* for switching modulation types */
unsigned char ts_gen_cntrl;
- /* List of attached drivers */
+ /* List of attached drivers; must hold core->lock to access */
struct list_head drvlist;
+
struct work_struct request_module_wk;
};
@@ -685,6 +688,8 @@ int cx88_audio_thread(void *data);
int cx8802_register_driver(struct cx8802_driver *drv);
int cx8802_unregister_driver(struct cx8802_driver *drv);
+
+/* Caller must hold core->lock */
struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype);
/* ----------------------------------------------------------- */
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
index 985100ea17a4..3cb78f26df90 100644
--- a/drivers/media/video/em28xx/Kconfig
+++ b/drivers/media/video/em28xx/Kconfig
@@ -38,6 +38,8 @@ config VIDEO_EM28XX_DVB
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
select DVB_TDA10023 if !DVB_FE_CUSTOMISE
select DVB_S921 if !DVB_FE_CUSTOMISE
+ select DVB_DRXD if !DVB_FE_CUSTOMISE
+ select DVB_CXD2820R if !DVB_FE_CUSTOMISE
select VIDEOBUF_DVB
---help---
This adds support for DVB cards based on the
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 69fcea82d01c..4e37375decf5 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -100,6 +100,13 @@ static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
{ -1, -1, -1, -1},
};
+/* Board Hauppauge WinTV HVR 900 (R2) digital */
+static struct em28xx_reg_seq hauppauge_wintv_hvr_900R2_digital[] = {
+ {EM28XX_R08_GPIO, 0x2e, ~EM_GPIO_4, 10},
+ {EM2880_R04_GPO, 0x0c, 0x0f, 10},
+ { -1, -1, -1, -1},
+};
+
/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */
static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = {
{EM28XX_R08_GPIO, 0x69, ~EM_GPIO_4, 10},
@@ -282,6 +289,16 @@ static struct em28xx_reg_seq leadership_reset[] = {
{ -1, -1, -1, -1},
};
+/* 2013:024f PCTV Systems nanoStick T2 290e
+ * GPIO_6 - demod reset
+ * GPIO_7 - LED
+ */
+static struct em28xx_reg_seq pctv_290e[] = {
+ {EM2874_R80_GPIO, 0x00, 0xff, 80},
+ {EM2874_R80_GPIO, 0x40, 0xff, 80}, /* GPIO_6 = 1 */
+ {EM2874_R80_GPIO, 0xc0, 0xff, 80}, /* GPIO_7 = 1 */
+ {-1, -1, -1, -1},
+};
/*
* Board definitions
@@ -859,6 +876,8 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_XC2028,
.tuner_gpio = default_tuner_gpio,
.mts_firmware = 1,
+ .has_dvb = 1,
+ .dvb_gpio = hauppauge_wintv_hvr_900R2_digital,
.ir_codes = RC_MAP_HAUPPAUGE,
.decoder = EM28XX_TVP5150,
.input = { {
@@ -1448,12 +1467,14 @@ struct em28xx_board em28xx_boards[] = {
.gpio = pinnacle_hybrid_pro_analog,
} },
},
- [EM2882_BOARD_PINNACLE_HYBRID_PRO] = {
- .name = "Pinnacle Hybrid Pro (2)",
- .valid = EM28XX_BOARD_NOT_VALIDATED,
+ [EM2882_BOARD_PINNACLE_HYBRID_PRO_330E] = {
+ .name = "Pinnacle Hybrid Pro (330e)",
.tuner_type = TUNER_XC2028,
.tuner_gpio = default_tuner_gpio,
.mts_firmware = 1,
+ .has_dvb = 1,
+ .dvb_gpio = hauppauge_wintv_hvr_900R2_digital,
+ .ir_codes = RC_MAP_PINNACLE_PCTV_HD,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
@@ -1749,6 +1770,17 @@ struct em28xx_board em28xx_boards[] = {
.dvb_gpio = kworld_a340_digital,
.tuner_gpio = default_tuner_gpio,
},
+ /* 2013:024f PCTV Systems nanoStick T2 290e.
+ * Empia EM28174, Sony CXD2820R and NXP TDA18271HD/C2 */
+ [EM28174_BOARD_PCTV_290E] = {
+ .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
+ EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_100_KHZ,
+ .xclk = EM28XX_XCLK_FREQUENCY_12MHZ,
+ .name = "PCTV Systems nanoStick T2 290e",
+ .tuner_type = TUNER_ABSENT,
+ .tuner_gpio = pctv_290e,
+ .has_dvb = 1,
+ },
};
const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
@@ -1863,7 +1895,7 @@ struct usb_device_id em28xx_id_table[] = {
{ USB_DEVICE(0x2304, 0x021a),
.driver_info = EM2820_BOARD_PINNACLE_DVC_90 },
{ USB_DEVICE(0x2304, 0x0226),
- .driver_info = EM2882_BOARD_PINNACLE_HYBRID_PRO },
+ .driver_info = EM2882_BOARD_PINNACLE_HYBRID_PRO_330E },
{ USB_DEVICE(0x2304, 0x0227),
.driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO },
{ USB_DEVICE(0x0413, 0x6023),
@@ -1876,6 +1908,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2860_BOARD_GADMEI_UTV330 },
{ USB_DEVICE(0x1b80, 0xa340),
.driver_info = EM2870_BOARD_KWORLD_A340 },
+ { USB_DEVICE(0x2013, 0x024f),
+ .driver_info = EM28174_BOARD_PCTV_290E },
{ },
};
MODULE_DEVICE_TABLE(usb, em28xx_id_table);
@@ -2229,7 +2263,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
ctl->demod = XC3028_FE_ZARLINK456;
break;
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
- /* djh - Not sure which demod we need here */
+ case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
ctl->demod = XC3028_FE_DEFAULT;
break;
case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
@@ -2799,6 +2833,11 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
dev->reg_gpio_num = EM2874_R80_GPIO;
dev->wait_after_write = 0;
break;
+ case CHIP_ID_EM28174:
+ em28xx_info("chip ID is em28174\n");
+ dev->reg_gpio_num = EM2874_R80_GPIO;
+ dev->wait_after_write = 0;
+ break;
case CHIP_ID_EM2883:
em28xx_info("chip ID is em2882/em2883\n");
dev->wait_after_write = 0;
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index 44c63cbd6dda..e33f145d867a 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -489,7 +489,8 @@ int em28xx_audio_setup(struct em28xx *dev)
int vid1, vid2, feat, cfg;
u32 vid;
- if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874) {
+ if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874
+ || dev->chip_id == CHIP_ID_EM28174) {
/* Digital only device - don't load any alsa module */
dev->audio_mode.has_audio = 0;
dev->has_audio_class = 0;
@@ -614,7 +615,7 @@ int em28xx_capture_start(struct em28xx *dev, int start)
{
int rc;
- if (dev->chip_id == CHIP_ID_EM2874) {
+ if (dev->chip_id == CHIP_ID_EM2874 || dev->chip_id == CHIP_ID_EM28174) {
/* The Transport Stream Enable Register moved in em2874 */
if (!start) {
rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
@@ -1111,6 +1112,10 @@ int em28xx_isoc_dvb_max_packetsize(struct em28xx *dev)
/* FIXME - for now assume 564 like it was before, but the
em2874 code should be added to return the proper value... */
packet_size = 564;
+ } else if (dev->chip_id == CHIP_ID_EM28174) {
+ /* FIXME same as em2874. 564 was enough for 22 Mbit DVB-T
+ but too much for 44 Mbit DVB-C. */
+ packet_size = 752;
} else {
/* TS max packet size stored in bits 1-0 of R01 */
chip_cfg2 = em28xx_read_reg(dev, EM28XX_R01_CHIPCFG2);
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
index c7c04bf712aa..7904ca4b6913 100644
--- a/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
@@ -38,6 +38,8 @@
#include "tda1002x.h"
#include "tda18271.h"
#include "s921.h"
+#include "drxd.h"
+#include "cxd2820r.h"
MODULE_DESCRIPTION("driver for em28xx based DVB cards");
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
@@ -58,7 +60,7 @@ if (debug >= level) \
#define EM28XX_DVB_MAX_PACKETS 64
struct em28xx_dvb {
- struct dvb_frontend *frontend;
+ struct dvb_frontend *fe[2];
/* feed count management */
struct mutex lock;
@@ -285,12 +287,13 @@ static struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = {
.if2 = 45600,
};
-#ifdef EM28XX_DRX397XD_SUPPORT
-/* [TODO] djh - not sure yet what the device config needs to contain */
-static struct drx397xD_config em28xx_drx397xD_with_xc3028 = {
- .demod_address = (0xe0 >> 1),
+static struct drxd_config em28xx_drxd = {
+ .index = 0, .demod_address = 0x70, .demod_revision = 0xa2,
+ .demoda_address = 0x00, .pll_address = 0x00,
+ .pll_type = DRXD_PLL_NONE, .clock = 12000, .insert_rs_byte = 1,
+ .pll_set = NULL, .osc_deviation = NULL, .IF = 42800000,
+ .disable_i2c_gate_ctrl = 1,
};
-#endif
static int mt352_terratec_xs_init(struct dvb_frontend *fe)
{
@@ -332,6 +335,26 @@ static struct tda10023_config em28xx_tda10023_config = {
.invert = 1,
};
+static struct cxd2820r_config em28xx_cxd2820r_config = {
+ .i2c_address = (0xd8 >> 1),
+ .ts_mode = CXD2820R_TS_SERIAL,
+ .if_dvbt_6 = 3300,
+ .if_dvbt_7 = 3500,
+ .if_dvbt_8 = 4000,
+ .if_dvbt2_6 = 3300,
+ .if_dvbt2_7 = 3500,
+ .if_dvbt2_8 = 4000,
+ .if_dvbc = 5000,
+
+ /* enable LNA for DVB-T2 and DVB-C */
+ .gpio_dvbt2[0] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | CXD2820R_GPIO_L,
+ .gpio_dvbc[0] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | CXD2820R_GPIO_L,
+};
+
+static struct tda18271_config em28xx_cxd2820r_tda18271_config = {
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
+};
+
/* ------------------------------------------------------------------ */
static int attach_xc3028(u8 addr, struct em28xx *dev)
@@ -343,17 +366,17 @@ static int attach_xc3028(u8 addr, struct em28xx *dev)
cfg.i2c_adap = &dev->i2c_adap;
cfg.i2c_addr = addr;
- if (!dev->dvb->frontend) {
+ if (!dev->dvb->fe[0]) {
em28xx_errdev("/2: dvb frontend not attached. "
"Can't attach xc3028\n");
return -EINVAL;
}
- fe = dvb_attach(xc2028_attach, dev->dvb->frontend, &cfg);
+ fe = dvb_attach(xc2028_attach, dev->dvb->fe[0], &cfg);
if (!fe) {
em28xx_errdev("/2: xc3028 attach failed\n");
- dvb_frontend_detach(dev->dvb->frontend);
- dev->dvb->frontend = NULL;
+ dvb_frontend_detach(dev->dvb->fe[0]);
+ dev->dvb->fe[0] = NULL;
return -EINVAL;
}
@@ -383,16 +406,28 @@ static int register_dvb(struct em28xx_dvb *dvb,
}
/* Ensure all frontends negotiate bus access */
- dvb->frontend->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
+ dvb->fe[0]->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
+ if (dvb->fe[1])
+ dvb->fe[1]->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
dvb->adapter.priv = dev;
/* register frontend */
- result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+ result = dvb_register_frontend(&dvb->adapter, dvb->fe[0]);
if (result < 0) {
printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n",
dev->name, result);
- goto fail_frontend;
+ goto fail_frontend0;
+ }
+
+ /* register 2nd frontend */
+ if (dvb->fe[1]) {
+ result = dvb_register_frontend(&dvb->adapter, dvb->fe[1]);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: 2nd dvb_register_frontend failed (errno = %d)\n",
+ dev->name, result);
+ goto fail_frontend1;
+ }
}
/* register demux stuff */
@@ -458,9 +493,14 @@ fail_fe_hw:
fail_dmxdev:
dvb_dmx_release(&dvb->demux);
fail_dmx:
- dvb_unregister_frontend(dvb->frontend);
-fail_frontend:
- dvb_frontend_detach(dvb->frontend);
+ if (dvb->fe[1])
+ dvb_unregister_frontend(dvb->fe[1]);
+ dvb_unregister_frontend(dvb->fe[0]);
+fail_frontend1:
+ if (dvb->fe[1])
+ dvb_frontend_detach(dvb->fe[1]);
+fail_frontend0:
+ dvb_frontend_detach(dvb->fe[0]);
dvb_unregister_adapter(&dvb->adapter);
fail_adapter:
return result;
@@ -473,12 +513,15 @@ static void unregister_dvb(struct em28xx_dvb *dvb)
dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
dvb_dmxdev_release(&dvb->dmxdev);
dvb_dmx_release(&dvb->demux);
- dvb_unregister_frontend(dvb->frontend);
- dvb_frontend_detach(dvb->frontend);
+ if (dvb->fe[1])
+ dvb_unregister_frontend(dvb->fe[1]);
+ dvb_unregister_frontend(dvb->fe[0]);
+ if (dvb->fe[1])
+ dvb_frontend_detach(dvb->fe[1]);
+ dvb_frontend_detach(dvb->fe[0]);
dvb_unregister_adapter(&dvb->adapter);
}
-
static int dvb_init(struct em28xx *dev)
{
int result = 0;
@@ -497,16 +540,17 @@ static int dvb_init(struct em28xx *dev)
return -ENOMEM;
}
dev->dvb = dvb;
+ dvb->fe[0] = dvb->fe[1] = NULL;
mutex_lock(&dev->lock);
em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
/* init frontend */
switch (dev->model) {
case EM2874_LEADERSHIP_ISDBT:
- dvb->frontend = dvb_attach(s921_attach,
+ dvb->fe[0] = dvb_attach(s921_attach,
&sharp_isdbt, &dev->i2c_adap);
- if (!dvb->frontend) {
+ if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free;
}
@@ -516,7 +560,7 @@ static int dvb_init(struct em28xx *dev)
case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
- dvb->frontend = dvb_attach(lgdt330x_attach,
+ dvb->fe[0] = dvb_attach(lgdt330x_attach,
&em2880_lgdt3303_dev,
&dev->i2c_adap);
if (attach_xc3028(0x61, dev) < 0) {
@@ -525,7 +569,7 @@ static int dvb_init(struct em28xx *dev)
}
break;
case EM2880_BOARD_KWORLD_DVB_310U:
- dvb->frontend = dvb_attach(zl10353_attach,
+ dvb->fe[0] = dvb_attach(zl10353_attach,
&em28xx_zl10353_with_xc3028,
&dev->i2c_adap);
if (attach_xc3028(0x61, dev) < 0) {
@@ -536,7 +580,7 @@ static int dvb_init(struct em28xx *dev)
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
case EM2882_BOARD_TERRATEC_HYBRID_XS:
case EM2880_BOARD_EMPIRE_DUAL_TV:
- dvb->frontend = dvb_attach(zl10353_attach,
+ dvb->fe[0] = dvb_attach(zl10353_attach,
&em28xx_zl10353_xc3028_no_i2c_gate,
&dev->i2c_adap);
if (attach_xc3028(0x61, dev) < 0) {
@@ -549,13 +593,13 @@ static int dvb_init(struct em28xx *dev)
case EM2881_BOARD_PINNACLE_HYBRID_PRO:
case EM2882_BOARD_DIKOM_DK300:
case EM2882_BOARD_KWORLD_VS_DVBT:
- dvb->frontend = dvb_attach(zl10353_attach,
+ dvb->fe[0] = dvb_attach(zl10353_attach,
&em28xx_zl10353_xc3028_no_i2c_gate,
&dev->i2c_adap);
- if (dvb->frontend == NULL) {
+ if (dvb->fe[0] == NULL) {
/* This board could have either a zl10353 or a mt352.
If the chip id isn't for zl10353, try mt352 */
- dvb->frontend = dvb_attach(mt352_attach,
+ dvb->fe[0] = dvb_attach(mt352_attach,
&terratec_xs_mt352_cfg,
&dev->i2c_adap);
}
@@ -567,7 +611,7 @@ static int dvb_init(struct em28xx *dev)
break;
case EM2883_BOARD_KWORLD_HYBRID_330U:
case EM2882_BOARD_EVGA_INDTUBE:
- dvb->frontend = dvb_attach(s5h1409_attach,
+ dvb->fe[0] = dvb_attach(s5h1409_attach,
&em28xx_s5h1409_with_xc3028,
&dev->i2c_adap);
if (attach_xc3028(0x61, dev) < 0) {
@@ -576,11 +620,11 @@ static int dvb_init(struct em28xx *dev)
}
break;
case EM2882_BOARD_KWORLD_ATSC_315U:
- dvb->frontend = dvb_attach(lgdt330x_attach,
+ dvb->fe[0] = dvb_attach(lgdt330x_attach,
&em2880_lgdt3303_dev,
&dev->i2c_adap);
- if (dvb->frontend != NULL) {
- if (!dvb_attach(simple_tuner_attach, dvb->frontend,
+ if (dvb->fe[0] != NULL) {
+ if (!dvb_attach(simple_tuner_attach, dvb->fe[0],
&dev->i2c_adap, 0x61, TUNER_THOMSON_DTT761X)) {
result = -EINVAL;
goto out_free;
@@ -588,25 +632,21 @@ static int dvb_init(struct em28xx *dev)
}
break;
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
-#ifdef EM28XX_DRX397XD_SUPPORT
- /* We don't have the config structure properly populated, so
- this is commented out for now */
- dvb->frontend = dvb_attach(drx397xD_attach,
- &em28xx_drx397xD_with_xc3028,
- &dev->i2c_adap);
+ case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
+ dvb->fe[0] = dvb_attach(drxd_attach, &em28xx_drxd, NULL,
+ &dev->i2c_adap, &dev->udev->dev);
if (attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free;
}
break;
-#endif
case EM2870_BOARD_REDDO_DVB_C_USB_BOX:
/* Philips CU1216L NIM (Philips TDA10023 + Infineon TUA6034) */
- dvb->frontend = dvb_attach(tda10023_attach,
+ dvb->fe[0] = dvb_attach(tda10023_attach,
&em28xx_tda10023_config,
&dev->i2c_adap, 0x48);
- if (dvb->frontend) {
- if (!dvb_attach(simple_tuner_attach, dvb->frontend,
+ if (dvb->fe[0]) {
+ if (!dvb_attach(simple_tuner_attach, dvb->fe[0],
&dev->i2c_adap, 0x60, TUNER_PHILIPS_CU1216L)) {
result = -EINVAL;
goto out_free;
@@ -614,25 +654,53 @@ static int dvb_init(struct em28xx *dev)
}
break;
case EM2870_BOARD_KWORLD_A340:
- dvb->frontend = dvb_attach(lgdt3305_attach,
+ dvb->fe[0] = dvb_attach(lgdt3305_attach,
&em2870_lgdt3304_dev,
&dev->i2c_adap);
- if (dvb->frontend != NULL)
- dvb_attach(tda18271_attach, dvb->frontend, 0x60,
+ if (dvb->fe[0] != NULL)
+ dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
&dev->i2c_adap, &kworld_a340_config);
break;
+ case EM28174_BOARD_PCTV_290E:
+ /* MFE
+ * FE 0 = DVB-T/T2 + FE 1 = DVB-C, both sharing same tuner. */
+ /* FE 0 */
+ dvb->fe[0] = dvb_attach(cxd2820r_attach,
+ &em28xx_cxd2820r_config, &dev->i2c_adap, NULL);
+ if (dvb->fe[0]) {
+ struct i2c_adapter *i2c_tuner;
+ i2c_tuner = cxd2820r_get_tuner_i2c_adapter(dvb->fe[0]);
+ /* FE 0 attach tuner */
+ if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
+ i2c_tuner, &em28xx_cxd2820r_tda18271_config)) {
+ dvb_frontend_detach(dvb->fe[0]);
+ result = -EINVAL;
+ goto out_free;
+ }
+ /* FE 1. This dvb_attach() cannot fail. */
+ dvb->fe[1] = dvb_attach(cxd2820r_attach, NULL, NULL,
+ dvb->fe[0]);
+ dvb->fe[1]->id = 1;
+ /* FE 1 attach tuner */
+ if (!dvb_attach(tda18271_attach, dvb->fe[1], 0x60,
+ i2c_tuner, &em28xx_cxd2820r_tda18271_config)) {
+ dvb_frontend_detach(dvb->fe[1]);
+ /* leave FE 0 still active */
+ }
+ }
+ break;
default:
em28xx_errdev("/2: The frontend of your DVB/ATSC card"
" isn't supported yet\n");
break;
}
- if (NULL == dvb->frontend) {
+ if (NULL == dvb->fe[0]) {
em28xx_errdev("/2: frontend initialization failed\n");
result = -EINVAL;
goto out_free;
}
/* define general-purpose callback pointer */
- dvb->frontend->callback = em28xx_tuner_callback;
+ dvb->fe[0]->callback = em28xx_tuner_callback;
/* register everything */
result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index 71474d31e155..4739fc7e6eb3 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -332,7 +332,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
struct em28xx_eeprom *em_eeprom = (void *)eedata;
int i, err, size = len, block;
- if (dev->chip_id == CHIP_ID_EM2874) {
+ if (dev->chip_id == CHIP_ID_EM2874 || dev->chip_id == CHIP_ID_EM28174) {
/* Empia switched to a 16-bit addressable eeprom in newer
devices. While we could certainly write a routine to read
the eeprom, there is nothing of use in there that cannot be
diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/video/em28xx/em28xx-reg.h
index 91e90559642b..e92a28ede434 100644
--- a/drivers/media/video/em28xx/em28xx-reg.h
+++ b/drivers/media/video/em28xx/em28xx-reg.h
@@ -201,6 +201,7 @@ enum em28xx_chip_id {
CHIP_ID_EM2870 = 35,
CHIP_ID_EM2883 = 36,
CHIP_ID_EM2874 = 65,
+ CHIP_ID_EM28174 = 113,
};
/*
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index 6f2795a3d4b7..3cca33122450 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -97,7 +97,7 @@
#define EM2881_BOARD_PINNACLE_HYBRID_PRO 53
#define EM2882_BOARD_KWORLD_VS_DVBT 54
#define EM2882_BOARD_TERRATEC_HYBRID_XS 55
-#define EM2882_BOARD_PINNACLE_HYBRID_PRO 56
+#define EM2882_BOARD_PINNACLE_HYBRID_PRO_330E 56
#define EM2883_BOARD_KWORLD_HYBRID_330U 57
#define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58
#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 60
@@ -118,6 +118,7 @@
#define EM2882_BOARD_DIKOM_DK300 75
#define EM2870_BOARD_KWORLD_A340 76
#define EM2874_LEADERSHIP_ISDBT 77
+#define EM28174_BOARD_PCTV_290E 78
/* Limits minimum and default number of buffers */
diff --git a/drivers/media/video/fsl-viu.c b/drivers/media/video/fsl-viu.c
index 031af1610154..908d7012c3f2 100644
--- a/drivers/media/video/fsl-viu.c
+++ b/drivers/media/video/fsl-viu.c
@@ -766,7 +766,7 @@ inline void viu_activate_overlay(struct viu_reg *viu_reg)
out_be32(&vr->picture_count, reg_val.picture_count);
}
-static int viu_start_preview(struct viu_dev *dev, struct viu_fh *fh)
+static int viu_setup_preview(struct viu_dev *dev, struct viu_fh *fh)
{
int bpp;
@@ -805,11 +805,6 @@ static int viu_start_preview(struct viu_dev *dev, struct viu_fh *fh)
/* 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;
}
@@ -825,13 +820,11 @@ static int vidioc_s_fmt_overlay(struct file *file, void *priv,
if (err)
return err;
- mutex_lock(&dev->lock);
fh->win = f->fmt.win;
spin_lock_irqsave(&dev->slock, flags);
- viu_start_preview(dev, fh);
+ viu_setup_preview(dev, fh);
spin_unlock_irqrestore(&dev->slock, flags);
- mutex_unlock(&dev->lock);
return 0;
}
@@ -841,6 +834,28 @@ static int vidioc_try_fmt_overlay(struct file *file, void *priv,
return 0;
}
+static int vidioc_overlay(struct file *file, void *priv, unsigned int on)
+{
+ struct viu_fh *fh = priv;
+ struct viu_dev *dev = (struct viu_dev *)fh->dev;
+ unsigned long flags;
+
+ if (on) {
+ spin_lock_irqsave(&dev->slock, flags);
+ viu_activate_overlay(dev->vr);
+ dev->ovenable = 1;
+
+ /* start dma */
+ viu_start_dma(dev);
+ spin_unlock_irqrestore(&dev->slock, flags);
+ } else {
+ viu_stop_dma(dev);
+ dev->ovenable = 0;
+ }
+
+ return 0;
+}
+
int vidioc_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg)
{
struct viu_fh *fh = priv;
@@ -911,12 +926,16 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct viu_fh *fh = priv;
+ struct viu_dev *dev = fh->dev;
if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (fh->type != i)
return -EINVAL;
+ if (dev->ovenable)
+ dev->ovenable = 0;
+
viu_start_dma(fh->dev);
return videobuf_streamon(&fh->vb_vidq);
@@ -1311,7 +1330,8 @@ static int viu_open(struct file *file)
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, NULL);
+ sizeof(struct viu_buf), fh,
+ &fh->dev->lock);
return 0;
}
@@ -1401,7 +1421,7 @@ static struct v4l2_file_operations viu_fops = {
.release = viu_release,
.read = viu_read,
.poll = viu_poll,
- .ioctl = video_ioctl2, /* V4L2 ioctl handler */
+ .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
.mmap = viu_mmap,
};
@@ -1415,6 +1435,7 @@ static const struct v4l2_ioctl_ops viu_ioctl_ops = {
.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_overlay = vidioc_overlay,
.vidioc_g_fbuf = vidioc_g_fbuf,
.vidioc_s_fbuf = vidioc_s_fbuf,
.vidioc_reqbufs = vidioc_reqbufs,
@@ -1498,9 +1519,6 @@ static int __devinit viu_of_probe(struct platform_device *op)
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);
@@ -1531,8 +1549,15 @@ static int __devinit viu_of_probe(struct platform_device *op)
viu_dev->vdev = vdev;
+ /* initialize locks */
+ mutex_init(&viu_dev->lock);
+ viu_dev->vdev->lock = &viu_dev->lock;
+ spin_lock_init(&viu_dev->slock);
+
video_set_drvdata(viu_dev->vdev, viu_dev);
+ mutex_lock(&viu_dev->lock);
+
ret = video_register_device(viu_dev->vdev, VFL_TYPE_GRABBER, -1);
if (ret < 0) {
video_device_release(viu_dev->vdev);
@@ -1559,6 +1584,8 @@ static int __devinit viu_of_probe(struct platform_device *op)
goto err_irq;
}
+ mutex_unlock(&viu_dev->lock);
+
dev_info(&op->dev, "Freescale VIU Video Capture Board\n");
return ret;
@@ -1568,6 +1595,7 @@ err_irq:
err_clk:
video_unregister_device(viu_dev->vdev);
err_vdev:
+ mutex_unlock(&viu_dev->lock);
i2c_put_adapter(ad);
v4l2_device_unregister(&viu_dev->v4l2_dev);
err:
diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig
index eb04e8b59989..34ae2c299799 100644
--- a/drivers/media/video/gspca/Kconfig
+++ b/drivers/media/video/gspca/Kconfig
@@ -77,6 +77,15 @@ config USB_GSPCA_JEILINJ
To compile this driver as a module, choose M here: the
module will be called gspca_jeilinj.
+config USB_GSPCA_KINECT
+ tristate "Kinect sensor device USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for the Microsoft Kinect sensor device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_kinect.
+
config USB_GSPCA_KONICA
tristate "Konica USB Camera V4L2 driver"
depends on VIDEO_V4L2 && USB_GSPCA
diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile
index 855fbc8c9c47..802fbe1bff4a 100644
--- a/drivers/media/video/gspca/Makefile
+++ b/drivers/media/video/gspca/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_USB_GSPCA_CPIA1) += gspca_cpia1.o
obj-$(CONFIG_USB_GSPCA_ETOMS) += gspca_etoms.o
obj-$(CONFIG_USB_GSPCA_FINEPIX) += gspca_finepix.o
obj-$(CONFIG_USB_GSPCA_JEILINJ) += gspca_jeilinj.o
+obj-$(CONFIG_USB_GSPCA_KINECT) += gspca_kinect.o
obj-$(CONFIG_USB_GSPCA_KONICA) += gspca_konica.o
obj-$(CONFIG_USB_GSPCA_MARS) += gspca_mars.o
obj-$(CONFIG_USB_GSPCA_MR97310A) += gspca_mr97310a.o
@@ -46,6 +47,7 @@ gspca_cpia1-objs := cpia1.o
gspca_etoms-objs := etoms.o
gspca_finepix-objs := finepix.o
gspca_jeilinj-objs := jeilinj.o
+gspca_kinect-objs := kinect.o
gspca_konica-objs := konica.o
gspca_mars-objs := mars.o
gspca_mr97310a-objs := mr97310a.o
diff --git a/drivers/media/video/gspca/cpia1.c b/drivers/media/video/gspca/cpia1.c
index 9ddbac680663..f2a9451eea19 100644
--- a/drivers/media/video/gspca/cpia1.c
+++ b/drivers/media/video/gspca/cpia1.c
@@ -1262,7 +1262,7 @@ static int set_flicker(struct gspca_dev *gspca_dev, int on, int apply)
static void monitor_exposure(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- u8 exp_acc, bcomp, gain, coarseL, cmd[8];
+ u8 exp_acc, bcomp, cmd[8];
int ret, light_exp, dark_exp, very_dark_exp;
int old_exposure, new_exposure, framerate;
int setfps = 0, setexp = 0, setflicker = 0;
@@ -1284,8 +1284,6 @@ static void monitor_exposure(struct gspca_dev *gspca_dev)
}
exp_acc = gspca_dev->usb_buf[0];
bcomp = gspca_dev->usb_buf[1];
- gain = gspca_dev->usb_buf[2];
- coarseL = gspca_dev->usb_buf[3];
light_exp = sd->params.colourParams.brightness +
TC - 50 + EXP_ACC_LIGHT;
@@ -1772,9 +1770,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
-#ifdef GSPCA_DEBUG
struct sd *sd = (struct sd *) gspca_dev;
-#endif
int ret;
/* Start / Stop the camera to make sure we are talking to
diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/video/gspca/gl860/gl860.c
index 99083038cec3..e8e071aa212f 100644
--- a/drivers/media/video/gspca/gl860/gl860.c
+++ b/drivers/media/video/gspca/gl860/gl860.c
@@ -499,21 +499,8 @@ MODULE_DEVICE_TABLE(usb, device_table);
static int sd_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- struct gspca_dev *gspca_dev;
- s32 ret;
-
- ret = gspca_dev_probe(intf, id,
+ return gspca_dev_probe(intf, id,
&sd_desc_mi1320, sizeof(struct sd), THIS_MODULE);
-
- if (ret >= 0) {
- gspca_dev = usb_get_intfdata(intf);
-
- PDEBUG(D_PROBE,
- "Camera is now controlling video device %s",
- video_device_node_name(&gspca_dev->vdev));
- }
-
- return ret;
}
static void sd_disconnect(struct usb_interface *intf)
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index e526aa3dedaf..08ce9948d99b 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -55,7 +55,7 @@ MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>");
MODULE_DESCRIPTION("GSPCA USB Camera Driver");
MODULE_LICENSE("GPL");
-#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 12, 0)
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 13, 0)
#ifdef GSPCA_DEBUG
int gspca_debug = D_ERR | D_PROBE;
@@ -2495,6 +2495,6 @@ module_exit(gspca_exit);
module_param_named(debug, gspca_debug, int, 0644);
MODULE_PARM_DESC(debug,
"Debug (bit) 0x01:error 0x02:probe 0x04:config"
- " 0x08:stream 0x10:frame 0x20:packet 0x40:USBin 0x80:USBout"
+ " 0x08:stream 0x10:frame 0x20:packet"
" 0x0100: v4l2");
#endif
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
index 41755226d389..49e2fcbe81fb 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/video/gspca/gspca.h
@@ -9,7 +9,7 @@
#include <linux/mutex.h>
/* compilation option */
-#define GSPCA_DEBUG 1
+/*#define GSPCA_DEBUG 1*/
#ifdef GSPCA_DEBUG
/* GSPCA our debug messages */
@@ -25,8 +25,8 @@ extern int gspca_debug;
#define D_STREAM 0x08
#define D_FRAM 0x10
#define D_PACK 0x20
-#define D_USBI 0x40
-#define D_USBO 0x80
+#define D_USBI 0x00
+#define D_USBO 0x00
#define D_V4L2 0x0100
#else
#define PDEBUG(level, fmt, args...)
diff --git a/drivers/media/video/gspca/jeilinj.c b/drivers/media/video/gspca/jeilinj.c
index 36dae38b1e38..1bd9c4b542dd 100644
--- a/drivers/media/video/gspca/jeilinj.c
+++ b/drivers/media/video/gspca/jeilinj.c
@@ -6,6 +6,9 @@
*
* Copyright (C) 2009 Theodore Kilgore
*
+ * Sportscam DV15 support and control settings are
+ * Copyright (C) 2011 Patrice Chotard
+ *
* This program is free software; you can redistribute it and/or modify
* 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,7 +26,6 @@
#define MODULE_NAME "jeilinj"
-#include <linux/workqueue.h>
#include <linux/slab.h>
#include "gspca.h"
#include "jpeg.h"
@@ -34,29 +36,51 @@ MODULE_LICENSE("GPL");
/* Default timeouts, in ms */
#define JEILINJ_CMD_TIMEOUT 500
+#define JEILINJ_CMD_DELAY 160
#define JEILINJ_DATA_TIMEOUT 1000
/* Maximum transfer size to use. */
#define JEILINJ_MAX_TRANSFER 0x200
-
#define FRAME_HEADER_LEN 0x10
+#define FRAME_START 0xFFFFFFFF
+
+enum {
+ SAKAR_57379,
+ SPORTSCAM_DV15,
+};
+
+#define CAMQUALITY_MIN 0 /* highest cam quality */
+#define CAMQUALITY_MAX 97 /* lowest cam quality */
+
+enum e_ctrl {
+ LIGHTFREQ,
+ AUTOGAIN,
+ RED,
+ GREEN,
+ BLUE,
+ NCTRLS /* number of controls */
+};
/* Structure to hold all of our device specific stuff */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
+ struct gspca_ctrl ctrls[NCTRLS];
+ int blocks_left;
const struct v4l2_pix_format *cap_mode;
/* Driver stuff */
- struct work_struct work_struct;
- struct workqueue_struct *work_thread;
+ u8 type;
u8 quality; /* image quality */
- u8 jpegqual; /* webcam quality */
+#define QUALITY_MIN 35
+#define QUALITY_MAX 85
+#define QUALITY_DEF 85
u8 jpeg_hdr[JPEG_HDR_SZ];
};
- struct jlj_command {
- unsigned char instruction[2];
- unsigned char ack_wanted;
- };
+struct jlj_command {
+ unsigned char instruction[2];
+ unsigned char ack_wanted;
+ unsigned char delay;
+};
/* AFAICT these cameras will only do 320x240. */
static struct v4l2_pix_format jlj_mode[] = {
@@ -64,6 +88,11 @@ static struct v4l2_pix_format jlj_mode[] = {
.bytesperline = 320,
.sizeimage = 320 * 240,
.colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+ { 640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480,
+ .colorspace = V4L2_COLORSPACE_JPEG,
.priv = 0}
};
@@ -73,178 +102,295 @@ static struct v4l2_pix_format jlj_mode[] = {
*/
/* All commands are two bytes only */
-static int jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command)
+static void jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command)
{
int retval;
+ if (gspca_dev->usb_err < 0)
+ return;
memcpy(gspca_dev->usb_buf, command, 2);
retval = usb_bulk_msg(gspca_dev->dev,
usb_sndbulkpipe(gspca_dev->dev, 3),
gspca_dev->usb_buf, 2, NULL, 500);
- if (retval < 0)
+ if (retval < 0) {
err("command write [%02x] error %d",
gspca_dev->usb_buf[0], retval);
- return retval;
+ gspca_dev->usb_err = retval;
+ }
}
/* Responses are one byte only */
-static int jlj_read1(struct gspca_dev *gspca_dev, unsigned char response)
+static void jlj_read1(struct gspca_dev *gspca_dev, unsigned char response)
{
int retval;
+ if (gspca_dev->usb_err < 0)
+ return;
retval = usb_bulk_msg(gspca_dev->dev,
usb_rcvbulkpipe(gspca_dev->dev, 0x84),
gspca_dev->usb_buf, 1, NULL, 500);
response = gspca_dev->usb_buf[0];
- if (retval < 0)
+ if (retval < 0) {
err("read command [%02x] error %d",
gspca_dev->usb_buf[0], retval);
- return retval;
+ gspca_dev->usb_err = retval;
+ }
}
-static int jlj_start(struct gspca_dev *gspca_dev)
+static void setfreq(struct gspca_dev *gspca_dev)
{
- int i;
- int retval = -1;
- u8 response = 0xff;
- struct jlj_command start_commands[] = {
- {{0x71, 0x81}, 0},
- {{0x70, 0x05}, 0},
- {{0x95, 0x70}, 1},
- {{0x71, 0x81}, 0},
- {{0x70, 0x04}, 0},
- {{0x95, 0x70}, 1},
- {{0x71, 0x00}, 0},
- {{0x70, 0x08}, 0},
- {{0x95, 0x70}, 1},
- {{0x94, 0x02}, 0},
- {{0xde, 0x24}, 0},
- {{0x94, 0x02}, 0},
- {{0xdd, 0xf0}, 0},
- {{0x94, 0x02}, 0},
- {{0xe3, 0x2c}, 0},
- {{0x94, 0x02}, 0},
- {{0xe4, 0x00}, 0},
- {{0x94, 0x02}, 0},
- {{0xe5, 0x00}, 0},
- {{0x94, 0x02}, 0},
- {{0xe6, 0x2c}, 0},
- {{0x94, 0x03}, 0},
- {{0xaa, 0x00}, 0},
- {{0x71, 0x1e}, 0},
- {{0x70, 0x06}, 0},
- {{0x71, 0x80}, 0},
- {{0x70, 0x07}, 0}
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 freq_commands[][2] = {
+ {0x71, 0x80},
+ {0x70, 0x07}
};
- for (i = 0; i < ARRAY_SIZE(start_commands); i++) {
- retval = jlj_write2(gspca_dev, start_commands[i].instruction);
- if (retval < 0)
- return retval;
- if (start_commands[i].ack_wanted)
- retval = jlj_read1(gspca_dev, response);
- if (retval < 0)
- return retval;
- }
- PDEBUG(D_ERR, "jlj_start retval is %d", retval);
- return retval;
+
+ freq_commands[0][1] |= (sd->ctrls[LIGHTFREQ].val >> 1);
+
+ jlj_write2(gspca_dev, freq_commands[0]);
+ jlj_write2(gspca_dev, freq_commands[1]);
}
-static int jlj_stop(struct gspca_dev *gspca_dev)
+static void setcamquality(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 quality_commands[][2] = {
+ {0x71, 0x1E},
+ {0x70, 0x06}
+ };
+ u8 camquality;
+
+ /* adapt camera quality from jpeg quality */
+ camquality = ((QUALITY_MAX - sd->quality) * CAMQUALITY_MAX)
+ / (QUALITY_MAX - QUALITY_MIN);
+ quality_commands[0][1] += camquality;
+
+ jlj_write2(gspca_dev, quality_commands[0]);
+ jlj_write2(gspca_dev, quality_commands[1]);
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 autogain_commands[][2] = {
+ {0x94, 0x02},
+ {0xcf, 0x00}
+ };
+
+ autogain_commands[1][1] = (sd->ctrls[AUTOGAIN].val << 4);
+
+ jlj_write2(gspca_dev, autogain_commands[0]);
+ jlj_write2(gspca_dev, autogain_commands[1]);
+}
+
+static void setred(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 setred_commands[][2] = {
+ {0x94, 0x02},
+ {0xe6, 0x00}
+ };
+
+ setred_commands[1][1] = sd->ctrls[RED].val;
+
+ jlj_write2(gspca_dev, setred_commands[0]);
+ jlj_write2(gspca_dev, setred_commands[1]);
+}
+
+static void setgreen(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 setgreen_commands[][2] = {
+ {0x94, 0x02},
+ {0xe7, 0x00}
+ };
+
+ setgreen_commands[1][1] = sd->ctrls[GREEN].val;
+
+ jlj_write2(gspca_dev, setgreen_commands[0]);
+ jlj_write2(gspca_dev, setgreen_commands[1]);
+}
+
+static void setblue(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 setblue_commands[][2] = {
+ {0x94, 0x02},
+ {0xe9, 0x00}
+ };
+
+ setblue_commands[1][1] = sd->ctrls[BLUE].val;
+
+ jlj_write2(gspca_dev, setblue_commands[0]);
+ jlj_write2(gspca_dev, setblue_commands[1]);
+}
+
+static const struct ctrl sd_ctrls[NCTRLS] = {
+[LIGHTFREQ] = {
+ {
+ .id = V4L2_CID_POWER_LINE_FREQUENCY,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .name = "Light frequency filter",
+ .minimum = V4L2_CID_POWER_LINE_FREQUENCY_DISABLED, /* 1 */
+ .maximum = V4L2_CID_POWER_LINE_FREQUENCY_60HZ, /* 2 */
+ .step = 1,
+ .default_value = V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
+ },
+ .set_control = setfreq
+ },
+[AUTOGAIN] = {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Automatic Gain (and Exposure)",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+#define AUTOGAIN_DEF 0
+ .default_value = AUTOGAIN_DEF,
+ },
+ .set_control = setautogain
+ },
+[RED] = {
+ {
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "red balance",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+#define RED_BALANCE_DEF 2
+ .default_value = RED_BALANCE_DEF,
+ },
+ .set_control = setred
+ },
+
+[GREEN] = {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "green balance",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+#define GREEN_BALANCE_DEF 2
+ .default_value = GREEN_BALANCE_DEF,
+ },
+ .set_control = setgreen
+ },
+[BLUE] = {
+ {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "blue balance",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+#define BLUE_BALANCE_DEF 2
+ .default_value = BLUE_BALANCE_DEF,
+ },
+ .set_control = setblue
+ },
+};
+
+static int jlj_start(struct gspca_dev *gspca_dev)
{
int i;
- int retval;
- struct jlj_command stop_commands[] = {
- {{0x71, 0x00}, 0},
- {{0x70, 0x09}, 0},
- {{0x71, 0x80}, 0},
- {{0x70, 0x05}, 0}
+ int start_commands_size;
+ u8 response = 0xff;
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct jlj_command start_commands[] = {
+ {{0x71, 0x81}, 0, 0},
+ {{0x70, 0x05}, 0, JEILINJ_CMD_DELAY},
+ {{0x95, 0x70}, 1, 0},
+ {{0x71, 0x81 - gspca_dev->curr_mode}, 0, 0},
+ {{0x70, 0x04}, 0, JEILINJ_CMD_DELAY},
+ {{0x95, 0x70}, 1, 0},
+ {{0x71, 0x00}, 0, 0}, /* start streaming ??*/
+ {{0x70, 0x08}, 0, JEILINJ_CMD_DELAY},
+ {{0x95, 0x70}, 1, 0},
+#define SPORTSCAM_DV15_CMD_SIZE 9
+ {{0x94, 0x02}, 0, 0},
+ {{0xde, 0x24}, 0, 0},
+ {{0x94, 0x02}, 0, 0},
+ {{0xdd, 0xf0}, 0, 0},
+ {{0x94, 0x02}, 0, 0},
+ {{0xe3, 0x2c}, 0, 0},
+ {{0x94, 0x02}, 0, 0},
+ {{0xe4, 0x00}, 0, 0},
+ {{0x94, 0x02}, 0, 0},
+ {{0xe5, 0x00}, 0, 0},
+ {{0x94, 0x02}, 0, 0},
+ {{0xe6, 0x2c}, 0, 0},
+ {{0x94, 0x03}, 0, 0},
+ {{0xaa, 0x00}, 0, 0}
};
- for (i = 0; i < ARRAY_SIZE(stop_commands); i++) {
- retval = jlj_write2(gspca_dev, stop_commands[i].instruction);
- if (retval < 0)
- return retval;
+
+ sd->blocks_left = 0;
+ /* Under Windows, USB spy shows that only the 9 first start
+ * commands are used for SPORTSCAM_DV15 webcam
+ */
+ if (sd->type == SPORTSCAM_DV15)
+ start_commands_size = SPORTSCAM_DV15_CMD_SIZE;
+ else
+ start_commands_size = ARRAY_SIZE(start_commands);
+
+ for (i = 0; i < start_commands_size; i++) {
+ jlj_write2(gspca_dev, start_commands[i].instruction);
+ if (start_commands[i].delay)
+ msleep(start_commands[i].delay);
+ if (start_commands[i].ack_wanted)
+ jlj_read1(gspca_dev, response);
}
- return retval;
+ setcamquality(gspca_dev);
+ msleep(2);
+ setfreq(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ PDEBUG(D_ERR, "Start streaming command failed");
+ return gspca_dev->usb_err;
}
-/* This function is called as a workqueue function and runs whenever the camera
- * is streaming data. Because it is a workqueue function it is allowed to sleep
- * so we can use synchronous USB calls. To avoid possible collisions with other
- * threads attempting to use the camera's USB interface the gspca usb_lock is
- * used when performing the one USB control operation inside the workqueue,
- * which tells the camera to close the stream. In practice the only thing
- * which needs to be protected against is the usb_set_interface call that
- * gspca makes during stream_off. Otherwise the camera doesn't provide any
- * controls that the user could try to change.
- */
-
-static void jlj_dostream(struct work_struct *work)
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ u8 *data, int len)
{
- struct sd *dev = container_of(work, struct sd, work_struct);
- struct gspca_dev *gspca_dev = &dev->gspca_dev;
- int blocks_left; /* 0x200-sized blocks remaining in current frame. */
- int act_len;
+ struct sd *sd = (struct sd *) gspca_dev;
int packet_type;
- int ret;
- u8 *buffer;
+ u32 header_marker;
- buffer = kmalloc(JEILINJ_MAX_TRANSFER, GFP_KERNEL | GFP_DMA);
- if (!buffer) {
- err("Couldn't allocate USB buffer");
- goto quit_stream;
+ PDEBUG(D_STREAM, "Got %d bytes out of %d for Block 0",
+ len, JEILINJ_MAX_TRANSFER);
+ if (len != JEILINJ_MAX_TRANSFER) {
+ PDEBUG(D_PACK, "bad length");
+ goto discard;
}
- while (gspca_dev->present && gspca_dev->streaming) {
- /*
- * Now request data block 0. Line 0 reports the size
- * to download, in blocks of size 0x200, and also tells the
- * "actual" data size, in bytes, which seems best to ignore.
- */
- ret = usb_bulk_msg(gspca_dev->dev,
- usb_rcvbulkpipe(gspca_dev->dev, 0x82),
- buffer, JEILINJ_MAX_TRANSFER, &act_len,
- JEILINJ_DATA_TIMEOUT);
- PDEBUG(D_STREAM,
- "Got %d bytes out of %d for Block 0",
- act_len, JEILINJ_MAX_TRANSFER);
- if (ret < 0 || act_len < FRAME_HEADER_LEN)
- goto quit_stream;
- blocks_left = buffer[0x0a] - 1;
- PDEBUG(D_STREAM, "blocks_left = 0x%x", blocks_left);
-
+ /* check if it's start of frame */
+ header_marker = ((u32 *)data)[0];
+ if (header_marker == FRAME_START) {
+ sd->blocks_left = data[0x0a] - 1;
+ PDEBUG(D_STREAM, "blocks_left = 0x%x", sd->blocks_left);
/* Start a new frame, and add the JPEG header, first thing */
gspca_frame_add(gspca_dev, FIRST_PACKET,
- dev->jpeg_hdr, JPEG_HDR_SZ);
+ sd->jpeg_hdr, JPEG_HDR_SZ);
/* Toss line 0 of data block 0, keep the rest. */
gspca_frame_add(gspca_dev, INTER_PACKET,
- buffer + FRAME_HEADER_LEN,
+ data + FRAME_HEADER_LEN,
JEILINJ_MAX_TRANSFER - FRAME_HEADER_LEN);
-
- while (blocks_left > 0) {
- if (!gspca_dev->present)
- goto quit_stream;
- ret = usb_bulk_msg(gspca_dev->dev,
- usb_rcvbulkpipe(gspca_dev->dev, 0x82),
- buffer, JEILINJ_MAX_TRANSFER, &act_len,
- JEILINJ_DATA_TIMEOUT);
- if (ret < 0 || act_len < JEILINJ_MAX_TRANSFER)
- goto quit_stream;
- PDEBUG(D_STREAM,
- "%d blocks remaining for frame", blocks_left);
- blocks_left -= 1;
- if (blocks_left == 0)
- packet_type = LAST_PACKET;
- else
- packet_type = INTER_PACKET;
- gspca_frame_add(gspca_dev, packet_type,
- buffer, JEILINJ_MAX_TRANSFER);
- }
- }
-quit_stream:
- mutex_lock(&gspca_dev->usb_lock);
- if (gspca_dev->present)
- jlj_stop(gspca_dev);
- mutex_unlock(&gspca_dev->usb_lock);
- kfree(buffer);
+ } else if (sd->blocks_left > 0) {
+ PDEBUG(D_STREAM, "%d blocks remaining for frame",
+ sd->blocks_left);
+ sd->blocks_left -= 1;
+ if (sd->blocks_left == 0)
+ packet_type = LAST_PACKET;
+ else
+ packet_type = INTER_PACKET;
+ gspca_frame_add(gspca_dev, packet_type,
+ data, JEILINJ_MAX_TRANSFER);
+ } else
+ goto discard;
+ return;
+discard:
+ /* Discard data until a new frame starts. */
+ gspca_dev->last_packet_type = DISCARD_PACKET;
}
/* This function is called at probe time just before sd_init */
@@ -254,78 +400,169 @@ static int sd_config(struct gspca_dev *gspca_dev,
struct cam *cam = &gspca_dev->cam;
struct sd *dev = (struct sd *) gspca_dev;
- dev->quality = 85;
- dev->jpegqual = 85;
+ dev->type = id->driver_info;
+ gspca_dev->cam.ctrls = dev->ctrls;
+ dev->quality = QUALITY_DEF;
+ dev->ctrls[LIGHTFREQ].def = V4L2_CID_POWER_LINE_FREQUENCY_60HZ;
+ dev->ctrls[RED].def = RED_BALANCE_DEF;
+ dev->ctrls[GREEN].def = GREEN_BALANCE_DEF;
+ dev->ctrls[BLUE].def = BLUE_BALANCE_DEF;
PDEBUG(D_PROBE,
"JEILINJ camera detected"
" (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
cam->cam_mode = jlj_mode;
- cam->nmodes = 1;
+ cam->nmodes = ARRAY_SIZE(jlj_mode);
cam->bulk = 1;
- /* We don't use the buffer gspca allocates so make it small. */
- cam->bulk_size = 32;
- INIT_WORK(&dev->work_struct, jlj_dostream);
+ cam->bulk_nurbs = 1;
+ cam->bulk_size = JEILINJ_MAX_TRANSFER;
return 0;
}
-/* called on streamoff with alt==0 and on disconnect */
-/* the usb_lock is held at entry - restore on exit */
-static void sd_stop0(struct gspca_dev *gspca_dev)
+static void sd_stopN(struct gspca_dev *gspca_dev)
{
- struct sd *dev = (struct sd *) gspca_dev;
+ int i;
+ u8 *buf;
+ u8 stop_commands[][2] = {
+ {0x71, 0x00},
+ {0x70, 0x09},
+ {0x71, 0x80},
+ {0x70, 0x05}
+ };
+
+ for (;;) {
+ /* get the image remaining blocks */
+ usb_bulk_msg(gspca_dev->dev,
+ gspca_dev->urb[0]->pipe,
+ gspca_dev->urb[0]->transfer_buffer,
+ JEILINJ_MAX_TRANSFER, NULL,
+ JEILINJ_DATA_TIMEOUT);
+
+ /* search for 0xff 0xd9 (EOF for JPEG) */
+ i = 0;
+ buf = gspca_dev->urb[0]->transfer_buffer;
+ while ((i < (JEILINJ_MAX_TRANSFER - 1)) &&
+ ((buf[i] != 0xff) || (buf[i+1] != 0xd9)))
+ i++;
- /* wait for the work queue to terminate */
- mutex_unlock(&gspca_dev->usb_lock);
- /* This waits for jlj_dostream to finish */
- destroy_workqueue(dev->work_thread);
- dev->work_thread = NULL;
- mutex_lock(&gspca_dev->usb_lock);
+ if (i != (JEILINJ_MAX_TRANSFER - 1))
+ /* last remaining block found */
+ break;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(stop_commands); i++)
+ jlj_write2(gspca_dev, stop_commands[i]);
}
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
- return 0;
+ return gspca_dev->usb_err;
}
/* Set up for getting frames. */
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *dev = (struct sd *) gspca_dev;
- int ret;
/* create the JPEG header */
jpeg_define(dev->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x21); /* JPEG 422 */
jpeg_set_qual(dev->jpeg_hdr, dev->quality);
- PDEBUG(D_STREAM, "Start streaming at 320x240");
- ret = jlj_start(gspca_dev);
- if (ret < 0) {
- PDEBUG(D_ERR, "Start streaming command failed");
- return ret;
- }
- /* Start the workqueue function to do the streaming */
- dev->work_thread = create_singlethread_workqueue(MODULE_NAME);
- queue_work(dev->work_thread, &dev->work_struct);
-
- return 0;
+ PDEBUG(D_STREAM, "Start streaming at %dx%d",
+ gspca_dev->height, gspca_dev->width);
+ jlj_start(gspca_dev);
+ return gspca_dev->usb_err;
}
/* Table of supported USB devices */
static const struct usb_device_id device_table[] = {
- {USB_DEVICE(0x0979, 0x0280)},
+ {USB_DEVICE(0x0979, 0x0280), .driver_info = SAKAR_57379},
+ {USB_DEVICE(0x0979, 0x0270), .driver_info = SPORTSCAM_DV15},
{}
};
MODULE_DEVICE_TABLE(usb, device_table);
+static int sd_querymenu(struct gspca_dev *gspca_dev,
+ struct v4l2_querymenu *menu)
+{
+ switch (menu->id) {
+ case V4L2_CID_POWER_LINE_FREQUENCY:
+ switch (menu->index) {
+ case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */
+ strcpy((char *) menu->name, "disable");
+ return 0;
+ case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
+ strcpy((char *) menu->name, "50 Hz");
+ return 0;
+ case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
+ strcpy((char *) menu->name, "60 Hz");
+ return 0;
+ }
+ break;
+ }
+ return -EINVAL;
+}
+
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (jcomp->quality < QUALITY_MIN)
+ sd->quality = QUALITY_MIN;
+ else if (jcomp->quality > QUALITY_MAX)
+ sd->quality = QUALITY_MAX;
+ else
+ sd->quality = jcomp->quality;
+ if (gspca_dev->streaming) {
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+ setcamquality(gspca_dev);
+ }
+ return 0;
+}
+
+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 = 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 = {
+static const struct sd_desc sd_desc_sakar_57379 = {
.name = MODULE_NAME,
.config = sd_config,
.init = sd_init,
.start = sd_start,
- .stop0 = sd_stop0,
+ .stopN = sd_stopN,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* sub-driver description */
+static const struct sd_desc sd_desc_sportscam_dv15 = {
+ .name = MODULE_NAME,
+ .config = sd_config,
+ .init = sd_init,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .pkt_scan = sd_pkt_scan,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .querymenu = sd_querymenu,
+ .get_jcomp = sd_get_jcomp,
+ .set_jcomp = sd_set_jcomp,
+};
+
+static const struct sd_desc *sd_desc[2] = {
+ &sd_desc_sakar_57379,
+ &sd_desc_sportscam_dv15
};
/* -- device connect -- */
@@ -333,7 +570,7 @@ static int sd_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return gspca_dev_probe(intf, id,
- &sd_desc,
+ sd_desc[id->driver_info],
sizeof(struct sd),
THIS_MODULE);
}
diff --git a/drivers/media/video/gspca/kinect.c b/drivers/media/video/gspca/kinect.c
new file mode 100644
index 000000000000..26fc206f095e
--- /dev/null
+++ b/drivers/media/video/gspca/kinect.c
@@ -0,0 +1,429 @@
+/*
+ * kinect sensor device camera, gspca driver
+ *
+ * Copyright (C) 2011 Antonio Ospite <ospite@studenti.unina.it>
+ *
+ * Based on the OpenKinect project and libfreenect
+ * http://openkinect.org/wiki/Init_Analysis
+ *
+ * Special thanks to Steven Toth and kernellabs.com for sponsoring a Kinect
+ * sensor device which I tested the driver on.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * 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 "kinect"
+
+#include "gspca.h"
+
+#define CTRL_TIMEOUT 500
+
+MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>");
+MODULE_DESCRIPTION("GSPCA/Kinect Sensor Device USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+#ifdef GSPCA_DEBUG
+int gspca_debug = D_ERR | D_PROBE | D_CONF | D_STREAM | D_FRAM | D_PACK |
+ D_USBI | D_USBO | D_V4L2;
+#endif
+
+struct pkt_hdr {
+ uint8_t magic[2];
+ uint8_t pad;
+ uint8_t flag;
+ uint8_t unk1;
+ uint8_t seq;
+ uint8_t unk2;
+ uint8_t unk3;
+ uint32_t timestamp;
+};
+
+struct cam_hdr {
+ uint8_t magic[2];
+ uint16_t len;
+ uint16_t cmd;
+ uint16_t tag;
+};
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+ uint16_t cam_tag; /* a sequence number for packets */
+ uint8_t stream_flag; /* to identify different stream types */
+ uint8_t obuf[0x400]; /* output buffer for control commands */
+ uint8_t ibuf[0x200]; /* input buffer for control commands */
+};
+
+/* V4L2 controls supported by the driver */
+/* controls prototypes here */
+
+static const struct ctrl sd_ctrls[] = {
+};
+
+#define MODE_640x480 0x0001
+#define MODE_640x488 0x0002
+#define MODE_1280x1024 0x0004
+
+#define FORMAT_BAYER 0x0010
+#define FORMAT_UYVY 0x0020
+#define FORMAT_Y10B 0x0040
+
+#define FPS_HIGH 0x0100
+
+static const struct v4l2_pix_format video_camera_mode[] = {
+ {640, 480, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = MODE_640x480 | FORMAT_BAYER | FPS_HIGH},
+ {640, 480, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE,
+ .bytesperline = 640 * 2,
+ .sizeimage = 640 * 480 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = MODE_640x480 | FORMAT_UYVY},
+ {1280, 1024, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,
+ .bytesperline = 1280,
+ .sizeimage = 1280 * 1024,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = MODE_1280x1024 | FORMAT_BAYER},
+ {640, 488, V4L2_PIX_FMT_Y10BPACK, V4L2_FIELD_NONE,
+ .bytesperline = 640 * 10 / 8,
+ .sizeimage = 640 * 488 * 10 / 8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = MODE_640x488 | FORMAT_Y10B | FPS_HIGH},
+ {1280, 1024, V4L2_PIX_FMT_Y10BPACK, V4L2_FIELD_NONE,
+ .bytesperline = 1280 * 10 / 8,
+ .sizeimage = 1280 * 1024 * 10 / 8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = MODE_1280x1024 | FORMAT_Y10B},
+};
+
+static int kinect_write(struct usb_device *udev, uint8_t *data,
+ uint16_t wLength)
+{
+ return usb_control_msg(udev,
+ usb_sndctrlpipe(udev, 0),
+ 0x00,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, 0, data, wLength, CTRL_TIMEOUT);
+}
+
+static int kinect_read(struct usb_device *udev, uint8_t *data, uint16_t wLength)
+{
+ return usb_control_msg(udev,
+ usb_rcvctrlpipe(udev, 0),
+ 0x00,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, 0, data, wLength, CTRL_TIMEOUT);
+}
+
+static int send_cmd(struct gspca_dev *gspca_dev, uint16_t cmd, void *cmdbuf,
+ unsigned int cmd_len, void *replybuf, unsigned int reply_len)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct usb_device *udev = gspca_dev->dev;
+ int res, actual_len;
+ uint8_t *obuf = sd->obuf;
+ uint8_t *ibuf = sd->ibuf;
+ struct cam_hdr *chdr = (void *)obuf;
+ struct cam_hdr *rhdr = (void *)ibuf;
+
+ if (cmd_len & 1 || cmd_len > (0x400 - sizeof(*chdr))) {
+ err("send_cmd: Invalid command length (0x%x)", cmd_len);
+ return -1;
+ }
+
+ chdr->magic[0] = 0x47;
+ chdr->magic[1] = 0x4d;
+ chdr->cmd = cpu_to_le16(cmd);
+ chdr->tag = cpu_to_le16(sd->cam_tag);
+ chdr->len = cpu_to_le16(cmd_len / 2);
+
+ memcpy(obuf+sizeof(*chdr), cmdbuf, cmd_len);
+
+ res = kinect_write(udev, obuf, cmd_len + sizeof(*chdr));
+ PDEBUG(D_USBO, "Control cmd=%04x tag=%04x len=%04x: %d", cmd,
+ sd->cam_tag, cmd_len, res);
+ if (res < 0) {
+ err("send_cmd: Output control transfer failed (%d)", res);
+ return res;
+ }
+
+ do {
+ actual_len = kinect_read(udev, ibuf, 0x200);
+ } while (actual_len == 0);
+ PDEBUG(D_USBO, "Control reply: %d", res);
+ if (actual_len < sizeof(*rhdr)) {
+ err("send_cmd: Input control transfer failed (%d)", res);
+ return res;
+ }
+ actual_len -= sizeof(*rhdr);
+
+ if (rhdr->magic[0] != 0x52 || rhdr->magic[1] != 0x42) {
+ err("send_cmd: Bad magic %02x %02x", rhdr->magic[0],
+ rhdr->magic[1]);
+ return -1;
+ }
+ if (rhdr->cmd != chdr->cmd) {
+ err("send_cmd: Bad cmd %02x != %02x", rhdr->cmd, chdr->cmd);
+ return -1;
+ }
+ if (rhdr->tag != chdr->tag) {
+ err("send_cmd: Bad tag %04x != %04x", rhdr->tag, chdr->tag);
+ return -1;
+ }
+ if (cpu_to_le16(rhdr->len) != (actual_len/2)) {
+ err("send_cmd: Bad len %04x != %04x",
+ cpu_to_le16(rhdr->len), (int)(actual_len/2));
+ return -1;
+ }
+
+ if (actual_len > reply_len) {
+ warn("send_cmd: Data buffer is %d bytes long, but got %d bytes",
+ reply_len, actual_len);
+ memcpy(replybuf, ibuf+sizeof(*rhdr), reply_len);
+ } else {
+ memcpy(replybuf, ibuf+sizeof(*rhdr), actual_len);
+ }
+
+ sd->cam_tag++;
+
+ return actual_len;
+}
+
+static int write_register(struct gspca_dev *gspca_dev, uint16_t reg,
+ uint16_t data)
+{
+ uint16_t reply[2];
+ uint16_t cmd[2];
+ int res;
+
+ cmd[0] = cpu_to_le16(reg);
+ cmd[1] = cpu_to_le16(data);
+
+ PDEBUG(D_USBO, "Write Reg 0x%04x <= 0x%02x", reg, data);
+ res = send_cmd(gspca_dev, 0x03, cmd, 4, reply, 4);
+ if (res < 0)
+ return res;
+ if (res != 2) {
+ warn("send_cmd returned %d [%04x %04x], 0000 expected",
+ res, reply[0], reply[1]);
+ }
+ return 0;
+}
+
+/* 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;
+ struct cam *cam;
+
+ sd->cam_tag = 0;
+
+ /* Only video stream is supported for now,
+ * which has stream flag = 0x80 */
+ sd->stream_flag = 0x80;
+
+ cam = &gspca_dev->cam;
+
+ cam->cam_mode = video_camera_mode;
+ cam->nmodes = ARRAY_SIZE(video_camera_mode);
+
+#if 0
+ /* Setting those values is not needed for video stream */
+ cam->npkt = 15;
+ gspca_dev->pkt_size = 960 * 2;
+#endif
+
+ return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ PDEBUG(D_PROBE, "Kinect Camera device.");
+
+ return 0;
+}
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+ int mode;
+ uint8_t fmt_reg, fmt_val;
+ uint8_t res_reg, res_val;
+ uint8_t fps_reg, fps_val;
+ uint8_t mode_val;
+
+ mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+
+ if (mode & FORMAT_Y10B) {
+ fmt_reg = 0x19;
+ res_reg = 0x1a;
+ fps_reg = 0x1b;
+ mode_val = 0x03;
+ } else {
+ fmt_reg = 0x0c;
+ res_reg = 0x0d;
+ fps_reg = 0x0e;
+ mode_val = 0x01;
+ }
+
+ /* format */
+ if (mode & FORMAT_UYVY)
+ fmt_val = 0x05;
+ else
+ fmt_val = 0x00;
+
+ if (mode & MODE_1280x1024)
+ res_val = 0x02;
+ else
+ res_val = 0x01;
+
+ if (mode & FPS_HIGH)
+ fps_val = 0x1e;
+ else
+ fps_val = 0x0f;
+
+
+ /* turn off IR-reset function */
+ write_register(gspca_dev, 0x105, 0x00);
+
+ /* Reset video stream */
+ write_register(gspca_dev, 0x05, 0x00);
+
+ /* Due to some ridiculous condition in the firmware, we have to start
+ * and stop the depth stream before the camera will hand us 1280x1024
+ * IR. This is a stupid workaround, but we've yet to find a better
+ * solution.
+ *
+ * Thanks to Drew Fisher for figuring this out.
+ */
+ if (mode & (FORMAT_Y10B | MODE_1280x1024)) {
+ write_register(gspca_dev, 0x13, 0x01);
+ write_register(gspca_dev, 0x14, 0x1e);
+ write_register(gspca_dev, 0x06, 0x02);
+ write_register(gspca_dev, 0x06, 0x00);
+ }
+
+ write_register(gspca_dev, fmt_reg, fmt_val);
+ write_register(gspca_dev, res_reg, res_val);
+ write_register(gspca_dev, fps_reg, fps_val);
+
+ /* Start video stream */
+ write_register(gspca_dev, 0x05, mode_val);
+
+ /* disable Hflip */
+ write_register(gspca_dev, 0x47, 0x00);
+
+ return 0;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ /* reset video stream */
+ write_register(gspca_dev, 0x05, 0x00);
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *__data, int len)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ struct pkt_hdr *hdr = (void *)__data;
+ uint8_t *data = __data + sizeof(*hdr);
+ int datalen = len - sizeof(*hdr);
+
+ uint8_t sof = sd->stream_flag | 1;
+ uint8_t mof = sd->stream_flag | 2;
+ uint8_t eof = sd->stream_flag | 5;
+
+ if (len < 12)
+ return;
+
+ if (hdr->magic[0] != 'R' || hdr->magic[1] != 'B') {
+ warn("[Stream %02x] Invalid magic %02x%02x", sd->stream_flag,
+ hdr->magic[0], hdr->magic[1]);
+ return;
+ }
+
+ if (hdr->flag == sof)
+ gspca_frame_add(gspca_dev, FIRST_PACKET, data, datalen);
+
+ else if (hdr->flag == mof)
+ gspca_frame_add(gspca_dev, INTER_PACKET, data, datalen);
+
+ else if (hdr->flag == eof)
+ gspca_frame_add(gspca_dev, LAST_PACKET, data, datalen);
+
+ else
+ warn("Packet type not recognized...");
+}
+
+/* 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,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .pkt_scan = sd_pkt_scan,
+ /*
+ .querymenu = sd_querymenu,
+ .get_streamparm = sd_get_streamparm,
+ .set_streamparm = sd_set_streamparm,
+ */
+};
+
+/* -- module initialisation -- */
+static const struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x045e, 0x02ae)},
+ {}
+};
+
+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)
+{
+ return usb_register(&sd_driver);
+}
+
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c
index 41dce49fb43d..9d0b46027b93 100644
--- a/drivers/media/video/gspca/spca508.c
+++ b/drivers/media/video/gspca/spca508.c
@@ -1375,7 +1375,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
{
struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam;
- int data1, data2;
const u16 (*init_data)[2];
static const u16 (*(init_data_tb[]))[2] = {
spca508_vista_init_data, /* CreativeVista 0 */
@@ -1386,6 +1385,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
spca508_init_data, /* ViewQuestVQ110 5 */
};
+#ifdef GSPCA_DEBUG
+ int data1, data2;
+
/* Read from global register the USB product and vendor IDs, just to
* prove that we can communicate with the device. This works, which
* confirms at we are communicating properly and that the device
@@ -1400,6 +1402,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
data1 = reg_read(gspca_dev, 0x8621);
PDEBUG(D_PROBE, "Window 1 average luminance: %d", data1);
+#endif
cam = &gspca_dev->cam;
cam->cam_mode = sif_mode;
diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c
index 87be52b5e1e3..763747700f10 100644
--- a/drivers/media/video/gspca/stk014.c
+++ b/drivers/media/video/gspca/stk014.c
@@ -436,17 +436,14 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
static int sd_querymenu(struct gspca_dev *gspca_dev,
struct v4l2_querymenu *menu)
{
+ static const char *freq_nm[3] = {"NoFliker", "50 Hz", "60 Hz"};
+
switch (menu->id) {
case V4L2_CID_POWER_LINE_FREQUENCY:
- switch (menu->index) {
- case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
- strcpy((char *) menu->name, "50 Hz");
- return 0;
- case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
- strcpy((char *) menu->name, "60 Hz");
- return 0;
- }
- break;
+ if ((unsigned) menu->index >= ARRAY_SIZE(freq_nm))
+ break;
+ strcpy((char *) menu->name, freq_nm[menu->index]);
+ return 0;
}
return -EINVAL;
}
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
index ac47b4c94388..75a5b9c2f15f 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
@@ -217,6 +217,8 @@ static int pb0100_start(struct sd *sd)
intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
+ if (!alt)
+ return -ENODEV;
packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
/* If we don't have enough bandwidth use a lower framerate */
diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c
index 543542af2720..b089c0d3ee9f 100644
--- a/drivers/media/video/gspca/sunplus.c
+++ b/drivers/media/video/gspca/sunplus.c
@@ -396,57 +396,6 @@ static void reg_w_riv(struct gspca_dev *gspca_dev,
req, index, value);
}
-/* read 1 byte */
-static u8 reg_r_1(struct gspca_dev *gspca_dev,
- u16 value) /* wValue */
-{
- int ret;
-
- if (gspca_dev->usb_err < 0)
- return 0;
- ret = usb_control_msg(gspca_dev->dev,
- usb_rcvctrlpipe(gspca_dev->dev, 0),
- 0x20, /* request */
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- value,
- 0, /* index */
- gspca_dev->usb_buf, 1,
- 500); /* timeout */
- if (ret < 0) {
- err("reg_r_1 err %d", ret);
- gspca_dev->usb_err = ret;
- return 0;
- }
- return gspca_dev->usb_buf[0];
-}
-
-/* read 1 or 2 bytes */
-static u16 reg_r_12(struct gspca_dev *gspca_dev,
- u8 req, /* bRequest */
- u16 index, /* wIndex */
- u16 length) /* wLength (1 or 2 only) */
-{
- int ret;
-
- if (gspca_dev->usb_err < 0)
- return 0;
- gspca_dev->usb_buf[1] = 0;
- ret = usb_control_msg(gspca_dev->dev,
- usb_rcvctrlpipe(gspca_dev->dev, 0),
- req,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, /* value */
- index,
- gspca_dev->usb_buf, length,
- 500);
- if (ret < 0) {
- err("reg_r_12 err %d", ret);
- gspca_dev->usb_err = ret;
- return 0;
- }
- return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
-}
-
static void write_vector(struct gspca_dev *gspca_dev,
const struct cmd *data, int ncmds)
{
@@ -473,44 +422,46 @@ static void setup_qtable(struct gspca_dev *gspca_dev,
static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
u8 req, u16 idx, u16 val)
{
- u16 notdone;
-
reg_w_riv(gspca_dev, req, idx, val);
- notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
+ reg_r(gspca_dev, 0x01, 0x0001, 1);
+ PDEBUG(D_FRAM, "before wait 0x%04x", gspca_dev->usb_buf[0]);
reg_w_riv(gspca_dev, req, idx, val);
- PDEBUG(D_FRAM, "before wait 0x%04x", notdone);
-
msleep(200);
- notdone = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
- PDEBUG(D_FRAM, "after wait 0x%04x", notdone);
+ reg_r(gspca_dev, 0x01, 0x0001, 1);
+ PDEBUG(D_FRAM, "after wait 0x%04x", gspca_dev->usb_buf[0]);
}
+#ifdef GSPCA_DEBUG
static void spca504_read_info(struct gspca_dev *gspca_dev)
{
int i;
u8 info[6];
- for (i = 0; i < 6; i++)
- info[i] = reg_r_1(gspca_dev, i);
+ for (i = 0; i < 6; i++) {
+ reg_r(gspca_dev, 0, i, 1);
+ info[i] = gspca_dev->usb_buf[0];
+ }
PDEBUG(D_STREAM,
"Read info: %d %d %d %d %d %d."
" Should be 1,0,2,2,0,0",
info[0], info[1], info[2],
info[3], info[4], info[5]);
}
+#endif
static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
u8 req,
- u16 idx, u16 val, u16 endcode, u8 count)
+ u16 idx, u16 val, u8 endcode, u8 count)
{
u16 status;
reg_w_riv(gspca_dev, req, idx, val);
- status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
+ reg_r(gspca_dev, 0x01, 0x0001, 1);
if (gspca_dev->usb_err < 0)
return;
- PDEBUG(D_FRAM, "Status 0x%04x Need 0x%04x", status, endcode);
+ PDEBUG(D_FRAM, "Status 0x%02x Need 0x%02x",
+ gspca_dev->usb_buf[0], endcode);
if (!count)
return;
count = 200;
@@ -518,7 +469,8 @@ static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
msleep(10);
/* gsmart mini2 write a each wait setting 1 ms is enough */
/* reg_w_riv(gspca_dev, req, idx, val); */
- status = reg_r_12(gspca_dev, 0x01, 0x0001, 1);
+ reg_r(gspca_dev, 0x01, 0x0001, 1);
+ status = gspca_dev->usb_buf[0];
if (status == endcode) {
PDEBUG(D_FRAM, "status 0x%04x after wait %d",
status, 200 - count);
@@ -555,17 +507,19 @@ static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
}
}
+#ifdef GSPCA_DEBUG
static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
{
u8 *data;
data = gspca_dev->usb_buf;
reg_r(gspca_dev, 0x20, 0, 5);
- PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ",
+ PDEBUG(D_STREAM, "FirmWare: %d %d %d %d %d",
data[0], data[1], data[2], data[3], data[4]);
reg_r(gspca_dev, 0x23, 0, 64);
reg_r(gspca_dev, 0x23, 1, 64);
}
+#endif
static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
{
@@ -578,7 +532,9 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
reg_w_riv(gspca_dev, 0x31, 0, 0);
spca504B_WaitCmdStatus(gspca_dev);
spca504B_PollingDataReady(gspca_dev);
+#ifdef GSPCA_DEBUG
spca50x_GetFirmware(gspca_dev);
+#endif
reg_w_1(gspca_dev, 0x24, 0, 8, 2); /* type */
reg_r(gspca_dev, 0x24, 8, 1);
@@ -628,7 +584,8 @@ static void spca504_wait_status(struct gspca_dev *gspca_dev)
cnt = 256;
while (--cnt > 0) {
/* With this we get the status, when return 0 it's all ok */
- if (reg_r_12(gspca_dev, 0x06, 0x00, 1) == 0)
+ reg_r(gspca_dev, 0x06, 0x00, 1);
+ if (gspca_dev->usb_buf[0] == 0)
return;
msleep(10);
}
@@ -772,10 +729,14 @@ static int sd_init(struct gspca_dev *gspca_dev)
/* fall thru */
case BRIDGE_SPCA533:
spca504B_PollingDataReady(gspca_dev);
+#ifdef GSPCA_DEBUG
spca50x_GetFirmware(gspca_dev);
+#endif
break;
case BRIDGE_SPCA536:
+#ifdef GSPCA_DEBUG
spca50x_GetFirmware(gspca_dev);
+#endif
reg_r(gspca_dev, 0x00, 0x5002, 1);
reg_w_1(gspca_dev, 0x24, 0, 0, 0);
reg_r(gspca_dev, 0x24, 0, 1);
@@ -801,7 +762,9 @@ static int sd_init(struct gspca_dev *gspca_dev)
/* case BRIDGE_SPCA504: */
PDEBUG(D_STREAM, "Opening SPCA504");
if (sd->subtype == AiptekMiniPenCam13) {
+#ifdef GSPCA_DEBUG
spca504_read_info(gspca_dev);
+#endif
/* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
spca504A_acknowledged_command(gspca_dev, 0x24,
@@ -873,7 +836,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
break;
case BRIDGE_SPCA504:
if (sd->subtype == AiptekMiniPenCam13) {
+#ifdef GSPCA_DEBUG
spca504_read_info(gspca_dev);
+#endif
/* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
spca504A_acknowledged_command(gspca_dev, 0x24,
@@ -885,7 +850,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
0, 0, 0x9d, 1);
} else {
spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
+#ifdef GSPCA_DEBUG
spca504_read_info(gspca_dev);
+#endif
spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
}
diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c
index a3eccd815766..7e762d551099 100644
--- a/drivers/media/video/gspca/t613.c
+++ b/drivers/media/video/gspca/t613.c
@@ -92,8 +92,6 @@ 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[] = {
{
@@ -1379,17 +1377,14 @@ static int sd_getlowlight(struct gspca_dev *gspca_dev, __s32 *val)
static int sd_querymenu(struct gspca_dev *gspca_dev,
struct v4l2_querymenu *menu)
{
+ static const char *freq_nm[3] = {"NoFliker", "50 Hz", "60 Hz"};
+
switch (menu->id) {
case V4L2_CID_POWER_LINE_FREQUENCY:
- switch (menu->index) {
- case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */
- strcpy((char *) menu->name, "50 Hz");
- return 0;
- case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */
- strcpy((char *) menu->name, "60 Hz");
- return 0;
- }
- break;
+ if ((unsigned) menu->index >= ARRAY_SIZE(freq_nm))
+ break;
+ strcpy((char *) menu->name, freq_nm[menu->index]);
+ return 0;
case V4L2_CID_EFFECTS:
if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) {
strncpy((char *) menu->name,
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
index fa164e861cde..61cdd56a74a9 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -3065,15 +3065,10 @@ static const struct usb_action mc501cb_InitialScale[] = { /* 320x240 */
{0xaa, 0x55, 0x0010}, /* 00,55,10,aa */
{0xa0, 0xf0, 0x0199}, /* 01,99,F0,cc */
{0xa0, 0x80, 0x019a}, /* 01,9A,80,cc */
- {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
- {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
- {0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */
- {0xaa, 0x37, 0x004c}, /* 00,37,4C,aa */
- {0xaa, 0x3b, 0x001d}, /* 00,3B,1D,aa */
{}
};
-static const struct usb_action mc501cb_50HZScale[] = {
+static const struct usb_action mc501cb_50HZ[] = {
{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
{0xaa, 0x36, 0x001d}, /* 00,36,1D,aa */
@@ -3082,15 +3077,10 @@ static const struct usb_action mc501cb_50HZScale[] = {
{0xaa, 0x3c, 0x004c}, /* 00,3C,4C,aa */
{0xaa, 0x3d, 0x001d}, /* 00,3D,1D,aa */
{0xaa, 0x3e, 0x004c}, /* 00,3E,4C,aa */
- {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
- {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
- {0xaa, 0x36, 0x003a}, /* 00,36,3A,aa */
- {0xaa, 0x37, 0x0098}, /* 00,37,98,aa */
- {0xaa, 0x3b, 0x003a}, /* 00,3B,3A,aa */
{}
};
-static const struct usb_action mc501cb_50HZ[] = {
+static const struct usb_action mc501cb_50HZScale[] = {
{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
{0xaa, 0x36, 0x003a}, /* 00,36,3A,aa */
@@ -3099,15 +3089,10 @@ static const struct usb_action mc501cb_50HZ[] = {
{0xaa, 0x3c, 0x0098}, /* 00,3C,98,aa */
{0xaa, 0x3d, 0x003a}, /* 00,3D,3A,aa */
{0xaa, 0x3e, 0x0098}, /* 00,3E,98,aa */
- {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
- {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
- {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
- {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */
- {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */
{}
};
-static const struct usb_action mc501cb_60HZScale[] = {
+static const struct usb_action mc501cb_60HZ[] = {
{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
{0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
@@ -3116,15 +3101,10 @@ static const struct usb_action mc501cb_60HZScale[] = {
{0xaa, 0x3e, 0x006a}, /* 00,3E,6A,aa */
{0xaa, 0x3b, 0x0018}, /* 00,3B,18,aa */
{0xaa, 0x3c, 0x006a}, /* 00,3C,6A,aa */
- {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
- {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
- {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
- {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */
- {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */
{}
};
-static const struct usb_action mc501cb_60HZ[] = {
+static const struct usb_action mc501cb_60HZScale[] = {
{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
{0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
@@ -3133,15 +3113,10 @@ static const struct usb_action mc501cb_60HZ[] = {
{0xaa, 0x3e, 0x00d4}, /* 00,3E,D4,aa */
{0xaa, 0x3b, 0x0030}, /* 00,3B,30,aa */
{0xaa, 0x3c, 0x00d4}, /* 00,3C,D4,aa */
- {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
- {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
- {0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
- {0xaa, 0x37, 0x006a}, /* 00,37,6A,aa */
- {0xaa, 0x3d, 0x0018}, /* 00,3D,18,aa */
{}
};
-static const struct usb_action mc501cb_NoFlikerScale[] = {
+static const struct usb_action mc501cb_NoFliker[] = {
{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
{0xaa, 0x36, 0x0018}, /* 00,36,18,aa */
@@ -3150,15 +3125,10 @@ static const struct usb_action mc501cb_NoFlikerScale[] = {
{0xaa, 0x3e, 0x006a}, /* 00,3E,6A,aa */
{0xaa, 0x3b, 0x0018}, /* 00,3B,18,aa */
{0xaa, 0x3c, 0x006a}, /* 00,3C,6A,aa */
- {0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
- {0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
- {0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
- {0xaa, 0x37, 0x00d4}, /* 00,37,D4,aa */
- {0xaa, 0x3d, 0x0030}, /* 00,3D,30,aa */
{}
};
-static const struct usb_action mc501cb_NoFliker[] = {
+static const struct usb_action mc501cb_NoFlikerScale[] = {
{0xaa, 0x03, 0x0003}, /* 00,03,03,aa */
{0xaa, 0x10, 0x00fc}, /* 00,10,fc,aa */
{0xaa, 0x36, 0x0030}, /* 00,36,30,aa */
@@ -6296,7 +6266,6 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int i;
- u8 retbyte;
u16 retword;
/*fixme: lack of 8b=b3 (11,12)-> 10, 8b=e0 (14,15,16)-> 12 found in gspcav1*/
@@ -6389,8 +6358,12 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
retword |= i2c_read(gspca_dev, 0x01); /* ID 1 */
PDEBUG(D_PROBE, "probe 3wr vga 2 0x%04x", retword);
if (retword == 0x2030) {
+#ifdef GSPCA_DEBUG
+ u8 retbyte;
+
retbyte = i2c_read(gspca_dev, 0x02); /* revision number */
PDEBUG(D_PROBE, "sensor PO2030 rev 0x%02x", retbyte);
+#endif
send_unknown(gspca_dev, SENSOR_PO2030);
return retword;
}
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 39946420b301..a4e4dfdbc2f2 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -810,7 +810,6 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev,
const struct pci_device_id *pci_id)
{
u16 cmd;
- u8 card_rev;
unsigned char pci_latency;
IVTV_DEBUG_INFO("Enabling pci device\n");
@@ -857,7 +856,6 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev,
}
IVTV_DEBUG_INFO("Bus Mastering Enabled.\n");
- pci_read_config_byte(pdev, PCI_CLASS_REVISION, &card_rev);
pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
if (pci_latency < 64 && ivtv_pci_latency) {
@@ -874,7 +872,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev,
IVTV_DEBUG_INFO("%d (rev %d) at %02x:%02x.%x, "
"irq: %d, latency: %d, memory: 0x%lx\n",
- pdev->device, card_rev, pdev->bus->number,
+ pdev->device, pdev->revision, pdev->bus->number,
PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
pdev->irq, pci_latency, (unsigned long)itv->base_addr);
diff --git a/drivers/media/video/m5mols/Kconfig b/drivers/media/video/m5mols/Kconfig
new file mode 100644
index 000000000000..302dc3d70193
--- /dev/null
+++ b/drivers/media/video/m5mols/Kconfig
@@ -0,0 +1,5 @@
+config VIDEO_M5MOLS
+ tristate "Fujitsu M-5MOLS 8MP sensor support"
+ depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+ ---help---
+ This driver supports Fujitsu M-5MOLS camera sensor with ISP
diff --git a/drivers/media/video/m5mols/Makefile b/drivers/media/video/m5mols/Makefile
new file mode 100644
index 000000000000..0a44e028edc7
--- /dev/null
+++ b/drivers/media/video/m5mols/Makefile
@@ -0,0 +1,3 @@
+m5mols-objs := m5mols_core.o m5mols_controls.o m5mols_capture.o
+
+obj-$(CONFIG_VIDEO_M5MOLS) += m5mols.o
diff --git a/drivers/media/video/m5mols/m5mols.h b/drivers/media/video/m5mols/m5mols.h
new file mode 100644
index 000000000000..10b55c854487
--- /dev/null
+++ b/drivers/media/video/m5mols/m5mols.h
@@ -0,0 +1,296 @@
+/*
+ * Header for M-5MOLS 8M Pixel camera sensor with ISP
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Author: HeungJun Kim, riverful.kim@samsung.com
+ *
+ * Copyright (C) 2009 Samsung Electronics Co., Ltd.
+ * Author: Dongsoo Nathaniel Kim, dongsoo45.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 M5MOLS_H
+#define M5MOLS_H
+
+#include <media/v4l2-subdev.h>
+#include "m5mols_reg.h"
+
+extern int m5mols_debug;
+
+#define to_m5mols(__sd) container_of(__sd, struct m5mols_info, sd)
+
+#define to_sd(__ctrl) \
+ (&container_of(__ctrl->handler, struct m5mols_info, handle)->sd)
+
+enum m5mols_restype {
+ M5MOLS_RESTYPE_MONITOR,
+ M5MOLS_RESTYPE_CAPTURE,
+ M5MOLS_RESTYPE_MAX,
+};
+
+/**
+ * struct m5mols_resolution - structure for the resolution
+ * @type: resolution type according to the pixel code
+ * @width: width of the resolution
+ * @height: height of the resolution
+ * @reg: resolution preset register value
+ */
+struct m5mols_resolution {
+ u8 reg;
+ enum m5mols_restype type;
+ u16 width;
+ u16 height;
+};
+
+/**
+ * struct m5mols_exif - structure for the EXIF information of M-5MOLS
+ * @exposure_time: exposure time register value
+ * @shutter_speed: speed of the shutter register value
+ * @aperture: aperture register value
+ * @exposure_bias: it calls also EV bias
+ * @iso_speed: ISO register value
+ * @flash: status register value of the flash
+ * @sdr: status register value of the Subject Distance Range
+ * @qval: not written exact meaning in document
+ */
+struct m5mols_exif {
+ u32 exposure_time;
+ u32 shutter_speed;
+ u32 aperture;
+ u32 brightness;
+ u32 exposure_bias;
+ u16 iso_speed;
+ u16 flash;
+ u16 sdr;
+ u16 qval;
+};
+
+/**
+ * struct m5mols_capture - Structure for the capture capability
+ * @exif: EXIF information
+ * @main: size in bytes of the main image
+ * @thumb: size in bytes of the thumb image, if it was accompanied
+ * @total: total size in bytes of the produced image
+ */
+struct m5mols_capture {
+ struct m5mols_exif exif;
+ u32 main;
+ u32 thumb;
+ u32 total;
+};
+
+/**
+ * struct m5mols_scenemode - structure for the scenemode capability
+ * @metering: metering light register value
+ * @ev_bias: EV bias register value
+ * @wb_mode: mode which means the WhiteBalance is Auto or Manual
+ * @wb_preset: whitebalance preset register value in the Manual mode
+ * @chroma_en: register value whether the Chroma capability is enabled or not
+ * @chroma_lvl: chroma's level register value
+ * @edge_en: register value Whether the Edge capability is enabled or not
+ * @edge_lvl: edge's level register value
+ * @af_range: Auto Focus's range
+ * @fd_mode: Face Detection mode
+ * @mcc: Multi-axis Color Conversion which means emotion color
+ * @light: status of the Light
+ * @flash: status of the Flash
+ * @tone: Tone color which means Contrast
+ * @iso: ISO register value
+ * @capt_mode: Mode of the Image Stabilization while the camera capturing
+ * @wdr: Wide Dynamic Range register value
+ *
+ * The each value according to each scenemode is recommended in the documents.
+ */
+struct m5mols_scenemode {
+ u32 metering;
+ u32 ev_bias;
+ u32 wb_mode;
+ u32 wb_preset;
+ u32 chroma_en;
+ u32 chroma_lvl;
+ u32 edge_en;
+ u32 edge_lvl;
+ u32 af_range;
+ u32 fd_mode;
+ u32 mcc;
+ u32 light;
+ u32 flash;
+ u32 tone;
+ u32 iso;
+ u32 capt_mode;
+ u32 wdr;
+};
+
+/**
+ * struct m5mols_version - firmware version information
+ * @customer: customer information
+ * @project: version of project information according to customer
+ * @fw: firmware revision
+ * @hw: hardware revision
+ * @param: version of the parameter
+ * @awb: Auto WhiteBalance algorithm version
+ * @str: information about manufacturer and packaging vendor
+ * @af: Auto Focus version
+ *
+ * The register offset starts the customer version at 0x0, and it ends
+ * the awb version at 0x09. The customer, project information occupies 1 bytes
+ * each. And also the fw, hw, param, awb each requires 2 bytes. The str is
+ * unique string associated with firmware's version. It includes information
+ * about manufacturer and the vendor of the sensor's packaging. The least
+ * significant 2 bytes of the string indicate packaging manufacturer.
+ */
+#define VERSION_STRING_SIZE 22
+struct m5mols_version {
+ u8 customer;
+ u8 project;
+ u16 fw;
+ u16 hw;
+ u16 param;
+ u16 awb;
+ u8 str[VERSION_STRING_SIZE];
+ u8 af;
+};
+#define VERSION_SIZE sizeof(struct m5mols_version)
+
+/**
+ * struct m5mols_info - M-5MOLS driver data structure
+ * @pdata: platform data
+ * @sd: v4l-subdev instance
+ * @pad: media pad
+ * @ffmt: current fmt according to resolution type
+ * @res_type: current resolution type
+ * @code: current code
+ * @irq_waitq: waitqueue for the capture
+ * @work_irq: workqueue for the IRQ
+ * @flags: state variable for the interrupt handler
+ * @handle: control handler
+ * @autoexposure: Auto Exposure control
+ * @exposure: Exposure control
+ * @autowb: Auto White Balance control
+ * @colorfx: Color effect control
+ * @saturation: Saturation control
+ * @zoom: Zoom control
+ * @ver: information of the version
+ * @cap: the capture mode attributes
+ * @power: current sensor's power status
+ * @ctrl_sync: true means all controls of the sensor are initialized
+ * @int_capture: true means the capture interrupt is issued once
+ * @lock_ae: true means the Auto Exposure is locked
+ * @lock_awb: true means the Aut WhiteBalance is locked
+ * @resolution: register value for current resolution
+ * @interrupt: register value for current interrupt status
+ * @mode: register value for current operation mode
+ * @mode_save: register value for current operation mode for saving
+ * @set_power: optional power callback to the board code
+ */
+struct m5mols_info {
+ const struct m5mols_platform_data *pdata;
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+ struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX];
+ int res_type;
+ enum v4l2_mbus_pixelcode code;
+ wait_queue_head_t irq_waitq;
+ struct work_struct work_irq;
+ unsigned long flags;
+
+ struct v4l2_ctrl_handler handle;
+ /* Autoexposure/exposure control cluster */
+ struct {
+ struct v4l2_ctrl *autoexposure;
+ struct v4l2_ctrl *exposure;
+ };
+ struct v4l2_ctrl *autowb;
+ struct v4l2_ctrl *colorfx;
+ struct v4l2_ctrl *saturation;
+ struct v4l2_ctrl *zoom;
+
+ struct m5mols_version ver;
+ struct m5mols_capture cap;
+ bool power;
+ bool ctrl_sync;
+ bool lock_ae;
+ bool lock_awb;
+ u8 resolution;
+ u32 interrupt;
+ u32 mode;
+ u32 mode_save;
+ int (*set_power)(struct device *dev, int on);
+};
+
+#define ST_CAPT_IRQ 0
+
+#define is_powered(__info) (__info->power)
+#define is_ctrl_synced(__info) (__info->ctrl_sync)
+#define is_available_af(__info) (__info->ver.af)
+#define is_code(__code, __type) (__code == m5mols_default_ffmt[__type].code)
+#define is_manufacturer(__info, __manufacturer) \
+ (__info->ver.str[0] == __manufacturer[0] && \
+ __info->ver.str[1] == __manufacturer[1])
+/*
+ * I2C operation of the M-5MOLS
+ *
+ * The I2C read operation of the M-5MOLS requires 2 messages. The first
+ * message sends the information about the command, command category, and total
+ * message size. The second message is used to retrieve the data specifed in
+ * the first message
+ *
+ * 1st message 2nd message
+ * +-------+---+----------+-----+-------+ +------+------+------+------+
+ * | size1 | R | category | cmd | size2 | | d[0] | d[1] | d[2] | d[3] |
+ * +-------+---+----------+-----+-------+ +------+------+------+------+
+ * - size1: message data size(5 in this case)
+ * - size2: desired buffer size of the 2nd message
+ * - d[0..3]: according to size2
+ *
+ * The I2C write operation needs just one message. The message includes
+ * category, command, total size, and desired data.
+ *
+ * 1st message
+ * +-------+---+----------+-----+------+------+------+------+
+ * | size1 | W | category | cmd | d[0] | d[1] | d[2] | d[3] |
+ * +-------+---+----------+-----+------+------+------+------+
+ * - d[0..3]: according to size1
+ */
+int m5mols_read(struct v4l2_subdev *sd, u32 reg_comb, u32 *val);
+int m5mols_write(struct v4l2_subdev *sd, u32 reg_comb, u32 val);
+int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 value);
+
+/*
+ * Mode operation of the M-5MOLS
+ *
+ * Changing the mode of the M-5MOLS is needed right executing order.
+ * There are three modes(PARAMETER, MONITOR, CAPTURE) which can be changed
+ * by user. There are various categories associated with each mode.
+ *
+ * +============================================================+
+ * | mode | category |
+ * +============================================================+
+ * | FLASH | FLASH(only after Stand-by or Power-on) |
+ * | SYSTEM | SYSTEM(only after sensor arm-booting) |
+ * | PARAMETER | PARAMETER |
+ * | MONITOR | MONITOR(preview), Auto Focus, Face Detection |
+ * | CAPTURE | Single CAPTURE, Preview(recording) |
+ * +============================================================+
+ *
+ * The available executing order between each modes are as follows:
+ * PARAMETER <---> MONITOR <---> CAPTURE
+ */
+int m5mols_mode(struct m5mols_info *info, u32 mode);
+
+int m5mols_enable_interrupt(struct v4l2_subdev *sd, u32 reg);
+int m5mols_sync_controls(struct m5mols_info *info);
+int m5mols_start_capture(struct m5mols_info *info);
+int m5mols_do_scenemode(struct m5mols_info *info, u32 mode);
+int m5mols_lock_3a(struct m5mols_info *info, bool lock);
+int m5mols_set_ctrl(struct v4l2_ctrl *ctrl);
+
+/* The firmware function */
+int m5mols_update_fw(struct v4l2_subdev *sd,
+ int (*set_power)(struct m5mols_info *, bool));
+
+#endif /* M5MOLS_H */
diff --git a/drivers/media/video/m5mols/m5mols_capture.c b/drivers/media/video/m5mols/m5mols_capture.c
new file mode 100644
index 000000000000..d71a3903b60f
--- /dev/null
+++ b/drivers/media/video/m5mols/m5mols_capture.c
@@ -0,0 +1,191 @@
+/*
+ * The Capture code for Fujitsu M-5MOLS ISP
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Author: HeungJun Kim, riverful.kim@samsung.com
+ *
+ * Copyright (C) 2009 Samsung Electronics Co., Ltd.
+ * Author: Dongsoo Nathaniel Kim, dongsoo45.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.
+ */
+
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <linux/version.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/m5mols.h>
+
+#include "m5mols.h"
+#include "m5mols_reg.h"
+
+static int m5mols_capture_error_handler(struct m5mols_info *info,
+ int timeout)
+{
+ int ret;
+
+ /* Disable all interrupts and clear relevant interrupt staus bits */
+ ret = m5mols_write(&info->sd, SYSTEM_INT_ENABLE,
+ info->interrupt & ~(REG_INT_CAPTURE));
+ if (ret)
+ return ret;
+
+ if (timeout == 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+/**
+ * m5mols_read_rational - I2C read of a rational number
+ *
+ * Read numerator and denominator from registers @addr_num and @addr_den
+ * respectively and return the division result in @val.
+ */
+static int m5mols_read_rational(struct v4l2_subdev *sd, u32 addr_num,
+ u32 addr_den, u32 *val)
+{
+ u32 num, den;
+
+ int ret = m5mols_read(sd, addr_num, &num);
+ if (!ret)
+ ret = m5mols_read(sd, addr_den, &den);
+ if (ret)
+ return ret;
+ *val = den == 0 ? 0 : num / den;
+ return ret;
+}
+
+/**
+ * m5mols_capture_info - Gather captured image information
+ *
+ * For now it gathers only EXIF information and file size.
+ */
+static int m5mols_capture_info(struct m5mols_info *info)
+{
+ struct m5mols_exif *exif = &info->cap.exif;
+ struct v4l2_subdev *sd = &info->sd;
+ int ret;
+
+ ret = m5mols_read_rational(sd, EXIF_INFO_EXPTIME_NU,
+ EXIF_INFO_EXPTIME_DE, &exif->exposure_time);
+ if (ret)
+ return ret;
+ ret = m5mols_read_rational(sd, EXIF_INFO_TV_NU, EXIF_INFO_TV_DE,
+ &exif->shutter_speed);
+ if (ret)
+ return ret;
+ ret = m5mols_read_rational(sd, EXIF_INFO_AV_NU, EXIF_INFO_AV_DE,
+ &exif->aperture);
+ if (ret)
+ return ret;
+ ret = m5mols_read_rational(sd, EXIF_INFO_BV_NU, EXIF_INFO_BV_DE,
+ &exif->brightness);
+ if (ret)
+ return ret;
+ ret = m5mols_read_rational(sd, EXIF_INFO_EBV_NU, EXIF_INFO_EBV_DE,
+ &exif->exposure_bias);
+ if (ret)
+ return ret;
+
+ ret = m5mols_read(sd, EXIF_INFO_ISO, (u32 *)&exif->iso_speed);
+ if (!ret)
+ ret = m5mols_read(sd, EXIF_INFO_FLASH, (u32 *)&exif->flash);
+ if (!ret)
+ ret = m5mols_read(sd, EXIF_INFO_SDR, (u32 *)&exif->sdr);
+ if (!ret)
+ ret = m5mols_read(sd, EXIF_INFO_QVAL, (u32 *)&exif->qval);
+ if (ret)
+ return ret;
+
+ if (!ret)
+ ret = m5mols_read(sd, CAPC_IMAGE_SIZE, &info->cap.main);
+ if (!ret)
+ ret = m5mols_read(sd, CAPC_THUMB_SIZE, &info->cap.thumb);
+ if (!ret)
+ info->cap.total = info->cap.main + info->cap.thumb;
+
+ return ret;
+}
+
+int m5mols_start_capture(struct m5mols_info *info)
+{
+ struct v4l2_subdev *sd = &info->sd;
+ u32 resolution = info->resolution;
+ int timeout;
+ int ret;
+
+ /*
+ * Preparing capture. Setting control & interrupt before entering
+ * capture mode
+ *
+ * 1) change to MONITOR mode for operating control & interrupt
+ * 2) set controls (considering v4l2_control value & lock 3A)
+ * 3) set interrupt
+ * 4) change to CAPTURE mode
+ */
+ ret = m5mols_mode(info, REG_MONITOR);
+ if (!ret)
+ ret = m5mols_sync_controls(info);
+ if (!ret)
+ ret = m5mols_lock_3a(info, true);
+ if (!ret)
+ ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE);
+ if (!ret)
+ ret = m5mols_mode(info, REG_CAPTURE);
+ if (!ret) {
+ /* Wait for capture interrupt, after changing capture mode */
+ timeout = wait_event_interruptible_timeout(info->irq_waitq,
+ test_bit(ST_CAPT_IRQ, &info->flags),
+ msecs_to_jiffies(2000));
+ if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags))
+ ret = m5mols_capture_error_handler(info, timeout);
+ }
+ if (!ret)
+ ret = m5mols_lock_3a(info, false);
+ if (ret)
+ return ret;
+ /*
+ * Starting capture. Setting capture frame count and resolution and
+ * the format(available format: JPEG, Bayer RAW, YUV).
+ *
+ * 1) select single or multi(enable to 25), format, size
+ * 2) set interrupt
+ * 3) start capture(for main image, now)
+ * 4) get information
+ * 5) notify file size to v4l2 device(e.g, to s5p-fimc v4l2 device)
+ */
+ ret = m5mols_write(sd, CAPC_SEL_FRAME, 1);
+ if (!ret)
+ ret = m5mols_write(sd, CAPP_YUVOUT_MAIN, REG_JPEG);
+ if (!ret)
+ ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, resolution);
+ if (!ret)
+ ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE);
+ if (!ret)
+ ret = m5mols_write(sd, CAPC_START, REG_CAP_START_MAIN);
+ if (!ret) {
+ /* Wait for the capture completion interrupt */
+ timeout = wait_event_interruptible_timeout(info->irq_waitq,
+ test_bit(ST_CAPT_IRQ, &info->flags),
+ msecs_to_jiffies(2000));
+ if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags)) {
+ ret = m5mols_capture_info(info);
+ if (!ret)
+ v4l2_subdev_notify(sd, 0, &info->cap.total);
+ }
+ }
+
+ return m5mols_capture_error_handler(info, timeout);
+}
diff --git a/drivers/media/video/m5mols/m5mols_controls.c b/drivers/media/video/m5mols/m5mols_controls.c
new file mode 100644
index 000000000000..817c16fec368
--- /dev/null
+++ b/drivers/media/video/m5mols/m5mols_controls.c
@@ -0,0 +1,299 @@
+/*
+ * Controls for M-5MOLS 8M Pixel camera sensor with ISP
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Author: HeungJun Kim, riverful.kim@samsung.com
+ *
+ * Copyright (C) 2009 Samsung Electronics Co., Ltd.
+ * Author: Dongsoo Nathaniel Kim, dongsoo45.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.
+ */
+
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+
+#include "m5mols.h"
+#include "m5mols_reg.h"
+
+static struct m5mols_scenemode m5mols_default_scenemode[] = {
+ [REG_SCENE_NORMAL] = {
+ REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+ REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
+ REG_AF_NORMAL, REG_FD_OFF,
+ REG_MCC_NORMAL, REG_LIGHT_OFF, REG_FLASH_OFF,
+ 5, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+ },
+ [REG_SCENE_PORTRAIT] = {
+ REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+ REG_CHROMA_ON, 3, REG_EDGE_ON, 4,
+ REG_AF_NORMAL, BIT_FD_EN | BIT_FD_DRAW_FACE_FRAME,
+ REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+ 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+ },
+ [REG_SCENE_LANDSCAPE] = {
+ REG_AE_ALL, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+ REG_CHROMA_ON, 4, REG_EDGE_ON, 6,
+ REG_AF_NORMAL, REG_FD_OFF,
+ REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+ 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+ },
+ [REG_SCENE_SPORTS] = {
+ REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+ REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
+ REG_AF_NORMAL, REG_FD_OFF,
+ REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+ 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+ },
+ [REG_SCENE_PARTY_INDOOR] = {
+ REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+ REG_CHROMA_ON, 4, REG_EDGE_ON, 5,
+ REG_AF_NORMAL, REG_FD_OFF,
+ REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+ 6, REG_ISO_200, REG_CAP_NONE, REG_WDR_OFF,
+ },
+ [REG_SCENE_BEACH_SNOW] = {
+ REG_AE_CENTER, REG_AE_INDEX_10_POS, REG_AWB_AUTO, 0,
+ REG_CHROMA_ON, 4, REG_EDGE_ON, 5,
+ REG_AF_NORMAL, REG_FD_OFF,
+ REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+ 6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF,
+ },
+ [REG_SCENE_SUNSET] = {
+ REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET,
+ REG_AWB_DAYLIGHT,
+ REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
+ REG_AF_NORMAL, REG_FD_OFF,
+ REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+ 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+ },
+ [REG_SCENE_DAWN_DUSK] = {
+ REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET,
+ REG_AWB_FLUORESCENT_1,
+ REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
+ REG_AF_NORMAL, REG_FD_OFF,
+ REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+ 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+ },
+ [REG_SCENE_FALL] = {
+ REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+ REG_CHROMA_ON, 5, REG_EDGE_ON, 5,
+ REG_AF_NORMAL, REG_FD_OFF,
+ REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+ 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+ },
+ [REG_SCENE_NIGHT] = {
+ REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+ REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
+ REG_AF_NORMAL, REG_FD_OFF,
+ REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+ 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+ },
+ [REG_SCENE_AGAINST_LIGHT] = {
+ REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+ REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
+ REG_AF_NORMAL, REG_FD_OFF,
+ REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+ 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+ },
+ [REG_SCENE_FIRE] = {
+ REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+ REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
+ REG_AF_NORMAL, REG_FD_OFF,
+ REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+ 6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF,
+ },
+ [REG_SCENE_TEXT] = {
+ REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+ REG_CHROMA_ON, 3, REG_EDGE_ON, 7,
+ REG_AF_MACRO, REG_FD_OFF,
+ REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+ 6, REG_ISO_AUTO, REG_CAP_ANTI_SHAKE, REG_WDR_ON,
+ },
+ [REG_SCENE_CANDLE] = {
+ REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0,
+ REG_CHROMA_ON, 3, REG_EDGE_ON, 5,
+ REG_AF_NORMAL, REG_FD_OFF,
+ REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF,
+ 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF,
+ },
+};
+
+/**
+ * m5mols_do_scenemode() - Change current scenemode
+ * @mode: Desired mode of the scenemode
+ *
+ * WARNING: The execution order is important. Do not change the order.
+ */
+int m5mols_do_scenemode(struct m5mols_info *info, u32 mode)
+{
+ struct v4l2_subdev *sd = &info->sd;
+ struct m5mols_scenemode scenemode = m5mols_default_scenemode[mode];
+ int ret;
+
+ if (mode > REG_SCENE_CANDLE)
+ return -EINVAL;
+
+ ret = m5mols_lock_3a(info, false);
+ if (!ret)
+ ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, mode);
+ if (!ret)
+ ret = m5mols_write(sd, AE_EV_PRESET_CAPTURE, mode);
+ if (!ret)
+ ret = m5mols_write(sd, AE_MODE, scenemode.metering);
+ if (!ret)
+ ret = m5mols_write(sd, AE_INDEX, scenemode.ev_bias);
+ if (!ret)
+ ret = m5mols_write(sd, AWB_MODE, scenemode.wb_mode);
+ if (!ret)
+ ret = m5mols_write(sd, AWB_MANUAL, scenemode.wb_preset);
+ if (!ret)
+ ret = m5mols_write(sd, MON_CHROMA_EN, scenemode.chroma_en);
+ if (!ret)
+ ret = m5mols_write(sd, MON_CHROMA_LVL, scenemode.chroma_lvl);
+ if (!ret)
+ ret = m5mols_write(sd, MON_EDGE_EN, scenemode.edge_en);
+ if (!ret)
+ ret = m5mols_write(sd, MON_EDGE_LVL, scenemode.edge_lvl);
+ if (!ret && is_available_af(info))
+ ret = m5mols_write(sd, AF_MODE, scenemode.af_range);
+ if (!ret && is_available_af(info))
+ ret = m5mols_write(sd, FD_CTL, scenemode.fd_mode);
+ if (!ret)
+ ret = m5mols_write(sd, MON_TONE_CTL, scenemode.tone);
+ if (!ret)
+ ret = m5mols_write(sd, AE_ISO, scenemode.iso);
+ if (!ret)
+ ret = m5mols_mode(info, REG_CAPTURE);
+ if (!ret)
+ ret = m5mols_write(sd, CAPP_WDR_EN, scenemode.wdr);
+ if (!ret)
+ ret = m5mols_write(sd, CAPP_MCC_MODE, scenemode.mcc);
+ if (!ret)
+ ret = m5mols_write(sd, CAPP_LIGHT_CTRL, scenemode.light);
+ if (!ret)
+ ret = m5mols_write(sd, CAPP_FLASH_CTRL, scenemode.flash);
+ if (!ret)
+ ret = m5mols_write(sd, CAPC_MODE, scenemode.capt_mode);
+ if (!ret)
+ ret = m5mols_mode(info, REG_MONITOR);
+
+ return ret;
+}
+
+static int m5mols_lock_ae(struct m5mols_info *info, bool lock)
+{
+ int ret = 0;
+
+ if (info->lock_ae != lock)
+ ret = m5mols_write(&info->sd, AE_LOCK,
+ lock ? REG_AE_LOCK : REG_AE_UNLOCK);
+ if (!ret)
+ info->lock_ae = lock;
+
+ return ret;
+}
+
+static int m5mols_lock_awb(struct m5mols_info *info, bool lock)
+{
+ int ret = 0;
+
+ if (info->lock_awb != lock)
+ ret = m5mols_write(&info->sd, AWB_LOCK,
+ lock ? REG_AWB_LOCK : REG_AWB_UNLOCK);
+ if (!ret)
+ info->lock_awb = lock;
+
+ return ret;
+}
+
+/* m5mols_lock_3a() - Lock 3A(Auto Exposure, Auto Whitebalance, Auto Focus) */
+int m5mols_lock_3a(struct m5mols_info *info, bool lock)
+{
+ int ret;
+
+ ret = m5mols_lock_ae(info, lock);
+ if (!ret)
+ ret = m5mols_lock_awb(info, lock);
+ /* Don't need to handle unlocking AF */
+ if (!ret && is_available_af(info) && lock)
+ ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP);
+
+ return ret;
+}
+
+/* m5mols_set_ctrl() - The main s_ctrl function called by m5mols_set_ctrl() */
+int m5mols_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = to_sd(ctrl);
+ struct m5mols_info *info = to_m5mols(sd);
+ int ret;
+
+ switch (ctrl->id) {
+ case V4L2_CID_ZOOM_ABSOLUTE:
+ return m5mols_write(sd, MON_ZOOM, ctrl->val);
+
+ case V4L2_CID_EXPOSURE_AUTO:
+ ret = m5mols_lock_ae(info,
+ ctrl->val == V4L2_EXPOSURE_AUTO ? false : true);
+ if (!ret && ctrl->val == V4L2_EXPOSURE_AUTO)
+ ret = m5mols_write(sd, AE_MODE, REG_AE_ALL);
+ if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL) {
+ int val = info->exposure->val;
+ ret = m5mols_write(sd, AE_MODE, REG_AE_OFF);
+ if (!ret)
+ ret = m5mols_write(sd, AE_MAN_GAIN_MON, val);
+ if (!ret)
+ ret = m5mols_write(sd, AE_MAN_GAIN_CAP, val);
+ }
+ return ret;
+
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ ret = m5mols_lock_awb(info, ctrl->val ? false : true);
+ if (!ret)
+ ret = m5mols_write(sd, AWB_MODE, ctrl->val ?
+ REG_AWB_AUTO : REG_AWB_PRESET);
+ return ret;
+
+ case V4L2_CID_SATURATION:
+ ret = m5mols_write(sd, MON_CHROMA_LVL, ctrl->val);
+ if (!ret)
+ ret = m5mols_write(sd, MON_CHROMA_EN, REG_CHROMA_ON);
+ return ret;
+
+ case V4L2_CID_COLORFX:
+ /*
+ * This control uses two kinds of registers: normal & color.
+ * The normal effect belongs to category 1, while the color
+ * one belongs to category 2.
+ *
+ * The normal effect uses one register: CAT1_EFFECT.
+ * The color effect uses three registers:
+ * CAT2_COLOR_EFFECT, CAT2_CFIXR, CAT2_CFIXB.
+ */
+ ret = m5mols_write(sd, PARM_EFFECT,
+ ctrl->val == V4L2_COLORFX_NEGATIVE ? REG_EFFECT_NEGA :
+ ctrl->val == V4L2_COLORFX_EMBOSS ? REG_EFFECT_EMBOSS :
+ REG_EFFECT_OFF);
+ if (!ret)
+ ret = m5mols_write(sd, MON_EFFECT,
+ ctrl->val == V4L2_COLORFX_SEPIA ?
+ REG_COLOR_EFFECT_ON : REG_COLOR_EFFECT_OFF);
+ if (!ret)
+ ret = m5mols_write(sd, MON_CFIXR,
+ ctrl->val == V4L2_COLORFX_SEPIA ?
+ REG_CFIXR_SEPIA : 0);
+ if (!ret)
+ ret = m5mols_write(sd, MON_CFIXB,
+ ctrl->val == V4L2_COLORFX_SEPIA ?
+ REG_CFIXB_SEPIA : 0);
+ return ret;
+ }
+
+ return -EINVAL;
+}
diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/video/m5mols/m5mols_core.c
new file mode 100644
index 000000000000..76eac26e84ae
--- /dev/null
+++ b/drivers/media/video/m5mols/m5mols_core.c
@@ -0,0 +1,1004 @@
+/*
+ * Driver for M-5MOLS 8M Pixel camera sensor with ISP
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Author: HeungJun Kim, riverful.kim@samsung.com
+ *
+ * Copyright (C) 2009 Samsung Electronics Co., Ltd.
+ * Author: Dongsoo Nathaniel Kim, dongsoo45.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.
+ */
+
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/m5mols.h>
+
+#include "m5mols.h"
+#include "m5mols_reg.h"
+
+int m5mols_debug;
+module_param(m5mols_debug, int, 0644);
+
+#define MODULE_NAME "M5MOLS"
+#define M5MOLS_I2C_CHECK_RETRY 500
+
+/* The regulator consumer names for external voltage regulators */
+static struct regulator_bulk_data supplies[] = {
+ {
+ .supply = "core", /* ARM core power, 1.2V */
+ }, {
+ .supply = "dig_18", /* digital power 1, 1.8V */
+ }, {
+ .supply = "d_sensor", /* sensor power 1, 1.8V */
+ }, {
+ .supply = "dig_28", /* digital power 2, 2.8V */
+ }, {
+ .supply = "a_sensor", /* analog power */
+ }, {
+ .supply = "dig_12", /* digital power 3, 1.2V */
+ },
+};
+
+static struct v4l2_mbus_framefmt m5mols_default_ffmt[M5MOLS_RESTYPE_MAX] = {
+ [M5MOLS_RESTYPE_MONITOR] = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .field = V4L2_FIELD_NONE,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ },
+ [M5MOLS_RESTYPE_CAPTURE] = {
+ .width = 1920,
+ .height = 1080,
+ .code = V4L2_MBUS_FMT_JPEG_1X8,
+ .field = V4L2_FIELD_NONE,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ },
+};
+#define SIZE_DEFAULT_FFMT ARRAY_SIZE(m5mols_default_ffmt)
+
+static const struct m5mols_resolution m5mols_reg_res[] = {
+ { 0x01, M5MOLS_RESTYPE_MONITOR, 128, 96 }, /* SUB-QCIF */
+ { 0x03, M5MOLS_RESTYPE_MONITOR, 160, 120 }, /* QQVGA */
+ { 0x05, M5MOLS_RESTYPE_MONITOR, 176, 144 }, /* QCIF */
+ { 0x06, M5MOLS_RESTYPE_MONITOR, 176, 176 },
+ { 0x08, M5MOLS_RESTYPE_MONITOR, 240, 320 }, /* QVGA */
+ { 0x09, M5MOLS_RESTYPE_MONITOR, 320, 240 }, /* QVGA */
+ { 0x0c, M5MOLS_RESTYPE_MONITOR, 240, 400 }, /* WQVGA */
+ { 0x0d, M5MOLS_RESTYPE_MONITOR, 400, 240 }, /* WQVGA */
+ { 0x0e, M5MOLS_RESTYPE_MONITOR, 352, 288 }, /* CIF */
+ { 0x13, M5MOLS_RESTYPE_MONITOR, 480, 360 },
+ { 0x15, M5MOLS_RESTYPE_MONITOR, 640, 360 }, /* qHD */
+ { 0x17, M5MOLS_RESTYPE_MONITOR, 640, 480 }, /* VGA */
+ { 0x18, M5MOLS_RESTYPE_MONITOR, 720, 480 },
+ { 0x1a, M5MOLS_RESTYPE_MONITOR, 800, 480 }, /* WVGA */
+ { 0x1f, M5MOLS_RESTYPE_MONITOR, 800, 600 }, /* SVGA */
+ { 0x21, M5MOLS_RESTYPE_MONITOR, 1280, 720 }, /* HD */
+ { 0x25, M5MOLS_RESTYPE_MONITOR, 1920, 1080 }, /* 1080p */
+ { 0x29, M5MOLS_RESTYPE_MONITOR, 3264, 2448 }, /* 2.63fps 8M */
+ { 0x39, M5MOLS_RESTYPE_MONITOR, 800, 602 }, /* AHS_MON debug */
+
+ { 0x02, M5MOLS_RESTYPE_CAPTURE, 320, 240 }, /* QVGA */
+ { 0x04, M5MOLS_RESTYPE_CAPTURE, 400, 240 }, /* WQVGA */
+ { 0x07, M5MOLS_RESTYPE_CAPTURE, 480, 360 },
+ { 0x08, M5MOLS_RESTYPE_CAPTURE, 640, 360 }, /* qHD */
+ { 0x09, M5MOLS_RESTYPE_CAPTURE, 640, 480 }, /* VGA */
+ { 0x0a, M5MOLS_RESTYPE_CAPTURE, 800, 480 }, /* WVGA */
+ { 0x10, M5MOLS_RESTYPE_CAPTURE, 1280, 720 }, /* HD */
+ { 0x14, M5MOLS_RESTYPE_CAPTURE, 1280, 960 }, /* 1M */
+ { 0x17, M5MOLS_RESTYPE_CAPTURE, 1600, 1200 }, /* 2M */
+ { 0x19, M5MOLS_RESTYPE_CAPTURE, 1920, 1080 }, /* Full-HD */
+ { 0x1a, M5MOLS_RESTYPE_CAPTURE, 2048, 1152 }, /* 3Mega */
+ { 0x1b, M5MOLS_RESTYPE_CAPTURE, 2048, 1536 },
+ { 0x1c, M5MOLS_RESTYPE_CAPTURE, 2560, 1440 }, /* 4Mega */
+ { 0x1d, M5MOLS_RESTYPE_CAPTURE, 2560, 1536 },
+ { 0x1f, M5MOLS_RESTYPE_CAPTURE, 2560, 1920 }, /* 5Mega */
+ { 0x21, M5MOLS_RESTYPE_CAPTURE, 3264, 1836 }, /* 6Mega */
+ { 0x22, M5MOLS_RESTYPE_CAPTURE, 3264, 1960 },
+ { 0x25, M5MOLS_RESTYPE_CAPTURE, 3264, 2448 }, /* 8Mega */
+};
+
+/**
+ * m5mols_swap_byte - an byte array to integer conversion function
+ * @size: size in bytes of I2C packet defined in the M-5MOLS datasheet
+ *
+ * Convert I2C data byte array with performing any required byte
+ * reordering to assure proper values for each data type, regardless
+ * of the architecture endianness.
+ */
+static u32 m5mols_swap_byte(u8 *data, u8 length)
+{
+ if (length == 1)
+ return *data;
+ else if (length == 2)
+ return be16_to_cpu(*((u16 *)data));
+ else
+ return be32_to_cpu(*((u32 *)data));
+}
+
+/**
+ * m5mols_read - I2C read function
+ * @reg: combination of size, category and command for the I2C packet
+ * @val: read value
+ */
+int m5mols_read(struct v4l2_subdev *sd, u32 reg, u32 *val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 rbuf[M5MOLS_I2C_MAX_SIZE + 1];
+ u8 size = I2C_SIZE(reg);
+ u8 category = I2C_CATEGORY(reg);
+ u8 cmd = I2C_COMMAND(reg);
+ struct i2c_msg msg[2];
+ u8 wbuf[5];
+ int ret;
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ if (size != 1 && size != 2 && size != 4) {
+ v4l2_err(sd, "Wrong data size\n");
+ return -EINVAL;
+ }
+
+ msg[0].addr = client->addr;
+ msg[0].flags = 0;
+ msg[0].len = 5;
+ msg[0].buf = wbuf;
+ wbuf[0] = 5;
+ wbuf[1] = M5MOLS_BYTE_READ;
+ wbuf[2] = category;
+ wbuf[3] = cmd;
+ wbuf[4] = size;
+
+ msg[1].addr = client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = size + 1;
+ msg[1].buf = rbuf;
+
+ /* minimum stabilization time */
+ usleep_range(200, 200);
+
+ ret = i2c_transfer(client->adapter, msg, 2);
+ if (ret < 0) {
+ v4l2_err(sd, "read failed: size:%d cat:%02x cmd:%02x. %d\n",
+ size, category, cmd, ret);
+ return ret;
+ }
+
+ *val = m5mols_swap_byte(&rbuf[1], size);
+
+ return 0;
+}
+
+/**
+ * m5mols_write - I2C command write function
+ * @reg: combination of size, category and command for the I2C packet
+ * @val: value to write
+ */
+int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 wbuf[M5MOLS_I2C_MAX_SIZE + 4];
+ u8 category = I2C_CATEGORY(reg);
+ u8 cmd = I2C_COMMAND(reg);
+ u8 size = I2C_SIZE(reg);
+ u32 *buf = (u32 *)&wbuf[4];
+ struct i2c_msg msg[1];
+ int ret;
+
+ if (!client->adapter)
+ return -ENODEV;
+
+ if (size != 1 && size != 2 && size != 4) {
+ v4l2_err(sd, "Wrong data size\n");
+ return -EINVAL;
+ }
+
+ msg->addr = client->addr;
+ msg->flags = 0;
+ msg->len = (u16)size + 4;
+ msg->buf = wbuf;
+ wbuf[0] = size + 4;
+ wbuf[1] = M5MOLS_BYTE_WRITE;
+ wbuf[2] = category;
+ wbuf[3] = cmd;
+
+ *buf = m5mols_swap_byte((u8 *)&val, size);
+
+ usleep_range(200, 200);
+
+ ret = i2c_transfer(client->adapter, msg, 1);
+ if (ret < 0) {
+ v4l2_err(sd, "write failed: size:%d cat:%02x cmd:%02x. %d\n",
+ size, category, cmd, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 mask)
+{
+ u32 busy, i;
+ int ret;
+
+ for (i = 0; i < M5MOLS_I2C_CHECK_RETRY; i++) {
+ ret = m5mols_read(sd, I2C_REG(category, cmd, 1), &busy);
+ if (ret < 0)
+ return ret;
+ if ((busy & mask) == mask)
+ return 0;
+ }
+ return -EBUSY;
+}
+
+/**
+ * m5mols_enable_interrupt - Clear interrupt pending bits and unmask interrupts
+ *
+ * Before writing desired interrupt value the INT_FACTOR register should
+ * be read to clear pending interrupts.
+ */
+int m5mols_enable_interrupt(struct v4l2_subdev *sd, u32 reg)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+ u32 mask = is_available_af(info) ? REG_INT_AF : 0;
+ u32 dummy;
+ int ret;
+
+ ret = m5mols_read(sd, SYSTEM_INT_FACTOR, &dummy);
+ if (!ret)
+ ret = m5mols_write(sd, SYSTEM_INT_ENABLE, reg & ~mask);
+ return ret;
+}
+
+/**
+ * m5mols_reg_mode - Write the mode and check busy status
+ *
+ * It always accompanies a little delay changing the M-5MOLS mode, so it is
+ * needed checking current busy status to guarantee right mode.
+ */
+static int m5mols_reg_mode(struct v4l2_subdev *sd, u32 mode)
+{
+ int ret = m5mols_write(sd, SYSTEM_SYSMODE, mode);
+
+ return ret ? ret : m5mols_busy(sd, CAT_SYSTEM, CAT0_SYSMODE, mode);
+}
+
+/**
+ * m5mols_mode - manage the M-5MOLS's mode
+ * @mode: the required operation mode
+ *
+ * The commands of M-5MOLS are grouped into specific modes. Each functionality
+ * can be guaranteed only when the sensor is operating in mode which which
+ * a command belongs to.
+ */
+int m5mols_mode(struct m5mols_info *info, u32 mode)
+{
+ struct v4l2_subdev *sd = &info->sd;
+ int ret = -EINVAL;
+ u32 reg;
+
+ if (mode < REG_PARAMETER && mode > REG_CAPTURE)
+ return ret;
+
+ ret = m5mols_read(sd, SYSTEM_SYSMODE, &reg);
+ if ((!ret && reg == mode) || ret)
+ return ret;
+
+ switch (reg) {
+ case REG_PARAMETER:
+ ret = m5mols_reg_mode(sd, REG_MONITOR);
+ if (!ret && mode == REG_MONITOR)
+ break;
+ if (!ret)
+ ret = m5mols_reg_mode(sd, REG_CAPTURE);
+ break;
+
+ case REG_MONITOR:
+ if (mode == REG_PARAMETER) {
+ ret = m5mols_reg_mode(sd, REG_PARAMETER);
+ break;
+ }
+
+ ret = m5mols_reg_mode(sd, REG_CAPTURE);
+ break;
+
+ case REG_CAPTURE:
+ ret = m5mols_reg_mode(sd, REG_MONITOR);
+ if (!ret && mode == REG_MONITOR)
+ break;
+ if (!ret)
+ ret = m5mols_reg_mode(sd, REG_PARAMETER);
+ break;
+
+ default:
+ v4l2_warn(sd, "Wrong mode: %d\n", mode);
+ }
+
+ if (!ret)
+ info->mode = mode;
+
+ return ret;
+}
+
+/**
+ * m5mols_get_version - retrieve full revisions information of M-5MOLS
+ *
+ * The version information includes revisions of hardware and firmware,
+ * AutoFocus alghorithm version and the version string.
+ */
+static int m5mols_get_version(struct v4l2_subdev *sd)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+ union {
+ struct m5mols_version ver;
+ u8 bytes[VERSION_SIZE];
+ } version;
+ u32 *value;
+ u8 cmd = CAT0_VER_CUSTOMER;
+ int ret;
+
+ do {
+ value = (u32 *)&version.bytes[cmd];
+ ret = m5mols_read(sd, SYSTEM_CMD(cmd), value);
+ if (ret)
+ return ret;
+ } while (cmd++ != CAT0_VER_AWB);
+
+ do {
+ value = (u32 *)&version.bytes[cmd];
+ ret = m5mols_read(sd, SYSTEM_VER_STRING, value);
+ if (ret)
+ return ret;
+ if (cmd >= VERSION_SIZE - 1)
+ return -EINVAL;
+ } while (version.bytes[cmd++]);
+
+ value = (u32 *)&version.bytes[cmd];
+ ret = m5mols_read(sd, AF_VERSION, value);
+ if (ret)
+ return ret;
+
+ /* store version information swapped for being readable */
+ info->ver = version.ver;
+ info->ver.fw = be16_to_cpu(info->ver.fw);
+ info->ver.hw = be16_to_cpu(info->ver.hw);
+ info->ver.param = be16_to_cpu(info->ver.param);
+ info->ver.awb = be16_to_cpu(info->ver.awb);
+
+ v4l2_info(sd, "Manufacturer\t[%s]\n",
+ is_manufacturer(info, REG_SAMSUNG_ELECTRO) ?
+ "Samsung Electro-Machanics" :
+ is_manufacturer(info, REG_SAMSUNG_OPTICS) ?
+ "Samsung Fiber-Optics" :
+ is_manufacturer(info, REG_SAMSUNG_TECHWIN) ?
+ "Samsung Techwin" : "None");
+ v4l2_info(sd, "Customer/Project\t[0x%02x/0x%02x]\n",
+ info->ver.customer, info->ver.project);
+
+ if (!is_available_af(info))
+ v4l2_info(sd, "No support Auto Focus on this firmware\n");
+
+ return ret;
+}
+
+/**
+ * __find_restype - Lookup M-5MOLS resolution type according to pixel code
+ * @code: pixel code
+ */
+static enum m5mols_restype __find_restype(enum v4l2_mbus_pixelcode code)
+{
+ enum m5mols_restype type = M5MOLS_RESTYPE_MONITOR;
+
+ do {
+ if (code == m5mols_default_ffmt[type].code)
+ return type;
+ } while (type++ != SIZE_DEFAULT_FFMT);
+
+ return 0;
+}
+
+/**
+ * __find_resolution - Lookup preset and type of M-5MOLS's resolution
+ * @mf: pixel format to find/negotiate the resolution preset for
+ * @type: M-5MOLS resolution type
+ * @resolution: M-5MOLS resolution preset register value
+ *
+ * Find nearest resolution matching resolution preset and adjust mf
+ * to supported values.
+ */
+static int __find_resolution(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf,
+ enum m5mols_restype *type,
+ u32 *resolution)
+{
+ const struct m5mols_resolution *fsize = &m5mols_reg_res[0];
+ const struct m5mols_resolution *match = NULL;
+ enum m5mols_restype stype = __find_restype(mf->code);
+ int i = ARRAY_SIZE(m5mols_reg_res);
+ unsigned int min_err = ~0;
+
+ while (i--) {
+ int err;
+ if (stype == fsize->type) {
+ err = abs(fsize->width - mf->width)
+ + abs(fsize->height - mf->height);
+
+ if (err < min_err) {
+ min_err = err;
+ match = fsize;
+ }
+ }
+ fsize++;
+ }
+ if (match) {
+ mf->width = match->width;
+ mf->height = match->height;
+ *resolution = match->reg;
+ *type = stype;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static struct v4l2_mbus_framefmt *__find_format(struct m5mols_info *info,
+ struct v4l2_subdev_fh *fh,
+ enum v4l2_subdev_format_whence which,
+ enum m5mols_restype type)
+{
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return fh ? v4l2_subdev_get_try_format(fh, 0) : NULL;
+
+ return &info->ffmt[type];
+}
+
+static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+ struct v4l2_mbus_framefmt *format;
+
+ if (fmt->pad != 0)
+ return -EINVAL;
+
+ format = __find_format(info, fh, fmt->which, info->res_type);
+ if (!format)
+ return -EINVAL;
+
+ fmt->format = *format;
+ return 0;
+}
+
+static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+ struct v4l2_mbus_framefmt *format = &fmt->format;
+ struct v4l2_mbus_framefmt *sfmt;
+ enum m5mols_restype type;
+ u32 resolution = 0;
+ int ret;
+
+ if (fmt->pad != 0)
+ return -EINVAL;
+
+ ret = __find_resolution(sd, format, &type, &resolution);
+ if (ret < 0)
+ return ret;
+
+ sfmt = __find_format(info, fh, fmt->which, type);
+ if (!sfmt)
+ return 0;
+
+ *sfmt = m5mols_default_ffmt[type];
+ sfmt->width = format->width;
+ sfmt->height = format->height;
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ info->resolution = resolution;
+ info->code = format->code;
+ info->res_type = type;
+ }
+
+ return 0;
+}
+
+static int m5mols_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (!code || code->index >= SIZE_DEFAULT_FFMT)
+ return -EINVAL;
+
+ code->code = m5mols_default_ffmt[code->index].code;
+
+ return 0;
+}
+
+static struct v4l2_subdev_pad_ops m5mols_pad_ops = {
+ .enum_mbus_code = m5mols_enum_mbus_code,
+ .get_fmt = m5mols_get_fmt,
+ .set_fmt = m5mols_set_fmt,
+};
+
+/**
+ * m5mols_sync_controls - Apply default scene mode and the current controls
+ *
+ * This is used only streaming for syncing between v4l2_ctrl framework and
+ * m5mols's controls. First, do the scenemode to the sensor, then call
+ * v4l2_ctrl_handler_setup. It can be same between some commands and
+ * the scenemode's in the default v4l2_ctrls. But, such commands of control
+ * should be prior to the scenemode's one.
+ */
+int m5mols_sync_controls(struct m5mols_info *info)
+{
+ int ret = -EINVAL;
+
+ if (!is_ctrl_synced(info)) {
+ ret = m5mols_do_scenemode(info, REG_SCENE_NORMAL);
+ if (ret)
+ return ret;
+
+ v4l2_ctrl_handler_setup(&info->handle);
+ info->ctrl_sync = true;
+ }
+
+ return ret;
+}
+
+/**
+ * m5mols_start_monitor - Start the monitor mode
+ *
+ * Before applying the controls setup the resolution and frame rate
+ * in PARAMETER mode, and then switch over to MONITOR mode.
+ */
+static int m5mols_start_monitor(struct m5mols_info *info)
+{
+ struct v4l2_subdev *sd = &info->sd;
+ int ret;
+
+ ret = m5mols_mode(info, REG_PARAMETER);
+ if (!ret)
+ ret = m5mols_write(sd, PARM_MON_SIZE, info->resolution);
+ if (!ret)
+ ret = m5mols_write(sd, PARM_MON_FPS, REG_FPS_30);
+ if (!ret)
+ ret = m5mols_mode(info, REG_MONITOR);
+ if (!ret)
+ ret = m5mols_sync_controls(info);
+
+ return ret;
+}
+
+static int m5mols_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+
+ if (enable) {
+ int ret = -EINVAL;
+
+ if (is_code(info->code, M5MOLS_RESTYPE_MONITOR))
+ ret = m5mols_start_monitor(info);
+ if (is_code(info->code, M5MOLS_RESTYPE_CAPTURE))
+ ret = m5mols_start_capture(info);
+
+ return ret;
+ }
+
+ return m5mols_mode(info, REG_PARAMETER);
+}
+
+static const struct v4l2_subdev_video_ops m5mols_video_ops = {
+ .s_stream = m5mols_s_stream,
+};
+
+static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_subdev *sd = to_sd(ctrl);
+ struct m5mols_info *info = to_m5mols(sd);
+ int ret;
+
+ info->mode_save = info->mode;
+
+ ret = m5mols_mode(info, REG_PARAMETER);
+ if (!ret)
+ ret = m5mols_set_ctrl(ctrl);
+ if (!ret)
+ ret = m5mols_mode(info, info->mode_save);
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops m5mols_ctrl_ops = {
+ .s_ctrl = m5mols_s_ctrl,
+};
+
+static int m5mols_sensor_power(struct m5mols_info *info, bool enable)
+{
+ struct v4l2_subdev *sd = &info->sd;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ const struct m5mols_platform_data *pdata = info->pdata;
+ int ret;
+
+ if (enable) {
+ if (is_powered(info))
+ return 0;
+
+ if (info->set_power) {
+ ret = info->set_power(&client->dev, 1);
+ if (ret)
+ return ret;
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
+ if (ret) {
+ info->set_power(&client->dev, 0);
+ return ret;
+ }
+
+ gpio_set_value(pdata->gpio_reset, !pdata->reset_polarity);
+ usleep_range(1000, 1000);
+ info->power = true;
+
+ return ret;
+ }
+
+ if (!is_powered(info))
+ return 0;
+
+ ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
+ if (ret)
+ return ret;
+
+ if (info->set_power)
+ info->set_power(&client->dev, 0);
+
+ gpio_set_value(pdata->gpio_reset, pdata->reset_polarity);
+ usleep_range(1000, 1000);
+ info->power = false;
+
+ return ret;
+}
+
+/* m5mols_update_fw - optional firmware update routine */
+int __attribute__ ((weak)) m5mols_update_fw(struct v4l2_subdev *sd,
+ int (*set_power)(struct m5mols_info *, bool))
+{
+ return 0;
+}
+
+/**
+ * m5mols_sensor_armboot - Booting M-5MOLS internal ARM core.
+ *
+ * Booting internal ARM core makes the M-5MOLS is ready for getting commands
+ * with I2C. It's the first thing to be done after it powered up. It must wait
+ * at least 520ms recommended by M-5MOLS datasheet, after executing arm booting.
+ */
+static int m5mols_sensor_armboot(struct v4l2_subdev *sd)
+{
+ int ret;
+
+ ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT);
+ if (ret < 0)
+ return ret;
+
+ msleep(520);
+
+ ret = m5mols_get_version(sd);
+ if (!ret)
+ ret = m5mols_update_fw(sd, m5mols_sensor_power);
+ if (ret)
+ return ret;
+
+ v4l2_dbg(1, m5mols_debug, sd, "Success ARM Booting\n");
+
+ ret = m5mols_write(sd, PARM_INTERFACE, REG_INTERFACE_MIPI);
+ if (!ret)
+ ret = m5mols_enable_interrupt(sd, REG_INT_AF);
+
+ return ret;
+}
+
+static int m5mols_init_controls(struct m5mols_info *info)
+{
+ struct v4l2_subdev *sd = &info->sd;
+ u16 max_exposure;
+ u16 step_zoom;
+ int ret;
+
+ /* Determine value's range & step of controls for various FW version */
+ ret = m5mols_read(sd, AE_MAX_GAIN_MON, (u32 *)&max_exposure);
+ if (!ret)
+ step_zoom = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1;
+ if (ret)
+ return ret;
+
+ v4l2_ctrl_handler_init(&info->handle, 6);
+ info->autowb = v4l2_ctrl_new_std(&info->handle,
+ &m5mols_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE,
+ 0, 1, 1, 0);
+ info->saturation = v4l2_ctrl_new_std(&info->handle,
+ &m5mols_ctrl_ops, V4L2_CID_SATURATION,
+ 1, 5, 1, 3);
+ info->zoom = v4l2_ctrl_new_std(&info->handle,
+ &m5mols_ctrl_ops, V4L2_CID_ZOOM_ABSOLUTE,
+ 1, 70, step_zoom, 1);
+ info->exposure = v4l2_ctrl_new_std(&info->handle,
+ &m5mols_ctrl_ops, V4L2_CID_EXPOSURE,
+ 0, max_exposure, 1, (int)max_exposure/2);
+ info->colorfx = v4l2_ctrl_new_std_menu(&info->handle,
+ &m5mols_ctrl_ops, V4L2_CID_COLORFX,
+ 4, (1 << V4L2_COLORFX_BW), V4L2_COLORFX_NONE);
+ info->autoexposure = v4l2_ctrl_new_std_menu(&info->handle,
+ &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO,
+ 1, 0, V4L2_EXPOSURE_MANUAL);
+
+ sd->ctrl_handler = &info->handle;
+ if (info->handle.error) {
+ v4l2_err(sd, "Failed to initialize controls: %d\n", ret);
+ v4l2_ctrl_handler_free(&info->handle);
+ return info->handle.error;
+ }
+
+ v4l2_ctrl_cluster(2, &info->autoexposure);
+
+ return 0;
+}
+
+/**
+ * m5mols_s_power - Main sensor power control function
+ *
+ * To prevent breaking the lens when the sensor is powered off the Soft-Landing
+ * algorithm is called where available. The Soft-Landing algorithm availability
+ * dependends on the firmware provider.
+ */
+static int m5mols_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+ int ret;
+
+ if (on) {
+ ret = m5mols_sensor_power(info, true);
+ if (!ret)
+ ret = m5mols_sensor_armboot(sd);
+ if (!ret)
+ ret = m5mols_init_controls(info);
+ if (ret)
+ return ret;
+
+ info->ffmt[M5MOLS_RESTYPE_MONITOR] =
+ m5mols_default_ffmt[M5MOLS_RESTYPE_MONITOR];
+ info->ffmt[M5MOLS_RESTYPE_CAPTURE] =
+ m5mols_default_ffmt[M5MOLS_RESTYPE_CAPTURE];
+ return ret;
+ }
+
+ if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) {
+ ret = m5mols_mode(info, REG_MONITOR);
+ if (!ret)
+ ret = m5mols_write(sd, AF_EXECUTE, REG_AF_STOP);
+ if (!ret)
+ ret = m5mols_write(sd, AF_MODE, REG_AF_POWEROFF);
+ if (!ret)
+ ret = m5mols_busy(sd, CAT_SYSTEM, CAT0_STATUS,
+ REG_AF_IDLE);
+ if (!ret)
+ v4l2_info(sd, "Success soft-landing lens\n");
+ }
+
+ ret = m5mols_sensor_power(info, false);
+ if (!ret) {
+ v4l2_ctrl_handler_free(&info->handle);
+ info->ctrl_sync = false;
+ }
+
+ return ret;
+}
+
+static int m5mols_log_status(struct v4l2_subdev *sd)
+{
+ struct m5mols_info *info = to_m5mols(sd);
+
+ v4l2_ctrl_handler_log_status(&info->handle, sd->name);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_core_ops m5mols_core_ops = {
+ .s_power = m5mols_s_power,
+ .g_ctrl = v4l2_subdev_g_ctrl,
+ .s_ctrl = v4l2_subdev_s_ctrl,
+ .queryctrl = v4l2_subdev_queryctrl,
+ .querymenu = v4l2_subdev_querymenu,
+ .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+ .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+ .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+ .log_status = m5mols_log_status,
+};
+
+static const struct v4l2_subdev_ops m5mols_ops = {
+ .core = &m5mols_core_ops,
+ .pad = &m5mols_pad_ops,
+ .video = &m5mols_video_ops,
+};
+
+static void m5mols_irq_work(struct work_struct *work)
+{
+ struct m5mols_info *info =
+ container_of(work, struct m5mols_info, work_irq);
+ struct v4l2_subdev *sd = &info->sd;
+ u32 reg;
+ int ret;
+
+ if (!is_powered(info) ||
+ m5mols_read(sd, SYSTEM_INT_FACTOR, &info->interrupt))
+ return;
+
+ switch (info->interrupt & REG_INT_MASK) {
+ case REG_INT_AF:
+ if (!is_available_af(info))
+ break;
+ ret = m5mols_read(sd, AF_STATUS, &reg);
+ v4l2_dbg(2, m5mols_debug, sd, "AF %s\n",
+ reg == REG_AF_FAIL ? "Failed" :
+ reg == REG_AF_SUCCESS ? "Success" :
+ reg == REG_AF_IDLE ? "Idle" : "Busy");
+ break;
+ case REG_INT_CAPTURE:
+ if (!test_and_set_bit(ST_CAPT_IRQ, &info->flags))
+ wake_up_interruptible(&info->irq_waitq);
+
+ v4l2_dbg(2, m5mols_debug, sd, "CAPTURE\n");
+ break;
+ default:
+ v4l2_dbg(2, m5mols_debug, sd, "Undefined: %02x\n", reg);
+ break;
+ };
+}
+
+static irqreturn_t m5mols_irq_handler(int irq, void *data)
+{
+ struct v4l2_subdev *sd = data;
+ struct m5mols_info *info = to_m5mols(sd);
+
+ schedule_work(&info->work_irq);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit m5mols_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ const struct m5mols_platform_data *pdata = client->dev.platform_data;
+ struct m5mols_info *info;
+ struct v4l2_subdev *sd;
+ int ret;
+
+ if (pdata == NULL) {
+ dev_err(&client->dev, "No platform data\n");
+ return -EINVAL;
+ }
+
+ if (!gpio_is_valid(pdata->gpio_reset)) {
+ dev_err(&client->dev, "No valid RESET GPIO specified\n");
+ return -EINVAL;
+ }
+
+ if (!pdata->irq) {
+ dev_err(&client->dev, "Interrupt not assigned\n");
+ return -EINVAL;
+ }
+
+ info = kzalloc(sizeof(struct m5mols_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->pdata = pdata;
+ info->set_power = pdata->set_power;
+
+ ret = gpio_request(pdata->gpio_reset, "M5MOLS_NRST");
+ if (ret) {
+ dev_err(&client->dev, "Failed to request gpio: %d\n", ret);
+ goto out_free;
+ }
+ gpio_direction_output(pdata->gpio_reset, pdata->reset_polarity);
+
+ ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(supplies), supplies);
+ if (ret) {
+ dev_err(&client->dev, "Failed to get regulators: %d\n", ret);
+ goto out_gpio;
+ }
+
+ sd = &info->sd;
+ strlcpy(sd->name, MODULE_NAME, sizeof(sd->name));
+ v4l2_i2c_subdev_init(sd, client, &m5mols_ops);
+
+ info->pad.flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_init(&sd->entity, 1, &info->pad, 0);
+ if (ret < 0)
+ goto out_reg;
+ sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
+
+ init_waitqueue_head(&info->irq_waitq);
+ INIT_WORK(&info->work_irq, m5mols_irq_work);
+ ret = request_irq(pdata->irq, m5mols_irq_handler,
+ IRQF_TRIGGER_RISING, MODULE_NAME, sd);
+ if (ret) {
+ dev_err(&client->dev, "Interrupt request failed: %d\n", ret);
+ goto out_me;
+ }
+ info->res_type = M5MOLS_RESTYPE_MONITOR;
+ return 0;
+out_me:
+ media_entity_cleanup(&sd->entity);
+out_reg:
+ regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
+out_gpio:
+ gpio_free(pdata->gpio_reset);
+out_free:
+ kfree(info);
+ return ret;
+}
+
+static int __devexit m5mols_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct m5mols_info *info = to_m5mols(sd);
+
+ v4l2_device_unregister_subdev(sd);
+ free_irq(info->pdata->irq, sd);
+
+ regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
+ gpio_free(info->pdata->gpio_reset);
+ media_entity_cleanup(&sd->entity);
+ kfree(info);
+ return 0;
+}
+
+static const struct i2c_device_id m5mols_id[] = {
+ { MODULE_NAME, 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, m5mols_id);
+
+static struct i2c_driver m5mols_i2c_driver = {
+ .driver = {
+ .name = MODULE_NAME,
+ },
+ .probe = m5mols_probe,
+ .remove = __devexit_p(m5mols_remove),
+ .id_table = m5mols_id,
+};
+
+static int __init m5mols_mod_init(void)
+{
+ return i2c_add_driver(&m5mols_i2c_driver);
+}
+
+static void __exit m5mols_mod_exit(void)
+{
+ i2c_del_driver(&m5mols_i2c_driver);
+}
+
+module_init(m5mols_mod_init);
+module_exit(m5mols_mod_exit);
+
+MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>");
+MODULE_AUTHOR("Dongsoo Kim <dongsoo45.kim@samsung.com>");
+MODULE_DESCRIPTION("Fujitsu M-5MOLS 8M Pixel camera driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/m5mols/m5mols_reg.h b/drivers/media/video/m5mols/m5mols_reg.h
new file mode 100644
index 000000000000..b83e36fc6ac6
--- /dev/null
+++ b/drivers/media/video/m5mols/m5mols_reg.h
@@ -0,0 +1,399 @@
+/*
+ * Register map for M-5MOLS 8M Pixel camera sensor with ISP
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Author: HeungJun Kim, riverful.kim@samsung.com
+ *
+ * Copyright (C) 2009 Samsung Electronics Co., Ltd.
+ * Author: Dongsoo Nathaniel Kim, dongsoo45.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 M5MOLS_REG_H
+#define M5MOLS_REG_H
+
+#define M5MOLS_I2C_MAX_SIZE 4
+#define M5MOLS_BYTE_READ 0x01
+#define M5MOLS_BYTE_WRITE 0x02
+
+#define I2C_CATEGORY(__cat) ((__cat >> 16) & 0xff)
+#define I2C_COMMAND(__comm) ((__comm >> 8) & 0xff)
+#define I2C_SIZE(__reg_s) ((__reg_s) & 0xff)
+#define I2C_REG(__cat, __cmd, __reg_s) ((__cat << 16) | (__cmd << 8) | __reg_s)
+
+/*
+ * Category section register
+ *
+ * The category means set including relevant command of M-5MOLS.
+ */
+#define CAT_SYSTEM 0x00
+#define CAT_PARAM 0x01
+#define CAT_MONITOR 0x02
+#define CAT_AE 0x03
+#define CAT_WB 0x06
+#define CAT_EXIF 0x07
+#define CAT_FD 0x09
+#define CAT_LENS 0x0a
+#define CAT_CAPT_PARM 0x0b
+#define CAT_CAPT_CTRL 0x0c
+#define CAT_FLASH 0x0f /* related to FW, revisions, booting */
+
+/*
+ * Category 0 - SYSTEM mode
+ *
+ * The SYSTEM mode in the M-5MOLS means area available to handle with the whole
+ * & all-round system of sensor. It deals with version/interrupt/setting mode &
+ * even sensor's status. Especially, the M-5MOLS sensor with ISP varies by
+ * packaging & manufacturer, even the customer and project code. And the
+ * function details may vary among them. The version information helps to
+ * determine what methods shall be used in the driver.
+ *
+ * There is many registers between customer version address and awb one. For
+ * more specific contents, see definition if file m5mols.h.
+ */
+#define CAT0_VER_CUSTOMER 0x00 /* customer version */
+#define CAT0_VER_AWB 0x09 /* Auto WB version */
+#define CAT0_VER_STRING 0x0a /* string including M-5MOLS */
+#define CAT0_SYSMODE 0x0b /* SYSTEM mode register */
+#define CAT0_STATUS 0x0c /* SYSTEM mode status register */
+#define CAT0_INT_FACTOR 0x10 /* interrupt pending register */
+#define CAT0_INT_ENABLE 0x11 /* interrupt enable register */
+
+#define SYSTEM_SYSMODE I2C_REG(CAT_SYSTEM, CAT0_SYSMODE, 1)
+#define REG_SYSINIT 0x00 /* SYSTEM mode */
+#define REG_PARAMETER 0x01 /* PARAMETER mode */
+#define REG_MONITOR 0x02 /* MONITOR mode */
+#define REG_CAPTURE 0x03 /* CAPTURE mode */
+
+#define SYSTEM_CMD(__cmd) I2C_REG(CAT_SYSTEM, cmd, 1)
+#define SYSTEM_VER_STRING I2C_REG(CAT_SYSTEM, CAT0_VER_STRING, 1)
+#define REG_SAMSUNG_ELECTRO "SE" /* Samsung Electro-Mechanics */
+#define REG_SAMSUNG_OPTICS "OP" /* Samsung Fiber-Optics */
+#define REG_SAMSUNG_TECHWIN "TB" /* Samsung Techwin */
+
+#define SYSTEM_INT_FACTOR I2C_REG(CAT_SYSTEM, CAT0_INT_FACTOR, 1)
+#define SYSTEM_INT_ENABLE I2C_REG(CAT_SYSTEM, CAT0_INT_ENABLE, 1)
+#define REG_INT_MODE (1 << 0)
+#define REG_INT_AF (1 << 1)
+#define REG_INT_ZOOM (1 << 2)
+#define REG_INT_CAPTURE (1 << 3)
+#define REG_INT_FRAMESYNC (1 << 4)
+#define REG_INT_FD (1 << 5)
+#define REG_INT_LENS_INIT (1 << 6)
+#define REG_INT_SOUND (1 << 7)
+#define REG_INT_MASK 0x0f
+
+/*
+ * category 1 - PARAMETER mode
+ *
+ * This category supports function of camera features of M-5MOLS. It means we
+ * can handle with preview(MONITOR) resolution size/frame per second/interface
+ * between the sensor and the Application Processor/even the image effect.
+ */
+#define CAT1_DATA_INTERFACE 0x00 /* interface between sensor and AP */
+#define CAT1_MONITOR_SIZE 0x01 /* resolution at the MONITOR mode */
+#define CAT1_MONITOR_FPS 0x02 /* frame per second at this mode */
+#define CAT1_EFFECT 0x0b /* image effects */
+
+#define PARM_MON_SIZE I2C_REG(CAT_PARAM, CAT1_MONITOR_SIZE, 1)
+
+#define PARM_MON_FPS I2C_REG(CAT_PARAM, CAT1_MONITOR_FPS, 1)
+#define REG_FPS_30 0x02
+
+#define PARM_INTERFACE I2C_REG(CAT_PARAM, CAT1_DATA_INTERFACE, 1)
+#define REG_INTERFACE_MIPI 0x02
+
+#define PARM_EFFECT I2C_REG(CAT_PARAM, CAT1_EFFECT, 1)
+#define REG_EFFECT_OFF 0x00
+#define REG_EFFECT_NEGA 0x01
+#define REG_EFFECT_EMBOSS 0x06
+#define REG_EFFECT_OUTLINE 0x07
+#define REG_EFFECT_WATERCOLOR 0x08
+
+/*
+ * Category 2 - MONITOR mode
+ *
+ * The MONITOR mode is same as preview mode as we said. The M-5MOLS has another
+ * mode named "Preview", but this preview mode is used at the case specific
+ * vider-recording mode. This mmode supports only YUYV format. On the other
+ * hand, the JPEG & RAW formats is supports by CAPTURE mode. And, there are
+ * another options like zoom/color effect(different with effect in PARAMETER
+ * mode)/anti hand shaking algorithm.
+ */
+#define CAT2_ZOOM 0x01 /* set the zoom position & execute */
+#define CAT2_ZOOM_STEP 0x03 /* set the zoom step */
+#define CAT2_CFIXB 0x09 /* CB value for color effect */
+#define CAT2_CFIXR 0x0a /* CR value for color effect */
+#define CAT2_COLOR_EFFECT 0x0b /* set on/off of color effect */
+#define CAT2_CHROMA_LVL 0x0f /* set chroma level */
+#define CAT2_CHROMA_EN 0x10 /* set on/off of choroma */
+#define CAT2_EDGE_LVL 0x11 /* set sharpness level */
+#define CAT2_EDGE_EN 0x12 /* set on/off sharpness */
+#define CAT2_TONE_CTL 0x25 /* set tone color(contrast) */
+
+#define MON_ZOOM I2C_REG(CAT_MONITOR, CAT2_ZOOM, 1)
+
+#define MON_CFIXR I2C_REG(CAT_MONITOR, CAT2_CFIXR, 1)
+#define MON_CFIXB I2C_REG(CAT_MONITOR, CAT2_CFIXB, 1)
+#define REG_CFIXB_SEPIA 0xd8
+#define REG_CFIXR_SEPIA 0x18
+
+#define MON_EFFECT I2C_REG(CAT_MONITOR, CAT2_COLOR_EFFECT, 1)
+#define REG_COLOR_EFFECT_OFF 0x00
+#define REG_COLOR_EFFECT_ON 0x01
+
+#define MON_CHROMA_EN I2C_REG(CAT_MONITOR, CAT2_CHROMA_EN, 1)
+#define MON_CHROMA_LVL I2C_REG(CAT_MONITOR, CAT2_CHROMA_LVL, 1)
+#define REG_CHROMA_OFF 0x00
+#define REG_CHROMA_ON 0x01
+
+#define MON_EDGE_EN I2C_REG(CAT_MONITOR, CAT2_EDGE_EN, 1)
+#define MON_EDGE_LVL I2C_REG(CAT_MONITOR, CAT2_EDGE_LVL, 1)
+#define REG_EDGE_OFF 0x00
+#define REG_EDGE_ON 0x01
+
+#define MON_TONE_CTL I2C_REG(CAT_MONITOR, CAT2_TONE_CTL, 1)
+
+/*
+ * Category 3 - Auto Exposure
+ *
+ * The M-5MOLS exposure capbility is detailed as which is similar to digital
+ * camera. This category supports AE locking/various AE mode(range of exposure)
+ * /ISO/flickering/EV bias/shutter/meteoring, and anything else. And the
+ * maximum/minimum exposure gain value depending on M-5MOLS firmware, may be
+ * different. So, this category also provide getting the max/min values. And,
+ * each MONITOR and CAPTURE mode has each gain/shutter/max exposure values.
+ */
+#define CAT3_AE_LOCK 0x00 /* locking Auto exposure */
+#define CAT3_AE_MODE 0x01 /* set AE mode, mode means range */
+#define CAT3_ISO 0x05 /* set ISO */
+#define CAT3_EV_PRESET_MONITOR 0x0a /* EV(scenemode) preset for MONITOR */
+#define CAT3_EV_PRESET_CAPTURE 0x0b /* EV(scenemode) preset for CAPTURE */
+#define CAT3_MANUAL_GAIN_MON 0x12 /* meteoring value for the MONITOR */
+#define CAT3_MAX_GAIN_MON 0x1a /* max gain value for the MONITOR */
+#define CAT3_MANUAL_GAIN_CAP 0x26 /* meteoring value for the CAPTURE */
+#define CAT3_AE_INDEX 0x38 /* AE index */
+
+#define AE_LOCK I2C_REG(CAT_AE, CAT3_AE_LOCK, 1)
+#define REG_AE_UNLOCK 0x00
+#define REG_AE_LOCK 0x01
+
+#define AE_MODE I2C_REG(CAT_AE, CAT3_AE_MODE, 1)
+#define REG_AE_OFF 0x00 /* AE off */
+#define REG_AE_ALL 0x01 /* calc AE in all block integral */
+#define REG_AE_CENTER 0x03 /* calc AE in center weighted */
+#define REG_AE_SPOT 0x06 /* calc AE in specific spot */
+
+#define AE_ISO I2C_REG(CAT_AE, CAT3_ISO, 1)
+#define REG_ISO_AUTO 0x00
+#define REG_ISO_50 0x01
+#define REG_ISO_100 0x02
+#define REG_ISO_200 0x03
+#define REG_ISO_400 0x04
+#define REG_ISO_800 0x05
+
+#define AE_EV_PRESET_MONITOR I2C_REG(CAT_AE, CAT3_EV_PRESET_MONITOR, 1)
+#define AE_EV_PRESET_CAPTURE I2C_REG(CAT_AE, CAT3_EV_PRESET_CAPTURE, 1)
+#define REG_SCENE_NORMAL 0x00
+#define REG_SCENE_PORTRAIT 0x01
+#define REG_SCENE_LANDSCAPE 0x02
+#define REG_SCENE_SPORTS 0x03
+#define REG_SCENE_PARTY_INDOOR 0x04
+#define REG_SCENE_BEACH_SNOW 0x05
+#define REG_SCENE_SUNSET 0x06
+#define REG_SCENE_DAWN_DUSK 0x07
+#define REG_SCENE_FALL 0x08
+#define REG_SCENE_NIGHT 0x09
+#define REG_SCENE_AGAINST_LIGHT 0x0a
+#define REG_SCENE_FIRE 0x0b
+#define REG_SCENE_TEXT 0x0c
+#define REG_SCENE_CANDLE 0x0d
+
+#define AE_MAN_GAIN_MON I2C_REG(CAT_AE, CAT3_MANUAL_GAIN_MON, 2)
+#define AE_MAX_GAIN_MON I2C_REG(CAT_AE, CAT3_MAX_GAIN_MON, 2)
+#define AE_MAN_GAIN_CAP I2C_REG(CAT_AE, CAT3_MANUAL_GAIN_CAP, 2)
+
+#define AE_INDEX I2C_REG(CAT_AE, CAT3_AE_INDEX, 1)
+#define REG_AE_INDEX_20_NEG 0x00
+#define REG_AE_INDEX_15_NEG 0x01
+#define REG_AE_INDEX_10_NEG 0x02
+#define REG_AE_INDEX_05_NEG 0x03
+#define REG_AE_INDEX_00 0x04
+#define REG_AE_INDEX_05_POS 0x05
+#define REG_AE_INDEX_10_POS 0x06
+#define REG_AE_INDEX_15_POS 0x07
+#define REG_AE_INDEX_20_POS 0x08
+
+/*
+ * Category 6 - White Balance
+ *
+ * This category provide AWB locking/mode/preset/speed/gain bias, etc.
+ */
+#define CAT6_AWB_LOCK 0x00 /* locking Auto Whitebalance */
+#define CAT6_AWB_MODE 0x02 /* set Auto or Manual */
+#define CAT6_AWB_MANUAL 0x03 /* set Manual(preset) value */
+
+#define AWB_LOCK I2C_REG(CAT_WB, CAT6_AWB_LOCK, 1)
+#define REG_AWB_UNLOCK 0x00
+#define REG_AWB_LOCK 0x01
+
+#define AWB_MODE I2C_REG(CAT_WB, CAT6_AWB_MODE, 1)
+#define REG_AWB_AUTO 0x01 /* AWB off */
+#define REG_AWB_PRESET 0x02 /* AWB preset */
+
+#define AWB_MANUAL I2C_REG(CAT_WB, CAT6_AWB_MANUAL, 1)
+#define REG_AWB_INCANDESCENT 0x01
+#define REG_AWB_FLUORESCENT_1 0x02
+#define REG_AWB_FLUORESCENT_2 0x03
+#define REG_AWB_DAYLIGHT 0x04
+#define REG_AWB_CLOUDY 0x05
+#define REG_AWB_SHADE 0x06
+#define REG_AWB_HORIZON 0x07
+#define REG_AWB_LEDLIGHT 0x09
+
+/*
+ * Category 7 - EXIF information
+ */
+#define CAT7_INFO_EXPTIME_NU 0x00
+#define CAT7_INFO_EXPTIME_DE 0x04
+#define CAT7_INFO_TV_NU 0x08
+#define CAT7_INFO_TV_DE 0x0c
+#define CAT7_INFO_AV_NU 0x10
+#define CAT7_INFO_AV_DE 0x14
+#define CAT7_INFO_BV_NU 0x18
+#define CAT7_INFO_BV_DE 0x1c
+#define CAT7_INFO_EBV_NU 0x20
+#define CAT7_INFO_EBV_DE 0x24
+#define CAT7_INFO_ISO 0x28
+#define CAT7_INFO_FLASH 0x2a
+#define CAT7_INFO_SDR 0x2c
+#define CAT7_INFO_QVAL 0x2e
+
+#define EXIF_INFO_EXPTIME_NU I2C_REG(CAT_EXIF, CAT7_INFO_EXPTIME_NU, 4)
+#define EXIF_INFO_EXPTIME_DE I2C_REG(CAT_EXIF, CAT7_INFO_EXPTIME_DE, 4)
+#define EXIF_INFO_TV_NU I2C_REG(CAT_EXIF, CAT7_INFO_TV_NU, 4)
+#define EXIF_INFO_TV_DE I2C_REG(CAT_EXIF, CAT7_INFO_TV_DE, 4)
+#define EXIF_INFO_AV_NU I2C_REG(CAT_EXIF, CAT7_INFO_AV_NU, 4)
+#define EXIF_INFO_AV_DE I2C_REG(CAT_EXIF, CAT7_INFO_AV_DE, 4)
+#define EXIF_INFO_BV_NU I2C_REG(CAT_EXIF, CAT7_INFO_BV_NU, 4)
+#define EXIF_INFO_BV_DE I2C_REG(CAT_EXIF, CAT7_INFO_BV_DE, 4)
+#define EXIF_INFO_EBV_NU I2C_REG(CAT_EXIF, CAT7_INFO_EBV_NU, 4)
+#define EXIF_INFO_EBV_DE I2C_REG(CAT_EXIF, CAT7_INFO_EBV_DE, 4)
+#define EXIF_INFO_ISO I2C_REG(CAT_EXIF, CAT7_INFO_ISO, 2)
+#define EXIF_INFO_FLASH I2C_REG(CAT_EXIF, CAT7_INFO_FLASH, 2)
+#define EXIF_INFO_SDR I2C_REG(CAT_EXIF, CAT7_INFO_SDR, 2)
+#define EXIF_INFO_QVAL I2C_REG(CAT_EXIF, CAT7_INFO_QVAL, 2)
+
+/*
+ * Category 9 - Face Detection
+ */
+#define CAT9_FD_CTL 0x00
+
+#define FD_CTL I2C_REG(CAT_FD, CAT9_FD_CTL, 1)
+#define BIT_FD_EN 0
+#define BIT_FD_DRAW_FACE_FRAME 4
+#define BIT_FD_DRAW_SMILE_LVL 6
+#define REG_FD(shift) (1 << shift)
+#define REG_FD_OFF 0x0
+
+/*
+ * Category A - Lens Parameter
+ */
+#define CATA_AF_MODE 0x01
+#define CATA_AF_EXECUTE 0x02
+#define CATA_AF_STATUS 0x03
+#define CATA_AF_VERSION 0x0a
+
+#define AF_MODE I2C_REG(CAT_LENS, CATA_AF_MODE, 1)
+#define REG_AF_NORMAL 0x00 /* Normal AF, one time */
+#define REG_AF_MACRO 0x01 /* Macro AF, one time */
+#define REG_AF_POWEROFF 0x07
+
+#define AF_EXECUTE I2C_REG(CAT_LENS, CATA_AF_EXECUTE, 1)
+#define REG_AF_STOP 0x00
+#define REG_AF_EXE_AUTO 0x01
+#define REG_AF_EXE_CAF 0x02
+
+#define AF_STATUS I2C_REG(CAT_LENS, CATA_AF_STATUS, 1)
+#define REG_AF_FAIL 0x00
+#define REG_AF_SUCCESS 0x02
+#define REG_AF_IDLE 0x04
+#define REG_AF_BUSY 0x05
+
+#define AF_VERSION I2C_REG(CAT_LENS, CATA_AF_VERSION, 1)
+
+/*
+ * Category B - CAPTURE Parameter
+ */
+#define CATB_YUVOUT_MAIN 0x00
+#define CATB_MAIN_IMAGE_SIZE 0x01
+#define CATB_MCC_MODE 0x1d
+#define CATB_WDR_EN 0x2c
+#define CATB_LIGHT_CTRL 0x40
+#define CATB_FLASH_CTRL 0x41
+
+#define CAPP_YUVOUT_MAIN I2C_REG(CAT_CAPT_PARM, CATB_YUVOUT_MAIN, 1)
+#define REG_YUV422 0x00
+#define REG_BAYER10 0x05
+#define REG_BAYER8 0x06
+#define REG_JPEG 0x10
+
+#define CAPP_MAIN_IMAGE_SIZE I2C_REG(CAT_CAPT_PARM, CATB_MAIN_IMAGE_SIZE, 1)
+
+#define CAPP_MCC_MODE I2C_REG(CAT_CAPT_PARM, CATB_MCC_MODE, 1)
+#define REG_MCC_OFF 0x00
+#define REG_MCC_NORMAL 0x01
+
+#define CAPP_WDR_EN I2C_REG(CAT_CAPT_PARM, CATB_WDR_EN, 1)
+#define REG_WDR_OFF 0x00
+#define REG_WDR_ON 0x01
+#define REG_WDR_AUTO 0x02
+
+#define CAPP_LIGHT_CTRL I2C_REG(CAT_CAPT_PARM, CATB_LIGHT_CTRL, 1)
+#define REG_LIGHT_OFF 0x00
+#define REG_LIGHT_ON 0x01
+#define REG_LIGHT_AUTO 0x02
+
+#define CAPP_FLASH_CTRL I2C_REG(CAT_CAPT_PARM, CATB_FLASH_CTRL, 1)
+#define REG_FLASH_OFF 0x00
+#define REG_FLASH_ON 0x01
+#define REG_FLASH_AUTO 0x02
+
+/*
+ * Category C - CAPTURE Control
+ */
+#define CATC_CAP_MODE 0x00
+#define CATC_CAP_SEL_FRAME 0x06 /* It determines Single or Multi */
+#define CATC_CAP_START 0x09
+#define CATC_CAP_IMAGE_SIZE 0x0d
+#define CATC_CAP_THUMB_SIZE 0x11
+
+#define CAPC_MODE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_MODE, 1)
+#define REG_CAP_NONE 0x00
+#define REG_CAP_ANTI_SHAKE 0x02
+
+#define CAPC_SEL_FRAME I2C_REG(CAT_CAPT_CTRL, CATC_CAP_SEL_FRAME, 1)
+
+#define CAPC_START I2C_REG(CAT_CAPT_CTRL, CATC_CAP_START, 1)
+#define REG_CAP_START_MAIN 0x01
+#define REG_CAP_START_THUMB 0x03
+
+#define CAPC_IMAGE_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_IMAGE_SIZE, 1)
+#define CAPC_THUMB_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_THUMB_SIZE, 1)
+
+/*
+ * Category F - Flash
+ *
+ * This mode provides functions about internal flash stuff and system startup.
+ */
+#define CATF_CAM_START 0x12 /* It starts internal ARM core booting
+ * after power-up */
+
+#define FLASH_CAM_START I2C_REG(CAT_FLASH, CATF_CAM_START, 1)
+#define REG_START_ARM_BOOT 0x01
+
+#endif /* M5MOLS_REG_H */
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index 8126622fb4f5..de5d481b0328 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -96,7 +96,7 @@ MODULE_PARM_DESC(debug, "Enable debug messages [0-3]");
MODULE_PARM_DESC(stereo_threshold, "Sets signal threshold to activate stereo");
MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Default: Autodetect");
MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan");
-MODULE_PARM_DESC(dolby, "Activates Dolby processsing");
+MODULE_PARM_DESC(dolby, "Activates Dolby processing");
/* ---------------------------------------------------------------------- */
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
index 53fa2a7bf156..ebebed929627 100644
--- a/drivers/media/video/mt9m111.c
+++ b/drivers/media/video/mt9m111.c
@@ -315,10 +315,20 @@ static int mt9m111_setup_rect(struct i2c_client *client,
static int mt9m111_setup_pixfmt(struct i2c_client *client, u16 outfmt)
{
int ret;
+ u16 mask = MT9M111_OUTFMT_PROCESSED_BAYER | MT9M111_OUTFMT_RGB |
+ MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_SWAP_RGB_EVEN |
+ MT9M111_OUTFMT_RGB565 | MT9M111_OUTFMT_RGB555 |
+ MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr |
+ MT9M111_OUTFMT_SWAP_YCbCr_C_Y;
- ret = reg_write(OUTPUT_FORMAT_CTRL2_A, outfmt);
+ ret = reg_read(OUTPUT_FORMAT_CTRL2_A);
+ if (ret >= 0)
+ ret = reg_write(OUTPUT_FORMAT_CTRL2_A, (ret & ~mask) | outfmt);
if (!ret)
- ret = reg_write(OUTPUT_FORMAT_CTRL2_B, outfmt);
+ ret = reg_read(OUTPUT_FORMAT_CTRL2_B);
+ if (ret >= 0)
+ ret = reg_write(OUTPUT_FORMAT_CTRL2_B, (ret & ~mask) | outfmt);
+
return ret;
}
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index e313d8390092..fc76ed1c08e5 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -228,7 +228,7 @@ static int mt9v022_set_bus_param(struct soc_camera_device *icd,
flags = soc_camera_apply_sensor_flags(icl, flags);
- if (flags & SOCAM_PCLK_SAMPLE_RISING)
+ if (flags & SOCAM_PCLK_SAMPLE_FALLING)
pixclk |= 0x10;
if (!(flags & SOCAM_HSYNC_ACTIVE_HIGH))
diff --git a/drivers/media/video/mt9v032.c b/drivers/media/video/mt9v032.c
new file mode 100644
index 000000000000..1319c2c48aff
--- /dev/null
+++ b/drivers/media/video/mt9v032.c
@@ -0,0 +1,773 @@
+/*
+ * Driver for MT9V032 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2010, Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * Based on the MT9M001 driver,
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.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/log2.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-mediabus.h>
+
+#include <media/mt9v032.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#define MT9V032_PIXEL_ARRAY_HEIGHT 492
+#define MT9V032_PIXEL_ARRAY_WIDTH 782
+
+#define MT9V032_CHIP_VERSION 0x00
+#define MT9V032_CHIP_ID_REV1 0x1311
+#define MT9V032_CHIP_ID_REV3 0x1313
+#define MT9V032_ROW_START 0x01
+#define MT9V032_ROW_START_MIN 4
+#define MT9V032_ROW_START_DEF 10
+#define MT9V032_ROW_START_MAX 482
+#define MT9V032_COLUMN_START 0x02
+#define MT9V032_COLUMN_START_MIN 1
+#define MT9V032_COLUMN_START_DEF 2
+#define MT9V032_COLUMN_START_MAX 752
+#define MT9V032_WINDOW_HEIGHT 0x03
+#define MT9V032_WINDOW_HEIGHT_MIN 1
+#define MT9V032_WINDOW_HEIGHT_DEF 480
+#define MT9V032_WINDOW_HEIGHT_MAX 480
+#define MT9V032_WINDOW_WIDTH 0x04
+#define MT9V032_WINDOW_WIDTH_MIN 1
+#define MT9V032_WINDOW_WIDTH_DEF 752
+#define MT9V032_WINDOW_WIDTH_MAX 752
+#define MT9V032_HORIZONTAL_BLANKING 0x05
+#define MT9V032_HORIZONTAL_BLANKING_MIN 43
+#define MT9V032_HORIZONTAL_BLANKING_MAX 1023
+#define MT9V032_VERTICAL_BLANKING 0x06
+#define MT9V032_VERTICAL_BLANKING_MIN 4
+#define MT9V032_VERTICAL_BLANKING_MAX 3000
+#define MT9V032_CHIP_CONTROL 0x07
+#define MT9V032_CHIP_CONTROL_MASTER_MODE (1 << 3)
+#define MT9V032_CHIP_CONTROL_DOUT_ENABLE (1 << 7)
+#define MT9V032_CHIP_CONTROL_SEQUENTIAL (1 << 8)
+#define MT9V032_SHUTTER_WIDTH1 0x08
+#define MT9V032_SHUTTER_WIDTH2 0x09
+#define MT9V032_SHUTTER_WIDTH_CONTROL 0x0a
+#define MT9V032_TOTAL_SHUTTER_WIDTH 0x0b
+#define MT9V032_TOTAL_SHUTTER_WIDTH_MIN 1
+#define MT9V032_TOTAL_SHUTTER_WIDTH_DEF 480
+#define MT9V032_TOTAL_SHUTTER_WIDTH_MAX 32767
+#define MT9V032_RESET 0x0c
+#define MT9V032_READ_MODE 0x0d
+#define MT9V032_READ_MODE_ROW_BIN_MASK (3 << 0)
+#define MT9V032_READ_MODE_ROW_BIN_SHIFT 0
+#define MT9V032_READ_MODE_COLUMN_BIN_MASK (3 << 2)
+#define MT9V032_READ_MODE_COLUMN_BIN_SHIFT 2
+#define MT9V032_READ_MODE_ROW_FLIP (1 << 4)
+#define MT9V032_READ_MODE_COLUMN_FLIP (1 << 5)
+#define MT9V032_READ_MODE_DARK_COLUMNS (1 << 6)
+#define MT9V032_READ_MODE_DARK_ROWS (1 << 7)
+#define MT9V032_PIXEL_OPERATION_MODE 0x0f
+#define MT9V032_PIXEL_OPERATION_MODE_COLOR (1 << 2)
+#define MT9V032_PIXEL_OPERATION_MODE_HDR (1 << 6)
+#define MT9V032_ANALOG_GAIN 0x35
+#define MT9V032_ANALOG_GAIN_MIN 16
+#define MT9V032_ANALOG_GAIN_DEF 16
+#define MT9V032_ANALOG_GAIN_MAX 64
+#define MT9V032_MAX_ANALOG_GAIN 0x36
+#define MT9V032_MAX_ANALOG_GAIN_MAX 127
+#define MT9V032_FRAME_DARK_AVERAGE 0x42
+#define MT9V032_DARK_AVG_THRESH 0x46
+#define MT9V032_DARK_AVG_LOW_THRESH_MASK (255 << 0)
+#define MT9V032_DARK_AVG_LOW_THRESH_SHIFT 0
+#define MT9V032_DARK_AVG_HIGH_THRESH_MASK (255 << 8)
+#define MT9V032_DARK_AVG_HIGH_THRESH_SHIFT 8
+#define MT9V032_ROW_NOISE_CORR_CONTROL 0x70
+#define MT9V032_ROW_NOISE_CORR_ENABLE (1 << 5)
+#define MT9V032_ROW_NOISE_CORR_USE_BLK_AVG (1 << 7)
+#define MT9V032_PIXEL_CLOCK 0x74
+#define MT9V032_PIXEL_CLOCK_INV_LINE (1 << 0)
+#define MT9V032_PIXEL_CLOCK_INV_FRAME (1 << 1)
+#define MT9V032_PIXEL_CLOCK_XOR_LINE (1 << 2)
+#define MT9V032_PIXEL_CLOCK_CONT_LINE (1 << 3)
+#define MT9V032_PIXEL_CLOCK_INV_PXL_CLK (1 << 4)
+#define MT9V032_TEST_PATTERN 0x7f
+#define MT9V032_TEST_PATTERN_DATA_MASK (1023 << 0)
+#define MT9V032_TEST_PATTERN_DATA_SHIFT 0
+#define MT9V032_TEST_PATTERN_USE_DATA (1 << 10)
+#define MT9V032_TEST_PATTERN_GRAY_MASK (3 << 11)
+#define MT9V032_TEST_PATTERN_GRAY_NONE (0 << 11)
+#define MT9V032_TEST_PATTERN_GRAY_VERTICAL (1 << 11)
+#define MT9V032_TEST_PATTERN_GRAY_HORIZONTAL (2 << 11)
+#define MT9V032_TEST_PATTERN_GRAY_DIAGONAL (3 << 11)
+#define MT9V032_TEST_PATTERN_ENABLE (1 << 13)
+#define MT9V032_TEST_PATTERN_FLIP (1 << 14)
+#define MT9V032_AEC_AGC_ENABLE 0xaf
+#define MT9V032_AEC_ENABLE (1 << 0)
+#define MT9V032_AGC_ENABLE (1 << 1)
+#define MT9V032_THERMAL_INFO 0xc1
+
+struct mt9v032 {
+ struct v4l2_subdev subdev;
+ struct media_pad pad;
+
+ struct v4l2_mbus_framefmt format;
+ struct v4l2_rect crop;
+
+ struct v4l2_ctrl_handler ctrls;
+
+ struct mutex power_lock;
+ int power_count;
+
+ struct mt9v032_platform_data *pdata;
+ u16 chip_control;
+ u16 aec_agc;
+};
+
+static struct mt9v032 *to_mt9v032(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct mt9v032, subdev);
+}
+
+static int mt9v032_read(struct i2c_client *client, const u8 reg)
+{
+ s32 data = i2c_smbus_read_word_data(client, reg);
+ dev_dbg(&client->dev, "%s: read 0x%04x from 0x%02x\n", __func__,
+ swab16(data), reg);
+ return data < 0 ? data : swab16(data);
+}
+
+static int mt9v032_write(struct i2c_client *client, const u8 reg,
+ const u16 data)
+{
+ dev_dbg(&client->dev, "%s: writing 0x%04x to 0x%02x\n", __func__,
+ data, reg);
+ return i2c_smbus_write_word_data(client, reg, swab16(data));
+}
+
+static int mt9v032_set_chip_control(struct mt9v032 *mt9v032, u16 clear, u16 set)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+ u16 value = (mt9v032->chip_control & ~clear) | set;
+ int ret;
+
+ ret = mt9v032_write(client, MT9V032_CHIP_CONTROL, value);
+ if (ret < 0)
+ return ret;
+
+ mt9v032->chip_control = value;
+ return 0;
+}
+
+static int
+mt9v032_update_aec_agc(struct mt9v032 *mt9v032, u16 which, int enable)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+ u16 value = mt9v032->aec_agc;
+ int ret;
+
+ if (enable)
+ value |= which;
+ else
+ value &= ~which;
+
+ ret = mt9v032_write(client, MT9V032_AEC_AGC_ENABLE, value);
+ if (ret < 0)
+ return ret;
+
+ mt9v032->aec_agc = value;
+ return 0;
+}
+
+static int mt9v032_power_on(struct mt9v032 *mt9v032)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+ int ret;
+
+ if (mt9v032->pdata->set_clock) {
+ mt9v032->pdata->set_clock(&mt9v032->subdev, 25000000);
+ udelay(1);
+ }
+
+ /* Reset the chip and stop data read out */
+ ret = mt9v032_write(client, MT9V032_RESET, 1);
+ if (ret < 0)
+ return ret;
+
+ ret = mt9v032_write(client, MT9V032_RESET, 0);
+ if (ret < 0)
+ return ret;
+
+ return mt9v032_write(client, MT9V032_CHIP_CONTROL, 0);
+}
+
+static void mt9v032_power_off(struct mt9v032 *mt9v032)
+{
+ if (mt9v032->pdata->set_clock)
+ mt9v032->pdata->set_clock(&mt9v032->subdev, 0);
+}
+
+static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+ int ret;
+
+ if (!on) {
+ mt9v032_power_off(mt9v032);
+ return 0;
+ }
+
+ ret = mt9v032_power_on(mt9v032);
+ if (ret < 0)
+ return ret;
+
+ /* Configure the pixel clock polarity */
+ if (mt9v032->pdata && mt9v032->pdata->clk_pol) {
+ ret = mt9v032_write(client, MT9V032_PIXEL_CLOCK,
+ MT9V032_PIXEL_CLOCK_INV_PXL_CLK);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Disable the noise correction algorithm and restore the controls. */
+ ret = mt9v032_write(client, MT9V032_ROW_NOISE_CORR_CONTROL, 0);
+ if (ret < 0)
+ return ret;
+
+ return v4l2_ctrl_handler_setup(&mt9v032->ctrls);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev video operations
+ */
+
+static struct v4l2_mbus_framefmt *
+__mt9v032_get_pad_format(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_format(fh, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &mt9v032->format;
+ default:
+ return NULL;
+ }
+}
+
+static struct v4l2_rect *
+__mt9v032_get_pad_crop(struct mt9v032 *mt9v032, struct v4l2_subdev_fh *fh,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_get_try_crop(fh, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &mt9v032->crop;
+ default:
+ return NULL;
+ }
+}
+
+static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+ const u16 mode = MT9V032_CHIP_CONTROL_MASTER_MODE
+ | MT9V032_CHIP_CONTROL_DOUT_ENABLE
+ | MT9V032_CHIP_CONTROL_SEQUENTIAL;
+ struct i2c_client *client = v4l2_get_subdevdata(subdev);
+ struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+ struct v4l2_mbus_framefmt *format = &mt9v032->format;
+ struct v4l2_rect *crop = &mt9v032->crop;
+ unsigned int hratio;
+ unsigned int vratio;
+ int ret;
+
+ if (!enable)
+ return mt9v032_set_chip_control(mt9v032, mode, 0);
+
+ /* Configure the window size and row/column bin */
+ hratio = DIV_ROUND_CLOSEST(crop->width, format->width);
+ vratio = DIV_ROUND_CLOSEST(crop->height, format->height);
+
+ ret = mt9v032_write(client, MT9V032_READ_MODE,
+ (hratio - 1) << MT9V032_READ_MODE_ROW_BIN_SHIFT |
+ (vratio - 1) << MT9V032_READ_MODE_COLUMN_BIN_SHIFT);
+ if (ret < 0)
+ return ret;
+
+ ret = mt9v032_write(client, MT9V032_COLUMN_START, crop->left);
+ if (ret < 0)
+ return ret;
+
+ ret = mt9v032_write(client, MT9V032_ROW_START, crop->top);
+ if (ret < 0)
+ return ret;
+
+ ret = mt9v032_write(client, MT9V032_WINDOW_WIDTH, crop->width);
+ if (ret < 0)
+ return ret;
+
+ ret = mt9v032_write(client, MT9V032_WINDOW_HEIGHT, crop->height);
+ if (ret < 0)
+ return ret;
+
+ ret = mt9v032_write(client, MT9V032_HORIZONTAL_BLANKING,
+ max(43, 660 - crop->width));
+ if (ret < 0)
+ return ret;
+
+ /* Switch to master "normal" mode */
+ return mt9v032_set_chip_control(mt9v032, 0, mode);
+}
+
+static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index > 0)
+ return -EINVAL;
+
+ code->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ return 0;
+}
+
+static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ if (fse->index >= 8 || fse->code != V4L2_MBUS_FMT_SGRBG10_1X10)
+ return -EINVAL;
+
+ fse->min_width = MT9V032_WINDOW_WIDTH_DEF / fse->index;
+ fse->max_width = fse->min_width;
+ fse->min_height = MT9V032_WINDOW_HEIGHT_DEF / fse->index;
+ fse->max_height = fse->min_height;
+
+ return 0;
+}
+
+static int mt9v032_get_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *format)
+{
+ struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+
+ format->format = *__mt9v032_get_pad_format(mt9v032, fh, format->pad,
+ format->which);
+ return 0;
+}
+
+static int mt9v032_set_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *format)
+{
+ struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+ struct v4l2_mbus_framefmt *__format;
+ struct v4l2_rect *__crop;
+ unsigned int width;
+ unsigned int height;
+ unsigned int hratio;
+ unsigned int vratio;
+
+ __crop = __mt9v032_get_pad_crop(mt9v032, fh, format->pad,
+ format->which);
+
+ /* Clamp the width and height to avoid dividing by zero. */
+ width = clamp_t(unsigned int, ALIGN(format->format.width, 2),
+ max(__crop->width / 8, MT9V032_WINDOW_WIDTH_MIN),
+ __crop->width);
+ height = clamp_t(unsigned int, ALIGN(format->format.height, 2),
+ max(__crop->height / 8, MT9V032_WINDOW_HEIGHT_MIN),
+ __crop->height);
+
+ hratio = DIV_ROUND_CLOSEST(__crop->width, width);
+ vratio = DIV_ROUND_CLOSEST(__crop->height, height);
+
+ __format = __mt9v032_get_pad_format(mt9v032, fh, format->pad,
+ format->which);
+ __format->width = __crop->width / hratio;
+ __format->height = __crop->height / vratio;
+
+ format->format = *__format;
+
+ return 0;
+}
+
+static int mt9v032_get_crop(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+
+ crop->rect = *__mt9v032_get_pad_crop(mt9v032, fh, crop->pad,
+ crop->which);
+ return 0;
+}
+
+static int mt9v032_set_crop(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_crop *crop)
+{
+ struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+ struct v4l2_mbus_framefmt *__format;
+ struct v4l2_rect *__crop;
+ struct v4l2_rect rect;
+
+ /* Clamp the crop rectangle boundaries and align them to a multiple of 2
+ * pixels.
+ */
+ rect.left = clamp(ALIGN(crop->rect.left, 2),
+ MT9V032_COLUMN_START_MIN,
+ MT9V032_COLUMN_START_MAX);
+ rect.top = clamp(ALIGN(crop->rect.top, 2),
+ MT9V032_ROW_START_MIN,
+ MT9V032_ROW_START_MAX);
+ rect.width = clamp(ALIGN(crop->rect.width, 2),
+ MT9V032_WINDOW_WIDTH_MIN,
+ MT9V032_WINDOW_WIDTH_MAX);
+ rect.height = clamp(ALIGN(crop->rect.height, 2),
+ MT9V032_WINDOW_HEIGHT_MIN,
+ MT9V032_WINDOW_HEIGHT_MAX);
+
+ rect.width = min(rect.width, MT9V032_PIXEL_ARRAY_WIDTH - rect.left);
+ rect.height = min(rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top);
+
+ __crop = __mt9v032_get_pad_crop(mt9v032, fh, crop->pad, crop->which);
+
+ if (rect.width != __crop->width || rect.height != __crop->height) {
+ /* Reset the output image size if the crop rectangle size has
+ * been modified.
+ */
+ __format = __mt9v032_get_pad_format(mt9v032, fh, crop->pad,
+ crop->which);
+ __format->width = rect.width;
+ __format->height = rect.height;
+ }
+
+ *__crop = rect;
+ crop->rect = rect;
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev control operations
+ */
+
+#define V4L2_CID_TEST_PATTERN (V4L2_CID_USER_BASE | 0x1001)
+
+static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct mt9v032 *mt9v032 =
+ container_of(ctrl->handler, struct mt9v032, ctrls);
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+ u16 data;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUTOGAIN:
+ return mt9v032_update_aec_agc(mt9v032, MT9V032_AGC_ENABLE,
+ ctrl->val);
+
+ case V4L2_CID_GAIN:
+ return mt9v032_write(client, MT9V032_ANALOG_GAIN, ctrl->val);
+
+ case V4L2_CID_EXPOSURE_AUTO:
+ return mt9v032_update_aec_agc(mt9v032, MT9V032_AEC_ENABLE,
+ ctrl->val);
+
+ case V4L2_CID_EXPOSURE:
+ return mt9v032_write(client, MT9V032_TOTAL_SHUTTER_WIDTH,
+ ctrl->val);
+
+ case V4L2_CID_TEST_PATTERN:
+ switch (ctrl->val) {
+ case 0:
+ data = 0;
+ break;
+ case 1:
+ data = MT9V032_TEST_PATTERN_GRAY_VERTICAL
+ | MT9V032_TEST_PATTERN_ENABLE;
+ break;
+ case 2:
+ data = MT9V032_TEST_PATTERN_GRAY_HORIZONTAL
+ | MT9V032_TEST_PATTERN_ENABLE;
+ break;
+ case 3:
+ data = MT9V032_TEST_PATTERN_GRAY_DIAGONAL
+ | MT9V032_TEST_PATTERN_ENABLE;
+ break;
+ default:
+ data = (ctrl->val << MT9V032_TEST_PATTERN_DATA_SHIFT)
+ | MT9V032_TEST_PATTERN_USE_DATA
+ | MT9V032_TEST_PATTERN_ENABLE
+ | MT9V032_TEST_PATTERN_FLIP;
+ break;
+ }
+
+ return mt9v032_write(client, MT9V032_TEST_PATTERN, data);
+ }
+
+ return 0;
+}
+
+static struct v4l2_ctrl_ops mt9v032_ctrl_ops = {
+ .s_ctrl = mt9v032_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config mt9v032_ctrls[] = {
+ {
+ .ops = &mt9v032_ctrl_ops,
+ .id = V4L2_CID_TEST_PATTERN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Test pattern",
+ .min = 0,
+ .max = 1023,
+ .step = 1,
+ .def = 0,
+ .flags = 0,
+ }
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev core operations
+ */
+
+static int mt9v032_set_power(struct v4l2_subdev *subdev, int on)
+{
+ struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+ int ret = 0;
+
+ mutex_lock(&mt9v032->power_lock);
+
+ /* If the power count is modified from 0 to != 0 or from != 0 to 0,
+ * update the power state.
+ */
+ if (mt9v032->power_count == !on) {
+ ret = __mt9v032_set_power(mt9v032, !!on);
+ if (ret < 0)
+ goto done;
+ }
+
+ /* Update the power count. */
+ mt9v032->power_count += on ? 1 : -1;
+ WARN_ON(mt9v032->power_count < 0);
+
+done:
+ mutex_unlock(&mt9v032->power_lock);
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev internal operations
+ */
+
+static int mt9v032_registered(struct v4l2_subdev *subdev)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(subdev);
+ struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+ s32 data;
+ int ret;
+
+ dev_info(&client->dev, "Probing MT9V032 at address 0x%02x\n",
+ client->addr);
+
+ ret = mt9v032_power_on(mt9v032);
+ if (ret < 0) {
+ dev_err(&client->dev, "MT9V032 power up failed\n");
+ return ret;
+ }
+
+ /* Read and check the sensor version */
+ data = mt9v032_read(client, MT9V032_CHIP_VERSION);
+ if (data != MT9V032_CHIP_ID_REV1 && data != MT9V032_CHIP_ID_REV3) {
+ dev_err(&client->dev, "MT9V032 not detected, wrong version "
+ "0x%04x\n", data);
+ return -ENODEV;
+ }
+
+ mt9v032_power_off(mt9v032);
+
+ dev_info(&client->dev, "MT9V032 detected at address 0x%02x\n",
+ client->addr);
+
+ return ret;
+}
+
+static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ struct v4l2_mbus_framefmt *format;
+ struct v4l2_rect *crop;
+
+ crop = v4l2_subdev_get_try_crop(fh, 0);
+ crop->left = MT9V032_COLUMN_START_DEF;
+ crop->top = MT9V032_ROW_START_DEF;
+ crop->width = MT9V032_WINDOW_WIDTH_DEF;
+ crop->height = MT9V032_WINDOW_HEIGHT_DEF;
+
+ format = v4l2_subdev_get_try_format(fh, 0);
+ format->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ format->width = MT9V032_WINDOW_WIDTH_DEF;
+ format->height = MT9V032_WINDOW_HEIGHT_DEF;
+ format->field = V4L2_FIELD_NONE;
+ format->colorspace = V4L2_COLORSPACE_SRGB;
+
+ return mt9v032_set_power(subdev, 1);
+}
+
+static int mt9v032_close(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
+{
+ return mt9v032_set_power(subdev, 0);
+}
+
+static struct v4l2_subdev_core_ops mt9v032_subdev_core_ops = {
+ .s_power = mt9v032_set_power,
+};
+
+static struct v4l2_subdev_video_ops mt9v032_subdev_video_ops = {
+ .s_stream = mt9v032_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops mt9v032_subdev_pad_ops = {
+ .enum_mbus_code = mt9v032_enum_mbus_code,
+ .enum_frame_size = mt9v032_enum_frame_size,
+ .get_fmt = mt9v032_get_format,
+ .set_fmt = mt9v032_set_format,
+ .get_crop = mt9v032_get_crop,
+ .set_crop = mt9v032_set_crop,
+};
+
+static struct v4l2_subdev_ops mt9v032_subdev_ops = {
+ .core = &mt9v032_subdev_core_ops,
+ .video = &mt9v032_subdev_video_ops,
+ .pad = &mt9v032_subdev_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops mt9v032_subdev_internal_ops = {
+ .registered = mt9v032_registered,
+ .open = mt9v032_open,
+ .close = mt9v032_close,
+};
+
+/* -----------------------------------------------------------------------------
+ * Driver initialization and probing
+ */
+
+static int mt9v032_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct mt9v032 *mt9v032;
+ unsigned int i;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WORD_DATA)) {
+ dev_warn(&client->adapter->dev,
+ "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+ return -EIO;
+ }
+
+ mt9v032 = kzalloc(sizeof(*mt9v032), GFP_KERNEL);
+ if (!mt9v032)
+ return -ENOMEM;
+
+ mutex_init(&mt9v032->power_lock);
+ mt9v032->pdata = client->dev.platform_data;
+
+ v4l2_ctrl_handler_init(&mt9v032->ctrls, ARRAY_SIZE(mt9v032_ctrls) + 4);
+
+ v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
+ V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+ v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
+ V4L2_CID_GAIN, MT9V032_ANALOG_GAIN_MIN,
+ MT9V032_ANALOG_GAIN_MAX, 1, MT9V032_ANALOG_GAIN_DEF);
+ v4l2_ctrl_new_std_menu(&mt9v032->ctrls, &mt9v032_ctrl_ops,
+ V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL, 0,
+ V4L2_EXPOSURE_AUTO);
+ v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
+ V4L2_CID_EXPOSURE, MT9V032_TOTAL_SHUTTER_WIDTH_MIN,
+ MT9V032_TOTAL_SHUTTER_WIDTH_MAX, 1,
+ MT9V032_TOTAL_SHUTTER_WIDTH_DEF);
+
+ for (i = 0; i < ARRAY_SIZE(mt9v032_ctrls); ++i)
+ v4l2_ctrl_new_custom(&mt9v032->ctrls, &mt9v032_ctrls[i], NULL);
+
+ mt9v032->subdev.ctrl_handler = &mt9v032->ctrls;
+
+ if (mt9v032->ctrls.error)
+ printk(KERN_INFO "%s: control initialization error %d\n",
+ __func__, mt9v032->ctrls.error);
+
+ mt9v032->crop.left = MT9V032_COLUMN_START_DEF;
+ mt9v032->crop.top = MT9V032_ROW_START_DEF;
+ mt9v032->crop.width = MT9V032_WINDOW_WIDTH_DEF;
+ mt9v032->crop.height = MT9V032_WINDOW_HEIGHT_DEF;
+
+ mt9v032->format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ mt9v032->format.width = MT9V032_WINDOW_WIDTH_DEF;
+ mt9v032->format.height = MT9V032_WINDOW_HEIGHT_DEF;
+ mt9v032->format.field = V4L2_FIELD_NONE;
+ mt9v032->format.colorspace = V4L2_COLORSPACE_SRGB;
+
+ mt9v032->aec_agc = MT9V032_AEC_ENABLE | MT9V032_AGC_ENABLE;
+
+ v4l2_i2c_subdev_init(&mt9v032->subdev, client, &mt9v032_subdev_ops);
+ mt9v032->subdev.internal_ops = &mt9v032_subdev_internal_ops;
+ mt9v032->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+ mt9v032->pad.flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_init(&mt9v032->subdev.entity, 1, &mt9v032->pad, 0);
+ if (ret < 0)
+ kfree(mt9v032);
+
+ return ret;
+}
+
+static int mt9v032_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+
+ v4l2_device_unregister_subdev(subdev);
+ media_entity_cleanup(&subdev->entity);
+ kfree(mt9v032);
+ return 0;
+}
+
+static const struct i2c_device_id mt9v032_id[] = {
+ { "mt9v032", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9v032_id);
+
+static struct i2c_driver mt9v032_driver = {
+ .driver = {
+ .name = "mt9v032",
+ },
+ .probe = mt9v032_probe,
+ .remove = mt9v032_remove,
+ .id_table = mt9v032_id,
+};
+
+static int __init mt9v032_init(void)
+{
+ return i2c_add_driver(&mt9v032_driver);
+}
+
+static void __exit mt9v032_exit(void)
+{
+ i2c_del_driver(&mt9v032_driver);
+}
+
+module_init(mt9v032_init);
+module_exit(mt9v032_exit);
+
+MODULE_DESCRIPTION("Aptina MT9V032 Camera driver");
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c
index 502e2a40964c..c7680eb83664 100644
--- a/drivers/media/video/mx3_camera.c
+++ b/drivers/media/video/mx3_camera.c
@@ -400,6 +400,35 @@ static int mx3_videobuf_init(struct vb2_buffer *vb)
return 0;
}
+static int mx3_stop_streaming(struct vb2_queue *q)
+{
+ struct soc_camera_device *icd = soc_camera_from_vb2q(q);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct mx3_camera_dev *mx3_cam = ici->priv;
+ struct idmac_channel *ichan = mx3_cam->idmac_channel[0];
+ struct dma_chan *chan;
+ struct mx3_camera_buffer *buf, *tmp;
+ unsigned long flags;
+
+ if (ichan) {
+ chan = &ichan->dma_chan;
+ chan->device->device_control(chan, DMA_TERMINATE_ALL, 0);
+ }
+
+ spin_lock_irqsave(&mx3_cam->lock, flags);
+
+ mx3_cam->active = NULL;
+
+ list_for_each_entry_safe(buf, tmp, &mx3_cam->capture, queue) {
+ buf->state = CSI_BUF_NEEDS_INIT;
+ list_del_init(&buf->queue);
+ }
+
+ spin_unlock_irqrestore(&mx3_cam->lock, flags);
+
+ return 0;
+}
+
static struct vb2_ops mx3_videobuf_ops = {
.queue_setup = mx3_videobuf_setup,
.buf_prepare = mx3_videobuf_prepare,
@@ -408,6 +437,7 @@ static struct vb2_ops mx3_videobuf_ops = {
.buf_init = mx3_videobuf_init,
.wait_prepare = soc_camera_unlock,
.wait_finish = soc_camera_lock,
+ .stop_streaming = mx3_stop_streaming,
};
static int mx3_camera_init_videobuf(struct vb2_queue *q,
@@ -658,8 +688,8 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id
fmt = soc_mbus_get_fmtdesc(code);
if (!fmt) {
- dev_err(icd->dev.parent,
- "Invalid format code #%u: %d\n", idx, code);
+ dev_warn(icd->dev.parent,
+ "Unsupported format code #%u: %d\n", idx, code);
return 0;
}
@@ -712,13 +742,9 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id
static void configure_geometry(struct mx3_camera_dev *mx3_cam,
unsigned int width, unsigned int height,
- enum v4l2_mbus_pixelcode code)
+ const struct soc_mbus_pixelfmt *fmt)
{
u32 ctrl, width_field, height_field;
- const struct soc_mbus_pixelfmt *fmt;
-
- fmt = soc_mbus_get_fmtdesc(code);
- BUG_ON(!fmt);
if (fourcc_to_ipu_pix(fmt->fourcc) == IPU_PIX_FMT_GENERIC) {
/*
@@ -726,8 +752,10 @@ static void configure_geometry(struct mx3_camera_dev *mx3_cam,
* the width parameter count the number of samples to
* capture to complete the whole image width.
*/
- width *= soc_mbus_samples_per_pixel(fmt);
- BUG_ON(width < 0);
+ unsigned int num, den;
+ int ret = soc_mbus_samples_per_pixel(fmt, &num, &den);
+ BUG_ON(ret < 0);
+ width = width * num / den;
}
/* Setup frame size - this cannot be changed on-the-fly... */
@@ -774,8 +802,8 @@ static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam)
*/
static inline void stride_align(__u32 *width)
{
- if (((*width + 7) & ~7) < 4096)
- *width = (*width + 7) & ~7;
+ if (ALIGN(*width, 8) < 4096)
+ *width = ALIGN(*width, 8);
else
*width = *width & ~7;
}
@@ -801,11 +829,14 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd,
if (ret < 0)
return ret;
- /* The capture device might have changed its output */
+ /* The capture device might have changed its output sizes */
ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
if (ret < 0)
return ret;
+ if (mf.code != icd->current_fmt->code)
+ return -EINVAL;
+
if (mf.width & 7) {
/* Ouch! We can only handle 8-byte aligned width... */
stride_align(&mf.width);
@@ -815,7 +846,8 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd,
}
if (mf.width != icd->user_width || mf.height != icd->user_height)
- configure_geometry(mx3_cam, mf.width, mf.height, mf.code);
+ configure_geometry(mx3_cam, mf.width, mf.height,
+ icd->current_fmt->host_fmt);
dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n",
mf.width, mf.height);
@@ -853,7 +885,7 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd,
* mxc_v4l2_s_fmt()
*/
- configure_geometry(mx3_cam, pix->width, pix->height, xlate->code);
+ configure_geometry(mx3_cam, pix->width, pix->height, xlate->host_fmt);
mf.width = pix->width;
mf.height = pix->height;
diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c
index d4fe7bc92a1d..4ada9be1d430 100644
--- a/drivers/media/video/omap/omap_vout.c
+++ b/drivers/media/video/omap/omap_vout.c
@@ -47,7 +47,7 @@
#include <plat/dma.h>
#include <plat/vram.h>
#include <plat/vrfb.h>
-#include <plat/display.h>
+#include <video/omapdss.h>
#include "omap_voutlib.h"
#include "omap_voutdef.h"
diff --git a/drivers/media/video/omap/omap_voutdef.h b/drivers/media/video/omap/omap_voutdef.h
index ea3a047f8bca..659497b84996 100644
--- a/drivers/media/video/omap/omap_voutdef.h
+++ b/drivers/media/video/omap/omap_voutdef.h
@@ -11,7 +11,7 @@
#ifndef OMAP_VOUTDEF_H
#define OMAP_VOUTDEF_H
-#include <plat/display.h>
+#include <video/omapdss.h>
#define YUYV_BPP 2
#define RGB565_BPP 2
diff --git a/drivers/media/video/omap1_camera.c b/drivers/media/video/omap1_camera.c
index 5954b9306630..e7cfc85b0a1c 100644
--- a/drivers/media/video/omap1_camera.c
+++ b/drivers/media/video/omap1_camera.c
@@ -990,63 +990,80 @@ static void omap1_cam_remove_device(struct soc_camera_device *icd)
}
/* Duplicate standard formats based on host capability of byte swapping */
-static const struct soc_mbus_pixelfmt omap1_cam_formats[] = {
- [V4L2_MBUS_FMT_UYVY8_2X8] = {
+static const struct soc_mbus_lookup omap1_cam_formats[] = {
+{
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_YUYV,
.name = "YUYV",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
},
- [V4L2_MBUS_FMT_VYUY8_2X8] = {
+}, {
+ .code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_YVYU,
.name = "YVYU",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
},
- [V4L2_MBUS_FMT_YUYV8_2X8] = {
+}, {
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_UYVY,
.name = "UYVY",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
},
- [V4L2_MBUS_FMT_YVYU8_2X8] = {
+}, {
+ .code = V4L2_MBUS_FMT_YVYU8_2X8,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_VYUY,
.name = "VYUY",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
},
- [V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE] = {
+}, {
+ .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_RGB555,
.name = "RGB555",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
},
- [V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE] = {
+}, {
+ .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_RGB555X,
.name = "RGB555X",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
},
- [V4L2_MBUS_FMT_RGB565_2X8_BE] = {
+}, {
+ .code = V4L2_MBUS_FMT_RGB565_2X8_BE,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_RGB565,
.name = "RGB565",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
},
- [V4L2_MBUS_FMT_RGB565_2X8_LE] = {
+}, {
+ .code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_RGB565X,
.name = "RGB565X",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
},
+},
};
static int omap1_cam_get_formats(struct soc_camera_device *icd,
@@ -1065,7 +1082,7 @@ static int omap1_cam_get_formats(struct soc_camera_device *icd,
fmt = soc_mbus_get_fmtdesc(code);
if (!fmt) {
- dev_err(dev, "%s: invalid format code #%d: %d\n", __func__,
+ dev_warn(dev, "%s: unsupported format code #%d: %d\n", __func__,
idx, code);
return 0;
}
@@ -1085,12 +1102,14 @@ static int omap1_cam_get_formats(struct soc_camera_device *icd,
case V4L2_MBUS_FMT_RGB565_2X8_LE:
formats++;
if (xlate) {
- xlate->host_fmt = &omap1_cam_formats[code];
+ xlate->host_fmt = soc_mbus_find_fmtdesc(code,
+ omap1_cam_formats,
+ ARRAY_SIZE(omap1_cam_formats));
xlate->code = code;
xlate++;
dev_dbg(dev,
"%s: providing format %s as byte swapped code #%d\n",
- __func__, omap1_cam_formats[code].name, code);
+ __func__, xlate->host_fmt->name, code);
}
default:
if (xlate)
diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c
index ca9f83a85ca5..453627b07833 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-std.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-std.c
@@ -278,12 +278,10 @@ static struct v4l2_standard generic_standards[] = {
}
};
-#define generic_standards_cnt ARRAY_SIZE(generic_standards)
-
static struct v4l2_standard *match_std(v4l2_std_id id)
{
unsigned int idx;
- for (idx = 0; idx < generic_standards_cnt; idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(generic_standards); idx++) {
if (generic_standards[idx].id & id) {
return generic_standards + idx;
}
@@ -370,7 +368,11 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
stddefs = kzalloc(sizeof(struct v4l2_standard) * std_cnt,
GFP_KERNEL);
- for (idx = 0; idx < std_cnt; idx++) stddefs[idx].index = idx;
+ if (!stddefs)
+ return NULL;
+
+ for (idx = 0; idx < std_cnt; idx++)
+ stddefs[idx].index = idx;
idx = 0;
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index 780af5f81642..356cd42b593b 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -1850,7 +1850,6 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
} else {
/* Device is closed, so we can safely unregister it */
PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n");
- pwc_cleanup(pdev);
disconnect_out:
/* search device_hint[] table if we occupy a slot, by any chance */
@@ -1860,6 +1859,7 @@ disconnect_out:
}
mutex_unlock(&pdev->modlock);
+ pwc_cleanup(pdev);
}
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c
index aa87e462a958..f85c51249c7b 100644
--- a/drivers/media/video/pwc/pwc-v4l.c
+++ b/drivers/media/video/pwc/pwc-v4l.c
@@ -379,8 +379,27 @@ static int pwc_s_input(struct file *file, void *fh, unsigned int i)
static int pwc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c)
{
- int i;
-
+ int i, idx;
+ u32 id;
+
+ id = c->id;
+ if (id & V4L2_CTRL_FLAG_NEXT_CTRL) {
+ id &= V4L2_CTRL_ID_MASK;
+ id++;
+ idx = -1;
+ for (i = 0; i < ARRAY_SIZE(pwc_controls); i++) {
+ if (pwc_controls[i].id < id)
+ continue;
+ if (idx >= 0
+ && pwc_controls[i].id > pwc_controls[idx].id)
+ continue;
+ idx = i;
+ }
+ if (idx < 0)
+ return -EINVAL;
+ memcpy(c, &pwc_controls[idx], sizeof pwc_controls[0]);
+ return 0;
+ }
for (i = 0; i < sizeof(pwc_controls) / sizeof(struct v4l2_queryctrl); i++) {
if (pwc_controls[i].id == c->id) {
PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index c1ee09a043ba..b42bfa5ccdf2 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -1155,15 +1155,11 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct pxa_camera_dev *pcdev = ici->priv;
unsigned long bus_flags, camera_flags, common_flags;
- const struct soc_mbus_pixelfmt *fmt;
int ret;
struct pxa_cam *cam = icd->host_priv;
- fmt = soc_mbus_get_fmtdesc(icd->current_fmt->code);
- if (!fmt)
- return -EINVAL;
-
- ret = test_platform_param(pcdev, fmt->bits_per_sample, &bus_flags);
+ ret = test_platform_param(pcdev, icd->current_fmt->host_fmt->bits_per_sample,
+ &bus_flags);
if (ret < 0)
return ret;
diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c
index 561909b65ce6..5b9dce85645c 100644
--- a/drivers/media/video/s2255drv.c
+++ b/drivers/media/video/s2255drv.c
@@ -394,12 +394,17 @@ static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
/* start video number */
static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
+/* Enable jpeg capture. */
+static int jpeg_enable = 1;
+
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Debug level(0-100) default 0");
module_param(vid_limit, int, 0644);
MODULE_PARM_DESC(vid_limit, "video memory limit(Mb)");
module_param(video_nr, int, 0644);
MODULE_PARM_DESC(video_nr, "start video minor(-1 default autodetect)");
+module_param(jpeg_enable, int, 0644);
+MODULE_PARM_DESC(jpeg_enable, "Jpeg enable(1-on 0-off) default 1");
/* USB device table */
#define USB_SENSORAY_VID 0x1943
@@ -413,6 +418,7 @@ MODULE_DEVICE_TABLE(usb, s2255_table);
#define BUFFER_TIMEOUT msecs_to_jiffies(400)
/* image formats. */
+/* JPEG formats must be defined last to support jpeg_enable parameter */
static const struct s2255_fmt formats[] = {
{
.name = "4:2:2, planar, YUV422P",
@@ -429,13 +435,17 @@ static const struct s2255_fmt formats[] = {
.fourcc = V4L2_PIX_FMT_UYVY,
.depth = 16
}, {
+ .name = "8bpp GREY",
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .depth = 8
+ }, {
.name = "JPG",
.fourcc = V4L2_PIX_FMT_JPEG,
.depth = 24
}, {
- .name = "8bpp GREY",
- .fourcc = V4L2_PIX_FMT_GREY,
- .depth = 8
+ .name = "MJPG",
+ .fourcc = V4L2_PIX_FMT_MJPEG,
+ .depth = 24
}
};
@@ -610,6 +620,9 @@ static const struct s2255_fmt *format_by_fourcc(int fourcc)
for (i = 0; i < ARRAY_SIZE(formats); i++) {
if (-1 == formats[i].fourcc)
continue;
+ if (!jpeg_enable && ((formats[i].fourcc == V4L2_PIX_FMT_JPEG) ||
+ (formats[i].fourcc == V4L2_PIX_FMT_MJPEG)))
+ continue;
if (formats[i].fourcc == fourcc)
return formats + i;
}
@@ -653,6 +666,7 @@ static void s2255_fillbuff(struct s2255_channel *channel,
memcpy(vbuf, tmpbuf, buf->vb.width * buf->vb.height);
break;
case V4L2_PIX_FMT_JPEG:
+ case V4L2_PIX_FMT_MJPEG:
buf->vb.size = jpgsize;
memcpy(vbuf, tmpbuf, buf->vb.size);
break;
@@ -856,7 +870,9 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
if (index >= ARRAY_SIZE(formats))
return -EINVAL;
-
+ if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) ||
+ (formats[index].fourcc == V4L2_PIX_FMT_MJPEG)))
+ return -EINVAL;
dprintk(4, "name %s\n", formats[index].name);
strlcpy(f->description, formats[index].name, sizeof(f->description));
f->pixelformat = formats[index].fourcc;
@@ -1037,6 +1053,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
mode.color |= COLOR_Y8;
break;
case V4L2_PIX_FMT_JPEG:
+ case V4L2_PIX_FMT_MJPEG:
mode.color &= ~MASK_COLOR;
mode.color |= COLOR_JPG;
mode.color |= (channel->jc.quality << 8);
@@ -2382,7 +2399,7 @@ static void read_pipe_completion(struct urb *purb)
read_pipe_completion, pipe_info);
if (pipe_info->state != 0) {
- if (usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL)) {
+ if (usb_submit_urb(pipe_info->stream_urb, GFP_ATOMIC)) {
dev_err(&dev->udev->dev, "error submitting urb\n");
}
} else {
diff --git a/drivers/media/video/s5p-fimc/Makefile b/drivers/media/video/s5p-fimc/Makefile
index 7ea1b1403b1e..df6954ab1d99 100644
--- a/drivers/media/video/s5p-fimc/Makefile
+++ b/drivers/media/video/s5p-fimc/Makefile
@@ -1,3 +1,5 @@
+s5p-fimc-objs := fimc-core.o fimc-reg.o fimc-capture.o
+s5p-csis-objs := mipi-csis.o
-obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) := s5p-fimc.o
-s5p-fimc-y := fimc-core.o fimc-reg.o fimc-capture.o
+obj-$(CONFIG_VIDEO_S5P_MIPI_CSIS) += s5p-csis.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc.o
diff --git a/drivers/media/video/s5p-fimc/mipi-csis.c b/drivers/media/video/s5p-fimc/mipi-csis.c
new file mode 100644
index 000000000000..ef056d6605ca
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/mipi-csis.c
@@ -0,0 +1,724 @@
+/*
+ * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ * Contact: Sylwester Nawrocki, <s.nawrocki@samsung.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/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/memory.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-subdev.h>
+#include <plat/mipi_csis.h>
+#include "mipi-csis.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+/* Register map definition */
+
+/* CSIS global control */
+#define S5PCSIS_CTRL 0x00
+#define S5PCSIS_CTRL_DPDN_DEFAULT (0 << 31)
+#define S5PCSIS_CTRL_DPDN_SWAP (1 << 31)
+#define S5PCSIS_CTRL_ALIGN_32BIT (1 << 20)
+#define S5PCSIS_CTRL_UPDATE_SHADOW (1 << 16)
+#define S5PCSIS_CTRL_WCLK_EXTCLK (1 << 8)
+#define S5PCSIS_CTRL_RESET (1 << 4)
+#define S5PCSIS_CTRL_ENABLE (1 << 0)
+
+/* D-PHY control */
+#define S5PCSIS_DPHYCTRL 0x04
+#define S5PCSIS_DPHYCTRL_HSS_MASK (0x1f << 27)
+#define S5PCSIS_DPHYCTRL_ENABLE (0x1f << 0)
+
+#define S5PCSIS_CONFIG 0x08
+#define S5PCSIS_CFG_FMT_YCBCR422_8BIT (0x1e << 2)
+#define S5PCSIS_CFG_FMT_RAW8 (0x2a << 2)
+#define S5PCSIS_CFG_FMT_RAW10 (0x2b << 2)
+#define S5PCSIS_CFG_FMT_RAW12 (0x2c << 2)
+/* User defined formats, x = 1...4 */
+#define S5PCSIS_CFG_FMT_USER(x) ((0x30 + x - 1) << 2)
+#define S5PCSIS_CFG_FMT_MASK (0x3f << 2)
+#define S5PCSIS_CFG_NR_LANE_MASK 3
+
+/* Interrupt mask. */
+#define S5PCSIS_INTMSK 0x10
+#define S5PCSIS_INTMSK_EN_ALL 0xf000003f
+#define S5PCSIS_INTSRC 0x14
+
+/* Pixel resolution */
+#define S5PCSIS_RESOL 0x2c
+#define CSIS_MAX_PIX_WIDTH 0xffff
+#define CSIS_MAX_PIX_HEIGHT 0xffff
+
+enum {
+ CSIS_CLK_MUX,
+ CSIS_CLK_GATE,
+};
+
+static char *csi_clock_name[] = {
+ [CSIS_CLK_MUX] = "sclk_csis",
+ [CSIS_CLK_GATE] = "csis",
+};
+#define NUM_CSIS_CLOCKS ARRAY_SIZE(csi_clock_name)
+
+enum {
+ ST_POWERED = 1,
+ ST_STREAMING = 2,
+ ST_SUSPENDED = 4,
+};
+
+/**
+ * struct csis_state - the driver's internal state data structure
+ * @lock: mutex serializing the subdev and power management operations,
+ * protecting @format and @flags members
+ * @pads: CSIS pads array
+ * @sd: v4l2_subdev associated with CSIS device instance
+ * @pdev: CSIS platform device
+ * @regs_res: requested I/O register memory resource
+ * @regs: mmaped I/O registers memory
+ * @clock: CSIS clocks
+ * @irq: requested s5p-mipi-csis irq number
+ * @flags: the state variable for power and streaming control
+ * @csis_fmt: current CSIS pixel format
+ * @format: common media bus format for the source and sink pad
+ */
+struct csis_state {
+ struct mutex lock;
+ struct media_pad pads[CSIS_PADS_NUM];
+ struct v4l2_subdev sd;
+ struct platform_device *pdev;
+ struct resource *regs_res;
+ void __iomem *regs;
+ struct clk *clock[NUM_CSIS_CLOCKS];
+ int irq;
+ struct regulator *supply;
+ u32 flags;
+ const struct csis_pix_format *csis_fmt;
+ struct v4l2_mbus_framefmt format;
+};
+
+/**
+ * struct csis_pix_format - CSIS pixel format description
+ * @pix_width_alignment: horizontal pixel alignment, width will be
+ * multiple of 2^pix_width_alignment
+ * @code: corresponding media bus code
+ * @fmt_reg: S5PCSIS_CONFIG register value
+ */
+struct csis_pix_format {
+ unsigned int pix_width_alignment;
+ enum v4l2_mbus_pixelcode code;
+ u32 fmt_reg;
+};
+
+static const struct csis_pix_format s5pcsis_formats[] = {
+ {
+ .code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .fmt_reg = S5PCSIS_CFG_FMT_YCBCR422_8BIT,
+ }, {
+ .code = V4L2_MBUS_FMT_JPEG_1X8,
+ .fmt_reg = S5PCSIS_CFG_FMT_USER(1),
+ },
+};
+
+#define s5pcsis_write(__csis, __r, __v) writel(__v, __csis->regs + __r)
+#define s5pcsis_read(__csis, __r) readl(__csis->regs + __r)
+
+static struct csis_state *sd_to_csis_state(struct v4l2_subdev *sdev)
+{
+ return container_of(sdev, struct csis_state, sd);
+}
+
+static const struct csis_pix_format *find_csis_format(
+ struct v4l2_mbus_framefmt *mf)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(s5pcsis_formats); i++)
+ if (mf->code == s5pcsis_formats[i].code)
+ return &s5pcsis_formats[i];
+ return NULL;
+}
+
+static void s5pcsis_enable_interrupts(struct csis_state *state, bool on)
+{
+ u32 val = s5pcsis_read(state, S5PCSIS_INTMSK);
+
+ val = on ? val | S5PCSIS_INTMSK_EN_ALL :
+ val & ~S5PCSIS_INTMSK_EN_ALL;
+ s5pcsis_write(state, S5PCSIS_INTMSK, val);
+}
+
+static void s5pcsis_reset(struct csis_state *state)
+{
+ u32 val = s5pcsis_read(state, S5PCSIS_CTRL);
+
+ s5pcsis_write(state, S5PCSIS_CTRL, val | S5PCSIS_CTRL_RESET);
+ udelay(10);
+}
+
+static void s5pcsis_system_enable(struct csis_state *state, int on)
+{
+ u32 val;
+
+ val = s5pcsis_read(state, S5PCSIS_CTRL);
+ if (on)
+ val |= S5PCSIS_CTRL_ENABLE;
+ else
+ val &= ~S5PCSIS_CTRL_ENABLE;
+ s5pcsis_write(state, S5PCSIS_CTRL, val);
+
+ val = s5pcsis_read(state, S5PCSIS_DPHYCTRL);
+ if (on)
+ val |= S5PCSIS_DPHYCTRL_ENABLE;
+ else
+ val &= ~S5PCSIS_DPHYCTRL_ENABLE;
+ s5pcsis_write(state, S5PCSIS_DPHYCTRL, val);
+}
+
+/* Called with the state.lock mutex held */
+static void __s5pcsis_set_format(struct csis_state *state)
+{
+ struct v4l2_mbus_framefmt *mf = &state->format;
+ u32 val;
+
+ v4l2_dbg(1, debug, &state->sd, "fmt: %d, %d x %d\n",
+ mf->code, mf->width, mf->height);
+
+ /* Color format */
+ val = s5pcsis_read(state, S5PCSIS_CONFIG);
+ val = (val & ~S5PCSIS_CFG_FMT_MASK) | state->csis_fmt->fmt_reg;
+ s5pcsis_write(state, S5PCSIS_CONFIG, val);
+
+ /* Pixel resolution */
+ val = (mf->width << 16) | mf->height;
+ s5pcsis_write(state, S5PCSIS_RESOL, val);
+}
+
+static void s5pcsis_set_hsync_settle(struct csis_state *state, int settle)
+{
+ u32 val = s5pcsis_read(state, S5PCSIS_DPHYCTRL);
+
+ val = (val & ~S5PCSIS_DPHYCTRL_HSS_MASK) | (settle << 27);
+ s5pcsis_write(state, S5PCSIS_DPHYCTRL, val);
+}
+
+static void s5pcsis_set_params(struct csis_state *state)
+{
+ struct s5p_platform_mipi_csis *pdata = state->pdev->dev.platform_data;
+ u32 val;
+
+ val = s5pcsis_read(state, S5PCSIS_CONFIG);
+ val = (val & ~S5PCSIS_CFG_NR_LANE_MASK) | (pdata->lanes - 1);
+ s5pcsis_write(state, S5PCSIS_CONFIG, val);
+
+ __s5pcsis_set_format(state);
+ s5pcsis_set_hsync_settle(state, pdata->hs_settle);
+
+ val = s5pcsis_read(state, S5PCSIS_CTRL);
+ if (pdata->alignment == 32)
+ val |= S5PCSIS_CTRL_ALIGN_32BIT;
+ else /* 24-bits */
+ val &= ~S5PCSIS_CTRL_ALIGN_32BIT;
+ /* Not using external clock. */
+ val &= ~S5PCSIS_CTRL_WCLK_EXTCLK;
+ s5pcsis_write(state, S5PCSIS_CTRL, val);
+
+ /* Update the shadow register. */
+ val = s5pcsis_read(state, S5PCSIS_CTRL);
+ s5pcsis_write(state, S5PCSIS_CTRL, val | S5PCSIS_CTRL_UPDATE_SHADOW);
+}
+
+static void s5pcsis_clk_put(struct csis_state *state)
+{
+ int i;
+
+ for (i = 0; i < NUM_CSIS_CLOCKS; i++)
+ if (!IS_ERR_OR_NULL(state->clock[i]))
+ clk_put(state->clock[i]);
+}
+
+static int s5pcsis_clk_get(struct csis_state *state)
+{
+ struct device *dev = &state->pdev->dev;
+ int i;
+
+ for (i = 0; i < NUM_CSIS_CLOCKS; i++) {
+ state->clock[i] = clk_get(dev, csi_clock_name[i]);
+ if (IS_ERR(state->clock[i])) {
+ s5pcsis_clk_put(state);
+ dev_err(dev, "failed to get clock: %s\n",
+ csi_clock_name[i]);
+ return -ENXIO;
+ }
+ }
+ return 0;
+}
+
+static int s5pcsis_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct csis_state *state = sd_to_csis_state(sd);
+ struct device *dev = &state->pdev->dev;
+
+ if (on)
+ return pm_runtime_get_sync(dev);
+
+ return pm_runtime_put_sync(dev);
+}
+
+static void s5pcsis_start_stream(struct csis_state *state)
+{
+ s5pcsis_reset(state);
+ s5pcsis_set_params(state);
+ s5pcsis_system_enable(state, true);
+ s5pcsis_enable_interrupts(state, true);
+}
+
+static void s5pcsis_stop_stream(struct csis_state *state)
+{
+ s5pcsis_enable_interrupts(state, false);
+ s5pcsis_system_enable(state, false);
+}
+
+/* v4l2_subdev operations */
+static int s5pcsis_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct csis_state *state = sd_to_csis_state(sd);
+ int ret = 0;
+
+ v4l2_dbg(1, debug, sd, "%s: %d, state: 0x%x\n",
+ __func__, enable, state->flags);
+
+ if (enable) {
+ ret = pm_runtime_get_sync(&state->pdev->dev);
+ if (ret && ret != 1)
+ return ret;
+ }
+ mutex_lock(&state->lock);
+ if (enable) {
+ if (state->flags & ST_SUSPENDED) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+ s5pcsis_start_stream(state);
+ state->flags |= ST_STREAMING;
+ } else {
+ s5pcsis_stop_stream(state);
+ state->flags &= ~ST_STREAMING;
+ }
+unlock:
+ mutex_unlock(&state->lock);
+ if (!enable)
+ pm_runtime_put(&state->pdev->dev);
+
+ return ret == 1 ? 0 : ret;
+}
+
+static int s5pcsis_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index >= ARRAY_SIZE(s5pcsis_formats))
+ return -EINVAL;
+
+ code->code = s5pcsis_formats[code->index].code;
+ return 0;
+}
+
+static struct csis_pix_format const *s5pcsis_try_format(
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct csis_pix_format const *csis_fmt;
+
+ csis_fmt = find_csis_format(mf);
+ if (csis_fmt == NULL)
+ csis_fmt = &s5pcsis_formats[0];
+
+ mf->code = csis_fmt->code;
+ v4l_bound_align_image(&mf->width, 1, CSIS_MAX_PIX_WIDTH,
+ csis_fmt->pix_width_alignment,
+ &mf->height, 1, CSIS_MAX_PIX_HEIGHT, 1,
+ 0);
+ return csis_fmt;
+}
+
+static struct v4l2_mbus_framefmt *__s5pcsis_get_format(
+ struct csis_state *state, struct v4l2_subdev_fh *fh,
+ u32 pad, enum v4l2_subdev_format_whence which)
+{
+ if (which == V4L2_SUBDEV_FORMAT_TRY)
+ return fh ? v4l2_subdev_get_try_format(fh, pad) : NULL;
+
+ return &state->format;
+}
+
+static int s5pcsis_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct csis_state *state = sd_to_csis_state(sd);
+ struct csis_pix_format const *csis_fmt;
+ struct v4l2_mbus_framefmt *mf;
+
+ if (fmt->pad != CSIS_PAD_SOURCE && fmt->pad != CSIS_PAD_SINK)
+ return -EINVAL;
+
+ mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which);
+
+ if (fmt->pad == CSIS_PAD_SOURCE) {
+ if (mf) {
+ mutex_lock(&state->lock);
+ fmt->format = *mf;
+ mutex_unlock(&state->lock);
+ }
+ return 0;
+ }
+ csis_fmt = s5pcsis_try_format(&fmt->format);
+ if (mf) {
+ mutex_lock(&state->lock);
+ *mf = fmt->format;
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ state->csis_fmt = csis_fmt;
+ mutex_unlock(&state->lock);
+ }
+ return 0;
+}
+
+static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct csis_state *state = sd_to_csis_state(sd);
+ struct v4l2_mbus_framefmt *mf;
+
+ if (fmt->pad != CSIS_PAD_SOURCE && fmt->pad != CSIS_PAD_SINK)
+ return -EINVAL;
+
+ mf = __s5pcsis_get_format(state, fh, fmt->pad, fmt->which);
+ if (!mf)
+ return -EINVAL;
+
+ mutex_lock(&state->lock);
+ fmt->format = *mf;
+ mutex_unlock(&state->lock);
+ return 0;
+}
+
+static struct v4l2_subdev_core_ops s5pcsis_core_ops = {
+ .s_power = s5pcsis_s_power,
+};
+
+static struct v4l2_subdev_pad_ops s5pcsis_pad_ops = {
+ .enum_mbus_code = s5pcsis_enum_mbus_code,
+ .get_fmt = s5pcsis_get_fmt,
+ .set_fmt = s5pcsis_set_fmt,
+};
+
+static struct v4l2_subdev_video_ops s5pcsis_video_ops = {
+ .s_stream = s5pcsis_s_stream,
+};
+
+static struct v4l2_subdev_ops s5pcsis_subdev_ops = {
+ .core = &s5pcsis_core_ops,
+ .pad = &s5pcsis_pad_ops,
+ .video = &s5pcsis_video_ops,
+};
+
+static irqreturn_t s5pcsis_irq_handler(int irq, void *dev_id)
+{
+ struct csis_state *state = dev_id;
+ u32 val;
+
+ /* Just clear the interrupt pending bits. */
+ val = s5pcsis_read(state, S5PCSIS_INTSRC);
+ s5pcsis_write(state, S5PCSIS_INTSRC, val);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit s5pcsis_probe(struct platform_device *pdev)
+{
+ struct s5p_platform_mipi_csis *pdata;
+ struct resource *mem_res;
+ struct resource *regs_res;
+ struct csis_state *state;
+ int ret = -ENOMEM;
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
+
+ mutex_init(&state->lock);
+ state->pdev = pdev;
+
+ pdata = pdev->dev.platform_data;
+ if (pdata == NULL || pdata->phy_enable == NULL) {
+ dev_err(&pdev->dev, "Platform data not fully specified\n");
+ goto e_free;
+ }
+
+ if ((pdev->id == 1 && pdata->lanes > CSIS1_MAX_LANES) ||
+ pdata->lanes > CSIS0_MAX_LANES) {
+ ret = -EINVAL;
+ dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n",
+ pdata->lanes);
+ goto e_free;
+ }
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem_res) {
+ dev_err(&pdev->dev, "Failed to get IO memory region\n");
+ goto e_free;
+ }
+
+ regs_res = request_mem_region(mem_res->start, resource_size(mem_res),
+ pdev->name);
+ if (!regs_res) {
+ dev_err(&pdev->dev, "Failed to request IO memory region\n");
+ goto e_free;
+ }
+ state->regs_res = regs_res;
+
+ state->regs = ioremap(mem_res->start, resource_size(mem_res));
+ if (!state->regs) {
+ dev_err(&pdev->dev, "Failed to remap IO region\n");
+ goto e_reqmem;
+ }
+
+ ret = s5pcsis_clk_get(state);
+ if (ret)
+ goto e_unmap;
+
+ clk_enable(state->clock[CSIS_CLK_MUX]);
+ if (pdata->clk_rate)
+ clk_set_rate(state->clock[CSIS_CLK_MUX], pdata->clk_rate);
+ else
+ dev_WARN(&pdev->dev, "No clock frequency specified!\n");
+
+ state->irq = platform_get_irq(pdev, 0);
+ if (state->irq < 0) {
+ ret = state->irq;
+ dev_err(&pdev->dev, "Failed to get irq\n");
+ goto e_clkput;
+ }
+
+ if (!pdata->fixed_phy_vdd) {
+ state->supply = regulator_get(&pdev->dev, "vdd");
+ if (IS_ERR(state->supply)) {
+ ret = PTR_ERR(state->supply);
+ state->supply = NULL;
+ goto e_clkput;
+ }
+ }
+
+ ret = request_irq(state->irq, s5pcsis_irq_handler, 0,
+ dev_name(&pdev->dev), state);
+ if (ret) {
+ dev_err(&pdev->dev, "request_irq failed\n");
+ goto e_regput;
+ }
+
+ v4l2_subdev_init(&state->sd, &s5pcsis_subdev_ops);
+ state->sd.owner = THIS_MODULE;
+ strlcpy(state->sd.name, dev_name(&pdev->dev), sizeof(state->sd.name));
+ state->csis_fmt = &s5pcsis_formats[0];
+
+ state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+ ret = media_entity_init(&state->sd.entity,
+ CSIS_PADS_NUM, state->pads, 0);
+ if (ret < 0)
+ goto e_irqfree;
+
+ /* This allows to retrieve the platform device id by the host driver */
+ v4l2_set_subdevdata(&state->sd, pdev);
+
+ /* .. and a pointer to the subdev. */
+ platform_set_drvdata(pdev, &state->sd);
+
+ state->flags = ST_SUSPENDED;
+ pm_runtime_enable(&pdev->dev);
+
+ return 0;
+
+e_irqfree:
+ free_irq(state->irq, state);
+e_regput:
+ if (state->supply)
+ regulator_put(state->supply);
+e_clkput:
+ clk_disable(state->clock[CSIS_CLK_MUX]);
+ s5pcsis_clk_put(state);
+e_unmap:
+ iounmap(state->regs);
+e_reqmem:
+ release_mem_region(regs_res->start, resource_size(regs_res));
+e_free:
+ kfree(state);
+ return ret;
+}
+
+static int s5pcsis_suspend(struct device *dev)
+{
+ struct s5p_platform_mipi_csis *pdata = dev->platform_data;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+ struct csis_state *state = sd_to_csis_state(sd);
+ int ret = 0;
+
+ v4l2_dbg(1, debug, sd, "%s: flags: 0x%x\n",
+ __func__, state->flags);
+
+ mutex_lock(&state->lock);
+ if (state->flags & ST_POWERED) {
+ s5pcsis_stop_stream(state);
+ ret = pdata->phy_enable(state->pdev, false);
+ if (ret)
+ goto unlock;
+ if (state->supply) {
+ ret = regulator_disable(state->supply);
+ if (ret)
+ goto unlock;
+ }
+ clk_disable(state->clock[CSIS_CLK_GATE]);
+ state->flags &= ~ST_POWERED;
+ }
+ state->flags |= ST_SUSPENDED;
+ unlock:
+ mutex_unlock(&state->lock);
+ return ret ? -EAGAIN : 0;
+}
+
+static int s5pcsis_resume(struct device *dev)
+{
+ struct s5p_platform_mipi_csis *pdata = dev->platform_data;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+ struct csis_state *state = sd_to_csis_state(sd);
+ int ret = 0;
+
+ v4l2_dbg(1, debug, sd, "%s: flags: 0x%x\n",
+ __func__, state->flags);
+
+ mutex_lock(&state->lock);
+ if (!(state->flags & ST_SUSPENDED))
+ goto unlock;
+
+ if (!(state->flags & ST_POWERED)) {
+ if (state->supply)
+ ret = regulator_enable(state->supply);
+ if (ret)
+ goto unlock;
+
+ ret = pdata->phy_enable(state->pdev, true);
+ if (!ret) {
+ state->flags |= ST_POWERED;
+ } else if (state->supply) {
+ regulator_disable(state->supply);
+ goto unlock;
+ }
+ clk_enable(state->clock[CSIS_CLK_GATE]);
+ }
+ if (state->flags & ST_STREAMING)
+ s5pcsis_start_stream(state);
+
+ state->flags &= ~ST_SUSPENDED;
+ unlock:
+ mutex_unlock(&state->lock);
+ return ret ? -EAGAIN : 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int s5pcsis_pm_suspend(struct device *dev)
+{
+ return s5pcsis_suspend(dev);
+}
+
+static int s5pcsis_pm_resume(struct device *dev)
+{
+ int ret;
+
+ ret = s5pcsis_resume(dev);
+
+ if (!ret) {
+ pm_runtime_disable(dev);
+ ret = pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ }
+
+ return ret;
+}
+#endif
+
+static int __devexit s5pcsis_remove(struct platform_device *pdev)
+{
+ struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+ struct csis_state *state = sd_to_csis_state(sd);
+ struct resource *res = state->regs_res;
+
+ pm_runtime_disable(&pdev->dev);
+ s5pcsis_suspend(&pdev->dev);
+ clk_disable(state->clock[CSIS_CLK_MUX]);
+ pm_runtime_set_suspended(&pdev->dev);
+
+ s5pcsis_clk_put(state);
+ if (state->supply)
+ regulator_put(state->supply);
+
+ media_entity_cleanup(&state->sd.entity);
+ free_irq(state->irq, state);
+ iounmap(state->regs);
+ release_mem_region(res->start, resource_size(res));
+ kfree(state);
+
+ return 0;
+}
+
+static const struct dev_pm_ops s5pcsis_pm_ops = {
+ SET_RUNTIME_PM_OPS(s5pcsis_suspend, s5pcsis_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(s5pcsis_pm_suspend, s5pcsis_pm_resume)
+};
+
+static struct platform_driver s5pcsis_driver = {
+ .probe = s5pcsis_probe,
+ .remove = __devexit_p(s5pcsis_remove),
+ .driver = {
+ .name = CSIS_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .pm = &s5pcsis_pm_ops,
+ },
+};
+
+static int __init s5pcsis_init(void)
+{
+ return platform_driver_probe(&s5pcsis_driver, s5pcsis_probe);
+}
+
+static void __exit s5pcsis_exit(void)
+{
+ platform_driver_unregister(&s5pcsis_driver);
+}
+
+module_init(s5pcsis_init);
+module_exit(s5pcsis_exit);
+
+MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
+MODULE_DESCRIPTION("S5P/EXYNOS4 MIPI CSI receiver driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/s5p-fimc/mipi-csis.h b/drivers/media/video/s5p-fimc/mipi-csis.h
new file mode 100644
index 000000000000..f5691336dd5c
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/mipi-csis.h
@@ -0,0 +1,22 @@
+/*
+ * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver
+ *
+ * Copyright (C) 2011 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef S5P_MIPI_CSIS_H_
+#define S5P_MIPI_CSIS_H_
+
+#define CSIS_DRIVER_NAME "s5p-mipi-csis"
+#define CSIS_MAX_ENTITIES 2
+#define CSIS0_MAX_LANES 4
+#define CSIS1_MAX_LANES 2
+
+#define CSIS_PAD_SINK 0
+#define CSIS_PAD_SOURCE 1
+#define CSIS_PADS_NUM 2
+
+#endif
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 50f1be05ebd3..e2062b240e32 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -5591,6 +5591,105 @@ struct saa7134_board saa7134_boards[] = {
.amux = TV,
},
},
+ [SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2] = {
+ /* Timothy Lee <timothy.lee@siriushk.com> */
+ .name = "MagicPro ProHDTV Pro2 DMB-TH/Hybrid",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_config = 3,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x02050000,
+ .mpeg = SAA7134_MPEG_DVB,
+ .ts_type = SAA7134_MPEG_TS_PARALLEL,
+ .inputs = { {
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ .gpio = 0x00050000,
+ }, {
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x00050000,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x00050000,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = TV,
+ .gpio = 0x00050000,
+ },
+ .mute = {
+ .name = name_mute,
+ .vmux = 0,
+ .amux = TV,
+ .gpio = 0x00050000,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_501] = {
+ /* Beholder Intl. Ltd. 2010 */
+ /* Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV 501",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x00008000,
+ .inputs = { {
+ .name = name_tv,
+ .vmux = 3,
+ .amux = LINE2,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .mute = {
+ .name = name_mute,
+ .amux = LINE1,
+ },
+ },
+ [SAA7134_BOARD_BEHOLD_503FM] = {
+ /* Beholder Intl. Ltd. 2010 */
+ /* Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV 503 FM",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x00008000,
+ .inputs = { {
+ .name = name_tv,
+ .vmux = 3,
+ .amux = LINE2,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .mute = {
+ .name = name_mute,
+ .amux = LINE1,
+ },
+ },
};
@@ -6796,6 +6895,24 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0xc900,
.driver_data = SAA7134_BOARD_VIDEOMATE_M1F,
}, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace,
+ .subdevice = 0x5030,
+ .driver_data = SAA7134_BOARD_BEHOLD_503FM,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x5ace,
+ .subdevice = 0x5010,
+ .driver_data = SAA7134_BOARD_BEHOLD_501,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x17de,
+ .subdevice = 0xd136,
+ .driver_data = SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2,
+ }, {
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -6988,6 +7105,7 @@ static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev,
switch (dev->board) {
case SAA7134_BOARD_HAUPPAUGE_HVR1150:
case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+ case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2:
ret = saa7134_tda18271_hvr11x0_toggle_agc(dev, arg);
break;
case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
@@ -7014,6 +7132,7 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev,
case SAA7134_BOARD_HAUPPAUGE_HVR1120:
case SAA7134_BOARD_AVERMEDIA_M733A:
case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
+ case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2:
/* tda8290 + tda18271 */
ret = saa7134_tda8290_18271_callback(dev, command, arg);
break;
@@ -7264,6 +7383,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
break;
case SAA7134_BOARD_HAUPPAUGE_HVR1150:
case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+ dev->has_remote = SAA7134_REMOTE_GPIO;
/* GPIO 26 high for digital, low for analog */
saa7134_set_gpio(dev, 26, 0);
msleep(1);
@@ -7326,6 +7446,11 @@ int saa7134_board_init1(struct saa7134_dev *dev)
saa7134_set_gpio(dev, 1, 1);
dev->has_remote = SAA7134_REMOTE_GPIO;
break;
+ case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2:
+ /* enable LGS-8G75 */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x0e050000, 0x0c050000);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0e050000, 0x0c050000);
+ break;
}
return 0;
}
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 41f836fc93ec..f9be737ba6f4 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -927,7 +927,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
}
/* print pci info */
- pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
+ dev->pci_rev = pci_dev->revision;
pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, "
"latency: %d, mmio: 0x%llx\n", dev->name,
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index f65cad287b83..996a206c6d79 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -53,6 +53,7 @@
#include "lgdt3305.h"
#include "tda8290.h"
#include "mb86a20s.h"
+#include "lgs8gxx.h"
#include "zl10353.h"
@@ -1123,6 +1124,26 @@ static struct tda18271_config dtv1000s_tda18271_config = {
.gate = TDA18271_GATE_ANALOG,
};
+static struct lgs8gxx_config prohdtv_pro2_lgs8g75_config = {
+ .prod = LGS8GXX_PROD_LGS8G75,
+ .demod_address = 0x1d,
+ .serial_ts = 0,
+ .ts_clk_pol = 1,
+ .ts_clk_gated = 0,
+ .if_clk_freq = 30400, /* 30.4 MHz */
+ .if_freq = 4000, /* 4.00 MHz */
+ .if_neg_center = 0,
+ .ext_adc = 0,
+ .adc_signed = 1,
+ .adc_vpp = 3, /* 2.0 Vpp */
+ .if_neg_edge = 1,
+};
+
+static struct tda18271_config prohdtv_pro2_tda18271_config = {
+ .gate = TDA18271_GATE_ANALOG,
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
+};
+
/* ==================================================================
* Core code
*/
@@ -1674,6 +1695,19 @@ static int dvb_init(struct saa7134_dev *dev)
/* mb86a20s need to use the I2C gateway */
break;
+ case SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2:
+ fe0->dvb.frontend = dvb_attach(lgs8gxx_attach,
+ &prohdtv_pro2_lgs8g75_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(tda829x_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0x4b,
+ &tda829x_no_probe);
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_adap,
+ &prohdtv_pro2_tda18271_config);
+ }
+ break;
default:
wprintk("Huh? unknown DVB card?\n");
break;
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index be1c2a2de27c..ff6c0e97563e 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -756,6 +756,14 @@ int saa7134_input_init1(struct saa7134_dev *dev)
mask_keycode = 0x0ff00;
mask_keyup = 0x040000;
break;
+ case SAA7134_BOARD_HAUPPAUGE_HVR1150:
+ case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+ ir_codes = RC_MAP_HAUPPAUGE;
+ mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */
+ mask_keyup = 0x0040000;
+ mask_keycode = 0xffff;
+ raw_decode = true;
+ break;
}
if (NULL == ir_codes) {
printk("%s: Oops: IR config error [card=%d]\n",
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index f96cd5d761f9..28eb10398323 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -328,6 +328,9 @@ struct saa7134_card_ir {
#define SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG 182
#define SAA7134_BOARD_VIDEOMATE_M1F 183
#define SAA7134_BOARD_ENCORE_ENLTV_FM3 184
+#define SAA7134_BOARD_MAGICPRO_PROHDTV_PRO2 185
+#define SAA7134_BOARD_BEHOLD_501 186
+#define SAA7134_BOARD_BEHOLD_503FM 187
#define SAA7134_MAXBOARDS 32
#define SAA7134_INPUT_MAX 8
diff --git a/drivers/media/video/saa7164/saa7164-core.c b/drivers/media/video/saa7164/saa7164-core.c
index b813aec1e456..3b7d7b4e3034 100644
--- a/drivers/media/video/saa7164/saa7164-core.c
+++ b/drivers/media/video/saa7164/saa7164-core.c
@@ -1247,7 +1247,7 @@ static int __devinit saa7164_initdev(struct pci_dev *pci_dev,
}
/* print pci info */
- pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
+ dev->pci_rev = pci_dev->revision;
pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat);
printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
"latency: %d, mmio: 0x%llx\n", dev->name,
diff --git a/drivers/media/video/saa7164/saa7164-encoder.c b/drivers/media/video/saa7164/saa7164-encoder.c
index f9d594698832..400364569c8d 100644
--- a/drivers/media/video/saa7164/saa7164-encoder.c
+++ b/drivers/media/video/saa7164/saa7164-encoder.c
@@ -177,7 +177,7 @@ static int saa7164_encoder_buffers_alloc(struct saa7164_port *port)
}
}
- /* Allocate some kenrel kernel buffers for copying
+ /* Allocate some kernel buffers for copying
* to userpsace.
*/
len = params->numberoflines * params->pitch;
diff --git a/drivers/media/video/saa7164/saa7164-vbi.c b/drivers/media/video/saa7164/saa7164-vbi.c
index 9e5b01c29cf5..bc1fcedba874 100644
--- a/drivers/media/video/saa7164/saa7164-vbi.c
+++ b/drivers/media/video/saa7164/saa7164-vbi.c
@@ -148,7 +148,7 @@ static int saa7164_vbi_buffers_alloc(struct saa7164_port *port)
}
}
- /* Allocate some kenrel kernel buffers for copying
+ /* Allocate some kernel buffers for copying
* to userpsace.
*/
len = params->numberoflines * params->pitch;
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index 134e86bf6d97..3ae5c9c58cba 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/io.h>
+#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/errno.h>
@@ -106,6 +107,7 @@ struct sh_mobile_ceu_dev {
struct vb2_alloc_ctx *alloc_ctx;
struct sh_mobile_ceu_info *pdata;
+ struct completion complete;
u32 cflcr;
@@ -114,6 +116,7 @@ struct sh_mobile_ceu_dev {
unsigned int image_mode:1;
unsigned int is_16bit:1;
+ unsigned int frozen:1;
};
struct sh_mobile_ceu_cam {
@@ -273,7 +276,8 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) & ~CEU_CEIER_MASK);
status = ceu_read(pcdev, CETCR);
ceu_write(pcdev, CETCR, ~status & CEU_CETCR_MAGIC);
- ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) | CEU_CEIER_MASK);
+ if (!pcdev->frozen)
+ ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) | CEU_CEIER_MASK);
ceu_write(pcdev, CAPCR, ceu_read(pcdev, CAPCR) & ~CEU_CAPCR_CTNCP);
ceu_write(pcdev, CETCR, CEU_CETCR_MAGIC ^ CEU_CETCR_IGRW);
@@ -287,6 +291,11 @@ static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
ret = -EIO;
}
+ if (pcdev->frozen) {
+ complete(&pcdev->complete);
+ return ret;
+ }
+
if (!pcdev->active)
return ret;
@@ -378,12 +387,11 @@ static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb)
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb);
- unsigned long flags;
dev_dbg(icd->dev.parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
- spin_lock_irqsave(&pcdev->lock, flags);
+ spin_lock_irq(&pcdev->lock);
list_add_tail(&buf->queue, &pcdev->capture);
if (!pcdev->active) {
@@ -395,7 +403,7 @@ static void sh_mobile_ceu_videobuf_queue(struct vb2_buffer *vb)
pcdev->active = vb;
sh_mobile_ceu_capture(pcdev);
}
- spin_unlock_irqrestore(&pcdev->lock, flags);
+ spin_unlock_irq(&pcdev->lock);
}
static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb)
@@ -404,9 +412,8 @@ static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb)
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct sh_mobile_ceu_buffer *buf = to_ceu_vb(vb);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
- unsigned long flags;
- spin_lock_irqsave(&pcdev->lock, flags);
+ spin_lock_irq(&pcdev->lock);
if (pcdev->active == vb) {
/* disable capture (release DMA buffer), reset */
@@ -417,7 +424,7 @@ static void sh_mobile_ceu_videobuf_release(struct vb2_buffer *vb)
/* Doesn't hurt also if the list is empty */
list_del_init(&buf->queue);
- spin_unlock_irqrestore(&pcdev->lock, flags);
+ spin_unlock_irq(&pcdev->lock);
}
static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb)
@@ -427,6 +434,25 @@ static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb)
return 0;
}
+static int sh_mobile_ceu_stop_streaming(struct vb2_queue *q)
+{
+ struct soc_camera_device *icd = container_of(q, struct soc_camera_device, vb2_vidq);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct sh_mobile_ceu_dev *pcdev = ici->priv;
+ struct list_head *buf_head, *tmp;
+
+ spin_lock_irq(&pcdev->lock);
+
+ pcdev->active = NULL;
+
+ list_for_each_safe(buf_head, tmp, &pcdev->capture)
+ list_del_init(buf_head);
+
+ spin_unlock_irq(&pcdev->lock);
+
+ return sh_mobile_ceu_soft_reset(pcdev);
+}
+
static struct vb2_ops sh_mobile_ceu_videobuf_ops = {
.queue_setup = sh_mobile_ceu_videobuf_setup,
.buf_prepare = sh_mobile_ceu_videobuf_prepare,
@@ -435,6 +461,7 @@ static struct vb2_ops sh_mobile_ceu_videobuf_ops = {
.buf_init = sh_mobile_ceu_videobuf_init,
.wait_prepare = soc_camera_unlock,
.wait_finish = soc_camera_lock,
+ .stop_streaming = sh_mobile_ceu_stop_streaming,
};
static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
@@ -500,7 +527,6 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
{
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
- unsigned long flags;
BUG_ON(icd != pcdev->icd);
@@ -509,13 +535,13 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd)
sh_mobile_ceu_soft_reset(pcdev);
/* make sure active buffer is canceled */
- spin_lock_irqsave(&pcdev->lock, flags);
+ spin_lock_irq(&pcdev->lock);
if (pcdev->active) {
list_del_init(&to_ceu_vb(pcdev->active)->queue);
vb2_buffer_done(pcdev->active, VB2_BUF_STATE_ERROR);
pcdev->active = NULL;
}
- spin_unlock_irqrestore(&pcdev->lock, flags);
+ spin_unlock_irq(&pcdev->lock);
pm_runtime_put_sync(ici->v4l2_dev.dev);
@@ -891,8 +917,8 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
fmt = soc_mbus_get_fmtdesc(code);
if (!fmt) {
- dev_err(dev, "Invalid format code #%u: %d\n", idx, code);
- return -EINVAL;
+ dev_warn(dev, "unsupported format code #%u: %d\n", idx, code);
+ return 0;
}
if (!pcdev->pdata->csi2_dev) {
@@ -1330,7 +1356,7 @@ static int client_scale(struct soc_camera_device *icd,
/*
* CEU can scale and crop, but we don't want to waste bandwidth and kill the
* framerate by always requesting the maximum image from the client. See
- * Documentation/video4linux/sh_mobile_camera_ceu.txt for a description of
+ * Documentation/video4linux/sh_mobile_ceu_camera.txt for a description of
* scaling and cropping algorithms and for the meaning of referenced here steps.
*/
static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
@@ -1377,10 +1403,6 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
if (mf.width > 2560 || mf.height > 1920)
return -EINVAL;
- /* Cache camera output window */
- cam->width = mf.width;
- cam->height = mf.height;
-
/* 4. Calculate camera scales */
scale_cam_h = calc_generic_scale(cam_rect->width, mf.width);
scale_cam_v = calc_generic_scale(cam_rect->height, mf.height);
@@ -1389,6 +1411,39 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd,
interm_width = scale_down(rect->width, scale_cam_h);
interm_height = scale_down(rect->height, scale_cam_v);
+ if (interm_width < icd->user_width) {
+ u32 new_scale_h;
+
+ new_scale_h = calc_generic_scale(rect->width, icd->user_width);
+
+ mf.width = scale_down(cam_rect->width, new_scale_h);
+ }
+
+ if (interm_height < icd->user_height) {
+ u32 new_scale_v;
+
+ new_scale_v = calc_generic_scale(rect->height, icd->user_height);
+
+ mf.height = scale_down(cam_rect->height, new_scale_v);
+ }
+
+ if (interm_width < icd->user_width || interm_height < icd->user_height) {
+ ret = v4l2_device_call_until_err(sd->v4l2_dev, (int)icd, video,
+ s_mbus_fmt, &mf);
+ if (ret < 0)
+ return ret;
+
+ dev_geo(dev, "New camera output %ux%u\n", mf.width, mf.height);
+ scale_cam_h = calc_generic_scale(cam_rect->width, mf.width);
+ scale_cam_v = calc_generic_scale(cam_rect->height, mf.height);
+ interm_width = scale_down(rect->width, scale_cam_h);
+ interm_height = scale_down(rect->height, scale_cam_v);
+ }
+
+ /* Cache camera output window */
+ cam->width = mf.width;
+ cam->height = mf.height;
+
if (pcdev->image_mode) {
out_width = min(interm_width, icd->user_width);
out_height = min(interm_height, icd->user_height);
@@ -1704,6 +1759,63 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
return ret;
}
+static int sh_mobile_ceu_set_livecrop(struct soc_camera_device *icd,
+ struct v4l2_crop *a)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct sh_mobile_ceu_dev *pcdev = ici->priv;
+ u32 out_width = icd->user_width, out_height = icd->user_height;
+ int ret;
+
+ /* Freeze queue */
+ pcdev->frozen = 1;
+ /* Wait for frame */
+ ret = wait_for_completion_interruptible(&pcdev->complete);
+ /* Stop the client */
+ ret = v4l2_subdev_call(sd, video, s_stream, 0);
+ if (ret < 0)
+ dev_warn(icd->dev.parent,
+ "Client failed to stop the stream: %d\n", ret);
+ else
+ /* Do the crop, if it fails, there's nothing more we can do */
+ sh_mobile_ceu_set_crop(icd, a);
+
+ dev_geo(icd->dev.parent, "Output after crop: %ux%u\n", icd->user_width, icd->user_height);
+
+ if (icd->user_width != out_width || icd->user_height != out_height) {
+ struct v4l2_format f = {
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .fmt.pix = {
+ .width = out_width,
+ .height = out_height,
+ .pixelformat = icd->current_fmt->host_fmt->fourcc,
+ .field = pcdev->field,
+ .colorspace = icd->colorspace,
+ },
+ };
+ ret = sh_mobile_ceu_set_fmt(icd, &f);
+ if (!ret && (out_width != f.fmt.pix.width ||
+ out_height != f.fmt.pix.height))
+ ret = -EINVAL;
+ if (!ret) {
+ icd->user_width = out_width;
+ icd->user_height = out_height;
+ ret = sh_mobile_ceu_set_bus_param(icd,
+ icd->current_fmt->host_fmt->fourcc);
+ }
+ }
+
+ /* Thaw the queue */
+ pcdev->frozen = 0;
+ spin_lock_irq(&pcdev->lock);
+ sh_mobile_ceu_capture(pcdev);
+ spin_unlock_irq(&pcdev->lock);
+ /* Start the client */
+ ret = v4l2_subdev_call(sd, video, s_stream, 1);
+ return ret;
+}
+
static unsigned int sh_mobile_ceu_poll(struct file *file, poll_table *pt)
{
struct soc_camera_device *icd = file->private_data;
@@ -1790,6 +1902,7 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
.put_formats = sh_mobile_ceu_put_formats,
.get_crop = sh_mobile_ceu_get_crop,
.set_crop = sh_mobile_ceu_set_crop,
+ .set_livecrop = sh_mobile_ceu_set_livecrop,
.set_fmt = sh_mobile_ceu_set_fmt,
.try_fmt = sh_mobile_ceu_try_fmt,
.set_ctrl = sh_mobile_ceu_set_ctrl,
@@ -1856,6 +1969,7 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&pcdev->capture);
spin_lock_init(&pcdev->lock);
+ init_completion(&pcdev->complete);
pcdev->pdata = pdev->dev.platform_data;
if (!pcdev->pdata) {
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index ddb4c091dedc..398864370267 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -41,6 +41,11 @@
#define DEFAULT_WIDTH 640
#define DEFAULT_HEIGHT 480
+#define is_streaming(ici, icd) \
+ (((ici)->ops->init_videobuf) ? \
+ (icd)->vb_vidq.streaming : \
+ vb2_is_streaming(&(icd)->vb2_vidq))
+
static LIST_HEAD(hosts);
static LIST_HEAD(devices);
static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */
@@ -358,8 +363,6 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd)
if (!icd->user_formats)
return -ENOMEM;
- icd->num_user_formats = fmts;
-
dev_dbg(&icd->dev, "Found %d supported formats.\n", fmts);
/* Second pass - actually fill data formats */
@@ -367,9 +370,10 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd)
for (i = 0; i < raw_fmts; i++)
if (!ici->ops->get_formats) {
v4l2_subdev_call(sd, video, enum_mbus_fmt, i, &code);
- icd->user_formats[i].host_fmt =
+ icd->user_formats[fmts].host_fmt =
soc_mbus_get_fmtdesc(code);
- icd->user_formats[i].code = code;
+ if (icd->user_formats[fmts].host_fmt)
+ icd->user_formats[fmts++].code = code;
} else {
ret = ici->ops->get_formats(icd, i,
&icd->user_formats[fmts]);
@@ -378,12 +382,12 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd)
fmts += ret;
}
+ icd->num_user_formats = fmts;
icd->current_fmt = &icd->user_formats[0];
return 0;
egfmt:
- icd->num_user_formats = 0;
vfree(icd->user_formats);
return ret;
}
@@ -662,7 +666,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
if (icd->streamer && icd->streamer != file)
return -EBUSY;
- if (icd->vb_vidq.bufs[0]) {
+ if (is_streaming(to_soc_camera_host(icd->dev.parent), icd)) {
dev_err(&icd->dev, "S_FMT denied: queue initialised\n");
return -EBUSY;
}
@@ -903,14 +907,17 @@ static int soc_camera_s_crop(struct file *file, void *fh,
if (ret < 0) {
dev_err(&icd->dev,
"S_CROP denied: getting current crop failed\n");
- } else if (icd->vb_vidq.bufs[0] &&
- (a->c.width != current_crop.c.width ||
- a->c.height != current_crop.c.height)) {
+ } else if ((a->c.width == current_crop.c.width &&
+ a->c.height == current_crop.c.height) ||
+ !is_streaming(ici, icd)) {
+ /* same size or not streaming - use .set_crop() */
+ ret = ici->ops->set_crop(icd, a);
+ } else if (ici->ops->set_livecrop) {
+ ret = ici->ops->set_livecrop(icd, a);
+ } else {
dev_err(&icd->dev,
"S_CROP denied: queue initialised and sizes differ\n");
ret = -EBUSY;
- } else {
- ret = ici->ops->set_crop(icd, a);
}
return ret;
diff --git a/drivers/media/video/soc_mediabus.c b/drivers/media/video/soc_mediabus.c
index ed77aa055b63..bea7c9cf4f88 100644
--- a/drivers/media/video/soc_mediabus.c
+++ b/drivers/media/video/soc_mediabus.c
@@ -15,132 +15,329 @@
#include <media/v4l2-mediabus.h>
#include <media/soc_mediabus.h>
-#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)] = {
+static const struct soc_mbus_lookup mbus_fmt[] = {
+{
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .fmt = {
.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)] = {
+}, {
+ .code = V4L2_MBUS_FMT_YVYU8_2X8,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_YVYU,
.name = "YVYU",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(UYVY8_2X8)] = {
+}, {
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_UYVY,
.name = "UYVY",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(VYUY8_2X8)] = {
+}, {
+ .code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_VYUY,
.name = "VYUY",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(RGB555_2X8_PADHI_LE)] = {
+}, {
+ .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_RGB555,
.name = "RGB555",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(RGB555_2X8_PADHI_BE)] = {
+}, {
+ .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_RGB555X,
.name = "RGB555X",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(RGB565_2X8_LE)] = {
+}, {
+ .code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_RGB565,
.name = "RGB565",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(RGB565_2X8_BE)] = {
+}, {
+ .code = V4L2_MBUS_FMT_RGB565_2X8_BE,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_RGB565X,
.name = "RGB565X",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(SBGGR8_1X8)] = {
+}, {
+ .code = V4L2_MBUS_FMT_SBGGR8_1X8,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_SBGGR8,
.name = "Bayer 8 BGGR",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_NONE,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(SBGGR10_1X10)] = {
+}, {
+ .code = V4L2_MBUS_FMT_SBGGR10_1X10,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_SBGGR10,
.name = "Bayer 10 BGGR",
.bits_per_sample = 10,
.packing = SOC_MBUS_PACKING_EXTEND16,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(Y8_1X8)] = {
+}, {
+ .code = V4L2_MBUS_FMT_Y8_1X8,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_GREY,
.name = "Grey",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_NONE,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(Y10_1X10)] = {
+}, {
+ .code = V4L2_MBUS_FMT_Y10_1X10,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_Y10,
.name = "Grey 10bit",
.bits_per_sample = 10,
.packing = SOC_MBUS_PACKING_EXTEND16,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(SBGGR10_2X8_PADHI_LE)] = {
+}, {
+ .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_SBGGR10,
.name = "Bayer 10 BGGR",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(SBGGR10_2X8_PADLO_LE)] = {
+}, {
+ .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_SBGGR10,
.name = "Bayer 10 BGGR",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADLO,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(SBGGR10_2X8_PADHI_BE)] = {
+}, {
+ .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_SBGGR10,
.name = "Bayer 10 BGGR",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_BE,
},
- [MBUS_IDX(SBGGR10_2X8_PADLO_BE)] = {
+}, {
+ .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE,
+ .fmt = {
.fourcc = V4L2_PIX_FMT_SBGGR10,
.name = "Bayer 10 BGGR",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADLO,
.order = SOC_MBUS_ORDER_BE,
},
+}, {
+ .code = V4L2_MBUS_FMT_JPEG_1X8,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ .name = "JPEG",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_VARIABLE,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_RGB444,
+ .name = "RGB444",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_BE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_YUYV8_1_5X8,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .name = "YUYV 4:2:0",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_1_5X8,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_YVYU8_1_5X8,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_YVU420,
+ .name = "YVYU 4:2:0",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_1_5X8,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_UYVY8_1X16,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .name = "UYVY 16bit",
+ .bits_per_sample = 16,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_VYUY8_1X16,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .name = "VYUY 16bit",
+ .bits_per_sample = 16,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_YUYV8_1X16,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .name = "YUYV 16bit",
+ .bits_per_sample = 16,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_YVYU8_1X16,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .name = "YVYU 16bit",
+ .bits_per_sample = 16,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_SGRBG8_1X8,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SGRBG8,
+ .name = "Bayer 8 GRBG",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_NONE,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SGRBG10DPCM8,
+ .name = "Bayer 10 BGGR DPCM 8",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_NONE,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_SGBRG10_1X10,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SGBRG10,
+ .name = "Bayer 10 GBRG",
+ .bits_per_sample = 10,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_SGRBG10_1X10,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SGRBG10,
+ .name = "Bayer 10 GRBG",
+ .bits_per_sample = 10,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_SRGGB10_1X10,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SRGGB10,
+ .name = "Bayer 10 RGGB",
+ .bits_per_sample = 10,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_SBGGR12_1X12,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SBGGR12,
+ .name = "Bayer 12 BGGR",
+ .bits_per_sample = 12,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_SGBRG12_1X12,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SGBRG12,
+ .name = "Bayer 12 GBRG",
+ .bits_per_sample = 12,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_SGRBG12_1X12,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SGRBG12,
+ .name = "Bayer 12 GRBG",
+ .bits_per_sample = 12,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+}, {
+ .code = V4L2_MBUS_FMT_SRGGB12_1X12,
+ .fmt = {
+ .fourcc = V4L2_PIX_FMT_SRGGB12,
+ .name = "Bayer 12 RGGB",
+ .bits_per_sample = 12,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+},
};
-int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf)
+int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf,
+ unsigned int *numerator, unsigned int *denominator)
{
switch (mf->packing) {
case SOC_MBUS_PACKING_NONE:
case SOC_MBUS_PACKING_EXTEND16:
- return 1;
+ *numerator = 1;
+ *denominator = 1;
+ return 0;
case SOC_MBUS_PACKING_2X8_PADHI:
case SOC_MBUS_PACKING_2X8_PADLO:
- return 2;
+ *numerator = 2;
+ *denominator = 1;
+ return 0;
+ case SOC_MBUS_PACKING_1_5X8:
+ *numerator = 3;
+ *denominator = 2;
+ return 0;
+ case SOC_MBUS_PACKING_VARIABLE:
+ *numerator = 0;
+ *denominator = 1;
+ return 0;
}
return -EINVAL;
}
@@ -155,18 +352,34 @@ s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
case SOC_MBUS_PACKING_2X8_PADLO:
case SOC_MBUS_PACKING_EXTEND16:
return width * 2;
+ case SOC_MBUS_PACKING_1_5X8:
+ return width * 3 / 2;
+ case SOC_MBUS_PACKING_VARIABLE:
+ return 0;
}
return -EINVAL;
}
EXPORT_SYMBOL(soc_mbus_bytes_per_line);
+const struct soc_mbus_pixelfmt *soc_mbus_find_fmtdesc(
+ enum v4l2_mbus_pixelcode code,
+ const struct soc_mbus_lookup *lookup,
+ int n)
+{
+ int i;
+
+ for (i = 0; i < n; i++)
+ if (lookup[i].code == code)
+ return &lookup[i].fmt;
+
+ return NULL;
+}
+EXPORT_SYMBOL(soc_mbus_find_fmtdesc);
+
const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc(
enum v4l2_mbus_pixelcode code)
{
- if (code - V4L2_MBUS_FMT_FIXED > ARRAY_SIZE(mbus_fmt) ||
- code <= V4L2_MBUS_FMT_FIXED)
- return NULL;
- return mbus_fmt + code - V4L2_MBUS_FMT_FIXED - 1;
+ return soc_mbus_find_fmtdesc(code, mbus_fmt, ARRAY_SIZE(mbus_fmt));
}
EXPORT_SYMBOL(soc_mbus_get_fmtdesc);
diff --git a/drivers/media/video/timblogiw.c b/drivers/media/video/timblogiw.c
index 84d4c7c83435..fc611ebeb82c 100644
--- a/drivers/media/video/timblogiw.c
+++ b/drivers/media/video/timblogiw.c
@@ -24,7 +24,6 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/dmaengine.h>
-#include <linux/mfd/core.h>
#include <linux/scatterlist.h>
#include <linux/interrupt.h>
#include <linux/list.h>
@@ -791,7 +790,7 @@ static int __devinit timblogiw_probe(struct platform_device *pdev)
{
int err;
struct timblogiw *lw = NULL;
- struct timb_video_platform_data *pdata = mfd_get_data(pdev);
+ struct timb_video_platform_data *pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(&pdev->dev, "No platform data\n");
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index 07fabdd9b465..6103d1b1081e 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -267,21 +267,27 @@ hauppauge_tuner[] =
{ TUNER_ABSENT, "Xceive XC4000"},
{ TUNER_ABSENT, "Dibcom 7070"},
{ TUNER_PHILIPS_TDA8290, "NXP 18271C2"},
- { TUNER_ABSENT, "unknown"},
- { TUNER_ABSENT, "unknown"},
- { TUNER_ABSENT, "unknown"},
- { TUNER_ABSENT, "unknown"},
+ { TUNER_ABSENT, "Siano SMS1010"},
+ { TUNER_ABSENT, "Siano SMS1150"},
+ { TUNER_ABSENT, "MaxLinear 5007"},
+ { TUNER_ABSENT, "TCL M09WPP_2P_E"},
/* 160-169 */
- { TUNER_ABSENT, "unknown"},
- { TUNER_ABSENT, "unknown"},
- { TUNER_ABSENT, "unknown"},
- { TUNER_ABSENT, "unknown"},
- { TUNER_ABSENT, "unknown"},
- { TUNER_ABSENT, "unknown"},
- { TUNER_ABSENT, "unknown"},
- { TUNER_ABSENT, "unknown"},
+ { TUNER_ABSENT, "Siano SMS1180"},
+ { TUNER_ABSENT, "Maxim_MAX2165"},
+ { TUNER_ABSENT, "Siano SMS1140"},
+ { TUNER_ABSENT, "Siano SMS1150 B1"},
+ { TUNER_ABSENT, "MaxLinear 111"},
+ { TUNER_ABSENT, "Dibcom 7770"},
+ { TUNER_ABSENT, "Siano SMS1180VNS"},
+ { TUNER_ABSENT, "Siano SMS1184"},
{ TUNER_PHILIPS_FQ1236_MK5, "TCL M30WTP-4N-E"},
- { TUNER_ABSENT, "unknown"},
+ { TUNER_ABSENT, "TCL_M11WPP_2PN_E"},
+ /* 170-179 */
+ { TUNER_ABSENT, "MaxLinear 301"},
+ { TUNER_ABSENT, "Mirics MSi001"},
+ { TUNER_ABSENT, "MaxLinear MxL241SF"},
+ { TUNER_ABSENT, "Xceive XC5000C"},
+ { TUNER_ABSENT, "Montage M68TS2020"},
};
/* Use V4L2_IDENT_AMBIGUOUS for those audio 'chips' that are
diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c
index 68b998bd203f..8f5266157f15 100644
--- a/drivers/media/video/usbvision/usbvision-cards.c
+++ b/drivers/media/video/usbvision/usbvision-cards.c
@@ -1025,6 +1025,34 @@ struct usbvision_device_data_st usbvision_device_data[] = {
.y_offset = -1,
.model_string = "Hauppauge WinTv-USB",
},
+ [MICROCAM_NTSC] = {
+ .interface = -1,
+ .codec = CODEC_WEBCAM,
+ .video_channels = 1,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 0,
+ .radio = 0,
+ .vbi = 0,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 71,
+ .y_offset = 15,
+ .model_string = "Nogatech USB MicroCam NTSC (NV3000N)",
+ },
+ [MICROCAM_PAL] = {
+ .interface = -1,
+ .codec = CODEC_WEBCAM,
+ .video_channels = 1,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 0,
+ .radio = 0,
+ .vbi = 0,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 71,
+ .y_offset = 18,
+ .model_string = "Nogatech USB MicroCam PAL (NV3001P)",
+ },
};
const int usbvision_device_data_size = ARRAY_SIZE(usbvision_device_data);
@@ -1042,6 +1070,8 @@ struct usb_device_id usbvision_table[] = {
{ USB_DEVICE(0x0573, 0x2d00), .driver_info = HPG_WINTV_LIVE_PAL_BG },
{ USB_DEVICE(0x0573, 0x2d01), .driver_info = HPG_WINTV_LIVE_PRO_NTSC_MN },
{ USB_DEVICE(0x0573, 0x2101), .driver_info = ZORAN_PMD_NOGATECH },
+ { USB_DEVICE(0x0573, 0x3000), .driver_info = MICROCAM_NTSC },
+ { USB_DEVICE(0x0573, 0x3001), .driver_info = MICROCAM_PAL },
{ USB_DEVICE(0x0573, 0x4100), .driver_info = NOGATECH_USB_TV_NTSC_FM },
{ USB_DEVICE(0x0573, 0x4110), .driver_info = PNY_USB_TV_NTSC_FM },
{ USB_DEVICE(0x0573, 0x4450), .driver_info = PV_PLAYTV_USB_PRO_PAL_FM },
@@ -1088,8 +1118,7 @@ struct usb_device_id usbvision_table[] = {
{ USB_DEVICE(0x2304, 0x0110), .driver_info = PINNA_PCTV_USB_PAL_FM },
{ USB_DEVICE(0x2304, 0x0111), .driver_info = MIRO_PCTV_USB },
{ USB_DEVICE(0x2304, 0x0112), .driver_info = PINNA_PCTV_USB_NTSC_FM },
- { USB_DEVICE(0x2304, 0x0113),
- .driver_info = PINNA_PCTV_USB_NTSC_FM_V3 },
+ { USB_DEVICE(0x2304, 0x0113), .driver_info = PINNA_PCTV_USB_NTSC_FM_V3 },
{ USB_DEVICE(0x2304, 0x0210), .driver_info = PINNA_PCTV_USB_PAL_FM_V2 },
{ USB_DEVICE(0x2304, 0x0212), .driver_info = PINNA_PCTV_USB_NTSC_FM_V2 },
{ USB_DEVICE(0x2304, 0x0214), .driver_info = PINNA_PCTV_USB_PAL_FM_V3 },
diff --git a/drivers/media/video/usbvision/usbvision-cards.h b/drivers/media/video/usbvision/usbvision-cards.h
index 9c6ad22960d8..a51cc1185cce 100644
--- a/drivers/media/video/usbvision/usbvision-cards.h
+++ b/drivers/media/video/usbvision/usbvision-cards.h
@@ -63,5 +63,7 @@
#define PINNA_PCTV_BUNGEE_PAL_FM 62
#define HPG_WINTV 63
#define PINNA_PCTV_USB_NTSC_FM_V3 64
+#define MICROCAM_NTSC 65
+#define MICROCAM_PAL 66
extern const int usbvision_device_data_size;
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c
index c8feb0d6fccf..f344411a4578 100644
--- a/drivers/media/video/usbvision/usbvision-core.c
+++ b/drivers/media/video/usbvision/usbvision-core.c
@@ -49,10 +49,6 @@ static unsigned int core_debug;
module_param(core_debug, int, 0644);
MODULE_PARM_DESC(core_debug, "enable debug messages [core]");
-static unsigned int force_testpattern;
-module_param(force_testpattern, int, 0644);
-MODULE_PARM_DESC(force_testpattern, "enable test pattern display [core]");
-
static int adjust_compression = 1; /* Set the compression to be adaptive */
module_param(adjust_compression, int, 0444);
MODULE_PARM_DESC(adjust_compression, " Set the ADPCM compression for the device. Default: 1 (On)");
@@ -388,90 +384,6 @@ void usbvision_scratch_free(struct usb_usbvision *usbvision)
}
/*
- * usbvision_testpattern()
- *
- * Procedure forms a test pattern (yellow grid on blue background).
- *
- * Parameters:
- * fullframe: if TRUE then entire frame is filled, otherwise the procedure
- * continues from the current scanline.
- * pmode 0: fill the frame with solid blue color (like on VCR or TV)
- * 1: Draw a colored grid
- *
- */
-static void usbvision_testpattern(struct usb_usbvision *usbvision,
- int fullframe, int pmode)
-{
- static const char proc[] = "usbvision_testpattern";
- struct usbvision_frame *frame;
- unsigned char *f;
- int num_cell = 0;
- int scan_length = 0;
- static int num_pass;
-
- if (usbvision == NULL) {
- printk(KERN_ERR "%s: usbvision == NULL\n", proc);
- return;
- }
- if (usbvision->cur_frame == NULL) {
- printk(KERN_ERR "%s: usbvision->cur_frame is NULL.\n", proc);
- return;
- }
-
- /* Grab the current frame */
- frame = usbvision->cur_frame;
-
- /* Optionally start at the beginning */
- if (fullframe) {
- frame->curline = 0;
- frame->scanlength = 0;
- }
-
- /* Form every scan line */
- for (; frame->curline < frame->frmheight; frame->curline++) {
- int i;
-
- f = frame->data + (usbvision->curwidth * 3 * frame->curline);
- for (i = 0; i < usbvision->curwidth; i++) {
- unsigned char cb = 0x80;
- unsigned char cg = 0;
- unsigned char cr = 0;
-
- if (pmode == 1) {
- if (frame->curline % 32 == 0)
- cb = 0, cg = cr = 0xFF;
- else if (i % 32 == 0) {
- if (frame->curline % 32 == 1)
- num_cell++;
- cb = 0, cg = cr = 0xFF;
- } else {
- cb =
- ((num_cell * 7) +
- num_pass) & 0xFF;
- cg =
- ((num_cell * 5) +
- num_pass * 2) & 0xFF;
- cr =
- ((num_cell * 3) +
- num_pass * 3) & 0xFF;
- }
- } else {
- /* Just the blue screen */
- }
-
- *f++ = cb;
- *f++ = cg;
- *f++ = cr;
- scan_length += 3;
- }
- }
-
- frame->grabstate = frame_state_done;
- frame->scanlength += scan_length;
- ++num_pass;
-}
-
-/*
* usbvision_decompress_alloc()
*
* allocates intermediate buffer for decompression
@@ -571,10 +483,6 @@ static enum parse_state usbvision_find_header(struct usb_usbvision *usbvision)
frame->scanstate = scan_state_lines;
frame->curline = 0;
- if (force_testpattern) {
- usbvision_testpattern(usbvision, 1, 1);
- return parse_state_next_frame;
- }
return parse_state_continue;
}
@@ -1679,6 +1587,55 @@ int usbvision_power_off(struct usb_usbvision *usbvision)
return err_code;
}
+/* configure webcam image sensor using the serial port */
+static int usbvision_init_webcam(struct usb_usbvision *usbvision)
+{
+ int rc;
+ int i;
+ static char init_values[38][3] = {
+ { 0x04, 0x12, 0x08 }, { 0x05, 0xff, 0xc8 }, { 0x06, 0x18, 0x07 }, { 0x07, 0x90, 0x00 },
+ { 0x09, 0x00, 0x00 }, { 0x0a, 0x00, 0x00 }, { 0x0b, 0x08, 0x00 }, { 0x0d, 0xcc, 0xcc },
+ { 0x0e, 0x13, 0x14 }, { 0x10, 0x9b, 0x83 }, { 0x11, 0x5a, 0x3f }, { 0x12, 0xe4, 0x73 },
+ { 0x13, 0x88, 0x84 }, { 0x14, 0x89, 0x80 }, { 0x15, 0x00, 0x20 }, { 0x16, 0x00, 0x00 },
+ { 0x17, 0xff, 0xa0 }, { 0x18, 0x6b, 0x20 }, { 0x19, 0x22, 0x40 }, { 0x1a, 0x10, 0x07 },
+ { 0x1b, 0x00, 0x47 }, { 0x1c, 0x03, 0xe0 }, { 0x1d, 0x00, 0x00 }, { 0x1e, 0x00, 0x00 },
+ { 0x1f, 0x00, 0x00 }, { 0x20, 0x00, 0x00 }, { 0x21, 0x00, 0x00 }, { 0x22, 0x00, 0x00 },
+ { 0x23, 0x00, 0x00 }, { 0x24, 0x00, 0x00 }, { 0x25, 0x00, 0x00 }, { 0x26, 0x00, 0x00 },
+ { 0x27, 0x00, 0x00 }, { 0x28, 0x00, 0x00 }, { 0x29, 0x00, 0x00 }, { 0x08, 0x80, 0x60 },
+ { 0x0f, 0x2d, 0x24 }, { 0x0c, 0x80, 0x80 }
+ };
+ char value[3];
+
+ /* the only difference between PAL and NTSC init_values */
+ if (usbvision_device_data[usbvision->dev_model].video_norm == V4L2_STD_NTSC)
+ init_values[4][1] = 0x34;
+
+ for (i = 0; i < sizeof(init_values) / 3; i++) {
+ usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SOFT);
+ memcpy(value, init_values[i], 3);
+ rc = usb_control_msg(usbvision->dev,
+ usb_sndctrlpipe(usbvision->dev, 1),
+ USBVISION_OP_CODE,
+ USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_ENDPOINT, 0,
+ (__u16) USBVISION_SER_DAT1, value,
+ 3, HZ);
+ if (rc < 0)
+ return rc;
+ usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SIO);
+ /* write 3 bytes to the serial port using SIO mode */
+ usbvision_write_reg(usbvision, USBVISION_SER_CONT, 3 | 0x10);
+ usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, 0);
+ usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SOFT);
+ usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, USBVISION_IO_2);
+ usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SOFT | USBVISION_CLK_OUT);
+ usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SOFT | USBVISION_DAT_IO);
+ usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_SER_MODE_SOFT | USBVISION_CLK_OUT | USBVISION_DAT_IO);
+ }
+
+ return 0;
+}
+
/*
* usbvision_set_video_format()
*
@@ -1797,6 +1754,13 @@ int usbvision_set_output(struct usb_usbvision *usbvision, int width,
frame_drop = FRAMERATE_MAX; /* We can allow the maximum here, because dropping is controlled */
+ if (usbvision_device_data[usbvision->dev_model].codec == CODEC_WEBCAM) {
+ if (usbvision_device_data[usbvision->dev_model].video_norm == V4L2_STD_PAL)
+ frame_drop = 25;
+ else
+ frame_drop = 30;
+ }
+
/* frame_drop = 7; => frame_phase = 1, 5, 9, 13, 17, 21, 25, 0, 4, 8, ...
=> frame_skip = 4;
=> frame_rate = (7 + 1) * 25 / 32 = 200 / 32 = 6.25;
@@ -2046,6 +2010,12 @@ int usbvision_set_input(struct usb_usbvision *usbvision)
value[7] = 0x00; /* 0x0010 -> 16 Input video v offset */
}
+ /* webcam is only 480 pixels wide, both PAL and NTSC version */
+ if (usbvision_device_data[usbvision->dev_model].codec == CODEC_WEBCAM) {
+ value[0] = 0xe0;
+ value[1] = 0x01; /* 0x01E0 -> 480 Input video line length */
+ }
+
if (usbvision_device_data[usbvision->dev_model].x_offset >= 0) {
value[4] = usbvision_device_data[usbvision->dev_model].x_offset & 0xff;
value[5] = (usbvision_device_data[usbvision->dev_model].x_offset & 0x0300) >> 8;
@@ -2148,7 +2118,7 @@ static int usbvision_set_dram_settings(struct usb_usbvision *usbvision)
(__u16) USBVISION_DRM_PRM1, value, 8, HZ);
if (rc < 0) {
- dev_err(&usbvision->dev->dev, "%sERROR=%d\n", __func__, rc);
+ dev_err(&usbvision->dev->dev, "%s: ERROR=%d\n", __func__, rc);
return rc;
}
@@ -2180,8 +2150,15 @@ int usbvision_power_on(struct usb_usbvision *usbvision)
usbvision_write_reg(usbvision, USBVISION_PWR_REG,
USBVISION_SSPND_EN | USBVISION_RES2);
+ if (usbvision_device_data[usbvision->dev_model].codec == CODEC_WEBCAM) {
+ usbvision_write_reg(usbvision, USBVISION_VIN_REG1,
+ USBVISION_16_422_SYNC | USBVISION_HVALID_PO);
+ usbvision_write_reg(usbvision, USBVISION_VIN_REG2,
+ USBVISION_NOHVALID | USBVISION_KEEP_BLANK);
+ }
usbvision_write_reg(usbvision, USBVISION_PWR_REG,
USBVISION_SSPND_EN | USBVISION_PWR_VID);
+ mdelay(10);
err_code = usbvision_write_reg(usbvision, USBVISION_PWR_REG,
USBVISION_SSPND_EN | USBVISION_PWR_VID | USBVISION_RES2);
if (err_code == 1)
@@ -2310,6 +2287,8 @@ int usbvision_set_audio(struct usb_usbvision *usbvision, int audio_channel)
int usbvision_setup(struct usb_usbvision *usbvision, int format)
{
+ if (usbvision_device_data[usbvision->dev_model].codec == CODEC_WEBCAM)
+ usbvision_init_webcam(usbvision);
usbvision_set_video_format(usbvision, format);
usbvision_set_dram_settings(usbvision);
usbvision_set_compress_params(usbvision);
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c
index 05b1344181cd..d7f97513b289 100644
--- a/drivers/media/video/usbvision/usbvision-i2c.c
+++ b/drivers/media/video/usbvision/usbvision-i2c.c
@@ -222,7 +222,7 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision)
i2c_set_adapdata(&usbvision->i2c_adap, &usbvision->v4l2_dev);
if (usbvision_write_reg(usbvision, USBVISION_SER_MODE, USBVISION_IIC_LRNACK) < 0) {
- printk(KERN_ERR "usbvision_register: can't write reg\n");
+ printk(KERN_ERR "usbvision_i2c_register: can't write reg\n");
return -EBUSY;
}
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index 6083137f0bf8..ea8ea8a48dfe 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -70,8 +70,9 @@
#include "usbvision.h"
#include "usbvision-cards.h"
-#define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>, \
-Dwaine Garden <DwaineGarden@rogers.com>"
+#define DRIVER_AUTHOR \
+ "Joerg Heckenbach <joerg@heckenbach-aw.de>, " \
+ "Dwaine Garden <DwaineGarden@rogers.com>"
#define DRIVER_NAME "usbvision"
#define DRIVER_ALIAS "USBVision"
#define DRIVER_DESC "USBVision USB Video Device Driver for Linux"
@@ -1470,7 +1471,8 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision)
/* This should be here to make i2c clients to be able to register */
/* first switch off audio */
- usbvision_audio_off(usbvision);
+ if (usbvision_device_data[model].audio_channels > 0)
+ usbvision_audio_off(usbvision);
if (!power_on_at_open) {
/* and then power up the noisy tuner */
usbvision_power_on(usbvision);
diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h
index 8074787fd1ac..43cf61fe4943 100644
--- a/drivers/media/video/usbvision/usbvision.h
+++ b/drivers/media/video/usbvision/usbvision.h
@@ -59,6 +59,11 @@
#define USBVISION_AUDIO_RADIO 2
#define USBVISION_AUDIO_MUTE 3
#define USBVISION_SER_MODE 0x07
+ #define USBVISION_CLK_OUT (1 << 0)
+ #define USBVISION_DAT_IO (1 << 1)
+ #define USBVISION_SENS_OUT (1 << 2)
+ #define USBVISION_SER_MODE_SOFT (0 << 4)
+ #define USBVISION_SER_MODE_SIO (1 << 4)
#define USBVISION_SER_ADRS 0x08
#define USBVISION_SER_CONT 0x09
#define USBVISION_SER_DAT1 0x0A
@@ -328,6 +333,7 @@ struct usbvision_frame {
#define CODEC_SAA7113 7113
#define CODEC_SAA7111 7111
+#define CODEC_WEBCAM 3000
#define BRIDGE_NT1003 1003
#define BRIDGE_NT1004 1004
#define BRIDGE_NT1005 1005
diff --git a/drivers/media/video/uvc/Makefile b/drivers/media/video/uvc/Makefile
index 968c1994eda0..2071ca8a2f03 100644
--- a/drivers/media/video/uvc/Makefile
+++ b/drivers/media/video/uvc/Makefile
@@ -1,3 +1,6 @@
uvcvideo-objs := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \
uvc_status.o uvc_isight.o
+ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
+uvcvideo-objs += uvc_entity.o
+endif
obj-$(CONFIG_USB_VIDEO_CLASS) += uvcvideo.o
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index 59f8a9ad3796..a4db26fa2f53 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -42,281 +42,313 @@ static struct uvc_control_info uvc_ctrls[] = {
.selector = UVC_PU_BRIGHTNESS_CONTROL,
.index = 0,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_CONTRAST_CONTROL,
.index = 1,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_HUE_CONTROL,
.index = 2,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_SATURATION_CONTROL,
.index = 3,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_SHARPNESS_CONTROL,
.index = 4,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_GAMMA_CONTROL,
.index = 5,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
.index = 6,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL,
.index = 7,
.size = 4,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_BACKLIGHT_COMPENSATION_CONTROL,
.index = 8,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_GAIN_CONTROL,
.index = 9,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
.index = 10,
.size = 1,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
- | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+ | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_HUE_AUTO_CONTROL,
.index = 11,
.size = 1,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
- | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+ | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
.index = 12,
.size = 1,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
- | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+ | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
.index = 13,
.size = 1,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
- | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+ | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_DIGITAL_MULTIPLIER_CONTROL,
.index = 14,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL,
.index = 15,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL,
.index = 16,
.size = 1,
- .flags = UVC_CONTROL_GET_CUR,
+ .flags = UVC_CTRL_FLAG_GET_CUR,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
.selector = UVC_PU_ANALOG_LOCK_STATUS_CONTROL,
.index = 17,
.size = 1,
- .flags = UVC_CONTROL_GET_CUR,
+ .flags = UVC_CTRL_FLAG_GET_CUR,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_SCANNING_MODE_CONTROL,
.index = 0,
.size = 1,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_AE_MODE_CONTROL,
.index = 1,
.size = 1,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
- | UVC_CONTROL_GET_DEF | UVC_CONTROL_GET_RES
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+ | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_GET_RES
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_AE_PRIORITY_CONTROL,
.index = 2,
.size = 1,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
.index = 3,
.size = 4,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL,
.index = 4,
.size = 1,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_FOCUS_ABSOLUTE_CONTROL,
.index = 5,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_FOCUS_RELATIVE_CONTROL,
.index = 6,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN
- | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES
- | UVC_CONTROL_GET_DEF | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN
+ | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES
+ | UVC_CTRL_FLAG_GET_DEF
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_IRIS_ABSOLUTE_CONTROL,
.index = 7,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_IRIS_RELATIVE_CONTROL,
.index = 8,
.size = 1,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_ZOOM_ABSOLUTE_CONTROL,
.index = 9,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_ZOOM_RELATIVE_CONTROL,
.index = 10,
.size = 3,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN
- | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES
- | UVC_CONTROL_GET_DEF | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN
+ | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES
+ | UVC_CTRL_FLAG_GET_DEF
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL,
.index = 11,
.size = 8,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_PANTILT_RELATIVE_CONTROL,
.index = 12,
.size = 4,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN
- | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES
- | UVC_CONTROL_GET_DEF | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN
+ | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES
+ | UVC_CTRL_FLAG_GET_DEF
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_ROLL_ABSOLUTE_CONTROL,
.index = 13,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR
+ | UVC_CTRL_FLAG_GET_RANGE
+ | UVC_CTRL_FLAG_RESTORE
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_ROLL_RELATIVE_CONTROL,
.index = 14,
.size = 2,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN
- | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES
- | UVC_CONTROL_GET_DEF | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN
+ | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES
+ | UVC_CTRL_FLAG_GET_DEF
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_FOCUS_AUTO_CONTROL,
.index = 17,
.size = 1,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
- | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+ | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
.selector = UVC_CT_PRIVACY_CONTROL,
.index = 18,
.size = 1,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
- | UVC_CONTROL_RESTORE | UVC_CONTROL_AUTO_UPDATE,
+ .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+ | UVC_CTRL_FLAG_RESTORE
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
};
@@ -816,7 +848,7 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
{
int ret;
- if (ctrl->info.flags & UVC_CONTROL_GET_DEF) {
+ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) {
ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id,
chain->dev->intfnum, ctrl->info.selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF),
@@ -825,7 +857,7 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
return ret;
}
- if (ctrl->info.flags & UVC_CONTROL_GET_MIN) {
+ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN) {
ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id,
chain->dev->intfnum, ctrl->info.selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN),
@@ -833,7 +865,7 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
if (ret < 0)
return ret;
}
- if (ctrl->info.flags & UVC_CONTROL_GET_MAX) {
+ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) {
ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id,
chain->dev->intfnum, ctrl->info.selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX),
@@ -841,7 +873,7 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
if (ret < 0)
return ret;
}
- if (ctrl->info.flags & UVC_CONTROL_GET_RES) {
+ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) {
ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id,
chain->dev->intfnum, ctrl->info.selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES),
@@ -879,9 +911,9 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
strlcpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name);
v4l2_ctrl->flags = 0;
- if (!(ctrl->info.flags & UVC_CONTROL_GET_CUR))
+ if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
v4l2_ctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
- if (!(ctrl->info.flags & UVC_CONTROL_SET_CUR))
+ if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
if (!ctrl->cached) {
@@ -890,7 +922,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
goto done;
}
- if (ctrl->info.flags & UVC_CONTROL_GET_DEF) {
+ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) {
v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
}
@@ -927,15 +959,15 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
break;
}
- if (ctrl->info.flags & UVC_CONTROL_GET_MIN)
+ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN)
v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
- if (ctrl->info.flags & UVC_CONTROL_GET_MAX)
+ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX)
v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
- if (ctrl->info.flags & UVC_CONTROL_GET_RES)
+ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)
v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
@@ -983,6 +1015,24 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
}
menu_info = &mapping->menu_info[query_menu->index];
+
+ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) {
+ s32 bitmap;
+
+ if (!ctrl->cached) {
+ ret = uvc_ctrl_populate_cache(chain, ctrl);
+ if (ret < 0)
+ goto done;
+ }
+
+ bitmap = mapping->get(mapping, UVC_GET_RES,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
+ if (!(bitmap & menu_info->value)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name);
done:
@@ -1039,7 +1089,7 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
* marked as loaded in uvc_ctrl_get/uvc_ctrl_set to prevent
* uvc_ctrl_get from using the cached value.
*/
- if (ctrl->info.flags & UVC_CONTROL_AUTO_UPDATE)
+ if (ctrl->info.flags & UVC_CTRL_FLAG_AUTO_UPDATE)
ctrl->loaded = 0;
if (!ctrl->dirty)
@@ -1094,7 +1144,7 @@ int uvc_ctrl_get(struct uvc_video_chain *chain,
int ret;
ctrl = uvc_find_control(chain, xctrl->id, &mapping);
- if (ctrl == NULL || (ctrl->info.flags & UVC_CONTROL_GET_CUR) == 0)
+ if (ctrl == NULL || (ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) == 0)
return -EINVAL;
if (!ctrl->loaded) {
@@ -1136,7 +1186,7 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
int ret;
ctrl = uvc_find_control(chain, xctrl->id, &mapping);
- if (ctrl == NULL || (ctrl->info.flags & UVC_CONTROL_SET_CUR) == 0)
+ if (ctrl == NULL || (ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR) == 0)
return -EINVAL;
/* Clamp out of range values. */
@@ -1171,6 +1221,23 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
if (xctrl->value < 0 || xctrl->value >= mapping->menu_count)
return -ERANGE;
value = mapping->menu_info[xctrl->value].value;
+
+ /* Valid menu indices are reported by the GET_RES request for
+ * UVC controls that support it.
+ */
+ if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) {
+ if (!ctrl->cached) {
+ ret = uvc_ctrl_populate_cache(chain, ctrl);
+ if (ret < 0)
+ return ret;
+ }
+
+ step = mapping->get(mapping, UVC_GET_RES,
+ uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
+ if (!(step & value))
+ return -ERANGE;
+ }
+
break;
default:
@@ -1183,7 +1250,7 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
* operation.
*/
if (!ctrl->loaded && (ctrl->info.size * 8) != mapping->size) {
- if ((ctrl->info.flags & UVC_CONTROL_GET_CUR) == 0) {
+ if ((ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) == 0) {
memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
0, ctrl->info.size);
} else {
@@ -1230,17 +1297,17 @@ static void uvc_ctrl_fixup_xu_info(struct uvc_device *dev,
static const struct uvc_ctrl_fixup fixups[] = {
{ { USB_DEVICE(0x046d, 0x08c2) }, 9, 1,
- UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
- UVC_CONTROL_GET_DEF | UVC_CONTROL_SET_CUR |
- UVC_CONTROL_AUTO_UPDATE },
+ UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX |
+ UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_SET_CUR |
+ UVC_CTRL_FLAG_AUTO_UPDATE },
{ { USB_DEVICE(0x046d, 0x08cc) }, 9, 1,
- UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
- UVC_CONTROL_GET_DEF | UVC_CONTROL_SET_CUR |
- UVC_CONTROL_AUTO_UPDATE },
+ UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX |
+ UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_SET_CUR |
+ UVC_CTRL_FLAG_AUTO_UPDATE },
{ { USB_DEVICE(0x046d, 0x0994) }, 9, 1,
- UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
- UVC_CONTROL_GET_DEF | UVC_CONTROL_SET_CUR |
- UVC_CONTROL_AUTO_UPDATE },
+ UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX |
+ UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_SET_CUR |
+ UVC_CTRL_FLAG_AUTO_UPDATE },
};
unsigned int i;
@@ -1297,21 +1364,23 @@ static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
goto done;
}
- info->flags = UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX
- | UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF
- | (data[0] & UVC_CONTROL_CAP_GET ? UVC_CONTROL_GET_CUR : 0)
- | (data[0] & UVC_CONTROL_CAP_SET ? UVC_CONTROL_SET_CUR : 0)
+ info->flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
+ | UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF
+ | (data[0] & UVC_CONTROL_CAP_GET ?
+ UVC_CTRL_FLAG_GET_CUR : 0)
+ | (data[0] & UVC_CONTROL_CAP_SET ?
+ UVC_CTRL_FLAG_SET_CUR : 0)
| (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ?
- UVC_CONTROL_AUTO_UPDATE : 0);
+ UVC_CTRL_FLAG_AUTO_UPDATE : 0);
uvc_ctrl_fixup_xu_info(dev, ctrl, info);
uvc_trace(UVC_TRACE_CONTROL, "XU control %pUl/%u queried: len %u, "
"flags { get %u set %u auto %u }.\n",
info->entity, info->selector, info->size,
- (info->flags & UVC_CONTROL_GET_CUR) ? 1 : 0,
- (info->flags & UVC_CONTROL_SET_CUR) ? 1 : 0,
- (info->flags & UVC_CONTROL_AUTO_UPDATE) ? 1 : 0);
+ (info->flags & UVC_CTRL_FLAG_GET_CUR) ? 1 : 0,
+ (info->flags & UVC_CTRL_FLAG_SET_CUR) ? 1 : 0,
+ (info->flags & UVC_CTRL_FLAG_AUTO_UPDATE) ? 1 : 0);
done:
kfree(data);
@@ -1344,32 +1413,33 @@ static int uvc_ctrl_init_xu_ctrl(struct uvc_device *dev,
}
int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
- struct uvc_xu_control *xctrl, int set)
+ struct uvc_xu_control_query *xqry)
{
struct uvc_entity *entity;
- struct uvc_control *ctrl = NULL;
+ struct uvc_control *ctrl;
unsigned int i, found = 0;
- int restore = 0;
- __u8 *data;
+ __u32 reqflags;
+ __u16 size;
+ __u8 *data = NULL;
int ret;
/* Find the extension unit. */
list_for_each_entry(entity, &chain->entities, chain) {
if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT &&
- entity->id == xctrl->unit)
+ entity->id == xqry->unit)
break;
}
- if (entity->id != xctrl->unit) {
+ if (entity->id != xqry->unit) {
uvc_trace(UVC_TRACE_CONTROL, "Extension unit %u not found.\n",
- xctrl->unit);
- return -EINVAL;
+ xqry->unit);
+ return -ENOENT;
}
/* Find the control and perform delayed initialization if needed. */
for (i = 0; i < entity->ncontrols; ++i) {
ctrl = &entity->controls[i];
- if (ctrl->index == xctrl->selector - 1) {
+ if (ctrl->index == xqry->selector - 1) {
found = 1;
break;
}
@@ -1377,8 +1447,8 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
if (!found) {
uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u not found.\n",
- entity->extension.guidExtensionCode, xctrl->selector);
- return -EINVAL;
+ entity->extension.guidExtensionCode, xqry->selector);
+ return -ENOENT;
}
if (mutex_lock_interruptible(&chain->ctrl_mutex))
@@ -1390,43 +1460,72 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
goto done;
}
- /* Validate control data size. */
- if (ctrl->info.size != xctrl->size) {
+ /* Validate the required buffer size and flags for the request */
+ reqflags = 0;
+ size = ctrl->info.size;
+
+ switch (xqry->query) {
+ case UVC_GET_CUR:
+ reqflags = UVC_CTRL_FLAG_GET_CUR;
+ break;
+ case UVC_GET_MIN:
+ reqflags = UVC_CTRL_FLAG_GET_MIN;
+ break;
+ case UVC_GET_MAX:
+ reqflags = UVC_CTRL_FLAG_GET_MAX;
+ break;
+ case UVC_GET_DEF:
+ reqflags = UVC_CTRL_FLAG_GET_DEF;
+ break;
+ case UVC_GET_RES:
+ reqflags = UVC_CTRL_FLAG_GET_RES;
+ break;
+ case UVC_SET_CUR:
+ reqflags = UVC_CTRL_FLAG_SET_CUR;
+ break;
+ case UVC_GET_LEN:
+ size = 2;
+ break;
+ case UVC_GET_INFO:
+ size = 1;
+ break;
+ default:
ret = -EINVAL;
goto done;
}
- if ((set && !(ctrl->info.flags & UVC_CONTROL_SET_CUR)) ||
- (!set && !(ctrl->info.flags & UVC_CONTROL_GET_CUR))) {
- ret = -EINVAL;
+ if (size != xqry->size) {
+ ret = -ENOBUFS;
goto done;
}
- memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
- ctrl->info.size);
- data = uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT);
- restore = set;
+ if (reqflags && !(ctrl->info.flags & reqflags)) {
+ ret = -EBADRQC;
+ goto done;
+ }
- if (set && copy_from_user(data, xctrl->data, xctrl->size)) {
+ data = kmalloc(size, GFP_KERNEL);
+ if (data == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ if (xqry->query == UVC_SET_CUR &&
+ copy_from_user(data, xqry->data, size)) {
ret = -EFAULT;
goto done;
}
- ret = uvc_query_ctrl(chain->dev, set ? UVC_SET_CUR : UVC_GET_CUR,
- xctrl->unit, chain->dev->intfnum, xctrl->selector,
- data, xctrl->size);
+ ret = uvc_query_ctrl(chain->dev, xqry->query, xqry->unit,
+ chain->dev->intfnum, xqry->selector, data, size);
if (ret < 0)
goto done;
- if (!set && copy_to_user(xctrl->data, data, xctrl->size))
+ if (xqry->query != UVC_SET_CUR &&
+ copy_to_user(xqry->data, data, size))
ret = -EFAULT;
done:
- if (ret && restore)
- memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
- xctrl->size);
-
+ kfree(data);
mutex_unlock(&chain->ctrl_mutex);
return ret;
}
@@ -1458,7 +1557,7 @@ int uvc_ctrl_resume_device(struct uvc_device *dev)
ctrl = &entity->controls[i];
if (!ctrl->initialized || !ctrl->modified ||
- (ctrl->info.flags & UVC_CONTROL_RESTORE) == 0)
+ (ctrl->info.flags & UVC_CTRL_FLAG_RESTORE) == 0)
continue;
printk(KERN_INFO "restoring control %pUl/%u/%u\n",
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index 6459b8cba223..b6eae48d7fb8 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -84,6 +84,11 @@ static struct uvc_format_desc uvc_fmts[] = {
.fcc = V4L2_PIX_FMT_YUV420,
},
{
+ .name = "YUV 4:2:0 (M420)",
+ .guid = UVC_GUID_FORMAT_M420,
+ .fcc = V4L2_PIX_FMT_M420,
+ },
+ {
.name = "YUV 4:2:2 (UYVY)",
.guid = UVC_GUID_FORMAT_UYVY,
.fcc = V4L2_PIX_FMT_UYVY,
@@ -103,6 +108,11 @@ static struct uvc_format_desc uvc_fmts[] = {
.guid = UVC_GUID_FORMAT_BY8,
.fcc = V4L2_PIX_FMT_SBGGR8,
},
+ {
+ .name = "RGB565",
+ .guid = UVC_GUID_FORMAT_RGBP,
+ .fcc = V4L2_PIX_FMT_RGB565,
+ },
};
/* ------------------------------------------------------------------------
@@ -238,7 +248,7 @@ uint32_t uvc_fraction_to_interval(uint32_t numerator, uint32_t denominator)
* Terminal and unit management
*/
-static struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id)
+struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id)
{
struct uvc_entity *entity;
@@ -785,9 +795,12 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id,
struct uvc_entity *entity;
unsigned int num_inputs;
unsigned int size;
+ unsigned int i;
+ extra_size = ALIGN(extra_size, sizeof(*entity->pads));
num_inputs = (type & UVC_TERM_OUTPUT) ? num_pads : num_pads - 1;
- size = sizeof(*entity) + extra_size + num_inputs;
+ size = sizeof(*entity) + extra_size + sizeof(*entity->pads) * num_pads
+ + num_inputs;
entity = kzalloc(size, GFP_KERNEL);
if (entity == NULL)
return NULL;
@@ -795,8 +808,17 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id,
entity->id = id;
entity->type = type;
+ entity->num_links = 0;
+ entity->num_pads = num_pads;
+ entity->pads = ((void *)(entity + 1)) + extra_size;
+
+ for (i = 0; i < num_inputs; ++i)
+ entity->pads[i].flags = MEDIA_PAD_FL_SINK;
+ if (!UVC_ENTITY_IS_OTERM(entity))
+ entity->pads[num_pads-1].flags = MEDIA_PAD_FL_SOURCE;
+
entity->bNrInPins = num_inputs;
- entity->baSourceID = ((__u8 *)entity) + sizeof(*entity) + extra_size;
+ entity->baSourceID = (__u8 *)(&entity->pads[num_pads]);
return entity;
}
@@ -1575,6 +1597,13 @@ static void uvc_delete(struct uvc_device *dev)
uvc_status_cleanup(dev);
uvc_ctrl_cleanup_device(dev);
+ if (dev->vdev.dev)
+ v4l2_device_unregister(&dev->vdev);
+#ifdef CONFIG_MEDIA_CONTROLLER
+ if (media_devnode_is_registered(&dev->mdev.devnode))
+ media_device_unregister(&dev->mdev);
+#endif
+
list_for_each_safe(p, n, &dev->chains) {
struct uvc_video_chain *chain;
chain = list_entry(p, struct uvc_video_chain, list);
@@ -1584,6 +1613,13 @@ static void uvc_delete(struct uvc_device *dev)
list_for_each_safe(p, n, &dev->entities) {
struct uvc_entity *entity;
entity = list_entry(p, struct uvc_entity, list);
+#ifdef CONFIG_MEDIA_CONTROLLER
+ uvc_mc_cleanup_entity(entity);
+#endif
+ if (entity->vdev) {
+ video_device_release(entity->vdev);
+ entity->vdev = NULL;
+ }
kfree(entity);
}
@@ -1606,8 +1642,6 @@ static void uvc_release(struct video_device *vdev)
struct uvc_streaming *stream = video_get_drvdata(vdev);
struct uvc_device *dev = stream->dev;
- video_device_release(vdev);
-
/* Decrement the registered streams count and delete the device when it
* reaches zero.
*/
@@ -1672,7 +1706,7 @@ static int uvc_register_video(struct uvc_device *dev,
* unregistered before the reference is released, so we don't need to
* get another one.
*/
- vdev->parent = &dev->intf->dev;
+ vdev->v4l2_dev = &dev->vdev;
vdev->fops = &uvc_fops;
vdev->release = uvc_release;
strlcpy(vdev->name, dev->name, sizeof vdev->name);
@@ -1721,6 +1755,8 @@ static int uvc_register_terms(struct uvc_device *dev,
ret = uvc_register_video(dev, stream);
if (ret < 0)
return ret;
+
+ term->vdev = stream->vdev;
}
return 0;
@@ -1735,6 +1771,14 @@ static int uvc_register_chains(struct uvc_device *dev)
ret = uvc_register_terms(dev, chain);
if (ret < 0)
return ret;
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+ ret = uvc_mc_register_entities(chain);
+ if (ret < 0) {
+ uvc_printk(KERN_INFO, "Failed to register entites "
+ "(%d).\n", ret);
+ }
+#endif
}
return 0;
@@ -1804,6 +1848,24 @@ static int uvc_probe(struct usb_interface *intf,
"linux-uvc-devel mailing list.\n");
}
+ /* Register the media and V4L2 devices. */
+#ifdef CONFIG_MEDIA_CONTROLLER
+ dev->mdev.dev = &intf->dev;
+ strlcpy(dev->mdev.model, dev->name, sizeof(dev->mdev.model));
+ if (udev->serial)
+ strlcpy(dev->mdev.serial, udev->serial,
+ sizeof(dev->mdev.serial));
+ strcpy(dev->mdev.bus_info, udev->devpath);
+ dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
+ dev->mdev.driver_version = DRIVER_VERSION_NUMBER;
+ if (media_device_register(&dev->mdev) < 0)
+ goto error;
+
+ dev->vdev.mdev = &dev->mdev;
+#endif
+ if (v4l2_device_register(&intf->dev, &dev->vdev) < 0)
+ goto error;
+
/* Initialize controls. */
if (uvc_ctrl_init_device(dev) < 0)
goto error;
@@ -1812,7 +1874,7 @@ static int uvc_probe(struct usb_interface *intf,
if (uvc_scan_device(dev) < 0)
goto error;
- /* Register video devices. */
+ /* Register video device nodes. */
if (uvc_register_chains(dev) < 0)
goto error;
@@ -2077,6 +2139,15 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* Hercules Classic Silver */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x06f8,
+ .idProduct = 0x300c,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_FIX_BANDWIDTH },
/* ViMicro Vega */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2123,6 +2194,15 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* JMicron USB2.0 XGA WebCam */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x152d,
+ .idProduct = 0x0310,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
/* Syntek (HP Spartan) */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
diff --git a/drivers/media/video/uvc/uvc_entity.c b/drivers/media/video/uvc/uvc_entity.c
new file mode 100644
index 000000000000..ede7852bb1df
--- /dev/null
+++ b/drivers/media/video/uvc/uvc_entity.c
@@ -0,0 +1,118 @@
+/*
+ * uvc_entity.c -- USB Video Class driver
+ *
+ * Copyright (C) 2005-2011
+ * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-common.h>
+
+#include "uvcvideo.h"
+
+/* ------------------------------------------------------------------------
+ * Video subdevices registration and unregistration
+ */
+
+static int uvc_mc_register_entity(struct uvc_video_chain *chain,
+ struct uvc_entity *entity)
+{
+ const u32 flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE;
+ struct uvc_entity *remote;
+ unsigned int i;
+ u8 remote_pad;
+ int ret;
+
+ for (i = 0; i < entity->num_pads; ++i) {
+ struct media_entity *source;
+ struct media_entity *sink;
+
+ if (!(entity->pads[i].flags & MEDIA_PAD_FL_SINK))
+ continue;
+
+ remote = uvc_entity_by_id(chain->dev, entity->baSourceID[i]);
+ if (remote == NULL)
+ return -EINVAL;
+
+ source = (UVC_ENTITY_TYPE(remote) == UVC_TT_STREAMING)
+ ? &remote->vdev->entity : &remote->subdev.entity;
+ sink = (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING)
+ ? &entity->vdev->entity : &entity->subdev.entity;
+
+ remote_pad = remote->num_pads - 1;
+ ret = media_entity_create_link(source, remote_pad,
+ sink, i, flags);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING)
+ ret = v4l2_device_register_subdev(&chain->dev->vdev,
+ &entity->subdev);
+
+ return ret;
+}
+
+static struct v4l2_subdev_ops uvc_subdev_ops = {
+};
+
+void uvc_mc_cleanup_entity(struct uvc_entity *entity)
+{
+ if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING)
+ media_entity_cleanup(&entity->subdev.entity);
+ else if (entity->vdev != NULL)
+ media_entity_cleanup(&entity->vdev->entity);
+}
+
+static int uvc_mc_init_entity(struct uvc_entity *entity)
+{
+ int ret;
+
+ if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) {
+ v4l2_subdev_init(&entity->subdev, &uvc_subdev_ops);
+ strlcpy(entity->subdev.name, entity->name,
+ sizeof(entity->subdev.name));
+
+ ret = media_entity_init(&entity->subdev.entity,
+ entity->num_pads, entity->pads, 0);
+ } else
+ ret = media_entity_init(&entity->vdev->entity,
+ entity->num_pads, entity->pads, 0);
+
+ return ret;
+}
+
+int uvc_mc_register_entities(struct uvc_video_chain *chain)
+{
+ struct uvc_entity *entity;
+ int ret;
+
+ list_for_each_entry(entity, &chain->entities, chain) {
+ ret = uvc_mc_init_entity(entity);
+ if (ret < 0) {
+ uvc_printk(KERN_INFO, "Failed to initialize entity for "
+ "entity %u\n", entity->id);
+ return ret;
+ }
+ }
+
+ list_for_each_entry(entity, &chain->entities, chain) {
+ ret = uvc_mc_register_entity(chain, entity);
+ if (ret < 0) {
+ uvc_printk(KERN_INFO, "Failed to register entity for "
+ "entity %u\n", entity->id);
+ return ret;
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c
index f14581bd707f..109a06384a8f 100644
--- a/drivers/media/video/uvc/uvc_queue.c
+++ b/drivers/media/video/uvc/uvc_queue.c
@@ -424,7 +424,7 @@ int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
break;
}
- if (i == queue->count || size != queue->buf_size) {
+ if (i == queue->count || PAGE_ALIGN(size) != queue->buf_size) {
ret = -EINVAL;
goto done;
}
@@ -436,6 +436,7 @@ int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
vma->vm_flags |= VM_IO;
addr = (unsigned long)queue->mem + buffer->buf.m.offset;
+#ifdef CONFIG_MMU
while (size > 0) {
page = vmalloc_to_page((void *)addr);
if ((ret = vm_insert_page(vma, start, page)) < 0)
@@ -445,6 +446,7 @@ int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
addr += PAGE_SIZE;
size -= PAGE_SIZE;
}
+#endif
vma->vm_ops = &uvc_vm_ops;
vma->vm_private_data = buffer;
@@ -488,6 +490,36 @@ done:
return mask;
}
+#ifndef CONFIG_MMU
+/*
+ * Get unmapped area.
+ *
+ * NO-MMU arch need this function to make mmap() work correctly.
+ */
+unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
+ unsigned long pgoff)
+{
+ struct uvc_buffer *buffer;
+ unsigned int i;
+ unsigned long ret;
+
+ mutex_lock(&queue->mutex);
+ for (i = 0; i < queue->count; ++i) {
+ buffer = &queue->buffer[i];
+ if ((buffer->buf.m.offset >> PAGE_SHIFT) == pgoff)
+ break;
+ }
+ if (i == queue->count) {
+ ret = -EINVAL;
+ goto done;
+ }
+ ret = (unsigned long)queue->mem + buffer->buf.m.offset;
+done:
+ mutex_unlock(&queue->mutex);
+ return ret;
+}
+#endif
+
/*
* Enable or disable the video buffers queue.
*
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index 9005a8d9d5f8..543a80395b7f 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -538,6 +538,20 @@ static int uvc_v4l2_release(struct file *file)
return 0;
}
+static void uvc_v4l2_ioctl_warn(void)
+{
+ static int warned;
+
+ if (warned)
+ return;
+
+ uvc_printk(KERN_INFO, "Deprecated UVCIOC_CTRL_{ADD,MAP_OLD,GET,SET} "
+ "ioctls will be removed in 2.6.42.\n");
+ uvc_printk(KERN_INFO, "See http://www.ideasonboard.org/uvc/upgrade/ "
+ "for upgrade instructions.\n");
+ warned = 1;
+}
+
static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *vdev = video_devdata(file);
@@ -1018,21 +1032,40 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
uvc_trace(UVC_TRACE_IOCTL, "Unsupported ioctl 0x%08x\n", cmd);
return -EINVAL;
- /* Dynamic controls. */
- case UVCIOC_CTRL_ADD:
- /* Legacy ioctl, kept for API compatibility reasons */
+ /* Dynamic controls. UVCIOC_CTRL_ADD, UVCIOC_CTRL_MAP_OLD,
+ * UVCIOC_CTRL_GET and UVCIOC_CTRL_SET are deprecated and scheduled for
+ * removal in 2.6.42.
+ */
+ case __UVCIOC_CTRL_ADD:
+ uvc_v4l2_ioctl_warn();
return -EEXIST;
- case UVCIOC_CTRL_MAP_OLD:
+ case __UVCIOC_CTRL_MAP_OLD:
+ uvc_v4l2_ioctl_warn();
+ case __UVCIOC_CTRL_MAP:
case UVCIOC_CTRL_MAP:
return uvc_ioctl_ctrl_map(chain, arg,
- cmd == UVCIOC_CTRL_MAP_OLD);
+ cmd == __UVCIOC_CTRL_MAP_OLD);
- case UVCIOC_CTRL_GET:
- return uvc_xu_ctrl_query(chain, arg, 0);
+ case __UVCIOC_CTRL_GET:
+ case __UVCIOC_CTRL_SET:
+ {
+ struct uvc_xu_control *xctrl = arg;
+ struct uvc_xu_control_query xqry = {
+ .unit = xctrl->unit,
+ .selector = xctrl->selector,
+ .query = cmd == __UVCIOC_CTRL_GET
+ ? UVC_GET_CUR : UVC_SET_CUR,
+ .size = xctrl->size,
+ .data = xctrl->data,
+ };
+
+ uvc_v4l2_ioctl_warn();
+ return uvc_xu_ctrl_query(chain, &xqry);
+ }
- case UVCIOC_CTRL_SET:
- return uvc_xu_ctrl_query(chain, arg, 1);
+ case UVCIOC_CTRL_QUERY:
+ return uvc_xu_ctrl_query(chain, arg);
default:
uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n", cmd);
@@ -1081,6 +1114,20 @@ static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait)
return uvc_queue_poll(&stream->queue, file, wait);
}
+#ifndef CONFIG_MMU
+static unsigned long uvc_v4l2_get_unmapped_area(struct file *file,
+ unsigned long addr, unsigned long len, unsigned long pgoff,
+ unsigned long flags)
+{
+ struct uvc_fh *handle = file->private_data;
+ struct uvc_streaming *stream = handle->stream;
+
+ uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_get_unmapped_area\n");
+
+ return uvc_queue_get_unmapped_area(&stream->queue, pgoff);
+}
+#endif
+
const struct v4l2_file_operations uvc_fops = {
.owner = THIS_MODULE,
.open = uvc_v4l2_open,
@@ -1089,5 +1136,8 @@ const struct v4l2_file_operations uvc_fops = {
.read = uvc_v4l2_read,
.mmap = uvc_v4l2_mmap,
.poll = uvc_v4l2_poll,
+#ifndef CONFIG_MMU
+ .get_unmapped_area = uvc_v4l2_get_unmapped_area,
+#endif
};
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index 45f01e7e13d2..20107fd3574d 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -4,6 +4,14 @@
#include <linux/kernel.h>
#include <linux/videodev2.h>
+#ifndef __KERNEL__
+/*
+ * This header provides binary compatibility with applications using the private
+ * uvcvideo API. This API is deprecated and will be removed in 2.6.42.
+ * Applications should be recompiled against the public linux/uvcvideo.h header.
+ */
+#warn "The uvcvideo.h header is deprecated, use linux/uvcvideo.h instead."
+
/*
* Dynamic controls
*/
@@ -23,32 +31,18 @@
#define UVC_CONTROL_GET_MAX (1 << 3)
#define UVC_CONTROL_GET_RES (1 << 4)
#define UVC_CONTROL_GET_DEF (1 << 5)
-/* Control should be saved at suspend and restored at resume. */
#define UVC_CONTROL_RESTORE (1 << 6)
-/* Control can be updated by the camera. */
#define UVC_CONTROL_AUTO_UPDATE (1 << 7)
#define UVC_CONTROL_GET_RANGE (UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_MIN | \
UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | \
UVC_CONTROL_GET_DEF)
-struct uvc_xu_control_info {
- __u8 entity[16];
- __u8 index;
- __u8 selector;
- __u16 size;
- __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];
@@ -57,7 +51,7 @@ struct uvc_xu_control_mapping {
__u8 size;
__u8 offset;
- enum v4l2_ctrl_type v4l2_type;
+ __u32 v4l2_type;
__u32 data_type;
struct uvc_menu_info __user *menu_info;
@@ -66,6 +60,20 @@ struct uvc_xu_control_mapping {
__u32 reserved[4];
};
+#endif
+
+struct uvc_xu_control_info {
+ __u8 entity[16];
+ __u8 index;
+ __u8 selector;
+ __u16 size;
+ __u32 flags;
+};
+
+struct uvc_xu_control_mapping_old {
+ __u8 reserved[64];
+};
+
struct uvc_xu_control {
__u8 unit;
__u8 selector;
@@ -73,16 +81,28 @@ struct uvc_xu_control {
__u8 __user *data;
};
+#ifndef __KERNEL__
#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)
+#else
+#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)
+#endif
#ifdef __KERNEL__
#include <linux/poll.h>
+#include <linux/usb.h>
#include <linux/usb/video.h>
+#include <linux/uvcvideo.h>
+#include <media/media-device.h>
+#include <media/v4l2-device.h>
/* --------------------------------------------------------------------------
* UVC constants
@@ -152,13 +172,19 @@ struct uvc_xu_control {
#define UVC_GUID_FORMAT_BY8 \
{ 'B', 'Y', '8', ' ', 0x00, 0x00, 0x10, 0x00, \
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_RGBP \
+ { 'R', 'G', 'B', 'P', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_M420 \
+ { 'M', '4', '2', '0', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
/* ------------------------------------------------------------------------
* Driver specific constants.
*/
-#define DRIVER_VERSION_NUMBER KERNEL_VERSION(1, 0, 0)
-#define DRIVER_VERSION "v1.0.0"
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(1, 1, 0)
+#define DRIVER_VERSION "v1.1.0"
/* Number of isochronous URBs. */
#define UVC_URBS 5
@@ -278,6 +304,13 @@ struct uvc_entity {
__u16 type;
char name[64];
+ /* Media controller-related fields. */
+ struct video_device *vdev;
+ struct v4l2_subdev subdev;
+ unsigned int num_pads;
+ unsigned int num_links;
+ struct media_pad *pads;
+
union {
struct {
__u16 wObjectiveFocalLengthMin;
@@ -481,6 +514,10 @@ struct uvc_device {
atomic_t nmappings;
/* Video control interface */
+#ifdef CONFIG_MEDIA_CONTROLLER
+ struct media_device mdev;
+#endif
+ struct v4l2_device vdev;
__u16 uvc_version;
__u32 clock_frequency;
@@ -560,6 +597,8 @@ extern unsigned int uvc_timeout_param;
/* Core driver */
extern struct uvc_driver uvc_driver;
+extern struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id);
+
/* Video buffers queue management. */
extern void uvc_queue_init(struct uvc_video_queue *queue,
enum v4l2_buf_type type, int drop_corrupted);
@@ -580,6 +619,10 @@ extern int uvc_queue_mmap(struct uvc_video_queue *queue,
struct vm_area_struct *vma);
extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
struct file *file, poll_table *wait);
+#ifndef CONFIG_MMU
+extern unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
+ unsigned long pgoff);
+#endif
extern int uvc_queue_allocated(struct uvc_video_queue *queue);
static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
{
@@ -589,6 +632,10 @@ static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
/* V4L2 interface */
extern const struct v4l2_file_operations uvc_fops;
+/* Media controller */
+extern int uvc_mc_register_entities(struct uvc_video_chain *chain);
+extern void uvc_mc_cleanup_entity(struct uvc_entity *entity);
+
/* Video */
extern int uvc_video_init(struct uvc_streaming *stream);
extern int uvc_video_suspend(struct uvc_streaming *stream);
@@ -638,7 +685,7 @@ extern int uvc_ctrl_set(struct uvc_video_chain *chain,
struct v4l2_ext_control *xctrl);
extern int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
- struct uvc_xu_control *ctrl, int set);
+ struct uvc_xu_control_query *xqry);
/* Utility functions */
extern void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator,
@@ -655,4 +702,3 @@ void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream,
#endif /* __KERNEL__ */
#endif
-
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 6dc7196296b3..19d5ae293780 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -352,6 +352,23 @@ static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return ret;
}
+#ifdef CONFIG_MMU
+#define v4l2_get_unmapped_area NULL
+#else
+static unsigned long v4l2_get_unmapped_area(struct file *filp,
+ unsigned long addr, unsigned long len, unsigned long pgoff,
+ unsigned long flags)
+{
+ struct video_device *vdev = video_devdata(filp);
+
+ if (!vdev->fops->get_unmapped_area)
+ return -ENOSYS;
+ if (!video_is_registered(vdev))
+ return -ENODEV;
+ return vdev->fops->get_unmapped_area(filp, addr, len, pgoff, flags);
+}
+#endif
+
static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
{
struct video_device *vdev = video_devdata(filp);
@@ -454,6 +471,7 @@ static const struct file_operations v4l2_fops = {
.read = v4l2_read,
.write = v4l2_write,
.open = v4l2_open,
+ .get_unmapped_area = v4l2_get_unmapped_area,
.mmap = v4l2_mmap,
.unlocked_ioctl = v4l2_ioctl,
#ifdef CONFIG_COMPAT
diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c
index 8c780c2d937b..85d3048c1d67 100644
--- a/drivers/media/video/via-camera.c
+++ b/drivers/media/video/via-camera.c
@@ -29,6 +29,7 @@
#include "via-camera.h"
+MODULE_ALIAS("platform:viafb-camera");
MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
MODULE_DESCRIPTION("VIA framebuffer-based camera controller driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/zoran/zoran_card.c b/drivers/media/video/zoran/zoran_card.c
index 9f2bac519647..79b04ac0f1ad 100644
--- a/drivers/media/video/zoran/zoran_card.c
+++ b/drivers/media/video/zoran/zoran_card.c
@@ -64,14 +64,6 @@ static int card[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 };
module_param_array(card, int, NULL, 0444);
MODULE_PARM_DESC(card, "Card type");
-static int encoder[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 };
-module_param_array(encoder, int, NULL, 0444);
-MODULE_PARM_DESC(encoder, "Video encoder chip");
-
-static int decoder[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 };
-module_param_array(decoder, int, NULL, 0444);
-MODULE_PARM_DESC(decoder, "Video decoder chip");
-
/*
The video mem address of the video card.
The driver has a little database for some videocards
@@ -1230,7 +1222,7 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
mutex_init(&zr->other_lock);
if (pci_enable_device(pdev))
goto zr_unreg;
- pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision);
+ zr->revision = zr->pci_dev->revision;
dprintk(1,
KERN_INFO
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index fa15e853d4e8..7956a10f9488 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -83,19 +83,18 @@ MODULE_VERSION(my_VERSION);
static int mpt_msi_enable_spi;
module_param(mpt_msi_enable_spi, int, 0);
-MODULE_PARM_DESC(mpt_msi_enable_spi, " Enable MSI Support for SPI \
- controllers (default=0)");
+MODULE_PARM_DESC(mpt_msi_enable_spi,
+ " Enable MSI Support for SPI controllers (default=0)");
static int mpt_msi_enable_fc;
module_param(mpt_msi_enable_fc, int, 0);
-MODULE_PARM_DESC(mpt_msi_enable_fc, " Enable MSI Support for FC \
- controllers (default=0)");
+MODULE_PARM_DESC(mpt_msi_enable_fc,
+ " Enable MSI Support for FC controllers (default=0)");
static int mpt_msi_enable_sas;
module_param(mpt_msi_enable_sas, int, 0);
-MODULE_PARM_DESC(mpt_msi_enable_sas, " Enable MSI Support for SAS \
- controllers (default=0)");
-
+MODULE_PARM_DESC(mpt_msi_enable_sas,
+ " Enable MSI Support for SAS controllers (default=0)");
static int mpt_channel_mapping;
module_param(mpt_channel_mapping, int, 0);
@@ -105,15 +104,14 @@ static int mpt_debug_level;
static int mpt_set_debug_level(const char *val, struct kernel_param *kp);
module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int,
&mpt_debug_level, 0600);
-MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h \
- - (default=0)");
+MODULE_PARM_DESC(mpt_debug_level,
+ " debug level - refer to mptdebug.h - (default=0)");
int mpt_fwfault_debug;
EXPORT_SYMBOL(mpt_fwfault_debug);
module_param(mpt_fwfault_debug, int, 0600);
-MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault"
- " and halt Firmware on fault - (default=0)");
-
+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];
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index 1735c84ff757..fe902338539b 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.18"
-#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.18"
+#define MPT_LINUX_VERSION_COMMON "3.04.19"
+#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.19"
#define WHAT_MAGIC_STRING "@" "(" "#" ")"
#define show_mptmod_ver(s,ver) \
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index 66f94125de4e..7596aecd5072 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -5012,7 +5012,6 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
(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;
@@ -5023,7 +5022,8 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
"LogInfo (0x%x) available for "
"INTERNAL_DEVICE_RESET"
"fw_id %d fw_channel %d\n", ioc->name,
- log_info, id, channel));
+ le32_to_cpu(reply->IOCLogInfo),
+ id, channel));
if (vtarget->raidVolume) {
devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"Skipping Raid Volume for inDMD\n",
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index 0d9b82a44540..a1d4ee6671be 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -1415,11 +1415,8 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
dmfprintk(ioc, printk(MYIOC_s_DEBUG_FMT "qcmd: SCpnt=%p, done()=%p\n",
ioc->name, SCpnt, done));
- if (ioc->taskmgmt_quiesce_io) {
- dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "qcmd: SCpnt=%p timeout + 60HZ\n",
- ioc->name, SCpnt));
+ if (ioc->taskmgmt_quiesce_io)
return SCSI_MLQUEUE_HOST_BUSY;
- }
/*
* Put together a MPT SCSI request...
@@ -1773,7 +1770,6 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
int scpnt_idx;
int retval;
VirtDevice *vdevice;
- ulong sn = SCpnt->serial_number;
MPT_ADAPTER *ioc;
/* If we can't locate our host adapter structure, return FAILED status.
@@ -1859,8 +1855,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
vdevice->vtarget->id, vdevice->lun,
ctx2abort, mptscsih_get_tm_timeout(ioc));
- if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx &&
- SCpnt->serial_number == sn) {
+ if (SCPNT_TO_LOOKUP_IDX(ioc, SCpnt) == scpnt_idx) {
dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
"task abort: command still in active list! (sc=%p)\n",
ioc->name, SCpnt));
@@ -1873,9 +1868,9 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
}
out:
- printk(MYIOC_s_INFO_FMT "task abort: %s (rv=%04x) (sc=%p) (sn=%ld)\n",
+ printk(MYIOC_s_INFO_FMT "task abort: %s (rv=%04x) (sc=%p)\n",
ioc->name, ((retval == SUCCESS) ? "SUCCESS" : "FAILED"), retval,
- SCpnt, SCpnt->serial_number);
+ SCpnt);
return retval;
}
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index 6d9568d2ec59..8f61ba6aac23 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -867,6 +867,10 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget,
struct _x_config_parms cfg;
struct _CONFIG_PAGE_HEADER hdr;
int err = -EBUSY;
+ u32 nego_parms;
+ u32 period;
+ struct scsi_device *sdev;
+ int i;
/* don't allow updating nego parameters on RAID devices */
if (starget->channel == 0 &&
@@ -904,6 +908,24 @@ static int mptspi_write_spi_device_pg1(struct scsi_target *starget,
pg1->Header.PageNumber = hdr.PageNumber;
pg1->Header.PageType = hdr.PageType;
+ nego_parms = le32_to_cpu(pg1->RequestedParameters);
+ period = (nego_parms & MPI_SCSIDEVPAGE1_RP_MIN_SYNC_PERIOD_MASK) >>
+ MPI_SCSIDEVPAGE1_RP_SHIFT_MIN_SYNC_PERIOD;
+ if (period == 8) {
+ /* Turn on inline data padding for TAPE when running U320 */
+ for (i = 0 ; i < 16; i++) {
+ sdev = scsi_device_lookup_by_target(starget, i);
+ if (sdev && sdev->type == TYPE_TAPE) {
+ sdev_printk(KERN_DEBUG, sdev, MYIOC_s_FMT
+ "IDP:ON\n", ioc->name);
+ nego_parms |= MPI_SCSIDEVPAGE1_RP_IDP;
+ pg1->RequestedParameters =
+ cpu_to_le32(nego_parms);
+ break;
+ }
+ }
+ }
+
mptspi_print_write_nego(hd, starget, le32_to_cpu(pg1->RequestedParameters));
if (mpt_config(ioc, &cfg)) {
diff --git a/drivers/message/i2o/README.ioctl b/drivers/message/i2o/README.ioctl
index 65c0c47aeb79..5fb195af43e2 100644
--- a/drivers/message/i2o/README.ioctl
+++ b/drivers/message/i2o/README.ioctl
@@ -110,7 +110,7 @@ V. Getting Logical Configuration Table
ENOBUFS Buffer not large enough. If this occurs, the required
buffer length is written into *(lct->reslen)
-VI. Settting Parameters
+VI. Setting Parameters
SYNOPSIS
diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c
index f003957e8e1c..74fbe56321ff 100644
--- a/drivers/message/i2o/i2o_scsi.c
+++ b/drivers/message/i2o/i2o_scsi.c
@@ -361,7 +361,7 @@ static int i2o_scsi_reply(struct i2o_controller *c, u32 m,
*/
error = le32_to_cpu(msg->body[0]);
- osm_debug("Completed %ld\n", cmd->serial_number);
+ osm_debug("Completed %0x%p\n", cmd);
cmd->result = error & 0xff;
/*
@@ -678,7 +678,7 @@ static int i2o_scsi_queuecommand_lck(struct scsi_cmnd *SCpnt,
/* Queue the message */
i2o_msg_post(c, msg);
- osm_debug("Issued %ld\n", SCpnt->serial_number);
+ osm_debug("Issued %0x%p\n", SCpnt);
return 0;
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c
index 011cb6ce861b..17dfe9bb6d27 100644
--- a/drivers/mfd/88pm860x-core.c
+++ b/drivers/mfd/88pm860x-core.c
@@ -21,13 +21,13 @@
#define INT_STATUS_NUM 3
-static struct resource bk_resources[] __initdata = {
+static struct resource bk_resources[] __devinitdata = {
{PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_IO,},
{PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_IO,},
{PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO,},
};
-static struct resource led_resources[] __initdata = {
+static struct resource led_resources[] __devinitdata = {
{PM8606_LED1_RED, PM8606_LED1_RED, "led0-red", IORESOURCE_IO,},
{PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_IO,},
{PM8606_LED1_BLUE, PM8606_LED1_BLUE, "led0-blue", IORESOURCE_IO,},
@@ -36,7 +36,7 @@ static struct resource led_resources[] __initdata = {
{PM8606_LED2_BLUE, PM8606_LED2_BLUE, "led1-blue", IORESOURCE_IO,},
};
-static struct resource regulator_resources[] __initdata = {
+static struct resource regulator_resources[] __devinitdata = {
{PM8607_ID_BUCK1, PM8607_ID_BUCK1, "buck-1", IORESOURCE_IO,},
{PM8607_ID_BUCK2, PM8607_ID_BUCK2, "buck-2", IORESOURCE_IO,},
{PM8607_ID_BUCK3, PM8607_ID_BUCK3, "buck-3", IORESOURCE_IO,},
@@ -57,15 +57,15 @@ static struct resource regulator_resources[] __initdata = {
{PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO,},
};
-static struct resource touch_resources[] __initdata = {
+static struct resource touch_resources[] __devinitdata = {
{PM8607_IRQ_PEN, PM8607_IRQ_PEN, "touch", IORESOURCE_IRQ,},
};
-static struct resource onkey_resources[] __initdata = {
+static struct resource onkey_resources[] __devinitdata = {
{PM8607_IRQ_ONKEY, PM8607_IRQ_ONKEY, "onkey", IORESOURCE_IRQ,},
};
-static struct resource codec_resources[] __initdata = {
+static struct resource codec_resources[] __devinitdata = {
/* Headset microphone insertion or removal */
{PM8607_IRQ_MICIN, PM8607_IRQ_MICIN, "micin", IORESOURCE_IRQ,},
/* Hook-switch press or release */
@@ -76,12 +76,12 @@ static struct resource codec_resources[] __initdata = {
{PM8607_IRQ_AUDIO_SHORT, PM8607_IRQ_AUDIO_SHORT, "audio-short", IORESOURCE_IRQ,},
};
-static struct resource battery_resources[] __initdata = {
+static struct resource battery_resources[] __devinitdata = {
{PM8607_IRQ_CC, PM8607_IRQ_CC, "columb counter", IORESOURCE_IRQ,},
{PM8607_IRQ_BAT, PM8607_IRQ_BAT, "battery", IORESOURCE_IRQ,},
};
-static struct resource charger_resources[] __initdata = {
+static struct resource charger_resources[] __devinitdata = {
{PM8607_IRQ_CHG, PM8607_IRQ_CHG, "charger detect", IORESOURCE_IRQ,},
{PM8607_IRQ_CHG_DONE, PM8607_IRQ_CHG_DONE, "charging done", IORESOURCE_IRQ,},
{PM8607_IRQ_CHG_FAULT, PM8607_IRQ_CHG_FAULT, "charging timeout", IORESOURCE_IRQ,},
@@ -90,13 +90,17 @@ static struct resource charger_resources[] __initdata = {
{PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage", IORESOURCE_IRQ,},
};
-static struct mfd_cell bk_devs[] __initdata = {
+static struct resource rtc_resources[] __devinitdata = {
+ {PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ,},
+};
+
+static struct mfd_cell bk_devs[] = {
{"88pm860x-backlight", 0,},
{"88pm860x-backlight", 1,},
{"88pm860x-backlight", 2,},
};
-static struct mfd_cell led_devs[] __initdata = {
+static struct mfd_cell led_devs[] = {
{"88pm860x-led", 0,},
{"88pm860x-led", 1,},
{"88pm860x-led", 2,},
@@ -105,7 +109,7 @@ static struct mfd_cell led_devs[] __initdata = {
{"88pm860x-led", 5,},
};
-static struct mfd_cell regulator_devs[] __initdata = {
+static struct mfd_cell regulator_devs[] = {
{"88pm860x-regulator", 0,},
{"88pm860x-regulator", 1,},
{"88pm860x-regulator", 2,},
@@ -126,15 +130,15 @@ static struct mfd_cell regulator_devs[] __initdata = {
{"88pm860x-regulator", 17,},
};
-static struct mfd_cell touch_devs[] __initdata = {
+static struct mfd_cell touch_devs[] = {
{"88pm860x-touch", -1,},
};
-static struct mfd_cell onkey_devs[] __initdata = {
+static struct mfd_cell onkey_devs[] = {
{"88pm860x-onkey", -1,},
};
-static struct mfd_cell codec_devs[] __initdata = {
+static struct mfd_cell codec_devs[] = {
{"88pm860x-codec", -1,},
};
@@ -143,11 +147,10 @@ static struct mfd_cell power_devs[] = {
{"88pm860x-charger", -1,},
};
-static struct pm860x_backlight_pdata bk_pdata[ARRAY_SIZE(bk_devs)];
-static struct pm860x_led_pdata led_pdata[ARRAY_SIZE(led_devs)];
-static struct regulator_init_data regulator_pdata[ARRAY_SIZE(regulator_devs)];
-static struct pm860x_touch_pdata touch_pdata;
-static struct pm860x_power_pdata power_pdata;
+static struct mfd_cell rtc_devs[] = {
+ {"88pm860x-rtc", -1,},
+};
+
struct pm860x_irq_data {
int reg;
@@ -501,7 +504,6 @@ static void device_irq_exit(struct pm860x_chip *chip)
}
static void __devinit device_bk_init(struct pm860x_chip *chip,
- struct i2c_client *i2c,
struct pm860x_platform_data *pdata)
{
int ret;
@@ -514,13 +516,12 @@ static void __devinit device_bk_init(struct pm860x_chip *chip,
pdata->num_backlights = ARRAY_SIZE(bk_devs);
for (i = 0; i < pdata->num_backlights; i++) {
- memcpy(&bk_pdata[i], &pdata->backlight[i],
- sizeof(struct pm860x_backlight_pdata));
- bk_devs[i].mfd_data = &bk_pdata[i];
+ bk_devs[i].platform_data = &pdata->backlight[i];
+ bk_devs[i].pdata_size = sizeof(struct pm860x_backlight_pdata);
for (j = 0; j < ARRAY_SIZE(bk_devs); j++) {
id = bk_resources[j].start;
- if (bk_pdata[i].flags != id)
+ if (pdata->backlight[i].flags != id)
continue;
bk_devs[i].num_resources = 1;
@@ -538,7 +539,6 @@ static void __devinit device_bk_init(struct pm860x_chip *chip,
}
static void __devinit device_led_init(struct pm860x_chip *chip,
- struct i2c_client *i2c,
struct pm860x_platform_data *pdata)
{
int ret;
@@ -551,13 +551,12 @@ static void __devinit device_led_init(struct pm860x_chip *chip,
pdata->num_leds = ARRAY_SIZE(led_devs);
for (i = 0; i < pdata->num_leds; i++) {
- memcpy(&led_pdata[i], &pdata->led[i],
- sizeof(struct pm860x_led_pdata));
- led_devs[i].mfd_data = &led_pdata[i];
+ led_devs[i].platform_data = &pdata->led[i];
+ led_devs[i].pdata_size = sizeof(struct pm860x_led_pdata);
for (j = 0; j < ARRAY_SIZE(led_devs); j++) {
id = led_resources[j].start;
- if (led_pdata[i].flags != id)
+ if (pdata->led[i].flags != id)
continue;
led_devs[i].num_resources = 1;
@@ -575,12 +574,11 @@ static void __devinit device_led_init(struct pm860x_chip *chip,
}
static void __devinit device_regulator_init(struct pm860x_chip *chip,
- struct i2c_client *i2c,
struct pm860x_platform_data *pdata)
{
struct regulator_init_data *initdata;
int ret;
- int i, j;
+ int i, seq;
if ((pdata == NULL) || (pdata->regulator == NULL))
return;
@@ -588,41 +586,21 @@ static void __devinit device_regulator_init(struct pm860x_chip *chip,
if (pdata->num_regulators > ARRAY_SIZE(regulator_devs))
pdata->num_regulators = ARRAY_SIZE(regulator_devs);
- for (i = 0, j = -1; i < pdata->num_regulators; i++) {
+ for (i = 0, seq = -1; i < pdata->num_regulators; i++) {
initdata = &pdata->regulator[i];
- if (strstr(initdata->constraints.name, "BUCK")) {
- sscanf(initdata->constraints.name, "BUCK%d", &j);
- /* BUCK1 ~ BUCK3 */
- if ((j < 1) || (j > 3)) {
- dev_err(chip->dev, "Failed to add constraint "
- "(%s)\n", initdata->constraints.name);
- goto out;
- }
- j = (j - 1) + PM8607_ID_BUCK1;
- }
- if (strstr(initdata->constraints.name, "LDO")) {
- sscanf(initdata->constraints.name, "LDO%d", &j);
- /* LDO1 ~ LDO15 */
- if ((j < 1) || (j > 15)) {
- dev_err(chip->dev, "Failed to add constraint "
- "(%s)\n", initdata->constraints.name);
- goto out;
- }
- j = (j - 1) + PM8607_ID_LDO1;
- }
- if (j == -1) {
- dev_err(chip->dev, "Failed to add constraint (%s)\n",
- initdata->constraints.name);
+ seq = *(unsigned int *)initdata->driver_data;
+ if ((seq < 0) || (seq > PM8607_ID_RG_MAX)) {
+ dev_err(chip->dev, "Wrong ID(%d) on regulator(%s)\n",
+ seq, initdata->constraints.name);
goto out;
}
- memcpy(&regulator_pdata[i], &pdata->regulator[i],
- sizeof(struct regulator_init_data));
- regulator_devs[i].mfd_data = &regulator_pdata[i];
+ regulator_devs[i].platform_data = &pdata->regulator[i];
+ regulator_devs[i].pdata_size = sizeof(struct regulator_init_data);
regulator_devs[i].num_resources = 1;
- regulator_devs[i].resources = &regulator_resources[j];
+ regulator_devs[i].resources = &regulator_resources[seq];
ret = mfd_add_devices(chip->dev, 0, &regulator_devs[i], 1,
- &regulator_resources[j], 0);
+ &regulator_resources[seq], 0);
if (ret < 0) {
dev_err(chip->dev, "Failed to add regulator subdev\n");
goto out;
@@ -632,17 +610,35 @@ out:
return;
}
+static void __devinit device_rtc_init(struct pm860x_chip *chip,
+ struct pm860x_platform_data *pdata)
+{
+ int ret;
+
+ if ((pdata == NULL))
+ return;
+
+ rtc_devs[0].platform_data = pdata->rtc;
+ rtc_devs[0].pdata_size = sizeof(struct pm860x_rtc_pdata);
+ rtc_devs[0].num_resources = ARRAY_SIZE(rtc_resources);
+ rtc_devs[0].resources = &rtc_resources[0];
+ ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
+ ARRAY_SIZE(rtc_devs), &rtc_resources[0],
+ chip->irq_base);
+ if (ret < 0)
+ dev_err(chip->dev, "Failed to add rtc subdev\n");
+}
+
static void __devinit device_touch_init(struct pm860x_chip *chip,
- struct i2c_client *i2c,
struct pm860x_platform_data *pdata)
{
int ret;
- if ((pdata == NULL) || (pdata->touch == NULL))
+ if (pdata == NULL)
return;
- memcpy(&touch_pdata, pdata->touch, sizeof(struct pm860x_touch_pdata));
- touch_devs[0].mfd_data = &touch_pdata;
+ touch_devs[0].platform_data = pdata->touch;
+ touch_devs[0].pdata_size = sizeof(struct pm860x_touch_pdata);
touch_devs[0].num_resources = ARRAY_SIZE(touch_resources);
touch_devs[0].resources = &touch_resources[0];
ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
@@ -653,16 +649,15 @@ static void __devinit device_touch_init(struct pm860x_chip *chip,
}
static void __devinit device_power_init(struct pm860x_chip *chip,
- struct i2c_client *i2c,
struct pm860x_platform_data *pdata)
{
int ret;
- if ((pdata == NULL) || (pdata->power == NULL))
+ if (pdata == NULL)
return;
- memcpy(&power_pdata, pdata->power, sizeof(struct pm860x_power_pdata));
- power_devs[0].mfd_data = &power_pdata;
+ power_devs[0].platform_data = pdata->power;
+ power_devs[0].pdata_size = sizeof(struct pm860x_power_pdata);
power_devs[0].num_resources = ARRAY_SIZE(battery_resources);
power_devs[0].resources = &battery_resources[0],
ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 1,
@@ -670,7 +665,8 @@ static void __devinit device_power_init(struct pm860x_chip *chip,
if (ret < 0)
dev_err(chip->dev, "Failed to add battery subdev\n");
- power_devs[1].mfd_data = &power_pdata;
+ power_devs[1].platform_data = pdata->power;
+ power_devs[1].pdata_size = sizeof(struct pm860x_power_pdata);
power_devs[1].num_resources = ARRAY_SIZE(charger_resources);
power_devs[1].resources = &charger_resources[0],
ret = mfd_add_devices(chip->dev, 0, &power_devs[1], 1,
@@ -680,7 +676,6 @@ static void __devinit device_power_init(struct pm860x_chip *chip,
}
static void __devinit device_onkey_init(struct pm860x_chip *chip,
- struct i2c_client *i2c,
struct pm860x_platform_data *pdata)
{
int ret;
@@ -695,7 +690,6 @@ static void __devinit device_onkey_init(struct pm860x_chip *chip,
}
static void __devinit device_codec_init(struct pm860x_chip *chip,
- struct i2c_client *i2c,
struct pm860x_platform_data *pdata)
{
int ret;
@@ -763,11 +757,12 @@ static void __devinit device_8607_init(struct pm860x_chip *chip,
if (ret < 0)
goto out;
- device_regulator_init(chip, i2c, pdata);
- device_onkey_init(chip, i2c, pdata);
- device_touch_init(chip, i2c, pdata);
- device_power_init(chip, i2c, pdata);
- device_codec_init(chip, i2c, pdata);
+ device_regulator_init(chip, pdata);
+ device_rtc_init(chip, pdata);
+ device_onkey_init(chip, pdata);
+ device_touch_init(chip, pdata);
+ device_power_init(chip, pdata);
+ device_codec_init(chip, pdata);
out:
return;
}
@@ -779,8 +774,8 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
switch (chip->id) {
case CHIP_PM8606:
- device_bk_init(chip, chip->client, pdata);
- device_led_init(chip, chip->client, pdata);
+ device_bk_init(chip, pdata);
+ device_led_init(chip, pdata);
break;
case CHIP_PM8607:
device_8607_init(chip, chip->client, pdata);
@@ -790,8 +785,8 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
if (chip->companion) {
switch (chip->id) {
case CHIP_PM8607:
- device_bk_init(chip, chip->companion, pdata);
- device_led_init(chip, chip->companion, pdata);
+ device_bk_init(chip, pdata);
+ device_led_init(chip, pdata);
break;
case CHIP_PM8606:
device_8607_init(chip, chip->companion, pdata);
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 3ed3ff06be5d..b6c267724e14 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -157,6 +157,20 @@ config TPS6507X
This driver can also be built as a module. If so, the module
will be called tps6507x.
+config MFD_TPS6586X
+ bool "TPS6586x Power Management chips"
+ depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
+ select MFD_CORE
+ help
+ If you say yes here you get support for the TPS6586X series of
+ Power Management chips.
+ This driver provides common support for accessing the device,
+ additional drivers must be enabled in order to use the
+ functionality of the device.
+
+ This driver can also be built as a module. If so, the module
+ will be called tps6586x.
+
config MENELAUS
bool "Texas Instruments TWL92330/Menelaus PM chip"
depends on I2C=y && ARCH_OMAP2
@@ -455,6 +469,20 @@ config MFD_PCF50633
facilities, and registers devices for the various functions
so that function-specific drivers can bind to them.
+config PCF50633_ADC
+ tristate "Support for NXP PCF50633 ADC"
+ depends on MFD_PCF50633
+ help
+ Say yes here if you want to include support for ADC in the
+ NXP PCF50633 chip.
+
+config PCF50633_GPIO
+ tristate "Support for NXP PCF50633 GPIO"
+ depends on MFD_PCF50633
+ help
+ Say yes here if you want to include support GPIO for pins on
+ the PCF50633 chip.
+
config MFD_MC13783
tristate
@@ -470,20 +498,6 @@ config MFD_MC13XXX
additional drivers must be enabled in order to use the
functionality of the device.
-config PCF50633_ADC
- tristate "Support for NXP PCF50633 ADC"
- depends on MFD_PCF50633
- help
- Say yes here if you want to include support for ADC in the
- NXP PCF50633 chip.
-
-config PCF50633_GPIO
- tristate "Support for NXP PCF50633 GPIO"
- depends on MFD_PCF50633
- help
- Say yes here if you want to include support GPIO for pins on
- the PCF50633 chip.
-
config ABX500_CORE
bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions"
default y if ARCH_U300 || ARCH_U8500
@@ -538,7 +552,7 @@ config AB8500_CORE
config AB8500_I2C_CORE
bool "AB8500 register access via PRCMU I2C"
- depends on AB8500_CORE && UX500_SOC_DB8500
+ depends on AB8500_CORE && MFD_DB8500_PRCMU
default y
help
This enables register access to the AB8500 chip via PRCMU I2C.
@@ -575,6 +589,26 @@ config AB3550_CORE
LEDs, vibrator, system power and temperature, power management
and ALSA sound.
+config MFD_DB8500_PRCMU
+ bool "ST-Ericsson DB8500 Power Reset Control Management Unit"
+ depends on UX500_SOC_DB8500
+ select MFD_CORE
+ help
+ Select this option to enable support for the DB8500 Power Reset
+ and Control Management Unit. This is basically an autonomous
+ system controller running an XP70 microprocessor, which is accessed
+ through a register map.
+
+config MFD_DB5500_PRCMU
+ bool "ST-Ericsson DB5500 Power Reset Control Management Unit"
+ depends on UX500_SOC_DB5500
+ select MFD_CORE
+ help
+ Select this option to enable support for the DB5500 Power Reset
+ and Control Management Unit. This is basically an autonomous
+ system controller running an XP70 microprocessor, which is accessed
+ through a register map.
+
config MFD_CS5535
tristate "Support for CS5535 and CS5536 southbridge core functions"
select MFD_CORE
@@ -629,20 +663,6 @@ config MFD_JZ4740_ADC
Say yes here if you want support for the ADC unit in the JZ4740 SoC.
This driver is necessary for jz4740-battery and jz4740-hwmon driver.
-config MFD_TPS6586X
- bool "TPS6586x Power Management chips"
- depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
- select MFD_CORE
- help
- If you say yes here you get support for the TPS6586X series of
- Power Management chips.
- This driver provides common support for accessing the device,
- additional drivers must be enabled in order to use the
- functionality of the device.
-
- This driver can also be built as a module. If so, the module
- will be called tps6586x.
-
config MFD_VX855
tristate "Support for VIA VX855/VX875 integrated south bridge"
depends on PCI
@@ -671,6 +691,43 @@ config MFD_OMAP_USB_HOST
This MFD driver does the required setup functionalities for
OMAP USB Host drivers.
+config MFD_PM8XXX
+ tristate
+
+config MFD_PM8921_CORE
+ tristate "Qualcomm PM8921 PMIC chip"
+ depends on MSM_SSBI
+ select MFD_CORE
+ select MFD_PM8XXX
+ help
+ If you say yes to this option, support will be included for the
+ built-in PM8921 PMIC chip.
+
+ This is required if your board has a PM8921 and uses its features,
+ such as: MPPs, GPIOs, regulators, interrupts, and PWM.
+
+ Say M here if you want to include support for PM8921 chip as a module.
+ This will build a module called "pm8921-core".
+
+config MFD_PM8XXX_IRQ
+ bool "Support for Qualcomm PM8xxx IRQ features"
+ depends on MFD_PM8XXX
+ default y if MFD_PM8XXX
+ help
+ This is the IRQ driver for Qualcomm PM 8xxx PMIC chips.
+
+ This is required to use certain other PM 8xxx features, such as GPIO
+ and MPP.
+
+config MFD_TPS65910
+ bool "TPS65910 Power Management chip"
+ depends on I2C=y
+ select MFD_CORE
+ select GPIO_TPS65910
+ help
+ if you say yes here you get support for the TPS65910 series of
+ Power Management chips.
+
endif # MFD_SUPPORT
menu "Multimedia Capabilities Port drivers"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 419caa9d7dcf..efe3cc33ed92 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -74,9 +74,12 @@ obj-$(CONFIG_AB3100_CORE) += ab3100-core.o
obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
obj-$(CONFIG_AB3550_CORE) += ab3550-core.o
obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o
-obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o
obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o
obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o
+obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o
+# ab8500-i2c need to come after db8500-prcmu (which provides the channel)
+obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o
+obj-$(CONFIG_MFD_DB5500_PRCMU) += db5500-prcmu.o
obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o
obj-$(CONFIG_PMIC_ADP5520) += adp5520.o
obj-$(CONFIG_LPC_SCH) += lpc_sch.o
@@ -88,3 +91,6 @@ obj-$(CONFIG_MFD_VX855) += vx855.o
obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o
obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o
obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o
+obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o
+obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o
+obj-$(CONFIG_MFD_TPS65910) += tps65910.o tps65910-irq.o
diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c
index a751927047ac..a20e1c41bed2 100644
--- a/drivers/mfd/ab3100-core.c
+++ b/drivers/mfd/ab3100-core.c
@@ -949,8 +949,10 @@ static int __devinit ab3100_probe(struct i2c_client *client,
goto exit_no_ops;
/* Set up and register the platform devices. */
- for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++)
- ab3100_devs[i].mfd_data = ab3100_plf_data;
+ for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++) {
+ ab3100_devs[i].platform_data = ab3100_plf_data;
+ ab3100_devs[i].pdata_size = sizeof(struct ab3100_platform_data);
+ }
err = mfd_add_devices(&client->dev, 0, ab3100_devs,
ARRAY_SIZE(ab3100_devs), NULL, 0);
diff --git a/drivers/mfd/ab3550-core.c b/drivers/mfd/ab3550-core.c
index ff86acf3e6bd..3d7dce671b93 100644
--- a/drivers/mfd/ab3550-core.c
+++ b/drivers/mfd/ab3550-core.c
@@ -1320,8 +1320,10 @@ static int __init ab3550_probe(struct i2c_client *client,
goto exit_no_ops;
/* Set up and register the platform devices. */
- for (i = 0; i < AB3550_NUM_DEVICES; i++)
- ab3550_devs[i].mfd_data = ab3550_plf_data->dev_data[i];
+ for (i = 0; i < AB3550_NUM_DEVICES; i++) {
+ ab3550_devs[i].platform_data = ab3550_plf_data->dev_data[i];
+ ab3550_devs[i].pdata_size = ab3550_plf_data->dev_data_sz[i];
+ }
err = mfd_add_devices(&client->dev, 0, ab3550_devs,
ARRAY_SIZE(ab3550_devs), NULL,
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 67d01c938284..fc0c1af1566e 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -254,8 +254,9 @@ static void ab8500_irq_sync_unlock(struct irq_data *data)
if (new == old)
continue;
- /* Interrupt register 12 does'nt exist prior to version 0x20 */
- if (ab8500_irq_regoffset[i] == 11 && ab8500->chip_id < 0x20)
+ /* Interrupt register 12 doesn't exist prior to version 2.0 */
+ if (ab8500_irq_regoffset[i] == 11 &&
+ ab8500->chip_id < AB8500_CUT2P0)
continue;
ab8500->oldmask[i] = new;
@@ -307,8 +308,8 @@ static irqreturn_t ab8500_irq(int irq, void *dev)
int status;
u8 value;
- /* Interrupt register 12 does'nt exist prior to version 0x20 */
- if (regoffset == 11 && ab8500->chip_id < 0x20)
+ /* Interrupt register 12 doesn't exist prior to version 2.0 */
+ if (regoffset == 11 && ab8500->chip_id < AB8500_CUT2P0)
continue;
status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
@@ -724,17 +725,15 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
if (ret < 0)
return ret;
- /*
- * 0x0 - Early Drop
- * 0x10 - Cut 1.0
- * 0x11 - Cut 1.1
- * 0x20 - Cut 2.0
- * 0x30 - Cut 3.0
- */
- if (value == 0x0 || value == 0x10 || value == 0x11 || value == 0x20 ||
- value == 0x30) {
+ switch (value) {
+ case AB8500_CUTEARLY:
+ case AB8500_CUT1P0:
+ case AB8500_CUT1P1:
+ case AB8500_CUT2P0:
+ case AB8500_CUT3P0:
dev_info(ab8500->dev, "detected chip, revision: %#x\n", value);
- } else {
+ break;
+ default:
dev_err(ab8500->dev, "unknown chip, revision: %#x\n", value);
return -EINVAL;
}
@@ -763,8 +762,9 @@ int __devinit ab8500_init(struct ab8500 *ab8500)
/* Clear and mask all interrupts */
for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
- /* Interrupt register 12 does'nt exist prior to version 0x20 */
- if (ab8500_irq_regoffset[i] == 11 && ab8500->chip_id < 0x20)
+ /* Interrupt register 12 doesn't exist prior to version 2.0 */
+ if (ab8500_irq_regoffset[i] == 11 &&
+ ab8500->chip_id < AB8500_CUT2P0)
continue;
get_register_interruptible(ab8500, AB8500_INTERRUPT,
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c
index 6421ad1160de..f16afb234ff9 100644
--- a/drivers/mfd/ab8500-gpadc.c
+++ b/drivers/mfd/ab8500-gpadc.c
@@ -57,6 +57,7 @@
#define SW_AVG_16 0x60
#define ADC_SW_CONV 0x04
#define EN_ICHAR 0x80
+#define BTEMP_PULL_UP 0x08
#define EN_BUF 0x40
#define DIS_ZERO 0x00
#define GPADC_BUSY 0x01
@@ -101,6 +102,7 @@ struct adc_cal_data {
/**
* struct ab8500_gpadc - AB8500 GPADC device information
+ * @chip_id ABB chip id
* @dev: pointer to the struct device
* @node: a list of AB8500 GPADCs, hence prepared for
reentrance
@@ -112,6 +114,7 @@ struct adc_cal_data {
* @cal_data array of ADC calibration data structs
*/
struct ab8500_gpadc {
+ u8 chip_id;
struct device *dev;
struct list_head node;
struct completion ab8500_gpadc_complete;
@@ -274,6 +277,7 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input)
dev_err(gpadc->dev, "gpadc_conversion: enable gpadc failed\n");
goto out;
}
+
/* Select the input source and set average samples to 16 */
ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC,
AB8500_GPADC_CTRL2_REG, (input | SW_AVG_16));
@@ -282,9 +286,11 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input)
"gpadc_conversion: set avg samples failed\n");
goto out;
}
+
/*
* Enable ADC, buffering, select rising edge and enable ADC path
- * charging current sense if it needed
+ * charging current sense if it needed, ABB 3.0 needs some special
+ * treatment too.
*/
switch (input) {
case MAIN_CHARGER_C:
@@ -294,6 +300,23 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input)
EN_BUF | EN_ICHAR,
EN_BUF | EN_ICHAR);
break;
+ case BTEMP_BALL:
+ if (gpadc->chip_id >= AB8500_CUT3P0) {
+ /* Turn on btemp pull-up on ABB 3.0 */
+ ret = abx500_mask_and_set_register_interruptible(
+ gpadc->dev,
+ AB8500_GPADC, AB8500_GPADC_CTRL1_REG,
+ EN_BUF | BTEMP_PULL_UP,
+ EN_BUF | BTEMP_PULL_UP);
+
+ /*
+ * Delay might be needed for ABB8500 cut 3.0, if not, remove
+ * when hardware will be availible
+ */
+ msleep(1);
+ break;
+ }
+ /* Intentional fallthrough */
default:
ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_BUF, EN_BUF);
@@ -304,6 +327,7 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input)
"gpadc_conversion: select falling edge failed\n");
goto out;
}
+
ret = abx500_mask_and_set_register_interruptible(gpadc->dev,
AB8500_GPADC, AB8500_GPADC_CTRL1_REG, ADC_SW_CONV, ADC_SW_CONV);
if (ret < 0) {
@@ -552,6 +576,14 @@ static int __devinit ab8500_gpadc_probe(struct platform_device *pdev)
goto fail;
}
+ /* Get Chip ID of the ABB ASIC */
+ ret = abx500_get_chip_id(gpadc->dev);
+ if (ret < 0) {
+ dev_err(gpadc->dev, "failed to get chip ID\n");
+ goto fail_irq;
+ }
+ gpadc->chip_id = (u8) ret;
+
/* VTVout LDO used to power up ab8500-GPADC */
gpadc->regu = regulator_get(&pdev->dev, "vddadc");
if (IS_ERR(gpadc->regu)) {
diff --git a/drivers/mfd/ab8500-i2c.c b/drivers/mfd/ab8500-i2c.c
index 821e6b86afd2..9be541c6b004 100644
--- a/drivers/mfd/ab8500-i2c.c
+++ b/drivers/mfd/ab8500-i2c.c
@@ -11,8 +11,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mfd/ab8500.h>
-
-#include <mach/prcmu.h>
+#include <linux/mfd/db8500-prcmu.h>
static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
{
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index 0b4d5b23bec9..c27fd1fc3b86 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -88,19 +88,19 @@ struct asic3 {
static int asic3_gpio_get(struct gpio_chip *chip, unsigned offset);
-static inline void asic3_write_register(struct asic3 *asic,
- unsigned int reg, u32 value)
+void asic3_write_register(struct asic3 *asic, unsigned int reg, u32 value)
{
iowrite16(value, asic->mapping +
(reg >> asic->bus_shift));
}
+EXPORT_SYMBOL_GPL(asic3_write_register);
-static inline u32 asic3_read_register(struct asic3 *asic,
- unsigned int reg)
+u32 asic3_read_register(struct asic3 *asic, unsigned int reg)
{
return ioread16(asic->mapping +
(reg >> asic->bus_shift));
}
+EXPORT_SYMBOL_GPL(asic3_read_register);
static void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set)
{
@@ -676,7 +676,8 @@ static struct mfd_cell asic3_cell_ds1wm = {
.name = "ds1wm",
.enable = ds1wm_enable,
.disable = ds1wm_disable,
- .mfd_data = &ds1wm_pdata,
+ .platform_data = &ds1wm_pdata,
+ .pdata_size = sizeof(ds1wm_pdata),
.num_resources = ARRAY_SIZE(ds1wm_resources),
.resources = ds1wm_resources,
};
@@ -777,12 +778,61 @@ static struct mfd_cell asic3_cell_mmc = {
.name = "tmio-mmc",
.enable = asic3_mmc_enable,
.disable = asic3_mmc_disable,
- .mfd_data = &asic3_mmc_data,
+ .platform_data = &asic3_mmc_data,
+ .pdata_size = sizeof(asic3_mmc_data),
.num_resources = ARRAY_SIZE(asic3_mmc_resources),
.resources = asic3_mmc_resources,
};
+static const int clock_ledn[ASIC3_NUM_LEDS] = {
+ [0] = ASIC3_CLOCK_LED0,
+ [1] = ASIC3_CLOCK_LED1,
+ [2] = ASIC3_CLOCK_LED2,
+};
+
+static int asic3_leds_enable(struct platform_device *pdev)
+{
+ const struct mfd_cell *cell = mfd_get_cell(pdev);
+ struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
+
+ asic3_clk_enable(asic, &asic->clocks[clock_ledn[cell->id]]);
+
+ return 0;
+}
+
+static int asic3_leds_disable(struct platform_device *pdev)
+{
+ const struct mfd_cell *cell = mfd_get_cell(pdev);
+ struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
+
+ asic3_clk_disable(asic, &asic->clocks[clock_ledn[cell->id]]);
+
+ return 0;
+}
+
+static struct mfd_cell asic3_cell_leds[ASIC3_NUM_LEDS] = {
+ [0] = {
+ .name = "leds-asic3",
+ .id = 0,
+ .enable = asic3_leds_enable,
+ .disable = asic3_leds_disable,
+ },
+ [1] = {
+ .name = "leds-asic3",
+ .id = 1,
+ .enable = asic3_leds_enable,
+ .disable = asic3_leds_disable,
+ },
+ [2] = {
+ .name = "leds-asic3",
+ .id = 2,
+ .enable = asic3_leds_enable,
+ .disable = asic3_leds_disable,
+ },
+};
+
static int __init asic3_mfd_probe(struct platform_device *pdev,
+ struct asic3_platform_data *pdata,
struct resource *mem)
{
struct asic3 *asic = platform_get_drvdata(pdev);
@@ -806,7 +856,8 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
/* MMC */
asic->tmio_cnf = ioremap((ASIC3_SD_CONFIG_BASE >> asic->bus_shift) +
- mem_sdio->start, 0x400 >> asic->bus_shift);
+ mem_sdio->start,
+ ASIC3_SD_CONFIG_SIZE >> asic->bus_shift);
if (!asic->tmio_cnf) {
ret = -ENOMEM;
dev_dbg(asic->dev, "Couldn't ioremap SD_CONFIG\n");
@@ -820,9 +871,23 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
if (ret < 0)
goto out;
- if (mem_sdio && (irq >= 0))
+ if (mem_sdio && (irq >= 0)) {
ret = mfd_add_devices(&pdev->dev, pdev->id,
&asic3_cell_mmc, 1, mem_sdio, irq);
+ if (ret < 0)
+ goto out;
+ }
+
+ if (pdata->leds) {
+ int i;
+
+ for (i = 0; i < ASIC3_NUM_LEDS; ++i) {
+ asic3_cell_leds[i].platform_data = &pdata->leds[i];
+ asic3_cell_leds[i].pdata_size = sizeof(pdata->leds[i]);
+ }
+ ret = mfd_add_devices(&pdev->dev, 0,
+ asic3_cell_leds, ASIC3_NUM_LEDS, NULL, 0);
+ }
out:
return ret;
@@ -903,7 +968,7 @@ static int __init asic3_probe(struct platform_device *pdev)
*/
memcpy(asic->clocks, asic3_clk_init, sizeof(asic3_clk_init));
- asic3_mfd_probe(pdev, mem);
+ asic3_mfd_probe(pdev, pdata, mem);
dev_info(asic->dev, "ASIC3 Core driver\n");
diff --git a/drivers/mfd/davinci_voicecodec.c b/drivers/mfd/davinci_voicecodec.c
index 414783b04849..4e2af2cb2d26 100644
--- a/drivers/mfd/davinci_voicecodec.c
+++ b/drivers/mfd/davinci_voicecodec.c
@@ -119,12 +119,14 @@ static int __init davinci_vc_probe(struct platform_device *pdev)
/* Voice codec interface client */
cell = &davinci_vc->cells[DAVINCI_VC_VCIF_CELL];
cell->name = "davinci-vcif";
- cell->mfd_data = davinci_vc;
+ cell->platform_data = davinci_vc;
+ cell->pdata_size = sizeof(*davinci_vc);
/* Voice codec CQ93VC client */
cell = &davinci_vc->cells[DAVINCI_VC_CQ93VC_CELL];
cell->name = "cq93vc-codec";
- cell->mfd_data = davinci_vc;
+ cell->platform_data = davinci_vc;
+ cell->pdata_size = sizeof(*davinci_vc);
ret = mfd_add_devices(&pdev->dev, pdev->id, davinci_vc->cells,
DAVINCI_VC_CELLS, NULL, 0);
diff --git a/arch/arm/mach-ux500/include/mach/prcmu-regs.h b/drivers/mfd/db5500-prcmu-regs.h
index 455467e88791..9a8e9e4ddd33 100644
--- a/arch/arm/mach-ux500/include/mach/prcmu-regs.h
+++ b/drivers/mfd/db5500-prcmu-regs.h
@@ -15,11 +15,20 @@
#include <mach/hardware.h>
-#define _PRCMU_BASE IO_ADDRESS(U8500_PRCMU_BASE)
-
#define PRCM_ARM_PLLDIVPS (_PRCMU_BASE + 0x118)
+#define PRCM_ARM_PLLDIVPS_ARM_BRM_RATE 0x3f
+#define PRCM_ARM_PLLDIVPS_MAX_MASK 0xf
+
+#define PRCM_PLLARM_LOCKP (_PRCMU_BASE + 0x0a8)
+#define PRCM_PLLARM_LOCKP_PRCM_PLLARM_LOCKP3 0x2
+
#define PRCM_ARM_CHGCLKREQ (_PRCMU_BASE + 0x114)
+#define PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ 0x1
+
#define PRCM_PLLARM_ENABLE (_PRCMU_BASE + 0x98)
+#define PRCM_PLLARM_ENABLE_PRCM_PLLARM_ENABLE 0x1
+#define PRCM_PLLARM_ENABLE_PRCM_PLLARM_COUNTON 0x100
+
#define PRCM_ARMCLKFIX_MGT (_PRCMU_BASE + 0x0)
#define PRCM_A9_RESETN_CLR (_PRCMU_BASE + 0x1f4)
#define PRCM_A9_RESETN_SET (_PRCMU_BASE + 0x1f0)
@@ -28,7 +37,8 @@
/* ARM WFI Standby signal register */
#define PRCM_ARM_WFI_STANDBY (_PRCMU_BASE + 0x130)
-#define PRCMU_IOCR (_PRCMU_BASE + 0x310)
+#define PRCM_IOCR (_PRCMU_BASE + 0x310)
+#define PRCM_IOCR_IOFORCE 0x1
/* CPU mailbox registers */
#define PRCM_MBOX_CPU_VAL (_PRCMU_BASE + 0x0fc)
@@ -37,6 +47,8 @@
/* Dual A9 core interrupt management unit registers */
#define PRCM_A9_MASK_REQ (_PRCMU_BASE + 0x328)
+#define PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ 0x1
+
#define PRCM_A9_MASK_ACK (_PRCMU_BASE + 0x32c)
#define PRCM_ARMITMSK31TO0 (_PRCMU_BASE + 0x11c)
#define PRCM_ARMITMSK63TO32 (_PRCMU_BASE + 0x120)
@@ -74,14 +86,17 @@
/* PRCMU clock/PLL/reset registers */
#define PRCM_PLLDSI_FREQ (_PRCMU_BASE + 0x500)
#define PRCM_PLLDSI_ENABLE (_PRCMU_BASE + 0x504)
+#define PRCM_PLLDSI_LOCKP (_PRCMU_BASE + 0x508)
#define PRCM_LCDCLK_MGT (_PRCMU_BASE + 0x044)
#define PRCM_MCDECLK_MGT (_PRCMU_BASE + 0x064)
#define PRCM_HDMICLK_MGT (_PRCMU_BASE + 0x058)
#define PRCM_TVCLK_MGT (_PRCMU_BASE + 0x07c)
#define PRCM_DSI_PLLOUT_SEL (_PRCMU_BASE + 0x530)
#define PRCM_DSITVCLK_DIV (_PRCMU_BASE + 0x52C)
+#define PRCM_PLLDSI_LOCKP (_PRCMU_BASE + 0x508)
#define PRCM_APE_RESETN_SET (_PRCMU_BASE + 0x1E4)
#define PRCM_APE_RESETN_CLR (_PRCMU_BASE + 0x1E8)
+#define PRCM_CLKOCR (_PRCMU_BASE + 0x1CC)
/* ePOD and memory power signal control registers */
#define PRCM_EPOD_C_SET (_PRCMU_BASE + 0x410)
@@ -92,5 +107,9 @@
/* Miscellaneous unit registers */
#define PRCM_DSI_SW_RESET (_PRCMU_BASE + 0x324)
+#define PRCM_GPIOCR (_PRCMU_BASE + 0x138)
+#define PRCM_GPIOCR_DBG_STM_MOD_CMD1 0x800
+#define PRCM_GPIOCR_DBG_UARTMOD_CMD0 0x1
+
-#endif /* __MACH_PRCMU_REGS_H */
+#endif /* __MACH_PRCMU__REGS_H */
diff --git a/drivers/mfd/db5500-prcmu.c b/drivers/mfd/db5500-prcmu.c
new file mode 100644
index 000000000000..9dbb3cab4a6f
--- /dev/null
+++ b/drivers/mfd/db5500-prcmu.c
@@ -0,0 +1,448 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
+ *
+ * U5500 PRCM Unit interface driver
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/irq.h>
+#include <linux/jiffies.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/db5500-prcmu.h>
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/db5500-regs.h>
+#include "db5500-prcmu-regs.h"
+
+#define _PRCM_MB_HEADER (tcdm_base + 0xFE8)
+#define PRCM_REQ_MB0_HEADER (_PRCM_MB_HEADER + 0x0)
+#define PRCM_REQ_MB1_HEADER (_PRCM_MB_HEADER + 0x1)
+#define PRCM_REQ_MB2_HEADER (_PRCM_MB_HEADER + 0x2)
+#define PRCM_REQ_MB3_HEADER (_PRCM_MB_HEADER + 0x3)
+#define PRCM_REQ_MB4_HEADER (_PRCM_MB_HEADER + 0x4)
+#define PRCM_REQ_MB5_HEADER (_PRCM_MB_HEADER + 0x5)
+#define PRCM_REQ_MB6_HEADER (_PRCM_MB_HEADER + 0x6)
+#define PRCM_REQ_MB7_HEADER (_PRCM_MB_HEADER + 0x7)
+#define PRCM_ACK_MB0_HEADER (_PRCM_MB_HEADER + 0x8)
+#define PRCM_ACK_MB1_HEADER (_PRCM_MB_HEADER + 0x9)
+#define PRCM_ACK_MB2_HEADER (_PRCM_MB_HEADER + 0xa)
+#define PRCM_ACK_MB3_HEADER (_PRCM_MB_HEADER + 0xb)
+#define PRCM_ACK_MB4_HEADER (_PRCM_MB_HEADER + 0xc)
+#define PRCM_ACK_MB5_HEADER (_PRCM_MB_HEADER + 0xd)
+#define PRCM_ACK_MB6_HEADER (_PRCM_MB_HEADER + 0xe)
+#define PRCM_ACK_MB7_HEADER (_PRCM_MB_HEADER + 0xf)
+
+/* Req Mailboxes */
+#define PRCM_REQ_MB0 (tcdm_base + 0xFD8)
+#define PRCM_REQ_MB1 (tcdm_base + 0xFCC)
+#define PRCM_REQ_MB2 (tcdm_base + 0xFC4)
+#define PRCM_REQ_MB3 (tcdm_base + 0xFC0)
+#define PRCM_REQ_MB4 (tcdm_base + 0xF98)
+#define PRCM_REQ_MB5 (tcdm_base + 0xF90)
+#define PRCM_REQ_MB6 (tcdm_base + 0xF8C)
+#define PRCM_REQ_MB7 (tcdm_base + 0xF84)
+
+/* Ack Mailboxes */
+#define PRCM_ACK_MB0 (tcdm_base + 0xF38)
+#define PRCM_ACK_MB1 (tcdm_base + 0xF30)
+#define PRCM_ACK_MB2 (tcdm_base + 0xF24)
+#define PRCM_ACK_MB3 (tcdm_base + 0xF20)
+#define PRCM_ACK_MB4 (tcdm_base + 0xF1C)
+#define PRCM_ACK_MB5 (tcdm_base + 0xF14)
+#define PRCM_ACK_MB6 (tcdm_base + 0xF0C)
+#define PRCM_ACK_MB7 (tcdm_base + 0xF08)
+
+enum mb_return_code {
+ RC_SUCCESS,
+ RC_FAIL,
+};
+
+/* Mailbox 0 headers. */
+enum mb0_header {
+ /* request */
+ RMB0H_PWR_STATE_TRANS = 1,
+ RMB0H_WAKE_UP_CFG,
+ RMB0H_RD_WAKE_UP_ACK,
+ /* acknowledge */
+ AMB0H_WAKE_UP = 1,
+};
+
+/* Mailbox 5 headers. */
+enum mb5_header {
+ MB5H_I2C_WRITE = 1,
+ MB5H_I2C_READ,
+};
+
+/* Request mailbox 5 fields. */
+#define PRCM_REQ_MB5_I2C_SLAVE (PRCM_REQ_MB5 + 0)
+#define PRCM_REQ_MB5_I2C_REG (PRCM_REQ_MB5 + 1)
+#define PRCM_REQ_MB5_I2C_SIZE (PRCM_REQ_MB5 + 2)
+#define PRCM_REQ_MB5_I2C_DATA (PRCM_REQ_MB5 + 4)
+
+/* Acknowledge mailbox 5 fields. */
+#define PRCM_ACK_MB5_RETURN_CODE (PRCM_ACK_MB5 + 0)
+#define PRCM_ACK_MB5_I2C_DATA (PRCM_ACK_MB5 + 4)
+
+#define NUM_MB 8
+#define MBOX_BIT BIT
+#define ALL_MBOX_BITS (MBOX_BIT(NUM_MB) - 1)
+
+/*
+* Used by MCDE to setup all necessary PRCMU registers
+*/
+#define PRCMU_RESET_DSIPLL 0x00004000
+#define PRCMU_UNCLAMP_DSIPLL 0x00400800
+
+/* HDMI CLK MGT PLLSW=001 (PLLSOC0), PLLDIV=0x8, = 50 Mhz*/
+#define PRCMU_DSI_CLOCK_SETTING 0x00000128
+/* TVCLK_MGT PLLSW=001 (PLLSOC0) PLLDIV=0x13, = 19.05 MHZ */
+#define PRCMU_DSI_LP_CLOCK_SETTING 0x00000135
+#define PRCMU_PLLDSI_FREQ_SETTING 0x0004013C
+#define PRCMU_DSI_PLLOUT_SEL_SETTING 0x00000002
+#define PRCMU_ENABLE_ESCAPE_CLOCK_DIV 0x03000101
+#define PRCMU_DISABLE_ESCAPE_CLOCK_DIV 0x00000101
+
+#define PRCMU_ENABLE_PLLDSI 0x00000001
+#define PRCMU_DISABLE_PLLDSI 0x00000000
+
+#define PRCMU_DSI_RESET_SW 0x00000003
+
+#define PRCMU_PLLDSI_LOCKP_LOCKED 0x3
+
+/*
+ * mb0_transfer - state needed for mailbox 0 communication.
+ * @lock: The transaction lock.
+ */
+static struct {
+ spinlock_t lock;
+} mb0_transfer;
+
+/*
+ * mb5_transfer - state needed for mailbox 5 communication.
+ * @lock: The transaction lock.
+ * @work: The transaction completion structure.
+ * @ack: Reply ("acknowledge") data.
+ */
+static struct {
+ struct mutex lock;
+ struct completion work;
+ struct {
+ u8 header;
+ u8 status;
+ u8 value[4];
+ } ack;
+} mb5_transfer;
+
+/* PRCMU TCDM base IO address. */
+static __iomem void *tcdm_base;
+
+/**
+ * db5500_prcmu_abb_read() - Read register value(s) from the ABB.
+ * @slave: The I2C slave address.
+ * @reg: The (start) register address.
+ * @value: The read out value(s).
+ * @size: The number of registers to read.
+ *
+ * Reads register value(s) from the ABB.
+ * @size has to be <= 4.
+ */
+int db5500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
+{
+ int r;
+
+ if ((size < 1) || (4 < size))
+ return -EINVAL;
+
+ mutex_lock(&mb5_transfer.lock);
+
+ while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
+ cpu_relax();
+ writeb(slave, PRCM_REQ_MB5_I2C_SLAVE);
+ writeb(reg, PRCM_REQ_MB5_I2C_REG);
+ writeb(size, PRCM_REQ_MB5_I2C_SIZE);
+ writeb(MB5H_I2C_READ, PRCM_REQ_MB5_HEADER);
+
+ writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
+ wait_for_completion(&mb5_transfer.work);
+
+ r = 0;
+ if ((mb5_transfer.ack.header == MB5H_I2C_READ) &&
+ (mb5_transfer.ack.status == RC_SUCCESS))
+ memcpy(value, mb5_transfer.ack.value, (size_t)size);
+ else
+ r = -EIO;
+
+ mutex_unlock(&mb5_transfer.lock);
+
+ return r;
+}
+
+/**
+ * db5500_prcmu_abb_write() - Write register value(s) to the ABB.
+ * @slave: The I2C slave address.
+ * @reg: The (start) register address.
+ * @value: The value(s) to write.
+ * @size: The number of registers to write.
+ *
+ * Writes register value(s) to the ABB.
+ * @size has to be <= 4.
+ */
+int db5500_prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+{
+ int r;
+
+ if ((size < 1) || (4 < size))
+ return -EINVAL;
+
+ mutex_lock(&mb5_transfer.lock);
+
+ while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
+ cpu_relax();
+ writeb(slave, PRCM_REQ_MB5_I2C_SLAVE);
+ writeb(reg, PRCM_REQ_MB5_I2C_REG);
+ writeb(size, PRCM_REQ_MB5_I2C_SIZE);
+ memcpy_toio(PRCM_REQ_MB5_I2C_DATA, value, size);
+ writeb(MB5H_I2C_WRITE, PRCM_REQ_MB5_HEADER);
+
+ writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET);
+ wait_for_completion(&mb5_transfer.work);
+
+ if ((mb5_transfer.ack.header == MB5H_I2C_WRITE) &&
+ (mb5_transfer.ack.status == RC_SUCCESS))
+ r = 0;
+ else
+ r = -EIO;
+
+ mutex_unlock(&mb5_transfer.lock);
+
+ return r;
+}
+
+int db5500_prcmu_enable_dsipll(void)
+{
+ int i;
+
+ /* Enable DSIPLL_RESETN resets */
+ writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_CLR);
+ /* Unclamp DSIPLL in/out */
+ writel(PRCMU_UNCLAMP_DSIPLL, PRCM_MMIP_LS_CLAMP_CLR);
+ /* Set DSI PLL FREQ */
+ writel(PRCMU_PLLDSI_FREQ_SETTING, PRCM_PLLDSI_FREQ);
+ writel(PRCMU_DSI_PLLOUT_SEL_SETTING,
+ PRCM_DSI_PLLOUT_SEL);
+ /* Enable Escape clocks */
+ writel(PRCMU_ENABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV);
+
+ /* Start DSI PLL */
+ writel(PRCMU_ENABLE_PLLDSI, PRCM_PLLDSI_ENABLE);
+ /* Reset DSI PLL */
+ writel(PRCMU_DSI_RESET_SW, PRCM_DSI_SW_RESET);
+ for (i = 0; i < 10; i++) {
+ if ((readl(PRCM_PLLDSI_LOCKP) &
+ PRCMU_PLLDSI_LOCKP_LOCKED) == PRCMU_PLLDSI_LOCKP_LOCKED)
+ break;
+ udelay(100);
+ }
+ /* Release DSIPLL_RESETN */
+ writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_SET);
+ return 0;
+}
+
+int db5500_prcmu_disable_dsipll(void)
+{
+ /* Disable dsi pll */
+ writel(PRCMU_DISABLE_PLLDSI, PRCM_PLLDSI_ENABLE);
+ /* Disable escapeclock */
+ writel(PRCMU_DISABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV);
+ return 0;
+}
+
+int db5500_prcmu_set_display_clocks(void)
+{
+ /* HDMI and TVCLK Should be handled somewhere else */
+ /* PLLDIV=8, PLLSW=2, CLKEN=1 */
+ writel(PRCMU_DSI_CLOCK_SETTING, PRCM_HDMICLK_MGT);
+ /* PLLDIV=14, PLLSW=2, CLKEN=1 */
+ writel(PRCMU_DSI_LP_CLOCK_SETTING, PRCM_TVCLK_MGT);
+ return 0;
+}
+
+static void ack_dbb_wakeup(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mb0_transfer.lock, flags);
+
+ while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(0))
+ cpu_relax();
+
+ writeb(RMB0H_RD_WAKE_UP_ACK, PRCM_REQ_MB0_HEADER);
+ writel(MBOX_BIT(0), PRCM_MBOX_CPU_SET);
+
+ spin_unlock_irqrestore(&mb0_transfer.lock, flags);
+}
+
+static inline void print_unknown_header_warning(u8 n, u8 header)
+{
+ pr_warning("prcmu: Unknown message header (%d) in mailbox %d.\n",
+ header, n);
+}
+
+static bool read_mailbox_0(void)
+{
+ bool r;
+ u8 header;
+
+ header = readb(PRCM_ACK_MB0_HEADER);
+ switch (header) {
+ case AMB0H_WAKE_UP:
+ r = true;
+ break;
+ default:
+ print_unknown_header_warning(0, header);
+ r = false;
+ break;
+ }
+ writel(MBOX_BIT(0), PRCM_ARM_IT1_CLEAR);
+ return r;
+}
+
+static bool read_mailbox_1(void)
+{
+ writel(MBOX_BIT(1), PRCM_ARM_IT1_CLEAR);
+ return false;
+}
+
+static bool read_mailbox_2(void)
+{
+ writel(MBOX_BIT(2), PRCM_ARM_IT1_CLEAR);
+ return false;
+}
+
+static bool read_mailbox_3(void)
+{
+ writel(MBOX_BIT(3), PRCM_ARM_IT1_CLEAR);
+ return false;
+}
+
+static bool read_mailbox_4(void)
+{
+ writel(MBOX_BIT(4), PRCM_ARM_IT1_CLEAR);
+ return false;
+}
+
+static bool read_mailbox_5(void)
+{
+ u8 header;
+
+ header = readb(PRCM_ACK_MB5_HEADER);
+ switch (header) {
+ case MB5H_I2C_READ:
+ memcpy_fromio(mb5_transfer.ack.value, PRCM_ACK_MB5_I2C_DATA, 4);
+ case MB5H_I2C_WRITE:
+ mb5_transfer.ack.header = header;
+ mb5_transfer.ack.status = readb(PRCM_ACK_MB5_RETURN_CODE);
+ complete(&mb5_transfer.work);
+ break;
+ default:
+ print_unknown_header_warning(5, header);
+ break;
+ }
+ writel(MBOX_BIT(5), PRCM_ARM_IT1_CLEAR);
+ return false;
+}
+
+static bool read_mailbox_6(void)
+{
+ writel(MBOX_BIT(6), PRCM_ARM_IT1_CLEAR);
+ return false;
+}
+
+static bool read_mailbox_7(void)
+{
+ writel(MBOX_BIT(7), PRCM_ARM_IT1_CLEAR);
+ return false;
+}
+
+static bool (* const read_mailbox[NUM_MB])(void) = {
+ read_mailbox_0,
+ read_mailbox_1,
+ read_mailbox_2,
+ read_mailbox_3,
+ read_mailbox_4,
+ read_mailbox_5,
+ read_mailbox_6,
+ read_mailbox_7
+};
+
+static irqreturn_t prcmu_irq_handler(int irq, void *data)
+{
+ u32 bits;
+ u8 n;
+ irqreturn_t r;
+
+ bits = (readl(PRCM_ARM_IT1_VAL) & ALL_MBOX_BITS);
+ if (unlikely(!bits))
+ return IRQ_NONE;
+
+ r = IRQ_HANDLED;
+ for (n = 0; bits; n++) {
+ if (bits & MBOX_BIT(n)) {
+ bits -= MBOX_BIT(n);
+ if (read_mailbox[n]())
+ r = IRQ_WAKE_THREAD;
+ }
+ }
+ return r;
+}
+
+static irqreturn_t prcmu_irq_thread_fn(int irq, void *data)
+{
+ ack_dbb_wakeup();
+ return IRQ_HANDLED;
+}
+
+void __init db5500_prcmu_early_init(void)
+{
+ tcdm_base = __io_address(U5500_PRCMU_TCDM_BASE);
+ spin_lock_init(&mb0_transfer.lock);
+ mutex_init(&mb5_transfer.lock);
+ init_completion(&mb5_transfer.work);
+}
+
+/**
+ * prcmu_fw_init - arch init call for the Linux PRCMU fw init logic
+ *
+ */
+int __init db5500_prcmu_init(void)
+{
+ int r = 0;
+
+ if (ux500_is_svp() || !cpu_is_u5500())
+ return -ENODEV;
+
+ /* Clean up the mailbox interrupts after pre-kernel code. */
+ writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLEAR);
+
+ r = request_threaded_irq(IRQ_DB5500_PRCMU1, prcmu_irq_handler,
+ prcmu_irq_thread_fn, 0, "prcmu", NULL);
+ if (r < 0) {
+ pr_err("prcmu: Failed to allocate IRQ_DB5500_PRCMU1.\n");
+ return -EBUSY;
+ }
+ return 0;
+}
+
+arch_initcall(db5500_prcmu_init);
diff --git a/drivers/mfd/db8500-prcmu-regs.h b/drivers/mfd/db8500-prcmu-regs.h
new file mode 100644
index 000000000000..3bbf04d58043
--- /dev/null
+++ b/drivers/mfd/db8500-prcmu-regs.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com>
+ *
+ * License Terms: GNU General Public License v2
+ *
+ * PRCM Unit registers
+ */
+#ifndef __DB8500_PRCMU_REGS_H
+#define __DB8500_PRCMU_REGS_H
+
+#include <linux/bitops.h>
+#include <mach/hardware.h>
+
+#define BITS(_start, _end) ((BIT(_end) - BIT(_start)) + BIT(_end))
+
+#define PRCM_ARM_PLLDIVPS 0x118
+#define PRCM_ARM_PLLDIVPS_ARM_BRM_RATE BITS(0, 5)
+#define PRCM_ARM_PLLDIVPS_MAX_MASK 0xF
+
+#define PRCM_PLLARM_LOCKP 0x0A8
+#define PRCM_PLLARM_LOCKP_PRCM_PLLARM_LOCKP3 BIT(1)
+
+#define PRCM_ARM_CHGCLKREQ 0x114
+#define PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ BIT(0)
+
+#define PRCM_PLLARM_ENABLE 0x98
+#define PRCM_PLLARM_ENABLE_PRCM_PLLARM_ENABLE BIT(0)
+#define PRCM_PLLARM_ENABLE_PRCM_PLLARM_COUNTON BIT(8)
+
+#define PRCM_ARMCLKFIX_MGT 0x0
+#define PRCM_A9_RESETN_CLR 0x1f4
+#define PRCM_A9_RESETN_SET 0x1f0
+#define PRCM_ARM_LS_CLAMP 0x30C
+#define PRCM_SRAM_A9 0x308
+
+/* ARM WFI Standby signal register */
+#define PRCM_ARM_WFI_STANDBY 0x130
+#define PRCM_IOCR 0x310
+#define PRCM_IOCR_IOFORCE BIT(0)
+
+/* CPU mailbox registers */
+#define PRCM_MBOX_CPU_VAL 0x0FC
+#define PRCM_MBOX_CPU_SET 0x100
+
+/* Dual A9 core interrupt management unit registers */
+#define PRCM_A9_MASK_REQ 0x328
+#define PRCM_A9_MASK_REQ_PRCM_A9_MASK_REQ BIT(0)
+
+#define PRCM_A9_MASK_ACK 0x32C
+#define PRCM_ARMITMSK31TO0 0x11C
+#define PRCM_ARMITMSK63TO32 0x120
+#define PRCM_ARMITMSK95TO64 0x124
+#define PRCM_ARMITMSK127TO96 0x128
+#define PRCM_POWER_STATE_VAL 0x25C
+#define PRCM_ARMITVAL31TO0 0x260
+#define PRCM_ARMITVAL63TO32 0x264
+#define PRCM_ARMITVAL95TO64 0x268
+#define PRCM_ARMITVAL127TO96 0x26C
+
+#define PRCM_HOSTACCESS_REQ 0x334
+#define PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ BIT(0)
+
+#define PRCM_ARM_IT1_CLR 0x48C
+#define PRCM_ARM_IT1_VAL 0x494
+
+#define PRCM_ITSTATUS0 0x148
+#define PRCM_ITSTATUS1 0x150
+#define PRCM_ITSTATUS2 0x158
+#define PRCM_ITSTATUS3 0x160
+#define PRCM_ITSTATUS4 0x168
+#define PRCM_ITSTATUS5 0x484
+#define PRCM_ITCLEAR5 0x488
+#define PRCM_ARMIT_MASKXP70_IT 0x1018
+
+/* System reset register */
+#define PRCM_APE_SOFTRST 0x228
+
+/* Level shifter and clamp control registers */
+#define PRCM_MMIP_LS_CLAMP_SET 0x420
+#define PRCM_MMIP_LS_CLAMP_CLR 0x424
+
+/* PRCMU HW semaphore */
+#define PRCM_SEM 0x400
+#define PRCM_SEM_PRCM_SEM BIT(0)
+
+/* PRCMU clock/PLL/reset registers */
+#define PRCM_PLLDSI_FREQ 0x500
+#define PRCM_PLLDSI_ENABLE 0x504
+#define PRCM_PLLDSI_LOCKP 0x508
+#define PRCM_DSI_PLLOUT_SEL 0x530
+#define PRCM_DSITVCLK_DIV 0x52C
+#define PRCM_APE_RESETN_SET 0x1E4
+#define PRCM_APE_RESETN_CLR 0x1E8
+
+#define PRCM_TCR 0x1C8
+#define PRCM_TCR_TENSEL_MASK BITS(0, 7)
+#define PRCM_TCR_STOP_TIMERS BIT(16)
+#define PRCM_TCR_DOZE_MODE BIT(17)
+
+#define PRCM_CLKOCR 0x1CC
+#define PRCM_CLKOCR_CLKODIV0_SHIFT 0
+#define PRCM_CLKOCR_CLKODIV0_MASK BITS(0, 5)
+#define PRCM_CLKOCR_CLKOSEL0_SHIFT 6
+#define PRCM_CLKOCR_CLKOSEL0_MASK BITS(6, 8)
+#define PRCM_CLKOCR_CLKODIV1_SHIFT 16
+#define PRCM_CLKOCR_CLKODIV1_MASK BITS(16, 21)
+#define PRCM_CLKOCR_CLKOSEL1_SHIFT 22
+#define PRCM_CLKOCR_CLKOSEL1_MASK BITS(22, 24)
+#define PRCM_CLKOCR_CLK1TYPE BIT(28)
+
+#define PRCM_SGACLK_MGT 0x014
+#define PRCM_UARTCLK_MGT 0x018
+#define PRCM_MSP02CLK_MGT 0x01C
+#define PRCM_MSP1CLK_MGT 0x288
+#define PRCM_I2CCLK_MGT 0x020
+#define PRCM_SDMMCCLK_MGT 0x024
+#define PRCM_SLIMCLK_MGT 0x028
+#define PRCM_PER1CLK_MGT 0x02C
+#define PRCM_PER2CLK_MGT 0x030
+#define PRCM_PER3CLK_MGT 0x034
+#define PRCM_PER5CLK_MGT 0x038
+#define PRCM_PER6CLK_MGT 0x03C
+#define PRCM_PER7CLK_MGT 0x040
+#define PRCM_LCDCLK_MGT 0x044
+#define PRCM_BMLCLK_MGT 0x04C
+#define PRCM_HSITXCLK_MGT 0x050
+#define PRCM_HSIRXCLK_MGT 0x054
+#define PRCM_HDMICLK_MGT 0x058
+#define PRCM_APEATCLK_MGT 0x05C
+#define PRCM_APETRACECLK_MGT 0x060
+#define PRCM_MCDECLK_MGT 0x064
+#define PRCM_IPI2CCLK_MGT 0x068
+#define PRCM_DSIALTCLK_MGT 0x06C
+#define PRCM_DMACLK_MGT 0x074
+#define PRCM_B2R2CLK_MGT 0x078
+#define PRCM_TVCLK_MGT 0x07C
+#define PRCM_UNIPROCLK_MGT 0x278
+#define PRCM_SSPCLK_MGT 0x280
+#define PRCM_RNGCLK_MGT 0x284
+#define PRCM_UICCCLK_MGT 0x27C
+
+#define PRCM_CLK_MGT_CLKPLLDIV_MASK BITS(0, 4)
+#define PRCM_CLK_MGT_CLKPLLSW_MASK BITS(5, 7)
+#define PRCM_CLK_MGT_CLKEN BIT(8)
+
+/* ePOD and memory power signal control registers */
+#define PRCM_EPOD_C_SET 0x410
+#define PRCM_SRAM_LS_SLEEP 0x304
+
+/* Debug power control unit registers */
+#define PRCM_POWER_STATE_SET 0x254
+
+/* Miscellaneous unit registers */
+#define PRCM_DSI_SW_RESET 0x324
+#define PRCM_GPIOCR 0x138
+
+/* GPIOCR register */
+#define PRCM_GPIOCR_SPI2_SELECT BIT(23)
+
+#define PRCM_DDR_SUBSYS_APE_MINBW 0x438
+
+#endif /* __DB8500_PRCMU_REGS_H */
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
new file mode 100644
index 000000000000..e63782107e2f
--- /dev/null
+++ b/drivers/mfd/db8500-prcmu.c
@@ -0,0 +1,2069 @@
+/*
+ * Copyright (C) STMicroelectronics 2009
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
+ * Author: Sundar Iyer <sundar.iyer@stericsson.com>
+ * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
+ *
+ * U8500 PRCM Unit interface driver
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/irq.h>
+#include <linux/jiffies.h>
+#include <linux/bitops.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/db8500-prcmu.h>
+#include <linux/regulator/db8500-prcmu.h>
+#include <linux/regulator/machine.h>
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/db8500-regs.h>
+#include <mach/id.h>
+#include "db8500-prcmu-regs.h"
+
+/* Offset for the firmware version within the TCPM */
+#define PRCMU_FW_VERSION_OFFSET 0xA4
+
+/* PRCMU project numbers, defined by PRCMU FW */
+#define PRCMU_PROJECT_ID_8500V1_0 1
+#define PRCMU_PROJECT_ID_8500V2_0 2
+#define PRCMU_PROJECT_ID_8400V2_0 3
+
+/* Index of different voltages to be used when accessing AVSData */
+#define PRCM_AVS_BASE 0x2FC
+#define PRCM_AVS_VBB_RET (PRCM_AVS_BASE + 0x0)
+#define PRCM_AVS_VBB_MAX_OPP (PRCM_AVS_BASE + 0x1)
+#define PRCM_AVS_VBB_100_OPP (PRCM_AVS_BASE + 0x2)
+#define PRCM_AVS_VBB_50_OPP (PRCM_AVS_BASE + 0x3)
+#define PRCM_AVS_VARM_MAX_OPP (PRCM_AVS_BASE + 0x4)
+#define PRCM_AVS_VARM_100_OPP (PRCM_AVS_BASE + 0x5)
+#define PRCM_AVS_VARM_50_OPP (PRCM_AVS_BASE + 0x6)
+#define PRCM_AVS_VARM_RET (PRCM_AVS_BASE + 0x7)
+#define PRCM_AVS_VAPE_100_OPP (PRCM_AVS_BASE + 0x8)
+#define PRCM_AVS_VAPE_50_OPP (PRCM_AVS_BASE + 0x9)
+#define PRCM_AVS_VMOD_100_OPP (PRCM_AVS_BASE + 0xA)
+#define PRCM_AVS_VMOD_50_OPP (PRCM_AVS_BASE + 0xB)
+#define PRCM_AVS_VSAFE (PRCM_AVS_BASE + 0xC)
+
+#define PRCM_AVS_VOLTAGE 0
+#define PRCM_AVS_VOLTAGE_MASK 0x3f
+#define PRCM_AVS_ISSLOWSTARTUP 6
+#define PRCM_AVS_ISSLOWSTARTUP_MASK (1 << PRCM_AVS_ISSLOWSTARTUP)
+#define PRCM_AVS_ISMODEENABLE 7
+#define PRCM_AVS_ISMODEENABLE_MASK (1 << PRCM_AVS_ISMODEENABLE)
+
+#define PRCM_BOOT_STATUS 0xFFF
+#define PRCM_ROMCODE_A2P 0xFFE
+#define PRCM_ROMCODE_P2A 0xFFD
+#define PRCM_XP70_CUR_PWR_STATE 0xFFC /* 4 BYTES */
+
+#define PRCM_SW_RST_REASON 0xFF8 /* 2 bytes */
+
+#define _PRCM_MBOX_HEADER 0xFE8 /* 16 bytes */
+#define PRCM_MBOX_HEADER_REQ_MB0 (_PRCM_MBOX_HEADER + 0x0)
+#define PRCM_MBOX_HEADER_REQ_MB1 (_PRCM_MBOX_HEADER + 0x1)
+#define PRCM_MBOX_HEADER_REQ_MB2 (_PRCM_MBOX_HEADER + 0x2)
+#define PRCM_MBOX_HEADER_REQ_MB3 (_PRCM_MBOX_HEADER + 0x3)
+#define PRCM_MBOX_HEADER_REQ_MB4 (_PRCM_MBOX_HEADER + 0x4)
+#define PRCM_MBOX_HEADER_REQ_MB5 (_PRCM_MBOX_HEADER + 0x5)
+#define PRCM_MBOX_HEADER_ACK_MB0 (_PRCM_MBOX_HEADER + 0x8)
+
+/* Req Mailboxes */
+#define PRCM_REQ_MB0 0xFDC /* 12 bytes */
+#define PRCM_REQ_MB1 0xFD0 /* 12 bytes */
+#define PRCM_REQ_MB2 0xFC0 /* 16 bytes */
+#define PRCM_REQ_MB3 0xE4C /* 372 bytes */
+#define PRCM_REQ_MB4 0xE48 /* 4 bytes */
+#define PRCM_REQ_MB5 0xE44 /* 4 bytes */
+
+/* Ack Mailboxes */
+#define PRCM_ACK_MB0 0xE08 /* 52 bytes */
+#define PRCM_ACK_MB1 0xE04 /* 4 bytes */
+#define PRCM_ACK_MB2 0xE00 /* 4 bytes */
+#define PRCM_ACK_MB3 0xDFC /* 4 bytes */
+#define PRCM_ACK_MB4 0xDF8 /* 4 bytes */
+#define PRCM_ACK_MB5 0xDF4 /* 4 bytes */
+
+/* Mailbox 0 headers */
+#define MB0H_POWER_STATE_TRANS 0
+#define MB0H_CONFIG_WAKEUPS_EXE 1
+#define MB0H_READ_WAKEUP_ACK 3
+#define MB0H_CONFIG_WAKEUPS_SLEEP 4
+
+#define MB0H_WAKEUP_EXE 2
+#define MB0H_WAKEUP_SLEEP 5
+
+/* Mailbox 0 REQs */
+#define PRCM_REQ_MB0_AP_POWER_STATE (PRCM_REQ_MB0 + 0x0)
+#define PRCM_REQ_MB0_AP_PLL_STATE (PRCM_REQ_MB0 + 0x1)
+#define PRCM_REQ_MB0_ULP_CLOCK_STATE (PRCM_REQ_MB0 + 0x2)
+#define PRCM_REQ_MB0_DO_NOT_WFI (PRCM_REQ_MB0 + 0x3)
+#define PRCM_REQ_MB0_WAKEUP_8500 (PRCM_REQ_MB0 + 0x4)
+#define PRCM_REQ_MB0_WAKEUP_4500 (PRCM_REQ_MB0 + 0x8)
+
+/* Mailbox 0 ACKs */
+#define PRCM_ACK_MB0_AP_PWRSTTR_STATUS (PRCM_ACK_MB0 + 0x0)
+#define PRCM_ACK_MB0_READ_POINTER (PRCM_ACK_MB0 + 0x1)
+#define PRCM_ACK_MB0_WAKEUP_0_8500 (PRCM_ACK_MB0 + 0x4)
+#define PRCM_ACK_MB0_WAKEUP_0_4500 (PRCM_ACK_MB0 + 0x8)
+#define PRCM_ACK_MB0_WAKEUP_1_8500 (PRCM_ACK_MB0 + 0x1C)
+#define PRCM_ACK_MB0_WAKEUP_1_4500 (PRCM_ACK_MB0 + 0x20)
+#define PRCM_ACK_MB0_EVENT_4500_NUMBERS 20
+
+/* Mailbox 1 headers */
+#define MB1H_ARM_APE_OPP 0x0
+#define MB1H_RESET_MODEM 0x2
+#define MB1H_REQUEST_APE_OPP_100_VOLT 0x3
+#define MB1H_RELEASE_APE_OPP_100_VOLT 0x4
+#define MB1H_RELEASE_USB_WAKEUP 0x5
+
+/* Mailbox 1 Requests */
+#define PRCM_REQ_MB1_ARM_OPP (PRCM_REQ_MB1 + 0x0)
+#define PRCM_REQ_MB1_APE_OPP (PRCM_REQ_MB1 + 0x1)
+#define PRCM_REQ_MB1_APE_OPP_100_RESTORE (PRCM_REQ_MB1 + 0x4)
+#define PRCM_REQ_MB1_ARM_OPP_100_RESTORE (PRCM_REQ_MB1 + 0x8)
+
+/* Mailbox 1 ACKs */
+#define PRCM_ACK_MB1_CURRENT_ARM_OPP (PRCM_ACK_MB1 + 0x0)
+#define PRCM_ACK_MB1_CURRENT_APE_OPP (PRCM_ACK_MB1 + 0x1)
+#define PRCM_ACK_MB1_APE_VOLTAGE_STATUS (PRCM_ACK_MB1 + 0x2)
+#define PRCM_ACK_MB1_DVFS_STATUS (PRCM_ACK_MB1 + 0x3)
+
+/* Mailbox 2 headers */
+#define MB2H_DPS 0x0
+#define MB2H_AUTO_PWR 0x1
+
+/* Mailbox 2 REQs */
+#define PRCM_REQ_MB2_SVA_MMDSP (PRCM_REQ_MB2 + 0x0)
+#define PRCM_REQ_MB2_SVA_PIPE (PRCM_REQ_MB2 + 0x1)
+#define PRCM_REQ_MB2_SIA_MMDSP (PRCM_REQ_MB2 + 0x2)
+#define PRCM_REQ_MB2_SIA_PIPE (PRCM_REQ_MB2 + 0x3)
+#define PRCM_REQ_MB2_SGA (PRCM_REQ_MB2 + 0x4)
+#define PRCM_REQ_MB2_B2R2_MCDE (PRCM_REQ_MB2 + 0x5)
+#define PRCM_REQ_MB2_ESRAM12 (PRCM_REQ_MB2 + 0x6)
+#define PRCM_REQ_MB2_ESRAM34 (PRCM_REQ_MB2 + 0x7)
+#define PRCM_REQ_MB2_AUTO_PM_SLEEP (PRCM_REQ_MB2 + 0x8)
+#define PRCM_REQ_MB2_AUTO_PM_IDLE (PRCM_REQ_MB2 + 0xC)
+
+/* Mailbox 2 ACKs */
+#define PRCM_ACK_MB2_DPS_STATUS (PRCM_ACK_MB2 + 0x0)
+#define HWACC_PWR_ST_OK 0xFE
+
+/* Mailbox 3 headers */
+#define MB3H_ANC 0x0
+#define MB3H_SIDETONE 0x1
+#define MB3H_SYSCLK 0xE
+
+/* Mailbox 3 Requests */
+#define PRCM_REQ_MB3_ANC_FIR_COEFF (PRCM_REQ_MB3 + 0x0)
+#define PRCM_REQ_MB3_ANC_IIR_COEFF (PRCM_REQ_MB3 + 0x20)
+#define PRCM_REQ_MB3_ANC_SHIFTER (PRCM_REQ_MB3 + 0x60)
+#define PRCM_REQ_MB3_ANC_WARP (PRCM_REQ_MB3 + 0x64)
+#define PRCM_REQ_MB3_SIDETONE_FIR_GAIN (PRCM_REQ_MB3 + 0x68)
+#define PRCM_REQ_MB3_SIDETONE_FIR_COEFF (PRCM_REQ_MB3 + 0x6C)
+#define PRCM_REQ_MB3_SYSCLK_MGT (PRCM_REQ_MB3 + 0x16C)
+
+/* Mailbox 4 headers */
+#define MB4H_DDR_INIT 0x0
+#define MB4H_MEM_ST 0x1
+#define MB4H_HOTDOG 0x12
+#define MB4H_HOTMON 0x13
+#define MB4H_HOT_PERIOD 0x14
+
+/* Mailbox 4 Requests */
+#define PRCM_REQ_MB4_DDR_ST_AP_SLEEP_IDLE (PRCM_REQ_MB4 + 0x0)
+#define PRCM_REQ_MB4_DDR_ST_AP_DEEP_IDLE (PRCM_REQ_MB4 + 0x1)
+#define PRCM_REQ_MB4_ESRAM0_ST (PRCM_REQ_MB4 + 0x3)
+#define PRCM_REQ_MB4_HOTDOG_THRESHOLD (PRCM_REQ_MB4 + 0x0)
+#define PRCM_REQ_MB4_HOTMON_LOW (PRCM_REQ_MB4 + 0x0)
+#define PRCM_REQ_MB4_HOTMON_HIGH (PRCM_REQ_MB4 + 0x1)
+#define PRCM_REQ_MB4_HOTMON_CONFIG (PRCM_REQ_MB4 + 0x2)
+#define PRCM_REQ_MB4_HOT_PERIOD (PRCM_REQ_MB4 + 0x0)
+#define HOTMON_CONFIG_LOW BIT(0)
+#define HOTMON_CONFIG_HIGH BIT(1)
+
+/* Mailbox 5 Requests */
+#define PRCM_REQ_MB5_I2C_SLAVE_OP (PRCM_REQ_MB5 + 0x0)
+#define PRCM_REQ_MB5_I2C_HW_BITS (PRCM_REQ_MB5 + 0x1)
+#define PRCM_REQ_MB5_I2C_REG (PRCM_REQ_MB5 + 0x2)
+#define PRCM_REQ_MB5_I2C_VAL (PRCM_REQ_MB5 + 0x3)
+#define PRCMU_I2C_WRITE(slave) \
+ (((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0))
+#define PRCMU_I2C_READ(slave) \
+ (((slave) << 1) | BIT(0) | (cpu_is_u8500v2() ? BIT(6) : 0))
+#define PRCMU_I2C_STOP_EN BIT(3)
+
+/* Mailbox 5 ACKs */
+#define PRCM_ACK_MB5_I2C_STATUS (PRCM_ACK_MB5 + 0x1)
+#define PRCM_ACK_MB5_I2C_VAL (PRCM_ACK_MB5 + 0x3)
+#define I2C_WR_OK 0x1
+#define I2C_RD_OK 0x2
+
+#define NUM_MB 8
+#define MBOX_BIT BIT
+#define ALL_MBOX_BITS (MBOX_BIT(NUM_MB) - 1)
+
+/*
+ * Wakeups/IRQs
+ */
+
+#define WAKEUP_BIT_RTC BIT(0)
+#define WAKEUP_BIT_RTT0 BIT(1)
+#define WAKEUP_BIT_RTT1 BIT(2)
+#define WAKEUP_BIT_HSI0 BIT(3)
+#define WAKEUP_BIT_HSI1 BIT(4)
+#define WAKEUP_BIT_CA_WAKE BIT(5)
+#define WAKEUP_BIT_USB BIT(6)
+#define WAKEUP_BIT_ABB BIT(7)
+#define WAKEUP_BIT_ABB_FIFO BIT(8)
+#define WAKEUP_BIT_SYSCLK_OK BIT(9)
+#define WAKEUP_BIT_CA_SLEEP BIT(10)
+#define WAKEUP_BIT_AC_WAKE_ACK BIT(11)
+#define WAKEUP_BIT_SIDE_TONE_OK BIT(12)
+#define WAKEUP_BIT_ANC_OK BIT(13)
+#define WAKEUP_BIT_SW_ERROR BIT(14)
+#define WAKEUP_BIT_AC_SLEEP_ACK BIT(15)
+#define WAKEUP_BIT_ARM BIT(17)
+#define WAKEUP_BIT_HOTMON_LOW BIT(18)
+#define WAKEUP_BIT_HOTMON_HIGH BIT(19)
+#define WAKEUP_BIT_MODEM_SW_RESET_REQ BIT(20)
+#define WAKEUP_BIT_GPIO0 BIT(23)
+#define WAKEUP_BIT_GPIO1 BIT(24)
+#define WAKEUP_BIT_GPIO2 BIT(25)
+#define WAKEUP_BIT_GPIO3 BIT(26)
+#define WAKEUP_BIT_GPIO4 BIT(27)
+#define WAKEUP_BIT_GPIO5 BIT(28)
+#define WAKEUP_BIT_GPIO6 BIT(29)
+#define WAKEUP_BIT_GPIO7 BIT(30)
+#define WAKEUP_BIT_GPIO8 BIT(31)
+
+/*
+ * This vector maps irq numbers to the bits in the bit field used in
+ * communication with the PRCMU firmware.
+ *
+ * The reason for having this is to keep the irq numbers contiguous even though
+ * the bits in the bit field are not. (The bits also have a tendency to move
+ * around, to further complicate matters.)
+ */
+#define IRQ_INDEX(_name) ((IRQ_PRCMU_##_name) - IRQ_PRCMU_BASE)
+#define IRQ_ENTRY(_name)[IRQ_INDEX(_name)] = (WAKEUP_BIT_##_name)
+static u32 prcmu_irq_bit[NUM_PRCMU_WAKEUPS] = {
+ IRQ_ENTRY(RTC),
+ IRQ_ENTRY(RTT0),
+ IRQ_ENTRY(RTT1),
+ IRQ_ENTRY(HSI0),
+ IRQ_ENTRY(HSI1),
+ IRQ_ENTRY(CA_WAKE),
+ IRQ_ENTRY(USB),
+ IRQ_ENTRY(ABB),
+ IRQ_ENTRY(ABB_FIFO),
+ IRQ_ENTRY(CA_SLEEP),
+ IRQ_ENTRY(ARM),
+ IRQ_ENTRY(HOTMON_LOW),
+ IRQ_ENTRY(HOTMON_HIGH),
+ IRQ_ENTRY(MODEM_SW_RESET_REQ),
+ IRQ_ENTRY(GPIO0),
+ IRQ_ENTRY(GPIO1),
+ IRQ_ENTRY(GPIO2),
+ IRQ_ENTRY(GPIO3),
+ IRQ_ENTRY(GPIO4),
+ IRQ_ENTRY(GPIO5),
+ IRQ_ENTRY(GPIO6),
+ IRQ_ENTRY(GPIO7),
+ IRQ_ENTRY(GPIO8)
+};
+
+#define VALID_WAKEUPS (BIT(NUM_PRCMU_WAKEUP_INDICES) - 1)
+#define WAKEUP_ENTRY(_name)[PRCMU_WAKEUP_INDEX_##_name] = (WAKEUP_BIT_##_name)
+static u32 prcmu_wakeup_bit[NUM_PRCMU_WAKEUP_INDICES] = {
+ WAKEUP_ENTRY(RTC),
+ WAKEUP_ENTRY(RTT0),
+ WAKEUP_ENTRY(RTT1),
+ WAKEUP_ENTRY(HSI0),
+ WAKEUP_ENTRY(HSI1),
+ WAKEUP_ENTRY(USB),
+ WAKEUP_ENTRY(ABB),
+ WAKEUP_ENTRY(ABB_FIFO),
+ WAKEUP_ENTRY(ARM)
+};
+
+/*
+ * mb0_transfer - state needed for mailbox 0 communication.
+ * @lock: The transaction lock.
+ * @dbb_events_lock: A lock used to handle concurrent access to (parts of)
+ * the request data.
+ * @mask_work: Work structure used for (un)masking wakeup interrupts.
+ * @req: Request data that need to persist between requests.
+ */
+static struct {
+ spinlock_t lock;
+ spinlock_t dbb_irqs_lock;
+ struct work_struct mask_work;
+ struct mutex ac_wake_lock;
+ struct completion ac_wake_work;
+ struct {
+ u32 dbb_irqs;
+ u32 dbb_wakeups;
+ u32 abb_events;
+ } req;
+} mb0_transfer;
+
+/*
+ * mb1_transfer - state needed for mailbox 1 communication.
+ * @lock: The transaction lock.
+ * @work: The transaction completion structure.
+ * @ack: Reply ("acknowledge") data.
+ */
+static struct {
+ struct mutex lock;
+ struct completion work;
+ struct {
+ u8 header;
+ u8 arm_opp;
+ u8 ape_opp;
+ u8 ape_voltage_status;
+ } ack;
+} mb1_transfer;
+
+/*
+ * mb2_transfer - state needed for mailbox 2 communication.
+ * @lock: The transaction lock.
+ * @work: The transaction completion structure.
+ * @auto_pm_lock: The autonomous power management configuration lock.
+ * @auto_pm_enabled: A flag indicating whether autonomous PM is enabled.
+ * @req: Request data that need to persist between requests.
+ * @ack: Reply ("acknowledge") data.
+ */
+static struct {
+ struct mutex lock;
+ struct completion work;
+ spinlock_t auto_pm_lock;
+ bool auto_pm_enabled;
+ struct {
+ u8 status;
+ } ack;
+} mb2_transfer;
+
+/*
+ * mb3_transfer - state needed for mailbox 3 communication.
+ * @lock: The request lock.
+ * @sysclk_lock: A lock used to handle concurrent sysclk requests.
+ * @sysclk_work: Work structure used for sysclk requests.
+ */
+static struct {
+ spinlock_t lock;
+ struct mutex sysclk_lock;
+ struct completion sysclk_work;
+} mb3_transfer;
+
+/*
+ * mb4_transfer - state needed for mailbox 4 communication.
+ * @lock: The transaction lock.
+ * @work: The transaction completion structure.
+ */
+static struct {
+ struct mutex lock;
+ struct completion work;
+} mb4_transfer;
+
+/*
+ * mb5_transfer - state needed for mailbox 5 communication.
+ * @lock: The transaction lock.
+ * @work: The transaction completion structure.
+ * @ack: Reply ("acknowledge") data.
+ */
+static struct {
+ struct mutex lock;
+ struct completion work;
+ struct {
+ u8 status;
+ u8 value;
+ } ack;
+} mb5_transfer;
+
+static atomic_t ac_wake_req_state = ATOMIC_INIT(0);
+
+/* Spinlocks */
+static DEFINE_SPINLOCK(clkout_lock);
+static DEFINE_SPINLOCK(gpiocr_lock);
+
+/* Global var to runtime determine TCDM base for v2 or v1 */
+static __iomem void *tcdm_base;
+
+struct clk_mgt {
+ unsigned int offset;
+ u32 pllsw;
+};
+
+static DEFINE_SPINLOCK(clk_mgt_lock);
+
+#define CLK_MGT_ENTRY(_name)[PRCMU_##_name] = { (PRCM_##_name##_MGT), 0 }
+struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = {
+ CLK_MGT_ENTRY(SGACLK),
+ CLK_MGT_ENTRY(UARTCLK),
+ CLK_MGT_ENTRY(MSP02CLK),
+ CLK_MGT_ENTRY(MSP1CLK),
+ CLK_MGT_ENTRY(I2CCLK),
+ CLK_MGT_ENTRY(SDMMCCLK),
+ CLK_MGT_ENTRY(SLIMCLK),
+ CLK_MGT_ENTRY(PER1CLK),
+ CLK_MGT_ENTRY(PER2CLK),
+ CLK_MGT_ENTRY(PER3CLK),
+ CLK_MGT_ENTRY(PER5CLK),
+ CLK_MGT_ENTRY(PER6CLK),
+ CLK_MGT_ENTRY(PER7CLK),
+ CLK_MGT_ENTRY(LCDCLK),
+ CLK_MGT_ENTRY(BMLCLK),
+ CLK_MGT_ENTRY(HSITXCLK),
+ CLK_MGT_ENTRY(HSIRXCLK),
+ CLK_MGT_ENTRY(HDMICLK),
+ CLK_MGT_ENTRY(APEATCLK),
+ CLK_MGT_ENTRY(APETRACECLK),
+ CLK_MGT_ENTRY(MCDECLK),
+ CLK_MGT_ENTRY(IPI2CCLK),
+ CLK_MGT_ENTRY(DSIALTCLK),
+ CLK_MGT_ENTRY(DMACLK),
+ CLK_MGT_ENTRY(B2R2CLK),
+ CLK_MGT_ENTRY(TVCLK),
+ CLK_MGT_ENTRY(SSPCLK),
+ CLK_MGT_ENTRY(RNGCLK),
+ CLK_MGT_ENTRY(UICCCLK),
+};
+
+/*
+* Used by MCDE to setup all necessary PRCMU registers
+*/
+#define PRCMU_RESET_DSIPLL 0x00004000
+#define PRCMU_UNCLAMP_DSIPLL 0x00400800
+
+#define PRCMU_CLK_PLL_DIV_SHIFT 0
+#define PRCMU_CLK_PLL_SW_SHIFT 5
+#define PRCMU_CLK_38 (1 << 9)
+#define PRCMU_CLK_38_SRC (1 << 10)
+#define PRCMU_CLK_38_DIV (1 << 11)
+
+/* PLLDIV=12, PLLSW=4 (PLLDDR) */
+#define PRCMU_DSI_CLOCK_SETTING 0x0000008C
+
+/* PLLDIV=8, PLLSW=4 (PLLDDR) */
+#define PRCMU_DSI_CLOCK_SETTING_U8400 0x00000088
+
+/* DPI 50000000 Hz */
+#define PRCMU_DPI_CLOCK_SETTING ((1 << PRCMU_CLK_PLL_SW_SHIFT) | \
+ (16 << PRCMU_CLK_PLL_DIV_SHIFT))
+#define PRCMU_DSI_LP_CLOCK_SETTING 0x00000E00
+
+/* D=101, N=1, R=4, SELDIV2=0 */
+#define PRCMU_PLLDSI_FREQ_SETTING 0x00040165
+
+/* D=70, N=1, R=3, SELDIV2=0 */
+#define PRCMU_PLLDSI_FREQ_SETTING_U8400 0x00030146
+
+#define PRCMU_ENABLE_PLLDSI 0x00000001
+#define PRCMU_DISABLE_PLLDSI 0x00000000
+#define PRCMU_RELEASE_RESET_DSS 0x0000400C
+#define PRCMU_DSI_PLLOUT_SEL_SETTING 0x00000202
+/* ESC clk, div0=1, div1=1, div2=3 */
+#define PRCMU_ENABLE_ESCAPE_CLOCK_DIV 0x07030101
+#define PRCMU_DISABLE_ESCAPE_CLOCK_DIV 0x00030101
+#define PRCMU_DSI_RESET_SW 0x00000007
+
+#define PRCMU_PLLDSI_LOCKP_LOCKED 0x3
+
+static struct {
+ u8 project_number;
+ u8 api_version;
+ u8 func_version;
+ u8 errata;
+} prcmu_version;
+
+
+int prcmu_enable_dsipll(void)
+{
+ int i;
+ unsigned int plldsifreq;
+
+ /* Clear DSIPLL_RESETN */
+ writel(PRCMU_RESET_DSIPLL, (_PRCMU_BASE + PRCM_APE_RESETN_CLR));
+ /* Unclamp DSIPLL in/out */
+ writel(PRCMU_UNCLAMP_DSIPLL, (_PRCMU_BASE + PRCM_MMIP_LS_CLAMP_CLR));
+
+ if (prcmu_is_u8400())
+ plldsifreq = PRCMU_PLLDSI_FREQ_SETTING_U8400;
+ else
+ plldsifreq = PRCMU_PLLDSI_FREQ_SETTING;
+ /* Set DSI PLL FREQ */
+ writel(plldsifreq, (_PRCMU_BASE + PRCM_PLLDSI_FREQ));
+ writel(PRCMU_DSI_PLLOUT_SEL_SETTING,
+ (_PRCMU_BASE + PRCM_DSI_PLLOUT_SEL));
+ /* Enable Escape clocks */
+ writel(PRCMU_ENABLE_ESCAPE_CLOCK_DIV,
+ (_PRCMU_BASE + PRCM_DSITVCLK_DIV));
+
+ /* Start DSI PLL */
+ writel(PRCMU_ENABLE_PLLDSI, (_PRCMU_BASE + PRCM_PLLDSI_ENABLE));
+ /* Reset DSI PLL */
+ writel(PRCMU_DSI_RESET_SW, (_PRCMU_BASE + PRCM_DSI_SW_RESET));
+ for (i = 0; i < 10; i++) {
+ if ((readl(_PRCMU_BASE + PRCM_PLLDSI_LOCKP) &
+ PRCMU_PLLDSI_LOCKP_LOCKED)
+ == PRCMU_PLLDSI_LOCKP_LOCKED)
+ break;
+ udelay(100);
+ }
+ /* Set DSIPLL_RESETN */
+ writel(PRCMU_RESET_DSIPLL, (_PRCMU_BASE + PRCM_APE_RESETN_SET));
+ return 0;
+}
+
+int prcmu_disable_dsipll(void)
+{
+ /* Disable dsi pll */
+ writel(PRCMU_DISABLE_PLLDSI, (_PRCMU_BASE + PRCM_PLLDSI_ENABLE));
+ /* Disable escapeclock */
+ writel(PRCMU_DISABLE_ESCAPE_CLOCK_DIV,
+ (_PRCMU_BASE + PRCM_DSITVCLK_DIV));
+ return 0;
+}
+
+int prcmu_set_display_clocks(void)
+{
+ unsigned long flags;
+ unsigned int dsiclk;
+
+ if (prcmu_is_u8400())
+ dsiclk = PRCMU_DSI_CLOCK_SETTING_U8400;
+ else
+ dsiclk = PRCMU_DSI_CLOCK_SETTING;
+
+ spin_lock_irqsave(&clk_mgt_lock, flags);
+
+ /* Grab the HW semaphore. */
+ while ((readl(_PRCMU_BASE + PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
+ cpu_relax();
+
+ writel(dsiclk, (_PRCMU_BASE + PRCM_HDMICLK_MGT));
+ writel(PRCMU_DSI_LP_CLOCK_SETTING, (_PRCMU_BASE + PRCM_TVCLK_MGT));
+ writel(PRCMU_DPI_CLOCK_SETTING, (_PRCMU_BASE + PRCM_LCDCLK_MGT));
+
+ /* Release the HW semaphore. */
+ writel(0, (_PRCMU_BASE + PRCM_SEM));
+
+ spin_unlock_irqrestore(&clk_mgt_lock, flags);
+
+ return 0;
+}
+
+/**
+ * prcmu_enable_spi2 - Enables pin muxing for SPI2 on OtherAlternateC1.
+ */
+void prcmu_enable_spi2(void)
+{
+ u32 reg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gpiocr_lock, flags);
+ reg = readl(_PRCMU_BASE + PRCM_GPIOCR);
+ writel(reg | PRCM_GPIOCR_SPI2_SELECT, _PRCMU_BASE + PRCM_GPIOCR);
+ spin_unlock_irqrestore(&gpiocr_lock, flags);
+}
+
+/**
+ * prcmu_disable_spi2 - Disables pin muxing for SPI2 on OtherAlternateC1.
+ */
+void prcmu_disable_spi2(void)
+{
+ u32 reg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&gpiocr_lock, flags);
+ reg = readl(_PRCMU_BASE + PRCM_GPIOCR);
+ writel(reg & ~PRCM_GPIOCR_SPI2_SELECT, _PRCMU_BASE + PRCM_GPIOCR);
+ spin_unlock_irqrestore(&gpiocr_lock, flags);
+}
+
+bool prcmu_has_arm_maxopp(void)
+{
+ return (readb(tcdm_base + PRCM_AVS_VARM_MAX_OPP) &
+ PRCM_AVS_ISMODEENABLE_MASK) == PRCM_AVS_ISMODEENABLE_MASK;
+}
+
+bool prcmu_is_u8400(void)
+{
+ return prcmu_version.project_number == PRCMU_PROJECT_ID_8400V2_0;
+}
+
+/**
+ * prcmu_get_boot_status - PRCMU boot status checking
+ * Returns: the current PRCMU boot status
+ */
+int prcmu_get_boot_status(void)
+{
+ return readb(tcdm_base + PRCM_BOOT_STATUS);
+}
+
+/**
+ * prcmu_set_rc_a2p - This function is used to run few power state sequences
+ * @val: Value to be set, i.e. transition requested
+ * Returns: 0 on success, -EINVAL on invalid argument
+ *
+ * This function is used to run the following power state sequences -
+ * any state to ApReset, ApDeepSleep to ApExecute, ApExecute to ApDeepSleep
+ */
+int prcmu_set_rc_a2p(enum romcode_write val)
+{
+ if (val < RDY_2_DS || val > RDY_2_XP70_RST)
+ return -EINVAL;
+ writeb(val, (tcdm_base + PRCM_ROMCODE_A2P));
+ return 0;
+}
+
+/**
+ * prcmu_get_rc_p2a - This function is used to get power state sequences
+ * Returns: the power transition that has last happened
+ *
+ * This function can return the following transitions-
+ * any state to ApReset, ApDeepSleep to ApExecute, ApExecute to ApDeepSleep
+ */
+enum romcode_read prcmu_get_rc_p2a(void)
+{
+ return readb(tcdm_base + PRCM_ROMCODE_P2A);
+}
+
+/**
+ * prcmu_get_current_mode - Return the current XP70 power mode
+ * Returns: Returns the current AP(ARM) power mode: init,
+ * apBoot, apExecute, apDeepSleep, apSleep, apIdle, apReset
+ */
+enum ap_pwrst prcmu_get_xp70_current_state(void)
+{
+ return readb(tcdm_base + PRCM_XP70_CUR_PWR_STATE);
+}
+
+/**
+ * prcmu_config_clkout - Configure one of the programmable clock outputs.
+ * @clkout: The CLKOUT number (0 or 1).
+ * @source: The clock to be used (one of the PRCMU_CLKSRC_*).
+ * @div: The divider to be applied.
+ *
+ * Configures one of the programmable clock outputs (CLKOUTs).
+ * @div should be in the range [1,63] to request a configuration, or 0 to
+ * inform that the configuration is no longer requested.
+ */
+int prcmu_config_clkout(u8 clkout, u8 source, u8 div)
+{
+ static int requests[2];
+ int r = 0;
+ unsigned long flags;
+ u32 val;
+ u32 bits;
+ u32 mask;
+ u32 div_mask;
+
+ BUG_ON(clkout > 1);
+ BUG_ON(div > 63);
+ BUG_ON((clkout == 0) && (source > PRCMU_CLKSRC_CLK009));
+
+ if (!div && !requests[clkout])
+ return -EINVAL;
+
+ switch (clkout) {
+ case 0:
+ div_mask = PRCM_CLKOCR_CLKODIV0_MASK;
+ mask = (PRCM_CLKOCR_CLKODIV0_MASK | PRCM_CLKOCR_CLKOSEL0_MASK);
+ bits = ((source << PRCM_CLKOCR_CLKOSEL0_SHIFT) |
+ (div << PRCM_CLKOCR_CLKODIV0_SHIFT));
+ break;
+ case 1:
+ div_mask = PRCM_CLKOCR_CLKODIV1_MASK;
+ mask = (PRCM_CLKOCR_CLKODIV1_MASK | PRCM_CLKOCR_CLKOSEL1_MASK |
+ PRCM_CLKOCR_CLK1TYPE);
+ bits = ((source << PRCM_CLKOCR_CLKOSEL1_SHIFT) |
+ (div << PRCM_CLKOCR_CLKODIV1_SHIFT));
+ break;
+ }
+ bits &= mask;
+
+ spin_lock_irqsave(&clkout_lock, flags);
+
+ val = readl(_PRCMU_BASE + PRCM_CLKOCR);
+ if (val & div_mask) {
+ if (div) {
+ if ((val & mask) != bits) {
+ r = -EBUSY;
+ goto unlock_and_return;
+ }
+ } else {
+ if ((val & mask & ~div_mask) != bits) {
+ r = -EINVAL;
+ goto unlock_and_return;
+ }
+ }
+ }
+ writel((bits | (val & ~mask)), (_PRCMU_BASE + PRCM_CLKOCR));
+ requests[clkout] += (div ? 1 : -1);
+
+unlock_and_return:
+ spin_unlock_irqrestore(&clkout_lock, flags);
+
+ return r;
+}
+
+int prcmu_set_power_state(u8 state, bool keep_ulp_clk, bool keep_ap_pll)
+{
+ unsigned long flags;
+
+ BUG_ON((state < PRCMU_AP_SLEEP) || (PRCMU_AP_DEEP_IDLE < state));
+
+ spin_lock_irqsave(&mb0_transfer.lock, flags);
+
+ while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(0))
+ cpu_relax();
+
+ writeb(MB0H_POWER_STATE_TRANS, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB0));
+ writeb(state, (tcdm_base + PRCM_REQ_MB0_AP_POWER_STATE));
+ writeb((keep_ap_pll ? 1 : 0), (tcdm_base + PRCM_REQ_MB0_AP_PLL_STATE));
+ writeb((keep_ulp_clk ? 1 : 0),
+ (tcdm_base + PRCM_REQ_MB0_ULP_CLOCK_STATE));
+ writeb(0, (tcdm_base + PRCM_REQ_MB0_DO_NOT_WFI));
+ writel(MBOX_BIT(0), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+
+ spin_unlock_irqrestore(&mb0_transfer.lock, flags);
+
+ return 0;
+}
+
+/* This function should only be called while mb0_transfer.lock is held. */
+static void config_wakeups(void)
+{
+ const u8 header[2] = {
+ MB0H_CONFIG_WAKEUPS_EXE,
+ MB0H_CONFIG_WAKEUPS_SLEEP
+ };
+ static u32 last_dbb_events;
+ static u32 last_abb_events;
+ u32 dbb_events;
+ u32 abb_events;
+ unsigned int i;
+
+ dbb_events = mb0_transfer.req.dbb_irqs | mb0_transfer.req.dbb_wakeups;
+ dbb_events |= (WAKEUP_BIT_AC_WAKE_ACK | WAKEUP_BIT_AC_SLEEP_ACK);
+
+ abb_events = mb0_transfer.req.abb_events;
+
+ if ((dbb_events == last_dbb_events) && (abb_events == last_abb_events))
+ return;
+
+ for (i = 0; i < 2; i++) {
+ while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(0))
+ cpu_relax();
+ writel(dbb_events, (tcdm_base + PRCM_REQ_MB0_WAKEUP_8500));
+ writel(abb_events, (tcdm_base + PRCM_REQ_MB0_WAKEUP_4500));
+ writeb(header[i], (tcdm_base + PRCM_MBOX_HEADER_REQ_MB0));
+ writel(MBOX_BIT(0), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+ }
+ last_dbb_events = dbb_events;
+ last_abb_events = abb_events;
+}
+
+void prcmu_enable_wakeups(u32 wakeups)
+{
+ unsigned long flags;
+ u32 bits;
+ int i;
+
+ BUG_ON(wakeups != (wakeups & VALID_WAKEUPS));
+
+ for (i = 0, bits = 0; i < NUM_PRCMU_WAKEUP_INDICES; i++) {
+ if (wakeups & BIT(i))
+ bits |= prcmu_wakeup_bit[i];
+ }
+
+ spin_lock_irqsave(&mb0_transfer.lock, flags);
+
+ mb0_transfer.req.dbb_wakeups = bits;
+ config_wakeups();
+
+ spin_unlock_irqrestore(&mb0_transfer.lock, flags);
+}
+
+void prcmu_config_abb_event_readout(u32 abb_events)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mb0_transfer.lock, flags);
+
+ mb0_transfer.req.abb_events = abb_events;
+ config_wakeups();
+
+ spin_unlock_irqrestore(&mb0_transfer.lock, flags);
+}
+
+void prcmu_get_abb_event_buffer(void __iomem **buf)
+{
+ if (readb(tcdm_base + PRCM_ACK_MB0_READ_POINTER) & 1)
+ *buf = (tcdm_base + PRCM_ACK_MB0_WAKEUP_1_4500);
+ else
+ *buf = (tcdm_base + PRCM_ACK_MB0_WAKEUP_0_4500);
+}
+
+/**
+ * prcmu_set_arm_opp - set the appropriate ARM OPP
+ * @opp: The new ARM operating point to which transition is to be made
+ * Returns: 0 on success, non-zero on failure
+ *
+ * This function sets the the operating point of the ARM.
+ */
+int prcmu_set_arm_opp(u8 opp)
+{
+ int r;
+
+ if (opp < ARM_NO_CHANGE || opp > ARM_EXTCLK)
+ return -EINVAL;
+
+ r = 0;
+
+ mutex_lock(&mb1_transfer.lock);
+
+ while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
+ cpu_relax();
+
+ writeb(MB1H_ARM_APE_OPP, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
+ writeb(opp, (tcdm_base + PRCM_REQ_MB1_ARM_OPP));
+ writeb(APE_NO_CHANGE, (tcdm_base + PRCM_REQ_MB1_APE_OPP));
+
+ writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+ wait_for_completion(&mb1_transfer.work);
+
+ if ((mb1_transfer.ack.header != MB1H_ARM_APE_OPP) ||
+ (mb1_transfer.ack.arm_opp != opp))
+ r = -EIO;
+
+ mutex_unlock(&mb1_transfer.lock);
+
+ return r;
+}
+
+/**
+ * prcmu_get_arm_opp - get the current ARM OPP
+ *
+ * Returns: the current ARM OPP
+ */
+int prcmu_get_arm_opp(void)
+{
+ return readb(tcdm_base + PRCM_ACK_MB1_CURRENT_ARM_OPP);
+}
+
+/**
+ * prcmu_get_ddr_opp - get the current DDR OPP
+ *
+ * Returns: the current DDR OPP
+ */
+int prcmu_get_ddr_opp(void)
+{
+ return readb(_PRCMU_BASE + PRCM_DDR_SUBSYS_APE_MINBW);
+}
+
+/**
+ * set_ddr_opp - set the appropriate DDR OPP
+ * @opp: The new DDR operating point to which transition is to be made
+ * Returns: 0 on success, non-zero on failure
+ *
+ * This function sets the operating point of the DDR.
+ */
+int prcmu_set_ddr_opp(u8 opp)
+{
+ if (opp < DDR_100_OPP || opp > DDR_25_OPP)
+ return -EINVAL;
+ /* Changing the DDR OPP can hang the hardware pre-v21 */
+ if (cpu_is_u8500v20_or_later() && !cpu_is_u8500v20())
+ writeb(opp, (_PRCMU_BASE + PRCM_DDR_SUBSYS_APE_MINBW));
+
+ return 0;
+}
+/**
+ * set_ape_opp - set the appropriate APE OPP
+ * @opp: The new APE operating point to which transition is to be made
+ * Returns: 0 on success, non-zero on failure
+ *
+ * This function sets the operating point of the APE.
+ */
+int prcmu_set_ape_opp(u8 opp)
+{
+ int r = 0;
+
+ mutex_lock(&mb1_transfer.lock);
+
+ while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
+ cpu_relax();
+
+ writeb(MB1H_ARM_APE_OPP, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
+ writeb(ARM_NO_CHANGE, (tcdm_base + PRCM_REQ_MB1_ARM_OPP));
+ writeb(opp, (tcdm_base + PRCM_REQ_MB1_APE_OPP));
+
+ writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+ wait_for_completion(&mb1_transfer.work);
+
+ if ((mb1_transfer.ack.header != MB1H_ARM_APE_OPP) ||
+ (mb1_transfer.ack.ape_opp != opp))
+ r = -EIO;
+
+ mutex_unlock(&mb1_transfer.lock);
+
+ return r;
+}
+
+/**
+ * prcmu_get_ape_opp - get the current APE OPP
+ *
+ * Returns: the current APE OPP
+ */
+int prcmu_get_ape_opp(void)
+{
+ return readb(tcdm_base + PRCM_ACK_MB1_CURRENT_APE_OPP);
+}
+
+/**
+ * prcmu_request_ape_opp_100_voltage - Request APE OPP 100% voltage
+ * @enable: true to request the higher voltage, false to drop a request.
+ *
+ * Calls to this function to enable and disable requests must be balanced.
+ */
+int prcmu_request_ape_opp_100_voltage(bool enable)
+{
+ int r = 0;
+ u8 header;
+ static unsigned int requests;
+
+ mutex_lock(&mb1_transfer.lock);
+
+ if (enable) {
+ if (0 != requests++)
+ goto unlock_and_return;
+ header = MB1H_REQUEST_APE_OPP_100_VOLT;
+ } else {
+ if (requests == 0) {
+ r = -EIO;
+ goto unlock_and_return;
+ } else if (1 != requests--) {
+ goto unlock_and_return;
+ }
+ header = MB1H_RELEASE_APE_OPP_100_VOLT;
+ }
+
+ while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
+ cpu_relax();
+
+ writeb(header, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
+
+ writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+ wait_for_completion(&mb1_transfer.work);
+
+ if ((mb1_transfer.ack.header != header) ||
+ ((mb1_transfer.ack.ape_voltage_status & BIT(0)) != 0))
+ r = -EIO;
+
+unlock_and_return:
+ mutex_unlock(&mb1_transfer.lock);
+
+ return r;
+}
+
+/**
+ * prcmu_release_usb_wakeup_state - release the state required by a USB wakeup
+ *
+ * This function releases the power state requirements of a USB wakeup.
+ */
+int prcmu_release_usb_wakeup_state(void)
+{
+ int r = 0;
+
+ mutex_lock(&mb1_transfer.lock);
+
+ while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
+ cpu_relax();
+
+ writeb(MB1H_RELEASE_USB_WAKEUP,
+ (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
+
+ writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+ wait_for_completion(&mb1_transfer.work);
+
+ if ((mb1_transfer.ack.header != MB1H_RELEASE_USB_WAKEUP) ||
+ ((mb1_transfer.ack.ape_voltage_status & BIT(0)) != 0))
+ r = -EIO;
+
+ mutex_unlock(&mb1_transfer.lock);
+
+ return r;
+}
+
+/**
+ * prcmu_set_epod - set the state of a EPOD (power domain)
+ * @epod_id: The EPOD to set
+ * @epod_state: The new EPOD state
+ *
+ * This function sets the state of a EPOD (power domain). It may not be called
+ * from interrupt context.
+ */
+int prcmu_set_epod(u16 epod_id, u8 epod_state)
+{
+ int r = 0;
+ bool ram_retention = false;
+ int i;
+
+ /* check argument */
+ BUG_ON(epod_id >= NUM_EPOD_ID);
+
+ /* set flag if retention is possible */
+ switch (epod_id) {
+ case EPOD_ID_SVAMMDSP:
+ case EPOD_ID_SIAMMDSP:
+ case EPOD_ID_ESRAM12:
+ case EPOD_ID_ESRAM34:
+ ram_retention = true;
+ break;
+ }
+
+ /* check argument */
+ BUG_ON(epod_state > EPOD_STATE_ON);
+ BUG_ON(epod_state == EPOD_STATE_RAMRET && !ram_retention);
+
+ /* get lock */
+ mutex_lock(&mb2_transfer.lock);
+
+ /* wait for mailbox */
+ while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(2))
+ cpu_relax();
+
+ /* fill in mailbox */
+ for (i = 0; i < NUM_EPOD_ID; i++)
+ writeb(EPOD_STATE_NO_CHANGE, (tcdm_base + PRCM_REQ_MB2 + i));
+ writeb(epod_state, (tcdm_base + PRCM_REQ_MB2 + epod_id));
+
+ writeb(MB2H_DPS, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB2));
+
+ writel(MBOX_BIT(2), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+
+ /*
+ * The current firmware version does not handle errors correctly,
+ * and we cannot recover if there is an error.
+ * This is expected to change when the firmware is updated.
+ */
+ if (!wait_for_completion_timeout(&mb2_transfer.work,
+ msecs_to_jiffies(20000))) {
+ pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
+ __func__);
+ r = -EIO;
+ goto unlock_and_return;
+ }
+
+ if (mb2_transfer.ack.status != HWACC_PWR_ST_OK)
+ r = -EIO;
+
+unlock_and_return:
+ mutex_unlock(&mb2_transfer.lock);
+ return r;
+}
+
+/**
+ * prcmu_configure_auto_pm - Configure autonomous power management.
+ * @sleep: Configuration for ApSleep.
+ * @idle: Configuration for ApIdle.
+ */
+void prcmu_configure_auto_pm(struct prcmu_auto_pm_config *sleep,
+ struct prcmu_auto_pm_config *idle)
+{
+ u32 sleep_cfg;
+ u32 idle_cfg;
+ unsigned long flags;
+
+ BUG_ON((sleep == NULL) || (idle == NULL));
+
+ sleep_cfg = (sleep->sva_auto_pm_enable & 0xF);
+ sleep_cfg = ((sleep_cfg << 4) | (sleep->sia_auto_pm_enable & 0xF));
+ sleep_cfg = ((sleep_cfg << 8) | (sleep->sva_power_on & 0xFF));
+ sleep_cfg = ((sleep_cfg << 8) | (sleep->sia_power_on & 0xFF));
+ sleep_cfg = ((sleep_cfg << 4) | (sleep->sva_policy & 0xF));
+ sleep_cfg = ((sleep_cfg << 4) | (sleep->sia_policy & 0xF));
+
+ idle_cfg = (idle->sva_auto_pm_enable & 0xF);
+ idle_cfg = ((idle_cfg << 4) | (idle->sia_auto_pm_enable & 0xF));
+ idle_cfg = ((idle_cfg << 8) | (idle->sva_power_on & 0xFF));
+ idle_cfg = ((idle_cfg << 8) | (idle->sia_power_on & 0xFF));
+ idle_cfg = ((idle_cfg << 4) | (idle->sva_policy & 0xF));
+ idle_cfg = ((idle_cfg << 4) | (idle->sia_policy & 0xF));
+
+ spin_lock_irqsave(&mb2_transfer.auto_pm_lock, flags);
+
+ /*
+ * The autonomous power management configuration is done through
+ * fields in mailbox 2, but these fields are only used as shared
+ * variables - i.e. there is no need to send a message.
+ */
+ writel(sleep_cfg, (tcdm_base + PRCM_REQ_MB2_AUTO_PM_SLEEP));
+ writel(idle_cfg, (tcdm_base + PRCM_REQ_MB2_AUTO_PM_IDLE));
+
+ mb2_transfer.auto_pm_enabled =
+ ((sleep->sva_auto_pm_enable == PRCMU_AUTO_PM_ON) ||
+ (sleep->sia_auto_pm_enable == PRCMU_AUTO_PM_ON) ||
+ (idle->sva_auto_pm_enable == PRCMU_AUTO_PM_ON) ||
+ (idle->sia_auto_pm_enable == PRCMU_AUTO_PM_ON));
+
+ spin_unlock_irqrestore(&mb2_transfer.auto_pm_lock, flags);
+}
+EXPORT_SYMBOL(prcmu_configure_auto_pm);
+
+bool prcmu_is_auto_pm_enabled(void)
+{
+ return mb2_transfer.auto_pm_enabled;
+}
+
+static int request_sysclk(bool enable)
+{
+ int r;
+ unsigned long flags;
+
+ r = 0;
+
+ mutex_lock(&mb3_transfer.sysclk_lock);
+
+ spin_lock_irqsave(&mb3_transfer.lock, flags);
+
+ while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(3))
+ cpu_relax();
+
+ writeb((enable ? ON : OFF), (tcdm_base + PRCM_REQ_MB3_SYSCLK_MGT));
+
+ writeb(MB3H_SYSCLK, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB3));
+ writel(MBOX_BIT(3), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+
+ spin_unlock_irqrestore(&mb3_transfer.lock, flags);
+
+ /*
+ * The firmware only sends an ACK if we want to enable the
+ * SysClk, and it succeeds.
+ */
+ if (enable && !wait_for_completion_timeout(&mb3_transfer.sysclk_work,
+ msecs_to_jiffies(20000))) {
+ pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
+ __func__);
+ r = -EIO;
+ }
+
+ mutex_unlock(&mb3_transfer.sysclk_lock);
+
+ return r;
+}
+
+static int request_timclk(bool enable)
+{
+ u32 val = (PRCM_TCR_DOZE_MODE | PRCM_TCR_TENSEL_MASK);
+
+ if (!enable)
+ val |= PRCM_TCR_STOP_TIMERS;
+ writel(val, (_PRCMU_BASE + PRCM_TCR));
+
+ return 0;
+}
+
+static int request_reg_clock(u8 clock, bool enable)
+{
+ u32 val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&clk_mgt_lock, flags);
+
+ /* Grab the HW semaphore. */
+ while ((readl(_PRCMU_BASE + PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
+ cpu_relax();
+
+ val = readl(_PRCMU_BASE + clk_mgt[clock].offset);
+ if (enable) {
+ val |= (PRCM_CLK_MGT_CLKEN | clk_mgt[clock].pllsw);
+ } else {
+ clk_mgt[clock].pllsw = (val & PRCM_CLK_MGT_CLKPLLSW_MASK);
+ val &= ~(PRCM_CLK_MGT_CLKEN | PRCM_CLK_MGT_CLKPLLSW_MASK);
+ }
+ writel(val, (_PRCMU_BASE + clk_mgt[clock].offset));
+
+ /* Release the HW semaphore. */
+ writel(0, (_PRCMU_BASE + PRCM_SEM));
+
+ spin_unlock_irqrestore(&clk_mgt_lock, flags);
+
+ return 0;
+}
+
+/**
+ * prcmu_request_clock() - Request for a clock to be enabled or disabled.
+ * @clock: The clock for which the request is made.
+ * @enable: Whether the clock should be enabled (true) or disabled (false).
+ *
+ * This function should only be used by the clock implementation.
+ * Do not use it from any other place!
+ */
+int prcmu_request_clock(u8 clock, bool enable)
+{
+ if (clock < PRCMU_NUM_REG_CLOCKS)
+ return request_reg_clock(clock, enable);
+ else if (clock == PRCMU_TIMCLK)
+ return request_timclk(enable);
+ else if (clock == PRCMU_SYSCLK)
+ return request_sysclk(enable);
+ else
+ return -EINVAL;
+}
+
+int prcmu_config_esram0_deep_sleep(u8 state)
+{
+ if ((state > ESRAM0_DEEP_SLEEP_STATE_RET) ||
+ (state < ESRAM0_DEEP_SLEEP_STATE_OFF))
+ return -EINVAL;
+
+ mutex_lock(&mb4_transfer.lock);
+
+ while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
+ cpu_relax();
+
+ writeb(MB4H_MEM_ST, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4));
+ writeb(((DDR_PWR_STATE_OFFHIGHLAT << 4) | DDR_PWR_STATE_ON),
+ (tcdm_base + PRCM_REQ_MB4_DDR_ST_AP_SLEEP_IDLE));
+ writeb(DDR_PWR_STATE_ON,
+ (tcdm_base + PRCM_REQ_MB4_DDR_ST_AP_DEEP_IDLE));
+ writeb(state, (tcdm_base + PRCM_REQ_MB4_ESRAM0_ST));
+
+ writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+ wait_for_completion(&mb4_transfer.work);
+
+ mutex_unlock(&mb4_transfer.lock);
+
+ return 0;
+}
+
+int prcmu_config_hotdog(u8 threshold)
+{
+ mutex_lock(&mb4_transfer.lock);
+
+ while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
+ cpu_relax();
+
+ writeb(threshold, (tcdm_base + PRCM_REQ_MB4_HOTDOG_THRESHOLD));
+ writeb(MB4H_HOTDOG, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4));
+
+ writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+ wait_for_completion(&mb4_transfer.work);
+
+ mutex_unlock(&mb4_transfer.lock);
+
+ return 0;
+}
+
+int prcmu_config_hotmon(u8 low, u8 high)
+{
+ mutex_lock(&mb4_transfer.lock);
+
+ while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
+ cpu_relax();
+
+ writeb(low, (tcdm_base + PRCM_REQ_MB4_HOTMON_LOW));
+ writeb(high, (tcdm_base + PRCM_REQ_MB4_HOTMON_HIGH));
+ writeb((HOTMON_CONFIG_LOW | HOTMON_CONFIG_HIGH),
+ (tcdm_base + PRCM_REQ_MB4_HOTMON_CONFIG));
+ writeb(MB4H_HOTMON, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4));
+
+ writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+ wait_for_completion(&mb4_transfer.work);
+
+ mutex_unlock(&mb4_transfer.lock);
+
+ return 0;
+}
+
+static int config_hot_period(u16 val)
+{
+ mutex_lock(&mb4_transfer.lock);
+
+ while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(4))
+ cpu_relax();
+
+ writew(val, (tcdm_base + PRCM_REQ_MB4_HOT_PERIOD));
+ writeb(MB4H_HOT_PERIOD, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB4));
+
+ writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+ wait_for_completion(&mb4_transfer.work);
+
+ mutex_unlock(&mb4_transfer.lock);
+
+ return 0;
+}
+
+int prcmu_start_temp_sense(u16 cycles32k)
+{
+ if (cycles32k == 0xFFFF)
+ return -EINVAL;
+
+ return config_hot_period(cycles32k);
+}
+
+int prcmu_stop_temp_sense(void)
+{
+ return config_hot_period(0xFFFF);
+}
+
+/**
+ * prcmu_set_clock_divider() - Configure the clock divider.
+ * @clock: The clock for which the request is made.
+ * @divider: The clock divider. (< 32)
+ *
+ * This function should only be used by the clock implementation.
+ * Do not use it from any other place!
+ */
+int prcmu_set_clock_divider(u8 clock, u8 divider)
+{
+ u32 val;
+ unsigned long flags;
+
+ if ((clock >= PRCMU_NUM_REG_CLOCKS) || (divider < 1) || (31 < divider))
+ return -EINVAL;
+
+ spin_lock_irqsave(&clk_mgt_lock, flags);
+
+ /* Grab the HW semaphore. */
+ while ((readl(_PRCMU_BASE + PRCM_SEM) & PRCM_SEM_PRCM_SEM) != 0)
+ cpu_relax();
+
+ val = readl(_PRCMU_BASE + clk_mgt[clock].offset);
+ val &= ~(PRCM_CLK_MGT_CLKPLLDIV_MASK);
+ val |= (u32)divider;
+ writel(val, (_PRCMU_BASE + clk_mgt[clock].offset));
+
+ /* Release the HW semaphore. */
+ writel(0, (_PRCMU_BASE + PRCM_SEM));
+
+ spin_unlock_irqrestore(&clk_mgt_lock, flags);
+
+ return 0;
+}
+
+/**
+ * prcmu_abb_read() - Read register value(s) from the ABB.
+ * @slave: The I2C slave address.
+ * @reg: The (start) register address.
+ * @value: The read out value(s).
+ * @size: The number of registers to read.
+ *
+ * Reads register value(s) from the ABB.
+ * @size has to be 1 for the current firmware version.
+ */
+int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size)
+{
+ int r;
+
+ if (size != 1)
+ return -EINVAL;
+
+ mutex_lock(&mb5_transfer.lock);
+
+ while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
+ cpu_relax();
+
+ writeb(PRCMU_I2C_READ(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP));
+ writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS));
+ writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG));
+ writeb(0, (tcdm_base + PRCM_REQ_MB5_I2C_VAL));
+
+ writel(MBOX_BIT(5), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+
+ if (!wait_for_completion_timeout(&mb5_transfer.work,
+ msecs_to_jiffies(20000))) {
+ pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
+ __func__);
+ r = -EIO;
+ } else {
+ r = ((mb5_transfer.ack.status == I2C_RD_OK) ? 0 : -EIO);
+ }
+
+ if (!r)
+ *value = mb5_transfer.ack.value;
+
+ mutex_unlock(&mb5_transfer.lock);
+
+ return r;
+}
+
+/**
+ * prcmu_abb_write() - Write register value(s) to the ABB.
+ * @slave: The I2C slave address.
+ * @reg: The (start) register address.
+ * @value: The value(s) to write.
+ * @size: The number of registers to write.
+ *
+ * Reads register value(s) from the ABB.
+ * @size has to be 1 for the current firmware version.
+ */
+int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
+{
+ int r;
+
+ if (size != 1)
+ return -EINVAL;
+
+ mutex_lock(&mb5_transfer.lock);
+
+ while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(5))
+ cpu_relax();
+
+ writeb(PRCMU_I2C_WRITE(slave), (tcdm_base + PRCM_REQ_MB5_I2C_SLAVE_OP));
+ writeb(PRCMU_I2C_STOP_EN, (tcdm_base + PRCM_REQ_MB5_I2C_HW_BITS));
+ writeb(reg, (tcdm_base + PRCM_REQ_MB5_I2C_REG));
+ writeb(*value, (tcdm_base + PRCM_REQ_MB5_I2C_VAL));
+
+ writel(MBOX_BIT(5), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+
+ if (!wait_for_completion_timeout(&mb5_transfer.work,
+ msecs_to_jiffies(20000))) {
+ pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
+ __func__);
+ r = -EIO;
+ } else {
+ r = ((mb5_transfer.ack.status == I2C_WR_OK) ? 0 : -EIO);
+ }
+
+ mutex_unlock(&mb5_transfer.lock);
+
+ return r;
+}
+
+/**
+ * prcmu_ac_wake_req - should be called whenever ARM wants to wakeup Modem
+ */
+void prcmu_ac_wake_req(void)
+{
+ u32 val;
+
+ mutex_lock(&mb0_transfer.ac_wake_lock);
+
+ val = readl(_PRCMU_BASE + PRCM_HOSTACCESS_REQ);
+ if (val & PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ)
+ goto unlock_and_return;
+
+ atomic_set(&ac_wake_req_state, 1);
+
+ writel((val | PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ),
+ (_PRCMU_BASE + PRCM_HOSTACCESS_REQ));
+
+ if (!wait_for_completion_timeout(&mb0_transfer.ac_wake_work,
+ msecs_to_jiffies(20000))) {
+ pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
+ __func__);
+ }
+
+unlock_and_return:
+ mutex_unlock(&mb0_transfer.ac_wake_lock);
+}
+
+/**
+ * prcmu_ac_sleep_req - called when ARM no longer needs to talk to modem
+ */
+void prcmu_ac_sleep_req()
+{
+ u32 val;
+
+ mutex_lock(&mb0_transfer.ac_wake_lock);
+
+ val = readl(_PRCMU_BASE + PRCM_HOSTACCESS_REQ);
+ if (!(val & PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ))
+ goto unlock_and_return;
+
+ writel((val & ~PRCM_HOSTACCESS_REQ_HOSTACCESS_REQ),
+ (_PRCMU_BASE + PRCM_HOSTACCESS_REQ));
+
+ if (!wait_for_completion_timeout(&mb0_transfer.ac_wake_work,
+ msecs_to_jiffies(20000))) {
+ pr_err("prcmu: %s timed out (20 s) waiting for a reply.\n",
+ __func__);
+ }
+
+ atomic_set(&ac_wake_req_state, 0);
+
+unlock_and_return:
+ mutex_unlock(&mb0_transfer.ac_wake_lock);
+}
+
+bool prcmu_is_ac_wake_requested(void)
+{
+ return (atomic_read(&ac_wake_req_state) != 0);
+}
+
+/**
+ * prcmu_system_reset - System reset
+ *
+ * Saves the reset reason code and then sets the APE_SOFRST register which
+ * fires interrupt to fw
+ */
+void prcmu_system_reset(u16 reset_code)
+{
+ writew(reset_code, (tcdm_base + PRCM_SW_RST_REASON));
+ writel(1, (_PRCMU_BASE + PRCM_APE_SOFTRST));
+}
+
+/**
+ * prcmu_reset_modem - ask the PRCMU to reset modem
+ */
+void prcmu_modem_reset(void)
+{
+ mutex_lock(&mb1_transfer.lock);
+
+ while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
+ cpu_relax();
+
+ writeb(MB1H_RESET_MODEM, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB1));
+ writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+ wait_for_completion(&mb1_transfer.work);
+
+ /*
+ * No need to check return from PRCMU as modem should go in reset state
+ * This state is already managed by upper layer
+ */
+
+ mutex_unlock(&mb1_transfer.lock);
+}
+
+static void ack_dbb_wakeup(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mb0_transfer.lock, flags);
+
+ while (readl(_PRCMU_BASE + PRCM_MBOX_CPU_VAL) & MBOX_BIT(0))
+ cpu_relax();
+
+ writeb(MB0H_READ_WAKEUP_ACK, (tcdm_base + PRCM_MBOX_HEADER_REQ_MB0));
+ writel(MBOX_BIT(0), (_PRCMU_BASE + PRCM_MBOX_CPU_SET));
+
+ spin_unlock_irqrestore(&mb0_transfer.lock, flags);
+}
+
+static inline void print_unknown_header_warning(u8 n, u8 header)
+{
+ pr_warning("prcmu: Unknown message header (%d) in mailbox %d.\n",
+ header, n);
+}
+
+static bool read_mailbox_0(void)
+{
+ bool r;
+ u32 ev;
+ unsigned int n;
+ u8 header;
+
+ header = readb(tcdm_base + PRCM_MBOX_HEADER_ACK_MB0);
+ switch (header) {
+ case MB0H_WAKEUP_EXE:
+ case MB0H_WAKEUP_SLEEP:
+ if (readb(tcdm_base + PRCM_ACK_MB0_READ_POINTER) & 1)
+ ev = readl(tcdm_base + PRCM_ACK_MB0_WAKEUP_1_8500);
+ else
+ ev = readl(tcdm_base + PRCM_ACK_MB0_WAKEUP_0_8500);
+
+ if (ev & (WAKEUP_BIT_AC_WAKE_ACK | WAKEUP_BIT_AC_SLEEP_ACK))
+ complete(&mb0_transfer.ac_wake_work);
+ if (ev & WAKEUP_BIT_SYSCLK_OK)
+ complete(&mb3_transfer.sysclk_work);
+
+ ev &= mb0_transfer.req.dbb_irqs;
+
+ for (n = 0; n < NUM_PRCMU_WAKEUPS; n++) {
+ if (ev & prcmu_irq_bit[n])
+ generic_handle_irq(IRQ_PRCMU_BASE + n);
+ }
+ r = true;
+ break;
+ default:
+ print_unknown_header_warning(0, header);
+ r = false;
+ break;
+ }
+ writel(MBOX_BIT(0), (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+ return r;
+}
+
+static bool read_mailbox_1(void)
+{
+ mb1_transfer.ack.header = readb(tcdm_base + PRCM_MBOX_HEADER_REQ_MB1);
+ mb1_transfer.ack.arm_opp = readb(tcdm_base +
+ PRCM_ACK_MB1_CURRENT_ARM_OPP);
+ mb1_transfer.ack.ape_opp = readb(tcdm_base +
+ PRCM_ACK_MB1_CURRENT_APE_OPP);
+ mb1_transfer.ack.ape_voltage_status = readb(tcdm_base +
+ PRCM_ACK_MB1_APE_VOLTAGE_STATUS);
+ writel(MBOX_BIT(1), (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+ complete(&mb1_transfer.work);
+ return false;
+}
+
+static bool read_mailbox_2(void)
+{
+ mb2_transfer.ack.status = readb(tcdm_base + PRCM_ACK_MB2_DPS_STATUS);
+ writel(MBOX_BIT(2), (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+ complete(&mb2_transfer.work);
+ return false;
+}
+
+static bool read_mailbox_3(void)
+{
+ writel(MBOX_BIT(3), (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+ return false;
+}
+
+static bool read_mailbox_4(void)
+{
+ u8 header;
+ bool do_complete = true;
+
+ header = readb(tcdm_base + PRCM_MBOX_HEADER_REQ_MB4);
+ switch (header) {
+ case MB4H_MEM_ST:
+ case MB4H_HOTDOG:
+ case MB4H_HOTMON:
+ case MB4H_HOT_PERIOD:
+ break;
+ default:
+ print_unknown_header_warning(4, header);
+ do_complete = false;
+ break;
+ }
+
+ writel(MBOX_BIT(4), (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+
+ if (do_complete)
+ complete(&mb4_transfer.work);
+
+ return false;
+}
+
+static bool read_mailbox_5(void)
+{
+ mb5_transfer.ack.status = readb(tcdm_base + PRCM_ACK_MB5_I2C_STATUS);
+ mb5_transfer.ack.value = readb(tcdm_base + PRCM_ACK_MB5_I2C_VAL);
+ writel(MBOX_BIT(5), (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+ complete(&mb5_transfer.work);
+ return false;
+}
+
+static bool read_mailbox_6(void)
+{
+ writel(MBOX_BIT(6), (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+ return false;
+}
+
+static bool read_mailbox_7(void)
+{
+ writel(MBOX_BIT(7), (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+ return false;
+}
+
+static bool (* const read_mailbox[NUM_MB])(void) = {
+ read_mailbox_0,
+ read_mailbox_1,
+ read_mailbox_2,
+ read_mailbox_3,
+ read_mailbox_4,
+ read_mailbox_5,
+ read_mailbox_6,
+ read_mailbox_7
+};
+
+static irqreturn_t prcmu_irq_handler(int irq, void *data)
+{
+ u32 bits;
+ u8 n;
+ irqreturn_t r;
+
+ bits = (readl(_PRCMU_BASE + PRCM_ARM_IT1_VAL) & ALL_MBOX_BITS);
+ if (unlikely(!bits))
+ return IRQ_NONE;
+
+ r = IRQ_HANDLED;
+ for (n = 0; bits; n++) {
+ if (bits & MBOX_BIT(n)) {
+ bits -= MBOX_BIT(n);
+ if (read_mailbox[n]())
+ r = IRQ_WAKE_THREAD;
+ }
+ }
+ return r;
+}
+
+static irqreturn_t prcmu_irq_thread_fn(int irq, void *data)
+{
+ ack_dbb_wakeup();
+ return IRQ_HANDLED;
+}
+
+static void prcmu_mask_work(struct work_struct *work)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mb0_transfer.lock, flags);
+
+ config_wakeups();
+
+ spin_unlock_irqrestore(&mb0_transfer.lock, flags);
+}
+
+static void prcmu_irq_mask(struct irq_data *d)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags);
+
+ mb0_transfer.req.dbb_irqs &= ~prcmu_irq_bit[d->irq - IRQ_PRCMU_BASE];
+
+ spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags);
+
+ if (d->irq != IRQ_PRCMU_CA_SLEEP)
+ schedule_work(&mb0_transfer.mask_work);
+}
+
+static void prcmu_irq_unmask(struct irq_data *d)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags);
+
+ mb0_transfer.req.dbb_irqs |= prcmu_irq_bit[d->irq - IRQ_PRCMU_BASE];
+
+ spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags);
+
+ if (d->irq != IRQ_PRCMU_CA_SLEEP)
+ schedule_work(&mb0_transfer.mask_work);
+}
+
+static void noop(struct irq_data *d)
+{
+}
+
+static struct irq_chip prcmu_irq_chip = {
+ .name = "prcmu",
+ .irq_disable = prcmu_irq_mask,
+ .irq_ack = noop,
+ .irq_mask = prcmu_irq_mask,
+ .irq_unmask = prcmu_irq_unmask,
+};
+
+void __init prcmu_early_init(void)
+{
+ unsigned int i;
+
+ if (cpu_is_u8500v1()) {
+ tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE_V1);
+ } else if (cpu_is_u8500v2()) {
+ void *tcpm_base = ioremap_nocache(U8500_PRCMU_TCPM_BASE, SZ_4K);
+
+ if (tcpm_base != NULL) {
+ int version;
+ version = readl(tcpm_base + PRCMU_FW_VERSION_OFFSET);
+ prcmu_version.project_number = version & 0xFF;
+ prcmu_version.api_version = (version >> 8) & 0xFF;
+ prcmu_version.func_version = (version >> 16) & 0xFF;
+ prcmu_version.errata = (version >> 24) & 0xFF;
+ pr_info("PRCMU firmware version %d.%d.%d\n",
+ (version >> 8) & 0xFF, (version >> 16) & 0xFF,
+ (version >> 24) & 0xFF);
+ iounmap(tcpm_base);
+ }
+
+ tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE);
+ } else {
+ pr_err("prcmu: Unsupported chip version\n");
+ BUG();
+ }
+
+ spin_lock_init(&mb0_transfer.lock);
+ spin_lock_init(&mb0_transfer.dbb_irqs_lock);
+ mutex_init(&mb0_transfer.ac_wake_lock);
+ init_completion(&mb0_transfer.ac_wake_work);
+ mutex_init(&mb1_transfer.lock);
+ init_completion(&mb1_transfer.work);
+ mutex_init(&mb2_transfer.lock);
+ init_completion(&mb2_transfer.work);
+ spin_lock_init(&mb2_transfer.auto_pm_lock);
+ spin_lock_init(&mb3_transfer.lock);
+ mutex_init(&mb3_transfer.sysclk_lock);
+ init_completion(&mb3_transfer.sysclk_work);
+ mutex_init(&mb4_transfer.lock);
+ init_completion(&mb4_transfer.work);
+ mutex_init(&mb5_transfer.lock);
+ init_completion(&mb5_transfer.work);
+
+ INIT_WORK(&mb0_transfer.mask_work, prcmu_mask_work);
+
+ /* Initalize irqs. */
+ for (i = 0; i < NUM_PRCMU_WAKEUPS; i++) {
+ unsigned int irq;
+
+ irq = IRQ_PRCMU_BASE + i;
+ irq_set_chip_and_handler(irq, &prcmu_irq_chip,
+ handle_simple_irq);
+ set_irq_flags(irq, IRQF_VALID);
+ }
+}
+
+/*
+ * Power domain switches (ePODs) modeled as regulators for the DB8500 SoC
+ */
+static struct regulator_consumer_supply db8500_vape_consumers[] = {
+ REGULATOR_SUPPLY("v-ape", NULL),
+ REGULATOR_SUPPLY("v-i2c", "nmk-i2c.0"),
+ REGULATOR_SUPPLY("v-i2c", "nmk-i2c.1"),
+ REGULATOR_SUPPLY("v-i2c", "nmk-i2c.2"),
+ REGULATOR_SUPPLY("v-i2c", "nmk-i2c.3"),
+ /* "v-mmc" changed to "vcore" in the mainline kernel */
+ REGULATOR_SUPPLY("vcore", "sdi0"),
+ REGULATOR_SUPPLY("vcore", "sdi1"),
+ REGULATOR_SUPPLY("vcore", "sdi2"),
+ REGULATOR_SUPPLY("vcore", "sdi3"),
+ REGULATOR_SUPPLY("vcore", "sdi4"),
+ REGULATOR_SUPPLY("v-dma", "dma40.0"),
+ REGULATOR_SUPPLY("v-ape", "ab8500-usb.0"),
+ /* "v-uart" changed to "vcore" in the mainline kernel */
+ REGULATOR_SUPPLY("vcore", "uart0"),
+ REGULATOR_SUPPLY("vcore", "uart1"),
+ REGULATOR_SUPPLY("vcore", "uart2"),
+ REGULATOR_SUPPLY("v-ape", "nmk-ske-keypad.0"),
+};
+
+static struct regulator_consumer_supply db8500_vsmps2_consumers[] = {
+ /* CG2900 and CW1200 power to off-chip peripherals */
+ REGULATOR_SUPPLY("gbf_1v8", "cg2900-uart.0"),
+ REGULATOR_SUPPLY("wlan_1v8", "cw1200.0"),
+ REGULATOR_SUPPLY("musb_1v8", "ab8500-usb.0"),
+ /* AV8100 regulator */
+ REGULATOR_SUPPLY("hdmi_1v8", "0-0070"),
+};
+
+static struct regulator_consumer_supply db8500_b2r2_mcde_consumers[] = {
+ REGULATOR_SUPPLY("vsupply", "b2r2.0"),
+ REGULATOR_SUPPLY("vsupply", "mcde.0"),
+};
+
+static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
+ [DB8500_REGULATOR_VAPE] = {
+ .constraints = {
+ .name = "db8500-vape",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .consumer_supplies = db8500_vape_consumers,
+ .num_consumer_supplies = ARRAY_SIZE(db8500_vape_consumers),
+ },
+ [DB8500_REGULATOR_VARM] = {
+ .constraints = {
+ .name = "db8500-varm",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ },
+ [DB8500_REGULATOR_VMODEM] = {
+ .constraints = {
+ .name = "db8500-vmodem",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ },
+ [DB8500_REGULATOR_VPLL] = {
+ .constraints = {
+ .name = "db8500-vpll",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ },
+ [DB8500_REGULATOR_VSMPS1] = {
+ .constraints = {
+ .name = "db8500-vsmps1",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ },
+ [DB8500_REGULATOR_VSMPS2] = {
+ .constraints = {
+ .name = "db8500-vsmps2",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .consumer_supplies = db8500_vsmps2_consumers,
+ .num_consumer_supplies = ARRAY_SIZE(db8500_vsmps2_consumers),
+ },
+ [DB8500_REGULATOR_VSMPS3] = {
+ .constraints = {
+ .name = "db8500-vsmps3",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ },
+ [DB8500_REGULATOR_VRF1] = {
+ .constraints = {
+ .name = "db8500-vrf1",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ },
+ [DB8500_REGULATOR_SWITCH_SVAMMDSP] = {
+ .supply_regulator = "db8500-vape",
+ .constraints = {
+ .name = "db8500-sva-mmdsp",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ },
+ [DB8500_REGULATOR_SWITCH_SVAMMDSPRET] = {
+ .constraints = {
+ /* "ret" means "retention" */
+ .name = "db8500-sva-mmdsp-ret",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ },
+ [DB8500_REGULATOR_SWITCH_SVAPIPE] = {
+ .supply_regulator = "db8500-vape",
+ .constraints = {
+ .name = "db8500-sva-pipe",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ },
+ [DB8500_REGULATOR_SWITCH_SIAMMDSP] = {
+ .supply_regulator = "db8500-vape",
+ .constraints = {
+ .name = "db8500-sia-mmdsp",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ },
+ [DB8500_REGULATOR_SWITCH_SIAMMDSPRET] = {
+ .constraints = {
+ .name = "db8500-sia-mmdsp-ret",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ },
+ [DB8500_REGULATOR_SWITCH_SIAPIPE] = {
+ .supply_regulator = "db8500-vape",
+ .constraints = {
+ .name = "db8500-sia-pipe",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ },
+ [DB8500_REGULATOR_SWITCH_SGA] = {
+ .supply_regulator = "db8500-vape",
+ .constraints = {
+ .name = "db8500-sga",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ },
+ [DB8500_REGULATOR_SWITCH_B2R2_MCDE] = {
+ .supply_regulator = "db8500-vape",
+ .constraints = {
+ .name = "db8500-b2r2-mcde",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ .consumer_supplies = db8500_b2r2_mcde_consumers,
+ .num_consumer_supplies = ARRAY_SIZE(db8500_b2r2_mcde_consumers),
+ },
+ [DB8500_REGULATOR_SWITCH_ESRAM12] = {
+ .supply_regulator = "db8500-vape",
+ .constraints = {
+ .name = "db8500-esram12",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ },
+ [DB8500_REGULATOR_SWITCH_ESRAM12RET] = {
+ .constraints = {
+ .name = "db8500-esram12-ret",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ },
+ [DB8500_REGULATOR_SWITCH_ESRAM34] = {
+ .supply_regulator = "db8500-vape",
+ .constraints = {
+ .name = "db8500-esram34",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ },
+ [DB8500_REGULATOR_SWITCH_ESRAM34RET] = {
+ .constraints = {
+ .name = "db8500-esram34-ret",
+ .valid_ops_mask = REGULATOR_CHANGE_STATUS,
+ },
+ },
+};
+
+static struct mfd_cell db8500_prcmu_devs[] = {
+ {
+ .name = "db8500-prcmu-regulators",
+ .mfd_data = &db8500_regulators,
+ },
+ {
+ .name = "cpufreq-u8500",
+ },
+};
+
+/**
+ * prcmu_fw_init - arch init call for the Linux PRCMU fw init logic
+ *
+ */
+static int __init db8500_prcmu_probe(struct platform_device *pdev)
+{
+ int err = 0;
+
+ if (ux500_is_svp())
+ return -ENODEV;
+
+ /* Clean up the mailbox interrupts after pre-kernel code. */
+ writel(ALL_MBOX_BITS, (_PRCMU_BASE + PRCM_ARM_IT1_CLR));
+
+ err = request_threaded_irq(IRQ_DB8500_PRCMU1, prcmu_irq_handler,
+ prcmu_irq_thread_fn, IRQF_NO_SUSPEND, "prcmu", NULL);
+ if (err < 0) {
+ pr_err("prcmu: Failed to allocate IRQ_DB8500_PRCMU1.\n");
+ err = -EBUSY;
+ goto no_irq_return;
+ }
+
+ if (cpu_is_u8500v20_or_later())
+ prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET);
+
+ err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs,
+ ARRAY_SIZE(db8500_prcmu_devs), NULL,
+ 0);
+
+ if (err)
+ pr_err("prcmu: Failed to add subdevices\n");
+ else
+ pr_info("DB8500 PRCMU initialized\n");
+
+no_irq_return:
+ return err;
+}
+
+static struct platform_driver db8500_prcmu_driver = {
+ .driver = {
+ .name = "db8500-prcmu",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init db8500_prcmu_init(void)
+{
+ return platform_driver_probe(&db8500_prcmu_driver, db8500_prcmu_probe);
+}
+
+arch_initcall(db8500_prcmu_init);
+
+MODULE_AUTHOR("Mattias Nilsson <mattias.i.nilsson@stericsson.com>");
+MODULE_DESCRIPTION("DB8500 PRCM Unit driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c
index fb9770b39a32..2808bd125d13 100644
--- a/drivers/mfd/htc-pasic3.c
+++ b/drivers/mfd/htc-pasic3.c
@@ -117,7 +117,8 @@ static struct mfd_cell ds1wm_cell __initdata = {
.name = "ds1wm",
.enable = ds1wm_enable,
.disable = ds1wm_disable,
- .mfd_data = &ds1wm_pdata,
+ .platform_data = &ds1wm_pdata,
+ .pdata_size = sizeof(ds1wm_pdata),
.num_resources = 2,
.resources = ds1wm_resources,
};
@@ -172,6 +173,8 @@ static int __init pasic3_probe(struct platform_device *pdev)
}
if (pdata && pdata->led_pdata) {
+ led_cell.platform_data = pdata->led_pdata;
+ led_cell.pdata_size = sizeof(struct pasic3_leds_machinfo);
ret = mfd_add_devices(&pdev->dev, pdev->id, &led_cell, 1, r, 0);
if (ret < 0)
dev_warn(dev, "failed to register LED device\n");
diff --git a/drivers/mfd/janz-cmodio.c b/drivers/mfd/janz-cmodio.c
index fc4191137e90..5c2a06acb77f 100644
--- a/drivers/mfd/janz-cmodio.c
+++ b/drivers/mfd/janz-cmodio.c
@@ -86,7 +86,8 @@ static int __devinit cmodio_setup_subdevice(struct cmodio_device *priv,
/* Add platform data */
pdata->modno = modno;
- cell->mfd_data = pdata;
+ cell->platform_data = pdata;
+ cell->pdata_size = sizeof(*pdata);
/* MODULbus registers -- PCI BAR3 is big-endian MODULbus access */
res->flags = IORESOURCE_MEM;
diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c
index 58cc5fdde016..e1e59c92f758 100644
--- a/drivers/mfd/max8925-core.c
+++ b/drivers/mfd/max8925-core.c
@@ -627,7 +627,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip,
goto out_dev;
}
- if (pdata && pdata->regulator[0]) {
+ if (pdata) {
ret = mfd_add_devices(chip->dev, 0, &regulator_devs[0],
ARRAY_SIZE(regulator_devs),
&regulator_resources[0], 0);
diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
index 668634e89e81..7e4d44bf92ab 100644
--- a/drivers/mfd/mc13xxx-core.c
+++ b/drivers/mfd/mc13xxx-core.c
@@ -683,13 +683,14 @@ out:
EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion);
static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx,
- const char *format, void *pdata)
+ const char *format, void *pdata, size_t pdata_size)
{
char buf[30];
const char *name = mc13xxx_get_chipname(mc13xxx);
struct mfd_cell cell = {
- .mfd_data = pdata,
+ .platform_data = pdata,
+ .pdata_size = pdata_size,
};
/* there is no asnprintf in the kernel :-( */
@@ -705,7 +706,7 @@ static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx,
static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
{
- return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL);
+ return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0);
}
static int mc13xxx_probe(struct spi_device *spi)
@@ -764,7 +765,7 @@ err_revision:
if (pdata->flags & MC13XXX_USE_REGULATOR) {
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
- &pdata->regulators);
+ &pdata->regulators, sizeof(pdata->regulators));
}
if (pdata->flags & MC13XXX_USE_RTC)
@@ -774,7 +775,8 @@ err_revision:
mc13xxx_add_subdevice(mc13xxx, "%s-ts");
if (pdata->flags & MC13XXX_USE_LED)
- mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led", pdata->leds);
+ mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led",
+ pdata->leds, sizeof(*pdata->leds));
return 0;
}
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index f4c8c844b913..0902523af62d 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -88,6 +88,13 @@ static int mfd_add_device(struct device *parent, int id,
pdev->dev.parent = parent;
+ if (cell->pdata_size) {
+ ret = platform_device_add_data(pdev,
+ cell->platform_data, cell->pdata_size);
+ if (ret)
+ goto fail_res;
+ }
+
ret = mfd_platform_add_cell(pdev, cell);
if (ret)
goto fail_res;
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
index 3ab9ffa00aad..855219526ccb 100644
--- a/drivers/mfd/omap-usb-host.c
+++ b/drivers/mfd/omap-usb-host.c
@@ -26,6 +26,7 @@
#include <linux/spinlock.h>
#include <linux/gpio.h>
#include <plat/usb.h>
+#include <linux/pm_runtime.h>
#define USBHS_DRIVER_NAME "usbhs-omap"
#define OMAP_EHCI_DEVICE "ehci-omap"
@@ -146,9 +147,6 @@
struct usbhs_hcd_omap {
- struct clk *usbhost_ick;
- struct clk *usbhost_hs_fck;
- struct clk *usbhost_fs_fck;
struct clk *xclk60mhsp1_ck;
struct clk *xclk60mhsp2_ck;
struct clk *utmi_p1_fck;
@@ -158,8 +156,6 @@ struct usbhs_hcd_omap {
struct clk *usbhost_p2_fck;
struct clk *usbtll_p2_fck;
struct clk *init_60m_fclk;
- struct clk *usbtll_fck;
- struct clk *usbtll_ick;
void __iomem *uhh_base;
void __iomem *tll_base;
@@ -281,6 +277,7 @@ static int omap_usbhs_alloc_children(struct platform_device *pdev)
if (!ehci) {
dev_err(dev, "omap_usbhs_alloc_child failed\n");
+ ret = -ENOMEM;
goto err_end;
}
@@ -304,13 +301,14 @@ static int omap_usbhs_alloc_children(struct platform_device *pdev)
sizeof(*ohci_data), dev);
if (!ohci) {
dev_err(dev, "omap_usbhs_alloc_child failed\n");
+ ret = -ENOMEM;
goto err_ehci;
}
return 0;
err_ehci:
- platform_device_put(ehci);
+ platform_device_unregister(ehci);
err_end:
return ret;
@@ -351,46 +349,13 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev)
omap->platdata.ehci_data = pdata->ehci_data;
omap->platdata.ohci_data = pdata->ohci_data;
- omap->usbhost_ick = clk_get(dev, "usbhost_ick");
- if (IS_ERR(omap->usbhost_ick)) {
- ret = PTR_ERR(omap->usbhost_ick);
- dev_err(dev, "usbhost_ick failed error:%d\n", ret);
- goto err_end;
- }
-
- omap->usbhost_hs_fck = clk_get(dev, "hs_fck");
- if (IS_ERR(omap->usbhost_hs_fck)) {
- ret = PTR_ERR(omap->usbhost_hs_fck);
- dev_err(dev, "usbhost_hs_fck failed error:%d\n", ret);
- goto err_usbhost_ick;
- }
-
- omap->usbhost_fs_fck = clk_get(dev, "fs_fck");
- if (IS_ERR(omap->usbhost_fs_fck)) {
- ret = PTR_ERR(omap->usbhost_fs_fck);
- dev_err(dev, "usbhost_fs_fck failed error:%d\n", ret);
- goto err_usbhost_hs_fck;
- }
-
- omap->usbtll_fck = clk_get(dev, "usbtll_fck");
- if (IS_ERR(omap->usbtll_fck)) {
- ret = PTR_ERR(omap->usbtll_fck);
- dev_err(dev, "usbtll_fck failed error:%d\n", ret);
- goto err_usbhost_fs_fck;
- }
-
- omap->usbtll_ick = clk_get(dev, "usbtll_ick");
- if (IS_ERR(omap->usbtll_ick)) {
- ret = PTR_ERR(omap->usbtll_ick);
- dev_err(dev, "usbtll_ick failed error:%d\n", ret);
- goto err_usbtll_fck;
- }
+ pm_runtime_enable(&pdev->dev);
omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
if (IS_ERR(omap->utmi_p1_fck)) {
ret = PTR_ERR(omap->utmi_p1_fck);
dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
- goto err_usbtll_ick;
+ goto err_end;
}
omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
@@ -520,22 +485,8 @@ err_xclk60mhsp1_ck:
err_utmi_p1_fck:
clk_put(omap->utmi_p1_fck);
-err_usbtll_ick:
- clk_put(omap->usbtll_ick);
-
-err_usbtll_fck:
- clk_put(omap->usbtll_fck);
-
-err_usbhost_fs_fck:
- clk_put(omap->usbhost_fs_fck);
-
-err_usbhost_hs_fck:
- clk_put(omap->usbhost_hs_fck);
-
-err_usbhost_ick:
- clk_put(omap->usbhost_ick);
-
err_end:
+ pm_runtime_disable(&pdev->dev);
kfree(omap);
end_probe:
@@ -569,11 +520,7 @@ static int __devexit usbhs_omap_remove(struct platform_device *pdev)
clk_put(omap->utmi_p2_fck);
clk_put(omap->xclk60mhsp1_ck);
clk_put(omap->utmi_p1_fck);
- clk_put(omap->usbtll_ick);
- clk_put(omap->usbtll_fck);
- clk_put(omap->usbhost_fs_fck);
- clk_put(omap->usbhost_hs_fck);
- clk_put(omap->usbhost_ick);
+ pm_runtime_disable(&pdev->dev);
kfree(omap);
return 0;
@@ -693,7 +640,6 @@ static int usbhs_enable(struct device *dev)
struct usbhs_omap_platform_data *pdata = &omap->platdata;
unsigned long flags = 0;
int ret = 0;
- unsigned long timeout;
unsigned reg;
dev_dbg(dev, "starting TI HSUSB Controller\n");
@@ -706,11 +652,7 @@ static int usbhs_enable(struct device *dev)
if (omap->count > 0)
goto end_count;
- clk_enable(omap->usbhost_ick);
- clk_enable(omap->usbhost_hs_fck);
- clk_enable(omap->usbhost_fs_fck);
- clk_enable(omap->usbtll_fck);
- clk_enable(omap->usbtll_ick);
+ pm_runtime_get_sync(dev);
if (pdata->ehci_data->phy_reset) {
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) {
@@ -734,50 +676,6 @@ static int usbhs_enable(struct device *dev)
omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev);
- /* perform TLL soft reset, and wait until reset is complete */
- usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
- OMAP_USBTLL_SYSCONFIG_SOFTRESET);
-
- /* Wait for TLL reset to complete */
- timeout = jiffies + msecs_to_jiffies(1000);
- while (!(usbhs_read(omap->tll_base, OMAP_USBTLL_SYSSTATUS)
- & OMAP_USBTLL_SYSSTATUS_RESETDONE)) {
- cpu_relax();
-
- if (time_after(jiffies, timeout)) {
- dev_dbg(dev, "operation timed out\n");
- ret = -EINVAL;
- goto err_tll;
- }
- }
-
- dev_dbg(dev, "TLL RESET DONE\n");
-
- /* (1<<3) = no idle mode only for initial debugging */
- usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
- OMAP_USBTLL_SYSCONFIG_ENAWAKEUP |
- OMAP_USBTLL_SYSCONFIG_SIDLEMODE |
- OMAP_USBTLL_SYSCONFIG_AUTOIDLE);
-
- /* Put UHH in NoIdle/NoStandby mode */
- reg = usbhs_read(omap->uhh_base, OMAP_UHH_SYSCONFIG);
- if (is_omap_usbhs_rev1(omap)) {
- reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP
- | OMAP_UHH_SYSCONFIG_SIDLEMODE
- | OMAP_UHH_SYSCONFIG_CACTIVITY
- | OMAP_UHH_SYSCONFIG_MIDLEMODE);
- reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE;
-
-
- } else if (is_omap_usbhs_rev2(omap)) {
- reg &= ~OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR;
- reg |= OMAP4_UHH_SYSCONFIG_NOIDLE;
- reg &= ~OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR;
- reg |= OMAP4_UHH_SYSCONFIG_NOSTDBY;
- }
-
- usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg);
-
reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
/* setup ULPI bypass and burst configurations */
reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
@@ -917,6 +815,8 @@ end_count:
return 0;
err_tll:
+ pm_runtime_put_sync(dev);
+ spin_unlock_irqrestore(&omap->lock, flags);
if (pdata->ehci_data->phy_reset) {
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
gpio_free(pdata->ehci_data->reset_gpio_port[0]);
@@ -924,13 +824,6 @@ err_tll:
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
gpio_free(pdata->ehci_data->reset_gpio_port[1]);
}
-
- clk_disable(omap->usbtll_ick);
- clk_disable(omap->usbtll_fck);
- clk_disable(omap->usbhost_fs_fck);
- clk_disable(omap->usbhost_hs_fck);
- clk_disable(omap->usbhost_ick);
- spin_unlock_irqrestore(&omap->lock, flags);
return ret;
}
@@ -994,6 +887,20 @@ static void usbhs_disable(struct device *dev)
dev_dbg(dev, "operation timed out\n");
}
+ if (is_omap_usbhs_rev2(omap)) {
+ if (is_ehci_tll_mode(pdata->port_mode[0]))
+ clk_enable(omap->usbtll_p1_fck);
+ if (is_ehci_tll_mode(pdata->port_mode[1]))
+ clk_enable(omap->usbtll_p2_fck);
+ clk_disable(omap->utmi_p2_fck);
+ clk_disable(omap->utmi_p1_fck);
+ }
+
+ pm_runtime_put_sync(dev);
+
+ /* The gpio_free migh sleep; so unlock the spinlock */
+ spin_unlock_irqrestore(&omap->lock, flags);
+
if (pdata->ehci_data->phy_reset) {
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
gpio_free(pdata->ehci_data->reset_gpio_port[0]);
@@ -1001,14 +908,7 @@ static void usbhs_disable(struct device *dev)
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
gpio_free(pdata->ehci_data->reset_gpio_port[1]);
}
-
- clk_disable(omap->utmi_p2_fck);
- clk_disable(omap->utmi_p1_fck);
- clk_disable(omap->usbtll_ick);
- clk_disable(omap->usbtll_fck);
- clk_disable(omap->usbhost_fs_fck);
- clk_disable(omap->usbhost_hs_fck);
- clk_disable(omap->usbhost_ick);
+ return;
end_disble:
spin_unlock_irqrestore(&omap->lock, flags);
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
new file mode 100644
index 000000000000..e873b15753d8
--- /dev/null
+++ b/drivers/mfd/pm8921-core.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 2011, 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/msm_ssbi.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/pm8xxx/pm8921.h>
+#include <linux/mfd/pm8xxx/core.h>
+
+#define REG_HWREV 0x002 /* PMIC4 revision */
+#define REG_HWREV_2 0x0E8 /* PMIC4 revision 2 */
+
+struct pm8921 {
+ struct device *dev;
+ struct pm_irq_chip *irq_chip;
+};
+
+static int pm8921_readb(const struct device *dev, u16 addr, u8 *val)
+{
+ const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
+ const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
+
+ return msm_ssbi_read(pmic->dev->parent, addr, val, 1);
+}
+
+static int pm8921_writeb(const struct device *dev, u16 addr, u8 val)
+{
+ const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
+ const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
+
+ return msm_ssbi_write(pmic->dev->parent, addr, &val, 1);
+}
+
+static int pm8921_read_buf(const struct device *dev, u16 addr, u8 *buf,
+ int cnt)
+{
+ const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
+ const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
+
+ return msm_ssbi_read(pmic->dev->parent, addr, buf, cnt);
+}
+
+static int pm8921_write_buf(const struct device *dev, u16 addr, u8 *buf,
+ int cnt)
+{
+ const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
+ const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
+
+ return msm_ssbi_write(pmic->dev->parent, addr, buf, cnt);
+}
+
+static int pm8921_read_irq_stat(const struct device *dev, int irq)
+{
+ const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
+ const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
+
+ return pm8xxx_get_irq_stat(pmic->irq_chip, irq);
+}
+
+static struct pm8xxx_drvdata pm8921_drvdata = {
+ .pmic_readb = pm8921_readb,
+ .pmic_writeb = pm8921_writeb,
+ .pmic_read_buf = pm8921_read_buf,
+ .pmic_write_buf = pm8921_write_buf,
+ .pmic_read_irq_stat = pm8921_read_irq_stat,
+};
+
+static int __devinit pm8921_add_subdevices(const struct pm8921_platform_data
+ *pdata,
+ struct pm8921 *pmic,
+ u32 rev)
+{
+ int ret = 0, irq_base = 0;
+ struct pm_irq_chip *irq_chip;
+
+ if (pdata->irq_pdata) {
+ pdata->irq_pdata->irq_cdata.nirqs = PM8921_NR_IRQS;
+ pdata->irq_pdata->irq_cdata.rev = rev;
+ irq_base = pdata->irq_pdata->irq_base;
+ irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
+
+ if (IS_ERR(irq_chip)) {
+ pr_err("Failed to init interrupts ret=%ld\n",
+ PTR_ERR(irq_chip));
+ return PTR_ERR(irq_chip);
+ }
+ pmic->irq_chip = irq_chip;
+ }
+ return ret;
+}
+
+static int __devinit pm8921_probe(struct platform_device *pdev)
+{
+ const struct pm8921_platform_data *pdata = pdev->dev.platform_data;
+ struct pm8921 *pmic;
+ int rc;
+ u8 val;
+ u32 rev;
+
+ if (!pdata) {
+ pr_err("missing platform data\n");
+ return -EINVAL;
+ }
+
+ pmic = kzalloc(sizeof(struct pm8921), GFP_KERNEL);
+ if (!pmic) {
+ pr_err("Cannot alloc pm8921 struct\n");
+ return -ENOMEM;
+ }
+
+ /* Read PMIC chip revision */
+ rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV, &val, sizeof(val));
+ if (rc) {
+ pr_err("Failed to read hw rev reg %d:rc=%d\n", REG_HWREV, rc);
+ goto err_read_rev;
+ }
+ pr_info("PMIC revision 1: %02X\n", val);
+ rev = val;
+
+ /* Read PMIC chip revision 2 */
+ rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV_2, &val, sizeof(val));
+ if (rc) {
+ pr_err("Failed to read hw rev 2 reg %d:rc=%d\n",
+ REG_HWREV_2, rc);
+ goto err_read_rev;
+ }
+ pr_info("PMIC revision 2: %02X\n", val);
+ rev |= val << BITS_PER_BYTE;
+
+ pmic->dev = &pdev->dev;
+ pm8921_drvdata.pm_chip_data = pmic;
+ platform_set_drvdata(pdev, &pm8921_drvdata);
+
+ rc = pm8921_add_subdevices(pdata, pmic, rev);
+ if (rc) {
+ pr_err("Cannot add subdevices rc=%d\n", rc);
+ goto err;
+ }
+
+ /* gpio might not work if no irq device is found */
+ WARN_ON(pmic->irq_chip == NULL);
+
+ return 0;
+
+err:
+ mfd_remove_devices(pmic->dev);
+ platform_set_drvdata(pdev, NULL);
+err_read_rev:
+ kfree(pmic);
+ return rc;
+}
+
+static int __devexit pm8921_remove(struct platform_device *pdev)
+{
+ struct pm8xxx_drvdata *drvdata;
+ struct pm8921 *pmic = NULL;
+
+ drvdata = platform_get_drvdata(pdev);
+ if (drvdata)
+ pmic = drvdata->pm_chip_data;
+ if (pmic)
+ mfd_remove_devices(pmic->dev);
+ if (pmic->irq_chip) {
+ pm8xxx_irq_exit(pmic->irq_chip);
+ pmic->irq_chip = NULL;
+ }
+ platform_set_drvdata(pdev, NULL);
+ kfree(pmic);
+
+ return 0;
+}
+
+static struct platform_driver pm8921_driver = {
+ .probe = pm8921_probe,
+ .remove = __devexit_p(pm8921_remove),
+ .driver = {
+ .name = "pm8921-core",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pm8921_init(void)
+{
+ return platform_driver_register(&pm8921_driver);
+}
+subsys_initcall(pm8921_init);
+
+static void __exit pm8921_exit(void)
+{
+ platform_driver_unregister(&pm8921_driver);
+}
+module_exit(pm8921_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("PMIC 8921 core driver");
+MODULE_VERSION("1.0");
+MODULE_ALIAS("platform:pm8921-core");
diff --git a/drivers/mfd/pm8xxx-irq.c b/drivers/mfd/pm8xxx-irq.c
new file mode 100644
index 000000000000..d452dd013081
--- /dev/null
+++ b/drivers/mfd/pm8xxx-irq.c
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2011, 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.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mfd/pm8xxx/core.h>
+#include <linux/mfd/pm8xxx/irq.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+/* PMIC8xxx IRQ */
+
+#define SSBI_REG_ADDR_IRQ_BASE 0x1BB
+
+#define SSBI_REG_ADDR_IRQ_ROOT (SSBI_REG_ADDR_IRQ_BASE + 0)
+#define SSBI_REG_ADDR_IRQ_M_STATUS1 (SSBI_REG_ADDR_IRQ_BASE + 1)
+#define SSBI_REG_ADDR_IRQ_M_STATUS2 (SSBI_REG_ADDR_IRQ_BASE + 2)
+#define SSBI_REG_ADDR_IRQ_M_STATUS3 (SSBI_REG_ADDR_IRQ_BASE + 3)
+#define SSBI_REG_ADDR_IRQ_M_STATUS4 (SSBI_REG_ADDR_IRQ_BASE + 4)
+#define SSBI_REG_ADDR_IRQ_BLK_SEL (SSBI_REG_ADDR_IRQ_BASE + 5)
+#define SSBI_REG_ADDR_IRQ_IT_STATUS (SSBI_REG_ADDR_IRQ_BASE + 6)
+#define SSBI_REG_ADDR_IRQ_CONFIG (SSBI_REG_ADDR_IRQ_BASE + 7)
+#define SSBI_REG_ADDR_IRQ_RT_STATUS (SSBI_REG_ADDR_IRQ_BASE + 8)
+
+#define PM_IRQF_LVL_SEL 0x01 /* level select */
+#define PM_IRQF_MASK_FE 0x02 /* mask falling edge */
+#define PM_IRQF_MASK_RE 0x04 /* mask rising edge */
+#define PM_IRQF_CLR 0x08 /* clear interrupt */
+#define PM_IRQF_BITS_MASK 0x70
+#define PM_IRQF_BITS_SHIFT 4
+#define PM_IRQF_WRITE 0x80
+
+#define PM_IRQF_MASK_ALL (PM_IRQF_MASK_FE | \
+ PM_IRQF_MASK_RE)
+
+struct pm_irq_chip {
+ struct device *dev;
+ spinlock_t pm_irq_lock;
+ unsigned int devirq;
+ unsigned int irq_base;
+ unsigned int num_irqs;
+ unsigned int num_blocks;
+ unsigned int num_masters;
+ u8 config[0];
+};
+
+static int pm8xxx_read_root_irq(const struct pm_irq_chip *chip, u8 *rp)
+{
+ return pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_ROOT, rp);
+}
+
+static int pm8xxx_read_master_irq(const struct pm_irq_chip *chip, u8 m, u8 *bp)
+{
+ return pm8xxx_readb(chip->dev,
+ SSBI_REG_ADDR_IRQ_M_STATUS1 + m, bp);
+}
+
+static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, u8 bp, u8 *ip)
+{
+ int rc;
+
+ spin_lock(&chip->pm_irq_lock);
+ rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
+ if (rc) {
+ pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
+ goto bail;
+ }
+
+ rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_IT_STATUS, ip);
+ if (rc)
+ pr_err("Failed Reading Status rc=%d\n", rc);
+bail:
+ spin_unlock(&chip->pm_irq_lock);
+ return rc;
+}
+
+static int pm8xxx_config_irq(struct pm_irq_chip *chip, u8 bp, u8 cp)
+{
+ int rc;
+
+ spin_lock(&chip->pm_irq_lock);
+ rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
+ if (rc) {
+ pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
+ goto bail;
+ }
+
+ cp |= PM_IRQF_WRITE;
+ rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_CONFIG, cp);
+ if (rc)
+ pr_err("Failed Configuring IRQ rc=%d\n", rc);
+bail:
+ spin_unlock(&chip->pm_irq_lock);
+ return rc;
+}
+
+static int pm8xxx_irq_block_handler(struct pm_irq_chip *chip, int block)
+{
+ int pmirq, irq, i, ret = 0;
+ u8 bits;
+
+ ret = pm8xxx_read_block_irq(chip, block, &bits);
+ if (ret) {
+ pr_err("Failed reading %d block ret=%d", block, ret);
+ return ret;
+ }
+ if (!bits) {
+ pr_err("block bit set in master but no irqs: %d", block);
+ return 0;
+ }
+
+ /* Check IRQ bits */
+ for (i = 0; i < 8; i++) {
+ if (bits & (1 << i)) {
+ pmirq = block * 8 + i;
+ irq = pmirq + chip->irq_base;
+ generic_handle_irq(irq);
+ }
+ }
+ return 0;
+}
+
+static int pm8xxx_irq_master_handler(struct pm_irq_chip *chip, int master)
+{
+ u8 blockbits;
+ int block_number, i, ret = 0;
+
+ ret = pm8xxx_read_master_irq(chip, master, &blockbits);
+ if (ret) {
+ pr_err("Failed to read master %d ret=%d\n", master, ret);
+ return ret;
+ }
+ if (!blockbits) {
+ pr_err("master bit set in root but no blocks: %d", master);
+ return 0;
+ }
+
+ for (i = 0; i < 8; i++)
+ if (blockbits & (1 << i)) {
+ block_number = master * 8 + i; /* block # */
+ ret |= pm8xxx_irq_block_handler(chip, block_number);
+ }
+ return ret;
+}
+
+static void pm8xxx_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+ struct pm_irq_chip *chip = irq_desc_get_handler_data(desc);
+ struct irq_chip *irq_chip = irq_desc_get_chip(desc);
+ u8 root;
+ int i, ret, masters = 0;
+
+ ret = pm8xxx_read_root_irq(chip, &root);
+ if (ret) {
+ pr_err("Can't read root status ret=%d\n", ret);
+ return;
+ }
+
+ /* on pm8xxx series masters start from bit 1 of the root */
+ masters = root >> 1;
+
+ /* Read allowed masters for blocks. */
+ for (i = 0; i < chip->num_masters; i++)
+ if (masters & (1 << i))
+ pm8xxx_irq_master_handler(chip, i);
+
+ irq_chip->irq_ack(&desc->irq_data);
+}
+
+static void pm8xxx_irq_mask_ack(struct irq_data *d)
+{
+ struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+ unsigned int pmirq = d->irq - chip->irq_base;
+ int master, irq_bit;
+ u8 block, config;
+
+ block = pmirq / 8;
+ master = block / 8;
+ irq_bit = pmirq % 8;
+
+ config = chip->config[pmirq] | PM_IRQF_MASK_ALL | PM_IRQF_CLR;
+ pm8xxx_config_irq(chip, block, config);
+}
+
+static void pm8xxx_irq_unmask(struct irq_data *d)
+{
+ struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+ unsigned int pmirq = d->irq - chip->irq_base;
+ int master, irq_bit;
+ u8 block, config;
+
+ block = pmirq / 8;
+ master = block / 8;
+ irq_bit = pmirq % 8;
+
+ config = chip->config[pmirq];
+ pm8xxx_config_irq(chip, block, config);
+}
+
+static int pm8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
+{
+ struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+ unsigned int pmirq = d->irq - chip->irq_base;
+ int master, irq_bit;
+ u8 block, config;
+
+ block = pmirq / 8;
+ master = block / 8;
+ irq_bit = pmirq % 8;
+
+ chip->config[pmirq] = (irq_bit << PM_IRQF_BITS_SHIFT)
+ | PM_IRQF_MASK_ALL;
+ if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
+ if (flow_type & IRQF_TRIGGER_RISING)
+ chip->config[pmirq] &= ~PM_IRQF_MASK_RE;
+ if (flow_type & IRQF_TRIGGER_FALLING)
+ chip->config[pmirq] &= ~PM_IRQF_MASK_FE;
+ } else {
+ chip->config[pmirq] |= PM_IRQF_LVL_SEL;
+
+ if (flow_type & IRQF_TRIGGER_HIGH)
+ chip->config[pmirq] &= ~PM_IRQF_MASK_RE;
+ else
+ chip->config[pmirq] &= ~PM_IRQF_MASK_FE;
+ }
+
+ config = chip->config[pmirq] | PM_IRQF_CLR;
+ return pm8xxx_config_irq(chip, block, config);
+}
+
+static int pm8xxx_irq_set_wake(struct irq_data *d, unsigned int on)
+{
+ return 0;
+}
+
+static struct irq_chip pm8xxx_irq_chip = {
+ .name = "pm8xxx",
+ .irq_mask_ack = pm8xxx_irq_mask_ack,
+ .irq_unmask = pm8xxx_irq_unmask,
+ .irq_set_type = pm8xxx_irq_set_type,
+ .irq_set_wake = pm8xxx_irq_set_wake,
+ .flags = IRQCHIP_MASK_ON_SUSPEND,
+};
+
+/**
+ * pm8xxx_get_irq_stat - get the status of the irq line
+ * @chip: pointer to identify a pmic irq controller
+ * @irq: the irq number
+ *
+ * The pm8xxx gpio and mpp rely on the interrupt block to read
+ * the values on their pins. This function is to facilitate reading
+ * the status of a gpio or an mpp line. The caller has to convert the
+ * gpio number to irq number.
+ *
+ * RETURNS:
+ * an int indicating the value read on that line
+ */
+int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq)
+{
+ int pmirq, rc;
+ u8 block, bits, bit;
+ unsigned long flags;
+
+ if (chip == NULL || irq < chip->irq_base ||
+ irq >= chip->irq_base + chip->num_irqs)
+ return -EINVAL;
+
+ pmirq = irq - chip->irq_base;
+
+ block = pmirq / 8;
+ bit = pmirq % 8;
+
+ spin_lock_irqsave(&chip->pm_irq_lock, flags);
+
+ rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, block);
+ if (rc) {
+ pr_err("Failed Selecting block irq=%d pmirq=%d blk=%d rc=%d\n",
+ irq, pmirq, block, rc);
+ goto bail_out;
+ }
+
+ rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_RT_STATUS, &bits);
+ if (rc) {
+ pr_err("Failed Configuring irq=%d pmirq=%d blk=%d rc=%d\n",
+ irq, pmirq, block, rc);
+ goto bail_out;
+ }
+
+ rc = (bits & (1 << bit)) ? 1 : 0;
+
+bail_out:
+ spin_unlock_irqrestore(&chip->pm_irq_lock, flags);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(pm8xxx_get_irq_stat);
+
+struct pm_irq_chip * __devinit pm8xxx_irq_init(struct device *dev,
+ const struct pm8xxx_irq_platform_data *pdata)
+{
+ struct pm_irq_chip *chip;
+ int devirq, rc;
+ unsigned int pmirq;
+
+ if (!pdata) {
+ pr_err("No platform data\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ devirq = pdata->devirq;
+ if (devirq < 0) {
+ pr_err("missing devirq\n");
+ rc = devirq;
+ return ERR_PTR(-EINVAL);
+ }
+
+ chip = kzalloc(sizeof(struct pm_irq_chip)
+ + sizeof(u8) * pdata->irq_cdata.nirqs, GFP_KERNEL);
+ if (!chip) {
+ pr_err("Cannot alloc pm_irq_chip struct\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ chip->dev = dev;
+ chip->devirq = devirq;
+ chip->irq_base = pdata->irq_base;
+ chip->num_irqs = pdata->irq_cdata.nirqs;
+ chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8);
+ chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8);
+ spin_lock_init(&chip->pm_irq_lock);
+
+ for (pmirq = 0; pmirq < chip->num_irqs; pmirq++) {
+ irq_set_chip_and_handler(chip->irq_base + pmirq,
+ &pm8xxx_irq_chip,
+ handle_level_irq);
+ irq_set_chip_data(chip->irq_base + pmirq, chip);
+#ifdef CONFIG_ARM
+ set_irq_flags(chip->irq_base + pmirq, IRQF_VALID);
+#else
+ irq_set_noprobe(chip->irq_base + pmirq);
+#endif
+ }
+
+ irq_set_irq_type(devirq, pdata->irq_trigger_flag);
+ irq_set_handler_data(devirq, chip);
+ irq_set_chained_handler(devirq, pm8xxx_irq_handler);
+ set_irq_wake(devirq, 1);
+
+ return chip;
+}
+
+int __devexit pm8xxx_irq_exit(struct pm_irq_chip *chip)
+{
+ irq_set_chained_handler(chip->devirq, NULL);
+ kfree(chip);
+ return 0;
+}
diff --git a/drivers/mfd/rdc321x-southbridge.c b/drivers/mfd/rdc321x-southbridge.c
index 10dbe6374a89..809bd4a61089 100644
--- a/drivers/mfd/rdc321x-southbridge.c
+++ b/drivers/mfd/rdc321x-southbridge.c
@@ -61,12 +61,14 @@ static struct mfd_cell rdc321x_sb_cells[] = {
.name = "rdc321x-wdt",
.resources = rdc321x_wdt_resource,
.num_resources = ARRAY_SIZE(rdc321x_wdt_resource),
- .mfd_data = &rdc321x_wdt_pdata,
+ .platform_data = &rdc321x_wdt_pdata,
+ .pdata_size = sizeof(rdc321x_wdt_pdata),
}, {
.name = "rdc321x-gpio",
.resources = rdc321x_gpio_resources,
.num_resources = ARRAY_SIZE(rdc321x_gpio_resources),
- .mfd_data = &rdc321x_gpio_pdata,
+ .platform_data = &rdc321x_gpio_pdata,
+ .pdata_size = sizeof(rdc321x_gpio_pdata),
},
};
diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c
index 42830e692964..91ad21ef7721 100644
--- a/drivers/mfd/t7l66xb.c
+++ b/drivers/mfd/t7l66xb.c
@@ -170,7 +170,8 @@ static struct mfd_cell t7l66xb_cells[] = {
.name = "tmio-mmc",
.enable = t7l66xb_mmc_enable,
.disable = t7l66xb_mmc_disable,
- .mfd_data = &t7166xb_mmc_data,
+ .platform_data = &t7166xb_mmc_data,
+ .pdata_size = sizeof(t7166xb_mmc_data),
.num_resources = ARRAY_SIZE(t7l66xb_mmc_resources),
.resources = t7l66xb_mmc_resources,
},
@@ -382,7 +383,8 @@ static int t7l66xb_probe(struct platform_device *dev)
t7l66xb_attach_irq(dev);
- t7l66xb_cells[T7L66XB_CELL_NAND].mfd_data = pdata->nand_data;
+ t7l66xb_cells[T7L66XB_CELL_NAND].platform_data = pdata->nand_data;
+ t7l66xb_cells[T7L66XB_CELL_NAND].pdata_size = sizeof(*pdata->nand_data);
ret = mfd_add_devices(&dev->dev, dev->id,
t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells),
diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c
index b006f7cee952..ad715bf49cac 100644
--- a/drivers/mfd/tc6387xb.c
+++ b/drivers/mfd/tc6387xb.c
@@ -131,7 +131,8 @@ static struct mfd_cell tc6387xb_cells[] = {
.name = "tmio-mmc",
.enable = tc6387xb_mmc_enable,
.disable = tc6387xb_mmc_disable,
- .mfd_data = &tc6387xb_mmc_data,
+ .platform_data = &tc6387xb_mmc_data,
+ .pdata_size = sizeof(tc6387xb_mmc_data),
.num_resources = ARRAY_SIZE(tc6387xb_mmc_resources),
.resources = tc6387xb_mmc_resources,
},
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c
index fc53ce287601..9612264f0e6d 100644
--- a/drivers/mfd/tc6393xb.c
+++ b/drivers/mfd/tc6393xb.c
@@ -393,7 +393,8 @@ static struct mfd_cell __devinitdata tc6393xb_cells[] = {
.name = "tmio-mmc",
.enable = tc6393xb_mmc_enable,
.resume = tc6393xb_mmc_resume,
- .mfd_data = &tc6393xb_mmc_data,
+ .platform_data = &tc6393xb_mmc_data,
+ .pdata_size = sizeof(tc6393xb_mmc_data),
.num_resources = ARRAY_SIZE(tc6393xb_mmc_resources),
.resources = tc6393xb_mmc_resources,
},
@@ -692,8 +693,11 @@ static int __devinit tc6393xb_probe(struct platform_device *dev)
goto err_setup;
}
- tc6393xb_cells[TC6393XB_CELL_NAND].mfd_data = tcpd->nand_data;
- tc6393xb_cells[TC6393XB_CELL_FB].mfd_data = tcpd->fb_data;
+ tc6393xb_cells[TC6393XB_CELL_NAND].platform_data = tcpd->nand_data;
+ tc6393xb_cells[TC6393XB_CELL_NAND].pdata_size =
+ sizeof(*tcpd->nand_data);
+ tc6393xb_cells[TC6393XB_CELL_FB].platform_data = tcpd->fb_data;
+ tc6393xb_cells[TC6393XB_CELL_FB].pdata_size = sizeof(*tcpd->fb_data);
ret = mfd_add_devices(&dev->dev, dev->id,
tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells),
diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c
index 94c6c8afad12..69272e4e3459 100644
--- a/drivers/mfd/timberdale.c
+++ b/drivers/mfd/timberdale.c
@@ -384,7 +384,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = {
.name = "timb-dma",
.num_resources = ARRAY_SIZE(timberdale_dma_resources),
.resources = timberdale_dma_resources,
- .mfd_data = &timb_dma_platform_data,
+ .platform_data = &timb_dma_platform_data,
+ .pdata_size = sizeof(timb_dma_platform_data),
},
{
.name = "timb-uart",
@@ -395,37 +396,43 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = {
.name = "xiic-i2c",
.num_resources = ARRAY_SIZE(timberdale_xiic_resources),
.resources = timberdale_xiic_resources,
- .mfd_data = &timberdale_xiic_platform_data,
+ .platform_data = &timberdale_xiic_platform_data,
+ .pdata_size = sizeof(timberdale_xiic_platform_data),
},
{
.name = "timb-gpio",
.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
.resources = timberdale_gpio_resources,
- .mfd_data = &timberdale_gpio_platform_data,
+ .platform_data = &timberdale_gpio_platform_data,
+ .pdata_size = sizeof(timberdale_gpio_platform_data),
},
{
.name = "timb-video",
.num_resources = ARRAY_SIZE(timberdale_video_resources),
.resources = timberdale_video_resources,
- .mfd_data = &timberdale_video_platform_data,
+ .platform_data = &timberdale_video_platform_data,
+ .pdata_size = sizeof(timberdale_video_platform_data),
},
{
.name = "timb-radio",
.num_resources = ARRAY_SIZE(timberdale_radio_resources),
.resources = timberdale_radio_resources,
- .mfd_data = &timberdale_radio_platform_data,
+ .platform_data = &timberdale_radio_platform_data,
+ .pdata_size = sizeof(timberdale_radio_platform_data),
},
{
.name = "xilinx_spi",
.num_resources = ARRAY_SIZE(timberdale_spi_resources),
.resources = timberdale_spi_resources,
- .mfd_data = &timberdale_xspi_platform_data,
+ .platform_data = &timberdale_xspi_platform_data,
+ .pdata_size = sizeof(timberdale_xspi_platform_data),
},
{
.name = "ks8842",
.num_resources = ARRAY_SIZE(timberdale_eth_resources),
.resources = timberdale_eth_resources,
- .mfd_data = &timberdale_ks8842_platform_data,
+ .platform_data = &timberdale_ks8842_platform_data,
+ .pdata_size = sizeof(timberdale_ks8842_platform_data),
},
};
@@ -434,7 +441,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
.name = "timb-dma",
.num_resources = ARRAY_SIZE(timberdale_dma_resources),
.resources = timberdale_dma_resources,
- .mfd_data = &timb_dma_platform_data,
+ .platform_data = &timb_dma_platform_data,
+ .pdata_size = sizeof(timb_dma_platform_data),
},
{
.name = "timb-uart",
@@ -450,13 +458,15 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
.name = "xiic-i2c",
.num_resources = ARRAY_SIZE(timberdale_xiic_resources),
.resources = timberdale_xiic_resources,
- .mfd_data = &timberdale_xiic_platform_data,
+ .platform_data = &timberdale_xiic_platform_data,
+ .pdata_size = sizeof(timberdale_xiic_platform_data),
},
{
.name = "timb-gpio",
.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
.resources = timberdale_gpio_resources,
- .mfd_data = &timberdale_gpio_platform_data,
+ .platform_data = &timberdale_gpio_platform_data,
+ .pdata_size = sizeof(timberdale_gpio_platform_data),
},
{
.name = "timb-mlogicore",
@@ -467,25 +477,29 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
.name = "timb-video",
.num_resources = ARRAY_SIZE(timberdale_video_resources),
.resources = timberdale_video_resources,
- .mfd_data = &timberdale_video_platform_data,
+ .platform_data = &timberdale_video_platform_data,
+ .pdata_size = sizeof(timberdale_video_platform_data),
},
{
.name = "timb-radio",
.num_resources = ARRAY_SIZE(timberdale_radio_resources),
.resources = timberdale_radio_resources,
- .mfd_data = &timberdale_radio_platform_data,
+ .platform_data = &timberdale_radio_platform_data,
+ .pdata_size = sizeof(timberdale_radio_platform_data),
},
{
.name = "xilinx_spi",
.num_resources = ARRAY_SIZE(timberdale_spi_resources),
.resources = timberdale_spi_resources,
- .mfd_data = &timberdale_xspi_platform_data,
+ .platform_data = &timberdale_xspi_platform_data,
+ .pdata_size = sizeof(timberdale_xspi_platform_data),
},
{
.name = "ks8842",
.num_resources = ARRAY_SIZE(timberdale_eth_resources),
.resources = timberdale_eth_resources,
- .mfd_data = &timberdale_ks8842_platform_data,
+ .platform_data = &timberdale_ks8842_platform_data,
+ .pdata_size = sizeof(timberdale_ks8842_platform_data),
},
};
@@ -494,7 +508,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = {
.name = "timb-dma",
.num_resources = ARRAY_SIZE(timberdale_dma_resources),
.resources = timberdale_dma_resources,
- .mfd_data = &timb_dma_platform_data,
+ .platform_data = &timb_dma_platform_data,
+ .pdata_size = sizeof(timb_dma_platform_data),
},
{
.name = "timb-uart",
@@ -505,31 +520,36 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = {
.name = "xiic-i2c",
.num_resources = ARRAY_SIZE(timberdale_xiic_resources),
.resources = timberdale_xiic_resources,
- .mfd_data = &timberdale_xiic_platform_data,
+ .platform_data = &timberdale_xiic_platform_data,
+ .pdata_size = sizeof(timberdale_xiic_platform_data),
},
{
.name = "timb-gpio",
.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
.resources = timberdale_gpio_resources,
- .mfd_data = &timberdale_gpio_platform_data,
+ .platform_data = &timberdale_gpio_platform_data,
+ .pdata_size = sizeof(timberdale_gpio_platform_data),
},
{
.name = "timb-video",
.num_resources = ARRAY_SIZE(timberdale_video_resources),
.resources = timberdale_video_resources,
- .mfd_data = &timberdale_video_platform_data,
+ .platform_data = &timberdale_video_platform_data,
+ .pdata_size = sizeof(timberdale_video_platform_data),
},
{
.name = "timb-radio",
.num_resources = ARRAY_SIZE(timberdale_radio_resources),
.resources = timberdale_radio_resources,
- .mfd_data = &timberdale_radio_platform_data,
+ .platform_data = &timberdale_radio_platform_data,
+ .pdata_size = sizeof(timberdale_radio_platform_data),
},
{
.name = "xilinx_spi",
.num_resources = ARRAY_SIZE(timberdale_spi_resources),
.resources = timberdale_spi_resources,
- .mfd_data = &timberdale_xspi_platform_data,
+ .platform_data = &timberdale_xspi_platform_data,
+ .pdata_size = sizeof(timberdale_xspi_platform_data),
},
};
@@ -538,7 +558,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = {
.name = "timb-dma",
.num_resources = ARRAY_SIZE(timberdale_dma_resources),
.resources = timberdale_dma_resources,
- .mfd_data = &timb_dma_platform_data,
+ .platform_data = &timb_dma_platform_data,
+ .pdata_size = sizeof(timb_dma_platform_data),
},
{
.name = "timb-uart",
@@ -549,37 +570,43 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = {
.name = "ocores-i2c",
.num_resources = ARRAY_SIZE(timberdale_ocores_resources),
.resources = timberdale_ocores_resources,
- .mfd_data = &timberdale_ocores_platform_data,
+ .platform_data = &timberdale_ocores_platform_data,
+ .pdata_size = sizeof(timberdale_ocores_platform_data),
},
{
.name = "timb-gpio",
.num_resources = ARRAY_SIZE(timberdale_gpio_resources),
.resources = timberdale_gpio_resources,
- .mfd_data = &timberdale_gpio_platform_data,
+ .platform_data = &timberdale_gpio_platform_data,
+ .pdata_size = sizeof(timberdale_gpio_platform_data),
},
{
.name = "timb-video",
.num_resources = ARRAY_SIZE(timberdale_video_resources),
.resources = timberdale_video_resources,
- .mfd_data = &timberdale_video_platform_data,
+ .platform_data = &timberdale_video_platform_data,
+ .pdata_size = sizeof(timberdale_video_platform_data),
},
{
.name = "timb-radio",
.num_resources = ARRAY_SIZE(timberdale_radio_resources),
.resources = timberdale_radio_resources,
- .mfd_data = &timberdale_radio_platform_data,
+ .platform_data = &timberdale_radio_platform_data,
+ .pdata_size = sizeof(timberdale_radio_platform_data),
},
{
.name = "xilinx_spi",
.num_resources = ARRAY_SIZE(timberdale_spi_resources),
.resources = timberdale_spi_resources,
- .mfd_data = &timberdale_xspi_platform_data,
+ .platform_data = &timberdale_xspi_platform_data,
+ .pdata_size = sizeof(timberdale_xspi_platform_data),
},
{
.name = "ks8842",
.num_resources = ARRAY_SIZE(timberdale_eth_resources),
.resources = timberdale_eth_resources,
- .mfd_data = &timberdale_ks8842_platform_data,
+ .platform_data = &timberdale_ks8842_platform_data,
+ .pdata_size = sizeof(timberdale_ks8842_platform_data),
},
};
diff --git a/drivers/mfd/tps6105x.c b/drivers/mfd/tps6105x.c
index 46d8205646b6..a293b978e27c 100644
--- a/drivers/mfd/tps6105x.c
+++ b/drivers/mfd/tps6105x.c
@@ -183,7 +183,8 @@ static int __devinit tps6105x_probe(struct i2c_client *client,
/* Set up and register the platform devices. */
for (i = 0; i < ARRAY_SIZE(tps6105x_cells); i++) {
/* One state holder for all drivers, this is simple */
- tps6105x_cells[i].mfd_data = tps6105x;
+ tps6105x_cells[i].platform_data = tps6105x;
+ tps6105x_cells[i].pdata_size = sizeof(*tps6105x);
}
ret = mfd_add_devices(&client->dev, 0, tps6105x_cells,
diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c
index b600808690c1..bba26d96c240 100644
--- a/drivers/mfd/tps6586x.c
+++ b/drivers/mfd/tps6586x.c
@@ -270,8 +270,8 @@ static void tps6586x_gpio_set(struct gpio_chip *chip, unsigned offset,
{
struct tps6586x *tps6586x = container_of(chip, struct tps6586x, gpio);
- __tps6586x_write(tps6586x->client, TPS6586X_GPIOSET2,
- value << offset);
+ tps6586x_update(tps6586x->dev, TPS6586X_GPIOSET2,
+ value << offset, 1 << offset);
}
static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset,
diff --git a/drivers/mfd/tps65910-irq.c b/drivers/mfd/tps65910-irq.c
new file mode 100644
index 000000000000..2bfad5c86cc7
--- /dev/null
+++ b/drivers/mfd/tps65910-irq.c
@@ -0,0 +1,218 @@
+/*
+ * tps65910-irq.c -- TI TPS6591x
+ *
+ * Copyright 2010 Texas Instruments Inc.
+ *
+ * Author: Graeme Gregory <gg@slimlogic.co.uk>
+ * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/mfd/tps65910.h>
+
+static inline int irq_to_tps65910_irq(struct tps65910 *tps65910,
+ int irq)
+{
+ return (irq - tps65910->irq_base);
+}
+
+/*
+ * This is a threaded IRQ handler so can access I2C/SPI. Since all
+ * interrupts are clear on read the IRQ line will be reasserted and
+ * the physical IRQ will be handled again if another interrupt is
+ * asserted while we run - in the normal course of events this is a
+ * rare occurrence so we save I2C/SPI reads. We're also assuming that
+ * it's rare to get lots of interrupts firing simultaneously so try to
+ * minimise I/O.
+ */
+static irqreturn_t tps65910_irq(int irq, void *irq_data)
+{
+ struct tps65910 *tps65910 = irq_data;
+ u32 irq_sts;
+ u32 irq_mask;
+ u8 reg;
+ int i;
+
+ tps65910->read(tps65910, TPS65910_INT_STS, 1, &reg);
+ irq_sts = reg;
+ tps65910->read(tps65910, TPS65910_INT_STS2, 1, &reg);
+ irq_sts |= reg << 8;
+ switch (tps65910_chip_id(tps65910)) {
+ case TPS65911:
+ tps65910->read(tps65910, TPS65910_INT_STS3, 1, &reg);
+ irq_sts |= reg << 16;
+ }
+
+ tps65910->read(tps65910, TPS65910_INT_MSK, 1, &reg);
+ irq_mask = reg;
+ tps65910->read(tps65910, TPS65910_INT_MSK2, 1, &reg);
+ irq_mask |= reg << 8;
+ switch (tps65910_chip_id(tps65910)) {
+ case TPS65911:
+ tps65910->read(tps65910, TPS65910_INT_MSK3, 1, &reg);
+ irq_mask |= reg << 16;
+ }
+
+ irq_sts &= ~irq_mask;
+
+ if (!irq_sts)
+ return IRQ_NONE;
+
+ for (i = 0; i < tps65910->irq_num; i++) {
+
+ if (!(irq_sts & (1 << i)))
+ continue;
+
+ handle_nested_irq(tps65910->irq_base + i);
+ }
+
+ /* Write the STS register back to clear IRQs we handled */
+ reg = irq_sts & 0xFF;
+ irq_sts >>= 8;
+ tps65910->write(tps65910, TPS65910_INT_STS, 1, &reg);
+ reg = irq_sts & 0xFF;
+ tps65910->write(tps65910, TPS65910_INT_STS2, 1, &reg);
+ switch (tps65910_chip_id(tps65910)) {
+ case TPS65911:
+ reg = irq_sts >> 8;
+ tps65910->write(tps65910, TPS65910_INT_STS3, 1, &reg);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void tps65910_irq_lock(struct irq_data *data)
+{
+ struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);
+
+ mutex_lock(&tps65910->irq_lock);
+}
+
+static void tps65910_irq_sync_unlock(struct irq_data *data)
+{
+ struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);
+ u32 reg_mask;
+ u8 reg;
+
+ tps65910->read(tps65910, TPS65910_INT_MSK, 1, &reg);
+ reg_mask = reg;
+ tps65910->read(tps65910, TPS65910_INT_MSK2, 1, &reg);
+ reg_mask |= reg << 8;
+ switch (tps65910_chip_id(tps65910)) {
+ case TPS65911:
+ tps65910->read(tps65910, TPS65910_INT_MSK3, 1, &reg);
+ reg_mask |= reg << 16;
+ }
+
+ if (tps65910->irq_mask != reg_mask) {
+ reg = tps65910->irq_mask & 0xFF;
+ tps65910->write(tps65910, TPS65910_INT_MSK, 1, &reg);
+ reg = tps65910->irq_mask >> 8 & 0xFF;
+ tps65910->write(tps65910, TPS65910_INT_MSK2, 1, &reg);
+ switch (tps65910_chip_id(tps65910)) {
+ case TPS65911:
+ reg = tps65910->irq_mask >> 16;
+ tps65910->write(tps65910, TPS65910_INT_MSK3, 1, &reg);
+ }
+ }
+ mutex_unlock(&tps65910->irq_lock);
+}
+
+static void tps65910_irq_enable(struct irq_data *data)
+{
+ struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);
+
+ tps65910->irq_mask &= ~( 1 << irq_to_tps65910_irq(tps65910, data->irq));
+}
+
+static void tps65910_irq_disable(struct irq_data *data)
+{
+ struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data);
+
+ tps65910->irq_mask |= ( 1 << irq_to_tps65910_irq(tps65910, data->irq));
+}
+
+static struct irq_chip tps65910_irq_chip = {
+ .name = "tps65910",
+ .irq_bus_lock = tps65910_irq_lock,
+ .irq_bus_sync_unlock = tps65910_irq_sync_unlock,
+ .irq_disable = tps65910_irq_disable,
+ .irq_enable = tps65910_irq_enable,
+};
+
+int tps65910_irq_init(struct tps65910 *tps65910, int irq,
+ struct tps65910_platform_data *pdata)
+{
+ int ret, cur_irq;
+ int flags = IRQF_ONESHOT;
+
+ if (!irq) {
+ dev_warn(tps65910->dev, "No interrupt support, no core IRQ\n");
+ return -EINVAL;
+ }
+
+ if (!pdata || !pdata->irq_base) {
+ dev_warn(tps65910->dev, "No interrupt support, no IRQ base\n");
+ return -EINVAL;
+ }
+
+ tps65910->irq_mask = 0xFFFFFF;
+
+ mutex_init(&tps65910->irq_lock);
+ tps65910->chip_irq = irq;
+ tps65910->irq_base = pdata->irq_base;
+
+ switch (tps65910_chip_id(tps65910)) {
+ case TPS65910:
+ tps65910->irq_num = TPS65910_NUM_IRQ;
+ case TPS65911:
+ tps65910->irq_num = TPS65911_NUM_IRQ;
+ }
+
+ /* Register with genirq */
+ for (cur_irq = tps65910->irq_base;
+ cur_irq < tps65910->irq_num + tps65910->irq_base;
+ cur_irq++) {
+ irq_set_chip_data(cur_irq, tps65910);
+ irq_set_chip_and_handler(cur_irq, &tps65910_irq_chip,
+ handle_edge_irq);
+ irq_set_nested_thread(cur_irq, 1);
+
+ /* ARM needs us to explicitly flag the IRQ as valid
+ * and will set them noprobe when we do so. */
+#ifdef CONFIG_ARM
+ set_irq_flags(cur_irq, IRQF_VALID);
+#else
+ irq_set_noprobe(cur_irq);
+#endif
+ }
+
+ ret = request_threaded_irq(irq, NULL, tps65910_irq, flags,
+ "tps65910", tps65910);
+
+ irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);
+
+ if (ret != 0)
+ dev_err(tps65910->dev, "Failed to request IRQ: %d\n", ret);
+
+ return ret;
+}
+
+int tps65910_irq_exit(struct tps65910 *tps65910)
+{
+ free_irq(tps65910->chip_irq, tps65910);
+ return 0;
+}
diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c
new file mode 100644
index 000000000000..2229e66d80db
--- /dev/null
+++ b/drivers/mfd/tps65910.c
@@ -0,0 +1,229 @@
+/*
+ * tps65910.c -- TI TPS6591x
+ *
+ * Copyright 2010 Texas Instruments Inc.
+ *
+ * Author: Graeme Gregory <gg@slimlogic.co.uk>
+ * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * 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/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps65910.h>
+
+static struct mfd_cell tps65910s[] = {
+ {
+ .name = "tps65910-pmic",
+ },
+ {
+ .name = "tps65910-rtc",
+ },
+ {
+ .name = "tps65910-power",
+ },
+};
+
+
+static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg,
+ int bytes, void *dest)
+{
+ struct i2c_client *i2c = tps65910->i2c_client;
+ struct i2c_msg xfer[2];
+ int ret;
+
+ /* Write register */
+ xfer[0].addr = i2c->addr;
+ xfer[0].flags = 0;
+ xfer[0].len = 1;
+ xfer[0].buf = &reg;
+
+ /* Read data */
+ xfer[1].addr = i2c->addr;
+ xfer[1].flags = I2C_M_RD;
+ xfer[1].len = bytes;
+ xfer[1].buf = dest;
+
+ ret = i2c_transfer(i2c->adapter, xfer, 2);
+ if (ret == 2)
+ ret = 0;
+ else if (ret >= 0)
+ ret = -EIO;
+
+ return ret;
+}
+
+static int tps65910_i2c_write(struct tps65910 *tps65910, u8 reg,
+ int bytes, void *src)
+{
+ struct i2c_client *i2c = tps65910->i2c_client;
+ /* we add 1 byte for device register */
+ u8 msg[TPS65910_MAX_REGISTER + 1];
+ int ret;
+
+ if (bytes > TPS65910_MAX_REGISTER)
+ return -EINVAL;
+
+ msg[0] = reg;
+ memcpy(&msg[1], src, bytes);
+
+ ret = i2c_master_send(i2c, msg, bytes + 1);
+ if (ret < 0)
+ return ret;
+ if (ret != bytes + 1)
+ return -EIO;
+ return 0;
+}
+
+int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
+{
+ u8 data;
+ int err;
+
+ mutex_lock(&tps65910->io_mutex);
+ err = tps65910_i2c_read(tps65910, reg, 1, &data);
+ if (err) {
+ dev_err(tps65910->dev, "read from reg %x failed\n", reg);
+ goto out;
+ }
+
+ data |= mask;
+ err = tps65910_i2c_write(tps65910, reg, 1, &data);
+ if (err)
+ dev_err(tps65910->dev, "write to reg %x failed\n", reg);
+
+out:
+ mutex_unlock(&tps65910->io_mutex);
+ return err;
+}
+EXPORT_SYMBOL_GPL(tps65910_set_bits);
+
+int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
+{
+ u8 data;
+ int err;
+
+ mutex_lock(&tps65910->io_mutex);
+ err = tps65910_i2c_read(tps65910, reg, 1, &data);
+ if (err) {
+ dev_err(tps65910->dev, "read from reg %x failed\n", reg);
+ goto out;
+ }
+
+ data &= mask;
+ err = tps65910_i2c_write(tps65910, reg, 1, &data);
+ if (err)
+ dev_err(tps65910->dev, "write to reg %x failed\n", reg);
+
+out:
+ mutex_unlock(&tps65910->io_mutex);
+ return err;
+}
+EXPORT_SYMBOL_GPL(tps65910_clear_bits);
+
+static int tps65910_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct tps65910 *tps65910;
+ struct tps65910_board *pmic_plat_data;
+ struct tps65910_platform_data *init_data;
+ int ret = 0;
+
+ pmic_plat_data = dev_get_platdata(&i2c->dev);
+ if (!pmic_plat_data)
+ return -EINVAL;
+
+ init_data = kzalloc(sizeof(struct tps65910_platform_data), GFP_KERNEL);
+ if (init_data == NULL)
+ return -ENOMEM;
+
+ init_data->irq = pmic_plat_data->irq;
+ init_data->irq_base = pmic_plat_data->irq;
+
+ tps65910 = kzalloc(sizeof(struct tps65910), GFP_KERNEL);
+ if (tps65910 == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, tps65910);
+ tps65910->dev = &i2c->dev;
+ tps65910->i2c_client = i2c;
+ tps65910->id = id->driver_data;
+ tps65910->read = tps65910_i2c_read;
+ tps65910->write = tps65910_i2c_write;
+ mutex_init(&tps65910->io_mutex);
+
+ ret = mfd_add_devices(tps65910->dev, -1,
+ tps65910s, ARRAY_SIZE(tps65910s),
+ NULL, 0);
+ if (ret < 0)
+ goto err;
+
+ tps65910_gpio_init(tps65910, pmic_plat_data->gpio_base);
+
+ ret = tps65910_irq_init(tps65910, init_data->irq, init_data);
+ if (ret < 0)
+ goto err;
+
+ return ret;
+
+err:
+ mfd_remove_devices(tps65910->dev);
+ kfree(tps65910);
+ return ret;
+}
+
+static int tps65910_i2c_remove(struct i2c_client *i2c)
+{
+ struct tps65910 *tps65910 = i2c_get_clientdata(i2c);
+
+ mfd_remove_devices(tps65910->dev);
+ kfree(tps65910);
+
+ return 0;
+}
+
+static const struct i2c_device_id tps65910_i2c_id[] = {
+ { "tps65910", TPS65910 },
+ { "tps65911", TPS65911 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tps65910_i2c_id);
+
+
+static struct i2c_driver tps65910_i2c_driver = {
+ .driver = {
+ .name = "tps65910",
+ .owner = THIS_MODULE,
+ },
+ .probe = tps65910_i2c_probe,
+ .remove = tps65910_i2c_remove,
+ .id_table = tps65910_i2c_id,
+};
+
+static int __init tps65910_i2c_init(void)
+{
+ return i2c_add_driver(&tps65910_i2c_driver);
+}
+/* init early so consumer devices can complete system boot */
+subsys_initcall(tps65910_i2c_init);
+
+static void __exit tps65910_i2c_exit(void)
+{
+ i2c_del_driver(&tps65910_i2c_driver);
+}
+module_exit(tps65910_i2c_exit);
+
+MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
+MODULE_AUTHOR("Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>");
+MODULE_DESCRIPTION("TPS6591x chip family multi-function driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/tps65911-comparator.c b/drivers/mfd/tps65911-comparator.c
new file mode 100644
index 000000000000..3d2dc56a3d40
--- /dev/null
+++ b/drivers/mfd/tps65911-comparator.c
@@ -0,0 +1,188 @@
+/*
+ * tps65910.c -- TI TPS6591x
+ *
+ * Copyright 2010 Texas Instruments Inc.
+ *
+ * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+#include <linux/gpio.h>
+#include <linux/mfd/tps65910.h>
+
+#define COMP 0
+#define COMP1 1
+#define COMP2 2
+
+/* Comparator 1 voltage selection table in milivolts */
+static const u16 COMP_VSEL_TABLE[] = {
+ 0, 2500, 2500, 2500, 2500, 2550, 2600, 2650,
+ 2700, 2750, 2800, 2850, 2900, 2950, 3000, 3050,
+ 3100, 3150, 3200, 3250, 3300, 3350, 3400, 3450,
+ 3500,
+};
+
+struct comparator {
+ const char *name;
+ int reg;
+ int uV_max;
+ const u16 *vsel_table;
+};
+
+static struct comparator tps_comparators[] = {
+ {
+ .name = "COMP1",
+ .reg = TPS65911_VMBCH,
+ .uV_max = 3500,
+ .vsel_table = COMP_VSEL_TABLE,
+ },
+ {
+ .name = "COMP2",
+ .reg = TPS65911_VMBCH2,
+ .uV_max = 3500,
+ .vsel_table = COMP_VSEL_TABLE,
+ },
+};
+
+static int comp_threshold_set(struct tps65910 *tps65910, int id, int voltage)
+{
+ struct comparator tps_comp = tps_comparators[id];
+ int curr_voltage = 0;
+ int ret;
+ u8 index = 0, val;
+
+ if (id == COMP)
+ return 0;
+
+ while (curr_voltage < tps_comp.uV_max) {
+ curr_voltage = tps_comp.vsel_table[index];
+ if (curr_voltage >= voltage)
+ break;
+ else if (curr_voltage < voltage)
+ index ++;
+ }
+
+ if (curr_voltage > tps_comp.uV_max)
+ return -EINVAL;
+
+ val = index << 1;
+ ret = tps65910->write(tps65910, tps_comp.reg, 1, &val);
+
+ return ret;
+}
+
+static int comp_threshold_get(struct tps65910 *tps65910, int id)
+{
+ struct comparator tps_comp = tps_comparators[id];
+ int ret;
+ u8 val;
+
+ if (id == COMP)
+ return 0;
+
+ ret = tps65910->read(tps65910, tps_comp.reg, 1, &val);
+ if (ret < 0)
+ return ret;
+
+ val >>= 1;
+ return tps_comp.vsel_table[val];
+}
+
+static ssize_t comp_threshold_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tps65910 *tps65910 = dev_get_drvdata(dev->parent);
+ struct attribute comp_attr = attr->attr;
+ int id, uVolt;
+
+ if (!strcmp(comp_attr.name, "comp1_threshold"))
+ id = COMP1;
+ else if (!strcmp(comp_attr.name, "comp2_threshold"))
+ id = COMP2;
+ else
+ return -EINVAL;
+
+ uVolt = comp_threshold_get(tps65910, id);
+
+ return sprintf(buf, "%d\n", uVolt);
+}
+
+static DEVICE_ATTR(comp1_threshold, S_IRUGO, comp_threshold_show, NULL);
+static DEVICE_ATTR(comp2_threshold, S_IRUGO, comp_threshold_show, NULL);
+
+static __devinit int tps65911_comparator_probe(struct platform_device *pdev)
+{
+ struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent);
+ struct tps65910_platform_data *pdata = dev_get_platdata(tps65910->dev);
+ int ret;
+
+ ret = comp_threshold_set(tps65910, COMP1, pdata->vmbch_threshold);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "cannot set COMP1 threshold\n");
+ return ret;
+ }
+
+ ret = comp_threshold_set(tps65910, COMP2, pdata->vmbch2_threshold);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "cannot set COMP2 theshold\n");
+ return ret;
+ }
+
+ /* Create sysfs entry */
+ ret = device_create_file(&pdev->dev, &dev_attr_comp1_threshold);
+ if (ret < 0)
+ dev_err(&pdev->dev, "failed to add COMP1 sysfs file\n");
+
+ ret = device_create_file(&pdev->dev, &dev_attr_comp2_threshold);
+ if (ret < 0)
+ dev_err(&pdev->dev, "failed to add COMP2 sysfs file\n");
+
+ return ret;
+}
+
+static __devexit int tps65911_comparator_remove(struct platform_device *pdev)
+{
+ struct tps65910 *tps65910;
+
+ tps65910 = dev_get_drvdata(pdev->dev.parent);
+
+ return 0;
+}
+
+static struct platform_driver tps65911_comparator_driver = {
+ .driver = {
+ .name = "tps65911-comparator",
+ .owner = THIS_MODULE,
+ },
+ .probe = tps65911_comparator_probe,
+ .remove = __devexit_p(tps65911_comparator_remove),
+};
+
+static int __init tps65911_comparator_init(void)
+{
+ return platform_driver_register(&tps65911_comparator_driver);
+}
+subsys_initcall(tps65911_comparator_init);
+
+static void __exit tps65911_comparator_exit(void)
+{
+ platform_driver_unregister(&tps65911_comparator_driver);
+}
+module_exit(tps65911_comparator_exit);
+
+MODULE_AUTHOR("Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>");
+MODULE_DESCRIPTION("TPS65911 comparator driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:tps65911-comparator");
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index 960b5bed7f52..b8f2a4e7f6e7 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -198,6 +198,7 @@
#define TWL6030_BASEADD_GASGAUGE 0x00C0
#define TWL6030_BASEADD_PIH 0x00D0
#define TWL6030_BASEADD_CHARGER 0x00E0
+#define TWL6025_BASEADD_CHARGER 0x00DA
/* subchip/slave 2 0x4A - DFT */
#define TWL6030_BASEADD_DIEID 0x00C0
@@ -229,6 +230,9 @@
/* is driver active, bound to a chip? */
static bool inuse;
+/* TWL IDCODE Register value */
+static u32 twl_idcode;
+
static unsigned int twl_id;
unsigned int twl_rev(void)
{
@@ -328,6 +332,7 @@ static struct twl_mapping twl6030_map[] = {
{ SUB_CHIP_ID0, TWL6030_BASEADD_RTC },
{ SUB_CHIP_ID0, TWL6030_BASEADD_MEM },
+ { SUB_CHIP_ID1, TWL6025_BASEADD_CHARGER },
};
/*----------------------------------------------------------------------*/
@@ -487,6 +492,58 @@ EXPORT_SYMBOL(twl_i2c_read_u8);
/*----------------------------------------------------------------------*/
+/**
+ * twl_read_idcode_register - API to read the IDCODE register.
+ *
+ * Unlocks the IDCODE register and read the 32 bit value.
+ */
+static int twl_read_idcode_register(void)
+{
+ int err;
+
+ err = twl_i2c_write_u8(TWL4030_MODULE_INTBR, TWL_EEPROM_R_UNLOCK,
+ REG_UNLOCK_TEST_REG);
+ if (err) {
+ pr_err("TWL4030 Unable to unlock IDCODE registers -%d\n", err);
+ goto fail;
+ }
+
+ err = twl_i2c_read(TWL4030_MODULE_INTBR, (u8 *)(&twl_idcode),
+ REG_IDCODE_7_0, 4);
+ if (err) {
+ pr_err("TWL4030: unable to read IDCODE -%d\n", err);
+ goto fail;
+ }
+
+ err = twl_i2c_write_u8(TWL4030_MODULE_INTBR, 0x0, REG_UNLOCK_TEST_REG);
+ if (err)
+ pr_err("TWL4030 Unable to relock IDCODE registers -%d\n", err);
+fail:
+ return err;
+}
+
+/**
+ * twl_get_type - API to get TWL Si type.
+ *
+ * Api to get the TWL Si type from IDCODE value.
+ */
+int twl_get_type(void)
+{
+ return TWL_SIL_TYPE(twl_idcode);
+}
+EXPORT_SYMBOL_GPL(twl_get_type);
+
+/**
+ * twl_get_version - API to get TWL Si version.
+ *
+ * Api to get the TWL Si version from IDCODE value.
+ */
+int twl_get_version(void)
+{
+ return TWL_SIL_REV(twl_idcode);
+}
+EXPORT_SYMBOL_GPL(twl_get_version);
+
static struct device *
add_numbered_child(unsigned chip, const char *name, int num,
void *pdata, unsigned pdata_len,
@@ -549,7 +606,7 @@ static inline struct device *add_child(unsigned chip, const char *name,
static struct device *
add_regulator_linked(int num, struct regulator_init_data *pdata,
struct regulator_consumer_supply *consumers,
- unsigned num_consumers)
+ unsigned num_consumers, unsigned long features)
{
unsigned sub_chip_id;
/* regulator framework demands init_data ... */
@@ -561,6 +618,8 @@ add_regulator_linked(int num, struct regulator_init_data *pdata,
pdata->num_consumer_supplies = num_consumers;
}
+ pdata->driver_data = (void *)features;
+
/* NOTE: we currently ignore regulator IRQs, e.g. for short circuits */
sub_chip_id = twl_map[TWL_MODULE_PM_MASTER].sid;
return add_numbered_child(sub_chip_id, "twl_reg", num,
@@ -568,9 +627,10 @@ add_regulator_linked(int num, struct regulator_init_data *pdata,
}
static struct device *
-add_regulator(int num, struct regulator_init_data *pdata)
+add_regulator(int num, struct regulator_init_data *pdata,
+ unsigned long features)
{
- return add_regulator_linked(num, pdata, NULL, 0);
+ return add_regulator_linked(num, pdata, NULL, 0, features);
}
/*
@@ -650,17 +710,20 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
};
child = add_regulator_linked(TWL4030_REG_VUSB1V5,
- &usb_fixed, &usb1v5, 1);
+ &usb_fixed, &usb1v5, 1,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
child = add_regulator_linked(TWL4030_REG_VUSB1V8,
- &usb_fixed, &usb1v8, 1);
+ &usb_fixed, &usb1v8, 1,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
child = add_regulator_linked(TWL4030_REG_VUSB3V1,
- &usb_fixed, &usb3v1, 1);
+ &usb_fixed, &usb3v1, 1,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
@@ -685,9 +748,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
}
if (twl_has_usb() && pdata->usb && twl_class_is_6030()) {
- static struct regulator_consumer_supply usb3v3 = {
- .supply = "vusb",
- };
+ static struct regulator_consumer_supply usb3v3;
+ int regulator;
if (twl_has_regulator()) {
/* this is a template that gets copied */
@@ -700,12 +762,22 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
| REGULATOR_CHANGE_STATUS,
};
- child = add_regulator_linked(TWL6030_REG_VUSB,
- &usb_fixed, &usb3v3, 1);
+ if (features & TWL6025_SUBCLASS) {
+ usb3v3.supply = "ldousb";
+ regulator = TWL6025_REG_LDOUSB;
+ } else {
+ usb3v3.supply = "vusb";
+ regulator = TWL6030_REG_VUSB;
+ }
+ child = add_regulator_linked(regulator, &usb_fixed,
+ &usb3v3, 1,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
}
+ pdata->usb->features = features;
+
child = add_child(0, "twl6030_usb",
pdata->usb, sizeof(*pdata->usb),
true,
@@ -718,7 +790,16 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
/* we need to connect regulators to this transceiver */
if (twl_has_regulator() && child)
usb3v3.dev = child;
+ } else if (twl_has_regulator() && twl_class_is_6030()) {
+ if (features & TWL6025_SUBCLASS)
+ child = add_regulator(TWL6025_REG_LDOUSB,
+ pdata->ldousb, features);
+ else
+ child = add_regulator(TWL6030_REG_VUSB,
+ pdata->vusb, features);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
}
if (twl_has_watchdog() && twl_class_is_4030()) {
@@ -755,46 +836,55 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
/* twl4030 regulators */
if (twl_has_regulator() && twl_class_is_4030()) {
- child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1);
+ child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL4030_REG_VIO, pdata->vio);
+ child = add_regulator(TWL4030_REG_VIO, pdata->vio,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1);
+ child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2);
+ child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1);
+ child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL4030_REG_VDAC, pdata->vdac);
+ child = add_regulator(TWL4030_REG_VDAC, pdata->vdac,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
child = add_regulator((features & TWL4030_VAUX2)
? TWL4030_REG_VAUX2_4030
: TWL4030_REG_VAUX2,
- pdata->vaux2);
+ pdata->vaux2, features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL4030_REG_VINTANA1, pdata->vintana1);
+ child = add_regulator(TWL4030_REG_VINTANA1, pdata->vintana1,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL4030_REG_VINTANA2, pdata->vintana2);
+ child = add_regulator(TWL4030_REG_VINTANA2, pdata->vintana2,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL4030_REG_VINTDIG, pdata->vintdig);
+ child = add_regulator(TWL4030_REG_VINTDIG, pdata->vintdig,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
}
@@ -802,72 +892,152 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
/* maybe add LDOs that are omitted on cost-reduced parts */
if (twl_has_regulator() && !(features & TPS_SUBSET)
&& twl_class_is_4030()) {
- child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2);
+ child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2);
+ child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL4030_REG_VSIM, pdata->vsim);
+ child = add_regulator(TWL4030_REG_VSIM, pdata->vsim,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1);
+ child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3);
+ child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4);
+ child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
}
/* twl6030 regulators */
+ if (twl_has_regulator() && twl_class_is_6030() &&
+ !(features & TWL6025_SUBCLASS)) {
+ child = add_regulator(TWL6030_REG_VMMC, pdata->vmmc,
+ features);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator(TWL6030_REG_VPP, pdata->vpp,
+ features);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator(TWL6030_REG_VUSIM, pdata->vusim,
+ features);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator(TWL6030_REG_VCXIO, pdata->vcxio,
+ features);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator(TWL6030_REG_VDAC, pdata->vdac,
+ features);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator(TWL6030_REG_VAUX1_6030, pdata->vaux1,
+ features);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator(TWL6030_REG_VAUX2_6030, pdata->vaux2,
+ features);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator(TWL6030_REG_VAUX3_6030, pdata->vaux3,
+ features);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator(TWL6030_REG_CLK32KG, pdata->clk32kg,
+ features);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+ }
+
+ /* 6030 and 6025 share this regulator */
if (twl_has_regulator() && twl_class_is_6030()) {
- child = add_regulator(TWL6030_REG_VMMC, pdata->vmmc);
+ child = add_regulator(TWL6030_REG_VANA, pdata->vana,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
+ }
- child = add_regulator(TWL6030_REG_VPP, pdata->vpp);
+ /* twl6025 regulators */
+ if (twl_has_regulator() && twl_class_is_6030() &&
+ (features & TWL6025_SUBCLASS)) {
+ child = add_regulator(TWL6025_REG_LDO5, pdata->ldo5,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL6030_REG_VUSIM, pdata->vusim);
+ child = add_regulator(TWL6025_REG_LDO1, pdata->ldo1,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL6030_REG_VANA, pdata->vana);
+ child = add_regulator(TWL6025_REG_LDO7, pdata->ldo7,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL6030_REG_VCXIO, pdata->vcxio);
+ child = add_regulator(TWL6025_REG_LDO6, pdata->ldo6,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL6030_REG_VDAC, pdata->vdac);
+ child = add_regulator(TWL6025_REG_LDOLN, pdata->ldoln,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL6030_REG_VAUX1_6030, pdata->vaux1);
+ child = add_regulator(TWL6025_REG_LDO2, pdata->ldo2,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL6030_REG_VAUX2_6030, pdata->vaux2);
+ child = add_regulator(TWL6025_REG_LDO4, pdata->ldo4,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL6030_REG_VAUX3_6030, pdata->vaux3);
+ child = add_regulator(TWL6025_REG_LDO3, pdata->ldo3,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
- child = add_regulator(TWL6030_REG_CLK32KG, pdata->clk32kg);
+ child = add_regulator(TWL6025_REG_SMPS3, pdata->smps3,
+ features);
if (IS_ERR(child))
return PTR_ERR(child);
+
+ child = add_regulator(TWL6025_REG_SMPS4, pdata->smps4,
+ features);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator(TWL6025_REG_VIO, pdata->vio6025,
+ features);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
}
if (twl_has_bci() && pdata->bci &&
@@ -1014,6 +1184,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
unsigned i;
struct twl4030_platform_data *pdata = client->dev.platform_data;
u8 temp;
+ int ret = 0;
if (!pdata) {
dev_dbg(&client->dev, "no platform data?\n");
@@ -1060,6 +1231,12 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
/* setup clock framework */
clocks_init(&client->dev, pdata->clock);
+ /* read TWL IDCODE Register */
+ if (twl_id == TWL4030_CLASS_ID) {
+ ret = twl_read_idcode_register();
+ WARN(ret < 0, "Error: reading twl_idcode register value\n");
+ }
+
/* load power event scripts */
if (twl_has_power() && pdata->power)
twl4030_power_init(pdata->power);
@@ -1108,6 +1285,7 @@ static const struct i2c_device_id twl_ids[] = {
{ "tps65930", TPS_SUBSET }, /* fewer LDOs and DACs; no charger */
{ "tps65920", TPS_SUBSET }, /* fewer LDOs; no codec or charger */
{ "twl6030", TWL6030_CLASS }, /* "Phoenix power chip" */
+ { "twl6025", TWL6030_CLASS | TWL6025_SUBCLASS }, /* "Phoenix lite" */
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(i2c, twl_ids);
diff --git a/drivers/mfd/twl4030-codec.c b/drivers/mfd/twl4030-codec.c
index c02fded316c9..2bf4136464c1 100644
--- a/drivers/mfd/twl4030-codec.c
+++ b/drivers/mfd/twl4030-codec.c
@@ -1,7 +1,7 @@
/*
* MFD driver for twl4030 codec submodule
*
- * Author: Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ * Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
*
* Copyright: (C) 2009 Nokia Corporation
*
@@ -208,13 +208,15 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
if (pdata->audio) {
cell = &codec->cells[childs];
cell->name = "twl4030-codec";
- cell->mfd_data = pdata->audio;
+ cell->platform_data = pdata->audio;
+ cell->pdata_size = sizeof(*pdata->audio);
childs++;
}
if (pdata->vibra) {
cell = &codec->cells[childs];
cell->name = "twl4030-vibra";
- cell->mfd_data = pdata->vibra;
+ cell->platform_data = pdata->vibra;
+ cell->pdata_size = sizeof(*pdata->vibra);
childs++;
}
@@ -270,6 +272,6 @@ static void __devexit twl4030_codec_exit(void)
}
module_exit(twl4030_codec_exit);
-MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@nokia.com>");
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
index 2c0d4d16491a..a764676f0922 100644
--- a/drivers/mfd/twl4030-power.c
+++ b/drivers/mfd/twl4030-power.c
@@ -120,7 +120,7 @@ static u8 res_config_addrs[] = {
[RES_HFCLKOUT] = 0x8b,
[RES_32KCLKOUT] = 0x8e,
[RES_RESET] = 0x91,
- [RES_Main_Ref] = 0x94,
+ [RES_MAIN_REF] = 0x94,
};
static int __init twl4030_write_script_byte(u8 address, u8 byte)
@@ -448,7 +448,7 @@ static int __init load_twl4030_script(struct twl4030_script *tscript,
goto out;
}
if (tscript->flags & TWL4030_SLEEP_SCRIPT) {
- if (order)
+ if (!order)
pr_warning("TWL4030: Bad order of scripts (sleep "\
"script before wakeup) Leads to boot"\
"failure on some boards\n");
@@ -485,9 +485,9 @@ int twl4030_remove_script(u8 flags)
return err;
}
if (flags & TWL4030_WAKEUP12_SCRIPT) {
- if (err)
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT,
R_SEQ_ADD_S2A12);
+ if (err)
return err;
}
if (flags & TWL4030_WAKEUP3_SCRIPT) {
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index dfbae34e1804..eb3b5f88e566 100644
--- a/drivers/mfd/twl6030-irq.c
+++ b/drivers/mfd/twl6030-irq.c
@@ -76,8 +76,8 @@ static int twl6030_interrupt_mapping[24] = {
USBOTG_INTR_OFFSET, /* Bit 18 ID */
USB_PRES_INTR_OFFSET, /* Bit 19 VBUS */
CHARGER_INTR_OFFSET, /* Bit 20 CHRG_CTRL */
- CHARGER_INTR_OFFSET, /* Bit 21 EXT_CHRG */
- CHARGER_INTR_OFFSET, /* Bit 22 INT_CHRG */
+ CHARGERFAULT_INTR_OFFSET, /* Bit 21 EXT_CHRG */
+ CHARGERFAULT_INTR_OFFSET, /* Bit 22 INT_CHRG */
RSV_INTR_OFFSET, /* Bit 23 Reserved */
};
/*----------------------------------------------------------------------*/
diff --git a/drivers/mfd/wl1273-core.c b/drivers/mfd/wl1273-core.c
index 04914f2836c0..d97a86945174 100644
--- a/drivers/mfd/wl1273-core.c
+++ b/drivers/mfd/wl1273-core.c
@@ -153,7 +153,6 @@ out:
*/
static int wl1273_fm_set_volume(struct wl1273_core *core, unsigned int volume)
{
- u16 val;
int r;
if (volume > WL1273_MAX_VOLUME)
@@ -217,7 +216,8 @@ static int __devinit wl1273_core_probe(struct i2c_client *client,
cell = &core->cells[children];
cell->name = "wl1273_fm_radio";
- cell->mfd_data = &core;
+ cell->platform_data = &core;
+ cell->pdata_size = sizeof(core);
children++;
core->read = wl1273_fm_read_reg;
@@ -231,7 +231,8 @@ static int __devinit wl1273_core_probe(struct i2c_client *client,
dev_dbg(&client->dev, "%s: Have codec.\n", __func__);
cell->name = "wl1273-codec";
- cell->mfd_data = &core;
+ cell->platform_data = &core;
+ cell->pdata_size = sizeof(core);
children++;
}
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index 3fe9a58fe6c7..265f75fc6a25 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -1442,7 +1442,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
struct wm831x_pdata *pdata = wm831x->dev->platform_data;
int rev;
enum wm831x_parent parent;
- int ret;
+ int ret, i;
mutex_init(&wm831x->io_lock);
mutex_init(&wm831x->key_lock);
@@ -1581,6 +1581,17 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
}
}
+ if (pdata) {
+ for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) {
+ if (!pdata->gpio_defaults[i])
+ continue;
+
+ wm831x_reg_write(wm831x,
+ WM831X_GPIO1_CONTROL + i,
+ pdata->gpio_defaults[i] & 0xffff);
+ }
+ }
+
ret = wm831x_irq_init(wm831x, irq);
if (ret != 0)
goto err;
diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c
index 23e66af89dea..42b928ec891e 100644
--- a/drivers/mfd/wm831x-irq.c
+++ b/drivers/mfd/wm831x-irq.c
@@ -515,12 +515,6 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
0xffff);
}
- if (!irq) {
- dev_warn(wm831x->dev,
- "No interrupt specified - functionality limited\n");
- return 0;
- }
-
if (!pdata || !pdata->irq_base) {
dev_err(wm831x->dev,
"No interrupt base specified, no interrupts\n");
@@ -567,15 +561,22 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq)
#endif
}
- ret = request_threaded_irq(irq, NULL, wm831x_irq_thread,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- "wm831x", wm831x);
- if (ret != 0) {
- dev_err(wm831x->dev, "Failed to request IRQ %d: %d\n",
- irq, ret);
- return ret;
+ if (irq) {
+ ret = request_threaded_irq(irq, NULL, wm831x_irq_thread,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "wm831x", wm831x);
+ if (ret != 0) {
+ dev_err(wm831x->dev, "Failed to request IRQ %d: %d\n",
+ irq, ret);
+ return ret;
+ }
+ } else {
+ dev_warn(wm831x->dev,
+ "No interrupt specified - functionality limited\n");
}
+
+
/* Enable top level interrupts, we mask at secondary level */
wm831x_reg_write(wm831x, WM831X_SYSTEM_INTERRUPTS_MASK, 0);
diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c
index 3a6e78cb0384..597f82edacaa 100644
--- a/drivers/mfd/wm8400-core.c
+++ b/drivers/mfd/wm8400-core.c
@@ -245,7 +245,8 @@ static int wm8400_register_codec(struct wm8400 *wm8400)
{
struct mfd_cell cell = {
.name = "wm8400-codec",
- .mfd_data = wm8400,
+ .platform_data = wm8400,
+ .pdata_size = sizeof(*wm8400),
};
return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0);
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 4e007c6a4b44..4e349cd98bcf 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -144,6 +144,19 @@ config PHANTOM
If you choose to build module, its name will be phantom. If unsure,
say N here.
+config INTEL_MID_PTI
+ tristate "Parallel Trace Interface for MIPI P1149.7 cJTAG standard"
+ default n
+ help
+ The PTI (Parallel Trace Interface) driver directs
+ trace data routed from various parts in the system out
+ through an Intel Penwell PTI port and out of the mobile
+ device for analysis with a debugging tool (Lauterbach or Fido).
+
+ You should select this driver if the target kernel is meant for
+ an Intel Atom (non-netbook) mobile device containing a MIPI
+ P1149.7 standard implementation.
+
config SGI_IOC4
tristate "SGI IOC4 Base IO support"
depends on PCI
@@ -459,7 +472,7 @@ config BMP085
module will be called bmp085.
config PCH_PHUB
- tristate "PCH Packet Hub of Intel Topcliff / OKI SEMICONDUCTOR ML7213"
+ tristate "Intel EG20T PCH / OKI SEMICONDUCTOR IOH(ML7213/ML7223) PHUB"
depends on PCI
help
This driver is for PCH(Platform controller Hub) PHUB(Packet Hub) of
@@ -467,10 +480,12 @@ config PCH_PHUB
processor. The Topcliff has MAC address and Option ROM data in SROM.
This driver can access MAC address and Option ROM data in SROM.
- This driver also can be used for OKI SEMICONDUCTOR's ML7213 which is
- for IVI(In-Vehicle Infotainment) use.
- ML7213 is companion chip for Intel Atom E6xx series.
- ML7213 is completely compatible for Intel EG20T PCH.
+ This driver also can be used for OKI SEMICONDUCTOR IOH(Input/
+ Output Hub), ML7213 and ML7223.
+ ML7213 IOH is for IVI(In-Vehicle Infotainment) use and ML7223 IOH is
+ for MP(Media Phone) use.
+ ML7213/ML7223 is companion chip for Intel Atom E6xx series.
+ ML7213/ML7223 is completely compatible for Intel EG20T PCH.
To compile this driver as a module, choose M here: the module will
be called pch_phub.
@@ -481,5 +496,6 @@ source "drivers/misc/cb710/Kconfig"
source "drivers/misc/iwmc3200top/Kconfig"
source "drivers/misc/ti-st/Kconfig"
source "drivers/misc/lis3lv02d/Kconfig"
+source "drivers/misc/carma/Kconfig"
endif # MISC_DEVICES
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index f5468602961f..5f03172cc0b5 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_IBM_ASM) += ibmasm/
obj-$(CONFIG_AD525X_DPOT) += ad525x_dpot.o
obj-$(CONFIG_AD525X_DPOT_I2C) += ad525x_dpot-i2c.o
obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_dpot-spi.o
+0bj-$(CONFIG_INTEL_MID_PTI) += pti.o
obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o
obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
@@ -44,3 +45,4 @@ obj-$(CONFIG_PCH_PHUB) += pch_phub.o
obj-y += ti-st/
obj-$(CONFIG_AB8500_PWM) += ab8500-pwm.o
obj-y += lis3lv02d/
+obj-y += carma/
diff --git a/drivers/misc/bh1780gli.c b/drivers/misc/bh1780gli.c
index d07cd67c951c..82fe2d067827 100644
--- a/drivers/misc/bh1780gli.c
+++ b/drivers/misc/bh1780gli.c
@@ -49,8 +49,8 @@ static int bh1780_write(struct bh1780_data *ddata, u8 reg, u8 val, char *msg)
int ret = i2c_smbus_write_byte_data(ddata->client, reg, val);
if (ret < 0)
dev_err(&ddata->client->dev,
- "i2c_smbus_write_byte_data failed error %d\
- Register (%s)\n", ret, msg);
+ "i2c_smbus_write_byte_data failed error %d Register (%s)\n",
+ ret, msg);
return ret;
}
@@ -59,8 +59,8 @@ static int bh1780_read(struct bh1780_data *ddata, u8 reg, char *msg)
int ret = i2c_smbus_read_byte_data(ddata->client, reg);
if (ret < 0)
dev_err(&ddata->client->dev,
- "i2c_smbus_read_byte_data failed error %d\
- Register (%s)\n", ret, msg);
+ "i2c_smbus_read_byte_data failed error %d Register (%s)\n",
+ ret, msg);
return ret;
}
diff --git a/drivers/misc/carma/Kconfig b/drivers/misc/carma/Kconfig
new file mode 100644
index 000000000000..c90370ed712b
--- /dev/null
+++ b/drivers/misc/carma/Kconfig
@@ -0,0 +1,17 @@
+config CARMA_FPGA
+ tristate "CARMA DATA-FPGA Access Driver"
+ depends on FSL_SOC && PPC_83xx && MEDIA_SUPPORT && HAS_DMA && FSL_DMA
+ select VIDEOBUF_DMA_SG
+ default n
+ help
+ Say Y here to include support for communicating with the data
+ processing FPGAs on the OVRO CARMA board.
+
+config CARMA_FPGA_PROGRAM
+ tristate "CARMA DATA-FPGA Programmer"
+ depends on FSL_SOC && PPC_83xx && MEDIA_SUPPORT && HAS_DMA && FSL_DMA
+ select VIDEOBUF_DMA_SG
+ default n
+ help
+ Say Y here to include support for programming the data processing
+ FPGAs on the OVRO CARMA board.
diff --git a/drivers/misc/carma/Makefile b/drivers/misc/carma/Makefile
new file mode 100644
index 000000000000..ff36ac2ce534
--- /dev/null
+++ b/drivers/misc/carma/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_CARMA_FPGA) += carma-fpga.o
+obj-$(CONFIG_CARMA_FPGA_PROGRAM) += carma-fpga-program.o
diff --git a/drivers/misc/carma/carma-fpga-program.c b/drivers/misc/carma/carma-fpga-program.c
new file mode 100644
index 000000000000..7ce6065dc20e
--- /dev/null
+++ b/drivers/misc/carma/carma-fpga-program.c
@@ -0,0 +1,1141 @@
+/*
+ * CARMA Board DATA-FPGA Programmer
+ *
+ * Copyright (c) 2009-2011 Ira W. Snyder <iws@ovro.caltech.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/of_platform.h>
+#include <linux/completion.h>
+#include <linux/miscdevice.h>
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+#include <linux/highmem.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
+#include <linux/kref.h>
+#include <linux/fs.h>
+#include <linux/io.h>
+
+#include <media/videobuf-dma-sg.h>
+
+/* MPC8349EMDS specific get_immrbase() */
+#include <sysdev/fsl_soc.h>
+
+static const char drv_name[] = "carma-fpga-program";
+
+/*
+ * Firmware images are always this exact size
+ *
+ * 12849552 bytes for a CARMA Digitizer Board (EP2S90 FPGAs)
+ * 18662880 bytes for a CARMA Correlator Board (EP2S130 FPGAs)
+ */
+#define FW_SIZE_EP2S90 12849552
+#define FW_SIZE_EP2S130 18662880
+
+struct fpga_dev {
+ struct miscdevice miscdev;
+
+ /* Reference count */
+ struct kref ref;
+
+ /* Device Registers */
+ struct device *dev;
+ void __iomem *regs;
+ void __iomem *immr;
+
+ /* Freescale DMA Device */
+ struct dma_chan *chan;
+
+ /* Interrupts */
+ int irq, status;
+ struct completion completion;
+
+ /* FPGA Bitfile */
+ struct mutex lock;
+
+ struct videobuf_dmabuf vb;
+ bool vb_allocated;
+
+ /* max size and written bytes */
+ size_t fw_size;
+ size_t bytes;
+};
+
+/*
+ * FPGA Bitfile Helpers
+ */
+
+/**
+ * fpga_drop_firmware_data() - drop the bitfile image from memory
+ * @priv: the driver's private data structure
+ *
+ * LOCKING: must hold priv->lock
+ */
+static void fpga_drop_firmware_data(struct fpga_dev *priv)
+{
+ videobuf_dma_free(&priv->vb);
+ priv->vb_allocated = false;
+ priv->bytes = 0;
+}
+
+/*
+ * Private Data Reference Count
+ */
+
+static void fpga_dev_remove(struct kref *ref)
+{
+ struct fpga_dev *priv = container_of(ref, struct fpga_dev, ref);
+
+ /* free any firmware image that was not programmed */
+ fpga_drop_firmware_data(priv);
+
+ mutex_destroy(&priv->lock);
+ kfree(priv);
+}
+
+/*
+ * LED Trigger (could be a seperate module)
+ */
+
+/*
+ * NOTE: this whole thing does have the problem that whenever the led's are
+ * NOTE: first set to use the fpga trigger, they could be in the wrong state
+ */
+
+DEFINE_LED_TRIGGER(ledtrig_fpga);
+
+static void ledtrig_fpga_programmed(bool enabled)
+{
+ if (enabled)
+ led_trigger_event(ledtrig_fpga, LED_FULL);
+ else
+ led_trigger_event(ledtrig_fpga, LED_OFF);
+}
+
+/*
+ * FPGA Register Helpers
+ */
+
+/* Register Definitions */
+#define FPGA_CONFIG_CONTROL 0x40
+#define FPGA_CONFIG_STATUS 0x44
+#define FPGA_CONFIG_FIFO_SIZE 0x48
+#define FPGA_CONFIG_FIFO_USED 0x4C
+#define FPGA_CONFIG_TOTAL_BYTE_COUNT 0x50
+#define FPGA_CONFIG_CUR_BYTE_COUNT 0x54
+
+#define FPGA_FIFO_ADDRESS 0x3000
+
+static int fpga_fifo_size(void __iomem *regs)
+{
+ return ioread32be(regs + FPGA_CONFIG_FIFO_SIZE);
+}
+
+#define CFG_STATUS_ERR_MASK 0xfffe
+
+static int fpga_config_error(void __iomem *regs)
+{
+ return ioread32be(regs + FPGA_CONFIG_STATUS) & CFG_STATUS_ERR_MASK;
+}
+
+static int fpga_fifo_empty(void __iomem *regs)
+{
+ return ioread32be(regs + FPGA_CONFIG_FIFO_USED) == 0;
+}
+
+static void fpga_fifo_write(void __iomem *regs, u32 val)
+{
+ iowrite32be(val, regs + FPGA_FIFO_ADDRESS);
+}
+
+static void fpga_set_byte_count(void __iomem *regs, u32 count)
+{
+ iowrite32be(count, regs + FPGA_CONFIG_TOTAL_BYTE_COUNT);
+}
+
+#define CFG_CTL_ENABLE (1 << 0)
+#define CFG_CTL_RESET (1 << 1)
+#define CFG_CTL_DMA (1 << 2)
+
+static void fpga_programmer_enable(struct fpga_dev *priv, bool dma)
+{
+ u32 val;
+
+ val = (dma) ? (CFG_CTL_ENABLE | CFG_CTL_DMA) : CFG_CTL_ENABLE;
+ iowrite32be(val, priv->regs + FPGA_CONFIG_CONTROL);
+}
+
+static void fpga_programmer_disable(struct fpga_dev *priv)
+{
+ iowrite32be(0x0, priv->regs + FPGA_CONFIG_CONTROL);
+}
+
+static void fpga_dump_registers(struct fpga_dev *priv)
+{
+ u32 control, status, size, used, total, curr;
+
+ /* good status: do nothing */
+ if (priv->status == 0)
+ return;
+
+ /* Dump all status registers */
+ control = ioread32be(priv->regs + FPGA_CONFIG_CONTROL);
+ status = ioread32be(priv->regs + FPGA_CONFIG_STATUS);
+ size = ioread32be(priv->regs + FPGA_CONFIG_FIFO_SIZE);
+ used = ioread32be(priv->regs + FPGA_CONFIG_FIFO_USED);
+ total = ioread32be(priv->regs + FPGA_CONFIG_TOTAL_BYTE_COUNT);
+ curr = ioread32be(priv->regs + FPGA_CONFIG_CUR_BYTE_COUNT);
+
+ dev_err(priv->dev, "Configuration failed, dumping status registers\n");
+ dev_err(priv->dev, "Control: 0x%.8x\n", control);
+ dev_err(priv->dev, "Status: 0x%.8x\n", status);
+ dev_err(priv->dev, "FIFO Size: 0x%.8x\n", size);
+ dev_err(priv->dev, "FIFO Used: 0x%.8x\n", used);
+ dev_err(priv->dev, "FIFO Total: 0x%.8x\n", total);
+ dev_err(priv->dev, "FIFO Curr: 0x%.8x\n", curr);
+}
+
+/*
+ * FPGA Power Supply Code
+ */
+
+#define CTL_PWR_CONTROL 0x2006
+#define CTL_PWR_STATUS 0x200A
+#define CTL_PWR_FAIL 0x200B
+
+#define PWR_CONTROL_ENABLE 0x01
+
+#define PWR_STATUS_ERROR_MASK 0x10
+#define PWR_STATUS_GOOD 0x0f
+
+/*
+ * Determine if the FPGA power is good for all supplies
+ */
+static bool fpga_power_good(struct fpga_dev *priv)
+{
+ u8 val;
+
+ val = ioread8(priv->regs + CTL_PWR_STATUS);
+ if (val & PWR_STATUS_ERROR_MASK)
+ return false;
+
+ return val == PWR_STATUS_GOOD;
+}
+
+/*
+ * Disable the FPGA power supplies
+ */
+static void fpga_disable_power_supplies(struct fpga_dev *priv)
+{
+ unsigned long start;
+ u8 val;
+
+ iowrite8(0x0, priv->regs + CTL_PWR_CONTROL);
+
+ /*
+ * Wait 500ms for the power rails to discharge
+ *
+ * Without this delay, the CTL-CPLD state machine can get into a
+ * state where it is waiting for the power-goods to assert, but they
+ * never do. This only happens when enabling and disabling the
+ * power sequencer very rapidly.
+ *
+ * The loop below will also wait for the power goods to de-assert,
+ * but testing has shown that they are always disabled by the time
+ * the sleep completes. However, omitting the sleep and only waiting
+ * for the power-goods to de-assert was not sufficient to ensure
+ * that the power sequencer would not wedge itself.
+ */
+ msleep(500);
+
+ start = jiffies;
+ while (time_before(jiffies, start + HZ)) {
+ val = ioread8(priv->regs + CTL_PWR_STATUS);
+ if (!(val & PWR_STATUS_GOOD))
+ break;
+
+ usleep_range(5000, 10000);
+ }
+
+ val = ioread8(priv->regs + CTL_PWR_STATUS);
+ if (val & PWR_STATUS_GOOD) {
+ dev_err(priv->dev, "power disable failed: "
+ "power goods: status 0x%.2x\n", val);
+ }
+
+ if (val & PWR_STATUS_ERROR_MASK) {
+ dev_err(priv->dev, "power disable failed: "
+ "alarm bit set: status 0x%.2x\n", val);
+ }
+}
+
+/**
+ * fpga_enable_power_supplies() - enable the DATA-FPGA power supplies
+ * @priv: the driver's private data structure
+ *
+ * Enable the DATA-FPGA power supplies, waiting up to 1 second for
+ * them to enable successfully.
+ *
+ * Returns 0 on success, -ERRNO otherwise
+ */
+static int fpga_enable_power_supplies(struct fpga_dev *priv)
+{
+ unsigned long start = jiffies;
+
+ if (fpga_power_good(priv)) {
+ dev_dbg(priv->dev, "power was already good\n");
+ return 0;
+ }
+
+ iowrite8(PWR_CONTROL_ENABLE, priv->regs + CTL_PWR_CONTROL);
+ while (time_before(jiffies, start + HZ)) {
+ if (fpga_power_good(priv))
+ return 0;
+
+ usleep_range(5000, 10000);
+ }
+
+ return fpga_power_good(priv) ? 0 : -ETIMEDOUT;
+}
+
+/*
+ * Determine if the FPGA power supplies are all enabled
+ */
+static bool fpga_power_enabled(struct fpga_dev *priv)
+{
+ u8 val;
+
+ val = ioread8(priv->regs + CTL_PWR_CONTROL);
+ if (val & PWR_CONTROL_ENABLE)
+ return true;
+
+ return false;
+}
+
+/*
+ * Determine if the FPGA's are programmed and running correctly
+ */
+static bool fpga_running(struct fpga_dev *priv)
+{
+ if (!fpga_power_good(priv))
+ return false;
+
+ /* Check the config done bit */
+ return ioread32be(priv->regs + FPGA_CONFIG_STATUS) & (1 << 18);
+}
+
+/*
+ * FPGA Programming Code
+ */
+
+/**
+ * fpga_program_block() - put a block of data into the programmer's FIFO
+ * @priv: the driver's private data structure
+ * @buf: the data to program
+ * @count: the length of data to program (must be a multiple of 4 bytes)
+ *
+ * Returns 0 on success, -ERRNO otherwise
+ */
+static int fpga_program_block(struct fpga_dev *priv, void *buf, size_t count)
+{
+ u32 *data = buf;
+ int size = fpga_fifo_size(priv->regs);
+ int i, len;
+ unsigned long timeout;
+
+ /* enforce correct data length for the FIFO */
+ BUG_ON(count % 4 != 0);
+
+ while (count > 0) {
+
+ /* Get the size of the block to write (maximum is FIFO_SIZE) */
+ len = min_t(size_t, count, size);
+ timeout = jiffies + HZ / 4;
+
+ /* Write the block */
+ for (i = 0; i < len / 4; i++)
+ fpga_fifo_write(priv->regs, data[i]);
+
+ /* Update the amounts left */
+ count -= len;
+ data += len / 4;
+
+ /* Wait for the fifo to empty */
+ while (true) {
+
+ if (fpga_fifo_empty(priv->regs)) {
+ break;
+ } else {
+ dev_dbg(priv->dev, "Fifo not empty\n");
+ cpu_relax();
+ }
+
+ if (fpga_config_error(priv->regs)) {
+ dev_err(priv->dev, "Error detected\n");
+ return -EIO;
+ }
+
+ if (time_after(jiffies, timeout)) {
+ dev_err(priv->dev, "Fifo drain timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ usleep_range(5000, 10000);
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * fpga_program_cpu() - program the DATA-FPGA's using the CPU
+ * @priv: the driver's private data structure
+ *
+ * This is useful when the DMA programming method fails. It is possible to
+ * wedge the Freescale DMA controller such that the DMA programming method
+ * always fails. This method has always succeeded.
+ *
+ * Returns 0 on success, -ERRNO otherwise
+ */
+static noinline int fpga_program_cpu(struct fpga_dev *priv)
+{
+ int ret;
+
+ /* Disable the programmer */
+ fpga_programmer_disable(priv);
+
+ /* Set the total byte count */
+ fpga_set_byte_count(priv->regs, priv->bytes);
+ dev_dbg(priv->dev, "total byte count %u bytes\n", priv->bytes);
+
+ /* Enable the controller for programming */
+ fpga_programmer_enable(priv, false);
+ dev_dbg(priv->dev, "enabled the controller\n");
+
+ /* Write each chunk of the FPGA bitfile to FPGA programmer */
+ ret = fpga_program_block(priv, priv->vb.vaddr, priv->bytes);
+ if (ret)
+ goto out_disable_controller;
+
+ /* Wait for the interrupt handler to signal that programming finished */
+ ret = wait_for_completion_timeout(&priv->completion, 2 * HZ);
+ if (!ret) {
+ dev_err(priv->dev, "Timed out waiting for completion\n");
+ ret = -ETIMEDOUT;
+ goto out_disable_controller;
+ }
+
+ /* Retrieve the status from the interrupt handler */
+ ret = priv->status;
+
+out_disable_controller:
+ fpga_programmer_disable(priv);
+ return ret;
+}
+
+#define FIFO_DMA_ADDRESS 0xf0003000
+#define FIFO_MAX_LEN 4096
+
+/**
+ * fpga_program_dma() - program the DATA-FPGA's using the DMA engine
+ * @priv: the driver's private data structure
+ *
+ * Program the DATA-FPGA's using the Freescale DMA engine. This requires that
+ * the engine is programmed such that the hardware DMA request lines can
+ * control the entire DMA transaction. The system controller FPGA then
+ * completely offloads the programming from the CPU.
+ *
+ * Returns 0 on success, -ERRNO otherwise
+ */
+static noinline int fpga_program_dma(struct fpga_dev *priv)
+{
+ struct videobuf_dmabuf *vb = &priv->vb;
+ struct dma_chan *chan = priv->chan;
+ struct dma_async_tx_descriptor *tx;
+ size_t num_pages, len, avail = 0;
+ struct dma_slave_config config;
+ struct scatterlist *sg;
+ struct sg_table table;
+ dma_cookie_t cookie;
+ int ret, i;
+
+ /* Disable the programmer */
+ fpga_programmer_disable(priv);
+
+ /* Allocate a scatterlist for the DMA destination */
+ num_pages = DIV_ROUND_UP(priv->bytes, FIFO_MAX_LEN);
+ ret = sg_alloc_table(&table, num_pages, GFP_KERNEL);
+ if (ret) {
+ dev_err(priv->dev, "Unable to allocate dst scatterlist\n");
+ ret = -ENOMEM;
+ goto out_return;
+ }
+
+ /*
+ * This is an ugly hack
+ *
+ * We fill in a scatterlist as if it were mapped for DMA. This is
+ * necessary because there exists no better structure for this
+ * inside the kernel code.
+ *
+ * As an added bonus, we can use the DMAEngine API for all of this,
+ * rather than inventing another extremely similar API.
+ */
+ avail = priv->bytes;
+ for_each_sg(table.sgl, sg, num_pages, i) {
+ len = min_t(size_t, avail, FIFO_MAX_LEN);
+ sg_dma_address(sg) = FIFO_DMA_ADDRESS;
+ sg_dma_len(sg) = len;
+
+ avail -= len;
+ }
+
+ /* Map the buffer for DMA */
+ ret = videobuf_dma_map(priv->dev, &priv->vb);
+ if (ret) {
+ dev_err(priv->dev, "Unable to map buffer for DMA\n");
+ goto out_free_table;
+ }
+
+ /*
+ * Configure the DMA channel to transfer FIFO_SIZE / 2 bytes per
+ * transaction, and then put it under external control
+ */
+ memset(&config, 0, sizeof(config));
+ config.direction = DMA_TO_DEVICE;
+ config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ config.dst_maxburst = fpga_fifo_size(priv->regs) / 2 / 4;
+ ret = chan->device->device_control(chan, DMA_SLAVE_CONFIG,
+ (unsigned long)&config);
+ if (ret) {
+ dev_err(priv->dev, "DMA slave configuration failed\n");
+ goto out_dma_unmap;
+ }
+
+ ret = chan->device->device_control(chan, FSLDMA_EXTERNAL_START, 1);
+ if (ret) {
+ dev_err(priv->dev, "DMA external control setup failed\n");
+ goto out_dma_unmap;
+ }
+
+ /* setup and submit the DMA transaction */
+ tx = chan->device->device_prep_dma_sg(chan,
+ table.sgl, num_pages,
+ vb->sglist, vb->sglen, 0);
+ if (!tx) {
+ dev_err(priv->dev, "Unable to prep DMA transaction\n");
+ ret = -ENOMEM;
+ goto out_dma_unmap;
+ }
+
+ cookie = tx->tx_submit(tx);
+ if (dma_submit_error(cookie)) {
+ dev_err(priv->dev, "Unable to submit DMA transaction\n");
+ ret = -ENOMEM;
+ goto out_dma_unmap;
+ }
+
+ dma_async_memcpy_issue_pending(chan);
+
+ /* Set the total byte count */
+ fpga_set_byte_count(priv->regs, priv->bytes);
+ dev_dbg(priv->dev, "total byte count %u bytes\n", priv->bytes);
+
+ /* Enable the controller for DMA programming */
+ fpga_programmer_enable(priv, true);
+ dev_dbg(priv->dev, "enabled the controller\n");
+
+ /* Wait for the interrupt handler to signal that programming finished */
+ ret = wait_for_completion_timeout(&priv->completion, 2 * HZ);
+ if (!ret) {
+ dev_err(priv->dev, "Timed out waiting for completion\n");
+ ret = -ETIMEDOUT;
+ goto out_disable_controller;
+ }
+
+ /* Retrieve the status from the interrupt handler */
+ ret = priv->status;
+
+out_disable_controller:
+ fpga_programmer_disable(priv);
+out_dma_unmap:
+ videobuf_dma_unmap(priv->dev, vb);
+out_free_table:
+ sg_free_table(&table);
+out_return:
+ return ret;
+}
+
+/*
+ * Interrupt Handling
+ */
+
+static irqreturn_t fpga_irq(int irq, void *dev_id)
+{
+ struct fpga_dev *priv = dev_id;
+
+ /* Save the status */
+ priv->status = fpga_config_error(priv->regs) ? -EIO : 0;
+ dev_dbg(priv->dev, "INTERRUPT status %d\n", priv->status);
+ fpga_dump_registers(priv);
+
+ /* Disabling the programmer clears the interrupt */
+ fpga_programmer_disable(priv);
+
+ /* Notify any waiters */
+ complete(&priv->completion);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * SYSFS Helpers
+ */
+
+/**
+ * fpga_do_stop() - deconfigure (reset) the DATA-FPGA's
+ * @priv: the driver's private data structure
+ *
+ * LOCKING: must hold priv->lock
+ */
+static int fpga_do_stop(struct fpga_dev *priv)
+{
+ u32 val;
+
+ /* Set the led to unprogrammed */
+ ledtrig_fpga_programmed(false);
+
+ /* Pulse the config line to reset the FPGA's */
+ val = CFG_CTL_ENABLE | CFG_CTL_RESET;
+ iowrite32be(val, priv->regs + FPGA_CONFIG_CONTROL);
+ iowrite32be(0x0, priv->regs + FPGA_CONFIG_CONTROL);
+
+ return 0;
+}
+
+static noinline int fpga_do_program(struct fpga_dev *priv)
+{
+ int ret;
+
+ if (priv->bytes != priv->fw_size) {
+ dev_err(priv->dev, "Incorrect bitfile size: got %zu bytes, "
+ "should be %zu bytes\n",
+ priv->bytes, priv->fw_size);
+ return -EINVAL;
+ }
+
+ if (!fpga_power_enabled(priv)) {
+ dev_err(priv->dev, "Power not enabled\n");
+ return -EINVAL;
+ }
+
+ if (!fpga_power_good(priv)) {
+ dev_err(priv->dev, "Power not good\n");
+ return -EINVAL;
+ }
+
+ /* Set the LED to unprogrammed */
+ ledtrig_fpga_programmed(false);
+
+ /* Try to program the FPGA's using DMA */
+ ret = fpga_program_dma(priv);
+
+ /* If DMA failed or doesn't exist, try with CPU */
+ if (ret) {
+ dev_warn(priv->dev, "Falling back to CPU programming\n");
+ ret = fpga_program_cpu(priv);
+ }
+
+ if (ret) {
+ dev_err(priv->dev, "Unable to program FPGA's\n");
+ return ret;
+ }
+
+ /* Drop the firmware bitfile from memory */
+ fpga_drop_firmware_data(priv);
+
+ dev_dbg(priv->dev, "FPGA programming successful\n");
+ ledtrig_fpga_programmed(true);
+
+ return 0;
+}
+
+/*
+ * File Operations
+ */
+
+static int fpga_open(struct inode *inode, struct file *filp)
+{
+ /*
+ * The miscdevice layer puts our struct miscdevice into the
+ * filp->private_data field. We use this to find our private
+ * data and then overwrite it with our own private structure.
+ */
+ struct fpga_dev *priv = container_of(filp->private_data,
+ struct fpga_dev, miscdev);
+ unsigned int nr_pages;
+ int ret;
+
+ /* We only allow one process at a time */
+ ret = mutex_lock_interruptible(&priv->lock);
+ if (ret)
+ return ret;
+
+ filp->private_data = priv;
+ kref_get(&priv->ref);
+
+ /* Truncation: drop any existing data */
+ if (filp->f_flags & O_TRUNC)
+ priv->bytes = 0;
+
+ /* Check if we have already allocated a buffer */
+ if (priv->vb_allocated)
+ return 0;
+
+ /* Allocate a buffer to hold enough data for the bitfile */
+ nr_pages = DIV_ROUND_UP(priv->fw_size, PAGE_SIZE);
+ ret = videobuf_dma_init_kernel(&priv->vb, DMA_TO_DEVICE, nr_pages);
+ if (ret) {
+ dev_err(priv->dev, "unable to allocate data buffer\n");
+ mutex_unlock(&priv->lock);
+ kref_put(&priv->ref, fpga_dev_remove);
+ return ret;
+ }
+
+ priv->vb_allocated = true;
+ return 0;
+}
+
+static int fpga_release(struct inode *inode, struct file *filp)
+{
+ struct fpga_dev *priv = filp->private_data;
+
+ mutex_unlock(&priv->lock);
+ kref_put(&priv->ref, fpga_dev_remove);
+ return 0;
+}
+
+static ssize_t fpga_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ struct fpga_dev *priv = filp->private_data;
+
+ /* FPGA bitfiles have an exact size: disallow anything else */
+ if (priv->bytes >= priv->fw_size)
+ return -ENOSPC;
+
+ count = min_t(size_t, priv->fw_size - priv->bytes, count);
+ if (copy_from_user(priv->vb.vaddr + priv->bytes, buf, count))
+ return -EFAULT;
+
+ priv->bytes += count;
+ return count;
+}
+
+static ssize_t fpga_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *f_pos)
+{
+ struct fpga_dev *priv = filp->private_data;
+
+ count = min_t(size_t, priv->bytes - *f_pos, count);
+ if (copy_to_user(buf, priv->vb.vaddr + *f_pos, count))
+ return -EFAULT;
+
+ *f_pos += count;
+ return count;
+}
+
+static loff_t fpga_llseek(struct file *filp, loff_t offset, int origin)
+{
+ struct fpga_dev *priv = filp->private_data;
+ loff_t newpos;
+
+ /* only read-only opens are allowed to seek */
+ if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
+ return -EINVAL;
+
+ switch (origin) {
+ case SEEK_SET: /* seek relative to the beginning of the file */
+ newpos = offset;
+ break;
+ case SEEK_CUR: /* seek relative to current position in the file */
+ newpos = filp->f_pos + offset;
+ break;
+ case SEEK_END: /* seek relative to the end of the file */
+ newpos = priv->fw_size - offset;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* check for sanity */
+ if (newpos > priv->fw_size)
+ return -EINVAL;
+
+ filp->f_pos = newpos;
+ return newpos;
+}
+
+static const struct file_operations fpga_fops = {
+ .open = fpga_open,
+ .release = fpga_release,
+ .write = fpga_write,
+ .read = fpga_read,
+ .llseek = fpga_llseek,
+};
+
+/*
+ * Device Attributes
+ */
+
+static ssize_t pfail_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct fpga_dev *priv = dev_get_drvdata(dev);
+ u8 val;
+
+ val = ioread8(priv->regs + CTL_PWR_FAIL);
+ return snprintf(buf, PAGE_SIZE, "0x%.2x\n", val);
+}
+
+static ssize_t pgood_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct fpga_dev *priv = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%d\n", fpga_power_good(priv));
+}
+
+static ssize_t penable_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct fpga_dev *priv = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%d\n", fpga_power_enabled(priv));
+}
+
+static ssize_t penable_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fpga_dev *priv = dev_get_drvdata(dev);
+ unsigned long val;
+ int ret;
+
+ if (strict_strtoul(buf, 0, &val))
+ return -EINVAL;
+
+ if (val) {
+ ret = fpga_enable_power_supplies(priv);
+ if (ret)
+ return ret;
+ } else {
+ fpga_do_stop(priv);
+ fpga_disable_power_supplies(priv);
+ }
+
+ return count;
+}
+
+static ssize_t program_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct fpga_dev *priv = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%d\n", fpga_running(priv));
+}
+
+static ssize_t program_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fpga_dev *priv = dev_get_drvdata(dev);
+ unsigned long val;
+ int ret;
+
+ if (strict_strtoul(buf, 0, &val))
+ return -EINVAL;
+
+ /* We can't have an image writer and be programming simultaneously */
+ if (mutex_lock_interruptible(&priv->lock))
+ return -ERESTARTSYS;
+
+ /* Program or Reset the FPGA's */
+ ret = val ? fpga_do_program(priv) : fpga_do_stop(priv);
+ if (ret)
+ goto out_unlock;
+
+ /* Success */
+ ret = count;
+
+out_unlock:
+ mutex_unlock(&priv->lock);
+ return ret;
+}
+
+static DEVICE_ATTR(power_fail, S_IRUGO, pfail_show, NULL);
+static DEVICE_ATTR(power_good, S_IRUGO, pgood_show, NULL);
+static DEVICE_ATTR(power_enable, S_IRUGO | S_IWUSR,
+ penable_show, penable_store);
+
+static DEVICE_ATTR(program, S_IRUGO | S_IWUSR,
+ program_show, program_store);
+
+static struct attribute *fpga_attributes[] = {
+ &dev_attr_power_fail.attr,
+ &dev_attr_power_good.attr,
+ &dev_attr_power_enable.attr,
+ &dev_attr_program.attr,
+ NULL,
+};
+
+static const struct attribute_group fpga_attr_group = {
+ .attrs = fpga_attributes,
+};
+
+/*
+ * OpenFirmware Device Subsystem
+ */
+
+#define SYS_REG_VERSION 0x00
+#define SYS_REG_GEOGRAPHIC 0x10
+
+static bool dma_filter(struct dma_chan *chan, void *data)
+{
+ /*
+ * DMA Channel #0 is the only acceptable device
+ *
+ * This probably won't survive an unload/load cycle of the Freescale
+ * DMAEngine driver, but that won't be a problem
+ */
+ return chan->chan_id == 0 && chan->device->dev_id == 0;
+}
+
+static int fpga_of_remove(struct platform_device *op)
+{
+ struct fpga_dev *priv = dev_get_drvdata(&op->dev);
+ struct device *this_device = priv->miscdev.this_device;
+
+ sysfs_remove_group(&this_device->kobj, &fpga_attr_group);
+ misc_deregister(&priv->miscdev);
+
+ free_irq(priv->irq, priv);
+ irq_dispose_mapping(priv->irq);
+
+ /* make sure the power supplies are off */
+ fpga_disable_power_supplies(priv);
+
+ /* unmap registers */
+ iounmap(priv->immr);
+ iounmap(priv->regs);
+
+ dma_release_channel(priv->chan);
+
+ /* drop our reference to the private data structure */
+ kref_put(&priv->ref, fpga_dev_remove);
+ return 0;
+}
+
+/* CTL-CPLD Version Register */
+#define CTL_CPLD_VERSION 0x2000
+
+static int fpga_of_probe(struct platform_device *op,
+ const struct of_device_id *match)
+{
+ struct device_node *of_node = op->dev.of_node;
+ struct device *this_device;
+ struct fpga_dev *priv;
+ dma_cap_mask_t mask;
+ u32 ver;
+ int ret;
+
+ /* Allocate private data */
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(&op->dev, "Unable to allocate private data\n");
+ ret = -ENOMEM;
+ goto out_return;
+ }
+
+ /* Setup the miscdevice */
+ priv->miscdev.minor = MISC_DYNAMIC_MINOR;
+ priv->miscdev.name = drv_name;
+ priv->miscdev.fops = &fpga_fops;
+
+ kref_init(&priv->ref);
+
+ dev_set_drvdata(&op->dev, priv);
+ priv->dev = &op->dev;
+ mutex_init(&priv->lock);
+ init_completion(&priv->completion);
+ videobuf_dma_init(&priv->vb);
+
+ dev_set_drvdata(priv->dev, priv);
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_MEMCPY, mask);
+ dma_cap_set(DMA_INTERRUPT, mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ dma_cap_set(DMA_SG, mask);
+
+ /* Get control of DMA channel #0 */
+ priv->chan = dma_request_channel(mask, dma_filter, NULL);
+ if (!priv->chan) {
+ dev_err(&op->dev, "Unable to acquire DMA channel #0\n");
+ ret = -ENODEV;
+ goto out_free_priv;
+ }
+
+ /* Remap the registers for use */
+ priv->regs = of_iomap(of_node, 0);
+ if (!priv->regs) {
+ dev_err(&op->dev, "Unable to ioremap registers\n");
+ ret = -ENOMEM;
+ goto out_dma_release_channel;
+ }
+
+ /* Remap the IMMR for use */
+ priv->immr = ioremap(get_immrbase(), 0x100000);
+ if (!priv->immr) {
+ dev_err(&op->dev, "Unable to ioremap IMMR\n");
+ ret = -ENOMEM;
+ goto out_unmap_regs;
+ }
+
+ /*
+ * Check that external DMA is configured
+ *
+ * U-Boot does this for us, but we should check it and bail out if
+ * there is a problem. Failing to have this register setup correctly
+ * will cause the DMA controller to transfer a single cacheline
+ * worth of data, then wedge itself.
+ */
+ if ((ioread32be(priv->immr + 0x114) & 0xE00) != 0xE00) {
+ dev_err(&op->dev, "External DMA control not configured\n");
+ ret = -ENODEV;
+ goto out_unmap_immr;
+ }
+
+ /*
+ * Check the CTL-CPLD version
+ *
+ * This driver uses the CTL-CPLD DATA-FPGA power sequencer, and we
+ * don't want to run on any version of the CTL-CPLD that does not use
+ * a compatible register layout.
+ *
+ * v2: changed register layout, added power sequencer
+ * v3: added glitch filter on the i2c overcurrent/overtemp outputs
+ */
+ ver = ioread8(priv->regs + CTL_CPLD_VERSION);
+ if (ver != 0x02 && ver != 0x03) {
+ dev_err(&op->dev, "CTL-CPLD is not version 0x02 or 0x03!\n");
+ ret = -ENODEV;
+ goto out_unmap_immr;
+ }
+
+ /* Set the exact size that the firmware image should be */
+ ver = ioread32be(priv->regs + SYS_REG_VERSION);
+ priv->fw_size = (ver & (1 << 18)) ? FW_SIZE_EP2S130 : FW_SIZE_EP2S90;
+
+ /* Find the correct IRQ number */
+ priv->irq = irq_of_parse_and_map(of_node, 0);
+ if (priv->irq == NO_IRQ) {
+ dev_err(&op->dev, "Unable to find IRQ line\n");
+ ret = -ENODEV;
+ goto out_unmap_immr;
+ }
+
+ /* Request the IRQ */
+ ret = request_irq(priv->irq, fpga_irq, IRQF_SHARED, drv_name, priv);
+ if (ret) {
+ dev_err(&op->dev, "Unable to request IRQ %d\n", priv->irq);
+ ret = -ENODEV;
+ goto out_irq_dispose_mapping;
+ }
+
+ /* Reset and stop the FPGA's, just in case */
+ fpga_do_stop(priv);
+
+ /* Register the miscdevice */
+ ret = misc_register(&priv->miscdev);
+ if (ret) {
+ dev_err(&op->dev, "Unable to register miscdevice\n");
+ goto out_free_irq;
+ }
+
+ /* Create the sysfs files */
+ this_device = priv->miscdev.this_device;
+ dev_set_drvdata(this_device, priv);
+ ret = sysfs_create_group(&this_device->kobj, &fpga_attr_group);
+ if (ret) {
+ dev_err(&op->dev, "Unable to create sysfs files\n");
+ goto out_misc_deregister;
+ }
+
+ dev_info(priv->dev, "CARMA FPGA Programmer: %s rev%s with %s FPGAs\n",
+ (ver & (1 << 17)) ? "Correlator" : "Digitizer",
+ (ver & (1 << 16)) ? "B" : "A",
+ (ver & (1 << 18)) ? "EP2S130" : "EP2S90");
+
+ return 0;
+
+out_misc_deregister:
+ misc_deregister(&priv->miscdev);
+out_free_irq:
+ free_irq(priv->irq, priv);
+out_irq_dispose_mapping:
+ irq_dispose_mapping(priv->irq);
+out_unmap_immr:
+ iounmap(priv->immr);
+out_unmap_regs:
+ iounmap(priv->regs);
+out_dma_release_channel:
+ dma_release_channel(priv->chan);
+out_free_priv:
+ kref_put(&priv->ref, fpga_dev_remove);
+out_return:
+ return ret;
+}
+
+static struct of_device_id fpga_of_match[] = {
+ { .compatible = "carma,fpga-programmer", },
+ {},
+};
+
+static struct of_platform_driver fpga_of_driver = {
+ .probe = fpga_of_probe,
+ .remove = fpga_of_remove,
+ .driver = {
+ .name = drv_name,
+ .of_match_table = fpga_of_match,
+ .owner = THIS_MODULE,
+ },
+};
+
+/*
+ * Module Init / Exit
+ */
+
+static int __init fpga_init(void)
+{
+ led_trigger_register_simple("fpga", &ledtrig_fpga);
+ return of_register_platform_driver(&fpga_of_driver);
+}
+
+static void __exit fpga_exit(void)
+{
+ of_unregister_platform_driver(&fpga_of_driver);
+ led_trigger_unregister_simple(ledtrig_fpga);
+}
+
+MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
+MODULE_DESCRIPTION("CARMA Board DATA-FPGA Programmer");
+MODULE_LICENSE("GPL");
+
+module_init(fpga_init);
+module_exit(fpga_exit);
diff --git a/drivers/misc/carma/carma-fpga.c b/drivers/misc/carma/carma-fpga.c
new file mode 100644
index 000000000000..3965821fef17
--- /dev/null
+++ b/drivers/misc/carma/carma-fpga.c
@@ -0,0 +1,1433 @@
+/*
+ * CARMA DATA-FPGA Access Driver
+ *
+ * Copyright (c) 2009-2011 Ira W. Snyder <iws@ovro.caltech.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+/*
+ * FPGA Memory Dump Format
+ *
+ * FPGA #0 control registers (32 x 32-bit words)
+ * FPGA #1 control registers (32 x 32-bit words)
+ * FPGA #2 control registers (32 x 32-bit words)
+ * FPGA #3 control registers (32 x 32-bit words)
+ * SYSFPGA control registers (32 x 32-bit words)
+ * FPGA #0 correlation array (NUM_CORL0 correlation blocks)
+ * FPGA #1 correlation array (NUM_CORL1 correlation blocks)
+ * FPGA #2 correlation array (NUM_CORL2 correlation blocks)
+ * FPGA #3 correlation array (NUM_CORL3 correlation blocks)
+ *
+ * Each correlation array consists of:
+ *
+ * Correlation Data (2 x NUM_LAGSn x 32-bit words)
+ * Pipeline Metadata (2 x NUM_METAn x 32-bit words)
+ * Quantization Counters (2 x NUM_QCNTn x 32-bit words)
+ *
+ * The NUM_CORLn, NUM_LAGSn, NUM_METAn, and NUM_QCNTn values come from
+ * the FPGA configuration registers. They do not change once the FPGA's
+ * have been programmed, they only change on re-programming.
+ */
+
+/*
+ * Basic Description:
+ *
+ * This driver is used to capture correlation spectra off of the four data
+ * processing FPGAs. The FPGAs are often reprogrammed at runtime, therefore
+ * this driver supports dynamic enable/disable of capture while the device
+ * remains open.
+ *
+ * The nominal capture rate is 64Hz (every 15.625ms). To facilitate this fast
+ * capture rate, all buffers are pre-allocated to avoid any potentially long
+ * running memory allocations while capturing.
+ *
+ * There are two lists and one pointer which are used to keep track of the
+ * different states of data buffers.
+ *
+ * 1) free list
+ * This list holds all empty data buffers which are ready to receive data.
+ *
+ * 2) inflight pointer
+ * This pointer holds the currently inflight data buffer. This buffer is having
+ * data copied into it by the DMA engine.
+ *
+ * 3) used list
+ * This list holds data buffers which have been filled, and are waiting to be
+ * read by userspace.
+ *
+ * All buffers start life on the free list, then move successively to the
+ * inflight pointer, and then to the used list. After they have been read by
+ * userspace, they are moved back to the free list. The cycle repeats as long
+ * as necessary.
+ *
+ * It should be noted that all buffers are mapped and ready for DMA when they
+ * are on any of the three lists. They are only unmapped when they are in the
+ * process of being read by userspace.
+ */
+
+/*
+ * Notes on the IRQ masking scheme:
+ *
+ * The IRQ masking scheme here is different than most other hardware. The only
+ * way for the DATA-FPGAs to detect if the kernel has taken too long to copy
+ * the data is if the status registers are not cleared before the next
+ * correlation data dump is ready.
+ *
+ * The interrupt line is connected to the status registers, such that when they
+ * are cleared, the interrupt is de-asserted. Therein lies our problem. We need
+ * to schedule a long-running DMA operation and return from the interrupt
+ * handler quickly, but we cannot clear the status registers.
+ *
+ * To handle this, the system controller FPGA has the capability to connect the
+ * interrupt line to a user-controlled GPIO pin. This pin is driven high
+ * (unasserted) and left that way. To mask the interrupt, we change the
+ * interrupt source to the GPIO pin. Tada, we hid the interrupt. :)
+ */
+
+#include <linux/of_platform.h>
+#include <linux/dma-mapping.h>
+#include <linux/miscdevice.h>
+#include <linux/interrupt.h>
+#include <linux/dmaengine.h>
+#include <linux/seq_file.h>
+#include <linux/highmem.h>
+#include <linux/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/kref.h>
+#include <linux/io.h>
+
+#include <media/videobuf-dma-sg.h>
+
+/* system controller registers */
+#define SYS_IRQ_SOURCE_CTL 0x24
+#define SYS_IRQ_OUTPUT_EN 0x28
+#define SYS_IRQ_OUTPUT_DATA 0x2C
+#define SYS_IRQ_INPUT_DATA 0x30
+#define SYS_FPGA_CONFIG_STATUS 0x44
+
+/* GPIO IRQ line assignment */
+#define IRQ_CORL_DONE 0x10
+
+/* FPGA registers */
+#define MMAP_REG_VERSION 0x00
+#define MMAP_REG_CORL_CONF1 0x08
+#define MMAP_REG_CORL_CONF2 0x0C
+#define MMAP_REG_STATUS 0x48
+
+#define SYS_FPGA_BLOCK 0xF0000000
+
+#define DATA_FPGA_START 0x400000
+#define DATA_FPGA_SIZE 0x80000
+
+static const char drv_name[] = "carma-fpga";
+
+#define NUM_FPGA 4
+
+#define MIN_DATA_BUFS 8
+#define MAX_DATA_BUFS 64
+
+struct fpga_info {
+ unsigned int num_lag_ram;
+ unsigned int blk_size;
+};
+
+struct data_buf {
+ struct list_head entry;
+ struct videobuf_dmabuf vb;
+ size_t size;
+};
+
+struct fpga_device {
+ /* character device */
+ struct miscdevice miscdev;
+ struct device *dev;
+ struct mutex mutex;
+
+ /* reference count */
+ struct kref ref;
+
+ /* FPGA registers and information */
+ struct fpga_info info[NUM_FPGA];
+ void __iomem *regs;
+ int irq;
+
+ /* FPGA Physical Address/Size Information */
+ resource_size_t phys_addr;
+ size_t phys_size;
+
+ /* DMA structures */
+ struct sg_table corl_table;
+ unsigned int corl_nents;
+ struct dma_chan *chan;
+
+ /* Protection for all members below */
+ spinlock_t lock;
+
+ /* Device enable/disable flag */
+ bool enabled;
+
+ /* Correlation data buffers */
+ wait_queue_head_t wait;
+ struct list_head free;
+ struct list_head used;
+ struct data_buf *inflight;
+
+ /* Information about data buffers */
+ unsigned int num_dropped;
+ unsigned int num_buffers;
+ size_t bufsize;
+ struct dentry *dbg_entry;
+};
+
+struct fpga_reader {
+ struct fpga_device *priv;
+ struct data_buf *buf;
+ off_t buf_start;
+};
+
+static void fpga_device_release(struct kref *ref)
+{
+ struct fpga_device *priv = container_of(ref, struct fpga_device, ref);
+
+ /* the last reader has exited, cleanup the last bits */
+ mutex_destroy(&priv->mutex);
+ kfree(priv);
+}
+
+/*
+ * Data Buffer Allocation Helpers
+ */
+
+/**
+ * data_free_buffer() - free a single data buffer and all allocated memory
+ * @buf: the buffer to free
+ *
+ * This will free all of the pages allocated to the given data buffer, and
+ * then free the structure itself
+ */
+static void data_free_buffer(struct data_buf *buf)
+{
+ /* It is ok to free a NULL buffer */
+ if (!buf)
+ return;
+
+ /* free all memory */
+ videobuf_dma_free(&buf->vb);
+ kfree(buf);
+}
+
+/**
+ * data_alloc_buffer() - allocate and fill a data buffer with pages
+ * @bytes: the number of bytes required
+ *
+ * This allocates all space needed for a data buffer. It must be mapped before
+ * use in a DMA transaction using videobuf_dma_map().
+ *
+ * Returns NULL on failure
+ */
+static struct data_buf *data_alloc_buffer(const size_t bytes)
+{
+ unsigned int nr_pages;
+ struct data_buf *buf;
+ int ret;
+
+ /* calculate the number of pages necessary */
+ nr_pages = DIV_ROUND_UP(bytes, PAGE_SIZE);
+
+ /* allocate the buffer structure */
+ buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+ if (!buf)
+ goto out_return;
+
+ /* initialize internal fields */
+ INIT_LIST_HEAD(&buf->entry);
+ buf->size = bytes;
+
+ /* allocate the videobuf */
+ videobuf_dma_init(&buf->vb);
+ ret = videobuf_dma_init_kernel(&buf->vb, DMA_FROM_DEVICE, nr_pages);
+ if (ret)
+ goto out_free_buf;
+
+ return buf;
+
+out_free_buf:
+ kfree(buf);
+out_return:
+ return NULL;
+}
+
+/**
+ * data_free_buffers() - free all allocated buffers
+ * @priv: the driver's private data structure
+ *
+ * Free all buffers allocated by the driver (except those currently in the
+ * process of being read by userspace).
+ *
+ * LOCKING: must hold dev->mutex
+ * CONTEXT: user
+ */
+static void data_free_buffers(struct fpga_device *priv)
+{
+ struct data_buf *buf, *tmp;
+
+ /* the device should be stopped, no DMA in progress */
+ BUG_ON(priv->inflight != NULL);
+
+ list_for_each_entry_safe(buf, tmp, &priv->free, entry) {
+ list_del_init(&buf->entry);
+ videobuf_dma_unmap(priv->dev, &buf->vb);
+ data_free_buffer(buf);
+ }
+
+ list_for_each_entry_safe(buf, tmp, &priv->used, entry) {
+ list_del_init(&buf->entry);
+ videobuf_dma_unmap(priv->dev, &buf->vb);
+ data_free_buffer(buf);
+ }
+
+ priv->num_buffers = 0;
+ priv->bufsize = 0;
+}
+
+/**
+ * data_alloc_buffers() - allocate 1 seconds worth of data buffers
+ * @priv: the driver's private data structure
+ *
+ * Allocate enough buffers for a whole second worth of data
+ *
+ * This routine will attempt to degrade nicely by succeeding even if a full
+ * second worth of data buffers could not be allocated, as long as a minimum
+ * number were allocated. In this case, it will print a message to the kernel
+ * log.
+ *
+ * The device must not be modifying any lists when this is called.
+ *
+ * CONTEXT: user
+ * LOCKING: must hold dev->mutex
+ *
+ * Returns 0 on success, -ERRNO otherwise
+ */
+static int data_alloc_buffers(struct fpga_device *priv)
+{
+ struct data_buf *buf;
+ int i, ret;
+
+ for (i = 0; i < MAX_DATA_BUFS; i++) {
+
+ /* allocate a buffer */
+ buf = data_alloc_buffer(priv->bufsize);
+ if (!buf)
+ break;
+
+ /* map it for DMA */
+ ret = videobuf_dma_map(priv->dev, &buf->vb);
+ if (ret) {
+ data_free_buffer(buf);
+ break;
+ }
+
+ /* add it to the list of free buffers */
+ list_add_tail(&buf->entry, &priv->free);
+ priv->num_buffers++;
+ }
+
+ /* Make sure we allocated the minimum required number of buffers */
+ if (priv->num_buffers < MIN_DATA_BUFS) {
+ dev_err(priv->dev, "Unable to allocate enough data buffers\n");
+ data_free_buffers(priv);
+ return -ENOMEM;
+ }
+
+ /* Warn if we are running in a degraded state, but do not fail */
+ if (priv->num_buffers < MAX_DATA_BUFS) {
+ dev_warn(priv->dev,
+ "Unable to allocate %d buffers, using %d buffers instead\n",
+ MAX_DATA_BUFS, i);
+ }
+
+ return 0;
+}
+
+/*
+ * DMA Operations Helpers
+ */
+
+/**
+ * fpga_start_addr() - get the physical address a DATA-FPGA
+ * @priv: the driver's private data structure
+ * @fpga: the DATA-FPGA number (zero based)
+ */
+static dma_addr_t fpga_start_addr(struct fpga_device *priv, unsigned int fpga)
+{
+ return priv->phys_addr + 0x400000 + (0x80000 * fpga);
+}
+
+/**
+ * fpga_block_addr() - get the physical address of a correlation data block
+ * @priv: the driver's private data structure
+ * @fpga: the DATA-FPGA number (zero based)
+ * @blknum: the correlation block number (zero based)
+ */
+static dma_addr_t fpga_block_addr(struct fpga_device *priv, unsigned int fpga,
+ unsigned int blknum)
+{
+ return fpga_start_addr(priv, fpga) + (0x10000 * (1 + blknum));
+}
+
+#define REG_BLOCK_SIZE (32 * 4)
+
+/**
+ * data_setup_corl_table() - create the scatterlist for correlation dumps
+ * @priv: the driver's private data structure
+ *
+ * Create the scatterlist for transferring a correlation dump from the
+ * DATA FPGAs. This structure will be reused for each buffer than needs
+ * to be filled with correlation data.
+ *
+ * Returns 0 on success, -ERRNO otherwise
+ */
+static int data_setup_corl_table(struct fpga_device *priv)
+{
+ struct sg_table *table = &priv->corl_table;
+ struct scatterlist *sg;
+ struct fpga_info *info;
+ int i, j, ret;
+
+ /* Calculate the number of entries needed */
+ priv->corl_nents = (1 + NUM_FPGA) * REG_BLOCK_SIZE;
+ for (i = 0; i < NUM_FPGA; i++)
+ priv->corl_nents += priv->info[i].num_lag_ram;
+
+ /* Allocate the scatterlist table */
+ ret = sg_alloc_table(table, priv->corl_nents, GFP_KERNEL);
+ if (ret) {
+ dev_err(priv->dev, "unable to allocate DMA table\n");
+ return ret;
+ }
+
+ /* Add the DATA FPGA registers to the scatterlist */
+ sg = table->sgl;
+ for (i = 0; i < NUM_FPGA; i++) {
+ sg_dma_address(sg) = fpga_start_addr(priv, i);
+ sg_dma_len(sg) = REG_BLOCK_SIZE;
+ sg = sg_next(sg);
+ }
+
+ /* Add the SYS-FPGA registers to the scatterlist */
+ sg_dma_address(sg) = SYS_FPGA_BLOCK;
+ sg_dma_len(sg) = REG_BLOCK_SIZE;
+ sg = sg_next(sg);
+
+ /* Add the FPGA correlation data blocks to the scatterlist */
+ for (i = 0; i < NUM_FPGA; i++) {
+ info = &priv->info[i];
+ for (j = 0; j < info->num_lag_ram; j++) {
+ sg_dma_address(sg) = fpga_block_addr(priv, i, j);
+ sg_dma_len(sg) = info->blk_size;
+ sg = sg_next(sg);
+ }
+ }
+
+ /*
+ * All physical addresses and lengths are present in the structure
+ * now. It can be reused for every FPGA DATA interrupt
+ */
+ return 0;
+}
+
+/*
+ * FPGA Register Access Helpers
+ */
+
+static void fpga_write_reg(struct fpga_device *priv, unsigned int fpga,
+ unsigned int reg, u32 val)
+{
+ const int fpga_start = DATA_FPGA_START + (fpga * DATA_FPGA_SIZE);
+ iowrite32be(val, priv->regs + fpga_start + reg);
+}
+
+static u32 fpga_read_reg(struct fpga_device *priv, unsigned int fpga,
+ unsigned int reg)
+{
+ const int fpga_start = DATA_FPGA_START + (fpga * DATA_FPGA_SIZE);
+ return ioread32be(priv->regs + fpga_start + reg);
+}
+
+/**
+ * data_calculate_bufsize() - calculate the data buffer size required
+ * @priv: the driver's private data structure
+ *
+ * Calculate the total buffer size needed to hold a single block
+ * of correlation data
+ *
+ * CONTEXT: user
+ *
+ * Returns 0 on success, -ERRNO otherwise
+ */
+static int data_calculate_bufsize(struct fpga_device *priv)
+{
+ u32 num_corl, num_lags, num_meta, num_qcnt, num_pack;
+ u32 conf1, conf2, version;
+ u32 num_lag_ram, blk_size;
+ int i;
+
+ /* Each buffer starts with the 5 FPGA register areas */
+ priv->bufsize = (1 + NUM_FPGA) * REG_BLOCK_SIZE;
+
+ /* Read and store the configuration data for each FPGA */
+ for (i = 0; i < NUM_FPGA; i++) {
+ version = fpga_read_reg(priv, i, MMAP_REG_VERSION);
+ conf1 = fpga_read_reg(priv, i, MMAP_REG_CORL_CONF1);
+ conf2 = fpga_read_reg(priv, i, MMAP_REG_CORL_CONF2);
+
+ /* minor version 2 and later */
+ if ((version & 0x000000FF) >= 2) {
+ num_corl = (conf1 & 0x000000F0) >> 4;
+ num_pack = (conf1 & 0x00000F00) >> 8;
+ num_lags = (conf1 & 0x00FFF000) >> 12;
+ num_meta = (conf1 & 0x7F000000) >> 24;
+ num_qcnt = (conf2 & 0x00000FFF) >> 0;
+ } else {
+ num_corl = (conf1 & 0x000000F0) >> 4;
+ num_pack = 1; /* implied */
+ num_lags = (conf1 & 0x000FFF00) >> 8;
+ num_meta = (conf1 & 0x7FF00000) >> 20;
+ num_qcnt = (conf2 & 0x00000FFF) >> 0;
+ }
+
+ num_lag_ram = (num_corl + num_pack - 1) / num_pack;
+ blk_size = ((num_pack * num_lags) + num_meta + num_qcnt) * 8;
+
+ priv->info[i].num_lag_ram = num_lag_ram;
+ priv->info[i].blk_size = blk_size;
+ priv->bufsize += num_lag_ram * blk_size;
+
+ dev_dbg(priv->dev, "FPGA %d NUM_CORL: %d\n", i, num_corl);
+ dev_dbg(priv->dev, "FPGA %d NUM_PACK: %d\n", i, num_pack);
+ dev_dbg(priv->dev, "FPGA %d NUM_LAGS: %d\n", i, num_lags);
+ dev_dbg(priv->dev, "FPGA %d NUM_META: %d\n", i, num_meta);
+ dev_dbg(priv->dev, "FPGA %d NUM_QCNT: %d\n", i, num_qcnt);
+ dev_dbg(priv->dev, "FPGA %d BLK_SIZE: %d\n", i, blk_size);
+ }
+
+ dev_dbg(priv->dev, "TOTAL BUFFER SIZE: %zu bytes\n", priv->bufsize);
+ return 0;
+}
+
+/*
+ * Interrupt Handling
+ */
+
+/**
+ * data_disable_interrupts() - stop the device from generating interrupts
+ * @priv: the driver's private data structure
+ *
+ * Hide interrupts by switching to GPIO interrupt source
+ *
+ * LOCKING: must hold dev->lock
+ */
+static void data_disable_interrupts(struct fpga_device *priv)
+{
+ /* hide the interrupt by switching the IRQ driver to GPIO */
+ iowrite32be(0x2F, priv->regs + SYS_IRQ_SOURCE_CTL);
+}
+
+/**
+ * data_enable_interrupts() - allow the device to generate interrupts
+ * @priv: the driver's private data structure
+ *
+ * Unhide interrupts by switching to the FPGA interrupt source. At the
+ * same time, clear the DATA-FPGA status registers.
+ *
+ * LOCKING: must hold dev->lock
+ */
+static void data_enable_interrupts(struct fpga_device *priv)
+{
+ /* clear the actual FPGA corl_done interrupt */
+ fpga_write_reg(priv, 0, MMAP_REG_STATUS, 0x0);
+ fpga_write_reg(priv, 1, MMAP_REG_STATUS, 0x0);
+ fpga_write_reg(priv, 2, MMAP_REG_STATUS, 0x0);
+ fpga_write_reg(priv, 3, MMAP_REG_STATUS, 0x0);
+
+ /* flush the writes */
+ fpga_read_reg(priv, 0, MMAP_REG_STATUS);
+
+ /* switch back to the external interrupt source */
+ iowrite32be(0x3F, priv->regs + SYS_IRQ_SOURCE_CTL);
+}
+
+/**
+ * data_dma_cb() - DMAEngine callback for DMA completion
+ * @data: the driver's private data structure
+ *
+ * Complete a DMA transfer from the DATA-FPGA's
+ *
+ * This is called via the DMA callback mechanism, and will handle moving the
+ * completed DMA transaction to the used list, and then wake any processes
+ * waiting for new data
+ *
+ * CONTEXT: any, softirq expected
+ */
+static void data_dma_cb(void *data)
+{
+ struct fpga_device *priv = data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* If there is no inflight buffer, we've got a bug */
+ BUG_ON(priv->inflight == NULL);
+
+ /* Move the inflight buffer onto the used list */
+ list_move_tail(&priv->inflight->entry, &priv->used);
+ priv->inflight = NULL;
+
+ /* clear the FPGA status and re-enable interrupts */
+ data_enable_interrupts(priv);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /*
+ * We've changed both the inflight and used lists, so we need
+ * to wake up any processes that are blocking for those events
+ */
+ wake_up(&priv->wait);
+}
+
+/**
+ * data_submit_dma() - prepare and submit the required DMA to fill a buffer
+ * @priv: the driver's private data structure
+ * @buf: the data buffer
+ *
+ * Prepare and submit the necessary DMA transactions to fill a correlation
+ * data buffer.
+ *
+ * LOCKING: must hold dev->lock
+ * CONTEXT: hardirq only
+ *
+ * Returns 0 on success, -ERRNO otherwise
+ */
+static int data_submit_dma(struct fpga_device *priv, struct data_buf *buf)
+{
+ struct scatterlist *dst_sg, *src_sg;
+ unsigned int dst_nents, src_nents;
+ struct dma_chan *chan = priv->chan;
+ struct dma_async_tx_descriptor *tx;
+ dma_cookie_t cookie;
+ dma_addr_t dst, src;
+
+ dst_sg = buf->vb.sglist;
+ dst_nents = buf->vb.sglen;
+
+ src_sg = priv->corl_table.sgl;
+ src_nents = priv->corl_nents;
+
+ /*
+ * All buffers passed to this function should be ready and mapped
+ * for DMA already. Therefore, we don't need to do anything except
+ * submit it to the Freescale DMA Engine for processing
+ */
+
+ /* setup the scatterlist to scatterlist transfer */
+ tx = chan->device->device_prep_dma_sg(chan,
+ dst_sg, dst_nents,
+ src_sg, src_nents,
+ 0);
+ if (!tx) {
+ dev_err(priv->dev, "unable to prep scatterlist DMA\n");
+ return -ENOMEM;
+ }
+
+ /* submit the transaction to the DMA controller */
+ cookie = tx->tx_submit(tx);
+ if (dma_submit_error(cookie)) {
+ dev_err(priv->dev, "unable to submit scatterlist DMA\n");
+ return -ENOMEM;
+ }
+
+ /* Prepare the re-read of the SYS-FPGA block */
+ dst = sg_dma_address(dst_sg) + (NUM_FPGA * REG_BLOCK_SIZE);
+ src = SYS_FPGA_BLOCK;
+ tx = chan->device->device_prep_dma_memcpy(chan, dst, src,
+ REG_BLOCK_SIZE,
+ DMA_PREP_INTERRUPT);
+ if (!tx) {
+ dev_err(priv->dev, "unable to prep SYS-FPGA DMA\n");
+ return -ENOMEM;
+ }
+
+ /* Setup the callback */
+ tx->callback = data_dma_cb;
+ tx->callback_param = priv;
+
+ /* submit the transaction to the DMA controller */
+ cookie = tx->tx_submit(tx);
+ if (dma_submit_error(cookie)) {
+ dev_err(priv->dev, "unable to submit SYS-FPGA DMA\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+#define CORL_DONE 0x1
+#define CORL_ERR 0x2
+
+static irqreturn_t data_irq(int irq, void *dev_id)
+{
+ struct fpga_device *priv = dev_id;
+ bool submitted = false;
+ struct data_buf *buf;
+ u32 status;
+ int i;
+
+ /* detect spurious interrupts via FPGA status */
+ for (i = 0; i < 4; i++) {
+ status = fpga_read_reg(priv, i, MMAP_REG_STATUS);
+ if (!(status & (CORL_DONE | CORL_ERR))) {
+ dev_err(priv->dev, "spurious irq detected (FPGA)\n");
+ return IRQ_NONE;
+ }
+ }
+
+ /* detect spurious interrupts via raw IRQ pin readback */
+ status = ioread32be(priv->regs + SYS_IRQ_INPUT_DATA);
+ if (status & IRQ_CORL_DONE) {
+ dev_err(priv->dev, "spurious irq detected (IRQ)\n");
+ return IRQ_NONE;
+ }
+
+ spin_lock(&priv->lock);
+
+ /* hide the interrupt by switching the IRQ driver to GPIO */
+ data_disable_interrupts(priv);
+
+ /* If there are no free buffers, drop this data */
+ if (list_empty(&priv->free)) {
+ priv->num_dropped++;
+ goto out;
+ }
+
+ buf = list_first_entry(&priv->free, struct data_buf, entry);
+ list_del_init(&buf->entry);
+ BUG_ON(buf->size != priv->bufsize);
+
+ /* Submit a DMA transfer to get the correlation data */
+ if (data_submit_dma(priv, buf)) {
+ dev_err(priv->dev, "Unable to setup DMA transfer\n");
+ list_move_tail(&buf->entry, &priv->free);
+ goto out;
+ }
+
+ /* Save the buffer for the DMA callback */
+ priv->inflight = buf;
+ submitted = true;
+
+ /* Start the DMA Engine */
+ dma_async_memcpy_issue_pending(priv->chan);
+
+out:
+ /* If no DMA was submitted, re-enable interrupts */
+ if (!submitted)
+ data_enable_interrupts(priv);
+
+ spin_unlock(&priv->lock);
+ return IRQ_HANDLED;
+}
+
+/*
+ * Realtime Device Enable Helpers
+ */
+
+/**
+ * data_device_enable() - enable the device for buffered dumping
+ * @priv: the driver's private data structure
+ *
+ * Enable the device for buffered dumping. Allocates buffers and hooks up
+ * the interrupt handler. When this finishes, data will come pouring in.
+ *
+ * LOCKING: must hold dev->mutex
+ * CONTEXT: user context only
+ *
+ * Returns 0 on success, -ERRNO otherwise
+ */
+static int data_device_enable(struct fpga_device *priv)
+{
+ u32 val;
+ int ret;
+
+ /* multiple enables are safe: they do nothing */
+ if (priv->enabled)
+ return 0;
+
+ /* check that the FPGAs are programmed */
+ val = ioread32be(priv->regs + SYS_FPGA_CONFIG_STATUS);
+ if (!(val & (1 << 18))) {
+ dev_err(priv->dev, "DATA-FPGAs are not enabled\n");
+ return -ENODATA;
+ }
+
+ /* read the FPGAs to calculate the buffer size */
+ ret = data_calculate_bufsize(priv);
+ if (ret) {
+ dev_err(priv->dev, "unable to calculate buffer size\n");
+ goto out_error;
+ }
+
+ /* allocate the correlation data buffers */
+ ret = data_alloc_buffers(priv);
+ if (ret) {
+ dev_err(priv->dev, "unable to allocate buffers\n");
+ goto out_error;
+ }
+
+ /* setup the source scatterlist for dumping correlation data */
+ ret = data_setup_corl_table(priv);
+ if (ret) {
+ dev_err(priv->dev, "unable to setup correlation DMA table\n");
+ goto out_error;
+ }
+
+ /* hookup the irq handler */
+ ret = request_irq(priv->irq, data_irq, IRQF_SHARED, drv_name, priv);
+ if (ret) {
+ dev_err(priv->dev, "unable to request IRQ handler\n");
+ goto out_error;
+ }
+
+ /* switch to the external FPGA IRQ line */
+ data_enable_interrupts(priv);
+
+ /* success, we're enabled */
+ priv->enabled = true;
+ return 0;
+
+out_error:
+ sg_free_table(&priv->corl_table);
+ priv->corl_nents = 0;
+
+ data_free_buffers(priv);
+ return ret;
+}
+
+/**
+ * data_device_disable() - disable the device for buffered dumping
+ * @priv: the driver's private data structure
+ *
+ * Disable the device for buffered dumping. Stops new DMA transactions from
+ * being generated, waits for all outstanding DMA to complete, and then frees
+ * all buffers.
+ *
+ * LOCKING: must hold dev->mutex
+ * CONTEXT: user only
+ *
+ * Returns 0 on success, -ERRNO otherwise
+ */
+static int data_device_disable(struct fpga_device *priv)
+{
+ int ret;
+
+ /* allow multiple disable */
+ if (!priv->enabled)
+ return 0;
+
+ /* switch to the internal GPIO IRQ line */
+ data_disable_interrupts(priv);
+
+ /* unhook the irq handler */
+ free_irq(priv->irq, priv);
+
+ /*
+ * wait for all outstanding DMA to complete
+ *
+ * Device interrupts are disabled, therefore another buffer cannot
+ * be marked inflight.
+ */
+ ret = wait_event_interruptible(priv->wait, priv->inflight == NULL);
+ if (ret)
+ return ret;
+
+ /* free the correlation table */
+ sg_free_table(&priv->corl_table);
+ priv->corl_nents = 0;
+
+ /*
+ * We are taking the spinlock not to protect priv->enabled, but instead
+ * to make sure that there are no readers in the process of altering
+ * the free or used lists while we are setting this flag.
+ */
+ spin_lock_irq(&priv->lock);
+ priv->enabled = false;
+ spin_unlock_irq(&priv->lock);
+
+ /* free all buffers: the free and used lists are not being changed */
+ data_free_buffers(priv);
+ return 0;
+}
+
+/*
+ * DEBUGFS Interface
+ */
+#ifdef CONFIG_DEBUG_FS
+
+/*
+ * Count the number of entries in the given list
+ */
+static unsigned int list_num_entries(struct list_head *list)
+{
+ struct list_head *entry;
+ unsigned int ret = 0;
+
+ list_for_each(entry, list)
+ ret++;
+
+ return ret;
+}
+
+static int data_debug_show(struct seq_file *f, void *offset)
+{
+ struct fpga_device *priv = f->private;
+ int ret;
+
+ /*
+ * Lock the mutex first, so that we get an accurate value for enable
+ * Lock the spinlock next, to get accurate list counts
+ */
+ ret = mutex_lock_interruptible(&priv->mutex);
+ if (ret)
+ return ret;
+
+ spin_lock_irq(&priv->lock);
+
+ seq_printf(f, "enabled: %d\n", priv->enabled);
+ seq_printf(f, "bufsize: %d\n", priv->bufsize);
+ seq_printf(f, "num_buffers: %d\n", priv->num_buffers);
+ seq_printf(f, "num_free: %d\n", list_num_entries(&priv->free));
+ seq_printf(f, "inflight: %d\n", priv->inflight != NULL);
+ seq_printf(f, "num_used: %d\n", list_num_entries(&priv->used));
+ seq_printf(f, "num_dropped: %d\n", priv->num_dropped);
+
+ spin_unlock_irq(&priv->lock);
+ mutex_unlock(&priv->mutex);
+ return 0;
+}
+
+static int data_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, data_debug_show, inode->i_private);
+}
+
+static const struct file_operations data_debug_fops = {
+ .owner = THIS_MODULE,
+ .open = data_debug_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int data_debugfs_init(struct fpga_device *priv)
+{
+ priv->dbg_entry = debugfs_create_file(drv_name, S_IRUGO, NULL, priv,
+ &data_debug_fops);
+ if (IS_ERR(priv->dbg_entry))
+ return PTR_ERR(priv->dbg_entry);
+
+ return 0;
+}
+
+static void data_debugfs_exit(struct fpga_device *priv)
+{
+ debugfs_remove(priv->dbg_entry);
+}
+
+#else
+
+static inline int data_debugfs_init(struct fpga_device *priv)
+{
+ return 0;
+}
+
+static inline void data_debugfs_exit(struct fpga_device *priv)
+{
+}
+
+#endif /* CONFIG_DEBUG_FS */
+
+/*
+ * SYSFS Attributes
+ */
+
+static ssize_t data_en_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct fpga_device *priv = dev_get_drvdata(dev);
+ return snprintf(buf, PAGE_SIZE, "%u\n", priv->enabled);
+}
+
+static ssize_t data_en_set(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fpga_device *priv = dev_get_drvdata(dev);
+ unsigned long enable;
+ int ret;
+
+ ret = strict_strtoul(buf, 0, &enable);
+ if (ret) {
+ dev_err(priv->dev, "unable to parse enable input\n");
+ return -EINVAL;
+ }
+
+ ret = mutex_lock_interruptible(&priv->mutex);
+ if (ret)
+ return ret;
+
+ if (enable)
+ ret = data_device_enable(priv);
+ else
+ ret = data_device_disable(priv);
+
+ if (ret) {
+ dev_err(priv->dev, "device %s failed\n",
+ enable ? "enable" : "disable");
+ count = ret;
+ goto out_unlock;
+ }
+
+out_unlock:
+ mutex_unlock(&priv->mutex);
+ return count;
+}
+
+static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO, data_en_show, data_en_set);
+
+static struct attribute *data_sysfs_attrs[] = {
+ &dev_attr_enable.attr,
+ NULL,
+};
+
+static const struct attribute_group rt_sysfs_attr_group = {
+ .attrs = data_sysfs_attrs,
+};
+
+/*
+ * FPGA Realtime Data Character Device
+ */
+
+static int data_open(struct inode *inode, struct file *filp)
+{
+ /*
+ * The miscdevice layer puts our struct miscdevice into the
+ * filp->private_data field. We use this to find our private
+ * data and then overwrite it with our own private structure.
+ */
+ struct fpga_device *priv = container_of(filp->private_data,
+ struct fpga_device, miscdev);
+ struct fpga_reader *reader;
+ int ret;
+
+ /* allocate private data */
+ reader = kzalloc(sizeof(*reader), GFP_KERNEL);
+ if (!reader)
+ return -ENOMEM;
+
+ reader->priv = priv;
+ reader->buf = NULL;
+
+ filp->private_data = reader;
+ ret = nonseekable_open(inode, filp);
+ if (ret) {
+ dev_err(priv->dev, "nonseekable-open failed\n");
+ kfree(reader);
+ return ret;
+ }
+
+ /*
+ * success, increase the reference count of the private data structure
+ * so that it doesn't disappear if the device is unbound
+ */
+ kref_get(&priv->ref);
+ return 0;
+}
+
+static int data_release(struct inode *inode, struct file *filp)
+{
+ struct fpga_reader *reader = filp->private_data;
+ struct fpga_device *priv = reader->priv;
+
+ /* free the per-reader structure */
+ data_free_buffer(reader->buf);
+ kfree(reader);
+ filp->private_data = NULL;
+
+ /* decrement our reference count to the private data */
+ kref_put(&priv->ref, fpga_device_release);
+ return 0;
+}
+
+static ssize_t data_read(struct file *filp, char __user *ubuf, size_t count,
+ loff_t *f_pos)
+{
+ struct fpga_reader *reader = filp->private_data;
+ struct fpga_device *priv = reader->priv;
+ struct list_head *used = &priv->used;
+ struct data_buf *dbuf;
+ size_t avail;
+ void *data;
+ int ret;
+
+ /* check if we already have a partial buffer */
+ if (reader->buf) {
+ dbuf = reader->buf;
+ goto have_buffer;
+ }
+
+ spin_lock_irq(&priv->lock);
+
+ /* Block until there is at least one buffer on the used list */
+ while (list_empty(used)) {
+ spin_unlock_irq(&priv->lock);
+
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ ret = wait_event_interruptible(priv->wait, !list_empty(used));
+ if (ret)
+ return ret;
+
+ spin_lock_irq(&priv->lock);
+ }
+
+ /* Grab the first buffer off of the used list */
+ dbuf = list_first_entry(used, struct data_buf, entry);
+ list_del_init(&dbuf->entry);
+
+ spin_unlock_irq(&priv->lock);
+
+ /* Buffers are always mapped: unmap it */
+ videobuf_dma_unmap(priv->dev, &dbuf->vb);
+
+ /* save the buffer for later */
+ reader->buf = dbuf;
+ reader->buf_start = 0;
+
+have_buffer:
+ /* Get the number of bytes available */
+ avail = dbuf->size - reader->buf_start;
+ data = dbuf->vb.vaddr + reader->buf_start;
+
+ /* Get the number of bytes we can transfer */
+ count = min(count, avail);
+
+ /* Copy the data to the userspace buffer */
+ if (copy_to_user(ubuf, data, count))
+ return -EFAULT;
+
+ /* Update the amount of available space */
+ avail -= count;
+
+ /*
+ * If there is still some data available, save the buffer for the
+ * next userspace call to read() and return
+ */
+ if (avail > 0) {
+ reader->buf_start += count;
+ reader->buf = dbuf;
+ return count;
+ }
+
+ /*
+ * Get the buffer ready to be reused for DMA
+ *
+ * If it fails, we pretend that the read never happed and return
+ * -EFAULT to userspace. The read will be retried.
+ */
+ ret = videobuf_dma_map(priv->dev, &dbuf->vb);
+ if (ret) {
+ dev_err(priv->dev, "unable to remap buffer for DMA\n");
+ return -EFAULT;
+ }
+
+ /* Lock against concurrent enable/disable */
+ spin_lock_irq(&priv->lock);
+
+ /* the reader is finished with this buffer */
+ reader->buf = NULL;
+
+ /*
+ * One of two things has happened, the device is disabled, or the
+ * device has been reconfigured underneath us. In either case, we
+ * should just throw away the buffer.
+ */
+ if (!priv->enabled || dbuf->size != priv->bufsize) {
+ videobuf_dma_unmap(priv->dev, &dbuf->vb);
+ data_free_buffer(dbuf);
+ goto out_unlock;
+ }
+
+ /* The buffer is safe to reuse, so add it back to the free list */
+ list_add_tail(&dbuf->entry, &priv->free);
+
+out_unlock:
+ spin_unlock_irq(&priv->lock);
+ return count;
+}
+
+static unsigned int data_poll(struct file *filp, struct poll_table_struct *tbl)
+{
+ struct fpga_reader *reader = filp->private_data;
+ struct fpga_device *priv = reader->priv;
+ unsigned int mask = 0;
+
+ poll_wait(filp, &priv->wait, tbl);
+
+ if (!list_empty(&priv->used))
+ mask |= POLLIN | POLLRDNORM;
+
+ return mask;
+}
+
+static int data_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct fpga_reader *reader = filp->private_data;
+ struct fpga_device *priv = reader->priv;
+ unsigned long offset, vsize, psize, addr;
+
+ /* VMA properties */
+ offset = vma->vm_pgoff << PAGE_SHIFT;
+ vsize = vma->vm_end - vma->vm_start;
+ psize = priv->phys_size - offset;
+ addr = (priv->phys_addr + offset) >> PAGE_SHIFT;
+
+ /* Check against the FPGA region's physical memory size */
+ if (vsize > psize) {
+ dev_err(priv->dev, "requested mmap mapping too large\n");
+ return -EINVAL;
+ }
+
+ /* IO memory (stop cacheing) */
+ vma->vm_flags |= VM_IO | VM_RESERVED;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ return io_remap_pfn_range(vma, vma->vm_start, addr, vsize,
+ vma->vm_page_prot);
+}
+
+static const struct file_operations data_fops = {
+ .owner = THIS_MODULE,
+ .open = data_open,
+ .release = data_release,
+ .read = data_read,
+ .poll = data_poll,
+ .mmap = data_mmap,
+ .llseek = no_llseek,
+};
+
+/*
+ * OpenFirmware Device Subsystem
+ */
+
+static bool dma_filter(struct dma_chan *chan, void *data)
+{
+ /*
+ * DMA Channel #0 is used for the FPGA Programmer, so ignore it
+ *
+ * This probably won't survive an unload/load cycle of the Freescale
+ * DMAEngine driver, but that won't be a problem
+ */
+ if (chan->chan_id == 0 && chan->device->dev_id == 0)
+ return false;
+
+ return true;
+}
+
+static int data_of_probe(struct platform_device *op,
+ const struct of_device_id *match)
+{
+ struct device_node *of_node = op->dev.of_node;
+ struct device *this_device;
+ struct fpga_device *priv;
+ struct resource res;
+ dma_cap_mask_t mask;
+ int ret;
+
+ /* Allocate private data */
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(&op->dev, "Unable to allocate device private data\n");
+ ret = -ENOMEM;
+ goto out_return;
+ }
+
+ dev_set_drvdata(&op->dev, priv);
+ priv->dev = &op->dev;
+ kref_init(&priv->ref);
+ mutex_init(&priv->mutex);
+
+ dev_set_drvdata(priv->dev, priv);
+ spin_lock_init(&priv->lock);
+ INIT_LIST_HEAD(&priv->free);
+ INIT_LIST_HEAD(&priv->used);
+ init_waitqueue_head(&priv->wait);
+
+ /* Setup the misc device */
+ priv->miscdev.minor = MISC_DYNAMIC_MINOR;
+ priv->miscdev.name = drv_name;
+ priv->miscdev.fops = &data_fops;
+
+ /* Get the physical address of the FPGA registers */
+ ret = of_address_to_resource(of_node, 0, &res);
+ if (ret) {
+ dev_err(&op->dev, "Unable to find FPGA physical address\n");
+ ret = -ENODEV;
+ goto out_free_priv;
+ }
+
+ priv->phys_addr = res.start;
+ priv->phys_size = resource_size(&res);
+
+ /* ioremap the registers for use */
+ priv->regs = of_iomap(of_node, 0);
+ if (!priv->regs) {
+ dev_err(&op->dev, "Unable to ioremap registers\n");
+ ret = -ENOMEM;
+ goto out_free_priv;
+ }
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_MEMCPY, mask);
+ dma_cap_set(DMA_INTERRUPT, mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ dma_cap_set(DMA_SG, mask);
+
+ /* Request a DMA channel */
+ priv->chan = dma_request_channel(mask, dma_filter, NULL);
+ if (!priv->chan) {
+ dev_err(&op->dev, "Unable to request DMA channel\n");
+ ret = -ENODEV;
+ goto out_unmap_regs;
+ }
+
+ /* Find the correct IRQ number */
+ priv->irq = irq_of_parse_and_map(of_node, 0);
+ if (priv->irq == NO_IRQ) {
+ dev_err(&op->dev, "Unable to find IRQ line\n");
+ ret = -ENODEV;
+ goto out_release_dma;
+ }
+
+ /* Drive the GPIO for FPGA IRQ high (no interrupt) */
+ iowrite32be(IRQ_CORL_DONE, priv->regs + SYS_IRQ_OUTPUT_DATA);
+
+ /* Register the miscdevice */
+ ret = misc_register(&priv->miscdev);
+ if (ret) {
+ dev_err(&op->dev, "Unable to register miscdevice\n");
+ goto out_irq_dispose_mapping;
+ }
+
+ /* Create the debugfs files */
+ ret = data_debugfs_init(priv);
+ if (ret) {
+ dev_err(&op->dev, "Unable to create debugfs files\n");
+ goto out_misc_deregister;
+ }
+
+ /* Create the sysfs files */
+ this_device = priv->miscdev.this_device;
+ dev_set_drvdata(this_device, priv);
+ ret = sysfs_create_group(&this_device->kobj, &rt_sysfs_attr_group);
+ if (ret) {
+ dev_err(&op->dev, "Unable to create sysfs files\n");
+ goto out_data_debugfs_exit;
+ }
+
+ dev_info(&op->dev, "CARMA FPGA Realtime Data Driver Loaded\n");
+ return 0;
+
+out_data_debugfs_exit:
+ data_debugfs_exit(priv);
+out_misc_deregister:
+ misc_deregister(&priv->miscdev);
+out_irq_dispose_mapping:
+ irq_dispose_mapping(priv->irq);
+out_release_dma:
+ dma_release_channel(priv->chan);
+out_unmap_regs:
+ iounmap(priv->regs);
+out_free_priv:
+ kref_put(&priv->ref, fpga_device_release);
+out_return:
+ return ret;
+}
+
+static int data_of_remove(struct platform_device *op)
+{
+ struct fpga_device *priv = dev_get_drvdata(&op->dev);
+ struct device *this_device = priv->miscdev.this_device;
+
+ /* remove all sysfs files, now the device cannot be re-enabled */
+ sysfs_remove_group(&this_device->kobj, &rt_sysfs_attr_group);
+
+ /* remove all debugfs files */
+ data_debugfs_exit(priv);
+
+ /* disable the device from generating data */
+ data_device_disable(priv);
+
+ /* remove the character device to stop new readers from appearing */
+ misc_deregister(&priv->miscdev);
+
+ /* cleanup everything not needed by readers */
+ irq_dispose_mapping(priv->irq);
+ dma_release_channel(priv->chan);
+ iounmap(priv->regs);
+
+ /* release our reference */
+ kref_put(&priv->ref, fpga_device_release);
+ return 0;
+}
+
+static struct of_device_id data_of_match[] = {
+ { .compatible = "carma,carma-fpga", },
+ {},
+};
+
+static struct of_platform_driver data_of_driver = {
+ .probe = data_of_probe,
+ .remove = data_of_remove,
+ .driver = {
+ .name = drv_name,
+ .of_match_table = data_of_match,
+ .owner = THIS_MODULE,
+ },
+};
+
+/*
+ * Module Init / Exit
+ */
+
+static int __init data_init(void)
+{
+ return of_register_platform_driver(&data_of_driver);
+}
+
+static void __exit data_exit(void)
+{
+ of_unregister_platform_driver(&data_of_driver);
+}
+
+MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>");
+MODULE_DESCRIPTION("CARMA DATA-FPGA Access Driver");
+MODULE_LICENSE("GPL");
+
+module_init(data_init);
+module_exit(data_exit);
diff --git a/drivers/misc/cs5535-mfgpt.c b/drivers/misc/cs5535-mfgpt.c
index d02d302ee6d5..e01e08c8c88b 100644
--- a/drivers/misc/cs5535-mfgpt.c
+++ b/drivers/misc/cs5535-mfgpt.c
@@ -329,7 +329,7 @@ done:
return err;
}
-static struct platform_driver cs5535_mfgpt_drv = {
+static struct platform_driver cs5535_mfgpt_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
@@ -340,7 +340,7 @@ static struct platform_driver cs5535_mfgpt_drv = {
static int __init cs5535_mfgpt_init(void)
{
- return platform_driver_register(&cs5535_mfgpt_drv);
+ return platform_driver_register(&cs5535_mfgpt_driver);
}
module_init(cs5535_mfgpt_init);
diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c
index d2d5d23416dd..89947723a27d 100644
--- a/drivers/misc/ibmasm/ibmasmfs.c
+++ b/drivers/misc/ibmasm/ibmasmfs.c
@@ -29,7 +29,7 @@
/*
* The IBMASM file virtual filesystem. It creates the following hierarchy
- * dymamically when mounted from user space:
+ * dynamically when mounted from user space:
*
* /ibmasm
* |-- 0
diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c
index 74f16f167b8e..b0c56313dbbb 100644
--- a/drivers/misc/kgdbts.c
+++ b/drivers/misc/kgdbts.c
@@ -285,33 +285,26 @@ static void hw_break_val_write(void)
static int check_and_rewind_pc(char *put_str, char *arg)
{
unsigned long addr = lookup_addr(arg);
+ unsigned long ip;
int offset = 0;
kgdb_hex2mem(&put_str[1], (char *)kgdbts_gdb_regs,
NUMREGBYTES);
gdb_regs_to_pt_regs(kgdbts_gdb_regs, &kgdbts_regs);
- v2printk("Stopped at IP: %lx\n", instruction_pointer(&kgdbts_regs));
-#ifdef CONFIG_X86
- /* On x86 a breakpoint stop requires it to be decremented */
- if (addr + 1 == kgdbts_regs.ip)
- offset = -1;
-#elif defined(CONFIG_SUPERH)
- /* On SUPERH a breakpoint stop requires it to be decremented */
- if (addr + 2 == kgdbts_regs.pc)
- offset = -2;
+ ip = instruction_pointer(&kgdbts_regs);
+ v2printk("Stopped at IP: %lx\n", ip);
+#ifdef GDB_ADJUSTS_BREAK_OFFSET
+ /* On some arches, a breakpoint stop requires it to be decremented */
+ if (addr + BREAK_INSTR_SIZE == ip)
+ offset = -BREAK_INSTR_SIZE;
#endif
- if (strcmp(arg, "silent") &&
- instruction_pointer(&kgdbts_regs) + offset != addr) {
+ if (strcmp(arg, "silent") && ip + offset != addr) {
eprintk("kgdbts: BP mismatch %lx expected %lx\n",
- instruction_pointer(&kgdbts_regs) + offset, addr);
+ ip + offset, addr);
return 1;
}
-#ifdef CONFIG_X86
- /* On x86 adjust the instruction pointer if needed */
- kgdbts_regs.ip += offset;
-#elif defined(CONFIG_SUPERH)
- kgdbts_regs.pc += offset;
-#endif
+ /* Readjust the instruction pointer if needed */
+ instruction_pointer_set(&kgdbts_regs, ip + offset);
return 0;
}
diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c
index a19cb710a246..5fe79df44838 100644
--- a/drivers/misc/pch_phub.c
+++ b/drivers/misc/pch_phub.c
@@ -34,12 +34,18 @@
#define PHUB_TIMEOUT 0x05 /* Time out value for Status Register */
#define PCH_PHUB_ROM_WRITE_ENABLE 0x01 /* Enabling for writing ROM */
#define PCH_PHUB_ROM_WRITE_DISABLE 0x00 /* Disabling for writing ROM */
-#define PCH_PHUB_MAC_START_ADDR 0x20C /* MAC data area start address offset */
-#define PCH_PHUB_ROM_START_ADDR_EG20T 0x14 /* ROM data area start address offset
+#define PCH_PHUB_MAC_START_ADDR_EG20T 0x14 /* MAC data area start address
+ offset */
+#define PCH_PHUB_MAC_START_ADDR_ML7223 0x20C /* MAC data area start address
+ offset */
+#define PCH_PHUB_ROM_START_ADDR_EG20T 0x80 /* ROM data area start address offset
(Intel EG20T PCH)*/
#define PCH_PHUB_ROM_START_ADDR_ML7213 0x400 /* ROM data area start address
offset(OKI SEMICONDUCTOR ML7213)
*/
+#define PCH_PHUB_ROM_START_ADDR_ML7223 0x400 /* ROM data area start address
+ offset(OKI SEMICONDUCTOR ML7223)
+ */
/* MAX number of INT_REDUCE_CONTROL registers */
#define MAX_NUM_INT_REDUCE_CONTROL_REG 128
@@ -63,6 +69,10 @@
#define PCI_VENDOR_ID_ROHM 0x10db
#define PCI_DEVICE_ID_ROHM_ML7213_PHUB 0x801A
+/* Macros for ML7223 */
+#define PCI_DEVICE_ID_ROHM_ML7223_mPHUB 0x8012 /* for Bus-m */
+#define PCI_DEVICE_ID_ROHM_ML7223_nPHUB 0x8002 /* for Bus-n */
+
/* SROM ACCESS Macro */
#define PCH_WORD_ADDR_MASK (~((1 << 2) - 1))
@@ -100,6 +110,9 @@
* @clkcfg_reg: CLK CFG register val
* @pch_phub_base_address: Register base address
* @pch_phub_extrom_base_address: external rom base address
+ * @pch_mac_start_address: MAC address area start address
+ * @pch_opt_rom_start_address: Option ROM start address
+ * @ioh_type: Save IOH type
*/
struct pch_phub_reg {
u32 phub_id_reg;
@@ -117,6 +130,9 @@ struct pch_phub_reg {
u32 clkcfg_reg;
void __iomem *pch_phub_base_address;
void __iomem *pch_phub_extrom_base_address;
+ u32 pch_mac_start_address;
+ u32 pch_opt_rom_start_address;
+ int ioh_type;
};
/* SROM SPEC for MAC address assignment offset */
@@ -319,7 +335,7 @@ static void pch_phub_read_serial_rom_val(struct pch_phub_reg *chip,
{
unsigned int mem_addr;
- mem_addr = PCH_PHUB_ROM_START_ADDR_EG20T +
+ mem_addr = chip->pch_mac_start_address +
pch_phub_mac_offset[offset_address];
pch_phub_read_serial_rom(chip, mem_addr, data);
@@ -336,7 +352,7 @@ static int pch_phub_write_serial_rom_val(struct pch_phub_reg *chip,
int retval;
unsigned int mem_addr;
- mem_addr = PCH_PHUB_ROM_START_ADDR_EG20T +
+ mem_addr = chip->pch_mac_start_address +
pch_phub_mac_offset[offset_address];
retval = pch_phub_write_serial_rom(chip, mem_addr, data);
@@ -384,6 +400,48 @@ static int pch_phub_gbe_serial_rom_conf(struct pch_phub_reg *chip)
return retval;
}
+/* pch_phub_gbe_serial_rom_conf_mp - makes SerialROM header format configuration
+ * for Gigabit Ethernet MAC address
+ */
+static int pch_phub_gbe_serial_rom_conf_mp(struct pch_phub_reg *chip)
+{
+ int retval;
+ u32 offset_addr;
+
+ offset_addr = 0x200;
+ retval = pch_phub_write_serial_rom(chip, 0x03 + offset_addr, 0xbc);
+ retval |= pch_phub_write_serial_rom(chip, 0x02 + offset_addr, 0x00);
+ retval |= pch_phub_write_serial_rom(chip, 0x01 + offset_addr, 0x40);
+ retval |= pch_phub_write_serial_rom(chip, 0x00 + offset_addr, 0x02);
+
+ retval |= pch_phub_write_serial_rom(chip, 0x07 + offset_addr, 0x00);
+ retval |= pch_phub_write_serial_rom(chip, 0x06 + offset_addr, 0x00);
+ retval |= pch_phub_write_serial_rom(chip, 0x05 + offset_addr, 0x00);
+ retval |= pch_phub_write_serial_rom(chip, 0x04 + offset_addr, 0x80);
+
+ retval |= pch_phub_write_serial_rom(chip, 0x0b + offset_addr, 0xbc);
+ retval |= pch_phub_write_serial_rom(chip, 0x0a + offset_addr, 0x00);
+ retval |= pch_phub_write_serial_rom(chip, 0x09 + offset_addr, 0x40);
+ retval |= pch_phub_write_serial_rom(chip, 0x08 + offset_addr, 0x18);
+
+ retval |= pch_phub_write_serial_rom(chip, 0x13 + offset_addr, 0xbc);
+ retval |= pch_phub_write_serial_rom(chip, 0x12 + offset_addr, 0x00);
+ retval |= pch_phub_write_serial_rom(chip, 0x11 + offset_addr, 0x40);
+ retval |= pch_phub_write_serial_rom(chip, 0x10 + offset_addr, 0x19);
+
+ retval |= pch_phub_write_serial_rom(chip, 0x1b + offset_addr, 0xbc);
+ retval |= pch_phub_write_serial_rom(chip, 0x1a + offset_addr, 0x00);
+ retval |= pch_phub_write_serial_rom(chip, 0x19 + offset_addr, 0x40);
+ retval |= pch_phub_write_serial_rom(chip, 0x18 + offset_addr, 0x3a);
+
+ retval |= pch_phub_write_serial_rom(chip, 0x1f + offset_addr, 0x01);
+ retval |= pch_phub_write_serial_rom(chip, 0x1e + offset_addr, 0x00);
+ retval |= pch_phub_write_serial_rom(chip, 0x1d + offset_addr, 0x00);
+ retval |= pch_phub_write_serial_rom(chip, 0x1c + offset_addr, 0x00);
+
+ return retval;
+}
+
/**
* pch_phub_read_gbe_mac_addr() - Read Gigabit Ethernet MAC address
* @offset_address: Gigabit Ethernet MAC address offset value.
@@ -406,7 +464,10 @@ static int pch_phub_write_gbe_mac_addr(struct pch_phub_reg *chip, u8 *data)
int retval;
int i;
- retval = pch_phub_gbe_serial_rom_conf(chip);
+ if (chip->ioh_type == 1) /* EG20T */
+ retval = pch_phub_gbe_serial_rom_conf(chip);
+ else /* ML7223 */
+ retval = pch_phub_gbe_serial_rom_conf_mp(chip);
if (retval)
return retval;
@@ -441,12 +502,16 @@ static ssize_t pch_phub_bin_read(struct file *filp, struct kobject *kobj,
}
/* Get Rom signature */
- pch_phub_read_serial_rom(chip, 0x80, (unsigned char *)&rom_signature);
+ pch_phub_read_serial_rom(chip, chip->pch_opt_rom_start_address,
+ (unsigned char *)&rom_signature);
rom_signature &= 0xff;
- pch_phub_read_serial_rom(chip, 0x81, (unsigned char *)&tmp);
+ pch_phub_read_serial_rom(chip, chip->pch_opt_rom_start_address + 1,
+ (unsigned char *)&tmp);
rom_signature |= (tmp & 0xff) << 8;
if (rom_signature == 0xAA55) {
- pch_phub_read_serial_rom(chip, 0x82, &rom_length);
+ pch_phub_read_serial_rom(chip,
+ chip->pch_opt_rom_start_address + 2,
+ &rom_length);
orom_size = rom_length * 512;
if (orom_size < off) {
addr_offset = 0;
@@ -458,8 +523,9 @@ static ssize_t pch_phub_bin_read(struct file *filp, struct kobject *kobj,
}
for (addr_offset = 0; addr_offset < count; addr_offset++) {
- pch_phub_read_serial_rom(chip, 0x80 + addr_offset + off,
- &buf[addr_offset]);
+ pch_phub_read_serial_rom(chip,
+ chip->pch_opt_rom_start_address + addr_offset + off,
+ &buf[addr_offset]);
}
} else {
err = -ENODATA;
@@ -502,8 +568,9 @@ static ssize_t pch_phub_bin_write(struct file *filp, struct kobject *kobj,
if (PCH_PHUB_OROM_SIZE < off + addr_offset)
goto return_ok;
- ret = pch_phub_write_serial_rom(chip, 0x80 + addr_offset + off,
- buf[addr_offset]);
+ ret = pch_phub_write_serial_rom(chip,
+ chip->pch_opt_rom_start_address + addr_offset + off,
+ buf[addr_offset]);
if (ret) {
err = ret;
goto return_err;
@@ -603,19 +670,22 @@ static int __devinit pch_phub_probe(struct pci_dev *pdev,
dev_dbg(&pdev->dev, "%s : pci_iomap SUCCESS and value "
"in pch_phub_base_address variable is %p\n", __func__,
chip->pch_phub_base_address);
- chip->pch_phub_extrom_base_address = pci_map_rom(pdev, &rom_size);
- if (chip->pch_phub_extrom_base_address == 0) {
- dev_err(&pdev->dev, "%s : pci_map_rom FAILED", __func__);
- ret = -ENOMEM;
- goto err_pci_map;
+ if (id->driver_data != 3) {
+ chip->pch_phub_extrom_base_address =\
+ pci_map_rom(pdev, &rom_size);
+ if (chip->pch_phub_extrom_base_address == 0) {
+ dev_err(&pdev->dev, "%s: pci_map_rom FAILED", __func__);
+ ret = -ENOMEM;
+ goto err_pci_map;
+ }
+ dev_dbg(&pdev->dev, "%s : "
+ "pci_map_rom SUCCESS and value in "
+ "pch_phub_extrom_base_address variable is %p\n",
+ __func__, chip->pch_phub_extrom_base_address);
}
- dev_dbg(&pdev->dev, "%s : "
- "pci_map_rom SUCCESS and value in "
- "pch_phub_extrom_base_address variable is %p\n", __func__,
- chip->pch_phub_extrom_base_address);
- if (id->driver_data == 1) {
+ if (id->driver_data == 1) { /* EG20T PCH */
retval = sysfs_create_file(&pdev->dev.kobj,
&dev_attr_pch_mac.attr);
if (retval)
@@ -642,7 +712,9 @@ static int __devinit pch_phub_probe(struct pci_dev *pdev,
iowrite32(0x000affaa, chip->pch_phub_base_address + 0x14);
/* set the interrupt delay value */
iowrite32(0x25, chip->pch_phub_base_address + 0x44);
- } else if (id->driver_data == 2) {
+ chip->pch_opt_rom_start_address = PCH_PHUB_ROM_START_ADDR_EG20T;
+ chip->pch_mac_start_address = PCH_PHUB_MAC_START_ADDR_EG20T;
+ } else if (id->driver_data == 2) { /* ML7213 IOH */
retval = sysfs_create_bin_file(&pdev->dev.kobj, &pch_bin_attr);
if (retval)
goto err_sysfs_create;
@@ -653,7 +725,38 @@ static int __devinit pch_phub_probe(struct pci_dev *pdev,
* Device8(USB OHCI #0/ USB EHCI #0):a
*/
iowrite32(0x000affa0, chip->pch_phub_base_address + 0x14);
+ chip->pch_opt_rom_start_address =\
+ PCH_PHUB_ROM_START_ADDR_ML7213;
+ } else if (id->driver_data == 3) { /* ML7223 IOH Bus-m*/
+ /* set the prefech value
+ * Device8(GbE)
+ */
+ iowrite32(0x000a0000, chip->pch_phub_base_address + 0x14);
+ chip->pch_opt_rom_start_address =\
+ PCH_PHUB_ROM_START_ADDR_ML7223;
+ chip->pch_mac_start_address = PCH_PHUB_MAC_START_ADDR_ML7223;
+ } else if (id->driver_data == 4) { /* ML7223 IOH Bus-n*/
+ retval = sysfs_create_file(&pdev->dev.kobj,
+ &dev_attr_pch_mac.attr);
+ if (retval)
+ goto err_sysfs_create;
+ retval = sysfs_create_bin_file(&pdev->dev.kobj, &pch_bin_attr);
+ if (retval)
+ goto exit_bin_attr;
+ /* set the prefech value
+ * Device2(USB OHCI #0,1,2,3/ USB EHCI #0):a
+ * Device4(SDIO #0,1):f
+ * Device6(SATA 2):f
+ */
+ iowrite32(0x0000ffa0, chip->pch_phub_base_address + 0x14);
+ /* set the interrupt delay value */
+ iowrite32(0x25, chip->pch_phub_base_address + 0x140);
+ chip->pch_opt_rom_start_address =\
+ PCH_PHUB_ROM_START_ADDR_ML7223;
+ chip->pch_mac_start_address = PCH_PHUB_MAC_START_ADDR_ML7223;
}
+
+ chip->ioh_type = id->driver_data;
pci_set_drvdata(pdev, chip);
return 0;
@@ -733,6 +836,8 @@ static int pch_phub_resume(struct pci_dev *pdev)
static struct pci_device_id pch_phub_pcidev_id[] = {
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH1_PHUB), 1, },
{ PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7213_PHUB), 2, },
+ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7223_mPHUB), 3, },
+ { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7223_nPHUB), 4, },
{ }
};
MODULE_DEVICE_TABLE(pci, pch_phub_pcidev_id);
@@ -759,5 +864,5 @@ static void __exit pch_phub_pci_exit(void)
module_init(pch_phub_pci_init);
module_exit(pch_phub_pci_exit);
-MODULE_DESCRIPTION("PCH Packet Hub PCI Driver");
+MODULE_DESCRIPTION("Intel EG20T PCH/OKI SEMICONDUCTOR IOH(ML7213/ML7223) PHUB");
MODULE_LICENSE("GPL");
diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c
new file mode 100644
index 000000000000..bb6f9255c17c
--- /dev/null
+++ b/drivers/misc/pti.c
@@ -0,0 +1,980 @@
+/*
+ * pti.c - PTI driver for cJTAG data extration
+ *
+ * Copyright (C) Intel 2010
+ *
+ * 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * The PTI (Parallel Trace Interface) driver directs trace data routed from
+ * various parts in the system out through the Intel Penwell PTI port and
+ * out of the mobile device for analysis with a debugging tool
+ * (Lauterbach, Fido). This is part of a solution for the MIPI P1149.7,
+ * compact JTAG, standard.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/console.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/pci.h>
+#include <linux/mutex.h>
+#include <linux/miscdevice.h>
+#include <linux/pti.h>
+
+#define DRIVERNAME "pti"
+#define PCINAME "pciPTI"
+#define TTYNAME "ttyPTI"
+#define CHARNAME "pti"
+#define PTITTY_MINOR_START 0
+#define PTITTY_MINOR_NUM 2
+#define MAX_APP_IDS 16 /* 128 channel ids / u8 bit size */
+#define MAX_OS_IDS 16 /* 128 channel ids / u8 bit size */
+#define MAX_MODEM_IDS 16 /* 128 channel ids / u8 bit size */
+#define MODEM_BASE_ID 71 /* modem master ID address */
+#define CONTROL_ID 72 /* control master ID address */
+#define CONSOLE_ID 73 /* console master ID address */
+#define OS_BASE_ID 74 /* base OS master ID address */
+#define APP_BASE_ID 80 /* base App master ID address */
+#define CONTROL_FRAME_LEN 32 /* PTI control frame maximum size */
+#define USER_COPY_SIZE 8192 /* 8Kb buffer for user space copy */
+#define APERTURE_14 0x3800000 /* offset to first OS write addr */
+#define APERTURE_LEN 0x400000 /* address length */
+
+struct pti_tty {
+ struct pti_masterchannel *mc;
+};
+
+struct pti_dev {
+ struct tty_port port;
+ unsigned long pti_addr;
+ unsigned long aperture_base;
+ void __iomem *pti_ioaddr;
+ u8 ia_app[MAX_APP_IDS];
+ u8 ia_os[MAX_OS_IDS];
+ u8 ia_modem[MAX_MODEM_IDS];
+};
+
+/*
+ * This protects access to ia_app, ia_os, and ia_modem,
+ * which keeps track of channels allocated in
+ * an aperture write id.
+ */
+static DEFINE_MUTEX(alloclock);
+
+static struct pci_device_id pci_ids[] __devinitconst = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x82B)},
+ {0}
+};
+
+static struct tty_driver *pti_tty_driver;
+static struct pti_dev *drv_data;
+
+static unsigned int pti_console_channel;
+static unsigned int pti_control_channel;
+
+/**
+ * pti_write_to_aperture()- The private write function to PTI HW.
+ *
+ * @mc: The 'aperture'. It's part of a write address that holds
+ * a master and channel ID.
+ * @buf: Data being written to the HW that will ultimately be seen
+ * in a debugging tool (Fido, Lauterbach).
+ * @len: Size of buffer.
+ *
+ * Since each aperture is specified by a unique
+ * master/channel ID, no two processes will be writing
+ * to the same aperture at the same time so no lock is required. The
+ * PTI-Output agent will send these out in the order that they arrived, and
+ * thus, it will intermix these messages. The debug tool can then later
+ * regroup the appropriate message segments together reconstituting each
+ * message.
+ */
+static void pti_write_to_aperture(struct pti_masterchannel *mc,
+ u8 *buf,
+ int len)
+{
+ int dwordcnt;
+ int final;
+ int i;
+ u32 ptiword;
+ u32 __iomem *aperture;
+ u8 *p = buf;
+
+ /*
+ * calculate the aperture offset from the base using the master and
+ * channel id's.
+ */
+ aperture = drv_data->pti_ioaddr + (mc->master << 15)
+ + (mc->channel << 8);
+
+ dwordcnt = len >> 2;
+ final = len - (dwordcnt << 2); /* final = trailing bytes */
+ if (final == 0 && dwordcnt != 0) { /* always need a final dword */
+ final += 4;
+ dwordcnt--;
+ }
+
+ for (i = 0; i < dwordcnt; i++) {
+ ptiword = be32_to_cpu(*(u32 *)p);
+ p += 4;
+ iowrite32(ptiword, aperture);
+ }
+
+ aperture += PTI_LASTDWORD_DTS; /* adding DTS signals that is EOM */
+
+ ptiword = 0;
+ for (i = 0; i < final; i++)
+ ptiword |= *p++ << (24-(8*i));
+
+ iowrite32(ptiword, aperture);
+ return;
+}
+
+/**
+ * pti_control_frame_built_and_sent()- control frame build and send function.
+ *
+ * @mc: The master / channel structure on which the function
+ * built a control frame.
+ *
+ * To be able to post process the PTI contents on host side, a control frame
+ * is added before sending any PTI content. So the host side knows on
+ * each PTI frame the name of the thread using a dedicated master / channel.
+ * The thread name is retrieved from the 'current' global variable.
+ * This function builds this frame and sends it to a master ID CONTROL_ID.
+ * The overhead is only 32 bytes since the driver only writes to HW
+ * in 32 byte chunks.
+ */
+
+static void pti_control_frame_built_and_sent(struct pti_masterchannel *mc)
+{
+ struct pti_masterchannel mccontrol = {.master = CONTROL_ID,
+ .channel = 0};
+ const char *control_format = "%3d %3d %s";
+ u8 control_frame[CONTROL_FRAME_LEN];
+
+ /*
+ * Since we access the comm member in current's task_struct,
+ * we only need to be as large as what 'comm' in that
+ * structure is.
+ */
+ char comm[TASK_COMM_LEN];
+
+ if (!in_interrupt())
+ get_task_comm(comm, current);
+ else
+ strncpy(comm, "Interrupt", TASK_COMM_LEN);
+
+ /* Absolutely ensure our buffer is zero terminated. */
+ comm[TASK_COMM_LEN-1] = 0;
+
+ mccontrol.channel = pti_control_channel;
+ pti_control_channel = (pti_control_channel + 1) & 0x7f;
+
+ snprintf(control_frame, CONTROL_FRAME_LEN, control_format, mc->master,
+ mc->channel, comm);
+ pti_write_to_aperture(&mccontrol, control_frame, strlen(control_frame));
+}
+
+/**
+ * pti_write_full_frame_to_aperture()- high level function to
+ * write to PTI.
+ *
+ * @mc: The 'aperture'. It's part of a write address that holds
+ * a master and channel ID.
+ * @buf: Data being written to the HW that will ultimately be seen
+ * in a debugging tool (Fido, Lauterbach).
+ * @len: Size of buffer.
+ *
+ * All threads sending data (either console, user space application, ...)
+ * are calling the high level function to write to PTI meaning that it is
+ * possible to add a control frame before sending the content.
+ */
+static void pti_write_full_frame_to_aperture(struct pti_masterchannel *mc,
+ const unsigned char *buf,
+ int len)
+{
+ pti_control_frame_built_and_sent(mc);
+ pti_write_to_aperture(mc, (u8 *)buf, len);
+}
+
+/**
+ * get_id()- Allocate a master and channel ID.
+ *
+ * @id_array: an array of bits representing what channel
+ * id's are allocated for writing.
+ * @max_ids: The max amount of available write IDs to use.
+ * @base_id: The starting SW channel ID, based on the Intel
+ * PTI arch.
+ *
+ * Returns:
+ * pti_masterchannel struct with master, channel ID address
+ * 0 for error
+ *
+ * Each bit in the arrays ia_app and ia_os correspond to a master and
+ * channel id. The bit is one if the id is taken and 0 if free. For
+ * every master there are 128 channel id's.
+ */
+static struct pti_masterchannel *get_id(u8 *id_array, int max_ids, int base_id)
+{
+ struct pti_masterchannel *mc;
+ int i, j, mask;
+
+ mc = kmalloc(sizeof(struct pti_masterchannel), GFP_KERNEL);
+ if (mc == NULL)
+ return NULL;
+
+ /* look for a byte with a free bit */
+ for (i = 0; i < max_ids; i++)
+ if (id_array[i] != 0xff)
+ break;
+ if (i == max_ids) {
+ kfree(mc);
+ return NULL;
+ }
+ /* find the bit in the 128 possible channel opportunities */
+ mask = 0x80;
+ for (j = 0; j < 8; j++) {
+ if ((id_array[i] & mask) == 0)
+ break;
+ mask >>= 1;
+ }
+
+ /* grab it */
+ id_array[i] |= mask;
+ mc->master = base_id;
+ mc->channel = ((i & 0xf)<<3) + j;
+ /* write new master Id / channel Id allocation to channel control */
+ pti_control_frame_built_and_sent(mc);
+ return mc;
+}
+
+/*
+ * The following three functions:
+ * pti_request_mastercahannel(), mipi_release_masterchannel()
+ * and pti_writedata() are an API for other kernel drivers to
+ * access PTI.
+ */
+
+/**
+ * pti_request_masterchannel()- Kernel API function used to allocate
+ * a master, channel ID address
+ * to write to PTI HW.
+ *
+ * @type: 0- request Application master, channel aperture ID write address.
+ * 1- request OS master, channel aperture ID write
+ * address.
+ * 2- request Modem master, channel aperture ID
+ * write address.
+ * Other values, error.
+ *
+ * Returns:
+ * pti_masterchannel struct
+ * 0 for error
+ */
+struct pti_masterchannel *pti_request_masterchannel(u8 type)
+{
+ struct pti_masterchannel *mc;
+
+ mutex_lock(&alloclock);
+
+ switch (type) {
+
+ case 0:
+ mc = get_id(drv_data->ia_app, MAX_APP_IDS, APP_BASE_ID);
+ break;
+
+ case 1:
+ mc = get_id(drv_data->ia_os, MAX_OS_IDS, OS_BASE_ID);
+ break;
+
+ case 2:
+ mc = get_id(drv_data->ia_modem, MAX_MODEM_IDS, MODEM_BASE_ID);
+ break;
+ default:
+ mc = NULL;
+ }
+
+ mutex_unlock(&alloclock);
+ return mc;
+}
+EXPORT_SYMBOL_GPL(pti_request_masterchannel);
+
+/**
+ * pti_release_masterchannel()- Kernel API function used to release
+ * a master, channel ID address
+ * used to write to PTI HW.
+ *
+ * @mc: master, channel apeture ID address to be released.
+ */
+void pti_release_masterchannel(struct pti_masterchannel *mc)
+{
+ u8 master, channel, i;
+
+ mutex_lock(&alloclock);
+
+ if (mc) {
+ master = mc->master;
+ channel = mc->channel;
+
+ if (master == APP_BASE_ID) {
+ i = channel >> 3;
+ drv_data->ia_app[i] &= ~(0x80>>(channel & 0x7));
+ } else if (master == OS_BASE_ID) {
+ i = channel >> 3;
+ drv_data->ia_os[i] &= ~(0x80>>(channel & 0x7));
+ } else {
+ i = channel >> 3;
+ drv_data->ia_modem[i] &= ~(0x80>>(channel & 0x7));
+ }
+
+ kfree(mc);
+ }
+
+ mutex_unlock(&alloclock);
+}
+EXPORT_SYMBOL_GPL(pti_release_masterchannel);
+
+/**
+ * pti_writedata()- Kernel API function used to write trace
+ * debugging data to PTI HW.
+ *
+ * @mc: Master, channel aperture ID address to write to.
+ * Null value will return with no write occurring.
+ * @buf: Trace debuging data to write to the PTI HW.
+ * Null value will return with no write occurring.
+ * @count: Size of buf. Value of 0 or a negative number will
+ * return with no write occuring.
+ */
+void pti_writedata(struct pti_masterchannel *mc, u8 *buf, int count)
+{
+ /*
+ * since this function is exported, this is treated like an
+ * API function, thus, all parameters should
+ * be checked for validity.
+ */
+ if ((mc != NULL) && (buf != NULL) && (count > 0))
+ pti_write_to_aperture(mc, buf, count);
+ return;
+}
+EXPORT_SYMBOL_GPL(pti_writedata);
+
+/**
+ * pti_pci_remove()- Driver exit method to remove PTI from
+ * PCI bus.
+ * @pdev: variable containing pci info of PTI.
+ */
+static void __devexit pti_pci_remove(struct pci_dev *pdev)
+{
+ struct pti_dev *drv_data;
+
+ drv_data = pci_get_drvdata(pdev);
+ if (drv_data != NULL) {
+ pci_iounmap(pdev, drv_data->pti_ioaddr);
+ pci_set_drvdata(pdev, NULL);
+ kfree(drv_data);
+ pci_release_region(pdev, 1);
+ pci_disable_device(pdev);
+ }
+}
+
+/*
+ * for the tty_driver_*() basic function descriptions, see tty_driver.h.
+ * Specific header comments made for PTI-related specifics.
+ */
+
+/**
+ * pti_tty_driver_open()- Open an Application master, channel aperture
+ * ID to the PTI device via tty device.
+ *
+ * @tty: tty interface.
+ * @filp: filp interface pased to tty_port_open() call.
+ *
+ * Returns:
+ * int, 0 for success
+ * otherwise, fail value
+ *
+ * The main purpose of using the tty device interface is for
+ * each tty port to have a unique PTI write aperture. In an
+ * example use case, ttyPTI0 gets syslogd and an APP aperture
+ * ID and ttyPTI1 is where the n_tracesink ldisc hooks to route
+ * modem messages into PTI. Modem trace data does not have to
+ * go to ttyPTI1, but ttyPTI0 and ttyPTI1 do need to be distinct
+ * master IDs. These messages go through the PTI HW and out of
+ * the handheld platform and to the Fido/Lauterbach device.
+ */
+static int pti_tty_driver_open(struct tty_struct *tty, struct file *filp)
+{
+ /*
+ * we actually want to allocate a new channel per open, per
+ * system arch. HW gives more than plenty channels for a single
+ * system task to have its own channel to write trace data. This
+ * also removes a locking requirement for the actual write
+ * procedure.
+ */
+ return tty_port_open(&drv_data->port, tty, filp);
+}
+
+/**
+ * pti_tty_driver_close()- close tty device and release Application
+ * master, channel aperture ID to the PTI device via tty device.
+ *
+ * @tty: tty interface.
+ * @filp: filp interface pased to tty_port_close() call.
+ *
+ * The main purpose of using the tty device interface is to route
+ * syslog daemon messages to the PTI HW and out of the handheld platform
+ * and to the Fido/Lauterbach device.
+ */
+static void pti_tty_driver_close(struct tty_struct *tty, struct file *filp)
+{
+ tty_port_close(&drv_data->port, tty, filp);
+}
+
+/**
+ * pti_tty_intstall()- Used to set up specific master-channels
+ * to tty ports for organizational purposes when
+ * tracing viewed from debuging tools.
+ *
+ * @driver: tty driver information.
+ * @tty: tty struct containing pti information.
+ *
+ * Returns:
+ * 0 for success
+ * otherwise, error
+ */
+static int pti_tty_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+ int idx = tty->index;
+ struct pti_tty *pti_tty_data;
+ int ret = tty_init_termios(tty);
+
+ if (ret == 0) {
+ tty_driver_kref_get(driver);
+ tty->count++;
+ driver->ttys[idx] = tty;
+
+ pti_tty_data = kmalloc(sizeof(struct pti_tty), GFP_KERNEL);
+ if (pti_tty_data == NULL)
+ return -ENOMEM;
+
+ if (idx == PTITTY_MINOR_START)
+ pti_tty_data->mc = pti_request_masterchannel(0);
+ else
+ pti_tty_data->mc = pti_request_masterchannel(2);
+
+ if (pti_tty_data->mc == NULL)
+ return -ENXIO;
+ tty->driver_data = pti_tty_data;
+ }
+
+ return ret;
+}
+
+/**
+ * pti_tty_cleanup()- Used to de-allocate master-channel resources
+ * tied to tty's of this driver.
+ *
+ * @tty: tty struct containing pti information.
+ */
+static void pti_tty_cleanup(struct tty_struct *tty)
+{
+ struct pti_tty *pti_tty_data = tty->driver_data;
+ if (pti_tty_data == NULL)
+ return;
+ pti_release_masterchannel(pti_tty_data->mc);
+ kfree(tty->driver_data);
+ tty->driver_data = NULL;
+}
+
+/**
+ * pti_tty_driver_write()- Write trace debugging data through the char
+ * interface to the PTI HW. Part of the misc device implementation.
+ *
+ * @filp: Contains private data which is used to obtain
+ * master, channel write ID.
+ * @data: trace data to be written.
+ * @len: # of byte to write.
+ *
+ * Returns:
+ * int, # of bytes written
+ * otherwise, error
+ */
+static int pti_tty_driver_write(struct tty_struct *tty,
+ const unsigned char *buf, int len)
+{
+ struct pti_tty *pti_tty_data = tty->driver_data;
+ if ((pti_tty_data != NULL) && (pti_tty_data->mc != NULL)) {
+ pti_write_to_aperture(pti_tty_data->mc, (u8 *)buf, len);
+ return len;
+ }
+ /*
+ * we can't write to the pti hardware if the private driver_data
+ * and the mc address is not there.
+ */
+ else
+ return -EFAULT;
+}
+
+/**
+ * pti_tty_write_room()- Always returns 2048.
+ *
+ * @tty: contains tty info of the pti driver.
+ */
+static int pti_tty_write_room(struct tty_struct *tty)
+{
+ return 2048;
+}
+
+/**
+ * pti_char_open()- Open an Application master, channel aperture
+ * ID to the PTI device. Part of the misc device implementation.
+ *
+ * @inode: not used.
+ * @filp: Output- will have a masterchannel struct set containing
+ * the allocated application PTI aperture write address.
+ *
+ * Returns:
+ * int, 0 for success
+ * otherwise, a fail value
+ */
+static int pti_char_open(struct inode *inode, struct file *filp)
+{
+ struct pti_masterchannel *mc;
+
+ /*
+ * We really do want to fail immediately if
+ * pti_request_masterchannel() fails,
+ * before assigning the value to filp->private_data.
+ * Slightly easier to debug if this driver needs debugging.
+ */
+ mc = pti_request_masterchannel(0);
+ if (mc == NULL)
+ return -ENOMEM;
+ filp->private_data = mc;
+ return 0;
+}
+
+/**
+ * pti_char_release()- Close a char channel to the PTI device. Part
+ * of the misc device implementation.
+ *
+ * @inode: Not used in this implementaiton.
+ * @filp: Contains private_data that contains the master, channel
+ * ID to be released by the PTI device.
+ *
+ * Returns:
+ * always 0
+ */
+static int pti_char_release(struct inode *inode, struct file *filp)
+{
+ pti_release_masterchannel(filp->private_data);
+ kfree(filp->private_data);
+ return 0;
+}
+
+/**
+ * pti_char_write()- Write trace debugging data through the char
+ * interface to the PTI HW. Part of the misc device implementation.
+ *
+ * @filp: Contains private data which is used to obtain
+ * master, channel write ID.
+ * @data: trace data to be written.
+ * @len: # of byte to write.
+ * @ppose: Not used in this function implementation.
+ *
+ * Returns:
+ * int, # of bytes written
+ * otherwise, error value
+ *
+ * Notes: From side discussions with Alan Cox and experimenting
+ * with PTI debug HW like Nokia's Fido box and Lauterbach
+ * devices, 8192 byte write buffer used by USER_COPY_SIZE was
+ * deemed an appropriate size for this type of usage with
+ * debugging HW.
+ */
+static ssize_t pti_char_write(struct file *filp, const char __user *data,
+ size_t len, loff_t *ppose)
+{
+ struct pti_masterchannel *mc;
+ void *kbuf;
+ const char __user *tmp;
+ size_t size = USER_COPY_SIZE;
+ size_t n = 0;
+
+ tmp = data;
+ mc = filp->private_data;
+
+ kbuf = kmalloc(size, GFP_KERNEL);
+ if (kbuf == NULL) {
+ pr_err("%s(%d): buf allocation failed\n",
+ __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ do {
+ if (len - n > USER_COPY_SIZE)
+ size = USER_COPY_SIZE;
+ else
+ size = len - n;
+
+ if (copy_from_user(kbuf, tmp, size)) {
+ kfree(kbuf);
+ return n ? n : -EFAULT;
+ }
+
+ pti_write_to_aperture(mc, kbuf, size);
+ n += size;
+ tmp += size;
+
+ } while (len > n);
+
+ kfree(kbuf);
+ return len;
+}
+
+static const struct tty_operations pti_tty_driver_ops = {
+ .open = pti_tty_driver_open,
+ .close = pti_tty_driver_close,
+ .write = pti_tty_driver_write,
+ .write_room = pti_tty_write_room,
+ .install = pti_tty_install,
+ .cleanup = pti_tty_cleanup
+};
+
+static const struct file_operations pti_char_driver_ops = {
+ .owner = THIS_MODULE,
+ .write = pti_char_write,
+ .open = pti_char_open,
+ .release = pti_char_release,
+};
+
+static struct miscdevice pti_char_driver = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = CHARNAME,
+ .fops = &pti_char_driver_ops
+};
+
+/**
+ * pti_console_write()- Write to the console that has been acquired.
+ *
+ * @c: Not used in this implementaiton.
+ * @buf: Data to be written.
+ * @len: Length of buf.
+ */
+static void pti_console_write(struct console *c, const char *buf, unsigned len)
+{
+ static struct pti_masterchannel mc = {.master = CONSOLE_ID,
+ .channel = 0};
+
+ mc.channel = pti_console_channel;
+ pti_console_channel = (pti_console_channel + 1) & 0x7f;
+
+ pti_write_full_frame_to_aperture(&mc, buf, len);
+}
+
+/**
+ * pti_console_device()- Return the driver tty structure and set the
+ * associated index implementation.
+ *
+ * @c: Console device of the driver.
+ * @index: index associated with c.
+ *
+ * Returns:
+ * always value of pti_tty_driver structure when this function
+ * is called.
+ */
+static struct tty_driver *pti_console_device(struct console *c, int *index)
+{
+ *index = c->index;
+ return pti_tty_driver;
+}
+
+/**
+ * pti_console_setup()- Initialize console variables used by the driver.
+ *
+ * @c: Not used.
+ * @opts: Not used.
+ *
+ * Returns:
+ * always 0.
+ */
+static int pti_console_setup(struct console *c, char *opts)
+{
+ pti_console_channel = 0;
+ pti_control_channel = 0;
+ return 0;
+}
+
+/*
+ * pti_console struct, used to capture OS printk()'s and shift
+ * out to the PTI device for debugging. This cannot be
+ * enabled upon boot because of the possibility of eating
+ * any serial console printk's (race condition discovered).
+ * The console should be enabled upon when the tty port is
+ * used for the first time. Since the primary purpose for
+ * the tty port is to hook up syslog to it, the tty port
+ * will be open for a really long time.
+ */
+static struct console pti_console = {
+ .name = TTYNAME,
+ .write = pti_console_write,
+ .device = pti_console_device,
+ .setup = pti_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = 0,
+};
+
+/**
+ * pti_port_activate()- Used to start/initialize any items upon
+ * first opening of tty_port().
+ *
+ * @port- The tty port number of the PTI device.
+ * @tty- The tty struct associated with this device.
+ *
+ * Returns:
+ * always returns 0
+ *
+ * Notes: The primary purpose of the PTI tty port 0 is to hook
+ * the syslog daemon to it; thus this port will be open for a
+ * very long time.
+ */
+static int pti_port_activate(struct tty_port *port, struct tty_struct *tty)
+{
+ if (port->tty->index == PTITTY_MINOR_START)
+ console_start(&pti_console);
+ return 0;
+}
+
+/**
+ * pti_port_shutdown()- Used to stop/shutdown any items upon the
+ * last tty port close.
+ *
+ * @port- The tty port number of the PTI device.
+ *
+ * Notes: The primary purpose of the PTI tty port 0 is to hook
+ * the syslog daemon to it; thus this port will be open for a
+ * very long time.
+ */
+static void pti_port_shutdown(struct tty_port *port)
+{
+ if (port->tty->index == PTITTY_MINOR_START)
+ console_stop(&pti_console);
+}
+
+static const struct tty_port_operations tty_port_ops = {
+ .activate = pti_port_activate,
+ .shutdown = pti_port_shutdown,
+};
+
+/*
+ * Note the _probe() call sets everything up and ties the char and tty
+ * to successfully detecting the PTI device on the pci bus.
+ */
+
+/**
+ * pti_pci_probe()- Used to detect pti on the pci bus and set
+ * things up in the driver.
+ *
+ * @pdev- pci_dev struct values for pti.
+ * @ent- pci_device_id struct for pti driver.
+ *
+ * Returns:
+ * 0 for success
+ * otherwise, error
+ */
+static int __devinit pti_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int retval = -EINVAL;
+ int pci_bar = 1;
+
+ dev_dbg(&pdev->dev, "%s %s(%d): PTI PCI ID %04x:%04x\n", __FILE__,
+ __func__, __LINE__, pdev->vendor, pdev->device);
+
+ retval = misc_register(&pti_char_driver);
+ if (retval) {
+ pr_err("%s(%d): CHAR registration failed of pti driver\n",
+ __func__, __LINE__);
+ pr_err("%s(%d): Error value returned: %d\n",
+ __func__, __LINE__, retval);
+ return retval;
+ }
+
+ retval = pci_enable_device(pdev);
+ if (retval != 0) {
+ dev_err(&pdev->dev,
+ "%s: pci_enable_device() returned error %d\n",
+ __func__, retval);
+ return retval;
+ }
+
+ drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
+
+ if (drv_data == NULL) {
+ retval = -ENOMEM;
+ dev_err(&pdev->dev,
+ "%s(%d): kmalloc() returned NULL memory.\n",
+ __func__, __LINE__);
+ return retval;
+ }
+ drv_data->pti_addr = pci_resource_start(pdev, pci_bar);
+
+ retval = pci_request_region(pdev, pci_bar, dev_name(&pdev->dev));
+ if (retval != 0) {
+ dev_err(&pdev->dev,
+ "%s(%d): pci_request_region() returned error %d\n",
+ __func__, __LINE__, retval);
+ kfree(drv_data);
+ return retval;
+ }
+ drv_data->aperture_base = drv_data->pti_addr+APERTURE_14;
+ drv_data->pti_ioaddr =
+ ioremap_nocache((u32)drv_data->aperture_base,
+ APERTURE_LEN);
+ if (!drv_data->pti_ioaddr) {
+ pci_release_region(pdev, pci_bar);
+ retval = -ENOMEM;
+ kfree(drv_data);
+ return retval;
+ }
+
+ pci_set_drvdata(pdev, drv_data);
+
+ tty_port_init(&drv_data->port);
+ drv_data->port.ops = &tty_port_ops;
+
+ tty_register_device(pti_tty_driver, 0, &pdev->dev);
+ tty_register_device(pti_tty_driver, 1, &pdev->dev);
+
+ register_console(&pti_console);
+
+ return retval;
+}
+
+static struct pci_driver pti_pci_driver = {
+ .name = PCINAME,
+ .id_table = pci_ids,
+ .probe = pti_pci_probe,
+ .remove = pti_pci_remove,
+};
+
+/**
+ *
+ * pti_init()- Overall entry/init call to the pti driver.
+ * It starts the registration process with the kernel.
+ *
+ * Returns:
+ * int __init, 0 for success
+ * otherwise value is an error
+ *
+ */
+static int __init pti_init(void)
+{
+ int retval = -EINVAL;
+
+ /* First register module as tty device */
+
+ pti_tty_driver = alloc_tty_driver(1);
+ if (pti_tty_driver == NULL) {
+ pr_err("%s(%d): Memory allocation failed for ptiTTY driver\n",
+ __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ pti_tty_driver->owner = THIS_MODULE;
+ pti_tty_driver->magic = TTY_DRIVER_MAGIC;
+ pti_tty_driver->driver_name = DRIVERNAME;
+ pti_tty_driver->name = TTYNAME;
+ pti_tty_driver->major = 0;
+ pti_tty_driver->minor_start = PTITTY_MINOR_START;
+ pti_tty_driver->minor_num = PTITTY_MINOR_NUM;
+ pti_tty_driver->num = PTITTY_MINOR_NUM;
+ pti_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;
+ pti_tty_driver->subtype = SYSTEM_TYPE_SYSCONS;
+ pti_tty_driver->flags = TTY_DRIVER_REAL_RAW |
+ TTY_DRIVER_DYNAMIC_DEV;
+ pti_tty_driver->init_termios = tty_std_termios;
+
+ tty_set_operations(pti_tty_driver, &pti_tty_driver_ops);
+
+ retval = tty_register_driver(pti_tty_driver);
+ if (retval) {
+ pr_err("%s(%d): TTY registration failed of pti driver\n",
+ __func__, __LINE__);
+ pr_err("%s(%d): Error value returned: %d\n",
+ __func__, __LINE__, retval);
+
+ pti_tty_driver = NULL;
+ return retval;
+ }
+
+ retval = pci_register_driver(&pti_pci_driver);
+
+ if (retval) {
+ pr_err("%s(%d): PCI registration failed of pti driver\n",
+ __func__, __LINE__);
+ pr_err("%s(%d): Error value returned: %d\n",
+ __func__, __LINE__, retval);
+
+ tty_unregister_driver(pti_tty_driver);
+ pr_err("%s(%d): Unregistering TTY part of pti driver\n",
+ __func__, __LINE__);
+ pti_tty_driver = NULL;
+ return retval;
+ }
+
+ return retval;
+}
+
+/**
+ * pti_exit()- Unregisters this module as a tty and pci driver.
+ */
+static void __exit pti_exit(void)
+{
+ int retval;
+
+ tty_unregister_device(pti_tty_driver, 0);
+ tty_unregister_device(pti_tty_driver, 1);
+
+ retval = tty_unregister_driver(pti_tty_driver);
+ if (retval) {
+ pr_err("%s(%d): TTY unregistration failed of pti driver\n",
+ __func__, __LINE__);
+ pr_err("%s(%d): Error value returned: %d\n",
+ __func__, __LINE__, retval);
+ }
+
+ pci_unregister_driver(&pti_pci_driver);
+
+ retval = misc_deregister(&pti_char_driver);
+ if (retval) {
+ pr_err("%s(%d): CHAR unregistration failed of pti driver\n",
+ __func__, __LINE__);
+ pr_err("%s(%d): Error value returned: %d\n",
+ __func__, __LINE__, retval);
+ }
+
+ unregister_console(&pti_console);
+ return;
+}
+
+module_init(pti_init);
+module_exit(pti_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ken Mills, Jay Freyensee");
+MODULE_DESCRIPTION("PTI Driver");
+
diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c
index 38657cdaf54d..c4acac74725c 100644
--- a/drivers/misc/sgi-gru/grufault.c
+++ b/drivers/misc/sgi-gru/grufault.c
@@ -33,6 +33,7 @@
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/security.h>
+#include <linux/prefetch.h>
#include <asm/pgtable.h>
#include "gru.h"
#include "grutables.h"
diff --git a/drivers/misc/sgi-gru/grumain.c b/drivers/misc/sgi-gru/grumain.c
index f8538bbd0bfa..ae16c8cb4f3e 100644
--- a/drivers/misc/sgi-gru/grumain.c
+++ b/drivers/misc/sgi-gru/grumain.c
@@ -28,6 +28,7 @@
#include <linux/device.h>
#include <linux/list.h>
#include <linux/err.h>
+#include <linux/prefetch.h>
#include <asm/uv/uv_hub.h>
#include "gru.h"
#include "grutables.h"
diff --git a/drivers/misc/spear13xx_pcie_gadget.c b/drivers/misc/spear13xx_pcie_gadget.c
index ec3b8c911833..7aded90f9daa 100644
--- a/drivers/misc/spear13xx_pcie_gadget.c
+++ b/drivers/misc/spear13xx_pcie_gadget.c
@@ -787,8 +787,8 @@ static int __devinit spear_pcie_gadget_probe(struct platform_device *pdev)
status = request_irq(irq, spear_pcie_gadget_irq, 0, pdev->name, NULL);
if (status) {
- dev_err(&pdev->dev, "pcie gadget interrupt IRQ%d already \
- claimed\n", irq);
+ dev_err(&pdev->dev,
+ "pcie gadget interrupt IRQ%d already claimed\n", irq);
goto err_iounmap;
}
diff --git a/drivers/misc/ti-st/Kconfig b/drivers/misc/ti-st/Kconfig
index 2c8c3f39710d..abb5de1afce3 100644
--- a/drivers/misc/ti-st/Kconfig
+++ b/drivers/misc/ti-st/Kconfig
@@ -5,7 +5,7 @@
menu "Texas Instruments shared transport line discipline"
config TI_ST
tristate "Shared transport core driver"
- depends on RFKILL
+ depends on NET && GPIOLIB
select FW_LOADER
help
This enables the shared transport core driver for TI
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
index 486117f72c9f..1a05fe08e2cb 100644
--- a/drivers/misc/ti-st/st_core.c
+++ b/drivers/misc/ti-st/st_core.c
@@ -43,13 +43,15 @@ static void add_channel_to_table(struct st_data_s *st_gdata,
pr_info("%s: id %d\n", __func__, new_proto->chnl_id);
/* list now has the channel id as index itself */
st_gdata->list[new_proto->chnl_id] = new_proto;
+ st_gdata->is_registered[new_proto->chnl_id] = true;
}
static void remove_channel_from_table(struct st_data_s *st_gdata,
struct st_proto_s *proto)
{
pr_info("%s: id %d\n", __func__, proto->chnl_id);
- st_gdata->list[proto->chnl_id] = NULL;
+/* st_gdata->list[proto->chnl_id] = NULL; */
+ st_gdata->is_registered[proto->chnl_id] = false;
}
/*
@@ -104,7 +106,7 @@ void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata)
if (unlikely
(st_gdata == NULL || st_gdata->rx_skb == NULL
- || st_gdata->list[chnl_id] == NULL)) {
+ || st_gdata->is_registered[chnl_id] == false)) {
pr_err("chnl_id %d not registered, no data to send?",
chnl_id);
kfree_skb(st_gdata->rx_skb);
@@ -141,14 +143,15 @@ void st_reg_complete(struct st_data_s *st_gdata, char err)
unsigned char i = 0;
pr_info(" %s ", __func__);
for (i = 0; i < ST_MAX_CHANNELS; i++) {
- if (likely(st_gdata != NULL && st_gdata->list[i] != NULL &&
- st_gdata->list[i]->reg_complete_cb != NULL)) {
+ if (likely(st_gdata != NULL &&
+ st_gdata->is_registered[i] == true &&
+ st_gdata->list[i]->reg_complete_cb != NULL)) {
st_gdata->list[i]->reg_complete_cb
(st_gdata->list[i]->priv_data, err);
pr_info("protocol %d's cb sent %d\n", i, err);
if (err) { /* cleanup registered protocol */
st_gdata->protos_registered--;
- st_gdata->list[i] = NULL;
+ st_gdata->is_registered[i] = false;
}
}
}
@@ -475,9 +478,9 @@ void kim_st_list_protocols(struct st_data_s *st_gdata, void *buf)
{
seq_printf(buf, "[%d]\nBT=%c\nFM=%c\nGPS=%c\n",
st_gdata->protos_registered,
- st_gdata->list[0x04] != NULL ? 'R' : 'U',
- st_gdata->list[0x08] != NULL ? 'R' : 'U',
- st_gdata->list[0x09] != NULL ? 'R' : 'U');
+ st_gdata->is_registered[0x04] == true ? 'R' : 'U',
+ st_gdata->is_registered[0x08] == true ? 'R' : 'U',
+ st_gdata->is_registered[0x09] == true ? 'R' : 'U');
}
/********************************************************************/
@@ -504,7 +507,7 @@ long st_register(struct st_proto_s *new_proto)
return -EPROTONOSUPPORT;
}
- if (st_gdata->list[new_proto->chnl_id] != NULL) {
+ if (st_gdata->is_registered[new_proto->chnl_id] == true) {
pr_err("chnl_id %d already registered", new_proto->chnl_id);
return -EALREADY;
}
@@ -563,7 +566,7 @@ long st_register(struct st_proto_s *new_proto)
/* check for already registered once more,
* since the above check is old
*/
- if (st_gdata->list[new_proto->chnl_id] != NULL) {
+ if (st_gdata->is_registered[new_proto->chnl_id] == true) {
pr_err(" proto %d already registered ",
new_proto->chnl_id);
return -EALREADY;
@@ -744,8 +747,8 @@ static void st_tty_close(struct tty_struct *tty)
pr_debug("%s: done ", __func__);
}
-static void st_tty_receive(struct tty_struct *tty, const unsigned char *data,
- char *tty_flags, int count)
+static unsigned int st_tty_receive(struct tty_struct *tty,
+ const unsigned char *data, char *tty_flags, int count)
{
#ifdef VERBOSE
print_hex_dump(KERN_DEBUG, ">in>", DUMP_PREFIX_NONE,
@@ -758,6 +761,8 @@ static void st_tty_receive(struct tty_struct *tty, const unsigned char *data,
*/
st_recv(tty->disc_data, data, count);
pr_debug("done %s", __func__);
+
+ return count;
}
/* wake-up function called in from the TTY layer
diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c
index b4488c8f6b23..5da93ee6f6be 100644
--- a/drivers/misc/ti-st/st_kim.c
+++ b/drivers/misc/ti-st/st_kim.c
@@ -30,6 +30,7 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/sched.h>
+#include <linux/sysfs.h>
#include <linux/tty.h>
#include <linux/skbuff.h>
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 61d233a7c118..71da5641e258 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -31,7 +31,11 @@
#include <linux/mutex.h>
#include <linux/scatterlist.h>
#include <linux/string_helpers.h>
+#include <linux/delay.h>
+#include <linux/capability.h>
+#include <linux/compat.h>
+#include <linux/mmc/ioctl.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
@@ -48,6 +52,13 @@ MODULE_ALIAS("mmc:block");
#endif
#define MODULE_PARAM_PREFIX "mmcblk."
+#define INAND_CMD38_ARG_EXT_CSD 113
+#define INAND_CMD38_ARG_ERASE 0x00
+#define INAND_CMD38_ARG_TRIM 0x01
+#define INAND_CMD38_ARG_SECERASE 0x80
+#define INAND_CMD38_ARG_SECTRIM1 0x81
+#define INAND_CMD38_ARG_SECTRIM2 0x88
+
static DEFINE_MUTEX(block_mutex);
/*
@@ -64,6 +75,7 @@ static int max_devices;
/* 256 minors, so at most 256 separate devices */
static DECLARE_BITMAP(dev_use, 256);
+static DECLARE_BITMAP(name_use, 256);
/*
* There is one mmc_blk_data per slot.
@@ -72,9 +84,24 @@ struct mmc_blk_data {
spinlock_t lock;
struct gendisk *disk;
struct mmc_queue queue;
+ struct list_head part;
+
+ unsigned int flags;
+#define MMC_BLK_CMD23 (1 << 0) /* Can do SET_BLOCK_COUNT for multiblock */
+#define MMC_BLK_REL_WR (1 << 1) /* MMC Reliable write support */
unsigned int usage;
unsigned int read_only;
+ unsigned int part_type;
+ unsigned int name_idx;
+
+ /*
+ * Only set in main mmc_blk_data associated
+ * with mmc_card with mmc_set_drvdata, and keeps
+ * track of the current selected device partition.
+ */
+ unsigned int part_curr;
+ struct device_attribute force_ro;
};
static DEFINE_MUTEX(open_lock);
@@ -97,17 +124,22 @@ static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
return md;
}
+static inline int mmc_get_devidx(struct gendisk *disk)
+{
+ int devmaj = MAJOR(disk_devt(disk));
+ int devidx = MINOR(disk_devt(disk)) / perdev_minors;
+
+ if (!devmaj)
+ devidx = disk->first_minor / perdev_minors;
+ return devidx;
+}
+
static void mmc_blk_put(struct mmc_blk_data *md)
{
mutex_lock(&open_lock);
md->usage--;
if (md->usage == 0) {
- int devmaj = MAJOR(disk_devt(md->disk));
- int devidx = MINOR(disk_devt(md->disk)) / perdev_minors;
-
- if (!devmaj)
- devidx = md->disk->first_minor / perdev_minors;
-
+ int devidx = mmc_get_devidx(md->disk);
blk_cleanup_queue(md->queue.queue);
__clear_bit(devidx, dev_use);
@@ -118,6 +150,38 @@ static void mmc_blk_put(struct mmc_blk_data *md)
mutex_unlock(&open_lock);
}
+static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+
+ ret = snprintf(buf, PAGE_SIZE, "%d",
+ get_disk_ro(dev_to_disk(dev)) ^
+ md->read_only);
+ mmc_blk_put(md);
+ return ret;
+}
+
+static ssize_t force_ro_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+ char *end;
+ struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
+ unsigned long set = simple_strtoul(buf, &end, 0);
+ if (end == buf) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ set_disk_ro(dev_to_disk(dev), set || md->read_only);
+ ret = count;
+out:
+ mmc_blk_put(md);
+ return ret;
+}
+
static int mmc_blk_open(struct block_device *bdev, fmode_t mode)
{
struct mmc_blk_data *md = mmc_blk_get(bdev->bd_disk);
@@ -158,35 +222,255 @@ mmc_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return 0;
}
+struct mmc_blk_ioc_data {
+ struct mmc_ioc_cmd ic;
+ unsigned char *buf;
+ u64 buf_bytes;
+};
+
+static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
+ struct mmc_ioc_cmd __user *user)
+{
+ struct mmc_blk_ioc_data *idata;
+ int err;
+
+ idata = kzalloc(sizeof(*idata), GFP_KERNEL);
+ if (!idata) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ if (copy_from_user(&idata->ic, user, sizeof(idata->ic))) {
+ err = -EFAULT;
+ goto idata_err;
+ }
+
+ idata->buf_bytes = (u64) idata->ic.blksz * idata->ic.blocks;
+ if (idata->buf_bytes > MMC_IOC_MAX_BYTES) {
+ err = -EOVERFLOW;
+ goto idata_err;
+ }
+
+ idata->buf = kzalloc(idata->buf_bytes, GFP_KERNEL);
+ if (!idata->buf) {
+ err = -ENOMEM;
+ goto idata_err;
+ }
+
+ if (copy_from_user(idata->buf, (void __user *)(unsigned long)
+ idata->ic.data_ptr, idata->buf_bytes)) {
+ err = -EFAULT;
+ goto copy_err;
+ }
+
+ return idata;
+
+copy_err:
+ kfree(idata->buf);
+idata_err:
+ kfree(idata);
+out:
+ return ERR_PTR(err);
+}
+
+static int mmc_blk_ioctl_cmd(struct block_device *bdev,
+ struct mmc_ioc_cmd __user *ic_ptr)
+{
+ struct mmc_blk_ioc_data *idata;
+ struct mmc_blk_data *md;
+ struct mmc_card *card;
+ struct mmc_command cmd = {0};
+ struct mmc_data data = {0};
+ struct mmc_request mrq = {0};
+ struct scatterlist sg;
+ int err;
+
+ /*
+ * The caller must have CAP_SYS_RAWIO, and must be calling this on the
+ * whole block device, not on a partition. This prevents overspray
+ * between sibling partitions.
+ */
+ if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains))
+ return -EPERM;
+
+ idata = mmc_blk_ioctl_copy_from_user(ic_ptr);
+ if (IS_ERR(idata))
+ return PTR_ERR(idata);
+
+ cmd.opcode = idata->ic.opcode;
+ cmd.arg = idata->ic.arg;
+ cmd.flags = idata->ic.flags;
+
+ data.sg = &sg;
+ data.sg_len = 1;
+ data.blksz = idata->ic.blksz;
+ data.blocks = idata->ic.blocks;
+
+ sg_init_one(data.sg, idata->buf, idata->buf_bytes);
+
+ if (idata->ic.write_flag)
+ data.flags = MMC_DATA_WRITE;
+ else
+ data.flags = MMC_DATA_READ;
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+
+ md = mmc_blk_get(bdev->bd_disk);
+ if (!md) {
+ err = -EINVAL;
+ goto cmd_done;
+ }
+
+ card = md->queue.card;
+ if (IS_ERR(card)) {
+ err = PTR_ERR(card);
+ goto cmd_done;
+ }
+
+ mmc_claim_host(card->host);
+
+ if (idata->ic.is_acmd) {
+ err = mmc_app_cmd(card->host, card);
+ if (err)
+ goto cmd_rel_host;
+ }
+
+ /* data.flags must already be set before doing this. */
+ mmc_set_data_timeout(&data, card);
+ /* Allow overriding the timeout_ns for empirical tuning. */
+ if (idata->ic.data_timeout_ns)
+ data.timeout_ns = idata->ic.data_timeout_ns;
+
+ if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) {
+ /*
+ * Pretend this is a data transfer and rely on the host driver
+ * to compute timeout. When all host drivers support
+ * cmd.cmd_timeout for R1B, this can be changed to:
+ *
+ * mrq.data = NULL;
+ * cmd.cmd_timeout = idata->ic.cmd_timeout_ms;
+ */
+ data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000;
+ }
+
+ mmc_wait_for_req(card->host, &mrq);
+
+ if (cmd.error) {
+ dev_err(mmc_dev(card->host), "%s: cmd error %d\n",
+ __func__, cmd.error);
+ err = cmd.error;
+ goto cmd_rel_host;
+ }
+ if (data.error) {
+ dev_err(mmc_dev(card->host), "%s: data error %d\n",
+ __func__, data.error);
+ err = data.error;
+ goto cmd_rel_host;
+ }
+
+ /*
+ * According to the SD specs, some commands require a delay after
+ * issuing the command.
+ */
+ if (idata->ic.postsleep_min_us)
+ usleep_range(idata->ic.postsleep_min_us, idata->ic.postsleep_max_us);
+
+ if (copy_to_user(&(ic_ptr->response), cmd.resp, sizeof(cmd.resp))) {
+ err = -EFAULT;
+ goto cmd_rel_host;
+ }
+
+ if (!idata->ic.write_flag) {
+ if (copy_to_user((void __user *)(unsigned long) idata->ic.data_ptr,
+ idata->buf, idata->buf_bytes)) {
+ err = -EFAULT;
+ goto cmd_rel_host;
+ }
+ }
+
+cmd_rel_host:
+ mmc_release_host(card->host);
+
+cmd_done:
+ mmc_blk_put(md);
+ kfree(idata->buf);
+ kfree(idata);
+ return err;
+}
+
+static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = -EINVAL;
+ if (cmd == MMC_IOC_CMD)
+ ret = mmc_blk_ioctl_cmd(bdev, (struct mmc_ioc_cmd __user *)arg);
+ return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static int mmc_blk_compat_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned int cmd, unsigned long arg)
+{
+ return mmc_blk_ioctl(bdev, mode, cmd, (unsigned long) compat_ptr(arg));
+}
+#endif
+
static const struct block_device_operations mmc_bdops = {
.open = mmc_blk_open,
.release = mmc_blk_release,
.getgeo = mmc_blk_getgeo,
.owner = THIS_MODULE,
+ .ioctl = mmc_blk_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = mmc_blk_compat_ioctl,
+#endif
};
struct mmc_blk_request {
struct mmc_request mrq;
+ struct mmc_command sbc;
struct mmc_command cmd;
struct mmc_command stop;
struct mmc_data data;
};
+static inline int mmc_blk_part_switch(struct mmc_card *card,
+ struct mmc_blk_data *md)
+{
+ int ret;
+ struct mmc_blk_data *main_md = mmc_get_drvdata(card);
+ if (main_md->part_curr == md->part_type)
+ return 0;
+
+ if (mmc_card_mmc(card)) {
+ card->ext_csd.part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
+ card->ext_csd.part_config |= md->part_type;
+
+ ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ EXT_CSD_PART_CONFIG, card->ext_csd.part_config,
+ card->ext_csd.part_time);
+ if (ret)
+ return ret;
+}
+
+ main_md->part_curr = md->part_type;
+ return 0;
+}
+
static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
{
int err;
u32 result;
__be32 *blocks;
- struct mmc_request mrq;
- struct mmc_command cmd;
- struct mmc_data data;
+ struct mmc_request mrq = {0};
+ struct mmc_command cmd = {0};
+ struct mmc_data data = {0};
unsigned int timeout_us;
struct scatterlist sg;
- memset(&cmd, 0, sizeof(struct mmc_command));
-
cmd.opcode = MMC_APP_CMD;
cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
@@ -203,8 +487,6 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
cmd.arg = 0;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
- memset(&data, 0, sizeof(struct mmc_data));
-
data.timeout_ns = card->csd.tacc_ns * 100;
data.timeout_clks = card->csd.tacc_clks * 100;
@@ -223,8 +505,6 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
data.sg = &sg;
data.sg_len = 1;
- memset(&mrq, 0, sizeof(struct mmc_request));
-
mrq.cmd = &cmd;
mrq.data = &data;
@@ -247,10 +527,9 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
static u32 get_card_status(struct mmc_card *card, struct request *req)
{
- struct mmc_command cmd;
+ struct mmc_command cmd = {0};
int err;
- memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_SEND_STATUS;
if (!mmc_host_is_spi(card->host))
cmd.arg = card->rca << 16;
@@ -269,8 +548,6 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
unsigned int from, nr, arg;
int err = 0;
- mmc_claim_host(card->host);
-
if (!mmc_can_erase(card)) {
err = -EOPNOTSUPP;
goto out;
@@ -284,14 +561,22 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req)
else
arg = MMC_ERASE_ARG;
+ if (card->quirks & MMC_QUIRK_INAND_CMD38) {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ INAND_CMD38_ARG_EXT_CSD,
+ arg == MMC_TRIM_ARG ?
+ INAND_CMD38_ARG_TRIM :
+ INAND_CMD38_ARG_ERASE,
+ 0);
+ if (err)
+ goto out;
+ }
err = mmc_erase(card, from, nr, arg);
out:
spin_lock_irq(&md->lock);
__blk_end_request(req, err, blk_rq_bytes(req));
spin_unlock_irq(&md->lock);
- mmc_release_host(card->host);
-
return err ? 0 : 1;
}
@@ -303,8 +588,6 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
unsigned int from, nr, arg;
int err = 0;
- mmc_claim_host(card->host);
-
if (!mmc_can_secure_erase_trim(card)) {
err = -EOPNOTSUPP;
goto out;
@@ -318,19 +601,74 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
else
arg = MMC_SECURE_ERASE_ARG;
+ if (card->quirks & MMC_QUIRK_INAND_CMD38) {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ INAND_CMD38_ARG_EXT_CSD,
+ arg == MMC_SECURE_TRIM1_ARG ?
+ INAND_CMD38_ARG_SECTRIM1 :
+ INAND_CMD38_ARG_SECERASE,
+ 0);
+ if (err)
+ goto out;
+ }
err = mmc_erase(card, from, nr, arg);
- if (!err && arg == MMC_SECURE_TRIM1_ARG)
+ if (!err && arg == MMC_SECURE_TRIM1_ARG) {
+ if (card->quirks & MMC_QUIRK_INAND_CMD38) {
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+ INAND_CMD38_ARG_EXT_CSD,
+ INAND_CMD38_ARG_SECTRIM2,
+ 0);
+ if (err)
+ goto out;
+ }
err = mmc_erase(card, from, nr, MMC_SECURE_TRIM2_ARG);
+ }
out:
spin_lock_irq(&md->lock);
__blk_end_request(req, err, blk_rq_bytes(req));
spin_unlock_irq(&md->lock);
- mmc_release_host(card->host);
-
return err ? 0 : 1;
}
+static int mmc_blk_issue_flush(struct mmc_queue *mq, struct request *req)
+{
+ struct mmc_blk_data *md = mq->data;
+
+ /*
+ * No-op, only service this because we need REQ_FUA for reliable
+ * writes.
+ */
+ spin_lock_irq(&md->lock);
+ __blk_end_request_all(req, 0);
+ spin_unlock_irq(&md->lock);
+
+ return 1;
+}
+
+/*
+ * Reformat current write as a reliable write, supporting
+ * both legacy and the enhanced reliable write MMC cards.
+ * In each transfer we'll handle only as much as a single
+ * reliable write can handle, thus finish the request in
+ * partial completions.
+ */
+static inline void mmc_apply_rel_rw(struct mmc_blk_request *brq,
+ struct mmc_card *card,
+ struct request *req)
+{
+ if (!(card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN)) {
+ /* Legacy mode imposes restrictions on transfers. */
+ if (!IS_ALIGNED(brq->cmd.arg, card->ext_csd.rel_sectors))
+ brq->data.blocks = 1;
+
+ if (brq->data.blocks > card->ext_csd.rel_sectors)
+ brq->data.blocks = card->ext_csd.rel_sectors;
+ else if (brq->data.blocks < card->ext_csd.rel_sectors)
+ brq->data.blocks = 1;
+ }
+}
+
static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
{
struct mmc_blk_data *md = mq->data;
@@ -338,10 +676,17 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
struct mmc_blk_request brq;
int ret = 1, disable_multi = 0;
- mmc_claim_host(card->host);
+ /*
+ * Reliable writes are used to implement Forced Unit Access and
+ * REQ_META accesses, and are supported only on MMCs.
+ */
+ bool do_rel_wr = ((req->cmd_flags & REQ_FUA) ||
+ (req->cmd_flags & REQ_META)) &&
+ (rq_data_dir(req) == WRITE) &&
+ (md->flags & MMC_BLK_REL_WR);
do {
- struct mmc_command cmd;
+ struct mmc_command cmd = {0};
u32 readcmd, writecmd, status = 0;
memset(&brq, 0, sizeof(struct mmc_blk_request));
@@ -374,12 +719,12 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
if (disable_multi && brq.data.blocks > 1)
brq.data.blocks = 1;
- if (brq.data.blocks > 1) {
+ if (brq.data.blocks > 1 || do_rel_wr) {
/* SPI multiblock writes terminate using a special
* token, not a STOP_TRANSMISSION request.
*/
- if (!mmc_host_is_spi(card->host)
- || rq_data_dir(req) == READ)
+ if (!mmc_host_is_spi(card->host) ||
+ rq_data_dir(req) == READ)
brq.mrq.stop = &brq.stop;
readcmd = MMC_READ_MULTIPLE_BLOCK;
writecmd = MMC_WRITE_MULTIPLE_BLOCK;
@@ -396,6 +741,38 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
brq.data.flags |= MMC_DATA_WRITE;
}
+ if (do_rel_wr)
+ mmc_apply_rel_rw(&brq, card, req);
+
+ /*
+ * Pre-defined multi-block transfers are preferable to
+ * open ended-ones (and necessary for reliable writes).
+ * However, it is not sufficient to just send CMD23,
+ * and avoid the final CMD12, as on an error condition
+ * CMD12 (stop) needs to be sent anyway. This, coupled
+ * with Auto-CMD23 enhancements provided by some
+ * hosts, means that the complexity of dealing
+ * with this is best left to the host. If CMD23 is
+ * supported by card and host, we'll fill sbc in and let
+ * the host deal with handling it correctly. This means
+ * that for hosts that don't expose MMC_CAP_CMD23, no
+ * change of behavior will be observed.
+ *
+ * N.B: Some MMC cards experience perf degradation.
+ * We'll avoid using CMD23-bounded multiblock writes for
+ * these, while retaining features like reliable writes.
+ */
+
+ if ((md->flags & MMC_BLK_CMD23) &&
+ mmc_op_multi(brq.cmd.opcode) &&
+ (do_rel_wr || !(card->quirks & MMC_QUIRK_BLK_NO_CMD23))) {
+ brq.sbc.opcode = MMC_SET_BLOCK_COUNT;
+ brq.sbc.arg = brq.data.blocks |
+ (do_rel_wr ? (1 << 31) : 0);
+ brq.sbc.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ brq.mrq.sbc = &brq.sbc;
+ }
+
mmc_set_data_timeout(&brq.data, card);
brq.data.sg = mq->sg;
@@ -431,7 +808,8 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
* until later as we need to wait for the card to leave
* programming mode even when things go wrong.
*/
- if (brq.cmd.error || brq.data.error || brq.stop.error) {
+ if (brq.sbc.error || brq.cmd.error ||
+ brq.data.error || brq.stop.error) {
if (brq.data.blocks > 1 && rq_data_dir(req) == READ) {
/* Redo read one sector at a time */
printk(KERN_WARNING "%s: retrying using single "
@@ -442,6 +820,13 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
status = get_card_status(card, req);
}
+ if (brq.sbc.error) {
+ printk(KERN_ERR "%s: error %d sending SET_BLOCK_COUNT "
+ "command, response %#x, card status %#x\n",
+ req->rq_disk->disk_name, brq.sbc.error,
+ brq.sbc.resp[0], status);
+ }
+
if (brq.cmd.error) {
printk(KERN_ERR "%s: error %d sending read/write "
"command, response %#x, card status %#x\n",
@@ -520,8 +905,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
spin_unlock_irq(&md->lock);
} while (ret);
- mmc_release_host(card->host);
-
return 1;
cmd_err:
@@ -548,8 +931,6 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
spin_unlock_irq(&md->lock);
}
- mmc_release_host(card->host);
-
spin_lock_irq(&md->lock);
while (ret)
ret = __blk_end_request(req, -EIO, blk_rq_cur_bytes(req));
@@ -560,14 +941,31 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *req)
static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
{
+ int ret;
+ struct mmc_blk_data *md = mq->data;
+ struct mmc_card *card = md->queue.card;
+
+ mmc_claim_host(card->host);
+ ret = mmc_blk_part_switch(card, md);
+ if (ret) {
+ ret = 0;
+ goto out;
+ }
+
if (req->cmd_flags & REQ_DISCARD) {
if (req->cmd_flags & REQ_SECURE)
- return mmc_blk_issue_secdiscard_rq(mq, req);
+ ret = mmc_blk_issue_secdiscard_rq(mq, req);
else
- return mmc_blk_issue_discard_rq(mq, req);
+ ret = mmc_blk_issue_discard_rq(mq, req);
+ } else if (req->cmd_flags & REQ_FLUSH) {
+ ret = mmc_blk_issue_flush(mq, req);
} else {
- return mmc_blk_issue_rw_rq(mq, req);
+ ret = mmc_blk_issue_rw_rq(mq, req);
}
+
+out:
+ mmc_release_host(card->host);
+ return ret;
}
static inline int mmc_blk_readonly(struct mmc_card *card)
@@ -576,7 +974,11 @@ static inline int mmc_blk_readonly(struct mmc_card *card)
!(card->csd.cmdclass & CCC_BLOCK_WRITE);
}
-static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
+static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
+ struct device *parent,
+ sector_t size,
+ bool default_ro,
+ const char *subname)
{
struct mmc_blk_data *md;
int devidx, ret;
@@ -592,6 +994,19 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
goto out;
}
+ /*
+ * !subname implies we are creating main mmc_blk_data that will be
+ * associated with mmc_card with mmc_set_drvdata. Due to device
+ * partitions, devidx will not coincide with a per-physical card
+ * index anymore so we keep track of a name index.
+ */
+ if (!subname) {
+ md->name_idx = find_first_zero_bit(name_use, max_devices);
+ __set_bit(md->name_idx, name_use);
+ }
+ else
+ md->name_idx = ((struct mmc_blk_data *)
+ dev_to_disk(parent)->private_data)->name_idx;
/*
* Set the read-only status based on the supported commands
@@ -606,6 +1021,7 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
}
spin_lock_init(&md->lock);
+ INIT_LIST_HEAD(&md->part);
md->usage = 1;
ret = mmc_init_queue(&md->queue, card, &md->lock);
@@ -620,8 +1036,8 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
md->disk->fops = &mmc_bdops;
md->disk->private_data = md;
md->disk->queue = md->queue.queue;
- md->disk->driverfs_dev = &card->dev;
- set_disk_ro(md->disk, md->read_only);
+ md->disk->driverfs_dev = parent;
+ set_disk_ro(md->disk, md->read_only || default_ro);
/*
* As discussed on lkml, GENHD_FL_REMOVABLE should:
@@ -636,32 +1052,107 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
*/
snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
- "mmcblk%d", devidx);
+ "mmcblk%d%s", md->name_idx, subname ? subname : "");
blk_queue_logical_block_size(md->queue.queue, 512);
+ set_capacity(md->disk, size);
+
+ if (mmc_host_cmd23(card->host)) {
+ if (mmc_card_mmc(card) ||
+ (mmc_card_sd(card) &&
+ card->scr.cmds & SD_SCR_CMD23_SUPPORT))
+ md->flags |= MMC_BLK_CMD23;
+ }
+
+ if (mmc_card_mmc(card) &&
+ md->flags & MMC_BLK_CMD23 &&
+ ((card->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN) ||
+ card->ext_csd.rel_sectors)) {
+ md->flags |= MMC_BLK_REL_WR;
+ blk_queue_flush(md->queue.queue, REQ_FLUSH | REQ_FUA);
+ }
+
+ return md;
+
+ err_putdisk:
+ put_disk(md->disk);
+ err_kfree:
+ kfree(md);
+ out:
+ return ERR_PTR(ret);
+}
+
+static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
+{
+ sector_t size;
+ struct mmc_blk_data *md;
if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
/*
* The EXT_CSD sector count is in number or 512 byte
* sectors.
*/
- set_capacity(md->disk, card->ext_csd.sectors);
+ size = card->ext_csd.sectors;
} else {
/*
* The CSD capacity field is in units of read_blkbits.
* set_capacity takes units of 512 bytes.
*/
- set_capacity(md->disk,
- card->csd.capacity << (card->csd.read_blkbits - 9));
+ size = card->csd.capacity << (card->csd.read_blkbits - 9);
}
+
+ md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL);
return md;
+}
- err_putdisk:
- put_disk(md->disk);
- err_kfree:
- kfree(md);
- out:
- return ERR_PTR(ret);
+static int mmc_blk_alloc_part(struct mmc_card *card,
+ struct mmc_blk_data *md,
+ unsigned int part_type,
+ sector_t size,
+ bool default_ro,
+ const char *subname)
+{
+ char cap_str[10];
+ struct mmc_blk_data *part_md;
+
+ part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, default_ro,
+ subname);
+ if (IS_ERR(part_md))
+ return PTR_ERR(part_md);
+ part_md->part_type = part_type;
+ list_add(&part_md->part, &md->part);
+
+ string_get_size((u64)get_capacity(part_md->disk) << 9, STRING_UNITS_2,
+ cap_str, sizeof(cap_str));
+ printk(KERN_INFO "%s: %s %s partition %u %s\n",
+ part_md->disk->disk_name, mmc_card_id(card),
+ mmc_card_name(card), part_md->part_type, cap_str);
+ return 0;
+}
+
+static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
+{
+ int ret = 0;
+
+ if (!mmc_card_mmc(card))
+ return 0;
+
+ if (card->ext_csd.boot_size) {
+ ret = mmc_blk_alloc_part(card, md, EXT_CSD_PART_CONFIG_ACC_BOOT0,
+ card->ext_csd.boot_size >> 9,
+ true,
+ "boot0");
+ if (ret)
+ return ret;
+ ret = mmc_blk_alloc_part(card, md, EXT_CSD_PART_CONFIG_ACC_BOOT1,
+ card->ext_csd.boot_size >> 9,
+ true,
+ "boot1");
+ if (ret)
+ return ret;
+ }
+
+ return ret;
}
static int
@@ -682,9 +1173,81 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
return 0;
}
+static void mmc_blk_remove_req(struct mmc_blk_data *md)
+{
+ if (md) {
+ if (md->disk->flags & GENHD_FL_UP) {
+ device_remove_file(disk_to_dev(md->disk), &md->force_ro);
+
+ /* Stop new requests from getting into the queue */
+ del_gendisk(md->disk);
+ }
+
+ /* Then flush out any already in there */
+ mmc_cleanup_queue(&md->queue);
+ mmc_blk_put(md);
+ }
+}
+
+static void mmc_blk_remove_parts(struct mmc_card *card,
+ struct mmc_blk_data *md)
+{
+ struct list_head *pos, *q;
+ struct mmc_blk_data *part_md;
+
+ __clear_bit(md->name_idx, name_use);
+ list_for_each_safe(pos, q, &md->part) {
+ part_md = list_entry(pos, struct mmc_blk_data, part);
+ list_del(pos);
+ mmc_blk_remove_req(part_md);
+ }
+}
+
+static int mmc_add_disk(struct mmc_blk_data *md)
+{
+ int ret;
+
+ add_disk(md->disk);
+ md->force_ro.show = force_ro_show;
+ md->force_ro.store = force_ro_store;
+ sysfs_attr_init(&md->force_ro.attr);
+ md->force_ro.attr.name = "force_ro";
+ md->force_ro.attr.mode = S_IRUGO | S_IWUSR;
+ ret = device_create_file(disk_to_dev(md->disk), &md->force_ro);
+ if (ret)
+ del_gendisk(md->disk);
+
+ return ret;
+}
+
+static const struct mmc_fixup blk_fixups[] =
+{
+ MMC_FIXUP("SEM02G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
+ MMC_FIXUP("SEM04G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
+ MMC_FIXUP("SEM08G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
+ MMC_FIXUP("SEM16G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
+ MMC_FIXUP("SEM32G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38),
+
+ /*
+ * Some MMC cards experience performance degradation with CMD23
+ * instead of CMD12-bounded multiblock transfers. For now we'll
+ * black list what's bad...
+ * - Certain Toshiba cards.
+ *
+ * N.B. This doesn't affect SD cards.
+ */
+ MMC_FIXUP("MMC08G", 0x11, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_BLK_NO_CMD23),
+ MMC_FIXUP("MMC16G", 0x11, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_BLK_NO_CMD23),
+ MMC_FIXUP("MMC32G", 0x11, CID_OEMID_ANY, add_quirk_mmc,
+ MMC_QUIRK_BLK_NO_CMD23),
+ END_FIXUP
+};
+
static int mmc_blk_probe(struct mmc_card *card)
{
- struct mmc_blk_data *md;
+ struct mmc_blk_data *md, *part_md;
int err;
char cap_str[10];
@@ -708,14 +1271,24 @@ static int mmc_blk_probe(struct mmc_card *card)
md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
cap_str, md->read_only ? "(ro)" : "");
+ if (mmc_blk_alloc_parts(card, md))
+ goto out;
+
mmc_set_drvdata(card, md);
- add_disk(md->disk);
+ mmc_fixup_device(card, blk_fixups);
+
+ if (mmc_add_disk(md))
+ goto out;
+
+ list_for_each_entry(part_md, &md->part, part) {
+ if (mmc_add_disk(part_md))
+ goto out;
+ }
return 0;
out:
- mmc_cleanup_queue(&md->queue);
- mmc_blk_put(md);
-
+ mmc_blk_remove_parts(card, md);
+ mmc_blk_remove_req(md);
return err;
}
@@ -723,36 +1296,43 @@ static void mmc_blk_remove(struct mmc_card *card)
{
struct mmc_blk_data *md = mmc_get_drvdata(card);
- if (md) {
- /* Stop new requests from getting into the queue */
- del_gendisk(md->disk);
-
- /* Then flush out any already in there */
- mmc_cleanup_queue(&md->queue);
-
- mmc_blk_put(md);
- }
+ mmc_blk_remove_parts(card, md);
+ mmc_blk_remove_req(md);
mmc_set_drvdata(card, NULL);
}
#ifdef CONFIG_PM
static int mmc_blk_suspend(struct mmc_card *card, pm_message_t state)
{
+ struct mmc_blk_data *part_md;
struct mmc_blk_data *md = mmc_get_drvdata(card);
if (md) {
mmc_queue_suspend(&md->queue);
+ list_for_each_entry(part_md, &md->part, part) {
+ mmc_queue_suspend(&part_md->queue);
+ }
}
return 0;
}
static int mmc_blk_resume(struct mmc_card *card)
{
+ struct mmc_blk_data *part_md;
struct mmc_blk_data *md = mmc_get_drvdata(card);
if (md) {
mmc_blk_set_blksize(md, card);
+
+ /*
+ * Resume involves the card going into idle state,
+ * so current partition is always the main one.
+ */
+ md->part_curr = md->part_type;
mmc_queue_resume(&md->queue);
+ list_for_each_entry(part_md, &md->part, part) {
+ mmc_queue_resume(&part_md->queue);
+ }
}
return 0;
}
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index abc1a63bcc5e..233cdfae92f4 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -212,7 +212,7 @@ static int mmc_test_busy(struct mmc_command *cmd)
static int mmc_test_wait_busy(struct mmc_test_card *test)
{
int ret, busy;
- struct mmc_command cmd;
+ struct mmc_command cmd = {0};
busy = 0;
do {
@@ -246,18 +246,13 @@ static int mmc_test_buffer_transfer(struct mmc_test_card *test,
{
int ret;
- struct mmc_request mrq;
- struct mmc_command cmd;
- struct mmc_command stop;
- struct mmc_data data;
+ struct mmc_request mrq = {0};
+ struct mmc_command cmd = {0};
+ struct mmc_command stop = {0};
+ struct mmc_data data = {0};
struct scatterlist sg;
- memset(&mrq, 0, sizeof(struct mmc_request));
- memset(&cmd, 0, sizeof(struct mmc_command));
- memset(&data, 0, sizeof(struct mmc_data));
- memset(&stop, 0, sizeof(struct mmc_command));
-
mrq.cmd = &cmd;
mrq.data = &data;
mrq.stop = &stop;
@@ -731,15 +726,10 @@ static int mmc_test_simple_transfer(struct mmc_test_card *test,
struct scatterlist *sg, unsigned sg_len, unsigned dev_addr,
unsigned blocks, unsigned blksz, int write)
{
- struct mmc_request mrq;
- struct mmc_command cmd;
- struct mmc_command stop;
- struct mmc_data data;
-
- memset(&mrq, 0, sizeof(struct mmc_request));
- memset(&cmd, 0, sizeof(struct mmc_command));
- memset(&data, 0, sizeof(struct mmc_data));
- memset(&stop, 0, sizeof(struct mmc_command));
+ struct mmc_request mrq = {0};
+ struct mmc_command cmd = {0};
+ struct mmc_command stop = {0};
+ struct mmc_data data = {0};
mrq.cmd = &cmd;
mrq.data = &data;
@@ -761,18 +751,13 @@ static int mmc_test_simple_transfer(struct mmc_test_card *test,
static int mmc_test_broken_transfer(struct mmc_test_card *test,
unsigned blocks, unsigned blksz, int write)
{
- struct mmc_request mrq;
- struct mmc_command cmd;
- struct mmc_command stop;
- struct mmc_data data;
+ struct mmc_request mrq = {0};
+ struct mmc_command cmd = {0};
+ struct mmc_command stop = {0};
+ struct mmc_data data = {0};
struct scatterlist sg;
- memset(&mrq, 0, sizeof(struct mmc_request));
- memset(&cmd, 0, sizeof(struct mmc_command));
- memset(&data, 0, sizeof(struct mmc_data));
- memset(&stop, 0, sizeof(struct mmc_command));
-
mrq.cmd = &cmd;
mrq.data = &data;
mrq.stop = &stop;
@@ -1401,8 +1386,9 @@ static int mmc_test_area_io(struct mmc_test_card *test, unsigned long sz,
*/
static int mmc_test_area_fill(struct mmc_test_card *test)
{
- return mmc_test_area_io(test, test->area.max_tfr, test->area.dev_addr,
- 1, 0, 0);
+ struct mmc_test_area *t = &test->area;
+
+ return mmc_test_area_io(test, t->max_tfr, t->dev_addr, 1, 0, 0);
}
/*
@@ -1415,7 +1401,7 @@ static int mmc_test_area_erase(struct mmc_test_card *test)
if (!mmc_can_erase(test->card))
return 0;
- return mmc_erase(test->card, t->dev_addr, test->area.max_sz >> 9,
+ return mmc_erase(test->card, t->dev_addr, t->max_sz >> 9,
MMC_ERASE_ARG);
}
@@ -1542,8 +1528,10 @@ static int mmc_test_area_prepare_fill(struct mmc_test_card *test)
static int mmc_test_best_performance(struct mmc_test_card *test, int write,
int max_scatter)
{
- return mmc_test_area_io(test, test->area.max_tfr, test->area.dev_addr,
- write, max_scatter, 1);
+ struct mmc_test_area *t = &test->area;
+
+ return mmc_test_area_io(test, t->max_tfr, t->dev_addr, write,
+ max_scatter, 1);
}
/*
@@ -1583,18 +1571,19 @@ static int mmc_test_best_write_perf_max_scatter(struct mmc_test_card *test)
*/
static int mmc_test_profile_read_perf(struct mmc_test_card *test)
{
+ struct mmc_test_area *t = &test->area;
unsigned long sz;
unsigned int dev_addr;
int ret;
- for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
- dev_addr = test->area.dev_addr + (sz >> 9);
+ for (sz = 512; sz < t->max_tfr; sz <<= 1) {
+ dev_addr = t->dev_addr + (sz >> 9);
ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 1);
if (ret)
return ret;
}
- sz = test->area.max_tfr;
- dev_addr = test->area.dev_addr;
+ sz = t->max_tfr;
+ dev_addr = t->dev_addr;
return mmc_test_area_io(test, sz, dev_addr, 0, 0, 1);
}
@@ -1603,6 +1592,7 @@ static int mmc_test_profile_read_perf(struct mmc_test_card *test)
*/
static int mmc_test_profile_write_perf(struct mmc_test_card *test)
{
+ struct mmc_test_area *t = &test->area;
unsigned long sz;
unsigned int dev_addr;
int ret;
@@ -1610,8 +1600,8 @@ static int mmc_test_profile_write_perf(struct mmc_test_card *test)
ret = mmc_test_area_erase(test);
if (ret)
return ret;
- for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
- dev_addr = test->area.dev_addr + (sz >> 9);
+ for (sz = 512; sz < t->max_tfr; sz <<= 1) {
+ dev_addr = t->dev_addr + (sz >> 9);
ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 1);
if (ret)
return ret;
@@ -1619,8 +1609,8 @@ static int mmc_test_profile_write_perf(struct mmc_test_card *test)
ret = mmc_test_area_erase(test);
if (ret)
return ret;
- sz = test->area.max_tfr;
- dev_addr = test->area.dev_addr;
+ sz = t->max_tfr;
+ dev_addr = t->dev_addr;
return mmc_test_area_io(test, sz, dev_addr, 1, 0, 1);
}
@@ -1629,6 +1619,7 @@ static int mmc_test_profile_write_perf(struct mmc_test_card *test)
*/
static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
{
+ struct mmc_test_area *t = &test->area;
unsigned long sz;
unsigned int dev_addr;
struct timespec ts1, ts2;
@@ -1640,8 +1631,8 @@ static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
if (!mmc_can_erase(test->card))
return RESULT_UNSUP_HOST;
- for (sz = 512; sz < test->area.max_sz; sz <<= 1) {
- dev_addr = test->area.dev_addr + (sz >> 9);
+ for (sz = 512; sz < t->max_sz; sz <<= 1) {
+ dev_addr = t->dev_addr + (sz >> 9);
getnstimeofday(&ts1);
ret = mmc_erase(test->card, dev_addr, sz >> 9, MMC_TRIM_ARG);
if (ret)
@@ -1649,7 +1640,7 @@ static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
getnstimeofday(&ts2);
mmc_test_print_rate(test, sz, &ts1, &ts2);
}
- dev_addr = test->area.dev_addr;
+ dev_addr = t->dev_addr;
getnstimeofday(&ts1);
ret = mmc_erase(test->card, dev_addr, sz >> 9, MMC_TRIM_ARG);
if (ret)
@@ -1661,12 +1652,13 @@ static int mmc_test_profile_trim_perf(struct mmc_test_card *test)
static int mmc_test_seq_read_perf(struct mmc_test_card *test, unsigned long sz)
{
+ struct mmc_test_area *t = &test->area;
unsigned int dev_addr, i, cnt;
struct timespec ts1, ts2;
int ret;
- cnt = test->area.max_sz / sz;
- dev_addr = test->area.dev_addr;
+ cnt = t->max_sz / sz;
+ dev_addr = t->dev_addr;
getnstimeofday(&ts1);
for (i = 0; i < cnt; i++) {
ret = mmc_test_area_io(test, sz, dev_addr, 0, 0, 0);
@@ -1684,20 +1676,22 @@ static int mmc_test_seq_read_perf(struct mmc_test_card *test, unsigned long sz)
*/
static int mmc_test_profile_seq_read_perf(struct mmc_test_card *test)
{
+ struct mmc_test_area *t = &test->area;
unsigned long sz;
int ret;
- for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
+ for (sz = 512; sz < t->max_tfr; sz <<= 1) {
ret = mmc_test_seq_read_perf(test, sz);
if (ret)
return ret;
}
- sz = test->area.max_tfr;
+ sz = t->max_tfr;
return mmc_test_seq_read_perf(test, sz);
}
static int mmc_test_seq_write_perf(struct mmc_test_card *test, unsigned long sz)
{
+ struct mmc_test_area *t = &test->area;
unsigned int dev_addr, i, cnt;
struct timespec ts1, ts2;
int ret;
@@ -1705,8 +1699,8 @@ static int mmc_test_seq_write_perf(struct mmc_test_card *test, unsigned long sz)
ret = mmc_test_area_erase(test);
if (ret)
return ret;
- cnt = test->area.max_sz / sz;
- dev_addr = test->area.dev_addr;
+ cnt = t->max_sz / sz;
+ dev_addr = t->dev_addr;
getnstimeofday(&ts1);
for (i = 0; i < cnt; i++) {
ret = mmc_test_area_io(test, sz, dev_addr, 1, 0, 0);
@@ -1724,15 +1718,16 @@ static int mmc_test_seq_write_perf(struct mmc_test_card *test, unsigned long sz)
*/
static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test)
{
+ struct mmc_test_area *t = &test->area;
unsigned long sz;
int ret;
- for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
+ for (sz = 512; sz < t->max_tfr; sz <<= 1) {
ret = mmc_test_seq_write_perf(test, sz);
if (ret)
return ret;
}
- sz = test->area.max_tfr;
+ sz = t->max_tfr;
return mmc_test_seq_write_perf(test, sz);
}
@@ -1741,6 +1736,7 @@ static int mmc_test_profile_seq_write_perf(struct mmc_test_card *test)
*/
static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test)
{
+ struct mmc_test_area *t = &test->area;
unsigned long sz;
unsigned int dev_addr, i, cnt;
struct timespec ts1, ts2;
@@ -1752,15 +1748,15 @@ static int mmc_test_profile_seq_trim_perf(struct mmc_test_card *test)
if (!mmc_can_erase(test->card))
return RESULT_UNSUP_HOST;
- for (sz = 512; sz <= test->area.max_sz; sz <<= 1) {
+ for (sz = 512; sz <= t->max_sz; sz <<= 1) {
ret = mmc_test_area_erase(test);
if (ret)
return ret;
ret = mmc_test_area_fill(test);
if (ret)
return ret;
- cnt = test->area.max_sz / sz;
- dev_addr = test->area.dev_addr;
+ cnt = t->max_sz / sz;
+ dev_addr = t->dev_addr;
getnstimeofday(&ts1);
for (i = 0; i < cnt; i++) {
ret = mmc_erase(test->card, dev_addr, sz >> 9,
@@ -1823,11 +1819,12 @@ static int mmc_test_rnd_perf(struct mmc_test_card *test, int write, int print,
static int mmc_test_random_perf(struct mmc_test_card *test, int write)
{
+ struct mmc_test_area *t = &test->area;
unsigned int next;
unsigned long sz;
int ret;
- for (sz = 512; sz < test->area.max_tfr; sz <<= 1) {
+ for (sz = 512; sz < t->max_tfr; sz <<= 1) {
/*
* When writing, try to get more consistent results by running
* the test twice with exactly the same I/O but outputting the
@@ -1844,7 +1841,7 @@ static int mmc_test_random_perf(struct mmc_test_card *test, int write)
if (ret)
return ret;
}
- sz = test->area.max_tfr;
+ sz = t->max_tfr;
if (write) {
next = rnd_next;
ret = mmc_test_rnd_perf(test, write, 0, sz);
@@ -1874,17 +1871,18 @@ static int mmc_test_random_write_perf(struct mmc_test_card *test)
static int mmc_test_seq_perf(struct mmc_test_card *test, int write,
unsigned int tot_sz, int max_scatter)
{
+ struct mmc_test_area *t = &test->area;
unsigned int dev_addr, i, cnt, sz, ssz;
struct timespec ts1, ts2;
int ret;
- sz = test->area.max_tfr;
+ sz = t->max_tfr;
+
/*
* In the case of a maximally scattered transfer, the maximum transfer
* size is further limited by using PAGE_SIZE segments.
*/
if (max_scatter) {
- struct mmc_test_area *t = &test->area;
unsigned long max_tfr;
if (t->max_seg_sz >= PAGE_SIZE)
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index 2ae727568df9..c07322c2658c 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -343,18 +343,14 @@ unsigned int mmc_queue_map_sg(struct mmc_queue *mq)
*/
void mmc_queue_bounce_pre(struct mmc_queue *mq)
{
- unsigned long flags;
-
if (!mq->bounce_buf)
return;
if (rq_data_dir(mq->req) != WRITE)
return;
- local_irq_save(flags);
sg_copy_to_buffer(mq->bounce_sg, mq->bounce_sg_len,
mq->bounce_buf, mq->sg[0].length);
- local_irq_restore(flags);
}
/*
@@ -363,17 +359,13 @@ void mmc_queue_bounce_pre(struct mmc_queue *mq)
*/
void mmc_queue_bounce_post(struct mmc_queue *mq)
{
- unsigned long flags;
-
if (!mq->bounce_buf)
return;
if (rq_data_dir(mq->req) != READ)
return;
- local_irq_save(flags);
sg_copy_from_buffer(mq->bounce_sg, mq->bounce_sg_len,
mq->bounce_buf, mq->sg[0].length);
- local_irq_restore(flags);
}
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index d6d62fd07ee9..393d817ed040 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -274,8 +274,12 @@ int mmc_add_card(struct mmc_card *card)
break;
case MMC_TYPE_SD:
type = "SD";
- if (mmc_card_blockaddr(card))
- type = "SDHC";
+ if (mmc_card_blockaddr(card)) {
+ if (mmc_card_ext_capacity(card))
+ type = "SDXC";
+ else
+ type = "SDHC";
+ }
break;
case MMC_TYPE_SDIO:
type = "SDIO";
@@ -299,7 +303,8 @@ int mmc_add_card(struct mmc_card *card)
} else {
printk(KERN_INFO "%s: new %s%s%s card at address %04x\n",
mmc_hostname(card->host),
- mmc_card_highspeed(card) ? "high speed " : "",
+ mmc_sd_card_uhs(card) ? "ultra high speed " :
+ (mmc_card_highspeed(card) ? "high speed " : ""),
mmc_card_ddr_mode(card) ? "DDR " : "",
type, card->rca);
}
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 1f453acc8682..68091dda3f31 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -236,12 +236,10 @@ EXPORT_SYMBOL(mmc_wait_for_req);
*/
int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
{
- struct mmc_request mrq;
+ struct mmc_request mrq = {0};
WARN_ON(!host->claimed);
- memset(&mrq, 0, sizeof(struct mmc_request));
-
memset(cmd->resp, 0, sizeof(cmd->resp));
cmd->retries = retries;
@@ -720,22 +718,12 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
}
/*
- * Change data bus width and DDR mode of a host.
- */
-void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width,
- unsigned int ddr)
-{
- host->ios.bus_width = width;
- host->ios.ddr = ddr;
- mmc_set_ios(host);
-}
-
-/*
* Change data bus width of a host.
*/
void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
{
- mmc_set_bus_width_ddr(host, width, MMC_SDR_MODE);
+ host->ios.bus_width = width;
+ mmc_set_ios(host);
}
/**
@@ -944,6 +932,38 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
return ocr;
}
+int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11)
+{
+ struct mmc_command cmd = {0};
+ int err = 0;
+
+ BUG_ON(!host);
+
+ /*
+ * Send CMD11 only if the request is to switch the card to
+ * 1.8V signalling.
+ */
+ if ((signal_voltage != MMC_SIGNAL_VOLTAGE_330) && cmd11) {
+ cmd.opcode = SD_SWITCH_VOLTAGE;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+ err = mmc_wait_for_cmd(host, &cmd, 0);
+ if (err)
+ return err;
+
+ if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
+ return -EIO;
+ }
+
+ host->ios.signal_voltage = signal_voltage;
+
+ if (host->ops->start_signal_voltage_switch)
+ err = host->ops->start_signal_voltage_switch(host, &host->ios);
+
+ return err;
+}
+
/*
* Select timing parameters for host.
*/
@@ -954,6 +974,15 @@ void mmc_set_timing(struct mmc_host *host, unsigned int timing)
}
/*
+ * Select appropriate driver type for host.
+ */
+void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
+{
+ host->ios.drv_type = drv_type;
+ mmc_set_ios(host);
+}
+
+/*
* Apply power to the MMC stack. This is a two-stage process.
* First, we enable power to the card without the clock running.
* We then wait a bit for the power to stabilise. Finally,
@@ -1187,9 +1216,8 @@ void mmc_init_erase(struct mmc_card *card)
}
}
-static void mmc_set_mmc_erase_timeout(struct mmc_card *card,
- struct mmc_command *cmd,
- unsigned int arg, unsigned int qty)
+static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
+ unsigned int arg, unsigned int qty)
{
unsigned int erase_timeout;
@@ -1246,44 +1274,48 @@ static void mmc_set_mmc_erase_timeout(struct mmc_card *card,
if (mmc_host_is_spi(card->host) && erase_timeout < 1000)
erase_timeout = 1000;
- cmd->erase_timeout = erase_timeout;
+ return erase_timeout;
}
-static void mmc_set_sd_erase_timeout(struct mmc_card *card,
- struct mmc_command *cmd, unsigned int arg,
- unsigned int qty)
+static unsigned int mmc_sd_erase_timeout(struct mmc_card *card,
+ unsigned int arg,
+ unsigned int qty)
{
+ unsigned int erase_timeout;
+
if (card->ssr.erase_timeout) {
/* Erase timeout specified in SD Status Register (SSR) */
- cmd->erase_timeout = card->ssr.erase_timeout * qty +
- card->ssr.erase_offset;
+ erase_timeout = card->ssr.erase_timeout * qty +
+ card->ssr.erase_offset;
} else {
/*
* Erase timeout not specified in SD Status Register (SSR) so
* use 250ms per write block.
*/
- cmd->erase_timeout = 250 * qty;
+ erase_timeout = 250 * qty;
}
/* Must not be less than 1 second */
- if (cmd->erase_timeout < 1000)
- cmd->erase_timeout = 1000;
+ if (erase_timeout < 1000)
+ erase_timeout = 1000;
+
+ return erase_timeout;
}
-static void mmc_set_erase_timeout(struct mmc_card *card,
- struct mmc_command *cmd, unsigned int arg,
- unsigned int qty)
+static unsigned int mmc_erase_timeout(struct mmc_card *card,
+ unsigned int arg,
+ unsigned int qty)
{
if (mmc_card_sd(card))
- mmc_set_sd_erase_timeout(card, cmd, arg, qty);
+ return mmc_sd_erase_timeout(card, arg, qty);
else
- mmc_set_mmc_erase_timeout(card, cmd, arg, qty);
+ return mmc_mmc_erase_timeout(card, arg, qty);
}
static int mmc_do_erase(struct mmc_card *card, unsigned int from,
unsigned int to, unsigned int arg)
{
- struct mmc_command cmd;
+ struct mmc_command cmd = {0};
unsigned int qty = 0;
int err;
@@ -1317,7 +1349,6 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
to <<= 9;
}
- memset(&cmd, 0, sizeof(struct mmc_command));
if (mmc_card_sd(card))
cmd.opcode = SD_ERASE_WR_BLK_START;
else
@@ -1351,7 +1382,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
cmd.opcode = MMC_ERASE;
cmd.arg = arg;
cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
- mmc_set_erase_timeout(card, &cmd, arg, qty);
+ cmd.cmd_timeout_ms = mmc_erase_timeout(card, arg, qty);
err = mmc_wait_for_cmd(card->host, &cmd, 0);
if (err) {
printk(KERN_ERR "mmc_erase: erase error %d, status %#x\n",
@@ -1487,12 +1518,11 @@ EXPORT_SYMBOL(mmc_erase_group_aligned);
int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
{
- struct mmc_command cmd;
+ struct mmc_command cmd = {0};
if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card))
return 0;
- memset(&cmd, 0, sizeof(struct mmc_command));
cmd.opcode = MMC_SET_BLOCKLEN;
cmd.arg = blocklen;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
@@ -1578,7 +1608,7 @@ void mmc_rescan(struct work_struct *work)
for (i = 0; i < ARRAY_SIZE(freqs); i++) {
if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min)))
break;
- if (freqs[i] < host->f_min)
+ if (freqs[i] <= host->f_min)
break;
}
mmc_release_host(host);
@@ -1746,7 +1776,7 @@ int mmc_suspend_host(struct mmc_host *host)
}
mmc_bus_put(host);
- if (!err && !(host->pm_flags & MMC_PM_KEEP_POWER))
+ if (!err && !mmc_card_keep_power(host))
mmc_power_off(host);
return err;
@@ -1764,7 +1794,7 @@ int mmc_resume_host(struct mmc_host *host)
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead) {
- if (!(host->pm_flags & MMC_PM_KEEP_POWER)) {
+ if (!mmc_card_keep_power(host)) {
mmc_power_up(host);
mmc_select_voltage(host, host->ocr);
/*
@@ -1789,6 +1819,7 @@ int mmc_resume_host(struct mmc_host *host)
err = 0;
}
}
+ host->pm_flags &= ~MMC_PM_KEEP_POWER;
mmc_bus_put(host);
return err;
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 20b1c0831eac..d9411ed2a39b 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -38,10 +38,11 @@ void mmc_ungate_clock(struct mmc_host *host);
void mmc_set_ungated(struct mmc_host *host);
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
-void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width,
- unsigned int ddr);
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
+int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage,
+ bool cmd11);
void mmc_set_timing(struct mmc_host *host, unsigned int timing);
+void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
static inline void mmc_delay(unsigned int ms)
{
@@ -61,8 +62,6 @@ int mmc_attach_mmc(struct mmc_host *host);
int mmc_attach_sd(struct mmc_host *host);
int mmc_attach_sdio(struct mmc_host *host);
-void mmc_fixup_device(struct mmc_card *card);
-
/* Module parameters */
extern int use_spi_crc;
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 461e6a17fb90..b29d3e8fd3a2 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -325,12 +325,12 @@ int mmc_add_host(struct mmc_host *host)
WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
!host->ops->enable_sdio_irq);
- led_trigger_register_simple(dev_name(&host->class_dev), &host->led);
-
err = device_add(&host->class_dev);
if (err)
return err;
+ led_trigger_register_simple(dev_name(&host->class_dev), &host->led);
+
#ifdef CONFIG_DEBUG_FS
mmc_add_host_debugfs(host);
#endif
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 772d0d0a541b..2a7e43bc796d 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -20,6 +20,7 @@
#include "core.h"
#include "bus.h"
#include "mmc_ops.h"
+#include "sd_ops.h"
static const unsigned int tran_exp[] = {
10000, 100000, 1000000, 10000000,
@@ -173,14 +174,17 @@ static int mmc_decode_csd(struct mmc_card *card)
}
/*
- * Read and decode extended CSD.
+ * Read extended CSD.
*/
-static int mmc_read_ext_csd(struct mmc_card *card)
+static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
{
int err;
u8 *ext_csd;
BUG_ON(!card);
+ BUG_ON(!new_ext_csd);
+
+ *new_ext_csd = NULL;
if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
return 0;
@@ -198,12 +202,15 @@ static int mmc_read_ext_csd(struct mmc_card *card)
err = mmc_send_ext_csd(card, ext_csd);
if (err) {
+ kfree(ext_csd);
+ *new_ext_csd = NULL;
+
/* If the host or the card can't do the switch,
* fail more gracefully. */
if ((err != -EINVAL)
&& (err != -ENOSYS)
&& (err != -EFAULT))
- goto out;
+ return err;
/*
* High capacity cards should have this "magic" size
@@ -221,9 +228,23 @@ static int mmc_read_ext_csd(struct mmc_card *card)
mmc_hostname(card->host));
err = 0;
}
+ } else
+ *new_ext_csd = ext_csd;
- goto out;
- }
+ return err;
+}
+
+/*
+ * Decode extended CSD.
+ */
+static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
+{
+ int err = 0;
+
+ BUG_ON(!card);
+
+ if (!ext_csd)
+ return 0;
/* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */
if (card->csd.structure == 3) {
@@ -288,6 +309,10 @@ static int mmc_read_ext_csd(struct mmc_card *card)
if (card->ext_csd.rev >= 3) {
u8 sa_shift = ext_csd[EXT_CSD_S_A_TIMEOUT];
+ card->ext_csd.part_config = ext_csd[EXT_CSD_PART_CONFIG];
+
+ /* EXT_CSD value is in units of 10ms, but we store in ms */
+ card->ext_csd.part_time = 10 * ext_csd[EXT_CSD_PART_SWITCH_TIME];
/* Sleep / awake timeout in 100ns units */
if (sa_shift > 0 && sa_shift <= 0x17)
@@ -299,6 +324,14 @@ static int mmc_read_ext_csd(struct mmc_card *card)
ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT];
card->ext_csd.hc_erase_size =
ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] << 10;
+
+ card->ext_csd.rel_sectors = ext_csd[EXT_CSD_REL_WR_SEC_C];
+
+ /*
+ * There are two boot regions of equal size, defined in
+ * multiples of 128K.
+ */
+ card->ext_csd.boot_size = ext_csd[EXT_CSD_BOOT_MULT] << 17;
}
if (card->ext_csd.rev >= 4) {
@@ -350,14 +383,78 @@ static int mmc_read_ext_csd(struct mmc_card *card)
ext_csd[EXT_CSD_TRIM_MULT];
}
+ if (card->ext_csd.rev >= 5)
+ card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
+
if (ext_csd[EXT_CSD_ERASED_MEM_CONT])
card->erased_byte = 0xFF;
else
card->erased_byte = 0x0;
out:
+ return err;
+}
+
+static inline void mmc_free_ext_csd(u8 *ext_csd)
+{
kfree(ext_csd);
+}
+
+
+static int mmc_compare_ext_csds(struct mmc_card *card, u8 *ext_csd,
+ unsigned bus_width)
+{
+ u8 *bw_ext_csd;
+ int err;
+
+ err = mmc_get_ext_csd(card, &bw_ext_csd);
+ if (err)
+ return err;
+
+ if ((ext_csd == NULL || bw_ext_csd == NULL)) {
+ if (bus_width != MMC_BUS_WIDTH_1)
+ err = -EINVAL;
+ goto out;
+ }
+ if (bus_width == MMC_BUS_WIDTH_1)
+ goto out;
+
+ /* only compare read only fields */
+ err = (!(ext_csd[EXT_CSD_PARTITION_SUPPORT] ==
+ bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) &&
+ (ext_csd[EXT_CSD_ERASED_MEM_CONT] ==
+ bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) &&
+ (ext_csd[EXT_CSD_REV] ==
+ bw_ext_csd[EXT_CSD_REV]) &&
+ (ext_csd[EXT_CSD_STRUCTURE] ==
+ bw_ext_csd[EXT_CSD_STRUCTURE]) &&
+ (ext_csd[EXT_CSD_CARD_TYPE] ==
+ bw_ext_csd[EXT_CSD_CARD_TYPE]) &&
+ (ext_csd[EXT_CSD_S_A_TIMEOUT] ==
+ bw_ext_csd[EXT_CSD_S_A_TIMEOUT]) &&
+ (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] ==
+ bw_ext_csd[EXT_CSD_HC_WP_GRP_SIZE]) &&
+ (ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT] ==
+ bw_ext_csd[EXT_CSD_ERASE_TIMEOUT_MULT]) &&
+ (ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] ==
+ bw_ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) &&
+ (ext_csd[EXT_CSD_SEC_TRIM_MULT] ==
+ bw_ext_csd[EXT_CSD_SEC_TRIM_MULT]) &&
+ (ext_csd[EXT_CSD_SEC_ERASE_MULT] ==
+ bw_ext_csd[EXT_CSD_SEC_ERASE_MULT]) &&
+ (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] ==
+ bw_ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT]) &&
+ (ext_csd[EXT_CSD_TRIM_MULT] ==
+ bw_ext_csd[EXT_CSD_TRIM_MULT]) &&
+ memcmp(&ext_csd[EXT_CSD_SEC_CNT],
+ &bw_ext_csd[EXT_CSD_SEC_CNT],
+ 4) != 0);
+ if (err)
+ err = -EINVAL;
+
+out:
+ mmc_free_ext_csd(bw_ext_csd);
return err;
}
@@ -422,6 +519,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
u32 cid[4];
unsigned int max_dtr;
u32 rocr;
+ u8 *ext_csd = NULL;
BUG_ON(!host);
WARN_ON(!host->claimed);
@@ -520,7 +618,11 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
/*
* Fetch and process extended CSD.
*/
- err = mmc_read_ext_csd(card);
+
+ err = mmc_get_ext_csd(card, &ext_csd);
+ if (err)
+ goto free_card;
+ err = mmc_read_ext_csd(card, ext_csd);
if (err)
goto free_card;
@@ -542,7 +644,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
*/
if (card->ext_csd.enhanced_area_en) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_ERASE_GROUP_DEF, 1);
+ EXT_CSD_ERASE_GROUP_DEF, 1, 0);
if (err && err != -EBADMSG)
goto free_card;
@@ -568,12 +670,24 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
}
/*
+ * Ensure eMMC user default partition is enabled
+ */
+ if (card->ext_csd.part_config & EXT_CSD_PART_CONFIG_ACC_MASK) {
+ card->ext_csd.part_config &= ~EXT_CSD_PART_CONFIG_ACC_MASK;
+ err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONFIG,
+ card->ext_csd.part_config,
+ card->ext_csd.part_time);
+ if (err && err != -EBADMSG)
+ goto free_card;
+ }
+
+ /*
* Activate high speed (if supported)
*/
if ((card->ext_csd.hs_max_dtr != 0) &&
(host->caps & MMC_CAP_MMC_HIGHSPEED)) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_HS_TIMING, 1);
+ EXT_CSD_HS_TIMING, 1, 0);
if (err && err != -EBADMSG)
goto free_card;
@@ -606,10 +720,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
*/
if (mmc_card_highspeed(card)) {
if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
- && (host->caps & (MMC_CAP_1_8V_DDR)))
+ && ((host->caps & (MMC_CAP_1_8V_DDR |
+ MMC_CAP_UHS_DDR50))
+ == (MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50)))
ddr = MMC_1_8V_DDR_MODE;
else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
- && (host->caps & (MMC_CAP_1_2V_DDR)))
+ && ((host->caps & (MMC_CAP_1_2V_DDR |
+ MMC_CAP_UHS_DDR50))
+ == (MMC_CAP_1_2V_DDR | MMC_CAP_UHS_DDR50)))
ddr = MMC_1_2V_DDR_MODE;
}
@@ -640,18 +758,22 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
ddr = 0; /* no DDR for 1-bit width */
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
- ext_csd_bits[idx][0]);
+ ext_csd_bits[idx][0],
+ 0);
if (!err) {
- mmc_set_bus_width_ddr(card->host,
- bus_width, MMC_SDR_MODE);
+ mmc_set_bus_width(card->host, bus_width);
+
/*
* If controller can't handle bus width test,
- * use the highest bus width to maintain
- * compatibility with previous MMC behavior.
+ * compare ext_csd previously read in 1 bit mode
+ * against ext_csd at new bus width
*/
if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
- break;
- err = mmc_bus_test(card, bus_width);
+ err = mmc_compare_ext_csds(card,
+ ext_csd,
+ bus_width);
+ else
+ err = mmc_bus_test(card, bus_width);
if (!err)
break;
}
@@ -659,8 +781,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
if (!err && ddr) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
- EXT_CSD_BUS_WIDTH,
- ext_csd_bits[idx][1]);
+ EXT_CSD_BUS_WIDTH,
+ ext_csd_bits[idx][1],
+ 0);
}
if (err) {
printk(KERN_WARNING "%s: switch to bus width %d ddr %d "
@@ -668,20 +791,43 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
1 << bus_width, ddr);
goto free_card;
} else if (ddr) {
+ /*
+ * eMMC cards can support 3.3V to 1.2V i/o (vccq)
+ * signaling.
+ *
+ * EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
+ *
+ * 1.8V vccq at 3.3V core voltage (vcc) is not required
+ * in the JEDEC spec for DDR.
+ *
+ * Do not force change in vccq since we are obviously
+ * working and no change to vccq is needed.
+ *
+ * WARNING: eMMC rules are NOT the same as SD DDR
+ */
+ if (ddr == EXT_CSD_CARD_TYPE_DDR_1_2V) {
+ err = mmc_set_signal_voltage(host,
+ MMC_SIGNAL_VOLTAGE_120, 0);
+ if (err)
+ goto err;
+ }
mmc_card_set_ddr_mode(card);
- mmc_set_bus_width_ddr(card->host, bus_width, ddr);
+ mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
+ mmc_set_bus_width(card->host, bus_width);
}
}
if (!oldcard)
host->card = card;
+ mmc_free_ext_csd(ext_csd);
return 0;
free_card:
if (!oldcard)
mmc_remove_card(card);
err:
+ mmc_free_ext_csd(ext_csd);
return err;
}
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index f3b22bf89cc9..845ce7c533b9 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -23,12 +23,10 @@
static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
{
int err;
- struct mmc_command cmd;
+ struct mmc_command cmd = {0};
BUG_ON(!host);
- memset(&cmd, 0, sizeof(struct mmc_command));
-
cmd.opcode = MMC_SELECT_CARD;
if (card) {
@@ -60,15 +58,13 @@ int mmc_deselect_cards(struct mmc_host *host)
int mmc_card_sleepawake(struct mmc_host *host, int sleep)
{
- struct mmc_command cmd;
+ struct mmc_command cmd = {0};
struct mmc_card *card = host->card;
int err;
if (sleep)
mmc_deselect_cards(host);
- memset(&cmd, 0, sizeof(struct mmc_command));
-
cmd.opcode = MMC_SLEEP_AWAKE;
cmd.arg = card->rca << 16;
if (sleep)
@@ -97,7 +93,7 @@ int mmc_card_sleepawake(struct mmc_host *host, int sleep)
int mmc_go_idle(struct mmc_host *host)
{
int err;
- struct mmc_command cmd;
+ struct mmc_command cmd = {0};
/*
* Non-SPI hosts need to prevent chipselect going active during
@@ -113,8 +109,6 @@ int mmc_go_idle(struct mmc_host *host)
mmc_delay(1);
}
- memset(&cmd, 0, sizeof(struct mmc_command));
-
cmd.opcode = MMC_GO_IDLE_STATE;
cmd.arg = 0;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;
@@ -135,13 +129,11 @@ int mmc_go_idle(struct mmc_host *host)
int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
{
- struct mmc_command cmd;
+ struct mmc_command cmd = {0};
int i, err = 0;
BUG_ON(!host);
- memset(&cmd, 0, sizeof(struct mmc_command));
-
cmd.opcode = MMC_SEND_OP_COND;
cmd.arg = mmc_host_is_spi(host) ? 0 : ocr;
cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR;
@@ -178,13 +170,11 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
{
int err;
- struct mmc_command cmd;
+ struct mmc_command cmd = {0};
BUG_ON(!host);
BUG_ON(!cid);
- memset(&cmd, 0, sizeof(struct mmc_command));
-
cmd.opcode = MMC_ALL_SEND_CID;
cmd.arg = 0;
cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
@@ -201,13 +191,11 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid)
int mmc_set_relative_addr(struct mmc_card *card)
{
int err;
- struct mmc_command cmd;
+ struct mmc_command cmd = {0};
BUG_ON(!card);
BUG_ON(!card->host);
- memset(&cmd, 0, sizeof(struct mmc_command));
-
cmd.opcode = MMC_SET_RELATIVE_ADDR;
cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
@@ -223,13 +211,11 @@ static int
mmc_send_cxd_native(struct mmc_host *host, u32 arg, u32 *cxd, int opcode)
{
int err;
- struct mmc_command cmd;
+ struct mmc_command cmd = {0};
BUG_ON(!host);
BUG_ON(!cxd);
- memset(&cmd, 0, sizeof(struct mmc_command));
-
cmd.opcode = opcode;
cmd.arg = arg;
cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
@@ -247,9 +233,9 @@ static int
mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
u32 opcode, void *buf, unsigned len)
{
- struct mmc_request mrq;
- struct mmc_command cmd;
- struct mmc_data data;
+ struct mmc_request mrq = {0};
+ struct mmc_command cmd = {0};
+ struct mmc_data data = {0};
struct scatterlist sg;
void *data_buf;
@@ -260,10 +246,6 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
if (data_buf == NULL)
return -ENOMEM;
- memset(&mrq, 0, sizeof(struct mmc_request));
- memset(&cmd, 0, sizeof(struct mmc_command));
- memset(&data, 0, sizeof(struct mmc_data));
-
mrq.cmd = &cmd;
mrq.data = &data;
@@ -355,11 +337,9 @@ int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
{
- struct mmc_command cmd;
+ struct mmc_command cmd = {0};
int err;
- memset(&cmd, 0, sizeof(struct mmc_command));
-
cmd.opcode = MMC_SPI_READ_OCR;
cmd.arg = highcap ? (1 << 30) : 0;
cmd.flags = MMC_RSP_SPI_R3;
@@ -372,11 +352,9 @@ int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
{
- struct mmc_command cmd;
+ struct mmc_command cmd = {0};
int err;
- memset(&cmd, 0, sizeof(struct mmc_command));
-
cmd.opcode = MMC_SPI_CRC_ON_OFF;
cmd.flags = MMC_RSP_SPI_R1;
cmd.arg = use_crc;
@@ -387,23 +365,34 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
return err;
}
-int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
+/**
+ * mmc_switch - modify EXT_CSD register
+ * @card: the MMC card associated with the data transfer
+ * @set: cmd set values
+ * @index: EXT_CSD register index
+ * @value: value to program into EXT_CSD register
+ * @timeout_ms: timeout (ms) for operation performed by register write,
+ * timeout of zero implies maximum possible timeout
+ *
+ * Modifies the EXT_CSD register for selected card.
+ */
+int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
+ unsigned int timeout_ms)
{
int err;
- struct mmc_command cmd;
+ struct mmc_command cmd = {0};
u32 status;
BUG_ON(!card);
BUG_ON(!card->host);
- memset(&cmd, 0, sizeof(struct mmc_command));
-
cmd.opcode = MMC_SWITCH;
cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
(index << 16) |
(value << 8) |
set;
cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+ cmd.cmd_timeout_ms = timeout_ms;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
if (err)
@@ -433,17 +422,16 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value)
return 0;
}
+EXPORT_SYMBOL_GPL(mmc_switch);
int mmc_send_status(struct mmc_card *card, u32 *status)
{
int err;
- struct mmc_command cmd;
+ struct mmc_command cmd = {0};
BUG_ON(!card);
BUG_ON(!card->host);
- memset(&cmd, 0, sizeof(struct mmc_command));
-
cmd.opcode = MMC_SEND_STATUS;
if (!mmc_host_is_spi(card->host))
cmd.arg = card->rca << 16;
@@ -466,9 +454,9 @@ static int
mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
u8 len)
{
- struct mmc_request mrq;
- struct mmc_command cmd;
- struct mmc_data data;
+ struct mmc_request mrq = {0};
+ struct mmc_command cmd = {0};
+ struct mmc_data data = {0};
struct scatterlist sg;
u8 *data_buf;
u8 *test_buf;
@@ -497,10 +485,6 @@ mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
if (opcode == MMC_BUS_TEST_W)
memcpy(data_buf, test_buf, len);
- memset(&mrq, 0, sizeof(struct mmc_request));
- memset(&cmd, 0, sizeof(struct mmc_command));
- memset(&data, 0, sizeof(struct mmc_data));
-
mrq.cmd = &cmd;
mrq.data = &data;
cmd.opcode = opcode;
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index e6d44b8a18db..9276946fa5b7 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -20,7 +20,6 @@ int mmc_all_send_cid(struct mmc_host *host, u32 *cid);
int mmc_set_relative_addr(struct mmc_card *card);
int mmc_send_csd(struct mmc_card *card, u32 *csd);
int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
-int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value);
int mmc_send_status(struct mmc_card *card, u32 *status);
int mmc_send_cid(struct mmc_host *host, u32 *cid);
int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
diff --git a/drivers/mmc/core/quirks.c b/drivers/mmc/core/quirks.c
index 11118b74eb20..3a596217029e 100644
--- a/drivers/mmc/core/quirks.c
+++ b/drivers/mmc/core/quirks.c
@@ -1,7 +1,8 @@
/*
- * This file contains work-arounds for many known sdio hardware
- * bugs.
+ * This file contains work-arounds for many known SD/MMC
+ * and SDIO hardware bugs.
*
+ * Copyright (c) 2011 Andrei Warkentin <andreiw@motorola.com>
* Copyright (c) 2011 Pierre Tardy <tardyp@gmail.com>
* Inspired from pci fixup code:
* Copyright (c) 1999 Martin Mares <mj@ucw.cz>
@@ -11,34 +12,14 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/mmc/card.h>
-#include <linux/mod_devicetable.h>
-/*
- * The world is not perfect and supplies us with broken mmc/sdio devices.
- * For at least a part of these bugs we need a work-around
- */
-
-struct mmc_fixup {
- u16 vendor, device; /* You can use SDIO_ANY_ID here of course */
- void (*vendor_fixup)(struct mmc_card *card, int data);
- int data;
-};
-
-/*
- * This hook just adds a quirk unconditionnally
- */
-static void __maybe_unused add_quirk(struct mmc_card *card, int data)
-{
- card->quirks |= data;
-}
+#ifndef SDIO_VENDOR_ID_TI
+#define SDIO_VENDOR_ID_TI 0x0097
+#endif
-/*
- * This hook just removes a quirk unconditionnally
- */
-static void __maybe_unused remove_quirk(struct mmc_card *card, int data)
-{
- card->quirks &= ~data;
-}
+#ifndef SDIO_DEVICE_ID_TI_WL1271
+#define SDIO_DEVICE_ID_TI_WL1271 0x4076
+#endif
/*
* This hook just adds a quirk for all sdio devices
@@ -49,33 +30,47 @@ static void add_quirk_for_sdio_devices(struct mmc_card *card, int data)
card->quirks |= data;
}
-#ifndef SDIO_VENDOR_ID_TI
-#define SDIO_VENDOR_ID_TI 0x0097
-#endif
-
-#ifndef SDIO_DEVICE_ID_TI_WL1271
-#define SDIO_DEVICE_ID_TI_WL1271 0x4076
-#endif
-
static const struct mmc_fixup mmc_fixup_methods[] = {
/* by default sdio devices are considered CLK_GATING broken */
/* good cards will be whitelisted as they are tested */
- { SDIO_ANY_ID, SDIO_ANY_ID,
- add_quirk_for_sdio_devices, MMC_QUIRK_BROKEN_CLK_GATING },
- { SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
- remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING },
- { 0 }
+ SDIO_FIXUP(SDIO_ANY_ID, SDIO_ANY_ID,
+ add_quirk_for_sdio_devices,
+ MMC_QUIRK_BROKEN_CLK_GATING),
+
+ SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
+ remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING),
+
+ SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
+ add_quirk, MMC_QUIRK_NONSTD_FUNC_IF),
+
+ SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271,
+ add_quirk, MMC_QUIRK_DISABLE_CD),
+
+ END_FIXUP
};
-void mmc_fixup_device(struct mmc_card *card)
+void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table)
{
const struct mmc_fixup *f;
+ u64 rev = cid_rev_card(card);
+
+ /* Non-core specific workarounds. */
+ if (!table)
+ table = mmc_fixup_methods;
- for (f = mmc_fixup_methods; f->vendor_fixup; f++) {
- if ((f->vendor == card->cis.vendor
- || f->vendor == (u16) SDIO_ANY_ID) &&
- (f->device == card->cis.device
- || f->device == (u16) SDIO_ANY_ID)) {
+ for (f = table; f->vendor_fixup; f++) {
+ if ((f->manfid == CID_MANFID_ANY ||
+ f->manfid == card->cid.manfid) &&
+ (f->oemid == CID_OEMID_ANY ||
+ f->oemid == card->cid.oemid) &&
+ (f->name == CID_NAME_ANY ||
+ !strncmp(f->name, card->cid.prod_name,
+ sizeof(card->cid.prod_name))) &&
+ (f->cis_vendor == card->cis.vendor ||
+ f->cis_vendor == (u16) SDIO_ANY_ID) &&
+ (f->cis_device == card->cis.device ||
+ f->cis_device == (u16) SDIO_ANY_ID) &&
+ rev >= f->rev_start && rev <= f->rev_end) {
dev_dbg(&card->dev, "calling %pF\n", f->vendor_fixup);
f->vendor_fixup(card, f->data);
}
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 6dac89fe0535..ff2774128aa9 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -130,7 +130,7 @@ static int mmc_decode_csd(struct mmc_card *card)
break;
case 1:
/*
- * This is a block-addressed SDHC card. Most
+ * This is a block-addressed SDHC or SDXC card. Most
* interesting fields are unused and have fixed
* values. To avoid getting tripped by buggy cards,
* we assume those fixed values ourselves.
@@ -144,6 +144,11 @@ static int mmc_decode_csd(struct mmc_card *card)
e = UNSTUFF_BITS(resp, 96, 3);
csd->max_dtr = tran_exp[e] * tran_mant[m];
csd->cmdclass = UNSTUFF_BITS(resp, 84, 12);
+ csd->c_size = UNSTUFF_BITS(resp, 48, 22);
+
+ /* SDXC cards have a minimum C_SIZE of 0x00FFFF */
+ if (csd->c_size >= 0xFFFF)
+ mmc_card_set_ext_capacity(card);
m = UNSTUFF_BITS(resp, 48, 22);
csd->capacity = (1 + m) << 10;
@@ -189,12 +194,17 @@ static int mmc_decode_scr(struct mmc_card *card)
scr->sda_vsn = UNSTUFF_BITS(resp, 56, 4);
scr->bus_widths = UNSTUFF_BITS(resp, 48, 4);
+ if (scr->sda_vsn == SCR_SPEC_VER_2)
+ /* Check if Physical Layer Spec v3.0 is supported */
+ scr->sda_spec3 = UNSTUFF_BITS(resp, 47, 1);
if (UNSTUFF_BITS(resp, 55, 1))
card->erased_byte = 0xFF;
else
card->erased_byte = 0x0;
+ if (scr->sda_spec3)
+ scr->cmds = UNSTUFF_BITS(resp, 32, 2);
return 0;
}
@@ -274,29 +284,74 @@ static int mmc_read_switch(struct mmc_card *card)
status = kmalloc(64, GFP_KERNEL);
if (!status) {
printk(KERN_ERR "%s: could not allocate a buffer for "
- "switch capabilities.\n", mmc_hostname(card->host));
+ "switch capabilities.\n",
+ mmc_hostname(card->host));
return -ENOMEM;
}
+ /* Find out the supported Bus Speed Modes. */
err = mmc_sd_switch(card, 0, 0, 1, status);
if (err) {
- /* If the host or the card can't do the switch,
- * fail more gracefully. */
- if ((err != -EINVAL)
- && (err != -ENOSYS)
- && (err != -EFAULT))
+ /*
+ * If the host or the card can't do the switch,
+ * fail more gracefully.
+ */
+ if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
goto out;
- printk(KERN_WARNING "%s: problem reading switch "
- "capabilities, performance might suffer.\n",
+ printk(KERN_WARNING "%s: problem reading Bus Speed modes.\n",
mmc_hostname(card->host));
err = 0;
goto out;
}
- if (status[13] & 0x02)
- card->sw_caps.hs_max_dtr = 50000000;
+ if (card->scr.sda_spec3) {
+ card->sw_caps.sd3_bus_mode = status[13];
+
+ /* Find out Driver Strengths supported by the card */
+ err = mmc_sd_switch(card, 0, 2, 1, status);
+ if (err) {
+ /*
+ * If the host or the card can't do the switch,
+ * fail more gracefully.
+ */
+ if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
+ goto out;
+
+ printk(KERN_WARNING "%s: problem reading "
+ "Driver Strength.\n",
+ mmc_hostname(card->host));
+ err = 0;
+
+ goto out;
+ }
+
+ card->sw_caps.sd3_drv_type = status[9];
+
+ /* Find out Current Limits supported by the card */
+ err = mmc_sd_switch(card, 0, 3, 1, status);
+ if (err) {
+ /*
+ * If the host or the card can't do the switch,
+ * fail more gracefully.
+ */
+ if (err != -EINVAL && err != -ENOSYS && err != -EFAULT)
+ goto out;
+
+ printk(KERN_WARNING "%s: problem reading "
+ "Current Limit.\n",
+ mmc_hostname(card->host));
+ err = 0;
+
+ goto out;
+ }
+
+ card->sw_caps.sd3_curr_limit = status[7];
+ } else {
+ if (status[13] & 0x02)
+ card->sw_caps.hs_max_dtr = 50000000;
+ }
out:
kfree(status);
@@ -352,6 +407,232 @@ out:
return err;
}
+static int sd_select_driver_type(struct mmc_card *card, u8 *status)
+{
+ int host_drv_type = 0, card_drv_type = 0;
+ int err;
+
+ /*
+ * If the host doesn't support any of the Driver Types A,C or D,
+ * default Driver Type B is used.
+ */
+ if (!(card->host->caps & (MMC_CAP_DRIVER_TYPE_A | MMC_CAP_DRIVER_TYPE_C
+ | MMC_CAP_DRIVER_TYPE_D)))
+ return 0;
+
+ if (card->host->caps & MMC_CAP_DRIVER_TYPE_A) {
+ host_drv_type = MMC_SET_DRIVER_TYPE_A;
+ if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_A)
+ card_drv_type = MMC_SET_DRIVER_TYPE_A;
+ else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_B)
+ card_drv_type = MMC_SET_DRIVER_TYPE_B;
+ else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
+ card_drv_type = MMC_SET_DRIVER_TYPE_C;
+ } else if (card->host->caps & MMC_CAP_DRIVER_TYPE_C) {
+ host_drv_type = MMC_SET_DRIVER_TYPE_C;
+ if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
+ card_drv_type = MMC_SET_DRIVER_TYPE_C;
+ } else if (!(card->host->caps & MMC_CAP_DRIVER_TYPE_D)) {
+ /*
+ * If we are here, that means only the default driver type
+ * B is supported by the host.
+ */
+ host_drv_type = MMC_SET_DRIVER_TYPE_B;
+ if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_B)
+ card_drv_type = MMC_SET_DRIVER_TYPE_B;
+ else if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C)
+ card_drv_type = MMC_SET_DRIVER_TYPE_C;
+ }
+
+ err = mmc_sd_switch(card, 1, 2, card_drv_type, status);
+ if (err)
+ return err;
+
+ if ((status[15] & 0xF) != card_drv_type) {
+ printk(KERN_WARNING "%s: Problem setting driver strength!\n",
+ mmc_hostname(card->host));
+ return 0;
+ }
+
+ mmc_set_driver_type(card->host, host_drv_type);
+
+ return 0;
+}
+
+static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
+{
+ unsigned int bus_speed = 0, timing = 0;
+ int err;
+
+ /*
+ * If the host doesn't support any of the UHS-I modes, fallback on
+ * default speed.
+ */
+ if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50)))
+ return 0;
+
+ if ((card->host->caps & MMC_CAP_UHS_SDR104) &&
+ (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) {
+ bus_speed = UHS_SDR104_BUS_SPEED;
+ timing = MMC_TIMING_UHS_SDR104;
+ card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR;
+ } else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
+ (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) {
+ bus_speed = UHS_DDR50_BUS_SPEED;
+ timing = MMC_TIMING_UHS_DDR50;
+ card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR;
+ } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
+ MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
+ SD_MODE_UHS_SDR50)) {
+ bus_speed = UHS_SDR50_BUS_SPEED;
+ timing = MMC_TIMING_UHS_SDR50;
+ card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
+ } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
+ (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
+ bus_speed = UHS_SDR25_BUS_SPEED;
+ timing = MMC_TIMING_UHS_SDR25;
+ card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
+ } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
+ MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode &
+ SD_MODE_UHS_SDR12)) {
+ bus_speed = UHS_SDR12_BUS_SPEED;
+ timing = MMC_TIMING_UHS_SDR12;
+ card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR;
+ }
+
+ card->sd_bus_speed = bus_speed;
+ err = mmc_sd_switch(card, 1, 0, bus_speed, status);
+ if (err)
+ return err;
+
+ if ((status[16] & 0xF) != bus_speed)
+ printk(KERN_WARNING "%s: Problem setting bus speed mode!\n",
+ mmc_hostname(card->host));
+ else {
+ mmc_set_timing(card->host, timing);
+ mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr);
+ }
+
+ return 0;
+}
+
+static int sd_set_current_limit(struct mmc_card *card, u8 *status)
+{
+ int current_limit = 0;
+ int err;
+
+ /*
+ * Current limit switch is only defined for SDR50, SDR104, and DDR50
+ * bus speed modes. For other bus speed modes, we set the default
+ * current limit of 200mA.
+ */
+ if ((card->sd_bus_speed == UHS_SDR50_BUS_SPEED) ||
+ (card->sd_bus_speed == UHS_SDR104_BUS_SPEED) ||
+ (card->sd_bus_speed == UHS_DDR50_BUS_SPEED)) {
+ if (card->host->caps & MMC_CAP_MAX_CURRENT_800) {
+ if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_800)
+ current_limit = SD_SET_CURRENT_LIMIT_800;
+ else if (card->sw_caps.sd3_curr_limit &
+ SD_MAX_CURRENT_600)
+ current_limit = SD_SET_CURRENT_LIMIT_600;
+ else if (card->sw_caps.sd3_curr_limit &
+ SD_MAX_CURRENT_400)
+ current_limit = SD_SET_CURRENT_LIMIT_400;
+ else if (card->sw_caps.sd3_curr_limit &
+ SD_MAX_CURRENT_200)
+ current_limit = SD_SET_CURRENT_LIMIT_200;
+ } else if (card->host->caps & MMC_CAP_MAX_CURRENT_600) {
+ if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_600)
+ current_limit = SD_SET_CURRENT_LIMIT_600;
+ else if (card->sw_caps.sd3_curr_limit &
+ SD_MAX_CURRENT_400)
+ current_limit = SD_SET_CURRENT_LIMIT_400;
+ else if (card->sw_caps.sd3_curr_limit &
+ SD_MAX_CURRENT_200)
+ current_limit = SD_SET_CURRENT_LIMIT_200;
+ } else if (card->host->caps & MMC_CAP_MAX_CURRENT_400) {
+ if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_400)
+ current_limit = SD_SET_CURRENT_LIMIT_400;
+ else if (card->sw_caps.sd3_curr_limit &
+ SD_MAX_CURRENT_200)
+ current_limit = SD_SET_CURRENT_LIMIT_200;
+ } else if (card->host->caps & MMC_CAP_MAX_CURRENT_200) {
+ if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_200)
+ current_limit = SD_SET_CURRENT_LIMIT_200;
+ }
+ } else
+ current_limit = SD_SET_CURRENT_LIMIT_200;
+
+ err = mmc_sd_switch(card, 1, 3, current_limit, status);
+ if (err)
+ return err;
+
+ if (((status[15] >> 4) & 0x0F) != current_limit)
+ printk(KERN_WARNING "%s: Problem setting current limit!\n",
+ mmc_hostname(card->host));
+
+ return 0;
+}
+
+/*
+ * UHS-I specific initialization procedure
+ */
+static int mmc_sd_init_uhs_card(struct mmc_card *card)
+{
+ int err;
+ u8 *status;
+
+ if (!card->scr.sda_spec3)
+ return 0;
+
+ if (!(card->csd.cmdclass & CCC_SWITCH))
+ return 0;
+
+ status = kmalloc(64, GFP_KERNEL);
+ if (!status) {
+ printk(KERN_ERR "%s: could not allocate a buffer for "
+ "switch capabilities.\n", mmc_hostname(card->host));
+ return -ENOMEM;
+ }
+
+ /* Set 4-bit bus width */
+ if ((card->host->caps & MMC_CAP_4_BIT_DATA) &&
+ (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
+ err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
+ if (err)
+ goto out;
+
+ mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
+ }
+
+ /* Set the driver strength for the card */
+ err = sd_select_driver_type(card, status);
+ if (err)
+ goto out;
+
+ /* Set bus speed mode of the card */
+ err = sd_set_bus_speed_mode(card, status);
+ if (err)
+ goto out;
+
+ /* Set current limit for the card */
+ err = sd_set_current_limit(card, status);
+ if (err)
+ goto out;
+
+ /* SPI mode doesn't define CMD19 */
+ if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning)
+ err = card->host->ops->execute_tuning(card->host);
+
+out:
+ kfree(status);
+
+ return err;
+}
+
MMC_DEV_ATTR(cid, "%08x%08x%08x%08x\n", card->raw_cid[0], card->raw_cid[1],
card->raw_cid[2], card->raw_cid[3]);
MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
@@ -400,7 +681,7 @@ struct device_type sd_type = {
/*
* Fetch CID from card.
*/
-int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid)
+int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
{
int err;
@@ -420,12 +701,39 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid)
*/
err = mmc_send_if_cond(host, ocr);
if (!err)
- ocr |= 1 << 30;
+ ocr |= SD_OCR_CCS;
+
+ /*
+ * If the host supports one of UHS-I modes, request the card
+ * to switch to 1.8V signaling level.
+ */
+ if (host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))
+ ocr |= SD_OCR_S18R;
+
+ /* If the host can supply more than 150mA, XPC should be set to 1. */
+ if (host->caps & (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
+ MMC_CAP_SET_XPC_180))
+ ocr |= SD_OCR_XPC;
- err = mmc_send_app_op_cond(host, ocr, NULL);
+try_again:
+ err = mmc_send_app_op_cond(host, ocr, rocr);
if (err)
return err;
+ /*
+ * In case CCS and S18A in the response is set, start Signal Voltage
+ * Switch procedure. SPI mode doesn't support CMD11.
+ */
+ if (!mmc_host_is_spi(host) && rocr &&
+ ((*rocr & 0x41000000) == 0x41000000)) {
+ err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, true);
+ if (err) {
+ ocr &= ~SD_OCR_S18R;
+ goto try_again;
+ }
+ }
+
if (mmc_host_is_spi(host))
err = mmc_send_cid(host, cid);
else
@@ -553,11 +861,12 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
struct mmc_card *card;
int err;
u32 cid[4];
+ u32 rocr = 0;
BUG_ON(!host);
WARN_ON(!host->claimed);
- err = mmc_sd_get_cid(host, ocr, cid);
+ err = mmc_sd_get_cid(host, ocr, cid, &rocr);
if (err)
return err;
@@ -610,30 +919,47 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
if (err)
goto free_card;
- /*
- * Attempt to change to high-speed (if supported)
- */
- err = mmc_sd_switch_hs(card);
- if (err > 0)
- mmc_sd_go_highspeed(card);
- else if (err)
- goto free_card;
+ /* Initialization sequence for UHS-I cards */
+ if (rocr & SD_ROCR_S18A) {
+ err = mmc_sd_init_uhs_card(card);
+ if (err)
+ goto free_card;
- /*
- * Set bus speed.
- */
- mmc_set_clock(host, mmc_sd_get_max_clock(card));
+ /* Card is an ultra-high-speed card */
+ mmc_sd_card_set_uhs(card);
- /*
- * Switch to wider bus (if supported).
- */
- if ((host->caps & MMC_CAP_4_BIT_DATA) &&
- (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
- err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
- if (err)
+ /*
+ * Since initialization is now complete, enable preset
+ * value registers for UHS-I cards.
+ */
+ if (host->ops->enable_preset_value)
+ host->ops->enable_preset_value(host, true);
+ } else {
+ /*
+ * Attempt to change to high-speed (if supported)
+ */
+ err = mmc_sd_switch_hs(card);
+ if (err > 0)
+ mmc_sd_go_highspeed(card);
+ else if (err)
goto free_card;
- mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
+ /*
+ * Set bus speed.
+ */
+ mmc_set_clock(host, mmc_sd_get_max_clock(card));
+
+ /*
+ * Switch to wider bus (if supported).
+ */
+ if ((host->caps & MMC_CAP_4_BIT_DATA) &&
+ (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
+ err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4);
+ if (err)
+ goto free_card;
+
+ mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
+ }
}
host->card = card;
@@ -773,6 +1099,15 @@ int mmc_attach_sd(struct mmc_host *host)
BUG_ON(!host);
WARN_ON(!host->claimed);
+ /* Make sure we are at 3.3V signalling voltage */
+ err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, false);
+ if (err)
+ return err;
+
+ /* Disable preset value enable if already set since last time */
+ if (host->ops->enable_preset_value)
+ host->ops->enable_preset_value(host, false);
+
err = mmc_send_app_op_cond(host, 0, &ocr);
if (err)
return err;
diff --git a/drivers/mmc/core/sd.h b/drivers/mmc/core/sd.h
index 3d8800fa7600..4b34b24f3f76 100644
--- a/drivers/mmc/core/sd.h
+++ b/drivers/mmc/core/sd.h
@@ -5,7 +5,7 @@
extern struct device_type sd_type;
-int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid);
+int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr);
int mmc_sd_get_csd(struct mmc_host *host, struct mmc_card *card);
void mmc_decode_cid(struct mmc_card *card);
int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
diff --git a/drivers/mmc/core/sd_ops.c b/drivers/mmc/core/sd_ops.c
index 76af349c14b4..021fed153804 100644
--- a/drivers/mmc/core/sd_ops.c
+++ b/drivers/mmc/core/sd_ops.c
@@ -21,10 +21,10 @@
#include "core.h"
#include "sd_ops.h"
-static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
+int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
{
int err;
- struct mmc_command cmd;
+ struct mmc_command cmd = {0};
BUG_ON(!host);
BUG_ON(card && (card->host != host));
@@ -49,6 +49,7 @@ static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
return 0;
}
+EXPORT_SYMBOL_GPL(mmc_app_cmd);
/**
* mmc_wait_for_app_cmd - start an application command and wait for
@@ -66,7 +67,7 @@ static int mmc_app_cmd(struct mmc_host *host, struct mmc_card *card)
int mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card,
struct mmc_command *cmd, int retries)
{
- struct mmc_request mrq;
+ struct mmc_request mrq = {0};
int i, err;
@@ -119,13 +120,11 @@ EXPORT_SYMBOL(mmc_wait_for_app_cmd);
int mmc_app_set_bus_width(struct mmc_card *card, int width)
{
int err;
- struct mmc_command cmd;
+ struct mmc_command cmd = {0};
BUG_ON(!card);
BUG_ON(!card->host);
- memset(&cmd, 0, sizeof(struct mmc_command));
-
cmd.opcode = SD_APP_SET_BUS_WIDTH;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
@@ -149,13 +148,11 @@ int mmc_app_set_bus_width(struct mmc_card *card, int width)
int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
{
- struct mmc_command cmd;
+ struct mmc_command cmd = {0};
int i, err = 0;
BUG_ON(!host);
- memset(&cmd, 0, sizeof(struct mmc_command));
-
cmd.opcode = SD_APP_OP_COND;
if (mmc_host_is_spi(host))
cmd.arg = ocr & (1 << 30); /* SPI only defines one bit */
@@ -194,7 +191,7 @@ int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
{
- struct mmc_command cmd;
+ struct mmc_command cmd = {0};
int err;
static const u8 test_pattern = 0xAA;
u8 result_pattern;
@@ -226,13 +223,11 @@ int mmc_send_if_cond(struct mmc_host *host, u32 ocr)
int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
{
int err;
- struct mmc_command cmd;
+ struct mmc_command cmd = {0};
BUG_ON(!host);
BUG_ON(!rca);
- memset(&cmd, 0, sizeof(struct mmc_command));
-
cmd.opcode = SD_SEND_RELATIVE_ADDR;
cmd.arg = 0;
cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
@@ -249,9 +244,9 @@ int mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca)
int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
{
int err;
- struct mmc_request mrq;
- struct mmc_command cmd;
- struct mmc_data data;
+ struct mmc_request mrq = {0};
+ struct mmc_command cmd = {0};
+ struct mmc_data data = {0};
struct scatterlist sg;
void *data_buf;
@@ -272,10 +267,6 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
if (data_buf == NULL)
return -ENOMEM;
- memset(&mrq, 0, sizeof(struct mmc_request));
- memset(&cmd, 0, sizeof(struct mmc_command));
- memset(&data, 0, sizeof(struct mmc_data));
-
mrq.cmd = &cmd;
mrq.data = &data;
@@ -312,9 +303,9 @@ int mmc_app_send_scr(struct mmc_card *card, u32 *scr)
int mmc_sd_switch(struct mmc_card *card, int mode, int group,
u8 value, u8 *resp)
{
- struct mmc_request mrq;
- struct mmc_command cmd;
- struct mmc_data data;
+ struct mmc_request mrq = {0};
+ struct mmc_command cmd = {0};
+ struct mmc_data data = {0};
struct scatterlist sg;
BUG_ON(!card);
@@ -325,10 +316,6 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group,
mode = !!mode;
value &= 0xF;
- memset(&mrq, 0, sizeof(struct mmc_request));
- memset(&cmd, 0, sizeof(struct mmc_command));
- memset(&data, 0, sizeof(struct mmc_data));
-
mrq.cmd = &cmd;
mrq.data = &data;
@@ -361,9 +348,9 @@ int mmc_sd_switch(struct mmc_card *card, int mode, int group,
int mmc_app_sd_status(struct mmc_card *card, void *ssr)
{
int err;
- struct mmc_request mrq;
- struct mmc_command cmd;
- struct mmc_data data;
+ struct mmc_request mrq = {0};
+ struct mmc_command cmd = {0};
+ struct mmc_data data = {0};
struct scatterlist sg;
BUG_ON(!card);
@@ -376,10 +363,6 @@ int mmc_app_sd_status(struct mmc_card *card, void *ssr)
if (err)
return err;
- memset(&mrq, 0, sizeof(struct mmc_request));
- memset(&cmd, 0, sizeof(struct mmc_command));
- memset(&data, 0, sizeof(struct mmc_data));
-
mrq.cmd = &cmd;
mrq.data = &data;
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index db0f0b44d684..4d0c15bfa514 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -16,6 +16,7 @@
#include <linux/mmc/card.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
#include "core.h"
#include "bus.h"
@@ -31,6 +32,11 @@ static int sdio_read_fbr(struct sdio_func *func)
int ret;
unsigned char data;
+ if (mmc_card_nonstd_func_interface(func->card)) {
+ func->class = SDIO_CLASS_NONE;
+ return 0;
+ }
+
ret = mmc_io_rw_direct(func->card, 0, 0,
SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF, 0, &data);
if (ret)
@@ -181,7 +187,7 @@ static int sdio_disable_cd(struct mmc_card *card)
int ret;
u8 ctrl;
- if (!card->cccr.disable_cd)
+ if (!mmc_card_disable_cd(card))
return 0;
ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IF, 0, &ctrl);
@@ -363,8 +369,8 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
goto err;
}
- if (ocr & R4_MEMORY_PRESENT
- && mmc_sd_get_cid(host, host->ocr & ocr, card->raw_cid) == 0) {
+ if ((ocr & R4_MEMORY_PRESENT) &&
+ mmc_sd_get_cid(host, host->ocr & ocr, card->raw_cid, NULL) == 0) {
card->type = MMC_TYPE_SD_COMBO;
if (oldcard && (oldcard->type != MMC_TYPE_SD_COMBO ||
@@ -466,7 +472,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
card = oldcard;
}
- mmc_fixup_device(card);
+ mmc_fixup_device(card, NULL);
if (card->type == MMC_TYPE_SD_COMBO) {
err = mmc_sd_setup_card(host, card, oldcard != NULL);
@@ -625,7 +631,7 @@ static int mmc_sdio_suspend(struct mmc_host *host)
}
}
- if (!err && host->pm_flags & MMC_PM_KEEP_POWER) {
+ if (!err && mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
mmc_claim_host(host);
sdio_disable_wide(host->card);
mmc_release_host(host);
@@ -645,10 +651,10 @@ static int mmc_sdio_resume(struct mmc_host *host)
mmc_claim_host(host);
/* No need to reinitialize powered-resumed nonremovable cards */
- if (mmc_card_is_removable(host) || !mmc_card_is_powered_resumed(host))
+ if (mmc_card_is_removable(host) || !mmc_card_keep_power(host))
err = mmc_sdio_init_card(host, host->ocr, host->card,
- (host->pm_flags & MMC_PM_KEEP_POWER));
- else if (mmc_card_is_powered_resumed(host)) {
+ mmc_card_keep_power(host));
+ else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
/* We may have switched to 1-bit mode during suspend */
err = sdio_enable_4bit_bus(host->card);
if (err > 0) {
@@ -691,7 +697,7 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
mmc_claim_host(host);
ret = mmc_sdio_init_card(host, host->ocr, host->card,
- (host->pm_flags & MMC_PM_KEEP_POWER));
+ mmc_card_keep_power(host));
if (!ret && host->sdio_irqs)
mmc_signal_sdio_irq(host);
mmc_release_host(host);
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index b3001617e67d..03ead028d2ce 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -31,6 +31,17 @@ static int process_sdio_pending_irqs(struct mmc_card *card)
{
int i, ret, count;
unsigned char pending;
+ struct sdio_func *func;
+
+ /*
+ * Optimization, if there is only 1 function interrupt registered
+ * call irq handler directly
+ */
+ func = card->sdio_single_irq;
+ if (func) {
+ func->irq_handler(func);
+ return 1;
+ }
ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &pending);
if (ret) {
@@ -42,7 +53,7 @@ static int process_sdio_pending_irqs(struct mmc_card *card)
count = 0;
for (i = 1; i <= 7; i++) {
if (pending & (1 << i)) {
- struct sdio_func *func = card->sdio_func[i - 1];
+ func = card->sdio_func[i - 1];
if (!func) {
printk(KERN_WARNING "%s: pending IRQ for "
"non-existent function\n",
@@ -186,6 +197,24 @@ static int sdio_card_irq_put(struct mmc_card *card)
return 0;
}
+/* If there is only 1 function registered set sdio_single_irq */
+static void sdio_single_irq_set(struct mmc_card *card)
+{
+ struct sdio_func *func;
+ int i;
+
+ card->sdio_single_irq = NULL;
+ if ((card->host->caps & MMC_CAP_SDIO_IRQ) &&
+ card->host->sdio_irqs == 1)
+ for (i = 0; i < card->sdio_funcs; i++) {
+ func = card->sdio_func[i];
+ if (func && func->irq_handler) {
+ card->sdio_single_irq = func;
+ break;
+ }
+ }
+}
+
/**
* sdio_claim_irq - claim the IRQ for a SDIO function
* @func: SDIO function
@@ -227,6 +256,7 @@ int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler)
ret = sdio_card_irq_get(func->card);
if (ret)
func->irq_handler = NULL;
+ sdio_single_irq_set(func->card);
return ret;
}
@@ -251,6 +281,7 @@ int sdio_release_irq(struct sdio_func *func)
if (func->irq_handler) {
func->irq_handler = NULL;
sdio_card_irq_put(func->card);
+ sdio_single_irq_set(func->card);
}
ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, &reg);
diff --git a/drivers/mmc/core/sdio_ops.c b/drivers/mmc/core/sdio_ops.c
index dea36d9c22e6..f087d876c573 100644
--- a/drivers/mmc/core/sdio_ops.c
+++ b/drivers/mmc/core/sdio_ops.c
@@ -21,13 +21,11 @@
int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
{
- struct mmc_command cmd;
+ struct mmc_command cmd = {0};
int i, err = 0;
BUG_ON(!host);
- memset(&cmd, 0, sizeof(struct mmc_command));
-
cmd.opcode = SD_IO_SEND_OP_COND;
cmd.arg = ocr;
cmd.flags = MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR;
@@ -70,7 +68,7 @@ int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn,
unsigned addr, u8 in, u8 *out)
{
- struct mmc_command cmd;
+ struct mmc_command cmd = {0};
int err;
BUG_ON(!host);
@@ -80,8 +78,6 @@ static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn,
if (addr & ~0x1FFFF)
return -EINVAL;
- memset(&cmd, 0, sizeof(struct mmc_command));
-
cmd.opcode = SD_IO_RW_DIRECT;
cmd.arg = write ? 0x80000000 : 0x00000000;
cmd.arg |= fn << 28;
@@ -125,9 +121,9 @@ int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz)
{
- struct mmc_request mrq;
- struct mmc_command cmd;
- struct mmc_data data;
+ struct mmc_request mrq = {0};
+ struct mmc_command cmd = {0};
+ struct mmc_data data = {0};
struct scatterlist sg;
BUG_ON(!card);
@@ -140,10 +136,6 @@ int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
if (addr & ~0x1FFFF)
return -EINVAL;
- memset(&mrq, 0, sizeof(struct mmc_request));
- memset(&cmd, 0, sizeof(struct mmc_command));
- memset(&data, 0, sizeof(struct mmc_data));
-
mrq.cmd = &cmd;
mrq.data = &data;
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 94df40531c38..56dbf3f6ad08 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -154,7 +154,7 @@ config MMC_SDHCI_DOVE
If unsure, say N.
config MMC_SDHCI_TEGRA
- tristate "SDHCI platform support for the Tegra SD/MMC Controller"
+ bool "SDHCI platform support for the Tegra SD/MMC Controller"
depends on MMC_SDHCI_PLTFM && ARCH_TEGRA
select MMC_SDHCI_IO_ACCESSORS
help
@@ -535,6 +535,37 @@ config MMC_JZ4740
If you have a board based on such a SoC and with a SD/MMC slot,
say Y or M here.
+config MMC_VUB300
+ tristate "VUB300 USB to SDIO/SD/MMC Host Controller support"
+ depends on USB
+ help
+ This selects support for Elan Digital Systems' VUB300 chip.
+
+ The VUB300 is a USB-SDIO Host Controller Interface chip
+ that enables the host computer to use SDIO/SD/MMC cards
+ via a USB 2.0 or USB 1.1 host.
+
+ The VUB300 chip will be found in both physically separate
+ USB to SDIO/SD/MMC adapters and embedded on some motherboards.
+
+ The VUB300 chip supports SD and MMC memory cards in addition
+ to single and multifunction SDIO cards.
+
+ Some SDIO cards will need a firmware file to be loaded and
+ sent to VUB300 chip in order to achieve better data throughput.
+ Download these "Offload Pseudocode" from Elan Digital Systems'
+ web-site http://www.elandigitalsystems.com/support/downloads.php
+ and put them in /lib/firmware. Note that without these additional
+ firmware files the VUB300 chip will still function, but not at
+ the best obtainable data rate.
+
+ To compile this mmc host controller driver as a module,
+ choose M here: the module will be called vub300.
+
+ If you have a computer with an embedded VUB300 chip
+ or if you intend connecting a USB adapter based on a
+ VUB300 chip say Y or M here.
+
config MMC_USHC
tristate "USB SD Host Controller (USHC) support"
depends on USB
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 4f1df0aae574..58a5cf73d6e9 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
obj-$(CONFIG_MMC_DW) += dw_mmc.o
obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
+obj-$(CONFIG_MMC_VUB300) += vub300.o
obj-$(CONFIG_MMC_USHC) += ushc.o
obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-platform.o
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index ea3888b65d5d..aa8039f473c4 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -1899,5 +1899,5 @@ late_initcall(atmci_init); /* try to load after dma driver when built-in */
module_exit(atmci_exit);
MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver");
-MODULE_AUTHOR("Haavard Skinnemoen <haavard.skinnemoen@atmel.com>");
+MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 87e1f57ec9ba..66dcddb9c205 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1769,9 +1769,6 @@ static int dw_mci_suspend(struct platform_device *pdev, pm_message_t mesg)
int i, ret;
struct dw_mci *host = platform_get_drvdata(pdev);
- if (host->vmmc)
- regulator_enable(host->vmmc);
-
for (i = 0; i < host->num_slots; i++) {
struct dw_mci_slot *slot = host->slot[i];
if (!slot)
@@ -1798,6 +1795,9 @@ static int dw_mci_resume(struct platform_device *pdev)
int i, ret;
struct dw_mci *host = platform_get_drvdata(pdev);
+ if (host->vmmc)
+ regulator_enable(host->vmmc);
+
if (host->dma_ops->init)
host->dma_ops->init(host);
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index b4a7e4fba90f..4941e06fe2e1 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -77,7 +77,7 @@ static struct variant_data variant_arm_extended_fifo = {
static struct variant_data variant_u300 = {
.fifosize = 16 * 4,
.fifohalfsize = 8 * 4,
- .clkreg_enable = 1 << 13, /* HWFCEN */
+ .clkreg_enable = MCI_ST_U300_HWFCEN,
.datalength_bits = 16,
.sdio = true,
};
@@ -86,7 +86,7 @@ static struct variant_data variant_ux500 = {
.fifosize = 30 * 4,
.fifohalfsize = 8 * 4,
.clkreg = MCI_CLK_ENABLE,
- .clkreg_enable = 1 << 14, /* HWFCEN */
+ .clkreg_enable = MCI_ST_UX500_HWFCEN,
.datalength_bits = 24,
.sdio = true,
.st_clkdiv = true,
@@ -103,6 +103,8 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
if (desired) {
if (desired >= host->mclk) {
clk = MCI_CLK_BYPASS;
+ if (variant->st_clkdiv)
+ clk |= MCI_ST_UX500_NEG_EDGE;
host->cclk = host->mclk;
} else if (variant->st_clkdiv) {
/*
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index ec9a7bc6d0df..bb32e21c09db 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -11,23 +11,33 @@
#define MCI_PWR_OFF 0x00
#define MCI_PWR_UP 0x02
#define MCI_PWR_ON 0x03
-#define MCI_DATA2DIREN (1 << 2)
-#define MCI_CMDDIREN (1 << 3)
-#define MCI_DATA0DIREN (1 << 4)
-#define MCI_DATA31DIREN (1 << 5)
#define MCI_OD (1 << 6)
#define MCI_ROD (1 << 7)
-/* The ST Micro version does not have ROD */
-#define MCI_FBCLKEN (1 << 7)
-#define MCI_DATA74DIREN (1 << 8)
+/*
+ * The ST Micro version does not have ROD and reuse the voltage registers
+ * for direction settings
+ */
+#define MCI_ST_DATA2DIREN (1 << 2)
+#define MCI_ST_CMDDIREN (1 << 3)
+#define MCI_ST_DATA0DIREN (1 << 4)
+#define MCI_ST_DATA31DIREN (1 << 5)
+#define MCI_ST_FBCLKEN (1 << 7)
+#define MCI_ST_DATA74DIREN (1 << 8)
#define MMCICLOCK 0x004
#define MCI_CLK_ENABLE (1 << 8)
#define MCI_CLK_PWRSAVE (1 << 9)
#define MCI_CLK_BYPASS (1 << 10)
#define MCI_4BIT_BUS (1 << 11)
-/* 8bit wide buses supported in ST Micro versions */
+/*
+ * 8bit wide buses, hardware flow contronl, negative edges and clock inversion
+ * supported in ST Micro U300 and Ux500 versions
+ */
#define MCI_ST_8BIT_BUS (1 << 12)
+#define MCI_ST_U300_HWFCEN (1 << 13)
+#define MCI_ST_UX500_NEG_EDGE (1 << 13)
+#define MCI_ST_UX500_HWFCEN (1 << 14)
+#define MCI_ST_UX500_CLK_INV (1 << 15)
#define MMCIARGUMENT 0x008
#define MMCICOMMAND 0x00c
@@ -88,8 +98,9 @@
#define MCI_RXFIFOEMPTY (1 << 19)
#define MCI_TXDATAAVLBL (1 << 20)
#define MCI_RXDATAAVLBL (1 << 21)
-#define MCI_SDIOIT (1 << 22)
-#define MCI_CEATAEND (1 << 23)
+/* Extended status bits for the ST Micro variants */
+#define MCI_ST_SDIOIT (1 << 22)
+#define MCI_ST_CEATAEND (1 << 23)
#define MMCICLEAR 0x038
#define MCI_CMDCRCFAILCLR (1 << 0)
@@ -102,8 +113,9 @@
#define MCI_CMDSENTCLR (1 << 7)
#define MCI_DATAENDCLR (1 << 8)
#define MCI_DATABLOCKENDCLR (1 << 10)
-#define MCI_SDIOITC (1 << 22)
-#define MCI_CEATAENDC (1 << 23)
+/* Extended status bits for the ST Micro variants */
+#define MCI_ST_SDIOITC (1 << 22)
+#define MCI_ST_CEATAENDC (1 << 23)
#define MMCIMASK0 0x03c
#define MCI_CMDCRCFAILMASK (1 << 0)
@@ -127,8 +139,9 @@
#define MCI_RXFIFOEMPTYMASK (1 << 19)
#define MCI_TXDATAAVLBLMASK (1 << 20)
#define MCI_RXDATAAVLBLMASK (1 << 21)
-#define MCI_SDIOITMASK (1 << 22)
-#define MCI_CEATAENDMASK (1 << 23)
+/* Extended status bits for the ST Micro variants */
+#define MCI_ST_SDIOITMASK (1 << 22)
+#define MCI_ST_CEATAENDMASK (1 << 23)
#define MMCIMASK1 0x040
#define MMCIFIFOCNT 0x048
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index f8b5f37007b2..936bbca19c0a 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -18,11 +18,9 @@
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/device.h>
-
#include <linux/mmc/host.h>
-
-#include <asm/scatterlist.h>
-#include <asm/io.h>
+#include <linux/scatterlist.h>
+#include <linux/io.h>
#include "sdhci.h"
@@ -46,14 +44,14 @@ struct sdhci_pci_slot;
struct sdhci_pci_fixes {
unsigned int quirks;
- int (*probe)(struct sdhci_pci_chip*);
+ int (*probe) (struct sdhci_pci_chip *);
- int (*probe_slot)(struct sdhci_pci_slot*);
- void (*remove_slot)(struct sdhci_pci_slot*, int);
+ int (*probe_slot) (struct sdhci_pci_slot *);
+ void (*remove_slot) (struct sdhci_pci_slot *, int);
- int (*suspend)(struct sdhci_pci_chip*,
+ int (*suspend) (struct sdhci_pci_chip *,
pm_message_t);
- int (*resume)(struct sdhci_pci_chip*);
+ int (*resume) (struct sdhci_pci_chip *);
};
struct sdhci_pci_slot {
@@ -329,6 +327,11 @@ static int jmicron_probe(struct sdhci_pci_chip *chip)
return ret;
}
+ /* quirk for unsable RO-detection on JM388 chips */
+ if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_SD ||
+ chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD)
+ chip->quirks |= SDHCI_QUIRK_UNSTABLE_RO_DETECT;
+
return 0;
}
@@ -402,7 +405,7 @@ static int jmicron_suspend(struct sdhci_pci_chip *chip, pm_message_t state)
if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) {
- for (i = 0;i < chip->num_slots;i++)
+ for (i = 0; i < chip->num_slots; i++)
jmicron_enable_mmc(chip->slots[i]->host, 0);
}
@@ -415,7 +418,7 @@ static int jmicron_resume(struct sdhci_pci_chip *chip)
if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) {
- for (i = 0;i < chip->num_slots;i++)
+ for (i = 0; i < chip->num_slots; i++)
jmicron_enable_mmc(chip->slots[i]->host, 1);
}
@@ -798,7 +801,7 @@ static struct sdhci_ops sdhci_pci_ops = {
#ifdef CONFIG_PM
-static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
+static int sdhci_pci_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct sdhci_pci_chip *chip;
struct sdhci_pci_slot *slot;
@@ -810,7 +813,7 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
if (!chip)
return 0;
- for (i = 0;i < chip->num_slots;i++) {
+ for (i = 0; i < chip->num_slots; i++) {
slot = chip->slots[i];
if (!slot)
continue;
@@ -818,7 +821,7 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
ret = sdhci_suspend_host(slot->host, state);
if (ret) {
- for (i--;i >= 0;i--)
+ for (i--; i >= 0; i--)
sdhci_resume_host(chip->slots[i]->host);
return ret;
}
@@ -833,7 +836,7 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
if (chip->fixes && chip->fixes->suspend) {
ret = chip->fixes->suspend(chip, state);
if (ret) {
- for (i = chip->num_slots - 1;i >= 0;i--)
+ for (i = chip->num_slots - 1; i >= 0; i--)
sdhci_resume_host(chip->slots[i]->host);
return ret;
}
@@ -855,7 +858,7 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
return 0;
}
-static int sdhci_pci_resume (struct pci_dev *pdev)
+static int sdhci_pci_resume(struct pci_dev *pdev)
{
struct sdhci_pci_chip *chip;
struct sdhci_pci_slot *slot;
@@ -877,7 +880,7 @@ static int sdhci_pci_resume (struct pci_dev *pdev)
return ret;
}
- for (i = 0;i < chip->num_slots;i++) {
+ for (i = 0; i < chip->num_slots; i++) {
slot = chip->slots[i];
if (!slot)
continue;
@@ -1059,7 +1062,7 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
}
chip->pdev = pdev;
- chip->fixes = (const struct sdhci_pci_fixes*)ent->driver_data;
+ chip->fixes = (const struct sdhci_pci_fixes *)ent->driver_data;
if (chip->fixes)
chip->quirks = chip->fixes->quirks;
chip->num_slots = slots;
@@ -1074,10 +1077,10 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
slots = chip->num_slots; /* Quirk may have changed this */
- for (i = 0;i < slots;i++) {
+ for (i = 0; i < slots; i++) {
slot = sdhci_pci_probe_slot(pdev, chip, first_bar + i);
if (IS_ERR(slot)) {
- for (i--;i >= 0;i--)
+ for (i--; i >= 0; i--)
sdhci_pci_remove_slot(chip->slots[i]);
ret = PTR_ERR(slot);
goto free;
@@ -1105,7 +1108,7 @@ static void __devexit sdhci_pci_remove(struct pci_dev *pdev)
chip = pci_get_drvdata(pdev);
if (chip) {
- for (i = 0;i < chip->num_slots; i++)
+ for (i = 0; i < chip->num_slots; i++)
sdhci_pci_remove_slot(chip->slots[i]);
pci_set_drvdata(pdev, NULL);
@@ -1116,9 +1119,9 @@ static void __devexit sdhci_pci_remove(struct pci_dev *pdev)
}
static struct pci_driver sdhci_driver = {
- .name = "sdhci-pci",
+ .name = "sdhci-pci",
.id_table = pci_ids,
- .probe = sdhci_pci_probe,
+ .probe = sdhci_pci_probe,
.remove = __devexit_p(sdhci_pci_remove),
.suspend = sdhci_pci_suspend,
.resume = sdhci_pci_resume,
diff --git a/drivers/mmc/host/sdhci-pxa.c b/drivers/mmc/host/sdhci-pxa.c
index 5a61208cbc66..089c9a68b7b1 100644
--- a/drivers/mmc/host/sdhci-pxa.c
+++ b/drivers/mmc/host/sdhci-pxa.c
@@ -69,7 +69,45 @@ static void set_clock(struct sdhci_host *host, unsigned int clock)
}
}
+static int set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
+{
+ u16 ctrl_2;
+
+ /*
+ * Set V18_EN -- UHS modes do not work without this.
+ * does not change signaling voltage
+ */
+ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+
+ /* Select Bus Speed Mode for host */
+ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+ switch (uhs) {
+ case MMC_TIMING_UHS_SDR12:
+ ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
+ break;
+ case MMC_TIMING_UHS_SDR25:
+ ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
+ break;
+ case MMC_TIMING_UHS_SDR50:
+ ctrl_2 |= SDHCI_CTRL_UHS_SDR50 | SDHCI_CTRL_VDD_180;
+ break;
+ case MMC_TIMING_UHS_SDR104:
+ ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180;
+ break;
+ case MMC_TIMING_UHS_DDR50:
+ ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180;
+ break;
+ }
+
+ sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+ pr_debug("%s:%s uhs = %d, ctrl_2 = %04X\n",
+ __func__, mmc_hostname(host->mmc), uhs, ctrl_2);
+
+ return 0;
+}
+
static struct sdhci_ops sdhci_pxa_ops = {
+ .set_uhs_signaling = set_uhs_signaling,
.set_clock = set_clock,
};
@@ -136,11 +174,19 @@ static int __devinit sdhci_pxa_probe(struct platform_device *pdev)
host->hw_name = "MMC";
host->ops = &sdhci_pxa_ops;
host->irq = irq;
- host->quirks = SDHCI_QUIRK_BROKEN_ADMA | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
+ host->quirks = SDHCI_QUIRK_BROKEN_ADMA
+ | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
+ | SDHCI_QUIRK_32BIT_DMA_ADDR
+ | SDHCI_QUIRK_32BIT_DMA_SIZE
+ | SDHCI_QUIRK_32BIT_ADMA_SIZE
+ | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC;
if (pdata->quirks)
host->quirks |= pdata->quirks;
+ /* enable 1/8V DDR capable */
+ host->mmc->caps |= MMC_CAP_1_8V_DDR;
+
/* If slot design supports 8 bit data, indicate this to MMC. */
if (pdata->flags & PXA_FLAG_SD_8_BIT_CAPABLE_SLOT)
host->mmc->caps |= MMC_CAP_8_BIT_DATA;
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index f7e1f964395f..343c97edba32 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -184,6 +184,8 @@ static int tegra_sdhci_pltfm_init(struct sdhci_host *host,
clk_enable(clk);
pltfm_host->clk = clk;
+ host->mmc->pm_caps = plat->pm_flags;
+
if (plat->is_8bit)
host->mmc->caps |= MMC_CAP_8_BIT_DATA;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 5d20661bc357..58d5436ff649 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -38,13 +38,16 @@
#define SDHCI_USE_LEDS_CLASS
#endif
+#define MAX_TUNING_LOOP 40
+
static unsigned int debug_quirks = 0;
-static void sdhci_prepare_data(struct sdhci_host *, struct mmc_data *);
static void sdhci_finish_data(struct sdhci_host *);
static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
static void sdhci_finish_command(struct sdhci_host *);
+static int sdhci_execute_tuning(struct mmc_host *mmc);
+static void sdhci_tuning_timer(unsigned long data);
static void sdhci_dumpregs(struct sdhci_host *host)
{
@@ -84,6 +87,8 @@ static void sdhci_dumpregs(struct sdhci_host *host)
printk(KERN_DEBUG DRIVER_NAME ": Cmd: 0x%08x | Max curr: 0x%08x\n",
sdhci_readw(host, SDHCI_COMMAND),
sdhci_readl(host, SDHCI_MAX_CURRENT));
+ printk(KERN_DEBUG DRIVER_NAME ": Host ctl2: 0x%08x\n",
+ sdhci_readw(host, SDHCI_HOST_CONTROL2));
if (host->flags & SDHCI_USE_ADMA)
printk(KERN_DEBUG DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
@@ -157,6 +162,9 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
ier = sdhci_readl(host, SDHCI_INT_ENABLE);
+ if (host->ops->platform_reset_enter)
+ host->ops->platform_reset_enter(host, mask);
+
sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
if (mask & SDHCI_RESET_ALL)
@@ -177,6 +185,9 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
mdelay(1);
}
+ if (host->ops->platform_reset_exit)
+ host->ops->platform_reset_exit(host, mask);
+
if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier);
}
@@ -591,9 +602,10 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
data->sg_len, direction);
}
-static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
+static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
{
u8 count;
+ struct mmc_data *data = cmd->data;
unsigned target_timeout, current_timeout;
/*
@@ -605,9 +617,16 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
if (host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL)
return 0xE;
+ /* Unspecified timeout, assume max */
+ if (!data && !cmd->cmd_timeout_ms)
+ return 0xE;
+
/* timeout in us */
- target_timeout = data->timeout_ns / 1000 +
- data->timeout_clks / host->clock;
+ if (!data)
+ target_timeout = cmd->cmd_timeout_ms * 1000;
+ else
+ target_timeout = data->timeout_ns / 1000 +
+ data->timeout_clks / host->clock;
if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
host->timeout_clk = host->clock / 1000;
@@ -622,6 +641,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
* =>
* (1) / (2) > 2^6
*/
+ BUG_ON(!host->timeout_clk);
count = 0;
current_timeout = (1 << 13) * 1000 / host->timeout_clk;
while (current_timeout < target_timeout) {
@@ -632,8 +652,8 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
}
if (count >= 0xF) {
- printk(KERN_WARNING "%s: Too large timeout requested!\n",
- mmc_hostname(host->mmc));
+ printk(KERN_WARNING "%s: Too large timeout requested for CMD%d!\n",
+ mmc_hostname(host->mmc), cmd->opcode);
count = 0xE;
}
@@ -651,15 +671,21 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host)
sdhci_clear_set_irqs(host, dma_irqs, pio_irqs);
}
-static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
+static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
{
u8 count;
u8 ctrl;
+ struct mmc_data *data = cmd->data;
int ret;
WARN_ON(host->data);
- if (data == NULL)
+ if (data || (cmd->flags & MMC_RSP_BUSY)) {
+ count = sdhci_calc_timeout(host, cmd);
+ sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
+ }
+
+ if (!data)
return;
/* Sanity checks */
@@ -669,9 +695,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
host->data = data;
host->data_early = 0;
-
- count = sdhci_calc_timeout(host, data);
- sdhci_writeb(host, count, SDHCI_TIMEOUT_CONTROL);
+ host->data->bytes_xfered = 0;
if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA))
host->flags |= SDHCI_REQ_USE_DMA;
@@ -807,15 +831,17 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
sdhci_set_transfer_irqs(host);
- /* We do not handle DMA boundaries, so set it to max (512 KiB) */
- sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, data->blksz), SDHCI_BLOCK_SIZE);
+ /* Set the DMA boundary value and block size */
+ sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
+ data->blksz), SDHCI_BLOCK_SIZE);
sdhci_writew(host, data->blocks, SDHCI_BLOCK_COUNT);
}
static void sdhci_set_transfer_mode(struct sdhci_host *host,
- struct mmc_data *data)
+ struct mmc_command *cmd)
{
u16 mode;
+ struct mmc_data *data = cmd->data;
if (data == NULL)
return;
@@ -823,12 +849,20 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
WARN_ON(!host->data);
mode = SDHCI_TRNS_BLK_CNT_EN;
- if (data->blocks > 1) {
- if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
- mode |= SDHCI_TRNS_MULTI | SDHCI_TRNS_ACMD12;
- else
- mode |= SDHCI_TRNS_MULTI;
+ if (mmc_op_multi(cmd->opcode) || data->blocks > 1) {
+ mode |= SDHCI_TRNS_MULTI;
+ /*
+ * If we are sending CMD23, CMD12 never gets sent
+ * on successful completion (so no Auto-CMD12).
+ */
+ if (!host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD12))
+ mode |= SDHCI_TRNS_AUTO_CMD12;
+ else if (host->mrq->sbc && (host->flags & SDHCI_AUTO_CMD23)) {
+ mode |= SDHCI_TRNS_AUTO_CMD23;
+ sdhci_writel(host, host->mrq->sbc->arg, SDHCI_ARGUMENT2);
+ }
}
+
if (data->flags & MMC_DATA_READ)
mode |= SDHCI_TRNS_READ;
if (host->flags & SDHCI_REQ_USE_DMA)
@@ -868,7 +902,15 @@ static void sdhci_finish_data(struct sdhci_host *host)
else
data->bytes_xfered = data->blksz * data->blocks;
- if (data->stop) {
+ /*
+ * Need to send CMD12 if -
+ * a) open-ended multiblock transfer (no CMD23)
+ * b) error in multiblock transfer
+ */
+ if (data->stop &&
+ (data->error ||
+ !host->mrq->sbc)) {
+
/*
* The controller needs a reset of internal state machines
* upon error conditions.
@@ -920,11 +962,11 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
host->cmd = cmd;
- sdhci_prepare_data(host, cmd->data);
+ sdhci_prepare_data(host, cmd);
sdhci_writel(host, cmd->arg, SDHCI_ARGUMENT);
- sdhci_set_transfer_mode(host, cmd->data);
+ sdhci_set_transfer_mode(host, cmd);
if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
printk(KERN_ERR "%s: Unsupported response type!\n",
@@ -947,7 +989,9 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
flags |= SDHCI_CMD_CRC;
if (cmd->flags & MMC_RSP_OPCODE)
flags |= SDHCI_CMD_INDEX;
- if (cmd->data)
+
+ /* CMD19 is special in that the Data Present Select should be set */
+ if (cmd->data || (cmd->opcode == MMC_SEND_TUNING_BLOCK))
flags |= SDHCI_CMD_DATA;
sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
@@ -977,19 +1021,27 @@ static void sdhci_finish_command(struct sdhci_host *host)
host->cmd->error = 0;
- if (host->data && host->data_early)
- sdhci_finish_data(host);
+ /* Finished CMD23, now send actual command. */
+ if (host->cmd == host->mrq->sbc) {
+ host->cmd = NULL;
+ sdhci_send_command(host, host->mrq->cmd);
+ } else {
- if (!host->cmd->data)
- tasklet_schedule(&host->finish_tasklet);
+ /* Processed actual command. */
+ if (host->data && host->data_early)
+ sdhci_finish_data(host);
- host->cmd = NULL;
+ if (!host->cmd->data)
+ tasklet_schedule(&host->finish_tasklet);
+
+ host->cmd = NULL;
+ }
}
static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
{
- int div;
- u16 clk;
+ int div = 0; /* Initialized for compiler warning */
+ u16 clk = 0;
unsigned long timeout;
if (clock == host->clock)
@@ -1007,14 +1059,45 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
goto out;
if (host->version >= SDHCI_SPEC_300) {
- /* Version 3.00 divisors must be a multiple of 2. */
- if (host->max_clk <= clock)
- div = 1;
- else {
- for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) {
- if ((host->max_clk / div) <= clock)
- break;
+ /*
+ * Check if the Host Controller supports Programmable Clock
+ * Mode.
+ */
+ if (host->clk_mul) {
+ u16 ctrl;
+
+ /*
+ * We need to figure out whether the Host Driver needs
+ * to select Programmable Clock Mode, or the value can
+ * be set automatically by the Host Controller based on
+ * the Preset Value registers.
+ */
+ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ if (!(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
+ for (div = 1; div <= 1024; div++) {
+ if (((host->max_clk * host->clk_mul) /
+ div) <= clock)
+ break;
+ }
+ /*
+ * Set Programmable Clock Mode in the Clock
+ * Control register.
+ */
+ clk = SDHCI_PROG_CLOCK_MODE;
+ div--;
}
+ } else {
+ /* Version 3.00 divisors must be a multiple of 2. */
+ if (host->max_clk <= clock)
+ div = 1;
+ else {
+ for (div = 2; div < SDHCI_MAX_DIV_SPEC_300;
+ div += 2) {
+ if ((host->max_clk / div) <= clock)
+ break;
+ }
+ }
+ div >>= 1;
}
} else {
/* Version 2.00 divisors must be a power of 2. */
@@ -1022,10 +1105,10 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
if ((host->max_clk / div) <= clock)
break;
}
+ div >>= 1;
}
- div >>= 1;
- clk = (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
+ clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
<< SDHCI_DIVIDER_HI_SHIFT;
clk |= SDHCI_CLOCK_INT_EN;
@@ -1131,7 +1214,12 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
#ifndef SDHCI_USE_LEDS_CLASS
sdhci_activate_led(host);
#endif
- if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12) {
+
+ /*
+ * Ensure we don't send the STOP for non-SET_BLOCK_COUNTED
+ * requests if Auto-CMD12 is enabled.
+ */
+ if (!mrq->sbc && (host->flags & SDHCI_AUTO_CMD12)) {
if (mrq->stop) {
mrq->data->stop = NULL;
mrq->stop = NULL;
@@ -1150,8 +1238,30 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
if (!present || host->flags & SDHCI_DEVICE_DEAD) {
host->mrq->cmd->error = -ENOMEDIUM;
tasklet_schedule(&host->finish_tasklet);
- } else
- sdhci_send_command(host, mrq->cmd);
+ } else {
+ u32 present_state;
+
+ present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
+ /*
+ * Check if the re-tuning timer has already expired and there
+ * is no on-going data transfer. If so, we need to execute
+ * tuning procedure before sending command.
+ */
+ if ((host->flags & SDHCI_NEEDS_RETUNING) &&
+ !(present_state & (SDHCI_DOING_WRITE | SDHCI_DOING_READ))) {
+ spin_unlock_irqrestore(&host->lock, flags);
+ sdhci_execute_tuning(mmc);
+ spin_lock_irqsave(&host->lock, flags);
+
+ /* Restore original mmc_request structure */
+ host->mrq = mrq;
+ }
+
+ if (mrq->sbc && !(host->flags & SDHCI_AUTO_CMD23))
+ sdhci_send_command(host, mrq->sbc);
+ else
+ sdhci_send_command(host, mrq->cmd);
+ }
mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
@@ -1222,7 +1332,84 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
else
ctrl &= ~SDHCI_CTRL_HISPD;
- sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+ if (host->version >= SDHCI_SPEC_300) {
+ u16 clk, ctrl_2;
+ unsigned int clock;
+
+ /* In case of UHS-I modes, set High Speed Enable */
+ if ((ios->timing == MMC_TIMING_UHS_SDR50) ||
+ (ios->timing == MMC_TIMING_UHS_SDR104) ||
+ (ios->timing == MMC_TIMING_UHS_DDR50) ||
+ (ios->timing == MMC_TIMING_UHS_SDR25) ||
+ (ios->timing == MMC_TIMING_UHS_SDR12))
+ ctrl |= SDHCI_CTRL_HISPD;
+
+ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ if (!(ctrl_2 & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+ /*
+ * We only need to set Driver Strength if the
+ * preset value enable is not set.
+ */
+ ctrl_2 &= ~SDHCI_CTRL_DRV_TYPE_MASK;
+ if (ios->drv_type == MMC_SET_DRIVER_TYPE_A)
+ ctrl_2 |= SDHCI_CTRL_DRV_TYPE_A;
+ else if (ios->drv_type == MMC_SET_DRIVER_TYPE_C)
+ ctrl_2 |= SDHCI_CTRL_DRV_TYPE_C;
+
+ sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+ } else {
+ /*
+ * According to SDHC Spec v3.00, if the Preset Value
+ * Enable in the Host Control 2 register is set, we
+ * need to reset SD Clock Enable before changing High
+ * Speed Enable to avoid generating clock gliches.
+ */
+
+ /* Reset SD Clock Enable */
+ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ clk &= ~SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+
+ /* Re-enable SD Clock */
+ clock = host->clock;
+ host->clock = 0;
+ sdhci_set_clock(host, clock);
+ }
+
+
+ /* Reset SD Clock Enable */
+ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ clk &= ~SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+ if (host->ops->set_uhs_signaling)
+ host->ops->set_uhs_signaling(host, ios->timing);
+ else {
+ ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ /* Select Bus Speed Mode for host */
+ ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+ if (ios->timing == MMC_TIMING_UHS_SDR12)
+ ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
+ else if (ios->timing == MMC_TIMING_UHS_SDR25)
+ ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
+ else if (ios->timing == MMC_TIMING_UHS_SDR50)
+ ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
+ else if (ios->timing == MMC_TIMING_UHS_SDR104)
+ ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
+ else if (ios->timing == MMC_TIMING_UHS_DDR50)
+ ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
+ sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+ }
+
+ /* Re-enable SD Clock */
+ clock = host->clock;
+ host->clock = 0;
+ sdhci_set_clock(host, clock);
+ } else
+ sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
/*
* Some (ENE) controllers go apeshit on some ios operation,
@@ -1237,14 +1424,11 @@ out:
spin_unlock_irqrestore(&host->lock, flags);
}
-static int sdhci_get_ro(struct mmc_host *mmc)
+static int check_ro(struct sdhci_host *host)
{
- struct sdhci_host *host;
unsigned long flags;
int is_readonly;
- host = mmc_priv(mmc);
-
spin_lock_irqsave(&host->lock, flags);
if (host->flags & SDHCI_DEVICE_DEAD)
@@ -1262,6 +1446,29 @@ static int sdhci_get_ro(struct mmc_host *mmc)
!is_readonly : is_readonly;
}
+#define SAMPLE_COUNT 5
+
+static int sdhci_get_ro(struct mmc_host *mmc)
+{
+ struct sdhci_host *host;
+ int i, ro_count;
+
+ host = mmc_priv(mmc);
+
+ if (!(host->quirks & SDHCI_QUIRK_UNSTABLE_RO_DETECT))
+ return check_ro(host);
+
+ ro_count = 0;
+ for (i = 0; i < SAMPLE_COUNT; i++) {
+ if (check_ro(host)) {
+ if (++ro_count > SAMPLE_COUNT / 2)
+ return 1;
+ }
+ msleep(30);
+ }
+ return 0;
+}
+
static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
{
struct sdhci_host *host;
@@ -1284,11 +1491,322 @@ out:
spin_unlock_irqrestore(&host->lock, flags);
}
+static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
+ struct mmc_ios *ios)
+{
+ struct sdhci_host *host;
+ u8 pwr;
+ u16 clk, ctrl;
+ u32 present_state;
+
+ host = mmc_priv(mmc);
+
+ /*
+ * Signal Voltage Switching is only applicable for Host Controllers
+ * v3.00 and above.
+ */
+ if (host->version < SDHCI_SPEC_300)
+ return 0;
+
+ /*
+ * We first check whether the request is to set signalling voltage
+ * to 3.3V. If so, we change the voltage to 3.3V and return quickly.
+ */
+ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
+ /* Set 1.8V Signal Enable in the Host Control2 register to 0 */
+ ctrl &= ~SDHCI_CTRL_VDD_180;
+ sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+
+ /* Wait for 5ms */
+ usleep_range(5000, 5500);
+
+ /* 3.3V regulator output should be stable within 5 ms */
+ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ if (!(ctrl & SDHCI_CTRL_VDD_180))
+ return 0;
+ else {
+ printk(KERN_INFO DRIVER_NAME ": Switching to 3.3V "
+ "signalling voltage failed\n");
+ return -EIO;
+ }
+ } else if (!(ctrl & SDHCI_CTRL_VDD_180) &&
+ (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180)) {
+ /* Stop SDCLK */
+ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ clk &= ~SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+ /* Check whether DAT[3:0] is 0000 */
+ present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
+ if (!((present_state & SDHCI_DATA_LVL_MASK) >>
+ SDHCI_DATA_LVL_SHIFT)) {
+ /*
+ * Enable 1.8V Signal Enable in the Host Control2
+ * register
+ */
+ ctrl |= SDHCI_CTRL_VDD_180;
+ sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+
+ /* Wait for 5ms */
+ usleep_range(5000, 5500);
+
+ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ if (ctrl & SDHCI_CTRL_VDD_180) {
+ /* Provide SDCLK again and wait for 1ms*/
+ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ clk |= SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+ usleep_range(1000, 1500);
+
+ /*
+ * If DAT[3:0] level is 1111b, then the card
+ * was successfully switched to 1.8V signaling.
+ */
+ present_state = sdhci_readl(host,
+ SDHCI_PRESENT_STATE);
+ if ((present_state & SDHCI_DATA_LVL_MASK) ==
+ SDHCI_DATA_LVL_MASK)
+ return 0;
+ }
+ }
+
+ /*
+ * If we are here, that means the switch to 1.8V signaling
+ * failed. We power cycle the card, and retry initialization
+ * sequence by setting S18R to 0.
+ */
+ pwr = sdhci_readb(host, SDHCI_POWER_CONTROL);
+ pwr &= ~SDHCI_POWER_ON;
+ sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+
+ /* Wait for 1ms as per the spec */
+ usleep_range(1000, 1500);
+ pwr |= SDHCI_POWER_ON;
+ sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+
+ printk(KERN_INFO DRIVER_NAME ": Switching to 1.8V signalling "
+ "voltage failed, retrying with S18R set to 0\n");
+ return -EAGAIN;
+ } else
+ /* No signal voltage switch required */
+ return 0;
+}
+
+static int sdhci_execute_tuning(struct mmc_host *mmc)
+{
+ struct sdhci_host *host;
+ u16 ctrl;
+ u32 ier;
+ int tuning_loop_counter = MAX_TUNING_LOOP;
+ unsigned long timeout;
+ int err = 0;
+
+ host = mmc_priv(mmc);
+
+ disable_irq(host->irq);
+ spin_lock(&host->lock);
+
+ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+
+ /*
+ * Host Controller needs tuning only in case of SDR104 mode
+ * and for SDR50 mode when Use Tuning for SDR50 is set in
+ * Capabilities register.
+ */
+ if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR104) ||
+ (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) &&
+ (host->flags & SDHCI_SDR50_NEEDS_TUNING)))
+ ctrl |= SDHCI_CTRL_EXEC_TUNING;
+ else {
+ spin_unlock(&host->lock);
+ enable_irq(host->irq);
+ return 0;
+ }
+
+ sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+
+ /*
+ * As per the Host Controller spec v3.00, tuning command
+ * generates Buffer Read Ready interrupt, so enable that.
+ *
+ * Note: The spec clearly says that when tuning sequence
+ * is being performed, the controller does not generate
+ * interrupts other than Buffer Read Ready interrupt. But
+ * to make sure we don't hit a controller bug, we _only_
+ * enable Buffer Read Ready interrupt here.
+ */
+ ier = sdhci_readl(host, SDHCI_INT_ENABLE);
+ sdhci_clear_set_irqs(host, ier, SDHCI_INT_DATA_AVAIL);
+
+ /*
+ * Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number
+ * of loops reaches 40 times or a timeout of 150ms occurs.
+ */
+ timeout = 150;
+ do {
+ struct mmc_command cmd = {0};
+ struct mmc_request mrq = {0};
+
+ if (!tuning_loop_counter && !timeout)
+ break;
+
+ cmd.opcode = MMC_SEND_TUNING_BLOCK;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+ cmd.retries = 0;
+ cmd.data = NULL;
+ cmd.error = 0;
+
+ mrq.cmd = &cmd;
+ host->mrq = &mrq;
+
+ /*
+ * In response to CMD19, the card sends 64 bytes of tuning
+ * block to the Host Controller. So we set the block size
+ * to 64 here.
+ */
+ sdhci_writew(host, SDHCI_MAKE_BLKSZ(7, 64), SDHCI_BLOCK_SIZE);
+
+ /*
+ * The tuning block is sent by the card to the host controller.
+ * So we set the TRNS_READ bit in the Transfer Mode register.
+ * This also takes care of setting DMA Enable and Multi Block
+ * Select in the same register to 0.
+ */
+ sdhci_writew(host, SDHCI_TRNS_READ, SDHCI_TRANSFER_MODE);
+
+ sdhci_send_command(host, &cmd);
+
+ host->cmd = NULL;
+ host->mrq = NULL;
+
+ spin_unlock(&host->lock);
+ enable_irq(host->irq);
+
+ /* Wait for Buffer Read Ready interrupt */
+ wait_event_interruptible_timeout(host->buf_ready_int,
+ (host->tuning_done == 1),
+ msecs_to_jiffies(50));
+ disable_irq(host->irq);
+ spin_lock(&host->lock);
+
+ if (!host->tuning_done) {
+ printk(KERN_INFO DRIVER_NAME ": Timeout waiting for "
+ "Buffer Read Ready interrupt during tuning "
+ "procedure, falling back to fixed sampling "
+ "clock\n");
+ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ ctrl &= ~SDHCI_CTRL_TUNED_CLK;
+ ctrl &= ~SDHCI_CTRL_EXEC_TUNING;
+ sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+
+ err = -EIO;
+ goto out;
+ }
+
+ host->tuning_done = 0;
+
+ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ tuning_loop_counter--;
+ timeout--;
+ mdelay(1);
+ } while (ctrl & SDHCI_CTRL_EXEC_TUNING);
+
+ /*
+ * The Host Driver has exhausted the maximum number of loops allowed,
+ * so use fixed sampling frequency.
+ */
+ if (!tuning_loop_counter || !timeout) {
+ ctrl &= ~SDHCI_CTRL_TUNED_CLK;
+ sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+ } else {
+ if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
+ printk(KERN_INFO DRIVER_NAME ": Tuning procedure"
+ " failed, falling back to fixed sampling"
+ " clock\n");
+ err = -EIO;
+ }
+ }
+
+out:
+ /*
+ * If this is the very first time we are here, we start the retuning
+ * timer. Since only during the first time, SDHCI_NEEDS_RETUNING
+ * flag won't be set, we check this condition before actually starting
+ * the timer.
+ */
+ if (!(host->flags & SDHCI_NEEDS_RETUNING) && host->tuning_count &&
+ (host->tuning_mode == SDHCI_TUNING_MODE_1)) {
+ mod_timer(&host->tuning_timer, jiffies +
+ host->tuning_count * HZ);
+ /* Tuning mode 1 limits the maximum data length to 4MB */
+ mmc->max_blk_count = (4 * 1024 * 1024) / mmc->max_blk_size;
+ } else {
+ host->flags &= ~SDHCI_NEEDS_RETUNING;
+ /* Reload the new initial value for timer */
+ if (host->tuning_mode == SDHCI_TUNING_MODE_1)
+ mod_timer(&host->tuning_timer, jiffies +
+ host->tuning_count * HZ);
+ }
+
+ /*
+ * In case tuning fails, host controllers which support re-tuning can
+ * try tuning again at a later time, when the re-tuning timer expires.
+ * So for these controllers, we return 0. Since there might be other
+ * controllers who do not have this capability, we return error for
+ * them.
+ */
+ if (err && host->tuning_count &&
+ host->tuning_mode == SDHCI_TUNING_MODE_1)
+ err = 0;
+
+ sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier);
+ spin_unlock(&host->lock);
+ enable_irq(host->irq);
+
+ return err;
+}
+
+static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable)
+{
+ struct sdhci_host *host;
+ u16 ctrl;
+ unsigned long flags;
+
+ host = mmc_priv(mmc);
+
+ /* Host Controller v3.00 defines preset value registers */
+ if (host->version < SDHCI_SPEC_300)
+ return;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+
+ /*
+ * We only enable or disable Preset Value if they are not already
+ * enabled or disabled respectively. Otherwise, we bail out.
+ */
+ if (enable && !(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
+ ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE;
+ sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+ } else if (!enable && (ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
+ ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
+ sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
static const struct mmc_host_ops sdhci_ops = {
.request = sdhci_request,
.set_ios = sdhci_set_ios,
.get_ro = sdhci_get_ro,
.enable_sdio_irq = sdhci_enable_sdio_irq,
+ .start_signal_voltage_switch = sdhci_start_signal_voltage_switch,
+ .execute_tuning = sdhci_execute_tuning,
+ .enable_preset_value = sdhci_enable_preset_value,
};
/*****************************************************************************\
@@ -1345,6 +1863,9 @@ static void sdhci_tasklet_finish(unsigned long param)
del_timer(&host->timer);
+ if (host->version >= SDHCI_SPEC_300)
+ del_timer(&host->tuning_timer);
+
mrq = host->mrq;
/*
@@ -1418,6 +1939,20 @@ static void sdhci_timeout_timer(unsigned long data)
spin_unlock_irqrestore(&host->lock, flags);
}
+static void sdhci_tuning_timer(unsigned long data)
+{
+ struct sdhci_host *host;
+ unsigned long flags;
+
+ host = (struct sdhci_host *)data;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ host->flags |= SDHCI_NEEDS_RETUNING;
+
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
/*****************************************************************************\
* *
* Interrupt handling *
@@ -1506,6 +2041,16 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
{
BUG_ON(intmask == 0);
+ /* CMD19 generates _only_ Buffer Read Ready interrupt */
+ if (intmask & SDHCI_INT_DATA_AVAIL) {
+ if (SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)) ==
+ MMC_SEND_TUNING_BLOCK) {
+ host->tuning_done = 1;
+ wake_up(&host->buf_ready_int);
+ return;
+ }
+ }
+
if (!host->data) {
/*
* The "data complete" interrupt is also used to
@@ -1551,10 +2096,28 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
* We currently don't do anything fancy with DMA
* boundaries, but as we can't disable the feature
* we need to at least restart the transfer.
+ *
+ * According to the spec sdhci_readl(host, SDHCI_DMA_ADDRESS)
+ * should return a valid address to continue from, but as
+ * some controllers are faulty, don't trust them.
*/
- if (intmask & SDHCI_INT_DMA_END)
- sdhci_writel(host, sdhci_readl(host, SDHCI_DMA_ADDRESS),
- SDHCI_DMA_ADDRESS);
+ if (intmask & SDHCI_INT_DMA_END) {
+ u32 dmastart, dmanow;
+ dmastart = sg_dma_address(host->data->sg);
+ dmanow = dmastart + host->data->bytes_xfered;
+ /*
+ * Force update to the next DMA block boundary.
+ */
+ dmanow = (dmanow &
+ ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1)) +
+ SDHCI_DEFAULT_BOUNDARY_SIZE;
+ host->data->bytes_xfered = dmanow - dmastart;
+ DBG("%s: DMA base 0x%08x, transferred 0x%06x bytes,"
+ " next 0x%08x\n",
+ mmc_hostname(host->mmc), dmastart,
+ host->data->bytes_xfered, dmanow);
+ sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS);
+ }
if (intmask & SDHCI_INT_DATA_END) {
if (host->cmd) {
@@ -1664,6 +2227,14 @@ int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state)
sdhci_disable_card_detection(host);
+ /* Disable tuning since we are suspending */
+ if (host->version >= SDHCI_SPEC_300 && host->tuning_count &&
+ host->tuning_mode == SDHCI_TUNING_MODE_1) {
+ host->flags &= ~SDHCI_NEEDS_RETUNING;
+ mod_timer(&host->tuning_timer, jiffies +
+ host->tuning_count * HZ);
+ }
+
ret = mmc_suspend_host(host->mmc);
if (ret)
return ret;
@@ -1705,6 +2276,11 @@ int sdhci_resume_host(struct sdhci_host *host)
ret = mmc_resume_host(host->mmc);
sdhci_enable_card_detection(host);
+ /* Set the re-tuning expiration flag */
+ if ((host->version >= SDHCI_SPEC_300) && host->tuning_count &&
+ (host->tuning_mode == SDHCI_TUNING_MODE_1))
+ host->flags |= SDHCI_NEEDS_RETUNING;
+
return ret;
}
@@ -1751,7 +2327,9 @@ EXPORT_SYMBOL_GPL(sdhci_alloc_host);
int sdhci_add_host(struct sdhci_host *host)
{
struct mmc_host *mmc;
- unsigned int caps, ocr_avail;
+ u32 caps[2];
+ u32 max_current_caps;
+ unsigned int ocr_avail;
int ret;
WARN_ON(host == NULL);
@@ -1774,12 +2352,15 @@ int sdhci_add_host(struct sdhci_host *host)
host->version);
}
- caps = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps :
+ caps[0] = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps :
sdhci_readl(host, SDHCI_CAPABILITIES);
+ caps[1] = (host->version >= SDHCI_SPEC_300) ?
+ sdhci_readl(host, SDHCI_CAPABILITIES_1) : 0;
+
if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
host->flags |= SDHCI_USE_SDMA;
- else if (!(caps & SDHCI_CAN_DO_SDMA))
+ else if (!(caps[0] & SDHCI_CAN_DO_SDMA))
DBG("Controller doesn't have SDMA capability\n");
else
host->flags |= SDHCI_USE_SDMA;
@@ -1790,7 +2371,8 @@ int sdhci_add_host(struct sdhci_host *host)
host->flags &= ~SDHCI_USE_SDMA;
}
- if ((host->version >= SDHCI_SPEC_200) && (caps & SDHCI_CAN_DO_ADMA2))
+ if ((host->version >= SDHCI_SPEC_200) &&
+ (caps[0] & SDHCI_CAN_DO_ADMA2))
host->flags |= SDHCI_USE_ADMA;
if ((host->quirks & SDHCI_QUIRK_BROKEN_ADMA) &&
@@ -1840,10 +2422,10 @@ int sdhci_add_host(struct sdhci_host *host)
}
if (host->version >= SDHCI_SPEC_300)
- host->max_clk = (caps & SDHCI_CLOCK_V3_BASE_MASK)
+ host->max_clk = (caps[0] & SDHCI_CLOCK_V3_BASE_MASK)
>> SDHCI_CLOCK_BASE_SHIFT;
else
- host->max_clk = (caps & SDHCI_CLOCK_BASE_MASK)
+ host->max_clk = (caps[0] & SDHCI_CLOCK_BASE_MASK)
>> SDHCI_CLOCK_BASE_SHIFT;
host->max_clk *= 1000000;
@@ -1859,7 +2441,7 @@ int sdhci_add_host(struct sdhci_host *host)
}
host->timeout_clk =
- (caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
+ (caps[0] & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
if (host->timeout_clk == 0) {
if (host->ops->get_timeout_clock) {
host->timeout_clk = host->ops->get_timeout_clock(host);
@@ -1871,22 +2453,55 @@ int sdhci_add_host(struct sdhci_host *host)
return -ENODEV;
}
}
- if (caps & SDHCI_TIMEOUT_CLK_UNIT)
+ if (caps[0] & SDHCI_TIMEOUT_CLK_UNIT)
host->timeout_clk *= 1000;
/*
+ * In case of Host Controller v3.00, find out whether clock
+ * multiplier is supported.
+ */
+ host->clk_mul = (caps[1] & SDHCI_CLOCK_MUL_MASK) >>
+ SDHCI_CLOCK_MUL_SHIFT;
+
+ /*
+ * In case the value in Clock Multiplier is 0, then programmable
+ * clock mode is not supported, otherwise the actual clock
+ * multiplier is one more than the value of Clock Multiplier
+ * in the Capabilities Register.
+ */
+ if (host->clk_mul)
+ host->clk_mul += 1;
+
+ /*
* Set host parameters.
*/
mmc->ops = &sdhci_ops;
+ mmc->f_max = host->max_clk;
if (host->ops->get_min_clock)
mmc->f_min = host->ops->get_min_clock(host);
- else if (host->version >= SDHCI_SPEC_300)
- mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;
- else
+ else if (host->version >= SDHCI_SPEC_300) {
+ if (host->clk_mul) {
+ mmc->f_min = (host->max_clk * host->clk_mul) / 1024;
+ mmc->f_max = host->max_clk * host->clk_mul;
+ } else
+ mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;
+ } else
mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
- mmc->f_max = host->max_clk;
- mmc->caps |= MMC_CAP_SDIO_IRQ;
+ mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
+
+ if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
+ host->flags |= SDHCI_AUTO_CMD12;
+
+ /* Auto-CMD23 stuff only works in ADMA or PIO. */
+ if ((host->version >= SDHCI_SPEC_300) &&
+ ((host->flags & SDHCI_USE_ADMA) ||
+ !(host->flags & SDHCI_USE_SDMA))) {
+ host->flags |= SDHCI_AUTO_CMD23;
+ DBG("%s: Auto-CMD23 available\n", mmc_hostname(mmc));
+ } else {
+ DBG("%s: Auto-CMD23 unavailable\n", mmc_hostname(mmc));
+ }
/*
* A controller may support 8-bit width, but the board itself
@@ -1898,21 +2513,113 @@ int sdhci_add_host(struct sdhci_host *host)
if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA))
mmc->caps |= MMC_CAP_4_BIT_DATA;
- if (caps & SDHCI_CAN_DO_HISPD)
+ if (caps[0] & SDHCI_CAN_DO_HISPD)
mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) &&
mmc_card_is_removable(mmc))
mmc->caps |= MMC_CAP_NEEDS_POLL;
+ /* UHS-I mode(s) supported by the host controller. */
+ if (host->version >= SDHCI_SPEC_300)
+ mmc->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25;
+
+ /* SDR104 supports also implies SDR50 support */
+ if (caps[1] & SDHCI_SUPPORT_SDR104)
+ mmc->caps |= MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50;
+ else if (caps[1] & SDHCI_SUPPORT_SDR50)
+ mmc->caps |= MMC_CAP_UHS_SDR50;
+
+ if (caps[1] & SDHCI_SUPPORT_DDR50)
+ mmc->caps |= MMC_CAP_UHS_DDR50;
+
+ /* Does the host needs tuning for SDR50? */
+ if (caps[1] & SDHCI_USE_SDR50_TUNING)
+ host->flags |= SDHCI_SDR50_NEEDS_TUNING;
+
+ /* Driver Type(s) (A, C, D) supported by the host */
+ if (caps[1] & SDHCI_DRIVER_TYPE_A)
+ mmc->caps |= MMC_CAP_DRIVER_TYPE_A;
+ if (caps[1] & SDHCI_DRIVER_TYPE_C)
+ mmc->caps |= MMC_CAP_DRIVER_TYPE_C;
+ if (caps[1] & SDHCI_DRIVER_TYPE_D)
+ mmc->caps |= MMC_CAP_DRIVER_TYPE_D;
+
+ /* Initial value for re-tuning timer count */
+ host->tuning_count = (caps[1] & SDHCI_RETUNING_TIMER_COUNT_MASK) >>
+ SDHCI_RETUNING_TIMER_COUNT_SHIFT;
+
+ /*
+ * In case Re-tuning Timer is not disabled, the actual value of
+ * re-tuning timer will be 2 ^ (n - 1).
+ */
+ if (host->tuning_count)
+ host->tuning_count = 1 << (host->tuning_count - 1);
+
+ /* Re-tuning mode supported by the Host Controller */
+ host->tuning_mode = (caps[1] & SDHCI_RETUNING_MODE_MASK) >>
+ SDHCI_RETUNING_MODE_SHIFT;
+
ocr_avail = 0;
- if (caps & SDHCI_CAN_VDD_330)
+ /*
+ * According to SD Host Controller spec v3.00, if the Host System
+ * can afford more than 150mA, Host Driver should set XPC to 1. Also
+ * the value is meaningful only if Voltage Support in the Capabilities
+ * register is set. The actual current value is 4 times the register
+ * value.
+ */
+ max_current_caps = sdhci_readl(host, SDHCI_MAX_CURRENT);
+
+ if (caps[0] & SDHCI_CAN_VDD_330) {
+ int max_current_330;
+
ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34;
- if (caps & SDHCI_CAN_VDD_300)
+
+ max_current_330 = ((max_current_caps &
+ SDHCI_MAX_CURRENT_330_MASK) >>
+ SDHCI_MAX_CURRENT_330_SHIFT) *
+ SDHCI_MAX_CURRENT_MULTIPLIER;
+
+ if (max_current_330 > 150)
+ mmc->caps |= MMC_CAP_SET_XPC_330;
+ }
+ if (caps[0] & SDHCI_CAN_VDD_300) {
+ int max_current_300;
+
ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31;
- if (caps & SDHCI_CAN_VDD_180)
+
+ max_current_300 = ((max_current_caps &
+ SDHCI_MAX_CURRENT_300_MASK) >>
+ SDHCI_MAX_CURRENT_300_SHIFT) *
+ SDHCI_MAX_CURRENT_MULTIPLIER;
+
+ if (max_current_300 > 150)
+ mmc->caps |= MMC_CAP_SET_XPC_300;
+ }
+ if (caps[0] & SDHCI_CAN_VDD_180) {
+ int max_current_180;
+
ocr_avail |= MMC_VDD_165_195;
+ max_current_180 = ((max_current_caps &
+ SDHCI_MAX_CURRENT_180_MASK) >>
+ SDHCI_MAX_CURRENT_180_SHIFT) *
+ SDHCI_MAX_CURRENT_MULTIPLIER;
+
+ if (max_current_180 > 150)
+ mmc->caps |= MMC_CAP_SET_XPC_180;
+
+ /* Maximum current capabilities of the host at 1.8V */
+ if (max_current_180 >= 800)
+ mmc->caps |= MMC_CAP_MAX_CURRENT_800;
+ else if (max_current_180 >= 600)
+ mmc->caps |= MMC_CAP_MAX_CURRENT_600;
+ else if (max_current_180 >= 400)
+ mmc->caps |= MMC_CAP_MAX_CURRENT_400;
+ else
+ mmc->caps |= MMC_CAP_MAX_CURRENT_200;
+ }
+
mmc->ocr_avail = ocr_avail;
mmc->ocr_avail_sdio = ocr_avail;
if (host->ocr_avail_sdio)
@@ -1972,7 +2679,7 @@ int sdhci_add_host(struct sdhci_host *host)
if (host->quirks & SDHCI_QUIRK_FORCE_BLK_SZ_2048) {
mmc->max_blk_size = 2;
} else {
- mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >>
+ mmc->max_blk_size = (caps[0] & SDHCI_MAX_BLOCK_MASK) >>
SDHCI_MAX_BLOCK_SHIFT;
if (mmc->max_blk_size >= 3) {
printk(KERN_WARNING "%s: Invalid maximum block size, "
@@ -1998,6 +2705,15 @@ int sdhci_add_host(struct sdhci_host *host)
setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);
+ if (host->version >= SDHCI_SPEC_300) {
+ init_waitqueue_head(&host->buf_ready_int);
+
+ /* Initialize re-tuning timer */
+ init_timer(&host->tuning_timer);
+ host->tuning_timer.data = (unsigned long)host;
+ host->tuning_timer.function = sdhci_tuning_timer;
+ }
+
ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
mmc_hostname(mmc), host);
if (ret)
@@ -2091,6 +2807,8 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
free_irq(host->irq, host);
del_timer_sync(&host->timer);
+ if (host->version >= SDHCI_SPEC_300)
+ del_timer_sync(&host->tuning_timer);
tasklet_kill(&host->card_tasklet);
tasklet_kill(&host->finish_tasklet);
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 25e8bde600d1..745c42fa41ed 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -25,6 +25,7 @@
*/
#define SDHCI_DMA_ADDRESS 0x00
+#define SDHCI_ARGUMENT2 SDHCI_DMA_ADDRESS
#define SDHCI_BLOCK_SIZE 0x04
#define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF))
@@ -36,7 +37,8 @@
#define SDHCI_TRANSFER_MODE 0x0C
#define SDHCI_TRNS_DMA 0x01
#define SDHCI_TRNS_BLK_CNT_EN 0x02
-#define SDHCI_TRNS_ACMD12 0x04
+#define SDHCI_TRNS_AUTO_CMD12 0x04
+#define SDHCI_TRNS_AUTO_CMD23 0x08
#define SDHCI_TRNS_READ 0x10
#define SDHCI_TRNS_MULTI 0x20
@@ -68,8 +70,10 @@
#define SDHCI_DATA_AVAILABLE 0x00000800
#define SDHCI_CARD_PRESENT 0x00010000
#define SDHCI_WRITE_PROTECT 0x00080000
+#define SDHCI_DATA_LVL_MASK 0x00F00000
+#define SDHCI_DATA_LVL_SHIFT 20
-#define SDHCI_HOST_CONTROL 0x28
+#define SDHCI_HOST_CONTROL 0x28
#define SDHCI_CTRL_LED 0x01
#define SDHCI_CTRL_4BITBUS 0x02
#define SDHCI_CTRL_HISPD 0x04
@@ -99,6 +103,7 @@
#define SDHCI_DIV_MASK 0xFF
#define SDHCI_DIV_MASK_LEN 8
#define SDHCI_DIV_HI_MASK 0x300
+#define SDHCI_PROG_CLOCK_MODE 0x0020
#define SDHCI_CLOCK_CARD_EN 0x0004
#define SDHCI_CLOCK_INT_STABLE 0x0002
#define SDHCI_CLOCK_INT_EN 0x0001
@@ -146,7 +151,22 @@
#define SDHCI_ACMD12_ERR 0x3C
-/* 3E-3F reserved */
+#define SDHCI_HOST_CONTROL2 0x3E
+#define SDHCI_CTRL_UHS_MASK 0x0007
+#define SDHCI_CTRL_UHS_SDR12 0x0000
+#define SDHCI_CTRL_UHS_SDR25 0x0001
+#define SDHCI_CTRL_UHS_SDR50 0x0002
+#define SDHCI_CTRL_UHS_SDR104 0x0003
+#define SDHCI_CTRL_UHS_DDR50 0x0004
+#define SDHCI_CTRL_VDD_180 0x0008
+#define SDHCI_CTRL_DRV_TYPE_MASK 0x0030
+#define SDHCI_CTRL_DRV_TYPE_B 0x0000
+#define SDHCI_CTRL_DRV_TYPE_A 0x0010
+#define SDHCI_CTRL_DRV_TYPE_C 0x0020
+#define SDHCI_CTRL_DRV_TYPE_D 0x0030
+#define SDHCI_CTRL_EXEC_TUNING 0x0040
+#define SDHCI_CTRL_TUNED_CLK 0x0080
+#define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000
#define SDHCI_CAPABILITIES 0x40
#define SDHCI_TIMEOUT_CLK_MASK 0x0000003F
@@ -167,9 +187,30 @@
#define SDHCI_CAN_VDD_180 0x04000000
#define SDHCI_CAN_64BIT 0x10000000
+#define SDHCI_SUPPORT_SDR50 0x00000001
+#define SDHCI_SUPPORT_SDR104 0x00000002
+#define SDHCI_SUPPORT_DDR50 0x00000004
+#define SDHCI_DRIVER_TYPE_A 0x00000010
+#define SDHCI_DRIVER_TYPE_C 0x00000020
+#define SDHCI_DRIVER_TYPE_D 0x00000040
+#define SDHCI_RETUNING_TIMER_COUNT_MASK 0x00000F00
+#define SDHCI_RETUNING_TIMER_COUNT_SHIFT 8
+#define SDHCI_USE_SDR50_TUNING 0x00002000
+#define SDHCI_RETUNING_MODE_MASK 0x0000C000
+#define SDHCI_RETUNING_MODE_SHIFT 14
+#define SDHCI_CLOCK_MUL_MASK 0x00FF0000
+#define SDHCI_CLOCK_MUL_SHIFT 16
+
#define SDHCI_CAPABILITIES_1 0x44
-#define SDHCI_MAX_CURRENT 0x48
+#define SDHCI_MAX_CURRENT 0x48
+#define SDHCI_MAX_CURRENT_330_MASK 0x0000FF
+#define SDHCI_MAX_CURRENT_330_SHIFT 0
+#define SDHCI_MAX_CURRENT_300_MASK 0x00FF00
+#define SDHCI_MAX_CURRENT_300_SHIFT 8
+#define SDHCI_MAX_CURRENT_180_MASK 0xFF0000
+#define SDHCI_MAX_CURRENT_180_SHIFT 16
+#define SDHCI_MAX_CURRENT_MULTIPLIER 4
/* 4C-4F reserved for more max current */
@@ -202,6 +243,12 @@
#define SDHCI_MAX_DIV_SPEC_200 256
#define SDHCI_MAX_DIV_SPEC_300 2046
+/*
+ * Host SDMA buffer boundary. Valid values from 4K to 512K in powers of 2.
+ */
+#define SDHCI_DEFAULT_BOUNDARY_SIZE (512 * 1024)
+#define SDHCI_DEFAULT_BOUNDARY_ARG (ilog2(SDHCI_DEFAULT_BOUNDARY_SIZE) - 12)
+
struct sdhci_ops {
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
u32 (*read_l)(struct sdhci_host *host, int reg);
@@ -223,6 +270,10 @@ struct sdhci_ops {
void (*platform_send_init_74_clocks)(struct sdhci_host *host,
u8 power_mode);
unsigned int (*get_ro)(struct sdhci_host *host);
+ void (*platform_reset_enter)(struct sdhci_host *host, u8 mask);
+ void (*platform_reset_exit)(struct sdhci_host *host, u8 mask);
+ int (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
+
};
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c
index bbc298fd2a15..496b7efbc6b0 100644
--- a/drivers/mmc/host/sdricoh_cs.c
+++ b/drivers/mmc/host/sdricoh_cs.c
@@ -76,7 +76,7 @@ static unsigned int switchlocked;
#define BUSY_TIMEOUT 32767
/* list of supported pcmcia devices */
-static struct pcmcia_device_id pcmcia_ids[] = {
+static const struct pcmcia_device_id pcmcia_ids[] = {
/* vendor and device strings followed by their crc32 hashes */
PCMCIA_DEVICE_PROD_ID12("RICOH", "Bay1Controller", 0xd9f522ed,
0xc3901202),
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index af97015a2fc7..14f8edbaa195 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -29,6 +29,8 @@
#include <linux/mmc/sh_mmcif.h>
#include <linux/pagemap.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/spinlock.h>
#define DRIVER_NAME "sh_mmcif"
#define DRIVER_VERSION "2010-04-28"
@@ -153,6 +155,12 @@
#define CLKDEV_MMC_DATA 20000000 /* 20MHz */
#define CLKDEV_INIT 400000 /* 400 KHz */
+enum mmcif_state {
+ STATE_IDLE,
+ STATE_REQUEST,
+ STATE_IOS,
+};
+
struct sh_mmcif_host {
struct mmc_host *mmc;
struct mmc_data *data;
@@ -164,6 +172,9 @@ struct sh_mmcif_host {
long timeout;
void __iomem *addr;
struct completion intr_wait;
+ enum mmcif_state state;
+ spinlock_t lock;
+ bool power;
/* DMA support */
struct dma_chan *chan_rx;
@@ -798,17 +809,31 @@ static void sh_mmcif_stop_cmd(struct sh_mmcif_host *host,
static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct sh_mmcif_host *host = mmc_priv(mmc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ if (host->state != STATE_IDLE) {
+ spin_unlock_irqrestore(&host->lock, flags);
+ mrq->cmd->error = -EAGAIN;
+ mmc_request_done(mmc, mrq);
+ return;
+ }
+
+ host->state = STATE_REQUEST;
+ spin_unlock_irqrestore(&host->lock, flags);
switch (mrq->cmd->opcode) {
/* MMCIF does not support SD/SDIO command */
case SD_IO_SEND_OP_COND:
case MMC_APP_CMD:
+ host->state = STATE_IDLE;
mrq->cmd->error = -ETIMEDOUT;
mmc_request_done(mmc, mrq);
return;
case MMC_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */
if (!mrq->data) {
/* send_if_cond cmd (not support) */
+ host->state = STATE_IDLE;
mrq->cmd->error = -ETIMEDOUT;
mmc_request_done(mmc, mrq);
return;
@@ -830,12 +855,9 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
sh_mmcif_start_cmd(host, mrq, mrq->cmd);
host->data = NULL;
- if (mrq->cmd->error != 0) {
- mmc_request_done(mmc, mrq);
- return;
- }
- if (mrq->stop)
+ if (!mrq->cmd->error && mrq->stop)
sh_mmcif_stop_cmd(host, mrq, mrq->stop);
+ host->state = STATE_IDLE;
mmc_request_done(mmc, mrq);
}
@@ -843,15 +865,39 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct sh_mmcif_host *host = mmc_priv(mmc);
struct sh_mmcif_plat_data *p = host->pd->dev.platform_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ if (host->state != STATE_IDLE) {
+ spin_unlock_irqrestore(&host->lock, flags);
+ return;
+ }
+
+ host->state = STATE_IOS;
+ spin_unlock_irqrestore(&host->lock, flags);
if (ios->power_mode == MMC_POWER_UP) {
if (p->set_pwr)
p->set_pwr(host->pd, ios->power_mode);
+ if (!host->power) {
+ /* See if we also get DMA */
+ sh_mmcif_request_dma(host, host->pd->dev.platform_data);
+ pm_runtime_get_sync(&host->pd->dev);
+ host->power = true;
+ }
} else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) {
/* clock stop */
sh_mmcif_clock_control(host, 0);
- if (ios->power_mode == MMC_POWER_OFF && p->down_pwr)
- p->down_pwr(host->pd);
+ if (ios->power_mode == MMC_POWER_OFF) {
+ if (host->power) {
+ pm_runtime_put(&host->pd->dev);
+ sh_mmcif_release_dma(host);
+ host->power = false;
+ }
+ if (p->down_pwr)
+ p->down_pwr(host->pd);
+ }
+ host->state = STATE_IDLE;
return;
}
@@ -859,6 +905,7 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
sh_mmcif_clock_control(host, ios->clock);
host->bus_width = ios->bus_width;
+ host->state = STATE_IDLE;
}
static int sh_mmcif_get_cd(struct mmc_host *mmc)
@@ -925,7 +972,7 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state);
err = 1;
} else {
- dev_dbg(&host->pd->dev, "Not support int\n");
+ dev_dbg(&host->pd->dev, "Unsupported interrupt: 0x%x\n", state);
sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state);
sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state);
err = 1;
@@ -996,6 +1043,7 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
host->pd = pdev;
init_completion(&host->intr_wait);
+ spin_lock_init(&host->lock);
mmc->ops = &sh_mmcif_ops;
mmc->f_max = host->clk;
@@ -1020,24 +1068,29 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
sh_mmcif_sync_reset(host);
platform_set_drvdata(pdev, host);
- /* See if we also get DMA */
- sh_mmcif_request_dma(host, pd);
+ pm_runtime_enable(&pdev->dev);
+ host->power = false;
+
+ ret = pm_runtime_resume(&pdev->dev);
+ if (ret < 0)
+ goto clean_up2;
mmc_add_host(mmc);
+ sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
+
ret = request_irq(irq[0], sh_mmcif_intr, 0, "sh_mmc:error", host);
if (ret) {
dev_err(&pdev->dev, "request_irq error (sh_mmc:error)\n");
- goto clean_up2;
+ goto clean_up3;
}
ret = request_irq(irq[1], sh_mmcif_intr, 0, "sh_mmc:int", host);
if (ret) {
free_irq(irq[0], host);
dev_err(&pdev->dev, "request_irq error (sh_mmc:int)\n");
- goto clean_up2;
+ goto clean_up3;
}
- sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
sh_mmcif_detect(host->mmc);
dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION);
@@ -1045,7 +1098,11 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff);
return ret;
+clean_up3:
+ mmc_remove_host(mmc);
+ pm_runtime_suspend(&pdev->dev);
clean_up2:
+ pm_runtime_disable(&pdev->dev);
clk_disable(host->hclk);
clean_up1:
mmc_free_host(mmc);
@@ -1060,14 +1117,14 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev)
struct sh_mmcif_host *host = platform_get_drvdata(pdev);
int irq[2];
+ pm_runtime_get_sync(&pdev->dev);
+
mmc_remove_host(host->mmc);
- sh_mmcif_release_dma(host);
+ sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
if (host->addr)
iounmap(host->addr);
- sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
-
irq[0] = platform_get_irq(pdev, 0);
irq[1] = platform_get_irq(pdev, 1);
@@ -1078,15 +1135,52 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev)
clk_disable(host->hclk);
mmc_free_host(host->mmc);
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
return 0;
}
+#ifdef CONFIG_PM
+static int sh_mmcif_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct sh_mmcif_host *host = platform_get_drvdata(pdev);
+ int ret = mmc_suspend_host(host->mmc);
+
+ if (!ret) {
+ sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
+ clk_disable(host->hclk);
+ }
+
+ return ret;
+}
+
+static int sh_mmcif_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct sh_mmcif_host *host = platform_get_drvdata(pdev);
+
+ clk_enable(host->hclk);
+
+ return mmc_resume_host(host->mmc);
+}
+#else
+#define sh_mmcif_suspend NULL
+#define sh_mmcif_resume NULL
+#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops sh_mmcif_dev_pm_ops = {
+ .suspend = sh_mmcif_suspend,
+ .resume = sh_mmcif_resume,
+};
+
static struct platform_driver sh_mmcif_driver = {
.probe = sh_mmcif_probe,
.remove = sh_mmcif_remove,
.driver = {
.name = DRIVER_NAME,
+ .pm = &sh_mmcif_dev_pm_ops,
},
};
diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index cc701236d16f..b3654293017b 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -62,7 +62,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
struct tmio_mmc_host *host;
char clk_name[8];
- int ret;
+ int i, irq, ret;
priv = kzalloc(sizeof(struct sh_mobile_sdhi), GFP_KERNEL);
if (priv == NULL) {
@@ -71,6 +71,7 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
}
mmc_data = &priv->mmc_data;
+ p->pdata = mmc_data;
snprintf(clk_name, sizeof(clk_name), "sdhi%d", pdev->id);
priv->clk = clk_get(&pdev->dev, clk_name);
@@ -116,11 +117,36 @@ static int __devinit sh_mobile_sdhi_probe(struct platform_device *pdev)
if (ret < 0)
goto eprobe;
- pr_info("%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc),
- (unsigned long)host->ctl, host->irq);
+ for (i = 0; i < 3; i++) {
+ irq = platform_get_irq(pdev, i);
+ if (irq < 0) {
+ if (i) {
+ continue;
+ } else {
+ ret = irq;
+ goto eirq;
+ }
+ }
+ ret = request_irq(irq, tmio_mmc_irq, 0,
+ dev_name(&pdev->dev), host);
+ if (ret) {
+ while (i--) {
+ irq = platform_get_irq(pdev, i);
+ if (irq >= 0)
+ free_irq(irq, host);
+ }
+ goto eirq;
+ }
+ }
+ dev_info(&pdev->dev, "%s base at 0x%08lx clock rate %u MHz\n",
+ mmc_hostname(host->mmc), (unsigned long)
+ (platform_get_resource(pdev,IORESOURCE_MEM, 0)->start),
+ mmc_data->hclk / 1000000);
return ret;
+eirq:
+ tmio_mmc_host_remove(host);
eprobe:
clk_disable(priv->clk);
clk_put(priv->clk);
@@ -134,6 +160,16 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev)
struct mmc_host *mmc = platform_get_drvdata(pdev);
struct tmio_mmc_host *host = mmc_priv(mmc);
struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data);
+ struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
+ int i, irq;
+
+ p->pdata = NULL;
+
+ for (i = 0; i < 3; i++) {
+ irq = platform_get_irq(pdev, i);
+ if (irq >= 0)
+ free_irq(irq, host);
+ }
tmio_mmc_host_remove(host);
clk_disable(priv->clk);
@@ -143,10 +179,18 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev)
return 0;
}
+static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
+ .suspend = tmio_mmc_host_suspend,
+ .resume = tmio_mmc_host_resume,
+ .runtime_suspend = tmio_mmc_host_runtime_suspend,
+ .runtime_resume = tmio_mmc_host_runtime_resume,
+};
+
static struct platform_driver sh_mobile_sdhi_driver = {
.driver = {
.name = "sh_mobile_sdhi",
.owner = THIS_MODULE,
+ .pm = &tmio_mmc_dev_pm_ops,
},
.probe = sh_mobile_sdhi_probe,
.remove = __devexit_p(sh_mobile_sdhi_remove),
diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c
index 79c568461d59..8d185de90d20 100644
--- a/drivers/mmc/host/tmio_mmc.c
+++ b/drivers/mmc/host/tmio_mmc.c
@@ -30,7 +30,7 @@ static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state)
struct mmc_host *mmc = platform_get_drvdata(dev);
int ret;
- ret = mmc_suspend_host(mmc);
+ ret = tmio_mmc_host_suspend(&dev->dev);
/* Tell MFD core it can disable us now.*/
if (!ret && cell->disable)
@@ -46,15 +46,12 @@ static int tmio_mmc_resume(struct platform_device *dev)
int ret = 0;
/* Tell the MFD core we are ready to be enabled */
- if (cell->resume) {
+ if (cell->resume)
ret = cell->resume(dev);
- if (ret)
- goto out;
- }
- mmc_resume_host(mmc);
+ if (!ret)
+ ret = tmio_mmc_host_resume(&dev->dev);
-out:
return ret;
}
#else
@@ -67,15 +64,21 @@ static int __devinit tmio_mmc_probe(struct platform_device *pdev)
const struct mfd_cell *cell = mfd_get_cell(pdev);
struct tmio_mmc_data *pdata;
struct tmio_mmc_host *host;
- int ret = -EINVAL;
+ int ret = -EINVAL, irq;
if (pdev->num_resources != 2)
goto out;
- pdata = mfd_get_data(pdev);
+ pdata = pdev->dev.platform_data;
if (!pdata || !pdata->hclk)
goto out;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ ret = irq;
+ goto out;
+ }
+
/* Tell the MFD core we are ready to be enabled */
if (cell->enable) {
ret = cell->enable(pdev);
@@ -87,11 +90,18 @@ static int __devinit tmio_mmc_probe(struct platform_device *pdev)
if (ret)
goto cell_disable;
+ ret = request_irq(irq, tmio_mmc_irq, IRQF_DISABLED |
+ IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), host);
+ if (ret)
+ goto host_remove;
+
pr_info("%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc),
- (unsigned long)host->ctl, host->irq);
+ (unsigned long)host->ctl, irq);
return 0;
+host_remove:
+ tmio_mmc_host_remove(host);
cell_disable:
if (cell->disable)
cell->disable(pdev);
@@ -107,7 +117,9 @@ static int __devexit tmio_mmc_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL);
if (mmc) {
- tmio_mmc_host_remove(mmc_priv(mmc));
+ struct tmio_mmc_host *host = mmc_priv(mmc);
+ free_irq(platform_get_irq(pdev, 0), host);
+ tmio_mmc_host_remove(host);
if (cell->disable)
cell->disable(pdev);
}
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index 099ed49a259b..8260bc2c34e3 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -19,6 +19,7 @@
#include <linux/highmem.h>
#include <linux/mmc/tmio.h>
#include <linux/pagemap.h>
+#include <linux/spinlock.h>
/* Definitions for values the CTRL_SDIO_STATUS register can take. */
#define TMIO_SDIO_STAT_IOIRQ 0x0001
@@ -44,13 +45,14 @@ struct tmio_mmc_host {
struct mmc_request *mrq;
struct mmc_data *data;
struct mmc_host *mmc;
- int irq;
unsigned int sdio_irq_enabled;
/* Callbacks for clock / power control */
void (*set_pwr)(struct platform_device *host, int state);
void (*set_clk_div)(struct platform_device *host, int state);
+ int pm_error;
+
/* pio related stuff */
struct scatterlist *sg_ptr;
struct scatterlist *sg_orig;
@@ -83,6 +85,7 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host);
void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i);
+irqreturn_t tmio_mmc_irq(int irq, void *devid);
static inline char *tmio_mmc_kmap_atomic(struct scatterlist *sg,
unsigned long *flags)
@@ -120,4 +123,15 @@ static inline void tmio_mmc_release_dma(struct tmio_mmc_host *host)
}
#endif
+#ifdef CONFIG_PM
+int tmio_mmc_host_suspend(struct device *dev);
+int tmio_mmc_host_resume(struct device *dev);
+#else
+#define tmio_mmc_host_suspend NULL
+#define tmio_mmc_host_resume NULL
+#endif
+
+int tmio_mmc_host_runtime_suspend(struct device *dev);
+int tmio_mmc_host_runtime_resume(struct device *dev);
+
#endif
diff --git a/drivers/mmc/host/tmio_mmc_dma.c b/drivers/mmc/host/tmio_mmc_dma.c
index d3de74ab633e..25f1ad6cbe09 100644
--- a/drivers/mmc/host/tmio_mmc_dma.c
+++ b/drivers/mmc/host/tmio_mmc_dma.c
@@ -256,7 +256,10 @@ static bool tmio_mmc_filter(struct dma_chan *chan, void *arg)
void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata)
{
/* We can only either use DMA for both Tx and Rx or not use it at all */
- if (pdata->dma) {
+ if (!pdata->dma)
+ return;
+
+ if (!host->chan_tx && !host->chan_rx) {
dma_cap_mask_t mask;
dma_cap_zero(mask);
@@ -284,18 +287,18 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat
tasklet_init(&host->dma_complete, tmio_mmc_tasklet_fn, (unsigned long)host);
tasklet_init(&host->dma_issue, tmio_mmc_issue_tasklet_fn, (unsigned long)host);
+ }
- tmio_mmc_enable_dma(host, true);
+ tmio_mmc_enable_dma(host, true);
+
+ return;
- return;
ebouncebuf:
- dma_release_channel(host->chan_rx);
- host->chan_rx = NULL;
+ dma_release_channel(host->chan_rx);
+ host->chan_rx = NULL;
ereqrx:
- dma_release_channel(host->chan_tx);
- host->chan_tx = NULL;
- return;
- }
+ dma_release_channel(host->chan_tx);
+ host->chan_tx = NULL;
}
void tmio_mmc_release_dma(struct tmio_mmc_host *host)
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index 710339a85c84..ad6347bb02dd 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -39,6 +39,7 @@
#include <linux/module.h>
#include <linux/pagemap.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/scatterlist.h>
#include <linux/workqueue.h>
#include <linux/spinlock.h>
@@ -243,8 +244,12 @@ static void tmio_mmc_reset_work(struct work_struct *work)
spin_lock_irqsave(&host->lock, flags);
mrq = host->mrq;
- /* request already finished */
- if (!mrq
+ /*
+ * is request already finished? Since we use a non-blocking
+ * cancel_delayed_work(), it can happen, that a .set_ios() call preempts
+ * us, so, have to check for IS_ERR(host->mrq)
+ */
+ if (IS_ERR_OR_NULL(mrq)
|| time_is_after_jiffies(host->last_req_ts +
msecs_to_jiffies(2000))) {
spin_unlock_irqrestore(&host->lock, flags);
@@ -264,16 +269,19 @@ static void tmio_mmc_reset_work(struct work_struct *work)
host->cmd = NULL;
host->data = NULL;
- host->mrq = NULL;
host->force_pio = false;
spin_unlock_irqrestore(&host->lock, flags);
tmio_mmc_reset(host);
+ /* Ready for new calls */
+ host->mrq = NULL;
+
mmc_request_done(host->mmc, mrq);
}
+/* called with host->lock held, interrupts disabled */
static void tmio_mmc_finish_request(struct tmio_mmc_host *host)
{
struct mmc_request *mrq = host->mrq;
@@ -281,13 +289,15 @@ static void tmio_mmc_finish_request(struct tmio_mmc_host *host)
if (!mrq)
return;
- host->mrq = NULL;
host->cmd = NULL;
host->data = NULL;
host->force_pio = false;
cancel_delayed_work(&host->delayed_reset_work);
+ host->mrq = NULL;
+
+ /* FIXME: mmc_request_done() can schedule! */
mmc_request_done(host->mmc, mrq);
}
@@ -554,7 +564,7 @@ out:
spin_unlock(&host->lock);
}
-static irqreturn_t tmio_mmc_irq(int irq, void *devid)
+irqreturn_t tmio_mmc_irq(int irq, void *devid)
{
struct tmio_mmc_host *host = devid;
struct tmio_mmc_data *pdata = host->pdata;
@@ -649,6 +659,7 @@ static irqreturn_t tmio_mmc_irq(int irq, void *devid)
out:
return IRQ_HANDLED;
}
+EXPORT_SYMBOL(tmio_mmc_irq);
static int tmio_mmc_start_data(struct tmio_mmc_host *host,
struct mmc_data *data)
@@ -685,15 +696,27 @@ static int tmio_mmc_start_data(struct tmio_mmc_host *host,
static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct tmio_mmc_host *host = mmc_priv(mmc);
+ unsigned long flags;
int ret;
- if (host->mrq)
+ spin_lock_irqsave(&host->lock, flags);
+
+ if (host->mrq) {
pr_debug("request not null\n");
+ if (IS_ERR(host->mrq)) {
+ spin_unlock_irqrestore(&host->lock, flags);
+ mrq->cmd->error = -EAGAIN;
+ mmc_request_done(mmc, mrq);
+ return;
+ }
+ }
host->last_req_ts = jiffies;
wmb();
host->mrq = mrq;
+ spin_unlock_irqrestore(&host->lock, flags);
+
if (mrq->data) {
ret = tmio_mmc_start_data(host, mrq->data);
if (ret)
@@ -708,8 +731,8 @@ static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
}
fail:
- host->mrq = NULL;
host->force_pio = false;
+ host->mrq = NULL;
mrq->cmd->error = ret;
mmc_request_done(mmc, mrq);
}
@@ -723,19 +746,54 @@ fail:
static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct tmio_mmc_host *host = mmc_priv(mmc);
+ struct tmio_mmc_data *pdata = host->pdata;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ if (host->mrq) {
+ if (IS_ERR(host->mrq)) {
+ dev_dbg(&host->pdev->dev,
+ "%s.%d: concurrent .set_ios(), clk %u, mode %u\n",
+ current->comm, task_pid_nr(current),
+ ios->clock, ios->power_mode);
+ host->mrq = ERR_PTR(-EINTR);
+ } else {
+ dev_dbg(&host->pdev->dev,
+ "%s.%d: CMD%u active since %lu, now %lu!\n",
+ current->comm, task_pid_nr(current),
+ host->mrq->cmd->opcode, host->last_req_ts, jiffies);
+ }
+ spin_unlock_irqrestore(&host->lock, flags);
+ return;
+ }
+
+ host->mrq = ERR_PTR(-EBUSY);
+
+ spin_unlock_irqrestore(&host->lock, flags);
if (ios->clock)
tmio_mmc_set_clock(host, ios->clock);
/* Power sequence - OFF -> UP -> ON */
if (ios->power_mode == MMC_POWER_UP) {
+ if ((pdata->flags & TMIO_MMC_HAS_COLD_CD) && !pdata->power) {
+ pm_runtime_get_sync(&host->pdev->dev);
+ pdata->power = true;
+ }
/* power up SD bus */
if (host->set_pwr)
host->set_pwr(host->pdev, 1);
} else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) {
/* power down SD bus */
- if (ios->power_mode == MMC_POWER_OFF && host->set_pwr)
- host->set_pwr(host->pdev, 0);
+ if (ios->power_mode == MMC_POWER_OFF) {
+ if (host->set_pwr)
+ host->set_pwr(host->pdev, 0);
+ if ((pdata->flags & TMIO_MMC_HAS_COLD_CD) &&
+ pdata->power) {
+ pdata->power = false;
+ pm_runtime_put(&host->pdev->dev);
+ }
+ }
tmio_mmc_clk_stop(host);
} else {
/* start bus clock */
@@ -753,6 +811,12 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
/* Let things settle. delay taken from winCE driver */
udelay(140);
+ if (PTR_ERR(host->mrq) == -EINTR)
+ dev_dbg(&host->pdev->dev,
+ "%s.%d: IOS interrupted: clk %u, mode %u",
+ current->comm, task_pid_nr(current),
+ ios->clock, ios->power_mode);
+ host->mrq = NULL;
}
static int tmio_mmc_get_ro(struct mmc_host *mmc)
@@ -801,6 +865,7 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
if (!mmc)
return -ENOMEM;
+ pdata->dev = &pdev->dev;
_host = mmc_priv(mmc);
_host->pdata = pdata;
_host->mmc = mmc;
@@ -834,24 +899,19 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
else
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
- tmio_mmc_clk_stop(_host);
- tmio_mmc_reset(_host);
-
- ret = platform_get_irq(pdev, 0);
+ pdata->power = false;
+ pm_runtime_enable(&pdev->dev);
+ ret = pm_runtime_resume(&pdev->dev);
if (ret < 0)
- goto unmap_ctl;
+ goto pm_disable;
- _host->irq = ret;
+ tmio_mmc_clk_stop(_host);
+ tmio_mmc_reset(_host);
tmio_mmc_disable_mmc_irqs(_host, TMIO_MASK_ALL);
if (pdata->flags & TMIO_MMC_SDIO_IRQ)
tmio_mmc_enable_sdio_irq(mmc, 0);
- ret = request_irq(_host->irq, tmio_mmc_irq, IRQF_DISABLED |
- IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), _host);
- if (ret)
- goto unmap_ctl;
-
spin_lock_init(&_host->lock);
/* Init delayed work for request timeouts */
@@ -860,6 +920,10 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
/* See if we also get DMA */
tmio_mmc_request_dma(_host, pdata);
+ /* We have to keep the device powered for its card detection to work */
+ if (!(pdata->flags & TMIO_MMC_HAS_COLD_CD))
+ pm_runtime_get_noresume(&pdev->dev);
+
mmc_add_host(mmc);
/* Unmask the IRQs we want to know about */
@@ -874,7 +938,8 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
return 0;
-unmap_ctl:
+pm_disable:
+ pm_runtime_disable(&pdev->dev);
iounmap(_host->ctl);
host_free:
mmc_free_host(mmc);
@@ -885,13 +950,88 @@ EXPORT_SYMBOL(tmio_mmc_host_probe);
void tmio_mmc_host_remove(struct tmio_mmc_host *host)
{
+ struct platform_device *pdev = host->pdev;
+
+ /*
+ * We don't have to manipulate pdata->power here: if there is a card in
+ * the slot, the runtime PM is active and our .runtime_resume() will not
+ * be run. If there is no card in the slot and the platform can suspend
+ * the controller, the runtime PM is suspended and pdata->power == false,
+ * so, our .runtime_resume() will not try to detect a card in the slot.
+ */
+ if (host->pdata->flags & TMIO_MMC_HAS_COLD_CD)
+ pm_runtime_get_sync(&pdev->dev);
+
mmc_remove_host(host->mmc);
cancel_delayed_work_sync(&host->delayed_reset_work);
tmio_mmc_release_dma(host);
- free_irq(host->irq, host);
+
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
iounmap(host->ctl);
mmc_free_host(host->mmc);
}
EXPORT_SYMBOL(tmio_mmc_host_remove);
+#ifdef CONFIG_PM
+int tmio_mmc_host_suspend(struct device *dev)
+{
+ struct mmc_host *mmc = dev_get_drvdata(dev);
+ struct tmio_mmc_host *host = mmc_priv(mmc);
+ int ret = mmc_suspend_host(mmc);
+
+ if (!ret)
+ tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_ALL);
+
+ host->pm_error = pm_runtime_put_sync(dev);
+
+ return ret;
+}
+EXPORT_SYMBOL(tmio_mmc_host_suspend);
+
+int tmio_mmc_host_resume(struct device *dev)
+{
+ struct mmc_host *mmc = dev_get_drvdata(dev);
+ struct tmio_mmc_host *host = mmc_priv(mmc);
+
+ /* The MMC core will perform the complete set up */
+ host->pdata->power = false;
+
+ if (!host->pm_error)
+ pm_runtime_get_sync(dev);
+
+ tmio_mmc_reset(mmc_priv(mmc));
+ tmio_mmc_request_dma(host, host->pdata);
+
+ return mmc_resume_host(mmc);
+}
+EXPORT_SYMBOL(tmio_mmc_host_resume);
+
+#endif /* CONFIG_PM */
+
+int tmio_mmc_host_runtime_suspend(struct device *dev)
+{
+ return 0;
+}
+EXPORT_SYMBOL(tmio_mmc_host_runtime_suspend);
+
+int tmio_mmc_host_runtime_resume(struct device *dev)
+{
+ struct mmc_host *mmc = dev_get_drvdata(dev);
+ struct tmio_mmc_host *host = mmc_priv(mmc);
+ struct tmio_mmc_data *pdata = host->pdata;
+
+ tmio_mmc_reset(host);
+
+ if (pdata->power) {
+ /* Only entered after a card-insert interrupt */
+ tmio_mmc_set_ios(mmc, &mmc->ios);
+ mmc_detect_change(mmc, msecs_to_jiffies(100));
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(tmio_mmc_host_runtime_resume);
+
MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c
new file mode 100644
index 000000000000..cbb03305b77b
--- /dev/null
+++ b/drivers/mmc/host/vub300.c
@@ -0,0 +1,2506 @@
+/*
+ * Remote VUB300 SDIO/SDmem Host Controller Driver
+ *
+ * Copyright (C) 2010 Elan Digital Systems Limited
+ *
+ * based on USB Skeleton driver - 2.2
+ *
+ * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2
+ *
+ * VUB300: is a USB 2.0 client device with a single SDIO/SDmem/MMC slot
+ * Any SDIO/SDmem/MMC device plugged into the VUB300 will appear,
+ * by virtue of this driver, to have been plugged into a local
+ * SDIO host controller, similar to, say, a PCI Ricoh controller
+ * This is because this kernel device driver is both a USB 2.0
+ * client device driver AND an MMC host controller driver. Thus
+ * if there is an existing driver for the inserted SDIO/SDmem/MMC
+ * device then that driver will be used by the kernel to manage
+ * the device in exactly the same fashion as if it had been
+ * directly plugged into, say, a local pci bus Ricoh controller
+ *
+ * RANT: this driver was written using a display 128x48 - converting it
+ * to a line width of 80 makes it very difficult to support. In
+ * particular functions have been broken down into sub functions
+ * and the original meaningful names have been shortened into
+ * cryptic ones.
+ * The problem is that executing a fragment of code subject to
+ * two conditions means an indentation of 24, thus leaving only
+ * 56 characters for a C statement. And that is quite ridiculous!
+ *
+ * Data types: data passed to/from the VUB300 is fixed to a number of
+ * bits and driver data fields reflect that limit by using
+ * u8, u16, u32
+ */
+#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/uaccess.h>
+#include <linux/usb.h>
+#include <linux/mutex.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/workqueue.h>
+#include <linux/ctype.h>
+#include <linux/firmware.h>
+#include <linux/scatterlist.h>
+
+struct host_controller_info {
+ u8 info_size;
+ u16 firmware_version;
+ u8 number_of_ports;
+} __packed;
+
+#define FIRMWARE_BLOCK_BOUNDARY 1024
+struct sd_command_header {
+ u8 header_size;
+ u8 header_type;
+ u8 port_number;
+ u8 command_type; /* Bit7 - Rd/Wr */
+ u8 command_index;
+ u8 transfer_size[4]; /* ReadSize + ReadSize */
+ u8 response_type;
+ u8 arguments[4];
+ u8 block_count[2];
+ u8 block_size[2];
+ u8 block_boundary[2];
+ u8 reserved[44]; /* to pad out to 64 bytes */
+} __packed;
+
+struct sd_irqpoll_header {
+ u8 header_size;
+ u8 header_type;
+ u8 port_number;
+ u8 command_type; /* Bit7 - Rd/Wr */
+ u8 padding[16]; /* don't ask why !! */
+ u8 poll_timeout_msb;
+ u8 poll_timeout_lsb;
+ u8 reserved[42]; /* to pad out to 64 bytes */
+} __packed;
+
+struct sd_common_header {
+ u8 header_size;
+ u8 header_type;
+ u8 port_number;
+} __packed;
+
+struct sd_response_header {
+ u8 header_size;
+ u8 header_type;
+ u8 port_number;
+ u8 command_type;
+ u8 command_index;
+ u8 command_response[0];
+} __packed;
+
+struct sd_status_header {
+ u8 header_size;
+ u8 header_type;
+ u8 port_number;
+ u16 port_flags;
+ u32 sdio_clock;
+ u16 host_header_size;
+ u16 func_header_size;
+ u16 ctrl_header_size;
+} __packed;
+
+struct sd_error_header {
+ u8 header_size;
+ u8 header_type;
+ u8 port_number;
+ u8 error_code;
+} __packed;
+
+struct sd_interrupt_header {
+ u8 header_size;
+ u8 header_type;
+ u8 port_number;
+} __packed;
+
+struct offload_registers_access {
+ u8 command_byte[4];
+ u8 Respond_Byte[4];
+} __packed;
+
+#define INTERRUPT_REGISTER_ACCESSES 15
+struct sd_offloaded_interrupt {
+ u8 header_size;
+ u8 header_type;
+ u8 port_number;
+ struct offload_registers_access reg[INTERRUPT_REGISTER_ACCESSES];
+} __packed;
+
+struct sd_register_header {
+ u8 header_size;
+ u8 header_type;
+ u8 port_number;
+ u8 command_type;
+ u8 command_index;
+ u8 command_response[6];
+} __packed;
+
+#define PIGGYBACK_REGISTER_ACCESSES 14
+struct sd_offloaded_piggyback {
+ struct sd_register_header sdio;
+ struct offload_registers_access reg[PIGGYBACK_REGISTER_ACCESSES];
+} __packed;
+
+union sd_response {
+ struct sd_common_header common;
+ struct sd_status_header status;
+ struct sd_error_header error;
+ struct sd_interrupt_header interrupt;
+ struct sd_response_header response;
+ struct sd_offloaded_interrupt irq;
+ struct sd_offloaded_piggyback pig;
+} __packed;
+
+union sd_command {
+ struct sd_command_header head;
+ struct sd_irqpoll_header poll;
+} __packed;
+
+enum SD_RESPONSE_TYPE {
+ SDRT_UNSPECIFIED = 0,
+ SDRT_NONE,
+ SDRT_1,
+ SDRT_1B,
+ SDRT_2,
+ SDRT_3,
+ SDRT_4,
+ SDRT_5,
+ SDRT_5B,
+ SDRT_6,
+ SDRT_7,
+};
+
+#define RESPONSE_INTERRUPT 0x01
+#define RESPONSE_ERROR 0x02
+#define RESPONSE_STATUS 0x03
+#define RESPONSE_IRQ_DISABLED 0x05
+#define RESPONSE_IRQ_ENABLED 0x06
+#define RESPONSE_PIGGYBACKED 0x07
+#define RESPONSE_NO_INTERRUPT 0x08
+#define RESPONSE_PIG_DISABLED 0x09
+#define RESPONSE_PIG_ENABLED 0x0A
+#define SD_ERROR_1BIT_TIMEOUT 0x01
+#define SD_ERROR_4BIT_TIMEOUT 0x02
+#define SD_ERROR_1BIT_CRC_WRONG 0x03
+#define SD_ERROR_4BIT_CRC_WRONG 0x04
+#define SD_ERROR_1BIT_CRC_ERROR 0x05
+#define SD_ERROR_4BIT_CRC_ERROR 0x06
+#define SD_ERROR_NO_CMD_ENDBIT 0x07
+#define SD_ERROR_NO_1BIT_DATEND 0x08
+#define SD_ERROR_NO_4BIT_DATEND 0x09
+#define SD_ERROR_1BIT_UNEXPECTED_TIMEOUT 0x0A
+#define SD_ERROR_4BIT_UNEXPECTED_TIMEOUT 0x0B
+#define SD_ERROR_ILLEGAL_COMMAND 0x0C
+#define SD_ERROR_NO_DEVICE 0x0D
+#define SD_ERROR_TRANSFER_LENGTH 0x0E
+#define SD_ERROR_1BIT_DATA_TIMEOUT 0x0F
+#define SD_ERROR_4BIT_DATA_TIMEOUT 0x10
+#define SD_ERROR_ILLEGAL_STATE 0x11
+#define SD_ERROR_UNKNOWN_ERROR 0x12
+#define SD_ERROR_RESERVED_ERROR 0x13
+#define SD_ERROR_INVALID_FUNCTION 0x14
+#define SD_ERROR_OUT_OF_RANGE 0x15
+#define SD_ERROR_STAT_CMD 0x16
+#define SD_ERROR_STAT_DATA 0x17
+#define SD_ERROR_STAT_CMD_TIMEOUT 0x18
+#define SD_ERROR_SDCRDY_STUCK 0x19
+#define SD_ERROR_UNHANDLED 0x1A
+#define SD_ERROR_OVERRUN 0x1B
+#define SD_ERROR_PIO_TIMEOUT 0x1C
+
+#define FUN(c) (0x000007 & (c->arg>>28))
+#define REG(c) (0x01FFFF & (c->arg>>9))
+
+static int limit_speed_to_24_MHz;
+module_param(limit_speed_to_24_MHz, bool, 0644);
+MODULE_PARM_DESC(limit_speed_to_24_MHz, "Limit Max SDIO Clock Speed to 24 MHz");
+
+static int pad_input_to_usb_pkt;
+module_param(pad_input_to_usb_pkt, bool, 0644);
+MODULE_PARM_DESC(pad_input_to_usb_pkt,
+ "Pad USB data input transfers to whole USB Packet");
+
+static int disable_offload_processing;
+module_param(disable_offload_processing, bool, 0644);
+MODULE_PARM_DESC(disable_offload_processing, "Disable Offload Processing");
+
+static int force_1_bit_data_xfers;
+module_param(force_1_bit_data_xfers, bool, 0644);
+MODULE_PARM_DESC(force_1_bit_data_xfers,
+ "Force SDIO Data Transfers to 1-bit Mode");
+
+static int force_polling_for_irqs;
+module_param(force_polling_for_irqs, bool, 0644);
+MODULE_PARM_DESC(force_polling_for_irqs, "Force Polling for SDIO interrupts");
+
+static int firmware_irqpoll_timeout = 1024;
+module_param(firmware_irqpoll_timeout, int, 0644);
+MODULE_PARM_DESC(firmware_irqpoll_timeout, "VUB300 firmware irqpoll timeout");
+
+static int force_max_req_size = 128;
+module_param(force_max_req_size, int, 0644);
+MODULE_PARM_DESC(force_max_req_size, "set max request size in kBytes");
+
+#ifdef SMSC_DEVELOPMENT_BOARD
+static int firmware_rom_wait_states = 0x04;
+#else
+static int firmware_rom_wait_states = 0x1C;
+#endif
+
+module_param(firmware_rom_wait_states, bool, 0644);
+MODULE_PARM_DESC(firmware_rom_wait_states,
+ "ROM wait states byte=RRRIIEEE (Reserved Internal External)");
+
+#define ELAN_VENDOR_ID 0x2201
+#define VUB300_VENDOR_ID 0x0424
+#define VUB300_PRODUCT_ID 0x012C
+static struct usb_device_id vub300_table[] = {
+ {USB_DEVICE(ELAN_VENDOR_ID, VUB300_PRODUCT_ID)},
+ {USB_DEVICE(VUB300_VENDOR_ID, VUB300_PRODUCT_ID)},
+ {} /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, vub300_table);
+
+static struct workqueue_struct *cmndworkqueue;
+static struct workqueue_struct *pollworkqueue;
+static struct workqueue_struct *deadworkqueue;
+
+static inline int interface_to_InterfaceNumber(struct usb_interface *interface)
+{
+ if (!interface)
+ return -1;
+ if (!interface->cur_altsetting)
+ return -1;
+ return interface->cur_altsetting->desc.bInterfaceNumber;
+}
+
+struct sdio_register {
+ unsigned func_num:3;
+ unsigned sdio_reg:17;
+ unsigned activate:1;
+ unsigned prepared:1;
+ unsigned regvalue:8;
+ unsigned response:8;
+ unsigned sparebit:26;
+};
+
+struct vub300_mmc_host {
+ struct usb_device *udev;
+ struct usb_interface *interface;
+ struct kref kref;
+ struct mutex cmd_mutex;
+ struct mutex irq_mutex;
+ char vub_name[3 + (9 * 8) + 4 + 1]; /* max of 7 sdio fn's */
+ u8 cmnd_out_ep; /* EndPoint for commands */
+ u8 cmnd_res_ep; /* EndPoint for responses */
+ u8 data_out_ep; /* EndPoint for out data */
+ u8 data_inp_ep; /* EndPoint for inp data */
+ bool card_powered;
+ bool card_present;
+ bool read_only;
+ bool large_usb_packets;
+ bool app_spec; /* ApplicationSpecific */
+ bool irq_enabled; /* by the MMC CORE */
+ bool irq_disabled; /* in the firmware */
+ unsigned bus_width:4;
+ u8 total_offload_count;
+ u8 dynamic_register_count;
+ u8 resp_len;
+ u32 datasize;
+ int errors;
+ int usb_transport_fail;
+ int usb_timed_out;
+ int irqs_queued;
+ struct sdio_register sdio_register[16];
+ struct offload_interrupt_function_register {
+#define MAXREGBITS 4
+#define MAXREGS (1<<MAXREGBITS)
+#define MAXREGMASK (MAXREGS-1)
+ u8 offload_count;
+ u32 offload_point;
+ struct offload_registers_access reg[MAXREGS];
+ } fn[8];
+ u16 fbs[8]; /* Function Block Size */
+ struct mmc_command *cmd;
+ struct mmc_request *req;
+ struct mmc_data *data;
+ struct mmc_host *mmc;
+ struct urb *urb;
+ struct urb *command_out_urb;
+ struct urb *command_res_urb;
+ struct completion command_complete;
+ struct completion irqpoll_complete;
+ union sd_command cmnd;
+ union sd_response resp;
+ struct timer_list sg_transfer_timer;
+ struct usb_sg_request sg_request;
+ struct timer_list inactivity_timer;
+ struct work_struct deadwork;
+ struct work_struct cmndwork;
+ struct delayed_work pollwork;
+ struct host_controller_info hc_info;
+ struct sd_status_header system_port_status;
+ u8 padded_buffer[64];
+};
+
+#define kref_to_vub300_mmc_host(d) container_of(d, struct vub300_mmc_host, kref)
+#define SET_TRANSFER_PSEUDOCODE 21
+#define SET_INTERRUPT_PSEUDOCODE 20
+#define SET_FAILURE_MODE 18
+#define SET_ROM_WAIT_STATES 16
+#define SET_IRQ_ENABLE 13
+#define SET_CLOCK_SPEED 11
+#define SET_FUNCTION_BLOCK_SIZE 9
+#define SET_SD_DATA_MODE 6
+#define SET_SD_POWER 4
+#define ENTER_DFU_MODE 3
+#define GET_HC_INF0 1
+#define GET_SYSTEM_PORT_STATUS 0
+
+static void vub300_delete(struct kref *kref)
+{ /* kref callback - softirq */
+ struct vub300_mmc_host *vub300 = kref_to_vub300_mmc_host(kref);
+ struct mmc_host *mmc = vub300->mmc;
+ usb_free_urb(vub300->command_out_urb);
+ vub300->command_out_urb = NULL;
+ usb_free_urb(vub300->command_res_urb);
+ vub300->command_res_urb = NULL;
+ usb_put_dev(vub300->udev);
+ mmc_free_host(mmc);
+ /*
+ * and hence also frees vub300
+ * which is contained at the end of struct mmc
+ */
+}
+
+static void vub300_queue_cmnd_work(struct vub300_mmc_host *vub300)
+{
+ kref_get(&vub300->kref);
+ if (queue_work(cmndworkqueue, &vub300->cmndwork)) {
+ /*
+ * then the cmndworkqueue was not previously
+ * running and the above get ref is obvious
+ * required and will be put when the thread
+ * terminates by a specific call
+ */
+ } else {
+ /*
+ * the cmndworkqueue was already running from
+ * a previous invocation and thus to keep the
+ * kref counts correct we must undo the get
+ */
+ kref_put(&vub300->kref, vub300_delete);
+ }
+}
+
+static void vub300_queue_poll_work(struct vub300_mmc_host *vub300, int delay)
+{
+ kref_get(&vub300->kref);
+ if (queue_delayed_work(pollworkqueue, &vub300->pollwork, delay)) {
+ /*
+ * then the pollworkqueue was not previously
+ * running and the above get ref is obvious
+ * required and will be put when the thread
+ * terminates by a specific call
+ */
+ } else {
+ /*
+ * the pollworkqueue was already running from
+ * a previous invocation and thus to keep the
+ * kref counts correct we must undo the get
+ */
+ kref_put(&vub300->kref, vub300_delete);
+ }
+}
+
+static void vub300_queue_dead_work(struct vub300_mmc_host *vub300)
+{
+ kref_get(&vub300->kref);
+ if (queue_work(deadworkqueue, &vub300->deadwork)) {
+ /*
+ * then the deadworkqueue was not previously
+ * running and the above get ref is obvious
+ * required and will be put when the thread
+ * terminates by a specific call
+ */
+ } else {
+ /*
+ * the deadworkqueue was already running from
+ * a previous invocation and thus to keep the
+ * kref counts correct we must undo the get
+ */
+ kref_put(&vub300->kref, vub300_delete);
+ }
+}
+
+static void irqpoll_res_completed(struct urb *urb)
+{ /* urb completion handler - hardirq */
+ struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context;
+ if (urb->status)
+ vub300->usb_transport_fail = urb->status;
+ complete(&vub300->irqpoll_complete);
+}
+
+static void irqpoll_out_completed(struct urb *urb)
+{ /* urb completion handler - hardirq */
+ struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context;
+ if (urb->status) {
+ vub300->usb_transport_fail = urb->status;
+ complete(&vub300->irqpoll_complete);
+ return;
+ } else {
+ int ret;
+ unsigned int pipe =
+ usb_rcvbulkpipe(vub300->udev, vub300->cmnd_res_ep);
+ usb_fill_bulk_urb(vub300->command_res_urb, vub300->udev, pipe,
+ &vub300->resp, sizeof(vub300->resp),
+ irqpoll_res_completed, vub300);
+ vub300->command_res_urb->actual_length = 0;
+ ret = usb_submit_urb(vub300->command_res_urb, GFP_ATOMIC);
+ if (ret) {
+ vub300->usb_transport_fail = ret;
+ complete(&vub300->irqpoll_complete);
+ }
+ return;
+ }
+}
+
+static void send_irqpoll(struct vub300_mmc_host *vub300)
+{
+ /* cmd_mutex is held by vub300_pollwork_thread */
+ int retval;
+ int timeout = 0xFFFF & (0x0001FFFF - firmware_irqpoll_timeout);
+ vub300->cmnd.poll.header_size = 22;
+ vub300->cmnd.poll.header_type = 1;
+ vub300->cmnd.poll.port_number = 0;
+ vub300->cmnd.poll.command_type = 2;
+ vub300->cmnd.poll.poll_timeout_lsb = 0xFF & (unsigned)timeout;
+ vub300->cmnd.poll.poll_timeout_msb = 0xFF & (unsigned)(timeout >> 8);
+ usb_fill_bulk_urb(vub300->command_out_urb, vub300->udev,
+ usb_sndbulkpipe(vub300->udev, vub300->cmnd_out_ep)
+ , &vub300->cmnd, sizeof(vub300->cmnd)
+ , irqpoll_out_completed, vub300);
+ retval = usb_submit_urb(vub300->command_out_urb, GFP_KERNEL);
+ if (0 > retval) {
+ vub300->usb_transport_fail = retval;
+ vub300_queue_poll_work(vub300, 1);
+ complete(&vub300->irqpoll_complete);
+ return;
+ } else {
+ return;
+ }
+}
+
+static void new_system_port_status(struct vub300_mmc_host *vub300)
+{
+ int old_card_present = vub300->card_present;
+ int new_card_present =
+ (0x0001 & vub300->system_port_status.port_flags) ? 1 : 0;
+ vub300->read_only =
+ (0x0010 & vub300->system_port_status.port_flags) ? 1 : 0;
+ if (new_card_present && !old_card_present) {
+ dev_info(&vub300->udev->dev, "card just inserted\n");
+ vub300->card_present = 1;
+ vub300->bus_width = 0;
+ if (disable_offload_processing)
+ strncpy(vub300->vub_name, "EMPTY Processing Disabled",
+ sizeof(vub300->vub_name));
+ else
+ vub300->vub_name[0] = 0;
+ mmc_detect_change(vub300->mmc, 1);
+ } else if (!new_card_present && old_card_present) {
+ dev_info(&vub300->udev->dev, "card just ejected\n");
+ vub300->card_present = 0;
+ mmc_detect_change(vub300->mmc, 0);
+ } else {
+ /* no change */
+ }
+}
+
+static void __add_offloaded_reg_to_fifo(struct vub300_mmc_host *vub300,
+ struct offload_registers_access
+ *register_access, u8 func)
+{
+ u8 r = vub300->fn[func].offload_point + vub300->fn[func].offload_count;
+ memcpy(&vub300->fn[func].reg[MAXREGMASK & r], register_access,
+ sizeof(struct offload_registers_access));
+ vub300->fn[func].offload_count += 1;
+ vub300->total_offload_count += 1;
+}
+
+static void add_offloaded_reg(struct vub300_mmc_host *vub300,
+ struct offload_registers_access *register_access)
+{
+ u32 Register = ((0x03 & register_access->command_byte[0]) << 15)
+ | ((0xFF & register_access->command_byte[1]) << 7)
+ | ((0xFE & register_access->command_byte[2]) >> 1);
+ u8 func = ((0x70 & register_access->command_byte[0]) >> 4);
+ u8 regs = vub300->dynamic_register_count;
+ u8 i = 0;
+ while (0 < regs-- && 1 == vub300->sdio_register[i].activate) {
+ if (vub300->sdio_register[i].func_num == func &&
+ vub300->sdio_register[i].sdio_reg == Register) {
+ if (vub300->sdio_register[i].prepared == 0)
+ vub300->sdio_register[i].prepared = 1;
+ vub300->sdio_register[i].response =
+ register_access->Respond_Byte[2];
+ vub300->sdio_register[i].regvalue =
+ register_access->Respond_Byte[3];
+ return;
+ } else {
+ i += 1;
+ continue;
+ }
+ };
+ __add_offloaded_reg_to_fifo(vub300, register_access, func);
+}
+
+static void check_vub300_port_status(struct vub300_mmc_host *vub300)
+{
+ /*
+ * cmd_mutex is held by vub300_pollwork_thread,
+ * vub300_deadwork_thread or vub300_cmndwork_thread
+ */
+ int retval;
+ retval =
+ usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
+ GET_SYSTEM_PORT_STATUS,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x0000, 0x0000, &vub300->system_port_status,
+ sizeof(vub300->system_port_status), HZ);
+ if (sizeof(vub300->system_port_status) == retval)
+ new_system_port_status(vub300);
+}
+
+static void __vub300_irqpoll_response(struct vub300_mmc_host *vub300)
+{
+ /* cmd_mutex is held by vub300_pollwork_thread */
+ if (vub300->command_res_urb->actual_length == 0)
+ return;
+
+ switch (vub300->resp.common.header_type) {
+ case RESPONSE_INTERRUPT:
+ mutex_lock(&vub300->irq_mutex);
+ if (vub300->irq_enabled)
+ mmc_signal_sdio_irq(vub300->mmc);
+ else
+ vub300->irqs_queued += 1;
+ vub300->irq_disabled = 1;
+ mutex_unlock(&vub300->irq_mutex);
+ break;
+ case RESPONSE_ERROR:
+ if (vub300->resp.error.error_code == SD_ERROR_NO_DEVICE)
+ check_vub300_port_status(vub300);
+ break;
+ case RESPONSE_STATUS:
+ vub300->system_port_status = vub300->resp.status;
+ new_system_port_status(vub300);
+ if (!vub300->card_present)
+ vub300_queue_poll_work(vub300, HZ / 5);
+ break;
+ case RESPONSE_IRQ_DISABLED:
+ {
+ int offloaded_data_length = vub300->resp.common.header_size - 3;
+ int register_count = offloaded_data_length >> 3;
+ int ri = 0;
+ while (register_count--) {
+ add_offloaded_reg(vub300, &vub300->resp.irq.reg[ri]);
+ ri += 1;
+ }
+ mutex_lock(&vub300->irq_mutex);
+ if (vub300->irq_enabled)
+ mmc_signal_sdio_irq(vub300->mmc);
+ else
+ vub300->irqs_queued += 1;
+ vub300->irq_disabled = 1;
+ mutex_unlock(&vub300->irq_mutex);
+ break;
+ }
+ case RESPONSE_IRQ_ENABLED:
+ {
+ int offloaded_data_length = vub300->resp.common.header_size - 3;
+ int register_count = offloaded_data_length >> 3;
+ int ri = 0;
+ while (register_count--) {
+ add_offloaded_reg(vub300, &vub300->resp.irq.reg[ri]);
+ ri += 1;
+ }
+ mutex_lock(&vub300->irq_mutex);
+ if (vub300->irq_enabled)
+ mmc_signal_sdio_irq(vub300->mmc);
+ else if (vub300->irqs_queued)
+ vub300->irqs_queued += 1;
+ else
+ vub300->irqs_queued += 1;
+ vub300->irq_disabled = 0;
+ mutex_unlock(&vub300->irq_mutex);
+ break;
+ }
+ case RESPONSE_NO_INTERRUPT:
+ vub300_queue_poll_work(vub300, 1);
+ break;
+ default:
+ break;
+ }
+}
+
+static void __do_poll(struct vub300_mmc_host *vub300)
+{
+ /* cmd_mutex is held by vub300_pollwork_thread */
+ long commretval;
+ mod_timer(&vub300->inactivity_timer, jiffies + HZ);
+ init_completion(&vub300->irqpoll_complete);
+ send_irqpoll(vub300);
+ commretval = wait_for_completion_timeout(&vub300->irqpoll_complete,
+ msecs_to_jiffies(500));
+ if (vub300->usb_transport_fail) {
+ /* no need to do anything */
+ } else if (commretval == 0) {
+ vub300->usb_timed_out = 1;
+ usb_kill_urb(vub300->command_out_urb);
+ usb_kill_urb(vub300->command_res_urb);
+ } else if (commretval < 0) {
+ vub300_queue_poll_work(vub300, 1);
+ } else { /* commretval > 0 */
+ __vub300_irqpoll_response(vub300);
+ }
+}
+
+/* this thread runs only when the driver
+ * is trying to poll the device for an IRQ
+ */
+static void vub300_pollwork_thread(struct work_struct *work)
+{ /* NOT irq */
+ struct vub300_mmc_host *vub300 = container_of(work,
+ struct vub300_mmc_host, pollwork.work);
+ if (!vub300->interface) {
+ kref_put(&vub300->kref, vub300_delete);
+ return;
+ }
+ mutex_lock(&vub300->cmd_mutex);
+ if (vub300->cmd) {
+ vub300_queue_poll_work(vub300, 1);
+ } else if (!vub300->card_present) {
+ /* no need to do anything */
+ } else { /* vub300->card_present */
+ mutex_lock(&vub300->irq_mutex);
+ if (!vub300->irq_enabled) {
+ mutex_unlock(&vub300->irq_mutex);
+ } else if (vub300->irqs_queued) {
+ vub300->irqs_queued -= 1;
+ mmc_signal_sdio_irq(vub300->mmc);
+ mod_timer(&vub300->inactivity_timer, jiffies + HZ);
+ mutex_unlock(&vub300->irq_mutex);
+ } else { /* NOT vub300->irqs_queued */
+ mutex_unlock(&vub300->irq_mutex);
+ __do_poll(vub300);
+ }
+ }
+ mutex_unlock(&vub300->cmd_mutex);
+ kref_put(&vub300->kref, vub300_delete);
+}
+
+static void vub300_deadwork_thread(struct work_struct *work)
+{ /* NOT irq */
+ struct vub300_mmc_host *vub300 =
+ container_of(work, struct vub300_mmc_host, deadwork);
+ if (!vub300->interface) {
+ kref_put(&vub300->kref, vub300_delete);
+ return;
+ }
+ mutex_lock(&vub300->cmd_mutex);
+ if (vub300->cmd) {
+ /*
+ * a command got in as the inactivity
+ * timer expired - so we just let the
+ * processing of the command show if
+ * the device is dead
+ */
+ } else if (vub300->card_present) {
+ check_vub300_port_status(vub300);
+ } else if (vub300->mmc && vub300->mmc->card &&
+ mmc_card_present(vub300->mmc->card)) {
+ /*
+ * the MMC core must not have responded
+ * to the previous indication - lets
+ * hope that it eventually does so we
+ * will just ignore this for now
+ */
+ } else {
+ check_vub300_port_status(vub300);
+ }
+ mod_timer(&vub300->inactivity_timer, jiffies + HZ);
+ mutex_unlock(&vub300->cmd_mutex);
+ kref_put(&vub300->kref, vub300_delete);
+}
+
+static void vub300_inactivity_timer_expired(unsigned long data)
+{ /* softirq */
+ struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)data;
+ if (!vub300->interface) {
+ kref_put(&vub300->kref, vub300_delete);
+ } else if (vub300->cmd) {
+ mod_timer(&vub300->inactivity_timer, jiffies + HZ);
+ } else {
+ vub300_queue_dead_work(vub300);
+ mod_timer(&vub300->inactivity_timer, jiffies + HZ);
+ }
+}
+
+static int vub300_response_error(u8 error_code)
+{
+ switch (error_code) {
+ case SD_ERROR_PIO_TIMEOUT:
+ case SD_ERROR_1BIT_TIMEOUT:
+ case SD_ERROR_4BIT_TIMEOUT:
+ return -ETIMEDOUT;
+ case SD_ERROR_STAT_DATA:
+ case SD_ERROR_OVERRUN:
+ case SD_ERROR_STAT_CMD:
+ case SD_ERROR_STAT_CMD_TIMEOUT:
+ case SD_ERROR_SDCRDY_STUCK:
+ case SD_ERROR_UNHANDLED:
+ case SD_ERROR_1BIT_CRC_WRONG:
+ case SD_ERROR_4BIT_CRC_WRONG:
+ case SD_ERROR_1BIT_CRC_ERROR:
+ case SD_ERROR_4BIT_CRC_ERROR:
+ case SD_ERROR_NO_CMD_ENDBIT:
+ case SD_ERROR_NO_1BIT_DATEND:
+ case SD_ERROR_NO_4BIT_DATEND:
+ case SD_ERROR_1BIT_DATA_TIMEOUT:
+ case SD_ERROR_4BIT_DATA_TIMEOUT:
+ case SD_ERROR_1BIT_UNEXPECTED_TIMEOUT:
+ case SD_ERROR_4BIT_UNEXPECTED_TIMEOUT:
+ return -EILSEQ;
+ case 33:
+ return -EILSEQ;
+ case SD_ERROR_ILLEGAL_COMMAND:
+ return -EINVAL;
+ case SD_ERROR_NO_DEVICE:
+ return -ENOMEDIUM;
+ default:
+ return -ENODEV;
+ }
+}
+
+static void command_res_completed(struct urb *urb)
+{ /* urb completion handler - hardirq */
+ struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context;
+ if (urb->status) {
+ /* we have to let the initiator handle the error */
+ } else if (vub300->command_res_urb->actual_length == 0) {
+ /*
+ * we have seen this happen once or twice and
+ * we suspect a buggy USB host controller
+ */
+ } else if (!vub300->data) {
+ /* this means that the command (typically CMD52) suceeded */
+ } else if (vub300->resp.common.header_type != 0x02) {
+ /*
+ * this is an error response from the VUB300 chip
+ * and we let the initiator handle it
+ */
+ } else if (vub300->urb) {
+ vub300->cmd->error =
+ vub300_response_error(vub300->resp.error.error_code);
+ usb_unlink_urb(vub300->urb);
+ } else {
+ vub300->cmd->error =
+ vub300_response_error(vub300->resp.error.error_code);
+ usb_sg_cancel(&vub300->sg_request);
+ }
+ complete(&vub300->command_complete); /* got_response_in */
+}
+
+static void command_out_completed(struct urb *urb)
+{ /* urb completion handler - hardirq */
+ struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)urb->context;
+ if (urb->status) {
+ complete(&vub300->command_complete);
+ } else {
+ int ret;
+ unsigned int pipe =
+ usb_rcvbulkpipe(vub300->udev, vub300->cmnd_res_ep);
+ usb_fill_bulk_urb(vub300->command_res_urb, vub300->udev, pipe,
+ &vub300->resp, sizeof(vub300->resp),
+ command_res_completed, vub300);
+ vub300->command_res_urb->actual_length = 0;
+ ret = usb_submit_urb(vub300->command_res_urb, GFP_ATOMIC);
+ if (ret == 0) {
+ /*
+ * the urb completion handler will call
+ * our completion handler
+ */
+ } else {
+ /*
+ * and thus we only call it directly
+ * when it will not be called
+ */
+ complete(&vub300->command_complete);
+ }
+ }
+}
+
+/*
+ * the STUFF bits are masked out for the comparisons
+ */
+static void snoop_block_size_and_bus_width(struct vub300_mmc_host *vub300,
+ u32 cmd_arg)
+{
+ if ((0xFBFFFE00 & cmd_arg) == 0x80022200)
+ vub300->fbs[1] = (cmd_arg << 8) | (0x00FF & vub300->fbs[1]);
+ else if ((0xFBFFFE00 & cmd_arg) == 0x80022000)
+ vub300->fbs[1] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[1]);
+ else if ((0xFBFFFE00 & cmd_arg) == 0x80042200)
+ vub300->fbs[2] = (cmd_arg << 8) | (0x00FF & vub300->fbs[2]);
+ else if ((0xFBFFFE00 & cmd_arg) == 0x80042000)
+ vub300->fbs[2] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[2]);
+ else if ((0xFBFFFE00 & cmd_arg) == 0x80062200)
+ vub300->fbs[3] = (cmd_arg << 8) | (0x00FF & vub300->fbs[3]);
+ else if ((0xFBFFFE00 & cmd_arg) == 0x80062000)
+ vub300->fbs[3] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[3]);
+ else if ((0xFBFFFE00 & cmd_arg) == 0x80082200)
+ vub300->fbs[4] = (cmd_arg << 8) | (0x00FF & vub300->fbs[4]);
+ else if ((0xFBFFFE00 & cmd_arg) == 0x80082000)
+ vub300->fbs[4] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[4]);
+ else if ((0xFBFFFE00 & cmd_arg) == 0x800A2200)
+ vub300->fbs[5] = (cmd_arg << 8) | (0x00FF & vub300->fbs[5]);
+ else if ((0xFBFFFE00 & cmd_arg) == 0x800A2000)
+ vub300->fbs[5] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[5]);
+ else if ((0xFBFFFE00 & cmd_arg) == 0x800C2200)
+ vub300->fbs[6] = (cmd_arg << 8) | (0x00FF & vub300->fbs[6]);
+ else if ((0xFBFFFE00 & cmd_arg) == 0x800C2000)
+ vub300->fbs[6] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[6]);
+ else if ((0xFBFFFE00 & cmd_arg) == 0x800E2200)
+ vub300->fbs[7] = (cmd_arg << 8) | (0x00FF & vub300->fbs[7]);
+ else if ((0xFBFFFE00 & cmd_arg) == 0x800E2000)
+ vub300->fbs[7] = (0xFF & cmd_arg) | (0xFF00 & vub300->fbs[7]);
+ else if ((0xFBFFFE03 & cmd_arg) == 0x80000E00)
+ vub300->bus_width = 1;
+ else if ((0xFBFFFE03 & cmd_arg) == 0x80000E02)
+ vub300->bus_width = 4;
+}
+
+static void send_command(struct vub300_mmc_host *vub300)
+{
+ /* cmd_mutex is held by vub300_cmndwork_thread */
+ struct mmc_command *cmd = vub300->cmd;
+ struct mmc_data *data = vub300->data;
+ int retval;
+ int i;
+ u8 response_type;
+ if (vub300->app_spec) {
+ switch (cmd->opcode) {
+ case 6:
+ response_type = SDRT_1;
+ vub300->resp_len = 6;
+ if (0x00000000 == (0x00000003 & cmd->arg))
+ vub300->bus_width = 1;
+ else if (0x00000002 == (0x00000003 & cmd->arg))
+ vub300->bus_width = 4;
+ else
+ dev_err(&vub300->udev->dev,
+ "unexpected ACMD6 bus_width=%d\n",
+ 0x00000003 & cmd->arg);
+ break;
+ case 13:
+ response_type = SDRT_1;
+ vub300->resp_len = 6;
+ break;
+ case 22:
+ response_type = SDRT_1;
+ vub300->resp_len = 6;
+ break;
+ case 23:
+ response_type = SDRT_1;
+ vub300->resp_len = 6;
+ break;
+ case 41:
+ response_type = SDRT_3;
+ vub300->resp_len = 6;
+ break;
+ case 42:
+ response_type = SDRT_1;
+ vub300->resp_len = 6;
+ break;
+ case 51:
+ response_type = SDRT_1;
+ vub300->resp_len = 6;
+ break;
+ case 55:
+ response_type = SDRT_1;
+ vub300->resp_len = 6;
+ break;
+ default:
+ vub300->resp_len = 0;
+ cmd->error = -EINVAL;
+ complete(&vub300->command_complete);
+ return;
+ }
+ vub300->app_spec = 0;
+ } else {
+ switch (cmd->opcode) {
+ case 0:
+ response_type = SDRT_NONE;
+ vub300->resp_len = 0;
+ break;
+ case 1:
+ response_type = SDRT_3;
+ vub300->resp_len = 6;
+ break;
+ case 2:
+ response_type = SDRT_2;
+ vub300->resp_len = 17;
+ break;
+ case 3:
+ response_type = SDRT_6;
+ vub300->resp_len = 6;
+ break;
+ case 4:
+ response_type = SDRT_NONE;
+ vub300->resp_len = 0;
+ break;
+ case 5:
+ response_type = SDRT_4;
+ vub300->resp_len = 6;
+ break;
+ case 6:
+ response_type = SDRT_1;
+ vub300->resp_len = 6;
+ break;
+ case 7:
+ response_type = SDRT_1B;
+ vub300->resp_len = 6;
+ break;
+ case 8:
+ response_type = SDRT_7;
+ vub300->resp_len = 6;
+ break;
+ case 9:
+ response_type = SDRT_2;
+ vub300->resp_len = 17;
+ break;
+ case 10:
+ response_type = SDRT_2;
+ vub300->resp_len = 17;
+ break;
+ case 12:
+ response_type = SDRT_1B;
+ vub300->resp_len = 6;
+ break;
+ case 13:
+ response_type = SDRT_1;
+ vub300->resp_len = 6;
+ break;
+ case 15:
+ response_type = SDRT_NONE;
+ vub300->resp_len = 0;
+ break;
+ case 16:
+ for (i = 0; i < ARRAY_SIZE(vub300->fbs); i++)
+ vub300->fbs[i] = 0xFFFF & cmd->arg;
+ response_type = SDRT_1;
+ vub300->resp_len = 6;
+ break;
+ case 17:
+ case 18:
+ case 24:
+ case 25:
+ case 27:
+ response_type = SDRT_1;
+ vub300->resp_len = 6;
+ break;
+ case 28:
+ case 29:
+ response_type = SDRT_1B;
+ vub300->resp_len = 6;
+ break;
+ case 30:
+ case 32:
+ case 33:
+ response_type = SDRT_1;
+ vub300->resp_len = 6;
+ break;
+ case 38:
+ response_type = SDRT_1B;
+ vub300->resp_len = 6;
+ break;
+ case 42:
+ response_type = SDRT_1;
+ vub300->resp_len = 6;
+ break;
+ case 52:
+ response_type = SDRT_5;
+ vub300->resp_len = 6;
+ snoop_block_size_and_bus_width(vub300, cmd->arg);
+ break;
+ case 53:
+ response_type = SDRT_5;
+ vub300->resp_len = 6;
+ break;
+ case 55:
+ response_type = SDRT_1;
+ vub300->resp_len = 6;
+ vub300->app_spec = 1;
+ break;
+ case 56:
+ response_type = SDRT_1;
+ vub300->resp_len = 6;
+ break;
+ default:
+ vub300->resp_len = 0;
+ cmd->error = -EINVAL;
+ complete(&vub300->command_complete);
+ return;
+ }
+ }
+ /*
+ * it is a shame that we can not use "sizeof(struct sd_command_header)"
+ * this is because the packet _must_ be padded to 64 bytes
+ */
+ vub300->cmnd.head.header_size = 20;
+ vub300->cmnd.head.header_type = 0x00;
+ vub300->cmnd.head.port_number = 0; /* "0" means port 1 */
+ vub300->cmnd.head.command_type = 0x00; /* standard read command */
+ vub300->cmnd.head.response_type = response_type;
+ vub300->cmnd.head.command_index = cmd->opcode;
+ vub300->cmnd.head.arguments[0] = cmd->arg >> 24;
+ vub300->cmnd.head.arguments[1] = cmd->arg >> 16;
+ vub300->cmnd.head.arguments[2] = cmd->arg >> 8;
+ vub300->cmnd.head.arguments[3] = cmd->arg >> 0;
+ if (cmd->opcode == 52) {
+ int fn = 0x7 & (cmd->arg >> 28);
+ vub300->cmnd.head.block_count[0] = 0;
+ vub300->cmnd.head.block_count[1] = 0;
+ vub300->cmnd.head.block_size[0] = (vub300->fbs[fn] >> 8) & 0xFF;
+ vub300->cmnd.head.block_size[1] = (vub300->fbs[fn] >> 0) & 0xFF;
+ vub300->cmnd.head.command_type = 0x00;
+ vub300->cmnd.head.transfer_size[0] = 0;
+ vub300->cmnd.head.transfer_size[1] = 0;
+ vub300->cmnd.head.transfer_size[2] = 0;
+ vub300->cmnd.head.transfer_size[3] = 0;
+ } else if (!data) {
+ vub300->cmnd.head.block_count[0] = 0;
+ vub300->cmnd.head.block_count[1] = 0;
+ vub300->cmnd.head.block_size[0] = (vub300->fbs[0] >> 8) & 0xFF;
+ vub300->cmnd.head.block_size[1] = (vub300->fbs[0] >> 0) & 0xFF;
+ vub300->cmnd.head.command_type = 0x00;
+ vub300->cmnd.head.transfer_size[0] = 0;
+ vub300->cmnd.head.transfer_size[1] = 0;
+ vub300->cmnd.head.transfer_size[2] = 0;
+ vub300->cmnd.head.transfer_size[3] = 0;
+ } else if (cmd->opcode == 53) {
+ int fn = 0x7 & (cmd->arg >> 28);
+ if (0x08 & vub300->cmnd.head.arguments[0]) { /* BLOCK MODE */
+ vub300->cmnd.head.block_count[0] =
+ (data->blocks >> 8) & 0xFF;
+ vub300->cmnd.head.block_count[1] =
+ (data->blocks >> 0) & 0xFF;
+ vub300->cmnd.head.block_size[0] =
+ (data->blksz >> 8) & 0xFF;
+ vub300->cmnd.head.block_size[1] =
+ (data->blksz >> 0) & 0xFF;
+ } else { /* BYTE MODE */
+ vub300->cmnd.head.block_count[0] = 0;
+ vub300->cmnd.head.block_count[1] = 0;
+ vub300->cmnd.head.block_size[0] =
+ (vub300->datasize >> 8) & 0xFF;
+ vub300->cmnd.head.block_size[1] =
+ (vub300->datasize >> 0) & 0xFF;
+ }
+ vub300->cmnd.head.command_type =
+ (MMC_DATA_READ & data->flags) ? 0x00 : 0x80;
+ vub300->cmnd.head.transfer_size[0] =
+ (vub300->datasize >> 24) & 0xFF;
+ vub300->cmnd.head.transfer_size[1] =
+ (vub300->datasize >> 16) & 0xFF;
+ vub300->cmnd.head.transfer_size[2] =
+ (vub300->datasize >> 8) & 0xFF;
+ vub300->cmnd.head.transfer_size[3] =
+ (vub300->datasize >> 0) & 0xFF;
+ if (vub300->datasize < vub300->fbs[fn]) {
+ vub300->cmnd.head.block_count[0] = 0;
+ vub300->cmnd.head.block_count[1] = 0;
+ }
+ } else {
+ vub300->cmnd.head.block_count[0] = (data->blocks >> 8) & 0xFF;
+ vub300->cmnd.head.block_count[1] = (data->blocks >> 0) & 0xFF;
+ vub300->cmnd.head.block_size[0] = (data->blksz >> 8) & 0xFF;
+ vub300->cmnd.head.block_size[1] = (data->blksz >> 0) & 0xFF;
+ vub300->cmnd.head.command_type =
+ (MMC_DATA_READ & data->flags) ? 0x00 : 0x80;
+ vub300->cmnd.head.transfer_size[0] =
+ (vub300->datasize >> 24) & 0xFF;
+ vub300->cmnd.head.transfer_size[1] =
+ (vub300->datasize >> 16) & 0xFF;
+ vub300->cmnd.head.transfer_size[2] =
+ (vub300->datasize >> 8) & 0xFF;
+ vub300->cmnd.head.transfer_size[3] =
+ (vub300->datasize >> 0) & 0xFF;
+ if (vub300->datasize < vub300->fbs[0]) {
+ vub300->cmnd.head.block_count[0] = 0;
+ vub300->cmnd.head.block_count[1] = 0;
+ }
+ }
+ if (vub300->cmnd.head.block_size[0] || vub300->cmnd.head.block_size[1]) {
+ u16 block_size = vub300->cmnd.head.block_size[1] |
+ (vub300->cmnd.head.block_size[0] << 8);
+ u16 block_boundary = FIRMWARE_BLOCK_BOUNDARY -
+ (FIRMWARE_BLOCK_BOUNDARY % block_size);
+ vub300->cmnd.head.block_boundary[0] =
+ (block_boundary >> 8) & 0xFF;
+ vub300->cmnd.head.block_boundary[1] =
+ (block_boundary >> 0) & 0xFF;
+ } else {
+ vub300->cmnd.head.block_boundary[0] = 0;
+ vub300->cmnd.head.block_boundary[1] = 0;
+ }
+ usb_fill_bulk_urb(vub300->command_out_urb, vub300->udev,
+ usb_sndbulkpipe(vub300->udev, vub300->cmnd_out_ep),
+ &vub300->cmnd, sizeof(vub300->cmnd),
+ command_out_completed, vub300);
+ retval = usb_submit_urb(vub300->command_out_urb, GFP_KERNEL);
+ if (retval < 0) {
+ cmd->error = retval;
+ complete(&vub300->command_complete);
+ return;
+ } else {
+ return;
+ }
+}
+
+/*
+ * timer callback runs in atomic mode
+ * so it cannot call usb_kill_urb()
+ */
+static void vub300_sg_timed_out(unsigned long data)
+{
+ struct vub300_mmc_host *vub300 = (struct vub300_mmc_host *)data;
+ vub300->usb_timed_out = 1;
+ usb_sg_cancel(&vub300->sg_request);
+ usb_unlink_urb(vub300->command_out_urb);
+ usb_unlink_urb(vub300->command_res_urb);
+}
+
+static u16 roundup_to_multiple_of_64(u16 number)
+{
+ return 0xFFC0 & (0x3F + number);
+}
+
+/*
+ * this is a separate function to solve the 80 column width restriction
+ */
+static void __download_offload_pseudocode(struct vub300_mmc_host *vub300,
+ const struct firmware *fw)
+{
+ u8 register_count = 0;
+ u16 ts = 0;
+ u16 interrupt_size = 0;
+ const u8 *data = fw->data;
+ int size = fw->size;
+ u8 c;
+ dev_info(&vub300->udev->dev, "using %s for SDIO offload processing\n",
+ vub300->vub_name);
+ do {
+ c = *data++;
+ } while (size-- && c); /* skip comment */
+ dev_info(&vub300->udev->dev, "using offload firmware %s %s\n", fw->data,
+ vub300->vub_name);
+ if (size < 4) {
+ dev_err(&vub300->udev->dev,
+ "corrupt offload pseudocode in firmware %s\n",
+ vub300->vub_name);
+ strncpy(vub300->vub_name, "corrupt offload pseudocode",
+ sizeof(vub300->vub_name));
+ return;
+ }
+ interrupt_size += *data++;
+ size -= 1;
+ interrupt_size <<= 8;
+ interrupt_size += *data++;
+ size -= 1;
+ if (interrupt_size < size) {
+ u16 xfer_length = roundup_to_multiple_of_64(interrupt_size);
+ u8 *xfer_buffer = kmalloc(xfer_length, GFP_KERNEL);
+ if (xfer_buffer) {
+ int retval;
+ memcpy(xfer_buffer, data, interrupt_size);
+ memset(xfer_buffer + interrupt_size, 0,
+ xfer_length - interrupt_size);
+ size -= interrupt_size;
+ data += interrupt_size;
+ retval =
+ usb_control_msg(vub300->udev,
+ usb_sndctrlpipe(vub300->udev, 0),
+ SET_INTERRUPT_PSEUDOCODE,
+ USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_DEVICE, 0x0000, 0x0000,
+ xfer_buffer, xfer_length, HZ);
+ kfree(xfer_buffer);
+ if (retval < 0) {
+ strncpy(vub300->vub_name,
+ "SDIO pseudocode download failed",
+ sizeof(vub300->vub_name));
+ return;
+ }
+ } else {
+ dev_err(&vub300->udev->dev,
+ "not enough memory for xfer buffer to send"
+ " INTERRUPT_PSEUDOCODE for %s %s\n", fw->data,
+ vub300->vub_name);
+ strncpy(vub300->vub_name,
+ "SDIO interrupt pseudocode download failed",
+ sizeof(vub300->vub_name));
+ return;
+ }
+ } else {
+ dev_err(&vub300->udev->dev,
+ "corrupt interrupt pseudocode in firmware %s %s\n",
+ fw->data, vub300->vub_name);
+ strncpy(vub300->vub_name, "corrupt interrupt pseudocode",
+ sizeof(vub300->vub_name));
+ return;
+ }
+ ts += *data++;
+ size -= 1;
+ ts <<= 8;
+ ts += *data++;
+ size -= 1;
+ if (ts < size) {
+ u16 xfer_length = roundup_to_multiple_of_64(ts);
+ u8 *xfer_buffer = kmalloc(xfer_length, GFP_KERNEL);
+ if (xfer_buffer) {
+ int retval;
+ memcpy(xfer_buffer, data, ts);
+ memset(xfer_buffer + ts, 0,
+ xfer_length - ts);
+ size -= ts;
+ data += ts;
+ retval =
+ usb_control_msg(vub300->udev,
+ usb_sndctrlpipe(vub300->udev, 0),
+ SET_TRANSFER_PSEUDOCODE,
+ USB_DIR_OUT | USB_TYPE_VENDOR |
+ USB_RECIP_DEVICE, 0x0000, 0x0000,
+ xfer_buffer, xfer_length, HZ);
+ kfree(xfer_buffer);
+ if (retval < 0) {
+ strncpy(vub300->vub_name,
+ "SDIO pseudocode download failed",
+ sizeof(vub300->vub_name));
+ return;
+ }
+ } else {
+ dev_err(&vub300->udev->dev,
+ "not enough memory for xfer buffer to send"
+ " TRANSFER_PSEUDOCODE for %s %s\n", fw->data,
+ vub300->vub_name);
+ strncpy(vub300->vub_name,
+ "SDIO transfer pseudocode download failed",
+ sizeof(vub300->vub_name));
+ return;
+ }
+ } else {
+ dev_err(&vub300->udev->dev,
+ "corrupt transfer pseudocode in firmware %s %s\n",
+ fw->data, vub300->vub_name);
+ strncpy(vub300->vub_name, "corrupt transfer pseudocode",
+ sizeof(vub300->vub_name));
+ return;
+ }
+ register_count += *data++;
+ size -= 1;
+ if (register_count * 4 == size) {
+ int I = vub300->dynamic_register_count = register_count;
+ int i = 0;
+ while (I--) {
+ unsigned int func_num = 0;
+ vub300->sdio_register[i].func_num = *data++;
+ size -= 1;
+ func_num += *data++;
+ size -= 1;
+ func_num <<= 8;
+ func_num += *data++;
+ size -= 1;
+ func_num <<= 8;
+ func_num += *data++;
+ size -= 1;
+ vub300->sdio_register[i].sdio_reg = func_num;
+ vub300->sdio_register[i].activate = 1;
+ vub300->sdio_register[i].prepared = 0;
+ i += 1;
+ }
+ dev_info(&vub300->udev->dev,
+ "initialized %d dynamic pseudocode registers\n",
+ vub300->dynamic_register_count);
+ return;
+ } else {
+ dev_err(&vub300->udev->dev,
+ "corrupt dynamic registers in firmware %s\n",
+ vub300->vub_name);
+ strncpy(vub300->vub_name, "corrupt dynamic registers",
+ sizeof(vub300->vub_name));
+ return;
+ }
+}
+
+/*
+ * if the binary containing the EMPTY PseudoCode can not be found
+ * vub300->vub_name is set anyway in order to prevent an automatic retry
+ */
+static void download_offload_pseudocode(struct vub300_mmc_host *vub300)
+{
+ struct mmc_card *card = vub300->mmc->card;
+ int sdio_funcs = card->sdio_funcs;
+ const struct firmware *fw = NULL;
+ int l = snprintf(vub300->vub_name, sizeof(vub300->vub_name),
+ "vub_%04X%04X", card->cis.vendor, card->cis.device);
+ int n = 0;
+ int retval;
+ for (n = 0; n < sdio_funcs; n++) {
+ struct sdio_func *sf = card->sdio_func[n];
+ l += snprintf(vub300->vub_name + l,
+ sizeof(vub300->vub_name) - l, "_%04X%04X",
+ sf->vendor, sf->device);
+ };
+ snprintf(vub300->vub_name + l, sizeof(vub300->vub_name) - l, ".bin");
+ dev_info(&vub300->udev->dev, "requesting offload firmware %s\n",
+ vub300->vub_name);
+ retval = request_firmware(&fw, vub300->vub_name, &card->dev);
+ if (retval < 0) {
+ strncpy(vub300->vub_name, "vub_default.bin",
+ sizeof(vub300->vub_name));
+ retval = request_firmware(&fw, vub300->vub_name, &card->dev);
+ if (retval < 0) {
+ strncpy(vub300->vub_name,
+ "no SDIO offload firmware found",
+ sizeof(vub300->vub_name));
+ } else {
+ __download_offload_pseudocode(vub300, fw);
+ release_firmware(fw);
+ }
+ } else {
+ __download_offload_pseudocode(vub300, fw);
+ release_firmware(fw);
+ }
+}
+
+static void vub300_usb_bulk_msg_completion(struct urb *urb)
+{ /* urb completion handler - hardirq */
+ complete((struct completion *)urb->context);
+}
+
+static int vub300_usb_bulk_msg(struct vub300_mmc_host *vub300,
+ unsigned int pipe, void *data, int len,
+ int *actual_length, int timeout_msecs)
+{
+ /* cmd_mutex is held by vub300_cmndwork_thread */
+ struct usb_device *usb_dev = vub300->udev;
+ struct completion done;
+ int retval;
+ vub300->urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!vub300->urb)
+ return -ENOMEM;
+ usb_fill_bulk_urb(vub300->urb, usb_dev, pipe, data, len,
+ vub300_usb_bulk_msg_completion, NULL);
+ init_completion(&done);
+ vub300->urb->context = &done;
+ vub300->urb->actual_length = 0;
+ retval = usb_submit_urb(vub300->urb, GFP_KERNEL);
+ if (unlikely(retval))
+ goto out;
+ if (!wait_for_completion_timeout
+ (&done, msecs_to_jiffies(timeout_msecs))) {
+ retval = -ETIMEDOUT;
+ usb_kill_urb(vub300->urb);
+ } else {
+ retval = vub300->urb->status;
+ }
+out:
+ *actual_length = vub300->urb->actual_length;
+ usb_free_urb(vub300->urb);
+ vub300->urb = NULL;
+ return retval;
+}
+
+static int __command_read_data(struct vub300_mmc_host *vub300,
+ struct mmc_command *cmd, struct mmc_data *data)
+{
+ /* cmd_mutex is held by vub300_cmndwork_thread */
+ int linear_length = vub300->datasize;
+ int padded_length = vub300->large_usb_packets ?
+ ((511 + linear_length) >> 9) << 9 :
+ ((63 + linear_length) >> 6) << 6;
+ if ((padded_length == linear_length) || !pad_input_to_usb_pkt) {
+ int result;
+ unsigned pipe;
+ pipe = usb_rcvbulkpipe(vub300->udev, vub300->data_inp_ep);
+ result = usb_sg_init(&vub300->sg_request, vub300->udev,
+ pipe, 0, data->sg,
+ data->sg_len, 0, GFP_KERNEL);
+ if (result < 0) {
+ usb_unlink_urb(vub300->command_out_urb);
+ usb_unlink_urb(vub300->command_res_urb);
+ cmd->error = result;
+ data->bytes_xfered = 0;
+ return 0;
+ } else {
+ vub300->sg_transfer_timer.expires =
+ jiffies + msecs_to_jiffies(2000 +
+ (linear_length / 16384));
+ add_timer(&vub300->sg_transfer_timer);
+ usb_sg_wait(&vub300->sg_request);
+ del_timer(&vub300->sg_transfer_timer);
+ if (vub300->sg_request.status < 0) {
+ cmd->error = vub300->sg_request.status;
+ data->bytes_xfered = 0;
+ return 0;
+ } else {
+ data->bytes_xfered = vub300->datasize;
+ return linear_length;
+ }
+ }
+ } else {
+ u8 *buf = kmalloc(padded_length, GFP_KERNEL);
+ if (buf) {
+ int result;
+ unsigned pipe = usb_rcvbulkpipe(vub300->udev,
+ vub300->data_inp_ep);
+ int actual_length = 0;
+ result = vub300_usb_bulk_msg(vub300, pipe, buf,
+ padded_length, &actual_length,
+ 2000 + (padded_length / 16384));
+ if (result < 0) {
+ cmd->error = result;
+ data->bytes_xfered = 0;
+ kfree(buf);
+ return 0;
+ } else if (actual_length < linear_length) {
+ cmd->error = -EREMOTEIO;
+ data->bytes_xfered = 0;
+ kfree(buf);
+ return 0;
+ } else {
+ sg_copy_from_buffer(data->sg, data->sg_len, buf,
+ linear_length);
+ kfree(buf);
+ data->bytes_xfered = vub300->datasize;
+ return linear_length;
+ }
+ } else {
+ cmd->error = -ENOMEM;
+ data->bytes_xfered = 0;
+ return 0;
+ }
+ }
+}
+
+static int __command_write_data(struct vub300_mmc_host *vub300,
+ struct mmc_command *cmd, struct mmc_data *data)
+{
+ /* cmd_mutex is held by vub300_cmndwork_thread */
+ unsigned pipe = usb_sndbulkpipe(vub300->udev, vub300->data_out_ep);
+ int linear_length = vub300->datasize;
+ int modulo_64_length = linear_length & 0x003F;
+ int modulo_512_length = linear_length & 0x01FF;
+ if (linear_length < 64) {
+ int result;
+ int actual_length;
+ sg_copy_to_buffer(data->sg, data->sg_len,
+ vub300->padded_buffer,
+ sizeof(vub300->padded_buffer));
+ memset(vub300->padded_buffer + linear_length, 0,
+ sizeof(vub300->padded_buffer) - linear_length);
+ result = vub300_usb_bulk_msg(vub300, pipe, vub300->padded_buffer,
+ sizeof(vub300->padded_buffer),
+ &actual_length, 2000 +
+ (sizeof(vub300->padded_buffer) /
+ 16384));
+ if (result < 0) {
+ cmd->error = result;
+ data->bytes_xfered = 0;
+ } else {
+ data->bytes_xfered = vub300->datasize;
+ }
+ } else if ((!vub300->large_usb_packets && (0 < modulo_64_length)) ||
+ (vub300->large_usb_packets && (64 > modulo_512_length))
+ ) { /* don't you just love these work-rounds */
+ int padded_length = ((63 + linear_length) >> 6) << 6;
+ u8 *buf = kmalloc(padded_length, GFP_KERNEL);
+ if (buf) {
+ int result;
+ int actual_length;
+ sg_copy_to_buffer(data->sg, data->sg_len, buf,
+ padded_length);
+ memset(buf + linear_length, 0,
+ padded_length - linear_length);
+ result =
+ vub300_usb_bulk_msg(vub300, pipe, buf,
+ padded_length, &actual_length,
+ 2000 + padded_length / 16384);
+ kfree(buf);
+ if (result < 0) {
+ cmd->error = result;
+ data->bytes_xfered = 0;
+ } else {
+ data->bytes_xfered = vub300->datasize;
+ }
+ } else {
+ cmd->error = -ENOMEM;
+ data->bytes_xfered = 0;
+ }
+ } else { /* no data padding required */
+ int result;
+ unsigned char buf[64 * 4];
+ sg_copy_to_buffer(data->sg, data->sg_len, buf, sizeof(buf));
+ result = usb_sg_init(&vub300->sg_request, vub300->udev,
+ pipe, 0, data->sg,
+ data->sg_len, 0, GFP_KERNEL);
+ if (result < 0) {
+ usb_unlink_urb(vub300->command_out_urb);
+ usb_unlink_urb(vub300->command_res_urb);
+ cmd->error = result;
+ data->bytes_xfered = 0;
+ } else {
+ vub300->sg_transfer_timer.expires =
+ jiffies + msecs_to_jiffies(2000 +
+ linear_length / 16384);
+ add_timer(&vub300->sg_transfer_timer);
+ usb_sg_wait(&vub300->sg_request);
+ if (cmd->error) {
+ data->bytes_xfered = 0;
+ } else {
+ del_timer(&vub300->sg_transfer_timer);
+ if (vub300->sg_request.status < 0) {
+ cmd->error = vub300->sg_request.status;
+ data->bytes_xfered = 0;
+ } else {
+ data->bytes_xfered = vub300->datasize;
+ }
+ }
+ }
+ }
+ return linear_length;
+}
+
+static void __vub300_command_response(struct vub300_mmc_host *vub300,
+ struct mmc_command *cmd,
+ struct mmc_data *data, int data_length)
+{
+ /* cmd_mutex is held by vub300_cmndwork_thread */
+ long respretval;
+ int msec_timeout = 1000 + data_length / 4;
+ respretval =
+ wait_for_completion_timeout(&vub300->command_complete,
+ msecs_to_jiffies(msec_timeout));
+ if (respretval == 0) { /* TIMED OUT */
+ /* we don't know which of "out" and "res" if any failed */
+ int result;
+ vub300->usb_timed_out = 1;
+ usb_kill_urb(vub300->command_out_urb);
+ usb_kill_urb(vub300->command_res_urb);
+ cmd->error = -ETIMEDOUT;
+ result = usb_lock_device_for_reset(vub300->udev,
+ vub300->interface);
+ if (result == 0) {
+ result = usb_reset_device(vub300->udev);
+ usb_unlock_device(vub300->udev);
+ }
+ } else if (respretval < 0) {
+ /* we don't know which of "out" and "res" if any failed */
+ usb_kill_urb(vub300->command_out_urb);
+ usb_kill_urb(vub300->command_res_urb);
+ cmd->error = respretval;
+ } else if (cmd->error) {
+ /*
+ * the error occured sending the command
+ * or recieving the response
+ */
+ } else if (vub300->command_out_urb->status) {
+ vub300->usb_transport_fail = vub300->command_out_urb->status;
+ cmd->error = -EPROTO == vub300->command_out_urb->status ?
+ -ESHUTDOWN : vub300->command_out_urb->status;
+ } else if (vub300->command_res_urb->status) {
+ vub300->usb_transport_fail = vub300->command_res_urb->status;
+ cmd->error = -EPROTO == vub300->command_res_urb->status ?
+ -ESHUTDOWN : vub300->command_res_urb->status;
+ } else if (vub300->resp.common.header_type == 0x00) {
+ /*
+ * the command completed successfully
+ * and there was no piggybacked data
+ */
+ } else if (vub300->resp.common.header_type == RESPONSE_ERROR) {
+ cmd->error =
+ vub300_response_error(vub300->resp.error.error_code);
+ if (vub300->data)
+ usb_sg_cancel(&vub300->sg_request);
+ } else if (vub300->resp.common.header_type == RESPONSE_PIGGYBACKED) {
+ int offloaded_data_length =
+ vub300->resp.common.header_size -
+ sizeof(struct sd_register_header);
+ int register_count = offloaded_data_length >> 3;
+ int ri = 0;
+ while (register_count--) {
+ add_offloaded_reg(vub300, &vub300->resp.pig.reg[ri]);
+ ri += 1;
+ }
+ vub300->resp.common.header_size =
+ sizeof(struct sd_register_header);
+ vub300->resp.common.header_type = 0x00;
+ cmd->error = 0;
+ } else if (vub300->resp.common.header_type == RESPONSE_PIG_DISABLED) {
+ int offloaded_data_length =
+ vub300->resp.common.header_size -
+ sizeof(struct sd_register_header);
+ int register_count = offloaded_data_length >> 3;
+ int ri = 0;
+ while (register_count--) {
+ add_offloaded_reg(vub300, &vub300->resp.pig.reg[ri]);
+ ri += 1;
+ }
+ mutex_lock(&vub300->irq_mutex);
+ if (vub300->irqs_queued) {
+ vub300->irqs_queued += 1;
+ } else if (vub300->irq_enabled) {
+ vub300->irqs_queued += 1;
+ vub300_queue_poll_work(vub300, 0);
+ } else {
+ vub300->irqs_queued += 1;
+ }
+ vub300->irq_disabled = 1;
+ mutex_unlock(&vub300->irq_mutex);
+ vub300->resp.common.header_size =
+ sizeof(struct sd_register_header);
+ vub300->resp.common.header_type = 0x00;
+ cmd->error = 0;
+ } else if (vub300->resp.common.header_type == RESPONSE_PIG_ENABLED) {
+ int offloaded_data_length =
+ vub300->resp.common.header_size -
+ sizeof(struct sd_register_header);
+ int register_count = offloaded_data_length >> 3;
+ int ri = 0;
+ while (register_count--) {
+ add_offloaded_reg(vub300, &vub300->resp.pig.reg[ri]);
+ ri += 1;
+ }
+ mutex_lock(&vub300->irq_mutex);
+ if (vub300->irqs_queued) {
+ vub300->irqs_queued += 1;
+ } else if (vub300->irq_enabled) {
+ vub300->irqs_queued += 1;
+ vub300_queue_poll_work(vub300, 0);
+ } else {
+ vub300->irqs_queued += 1;
+ }
+ vub300->irq_disabled = 0;
+ mutex_unlock(&vub300->irq_mutex);
+ vub300->resp.common.header_size =
+ sizeof(struct sd_register_header);
+ vub300->resp.common.header_type = 0x00;
+ cmd->error = 0;
+ } else {
+ cmd->error = -EINVAL;
+ }
+}
+
+static void construct_request_response(struct vub300_mmc_host *vub300,
+ struct mmc_command *cmd)
+{
+ int resp_len = vub300->resp_len;
+ int less_cmd = (17 == resp_len) ? resp_len : resp_len - 1;
+ int bytes = 3 & less_cmd;
+ int words = less_cmd >> 2;
+ u8 *r = vub300->resp.response.command_response;
+ if (bytes == 3) {
+ cmd->resp[words] = (r[1 + (words << 2)] << 24)
+ | (r[2 + (words << 2)] << 16)
+ | (r[3 + (words << 2)] << 8);
+ } else if (bytes == 2) {
+ cmd->resp[words] = (r[1 + (words << 2)] << 24)
+ | (r[2 + (words << 2)] << 16);
+ } else if (bytes == 1) {
+ cmd->resp[words] = (r[1 + (words << 2)] << 24);
+ }
+ while (words-- > 0) {
+ cmd->resp[words] = (r[1 + (words << 2)] << 24)
+ | (r[2 + (words << 2)] << 16)
+ | (r[3 + (words << 2)] << 8)
+ | (r[4 + (words << 2)] << 0);
+ }
+ if ((cmd->opcode == 53) && (0x000000FF & cmd->resp[0]))
+ cmd->resp[0] &= 0xFFFFFF00;
+}
+
+/* this thread runs only when there is an upper level command req outstanding */
+static void vub300_cmndwork_thread(struct work_struct *work)
+{
+ struct vub300_mmc_host *vub300 =
+ container_of(work, struct vub300_mmc_host, cmndwork);
+ if (!vub300->interface) {
+ kref_put(&vub300->kref, vub300_delete);
+ return;
+ } else {
+ struct mmc_request *req = vub300->req;
+ struct mmc_command *cmd = vub300->cmd;
+ struct mmc_data *data = vub300->data;
+ int data_length;
+ mutex_lock(&vub300->cmd_mutex);
+ init_completion(&vub300->command_complete);
+ if (likely(vub300->vub_name[0]) || !vub300->mmc->card ||
+ !mmc_card_present(vub300->mmc->card)) {
+ /*
+ * the name of the EMPTY Pseudo firmware file
+ * is used as a flag to indicate that the file
+ * has been already downloaded to the VUB300 chip
+ */
+ } else if (0 == vub300->mmc->card->sdio_funcs) {
+ strncpy(vub300->vub_name, "SD memory device",
+ sizeof(vub300->vub_name));
+ } else {
+ download_offload_pseudocode(vub300);
+ }
+ send_command(vub300);
+ if (!data)
+ data_length = 0;
+ else if (MMC_DATA_READ & data->flags)
+ data_length = __command_read_data(vub300, cmd, data);
+ else
+ data_length = __command_write_data(vub300, cmd, data);
+ __vub300_command_response(vub300, cmd, data, data_length);
+ vub300->req = NULL;
+ vub300->cmd = NULL;
+ vub300->data = NULL;
+ if (cmd->error) {
+ if (cmd->error == -ENOMEDIUM)
+ check_vub300_port_status(vub300);
+ mutex_unlock(&vub300->cmd_mutex);
+ mmc_request_done(vub300->mmc, req);
+ kref_put(&vub300->kref, vub300_delete);
+ return;
+ } else {
+ construct_request_response(vub300, cmd);
+ vub300->resp_len = 0;
+ mutex_unlock(&vub300->cmd_mutex);
+ kref_put(&vub300->kref, vub300_delete);
+ mmc_request_done(vub300->mmc, req);
+ return;
+ }
+ }
+}
+
+static int examine_cyclic_buffer(struct vub300_mmc_host *vub300,
+ struct mmc_command *cmd, u8 Function)
+{
+ /* cmd_mutex is held by vub300_mmc_request */
+ u8 cmd0 = 0xFF & (cmd->arg >> 24);
+ u8 cmd1 = 0xFF & (cmd->arg >> 16);
+ u8 cmd2 = 0xFF & (cmd->arg >> 8);
+ u8 cmd3 = 0xFF & (cmd->arg >> 0);
+ int first = MAXREGMASK & vub300->fn[Function].offload_point;
+ struct offload_registers_access *rf = &vub300->fn[Function].reg[first];
+ if (cmd0 == rf->command_byte[0] &&
+ cmd1 == rf->command_byte[1] &&
+ cmd2 == rf->command_byte[2] &&
+ cmd3 == rf->command_byte[3]) {
+ u8 checksum = 0x00;
+ cmd->resp[1] = checksum << 24;
+ cmd->resp[0] = (rf->Respond_Byte[0] << 24)
+ | (rf->Respond_Byte[1] << 16)
+ | (rf->Respond_Byte[2] << 8)
+ | (rf->Respond_Byte[3] << 0);
+ vub300->fn[Function].offload_point += 1;
+ vub300->fn[Function].offload_count -= 1;
+ vub300->total_offload_count -= 1;
+ return 1;
+ } else {
+ int delta = 1; /* because it does not match the first one */
+ u8 register_count = vub300->fn[Function].offload_count - 1;
+ u32 register_point = vub300->fn[Function].offload_point + 1;
+ while (0 < register_count) {
+ int point = MAXREGMASK & register_point;
+ struct offload_registers_access *r =
+ &vub300->fn[Function].reg[point];
+ if (cmd0 == r->command_byte[0] &&
+ cmd1 == r->command_byte[1] &&
+ cmd2 == r->command_byte[2] &&
+ cmd3 == r->command_byte[3]) {
+ u8 checksum = 0x00;
+ cmd->resp[1] = checksum << 24;
+ cmd->resp[0] = (r->Respond_Byte[0] << 24)
+ | (r->Respond_Byte[1] << 16)
+ | (r->Respond_Byte[2] << 8)
+ | (r->Respond_Byte[3] << 0);
+ vub300->fn[Function].offload_point += delta;
+ vub300->fn[Function].offload_count -= delta;
+ vub300->total_offload_count -= delta;
+ return 1;
+ } else {
+ register_point += 1;
+ register_count -= 1;
+ delta += 1;
+ continue;
+ }
+ }
+ return 0;
+ }
+}
+
+static int satisfy_request_from_offloaded_data(struct vub300_mmc_host *vub300,
+ struct mmc_command *cmd)
+{
+ /* cmd_mutex is held by vub300_mmc_request */
+ u8 regs = vub300->dynamic_register_count;
+ u8 i = 0;
+ u8 func = FUN(cmd);
+ u32 reg = REG(cmd);
+ while (0 < regs--) {
+ if ((vub300->sdio_register[i].func_num == func) &&
+ (vub300->sdio_register[i].sdio_reg == reg)) {
+ if (!vub300->sdio_register[i].prepared) {
+ return 0;
+ } else if ((0x80000000 & cmd->arg) == 0x80000000) {
+ /*
+ * a write to a dynamic register
+ * nullifies our offloaded value
+ */
+ vub300->sdio_register[i].prepared = 0;
+ return 0;
+ } else {
+ u8 checksum = 0x00;
+ u8 rsp0 = 0x00;
+ u8 rsp1 = 0x00;
+ u8 rsp2 = vub300->sdio_register[i].response;
+ u8 rsp3 = vub300->sdio_register[i].regvalue;
+ vub300->sdio_register[i].prepared = 0;
+ cmd->resp[1] = checksum << 24;
+ cmd->resp[0] = (rsp0 << 24)
+ | (rsp1 << 16)
+ | (rsp2 << 8)
+ | (rsp3 << 0);
+ return 1;
+ }
+ } else {
+ i += 1;
+ continue;
+ }
+ };
+ if (vub300->total_offload_count == 0)
+ return 0;
+ else if (vub300->fn[func].offload_count == 0)
+ return 0;
+ else
+ return examine_cyclic_buffer(vub300, cmd, func);
+}
+
+static void vub300_mmc_request(struct mmc_host *mmc, struct mmc_request *req)
+{ /* NOT irq */
+ struct mmc_command *cmd = req->cmd;
+ struct vub300_mmc_host *vub300 = mmc_priv(mmc);
+ if (!vub300->interface) {
+ cmd->error = -ESHUTDOWN;
+ mmc_request_done(mmc, req);
+ return;
+ } else {
+ struct mmc_data *data = req->data;
+ if (!vub300->card_powered) {
+ cmd->error = -ENOMEDIUM;
+ mmc_request_done(mmc, req);
+ return;
+ }
+ if (!vub300->card_present) {
+ cmd->error = -ENOMEDIUM;
+ mmc_request_done(mmc, req);
+ return;
+ }
+ if (vub300->usb_transport_fail) {
+ cmd->error = vub300->usb_transport_fail;
+ mmc_request_done(mmc, req);
+ return;
+ }
+ if (!vub300->interface) {
+ cmd->error = -ENODEV;
+ mmc_request_done(mmc, req);
+ return;
+ }
+ kref_get(&vub300->kref);
+ mutex_lock(&vub300->cmd_mutex);
+ mod_timer(&vub300->inactivity_timer, jiffies + HZ);
+ /*
+ * for performance we have to return immediately
+ * if the requested data has been offloaded
+ */
+ if (cmd->opcode == 52 &&
+ satisfy_request_from_offloaded_data(vub300, cmd)) {
+ cmd->error = 0;
+ mutex_unlock(&vub300->cmd_mutex);
+ kref_put(&vub300->kref, vub300_delete);
+ mmc_request_done(mmc, req);
+ return;
+ } else {
+ vub300->cmd = cmd;
+ vub300->req = req;
+ vub300->data = data;
+ if (data)
+ vub300->datasize = data->blksz * data->blocks;
+ else
+ vub300->datasize = 0;
+ vub300_queue_cmnd_work(vub300);
+ mutex_unlock(&vub300->cmd_mutex);
+ kref_put(&vub300->kref, vub300_delete);
+ /*
+ * the kernel lock diagnostics complain
+ * if the cmd_mutex * is "passed on"
+ * to the cmndwork thread,
+ * so we must release it now
+ * and re-acquire it in the cmndwork thread
+ */
+ }
+ }
+}
+
+static void __set_clock_speed(struct vub300_mmc_host *vub300, u8 buf[8],
+ struct mmc_ios *ios)
+{
+ int buf_array_size = 8; /* ARRAY_SIZE(buf) does not work !!! */
+ int retval;
+ u32 kHzClock;
+ if (ios->clock >= 48000000)
+ kHzClock = 48000;
+ else if (ios->clock >= 24000000)
+ kHzClock = 24000;
+ else if (ios->clock >= 20000000)
+ kHzClock = 20000;
+ else if (ios->clock >= 15000000)
+ kHzClock = 15000;
+ else if (ios->clock >= 200000)
+ kHzClock = 200;
+ else
+ kHzClock = 0;
+ {
+ int i;
+ u64 c = kHzClock;
+ for (i = 0; i < buf_array_size; i++) {
+ buf[i] = c;
+ c >>= 8;
+ }
+ }
+ retval =
+ usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
+ SET_CLOCK_SPEED,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x00, 0x00, buf, buf_array_size, HZ);
+ if (retval != 8) {
+ dev_err(&vub300->udev->dev, "SET_CLOCK_SPEED"
+ " %dkHz failed with retval=%d\n", kHzClock, retval);
+ } else {
+ dev_dbg(&vub300->udev->dev, "SET_CLOCK_SPEED"
+ " %dkHz\n", kHzClock);
+ }
+}
+
+static void vub300_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{ /* NOT irq */
+ struct vub300_mmc_host *vub300 = mmc_priv(mmc);
+ if (!vub300->interface)
+ return;
+ kref_get(&vub300->kref);
+ mutex_lock(&vub300->cmd_mutex);
+ if ((ios->power_mode == MMC_POWER_OFF) && vub300->card_powered) {
+ vub300->card_powered = 0;
+ usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
+ SET_SD_POWER,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x0000, 0x0000, NULL, 0, HZ);
+ /* must wait for the VUB300 u-proc to boot up */
+ msleep(600);
+ } else if ((ios->power_mode == MMC_POWER_UP) && !vub300->card_powered) {
+ usb_control_msg(vub300->udev, usb_sndctrlpipe(vub300->udev, 0),
+ SET_SD_POWER,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x0001, 0x0000, NULL, 0, HZ);
+ msleep(600);
+ vub300->card_powered = 1;
+ } else if (ios->power_mode == MMC_POWER_ON) {
+ u8 *buf = kmalloc(8, GFP_KERNEL);
+ if (buf) {
+ __set_clock_speed(vub300, buf, ios);
+ kfree(buf);
+ }
+ } else {
+ /* this should mean no change of state */
+ }
+ mutex_unlock(&vub300->cmd_mutex);
+ kref_put(&vub300->kref, vub300_delete);
+}
+
+static int vub300_mmc_get_ro(struct mmc_host *mmc)
+{
+ struct vub300_mmc_host *vub300 = mmc_priv(mmc);
+ return vub300->read_only;
+}
+
+static void vub300_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{ /* NOT irq */
+ struct vub300_mmc_host *vub300 = mmc_priv(mmc);
+ if (!vub300->interface)
+ return;
+ kref_get(&vub300->kref);
+ if (enable) {
+ mutex_lock(&vub300->irq_mutex);
+ if (vub300->irqs_queued) {
+ vub300->irqs_queued -= 1;
+ mmc_signal_sdio_irq(vub300->mmc);
+ } else if (vub300->irq_disabled) {
+ vub300->irq_disabled = 0;
+ vub300->irq_enabled = 1;
+ vub300_queue_poll_work(vub300, 0);
+ } else if (vub300->irq_enabled) {
+ /* this should not happen, so we will just ignore it */
+ } else {
+ vub300->irq_enabled = 1;
+ vub300_queue_poll_work(vub300, 0);
+ }
+ mutex_unlock(&vub300->irq_mutex);
+ } else {
+ vub300->irq_enabled = 0;
+ }
+ kref_put(&vub300->kref, vub300_delete);
+}
+
+void vub300_init_card(struct mmc_host *mmc, struct mmc_card *card)
+{ /* NOT irq */
+ struct vub300_mmc_host *vub300 = mmc_priv(mmc);
+ dev_info(&vub300->udev->dev, "NO host QUIRKS for this card\n");
+}
+
+static struct mmc_host_ops vub300_mmc_ops = {
+ .request = vub300_mmc_request,
+ .set_ios = vub300_mmc_set_ios,
+ .get_ro = vub300_mmc_get_ro,
+ .enable_sdio_irq = vub300_enable_sdio_irq,
+ .init_card = vub300_init_card,
+};
+
+static int vub300_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{ /* NOT irq */
+ struct vub300_mmc_host *vub300 = NULL;
+ struct usb_host_interface *iface_desc;
+ struct usb_device *udev = usb_get_dev(interface_to_usbdev(interface));
+ int i;
+ int retval = -ENOMEM;
+ struct urb *command_out_urb;
+ struct urb *command_res_urb;
+ struct mmc_host *mmc;
+ char manufacturer[48];
+ char product[32];
+ char serial_number[32];
+ usb_string(udev, udev->descriptor.iManufacturer, manufacturer,
+ sizeof(manufacturer));
+ usb_string(udev, udev->descriptor.iProduct, product, sizeof(product));
+ usb_string(udev, udev->descriptor.iSerialNumber, serial_number,
+ sizeof(serial_number));
+ dev_info(&udev->dev, "probing VID:PID(%04X:%04X) %s %s %s\n",
+ udev->descriptor.idVendor, udev->descriptor.idProduct,
+ manufacturer, product, serial_number);
+ command_out_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!command_out_urb) {
+ retval = -ENOMEM;
+ dev_err(&vub300->udev->dev,
+ "not enough memory for the command_out_urb\n");
+ goto error0;
+ }
+ command_res_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!command_res_urb) {
+ retval = -ENOMEM;
+ dev_err(&vub300->udev->dev,
+ "not enough memory for the command_res_urb\n");
+ goto error1;
+ }
+ /* this also allocates memory for our VUB300 mmc host device */
+ mmc = mmc_alloc_host(sizeof(struct vub300_mmc_host), &udev->dev);
+ if (!mmc) {
+ retval = -ENOMEM;
+ dev_err(&vub300->udev->dev,
+ "not enough memory for the mmc_host\n");
+ goto error4;
+ }
+ /* MMC core transfer sizes tunable parameters */
+ mmc->caps = 0;
+ if (!force_1_bit_data_xfers)
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
+ if (!force_polling_for_irqs)
+ mmc->caps |= MMC_CAP_SDIO_IRQ;
+ mmc->caps &= ~MMC_CAP_NEEDS_POLL;
+ /*
+ * MMC_CAP_NEEDS_POLL causes core.c:mmc_rescan() to poll
+ * for devices which results in spurious CMD7's being
+ * issued which stops some SDIO cards from working
+ */
+ if (limit_speed_to_24_MHz) {
+ mmc->caps |= MMC_CAP_MMC_HIGHSPEED;
+ mmc->caps |= MMC_CAP_SD_HIGHSPEED;
+ mmc->f_max = 24000000;
+ dev_info(&udev->dev, "limiting SDIO speed to 24_MHz\n");
+ } else {
+ mmc->caps |= MMC_CAP_MMC_HIGHSPEED;
+ mmc->caps |= MMC_CAP_SD_HIGHSPEED;
+ mmc->f_max = 48000000;
+ }
+ mmc->f_min = 200000;
+ mmc->max_blk_count = 511;
+ mmc->max_blk_size = 512;
+ mmc->max_segs = 128;
+ if (force_max_req_size)
+ mmc->max_req_size = force_max_req_size * 1024;
+ else
+ mmc->max_req_size = 64 * 1024;
+ mmc->max_seg_size = mmc->max_req_size;
+ mmc->ocr_avail = 0;
+ mmc->ocr_avail |= MMC_VDD_165_195;
+ mmc->ocr_avail |= MMC_VDD_20_21;
+ mmc->ocr_avail |= MMC_VDD_21_22;
+ mmc->ocr_avail |= MMC_VDD_22_23;
+ mmc->ocr_avail |= MMC_VDD_23_24;
+ mmc->ocr_avail |= MMC_VDD_24_25;
+ mmc->ocr_avail |= MMC_VDD_25_26;
+ mmc->ocr_avail |= MMC_VDD_26_27;
+ mmc->ocr_avail |= MMC_VDD_27_28;
+ mmc->ocr_avail |= MMC_VDD_28_29;
+ mmc->ocr_avail |= MMC_VDD_29_30;
+ mmc->ocr_avail |= MMC_VDD_30_31;
+ mmc->ocr_avail |= MMC_VDD_31_32;
+ mmc->ocr_avail |= MMC_VDD_32_33;
+ mmc->ocr_avail |= MMC_VDD_33_34;
+ mmc->ocr_avail |= MMC_VDD_34_35;
+ mmc->ocr_avail |= MMC_VDD_35_36;
+ mmc->ops = &vub300_mmc_ops;
+ vub300 = mmc_priv(mmc);
+ vub300->mmc = mmc;
+ vub300->card_powered = 0;
+ vub300->bus_width = 0;
+ vub300->cmnd.head.block_size[0] = 0x00;
+ vub300->cmnd.head.block_size[1] = 0x00;
+ vub300->app_spec = 0;
+ mutex_init(&vub300->cmd_mutex);
+ mutex_init(&vub300->irq_mutex);
+ vub300->command_out_urb = command_out_urb;
+ vub300->command_res_urb = command_res_urb;
+ vub300->usb_timed_out = 0;
+ vub300->dynamic_register_count = 0;
+
+ for (i = 0; i < ARRAY_SIZE(vub300->fn); i++) {
+ vub300->fn[i].offload_point = 0;
+ vub300->fn[i].offload_count = 0;
+ }
+
+ vub300->total_offload_count = 0;
+ vub300->irq_enabled = 0;
+ vub300->irq_disabled = 0;
+ vub300->irqs_queued = 0;
+
+ for (i = 0; i < ARRAY_SIZE(vub300->sdio_register); i++)
+ vub300->sdio_register[i++].activate = 0;
+
+ vub300->udev = udev;
+ vub300->interface = interface;
+ vub300->cmnd_res_ep = 0;
+ vub300->cmnd_out_ep = 0;
+ vub300->data_inp_ep = 0;
+ vub300->data_out_ep = 0;
+
+ for (i = 0; i < ARRAY_SIZE(vub300->fbs); i++)
+ vub300->fbs[i] = 512;
+
+ /*
+ * set up the endpoint information
+ *
+ * use the first pair of bulk-in and bulk-out
+ * endpoints for Command/Response+Interrupt
+ *
+ * use the second pair of bulk-in and bulk-out
+ * endpoints for Data In/Out
+ */
+ vub300->large_usb_packets = 0;
+ iface_desc = interface->cur_altsetting;
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ struct usb_endpoint_descriptor *endpoint =
+ &iface_desc->endpoint[i].desc;
+ dev_info(&vub300->udev->dev,
+ "vub300 testing %s EndPoint(%d) %02X\n",
+ usb_endpoint_is_bulk_in(endpoint) ? "BULK IN" :
+ usb_endpoint_is_bulk_out(endpoint) ? "BULK OUT" :
+ "UNKNOWN", i, endpoint->bEndpointAddress);
+ if (endpoint->wMaxPacketSize > 64)
+ vub300->large_usb_packets = 1;
+ if (usb_endpoint_is_bulk_in(endpoint)) {
+ if (!vub300->cmnd_res_ep) {
+ vub300->cmnd_res_ep =
+ endpoint->bEndpointAddress;
+ } else if (!vub300->data_inp_ep) {
+ vub300->data_inp_ep =
+ endpoint->bEndpointAddress;
+ } else {
+ dev_warn(&vub300->udev->dev,
+ "ignoring"
+ " unexpected bulk_in endpoint");
+ }
+ } else if (usb_endpoint_is_bulk_out(endpoint)) {
+ if (!vub300->cmnd_out_ep) {
+ vub300->cmnd_out_ep =
+ endpoint->bEndpointAddress;
+ } else if (!vub300->data_out_ep) {
+ vub300->data_out_ep =
+ endpoint->bEndpointAddress;
+ } else {
+ dev_warn(&vub300->udev->dev,
+ "ignoring"
+ " unexpected bulk_out endpoint");
+ }
+ } else {
+ dev_warn(&vub300->udev->dev,
+ "vub300 ignoring EndPoint(%d) %02X", i,
+ endpoint->bEndpointAddress);
+ }
+ }
+ if (vub300->cmnd_res_ep && vub300->cmnd_out_ep &&
+ vub300->data_inp_ep && vub300->data_out_ep) {
+ dev_info(&vub300->udev->dev,
+ "vub300 %s packets"
+ " using EndPoints %02X %02X %02X %02X\n",
+ vub300->large_usb_packets ? "LARGE" : "SMALL",
+ vub300->cmnd_out_ep, vub300->cmnd_res_ep,
+ vub300->data_out_ep, vub300->data_inp_ep);
+ /* we have the expected EndPoints */
+ } else {
+ dev_err(&vub300->udev->dev,
+ "Could not find two sets of bulk-in/out endpoint pairs\n");
+ retval = -EINVAL;
+ goto error5;
+ }
+ retval =
+ usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
+ GET_HC_INF0,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x0000, 0x0000, &vub300->hc_info,
+ sizeof(vub300->hc_info), HZ);
+ if (retval < 0)
+ goto error5;
+ retval =
+ usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
+ SET_ROM_WAIT_STATES,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ firmware_rom_wait_states, 0x0000, NULL, 0, HZ);
+ if (retval < 0)
+ goto error5;
+ dev_info(&vub300->udev->dev,
+ "operating_mode = %s %s %d MHz %s %d byte USB packets\n",
+ (mmc->caps & MMC_CAP_SDIO_IRQ) ? "IRQs" : "POLL",
+ (mmc->caps & MMC_CAP_4_BIT_DATA) ? "4-bit" : "1-bit",
+ mmc->f_max / 1000000,
+ pad_input_to_usb_pkt ? "padding input data to" : "with",
+ vub300->large_usb_packets ? 512 : 64);
+ retval =
+ usb_control_msg(vub300->udev, usb_rcvctrlpipe(vub300->udev, 0),
+ GET_SYSTEM_PORT_STATUS,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x0000, 0x0000, &vub300->system_port_status,
+ sizeof(vub300->system_port_status), HZ);
+ if (retval < 0) {
+ goto error4;
+ } else if (sizeof(vub300->system_port_status) == retval) {
+ vub300->card_present =
+ (0x0001 & vub300->system_port_status.port_flags) ? 1 : 0;
+ vub300->read_only =
+ (0x0010 & vub300->system_port_status.port_flags) ? 1 : 0;
+ } else {
+ goto error4;
+ }
+ usb_set_intfdata(interface, vub300);
+ INIT_DELAYED_WORK(&vub300->pollwork, vub300_pollwork_thread);
+ INIT_WORK(&vub300->cmndwork, vub300_cmndwork_thread);
+ INIT_WORK(&vub300->deadwork, vub300_deadwork_thread);
+ kref_init(&vub300->kref);
+ init_timer(&vub300->sg_transfer_timer);
+ vub300->sg_transfer_timer.data = (unsigned long)vub300;
+ vub300->sg_transfer_timer.function = vub300_sg_timed_out;
+ kref_get(&vub300->kref);
+ init_timer(&vub300->inactivity_timer);
+ vub300->inactivity_timer.data = (unsigned long)vub300;
+ vub300->inactivity_timer.function = vub300_inactivity_timer_expired;
+ vub300->inactivity_timer.expires = jiffies + HZ;
+ add_timer(&vub300->inactivity_timer);
+ if (vub300->card_present)
+ dev_info(&vub300->udev->dev,
+ "USB vub300 remote SDIO host controller[%d]"
+ "connected with SD/SDIO card inserted\n",
+ interface_to_InterfaceNumber(interface));
+ else
+ dev_info(&vub300->udev->dev,
+ "USB vub300 remote SDIO host controller[%d]"
+ "connected with no SD/SDIO card inserted\n",
+ interface_to_InterfaceNumber(interface));
+ mmc_add_host(mmc);
+ return 0;
+error5:
+ mmc_free_host(mmc);
+ /*
+ * and hence also frees vub300
+ * which is contained at the end of struct mmc
+ */
+error4:
+ usb_free_urb(command_out_urb);
+error1:
+ usb_free_urb(command_res_urb);
+error0:
+ return retval;
+}
+
+static void vub300_disconnect(struct usb_interface *interface)
+{ /* NOT irq */
+ struct vub300_mmc_host *vub300 = usb_get_intfdata(interface);
+ if (!vub300 || !vub300->mmc) {
+ return;
+ } else {
+ struct mmc_host *mmc = vub300->mmc;
+ if (!vub300->mmc) {
+ return;
+ } else {
+ int ifnum = interface_to_InterfaceNumber(interface);
+ usb_set_intfdata(interface, NULL);
+ /* prevent more I/O from starting */
+ vub300->interface = NULL;
+ kref_put(&vub300->kref, vub300_delete);
+ mmc_remove_host(mmc);
+ pr_info("USB vub300 remote SDIO host controller[%d]"
+ " now disconnected", ifnum);
+ return;
+ }
+ }
+}
+
+#ifdef CONFIG_PM
+static int vub300_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct vub300_mmc_host *vub300 = usb_get_intfdata(intf);
+ if (!vub300 || !vub300->mmc) {
+ return 0;
+ } else {
+ struct mmc_host *mmc = vub300->mmc;
+ mmc_suspend_host(mmc);
+ return 0;
+ }
+}
+
+static int vub300_resume(struct usb_interface *intf)
+{
+ struct vub300_mmc_host *vub300 = usb_get_intfdata(intf);
+ if (!vub300 || !vub300->mmc) {
+ return 0;
+ } else {
+ struct mmc_host *mmc = vub300->mmc;
+ mmc_resume_host(mmc);
+ return 0;
+ }
+}
+#else
+#define vub300_suspend NULL
+#define vub300_resume NULL
+#endif
+static int vub300_pre_reset(struct usb_interface *intf)
+{ /* NOT irq */
+ struct vub300_mmc_host *vub300 = usb_get_intfdata(intf);
+ mutex_lock(&vub300->cmd_mutex);
+ return 0;
+}
+
+static int vub300_post_reset(struct usb_interface *intf)
+{ /* NOT irq */
+ struct vub300_mmc_host *vub300 = usb_get_intfdata(intf);
+ /* we are sure no URBs are active - no locking needed */
+ vub300->errors = -EPIPE;
+ mutex_unlock(&vub300->cmd_mutex);
+ return 0;
+}
+
+static struct usb_driver vub300_driver = {
+ .name = "vub300",
+ .probe = vub300_probe,
+ .disconnect = vub300_disconnect,
+ .suspend = vub300_suspend,
+ .resume = vub300_resume,
+ .pre_reset = vub300_pre_reset,
+ .post_reset = vub300_post_reset,
+ .id_table = vub300_table,
+ .supports_autosuspend = 1,
+};
+
+static int __init vub300_init(void)
+{ /* NOT irq */
+ int result;
+
+ pr_info("VUB300 Driver rom wait states = %02X irqpoll timeout = %04X",
+ firmware_rom_wait_states, 0x0FFFF & firmware_irqpoll_timeout);
+ cmndworkqueue = create_singlethread_workqueue("kvub300c");
+ if (!cmndworkqueue) {
+ pr_err("not enough memory for the REQUEST workqueue");
+ result = -ENOMEM;
+ goto out1;
+ }
+ pollworkqueue = create_singlethread_workqueue("kvub300p");
+ if (!pollworkqueue) {
+ pr_err("not enough memory for the IRQPOLL workqueue");
+ result = -ENOMEM;
+ goto out2;
+ }
+ deadworkqueue = create_singlethread_workqueue("kvub300d");
+ if (!deadworkqueue) {
+ pr_err("not enough memory for the EXPIRED workqueue");
+ result = -ENOMEM;
+ goto out3;
+ }
+ result = usb_register(&vub300_driver);
+ if (result) {
+ pr_err("usb_register failed. Error number %d", result);
+ goto out4;
+ }
+ return 0;
+out4:
+ destroy_workqueue(deadworkqueue);
+out3:
+ destroy_workqueue(pollworkqueue);
+out2:
+ destroy_workqueue(cmndworkqueue);
+out1:
+ return result;
+}
+
+static void __exit vub300_exit(void)
+{
+ usb_deregister(&vub300_driver);
+ flush_workqueue(cmndworkqueue);
+ flush_workqueue(pollworkqueue);
+ flush_workqueue(deadworkqueue);
+ destroy_workqueue(cmndworkqueue);
+ destroy_workqueue(pollworkqueue);
+ destroy_workqueue(deadworkqueue);
+}
+
+module_init(vub300_init);
+module_exit(vub300_exit);
+
+MODULE_AUTHOR("Tony Olech <tony.olech@elandigitalsystems.com>");
+MODULE_DESCRIPTION("VUB300 USB to SD/MMC/SDIO adapter driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index b4567c35a322..bc50d5ea5534 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -148,8 +148,7 @@ config MTD_AFS_PARTS
You will still need the parsing functions to be called by the driver
for your particular device. It won't happen automatically. The
- 'armflash' map driver (CONFIG_MTD_ARM_INTEGRATOR) does this, for
- example.
+ 'physmap' map driver (CONFIG_MTD_PHYSMAP) does this, for example.
config MTD_OF_PARTS
def_bool y
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 44b1f46458ca..5069111c81cc 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -260,6 +260,13 @@ config MTD_BCM963XX
Support for parsing CFE image tag and creating MTD partitions on
Broadcom BCM63xx boards.
+config MTD_LANTIQ
+ tristate "Lantiq SoC NOR support"
+ depends on LANTIQ
+ select MTD_PARTITIONS
+ help
+ Support for NOR flash attached to the Lantiq SoC's External Bus Unit.
+
config MTD_DILNETPC
tristate "CFI Flash device mapped on DIL/Net PC"
depends on X86 && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index 08533bd5cba7..cb48b11affff 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -8,7 +8,6 @@ endif
# Chip mappings
obj-$(CONFIG_MTD_CDB89712) += cdb89712.o
-obj-$(CONFIG_MTD_ARM_INTEGRATOR)+= integrator-flash.o
obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o
obj-$(CONFIG_MTD_DC21285) += dc21285.o
obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o
@@ -60,3 +59,4 @@ obj-$(CONFIG_MTD_VMU) += vmu-flash.o
obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o
obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-flash.o
obj-$(CONFIG_MTD_LATCH_ADDR) += latch-addr-flash.o
+obj-$(CONFIG_MTD_LANTIQ) += lantiq-flash.o
diff --git a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c
deleted file mode 100644
index e22ff5adbbf4..000000000000
--- a/drivers/mtd/maps/integrator-flash.c
+++ /dev/null
@@ -1,309 +0,0 @@
-/*======================================================================
-
- drivers/mtd/maps/integrator-flash.c: ARM Integrator flash map driver
-
- Copyright (C) 2000 ARM Limited
- Copyright (C) 2003 Deep Blue Solutions Ltd.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You 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
-
- This is access code for flashes using ARM's flash partitioning
- standards.
-
-======================================================================*/
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/platform_device.h>
-#include <linux/init.h>
-#include <linux/io.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-#include <linux/mtd/concat.h>
-
-#include <asm/mach/flash.h>
-#include <mach/hardware.h>
-#include <asm/system.h>
-
-struct armflash_subdev_info {
- char *name;
- struct mtd_info *mtd;
- struct map_info map;
- struct flash_platform_data *plat;
-};
-
-struct armflash_info {
- struct resource *res;
- struct mtd_partition *parts;
- struct mtd_info *mtd;
- int nr_subdev;
- struct armflash_subdev_info subdev[0];
-};
-
-static void armflash_set_vpp(struct map_info *map, int on)
-{
- struct armflash_subdev_info *info =
- container_of(map, struct armflash_subdev_info, map);
-
- if (info->plat && info->plat->set_vpp)
- info->plat->set_vpp(on);
-}
-
-static const char *probes[] = { "cmdlinepart", "RedBoot", "afs", NULL };
-
-static int armflash_subdev_probe(struct armflash_subdev_info *subdev,
- struct resource *res)
-{
- struct flash_platform_data *plat = subdev->plat;
- resource_size_t size = res->end - res->start + 1;
- void __iomem *base;
- int err = 0;
-
- if (!request_mem_region(res->start, size, subdev->name)) {
- err = -EBUSY;
- goto out;
- }
-
- base = ioremap(res->start, size);
- if (!base) {
- err = -ENOMEM;
- goto no_mem;
- }
-
- /*
- * look for CFI based flash parts fitted to this board
- */
- subdev->map.size = size;
- subdev->map.bankwidth = plat->width;
- subdev->map.phys = res->start;
- subdev->map.virt = base;
- subdev->map.name = subdev->name;
- subdev->map.set_vpp = armflash_set_vpp;
-
- simple_map_init(&subdev->map);
-
- /*
- * Also, the CFI layer automatically works out what size
- * of chips we have, and does the necessary identification
- * for us automatically.
- */
- subdev->mtd = do_map_probe(plat->map_name, &subdev->map);
- if (!subdev->mtd) {
- err = -ENXIO;
- goto no_device;
- }
-
- subdev->mtd->owner = THIS_MODULE;
-
- /* Successful? */
- if (err == 0)
- return err;
-
- if (subdev->mtd)
- map_destroy(subdev->mtd);
- no_device:
- iounmap(base);
- no_mem:
- release_mem_region(res->start, size);
- out:
- return err;
-}
-
-static void armflash_subdev_remove(struct armflash_subdev_info *subdev)
-{
- if (subdev->mtd)
- map_destroy(subdev->mtd);
- if (subdev->map.virt)
- iounmap(subdev->map.virt);
- kfree(subdev->name);
- subdev->name = NULL;
- release_mem_region(subdev->map.phys, subdev->map.size);
-}
-
-static int armflash_probe(struct platform_device *dev)
-{
- struct flash_platform_data *plat = dev->dev.platform_data;
- unsigned int size;
- struct armflash_info *info;
- int i, nr, err;
-
- /* Count the number of devices */
- for (nr = 0; ; nr++)
- if (!platform_get_resource(dev, IORESOURCE_MEM, nr))
- break;
- if (nr == 0) {
- err = -ENODEV;
- goto out;
- }
-
- size = sizeof(struct armflash_info) +
- sizeof(struct armflash_subdev_info) * nr;
- info = kzalloc(size, GFP_KERNEL);
- if (!info) {
- err = -ENOMEM;
- goto out;
- }
-
- if (plat && plat->init) {
- err = plat->init();
- if (err)
- goto no_resource;
- }
-
- for (i = 0; i < nr; i++) {
- struct armflash_subdev_info *subdev = &info->subdev[i];
- struct resource *res;
-
- res = platform_get_resource(dev, IORESOURCE_MEM, i);
- if (!res)
- break;
-
- if (nr == 1)
- /* No MTD concatenation, just use the default name */
- subdev->name = kstrdup(dev_name(&dev->dev), GFP_KERNEL);
- else
- subdev->name = kasprintf(GFP_KERNEL, "%s-%d",
- dev_name(&dev->dev), i);
- if (!subdev->name) {
- err = -ENOMEM;
- break;
- }
- subdev->plat = plat;
-
- err = armflash_subdev_probe(subdev, res);
- if (err) {
- kfree(subdev->name);
- subdev->name = NULL;
- break;
- }
- }
- info->nr_subdev = i;
-
- if (err)
- goto subdev_err;
-
- if (info->nr_subdev == 1)
- info->mtd = info->subdev[0].mtd;
- else if (info->nr_subdev > 1) {
- struct mtd_info *cdev[info->nr_subdev];
-
- /*
- * We detected multiple devices. Concatenate them together.
- */
- for (i = 0; i < info->nr_subdev; i++)
- cdev[i] = info->subdev[i].mtd;
-
- info->mtd = mtd_concat_create(cdev, info->nr_subdev,
- dev_name(&dev->dev));
- if (info->mtd == NULL)
- err = -ENXIO;
- }
-
- if (err < 0)
- goto cleanup;
-
- err = parse_mtd_partitions(info->mtd, probes, &info->parts, 0);
- if (err > 0) {
- err = add_mtd_partitions(info->mtd, info->parts, err);
- if (err)
- printk(KERN_ERR
- "mtd partition registration failed: %d\n", err);
- }
-
- if (err == 0) {
- platform_set_drvdata(dev, info);
- return err;
- }
-
- /*
- * We got an error, free all resources.
- */
- cleanup:
- if (info->mtd) {
- del_mtd_partitions(info->mtd);
- if (info->mtd != info->subdev[0].mtd)
- mtd_concat_destroy(info->mtd);
- }
- kfree(info->parts);
- subdev_err:
- for (i = info->nr_subdev - 1; i >= 0; i--)
- armflash_subdev_remove(&info->subdev[i]);
- no_resource:
- if (plat && plat->exit)
- plat->exit();
- kfree(info);
- out:
- return err;
-}
-
-static int armflash_remove(struct platform_device *dev)
-{
- struct armflash_info *info = platform_get_drvdata(dev);
- struct flash_platform_data *plat = dev->dev.platform_data;
- int i;
-
- platform_set_drvdata(dev, NULL);
-
- if (info) {
- if (info->mtd) {
- del_mtd_partitions(info->mtd);
- if (info->mtd != info->subdev[0].mtd)
- mtd_concat_destroy(info->mtd);
- }
- kfree(info->parts);
-
- for (i = info->nr_subdev - 1; i >= 0; i--)
- armflash_subdev_remove(&info->subdev[i]);
-
- if (plat && plat->exit)
- plat->exit();
-
- kfree(info);
- }
-
- return 0;
-}
-
-static struct platform_driver armflash_driver = {
- .probe = armflash_probe,
- .remove = armflash_remove,
- .driver = {
- .name = "armflash",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init armflash_init(void)
-{
- return platform_driver_register(&armflash_driver);
-}
-
-static void __exit armflash_exit(void)
-{
- platform_driver_unregister(&armflash_driver);
-}
-
-module_init(armflash_init);
-module_exit(armflash_exit);
-
-MODULE_AUTHOR("ARM Ltd");
-MODULE_DESCRIPTION("ARM Integrator CFI map driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:armflash");
diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c
new file mode 100644
index 000000000000..a90cabd7b84d
--- /dev/null
+++ b/drivers/mtd/maps/lantiq-flash.c
@@ -0,0 +1,251 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2004 Liu Peng Infineon IFAP DC COM CPE
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/cfi.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
+
+#include <lantiq_soc.h>
+#include <lantiq_platform.h>
+
+/*
+ * The NOR flash is connected to the same external bus unit (EBU) as PCI.
+ * To make PCI work we need to enable the endianness swapping for the address
+ * written to the EBU. This endianness swapping works for PCI correctly but
+ * fails for attached NOR devices. To workaround this we need to use a complex
+ * map. The workaround involves swapping all addresses whilst probing the chip.
+ * Once probing is complete we stop swapping the addresses but swizzle the
+ * unlock addresses to ensure that access to the NOR device works correctly.
+ */
+
+enum {
+ LTQ_NOR_PROBING,
+ LTQ_NOR_NORMAL
+};
+
+struct ltq_mtd {
+ struct resource *res;
+ struct mtd_info *mtd;
+ struct map_info *map;
+};
+
+static char ltq_map_name[] = "ltq_nor";
+
+static map_word
+ltq_read16(struct map_info *map, unsigned long adr)
+{
+ unsigned long flags;
+ map_word temp;
+
+ if (map->map_priv_1 == LTQ_NOR_PROBING)
+ adr ^= 2;
+ spin_lock_irqsave(&ebu_lock, flags);
+ temp.x[0] = *(u16 *)(map->virt + adr);
+ spin_unlock_irqrestore(&ebu_lock, flags);
+ return temp;
+}
+
+static void
+ltq_write16(struct map_info *map, map_word d, unsigned long adr)
+{
+ unsigned long flags;
+
+ if (map->map_priv_1 == LTQ_NOR_PROBING)
+ adr ^= 2;
+ spin_lock_irqsave(&ebu_lock, flags);
+ *(u16 *)(map->virt + adr) = d.x[0];
+ spin_unlock_irqrestore(&ebu_lock, flags);
+}
+
+/*
+ * The following 2 functions copy data between iomem and a cached memory
+ * section. As memcpy() makes use of pre-fetching we cannot use it here.
+ * The normal alternative of using memcpy_{to,from}io also makes use of
+ * memcpy() on MIPS so it is not applicable either. We are therefore stuck
+ * with having to use our own loop.
+ */
+static void
+ltq_copy_from(struct map_info *map, void *to,
+ unsigned long from, ssize_t len)
+{
+ unsigned char *f = (unsigned char *)map->virt + from;
+ unsigned char *t = (unsigned char *)to;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ebu_lock, flags);
+ while (len--)
+ *t++ = *f++;
+ spin_unlock_irqrestore(&ebu_lock, flags);
+}
+
+static void
+ltq_copy_to(struct map_info *map, unsigned long to,
+ const void *from, ssize_t len)
+{
+ unsigned char *f = (unsigned char *)from;
+ unsigned char *t = (unsigned char *)map->virt + to;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ebu_lock, flags);
+ while (len--)
+ *t++ = *f++;
+ spin_unlock_irqrestore(&ebu_lock, flags);
+}
+
+static const char const *part_probe_types[] = { "cmdlinepart", NULL };
+
+static int __init
+ltq_mtd_probe(struct platform_device *pdev)
+{
+ struct physmap_flash_data *ltq_mtd_data = dev_get_platdata(&pdev->dev);
+ struct ltq_mtd *ltq_mtd;
+ struct mtd_partition *parts;
+ struct resource *res;
+ int nr_parts = 0;
+ struct cfi_private *cfi;
+ int err;
+
+ ltq_mtd = kzalloc(sizeof(struct ltq_mtd), GFP_KERNEL);
+ platform_set_drvdata(pdev, ltq_mtd);
+
+ ltq_mtd->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!ltq_mtd->res) {
+ dev_err(&pdev->dev, "failed to get memory resource");
+ err = -ENOENT;
+ goto err_out;
+ }
+
+ res = devm_request_mem_region(&pdev->dev, ltq_mtd->res->start,
+ resource_size(ltq_mtd->res), dev_name(&pdev->dev));
+ if (!ltq_mtd->res) {
+ dev_err(&pdev->dev, "failed to request mem resource");
+ err = -EBUSY;
+ goto err_out;
+ }
+
+ ltq_mtd->map = kzalloc(sizeof(struct map_info), GFP_KERNEL);
+ ltq_mtd->map->phys = res->start;
+ ltq_mtd->map->size = resource_size(res);
+ ltq_mtd->map->virt = devm_ioremap_nocache(&pdev->dev,
+ ltq_mtd->map->phys, ltq_mtd->map->size);
+ if (!ltq_mtd->map->virt) {
+ dev_err(&pdev->dev, "failed to ioremap!\n");
+ err = -ENOMEM;
+ goto err_free;
+ }
+
+ ltq_mtd->map->name = ltq_map_name;
+ ltq_mtd->map->bankwidth = 2;
+ ltq_mtd->map->read = ltq_read16;
+ ltq_mtd->map->write = ltq_write16;
+ ltq_mtd->map->copy_from = ltq_copy_from;
+ ltq_mtd->map->copy_to = ltq_copy_to;
+
+ ltq_mtd->map->map_priv_1 = LTQ_NOR_PROBING;
+ ltq_mtd->mtd = do_map_probe("cfi_probe", ltq_mtd->map);
+ ltq_mtd->map->map_priv_1 = LTQ_NOR_NORMAL;
+
+ if (!ltq_mtd->mtd) {
+ dev_err(&pdev->dev, "probing failed\n");
+ err = -ENXIO;
+ goto err_unmap;
+ }
+
+ ltq_mtd->mtd->owner = THIS_MODULE;
+
+ cfi = ltq_mtd->map->fldrv_priv;
+ cfi->addr_unlock1 ^= 1;
+ cfi->addr_unlock2 ^= 1;
+
+ nr_parts = parse_mtd_partitions(ltq_mtd->mtd,
+ part_probe_types, &parts, 0);
+ if (nr_parts > 0) {
+ dev_info(&pdev->dev,
+ "using %d partitions from cmdline", nr_parts);
+ } else {
+ nr_parts = ltq_mtd_data->nr_parts;
+ parts = ltq_mtd_data->parts;
+ }
+
+ err = add_mtd_partitions(ltq_mtd->mtd, parts, nr_parts);
+ if (err) {
+ dev_err(&pdev->dev, "failed to add partitions\n");
+ goto err_destroy;
+ }
+
+ return 0;
+
+err_destroy:
+ map_destroy(ltq_mtd->mtd);
+err_unmap:
+ iounmap(ltq_mtd->map->virt);
+err_free:
+ kfree(ltq_mtd->map);
+err_out:
+ kfree(ltq_mtd);
+ return err;
+}
+
+static int __devexit
+ltq_mtd_remove(struct platform_device *pdev)
+{
+ struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev);
+
+ if (ltq_mtd) {
+ if (ltq_mtd->mtd) {
+ del_mtd_partitions(ltq_mtd->mtd);
+ map_destroy(ltq_mtd->mtd);
+ }
+ if (ltq_mtd->map->virt)
+ iounmap(ltq_mtd->map->virt);
+ kfree(ltq_mtd->map);
+ kfree(ltq_mtd);
+ }
+ return 0;
+}
+
+static struct platform_driver ltq_mtd_driver = {
+ .remove = __devexit_p(ltq_mtd_remove),
+ .driver = {
+ .name = "ltq_nor",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init
+init_ltq_mtd(void)
+{
+ int ret = platform_driver_probe(&ltq_mtd_driver, ltq_mtd_probe);
+
+ if (ret)
+ pr_err("ltq_nor: error registering platform driver");
+ return ret;
+}
+
+static void __exit
+exit_ltq_mtd(void)
+{
+ platform_driver_unregister(&ltq_mtd_driver);
+}
+
+module_init(init_ltq_mtd);
+module_exit(exit_ltq_mtd);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_DESCRIPTION("Lantiq SoC NOR");
diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c
index 6799e75d74e0..33dc2829b01b 100644
--- a/drivers/mtd/maps/pcmciamtd.c
+++ b/drivers/mtd/maps/pcmciamtd.c
@@ -694,7 +694,7 @@ static int pcmciamtd_probe(struct pcmcia_device *link)
return pcmciamtd_config(link);
}
-static struct pcmcia_device_id pcmciamtd_ids[] = {
+static const struct pcmcia_device_id pcmciamtd_ids[] = {
PCMCIA_DEVICE_FUNC_ID(1),
PCMCIA_DEVICE_PROD_ID123("IO DATA", "PCS-2M", "2MB SRAM", 0x547e66dc, 0x1fed36cd, 0x36eadd21),
PCMCIA_DEVICE_PROD_ID12("IBM", "2MB SRAM", 0xb569a6e5, 0x36eadd21),
diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c
index 7522df4f71f1..1a9b94f0ee54 100644
--- a/drivers/mtd/maps/physmap.c
+++ b/drivers/mtd/maps/physmap.c
@@ -67,9 +67,25 @@ static int physmap_flash_remove(struct platform_device *dev)
if (info->mtd[i] != NULL)
map_destroy(info->mtd[i]);
}
+
+ if (physmap_data->exit)
+ physmap_data->exit(dev);
+
return 0;
}
+static void physmap_set_vpp(struct map_info *map, int state)
+{
+ struct platform_device *pdev;
+ struct physmap_flash_data *physmap_data;
+
+ pdev = (struct platform_device *)map->map_priv_1;
+ physmap_data = pdev->dev.platform_data;
+
+ if (physmap_data->set_vpp)
+ physmap_data->set_vpp(pdev, state);
+}
+
static const char *rom_probe_types[] = {
"cfi_probe",
"jedec_probe",
@@ -77,7 +93,8 @@ static const char *rom_probe_types[] = {
"map_rom",
NULL };
#ifdef CONFIG_MTD_PARTITIONS
-static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
+static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", "afs",
+ NULL };
#endif
static int physmap_flash_probe(struct platform_device *dev)
@@ -100,6 +117,12 @@ static int physmap_flash_probe(struct platform_device *dev)
goto err_out;
}
+ if (physmap_data->init) {
+ err = physmap_data->init(dev);
+ if (err)
+ goto err_out;
+ }
+
platform_set_drvdata(dev, info);
for (i = 0; i < dev->num_resources; i++) {
@@ -120,8 +143,9 @@ static int physmap_flash_probe(struct platform_device *dev)
info->map[i].phys = dev->resource[i].start;
info->map[i].size = resource_size(&dev->resource[i]);
info->map[i].bankwidth = physmap_data->width;
- info->map[i].set_vpp = physmap_data->set_vpp;
+ info->map[i].set_vpp = physmap_set_vpp;
info->map[i].pfow_base = physmap_data->pfow_base;
+ info->map[i].map_priv_1 = (unsigned long)dev;
info->map[i].virt = devm_ioremap(&dev->dev, info->map[i].phys,
info->map[i].size);
diff --git a/drivers/mtd/maps/pismo.c b/drivers/mtd/maps/pismo.c
index f4ce273e93fd..65bd1cd4d627 100644
--- a/drivers/mtd/maps/pismo.c
+++ b/drivers/mtd/maps/pismo.c
@@ -50,39 +50,13 @@ struct pismo_data {
struct platform_device *dev[PISMO_NUM_CS];
};
-/* FIXME: set_vpp could do with a better calling convention */
-static struct pismo_data *vpp_pismo;
-static DEFINE_MUTEX(pismo_mutex);
-
-static int pismo_setvpp_probe_fix(struct pismo_data *pismo)
+static void pismo_set_vpp(struct platform_device *pdev, int on)
{
- mutex_lock(&pismo_mutex);
- if (vpp_pismo) {
- mutex_unlock(&pismo_mutex);
- kfree(pismo);
- return -EBUSY;
- }
- vpp_pismo = pismo;
- mutex_unlock(&pismo_mutex);
- return 0;
-}
-
-static void pismo_setvpp_remove_fix(struct pismo_data *pismo)
-{
- mutex_lock(&pismo_mutex);
- if (vpp_pismo == pismo)
- vpp_pismo = NULL;
- mutex_unlock(&pismo_mutex);
-}
-
-static void pismo_set_vpp(struct map_info *map, int on)
-{
- struct pismo_data *pismo = vpp_pismo;
+ struct i2c_client *client = to_i2c_client(pdev->dev.parent);
+ struct pismo_data *pismo = i2c_get_clientdata(client);
pismo->vpp(pismo->vpp_data, on);
}
-/* end of hack */
-
static unsigned int __devinit pismo_width_to_bytes(unsigned int width)
{
@@ -231,9 +205,6 @@ static int __devexit pismo_remove(struct i2c_client *client)
for (i = 0; i < ARRAY_SIZE(pismo->dev); i++)
platform_device_unregister(pismo->dev[i]);
- /* FIXME: set_vpp needs saner arguments */
- pismo_setvpp_remove_fix(pismo);
-
kfree(pismo);
return 0;
@@ -257,11 +228,6 @@ static int __devinit pismo_probe(struct i2c_client *client,
if (!pismo)
return -ENOMEM;
- /* FIXME: set_vpp needs saner arguments */
- ret = pismo_setvpp_probe_fix(pismo);
- if (ret)
- return ret;
-
pismo->client = client;
if (pdata) {
pismo->vpp = pdata->set_vpp;
diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c
index 3ffe05db4923..5d513b54a7d7 100644
--- a/drivers/mtd/nand/au1550nd.c
+++ b/drivers/mtd/nand/au1550nd.c
@@ -10,6 +10,7 @@
*/
#include <linux/slab.h>
+#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
@@ -470,7 +471,7 @@ static int __init au1xxx_nand_init(void)
#ifdef CONFIG_MIPS_PB1550
/* set gpio206 high */
- au_writel(au_readl(GPIO2_DIR) & ~(1 << 6), GPIO2_DIR);
+ gpio_direction_input(206);
boot_swapboot = (au_readl(MEM_STSTAT) & (0x7 << 1)) | ((bcsr_read(BCSR_STATUS) >> 6) & 0x1);
diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c
index 14c578707824..c004e474631b 100644
--- a/drivers/mtd/nand/tmio_nand.c
+++ b/drivers/mtd/nand/tmio_nand.c
@@ -372,7 +372,7 @@ static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio)
static int tmio_probe(struct platform_device *dev)
{
- struct tmio_nand_data *data = mfd_get_data(dev);
+ struct tmio_nand_data *data = dev->dev.platform_data;
struct resource *fcr = platform_get_resource(dev,
IORESOURCE_MEM, 0);
struct resource *ccr = platform_get_resource(dev,
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index af9fb0ff8210..191f3bb3c41a 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -115,7 +115,7 @@ static int vol_cdev_open(struct inode *inode, struct file *file)
mode = UBI_READONLY;
dbg_gen("open device %d, volume %d, mode %d",
- ubi_num, vol_id, mode);
+ ubi_num, vol_id, mode);
desc = ubi_open_volume(ubi_num, vol_id, mode);
if (IS_ERR(desc))
@@ -158,7 +158,7 @@ static loff_t vol_cdev_llseek(struct file *file, loff_t offset, int origin)
loff_t new_offset;
if (vol->updating) {
- /* Update is in progress, seeking is prohibited */
+ /* Update is in progress, seeking is prohibited */
dbg_err("updating");
return -EBUSY;
}
@@ -561,18 +561,18 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
}
/* Set volume property command */
- case UBI_IOCSETPROP:
+ case UBI_IOCSETVOLPROP:
{
- struct ubi_set_prop_req req;
+ struct ubi_set_vol_prop_req req;
err = copy_from_user(&req, argp,
- sizeof(struct ubi_set_prop_req));
+ sizeof(struct ubi_set_vol_prop_req));
if (err) {
err = -EFAULT;
break;
}
switch (req.property) {
- case UBI_PROP_DIRECT_WRITE:
+ case UBI_VOL_PROP_DIRECT_WRITE:
mutex_lock(&ubi->device_mutex);
desc->vol->direct_writes = !!req.value;
mutex_unlock(&ubi->device_mutex);
@@ -1100,5 +1100,5 @@ const struct file_operations ubi_ctrl_cdev_operations = {
.owner = THIS_MODULE,
.unlocked_ioctl = ctrl_cdev_ioctl,
.compat_ioctl = ctrl_cdev_compat_ioctl,
- .llseek = noop_llseek,
+ .llseek = no_llseek,
};
diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
index d4d07e5f138f..2224cbe41ddf 100644
--- a/drivers/mtd/ubi/debug.c
+++ b/drivers/mtd/ubi/debug.c
@@ -30,15 +30,12 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-unsigned int ubi_msg_flags;
unsigned int ubi_chk_flags;
unsigned int ubi_tst_flags;
-module_param_named(debug_msgs, ubi_msg_flags, uint, S_IRUGO | S_IWUSR);
module_param_named(debug_chks, ubi_chk_flags, uint, S_IRUGO | S_IWUSR);
module_param_named(debug_tsts, ubi_chk_flags, uint, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug_msgs, "Debug message type flags");
MODULE_PARM_DESC(debug_chks, "Debug check flags");
MODULE_PARM_DESC(debug_tsts, "Debug special test flags");
@@ -75,15 +72,15 @@ void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr)
{
printk(KERN_DEBUG "Volume identifier header dump:\n");
printk(KERN_DEBUG "\tmagic %08x\n", be32_to_cpu(vid_hdr->magic));
- printk(KERN_DEBUG "\tversion %d\n", (int)vid_hdr->version);
- printk(KERN_DEBUG "\tvol_type %d\n", (int)vid_hdr->vol_type);
- printk(KERN_DEBUG "\tcopy_flag %d\n", (int)vid_hdr->copy_flag);
- printk(KERN_DEBUG "\tcompat %d\n", (int)vid_hdr->compat);
- printk(KERN_DEBUG "\tvol_id %d\n", be32_to_cpu(vid_hdr->vol_id));
- printk(KERN_DEBUG "\tlnum %d\n", be32_to_cpu(vid_hdr->lnum));
- printk(KERN_DEBUG "\tdata_size %d\n", be32_to_cpu(vid_hdr->data_size));
- printk(KERN_DEBUG "\tused_ebs %d\n", be32_to_cpu(vid_hdr->used_ebs));
- printk(KERN_DEBUG "\tdata_pad %d\n", be32_to_cpu(vid_hdr->data_pad));
+ printk(KERN_DEBUG "\tversion %d\n", (int)vid_hdr->version);
+ printk(KERN_DEBUG "\tvol_type %d\n", (int)vid_hdr->vol_type);
+ printk(KERN_DEBUG "\tcopy_flag %d\n", (int)vid_hdr->copy_flag);
+ printk(KERN_DEBUG "\tcompat %d\n", (int)vid_hdr->compat);
+ printk(KERN_DEBUG "\tvol_id %d\n", be32_to_cpu(vid_hdr->vol_id));
+ printk(KERN_DEBUG "\tlnum %d\n", be32_to_cpu(vid_hdr->lnum));
+ printk(KERN_DEBUG "\tdata_size %d\n", be32_to_cpu(vid_hdr->data_size));
+ printk(KERN_DEBUG "\tused_ebs %d\n", be32_to_cpu(vid_hdr->used_ebs));
+ printk(KERN_DEBUG "\tdata_pad %d\n", be32_to_cpu(vid_hdr->data_pad));
printk(KERN_DEBUG "\tsqnum %llu\n",
(unsigned long long)be64_to_cpu(vid_hdr->sqnum));
printk(KERN_DEBUG "\thdr_crc %08x\n", be32_to_cpu(vid_hdr->hdr_crc));
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index 0b0c2888c656..3f1a09c5c438 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -21,11 +21,17 @@
#ifndef __UBI_DEBUG_H__
#define __UBI_DEBUG_H__
+struct ubi_ec_hdr;
+struct ubi_vid_hdr;
+struct ubi_volume;
+struct ubi_vtbl_record;
+struct ubi_scan_volume;
+struct ubi_scan_leb;
+struct ubi_mkvol_req;
+
#ifdef CONFIG_MTD_UBI_DEBUG
#include <linux/random.h>
-#define dbg_err(fmt, ...) ubi_err(fmt, ##__VA_ARGS__)
-
#define ubi_assert(expr) do { \
if (unlikely(!(expr))) { \
printk(KERN_CRIT "UBI assert failed in %s at %u (pid %d)\n", \
@@ -34,24 +40,28 @@
} \
} while (0)
-#define dbg_msg(fmt, ...) \
- printk(KERN_DEBUG "UBI DBG (pid %d): %s: " fmt "\n", \
- current->pid, __func__, ##__VA_ARGS__)
-
-#define dbg_do_msg(typ, fmt, ...) do { \
- if (ubi_msg_flags & typ) \
- dbg_msg(fmt, ##__VA_ARGS__); \
-} while (0)
+#define dbg_err(fmt, ...) ubi_err(fmt, ##__VA_ARGS__)
#define ubi_dbg_dump_stack() dump_stack()
-struct ubi_ec_hdr;
-struct ubi_vid_hdr;
-struct ubi_volume;
-struct ubi_vtbl_record;
-struct ubi_scan_volume;
-struct ubi_scan_leb;
-struct ubi_mkvol_req;
+#define ubi_dbg_print_hex_dump(l, ps, pt, r, g, b, len, a) \
+ print_hex_dump(l, ps, pt, r, g, b, len, a)
+
+#define ubi_dbg_msg(type, fmt, ...) \
+ pr_debug("UBI DBG " type ": " fmt "\n", ##__VA_ARGS__)
+
+/* Just a debugging messages not related to any specific UBI subsystem */
+#define dbg_msg(fmt, ...) ubi_dbg_msg("msg", fmt, ##__VA_ARGS__)
+/* General debugging messages */
+#define dbg_gen(fmt, ...) ubi_dbg_msg("gen", fmt, ##__VA_ARGS__)
+/* Messages from the eraseblock association sub-system */
+#define dbg_eba(fmt, ...) ubi_dbg_msg("eba", fmt, ##__VA_ARGS__)
+/* Messages from the wear-leveling sub-system */
+#define dbg_wl(fmt, ...) ubi_dbg_msg("wl", fmt, ##__VA_ARGS__)
+/* Messages from the input/output sub-system */
+#define dbg_io(fmt, ...) ubi_dbg_msg("io", fmt, ##__VA_ARGS__)
+/* Initialization and build messages */
+#define dbg_bld(fmt, ...) ubi_dbg_msg("bld", fmt, ##__VA_ARGS__)
void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr);
void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr);
@@ -62,43 +72,6 @@ void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type);
void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req);
void ubi_dbg_dump_flash(struct ubi_device *ubi, int pnum, int offset, int len);
-extern unsigned int ubi_msg_flags;
-
-/*
- * Debugging message type flags (must match msg_type_names in debug.c).
- *
- * UBI_MSG_GEN: general messages
- * UBI_MSG_EBA: journal messages
- * UBI_MSG_WL: mount messages
- * UBI_MSG_IO: commit messages
- * UBI_MSG_BLD: LEB find messages
- */
-enum {
- UBI_MSG_GEN = 0x1,
- UBI_MSG_EBA = 0x2,
- UBI_MSG_WL = 0x4,
- UBI_MSG_IO = 0x8,
- UBI_MSG_BLD = 0x10,
-};
-
-#define ubi_dbg_print_hex_dump(l, ps, pt, r, g, b, len, a) \
- print_hex_dump(l, ps, pt, r, g, b, len, a)
-
-/* General debugging messages */
-#define dbg_gen(fmt, ...) dbg_do_msg(UBI_MSG_GEN, fmt, ##__VA_ARGS__)
-
-/* Messages from the eraseblock association sub-system */
-#define dbg_eba(fmt, ...) dbg_do_msg(UBI_MSG_EBA, fmt, ##__VA_ARGS__)
-
-/* Messages from the wear-leveling sub-system */
-#define dbg_wl(fmt, ...) dbg_do_msg(UBI_MSG_WL, fmt, ##__VA_ARGS__)
-
-/* Messages from the input/output sub-system */
-#define dbg_io(fmt, ...) dbg_do_msg(UBI_MSG_IO, fmt, ##__VA_ARGS__)
-
-/* Initialization and build messages */
-#define dbg_bld(fmt, ...) dbg_do_msg(UBI_MSG_BLD, fmt, ##__VA_ARGS__)
-
extern unsigned int ubi_chk_flags;
/*
@@ -184,31 +157,61 @@ static inline int ubi_dbg_is_erase_failure(void)
#else
-#define ubi_assert(expr) ({})
-#define dbg_err(fmt, ...) ({})
-#define dbg_msg(fmt, ...) ({})
-#define dbg_gen(fmt, ...) ({})
-#define dbg_eba(fmt, ...) ({})
-#define dbg_wl(fmt, ...) ({})
-#define dbg_io(fmt, ...) ({})
-#define dbg_bld(fmt, ...) ({})
-#define ubi_dbg_dump_stack() ({})
-#define ubi_dbg_dump_ec_hdr(ec_hdr) ({})
-#define ubi_dbg_dump_vid_hdr(vid_hdr) ({})
-#define ubi_dbg_dump_vol_info(vol) ({})
-#define ubi_dbg_dump_vtbl_record(r, idx) ({})
-#define ubi_dbg_dump_sv(sv) ({})
-#define ubi_dbg_dump_seb(seb, type) ({})
-#define ubi_dbg_dump_mkvol_req(req) ({})
-#define ubi_dbg_dump_flash(ubi, pnum, offset, len) ({})
-#define ubi_dbg_print_hex_dump(l, ps, pt, r, g, b, len, a) ({})
-
-#define ubi_dbg_is_bgt_disabled() 0
-#define ubi_dbg_is_bitflip() 0
-#define ubi_dbg_is_write_failure() 0
-#define ubi_dbg_is_erase_failure() 0
-#define ubi_dbg_check_all_ff(ubi, pnum, offset, len) 0
-#define ubi_dbg_check_write(ubi, buf, pnum, offset, len) 0
+/* Use "if (0)" to make compiler check arguments even if debugging is off */
+#define ubi_assert(expr) do { \
+ if (0) { \
+ printk(KERN_CRIT "UBI assert failed in %s at %u (pid %d)\n", \
+ __func__, __LINE__, current->pid); \
+ } \
+} while (0)
+
+#define dbg_err(fmt, ...) do { \
+ if (0) \
+ ubi_err(fmt, ##__VA_ARGS__); \
+} while (0)
+
+#define ubi_dbg_msg(fmt, ...) do { \
+ if (0) \
+ pr_debug(fmt "\n", ##__VA_ARGS__); \
+} while (0)
+
+#define dbg_msg(fmt, ...) ubi_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_gen(fmt, ...) ubi_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_eba(fmt, ...) ubi_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_wl(fmt, ...) ubi_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_io(fmt, ...) ubi_dbg_msg(fmt, ##__VA_ARGS__)
+#define dbg_bld(fmt, ...) ubi_dbg_msg(fmt, ##__VA_ARGS__)
+
+static inline void ubi_dbg_dump_stack(void) { return; }
+static inline void
+ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr) { return; }
+static inline void
+ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr) { return; }
+static inline void
+ubi_dbg_dump_vol_info(const struct ubi_volume *vol) { return; }
+static inline void
+ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx) { return; }
+static inline void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv) { return; }
+static inline void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb,
+ int type) { return; }
+static inline void
+ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req) { return; }
+static inline void ubi_dbg_dump_flash(struct ubi_device *ubi,
+ int pnum, int offset, int len) { return; }
+static inline void
+ubi_dbg_print_hex_dump(const char *l, const char *ps, int pt, int r,
+ int g, const void *b, size_t len, bool a) { return; }
+
+static inline int ubi_dbg_is_bgt_disabled(void) { return 0; }
+static inline int ubi_dbg_is_bitflip(void) { return 0; }
+static inline int ubi_dbg_is_write_failure(void) { return 0; }
+static inline int ubi_dbg_is_erase_failure(void) { return 0; }
+static inline int ubi_dbg_check_all_ff(struct ubi_device *ubi,
+ int pnum, int offset,
+ int len) { return 0; }
+static inline int ubi_dbg_check_write(struct ubi_device *ubi,
+ const void *buf, int pnum,
+ int offset, int len) { return 0; }
#endif /* !CONFIG_MTD_UBI_DEBUG */
#endif /* !__UBI_DEBUG_H__ */
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index e347cc4388ed..8c1b1c7bc4a7 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -189,8 +189,8 @@ retry:
}
if (retries++ < UBI_IO_RETRIES) {
- dbg_io("error %d%s while reading %d bytes from PEB %d:%d,"
- " read only %zd bytes, retry",
+ dbg_io("error %d%s while reading %d bytes from PEB "
+ "%d:%d, read only %zd bytes, retry",
err, errstr, len, pnum, offset, read);
yield();
goto retry;
@@ -465,7 +465,7 @@ static int torture_peb(struct ubi_device *ubi, int pnum)
}
err = patt_count;
- ubi_msg("PEB %d passed torture test, do not mark it a bad", pnum);
+ ubi_msg("PEB %d passed torture test, do not mark it as bad", pnum);
out:
mutex_unlock(&ubi->buf_mutex);
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
index d2d12ab7def4..2135a53732ff 100644
--- a/drivers/mtd/ubi/scan.c
+++ b/drivers/mtd/ubi/scan.c
@@ -1103,7 +1103,7 @@ static int check_what_we_have(struct ubi_device *ubi, struct ubi_scan_info *si)
* otherwise, only print a warning.
*/
if (si->corr_peb_count >= max_corr) {
- ubi_err("too many corrupted PEBs, refusing this device");
+ ubi_err("too many corrupted PEBs, refusing");
return -EINVAL;
}
}
diff --git a/drivers/mtd/ubi/ubi-media.h b/drivers/mtd/ubi/ubi-media.h
index 503ea9b27309..6fb8ec2174a5 100644
--- a/drivers/mtd/ubi/ubi-media.h
+++ b/drivers/mtd/ubi/ubi-media.h
@@ -164,7 +164,7 @@ struct ubi_ec_hdr {
__be32 image_seq;
__u8 padding2[32];
__be32 hdr_crc;
-} __attribute__ ((packed));
+} __packed;
/**
* struct ubi_vid_hdr - on-flash UBI volume identifier header.
@@ -292,7 +292,7 @@ struct ubi_vid_hdr {
__be64 sqnum;
__u8 padding3[12];
__be32 hdr_crc;
-} __attribute__ ((packed));
+} __packed;
/* Internal UBI volumes count */
#define UBI_INT_VOL_COUNT 1
@@ -373,6 +373,6 @@ struct ubi_vtbl_record {
__u8 flags;
__u8 padding[23];
__be32 crc;
-} __attribute__ ((packed));
+} __packed;
#endif /* !__UBI_MEDIA_H__ */
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index f1be8b79663c..c6c22295898e 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -341,8 +341,8 @@ struct ubi_wl_entry;
* protected from the wear-leveling worker)
* @pq_head: protection queue head
* @wl_lock: protects the @used, @free, @pq, @pq_head, @lookuptbl, @move_from,
- * @move_to, @move_to_put @erase_pending, @wl_scheduled, @works,
- * @erroneous, and @erroneous_peb_count fields
+ * @move_to, @move_to_put @erase_pending, @wl_scheduled, @works,
+ * @erroneous, and @erroneous_peb_count fields
* @move_mutex: serializes eraseblock moves
* @work_sem: synchronizes the WL worker with use tasks
* @wl_scheduled: non-zero if the wear-leveling was scheduled
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index b4cf57db2556..ff2c4956eeff 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -1570,7 +1570,8 @@ void ubi_wl_close(struct ubi_device *ubi)
* @ec: the erase counter to check
*
* This function returns zero if the erase counter of physical eraseblock @pnum
- * is equivalent to @ec, and a negative error code if not or if an error occurred.
+ * is equivalent to @ec, and a negative error code if not or if an error
+ * occurred.
*/
static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec)
{
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index 91abb965fb44..5f25889e27ef 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -185,7 +185,7 @@ static int max_interrupt_work = 10;
static int nopnp;
#endif
-static int __devinit el3_common_init(struct net_device *dev);
+static int el3_common_init(struct net_device *dev);
static void el3_common_remove(struct net_device *dev);
static ushort id_read_eeprom(int index);
static ushort read_eeprom(int ioaddr, int index);
@@ -395,7 +395,7 @@ static struct isa_driver el3_isa_driver = {
static int isa_registered;
#ifdef CONFIG_PNP
-static struct pnp_device_id el3_pnp_ids[] = {
+static const struct pnp_device_id el3_pnp_ids[] __devinitconst = {
{ .id = "TCM5090" }, /* 3Com Etherlink III (TP) */
{ .id = "TCM5091" }, /* 3Com Etherlink III */
{ .id = "TCM5094" }, /* 3Com Etherlink III (combo) */
@@ -478,7 +478,7 @@ static int pnp_registered;
#endif /* CONFIG_PNP */
#ifdef CONFIG_EISA
-static struct eisa_device_id el3_eisa_ids[] = {
+static const struct eisa_device_id el3_eisa_ids[] __devinitconst = {
{ "TCM5090" },
{ "TCM5091" },
{ "TCM5092" },
@@ -508,7 +508,7 @@ static int eisa_registered;
#ifdef CONFIG_MCA
static int el3_mca_probe(struct device *dev);
-static short el3_mca_adapter_ids[] __initdata = {
+static const short el3_mca_adapter_ids[] __devinitconst = {
0x627c,
0x627d,
0x62db,
@@ -517,7 +517,7 @@ static short el3_mca_adapter_ids[] __initdata = {
0x0000
};
-static char *el3_mca_adapter_names[] __initdata = {
+static const char *const el3_mca_adapter_names[] __devinitconst = {
"3Com 3c529 EtherLink III (10base2)",
"3Com 3c529 EtherLink III (10baseT)",
"3Com 3c529 EtherLink III (test mode)",
@@ -601,7 +601,7 @@ static void el3_common_remove (struct net_device *dev)
}
#ifdef CONFIG_MCA
-static int __init el3_mca_probe(struct device *device)
+static int __devinit el3_mca_probe(struct device *device)
{
/* Based on Erik Nygren's (nygren@mit.edu) 3c529 patch,
* heavily modified by Chris Beauregard
@@ -671,7 +671,7 @@ static int __init el3_mca_probe(struct device *device)
#endif /* CONFIG_MCA */
#ifdef CONFIG_EISA
-static int __init el3_eisa_probe (struct device *device)
+static int __devinit el3_eisa_probe (struct device *device)
{
short i;
int ioaddr, irq, if_port;
@@ -1207,7 +1207,7 @@ el3_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
ecmd->duplex = DUPLEX_FULL;
}
- ecmd->speed = SPEED_10;
+ ethtool_cmd_speed_set(ecmd, SPEED_10);
EL3WINDOW(1);
return 0;
}
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 8cc22568ebd3..99f43d275442 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -901,14 +901,14 @@ static const struct dev_pm_ops vortex_pm_ops = {
#endif /* !CONFIG_PM */
#ifdef CONFIG_EISA
-static struct eisa_device_id vortex_eisa_ids[] = {
+static const struct eisa_device_id vortex_eisa_ids[] __devinitconst = {
{ "TCM5920", CH_3C592 },
{ "TCM5970", CH_3C597 },
{ "" }
};
MODULE_DEVICE_TABLE(eisa, vortex_eisa_ids);
-static int __init vortex_eisa_probe(struct device *device)
+static int __devinit vortex_eisa_probe(struct device *device)
{
void __iomem *ioaddr;
struct eisa_device *edev;
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index dd16e83933a2..10c45051caea 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -758,8 +758,7 @@ static netdev_tx_t cp_start_xmit (struct sk_buff *skb,
entry = cp->tx_head;
eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
- if (dev->features & NETIF_F_TSO)
- mss = skb_shinfo(skb)->gso_size;
+ mss = skb_shinfo(skb)->gso_size;
if (skb_shinfo(skb)->nr_frags == 0) {
struct cp_desc *txd = &cp->tx_ring[entry];
@@ -1416,32 +1415,23 @@ static void cp_set_msglevel(struct net_device *dev, u32 value)
cp->msg_enable = value;
}
-static u32 cp_get_rx_csum(struct net_device *dev)
+static int cp_set_features(struct net_device *dev, u32 features)
{
struct cp_private *cp = netdev_priv(dev);
- return (cpr16(CpCmd) & RxChkSum) ? 1 : 0;
-}
+ unsigned long flags;
-static int cp_set_rx_csum(struct net_device *dev, u32 data)
-{
- struct cp_private *cp = netdev_priv(dev);
- u16 cmd = cp->cpcmd, newcmd;
+ if (!((dev->features ^ features) & NETIF_F_RXCSUM))
+ return 0;
- newcmd = cmd;
+ spin_lock_irqsave(&cp->lock, flags);
- if (data)
- newcmd |= RxChkSum;
+ if (features & NETIF_F_RXCSUM)
+ cp->cpcmd |= RxChkSum;
else
- newcmd &= ~RxChkSum;
-
- if (newcmd != cmd) {
- unsigned long flags;
+ cp->cpcmd &= ~RxChkSum;
- spin_lock_irqsave(&cp->lock, flags);
- cp->cpcmd = newcmd;
- cpw16_f(CpCmd, newcmd);
- spin_unlock_irqrestore(&cp->lock, flags);
- }
+ cpw16_f(CpCmd, cp->cpcmd);
+ spin_unlock_irqrestore(&cp->lock, flags);
return 0;
}
@@ -1554,11 +1544,6 @@ static const struct ethtool_ops cp_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_msglevel = cp_get_msglevel,
.set_msglevel = cp_set_msglevel,
- .get_rx_csum = cp_get_rx_csum,
- .set_rx_csum = cp_set_rx_csum,
- .set_tx_csum = ethtool_op_set_tx_csum, /* local! */
- .set_sg = ethtool_op_set_sg,
- .set_tso = ethtool_op_set_tso,
.get_regs = cp_get_regs,
.get_wol = cp_get_wol,
.set_wol = cp_set_wol,
@@ -1831,6 +1816,7 @@ static const struct net_device_ops cp_netdev_ops = {
.ndo_do_ioctl = cp_ioctl,
.ndo_start_xmit = cp_start_xmit,
.ndo_tx_timeout = cp_tx_timeout,
+ .ndo_set_features = cp_set_features,
#if CP_VLAN_TAG_USED
.ndo_vlan_rx_register = cp_vlan_rx_register,
#endif
@@ -1934,6 +1920,9 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
cp->cpcmd = (pci_using_dac ? PCIDAC : 0) |
PCIMulRW | RxChkSum | CpRxOn | CpTxOn;
+ dev->features |= NETIF_F_RXCSUM;
+ dev->hw_features |= NETIF_F_RXCSUM;
+
regs = ioremap(pciaddr, CP_REGS_SIZE);
if (!regs) {
rc = -EIO;
@@ -1966,9 +1955,8 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (pci_using_dac)
dev->features |= NETIF_F_HIGHDMA;
-#if 0 /* disabled by default until verified */
- dev->features |= NETIF_F_TSO;
-#endif
+ /* disabled by default until verified */
+ dev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
dev->irq = pdev->irq;
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 6c884ef1b069..19f04a34783a 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2017,6 +2017,13 @@ config FTMAC100
from Faraday. It is used on Faraday A320, Andes AG101 and some
other ARM/NDS32 SoC's.
+config LANTIQ_ETOP
+ tristate "Lantiq SoC ETOP driver"
+ depends on SOC_TYPE_XWAY
+ help
+ Support for the MII0 inside the Lantiq SoC
+
+
source "drivers/net/fs_enet/Kconfig"
source "drivers/net/octeon/Kconfig"
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index e5a7375685ad..776a478e6296 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_ATL2) += atlx/
obj-$(CONFIG_ATL1E) += atl1e/
obj-$(CONFIG_ATL1C) += atl1c/
obj-$(CONFIG_GIANFAR) += gianfar_driver.o
+obj-$(CONFIG_PTP_1588_CLOCK_GIANFAR) += gianfar_ptp.o
obj-$(CONFIG_TEHUTI) += tehuti.o
obj-$(CONFIG_ENIC) += enic/
obj-$(CONFIG_JME) += jme.o
@@ -259,6 +260,7 @@ obj-$(CONFIG_MLX4_CORE) += mlx4/
obj-$(CONFIG_ENC28J60) += enc28j60.o
obj-$(CONFIG_ETHOC) += ethoc.o
obj-$(CONFIG_GRETH) += greth.o
+obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o
obj-$(CONFIG_XTENSA_XT2000_SONIC) += xtsonic.o
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index ee648fe5d96f..d7c1bfe4b6ec 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -68,6 +68,7 @@
#include <linux/sockios.h>
#include <linux/firmware.h>
#include <linux/slab.h>
+#include <linux/prefetch.h>
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
#include <linux/if_vlan.h>
@@ -2658,15 +2659,15 @@ static int ace_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
link = readl(&regs->GigLnkState);
if (link & LNK_1000MB)
- ecmd->speed = SPEED_1000;
+ ethtool_cmd_speed_set(ecmd, SPEED_1000);
else {
link = readl(&regs->FastLnkState);
if (link & LNK_100MB)
- ecmd->speed = SPEED_100;
+ ethtool_cmd_speed_set(ecmd, SPEED_100);
else if (link & LNK_10MB)
- ecmd->speed = SPEED_10;
+ ethtool_cmd_speed_set(ecmd, SPEED_10);
else
- ecmd->speed = 0;
+ ethtool_cmd_speed_set(ecmd, 0);
}
if (link & LNK_FULL_DUPLEX)
ecmd->duplex = DUPLEX_FULL;
@@ -2718,9 +2719,9 @@ static int ace_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
link |= LNK_TX_FLOW_CTL_Y;
if (ecmd->autoneg == AUTONEG_ENABLE)
link |= LNK_NEGOTIATE;
- if (ecmd->speed != speed) {
+ if (ethtool_cmd_speed(ecmd) != speed) {
link &= ~(LNK_1000MB | LNK_100MB | LNK_10MB);
- switch (speed) {
+ switch (ethtool_cmd_speed(ecmd)) {
case SPEED_1000:
link |= LNK_1000MB;
break;
diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c
index fbfb5b47c506..03e217a868d4 100644
--- a/drivers/net/arm/etherh.c
+++ b/drivers/net/arm/etherh.c
@@ -591,10 +591,11 @@ static void etherh_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i
static int etherh_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
cmd->supported = etherh_priv(dev)->supported;
- cmd->speed = SPEED_10;
+ ethtool_cmd_speed_set(cmd, SPEED_10);
cmd->duplex = DUPLEX_HALF;
cmd->port = dev->if_port == IF_PORT_10BASET ? PORT_TP : PORT_BNC;
- cmd->autoneg = dev->flags & IFF_AUTOMEDIA ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+ cmd->autoneg = (dev->flags & IFF_AUTOMEDIA ?
+ AUTONEG_ENABLE : AUTONEG_DISABLE);
return 0;
}
diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c
index 9eb9b98a7ae3..de51e8453c13 100644
--- a/drivers/net/arm/ixp4xx_eth.c
+++ b/drivers/net/arm/ixp4xx_eth.c
@@ -30,9 +30,12 @@
#include <linux/etherdevice.h>
#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/net_tstamp.h>
#include <linux/phy.h>
#include <linux/platform_device.h>
+#include <linux/ptp_classify.h>
#include <linux/slab.h>
+#include <mach/ixp46x_ts.h>
#include <mach/npe.h>
#include <mach/qmgr.h>
@@ -67,6 +70,10 @@
#define RXFREE_QUEUE(port_id) (NPE_ID(port_id) + 26)
#define TXDONE_QUEUE 31
+#define PTP_SLAVE_MODE 1
+#define PTP_MASTER_MODE 2
+#define PORT2CHANNEL(p) NPE_ID(p->id)
+
/* TX Control Registers */
#define TX_CNTRL0_TX_EN 0x01
#define TX_CNTRL0_HALFDUPLEX 0x02
@@ -171,6 +178,8 @@ struct port {
int id; /* logical port ID */
int speed, duplex;
u8 firmware[4];
+ int hwts_tx_en;
+ int hwts_rx_en;
};
/* NPE message structure */
@@ -246,6 +255,172 @@ static int ports_open;
static struct port *npe_port_tab[MAX_NPES];
static struct dma_pool *dma_pool;
+static struct sock_filter ptp_filter[] = {
+ PTP_FILTER
+};
+
+static int ixp_ptp_match(struct sk_buff *skb, u16 uid_hi, u32 uid_lo, u16 seqid)
+{
+ u8 *data = skb->data;
+ unsigned int offset;
+ u16 *hi, *id;
+ u32 lo;
+
+ if (sk_run_filter(skb, ptp_filter) != PTP_CLASS_V1_IPV4)
+ return 0;
+
+ offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN;
+
+ if (skb->len < offset + OFF_PTP_SEQUENCE_ID + sizeof(seqid))
+ return 0;
+
+ hi = (u16 *)(data + offset + OFF_PTP_SOURCE_UUID);
+ id = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID);
+
+ memcpy(&lo, &hi[1], sizeof(lo));
+
+ return (uid_hi == ntohs(*hi) &&
+ uid_lo == ntohl(lo) &&
+ seqid == ntohs(*id));
+}
+
+static void ixp_rx_timestamp(struct port *port, struct sk_buff *skb)
+{
+ struct skb_shared_hwtstamps *shhwtstamps;
+ struct ixp46x_ts_regs *regs;
+ u64 ns;
+ u32 ch, hi, lo, val;
+ u16 uid, seq;
+
+ if (!port->hwts_rx_en)
+ return;
+
+ ch = PORT2CHANNEL(port);
+
+ regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT;
+
+ val = __raw_readl(&regs->channel[ch].ch_event);
+
+ if (!(val & RX_SNAPSHOT_LOCKED))
+ return;
+
+ lo = __raw_readl(&regs->channel[ch].src_uuid_lo);
+ hi = __raw_readl(&regs->channel[ch].src_uuid_hi);
+
+ uid = hi & 0xffff;
+ seq = (hi >> 16) & 0xffff;
+
+ if (!ixp_ptp_match(skb, htons(uid), htonl(lo), htons(seq)))
+ goto out;
+
+ lo = __raw_readl(&regs->channel[ch].rx_snap_lo);
+ hi = __raw_readl(&regs->channel[ch].rx_snap_hi);
+ ns = ((u64) hi) << 32;
+ ns |= lo;
+ ns <<= TICKS_NS_SHIFT;
+
+ shhwtstamps = skb_hwtstamps(skb);
+ memset(shhwtstamps, 0, sizeof(*shhwtstamps));
+ shhwtstamps->hwtstamp = ns_to_ktime(ns);
+out:
+ __raw_writel(RX_SNAPSHOT_LOCKED, &regs->channel[ch].ch_event);
+}
+
+static void ixp_tx_timestamp(struct port *port, struct sk_buff *skb)
+{
+ struct skb_shared_hwtstamps shhwtstamps;
+ struct ixp46x_ts_regs *regs;
+ struct skb_shared_info *shtx;
+ u64 ns;
+ u32 ch, cnt, hi, lo, val;
+
+ shtx = skb_shinfo(skb);
+ if (unlikely(shtx->tx_flags & SKBTX_HW_TSTAMP && port->hwts_tx_en))
+ shtx->tx_flags |= SKBTX_IN_PROGRESS;
+ else
+ return;
+
+ ch = PORT2CHANNEL(port);
+
+ regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT;
+
+ /*
+ * This really stinks, but we have to poll for the Tx time stamp.
+ * Usually, the time stamp is ready after 4 to 6 microseconds.
+ */
+ for (cnt = 0; cnt < 100; cnt++) {
+ val = __raw_readl(&regs->channel[ch].ch_event);
+ if (val & TX_SNAPSHOT_LOCKED)
+ break;
+ udelay(1);
+ }
+ if (!(val & TX_SNAPSHOT_LOCKED)) {
+ shtx->tx_flags &= ~SKBTX_IN_PROGRESS;
+ return;
+ }
+
+ lo = __raw_readl(&regs->channel[ch].tx_snap_lo);
+ hi = __raw_readl(&regs->channel[ch].tx_snap_hi);
+ ns = ((u64) hi) << 32;
+ ns |= lo;
+ ns <<= TICKS_NS_SHIFT;
+
+ memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+ shhwtstamps.hwtstamp = ns_to_ktime(ns);
+ skb_tstamp_tx(skb, &shhwtstamps);
+
+ __raw_writel(TX_SNAPSHOT_LOCKED, &regs->channel[ch].ch_event);
+}
+
+static int hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+ struct hwtstamp_config cfg;
+ struct ixp46x_ts_regs *regs;
+ struct port *port = netdev_priv(netdev);
+ int ch;
+
+ if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
+ return -EFAULT;
+
+ if (cfg.flags) /* reserved for future extensions */
+ return -EINVAL;
+
+ ch = PORT2CHANNEL(port);
+ regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT;
+
+ switch (cfg.tx_type) {
+ case HWTSTAMP_TX_OFF:
+ port->hwts_tx_en = 0;
+ break;
+ case HWTSTAMP_TX_ON:
+ port->hwts_tx_en = 1;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ switch (cfg.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ port->hwts_rx_en = 0;
+ break;
+ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+ port->hwts_rx_en = PTP_SLAVE_MODE;
+ __raw_writel(0, &regs->channel[ch].ch_control);
+ break;
+ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+ port->hwts_rx_en = PTP_MASTER_MODE;
+ __raw_writel(MASTER_MODE, &regs->channel[ch].ch_control);
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ /* Clear out any old time stamps. */
+ __raw_writel(TX_SNAPSHOT_LOCKED | RX_SNAPSHOT_LOCKED,
+ &regs->channel[ch].ch_event);
+
+ return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
+}
static int ixp4xx_mdio_cmd(struct mii_bus *bus, int phy_id, int location,
int write, u16 cmd)
@@ -573,6 +748,7 @@ static int eth_poll(struct napi_struct *napi, int budget)
debug_pkt(dev, "eth_poll", skb->data, skb->len);
+ ixp_rx_timestamp(port, skb);
skb->protocol = eth_type_trans(skb, dev);
dev->stats.rx_packets++;
dev->stats.rx_bytes += skb->len;
@@ -679,14 +855,12 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
memcpy_swab32(mem, (u32 *)((int)skb->data & ~3), bytes / 4);
- dev_kfree_skb(skb);
#endif
phys = dma_map_single(&dev->dev, mem, bytes, DMA_TO_DEVICE);
if (dma_mapping_error(&dev->dev, phys)) {
-#ifdef __ARMEB__
dev_kfree_skb(skb);
-#else
+#ifndef __ARMEB__
kfree(mem);
#endif
dev->stats.tx_dropped++;
@@ -728,6 +902,13 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev)
#if DEBUG_TX
printk(KERN_DEBUG "%s: eth_xmit end\n", dev->name);
#endif
+
+ ixp_tx_timestamp(port, skb);
+ skb_tx_timestamp(skb);
+
+#ifndef __ARMEB__
+ dev_kfree_skb(skb);
+#endif
return NETDEV_TX_OK;
}
@@ -783,6 +964,9 @@ static int eth_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
if (!netif_running(dev))
return -EINVAL;
+ if (cpu_is_ixp46x() && cmd == SIOCSHWTSTAMP)
+ return hwtstamp_ioctl(dev, req, cmd);
+
return phy_mii_ioctl(port->phydev, req, cmd);
}
@@ -1171,6 +1355,11 @@ static int __devinit eth_init_one(struct platform_device *pdev)
char phy_id[MII_BUS_ID_SIZE + 3];
int err;
+ if (ptp_filter_init(ptp_filter, ARRAY_SIZE(ptp_filter))) {
+ pr_err("ixp4xx_eth: bad ptp filter\n");
+ return -EINVAL;
+ }
+
if (!(dev = alloc_etherdev(sizeof(struct port))))
return -ENOMEM;
diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c
index aa07657744c3..a7b0caa18179 100644
--- a/drivers/net/arm/ks8695net.c
+++ b/drivers/net/arm/ks8695net.c
@@ -891,15 +891,16 @@ ks8695_wan_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd)
cmd->advertising |= ADVERTISED_Pause;
cmd->autoneg = AUTONEG_ENABLE;
- cmd->speed = (ctrl & WMC_WSS) ? SPEED_100 : SPEED_10;
+ ethtool_cmd_speed_set(cmd,
+ (ctrl & WMC_WSS) ? SPEED_100 : SPEED_10);
cmd->duplex = (ctrl & WMC_WDS) ?
DUPLEX_FULL : DUPLEX_HALF;
} else {
/* auto-negotiation is disabled */
cmd->autoneg = AUTONEG_DISABLE;
- cmd->speed = (ctrl & WMC_WANF100) ?
- SPEED_100 : SPEED_10;
+ ethtool_cmd_speed_set(cmd, ((ctrl & WMC_WANF100) ?
+ SPEED_100 : SPEED_10));
cmd->duplex = (ctrl & WMC_WANFF) ?
DUPLEX_FULL : DUPLEX_HALF;
}
diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c
index ce0091eb06f5..1264d781b554 100644
--- a/drivers/net/atarilance.c
+++ b/drivers/net/atarilance.c
@@ -554,7 +554,7 @@ static unsigned long __init lance_probe1( struct net_device *dev,
memaddr == (unsigned short *)0xffe00000) {
/* PAMs card and Riebl on ST use level 5 autovector */
if (request_irq(IRQ_AUTO_5, lance_interrupt, IRQ_TYPE_PRIO,
- "PAM/Riebl-ST Ethernet", dev)) {
+ "PAM,Riebl-ST Ethernet", dev)) {
printk( "Lance: request for irq %d failed\n", IRQ_AUTO_5 );
return 0;
}
diff --git a/drivers/net/atl1c/atl1c_ethtool.c b/drivers/net/atl1c/atl1c_ethtool.c
index 7c521508313c..7be884d0aaf6 100644
--- a/drivers/net/atl1c/atl1c_ethtool.c
+++ b/drivers/net/atl1c/atl1c_ethtool.c
@@ -50,13 +50,13 @@ static int atl1c_get_settings(struct net_device *netdev,
ecmd->transceiver = XCVR_INTERNAL;
if (adapter->link_speed != SPEED_0) {
- ecmd->speed = adapter->link_speed;
+ ethtool_cmd_speed_set(ecmd, adapter->link_speed);
if (adapter->link_duplex == FULL_DUPLEX)
ecmd->duplex = DUPLEX_FULL;
else
ecmd->duplex = DUPLEX_HALF;
} else {
- ecmd->speed = -1;
+ ethtool_cmd_speed_set(ecmd, -1);
ecmd->duplex = -1;
}
@@ -77,7 +77,8 @@ static int atl1c_set_settings(struct net_device *netdev,
if (ecmd->autoneg == AUTONEG_ENABLE) {
autoneg_advertised = ADVERTISED_Autoneg;
} else {
- if (ecmd->speed == SPEED_1000) {
+ u32 speed = ethtool_cmd_speed(ecmd);
+ if (speed == SPEED_1000) {
if (ecmd->duplex != DUPLEX_FULL) {
if (netif_msg_link(adapter))
dev_warn(&adapter->pdev->dev,
@@ -86,7 +87,7 @@ static int atl1c_set_settings(struct net_device *netdev,
return -EINVAL;
}
autoneg_advertised = ADVERTISED_1000baseT_Full;
- } else if (ecmd->speed == SPEED_100) {
+ } else if (speed == SPEED_100) {
if (ecmd->duplex == DUPLEX_FULL)
autoneg_advertised = ADVERTISED_100baseT_Full;
else
@@ -113,11 +114,6 @@ static int atl1c_set_settings(struct net_device *netdev,
return 0;
}
-static u32 atl1c_get_tx_csum(struct net_device *netdev)
-{
- return (netdev->features & NETIF_F_HW_CSUM) != 0;
-}
-
static u32 atl1c_get_msglevel(struct net_device *netdev)
{
struct atl1c_adapter *adapter = netdev_priv(netdev);
@@ -307,9 +303,6 @@ static const struct ethtool_ops atl1c_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_eeprom_len = atl1c_get_eeprom_len,
.get_eeprom = atl1c_get_eeprom,
- .get_tx_csum = atl1c_get_tx_csum,
- .get_sg = ethtool_op_get_sg,
- .set_sg = ethtool_op_set_sg,
};
void atl1c_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c
index a6e1c36e48e6..1269ba5d6e56 100644
--- a/drivers/net/atl1c/atl1c_main.c
+++ b/drivers/net/atl1c/atl1c_main.c
@@ -480,6 +480,15 @@ static void atl1c_set_rxbufsize(struct atl1c_adapter *adapter,
adapter->rx_buffer_len = mtu > AT_RX_BUF_SIZE ?
roundup(mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN, 8) : AT_RX_BUF_SIZE;
}
+
+static u32 atl1c_fix_features(struct net_device *netdev, u32 features)
+{
+ if (netdev->mtu > MAX_TSO_FRAME_SIZE)
+ features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
+
+ return features;
+}
+
/*
* atl1c_change_mtu - Change the Maximum Transfer Unit
* @netdev: network interface device structure
@@ -506,14 +515,8 @@ 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);
+ netdev_update_features(netdev);
atl1c_up(adapter);
clear_bit(__AT_RESETTING, &adapter->flags);
if (adapter->hw.ctrl_flags & ATL1C_FPGA_VERSION) {
@@ -1088,10 +1091,8 @@ static void atl1c_configure_tx(struct atl1c_adapter *adapter)
u32 max_pay_load;
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;
AT_WRITE_REG(hw, REG_TX_TSO_OFFLOAD_THRESH,
(tx_offload_thresh >> 3) & TX_TSO_OFFLOAD_THRESH_MASK);
@@ -2536,6 +2537,7 @@ static int atl1c_suspend(struct device *dev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
static int atl1c_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
@@ -2562,6 +2564,7 @@ static int atl1c_resume(struct device *dev)
return 0;
}
+#endif
static void atl1c_shutdown(struct pci_dev *pdev)
{
@@ -2581,6 +2584,7 @@ static const struct net_device_ops atl1c_netdev_ops = {
.ndo_set_mac_address = atl1c_set_mac_addr,
.ndo_set_multicast_list = atl1c_set_multi,
.ndo_change_mtu = atl1c_change_mtu,
+ .ndo_fix_features = atl1c_fix_features,
.ndo_do_ioctl = atl1c_ioctl,
.ndo_tx_timeout = atl1c_tx_timeout,
.ndo_get_stats = atl1c_get_stats,
@@ -2601,12 +2605,13 @@ static int atl1c_init_netdev(struct net_device *netdev, struct pci_dev *pdev)
atl1c_set_ethtool_ops(netdev);
/* TODO: add when ready */
- netdev->features = NETIF_F_SG |
+ netdev->hw_features = NETIF_F_SG |
NETIF_F_HW_CSUM |
NETIF_F_HW_VLAN_TX |
- NETIF_F_HW_VLAN_RX |
NETIF_F_TSO |
NETIF_F_TSO6;
+ netdev->features = netdev->hw_features |
+ NETIF_F_HW_VLAN_RX;
return 0;
}
diff --git a/drivers/net/atl1e/atl1e_ethtool.c b/drivers/net/atl1e/atl1e_ethtool.c
index 1209297433b8..6269438d365f 100644
--- a/drivers/net/atl1e/atl1e_ethtool.c
+++ b/drivers/net/atl1e/atl1e_ethtool.c
@@ -51,13 +51,13 @@ static int atl1e_get_settings(struct net_device *netdev,
ecmd->transceiver = XCVR_INTERNAL;
if (adapter->link_speed != SPEED_0) {
- ecmd->speed = adapter->link_speed;
+ ethtool_cmd_speed_set(ecmd, adapter->link_speed);
if (adapter->link_duplex == FULL_DUPLEX)
ecmd->duplex = DUPLEX_FULL;
else
ecmd->duplex = DUPLEX_HALF;
} else {
- ecmd->speed = -1;
+ ethtool_cmd_speed_set(ecmd, -1);
ecmd->duplex = -1;
}
@@ -382,9 +382,6 @@ static const struct ethtool_ops atl1e_ethtool_ops = {
.get_eeprom_len = atl1e_get_eeprom_len,
.get_eeprom = atl1e_get_eeprom,
.set_eeprom = atl1e_set_eeprom,
- .set_tx_csum = ethtool_op_set_tx_hw_csum,
- .set_sg = ethtool_op_set_sg,
- .set_tso = ethtool_op_set_tso,
};
void atl1e_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c
index b0a71e2f28a9..86a912283134 100644
--- a/drivers/net/atl1e/atl1e_main.c
+++ b/drivers/net/atl1e/atl1e_main.c
@@ -691,10 +691,8 @@ static void atl1e_cal_ring_size(struct atl1e_adapter *adapter, u32 *ring_size)
static void atl1e_init_ring_resources(struct atl1e_adapter *adapter)
{
- struct atl1e_tx_ring *tx_ring = NULL;
struct atl1e_rx_ring *rx_ring = NULL;
- tx_ring = &adapter->tx_ring;
rx_ring = &adapter->rx_ring;
rx_ring->real_page_size = adapter->rx_ring.page_size
@@ -1927,11 +1925,7 @@ void atl1e_down(struct atl1e_adapter *adapter)
* reschedule our watchdog timer */
set_bit(__AT_DOWN, &adapter->flags);
-#ifdef NETIF_F_LLTX
netif_stop_queue(netdev);
-#else
- netif_tx_disable(netdev);
-#endif
/* reset MAC to disable all RX/TX */
atl1e_reset_hw(&adapter->hw);
@@ -2223,10 +2217,10 @@ static int atl1e_init_netdev(struct net_device *netdev, struct pci_dev *pdev)
netdev->watchdog_timeo = AT_TX_WATCHDOG;
atl1e_set_ethtool_ops(netdev);
- netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM |
- NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
- netdev->features |= NETIF_F_LLTX;
- netdev->features |= NETIF_F_TSO;
+ netdev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO |
+ NETIF_F_HW_VLAN_TX;
+ netdev->features = netdev->hw_features |
+ NETIF_F_HW_VLAN_RX | NETIF_F_LLTX;
return 0;
}
diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c
index 67f40b9c16ed..cd5789ff3726 100644
--- a/drivers/net/atlx/atl1.c
+++ b/drivers/net/atlx/atl1.c
@@ -83,8 +83,9 @@
#include "atl1.h"
#define ATLX_DRIVER_VERSION "2.1.3"
-MODULE_AUTHOR("Xiong Huang <xiong.huang@atheros.com>, \
-Chris Snook <csnook@redhat.com>, Jay Cliburn <jcliburn@gmail.com>");
+MODULE_AUTHOR("Xiong Huang <xiong.huang@atheros.com>, "
+ "Chris Snook <csnook@redhat.com>, "
+ "Jay Cliburn <jcliburn@gmail.com>");
MODULE_LICENSE("GPL");
MODULE_VERSION(ATLX_DRIVER_VERSION);
@@ -2074,9 +2075,6 @@ static void atl1_intr_tx(struct atl1_adapter *adapter)
cmb_tpd_next_to_clean = le16_to_cpu(adapter->cmb.cmb->tpd_cons_idx);
while (cmb_tpd_next_to_clean != sw_tpd_next_to_clean) {
- struct tx_packet_desc *tpd;
-
- tpd = ATL1_TPD_DESC(tpd_ring, sw_tpd_next_to_clean);
buffer_info = &tpd_ring->buffer_info[sw_tpd_next_to_clean];
if (buffer_info->dma) {
pci_unmap_page(adapter->pdev, buffer_info->dma,
@@ -2572,7 +2570,7 @@ static s32 atl1_up(struct atl1_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
int err;
- int irq_flags = IRQF_SAMPLE_RANDOM;
+ int irq_flags = 0;
/* hardware has been reset, we need to reload some things */
atlx_set_multi(netdev);
@@ -2986,6 +2984,11 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
netdev->features |= NETIF_F_SG;
netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
+ netdev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_TSO;
+
+ /* is this valid? see atl1_setup_mac_ctrl() */
+ netdev->features |= NETIF_F_RXCSUM;
+
/*
* patch for some L1 of old version,
* the final version of L1 may not need these
@@ -3229,13 +3232,13 @@ static int atl1_get_settings(struct net_device *netdev,
if (netif_carrier_ok(adapter->netdev)) {
u16 link_speed, link_duplex;
atl1_get_speed_and_duplex(hw, &link_speed, &link_duplex);
- ecmd->speed = link_speed;
+ ethtool_cmd_speed_set(ecmd, link_speed);
if (link_duplex == FULL_DUPLEX)
ecmd->duplex = DUPLEX_FULL;
else
ecmd->duplex = DUPLEX_HALF;
} else {
- ecmd->speed = -1;
+ ethtool_cmd_speed_set(ecmd, -1);
ecmd->duplex = -1;
}
if (hw->media_type == MEDIA_TYPE_AUTO_SENSOR ||
@@ -3266,7 +3269,8 @@ static int atl1_set_settings(struct net_device *netdev,
if (ecmd->autoneg == AUTONEG_ENABLE)
hw->media_type = MEDIA_TYPE_AUTO_SENSOR;
else {
- if (ecmd->speed == SPEED_1000) {
+ u32 speed = ethtool_cmd_speed(ecmd);
+ if (speed == SPEED_1000) {
if (ecmd->duplex != DUPLEX_FULL) {
if (netif_msg_link(adapter))
dev_warn(&adapter->pdev->dev,
@@ -3275,7 +3279,7 @@ static int atl1_set_settings(struct net_device *netdev,
goto exit_sset;
}
hw->media_type = MEDIA_TYPE_1000M_FULL;
- } else if (ecmd->speed == SPEED_100) {
+ } else if (speed == SPEED_100) {
if (ecmd->duplex == DUPLEX_FULL)
hw->media_type = MEDIA_TYPE_100M_FULL;
else
@@ -3595,12 +3599,6 @@ static int atl1_set_pauseparam(struct net_device *netdev,
return 0;
}
-/* FIXME: is this right? -- CHS */
-static u32 atl1_get_rx_csum(struct net_device *netdev)
-{
- return 1;
-}
-
static void atl1_get_strings(struct net_device *netdev, u32 stringset,
u8 *data)
{
@@ -3668,13 +3666,9 @@ static const struct ethtool_ops atl1_ethtool_ops = {
.set_ringparam = atl1_set_ringparam,
.get_pauseparam = atl1_get_pauseparam,
.set_pauseparam = atl1_set_pauseparam,
- .get_rx_csum = atl1_get_rx_csum,
- .set_tx_csum = ethtool_op_set_tx_hw_csum,
.get_link = ethtool_op_get_link,
- .set_sg = ethtool_op_set_sg,
.get_strings = atl1_get_strings,
.nway_reset = atl1_nway_reset,
.get_ethtool_stats = atl1_get_ethtool_stats,
.get_sset_count = atl1_get_sset_count,
- .set_tso = ethtool_op_set_tso,
};
diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c
index e3cbf45dc612..16249e9b6b95 100644
--- a/drivers/net/atlx/atl2.c
+++ b/drivers/net/atlx/atl2.c
@@ -1411,9 +1411,8 @@ static int __devinit atl2_probe(struct pci_dev *pdev,
err = -EIO;
-#ifdef NETIF_F_HW_VLAN_TX
+ netdev->hw_features = NETIF_F_SG;
netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
-#endif
/* Init PHY as early as possible due to power saving issue */
atl2_phy_init(&adapter->hw);
@@ -1770,13 +1769,13 @@ static int atl2_get_settings(struct net_device *netdev,
ecmd->transceiver = XCVR_INTERNAL;
if (adapter->link_speed != SPEED_0) {
- ecmd->speed = adapter->link_speed;
+ ethtool_cmd_speed_set(ecmd, adapter->link_speed);
if (adapter->link_duplex == FULL_DUPLEX)
ecmd->duplex = DUPLEX_FULL;
else
ecmd->duplex = DUPLEX_HALF;
} else {
- ecmd->speed = -1;
+ ethtool_cmd_speed_set(ecmd, -1);
ecmd->duplex = -1;
}
@@ -1840,11 +1839,6 @@ static int atl2_set_settings(struct net_device *netdev,
return 0;
}
-static u32 atl2_get_tx_csum(struct net_device *netdev)
-{
- return (netdev->features & NETIF_F_HW_CSUM) != 0;
-}
-
static u32 atl2_get_msglevel(struct net_device *netdev)
{
return 0;
@@ -2112,12 +2106,6 @@ static const struct ethtool_ops atl2_ethtool_ops = {
.get_eeprom_len = atl2_get_eeprom_len,
.get_eeprom = atl2_get_eeprom,
.set_eeprom = atl2_set_eeprom,
- .get_tx_csum = atl2_get_tx_csum,
- .get_sg = ethtool_op_get_sg,
- .set_sg = ethtool_op_set_sg,
-#ifdef NETIF_F_TSO
- .get_tso = ethtool_op_get_tso,
-#endif
};
static void atl2_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 2e2b76258ab4..a69331e06b8d 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -1807,8 +1807,8 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
if (bp->flags & B44_FLAG_ADV_100FULL)
cmd->advertising |= ADVERTISED_100baseT_Full;
cmd->advertising |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
- cmd->speed = (bp->flags & B44_FLAG_100_BASE_T) ?
- SPEED_100 : SPEED_10;
+ ethtool_cmd_speed_set(cmd, ((bp->flags & B44_FLAG_100_BASE_T) ?
+ SPEED_100 : SPEED_10));
cmd->duplex = (bp->flags & B44_FLAG_FULL_DUPLEX) ?
DUPLEX_FULL : DUPLEX_HALF;
cmd->port = 0;
@@ -1820,7 +1820,7 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
if (cmd->autoneg == AUTONEG_ENABLE)
cmd->advertising |= ADVERTISED_Autoneg;
if (!netif_running(dev)){
- cmd->speed = 0;
+ ethtool_cmd_speed_set(cmd, 0);
cmd->duplex = 0xff;
}
cmd->maxtxpkt = 0;
@@ -1831,6 +1831,7 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct b44 *bp = netdev_priv(dev);
+ u32 speed = ethtool_cmd_speed(cmd);
/* We do not support gigabit. */
if (cmd->autoneg == AUTONEG_ENABLE) {
@@ -1838,8 +1839,8 @@ static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
(ADVERTISED_1000baseT_Half |
ADVERTISED_1000baseT_Full))
return -EINVAL;
- } else if ((cmd->speed != SPEED_100 &&
- cmd->speed != SPEED_10) ||
+ } else if ((speed != SPEED_100 &&
+ speed != SPEED_10) ||
(cmd->duplex != DUPLEX_HALF &&
cmd->duplex != DUPLEX_FULL)) {
return -EINVAL;
@@ -1873,7 +1874,7 @@ static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
} else {
bp->flags |= B44_FLAG_FORCE_LINK;
bp->flags &= ~(B44_FLAG_100_BASE_T | B44_FLAG_FULL_DUPLEX);
- if (cmd->speed == SPEED_100)
+ if (speed == SPEED_100)
bp->flags |= B44_FLAG_100_BASE_T;
if (cmd->duplex == DUPLEX_FULL)
bp->flags |= B44_FLAG_FULL_DUPLEX;
diff --git a/drivers/net/bcm63xx_enet.c b/drivers/net/bcm63xx_enet.c
index c48104b08861..f1573d492e90 100644
--- a/drivers/net/bcm63xx_enet.c
+++ b/drivers/net/bcm63xx_enet.c
@@ -839,8 +839,8 @@ static int bcm_enet_open(struct net_device *dev)
if (ret)
goto out_phy_disconnect;
- ret = request_irq(priv->irq_rx, bcm_enet_isr_dma,
- IRQF_SAMPLE_RANDOM | IRQF_DISABLED, dev->name, dev);
+ ret = request_irq(priv->irq_rx, bcm_enet_isr_dma, IRQF_DISABLED,
+ dev->name, dev);
if (ret)
goto out_freeirq;
@@ -1346,7 +1346,8 @@ static int bcm_enet_get_settings(struct net_device *dev,
return phy_ethtool_gset(priv->phydev, cmd);
} else {
cmd->autoneg = 0;
- cmd->speed = (priv->force_speed_100) ? SPEED_100 : SPEED_10;
+ ethtool_cmd_speed_set(cmd, ((priv->force_speed_100)
+ ? SPEED_100 : SPEED_10));
cmd->duplex = (priv->force_duplex_full) ?
DUPLEX_FULL : DUPLEX_HALF;
cmd->supported = ADVERTISED_10baseT_Half |
diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h
index 2353eca32593..a7db870d1641 100644
--- a/drivers/net/benet/be.h
+++ b/drivers/net/benet/be.h
@@ -49,6 +49,7 @@
#define OC_DEVICE_ID1 0x700 /* Device Id for BE2 cards */
#define OC_DEVICE_ID2 0x710 /* Device Id for BE3 cards */
#define OC_DEVICE_ID3 0xe220 /* Device id for Lancer cards */
+#define OC_DEVICE_ID4 0xe228 /* Device id for VF in Lancer */
static inline char *nic_name(struct pci_dev *pdev)
{
@@ -58,6 +59,7 @@ static inline char *nic_name(struct pci_dev *pdev)
case OC_DEVICE_ID2:
return OC_NAME_BE;
case OC_DEVICE_ID3:
+ case OC_DEVICE_ID4:
return OC_NAME_LANCER;
case BE_DEVICE_ID2:
return BE3_NAME;
@@ -84,15 +86,14 @@ static inline char *nic_name(struct pci_dev *pdev)
#define MCC_CQ_LEN 256
#define MAX_RSS_QS 4 /* BE limit is 4 queues/port */
-#define BE_MAX_MSIX_VECTORS (MAX_RSS_QS + 1 + 1)/* RSS qs + 1 def Rx + Tx */
+#define MAX_RX_QS (MAX_RSS_QS + 1) /* RSS qs + 1 def Rx */
+#define BE_MAX_MSIX_VECTORS (MAX_RX_QS + 1)/* RX + TX */
#define BE_NAPI_WEIGHT 64
#define MAX_RX_POST BE_NAPI_WEIGHT /* Frags posted at a time */
#define RX_FRAGS_REFILL_WM (RX_Q_LEN - MAX_RX_POST)
#define FW_VER_LEN 32
-#define BE_MAX_VF 32
-
struct be_dma_mem {
void *va;
dma_addr_t dma;
@@ -245,6 +246,43 @@ struct be_rx_obj {
struct be_drv_stats {
u8 be_on_die_temperature;
+ u64 be_tx_events;
+ u64 eth_red_drops;
+ u64 rx_drops_no_pbuf;
+ u64 rx_drops_no_txpb;
+ u64 rx_drops_no_erx_descr;
+ u64 rx_drops_no_tpre_descr;
+ u64 rx_drops_too_many_frags;
+ u64 rx_drops_invalid_ring;
+ u64 forwarded_packets;
+ u64 rx_drops_mtu;
+ u64 rx_crc_errors;
+ u64 rx_alignment_symbol_errors;
+ u64 rx_pause_frames;
+ u64 rx_priority_pause_frames;
+ u64 rx_control_frames;
+ u64 rx_in_range_errors;
+ u64 rx_out_range_errors;
+ u64 rx_frame_too_long;
+ u64 rx_address_match_errors;
+ u64 rx_dropped_too_small;
+ u64 rx_dropped_too_short;
+ u64 rx_dropped_header_too_small;
+ u64 rx_dropped_tcp_length;
+ u64 rx_dropped_runt;
+ u64 rx_ip_checksum_errs;
+ u64 rx_tcp_checksum_errs;
+ u64 rx_udp_checksum_errs;
+ u64 rx_switched_unicast_packets;
+ u64 rx_switched_multicast_packets;
+ u64 rx_switched_broadcast_packets;
+ u64 tx_pauseframes;
+ u64 tx_priority_pauseframes;
+ u64 tx_controlframes;
+ u64 rxpp_fifo_overflow_drop;
+ u64 rx_input_fifo_overflow_drop;
+ u64 pmem_fifo_overflow_drop;
+ u64 jabber_events;
};
struct be_vf_cfg {
@@ -276,7 +314,7 @@ struct be_adapter {
spinlock_t mcc_cq_lock;
struct msix_entry msix_entries[BE_MAX_MSIX_VECTORS];
- bool msix_enabled;
+ u32 num_msix_vec;
bool isr_registered;
/* TX Rings */
@@ -287,7 +325,7 @@ struct be_adapter {
u32 cache_line_break[8];
/* Rx rings */
- struct be_rx_obj rx_obj[MAX_RSS_QS + 1]; /* one default non-rss Q */
+ struct be_rx_obj rx_obj[MAX_RX_QS];
u32 num_rx_qs;
u32 big_page_size; /* Compounded page size shared by rx wrbs */
@@ -308,10 +346,10 @@ struct be_adapter {
u16 work_counter;
/* Ethtool knobs and info */
- bool rx_csum; /* BE card must perform rx-checksumming */
char fw_ver[FW_VER_LEN];
u32 if_handle; /* Used to configure filtering */
u32 pmac_id; /* MAC addr handle used by BE card */
+ u32 beacon_state; /* for set_phys_id */
bool eeh_err;
bool link_up;
@@ -334,7 +372,7 @@ struct be_adapter {
bool be3_native;
bool sriov_enabled;
- struct be_vf_cfg vf_cfg[BE_MAX_VF];
+ struct be_vf_cfg *vf_cfg;
u8 is_virtfn;
u32 sli_family;
u8 hba_port_num;
@@ -347,10 +385,12 @@ struct be_adapter {
#define BE_GEN2 2
#define BE_GEN3 3
-#define lancer_chip(adapter) (adapter->pdev->device == OC_DEVICE_ID3)
+#define lancer_chip(adapter) ((adapter->pdev->device == OC_DEVICE_ID3) || \
+ (adapter->pdev->device == OC_DEVICE_ID4))
extern const struct ethtool_ops be_ethtool_ops;
+#define msix_enabled(adapter) (adapter->num_msix_vec > 0)
#define tx_stats(adapter) (&adapter->tx_stats)
#define rx_stats(rxo) (&rxo->stats)
@@ -455,18 +495,10 @@ static inline u8 is_udp_pkt(struct sk_buff *skb)
static inline void be_check_sriov_fn_type(struct be_adapter *adapter)
{
- u8 data;
u32 sli_intf;
- if (lancer_chip(adapter)) {
- pci_read_config_dword(adapter->pdev, SLI_INTF_REG_OFFSET,
- &sli_intf);
- adapter->is_virtfn = (sli_intf & SLI_INTF_FT_MASK) ? 1 : 0;
- } else {
- pci_write_config_byte(adapter->pdev, 0xFE, 0xAA);
- pci_read_config_byte(adapter->pdev, 0xFE, &data);
- adapter->is_virtfn = (data != 0xAA);
- }
+ pci_read_config_dword(adapter->pdev, SLI_INTF_REG_OFFSET, &sli_intf);
+ adapter->is_virtfn = (sli_intf & SLI_INTF_FT_MASK) ? 1 : 0;
}
static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac)
@@ -482,9 +514,15 @@ static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac)
memcpy(mac, adapter->netdev->dev_addr, 3);
}
+static inline bool be_multi_rxq(const struct be_adapter *adapter)
+{
+ return adapter->num_rx_qs > 1;
+}
+
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);
extern void netdev_stats_update(struct be_adapter *adapter);
+extern void be_parse_stats(struct be_adapter *adapter);
extern int be_load_fw(struct be_adapter *adapter, u8 *func);
#endif /* BE_H */
diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c
index 9dc9394fd4ca..81654ae16c63 100644
--- a/drivers/net/benet/be_cmds.c
+++ b/drivers/net/benet/be_cmds.c
@@ -71,18 +71,38 @@ static int be_mcc_compl_process(struct be_adapter *adapter,
compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) &
CQE_STATUS_COMPL_MASK;
- if ((compl->tag0 == OPCODE_COMMON_WRITE_FLASHROM) &&
+ if (((compl->tag0 == OPCODE_COMMON_WRITE_FLASHROM) ||
+ (compl->tag0 == OPCODE_COMMON_WRITE_OBJECT)) &&
(compl->tag1 == CMD_SUBSYSTEM_COMMON)) {
adapter->flash_status = compl_status;
complete(&adapter->flash_compl);
}
if (compl_status == MCC_STATUS_SUCCESS) {
- if (compl->tag0 == OPCODE_ETH_GET_STATISTICS) {
- struct be_cmd_resp_get_stats *resp =
- adapter->stats_cmd.va;
- be_dws_le_to_cpu(&resp->hw_stats,
- sizeof(resp->hw_stats));
+ if (((compl->tag0 == OPCODE_ETH_GET_STATISTICS) ||
+ (compl->tag0 == OPCODE_ETH_GET_PPORT_STATS)) &&
+ (compl->tag1 == CMD_SUBSYSTEM_ETH)) {
+ if (adapter->generation == BE_GEN3) {
+ if (lancer_chip(adapter)) {
+ struct lancer_cmd_resp_pport_stats
+ *resp = adapter->stats_cmd.va;
+ be_dws_le_to_cpu(&resp->pport_stats,
+ sizeof(resp->pport_stats));
+ } else {
+ struct be_cmd_resp_get_stats_v1 *resp =
+ adapter->stats_cmd.va;
+
+ be_dws_le_to_cpu(&resp->hw_stats,
+ sizeof(resp->hw_stats));
+ }
+ } else {
+ struct be_cmd_resp_get_stats_v0 *resp =
+ adapter->stats_cmd.va;
+
+ be_dws_le_to_cpu(&resp->hw_stats,
+ sizeof(resp->hw_stats));
+ }
+ be_parse_stats(adapter);
netdev_stats_update(adapter);
adapter->stats_cmd_sent = false;
}
@@ -292,12 +312,12 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db)
if (msecs > 4000) {
dev_err(&adapter->pdev->dev, "mbox poll timed out\n");
- be_detect_dump_ue(adapter);
+ if (!lancer_chip(adapter))
+ be_detect_dump_ue(adapter);
return -1;
}
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(msecs_to_jiffies(1));
+ msleep(1);
msecs++;
} while (true);
@@ -374,23 +394,25 @@ int be_cmd_POST(struct be_adapter *adapter)
{
u16 stage;
int status, timeout = 0;
+ struct device *dev = &adapter->pdev->dev;
do {
status = be_POST_stage_get(adapter, &stage);
if (status) {
- dev_err(&adapter->pdev->dev, "POST error; stage=0x%x\n",
- stage);
+ dev_err(dev, "POST error; stage=0x%x\n", stage);
return -1;
} else if (stage != POST_STAGE_ARMFW_RDY) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(2 * HZ);
+ if (msleep_interruptible(2000)) {
+ dev_err(dev, "Waiting for POST aborted\n");
+ return -EINTR;
+ }
timeout += 2;
} else {
return 0;
}
} while (timeout < 40);
- dev_err(&adapter->pdev->dev, "POST timeout; stage=0x%x\n", stage);
+ dev_err(dev, "POST timeout; stage=0x%x\n", stage);
return -1;
}
@@ -728,8 +750,6 @@ int be_cmd_cq_create(struct be_adapter *adapter,
if (lancer_chip(adapter)) {
req->hdr.version = 2;
req->page_size = 1; /* 1 for 4K */
- AMAP_SET_BITS(struct amap_cq_context_lancer, coalescwm, ctxt,
- coalesce_wm);
AMAP_SET_BITS(struct amap_cq_context_lancer, nodelay, ctxt,
no_delay);
AMAP_SET_BITS(struct amap_cq_context_lancer, count, ctxt,
@@ -1074,7 +1094,7 @@ int be_cmd_if_destroy(struct be_adapter *adapter, u32 interface_id, u32 domain)
int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd)
{
struct be_mcc_wrb *wrb;
- struct be_cmd_req_get_stats *req;
+ struct be_cmd_req_hdr *hdr;
struct be_sge *sge;
int status = 0;
@@ -1088,14 +1108,62 @@ int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd)
status = -EBUSY;
goto err;
}
- req = nonemb_cmd->va;
+ hdr = nonemb_cmd->va;
sge = nonembedded_sgl(wrb);
- be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1,
+ be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, 1,
OPCODE_ETH_GET_STATISTICS);
+ be_cmd_hdr_prepare(hdr, CMD_SUBSYSTEM_ETH,
+ OPCODE_ETH_GET_STATISTICS, nonemb_cmd->size);
+
+ if (adapter->generation == BE_GEN3)
+ hdr->version = 1;
+
+ wrb->tag1 = CMD_SUBSYSTEM_ETH;
+ 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(adapter);
+ adapter->stats_cmd_sent = true;
+
+err:
+ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
+}
+
+/* Lancer Stats */
+int lancer_cmd_get_pport_stats(struct be_adapter *adapter,
+ struct be_dma_mem *nonemb_cmd)
+{
+
+ struct be_mcc_wrb *wrb;
+ struct lancer_cmd_req_pport_stats *req;
+ struct be_sge *sge;
+ int status = 0;
+
+ spin_lock_bh(&adapter->mcc_lock);
+
+ wrb = wrb_from_mccq(adapter);
+ if (!wrb) {
+ status = -EBUSY;
+ goto err;
+ }
+ req = nonemb_cmd->va;
+ sge = nonembedded_sgl(wrb);
+
+ be_wrb_hdr_prepare(wrb, nonemb_cmd->size, false, 1,
+ OPCODE_ETH_GET_PPORT_STATS);
+
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
- OPCODE_ETH_GET_STATISTICS, sizeof(*req));
+ OPCODE_ETH_GET_PPORT_STATS, nonemb_cmd->size);
+
+
+ req->cmd_params.params.pport_num = cpu_to_le16(adapter->port_num);
+ req->cmd_params.params.reset_stats = 0;
+
+ wrb->tag1 = CMD_SUBSYSTEM_ETH;
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);
@@ -1110,7 +1178,7 @@ err:
/* Uses synchronous mcc */
int be_cmd_link_status_query(struct be_adapter *adapter,
- bool *link_up, u8 *mac_speed, u16 *link_speed)
+ bool *link_up, u8 *mac_speed, u16 *link_speed, u32 dom)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_link_status *req;
@@ -1186,6 +1254,116 @@ err:
return status;
}
+/* Uses synchronous mcc */
+int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size)
+{
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_get_fat *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_MANAGE_FAT);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_MANAGE_FAT, sizeof(*req));
+ req->fat_operation = cpu_to_le32(QUERY_FAT);
+ status = be_mcc_notify_wait(adapter);
+ if (!status) {
+ struct be_cmd_resp_get_fat *resp = embedded_payload(wrb);
+ if (log_size && resp->log_size)
+ *log_size = le32_to_cpu(resp->log_size) -
+ sizeof(u32);
+ }
+err:
+ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
+}
+
+void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf)
+{
+ struct be_dma_mem get_fat_cmd;
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_get_fat *req;
+ struct be_sge *sge;
+ u32 offset = 0, total_size, buf_size,
+ log_offset = sizeof(u32), payload_len;
+ int status;
+
+ if (buf_len == 0)
+ return;
+
+ total_size = buf_len;
+
+ get_fat_cmd.size = sizeof(struct be_cmd_req_get_fat) + 60*1024;
+ get_fat_cmd.va = pci_alloc_consistent(adapter->pdev,
+ get_fat_cmd.size,
+ &get_fat_cmd.dma);
+ if (!get_fat_cmd.va) {
+ status = -ENOMEM;
+ dev_err(&adapter->pdev->dev,
+ "Memory allocation failure while retrieving FAT data\n");
+ return;
+ }
+
+ spin_lock_bh(&adapter->mcc_lock);
+
+ while (total_size) {
+ buf_size = min(total_size, (u32)60*1024);
+ total_size -= buf_size;
+
+ wrb = wrb_from_mccq(adapter);
+ if (!wrb) {
+ status = -EBUSY;
+ goto err;
+ }
+ req = get_fat_cmd.va;
+ sge = nonembedded_sgl(wrb);
+
+ payload_len = sizeof(struct be_cmd_req_get_fat) + buf_size;
+ be_wrb_hdr_prepare(wrb, payload_len, false, 1,
+ OPCODE_COMMON_MANAGE_FAT);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_MANAGE_FAT, payload_len);
+
+ sge->pa_hi = cpu_to_le32(upper_32_bits(get_fat_cmd.dma));
+ sge->pa_lo = cpu_to_le32(get_fat_cmd.dma & 0xFFFFFFFF);
+ sge->len = cpu_to_le32(get_fat_cmd.size);
+
+ req->fat_operation = cpu_to_le32(RETRIEVE_FAT);
+ req->read_log_offset = cpu_to_le32(log_offset);
+ req->read_log_length = cpu_to_le32(buf_size);
+ req->data_buffer_size = cpu_to_le32(buf_size);
+
+ status = be_mcc_notify_wait(adapter);
+ if (!status) {
+ struct be_cmd_resp_get_fat *resp = get_fat_cmd.va;
+ memcpy(buf + offset,
+ resp->data_buffer,
+ resp->read_log_length);
+ } else {
+ dev_err(&adapter->pdev->dev, "FAT Table Retrieve error\n");
+ goto err;
+ }
+ offset += buf_size;
+ log_offset += buf_size;
+ }
+err:
+ pci_free_consistent(adapter->pdev, get_fat_cmd.size,
+ get_fat_cmd.va,
+ get_fat_cmd.dma);
+ spin_unlock_bh(&adapter->mcc_lock);
+}
+
/* Uses Mbox */
int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver)
{
@@ -1293,12 +1471,24 @@ err:
/* Uses MCC for this command as it may be called in BH context
* Uses synchronous mcc
*/
-int be_cmd_promiscuous_config(struct be_adapter *adapter, u8 port_num, bool en)
+int be_cmd_promiscuous_config(struct be_adapter *adapter, bool en)
{
struct be_mcc_wrb *wrb;
- struct be_cmd_req_promiscuous_config *req;
+ struct be_cmd_req_rx_filter *req;
+ struct be_dma_mem promiscous_cmd;
+ struct be_sge *sge;
int status;
+ memset(&promiscous_cmd, 0, sizeof(struct be_dma_mem));
+ promiscous_cmd.size = sizeof(struct be_cmd_req_rx_filter);
+ promiscous_cmd.va = pci_alloc_consistent(adapter->pdev,
+ promiscous_cmd.size, &promiscous_cmd.dma);
+ if (!promiscous_cmd.va) {
+ dev_err(&adapter->pdev->dev,
+ "Memory allocation failure\n");
+ return -ENOMEM;
+ }
+
spin_lock_bh(&adapter->mcc_lock);
wrb = wrb_from_mccq(adapter);
@@ -1306,26 +1496,30 @@ int be_cmd_promiscuous_config(struct be_adapter *adapter, u8 port_num, bool en)
status = -EBUSY;
goto err;
}
- req = embedded_payload(wrb);
- be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, OPCODE_ETH_PROMISCUOUS);
+ req = promiscous_cmd.va;
+ sge = nonembedded_sgl(wrb);
- be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
- OPCODE_ETH_PROMISCUOUS, sizeof(*req));
-
- /* In FW versions X.102.149/X.101.487 and later,
- * the port setting associated only with the
- * issuing pci function will take effect
- */
- if (port_num)
- req->port1_promiscuous = en;
- else
- req->port0_promiscuous = en;
+ be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1,
+ OPCODE_COMMON_NTWK_RX_FILTER);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_NTWK_RX_FILTER, sizeof(*req));
+
+ req->if_id = cpu_to_le32(adapter->if_handle);
+ req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS);
+ if (en)
+ req->if_flags = cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS);
+
+ sge->pa_hi = cpu_to_le32(upper_32_bits(promiscous_cmd.dma));
+ sge->pa_lo = cpu_to_le32(promiscous_cmd.dma & 0xFFFFFFFF);
+ sge->len = cpu_to_le32(promiscous_cmd.size);
status = be_mcc_notify_wait(adapter);
err:
spin_unlock_bh(&adapter->mcc_lock);
+ pci_free_consistent(adapter->pdev, promiscous_cmd.size,
+ promiscous_cmd.va, promiscous_cmd.dma);
return status;
}
@@ -1509,7 +1703,8 @@ int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, u16 table_size)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_rss_config *req;
- u32 myhash[10];
+ u32 myhash[10] = {0x0123, 0x4567, 0x89AB, 0xCDEF, 0x01EF,
+ 0x0123, 0x4567, 0x89AB, 0xCDEF, 0x01EF};
int status;
if (mutex_lock_interruptible(&adapter->mbox_lock))
@@ -1608,6 +1803,81 @@ err:
return status;
}
+int lancer_cmd_write_object(struct be_adapter *adapter, struct be_dma_mem *cmd,
+ u32 data_size, u32 data_offset, const char *obj_name,
+ u32 *data_written, u8 *addn_status)
+{
+ struct be_mcc_wrb *wrb;
+ struct lancer_cmd_req_write_object *req;
+ struct lancer_cmd_resp_write_object *resp;
+ void *ctxt = NULL;
+ int status;
+
+ spin_lock_bh(&adapter->mcc_lock);
+ adapter->flash_status = 0;
+
+ wrb = wrb_from_mccq(adapter);
+ if (!wrb) {
+ status = -EBUSY;
+ goto err_unlock;
+ }
+
+ req = embedded_payload(wrb);
+
+ be_wrb_hdr_prepare(wrb, sizeof(struct lancer_cmd_req_write_object),
+ true, 1, OPCODE_COMMON_WRITE_OBJECT);
+ wrb->tag1 = CMD_SUBSYSTEM_COMMON;
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_WRITE_OBJECT,
+ sizeof(struct lancer_cmd_req_write_object));
+
+ ctxt = &req->context;
+ AMAP_SET_BITS(struct amap_lancer_write_obj_context,
+ write_length, ctxt, data_size);
+
+ if (data_size == 0)
+ AMAP_SET_BITS(struct amap_lancer_write_obj_context,
+ eof, ctxt, 1);
+ else
+ AMAP_SET_BITS(struct amap_lancer_write_obj_context,
+ eof, ctxt, 0);
+
+ be_dws_cpu_to_le(ctxt, sizeof(req->context));
+ req->write_offset = cpu_to_le32(data_offset);
+ strcpy(req->object_name, obj_name);
+ req->descriptor_count = cpu_to_le32(1);
+ req->buf_len = cpu_to_le32(data_size);
+ req->addr_low = cpu_to_le32((cmd->dma +
+ sizeof(struct lancer_cmd_req_write_object))
+ & 0xFFFFFFFF);
+ req->addr_high = cpu_to_le32(upper_32_bits(cmd->dma +
+ sizeof(struct lancer_cmd_req_write_object)));
+
+ be_mcc_notify(adapter);
+ spin_unlock_bh(&adapter->mcc_lock);
+
+ if (!wait_for_completion_timeout(&adapter->flash_compl,
+ msecs_to_jiffies(12000)))
+ status = -1;
+ else
+ status = adapter->flash_status;
+
+ resp = embedded_payload(wrb);
+ if (!status) {
+ *data_written = le32_to_cpu(resp->actual_write_len);
+ } else {
+ *addn_status = resp->additional_status;
+ status = resp->status;
+ }
+
+ return status;
+
+err_unlock:
+ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
+}
+
int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
u32 flash_type, u32 flash_opcode, u32 buf_size)
{
diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h
index 4f254cfaabe2..8148cc66cbe9 100644
--- a/drivers/net/benet/be_cmds.h
+++ b/drivers/net/benet/be_cmds.h
@@ -186,12 +186,14 @@ struct be_mcc_mailbox {
#define OPCODE_COMMON_NTWK_PMAC_ADD 59
#define OPCODE_COMMON_NTWK_PMAC_DEL 60
#define OPCODE_COMMON_FUNCTION_RESET 61
+#define OPCODE_COMMON_MANAGE_FAT 68
#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_COMMON_SET_DRIVER_FUNCTION_CAP 103
#define OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES 121
+#define OPCODE_COMMON_WRITE_OBJECT 172
#define OPCODE_ETH_RSS_CONFIG 1
#define OPCODE_ETH_ACPI_CONFIG 2
@@ -202,6 +204,7 @@ struct be_mcc_mailbox {
#define OPCODE_ETH_TX_DESTROY 9
#define OPCODE_ETH_RX_DESTROY 10
#define OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG 12
+#define OPCODE_ETH_GET_PPORT_STATS 18
#define OPCODE_LOWLEVEL_HOST_DDR_DMA 17
#define OPCODE_LOWLEVEL_LOOPBACK_TEST 18
@@ -380,6 +383,24 @@ struct be_cmd_resp_cq_create {
u16 rsvd0;
} __packed;
+struct be_cmd_req_get_fat {
+ struct be_cmd_req_hdr hdr;
+ u32 fat_operation;
+ u32 read_log_offset;
+ u32 read_log_length;
+ u32 data_buffer_size;
+ u32 data_buffer[1];
+} __packed;
+
+struct be_cmd_resp_get_fat {
+ struct be_cmd_resp_hdr hdr;
+ u32 log_size;
+ u32 read_log_length;
+ u32 rsvd[2];
+ u32 data_buffer[1];
+} __packed;
+
+
/******************** Create MCCQ ***************************/
/* Pseudo amap definition in which each bit of the actual structure is defined
* as a byte: used to calculate offset/shift/mask of each field */
@@ -549,7 +570,7 @@ struct be_cmd_req_if_destroy {
};
/*************** HW Stats Get **********************************/
-struct be_port_rxf_stats {
+struct be_port_rxf_stats_v0 {
u32 rx_bytes_lsd; /* dword 0*/
u32 rx_bytes_msd; /* dword 1*/
u32 rx_total_frames; /* dword 2*/
@@ -618,8 +639,8 @@ struct be_port_rxf_stats {
u32 rx_input_fifo_overflow; /* dword 65*/
};
-struct be_rxf_stats {
- struct be_port_rxf_stats port[2];
+struct be_rxf_stats_v0 {
+ struct be_port_rxf_stats_v0 port[2];
u32 rx_drops_no_pbuf; /* dword 132*/
u32 rx_drops_no_txpb; /* dword 133*/
u32 rx_drops_no_erx_descr; /* dword 134*/
@@ -642,36 +663,227 @@ struct be_rxf_stats {
u32 rsvd1[6];
};
-struct be_erx_stats {
+struct be_erx_stats_v0 {
u32 rx_drops_no_fragments[44]; /* dwordS 0 to 43*/
- u32 debug_wdma_sent_hold; /* dword 44*/
- u32 debug_wdma_pbfree_sent_hold; /* dword 45*/
- u32 debug_wdma_zerobyte_pbfree_sent_hold; /* dword 46*/
- u32 debug_pmem_pbuf_dealloc; /* dword 47*/
+ u32 rsvd[4];
};
struct be_pmem_stats {
u32 eth_red_drops;
- u32 rsvd[4];
+ u32 rsvd[5];
};
-struct be_hw_stats {
- struct be_rxf_stats rxf;
+struct be_hw_stats_v0 {
+ struct be_rxf_stats_v0 rxf;
u32 rsvd[48];
- struct be_erx_stats erx;
+ struct be_erx_stats_v0 erx;
struct be_pmem_stats pmem;
};
-struct be_cmd_req_get_stats {
+struct be_cmd_req_get_stats_v0 {
+ struct be_cmd_req_hdr hdr;
+ u8 rsvd[sizeof(struct be_hw_stats_v0)];
+};
+
+struct be_cmd_resp_get_stats_v0 {
+ struct be_cmd_resp_hdr hdr;
+ struct be_hw_stats_v0 hw_stats;
+};
+
+#define make_64bit_val(hi_32, lo_32) (((u64)hi_32<<32) | lo_32)
+struct lancer_cmd_pport_stats {
+ u32 tx_packets_lo;
+ u32 tx_packets_hi;
+ u32 tx_unicast_packets_lo;
+ u32 tx_unicast_packets_hi;
+ u32 tx_multicast_packets_lo;
+ u32 tx_multicast_packets_hi;
+ u32 tx_broadcast_packets_lo;
+ u32 tx_broadcast_packets_hi;
+ u32 tx_bytes_lo;
+ u32 tx_bytes_hi;
+ u32 tx_unicast_bytes_lo;
+ u32 tx_unicast_bytes_hi;
+ u32 tx_multicast_bytes_lo;
+ u32 tx_multicast_bytes_hi;
+ u32 tx_broadcast_bytes_lo;
+ u32 tx_broadcast_bytes_hi;
+ u32 tx_discards_lo;
+ u32 tx_discards_hi;
+ u32 tx_errors_lo;
+ u32 tx_errors_hi;
+ u32 tx_pause_frames_lo;
+ u32 tx_pause_frames_hi;
+ u32 tx_pause_on_frames_lo;
+ u32 tx_pause_on_frames_hi;
+ u32 tx_pause_off_frames_lo;
+ u32 tx_pause_off_frames_hi;
+ u32 tx_internal_mac_errors_lo;
+ u32 tx_internal_mac_errors_hi;
+ u32 tx_control_frames_lo;
+ u32 tx_control_frames_hi;
+ u32 tx_packets_64_bytes_lo;
+ u32 tx_packets_64_bytes_hi;
+ u32 tx_packets_65_to_127_bytes_lo;
+ u32 tx_packets_65_to_127_bytes_hi;
+ u32 tx_packets_128_to_255_bytes_lo;
+ u32 tx_packets_128_to_255_bytes_hi;
+ u32 tx_packets_256_to_511_bytes_lo;
+ u32 tx_packets_256_to_511_bytes_hi;
+ u32 tx_packets_512_to_1023_bytes_lo;
+ u32 tx_packets_512_to_1023_bytes_hi;
+ u32 tx_packets_1024_to_1518_bytes_lo;
+ u32 tx_packets_1024_to_1518_bytes_hi;
+ u32 tx_packets_1519_to_2047_bytes_lo;
+ u32 tx_packets_1519_to_2047_bytes_hi;
+ u32 tx_packets_2048_to_4095_bytes_lo;
+ u32 tx_packets_2048_to_4095_bytes_hi;
+ u32 tx_packets_4096_to_8191_bytes_lo;
+ u32 tx_packets_4096_to_8191_bytes_hi;
+ u32 tx_packets_8192_to_9216_bytes_lo;
+ u32 tx_packets_8192_to_9216_bytes_hi;
+ u32 tx_lso_packets_lo;
+ u32 tx_lso_packets_hi;
+ u32 rx_packets_lo;
+ u32 rx_packets_hi;
+ u32 rx_unicast_packets_lo;
+ u32 rx_unicast_packets_hi;
+ u32 rx_multicast_packets_lo;
+ u32 rx_multicast_packets_hi;
+ u32 rx_broadcast_packets_lo;
+ u32 rx_broadcast_packets_hi;
+ u32 rx_bytes_lo;
+ u32 rx_bytes_hi;
+ u32 rx_unicast_bytes_lo;
+ u32 rx_unicast_bytes_hi;
+ u32 rx_multicast_bytes_lo;
+ u32 rx_multicast_bytes_hi;
+ u32 rx_broadcast_bytes_lo;
+ u32 rx_broadcast_bytes_hi;
+ u32 rx_unknown_protos;
+ u32 rsvd_69; /* Word 69 is reserved */
+ u32 rx_discards_lo;
+ u32 rx_discards_hi;
+ u32 rx_errors_lo;
+ u32 rx_errors_hi;
+ u32 rx_crc_errors_lo;
+ u32 rx_crc_errors_hi;
+ u32 rx_alignment_errors_lo;
+ u32 rx_alignment_errors_hi;
+ u32 rx_symbol_errors_lo;
+ u32 rx_symbol_errors_hi;
+ u32 rx_pause_frames_lo;
+ u32 rx_pause_frames_hi;
+ u32 rx_pause_on_frames_lo;
+ u32 rx_pause_on_frames_hi;
+ u32 rx_pause_off_frames_lo;
+ u32 rx_pause_off_frames_hi;
+ u32 rx_frames_too_long_lo;
+ u32 rx_frames_too_long_hi;
+ u32 rx_internal_mac_errors_lo;
+ u32 rx_internal_mac_errors_hi;
+ u32 rx_undersize_packets;
+ u32 rx_oversize_packets;
+ u32 rx_fragment_packets;
+ u32 rx_jabbers;
+ u32 rx_control_frames_lo;
+ u32 rx_control_frames_hi;
+ u32 rx_control_frames_unknown_opcode_lo;
+ u32 rx_control_frames_unknown_opcode_hi;
+ u32 rx_in_range_errors;
+ u32 rx_out_of_range_errors;
+ u32 rx_address_match_errors;
+ u32 rx_vlan_mismatch_errors;
+ u32 rx_dropped_too_small;
+ u32 rx_dropped_too_short;
+ u32 rx_dropped_header_too_small;
+ u32 rx_dropped_invalid_tcp_length;
+ u32 rx_dropped_runt;
+ u32 rx_ip_checksum_errors;
+ u32 rx_tcp_checksum_errors;
+ u32 rx_udp_checksum_errors;
+ u32 rx_non_rss_packets;
+ u32 rsvd_111;
+ u32 rx_ipv4_packets_lo;
+ u32 rx_ipv4_packets_hi;
+ u32 rx_ipv6_packets_lo;
+ u32 rx_ipv6_packets_hi;
+ u32 rx_ipv4_bytes_lo;
+ u32 rx_ipv4_bytes_hi;
+ u32 rx_ipv6_bytes_lo;
+ u32 rx_ipv6_bytes_hi;
+ u32 rx_nic_packets_lo;
+ u32 rx_nic_packets_hi;
+ u32 rx_tcp_packets_lo;
+ u32 rx_tcp_packets_hi;
+ u32 rx_iscsi_packets_lo;
+ u32 rx_iscsi_packets_hi;
+ u32 rx_management_packets_lo;
+ u32 rx_management_packets_hi;
+ u32 rx_switched_unicast_packets_lo;
+ u32 rx_switched_unicast_packets_hi;
+ u32 rx_switched_multicast_packets_lo;
+ u32 rx_switched_multicast_packets_hi;
+ u32 rx_switched_broadcast_packets_lo;
+ u32 rx_switched_broadcast_packets_hi;
+ u32 num_forwards_lo;
+ u32 num_forwards_hi;
+ u32 rx_fifo_overflow;
+ u32 rx_input_fifo_overflow;
+ u32 rx_drops_too_many_frags_lo;
+ u32 rx_drops_too_many_frags_hi;
+ u32 rx_drops_invalid_queue;
+ u32 rsvd_141;
+ u32 rx_drops_mtu_lo;
+ u32 rx_drops_mtu_hi;
+ u32 rx_packets_64_bytes_lo;
+ u32 rx_packets_64_bytes_hi;
+ u32 rx_packets_65_to_127_bytes_lo;
+ u32 rx_packets_65_to_127_bytes_hi;
+ u32 rx_packets_128_to_255_bytes_lo;
+ u32 rx_packets_128_to_255_bytes_hi;
+ u32 rx_packets_256_to_511_bytes_lo;
+ u32 rx_packets_256_to_511_bytes_hi;
+ u32 rx_packets_512_to_1023_bytes_lo;
+ u32 rx_packets_512_to_1023_bytes_hi;
+ u32 rx_packets_1024_to_1518_bytes_lo;
+ u32 rx_packets_1024_to_1518_bytes_hi;
+ u32 rx_packets_1519_to_2047_bytes_lo;
+ u32 rx_packets_1519_to_2047_bytes_hi;
+ u32 rx_packets_2048_to_4095_bytes_lo;
+ u32 rx_packets_2048_to_4095_bytes_hi;
+ u32 rx_packets_4096_to_8191_bytes_lo;
+ u32 rx_packets_4096_to_8191_bytes_hi;
+ u32 rx_packets_8192_to_9216_bytes_lo;
+ u32 rx_packets_8192_to_9216_bytes_hi;
+};
+
+struct pport_stats_params {
+ u16 pport_num;
+ u8 rsvd;
+ u8 reset_stats;
+};
+
+struct lancer_cmd_req_pport_stats {
struct be_cmd_req_hdr hdr;
- u8 rsvd[sizeof(struct be_hw_stats)];
+ union {
+ struct pport_stats_params params;
+ u8 rsvd[sizeof(struct lancer_cmd_pport_stats)];
+ } cmd_params;
};
-struct be_cmd_resp_get_stats {
+struct lancer_cmd_resp_pport_stats {
struct be_cmd_resp_hdr hdr;
- struct be_hw_stats hw_stats;
+ struct lancer_cmd_pport_stats pport_stats;
};
+static inline struct lancer_cmd_pport_stats*
+ pport_stats_from_cmd(struct be_adapter *adapter)
+{
+ struct lancer_cmd_resp_pport_stats *cmd = adapter->stats_cmd.va;
+ return &cmd->pport_stats;
+}
+
struct be_cmd_req_get_cntl_addnl_attribs {
struct be_cmd_req_hdr hdr;
u8 rsvd[8];
@@ -695,13 +907,6 @@ struct be_cmd_req_vlan_config {
u16 normal_vlan[64];
} __packed;
-struct be_cmd_req_promiscuous_config {
- struct be_cmd_req_hdr hdr;
- u8 port0_promiscuous;
- u8 port1_promiscuous;
- u16 rsvd0;
-} __packed;
-
/******************** Multicast MAC Config *******************/
#define BE_MAX_MC 64 /* set mcast promisc if > 64 */
struct macaddr {
@@ -716,11 +921,18 @@ struct be_cmd_req_mcast_mac_config {
struct macaddr mac[BE_MAX_MC];
} __packed;
-static inline struct be_hw_stats *
-hw_stats_from_cmd(struct be_cmd_resp_get_stats *cmd)
-{
- return &cmd->hw_stats;
-}
+/******************* RX FILTER ******************************/
+struct be_cmd_req_rx_filter {
+ struct be_cmd_req_hdr hdr;
+ u32 global_flags_mask;
+ u32 global_flags;
+ u32 if_flags_mask;
+ u32 if_flags;
+ u32 if_id;
+ u32 multicast_num;
+ struct macaddr mac[BE_MAX_MC];
+};
+
/******************** Link Status Query *******************/
struct be_cmd_req_link_status {
@@ -920,6 +1132,36 @@ struct be_cmd_write_flashrom {
struct flashrom_params params;
};
+/**************** Lancer Firmware Flash ************/
+struct amap_lancer_write_obj_context {
+ u8 write_length[24];
+ u8 reserved1[7];
+ u8 eof;
+} __packed;
+
+struct lancer_cmd_req_write_object {
+ struct be_cmd_req_hdr hdr;
+ u8 context[sizeof(struct amap_lancer_write_obj_context) / 8];
+ u32 write_offset;
+ u8 object_name[104];
+ u32 descriptor_count;
+ u32 buf_len;
+ u32 addr_low;
+ u32 addr_high;
+};
+
+struct lancer_cmd_resp_write_object {
+ u8 opcode;
+ u8 subsystem;
+ u8 rsvd1[2];
+ u8 status;
+ u8 additional_status;
+ u8 rsvd2[2];
+ u32 resp_len;
+ u32 actual_resp_len;
+ u32 actual_write_len;
+};
+
/************************ WOL *******************************/
struct be_cmd_req_acpi_wol_magic_config{
struct be_cmd_req_hdr hdr;
@@ -1061,6 +1303,151 @@ struct be_cmd_resp_set_func_cap {
u8 rsvd[212];
};
+/*************** HW Stats Get v1 **********************************/
+#define BE_TXP_SW_SZ 48
+struct be_port_rxf_stats_v1 {
+ u32 rsvd0[12];
+ u32 rx_crc_errors;
+ u32 rx_alignment_symbol_errors;
+ u32 rx_pause_frames;
+ u32 rx_priority_pause_frames;
+ u32 rx_control_frames;
+ u32 rx_in_range_errors;
+ u32 rx_out_range_errors;
+ u32 rx_frame_too_long;
+ u32 rx_address_match_errors;
+ u32 rx_dropped_too_small;
+ u32 rx_dropped_too_short;
+ u32 rx_dropped_header_too_small;
+ u32 rx_dropped_tcp_length;
+ u32 rx_dropped_runt;
+ u32 rsvd1[10];
+ u32 rx_ip_checksum_errs;
+ u32 rx_tcp_checksum_errs;
+ u32 rx_udp_checksum_errs;
+ u32 rsvd2[7];
+ u32 rx_switched_unicast_packets;
+ u32 rx_switched_multicast_packets;
+ u32 rx_switched_broadcast_packets;
+ u32 rsvd3[3];
+ u32 tx_pauseframes;
+ u32 tx_priority_pauseframes;
+ u32 tx_controlframes;
+ u32 rsvd4[10];
+ u32 rxpp_fifo_overflow_drop;
+ u32 rx_input_fifo_overflow_drop;
+ u32 pmem_fifo_overflow_drop;
+ u32 jabber_events;
+ u32 rsvd5[3];
+};
+
+
+struct be_rxf_stats_v1 {
+ struct be_port_rxf_stats_v1 port[4];
+ u32 rsvd0[2];
+ u32 rx_drops_no_pbuf;
+ u32 rx_drops_no_txpb;
+ u32 rx_drops_no_erx_descr;
+ u32 rx_drops_no_tpre_descr;
+ u32 rsvd1[6];
+ u32 rx_drops_too_many_frags;
+ u32 rx_drops_invalid_ring;
+ u32 forwarded_packets;
+ u32 rx_drops_mtu;
+ u32 rsvd2[14];
+};
+
+struct be_erx_stats_v1 {
+ u32 rx_drops_no_fragments[68]; /* dwordS 0 to 67*/
+ u32 rsvd[4];
+};
+
+struct be_hw_stats_v1 {
+ struct be_rxf_stats_v1 rxf;
+ u32 rsvd0[BE_TXP_SW_SZ];
+ struct be_erx_stats_v1 erx;
+ struct be_pmem_stats pmem;
+ u32 rsvd1[3];
+};
+
+struct be_cmd_req_get_stats_v1 {
+ struct be_cmd_req_hdr hdr;
+ u8 rsvd[sizeof(struct be_hw_stats_v1)];
+};
+
+struct be_cmd_resp_get_stats_v1 {
+ struct be_cmd_resp_hdr hdr;
+ struct be_hw_stats_v1 hw_stats;
+};
+
+static inline void *
+hw_stats_from_cmd(struct be_adapter *adapter)
+{
+ if (adapter->generation == BE_GEN3) {
+ struct be_cmd_resp_get_stats_v1 *cmd = adapter->stats_cmd.va;
+
+ return &cmd->hw_stats;
+ } else {
+ struct be_cmd_resp_get_stats_v0 *cmd = adapter->stats_cmd.va;
+
+ return &cmd->hw_stats;
+ }
+}
+
+static inline void *be_port_rxf_stats_from_cmd(struct be_adapter *adapter)
+{
+ if (adapter->generation == BE_GEN3) {
+ struct be_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter);
+ struct be_rxf_stats_v1 *rxf_stats = &hw_stats->rxf;
+
+ return &rxf_stats->port[adapter->port_num];
+ } else {
+ struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter);
+ struct be_rxf_stats_v0 *rxf_stats = &hw_stats->rxf;
+
+ return &rxf_stats->port[adapter->port_num];
+ }
+}
+
+static inline void *be_rxf_stats_from_cmd(struct be_adapter *adapter)
+{
+ if (adapter->generation == BE_GEN3) {
+ struct be_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter);
+
+ return &hw_stats->rxf;
+ } else {
+ struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter);
+
+ return &hw_stats->rxf;
+ }
+}
+
+static inline void *be_erx_stats_from_cmd(struct be_adapter *adapter)
+{
+ if (adapter->generation == BE_GEN3) {
+ struct be_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter);
+
+ return &hw_stats->erx;
+ } else {
+ struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter);
+
+ return &hw_stats->erx;
+ }
+}
+
+static inline void *be_pmem_stats_from_cmd(struct be_adapter *adapter)
+{
+ if (adapter->generation == BE_GEN3) {
+ struct be_hw_stats_v1 *hw_stats = hw_stats_from_cmd(adapter);
+
+ return &hw_stats->pmem;
+ } else {
+ struct be_hw_stats_v0 *hw_stats = hw_stats_from_cmd(adapter);
+
+ return &hw_stats->pmem;
+ }
+}
+
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,
@@ -1093,18 +1480,19 @@ extern int be_cmd_rxq_create(struct be_adapter *adapter,
extern int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q,
int type);
extern int be_cmd_link_status_query(struct be_adapter *adapter,
- bool *link_up, u8 *mac_speed, u16 *link_speed);
+ bool *link_up, u8 *mac_speed, u16 *link_speed, u32 dom);
extern int be_cmd_reset(struct be_adapter *adapter);
extern int be_cmd_get_stats(struct be_adapter *adapter,
struct be_dma_mem *nonemb_cmd);
+extern int lancer_cmd_get_pport_stats(struct be_adapter *adapter,
+ struct be_dma_mem *nonemb_cmd);
extern int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver);
extern int be_cmd_modify_eqd(struct be_adapter *adapter, u32 eq_id, u32 eqd);
extern int be_cmd_vlan_config(struct be_adapter *adapter, u32 if_id,
u16 *vtag_array, u32 num, bool untagged,
bool promiscuous);
-extern int be_cmd_promiscuous_config(struct be_adapter *adapter,
- u8 port_num, bool en);
+extern int be_cmd_promiscuous_config(struct be_adapter *adapter, bool en);
extern int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id,
struct net_device *netdev, struct be_dma_mem *mem);
extern int be_cmd_set_flow_control(struct be_adapter *adapter,
@@ -1124,6 +1512,11 @@ extern int be_cmd_get_beacon_state(struct be_adapter *adapter,
extern int be_cmd_write_flashrom(struct be_adapter *adapter,
struct be_dma_mem *cmd, u32 flash_oper,
u32 flash_opcode, u32 buf_size);
+extern int lancer_cmd_write_object(struct be_adapter *adapter,
+ struct be_dma_mem *cmd,
+ u32 data_size, u32 data_offset,
+ const char *obj_name,
+ u32 *data_written, u8 *addn_status);
int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
int offset);
extern int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac,
@@ -1148,4 +1541,6 @@ extern void be_detect_dump_ue(struct be_adapter *adapter);
extern int be_cmd_get_die_temperature(struct be_adapter *adapter);
extern int be_cmd_get_cntl_attributes(struct be_adapter *adapter);
extern int be_cmd_check_native_mode(struct be_adapter *adapter);
+extern int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size);
+extern void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf);
diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c
index aac248fbd18b..facfe3ca5c40 100644
--- a/drivers/net/benet/be_ethtool.c
+++ b/drivers/net/benet/be_ethtool.c
@@ -26,8 +26,8 @@ struct be_ethtool_stat {
int offset;
};
-enum {NETSTAT, PORTSTAT, MISCSTAT, DRVSTAT_TX, DRVSTAT_RX, ERXSTAT,
- PMEMSTAT, DRVSTAT};
+enum {NETSTAT, DRVSTAT_TX, DRVSTAT_RX, ERXSTAT,
+ DRVSTAT};
#define FIELDINFO(_struct, field) FIELD_SIZEOF(_struct, field), \
offsetof(_struct, field)
#define NETSTAT_INFO(field) #field, NETSTAT,\
@@ -37,15 +37,8 @@ enum {NETSTAT, PORTSTAT, MISCSTAT, DRVSTAT_TX, DRVSTAT_RX, ERXSTAT,
FIELDINFO(struct be_tx_stats, field)
#define DRVSTAT_RX_INFO(field) #field, DRVSTAT_RX,\
FIELDINFO(struct be_rx_stats, field)
-#define MISCSTAT_INFO(field) #field, MISCSTAT,\
- FIELDINFO(struct be_rxf_stats, field)
-#define PORTSTAT_INFO(field) #field, PORTSTAT,\
- FIELDINFO(struct be_port_rxf_stats, \
- field)
-#define ERXSTAT_INFO(field) #field, ERXSTAT,\
- FIELDINFO(struct be_erx_stats, field)
-#define PMEMSTAT_INFO(field) #field, PMEMSTAT,\
- FIELDINFO(struct be_pmem_stats, field)
+#define ERXSTAT_INFO(field) #field, ERXSTAT,\
+ FIELDINFO(struct be_erx_stats_v1, field)
#define DRVSTAT_INFO(field) #field, DRVSTAT,\
FIELDINFO(struct be_drv_stats, \
field)
@@ -65,50 +58,41 @@ static const struct be_ethtool_stat et_stats[] = {
{DRVSTAT_TX_INFO(be_tx_stops)},
{DRVSTAT_TX_INFO(be_tx_events)},
{DRVSTAT_TX_INFO(be_tx_compl)},
- {PORTSTAT_INFO(rx_unicast_frames)},
- {PORTSTAT_INFO(rx_multicast_frames)},
- {PORTSTAT_INFO(rx_broadcast_frames)},
- {PORTSTAT_INFO(rx_crc_errors)},
- {PORTSTAT_INFO(rx_alignment_symbol_errors)},
- {PORTSTAT_INFO(rx_pause_frames)},
- {PORTSTAT_INFO(rx_control_frames)},
- {PORTSTAT_INFO(rx_in_range_errors)},
- {PORTSTAT_INFO(rx_out_range_errors)},
- {PORTSTAT_INFO(rx_frame_too_long)},
- {PORTSTAT_INFO(rx_address_match_errors)},
- {PORTSTAT_INFO(rx_vlan_mismatch)},
- {PORTSTAT_INFO(rx_dropped_too_small)},
- {PORTSTAT_INFO(rx_dropped_too_short)},
- {PORTSTAT_INFO(rx_dropped_header_too_small)},
- {PORTSTAT_INFO(rx_dropped_tcp_length)},
- {PORTSTAT_INFO(rx_dropped_runt)},
- {PORTSTAT_INFO(rx_fifo_overflow)},
- {PORTSTAT_INFO(rx_input_fifo_overflow)},
- {PORTSTAT_INFO(rx_ip_checksum_errs)},
- {PORTSTAT_INFO(rx_tcp_checksum_errs)},
- {PORTSTAT_INFO(rx_udp_checksum_errs)},
- {PORTSTAT_INFO(rx_non_rss_packets)},
- {PORTSTAT_INFO(rx_ipv4_packets)},
- {PORTSTAT_INFO(rx_ipv6_packets)},
- {PORTSTAT_INFO(rx_switched_unicast_packets)},
- {PORTSTAT_INFO(rx_switched_multicast_packets)},
- {PORTSTAT_INFO(rx_switched_broadcast_packets)},
- {PORTSTAT_INFO(tx_unicastframes)},
- {PORTSTAT_INFO(tx_multicastframes)},
- {PORTSTAT_INFO(tx_broadcastframes)},
- {PORTSTAT_INFO(tx_pauseframes)},
- {PORTSTAT_INFO(tx_controlframes)},
- {MISCSTAT_INFO(rx_drops_no_pbuf)},
- {MISCSTAT_INFO(rx_drops_no_txpb)},
- {MISCSTAT_INFO(rx_drops_no_erx_descr)},
- {MISCSTAT_INFO(rx_drops_no_tpre_descr)},
- {MISCSTAT_INFO(rx_drops_too_many_frags)},
- {MISCSTAT_INFO(rx_drops_invalid_ring)},
- {MISCSTAT_INFO(forwarded_packets)},
- {MISCSTAT_INFO(rx_drops_mtu)},
- {MISCSTAT_INFO(port0_jabber_events)},
- {MISCSTAT_INFO(port1_jabber_events)},
- {PMEMSTAT_INFO(eth_red_drops)},
+ {DRVSTAT_INFO(rx_crc_errors)},
+ {DRVSTAT_INFO(rx_alignment_symbol_errors)},
+ {DRVSTAT_INFO(rx_pause_frames)},
+ {DRVSTAT_INFO(rx_control_frames)},
+ {DRVSTAT_INFO(rx_in_range_errors)},
+ {DRVSTAT_INFO(rx_out_range_errors)},
+ {DRVSTAT_INFO(rx_frame_too_long)},
+ {DRVSTAT_INFO(rx_address_match_errors)},
+ {DRVSTAT_INFO(rx_dropped_too_small)},
+ {DRVSTAT_INFO(rx_dropped_too_short)},
+ {DRVSTAT_INFO(rx_dropped_header_too_small)},
+ {DRVSTAT_INFO(rx_dropped_tcp_length)},
+ {DRVSTAT_INFO(rx_dropped_runt)},
+ {DRVSTAT_INFO(rxpp_fifo_overflow_drop)},
+ {DRVSTAT_INFO(rx_input_fifo_overflow_drop)},
+ {DRVSTAT_INFO(rx_ip_checksum_errs)},
+ {DRVSTAT_INFO(rx_tcp_checksum_errs)},
+ {DRVSTAT_INFO(rx_udp_checksum_errs)},
+ {DRVSTAT_INFO(rx_switched_unicast_packets)},
+ {DRVSTAT_INFO(rx_switched_multicast_packets)},
+ {DRVSTAT_INFO(rx_switched_broadcast_packets)},
+ {DRVSTAT_INFO(tx_pauseframes)},
+ {DRVSTAT_INFO(tx_controlframes)},
+ {DRVSTAT_INFO(rx_priority_pause_frames)},
+ {DRVSTAT_INFO(pmem_fifo_overflow_drop)},
+ {DRVSTAT_INFO(jabber_events)},
+ {DRVSTAT_INFO(rx_drops_no_pbuf)},
+ {DRVSTAT_INFO(rx_drops_no_txpb)},
+ {DRVSTAT_INFO(rx_drops_no_erx_descr)},
+ {DRVSTAT_INFO(rx_drops_no_tpre_descr)},
+ {DRVSTAT_INFO(rx_drops_too_many_frags)},
+ {DRVSTAT_INFO(rx_drops_invalid_ring)},
+ {DRVSTAT_INFO(forwarded_packets)},
+ {DRVSTAT_INFO(rx_drops_mtu)},
+ {DRVSTAT_INFO(eth_red_drops)},
{DRVSTAT_INFO(be_on_die_temperature)}
};
#define ETHTOOL_STATS_NUM ARRAY_SIZE(et_stats)
@@ -156,6 +140,29 @@ be_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
}
static int
+be_get_reg_len(struct net_device *netdev)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
+ u32 log_size = 0;
+
+ if (be_physfn(adapter))
+ be_cmd_get_reg_len(adapter, &log_size);
+
+ return log_size;
+}
+
+static void
+be_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *buf)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
+
+ if (be_physfn(adapter)) {
+ memset(buf, 0, regs->len);
+ be_cmd_get_regs(adapter, regs->len, buf);
+ }
+}
+
+static int
be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
{
struct be_adapter *adapter = netdev_priv(netdev);
@@ -186,9 +193,9 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
struct be_rx_obj *rxo;
struct be_eq_obj *rx_eq;
struct be_eq_obj *tx_eq = &adapter->tx_eq;
- u32 tx_max, tx_min, tx_cur;
u32 rx_max, rx_min, rx_cur;
int status = 0, i;
+ u32 tx_cur;
if (coalesce->use_adaptive_tx_coalesce == 1)
return -EINVAL;
@@ -227,8 +234,6 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
}
}
- tx_max = coalesce->tx_coalesce_usecs_high;
- tx_min = coalesce->tx_coalesce_usecs_low;
tx_cur = coalesce->tx_coalesce_usecs;
if (tx_cur > BE_MAX_EQD)
@@ -242,32 +247,11 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
return 0;
}
-static u32 be_get_rx_csum(struct net_device *netdev)
-{
- struct be_adapter *adapter = netdev_priv(netdev);
-
- return adapter->rx_csum;
-}
-
-static int be_set_rx_csum(struct net_device *netdev, uint32_t data)
-{
- struct be_adapter *adapter = netdev_priv(netdev);
-
- if (data)
- adapter->rx_csum = true;
- else
- adapter->rx_csum = false;
-
- return 0;
-}
-
static void
be_get_ethtool_stats(struct net_device *netdev,
struct ethtool_stats *stats, uint64_t *data)
{
struct be_adapter *adapter = netdev_priv(netdev);
- struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats_cmd.va);
- struct be_erx_stats *erx_stats = &hw_stats->erx;
struct be_rx_obj *rxo;
void *p = NULL;
int i, j;
@@ -280,15 +264,6 @@ be_get_ethtool_stats(struct net_device *netdev,
case DRVSTAT_TX:
p = &adapter->tx_stats;
break;
- case PORTSTAT:
- p = &hw_stats->rxf.port[adapter->port_num];
- break;
- case MISCSTAT:
- p = &hw_stats->rxf;
- break;
- case PMEMSTAT:
- p = &hw_stats->pmem;
- break;
case DRVSTAT:
p = &adapter->drv_stats;
break;
@@ -306,7 +281,8 @@ be_get_ethtool_stats(struct net_device *netdev,
p = (u8 *)&rxo->stats + et_rx_stats[i].offset;
break;
case ERXSTAT:
- p = (u32 *)erx_stats + rxo->q.id;
+ p = (u32 *)be_erx_stats_from_cmd(adapter) +
+ rxo->q.id;
break;
}
data[ETHTOOL_STATS_NUM + j * ETHTOOL_RXSTATS_NUM + i] =
@@ -374,19 +350,28 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
if ((adapter->link_speed < 0) || (!(netdev->flags & IFF_UP))) {
status = be_cmd_link_status_query(adapter, &link_up,
- &mac_speed, &link_speed);
+ &mac_speed, &link_speed, 0);
be_link_status_update(adapter, link_up);
/* link_speed is in units of 10 Mbps */
if (link_speed) {
- ecmd->speed = link_speed*10;
+ ethtool_cmd_speed_set(ecmd, link_speed*10);
} else {
switch (mac_speed) {
+ case PHY_LINK_SPEED_10MBPS:
+ ethtool_cmd_speed_set(ecmd, SPEED_10);
+ break;
+ case PHY_LINK_SPEED_100MBPS:
+ ethtool_cmd_speed_set(ecmd, SPEED_100);
+ break;
case PHY_LINK_SPEED_1GBPS:
- ecmd->speed = SPEED_1000;
+ ethtool_cmd_speed_set(ecmd, SPEED_1000);
break;
case PHY_LINK_SPEED_10GBPS:
- ecmd->speed = SPEED_10000;
+ ethtool_cmd_speed_set(ecmd, SPEED_10000);
+ break;
+ case PHY_LINK_SPEED_ZERO:
+ ethtool_cmd_speed_set(ecmd, 0);
break;
}
}
@@ -429,14 +414,14 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
}
/* Save for future use */
- adapter->link_speed = ecmd->speed;
+ adapter->link_speed = ethtool_cmd_speed(ecmd);
adapter->port_type = ecmd->port;
adapter->transceiver = ecmd->transceiver;
adapter->autoneg = ecmd->autoneg;
dma_free_coherent(&adapter->pdev->dev, phy_cmd.size, phy_cmd.va,
phy_cmd.dma);
} else {
- ecmd->speed = adapter->link_speed;
+ ethtool_cmd_speed_set(ecmd, adapter->link_speed);
ecmd->port = adapter->port_type;
ecmd->transceiver = adapter->transceiver;
ecmd->autoneg = adapter->autoneg;
@@ -507,29 +492,33 @@ be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd)
}
static int
-be_phys_id(struct net_device *netdev, u32 data)
+be_set_phys_id(struct net_device *netdev,
+ enum ethtool_phys_id_state state)
{
struct be_adapter *adapter = netdev_priv(netdev);
- int status;
- u32 cur;
-
- be_cmd_get_beacon_state(adapter, adapter->hba_port_num, &cur);
- if (cur == BEACON_STATE_ENABLED)
- return 0;
+ switch (state) {
+ case ETHTOOL_ID_ACTIVE:
+ be_cmd_get_beacon_state(adapter, adapter->hba_port_num,
+ &adapter->beacon_state);
+ return 1; /* cycle on/off once per second */
- if (data < 2)
- data = 2;
+ case ETHTOOL_ID_ON:
+ be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0,
+ BEACON_STATE_ENABLED);
+ break;
- status = be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0,
- BEACON_STATE_ENABLED);
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(data*HZ);
+ case ETHTOOL_ID_OFF:
+ be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0,
+ BEACON_STATE_DISABLED);
+ break;
- status = be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0,
- BEACON_STATE_DISABLED);
+ case ETHTOOL_ID_INACTIVE:
+ be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0,
+ adapter->beacon_state);
+ }
- return status;
+ return 0;
}
static bool
@@ -646,7 +635,7 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data)
}
if (be_cmd_link_status_query(adapter, &link_up, &mac_speed,
- &qos_link_speed) != 0) {
+ &qos_link_speed, 0) != 0) {
test->flags |= ETH_TEST_FL_FAILED;
data[4] = -1;
} else if (!mac_speed) {
@@ -660,11 +649,9 @@ be_do_flash(struct net_device *netdev, struct ethtool_flash *efl)
{
struct be_adapter *adapter = netdev_priv(netdev);
char file_name[ETHTOOL_FLASH_MAX_FILENAME];
- u32 region;
file_name[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0;
strcpy(file_name, efl->data);
- region = efl->region;
return be_load_fw(adapter, file_name);
}
@@ -725,18 +712,12 @@ const struct ethtool_ops be_ethtool_ops = {
.get_ringparam = be_get_ringparam,
.get_pauseparam = be_get_pauseparam,
.set_pauseparam = be_set_pauseparam,
- .get_rx_csum = be_get_rx_csum,
- .set_rx_csum = be_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = ethtool_op_set_tx_hw_csum,
- .get_sg = ethtool_op_get_sg,
- .set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
- .set_tso = ethtool_op_set_tso,
.get_strings = be_get_stat_strings,
- .phys_id = be_phys_id,
+ .set_phys_id = be_set_phys_id,
.get_sset_count = be_get_sset_count,
.get_ethtool_stats = be_get_ethtool_stats,
+ .get_regs_len = be_get_reg_len,
+ .get_regs = be_get_regs,
.flash_device = be_do_flash,
.self_test = be_self_test,
};
diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h
index d4344a06090b..53d658afea2a 100644
--- a/drivers/net/benet/be_hw.h
+++ b/drivers/net/benet/be_hw.h
@@ -155,6 +155,10 @@
/********** SRIOV VF PCICFG OFFSET ********/
#define SRIOV_VF_PCICFG_OFFSET (4096)
+/********** FAT TABLE ********/
+#define RETRIEVE_FAT 0
+#define QUERY_FAT 1
+
/* Flashrom related descriptors */
#define IMAGE_TYPE_FIRMWARE 160
#define IMAGE_TYPE_BOOTCODE 224
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index 9187fb4e08f1..a485f7fdaf37 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -15,6 +15,7 @@
* Costa Mesa, CA 92626
*/
+#include <linux/prefetch.h>
#include "be.h"
#include "be_cmds.h"
#include <asm/div64.h>
@@ -42,6 +43,7 @@ static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = {
{ PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID1) },
{ PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) },
{ PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID3)},
+ { PCI_DEVICE(EMULEX_VENDOR_ID, OC_DEVICE_ID4)},
{ 0 }
};
MODULE_DEVICE_TABLE(pci, be_dev_ids);
@@ -116,11 +118,6 @@ static char *ue_status_hi_desc[] = {
"Unknown"
};
-static inline bool be_multi_rxq(struct be_adapter *adapter)
-{
- return (adapter->num_rx_qs > 1);
-}
-
static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q)
{
struct be_dma_mem *mem = &q->dma_mem;
@@ -250,14 +247,185 @@ netdev_addr:
return status;
}
+static void populate_be2_stats(struct be_adapter *adapter)
+{
+
+ struct be_drv_stats *drvs = &adapter->drv_stats;
+ struct be_pmem_stats *pmem_sts = be_pmem_stats_from_cmd(adapter);
+ struct be_port_rxf_stats_v0 *port_stats =
+ be_port_rxf_stats_from_cmd(adapter);
+ struct be_rxf_stats_v0 *rxf_stats =
+ be_rxf_stats_from_cmd(adapter);
+
+ drvs->rx_pause_frames = port_stats->rx_pause_frames;
+ drvs->rx_crc_errors = port_stats->rx_crc_errors;
+ drvs->rx_control_frames = port_stats->rx_control_frames;
+ drvs->rx_in_range_errors = port_stats->rx_in_range_errors;
+ drvs->rx_frame_too_long = port_stats->rx_frame_too_long;
+ drvs->rx_dropped_runt = port_stats->rx_dropped_runt;
+ drvs->rx_ip_checksum_errs = port_stats->rx_ip_checksum_errs;
+ drvs->rx_tcp_checksum_errs = port_stats->rx_tcp_checksum_errs;
+ drvs->rx_udp_checksum_errs = port_stats->rx_udp_checksum_errs;
+ drvs->rxpp_fifo_overflow_drop = port_stats->rx_fifo_overflow;
+ drvs->rx_dropped_tcp_length = port_stats->rx_dropped_tcp_length;
+ drvs->rx_dropped_too_small = port_stats->rx_dropped_too_small;
+ drvs->rx_dropped_too_short = port_stats->rx_dropped_too_short;
+ drvs->rx_out_range_errors = port_stats->rx_out_range_errors;
+ drvs->rx_input_fifo_overflow_drop =
+ port_stats->rx_input_fifo_overflow;
+ drvs->rx_dropped_header_too_small =
+ port_stats->rx_dropped_header_too_small;
+ drvs->rx_address_match_errors =
+ port_stats->rx_address_match_errors;
+ drvs->rx_alignment_symbol_errors =
+ port_stats->rx_alignment_symbol_errors;
+
+ drvs->tx_pauseframes = port_stats->tx_pauseframes;
+ drvs->tx_controlframes = port_stats->tx_controlframes;
+
+ if (adapter->port_num)
+ drvs->jabber_events =
+ rxf_stats->port1_jabber_events;
+ else
+ drvs->jabber_events =
+ rxf_stats->port0_jabber_events;
+ drvs->rx_drops_no_pbuf = rxf_stats->rx_drops_no_pbuf;
+ drvs->rx_drops_no_txpb = rxf_stats->rx_drops_no_txpb;
+ drvs->rx_drops_no_erx_descr = rxf_stats->rx_drops_no_erx_descr;
+ drvs->rx_drops_invalid_ring = rxf_stats->rx_drops_invalid_ring;
+ drvs->forwarded_packets = rxf_stats->forwarded_packets;
+ drvs->rx_drops_mtu = rxf_stats->rx_drops_mtu;
+ drvs->rx_drops_no_tpre_descr =
+ rxf_stats->rx_drops_no_tpre_descr;
+ drvs->rx_drops_too_many_frags =
+ rxf_stats->rx_drops_too_many_frags;
+ adapter->drv_stats.eth_red_drops = pmem_sts->eth_red_drops;
+}
+
+static void populate_be3_stats(struct be_adapter *adapter)
+{
+ struct be_drv_stats *drvs = &adapter->drv_stats;
+ struct be_pmem_stats *pmem_sts = be_pmem_stats_from_cmd(adapter);
+
+ struct be_rxf_stats_v1 *rxf_stats =
+ be_rxf_stats_from_cmd(adapter);
+ struct be_port_rxf_stats_v1 *port_stats =
+ be_port_rxf_stats_from_cmd(adapter);
+
+ drvs->rx_priority_pause_frames = 0;
+ drvs->pmem_fifo_overflow_drop = 0;
+ drvs->rx_pause_frames = port_stats->rx_pause_frames;
+ drvs->rx_crc_errors = port_stats->rx_crc_errors;
+ drvs->rx_control_frames = port_stats->rx_control_frames;
+ drvs->rx_in_range_errors = port_stats->rx_in_range_errors;
+ drvs->rx_frame_too_long = port_stats->rx_frame_too_long;
+ drvs->rx_dropped_runt = port_stats->rx_dropped_runt;
+ drvs->rx_ip_checksum_errs = port_stats->rx_ip_checksum_errs;
+ drvs->rx_tcp_checksum_errs = port_stats->rx_tcp_checksum_errs;
+ drvs->rx_udp_checksum_errs = port_stats->rx_udp_checksum_errs;
+ drvs->rx_dropped_tcp_length = port_stats->rx_dropped_tcp_length;
+ drvs->rx_dropped_too_small = port_stats->rx_dropped_too_small;
+ drvs->rx_dropped_too_short = port_stats->rx_dropped_too_short;
+ drvs->rx_out_range_errors = port_stats->rx_out_range_errors;
+ drvs->rx_dropped_header_too_small =
+ port_stats->rx_dropped_header_too_small;
+ drvs->rx_input_fifo_overflow_drop =
+ port_stats->rx_input_fifo_overflow_drop;
+ drvs->rx_address_match_errors =
+ port_stats->rx_address_match_errors;
+ drvs->rx_alignment_symbol_errors =
+ port_stats->rx_alignment_symbol_errors;
+ drvs->rxpp_fifo_overflow_drop =
+ port_stats->rxpp_fifo_overflow_drop;
+ drvs->tx_pauseframes = port_stats->tx_pauseframes;
+ drvs->tx_controlframes = port_stats->tx_controlframes;
+ drvs->jabber_events = port_stats->jabber_events;
+ drvs->rx_drops_no_pbuf = rxf_stats->rx_drops_no_pbuf;
+ drvs->rx_drops_no_txpb = rxf_stats->rx_drops_no_txpb;
+ drvs->rx_drops_no_erx_descr = rxf_stats->rx_drops_no_erx_descr;
+ drvs->rx_drops_invalid_ring = rxf_stats->rx_drops_invalid_ring;
+ drvs->forwarded_packets = rxf_stats->forwarded_packets;
+ drvs->rx_drops_mtu = rxf_stats->rx_drops_mtu;
+ drvs->rx_drops_no_tpre_descr =
+ rxf_stats->rx_drops_no_tpre_descr;
+ drvs->rx_drops_too_many_frags =
+ rxf_stats->rx_drops_too_many_frags;
+ adapter->drv_stats.eth_red_drops = pmem_sts->eth_red_drops;
+}
+
+static void populate_lancer_stats(struct be_adapter *adapter)
+{
+
+ struct be_drv_stats *drvs = &adapter->drv_stats;
+ struct lancer_cmd_pport_stats *pport_stats = pport_stats_from_cmd
+ (adapter);
+ drvs->rx_priority_pause_frames = 0;
+ drvs->pmem_fifo_overflow_drop = 0;
+ drvs->rx_pause_frames =
+ make_64bit_val(pport_stats->rx_pause_frames_lo,
+ pport_stats->rx_pause_frames_hi);
+ drvs->rx_crc_errors = make_64bit_val(pport_stats->rx_crc_errors_hi,
+ pport_stats->rx_crc_errors_lo);
+ drvs->rx_control_frames =
+ make_64bit_val(pport_stats->rx_control_frames_hi,
+ pport_stats->rx_control_frames_lo);
+ drvs->rx_in_range_errors = pport_stats->rx_in_range_errors;
+ drvs->rx_frame_too_long =
+ make_64bit_val(pport_stats->rx_internal_mac_errors_hi,
+ pport_stats->rx_frames_too_long_lo);
+ drvs->rx_dropped_runt = pport_stats->rx_dropped_runt;
+ drvs->rx_ip_checksum_errs = pport_stats->rx_ip_checksum_errors;
+ drvs->rx_tcp_checksum_errs = pport_stats->rx_tcp_checksum_errors;
+ drvs->rx_udp_checksum_errs = pport_stats->rx_udp_checksum_errors;
+ drvs->rx_dropped_tcp_length =
+ pport_stats->rx_dropped_invalid_tcp_length;
+ drvs->rx_dropped_too_small = pport_stats->rx_dropped_too_small;
+ drvs->rx_dropped_too_short = pport_stats->rx_dropped_too_short;
+ drvs->rx_out_range_errors = pport_stats->rx_out_of_range_errors;
+ drvs->rx_dropped_header_too_small =
+ pport_stats->rx_dropped_header_too_small;
+ drvs->rx_input_fifo_overflow_drop = pport_stats->rx_fifo_overflow;
+ drvs->rx_address_match_errors = pport_stats->rx_address_match_errors;
+ drvs->rx_alignment_symbol_errors =
+ make_64bit_val(pport_stats->rx_symbol_errors_hi,
+ pport_stats->rx_symbol_errors_lo);
+ drvs->rxpp_fifo_overflow_drop = pport_stats->rx_fifo_overflow;
+ drvs->tx_pauseframes = make_64bit_val(pport_stats->tx_pause_frames_hi,
+ pport_stats->tx_pause_frames_lo);
+ drvs->tx_controlframes =
+ make_64bit_val(pport_stats->tx_control_frames_hi,
+ pport_stats->tx_control_frames_lo);
+ drvs->jabber_events = pport_stats->rx_jabbers;
+ drvs->rx_drops_no_pbuf = 0;
+ drvs->rx_drops_no_txpb = 0;
+ drvs->rx_drops_no_erx_descr = 0;
+ drvs->rx_drops_invalid_ring = pport_stats->rx_drops_invalid_queue;
+ drvs->forwarded_packets = make_64bit_val(pport_stats->num_forwards_hi,
+ pport_stats->num_forwards_lo);
+ drvs->rx_drops_mtu = make_64bit_val(pport_stats->rx_drops_mtu_hi,
+ pport_stats->rx_drops_mtu_lo);
+ drvs->rx_drops_no_tpre_descr = 0;
+ drvs->rx_drops_too_many_frags =
+ make_64bit_val(pport_stats->rx_drops_too_many_frags_hi,
+ pport_stats->rx_drops_too_many_frags_lo);
+}
+
+void be_parse_stats(struct be_adapter *adapter)
+{
+ if (adapter->generation == BE_GEN3) {
+ if (lancer_chip(adapter))
+ populate_lancer_stats(adapter);
+ else
+ populate_be3_stats(adapter);
+ } else {
+ populate_be2_stats(adapter);
+ }
+}
+
void netdev_stats_update(struct be_adapter *adapter)
{
- struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats_cmd.va);
- struct be_rxf_stats *rxf_stats = &hw_stats->rxf;
- struct be_port_rxf_stats *port_stats =
- &rxf_stats->port[adapter->port_num];
+ struct be_drv_stats *drvs = &adapter->drv_stats;
struct net_device_stats *dev_stats = &adapter->netdev->stats;
- struct be_erx_stats *erx_stats = &hw_stats->erx;
struct be_rx_obj *rxo;
int i;
@@ -267,43 +435,54 @@ void netdev_stats_update(struct be_adapter *adapter)
dev_stats->rx_bytes += rx_stats(rxo)->rx_bytes;
dev_stats->multicast += rx_stats(rxo)->rx_mcast_pkts;
/* no space in linux buffers: best possible approximation */
- dev_stats->rx_dropped +=
- erx_stats->rx_drops_no_fragments[rxo->q.id];
+ if (adapter->generation == BE_GEN3) {
+ if (!(lancer_chip(adapter))) {
+ struct be_erx_stats_v1 *erx_stats =
+ be_erx_stats_from_cmd(adapter);
+ dev_stats->rx_dropped +=
+ erx_stats->rx_drops_no_fragments[rxo->q.id];
+ }
+ } else {
+ struct be_erx_stats_v0 *erx_stats =
+ be_erx_stats_from_cmd(adapter);
+ dev_stats->rx_dropped +=
+ erx_stats->rx_drops_no_fragments[rxo->q.id];
+ }
}
dev_stats->tx_packets = tx_stats(adapter)->be_tx_pkts;
dev_stats->tx_bytes = tx_stats(adapter)->be_tx_bytes;
/* bad pkts received */
- dev_stats->rx_errors = port_stats->rx_crc_errors +
- port_stats->rx_alignment_symbol_errors +
- port_stats->rx_in_range_errors +
- port_stats->rx_out_range_errors +
- port_stats->rx_frame_too_long +
- port_stats->rx_dropped_too_small +
- port_stats->rx_dropped_too_short +
- port_stats->rx_dropped_header_too_small +
- port_stats->rx_dropped_tcp_length +
- port_stats->rx_dropped_runt +
- port_stats->rx_tcp_checksum_errs +
- port_stats->rx_ip_checksum_errs +
- port_stats->rx_udp_checksum_errs;
+ dev_stats->rx_errors = drvs->rx_crc_errors +
+ drvs->rx_alignment_symbol_errors +
+ drvs->rx_in_range_errors +
+ drvs->rx_out_range_errors +
+ drvs->rx_frame_too_long +
+ drvs->rx_dropped_too_small +
+ drvs->rx_dropped_too_short +
+ drvs->rx_dropped_header_too_small +
+ drvs->rx_dropped_tcp_length +
+ drvs->rx_dropped_runt +
+ drvs->rx_tcp_checksum_errs +
+ drvs->rx_ip_checksum_errs +
+ drvs->rx_udp_checksum_errs;
/* detailed rx errors */
- dev_stats->rx_length_errors = port_stats->rx_in_range_errors +
- port_stats->rx_out_range_errors +
- port_stats->rx_frame_too_long;
+ dev_stats->rx_length_errors = drvs->rx_in_range_errors +
+ drvs->rx_out_range_errors +
+ drvs->rx_frame_too_long;
- dev_stats->rx_crc_errors = port_stats->rx_crc_errors;
+ dev_stats->rx_crc_errors = drvs->rx_crc_errors;
/* frame alignment errors */
- dev_stats->rx_frame_errors = port_stats->rx_alignment_symbol_errors;
+ dev_stats->rx_frame_errors = drvs->rx_alignment_symbol_errors;
/* receiver fifo overrun */
/* drops_no_pbuf is no per i/f, it's per BE card */
- dev_stats->rx_fifo_errors = port_stats->rx_fifo_overflow +
- port_stats->rx_input_fifo_overflow +
- rxf_stats->rx_drops_no_pbuf;
+ dev_stats->rx_fifo_errors = drvs->rxpp_fifo_overflow_drop +
+ drvs->rx_input_fifo_overflow_drop +
+ drvs->rx_drops_no_pbuf;
}
void be_link_status_update(struct be_adapter *adapter, bool link_up)
@@ -703,7 +882,7 @@ static void be_set_multicast_list(struct net_device *netdev)
struct be_adapter *adapter = netdev_priv(netdev);
if (netdev->flags & IFF_PROMISC) {
- be_cmd_promiscuous_config(adapter, adapter->port_num, 1);
+ be_cmd_promiscuous_config(adapter, true);
adapter->promiscuous = true;
goto done;
}
@@ -711,7 +890,7 @@ static void be_set_multicast_list(struct net_device *netdev)
/* BE was previously in promiscuous mode; disable it */
if (adapter->promiscuous) {
adapter->promiscuous = false;
- be_cmd_promiscuous_config(adapter, adapter->port_num, 0);
+ be_cmd_promiscuous_config(adapter, false);
}
/* Enable multicast promisc if num configured exceeds what we support */
@@ -993,9 +1172,10 @@ static void be_rx_compl_process(struct be_adapter *adapter,
struct be_rx_obj *rxo,
struct be_rx_compl_info *rxcp)
{
+ struct net_device *netdev = adapter->netdev;
struct sk_buff *skb;
- skb = netdev_alloc_skb_ip_align(adapter->netdev, BE_HDR_LEN);
+ skb = netdev_alloc_skb_ip_align(netdev, BE_HDR_LEN);
if (unlikely(!skb)) {
if (net_ratelimit())
dev_warn(&adapter->pdev->dev, "skb alloc failed\n");
@@ -1005,13 +1185,16 @@ static void be_rx_compl_process(struct be_adapter *adapter,
skb_fill_rx_data(adapter, rxo, skb, rxcp);
- if (likely(adapter->rx_csum && csum_passed(rxcp)))
+ if (likely((netdev->features & NETIF_F_RXCSUM) && csum_passed(rxcp)))
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
skb_checksum_none_assert(skb);
skb->truesize = skb->len + sizeof(struct sk_buff);
- skb->protocol = eth_type_trans(skb, adapter->netdev);
+ skb->protocol = eth_type_trans(skb, netdev);
+ if (adapter->netdev->features & NETIF_F_RXHASH)
+ skb->rxhash = rxcp->rss_hash;
+
if (unlikely(rxcp->vlanf)) {
if (!adapter->vlan_grp || adapter->vlans_added == 0) {
@@ -1073,6 +1256,8 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter,
skb->data_len = rxcp->pkt_size;
skb->truesize += rxcp->pkt_size;
skb->ip_summed = CHECKSUM_UNNECESSARY;
+ if (adapter->netdev->features & NETIF_F_RXHASH)
+ skb->rxhash = rxcp->rss_hash;
if (likely(!rxcp->vlanf))
napi_gro_frags(&eq_obj->napi);
@@ -1103,9 +1288,14 @@ static void be_parse_rx_compl_v1(struct be_adapter *adapter,
AMAP_GET_BITS(struct amap_eth_rx_compl_v1, numfrags, compl);
rxcp->pkt_type =
AMAP_GET_BITS(struct amap_eth_rx_compl_v1, cast_enc, compl);
- rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm, compl);
- rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag,
- compl);
+ rxcp->rss_hash =
+ AMAP_GET_BITS(struct amap_eth_rx_compl_v1, rsshash, rxcp);
+ if (rxcp->vlanf) {
+ rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm,
+ compl);
+ rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag,
+ compl);
+ }
}
static void be_parse_rx_compl_v0(struct be_adapter *adapter,
@@ -1130,9 +1320,14 @@ static void be_parse_rx_compl_v0(struct be_adapter *adapter,
AMAP_GET_BITS(struct amap_eth_rx_compl_v0, numfrags, compl);
rxcp->pkt_type =
AMAP_GET_BITS(struct amap_eth_rx_compl_v0, cast_enc, compl);
- rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm, compl);
- rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag,
- compl);
+ rxcp->rss_hash =
+ AMAP_GET_BITS(struct amap_eth_rx_compl_v0, rsshash, rxcp);
+ if (rxcp->vlanf) {
+ rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm,
+ compl);
+ rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag,
+ compl);
+ }
}
static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo)
@@ -1154,17 +1349,20 @@ static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo)
else
be_parse_rx_compl_v0(adapter, compl, rxcp);
- /* vlanf could be wrongly set in some cards. ignore if vtm is not set */
- if ((adapter->function_mode & 0x400) && !rxcp->vtm)
- rxcp->vlanf = 0;
+ if (rxcp->vlanf) {
+ /* vlanf could be wrongly set in some cards.
+ * ignore if vtm is not set */
+ if ((adapter->function_mode & 0x400) && !rxcp->vtm)
+ rxcp->vlanf = 0;
- if (!lancer_chip(adapter))
- rxcp->vlan_tag = swab16(rxcp->vlan_tag);
+ if (!lancer_chip(adapter))
+ rxcp->vlan_tag = swab16(rxcp->vlan_tag);
- if (((adapter->pvid & VLAN_VID_MASK) ==
- (rxcp->vlan_tag & VLAN_VID_MASK)) &&
- !adapter->vlan_tag[rxcp->vlan_tag])
- rxcp->vlanf = 0;
+ if (((adapter->pvid & VLAN_VID_MASK) ==
+ (rxcp->vlan_tag & VLAN_VID_MASK)) &&
+ !adapter->vlan_tag[rxcp->vlan_tag])
+ rxcp->vlanf = 0;
+ }
/* As the compl has been parsed, reset it; we wont touch it again */
compl->dw[offsetof(struct amap_eth_rx_compl_v1, valid) / 32] = 0;
@@ -1261,7 +1459,7 @@ static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq)
return txcp;
}
-static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index)
+static u16 be_tx_compl_process(struct be_adapter *adapter, u16 last_index)
{
struct be_queue_info *txq = &adapter->tx_obj.q;
struct be_eth_wrb *wrb;
@@ -1288,9 +1486,8 @@ static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index)
queue_tail_inc(txq);
} while (cur_index != last_index);
- atomic_sub(num_wrbs, &txq->used);
-
kfree_skb(sent_skb);
+ return num_wrbs;
}
static inline struct be_eq_entry *event_get(struct be_eq_obj *eq_obj)
@@ -1373,7 +1570,7 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
struct be_queue_info *tx_cq = &adapter->tx_obj.cq;
struct be_queue_info *txq = &adapter->tx_obj.q;
struct be_eth_tx_compl *txcp;
- u16 end_idx, cmpl = 0, timeo = 0;
+ u16 end_idx, cmpl = 0, timeo = 0, num_wrbs = 0;
struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list;
struct sk_buff *sent_skb;
bool dummy_wrb;
@@ -1383,12 +1580,14 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
while ((txcp = be_tx_compl_get(tx_cq))) {
end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl,
wrb_index, txcp);
- be_tx_compl_process(adapter, end_idx);
+ num_wrbs += be_tx_compl_process(adapter, end_idx);
cmpl++;
}
if (cmpl) {
be_cq_notify(adapter, tx_cq->id, false, cmpl);
+ atomic_sub(num_wrbs, &txq->used);
cmpl = 0;
+ num_wrbs = 0;
}
if (atomic_read(&txq->used) == 0 || ++timeo > 200)
@@ -1408,7 +1607,8 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
index_adv(&end_idx,
wrb_cnt_for_skb(adapter, sent_skb, &dummy_wrb) - 1,
txq->len);
- be_tx_compl_process(adapter, end_idx);
+ num_wrbs = be_tx_compl_process(adapter, end_idx);
+ atomic_sub(num_wrbs, &txq->used);
}
}
@@ -1573,12 +1773,31 @@ static void be_rx_queues_destroy(struct be_adapter *adapter)
}
}
+static u32 be_num_rxqs_want(struct be_adapter *adapter)
+{
+ if (multi_rxq && (adapter->function_caps & BE_FUNCTION_CAPS_RSS) &&
+ !adapter->sriov_enabled && !(adapter->function_mode & 0x400)) {
+ return 1 + MAX_RSS_QS; /* one default non-RSS queue */
+ } else {
+ dev_warn(&adapter->pdev->dev,
+ "No support for multiple RX queues\n");
+ return 1;
+ }
+}
+
static int be_rx_queues_create(struct be_adapter *adapter)
{
struct be_queue_info *eq, *q, *cq;
struct be_rx_obj *rxo;
int rc, i;
+ adapter->num_rx_qs = min(be_num_rxqs_want(adapter),
+ msix_enabled(adapter) ?
+ adapter->num_msix_vec - 1 : 1);
+ if (adapter->num_rx_qs != MAX_RX_QS)
+ dev_warn(&adapter->pdev->dev,
+ "Can create only %d RX queues", adapter->num_rx_qs);
+
adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE;
for_all_rx_queues(adapter, rxo, i) {
rxo->adapter = adapter;
@@ -1724,12 +1943,15 @@ static int be_poll_rx(struct napi_struct *napi, int budget)
break;
/* Ignore flush completions */
- if (rxcp->num_rcvd) {
+ if (rxcp->num_rcvd && rxcp->pkt_size) {
if (do_gro(rxcp))
be_rx_compl_process_gro(adapter, rxo, rxcp);
else
be_rx_compl_process(adapter, rxo, rxcp);
+ } else if (rxcp->pkt_size == 0) {
+ be_rx_compl_discard(adapter, rxo, rxcp);
}
+
be_rx_stats_update(rxo, rxcp);
}
@@ -1760,12 +1982,12 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
struct be_queue_info *tx_cq = &adapter->tx_obj.cq;
struct be_eth_tx_compl *txcp;
int tx_compl = 0, mcc_compl, status = 0;
- u16 end_idx;
+ u16 end_idx, num_wrbs = 0;
while ((txcp = be_tx_compl_get(tx_cq))) {
end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl,
wrb_index, txcp);
- be_tx_compl_process(adapter, end_idx);
+ num_wrbs += be_tx_compl_process(adapter, end_idx);
tx_compl++;
}
@@ -1781,6 +2003,8 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
if (tx_compl) {
be_cq_notify(adapter, adapter->tx_obj.cq.id, true, tx_compl);
+ atomic_sub(num_wrbs, &txq->used);
+
/* As Tx wrbs have been freed up, wake up netdev queue if
* it was stopped due to lack of tx wrbs.
*/
@@ -1843,6 +2067,9 @@ static void be_worker(struct work_struct *work)
struct be_rx_obj *rxo;
int i;
+ if (!adapter->ue_detected && !lancer_chip(adapter))
+ be_detect_dump_ue(adapter);
+
/* when interrupts are not yet enabled, just reap any pending
* mcc completions */
if (!netif_running(adapter->netdev)) {
@@ -1855,15 +2082,16 @@ static void be_worker(struct work_struct *work)
be_cq_notify(adapter, mcc_obj->cq.id, false, mcc_compl);
}
- if (!adapter->ue_detected && !lancer_chip(adapter))
- be_detect_dump_ue(adapter);
-
goto reschedule;
}
- if (!adapter->stats_cmd_sent)
- be_cmd_get_stats(adapter, &adapter->stats_cmd);
-
+ if (!adapter->stats_cmd_sent) {
+ if (lancer_chip(adapter))
+ lancer_cmd_get_pport_stats(adapter,
+ &adapter->stats_cmd);
+ else
+ be_cmd_get_stats(adapter, &adapter->stats_cmd);
+ }
be_tx_rate_update(adapter);
for_all_rx_queues(adapter, rxo, i) {
@@ -1875,8 +2103,6 @@ static void be_worker(struct work_struct *work)
be_post_rx_frags(rxo, GFP_KERNEL);
}
}
- if (!adapter->ue_detected && !lancer_chip(adapter))
- be_detect_dump_ue(adapter);
reschedule:
adapter->work_counter++;
@@ -1885,51 +2111,35 @@ reschedule:
static void be_msix_disable(struct be_adapter *adapter)
{
- if (adapter->msix_enabled) {
+ if (msix_enabled(adapter)) {
pci_disable_msix(adapter->pdev);
- adapter->msix_enabled = false;
- }
-}
-
-static int be_num_rxqs_get(struct be_adapter *adapter)
-{
- if (multi_rxq && (adapter->function_caps & BE_FUNCTION_CAPS_RSS) &&
- !adapter->sriov_enabled && !(adapter->function_mode & 0x400)) {
- return 1 + MAX_RSS_QS; /* one default non-RSS queue */
- } else {
- dev_warn(&adapter->pdev->dev,
- "No support for multiple RX queues\n");
- return 1;
+ adapter->num_msix_vec = 0;
}
}
static void be_msix_enable(struct be_adapter *adapter)
{
#define BE_MIN_MSIX_VECTORS (1 + 1) /* Rx + Tx */
- int i, status;
+ int i, status, num_vec;
- adapter->num_rx_qs = be_num_rxqs_get(adapter);
+ num_vec = be_num_rxqs_want(adapter) + 1;
- for (i = 0; i < (adapter->num_rx_qs + 1); i++)
+ for (i = 0; i < num_vec; i++)
adapter->msix_entries[i].entry = i;
- status = pci_enable_msix(adapter->pdev, adapter->msix_entries,
- adapter->num_rx_qs + 1);
+ status = pci_enable_msix(adapter->pdev, adapter->msix_entries, num_vec);
if (status == 0) {
goto done;
} else if (status >= BE_MIN_MSIX_VECTORS) {
+ num_vec = status;
if (pci_enable_msix(adapter->pdev, adapter->msix_entries,
- status) == 0) {
- adapter->num_rx_qs = status - 1;
- dev_warn(&adapter->pdev->dev,
- "Could alloc only %d MSIx vectors. "
- "Using %d RX Qs\n", status, adapter->num_rx_qs);
+ num_vec) == 0)
goto done;
- }
}
return;
done:
- adapter->msix_enabled = true;
+ adapter->num_msix_vec = num_vec;
+ return;
}
static void be_sriov_enable(struct be_adapter *adapter)
@@ -1937,7 +2147,20 @@ static void be_sriov_enable(struct be_adapter *adapter)
be_check_sriov_fn_type(adapter);
#ifdef CONFIG_PCI_IOV
if (be_physfn(adapter) && num_vfs) {
- int status;
+ int status, pos;
+ u16 nvfs;
+
+ pos = pci_find_ext_capability(adapter->pdev,
+ PCI_EXT_CAP_ID_SRIOV);
+ pci_read_config_word(adapter->pdev,
+ pos + PCI_SRIOV_TOTAL_VF, &nvfs);
+
+ if (num_vfs > nvfs) {
+ dev_info(&adapter->pdev->dev,
+ "Device supports %d VFs and not %d\n",
+ nvfs, num_vfs);
+ num_vfs = nvfs;
+ }
status = pci_enable_sriov(adapter->pdev, num_vfs);
adapter->sriov_enabled = status ? false : true;
@@ -2010,8 +2233,7 @@ err_msix:
err:
dev_warn(&adapter->pdev->dev,
"MSIX Request IRQ failed - err %d\n", status);
- pci_disable_msix(adapter->pdev);
- adapter->msix_enabled = false;
+ be_msix_disable(adapter);
return status;
}
@@ -2020,7 +2242,7 @@ static int be_irq_register(struct be_adapter *adapter)
struct net_device *netdev = adapter->netdev;
int status;
- if (adapter->msix_enabled) {
+ if (msix_enabled(adapter)) {
status = be_msix_register(adapter);
if (status == 0)
goto done;
@@ -2053,7 +2275,7 @@ static void be_irq_unregister(struct be_adapter *adapter)
return;
/* INTx */
- if (!adapter->msix_enabled) {
+ if (!msix_enabled(adapter)) {
free_irq(netdev->irq, adapter);
goto done;
}
@@ -2095,7 +2317,7 @@ static int be_close(struct net_device *netdev)
be_cq_notify(adapter, rxo->cq.id, false, 0);
}
- if (adapter->msix_enabled) {
+ if (msix_enabled(adapter)) {
vec = be_msix_vec_get(adapter, tx_eq);
synchronize_irq(vec);
@@ -2148,7 +2370,7 @@ static int be_open(struct net_device *netdev)
be_async_mcc_enable(adapter);
status = be_cmd_link_status_query(adapter, &link_up, &mac_speed,
- &link_speed);
+ &link_speed, 0);
if (status)
goto err;
be_link_status_update(adapter, link_up);
@@ -2268,7 +2490,7 @@ static int be_setup(struct be_adapter *adapter)
BE_IF_FLAGS_PASS_L3L4_ERRORS;
en_flags |= BE_IF_FLAGS_PASS_L3L4_ERRORS;
- if (be_multi_rxq(adapter)) {
+ if (adapter->function_caps & BE_FUNCTION_CAPS_RSS) {
cap_flags |= BE_IF_FLAGS_RSS;
en_flags |= BE_IF_FLAGS_RSS;
}
@@ -2325,7 +2547,6 @@ static int be_setup(struct be_adapter *adapter)
return 0;
- be_mcc_queues_destroy(adapter);
rx_qs_destroy:
be_rx_queues_destroy(adapter);
tx_qs_destroy:
@@ -2493,7 +2714,6 @@ static int be_flash_data(struct be_adapter *adapter,
"cmd to write to flash rom failed.\n");
return -1;
}
- yield();
}
}
return 0;
@@ -2511,32 +2731,96 @@ static int get_ufigen_type(struct flash_file_hdr_g2 *fhdr)
return 0;
}
-int be_load_fw(struct be_adapter *adapter, u8 *func)
+static int lancer_fw_download(struct be_adapter *adapter,
+ const struct firmware *fw)
{
- char fw_file[ETHTOOL_FLASH_MAX_FILENAME];
- const struct firmware *fw;
- struct flash_file_hdr_g2 *fhdr;
- struct flash_file_hdr_g3 *fhdr3;
- struct image_hdr *img_hdr_ptr = NULL;
+#define LANCER_FW_DOWNLOAD_CHUNK (32 * 1024)
+#define LANCER_FW_DOWNLOAD_LOCATION "/prg"
struct be_dma_mem flash_cmd;
- int status, i = 0, num_imgs = 0;
- const u8 *p;
+ const u8 *data_ptr = NULL;
+ u8 *dest_image_ptr = NULL;
+ size_t image_size = 0;
+ u32 chunk_size = 0;
+ u32 data_written = 0;
+ u32 offset = 0;
+ int status = 0;
+ u8 add_status = 0;
- if (!netif_running(adapter->netdev)) {
+ if (!IS_ALIGNED(fw->size, sizeof(u32))) {
dev_err(&adapter->pdev->dev,
- "Firmware load not allowed (interface is down)\n");
- return -EPERM;
+ "FW Image not properly aligned. "
+ "Length must be 4 byte aligned.\n");
+ status = -EINVAL;
+ goto lancer_fw_exit;
+ }
+
+ flash_cmd.size = sizeof(struct lancer_cmd_req_write_object)
+ + LANCER_FW_DOWNLOAD_CHUNK;
+ flash_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, flash_cmd.size,
+ &flash_cmd.dma, GFP_KERNEL);
+ if (!flash_cmd.va) {
+ status = -ENOMEM;
+ dev_err(&adapter->pdev->dev,
+ "Memory allocation failure while flashing\n");
+ goto lancer_fw_exit;
}
- strcpy(fw_file, func);
+ dest_image_ptr = flash_cmd.va +
+ sizeof(struct lancer_cmd_req_write_object);
+ image_size = fw->size;
+ data_ptr = fw->data;
- status = request_firmware(&fw, fw_file, &adapter->pdev->dev);
- if (status)
- goto fw_exit;
+ while (image_size) {
+ chunk_size = min_t(u32, image_size, LANCER_FW_DOWNLOAD_CHUNK);
+
+ /* Copy the image chunk content. */
+ memcpy(dest_image_ptr, data_ptr, chunk_size);
+
+ status = lancer_cmd_write_object(adapter, &flash_cmd,
+ chunk_size, offset, LANCER_FW_DOWNLOAD_LOCATION,
+ &data_written, &add_status);
+
+ if (status)
+ break;
+
+ offset += data_written;
+ data_ptr += data_written;
+ image_size -= data_written;
+ }
+
+ if (!status) {
+ /* Commit the FW written */
+ status = lancer_cmd_write_object(adapter, &flash_cmd,
+ 0, offset, LANCER_FW_DOWNLOAD_LOCATION,
+ &data_written, &add_status);
+ }
+
+ dma_free_coherent(&adapter->pdev->dev, flash_cmd.size, flash_cmd.va,
+ flash_cmd.dma);
+ if (status) {
+ dev_err(&adapter->pdev->dev,
+ "Firmware load error. "
+ "Status code: 0x%x Additional Status: 0x%x\n",
+ status, add_status);
+ goto lancer_fw_exit;
+ }
+
+ dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n");
+lancer_fw_exit:
+ return status;
+}
+
+static int be_fw_download(struct be_adapter *adapter, const struct firmware* fw)
+{
+ struct flash_file_hdr_g2 *fhdr;
+ struct flash_file_hdr_g3 *fhdr3;
+ struct image_hdr *img_hdr_ptr = NULL;
+ struct be_dma_mem flash_cmd;
+ const u8 *p;
+ int status = 0, i = 0, num_imgs = 0;
p = fw->data;
fhdr = (struct flash_file_hdr_g2 *) p;
- dev_info(&adapter->pdev->dev, "Flashing firmware file %s\n", fw_file);
flash_cmd.size = sizeof(struct be_cmd_write_flashrom) + 32*1024;
flash_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, flash_cmd.size,
@@ -2545,7 +2829,7 @@ int be_load_fw(struct be_adapter *adapter, u8 *func)
status = -ENOMEM;
dev_err(&adapter->pdev->dev,
"Memory allocation failure while flashing\n");
- goto fw_exit;
+ goto be_fw_exit;
}
if ((adapter->generation == BE_GEN3) &&
@@ -2573,11 +2857,37 @@ int be_load_fw(struct be_adapter *adapter, u8 *func)
flash_cmd.dma);
if (status) {
dev_err(&adapter->pdev->dev, "Firmware load error\n");
- goto fw_exit;
+ goto be_fw_exit;
}
dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n");
+be_fw_exit:
+ return status;
+}
+
+int be_load_fw(struct be_adapter *adapter, u8 *fw_file)
+{
+ const struct firmware *fw;
+ int status;
+
+ if (!netif_running(adapter->netdev)) {
+ dev_err(&adapter->pdev->dev,
+ "Firmware load not allowed (interface is down)\n");
+ return -1;
+ }
+
+ status = request_firmware(&fw, fw_file, &adapter->pdev->dev);
+ if (status)
+ goto fw_exit;
+
+ dev_info(&adapter->pdev->dev, "Flashing firmware file %s\n", fw_file);
+
+ if (lancer_chip(adapter))
+ status = lancer_fw_download(adapter, fw);
+ else
+ status = be_fw_download(adapter, fw);
+
fw_exit:
release_firmware(fw);
return status;
@@ -2606,10 +2916,14 @@ static void be_netdev_init(struct net_device *netdev)
struct be_rx_obj *rxo;
int i;
- 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_IP_CSUM | NETIF_F_IPV6_CSUM |
- NETIF_F_GRO | NETIF_F_TSO6;
+ netdev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
+ NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |
+ NETIF_F_HW_VLAN_TX;
+ if (be_multi_rxq(adapter))
+ netdev->hw_features |= NETIF_F_RXHASH;
+
+ netdev->features |= netdev->hw_features |
+ NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO |
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
@@ -2619,8 +2933,6 @@ static void be_netdev_init(struct net_device *netdev)
netdev->flags |= IFF_MULTICAST;
- adapter->rx_csum = true;
-
/* Default settings for Rx and Tx flow control */
adapter->rx_fc = true;
adapter->tx_fc = true;
@@ -2788,7 +3100,14 @@ static int be_stats_init(struct be_adapter *adapter)
{
struct be_dma_mem *cmd = &adapter->stats_cmd;
- cmd->size = sizeof(struct be_cmd_req_get_stats);
+ if (adapter->generation == BE_GEN2) {
+ cmd->size = sizeof(struct be_cmd_req_get_stats_v0);
+ } else {
+ if (lancer_chip(adapter))
+ cmd->size = sizeof(struct lancer_cmd_req_pport_stats);
+ else
+ cmd->size = sizeof(struct be_cmd_req_get_stats_v1);
+ }
cmd->va = dma_alloc_coherent(&adapter->pdev->dev, cmd->size, &cmd->dma,
GFP_KERNEL);
if (cmd->va == NULL)
@@ -2814,6 +3133,7 @@ static void __devexit be_remove(struct pci_dev *pdev)
be_ctrl_cleanup(adapter);
+ kfree(adapter->vf_cfg);
be_sriov_disable(adapter);
be_msix_disable(adapter);
@@ -2841,7 +3161,8 @@ static int be_get_config(struct be_adapter *adapter)
memset(mac, 0, ETH_ALEN);
- if (be_physfn(adapter)) {
+ /* A default permanent address is given to each VF for Lancer*/
+ if (be_physfn(adapter) || lancer_chip(adapter)) {
status = be_cmd_mac_addr_query(adapter, mac,
MAC_ADDRESS_TYPE_NETWORK, true /*permanent */, 0);
@@ -2883,6 +3204,7 @@ static int be_dev_family_check(struct be_adapter *adapter)
adapter->generation = BE_GEN3;
break;
case OC_DEVICE_ID3:
+ case OC_DEVICE_ID4:
pci_read_config_dword(pdev, SLI_INTF_REG_OFFSET, &sli_intf);
if_type = (sli_intf & SLI_INTF_IF_TYPE_MASK) >>
SLI_INTF_IF_TYPE_SHIFT;
@@ -2892,10 +3214,6 @@ static int be_dev_family_check(struct be_adapter *adapter)
dev_err(&pdev->dev, "SLI_INTF reg val is not valid\n");
return -EINVAL;
}
- if (num_vfs > 0) {
- dev_err(&pdev->dev, "VFs not supported\n");
- return -EINVAL;
- }
adapter->sli_family = ((sli_intf & SLI_INTF_FAMILY_MASK) >>
SLI_INTF_FAMILY_SHIFT);
adapter->generation = BE_GEN3;
@@ -2998,16 +3316,23 @@ static int __devinit be_probe(struct pci_dev *pdev,
}
be_sriov_enable(adapter);
+ if (adapter->sriov_enabled) {
+ adapter->vf_cfg = kcalloc(num_vfs,
+ sizeof(struct be_vf_cfg), GFP_KERNEL);
+
+ if (!adapter->vf_cfg)
+ goto free_netdev;
+ }
status = be_ctrl_init(adapter);
if (status)
- goto free_netdev;
+ goto free_vf_cfg;
if (lancer_chip(adapter)) {
status = lancer_test_and_set_rdy_state(adapter);
if (status) {
dev_err(&pdev->dev, "Adapter in non recoverable error\n");
- goto free_netdev;
+ goto ctrl_clean;
}
}
@@ -3050,9 +3375,24 @@ static int __devinit be_probe(struct pci_dev *pdev,
netif_carrier_off(netdev);
if (be_physfn(adapter) && adapter->sriov_enabled) {
- status = be_vf_eth_addr_config(adapter);
- if (status)
- goto unreg_netdev;
+ u8 mac_speed;
+ bool link_up;
+ u16 vf, lnk_speed;
+
+ if (!lancer_chip(adapter)) {
+ status = be_vf_eth_addr_config(adapter);
+ if (status)
+ goto unreg_netdev;
+ }
+
+ for (vf = 0; vf < num_vfs; vf++) {
+ status = be_cmd_link_status_query(adapter, &link_up,
+ &mac_speed, &lnk_speed, vf + 1);
+ if (!status)
+ adapter->vf_cfg[vf].vf_tx_rate = lnk_speed * 10;
+ else
+ goto unreg_netdev;
+ }
}
dev_info(&pdev->dev, "%s port %d\n", nic_name(pdev), adapter->port_num);
@@ -3069,6 +3409,8 @@ stats_clean:
be_stats_cleanup(adapter);
ctrl_clean:
be_ctrl_cleanup(adapter);
+free_vf_cfg:
+ kfree(adapter->vf_cfg);
free_netdev:
be_sriov_disable(adapter);
free_netdev(netdev);
@@ -3153,16 +3495,15 @@ static void be_shutdown(struct pci_dev *pdev)
if (!adapter)
return;
- if (netif_running(adapter->netdev))
- cancel_delayed_work_sync(&adapter->work);
+ cancel_delayed_work_sync(&adapter->work);
netif_device_detach(adapter->netdev);
- be_cmd_reset_function(adapter);
-
if (adapter->wol)
be_setup_wol(adapter, true);
+ be_cmd_reset_function(adapter);
+
pci_disable_device(pdev);
}
@@ -3274,13 +3615,6 @@ static int __init be_init_module(void)
rx_frag_size = 2048;
}
- if (num_vfs > 32) {
- printk(KERN_WARNING DRV_NAME
- " : Module param num_vfs must not be greater than 32."
- "Using 32\n");
- num_vfs = 32;
- }
-
return pci_register_driver(&be_driver);
}
module_init(be_init_module);
diff --git a/drivers/net/bna/bfa_ioc.c b/drivers/net/bna/bfa_ioc.c
index 7581518ecfa2..fcb9bb3169e0 100644
--- a/drivers/net/bna/bfa_ioc.c
+++ b/drivers/net/bna/bfa_ioc.c
@@ -82,7 +82,6 @@ static void bfa_ioc_pf_fwmismatch(struct bfa_ioc *ioc);
static void bfa_ioc_boot(struct bfa_ioc *ioc, u32 boot_type,
u32 boot_param);
static u32 bfa_ioc_smem_pgnum(struct bfa_ioc *ioc, u32 fmaddr);
-static u32 bfa_ioc_smem_pgoff(struct bfa_ioc *ioc, u32 fmaddr);
static void bfa_ioc_get_adapter_serial_num(struct bfa_ioc *ioc,
char *serial_num);
static void bfa_ioc_get_adapter_fw_ver(struct bfa_ioc *ioc,
@@ -1274,13 +1273,12 @@ bfa_ioc_lpu_stop(struct bfa_ioc *ioc)
void
bfa_nw_ioc_fwver_get(struct bfa_ioc *ioc, struct bfi_ioc_image_hdr *fwhdr)
{
- u32 pgnum, pgoff;
+ u32 pgnum;
u32 loff = 0;
int i;
u32 *fwsig = (u32 *) fwhdr;
pgnum = bfa_ioc_smem_pgnum(ioc, loff);
- pgoff = bfa_ioc_smem_pgoff(ioc, loff);
writel(pgnum, ioc->ioc_regs.host_page_num_fn);
for (i = 0; i < (sizeof(struct bfi_ioc_image_hdr) / sizeof(u32));
@@ -1514,7 +1512,7 @@ bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type,
u32 boot_env)
{
u32 *fwimg;
- u32 pgnum, pgoff;
+ u32 pgnum;
u32 loff = 0;
u32 chunkno = 0;
u32 i;
@@ -1527,7 +1525,6 @@ bfa_ioc_download_fw(struct bfa_ioc *ioc, u32 boot_type,
fwimg = bfa_cb_image_get_chunk(BFA_IOC_FWIMG_TYPE(ioc), chunkno);
pgnum = bfa_ioc_smem_pgnum(ioc, loff);
- pgoff = bfa_ioc_smem_pgoff(ioc, loff);
writel(pgnum, ioc->ioc_regs.host_page_num_fn);
@@ -1925,12 +1922,6 @@ bfa_ioc_smem_pgnum(struct bfa_ioc *ioc, u32 fmaddr)
return PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, fmaddr);
}
-static u32
-bfa_ioc_smem_pgoff(struct bfa_ioc *ioc, u32 fmaddr)
-{
- return PSS_SMEM_PGOFF(fmaddr);
-}
-
/**
* Register mailbox message handler function, to be called by common modules
*/
diff --git a/drivers/net/bna/bna_ctrl.c b/drivers/net/bna/bna_ctrl.c
index e1527472b961..53b14169e363 100644
--- a/drivers/net/bna/bna_ctrl.c
+++ b/drivers/net/bna/bna_ctrl.c
@@ -246,7 +246,6 @@ static void
bna_mbox_flush_q(struct bna *bna, struct list_head *q)
{
struct bna_mbox_qe *mb_qe = NULL;
- struct bfi_mhdr *cmd_h;
struct list_head *mb_q;
void (*cbfn)(void *arg, int status);
void *cbarg;
@@ -260,7 +259,6 @@ bna_mbox_flush_q(struct bna *bna, struct list_head *q)
bfa_q_qe_init(mb_qe);
bna->mbox_mod.msg_pending--;
- cmd_h = (struct bfi_mhdr *)(&mb_qe->cmd.msg[0]);
if (cbfn)
cbfn(cbarg, BNA_CB_NOT_EXEC);
}
@@ -2774,23 +2772,6 @@ bna_rit_mod_init(struct bna_rit_mod *rit_mod,
}
}
-static void
-bna_rit_mod_uninit(struct bna_rit_mod *rit_mod)
-{
- struct bna_rit_segment *rit_segment;
- struct list_head *qe;
- int i;
- int j;
-
- for (i = 0; i < BFI_RIT_SEG_TOTAL_POOLS; i++) {
- j = 0;
- list_for_each(qe, &rit_mod->rit_seg_pool[i]) {
- rit_segment = (struct bna_rit_segment *)qe;
- j++;
- }
- }
-}
-
/*
* Public functions
*/
@@ -2977,8 +2958,6 @@ bna_uninit(struct bna *bna)
bna_ucam_mod_uninit(&bna->ucam_mod);
- bna_rit_mod_uninit(&bna->rit_mod);
-
bna_ib_mod_uninit(&bna->ib_mod);
bna_rx_mod_uninit(&bna->rx_mod);
diff --git a/drivers/net/bna/bna_txrx.c b/drivers/net/bna/bna_txrx.c
index 58c7664040dc..380085cc3088 100644
--- a/drivers/net/bna/bna_txrx.c
+++ b/drivers/net/bna/bna_txrx.c
@@ -2229,14 +2229,11 @@ void
bna_rit_create(struct bna_rx *rx)
{
struct list_head *qe_rxp;
- struct bna *bna;
struct bna_rxp *rxp;
struct bna_rxq *q0 = NULL;
struct bna_rxq *q1 = NULL;
int offset;
- bna = rx->bna;
-
offset = 0;
list_for_each(qe_rxp, &rx->rxp_q) {
rxp = (struct bna_rxp *)qe_rxp;
@@ -2830,7 +2827,7 @@ bna_rx_create(struct bna *bna, struct bnad *bnad,
struct bna_mem_descr *dsqpt_mem; /* s/w qpt for data */
struct bna_mem_descr *hpage_mem; /* hdr page mem */
struct bna_mem_descr *dpage_mem; /* data page mem */
- int i, cpage_idx = 0, dpage_idx = 0, hpage_idx = 0, ret;
+ int i, cpage_idx = 0, dpage_idx = 0, hpage_idx = 0;
int dpage_count, hpage_count, rcb_idx;
struct bna_ib_config ibcfg;
/* Fail if we don't have enough RXPs, RXQs */
@@ -2924,7 +2921,7 @@ bna_rx_create(struct bna *bna, struct bnad *bnad,
ibcfg.interpkt_timeo = BFI_RX_INTERPKT_TIMEO;
ibcfg.ctrl_flags = BFI_IB_CF_INT_ENABLE;
- ret = bna_ib_config(rxp->cq.ib, &ibcfg);
+ bna_ib_config(rxp->cq.ib, &ibcfg);
/* Link rxqs to rxp */
_rxp_add_rxqs(rxp, q0, q1);
diff --git a/drivers/net/bna/bnad.c b/drivers/net/bna/bnad.c
index 8e6ceab9f4d8..7d25a97d33f6 100644
--- a/drivers/net/bna/bnad.c
+++ b/drivers/net/bna/bnad.c
@@ -23,6 +23,7 @@
#include <linux/if_vlan.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
+#include <linux/prefetch.h>
#include "bnad.h"
#include "bna.h"
@@ -501,7 +502,7 @@ bnad_poll_cq(struct bnad *bnad, struct bna_ccb *ccb, int budget)
skb_put(skb, ntohs(cmpl->length));
if (likely
- (bnad->rx_csum &&
+ ((bnad->netdev->features & NETIF_F_RXCSUM) &&
(((flags & BNA_CQ_EF_IPV4) &&
(flags & BNA_CQ_EF_L3_CKSUM_OK)) ||
(flags & BNA_CQ_EF_IPV6)) &&
@@ -2902,23 +2903,20 @@ bnad_netdev_init(struct bnad *bnad, bool using_dac)
{
struct net_device *netdev = bnad->netdev;
- netdev->features |= NETIF_F_IPV6_CSUM;
- netdev->features |= NETIF_F_TSO;
- netdev->features |= NETIF_F_TSO6;
+ netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM |
+ NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+ NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_VLAN_TX;
- netdev->features |= NETIF_F_GRO;
- pr_warn("bna: GRO enabled, using kernel stack GRO\n");
+ netdev->vlan_features = NETIF_F_SG | NETIF_F_HIGHDMA |
+ NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+ NETIF_F_TSO | NETIF_F_TSO6;
- netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+ netdev->features |= netdev->hw_features |
+ NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
if (using_dac)
netdev->features |= NETIF_F_HIGHDMA;
- netdev->features |=
- NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
- NETIF_F_HW_VLAN_FILTER;
-
- netdev->vlan_features = netdev->features;
netdev->mem_start = bnad->mmio_start;
netdev->mem_end = bnad->mmio_start + bnad->mmio_len - 1;
@@ -2969,7 +2967,6 @@ bnad_init(struct bnad *bnad,
bnad->txq_depth = BNAD_TXQ_DEPTH;
bnad->rxq_depth = BNAD_RXQ_DEPTH;
- bnad->rx_csum = true;
bnad->tx_coalescing_timeo = BFI_TX_COALESCING_TIMEO;
bnad->rx_coalescing_timeo = BFI_RX_COALESCING_TIMEO;
diff --git a/drivers/net/bna/bnad.h b/drivers/net/bna/bnad.h
index a89117fa4970..ccdabad0a40c 100644
--- a/drivers/net/bna/bnad.h
+++ b/drivers/net/bna/bnad.h
@@ -237,8 +237,6 @@ struct bnad {
struct bna_rx_config rx_config[BNAD_MAX_RXS];
struct bna_tx_config tx_config[BNAD_MAX_TXS];
- u32 rx_csum;
-
void __iomem *bar0; /* BAR0 address */
struct bna bna;
diff --git a/drivers/net/bna/bnad_ethtool.c b/drivers/net/bna/bnad_ethtool.c
index 142d6047da27..3330cd78da2c 100644
--- a/drivers/net/bna/bnad_ethtool.c
+++ b/drivers/net/bna/bnad_ethtool.c
@@ -237,10 +237,10 @@ bnad_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
cmd->phy_address = 0;
if (netif_carrier_ok(netdev)) {
- cmd->speed = SPEED_10000;
+ ethtool_cmd_speed_set(cmd, SPEED_10000);
cmd->duplex = DUPLEX_FULL;
} else {
- cmd->speed = -1;
+ ethtool_cmd_speed_set(cmd, -1);
cmd->duplex = -1;
}
cmd->transceiver = XCVR_EXTERNAL;
@@ -256,7 +256,8 @@ bnad_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
/* 10G full duplex setting supported only */
if (cmd->autoneg == AUTONEG_ENABLE)
return -EOPNOTSUPP; else {
- if ((cmd->speed == SPEED_10000) && (cmd->duplex == DUPLEX_FULL))
+ if ((ethtool_cmd_speed(cmd) == SPEED_10000)
+ && (cmd->duplex == DUPLEX_FULL))
return 0;
}
@@ -806,61 +807,6 @@ bnad_set_pauseparam(struct net_device *netdev,
return 0;
}
-static u32
-bnad_get_rx_csum(struct net_device *netdev)
-{
- u32 rx_csum;
- struct bnad *bnad = netdev_priv(netdev);
-
- rx_csum = bnad->rx_csum;
- return rx_csum;
-}
-
-static int
-bnad_set_rx_csum(struct net_device *netdev, u32 rx_csum)
-{
- struct bnad *bnad = netdev_priv(netdev);
-
- mutex_lock(&bnad->conf_mutex);
- bnad->rx_csum = rx_csum;
- mutex_unlock(&bnad->conf_mutex);
- return 0;
-}
-
-static int
-bnad_set_tx_csum(struct net_device *netdev, u32 tx_csum)
-{
- struct bnad *bnad = netdev_priv(netdev);
-
- mutex_lock(&bnad->conf_mutex);
- if (tx_csum) {
- netdev->features |= NETIF_F_IP_CSUM;
- netdev->features |= NETIF_F_IPV6_CSUM;
- } else {
- netdev->features &= ~NETIF_F_IP_CSUM;
- netdev->features &= ~NETIF_F_IPV6_CSUM;
- }
- mutex_unlock(&bnad->conf_mutex);
- return 0;
-}
-
-static int
-bnad_set_tso(struct net_device *netdev, u32 tso)
-{
- struct bnad *bnad = netdev_priv(netdev);
-
- mutex_lock(&bnad->conf_mutex);
- if (tso) {
- netdev->features |= NETIF_F_TSO;
- netdev->features |= NETIF_F_TSO6;
- } else {
- netdev->features &= ~NETIF_F_TSO;
- netdev->features &= ~NETIF_F_TSO6;
- }
- mutex_unlock(&bnad->conf_mutex);
- return 0;
-}
-
static void
bnad_get_strings(struct net_device *netdev, u32 stringset, u8 * string)
{
@@ -1256,14 +1202,6 @@ static struct ethtool_ops bnad_ethtool_ops = {
.set_ringparam = bnad_set_ringparam,
.get_pauseparam = bnad_get_pauseparam,
.set_pauseparam = bnad_set_pauseparam,
- .get_rx_csum = bnad_get_rx_csum,
- .set_rx_csum = bnad_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = bnad_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
- .set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
- .set_tso = bnad_set_tso,
.get_strings = bnad_get_strings,
.get_ethtool_stats = bnad_get_ethtool_stats,
.get_sset_count = bnad_get_sset_count
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index d8383a9af9ad..57d3293c65bd 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -3174,7 +3174,7 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
}
skb_checksum_none_assert(skb);
- if (bp->rx_csum &&
+ if ((bp->dev->features & NETIF_F_RXCSUM) &&
(status & (L2_FHDR_STATUS_TCP_SEGMENT |
L2_FHDR_STATUS_UDP_DATAGRAM))) {
@@ -6696,17 +6696,16 @@ bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
if (bp->autoneg & AUTONEG_SPEED) {
cmd->autoneg = AUTONEG_ENABLE;
- }
- else {
+ } else {
cmd->autoneg = AUTONEG_DISABLE;
}
if (netif_carrier_ok(dev)) {
- cmd->speed = bp->line_speed;
+ ethtool_cmd_speed_set(cmd, bp->line_speed);
cmd->duplex = bp->duplex;
}
else {
- cmd->speed = -1;
+ ethtool_cmd_speed_set(cmd, -1);
cmd->duplex = -1;
}
spin_unlock_bh(&bp->phy_lock);
@@ -6758,21 +6757,21 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
advertising |= ADVERTISED_Autoneg;
}
else {
+ u32 speed = ethtool_cmd_speed(cmd);
if (cmd->port == PORT_FIBRE) {
- if ((cmd->speed != SPEED_1000 &&
- cmd->speed != SPEED_2500) ||
+ if ((speed != SPEED_1000 &&
+ speed != SPEED_2500) ||
(cmd->duplex != DUPLEX_FULL))
goto err_out_unlock;
- if (cmd->speed == SPEED_2500 &&
+ if (speed == SPEED_2500 &&
!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE))
goto err_out_unlock;
- }
- else if (cmd->speed == SPEED_1000 || cmd->speed == SPEED_2500)
+ } else if (speed == SPEED_1000 || speed == SPEED_2500)
goto err_out_unlock;
autoneg &= ~AUTONEG_SPEED;
- req_line_speed = cmd->speed;
+ req_line_speed = speed;
req_duplex = cmd->duplex;
advertising = 0;
}
@@ -7189,38 +7188,6 @@ bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
return 0;
}
-static u32
-bnx2_get_rx_csum(struct net_device *dev)
-{
- struct bnx2 *bp = netdev_priv(dev);
-
- return bp->rx_csum;
-}
-
-static int
-bnx2_set_rx_csum(struct net_device *dev, u32 data)
-{
- struct bnx2 *bp = netdev_priv(dev);
-
- bp->rx_csum = data;
- return 0;
-}
-
-static int
-bnx2_set_tso(struct net_device *dev, u32 data)
-{
- struct bnx2 *bp = netdev_priv(dev);
-
- if (data) {
- dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
- if (CHIP_NUM(bp) == CHIP_NUM_5709)
- dev->features |= NETIF_F_TSO6;
- } else
- dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6 |
- NETIF_F_TSO_ECN);
- return 0;
-}
-
static struct {
char string[ETH_GSTRING_LEN];
} bnx2_stats_str_arr[] = {
@@ -7495,82 +7462,74 @@ bnx2_get_ethtool_stats(struct net_device *dev,
}
static int
-bnx2_phys_id(struct net_device *dev, u32 data)
+bnx2_set_phys_id(struct net_device *dev, enum ethtool_phys_id_state state)
{
struct bnx2 *bp = netdev_priv(dev);
- int i;
- u32 save;
- bnx2_set_power_state(bp, PCI_D0);
+ switch (state) {
+ case ETHTOOL_ID_ACTIVE:
+ bnx2_set_power_state(bp, PCI_D0);
+
+ bp->leds_save = REG_RD(bp, BNX2_MISC_CFG);
+ REG_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC);
+ return 1; /* cycle on/off once per second */
+
+ case ETHTOOL_ID_ON:
+ REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE |
+ BNX2_EMAC_LED_1000MB_OVERRIDE |
+ BNX2_EMAC_LED_100MB_OVERRIDE |
+ BNX2_EMAC_LED_10MB_OVERRIDE |
+ BNX2_EMAC_LED_TRAFFIC_OVERRIDE |
+ BNX2_EMAC_LED_TRAFFIC);
+ break;
- if (data == 0)
- data = 2;
+ case ETHTOOL_ID_OFF:
+ REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE);
+ break;
- save = REG_RD(bp, BNX2_MISC_CFG);
- REG_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC);
+ case ETHTOOL_ID_INACTIVE:
+ REG_WR(bp, BNX2_EMAC_LED, 0);
+ REG_WR(bp, BNX2_MISC_CFG, bp->leds_save);
- for (i = 0; i < (data * 2); i++) {
- if ((i % 2) == 0) {
- REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE);
- }
- else {
- REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE |
- BNX2_EMAC_LED_1000MB_OVERRIDE |
- BNX2_EMAC_LED_100MB_OVERRIDE |
- BNX2_EMAC_LED_10MB_OVERRIDE |
- BNX2_EMAC_LED_TRAFFIC_OVERRIDE |
- BNX2_EMAC_LED_TRAFFIC);
- }
- msleep_interruptible(500);
- if (signal_pending(current))
- break;
+ if (!netif_running(dev))
+ bnx2_set_power_state(bp, PCI_D3hot);
+ break;
}
- REG_WR(bp, BNX2_EMAC_LED, 0);
- REG_WR(bp, BNX2_MISC_CFG, save);
-
- if (!netif_running(dev))
- bnx2_set_power_state(bp, PCI_D3hot);
return 0;
}
-static int
-bnx2_set_tx_csum(struct net_device *dev, u32 data)
+static u32
+bnx2_fix_features(struct net_device *dev, u32 features)
{
struct bnx2 *bp = netdev_priv(dev);
- if (CHIP_NUM(bp) == CHIP_NUM_5709)
- return ethtool_op_set_tx_ipv6_csum(dev, data);
- else
- return ethtool_op_set_tx_csum(dev, data);
+ if (!(bp->flags & BNX2_FLAG_CAN_KEEP_VLAN))
+ features |= NETIF_F_HW_VLAN_RX;
+
+ return features;
}
static int
-bnx2_set_flags(struct net_device *dev, u32 data)
+bnx2_set_features(struct net_device *dev, u32 features)
{
struct bnx2 *bp = netdev_priv(dev);
- int rc;
-
- if (!(bp->flags & BNX2_FLAG_CAN_KEEP_VLAN) &&
- !(data & ETH_FLAG_RXVLAN))
- return -EINVAL;
/* TSO with VLAN tag won't work with current firmware */
- if (!(data & ETH_FLAG_TXVLAN))
- return -EINVAL;
-
- rc = ethtool_op_set_flags(dev, data, ETH_FLAG_RXHASH | ETH_FLAG_RXVLAN |
- ETH_FLAG_TXVLAN);
- if (rc)
- return rc;
+ if (features & NETIF_F_HW_VLAN_TX)
+ dev->vlan_features |= (dev->hw_features & NETIF_F_ALL_TSO);
+ else
+ dev->vlan_features &= ~NETIF_F_ALL_TSO;
- if ((!!(data & ETH_FLAG_RXVLAN) !=
+ if ((!!(features & NETIF_F_HW_VLAN_RX) !=
!!(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG)) &&
netif_running(dev)) {
bnx2_netif_stop(bp, false);
+ dev->features = features;
bnx2_set_rx_mode(dev);
bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE, 0, 1);
bnx2_netif_start(bp, false);
+ return 1;
}
return 0;
@@ -7595,18 +7554,11 @@ static const struct ethtool_ops bnx2_ethtool_ops = {
.set_ringparam = bnx2_set_ringparam,
.get_pauseparam = bnx2_get_pauseparam,
.set_pauseparam = bnx2_set_pauseparam,
- .get_rx_csum = bnx2_get_rx_csum,
- .set_rx_csum = bnx2_set_rx_csum,
- .set_tx_csum = bnx2_set_tx_csum,
- .set_sg = ethtool_op_set_sg,
- .set_tso = bnx2_set_tso,
.self_test = bnx2_self_test,
.get_strings = bnx2_get_strings,
- .phys_id = bnx2_phys_id,
+ .set_phys_id = bnx2_set_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 */
@@ -8118,8 +8070,6 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->tx_ring_size = MAX_TX_DESC_CNT;
bnx2_set_rx_ring_size(bp, 255);
- bp->rx_csum = 1;
-
bp->tx_quick_cons_trip_int = 2;
bp->tx_quick_cons_trip = 20;
bp->tx_ticks_int = 18;
@@ -8311,17 +8261,14 @@ static const struct net_device_ops bnx2_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = bnx2_change_mac_addr,
.ndo_change_mtu = bnx2_change_mtu,
+ .ndo_fix_features = bnx2_fix_features,
+ .ndo_set_features = bnx2_set_features,
.ndo_tx_timeout = bnx2_tx_timeout,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = poll_bnx2,
#endif
};
-static inline void vlan_features_add(struct net_device *dev, u32 flags)
-{
- dev->vlan_features |= flags;
-}
-
static int __devinit
bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -8361,20 +8308,17 @@ 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 |
- 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;
- vlan_features_add(dev, NETIF_F_IPV6_CSUM);
- }
- dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
- dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
- vlan_features_add(dev, NETIF_F_TSO | NETIF_F_TSO_ECN);
- if (CHIP_NUM(bp) == CHIP_NUM_5709) {
- dev->features |= NETIF_F_TSO6;
- vlan_features_add(dev, NETIF_F_TSO6);
- }
+ dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
+ NETIF_F_TSO | NETIF_F_TSO_ECN |
+ NETIF_F_RXHASH | NETIF_F_RXCSUM;
+
+ if (CHIP_NUM(bp) == CHIP_NUM_5709)
+ dev->hw_features |= NETIF_F_IPV6_CSUM | NETIF_F_TSO6;
+
+ dev->vlan_features = dev->hw_features;
+ dev->hw_features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ dev->features |= dev->hw_features;
+
if ((rc = register_netdev(dev))) {
dev_err(&pdev->dev, "Cannot register net device\n");
goto error;
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index 68020451dc4f..bf371f6fe154 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -6754,8 +6754,6 @@ struct bnx2 {
u32 rx_max_ring_idx;
u32 rx_max_pg_ring_idx;
- u32 rx_csum;
-
/* TX constants */
int tx_ring_size;
u32 tx_wake_thresh;
@@ -6922,6 +6920,7 @@ struct bnx2 {
u8 num_tx_rings;
u8 num_rx_rings;
+ u32 leds_save;
u32 idle_chk_status_idx;
#ifdef BCM_CNIC
diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/bnx2x/bnx2x.h
index e0fca701d2f3..668a578c49e9 100644
--- a/drivers/net/bnx2x/bnx2x.h
+++ b/drivers/net/bnx2x/bnx2x.h
@@ -1,6 +1,6 @@
/* bnx2x.h: Broadcom Everest network driver.
*
- * Copyright (c) 2007-2010 Broadcom Corporation
+ * Copyright (c) 2007-2011 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
@@ -22,8 +22,8 @@
* (you will need to reboot afterwards) */
/* #define BNX2X_STOP_ON_ERROR */
-#define DRV_MODULE_VERSION "1.62.11-0"
-#define DRV_MODULE_RELDATE "2011/01/31"
+#define DRV_MODULE_VERSION "1.62.12-0"
+#define DRV_MODULE_RELDATE "2011/03/20"
#define BNX2X_BC_VER 0x040200
#define BNX2X_MULTI_QUEUE
@@ -473,7 +473,8 @@ struct bnx2x_fastpath {
#define NUM_RX_BD (RX_DESC_CNT * NUM_RX_RINGS)
#define MAX_RX_BD (NUM_RX_BD - 1)
#define MAX_RX_AVAIL (MAX_RX_DESC_CNT * NUM_RX_RINGS - 2)
-#define MIN_RX_AVAIL 128
+#define MIN_RX_SIZE_TPA 72
+#define MIN_RX_SIZE_NONTPA 10
#define INIT_JUMBO_RX_RING_SIZE MAX_RX_AVAIL
#define INIT_RX_RING_SIZE MAX_RX_AVAIL
#define NEXT_RX_IDX(x) ((((x) & RX_DESC_MASK) == \
@@ -893,6 +894,22 @@ typedef enum {
(&bp->def_status_blk->sp_sb.\
index_values[HC_SP_INDEX_EQ_CONS])
+/* This is a data that will be used to create a link report message.
+ * We will keep the data used for the last link report in order
+ * to prevent reporting the same link parameters twice.
+ */
+struct bnx2x_link_report_data {
+ u16 line_speed; /* Effective line speed */
+ unsigned long link_report_flags;/* BNX2X_LINK_REPORT_XXX flags */
+};
+
+enum {
+ BNX2X_LINK_REPORT_FD, /* Full DUPLEX */
+ BNX2X_LINK_REPORT_LINK_DOWN,
+ BNX2X_LINK_REPORT_RX_FC_ON,
+ BNX2X_LINK_REPORT_TX_FC_ON,
+};
+
struct bnx2x {
/* Fields used in the tx and intr/napi performance paths
* are grouped together in the beginning of the structure
@@ -918,7 +935,6 @@ struct bnx2x {
int tx_ring_size;
- u32 rx_csum;
/* L2 header size + 2*VLANs (8 bytes) + LLC SNAP (8 bytes) */
#define ETH_OVREHEAD (ETH_HLEN + 8 + 8)
#define ETH_MIN_PACKET_SIZE 60
@@ -1026,6 +1042,9 @@ struct bnx2x {
struct link_params link_params;
struct link_vars link_vars;
+ u32 link_cnt;
+ struct bnx2x_link_report_data last_reported_link;
+
struct mdio_if_info mdio;
struct bnx2x_common common;
@@ -1223,6 +1242,10 @@ struct bnx2x {
/* DCBX Negotiation results */
struct dcbx_features dcbx_local_feat;
u32 dcbx_error;
+#ifdef BCM_DCBNL
+ struct dcbx_features dcbx_remote_feat;
+ u32 dcbx_remote_flags;
+#endif
u32 pending_max;
};
@@ -1442,6 +1465,8 @@ struct bnx2x_func_init_params {
#define WAIT_RAMROD_POLL 0x01
#define WAIT_RAMROD_COMMON 0x02
+void bnx2x_read_mf_cfg(struct bnx2x *bp);
+
/* dmae */
void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32);
void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c
index 16581df5ee4e..289044332ed8 100644
--- a/drivers/net/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/bnx2x/bnx2x_cmn.c
@@ -1,6 +1,6 @@
/* bnx2x_cmn.c: Broadcom Everest network driver.
*
- * Copyright (c) 2007-2010 Broadcom Corporation
+ * Copyright (c) 2007-2011 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
@@ -21,12 +21,56 @@
#include <net/ipv6.h>
#include <net/ip6_checksum.h>
#include <linux/firmware.h>
+#include <linux/prefetch.h>
#include "bnx2x_cmn.h"
#include "bnx2x_init.h"
static int bnx2x_setup_irqs(struct bnx2x *bp);
+/**
+ * bnx2x_bz_fp - zero content of the fastpath structure.
+ *
+ * @bp: driver handle
+ * @index: fastpath index to be zeroed
+ *
+ * Makes sure the contents of the bp->fp[index].napi is kept
+ * intact.
+ */
+static inline void bnx2x_bz_fp(struct bnx2x *bp, int index)
+{
+ struct bnx2x_fastpath *fp = &bp->fp[index];
+ struct napi_struct orig_napi = fp->napi;
+ /* bzero bnx2x_fastpath contents */
+ memset(fp, 0, sizeof(*fp));
+
+ /* Restore the NAPI object as it has been already initialized */
+ fp->napi = orig_napi;
+}
+
+/**
+ * bnx2x_move_fp - move content of the fastpath structure.
+ *
+ * @bp: driver handle
+ * @from: source FP index
+ * @to: destination FP index
+ *
+ * Makes sure the contents of the bp->fp[to].napi is kept
+ * intact.
+ */
+static inline void bnx2x_move_fp(struct bnx2x *bp, int from, int to)
+{
+ struct bnx2x_fastpath *from_fp = &bp->fp[from];
+ struct bnx2x_fastpath *to_fp = &bp->fp[to];
+ struct napi_struct orig_napi = to_fp->napi;
+ /* Move bnx2x_fastpath contents */
+ memcpy(to_fp, from_fp, sizeof(*to_fp));
+ to_fp->index = to;
+
+ /* Restore the NAPI object as it has been already initialized */
+ to_fp->napi = orig_napi;
+}
+
/* free skb in the packet ring at pos idx
* return idx of last bd freed
*/
@@ -87,7 +131,7 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fastpath *fp,
/* release skb */
WARN_ON(!skb);
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
tx_buf->first_bd = 0;
tx_buf->skb = NULL;
@@ -265,13 +309,15 @@ static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue,
*/
#define TPA_TSTAMP_OPT_LEN 12
/**
- * Calculate the approximate value of the MSS for this
- * aggregation using the first packet of it.
+ * bnx2x_set_lro_mss - calculate the approximate value of the MSS
*
- * @param bp
- * @param parsing_flags Parsing flags from the START CQE
- * @param len_on_bd Total length of the first packet for the
- * aggregation.
+ * @bp: driver handle
+ * @parsing_flags: parsing flags from the START CQE
+ * @len_on_bd: total length of the first packet for the
+ * aggregation.
+ *
+ * Approximate value of the MSS for this aggregation calculated using
+ * the first packet of it.
*/
static inline u16 bnx2x_set_lro_mss(struct bnx2x *bp, u16 parsing_flags,
u16 len_on_bd)
@@ -419,7 +465,7 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
} else {
DP(NETIF_MSG_RX_STATUS, "Failed to allocate new pages"
" - dropping packet!\n");
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
}
@@ -640,7 +686,7 @@ reuse_rx:
skb_checksum_none_assert(skb);
- if (bp->rx_csum) {
+ if (bp->dev->features & NETIF_F_RXCSUM) {
if (likely(BNX2X_RX_CSUM_OK(cqe)))
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
@@ -758,35 +804,119 @@ u16 bnx2x_get_mf_speed(struct bnx2x *bp)
return line_speed;
}
+/**
+ * bnx2x_fill_report_data - fill link report data to report
+ *
+ * @bp: driver handle
+ * @data: link state to update
+ *
+ * It uses a none-atomic bit operations because is called under the mutex.
+ */
+static inline void bnx2x_fill_report_data(struct bnx2x *bp,
+ struct bnx2x_link_report_data *data)
+{
+ u16 line_speed = bnx2x_get_mf_speed(bp);
+
+ memset(data, 0, sizeof(*data));
+
+ /* Fill the report data: efective line speed */
+ data->line_speed = line_speed;
+
+ /* Link is down */
+ if (!bp->link_vars.link_up || (bp->flags & MF_FUNC_DIS))
+ __set_bit(BNX2X_LINK_REPORT_LINK_DOWN,
+ &data->link_report_flags);
+
+ /* Full DUPLEX */
+ if (bp->link_vars.duplex == DUPLEX_FULL)
+ __set_bit(BNX2X_LINK_REPORT_FD, &data->link_report_flags);
+
+ /* Rx Flow Control is ON */
+ if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX)
+ __set_bit(BNX2X_LINK_REPORT_RX_FC_ON, &data->link_report_flags);
+
+ /* Tx Flow Control is ON */
+ if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX)
+ __set_bit(BNX2X_LINK_REPORT_TX_FC_ON, &data->link_report_flags);
+}
+
+/**
+ * bnx2x_link_report - report link status to OS.
+ *
+ * @bp: driver handle
+ *
+ * Calls the __bnx2x_link_report() under the same locking scheme
+ * as a link/PHY state managing code to ensure a consistent link
+ * reporting.
+ */
+
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;
- }
+ bnx2x_acquire_phy_lock(bp);
+ __bnx2x_link_report(bp);
+ bnx2x_release_phy_lock(bp);
+}
- if (bp->link_vars.link_up) {
- u16 line_speed;
+/**
+ * __bnx2x_link_report - report link status to OS.
+ *
+ * @bp: driver handle
+ *
+ * None atomic inmlementation.
+ * Should be called under the phy_lock.
+ */
+void __bnx2x_link_report(struct bnx2x *bp)
+{
+ struct bnx2x_link_report_data cur_data;
- if (bp->state == BNX2X_STATE_OPEN)
- netif_carrier_on(bp->dev);
- netdev_info(bp->dev, "NIC Link is Up, ");
+ /* reread mf_cfg */
+ if (!CHIP_IS_E1(bp))
+ bnx2x_read_mf_cfg(bp);
- line_speed = bnx2x_get_mf_speed(bp);
+ /* Read the current link report info */
+ bnx2x_fill_report_data(bp, &cur_data);
+
+ /* Don't report link down or exactly the same link status twice */
+ if (!memcmp(&cur_data, &bp->last_reported_link, sizeof(cur_data)) ||
+ (test_bit(BNX2X_LINK_REPORT_LINK_DOWN,
+ &bp->last_reported_link.link_report_flags) &&
+ test_bit(BNX2X_LINK_REPORT_LINK_DOWN,
+ &cur_data.link_report_flags)))
+ return;
+
+ bp->link_cnt++;
+
+ /* We are going to report a new link parameters now -
+ * remember the current data for the next time.
+ */
+ memcpy(&bp->last_reported_link, &cur_data, sizeof(cur_data));
- pr_cont("%d Mbps ", line_speed);
+ if (test_bit(BNX2X_LINK_REPORT_LINK_DOWN,
+ &cur_data.link_report_flags)) {
+ netif_carrier_off(bp->dev);
+ netdev_err(bp->dev, "NIC Link is Down\n");
+ return;
+ } else {
+ netif_carrier_on(bp->dev);
+ netdev_info(bp->dev, "NIC Link is Up, ");
+ pr_cont("%d Mbps ", cur_data.line_speed);
- if (bp->link_vars.duplex == DUPLEX_FULL)
+ if (test_and_clear_bit(BNX2X_LINK_REPORT_FD,
+ &cur_data.link_report_flags))
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) {
+ /* Handle the FC at the end so that only these flags would be
+ * possibly set. This way we may easily check if there is no FC
+ * enabled.
+ */
+ if (cur_data.link_report_flags) {
+ if (test_bit(BNX2X_LINK_REPORT_RX_FC_ON,
+ &cur_data.link_report_flags)) {
pr_cont(", receive ");
- if (bp->link_vars.flow_ctrl &
- BNX2X_FLOW_CTRL_TX)
+ if (test_bit(BNX2X_LINK_REPORT_TX_FC_ON,
+ &cur_data.link_report_flags))
pr_cont("& transmit ");
} else {
pr_cont(", transmit ");
@@ -794,62 +924,9 @@ void bnx2x_link_report(struct bnx2x *bp)
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");
}
}
-/* Returns the number of actually allocated BDs */
-static inline int bnx2x_alloc_rx_bds(struct bnx2x_fastpath *fp,
- int rx_ring_size)
-{
- struct bnx2x *bp = fp->bp;
- u16 ring_prod, cqe_ring_prod;
- int i;
-
- fp->rx_comp_cons = 0;
- cqe_ring_prod = ring_prod = 0;
- for (i = 0; i < 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, fp->index);
- 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;
- /* Limit the CQE producer by the CQE ring size */
- fp->rx_comp_prod = min_t(u16, NUM_RCQ_RINGS*RCQ_DESC_CNT,
- cqe_ring_prod);
- fp->rx_pkt = fp->rx_calls = 0;
-
- return i;
-}
-
-static inline void bnx2x_alloc_rx_bd_ring(struct bnx2x_fastpath *fp)
-{
- struct bnx2x *bp = fp->bp;
- int rx_ring_size = bp->rx_ring_size ? bp->rx_ring_size :
- MAX_RX_AVAIL/bp->num_queues;
-
- rx_ring_size = max_t(int, MIN_RX_AVAIL, rx_ring_size);
-
- bnx2x_alloc_rx_bds(fp, rx_ring_size);
-
- /* Warning!
- * this will generate an interrupt (to the TSTORM)
- * must only be done after chip is initialized
- */
- bnx2x_update_rx_prod(bp, fp, fp->rx_bd_prod, fp->rx_comp_prod,
- fp->rx_sge_prod);
-}
-
void bnx2x_init_rx_rings(struct bnx2x *bp)
{
int func = BP_FUNC(bp);
@@ -858,6 +935,7 @@ void bnx2x_init_rx_rings(struct bnx2x *bp)
u16 ring_prod;
int i, j;
+ /* Allocate TPA resources */
for_each_rx_queue(bp, j) {
struct bnx2x_fastpath *fp = &bp->fp[j];
@@ -865,6 +943,7 @@ void bnx2x_init_rx_rings(struct bnx2x *bp)
"mtu %d rx_buf_size %d\n", bp->dev->mtu, fp->rx_buf_size);
if (!fp->disable_tpa) {
+ /* Fill the per-aggregation pool */
for (i = 0; i < max_agg_queues; i++) {
fp->tpa_pool[i].skb =
netdev_alloc_skb(bp->dev, fp->rx_buf_size);
@@ -919,13 +998,13 @@ void bnx2x_init_rx_rings(struct bnx2x *bp)
fp->rx_bd_cons = 0;
- bnx2x_set_next_page_rx_bd(fp);
-
- /* CQ ring */
- bnx2x_set_next_page_rx_cq(fp);
-
- /* Allocate BDs and initialize BD ring */
- bnx2x_alloc_rx_bd_ring(fp);
+ /* Activate BD ring */
+ /* Warning!
+ * this will generate an interrupt (to the TSTORM)
+ * must only be done after chip is initialized
+ */
+ bnx2x_update_rx_prod(bp, fp, fp->rx_bd_prod, fp->rx_comp_prod,
+ fp->rx_sge_prod);
if (j != 0)
continue;
@@ -959,27 +1038,40 @@ static void bnx2x_free_tx_skbs(struct bnx2x *bp)
}
}
+static void bnx2x_free_rx_bds(struct bnx2x_fastpath *fp)
+{
+ struct bnx2x *bp = fp->bp;
+ int i;
+
+ /* ring wasn't allocated */
+ if (fp->rx_buf_ring == NULL)
+ return;
+
+ 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),
+ fp->rx_buf_size, DMA_FROM_DEVICE);
+
+ rx_buf->skb = NULL;
+ dev_kfree_skb(skb);
+ }
+}
+
static void bnx2x_free_rx_skbs(struct bnx2x *bp)
{
- int i, j;
+ int j;
for_each_rx_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;
+ bnx2x_free_rx_bds(fp);
- dma_unmap_single(&bp->pdev->dev,
- dma_unmap_addr(rx_buf, mapping),
- fp->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 :
@@ -1345,29 +1437,47 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD;
+ /* Set the initial link reported state to link down */
+ bnx2x_acquire_phy_lock(bp);
+ memset(&bp->last_reported_link, 0, sizeof(bp->last_reported_link));
+ __set_bit(BNX2X_LINK_REPORT_LINK_DOWN,
+ &bp->last_reported_link.link_report_flags);
+ bnx2x_release_phy_lock(bp);
+
/* must be called before memory allocation and HW init */
bnx2x_ilt_set_info(bp);
+ /* zero fastpath structures preserving invariants like napi which are
+ * allocated only once
+ */
+ for_each_queue(bp, i)
+ bnx2x_bz_fp(bp, i);
+
/* Set the receive queues buffer size */
bnx2x_set_rx_buf_size(bp);
+ for_each_queue(bp, i)
+ bnx2x_fp(bp, i, disable_tpa) =
+ ((bp->flags & TPA_ENABLE_FLAG) == 0);
+
+#ifdef BCM_CNIC
+ /* We don't want TPA on FCoE L2 ring */
+ bnx2x_fcoe(bp, disable_tpa) = 1;
+#endif
+
if (bnx2x_alloc_mem(bp))
return -ENOMEM;
+ /* As long as bnx2x_alloc_mem() may possibly update
+ * bp->num_queues, bnx2x_set_real_num_queues() should always
+ * come after it.
+ */
rc = bnx2x_set_real_num_queues(bp);
if (rc) {
BNX2X_ERR("Unable to set real_num_queues\n");
goto load_error0;
}
- for_each_queue(bp, i)
- bnx2x_fp(bp, i, disable_tpa) =
- ((bp->flags & TPA_ENABLE_FLAG) == 0);
-
-#ifdef BCM_CNIC
- /* We don't want TPA on FCoE L2 ring */
- bnx2x_fcoe(bp, disable_tpa) = 1;
-#endif
bnx2x_napi_enable(bp);
/* Send LOAD_REQUEST command to MCP
@@ -1976,12 +2086,11 @@ static inline void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, u32 *parsing_data,
}
/**
- * Update PBD in GSO case.
+ * bnx2x_set_pbd_gso - update PBD in GSO case.
*
- * @param skb
- * @param tx_start_bd
- * @param pbd
- * @param xmit_type
+ * @skb: packet skb
+ * @pbd: parse BD
+ * @xmit_type: xmit flags
*/
static inline void bnx2x_set_pbd_gso(struct sk_buff *skb,
struct eth_tx_parse_bd_e1x *pbd,
@@ -2008,13 +2117,14 @@ static inline void bnx2x_set_pbd_gso(struct sk_buff *skb,
}
/**
+ * bnx2x_set_pbd_csum_e2 - update PBD with checksum and return header length
*
- * @param skb
- * @param tx_start_bd
- * @param pbd_e2
- * @param xmit_type
+ * @bp: driver handle
+ * @skb: packet skb
+ * @parsing_data: data to be updated
+ * @xmit_type: xmit flags
*
- * @return header len
+ * 57712 related
*/
static inline u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb,
u32 *parsing_data, u32 xmit_type)
@@ -2039,13 +2149,12 @@ static inline u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb,
}
/**
+ * bnx2x_set_pbd_csum - update PBD with checksum and return header length
*
- * @param skb
- * @param tx_start_bd
- * @param pbd
- * @param xmit_type
- *
- * @return Header length
+ * @bp: driver handle
+ * @skb: packet skb
+ * @pbd: parse BD to be updated
+ * @xmit_type: xmit flags
*/
static inline u8 bnx2x_set_pbd_csum(struct bnx2x *bp, struct sk_buff *skb,
struct eth_tx_parse_bd_e1x *pbd,
@@ -2393,6 +2502,232 @@ int bnx2x_change_mac_addr(struct net_device *dev, void *p)
return 0;
}
+static void bnx2x_free_fp_mem_at(struct bnx2x *bp, int fp_index)
+{
+ union host_hc_status_block *sb = &bnx2x_fp(bp, fp_index, status_blk);
+ struct bnx2x_fastpath *fp = &bp->fp[fp_index];
+
+ /* Common */
+#ifdef BCM_CNIC
+ if (IS_FCOE_IDX(fp_index)) {
+ memset(sb, 0, sizeof(union host_hc_status_block));
+ fp->status_blk_mapping = 0;
+
+ } else {
+#endif
+ /* status blocks */
+ if (CHIP_IS_E2(bp))
+ BNX2X_PCI_FREE(sb->e2_sb,
+ bnx2x_fp(bp, fp_index,
+ status_blk_mapping),
+ sizeof(struct host_hc_status_block_e2));
+ else
+ BNX2X_PCI_FREE(sb->e1x_sb,
+ bnx2x_fp(bp, fp_index,
+ status_blk_mapping),
+ sizeof(struct host_hc_status_block_e1x));
+#ifdef BCM_CNIC
+ }
+#endif
+ /* Rx */
+ if (!skip_rx_queue(bp, fp_index)) {
+ bnx2x_free_rx_bds(fp);
+
+ /* fastpath rx rings: rx_buf rx_desc rx_comp */
+ BNX2X_FREE(bnx2x_fp(bp, fp_index, rx_buf_ring));
+ BNX2X_PCI_FREE(bnx2x_fp(bp, fp_index, rx_desc_ring),
+ bnx2x_fp(bp, fp_index, rx_desc_mapping),
+ sizeof(struct eth_rx_bd) * NUM_RX_BD);
+
+ BNX2X_PCI_FREE(bnx2x_fp(bp, fp_index, rx_comp_ring),
+ bnx2x_fp(bp, fp_index, rx_comp_mapping),
+ sizeof(struct eth_fast_path_rx_cqe) *
+ NUM_RCQ_BD);
+
+ /* SGE ring */
+ BNX2X_FREE(bnx2x_fp(bp, fp_index, rx_page_ring));
+ BNX2X_PCI_FREE(bnx2x_fp(bp, fp_index, rx_sge_ring),
+ bnx2x_fp(bp, fp_index, rx_sge_mapping),
+ BCM_PAGE_SIZE * NUM_RX_SGE_PAGES);
+ }
+
+ /* Tx */
+ if (!skip_tx_queue(bp, fp_index)) {
+ /* fastpath tx rings: tx_buf tx_desc */
+ BNX2X_FREE(bnx2x_fp(bp, fp_index, tx_buf_ring));
+ BNX2X_PCI_FREE(bnx2x_fp(bp, fp_index, tx_desc_ring),
+ bnx2x_fp(bp, fp_index, tx_desc_mapping),
+ sizeof(union eth_tx_bd_types) * NUM_TX_BD);
+ }
+ /* end of fastpath */
+}
+
+void bnx2x_free_fp_mem(struct bnx2x *bp)
+{
+ int i;
+ for_each_queue(bp, i)
+ bnx2x_free_fp_mem_at(bp, i);
+}
+
+static inline void set_sb_shortcuts(struct bnx2x *bp, int index)
+{
+ union host_hc_status_block status_blk = bnx2x_fp(bp, index, status_blk);
+ if (CHIP_IS_E2(bp)) {
+ bnx2x_fp(bp, index, sb_index_values) =
+ (__le16 *)status_blk.e2_sb->sb.index_values;
+ bnx2x_fp(bp, index, sb_running_index) =
+ (__le16 *)status_blk.e2_sb->sb.running_index;
+ } else {
+ bnx2x_fp(bp, index, sb_index_values) =
+ (__le16 *)status_blk.e1x_sb->sb.index_values;
+ bnx2x_fp(bp, index, sb_running_index) =
+ (__le16 *)status_blk.e1x_sb->sb.running_index;
+ }
+}
+
+static int bnx2x_alloc_fp_mem_at(struct bnx2x *bp, int index)
+{
+ union host_hc_status_block *sb;
+ struct bnx2x_fastpath *fp = &bp->fp[index];
+ int ring_size = 0;
+
+ /* if rx_ring_size specified - use it */
+ int rx_ring_size = bp->rx_ring_size ? bp->rx_ring_size :
+ MAX_RX_AVAIL/bp->num_queues;
+
+ /* allocate at least number of buffers required by FW */
+ rx_ring_size = max_t(int, fp->disable_tpa ? MIN_RX_SIZE_NONTPA :
+ MIN_RX_SIZE_TPA,
+ rx_ring_size);
+
+ bnx2x_fp(bp, index, bp) = bp;
+ bnx2x_fp(bp, index, index) = index;
+
+ /* Common */
+ sb = &bnx2x_fp(bp, index, status_blk);
+#ifdef BCM_CNIC
+ if (!IS_FCOE_IDX(index)) {
+#endif
+ /* status blocks */
+ if (CHIP_IS_E2(bp))
+ BNX2X_PCI_ALLOC(sb->e2_sb,
+ &bnx2x_fp(bp, index, status_blk_mapping),
+ sizeof(struct host_hc_status_block_e2));
+ else
+ BNX2X_PCI_ALLOC(sb->e1x_sb,
+ &bnx2x_fp(bp, index, status_blk_mapping),
+ sizeof(struct host_hc_status_block_e1x));
+#ifdef BCM_CNIC
+ }
+#endif
+ set_sb_shortcuts(bp, index);
+
+ /* Tx */
+ if (!skip_tx_queue(bp, index)) {
+ /* fastpath tx rings: tx_buf tx_desc */
+ BNX2X_ALLOC(bnx2x_fp(bp, index, tx_buf_ring),
+ sizeof(struct sw_tx_bd) * NUM_TX_BD);
+ BNX2X_PCI_ALLOC(bnx2x_fp(bp, index, tx_desc_ring),
+ &bnx2x_fp(bp, index, tx_desc_mapping),
+ sizeof(union eth_tx_bd_types) * NUM_TX_BD);
+ }
+
+ /* Rx */
+ if (!skip_rx_queue(bp, index)) {
+ /* fastpath rx rings: rx_buf rx_desc rx_comp */
+ BNX2X_ALLOC(bnx2x_fp(bp, index, rx_buf_ring),
+ sizeof(struct sw_rx_bd) * NUM_RX_BD);
+ BNX2X_PCI_ALLOC(bnx2x_fp(bp, index, rx_desc_ring),
+ &bnx2x_fp(bp, index, rx_desc_mapping),
+ sizeof(struct eth_rx_bd) * NUM_RX_BD);
+
+ BNX2X_PCI_ALLOC(bnx2x_fp(bp, index, rx_comp_ring),
+ &bnx2x_fp(bp, index, rx_comp_mapping),
+ sizeof(struct eth_fast_path_rx_cqe) *
+ NUM_RCQ_BD);
+
+ /* SGE ring */
+ BNX2X_ALLOC(bnx2x_fp(bp, index, rx_page_ring),
+ sizeof(struct sw_rx_page) * NUM_RX_SGE);
+ BNX2X_PCI_ALLOC(bnx2x_fp(bp, index, rx_sge_ring),
+ &bnx2x_fp(bp, index, rx_sge_mapping),
+ BCM_PAGE_SIZE * NUM_RX_SGE_PAGES);
+ /* RX BD ring */
+ bnx2x_set_next_page_rx_bd(fp);
+
+ /* CQ ring */
+ bnx2x_set_next_page_rx_cq(fp);
+
+ /* BDs */
+ ring_size = bnx2x_alloc_rx_bds(fp, rx_ring_size);
+ if (ring_size < rx_ring_size)
+ goto alloc_mem_err;
+ }
+
+ return 0;
+
+/* handles low memory cases */
+alloc_mem_err:
+ BNX2X_ERR("Unable to allocate full memory for queue %d (size %d)\n",
+ index, ring_size);
+ /* FW will drop all packets if queue is not big enough,
+ * In these cases we disable the queue
+ * Min size diferent for TPA and non-TPA queues
+ */
+ if (ring_size < (fp->disable_tpa ?
+ MIN_RX_SIZE_NONTPA : MIN_RX_SIZE_TPA)) {
+ /* release memory allocated for this queue */
+ bnx2x_free_fp_mem_at(bp, index);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+int bnx2x_alloc_fp_mem(struct bnx2x *bp)
+{
+ int i;
+
+ /**
+ * 1. Allocate FP for leading - fatal if error
+ * 2. {CNIC} Allocate FCoE FP - fatal if error
+ * 3. Allocate RSS - fix number of queues if error
+ */
+
+ /* leading */
+ if (bnx2x_alloc_fp_mem_at(bp, 0))
+ return -ENOMEM;
+#ifdef BCM_CNIC
+ /* FCoE */
+ if (bnx2x_alloc_fp_mem_at(bp, FCOE_IDX))
+ return -ENOMEM;
+#endif
+ /* RSS */
+ for_each_nondefault_eth_queue(bp, i)
+ if (bnx2x_alloc_fp_mem_at(bp, i))
+ break;
+
+ /* handle memory failures */
+ if (i != BNX2X_NUM_ETH_QUEUES(bp)) {
+ int delta = BNX2X_NUM_ETH_QUEUES(bp) - i;
+
+ WARN_ON(delta < 0);
+#ifdef BCM_CNIC
+ /**
+ * move non eth FPs next to last eth FP
+ * must be done in that order
+ * FCOE_IDX < FWD_IDX < OOO_IDX
+ */
+
+ /* move FCoE fp */
+ bnx2x_move_fp(bp, FCOE_IDX, FCOE_IDX - delta);
+#endif
+ bp->num_queues -= delta;
+ BNX2X_ERR("Adjusted num of queues from %d to %d\n",
+ bp->num_queues + delta, bp->num_queues);
+ }
+
+ return 0;
+}
static int bnx2x_setup_irqs(struct bnx2x *bp)
{
@@ -2457,11 +2792,21 @@ alloc_err:
}
+static int bnx2x_reload_if_running(struct net_device *dev)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+
+ if (unlikely(!netif_running(dev)))
+ return 0;
+
+ bnx2x_nic_unload(bp, UNLOAD_NORMAL);
+ return bnx2x_nic_load(bp, LOAD_NORMAL);
+}
+
/* 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");
@@ -2478,12 +2823,55 @@ int bnx2x_change_mtu(struct net_device *dev, int new_mtu)
*/
dev->mtu = new_mtu;
- if (netif_running(dev)) {
- bnx2x_nic_unload(bp, UNLOAD_NORMAL);
- rc = bnx2x_nic_load(bp, LOAD_NORMAL);
+ return bnx2x_reload_if_running(dev);
+}
+
+u32 bnx2x_fix_features(struct net_device *dev, u32 features)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+
+ /* TPA requires Rx CSUM offloading */
+ if (!(features & NETIF_F_RXCSUM) || bp->disable_tpa)
+ features &= ~NETIF_F_LRO;
+
+ return features;
+}
+
+int bnx2x_set_features(struct net_device *dev, u32 features)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ u32 flags = bp->flags;
+ bool bnx2x_reload = false;
+
+ if (features & NETIF_F_LRO)
+ flags |= TPA_ENABLE_FLAG;
+ else
+ flags &= ~TPA_ENABLE_FLAG;
+
+ if (features & NETIF_F_LOOPBACK) {
+ if (bp->link_params.loopback_mode != LOOPBACK_BMAC) {
+ bp->link_params.loopback_mode = LOOPBACK_BMAC;
+ bnx2x_reload = true;
+ }
+ } else {
+ if (bp->link_params.loopback_mode != LOOPBACK_NONE) {
+ bp->link_params.loopback_mode = LOOPBACK_NONE;
+ bnx2x_reload = true;
+ }
}
- return rc;
+ if (flags ^ bp->flags) {
+ bp->flags = flags;
+ bnx2x_reload = true;
+ }
+
+ if (bnx2x_reload) {
+ if (bp->recovery_state == BNX2X_RECOVERY_DONE)
+ return bnx2x_reload_if_running(dev);
+ /* else: bnx2x_nic_load() will be called at end of recovery */
+ }
+
+ return 0;
}
void bnx2x_tx_timeout(struct net_device *dev)
diff --git a/drivers/net/bnx2x/bnx2x_cmn.h b/drivers/net/bnx2x/bnx2x_cmn.h
index ef37b98d6146..1a3545bd8a92 100644
--- a/drivers/net/bnx2x/bnx2x_cmn.h
+++ b/drivers/net/bnx2x/bnx2x_cmn.h
@@ -1,6 +1,6 @@
/* bnx2x_cmn.h: Broadcom Everest network driver.
*
- * Copyright (c) 2007-2010 Broadcom Corporation
+ * Copyright (c) 2007-2011 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
@@ -25,260 +25,277 @@
extern int num_queues;
+/************************ Macros ********************************/
+#define BNX2X_PCI_FREE(x, y, size) \
+ do { \
+ if (x) { \
+ dma_free_coherent(&bp->pdev->dev, size, (void *)x, y); \
+ x = NULL; \
+ y = 0; \
+ } \
+ } while (0)
+
+#define BNX2X_FREE(x) \
+ do { \
+ if (x) { \
+ kfree((void *)x); \
+ x = NULL; \
+ } \
+ } while (0)
+
+#define BNX2X_PCI_ALLOC(x, y, size) \
+ do { \
+ x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \
+ if (x == NULL) \
+ goto alloc_mem_err; \
+ memset((void *)x, 0, size); \
+ } while (0)
+
+#define BNX2X_ALLOC(x, size) \
+ do { \
+ x = kzalloc(size, GFP_KERNEL); \
+ if (x == NULL) \
+ goto alloc_mem_err; \
+ } while (0)
+
/*********************** Interfaces ****************************
* Functions that need to be implemented by each driver version
*/
/**
- * Initialize link parameters structure variables.
- *
- * @param bp
- * @param load_mode
+ * bnx2x_initial_phy_init - initialize link parameters structure variables.
*
- * @return u8
+ * @bp: driver handle
+ * @load_mode: current mode
*/
u8 bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode);
/**
- * Configure hw according to link parameters structure.
+ * bnx2x_link_set - configure hw according to link parameters structure.
*
- * @param bp
+ * @bp: driver handle
*/
void bnx2x_link_set(struct bnx2x *bp);
/**
- * Query link status
+ * bnx2x_link_test - query link status.
*
- * @param bp
- * @param is_serdes
+ * @bp: driver handle
+ * @is_serdes: bool
*
- * @return 0 - link is UP
+ * Returns 0 if link is UP.
*/
u8 bnx2x_link_test(struct bnx2x *bp, u8 is_serdes);
/**
- * Handles link status change
+ * bnx2x__link_status_update - handles link status change.
*
- * @param bp
+ * @bp: driver handle
*/
void bnx2x__link_status_update(struct bnx2x *bp);
/**
- * Report link status to upper layer
- *
- * @param bp
+ * bnx2x_link_report - report link status to upper layer.
*
- * @return int
+ * @bp: driver handle
*/
void bnx2x_link_report(struct bnx2x *bp);
+/* None-atomic version of bnx2x_link_report() */
+void __bnx2x_link_report(struct bnx2x *bp);
+
/**
- * calculates MF speed according to current linespeed and MF
- * configuration
+ * bnx2x_get_mf_speed - calculate MF speed.
*
- * @param bp
+ * @bp: driver handle
*
- * @return u16
+ * Takes into account current linespeed and MF configuration.
*/
u16 bnx2x_get_mf_speed(struct bnx2x *bp);
/**
- * MSI-X slowpath interrupt handler
- *
- * @param irq
- * @param dev_instance
+ * bnx2x_msix_sp_int - MSI-X slowpath interrupt handler
*
- * @return irqreturn_t
+ * @irq: irq number
+ * @dev_instance: private instance
*/
irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance);
/**
- * non MSI-X interrupt handler
+ * bnx2x_interrupt - non MSI-X interrupt handler
*
- * @param irq
- * @param dev_instance
- *
- * @return irqreturn_t
+ * @irq: irq number
+ * @dev_instance: private instance
*/
irqreturn_t bnx2x_interrupt(int irq, void *dev_instance);
#ifdef BCM_CNIC
/**
- * Send command to cnic driver
+ * bnx2x_cnic_notify - send command to cnic driver
*
- * @param bp
- * @param cmd
+ * @bp: driver handle
+ * @cmd: command
*/
int bnx2x_cnic_notify(struct bnx2x *bp, int cmd);
/**
- * Provides cnic information for proper interrupt handling
+ * bnx2x_setup_cnic_irq_info - provides cnic with IRQ information
*
- * @param bp
+ * @bp: driver handle
*/
void bnx2x_setup_cnic_irq_info(struct bnx2x *bp);
#endif
/**
- * Enable HW interrupts.
+ * bnx2x_int_enable - enable HW interrupts.
*
- * @param bp
+ * @bp: driver handle
*/
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.
+ * bnx2x_int_disable_sync - disable interrupts.
*
- * @param bp
- * @param disable_hw if true, disable HW interrupts.
+ * @bp: driver handle
+ * @disable_hw: true, disable HW interrupts.
+ *
+ * This function ensures that there are no
+ * ISRs or SP DPCs (sp_task) are running after it returns.
*/
void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw);
/**
- * Loads device firmware
+ * bnx2x_init_firmware - loads device firmware
*
- * @param bp
- *
- * @return int
+ * @bp: driver handle
*/
int bnx2x_init_firmware(struct bnx2x *bp);
/**
- * Init HW blocks according to current initialization stage:
- * COMMON, PORT or FUNCTION.
- *
- * @param bp
- * @param load_code: COMMON, PORT or FUNCTION
+ * bnx2x_init_hw - init HW blocks according to current initialization stage.
*
- * @return int
+ * @bp: driver handle
+ * @load_code: COMMON, PORT or FUNCTION
*/
int bnx2x_init_hw(struct bnx2x *bp, u32 load_code);
/**
- * Init driver internals:
+ * bnx2x_nic_init - init driver internals.
+ *
+ * @bp: driver handle
+ * @load_code: COMMON, PORT or FUNCTION
+ *
+ * Initializes:
* - 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.
+ * bnx2x_alloc_mem - allocate driver's memory.
*
- * @param bp
- *
- * @return int
+ * @bp: driver handle
*/
int bnx2x_alloc_mem(struct bnx2x *bp);
/**
- * Release driver's memory.
+ * bnx2x_free_mem - release driver's memory.
*
- * @param bp
+ * @bp: driver handle
*/
void bnx2x_free_mem(struct bnx2x *bp);
/**
- * Setup eth Client.
- *
- * @param bp
- * @param fp
- * @param is_leading
+ * bnx2x_setup_client - setup eth client.
*
- * @return int
+ * @bp: driver handle
+ * @fp: pointer to fastpath structure
+ * @is_leading: boolean
*/
int bnx2x_setup_client(struct bnx2x *bp, struct bnx2x_fastpath *fp,
int is_leading);
/**
- * Set number of queues according to mode
- *
- * @param bp
+ * bnx2x_set_num_queues - set number of queues according to mode.
*
+ * @bp: driver handle
*/
void bnx2x_set_num_queues(struct bnx2x *bp);
/**
- * Cleanup chip internals:
+ * bnx2x_chip_cleanup - cleanup chip internals.
+ *
+ * @bp: driver handle
+ * @unload_mode: COMMON, PORT, FUNCTION
+ *
* - Cleanup MAC configuration.
- * - Close clients.
+ * - Closes 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
+ * bnx2x_acquire_hw_lock - acquire HW lock.
*
- * @return int
+ * @bp: driver handle
+ * @resource: resource bit which was locked
*/
int bnx2x_acquire_hw_lock(struct bnx2x *bp, u32 resource);
/**
- * Release HW lock.
+ * bnx2x_release_hw_lock - release HW lock.
*
- * @param bp driver handle
- * @param resource Resource bit which was locked
- *
- * @return int
+ * @bp: driver handle
+ * @resource: resource bit which was locked
*/
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.
+ * bnx2x_set_eth_mac - configure eth MAC address in the HW
+ *
+ * @bp: driver handle
+ * @set: set or clear
*
- * @param bp driver handle
- * @param set
+ * Configures according to the value in netdev->dev_addr.
*/
void bnx2x_set_eth_mac(struct bnx2x *bp, int set);
#ifdef BCM_CNIC
/**
- * Set/Clear FIP MAC(s) at the next enties in the CAM after the ETH
- * MAC(s). This function will wait until the ramdord completion
- * returns.
+ * bnx2x_set_fip_eth_mac_addr - Set/Clear FIP MAC(s)
*
- * @param bp driver handle
- * @param set set or clear the CAM entry
+ * @bp: driver handle
+ * @set: set or clear the CAM entry
*
- * @return 0 if cussess, -ENODEV if ramrod doesn't return.
+ * Used next enties in the CAM after the ETH MAC(s).
+ * This function will wait until the ramdord completion returns.
+ * Return 0 if cussess, -ENODEV if ramrod doesn't return.
*/
int bnx2x_set_fip_eth_mac_addr(struct bnx2x *bp, int set);
/**
- * Set/Clear ALL_ENODE mcast MAC.
+ * bnx2x_set_all_enode_macs - Set/Clear ALL_ENODE mcast MAC.
*
- * @param bp
- * @param set
- *
- * @return int
+ * @bp: driver handle
+ * @set: set or clear
*/
int bnx2x_set_all_enode_macs(struct bnx2x *bp, int set);
#endif
/**
- * Set MAC filtering configurations.
+ * bnx2x_set_rx_mode - set MAC filtering configurations.
*
- * @remarks called with netif_tx_lock from dev_mcast.c
+ * @dev: netdevice
*
- * @param dev net_device
+ * called with netif_tx_lock from dev_mcast.c
*/
void bnx2x_set_rx_mode(struct net_device *dev);
/**
- * Configure MAC filtering rules in a FW.
+ * bnx2x_set_storm_rx_mode - configure MAC filtering rules in a FW.
*
- * @param bp driver handle
+ * @bp: driver handle
*/
void bnx2x_set_storm_rx_mode(struct bnx2x *bp);
@@ -290,63 +307,59 @@ bool bnx2x_reset_is_done(struct bnx2x *bp);
void bnx2x_disable_close_the_gate(struct bnx2x *bp);
/**
- * Perform statistics handling according to event
+ * bnx2x_stats_handle - perform statistics handling according to event.
*
- * @param bp driver handle
- * @param event bnx2x_stats_event
+ * @bp: driver handle
+ * @event: bnx2x_stats_event
*/
void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event);
/**
- * Handle ramrods completion
+ * bnx2x_sp_event - handle ramrods completion.
*
- * @param fp fastpath handle for the event
- * @param rr_cqe eth_rx_cqe
+ * @fp: fastpath handle for the event
+ * @rr_cqe: eth_rx_cqe
*/
void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe);
/**
- * Init/halt function before/after sending
- * CLIENT_SETUP/CFC_DEL for the first/last client.
+ * bnx2x_func_start - init function
*
- * @param bp
+ * @bp: driver handle
*
- * @return int
+ * Must be called before sending CLIENT_SETUP for the first client.
*/
int bnx2x_func_start(struct bnx2x *bp);
/**
- * Prepare ILT configurations according to current driver
- * parameters.
+ * bnx2x_ilt_set_info - prepare ILT configurations.
*
- * @param bp
+ * @bp: driver handle
*/
void bnx2x_ilt_set_info(struct bnx2x *bp);
/**
- * Inintialize dcbx protocol
+ * bnx2x_dcbx_init - initialize dcbx protocol.
*
- * @param bp
+ * @bp: driver handle
*/
void bnx2x_dcbx_init(struct bnx2x *bp);
/**
- * Set power state to the requested value. Currently only D0 and
- * D3hot are supported.
+ * bnx2x_set_power_state - set power state to the requested value.
*
- * @param bp
- * @param state D0 or D3hot
+ * @bp: driver handle
+ * @state: required state D0 or D3hot
*
- * @return int
+ * Currently only D0 and D3hot are supported.
*/
int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state);
/**
- * Updates MAX part of MF configuration in HW
- * (if required)
+ * bnx2x_update_max_mf_config - update MAX part of MF configuration in HW.
*
- * @param bp
- * @param value
+ * @bp: driver handle
+ * @value: new value
*/
void bnx2x_update_max_mf_config(struct bnx2x *bp, u32 value);
@@ -377,83 +390,72 @@ int bnx2x_resume(struct pci_dev *pdev);
/* Release IRQ vectors */
void bnx2x_free_irq(struct bnx2x *bp);
+void bnx2x_free_fp_mem(struct bnx2x *bp);
+int bnx2x_alloc_fp_mem(struct bnx2x *bp);
+
void bnx2x_init_rx_rings(struct bnx2x *bp);
void bnx2x_free_skbs(struct bnx2x *bp);
void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw);
void bnx2x_netif_start(struct bnx2x *bp);
/**
- * Fill msix_table, request vectors, update num_queues according
- * to number of available vectors
+ * bnx2x_enable_msix - set msix configuration.
*
- * @param bp
+ * @bp: driver handle
*
- * @return int
+ * fills msix_table, requests vectors, updates num_queues
+ * according to number of available vectors.
*/
int bnx2x_enable_msix(struct bnx2x *bp);
/**
- * Request msi mode from OS, updated internals accordingly
+ * bnx2x_enable_msi - request msi mode from OS, updated internals accordingly
*
- * @param bp
- *
- * @return int
+ * @bp: driver handle
*/
int bnx2x_enable_msi(struct bnx2x *bp);
/**
- * NAPI callback
+ * bnx2x_poll - NAPI callback
*
- * @param napi
- * @param budget
+ * @napi: napi structure
+ * @budget:
*
- * @return int
*/
int bnx2x_poll(struct napi_struct *napi, int budget);
/**
- * Allocate/release memories outsize main driver structure
- *
- * @param bp
+ * bnx2x_alloc_mem_bp - allocate memories outsize main driver structure
*
- * @return int
+ * @bp: driver handle
*/
int __devinit bnx2x_alloc_mem_bp(struct bnx2x *bp);
-void bnx2x_free_mem_bp(struct bnx2x *bp);
/**
- * Change mtu netdev callback
- *
- * @param dev
- * @param new_mtu
+ * bnx2x_free_mem_bp - release memories outsize main driver structure
*
- * @return int
+ * @bp: driver handle
*/
-int bnx2x_change_mtu(struct net_device *dev, int new_mtu);
+void bnx2x_free_mem_bp(struct bnx2x *bp);
/**
- * tx timeout netdev callback
+ * bnx2x_change_mtu - change mtu netdev callback
*
- * @param dev
- * @param new_mtu
+ * @dev: net device
+ * @new_mtu: requested mtu
*
- * @return int
*/
-void bnx2x_tx_timeout(struct net_device *dev);
+int bnx2x_change_mtu(struct net_device *dev, int new_mtu);
+
+u32 bnx2x_fix_features(struct net_device *dev, u32 features);
+int bnx2x_set_features(struct net_device *dev, u32 features);
-#ifdef BCM_VLAN
/**
- * vlan rx register netdev callback
- *
- * @param dev
- * @param new_mtu
+ * bnx2x_tx_timeout - tx timeout netdev callback
*
- * @return int
+ * @dev: net device
*/
-void bnx2x_vlan_rx_register(struct net_device *dev,
- struct vlan_group *vlgrp);
-
-#endif
+void bnx2x_tx_timeout(struct net_device *dev);
static inline void bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp)
{
@@ -705,7 +707,7 @@ static inline int bnx2x_has_rx_work(struct bnx2x_fastpath *fp)
/**
* disables tx from stack point of view
*
- * @param bp
+ * @bp: driver handle
*/
static inline void bnx2x_tx_disable(struct bnx2x *bp)
{
@@ -838,7 +840,7 @@ static inline int bnx2x_alloc_rx_skb(struct bnx2x *bp,
mapping = dma_map_single(&bp->pdev->dev, skb->data, fp->rx_buf_size,
DMA_FROM_DEVICE);
if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) {
- dev_kfree_skb(skb);
+ dev_kfree_skb_any(skb);
return -ENOMEM;
}
@@ -880,6 +882,9 @@ static inline void bnx2x_free_rx_sge_range(struct bnx2x *bp,
{
int i;
+ if (fp->disable_tpa)
+ return;
+
for (i = 0; i < last; i++)
bnx2x_free_rx_sge(bp, fp, i);
}
@@ -908,36 +913,39 @@ static inline void bnx2x_free_tpa_pool(struct bnx2x *bp,
}
}
-
-static inline void bnx2x_init_tx_rings(struct bnx2x *bp)
+static inline void bnx2x_init_tx_ring_one(struct bnx2x_fastpath *fp)
{
- int i, j;
+ int i;
- for_each_tx_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;
- 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)));
+ }
- 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)));
- }
+ SET_FLAG(fp->tx_db.data.header.header, DOORBELL_HDR_DB_TYPE, 1);
+ fp->tx_db.data.zero_fill1 = 0;
+ fp->tx_db.data.prod = 0;
- SET_FLAG(fp->tx_db.data.header.header, DOORBELL_HDR_DB_TYPE, 1);
- 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_pkt = 0;
+}
- fp->tx_pkt_prod = 0;
- fp->tx_pkt_cons = 0;
- fp->tx_bd_prod = 0;
- fp->tx_bd_cons = 0;
- fp->tx_pkt = 0;
- }
+static inline void bnx2x_init_tx_rings(struct bnx2x *bp)
+{
+ int i;
+
+ for_each_tx_queue(bp, i)
+ bnx2x_init_tx_ring_one(&bp->fp[i]);
}
static inline void bnx2x_set_next_page_rx_bd(struct bnx2x_fastpath *fp)
@@ -992,6 +1000,44 @@ static inline void bnx2x_set_next_page_rx_cq(struct bnx2x_fastpath *fp)
}
}
+/* Returns the number of actually allocated BDs */
+static inline int bnx2x_alloc_rx_bds(struct bnx2x_fastpath *fp,
+ int rx_ring_size)
+{
+ struct bnx2x *bp = fp->bp;
+ u16 ring_prod, cqe_ring_prod;
+ int i;
+
+ fp->rx_comp_cons = 0;
+ cqe_ring_prod = ring_prod = 0;
+
+ /* This routine is called only during fo init so
+ * fp->eth_q_stats.rx_skb_alloc_failed = 0
+ */
+ for (i = 0; i < rx_ring_size; i++) {
+ if (bnx2x_alloc_rx_skb(bp, fp, ring_prod) < 0) {
+ fp->eth_q_stats.rx_skb_alloc_failed++;
+ continue;
+ }
+ ring_prod = NEXT_RX_IDX(ring_prod);
+ cqe_ring_prod = NEXT_RCQ_IDX(cqe_ring_prod);
+ WARN_ON(ring_prod <= (i - fp->eth_q_stats.rx_skb_alloc_failed));
+ }
+
+ if (fp->eth_q_stats.rx_skb_alloc_failed)
+ BNX2X_ERR("was only able to allocate "
+ "%d rx skbs on queue[%d]\n",
+ (i - fp->eth_q_stats.rx_skb_alloc_failed), fp->index);
+
+ fp->rx_bd_prod = ring_prod;
+ /* Limit the CQE producer by the CQE ring size */
+ fp->rx_comp_prod = min_t(u16, NUM_RCQ_RINGS*RCQ_DESC_CNT,
+ cqe_ring_prod);
+ fp->rx_pkt = fp->rx_calls = 0;
+
+ return i - fp->eth_q_stats.rx_skb_alloc_failed;
+}
+
#ifdef BCM_CNIC
static inline void bnx2x_init_fcoe_fp(struct bnx2x *bp)
{
@@ -1041,12 +1087,23 @@ static inline void storm_memset_cmng(struct bnx2x *bp,
struct cmng_struct_per_port *cmng,
u8 port)
{
- size_t size = sizeof(struct cmng_struct_per_port);
+ size_t size =
+ sizeof(struct rate_shaping_vars_per_port) +
+ sizeof(struct fairness_vars_per_port) +
+ sizeof(struct safc_struct_per_port) +
+ sizeof(struct pfc_struct_per_port);
u32 addr = BAR_XSTRORM_INTMEM +
XSTORM_CMNG_PER_PORT_VARS_OFFSET(port);
__storm_memset_struct(bp, addr, size, (u32 *)cmng);
+
+ addr += size + 4 /* SKIP DCB+LLFC */;
+ size = sizeof(struct cmng_struct_per_port) -
+ size /* written */ - 4 /*skipped*/;
+
+ __storm_memset_struct(bp, addr, size,
+ (u32 *)(cmng->traffic_type_to_priority_cos));
}
/* HW Lock for shared dual port PHYs */
@@ -1054,12 +1111,11 @@ void bnx2x_acquire_phy_lock(struct bnx2x *bp);
void bnx2x_release_phy_lock(struct bnx2x *bp);
/**
- * Extracts MAX BW part from MF configuration.
+ * bnx2x_extract_max_cfg - extract MAX BW part from MF configuration.
*
- * @param bp
- * @param mf_cfg
+ * @bp: driver handle
+ * @mf_cfg: MF configuration
*
- * @return u16
*/
static inline u16 bnx2x_extract_max_cfg(struct bnx2x *bp, u32 mf_cfg)
{
diff --git a/drivers/net/bnx2x/bnx2x_dcb.c b/drivers/net/bnx2x/bnx2x_dcb.c
index 9a24d79c71d9..410a49e571ac 100644
--- a/drivers/net/bnx2x/bnx2x_dcb.c
+++ b/drivers/net/bnx2x/bnx2x_dcb.c
@@ -1,6 +1,6 @@
/* bnx2x_dcb.c: Broadcom Everest network driver.
*
- * Copyright 2009-2010 Broadcom Corporation
+ * Copyright 2009-2011 Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -485,6 +485,36 @@ static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp)
}
}
+#ifdef BCM_DCBNL
+static int bnx2x_dcbx_read_shmem_remote_mib(struct bnx2x *bp)
+{
+ struct lldp_remote_mib remote_mib = {0};
+ u32 dcbx_remote_mib_offset = SHMEM2_RD(bp, dcbx_remote_mib_offset);
+ int rc;
+
+ DP(NETIF_MSG_LINK, "dcbx_remote_mib_offset 0x%x\n",
+ dcbx_remote_mib_offset);
+
+ if (SHMEM_DCBX_REMOTE_MIB_NONE == dcbx_remote_mib_offset) {
+ BNX2X_ERR("FW doesn't support dcbx_remote_mib_offset\n");
+ return -EINVAL;
+ }
+
+ rc = bnx2x_dcbx_read_mib(bp, (u32 *)&remote_mib, dcbx_remote_mib_offset,
+ DCBX_READ_REMOTE_MIB);
+
+ if (rc) {
+ BNX2X_ERR("Faild to read remote mib from FW\n");
+ return rc;
+ }
+
+ /* save features and flags */
+ bp->dcbx_remote_feat = remote_mib.features;
+ bp->dcbx_remote_flags = remote_mib.flags;
+ return 0;
+}
+#endif
+
static int bnx2x_dcbx_read_shmem_neg_results(struct bnx2x *bp)
{
struct lldp_local_mib local_mib = {0};
@@ -571,6 +601,28 @@ void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state)
{
switch (state) {
case BNX2X_DCBX_STATE_NEG_RECEIVED:
+#ifdef BCM_CNIC
+ if (bp->state != BNX2X_STATE_OPENING_WAIT4_LOAD) {
+ struct cnic_ops *c_ops;
+ struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+ bp->flags |= NO_ISCSI_OOO_FLAG | NO_ISCSI_FLAG;
+ cp->drv_state |= CNIC_DRV_STATE_NO_ISCSI_OOO;
+ cp->drv_state |= CNIC_DRV_STATE_NO_ISCSI;
+
+ rcu_read_lock();
+ c_ops = rcu_dereference(bp->cnic_ops);
+ if (c_ops) {
+ bnx2x_cnic_notify(bp, CNIC_CTL_STOP_ISCSI_CMD);
+ rcu_read_unlock();
+ return;
+ }
+ rcu_read_unlock();
+ }
+
+ /* fall through if no CNIC initialized */
+ case BNX2X_DCBX_STATE_ISCSI_STOPPED:
+#endif
+
{
DP(NETIF_MSG_LINK, "BNX2X_DCBX_STATE_NEG_RECEIVED\n");
#ifdef BCM_DCBNL
@@ -579,6 +631,10 @@ void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state)
* negotiation results
*/
bnx2x_dcbnl_update_applist(bp, true);
+
+ /* Read rmeote mib if dcbx is in the FW */
+ if (bnx2x_dcbx_read_shmem_remote_mib(bp))
+ return;
#endif
/* Read neg results if dcbx is in the FW */
if (bnx2x_dcbx_read_shmem_neg_results(bp))
@@ -1057,12 +1113,6 @@ static void bnx2x_dcbx_get_num_pg_traf_type(struct bnx2x *bp,
}
}
-
-/*******************************************************************************
- * Description: single priority group
- *
- * Return:
- ******************************************************************************/
static void bnx2x_dcbx_ets_disabled_entry_data(struct bnx2x *bp,
struct cos_help_data *cos_data,
u32 pri_join_mask)
@@ -1075,11 +1125,6 @@ static void bnx2x_dcbx_ets_disabled_entry_data(struct bnx2x *bp,
cos_data->num_of_cos = 1;
}
-/*******************************************************************************
- * Description: updating the cos bw
- *
- * Return:
- ******************************************************************************/
static inline void bnx2x_dcbx_add_to_cos_bw(struct bnx2x *bp,
struct cos_entry_help_data *data,
u8 pg_bw)
@@ -1090,11 +1135,6 @@ static inline void bnx2x_dcbx_add_to_cos_bw(struct bnx2x *bp,
data->cos_bw += pg_bw;
}
-/*******************************************************************************
- * Description: single priority group
- *
- * Return:
- ******************************************************************************/
static void bnx2x_dcbx_separate_pauseable_from_non(struct bnx2x *bp,
struct cos_help_data *cos_data,
u32 *pg_pri_orginal_spread,
@@ -1347,11 +1387,6 @@ static void bnx2x_dcbx_two_pg_to_cos_params(
}
}
-/*******************************************************************************
- * Description: Still
- *
- * Return:
- ******************************************************************************/
static void bnx2x_dcbx_three_pg_to_cos_params(
struct bnx2x *bp,
struct pg_help_data *pg_help_data,
@@ -1539,11 +1574,6 @@ static void bnx2x_dcbx_get_ets_pri_pg_tbl(struct bnx2x *bp,
}
}
-/*******************************************************************************
- * Description: Fill pfc_config struct that will be sent in DCBX start ramrod
- *
- * Return:
- ******************************************************************************/
static void bnx2x_pfc_fw_struct_e2(struct bnx2x *bp)
{
struct flow_control_configuration *pfc_fw_cfg = NULL;
@@ -2035,7 +2065,6 @@ static u8 bnx2x_dcbnl_set_dcbx(struct net_device *netdev, u8 state)
return 0;
}
-
static u8 bnx2x_dcbnl_get_featcfg(struct net_device *netdev, int featid,
u8 *flags)
{
@@ -2115,31 +2144,100 @@ static u8 bnx2x_dcbnl_set_featcfg(struct net_device *netdev, int featid,
return rval;
}
+static int bnx2x_peer_appinfo(struct net_device *netdev,
+ struct dcb_peer_app_info *info, u16* app_count)
+{
+ int i;
+ struct bnx2x *bp = netdev_priv(netdev);
+
+ DP(NETIF_MSG_LINK, "APP-INFO\n");
+
+ info->willing = (bp->dcbx_remote_flags & DCBX_APP_REM_WILLING) ?: 0;
+ info->error = (bp->dcbx_remote_flags & DCBX_APP_RX_ERROR) ?: 0;
+ *app_count = 0;
+
+ for (i = 0; i < DCBX_MAX_APP_PROTOCOL; i++)
+ if (bp->dcbx_remote_feat.app.app_pri_tbl[i].appBitfield &
+ DCBX_APP_ENTRY_VALID)
+ (*app_count)++;
+ return 0;
+}
+
+static int bnx2x_peer_apptable(struct net_device *netdev,
+ struct dcb_app *table)
+{
+ int i, j;
+ struct bnx2x *bp = netdev_priv(netdev);
+
+ DP(NETIF_MSG_LINK, "APP-TABLE\n");
+
+ for (i = 0, j = 0; i < DCBX_MAX_APP_PROTOCOL; i++) {
+ struct dcbx_app_priority_entry *ent =
+ &bp->dcbx_remote_feat.app.app_pri_tbl[i];
+
+ if (ent->appBitfield & DCBX_APP_ENTRY_VALID) {
+ table[j].selector = bnx2x_dcbx_dcbnl_app_idtype(ent);
+ table[j].priority = bnx2x_dcbx_dcbnl_app_up(ent);
+ table[j++].protocol = ent->app_id;
+ }
+ }
+ return 0;
+}
+
+static int bnx2x_cee_peer_getpg(struct net_device *netdev, struct cee_pg *pg)
+{
+ int i;
+ struct bnx2x *bp = netdev_priv(netdev);
+
+ pg->willing = (bp->dcbx_remote_flags & DCBX_ETS_REM_WILLING) ?: 0;
+
+ for (i = 0; i < CEE_DCBX_MAX_PGS; i++) {
+ pg->pg_bw[i] =
+ DCBX_PG_BW_GET(bp->dcbx_remote_feat.ets.pg_bw_tbl, i);
+ pg->prio_pg[i] =
+ DCBX_PRI_PG_GET(bp->dcbx_remote_feat.ets.pri_pg_tbl, i);
+ }
+ return 0;
+}
+
+static int bnx2x_cee_peer_getpfc(struct net_device *netdev,
+ struct cee_pfc *pfc)
+{
+ struct bnx2x *bp = netdev_priv(netdev);
+ pfc->tcs_supported = bp->dcbx_remote_feat.pfc.pfc_caps;
+ pfc->pfc_en = bp->dcbx_remote_feat.pfc.pri_en_bitmap;
+ return 0;
+}
+
const struct dcbnl_rtnl_ops bnx2x_dcbnl_ops = {
- .getstate = bnx2x_dcbnl_get_state,
- .setstate = bnx2x_dcbnl_set_state,
- .getpermhwaddr = bnx2x_dcbnl_get_perm_hw_addr,
- .setpgtccfgtx = bnx2x_dcbnl_set_pg_tccfg_tx,
- .setpgbwgcfgtx = bnx2x_dcbnl_set_pg_bwgcfg_tx,
- .setpgtccfgrx = bnx2x_dcbnl_set_pg_tccfg_rx,
- .setpgbwgcfgrx = bnx2x_dcbnl_set_pg_bwgcfg_rx,
- .getpgtccfgtx = bnx2x_dcbnl_get_pg_tccfg_tx,
- .getpgbwgcfgtx = bnx2x_dcbnl_get_pg_bwgcfg_tx,
- .getpgtccfgrx = bnx2x_dcbnl_get_pg_tccfg_rx,
- .getpgbwgcfgrx = bnx2x_dcbnl_get_pg_bwgcfg_rx,
- .setpfccfg = bnx2x_dcbnl_set_pfc_cfg,
- .getpfccfg = bnx2x_dcbnl_get_pfc_cfg,
- .setall = bnx2x_dcbnl_set_all,
- .getcap = bnx2x_dcbnl_get_cap,
- .getnumtcs = bnx2x_dcbnl_get_numtcs,
- .setnumtcs = bnx2x_dcbnl_set_numtcs,
- .getpfcstate = bnx2x_dcbnl_get_pfc_state,
- .setpfcstate = bnx2x_dcbnl_set_pfc_state,
- .setapp = bnx2x_dcbnl_set_app_up,
- .getdcbx = bnx2x_dcbnl_get_dcbx,
- .setdcbx = bnx2x_dcbnl_set_dcbx,
- .getfeatcfg = bnx2x_dcbnl_get_featcfg,
- .setfeatcfg = bnx2x_dcbnl_set_featcfg,
+ .getstate = bnx2x_dcbnl_get_state,
+ .setstate = bnx2x_dcbnl_set_state,
+ .getpermhwaddr = bnx2x_dcbnl_get_perm_hw_addr,
+ .setpgtccfgtx = bnx2x_dcbnl_set_pg_tccfg_tx,
+ .setpgbwgcfgtx = bnx2x_dcbnl_set_pg_bwgcfg_tx,
+ .setpgtccfgrx = bnx2x_dcbnl_set_pg_tccfg_rx,
+ .setpgbwgcfgrx = bnx2x_dcbnl_set_pg_bwgcfg_rx,
+ .getpgtccfgtx = bnx2x_dcbnl_get_pg_tccfg_tx,
+ .getpgbwgcfgtx = bnx2x_dcbnl_get_pg_bwgcfg_tx,
+ .getpgtccfgrx = bnx2x_dcbnl_get_pg_tccfg_rx,
+ .getpgbwgcfgrx = bnx2x_dcbnl_get_pg_bwgcfg_rx,
+ .setpfccfg = bnx2x_dcbnl_set_pfc_cfg,
+ .getpfccfg = bnx2x_dcbnl_get_pfc_cfg,
+ .setall = bnx2x_dcbnl_set_all,
+ .getcap = bnx2x_dcbnl_get_cap,
+ .getnumtcs = bnx2x_dcbnl_get_numtcs,
+ .setnumtcs = bnx2x_dcbnl_set_numtcs,
+ .getpfcstate = bnx2x_dcbnl_get_pfc_state,
+ .setpfcstate = bnx2x_dcbnl_set_pfc_state,
+ .setapp = bnx2x_dcbnl_set_app_up,
+ .getdcbx = bnx2x_dcbnl_get_dcbx,
+ .setdcbx = bnx2x_dcbnl_set_dcbx,
+ .getfeatcfg = bnx2x_dcbnl_get_featcfg,
+ .setfeatcfg = bnx2x_dcbnl_set_featcfg,
+ .peer_getappinfo = bnx2x_peer_appinfo,
+ .peer_getapptable = bnx2x_peer_apptable,
+ .cee_peer_getpg = bnx2x_cee_peer_getpg,
+ .cee_peer_getpfc = bnx2x_cee_peer_getpfc,
};
#endif /* BCM_DCBNL */
diff --git a/drivers/net/bnx2x/bnx2x_dcb.h b/drivers/net/bnx2x/bnx2x_dcb.h
index 71b8eda43bd0..bed369d67e02 100644
--- a/drivers/net/bnx2x/bnx2x_dcb.h
+++ b/drivers/net/bnx2x/bnx2x_dcb.h
@@ -1,6 +1,6 @@
/* bnx2x_dcb.h: Broadcom Everest network driver.
*
- * Copyright 2009-2010 Broadcom Corporation
+ * Copyright 2009-2011 Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
@@ -61,9 +61,6 @@ struct bnx2x_dcbx_port_params {
#define BNX2X_DCBX_OVERWRITE_SETTINGS_ENABLE 1
#define BNX2X_DCBX_OVERWRITE_SETTINGS_INVALID (BNX2X_DCBX_CONFIG_INV_VALUE)
-/*******************************************************************************
- * LLDP protocol configuration parameters.
- ******************************************************************************/
struct bnx2x_config_lldp_params {
u32 overwrite_settings;
u32 msg_tx_hold;
@@ -83,9 +80,6 @@ struct bnx2x_admin_priority_app_table {
u32 app_id;
};
-/*******************************************************************************
- * DCBX protocol configuration parameters.
- ******************************************************************************/
struct bnx2x_config_dcbx_params {
u32 overwrite_settings;
u32 admin_dcbx_version;
@@ -183,9 +177,13 @@ void bnx2x_dcbx_set_state(struct bnx2x *bp, bool dcb_on, u32 dcbx_enabled);
enum {
BNX2X_DCBX_STATE_NEG_RECEIVED = 0x1,
- BNX2X_DCBX_STATE_TX_PAUSED = 0x2,
- BNX2X_DCBX_STATE_TX_RELEASED = 0x4
+#ifdef BCM_CNIC
+ BNX2X_DCBX_STATE_ISCSI_STOPPED,
+#endif
+ BNX2X_DCBX_STATE_TX_PAUSED,
+ BNX2X_DCBX_STATE_TX_RELEASED
};
+
void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state);
/* DCB netlink */
diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c
index 89cb977898cb..727fe89ff37f 100644
--- a/drivers/net/bnx2x/bnx2x_ethtool.c
+++ b/drivers/net/bnx2x/bnx2x_ethtool.c
@@ -1,6 +1,6 @@
/* bnx2x_ethtool.c: Broadcom Everest network driver.
*
- * Copyright (c) 2007-2010 Broadcom Corporation
+ * Copyright (c) 2007-2011 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
@@ -167,6 +167,7 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct bnx2x *bp = netdev_priv(dev);
int cfg_idx = bnx2x_get_link_cfg_idx(bp);
+
/* Dual Media boards present all available port types */
cmd->supported = bp->port.supported[cfg_idx] |
(bp->port.supported[cfg_idx ^ 1] &
@@ -176,16 +177,16 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
if ((bp->state == BNX2X_STATE_OPEN) &&
!(bp->flags & MF_FUNC_DIS) &&
(bp->link_vars.link_up)) {
- cmd->speed = bp->link_vars.line_speed;
+ ethtool_cmd_speed_set(cmd, bp->link_vars.line_speed);
cmd->duplex = bp->link_vars.duplex;
} else {
-
- cmd->speed = bp->link_params.req_line_speed[cfg_idx];
+ ethtool_cmd_speed_set(
+ cmd, bp->link_params.req_line_speed[cfg_idx]);
cmd->duplex = bp->link_params.req_duplex[cfg_idx];
}
if (IS_MF(bp))
- cmd->speed = bnx2x_get_mf_speed(bp);
+ ethtool_cmd_speed_set(cmd, bnx2x_get_mf_speed(bp));
if (bp->port.supported[cfg_idx] & SUPPORTED_TP)
cmd->port = PORT_TP;
@@ -206,10 +207,11 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
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 " supported 0x%x advertising 0x%x speed %u\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->cmd, cmd->supported, cmd->advertising,
+ ethtool_cmd_speed(cmd),
cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver,
cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt);
@@ -226,16 +228,15 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
return 0;
DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n"
- " supported 0x%x advertising 0x%x speed %d speed_hi %d\n"
+ " supported 0x%x advertising 0x%x speed %u\n"
" duplex %d port %d phy_address %d transceiver %d\n"
" autoneg %d maxtxpkt %d maxrxpkt %d\n",
- cmd->cmd, cmd->supported, cmd->advertising, cmd->speed,
- cmd->speed_hi,
+ cmd->cmd, cmd->supported, cmd->advertising,
+ ethtool_cmd_speed(cmd),
cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver,
cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt);
- speed = cmd->speed;
- speed |= (cmd->speed_hi << 16);
+ speed = ethtool_cmd_speed(cmd);
if (IS_MF_SI(bp)) {
u32 part;
@@ -439,7 +440,7 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
break;
default:
- DP(NETIF_MSG_LINK, "Unsupported speed %d\n", speed);
+ DP(NETIF_MSG_LINK, "Unsupported speed %u\n", speed);
return -EINVAL;
}
@@ -1219,7 +1220,8 @@ static int bnx2x_set_ringparam(struct net_device *dev,
}
if ((ering->rx_pending > MAX_RX_AVAIL) ||
- (ering->rx_pending < MIN_RX_AVAIL) ||
+ (ering->rx_pending < (bp->disable_tpa ? MIN_RX_SIZE_NONTPA :
+ MIN_RX_SIZE_TPA)) ||
(ering->tx_pending > MAX_TX_AVAIL) ||
(ering->tx_pending <= MAX_SKB_FRAGS + 4))
return -EINVAL;
@@ -1299,91 +1301,6 @@ static int bnx2x_set_pauseparam(struct net_device *dev,
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;
- }
-
- if (!(data & ETH_FLAG_RXVLAN))
- return -EINVAL;
-
- if ((data & ETH_FLAG_LRO) && bp->rx_csum && bp->disable_tpa)
- return -EINVAL;
-
- rc = ethtool_op_set_flags(dev, data, ETH_FLAG_LRO | ETH_FLAG_RXVLAN |
- ETH_FLAG_TXVLAN | ETH_FLAG_RXHASH);
- if (rc)
- return rc;
-
- /* TPA requires Rx CSUM offloading */
- if ((data & ETH_FLAG_LRO) && bp->rx_csum) {
- if (!(bp->flags & TPA_ENABLE_FLAG)) {
- bp->flags |= TPA_ENABLE_FLAG;
- changed = 1;
- }
- } else if (bp->flags & TPA_ENABLE_FLAG) {
- dev->features &= ~NETIF_F_LRO;
- bp->flags &= ~TPA_ENABLE_FLAG;
- changed = 1;
- }
-
- 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] = {
@@ -2097,35 +2014,37 @@ static void bnx2x_get_ethtool_stats(struct net_device *dev,
}
}
-static int bnx2x_phys_id(struct net_device *dev, u32 data)
+static int bnx2x_set_phys_id(struct net_device *dev,
+ enum ethtool_phys_id_state state)
{
struct bnx2x *bp = netdev_priv(dev);
- int i;
if (!netif_running(dev))
- return 0;
+ return -EAGAIN;
if (!bp->port.pmf)
- return 0;
+ return -EOPNOTSUPP;
- if (data == 0)
- data = 2;
+ switch (state) {
+ case ETHTOOL_ID_ACTIVE:
+ return 1; /* cycle on/off once per second */
- for (i = 0; i < (data * 2); i++) {
- if ((i % 2) == 0)
- bnx2x_set_led(&bp->link_params, &bp->link_vars,
- LED_MODE_ON, SPEED_1000);
- else
- bnx2x_set_led(&bp->link_params, &bp->link_vars,
- LED_MODE_FRONT_PANEL_OFF, 0);
+ case ETHTOOL_ID_ON:
+ bnx2x_set_led(&bp->link_params, &bp->link_vars,
+ LED_MODE_ON, SPEED_1000);
+ break;
- msleep_interruptible(500);
- if (signal_pending(current))
- break;
- }
+ case ETHTOOL_ID_OFF:
+ bnx2x_set_led(&bp->link_params, &bp->link_vars,
+ LED_MODE_FRONT_PANEL_OFF, 0);
+
+ break;
- bnx2x_set_led(&bp->link_params, &bp->link_vars,
- LED_MODE_OPER, bp->link_vars.line_speed);
+ case ETHTOOL_ID_INACTIVE:
+ bnx2x_set_led(&bp->link_params, &bp->link_vars,
+ LED_MODE_OPER,
+ bp->link_vars.line_speed);
+ }
return 0;
}
@@ -2204,20 +2123,10 @@ static const struct ethtool_ops bnx2x_ethtool_ops = {
.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,
+ .set_phys_id = bnx2x_set_phys_id,
.get_ethtool_stats = bnx2x_get_ethtool_stats,
.get_rxnfc = bnx2x_get_rxnfc,
.get_rxfh_indir = bnx2x_get_rxfh_indir,
diff --git a/drivers/net/bnx2x/bnx2x_fw_defs.h b/drivers/net/bnx2x/bnx2x_fw_defs.h
index f4e5b1ce8149..9fe367836a57 100644
--- a/drivers/net/bnx2x/bnx2x_fw_defs.h
+++ b/drivers/net/bnx2x/bnx2x_fw_defs.h
@@ -1,6 +1,6 @@
/* bnx2x_fw_defs.h: Broadcom Everest network driver.
*
- * Copyright (c) 2007-2010 Broadcom Corporation
+ * Copyright (c) 2007-2011 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
diff --git a/drivers/net/bnx2x/bnx2x_fw_file_hdr.h b/drivers/net/bnx2x/bnx2x_fw_file_hdr.h
index f807262911e5..f4a07fbaed05 100644
--- a/drivers/net/bnx2x/bnx2x_fw_file_hdr.h
+++ b/drivers/net/bnx2x/bnx2x_fw_file_hdr.h
@@ -1,6 +1,6 @@
/* bnx2x_fw_file_hdr.h: FW binary file header structure.
*
- * Copyright (c) 2007-2009 Broadcom Corporation
+ * Copyright (c) 2007-2011 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
diff --git a/drivers/net/bnx2x/bnx2x_hsi.h b/drivers/net/bnx2x/bnx2x_hsi.h
index dac1bf9cbbfa..cdf19fe7c7f6 100644
--- a/drivers/net/bnx2x/bnx2x_hsi.h
+++ b/drivers/net/bnx2x/bnx2x_hsi.h
@@ -1,6 +1,6 @@
/* bnx2x_hsi.h: Broadcom Everest network driver.
*
- * Copyright (c) 2007-2010 Broadcom Corporation
+ * Copyright (c) 2007-2011 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
@@ -1929,7 +1929,7 @@ struct host_func_stats {
#define BCM_5710_FW_MAJOR_VERSION 6
#define BCM_5710_FW_MINOR_VERSION 2
-#define BCM_5710_FW_REVISION_VERSION 5
+#define BCM_5710_FW_REVISION_VERSION 9
#define BCM_5710_FW_ENGINEERING_VERSION 0
#define BCM_5710_FW_COMPILE_FLAGS 1
diff --git a/drivers/net/bnx2x/bnx2x_init.h b/drivers/net/bnx2x/bnx2x_init.h
index fa6dbe3f2058..d5399206f66e 100644
--- a/drivers/net/bnx2x/bnx2x_init.h
+++ b/drivers/net/bnx2x/bnx2x_init.h
@@ -1,7 +1,7 @@
/* bnx2x_init.h: Broadcom Everest network driver.
* Structures and macroes needed during the initialization.
*
- * Copyright (c) 2007-2009 Broadcom Corporation
+ * Copyright (c) 2007-2011 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
diff --git a/drivers/net/bnx2x/bnx2x_init_ops.h b/drivers/net/bnx2x/bnx2x_init_ops.h
index 66df29fcf751..aafd0232393f 100644
--- a/drivers/net/bnx2x/bnx2x_init_ops.h
+++ b/drivers/net/bnx2x/bnx2x_init_ops.h
@@ -2,7 +2,7 @@
* Static functions needed during the initialization.
* This file is "included" in bnx2x_main.c.
*
- * Copyright (c) 2007-2010 Broadcom Corporation
+ * Copyright (c) 2007-2011 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
diff --git a/drivers/net/bnx2x/bnx2x_link.c b/drivers/net/bnx2x/bnx2x_link.c
index 974ef2be36a5..076e11f5769f 100644
--- a/drivers/net/bnx2x/bnx2x_link.c
+++ b/drivers/net/bnx2x/bnx2x_link.c
@@ -385,7 +385,7 @@ u8 bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos)
return 0;
}
/******************************************************************/
-/* ETS section */
+/* PFC section */
/******************************************************************/
static void bnx2x_bmac2_get_pfc_stat(struct link_params *params,
@@ -1301,14 +1301,12 @@ static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
return 0;
}
-/*
- * get_emac_base
- *
- * @param cb
- * @param mdc_mdio_access
- * @param port
+/**
+ * bnx2x_get_emac_base - retrive emac base address
*
- * @return u32
+ * @bp: driver handle
+ * @mdc_mdio_access: access type
+ * @port: port id
*
* This function selects the MDC/MDIO access (through emac0 or
* emac1) depend on the mdc_mdio_access, port, port swapped. Each
diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c
index a97a4a1c344f..4b70311a11ef 100644
--- a/drivers/net/bnx2x/bnx2x_main.c
+++ b/drivers/net/bnx2x/bnx2x_main.c
@@ -1,6 +1,6 @@
/* bnx2x_main.c: Broadcom Everest network driver.
*
- * Copyright (c) 2007-2010 Broadcom Corporation
+ * Copyright (c) 2007-2011 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
@@ -571,7 +571,7 @@ static int bnx2x_issue_dmae_with_comp(struct bnx2x *bp,
struct dmae_command *dmae)
{
u32 *wb_comp = bnx2x_sp(bp, wb_comp);
- int cnt = CHIP_REV_IS_SLOW(bp) ? (400000) : 40;
+ int cnt = CHIP_REV_IS_SLOW(bp) ? (400000) : 4000;
int rc = 0;
DP(BNX2X_MSG_OFF, "data before [0x%08x 0x%08x 0x%08x 0x%08x]\n",
@@ -2036,7 +2036,7 @@ static int bnx2x_get_cmng_fns_mode(struct bnx2x *bp)
return CMNG_FNS_NONE;
}
-static void bnx2x_read_mf_cfg(struct bnx2x *bp)
+void bnx2x_read_mf_cfg(struct bnx2x *bp)
{
int vn, n = (CHIP_MODE_IS_4_PORT(bp) ? 2 : 1);
@@ -2123,7 +2123,6 @@ static inline void bnx2x_link_sync_notify(struct bnx2x *bp)
/* This function is called upon link interrupt */
static void bnx2x_link_attn(struct bnx2x *bp)
{
- u32 prev_link_status = bp->link_vars.link_status;
/* Make sure that we are synced with the current statistics */
bnx2x_stats_handle(bp, STATS_EVENT_STOP);
@@ -2168,17 +2167,15 @@ static void bnx2x_link_attn(struct bnx2x *bp)
"single function mode without fairness\n");
}
+ __bnx2x_link_report(bp);
+
if (IS_MF(bp))
bnx2x_link_sync_notify(bp);
-
- /* indicate link status only if link status actually changed */
- if (prev_link_status != bp->link_vars.link_status)
- bnx2x_link_report(bp);
}
void bnx2x__link_status_update(struct bnx2x *bp)
{
- if ((bp->state != BNX2X_STATE_OPEN) || (bp->flags & MF_FUNC_DIS))
+ if (bp->state != BNX2X_STATE_OPEN)
return;
bnx2x_link_status_update(&bp->link_params, &bp->link_vars);
@@ -2188,10 +2185,6 @@ void bnx2x__link_status_update(struct bnx2x *bp)
else
bnx2x_stats_handle(bp, STATS_EVENT_STOP);
- /* the link status update could be the result of a DCC event
- hence re-read the shmem mf configuration */
- bnx2x_read_mf_cfg(bp);
-
/* indicate link status */
bnx2x_link_report(bp);
}
@@ -2229,12 +2222,13 @@ static void bnx2x_pmf_update(struct bnx2x *bp)
u32 bnx2x_fw_command(struct bnx2x *bp, u32 command, u32 param)
{
int mb_idx = BP_FW_MB_IDX(bp);
- u32 seq = ++bp->fw_seq;
+ u32 seq;
u32 rc = 0;
u32 cnt = 1;
u8 delay = CHIP_REV_IS_SLOW(bp) ? 100 : 10;
mutex_lock(&bp->fw_mb_mutex);
+ seq = ++bp->fw_seq;
SHMEM_WR(bp, func_mb[mb_idx].drv_mb_param, param);
SHMEM_WR(bp, func_mb[mb_idx].drv_mb_header, (command | seq));
@@ -3120,10 +3114,14 @@ static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
if (val & DRV_STATUS_SET_MF_BW)
bnx2x_set_mf_bw(bp);
- bnx2x__link_status_update(bp);
if ((bp->port.pmf == 0) && (val & DRV_STATUS_PMF))
bnx2x_pmf_update(bp);
+ /* Always call it here: bnx2x_link_report() will
+ * prevent the link indication duplication.
+ */
+ bnx2x__link_status_update(bp);
+
if (bp->port.pmf &&
(val & DRV_STATUS_DCBX_NEGOTIATION_RESULTS) &&
bp->dcbx_enabled > 0)
@@ -3669,7 +3667,8 @@ static int bnx2x_cnic_handle_cfc_del(struct bnx2x *bp, u32 cid,
union event_ring_elem *elem)
{
if (!bp->cnic_eth_dev.starting_cid ||
- cid < bp->cnic_eth_dev.starting_cid)
+ (cid < bp->cnic_eth_dev.starting_cid &&
+ cid != bp->cnic_eth_dev.iscsi_l2_cid))
return 1;
DP(BNX2X_MSG_SP, "got delete ramrod for CNIC CID %d\n", cid);
@@ -3904,10 +3903,9 @@ static void bnx2x_timer(unsigned long data)
if (poll) {
struct bnx2x_fastpath *fp = &bp->fp[0];
- int rc;
bnx2x_tx_int(fp);
- rc = bnx2x_rx_int(fp, 1000);
+ bnx2x_rx_int(fp, 1000);
}
if (!BP_NOMCP(bp)) {
@@ -4062,7 +4060,6 @@ static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
struct hc_status_block_data_e2 sb_data_e2;
struct hc_status_block_data_e1x sb_data_e1x;
struct hc_status_block_sm *hc_sm_p;
- struct hc_index_data *hc_index_p;
int data_size;
u32 *sb_data_p;
@@ -4083,7 +4080,6 @@ static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
sb_data_e2.common.host_sb_addr.hi = U64_HI(mapping);
sb_data_e2.common.host_sb_addr.lo = U64_LO(mapping);
hc_sm_p = sb_data_e2.common.state_machine;
- hc_index_p = sb_data_e2.index_data;
sb_data_p = (u32 *)&sb_data_e2;
data_size = sizeof(struct hc_status_block_data_e2)/sizeof(u32);
} else {
@@ -4097,7 +4093,6 @@ static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid,
sb_data_e1x.common.host_sb_addr.hi = U64_HI(mapping);
sb_data_e1x.common.host_sb_addr.lo = U64_LO(mapping);
hc_sm_p = sb_data_e1x.common.state_machine;
- hc_index_p = sb_data_e1x.index_data;
sb_data_p = (u32 *)&sb_data_e1x;
data_size = sizeof(struct hc_status_block_data_e1x)/sizeof(u32);
}
@@ -4454,7 +4449,7 @@ static void bnx2x_init_fp_sb(struct bnx2x *bp, int fp_idx)
fp->state = BNX2X_FP_STATE_CLOSED;
- fp->index = fp->cid = fp_idx;
+ fp->cid = fp_idx;
fp->cl_id = BP_L_ID(bp) + fp_idx;
fp->fw_sb_id = bp->base_fw_ndsb + fp->cl_id + CNIC_CONTEXT_USE;
fp->igu_sb_id = bp->igu_base_sb + fp_idx + CNIC_CONTEXT_USE;
@@ -4566,9 +4561,11 @@ gunzip_nomem1:
static void bnx2x_gunzip_end(struct bnx2x *bp)
{
- kfree(bp->strm->workspace);
- kfree(bp->strm);
- bp->strm = NULL;
+ if (bp->strm) {
+ kfree(bp->strm->workspace);
+ kfree(bp->strm);
+ bp->strm = NULL;
+ }
if (bp->gunzip_buf) {
dma_free_coherent(&bp->pdev->dev, FW_BUF_SIZE, bp->gunzip_buf,
@@ -5876,9 +5873,6 @@ int bnx2x_init_hw(struct bnx2x *bp, u32 load_code)
bp->dmae_ready = 0;
spin_lock_init(&bp->dmae_lock);
- rc = bnx2x_gunzip_init(bp);
- if (rc)
- return rc;
switch (load_code) {
case FW_MSG_CODE_DRV_LOAD_COMMON:
@@ -5922,80 +5916,10 @@ init_hw_err:
void bnx2x_free_mem(struct bnx2x *bp)
{
-
-#define BNX2X_PCI_FREE(x, y, size) \
- do { \
- if (x) { \
- dma_free_coherent(&bp->pdev->dev, size, (void *)x, y); \
- x = NULL; \
- y = 0; \
- } \
- } while (0)
-
-#define BNX2X_FREE(x) \
- do { \
- if (x) { \
- kfree((void *)x); \
- x = NULL; \
- } \
- } while (0)
-
- int i;
+ bnx2x_gunzip_end(bp);
/* fastpath */
- /* Common */
- for_each_queue(bp, i) {
-#ifdef BCM_CNIC
- /* FCoE client uses default status block */
- if (IS_FCOE_IDX(i)) {
- union host_hc_status_block *sb =
- &bnx2x_fp(bp, i, status_blk);
- memset(sb, 0, sizeof(union host_hc_status_block));
- bnx2x_fp(bp, i, status_blk_mapping) = 0;
- } else {
-#endif
- /* status blocks */
- if (CHIP_IS_E2(bp))
- BNX2X_PCI_FREE(bnx2x_fp(bp, i, status_blk.e2_sb),
- bnx2x_fp(bp, i, status_blk_mapping),
- sizeof(struct host_hc_status_block_e2));
- else
- BNX2X_PCI_FREE(bnx2x_fp(bp, i, status_blk.e1x_sb),
- bnx2x_fp(bp, i, status_blk_mapping),
- sizeof(struct host_hc_status_block_e1x));
-#ifdef BCM_CNIC
- }
-#endif
- }
- /* Rx */
- for_each_rx_queue(bp, i) {
-
- /* fastpath rx rings: rx_buf rx_desc rx_comp */
- BNX2X_FREE(bnx2x_fp(bp, i, rx_buf_ring));
- BNX2X_PCI_FREE(bnx2x_fp(bp, i, rx_desc_ring),
- bnx2x_fp(bp, i, rx_desc_mapping),
- sizeof(struct eth_rx_bd) * NUM_RX_BD);
-
- BNX2X_PCI_FREE(bnx2x_fp(bp, i, rx_comp_ring),
- bnx2x_fp(bp, i, rx_comp_mapping),
- sizeof(struct eth_fast_path_rx_cqe) *
- NUM_RCQ_BD);
-
- /* SGE ring */
- BNX2X_FREE(bnx2x_fp(bp, i, rx_page_ring));
- BNX2X_PCI_FREE(bnx2x_fp(bp, i, rx_sge_ring),
- bnx2x_fp(bp, i, rx_sge_mapping),
- BCM_PAGE_SIZE * NUM_RX_SGE_PAGES);
- }
- /* Tx */
- for_each_tx_queue(bp, i) {
-
- /* fastpath tx rings: tx_buf tx_desc */
- BNX2X_FREE(bnx2x_fp(bp, i, tx_buf_ring));
- BNX2X_PCI_FREE(bnx2x_fp(bp, i, tx_desc_ring),
- bnx2x_fp(bp, i, tx_desc_mapping),
- sizeof(union eth_tx_bd_types) * NUM_TX_BD);
- }
+ bnx2x_free_fp_mem(bp);
/* end of fastpath */
BNX2X_PCI_FREE(bp->def_status_blk, bp->def_status_blk_mapping,
@@ -6028,101 +5952,13 @@ void bnx2x_free_mem(struct bnx2x *bp)
BCM_PAGE_SIZE * NUM_EQ_PAGES);
BNX2X_FREE(bp->rx_indir_table);
-
-#undef BNX2X_PCI_FREE
-#undef BNX2X_KFREE
}
-static inline void set_sb_shortcuts(struct bnx2x *bp, int index)
-{
- union host_hc_status_block status_blk = bnx2x_fp(bp, index, status_blk);
- if (CHIP_IS_E2(bp)) {
- bnx2x_fp(bp, index, sb_index_values) =
- (__le16 *)status_blk.e2_sb->sb.index_values;
- bnx2x_fp(bp, index, sb_running_index) =
- (__le16 *)status_blk.e2_sb->sb.running_index;
- } else {
- bnx2x_fp(bp, index, sb_index_values) =
- (__le16 *)status_blk.e1x_sb->sb.index_values;
- bnx2x_fp(bp, index, sb_running_index) =
- (__le16 *)status_blk.e1x_sb->sb.running_index;
- }
-}
int bnx2x_alloc_mem(struct bnx2x *bp)
{
-#define BNX2X_PCI_ALLOC(x, y, size) \
- do { \
- x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \
- if (x == NULL) \
- goto alloc_mem_err; \
- memset(x, 0, size); \
- } while (0)
-
-#define BNX2X_ALLOC(x, size) \
- do { \
- x = kzalloc(size, GFP_KERNEL); \
- if (x == NULL) \
- goto alloc_mem_err; \
- } while (0)
-
- int i;
-
- /* fastpath */
- /* Common */
- for_each_queue(bp, i) {
- union host_hc_status_block *sb = &bnx2x_fp(bp, i, status_blk);
- bnx2x_fp(bp, i, bp) = bp;
- /* status blocks */
-#ifdef BCM_CNIC
- if (!IS_FCOE_IDX(i)) {
-#endif
- if (CHIP_IS_E2(bp))
- BNX2X_PCI_ALLOC(sb->e2_sb,
- &bnx2x_fp(bp, i, status_blk_mapping),
- sizeof(struct host_hc_status_block_e2));
- else
- BNX2X_PCI_ALLOC(sb->e1x_sb,
- &bnx2x_fp(bp, i, status_blk_mapping),
- sizeof(struct host_hc_status_block_e1x));
-#ifdef BCM_CNIC
- }
-#endif
- set_sb_shortcuts(bp, i);
- }
- /* Rx */
- for_each_queue(bp, i) {
-
- /* fastpath rx rings: rx_buf rx_desc rx_comp */
- BNX2X_ALLOC(bnx2x_fp(bp, i, rx_buf_ring),
- sizeof(struct sw_rx_bd) * NUM_RX_BD);
- BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, rx_desc_ring),
- &bnx2x_fp(bp, i, rx_desc_mapping),
- sizeof(struct eth_rx_bd) * NUM_RX_BD);
-
- BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, rx_comp_ring),
- &bnx2x_fp(bp, i, rx_comp_mapping),
- sizeof(struct eth_fast_path_rx_cqe) *
- NUM_RCQ_BD);
-
- /* SGE ring */
- BNX2X_ALLOC(bnx2x_fp(bp, i, rx_page_ring),
- sizeof(struct sw_rx_page) * NUM_RX_SGE);
- BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, rx_sge_ring),
- &bnx2x_fp(bp, i, rx_sge_mapping),
- BCM_PAGE_SIZE * NUM_RX_SGE_PAGES);
- }
- /* Tx */
- for_each_queue(bp, i) {
-
- /* fastpath tx rings: tx_buf tx_desc */
- BNX2X_ALLOC(bnx2x_fp(bp, i, tx_buf_ring),
- sizeof(struct sw_tx_bd) * NUM_TX_BD);
- BNX2X_PCI_ALLOC(bnx2x_fp(bp, i, tx_desc_ring),
- &bnx2x_fp(bp, i, tx_desc_mapping),
- sizeof(union eth_tx_bd_types) * NUM_TX_BD);
- }
- /* end of fastpath */
+ if (bnx2x_gunzip_init(bp))
+ return -ENOMEM;
#ifdef BCM_CNIC
if (CHIP_IS_E2(bp))
@@ -6162,14 +5998,18 @@ int bnx2x_alloc_mem(struct bnx2x *bp)
BNX2X_ALLOC(bp->rx_indir_table, sizeof(bp->rx_indir_table[0]) *
TSTORM_INDIRECTION_TABLE_SIZE);
+
+ /* fastpath */
+ /* need to be done at the end, since it's self adjusting to amount
+ * of memory available for RSS queues
+ */
+ if (bnx2x_alloc_fp_mem(bp))
+ goto alloc_mem_err;
return 0;
alloc_mem_err:
bnx2x_free_mem(bp);
return -ENOMEM;
-
-#undef BNX2X_PCI_ALLOC
-#undef BNX2X_ALLOC
}
/*
@@ -6197,14 +6037,14 @@ static int bnx2x_func_stop(struct bnx2x *bp)
}
/**
- * Sets a MAC in a CAM for a few L2 Clients for E1x chips
+ * bnx2x_set_mac_addr_gen - set a MAC in a CAM for a few L2 Clients for E1x chips
*
- * @param bp driver descriptor
- * @param set set or clear an entry (1 or 0)
- * @param mac pointer to a buffer containing a MAC
- * @param cl_bit_vec bit vector of clients to register a MAC for
- * @param cam_offset offset in a CAM to use
- * @param is_bcast is the set MAC a broadcast address (for E1 only)
+ * @bp: driver handle
+ * @set: set or clear an entry (1 or 0)
+ * @mac: pointer to a buffer containing a MAC
+ * @cl_bit_vec: bit vector of clients to register a MAC for
+ * @cam_offset: offset in a CAM to use
+ * @is_bcast: is the set MAC a broadcast address (for E1 only)
*/
static void bnx2x_set_mac_addr_gen(struct bnx2x *bp, int set, const u8 *mac,
u32 cl_bit_vec, u8 cam_offset,
@@ -6564,14 +6404,13 @@ void bnx2x_invalidate_e1h_mc_list(struct bnx2x *bp)
#ifdef BCM_CNIC
/**
- * Set iSCSI MAC(s) at the next enties in the CAM after the ETH
- * MAC(s). This function will wait until the ramdord completion
- * returns.
+ * bnx2x_set_iscsi_eth_mac_addr - set iSCSI MAC(s).
*
- * @param bp driver handle
- * @param set set or clear the CAM entry
+ * @bp: driver handle
+ * @set: set or clear the CAM entry
*
- * @return 0 if cussess, -ENODEV if ramrod doesn't return.
+ * This function will wait until the ramdord completion returns.
+ * Return 0 if success, -ENODEV if ramrod doesn't return.
*/
static int bnx2x_set_iscsi_eth_mac_addr(struct bnx2x *bp, int set)
{
@@ -6592,14 +6431,13 @@ static int bnx2x_set_iscsi_eth_mac_addr(struct bnx2x *bp, int set)
}
/**
- * Set FCoE L2 MAC(s) at the next enties in the CAM after the
- * ETH MAC(s). This function will wait until the ramdord
- * completion returns.
+ * bnx2x_set_fip_eth_mac_addr - set FCoE L2 MAC(s)
*
- * @param bp driver handle
- * @param set set or clear the CAM entry
+ * @bp: driver handle
+ * @set: set or clear the CAM entry
*
- * @return 0 if cussess, -ENODEV if ramrod doesn't return.
+ * This function will wait until the ramrod completion returns.
+ * Returns 0 if success, -ENODEV if ramrod doesn't return.
*/
int bnx2x_set_fip_eth_mac_addr(struct bnx2x *bp, int set)
{
@@ -6803,12 +6641,11 @@ static int bnx2x_setup_fw_client(struct bnx2x *bp,
}
/**
- * Configure interrupt mode according to current configuration.
- * In case of MSI-X it will also try to enable MSI-X.
+ * bnx2x_set_int_mode - configure interrupt mode
*
- * @param bp
+ * @bp: driver handle
*
- * @return int
+ * In case of MSI-X it will also try to enable MSI-X.
*/
static int __devinit bnx2x_set_int_mode(struct bnx2x *bp)
{
@@ -7392,10 +7229,11 @@ static void bnx2x_clp_reset_prep(struct bnx2x *bp, u32 *magic_val)
MF_CFG_WR(bp, shared_mf_config.clp_mb, val | SHARED_MF_CLP_MAGIC);
}
-/* Restore the value of the `magic' bit.
+/**
+ * bnx2x_clp_reset_done - restore the value of the `magic' bit.
*
- * @param pdev Device handle.
- * @param magic_val Old value of the `magic' bit.
+ * @bp: driver handle
+ * @magic_val: old value of the `magic' bit.
*/
static void bnx2x_clp_reset_done(struct bnx2x *bp, u32 magic_val)
{
@@ -7406,10 +7244,12 @@ static void bnx2x_clp_reset_done(struct bnx2x *bp, u32 magic_val)
}
/**
- * Prepares for MCP reset: takes care of CLP configurations.
+ * bnx2x_reset_mcp_prep - prepare for MCP reset.
*
- * @param bp
- * @param magic_val Old value of 'magic' bit.
+ * @bp: driver handle
+ * @magic_val: old value of 'magic' bit.
+ *
+ * Takes care of CLP configurations.
*/
static void bnx2x_reset_mcp_prep(struct bnx2x *bp, u32 *magic_val)
{
@@ -7434,10 +7274,10 @@ static void bnx2x_reset_mcp_prep(struct bnx2x *bp, u32 *magic_val)
#define MCP_TIMEOUT 5000 /* 5 seconds (in ms) */
#define MCP_ONE_TIMEOUT 100 /* 100 ms */
-/* Waits for MCP_ONE_TIMEOUT or MCP_ONE_TIMEOUT*10,
- * depending on the HW type.
+/**
+ * bnx2x_mcp_wait_one - wait for MCP_ONE_TIMEOUT
*
- * @param bp
+ * @bp: driver handle
*/
static inline void bnx2x_mcp_wait_one(struct bnx2x *bp)
{
@@ -7449,51 +7289,35 @@ static inline void bnx2x_mcp_wait_one(struct bnx2x *bp)
msleep(MCP_ONE_TIMEOUT);
}
-static int bnx2x_reset_mcp_comp(struct bnx2x *bp, u32 magic_val)
+/*
+ * initializes bp->common.shmem_base and waits for validity signature to appear
+ */
+static int bnx2x_init_shmem(struct bnx2x *bp)
{
- u32 shmem, cnt, validity_offset, val;
- int rc = 0;
-
- msleep(100);
-
- /* Get shmem offset */
- shmem = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR);
- if (shmem == 0) {
- BNX2X_ERR("Shmem 0 return failure\n");
- rc = -ENOTTY;
- goto exit_lbl;
- }
+ int cnt = 0;
+ u32 val = 0;
- validity_offset = offsetof(struct shmem_region, validity_map[0]);
+ do {
+ bp->common.shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR);
+ if (bp->common.shmem_base) {
+ val = SHMEM_RD(bp, validity_map[BP_PORT(bp)]);
+ if (val & SHR_MEM_VALIDITY_MB)
+ return 0;
+ }
- /* Wait for MCP to come up */
- for (cnt = 0; cnt < (MCP_TIMEOUT / MCP_ONE_TIMEOUT); cnt++) {
- /* TBD: its best to check validity map of last port.
- * currently checks on port 0.
- */
- val = REG_RD(bp, shmem + validity_offset);
- DP(NETIF_MSG_HW, "shmem 0x%x validity map(0x%x)=0x%x\n", shmem,
- shmem + validity_offset, val);
+ bnx2x_mcp_wait_one(bp);
- /* check that shared memory is valid. */
- if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
- == (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
- break;
+ } while (cnt++ < (MCP_TIMEOUT / MCP_ONE_TIMEOUT));
- bnx2x_mcp_wait_one(bp);
- }
+ BNX2X_ERR("BAD MCP validity signature\n");
- DP(NETIF_MSG_HW, "Cnt=%d Shmem validity map 0x%x\n", cnt, val);
+ return -ENODEV;
+}
- /* Check that shared memory is valid. This indicates that MCP is up. */
- if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) !=
- (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) {
- BNX2X_ERR("Shmem signature not present. MCP is not up !!\n");
- rc = -ENOTTY;
- goto exit_lbl;
- }
+static int bnx2x_reset_mcp_comp(struct bnx2x *bp, u32 magic_val)
+{
+ int rc = bnx2x_init_shmem(bp);
-exit_lbl:
/* Restore the `magic' bit value */
if (!CHIP_IS_E1(bp))
bnx2x_clp_reset_done(bp, magic_val);
@@ -8006,10 +7830,12 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
BNX2X_DEV_INFO("flash_size 0x%x (%d)\n",
bp->common.flash_size, bp->common.flash_size);
- bp->common.shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR);
+ bnx2x_init_shmem(bp);
+
bp->common.shmem2_base = REG_RD(bp, (BP_PATH(bp) ?
MISC_REG_GENERIC_CR_1 :
MISC_REG_GENERIC_CR_0));
+
bp->link_params.shmem_base = bp->common.shmem_base;
bp->link_params.shmem2_base = bp->common.shmem2_base;
BNX2X_DEV_INFO("shmem offset 0x%x shmem2 offset 0x%x\n",
@@ -8021,11 +7847,6 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
return;
}
- val = SHMEM_RD(bp, validity_map[BP_PORT(bp)]);
- if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
- != (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
- BNX2X_ERR("BAD MCP validity signature\n");
-
bp->common.hw_config = SHMEM_RD(bp, dev_info.shared_hw_config.config);
BNX2X_DEV_INFO("hw_config 0x%08x\n", bp->common.hw_config);
@@ -8059,13 +7880,9 @@ static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp)
(val >= REQ_BC_VER_4_VRFY_SPECIFIC_PHY_OPT_MDL) ?
FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY : 0;
- if (BP_E1HVN(bp) == 0) {
- pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_PMC, &pmc);
- bp->flags |= (pmc & PCI_PM_CAP_PME_D3cold) ? 0 : NO_WOL_FLAG;
- } else {
- /* no WOL capability for E1HVN != 0 */
- bp->flags |= NO_WOL_FLAG;
- }
+ pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_PMC, &pmc);
+ bp->flags |= (pmc & PCI_PM_CAP_PME_D3cold) ? 0 : NO_WOL_FLAG;
+
BNX2X_DEV_INFO("%sWoL capable\n",
(bp->flags & NO_WOL_FLAG) ? "not " : "");
@@ -8571,15 +8388,6 @@ static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp)
BNX2X_DEV_INFO("Read iSCSI MAC: "
"0x%x:0x%04x\n", val2, val);
bnx2x_set_mac_buf(iscsi_mac, val, val2);
-
- /* Disable iSCSI OOO if MAC configuration is
- * invalid.
- */
- if (!is_valid_ether_addr(iscsi_mac)) {
- bp->flags |= NO_ISCSI_OOO_FLAG |
- NO_ISCSI_FLAG;
- memset(iscsi_mac, 0, ETH_ALEN);
- }
} else
bp->flags |= NO_ISCSI_OOO_FLAG | NO_ISCSI_FLAG;
@@ -8592,13 +8400,6 @@ static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp)
"0x%x:0x%04x\n", val2, val);
bnx2x_set_mac_buf(fip_mac, val, val2);
- /* Disable FCoE if MAC configuration is
- * invalid.
- */
- if (!is_valid_ether_addr(fip_mac)) {
- bp->flags |= NO_FCOE_FLAG;
- memset(bp->fip_mac, 0, ETH_ALEN);
- }
} else
bp->flags |= NO_FCOE_FLAG;
}
@@ -8629,13 +8430,29 @@ static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp)
else if (!IS_MF(bp))
memcpy(fip_mac, iscsi_mac, ETH_ALEN);
}
+
+ /* Disable iSCSI if MAC configuration is
+ * invalid.
+ */
+ if (!is_valid_ether_addr(iscsi_mac)) {
+ bp->flags |= NO_ISCSI_FLAG;
+ memset(iscsi_mac, 0, ETH_ALEN);
+ }
+
+ /* Disable FCoE if MAC configuration is
+ * invalid.
+ */
+ if (!is_valid_ether_addr(fip_mac)) {
+ bp->flags |= NO_FCOE_FLAG;
+ memset(bp->fip_mac, 0, ETH_ALEN);
+ }
#endif
}
static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
{
int /*abs*/func = BP_ABS_FUNC(bp);
- int vn, port;
+ int vn;
u32 val = 0;
int rc = 0;
@@ -8670,7 +8487,6 @@ static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
bp->mf_ov = 0;
bp->mf_mode = 0;
vn = BP_E1HVN(bp);
- port = BP_PORT(bp);
if (!CHIP_IS_E1(bp) && !BP_NOMCP(bp)) {
DP(NETIF_MSG_PROBE,
@@ -8904,8 +8720,6 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
bp->multi_mode = multi_mode;
bp->int_mode = int_mode;
- bp->dev->features |= NETIF_F_GRO;
-
/* Set TPA flags */
if (disable_tpa) {
bp->flags &= ~TPA_ENABLE_FLAG;
@@ -8925,8 +8739,6 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
bp->tx_ring_size = MAX_TX_AVAIL;
- bp->rx_csum = 1;
-
/* make sure that the numbers are in the right granularity */
bp->tx_ticks = (50 / BNX2X_BTR) * BNX2X_BTR;
bp->rx_ticks = (25 / BNX2X_BTR) * BNX2X_BTR;
@@ -9304,6 +9116,8 @@ static const struct net_device_ops bnx2x_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = bnx2x_ioctl,
.ndo_change_mtu = bnx2x_change_mtu,
+ .ndo_fix_features = bnx2x_fix_features,
+ .ndo_set_features = bnx2x_set_features,
.ndo_tx_timeout = bnx2x_tx_timeout,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = poll_bnx2x,
@@ -9430,20 +9244,20 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
dev->netdev_ops = &bnx2x_netdev_ops;
bnx2x_set_ethtool_ops(dev);
- dev->features |= NETIF_F_SG;
- dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+
+ dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+ NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 |
+ NETIF_F_RXCSUM | NETIF_F_LRO | NETIF_F_HW_VLAN_TX;
+
+ dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+ NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_HIGHDMA;
+
+ dev->features |= dev->hw_features | NETIF_F_HW_VLAN_RX;
if (bp->flags & USING_DAC_FLAG)
dev->features |= NETIF_F_HIGHDMA;
- dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
- dev->features |= NETIF_F_TSO6;
- dev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
- dev->vlan_features |= NETIF_F_SG;
- dev->vlan_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
- if (bp->flags & USING_DAC_FLAG)
- dev->vlan_features |= NETIF_F_HIGHDMA;
- dev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
- dev->vlan_features |= NETIF_F_TSO6;
+ /* Add Loopback capability to the device */
+ dev->hw_features |= NETIF_F_LOOPBACK;
#ifdef BCM_DCBNL
dev->dcbnl_ops = &bnx2x_dcbnl_ops;
@@ -10342,6 +10156,11 @@ static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl)
break;
}
+ case DRV_CTL_ISCSI_STOPPED_CMD: {
+ bnx2x_dcbx_set_params(bp, BNX2X_DCBX_STATE_ISCSI_STOPPED);
+ break;
+ }
+
default:
BNX2X_ERR("unknown command %x\n", ctl->cmd);
rc = -EINVAL;
diff --git a/drivers/net/bnx2x/bnx2x_reg.h b/drivers/net/bnx2x/bnx2x_reg.h
index 1509a2318af9..86bba25d2d3f 100644
--- a/drivers/net/bnx2x/bnx2x_reg.h
+++ b/drivers/net/bnx2x/bnx2x_reg.h
@@ -1,6 +1,6 @@
/* bnx2x_reg.h: Broadcom Everest network driver.
*
- * Copyright (c) 2007-2010 Broadcom Corporation
+ * Copyright (c) 2007-2011 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
diff --git a/drivers/net/bnx2x/bnx2x_stats.c b/drivers/net/bnx2x/bnx2x_stats.c
index 3445ded6674f..e535bfa08945 100644
--- a/drivers/net/bnx2x/bnx2x_stats.c
+++ b/drivers/net/bnx2x/bnx2x_stats.c
@@ -1,6 +1,6 @@
/* bnx2x_stats.c: Broadcom Everest network driver.
*
- * Copyright (c) 2007-2010 Broadcom Corporation
+ * Copyright (c) 2007-2011 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
diff --git a/drivers/net/bnx2x/bnx2x_stats.h b/drivers/net/bnx2x/bnx2x_stats.h
index 596798c47452..45d14d8bc1aa 100644
--- a/drivers/net/bnx2x/bnx2x_stats.h
+++ b/drivers/net/bnx2x/bnx2x_stats.h
@@ -1,6 +1,6 @@
/* bnx2x_stats.h: Broadcom Everest network driver.
*
- * Copyright (c) 2007-2010 Broadcom Corporation
+ * Copyright (c) 2007-2011 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
diff --git a/drivers/net/bonding/Makefile b/drivers/net/bonding/Makefile
index 3c5c014e82b2..4c21bf6b8b2f 100644
--- a/drivers/net/bonding/Makefile
+++ b/drivers/net/bonding/Makefile
@@ -9,6 +9,3 @@ bonding-objs := bond_main.o bond_3ad.o bond_alb.o bond_sysfs.o bond_debugfs.o
proc-$(CONFIG_PROC_FS) += bond_procfs.o
bonding-objs += $(proc-y)
-ipv6-$(subst m,y,$(CONFIG_IPV6)) += bond_ipv6.o
-bonding-objs += $(ipv6-y)
-
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 31912f17653f..c7537abca4f2 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -716,11 +716,9 @@ static void __set_agg_ports_ready(struct aggregator *aggregator, int val)
static u32 __get_agg_bandwidth(struct aggregator *aggregator)
{
u32 bandwidth = 0;
- u32 basic_speed;
if (aggregator->num_of_ports) {
- basic_speed = __get_link_speed(aggregator->lag_ports);
- switch (basic_speed) {
+ switch (__get_link_speed(aggregator->lag_ports)) {
case AD_LINK_SPEED_BITMASK_1MBPS:
bandwidth = aggregator->num_of_ports;
break;
@@ -2405,14 +2403,6 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
struct ad_info ad_info;
int res = 1;
- /* make sure that the slaves list will
- * not change during tx
- */
- read_lock(&bond->lock);
-
- if (!BOND_IS_OK(bond))
- goto out;
-
if (bond_3ad_get_active_agg_info(bond, &ad_info)) {
pr_debug("%s: Error: bond_3ad_get_active_agg_info failed\n",
dev->name);
@@ -2466,39 +2456,20 @@ out:
/* no suitable interface, frame not sent */
dev_kfree_skb(skb);
}
- read_unlock(&bond->lock);
+
return NETDEV_TX_OK;
}
-int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev)
+void bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond,
+ struct slave *slave)
{
- struct bonding *bond = netdev_priv(dev);
- struct slave *slave = NULL;
- int ret = NET_RX_DROP;
-
- if (!(dev->flags & IFF_MASTER))
- goto out;
-
- skb = skb_share_check(skb, GFP_ATOMIC);
- if (!skb)
- goto out;
+ if (skb->protocol != PKT_TYPE_LACPDU)
+ return;
if (!pskb_may_pull(skb, sizeof(struct lacpdu)))
- goto out;
+ return;
read_lock(&bond->lock);
- slave = bond_get_slave_by_dev(netdev_priv(dev), orig_dev);
- if (!slave)
- goto out_unlock;
-
bond_3ad_rx_indication((struct lacpdu *) skb->data, slave, skb->len);
-
- ret = NET_RX_SUCCESS;
-
-out_unlock:
read_unlock(&bond->lock);
-out:
- dev_kfree_skb(skb);
-
- return ret;
}
diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h
index 01b8a6af275b..0ee3f1632c46 100644
--- a/drivers/net/bonding/bond_3ad.h
+++ b/drivers/net/bonding/bond_3ad.h
@@ -258,7 +258,6 @@ struct ad_bond_info {
* requested
*/
struct timer_list ad_timer;
- struct packet_type ad_pkt_type;
};
struct ad_slave_info {
@@ -280,7 +279,8 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave);
void bond_3ad_handle_link_change(struct slave *slave, char link);
int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info);
int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev);
-int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev);
+void bond_3ad_lacpdu_recv(struct sk_buff *skb, struct bonding *bond,
+ struct slave *slave);
int bond_3ad_set_carrier(struct bonding *bond);
#endif //__BOND_3AD_H__
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index ba715826e2a8..2df9276720a0 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -163,8 +163,6 @@ static int tlb_initialize(struct bonding *bond)
struct tlb_client_info *new_hashtbl;
int i;
- spin_lock_init(&(bond_info->tx_hashtbl_lock));
-
new_hashtbl = kzalloc(size, GFP_KERNEL);
if (!new_hashtbl) {
pr_err("%s: Error: Failed to allocate TLB hash table\n",
@@ -308,49 +306,33 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp)
_unlock_rx_hashtbl(bond);
}
-static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct packet_type *ptype, struct net_device *orig_dev)
+static void rlb_arp_recv(struct sk_buff *skb, struct bonding *bond,
+ struct slave *slave)
{
- struct bonding *bond;
- struct arp_pkt *arp = (struct arp_pkt *)skb->data;
- int res = NET_RX_DROP;
-
- while (bond_dev->priv_flags & IFF_802_1Q_VLAN)
- bond_dev = vlan_dev_real_dev(bond_dev);
+ struct arp_pkt *arp;
- if (!(bond_dev->priv_flags & IFF_BONDING) ||
- !(bond_dev->flags & IFF_MASTER))
- goto out;
+ if (skb->protocol != cpu_to_be16(ETH_P_ARP))
+ return;
+ arp = (struct arp_pkt *) skb->data;
if (!arp) {
pr_debug("Packet has no ARP data\n");
- goto out;
+ return;
}
- skb = skb_share_check(skb, GFP_ATOMIC);
- if (!skb)
- goto out;
-
- if (!pskb_may_pull(skb, arp_hdr_len(bond_dev)))
- goto out;
+ if (!pskb_may_pull(skb, arp_hdr_len(bond->dev)))
+ return;
if (skb->len < sizeof(struct arp_pkt)) {
pr_debug("Packet is too small to be an ARP\n");
- goto out;
+ return;
}
if (arp->op_code == htons(ARPOP_REPLY)) {
/* update rx hash table for this ARP */
- bond = netdev_priv(bond_dev);
rlb_update_entry_from_arp(bond, arp);
pr_debug("Server received an ARP Reply from client\n");
}
-
- res = NET_RX_SUCCESS;
-
-out:
- dev_kfree_skb(skb);
-
- return res;
}
/* Caller must hold bond lock for read */
@@ -759,13 +741,10 @@ static void rlb_init_table_entry(struct rlb_client_info *entry)
static int rlb_initialize(struct bonding *bond)
{
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
- struct packet_type *pk_type = &(BOND_ALB_INFO(bond).rlb_pkt_type);
struct rlb_client_info *new_hashtbl;
int size = RLB_HASH_TABLE_SIZE * sizeof(struct rlb_client_info);
int i;
- spin_lock_init(&(bond_info->rx_hashtbl_lock));
-
new_hashtbl = kmalloc(size, GFP_KERNEL);
if (!new_hashtbl) {
pr_err("%s: Error: Failed to allocate RLB hash table\n",
@@ -784,13 +763,8 @@ static int rlb_initialize(struct bonding *bond)
_unlock_rx_hashtbl(bond);
- /*initialize packet type*/
- pk_type->type = cpu_to_be16(ETH_P_ARP);
- pk_type->dev = bond->dev;
- pk_type->func = rlb_arp_recv;
-
/* register to receive ARPs */
- dev_add_pack(pk_type);
+ bond->recv_probe = rlb_arp_recv;
return 0;
}
@@ -799,8 +773,6 @@ static void rlb_deinitialize(struct bonding *bond)
{
struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
- dev_remove_pack(&(bond_info->rlb_pkt_type));
-
_lock_rx_hashtbl(bond);
kfree(bond_info->rx_hashtbl);
@@ -1249,16 +1221,10 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
skb_reset_mac_header(skb);
eth_data = eth_hdr(skb);
- /* make sure that the curr_active_slave and the slaves list do
- * not change during tx
+ /* make sure that the curr_active_slave do not change during tx
*/
- read_lock(&bond->lock);
read_lock(&bond->curr_slave_lock);
- if (!BOND_IS_OK(bond)) {
- goto out;
- }
-
switch (ntohs(skb->protocol)) {
case ETH_P_IP: {
const struct iphdr *iph = ip_hdr(skb);
@@ -1358,13 +1324,12 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
}
}
-out:
if (res) {
/* no suitable interface, frame not sent */
dev_kfree_skb(skb);
}
read_unlock(&bond->curr_slave_lock);
- read_unlock(&bond->lock);
+
return NETDEV_TX_OK;
}
diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h
index 8ca7158b2dda..90f140a2d197 100644
--- a/drivers/net/bonding/bond_alb.h
+++ b/drivers/net/bonding/bond_alb.h
@@ -129,7 +129,6 @@ struct alb_bond_info {
int lp_counter;
/* -------- rlb parameters -------- */
int rlb_enabled;
- struct packet_type rlb_pkt_type;
struct rlb_client_info *rx_hashtbl; /* Receive hash table */
spinlock_t rx_hashtbl_lock;
u32 rx_hashtbl_head;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 16d6fe954695..6141667c5fb7 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -89,8 +89,7 @@
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 num_peer_notif = 1;
static int miimon = BOND_LINK_MON_INTERV;
static int updelay;
static int downdelay;
@@ -113,10 +112,10 @@ 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);
-MODULE_PARM_DESC(num_unsol_na, "Number of unsolicited IPv6 Neighbor Advertisements packets to send on failover event");
+module_param_named(num_grat_arp, num_peer_notif, int, 0644);
+MODULE_PARM_DESC(num_grat_arp, "Number of peer notifications to send on failover event (alias of num_unsol_na)");
+module_param_named(num_unsol_na, num_peer_notif, int, 0644);
+MODULE_PARM_DESC(num_unsol_na, "Number of peer notifications to send on failover event (alias of num_grat_arp)");
module_param(miimon, int, 0);
MODULE_PARM_DESC(miimon, "Link check interval in milliseconds");
module_param(updelay, int, 0);
@@ -234,7 +233,6 @@ struct bond_parm_tbl ad_select_tbl[] = {
/*-------------------------- Forward declarations ---------------------------*/
-static void bond_send_gratuitous_arp(struct bonding *bond);
static int bond_init(struct net_device *bond_dev);
static void bond_uninit(struct net_device *bond_dev);
@@ -346,32 +344,6 @@ out:
}
/**
- * bond_has_challenged_slaves
- * @bond: the bond we're working on
- *
- * Searches the slave list. Returns 1 if a vlan challenged slave
- * was found, 0 otherwise.
- *
- * Assumes bond->lock is held.
- */
-static int bond_has_challenged_slaves(struct bonding *bond)
-{
- struct slave *slave;
- int i;
-
- bond_for_each_slave(bond, slave, i) {
- if (slave->dev->features & NETIF_F_VLAN_CHALLENGED) {
- pr_debug("found VLAN challenged slave - %s\n",
- slave->dev->name);
- return 1;
- }
- }
-
- pr_debug("no VLAN challenged slaves found\n");
- return 0;
-}
-
-/**
* bond_next_vlan - safely skip to the next item in the vlans list.
* @bond: the bond we're working on
* @curr: item we're advancing from
@@ -631,7 +603,8 @@ down:
static int bond_update_speed_duplex(struct slave *slave)
{
struct net_device *slave_dev = slave->dev;
- struct ethtool_cmd etool;
+ struct ethtool_cmd etool = { .cmd = ETHTOOL_GSET };
+ u32 slave_speed;
int res;
/* Fake speed and duplex */
@@ -645,7 +618,8 @@ static int bond_update_speed_duplex(struct slave *slave)
if (res < 0)
return -1;
- switch (etool.speed) {
+ slave_speed = ethtool_cmd_speed(&etool);
+ switch (slave_speed) {
case SPEED_10:
case SPEED_100:
case SPEED_1000:
@@ -663,7 +637,7 @@ static int bond_update_speed_duplex(struct slave *slave)
return -1;
}
- slave->speed = etool.speed;
+ slave->speed = slave_speed;
slave->duplex = etool.duplex;
return 0;
@@ -878,7 +852,7 @@ static void bond_resend_igmp_join_requests(struct bonding *bond)
static void bond_resend_igmp_join_requests_delayed(struct work_struct *work)
{
struct bonding *bond = container_of(work, struct bonding,
- mcast_work.work);
+ mcast_work.work);
bond_resend_igmp_join_requests(bond);
}
@@ -1087,6 +1061,21 @@ static struct slave *bond_find_best_slave(struct bonding *bond)
return bestslave;
}
+static bool bond_should_notify_peers(struct bonding *bond)
+{
+ struct slave *slave = bond->curr_active_slave;
+
+ pr_debug("bond_should_notify_peers: bond %s slave %s\n",
+ bond->dev->name, slave ? slave->dev->name : "NULL");
+
+ if (!slave || !bond->send_peer_notif ||
+ test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state))
+ return false;
+
+ bond->send_peer_notif--;
+ return true;
+}
+
/**
* change_active_interface - change the active slave into the specified one
* @bond: our bonding struct
@@ -1154,6 +1143,8 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
bond_set_slave_inactive_flags(old_active);
if (new_active) {
+ bool should_notify_peers = false;
+
bond_set_slave_active_flags(new_active);
if (bond->params.fail_over_mac)
@@ -1161,17 +1152,19 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
old_active);
if (netif_running(bond->dev)) {
- bond->send_grat_arp = bond->params.num_grat_arp;
- bond_send_gratuitous_arp(bond);
-
- bond->send_unsol_na = bond->params.num_unsol_na;
- bond_send_unsolicited_na(bond);
+ bond->send_peer_notif =
+ bond->params.num_peer_notif;
+ should_notify_peers =
+ bond_should_notify_peers(bond);
}
write_unlock_bh(&bond->curr_slave_lock);
read_unlock(&bond->lock);
netdev_bonding_change(bond->dev, NETDEV_BONDING_FAILOVER);
+ if (should_notify_peers)
+ netdev_bonding_change(bond->dev,
+ NETDEV_NOTIFY_PEERS);
read_lock(&bond->lock);
write_lock_bh(&bond->curr_slave_lock);
@@ -1179,10 +1172,12 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
}
/* resend IGMP joins since active slave has changed or
- * all were sent on curr_active_slave */
- if (((USES_PRIMARY(bond->params.mode) && new_active) ||
- bond->params.mode == BOND_MODE_ROUNDROBIN) &&
- netif_running(bond->dev)) {
+ * all were sent on curr_active_slave.
+ * resend only if bond is brought up with the affected
+ * bonding modes and the retransmission is enabled */
+ if (netif_running(bond->dev) && (bond->params.resend_igmp > 0) &&
+ ((USES_PRIMARY(bond->params.mode) && new_active) ||
+ bond->params.mode == BOND_MODE_ROUNDROBIN)) {
bond->igmp_retrans = bond->params.resend_igmp;
queue_delayed_work(bond->wq, &bond->mcast_work, 0);
}
@@ -1387,52 +1382,68 @@ static int bond_sethwaddr(struct net_device *bond_dev,
return 0;
}
-#define BOND_VLAN_FEATURES \
- (NETIF_F_VLAN_CHALLENGED | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX | \
- NETIF_F_HW_VLAN_FILTER)
-
-/*
- * Compute the common dev->feature set available to all slaves. Some
- * feature bits are managed elsewhere, so preserve those feature bits
- * on the master device.
- */
-static int bond_compute_features(struct bonding *bond)
+static u32 bond_fix_features(struct net_device *dev, u32 features)
{
struct slave *slave;
- struct net_device *bond_dev = bond->dev;
- u32 features = bond_dev->features;
- u32 vlan_features = 0;
- unsigned short max_hard_header_len = max((u16)ETH_HLEN,
- bond_dev->hard_header_len);
+ struct bonding *bond = netdev_priv(dev);
+ u32 mask;
int i;
- features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES);
- features |= NETIF_F_GSO_MASK | NETIF_F_NO_CSUM;
+ read_lock(&bond->lock);
- if (!bond->first_slave)
- goto done;
+ if (!bond->first_slave) {
+ /* Disable adding VLANs to empty bond. But why? --mq */
+ features |= NETIF_F_VLAN_CHALLENGED;
+ goto out;
+ }
+ mask = features;
features &= ~NETIF_F_ONE_FOR_ALL;
+ features |= NETIF_F_ALL_FOR_ALL;
- vlan_features = bond->first_slave->dev->vlan_features;
bond_for_each_slave(bond, slave, i) {
features = netdev_increment_features(features,
slave->dev->features,
- NETIF_F_ONE_FOR_ALL);
+ mask);
+ }
+
+out:
+ read_unlock(&bond->lock);
+ return features;
+}
+
+#define BOND_VLAN_FEATURES (NETIF_F_ALL_TX_OFFLOADS | \
+ NETIF_F_SOFT_FEATURES | \
+ NETIF_F_LRO)
+
+static void bond_compute_features(struct bonding *bond)
+{
+ struct slave *slave;
+ struct net_device *bond_dev = bond->dev;
+ u32 vlan_features = BOND_VLAN_FEATURES;
+ unsigned short max_hard_header_len = ETH_HLEN;
+ int i;
+
+ read_lock(&bond->lock);
+
+ if (!bond->first_slave)
+ goto done;
+
+ bond_for_each_slave(bond, slave, i) {
vlan_features = netdev_increment_features(vlan_features,
- slave->dev->vlan_features,
- NETIF_F_ONE_FOR_ALL);
+ slave->dev->vlan_features, BOND_VLAN_FEATURES);
+
if (slave->dev->hard_header_len > max_hard_header_len)
max_hard_header_len = slave->dev->hard_header_len;
}
done:
- features |= (bond_dev->features & BOND_VLAN_FEATURES);
- bond_dev->features = netdev_fix_features(bond_dev, features);
- bond_dev->vlan_features = netdev_fix_features(bond_dev, vlan_features);
+ bond_dev->vlan_features = vlan_features;
bond_dev->hard_header_len = max_hard_header_len;
- return 0;
+ read_unlock(&bond->lock);
+
+ netdev_change_features(bond_dev);
}
static void bond_setup_by_slave(struct net_device *bond_dev,
@@ -1452,27 +1463,17 @@ static void bond_setup_by_slave(struct net_device *bond_dev,
}
/* On bonding slaves other than the currently active slave, suppress
- * duplicates except for 802.3ad ETH_P_SLOW, alb non-mcast/bcast, and
- * ARP on active-backup slaves with arp_validate enabled.
+ * duplicates except for alb non-mcast/bcast.
*/
static bool bond_should_deliver_exact_match(struct sk_buff *skb,
struct slave *slave,
struct bonding *bond)
{
if (bond_is_slave_inactive(slave)) {
- if (slave_do_arp_validate(bond, slave) &&
- skb->protocol == __cpu_to_be16(ETH_P_ARP))
- return false;
-
if (bond->params.mode == BOND_MODE_ALB &&
skb->pkt_type != PACKET_BROADCAST &&
skb->pkt_type != PACKET_MULTICAST)
- return false;
-
- if (bond->params.mode == BOND_MODE_8023AD &&
- skb->protocol == __cpu_to_be16(ETH_P_SLOW))
return false;
-
return true;
}
return false;
@@ -1496,6 +1497,15 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb)
if (bond->params.arp_interval)
slave->dev->last_rx = jiffies;
+ if (bond->recv_probe) {
+ struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC);
+
+ if (likely(nskb)) {
+ bond->recv_probe(nskb, bond, slave);
+ dev_kfree_skb(nskb);
+ }
+ }
+
if (bond_should_deliver_exact_match(skb, slave, bond)) {
return RX_HANDLER_EXACT;
}
@@ -1526,7 +1536,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
struct netdev_hw_addr *ha;
struct sockaddr addr;
int link_reporting;
- int old_features = bond_dev->features;
int res = 0;
if (!bond->params.use_carrier && slave_dev->ethtool_ops == NULL &&
@@ -1535,12 +1544,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
bond_dev->name, slave_dev->name);
}
- /* bond must be initialized by bond_open() before enslaving */
- if (!(bond_dev->flags & IFF_UP)) {
- pr_warning("%s: master_dev is not up in bond_enslave\n",
- bond_dev->name);
- }
-
/* already enslaved */
if (slave_dev->flags & IFF_SLAVE) {
pr_debug("Error, Device was already enslaved\n");
@@ -1559,16 +1562,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
pr_warning("%s: Warning: enslaved VLAN challenged slave %s. Adding VLANs will be blocked as long as %s is part of bond %s\n",
bond_dev->name, slave_dev->name,
slave_dev->name, bond_dev->name);
- bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
}
} else {
pr_debug("%s: ! NETIF_F_VLAN_CHALLENGED\n", slave_dev->name);
- if (bond->slave_cnt == 0) {
- /* First slave, and it is not VLAN challenged,
- * so remove the block of adding VLANs over the bond.
- */
- bond_dev->features &= ~NETIF_F_VLAN_CHALLENGED;
- }
}
/*
@@ -1640,6 +1636,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
}
}
+ call_netdevice_notifiers(NETDEV_JOIN, 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 (is_zero_ether_addr(bond->dev->dev_addr))
@@ -1757,10 +1755,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
new_slave->delay = 0;
new_slave->link_failure_count = 0;
- bond_compute_features(bond);
-
write_unlock_bh(&bond->lock);
+ bond_compute_features(bond);
+
read_lock(&bond->lock);
new_slave->last_arp_rx = jiffies;
@@ -1940,7 +1938,7 @@ err_free:
kfree(new_slave);
err_undo_flags:
- bond_dev->features = old_features;
+ bond_compute_features(bond);
return res;
}
@@ -1961,6 +1959,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
struct bonding *bond = netdev_priv(bond_dev);
struct slave *slave, *oldcurrent;
struct sockaddr addr;
+ u32 old_features = bond_dev->features;
/* slave is not a slave or master is not master of this slave */
if (!(slave_dev->flags & IFF_SLAVE) ||
@@ -1971,7 +1970,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
}
block_netpoll_tx();
- netdev_bonding_change(bond_dev, NETDEV_BONDING_DESLAVE);
+ netdev_bonding_change(bond_dev, NETDEV_RELEASE);
write_lock_bh(&bond->lock);
slave = bond_get_slave_by_dev(bond, slave_dev);
@@ -2021,8 +2020,6 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
/* release the slave from its bond */
bond_detach_slave(bond, slave);
- bond_compute_features(bond);
-
if (bond->primary_slave == slave)
bond->primary_slave = NULL;
@@ -2066,24 +2063,23 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
*/
memset(bond_dev->dev_addr, 0, bond_dev->addr_len);
- if (!bond->vlgrp) {
- bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
- } else {
+ if (bond->vlgrp) {
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",
bond_dev->name);
}
- } else if ((bond_dev->features & NETIF_F_VLAN_CHALLENGED) &&
- !bond_has_challenged_slaves(bond)) {
- pr_info("%s: last VLAN challenged slave %s left bond %s. VLAN blocking is removed\n",
- bond_dev->name, slave_dev->name, bond_dev->name);
- bond_dev->features &= ~NETIF_F_VLAN_CHALLENGED;
}
write_unlock_bh(&bond->lock);
unblock_netpoll_tx();
+ bond_compute_features(bond);
+ if (!(bond_dev->features & NETIF_F_VLAN_CHALLENGED) &&
+ (old_features & NETIF_F_VLAN_CHALLENGED))
+ pr_info("%s: last VLAN challenged slave %s left bond %s. VLAN blocking is removed\n",
+ bond_dev->name, slave_dev->name, bond_dev->name);
+
/* must do this from outside any spinlocks */
bond_destroy_slave_symlinks(bond_dev, slave_dev);
@@ -2201,8 +2197,6 @@ static int bond_release_all(struct net_device *bond_dev)
bond_alb_deinit_slave(bond, slave);
}
- bond_compute_features(bond);
-
bond_destroy_slave_symlinks(bond_dev, slave_dev);
bond_del_vlans_from_slave(bond, slave_dev);
@@ -2251,9 +2245,7 @@ static int bond_release_all(struct net_device *bond_dev)
*/
memset(bond_dev->dev_addr, 0, bond_dev->addr_len);
- if (!bond->vlgrp) {
- bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
- } else {
+ if (bond->vlgrp) {
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",
@@ -2264,6 +2256,9 @@ static int bond_release_all(struct net_device *bond_dev)
out:
write_unlock_bh(&bond->lock);
+
+ bond_compute_features(bond);
+
return 0;
}
@@ -2493,7 +2488,7 @@ static void bond_miimon_commit(struct bonding *bond)
bond_update_speed_duplex(slave);
- pr_info("%s: link status definitely up for interface %s, %d Mbps %s duplex.\n",
+ pr_info("%s: link status definitely up for interface %s, %u Mbps %s duplex.\n",
bond->dev->name, slave->dev->name,
slave->speed, slave->duplex ? "full" : "half");
@@ -2570,6 +2565,7 @@ void bond_mii_monitor(struct work_struct *work)
{
struct bonding *bond = container_of(work, struct bonding,
mii_work.work);
+ bool should_notify_peers = false;
read_lock(&bond->lock);
if (bond->kill_timers)
@@ -2578,17 +2574,7 @@ void bond_mii_monitor(struct work_struct *work)
if (bond->slave_cnt == 0)
goto re_arm;
- if (bond->send_grat_arp) {
- read_lock(&bond->curr_slave_lock);
- bond_send_gratuitous_arp(bond);
- read_unlock(&bond->curr_slave_lock);
- }
-
- if (bond->send_unsol_na) {
- read_lock(&bond->curr_slave_lock);
- bond_send_unsolicited_na(bond);
- read_unlock(&bond->curr_slave_lock);
- }
+ should_notify_peers = bond_should_notify_peers(bond);
if (bond_miimon_inspect(bond)) {
read_unlock(&bond->lock);
@@ -2608,6 +2594,12 @@ re_arm:
msecs_to_jiffies(bond->params.miimon));
out:
read_unlock(&bond->lock);
+
+ if (should_notify_peers) {
+ rtnl_lock();
+ netdev_bonding_change(bond->dev, NETDEV_NOTIFY_PEERS);
+ rtnl_unlock();
+ }
}
static __be32 bond_glean_dev_ip(struct net_device *dev)
@@ -2751,44 +2743,6 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
}
}
-/*
- * Kick out a gratuitous ARP for an IP on the bonding master plus one
- * for each VLAN above us.
- *
- * Caller must hold curr_slave_lock for read or better
- */
-static void bond_send_gratuitous_arp(struct bonding *bond)
-{
- struct slave *slave = bond->curr_active_slave;
- struct vlan_entry *vlan;
- struct net_device *vlan_dev;
-
- pr_debug("bond_send_grat_arp: bond %s slave %s\n",
- bond->dev->name, slave ? slave->dev->name : "NULL");
-
- if (!slave || !bond->send_grat_arp ||
- test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state))
- return;
-
- bond->send_grat_arp--;
-
- if (bond->master_ip) {
- bond_arp_send(slave->dev, ARPOP_REPLY, bond->master_ip,
- 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) {
- bond_arp_send(slave->dev, ARPOP_REPLY, vlan->vlan_ip,
- vlan->vlan_ip, vlan->vlan_id);
- }
- }
-}
-
static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32 sip, __be32 tip)
{
int i;
@@ -2806,48 +2760,26 @@ static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32
}
}
-static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
+static void bond_arp_rcv(struct sk_buff *skb, struct bonding *bond,
+ struct slave *slave)
{
struct arphdr *arp;
- struct slave *slave;
- struct bonding *bond;
unsigned char *arp_ptr;
__be32 sip, tip;
- if (dev->priv_flags & IFF_802_1Q_VLAN) {
- /*
- * When using VLANS and bonding, dev and oriv_dev may be
- * incorrect if the physical interface supports VLAN
- * acceleration. With this change ARP validation now
- * works for hosts only reachable on the VLAN interface.
- */
- dev = vlan_dev_real_dev(dev);
- orig_dev = dev_get_by_index_rcu(dev_net(skb->dev),skb->skb_iif);
- }
-
- if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER))
- goto out;
+ if (skb->protocol != __cpu_to_be16(ETH_P_ARP))
+ return;
- bond = netdev_priv(dev);
read_lock(&bond->lock);
- pr_debug("bond_arp_rcv: bond %s skb->dev %s orig_dev %s\n",
- bond->dev->name, skb->dev ? skb->dev->name : "NULL",
- orig_dev ? orig_dev->name : "NULL");
+ pr_debug("bond_arp_rcv: bond %s skb->dev %s\n",
+ bond->dev->name, skb->dev->name);
- slave = bond_get_slave_by_dev(bond, orig_dev);
- if (!slave || !slave_do_arp_validate(bond, slave))
- goto out_unlock;
-
- skb = skb_share_check(skb, GFP_ATOMIC);
- if (!skb)
- goto out_unlock;
-
- if (!pskb_may_pull(skb, arp_hdr_len(dev)))
+ if (!pskb_may_pull(skb, arp_hdr_len(bond->dev)))
goto out_unlock;
arp = arp_hdr(skb);
- if (arp->ar_hln != dev->addr_len ||
+ if (arp->ar_hln != bond->dev->addr_len ||
skb->pkt_type == PACKET_OTHERHOST ||
skb->pkt_type == PACKET_LOOPBACK ||
arp->ar_hrd != htons(ARPHRD_ETHER) ||
@@ -2856,9 +2788,9 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack
goto out_unlock;
arp_ptr = (unsigned char *)(arp + 1);
- arp_ptr += dev->addr_len;
+ arp_ptr += bond->dev->addr_len;
memcpy(&sip, arp_ptr, 4);
- arp_ptr += 4 + dev->addr_len;
+ arp_ptr += 4 + bond->dev->addr_len;
memcpy(&tip, arp_ptr, 4);
pr_debug("bond_arp_rcv: %s %s/%d av %d sv %d sip %pI4 tip %pI4\n",
@@ -2881,9 +2813,6 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack
out_unlock:
read_unlock(&bond->lock);
-out:
- dev_kfree_skb(skb);
- return NET_RX_SUCCESS;
}
/*
@@ -3243,6 +3172,7 @@ void bond_activebackup_arp_mon(struct work_struct *work)
{
struct bonding *bond = container_of(work, struct bonding,
arp_work.work);
+ bool should_notify_peers = false;
int delta_in_ticks;
read_lock(&bond->lock);
@@ -3255,17 +3185,7 @@ void bond_activebackup_arp_mon(struct work_struct *work)
if (bond->slave_cnt == 0)
goto re_arm;
- if (bond->send_grat_arp) {
- read_lock(&bond->curr_slave_lock);
- bond_send_gratuitous_arp(bond);
- read_unlock(&bond->curr_slave_lock);
- }
-
- if (bond->send_unsol_na) {
- read_lock(&bond->curr_slave_lock);
- bond_send_unsolicited_na(bond);
- read_unlock(&bond->curr_slave_lock);
- }
+ should_notify_peers = bond_should_notify_peers(bond);
if (bond_ab_arp_inspect(bond, delta_in_ticks)) {
read_unlock(&bond->lock);
@@ -3286,6 +3206,12 @@ re_arm:
queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
out:
read_unlock(&bond->lock);
+
+ if (should_notify_peers) {
+ rtnl_lock();
+ netdev_bonding_change(bond->dev, NETDEV_NOTIFY_PEERS);
+ rtnl_unlock();
+ }
}
/*-------------------------- netdev event handling --------------------------*/
@@ -3339,8 +3265,8 @@ static int bond_slave_netdev_event(unsigned long event,
slave = bond_get_slave_by_dev(bond, slave_dev);
if (slave) {
- u16 old_speed = slave->speed;
- u16 old_duplex = slave->duplex;
+ u32 old_speed = slave->speed;
+ u8 old_duplex = slave->duplex;
bond_update_speed_duplex(slave);
@@ -3482,48 +3408,6 @@ static struct notifier_block bond_inetaddr_notifier = {
.notifier_call = bond_inetaddr_event,
};
-/*-------------------------- Packet type handling ---------------------------*/
-
-/* register to receive lacpdus on a bond */
-static void bond_register_lacpdu(struct bonding *bond)
-{
- struct packet_type *pk_type = &(BOND_AD_INFO(bond).ad_pkt_type);
-
- /* initialize packet type */
- pk_type->type = PKT_TYPE_LACPDU;
- pk_type->dev = bond->dev;
- pk_type->func = bond_3ad_lacpdu_recv;
-
- dev_add_pack(pk_type);
-}
-
-/* unregister to receive lacpdus on a bond */
-static void bond_unregister_lacpdu(struct bonding *bond)
-{
- dev_remove_pack(&(BOND_AD_INFO(bond).ad_pkt_type));
-}
-
-void bond_register_arp(struct bonding *bond)
-{
- struct packet_type *pt = &bond->arp_mon_pt;
-
- if (pt->type)
- return;
-
- pt->type = htons(ETH_P_ARP);
- pt->dev = bond->dev;
- pt->func = bond_arp_rcv;
- dev_add_pack(pt);
-}
-
-void bond_unregister_arp(struct bonding *bond)
-{
- struct packet_type *pt = &bond->arp_mon_pt;
-
- dev_remove_pack(pt);
- pt->type = 0;
-}
-
/*---------------------------- Hashing Policies -----------------------------*/
/*
@@ -3617,14 +3501,14 @@ static int bond_open(struct net_device *bond_dev)
queue_delayed_work(bond->wq, &bond->arp_work, 0);
if (bond->params.arp_validate)
- bond_register_arp(bond);
+ bond->recv_probe = bond_arp_rcv;
}
if (bond->params.mode == BOND_MODE_8023AD) {
INIT_DELAYED_WORK(&bond->ad_work, bond_3ad_state_machine_handler);
queue_delayed_work(bond->wq, &bond->ad_work, 0);
/* register to receive LACPDUs */
- bond_register_lacpdu(bond);
+ bond->recv_probe = bond_3ad_lacpdu_recv;
bond_3ad_initiate_agg_selection(bond, 1);
}
@@ -3635,18 +3519,9 @@ static int bond_close(struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
- if (bond->params.mode == BOND_MODE_8023AD) {
- /* Unregister the receive of LACPDUs */
- bond_unregister_lacpdu(bond);
- }
-
- if (bond->params.arp_validate)
- bond_unregister_arp(bond);
-
write_lock_bh(&bond->lock);
- bond->send_grat_arp = 0;
- bond->send_unsol_na = 0;
+ bond->send_peer_notif = 0;
/* signal timers not to re-arm */
bond->kill_timers = 1;
@@ -3682,6 +3557,7 @@ static int bond_close(struct net_device *bond_dev)
*/
bond_alb_deinitialize(bond);
}
+ bond->recv_probe = NULL;
return 0;
}
@@ -4105,10 +3981,6 @@ static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev
int i, slave_no, res = 1;
struct iphdr *iph = ip_hdr(skb);
- read_lock(&bond->lock);
-
- if (!BOND_IS_OK(bond))
- goto out;
/*
* Start with the curr_active_slave that joined the bond as the
* default for sending IGMP traffic. For failover purposes one
@@ -4155,7 +4027,7 @@ out:
/* no suitable interface, frame not sent */
dev_kfree_skb(skb);
}
- read_unlock(&bond->lock);
+
return NETDEV_TX_OK;
}
@@ -4169,24 +4041,18 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d
struct bonding *bond = netdev_priv(bond_dev);
int res = 1;
- read_lock(&bond->lock);
read_lock(&bond->curr_slave_lock);
- if (!BOND_IS_OK(bond))
- goto out;
-
- if (!bond->curr_active_slave)
- goto out;
-
- res = bond_dev_queue_xmit(bond, skb, bond->curr_active_slave->dev);
+ if (bond->curr_active_slave)
+ res = bond_dev_queue_xmit(bond, skb,
+ bond->curr_active_slave->dev);
-out:
if (res)
/* no suitable interface, frame not sent */
dev_kfree_skb(skb);
read_unlock(&bond->curr_slave_lock);
- read_unlock(&bond->lock);
+
return NETDEV_TX_OK;
}
@@ -4203,11 +4069,6 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev)
int i;
int res = 1;
- read_lock(&bond->lock);
-
- if (!BOND_IS_OK(bond))
- goto out;
-
slave_no = bond->xmit_hash_policy(skb, bond->slave_cnt);
bond_for_each_slave(bond, slave, i) {
@@ -4227,12 +4088,11 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev)
}
}
-out:
if (res) {
/* no suitable interface, frame not sent */
dev_kfree_skb(skb);
}
- read_unlock(&bond->lock);
+
return NETDEV_TX_OK;
}
@@ -4247,11 +4107,6 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev)
int i;
int res = 1;
- read_lock(&bond->lock);
-
- if (!BOND_IS_OK(bond))
- goto out;
-
read_lock(&bond->curr_slave_lock);
start_at = bond->curr_active_slave;
read_unlock(&bond->curr_slave_lock);
@@ -4290,7 +4145,6 @@ out:
dev_kfree_skb(skb);
/* frame sent to all suitable interfaces */
- read_unlock(&bond->lock);
return NETDEV_TX_OK;
}
@@ -4322,10 +4176,8 @@ static inline int bond_slave_override(struct bonding *bond,
struct slave *slave = NULL;
struct slave *check_slave;
- read_lock(&bond->lock);
-
- if (!BOND_IS_OK(bond) || !skb->queue_mapping)
- goto out;
+ if (!skb->queue_mapping)
+ return 1;
/* Find out if any slaves have the same mapping as this skb. */
bond_for_each_slave(bond, check_slave, i) {
@@ -4341,8 +4193,6 @@ static inline int bond_slave_override(struct bonding *bond,
res = bond_dev_queue_xmit(bond, skb, slave->dev);
}
-out:
- read_unlock(&bond->lock);
return res;
}
@@ -4357,24 +4207,17 @@ static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb)
u16 txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) : 0;
if (unlikely(txq >= dev->real_num_tx_queues)) {
- do
+ do {
txq -= dev->real_num_tx_queues;
- while (txq >= dev->real_num_tx_queues);
+ } while (txq >= dev->real_num_tx_queues);
}
return txq;
}
-static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t __bond_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct bonding *bond = netdev_priv(dev);
- /*
- * If we risk deadlock from transmitting this in the
- * netpoll path, tell netpoll to queue the frame for later tx
- */
- if (is_netpoll_tx_blocked(dev))
- return NETDEV_TX_BUSY;
-
if (TX_QUEUE_OVERRIDE(bond->params.mode)) {
if (!bond_slave_override(bond, skb))
return NETDEV_TX_OK;
@@ -4404,6 +4247,29 @@ static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
}
+static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct bonding *bond = netdev_priv(dev);
+ netdev_tx_t ret = NETDEV_TX_OK;
+
+ /*
+ * If we risk deadlock from transmitting this in the
+ * netpoll path, tell netpoll to queue the frame for later tx
+ */
+ if (is_netpoll_tx_blocked(dev))
+ return NETDEV_TX_BUSY;
+
+ read_lock(&bond->lock);
+
+ if (bond->slave_cnt)
+ ret = __bond_start_xmit(skb, dev);
+ else
+ dev_kfree_skb(skb);
+
+ read_unlock(&bond->lock);
+
+ return ret;
+}
/*
* set bond mode specific net device operations
@@ -4448,11 +4314,6 @@ static void bond_ethtool_get_drvinfo(struct net_device *bond_dev,
static const struct ethtool_ops bond_ethtool_ops = {
.get_drvinfo = bond_ethtool_get_drvinfo,
.get_link = ethtool_op_get_link,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .get_sg = ethtool_op_get_sg,
- .get_tso = ethtool_op_get_tso,
- .get_ufo = ethtool_op_get_ufo,
- .get_flags = ethtool_op_get_flags,
};
static const struct net_device_ops bond_netdev_ops = {
@@ -4478,6 +4339,7 @@ static const struct net_device_ops bond_netdev_ops = {
#endif
.ndo_add_slave = bond_enslave,
.ndo_del_slave = bond_release,
+ .ndo_fix_features = bond_fix_features,
};
static void bond_destructor(struct net_device *bond_dev)
@@ -4533,14 +4395,14 @@ static void bond_setup(struct net_device *bond_dev)
* when there are slaves that are not hw accel
* capable
*/
- bond_dev->features |= (NETIF_F_HW_VLAN_TX |
- NETIF_F_HW_VLAN_RX |
- NETIF_F_HW_VLAN_FILTER);
- /* By default, we enable GRO on bonding devices.
- * Actual support requires lowlevel drivers are GRO ready.
- */
- bond_dev->features |= NETIF_F_GRO;
+ bond_dev->hw_features = BOND_VLAN_FEATURES |
+ NETIF_F_HW_VLAN_TX |
+ NETIF_F_HW_VLAN_RX |
+ NETIF_F_HW_VLAN_FILTER;
+
+ bond_dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_NO_CSUM);
+ bond_dev->features |= bond_dev->hw_features;
}
static void bond_work_cancel_all(struct bonding *bond)
@@ -4724,16 +4586,10 @@ static int bond_check_params(struct bond_params *params)
use_carrier = 1;
}
- if (num_grat_arp < 0 || num_grat_arp > 255) {
- pr_warning("Warning: num_grat_arp (%d) not in range 0-255 so it was reset to 1\n",
- num_grat_arp);
- num_grat_arp = 1;
- }
-
- if (num_unsol_na < 0 || num_unsol_na > 255) {
- pr_warning("Warning: num_unsol_na (%d) not in range 0-255 so it was reset to 1\n",
- num_unsol_na);
- num_unsol_na = 1;
+ if (num_peer_notif < 0 || num_peer_notif > 255) {
+ pr_warning("Warning: num_grat_arp/num_unsol_na (%d) not in range 0-255 so it was reset to 1\n",
+ num_peer_notif);
+ num_peer_notif = 1;
}
/* reset values for 802.3ad */
@@ -4925,8 +4781,7 @@ static int bond_check_params(struct bond_params *params)
params->mode = bond_mode;
params->xmit_policy = xmit_hashtype;
params->miimon = miimon;
- params->num_grat_arp = num_grat_arp;
- params->num_unsol_na = num_unsol_na;
+ params->num_peer_notif = num_peer_notif;
params->arp_interval = arp_interval;
params->arp_validate = arp_validate_value;
params->updelay = updelay;
@@ -4975,9 +4830,19 @@ static int bond_init(struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
struct bond_net *bn = net_generic(dev_net(bond_dev), bond_net_id);
+ struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
pr_debug("Begin bond_init for %s\n", bond_dev->name);
+ /*
+ * Initialize locks that may be required during
+ * en/deslave operations. All of the bond_open work
+ * (of which this is part) should really be moved to
+ * a phase prior to dev_open
+ */
+ spin_lock_init(&(bond_info->tx_hashtbl_lock));
+ spin_lock_init(&(bond_info->rx_hashtbl_lock));
+
bond->wq = create_singlethread_workqueue(bond_dev->name);
if (!bond->wq)
return -ENOMEM;
@@ -5025,8 +4890,9 @@ int bond_create(struct net *net, const char *name)
rtnl_lock();
- bond_dev = alloc_netdev_mq(sizeof(struct bonding), name ? name : "",
- bond_setup, tx_queues);
+ bond_dev = alloc_netdev_mq(sizeof(struct bonding),
+ name ? name : "bond%d",
+ bond_setup, tx_queues);
if (!bond_dev) {
pr_err("%s: eek! can't alloc netdev!\n", name);
rtnl_unlock();
@@ -5036,26 +4902,10 @@ int bond_create(struct net *net, const char *name)
dev_net_set(bond_dev, net);
bond_dev->rtnl_link_ops = &bond_link_ops;
- if (!name) {
- res = dev_alloc_name(bond_dev, "bond%d");
- if (res < 0)
- goto out;
- } else {
- /*
- * If we're given a name to register
- * we need to ensure that its not already
- * registered
- */
- res = -EEXIST;
- if (__dev_get_by_name(net, name) != NULL)
- goto out;
- }
-
res = register_netdevice(bond_dev);
netif_carrier_off(bond_dev);
-out:
rtnl_unlock();
if (res < 0)
bond_destructor(bond_dev);
@@ -5121,7 +4971,6 @@ static int __init bonding_init(void)
register_netdevice_notifier(&bond_netdev_notifier);
register_inetaddr_notifier(&bond_inetaddr_notifier);
- bond_register_ipv6_notifier();
out:
return res;
err:
@@ -5136,7 +4985,6 @@ static void __exit bonding_exit(void)
{
unregister_netdevice_notifier(&bond_netdev_notifier);
unregister_inetaddr_notifier(&bond_inetaddr_notifier);
- bond_unregister_ipv6_notifier();
bond_destroy_sysfs();
bond_destroy_debugfs();
diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c
index c32ff55a34c1..c97307ddd1c9 100644
--- a/drivers/net/bonding/bond_procfs.c
+++ b/drivers/net/bonding/bond_procfs.c
@@ -4,8 +4,6 @@
#include "bonding.h"
-extern const char *bond_mode_name(int mode);
-
static void *bond_info_seq_start(struct seq_file *seq, loff_t *pos)
__acquires(RCU)
__acquires(&bond->lock)
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index de87aea6d01a..88fcb25e554a 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -227,12 +227,6 @@ static ssize_t bonding_store_slaves(struct device *d,
struct net_device *dev;
struct bonding *bond = to_bond(d);
- /* Quick sanity check -- is the bond interface up? */
- if (!(bond->dev->flags & IFF_UP)) {
- pr_warning("%s: doing slave updates when interface is down.\n",
- bond->dev->name);
- }
-
if (!rtnl_trylock())
return restart_syscall();
@@ -422,11 +416,6 @@ static ssize_t bonding_store_arp_validate(struct device *d,
bond->dev->name, arp_validate_tbl[new_value].modename,
new_value);
- if (!bond->params.arp_validate && new_value)
- bond_register_arp(bond);
- else if (bond->params.arp_validate && !new_value)
- bond_unregister_arp(bond);
-
bond->params.arp_validate = new_value;
return count;
@@ -874,82 +863,28 @@ static DEVICE_ATTR(ad_select, S_IRUGO | S_IWUSR,
bonding_show_ad_select, bonding_store_ad_select);
/*
- * Show and set the number of grat ARP to send after a failover event.
+ * Show and set the number of peer notifications to send after a failover event.
*/
-static ssize_t bonding_show_n_grat_arp(struct device *d,
- struct device_attribute *attr,
- char *buf)
+static ssize_t bonding_show_num_peer_notif(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
{
struct bonding *bond = to_bond(d);
-
- return sprintf(buf, "%d\n", bond->params.num_grat_arp);
+ return sprintf(buf, "%d\n", bond->params.num_peer_notif);
}
-static ssize_t bonding_store_n_grat_arp(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t bonding_store_num_peer_notif(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
- int new_value, ret = count;
struct bonding *bond = to_bond(d);
-
- if (sscanf(buf, "%d", &new_value) != 1) {
- pr_err("%s: no num_grat_arp value specified.\n",
- bond->dev->name);
- ret = -EINVAL;
- goto out;
- }
- if (new_value < 0 || new_value > 255) {
- pr_err("%s: Invalid num_grat_arp value %d not in range 0-255; rejected.\n",
- bond->dev->name, new_value);
- ret = -EINVAL;
- goto out;
- } else {
- bond->params.num_grat_arp = new_value;
- }
-out:
- return ret;
+ int err = kstrtou8(buf, 10, &bond->params.num_peer_notif);
+ return err ? err : count;
}
static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR,
- bonding_show_n_grat_arp, bonding_store_n_grat_arp);
-
-/*
- * Show and set the number of unsolicited NA's to send after a failover event.
- */
-static ssize_t bonding_show_n_unsol_na(struct device *d,
- struct device_attribute *attr,
- char *buf)
-{
- struct bonding *bond = to_bond(d);
-
- return sprintf(buf, "%d\n", bond->params.num_unsol_na);
-}
-
-static ssize_t bonding_store_n_unsol_na(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- int new_value, ret = count;
- struct bonding *bond = to_bond(d);
-
- if (sscanf(buf, "%d", &new_value) != 1) {
- pr_err("%s: no num_unsol_na value specified.\n",
- bond->dev->name);
- ret = -EINVAL;
- goto out;
- }
-
- if (new_value < 0 || new_value > 255) {
- pr_err("%s: Invalid num_unsol_na value %d not in range 0-255; rejected.\n",
- bond->dev->name, new_value);
- ret = -EINVAL;
- goto out;
- } else
- bond->params.num_unsol_na = new_value;
-out:
- return ret;
-}
+ bonding_show_num_peer_notif, bonding_store_num_peer_notif);
static DEVICE_ATTR(num_unsol_na, S_IRUGO | S_IWUSR,
- bonding_show_n_unsol_na, bonding_store_n_unsol_na);
+ bonding_show_num_peer_notif, bonding_store_num_peer_notif);
/*
* Show and set the MII monitor interval. There are two tricky bits
@@ -1001,7 +936,6 @@ static ssize_t bonding_store_miimon(struct device *d,
bond->dev->name);
bond->params.arp_interval = 0;
if (bond->params.arp_validate) {
- bond_unregister_arp(bond);
bond->params.arp_validate =
BOND_ARP_VALIDATE_NONE;
}
@@ -1599,8 +1533,8 @@ static DEVICE_ATTR(all_slaves_active, S_IRUGO | S_IWUSR,
* Show and set the number of IGMP membership reports to send on link failure
*/
static ssize_t bonding_show_resend_igmp(struct device *d,
- struct device_attribute *attr,
- char *buf)
+ struct device_attribute *attr,
+ char *buf)
{
struct bonding *bond = to_bond(d);
@@ -1608,8 +1542,8 @@ static ssize_t bonding_show_resend_igmp(struct device *d,
}
static ssize_t bonding_store_resend_igmp(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
int new_value, ret = count;
struct bonding *bond = to_bond(d);
@@ -1621,7 +1555,7 @@ static ssize_t bonding_store_resend_igmp(struct device *d,
goto out;
}
- if (new_value < 0) {
+ if (new_value < 0 || new_value > 255) {
pr_err("%s: Invalid resend_igmp value %d not in range 0-255; rejected.\n",
bond->dev->name, new_value);
ret = -EINVAL;
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 90736cb4d975..ea1d005be92d 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -24,8 +24,8 @@
#include "bond_3ad.h"
#include "bond_alb.h"
-#define DRV_VERSION "3.7.0"
-#define DRV_RELDATE "June 2, 2010"
+#define DRV_VERSION "3.7.1"
+#define DRV_RELDATE "April 27, 2011"
#define DRV_NAME "bonding"
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
@@ -39,16 +39,6 @@
netif_carrier_ok(dev))
/*
- * Checks whether bond is ready for transmit.
- *
- * Caller must hold bond->lock
- */
-#define BOND_IS_OK(bond) \
- (((bond)->dev->flags & IFF_UP) && \
- netif_running((bond)->dev) && \
- ((bond)->slave_cnt > 0))
-
-/*
* Checks whether slave is ready for transmit.
*/
#define SLAVE_IS_OK(slave) \
@@ -149,8 +139,7 @@ struct bond_params {
int mode;
int xmit_policy;
int miimon;
- int num_grat_arp;
- int num_unsol_na;
+ u8 num_peer_notif;
int arp_interval;
int arp_validate;
int use_carrier;
@@ -178,9 +167,6 @@ struct vlan_entry {
struct list_head vlan_list;
__be32 vlan_ip;
unsigned short vlan_id;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- struct in6_addr vlan_ipv6;
-#endif
};
struct slave {
@@ -196,12 +182,12 @@ struct slave {
u8 backup:1, /* indicates backup slave. Value corresponds with
BOND_STATE_ACTIVE and BOND_STATE_BACKUP */
inactive:1; /* indicates inactive slave */
+ u8 duplex;
u32 original_mtu;
u32 link_failure_count;
- u8 perm_hwaddr[ETH_ALEN];
- u16 speed;
- u8 duplex;
+ u32 speed;
u16 queue_id;
+ u8 perm_hwaddr[ETH_ALEN];
struct ad_slave_info ad_info; /* HUGE - better to dynamically alloc */
struct tlb_slave_info tlb_info;
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -231,11 +217,12 @@ struct bonding {
struct slave *primary_slave;
bool force_primary;
s32 slave_cnt; /* never change this value outside the attach/detach wrappers */
+ void (*recv_probe)(struct sk_buff *, struct bonding *,
+ struct slave *);
rwlock_t lock;
rwlock_t curr_slave_lock;
s8 kill_timers;
- s8 send_grat_arp;
- s8 send_unsol_na;
+ u8 send_peer_notif;
s8 setup_by_slave;
s8 igmp_retrans;
#ifdef CONFIG_PROC_FS
@@ -260,9 +247,6 @@ struct bonding {
struct delayed_work alb_work;
struct delayed_work ad_work;
struct delayed_work mcast_work;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- struct in6_addr master_ipv6;
-#endif
#ifdef CONFIG_DEBUG_FS
/* debugging suport via debugfs */
struct dentry *debug_dir;
@@ -409,13 +393,12 @@ void bond_set_mode_ops(struct bonding *bond, int mode);
int bond_parse_parm(const char *mode_arg, const struct bond_parm_tbl *tbl);
void bond_select_active_slave(struct bonding *bond);
void bond_change_active_slave(struct bonding *bond, struct slave *new_active);
-void bond_register_arp(struct bonding *);
-void bond_unregister_arp(struct bonding *);
void bond_create_debugfs(void);
void bond_destroy_debugfs(void);
void bond_debug_register(struct bonding *bond);
void bond_debug_unregister(struct bonding *bond);
void bond_debug_reregister(struct bonding *bond);
+const char *bond_mode_name(int mode);
struct bond_net {
struct net * net; /* Associated network namespace */
@@ -459,23 +442,4 @@ extern const struct bond_parm_tbl fail_over_mac_tbl[];
extern const struct bond_parm_tbl pri_reselect_tbl[];
extern struct bond_parm_tbl ad_select_tbl[];
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-void bond_send_unsolicited_na(struct bonding *bond);
-void bond_register_ipv6_notifier(void);
-void bond_unregister_ipv6_notifier(void);
-#else
-static inline void bond_send_unsolicited_na(struct bonding *bond)
-{
- return;
-}
-static inline void bond_register_ipv6_notifier(void)
-{
- return;
-}
-static inline void bond_unregister_ipv6_notifier(void)
-{
- return;
-}
-#endif
-
#endif /* _LINUX_BONDING_H */
diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c
index 3df0c0f8b8bf..73c7e03617ec 100644
--- a/drivers/net/caif/caif_serial.c
+++ b/drivers/net/caif/caif_serial.c
@@ -167,8 +167,8 @@ static inline void debugfs_tx(struct ser_device *ser, const u8 *data, int size)
#endif
-static void ldisc_receive(struct tty_struct *tty, const u8 *data,
- char *flags, int count)
+static unsigned int ldisc_receive(struct tty_struct *tty,
+ const u8 *data, char *flags, int count)
{
struct sk_buff *skb = NULL;
struct ser_device *ser;
@@ -215,6 +215,8 @@ static void ldisc_receive(struct tty_struct *tty, const u8 *data,
} else
++ser->dev->stats.rx_dropped;
update_tty_status(ser);
+
+ return count;
}
static int handle_tx(struct ser_device *ser)
diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c
index 587fba48cdd9..f1942cab35f6 100644
--- a/drivers/net/can/janz-ican3.c
+++ b/drivers/net/can/janz-ican3.c
@@ -15,7 +15,6 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
-#include <linux/mfd/core.h>
#include <linux/netdevice.h>
#include <linux/can.h>
@@ -1644,7 +1643,7 @@ static int __devinit ican3_probe(struct platform_device *pdev)
struct device *dev;
int ret;
- pdata = mfd_get_data(pdev);
+ pdata = pdev->dev.platform_data;
if (!pdata)
return -ENXIO;
diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c
index e54712b22c27..d11fbb2b95ff 100644
--- a/drivers/net/can/pch_can.c
+++ b/drivers/net/can/pch_can.c
@@ -653,7 +653,7 @@ static int pch_can_rx_normal(struct net_device *ndev, u32 obj_num, int quota)
u16 data_reg;
do {
- /* Reading the messsage object from the Message RAM */
+ /* Reading the message object from the Message RAM */
iowrite32(PCH_CMASK_RX_TX_GET, &priv->regs->ifregs[0].cmask);
pch_can_rw_msg_obj(&priv->regs->ifregs[0].creq, obj_num);
diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c
index 1b49df6b2470..75622d54581f 100644
--- a/drivers/net/can/slcan.c
+++ b/drivers/net/can/slcan.c
@@ -425,16 +425,17 @@ static void slc_setup(struct net_device *dev)
* in parallel
*/
-static void slcan_receive_buf(struct tty_struct *tty,
+static unsigned int slcan_receive_buf(struct tty_struct *tty,
const unsigned char *cp, char *fp, int count)
{
struct slcan *sl = (struct slcan *) tty->disc_data;
+ int bytes = count;
if (!sl || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev))
- return;
+ return -ENODEV;
/* Read the characters out of the buffer */
- while (count--) {
+ while (bytes--) {
if (fp && *fp++) {
if (!test_and_set_bit(SLF_ERROR, &sl->flags))
sl->dev->stats.rx_errors++;
@@ -443,6 +444,8 @@ static void slcan_receive_buf(struct tty_struct *tty,
}
slcan_unesc(sl, *cp++);
}
+
+ return count;
}
/************************************
diff --git a/drivers/net/can/softing/softing_cs.c b/drivers/net/can/softing/softing_cs.c
index c11bb4de8630..c0e1b1eb87a9 100644
--- a/drivers/net/can/softing/softing_cs.c
+++ b/drivers/net/can/softing/softing_cs.c
@@ -315,7 +315,7 @@ pcmcia_failed:
return ret ?: -ENODEV;
}
-static /*const*/ struct pcmcia_device_id softingcs_ids[] = {
+static const struct pcmcia_device_id softingcs_ids[] = {
/* softing */
PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0001),
PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0002),
diff --git a/drivers/net/can/softing/softing_main.c b/drivers/net/can/softing/softing_main.c
index 7a70709d5608..60a49e5a2a53 100644
--- a/drivers/net/can/softing/softing_main.c
+++ b/drivers/net/can/softing/softing_main.c
@@ -797,7 +797,7 @@ static __devinit int softing_pdev_probe(struct platform_device *pdev)
ret = -EINVAL;
pres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!pres)
- goto platform_resource_failed;;
+ goto platform_resource_failed;
card->dpram_phys = pres->start;
card->dpram_size = pres->end - pres->start + 1;
card->dpram = ioremap_nocache(card->dpram_phys, card->dpram_size);
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index 143a28c666af..22ce03e55b83 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -709,10 +709,11 @@ static void cas_begin_auto_negotiation(struct cas *cp, struct ethtool_cmd *ep)
if (ep->autoneg == AUTONEG_ENABLE)
cp->link_cntl = BMCR_ANENABLE;
else {
+ u32 speed = ethtool_cmd_speed(ep);
cp->link_cntl = 0;
- if (ep->speed == SPEED_100)
+ if (speed == SPEED_100)
cp->link_cntl |= BMCR_SPEED100;
- else if (ep->speed == SPEED_1000)
+ else if (speed == SPEED_1000)
cp->link_cntl |= CAS_BMCR_SPEED1000;
if (ep->duplex == DUPLEX_FULL)
cp->link_cntl |= BMCR_FULLDPLX;
@@ -4605,18 +4606,17 @@ static int cas_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
if (bmcr & BMCR_ANENABLE) {
cmd->advertising |= ADVERTISED_Autoneg;
cmd->autoneg = AUTONEG_ENABLE;
- cmd->speed = ((speed == 10) ?
- SPEED_10 :
- ((speed == 1000) ?
- SPEED_1000 : SPEED_100));
+ ethtool_cmd_speed_set(cmd, ((speed == 10) ?
+ SPEED_10 :
+ ((speed == 1000) ?
+ SPEED_1000 : SPEED_100)));
cmd->duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
} else {
cmd->autoneg = AUTONEG_DISABLE;
- cmd->speed =
- (bmcr & CAS_BMCR_SPEED1000) ?
- SPEED_1000 :
- ((bmcr & BMCR_SPEED100) ? SPEED_100:
- SPEED_10);
+ ethtool_cmd_speed_set(cmd, ((bmcr & CAS_BMCR_SPEED1000) ?
+ SPEED_1000 :
+ ((bmcr & BMCR_SPEED100) ?
+ SPEED_100 : SPEED_10)));
cmd->duplex =
(bmcr & BMCR_FULLDPLX) ?
DUPLEX_FULL : DUPLEX_HALF;
@@ -4633,14 +4633,14 @@ static int cas_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
* settings that we configured.
*/
if (cp->link_cntl & BMCR_ANENABLE) {
- cmd->speed = 0;
+ ethtool_cmd_speed_set(cmd, 0);
cmd->duplex = 0xff;
} else {
- cmd->speed = SPEED_10;
+ ethtool_cmd_speed_set(cmd, SPEED_10);
if (cp->link_cntl & BMCR_SPEED100) {
- cmd->speed = SPEED_100;
+ ethtool_cmd_speed_set(cmd, SPEED_100);
} else if (cp->link_cntl & CAS_BMCR_SPEED1000) {
- cmd->speed = SPEED_1000;
+ ethtool_cmd_speed_set(cmd, SPEED_1000);
}
cmd->duplex = (cp->link_cntl & BMCR_FULLDPLX)?
DUPLEX_FULL : DUPLEX_HALF;
@@ -4653,6 +4653,7 @@ static int cas_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct cas *cp = netdev_priv(dev);
unsigned long flags;
+ u32 speed = ethtool_cmd_speed(cmd);
/* Verify the settings we care about. */
if (cmd->autoneg != AUTONEG_ENABLE &&
@@ -4660,9 +4661,9 @@ static int cas_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
return -EINVAL;
if (cmd->autoneg == AUTONEG_DISABLE &&
- ((cmd->speed != SPEED_1000 &&
- cmd->speed != SPEED_100 &&
- cmd->speed != SPEED_10) ||
+ ((speed != SPEED_1000 &&
+ speed != SPEED_100 &&
+ speed != SPEED_10) ||
(cmd->duplex != DUPLEX_HALF &&
cmd->duplex != DUPLEX_FULL)))
return -EINVAL;
diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h
index 092f31a126e6..c26d863e1697 100644
--- a/drivers/net/chelsio/common.h
+++ b/drivers/net/chelsio/common.h
@@ -264,11 +264,6 @@ struct adapter {
enum { /* adapter flags */
FULL_INIT_DONE = 1 << 0,
- TSO_CAPABLE = 1 << 2,
- TCP_CSUM_CAPABLE = 1 << 3,
- UDP_CSUM_CAPABLE = 1 << 4,
- VLAN_ACCEL_CAPABLE = 1 << 5,
- RX_CSUM_ENABLED = 1 << 6,
};
struct mdio_ops;
diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c
index 0f71304e0542..b422d83f5343 100644
--- a/drivers/net/chelsio/cxgb2.c
+++ b/drivers/net/chelsio/cxgb2.c
@@ -192,10 +192,8 @@ static void link_start(struct port_info *p)
static void enable_hw_csum(struct adapter *adapter)
{
- if (adapter->flags & TSO_CAPABLE)
+ if (adapter->port[0].dev->hw_features & NETIF_F_TSO)
t1_tp_set_ip_checksum_offload(adapter->tp, 1); /* for TSO only */
- if (adapter->flags & UDP_CSUM_CAPABLE)
- t1_tp_set_udp_checksum_offload(adapter->tp, 1);
t1_tp_set_tcp_checksum_offload(adapter->tp, 1);
}
@@ -579,10 +577,10 @@ static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->advertising = p->link_config.advertising;
if (netif_carrier_ok(dev)) {
- cmd->speed = p->link_config.speed;
+ ethtool_cmd_speed_set(cmd, p->link_config.speed);
cmd->duplex = p->link_config.duplex;
} else {
- cmd->speed = -1;
+ ethtool_cmd_speed_set(cmd, -1);
cmd->duplex = -1;
}
@@ -640,11 +638,12 @@ static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
return -EOPNOTSUPP; /* can't change speed/duplex */
if (cmd->autoneg == AUTONEG_DISABLE) {
- int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
+ u32 speed = ethtool_cmd_speed(cmd);
+ int cap = speed_duplex_to_caps(speed, cmd->duplex);
- if (!(lc->supported & cap) || cmd->speed == SPEED_1000)
+ if (!(lc->supported & cap) || (speed == SPEED_1000))
return -EINVAL;
- lc->requested_speed = cmd->speed;
+ lc->requested_speed = speed;
lc->requested_duplex = cmd->duplex;
lc->advertising = 0;
} else {
@@ -705,33 +704,6 @@ static int set_pauseparam(struct net_device *dev,
return 0;
}
-static u32 get_rx_csum(struct net_device *dev)
-{
- struct adapter *adapter = dev->ml_priv;
-
- return (adapter->flags & RX_CSUM_ENABLED) != 0;
-}
-
-static int set_rx_csum(struct net_device *dev, u32 data)
-{
- struct adapter *adapter = dev->ml_priv;
-
- if (data)
- adapter->flags |= RX_CSUM_ENABLED;
- else
- adapter->flags &= ~RX_CSUM_ENABLED;
- return 0;
-}
-
-static int set_tso(struct net_device *dev, u32 value)
-{
- struct adapter *adapter = dev->ml_priv;
-
- if (!(adapter->flags & TSO_CAPABLE))
- return value ? -EOPNOTSUPP : 0;
- return ethtool_op_set_tso(dev, value);
-}
-
static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
{
struct adapter *adapter = dev->ml_priv;
@@ -831,17 +803,12 @@ static const struct ethtool_ops t1_ethtool_ops = {
.get_eeprom = get_eeprom,
.get_pauseparam = get_pauseparam,
.set_pauseparam = set_pauseparam,
- .get_rx_csum = get_rx_csum,
- .set_rx_csum = set_rx_csum,
- .set_tx_csum = ethtool_op_set_tx_csum,
- .set_sg = ethtool_op_set_sg,
.get_link = ethtool_op_get_link,
.get_strings = get_strings,
.get_sset_count = get_sset_count,
.get_ethtool_stats = get_stats,
.get_regs_len = get_regs_len,
.get_regs = get_regs,
- .set_tso = set_tso,
};
static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
@@ -1105,28 +1072,28 @@ static int __devinit init_one(struct pci_dev *pdev,
netdev->mem_start = mmio_start;
netdev->mem_end = mmio_start + mmio_len - 1;
netdev->ml_priv = adapter;
- netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
- netdev->features |= NETIF_F_LLTX;
+ netdev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM |
+ NETIF_F_RXCSUM;
+ netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM |
+ NETIF_F_RXCSUM | NETIF_F_LLTX;
- adapter->flags |= RX_CSUM_ENABLED | TCP_CSUM_CAPABLE;
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
if (vlan_tso_capable(adapter)) {
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
- adapter->flags |= VLAN_ACCEL_CAPABLE;
netdev->features |=
NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
#endif
/* T204: disable TSO */
if (!(is_T2(adapter)) || bi->port_number != 4) {
- adapter->flags |= TSO_CAPABLE;
+ netdev->hw_features |= NETIF_F_TSO;
netdev->features |= NETIF_F_TSO;
}
}
netdev->netdev_ops = &cxgb_netdev_ops;
- netdev->hard_header_len += (adapter->flags & TSO_CAPABLE) ?
+ netdev->hard_header_len += (netdev->hw_features & NETIF_F_TSO) ?
sizeof(struct cpl_tx_pkt_lso) : sizeof(struct cpl_tx_pkt);
netif_napi_add(netdev, &adapter->napi, t1_poll, 64);
diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
index 8754d4473042..58380d240619 100644
--- a/drivers/net/chelsio/sge.c
+++ b/drivers/net/chelsio/sge.c
@@ -54,6 +54,7 @@
#include <linux/in.h>
#include <linux/if_arp.h>
#include <linux/slab.h>
+#include <linux/prefetch.h>
#include "cpl5_cmd.h"
#include "sge.h"
@@ -929,7 +930,7 @@ void t1_sge_intr_enable(struct sge *sge)
u32 en = SGE_INT_ENABLE;
u32 val = readl(sge->adapter->regs + A_PL_ENABLE);
- if (sge->adapter->flags & TSO_CAPABLE)
+ if (sge->adapter->port[0].dev->hw_features & NETIF_F_TSO)
en &= ~F_PACKET_TOO_BIG;
writel(en, sge->adapter->regs + A_SG_INT_ENABLE);
writel(val | SGE_PL_INTR_MASK, sge->adapter->regs + A_PL_ENABLE);
@@ -952,7 +953,7 @@ int t1_sge_intr_error_handler(struct sge *sge)
struct adapter *adapter = sge->adapter;
u32 cause = readl(adapter->regs + A_SG_INT_CAUSE);
- if (adapter->flags & TSO_CAPABLE)
+ if (adapter->port[0].dev->hw_features & NETIF_F_TSO)
cause &= ~F_PACKET_TOO_BIG;
if (cause & F_RESPQ_EXHAUSTED)
sge->stats.respQ_empty++;
@@ -1369,6 +1370,7 @@ static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len)
const struct cpl_rx_pkt *p;
struct adapter *adapter = sge->adapter;
struct sge_port_stats *st;
+ struct net_device *dev;
skb = get_packet(adapter->pdev, fl, len - sge->rx_pkt_pad);
if (unlikely(!skb)) {
@@ -1384,9 +1386,10 @@ static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len)
__skb_pull(skb, sizeof(*p));
st = this_cpu_ptr(sge->port_stats[p->iff]);
+ dev = adapter->port[p->iff].dev;
- skb->protocol = eth_type_trans(skb, adapter->port[p->iff].dev);
- if ((adapter->flags & RX_CSUM_ENABLED) && p->csum == 0xffff &&
+ skb->protocol = eth_type_trans(skb, dev);
+ if ((dev->features & NETIF_F_RXCSUM) && p->csum == 0xffff &&
skb->protocol == htons(ETH_P_IP) &&
(skb->data[9] == IPPROTO_TCP || skb->data[9] == IPPROTO_UDP)) {
++st->rx_cso_good;
@@ -1838,8 +1841,7 @@ netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_OK;
}
- if (!(adapter->flags & UDP_CSUM_CAPABLE) &&
- skb->ip_summed == CHECKSUM_PARTIAL &&
+ if (skb->ip_summed == CHECKSUM_PARTIAL &&
ip_hdr(skb)->protocol == IPPROTO_UDP) {
if (unlikely(skb_checksum_help(skb))) {
pr_debug("%s: unable to do udp checksum\n", dev->name);
diff --git a/drivers/net/chelsio/tp.c b/drivers/net/chelsio/tp.c
index 6222d585e447..8bed4a59e65f 100644
--- a/drivers/net/chelsio/tp.c
+++ b/drivers/net/chelsio/tp.c
@@ -152,11 +152,6 @@ void t1_tp_set_ip_checksum_offload(struct petp *tp, int enable)
set_csum_offload(tp, F_IP_CSUM, enable);
}
-void t1_tp_set_udp_checksum_offload(struct petp *tp, int enable)
-{
- set_csum_offload(tp, F_UDP_CSUM, enable);
-}
-
void t1_tp_set_tcp_checksum_offload(struct petp *tp, int enable)
{
set_csum_offload(tp, F_TCP_CSUM, enable);
diff --git a/drivers/net/chelsio/tp.h b/drivers/net/chelsio/tp.h
index 32fc71e58913..dfd8ce25106a 100644
--- a/drivers/net/chelsio/tp.h
+++ b/drivers/net/chelsio/tp.h
@@ -65,7 +65,6 @@ void t1_tp_intr_clear(struct petp *tp);
int t1_tp_intr_handler(struct petp *tp);
void t1_tp_get_mib_statistics(adapter_t *adap, struct tp_mib_statistics *tps);
-void t1_tp_set_udp_checksum_offload(struct petp *tp, int enable);
void t1_tp_set_tcp_checksum_offload(struct petp *tp, int enable);
void t1_tp_set_ip_checksum_offload(struct petp *tp, int enable);
int t1_tp_set_coalescing_size(struct petp *tp, unsigned int size);
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
index 8cca60e43444..11a92afdf982 100644
--- a/drivers/net/cnic.c
+++ b/drivers/net/cnic.c
@@ -27,6 +27,7 @@
#include <linux/delay.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
+#include <linux/prefetch.h>
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
#define BCM_VLAN 1
#endif
@@ -2966,31 +2967,36 @@ static int cnic_service_bnx2x(void *data, void *status_blk)
return 0;
}
-static void cnic_ulp_stop(struct cnic_dev *dev)
+static void cnic_ulp_stop_one(struct cnic_local *cp, int if_type)
{
- struct cnic_local *cp = dev->cnic_priv;
- int if_type;
-
- cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL);
+ struct cnic_ulp_ops *ulp_ops;
- for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++) {
- struct cnic_ulp_ops *ulp_ops;
+ if (if_type == CNIC_ULP_ISCSI)
+ cnic_send_nlmsg(cp, ISCSI_KEVENT_IF_DOWN, NULL);
- mutex_lock(&cnic_lock);
- ulp_ops = rcu_dereference_protected(cp->ulp_ops[if_type],
- lockdep_is_held(&cnic_lock));
- if (!ulp_ops) {
- mutex_unlock(&cnic_lock);
- continue;
- }
- set_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]);
+ mutex_lock(&cnic_lock);
+ ulp_ops = rcu_dereference_protected(cp->ulp_ops[if_type],
+ lockdep_is_held(&cnic_lock));
+ if (!ulp_ops) {
mutex_unlock(&cnic_lock);
+ return;
+ }
+ set_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]);
+ mutex_unlock(&cnic_lock);
- if (test_and_clear_bit(ULP_F_START, &cp->ulp_flags[if_type]))
- ulp_ops->cnic_stop(cp->ulp_handle[if_type]);
+ if (test_and_clear_bit(ULP_F_START, &cp->ulp_flags[if_type]))
+ ulp_ops->cnic_stop(cp->ulp_handle[if_type]);
- clear_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]);
- }
+ clear_bit(ULP_F_CALL_PENDING, &cp->ulp_flags[if_type]);
+}
+
+static void cnic_ulp_stop(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ int if_type;
+
+ for (if_type = 0; if_type < MAX_CNIC_ULP_TYPE; if_type++)
+ cnic_ulp_stop_one(cp, if_type);
}
static void cnic_ulp_start(struct cnic_dev *dev)
@@ -3039,6 +3045,12 @@ static int cnic_ctl(void *data, struct cnic_ctl_info *info)
cnic_put(dev);
break;
+ case CNIC_CTL_STOP_ISCSI_CMD: {
+ struct cnic_local *cp = dev->cnic_priv;
+ set_bit(CNIC_LCL_FL_STOP_ISCSI, &cp->cnic_local_flags);
+ queue_delayed_work(cnic_wq, &cp->delete_task, 0);
+ break;
+ }
case CNIC_CTL_COMPLETION_CMD: {
u32 cid = BNX2X_SW_CID(info->data.comp.cid);
u32 l5_cid;
@@ -3562,8 +3574,12 @@ static void cnic_init_csk_state(struct cnic_sock *csk)
static int cnic_cm_connect(struct cnic_sock *csk, struct cnic_sockaddr *saddr)
{
+ struct cnic_local *cp = csk->dev->cnic_priv;
int err = 0;
+ if (cp->ethdev->drv_state & CNIC_DRV_STATE_NO_ISCSI)
+ return -EOPNOTSUPP;
+
if (!cnic_in_use(csk))
return -EINVAL;
@@ -3965,6 +3981,15 @@ static void cnic_delete_task(struct work_struct *work)
cp = container_of(work, struct cnic_local, delete_task.work);
dev = cp->dev;
+ if (test_and_clear_bit(CNIC_LCL_FL_STOP_ISCSI, &cp->cnic_local_flags)) {
+ struct drv_ctl_info info;
+
+ cnic_ulp_stop_one(cp, CNIC_ULP_ISCSI);
+
+ info.cmd = DRV_CTL_ISCSI_STOPPED_CMD;
+ cp->ethdev->drv_ctl(dev->netdev, &info);
+ }
+
for (i = 0; i < cp->max_cid_space; i++) {
struct cnic_context *ctx = &cp->ctx_tbl[i];
diff --git a/drivers/net/cnic.h b/drivers/net/cnic.h
index 4456260c653c..3367a6d3a774 100644
--- a/drivers/net/cnic.h
+++ b/drivers/net/cnic.h
@@ -226,6 +226,7 @@ struct cnic_local {
#define CNIC_LCL_FL_KWQ_INIT 0x0
#define CNIC_LCL_FL_L2_WAIT 0x1
#define CNIC_LCL_FL_RINGS_INITED 0x2
+#define CNIC_LCL_FL_STOP_ISCSI 0x4
struct cnic_dev *dev;
diff --git a/drivers/net/cnic_if.h b/drivers/net/cnic_if.h
index e01b49ee3591..fdd8e46a9050 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.2.13"
-#define CNIC_MODULE_RELDATE "Jan 31, 2011"
+#define CNIC_MODULE_VERSION "2.2.14"
+#define CNIC_MODULE_RELDATE "Mar 30, 2011"
#define CNIC_ULP_RDMA 0
#define CNIC_ULP_ISCSI 1
@@ -85,6 +85,7 @@ struct kcqe {
#define CNIC_CTL_STOP_CMD 1
#define CNIC_CTL_START_CMD 2
#define CNIC_CTL_COMPLETION_CMD 3
+#define CNIC_CTL_STOP_ISCSI_CMD 4
#define DRV_CTL_IO_WR_CMD 0x101
#define DRV_CTL_IO_RD_CMD 0x102
@@ -94,6 +95,7 @@ struct kcqe {
#define DRV_CTL_START_L2_CMD 0x106
#define DRV_CTL_STOP_L2_CMD 0x107
#define DRV_CTL_RET_L2_SPQ_CREDIT_CMD 0x10c
+#define DRV_CTL_ISCSI_STOPPED_CMD 0x10d
struct cnic_ctl_completion {
u32 cid;
diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
index 9d267d3a6892..e66aceb57cef 100644
--- a/drivers/net/cris/eth_v10.c
+++ b/drivers/net/cris/eth_v10.c
@@ -491,8 +491,8 @@ e100_open(struct net_device *dev)
/* allocate the irq corresponding to the receiving DMA */
- if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rxtx_interrupt,
- IRQF_SAMPLE_RANDOM, cardname, (void *)dev)) {
+ if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rxtx_interrupt, 0, cardname,
+ (void *)dev)) {
goto grace_exit0;
}
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
index ef67be59680f..7300de5a1426 100644
--- a/drivers/net/cxgb3/adapter.h
+++ b/drivers/net/cxgb3/adapter.h
@@ -50,11 +50,6 @@ struct adapter;
struct sge_qset;
struct port_info;
-enum { /* rx_offload flags */
- T3_RX_CSUM = 1 << 0,
- T3_LRO = 1 << 1,
-};
-
enum mac_idx_types {
LAN_MAC_IDX = 0,
SAN_MAC_IDX,
@@ -74,7 +69,6 @@ struct port_info {
struct vlan_group *vlan_grp;
struct sge_qset *qs;
u8 port_id;
- u8 rx_offload;
u8 nqsets;
u8 first_qset;
struct cphy phy;
@@ -212,7 +206,6 @@ struct sge_qset { /* an SGE queue set */
struct sge_fl fl[SGE_RXQ_PER_SET];
struct sge_txq txq[SGE_TXQ_PER_SET];
int nomem;
- int lro_enabled;
void *lro_va;
struct net_device *netdev;
struct netdev_queue *tx_q; /* associated netdev TX queue */
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
index 5ccb77d078aa..056ee8c831f1 100644
--- a/drivers/net/cxgb3/common.h
+++ b/drivers/net/cxgb3/common.h
@@ -317,7 +317,6 @@ struct tp_params {
struct qset_params { /* SGE queue set parameters */
unsigned int polling; /* polling/interrupt service for rspq */
- unsigned int lro; /* large receive offload */
unsigned int coalesce_usecs; /* irq coalescing timer */
unsigned int rspq_size; /* # of entries in response queue */
unsigned int fl_size; /* # of entries in regular free list */
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index 910893143295..9081ce037149 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -644,26 +644,6 @@ static void enable_all_napi(struct adapter *adap)
}
/**
- * set_qset_lro - Turn a queue set's LRO capability on and off
- * @dev: the device the qset is attached to
- * @qset_idx: the queue set index
- * @val: the LRO switch
- *
- * Sets LRO on or off for a particular queue set.
- * the device's features flag is updated to reflect the LRO
- * capability when all queues belonging to the device are
- * in the same state.
- */
-static void set_qset_lro(struct net_device *dev, int qset_idx, int val)
-{
- struct port_info *pi = netdev_priv(dev);
- struct adapter *adapter = pi->adapter;
-
- adapter->params.sge.qset[qset_idx].lro = !!val;
- adapter->sge.qs[qset_idx].lro_enabled = !!val;
-}
-
-/**
* setup_sge_qsets - configure SGE Tx/Rx/response queues
* @adap: the adapter
*
@@ -685,7 +665,6 @@ static int setup_sge_qsets(struct adapter *adap)
pi->qs = &adap->sge.qs[pi->first_qset];
for (j = 0; j < pi->nqsets; ++j, ++qset_idx) {
- set_qset_lro(dev, qset_idx, pi->rx_offload & T3_LRO);
err = t3_sge_alloc_qset(adap, qset_idx, 1,
(adap->flags & USING_MSIX) ? qset_idx + 1 :
irq_idx,
@@ -1749,23 +1728,26 @@ static int restart_autoneg(struct net_device *dev)
return 0;
}
-static int cxgb3_phys_id(struct net_device *dev, u32 data)
+static int set_phys_id(struct net_device *dev,
+ enum ethtool_phys_id_state state)
{
struct port_info *pi = netdev_priv(dev);
struct adapter *adapter = pi->adapter;
- int i;
- if (data == 0)
- data = 2;
+ switch (state) {
+ case ETHTOOL_ID_ACTIVE:
+ return 1; /* cycle on/off once per second */
- for (i = 0; i < data * 2; i++) {
+ case ETHTOOL_ID_OFF:
+ t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL, 0);
+ break;
+
+ case ETHTOOL_ID_ON:
+ case ETHTOOL_ID_INACTIVE:
t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
- (i & 1) ? F_GPIO0_OUT_VAL : 0);
- if (msleep_interruptible(500))
- break;
- }
- t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
F_GPIO0_OUT_VAL);
+ }
+
return 0;
}
@@ -1777,10 +1759,10 @@ static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->advertising = p->link_config.advertising;
if (netif_carrier_ok(dev)) {
- cmd->speed = p->link_config.speed;
+ ethtool_cmd_speed_set(cmd, p->link_config.speed);
cmd->duplex = p->link_config.duplex;
} else {
- cmd->speed = -1;
+ ethtool_cmd_speed_set(cmd, -1);
cmd->duplex = -1;
}
@@ -1839,7 +1821,8 @@ static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
* being requested.
*/
if (cmd->autoneg == AUTONEG_DISABLE) {
- int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
+ u32 speed = ethtool_cmd_speed(cmd);
+ int cap = speed_duplex_to_caps(speed, cmd->duplex);
if (lc->supported & cap)
return 0;
}
@@ -1847,11 +1830,12 @@ static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
}
if (cmd->autoneg == AUTONEG_DISABLE) {
- int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
+ u32 speed = ethtool_cmd_speed(cmd);
+ int cap = speed_duplex_to_caps(speed, cmd->duplex);
- if (!(lc->supported & cap) || cmd->speed == SPEED_1000)
+ if (!(lc->supported & cap) || (speed == SPEED_1000))
return -EINVAL;
- lc->requested_speed = cmd->speed;
+ lc->requested_speed = speed;
lc->requested_duplex = cmd->duplex;
lc->advertising = 0;
} else {
@@ -1907,29 +1891,6 @@ static int set_pauseparam(struct net_device *dev,
return 0;
}
-static u32 get_rx_csum(struct net_device *dev)
-{
- struct port_info *p = netdev_priv(dev);
-
- return p->rx_offload & T3_RX_CSUM;
-}
-
-static int set_rx_csum(struct net_device *dev, u32 data)
-{
- struct port_info *p = netdev_priv(dev);
-
- if (data) {
- p->rx_offload |= T3_RX_CSUM;
- } else {
- int i;
-
- p->rx_offload &= ~(T3_RX_CSUM | T3_LRO);
- for (i = p->first_qset; i < p->first_qset + p->nqsets; i++)
- set_qset_lro(dev, i, 0);
- }
- return 0;
-}
-
static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
{
struct port_info *pi = netdev_priv(dev);
@@ -2101,20 +2062,15 @@ static const struct ethtool_ops cxgb_ethtool_ops = {
.set_eeprom = set_eeprom,
.get_pauseparam = get_pauseparam,
.set_pauseparam = set_pauseparam,
- .get_rx_csum = get_rx_csum,
- .set_rx_csum = set_rx_csum,
- .set_tx_csum = ethtool_op_set_tx_csum,
- .set_sg = ethtool_op_set_sg,
.get_link = ethtool_op_get_link,
.get_strings = get_strings,
- .phys_id = cxgb3_phys_id,
+ .set_phys_id = set_phys_id,
.nway_reset = restart_autoneg,
.get_sset_count = get_sset_count,
.get_ethtool_stats = get_stats,
.get_regs_len = get_regs_len,
.get_regs = get_regs,
.get_wol = get_wol,
- .set_tso = ethtool_op_set_tso,
};
static int in_range(int val, int lo, int hi)
@@ -2162,15 +2118,6 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
MAX_RSPQ_ENTRIES))
return -EINVAL;
- if ((adapter->flags & FULL_INIT_DONE) && t.lro > 0)
- for_each_port(adapter, i) {
- pi = adap2pinfo(adapter, i);
- if (t.qset_idx >= pi->first_qset &&
- t.qset_idx < pi->first_qset + pi->nqsets &&
- !(pi->rx_offload & T3_RX_CSUM))
- return -EINVAL;
- }
-
if ((adapter->flags & FULL_INIT_DONE) &&
(t.rspq_size >= 0 || t.fl_size[0] >= 0 ||
t.fl_size[1] >= 0 || t.txq_size[0] >= 0 ||
@@ -2231,8 +2178,14 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
}
}
}
- if (t.lro >= 0)
- set_qset_lro(dev, t.qset_idx, t.lro);
+
+ if (t.lro >= 0) {
+ if (t.lro)
+ dev->wanted_features |= NETIF_F_GRO;
+ else
+ dev->wanted_features &= ~NETIF_F_GRO;
+ netdev_update_features(dev);
+ }
break;
}
@@ -2266,7 +2219,7 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
t.fl_size[0] = q->fl_size;
t.fl_size[1] = q->jumbo_size;
t.polling = q->polling;
- t.lro = q->lro;
+ t.lro = !!(dev->features & NETIF_F_GRO);
t.intr_lat = q->coalesce_usecs;
t.cong_thres = q->cong_thres;
t.qnum = q1;
@@ -3304,18 +3257,18 @@ static int __devinit init_one(struct pci_dev *pdev,
adapter->port[i] = netdev;
pi = netdev_priv(netdev);
pi->adapter = adapter;
- pi->rx_offload = T3_RX_CSUM | T3_LRO;
pi->port_id = i;
netif_carrier_off(netdev);
netdev->irq = pdev->irq;
netdev->mem_start = mmio_start;
netdev->mem_end = mmio_start + mmio_len - 1;
- netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
- netdev->features |= NETIF_F_GRO;
+ netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM |
+ NETIF_F_TSO | NETIF_F_RXCSUM;
+ netdev->features |= netdev->hw_features |
+ NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
- netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
netdev->netdev_ops = &cxgb_netdev_ops;
SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops);
}
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index bfa2d56af1ee..3f562ba2f0c9 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -37,6 +37,7 @@
#include <linux/tcp.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
+#include <linux/prefetch.h>
#include <net/arp.h>
#include "common.h"
#include "regs.h"
@@ -2019,7 +2020,7 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq,
skb_pull(skb, sizeof(*p) + pad);
skb->protocol = eth_type_trans(skb, adap->port[p->iff]);
pi = netdev_priv(skb->dev);
- if ((pi->rx_offload & T3_RX_CSUM) && p->csum_valid &&
+ if ((skb->dev->features & NETIF_F_RXCSUM) && p->csum_valid &&
p->csum == htons(0xffff) && !p->fragment) {
qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++;
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -2120,7 +2121,7 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs,
offset = 2 + sizeof(struct cpl_rx_pkt);
cpl = qs->lro_va = sd->pg_chunk.va + 2;
- if ((pi->rx_offload & T3_RX_CSUM) &&
+ if ((qs->netdev->features & NETIF_F_RXCSUM) &&
cpl->csum_valid && cpl->csum == htons(0xffff)) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++;
@@ -2285,7 +2286,8 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs,
q->next_holdoff = q->holdoff_tmr;
while (likely(budget_left && is_new_response(r, q))) {
- int packet_complete, eth, ethpad = 2, lro = qs->lro_enabled;
+ int packet_complete, eth, ethpad = 2;
+ int lro = !!(qs->netdev->features & NETIF_F_GRO);
struct sk_buff *skb = NULL;
u32 len, flags;
__be32 rss_hi, rss_lo;
diff --git a/drivers/net/cxgb4/cxgb4.h b/drivers/net/cxgb4/cxgb4.h
index 01d49eaa44d2..bc9982a4c1f4 100644
--- a/drivers/net/cxgb4/cxgb4.h
+++ b/drivers/net/cxgb4/cxgb4.h
@@ -290,7 +290,6 @@ struct port_info {
u8 port_id;
u8 tx_chan;
u8 lport; /* associated offload logical port */
- u8 rx_offload; /* CSO, etc */
u8 nqsets; /* # of qsets */
u8 first_qset; /* index of first qset */
u8 rss_mode;
@@ -298,11 +297,6 @@ struct port_info {
u16 *rss;
};
-/* port_info.rx_offload flags */
-enum {
- RX_CSO = 1 << 0,
-};
-
struct dentry;
struct work_struct;
diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c
index 5352c8a23f4d..7e3cfbe89e3b 100644
--- a/drivers/net/cxgb4/cxgb4_main.c
+++ b/drivers/net/cxgb4/cxgb4_main.c
@@ -1336,15 +1336,20 @@ static int restart_autoneg(struct net_device *dev)
return 0;
}
-static int identify_port(struct net_device *dev, u32 data)
+static int identify_port(struct net_device *dev,
+ enum ethtool_phys_id_state state)
{
+ unsigned int val;
struct adapter *adap = netdev2adap(dev);
- if (data == 0)
- data = 2; /* default to 2 seconds */
+ if (state == ETHTOOL_ID_ACTIVE)
+ val = 0xffff;
+ else if (state == ETHTOOL_ID_INACTIVE)
+ val = 0;
+ else
+ return -EINVAL;
- return t4_identify_port(adap, adap->fn, netdev2pinfo(dev)->viid,
- data * 5);
+ return t4_identify_port(adap, adap->fn, netdev2pinfo(dev)->viid, val);
}
static unsigned int from_fw_linkcaps(unsigned int type, unsigned int caps)
@@ -1431,7 +1436,8 @@ static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->supported = from_fw_linkcaps(p->port_type, p->link_cfg.supported);
cmd->advertising = from_fw_linkcaps(p->port_type,
p->link_cfg.advertising);
- cmd->speed = netif_carrier_ok(dev) ? p->link_cfg.speed : 0;
+ ethtool_cmd_speed_set(cmd,
+ netif_carrier_ok(dev) ? p->link_cfg.speed : 0);
cmd->duplex = DUPLEX_FULL;
cmd->autoneg = p->link_cfg.autoneg;
cmd->maxtxpkt = 0;
@@ -1455,6 +1461,7 @@ static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
unsigned int cap;
struct port_info *p = netdev_priv(dev);
struct link_config *lc = &p->link_cfg;
+ u32 speed = ethtool_cmd_speed(cmd);
if (cmd->duplex != DUPLEX_FULL) /* only full-duplex supported */
return -EINVAL;
@@ -1465,16 +1472,16 @@ static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
* being requested.
*/
if (cmd->autoneg == AUTONEG_DISABLE &&
- (lc->supported & speed_to_caps(cmd->speed)))
- return 0;
+ (lc->supported & speed_to_caps(speed)))
+ return 0;
return -EINVAL;
}
if (cmd->autoneg == AUTONEG_DISABLE) {
- cap = speed_to_caps(cmd->speed);
+ cap = speed_to_caps(speed);
- if (!(lc->supported & cap) || cmd->speed == SPEED_1000 ||
- cmd->speed == SPEED_10000)
+ if (!(lc->supported & cap) || (speed == SPEED_1000) ||
+ (speed == SPEED_10000))
return -EINVAL;
lc->requested_speed = cap;
lc->advertising = 0;
@@ -1526,24 +1533,6 @@ static int set_pauseparam(struct net_device *dev,
return 0;
}
-static u32 get_rx_csum(struct net_device *dev)
-{
- struct port_info *p = netdev_priv(dev);
-
- return p->rx_offload & RX_CSO;
-}
-
-static int set_rx_csum(struct net_device *dev, u32 data)
-{
- struct port_info *p = netdev_priv(dev);
-
- if (data)
- p->rx_offload |= RX_CSO;
- else
- p->rx_offload &= ~RX_CSO;
- return 0;
-}
-
static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
{
const struct port_info *pi = netdev_priv(dev);
@@ -1865,36 +1854,20 @@ 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 |= TSO_FLAGS;
- else
- dev->features &= ~TSO_FLAGS;
- return 0;
-}
-
-static int set_flags(struct net_device *dev, u32 flags)
+static int cxgb_set_features(struct net_device *dev, u32 features)
{
+ const struct port_info *pi = netdev_priv(dev);
+ u32 changed = dev->features ^ features;
int err;
- unsigned long old_feat = dev->features;
- err = ethtool_op_set_flags(dev, flags, ETH_FLAG_RXHASH |
- ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN);
- if (err)
- return err;
-
- if ((old_feat ^ dev->features) & NETIF_F_HW_VLAN_RX) {
- const struct port_info *pi = netdev_priv(dev);
+ if (!(changed & NETIF_F_HW_VLAN_RX))
+ return 0;
- err = t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, -1,
- -1, -1, -1, !!(flags & ETH_FLAG_RXVLAN),
- true);
- if (err)
- dev->features = old_feat;
- }
+ err = t4_set_rxmode(pi->adapter, pi->adapter->fn, pi->viid, -1,
+ -1, -1, -1,
+ !!(features & NETIF_F_HW_VLAN_RX), true);
+ if (unlikely(err))
+ dev->features = features ^ NETIF_F_HW_VLAN_RX;
return err;
}
@@ -2005,13 +1978,9 @@ static struct ethtool_ops cxgb_ethtool_ops = {
.set_eeprom = set_eeprom,
.get_pauseparam = get_pauseparam,
.set_pauseparam = set_pauseparam,
- .get_rx_csum = get_rx_csum,
- .set_rx_csum = 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 = get_strings,
- .phys_id = identify_port,
+ .set_phys_id = identify_port,
.nway_reset = restart_autoneg,
.get_sset_count = get_sset_count,
.get_ethtool_stats = get_stats,
@@ -2019,8 +1988,6 @@ static struct ethtool_ops cxgb_ethtool_ops = {
.get_regs = get_regs,
.get_wol = get_wol,
.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,
@@ -2877,6 +2844,7 @@ static const struct net_device_ops cxgb4_netdev_ops = {
.ndo_get_stats64 = cxgb_get_stats,
.ndo_set_rx_mode = cxgb_set_rxmode,
.ndo_set_mac_address = cxgb_set_mac_addr,
+ .ndo_set_features = cxgb_set_features,
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = cxgb_ioctl,
.ndo_change_mtu = cxgb_change_mtu,
@@ -3559,6 +3527,7 @@ static void free_some_resources(struct adapter *adapter)
t4_fw_bye(adapter, adapter->fn);
}
+#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN)
#define VLAN_FEAT (NETIF_F_SG | NETIF_F_IP_CSUM | TSO_FLAGS | \
NETIF_F_IPV6_CSUM | NETIF_F_HIGHDMA)
@@ -3660,14 +3629,14 @@ static int __devinit init_one(struct pci_dev *pdev,
pi = netdev_priv(netdev);
pi->adapter = adapter;
pi->xact_addr_filt = -1;
- pi->rx_offload = RX_CSO;
pi->port_id = i;
netdev->irq = pdev->irq;
- 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;
+ netdev->hw_features = NETIF_F_SG | TSO_FLAGS |
+ NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+ NETIF_F_RXCSUM | NETIF_F_RXHASH |
+ NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ netdev->features |= netdev->hw_features | highdma;
netdev->vlan_features = netdev->features & VLAN_FEAT;
netdev->netdev_ops = &cxgb4_netdev_ops;
diff --git a/drivers/net/cxgb4/sge.c b/drivers/net/cxgb4/sge.c
index 311471b439a8..56adf448b9fe 100644
--- a/drivers/net/cxgb4/sge.c
+++ b/drivers/net/cxgb4/sge.c
@@ -39,6 +39,7 @@
#include <linux/ip.h>
#include <linux/dma-mapping.h>
#include <linux/jiffies.h>
+#include <linux/prefetch.h>
#include <net/ipv6.h>
#include <net/tcp.h>
#include "cxgb4.h"
@@ -1556,7 +1557,6 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp,
{
bool csum_ok;
struct sk_buff *skb;
- struct port_info *pi;
const struct cpl_rx_pkt *pkt;
struct sge_eth_rxq *rxq = container_of(q, struct sge_eth_rxq, rspq);
@@ -1584,10 +1584,9 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp,
if (skb->dev->features & NETIF_F_RXHASH)
skb->rxhash = (__force u32)pkt->rsshdr.hash_val;
- pi = netdev_priv(skb->dev);
rxq->stats.pkts++;
- if (csum_ok && (pi->rx_offload & RX_CSO) &&
+ if (csum_ok && (q->netdev->features & NETIF_F_RXCSUM) &&
(pkt->l2info & htonl(RXF_UDP | RXF_TCP))) {
if (!pkt->ip_frag) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
diff --git a/drivers/net/cxgb4vf/adapter.h b/drivers/net/cxgb4vf/adapter.h
index 4766b4116b41..4fd821aadc8a 100644
--- a/drivers/net/cxgb4vf/adapter.h
+++ b/drivers/net/cxgb4vf/adapter.h
@@ -97,17 +97,11 @@ struct port_info {
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
diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c
index 4661cbbd9bd9..e71c08e547e4 100644
--- a/drivers/net/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/cxgb4vf/cxgb4vf_main.c
@@ -1167,7 +1167,8 @@ static int cxgb4vf_get_settings(struct net_device *dev,
cmd->supported = pi->link_cfg.supported;
cmd->advertising = pi->link_cfg.advertising;
- cmd->speed = netif_carrier_ok(dev) ? pi->link_cfg.speed : -1;
+ ethtool_cmd_speed_set(cmd,
+ netif_carrier_ok(dev) ? pi->link_cfg.speed : -1);
cmd->duplex = DUPLEX_FULL;
cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
@@ -1326,37 +1327,22 @@ static void cxgb4vf_get_pauseparam(struct net_device *dev,
}
/*
- * 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.
+ * Identify the port by blinking the port's LED.
*/
-static int cxgb4vf_set_rx_csum(struct net_device *dev, u32 csum)
+static int cxgb4vf_phys_id(struct net_device *dev,
+ enum ethtool_phys_id_state state)
{
+ unsigned int val;
struct port_info *pi = netdev_priv(dev);
- if (csum)
- pi->rx_offload |= RX_CSO;
+ if (state == ETHTOOL_ID_ACTIVE)
+ val = 0xffff;
+ else if (state == ETHTOOL_ID_INACTIVE)
+ val = 0;
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 -EINVAL;
- return t4vf_identify_port(pi->adapter, pi->viid, 5);
+ return t4vf_identify_port(pi->adapter, pi->viid, val);
}
/*
@@ -1560,18 +1546,6 @@ static void cxgb4vf_get_wol(struct net_device *dev,
*/
#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN)
-/*
- * Set TCP Segmentation Offloading feature capabilities.
- */
-static int cxgb4vf_set_tso(struct net_device *dev, u32 tso)
-{
- if (tso)
- dev->features |= TSO_FLAGS;
- else
- dev->features &= ~TSO_FLAGS;
- return 0;
-}
-
static struct ethtool_ops cxgb4vf_ethtool_ops = {
.get_settings = cxgb4vf_get_settings,
.get_drvinfo = cxgb4vf_get_drvinfo,
@@ -1582,19 +1556,14 @@ static struct ethtool_ops cxgb4vf_ethtool_ops = {
.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,
+ .set_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,
};
/*
@@ -2629,19 +2598,19 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
* it.
*/
pi->xact_addr_filt = -1;
- pi->rx_offload = RX_CSO;
netif_carrier_off(netdev);
netdev->irq = pdev->irq;
- netdev->features = (NETIF_F_SG | TSO_FLAGS |
- NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
- NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
- NETIF_F_GRO);
+ netdev->hw_features = NETIF_F_SG | TSO_FLAGS |
+ NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+ NETIF_F_HW_VLAN_TX | NETIF_F_RXCSUM;
+ netdev->vlan_features = NETIF_F_SG | TSO_FLAGS |
+ NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+ NETIF_F_HIGHDMA;
+ netdev->features = netdev->hw_features |
+ NETIF_F_HW_VLAN_RX;
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;
diff --git a/drivers/net/cxgb4vf/sge.c b/drivers/net/cxgb4vf/sge.c
index bb65121f581c..5fd75fdaa631 100644
--- a/drivers/net/cxgb4vf/sge.c
+++ b/drivers/net/cxgb4vf/sge.c
@@ -41,6 +41,7 @@
#include <net/ipv6.h>
#include <net/tcp.h>
#include <linux/dma-mapping.h>
+#include <linux/prefetch.h>
#include "t4vf_common.h"
#include "t4vf_defs.h"
@@ -1555,8 +1556,8 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
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 (csum_ok && (rspq->netdev->features & NETIF_F_RXCSUM) &&
+ !pkt->err_vec && (be32_to_cpu(pkt->l2info) & (RXF_UDP|RXF_TCP))) {
if (!pkt->ip_frag)
skb->ip_summed = CHECKSUM_UNNECESSARY;
else {
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index 8b0084d17c8c..17654059922d 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -331,18 +331,18 @@ static struct {
"DE422",\
""}
-static char* __initdata depca_signature[] = DEPCA_SIGNATURE;
+static const char* const depca_signature[] __devinitconst = DEPCA_SIGNATURE;
enum depca_type {
DEPCA, de100, de101, de200, de201, de202, de210, de212, de422, unknown
};
-static char depca_string[] = "depca";
+static const char depca_string[] = "depca";
static int depca_device_remove (struct device *device);
#ifdef CONFIG_EISA
-static struct eisa_device_id depca_eisa_ids[] = {
+static const struct eisa_device_id depca_eisa_ids[] __devinitconst = {
{ "DEC4220", de422 },
{ "" }
};
@@ -367,19 +367,19 @@ static struct eisa_driver depca_eisa_driver = {
#define DE210_ID 0x628d
#define DE212_ID 0x6def
-static short depca_mca_adapter_ids[] = {
+static const short depca_mca_adapter_ids[] __devinitconst = {
DE210_ID,
DE212_ID,
0x0000
};
-static char *depca_mca_adapter_name[] = {
+static const char *depca_mca_adapter_name[] = {
"DEC EtherWORKS MC Adapter (DE210)",
"DEC EtherWORKS MC Adapter (DE212)",
NULL
};
-static enum depca_type depca_mca_adapter_type[] = {
+static const enum depca_type depca_mca_adapter_type[] = {
de210,
de212,
0
@@ -541,10 +541,9 @@ static void SetMulticastFilter(struct net_device *dev);
static int load_packet(struct net_device *dev, struct sk_buff *skb);
static void depca_dbg_open(struct net_device *dev);
-static u_char de1xx_irq[] __initdata = { 2, 3, 4, 5, 7, 9, 0 };
-static u_char de2xx_irq[] __initdata = { 5, 9, 10, 11, 15, 0 };
-static u_char de422_irq[] __initdata = { 5, 9, 10, 11, 0 };
-static u_char *depca_irq;
+static const u_char de1xx_irq[] __devinitconst = { 2, 3, 4, 5, 7, 9, 0 };
+static const u_char de2xx_irq[] __devinitconst = { 5, 9, 10, 11, 15, 0 };
+static const u_char de422_irq[] __devinitconst = { 5, 9, 10, 11, 0 };
static int irq;
static int io;
@@ -580,7 +579,7 @@ static const struct net_device_ops depca_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
};
-static int __init depca_hw_init (struct net_device *dev, struct device *device)
+static int __devinit depca_hw_init (struct net_device *dev, struct device *device)
{
struct depca_private *lp;
int i, j, offset, netRAM, mem_len, status = 0;
@@ -748,6 +747,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device)
if (dev->irq < 2) {
unsigned char irqnum;
unsigned long irq_mask, delay;
+ const u_char *depca_irq;
irq_mask = probe_irq_on();
@@ -770,6 +770,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device)
break;
default:
+ depca_irq = NULL;
break; /* Not reached */
}
@@ -1302,7 +1303,7 @@ static void SetMulticastFilter(struct net_device *dev)
}
}
-static int __init depca_common_init (u_long ioaddr, struct net_device **devp)
+static int __devinit depca_common_init (u_long ioaddr, struct net_device **devp)
{
int status = 0;
@@ -1333,7 +1334,7 @@ static int __init depca_common_init (u_long ioaddr, struct net_device **devp)
/*
** Microchannel bus I/O device probe
*/
-static int __init depca_mca_probe(struct device *device)
+static int __devinit depca_mca_probe(struct device *device)
{
unsigned char pos[2];
unsigned char where;
@@ -1457,7 +1458,7 @@ static int __init depca_mca_probe(struct device *device)
** ISA bus I/O device probe
*/
-static void __init depca_platform_probe (void)
+static void __devinit depca_platform_probe (void)
{
int i;
struct platform_device *pldev;
@@ -1497,7 +1498,7 @@ static void __init depca_platform_probe (void)
}
}
-static enum depca_type __init depca_shmem_probe (ulong *mem_start)
+static enum depca_type __devinit depca_shmem_probe (ulong *mem_start)
{
u_long mem_base[] = DEPCA_RAM_BASE_ADDRESSES;
enum depca_type adapter = unknown;
@@ -1558,7 +1559,7 @@ static int __devinit depca_isa_probe (struct platform_device *device)
*/
#ifdef CONFIG_EISA
-static int __init depca_eisa_probe (struct device *device)
+static int __devinit depca_eisa_probe (struct device *device)
{
enum depca_type adapter = unknown;
struct eisa_device *edev;
@@ -1629,7 +1630,7 @@ static int __devexit depca_device_remove (struct device *device)
** and Boot (readb) ROM. This will also give us a clue to the network RAM
** base address.
*/
-static int __init DepcaSignature(char *name, u_long base_addr)
+static int __devinit DepcaSignature(char *name, u_long base_addr)
{
u_int i, j, k;
void __iomem *ptr;
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
index c05db6046050..c445457b66d5 100644
--- a/drivers/net/dl2k.c
+++ b/drivers/net/dl2k.c
@@ -1189,10 +1189,10 @@ static int rio_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->transceiver = XCVR_INTERNAL;
}
if ( np->link_status ) {
- cmd->speed = np->speed;
+ ethtool_cmd_speed_set(cmd, np->speed);
cmd->duplex = np->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
} else {
- cmd->speed = -1;
+ ethtool_cmd_speed_set(cmd, -1);
cmd->duplex = -1;
}
if ( np->an_enable)
@@ -1219,31 +1219,20 @@ static int rio_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
} else {
np->an_enable = 0;
if (np->speed == 1000) {
- cmd->speed = SPEED_100;
+ ethtool_cmd_speed_set(cmd, SPEED_100);
cmd->duplex = DUPLEX_FULL;
printk("Warning!! Can't disable Auto negotiation in 1000Mbps, change to Manual 100Mbps, Full duplex.\n");
}
- switch(cmd->speed + cmd->duplex) {
-
- case SPEED_10 + DUPLEX_HALF:
- np->speed = 10;
- np->full_duplex = 0;
- break;
-
- case SPEED_10 + DUPLEX_FULL:
+ switch (ethtool_cmd_speed(cmd)) {
+ case SPEED_10:
np->speed = 10;
- np->full_duplex = 1;
+ np->full_duplex = (cmd->duplex == DUPLEX_FULL);
break;
- case SPEED_100 + DUPLEX_HALF:
+ case SPEED_100:
np->speed = 100;
- np->full_duplex = 0;
- break;
- case SPEED_100 + DUPLEX_FULL:
- np->speed = 100;
- np->full_duplex = 1;
+ np->full_duplex = (cmd->duplex == DUPLEX_FULL);
break;
- case SPEED_1000 + DUPLEX_HALF:/* not supported */
- case SPEED_1000 + DUPLEX_FULL:/* not supported */
+ case SPEED_1000: /* not supported */
default:
return -EINVAL;
}
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index b7af5bab9937..fbaff3584bd4 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -131,8 +131,6 @@ typedef struct board_info {
u32 msg_enable;
u32 wake_state;
- int rx_csum;
- int can_csum;
int ip_summed;
} board_info_t;
@@ -470,47 +468,20 @@ static int dm9000_nway_reset(struct net_device *dev)
return mii_nway_restart(&dm->mii);
}
-static uint32_t dm9000_get_rx_csum(struct net_device *dev)
+static int dm9000_set_features(struct net_device *dev, u32 features)
{
board_info_t *dm = to_dm9000_board(dev);
- return dm->rx_csum;
-}
-
-static int dm9000_set_rx_csum_unlocked(struct net_device *dev, uint32_t data)
-{
- board_info_t *dm = to_dm9000_board(dev);
-
- if (dm->can_csum) {
- dm->rx_csum = data;
- iow(dm, DM9000_RCSR, dm->rx_csum ? RCSR_CSUM : 0);
+ u32 changed = dev->features ^ features;
+ unsigned long flags;
+ if (!(changed & NETIF_F_RXCSUM))
return 0;
- }
-
- return -EOPNOTSUPP;
-}
-
-static int dm9000_set_rx_csum(struct net_device *dev, uint32_t data)
-{
- board_info_t *dm = to_dm9000_board(dev);
- unsigned long flags;
- int ret;
spin_lock_irqsave(&dm->lock, flags);
- ret = dm9000_set_rx_csum_unlocked(dev, data);
+ iow(dm, DM9000_RCSR, (features & NETIF_F_RXCSUM) ? RCSR_CSUM : 0);
spin_unlock_irqrestore(&dm->lock, flags);
- return ret;
-}
-
-static int dm9000_set_tx_csum(struct net_device *dev, uint32_t data)
-{
- board_info_t *dm = to_dm9000_board(dev);
- int ret = -EOPNOTSUPP;
-
- if (dm->can_csum)
- ret = ethtool_op_set_tx_csum(dev, data);
- return ret;
+ return 0;
}
static u32 dm9000_get_link(struct net_device *dev)
@@ -643,10 +614,6 @@ static const struct ethtool_ops dm9000_ethtool_ops = {
.get_eeprom_len = dm9000_get_eeprom_len,
.get_eeprom = dm9000_get_eeprom,
.set_eeprom = dm9000_set_eeprom,
- .get_rx_csum = dm9000_get_rx_csum,
- .set_rx_csum = dm9000_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = dm9000_set_tx_csum,
};
static void dm9000_show_carrier(board_info_t *db,
@@ -800,7 +767,9 @@ dm9000_init_dm9000(struct net_device *dev)
db->io_mode = ior(db, DM9000_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */
/* Checksum mode */
- dm9000_set_rx_csum_unlocked(dev, db->rx_csum);
+ if (dev->hw_features & NETIF_F_RXCSUM)
+ iow(db, DM9000_RCSR,
+ (dev->features & NETIF_F_RXCSUM) ? RCSR_CSUM : 0);
iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */
@@ -1049,7 +1018,7 @@ dm9000_rx(struct net_device *dev)
/* Pass to upper layer */
skb->protocol = eth_type_trans(skb, dev);
- if (db->rx_csum) {
+ if (dev->features & NETIF_F_RXCSUM) {
if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0)
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
@@ -1358,6 +1327,7 @@ static const struct net_device_ops dm9000_netdev_ops = {
.ndo_set_multicast_list = dm9000_hash_table,
.ndo_do_ioctl = dm9000_ioctl,
.ndo_change_mtu = eth_change_mtu,
+ .ndo_set_features = dm9000_set_features,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -1551,9 +1521,8 @@ dm9000_probe(struct platform_device *pdev)
/* dm9000a/b are capable of hardware checksum offload */
if (db->type == TYPE_DM9000A || db->type == TYPE_DM9000B) {
- db->can_csum = 1;
- db->rx_csum = 1;
- ndev->features |= NETIF_F_IP_CSUM;
+ ndev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM;
+ ndev->features |= ndev->hw_features;
}
/* from this point we assume that we have found a DM9000 */
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index ff2d29b17858..39cf9b9bd673 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -168,10 +168,6 @@ static int __init dummy_init_one(void)
if (!dev_dummy)
return -ENOMEM;
- err = dev_alloc_name(dev_dummy, dev_dummy->name);
- if (err < 0)
- goto err;
-
dev_dummy->rtnl_link_ops = &dummy_link_ops;
err = register_netdevice(dev_dummy);
if (err < 0)
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index b0aa9e68990a..e336c7937f05 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -593,7 +593,6 @@ struct nic {
enum phy phy;
struct params params;
struct timer_list watchdog;
- struct timer_list blink_timer;
struct mii_if_info mii;
struct work_struct tx_timeout_task;
enum loopback loopback;
@@ -618,7 +617,6 @@ struct nic {
u32 rx_tco_frames;
u32 rx_over_length_errors;
- u16 leds;
u16 eeprom_wc;
__le16 eeprom[256];
spinlock_t mdio_lock;
@@ -1512,7 +1510,7 @@ static int e100_phy_init(struct nic *nic)
static int e100_hw_init(struct nic *nic)
{
- int err;
+ int err = 0;
e100_hw_reset(nic);
@@ -1668,7 +1666,8 @@ static void e100_adjust_adaptive_ifs(struct nic *nic, int speed, int duplex)
static void e100_watchdog(unsigned long data)
{
struct nic *nic = (struct nic *)data;
- struct ethtool_cmd cmd;
+ struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET };
+ u32 speed;
netif_printk(nic, timer, KERN_DEBUG, nic->netdev,
"right now = %ld\n", jiffies);
@@ -1676,10 +1675,11 @@ static void e100_watchdog(unsigned long data)
/* mii library handles link maintenance tasks */
mii_ethtool_gset(&nic->mii, &cmd);
+ speed = ethtool_cmd_speed(&cmd);
if (mii_link_ok(&nic->mii) && !netif_carrier_ok(nic->netdev)) {
netdev_info(nic->netdev, "NIC Link is Up %u Mbps %s Duplex\n",
- cmd.speed == SPEED_100 ? 100 : 10,
+ speed == SPEED_100 ? 100 : 10,
cmd.duplex == DUPLEX_FULL ? "Full" : "Half");
} else if (!mii_link_ok(&nic->mii) && netif_carrier_ok(nic->netdev)) {
netdev_info(nic->netdev, "NIC Link is Down\n");
@@ -1698,13 +1698,13 @@ static void e100_watchdog(unsigned long data)
spin_unlock_irq(&nic->cmd_lock);
e100_update_stats(nic);
- e100_adjust_adaptive_ifs(nic, cmd.speed, cmd.duplex);
+ e100_adjust_adaptive_ifs(nic, speed, cmd.duplex);
if (nic->mac <= mac_82557_D100_C)
/* Issue a multicast command to workaround a 557 lock up */
e100_set_multicast_list(nic->netdev);
- if (nic->flags & ich && cmd.speed==SPEED_10 && cmd.duplex==DUPLEX_HALF)
+ if (nic->flags & ich && speed == SPEED_10 && cmd.duplex == DUPLEX_HALF)
/* Need SW workaround for ICH[x] 10Mbps/half duplex Tx hang. */
nic->flags |= ich_10h_workaround;
else
@@ -2351,30 +2351,6 @@ err_clean_rx:
#define E100_82552_LED_OVERRIDE 0x19
#define E100_82552_LED_ON 0x000F /* LEDTX and LED_RX both on */
#define E100_82552_LED_OFF 0x000A /* LEDTX and LED_RX both off */
-static void e100_blink_led(unsigned long data)
-{
- struct nic *nic = (struct nic *)data;
- enum led_state {
- led_on = 0x01,
- led_off = 0x04,
- led_on_559 = 0x05,
- led_on_557 = 0x07,
- };
- u16 led_reg = MII_LED_CONTROL;
-
- if (nic->phy == phy_82552_v) {
- led_reg = E100_82552_LED_OVERRIDE;
-
- nic->leds = (nic->leds == E100_82552_LED_ON) ?
- E100_82552_LED_OFF : E100_82552_LED_ON;
- } else {
- nic->leds = (nic->leds & led_on) ? led_off :
- (nic->mac < mac_82559_D101M) ? led_on_557 :
- led_on_559;
- }
- mdio_write(nic->netdev, nic->mii.phy_id, led_reg, nic->leds);
- mod_timer(&nic->blink_timer, jiffies + HZ / 4);
-}
static int e100_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
{
@@ -2598,19 +2574,38 @@ static void e100_diag_test(struct net_device *netdev,
msleep_interruptible(4 * 1000);
}
-static int e100_phys_id(struct net_device *netdev, u32 data)
+static int e100_set_phys_id(struct net_device *netdev,
+ enum ethtool_phys_id_state state)
{
struct nic *nic = netdev_priv(netdev);
+ enum led_state {
+ led_on = 0x01,
+ led_off = 0x04,
+ led_on_559 = 0x05,
+ led_on_557 = 0x07,
+ };
u16 led_reg = (nic->phy == phy_82552_v) ? E100_82552_LED_OVERRIDE :
- MII_LED_CONTROL;
+ MII_LED_CONTROL;
+ u16 leds = 0;
- if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
- data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
- mod_timer(&nic->blink_timer, jiffies);
- msleep_interruptible(data * 1000);
- del_timer_sync(&nic->blink_timer);
- mdio_write(netdev, nic->mii.phy_id, led_reg, 0);
+ switch (state) {
+ case ETHTOOL_ID_ACTIVE:
+ return 2;
+
+ case ETHTOOL_ID_ON:
+ leds = (nic->phy == phy_82552_v) ? E100_82552_LED_ON :
+ (nic->mac < mac_82559_D101M) ? led_on_557 : led_on_559;
+ break;
+
+ case ETHTOOL_ID_OFF:
+ leds = (nic->phy == phy_82552_v) ? E100_82552_LED_OFF : led_off;
+ break;
+
+ case ETHTOOL_ID_INACTIVE:
+ break;
+ }
+ mdio_write(netdev, nic->mii.phy_id, led_reg, leds);
return 0;
}
@@ -2691,7 +2686,7 @@ static const struct ethtool_ops e100_ethtool_ops = {
.set_ringparam = e100_set_ringparam,
.self_test = e100_diag_test,
.get_strings = e100_get_strings,
- .phys_id = e100_phys_id,
+ .set_phys_id = e100_set_phys_id,
.get_ethtool_stats = e100_get_ethtool_stats,
.get_sset_count = e100_get_sset_count,
};
@@ -2832,9 +2827,6 @@ static int __devinit e100_probe(struct pci_dev *pdev,
init_timer(&nic->watchdog);
nic->watchdog.function = e100_watchdog;
nic->watchdog.data = (unsigned long)nic;
- init_timer(&nic->blink_timer);
- nic->blink_timer.function = e100_blink_led;
- nic->blink_timer.data = (unsigned long)nic;
INIT_WORK(&nic->tx_timeout_task, e100_tx_timeout_task);
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index a881dd0093bd..8676899120c3 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -238,9 +238,6 @@ struct e1000_adapter {
struct work_struct reset_task;
u8 fc_autoneg;
- struct timer_list blink_timer;
- unsigned long led_status;
-
/* TX */
struct e1000_tx_ring *tx_ring; /* One per active queue */
unsigned int restart_queue;
@@ -349,7 +346,7 @@ extern int e1000_up(struct e1000_adapter *adapter);
extern void e1000_down(struct e1000_adapter *adapter);
extern void e1000_reinit_locked(struct e1000_adapter *adapter);
extern void e1000_reset(struct e1000_adapter *adapter);
-extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx);
+extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, u32 spd, u8 dplx);
extern int e1000_setup_all_rx_resources(struct e1000_adapter *adapter);
extern int e1000_setup_all_tx_resources(struct e1000_adapter *adapter);
extern void e1000_free_all_rx_resources(struct e1000_adapter *adapter);
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index dd70738eb2f4..ec0fa426cce2 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -158,7 +158,7 @@ static int e1000_get_settings(struct net_device *netdev,
e1000_get_speed_and_duplex(hw, &adapter->link_speed,
&adapter->link_duplex);
- ecmd->speed = adapter->link_speed;
+ ethtool_cmd_speed_set(ecmd, adapter->link_speed);
/* unfortunately FULL_DUPLEX != DUPLEX_FULL
* and HALF_DUPLEX != DUPLEX_HALF */
@@ -168,7 +168,7 @@ static int e1000_get_settings(struct net_device *netdev,
else
ecmd->duplex = DUPLEX_HALF;
} else {
- ecmd->speed = -1;
+ ethtool_cmd_speed_set(ecmd, -1);
ecmd->duplex = -1;
}
@@ -197,11 +197,13 @@ static int e1000_set_settings(struct net_device *netdev,
ADVERTISED_TP |
ADVERTISED_Autoneg;
ecmd->advertising = hw->autoneg_advertised;
- } else
- if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) {
+ } else {
+ u32 speed = ethtool_cmd_speed(ecmd);
+ if (e1000_set_spd_dplx(adapter, speed, ecmd->duplex)) {
clear_bit(__E1000_RESETTING, &adapter->flags);
return -EINVAL;
}
+ }
/* reset the link */
@@ -1753,46 +1755,28 @@ static int e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
return 0;
}
-/* toggle LED 4 times per second = 2 "blinks" per second */
-#define E1000_ID_INTERVAL (HZ/4)
-
-/* bit defines for adapter->led_status */
-#define E1000_LED_ON 0
-
-static void e1000_led_blink_callback(unsigned long data)
+static int e1000_set_phys_id(struct net_device *netdev,
+ enum ethtool_phys_id_state state)
{
- struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
- if (test_and_change_bit(E1000_LED_ON, &adapter->led_status))
- e1000_led_off(hw);
- else
- e1000_led_on(hw);
+ switch (state) {
+ case ETHTOOL_ID_ACTIVE:
+ e1000_setup_led(hw);
+ return 2;
- mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL);
-}
-
-static int e1000_phys_id(struct net_device *netdev, u32 data)
-{
- struct e1000_adapter *adapter = netdev_priv(netdev);
- struct e1000_hw *hw = &adapter->hw;
+ case ETHTOOL_ID_ON:
+ e1000_led_on(hw);
+ break;
- if (!data)
- data = INT_MAX;
+ case ETHTOOL_ID_OFF:
+ e1000_led_off(hw);
+ break;
- if (!adapter->blink_timer.function) {
- init_timer(&adapter->blink_timer);
- adapter->blink_timer.function = e1000_led_blink_callback;
- adapter->blink_timer.data = (unsigned long)adapter;
+ case ETHTOOL_ID_INACTIVE:
+ e1000_cleanup_led(hw);
}
- e1000_setup_led(hw);
- mod_timer(&adapter->blink_timer, jiffies);
- msleep_interruptible(data * 1000);
- del_timer_sync(&adapter->blink_timer);
-
- e1000_led_off(hw);
- clear_bit(E1000_LED_ON, &adapter->led_status);
- e1000_cleanup_led(hw);
return 0;
}
@@ -1929,7 +1913,7 @@ static const struct ethtool_ops e1000_ethtool_ops = {
.set_tso = e1000_set_tso,
.self_test = e1000_diag_test,
.get_strings = e1000_get_strings,
- .phys_id = e1000_phys_id,
+ .set_phys_id = e1000_set_phys_id,
.get_ethtool_stats = e1000_get_ethtool_stats,
.get_sset_count = e1000_get_sset_count,
.get_coalesce = e1000_get_coalesce,
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 477e066a1cf0..76e8af00d86d 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -29,6 +29,7 @@
#include "e1000.h"
#include <net/ip6_checksum.h>
#include <linux/io.h>
+#include <linux/prefetch.h>
/* Intel Media SOC GbE MDIO physical base address */
static unsigned long ce4100_gbe_mdio_base_phy;
@@ -96,7 +97,6 @@ int e1000_up(struct e1000_adapter *adapter);
void e1000_down(struct e1000_adapter *adapter);
void e1000_reinit_locked(struct e1000_adapter *adapter);
void e1000_reset(struct e1000_adapter *adapter);
-int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx);
int e1000_setup_all_tx_resources(struct e1000_adapter *adapter);
int e1000_setup_all_rx_resources(struct e1000_adapter *adapter);
void e1000_free_all_tx_resources(struct e1000_adapter *adapter);
@@ -4385,7 +4385,6 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
struct mii_ioctl_data *data = if_mii(ifr);
int retval;
u16 mii_reg;
- u16 spddplx;
unsigned long flags;
if (hw->media_type != e1000_media_type_copper)
@@ -4424,17 +4423,18 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
hw->autoneg = 1;
hw->autoneg_advertised = 0x2F;
} else {
+ u32 speed;
if (mii_reg & 0x40)
- spddplx = SPEED_1000;
+ speed = SPEED_1000;
else if (mii_reg & 0x2000)
- spddplx = SPEED_100;
+ speed = SPEED_100;
else
- spddplx = SPEED_10;
- spddplx += (mii_reg & 0x100)
- ? DUPLEX_FULL :
- DUPLEX_HALF;
- retval = e1000_set_spd_dplx(adapter,
- spddplx);
+ speed = SPEED_10;
+ retval = e1000_set_spd_dplx(
+ adapter, speed,
+ ((mii_reg & 0x100)
+ ? DUPLEX_FULL :
+ DUPLEX_HALF));
if (retval)
return retval;
}
@@ -4596,20 +4596,24 @@ static void e1000_restore_vlan(struct e1000_adapter *adapter)
}
}
-int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx)
+int e1000_set_spd_dplx(struct e1000_adapter *adapter, u32 spd, u8 dplx)
{
struct e1000_hw *hw = &adapter->hw;
hw->autoneg = 0;
+ /* Make sure dplx is at most 1 bit and lsb of speed is not set
+ * for the switch() below to work */
+ if ((spd & 1) || (dplx & ~1))
+ goto err_inval;
+
/* Fiber NICs only allow 1000 gbps Full duplex */
if ((hw->media_type == e1000_media_type_fiber) &&
- spddplx != (SPEED_1000 + DUPLEX_FULL)) {
- e_err(probe, "Unsupported Speed/Duplex configuration\n");
- return -EINVAL;
- }
+ spd != SPEED_1000 &&
+ dplx != DUPLEX_FULL)
+ goto err_inval;
- switch (spddplx) {
+ switch (spd + dplx) {
case SPEED_10 + DUPLEX_HALF:
hw->forced_speed_duplex = e1000_10_half;
break;
@@ -4628,10 +4632,13 @@ int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx)
break;
case SPEED_1000 + DUPLEX_HALF: /* not supported */
default:
- e_err(probe, "Unsupported Speed/Duplex configuration\n");
- return -EINVAL;
+ goto err_inval;
}
return 0;
+
+err_inval:
+ e_err(probe, "Unsupported Speed/Duplex configuration\n");
+ return -EINVAL;
}
static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake)
diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c
index 89a69035e538..8295f2192439 100644
--- a/drivers/net/e1000e/82571.c
+++ b/drivers/net/e1000e/82571.c
@@ -300,6 +300,7 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter)
func->set_lan_id = e1000_set_lan_id_single_port;
func->check_mng_mode = e1000e_check_mng_mode_generic;
func->led_on = e1000e_led_on_generic;
+ func->blink_led = e1000e_blink_led_generic;
/* FWSM register */
mac->has_fwsm = true;
@@ -320,6 +321,7 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter)
default:
func->check_mng_mode = e1000e_check_mng_mode_generic;
func->led_on = e1000e_led_on_generic;
+ func->blink_led = e1000e_blink_led_generic;
/* FWSM register */
mac->has_fwsm = true;
@@ -431,9 +433,6 @@ static s32 e1000_get_variants_82571(struct e1000_adapter *adapter)
case e1000_82573:
case e1000_82574:
case e1000_82583:
- /* Disable ASPM L0s due to hardware errata */
- e1000e_disable_aspm(adapter->pdev, PCIE_LINK_STATE_L0S);
-
if (pdev->device == E1000_DEV_ID_82573L) {
adapter->flags |= FLAG_HAS_JUMBO_FRAMES;
adapter->max_hw_frame_size = DEFAULT_JUMBO;
@@ -594,7 +593,7 @@ static s32 e1000_get_hw_semaphore_82573(struct e1000_hw *hw)
extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
- msleep(2);
+ usleep_range(2000, 4000);
i++;
} while (i < MDIO_OWNERSHIP_TIMEOUT);
@@ -816,7 +815,7 @@ static s32 e1000_update_nvm_checksum_82571(struct e1000_hw *hw)
/* Check for pending operations. */
for (i = 0; i < E1000_FLASH_UPDATES; i++) {
- msleep(1);
+ usleep_range(1000, 2000);
if ((er32(EECD) & E1000_EECD_FLUPD) == 0)
break;
}
@@ -840,7 +839,7 @@ static s32 e1000_update_nvm_checksum_82571(struct e1000_hw *hw)
ew32(EECD, eecd);
for (i = 0; i < E1000_FLASH_UPDATES; i++) {
- msleep(1);
+ usleep_range(1000, 2000);
if ((er32(EECD) & E1000_EECD_FLUPD) == 0)
break;
}
@@ -930,7 +929,7 @@ static s32 e1000_get_cfg_done_82571(struct e1000_hw *hw)
if (er32(EEMNGCTL) &
E1000_NVM_CFG_DONE_PORT_0)
break;
- msleep(1);
+ usleep_range(1000, 2000);
timeout--;
}
if (!timeout) {
@@ -1037,7 +1036,7 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
ew32(TCTL, E1000_TCTL_PSP);
e1e_flush();
- msleep(10);
+ usleep_range(10000, 20000);
/*
* Must acquire the MDIO ownership before MAC reset.
@@ -2066,7 +2065,8 @@ struct e1000_info e1000_82573_info = {
| FLAG_HAS_SMART_POWER_DOWN
| FLAG_HAS_AMT
| FLAG_HAS_SWSM_ON_LOAD,
- .flags2 = FLAG2_DISABLE_ASPM_L1,
+ .flags2 = FLAG2_DISABLE_ASPM_L1
+ | FLAG2_DISABLE_ASPM_L0S,
.pba = 20,
.max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN,
.get_variants = e1000_get_variants_82571,
@@ -2086,7 +2086,8 @@ struct e1000_info e1000_82574_info = {
| FLAG_HAS_SMART_POWER_DOWN
| FLAG_HAS_AMT
| FLAG_HAS_CTRLEXT_ON_LOAD,
- .flags2 = FLAG2_CHECK_PHY_HANG,
+ .flags2 = FLAG2_CHECK_PHY_HANG
+ | FLAG2_DISABLE_ASPM_L0S,
.pba = 32,
.max_hw_frame_size = DEFAULT_JUMBO,
.get_variants = e1000_get_variants_82571,
@@ -2104,6 +2105,7 @@ struct e1000_info e1000_82583_info = {
| FLAG_HAS_SMART_POWER_DOWN
| FLAG_HAS_AMT
| FLAG_HAS_CTRLEXT_ON_LOAD,
+ .flags2 = FLAG2_DISABLE_ASPM_L0S,
.pba = 32,
.max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN,
.get_variants = e1000_get_variants_82571,
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
index 00bf595ebd67..9549879e66a0 100644
--- a/drivers/net/e1000e/e1000.h
+++ b/drivers/net/e1000e/e1000.h
@@ -31,6 +31,7 @@
#ifndef _E1000_H_
#define _E1000_H_
+#include <linux/bitops.h>
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
@@ -39,6 +40,7 @@
#include <linux/pci.h>
#include <linux/pci-aspm.h>
#include <linux/crc32.h>
+#include <linux/if_vlan.h>
#include "hw.h"
@@ -280,7 +282,7 @@ struct e1000_adapter {
const struct e1000_info *ei;
- struct vlan_group *vlgrp;
+ unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
u32 bd_number;
u32 rx_buffer_len;
u16 mng_vlan_id;
@@ -389,13 +391,10 @@ struct e1000_adapter {
bool fc_autoneg;
- unsigned long led_status;
-
unsigned int flags;
unsigned int flags2;
struct work_struct downshift_task;
struct work_struct update_phy_task;
- struct work_struct led_blink_task;
struct work_struct print_hang_task;
bool idle_check;
@@ -456,6 +455,7 @@ struct e1000_info {
#define FLAG2_HAS_PHY_STATS (1 << 4)
#define FLAG2_HAS_EEE (1 << 5)
#define FLAG2_DMA_BURST (1 << 6)
+#define FLAG2_DISABLE_ASPM_L0S (1 << 7)
#define FLAG2_DISABLE_AIM (1 << 8)
#define FLAG2_CHECK_PHY_HANG (1 << 9)
@@ -484,7 +484,6 @@ extern const char e1000e_driver_version[];
extern void e1000e_check_options(struct e1000_adapter *adapter);
extern void e1000e_set_ethtool_ops(struct net_device *netdev);
-extern void e1000e_led_blink_task(struct work_struct *work);
extern int e1000e_up(struct e1000_adapter *adapter);
extern void e1000e_down(struct e1000_adapter *adapter);
@@ -502,7 +501,6 @@ extern void e1000e_set_interrupt_capability(struct e1000_adapter *adapter);
extern void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter);
extern void e1000e_get_hw_control(struct e1000_adapter *adapter);
extern void e1000e_release_hw_control(struct e1000_adapter *adapter);
-extern void e1000e_disable_aspm(struct pci_dev *pdev, u16 state);
extern unsigned int copybreak;
@@ -573,7 +571,7 @@ extern s32 e1000e_valid_led_default(struct e1000_hw *hw, u16 *data);
extern void e1000e_config_collision_dist(struct e1000_hw *hw);
extern s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw);
extern s32 e1000e_force_mac_fc(struct e1000_hw *hw);
-extern s32 e1000e_blink_led(struct e1000_hw *hw);
+extern s32 e1000e_blink_led_generic(struct e1000_hw *hw);
extern void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value);
extern s32 e1000_check_alt_mac_addr_generic(struct e1000_hw *hw);
extern void e1000e_reset_adaptive(struct e1000_hw *hw);
diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c
index 2fefa820302b..f4bbeb22f51f 100644
--- a/drivers/net/e1000e/es2lan.c
+++ b/drivers/net/e1000e/es2lan.c
@@ -612,7 +612,7 @@ static s32 e1000_get_cfg_done_80003es2lan(struct e1000_hw *hw)
while (timeout) {
if (er32(EEMNGCTL) & mask)
break;
- msleep(1);
+ usleep_range(1000, 2000);
timeout--;
}
if (!timeout) {
@@ -802,7 +802,7 @@ static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw)
ew32(TCTL, E1000_TCTL_PSP);
e1e_flush();
- msleep(10);
+ usleep_range(10000, 20000);
ctrl = er32(CTRL);
@@ -1434,6 +1434,7 @@ static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw)
static struct e1000_mac_operations es2_mac_ops = {
.read_mac_addr = e1000_read_mac_addr_80003es2lan,
.id_led_init = e1000e_id_led_init,
+ .blink_led = e1000e_blink_led_generic,
.check_mng_mode = e1000e_check_mng_mode_generic,
/* check_for_link dependent on media type */
.cleanup_led = e1000e_cleanup_led_generic,
diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c
index 07f09e96e453..859d0d3af6c9 100644
--- a/drivers/net/e1000e/ethtool.c
+++ b/drivers/net/e1000e/ethtool.c
@@ -122,6 +122,7 @@ static int e1000_get_settings(struct net_device *netdev,
{
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
+ u32 speed;
if (hw->phy.media_type == e1000_media_type_copper) {
@@ -159,23 +160,23 @@ static int e1000_get_settings(struct net_device *netdev,
ecmd->transceiver = XCVR_EXTERNAL;
}
- ecmd->speed = -1;
+ speed = -1;
ecmd->duplex = -1;
if (netif_running(netdev)) {
if (netif_carrier_ok(netdev)) {
- ecmd->speed = adapter->link_speed;
+ speed = adapter->link_speed;
ecmd->duplex = adapter->link_duplex - 1;
}
} else {
u32 status = er32(STATUS);
if (status & E1000_STATUS_LU) {
if (status & E1000_STATUS_SPEED_1000)
- ecmd->speed = 1000;
+ speed = SPEED_1000;
else if (status & E1000_STATUS_SPEED_100)
- ecmd->speed = 100;
+ speed = SPEED_100;
else
- ecmd->speed = 10;
+ speed = SPEED_10;
if (status & E1000_STATUS_FD)
ecmd->duplex = DUPLEX_FULL;
@@ -184,6 +185,7 @@ static int e1000_get_settings(struct net_device *netdev,
}
}
+ ethtool_cmd_speed_set(ecmd, speed);
ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) ||
hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE;
@@ -198,20 +200,25 @@ static int e1000_get_settings(struct net_device *netdev,
return 0;
}
-static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx)
+static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u32 spd, u8 dplx)
{
struct e1000_mac_info *mac = &adapter->hw.mac;
mac->autoneg = 0;
+ /* Make sure dplx is at most 1 bit and lsb of speed is not set
+ * for the switch() below to work */
+ if ((spd & 1) || (dplx & ~1))
+ goto err_inval;
+
/* Fiber NICs only allow 1000 gbps Full duplex */
if ((adapter->hw.phy.media_type == e1000_media_type_fiber) &&
- spddplx != (SPEED_1000 + DUPLEX_FULL)) {
- e_err("Unsupported Speed/Duplex configuration\n");
- return -EINVAL;
+ spd != SPEED_1000 &&
+ dplx != DUPLEX_FULL) {
+ goto err_inval;
}
- switch (spddplx) {
+ switch (spd + dplx) {
case SPEED_10 + DUPLEX_HALF:
mac->forced_speed_duplex = ADVERTISE_10_HALF;
break;
@@ -230,10 +237,13 @@ static 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");
- return -EINVAL;
+ goto err_inval;
}
return 0;
+
+err_inval:
+ e_err("Unsupported Speed/Duplex configuration\n");
+ return -EINVAL;
}
static int e1000_set_settings(struct net_device *netdev,
@@ -253,7 +263,7 @@ static int e1000_set_settings(struct net_device *netdev,
}
while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
- msleep(1);
+ usleep_range(1000, 2000);
if (ecmd->autoneg == AUTONEG_ENABLE) {
hw->mac.autoneg = 1;
@@ -269,7 +279,8 @@ static int e1000_set_settings(struct net_device *netdev,
if (adapter->fc_autoneg)
hw->fc.requested_mode = e1000_fc_default;
} else {
- if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) {
+ u32 speed = ethtool_cmd_speed(ecmd);
+ if (e1000_set_spd_dplx(adapter, speed, ecmd->duplex)) {
clear_bit(__E1000_RESETTING, &adapter->state);
return -EINVAL;
}
@@ -317,7 +328,7 @@ static int e1000_set_pauseparam(struct net_device *netdev,
adapter->fc_autoneg = pause->autoneg;
while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
- msleep(1);
+ usleep_range(1000, 2000);
if (adapter->fc_autoneg == AUTONEG_ENABLE) {
hw->fc.requested_mode = e1000_fc_default;
@@ -673,7 +684,7 @@ static int e1000_set_ringparam(struct net_device *netdev,
return -EINVAL;
while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
- msleep(1);
+ usleep_range(1000, 2000);
if (netif_running(adapter->netdev))
e1000e_down(adapter);
@@ -952,7 +963,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
/* Disable all the interrupts */
ew32(IMC, 0xFFFFFFFF);
- msleep(10);
+ usleep_range(10000, 20000);
/* Test each interrupt */
for (i = 0; i < 10; i++) {
@@ -984,7 +995,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
adapter->test_icr = 0;
ew32(IMC, mask);
ew32(ICS, mask);
- msleep(10);
+ usleep_range(10000, 20000);
if (adapter->test_icr & mask) {
*data = 3;
@@ -1002,7 +1013,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
adapter->test_icr = 0;
ew32(IMS, mask);
ew32(ICS, mask);
- msleep(10);
+ usleep_range(10000, 20000);
if (!(adapter->test_icr & mask)) {
*data = 4;
@@ -1020,7 +1031,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
adapter->test_icr = 0;
ew32(IMC, ~mask & 0x00007FFF);
ew32(ICS, ~mask & 0x00007FFF);
- msleep(10);
+ usleep_range(10000, 20000);
if (adapter->test_icr) {
*data = 5;
@@ -1031,7 +1042,7 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
/* Disable all the interrupts */
ew32(IMC, 0xFFFFFFFF);
- msleep(10);
+ usleep_range(10000, 20000);
/* Unhook test interrupt handler */
free_irq(irq, netdev);
@@ -1406,7 +1417,7 @@ static int e1000_set_82571_fiber_loopback(struct e1000_adapter *adapter)
*/
#define E1000_SERDES_LB_ON 0x410
ew32(SCTL, E1000_SERDES_LB_ON);
- msleep(10);
+ usleep_range(10000, 20000);
return 0;
}
@@ -1501,7 +1512,7 @@ static void e1000_loopback_cleanup(struct e1000_adapter *adapter)
hw->phy.media_type == e1000_media_type_internal_serdes) {
#define E1000_SERDES_LB_OFF 0x400
ew32(SCTL, E1000_SERDES_LB_OFF);
- msleep(10);
+ usleep_range(10000, 20000);
break;
}
/* Fall Through */
@@ -1851,64 +1862,35 @@ static int e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
return 0;
}
-/* toggle LED 4 times per second = 2 "blinks" per second */
-#define E1000_ID_INTERVAL (HZ/4)
-
-/* bit defines for adapter->led_status */
-#define E1000_LED_ON 0
-
-void e1000e_led_blink_task(struct work_struct *work)
-{
- struct e1000_adapter *adapter = container_of(work,
- struct e1000_adapter, led_blink_task);
-
- if (test_and_change_bit(E1000_LED_ON, &adapter->led_status))
- adapter->hw.mac.ops.led_off(&adapter->hw);
- else
- adapter->hw.mac.ops.led_on(&adapter->hw);
-}
-
-static void e1000_led_blink_callback(unsigned long data)
-{
- struct e1000_adapter *adapter = (struct e1000_adapter *) data;
-
- schedule_work(&adapter->led_blink_task);
- mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL);
-}
-
-static int e1000_phys_id(struct net_device *netdev, u32 data)
+static int e1000_set_phys_id(struct net_device *netdev,
+ enum ethtool_phys_id_state state)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
- if (!data)
- data = INT_MAX;
+ switch (state) {
+ case ETHTOOL_ID_ACTIVE:
+ if (!hw->mac.ops.blink_led)
+ return 2; /* cycle on/off twice per second */
- 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)) {
- if (!adapter->blink_timer.function) {
- init_timer(&adapter->blink_timer);
- adapter->blink_timer.function =
- e1000_led_blink_callback;
- adapter->blink_timer.data = (unsigned long) adapter;
- }
- mod_timer(&adapter->blink_timer, jiffies);
- msleep_interruptible(data * 1000);
- del_timer_sync(&adapter->blink_timer);
+ hw->mac.ops.blink_led(hw);
+ break;
+
+ case ETHTOOL_ID_INACTIVE:
if (hw->phy.type == e1000_phy_ife)
e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0);
- } else {
- e1000e_blink_led(hw);
- msleep_interruptible(data * 1000);
- }
+ hw->mac.ops.led_off(hw);
+ hw->mac.ops.cleanup_led(hw);
+ break;
- hw->mac.ops.led_off(hw);
- clear_bit(E1000_LED_ON, &adapter->led_status);
- hw->mac.ops.cleanup_led(hw);
+ case ETHTOOL_ID_ON:
+ adapter->hw.mac.ops.led_on(&adapter->hw);
+ break;
+ case ETHTOOL_ID_OFF:
+ adapter->hw.mac.ops.led_off(&adapter->hw);
+ break;
+ }
return 0;
}
@@ -2020,6 +2002,31 @@ static void e1000_get_strings(struct net_device *netdev, u32 stringset,
}
}
+static int e1000e_set_flags(struct net_device *netdev, u32 data)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ bool need_reset = false;
+ int rc;
+
+ need_reset = (data & ETH_FLAG_RXVLAN) !=
+ (netdev->features & NETIF_F_HW_VLAN_RX);
+
+ rc = ethtool_op_set_flags(netdev, data, ETH_FLAG_RXVLAN |
+ ETH_FLAG_TXVLAN);
+
+ if (rc)
+ return rc;
+
+ if (need_reset) {
+ if (netif_running(netdev))
+ e1000e_reinit_locked(adapter);
+ else
+ e1000e_reset(adapter);
+ }
+
+ return 0;
+}
+
static const struct ethtool_ops e1000_ethtool_ops = {
.get_settings = e1000_get_settings,
.set_settings = e1000_set_settings,
@@ -2049,12 +2056,13 @@ static const struct ethtool_ops e1000_ethtool_ops = {
.set_tso = e1000_set_tso,
.self_test = e1000_diag_test,
.get_strings = e1000_get_strings,
- .phys_id = e1000_phys_id,
+ .set_phys_id = e1000_set_phys_id,
.get_ethtool_stats = e1000_get_ethtool_stats,
.get_sset_count = e1000e_get_sset_count,
.get_coalesce = e1000_get_coalesce,
.set_coalesce = e1000_set_coalesce,
.get_flags = ethtool_op_get_flags,
+ .set_flags = e1000e_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 307e1ec22417..6c2fa8327f5c 100644
--- a/drivers/net/e1000e/hw.h
+++ b/drivers/net/e1000e/hw.h
@@ -756,6 +756,7 @@ struct e1000_host_mng_command_info {
/* Function pointers and static data for the MAC. */
struct e1000_mac_operations {
s32 (*id_led_init)(struct e1000_hw *);
+ s32 (*blink_led)(struct e1000_hw *);
bool (*check_mng_mode)(struct e1000_hw *);
s32 (*check_for_link)(struct e1000_hw *);
s32 (*cleanup_led)(struct e1000_hw *);
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c
index ce1dbfdca112..3369d1f6a39c 100644
--- a/drivers/net/e1000e/ich8lan.c
+++ b/drivers/net/e1000e/ich8lan.c
@@ -338,7 +338,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
/* Ungate automatic PHY configuration on non-managed 82579 */
if ((hw->mac.type == e1000_pch2lan) &&
!(fwsm & E1000_ICH_FWSM_FW_VALID)) {
- msleep(10);
+ usleep_range(10000, 20000);
e1000_gate_hw_phy_config_ich8lan(hw, false);
}
@@ -427,7 +427,7 @@ static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
phy->id = 0;
while ((e1000_phy_unknown == e1000e_get_phy_type_from_id(phy->id)) &&
(i++ < 100)) {
- msleep(1);
+ usleep_range(1000, 2000);
ret_val = e1000e_get_phy_id(hw);
if (ret_val)
return ret_val;
@@ -564,6 +564,8 @@ static s32 e1000_init_mac_params_ich8lan(struct e1000_adapter *adapter)
mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan;
/* ID LED init */
mac->ops.id_led_init = e1000e_id_led_init;
+ /* blink LED */
+ mac->ops.blink_led = e1000e_blink_led_generic;
/* setup LED */
mac->ops.setup_led = e1000e_setup_led_generic;
/* cleanup LED */
@@ -767,6 +769,8 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
(!(er32(CTRL_EXT) & E1000_CTRL_EXT_LSECCK)))) {
adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES;
adapter->max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN;
+
+ hw->mac.ops.blink_led = NULL;
}
if ((adapter->hw.mac.type == e1000_ich8lan) &&
@@ -1704,7 +1708,7 @@ static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw)
goto out;
/* Allow time for h/w to get to quiescent state after reset */
- msleep(10);
+ usleep_range(10000, 20000);
/* Perform any necessary post-reset workarounds */
switch (hw->mac.type) {
@@ -1737,7 +1741,7 @@ static s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw)
if (hw->mac.type == e1000_pch2lan) {
/* Ungate automatic PHY configuration on non-managed 82579 */
if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) {
- msleep(10);
+ usleep_range(10000, 20000);
e1000_gate_hw_phy_config_ich8lan(hw, false);
}
@@ -2532,7 +2536,7 @@ release:
*/
if (!ret_val) {
e1000e_reload_nvm(hw);
- msleep(10);
+ usleep_range(10000, 20000);
}
out:
@@ -3009,7 +3013,7 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
ew32(TCTL, E1000_TCTL_PSP);
e1e_flush();
- msleep(10);
+ usleep_range(10000, 20000);
/* Workaround for ICH8 bit corruption issue in FIFO memory */
if (hw->mac.type == e1000_ich8lan) {
diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c
index 96921de5df2e..dd8ab05b5590 100644
--- a/drivers/net/e1000e/lib.c
+++ b/drivers/net/e1000e/lib.c
@@ -144,7 +144,7 @@ void e1000_write_vfta_generic(struct e1000_hw *hw, u32 offset, u32 value)
* @hw: pointer to the HW structure
* @rar_count: receive address registers
*
- * Setups the receive address registers by setting the base receive address
+ * Setup the receive address registers by setting the base receive address
* register to the devices MAC address and clearing all the other receive
* address registers to 0.
**/
@@ -868,7 +868,7 @@ static s32 e1000_poll_fiber_serdes_link_generic(struct e1000_hw *hw)
* milliseconds even if the other end is doing it in SW).
*/
for (i = 0; i < FIBER_LINK_UP_LIMIT; i++) {
- msleep(10);
+ usleep_range(10000, 20000);
status = er32(STATUS);
if (status & E1000_STATUS_LU)
break;
@@ -930,7 +930,7 @@ s32 e1000e_setup_fiber_serdes_link(struct e1000_hw *hw)
ew32(CTRL, ctrl);
e1e_flush();
- msleep(1);
+ usleep_range(1000, 2000);
/*
* For these adapters, the SW definable pin 1 is set when the optics
@@ -1181,7 +1181,7 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw)
* of pause frames. In this case, we had to advertise
* FULL flow control because we could not advertise Rx
* ONLY. Hence, we must now check to see if we need to
- * turn OFF the TRANSMISSION of PAUSE frames.
+ * turn OFF the TRANSMISSION of PAUSE frames.
*/
if (hw->fc.requested_mode == e1000_fc_full) {
hw->fc.current_mode = e1000_fc_full;
@@ -1385,7 +1385,7 @@ s32 e1000e_get_auto_rd_done(struct e1000_hw *hw)
while (i < AUTO_READ_DONE_TIMEOUT) {
if (er32(EECD) & E1000_EECD_AUTO_RD)
break;
- msleep(1);
+ usleep_range(1000, 2000);
i++;
}
@@ -1530,12 +1530,12 @@ s32 e1000e_cleanup_led_generic(struct e1000_hw *hw)
}
/**
- * e1000e_blink_led - Blink LED
+ * e1000e_blink_led_generic - Blink LED
* @hw: pointer to the HW structure
*
* Blink the LEDs which are set to be on.
**/
-s32 e1000e_blink_led(struct e1000_hw *hw)
+s32 e1000e_blink_led_generic(struct e1000_hw *hw)
{
u32 ledctl_blink = 0;
u32 i;
@@ -2087,8 +2087,6 @@ s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
if (ret_val)
return ret_val;
- msleep(10);
-
while (widx < words) {
u8 write_opcode = NVM_WRITE_OPCODE_SPI;
@@ -2132,7 +2130,7 @@ s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
}
}
- msleep(10);
+ usleep_range(10000, 20000);
nvm->ops.release(hw);
return 0;
}
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 506a0a0043b3..3310c3d477d7 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -49,6 +49,7 @@
#include <linux/pm_qos_params.h>
#include <linux/pm_runtime.h>
#include <linux/aer.h>
+#include <linux/prefetch.h>
#include "e1000.h"
@@ -58,6 +59,8 @@
char e1000e_driver_name[] = "e1000e";
const char e1000e_driver_version[] = DRV_VERSION;
+static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state);
+
static const struct e1000_info *e1000_info_tbl[] = {
[board_82571] = &e1000_82571_info,
[board_82572] = &e1000_82572_info,
@@ -459,13 +462,13 @@ static void e1000_receive_skb(struct e1000_adapter *adapter,
struct net_device *netdev, struct sk_buff *skb,
u8 status, __le16 vlan)
{
+ u16 tag = le16_to_cpu(vlan);
skb->protocol = eth_type_trans(skb, netdev);
- if (adapter->vlgrp && (status & E1000_RXD_STAT_VP))
- vlan_gro_receive(&adapter->napi, adapter->vlgrp,
- le16_to_cpu(vlan), skb);
- else
- napi_gro_receive(&adapter->napi, skb);
+ if (status & E1000_RXD_STAT_VP)
+ __vlan_hwaccel_put_tag(skb, tag);
+
+ napi_gro_receive(&adapter->napi, skb);
}
/**
@@ -2433,6 +2436,8 @@ static void e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
vfta |= (1 << (vid & 0x1F));
hw->mac.ops.write_vfta(hw, index, vfta);
}
+
+ set_bit(vid, adapter->active_vlans);
}
static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
@@ -2441,13 +2446,6 @@ static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
struct e1000_hw *hw = &adapter->hw;
u32 vfta, index;
- if (!test_bit(__E1000_DOWN, &adapter->state))
- e1000_irq_disable(adapter);
- vlan_group_set_device(adapter->vlgrp, vid, NULL);
-
- if (!test_bit(__E1000_DOWN, &adapter->state))
- e1000_irq_enable(adapter);
-
if ((adapter->hw.mng_cookie.status &
E1000_MNG_DHCP_COOKIE_STATUS_VLAN) &&
(vid == adapter->mng_vlan_id)) {
@@ -2463,93 +2461,105 @@ static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
vfta &= ~(1 << (vid & 0x1F));
hw->mac.ops.write_vfta(hw, index, vfta);
}
+
+ clear_bit(vid, adapter->active_vlans);
}
-static void e1000_update_mng_vlan(struct e1000_adapter *adapter)
+/**
+ * e1000e_vlan_filter_disable - helper to disable hw VLAN filtering
+ * @adapter: board private structure to initialize
+ **/
+static void e1000e_vlan_filter_disable(struct e1000_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
- u16 vid = adapter->hw.mng_cookie.vlan_id;
- u16 old_vid = adapter->mng_vlan_id;
-
- if (!adapter->vlgrp)
- return;
+ struct e1000_hw *hw = &adapter->hw;
+ u32 rctl;
- if (!vlan_group_get_device(adapter->vlgrp, vid)) {
- adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
- if (adapter->hw.mng_cookie.status &
- E1000_MNG_DHCP_COOKIE_STATUS_VLAN) {
- e1000_vlan_rx_add_vid(netdev, vid);
- adapter->mng_vlan_id = vid;
+ if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) {
+ /* disable VLAN receive filtering */
+ rctl = er32(RCTL);
+ rctl &= ~(E1000_RCTL_VFE | E1000_RCTL_CFIEN);
+ ew32(RCTL, rctl);
+
+ if (adapter->mng_vlan_id != (u16)E1000_MNG_VLAN_NONE) {
+ e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
+ adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
}
-
- if ((old_vid != (u16)E1000_MNG_VLAN_NONE) &&
- (vid != old_vid) &&
- !vlan_group_get_device(adapter->vlgrp, old_vid))
- e1000_vlan_rx_kill_vid(netdev, old_vid);
- } else {
- adapter->mng_vlan_id = vid;
}
}
+/**
+ * e1000e_vlan_filter_enable - helper to enable HW VLAN filtering
+ * @adapter: board private structure to initialize
+ **/
+static void e1000e_vlan_filter_enable(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 rctl;
-static void e1000_vlan_rx_register(struct net_device *netdev,
- struct vlan_group *grp)
+ if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) {
+ /* enable VLAN receive filtering */
+ rctl = er32(RCTL);
+ rctl |= E1000_RCTL_VFE;
+ rctl &= ~E1000_RCTL_CFIEN;
+ ew32(RCTL, rctl);
+ }
+}
+
+/**
+ * e1000e_vlan_strip_enable - helper to disable HW VLAN stripping
+ * @adapter: board private structure to initialize
+ **/
+static void e1000e_vlan_strip_disable(struct e1000_adapter *adapter)
{
- struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
- u32 ctrl, rctl;
+ u32 ctrl;
- if (!test_bit(__E1000_DOWN, &adapter->state))
- e1000_irq_disable(adapter);
- adapter->vlgrp = grp;
+ /* disable VLAN tag insert/strip */
+ ctrl = er32(CTRL);
+ ctrl &= ~E1000_CTRL_VME;
+ ew32(CTRL, ctrl);
+}
- if (grp) {
- /* enable VLAN tag insert/strip */
- ctrl = er32(CTRL);
- ctrl |= E1000_CTRL_VME;
- ew32(CTRL, ctrl);
+/**
+ * e1000e_vlan_strip_enable - helper to enable HW VLAN stripping
+ * @adapter: board private structure to initialize
+ **/
+static void e1000e_vlan_strip_enable(struct e1000_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ u32 ctrl;
- if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) {
- /* enable VLAN receive filtering */
- rctl = er32(RCTL);
- rctl &= ~E1000_RCTL_CFIEN;
- ew32(RCTL, rctl);
- e1000_update_mng_vlan(adapter);
- }
- } else {
- /* disable VLAN tag insert/strip */
- ctrl = er32(CTRL);
- ctrl &= ~E1000_CTRL_VME;
- ew32(CTRL, ctrl);
+ /* enable VLAN tag insert/strip */
+ ctrl = er32(CTRL);
+ ctrl |= E1000_CTRL_VME;
+ ew32(CTRL, ctrl);
+}
- if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) {
- if (adapter->mng_vlan_id !=
- (u16)E1000_MNG_VLAN_NONE) {
- e1000_vlan_rx_kill_vid(netdev,
- adapter->mng_vlan_id);
- adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
- }
- }
+static void e1000_update_mng_vlan(struct e1000_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ u16 vid = adapter->hw.mng_cookie.vlan_id;
+ u16 old_vid = adapter->mng_vlan_id;
+
+ if (adapter->hw.mng_cookie.status &
+ E1000_MNG_DHCP_COOKIE_STATUS_VLAN) {
+ e1000_vlan_rx_add_vid(netdev, vid);
+ adapter->mng_vlan_id = vid;
}
- if (!test_bit(__E1000_DOWN, &adapter->state))
- e1000_irq_enable(adapter);
+ if ((old_vid != (u16)E1000_MNG_VLAN_NONE) && (vid != old_vid))
+ e1000_vlan_rx_kill_vid(netdev, old_vid);
}
static void e1000_restore_vlan(struct e1000_adapter *adapter)
{
u16 vid;
- e1000_vlan_rx_register(adapter->netdev, adapter->vlgrp);
-
- if (!adapter->vlgrp)
- return;
+ e1000_vlan_rx_add_vid(adapter->netdev, 0);
- for (vid = 0; vid < VLAN_N_VID; vid++) {
- if (!vlan_group_get_device(adapter->vlgrp, vid))
- continue;
+ for_each_set_bit(vid, adapter->active_vlans, VLAN_N_VID)
e1000_vlan_rx_add_vid(adapter->netdev, vid);
- }
}
static void e1000_init_manageability_pt(struct e1000_adapter *adapter)
@@ -2902,7 +2912,7 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
rctl = er32(RCTL);
ew32(RCTL, rctl & ~E1000_RCTL_EN);
e1e_flush();
- msleep(10);
+ usleep_range(10000, 20000);
if (adapter->flags2 & FLAG2_DMA_BURST) {
/*
@@ -3039,6 +3049,8 @@ static void e1000_set_multi(struct net_device *netdev)
if (netdev->flags & IFF_PROMISC) {
rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
rctl &= ~E1000_RCTL_VFE;
+ /* Do not hardware filter VLANs in promisc mode */
+ e1000e_vlan_filter_disable(adapter);
} else {
if (netdev->flags & IFF_ALLMULTI) {
rctl |= E1000_RCTL_MPE;
@@ -3046,8 +3058,7 @@ static void e1000_set_multi(struct net_device *netdev)
} else {
rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE);
}
- if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER)
- rctl |= E1000_RCTL_VFE;
+ e1000e_vlan_filter_enable(adapter);
}
ew32(RCTL, rctl);
@@ -3072,6 +3083,11 @@ static void e1000_set_multi(struct net_device *netdev)
*/
e1000_update_mc_addr_list(hw, NULL, 0);
}
+
+ if (netdev->features & NETIF_F_HW_VLAN_RX)
+ e1000e_vlan_strip_enable(adapter);
+ else
+ e1000e_vlan_strip_disable(adapter);
}
/**
@@ -3383,7 +3399,7 @@ void e1000e_down(struct e1000_adapter *adapter)
ew32(TCTL, tctl);
/* flush both disables and wait for them to finish */
e1e_flush();
- msleep(10);
+ usleep_range(10000, 20000);
napi_disable(&adapter->napi);
e1000_irq_disable(adapter);
@@ -3418,7 +3434,7 @@ void e1000e_reinit_locked(struct e1000_adapter *adapter)
{
might_sleep();
while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
- msleep(1);
+ usleep_range(1000, 2000);
e1000e_down(adapter);
e1000e_up(adapter);
clear_bit(__E1000_RESETTING, &adapter->state);
@@ -3721,10 +3737,8 @@ static int e1000_close(struct net_device *netdev)
* kill manageability vlan ID if supported, but not if a vlan with
* the same ID is registered on the host OS (let 8021q kill it)
*/
- if ((adapter->hw.mng_cookie.status &
- E1000_MNG_DHCP_COOKIE_STATUS_VLAN) &&
- !(adapter->vlgrp &&
- vlan_group_get_device(adapter->vlgrp, adapter->mng_vlan_id)))
+ if (adapter->hw.mng_cookie.status &
+ E1000_MNG_DHCP_COOKIE_STATUS_VLAN)
e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
/*
@@ -4328,7 +4342,6 @@ static void e1000_watchdog_task(struct work_struct *work)
link_up:
spin_lock(&adapter->stats64_lock);
e1000e_update_stats(adapter);
- spin_unlock(&adapter->stats64_lock);
mac->tx_packet_delta = adapter->stats.tpt - adapter->tpt_old;
adapter->tpt_old = adapter->stats.tpt;
@@ -4339,6 +4352,7 @@ link_up:
adapter->gorc_old = adapter->stats.gorc;
adapter->gotc = adapter->stats.gotc - adapter->gotc_old;
adapter->gotc_old = adapter->stats.gotc;
+ spin_unlock(&adapter->stats64_lock);
e1000e_update_adaptive(&adapter->hw);
@@ -5028,7 +5042,7 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu)
}
while (test_and_set_bit(__E1000_RESETTING, &adapter->state))
- msleep(1);
+ usleep_range(1000, 2000);
/* e1000e_down -> e1000e_reset dependent on max_frame_size & mtu */
adapter->max_frame_size = max_frame;
e_info("changing MTU from %d to %d\n", netdev->mtu, new_mtu);
@@ -5347,7 +5361,7 @@ static void e1000_complete_shutdown(struct pci_dev *pdev, bool sleep,
#ifdef CONFIG_PCIEASPM
static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
{
- pci_disable_link_state(pdev, state);
+ pci_disable_link_state_locked(pdev, state);
}
#else
static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
@@ -5373,7 +5387,7 @@ static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
pci_write_config_word(pdev->bus->self, pos + PCI_EXP_LNKCTL, reg16);
}
#endif
-void e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
+static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
{
dev_info(&pdev->dev, "Disabling ASPM %s %s\n",
(state & PCIE_LINK_STATE_L0S) ? "L0s" : "",
@@ -5393,13 +5407,19 @@ static int __e1000_resume(struct pci_dev *pdev)
struct net_device *netdev = pci_get_drvdata(pdev);
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
+ u16 aspm_disable_flag = 0;
u32 err;
+ if (adapter->flags2 & FLAG2_DISABLE_ASPM_L0S)
+ aspm_disable_flag = PCIE_LINK_STATE_L0S;
+ if (adapter->flags2 & FLAG2_DISABLE_ASPM_L1)
+ aspm_disable_flag |= PCIE_LINK_STATE_L1;
+ if (aspm_disable_flag)
+ e1000e_disable_aspm(pdev, aspm_disable_flag);
+
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
pci_save_state(pdev);
- if (adapter->flags2 & FLAG2_DISABLE_ASPM_L1)
- e1000e_disable_aspm(pdev, PCIE_LINK_STATE_L1);
e1000e_set_interrupt_capability(adapter);
if (netif_running(netdev)) {
@@ -5643,11 +5663,17 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)
struct net_device *netdev = pci_get_drvdata(pdev);
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
+ u16 aspm_disable_flag = 0;
int err;
pci_ers_result_t result;
+ if (adapter->flags2 & FLAG2_DISABLE_ASPM_L0S)
+ aspm_disable_flag = PCIE_LINK_STATE_L0S;
if (adapter->flags2 & FLAG2_DISABLE_ASPM_L1)
- e1000e_disable_aspm(pdev, PCIE_LINK_STATE_L1);
+ aspm_disable_flag |= PCIE_LINK_STATE_L1;
+ if (aspm_disable_flag)
+ e1000e_disable_aspm(pdev, aspm_disable_flag);
+
err = pci_enable_device_mem(pdev);
if (err) {
dev_err(&pdev->dev,
@@ -5714,7 +5740,7 @@ static void e1000_print_device_info(struct e1000_adapter *adapter)
u8 pba_str[E1000_PBANUM_LENGTH];
/* print bus type/speed/width info */
- e_info("(PCI Express:2.5GB/s:%s) %pM\n",
+ e_info("(PCI Express:2.5GT/s:%s) %pM\n",
/* bus width */
((hw->bus.width == e1000_bus_width_pcie_x4) ? "Width x4" :
"Width x1"),
@@ -5759,7 +5785,6 @@ static const struct net_device_ops e1000e_netdev_ops = {
.ndo_tx_timeout = e1000_tx_timeout,
.ndo_validate_addr = eth_validate_addr,
- .ndo_vlan_rx_register = e1000_vlan_rx_register,
.ndo_vlan_rx_add_vid = e1000_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = e1000_vlan_rx_kill_vid,
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -5789,12 +5814,17 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
resource_size_t flash_start, flash_len;
static int cards_found;
+ u16 aspm_disable_flag = 0;
int i, err, pci_using_dac;
u16 eeprom_data = 0;
u16 eeprom_apme_mask = E1000_EEPROM_APME;
+ if (ei->flags2 & FLAG2_DISABLE_ASPM_L0S)
+ aspm_disable_flag = PCIE_LINK_STATE_L0S;
if (ei->flags2 & FLAG2_DISABLE_ASPM_L1)
- e1000e_disable_aspm(pdev, PCIE_LINK_STATE_L1);
+ aspm_disable_flag |= PCIE_LINK_STATE_L1;
+ if (aspm_disable_flag)
+ e1000e_disable_aspm(pdev, aspm_disable_flag);
err = pci_enable_device_mem(pdev);
if (err)
@@ -5991,7 +6021,6 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
INIT_WORK(&adapter->downshift_task, e1000e_downshift_workaround);
INIT_WORK(&adapter->update_phy_task, e1000e_update_phy_task);
INIT_WORK(&adapter->print_hang_task, e1000_print_hw_hang);
- INIT_WORK(&adapter->led_blink_task, e1000e_led_blink_task);
/* Initialize link parameters. User can change them with ethtool */
adapter->hw.mac.autoneg = 1;
@@ -6124,7 +6153,6 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
cancel_work_sync(&adapter->watchdog_task);
cancel_work_sync(&adapter->downshift_task);
cancel_work_sync(&adapter->update_phy_task);
- cancel_work_sync(&adapter->led_blink_task);
cancel_work_sync(&adapter->print_hang_task);
if (!(netdev->flags & IFF_UP))
diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c
index 6ae31fcfb629..484774c13c21 100644
--- a/drivers/net/e1000e/phy.c
+++ b/drivers/net/e1000e/phy.c
@@ -2372,7 +2372,7 @@ s32 e1000e_determine_phy_address(struct e1000_hw *hw)
ret_val = 0;
goto out;
}
- msleep(1);
+ usleep_range(1000, 2000);
i++;
} while (i < 10);
}
@@ -2740,7 +2740,7 @@ void e1000_power_down_phy_copper(struct e1000_hw *hw)
e1e_rphy(hw, PHY_CONTROL, &mii_reg);
mii_reg |= MII_CR_POWER_DOWN;
e1e_wphy(hw, PHY_CONTROL, mii_reg);
- msleep(1);
+ usleep_range(1000, 2000);
}
/**
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index eb35951a2442..dfeb006035df 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -1703,7 +1703,7 @@ static int eepro_ethtool_get_settings(struct net_device *dev,
cmd->advertising |= ADVERTISED_AUI;
}
- cmd->speed = SPEED_10;
+ ethtool_cmd_speed_set(cmd, SPEED_10);
if (dev->if_port == TPE && lp->word[1] & ee_Duplex) {
cmd->duplex = DUPLEX_FULL;
diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c
index f3bbdcef338c..7f642aef5e82 100644
--- a/drivers/net/ehea/ehea_ethtool.c
+++ b/drivers/net/ehea/ehea_ethtool.c
@@ -34,6 +34,7 @@
static int ehea_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct ehea_port *port = netdev_priv(dev);
+ u32 speed;
int ret;
ret = ehea_sense_port_attr(port);
@@ -43,17 +44,29 @@ static int ehea_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
if (netif_carrier_ok(dev)) {
switch (port->port_speed) {
- case EHEA_SPEED_10M: cmd->speed = SPEED_10; break;
- case EHEA_SPEED_100M: cmd->speed = SPEED_100; break;
- case EHEA_SPEED_1G: cmd->speed = SPEED_1000; break;
- case EHEA_SPEED_10G: cmd->speed = SPEED_10000; break;
+ case EHEA_SPEED_10M:
+ speed = SPEED_10;
+ break;
+ case EHEA_SPEED_100M:
+ speed = SPEED_100;
+ break;
+ case EHEA_SPEED_1G:
+ speed = SPEED_1000;
+ break;
+ case EHEA_SPEED_10G:
+ speed = SPEED_10000;
+ break;
+ default:
+ speed = -1;
+ break; /* BUG */
}
cmd->duplex = port->full_duplex == 1 ?
DUPLEX_FULL : DUPLEX_HALF;
} else {
- cmd->speed = -1;
+ speed = ~0;
cmd->duplex = -1;
}
+ ethtool_cmd_speed_set(cmd, speed);
if (cmd->speed == SPEED_10000) {
cmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
@@ -167,11 +180,6 @@ static void ehea_set_msglevel(struct net_device *dev, u32 value)
port->msg_enable = value;
}
-static u32 ehea_get_rx_csum(struct net_device *dev)
-{
- return 1;
-}
-
static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = {
{"sig_comp_iv"},
{"swqe_refill_th"},
@@ -268,34 +276,16 @@ static void ehea_get_ethtool_stats(struct net_device *dev,
}
-static int ehea_set_flags(struct net_device *dev, u32 data)
-{
- /* Avoid changing the VLAN flags */
- if ((data & (ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN)) !=
- (ethtool_op_get_flags(dev) & (ETH_FLAG_RXVLAN |
- ETH_FLAG_TXVLAN))){
- return -EINVAL;
- }
-
- return ethtool_op_set_flags(dev, data, ETH_FLAG_LRO
- | ETH_FLAG_TXVLAN
- | ETH_FLAG_RXVLAN);
-}
-
const struct ethtool_ops ehea_ethtool_ops = {
.get_settings = ehea_get_settings,
.get_drvinfo = ehea_get_drvinfo,
.get_msglevel = ehea_get_msglevel,
.set_msglevel = ehea_set_msglevel,
.get_link = ethtool_op_get_link,
- .set_tso = ethtool_op_set_tso,
.get_strings = ehea_get_strings,
.get_sset_count = ehea_get_sset_count,
.get_ethtool_stats = ehea_get_ethtool_stats,
- .get_rx_csum = ehea_get_rx_csum,
.set_settings = ehea_set_settings,
- .get_flags = ethtool_op_get_flags,
- .set_flags = ehea_set_flags,
.nway_reset = ehea_nway_reset, /* Restart autonegotiation */
};
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index cf79cf759e13..3fd5a2400348 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -41,6 +41,7 @@
#include <linux/memory.h>
#include <asm/kexec.h>
#include <linux/mutex.h>
+#include <linux/prefetch.h>
#include <net/ip.h>
@@ -2082,7 +2083,7 @@ static void ehea_set_multicast_list(struct net_device *dev)
struct netdev_hw_addr *ha;
int ret;
- if (dev->flags & IFF_PROMISC) {
+ if (port->promisc) {
ehea_promiscuous(dev, 1);
return;
}
@@ -3262,10 +3263,12 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
dev->netdev_ops = &ehea_netdev_ops;
ehea_set_ethtool_ops(dev);
+ dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO
+ | NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX | NETIF_F_LRO;
dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO
| NETIF_F_HIGHDMA | NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX
| NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER
- | NETIF_F_LLTX;
+ | NETIF_F_LLTX | NETIF_F_RXCSUM;
dev->watchdog_timeo = EHEA_WATCH_DOG_TIMEOUT;
if (use_lro)
diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h
index 38104734a3be..fddff8ec8cfd 100644
--- a/drivers/net/ehea/ehea_qmr.h
+++ b/drivers/net/ehea/ehea_qmr.h
@@ -29,6 +29,7 @@
#ifndef __EHEA_QMR_H__
#define __EHEA_QMR_H__
+#include <linux/prefetch.h>
#include "ehea.h"
#include "ehea_hw.h"
diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c
index 907b05a1c659..2837ce209cd7 100644
--- a/drivers/net/enc28j60.c
+++ b/drivers/net/enc28j60.c
@@ -1488,7 +1488,7 @@ enc28j60_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->supported = SUPPORTED_10baseT_Half
| SUPPORTED_10baseT_Full
| SUPPORTED_TP;
- cmd->speed = SPEED_10;
+ ethtool_cmd_speed_set(cmd, SPEED_10);
cmd->duplex = priv->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
cmd->port = PORT_TP;
cmd->autoneg = AUTONEG_DISABLE;
@@ -1499,7 +1499,8 @@ enc28j60_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
static int
enc28j60_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
- return enc28j60_setlink(dev, cmd->autoneg, cmd->speed, cmd->duplex);
+ return enc28j60_setlink(dev, cmd->autoneg,
+ ethtool_cmd_speed(cmd), cmd->duplex);
}
static u32 enc28j60_get_msglevel(struct net_device *dev)
diff --git a/drivers/net/enic/Makefile b/drivers/net/enic/Makefile
index 2e573be16c13..9d4974bba247 100644
--- a/drivers/net/enic/Makefile
+++ b/drivers/net/enic/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_ENIC) := enic.o
enic-y := enic_main.o vnic_cq.o vnic_intr.o vnic_wq.o \
- enic_res.o enic_dev.o vnic_dev.o vnic_rq.o vnic_vic.o
+ enic_res.o enic_dev.o enic_pp.o vnic_dev.o vnic_rq.o vnic_vic.o
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index 3a3c3c8a3a9b..38b351c7b979 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -32,7 +32,7 @@
#define DRV_NAME "enic"
#define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver"
-#define DRV_VERSION "2.1.1.12"
+#define DRV_VERSION "2.1.1.13"
#define DRV_COPYRIGHT "Copyright 2008-2011 Cisco Systems, Inc"
#define ENIC_BARS_MAX 6
@@ -84,7 +84,6 @@ struct enic {
unsigned int flags;
unsigned int mc_count;
unsigned int uc_count;
- int csum_rx_enabled;
u32 port_mtu;
u32 rx_coalesce_usecs;
u32 tx_coalesce_usecs;
@@ -120,4 +119,6 @@ static inline struct device *enic_get_dev(struct enic *enic)
return &(enic->pdev->dev);
}
+void enic_reset_addr_lists(struct enic *enic);
+
#endif /* _ENIC_H_ */
diff --git a/drivers/net/enic/enic_dev.c b/drivers/net/enic/enic_dev.c
index 37ad3a1c82ee..90687b14e60f 100644
--- a/drivers/net/enic/enic_dev.c
+++ b/drivers/net/enic/enic_dev.c
@@ -177,24 +177,24 @@ int enic_vnic_dev_deinit(struct enic *enic)
return err;
}
-int enic_dev_init_prov(struct enic *enic, struct vic_provinfo *vp)
+int enic_dev_init_prov2(struct enic *enic, struct vic_provinfo *vp)
{
int err;
spin_lock(&enic->devcmd_lock);
- err = vnic_dev_init_prov(enic->vdev,
+ err = vnic_dev_init_prov2(enic->vdev,
(u8 *)vp, vic_provinfo_size(vp));
spin_unlock(&enic->devcmd_lock);
return err;
}
-int enic_dev_init_done(struct enic *enic, int *done, int *error)
+int enic_dev_deinit_done(struct enic *enic, int *status)
{
int err;
spin_lock(&enic->devcmd_lock);
- err = vnic_dev_init_done(enic->vdev, done, error);
+ err = vnic_dev_deinit_done(enic->vdev, status);
spin_unlock(&enic->devcmd_lock);
return err;
@@ -219,3 +219,57 @@ void enic_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
enic_del_vlan(enic, vid);
spin_unlock(&enic->devcmd_lock);
}
+
+int enic_dev_enable2(struct enic *enic, int active)
+{
+ int err;
+
+ spin_lock(&enic->devcmd_lock);
+ err = vnic_dev_enable2(enic->vdev, active);
+ spin_unlock(&enic->devcmd_lock);
+
+ return err;
+}
+
+int enic_dev_enable2_done(struct enic *enic, int *status)
+{
+ int err;
+
+ spin_lock(&enic->devcmd_lock);
+ err = vnic_dev_enable2_done(enic->vdev, status);
+ spin_unlock(&enic->devcmd_lock);
+
+ return err;
+}
+
+int enic_dev_status_to_errno(int devcmd_status)
+{
+ switch (devcmd_status) {
+ case ERR_SUCCESS:
+ return 0;
+ case ERR_EINVAL:
+ return -EINVAL;
+ case ERR_EFAULT:
+ return -EFAULT;
+ case ERR_EPERM:
+ return -EPERM;
+ case ERR_EBUSY:
+ return -EBUSY;
+ case ERR_ECMDUNKNOWN:
+ case ERR_ENOTSUPPORTED:
+ return -EOPNOTSUPP;
+ case ERR_EBADSTATE:
+ return -EINVAL;
+ case ERR_ENOMEM:
+ return -ENOMEM;
+ case ERR_ETIMEDOUT:
+ return -ETIMEDOUT;
+ case ERR_ELINKDOWN:
+ return -ENETDOWN;
+ case ERR_EINPROGRESS:
+ return -EINPROGRESS;
+ case ERR_EMAXRES:
+ default:
+ return (devcmd_status < 0) ? devcmd_status : -1;
+ }
+}
diff --git a/drivers/net/enic/enic_dev.h b/drivers/net/enic/enic_dev.h
index 495f57fcb887..d5f681337626 100644
--- a/drivers/net/enic/enic_dev.h
+++ b/drivers/net/enic/enic_dev.h
@@ -35,7 +35,10 @@ int enic_dev_set_ig_vlan_rewrite_mode(struct enic *enic);
int enic_dev_enable(struct enic *enic);
int enic_dev_disable(struct enic *enic);
int enic_vnic_dev_deinit(struct enic *enic);
-int enic_dev_init_prov(struct enic *enic, struct vic_provinfo *vp);
-int enic_dev_init_done(struct enic *enic, int *done, int *error);
+int enic_dev_init_prov2(struct enic *enic, struct vic_provinfo *vp);
+int enic_dev_deinit_done(struct enic *enic, int *status);
+int enic_dev_enable2(struct enic *enic, int arg);
+int enic_dev_enable2_done(struct enic *enic, int *status);
+int enic_dev_status_to_errno(int devcmd_status);
#endif /* _ENIC_DEV_H_ */
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index 8b9cad5e9712..2f433fbfca0c 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -35,6 +35,7 @@
#include <linux/ipv6.h>
#include <linux/tcp.h>
#include <linux/rtnetlink.h>
+#include <linux/prefetch.h>
#include <net/ip6_checksum.h>
#include "cq_enet_desc.h"
@@ -45,6 +46,7 @@
#include "enic_res.h"
#include "enic.h"
#include "enic_dev.h"
+#include "enic_pp.h"
#define ENIC_NOTIFY_TIMER_PERIOD (2 * HZ)
#define WQ_ENET_MAX_DESC_LEN (1 << WQ_ENET_LEN_BITS)
@@ -179,10 +181,10 @@ static int enic_get_settings(struct net_device *netdev,
ecmd->transceiver = XCVR_EXTERNAL;
if (netif_carrier_ok(netdev)) {
- ecmd->speed = vnic_dev_port_speed(enic->vdev);
+ ethtool_cmd_speed_set(ecmd, vnic_dev_port_speed(enic->vdev));
ecmd->duplex = DUPLEX_FULL;
} else {
- ecmd->speed = -1;
+ ethtool_cmd_speed_set(ecmd, -1);
ecmd->duplex = -1;
}
@@ -250,56 +252,6 @@ static void enic_get_ethtool_stats(struct net_device *netdev,
*(data++) = ((u64 *)&vstats->rx)[enic_rx_stats[i].offset];
}
-static u32 enic_get_rx_csum(struct net_device *netdev)
-{
- struct enic *enic = netdev_priv(netdev);
- return enic->csum_rx_enabled;
-}
-
-static int enic_set_rx_csum(struct net_device *netdev, u32 data)
-{
- struct enic *enic = netdev_priv(netdev);
-
- if (data && !ENIC_SETTING(enic, RXCSUM))
- return -EINVAL;
-
- enic->csum_rx_enabled = !!data;
-
- return 0;
-}
-
-static int enic_set_tx_csum(struct net_device *netdev, u32 data)
-{
- struct enic *enic = netdev_priv(netdev);
-
- if (data && !ENIC_SETTING(enic, TXCSUM))
- return -EINVAL;
-
- if (data)
- netdev->features |= NETIF_F_HW_CSUM;
- else
- netdev->features &= ~NETIF_F_HW_CSUM;
-
- return 0;
-}
-
-static int enic_set_tso(struct net_device *netdev, u32 data)
-{
- struct enic *enic = netdev_priv(netdev);
-
- if (data && !ENIC_SETTING(enic, TSO))
- return -EINVAL;
-
- if (data)
- netdev->features |=
- NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN;
- else
- netdev->features &=
- ~(NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN);
-
- return 0;
-}
-
static u32 enic_get_msglevel(struct net_device *netdev)
{
struct enic *enic = netdev_priv(netdev);
@@ -387,17 +339,8 @@ static const struct ethtool_ops enic_ethtool_ops = {
.get_strings = enic_get_strings,
.get_sset_count = enic_get_sset_count,
.get_ethtool_stats = enic_get_ethtool_stats,
- .get_rx_csum = enic_get_rx_csum,
- .set_rx_csum = enic_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = enic_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
- .set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
- .set_tso = enic_set_tso,
.get_coalesce = enic_get_coalesce,
.set_coalesce = enic_set_coalesce,
- .get_flags = ethtool_op_get_flags,
};
static void enic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf)
@@ -874,7 +817,7 @@ static struct net_device_stats *enic_get_stats(struct net_device *netdev)
return net_stats;
}
-static void enic_reset_addr_lists(struct enic *enic)
+void enic_reset_addr_lists(struct enic *enic)
{
enic->mc_count = 0;
enic->uc_count = 0;
@@ -1112,157 +1055,77 @@ static int enic_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
return -EINVAL;
}
-static int enic_set_port_profile(struct enic *enic, u8 *mac)
-{
- struct vic_provinfo *vp;
- u8 oui[3] = VIC_PROVINFO_CISCO_OUI;
- u16 os_type = VIC_GENERIC_PROV_OS_TYPE_LINUX;
- char uuid_str[38];
- char client_mac_str[18];
- u8 *client_mac;
- int err;
-
- err = enic_vnic_dev_deinit(enic);
- if (err)
- return err;
-
- enic_reset_addr_lists(enic);
-
- switch (enic->pp.request) {
-
- case PORT_REQUEST_ASSOCIATE:
-
- if (!(enic->pp.set & ENIC_SET_NAME) || !strlen(enic->pp.name))
- return -EINVAL;
-
- if (!is_valid_ether_addr(mac))
- return -EADDRNOTAVAIL;
-
- vp = vic_provinfo_alloc(GFP_KERNEL, oui,
- VIC_PROVINFO_GENERIC_TYPE);
- if (!vp)
- return -ENOMEM;
-
- vic_provinfo_add_tlv(vp,
- VIC_GENERIC_PROV_TLV_PORT_PROFILE_NAME_STR,
- strlen(enic->pp.name) + 1, enic->pp.name);
-
- if (!is_zero_ether_addr(enic->pp.mac_addr))
- client_mac = enic->pp.mac_addr;
- else
- client_mac = mac;
-
- vic_provinfo_add_tlv(vp,
- VIC_GENERIC_PROV_TLV_CLIENT_MAC_ADDR,
- ETH_ALEN, client_mac);
-
- sprintf(client_mac_str, "%pM", client_mac);
- vic_provinfo_add_tlv(vp,
- VIC_GENERIC_PROV_TLV_CLUSTER_PORT_UUID_STR,
- sizeof(client_mac_str), client_mac_str);
-
- if (enic->pp.set & ENIC_SET_INSTANCE) {
- sprintf(uuid_str, "%pUB", enic->pp.instance_uuid);
- vic_provinfo_add_tlv(vp,
- VIC_GENERIC_PROV_TLV_CLIENT_UUID_STR,
- sizeof(uuid_str), uuid_str);
- }
-
- if (enic->pp.set & ENIC_SET_HOST) {
- sprintf(uuid_str, "%pUB", enic->pp.host_uuid);
- vic_provinfo_add_tlv(vp,
- VIC_GENERIC_PROV_TLV_HOST_UUID_STR,
- sizeof(uuid_str), uuid_str);
- }
-
- os_type = htons(os_type);
- vic_provinfo_add_tlv(vp,
- VIC_GENERIC_PROV_TLV_OS_TYPE,
- sizeof(os_type), &os_type);
-
- err = enic_dev_init_prov(enic, vp);
- vic_provinfo_free(vp);
- if (err)
- return err;
- break;
-
- case PORT_REQUEST_DISASSOCIATE:
- break;
-
- default:
- return -EINVAL;
- }
-
- /* Set flag to indicate that the port assoc/disassoc
- * request has been sent out to fw
- */
- enic->pp.set |= ENIC_PORT_REQUEST_APPLIED;
-
- return 0;
-}
-
static int enic_set_vf_port(struct net_device *netdev, int vf,
struct nlattr *port[])
{
struct enic *enic = netdev_priv(netdev);
- struct enic_port_profile new_pp;
- int err = 0;
+ struct enic_port_profile prev_pp;
+ int err = 0, restore_pp = 1;
- memset(&new_pp, 0, sizeof(new_pp));
+ /* don't support VFs, yet */
+ if (vf != PORT_SELF_VF)
+ return -EOPNOTSUPP;
- if (port[IFLA_PORT_REQUEST]) {
- new_pp.set |= ENIC_SET_REQUEST;
- new_pp.request = nla_get_u8(port[IFLA_PORT_REQUEST]);
- }
+ if (!port[IFLA_PORT_REQUEST])
+ return -EOPNOTSUPP;
+
+ memcpy(&prev_pp, &enic->pp, sizeof(enic->pp));
+ memset(&enic->pp, 0, sizeof(enic->pp));
+
+ enic->pp.set |= ENIC_SET_REQUEST;
+ enic->pp.request = nla_get_u8(port[IFLA_PORT_REQUEST]);
if (port[IFLA_PORT_PROFILE]) {
- new_pp.set |= ENIC_SET_NAME;
- memcpy(new_pp.name, nla_data(port[IFLA_PORT_PROFILE]),
+ enic->pp.set |= ENIC_SET_NAME;
+ memcpy(enic->pp.name, nla_data(port[IFLA_PORT_PROFILE]),
PORT_PROFILE_MAX);
}
if (port[IFLA_PORT_INSTANCE_UUID]) {
- new_pp.set |= ENIC_SET_INSTANCE;
- memcpy(new_pp.instance_uuid,
+ enic->pp.set |= ENIC_SET_INSTANCE;
+ memcpy(enic->pp.instance_uuid,
nla_data(port[IFLA_PORT_INSTANCE_UUID]), PORT_UUID_MAX);
}
if (port[IFLA_PORT_HOST_UUID]) {
- new_pp.set |= ENIC_SET_HOST;
- memcpy(new_pp.host_uuid,
+ enic->pp.set |= ENIC_SET_HOST;
+ memcpy(enic->pp.host_uuid,
nla_data(port[IFLA_PORT_HOST_UUID]), PORT_UUID_MAX);
}
- /* don't support VFs, yet */
- if (vf != PORT_SELF_VF)
- return -EOPNOTSUPP;
-
- if (!(new_pp.set & ENIC_SET_REQUEST))
- return -EOPNOTSUPP;
-
- if (new_pp.request == PORT_REQUEST_ASSOCIATE) {
- /* Special case handling */
- if (!is_zero_ether_addr(enic->pp.vf_mac))
- memcpy(new_pp.mac_addr, enic->pp.vf_mac, ETH_ALEN);
+ /* Special case handling: mac came from IFLA_VF_MAC */
+ if (!is_zero_ether_addr(prev_pp.vf_mac))
+ memcpy(enic->pp.mac_addr, prev_pp.vf_mac, ETH_ALEN);
if (is_zero_ether_addr(netdev->dev_addr))
random_ether_addr(netdev->dev_addr);
- }
- memcpy(&enic->pp, &new_pp, sizeof(struct enic_port_profile));
+ err = enic_process_set_pp_request(enic, &prev_pp, &restore_pp);
+ if (err) {
+ if (restore_pp) {
+ /* Things are still the way they were: Implicit
+ * DISASSOCIATE failed
+ */
+ memcpy(&enic->pp, &prev_pp, sizeof(enic->pp));
+ } else {
+ memset(&enic->pp, 0, sizeof(enic->pp));
+ memset(netdev->dev_addr, 0, ETH_ALEN);
+ }
+ } else {
+ /* Set flag to indicate that the port assoc/disassoc
+ * request has been sent out to fw
+ */
+ enic->pp.set |= ENIC_PORT_REQUEST_APPLIED;
- err = enic_set_port_profile(enic, netdev->dev_addr);
- if (err)
- goto set_port_profile_cleanup;
+ /* If DISASSOCIATE, clean up all assigned/saved macaddresses */
+ if (enic->pp.request == PORT_REQUEST_DISASSOCIATE) {
+ memset(enic->pp.mac_addr, 0, ETH_ALEN);
+ memset(netdev->dev_addr, 0, ETH_ALEN);
+ }
+ }
-set_port_profile_cleanup:
memset(enic->pp.vf_mac, 0, ETH_ALEN);
- if (err || enic->pp.request == PORT_REQUEST_DISASSOCIATE) {
- memset(netdev->dev_addr, 0, ETH_ALEN);
- memset(enic->pp.mac_addr, 0, ETH_ALEN);
- }
-
return err;
}
@@ -1270,34 +1133,15 @@ static int enic_get_vf_port(struct net_device *netdev, int vf,
struct sk_buff *skb)
{
struct enic *enic = netdev_priv(netdev);
- int err, error, done;
u16 response = PORT_PROFILE_RESPONSE_SUCCESS;
+ int err;
if (!(enic->pp.set & ENIC_PORT_REQUEST_APPLIED))
return -ENODATA;
- err = enic_dev_init_done(enic, &done, &error);
+ err = enic_process_get_pp_request(enic, enic->pp.request, &response);
if (err)
- error = err;
-
- switch (error) {
- case ERR_SUCCESS:
- if (!done)
- response = PORT_PROFILE_RESPONSE_INPROGRESS;
- break;
- case ERR_EINVAL:
- response = PORT_PROFILE_RESPONSE_INVALID;
- break;
- case ERR_EBADSTATE:
- response = PORT_PROFILE_RESPONSE_BADSTATE;
- break;
- case ERR_ENOMEM:
- response = PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES;
- break;
- default:
- response = PORT_PROFILE_RESPONSE_ERROR;
- break;
- }
+ return err;
NLA_PUT_U16(skb, IFLA_PORT_REQUEST, enic->pp.request);
NLA_PUT_U16(skb, IFLA_PORT_RESPONSE, response);
@@ -1407,7 +1251,7 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq,
skb_put(skb, bytes_written);
skb->protocol = eth_type_trans(skb, netdev);
- if (enic->csum_rx_enabled && !csum_not_calc) {
+ if ((netdev->features & NETIF_F_RXCSUM) && !csum_not_calc) {
skb->csum = htons(checksum);
skb->ip_summed = CHECKSUM_COMPLETE;
}
@@ -2536,17 +2380,18 @@ static int __devinit enic_probe(struct pci_dev *pdev,
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;
+ netdev->hw_features |= NETIF_F_SG | NETIF_F_HW_CSUM;
if (ENIC_SETTING(enic, TSO))
- netdev->features |= NETIF_F_TSO |
+ netdev->hw_features |= NETIF_F_TSO |
NETIF_F_TSO6 | NETIF_F_TSO_ECN;
- if (ENIC_SETTING(enic, LRO))
- netdev->features |= NETIF_F_GRO;
+ if (ENIC_SETTING(enic, RXCSUM))
+ netdev->hw_features |= NETIF_F_RXCSUM;
+
+ netdev->features |= netdev->hw_features;
+
if (using_dac)
netdev->features |= NETIF_F_HIGHDMA;
- enic->csum_rx_enabled = ENIC_SETTING(enic, RXCSUM);
-
err = register_netdev(netdev);
if (err) {
dev_err(dev, "Cannot register net device, aborting\n");
diff --git a/drivers/net/enic/enic_pp.c b/drivers/net/enic/enic_pp.c
new file mode 100644
index 000000000000..ffaa75dd1ded
--- /dev/null
+++ b/drivers/net/enic/enic_pp.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2011 Cisco Systems, Inc. All rights reserved.
+ *
+ * This program is free software; you may 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <net/ip.h>
+
+#include "vnic_vic.h"
+#include "enic_res.h"
+#include "enic.h"
+#include "enic_dev.h"
+
+static int enic_set_port_profile(struct enic *enic)
+{
+ struct net_device *netdev = enic->netdev;
+ struct vic_provinfo *vp;
+ const u8 oui[3] = VIC_PROVINFO_CISCO_OUI;
+ const u16 os_type = htons(VIC_GENERIC_PROV_OS_TYPE_LINUX);
+ char uuid_str[38];
+ char client_mac_str[18];
+ u8 *client_mac;
+ int err;
+
+ if (!(enic->pp.set & ENIC_SET_NAME) || !strlen(enic->pp.name))
+ return -EINVAL;
+
+ vp = vic_provinfo_alloc(GFP_KERNEL, oui,
+ VIC_PROVINFO_GENERIC_TYPE);
+ if (!vp)
+ return -ENOMEM;
+
+ VIC_PROVINFO_ADD_TLV(vp,
+ VIC_GENERIC_PROV_TLV_PORT_PROFILE_NAME_STR,
+ strlen(enic->pp.name) + 1, enic->pp.name);
+
+ if (!is_zero_ether_addr(enic->pp.mac_addr))
+ client_mac = enic->pp.mac_addr;
+ else
+ client_mac = netdev->dev_addr;
+
+ VIC_PROVINFO_ADD_TLV(vp,
+ VIC_GENERIC_PROV_TLV_CLIENT_MAC_ADDR,
+ ETH_ALEN, client_mac);
+
+ snprintf(client_mac_str, sizeof(client_mac_str), "%pM", client_mac);
+ VIC_PROVINFO_ADD_TLV(vp,
+ VIC_GENERIC_PROV_TLV_CLUSTER_PORT_UUID_STR,
+ sizeof(client_mac_str), client_mac_str);
+
+ if (enic->pp.set & ENIC_SET_INSTANCE) {
+ sprintf(uuid_str, "%pUB", enic->pp.instance_uuid);
+ VIC_PROVINFO_ADD_TLV(vp,
+ VIC_GENERIC_PROV_TLV_CLIENT_UUID_STR,
+ sizeof(uuid_str), uuid_str);
+ }
+
+ if (enic->pp.set & ENIC_SET_HOST) {
+ sprintf(uuid_str, "%pUB", enic->pp.host_uuid);
+ VIC_PROVINFO_ADD_TLV(vp,
+ VIC_GENERIC_PROV_TLV_HOST_UUID_STR,
+ sizeof(uuid_str), uuid_str);
+ }
+
+ VIC_PROVINFO_ADD_TLV(vp,
+ VIC_GENERIC_PROV_TLV_OS_TYPE,
+ sizeof(os_type), &os_type);
+
+ err = enic_dev_status_to_errno(enic_dev_init_prov2(enic, vp));
+
+add_tlv_failure:
+ vic_provinfo_free(vp);
+
+ return err;
+}
+
+static int enic_unset_port_profile(struct enic *enic)
+{
+ int err;
+
+ err = enic_vnic_dev_deinit(enic);
+ if (err)
+ return enic_dev_status_to_errno(err);
+
+ enic_reset_addr_lists(enic);
+
+ return 0;
+}
+
+static int enic_are_pp_different(struct enic_port_profile *pp1,
+ struct enic_port_profile *pp2)
+{
+ return strcmp(pp1->name, pp2->name) | !!memcmp(pp1->instance_uuid,
+ pp2->instance_uuid, PORT_UUID_MAX) |
+ !!memcmp(pp1->host_uuid, pp2->host_uuid, PORT_UUID_MAX) |
+ !!memcmp(pp1->mac_addr, pp2->mac_addr, ETH_ALEN);
+}
+
+static int enic_pp_preassociate(struct enic *enic,
+ struct enic_port_profile *prev_pp, int *restore_pp);
+static int enic_pp_disassociate(struct enic *enic,
+ struct enic_port_profile *prev_pp, int *restore_pp);
+static int enic_pp_preassociate_rr(struct enic *enic,
+ struct enic_port_profile *prev_pp, int *restore_pp);
+static int enic_pp_associate(struct enic *enic,
+ struct enic_port_profile *prev_pp, int *restore_pp);
+
+static int (*enic_pp_handlers[])(struct enic *enic,
+ struct enic_port_profile *prev_state, int *restore_pp) = {
+ [PORT_REQUEST_PREASSOCIATE] = enic_pp_preassociate,
+ [PORT_REQUEST_PREASSOCIATE_RR] = enic_pp_preassociate_rr,
+ [PORT_REQUEST_ASSOCIATE] = enic_pp_associate,
+ [PORT_REQUEST_DISASSOCIATE] = enic_pp_disassociate,
+};
+
+static const int enic_pp_handlers_count =
+ sizeof(enic_pp_handlers)/sizeof(*enic_pp_handlers);
+
+static int enic_pp_preassociate(struct enic *enic,
+ struct enic_port_profile *prev_pp, int *restore_pp)
+{
+ return -EOPNOTSUPP;
+}
+
+static int enic_pp_disassociate(struct enic *enic,
+ struct enic_port_profile *prev_pp, int *restore_pp)
+{
+ return enic_unset_port_profile(enic);
+}
+
+static int enic_pp_preassociate_rr(struct enic *enic,
+ struct enic_port_profile *prev_pp, int *restore_pp)
+{
+ int err;
+ int active = 0;
+
+ if (enic->pp.request != PORT_REQUEST_ASSOCIATE) {
+ /* If pre-associate is not part of an associate.
+ We always disassociate first */
+ err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE](enic,
+ prev_pp, restore_pp);
+ if (err)
+ return err;
+
+ *restore_pp = 0;
+ }
+
+ *restore_pp = 0;
+
+ err = enic_set_port_profile(enic);
+ if (err)
+ return err;
+
+ /* If pre-associate is not part of an associate. */
+ if (enic->pp.request != PORT_REQUEST_ASSOCIATE)
+ err = enic_dev_status_to_errno(enic_dev_enable2(enic, active));
+
+ return err;
+}
+
+static int enic_pp_associate(struct enic *enic,
+ struct enic_port_profile *prev_pp, int *restore_pp)
+{
+ int err;
+ int active = 1;
+
+ /* Check if a pre-associate was called before */
+ if (prev_pp->request != PORT_REQUEST_PREASSOCIATE_RR ||
+ (prev_pp->request == PORT_REQUEST_PREASSOCIATE_RR &&
+ enic_are_pp_different(prev_pp, &enic->pp))) {
+ err = enic_pp_handlers[PORT_REQUEST_DISASSOCIATE](
+ enic, prev_pp, restore_pp);
+ if (err)
+ return err;
+
+ *restore_pp = 0;
+ }
+
+ err = enic_pp_handlers[PORT_REQUEST_PREASSOCIATE_RR](
+ enic, prev_pp, restore_pp);
+ if (err)
+ return err;
+
+ *restore_pp = 0;
+
+ return enic_dev_status_to_errno(enic_dev_enable2(enic, active));
+}
+
+int enic_process_set_pp_request(struct enic *enic,
+ struct enic_port_profile *prev_pp, int *restore_pp)
+{
+ if (enic->pp.request < enic_pp_handlers_count
+ && enic_pp_handlers[enic->pp.request])
+ return enic_pp_handlers[enic->pp.request](enic,
+ prev_pp, restore_pp);
+ else
+ return -EOPNOTSUPP;
+}
+
+int enic_process_get_pp_request(struct enic *enic, int request,
+ u16 *response)
+{
+ int err, status = ERR_SUCCESS;
+
+ switch (request) {
+
+ case PORT_REQUEST_PREASSOCIATE_RR:
+ case PORT_REQUEST_ASSOCIATE:
+ err = enic_dev_enable2_done(enic, &status);
+ break;
+
+ case PORT_REQUEST_DISASSOCIATE:
+ err = enic_dev_deinit_done(enic, &status);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (err)
+ status = err;
+
+ switch (status) {
+ case ERR_SUCCESS:
+ *response = PORT_PROFILE_RESPONSE_SUCCESS;
+ break;
+ case ERR_EINVAL:
+ *response = PORT_PROFILE_RESPONSE_INVALID;
+ break;
+ case ERR_EBADSTATE:
+ *response = PORT_PROFILE_RESPONSE_BADSTATE;
+ break;
+ case ERR_ENOMEM:
+ *response = PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES;
+ break;
+ case ERR_EINPROGRESS:
+ *response = PORT_PROFILE_RESPONSE_INPROGRESS;
+ break;
+ default:
+ *response = PORT_PROFILE_RESPONSE_ERROR;
+ break;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/enic/enic_pp.h b/drivers/net/enic/enic_pp.h
new file mode 100644
index 000000000000..699e365a944d
--- /dev/null
+++ b/drivers/net/enic/enic_pp.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2011 Cisco Systems, Inc. All rights reserved.
+ *
+ * This program is free software; you may 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.
+ *
+ * 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 _ENIC_PP_H_
+#define _ENIC_PP_H_
+
+int enic_process_set_pp_request(struct enic *enic,
+ struct enic_port_profile *prev_pp, int *restore_pp);
+int enic_process_get_pp_request(struct enic *enic, int request,
+ u16 *response);
+
+#endif /* _ENIC_PP_H_ */
diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c
index f111a37419ce..6e5c6356e7df 100644
--- a/drivers/net/enic/enic_res.c
+++ b/drivers/net/enic/enic_res.c
@@ -98,9 +98,9 @@ int enic_get_vnic_config(struct enic *enic)
"vNIC MAC addr %pM wq/rq %d/%d mtu %d\n",
enic->mac_addr, c->wq_desc_count, c->rq_desc_count, c->mtu);
dev_info(enic_get_dev(enic), "vNIC csum tx/rx %d/%d "
- "tso/lro %d/%d intr timer %d usec rss %d\n",
+ "tso %d intr timer %d usec rss %d\n",
ENIC_SETTING(enic, TXCSUM), ENIC_SETTING(enic, RXCSUM),
- ENIC_SETTING(enic, TSO), ENIC_SETTING(enic, LRO),
+ ENIC_SETTING(enic, TSO),
c->intr_timer_usec, ENIC_SETTING(enic, RSS));
return 0;
diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c
index c089b362a36f..68f24ae860ae 100644
--- a/drivers/net/enic/vnic_dev.c
+++ b/drivers/net/enic/vnic_dev.c
@@ -786,48 +786,6 @@ int vnic_dev_init(struct vnic_dev *vdev, int arg)
return r;
}
-int vnic_dev_init_done(struct vnic_dev *vdev, int *done, int *err)
-{
- u64 a0 = 0, a1 = 0;
- int wait = 1000;
- int ret;
-
- *done = 0;
-
- ret = vnic_dev_cmd(vdev, CMD_INIT_STATUS, &a0, &a1, wait);
- if (ret)
- return ret;
-
- *done = (a0 == 0);
-
- *err = (a0 == 0) ? (int)a1:0;
-
- return 0;
-}
-
-int vnic_dev_init_prov(struct vnic_dev *vdev, u8 *buf, u32 len)
-{
- u64 a0, a1 = len;
- int wait = 1000;
- dma_addr_t prov_pa;
- void *prov_buf;
- int ret;
-
- prov_buf = pci_alloc_consistent(vdev->pdev, len, &prov_pa);
- if (!prov_buf)
- return -ENOMEM;
-
- memcpy(prov_buf, buf, len);
-
- a0 = prov_pa;
-
- ret = vnic_dev_cmd(vdev, CMD_INIT_PROV_INFO, &a0, &a1, wait);
-
- pci_free_consistent(vdev->pdev, len, prov_buf, prov_pa);
-
- return ret;
-}
-
int vnic_dev_deinit(struct vnic_dev *vdev)
{
u64 a0 = 0, a1 = 0;
@@ -927,4 +885,59 @@ err_out:
return NULL;
}
+int vnic_dev_init_prov2(struct vnic_dev *vdev, u8 *buf, u32 len)
+{
+ u64 a0, a1 = len;
+ int wait = 1000;
+ dma_addr_t prov_pa;
+ void *prov_buf;
+ int ret;
+
+ prov_buf = pci_alloc_consistent(vdev->pdev, len, &prov_pa);
+ if (!prov_buf)
+ return -ENOMEM;
+ memcpy(prov_buf, buf, len);
+
+ a0 = prov_pa;
+
+ ret = vnic_dev_cmd(vdev, CMD_INIT_PROV_INFO2, &a0, &a1, wait);
+
+ pci_free_consistent(vdev->pdev, len, prov_buf, prov_pa);
+
+ return ret;
+}
+
+int vnic_dev_enable2(struct vnic_dev *vdev, int active)
+{
+ u64 a0, a1 = 0;
+ int wait = 1000;
+
+ a0 = (active ? CMD_ENABLE2_ACTIVE : 0);
+
+ return vnic_dev_cmd(vdev, CMD_ENABLE2, &a0, &a1, wait);
+}
+
+static int vnic_dev_cmd_status(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
+ int *status)
+{
+ u64 a0 = cmd, a1 = 0;
+ int wait = 1000;
+ int ret;
+
+ ret = vnic_dev_cmd(vdev, CMD_STATUS, &a0, &a1, wait);
+ if (!ret)
+ *status = (int)a0;
+
+ return ret;
+}
+
+int vnic_dev_enable2_done(struct vnic_dev *vdev, int *status)
+{
+ return vnic_dev_cmd_status(vdev, CMD_ENABLE2, status);
+}
+
+int vnic_dev_deinit_done(struct vnic_dev *vdev, int *status)
+{
+ return vnic_dev_cmd_status(vdev, CMD_DEINIT, status);
+}
diff --git a/drivers/net/enic/vnic_dev.h b/drivers/net/enic/vnic_dev.h
index e837546213a8..cf482a2c9dd9 100644
--- a/drivers/net/enic/vnic_dev.h
+++ b/drivers/net/enic/vnic_dev.h
@@ -108,8 +108,6 @@ 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);
int vnic_dev_init(struct vnic_dev *vdev, int arg);
-int vnic_dev_init_done(struct vnic_dev *vdev, int *done, int *err);
-int vnic_dev_init_prov(struct vnic_dev *vdev, u8 *buf, u32 len);
int vnic_dev_deinit(struct vnic_dev *vdev);
int vnic_dev_hang_reset(struct vnic_dev *vdev, int arg);
int vnic_dev_hang_reset_done(struct vnic_dev *vdev, int *done);
@@ -122,5 +120,9 @@ int vnic_dev_set_ig_vlan_rewrite_mode(struct vnic_dev *vdev,
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);
+int vnic_dev_init_prov2(struct vnic_dev *vdev, u8 *buf, u32 len);
+int vnic_dev_enable2(struct vnic_dev *vdev, int active);
+int vnic_dev_enable2_done(struct vnic_dev *vdev, int *status);
+int vnic_dev_deinit_done(struct vnic_dev *vdev, int *status);
#endif /* _VNIC_DEV_H_ */
diff --git a/drivers/net/enic/vnic_devcmd.h b/drivers/net/enic/vnic_devcmd.h
index d833a071bac5..c5569bfb47ac 100644
--- a/drivers/net/enic/vnic_devcmd.h
+++ b/drivers/net/enic/vnic_devcmd.h
@@ -267,17 +267,62 @@ enum vnic_devcmd_cmd {
/*
* As for BY_BDF except a0 is index of hvnlink subordinate vnic
- * or SR-IOV virtual vnic */
+ * or SR-IOV virtual vnic
+ */
CMD_PROXY_BY_INDEX = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 43),
/*
- * in: (u64)a0=paddr of buffer to put latest VIC VIF-CONFIG-INFO TLV in
- * (u32)a1=length of buffer in a0
- * out: (u64)a0=paddr of buffer with latest VIC VIF-CONFIG-INFO TLV
- * (u32)a1=actual length of latest VIC VIF-CONFIG-INFO TLV */
+ * For HPP toggle:
+ * adapter-info-get
+ * in: (u64)a0=phsical address of buffer passed in from caller.
+ * (u16)a1=size of buffer specified in a0.
+ * out: (u64)a0=phsical address of buffer passed in from caller.
+ * (u16)a1=actual bytes from VIF-CONFIG-INFO TLV, or
+ * 0 if no VIF-CONFIG-INFO TLV was ever received. */
CMD_CONFIG_INFO_GET = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 44),
+
+ /* init_prov_info2:
+ * Variant of CMD_INIT_PROV_INFO, where it will not try to enable
+ * the vnic until CMD_ENABLE2 is issued.
+ * (u64)a0=paddr of vnic_devcmd_provinfo
+ * (u32)a1=sizeof provision info */
+ CMD_INIT_PROV_INFO2 = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 47),
+
+ /* enable2:
+ * (u32)a0=0 ==> standby
+ * =CMD_ENABLE2_ACTIVE ==> active
+ */
+ CMD_ENABLE2 = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 48),
+
+ /*
+ * cmd_status:
+ * Returns the status of the specified command
+ * Input:
+ * a0 = command for which status is being queried.
+ * Possible values are:
+ * CMD_SOFT_RESET
+ * CMD_HANG_RESET
+ * CMD_OPEN
+ * CMD_INIT
+ * CMD_INIT_PROV_INFO
+ * CMD_DEINIT
+ * CMD_INIT_PROV_INFO2
+ * CMD_ENABLE2
+ * Output:
+ * if status == STAT_ERROR
+ * a0 = ERR_ENOTSUPPORTED - status for command in a0 is
+ * not supported
+ * if status == STAT_NONE
+ * a0 = status of the devcmd specified in a0 as follows.
+ * ERR_SUCCESS - command in a0 completed successfully
+ * ERR_EINPROGRESS - command in a0 is still in progress
+ */
+ CMD_STATUS = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 49),
};
+/* CMD_ENABLE2 flags */
+#define CMD_ENABLE2_ACTIVE 0x1
+
/* flags for CMD_OPEN */
#define CMD_OPENF_OPROM 0x1 /* open coming from option rom */
@@ -315,6 +360,8 @@ enum vnic_devcmd_error {
ERR_ETIMEDOUT = 8,
ERR_ELINKDOWN = 9,
ERR_EMAXRES = 10,
+ ERR_ENOTSUPPORTED = 11,
+ ERR_EINPROGRESS = 12,
};
/*
diff --git a/drivers/net/enic/vnic_vic.c b/drivers/net/enic/vnic_vic.c
index 4725b79de0ef..24ef8cd40545 100644
--- a/drivers/net/enic/vnic_vic.c
+++ b/drivers/net/enic/vnic_vic.c
@@ -23,7 +23,8 @@
#include "vnic_vic.h"
-struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, u8 *oui, u8 type)
+struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, const u8 *oui,
+ const u8 type)
{
struct vic_provinfo *vp;
@@ -47,7 +48,7 @@ void vic_provinfo_free(struct vic_provinfo *vp)
}
int vic_provinfo_add_tlv(struct vic_provinfo *vp, u16 type, u16 length,
- void *value)
+ const void *value)
{
struct vic_provinfo_tlv *tlv;
diff --git a/drivers/net/enic/vnic_vic.h b/drivers/net/enic/vnic_vic.h
index f700f5d9e81d..9ef81f148351 100644
--- a/drivers/net/enic/vnic_vic.h
+++ b/drivers/net/enic/vnic_vic.h
@@ -47,6 +47,7 @@ enum vic_generic_prov_os_type {
VIC_GENERIC_PROV_OS_TYPE_ESX = 1,
VIC_GENERIC_PROV_OS_TYPE_LINUX = 2,
VIC_GENERIC_PROV_OS_TYPE_WINDOWS = 3,
+ VIC_GENERIC_PROV_OS_TYPE_SOLARIS = 4,
};
struct vic_provinfo {
@@ -61,14 +62,22 @@ struct vic_provinfo {
} tlv[0];
} __packed;
+#define VIC_PROVINFO_ADD_TLV(vp, tlvtype, tlvlen, data) \
+ do { \
+ err = vic_provinfo_add_tlv(vp, tlvtype, tlvlen, data); \
+ if (err) \
+ goto add_tlv_failure; \
+ } while (0)
+
#define VIC_PROVINFO_MAX_DATA 1385
#define VIC_PROVINFO_MAX_TLV_DATA (VIC_PROVINFO_MAX_DATA - \
sizeof(struct vic_provinfo))
-struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, u8 *oui, u8 type);
+struct vic_provinfo *vic_provinfo_alloc(gfp_t flags, const u8 *oui,
+ const u8 type);
void vic_provinfo_free(struct vic_provinfo *vp);
int vic_provinfo_add_tlv(struct vic_provinfo *vp, u16 type, u16 length,
- void *value);
+ const void *value);
size_t vic_provinfo_size(struct vic_provinfo *vp);
#endif /* _VNIC_VIC_H_ */
diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
index 380d0614a89a..b5f6173130f4 100644
--- a/drivers/net/ewrk3.c
+++ b/drivers/net/ewrk3.c
@@ -1545,7 +1545,7 @@ static int ewrk3_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
}
ecmd->supported |= SUPPORTED_10baseT_Half;
- ecmd->speed = SPEED_10;
+ ethtool_cmd_speed_set(ecmd, SPEED_10);
ecmd->duplex = DUPLEX_HALF;
return 0;
}
@@ -1604,55 +1604,47 @@ static u32 ewrk3_get_link(struct net_device *dev)
return !(cmr & CMR_LINK);
}
-static int ewrk3_phys_id(struct net_device *dev, u32 data)
+static int ewrk3_set_phys_id(struct net_device *dev,
+ enum ethtool_phys_id_state state)
{
struct ewrk3_private *lp = netdev_priv(dev);
unsigned long iobase = dev->base_addr;
- unsigned long flags;
u8 cr;
- int count;
-
- /* Toggle LED 4x per second */
- count = data << 2;
- spin_lock_irqsave(&lp->hw_lock, flags);
-
- /* Bail if a PHYS_ID is already in progress */
- if (lp->led_mask == 0) {
- spin_unlock_irqrestore(&lp->hw_lock, flags);
- return -EBUSY;
- }
+ spin_lock_irq(&lp->hw_lock);
- /* Prevent ISR from twiddling the LED */
- lp->led_mask = 0;
+ switch (state) {
+ case ETHTOOL_ID_ACTIVE:
+ /* Prevent ISR from twiddling the LED */
+ lp->led_mask = 0;
+ spin_unlock_irq(&lp->hw_lock);
+ return 2; /* cycle on/off twice per second */
- while (count--) {
- /* Toggle the LED */
+ case ETHTOOL_ID_ON:
cr = inb(EWRK3_CR);
- outb(cr ^ CR_LED, EWRK3_CR);
+ outb(cr | CR_LED, EWRK3_CR);
+ break;
- /* Wait a little while */
- spin_unlock_irqrestore(&lp->hw_lock, flags);
- msleep(250);
- spin_lock_irqsave(&lp->hw_lock, flags);
+ case ETHTOOL_ID_OFF:
+ cr = inb(EWRK3_CR);
+ outb(cr & ~CR_LED, EWRK3_CR);
+ break;
- /* Exit if we got a signal */
- if (signal_pending(current))
- break;
+ case ETHTOOL_ID_INACTIVE:
+ lp->led_mask = CR_LED;
+ cr = inb(EWRK3_CR);
+ outb(cr & ~CR_LED, EWRK3_CR);
}
+ spin_unlock_irq(&lp->hw_lock);
- lp->led_mask = CR_LED;
- cr = inb(EWRK3_CR);
- outb(cr & ~CR_LED, EWRK3_CR);
- spin_unlock_irqrestore(&lp->hw_lock, flags);
- return signal_pending(current) ? -ERESTARTSYS : 0;
+ return 0;
}
static const struct ethtool_ops ethtool_ops_203 = {
.get_drvinfo = ewrk3_get_drvinfo,
.get_settings = ewrk3_get_settings,
.set_settings = ewrk3_set_settings,
- .phys_id = ewrk3_phys_id,
+ .set_phys_id = ewrk3_set_phys_id,
};
static const struct ethtool_ops ethtool_ops = {
@@ -1660,7 +1652,7 @@ static const struct ethtool_ops ethtool_ops = {
.get_settings = ewrk3_get_settings,
.set_settings = ewrk3_set_settings,
.get_link = ewrk3_get_link,
- .phys_id = ewrk3_phys_id,
+ .set_phys_id = ewrk3_set_phys_id,
};
/*
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index d5ab4dad5051..537b6957bb79 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -64,6 +64,7 @@
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
+#include <linux/prefetch.h>
#include <linux/io.h>
#include <asm/irq.h>
@@ -774,7 +775,6 @@ struct fe_priv {
u32 driver_data;
u32 device_id;
u32 register_size;
- int rx_csum;
u32 mac_in_use;
int mgmt_version;
int mgmt_sema;
@@ -3956,6 +3956,7 @@ static int nv_set_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo)
static int nv_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
{
struct fe_priv *np = netdev_priv(dev);
+ u32 speed;
int adv;
spin_lock_irq(&np->lock);
@@ -3975,23 +3976,26 @@ static int nv_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
if (netif_carrier_ok(dev)) {
switch (np->linkspeed & (NVREG_LINKSPEED_MASK)) {
case NVREG_LINKSPEED_10:
- ecmd->speed = SPEED_10;
+ speed = SPEED_10;
break;
case NVREG_LINKSPEED_100:
- ecmd->speed = SPEED_100;
+ speed = SPEED_100;
break;
case NVREG_LINKSPEED_1000:
- ecmd->speed = SPEED_1000;
+ speed = SPEED_1000;
+ break;
+ default:
+ speed = -1;
break;
}
ecmd->duplex = DUPLEX_HALF;
if (np->duplex)
ecmd->duplex = DUPLEX_FULL;
} else {
- ecmd->speed = -1;
+ speed = -1;
ecmd->duplex = -1;
}
-
+ ethtool_cmd_speed_set(ecmd, speed);
ecmd->autoneg = np->autoneg;
ecmd->advertising = ADVERTISED_MII;
@@ -4030,6 +4034,7 @@ static int nv_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
{
struct fe_priv *np = netdev_priv(dev);
+ u32 speed = ethtool_cmd_speed(ecmd);
if (ecmd->port != PORT_MII)
return -EINVAL;
@@ -4055,7 +4060,7 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
/* Note: autonegotiation disable, speed 1000 intentionally
* forbidden - no one should need that. */
- if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100)
+ if (speed != SPEED_10 && speed != SPEED_100)
return -EINVAL;
if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
return -EINVAL;
@@ -4139,13 +4144,13 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ);
adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
- if (ecmd->speed == SPEED_10 && ecmd->duplex == DUPLEX_HALF)
+ if (speed == SPEED_10 && ecmd->duplex == DUPLEX_HALF)
adv |= ADVERTISE_10HALF;
- if (ecmd->speed == SPEED_10 && ecmd->duplex == DUPLEX_FULL)
+ if (speed == SPEED_10 && ecmd->duplex == DUPLEX_FULL)
adv |= ADVERTISE_10FULL;
- if (ecmd->speed == SPEED_100 && ecmd->duplex == DUPLEX_HALF)
+ if (speed == SPEED_100 && ecmd->duplex == DUPLEX_HALF)
adv |= ADVERTISE_100HALF;
- if (ecmd->speed == SPEED_100 && ecmd->duplex == DUPLEX_FULL)
+ if (speed == SPEED_100 && ecmd->duplex == DUPLEX_FULL)
adv |= ADVERTISE_100FULL;
np->pause_flags &= ~(NV_PAUSEFRAME_AUTONEG|NV_PAUSEFRAME_RX_ENABLE|NV_PAUSEFRAME_TX_ENABLE);
if (np->pause_flags & NV_PAUSEFRAME_RX_REQ) {/* for rx we set both advertisements but disable tx pause */
@@ -4264,16 +4269,6 @@ static int nv_nway_reset(struct net_device *dev)
return ret;
}
-static int nv_set_tso(struct net_device *dev, u32 value)
-{
- struct fe_priv *np = netdev_priv(dev);
-
- if ((np->driver_data & DEV_HAS_CHECKSUM))
- return ethtool_op_set_tso(dev, value);
- else
- return -EOPNOTSUPP;
-}
-
static void nv_get_ringparam(struct net_device *dev, struct ethtool_ringparam* ring)
{
struct fe_priv *np = netdev_priv(dev);
@@ -4480,58 +4475,36 @@ static int nv_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam*
return 0;
}
-static u32 nv_get_rx_csum(struct net_device *dev)
+static u32 nv_fix_features(struct net_device *dev, u32 features)
{
- struct fe_priv *np = netdev_priv(dev);
- return np->rx_csum != 0;
+ /* vlan is dependent on rx checksum offload */
+ if (features & (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX))
+ features |= NETIF_F_RXCSUM;
+
+ return features;
}
-static int nv_set_rx_csum(struct net_device *dev, u32 data)
+static int nv_set_features(struct net_device *dev, u32 features)
{
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
- int retcode = 0;
-
- if (np->driver_data & DEV_HAS_CHECKSUM) {
- if (data) {
- np->rx_csum = 1;
- np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK;
- } else {
- np->rx_csum = 0;
- /* vlan is dependent on rx checksum offload */
- if (!(np->vlanctl_bits & NVREG_VLANCONTROL_ENABLE))
- np->txrxctl_bits &= ~NVREG_TXRXCTL_RXCHECK;
- }
- if (netif_running(dev)) {
- spin_lock_irq(&np->lock);
- writel(np->txrxctl_bits, base + NvRegTxRxControl);
- spin_unlock_irq(&np->lock);
- }
- } else {
- return -EINVAL;
- }
+ u32 changed = dev->features ^ features;
- return retcode;
-}
+ if (changed & NETIF_F_RXCSUM) {
+ spin_lock_irq(&np->lock);
-static int nv_set_tx_csum(struct net_device *dev, u32 data)
-{
- struct fe_priv *np = netdev_priv(dev);
+ if (features & NETIF_F_RXCSUM)
+ np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK;
+ else
+ np->txrxctl_bits &= ~NVREG_TXRXCTL_RXCHECK;
- if (np->driver_data & DEV_HAS_CHECKSUM)
- return ethtool_op_set_tx_csum(dev, data);
- else
- return -EOPNOTSUPP;
-}
+ if (netif_running(dev))
+ writel(np->txrxctl_bits, base + NvRegTxRxControl);
-static int nv_set_sg(struct net_device *dev, u32 data)
-{
- struct fe_priv *np = netdev_priv(dev);
+ spin_unlock_irq(&np->lock);
+ }
- if (np->driver_data & DEV_HAS_CHECKSUM)
- return ethtool_op_set_sg(dev, data);
- else
- return -EOPNOTSUPP;
+ return 0;
}
static int nv_get_sset_count(struct net_device *dev, int sset)
@@ -4896,15 +4869,10 @@ static const struct ethtool_ops ops = {
.get_regs_len = nv_get_regs_len,
.get_regs = nv_get_regs,
.nway_reset = nv_nway_reset,
- .set_tso = nv_set_tso,
.get_ringparam = nv_get_ringparam,
.set_ringparam = nv_set_ringparam,
.get_pauseparam = nv_get_pauseparam,
.set_pauseparam = nv_set_pauseparam,
- .get_rx_csum = nv_get_rx_csum,
- .set_rx_csum = nv_set_rx_csum,
- .set_tx_csum = nv_set_tx_csum,
- .set_sg = nv_set_sg,
.get_strings = nv_get_strings,
.get_ethtool_stats = nv_get_ethtool_stats,
.get_sset_count = nv_get_sset_count,
@@ -5235,6 +5203,8 @@ static const struct net_device_ops nv_netdev_ops = {
.ndo_start_xmit = nv_start_xmit,
.ndo_tx_timeout = nv_tx_timeout,
.ndo_change_mtu = nv_change_mtu,
+ .ndo_fix_features = nv_fix_features,
+ .ndo_set_features = nv_set_features,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = nv_set_mac_address,
.ndo_set_multicast_list = nv_set_multicast,
@@ -5251,6 +5221,8 @@ static const struct net_device_ops nv_netdev_ops_optimized = {
.ndo_start_xmit = nv_start_xmit_optimized,
.ndo_tx_timeout = nv_tx_timeout,
.ndo_change_mtu = nv_change_mtu,
+ .ndo_fix_features = nv_fix_features,
+ .ndo_set_features = nv_set_features,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = nv_set_mac_address,
.ndo_set_multicast_list = nv_set_multicast,
@@ -5364,11 +5336,10 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
np->pkt_limit = NV_PKTLIMIT_2;
if (id->driver_data & DEV_HAS_CHECKSUM) {
- np->rx_csum = 1;
np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK;
- dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
- dev->features |= NETIF_F_TSO;
- dev->features |= NETIF_F_GRO;
+ dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_SG |
+ NETIF_F_TSO | NETIF_F_RXCSUM;
+ dev->features |= dev->hw_features;
}
np->vlanctl_bits = 0;
@@ -5384,7 +5355,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
np->pause_flags |= NV_PAUSEFRAME_TX_CAPABLE | NV_PAUSEFRAME_TX_REQ;
}
-
err = -ENOMEM;
np->base = ioremap(addr, np->register_size);
if (!np->base)
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index 5131e61c358c..21abb5c01a56 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -956,8 +956,6 @@ static const struct ethtool_ops fs_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_msglevel = fs_get_msglevel,
.set_msglevel = fs_set_msglevel,
- .set_tx_csum = ethtool_op_set_tx_csum, /* local! */
- .set_sg = ethtool_op_set_sg,
.get_regs = fs_get_regs,
};
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 2a0ad9a501bb..ff60b23a5b74 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -365,7 +365,7 @@ static void gfar_init_mac(struct net_device *ndev)
gfar_write(&regs->rir0, DEFAULT_RIR0);
}
- if (priv->rx_csum_enable)
+ if (ndev->features & NETIF_F_RXCSUM)
rctrl |= RCTRL_CHECKSUMMING;
if (priv->extended_hash) {
@@ -463,6 +463,7 @@ static const struct net_device_ops gfar_netdev_ops = {
.ndo_start_xmit = gfar_start_xmit,
.ndo_stop = gfar_close,
.ndo_change_mtu = gfar_change_mtu,
+ .ndo_set_features = gfar_set_features,
.ndo_set_multicast_list = gfar_set_multi,
.ndo_tx_timeout = gfar_timeout,
.ndo_do_ioctl = gfar_ioctl,
@@ -513,7 +514,7 @@ void unlock_tx_qs(struct gfar_private *priv)
/* Returns 1 if incoming frames use an FCB */
static inline int gfar_uses_fcb(struct gfar_private *priv)
{
- return priv->vlgrp || priv->rx_csum_enable ||
+ return priv->vlgrp || (priv->ndev->features & NETIF_F_RXCSUM) ||
(priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER);
}
@@ -1030,10 +1031,11 @@ static int gfar_probe(struct platform_device *ofdev)
netif_napi_add(dev, &priv->gfargrp[i].napi, gfar_poll, GFAR_DEV_WEIGHT);
if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) {
- priv->rx_csum_enable = 1;
- dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_HIGHDMA;
- } else
- priv->rx_csum_enable = 0;
+ dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
+ NETIF_F_RXCSUM;
+ dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG |
+ NETIF_F_RXCSUM | NETIF_F_HIGHDMA;
+ }
priv->vlgrp = NULL;
@@ -2697,7 +2699,7 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
if (priv->padding)
skb_pull(skb, priv->padding);
- if (priv->rx_csum_enable)
+ if (dev->features & NETIF_F_RXCSUM)
gfar_rx_checksum(skb, fcb);
/* Tell the skb what kind of packet this is */
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index b2fe7edefad9..fc86f5195445 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -382,23 +382,6 @@ extern const char gfar_driver_version[];
#define BD_LFLAG(flags) ((flags) << 16)
#define BD_LENGTH_MASK 0x0000ffff
-#define CLASS_CODE_UNRECOG 0x00
-#define CLASS_CODE_DUMMY1 0x01
-#define CLASS_CODE_ETHERTYPE1 0x02
-#define CLASS_CODE_ETHERTYPE2 0x03
-#define CLASS_CODE_USER_PROG1 0x04
-#define CLASS_CODE_USER_PROG2 0x05
-#define CLASS_CODE_USER_PROG3 0x06
-#define CLASS_CODE_USER_PROG4 0x07
-#define CLASS_CODE_TCP_IPV4 0x08
-#define CLASS_CODE_UDP_IPV4 0x09
-#define CLASS_CODE_AH_ESP_IPV4 0x0a
-#define CLASS_CODE_SCTP_IPV4 0x0b
-#define CLASS_CODE_TCP_IPV6 0x0c
-#define CLASS_CODE_UDP_IPV6 0x0d
-#define CLASS_CODE_AH_ESP_IPV6 0x0e
-#define CLASS_CODE_SCTP_IPV6 0x0f
-
#define FPR_FILER_MASK 0xFFFFFFFF
#define MAX_FILER_IDX 0xFF
@@ -1100,7 +1083,7 @@ struct gfar_private {
struct device_node *phy_node;
struct device_node *tbi_node;
u32 device_flags;
- unsigned char rx_csum_enable:1,
+ unsigned char
extended_hash:1,
bd_stash_en:1,
rx_filer_enable:1,
@@ -1170,6 +1153,7 @@ extern void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev,
extern void gfar_configure_coalescing(struct gfar_private *priv,
unsigned long tx_mask, unsigned long rx_mask);
void gfar_init_sysfs(struct net_device *dev);
+int gfar_set_features(struct net_device *dev, u32 features);
extern const struct ethtool_ops gfar_ethtool_ops;
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 3bc8e276ba4d..493d743839d9 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -517,15 +517,15 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva
return err;
}
-static int gfar_set_rx_csum(struct net_device *dev, uint32_t data)
+int gfar_set_features(struct net_device *dev, u32 features)
{
struct gfar_private *priv = netdev_priv(dev);
unsigned long flags;
int err = 0, i = 0;
+ u32 changed = dev->features ^ features;
- if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
- return -EOPNOTSUPP;
-
+ if (!(changed & NETIF_F_RXCSUM))
+ return 0;
if (dev->flags & IFF_UP) {
/* Halt TX and RX, and process the frames which
@@ -546,58 +546,15 @@ static int gfar_set_rx_csum(struct net_device *dev, uint32_t data)
/* Now we take down the rings to rebuild them */
stop_gfar(dev);
- }
- spin_lock_irqsave(&priv->bflock, flags);
- priv->rx_csum_enable = data;
- spin_unlock_irqrestore(&priv->bflock, flags);
+ dev->features = features;
- if (dev->flags & IFF_UP) {
err = startup_gfar(dev);
netif_tx_wake_all_queues(dev);
}
return err;
}
-static uint32_t gfar_get_rx_csum(struct net_device *dev)
-{
- struct gfar_private *priv = netdev_priv(dev);
-
- if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
- return 0;
-
- return priv->rx_csum_enable;
-}
-
-static int gfar_set_tx_csum(struct net_device *dev, uint32_t data)
-{
- struct gfar_private *priv = netdev_priv(dev);
-
- if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
- return -EOPNOTSUPP;
-
- netif_tx_lock_bh(dev);
-
- if (data)
- dev->features |= NETIF_F_IP_CSUM;
- else
- dev->features &= ~NETIF_F_IP_CSUM;
-
- netif_tx_unlock_bh(dev);
-
- return 0;
-}
-
-static uint32_t gfar_get_tx_csum(struct net_device *dev)
-{
- struct gfar_private *priv = netdev_priv(dev);
-
- if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
- return 0;
-
- return (dev->features & NETIF_F_IP_CSUM) != 0;
-}
-
static uint32_t gfar_get_msglevel(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
@@ -645,42 +602,6 @@ static int gfar_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
}
#endif
-static int gfar_ethflow_to_class(int flow_type, u64 *class)
-{
- switch (flow_type) {
- case TCP_V4_FLOW:
- *class = CLASS_CODE_TCP_IPV4;
- break;
- case UDP_V4_FLOW:
- *class = CLASS_CODE_UDP_IPV4;
- break;
- case AH_V4_FLOW:
- case ESP_V4_FLOW:
- *class = CLASS_CODE_AH_ESP_IPV4;
- break;
- case SCTP_V4_FLOW:
- *class = CLASS_CODE_SCTP_IPV4;
- break;
- case TCP_V6_FLOW:
- *class = CLASS_CODE_TCP_IPV6;
- break;
- case UDP_V6_FLOW:
- *class = CLASS_CODE_UDP_IPV6;
- break;
- case AH_V6_FLOW:
- case ESP_V6_FLOW:
- *class = CLASS_CODE_AH_ESP_IPV6;
- break;
- case SCTP_V6_FLOW:
- *class = CLASS_CODE_SCTP_IPV6;
- break;
- default:
- return 0;
- }
-
- return 1;
-}
-
static void ethflow_to_filer_rules (struct gfar_private *priv, u64 ethflow)
{
u32 fcr = 0x0, fpr = FPR_FILER_MASK;
@@ -778,11 +699,6 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u
case UDP_V6_FLOW:
cmp_rqfpr = RQFPR_IPV6 |RQFPR_UDP;
break;
- case IPV4_FLOW:
- cmp_rqfpr = RQFPR_IPV4;
- case IPV6_FLOW:
- cmp_rqfpr = RQFPR_IPV6;
- break;
default:
printk(KERN_ERR "Right now this class is not supported\n");
return 0;
@@ -848,18 +764,9 @@ static int gfar_ethflow_to_filer_table(struct gfar_private *priv, u64 ethflow, u
static int gfar_set_hash_opts(struct gfar_private *priv, struct ethtool_rxnfc *cmd)
{
- u64 class;
-
- if (!gfar_ethflow_to_class(cmd->flow_type, &class))
- return -EINVAL;
-
- if (class < CLASS_CODE_USER_PROG1 ||
- class > CLASS_CODE_SCTP_IPV6)
- return -EINVAL;
-
/* write the filer rules here */
if (!gfar_ethflow_to_filer_table(priv, cmd->data, cmd->flow_type))
- return -1;
+ return -EINVAL;
return 0;
}
@@ -894,11 +801,6 @@ const struct ethtool_ops gfar_ethtool_ops = {
.get_strings = gfar_gstrings,
.get_sset_count = gfar_sset_count,
.get_ethtool_stats = gfar_fill_stats,
- .get_rx_csum = gfar_get_rx_csum,
- .get_tx_csum = gfar_get_tx_csum,
- .set_rx_csum = gfar_set_rx_csum,
- .set_tx_csum = gfar_set_tx_csum,
- .set_sg = ethtool_op_set_sg,
.get_msglevel = gfar_get_msglevel,
.set_msglevel = gfar_set_msglevel,
#ifdef CONFIG_PM
diff --git a/drivers/net/gianfar_ptp.c b/drivers/net/gianfar_ptp.c
new file mode 100644
index 000000000000..d8e175382d1d
--- /dev/null
+++ b/drivers/net/gianfar_ptp.c
@@ -0,0 +1,588 @@
+/*
+ * PTP 1588 clock using the eTSEC
+ *
+ * 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/device.h>
+#include <linux/hrtimer.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/timex.h>
+#include <linux/io.h>
+
+#include <linux/ptp_clock_kernel.h>
+
+#include "gianfar.h"
+
+/*
+ * gianfar ptp registers
+ * Generated by regen.tcl on Thu May 13 01:38:57 PM CEST 2010
+ */
+struct gianfar_ptp_registers {
+ u32 tmr_ctrl; /* Timer control register */
+ u32 tmr_tevent; /* Timestamp event register */
+ u32 tmr_temask; /* Timer event mask register */
+ u32 tmr_pevent; /* Timestamp event register */
+ u32 tmr_pemask; /* Timer event mask register */
+ u32 tmr_stat; /* Timestamp status register */
+ u32 tmr_cnt_h; /* Timer counter high register */
+ u32 tmr_cnt_l; /* Timer counter low register */
+ u32 tmr_add; /* Timer drift compensation addend register */
+ u32 tmr_acc; /* Timer accumulator register */
+ u32 tmr_prsc; /* Timer prescale */
+ u8 res1[4];
+ u32 tmroff_h; /* Timer offset high */
+ u32 tmroff_l; /* Timer offset low */
+ u8 res2[8];
+ u32 tmr_alarm1_h; /* Timer alarm 1 high register */
+ u32 tmr_alarm1_l; /* Timer alarm 1 high register */
+ u32 tmr_alarm2_h; /* Timer alarm 2 high register */
+ u32 tmr_alarm2_l; /* Timer alarm 2 high register */
+ u8 res3[48];
+ u32 tmr_fiper1; /* Timer fixed period interval */
+ u32 tmr_fiper2; /* Timer fixed period interval */
+ u32 tmr_fiper3; /* Timer fixed period interval */
+ u8 res4[20];
+ u32 tmr_etts1_h; /* Timestamp of general purpose external trigger */
+ u32 tmr_etts1_l; /* Timestamp of general purpose external trigger */
+ u32 tmr_etts2_h; /* Timestamp of general purpose external trigger */
+ u32 tmr_etts2_l; /* Timestamp of general purpose external trigger */
+};
+
+/* Bit definitions for the TMR_CTRL register */
+#define ALM1P (1<<31) /* Alarm1 output polarity */
+#define ALM2P (1<<30) /* Alarm2 output polarity */
+#define FS (1<<28) /* FIPER start indication */
+#define PP1L (1<<27) /* Fiper1 pulse loopback mode enabled. */
+#define PP2L (1<<26) /* Fiper2 pulse loopback mode enabled. */
+#define TCLK_PERIOD_SHIFT (16) /* 1588 timer reference clock period. */
+#define TCLK_PERIOD_MASK (0x3ff)
+#define RTPE (1<<15) /* Record Tx Timestamp to PAL Enable. */
+#define FRD (1<<14) /* FIPER Realignment Disable */
+#define ESFDP (1<<11) /* External Tx/Rx SFD Polarity. */
+#define ESFDE (1<<10) /* External Tx/Rx SFD Enable. */
+#define ETEP2 (1<<9) /* External trigger 2 edge polarity */
+#define ETEP1 (1<<8) /* External trigger 1 edge polarity */
+#define COPH (1<<7) /* Generated clock output phase. */
+#define CIPH (1<<6) /* External oscillator input clock phase */
+#define TMSR (1<<5) /* Timer soft reset. */
+#define BYP (1<<3) /* Bypass drift compensated clock */
+#define TE (1<<2) /* 1588 timer enable. */
+#define CKSEL_SHIFT (0) /* 1588 Timer reference clock source */
+#define CKSEL_MASK (0x3)
+
+/* Bit definitions for the TMR_TEVENT register */
+#define ETS2 (1<<25) /* External trigger 2 timestamp sampled */
+#define ETS1 (1<<24) /* External trigger 1 timestamp sampled */
+#define ALM2 (1<<17) /* Current time = alarm time register 2 */
+#define ALM1 (1<<16) /* Current time = alarm time register 1 */
+#define PP1 (1<<7) /* periodic pulse generated on FIPER1 */
+#define PP2 (1<<6) /* periodic pulse generated on FIPER2 */
+#define PP3 (1<<5) /* periodic pulse generated on FIPER3 */
+
+/* Bit definitions for the TMR_TEMASK register */
+#define ETS2EN (1<<25) /* External trigger 2 timestamp enable */
+#define ETS1EN (1<<24) /* External trigger 1 timestamp enable */
+#define ALM2EN (1<<17) /* Timer ALM2 event enable */
+#define ALM1EN (1<<16) /* Timer ALM1 event enable */
+#define PP1EN (1<<7) /* Periodic pulse event 1 enable */
+#define PP2EN (1<<6) /* Periodic pulse event 2 enable */
+
+/* Bit definitions for the TMR_PEVENT register */
+#define TXP2 (1<<9) /* PTP transmitted timestamp im TXTS2 */
+#define TXP1 (1<<8) /* PTP transmitted timestamp in TXTS1 */
+#define RXP (1<<0) /* PTP frame has been received */
+
+/* Bit definitions for the TMR_PEMASK register */
+#define TXP2EN (1<<9) /* Transmit PTP packet event 2 enable */
+#define TXP1EN (1<<8) /* Transmit PTP packet event 1 enable */
+#define RXPEN (1<<0) /* Receive PTP packet event enable */
+
+/* Bit definitions for the TMR_STAT register */
+#define STAT_VEC_SHIFT (0) /* Timer general purpose status vector */
+#define STAT_VEC_MASK (0x3f)
+
+/* Bit definitions for the TMR_PRSC register */
+#define PRSC_OCK_SHIFT (0) /* Output clock division/prescale factor. */
+#define PRSC_OCK_MASK (0xffff)
+
+
+#define DRIVER "gianfar_ptp"
+#define DEFAULT_CKSEL 1
+#define N_ALARM 1 /* first alarm is used internally to reset fipers */
+#define N_EXT_TS 2
+#define REG_SIZE sizeof(struct gianfar_ptp_registers)
+
+struct etsects {
+ struct gianfar_ptp_registers *regs;
+ spinlock_t lock; /* protects regs */
+ struct ptp_clock *clock;
+ struct ptp_clock_info caps;
+ struct resource *rsrc;
+ int irq;
+ u64 alarm_interval; /* for periodic alarm */
+ u64 alarm_value;
+ u32 tclk_period; /* nanoseconds */
+ u32 tmr_prsc;
+ u32 tmr_add;
+ u32 cksel;
+ u32 tmr_fiper1;
+ u32 tmr_fiper2;
+};
+
+/*
+ * Register access functions
+ */
+
+/* Caller must hold etsects->lock. */
+static u64 tmr_cnt_read(struct etsects *etsects)
+{
+ u64 ns;
+ u32 lo, hi;
+
+ lo = gfar_read(&etsects->regs->tmr_cnt_l);
+ hi = gfar_read(&etsects->regs->tmr_cnt_h);
+ ns = ((u64) hi) << 32;
+ ns |= lo;
+ return ns;
+}
+
+/* Caller must hold etsects->lock. */
+static void tmr_cnt_write(struct etsects *etsects, u64 ns)
+{
+ u32 hi = ns >> 32;
+ u32 lo = ns & 0xffffffff;
+
+ gfar_write(&etsects->regs->tmr_cnt_l, lo);
+ gfar_write(&etsects->regs->tmr_cnt_h, hi);
+}
+
+/* Caller must hold etsects->lock. */
+static void set_alarm(struct etsects *etsects)
+{
+ u64 ns;
+ u32 lo, hi;
+
+ ns = tmr_cnt_read(etsects) + 1500000000ULL;
+ ns = div_u64(ns, 1000000000UL) * 1000000000ULL;
+ ns -= etsects->tclk_period;
+ hi = ns >> 32;
+ lo = ns & 0xffffffff;
+ gfar_write(&etsects->regs->tmr_alarm1_l, lo);
+ gfar_write(&etsects->regs->tmr_alarm1_h, hi);
+}
+
+/* Caller must hold etsects->lock. */
+static void set_fipers(struct etsects *etsects)
+{
+ u32 tmr_ctrl = gfar_read(&etsects->regs->tmr_ctrl);
+
+ gfar_write(&etsects->regs->tmr_ctrl, tmr_ctrl & (~TE));
+ gfar_write(&etsects->regs->tmr_prsc, etsects->tmr_prsc);
+ gfar_write(&etsects->regs->tmr_fiper1, etsects->tmr_fiper1);
+ gfar_write(&etsects->regs->tmr_fiper2, etsects->tmr_fiper2);
+ set_alarm(etsects);
+ gfar_write(&etsects->regs->tmr_ctrl, tmr_ctrl|TE);
+}
+
+/*
+ * Interrupt service routine
+ */
+
+static irqreturn_t isr(int irq, void *priv)
+{
+ struct etsects *etsects = priv;
+ struct ptp_clock_event event;
+ u64 ns;
+ u32 ack = 0, lo, hi, mask, val;
+
+ val = gfar_read(&etsects->regs->tmr_tevent);
+
+ if (val & ETS1) {
+ ack |= ETS1;
+ hi = gfar_read(&etsects->regs->tmr_etts1_h);
+ lo = gfar_read(&etsects->regs->tmr_etts1_l);
+ event.type = PTP_CLOCK_EXTTS;
+ event.index = 0;
+ event.timestamp = ((u64) hi) << 32;
+ event.timestamp |= lo;
+ ptp_clock_event(etsects->clock, &event);
+ }
+
+ if (val & ETS2) {
+ ack |= ETS2;
+ hi = gfar_read(&etsects->regs->tmr_etts2_h);
+ lo = gfar_read(&etsects->regs->tmr_etts2_l);
+ event.type = PTP_CLOCK_EXTTS;
+ event.index = 1;
+ event.timestamp = ((u64) hi) << 32;
+ event.timestamp |= lo;
+ ptp_clock_event(etsects->clock, &event);
+ }
+
+ if (val & ALM2) {
+ ack |= ALM2;
+ if (etsects->alarm_value) {
+ event.type = PTP_CLOCK_ALARM;
+ event.index = 0;
+ event.timestamp = etsects->alarm_value;
+ ptp_clock_event(etsects->clock, &event);
+ }
+ if (etsects->alarm_interval) {
+ ns = etsects->alarm_value + etsects->alarm_interval;
+ hi = ns >> 32;
+ lo = ns & 0xffffffff;
+ spin_lock(&etsects->lock);
+ gfar_write(&etsects->regs->tmr_alarm2_l, lo);
+ gfar_write(&etsects->regs->tmr_alarm2_h, hi);
+ spin_unlock(&etsects->lock);
+ etsects->alarm_value = ns;
+ } else {
+ gfar_write(&etsects->regs->tmr_tevent, ALM2);
+ spin_lock(&etsects->lock);
+ mask = gfar_read(&etsects->regs->tmr_temask);
+ mask &= ~ALM2EN;
+ gfar_write(&etsects->regs->tmr_temask, mask);
+ spin_unlock(&etsects->lock);
+ etsects->alarm_value = 0;
+ etsects->alarm_interval = 0;
+ }
+ }
+
+ if (val & PP1) {
+ ack |= PP1;
+ event.type = PTP_CLOCK_PPS;
+ ptp_clock_event(etsects->clock, &event);
+ }
+
+ if (ack) {
+ gfar_write(&etsects->regs->tmr_tevent, ack);
+ return IRQ_HANDLED;
+ } else
+ return IRQ_NONE;
+}
+
+/*
+ * PTP clock operations
+ */
+
+static int ptp_gianfar_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+{
+ u64 adj;
+ u32 diff, tmr_add;
+ int neg_adj = 0;
+ struct etsects *etsects = container_of(ptp, struct etsects, caps);
+
+ if (ppb < 0) {
+ neg_adj = 1;
+ ppb = -ppb;
+ }
+ tmr_add = etsects->tmr_add;
+ adj = tmr_add;
+ adj *= ppb;
+ diff = div_u64(adj, 1000000000ULL);
+
+ tmr_add = neg_adj ? tmr_add - diff : tmr_add + diff;
+
+ gfar_write(&etsects->regs->tmr_add, tmr_add);
+
+ return 0;
+}
+
+static int ptp_gianfar_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+ s64 now;
+ unsigned long flags;
+ struct etsects *etsects = container_of(ptp, struct etsects, caps);
+
+ spin_lock_irqsave(&etsects->lock, flags);
+
+ now = tmr_cnt_read(etsects);
+ now += delta;
+ tmr_cnt_write(etsects, now);
+
+ spin_unlock_irqrestore(&etsects->lock, flags);
+
+ set_fipers(etsects);
+
+ return 0;
+}
+
+static int ptp_gianfar_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+ u64 ns;
+ u32 remainder;
+ unsigned long flags;
+ struct etsects *etsects = container_of(ptp, struct etsects, caps);
+
+ spin_lock_irqsave(&etsects->lock, flags);
+
+ ns = tmr_cnt_read(etsects);
+
+ spin_unlock_irqrestore(&etsects->lock, flags);
+
+ ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder);
+ ts->tv_nsec = remainder;
+ return 0;
+}
+
+static int ptp_gianfar_settime(struct ptp_clock_info *ptp,
+ const struct timespec *ts)
+{
+ u64 ns;
+ unsigned long flags;
+ struct etsects *etsects = container_of(ptp, struct etsects, caps);
+
+ ns = ts->tv_sec * 1000000000ULL;
+ ns += ts->tv_nsec;
+
+ spin_lock_irqsave(&etsects->lock, flags);
+
+ tmr_cnt_write(etsects, ns);
+ set_fipers(etsects);
+
+ spin_unlock_irqrestore(&etsects->lock, flags);
+
+ return 0;
+}
+
+static int ptp_gianfar_enable(struct ptp_clock_info *ptp,
+ struct ptp_clock_request *rq, int on)
+{
+ struct etsects *etsects = container_of(ptp, struct etsects, caps);
+ unsigned long flags;
+ u32 bit, mask;
+
+ switch (rq->type) {
+ case PTP_CLK_REQ_EXTTS:
+ switch (rq->extts.index) {
+ case 0:
+ bit = ETS1EN;
+ break;
+ case 1:
+ bit = ETS2EN;
+ break;
+ default:
+ return -EINVAL;
+ }
+ spin_lock_irqsave(&etsects->lock, flags);
+ mask = gfar_read(&etsects->regs->tmr_temask);
+ if (on)
+ mask |= bit;
+ else
+ mask &= ~bit;
+ gfar_write(&etsects->regs->tmr_temask, mask);
+ spin_unlock_irqrestore(&etsects->lock, flags);
+ return 0;
+
+ case PTP_CLK_REQ_PPS:
+ spin_lock_irqsave(&etsects->lock, flags);
+ mask = gfar_read(&etsects->regs->tmr_temask);
+ if (on)
+ mask |= PP1EN;
+ else
+ mask &= ~PP1EN;
+ gfar_write(&etsects->regs->tmr_temask, mask);
+ spin_unlock_irqrestore(&etsects->lock, flags);
+ return 0;
+
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static struct ptp_clock_info ptp_gianfar_caps = {
+ .owner = THIS_MODULE,
+ .name = "gianfar clock",
+ .max_adj = 512000,
+ .n_alarm = N_ALARM,
+ .n_ext_ts = N_EXT_TS,
+ .n_per_out = 0,
+ .pps = 1,
+ .adjfreq = ptp_gianfar_adjfreq,
+ .adjtime = ptp_gianfar_adjtime,
+ .gettime = ptp_gianfar_gettime,
+ .settime = ptp_gianfar_settime,
+ .enable = ptp_gianfar_enable,
+};
+
+/* OF device tree */
+
+static int get_of_u32(struct device_node *node, char *str, u32 *val)
+{
+ int plen;
+ const u32 *prop = of_get_property(node, str, &plen);
+
+ if (!prop || plen != sizeof(*prop))
+ return -1;
+ *val = *prop;
+ return 0;
+}
+
+static int gianfar_ptp_probe(struct platform_device *dev)
+{
+ struct device_node *node = dev->dev.of_node;
+ struct etsects *etsects;
+ struct timespec now;
+ int err = -ENOMEM;
+ u32 tmr_ctrl;
+ unsigned long flags;
+
+ etsects = kzalloc(sizeof(*etsects), GFP_KERNEL);
+ if (!etsects)
+ goto no_memory;
+
+ err = -ENODEV;
+
+ etsects->caps = ptp_gianfar_caps;
+ etsects->cksel = DEFAULT_CKSEL;
+
+ if (get_of_u32(node, "fsl,tclk-period", &etsects->tclk_period) ||
+ get_of_u32(node, "fsl,tmr-prsc", &etsects->tmr_prsc) ||
+ get_of_u32(node, "fsl,tmr-add", &etsects->tmr_add) ||
+ get_of_u32(node, "fsl,tmr-fiper1", &etsects->tmr_fiper1) ||
+ get_of_u32(node, "fsl,tmr-fiper2", &etsects->tmr_fiper2) ||
+ get_of_u32(node, "fsl,max-adj", &etsects->caps.max_adj)) {
+ pr_err("device tree node missing required elements\n");
+ goto no_node;
+ }
+
+ etsects->irq = platform_get_irq(dev, 0);
+
+ if (etsects->irq == NO_IRQ) {
+ pr_err("irq not in device tree\n");
+ goto no_node;
+ }
+ if (request_irq(etsects->irq, isr, 0, DRIVER, etsects)) {
+ pr_err("request_irq failed\n");
+ goto no_node;
+ }
+
+ etsects->rsrc = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!etsects->rsrc) {
+ pr_err("no resource\n");
+ goto no_resource;
+ }
+ if (request_resource(&ioport_resource, etsects->rsrc)) {
+ pr_err("resource busy\n");
+ goto no_resource;
+ }
+
+ spin_lock_init(&etsects->lock);
+
+ etsects->regs = ioremap(etsects->rsrc->start,
+ 1 + etsects->rsrc->end - etsects->rsrc->start);
+ if (!etsects->regs) {
+ pr_err("ioremap ptp registers failed\n");
+ goto no_ioremap;
+ }
+ getnstimeofday(&now);
+ ptp_gianfar_settime(&etsects->caps, &now);
+
+ tmr_ctrl =
+ (etsects->tclk_period & TCLK_PERIOD_MASK) << TCLK_PERIOD_SHIFT |
+ (etsects->cksel & CKSEL_MASK) << CKSEL_SHIFT;
+
+ spin_lock_irqsave(&etsects->lock, flags);
+
+ gfar_write(&etsects->regs->tmr_ctrl, tmr_ctrl);
+ gfar_write(&etsects->regs->tmr_add, etsects->tmr_add);
+ gfar_write(&etsects->regs->tmr_prsc, etsects->tmr_prsc);
+ gfar_write(&etsects->regs->tmr_fiper1, etsects->tmr_fiper1);
+ gfar_write(&etsects->regs->tmr_fiper2, etsects->tmr_fiper2);
+ set_alarm(etsects);
+ gfar_write(&etsects->regs->tmr_ctrl, tmr_ctrl|FS|RTPE|TE);
+
+ spin_unlock_irqrestore(&etsects->lock, flags);
+
+ etsects->clock = ptp_clock_register(&etsects->caps);
+ if (IS_ERR(etsects->clock)) {
+ err = PTR_ERR(etsects->clock);
+ goto no_clock;
+ }
+
+ dev_set_drvdata(&dev->dev, etsects);
+
+ return 0;
+
+no_clock:
+no_ioremap:
+ release_resource(etsects->rsrc);
+no_resource:
+ free_irq(etsects->irq, etsects);
+no_node:
+ kfree(etsects);
+no_memory:
+ return err;
+}
+
+static int gianfar_ptp_remove(struct platform_device *dev)
+{
+ struct etsects *etsects = dev_get_drvdata(&dev->dev);
+
+ gfar_write(&etsects->regs->tmr_temask, 0);
+ gfar_write(&etsects->regs->tmr_ctrl, 0);
+
+ ptp_clock_unregister(etsects->clock);
+ iounmap(etsects->regs);
+ release_resource(etsects->rsrc);
+ free_irq(etsects->irq, etsects);
+ kfree(etsects);
+
+ return 0;
+}
+
+static struct of_device_id match_table[] = {
+ { .compatible = "fsl,etsec-ptp" },
+ {},
+};
+
+static struct platform_driver gianfar_ptp_driver = {
+ .driver = {
+ .name = "gianfar_ptp",
+ .of_match_table = match_table,
+ .owner = THIS_MODULE,
+ },
+ .probe = gianfar_ptp_probe,
+ .remove = gianfar_ptp_remove,
+};
+
+/* module operations */
+
+static int __init ptp_gianfar_init(void)
+{
+ return platform_driver_register(&gianfar_ptp_driver);
+}
+
+module_init(ptp_gianfar_init);
+
+static void __exit ptp_gianfar_exit(void)
+{
+ platform_driver_unregister(&gianfar_ptp_driver);
+}
+
+module_exit(ptp_gianfar_exit);
+
+MODULE_AUTHOR("Richard Cochran <richard.cochran@omicron.at>");
+MODULE_DESCRIPTION("PTP clock using the eTSEC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/greth.c b/drivers/net/greth.c
index 396ff7d785d1..f181304a7ab6 100644
--- a/drivers/net/greth.c
+++ b/drivers/net/greth.c
@@ -901,7 +901,7 @@ static int greth_rx_gbit(struct net_device *dev, int limit)
skb_put(skb, pkt_len);
- if (greth->flags & GRETH_FLAG_RX_CSUM && hw_checksummed(status))
+ if (dev->features & NETIF_F_RXCSUM && hw_checksummed(status))
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
skb_checksum_none_assert(skb);
@@ -1142,41 +1142,6 @@ static void greth_get_regs(struct net_device *dev, struct ethtool_regs *regs, vo
buff[i] = greth_read_bd(&greth_regs[i]);
}
-static u32 greth_get_rx_csum(struct net_device *dev)
-{
- struct greth_private *greth = netdev_priv(dev);
- return (greth->flags & GRETH_FLAG_RX_CSUM) != 0;
-}
-
-static int greth_set_rx_csum(struct net_device *dev, u32 data)
-{
- struct greth_private *greth = netdev_priv(dev);
-
- spin_lock_bh(&greth->devlock);
-
- if (data)
- greth->flags |= GRETH_FLAG_RX_CSUM;
- else
- greth->flags &= ~GRETH_FLAG_RX_CSUM;
-
- spin_unlock_bh(&greth->devlock);
-
- return 0;
-}
-
-static u32 greth_get_tx_csum(struct net_device *dev)
-{
- return (dev->features & NETIF_F_IP_CSUM) != 0;
-}
-
-static int greth_set_tx_csum(struct net_device *dev, u32 data)
-{
- netif_tx_lock_bh(dev);
- ethtool_op_set_tx_csum(dev, data);
- netif_tx_unlock_bh(dev);
- return 0;
-}
-
static const struct ethtool_ops greth_ethtool_ops = {
.get_msglevel = greth_get_msglevel,
.set_msglevel = greth_set_msglevel,
@@ -1185,10 +1150,6 @@ static const struct ethtool_ops greth_ethtool_ops = {
.get_drvinfo = greth_get_drvinfo,
.get_regs_len = greth_get_regs_len,
.get_regs = greth_get_regs,
- .get_rx_csum = greth_get_rx_csum,
- .set_rx_csum = greth_set_rx_csum,
- .get_tx_csum = greth_get_tx_csum,
- .set_tx_csum = greth_set_tx_csum,
.get_link = ethtool_op_get_link,
};
@@ -1570,9 +1531,10 @@ static int __devinit greth_of_probe(struct platform_device *ofdev)
GRETH_REGSAVE(regs->status, 0xFF);
if (greth->gbit_mac) {
- dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_HIGHDMA;
+ dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM |
+ NETIF_F_RXCSUM;
+ dev->features = dev->hw_features | NETIF_F_HIGHDMA;
greth_netdev_ops.ndo_start_xmit = greth_start_xmit_gbit;
- greth->flags = GRETH_FLAG_RX_CSUM;
}
if (greth->multicast) {
diff --git a/drivers/net/greth.h b/drivers/net/greth.h
index be0f2062bd14..9a0040dee4da 100644
--- a/drivers/net/greth.h
+++ b/drivers/net/greth.h
@@ -77,9 +77,6 @@
*/
#define MAX_FRAME_SIZE 1520
-/* Flags */
-#define GRETH_FLAG_RX_CSUM 0x1
-
/* GRETH APB registers */
struct greth_regs {
u32 control;
@@ -133,7 +130,6 @@ struct greth_private {
unsigned int duplex;
u32 msg_enable;
- u32 flags;
u8 phyaddr;
u8 multicast;
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index 80d25ed53344..a09041aa8509 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -132,13 +132,8 @@ static int tx_params[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
/*
* RX_CHECKSUM turns on card-generated receive checksum generation for
* TCP and UDP packets. Otherwise the upper layers do the calculation.
- * TX_CHECKSUM won't do anything too useful, even if it works. There's no
- * easy mechanism by which to tell the TCP/UDP stack that it need not
- * generate checksums for this device. But if somebody can find a way
- * to get that to work, most of the card work is in here already.
* 3/10/1999 Pete Wyckoff <wyckoff@ca.sandia.gov>
*/
-#undef TX_CHECKSUM
#define RX_CHECKSUM
/* Operational parameters that usually are not changed. */
@@ -630,11 +625,6 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev,
SET_NETDEV_DEV(dev, &pdev->dev);
-#ifdef TX_CHECKSUM
- printk("check that skbcopy in ip_queue_xmit isn't happening\n");
- dev->hard_header_len += 8; /* for cksum tag */
-#endif
-
for (i = 0; i < 6; i++)
dev->dev_addr[i] = 1 ? read_eeprom(ioaddr, 4 + i)
: readb(ioaddr + StationAddr + i);
@@ -937,11 +927,7 @@ static int hamachi_open(struct net_device *dev)
/* always 1, takes no more time to do it */
writew(0x0001, ioaddr + RxChecksum);
-#ifdef TX_CHECKSUM
- writew(0x0001, ioaddr + TxChecksum);
-#else
writew(0x0000, ioaddr + TxChecksum);
-#endif
writew(0x8000, ioaddr + MACCnfg); /* Soft reset the MAC */
writew(0x215F, ioaddr + MACCnfg);
writew(0x000C, ioaddr + FrameGap0);
@@ -1226,40 +1212,6 @@ static void hamachi_init_ring(struct net_device *dev)
}
-#ifdef TX_CHECKSUM
-#define csum_add(it, val) \
-do { \
- it += (u16) (val); \
- if (it & 0xffff0000) { \
- it &= 0xffff; \
- ++it; \
- } \
-} while (0)
- /* printk("add %04x --> %04x\n", val, it); \ */
-
-/* uh->len already network format, do not swap */
-#define pseudo_csum_udp(sum,ih,uh) do { \
- sum = 0; \
- csum_add(sum, (ih)->saddr >> 16); \
- csum_add(sum, (ih)->saddr & 0xffff); \
- csum_add(sum, (ih)->daddr >> 16); \
- csum_add(sum, (ih)->daddr & 0xffff); \
- csum_add(sum, cpu_to_be16(IPPROTO_UDP)); \
- csum_add(sum, (uh)->len); \
-} while (0)
-
-/* swap len */
-#define pseudo_csum_tcp(sum,ih,len) do { \
- sum = 0; \
- csum_add(sum, (ih)->saddr >> 16); \
- csum_add(sum, (ih)->saddr & 0xffff); \
- csum_add(sum, (ih)->daddr >> 16); \
- csum_add(sum, (ih)->daddr & 0xffff); \
- csum_add(sum, cpu_to_be16(IPPROTO_TCP)); \
- csum_add(sum, htons(len)); \
-} while (0)
-#endif
-
static netdev_tx_t hamachi_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
@@ -1292,36 +1244,6 @@ static netdev_tx_t hamachi_start_xmit(struct sk_buff *skb,
hmp->tx_skbuff[entry] = skb;
-#ifdef TX_CHECKSUM
- {
- /* tack on checksum tag */
- u32 tagval = 0;
- struct ethhdr *eh = (struct ethhdr *)skb->data;
- if (eh->h_proto == cpu_to_be16(ETH_P_IP)) {
- struct iphdr *ih = (struct iphdr *)((char *)eh + ETH_HLEN);
- if (ih->protocol == IPPROTO_UDP) {
- struct udphdr *uh
- = (struct udphdr *)((char *)ih + ih->ihl*4);
- u32 offset = ((unsigned char *)uh + 6) - skb->data;
- u32 pseudo;
- pseudo_csum_udp(pseudo, ih, uh);
- pseudo = htons(pseudo);
- printk("udp cksum was %04x, sending pseudo %04x\n",
- uh->check, pseudo);
- uh->check = 0; /* zero out uh->check before card calc */
- /*
- * start at 14 (skip ethhdr), store at offset (uh->check),
- * use pseudo value given.
- */
- tagval = (14 << 24) | (offset << 16) | pseudo;
- } else if (ih->protocol == IPPROTO_TCP) {
- printk("tcp, no auto cksum\n");
- }
- }
- *(u32 *)skb_push(skb, 8) = tagval;
- }
-#endif
-
hmp->tx_ring[entry].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev,
skb->data, skb->len, PCI_DMA_TODEVICE));
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 3e5d0b6b6516..992089639ea4 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -456,7 +456,7 @@ out:
* a block of 6pack data has been received, which can now be decapsulated
* and sent on to some IP layer for further processing.
*/
-static void sixpack_receive_buf(struct tty_struct *tty,
+static unsigned int sixpack_receive_buf(struct tty_struct *tty,
const unsigned char *cp, char *fp, int count)
{
struct sixpack *sp;
@@ -464,11 +464,11 @@ static void sixpack_receive_buf(struct tty_struct *tty,
int count1;
if (!count)
- return;
+ return 0;
sp = sp_get(tty);
if (!sp)
- return;
+ return -ENODEV;
memcpy(buf, cp, count < sizeof(buf) ? count : sizeof(buf));
@@ -487,6 +487,8 @@ static void sixpack_receive_buf(struct tty_struct *tty,
sp_put(sp);
tty_unthrottle(tty);
+
+ return count1;
}
/*
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
index a3c0dc9d8b98..9537aaa50c2f 100644
--- a/drivers/net/hamradio/baycom_epp.c
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -69,7 +69,7 @@ static const char paranoia_str[] = KERN_ERR
static const char bc_drvname[] = "baycom_epp";
static const char bc_drvinfo[] = KERN_INFO "baycom_epp: (C) 1998-2000 Thomas Sailer, HB9JNX/AE4WA\n"
-"baycom_epp: version 0.7 compiled " __TIME__ " " __DATE__ "\n";
+"baycom_epp: version 0.7\n";
/* --------------------------------------------------------------------- */
diff --git a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c
index 5f5af9a606f8..279d2296290a 100644
--- a/drivers/net/hamradio/baycom_par.c
+++ b/drivers/net/hamradio/baycom_par.c
@@ -102,7 +102,7 @@
static const char bc_drvname[] = "baycom_par";
static const char bc_drvinfo[] = KERN_INFO "baycom_par: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n"
-"baycom_par: version 0.9 compiled " __TIME__ " " __DATE__ "\n";
+"baycom_par: version 0.9\n";
/* --------------------------------------------------------------------- */
diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c
index 3e25f10cabd6..99cdce33df8b 100644
--- a/drivers/net/hamradio/baycom_ser_fdx.c
+++ b/drivers/net/hamradio/baycom_ser_fdx.c
@@ -92,7 +92,7 @@
static const char bc_drvname[] = "baycom_ser_fdx";
static const char bc_drvinfo[] = KERN_INFO "baycom_ser_fdx: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n"
-"baycom_ser_fdx: version 0.10 compiled " __TIME__ " " __DATE__ "\n";
+"baycom_ser_fdx: version 0.10\n";
/* --------------------------------------------------------------------- */
diff --git a/drivers/net/hamradio/baycom_ser_hdx.c b/drivers/net/hamradio/baycom_ser_hdx.c
index 1686f6dcbbce..d92fe6ca788f 100644
--- a/drivers/net/hamradio/baycom_ser_hdx.c
+++ b/drivers/net/hamradio/baycom_ser_hdx.c
@@ -80,7 +80,7 @@
static const char bc_drvname[] = "baycom_ser_hdx";
static const char bc_drvinfo[] = KERN_INFO "baycom_ser_hdx: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n"
-"baycom_ser_hdx: version 0.10 compiled " __TIME__ " " __DATE__ "\n";
+"baycom_ser_hdx: version 0.10\n";
/* --------------------------------------------------------------------- */
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index 8931168d3e74..18d8affecd1b 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -516,10 +516,6 @@ static int bpq_new_device(struct net_device *edev)
memcpy(bpq->dest_addr, bcast_addr, sizeof(bpq_eth_addr));
memcpy(bpq->acpt_addr, bcast_addr, sizeof(bpq_eth_addr));
- err = dev_alloc_name(ndev, ndev->name);
- if (err < 0)
- goto error;
-
err = register_netdevice(ndev);
if (err)
goto error;
diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c
index 5b37579e84b7..a4a3516b6bbf 100644
--- a/drivers/net/hamradio/hdlcdrv.c
+++ b/drivers/net/hamradio/hdlcdrv.c
@@ -749,7 +749,7 @@ EXPORT_SYMBOL(hdlcdrv_unregister);
static int __init hdlcdrv_init_driver(void)
{
printk(KERN_INFO "hdlcdrv: (C) 1996-2000 Thomas Sailer HB9JNX/AE4WA\n");
- printk(KERN_INFO "hdlcdrv: version 0.8 compiled " __TIME__ " " __DATE__ "\n");
+ printk(KERN_INFO "hdlcdrv: version 0.8\n");
return 0;
}
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index 4c628393c8b1..0e4f23531140 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -923,13 +923,14 @@ static long mkiss_compat_ioctl(struct tty_struct *tty, struct file *file,
* a block of data has been received, which can now be decapsulated
* and sent on to the AX.25 layer for further processing.
*/
-static void mkiss_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+static unsigned int mkiss_receive_buf(struct tty_struct *tty,
+ const unsigned char *cp, char *fp, int count)
{
struct mkiss *ax = mkiss_get(tty);
+ int bytes = count;
if (!ax)
- return;
+ return -ENODEV;
/*
* Argh! mtu change time! - costs us the packet part received
@@ -939,7 +940,7 @@ static void mkiss_receive_buf(struct tty_struct *tty, const unsigned char *cp,
ax_changedmtu(ax);
/* Read the characters out of the buffer */
- while (count--) {
+ while (bytes--) {
if (fp != NULL && *fp++) {
if (!test_and_set_bit(AXF_ERROR, &ax->flags))
ax->dev->stats.rx_errors++;
@@ -952,6 +953,8 @@ static void mkiss_receive_buf(struct tty_struct *tty, const unsigned char *cp,
mkiss_put(ax);
tty_unthrottle(tty);
+
+ return count;
}
/*
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index 8e10d2f6a5ad..c52a1df5d922 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -188,14 +188,14 @@ struct hp100_private {
* variables
*/
#ifdef CONFIG_ISA
-static const char *hp100_isa_tbl[] = {
+static const char *const hp100_isa_tbl[] __devinitconst = {
"HWPF150", /* HP J2573 rev A */
"HWP1950", /* HP J2573 */
};
#endif
#ifdef CONFIG_EISA
-static struct eisa_device_id hp100_eisa_tbl[] = {
+static const struct eisa_device_id hp100_eisa_tbl[] __devinitconst = {
{ "HWPF180" }, /* HP J2577 rev A */
{ "HWP1920" }, /* HP 27248B */
{ "HWP1940" }, /* HP J2577 */
@@ -336,7 +336,7 @@ static __devinit const char *hp100_read_id(int ioaddr)
}
#ifdef CONFIG_ISA
-static __init int hp100_isa_probe1(struct net_device *dev, int ioaddr)
+static __devinit int hp100_isa_probe1(struct net_device *dev, int ioaddr)
{
const char *sig;
int i;
@@ -372,7 +372,7 @@ static __init int hp100_isa_probe1(struct net_device *dev, int ioaddr)
* EISA and PCI are handled by device infrastructure.
*/
-static int __init hp100_isa_probe(struct net_device *dev, int addr)
+static int __devinit hp100_isa_probe(struct net_device *dev, int addr)
{
int err = -ENODEV;
@@ -396,7 +396,7 @@ static int __init hp100_isa_probe(struct net_device *dev, int addr)
#endif /* CONFIG_ISA */
#if !defined(MODULE) && defined(CONFIG_ISA)
-struct net_device * __init hp100_probe(int unit)
+struct net_device * __devinit hp100_probe(int unit)
{
struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private));
int err;
@@ -2843,7 +2843,7 @@ static void cleanup_dev(struct net_device *d)
}
#ifdef CONFIG_EISA
-static int __init hp100_eisa_probe (struct device *gendev)
+static int __devinit hp100_eisa_probe (struct device *gendev)
{
struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private));
struct eisa_device *edev = to_eisa_device(gendev);
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index 3bb990b6651a..079450fe5e96 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -2053,13 +2053,6 @@ static void emac_ethtool_get_pauseparam(struct net_device *ndev,
mutex_unlock(&dev->link_lock);
}
-static u32 emac_ethtool_get_rx_csum(struct net_device *ndev)
-{
- struct emac_instance *dev = netdev_priv(ndev);
-
- return dev->tah_dev != NULL;
-}
-
static int emac_get_regs_len(struct emac_instance *dev)
{
if (emac_has_feature(dev, EMAC_FTR_EMAC4))
@@ -2203,15 +2196,11 @@ static const struct ethtool_ops emac_ethtool_ops = {
.get_ringparam = emac_ethtool_get_ringparam,
.get_pauseparam = emac_ethtool_get_pauseparam,
- .get_rx_csum = emac_ethtool_get_rx_csum,
-
.get_strings = emac_ethtool_get_strings,
.get_sset_count = emac_ethtool_get_sset_count,
.get_ethtool_stats = emac_ethtool_get_ethtool_stats,
.get_link = ethtool_op_get_link,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .get_sg = ethtool_op_get_sg,
};
static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
@@ -2859,8 +2848,10 @@ static int __devinit emac_probe(struct platform_device *ofdev)
if (err != 0)
goto err_detach_tah;
- if (dev->tah_dev)
- ndev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
+ if (dev->tah_dev) {
+ ndev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG;
+ ndev->features |= ndev->hw_features | NETIF_F_RXCSUM;
+ }
ndev->watchdog_timeo = 5 * HZ;
if (emac_phy_supports_gige(dev->phy_mode)) {
ndev->netdev_ops = &emac_gige_netdev_ops;
diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c
index 8ff68ae6b520..136d7544cc33 100644
--- a/drivers/net/ibmlana.c
+++ b/drivers/net/ibmlana.c
@@ -782,7 +782,8 @@ static int ibmlana_open(struct net_device *dev)
/* register resources - only necessary for IRQ */
- result = request_irq(priv->realirq, irq_handler, IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, dev);
+ result = request_irq(priv->realirq, irq_handler, IRQF_SHARED,
+ dev->name, dev);
if (result != 0) {
printk(KERN_ERR "%s: failed to register irq %d\n", dev->name, dev->irq);
return result;
@@ -894,12 +895,12 @@ static int ibmlana_irq;
static int ibmlana_io;
static int startslot; /* counts through slots when probing multiple devices */
-static short ibmlana_adapter_ids[] __initdata = {
+static const short ibmlana_adapter_ids[] __devinitconst = {
IBM_LANA_ID,
0x0000
};
-static char *ibmlana_adapter_names[] __devinitdata = {
+static const char *const ibmlana_adapter_names[] __devinitconst = {
"IBM LAN Adapter/A",
NULL
};
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index 5522d459654c..b388d782c7c4 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -710,7 +710,7 @@ static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
SUPPORTED_FIBRE);
cmd->advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg |
ADVERTISED_FIBRE);
- cmd->speed = SPEED_1000;
+ ethtool_cmd_speed_set(cmd, SPEED_1000);
cmd->duplex = DUPLEX_FULL;
cmd->port = PORT_FIBRE;
cmd->phy_address = 0;
@@ -729,45 +729,24 @@ static void netdev_get_drvinfo(struct net_device *dev,
sizeof(info->version) - 1);
}
-static void ibmveth_set_rx_csum_flags(struct net_device *dev, u32 data)
+static u32 ibmveth_fix_features(struct net_device *dev, u32 features)
{
- struct ibmveth_adapter *adapter = netdev_priv(dev);
-
- if (data) {
- adapter->rx_csum = 1;
- } else {
- /*
- * Since the ibmveth firmware interface does not have the
- * concept of separate tx/rx checksum offload enable, if rx
- * checksum is disabled we also have to disable tx checksum
- * offload. Once we disable rx checksum offload, we are no
- * longer allowed to send tx buffers that are not properly
- * checksummed.
- */
- adapter->rx_csum = 0;
- dev->features &= ~NETIF_F_IP_CSUM;
- dev->features &= ~NETIF_F_IPV6_CSUM;
- }
-}
+ /*
+ * Since the ibmveth firmware interface does not have the
+ * concept of separate tx/rx checksum offload enable, if rx
+ * checksum is disabled we also have to disable tx checksum
+ * offload. Once we disable rx checksum offload, we are no
+ * longer allowed to send tx buffers that are not properly
+ * checksummed.
+ */
-static void ibmveth_set_tx_csum_flags(struct net_device *dev, u32 data)
-{
- struct ibmveth_adapter *adapter = netdev_priv(dev);
+ if (!(features & NETIF_F_RXCSUM))
+ features &= ~NETIF_F_ALL_CSUM;
- if (data) {
- if (adapter->fw_ipv4_csum_support)
- dev->features |= NETIF_F_IP_CSUM;
- if (adapter->fw_ipv6_csum_support)
- dev->features |= NETIF_F_IPV6_CSUM;
- adapter->rx_csum = 1;
- } else {
- dev->features &= ~NETIF_F_IP_CSUM;
- dev->features &= ~NETIF_F_IPV6_CSUM;
- }
+ return features;
}
-static int ibmveth_set_csum_offload(struct net_device *dev, u32 data,
- void (*done) (struct net_device *, u32))
+static int ibmveth_set_csum_offload(struct net_device *dev, u32 data)
{
struct ibmveth_adapter *adapter = netdev_priv(dev);
unsigned long set_attr, clr_attr, ret_attr;
@@ -827,8 +806,8 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data,
} else
adapter->fw_ipv6_csum_support = data;
- if (ret == H_SUCCESS || ret6 == H_SUCCESS)
- done(dev, data);
+ if (ret != H_SUCCESS || ret6 != H_SUCCESS)
+ adapter->rx_csum = data;
else
rc1 = -EIO;
} else {
@@ -844,41 +823,22 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data,
return rc1 ? rc1 : rc2;
}
-static int ibmveth_set_rx_csum(struct net_device *dev, u32 data)
+static int ibmveth_set_features(struct net_device *dev, u32 features)
{
struct ibmveth_adapter *adapter = netdev_priv(dev);
+ int rx_csum = !!(features & NETIF_F_RXCSUM);
+ int rc;
- if ((data && adapter->rx_csum) || (!data && !adapter->rx_csum))
- return 0;
-
- return ibmveth_set_csum_offload(dev, data, ibmveth_set_rx_csum_flags);
-}
-
-static int ibmveth_set_tx_csum(struct net_device *dev, u32 data)
-{
- struct ibmveth_adapter *adapter = netdev_priv(dev);
- int rc = 0;
-
- if (data && (dev->features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)))
- return 0;
- if (!data && !(dev->features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)))
+ if (rx_csum == adapter->rx_csum)
return 0;
- if (data && !adapter->rx_csum)
- rc = ibmveth_set_csum_offload(dev, data,
- ibmveth_set_tx_csum_flags);
- else
- ibmveth_set_tx_csum_flags(dev, data);
+ rc = ibmveth_set_csum_offload(dev, rx_csum);
+ if (rc && !adapter->rx_csum)
+ dev->features = features & ~(NETIF_F_ALL_CSUM | NETIF_F_RXCSUM);
return rc;
}
-static u32 ibmveth_get_rx_csum(struct net_device *dev)
-{
- struct ibmveth_adapter *adapter = netdev_priv(dev);
- return adapter->rx_csum;
-}
-
static void ibmveth_get_strings(struct net_device *dev, u32 stringset, u8 *data)
{
int i;
@@ -914,13 +874,9 @@ static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
.get_settings = netdev_get_settings,
.get_link = ethtool_op_get_link,
- .set_tx_csum = ibmveth_set_tx_csum,
- .get_rx_csum = ibmveth_get_rx_csum,
- .set_rx_csum = ibmveth_set_rx_csum,
.get_strings = ibmveth_get_strings,
.get_sset_count = ibmveth_get_sset_count,
.get_ethtool_stats = ibmveth_get_ethtool_stats,
- .set_sg = ethtool_op_set_sg,
};
static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
@@ -1345,6 +1301,8 @@ static const struct net_device_ops ibmveth_netdev_ops = {
.ndo_set_multicast_list = ibmveth_set_multicast_list,
.ndo_do_ioctl = ibmveth_ioctl,
.ndo_change_mtu = ibmveth_change_mtu,
+ .ndo_fix_features = ibmveth_fix_features,
+ .ndo_set_features = ibmveth_set_features,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -1412,7 +1370,9 @@ static int __devinit ibmveth_probe(struct vio_dev *dev,
netdev->netdev_ops = &ibmveth_netdev_ops;
netdev->ethtool_ops = &netdev_ethtool_ops;
SET_NETDEV_DEV(netdev, &dev->dev);
- netdev->features |= NETIF_F_SG;
+ netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM |
+ NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+ netdev->features |= netdev->hw_features;
memcpy(netdev->dev_addr, &adapter->mac_addr, netdev->addr_len);
@@ -1437,7 +1397,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev,
netdev_dbg(netdev, "registering netdev...\n");
- ibmveth_set_csum_offload(netdev, 1, ibmveth_set_tx_csum_flags);
+ ibmveth_set_features(netdev, netdev->features);
rc = register_netdev(netdev);
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index e07d487f015a..4fecaed67fc4 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -233,10 +233,6 @@ static int __init ifb_init_one(int index)
if (!dev_ifb)
return -ENOMEM;
- err = dev_alloc_name(dev_ifb, dev_ifb->name);
- if (err < 0)
- goto err;
-
dev_ifb->rtnl_link_ops = &ifb_link_ops;
err = register_netdevice(dev_ifb);
if (err < 0)
diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c
index 6b256c275e10..0f563c8c5ffc 100644
--- a/drivers/net/igb/e1000_82575.c
+++ b/drivers/net/igb/e1000_82575.c
@@ -244,6 +244,14 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
*/
size += NVM_WORD_SIZE_BASE_SHIFT;
+ /*
+ * Check for invalid size
+ */
+ if ((hw->mac.type == e1000_82576) && (size > 15)) {
+ printk("igb: The NVM size is not valid, "
+ "defaulting to 32K.\n");
+ size = 15;
+ }
nvm->word_size = 1 << size;
if (nvm->word_size == (1 << 15))
nvm->page_size = 128;
@@ -1877,7 +1885,7 @@ static s32 igb_validate_nvm_checksum_82580(struct e1000_hw *hw)
}
if (nvm_data & NVM_COMPATIBILITY_BIT_MASK) {
- /* if chekcsums compatibility bit is set validate checksums
+ /* if checksums compatibility bit is set validate checksums
* for all 4 ports. */
eeprom_regions_count = 4;
}
@@ -1988,6 +1996,7 @@ static s32 igb_update_nvm_checksum_i350(struct e1000_hw *hw)
out:
return ret_val;
}
+
/**
* igb_set_eee_i350 - Enable/disable EEE support
* @hw: pointer to the HW structure
diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h
index 1c687e298d5e..f4fa4b1751cf 100644
--- a/drivers/net/igb/igb.h
+++ b/drivers/net/igb/igb.h
@@ -360,7 +360,7 @@ extern int igb_up(struct igb_adapter *);
extern void igb_down(struct igb_adapter *);
extern void igb_reinit_locked(struct igb_adapter *);
extern void igb_reset(struct igb_adapter *);
-extern int igb_set_spd_dplx(struct igb_adapter *, u16);
+extern int igb_set_spd_dplx(struct igb_adapter *, u32, u8);
extern int igb_setup_tx_resources(struct igb_ring *);
extern int igb_setup_rx_resources(struct igb_ring *);
extern void igb_free_tx_resources(struct igb_ring *);
diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c
index d976733bbcc2..fdc895e5a3f8 100644
--- a/drivers/net/igb/igb_ethtool.c
+++ b/drivers/net/igb/igb_ethtool.c
@@ -178,11 +178,11 @@ static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
if ((status & E1000_STATUS_SPEED_1000) ||
hw->phy.media_type != e1000_media_type_copper)
- ecmd->speed = SPEED_1000;
+ ethtool_cmd_speed_set(ecmd, SPEED_1000);
else if (status & E1000_STATUS_SPEED_100)
- ecmd->speed = SPEED_100;
+ ethtool_cmd_speed_set(ecmd, SPEED_100);
else
- ecmd->speed = SPEED_10;
+ ethtool_cmd_speed_set(ecmd, SPEED_10);
if ((status & E1000_STATUS_FD) ||
hw->phy.media_type != e1000_media_type_copper)
@@ -190,7 +190,7 @@ static int igb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
else
ecmd->duplex = DUPLEX_HALF;
} else {
- ecmd->speed = -1;
+ ethtool_cmd_speed_set(ecmd, -1);
ecmd->duplex = -1;
}
@@ -223,7 +223,8 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
if (adapter->fc_autoneg)
hw->fc.requested_mode = e1000_fc_default;
} else {
- if (igb_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) {
+ u32 speed = ethtool_cmd_speed(ecmd);
+ if (igb_set_spd_dplx(adapter, speed, ecmd->duplex)) {
clear_bit(__IGB_RESETTING, &adapter->state);
return -EINVAL;
}
@@ -1963,27 +1964,28 @@ static int igb_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
/* bit defines for adapter->led_status */
#define IGB_LED_ON 0
-static int igb_phys_id(struct net_device *netdev, u32 data)
+static int igb_set_phys_id(struct net_device *netdev,
+ enum ethtool_phys_id_state state)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
- unsigned long timeout;
- timeout = data * 1000;
-
- /*
- * msleep_interruptable only accepts unsigned int so we are limited
- * in how long a duration we can wait
- */
- if (!timeout || timeout > UINT_MAX)
- timeout = UINT_MAX;
-
- igb_blink_led(hw);
- msleep_interruptible(timeout);
-
- igb_led_off(hw);
- clear_bit(IGB_LED_ON, &adapter->led_status);
- igb_cleanup_led(hw);
+ switch (state) {
+ case ETHTOOL_ID_ACTIVE:
+ igb_blink_led(hw);
+ return 2;
+ case ETHTOOL_ID_ON:
+ igb_blink_led(hw);
+ break;
+ case ETHTOOL_ID_OFF:
+ igb_led_off(hw);
+ break;
+ case ETHTOOL_ID_INACTIVE:
+ igb_led_off(hw);
+ clear_bit(IGB_LED_ON, &adapter->led_status);
+ igb_cleanup_led(hw);
+ break;
+ }
return 0;
}
@@ -2215,7 +2217,7 @@ static const struct ethtool_ops igb_ethtool_ops = {
.set_tso = igb_set_tso,
.self_test = igb_diag_test,
.get_strings = igb_get_strings,
- .phys_id = igb_phys_id,
+ .set_phys_id = igb_set_phys_id,
.get_sset_count = igb_get_sset_count,
.get_ethtool_stats = igb_get_ethtool_stats,
.get_coalesce = igb_get_coalesce,
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c
index 0dfd1b93829e..18fccf913635 100644
--- a/drivers/net/igb/igb_main.c
+++ b/drivers/net/igb/igb_main.c
@@ -45,6 +45,7 @@
#include <linux/interrupt.h>
#include <linux/if_ether.h>
#include <linux/aer.h>
+#include <linux/prefetch.h>
#ifdef CONFIG_IGB_DCA
#include <linux/dca.h>
#endif
@@ -3532,6 +3533,25 @@ bool igb_has_link(struct igb_adapter *adapter)
return link_active;
}
+static bool igb_thermal_sensor_event(struct e1000_hw *hw, u32 event)
+{
+ bool ret = false;
+ u32 ctrl_ext, thstat;
+
+ /* check for thermal sensor event on i350, copper only */
+ if (hw->mac.type == e1000_i350) {
+ thstat = rd32(E1000_THSTAT);
+ ctrl_ext = rd32(E1000_CTRL_EXT);
+
+ if ((hw->phy.media_type == e1000_media_type_copper) &&
+ !(ctrl_ext & E1000_CTRL_EXT_LINK_MODE_SGMII)) {
+ ret = !!(thstat & event);
+ }
+ }
+
+ return ret;
+}
+
/**
* igb_watchdog - Timer Call-back
* @data: pointer to adapter cast into an unsigned long
@@ -3550,7 +3570,7 @@ static void igb_watchdog_task(struct work_struct *work)
watchdog_task);
struct e1000_hw *hw = &adapter->hw;
struct net_device *netdev = adapter->netdev;
- u32 link, ctrl_ext, thstat;
+ u32 link;
int i;
link = igb_has_link(adapter);
@@ -3574,25 +3594,14 @@ static void igb_watchdog_task(struct work_struct *work)
((ctrl & E1000_CTRL_RFCE) ? "RX" :
((ctrl & E1000_CTRL_TFCE) ? "TX" : "None")));
- /* check for thermal sensor event on i350,
- * copper only */
- if (hw->mac.type == e1000_i350) {
- thstat = rd32(E1000_THSTAT);
- ctrl_ext = rd32(E1000_CTRL_EXT);
- if ((hw->phy.media_type ==
- e1000_media_type_copper) && !(ctrl_ext &
- E1000_CTRL_EXT_LINK_MODE_SGMII)) {
- if (thstat &
- E1000_THSTAT_LINK_THROTTLE) {
- printk(KERN_INFO "igb: %s The "
- "network adapter link "
- "speed was downshifted "
- "because it "
- "overheated.\n",
- netdev->name);
- }
- }
+ /* check for thermal sensor event */
+ if (igb_thermal_sensor_event(hw, E1000_THSTAT_LINK_THROTTLE)) {
+ printk(KERN_INFO "igb: %s The network adapter "
+ "link speed was downshifted "
+ "because it overheated.\n",
+ netdev->name);
}
+
/* adjust timeout factor according to speed/duplex */
adapter->tx_timeout_factor = 1;
switch (adapter->link_speed) {
@@ -3618,22 +3627,15 @@ static void igb_watchdog_task(struct work_struct *work)
if (netif_carrier_ok(netdev)) {
adapter->link_speed = 0;
adapter->link_duplex = 0;
- /* check for thermal sensor event on i350
- * copper only*/
- if (hw->mac.type == e1000_i350) {
- thstat = rd32(E1000_THSTAT);
- ctrl_ext = rd32(E1000_CTRL_EXT);
- if ((hw->phy.media_type ==
- e1000_media_type_copper) && !(ctrl_ext &
- E1000_CTRL_EXT_LINK_MODE_SGMII)) {
- if (thstat & E1000_THSTAT_PWR_DOWN) {
- printk(KERN_ERR "igb: %s The "
- "network adapter was stopped "
- "because it overheated.\n",
+
+ /* check for thermal sensor event */
+ if (igb_thermal_sensor_event(hw, E1000_THSTAT_PWR_DOWN)) {
+ printk(KERN_ERR "igb: %s The network adapter "
+ "was stopped because it "
+ "overheated.\n",
netdev->name);
- }
- }
}
+
/* Links status message must follow this format */
printk(KERN_INFO "igb: %s NIC Link is Down\n",
netdev->name);
@@ -6348,21 +6350,25 @@ static void igb_restore_vlan(struct igb_adapter *adapter)
}
}
-int igb_set_spd_dplx(struct igb_adapter *adapter, u16 spddplx)
+int igb_set_spd_dplx(struct igb_adapter *adapter, u32 spd, u8 dplx)
{
struct pci_dev *pdev = adapter->pdev;
struct e1000_mac_info *mac = &adapter->hw.mac;
mac->autoneg = 0;
+ /* Make sure dplx is at most 1 bit and lsb of speed is not set
+ * for the switch() below to work */
+ if ((spd & 1) || (dplx & ~1))
+ goto err_inval;
+
/* Fiber NIC's only allow 1000 Gbps Full duplex */
if ((adapter->hw.phy.media_type == e1000_media_type_internal_serdes) &&
- spddplx != (SPEED_1000 + DUPLEX_FULL)) {
- dev_err(&pdev->dev, "Unsupported Speed/Duplex configuration\n");
- return -EINVAL;
- }
+ spd != SPEED_1000 &&
+ dplx != DUPLEX_FULL)
+ goto err_inval;
- switch (spddplx) {
+ switch (spd + dplx) {
case SPEED_10 + DUPLEX_HALF:
mac->forced_speed_duplex = ADVERTISE_10_HALF;
break;
@@ -6381,10 +6387,13 @@ int igb_set_spd_dplx(struct igb_adapter *adapter, u16 spddplx)
break;
case SPEED_1000 + DUPLEX_HALF: /* not supported */
default:
- dev_err(&pdev->dev, "Unsupported Speed/Duplex configuration\n");
- return -EINVAL;
+ goto err_inval;
}
return 0;
+
+err_inval:
+ dev_err(&pdev->dev, "Unsupported Speed/Duplex configuration\n");
+ return -EINVAL;
}
static int __igb_shutdown(struct pci_dev *pdev, bool *enable_wake)
diff --git a/drivers/net/igbvf/ethtool.c b/drivers/net/igbvf/ethtool.c
index 1d943aa7c7a6..b0b14d63dfbf 100644
--- a/drivers/net/igbvf/ethtool.c
+++ b/drivers/net/igbvf/ethtool.c
@@ -90,18 +90,18 @@ static int igbvf_get_settings(struct net_device *netdev,
status = er32(STATUS);
if (status & E1000_STATUS_LU) {
if (status & E1000_STATUS_SPEED_1000)
- ecmd->speed = 1000;
+ ethtool_cmd_speed_set(ecmd, SPEED_1000);
else if (status & E1000_STATUS_SPEED_100)
- ecmd->speed = 100;
+ ethtool_cmd_speed_set(ecmd, SPEED_100);
else
- ecmd->speed = 10;
+ ethtool_cmd_speed_set(ecmd, SPEED_10);
if (status & E1000_STATUS_FD)
ecmd->duplex = DUPLEX_FULL;
else
ecmd->duplex = DUPLEX_HALF;
} else {
- ecmd->speed = -1;
+ ethtool_cmd_speed_set(ecmd, -1);
ecmd->duplex = -1;
}
@@ -391,11 +391,6 @@ static int igbvf_set_wol(struct net_device *netdev,
return -EOPNOTSUPP;
}
-static int igbvf_phys_id(struct net_device *netdev, u32 data)
-{
- return 0;
-}
-
static int igbvf_get_coalesce(struct net_device *netdev,
struct ethtool_coalesce *ec)
{
@@ -527,7 +522,6 @@ static const struct ethtool_ops igbvf_ethtool_ops = {
.self_test = igbvf_diag_test,
.get_sset_count = igbvf_get_sset_count,
.get_strings = igbvf_get_strings,
- .phys_id = igbvf_phys_id,
.get_ethtool_stats = igbvf_get_ethtool_stats,
.get_coalesce = igbvf_get_coalesce,
.set_coalesce = igbvf_set_coalesce,
diff --git a/drivers/net/igbvf/netdev.c b/drivers/net/igbvf/netdev.c
index 1d04ca6fdaea..1c77fb3bf4ae 100644
--- a/drivers/net/igbvf/netdev.c
+++ b/drivers/net/igbvf/netdev.c
@@ -41,6 +41,7 @@
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
+#include <linux/prefetch.h>
#include "igbvf.h"
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index c8ee8d28767b..32f07f868d89 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -90,8 +90,6 @@ struct ioc3_private {
u32 emcr, ehar_h, ehar_l;
spinlock_t ioc3_lock;
struct mii_if_info mii;
- unsigned long flags;
-#define IOC3_FLAG_RX_CHECKSUMS 1
struct pci_dev *pdev;
@@ -609,7 +607,7 @@ static inline void ioc3_rx(struct net_device *dev)
goto next;
}
- if (likely(ip->flags & IOC3_FLAG_RX_CHECKSUMS))
+ if (likely(dev->features & NETIF_F_RXCSUM))
ioc3_tcpudp_checksum(skb,
w0 & ERXBUF_IPCKSUM_MASK, len);
@@ -917,7 +915,7 @@ static void ioc3_alloc_rings(struct net_device *dev)
skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC);
if (!skb) {
- show_free_areas();
+ show_free_areas(0);
continue;
}
@@ -1328,6 +1326,7 @@ static int __devinit ioc3_probe(struct pci_dev *pdev,
dev->watchdog_timeo = 5 * HZ;
dev->netdev_ops = &ioc3_netdev_ops;
dev->ethtool_ops = &ioc3_ethtool_ops;
+ dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
dev->features = NETIF_F_IP_CSUM;
sw_physid1 = ioc3_mdio_read(dev, ip->mii.phy_id, MII_PHYSID1);
@@ -1618,37 +1617,12 @@ static u32 ioc3_get_link(struct net_device *dev)
return rc;
}
-static u32 ioc3_get_rx_csum(struct net_device *dev)
-{
- struct ioc3_private *ip = netdev_priv(dev);
-
- return ip->flags & IOC3_FLAG_RX_CHECKSUMS;
-}
-
-static int ioc3_set_rx_csum(struct net_device *dev, u32 data)
-{
- struct ioc3_private *ip = netdev_priv(dev);
-
- spin_lock_bh(&ip->ioc3_lock);
- if (data)
- ip->flags |= IOC3_FLAG_RX_CHECKSUMS;
- else
- ip->flags &= ~IOC3_FLAG_RX_CHECKSUMS;
- spin_unlock_bh(&ip->ioc3_lock);
-
- return 0;
-}
-
static const struct ethtool_ops ioc3_ethtool_ops = {
.get_drvinfo = ioc3_get_drvinfo,
.get_settings = ioc3_get_settings,
.set_settings = ioc3_set_settings,
.nway_reset = ioc3_nway_reset,
.get_link = ioc3_get_link,
- .get_rx_csum = ioc3_get_rx_csum,
- .set_rx_csum = ioc3_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = ethtool_op_set_tx_csum
};
static int ioc3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
index 872183f29ec4..d532dde5120f 100644
--- a/drivers/net/irda/ali-ircc.c
+++ b/drivers/net/irda/ali-ircc.c
@@ -1800,7 +1800,7 @@ static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self)
MessageCount = inb(iobase+ FIR_LSR)&0x07;
if (MessageCount > 0)
- IRDA_DEBUG(0, "%s(), Messsage count = %d,\n", __func__ , MessageCount);
+ IRDA_DEBUG(0, "%s(), Message count = %d,\n", __func__ , MessageCount);
for (i=0; i<=MessageCount; i++)
{
diff --git a/drivers/net/irda/bfin_sir.c b/drivers/net/irda/bfin_sir.c
index f940dfa1f7f8..9d4ce1aba10c 100644
--- a/drivers/net/irda/bfin_sir.c
+++ b/drivers/net/irda/bfin_sir.c
@@ -67,27 +67,27 @@ static void bfin_sir_stop_tx(struct bfin_sir_port *port)
disable_dma(port->tx_dma_channel);
#endif
- while (!(SIR_UART_GET_LSR(port) & THRE)) {
+ while (!(UART_GET_LSR(port) & THRE)) {
cpu_relax();
continue;
}
- SIR_UART_STOP_TX(port);
+ UART_CLEAR_IER(port, ETBEI);
}
static void bfin_sir_enable_tx(struct bfin_sir_port *port)
{
- SIR_UART_ENABLE_TX(port);
+ UART_SET_IER(port, ETBEI);
}
static void bfin_sir_stop_rx(struct bfin_sir_port *port)
{
- SIR_UART_STOP_RX(port);
+ UART_CLEAR_IER(port, ERBFI);
}
static void bfin_sir_enable_rx(struct bfin_sir_port *port)
{
- SIR_UART_ENABLE_RX(port);
+ UART_SET_IER(port, ERBFI);
}
static int bfin_sir_set_speed(struct bfin_sir_port *port, int speed)
@@ -116,7 +116,7 @@ static int bfin_sir_set_speed(struct bfin_sir_port *port, int speed)
do {
udelay(utime);
- lsr = SIR_UART_GET_LSR(port);
+ lsr = UART_GET_LSR(port);
} while (!(lsr & TEMT) && count--);
/* The useconds for 1 bits to transmit */
@@ -125,27 +125,27 @@ static int bfin_sir_set_speed(struct bfin_sir_port *port, int speed)
/* Clear UCEN bit to reset the UART state machine
* and control registers
*/
- val = SIR_UART_GET_GCTL(port);
+ val = UART_GET_GCTL(port);
val &= ~UCEN;
- SIR_UART_PUT_GCTL(port, val);
+ UART_PUT_GCTL(port, val);
/* Set DLAB in LCR to Access THR RBR IER */
- SIR_UART_SET_DLAB(port);
+ UART_SET_DLAB(port);
SSYNC();
- SIR_UART_PUT_DLL(port, quot & 0xFF);
- SIR_UART_PUT_DLH(port, (quot >> 8) & 0xFF);
+ UART_PUT_DLL(port, quot & 0xFF);
+ UART_PUT_DLH(port, (quot >> 8) & 0xFF);
SSYNC();
/* Clear DLAB in LCR */
- SIR_UART_CLEAR_DLAB(port);
+ UART_CLEAR_DLAB(port);
SSYNC();
- SIR_UART_PUT_LCR(port, lcr);
+ UART_PUT_LCR(port, lcr);
- val = SIR_UART_GET_GCTL(port);
+ val = UART_GET_GCTL(port);
val |= UCEN;
- SIR_UART_PUT_GCTL(port, val);
+ UART_PUT_GCTL(port, val);
ret = 0;
break;
@@ -154,12 +154,12 @@ static int bfin_sir_set_speed(struct bfin_sir_port *port, int speed)
break;
}
- val = SIR_UART_GET_GCTL(port);
+ val = UART_GET_GCTL(port);
/* If not add the 'RPOLC', we can't catch the receive interrupt.
* It's related with the HW layout and the IR transiver.
*/
val |= IREN | RPOLC;
- SIR_UART_PUT_GCTL(port, val);
+ UART_PUT_GCTL(port, val);
return ret;
}
@@ -168,7 +168,7 @@ static int bfin_sir_is_receiving(struct net_device *dev)
struct bfin_sir_self *self = netdev_priv(dev);
struct bfin_sir_port *port = self->sir_port;
- if (!(SIR_UART_GET_IER(port) & ERBFI))
+ if (!(UART_GET_IER(port) & ERBFI))
return 0;
return self->rx_buff.state != OUTSIDE_FRAME;
}
@@ -182,7 +182,7 @@ static void bfin_sir_tx_chars(struct net_device *dev)
if (self->tx_buff.len != 0) {
chr = *(self->tx_buff.data);
- SIR_UART_PUT_CHAR(port, chr);
+ UART_PUT_CHAR(port, chr);
self->tx_buff.data++;
self->tx_buff.len--;
} else {
@@ -206,8 +206,8 @@ static void bfin_sir_rx_chars(struct net_device *dev)
struct bfin_sir_port *port = self->sir_port;
unsigned char ch;
- SIR_UART_CLEAR_LSR(port);
- ch = SIR_UART_GET_CHAR(port);
+ UART_CLEAR_LSR(port);
+ ch = UART_GET_CHAR(port);
async_unwrap_char(dev, &self->stats, &self->rx_buff, ch);
dev->last_rx = jiffies;
}
@@ -219,7 +219,7 @@ static irqreturn_t bfin_sir_rx_int(int irq, void *dev_id)
struct bfin_sir_port *port = self->sir_port;
spin_lock(&self->lock);
- while ((SIR_UART_GET_LSR(port) & DR))
+ while ((UART_GET_LSR(port) & DR))
bfin_sir_rx_chars(dev);
spin_unlock(&self->lock);
@@ -233,7 +233,7 @@ static irqreturn_t bfin_sir_tx_int(int irq, void *dev_id)
struct bfin_sir_port *port = self->sir_port;
spin_lock(&self->lock);
- if (SIR_UART_GET_LSR(port) & THRE)
+ if (UART_GET_LSR(port) & THRE)
bfin_sir_tx_chars(dev);
spin_unlock(&self->lock);
@@ -312,7 +312,7 @@ static void bfin_sir_dma_rx_chars(struct net_device *dev)
struct bfin_sir_port *port = self->sir_port;
int i;
- SIR_UART_CLEAR_LSR(port);
+ UART_CLEAR_LSR(port);
for (i = port->rx_dma_buf.head; i < port->rx_dma_buf.tail; i++)
async_unwrap_char(dev, &self->stats, &self->rx_buff, port->rx_dma_buf.buf[i]);
@@ -430,11 +430,10 @@ static void bfin_sir_shutdown(struct bfin_sir_port *port, struct net_device *dev
unsigned short val;
bfin_sir_stop_rx(port);
- SIR_UART_DISABLE_INTS(port);
- val = SIR_UART_GET_GCTL(port);
+ val = UART_GET_GCTL(port);
val &= ~(UCEN | IREN | RPOLC);
- SIR_UART_PUT_GCTL(port, val);
+ UART_PUT_GCTL(port, val);
#ifdef CONFIG_SIR_BFIN_DMA
disable_dma(port->tx_dma_channel);
@@ -518,12 +517,12 @@ static void bfin_sir_send_work(struct work_struct *work)
* sending data. We also can set the speed, which will
* reset all the UART.
*/
- val = SIR_UART_GET_GCTL(port);
+ val = UART_GET_GCTL(port);
val &= ~(IREN | RPOLC);
- SIR_UART_PUT_GCTL(port, val);
+ UART_PUT_GCTL(port, val);
SSYNC();
val |= IREN | RPOLC;
- SIR_UART_PUT_GCTL(port, val);
+ UART_PUT_GCTL(port, val);
SSYNC();
/* bfin_sir_set_speed(port, self->speed); */
diff --git a/drivers/net/irda/bfin_sir.h b/drivers/net/irda/bfin_sir.h
index e3b285a67734..29cbde8501ed 100644
--- a/drivers/net/irda/bfin_sir.h
+++ b/drivers/net/irda/bfin_sir.h
@@ -26,7 +26,6 @@
#include <asm/cacheflush.h>
#include <asm/dma.h>
#include <asm/portmux.h>
-#include <mach/bfin_serial_5xx.h>
#undef DRIVER_NAME
#ifdef CONFIG_SIR_BFIN_DMA
@@ -83,64 +82,10 @@ struct bfin_sir_self {
#define DRIVER_NAME "bfin_sir"
-#define SIR_UART_GET_CHAR(port) bfin_read16((port)->membase + OFFSET_RBR)
-#define SIR_UART_GET_DLL(port) bfin_read16((port)->membase + OFFSET_DLL)
-#define SIR_UART_GET_DLH(port) bfin_read16((port)->membase + OFFSET_DLH)
-#define SIR_UART_GET_LCR(port) bfin_read16((port)->membase + OFFSET_LCR)
-#define SIR_UART_GET_GCTL(port) bfin_read16((port)->membase + OFFSET_GCTL)
-
-#define SIR_UART_PUT_CHAR(port, v) bfin_write16(((port)->membase + OFFSET_THR), v)
-#define SIR_UART_PUT_DLL(port, v) bfin_write16(((port)->membase + OFFSET_DLL), v)
-#define SIR_UART_PUT_DLH(port, v) bfin_write16(((port)->membase + OFFSET_DLH), v)
-#define SIR_UART_PUT_LCR(port, v) bfin_write16(((port)->membase + OFFSET_LCR), v)
-#define SIR_UART_PUT_GCTL(port, v) bfin_write16(((port)->membase + OFFSET_GCTL), v)
-
-#ifdef CONFIG_BF54x
-#define SIR_UART_GET_LSR(port) bfin_read16((port)->membase + OFFSET_LSR)
-#define SIR_UART_GET_IER(port) bfin_read16((port)->membase + OFFSET_IER_SET)
-#define SIR_UART_SET_IER(port, v) bfin_write16(((port)->membase + OFFSET_IER_SET), v)
-#define SIR_UART_CLEAR_IER(port, v) bfin_write16(((port)->membase + OFFSET_IER_CLEAR), v)
-#define SIR_UART_PUT_LSR(port, v) bfin_write16(((port)->membase + OFFSET_LSR), v)
-#define SIR_UART_CLEAR_LSR(port) bfin_write16(((port)->membase + OFFSET_LSR), -1)
-
-#define SIR_UART_SET_DLAB(port)
-#define SIR_UART_CLEAR_DLAB(port)
-
-#define SIR_UART_ENABLE_INTS(port, v) SIR_UART_SET_IER(port, v)
-#define SIR_UART_DISABLE_INTS(port) SIR_UART_CLEAR_IER(port, 0xF)
-#define SIR_UART_STOP_TX(port) do { SIR_UART_PUT_LSR(port, TFI); SIR_UART_CLEAR_IER(port, ETBEI); } while (0)
-#define SIR_UART_ENABLE_TX(port) do { SIR_UART_SET_IER(port, ETBEI); } while (0)
-#define SIR_UART_STOP_RX(port) do { SIR_UART_CLEAR_IER(port, ERBFI); } while (0)
-#define SIR_UART_ENABLE_RX(port) do { SIR_UART_SET_IER(port, ERBFI); } while (0)
-#else
-
-#define SIR_UART_GET_IIR(port) bfin_read16((port)->membase + OFFSET_IIR)
-#define SIR_UART_GET_IER(port) bfin_read16((port)->membase + OFFSET_IER)
-#define SIR_UART_PUT_IER(port, v) bfin_write16(((port)->membase + OFFSET_IER), v)
-
-#define SIR_UART_SET_DLAB(port) do { SIR_UART_PUT_LCR(port, SIR_UART_GET_LCR(port) | DLAB); } while (0)
-#define SIR_UART_CLEAR_DLAB(port) do { SIR_UART_PUT_LCR(port, SIR_UART_GET_LCR(port) & ~DLAB); } while (0)
-
-#define SIR_UART_ENABLE_INTS(port, v) SIR_UART_PUT_IER(port, v)
-#define SIR_UART_DISABLE_INTS(port) SIR_UART_PUT_IER(port, 0)
-#define SIR_UART_STOP_TX(port) do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) & ~ETBEI); } while (0)
-#define SIR_UART_ENABLE_TX(port) do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) | ETBEI); } while (0)
-#define SIR_UART_STOP_RX(port) do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) & ~ERBFI); } while (0)
-#define SIR_UART_ENABLE_RX(port) do { SIR_UART_PUT_IER(port, SIR_UART_GET_IER(port) | ERBFI); } while (0)
-
-static inline unsigned int SIR_UART_GET_LSR(struct bfin_sir_port *port)
-{
- unsigned int lsr = bfin_read16(port->membase + OFFSET_LSR);
- port->lsr |= (lsr & (BI|FE|PE|OE));
- return lsr | port->lsr;
-}
-
-static inline void SIR_UART_CLEAR_LSR(struct bfin_sir_port *port)
-{
- port->lsr = 0;
- bfin_read16(port->membase + OFFSET_LSR);
-}
-#endif
+#define port_membase(port) (((struct bfin_sir_port *)(port))->membase)
+#define get_lsr_cache(port) (((struct bfin_sir_port *)(port))->lsr)
+#define put_lsr_cache(port, v) (((struct bfin_sir_port *)(port))->lsr = (v))
+#include <asm/bfin_serial.h>
static const unsigned short per[][4] = {
/* rx pin tx pin NULL uart_number */
diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
index 3352b2443e58..035861d8acb1 100644
--- a/drivers/net/irda/irtty-sir.c
+++ b/drivers/net/irda/irtty-sir.c
@@ -216,23 +216,23 @@ static int irtty_do_write(struct sir_dev *dev, const unsigned char *ptr, size_t
* usbserial: urb-complete-interrupt / softint
*/
-static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+static unsigned int irtty_receive_buf(struct tty_struct *tty,
+ const unsigned char *cp, char *fp, int count)
{
struct sir_dev *dev;
struct sirtty_cb *priv = tty->disc_data;
int i;
- IRDA_ASSERT(priv != NULL, return;);
- IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);
+ IRDA_ASSERT(priv != NULL, return -ENODEV;);
+ IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -EINVAL;);
if (unlikely(count==0)) /* yes, this happens */
- return;
+ return 0;
dev = priv->dev;
if (!dev) {
IRDA_WARNING("%s(), not ready yet!\n", __func__);
- return;
+ return -ENODEV;
}
for (i = 0; i < count; i++) {
@@ -242,11 +242,13 @@ static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
if (fp && *fp++) {
IRDA_DEBUG(0, "Framing or parity error!\n");
sirdev_receive(dev, NULL, 0); /* notify sir_dev (updating stats) */
- return;
+ return -EINVAL;
}
}
sirdev_receive(dev, cp, count);
+
+ return count;
}
/*
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index 8800e1fe4129..69b5707db369 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -222,19 +222,19 @@ static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 s
static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self);
/* Probing */
-static int __init smsc_ircc_look_for_chips(void);
-static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type);
-static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfg_base, char *type);
-static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type);
-static int __init smsc_superio_fdc(unsigned short cfg_base);
-static int __init smsc_superio_lpc(unsigned short cfg_base);
+static int smsc_ircc_look_for_chips(void);
+static const struct smsc_chip * smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type);
+static int smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfg_base, char *type);
+static int smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type);
+static int smsc_superio_fdc(unsigned short cfg_base);
+static int smsc_superio_lpc(unsigned short cfg_base);
#ifdef CONFIG_PCI
-static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf);
-static int __init preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf);
-static void __init preconfigure_ali_port(struct pci_dev *dev,
+static int preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf);
+static int preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf);
+static void preconfigure_ali_port(struct pci_dev *dev,
unsigned short port);
-static int __init preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf);
-static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg,
+static int preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf);
+static int smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg,
unsigned short ircc_fir,
unsigned short ircc_sir,
unsigned char ircc_dma,
@@ -366,7 +366,7 @@ static inline void register_bank(int iobase, int bank)
}
/* PNP hotplug support */
-static const struct pnp_device_id smsc_ircc_pnp_table[] = {
+static const struct pnp_device_id smsc_ircc_pnp_table[] __devinitconst = {
{ .id = "SMCf010", .driver_data = 0 },
/* and presumably others */
{ }
@@ -515,7 +515,7 @@ static const struct net_device_ops smsc_ircc_netdev_ops = {
* Try to open driver instance
*
*/
-static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq)
+static int __devinit smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq)
{
struct smsc_ircc_cb *self;
struct net_device *dev;
@@ -2273,7 +2273,7 @@ static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned sho
}
-static int __init smsc_access(unsigned short cfg_base, unsigned char reg)
+static int __devinit smsc_access(unsigned short cfg_base, unsigned char reg)
{
IRDA_DEBUG(1, "%s\n", __func__);
@@ -2281,7 +2281,7 @@ static int __init smsc_access(unsigned short cfg_base, unsigned char reg)
return inb(cfg_base) != reg ? -1 : 0;
}
-static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type)
+static const struct smsc_chip * __devinit smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type)
{
u8 devid, xdevid, rev;
@@ -2406,7 +2406,7 @@ static int __init smsc_superio_lpc(unsigned short cfg_base)
#ifdef CONFIG_PCI
#define PCIID_VENDOR_INTEL 0x8086
#define PCIID_VENDOR_ALI 0x10b9
-static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __initdata = {
+static const struct smsc_ircc_subsystem_configuration subsystem_configurations[] __devinitconst = {
/*
* Subsystems needing entries:
* 0x10b9:0x1533 0x103c:0x0850 HP nx9010 family
@@ -2532,7 +2532,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini
* (FIR port, SIR port, FIR DMA, FIR IRQ)
* through the chip configuration port.
*/
-static int __init preconfigure_smsc_chip(struct
+static int __devinit preconfigure_smsc_chip(struct
smsc_ircc_subsystem_configuration
*conf)
{
@@ -2633,7 +2633,7 @@ static int __init preconfigure_smsc_chip(struct
* or Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge.
* They all work the same way!
*/
-static int __init preconfigure_through_82801(struct pci_dev *dev,
+static int __devinit preconfigure_through_82801(struct pci_dev *dev,
struct
smsc_ircc_subsystem_configuration
*conf)
@@ -2786,7 +2786,7 @@ static int __init preconfigure_through_82801(struct pci_dev *dev,
* This is based on reverse-engineering since ALi does not
* provide any data sheet for the 1533 chip.
*/
-static void __init preconfigure_ali_port(struct pci_dev *dev,
+static void __devinit preconfigure_ali_port(struct pci_dev *dev,
unsigned short port)
{
unsigned char reg;
@@ -2824,7 +2824,7 @@ static void __init preconfigure_ali_port(struct pci_dev *dev,
IRDA_MESSAGE("Activated ALi 1533 ISA bridge port 0x%04x.\n", port);
}
-static int __init preconfigure_through_ali(struct pci_dev *dev,
+static int __devinit preconfigure_through_ali(struct pci_dev *dev,
struct
smsc_ircc_subsystem_configuration
*conf)
@@ -2837,7 +2837,7 @@ static int __init preconfigure_through_ali(struct pci_dev *dev,
return preconfigure_smsc_chip(conf);
}
-static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg,
+static int __devinit smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg,
unsigned short ircc_fir,
unsigned short ircc_sir,
unsigned char ircc_dma,
@@ -2849,7 +2849,7 @@ static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg,
int ret = 0;
for_each_pci_dev(dev) {
- struct smsc_ircc_subsystem_configuration *conf;
+ const struct smsc_ircc_subsystem_configuration *conf;
/*
* Cache the subsystem vendor/device:
diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h
index 8f3df044e81e..49e8408f05fc 100644
--- a/drivers/net/ixgb/ixgb.h
+++ b/drivers/net/ixgb/ixgb.h
@@ -157,9 +157,6 @@ struct ixgb_adapter {
u16 link_duplex;
struct work_struct tx_timeout_task;
- struct timer_list blink_timer;
- unsigned long led_status;
-
/* TX */
struct ixgb_desc_ring tx_ring ____cacheline_aligned_in_smp;
unsigned int restart_queue;
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c
index cc53aa1541ba..6da890b9534c 100644
--- a/drivers/net/ixgb/ixgb_ethtool.c
+++ b/drivers/net/ixgb/ixgb_ethtool.c
@@ -104,10 +104,10 @@ ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
ecmd->transceiver = XCVR_EXTERNAL;
if (netif_carrier_ok(adapter->netdev)) {
- ecmd->speed = SPEED_10000;
+ ethtool_cmd_speed_set(ecmd, SPEED_10000);
ecmd->duplex = DUPLEX_FULL;
} else {
- ecmd->speed = -1;
+ ethtool_cmd_speed_set(ecmd, -1);
ecmd->duplex = -1;
}
@@ -129,9 +129,10 @@ static int
ixgb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
{
struct ixgb_adapter *adapter = netdev_priv(netdev);
+ u32 speed = ethtool_cmd_speed(ecmd);
if (ecmd->autoneg == AUTONEG_ENABLE ||
- ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL)
+ (speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL))
return -EINVAL;
if (netif_running(adapter->netdev)) {
@@ -610,45 +611,23 @@ err_setup_rx:
return err;
}
-/* toggle LED 4 times per second = 2 "blinks" per second */
-#define IXGB_ID_INTERVAL (HZ/4)
-
-/* bit defines for adapter->led_status */
-#define IXGB_LED_ON 0
-
-static void
-ixgb_led_blink_callback(unsigned long data)
-{
- struct ixgb_adapter *adapter = (struct ixgb_adapter *)data;
-
- if (test_and_change_bit(IXGB_LED_ON, &adapter->led_status))
- ixgb_led_off(&adapter->hw);
- else
- ixgb_led_on(&adapter->hw);
-
- mod_timer(&adapter->blink_timer, jiffies + IXGB_ID_INTERVAL);
-}
-
static int
-ixgb_phys_id(struct net_device *netdev, u32 data)
+ixgb_set_phys_id(struct net_device *netdev, enum ethtool_phys_id_state state)
{
struct ixgb_adapter *adapter = netdev_priv(netdev);
- if (!data)
- data = INT_MAX;
-
- if (!adapter->blink_timer.function) {
- init_timer(&adapter->blink_timer);
- adapter->blink_timer.function = ixgb_led_blink_callback;
- adapter->blink_timer.data = (unsigned long)adapter;
- }
+ switch (state) {
+ case ETHTOOL_ID_ACTIVE:
+ return 2;
- mod_timer(&adapter->blink_timer, jiffies);
+ case ETHTOOL_ID_ON:
+ ixgb_led_on(&adapter->hw);
+ break;
- msleep_interruptible(data * 1000);
- del_timer_sync(&adapter->blink_timer);
- ixgb_led_off(&adapter->hw);
- clear_bit(IXGB_LED_ON, &adapter->led_status);
+ case ETHTOOL_ID_OFF:
+ case ETHTOOL_ID_INACTIVE:
+ ixgb_led_off(&adapter->hw);
+ }
return 0;
}
@@ -766,7 +745,7 @@ static const struct ethtool_ops ixgb_ethtool_ops = {
.set_msglevel = ixgb_set_msglevel,
.set_tso = ixgb_set_tso,
.get_strings = ixgb_get_strings,
- .phys_id = ixgb_phys_id,
+ .set_phys_id = ixgb_set_phys_id,
.get_sset_count = ixgb_get_sset_count,
.get_ethtool_stats = ixgb_get_ethtool_stats,
.get_flags = ethtool_op_get_flags,
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index 0f681ac2da8d..6a130eb51cfa 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -28,6 +28,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/prefetch.h>
#include "ixgb.h"
char ixgb_driver_name[] = "ixgb";
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
index 8d468028bb55..e467b20ed1f0 100644
--- a/drivers/net/ixgbe/ixgbe.h
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -106,6 +106,7 @@
#define IXGBE_MAX_VF_FUNCTIONS 64
#define IXGBE_MAX_VFTA_ENTRIES 128
#define MAX_EMULATION_MAC_ADDRS 16
+#define IXGBE_MAX_PF_MACVLANS 15
#define VMDQ_P(p) ((p) + adapter->num_vfs)
struct vf_data_storage {
@@ -121,6 +122,15 @@ struct vf_data_storage {
u16 tx_rate;
};
+struct vf_macvlans {
+ struct list_head l;
+ int vf;
+ int rar_entry;
+ bool free;
+ bool is_macvlan;
+ u8 vf_macvlan[ETH_ALEN];
+};
+
/* wrapper around a pointer to a socket buffer,
* so a DMA handle can be stored along with the buffer */
struct ixgbe_tx_buffer {
@@ -331,10 +341,52 @@ struct ixgbe_q_vector {
/* board specific private data structure */
struct ixgbe_adapter {
- struct timer_list watchdog_timer;
+ unsigned long state;
+
+ /* Some features need tri-state capability,
+ * thus the additional *_CAPABLE flags.
+ */
+ u32 flags;
+#define IXGBE_FLAG_RX_CSUM_ENABLED (u32)(1)
+#define IXGBE_FLAG_MSI_CAPABLE (u32)(1 << 1)
+#define IXGBE_FLAG_MSI_ENABLED (u32)(1 << 2)
+#define IXGBE_FLAG_MSIX_CAPABLE (u32)(1 << 3)
+#define IXGBE_FLAG_MSIX_ENABLED (u32)(1 << 4)
+#define IXGBE_FLAG_RX_1BUF_CAPABLE (u32)(1 << 6)
+#define IXGBE_FLAG_RX_PS_CAPABLE (u32)(1 << 7)
+#define IXGBE_FLAG_RX_PS_ENABLED (u32)(1 << 8)
+#define IXGBE_FLAG_IN_NETPOLL (u32)(1 << 9)
+#define IXGBE_FLAG_DCA_ENABLED (u32)(1 << 10)
+#define IXGBE_FLAG_DCA_CAPABLE (u32)(1 << 11)
+#define IXGBE_FLAG_IMIR_ENABLED (u32)(1 << 12)
+#define IXGBE_FLAG_MQ_CAPABLE (u32)(1 << 13)
+#define IXGBE_FLAG_DCB_ENABLED (u32)(1 << 14)
+#define IXGBE_FLAG_RSS_ENABLED (u32)(1 << 16)
+#define IXGBE_FLAG_RSS_CAPABLE (u32)(1 << 17)
+#define IXGBE_FLAG_VMDQ_CAPABLE (u32)(1 << 18)
+#define IXGBE_FLAG_VMDQ_ENABLED (u32)(1 << 19)
+#define IXGBE_FLAG_FAN_FAIL_CAPABLE (u32)(1 << 20)
+#define IXGBE_FLAG_NEED_LINK_UPDATE (u32)(1 << 22)
+#define IXGBE_FLAG_NEED_LINK_CONFIG (u32)(1 << 23)
+#define IXGBE_FLAG_FDIR_HASH_CAPABLE (u32)(1 << 24)
+#define IXGBE_FLAG_FDIR_PERFECT_CAPABLE (u32)(1 << 25)
+#define IXGBE_FLAG_FCOE_CAPABLE (u32)(1 << 26)
+#define IXGBE_FLAG_FCOE_ENABLED (u32)(1 << 27)
+#define IXGBE_FLAG_SRIOV_CAPABLE (u32)(1 << 28)
+#define IXGBE_FLAG_SRIOV_ENABLED (u32)(1 << 29)
+
+ u32 flags2;
+#define IXGBE_FLAG2_RSC_CAPABLE (u32)(1)
+#define IXGBE_FLAG2_RSC_ENABLED (u32)(1 << 1)
+#define IXGBE_FLAG2_TEMP_SENSOR_CAPABLE (u32)(1 << 2)
+#define IXGBE_FLAG2_TEMP_SENSOR_EVENT (u32)(1 << 3)
+#define IXGBE_FLAG2_SEARCH_FOR_SFP (u32)(1 << 4)
+#define IXGBE_FLAG2_SFP_NEEDS_RESET (u32)(1 << 5)
+#define IXGBE_FLAG2_RESET_REQUESTED (u32)(1 << 6)
+#define IXGBE_FLAG2_FDIR_REQUIRES_REINIT (u32)(1 << 7)
+
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
u16 bd_number;
- struct work_struct reset_task;
struct ixgbe_q_vector *q_vector[MAX_MSIX_Q_VECTORS];
/* DCB parameters */
@@ -377,43 +429,6 @@ struct ixgbe_adapter {
u32 alloc_rx_page_failed;
u32 alloc_rx_buff_failed;
- /* Some features need tri-state capability,
- * thus the additional *_CAPABLE flags.
- */
- u32 flags;
-#define IXGBE_FLAG_RX_CSUM_ENABLED (u32)(1)
-#define IXGBE_FLAG_MSI_CAPABLE (u32)(1 << 1)
-#define IXGBE_FLAG_MSI_ENABLED (u32)(1 << 2)
-#define IXGBE_FLAG_MSIX_CAPABLE (u32)(1 << 3)
-#define IXGBE_FLAG_MSIX_ENABLED (u32)(1 << 4)
-#define IXGBE_FLAG_RX_1BUF_CAPABLE (u32)(1 << 6)
-#define IXGBE_FLAG_RX_PS_CAPABLE (u32)(1 << 7)
-#define IXGBE_FLAG_RX_PS_ENABLED (u32)(1 << 8)
-#define IXGBE_FLAG_IN_NETPOLL (u32)(1 << 9)
-#define IXGBE_FLAG_DCA_ENABLED (u32)(1 << 10)
-#define IXGBE_FLAG_DCA_CAPABLE (u32)(1 << 11)
-#define IXGBE_FLAG_IMIR_ENABLED (u32)(1 << 12)
-#define IXGBE_FLAG_MQ_CAPABLE (u32)(1 << 13)
-#define IXGBE_FLAG_DCB_ENABLED (u32)(1 << 14)
-#define IXGBE_FLAG_RSS_ENABLED (u32)(1 << 16)
-#define IXGBE_FLAG_RSS_CAPABLE (u32)(1 << 17)
-#define IXGBE_FLAG_VMDQ_CAPABLE (u32)(1 << 18)
-#define IXGBE_FLAG_VMDQ_ENABLED (u32)(1 << 19)
-#define IXGBE_FLAG_FAN_FAIL_CAPABLE (u32)(1 << 20)
-#define IXGBE_FLAG_NEED_LINK_UPDATE (u32)(1 << 22)
-#define IXGBE_FLAG_IN_SFP_LINK_TASK (u32)(1 << 23)
-#define IXGBE_FLAG_IN_SFP_MOD_TASK (u32)(1 << 24)
-#define IXGBE_FLAG_FDIR_HASH_CAPABLE (u32)(1 << 25)
-#define IXGBE_FLAG_FDIR_PERFECT_CAPABLE (u32)(1 << 26)
-#define IXGBE_FLAG_FCOE_CAPABLE (u32)(1 << 27)
-#define IXGBE_FLAG_FCOE_ENABLED (u32)(1 << 28)
-#define IXGBE_FLAG_SRIOV_CAPABLE (u32)(1 << 29)
-#define IXGBE_FLAG_SRIOV_ENABLED (u32)(1 << 30)
-
- u32 flags2;
-#define IXGBE_FLAG2_RSC_CAPABLE (u32)(1)
-#define IXGBE_FLAG2_RSC_ENABLED (u32)(1 << 1)
-#define IXGBE_FLAG2_TEMP_SENSOR_CAPABLE (u32)(1 << 2)
/* default to trying for four seconds */
#define IXGBE_TRY_LINK_TIMEOUT (4 * HZ)
@@ -434,7 +449,6 @@ struct ixgbe_adapter {
u32 rx_eitr_param;
u32 tx_eitr_param;
- unsigned long state;
u64 tx_busy;
unsigned int tx_ring_count;
unsigned int rx_ring_count;
@@ -443,15 +457,12 @@ struct ixgbe_adapter {
bool link_up;
unsigned long link_check_timeout;
- struct work_struct watchdog_task;
- struct work_struct sfp_task;
- struct timer_list sfp_timer;
- struct work_struct multispeed_fiber_task;
- struct work_struct sfp_config_module_task;
+ struct work_struct service_task;
+ struct timer_list service_timer;
u32 fdir_pballoc;
u32 atr_sample_rate;
+ unsigned long fdir_overflow; /* number of times ATR was backed off */
spinlock_t fdir_perfect_lock;
- struct work_struct fdir_reinit_task;
#ifdef IXGBE_FCOE
struct ixgbe_fcoe fcoe;
#endif /* IXGBE_FCOE */
@@ -461,7 +472,7 @@ struct ixgbe_adapter {
u16 eeprom_version;
int node;
- struct work_struct check_overtemp_task;
+ u32 led_reg;
u32 interrupt_event;
char lsc_int_name[IFNAMSIZ + 9];
@@ -470,13 +481,17 @@ struct ixgbe_adapter {
unsigned int num_vfs;
struct vf_data_storage *vfinfo;
int vf_rate_link_speed;
+ struct vf_macvlans vf_mvs;
+ struct vf_macvlans *mv_list;
+ bool antispoofing_enabled;
};
enum ixbge_state_t {
__IXGBE_TESTING,
__IXGBE_RESETTING,
__IXGBE_DOWN,
- __IXGBE_SFP_MODULE_NOT_FOUND
+ __IXGBE_SERVICE_SCHED,
+ __IXGBE_IN_SFP_INIT,
};
struct ixgbe_rsc_cb {
diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c
index 845c679c8b87..8179e5060a18 100644
--- a/drivers/net/ixgbe/ixgbe_82598.c
+++ b/drivers/net/ixgbe/ixgbe_82598.c
@@ -37,6 +37,7 @@
#define IXGBE_82598_RAR_ENTRIES 16
#define IXGBE_82598_MC_TBL_SIZE 128
#define IXGBE_82598_VFT_TBL_SIZE 128
+#define IXGBE_82598_RX_PB_SIZE 512
static s32 ixgbe_setup_copper_link_82598(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
@@ -197,14 +198,35 @@ out:
* @hw: pointer to hardware structure
*
* Starts the hardware using the generic start_hw function.
- * Then set pcie completion timeout
+ * Disables relaxed ordering Then set pcie completion timeout
+ *
**/
static s32 ixgbe_start_hw_82598(struct ixgbe_hw *hw)
{
+ u32 regval;
+ u32 i;
s32 ret_val = 0;
ret_val = ixgbe_start_hw_generic(hw);
+ /* Disable relaxed ordering */
+ for (i = 0; ((i < hw->mac.max_tx_queues) &&
+ (i < IXGBE_DCA_MAX_QUEUES_82598)); i++) {
+ regval = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL(i));
+ regval &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
+ IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(i), regval);
+ }
+
+ for (i = 0; ((i < hw->mac.max_rx_queues) &&
+ (i < IXGBE_DCA_MAX_QUEUES_82598)); i++) {
+ regval = IXGBE_READ_REG(hw, IXGBE_DCA_RXCTRL(i));
+ regval &= ~(IXGBE_DCA_RXCTRL_DESC_WRO_EN |
+ IXGBE_DCA_RXCTRL_DESC_HSRO_EN);
+ IXGBE_WRITE_REG(hw, IXGBE_DCA_RXCTRL(i), regval);
+ }
+
+ hw->mac.rx_pb_size = IXGBE_82598_RX_PB_SIZE;
+
/* set the completion timeout for interface */
if (ret_val == 0)
ixgbe_set_pcie_completion_timeout(hw);
@@ -1064,7 +1086,7 @@ static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset,
sfp_stat = sfp_stat & IXGBE_I2C_EEPROM_STATUS_MASK;
if (sfp_stat != IXGBE_I2C_EEPROM_STATUS_IN_PROGRESS)
break;
- msleep(10);
+ usleep_range(10000, 20000);
}
if (sfp_stat != IXGBE_I2C_EEPROM_STATUS_PASS) {
@@ -1188,6 +1210,38 @@ out:
return physical_layer;
}
+/**
+ * ixgbe_set_lan_id_multi_port_pcie_82598 - Set LAN id for PCIe multiple
+ * port devices.
+ * @hw: pointer to the HW structure
+ *
+ * Calls common function and corrects issue with some single port devices
+ * that enable LAN1 but not LAN0.
+ **/
+static void ixgbe_set_lan_id_multi_port_pcie_82598(struct ixgbe_hw *hw)
+{
+ struct ixgbe_bus_info *bus = &hw->bus;
+ u16 pci_gen = 0;
+ u16 pci_ctrl2 = 0;
+
+ ixgbe_set_lan_id_multi_port_pcie(hw);
+
+ /* check if LAN0 is disabled */
+ hw->eeprom.ops.read(hw, IXGBE_PCIE_GENERAL_PTR, &pci_gen);
+ if ((pci_gen != 0) && (pci_gen != 0xFFFF)) {
+
+ hw->eeprom.ops.read(hw, pci_gen + IXGBE_PCIE_CTRL2, &pci_ctrl2);
+
+ /* if LAN0 is completely disabled force function to 0 */
+ if ((pci_ctrl2 & IXGBE_PCIE_CTRL2_LAN_DISABLE) &&
+ !(pci_ctrl2 & IXGBE_PCIE_CTRL2_DISABLE_SELECT) &&
+ !(pci_ctrl2 & IXGBE_PCIE_CTRL2_DUMMY_ENABLE)) {
+
+ bus->func = 0;
+ }
+ }
+}
+
static struct ixgbe_mac_operations mac_ops_82598 = {
.init_hw = &ixgbe_init_hw_generic,
.reset_hw = &ixgbe_reset_hw_82598,
@@ -1199,7 +1253,7 @@ static struct ixgbe_mac_operations mac_ops_82598 = {
.get_mac_addr = &ixgbe_get_mac_addr_generic,
.stop_adapter = &ixgbe_stop_adapter_generic,
.get_bus_info = &ixgbe_get_bus_info_generic,
- .set_lan_id = &ixgbe_set_lan_id_multi_port_pcie,
+ .set_lan_id = &ixgbe_set_lan_id_multi_port_pcie_82598,
.read_analog_reg8 = &ixgbe_read_analog_reg8_82598,
.write_analog_reg8 = &ixgbe_write_analog_reg8_82598,
.setup_link = &ixgbe_setup_mac_link_82598,
@@ -1227,6 +1281,7 @@ static struct ixgbe_mac_operations mac_ops_82598 = {
static struct ixgbe_eeprom_operations eeprom_ops_82598 = {
.init_params = &ixgbe_init_eeprom_params_generic,
.read = &ixgbe_read_eerd_generic,
+ .read_buffer = &ixgbe_read_eerd_buffer_generic,
.calc_checksum = &ixgbe_calc_eeprom_checksum_generic,
.validate_checksum = &ixgbe_validate_eeprom_checksum_generic,
.update_checksum = &ixgbe_update_eeprom_checksum_generic,
diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c
index 00aeba385a2f..8ee661245af3 100644
--- a/drivers/net/ixgbe/ixgbe_82599.c
+++ b/drivers/net/ixgbe/ixgbe_82599.c
@@ -38,6 +38,7 @@
#define IXGBE_82599_RAR_ENTRIES 128
#define IXGBE_82599_MC_TBL_SIZE 128
#define IXGBE_82599_VFT_TBL_SIZE 128
+#define IXGBE_82599_RX_PB_SIZE 512
static void ixgbe_disable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw);
static void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw);
@@ -61,6 +62,7 @@ static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw,
bool autoneg,
bool autoneg_wait_to_complete);
static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw);
+static bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw);
static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw)
{
@@ -86,7 +88,8 @@ static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw)
if ((mac->ops.get_media_type(hw) ==
ixgbe_media_type_backplane) &&
(hw->phy.smart_speed == ixgbe_smart_speed_auto ||
- hw->phy.smart_speed == ixgbe_smart_speed_on))
+ hw->phy.smart_speed == ixgbe_smart_speed_on) &&
+ !ixgbe_verify_lesm_fw_enabled_82599(hw))
mac->ops.setup_link = &ixgbe_setup_mac_link_smartspeed;
else
mac->ops.setup_link = &ixgbe_setup_mac_link_82599;
@@ -107,7 +110,6 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw)
ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset,
&data_offset);
-
if (ret_val != 0)
goto setup_sfp_out;
@@ -127,9 +129,13 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw)
}
/* Release the semaphore */
- ixgbe_release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM);
- /* Delay obtaining semaphore again to allow FW access */
- msleep(hw->eeprom.semaphore_delay);
+ hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM);
+ /*
+ * Delay obtaining semaphore again to allow FW access,
+ * semaphore_delay is in ms usleep_range needs us.
+ */
+ usleep_range(hw->eeprom.semaphore_delay * 1000,
+ hw->eeprom.semaphore_delay * 2000);
/* Now restart DSP by setting Restart_AN and clearing LMS */
IXGBE_WRITE_REG(hw, IXGBE_AUTOC, ((IXGBE_READ_REG(hw,
@@ -138,7 +144,7 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw)
/* Wait for AN to leave state 0 */
for (i = 0; i < 10; i++) {
- msleep(4);
+ usleep_range(4000, 8000);
reg_anlp1 = IXGBE_READ_REG(hw, IXGBE_ANLP1);
if (reg_anlp1 & IXGBE_ANLP1_AN_STATE_MASK)
break;
@@ -353,6 +359,7 @@ static enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw)
case IXGBE_DEV_ID_82599_SFP:
case IXGBE_DEV_ID_82599_SFP_FCOE:
case IXGBE_DEV_ID_82599_SFP_EM:
+ case IXGBE_DEV_ID_82599_SFP_SF2:
media_type = ixgbe_media_type_fiber;
break;
case IXGBE_DEV_ID_82599_CX4:
@@ -361,6 +368,9 @@ static enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw)
case IXGBE_DEV_ID_82599_T3_LOM:
media_type = ixgbe_media_type_copper;
break;
+ case IXGBE_DEV_ID_82599_LS:
+ media_type = ixgbe_media_type_fiber_lco;
+ break;
default:
media_type = ixgbe_media_type_unknown;
break;
@@ -486,7 +496,7 @@ static void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw)
*
* Set the link speed in the AUTOC register and restarts link.
**/
-s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
+static s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw,
ixgbe_link_speed speed,
bool autoneg,
bool autoneg_wait_to_complete)
@@ -1176,7 +1186,7 @@ s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 pballoc)
if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) &
IXGBE_FDIRCTRL_INIT_DONE)
break;
- msleep(1);
+ usleep_range(1000, 2000);
}
if (i >= IXGBE_FDIR_INIT_DONE_POLL)
hw_dbg(hw, "Flow Director Signature poll time exceeded!\n");
@@ -1271,7 +1281,7 @@ s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc)
if (IXGBE_READ_REG(hw, IXGBE_FDIRCTRL) &
IXGBE_FDIRCTRL_INIT_DONE)
break;
- msleep(1);
+ usleep_range(1000, 2000);
}
if (i >= IXGBE_FDIR_INIT_DONE_POLL)
hw_dbg(hw, "Flow Director Perfect poll time exceeded!\n");
@@ -1740,30 +1750,29 @@ static s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val)
* ixgbe_start_hw_82599 - Prepare hardware for Tx/Rx
* @hw: pointer to hardware structure
*
- * Starts the hardware using the generic start_hw function.
- * Then performs device-specific:
- * Clears the rate limiter registers.
+ * Starts the hardware using the generic start_hw function
+ * and the generation start_hw function.
+ * Then performs revision-specific operations, if any.
**/
static s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw)
{
- u32 q_num;
- s32 ret_val;
+ s32 ret_val = 0;
ret_val = ixgbe_start_hw_generic(hw);
+ if (ret_val != 0)
+ goto out;
- /* Clear the rate limiters */
- for (q_num = 0; q_num < hw->mac.max_tx_queues; q_num++) {
- IXGBE_WRITE_REG(hw, IXGBE_RTTDQSEL, q_num);
- IXGBE_WRITE_REG(hw, IXGBE_RTTBCNRC, 0);
- }
- IXGBE_WRITE_FLUSH(hw);
+ ret_val = ixgbe_start_hw_gen2(hw);
+ if (ret_val != 0)
+ goto out;
/* We need to run link autotry after the driver loads */
hw->mac.autotry_restart = true;
+ hw->mac.rx_pb_size = IXGBE_82599_RX_PB_SIZE;
if (ret_val == 0)
ret_val = ixgbe_verify_fw_version_82599(hw);
-
+out:
return ret_val;
}
@@ -1775,7 +1784,7 @@ static s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw)
* If PHY already detected, maintains current PHY type in hw struct,
* otherwise executes the PHY detection routine.
**/
-s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw)
+static s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw)
{
s32 status = IXGBE_ERR_PHY_ADDR_INVALID;
@@ -1968,21 +1977,6 @@ static s32 ixgbe_enable_rx_dma_82599(struct ixgbe_hw *hw, u32 regval)
}
/**
- * ixgbe_get_device_caps_82599 - Get additional device capabilities
- * @hw: pointer to hardware structure
- * @device_caps: the EEPROM word with the extra device capabilities
- *
- * This function will read the EEPROM location for the device capabilities,
- * and return the word through device_caps.
- **/
-static s32 ixgbe_get_device_caps_82599(struct ixgbe_hw *hw, u16 *device_caps)
-{
- hw->eeprom.ops.read(hw, IXGBE_DEVICE_CAPS, device_caps);
-
- return 0;
-}
-
-/**
* ixgbe_verify_fw_version_82599 - verify fw version for 82599
* @hw: pointer to hardware structure
*
@@ -2030,6 +2024,110 @@ fw_version_out:
return status;
}
+/**
+ * ixgbe_verify_lesm_fw_enabled_82599 - Checks LESM FW module state.
+ * @hw: pointer to hardware structure
+ *
+ * Returns true if the LESM FW module is present and enabled. Otherwise
+ * returns false. Smart Speed must be disabled if LESM FW module is enabled.
+ **/
+static bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw)
+{
+ bool lesm_enabled = false;
+ u16 fw_offset, fw_lesm_param_offset, fw_lesm_state;
+ s32 status;
+
+ /* get the offset to the Firmware Module block */
+ status = hw->eeprom.ops.read(hw, IXGBE_FW_PTR, &fw_offset);
+
+ if ((status != 0) ||
+ (fw_offset == 0) || (fw_offset == 0xFFFF))
+ goto out;
+
+ /* get the offset to the LESM Parameters block */
+ status = hw->eeprom.ops.read(hw, (fw_offset +
+ IXGBE_FW_LESM_PARAMETERS_PTR),
+ &fw_lesm_param_offset);
+
+ if ((status != 0) ||
+ (fw_lesm_param_offset == 0) || (fw_lesm_param_offset == 0xFFFF))
+ goto out;
+
+ /* get the lesm state word */
+ status = hw->eeprom.ops.read(hw, (fw_lesm_param_offset +
+ IXGBE_FW_LESM_STATE_1),
+ &fw_lesm_state);
+
+ if ((status == 0) &&
+ (fw_lesm_state & IXGBE_FW_LESM_STATE_ENABLED))
+ lesm_enabled = true;
+
+out:
+ return lesm_enabled;
+}
+
+/**
+ * ixgbe_read_eeprom_buffer_82599 - Read EEPROM word(s) using
+ * fastest available method
+ *
+ * @hw: pointer to hardware structure
+ * @offset: offset of word in EEPROM to read
+ * @words: number of words
+ * @data: word(s) read from the EEPROM
+ *
+ * Retrieves 16 bit word(s) read from EEPROM
+ **/
+static s32 ixgbe_read_eeprom_buffer_82599(struct ixgbe_hw *hw, u16 offset,
+ u16 words, u16 *data)
+{
+ struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+ s32 ret_val = IXGBE_ERR_CONFIG;
+
+ /*
+ * If EEPROM is detected and can be addressed using 14 bits,
+ * use EERD otherwise use bit bang
+ */
+ if ((eeprom->type == ixgbe_eeprom_spi) &&
+ (offset + (words - 1) <= IXGBE_EERD_MAX_ADDR))
+ ret_val = ixgbe_read_eerd_buffer_generic(hw, offset, words,
+ data);
+ else
+ ret_val = ixgbe_read_eeprom_buffer_bit_bang_generic(hw, offset,
+ words,
+ data);
+
+ return ret_val;
+}
+
+/**
+ * ixgbe_read_eeprom_82599 - Read EEPROM word using
+ * fastest available method
+ *
+ * @hw: pointer to hardware structure
+ * @offset: offset of word in the EEPROM to read
+ * @data: word read from the EEPROM
+ *
+ * Reads a 16 bit word from the EEPROM
+ **/
+static s32 ixgbe_read_eeprom_82599(struct ixgbe_hw *hw,
+ u16 offset, u16 *data)
+{
+ struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+ s32 ret_val = IXGBE_ERR_CONFIG;
+
+ /*
+ * If EEPROM is detected and can be addressed using 14 bits,
+ * use EERD otherwise use bit bang
+ */
+ if ((eeprom->type == ixgbe_eeprom_spi) &&
+ (offset <= IXGBE_EERD_MAX_ADDR))
+ ret_val = ixgbe_read_eerd_generic(hw, offset, data);
+ else
+ ret_val = ixgbe_read_eeprom_bit_bang_generic(hw, offset, data);
+
+ return ret_val;
+}
+
static struct ixgbe_mac_operations mac_ops_82599 = {
.init_hw = &ixgbe_init_hw_generic,
.reset_hw = &ixgbe_reset_hw_82599,
@@ -2040,7 +2138,7 @@ static struct ixgbe_mac_operations mac_ops_82599 = {
.enable_rx_dma = &ixgbe_enable_rx_dma_82599,
.get_mac_addr = &ixgbe_get_mac_addr_generic,
.get_san_mac_addr = &ixgbe_get_san_mac_addr_generic,
- .get_device_caps = &ixgbe_get_device_caps_82599,
+ .get_device_caps = &ixgbe_get_device_caps_generic,
.get_wwn_prefix = &ixgbe_get_wwn_prefix_generic,
.stop_adapter = &ixgbe_stop_adapter_generic,
.get_bus_info = &ixgbe_get_bus_info_generic,
@@ -2076,8 +2174,10 @@ static struct ixgbe_mac_operations mac_ops_82599 = {
static struct ixgbe_eeprom_operations eeprom_ops_82599 = {
.init_params = &ixgbe_init_eeprom_params_generic,
- .read = &ixgbe_read_eerd_generic,
+ .read = &ixgbe_read_eeprom_82599,
+ .read_buffer = &ixgbe_read_eeprom_buffer_82599,
.write = &ixgbe_write_eeprom_generic,
+ .write_buffer = &ixgbe_write_eeprom_buffer_bit_bang_generic,
.calc_checksum = &ixgbe_calc_eeprom_checksum_generic,
.validate_checksum = &ixgbe_validate_eeprom_checksum_generic,
.update_checksum = &ixgbe_update_eeprom_checksum_generic,
diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c
index bcd952916eb2..b894b42a741c 100644
--- a/drivers/net/ixgbe/ixgbe_common.c
+++ b/drivers/net/ixgbe/ixgbe_common.c
@@ -54,6 +54,13 @@ static s32 ixgbe_device_supports_autoneg_fc(struct ixgbe_hw *hw);
static s32 ixgbe_negotiate_fc(struct ixgbe_hw *hw, u32 adv_reg, u32 lp_reg,
u32 adv_sym, u32 adv_asm, u32 lp_sym, u32 lp_asm);
static s32 ixgbe_setup_fc(struct ixgbe_hw *hw, s32 packetbuf_num);
+static s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg);
+static s32 ixgbe_read_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset,
+ u16 words, u16 *data);
+static s32 ixgbe_write_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset,
+ u16 words, u16 *data);
+static s32 ixgbe_detect_eeprom_page_size_generic(struct ixgbe_hw *hw,
+ u16 offset);
/**
* ixgbe_start_hw_generic - Prepare hardware for Tx/Rx
@@ -96,6 +103,45 @@ s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw)
}
/**
+ * ixgbe_start_hw_gen2 - Init sequence for common device family
+ * @hw: pointer to hw structure
+ *
+ * Performs the init sequence common to the second generation
+ * of 10 GbE devices.
+ * Devices in the second generation:
+ * 82599
+ * X540
+ **/
+s32 ixgbe_start_hw_gen2(struct ixgbe_hw *hw)
+{
+ u32 i;
+ u32 regval;
+
+ /* Clear the rate limiters */
+ for (i = 0; i < hw->mac.max_tx_queues; i++) {
+ IXGBE_WRITE_REG(hw, IXGBE_RTTDQSEL, i);
+ IXGBE_WRITE_REG(hw, IXGBE_RTTBCNRC, 0);
+ }
+ IXGBE_WRITE_FLUSH(hw);
+
+ /* Disable relaxed ordering */
+ for (i = 0; i < hw->mac.max_tx_queues; i++) {
+ regval = IXGBE_READ_REG(hw, IXGBE_DCA_TXCTRL_82599(i));
+ regval &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
+ IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(i), regval);
+ }
+
+ for (i = 0; i < hw->mac.max_rx_queues; i++) {
+ regval = IXGBE_READ_REG(hw, IXGBE_DCA_RXCTRL(i));
+ regval &= ~(IXGBE_DCA_RXCTRL_DESC_WRO_EN |
+ IXGBE_DCA_RXCTRL_DESC_HSRO_EN);
+ IXGBE_WRITE_REG(hw, IXGBE_DCA_RXCTRL(i), regval);
+ }
+
+ return 0;
+}
+
+/**
* ixgbe_init_hw_generic - Generic hardware initialization
* @hw: pointer to hardware structure
*
@@ -464,7 +510,7 @@ s32 ixgbe_stop_adapter_generic(struct ixgbe_hw *hw)
reg_val &= ~(IXGBE_RXCTRL_RXEN);
IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg_val);
IXGBE_WRITE_FLUSH(hw);
- msleep(2);
+ usleep_range(2000, 4000);
/* Clear interrupt mask to stop from interrupts being generated */
IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_IRQ_CLEAR_MASK);
@@ -545,6 +591,8 @@ s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw)
/* Set default semaphore delay to 10ms which is a well
* tested value */
eeprom->semaphore_delay = 10;
+ /* Clear EEPROM page size, it will be initialized as needed */
+ eeprom->word_page_size = 0;
/*
* Check for EEPROM present first.
@@ -577,26 +625,78 @@ s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw)
}
/**
- * ixgbe_write_eeprom_generic - Writes 16 bit value to EEPROM
+ * ixgbe_write_eeprom_buffer_bit_bang_generic - Write EEPROM using bit-bang
* @hw: pointer to hardware structure
- * @offset: offset within the EEPROM to be written to
- * @data: 16 bit word to be written to the EEPROM
+ * @offset: offset within the EEPROM to write
+ * @words: number of words
+ * @data: 16 bit word(s) to write to EEPROM
*
- * If ixgbe_eeprom_update_checksum is not called after this function, the
- * EEPROM will most likely contain an invalid checksum.
+ * Reads 16 bit word(s) from EEPROM through bit-bang method
**/
-s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data)
+s32 ixgbe_write_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
+ u16 words, u16 *data)
{
- s32 status;
- u8 write_opcode = IXGBE_EEPROM_WRITE_OPCODE_SPI;
+ s32 status = 0;
+ u16 i, count;
hw->eeprom.ops.init_params(hw);
- if (offset >= hw->eeprom.word_size) {
+ if (words == 0) {
+ status = IXGBE_ERR_INVALID_ARGUMENT;
+ goto out;
+ }
+
+ if (offset + words > hw->eeprom.word_size) {
status = IXGBE_ERR_EEPROM;
goto out;
}
+ /*
+ * The EEPROM page size cannot be queried from the chip. We do lazy
+ * initialization. It is worth to do that when we write large buffer.
+ */
+ if ((hw->eeprom.word_page_size == 0) &&
+ (words > IXGBE_EEPROM_PAGE_SIZE_MAX))
+ ixgbe_detect_eeprom_page_size_generic(hw, offset);
+
+ /*
+ * We cannot hold synchronization semaphores for too long
+ * to avoid other entity starvation. However it is more efficient
+ * to read in bursts than synchronizing access for each word.
+ */
+ for (i = 0; i < words; i += IXGBE_EEPROM_RD_BUFFER_MAX_COUNT) {
+ count = (words - i) / IXGBE_EEPROM_RD_BUFFER_MAX_COUNT > 0 ?
+ IXGBE_EEPROM_RD_BUFFER_MAX_COUNT : (words - i);
+ status = ixgbe_write_eeprom_buffer_bit_bang(hw, offset + i,
+ count, &data[i]);
+
+ if (status != 0)
+ break;
+ }
+
+out:
+ return status;
+}
+
+/**
+ * ixgbe_write_eeprom_buffer_bit_bang - Writes 16 bit word(s) to EEPROM
+ * @hw: pointer to hardware structure
+ * @offset: offset within the EEPROM to be written to
+ * @words: number of word(s)
+ * @data: 16 bit word(s) to be written to the EEPROM
+ *
+ * If ixgbe_eeprom_update_checksum is not called after this function, the
+ * EEPROM will most likely contain an invalid checksum.
+ **/
+static s32 ixgbe_write_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset,
+ u16 words, u16 *data)
+{
+ s32 status;
+ u16 word;
+ u16 page_size;
+ u16 i;
+ u8 write_opcode = IXGBE_EEPROM_WRITE_OPCODE_SPI;
+
/* Prepare the EEPROM for writing */
status = ixgbe_acquire_eeprom(hw);
@@ -608,62 +708,147 @@ s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data)
}
if (status == 0) {
- ixgbe_standby_eeprom(hw);
+ for (i = 0; i < words; i++) {
+ ixgbe_standby_eeprom(hw);
- /* Send the WRITE ENABLE command (8 bit opcode ) */
- ixgbe_shift_out_eeprom_bits(hw, IXGBE_EEPROM_WREN_OPCODE_SPI,
- IXGBE_EEPROM_OPCODE_BITS);
+ /* Send the WRITE ENABLE command (8 bit opcode ) */
+ ixgbe_shift_out_eeprom_bits(hw,
+ IXGBE_EEPROM_WREN_OPCODE_SPI,
+ IXGBE_EEPROM_OPCODE_BITS);
- ixgbe_standby_eeprom(hw);
+ ixgbe_standby_eeprom(hw);
- /*
- * Some SPI eeproms use the 8th address bit embedded in the
- * opcode
- */
- if ((hw->eeprom.address_bits == 8) && (offset >= 128))
- write_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI;
+ /*
+ * Some SPI eeproms use the 8th address bit embedded
+ * in the opcode
+ */
+ if ((hw->eeprom.address_bits == 8) &&
+ ((offset + i) >= 128))
+ write_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI;
+
+ /* Send the Write command (8-bit opcode + addr) */
+ ixgbe_shift_out_eeprom_bits(hw, write_opcode,
+ IXGBE_EEPROM_OPCODE_BITS);
+ ixgbe_shift_out_eeprom_bits(hw, (u16)((offset + i) * 2),
+ hw->eeprom.address_bits);
+
+ page_size = hw->eeprom.word_page_size;
+
+ /* Send the data in burst via SPI*/
+ do {
+ word = data[i];
+ word = (word >> 8) | (word << 8);
+ ixgbe_shift_out_eeprom_bits(hw, word, 16);
+
+ if (page_size == 0)
+ break;
+
+ /* do not wrap around page */
+ if (((offset + i) & (page_size - 1)) ==
+ (page_size - 1))
+ break;
+ } while (++i < words);
+
+ ixgbe_standby_eeprom(hw);
+ usleep_range(10000, 20000);
+ }
+ /* Done with writing - release the EEPROM */
+ ixgbe_release_eeprom(hw);
+ }
- /* Send the Write command (8-bit opcode + addr) */
- ixgbe_shift_out_eeprom_bits(hw, write_opcode,
- IXGBE_EEPROM_OPCODE_BITS);
- ixgbe_shift_out_eeprom_bits(hw, (u16)(offset*2),
- hw->eeprom.address_bits);
+ return status;
+}
- /* Send the data */
- data = (data >> 8) | (data << 8);
- ixgbe_shift_out_eeprom_bits(hw, data, 16);
- ixgbe_standby_eeprom(hw);
+/**
+ * ixgbe_write_eeprom_generic - Writes 16 bit value to EEPROM
+ * @hw: pointer to hardware structure
+ * @offset: offset within the EEPROM to be written to
+ * @data: 16 bit word to be written to the EEPROM
+ *
+ * If ixgbe_eeprom_update_checksum is not called after this function, the
+ * EEPROM will most likely contain an invalid checksum.
+ **/
+s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data)
+{
+ s32 status;
- /* Done with writing - release the EEPROM */
- ixgbe_release_eeprom(hw);
+ hw->eeprom.ops.init_params(hw);
+
+ if (offset >= hw->eeprom.word_size) {
+ status = IXGBE_ERR_EEPROM;
+ goto out;
}
+ status = ixgbe_write_eeprom_buffer_bit_bang(hw, offset, 1, &data);
+
out:
return status;
}
/**
- * ixgbe_read_eeprom_bit_bang_generic - Read EEPROM word using bit-bang
+ * ixgbe_read_eeprom_buffer_bit_bang_generic - Read EEPROM using bit-bang
* @hw: pointer to hardware structure
* @offset: offset within the EEPROM to be read
- * @data: read 16 bit value from EEPROM
+ * @words: number of word(s)
+ * @data: read 16 bit words(s) from EEPROM
*
- * Reads 16 bit value from EEPROM through bit-bang method
+ * Reads 16 bit word(s) from EEPROM through bit-bang method
**/
-s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
- u16 *data)
+s32 ixgbe_read_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
+ u16 words, u16 *data)
{
- s32 status;
- u16 word_in;
- u8 read_opcode = IXGBE_EEPROM_READ_OPCODE_SPI;
+ s32 status = 0;
+ u16 i, count;
hw->eeprom.ops.init_params(hw);
- if (offset >= hw->eeprom.word_size) {
+ if (words == 0) {
+ status = IXGBE_ERR_INVALID_ARGUMENT;
+ goto out;
+ }
+
+ if (offset + words > hw->eeprom.word_size) {
status = IXGBE_ERR_EEPROM;
goto out;
}
+ /*
+ * We cannot hold synchronization semaphores for too long
+ * to avoid other entity starvation. However it is more efficient
+ * to read in bursts than synchronizing access for each word.
+ */
+ for (i = 0; i < words; i += IXGBE_EEPROM_RD_BUFFER_MAX_COUNT) {
+ count = (words - i) / IXGBE_EEPROM_RD_BUFFER_MAX_COUNT > 0 ?
+ IXGBE_EEPROM_RD_BUFFER_MAX_COUNT : (words - i);
+
+ status = ixgbe_read_eeprom_buffer_bit_bang(hw, offset + i,
+ count, &data[i]);
+
+ if (status != 0)
+ break;
+ }
+
+out:
+ return status;
+}
+
+/**
+ * ixgbe_read_eeprom_buffer_bit_bang - Read EEPROM using bit-bang
+ * @hw: pointer to hardware structure
+ * @offset: offset within the EEPROM to be read
+ * @words: number of word(s)
+ * @data: read 16 bit word(s) from EEPROM
+ *
+ * Reads 16 bit word(s) from EEPROM through bit-bang method
+ **/
+static s32 ixgbe_read_eeprom_buffer_bit_bang(struct ixgbe_hw *hw, u16 offset,
+ u16 words, u16 *data)
+{
+ s32 status;
+ u16 word_in;
+ u8 read_opcode = IXGBE_EEPROM_READ_OPCODE_SPI;
+ u16 i;
+
/* Prepare the EEPROM for reading */
status = ixgbe_acquire_eeprom(hw);
@@ -675,29 +860,145 @@ s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
}
if (status == 0) {
- ixgbe_standby_eeprom(hw);
+ for (i = 0; i < words; i++) {
+ ixgbe_standby_eeprom(hw);
+ /*
+ * Some SPI eeproms use the 8th address bit embedded
+ * in the opcode
+ */
+ if ((hw->eeprom.address_bits == 8) &&
+ ((offset + i) >= 128))
+ read_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI;
+
+ /* Send the READ command (opcode + addr) */
+ ixgbe_shift_out_eeprom_bits(hw, read_opcode,
+ IXGBE_EEPROM_OPCODE_BITS);
+ ixgbe_shift_out_eeprom_bits(hw, (u16)((offset + i) * 2),
+ hw->eeprom.address_bits);
+
+ /* Read the data. */
+ word_in = ixgbe_shift_in_eeprom_bits(hw, 16);
+ data[i] = (word_in >> 8) | (word_in << 8);
+ }
- /*
- * Some SPI eeproms use the 8th address bit embedded in the
- * opcode
- */
- if ((hw->eeprom.address_bits == 8) && (offset >= 128))
- read_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI;
+ /* End this read operation */
+ ixgbe_release_eeprom(hw);
+ }
- /* Send the READ command (opcode + addr) */
- ixgbe_shift_out_eeprom_bits(hw, read_opcode,
- IXGBE_EEPROM_OPCODE_BITS);
- ixgbe_shift_out_eeprom_bits(hw, (u16)(offset*2),
- hw->eeprom.address_bits);
+ return status;
+}
+
+/**
+ * ixgbe_read_eeprom_bit_bang_generic - Read EEPROM word using bit-bang
+ * @hw: pointer to hardware structure
+ * @offset: offset within the EEPROM to be read
+ * @data: read 16 bit value from EEPROM
+ *
+ * Reads 16 bit value from EEPROM through bit-bang method
+ **/
+s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
+ u16 *data)
+{
+ s32 status;
- /* Read the data. */
- word_in = ixgbe_shift_in_eeprom_bits(hw, 16);
- *data = (word_in >> 8) | (word_in << 8);
+ hw->eeprom.ops.init_params(hw);
- /* End this read operation */
- ixgbe_release_eeprom(hw);
+ if (offset >= hw->eeprom.word_size) {
+ status = IXGBE_ERR_EEPROM;
+ goto out;
+ }
+
+ status = ixgbe_read_eeprom_buffer_bit_bang(hw, offset, 1, data);
+
+out:
+ return status;
+}
+
+/**
+ * ixgbe_read_eerd_buffer_generic - Read EEPROM word(s) using EERD
+ * @hw: pointer to hardware structure
+ * @offset: offset of word in the EEPROM to read
+ * @words: number of word(s)
+ * @data: 16 bit word(s) from the EEPROM
+ *
+ * Reads a 16 bit word(s) from the EEPROM using the EERD register.
+ **/
+s32 ixgbe_read_eerd_buffer_generic(struct ixgbe_hw *hw, u16 offset,
+ u16 words, u16 *data)
+{
+ u32 eerd;
+ s32 status = 0;
+ u32 i;
+
+ hw->eeprom.ops.init_params(hw);
+
+ if (words == 0) {
+ status = IXGBE_ERR_INVALID_ARGUMENT;
+ goto out;
+ }
+
+ if (offset >= hw->eeprom.word_size) {
+ status = IXGBE_ERR_EEPROM;
+ goto out;
}
+ for (i = 0; i < words; i++) {
+ eerd = ((offset + i) << IXGBE_EEPROM_RW_ADDR_SHIFT) +
+ IXGBE_EEPROM_RW_REG_START;
+
+ IXGBE_WRITE_REG(hw, IXGBE_EERD, eerd);
+ status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_READ);
+
+ if (status == 0) {
+ data[i] = (IXGBE_READ_REG(hw, IXGBE_EERD) >>
+ IXGBE_EEPROM_RW_REG_DATA);
+ } else {
+ hw_dbg(hw, "Eeprom read timed out\n");
+ goto out;
+ }
+ }
+out:
+ return status;
+}
+
+/**
+ * ixgbe_detect_eeprom_page_size_generic - Detect EEPROM page size
+ * @hw: pointer to hardware structure
+ * @offset: offset within the EEPROM to be used as a scratch pad
+ *
+ * Discover EEPROM page size by writing marching data at given offset.
+ * This function is called only when we are writing a new large buffer
+ * at given offset so the data would be overwritten anyway.
+ **/
+static s32 ixgbe_detect_eeprom_page_size_generic(struct ixgbe_hw *hw,
+ u16 offset)
+{
+ u16 data[IXGBE_EEPROM_PAGE_SIZE_MAX];
+ s32 status = 0;
+ u16 i;
+
+ for (i = 0; i < IXGBE_EEPROM_PAGE_SIZE_MAX; i++)
+ data[i] = i;
+
+ hw->eeprom.word_page_size = IXGBE_EEPROM_PAGE_SIZE_MAX;
+ status = ixgbe_write_eeprom_buffer_bit_bang(hw, offset,
+ IXGBE_EEPROM_PAGE_SIZE_MAX, data);
+ hw->eeprom.word_page_size = 0;
+ if (status != 0)
+ goto out;
+
+ status = ixgbe_read_eeprom_buffer_bit_bang(hw, offset, 1, data);
+ if (status != 0)
+ goto out;
+
+ /*
+ * When writing in burst more than the actual page size
+ * EEPROM address wraps around current page.
+ */
+ hw->eeprom.word_page_size = IXGBE_EEPROM_PAGE_SIZE_MAX - data[0];
+
+ hw_dbg(hw, "Detected EEPROM page size = %d words.",
+ hw->eeprom.word_page_size);
out:
return status;
}
@@ -712,33 +1013,75 @@ out:
**/
s32 ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data)
{
- u32 eerd;
- s32 status;
+ return ixgbe_read_eerd_buffer_generic(hw, offset, 1, data);
+}
+
+/**
+ * ixgbe_write_eewr_buffer_generic - Write EEPROM word(s) using EEWR
+ * @hw: pointer to hardware structure
+ * @offset: offset of word in the EEPROM to write
+ * @words: number of words
+ * @data: word(s) write to the EEPROM
+ *
+ * Write a 16 bit word(s) to the EEPROM using the EEWR register.
+ **/
+s32 ixgbe_write_eewr_buffer_generic(struct ixgbe_hw *hw, u16 offset,
+ u16 words, u16 *data)
+{
+ u32 eewr;
+ s32 status = 0;
+ u16 i;
hw->eeprom.ops.init_params(hw);
+ if (words == 0) {
+ status = IXGBE_ERR_INVALID_ARGUMENT;
+ goto out;
+ }
+
if (offset >= hw->eeprom.word_size) {
status = IXGBE_ERR_EEPROM;
goto out;
}
- eerd = (offset << IXGBE_EEPROM_RW_ADDR_SHIFT) +
- IXGBE_EEPROM_RW_REG_START;
+ for (i = 0; i < words; i++) {
+ eewr = ((offset + i) << IXGBE_EEPROM_RW_ADDR_SHIFT) |
+ (data[i] << IXGBE_EEPROM_RW_REG_DATA) |
+ IXGBE_EEPROM_RW_REG_START;
- IXGBE_WRITE_REG(hw, IXGBE_EERD, eerd);
- status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_READ);
+ status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE);
+ if (status != 0) {
+ hw_dbg(hw, "Eeprom write EEWR timed out\n");
+ goto out;
+ }
- if (status == 0)
- *data = (IXGBE_READ_REG(hw, IXGBE_EERD) >>
- IXGBE_EEPROM_RW_REG_DATA);
- else
- hw_dbg(hw, "Eeprom read timed out\n");
+ IXGBE_WRITE_REG(hw, IXGBE_EEWR, eewr);
+
+ status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE);
+ if (status != 0) {
+ hw_dbg(hw, "Eeprom write EEWR timed out\n");
+ goto out;
+ }
+ }
out:
return status;
}
/**
+ * ixgbe_write_eewr_generic - Write EEPROM word using EEWR
+ * @hw: pointer to hardware structure
+ * @offset: offset of word in the EEPROM to write
+ * @data: word write to the EEPROM
+ *
+ * Write a 16 bit word to the EEPROM using the EEWR register.
+ **/
+s32 ixgbe_write_eewr_generic(struct ixgbe_hw *hw, u16 offset, u16 data)
+{
+ return ixgbe_write_eewr_buffer_generic(hw, offset, 1, &data);
+}
+
+/**
* ixgbe_poll_eerd_eewr_done - Poll EERD read or EEWR write status
* @hw: pointer to hardware structure
* @ee_reg: EEPROM flag for polling
@@ -746,7 +1089,7 @@ out:
* Polls the status bit (bit 1) of the EERD or EEWR to determine when the
* read or write is done respectively.
**/
-s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg)
+static s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg)
{
u32 i;
u32 reg;
@@ -846,6 +1189,28 @@ static s32 ixgbe_get_eeprom_semaphore(struct ixgbe_hw *hw)
udelay(50);
}
+ if (i == timeout) {
+ hw_dbg(hw, "Driver can't access the Eeprom - SMBI Semaphore "
+ "not granted.\n");
+ /*
+ * this release is particularly important because our attempts
+ * above to get the semaphore may have succeeded, and if there
+ * was a timeout, we should unconditionally clear the semaphore
+ * bits to free the driver to make progress
+ */
+ ixgbe_release_eeprom_semaphore(hw);
+
+ udelay(50);
+ /*
+ * one last try
+ * If the SMBI bit is 0 when we read it, then the bit will be
+ * set and we have the semaphore
+ */
+ swsm = IXGBE_READ_REG(hw, IXGBE_SWSM);
+ if (!(swsm & IXGBE_SWSM_SMBI))
+ status = 0;
+ }
+
/* Now get the semaphore between SW/FW through the SWESMBI bit */
if (status == 0) {
for (i = 0; i < timeout; i++) {
@@ -1112,8 +1477,12 @@ static void ixgbe_release_eeprom(struct ixgbe_hw *hw)
hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
- /* Delay before attempt to obtain semaphore again to allow FW access */
- msleep(hw->eeprom.semaphore_delay);
+ /*
+ * Delay before attempt to obtain semaphore again to allow FW
+ * access. semaphore_delay is in ms we need us for usleep_range
+ */
+ usleep_range(hw->eeprom.semaphore_delay * 1000,
+ hw->eeprom.semaphore_delay * 2000);
}
/**
@@ -2189,7 +2558,7 @@ s32 ixgbe_acquire_swfw_sync(struct ixgbe_hw *hw, u16 mask)
* thread currently using resource (swmask)
*/
ixgbe_release_eeprom_semaphore(hw);
- msleep(5);
+ usleep_range(5000, 10000);
timeout--;
}
@@ -2263,7 +2632,7 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index)
autoc_reg |= IXGBE_AUTOC_AN_RESTART;
autoc_reg |= IXGBE_AUTOC_FLU;
IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg);
- msleep(10);
+ usleep_range(10000, 20000);
}
led_reg &= ~IXGBE_LED_MODE_MASK(index);
@@ -2883,3 +3252,18 @@ void ixgbe_set_vlan_anti_spoofing(struct ixgbe_hw *hw, bool enable, int vf)
pfvfspoof &= ~(1 << vf_target_shift);
IXGBE_WRITE_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg), pfvfspoof);
}
+
+/**
+ * ixgbe_get_device_caps_generic - Get additional device capabilities
+ * @hw: pointer to hardware structure
+ * @device_caps: the EEPROM word with the extra device capabilities
+ *
+ * This function will read the EEPROM location for the device capabilities,
+ * and return the word through device_caps.
+ **/
+s32 ixgbe_get_device_caps_generic(struct ixgbe_hw *hw, u16 *device_caps)
+{
+ hw->eeprom.ops.read(hw, IXGBE_DEVICE_CAPS, device_caps);
+
+ return 0;
+}
diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h
index 508f635fc2ca..46be83cfb500 100644
--- a/drivers/net/ixgbe/ixgbe_common.h
+++ b/drivers/net/ixgbe/ixgbe_common.h
@@ -35,6 +35,7 @@ u32 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw);
s32 ixgbe_init_ops_generic(struct ixgbe_hw *hw);
s32 ixgbe_init_hw_generic(struct ixgbe_hw *hw);
s32 ixgbe_start_hw_generic(struct ixgbe_hw *hw);
+s32 ixgbe_start_hw_gen2(struct ixgbe_hw *hw);
s32 ixgbe_clear_hw_cntrs_generic(struct ixgbe_hw *hw);
s32 ixgbe_read_pba_string_generic(struct ixgbe_hw *hw, u8 *pba_num,
u32 pba_num_size);
@@ -48,14 +49,22 @@ s32 ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index);
s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw);
s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data);
+s32 ixgbe_write_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
+ u16 words, u16 *data);
s32 ixgbe_read_eerd_generic(struct ixgbe_hw *hw, u16 offset, u16 *data);
+s32 ixgbe_read_eerd_buffer_generic(struct ixgbe_hw *hw, u16 offset,
+ u16 words, u16 *data);
+s32 ixgbe_write_eewr_generic(struct ixgbe_hw *hw, u16 offset, u16 data);
+s32 ixgbe_write_eewr_buffer_generic(struct ixgbe_hw *hw, u16 offset,
+ u16 words, u16 *data);
s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
u16 *data);
+s32 ixgbe_read_eeprom_buffer_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
+ u16 words, u16 *data);
u16 ixgbe_calc_eeprom_checksum_generic(struct ixgbe_hw *hw);
s32 ixgbe_validate_eeprom_checksum_generic(struct ixgbe_hw *hw,
u16 *checksum_val);
s32 ixgbe_update_eeprom_checksum_generic(struct ixgbe_hw *hw);
-s32 ixgbe_poll_eerd_eewr_done(struct ixgbe_hw *hw, u32 ee_reg);
s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq,
u32 enable_addr);
@@ -89,6 +98,7 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index);
s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index);
void ixgbe_set_mac_anti_spoofing(struct ixgbe_hw *hw, bool enable, int pf);
void ixgbe_set_vlan_anti_spoofing(struct ixgbe_hw *hw, bool enable, int vf);
+s32 ixgbe_get_device_caps_generic(struct ixgbe_hw *hw, u16 *device_caps);
#define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg)))
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82598.c b/drivers/net/ixgbe/ixgbe_dcb_82598.c
index 1bc57e52cee3..771d01a60d06 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_82598.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_82598.c
@@ -289,7 +289,7 @@ s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, u8 pfc_en)
* Configure queue statistics registers, all queues belonging to same traffic
* class uses a single set of queue statistics counters.
*/
-s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw)
+static s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw)
{
u32 reg = 0;
u8 i = 0;
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ixgbe/ixgbe_dcb_82599.c
index 025af8c53ddb..d50cf78c234d 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_82599.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_82599.c
@@ -39,36 +39,52 @@
*/
static s32 ixgbe_dcb_config_packet_buffers_82599(struct ixgbe_hw *hw, u8 rx_pba)
{
- s32 ret_val = 0;
- u32 value = IXGBE_RXPBSIZE_64KB;
+ int num_tcs = IXGBE_MAX_PACKET_BUFFERS;
+ u32 rx_pb_size = hw->mac.rx_pb_size << IXGBE_RXPBSIZE_SHIFT;
+ u32 rxpktsize;
+ u32 txpktsize;
+ u32 txpbthresh;
u8 i = 0;
- /* Setup Rx packet buffer sizes */
- switch (rx_pba) {
- case pba_80_48:
- /* Setup the first four at 80KB */
- value = IXGBE_RXPBSIZE_80KB;
- for (; i < 4; i++)
- IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), value);
- /* Setup the last four at 48KB...don't re-init i */
- value = IXGBE_RXPBSIZE_48KB;
- /* Fall Through */
- case pba_equal:
- default:
- for (; i < IXGBE_MAX_PACKET_BUFFERS; i++)
- IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), value);
-
- /* Setup Tx packet buffer sizes */
- for (i = 0; i < IXGBE_MAX_PACKET_BUFFERS; i++) {
- IXGBE_WRITE_REG(hw, IXGBE_TXPBSIZE(i),
- IXGBE_TXPBSIZE_20KB);
- IXGBE_WRITE_REG(hw, IXGBE_TXPBTHRESH(i),
- IXGBE_TXPBTHRESH_DCB);
- }
- break;
+ /*
+ * This really means configure the first half of the TCs
+ * (Traffic Classes) to use 5/8 of the Rx packet buffer
+ * space. To determine the size of the buffer for each TC,
+ * we are multiplying the average size by 5/4 and applying
+ * it to half of the traffic classes.
+ */
+ if (rx_pba == pba_80_48) {
+ rxpktsize = (rx_pb_size * 5) / (num_tcs * 4);
+ rx_pb_size -= rxpktsize * (num_tcs / 2);
+ for (; i < (num_tcs / 2); i++)
+ IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), rxpktsize);
+ }
+
+ /* Divide the remaining Rx packet buffer evenly among the TCs */
+ rxpktsize = rx_pb_size / (num_tcs - i);
+ for (; i < num_tcs; i++)
+ IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), rxpktsize);
+
+ /*
+ * Setup Tx packet buffer and threshold equally for all TCs
+ * TXPBTHRESH register is set in K so divide by 1024 and subtract
+ * 10 since the largest packet we support is just over 9K.
+ */
+ txpktsize = IXGBE_TXPBSIZE_MAX / num_tcs;
+ txpbthresh = (txpktsize / 1024) - IXGBE_TXPKT_SIZE_MAX;
+ for (i = 0; i < num_tcs; i++) {
+ IXGBE_WRITE_REG(hw, IXGBE_TXPBSIZE(i), txpktsize);
+ IXGBE_WRITE_REG(hw, IXGBE_TXPBTHRESH(i), txpbthresh);
+ }
+
+ /* Clear unused TCs, if any, to zero buffer size*/
+ for (; i < MAX_TRAFFIC_CLASS; i++) {
+ IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), 0);
+ IXGBE_WRITE_REG(hw, IXGBE_TXPBSIZE(i), 0);
+ IXGBE_WRITE_REG(hw, IXGBE_TXPBTHRESH(i), 0);
}
- return ret_val;
+ return 0;
}
/**
@@ -285,12 +301,17 @@ s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw, u8 pfc_en)
IXGBE_WRITE_REG(hw, IXGBE_FCCFG, reg);
/*
* Enable Receive PFC
- * We will always honor XOFF frames we receive when
- * we are in PFC mode.
+ * 82599 will always honor XOFF frames we receive when
+ * we are in PFC mode however X540 only honors enabled
+ * traffic classes.
*/
reg = IXGBE_READ_REG(hw, IXGBE_MFLCN);
reg &= ~IXGBE_MFLCN_RFCE;
reg |= IXGBE_MFLCN_RPFCE | IXGBE_MFLCN_DPF;
+
+ if (hw->mac.type == ixgbe_mac_X540)
+ reg |= pfc_en << IXGBE_MFLCN_RPFCE_SHIFT;
+
IXGBE_WRITE_REG(hw, IXGBE_MFLCN, reg);
} else {
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.h b/drivers/net/ixgbe/ixgbe_dcb_82599.h
index 148fd8b477a9..2de71a503153 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_82599.h
+++ b/drivers/net/ixgbe/ixgbe_dcb_82599.h
@@ -92,8 +92,10 @@
#define IXGBE_RXPBSIZE_64KB 0x00010000 /* 64KB Packet Buffer */
#define IXGBE_RXPBSIZE_80KB 0x00014000 /* 80KB Packet Buffer */
#define IXGBE_RXPBSIZE_128KB 0x00020000 /* 128KB Packet Buffer */
+#define IXGBE_TXPBSIZE_MAX 0x00028000 /* 160KB Packet Buffer*/
#define IXGBE_TXPBTHRESH_DCB 0xA /* THRESH value for DCB mode */
+#define IXGBE_TXPKT_SIZE_MAX 0xA /* Max Tx Packet size */
/* SECTXMINIFG DCB */
#define IXGBE_SECTX_DCB 0x00001F00 /* DCB TX Buffer IFG */
diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c
index 327c8614198c..5e7ed225851a 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_nl.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c
@@ -347,18 +347,28 @@ static void ixgbe_dcbnl_get_pfc_cfg(struct net_device *netdev, int priority,
static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct dcb_app app = {
+ .selector = DCB_APP_IDTYPE_ETHTYPE,
+ .protocol = ETH_P_FCOE,
+ };
+ u8 up = dcb_getapp(netdev, &app);
int ret;
- if (!adapter->dcb_set_bitmap ||
- !(adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE))
- return DCB_NO_HW_CHG;
-
ret = ixgbe_copy_dcb_cfg(&adapter->temp_dcb_cfg, &adapter->dcb_cfg,
MAX_TRAFFIC_CLASS);
-
if (ret)
return DCB_NO_HW_CHG;
+ /* In IEEE mode app data must be parsed into DCBX format for
+ * hardware routines.
+ */
+ if (adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE)
+ up = (1 << up);
+
+#ifdef IXGBE_FCOE
+ if (up && (up != (1 << adapter->fcoe.up)))
+ adapter->dcb_set_bitmap |= BIT_APP_UPCHG;
+
/*
* Only take down the adapter if an app change occurred. FCoE
* may shuffle tx rings in this case and this can not be done
@@ -366,12 +376,15 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
*/
if (adapter->dcb_set_bitmap & BIT_APP_UPCHG) {
while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
- msleep(1);
+ usleep_range(1000, 2000);
+
+ ixgbe_fcoe_setapp(adapter, up);
if (netif_running(netdev))
netdev->netdev_ops->ndo_stop(netdev);
ixgbe_clear_interrupt_scheme(adapter);
}
+#endif
if (adapter->dcb_cfg.pfc_mode_enable) {
switch (adapter->hw.mac.type) {
@@ -399,12 +412,14 @@ static u8 ixgbe_dcbnl_set_all(struct net_device *netdev)
}
}
+#ifdef IXGBE_FCOE
if (adapter->dcb_set_bitmap & BIT_APP_UPCHG) {
ixgbe_init_interrupt_scheme(adapter);
if (netif_running(netdev))
netdev->netdev_ops->ndo_open(netdev);
ret = DCB_HW_CHG_RST;
}
+#endif
if (adapter->dcb_set_bitmap & BIT_PFC) {
u8 pfc_en;
@@ -558,68 +573,6 @@ static u8 ixgbe_dcbnl_getapp(struct net_device *netdev, u8 idtype, u16 id)
return dcb_getapp(netdev, &app);
}
-/**
- * ixgbe_dcbnl_setapp - set the DCBX application user priority
- * @netdev : the corresponding netdev
- * @idtype : identifies the id as ether type or TCP/UDP port number
- * @id: id is either ether type or TCP/UDP port number
- * @up: the 802.1p user priority bitmap
- *
- * Returns : 0 on success or 1 on error
- */
-static u8 ixgbe_dcbnl_setapp(struct net_device *netdev,
- u8 idtype, u16 id, u8 up)
-{
- struct ixgbe_adapter *adapter = netdev_priv(netdev);
- u8 rval = 1;
- struct dcb_app app = {
- .selector = idtype,
- .protocol = id,
- .priority = up
- };
-
- if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE))
- return rval;
-
- rval = dcb_setapp(netdev, &app);
-
- switch (idtype) {
- case DCB_APP_IDTYPE_ETHTYPE:
-#ifdef IXGBE_FCOE
- if (id == ETH_P_FCOE) {
- u8 old_tc;
-
- /* Get current programmed tc */
- old_tc = adapter->fcoe.tc;
- rval = ixgbe_fcoe_setapp(adapter, up);
-
- if (rval ||
- !(adapter->flags & IXGBE_FLAG_DCB_ENABLED) ||
- !(adapter->flags & IXGBE_FLAG_FCOE_ENABLED))
- break;
-
- /* The FCoE application priority may be changed multiple
- * times in quick succession with switches that build up
- * TLVs. To avoid creating uneeded device resets this
- * checks the actual HW configuration and clears
- * BIT_APP_UPCHG if a HW configuration change is not
- * need
- */
- if (old_tc == adapter->fcoe.tc)
- adapter->dcb_set_bitmap &= ~BIT_APP_UPCHG;
- else
- adapter->dcb_set_bitmap |= BIT_APP_UPCHG;
- }
-#endif
- break;
- case DCB_APP_IDTYPE_PORTNUM:
- break;
- default:
- break;
- }
- return rval;
-}
-
static int ixgbe_dcbnl_ieee_getets(struct net_device *dev,
struct ieee_ets *ets)
{
@@ -745,25 +698,14 @@ static int ixgbe_dcbnl_ieee_setapp(struct net_device *dev,
if (!(adapter->dcbx_cap & DCB_CAP_DCBX_VER_IEEE))
return -EINVAL;
-#ifdef IXGBE_FCOE
- if (app->selector == 1 && app->protocol == ETH_P_FCOE) {
- if (adapter->fcoe.tc == app->priority)
- goto setapp;
- /* In IEEE mode map up to tc 1:1 */
- adapter->fcoe.tc = app->priority;
- adapter->fcoe.up = app->priority;
+ dcb_setapp(dev, app);
- /* Force hardware reset required to push FCoE
- * setup on {tx|rx}_rings
- */
- adapter->dcb_set_bitmap |= BIT_APP_UPCHG;
+#ifdef IXGBE_FCOE
+ if (app->selector == 1 && app->protocol == ETH_P_FCOE &&
+ adapter->fcoe.tc == app->priority)
ixgbe_dcbnl_set_all(dev);
- }
-
-setapp:
#endif
- dcb_setapp(dev, app);
return 0;
}
@@ -838,7 +780,6 @@ const struct dcbnl_rtnl_ops dcbnl_ops = {
.getpfcstate = ixgbe_dcbnl_getpfcstate,
.setpfcstate = ixgbe_dcbnl_setpfcstate,
.getapp = ixgbe_dcbnl_getapp,
- .setapp = ixgbe_dcbnl_setapp,
.getdcbx = ixgbe_dcbnl_getdcbx,
.setdcbx = ixgbe_dcbnl_setdcbx,
};
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
index 76380a2b35aa..cb1555bc8548 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -84,6 +84,7 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = {
{"hw_rsc_flushed", IXGBE_STAT(rsc_total_flush)},
{"fdir_match", IXGBE_STAT(stats.fdirmatch)},
{"fdir_miss", IXGBE_STAT(stats.fdirmiss)},
+ {"fdir_overflow", IXGBE_STAT(fdir_overflow)},
{"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)},
@@ -102,6 +103,10 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = {
{"alloc_rx_page_failed", IXGBE_STAT(alloc_rx_page_failed)},
{"alloc_rx_buff_failed", IXGBE_STAT(alloc_rx_buff_failed)},
{"rx_no_dma_resources", IXGBE_STAT(hw_rx_no_dma_resources)},
+ {"os2bmc_rx_by_bmc", IXGBE_STAT(stats.o2bgptc)},
+ {"os2bmc_tx_by_bmc", IXGBE_STAT(stats.b2ospc)},
+ {"os2bmc_tx_by_host", IXGBE_STAT(stats.o2bspc)},
+ {"os2bmc_rx_by_host", IXGBE_STAT(stats.b2ogprc)},
#ifdef IXGBE_FCOE
{"fcoe_bad_fccrc", IXGBE_STAT(stats.fccrc)},
{"rx_fcoe_dropped", IXGBE_STAT(stats.fcoerpdc)},
@@ -288,20 +293,20 @@ static int ixgbe_get_settings(struct net_device *netdev,
if (link_up) {
switch (link_speed) {
case IXGBE_LINK_SPEED_10GB_FULL:
- ecmd->speed = SPEED_10000;
+ ethtool_cmd_speed_set(ecmd, SPEED_10000);
break;
case IXGBE_LINK_SPEED_1GB_FULL:
- ecmd->speed = SPEED_1000;
+ ethtool_cmd_speed_set(ecmd, SPEED_1000);
break;
case IXGBE_LINK_SPEED_100_FULL:
- ecmd->speed = SPEED_100;
+ ethtool_cmd_speed_set(ecmd, SPEED_100);
break;
default:
break;
}
ecmd->duplex = DUPLEX_FULL;
} else {
- ecmd->speed = -1;
+ ethtool_cmd_speed_set(ecmd, -1);
ecmd->duplex = -1;
}
@@ -346,9 +351,10 @@ static int ixgbe_set_settings(struct net_device *netdev,
}
} else {
/* in this case we currently only support 10Gb/FULL */
+ u32 speed = ethtool_cmd_speed(ecmd);
if ((ecmd->autoneg == AUTONEG_ENABLE) ||
(ecmd->advertising != ADVERTISED_10000baseT_Full) ||
- (ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL))
+ (speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL))
return -EINVAL;
}
@@ -846,11 +852,8 @@ static int ixgbe_get_eeprom(struct net_device *netdev,
if (!eeprom_buff)
return -ENOMEM;
- for (i = 0; i < eeprom_len; i++) {
- if ((ret_val = hw->eeprom.ops.read(hw, first_word + i,
- &eeprom_buff[i])))
- break;
- }
+ ret_val = hw->eeprom.ops.read_buffer(hw, first_word, eeprom_len,
+ eeprom_buff);
/* Device's eeprom is always little-endian, word addressable */
for (i = 0; i < eeprom_len; i++)
@@ -931,7 +934,7 @@ static int ixgbe_set_ringparam(struct net_device *netdev,
}
while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
- msleep(1);
+ usleep_range(1000, 2000);
if (!netif_running(adapter->netdev)) {
for (i = 0; i < adapter->num_tx_queues; i++)
@@ -1030,9 +1033,6 @@ static int ixgbe_get_sset_count(struct net_device *netdev, int sset)
return IXGBE_TEST_LEN;
case ETH_SS_STATS:
return IXGBE_STATS_LEN;
- case ETH_SS_NTUPLE_FILTERS:
- return ETHTOOL_MAX_NTUPLE_LIST_ENTRY *
- ETHTOOL_MAX_NTUPLE_STRING_PER_ENTRY;
default:
return -EOPNOTSUPP;
}
@@ -1238,46 +1238,62 @@ static const struct ixgbe_reg_test reg_test_82598[] = {
{ 0, 0, 0, 0 }
};
-static const u32 register_test_patterns[] = {
- 0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF
-};
-
-#define REG_PATTERN_TEST(R, M, W) \
-{ \
- u32 pat, val, before; \
- for (pat = 0; pat < ARRAY_SIZE(register_test_patterns); pat++) { \
- before = readl(adapter->hw.hw_addr + R); \
- writel((register_test_patterns[pat] & W), \
- (adapter->hw.hw_addr + R)); \
- val = readl(adapter->hw.hw_addr + R); \
- if (val != (register_test_patterns[pat] & W & M)) { \
- e_err(drv, "pattern test reg %04X failed: got " \
- "0x%08X expected 0x%08X\n", \
- R, val, (register_test_patterns[pat] & W & M)); \
- *data = R; \
- writel(before, adapter->hw.hw_addr + R); \
- return 1; \
- } \
- writel(before, adapter->hw.hw_addr + R); \
- } \
+static bool reg_pattern_test(struct ixgbe_adapter *adapter, u64 *data, int reg,
+ u32 mask, u32 write)
+{
+ u32 pat, val, before;
+ static const u32 test_pattern[] = {
+ 0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};
+
+ for (pat = 0; pat < ARRAY_SIZE(test_pattern); pat++) {
+ before = readl(adapter->hw.hw_addr + reg);
+ writel((test_pattern[pat] & write),
+ (adapter->hw.hw_addr + reg));
+ val = readl(adapter->hw.hw_addr + reg);
+ if (val != (test_pattern[pat] & write & mask)) {
+ e_err(drv, "pattern test reg %04X failed: got "
+ "0x%08X expected 0x%08X\n",
+ reg, val, (test_pattern[pat] & write & mask));
+ *data = reg;
+ writel(before, adapter->hw.hw_addr + reg);
+ return 1;
+ }
+ writel(before, adapter->hw.hw_addr + reg);
+ }
+ return 0;
}
-#define REG_SET_AND_CHECK(R, M, W) \
-{ \
- u32 val, before; \
- before = readl(adapter->hw.hw_addr + R); \
- writel((W & M), (adapter->hw.hw_addr + R)); \
- val = readl(adapter->hw.hw_addr + R); \
- if ((W & M) != (val & 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; \
- } \
- writel(before, (adapter->hw.hw_addr + R)); \
+static bool reg_set_and_check(struct ixgbe_adapter *adapter, u64 *data, int reg,
+ u32 mask, u32 write)
+{
+ u32 val, before;
+ before = readl(adapter->hw.hw_addr + reg);
+ writel((write & mask), (adapter->hw.hw_addr + reg));
+ val = readl(adapter->hw.hw_addr + reg);
+ if ((write & mask) != (val & mask)) {
+ e_err(drv, "set/check reg %04X test failed: got 0x%08X "
+ "expected 0x%08X\n", reg, (val & mask), (write & mask));
+ *data = reg;
+ writel(before, (adapter->hw.hw_addr + reg));
+ return 1;
+ }
+ writel(before, (adapter->hw.hw_addr + reg));
+ return 0;
}
+#define REG_PATTERN_TEST(reg, mask, write) \
+ do { \
+ if (reg_pattern_test(adapter, data, reg, mask, write)) \
+ return 1; \
+ } while (0) \
+
+
+#define REG_SET_AND_CHECK(reg, mask, write) \
+ do { \
+ if (reg_set_and_check(adapter, data, reg, mask, write)) \
+ return 1; \
+ } while (0) \
+
static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data)
{
const struct ixgbe_reg_test *test;
@@ -1328,13 +1344,13 @@ static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data)
switch (test->test_type) {
case PATTERN_TEST:
REG_PATTERN_TEST(test->reg + (i * 0x40),
- test->mask,
- test->write);
+ test->mask,
+ test->write);
break;
case SET_READ_TEST:
REG_SET_AND_CHECK(test->reg + (i * 0x40),
- test->mask,
- test->write);
+ test->mask,
+ test->write);
break;
case WRITE_NO_TEST:
writel(test->write,
@@ -1343,18 +1359,18 @@ static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data)
break;
case TABLE32_TEST:
REG_PATTERN_TEST(test->reg + (i * 4),
- test->mask,
- test->write);
+ test->mask,
+ test->write);
break;
case TABLE64_TEST_LO:
REG_PATTERN_TEST(test->reg + (i * 8),
- test->mask,
- test->write);
+ test->mask,
+ test->write);
break;
case TABLE64_TEST_HI:
REG_PATTERN_TEST((test->reg + 4) + (i * 8),
- test->mask,
- test->write);
+ test->mask,
+ test->write);
break;
}
}
@@ -1417,7 +1433,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data)
/* Disable all the interrupts */
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF);
- msleep(10);
+ usleep_range(10000, 20000);
/* Test each interrupt */
for (; i < 10; i++) {
@@ -1437,7 +1453,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data)
~mask & 0x00007FFF);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS,
~mask & 0x00007FFF);
- msleep(10);
+ usleep_range(10000, 20000);
if (adapter->test_icr & mask) {
*data = 3;
@@ -1454,7 +1470,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data)
adapter->test_icr = 0;
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask);
- msleep(10);
+ usleep_range(10000, 20000);
if (!(adapter->test_icr &mask)) {
*data = 4;
@@ -1474,7 +1490,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data)
~mask & 0x00007FFF);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS,
~mask & 0x00007FFF);
- msleep(10);
+ usleep_range(10000, 20000);
if (adapter->test_icr) {
*data = 5;
@@ -1485,7 +1501,7 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data)
/* Disable all the interrupts */
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF);
- msleep(10);
+ usleep_range(10000, 20000);
/* Unhook test interrupt handler */
free_irq(irq, netdev);
@@ -1598,6 +1614,13 @@ static int ixgbe_setup_loopback_test(struct ixgbe_adapter *adapter)
struct ixgbe_hw *hw = &adapter->hw;
u32 reg_data;
+ /* X540 needs to set the MACC.FLU bit to force link up */
+ if (adapter->hw.mac.type == ixgbe_mac_X540) {
+ reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_MACC);
+ reg_data |= IXGBE_MACC_FLU;
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_MACC, reg_data);
+ }
+
/* right now we only support MAC loopback in the driver */
reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_HLREG0);
/* Setup MAC loopback */
@@ -1613,7 +1636,7 @@ static int ixgbe_setup_loopback_test(struct ixgbe_adapter *adapter)
reg_data |= IXGBE_AUTOC_LMS_10G_LINK_NO_AN | IXGBE_AUTOC_FLU;
IXGBE_WRITE_REG(&adapter->hw, IXGBE_AUTOC, reg_data);
IXGBE_WRITE_FLUSH(&adapter->hw);
- msleep(10);
+ usleep_range(10000, 20000);
/* Disable Atlas Tx lanes; re-enabled in reset path */
if (hw->mac.type == ixgbe_mac_82598EB) {
@@ -1999,25 +2022,30 @@ static int ixgbe_nway_reset(struct net_device *netdev)
return 0;
}
-static int ixgbe_phys_id(struct net_device *netdev, u32 data)
+static int ixgbe_set_phys_id(struct net_device *netdev,
+ enum ethtool_phys_id_state state)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
struct ixgbe_hw *hw = &adapter->hw;
- u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
- u32 i;
- if (!data || data > 300)
- data = 300;
+ switch (state) {
+ case ETHTOOL_ID_ACTIVE:
+ adapter->led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
+ return 2;
- for (i = 0; i < (data * 1000); i += 400) {
+ case ETHTOOL_ID_ON:
hw->mac.ops.led_on(hw, IXGBE_LED_ON);
- msleep_interruptible(200);
+ break;
+
+ case ETHTOOL_ID_OFF:
hw->mac.ops.led_off(hw, IXGBE_LED_ON);
- msleep_interruptible(200);
- }
+ break;
- /* Restore LED settings */
- IXGBE_WRITE_REG(&adapter->hw, IXGBE_LEDCTL, led_reg);
+ case ETHTOOL_ID_INACTIVE:
+ /* Restore LED settings */
+ IXGBE_WRITE_REG(&adapter->hw, IXGBE_LEDCTL, adapter->led_reg);
+ break;
+ }
return 0;
}
@@ -2230,8 +2258,13 @@ static int ixgbe_set_flags(struct net_device *netdev, u32 data)
need_reset = (data & ETH_FLAG_RXVLAN) !=
(netdev->features & NETIF_F_HW_VLAN_RX);
+ if ((data & ETH_FLAG_RXHASH) &&
+ !(adapter->flags & IXGBE_FLAG_RSS_ENABLED))
+ return -EOPNOTSUPP;
+
rc = ethtool_op_set_flags(netdev, data, ETH_FLAG_LRO | ETH_FLAG_NTUPLE |
- ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN);
+ ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN |
+ ETH_FLAG_RXHASH);
if (rc)
return rc;
@@ -2465,7 +2498,7 @@ static const struct ethtool_ops ixgbe_ethtool_ops = {
.set_tso = ixgbe_set_tso,
.self_test = ixgbe_diag_test,
.get_strings = ixgbe_get_strings,
- .phys_id = ixgbe_phys_id,
+ .set_phys_id = ixgbe_set_phys_id,
.get_sset_count = ixgbe_get_sset_count,
.get_ethtool_stats = ixgbe_get_ethtool_stats,
.get_coalesce = ixgbe_get_coalesce,
diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c
index dba7d77588ef..05920726e824 100644
--- a/drivers/net/ixgbe/ixgbe_fcoe.c
+++ b/drivers/net/ixgbe/ixgbe_fcoe.c
@@ -416,8 +416,7 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter,
if (!ddp->udl)
goto ddp_out;
- ddp->err = (fcerr | fceofe);
- if (ddp->err)
+ if (fcerr | fceofe)
goto ddp_out;
fcstat = (sterr & IXGBE_RXDADV_STAT_FCSTAT);
@@ -428,6 +427,7 @@ int ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter,
if (fcstat == IXGBE_RXDADV_STAT_FCSTAT_FCPRSP) {
pci_unmap_sg(adapter->pdev, ddp->sgl,
ddp->sgc, DMA_FROM_DEVICE);
+ ddp->err = (fcerr | fceofe);
ddp->sgl = NULL;
ddp->sgc = 0;
}
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 6f8adc7f5d7c..08e8e25c159d 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -41,6 +41,7 @@
#include <net/ip6_checksum.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
+#include <linux/prefetch.h>
#include <scsi/fc/fc_fcoe.h>
#include "ixgbe.h"
@@ -51,8 +52,12 @@
char ixgbe_driver_name[] = "ixgbe";
static const char ixgbe_driver_string[] =
"Intel(R) 10 Gigabit PCI Express Network Driver";
-
-#define DRV_VERSION "3.2.9-k2"
+#define MAJ 3
+#define MIN 3
+#define BUILD 8
+#define KFIX 2
+#define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \
+ __stringify(BUILD) "-k" __stringify(KFIX)
const char ixgbe_driver_version[] = DRV_VERSION;
static const char ixgbe_copyright[] =
"Copyright (c) 1999-2011 Intel Corporation.";
@@ -120,6 +125,10 @@ static DEFINE_PCI_DEVICE_TABLE(ixgbe_pci_tbl) = {
board_82599 },
{PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540T),
board_X540 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_SF2),
+ board_82599 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_LS),
+ board_82599 },
/* required last entry */
{0, }
@@ -185,6 +194,22 @@ static inline void ixgbe_disable_sriov(struct ixgbe_adapter *adapter)
adapter->flags &= ~IXGBE_FLAG_SRIOV_ENABLED;
}
+static void ixgbe_service_event_schedule(struct ixgbe_adapter *adapter)
+{
+ if (!test_bit(__IXGBE_DOWN, &adapter->state) &&
+ !test_and_set_bit(__IXGBE_SERVICE_SCHED, &adapter->state))
+ schedule_work(&adapter->service_task);
+}
+
+static void ixgbe_service_event_complete(struct ixgbe_adapter *adapter)
+{
+ BUG_ON(!test_bit(__IXGBE_SERVICE_SCHED, &adapter->state));
+
+ /* flush memory to make sure state is correct before next watchog */
+ smp_mb__before_clear_bit();
+ clear_bit(__IXGBE_SERVICE_SCHED, &adapter->state);
+}
+
struct ixgbe_reg_info {
u32 ofs;
char *name;
@@ -811,7 +836,19 @@ static inline bool ixgbe_check_tx_hang(struct ixgbe_ring *tx_ring)
#define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \
MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1) /* for context */
-static void ixgbe_tx_timeout(struct net_device *netdev);
+/**
+ * ixgbe_tx_timeout_reset - initiate reset due to Tx timeout
+ * @adapter: driver private struct
+ **/
+static void ixgbe_tx_timeout_reset(struct ixgbe_adapter *adapter)
+{
+
+ /* Do the reset outside of interrupt context */
+ if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
+ adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED;
+ ixgbe_service_event_schedule(adapter);
+ }
+}
/**
* ixgbe_clean_tx_irq - Reclaim resources after transmit completes
@@ -893,7 +930,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
adapter->tx_timeout_count + 1, tx_ring->queue_index);
/* schedule immediate reset if we believe we hung */
- ixgbe_tx_timeout(adapter->netdev);
+ ixgbe_tx_timeout_reset(adapter);
/* the adapter is about to reset, no point in enabling stuff */
return true;
@@ -943,8 +980,6 @@ static void ixgbe_update_rx_dca(struct ixgbe_adapter *adapter,
rxctrl |= IXGBE_DCA_RXCTRL_DESC_DCA_EN;
rxctrl |= IXGBE_DCA_RXCTRL_HEAD_DCA_EN;
rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_RRO_EN);
- rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_WRO_EN |
- IXGBE_DCA_RXCTRL_DESC_HSRO_EN);
IXGBE_WRITE_REG(hw, IXGBE_DCA_RXCTRL(reg_idx), rxctrl);
}
@@ -962,7 +997,6 @@ static void ixgbe_update_tx_dca(struct ixgbe_adapter *adapter,
txctrl &= ~IXGBE_DCA_TXCTRL_CPUID_MASK;
txctrl |= dca3_get_tag(&adapter->pdev->dev, cpu);
txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN;
- txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(reg_idx), txctrl);
break;
case ixgbe_mac_82599EB:
@@ -972,7 +1006,6 @@ static void ixgbe_update_tx_dca(struct ixgbe_adapter *adapter,
txctrl |= (dca3_get_tag(&adapter->pdev->dev, cpu) <<
IXGBE_DCA_TXCTRL_CPUID_SHIFT_82599);
txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN;
- txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(reg_idx), txctrl);
break;
default:
@@ -1061,8 +1094,14 @@ static int __ixgbe_notify_dca(struct device *dev, void *data)
return 0;
}
-
#endif /* CONFIG_IXGBE_DCA */
+
+static inline void ixgbe_rx_hash(union ixgbe_adv_rx_desc *rx_desc,
+ struct sk_buff *skb)
+{
+ skb->rxhash = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss);
+}
+
/**
* ixgbe_receive_skb - Send a completed packet up the stack
* @adapter: board private structure
@@ -1454,6 +1493,8 @@ static void ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
}
ixgbe_rx_checksum(adapter, rx_desc, skb);
+ if (adapter->netdev->features & NETIF_F_RXHASH)
+ ixgbe_rx_hash(rx_desc, skb);
/* probably a little skewed due to removing CRC */
total_rx_bytes += skb->len;
@@ -1787,35 +1828,51 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector)
}
/**
- * ixgbe_check_overtemp_task - worker thread to check over tempurature
- * @work: pointer to work_struct containing our data
+ * ixgbe_check_overtemp_subtask - check for over tempurature
+ * @adapter: pointer to adapter
**/
-static void ixgbe_check_overtemp_task(struct work_struct *work)
+static void ixgbe_check_overtemp_subtask(struct ixgbe_adapter *adapter)
{
- struct ixgbe_adapter *adapter = container_of(work,
- struct ixgbe_adapter,
- check_overtemp_task);
struct ixgbe_hw *hw = &adapter->hw;
u32 eicr = adapter->interrupt_event;
- if (!(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE))
+ if (test_bit(__IXGBE_DOWN, &adapter->state))
return;
+ if (!(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) &&
+ !(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_EVENT))
+ return;
+
+ adapter->flags2 &= ~IXGBE_FLAG2_TEMP_SENSOR_EVENT;
+
switch (hw->device_id) {
- case IXGBE_DEV_ID_82599_T3_LOM: {
- u32 autoneg;
- bool link_up = false;
+ case IXGBE_DEV_ID_82599_T3_LOM:
+ /*
+ * Since the warning interrupt is for both ports
+ * we don't have to check if:
+ * - This interrupt wasn't for our port.
+ * - We may have missed the interrupt so always have to
+ * check if we got a LSC
+ */
+ if (!(eicr & IXGBE_EICR_GPI_SDP0) &&
+ !(eicr & IXGBE_EICR_LSC))
+ return;
+
+ if (!(eicr & IXGBE_EICR_LSC) && hw->mac.ops.check_link) {
+ u32 autoneg;
+ bool link_up = false;
- if (hw->mac.ops.check_link)
hw->mac.ops.check_link(hw, &autoneg, &link_up, false);
- if (((eicr & IXGBE_EICR_GPI_SDP0) && (!link_up)) ||
- (eicr & IXGBE_EICR_LSC))
- /* Check if this is due to overtemp */
- if (hw->phy.ops.check_overtemp(hw) == IXGBE_ERR_OVERTEMP)
- break;
- return;
- }
+ if (link_up)
+ return;
+ }
+
+ /* Check if this is not due to overtemp */
+ if (hw->phy.ops.check_overtemp(hw) != IXGBE_ERR_OVERTEMP)
+ return;
+
+ break;
default:
if (!(eicr & IXGBE_EICR_GPI_SDP0))
return;
@@ -1825,8 +1882,8 @@ static void ixgbe_check_overtemp_task(struct work_struct *work)
"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);
+
+ adapter->interrupt_event = 0;
}
static void ixgbe_check_fan_failure(struct ixgbe_adapter *adapter, u32 eicr)
@@ -1848,15 +1905,19 @@ static void ixgbe_check_sfp_event(struct ixgbe_adapter *adapter, u32 eicr)
if (eicr & IXGBE_EICR_GPI_SDP2) {
/* Clear the interrupt */
IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2);
- if (!test_bit(__IXGBE_DOWN, &adapter->state))
- schedule_work(&adapter->sfp_config_module_task);
+ if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
+ adapter->flags2 |= IXGBE_FLAG2_SFP_NEEDS_RESET;
+ ixgbe_service_event_schedule(adapter);
+ }
}
if (eicr & IXGBE_EICR_GPI_SDP1) {
/* Clear the interrupt */
IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1);
- if (!test_bit(__IXGBE_DOWN, &adapter->state))
- schedule_work(&adapter->multispeed_fiber_task);
+ if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
+ adapter->flags |= IXGBE_FLAG_NEED_LINK_CONFIG;
+ ixgbe_service_event_schedule(adapter);
+ }
}
}
@@ -1870,7 +1931,7 @@ static void ixgbe_check_lsc(struct ixgbe_adapter *adapter)
if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_LSC);
IXGBE_WRITE_FLUSH(hw);
- schedule_work(&adapter->watchdog_task);
+ ixgbe_service_event_schedule(adapter);
}
}
@@ -1898,26 +1959,32 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data)
switch (hw->mac.type) {
case ixgbe_mac_82599EB:
- ixgbe_check_sfp_event(adapter, eicr);
- if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) &&
- ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) {
- adapter->interrupt_event = eicr;
- schedule_work(&adapter->check_overtemp_task);
- }
- /* now fallthrough to handle Flow Director */
case ixgbe_mac_X540:
/* Handle Flow Director Full threshold interrupt */
if (eicr & IXGBE_EICR_FLOW_DIR) {
+ int reinit_count = 0;
int i;
- IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_FLOW_DIR);
- /* Disable transmits before FDIR Re-initialization */
- netif_tx_stop_all_queues(netdev);
for (i = 0; i < adapter->num_tx_queues; i++) {
- struct ixgbe_ring *tx_ring =
- adapter->tx_ring[i];
+ struct ixgbe_ring *ring = adapter->tx_ring[i];
if (test_and_clear_bit(__IXGBE_TX_FDIR_INIT_DONE,
- &tx_ring->state))
- schedule_work(&adapter->fdir_reinit_task);
+ &ring->state))
+ reinit_count++;
+ }
+ if (reinit_count) {
+ /* no more flow director interrupts until after init */
+ IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_FLOW_DIR);
+ eicr &= ~IXGBE_EICR_FLOW_DIR;
+ adapter->flags2 |= IXGBE_FLAG2_FDIR_REQUIRES_REINIT;
+ ixgbe_service_event_schedule(adapter);
+ }
+ }
+ ixgbe_check_sfp_event(adapter, eicr);
+ if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) &&
+ ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) {
+ if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
+ adapter->interrupt_event = eicr;
+ adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_EVENT;
+ ixgbe_service_event_schedule(adapter);
}
}
break;
@@ -1927,8 +1994,10 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data)
ixgbe_check_fan_failure(adapter, eicr);
+ /* re-enable the original interrupt state, no lsc, no queues */
if (!test_bit(__IXGBE_DOWN, &adapter->state))
- IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER);
+ IXGBE_WRITE_REG(hw, IXGBE_EIMS, eicr &
+ ~(IXGBE_EIMS_LSC | IXGBE_EIMS_RTX_QUEUE));
return IRQ_HANDLED;
}
@@ -2513,8 +2582,11 @@ static irqreturn_t ixgbe_intr(int irq, void *data)
ixgbe_check_sfp_event(adapter, eicr);
if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) &&
((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) {
- adapter->interrupt_event = eicr;
- schedule_work(&adapter->check_overtemp_task);
+ if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
+ adapter->interrupt_event = eicr;
+ adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_EVENT;
+ ixgbe_service_event_schedule(adapter);
+ }
}
break;
default:
@@ -2731,7 +2803,7 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
/* poll to verify queue is enabled */
do {
- msleep(1);
+ usleep_range(1000, 2000);
txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx));
} while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE));
if (!wait_loop)
@@ -3023,7 +3095,7 @@ static void ixgbe_rx_desc_queue_enable(struct ixgbe_adapter *adapter,
return;
do {
- msleep(1);
+ usleep_range(1000, 2000);
rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx));
} while (--wait_loop && !(rxdctl & IXGBE_RXDCTL_ENABLE));
@@ -3178,7 +3250,9 @@ static void ixgbe_configure_virtualization(struct ixgbe_adapter *adapter)
/* enable Tx loopback for VF/PF communication */
IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN);
/* Enable MAC Anti-Spoofing */
- hw->mac.ops.set_mac_anti_spoofing(hw, (adapter->num_vfs != 0),
+ hw->mac.ops.set_mac_anti_spoofing(hw,
+ (adapter->antispoofing_enabled =
+ (adapter->num_vfs != 0)),
adapter->num_vfs);
}
@@ -3487,7 +3561,7 @@ 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);
+ unsigned int rar_entries = IXGBE_MAX_PF_MACVLANS;
int count = 0;
/* return ENOMEM indicating insufficient memory for addresses */
@@ -3760,31 +3834,16 @@ static inline bool ixgbe_is_sfp(struct ixgbe_hw *hw)
**/
static void ixgbe_sfp_link_config(struct ixgbe_adapter *adapter)
{
- struct ixgbe_hw *hw = &adapter->hw;
+ /*
+ * We are assuming the worst case scenerio here, and that
+ * is that an SFP was inserted/removed after the reset
+ * but before SFP detection was enabled. As such the best
+ * solution is to just start searching as soon as we start
+ */
+ if (adapter->hw.mac.type == ixgbe_mac_82598EB)
+ adapter->flags2 |= IXGBE_FLAG2_SEARCH_FOR_SFP;
- if (hw->phy.multispeed_fiber) {
- /*
- * In multispeed fiber setups, the device may not have
- * had a physical connection when the driver loaded.
- * If that's the case, the initial link configuration
- * couldn't get the MAC into 10G or 1G mode, so we'll
- * never have a link status change interrupt fire.
- * We need to try and force an autonegotiation
- * session, then bring up link.
- */
- if (hw->mac.ops.setup_sfp)
- hw->mac.ops.setup_sfp(hw);
- if (!(adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK))
- schedule_work(&adapter->multispeed_fiber_task);
- } else {
- /*
- * Direct Attach Cu and non-multispeed fiber modules
- * still need to be configured properly prior to
- * attempting link.
- */
- if (!(adapter->flags & IXGBE_FLAG_IN_SFP_MOD_TASK))
- schedule_work(&adapter->sfp_config_module_task);
- }
+ adapter->flags2 |= IXGBE_FLAG2_SFP_NEEDS_RESET;
}
/**
@@ -3860,9 +3919,10 @@ static void ixgbe_setup_gpie(struct ixgbe_adapter *adapter)
if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE)
gpie |= IXGBE_SDP1_GPIEN;
- if (hw->mac.type == ixgbe_mac_82599EB)
+ if (hw->mac.type == ixgbe_mac_82599EB) {
gpie |= IXGBE_SDP1_GPIEN;
gpie |= IXGBE_SDP2_GPIEN;
+ }
IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
}
@@ -3913,17 +3973,6 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
e_crit(drv, "Fan has stopped, replace the adapter\n");
}
- /*
- * For hot-pluggable SFP+ devices, a new SFP+ module may have
- * arrived before interrupts were enabled but after probe. Such
- * devices wouldn't have their type identified yet. We need to
- * kick off the SFP+ module setup first, then try to bring up link.
- * If we're not hot-pluggable SFP+, we just need to configure link
- * and bring it up.
- */
- if (hw->phy.type == ixgbe_phy_none)
- schedule_work(&adapter->sfp_config_module_task);
-
/* enable transmits */
netif_tx_start_all_queues(adapter->netdev);
@@ -3931,7 +3980,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
* link up interrupt but shouldn't be a problem */
adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
adapter->link_check_timeout = jiffies;
- mod_timer(&adapter->watchdog_timer, jiffies);
+ mod_timer(&adapter->service_timer, jiffies);
/* Set PF Reset Done bit so PF/VF Mail Ops can work */
ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
@@ -3944,8 +3993,11 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
void ixgbe_reinit_locked(struct ixgbe_adapter *adapter)
{
WARN_ON(in_interrupt());
+ /* put off any impending NetWatchDogTimeout */
+ adapter->netdev->trans_start = jiffies;
+
while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
- msleep(1);
+ usleep_range(1000, 2000);
ixgbe_down(adapter);
/*
* If SR-IOV enabled then wait a bit before bringing the adapter
@@ -3972,10 +4024,20 @@ void ixgbe_reset(struct ixgbe_adapter *adapter)
struct ixgbe_hw *hw = &adapter->hw;
int err;
+ /* lock SFP init bit to prevent race conditions with the watchdog */
+ while (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
+ usleep_range(1000, 2000);
+
+ /* clear all SFP and link config related flags while holding SFP_INIT */
+ adapter->flags2 &= ~(IXGBE_FLAG2_SEARCH_FOR_SFP |
+ IXGBE_FLAG2_SFP_NEEDS_RESET);
+ adapter->flags &= ~IXGBE_FLAG_NEED_LINK_CONFIG;
+
err = hw->mac.ops.init_hw(hw);
switch (err) {
case 0:
case IXGBE_ERR_SFP_NOT_PRESENT:
+ case IXGBE_ERR_SFP_NOT_SUPPORTED:
break;
case IXGBE_ERR_MASTER_REQUESTS_PENDING:
e_dev_err("master disable timed out\n");
@@ -3993,6 +4055,8 @@ void ixgbe_reset(struct ixgbe_adapter *adapter)
e_dev_err("Hardware Error: %d\n", err);
}
+ clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state);
+
/* reprogram the RAR[0] in case user changed it. */
hw->mac.ops.set_rar(hw, 0, hw->mac.addr, adapter->num_vfs,
IXGBE_RAH_AV);
@@ -4121,26 +4185,12 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
struct net_device *netdev = adapter->netdev;
struct ixgbe_hw *hw = &adapter->hw;
u32 rxctrl;
- u32 txdctl;
int i;
int num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
/* signal that we are down to the interrupt handler */
set_bit(__IXGBE_DOWN, &adapter->state);
- /* disable receive for all VFs and wait one second */
- if (adapter->num_vfs) {
- /* ping all the active vfs to let them know we are going down */
- ixgbe_ping_all_vfs(adapter);
-
- /* Disable all VFTE/VFRE TX/RX */
- ixgbe_disable_tx_rx(adapter);
-
- /* Mark all the VFs as inactive */
- for (i = 0 ; i < adapter->num_vfs; i++)
- adapter->vfinfo[i].clear_to_send = 0;
- }
-
/* disable receives */
rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN);
@@ -4150,15 +4200,11 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
/* this call also flushes the previous write */
ixgbe_disable_rx_queue(adapter, adapter->rx_ring[i]);
- msleep(10);
+ usleep_range(10000, 20000);
netif_tx_stop_all_queues(netdev);
- clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
- del_timer_sync(&adapter->sfp_timer);
- del_timer_sync(&adapter->watchdog_timer);
- cancel_work_sync(&adapter->watchdog_task);
-
+ /* call carrier off first to avoid false dev_watchdog timeouts */
netif_carrier_off(netdev);
netif_tx_disable(netdev);
@@ -4166,6 +4212,25 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
ixgbe_napi_disable_all(adapter);
+ adapter->flags2 &= ~(IXGBE_FLAG2_FDIR_REQUIRES_REINIT |
+ IXGBE_FLAG2_RESET_REQUESTED);
+ adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE;
+
+ del_timer_sync(&adapter->service_timer);
+
+ /* disable receive for all VFs and wait one second */
+ if (adapter->num_vfs) {
+ /* ping all the active vfs to let them know we are going down */
+ ixgbe_ping_all_vfs(adapter);
+
+ /* Disable all VFTE/VFRE TX/RX */
+ ixgbe_disable_tx_rx(adapter);
+
+ /* Mark all the VFs as inactive */
+ for (i = 0 ; i < adapter->num_vfs; i++)
+ adapter->vfinfo[i].clear_to_send = 0;
+ }
+
/* Cleanup the affinity_hint CPU mask memory and callback */
for (i = 0; i < num_q_vectors; i++) {
struct ixgbe_q_vector *q_vector = adapter->q_vector[i];
@@ -4175,21 +4240,13 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
free_cpumask_var(q_vector->affinity_mask);
}
- if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE ||
- adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
- cancel_work_sync(&adapter->fdir_reinit_task);
-
- if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE)
- cancel_work_sync(&adapter->check_overtemp_task);
-
/* disable transmits in the hardware now that interrupts are off */
for (i = 0; i < adapter->num_tx_queues; i++) {
u8 reg_idx = adapter->tx_ring[i]->reg_idx;
- txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx));
- IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx),
- (txdctl & ~IXGBE_TXDCTL_ENABLE));
+ IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), IXGBE_TXDCTL_SWFLSH);
}
- /* Disable the Tx DMA engine on 82599 */
+
+ /* Disable the Tx DMA engine on 82599 and X540 */
switch (hw->mac.type) {
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
@@ -4201,9 +4258,6 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
break;
}
- /* clear n-tuple filters that are cached */
- ethtool_ntuple_flush(netdev);
-
if (!pci_channel_offline(adapter->pdev))
ixgbe_reset(adapter);
@@ -4267,25 +4321,8 @@ static void ixgbe_tx_timeout(struct net_device *netdev)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
- adapter->tx_timeout_count++;
-
/* Do the reset outside of interrupt context */
- schedule_work(&adapter->reset_task);
-}
-
-static void ixgbe_reset_task(struct work_struct *work)
-{
- struct ixgbe_adapter *adapter;
- adapter = container_of(work, struct ixgbe_adapter, reset_task);
-
- /* If we're already down or resetting, just bail */
- if (test_bit(__IXGBE_DOWN, &adapter->state) ||
- test_bit(__IXGBE_RESETTING, &adapter->state))
- return;
-
- ixgbe_dump(adapter);
- netdev_err(adapter->netdev, "Reset adapter\n");
- ixgbe_reinit_locked(adapter);
+ ixgbe_tx_timeout_reset(adapter);
}
/**
@@ -4567,8 +4604,8 @@ static inline bool ixgbe_cache_ring_rss(struct ixgbe_adapter *adapter)
#ifdef CONFIG_IXGBE_DCB
/* ixgbe_get_first_reg_idx - Return first register index associated with ring */
-void ixgbe_get_first_reg_idx(struct ixgbe_adapter *adapter, u8 tc,
- unsigned int *tx, unsigned int *rx)
+static void ixgbe_get_first_reg_idx(struct ixgbe_adapter *adapter, u8 tc,
+ unsigned int *tx, unsigned int *rx)
{
struct net_device *dev = adapter->netdev;
struct ixgbe_hw *hw = &adapter->hw;
@@ -5100,11 +5137,6 @@ err_set_interrupt:
return err;
}
-static void ring_free_rcu(struct rcu_head *head)
-{
- kfree(container_of(head, struct ixgbe_ring, rcu));
-}
-
/**
* ixgbe_clear_interrupt_scheme - Clear the current interrupt scheme settings
* @adapter: board private structure to clear interrupt scheme on
@@ -5126,7 +5158,7 @@ void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter)
/* ixgbe_get_stats64() might access this ring, we must wait
* a grace period before freeing it.
*/
- call_rcu(&ring->rcu, ring_free_rcu);
+ kfree_rcu(ring, rcu);
adapter->rx_ring[i] = NULL;
}
@@ -5138,57 +5170,6 @@ void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter)
}
/**
- * ixgbe_sfp_timer - worker thread to find a missing module
- * @data: pointer to our adapter struct
- **/
-static void ixgbe_sfp_timer(unsigned long data)
-{
- struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data;
-
- /*
- * Do the sfp_timer outside of interrupt context due to the
- * delays that sfp+ detection requires
- */
- schedule_work(&adapter->sfp_task);
-}
-
-/**
- * ixgbe_sfp_task - worker thread to find a missing module
- * @work: pointer to work_struct containing our data
- **/
-static void ixgbe_sfp_task(struct work_struct *work)
-{
- struct ixgbe_adapter *adapter = container_of(work,
- struct ixgbe_adapter,
- sfp_task);
- struct ixgbe_hw *hw = &adapter->hw;
-
- if ((hw->phy.type == ixgbe_phy_nl) &&
- (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) {
- s32 ret = hw->phy.ops.identify_sfp(hw);
- if (ret == IXGBE_ERR_SFP_NOT_PRESENT)
- goto reschedule;
- ret = hw->phy.ops.reset(hw);
- if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) {
- 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 {
- 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);
- }
- return;
-reschedule:
- if (test_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state))
- mod_timer(&adapter->sfp_timer,
- round_jiffies(jiffies + (2 * HZ)));
-}
-
-/**
* ixgbe_sw_init - Initialize general software structures (struct ixgbe_adapter)
* @adapter: board private structure to initialize
*
@@ -5904,8 +5885,13 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
hwstats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
hwstats->tor += IXGBE_READ_REG(hw, IXGBE_TORH);
break;
- case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
+ /* OS2BMC stats are X540 only*/
+ hwstats->o2bgptc += IXGBE_READ_REG(hw, IXGBE_O2BGPTC);
+ hwstats->o2bspc += IXGBE_READ_REG(hw, IXGBE_O2BSPC);
+ hwstats->b2ospc += IXGBE_READ_REG(hw, IXGBE_B2OSPC);
+ hwstats->b2ogprc += IXGBE_READ_REG(hw, IXGBE_B2OGPRC);
+ case ixgbe_mac_82599EB:
hwstats->gorc += IXGBE_READ_REG(hw, IXGBE_GORCL);
IXGBE_READ_REG(hw, IXGBE_GORCH); /* to clear */
hwstats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL);
@@ -5979,23 +5965,66 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
}
/**
- * ixgbe_watchdog - Timer Call-back
- * @data: pointer to adapter cast into an unsigned long
+ * ixgbe_fdir_reinit_subtask - worker thread to reinit FDIR filter table
+ * @adapter - pointer to the device adapter structure
**/
-static void ixgbe_watchdog(unsigned long data)
+static void ixgbe_fdir_reinit_subtask(struct ixgbe_adapter *adapter)
{
- struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data;
struct ixgbe_hw *hw = &adapter->hw;
- u64 eics = 0;
int i;
- /*
- * Do the watchdog outside of interrupt context due to the lovely
- * delays that some of the newer hardware requires
- */
+ if (!(adapter->flags2 & IXGBE_FLAG2_FDIR_REQUIRES_REINIT))
+ return;
+
+ adapter->flags2 &= ~IXGBE_FLAG2_FDIR_REQUIRES_REINIT;
+ /* if interface is down do nothing */
if (test_bit(__IXGBE_DOWN, &adapter->state))
- goto watchdog_short_circuit;
+ return;
+
+ /* do nothing if we are not using signature filters */
+ if (!(adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE))
+ return;
+
+ adapter->fdir_overflow++;
+
+ if (ixgbe_reinit_fdir_tables_82599(hw) == 0) {
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ set_bit(__IXGBE_TX_FDIR_INIT_DONE,
+ &(adapter->tx_ring[i]->state));
+ /* re-enable flow director interrupts */
+ IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_FLOW_DIR);
+ } else {
+ e_err(probe, "failed to finish FDIR re-initialization, "
+ "ignored adding FDIR ATR filters\n");
+ }
+}
+
+/**
+ * ixgbe_check_hang_subtask - check for hung queues and dropped interrupts
+ * @adapter - pointer to the device adapter structure
+ *
+ * This function serves two purposes. First it strobes the interrupt lines
+ * in order to make certain interrupts are occuring. Secondly it sets the
+ * bits needed to check for TX hangs. As a result we should immediately
+ * determine if a hang has occured.
+ */
+static void ixgbe_check_hang_subtask(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u64 eics = 0;
+ int i;
+
+ /* If we're down or resetting, just bail */
+ if (test_bit(__IXGBE_DOWN, &adapter->state) ||
+ test_bit(__IXGBE_RESETTING, &adapter->state))
+ return;
+
+ /* Force detection of hung controller */
+ if (netif_carrier_ok(adapter->netdev)) {
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ set_check_for_tx_hang(adapter->tx_ring[i]);
+ }
if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) {
/*
@@ -6005,108 +6034,172 @@ static void ixgbe_watchdog(unsigned long data)
*/
IXGBE_WRITE_REG(hw, IXGBE_EICS,
(IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER));
- goto watchdog_reschedule;
- }
-
- /* get one bit for every active tx/rx interrupt vector */
- for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) {
- struct ixgbe_q_vector *qv = adapter->q_vector[i];
- if (qv->rxr_count || qv->txr_count)
- eics |= ((u64)1 << i);
+ } else {
+ /* get one bit for every active tx/rx interrupt vector */
+ for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) {
+ struct ixgbe_q_vector *qv = adapter->q_vector[i];
+ if (qv->rxr_count || qv->txr_count)
+ eics |= ((u64)1 << i);
+ }
}
- /* Cause software interrupt to ensure rx rings are cleaned */
+ /* Cause software interrupt to ensure rings are cleaned */
ixgbe_irq_rearm_queues(adapter, eics);
-watchdog_reschedule:
- /* Reset the timer */
- mod_timer(&adapter->watchdog_timer, round_jiffies(jiffies + 2 * HZ));
-
-watchdog_short_circuit:
- schedule_work(&adapter->watchdog_task);
}
/**
- * ixgbe_multispeed_fiber_task - worker thread to configure multispeed fiber
- * @work: pointer to work_struct containing our data
+ * ixgbe_watchdog_update_link - update the link status
+ * @adapter - pointer to the device adapter structure
+ * @link_speed - pointer to a u32 to store the link_speed
**/
-static void ixgbe_multispeed_fiber_task(struct work_struct *work)
+static void ixgbe_watchdog_update_link(struct ixgbe_adapter *adapter)
{
- struct ixgbe_adapter *adapter = container_of(work,
- struct ixgbe_adapter,
- multispeed_fiber_task);
struct ixgbe_hw *hw = &adapter->hw;
- u32 autoneg;
- bool negotiation;
+ u32 link_speed = adapter->link_speed;
+ bool link_up = adapter->link_up;
+ int i;
- adapter->flags |= IXGBE_FLAG_IN_SFP_LINK_TASK;
- autoneg = hw->phy.autoneg_advertised;
- if ((!autoneg) && (hw->mac.ops.get_link_capabilities))
- hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiation);
- hw->mac.autotry_restart = false;
- if (hw->mac.ops.setup_link)
- hw->mac.ops.setup_link(hw, autoneg, negotiation, true);
- adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
- adapter->flags &= ~IXGBE_FLAG_IN_SFP_LINK_TASK;
+ if (!(adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE))
+ return;
+
+ if (hw->mac.ops.check_link) {
+ hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
+ } else {
+ /* always assume link is up, if no check link function */
+ link_speed = IXGBE_LINK_SPEED_10GB_FULL;
+ link_up = true;
+ }
+ if (link_up) {
+ if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
+ for (i = 0; i < MAX_TRAFFIC_CLASS; i++)
+ hw->mac.ops.fc_enable(hw, i);
+ } else {
+ hw->mac.ops.fc_enable(hw, 0);
+ }
+ }
+
+ if (link_up ||
+ time_after(jiffies, (adapter->link_check_timeout +
+ IXGBE_TRY_LINK_TIMEOUT))) {
+ adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE;
+ IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMC_LSC);
+ IXGBE_WRITE_FLUSH(hw);
+ }
+
+ adapter->link_up = link_up;
+ adapter->link_speed = link_speed;
}
/**
- * ixgbe_sfp_config_module_task - worker thread to configure a new SFP+ module
- * @work: pointer to work_struct containing our data
+ * ixgbe_watchdog_link_is_up - update netif_carrier status and
+ * print link up message
+ * @adapter - pointer to the device adapter structure
**/
-static void ixgbe_sfp_config_module_task(struct work_struct *work)
+static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter)
{
- struct ixgbe_adapter *adapter = container_of(work,
- struct ixgbe_adapter,
- sfp_config_module_task);
+ struct net_device *netdev = adapter->netdev;
struct ixgbe_hw *hw = &adapter->hw;
- u32 err;
+ u32 link_speed = adapter->link_speed;
+ bool flow_rx, flow_tx;
- adapter->flags |= IXGBE_FLAG_IN_SFP_MOD_TASK;
+ /* only continue if link was previously down */
+ if (netif_carrier_ok(netdev))
+ return;
- /* Time for electrical oscillations to settle down */
- msleep(100);
- err = hw->phy.ops.identify_sfp(hw);
+ adapter->flags2 &= ~IXGBE_FLAG2_SEARCH_FOR_SFP;
- if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
- 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;
+ switch (hw->mac.type) {
+ case ixgbe_mac_82598EB: {
+ u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
+ u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS);
+ flow_rx = !!(frctl & IXGBE_FCTRL_RFCE);
+ flow_tx = !!(rmcs & IXGBE_RMCS_TFCE_802_3X);
+ }
+ break;
+ case ixgbe_mac_X540:
+ case ixgbe_mac_82599EB: {
+ u32 mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN);
+ u32 fccfg = IXGBE_READ_REG(hw, IXGBE_FCCFG);
+ flow_rx = !!(mflcn & IXGBE_MFLCN_RFCE);
+ flow_tx = !!(fccfg & IXGBE_FCCFG_TFCE_802_3X);
}
- if (hw->mac.ops.setup_sfp)
- hw->mac.ops.setup_sfp(hw);
+ break;
+ default:
+ flow_tx = false;
+ flow_rx = false;
+ break;
+ }
+ 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" :
+ (link_speed == IXGBE_LINK_SPEED_100_FULL ?
+ "100 Mbps" :
+ "unknown speed"))),
+ ((flow_rx && flow_tx) ? "RX/TX" :
+ (flow_rx ? "RX" :
+ (flow_tx ? "TX" : "None"))));
- if (!(adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK))
- /* This will also work for DA Twinax connections */
- schedule_work(&adapter->multispeed_fiber_task);
- adapter->flags &= ~IXGBE_FLAG_IN_SFP_MOD_TASK;
+ netif_carrier_on(netdev);
+#ifdef HAVE_IPLINK_VF_CONFIG
+ ixgbe_check_vf_rate_limit(adapter);
+#endif /* HAVE_IPLINK_VF_CONFIG */
}
/**
- * ixgbe_fdir_reinit_task - worker thread to reinit FDIR filter table
- * @work: pointer to work_struct containing our data
+ * ixgbe_watchdog_link_is_down - update netif_carrier status and
+ * print link down message
+ * @adapter - pointer to the adapter structure
**/
-static void ixgbe_fdir_reinit_task(struct work_struct *work)
+static void ixgbe_watchdog_link_is_down(struct ixgbe_adapter* adapter)
{
- struct ixgbe_adapter *adapter = container_of(work,
- struct ixgbe_adapter,
- fdir_reinit_task);
+ struct net_device *netdev = adapter->netdev;
struct ixgbe_hw *hw = &adapter->hw;
+
+ adapter->link_up = false;
+ adapter->link_speed = 0;
+
+ /* only continue if link was up previously */
+ if (!netif_carrier_ok(netdev))
+ return;
+
+ /* poll for SFP+ cable when link is down */
+ if (ixgbe_is_sfp(hw) && hw->mac.type == ixgbe_mac_82598EB)
+ adapter->flags2 |= IXGBE_FLAG2_SEARCH_FOR_SFP;
+
+ e_info(drv, "NIC Link is Down\n");
+ netif_carrier_off(netdev);
+}
+
+/**
+ * ixgbe_watchdog_flush_tx - flush queues on link down
+ * @adapter - pointer to the device adapter structure
+ **/
+static void ixgbe_watchdog_flush_tx(struct ixgbe_adapter *adapter)
+{
int i;
+ int some_tx_pending = 0;
- if (ixgbe_reinit_fdir_tables_82599(hw) == 0) {
- for (i = 0; i < adapter->num_tx_queues; i++)
- set_bit(__IXGBE_TX_FDIR_INIT_DONE,
- &(adapter->tx_ring[i]->state));
- } else {
- e_err(probe, "failed to finish FDIR re-initialization, "
- "ignored adding FDIR ATR filters\n");
+ if (!netif_carrier_ok(adapter->netdev)) {
+ for (i = 0; i < adapter->num_tx_queues; i++) {
+ struct ixgbe_ring *tx_ring = adapter->tx_ring[i];
+ if (tx_ring->next_to_use != tx_ring->next_to_clean) {
+ some_tx_pending = 1;
+ break;
+ }
+ }
+
+ if (some_tx_pending) {
+ /* We've lost link, so the controller stops DMA,
+ * but we've got queued Tx work that's never going
+ * to get done, so reset controller to flush Tx.
+ * (Do the reset outside of interrupt context).
+ */
+ adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED;
+ }
}
- /* Done FDIR Re-initialization, enable transmits */
- netif_tx_start_all_queues(adapter->netdev);
}
static void ixgbe_spoof_check(struct ixgbe_adapter *adapter)
@@ -6129,133 +6222,186 @@ static void ixgbe_spoof_check(struct ixgbe_adapter *adapter)
e_warn(drv, "%d Spoofed packets detected\n", ssvpc);
}
-static DEFINE_MUTEX(ixgbe_watchdog_lock);
+/**
+ * ixgbe_watchdog_subtask - check and bring link up
+ * @adapter - pointer to the device adapter structure
+ **/
+static void ixgbe_watchdog_subtask(struct ixgbe_adapter *adapter)
+{
+ /* if interface is down do nothing */
+ if (test_bit(__IXGBE_DOWN, &adapter->state))
+ return;
+
+ ixgbe_watchdog_update_link(adapter);
+
+ if (adapter->link_up)
+ ixgbe_watchdog_link_is_up(adapter);
+ else
+ ixgbe_watchdog_link_is_down(adapter);
+
+ ixgbe_spoof_check(adapter);
+ ixgbe_update_stats(adapter);
+
+ ixgbe_watchdog_flush_tx(adapter);
+}
/**
- * ixgbe_watchdog_task - worker thread to bring link up
- * @work: pointer to work_struct containing our data
+ * ixgbe_sfp_detection_subtask - poll for SFP+ cable
+ * @adapter - the ixgbe adapter structure
**/
-static void ixgbe_watchdog_task(struct work_struct *work)
+static void ixgbe_sfp_detection_subtask(struct ixgbe_adapter *adapter)
{
- struct ixgbe_adapter *adapter = container_of(work,
- struct ixgbe_adapter,
- watchdog_task);
- struct net_device *netdev = adapter->netdev;
struct ixgbe_hw *hw = &adapter->hw;
- u32 link_speed;
- bool link_up;
- int i;
- struct ixgbe_ring *tx_ring;
- int some_tx_pending = 0;
+ s32 err;
- mutex_lock(&ixgbe_watchdog_lock);
+ /* not searching for SFP so there is nothing to do here */
+ if (!(adapter->flags2 & IXGBE_FLAG2_SEARCH_FOR_SFP) &&
+ !(adapter->flags2 & IXGBE_FLAG2_SFP_NEEDS_RESET))
+ return;
- link_up = adapter->link_up;
- link_speed = adapter->link_speed;
+ /* someone else is in init, wait until next service event */
+ if (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
+ return;
- if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE) {
- hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
- if (link_up) {
-#ifdef CONFIG_DCB
- if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
- for (i = 0; i < MAX_TRAFFIC_CLASS; i++)
- hw->mac.ops.fc_enable(hw, i);
- } else {
- hw->mac.ops.fc_enable(hw, 0);
- }
-#else
- hw->mac.ops.fc_enable(hw, 0);
-#endif
- }
+ err = hw->phy.ops.identify_sfp(hw);
+ if (err == IXGBE_ERR_SFP_NOT_SUPPORTED)
+ goto sfp_out;
- if (link_up ||
- time_after(jiffies, (adapter->link_check_timeout +
- IXGBE_TRY_LINK_TIMEOUT))) {
- adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE;
- IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMC_LSC);
- }
- adapter->link_up = link_up;
- adapter->link_speed = link_speed;
+ if (err == IXGBE_ERR_SFP_NOT_PRESENT) {
+ /* If no cable is present, then we need to reset
+ * the next time we find a good cable. */
+ adapter->flags2 |= IXGBE_FLAG2_SFP_NEEDS_RESET;
}
- if (link_up) {
- if (!netif_carrier_ok(netdev)) {
- bool flow_rx, flow_tx;
-
- switch (hw->mac.type) {
- case ixgbe_mac_82598EB: {
- u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
- u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS);
- flow_rx = !!(frctl & IXGBE_FCTRL_RFCE);
- flow_tx = !!(rmcs & IXGBE_RMCS_TFCE_802_3X);
- }
- break;
- case ixgbe_mac_82599EB:
- case ixgbe_mac_X540: {
- u32 mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN);
- u32 fccfg = IXGBE_READ_REG(hw, IXGBE_FCCFG);
- flow_rx = !!(mflcn & IXGBE_MFLCN_RFCE);
- flow_tx = !!(fccfg & IXGBE_FCCFG_TFCE_802_3X);
- }
- break;
- default:
- flow_tx = false;
- flow_rx = false;
- break;
- }
+ /* exit on error */
+ if (err)
+ goto sfp_out;
- 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" :
- (link_speed == IXGBE_LINK_SPEED_100_FULL ?
- "100 Mbps" :
- "unknown speed"))),
- ((flow_rx && flow_tx) ? "RX/TX" :
- (flow_rx ? "RX" :
- (flow_tx ? "TX" : "None"))));
-
- netif_carrier_on(netdev);
- ixgbe_check_vf_rate_limit(adapter);
- } else {
- /* Force detection of hung controller */
- for (i = 0; i < adapter->num_tx_queues; i++) {
- tx_ring = adapter->tx_ring[i];
- set_check_for_tx_hang(tx_ring);
- }
- }
- } else {
- adapter->link_up = false;
- adapter->link_speed = 0;
- if (netif_carrier_ok(netdev)) {
- e_info(drv, "NIC Link is Down\n");
- netif_carrier_off(netdev);
- }
- }
+ /* exit if reset not needed */
+ if (!(adapter->flags2 & IXGBE_FLAG2_SFP_NEEDS_RESET))
+ goto sfp_out;
- if (!netif_carrier_ok(netdev)) {
- for (i = 0; i < adapter->num_tx_queues; i++) {
- tx_ring = adapter->tx_ring[i];
- if (tx_ring->next_to_use != tx_ring->next_to_clean) {
- some_tx_pending = 1;
- break;
- }
- }
+ adapter->flags2 &= ~IXGBE_FLAG2_SFP_NEEDS_RESET;
- if (some_tx_pending) {
- /* We've lost link, so the controller stops DMA,
- * but we've got queued Tx work that's never going
- * to get done, so reset controller to flush Tx.
- * (Do the reset outside of interrupt context).
- */
- schedule_work(&adapter->reset_task);
- }
+ /*
+ * A module may be identified correctly, but the EEPROM may not have
+ * support for that module. setup_sfp() will fail in that case, so
+ * we should not allow that module to load.
+ */
+ if (hw->mac.type == ixgbe_mac_82598EB)
+ err = hw->phy.ops.reset(hw);
+ else
+ err = hw->mac.ops.setup_sfp(hw);
+
+ if (err == IXGBE_ERR_SFP_NOT_SUPPORTED)
+ goto sfp_out;
+
+ adapter->flags |= IXGBE_FLAG_NEED_LINK_CONFIG;
+ e_info(probe, "detected SFP+: %d\n", hw->phy.sfp_type);
+
+sfp_out:
+ clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state);
+
+ if ((err == IXGBE_ERR_SFP_NOT_SUPPORTED) &&
+ (adapter->netdev->reg_state == NETREG_REGISTERED)) {
+ 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);
}
+}
- ixgbe_spoof_check(adapter);
- ixgbe_update_stats(adapter);
- mutex_unlock(&ixgbe_watchdog_lock);
+/**
+ * ixgbe_sfp_link_config_subtask - set up link SFP after module install
+ * @adapter - the ixgbe adapter structure
+ **/
+static void ixgbe_sfp_link_config_subtask(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 autoneg;
+ bool negotiation;
+
+ if (!(adapter->flags & IXGBE_FLAG_NEED_LINK_CONFIG))
+ return;
+
+ /* someone else is in init, wait until next service event */
+ if (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
+ return;
+
+ adapter->flags &= ~IXGBE_FLAG_NEED_LINK_CONFIG;
+
+ autoneg = hw->phy.autoneg_advertised;
+ if ((!autoneg) && (hw->mac.ops.get_link_capabilities))
+ hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiation);
+ hw->mac.autotry_restart = false;
+ if (hw->mac.ops.setup_link)
+ hw->mac.ops.setup_link(hw, autoneg, negotiation, true);
+
+ adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
+ adapter->link_check_timeout = jiffies;
+ clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state);
+}
+
+/**
+ * ixgbe_service_timer - Timer Call-back
+ * @data: pointer to adapter cast into an unsigned long
+ **/
+static void ixgbe_service_timer(unsigned long data)
+{
+ struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data;
+ unsigned long next_event_offset;
+
+ /* poll faster when waiting for link */
+ if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE)
+ next_event_offset = HZ / 10;
+ else
+ next_event_offset = HZ * 2;
+
+ /* Reset the timer */
+ mod_timer(&adapter->service_timer, next_event_offset + jiffies);
+
+ ixgbe_service_event_schedule(adapter);
+}
+
+static void ixgbe_reset_subtask(struct ixgbe_adapter *adapter)
+{
+ if (!(adapter->flags2 & IXGBE_FLAG2_RESET_REQUESTED))
+ return;
+
+ adapter->flags2 &= ~IXGBE_FLAG2_RESET_REQUESTED;
+
+ /* If we're already down or resetting, just bail */
+ if (test_bit(__IXGBE_DOWN, &adapter->state) ||
+ test_bit(__IXGBE_RESETTING, &adapter->state))
+ return;
+
+ ixgbe_dump(adapter);
+ netdev_err(adapter->netdev, "Reset adapter\n");
+ adapter->tx_timeout_count++;
+
+ ixgbe_reinit_locked(adapter);
+}
+
+/**
+ * ixgbe_service_task - manages and runs subtasks
+ * @work: pointer to work_struct containing our data
+ **/
+static void ixgbe_service_task(struct work_struct *work)
+{
+ struct ixgbe_adapter *adapter = container_of(work,
+ struct ixgbe_adapter,
+ service_task);
+
+ ixgbe_reset_subtask(adapter);
+ ixgbe_sfp_detection_subtask(adapter);
+ ixgbe_sfp_link_config_subtask(adapter);
+ ixgbe_check_overtemp_subtask(adapter);
+ ixgbe_watchdog_subtask(adapter);
+ ixgbe_fdir_reinit_subtask(adapter);
+ ixgbe_check_hang_subtask(adapter);
+
+ ixgbe_service_event_complete(adapter);
}
static int ixgbe_tso(struct ixgbe_adapter *adapter,
@@ -7094,6 +7240,8 @@ static void __devinit ixgbe_probe_vf(struct ixgbe_adapter *adapter,
#ifdef CONFIG_PCI_IOV
struct ixgbe_hw *hw = &adapter->hw;
int err;
+ int num_vf_macvlans, i;
+ struct vf_macvlans *mv_list;
if (hw->mac.type == ixgbe_mac_82598EB || !max_vfs)
return;
@@ -7110,6 +7258,26 @@ static void __devinit ixgbe_probe_vf(struct ixgbe_adapter *adapter,
e_err(probe, "Failed to enable PCI sriov: %d\n", err);
goto err_novfs;
}
+
+ num_vf_macvlans = hw->mac.num_rar_entries -
+ (IXGBE_MAX_PF_MACVLANS + 1 + adapter->num_vfs);
+
+ adapter->mv_list = mv_list = kcalloc(num_vf_macvlans,
+ sizeof(struct vf_macvlans),
+ GFP_KERNEL);
+ if (mv_list) {
+ /* Initialize list of VF macvlans */
+ INIT_LIST_HEAD(&adapter->vf_mvs.l);
+ for (i = 0; i < num_vf_macvlans; i++) {
+ mv_list->vf = -1;
+ mv_list->free = true;
+ mv_list->rar_entry = hw->mac.num_rar_entries -
+ (i + adapter->num_vfs + 1);
+ list_add(&mv_list->l, &adapter->vf_mvs.l);
+ mv_list++;
+ }
+ }
+
/* If call to enable VFs succeeded then allocate memory
* for per VF control structures.
*/
@@ -7280,22 +7448,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
hw->phy.mdio.mdio_read = ixgbe_mdio_read;
hw->phy.mdio.mdio_write = ixgbe_mdio_write;
- /* set up this timer and work struct before calling get_invariants
- * which might start the timer
- */
- init_timer(&adapter->sfp_timer);
- adapter->sfp_timer.function = ixgbe_sfp_timer;
- adapter->sfp_timer.data = (unsigned long) adapter;
-
- INIT_WORK(&adapter->sfp_task, ixgbe_sfp_task);
-
- /* multispeed fiber has its own tasklet, called from GPI SDP1 context */
- INIT_WORK(&adapter->multispeed_fiber_task, ixgbe_multispeed_fiber_task);
-
- /* a new SFP+ module arrival, called from GPI SDP2 context */
- INIT_WORK(&adapter->sfp_config_module_task,
- ixgbe_sfp_config_module_task);
-
ii->get_invariants(hw);
/* setup the private structure */
@@ -7329,17 +7481,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
hw->phy.reset_if_overtemp = false;
if (err == IXGBE_ERR_SFP_NOT_PRESENT &&
hw->mac.type == ixgbe_mac_82598EB) {
- /*
- * Start a kernel thread to watch for a module to arrive.
- * Only do this for 82598, since 82599 will generate
- * interrupts on module arrival.
- */
- set_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
- mod_timer(&adapter->sfp_timer,
- round_jiffies(jiffies + (2 * HZ)));
err = 0;
} else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
- e_dev_err("failed to initialize because an unsupported SFP+ "
+ e_dev_err("failed to load because an unsupported SFP+ "
"module type was detected.\n");
e_dev_err("Reload the driver after installing a supported "
"module.\n");
@@ -7361,9 +7505,16 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
netdev->features |= NETIF_F_TSO;
netdev->features |= NETIF_F_TSO6;
netdev->features |= NETIF_F_GRO;
+ netdev->features |= NETIF_F_RXHASH;
- if (adapter->hw.mac.type == ixgbe_mac_82599EB)
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_82599EB:
+ case ixgbe_mac_X540:
netdev->features |= NETIF_F_SCTP_CSUM;
+ break;
+ default:
+ break;
+ }
netdev->vlan_features |= NETIF_F_TSO;
netdev->vlan_features |= NETIF_F_TSO6;
@@ -7424,17 +7575,19 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
(hw->mac.type == ixgbe_mac_82599EB))))
hw->mac.ops.disable_tx_laser(hw);
- init_timer(&adapter->watchdog_timer);
- adapter->watchdog_timer.function = ixgbe_watchdog;
- adapter->watchdog_timer.data = (unsigned long)adapter;
+ setup_timer(&adapter->service_timer, &ixgbe_service_timer,
+ (unsigned long) adapter);
- INIT_WORK(&adapter->reset_task, ixgbe_reset_task);
- INIT_WORK(&adapter->watchdog_task, ixgbe_watchdog_task);
+ INIT_WORK(&adapter->service_task, ixgbe_service_task);
+ clear_bit(__IXGBE_SERVICE_SCHED, &adapter->state);
err = ixgbe_init_interrupt_scheme(adapter);
if (err)
goto err_sw_init;
+ if (!(adapter->flags & IXGBE_FLAG_RSS_ENABLED))
+ netdev->features &= ~NETIF_F_RXHASH;
+
switch (pdev->device) {
case IXGBE_DEV_ID_82599_SFP:
/* Only this subdevice supports WOL */
@@ -7463,8 +7616,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
/* print bus type/speed/width info */
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" :
+ (hw->bus.speed == ixgbe_bus_speed_5000 ? "5.0GT/s" :
+ hw->bus.speed == ixgbe_bus_speed_2500 ? "2.5GT/s" :
"Unknown"),
(hw->bus.width == ixgbe_bus_width_pcie_x8 ? "Width x8" :
hw->bus.width == ixgbe_bus_width_pcie_x4 ? "Width x4" :
@@ -7513,13 +7666,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
/* carrier off reporting is important to ethtool even BEFORE open */
netif_carrier_off(netdev);
- if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE ||
- adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
- INIT_WORK(&adapter->fdir_reinit_task, ixgbe_fdir_reinit_task);
-
- if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE)
- INIT_WORK(&adapter->check_overtemp_task,
- ixgbe_check_overtemp_task);
#ifdef CONFIG_IXGBE_DCA
if (dca_add_requester(&pdev->dev) == 0) {
adapter->flags |= IXGBE_FLAG_DCA_ENABLED;
@@ -7546,11 +7692,7 @@ err_sw_init:
err_eeprom:
if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED)
ixgbe_disable_sriov(adapter);
- clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
- del_timer_sync(&adapter->sfp_timer);
- cancel_work_sync(&adapter->sfp_task);
- cancel_work_sync(&adapter->multispeed_fiber_task);
- cancel_work_sync(&adapter->sfp_config_module_task);
+ adapter->flags2 &= ~IXGBE_FLAG2_SEARCH_FOR_SFP;
iounmap(hw->hw_addr);
err_ioremap:
free_netdev(netdev);
@@ -7578,24 +7720,7 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
struct net_device *netdev = adapter->netdev;
set_bit(__IXGBE_DOWN, &adapter->state);
-
- /*
- * The timers may be rescheduled, so explicitly disable them
- * from being rescheduled.
- */
- clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
- del_timer_sync(&adapter->watchdog_timer);
- del_timer_sync(&adapter->sfp_timer);
-
- cancel_work_sync(&adapter->watchdog_task);
- cancel_work_sync(&adapter->sfp_task);
- cancel_work_sync(&adapter->multispeed_fiber_task);
- cancel_work_sync(&adapter->sfp_config_module_task);
- if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE ||
- adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)
- cancel_work_sync(&adapter->fdir_reinit_task);
- if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE)
- cancel_work_sync(&adapter->check_overtemp_task);
+ cancel_work_sync(&adapter->service_task);
#ifdef CONFIG_IXGBE_DCA
if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) {
diff --git a/drivers/net/ixgbe/ixgbe_mbx.h b/drivers/net/ixgbe/ixgbe_mbx.h
index fe6ea81dc7f8..b239bdac38da 100644
--- a/drivers/net/ixgbe/ixgbe_mbx.h
+++ b/drivers/net/ixgbe/ixgbe_mbx.h
@@ -36,9 +36,6 @@
#define IXGBE_VFMAILBOX 0x002FC
#define IXGBE_VFMBMEM 0x00200
-#define IXGBE_PFMAILBOX(x) (0x04B00 + (4 * x))
-#define IXGBE_PFMBMEM(vfn) (0x13000 + (64 * vfn))
-
#define IXGBE_PFMAILBOX_STS 0x00000001 /* Initiate message send to VF */
#define IXGBE_PFMAILBOX_ACK 0x00000002 /* Ack message recv'd from VF */
#define IXGBE_PFMAILBOX_VFU 0x00000004 /* VF owns the mailbox buffer */
@@ -70,6 +67,7 @@
#define IXGBE_VF_SET_MULTICAST 0x03 /* VF requests PF to set MC addr */
#define IXGBE_VF_SET_VLAN 0x04 /* VF requests PF to set VLAN */
#define IXGBE_VF_SET_LPE 0x05 /* VF requests PF to set VMOLR.LPE */
+#define IXGBE_VF_SET_MACVLAN 0x06 /* VF requests PF for unicast filter */
/* length of permanent address message returned from PF */
#define IXGBE_VF_PERMADDR_MSG_LEN 4
diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c
index df5b8aa4795d..735f686c3b36 100644
--- a/drivers/net/ixgbe/ixgbe_phy.c
+++ b/drivers/net/ixgbe/ixgbe_phy.c
@@ -449,7 +449,8 @@ s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw)
MDIO_MMD_AN,
&autoneg_reg);
- autoneg_reg &= ~ADVERTISE_100FULL;
+ autoneg_reg &= ~(ADVERTISE_100FULL |
+ ADVERTISE_100HALF);
if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL)
autoneg_reg |= ADVERTISE_100FULL;
@@ -656,7 +657,8 @@ s32 ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw)
MDIO_MMD_AN,
&autoneg_reg);
- autoneg_reg &= ~ADVERTISE_100FULL;
+ autoneg_reg &= ~(ADVERTISE_100FULL |
+ ADVERTISE_100HALF);
if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL)
autoneg_reg |= ADVERTISE_100FULL;
@@ -753,7 +755,7 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw)
&phy_data);
if ((phy_data & MDIO_CTRL1_RESET) == 0)
break;
- msleep(10);
+ usleep_range(10000, 20000);
}
if ((phy_data & MDIO_CTRL1_RESET) != 0) {
@@ -782,7 +784,7 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw)
case IXGBE_DELAY_NL:
data_offset++;
hw_dbg(hw, "DELAY: %d MS\n", edata);
- msleep(edata);
+ usleep_range(edata * 1000, edata * 2000);
break;
case IXGBE_DATA_NL:
hw_dbg(hw, "DATA:\n");
@@ -1220,7 +1222,7 @@ s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
swfw_mask = IXGBE_GSSR_PHY0_SM;
do {
- if (ixgbe_acquire_swfw_sync(hw, swfw_mask) != 0) {
+ if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask) != 0) {
status = IXGBE_ERR_SWFW_SYNC;
goto read_byte_out;
}
@@ -1267,7 +1269,7 @@ s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
break;
fail:
- ixgbe_release_swfw_sync(hw, swfw_mask);
+ hw->mac.ops.release_swfw_sync(hw, swfw_mask);
msleep(100);
ixgbe_i2c_bus_clear(hw);
retry++;
@@ -1278,7 +1280,7 @@ fail:
} while (retry < max_retry);
- ixgbe_release_swfw_sync(hw, swfw_mask);
+ hw->mac.ops.release_swfw_sync(hw, swfw_mask);
read_byte_out:
return status;
@@ -1306,7 +1308,7 @@ s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
else
swfw_mask = IXGBE_GSSR_PHY0_SM;
- if (ixgbe_acquire_swfw_sync(hw, swfw_mask) != 0) {
+ if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask) != 0) {
status = IXGBE_ERR_SWFW_SYNC;
goto write_byte_out;
}
@@ -1350,7 +1352,7 @@ fail:
hw_dbg(hw, "I2C byte write error.\n");
} while (retry < max_retry);
- ixgbe_release_swfw_sync(hw, swfw_mask);
+ hw->mac.ops.release_swfw_sync(hw, swfw_mask);
write_byte_out:
return status;
diff --git a/drivers/net/ixgbe/ixgbe_sriov.c b/drivers/net/ixgbe/ixgbe_sriov.c
index 6e50d8328942..ac99b0458fe2 100644
--- a/drivers/net/ixgbe/ixgbe_sriov.c
+++ b/drivers/net/ixgbe/ixgbe_sriov.c
@@ -82,6 +82,21 @@ static int ixgbe_set_vf_multicasts(struct ixgbe_adapter *adapter,
return 0;
}
+static void ixgbe_restore_vf_macvlans(struct ixgbe_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct list_head *pos;
+ struct vf_macvlans *entry;
+
+ list_for_each(pos, &adapter->vf_mvs.l) {
+ entry = list_entry(pos, struct vf_macvlans, l);
+ if (entry->free == false)
+ hw->mac.ops.set_rar(hw, entry->rar_entry,
+ entry->vf_macvlan,
+ entry->vf, IXGBE_RAH_AV);
+ }
+}
+
void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
@@ -102,6 +117,9 @@ void ixgbe_restore_vf_multicasts(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(hw, IXGBE_MTA(vector_reg), mta_reg);
}
}
+
+ /* Restore any VF macvlans */
+ ixgbe_restore_vf_macvlans(adapter);
}
static int ixgbe_set_vf_vlan(struct ixgbe_adapter *adapter, int add, int vid,
@@ -110,7 +128,7 @@ static int ixgbe_set_vf_vlan(struct ixgbe_adapter *adapter, int add, int vid,
return adapter->hw.mac.ops.set_vfta(&adapter->hw, vid, vf, (bool)add);
}
-void ixgbe_set_vf_lpe(struct ixgbe_adapter *adapter, u32 *msgbuf)
+static void ixgbe_set_vf_lpe(struct ixgbe_adapter *adapter, u32 *msgbuf)
{
struct ixgbe_hw *hw = &adapter->hw;
int new_mtu = msgbuf[1];
@@ -200,6 +218,61 @@ static int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter,
return 0;
}
+static int ixgbe_set_vf_macvlan(struct ixgbe_adapter *adapter,
+ int vf, int index, unsigned char *mac_addr)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ struct list_head *pos;
+ struct vf_macvlans *entry;
+
+ if (index <= 1) {
+ list_for_each(pos, &adapter->vf_mvs.l) {
+ entry = list_entry(pos, struct vf_macvlans, l);
+ if (entry->vf == vf) {
+ entry->vf = -1;
+ entry->free = true;
+ entry->is_macvlan = false;
+ hw->mac.ops.clear_rar(hw, entry->rar_entry);
+ }
+ }
+ }
+
+ /*
+ * If index was zero then we were asked to clear the uc list
+ * for the VF. We're done.
+ */
+ if (!index)
+ return 0;
+
+ entry = NULL;
+
+ list_for_each(pos, &adapter->vf_mvs.l) {
+ entry = list_entry(pos, struct vf_macvlans, l);
+ if (entry->free)
+ break;
+ }
+
+ /*
+ * If we traversed the entire list and didn't find a free entry
+ * then we're out of space on the RAR table. Also entry may
+ * be NULL because the original memory allocation for the list
+ * failed, which is not fatal but does mean we can't support
+ * VF requests for MACVLAN because we couldn't allocate
+ * memory for the list management required.
+ */
+ if (!entry || !entry->free)
+ return -ENOSPC;
+
+ entry->free = false;
+ entry->is_macvlan = true;
+ entry->vf = vf;
+ memcpy(entry->vf_macvlan, mac_addr, ETH_ALEN);
+
+ hw->mac.ops.set_rar(hw, entry->rar_entry, mac_addr, vf, IXGBE_RAH_AV);
+
+ return 0;
+}
+
int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask)
{
unsigned char vf_mac_addr[6];
@@ -251,12 +324,12 @@ static inline void ixgbe_vf_reset_msg(struct ixgbe_adapter *adapter, u32 vf)
static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf)
{
u32 mbx_size = IXGBE_VFMAILBOX_SIZE;
- u32 msgbuf[mbx_size];
+ u32 msgbuf[IXGBE_VFMAILBOX_SIZE];
struct ixgbe_hw *hw = &adapter->hw;
s32 retval;
int entries;
u16 *hash_list;
- int add, vid;
+ int add, vid, index;
u8 *new_mac;
retval = ixgbe_read_mbx(hw, msgbuf, mbx_size, vf);
@@ -345,6 +418,24 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf)
retval = ixgbe_set_vf_vlan(adapter, add, vid, vf);
}
break;
+ case IXGBE_VF_SET_MACVLAN:
+ index = (msgbuf[0] & IXGBE_VT_MSGINFO_MASK) >>
+ IXGBE_VT_MSGINFO_SHIFT;
+ /*
+ * If the VF is allowed to set MAC filters then turn off
+ * anti-spoofing to avoid false positives. An index
+ * greater than 0 will indicate the VF is setting a
+ * macvlan MAC filter.
+ */
+ if (index > 0 && adapter->antispoofing_enabled) {
+ hw->mac.ops.set_mac_anti_spoofing(hw, false,
+ adapter->num_vfs);
+ hw->mac.ops.set_vlan_anti_spoofing(hw, false, vf);
+ adapter->antispoofing_enabled = false;
+ }
+ retval = ixgbe_set_vf_macvlan(adapter, vf, index,
+ (unsigned char *)(&msgbuf[1]));
+ break;
default:
e_err(drv, "Unhandled Msg %8.8x\n", msgbuf[0]);
retval = IXGBE_ERR_MBX;
@@ -452,7 +543,8 @@ int ixgbe_ndo_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos)
goto out;
ixgbe_set_vmvir(adapter, vlan | (qos << VLAN_PRIO_SHIFT), vf);
ixgbe_set_vmolr(hw, vf, false);
- hw->mac.ops.set_vlan_anti_spoofing(hw, true, vf);
+ if (adapter->antispoofing_enabled)
+ hw->mac.ops.set_vlan_anti_spoofing(hw, true, vf);
adapter->vfinfo[vf].pf_vlan = vlan;
adapter->vfinfo[vf].pf_qos = qos;
dev_info(&adapter->pdev->dev,
diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h
index 25c1fb7eda06..fa43f2507f43 100644
--- a/drivers/net/ixgbe/ixgbe_type.h
+++ b/drivers/net/ixgbe/ixgbe_type.h
@@ -58,9 +58,11 @@
#define IXGBE_DEV_ID_82599_SFP_FCOE 0x1529
#define IXGBE_SUBDEV_ID_82599_SFP 0x11A9
#define IXGBE_DEV_ID_82599_SFP_EM 0x1507
+#define IXGBE_DEV_ID_82599_SFP_SF2 0x154D
#define IXGBE_DEV_ID_82599_XAUI_LOM 0x10FC
#define IXGBE_DEV_ID_82599_COMBO_BACKPLANE 0x10F8
#define IXGBE_SUBDEV_ID_82599_KX4_KR_MEZZ 0x000C
+#define IXGBE_DEV_ID_82599_LS 0x154F
#define IXGBE_DEV_ID_X540T 0x1528
/* General Registers */
@@ -163,6 +165,9 @@
(0x0D018 + ((_i - 64) * 0x40)))
#define IXGBE_RXDCTL(_i) (((_i) < 64) ? (0x01028 + ((_i) * 0x40)) : \
(0x0D028 + ((_i - 64) * 0x40)))
+#define IXGBE_RSCCTL(_i) (((_i) < 64) ? (0x0102C + ((_i) * 0x40)) : \
+ (0x0D02C + ((_i - 64) * 0x40)))
+#define IXGBE_RSCDBU 0x03028
#define IXGBE_RDDCC 0x02F20
#define IXGBE_RXMEMWRAP 0x03190
#define IXGBE_STARCTRL 0x03024
@@ -227,17 +232,23 @@
#define IXGBE_VLVF(_i) (0x0F100 + ((_i) * 4)) /* 64 of these (0-63) */
#define IXGBE_VLVFB(_i) (0x0F200 + ((_i) * 4)) /* 128 of these (0-127) */
#define IXGBE_VMVIR(_i) (0x08000 + ((_i) * 4)) /* 64 of these (0-63) */
-#define IXGBE_VT_CTL 0x051B0
-#define IXGBE_VFRE(_i) (0x051E0 + ((_i) * 4))
-#define IXGBE_VFTE(_i) (0x08110 + ((_i) * 4))
-#define IXGBE_VMECM(_i) (0x08790 + ((_i) * 4))
-#define IXGBE_QDE 0x2F04
-#define IXGBE_VMOLR(_i) (0x0F000 + ((_i) * 4)) /* 64 total */
-#define IXGBE_UTA(_i) (0x0F400 + ((_i) * 4))
-#define IXGBE_VMRCTL(_i) (0x0F600 + ((_i) * 4))
-#define IXGBE_VMRVLAN(_i) (0x0F610 + ((_i) * 4))
-#define IXGBE_VMRVM(_i) (0x0F630 + ((_i) * 4))
-#define IXGBE_L34T_IMIR(_i) (0x0E800 + ((_i) * 4)) /*128 of these (0-127)*/
+#define IXGBE_VT_CTL 0x051B0
+#define IXGBE_PFMAILBOX(_i) (0x04B00 + (4 * (_i))) /* 64 total */
+#define IXGBE_PFMBMEM(_i) (0x13000 + (64 * (_i))) /* 64 Mailboxes, 16 DW each */
+#define IXGBE_PFMBICR(_i) (0x00710 + (4 * (_i))) /* 4 total */
+#define IXGBE_PFMBIMR(_i) (0x00720 + (4 * (_i))) /* 4 total */
+#define IXGBE_VFRE(_i) (0x051E0 + ((_i) * 4))
+#define IXGBE_VFTE(_i) (0x08110 + ((_i) * 4))
+#define IXGBE_VMECM(_i) (0x08790 + ((_i) * 4))
+#define IXGBE_QDE 0x2F04
+#define IXGBE_VMTXSW(_i) (0x05180 + ((_i) * 4)) /* 2 total */
+#define IXGBE_VMOLR(_i) (0x0F000 + ((_i) * 4)) /* 64 total */
+#define IXGBE_UTA(_i) (0x0F400 + ((_i) * 4))
+#define IXGBE_MRCTL(_i) (0x0F600 + ((_i) * 4))
+#define IXGBE_VMRVLAN(_i) (0x0F610 + ((_i) * 4))
+#define IXGBE_VMRVM(_i) (0x0F630 + ((_i) * 4))
+#define IXGBE_L34T_IMIR(_i) (0x0E800 + ((_i) * 4)) /*128 of these (0-127)*/
+#define IXGBE_RXFECCERR0 0x051B8
#define IXGBE_LLITHRESH 0x0EC90
#define IXGBE_IMIR(_i) (0x05A80 + ((_i) * 4)) /* 8 of these (0-7) */
#define IXGBE_IMIREXT(_i) (0x05AA0 + ((_i) * 4)) /* 8 of these (0-7) */
@@ -364,7 +375,7 @@
#define IXGBE_WUFC_FLX5 0x00200000 /* Flexible Filter 5 Enable */
#define IXGBE_WUFC_FLX_FILTERS 0x000F0000 /* Mask for 4 flex filters */
#define IXGBE_WUFC_EXT_FLX_FILTERS 0x00300000 /* Mask for Ext. flex filters */
-#define IXGBE_WUFC_ALL_FILTERS 0x003F00FF /* Mask for all 6 wakeup filters*/
+#define IXGBE_WUFC_ALL_FILTERS 0x003F00FF /* Mask for all wakeup filters */
#define IXGBE_WUFC_FLX_OFFSET 16 /* Offset to the Flexible Filters bits */
/* Wake Up Status */
@@ -406,7 +417,6 @@
#define IXGBE_SECTXSTAT 0x08804
#define IXGBE_SECTXBUFFAF 0x08808
#define IXGBE_SECTXMINIFG 0x08810
-#define IXGBE_SECTXSTAT 0x08804
#define IXGBE_SECRXCTRL 0x08D00
#define IXGBE_SECRXSTAT 0x08D04
@@ -499,21 +509,6 @@
#define IXGBE_SECTXCTRL_STORE_FORWARD_ENABLE 0x4
-/* HW RSC registers */
-#define IXGBE_RSCCTL(_i) (((_i) < 64) ? (0x0102C + ((_i) * 0x40)) : \
- (0x0D02C + ((_i - 64) * 0x40)))
-#define IXGBE_RSCDBU 0x03028
-#define IXGBE_RSCCTL_RSCEN 0x01
-#define IXGBE_RSCCTL_MAXDESC_1 0x00
-#define IXGBE_RSCCTL_MAXDESC_4 0x04
-#define IXGBE_RSCCTL_MAXDESC_8 0x08
-#define IXGBE_RSCCTL_MAXDESC_16 0x0C
-#define IXGBE_RXDADV_RSCCNT_SHIFT 17
-#define IXGBE_GPIE_RSC_DELAY_SHIFT 11
-#define IXGBE_RXDADV_RSCCNT_MASK 0x001E0000
-#define IXGBE_RSCDBU_RSCACKDIS 0x00000080
-#define IXGBE_RDRXCTL_RSCFRSTSIZE 0x003E0000
-
/* DCB registers */
#define IXGBE_RTRPCS 0x02430
#define IXGBE_RTTDCS 0x04900
@@ -522,6 +517,7 @@
#define IXGBE_RTRUP2TC 0x03020
#define IXGBE_RTTUP2TC 0x0C800
#define IXGBE_RTRPT4C(_i) (0x02140 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_TXLLQ(_i) (0x082E0 + ((_i) * 4)) /* 4 of these (0-3) */
#define IXGBE_RTRPT4S(_i) (0x02160 + ((_i) * 4)) /* 8 of these (0-7) */
#define IXGBE_RTTDT2C(_i) (0x04910 + ((_i) * 4)) /* 8 of these (0-7) */
#define IXGBE_RTTDT2S(_i) (0x04930 + ((_i) * 4)) /* 8 of these (0-7) */
@@ -540,7 +536,7 @@
(IXGBE_RTTBCNRC_RF_DEC_MASK << IXGBE_RTTBCNRC_RF_INT_SHIFT)
-/* FCoE registers */
+/* FCoE DMA Context Registers */
#define IXGBE_FCPTRL 0x02410 /* FC User Desc. PTR Low */
#define IXGBE_FCPTRH 0x02414 /* FC USer Desc. PTR High */
#define IXGBE_FCBUFF 0x02418 /* FC Buffer Control */
@@ -677,6 +673,10 @@
#define IXGBE_FCOEDWRC 0x0242C /* Number of FCoE DWords Received */
#define IXGBE_FCOEPTC 0x08784 /* Number of FCoE Packets Transmitted */
#define IXGBE_FCOEDWTC 0x08788 /* Number of FCoE DWords Transmitted */
+#define IXGBE_O2BGPTC 0x041C4
+#define IXGBE_O2BSPC 0x087B0
+#define IXGBE_B2OSPC 0x041C0
+#define IXGBE_B2OGPRC 0x02F90
#define IXGBE_PCRC8ECL 0x0E810
#define IXGBE_PCRC8ECH 0x0E811
#define IXGBE_PCRC8ECH_MASK 0x1F
@@ -742,17 +742,10 @@
#define IXGBE_PBACLR_82599 0x11068
#define IXGBE_CIAA_82599 0x11088
#define IXGBE_CIAD_82599 0x1108C
-#define IXGBE_PCIE_DIAG_0_82599 0x11090
-#define IXGBE_PCIE_DIAG_1_82599 0x11094
-#define IXGBE_PCIE_DIAG_2_82599 0x11098
-#define IXGBE_PCIE_DIAG_3_82599 0x1109C
-#define IXGBE_PCIE_DIAG_4_82599 0x110A0
-#define IXGBE_PCIE_DIAG_5_82599 0x110A4
-#define IXGBE_PCIE_DIAG_6_82599 0x110A8
-#define IXGBE_PCIE_DIAG_7_82599 0x110C0
-#define IXGBE_INTRPT_CSR_82599 0x110B0
-#define IXGBE_INTRPT_MASK_82599 0x110B8
+#define IXGBE_PICAUSE 0x110B0
+#define IXGBE_PIENA 0x110B8
#define IXGBE_CDQ_MBR_82599 0x110B4
+#define IXGBE_PCIESPARE 0x110BC
#define IXGBE_MISC_REG_82599 0x110F0
#define IXGBE_ECC_CTRL_0_82599 0x11100
#define IXGBE_ECC_CTRL_1_82599 0x11104
@@ -785,7 +778,19 @@
#define IXGBE_SYSTIML 0x08C0C /* System time register Low - RO */
#define IXGBE_SYSTIMH 0x08C10 /* System time register High - RO */
#define IXGBE_TIMINCA 0x08C14 /* Increment attributes register - RW */
-#define IXGBE_RXUDP 0x08C1C /* Time Sync Rx UDP Port - RW */
+#define IXGBE_TIMADJL 0x08C18 /* Time Adjustment Offset register Low - RW */
+#define IXGBE_TIMADJH 0x08C1C /* Time Adjustment Offset register High - RW */
+#define IXGBE_TSAUXC 0x08C20 /* TimeSync Auxiliary Control register - RW */
+#define IXGBE_TRGTTIML0 0x08C24 /* Target Time Register 0 Low - RW */
+#define IXGBE_TRGTTIMH0 0x08C28 /* Target Time Register 0 High - RW */
+#define IXGBE_TRGTTIML1 0x08C2C /* Target Time Register 1 Low - RW */
+#define IXGBE_TRGTTIMH1 0x08C30 /* Target Time Register 1 High - RW */
+#define IXGBE_FREQOUT0 0x08C34 /* Frequency Out 0 Control register - RW */
+#define IXGBE_FREQOUT1 0x08C38 /* Frequency Out 1 Control register - RW */
+#define IXGBE_AUXSTMPL0 0x08C3C /* Auxiliary Time Stamp 0 register Low - RO */
+#define IXGBE_AUXSTMPH0 0x08C40 /* Auxiliary Time Stamp 0 register High - RO */
+#define IXGBE_AUXSTMPL1 0x08C44 /* Auxiliary Time Stamp 1 register Low - RO */
+#define IXGBE_AUXSTMPH1 0x08C48 /* Auxiliary Time Stamp 1 register High - RO */
/* Diagnostic Registers */
#define IXGBE_RDSTATCTL 0x02C20
@@ -829,8 +834,20 @@
#define IXGBE_TXDATARDPTR(_i) (0x0C720 + ((_i) * 4)) /* 8 of these C720-C72C*/
#define IXGBE_TXDESCRDPTR(_i) (0x0C730 + ((_i) * 4)) /* 8 of these C730-C73C*/
#define IXGBE_PCIEECCCTL 0x1106C
+#define IXGBE_RXWRPTR(_i) (0x03100 + ((_i) * 4)) /* 8 of these 3100-310C*/
+#define IXGBE_RXUSED(_i) (0x03120 + ((_i) * 4)) /* 8 of these 3120-312C*/
+#define IXGBE_RXRDPTR(_i) (0x03140 + ((_i) * 4)) /* 8 of these 3140-314C*/
+#define IXGBE_RXRDWRPTR(_i) (0x03160 + ((_i) * 4)) /* 8 of these 3160-310C*/
+#define IXGBE_TXWRPTR(_i) (0x0C100 + ((_i) * 4)) /* 8 of these C100-C10C*/
+#define IXGBE_TXUSED(_i) (0x0C120 + ((_i) * 4)) /* 8 of these C120-C12C*/
+#define IXGBE_TXRDPTR(_i) (0x0C140 + ((_i) * 4)) /* 8 of these C140-C14C*/
+#define IXGBE_TXRDWRPTR(_i) (0x0C160 + ((_i) * 4)) /* 8 of these C160-C10C*/
#define IXGBE_PCIEECCCTL0 0x11100
#define IXGBE_PCIEECCCTL1 0x11104
+#define IXGBE_RXDBUECC 0x03F70
+#define IXGBE_TXDBUECC 0x0CF70
+#define IXGBE_RXDBUEST 0x03F74
+#define IXGBE_TXDBUEST 0x0CF74
#define IXGBE_PBTXECC 0x0C300
#define IXGBE_PBRXECC 0x03300
#define IXGBE_GHECCR 0x110B0
@@ -871,6 +888,7 @@
#define IXGBE_AUTOC3 0x042AC
#define IXGBE_ANLP1 0x042B0
#define IXGBE_ANLP2 0x042B4
+#define IXGBE_MACC 0x04330
#define IXGBE_ATLASCTL 0x04800
#define IXGBE_MMNGC 0x042D0
#define IXGBE_ANLPNP1 0x042D4
@@ -883,14 +901,49 @@
#define IXGBE_MPVC 0x04318
#define IXGBE_SGMIIC 0x04314
+/* Statistics Registers */
+#define IXGBE_RXNFGPC 0x041B0
+#define IXGBE_RXNFGBCL 0x041B4
+#define IXGBE_RXNFGBCH 0x041B8
+#define IXGBE_RXDGPC 0x02F50
+#define IXGBE_RXDGBCL 0x02F54
+#define IXGBE_RXDGBCH 0x02F58
+#define IXGBE_RXDDGPC 0x02F5C
+#define IXGBE_RXDDGBCL 0x02F60
+#define IXGBE_RXDDGBCH 0x02F64
+#define IXGBE_RXLPBKGPC 0x02F68
+#define IXGBE_RXLPBKGBCL 0x02F6C
+#define IXGBE_RXLPBKGBCH 0x02F70
+#define IXGBE_RXDLPBKGPC 0x02F74
+#define IXGBE_RXDLPBKGBCL 0x02F78
+#define IXGBE_RXDLPBKGBCH 0x02F7C
+#define IXGBE_TXDGPC 0x087A0
+#define IXGBE_TXDGBCL 0x087A4
+#define IXGBE_TXDGBCH 0x087A8
+
+#define IXGBE_RXDSTATCTRL 0x02F40
+
+/* Copper Pond 2 link timeout */
#define IXGBE_VALIDATE_LINK_READY_TIMEOUT 50
/* Omer CORECTL */
#define IXGBE_CORECTL 0x014F00
/* BARCTRL */
-#define IXGBE_BARCTRL 0x110F4
-#define IXGBE_BARCTRL_FLSIZE 0x0700
-#define IXGBE_BARCTRL_CSRSIZE 0x2000
+#define IXGBE_BARCTRL 0x110F4
+#define IXGBE_BARCTRL_FLSIZE 0x0700
+#define IXGBE_BARCTRL_FLSIZE_SHIFT 8
+#define IXGBE_BARCTRL_CSRSIZE 0x2000
+
+/* RSCCTL Bit Masks */
+#define IXGBE_RSCCTL_RSCEN 0x01
+#define IXGBE_RSCCTL_MAXDESC_1 0x00
+#define IXGBE_RSCCTL_MAXDESC_4 0x04
+#define IXGBE_RSCCTL_MAXDESC_8 0x08
+#define IXGBE_RSCCTL_MAXDESC_16 0x0C
+
+/* RSCDBU Bit Masks */
+#define IXGBE_RSCDBU_RSCSMALDIS_MASK 0x0000007F
+#define IXGBE_RSCDBU_RSCACKDIS 0x00000080
/* RDRXCTL Bit Masks */
#define IXGBE_RDRXCTL_RDMTS_1_2 0x00000000 /* Rx Desc Min Threshold Size */
@@ -898,6 +951,8 @@
#define IXGBE_RDRXCTL_MVMEN 0x00000020
#define IXGBE_RDRXCTL_DMAIDONE 0x00000008 /* DMA init cycle done */
#define IXGBE_RDRXCTL_AGGDIS 0x00010000 /* Aggregation disable */
+#define IXGBE_RDRXCTL_RSCFRSTSIZE 0x003E0000 /* RSC First packet size */
+#define IXGBE_RDRXCTL_RSCLLIDIS 0x00800000 /* Disable RSC compl on LLI */
#define IXGBE_RDRXCTL_RSCACKC 0x02000000 /* must set 1 when RSC enabled */
#define IXGBE_RDRXCTL_FCOE_WRFIX 0x04000000 /* must set 1 when RSC enabled */
@@ -969,8 +1024,8 @@
#define IXGBE_MSCA_OP_CODE_SHIFT 26 /* OP CODE shift */
#define IXGBE_MSCA_ADDR_CYCLE 0x00000000 /* OP CODE 00 (addr cycle) */
#define IXGBE_MSCA_WRITE 0x04000000 /* OP CODE 01 (write) */
-#define IXGBE_MSCA_READ 0x08000000 /* OP CODE 10 (read) */
-#define IXGBE_MSCA_READ_AUTOINC 0x0C000000 /* OP CODE 11 (read, auto inc)*/
+#define IXGBE_MSCA_READ 0x0C000000 /* OP CODE 11 (read) */
+#define IXGBE_MSCA_READ_AUTOINC 0x08000000 /* OP CODE 10 (read, auto inc)*/
#define IXGBE_MSCA_ST_CODE_MASK 0x30000000 /* ST Code mask */
#define IXGBE_MSCA_ST_CODE_SHIFT 28 /* ST Code shift */
#define IXGBE_MSCA_NEW_PROTOCOL 0x00000000 /* ST CODE 00 (new protocol) */
@@ -1057,6 +1112,7 @@
#define IXGBE_GPIE_EIMEN 0x00000040 /* Immediate Interrupt Enable */
#define IXGBE_GPIE_EIAME 0x40000000
#define IXGBE_GPIE_PBA_SUPPORT 0x80000000
+#define IXGBE_GPIE_RSC_DELAY_SHIFT 11
#define IXGBE_GPIE_VTMODE_MASK 0x0000C000 /* VT Mode Mask */
#define IXGBE_GPIE_VTMODE_16 0x00004000 /* 16 VFs 8 queues per VF */
#define IXGBE_GPIE_VTMODE_32 0x00008000 /* 32 VFs 4 queues per VF */
@@ -1291,6 +1347,11 @@
#define IXGBE_FTQF_POOL_SHIFT 8
#define IXGBE_FTQF_5TUPLE_MASK_MASK 0x0000001F
#define IXGBE_FTQF_5TUPLE_MASK_SHIFT 25
+#define IXGBE_FTQF_SOURCE_ADDR_MASK 0x1E
+#define IXGBE_FTQF_DEST_ADDR_MASK 0x1D
+#define IXGBE_FTQF_SOURCE_PORT_MASK 0x1B
+#define IXGBE_FTQF_DEST_PORT_MASK 0x17
+#define IXGBE_FTQF_PROTOCOL_COMP_MASK 0x0F
#define IXGBE_FTQF_POOL_MASK_EN 0x40000000
#define IXGBE_FTQF_QUEUE_ENABLE 0x80000000
@@ -1333,11 +1394,11 @@
*
* Current filters:
* EAPOL 802.1x (0x888e): Filter 0
- * BCN (0x8904): Filter 1
+ * FCoE (0x8906): Filter 2
* 1588 (0x88f7): Filter 3
+ * FIP (0x8914): Filter 4
*/
#define IXGBE_ETQF_FILTER_EAPOL 0
-#define IXGBE_ETQF_FILTER_BCN 1
#define IXGBE_ETQF_FILTER_FCOE 2
#define IXGBE_ETQF_FILTER_1588 3
#define IXGBE_ETQF_FILTER_FIP 4
@@ -1448,6 +1509,11 @@
#define IXGBE_AUTOC2_10G_XFI (0x1 << IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_SHIFT)
#define IXGBE_AUTOC2_10G_SFI (0x2 << IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_SHIFT)
+#define IXGBE_MACC_FLU 0x00000001
+#define IXGBE_MACC_FSV_10G 0x00030000
+#define IXGBE_MACC_FS 0x00040000
+#define IXGBE_MAC_RX2TX_LPBK 0x00000002
+
/* LINKS Bit Masks */
#define IXGBE_LINKS_KX_AN_COMP 0x80000000
#define IXGBE_LINKS_UP 0x40000000
@@ -1501,7 +1567,6 @@
#define IXGBE_ANLP1_ASM_PAUSE 0x0800
#define IXGBE_ANLP1_AN_STATE_MASK 0x000f0000
-
/* SW Semaphore Register bitmasks */
#define IXGBE_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */
#define IXGBE_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */
@@ -1514,6 +1579,10 @@
#define IXGBE_GSSR_PHY1_SM 0x0004
#define IXGBE_GSSR_MAC_CSR_SM 0x0008
#define IXGBE_GSSR_FLASH_SM 0x0010
+#define IXGBE_GSSR_SW_MNG_SM 0x0400
+
+/* FW Status register bitmask */
+#define IXGBE_FWSTS_FWRI 0x00000200 /* Firmware Reset Indication */
/* EEC Register */
#define IXGBE_EEC_SK 0x00000001 /* EEPROM Clock */
@@ -1534,6 +1603,7 @@
/* EEPROM Addressing bits based on type (0-small, 1-large) */
#define IXGBE_EEC_ADDR_SIZE 0x00000400
#define IXGBE_EEC_SIZE 0x00007800 /* EEPROM Size */
+#define IXGBE_EERD_MAX_ADDR 0x00003FFF /* EERD alows 14 bits for addr. */
#define IXGBE_EEC_SIZE_SHIFT 11
#define IXGBE_EEPROM_WORD_SIZE_SHIFT 6
@@ -1563,8 +1633,10 @@
#define IXGBE_FW_PTR 0x0F
#define IXGBE_PBANUM0_PTR 0x15
#define IXGBE_PBANUM1_PTR 0x16
-#define IXGBE_DEVICE_CAPS 0x2C
+#define IXGBE_FREE_SPACE_PTR 0X3E
#define IXGBE_SAN_MAC_ADDR_PTR 0x28
+#define IXGBE_DEVICE_CAPS 0x2C
+#define IXGBE_SERIAL_NUMBER_MAC_ADDR 0x11
#define IXGBE_PCIE_MSIX_82599_CAPS 0x72
#define IXGBE_PCIE_MSIX_82598_CAPS 0x62
@@ -1601,6 +1673,10 @@
#define IXGBE_ETH_LENGTH_OF_ADDRESS 6
+#define IXGBE_EEPROM_PAGE_SIZE_MAX 128
+#define IXGBE_EEPROM_RD_BUFFER_MAX_COUNT 512 /* EEPROM words # read in burst */
+#define IXGBE_EEPROM_WR_BUFFER_MAX_COUNT 256 /* EEPROM words # wr in burst */
+
#ifndef IXGBE_EEPROM_GRANT_ATTEMPTS
#define IXGBE_EEPROM_GRANT_ATTEMPTS 1000 /* EEPROM # attempts to gain grant */
#endif
@@ -1616,14 +1692,25 @@
#define IXGBE_FLUDONE_ATTEMPTS 20000
#endif
+#define IXGBE_PCIE_CTRL2 0x5 /* PCIe Control 2 Offset */
+#define IXGBE_PCIE_CTRL2_DUMMY_ENABLE 0x8 /* Dummy Function Enable */
+#define IXGBE_PCIE_CTRL2_LAN_DISABLE 0x2 /* LAN PCI Disable */
+#define IXGBE_PCIE_CTRL2_DISABLE_SELECT 0x1 /* LAN Disable Select */
+
#define IXGBE_SAN_MAC_ADDR_PORT0_OFFSET 0x0
#define IXGBE_SAN_MAC_ADDR_PORT1_OFFSET 0x3
#define IXGBE_DEVICE_CAPS_ALLOW_ANY_SFP 0x1
#define IXGBE_DEVICE_CAPS_FCOE_OFFLOADS 0x2
+#define IXGBE_FW_LESM_PARAMETERS_PTR 0x2
+#define IXGBE_FW_LESM_STATE_1 0x1
+#define IXGBE_FW_LESM_STATE_ENABLED 0x8000 /* LESM Enable bit */
#define IXGBE_FW_PASSTHROUGH_PATCH_CONFIG_PTR 0x4
-#define IXGBE_FW_PATCH_VERSION_4 0x7
-
-/* Alternative SAN MAC Address Block */
+#define IXGBE_FW_PATCH_VERSION_4 0x7
+#define IXGBE_FCOE_IBA_CAPS_BLK_PTR 0x33 /* iSCSI/FCOE block */
+#define IXGBE_FCOE_IBA_CAPS_FCOE 0x20 /* FCOE flags */
+#define IXGBE_ISCSI_FCOE_BLK_PTR 0x17 /* iSCSI/FCOE block */
+#define IXGBE_ISCSI_FCOE_FLAGS_OFFSET 0x0 /* FCOE flags */
+#define IXGBE_ISCSI_FCOE_FLAGS_ENABLE 0x1 /* FCOE flags enable bit */
#define IXGBE_ALT_SAN_MAC_ADDR_BLK_PTR 0x27 /* Alt. SAN MAC block */
#define IXGBE_ALT_SAN_MAC_ADDR_CAPS_OFFSET 0x0 /* Alt. SAN MAC capability */
#define IXGBE_ALT_SAN_MAC_ADDR_PORT0_OFFSET 0x1 /* Alt. SAN MAC 0 offset */
@@ -1688,6 +1775,7 @@
/* Transmit Config masks */
#define IXGBE_TXDCTL_ENABLE 0x02000000 /* Enable specific Tx Queue */
#define IXGBE_TXDCTL_SWFLSH 0x04000000 /* Tx Desc. write-back flushing */
+#define IXGBE_TXDCTL_WTHRESH_SHIFT 16 /* shift to WTHRESH bits */
/* Enable short packet padding to 64 bytes */
#define IXGBE_TX_PAD_ENABLE 0x00000400
#define IXGBE_JUMBO_FRAME_ENABLE 0x00000004 /* Allow jumbo frames */
@@ -1701,9 +1789,9 @@
#define IXGBE_RXCTRL_RXEN 0x00000001 /* Enable Receiver */
#define IXGBE_RXCTRL_DMBYPS 0x00000002 /* Descriptor Monitor Bypass */
#define IXGBE_RXDCTL_ENABLE 0x02000000 /* Enable specific Rx Queue */
-#define IXGBE_RXDCTL_VME 0x40000000 /* VLAN mode enable */
#define IXGBE_RXDCTL_RLPMLMASK 0x00003FFF /* Only supported on the X540 */
#define IXGBE_RXDCTL_RLPML_EN 0x00008000
+#define IXGBE_RXDCTL_VME 0x40000000 /* VLAN mode enable */
#define IXGBE_FCTRL_SBP 0x00000002 /* Store Bad Packet */
#define IXGBE_FCTRL_MPE 0x00000100 /* Multicast Promiscuous Ena*/
@@ -1719,6 +1807,8 @@
#define IXGBE_MFLCN_RPFCE 0x00000004 /* Receive Priority FC Enable */
#define IXGBE_MFLCN_RFCE 0x00000008 /* Receive FC Enable */
+#define IXGBE_MFLCN_RPFCE_SHIFT 4
+
/* Multiple Receive Queue Control */
#define IXGBE_MRQC_RSSEN 0x00000001 /* RSS Enable */
#define IXGBE_MRQC_MRQE_MASK 0xF /* Bits 3:0 */
@@ -1859,6 +1949,8 @@
#define IXGBE_RXDADV_PKTTYPE_MASK 0x0000FFF0
#define IXGBE_RXDADV_PKTTYPE_MASK_EX 0x0001FFF0
#define IXGBE_RXDADV_HDRBUFLEN_MASK 0x00007FE0
+#define IXGBE_RXDADV_RSCCNT_MASK 0x001E0000
+#define IXGBE_RXDADV_RSCCNT_SHIFT 17
#define IXGBE_RXDADV_HDRBUFLEN_SHIFT 5
#define IXGBE_RXDADV_SPLITHEADER_EN 0x00001000
#define IXGBE_RXDADV_SPH 0x8000
@@ -1934,15 +2026,6 @@
#define IXGBE_VFLRE(_i) (((_i & 1) ? 0x001C0 : 0x00600))
#define IXGBE_VFLREC(_i) (0x00700 + (_i * 4))
-/* Little Endian defines */
-#ifndef __le32
-#define __le32 u32
-#endif
-#ifndef __le64
-#define __le64 u64
-
-#endif
-
enum ixgbe_fdir_pballoc_type {
IXGBE_FDIR_PBALLOC_64K = 0,
IXGBE_FDIR_PBALLOC_128K,
@@ -2141,8 +2224,6 @@ typedef u32 ixgbe_link_speed;
IXGBE_LINK_SPEED_1GB_FULL | \
IXGBE_LINK_SPEED_10GB_FULL)
-#define IXGBE_PCIE_DEV_CTRL_2 0xC8
-#define PCIE_COMPL_TO_VALUE 0x05
/* Physical layer type */
typedef u32 ixgbe_physical_layer;
@@ -2315,6 +2396,7 @@ enum ixgbe_sfp_type {
enum ixgbe_media_type {
ixgbe_media_type_unknown = 0,
ixgbe_media_type_fiber,
+ ixgbe_media_type_fiber_lco,
ixgbe_media_type_copper,
ixgbe_media_type_backplane,
ixgbe_media_type_cx4,
@@ -2478,6 +2560,10 @@ struct ixgbe_hw_stats {
u64 fcoeptc;
u64 fcoedwrc;
u64 fcoedwtc;
+ u64 b2ospc;
+ u64 b2ogprc;
+ u64 o2bgptc;
+ u64 o2bspc;
};
/* forward declaration */
@@ -2491,7 +2577,9 @@ typedef u8* (*ixgbe_mc_addr_itr) (struct ixgbe_hw *hw, u8 **mc_addr_ptr,
struct ixgbe_eeprom_operations {
s32 (*init_params)(struct ixgbe_hw *);
s32 (*read)(struct ixgbe_hw *, u16, u16 *);
+ s32 (*read_buffer)(struct ixgbe_hw *, u16, u16, u16 *);
s32 (*write)(struct ixgbe_hw *, u16, u16);
+ s32 (*write_buffer)(struct ixgbe_hw *, u16, u16, u16 *);
s32 (*validate_checksum)(struct ixgbe_hw *, u16 *);
s32 (*update_checksum)(struct ixgbe_hw *);
u16 (*calc_checksum)(struct ixgbe_hw *);
@@ -2577,6 +2665,7 @@ struct ixgbe_eeprom_info {
u32 semaphore_delay;
u16 word_size;
u16 address_bits;
+ u16 word_page_size;
};
#define IXGBE_FLAGS_DOUBLE_RESET_REQUIRED 0x01
@@ -2597,6 +2686,7 @@ struct ixgbe_mac_info {
u32 vft_size;
u32 num_rar_entries;
u32 rar_highwater;
+ u32 rx_pb_size;
u32 max_tx_queues;
u32 max_rx_queues;
u32 max_msix_vectors;
diff --git a/drivers/net/ixgbe/ixgbe_x540.c b/drivers/net/ixgbe/ixgbe_x540.c
index d9323c08f5c7..4ed687be2fe3 100644
--- a/drivers/net/ixgbe/ixgbe_x540.c
+++ b/drivers/net/ixgbe/ixgbe_x540.c
@@ -37,6 +37,7 @@
#define IXGBE_X540_RAR_ENTRIES 128
#define IXGBE_X540_MC_TBL_SIZE 128
#define IXGBE_X540_VFT_TBL_SIZE 128
+#define IXGBE_X540_RX_PB_SIZE 384
static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw);
static s32 ixgbe_poll_flash_update_done_X540(struct ixgbe_hw *hw);
@@ -226,6 +227,28 @@ mac_reset_top:
}
/**
+ * ixgbe_start_hw_X540 - Prepare hardware for Tx/Rx
+ * @hw: pointer to hardware structure
+ *
+ * Starts the hardware using the generic start_hw function
+ * and the generation start_hw function.
+ * Then performs revision-specific operations, if any.
+ **/
+static s32 ixgbe_start_hw_X540(struct ixgbe_hw *hw)
+{
+ s32 ret_val = 0;
+
+ ret_val = ixgbe_start_hw_generic(hw);
+ if (ret_val != 0)
+ goto out;
+
+ ret_val = ixgbe_start_hw_gen2(hw);
+ hw->mac.rx_pb_size = IXGBE_X540_RX_PB_SIZE;
+out:
+ return ret_val;
+}
+
+/**
* ixgbe_get_supported_physical_layer_X540 - Returns physical layer type
* @hw: pointer to hardware structure
*
@@ -281,74 +304,105 @@ static s32 ixgbe_init_eeprom_params_X540(struct ixgbe_hw *hw)
}
/**
- * ixgbe_read_eerd_X540 - Read EEPROM word using EERD
- * @hw: pointer to hardware structure
- * @offset: offset of word in the EEPROM to read
- * @data: word read from the EERPOM
+ * ixgbe_read_eerd_X540- Read EEPROM word using EERD
+ * @hw: pointer to hardware structure
+ * @offset: offset of word in the EEPROM to read
+ * @data: word read from the EEPROM
+ *
+ * Reads a 16 bit word from the EEPROM using the EERD register.
**/
static s32 ixgbe_read_eerd_X540(struct ixgbe_hw *hw, u16 offset, u16 *data)
{
- s32 status;
+ s32 status = 0;
- if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0)
+ if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) ==
+ 0)
status = ixgbe_read_eerd_generic(hw, offset, data);
else
status = IXGBE_ERR_SWFW_SYNC;
- ixgbe_release_swfw_sync_X540(hw, IXGBE_GSSR_EEP_SM);
+ hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
return status;
}
/**
- * ixgbe_write_eewr_X540 - Write EEPROM word using EEWR
- * @hw: pointer to hardware structure
- * @offset: offset of word in the EEPROM to write
- * @data: word write to the EEPROM
+ * ixgbe_read_eerd_buffer_X540 - Read EEPROM word(s) using EERD
+ * @hw: pointer to hardware structure
+ * @offset: offset of word in the EEPROM to read
+ * @words: number of words
+ * @data: word(s) read from the EEPROM
*
- * Write a 16 bit word to the EEPROM using the EEWR register.
+ * Reads a 16 bit word(s) from the EEPROM using the EERD register.
**/
-static s32 ixgbe_write_eewr_X540(struct ixgbe_hw *hw, u16 offset, u16 data)
+static s32 ixgbe_read_eerd_buffer_X540(struct ixgbe_hw *hw,
+ u16 offset, u16 words, u16 *data)
{
- u32 eewr;
- s32 status;
+ s32 status = 0;
- hw->eeprom.ops.init_params(hw);
+ if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) ==
+ 0)
+ status = ixgbe_read_eerd_buffer_generic(hw, offset,
+ words, data);
+ else
+ status = IXGBE_ERR_SWFW_SYNC;
- if (offset >= hw->eeprom.word_size) {
- status = IXGBE_ERR_EEPROM;
- goto out;
- }
+ hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
+ return status;
+}
- eewr = (offset << IXGBE_EEPROM_RW_ADDR_SHIFT) |
- (data << IXGBE_EEPROM_RW_REG_DATA) |
- IXGBE_EEPROM_RW_REG_START;
+/**
+ * ixgbe_write_eewr_X540 - Write EEPROM word using EEWR
+ * @hw: pointer to hardware structure
+ * @offset: offset of word in the EEPROM to write
+ * @data: word write to the EEPROM
+ *
+ * Write a 16 bit word to the EEPROM using the EEWR register.
+ **/
+static s32 ixgbe_write_eewr_X540(struct ixgbe_hw *hw, u16 offset, u16 data)
+{
+ s32 status = 0;
- if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) {
- status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE);
- if (status != 0) {
- hw_dbg(hw, "Eeprom write EEWR timed out\n");
- goto out;
- }
+ if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0)
+ status = ixgbe_write_eewr_generic(hw, offset, data);
+ else
+ status = IXGBE_ERR_SWFW_SYNC;
- IXGBE_WRITE_REG(hw, IXGBE_EEWR, eewr);
+ hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
+ return status;
+}
- status = ixgbe_poll_eerd_eewr_done(hw, IXGBE_NVM_POLL_WRITE);
- if (status != 0) {
- hw_dbg(hw, "Eeprom write EEWR timed out\n");
- goto out;
- }
- } else {
+/**
+ * ixgbe_write_eewr_buffer_X540 - Write EEPROM word(s) using EEWR
+ * @hw: pointer to hardware structure
+ * @offset: offset of word in the EEPROM to write
+ * @words: number of words
+ * @data: word(s) write to the EEPROM
+ *
+ * Write a 16 bit word(s) to the EEPROM using the EEWR register.
+ **/
+static s32 ixgbe_write_eewr_buffer_X540(struct ixgbe_hw *hw,
+ u16 offset, u16 words, u16 *data)
+{
+ s32 status = 0;
+
+ if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) ==
+ 0)
+ status = ixgbe_write_eewr_buffer_generic(hw, offset,
+ words, data);
+ else
status = IXGBE_ERR_SWFW_SYNC;
- }
-out:
- ixgbe_release_swfw_sync_X540(hw, IXGBE_GSSR_EEP_SM);
+ hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
return status;
}
/**
- * ixgbe_calc_eeprom_checksum_X540 - Calculates and returns the checksum
- * @hw: pointer to hardware structure
+ * ixgbe_calc_eeprom_checksum_X540 - Calculates and returns the checksum
+ *
+ * This function does not use synchronization for EERD and EEWR. It can
+ * be used internally by function which utilize ixgbe_acquire_swfw_sync_X540.
+ *
+ * @hw: pointer to hardware structure
**/
static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw)
{
@@ -359,9 +413,15 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw)
u16 pointer = 0;
u16 word = 0;
+ /*
+ * Do not use hw->eeprom.ops.read because we do not want to take
+ * the synchronization semaphores here. Instead use
+ * ixgbe_read_eerd_generic
+ */
+
/* Include 0x0-0x3F in the checksum */
for (i = 0; i < IXGBE_EEPROM_CHECKSUM; i++) {
- if (hw->eeprom.ops.read(hw, i, &word) != 0) {
+ if (ixgbe_read_eerd_generic(hw, i, &word) != 0) {
hw_dbg(hw, "EEPROM read failed\n");
break;
}
@@ -376,7 +436,7 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw)
if (i == IXGBE_PHY_PTR || i == IXGBE_OPTION_ROM_PTR)
continue;
- if (hw->eeprom.ops.read(hw, i, &pointer) != 0) {
+ if (ixgbe_read_eerd_generic(hw, i, &pointer) != 0) {
hw_dbg(hw, "EEPROM read failed\n");
break;
}
@@ -386,7 +446,7 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw)
pointer >= hw->eeprom.word_size)
continue;
- if (hw->eeprom.ops.read(hw, pointer, &length) != 0) {
+ if (ixgbe_read_eerd_generic(hw, pointer, &length) != 0) {
hw_dbg(hw, "EEPROM read failed\n");
break;
}
@@ -397,7 +457,7 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw)
continue;
for (j = pointer+1; j <= pointer+length; j++) {
- if (hw->eeprom.ops.read(hw, j, &word) != 0) {
+ if (ixgbe_read_eerd_generic(hw, j, &word) != 0) {
hw_dbg(hw, "EEPROM read failed\n");
break;
}
@@ -411,6 +471,62 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw)
}
/**
+ * ixgbe_validate_eeprom_checksum_X540 - Validate EEPROM checksum
+ * @hw: pointer to hardware structure
+ * @checksum_val: calculated checksum
+ *
+ * Performs checksum calculation and validates the EEPROM checksum. If the
+ * caller does not need checksum_val, the value can be NULL.
+ **/
+static s32 ixgbe_validate_eeprom_checksum_X540(struct ixgbe_hw *hw,
+ u16 *checksum_val)
+{
+ s32 status;
+ u16 checksum;
+ u16 read_checksum = 0;
+
+ /*
+ * Read the first word from the EEPROM. If this times out or fails, do
+ * not continue or we could be in for a very long wait while every
+ * EEPROM read fails
+ */
+ status = hw->eeprom.ops.read(hw, 0, &checksum);
+
+ if (status != 0) {
+ hw_dbg(hw, "EEPROM read failed\n");
+ goto out;
+ }
+
+ if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) {
+ checksum = hw->eeprom.ops.calc_checksum(hw);
+
+ /*
+ * Do not use hw->eeprom.ops.read because we do not want to take
+ * the synchronization semaphores twice here.
+ */
+ ixgbe_read_eerd_generic(hw, IXGBE_EEPROM_CHECKSUM,
+ &read_checksum);
+
+ /*
+ * Verify read checksum from EEPROM is the same as
+ * calculated checksum
+ */
+ if (read_checksum != checksum)
+ status = IXGBE_ERR_EEPROM_CHECKSUM;
+
+ /* If the user cares, return the calculated checksum */
+ if (checksum_val)
+ *checksum_val = checksum;
+ } else {
+ status = IXGBE_ERR_SWFW_SYNC;
+ }
+
+ hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
+out:
+ return status;
+}
+
+/**
* ixgbe_update_eeprom_checksum_X540 - Updates the EEPROM checksum and flash
* @hw: pointer to hardware structure
*
@@ -421,11 +537,35 @@ static u16 ixgbe_calc_eeprom_checksum_X540(struct ixgbe_hw *hw)
static s32 ixgbe_update_eeprom_checksum_X540(struct ixgbe_hw *hw)
{
s32 status;
+ u16 checksum;
+
+ /*
+ * Read the first word from the EEPROM. If this times out or fails, do
+ * not continue or we could be in for a very long wait while every
+ * EEPROM read fails
+ */
+ status = hw->eeprom.ops.read(hw, 0, &checksum);
+
+ if (status != 0)
+ hw_dbg(hw, "EEPROM read failed\n");
- status = ixgbe_update_eeprom_checksum_generic(hw);
+ if (hw->mac.ops.acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) == 0) {
+ checksum = hw->eeprom.ops.calc_checksum(hw);
+
+ /*
+ * Do not use hw->eeprom.ops.write because we do not want to
+ * take the synchronization semaphores twice here.
+ */
+ status = ixgbe_write_eewr_generic(hw, IXGBE_EEPROM_CHECKSUM,
+ checksum);
- if (status)
+ if (status == 0)
status = ixgbe_update_flash_X540(hw);
+ else
+ status = IXGBE_ERR_SWFW_SYNC;
+ }
+
+ hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_EEP_SM);
return status;
}
@@ -452,7 +592,7 @@ static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw)
IXGBE_WRITE_REG(hw, IXGBE_EEC, flup);
status = ixgbe_poll_flash_update_done_X540(hw);
- if (status)
+ if (status == 0)
hw_dbg(hw, "Flash update complete\n");
else
hw_dbg(hw, "Flash update time out\n");
@@ -466,11 +606,10 @@ static s32 ixgbe_update_flash_X540(struct ixgbe_hw *hw)
}
status = ixgbe_poll_flash_update_done_X540(hw);
- if (status)
+ if (status == 0)
hw_dbg(hw, "Flash update complete\n");
else
hw_dbg(hw, "Flash update time out\n");
-
}
out:
return status;
@@ -542,7 +681,7 @@ static s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask)
* resource (swmask)
*/
ixgbe_release_swfw_sync_semaphore(hw);
- msleep(5);
+ usleep_range(5000, 10000);
}
}
@@ -564,7 +703,7 @@ static s32 ixgbe_acquire_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask)
}
}
- msleep(5);
+ usleep_range(5000, 10000);
return 0;
}
@@ -588,7 +727,7 @@ static void ixgbe_release_swfw_sync_X540(struct ixgbe_hw *hw, u16 mask)
IXGBE_WRITE_REG(hw, IXGBE_SWFW_SYNC, swfw_sync);
ixgbe_release_swfw_sync_semaphore(hw);
- msleep(5);
+ usleep_range(5000, 10000);
}
/**
@@ -658,10 +797,70 @@ static void ixgbe_release_swfw_sync_semaphore(struct ixgbe_hw *hw)
IXGBE_WRITE_FLUSH(hw);
}
+/**
+ * ixgbe_blink_led_start_X540 - Blink LED based on index.
+ * @hw: pointer to hardware structure
+ * @index: led number to blink
+ *
+ * Devices that implement the version 2 interface:
+ * X540
+ **/
+static s32 ixgbe_blink_led_start_X540(struct ixgbe_hw *hw, u32 index)
+{
+ u32 macc_reg;
+ u32 ledctl_reg;
+
+ /*
+ * In order for the blink bit in the LED control register
+ * to work, link and speed must be forced in the MAC. We
+ * will reverse this when we stop the blinking.
+ */
+ macc_reg = IXGBE_READ_REG(hw, IXGBE_MACC);
+ macc_reg |= IXGBE_MACC_FLU | IXGBE_MACC_FSV_10G | IXGBE_MACC_FS;
+ IXGBE_WRITE_REG(hw, IXGBE_MACC, macc_reg);
+
+ /* Set the LED to LINK_UP + BLINK. */
+ ledctl_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
+ ledctl_reg &= ~IXGBE_LED_MODE_MASK(index);
+ ledctl_reg |= IXGBE_LED_BLINK(index);
+ IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, ledctl_reg);
+ IXGBE_WRITE_FLUSH(hw);
+
+ return 0;
+}
+
+/**
+ * ixgbe_blink_led_stop_X540 - Stop blinking LED based on index.
+ * @hw: pointer to hardware structure
+ * @index: led number to stop blinking
+ *
+ * Devices that implement the version 2 interface:
+ * X540
+ **/
+static s32 ixgbe_blink_led_stop_X540(struct ixgbe_hw *hw, u32 index)
+{
+ u32 macc_reg;
+ u32 ledctl_reg;
+
+ /* Restore the LED to its default value. */
+ ledctl_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
+ ledctl_reg &= ~IXGBE_LED_MODE_MASK(index);
+ ledctl_reg |= IXGBE_LED_LINK_ACTIVE << IXGBE_LED_MODE_SHIFT(index);
+ ledctl_reg &= ~IXGBE_LED_BLINK(index);
+ IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, ledctl_reg);
+
+ /* Unforce link and speed in the MAC. */
+ macc_reg = IXGBE_READ_REG(hw, IXGBE_MACC);
+ macc_reg &= ~(IXGBE_MACC_FLU | IXGBE_MACC_FSV_10G | IXGBE_MACC_FS);
+ IXGBE_WRITE_REG(hw, IXGBE_MACC, macc_reg);
+ IXGBE_WRITE_FLUSH(hw);
+
+ return 0;
+}
static struct ixgbe_mac_operations mac_ops_X540 = {
.init_hw = &ixgbe_init_hw_generic,
.reset_hw = &ixgbe_reset_hw_X540,
- .start_hw = &ixgbe_start_hw_generic,
+ .start_hw = &ixgbe_start_hw_X540,
.clear_hw_cntrs = &ixgbe_clear_hw_cntrs_generic,
.get_media_type = &ixgbe_get_media_type_X540,
.get_supported_physical_layer =
@@ -669,7 +868,7 @@ static struct ixgbe_mac_operations mac_ops_X540 = {
.enable_rx_dma = &ixgbe_enable_rx_dma_generic,
.get_mac_addr = &ixgbe_get_mac_addr_generic,
.get_san_mac_addr = &ixgbe_get_san_mac_addr_generic,
- .get_device_caps = NULL,
+ .get_device_caps = &ixgbe_get_device_caps_generic,
.get_wwn_prefix = &ixgbe_get_wwn_prefix_generic,
.stop_adapter = &ixgbe_stop_adapter_generic,
.get_bus_info = &ixgbe_get_bus_info_generic,
@@ -681,8 +880,8 @@ static struct ixgbe_mac_operations mac_ops_X540 = {
.get_link_capabilities = &ixgbe_get_copper_link_capabilities_generic,
.led_on = &ixgbe_led_on_generic,
.led_off = &ixgbe_led_off_generic,
- .blink_led_start = &ixgbe_blink_led_start_generic,
- .blink_led_stop = &ixgbe_blink_led_stop_generic,
+ .blink_led_start = &ixgbe_blink_led_start_X540,
+ .blink_led_stop = &ixgbe_blink_led_stop_X540,
.set_rar = &ixgbe_set_rar_generic,
.clear_rar = &ixgbe_clear_rar_generic,
.set_vmdq = &ixgbe_set_vmdq_generic,
@@ -705,9 +904,11 @@ static struct ixgbe_mac_operations mac_ops_X540 = {
static struct ixgbe_eeprom_operations eeprom_ops_X540 = {
.init_params = &ixgbe_init_eeprom_params_X540,
.read = &ixgbe_read_eerd_X540,
+ .read_buffer = &ixgbe_read_eerd_buffer_X540,
.write = &ixgbe_write_eewr_X540,
+ .write_buffer = &ixgbe_write_eewr_buffer_X540,
.calc_checksum = &ixgbe_calc_eeprom_checksum_X540,
- .validate_checksum = &ixgbe_validate_eeprom_checksum_generic,
+ .validate_checksum = &ixgbe_validate_eeprom_checksum_X540,
.update_checksum = &ixgbe_update_eeprom_checksum_X540,
};
diff --git a/drivers/net/ixgbevf/ethtool.c b/drivers/net/ixgbevf/ethtool.c
index 0563ab29264e..deee3754b1f7 100644
--- a/drivers/net/ixgbevf/ethtool.c
+++ b/drivers/net/ixgbevf/ethtool.c
@@ -104,11 +104,13 @@ static int ixgbevf_get_settings(struct net_device *netdev,
hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
if (link_up) {
- ecmd->speed = (link_speed == IXGBE_LINK_SPEED_10GB_FULL) ?
- SPEED_10000 : SPEED_1000;
+ ethtool_cmd_speed_set(
+ ecmd,
+ (link_speed == IXGBE_LINK_SPEED_10GB_FULL) ?
+ SPEED_10000 : SPEED_1000);
ecmd->duplex = DUPLEX_FULL;
} else {
- ecmd->speed = -1;
+ ethtool_cmd_speed_set(ecmd, -1);
ecmd->duplex = -1;
}
diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c
index 05fa7c85deed..28d3cb21d376 100644
--- a/drivers/net/ixgbevf/ixgbevf_main.c
+++ b/drivers/net/ixgbevf/ixgbevf_main.c
@@ -44,6 +44,7 @@
#include <net/ip6_checksum.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
+#include <linux/prefetch.h>
#include "ixgbevf.h"
@@ -1460,6 +1461,34 @@ static void ixgbevf_restore_vlan(struct ixgbevf_adapter *adapter)
}
}
+static int ixgbevf_write_uc_addr_list(struct net_device *netdev)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ int count = 0;
+
+ if ((netdev_uc_count(netdev)) > 10) {
+ printk(KERN_ERR "Too many unicast filters - No Space\n");
+ return -ENOSPC;
+ }
+
+ if (!netdev_uc_empty(netdev)) {
+ struct netdev_hw_addr *ha;
+ netdev_for_each_uc_addr(ha, netdev) {
+ hw->mac.ops.set_uc_addr(hw, ++count, ha->addr);
+ udelay(200);
+ }
+ } else {
+ /*
+ * If the list is empty then send message to PF driver to
+ * clear all macvlans on this VF.
+ */
+ hw->mac.ops.set_uc_addr(hw, 0, NULL);
+ }
+
+ return count;
+}
+
/**
* ixgbevf_set_rx_mode - Multicast set
* @netdev: network interface device structure
@@ -1476,6 +1505,8 @@ static void ixgbevf_set_rx_mode(struct net_device *netdev)
/* reprogram multicast list */
if (hw->mac.ops.update_mc_addr_list)
hw->mac.ops.update_mc_addr_list(hw, netdev);
+
+ ixgbevf_write_uc_addr_list(netdev);
}
static void ixgbevf_napi_enable_all(struct ixgbevf_adapter *adapter)
diff --git a/drivers/net/ixgbevf/mbx.h b/drivers/net/ixgbevf/mbx.h
index b2b5bf5daa3d..ea393eb03f3a 100644
--- a/drivers/net/ixgbevf/mbx.h
+++ b/drivers/net/ixgbevf/mbx.h
@@ -81,6 +81,7 @@
#define IXGBE_VF_SET_MULTICAST 0x03 /* VF requests PF to set MC addr */
#define IXGBE_VF_SET_VLAN 0x04 /* VF requests PF to set VLAN */
#define IXGBE_VF_SET_LPE 0x05 /* VF requests PF to set VMOLR.LPE */
+#define IXGBE_VF_SET_MACVLAN 0x06 /* VF requests PF for unicast filter */
/* length of permanent address message returned from PF */
#define IXGBE_VF_PERMADDR_MSG_LEN 4
diff --git a/drivers/net/ixgbevf/vf.c b/drivers/net/ixgbevf/vf.c
index eecd3bf6833f..aa3682e8c473 100644
--- a/drivers/net/ixgbevf/vf.c
+++ b/drivers/net/ixgbevf/vf.c
@@ -216,6 +216,39 @@ static s32 ixgbevf_get_mac_addr_vf(struct ixgbe_hw *hw, u8 *mac_addr)
return 0;
}
+static s32 ixgbevf_set_uc_addr_vf(struct ixgbe_hw *hw, u32 index, u8 *addr)
+{
+ struct ixgbe_mbx_info *mbx = &hw->mbx;
+ u32 msgbuf[3];
+ u8 *msg_addr = (u8 *)(&msgbuf[1]);
+ s32 ret_val;
+
+ memset(msgbuf, 0, sizeof(msgbuf));
+ /*
+ * If index is one then this is the start of a new list and needs
+ * indication to the PF so it can do it's own list management.
+ * If it is zero then that tells the PF to just clear all of
+ * this VF's macvlans and there is no new list.
+ */
+ msgbuf[0] |= index << IXGBE_VT_MSGINFO_SHIFT;
+ msgbuf[0] |= IXGBE_VF_SET_MACVLAN;
+ if (addr)
+ memcpy(msg_addr, addr, 6);
+ ret_val = mbx->ops.write_posted(hw, msgbuf, 3);
+
+ if (!ret_val)
+ ret_val = mbx->ops.read_posted(hw, msgbuf, 3);
+
+ msgbuf[0] &= ~IXGBE_VT_MSGTYPE_CTS;
+
+ if (!ret_val)
+ if (msgbuf[0] ==
+ (IXGBE_VF_SET_MACVLAN | IXGBE_VT_MSGTYPE_NACK))
+ ret_val = -ENOMEM;
+
+ return ret_val;
+}
+
/**
* ixgbevf_set_rar_vf - set device MAC address
* @hw: pointer to hardware structure
@@ -378,6 +411,7 @@ static struct ixgbe_mac_operations ixgbevf_mac_ops = {
.check_link = ixgbevf_check_mac_link_vf,
.set_rar = ixgbevf_set_rar_vf,
.update_mc_addr_list = ixgbevf_update_mc_addr_list_vf,
+ .set_uc_addr = ixgbevf_set_uc_addr_vf,
.set_vfta = ixgbevf_set_vfta_vf,
};
diff --git a/drivers/net/ixgbevf/vf.h b/drivers/net/ixgbevf/vf.h
index 23eb114c149f..10306b492ee6 100644
--- a/drivers/net/ixgbevf/vf.h
+++ b/drivers/net/ixgbevf/vf.h
@@ -62,6 +62,7 @@ struct ixgbe_mac_operations {
/* RAR, Multicast, VLAN */
s32 (*set_rar)(struct ixgbe_hw *, u32, u8 *, u32);
+ s32 (*set_uc_addr)(struct ixgbe_hw *, u32, u8 *);
s32 (*init_rx_addrs)(struct ixgbe_hw *);
s32 (*update_mc_addr_list)(struct ixgbe_hw *, struct net_device *);
s32 (*enable_mc)(struct ixgbe_hw *);
diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index 994c80939c7a..b5b174a8c149 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -2230,17 +2230,9 @@ jme_change_mtu(struct net_device *netdev, int new_mtu)
jme_restart_rx_engine(jme);
}
- if (new_mtu > 1900) {
- netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
- NETIF_F_TSO | NETIF_F_TSO6);
- } else {
- if (test_bit(JME_FLAG_TXCSUM, &jme->flags))
- netdev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
- if (test_bit(JME_FLAG_TSO, &jme->flags))
- netdev->features |= NETIF_F_TSO | NETIF_F_TSO6;
- }
-
netdev->mtu = new_mtu;
+ netdev_update_features(netdev);
+
jme_reset_link(jme);
return 0;
@@ -2563,7 +2555,8 @@ jme_set_settings(struct net_device *netdev,
struct jme_adapter *jme = netdev_priv(netdev);
int rc, fdc = 0;
- if (ecmd->speed == SPEED_1000 && ecmd->autoneg != AUTONEG_ENABLE)
+ if (ethtool_cmd_speed(ecmd) == SPEED_1000
+ && ecmd->autoneg != AUTONEG_ENABLE)
return -EINVAL;
/*
@@ -2640,19 +2633,20 @@ jme_set_msglevel(struct net_device *netdev, u32 value)
}
static u32
-jme_get_rx_csum(struct net_device *netdev)
+jme_fix_features(struct net_device *netdev, u32 features)
{
- struct jme_adapter *jme = netdev_priv(netdev);
- return jme->reg_rxmcs & RXMCS_CHECKSUM;
+ if (netdev->mtu > 1900)
+ features &= ~(NETIF_F_ALL_TSO | NETIF_F_ALL_CSUM);
+ return features;
}
static int
-jme_set_rx_csum(struct net_device *netdev, u32 on)
+jme_set_features(struct net_device *netdev, u32 features)
{
struct jme_adapter *jme = netdev_priv(netdev);
spin_lock_bh(&jme->rxmcs_lock);
- if (on)
+ if (features & NETIF_F_RXCSUM)
jme->reg_rxmcs |= RXMCS_CHECKSUM;
else
jme->reg_rxmcs &= ~RXMCS_CHECKSUM;
@@ -2663,42 +2657,6 @@ jme_set_rx_csum(struct net_device *netdev, u32 on)
}
static int
-jme_set_tx_csum(struct net_device *netdev, u32 on)
-{
- struct jme_adapter *jme = netdev_priv(netdev);
-
- if (on) {
- set_bit(JME_FLAG_TXCSUM, &jme->flags);
- if (netdev->mtu <= 1900)
- netdev->features |=
- NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
- } else {
- clear_bit(JME_FLAG_TXCSUM, &jme->flags);
- netdev->features &=
- ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
- }
-
- return 0;
-}
-
-static int
-jme_set_tso(struct net_device *netdev, u32 on)
-{
- struct jme_adapter *jme = netdev_priv(netdev);
-
- if (on) {
- set_bit(JME_FLAG_TSO, &jme->flags);
- if (netdev->mtu <= 1900)
- netdev->features |= NETIF_F_TSO | NETIF_F_TSO6;
- } else {
- clear_bit(JME_FLAG_TSO, &jme->flags);
- netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
- }
-
- return 0;
-}
-
-static int
jme_nway_reset(struct net_device *netdev)
{
struct jme_adapter *jme = netdev_priv(netdev);
@@ -2839,11 +2797,6 @@ static const struct ethtool_ops jme_ethtool_ops = {
.get_link = jme_get_link,
.get_msglevel = jme_get_msglevel,
.set_msglevel = jme_set_msglevel,
- .get_rx_csum = jme_get_rx_csum,
- .set_rx_csum = jme_set_rx_csum,
- .set_tx_csum = jme_set_tx_csum,
- .set_tso = jme_set_tso,
- .set_sg = ethtool_op_set_sg,
.nway_reset = jme_nway_reset,
.get_eeprom_len = jme_get_eeprom_len,
.get_eeprom = jme_get_eeprom,
@@ -2903,6 +2856,8 @@ static const struct net_device_ops jme_netdev_ops = {
.ndo_change_mtu = jme_change_mtu,
.ndo_tx_timeout = jme_tx_timeout,
.ndo_vlan_rx_register = jme_vlan_rx_register,
+ .ndo_fix_features = jme_fix_features,
+ .ndo_set_features = jme_set_features,
};
static int __devinit
@@ -2957,6 +2912,12 @@ jme_init_one(struct pci_dev *pdev,
netdev->netdev_ops = &jme_netdev_ops;
netdev->ethtool_ops = &jme_ethtool_ops;
netdev->watchdog_timeo = TX_TIMEOUT;
+ netdev->hw_features = NETIF_F_IP_CSUM |
+ NETIF_F_IPV6_CSUM |
+ NETIF_F_SG |
+ NETIF_F_TSO |
+ NETIF_F_TSO6 |
+ NETIF_F_RXCSUM;
netdev->features = NETIF_F_IP_CSUM |
NETIF_F_IPV6_CSUM |
NETIF_F_SG |
@@ -3040,8 +3001,9 @@ jme_init_one(struct pci_dev *pdev,
jme->reg_txpfc = 0;
jme->reg_pmcs = PMCS_MFEN;
jme->reg_gpreg1 = GPREG1_DEFAULT;
- set_bit(JME_FLAG_TXCSUM, &jme->flags);
- set_bit(JME_FLAG_TSO, &jme->flags);
+
+ if (jme->reg_rxmcs & RXMCS_CHECKSUM)
+ netdev->features |= NETIF_F_RXCSUM;
/*
* Get Max Read Req Size from PCI Config Space
diff --git a/drivers/net/jme.h b/drivers/net/jme.h
index 8bf30451e821..e9aaeca96abc 100644
--- a/drivers/net/jme.h
+++ b/drivers/net/jme.h
@@ -468,8 +468,6 @@ struct jme_adapter {
enum jme_flags_bits {
JME_FLAG_MSI = 1,
JME_FLAG_SSET = 2,
- JME_FLAG_TXCSUM = 3,
- JME_FLAG_TSO = 4,
JME_FLAG_POLL = 5,
JME_FLAG_SHUTDOWN = 6,
};
diff --git a/drivers/net/ks8842.c b/drivers/net/ks8842.c
index f0d8346d0fa5..4d40626b3bfa 100644
--- a/drivers/net/ks8842.c
+++ b/drivers/net/ks8842.c
@@ -26,7 +26,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/mfd/core.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
@@ -1146,7 +1145,7 @@ static int __devinit ks8842_probe(struct platform_device *pdev)
struct resource *iomem;
struct net_device *netdev;
struct ks8842_adapter *adapter;
- struct ks8842_platform_data *pdata = mfd_get_data(pdev);
+ struct ks8842_platform_data *pdata = pdev->dev.platform_data;
u16 id;
unsigned i;
diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c
index 7f7d5708a658..41ea5920c158 100644
--- a/drivers/net/ksz884x.c
+++ b/drivers/net/ksz884x.c
@@ -1221,7 +1221,6 @@ struct ksz_port_info {
#define LINK_INT_WORKING (1 << 0)
#define SMALL_PACKET_TX_BUG (1 << 1)
#define HALF_DUPLEX_SIGNAL_BUG (1 << 2)
-#define IPV6_CSUM_GEN_HACK (1 << 3)
#define RX_HUGE_FRAME (1 << 4)
#define STP_SUPPORT (1 << 8)
@@ -3748,7 +3747,6 @@ static int hw_init(struct ksz_hw *hw)
if (1 == rc)
hw->features |= HALF_DUPLEX_SIGNAL_BUG;
}
- hw->features |= IPV6_CSUM_GEN_HACK;
return rc;
}
@@ -4887,8 +4885,7 @@ static netdev_tx_t netdev_tx(struct sk_buff *skb, struct net_device *dev)
left = hw_alloc_pkt(hw, skb->len, num);
if (left) {
if (left < num ||
- ((hw->features & IPV6_CSUM_GEN_HACK) &&
- (CHECKSUM_PARTIAL == skb->ip_summed) &&
+ ((CHECKSUM_PARTIAL == skb->ip_summed) &&
(ETH_P_IPV6 == htons(skb->protocol)))) {
struct sk_buff *org_skb = skb;
@@ -6001,6 +5998,7 @@ static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
struct dev_priv *priv = netdev_priv(dev);
struct dev_info *hw_priv = priv->adapter;
struct ksz_port *port = &priv->port;
+ u32 speed = ethtool_cmd_speed(cmd);
int rc;
/*
@@ -6009,11 +6007,11 @@ static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
*/
if (cmd->autoneg && priv->advertising == cmd->advertising) {
cmd->advertising |= ADVERTISED_ALL;
- if (10 == cmd->speed)
+ if (10 == speed)
cmd->advertising &=
~(ADVERTISED_100baseT_Full |
ADVERTISED_100baseT_Half);
- else if (100 == cmd->speed)
+ else if (100 == speed)
cmd->advertising &=
~(ADVERTISED_10baseT_Full |
ADVERTISED_10baseT_Half);
@@ -6035,8 +6033,8 @@ static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
port->force_link = 0;
} else {
port->duplex = cmd->duplex + 1;
- if (cmd->speed != 1000)
- port->speed = cmd->speed;
+ if (1000 != speed)
+ port->speed = speed;
if (cmd->autoneg)
port->force_link = 0;
else
@@ -6583,57 +6581,33 @@ static void netdev_get_ethtool_stats(struct net_device *dev,
}
/**
- * netdev_get_rx_csum - get receive checksum support
+ * netdev_set_features - set receive checksum support
* @dev: Network device.
- *
- * This function gets receive checksum support setting.
- *
- * Return true if receive checksum is enabled; false otherwise.
- */
-static u32 netdev_get_rx_csum(struct net_device *dev)
-{
- struct dev_priv *priv = netdev_priv(dev);
- struct dev_info *hw_priv = priv->adapter;
- struct ksz_hw *hw = &hw_priv->hw;
-
- return hw->rx_cfg &
- (DMA_RX_CSUM_UDP |
- DMA_RX_CSUM_TCP |
- DMA_RX_CSUM_IP);
-}
-
-/**
- * netdev_set_rx_csum - set receive checksum support
- * @dev: Network device.
- * @data: Zero to disable receive checksum support.
+ * @features: New device features (offloads).
*
* This function sets receive checksum support setting.
*
* Return 0 if successful; otherwise an error code.
*/
-static int netdev_set_rx_csum(struct net_device *dev, u32 data)
+static int netdev_set_features(struct net_device *dev, u32 features)
{
struct dev_priv *priv = netdev_priv(dev);
struct dev_info *hw_priv = priv->adapter;
struct ksz_hw *hw = &hw_priv->hw;
- u32 new_setting = hw->rx_cfg;
- if (data)
- new_setting |=
- (DMA_RX_CSUM_UDP | DMA_RX_CSUM_TCP |
- DMA_RX_CSUM_IP);
- else
- new_setting &=
- ~(DMA_RX_CSUM_UDP | DMA_RX_CSUM_TCP |
- DMA_RX_CSUM_IP);
- new_setting &= ~DMA_RX_CSUM_UDP;
mutex_lock(&hw_priv->lock);
- if (new_setting != hw->rx_cfg) {
- hw->rx_cfg = new_setting;
- if (hw->enabled)
- writel(hw->rx_cfg, hw->io + KS_DMA_RX_CTRL);
- }
+
+ /* see note in hw_setup() */
+ if (features & NETIF_F_RXCSUM)
+ hw->rx_cfg |= DMA_RX_CSUM_TCP | DMA_RX_CSUM_IP;
+ else
+ hw->rx_cfg &= ~(DMA_RX_CSUM_TCP | DMA_RX_CSUM_IP);
+
+ if (hw->enabled)
+ writel(hw->rx_cfg, hw->io + KS_DMA_RX_CTRL);
+
mutex_unlock(&hw_priv->lock);
+
return 0;
}
@@ -6658,12 +6632,6 @@ static struct ethtool_ops netdev_ethtool_ops = {
.get_strings = netdev_get_strings,
.get_sset_count = netdev_get_sset_count,
.get_ethtool_stats = netdev_get_ethtool_stats,
- .get_rx_csum = netdev_get_rx_csum,
- .set_rx_csum = netdev_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = ethtool_op_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
- .set_sg = ethtool_op_set_sg,
};
/*
@@ -6828,14 +6796,15 @@ static int __init netdev_init(struct net_device *dev)
/* 500 ms timeout */
dev->watchdog_timeo = HZ / 2;
- dev->features |= NETIF_F_IP_CSUM;
+ dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_RXCSUM;
/*
* Hardware does not really support IPv6 checksum generation, but
- * driver actually runs faster with this on. Refer IPV6_CSUM_GEN_HACK.
+ * driver actually runs faster with this on.
*/
- dev->features |= NETIF_F_IPV6_CSUM;
- dev->features |= NETIF_F_SG;
+ dev->hw_features |= NETIF_F_IPV6_CSUM;
+
+ dev->features |= dev->hw_features;
sema_init(&priv->proc_sem, 1);
@@ -6860,6 +6829,7 @@ static const struct net_device_ops netdev_ops = {
.ndo_start_xmit = netdev_tx,
.ndo_tx_timeout = netdev_tx_timeout,
.ndo_change_mtu = netdev_change_mtu,
+ .ndo_set_features = netdev_set_features,
.ndo_set_mac_address = netdev_set_mac_address,
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = netdev_ioctl,
diff --git a/drivers/net/lantiq_etop.c b/drivers/net/lantiq_etop.c
new file mode 100644
index 000000000000..45f252b7da30
--- /dev/null
+++ b/drivers/net/lantiq_etop.c
@@ -0,0 +1,805 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/uaccess.h>
+#include <linux/in.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/phy.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/skbuff.h>
+#include <linux/mm.h>
+#include <linux/platform_device.h>
+#include <linux/ethtool.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include <asm/checksum.h>
+
+#include <lantiq_soc.h>
+#include <xway_dma.h>
+#include <lantiq_platform.h>
+
+#define LTQ_ETOP_MDIO 0x11804
+#define MDIO_REQUEST 0x80000000
+#define MDIO_READ 0x40000000
+#define MDIO_ADDR_MASK 0x1f
+#define MDIO_ADDR_OFFSET 0x15
+#define MDIO_REG_MASK 0x1f
+#define MDIO_REG_OFFSET 0x10
+#define MDIO_VAL_MASK 0xffff
+
+#define PPE32_CGEN 0x800
+#define LQ_PPE32_ENET_MAC_CFG 0x1840
+
+#define LTQ_ETOP_ENETS0 0x11850
+#define LTQ_ETOP_MAC_DA0 0x1186C
+#define LTQ_ETOP_MAC_DA1 0x11870
+#define LTQ_ETOP_CFG 0x16020
+#define LTQ_ETOP_IGPLEN 0x16080
+
+#define MAX_DMA_CHAN 0x8
+#define MAX_DMA_CRC_LEN 0x4
+#define MAX_DMA_DATA_LEN 0x600
+
+#define ETOP_FTCU BIT(28)
+#define ETOP_MII_MASK 0xf
+#define ETOP_MII_NORMAL 0xd
+#define ETOP_MII_REVERSE 0xe
+#define ETOP_PLEN_UNDER 0x40
+#define ETOP_CGEN 0x800
+
+/* use 2 static channels for TX/RX */
+#define LTQ_ETOP_TX_CHANNEL 1
+#define LTQ_ETOP_RX_CHANNEL 6
+#define IS_TX(x) (x == LTQ_ETOP_TX_CHANNEL)
+#define IS_RX(x) (x == LTQ_ETOP_RX_CHANNEL)
+
+#define ltq_etop_r32(x) ltq_r32(ltq_etop_membase + (x))
+#define ltq_etop_w32(x, y) ltq_w32(x, ltq_etop_membase + (y))
+#define ltq_etop_w32_mask(x, y, z) \
+ ltq_w32_mask(x, y, ltq_etop_membase + (z))
+
+#define DRV_VERSION "1.0"
+
+static void __iomem *ltq_etop_membase;
+
+struct ltq_etop_chan {
+ int idx;
+ int tx_free;
+ struct net_device *netdev;
+ struct napi_struct napi;
+ struct ltq_dma_channel dma;
+ struct sk_buff *skb[LTQ_DESC_NUM];
+};
+
+struct ltq_etop_priv {
+ struct net_device *netdev;
+ struct ltq_eth_data *pldata;
+ struct resource *res;
+
+ struct mii_bus *mii_bus;
+ struct phy_device *phydev;
+
+ struct ltq_etop_chan ch[MAX_DMA_CHAN];
+ int tx_free[MAX_DMA_CHAN >> 1];
+
+ spinlock_t lock;
+};
+
+static int
+ltq_etop_alloc_skb(struct ltq_etop_chan *ch)
+{
+ ch->skb[ch->dma.desc] = dev_alloc_skb(MAX_DMA_DATA_LEN);
+ if (!ch->skb[ch->dma.desc])
+ return -ENOMEM;
+ ch->dma.desc_base[ch->dma.desc].addr = dma_map_single(NULL,
+ ch->skb[ch->dma.desc]->data, MAX_DMA_DATA_LEN,
+ DMA_FROM_DEVICE);
+ ch->dma.desc_base[ch->dma.desc].addr =
+ CPHYSADDR(ch->skb[ch->dma.desc]->data);
+ ch->dma.desc_base[ch->dma.desc].ctl =
+ LTQ_DMA_OWN | LTQ_DMA_RX_OFFSET(NET_IP_ALIGN) |
+ MAX_DMA_DATA_LEN;
+ skb_reserve(ch->skb[ch->dma.desc], NET_IP_ALIGN);
+ return 0;
+}
+
+static void
+ltq_etop_hw_receive(struct ltq_etop_chan *ch)
+{
+ struct ltq_etop_priv *priv = netdev_priv(ch->netdev);
+ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
+ struct sk_buff *skb = ch->skb[ch->dma.desc];
+ int len = (desc->ctl & LTQ_DMA_SIZE_MASK) - MAX_DMA_CRC_LEN;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (ltq_etop_alloc_skb(ch)) {
+ netdev_err(ch->netdev,
+ "failed to allocate new rx buffer, stopping DMA\n");
+ ltq_dma_close(&ch->dma);
+ }
+ ch->dma.desc++;
+ ch->dma.desc %= LTQ_DESC_NUM;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ skb_put(skb, len);
+ skb->dev = ch->netdev;
+ skb->protocol = eth_type_trans(skb, ch->netdev);
+ netif_receive_skb(skb);
+}
+
+static int
+ltq_etop_poll_rx(struct napi_struct *napi, int budget)
+{
+ struct ltq_etop_chan *ch = container_of(napi,
+ struct ltq_etop_chan, napi);
+ int rx = 0;
+ int complete = 0;
+
+ while ((rx < budget) && !complete) {
+ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
+
+ if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) {
+ ltq_etop_hw_receive(ch);
+ rx++;
+ } else {
+ complete = 1;
+ }
+ }
+ if (complete || !rx) {
+ napi_complete(&ch->napi);
+ ltq_dma_ack_irq(&ch->dma);
+ }
+ return rx;
+}
+
+static int
+ltq_etop_poll_tx(struct napi_struct *napi, int budget)
+{
+ struct ltq_etop_chan *ch =
+ container_of(napi, struct ltq_etop_chan, napi);
+ struct ltq_etop_priv *priv = netdev_priv(ch->netdev);
+ struct netdev_queue *txq =
+ netdev_get_tx_queue(ch->netdev, ch->idx >> 1);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ while ((ch->dma.desc_base[ch->tx_free].ctl &
+ (LTQ_DMA_OWN | LTQ_DMA_C)) == LTQ_DMA_C) {
+ dev_kfree_skb_any(ch->skb[ch->tx_free]);
+ ch->skb[ch->tx_free] = NULL;
+ memset(&ch->dma.desc_base[ch->tx_free], 0,
+ sizeof(struct ltq_dma_desc));
+ ch->tx_free++;
+ ch->tx_free %= LTQ_DESC_NUM;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (netif_tx_queue_stopped(txq))
+ netif_tx_start_queue(txq);
+ napi_complete(&ch->napi);
+ ltq_dma_ack_irq(&ch->dma);
+ return 1;
+}
+
+static irqreturn_t
+ltq_etop_dma_irq(int irq, void *_priv)
+{
+ struct ltq_etop_priv *priv = _priv;
+ int ch = irq - LTQ_DMA_CH0_INT;
+
+ napi_schedule(&priv->ch[ch].napi);
+ return IRQ_HANDLED;
+}
+
+static void
+ltq_etop_free_channel(struct net_device *dev, struct ltq_etop_chan *ch)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+
+ ltq_dma_free(&ch->dma);
+ if (ch->dma.irq)
+ free_irq(ch->dma.irq, priv);
+ if (IS_RX(ch->idx)) {
+ int desc;
+ for (desc = 0; desc < LTQ_DESC_NUM; desc++)
+ dev_kfree_skb_any(ch->skb[ch->dma.desc]);
+ }
+}
+
+static void
+ltq_etop_hw_exit(struct net_device *dev)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ int i;
+
+ ltq_pmu_disable(PMU_PPE);
+ for (i = 0; i < MAX_DMA_CHAN; i++)
+ if (IS_TX(i) || IS_RX(i))
+ ltq_etop_free_channel(dev, &priv->ch[i]);
+}
+
+static int
+ltq_etop_hw_init(struct net_device *dev)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ int i;
+
+ ltq_pmu_enable(PMU_PPE);
+
+ switch (priv->pldata->mii_mode) {
+ case PHY_INTERFACE_MODE_RMII:
+ ltq_etop_w32_mask(ETOP_MII_MASK,
+ ETOP_MII_REVERSE, LTQ_ETOP_CFG);
+ break;
+
+ case PHY_INTERFACE_MODE_MII:
+ ltq_etop_w32_mask(ETOP_MII_MASK,
+ ETOP_MII_NORMAL, LTQ_ETOP_CFG);
+ break;
+
+ default:
+ netdev_err(dev, "unknown mii mode %d\n",
+ priv->pldata->mii_mode);
+ return -ENOTSUPP;
+ }
+
+ /* enable crc generation */
+ ltq_etop_w32(PPE32_CGEN, LQ_PPE32_ENET_MAC_CFG);
+
+ ltq_dma_init_port(DMA_PORT_ETOP);
+
+ for (i = 0; i < MAX_DMA_CHAN; i++) {
+ int irq = LTQ_DMA_CH0_INT + i;
+ struct ltq_etop_chan *ch = &priv->ch[i];
+
+ ch->idx = ch->dma.nr = i;
+
+ if (IS_TX(i)) {
+ ltq_dma_alloc_tx(&ch->dma);
+ request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED,
+ "etop_tx", priv);
+ } else if (IS_RX(i)) {
+ ltq_dma_alloc_rx(&ch->dma);
+ for (ch->dma.desc = 0; ch->dma.desc < LTQ_DESC_NUM;
+ ch->dma.desc++)
+ if (ltq_etop_alloc_skb(ch))
+ return -ENOMEM;
+ ch->dma.desc = 0;
+ request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED,
+ "etop_rx", priv);
+ }
+ ch->dma.irq = irq;
+ }
+ return 0;
+}
+
+static void
+ltq_etop_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, "Lantiq ETOP");
+ strcpy(info->bus_info, "internal");
+ strcpy(info->version, DRV_VERSION);
+}
+
+static int
+ltq_etop_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+
+ return phy_ethtool_gset(priv->phydev, cmd);
+}
+
+static int
+ltq_etop_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+
+ return phy_ethtool_sset(priv->phydev, cmd);
+}
+
+static int
+ltq_etop_nway_reset(struct net_device *dev)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+
+ return phy_start_aneg(priv->phydev);
+}
+
+static const struct ethtool_ops ltq_etop_ethtool_ops = {
+ .get_drvinfo = ltq_etop_get_drvinfo,
+ .get_settings = ltq_etop_get_settings,
+ .set_settings = ltq_etop_set_settings,
+ .nway_reset = ltq_etop_nway_reset,
+};
+
+static int
+ltq_etop_mdio_wr(struct mii_bus *bus, int phy_addr, int phy_reg, u16 phy_data)
+{
+ u32 val = MDIO_REQUEST |
+ ((phy_addr & MDIO_ADDR_MASK) << MDIO_ADDR_OFFSET) |
+ ((phy_reg & MDIO_REG_MASK) << MDIO_REG_OFFSET) |
+ phy_data;
+
+ while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST)
+ ;
+ ltq_etop_w32(val, LTQ_ETOP_MDIO);
+ return 0;
+}
+
+static int
+ltq_etop_mdio_rd(struct mii_bus *bus, int phy_addr, int phy_reg)
+{
+ u32 val = MDIO_REQUEST | MDIO_READ |
+ ((phy_addr & MDIO_ADDR_MASK) << MDIO_ADDR_OFFSET) |
+ ((phy_reg & MDIO_REG_MASK) << MDIO_REG_OFFSET);
+
+ while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST)
+ ;
+ ltq_etop_w32(val, LTQ_ETOP_MDIO);
+ while (ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_REQUEST)
+ ;
+ val = ltq_etop_r32(LTQ_ETOP_MDIO) & MDIO_VAL_MASK;
+ return val;
+}
+
+static void
+ltq_etop_mdio_link(struct net_device *dev)
+{
+ /* nothing to do */
+}
+
+static int
+ltq_etop_mdio_probe(struct net_device *dev)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ struct phy_device *phydev = NULL;
+ int phy_addr;
+
+ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
+ if (priv->mii_bus->phy_map[phy_addr]) {
+ phydev = priv->mii_bus->phy_map[phy_addr];
+ break;
+ }
+ }
+
+ if (!phydev) {
+ netdev_err(dev, "no PHY found\n");
+ return -ENODEV;
+ }
+
+ phydev = phy_connect(dev, dev_name(&phydev->dev), &ltq_etop_mdio_link,
+ 0, priv->pldata->mii_mode);
+
+ if (IS_ERR(phydev)) {
+ netdev_err(dev, "Could not attach to PHY\n");
+ return PTR_ERR(phydev);
+ }
+
+ phydev->supported &= (SUPPORTED_10baseT_Half
+ | SUPPORTED_10baseT_Full
+ | SUPPORTED_100baseT_Half
+ | SUPPORTED_100baseT_Full
+ | SUPPORTED_Autoneg
+ | SUPPORTED_MII
+ | SUPPORTED_TP);
+
+ phydev->advertising = phydev->supported;
+ priv->phydev = phydev;
+ pr_info("%s: attached PHY [%s] (phy_addr=%s, irq=%d)\n",
+ dev->name, phydev->drv->name,
+ dev_name(&phydev->dev), phydev->irq);
+
+ return 0;
+}
+
+static int
+ltq_etop_mdio_init(struct net_device *dev)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ int i;
+ int err;
+
+ priv->mii_bus = mdiobus_alloc();
+ if (!priv->mii_bus) {
+ netdev_err(dev, "failed to allocate mii bus\n");
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ priv->mii_bus->priv = dev;
+ priv->mii_bus->read = ltq_etop_mdio_rd;
+ priv->mii_bus->write = ltq_etop_mdio_wr;
+ priv->mii_bus->name = "ltq_mii";
+ snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0);
+ priv->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+ if (!priv->mii_bus->irq) {
+ err = -ENOMEM;
+ goto err_out_free_mdiobus;
+ }
+
+ for (i = 0; i < PHY_MAX_ADDR; ++i)
+ priv->mii_bus->irq[i] = PHY_POLL;
+
+ if (mdiobus_register(priv->mii_bus)) {
+ err = -ENXIO;
+ goto err_out_free_mdio_irq;
+ }
+
+ if (ltq_etop_mdio_probe(dev)) {
+ err = -ENXIO;
+ goto err_out_unregister_bus;
+ }
+ return 0;
+
+err_out_unregister_bus:
+ mdiobus_unregister(priv->mii_bus);
+err_out_free_mdio_irq:
+ kfree(priv->mii_bus->irq);
+err_out_free_mdiobus:
+ mdiobus_free(priv->mii_bus);
+err_out:
+ return err;
+}
+
+static void
+ltq_etop_mdio_cleanup(struct net_device *dev)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+
+ phy_disconnect(priv->phydev);
+ mdiobus_unregister(priv->mii_bus);
+ kfree(priv->mii_bus->irq);
+ mdiobus_free(priv->mii_bus);
+}
+
+static int
+ltq_etop_open(struct net_device *dev)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ int i;
+
+ for (i = 0; i < MAX_DMA_CHAN; i++) {
+ struct ltq_etop_chan *ch = &priv->ch[i];
+
+ if (!IS_TX(i) && (!IS_RX(i)))
+ continue;
+ ltq_dma_open(&ch->dma);
+ napi_enable(&ch->napi);
+ }
+ phy_start(priv->phydev);
+ netif_tx_start_all_queues(dev);
+ return 0;
+}
+
+static int
+ltq_etop_stop(struct net_device *dev)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ int i;
+
+ netif_tx_stop_all_queues(dev);
+ phy_stop(priv->phydev);
+ for (i = 0; i < MAX_DMA_CHAN; i++) {
+ struct ltq_etop_chan *ch = &priv->ch[i];
+
+ if (!IS_RX(i) && !IS_TX(i))
+ continue;
+ napi_disable(&ch->napi);
+ ltq_dma_close(&ch->dma);
+ }
+ return 0;
+}
+
+static int
+ltq_etop_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ int queue = skb_get_queue_mapping(skb);
+ struct netdev_queue *txq = netdev_get_tx_queue(dev, queue);
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ struct ltq_etop_chan *ch = &priv->ch[(queue << 1) | 1];
+ struct ltq_dma_desc *desc = &ch->dma.desc_base[ch->dma.desc];
+ int len;
+ unsigned long flags;
+ u32 byte_offset;
+
+ len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
+
+ if ((desc->ctl & (LTQ_DMA_OWN | LTQ_DMA_C)) || ch->skb[ch->dma.desc]) {
+ dev_kfree_skb_any(skb);
+ netdev_err(dev, "tx ring full\n");
+ netif_tx_stop_queue(txq);
+ return NETDEV_TX_BUSY;
+ }
+
+ /* dma needs to start on a 16 byte aligned address */
+ byte_offset = CPHYSADDR(skb->data) % 16;
+ ch->skb[ch->dma.desc] = skb;
+
+ dev->trans_start = jiffies;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ desc->addr = ((unsigned int) dma_map_single(NULL, skb->data, len,
+ DMA_TO_DEVICE)) - byte_offset;
+ wmb();
+ desc->ctl = LTQ_DMA_OWN | LTQ_DMA_SOP | LTQ_DMA_EOP |
+ LTQ_DMA_TX_OFFSET(byte_offset) | (len & LTQ_DMA_SIZE_MASK);
+ ch->dma.desc++;
+ ch->dma.desc %= LTQ_DESC_NUM;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (ch->dma.desc_base[ch->dma.desc].ctl & LTQ_DMA_OWN)
+ netif_tx_stop_queue(txq);
+
+ return NETDEV_TX_OK;
+}
+
+static int
+ltq_etop_change_mtu(struct net_device *dev, int new_mtu)
+{
+ int ret = eth_change_mtu(dev, new_mtu);
+
+ if (!ret) {
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ ltq_etop_w32((ETOP_PLEN_UNDER << 16) | new_mtu,
+ LTQ_ETOP_IGPLEN);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+ return ret;
+}
+
+static int
+ltq_etop_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+
+ /* TODO: mii-toll reports "No MII transceiver present!." ?!*/
+ return phy_mii_ioctl(priv->phydev, rq, cmd);
+}
+
+static int
+ltq_etop_set_mac_address(struct net_device *dev, void *p)
+{
+ int ret = eth_mac_addr(dev, p);
+
+ if (!ret) {
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ unsigned long flags;
+
+ /* store the mac for the unicast filter */
+ spin_lock_irqsave(&priv->lock, flags);
+ ltq_etop_w32(*((u32 *)dev->dev_addr), LTQ_ETOP_MAC_DA0);
+ ltq_etop_w32(*((u16 *)&dev->dev_addr[4]) << 16,
+ LTQ_ETOP_MAC_DA1);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+ return ret;
+}
+
+static void
+ltq_etop_set_multicast_list(struct net_device *dev)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ unsigned long flags;
+
+ /* ensure that the unicast filter is not enabled in promiscious mode */
+ spin_lock_irqsave(&priv->lock, flags);
+ if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI))
+ ltq_etop_w32_mask(ETOP_FTCU, 0, LTQ_ETOP_ENETS0);
+ else
+ ltq_etop_w32_mask(0, ETOP_FTCU, LTQ_ETOP_ENETS0);
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static u16
+ltq_etop_select_queue(struct net_device *dev, struct sk_buff *skb)
+{
+ /* we are currently only using the first queue */
+ return 0;
+}
+
+static int
+ltq_etop_init(struct net_device *dev)
+{
+ struct ltq_etop_priv *priv = netdev_priv(dev);
+ struct sockaddr mac;
+ int err;
+
+ ether_setup(dev);
+ dev->watchdog_timeo = 10 * HZ;
+ err = ltq_etop_hw_init(dev);
+ if (err)
+ goto err_hw;
+ ltq_etop_change_mtu(dev, 1500);
+
+ memcpy(&mac, &priv->pldata->mac, sizeof(struct sockaddr));
+ if (!is_valid_ether_addr(mac.sa_data)) {
+ pr_warn("etop: invalid MAC, using random\n");
+ random_ether_addr(mac.sa_data);
+ }
+
+ err = ltq_etop_set_mac_address(dev, &mac);
+ if (err)
+ goto err_netdev;
+ ltq_etop_set_multicast_list(dev);
+ err = ltq_etop_mdio_init(dev);
+ if (err)
+ goto err_netdev;
+ return 0;
+
+err_netdev:
+ unregister_netdev(dev);
+ free_netdev(dev);
+err_hw:
+ ltq_etop_hw_exit(dev);
+ return err;
+}
+
+static void
+ltq_etop_tx_timeout(struct net_device *dev)
+{
+ int err;
+
+ ltq_etop_hw_exit(dev);
+ err = ltq_etop_hw_init(dev);
+ if (err)
+ goto err_hw;
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+ return;
+
+err_hw:
+ ltq_etop_hw_exit(dev);
+ netdev_err(dev, "failed to restart etop after TX timeout\n");
+}
+
+static const struct net_device_ops ltq_eth_netdev_ops = {
+ .ndo_open = ltq_etop_open,
+ .ndo_stop = ltq_etop_stop,
+ .ndo_start_xmit = ltq_etop_tx,
+ .ndo_change_mtu = ltq_etop_change_mtu,
+ .ndo_do_ioctl = ltq_etop_ioctl,
+ .ndo_set_mac_address = ltq_etop_set_mac_address,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_multicast_list = ltq_etop_set_multicast_list,
+ .ndo_select_queue = ltq_etop_select_queue,
+ .ndo_init = ltq_etop_init,
+ .ndo_tx_timeout = ltq_etop_tx_timeout,
+};
+
+static int __init
+ltq_etop_probe(struct platform_device *pdev)
+{
+ struct net_device *dev;
+ struct ltq_etop_priv *priv;
+ struct resource *res;
+ int err;
+ int i;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get etop resource\n");
+ err = -ENOENT;
+ goto err_out;
+ }
+
+ res = devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res), dev_name(&pdev->dev));
+ if (!res) {
+ dev_err(&pdev->dev, "failed to request etop resource\n");
+ err = -EBUSY;
+ goto err_out;
+ }
+
+ ltq_etop_membase = devm_ioremap_nocache(&pdev->dev,
+ res->start, resource_size(res));
+ if (!ltq_etop_membase) {
+ dev_err(&pdev->dev, "failed to remap etop engine %d\n",
+ pdev->id);
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ dev = alloc_etherdev_mq(sizeof(struct ltq_etop_priv), 4);
+ strcpy(dev->name, "eth%d");
+ dev->netdev_ops = &ltq_eth_netdev_ops;
+ dev->ethtool_ops = &ltq_etop_ethtool_ops;
+ priv = netdev_priv(dev);
+ priv->res = res;
+ priv->pldata = dev_get_platdata(&pdev->dev);
+ priv->netdev = dev;
+ spin_lock_init(&priv->lock);
+
+ for (i = 0; i < MAX_DMA_CHAN; i++) {
+ if (IS_TX(i))
+ netif_napi_add(dev, &priv->ch[i].napi,
+ ltq_etop_poll_tx, 8);
+ else if (IS_RX(i))
+ netif_napi_add(dev, &priv->ch[i].napi,
+ ltq_etop_poll_rx, 32);
+ priv->ch[i].netdev = dev;
+ }
+
+ err = register_netdev(dev);
+ if (err)
+ goto err_free;
+
+ platform_set_drvdata(pdev, dev);
+ return 0;
+
+err_free:
+ kfree(dev);
+err_out:
+ return err;
+}
+
+static int __devexit
+ltq_etop_remove(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+
+ if (dev) {
+ netif_tx_stop_all_queues(dev);
+ ltq_etop_hw_exit(dev);
+ ltq_etop_mdio_cleanup(dev);
+ unregister_netdev(dev);
+ }
+ return 0;
+}
+
+static struct platform_driver ltq_mii_driver = {
+ .remove = __devexit_p(ltq_etop_remove),
+ .driver = {
+ .name = "ltq_etop",
+ .owner = THIS_MODULE,
+ },
+};
+
+int __init
+init_ltq_etop(void)
+{
+ int ret = platform_driver_probe(&ltq_mii_driver, ltq_etop_probe);
+
+ if (ret)
+ pr_err("ltq_etop: Error registering platfom driver!");
+ return ret;
+}
+
+static void __exit
+exit_ltq_etop(void)
+{
+ platform_driver_unregister(&ltq_mii_driver);
+}
+
+module_init(init_ltq_etop);
+module_exit(exit_ltq_etop);
+
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_DESCRIPTION("Lantiq SoC ETOP");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index d70fb76edb77..4ce9e5f2c069 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -174,7 +174,8 @@ static void loopback_setup(struct net_device *dev)
| NETIF_F_HIGHDMA
| NETIF_F_LLTX
| NETIF_F_NETNS_LOCAL
- | NETIF_F_VLAN_CHALLENGED;
+ | NETIF_F_VLAN_CHALLENGED
+ | NETIF_F_LOOPBACK;
dev->ethtool_ops = &loopback_ethtool_ops;
dev->header_ops = &eth_header_ops;
dev->netdev_ops = &loopback_ops;
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 79ccb54ab00c..6c6a02869dfc 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -576,6 +576,11 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
* add that if/when we get our hands on a full-blown MII PHY.
*/
+ if (status & MACB_BIT(ISR_ROVR)) {
+ /* We missed at least one packet */
+ bp->hw_stats.rx_overruns++;
+ }
+
if (status & MACB_BIT(HRESP)) {
/*
* TODO: Reset the hardware, and maybe move the printk
@@ -1024,7 +1029,8 @@ static struct net_device_stats *macb_get_stats(struct net_device *dev)
hwstat->rx_jabbers +
hwstat->rx_undersize_pkts +
hwstat->rx_length_mismatch);
- nstat->rx_over_errors = hwstat->rx_resource_errors;
+ nstat->rx_over_errors = hwstat->rx_resource_errors +
+ hwstat->rx_overruns;
nstat->rx_crc_errors = hwstat->rx_fcs_errors;
nstat->rx_frame_errors = hwstat->rx_align_errors;
nstat->rx_fifo_errors = hwstat->rx_overruns;
@@ -1171,8 +1177,7 @@ static int __init macb_probe(struct platform_device *pdev)
}
dev->irq = platform_get_irq(pdev, 0);
- err = request_irq(dev->irq, macb_interrupt, IRQF_SAMPLE_RANDOM,
- dev->name, dev);
+ err = request_irq(dev->irq, macb_interrupt, 0, dev->name, dev);
if (err) {
printk(KERN_ERR
"%s: Unable to request IRQ %d (error %d)\n",
@@ -1351,5 +1356,5 @@ module_exit(macb_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Atmel MACB Ethernet driver");
-MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
MODULE_ALIAS("platform:macb");
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 78e34e9e4f00..d6aeaa5f25ea 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -70,16 +70,17 @@ static void macvlan_hash_add(struct macvlan_dev *vlan)
hlist_add_head_rcu(&vlan->hlist, &port->vlan_hash[addr[5]]);
}
-static void macvlan_hash_del(struct macvlan_dev *vlan)
+static void macvlan_hash_del(struct macvlan_dev *vlan, bool sync)
{
hlist_del_rcu(&vlan->hlist);
- synchronize_rcu();
+ if (sync)
+ synchronize_rcu();
}
static void macvlan_hash_change_addr(struct macvlan_dev *vlan,
const unsigned char *addr)
{
- macvlan_hash_del(vlan);
+ macvlan_hash_del(vlan, true);
/* Now that we are unhashed it is safe to change the device
* address without confusing packet delivery.
*/
@@ -237,10 +238,8 @@ static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
dest = macvlan_hash_lookup(port, eth->h_dest);
if (dest && dest->mode == MACVLAN_MODE_BRIDGE) {
- unsigned int length = skb->len + ETH_HLEN;
- int ret = dest->forward(dest->dev, skb);
- macvlan_count_rx(dest, length,
- ret == NET_RX_SUCCESS, 0);
+ /* send to lowerdev first for its network taps */
+ vlan->forward(vlan->lowerdev, skb);
return NET_XMIT_SUCCESS;
}
@@ -345,7 +344,7 @@ static int macvlan_stop(struct net_device *dev)
dev_uc_del(lowerdev, dev->dev_addr);
hash_del:
- macvlan_hash_del(vlan);
+ macvlan_hash_del(vlan, !dev->dismantle);
return 0;
}
@@ -415,7 +414,7 @@ static struct lock_class_key macvlan_netdev_addr_lock_key;
#define MACVLAN_FEATURES \
(NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \
NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \
- NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO)
+ NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO | NETIF_F_RXCSUM)
#define MACVLAN_STATE_MASK \
((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))
@@ -517,12 +516,6 @@ static void macvlan_ethtool_get_drvinfo(struct net_device *dev,
snprintf(drvinfo->version, 32, "0.1");
}
-static u32 macvlan_ethtool_get_rx_csum(struct net_device *dev)
-{
- const struct macvlan_dev *vlan = netdev_priv(dev);
- return dev_ethtool_get_rx_csum(vlan->lowerdev);
-}
-
static int macvlan_ethtool_get_settings(struct net_device *dev,
struct ethtool_cmd *cmd)
{
@@ -530,18 +523,10 @@ static int macvlan_ethtool_get_settings(struct net_device *dev,
return dev_ethtool_get_settings(vlan->lowerdev, cmd);
}
-static u32 macvlan_ethtool_get_flags(struct net_device *dev)
-{
- const struct macvlan_dev *vlan = netdev_priv(dev);
- return dev_ethtool_get_flags(vlan->lowerdev);
-}
-
static const struct ethtool_ops macvlan_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_settings = macvlan_ethtool_get_settings,
- .get_rx_csum = macvlan_ethtool_get_rx_csum,
.get_drvinfo = macvlan_ethtool_get_drvinfo,
- .get_flags = macvlan_ethtool_get_flags,
};
static const struct net_device_ops macvlan_netdev_ops = {
@@ -598,26 +583,18 @@ static int macvlan_port_create(struct net_device *dev)
err = netdev_rx_handler_register(dev, macvlan_handle_frame, port);
if (err)
kfree(port);
-
- dev->priv_flags |= IFF_MACVLAN_PORT;
+ else
+ dev->priv_flags |= IFF_MACVLAN_PORT;
return err;
}
-static void macvlan_port_rcu_free(struct rcu_head *head)
-{
- struct macvlan_port *port;
-
- 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);
+ kfree_rcu(port, rcu);
}
static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
@@ -799,6 +776,7 @@ static int macvlan_device_event(struct notifier_block *unused,
struct net_device *dev = ptr;
struct macvlan_dev *vlan, *next;
struct macvlan_port *port;
+ LIST_HEAD(list_kill);
if (!macvlan_port_exists(dev))
return NOTIFY_DONE;
@@ -824,7 +802,9 @@ static int macvlan_device_event(struct notifier_block *unused,
break;
list_for_each_entry_safe(vlan, next, &port->vlans, list)
- vlan->dev->rtnl_link_ops->dellink(vlan->dev, NULL);
+ vlan->dev->rtnl_link_ops->dellink(vlan->dev, &list_kill);
+ unregister_netdevice_many(&list_kill);
+ list_del(&list_kill);
break;
case NETDEV_PRE_TYPE_CHANGE:
/* Forbid underlaying device to change its type. */
diff --git a/drivers/net/mdio.c b/drivers/net/mdio.c
index e85bf04cf813..16fbb11d92ac 100644
--- a/drivers/net/mdio.c
+++ b/drivers/net/mdio.c
@@ -176,6 +176,9 @@ static u32 mdio45_get_an(const struct mdio_if_info *mdio, u16 addr)
* @npage_adv: Modes currently advertised on next pages
* @npage_lpa: Modes advertised by link partner on next pages
*
+ * The @ecmd parameter is expected to have been cleared before calling
+ * mdio45_ethtool_gset_npage().
+ *
* Since the CSRs for auto-negotiation using next pages are not fully
* standardised, this function does not attempt to decode them. The
* caller must pass them in.
@@ -185,6 +188,7 @@ void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio,
u32 npage_adv, u32 npage_lpa)
{
int reg;
+ u32 speed;
ecmd->transceiver = XCVR_INTERNAL;
ecmd->phy_address = mdio->prtad;
@@ -287,33 +291,36 @@ void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio,
if (modes & (ADVERTISED_10000baseT_Full |
ADVERTISED_10000baseKX4_Full |
ADVERTISED_10000baseKR_Full)) {
- ecmd->speed = SPEED_10000;
+ speed = SPEED_10000;
ecmd->duplex = DUPLEX_FULL;
} else if (modes & (ADVERTISED_1000baseT_Full |
ADVERTISED_1000baseT_Half |
ADVERTISED_1000baseKX_Full)) {
- ecmd->speed = SPEED_1000;
+ speed = SPEED_1000;
ecmd->duplex = !(modes & ADVERTISED_1000baseT_Half);
} else if (modes & (ADVERTISED_100baseT_Full |
ADVERTISED_100baseT_Half)) {
- ecmd->speed = SPEED_100;
+ speed = SPEED_100;
ecmd->duplex = !!(modes & ADVERTISED_100baseT_Full);
} else {
- ecmd->speed = SPEED_10;
+ speed = SPEED_10;
ecmd->duplex = !!(modes & ADVERTISED_10baseT_Full);
}
} else {
/* Report forced settings */
reg = mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
MDIO_CTRL1);
- ecmd->speed = (((reg & MDIO_PMA_CTRL1_SPEED1000) ? 100 : 1) *
- ((reg & MDIO_PMA_CTRL1_SPEED100) ? 100 : 10));
+ speed = (((reg & MDIO_PMA_CTRL1_SPEED1000) ? 100 : 1)
+ * ((reg & MDIO_PMA_CTRL1_SPEED100) ? 100 : 10));
ecmd->duplex = (reg & MDIO_CTRL1_FULLDPLX ||
- ecmd->speed == SPEED_10000);
+ speed == SPEED_10000);
}
+ ethtool_cmd_speed_set(ecmd, speed);
+
/* 10GBASE-T MDI/MDI-X */
- if (ecmd->port == PORT_TP && ecmd->speed == SPEED_10000) {
+ if (ecmd->port == PORT_TP
+ && (ethtool_cmd_speed(ecmd) == SPEED_10000)) {
switch (mdio->mdio_read(mdio->dev, mdio->prtad, MDIO_MMD_PMAPMD,
MDIO_PMA_10GBT_SWAPPOL)) {
case MDIO_PMA_10GBT_SWAPPOL_ABNX | MDIO_PMA_10GBT_SWAPPOL_CDNX:
diff --git a/drivers/net/mii.c b/drivers/net/mii.c
index d4fc00b1ff93..c62e7816d548 100644
--- a/drivers/net/mii.c
+++ b/drivers/net/mii.c
@@ -62,6 +62,9 @@ static u32 mii_get_an(struct mii_if_info *mii, u16 addr)
* @mii: MII interface
* @ecmd: requested ethtool_cmd
*
+ * The @ecmd parameter is expected to have been cleared before calling
+ * mii_ethtool_gset().
+ *
* Returns 0 for success, negative on error.
*/
int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
@@ -122,22 +125,25 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
if (nego & (ADVERTISED_1000baseT_Full |
ADVERTISED_1000baseT_Half)) {
- ecmd->speed = SPEED_1000;
+ ethtool_cmd_speed_set(ecmd, SPEED_1000);
ecmd->duplex = !!(nego & ADVERTISED_1000baseT_Full);
} else if (nego & (ADVERTISED_100baseT_Full |
ADVERTISED_100baseT_Half)) {
- ecmd->speed = SPEED_100;
+ ethtool_cmd_speed_set(ecmd, SPEED_100);
ecmd->duplex = !!(nego & ADVERTISED_100baseT_Full);
} else {
- ecmd->speed = SPEED_10;
+ ethtool_cmd_speed_set(ecmd, SPEED_10);
ecmd->duplex = !!(nego & ADVERTISED_10baseT_Full);
}
} else {
ecmd->autoneg = AUTONEG_DISABLE;
- ecmd->speed = ((bmcr & BMCR_SPEED1000 &&
- (bmcr & BMCR_SPEED100) == 0) ? SPEED_1000 :
- (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10);
+ ethtool_cmd_speed_set(ecmd,
+ ((bmcr & BMCR_SPEED1000 &&
+ (bmcr & BMCR_SPEED100) == 0) ?
+ SPEED_1000 :
+ ((bmcr & BMCR_SPEED100) ?
+ SPEED_100 : SPEED_10)));
ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
}
@@ -158,10 +164,11 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
{
struct net_device *dev = mii->dev;
+ u32 speed = ethtool_cmd_speed(ecmd);
- if (ecmd->speed != SPEED_10 &&
- ecmd->speed != SPEED_100 &&
- ecmd->speed != SPEED_1000)
+ if (speed != SPEED_10 &&
+ speed != SPEED_100 &&
+ speed != SPEED_1000)
return -EINVAL;
if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
return -EINVAL;
@@ -173,7 +180,7 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
return -EINVAL;
if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
return -EINVAL;
- if ((ecmd->speed == SPEED_1000) && (!mii->supports_gmii))
+ if ((speed == SPEED_1000) && (!mii->supports_gmii))
return -EINVAL;
/* ignore supported, maxtxpkt, maxrxpkt */
@@ -231,9 +238,9 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
BMCR_SPEED1000 | BMCR_FULLDPLX);
- if (ecmd->speed == SPEED_1000)
+ if (speed == SPEED_1000)
tmp |= BMCR_SPEED1000;
- else if (ecmd->speed == SPEED_100)
+ else if (speed == SPEED_100)
tmp |= BMCR_SPEED100;
if (ecmd->duplex == DUPLEX_FULL) {
tmp |= BMCR_FULLDPLX;
diff --git a/drivers/net/mlx4/en_ethtool.c b/drivers/net/mlx4/en_ethtool.c
index d54b7abf0225..2e858e4dcf4d 100644
--- a/drivers/net/mlx4/en_ethtool.c
+++ b/drivers/net/mlx4/en_ethtool.c
@@ -57,37 +57,6 @@ mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
drvinfo->eedump_len = 0;
}
-static u32 mlx4_en_get_tso(struct net_device *dev)
-{
- return (dev->features & NETIF_F_TSO) != 0;
-}
-
-static int mlx4_en_set_tso(struct net_device *dev, u32 data)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
-
- if (data) {
- if (!priv->mdev->LSO_support)
- return -EPERM;
- dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
- } else
- dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
- return 0;
-}
-
-static u32 mlx4_en_get_rx_csum(struct net_device *dev)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
- return priv->rx_csum;
-}
-
-static int mlx4_en_set_rx_csum(struct net_device *dev, u32 data)
-{
- struct mlx4_en_priv *priv = netdev_priv(dev);
- priv->rx_csum = (data != 0);
- return 0;
-}
-
static const char main_strings[][ETH_GSTRING_LEN] = {
"rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
"tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
@@ -296,10 +265,10 @@ static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
trans_type = priv->port_state.transciver;
if (netif_carrier_ok(dev)) {
- cmd->speed = priv->port_state.link_speed;
+ ethtool_cmd_speed_set(cmd, priv->port_state.link_speed);
cmd->duplex = DUPLEX_FULL;
} else {
- cmd->speed = -1;
+ ethtool_cmd_speed_set(cmd, -1);
cmd->duplex = -1;
}
@@ -323,7 +292,8 @@ static int mlx4_en_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
static int mlx4_en_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
if ((cmd->autoneg == AUTONEG_ENABLE) ||
- (cmd->speed != SPEED_10000) || (cmd->duplex != DUPLEX_FULL))
+ (ethtool_cmd_speed(cmd) != SPEED_10000) ||
+ (cmd->duplex != DUPLEX_FULL))
return -EINVAL;
/* Nothing to change */
@@ -483,17 +453,7 @@ const struct ethtool_ops mlx4_en_ethtool_ops = {
.get_drvinfo = mlx4_en_get_drvinfo,
.get_settings = mlx4_en_get_settings,
.set_settings = mlx4_en_set_settings,
-#ifdef NETIF_F_TSO
- .get_tso = mlx4_en_get_tso,
- .set_tso = mlx4_en_set_tso,
-#endif
- .get_sg = ethtool_op_get_sg,
- .set_sg = ethtool_op_set_sg,
.get_link = ethtool_op_get_link,
- .get_rx_csum = mlx4_en_get_rx_csum,
- .set_rx_csum = mlx4_en_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = ethtool_op_set_tx_ipv6_csum,
.get_strings = mlx4_en_get_strings,
.get_sset_count = mlx4_en_get_sset_count,
.get_ethtool_stats = mlx4_en_get_ethtool_stats,
@@ -508,7 +468,6 @@ const struct ethtool_ops mlx4_en_ethtool_ops = {
.set_pauseparam = mlx4_en_set_pauseparam,
.get_ringparam = mlx4_en_get_ringparam,
.set_ringparam = mlx4_en_set_ringparam,
- .get_flags = ethtool_op_get_flags,
};
diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c
index 77063f91c564..61850adae6f7 100644
--- a/drivers/net/mlx4/en_netdev.c
+++ b/drivers/net/mlx4/en_netdev.c
@@ -1083,7 +1083,6 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
priv->prof = prof;
priv->port = port;
priv->port_up = false;
- priv->rx_csum = 1;
priv->flags = prof->flags;
priv->tx_ring_num = prof->tx_ring_num;
priv->rx_ring_num = prof->rx_ring_num;
@@ -1141,21 +1140,16 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
/*
* Set driver features
*/
- dev->features |= NETIF_F_SG;
- dev->vlan_features |= NETIF_F_SG;
- dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
- dev->vlan_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
- dev->features |= NETIF_F_HIGHDMA;
- dev->features |= NETIF_F_HW_VLAN_TX |
- NETIF_F_HW_VLAN_RX |
- NETIF_F_HW_VLAN_FILTER;
- dev->features |= NETIF_F_GRO;
- if (mdev->LSO_support) {
- dev->features |= NETIF_F_TSO;
- dev->features |= NETIF_F_TSO6;
- dev->vlan_features |= NETIF_F_TSO;
- dev->vlan_features |= NETIF_F_TSO6;
- }
+ dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+ if (mdev->LSO_support)
+ dev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6;
+
+ dev->vlan_features = dev->hw_features;
+
+ dev->hw_features |= NETIF_F_RXCSUM;
+ dev->features = dev->hw_features | NETIF_F_HIGHDMA |
+ NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
+ NETIF_F_HW_VLAN_FILTER;
mdev->pndev[port] = dev;
diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c
index 62dd21b06df4..277215fb9d72 100644
--- a/drivers/net/mlx4/en_rx.c
+++ b/drivers/net/mlx4/en_rx.c
@@ -584,7 +584,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
ring->bytes += length;
ring->packets++;
- if (likely(priv->rx_csum)) {
+ if (likely(dev->features & NETIF_F_RXCSUM)) {
if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) &&
(cqe->checksum == cpu_to_be16(0xffff))) {
priv->port_stats.rx_chksum_good++;
diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h
index e30f6099c0de..0b5150df0585 100644
--- a/drivers/net/mlx4/mlx4_en.h
+++ b/drivers/net/mlx4/mlx4_en.h
@@ -451,7 +451,6 @@ struct mlx4_en_priv {
int registered;
int allocated;
int stride;
- int rx_csum;
u64 mac;
int mac_index;
unsigned max_mtu;
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index 34425b94452f..a5d9b1c310b3 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -1444,13 +1444,13 @@ mv643xx_eth_get_settings_phyless(struct mv643xx_eth_private *mp,
cmd->advertising = ADVERTISED_MII;
switch (port_status & PORT_SPEED_MASK) {
case PORT_SPEED_10:
- cmd->speed = SPEED_10;
+ ethtool_cmd_speed_set(cmd, SPEED_10);
break;
case PORT_SPEED_100:
- cmd->speed = SPEED_100;
+ ethtool_cmd_speed_set(cmd, SPEED_100);
break;
case PORT_SPEED_1000:
- cmd->speed = SPEED_1000;
+ ethtool_cmd_speed_set(cmd, SPEED_1000);
break;
default:
cmd->speed = -1;
@@ -1575,18 +1575,12 @@ mv643xx_eth_set_ringparam(struct net_device *dev, struct ethtool_ringparam *er)
return 0;
}
-static u32
-mv643xx_eth_get_rx_csum(struct net_device *dev)
-{
- struct mv643xx_eth_private *mp = netdev_priv(dev);
-
- return !!(rdlp(mp, PORT_CONFIG) & 0x02000000);
-}
static int
-mv643xx_eth_set_rx_csum(struct net_device *dev, u32 rx_csum)
+mv643xx_eth_set_features(struct net_device *dev, u32 features)
{
struct mv643xx_eth_private *mp = netdev_priv(dev);
+ u32 rx_csum = features & NETIF_F_RXCSUM;
wrlp(mp, PORT_CONFIG, rx_csum ? 0x02000000 : 0x00000000);
@@ -1634,11 +1628,6 @@ 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)
@@ -1657,14 +1646,8 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops = {
.set_coalesce = mv643xx_eth_set_coalesce,
.get_ringparam = mv643xx_eth_get_ringparam,
.set_ringparam = mv643xx_eth_set_ringparam,
- .get_rx_csum = mv643xx_eth_get_rx_csum,
- .set_rx_csum = mv643xx_eth_set_rx_csum,
- .set_tx_csum = ethtool_op_set_tx_csum,
- .set_sg = ethtool_op_set_sg,
.get_strings = mv643xx_eth_get_strings,
.get_ethtool_stats = mv643xx_eth_get_ethtool_stats,
- .get_flags = ethtool_op_get_flags,
- .set_flags = mv643xx_eth_set_flags,
.get_sset_count = mv643xx_eth_get_sset_count,
};
@@ -2264,7 +2247,7 @@ static void port_start(struct mv643xx_eth_private *mp)
* frames to RX queue #0, and include the pseudo-header when
* calculating receive checksums.
*/
- wrlp(mp, PORT_CONFIG, 0x02000000);
+ mv643xx_eth_set_features(mp->dev, mp->dev->features);
/*
* Treat BPDUs as normal multicasts, and disable partition mode.
@@ -2848,6 +2831,7 @@ static const struct net_device_ops mv643xx_eth_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = mv643xx_eth_ioctl,
.ndo_change_mtu = mv643xx_eth_change_mtu,
+ .ndo_set_features = mv643xx_eth_set_features,
.ndo_tx_timeout = mv643xx_eth_tx_timeout,
.ndo_get_stats = mv643xx_eth_get_stats,
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -2930,7 +2914,9 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
dev->watchdog_timeo = 2 * HZ;
dev->base_addr = 0;
- dev->features = NETIF_F_SG | NETIF_F_IP_CSUM;
+ dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM |
+ NETIF_F_RXCSUM | NETIF_F_LRO;
+ dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM;
SET_NETDEV_DEV(dev, &pdev->dev);
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 1446de59ae53..bf84849600ce 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -65,6 +65,7 @@
#include <linux/io.h>
#include <linux/log2.h>
#include <linux/slab.h>
+#include <linux/prefetch.h>
#include <net/checksum.h>
#include <net/ip.h>
#include <net/tcp.h>
@@ -205,7 +206,6 @@ struct myri10ge_priv {
int tx_boundary; /* boundary transmits cannot cross */
int num_slices;
int running; /* running? */
- int csum_flag; /* rx_csums? */
int small_bytes;
int big_bytes;
int max_intr_slots;
@@ -1386,7 +1386,7 @@ myri10ge_rx_done(struct myri10ge_slice_state *ss, int len, __wsum csum,
skb->protocol = eth_type_trans(skb, dev);
skb_record_rx_queue(skb, ss - &mgp->ss[0]);
- if (mgp->csum_flag) {
+ if (dev->features & NETIF_F_RXCSUM) {
if ((skb->protocol == htons(ETH_P_IP)) ||
(skb->protocol == htons(ETH_P_IPV6))) {
skb->csum = csum;
@@ -1645,7 +1645,7 @@ myri10ge_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
int i;
cmd->autoneg = AUTONEG_DISABLE;
- cmd->speed = SPEED_10000;
+ ethtool_cmd_speed_set(cmd, SPEED_10000);
cmd->duplex = DUPLEX_FULL;
/*
@@ -1757,43 +1757,6 @@ myri10ge_get_ringparam(struct net_device *netdev,
ring->tx_pending = ring->tx_max_pending;
}
-static u32 myri10ge_get_rx_csum(struct net_device *netdev)
-{
- struct myri10ge_priv *mgp = netdev_priv(netdev);
-
- if (mgp->csum_flag)
- return 1;
- else
- return 0;
-}
-
-static int myri10ge_set_rx_csum(struct net_device *netdev, u32 csum_enabled)
-{
- struct myri10ge_priv *mgp = netdev_priv(netdev);
- int err = 0;
-
- if (csum_enabled)
- mgp->csum_flag = MXGEFW_FLAGS_CKSUM;
- else {
- netdev->features &= ~NETIF_F_LRO;
- mgp->csum_flag = 0;
-
- }
- return err;
-}
-
-static int myri10ge_set_tso(struct net_device *netdev, u32 tso_enabled)
-{
- struct myri10ge_priv *mgp = netdev_priv(netdev);
- u32 flags = mgp->features & (NETIF_F_TSO6 | NETIF_F_TSO);
-
- if (tso_enabled)
- netdev->features |= flags;
- else
- netdev->features &= ~flags;
- return 0;
-}
-
static const char myri10ge_gstrings_main_stats[][ETH_GSTRING_LEN] = {
"rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
"tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
@@ -1944,11 +1907,6 @@ 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,
@@ -1957,19 +1915,12 @@ static const struct ethtool_ops myri10ge_ethtool_ops = {
.get_pauseparam = myri10ge_get_pauseparam,
.set_pauseparam = myri10ge_set_pauseparam,
.get_ringparam = myri10ge_get_ringparam,
- .get_rx_csum = myri10ge_get_rx_csum,
- .set_rx_csum = myri10ge_set_rx_csum,
- .set_tx_csum = ethtool_op_set_tx_hw_csum,
- .set_sg = ethtool_op_set_sg,
- .set_tso = myri10ge_set_tso,
.get_link = ethtool_op_get_link,
.get_strings = myri10ge_get_strings,
.get_sset_count = myri10ge_get_sset_count,
.get_ethtool_stats = myri10ge_get_ethtool_stats,
.set_msglevel = myri10ge_set_msglevel,
.get_msglevel = myri10ge_get_msglevel,
- .get_flags = ethtool_op_get_flags,
- .set_flags = myri10ge_set_flags
};
static int myri10ge_allocate_rings(struct myri10ge_slice_state *ss)
@@ -3136,6 +3087,14 @@ static int myri10ge_set_mac_address(struct net_device *dev, void *addr)
return 0;
}
+static u32 myri10ge_fix_features(struct net_device *dev, u32 features)
+{
+ if (!(features & NETIF_F_RXCSUM))
+ features &= ~NETIF_F_LRO;
+
+ return features;
+}
+
static int myri10ge_change_mtu(struct net_device *dev, int new_mtu)
{
struct myri10ge_priv *mgp = netdev_priv(dev);
@@ -3834,6 +3793,7 @@ static const struct net_device_ops myri10ge_netdev_ops = {
.ndo_get_stats = myri10ge_get_stats,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = myri10ge_change_mtu,
+ .ndo_fix_features = myri10ge_fix_features,
.ndo_set_multicast_list = myri10ge_set_multicast_list,
.ndo_set_mac_address = myri10ge_set_mac_address,
};
@@ -3860,7 +3820,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
mgp = netdev_priv(netdev);
mgp->dev = netdev;
mgp->pdev = pdev;
- mgp->csum_flag = MXGEFW_FLAGS_CKSUM;
mgp->pause = myri10ge_flow_control;
mgp->intr_coal_delay = myri10ge_intr_coal_delay;
mgp->msg_enable = netif_msg_init(myri10ge_debug, MYRI10GE_MSG_DEFAULT);
@@ -3976,11 +3935,11 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netdev->netdev_ops = &myri10ge_netdev_ops;
netdev->mtu = myri10ge_initial_mtu;
netdev->base_addr = mgp->iomem_base;
- netdev->features = mgp->features;
+ netdev->hw_features = mgp->features | NETIF_F_LRO | NETIF_F_RXCSUM;
+ netdev->features = netdev->hw_features;
if (dac_enabled)
netdev->features |= NETIF_F_HIGHDMA;
- netdev->features |= NETIF_F_LRO;
netdev->vlan_features |= mgp->features;
if (mgp->fw_ver_tiny < 37)
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 1074231f0a0d..b78be088c4ad 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -2820,7 +2820,7 @@ static int netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
u32 tmp;
ecmd->port = dev->if_port;
- ecmd->speed = np->speed;
+ ethtool_cmd_speed_set(ecmd, np->speed);
ecmd->duplex = np->duplex;
ecmd->autoneg = np->autoneg;
ecmd->advertising = 0;
@@ -2878,9 +2878,9 @@ static int netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
tmp = mii_nway_result(
np->advertising & mdio_read(dev, MII_LPA));
if (tmp == LPA_100FULL || tmp == LPA_100HALF)
- ecmd->speed = SPEED_100;
+ ethtool_cmd_speed_set(ecmd, SPEED_100);
else
- ecmd->speed = SPEED_10;
+ ethtool_cmd_speed_set(ecmd, SPEED_10);
if (tmp == LPA_100FULL || tmp == LPA_10FULL)
ecmd->duplex = DUPLEX_FULL;
else
@@ -2908,7 +2908,8 @@ static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
return -EINVAL;
}
} else if (ecmd->autoneg == AUTONEG_DISABLE) {
- if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100)
+ u32 speed = ethtool_cmd_speed(ecmd);
+ if (speed != SPEED_10 && speed != SPEED_100)
return -EINVAL;
if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
return -EINVAL;
@@ -2956,7 +2957,7 @@ static int netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
if (ecmd->advertising & ADVERTISED_100baseT_Full)
np->advertising |= ADVERTISE_100FULL;
} else {
- np->speed = ecmd->speed;
+ np->speed = ethtool_cmd_speed(ecmd);
np->duplex = ecmd->duplex;
/* user overriding the initial full duplex parm? */
if (np->duplex == DUPLEX_HALF)
diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c
index 243ed2aee88e..e8984b0ca521 100644
--- a/drivers/net/ne3210.c
+++ b/drivers/net/ne3210.c
@@ -80,17 +80,20 @@ static void ne3210_block_output(struct net_device *dev, int count, const unsigne
#define NE3210_DEBUG 0x0
-static unsigned char irq_map[] __initdata = {15, 12, 11, 10, 9, 7, 5, 3};
-static unsigned int shmem_map[] __initdata = {0xff0, 0xfe0, 0xfff0, 0xd8, 0xffe0, 0xffc0, 0xd0, 0x0};
-static const char *ifmap[] __initdata = {"UTP", "?", "BNC", "AUI"};
-static int ifmap_val[] __initdata = {
+static const unsigned char irq_map[] __devinitconst =
+ { 15, 12, 11, 10, 9, 7, 5, 3 };
+static const unsigned int shmem_map[] __devinitconst =
+ { 0xff0, 0xfe0, 0xfff0, 0xd8, 0xffe0, 0xffc0, 0xd0, 0x0 };
+static const char *const ifmap[] __devinitconst =
+ { "UTP", "?", "BNC", "AUI" };
+static const int ifmap_val[] __devinitconst = {
IF_PORT_10BASET,
IF_PORT_UNKNOWN,
IF_PORT_10BASE2,
IF_PORT_AUI,
};
-static int __init ne3210_eisa_probe (struct device *device)
+static int __devinit ne3210_eisa_probe (struct device *device)
{
unsigned long ioaddr, phys_mem;
int i, retval, port_index;
@@ -313,7 +316,7 @@ static void ne3210_block_output(struct net_device *dev, int count,
memcpy_toio(shmem, buf, count);
}
-static struct eisa_device_id ne3210_ids[] = {
+static const struct eisa_device_id ne3210_ids[] __devinitconst = {
{ "EGL0101" },
{ "NVL1801" },
{ "" },
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index eb41e44921e6..dfc82720065a 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -242,34 +242,6 @@ static struct netconsole_target *to_target(struct config_item *item)
}
/*
- * Wrapper over simple_strtol (base 10) with sanity and range checking.
- * We return (signed) long only because we may want to return errors.
- * Do not use this to convert numbers that are allowed to be negative.
- */
-static long strtol10_check_range(const char *cp, long min, long max)
-{
- long ret;
- char *p = (char *) cp;
-
- WARN_ON(min < 0);
- WARN_ON(max < min);
-
- ret = simple_strtol(p, &p, 10);
-
- if (*p && (*p != '\n')) {
- printk(KERN_ERR "netconsole: invalid input\n");
- return -EINVAL;
- }
- if ((ret < min) || (ret > max)) {
- printk(KERN_ERR "netconsole: input %ld must be between "
- "%ld and %ld\n", ret, min, max);
- return -EINVAL;
- }
-
- return ret;
-}
-
-/*
* Attribute operations for netconsole_target.
*/
@@ -327,12 +299,14 @@ static ssize_t store_enabled(struct netconsole_target *nt,
const char *buf,
size_t count)
{
+ int enabled;
int err;
- long enabled;
- enabled = strtol10_check_range(buf, 0, 1);
- if (enabled < 0)
- return enabled;
+ err = kstrtoint(buf, 10, &enabled);
+ if (err < 0)
+ return err;
+ if (enabled < 0 || enabled > 1)
+ return -EINVAL;
if (enabled) { /* 1 */
@@ -384,8 +358,7 @@ static ssize_t store_local_port(struct netconsole_target *nt,
const char *buf,
size_t count)
{
- long local_port;
-#define __U16_MAX ((__u16) ~0U)
+ int rv;
if (nt->enabled) {
printk(KERN_ERR "netconsole: target (%s) is enabled, "
@@ -394,12 +367,9 @@ static ssize_t store_local_port(struct netconsole_target *nt,
return -EINVAL;
}
- local_port = strtol10_check_range(buf, 0, __U16_MAX);
- if (local_port < 0)
- return local_port;
-
- nt->np.local_port = local_port;
-
+ rv = kstrtou16(buf, 10, &nt->np.local_port);
+ if (rv < 0)
+ return rv;
return strnlen(buf, count);
}
@@ -407,8 +377,7 @@ static ssize_t store_remote_port(struct netconsole_target *nt,
const char *buf,
size_t count)
{
- long remote_port;
-#define __U16_MAX ((__u16) ~0U)
+ int rv;
if (nt->enabled) {
printk(KERN_ERR "netconsole: target (%s) is enabled, "
@@ -417,12 +386,9 @@ static ssize_t store_remote_port(struct netconsole_target *nt,
return -EINVAL;
}
- remote_port = strtol10_check_range(buf, 0, __U16_MAX);
- if (remote_port < 0)
- return remote_port;
-
- nt->np.remote_port = remote_port;
-
+ rv = kstrtou16(buf, 10, &nt->np.remote_port);
+ if (rv < 0)
+ return rv;
return strnlen(buf, count);
}
@@ -463,8 +429,6 @@ static ssize_t store_remote_mac(struct netconsole_target *nt,
size_t count)
{
u8 remote_mac[ETH_ALEN];
- char *p = (char *) buf;
- int i;
if (nt->enabled) {
printk(KERN_ERR "netconsole: target (%s) is enabled, "
@@ -473,23 +437,13 @@ static ssize_t store_remote_mac(struct netconsole_target *nt,
return -EINVAL;
}
- for (i = 0; i < ETH_ALEN - 1; i++) {
- remote_mac[i] = simple_strtoul(p, &p, 16);
- if (*p != ':')
- goto invalid;
- p++;
- }
- remote_mac[ETH_ALEN - 1] = simple_strtoul(p, &p, 16);
- if (*p && (*p != '\n'))
- goto invalid;
-
+ if (!mac_pton(buf, remote_mac))
+ return -EINVAL;
+ if (buf[3 * ETH_ALEN - 1] && buf[3 * ETH_ALEN - 1] != '\n')
+ return -EINVAL;
memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN);
return strnlen(buf, count);
-
-invalid:
- printk(KERN_ERR "netconsole: invalid input\n");
- return -EINVAL;
}
/*
@@ -667,11 +621,10 @@ static int netconsole_netdev_event(struct notifier_block *this,
bool stopped = false;
if (!(event == NETDEV_CHANGENAME || event == NETDEV_UNREGISTER ||
- event == NETDEV_BONDING_DESLAVE || event == NETDEV_GOING_DOWN))
+ event == NETDEV_RELEASE || event == NETDEV_JOIN))
goto done;
spin_lock_irqsave(&target_list_lock, flags);
-restart:
list_for_each_entry(nt, &target_list, list) {
netconsole_target_get(nt);
if (nt->np.dev == dev) {
@@ -679,6 +632,8 @@ restart:
case NETDEV_CHANGENAME:
strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ);
break;
+ case NETDEV_RELEASE:
+ case NETDEV_JOIN:
case NETDEV_UNREGISTER:
/*
* rtnl_lock already held
@@ -693,11 +648,7 @@ restart:
dev_put(nt->np.dev);
nt->np.dev = NULL;
netconsole_target_put(nt);
- goto restart;
}
- /* Fall through */
- case NETDEV_GOING_DOWN:
- case NETDEV_BONDING_DESLAVE:
nt->enabled = 0;
stopped = true;
break;
@@ -706,10 +657,21 @@ restart:
netconsole_target_put(nt);
}
spin_unlock_irqrestore(&target_list_lock, flags);
- if (stopped && (event == NETDEV_UNREGISTER || event == NETDEV_BONDING_DESLAVE))
+ if (stopped) {
printk(KERN_INFO "netconsole: network logging stopped on "
- "interface %s as it %s\n", dev->name,
- event == NETDEV_UNREGISTER ? "unregistered" : "released slaves");
+ "interface %s as it ", dev->name);
+ switch (event) {
+ case NETDEV_UNREGISTER:
+ printk(KERN_CONT "unregistered\n");
+ break;
+ case NETDEV_RELEASE:
+ printk(KERN_CONT "released slaves\n");
+ break;
+ case NETDEV_JOIN:
+ printk(KERN_CONT "is joining a master device\n");
+ break;
+ }
+ }
done:
return NOTIFY_DONE;
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index 679dc8519c5b..77220687b92a 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -1177,7 +1177,7 @@ struct netxen_adapter {
u8 max_sds_rings;
u8 driver_mismatch;
u8 msix_supported;
- u8 rx_csum;
+ u8 __pad;
u8 pci_using_dac;
u8 portnum;
u8 physical_port;
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index 3bdcc803ec68..b34fb74d07e3 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -117,7 +117,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
ecmd->port = PORT_TP;
- ecmd->speed = adapter->link_speed;
+ ethtool_cmd_speed_set(ecmd, adapter->link_speed);
ecmd->duplex = adapter->link_duplex;
ecmd->autoneg = adapter->link_autoneg;
@@ -134,7 +134,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
}
if (netif_running(dev) && adapter->has_link_events) {
- ecmd->speed = adapter->link_speed;
+ ethtool_cmd_speed_set(ecmd, adapter->link_speed);
ecmd->autoneg = adapter->link_autoneg;
ecmd->duplex = adapter->link_duplex;
goto skip;
@@ -146,10 +146,10 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
u16 pcifn = adapter->ahw.pci_func;
val = NXRD32(adapter, P3_LINK_SPEED_REG(pcifn));
- ecmd->speed = P3_LINK_SPEED_MHZ *
- P3_LINK_SPEED_VAL(pcifn, val);
+ ethtool_cmd_speed_set(ecmd, P3_LINK_SPEED_MHZ *
+ P3_LINK_SPEED_VAL(pcifn, val));
} else
- ecmd->speed = SPEED_10000;
+ ethtool_cmd_speed_set(ecmd, SPEED_10000);
ecmd->duplex = DUPLEX_FULL;
ecmd->autoneg = AUTONEG_DISABLE;
@@ -251,6 +251,7 @@ static int
netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
{
struct netxen_adapter *adapter = netdev_priv(dev);
+ u32 speed = ethtool_cmd_speed(ecmd);
int ret;
if (adapter->ahw.port_type != NETXEN_NIC_GBE)
@@ -259,14 +260,14 @@ netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
if (!(adapter->capabilities & NX_FW_CAPABILITY_GBE_LINK_CFG))
return -EOPNOTSUPP;
- ret = nx_fw_cmd_set_gbe_port(adapter, ecmd->speed, ecmd->duplex,
+ ret = nx_fw_cmd_set_gbe_port(adapter, speed, ecmd->duplex,
ecmd->autoneg);
if (ret == NX_RCODE_NOT_SUPPORTED)
return -EOPNOTSUPP;
else if (ret)
return -EIO;
- adapter->link_speed = ecmd->speed;
+ adapter->link_speed = speed;
adapter->link_duplex = ecmd->duplex;
adapter->link_autoneg = ecmd->autoneg;
@@ -676,62 +677,6 @@ netxen_nic_get_ethtool_stats(struct net_device *dev,
}
}
-static u32 netxen_nic_get_tx_csum(struct net_device *dev)
-{
- return dev->features & NETIF_F_IP_CSUM;
-}
-
-static u32 netxen_nic_get_rx_csum(struct net_device *dev)
-{
- struct netxen_adapter *adapter = netdev_priv(dev);
- return adapter->rx_csum;
-}
-
-static int netxen_nic_set_rx_csum(struct net_device *dev, u32 data)
-{
- struct netxen_adapter *adapter = netdev_priv(dev);
-
- if (data) {
- adapter->rx_csum = data;
- return 0;
- }
-
- if (dev->features & NETIF_F_LRO) {
- if (netxen_config_hw_lro(adapter, NETXEN_NIC_LRO_DISABLED))
- return -EIO;
-
- dev->features &= ~NETIF_F_LRO;
- netxen_send_lro_cleanup(adapter);
- netdev_info(dev, "disabling LRO as rx_csum is off\n");
- }
- adapter->rx_csum = data;
- return 0;
-}
-
-static u32 netxen_nic_get_tso(struct net_device *dev)
-{
- struct netxen_adapter *adapter = netdev_priv(dev);
-
- if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
- return (dev->features & (NETIF_F_TSO | NETIF_F_TSO6)) != 0;
-
- return (dev->features & NETIF_F_TSO) != 0;
-}
-
-static int netxen_nic_set_tso(struct net_device *dev, u32 data)
-{
- if (data) {
- struct netxen_adapter *adapter = netdev_priv(dev);
-
- dev->features |= NETIF_F_TSO;
- if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
- dev->features |= NETIF_F_TSO6;
- } else
- dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
-
- return 0;
-}
-
static void
netxen_nic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
@@ -866,43 +811,6 @@ static int netxen_get_intr_coalesce(struct net_device *netdev,
return 0;
}
-static int netxen_nic_set_flags(struct net_device *netdev, u32 data)
-{
- struct netxen_adapter *adapter = netdev_priv(netdev);
- int hw_lro;
-
- if (ethtool_invalid_flags(netdev, data, ETH_FLAG_LRO))
- return -EINVAL;
-
- if (!(adapter->capabilities & NX_FW_CAPABILITY_HW_LRO))
- return -EINVAL;
-
- if (!adapter->rx_csum) {
- netdev_info(netdev, "rx csum is off, cannot toggle LRO\n");
- return -EINVAL;
- }
-
- if (!!(data & ETH_FLAG_LRO) == !!(netdev->features & NETIF_F_LRO))
- return 0;
-
- if (data & ETH_FLAG_LRO) {
- hw_lro = NETXEN_NIC_LRO_ENABLED;
- netdev->features |= NETIF_F_LRO;
- } else {
- hw_lro = NETXEN_NIC_LRO_DISABLED;
- netdev->features &= ~NETIF_F_LRO;
- }
-
- if (netxen_config_hw_lro(adapter, hw_lro))
- return -EIO;
-
- if ((hw_lro == 0) && netxen_send_lro_cleanup(adapter))
- return -EIO;
-
-
- return 0;
-}
-
const struct ethtool_ops netxen_nic_ethtool_ops = {
.get_settings = netxen_nic_get_settings,
.set_settings = netxen_nic_set_settings,
@@ -916,21 +824,12 @@ const struct ethtool_ops netxen_nic_ethtool_ops = {
.set_ringparam = netxen_nic_set_ringparam,
.get_pauseparam = netxen_nic_get_pauseparam,
.set_pauseparam = netxen_nic_set_pauseparam,
- .get_tx_csum = netxen_nic_get_tx_csum,
- .set_tx_csum = ethtool_op_set_tx_csum,
- .set_sg = ethtool_op_set_sg,
- .get_tso = netxen_nic_get_tso,
- .set_tso = netxen_nic_set_tso,
.get_wol = netxen_nic_get_wol,
.set_wol = netxen_nic_set_wol,
.self_test = netxen_nic_diag_test,
.get_strings = netxen_nic_get_strings,
.get_ethtool_stats = netxen_nic_get_ethtool_stats,
.get_sset_count = netxen_get_sset_count,
- .get_rx_csum = netxen_nic_get_rx_csum,
- .set_rx_csum = netxen_nic_set_rx_csum,
.get_coalesce = netxen_get_intr_coalesce,
.set_coalesce = netxen_set_intr_coalesce,
- .get_flags = ethtool_op_get_flags,
- .set_flags = netxen_nic_set_flags,
};
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index 731077d8d962..7f999671c7b2 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -1483,7 +1483,8 @@ static struct sk_buff *netxen_process_rxbuf(struct netxen_adapter *adapter,
if (!skb)
goto no_skb;
- if (likely(adapter->rx_csum && cksum == STATUS_CKSUM_OK)) {
+ if (likely((adapter->netdev->features & NETIF_F_RXCSUM)
+ && cksum == STATUS_CKSUM_OK)) {
adapter->stats.csummed++;
skb->ip_summed = CHECKSUM_UNNECESSARY;
} else
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index e8a4b6655999..b644383017f9 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -485,6 +485,37 @@ static void netxen_set_multicast_list(struct net_device *dev)
adapter->set_multi(dev);
}
+static u32 netxen_fix_features(struct net_device *dev, u32 features)
+{
+ if (!(features & NETIF_F_RXCSUM)) {
+ netdev_info(dev, "disabling LRO as RXCSUM is off\n");
+
+ features &= ~NETIF_F_LRO;
+ }
+
+ return features;
+}
+
+static int netxen_set_features(struct net_device *dev, u32 features)
+{
+ struct netxen_adapter *adapter = netdev_priv(dev);
+ int hw_lro;
+
+ if (!((dev->features ^ features) & NETIF_F_LRO))
+ return 0;
+
+ hw_lro = (features & NETIF_F_LRO) ? NETXEN_NIC_LRO_ENABLED
+ : NETXEN_NIC_LRO_DISABLED;
+
+ if (netxen_config_hw_lro(adapter, hw_lro))
+ return -EIO;
+
+ if (!(features & NETIF_F_LRO) && netxen_send_lro_cleanup(adapter))
+ return -EIO;
+
+ return 0;
+}
+
static const struct net_device_ops netxen_netdev_ops = {
.ndo_open = netxen_nic_open,
.ndo_stop = netxen_nic_close,
@@ -495,6 +526,8 @@ static const struct net_device_ops netxen_netdev_ops = {
.ndo_set_mac_address = netxen_nic_set_mac,
.ndo_change_mtu = netxen_nic_change_mtu,
.ndo_tx_timeout = netxen_tx_timeout,
+ .ndo_fix_features = netxen_fix_features,
+ .ndo_set_features = netxen_set_features,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = netxen_nic_poll_controller,
#endif
@@ -905,7 +938,7 @@ netxen_nic_request_irq(struct netxen_adapter *adapter)
struct nx_host_sds_ring *sds_ring;
int err, ring;
- unsigned long flags = IRQF_SAMPLE_RANDOM;
+ unsigned long flags = 0;
struct net_device *netdev = adapter->netdev;
struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
@@ -1196,7 +1229,6 @@ netxen_setup_netdev(struct netxen_adapter *adapter,
int err = 0;
struct pci_dev *pdev = adapter->pdev;
- adapter->rx_csum = 1;
adapter->mc_enabled = 0;
if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
adapter->max_mc_count = 38;
@@ -1210,14 +1242,13 @@ netxen_setup_netdev(struct netxen_adapter *adapter,
SET_ETHTOOL_OPS(netdev, &netxen_nic_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->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
+ NETIF_F_RXCSUM;
- if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
- netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
- netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
- }
+ if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
+ netdev->hw_features |= NETIF_F_IPV6_CSUM | NETIF_F_TSO6;
+
+ netdev->vlan_features |= netdev->hw_features;
if (adapter->pci_using_dac) {
netdev->features |= NETIF_F_HIGHDMA;
@@ -1225,10 +1256,12 @@ netxen_setup_netdev(struct netxen_adapter *adapter,
}
if (adapter->capabilities & NX_FW_CAPABILITY_FVLANTX)
- netdev->features |= (NETIF_F_HW_VLAN_TX);
+ netdev->hw_features |= NETIF_F_HW_VLAN_TX;
if (adapter->capabilities & NX_FW_CAPABILITY_HW_LRO)
- netdev->features |= NETIF_F_LRO;
+ netdev->hw_features |= NETIF_F_LRO;
+
+ netdev->features |= netdev->hw_features;
netdev->irq = adapter->msix_entries[0].vector;
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index 32678b6c6b39..cc25bff0bd3b 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -1233,7 +1233,7 @@ static int link_status_1g_rgmii(struct niu *np, int *link_up_p)
bmsr = err;
if (bmsr & BMSR_LSTATUS) {
- u16 adv, lpa, common, estat;
+ u16 adv, lpa;
err = mii_read(np, np->phy_addr, MII_ADVERTISE);
if (err < 0)
@@ -1245,12 +1245,9 @@ static int link_status_1g_rgmii(struct niu *np, int *link_up_p)
goto out;
lpa = err;
- common = adv & lpa;
-
err = mii_read(np, np->phy_addr, MII_ESTATUS);
if (err < 0)
goto out;
- estat = err;
link_up = 1;
current_speed = SPEED_1000;
current_duplex = DUPLEX_FULL;
@@ -1650,7 +1647,7 @@ static int xcvr_init_10g(struct niu *np)
break;
}
- return 0;
+ return err;
}
static int mii_reset(struct niu *np)
@@ -2381,17 +2378,14 @@ static int serdes_init_10g_serdes(struct niu *np)
struct niu_link_config *lp = &np->link_config;
unsigned long ctrl_reg, test_cfg_reg, pll_cfg, i;
u64 ctrl_val, test_cfg_val, sig, mask, val;
- u64 reset_val;
switch (np->port) {
case 0:
- reset_val = ENET_SERDES_RESET_0;
ctrl_reg = ENET_SERDES_0_CTRL_CFG;
test_cfg_reg = ENET_SERDES_0_TEST_CFG;
pll_cfg = ENET_SERDES_0_PLL_CFG;
break;
case 1:
- reset_val = ENET_SERDES_RESET_1;
ctrl_reg = ENET_SERDES_1_CTRL_CFG;
test_cfg_reg = ENET_SERDES_1_TEST_CFG;
pll_cfg = ENET_SERDES_1_PLL_CFG;
@@ -6071,8 +6065,7 @@ static int niu_request_irq(struct niu *np)
for (i = 0; i < np->num_ldg; i++) {
struct niu_ldg *lp = &np->ldg[i];
- err = request_irq(lp->irq, niu_interrupt,
- IRQF_SHARED | IRQF_SAMPLE_RANDOM,
+ err = request_irq(lp->irq, niu_interrupt, IRQF_SHARED,
np->irq_name[i], lp);
if (err)
goto out_free_irqs;
@@ -6851,7 +6844,7 @@ static int niu_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->supported = lp->supported;
cmd->advertising = lp->active_advertising;
cmd->autoneg = lp->active_autoneg;
- cmd->speed = lp->active_speed;
+ ethtool_cmd_speed_set(cmd, lp->active_speed);
cmd->duplex = lp->active_duplex;
cmd->port = (np->flags & NIU_FLAGS_FIBER) ? PORT_FIBRE : PORT_TP;
cmd->transceiver = (np->flags & NIU_FLAGS_XCVR_SERDES) ?
@@ -6866,7 +6859,7 @@ static int niu_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
struct niu_link_config *lp = &np->link_config;
lp->advertising = cmd->advertising;
- lp->speed = cmd->speed;
+ lp->speed = ethtool_cmd_speed(cmd);
lp->duplex = cmd->duplex;
lp->autoneg = cmd->autoneg;
return niu_init_link(np);
@@ -7023,6 +7016,7 @@ static int niu_ethflow_to_class(int flow_type, u64 *class)
case UDP_V4_FLOW:
*class = CLASS_CODE_UDP_IPV4;
break;
+ case AH_ESP_V4_FLOW:
case AH_V4_FLOW:
case ESP_V4_FLOW:
*class = CLASS_CODE_AH_ESP_IPV4;
@@ -7036,6 +7030,7 @@ static int niu_ethflow_to_class(int flow_type, u64 *class)
case UDP_V6_FLOW:
*class = CLASS_CODE_UDP_IPV6;
break;
+ case AH_ESP_V6_FLOW:
case AH_V6_FLOW:
case ESP_V6_FLOW:
*class = CLASS_CODE_AH_ESP_IPV6;
@@ -7889,37 +7884,35 @@ static void niu_force_led(struct niu *np, int on)
nw64_mac(reg, val);
}
-static int niu_phys_id(struct net_device *dev, u32 data)
+static int niu_set_phys_id(struct net_device *dev,
+ enum ethtool_phys_id_state state)
+
{
struct niu *np = netdev_priv(dev);
- u64 orig_led_state;
- int i;
if (!netif_running(dev))
return -EAGAIN;
- if (data == 0)
- data = 2;
+ switch (state) {
+ case ETHTOOL_ID_ACTIVE:
+ np->orig_led_state = niu_led_state_save(np);
+ return 1; /* cycle on/off once per second */
- orig_led_state = niu_led_state_save(np);
- for (i = 0; i < (data * 2); i++) {
- int on = ((i % 2) == 0);
+ case ETHTOOL_ID_ON:
+ niu_force_led(np, 1);
+ break;
- niu_force_led(np, on);
+ case ETHTOOL_ID_OFF:
+ niu_force_led(np, 0);
+ break;
- if (msleep_interruptible(500))
- break;
+ case ETHTOOL_ID_INACTIVE:
+ niu_led_state_restore(np, np->orig_led_state);
}
- niu_led_state_restore(np, orig_led_state);
return 0;
}
-static int niu_set_flags(struct net_device *dev, u32 data)
-{
- return ethtool_op_set_flags(dev, data, ETH_FLAG_RXHASH);
-}
-
static const struct ethtool_ops niu_ethtool_ops = {
.get_drvinfo = niu_get_drvinfo,
.get_link = ethtool_op_get_link,
@@ -7933,11 +7926,9 @@ static const struct ethtool_ops niu_ethtool_ops = {
.get_strings = niu_get_strings,
.get_sset_count = niu_get_sset_count,
.get_ethtool_stats = niu_get_ethtool_stats,
- .phys_id = niu_phys_id,
+ .set_phys_id = niu_set_phys_id,
.get_rxnfc = niu_get_nfc,
.set_rxnfc = niu_set_nfc,
- .set_flags = niu_set_flags,
- .get_flags = ethtool_op_get_flags,
};
static int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent,
@@ -8131,7 +8122,7 @@ static int __devinit niu_pci_vpd_scan_props(struct niu *np,
netif_printk(np, probe, KERN_DEBUG, np->dev,
"VPD_SCAN: start[%x] end[%x]\n", start, end);
while (start < end) {
- int len, err, instance, type, prop_len;
+ int len, err, prop_len;
char namebuf[64];
u8 *prop_buf;
int max_len;
@@ -8147,8 +8138,6 @@ static int __devinit niu_pci_vpd_scan_props(struct niu *np,
len = err;
start += 3;
- instance = niu_pci_eeprom_read(np, start);
- type = niu_pci_eeprom_read(np, start + 3);
prop_len = niu_pci_eeprom_read(np, start + 4);
err = niu_pci_vpd_get_propname(np, start + 5, namebuf, 64);
if (err < 0)
@@ -9768,8 +9757,8 @@ static void __devinit niu_device_announce(struct niu *np)
static void __devinit niu_set_basic_features(struct net_device *dev)
{
- dev->features |= (NETIF_F_SG | NETIF_F_HW_CSUM |
- NETIF_F_GRO | NETIF_F_RXHASH);
+ dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXHASH;
+ dev->features |= dev->hw_features | NETIF_F_RXCSUM;
}
static int __devinit niu_pci_init_one(struct pci_dev *pdev,
diff --git a/drivers/net/niu.h b/drivers/net/niu.h
index a41fa8ebe05f..51e177e1860d 100644
--- a/drivers/net/niu.h
+++ b/drivers/net/niu.h
@@ -3279,6 +3279,7 @@ struct niu {
unsigned long xpcs_off;
struct timer_list timer;
+ u64 orig_led_state;
const struct niu_phy_ops *phy_ops;
int phy_addr;
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index 6667e0667a88..3e4040f2f3cb 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -1251,7 +1251,7 @@ static int ns83820_get_settings(struct net_device *ndev,
/*
* Here's the list of available ethtool commands from other drivers:
* cmd->advertising =
- * cmd->speed =
+ * ethtool_cmd_speed_set(cmd, ...)
* cmd->duplex =
* cmd->port = 0;
* cmd->phy_address =
@@ -1289,13 +1289,13 @@ static int ns83820_get_settings(struct net_device *ndev,
cmd->duplex = fullduplex ? DUPLEX_FULL : DUPLEX_HALF;
switch (cfg / CFG_SPDSTS0 & 3) {
case 2:
- cmd->speed = SPEED_1000;
+ ethtool_cmd_speed_set(cmd, SPEED_1000);
break;
case 1:
- cmd->speed = SPEED_100;
+ ethtool_cmd_speed_set(cmd, SPEED_100);
break;
default:
- cmd->speed = SPEED_10;
+ ethtool_cmd_speed_set(cmd, SPEED_10);
break;
}
cmd->autoneg = (tbicr & TBICR_MR_AN_ENABLE)
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c
index 828e97cacdbf..9ec112ca62e4 100644
--- a/drivers/net/pasemi_mac.c
+++ b/drivers/net/pasemi_mac.c
@@ -35,6 +35,7 @@
#include <linux/tcp.h>
#include <net/checksum.h>
#include <linux/inet_lro.h>
+#include <linux/prefetch.h>
#include <asm/irq.h>
#include <asm/firmware.h>
diff --git a/drivers/net/pch_gbe/pch_gbe.h b/drivers/net/pch_gbe/pch_gbe.h
index bf126e76fabf..59fac77d0dbb 100644
--- a/drivers/net/pch_gbe/pch_gbe.h
+++ b/drivers/net/pch_gbe/pch_gbe.h
@@ -597,8 +597,6 @@ struct pch_gbe_hw_stats {
* @rx_ring: Pointer of Rx descriptor ring structure
* @rx_buffer_len: Receive buffer length
* @tx_queue_len: Transmit queue length
- * @rx_csum: Receive TCP/IP checksum enable/disable
- * @tx_csum: Transmit TCP/IP checksum enable/disable
* @have_msi: PCI MSI mode flag
*/
@@ -623,8 +621,6 @@ struct pch_gbe_adapter {
struct pch_gbe_rx_ring *rx_ring;
unsigned long rx_buffer_len;
unsigned long tx_queue_len;
- bool rx_csum;
- bool tx_csum;
bool have_msi;
};
diff --git a/drivers/net/pch_gbe/pch_gbe_ethtool.c b/drivers/net/pch_gbe/pch_gbe_ethtool.c
index d2174a40d708..ea2d8e41887a 100644
--- a/drivers/net/pch_gbe/pch_gbe_ethtool.c
+++ b/drivers/net/pch_gbe/pch_gbe_ethtool.c
@@ -92,7 +92,7 @@ static int pch_gbe_get_settings(struct net_device *netdev,
ecmd->advertising &= ~(ADVERTISED_TP | ADVERTISED_1000baseT_Half);
if (!netif_carrier_ok(adapter->netdev))
- ecmd->speed = -1;
+ ethtool_cmd_speed_set(ecmd, -1);
return ret;
}
@@ -109,12 +109,15 @@ static int pch_gbe_set_settings(struct net_device *netdev,
{
struct pch_gbe_adapter *adapter = netdev_priv(netdev);
struct pch_gbe_hw *hw = &adapter->hw;
+ u32 speed = ethtool_cmd_speed(ecmd);
int ret;
pch_gbe_hal_write_phy_reg(hw, MII_BMCR, BMCR_RESET);
- if (ecmd->speed == USHRT_MAX) {
- ecmd->speed = SPEED_1000;
+ /* when set_settings() is called with a ethtool_cmd previously
+ * filled by get_settings() on a down link, speed is -1: */
+ if (speed == UINT_MAX) {
+ speed = SPEED_1000;
ecmd->duplex = DUPLEX_FULL;
}
ret = mii_ethtool_sset(&adapter->mii, ecmd);
@@ -122,7 +125,7 @@ static int pch_gbe_set_settings(struct net_device *netdev,
pr_err("Error: mii_ethtool_sset\n");
return ret;
}
- hw->mac.link_speed = ecmd->speed;
+ hw->mac.link_speed = speed;
hw->mac.link_duplex = ecmd->duplex;
hw->phy.autoneg_advertised = ecmd->advertising;
hw->mac.autoneg = ecmd->autoneg;
@@ -434,57 +437,6 @@ static int pch_gbe_set_pauseparam(struct net_device *netdev,
}
/**
- * pch_gbe_get_rx_csum - Report whether receive checksums are turned on or off
- * @netdev: Network interface device structure
- * Returns
- * true(1): Checksum On
- * false(0): Checksum Off
- */
-static u32 pch_gbe_get_rx_csum(struct net_device *netdev)
-{
- struct pch_gbe_adapter *adapter = netdev_priv(netdev);
-
- return adapter->rx_csum;
-}
-
-/**
- * pch_gbe_set_rx_csum - Turn receive checksum on or off
- * @netdev: Network interface device structure
- * @data: Checksum On[true] or Off[false]
- * Returns
- * 0: Successful.
- * Negative value: Failed.
- */
-static int pch_gbe_set_rx_csum(struct net_device *netdev, u32 data)
-{
- struct pch_gbe_adapter *adapter = netdev_priv(netdev);
-
- adapter->rx_csum = data;
- if ((netif_running(netdev)))
- pch_gbe_reinit_locked(adapter);
- else
- pch_gbe_reset(adapter);
-
- return 0;
-}
-
-/**
- * pch_gbe_set_tx_csum - Turn transmit checksums on or off
- * @netdev: Network interface device structure
- * @data: Checksum on[true] or off[false]
- * Returns
- * 0: Successful.
- * Negative value: Failed.
- */
-static int pch_gbe_set_tx_csum(struct net_device *netdev, u32 data)
-{
- struct pch_gbe_adapter *adapter = netdev_priv(netdev);
-
- adapter->tx_csum = data;
- return ethtool_op_set_tx_ipv6_csum(netdev, data);
-}
-
-/**
* pch_gbe_get_strings - Return a set of strings that describe the requested
* objects
* @netdev: Network interface device structure
@@ -554,9 +506,6 @@ static const struct ethtool_ops pch_gbe_ethtool_ops = {
.set_ringparam = pch_gbe_set_ringparam,
.get_pauseparam = pch_gbe_get_pauseparam,
.set_pauseparam = pch_gbe_set_pauseparam,
- .get_rx_csum = pch_gbe_get_rx_csum,
- .set_rx_csum = pch_gbe_set_rx_csum,
- .set_tx_csum = pch_gbe_set_tx_csum,
.get_strings = pch_gbe_get_strings,
.get_ethtool_stats = pch_gbe_get_ethtool_stats,
.get_sset_count = pch_gbe_get_sset_count,
diff --git a/drivers/net/pch_gbe/pch_gbe_main.c b/drivers/net/pch_gbe/pch_gbe_main.c
index 56d049a472da..eac3c5ca9731 100644
--- a/drivers/net/pch_gbe/pch_gbe_main.c
+++ b/drivers/net/pch_gbe/pch_gbe_main.c
@@ -20,6 +20,7 @@
#include "pch_gbe.h"
#include "pch_gbe_api.h"
+#include <linux/prefetch.h>
#define DRV_VERSION "1.00"
const char pch_driver_version[] = DRV_VERSION;
@@ -659,6 +660,7 @@ static void pch_gbe_configure_tx(struct pch_gbe_adapter *adapter)
*/
static void pch_gbe_setup_rctl(struct pch_gbe_adapter *adapter)
{
+ struct net_device *netdev = adapter->netdev;
struct pch_gbe_hw *hw = &adapter->hw;
u32 rx_mode, tcpip;
@@ -669,7 +671,7 @@ static void pch_gbe_setup_rctl(struct pch_gbe_adapter *adapter)
tcpip = ioread32(&hw->reg->TCPIP_ACC);
- if (adapter->rx_csum) {
+ if (netdev->features & NETIF_F_RXCSUM) {
tcpip &= ~PCH_GBE_RX_TCPIPACC_OFF;
tcpip |= PCH_GBE_RX_TCPIPACC_EN;
} else {
@@ -890,12 +892,12 @@ static void pch_gbe_watchdog(unsigned long data)
struct pch_gbe_adapter *adapter = (struct pch_gbe_adapter *)data;
struct net_device *netdev = adapter->netdev;
struct pch_gbe_hw *hw = &adapter->hw;
- struct ethtool_cmd cmd;
pr_debug("right now = %ld\n", jiffies);
pch_gbe_update_stats(adapter);
if ((mii_link_ok(&adapter->mii)) && (!netif_carrier_ok(netdev))) {
+ struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET };
netdev->tx_queue_len = adapter->tx_queue_len;
/* mii library handles link maintenance tasks */
if (mii_ethtool_gset(&adapter->mii, &cmd)) {
@@ -905,7 +907,7 @@ static void pch_gbe_watchdog(unsigned long data)
PCH_GBE_WATCHDOG_PERIOD));
return;
}
- hw->mac.link_speed = cmd.speed;
+ hw->mac.link_speed = ethtool_cmd_speed(&cmd);
hw->mac.link_duplex = cmd.duplex;
/* Set the RGMII control. */
pch_gbe_set_rgmii_ctrl(adapter, hw->mac.link_speed,
@@ -915,7 +917,7 @@ static void pch_gbe_watchdog(unsigned long data)
hw->mac.link_duplex);
netdev_dbg(netdev,
"Link is Up %d Mbps %s-Duplex\n",
- cmd.speed,
+ hw->mac.link_speed,
cmd.duplex == DUPLEX_FULL ? "Full" : "Half");
netif_carrier_on(netdev);
netif_wake_queue(netdev);
@@ -953,7 +955,7 @@ static void pch_gbe_tx_queue(struct pch_gbe_adapter *adapter,
frame_ctrl = 0;
if (unlikely(skb->len < PCH_GBE_SHORT_PKT))
frame_ctrl |= PCH_GBE_TXD_CTRL_APAD;
- if (unlikely(!adapter->tx_csum))
+ if (skb->ip_summed == CHECKSUM_NONE)
frame_ctrl |= PCH_GBE_TXD_CTRL_TCPIP_ACC_OFF;
/* Performs checksum processing */
@@ -961,7 +963,7 @@ static void pch_gbe_tx_queue(struct pch_gbe_adapter *adapter,
* It is because the hardware accelerator does not support a checksum,
* when the received data size is less than 64 bytes.
*/
- if ((skb->len < PCH_GBE_SHORT_PKT) && (adapter->tx_csum)) {
+ if (skb->len < PCH_GBE_SHORT_PKT && skb->ip_summed != CHECKSUM_NONE) {
frame_ctrl |= PCH_GBE_TXD_CTRL_APAD |
PCH_GBE_TXD_CTRL_TCPIP_ACC_OFF;
if (skb->protocol == htons(ETH_P_IP)) {
@@ -1429,7 +1431,7 @@ pch_gbe_clean_rx(struct pch_gbe_adapter *adapter,
length = (rx_desc->rx_words_eob) - 3;
/* Decide the data conversion method */
- if (!adapter->rx_csum) {
+ if (!(netdev->features & NETIF_F_RXCSUM)) {
/* [Header:14][payload] */
if (NET_IP_ALIGN) {
/* Because alignment differs,
@@ -2032,6 +2034,29 @@ static int pch_gbe_change_mtu(struct net_device *netdev, int new_mtu)
}
/**
+ * pch_gbe_set_features - Reset device after features changed
+ * @netdev: Network interface device structure
+ * @features: New features
+ * Returns
+ * 0: HW state updated successfully
+ */
+static int pch_gbe_set_features(struct net_device *netdev, u32 features)
+{
+ struct pch_gbe_adapter *adapter = netdev_priv(netdev);
+ u32 changed = features ^ netdev->features;
+
+ if (!(changed & NETIF_F_RXCSUM))
+ return 0;
+
+ if (netif_running(netdev))
+ pch_gbe_reinit_locked(adapter);
+ else
+ pch_gbe_reset(adapter);
+
+ return 0;
+}
+
+/**
* pch_gbe_ioctl - Controls register through a MII interface
* @netdev: Network interface device structure
* @ifr: Pointer to ifr structure
@@ -2131,6 +2156,7 @@ static const struct net_device_ops pch_gbe_netdev_ops = {
.ndo_set_mac_address = pch_gbe_set_mac,
.ndo_tx_timeout = pch_gbe_tx_timeout,
.ndo_change_mtu = pch_gbe_change_mtu,
+ .ndo_set_features = pch_gbe_set_features,
.ndo_do_ioctl = pch_gbe_ioctl,
.ndo_set_multicast_list = &pch_gbe_set_multi,
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -2336,7 +2362,9 @@ static int pch_gbe_probe(struct pci_dev *pdev,
netdev->watchdog_timeo = PCH_GBE_WATCHDOG_PERIOD;
netif_napi_add(netdev, &adapter->napi,
pch_gbe_napi_poll, PCH_GBE_RX_WEIGHT);
- netdev->features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_GRO;
+ netdev->hw_features = NETIF_F_RXCSUM |
+ NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+ netdev->features = netdev->hw_features;
pch_gbe_set_ethtool_ops(netdev);
pch_gbe_mac_load_mac_addr(&adapter->hw);
@@ -2375,11 +2403,6 @@ static int pch_gbe_probe(struct pci_dev *pdev,
pch_gbe_check_options(adapter);
- if (adapter->tx_csum)
- netdev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
- else
- netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
-
/* initialize the wol settings based on the eeprom settings */
adapter->wake_up_evt = PCH_GBE_WL_INIT_SETTING;
dev_info(&pdev->dev, "MAC address : %pM\n", netdev->dev_addr);
diff --git a/drivers/net/pch_gbe/pch_gbe_param.c b/drivers/net/pch_gbe/pch_gbe_param.c
index ef0996a0eaaa..5b5d90a47e29 100644
--- a/drivers/net/pch_gbe/pch_gbe_param.c
+++ b/drivers/net/pch_gbe/pch_gbe_param.c
@@ -426,6 +426,8 @@ full_duplex_only:
void pch_gbe_check_options(struct pch_gbe_adapter *adapter)
{
struct pch_gbe_hw *hw = &adapter->hw;
+ struct net_device *dev = adapter->netdev;
+ int val;
{ /* Transmit Descriptor Count */
static const struct pch_gbe_option opt = {
@@ -466,9 +468,10 @@ void pch_gbe_check_options(struct pch_gbe_adapter *adapter)
.err = "defaulting to Enabled",
.def = PCH_GBE_DEFAULT_RX_CSUM
};
- adapter->rx_csum = XsumRX;
- pch_gbe_validate_option((int *)(&adapter->rx_csum),
- &opt, adapter);
+ val = XsumRX;
+ pch_gbe_validate_option(&val, &opt, adapter);
+ if (!val)
+ dev->features &= ~NETIF_F_RXCSUM;
}
{ /* Checksum Offload Enable/Disable */
static const struct pch_gbe_option opt = {
@@ -477,9 +480,10 @@ void pch_gbe_check_options(struct pch_gbe_adapter *adapter)
.err = "defaulting to Enabled",
.def = PCH_GBE_DEFAULT_TX_CSUM
};
- adapter->tx_csum = XsumTX;
- pch_gbe_validate_option((int *)(&adapter->tx_csum),
- &opt, adapter);
+ val = XsumTX;
+ pch_gbe_validate_option(&val, &opt, adapter);
+ if (!val)
+ dev->features &= ~NETIF_F_ALL_CSUM;
}
{ /* Flow Control */
static const struct pch_gbe_option opt = {
diff --git a/drivers/net/pch_gbe/pch_gbe_phy.c b/drivers/net/pch_gbe/pch_gbe_phy.c
index 923a687acd30..28bb9603d736 100644
--- a/drivers/net/pch_gbe/pch_gbe_phy.c
+++ b/drivers/net/pch_gbe/pch_gbe_phy.c
@@ -247,7 +247,7 @@ inline void pch_gbe_phy_set_rgmii(struct pch_gbe_hw *hw)
void pch_gbe_phy_init_setting(struct pch_gbe_hw *hw)
{
struct pch_gbe_adapter *adapter;
- struct ethtool_cmd cmd;
+ struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET };
int ret;
u16 mii_reg;
@@ -256,7 +256,7 @@ void pch_gbe_phy_init_setting(struct pch_gbe_hw *hw)
if (ret)
pr_err("Error: mii_ethtool_gset\n");
- cmd.speed = hw->mac.link_speed;
+ ethtool_cmd_speed_set(&cmd, hw->mac.link_speed);
cmd.duplex = hw->mac.link_duplex;
cmd.advertising = hw->phy.autoneg_advertised;
cmd.autoneg = hw->mac.autoneg;
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index 81ac330f931d..34c5e1cbf65d 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -1150,7 +1150,7 @@ static int el3_close(struct net_device *dev)
return 0;
}
-static struct pcmcia_device_id tc574_ids[] = {
+static const struct pcmcia_device_id tc574_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0574),
PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0556, "cis/3CCFEM556.cis"),
PCMCIA_DEVICE_NULL,
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index 79b9ca0dbdb4..4a1a35809807 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -908,7 +908,7 @@ static int el3_close(struct net_device *dev)
return 0;
}
-static struct pcmcia_device_id tc589_ids[] = {
+static const struct pcmcia_device_id tc589_ids[] = {
PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0101, 0x0562),
PCMCIA_MFC_DEVICE_PROD_ID1(0, "Motorola MARQUIS", 0xf03e4e77),
PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0589),
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index 3077d72e8222..9953db711969 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -687,7 +687,7 @@ static void block_output(struct net_device *dev, int count,
outsw(nic_base + AXNET_DATAPORT, buf, count>>1);
}
-static struct pcmcia_device_id axnet_ids[] = {
+static const struct pcmcia_device_id axnet_ids[] = {
PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x016c, 0x0081),
PCMCIA_DEVICE_MANF_CARD(0x018a, 0x0301),
PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x2328),
diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c
index 27bfad76fc40..980e65c14936 100644
--- a/drivers/net/pcmcia/com20020_cs.c
+++ b/drivers/net/pcmcia/com20020_cs.c
@@ -316,7 +316,7 @@ static int com20020_resume(struct pcmcia_device *link)
return 0;
}
-static struct pcmcia_device_id com20020_ids[] = {
+static const struct pcmcia_device_id com20020_ids[] = {
PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.",
"PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
PCMCIA_DEVICE_PROD_ID12("SoHard AG",
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 530ab5a10bd3..723815e7a997 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -667,7 +667,7 @@ static int fmvj18x_resume(struct pcmcia_device *link)
/*====================================================================*/
-static struct pcmcia_device_id fmvj18x_ids[] = {
+static const struct pcmcia_device_id fmvj18x_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x0004, 0x0004),
PCMCIA_DEVICE_PROD_ID12("EAGLE Technology", "NE200 ETHERNET LAN MBH10302 04", 0x528c88c4, 0x74f91e59),
PCMCIA_DEVICE_PROD_ID12("Eiger Labs,Inc", "EPX-10BT PC Card Ethernet 10BT", 0x53af556e, 0x877f9922),
diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c
index 15d57f5b6f29..6006d5488fbe 100644
--- a/drivers/net/pcmcia/ibmtr_cs.c
+++ b/drivers/net/pcmcia/ibmtr_cs.c
@@ -340,7 +340,7 @@ static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase)
outb(0x40, dev->base_addr);
}
-static struct pcmcia_device_id ibmtr_ids[] = {
+static const struct pcmcia_device_id ibmtr_ids[] = {
PCMCIA_DEVICE_PROD_ID12("3Com", "TokenLink Velocity PC Card", 0x41240e5b, 0x82c3734e),
PCMCIA_DEVICE_PROD_ID12("IBM", "TOKEN RING", 0xb569a6e5, 0xbf8eed47),
PCMCIA_DEVICE_NULL,
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index 76683d97d83b..9d70b6595220 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -1494,7 +1494,7 @@ static void set_multicast_list(struct net_device *dev)
} /* set_multicast_list */
-static struct pcmcia_device_id nmclan_ids[] = {
+static const struct pcmcia_device_id nmclan_ids[] = {
PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "Ethernet", 0x085a850b, 0x00b2e941),
PCMCIA_DEVICE_PROD_ID12("Portable Add-ons", "Ethernet+", 0xebf1d60, 0xad673aaf),
PCMCIA_DEVICE_NULL,
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index e953793a33ff..b4fd7c3ed077 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -1463,7 +1463,7 @@ failed:
/*====================================================================*/
-static struct pcmcia_device_id pcnet_ids[] = {
+static const struct pcmcia_device_id pcnet_ids[] = {
PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0057, 0x0021),
PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0104, 0x000a),
PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0xea15),
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index 108591756440..1cd9394c3359 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -1860,7 +1860,7 @@ static int smc_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
tmp = inw(ioaddr + CONFIG);
ecmd->port = (tmp & CFG_AUI_SELECT) ? PORT_AUI : PORT_TP;
ecmd->transceiver = XCVR_INTERNAL;
- ecmd->speed = SPEED_10;
+ ethtool_cmd_speed_set(ecmd, SPEED_10);
ecmd->phy_address = ioaddr + MGMT;
SMC_SELECT_BANK(0);
@@ -1875,8 +1875,8 @@ static int smc_netdev_set_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
u16 tmp;
unsigned int ioaddr = dev->base_addr;
- if (ecmd->speed != SPEED_10)
- return -EINVAL;
+ if (ethtool_cmd_speed(ecmd) != SPEED_10)
+ return -EINVAL;
if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
return -EINVAL;
if (ecmd->port != PORT_TP && ecmd->port != PORT_AUI)
@@ -2014,7 +2014,7 @@ static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
return rc;
}
-static struct pcmcia_device_id smc91c92_ids[] = {
+static const struct pcmcia_device_id smc91c92_ids[] = {
PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0109, 0x0501),
PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0140, 0x000a),
PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index a46b7fd6c0f5..e33b190d716f 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -1738,7 +1738,7 @@ do_stop(struct net_device *dev)
return 0;
}
-static struct pcmcia_device_id xirc2ps_ids[] = {
+static const struct pcmcia_device_id xirc2ps_ids[] = {
PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0089, 0x110a),
PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0138, 0x110a),
PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM28", 0x2e3ee845, 0x0ea978ea),
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 768037602dff..b48aba9e4227 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -295,12 +295,14 @@ struct pcnet32_private {
struct net_device *next;
struct mii_if_info mii_if;
struct timer_list watchdog_timer;
- struct timer_list blink_timer;
u32 msg_enable; /* debug message level */
/* each bit indicates an available PHY */
u32 phymask;
unsigned short chip_version; /* which variant this is */
+
+ /* saved registers during ethtool blink */
+ u16 save_regs[4];
};
static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *);
@@ -324,8 +326,6 @@ static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits);
static void pcnet32_ethtool_test(struct net_device *dev,
struct ethtool_test *eth_test, u64 * data);
static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1);
-static int pcnet32_phys_id(struct net_device *dev, u32 data);
-static void pcnet32_led_blink_callback(struct net_device *dev);
static int pcnet32_get_regs_len(struct net_device *dev);
static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
void *ptr);
@@ -1022,7 +1022,8 @@ clean_up:
return rc;
} /* end pcnet32_loopback_test */
-static void pcnet32_led_blink_callback(struct net_device *dev)
+static int pcnet32_set_phys_id(struct net_device *dev,
+ enum ethtool_phys_id_state state)
{
struct pcnet32_private *lp = netdev_priv(dev);
struct pcnet32_access *a = &lp->a;
@@ -1030,50 +1031,31 @@ static void pcnet32_led_blink_callback(struct net_device *dev)
unsigned long flags;
int i;
- spin_lock_irqsave(&lp->lock, flags);
- for (i = 4; i < 8; i++)
- a->write_bcr(ioaddr, i, a->read_bcr(ioaddr, i) ^ 0x4000);
- spin_unlock_irqrestore(&lp->lock, flags);
-
- mod_timer(&lp->blink_timer, PCNET32_BLINK_TIMEOUT);
-}
+ switch (state) {
+ case ETHTOOL_ID_ACTIVE:
+ /* Save the current value of the bcrs */
+ spin_lock_irqsave(&lp->lock, flags);
+ for (i = 4; i < 8; i++)
+ lp->save_regs[i - 4] = a->read_bcr(ioaddr, i);
+ spin_unlock_irqrestore(&lp->lock, flags);
+ return 2; /* cycle on/off twice per second */
-static int pcnet32_phys_id(struct net_device *dev, u32 data)
-{
- struct pcnet32_private *lp = netdev_priv(dev);
- struct pcnet32_access *a = &lp->a;
- ulong ioaddr = dev->base_addr;
- unsigned long flags;
- int i, regs[4];
+ case ETHTOOL_ID_ON:
+ case ETHTOOL_ID_OFF:
+ /* Blink the led */
+ spin_lock_irqsave(&lp->lock, flags);
+ for (i = 4; i < 8; i++)
+ a->write_bcr(ioaddr, i, a->read_bcr(ioaddr, i) ^ 0x4000);
+ spin_unlock_irqrestore(&lp->lock, flags);
+ break;
- if (!lp->blink_timer.function) {
- init_timer(&lp->blink_timer);
- lp->blink_timer.function = (void *)pcnet32_led_blink_callback;
- lp->blink_timer.data = (unsigned long)dev;
+ case ETHTOOL_ID_INACTIVE:
+ /* Restore the original value of the bcrs */
+ spin_lock_irqsave(&lp->lock, flags);
+ for (i = 4; i < 8; i++)
+ a->write_bcr(ioaddr, i, lp->save_regs[i - 4]);
+ spin_unlock_irqrestore(&lp->lock, flags);
}
-
- /* Save the current value of the bcrs */
- spin_lock_irqsave(&lp->lock, flags);
- for (i = 4; i < 8; i++)
- regs[i - 4] = a->read_bcr(ioaddr, i);
- spin_unlock_irqrestore(&lp->lock, flags);
-
- mod_timer(&lp->blink_timer, jiffies);
- set_current_state(TASK_INTERRUPTIBLE);
-
- /* AV: the limit here makes no sense whatsoever */
- if ((!data) || (data > (u32) (MAX_SCHEDULE_TIMEOUT / HZ)))
- data = (u32) (MAX_SCHEDULE_TIMEOUT / HZ);
-
- msleep_interruptible(data * 1000);
- del_timer_sync(&lp->blink_timer);
-
- /* Restore the original value of the bcrs */
- spin_lock_irqsave(&lp->lock, flags);
- for (i = 4; i < 8; i++)
- a->write_bcr(ioaddr, i, regs[i - 4]);
- spin_unlock_irqrestore(&lp->lock, flags);
-
return 0;
}
@@ -1450,7 +1432,7 @@ static const struct ethtool_ops pcnet32_ethtool_ops = {
.set_ringparam = pcnet32_set_ringparam,
.get_strings = pcnet32_get_strings,
.self_test = pcnet32_ethtool_test,
- .phys_id = pcnet32_phys_id,
+ .set_phys_id = pcnet32_set_phys_id,
.get_regs_len = pcnet32_get_regs_len,
.get_regs = pcnet32_get_regs,
.get_sset_count = pcnet32_get_sset_count,
@@ -2117,7 +2099,7 @@ static int pcnet32_open(struct net_device *dev)
int first_phy = -1;
u16 bmcr;
u32 bcr9;
- struct ethtool_cmd ecmd;
+ struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
/*
* There is really no good other way to handle multiple PHYs
@@ -2133,9 +2115,9 @@ static int pcnet32_open(struct net_device *dev)
ecmd.port = PORT_MII;
ecmd.transceiver = XCVR_INTERNAL;
ecmd.autoneg = AUTONEG_DISABLE;
- ecmd.speed =
- lp->
- options & PCNET32_PORT_100 ? SPEED_100 : SPEED_10;
+ ethtool_cmd_speed_set(&ecmd,
+ (lp->options & PCNET32_PORT_100) ?
+ SPEED_100 : SPEED_10);
bcr9 = lp->a.read_bcr(ioaddr, 9);
if (lp->options & PCNET32_PORT_FD) {
@@ -2781,11 +2763,11 @@ static void pcnet32_check_media(struct net_device *dev, int verbose)
netif_carrier_on(dev);
if (lp->mii) {
if (netif_msg_link(lp)) {
- struct ethtool_cmd ecmd;
+ struct ethtool_cmd ecmd = {
+ .cmd = ETHTOOL_GSET };
mii_ethtool_gset(&lp->mii_if, &ecmd);
- netdev_info(dev, "link up, %sMbps, %s-duplex\n",
- (ecmd.speed == SPEED_100)
- ? "100" : "10",
+ netdev_info(dev, "link up, %uMbps, %s-duplex\n",
+ ethtool_cmd_speed(&ecmd),
(ecmd.duplex == DUPLEX_FULL)
? "full" : "half");
}
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 13bebab65d02..2333215bbb32 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_FIXED_PHY) += fixed.o
obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o
obj-$(CONFIG_NATIONAL_PHY) += national.o
+obj-$(CONFIG_DP83640_PHY) += dp83640.o
obj-$(CONFIG_STE10XP) += ste10Xp.o
obj-$(CONFIG_MICREL_PHY) += micrel.o
obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o
diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c
new file mode 100644
index 000000000000..b0c9522bb535
--- /dev/null
+++ b/drivers/net/phy/dp83640.c
@@ -0,0 +1,1100 @@
+/*
+ * Driver for the National Semiconductor DP83640 PHYTER
+ *
+ * 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/ethtool.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/net_tstamp.h>
+#include <linux/netdevice.h>
+#include <linux/phy.h>
+#include <linux/ptp_classify.h>
+#include <linux/ptp_clock_kernel.h>
+
+#include "dp83640_reg.h"
+
+#define DP83640_PHY_ID 0x20005ce1
+#define PAGESEL 0x13
+#define LAYER4 0x02
+#define LAYER2 0x01
+#define MAX_RXTS 4
+#define MAX_TXTS 4
+#define N_EXT_TS 1
+#define PSF_PTPVER 2
+#define PSF_EVNT 0x4000
+#define PSF_RX 0x2000
+#define PSF_TX 0x1000
+#define EXT_EVENT 1
+#define EXT_GPIO 1
+#define CAL_EVENT 2
+#define CAL_GPIO 9
+#define CAL_TRIGGER 2
+
+/* phyter seems to miss the mark by 16 ns */
+#define ADJTIME_FIX 16
+
+#if defined(__BIG_ENDIAN)
+#define ENDIAN_FLAG 0
+#elif defined(__LITTLE_ENDIAN)
+#define ENDIAN_FLAG PSF_ENDIAN
+#endif
+
+#define SKB_PTP_TYPE(__skb) (*(unsigned int *)((__skb)->cb))
+
+struct phy_rxts {
+ u16 ns_lo; /* ns[15:0] */
+ u16 ns_hi; /* overflow[1:0], ns[29:16] */
+ u16 sec_lo; /* sec[15:0] */
+ u16 sec_hi; /* sec[31:16] */
+ u16 seqid; /* sequenceId[15:0] */
+ u16 msgtype; /* messageType[3:0], hash[11:0] */
+};
+
+struct phy_txts {
+ u16 ns_lo; /* ns[15:0] */
+ u16 ns_hi; /* overflow[1:0], ns[29:16] */
+ u16 sec_lo; /* sec[15:0] */
+ u16 sec_hi; /* sec[31:16] */
+};
+
+struct rxts {
+ struct list_head list;
+ unsigned long tmo;
+ u64 ns;
+ u16 seqid;
+ u8 msgtype;
+ u16 hash;
+};
+
+struct dp83640_clock;
+
+struct dp83640_private {
+ struct list_head list;
+ struct dp83640_clock *clock;
+ struct phy_device *phydev;
+ struct work_struct ts_work;
+ int hwts_tx_en;
+ int hwts_rx_en;
+ int layer;
+ int version;
+ /* remember state of cfg0 during calibration */
+ int cfg0;
+ /* remember the last event time stamp */
+ struct phy_txts edata;
+ /* list of rx timestamps */
+ struct list_head rxts;
+ struct list_head rxpool;
+ struct rxts rx_pool_data[MAX_RXTS];
+ /* protects above three fields from concurrent access */
+ spinlock_t rx_lock;
+ /* queues of incoming and outgoing packets */
+ struct sk_buff_head rx_queue;
+ struct sk_buff_head tx_queue;
+};
+
+struct dp83640_clock {
+ /* keeps the instance in the 'phyter_clocks' list */
+ struct list_head list;
+ /* we create one clock instance per MII bus */
+ struct mii_bus *bus;
+ /* protects extended registers from concurrent access */
+ struct mutex extreg_lock;
+ /* remembers which page was last selected */
+ int page;
+ /* our advertised capabilities */
+ struct ptp_clock_info caps;
+ /* protects the three fields below from concurrent access */
+ struct mutex clock_lock;
+ /* the one phyter from which we shall read */
+ struct dp83640_private *chosen;
+ /* list of the other attached phyters, not chosen */
+ struct list_head phylist;
+ /* reference to our PTP hardware clock */
+ struct ptp_clock *ptp_clock;
+};
+
+/* globals */
+
+static int chosen_phy = -1;
+static ushort cal_gpio = 4;
+
+module_param(chosen_phy, int, 0444);
+module_param(cal_gpio, ushort, 0444);
+
+MODULE_PARM_DESC(chosen_phy, \
+ "The address of the PHY to use for the ancillary clock features");
+MODULE_PARM_DESC(cal_gpio, \
+ "Which GPIO line to use for synchronizing multiple PHYs");
+
+/* a list of clocks and a mutex to protect it */
+static LIST_HEAD(phyter_clocks);
+static DEFINE_MUTEX(phyter_clocks_lock);
+
+static void rx_timestamp_work(struct work_struct *work);
+
+/* extended register access functions */
+
+#define BROADCAST_ADDR 31
+
+static inline int broadcast_write(struct mii_bus *bus, u32 regnum, u16 val)
+{
+ return mdiobus_write(bus, BROADCAST_ADDR, regnum, val);
+}
+
+/* Caller must hold extreg_lock. */
+static int ext_read(struct phy_device *phydev, int page, u32 regnum)
+{
+ struct dp83640_private *dp83640 = phydev->priv;
+ int val;
+
+ if (dp83640->clock->page != page) {
+ broadcast_write(phydev->bus, PAGESEL, page);
+ dp83640->clock->page = page;
+ }
+ val = phy_read(phydev, regnum);
+
+ return val;
+}
+
+/* Caller must hold extreg_lock. */
+static void ext_write(int broadcast, struct phy_device *phydev,
+ int page, u32 regnum, u16 val)
+{
+ struct dp83640_private *dp83640 = phydev->priv;
+
+ if (dp83640->clock->page != page) {
+ broadcast_write(phydev->bus, PAGESEL, page);
+ dp83640->clock->page = page;
+ }
+ if (broadcast)
+ broadcast_write(phydev->bus, regnum, val);
+ else
+ phy_write(phydev, regnum, val);
+}
+
+/* Caller must hold extreg_lock. */
+static int tdr_write(int bc, struct phy_device *dev,
+ const struct timespec *ts, u16 cmd)
+{
+ ext_write(bc, dev, PAGE4, PTP_TDR, ts->tv_nsec & 0xffff);/* ns[15:0] */
+ ext_write(bc, dev, PAGE4, PTP_TDR, ts->tv_nsec >> 16); /* ns[31:16] */
+ ext_write(bc, dev, PAGE4, PTP_TDR, ts->tv_sec & 0xffff); /* sec[15:0] */
+ ext_write(bc, dev, PAGE4, PTP_TDR, ts->tv_sec >> 16); /* sec[31:16]*/
+
+ ext_write(bc, dev, PAGE4, PTP_CTL, cmd);
+
+ return 0;
+}
+
+/* convert phy timestamps into driver timestamps */
+
+static void phy2rxts(struct phy_rxts *p, struct rxts *rxts)
+{
+ u32 sec;
+
+ sec = p->sec_lo;
+ sec |= p->sec_hi << 16;
+
+ rxts->ns = p->ns_lo;
+ rxts->ns |= (p->ns_hi & 0x3fff) << 16;
+ rxts->ns += ((u64)sec) * 1000000000ULL;
+ rxts->seqid = p->seqid;
+ rxts->msgtype = (p->msgtype >> 12) & 0xf;
+ rxts->hash = p->msgtype & 0x0fff;
+ rxts->tmo = jiffies + HZ;
+}
+
+static u64 phy2txts(struct phy_txts *p)
+{
+ u64 ns;
+ u32 sec;
+
+ sec = p->sec_lo;
+ sec |= p->sec_hi << 16;
+
+ ns = p->ns_lo;
+ ns |= (p->ns_hi & 0x3fff) << 16;
+ ns += ((u64)sec) * 1000000000ULL;
+
+ return ns;
+}
+
+/* ptp clock methods */
+
+static int ptp_dp83640_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+{
+ struct dp83640_clock *clock =
+ container_of(ptp, struct dp83640_clock, caps);
+ struct phy_device *phydev = clock->chosen->phydev;
+ u64 rate;
+ int neg_adj = 0;
+ u16 hi, lo;
+
+ if (ppb < 0) {
+ neg_adj = 1;
+ ppb = -ppb;
+ }
+ rate = ppb;
+ rate <<= 26;
+ rate = div_u64(rate, 1953125);
+
+ hi = (rate >> 16) & PTP_RATE_HI_MASK;
+ if (neg_adj)
+ hi |= PTP_RATE_DIR;
+
+ lo = rate & 0xffff;
+
+ mutex_lock(&clock->extreg_lock);
+
+ ext_write(1, phydev, PAGE4, PTP_RATEH, hi);
+ ext_write(1, phydev, PAGE4, PTP_RATEL, lo);
+
+ mutex_unlock(&clock->extreg_lock);
+
+ return 0;
+}
+
+static int ptp_dp83640_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+ struct dp83640_clock *clock =
+ container_of(ptp, struct dp83640_clock, caps);
+ struct phy_device *phydev = clock->chosen->phydev;
+ struct timespec ts;
+ int err;
+
+ delta += ADJTIME_FIX;
+
+ ts = ns_to_timespec(delta);
+
+ mutex_lock(&clock->extreg_lock);
+
+ err = tdr_write(1, phydev, &ts, PTP_STEP_CLK);
+
+ mutex_unlock(&clock->extreg_lock);
+
+ return err;
+}
+
+static int ptp_dp83640_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+ struct dp83640_clock *clock =
+ container_of(ptp, struct dp83640_clock, caps);
+ struct phy_device *phydev = clock->chosen->phydev;
+ unsigned int val[4];
+
+ mutex_lock(&clock->extreg_lock);
+
+ ext_write(0, phydev, PAGE4, PTP_CTL, PTP_RD_CLK);
+
+ val[0] = ext_read(phydev, PAGE4, PTP_TDR); /* ns[15:0] */
+ val[1] = ext_read(phydev, PAGE4, PTP_TDR); /* ns[31:16] */
+ val[2] = ext_read(phydev, PAGE4, PTP_TDR); /* sec[15:0] */
+ val[3] = ext_read(phydev, PAGE4, PTP_TDR); /* sec[31:16] */
+
+ mutex_unlock(&clock->extreg_lock);
+
+ ts->tv_nsec = val[0] | (val[1] << 16);
+ ts->tv_sec = val[2] | (val[3] << 16);
+
+ return 0;
+}
+
+static int ptp_dp83640_settime(struct ptp_clock_info *ptp,
+ const struct timespec *ts)
+{
+ struct dp83640_clock *clock =
+ container_of(ptp, struct dp83640_clock, caps);
+ struct phy_device *phydev = clock->chosen->phydev;
+ int err;
+
+ mutex_lock(&clock->extreg_lock);
+
+ err = tdr_write(1, phydev, ts, PTP_LOAD_CLK);
+
+ mutex_unlock(&clock->extreg_lock);
+
+ return err;
+}
+
+static int ptp_dp83640_enable(struct ptp_clock_info *ptp,
+ struct ptp_clock_request *rq, int on)
+{
+ struct dp83640_clock *clock =
+ container_of(ptp, struct dp83640_clock, caps);
+ struct phy_device *phydev = clock->chosen->phydev;
+ u16 evnt;
+
+ switch (rq->type) {
+ case PTP_CLK_REQ_EXTTS:
+ if (rq->extts.index != 0)
+ return -EINVAL;
+ evnt = EVNT_WR | (EXT_EVENT & EVNT_SEL_MASK) << EVNT_SEL_SHIFT;
+ if (on) {
+ evnt |= (EXT_GPIO & EVNT_GPIO_MASK) << EVNT_GPIO_SHIFT;
+ evnt |= EVNT_RISE;
+ }
+ ext_write(0, phydev, PAGE5, PTP_EVNT, evnt);
+ return 0;
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static u8 status_frame_dst[6] = { 0x01, 0x1B, 0x19, 0x00, 0x00, 0x00 };
+static u8 status_frame_src[6] = { 0x08, 0x00, 0x17, 0x0B, 0x6B, 0x0F };
+
+static void enable_status_frames(struct phy_device *phydev, bool on)
+{
+ u16 cfg0 = 0, ver;
+
+ if (on)
+ cfg0 = PSF_EVNT_EN | PSF_RXTS_EN | PSF_TXTS_EN | ENDIAN_FLAG;
+
+ ver = (PSF_PTPVER & VERSIONPTP_MASK) << VERSIONPTP_SHIFT;
+
+ ext_write(0, phydev, PAGE5, PSF_CFG0, cfg0);
+ ext_write(0, phydev, PAGE6, PSF_CFG1, ver);
+
+ if (!phydev->attached_dev) {
+ pr_warning("dp83640: expected to find an attached netdevice\n");
+ return;
+ }
+
+ if (on) {
+ if (dev_mc_add(phydev->attached_dev, status_frame_dst))
+ pr_warning("dp83640: failed to add mc address\n");
+ } else {
+ if (dev_mc_del(phydev->attached_dev, status_frame_dst))
+ pr_warning("dp83640: failed to delete mc address\n");
+ }
+}
+
+static bool is_status_frame(struct sk_buff *skb, int type)
+{
+ struct ethhdr *h = eth_hdr(skb);
+
+ if (PTP_CLASS_V2_L2 == type &&
+ !memcmp(h->h_source, status_frame_src, sizeof(status_frame_src)))
+ return true;
+ else
+ return false;
+}
+
+static int expired(struct rxts *rxts)
+{
+ return time_after(jiffies, rxts->tmo);
+}
+
+/* Caller must hold rx_lock. */
+static void prune_rx_ts(struct dp83640_private *dp83640)
+{
+ struct list_head *this, *next;
+ struct rxts *rxts;
+
+ list_for_each_safe(this, next, &dp83640->rxts) {
+ rxts = list_entry(this, struct rxts, list);
+ if (expired(rxts)) {
+ list_del_init(&rxts->list);
+ list_add(&rxts->list, &dp83640->rxpool);
+ }
+ }
+}
+
+/* synchronize the phyters so they act as one clock */
+
+static void enable_broadcast(struct phy_device *phydev, int init_page, int on)
+{
+ int val;
+ phy_write(phydev, PAGESEL, 0);
+ val = phy_read(phydev, PHYCR2);
+ if (on)
+ val |= BC_WRITE;
+ else
+ val &= ~BC_WRITE;
+ phy_write(phydev, PHYCR2, val);
+ phy_write(phydev, PAGESEL, init_page);
+}
+
+static void recalibrate(struct dp83640_clock *clock)
+{
+ s64 now, diff;
+ struct phy_txts event_ts;
+ struct timespec ts;
+ struct list_head *this;
+ struct dp83640_private *tmp;
+ struct phy_device *master = clock->chosen->phydev;
+ u16 cfg0, evnt, ptp_trig, trigger, val;
+
+ trigger = CAL_TRIGGER;
+
+ mutex_lock(&clock->extreg_lock);
+
+ /*
+ * enable broadcast, disable status frames, enable ptp clock
+ */
+ list_for_each(this, &clock->phylist) {
+ tmp = list_entry(this, struct dp83640_private, list);
+ enable_broadcast(tmp->phydev, clock->page, 1);
+ tmp->cfg0 = ext_read(tmp->phydev, PAGE5, PSF_CFG0);
+ ext_write(0, tmp->phydev, PAGE5, PSF_CFG0, 0);
+ ext_write(0, tmp->phydev, PAGE4, PTP_CTL, PTP_ENABLE);
+ }
+ enable_broadcast(master, clock->page, 1);
+ cfg0 = ext_read(master, PAGE5, PSF_CFG0);
+ ext_write(0, master, PAGE5, PSF_CFG0, 0);
+ ext_write(0, master, PAGE4, PTP_CTL, PTP_ENABLE);
+
+ /*
+ * enable an event timestamp
+ */
+ evnt = EVNT_WR | EVNT_RISE | EVNT_SINGLE;
+ evnt |= (CAL_EVENT & EVNT_SEL_MASK) << EVNT_SEL_SHIFT;
+ evnt |= (cal_gpio & EVNT_GPIO_MASK) << EVNT_GPIO_SHIFT;
+
+ list_for_each(this, &clock->phylist) {
+ tmp = list_entry(this, struct dp83640_private, list);
+ ext_write(0, tmp->phydev, PAGE5, PTP_EVNT, evnt);
+ }
+ ext_write(0, master, PAGE5, PTP_EVNT, evnt);
+
+ /*
+ * configure a trigger
+ */
+ ptp_trig = TRIG_WR | TRIG_IF_LATE | TRIG_PULSE;
+ ptp_trig |= (trigger & TRIG_CSEL_MASK) << TRIG_CSEL_SHIFT;
+ ptp_trig |= (cal_gpio & TRIG_GPIO_MASK) << TRIG_GPIO_SHIFT;
+ ext_write(0, master, PAGE5, PTP_TRIG, ptp_trig);
+
+ /* load trigger */
+ val = (trigger & TRIG_SEL_MASK) << TRIG_SEL_SHIFT;
+ val |= TRIG_LOAD;
+ ext_write(0, master, PAGE4, PTP_CTL, val);
+
+ /* enable trigger */
+ val &= ~TRIG_LOAD;
+ val |= TRIG_EN;
+ ext_write(0, master, PAGE4, PTP_CTL, val);
+
+ /* disable trigger */
+ val = (trigger & TRIG_SEL_MASK) << TRIG_SEL_SHIFT;
+ val |= TRIG_DIS;
+ ext_write(0, master, PAGE4, PTP_CTL, val);
+
+ /*
+ * read out and correct offsets
+ */
+ val = ext_read(master, PAGE4, PTP_STS);
+ pr_info("master PTP_STS 0x%04hx", val);
+ val = ext_read(master, PAGE4, PTP_ESTS);
+ pr_info("master PTP_ESTS 0x%04hx", val);
+ event_ts.ns_lo = ext_read(master, PAGE4, PTP_EDATA);
+ event_ts.ns_hi = ext_read(master, PAGE4, PTP_EDATA);
+ event_ts.sec_lo = ext_read(master, PAGE4, PTP_EDATA);
+ event_ts.sec_hi = ext_read(master, PAGE4, PTP_EDATA);
+ now = phy2txts(&event_ts);
+
+ list_for_each(this, &clock->phylist) {
+ tmp = list_entry(this, struct dp83640_private, list);
+ val = ext_read(tmp->phydev, PAGE4, PTP_STS);
+ pr_info("slave PTP_STS 0x%04hx", val);
+ val = ext_read(tmp->phydev, PAGE4, PTP_ESTS);
+ pr_info("slave PTP_ESTS 0x%04hx", val);
+ event_ts.ns_lo = ext_read(tmp->phydev, PAGE4, PTP_EDATA);
+ event_ts.ns_hi = ext_read(tmp->phydev, PAGE4, PTP_EDATA);
+ event_ts.sec_lo = ext_read(tmp->phydev, PAGE4, PTP_EDATA);
+ event_ts.sec_hi = ext_read(tmp->phydev, PAGE4, PTP_EDATA);
+ diff = now - (s64) phy2txts(&event_ts);
+ pr_info("slave offset %lld nanoseconds\n", diff);
+ diff += ADJTIME_FIX;
+ ts = ns_to_timespec(diff);
+ tdr_write(0, tmp->phydev, &ts, PTP_STEP_CLK);
+ }
+
+ /*
+ * restore status frames
+ */
+ list_for_each(this, &clock->phylist) {
+ tmp = list_entry(this, struct dp83640_private, list);
+ ext_write(0, tmp->phydev, PAGE5, PSF_CFG0, tmp->cfg0);
+ }
+ ext_write(0, master, PAGE5, PSF_CFG0, cfg0);
+
+ mutex_unlock(&clock->extreg_lock);
+}
+
+/* time stamping methods */
+
+static void decode_evnt(struct dp83640_private *dp83640,
+ struct phy_txts *phy_txts, u16 ests)
+{
+ struct ptp_clock_event event;
+ int words = (ests >> EVNT_TS_LEN_SHIFT) & EVNT_TS_LEN_MASK;
+
+ switch (words) { /* fall through in every case */
+ case 3:
+ dp83640->edata.sec_hi = phy_txts->sec_hi;
+ case 2:
+ dp83640->edata.sec_lo = phy_txts->sec_lo;
+ case 1:
+ dp83640->edata.ns_hi = phy_txts->ns_hi;
+ case 0:
+ dp83640->edata.ns_lo = phy_txts->ns_lo;
+ }
+
+ event.type = PTP_CLOCK_EXTTS;
+ event.index = 0;
+ event.timestamp = phy2txts(&dp83640->edata);
+
+ ptp_clock_event(dp83640->clock->ptp_clock, &event);
+}
+
+static void decode_rxts(struct dp83640_private *dp83640,
+ struct phy_rxts *phy_rxts)
+{
+ struct rxts *rxts;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dp83640->rx_lock, flags);
+
+ prune_rx_ts(dp83640);
+
+ if (list_empty(&dp83640->rxpool)) {
+ pr_warning("dp83640: rx timestamp pool is empty\n");
+ goto out;
+ }
+ rxts = list_first_entry(&dp83640->rxpool, struct rxts, list);
+ list_del_init(&rxts->list);
+ phy2rxts(phy_rxts, rxts);
+ list_add_tail(&rxts->list, &dp83640->rxts);
+out:
+ spin_unlock_irqrestore(&dp83640->rx_lock, flags);
+}
+
+static void decode_txts(struct dp83640_private *dp83640,
+ struct phy_txts *phy_txts)
+{
+ struct skb_shared_hwtstamps shhwtstamps;
+ struct sk_buff *skb;
+ u64 ns;
+
+ /* We must already have the skb that triggered this. */
+
+ skb = skb_dequeue(&dp83640->tx_queue);
+
+ if (!skb) {
+ pr_warning("dp83640: have timestamp but tx_queue empty\n");
+ return;
+ }
+ ns = phy2txts(phy_txts);
+ memset(&shhwtstamps, 0, sizeof(shhwtstamps));
+ shhwtstamps.hwtstamp = ns_to_ktime(ns);
+ skb_complete_tx_timestamp(skb, &shhwtstamps);
+}
+
+static void decode_status_frame(struct dp83640_private *dp83640,
+ struct sk_buff *skb)
+{
+ struct phy_rxts *phy_rxts;
+ struct phy_txts *phy_txts;
+ u8 *ptr;
+ int len, size;
+ u16 ests, type;
+
+ ptr = skb->data + 2;
+
+ for (len = skb_headlen(skb) - 2; len > sizeof(type); len -= size) {
+
+ type = *(u16 *)ptr;
+ ests = type & 0x0fff;
+ type = type & 0xf000;
+ len -= sizeof(type);
+ ptr += sizeof(type);
+
+ if (PSF_RX == type && len >= sizeof(*phy_rxts)) {
+
+ phy_rxts = (struct phy_rxts *) ptr;
+ decode_rxts(dp83640, phy_rxts);
+ size = sizeof(*phy_rxts);
+
+ } else if (PSF_TX == type && len >= sizeof(*phy_txts)) {
+
+ phy_txts = (struct phy_txts *) ptr;
+ decode_txts(dp83640, phy_txts);
+ size = sizeof(*phy_txts);
+
+ } else if (PSF_EVNT == type && len >= sizeof(*phy_txts)) {
+
+ phy_txts = (struct phy_txts *) ptr;
+ decode_evnt(dp83640, phy_txts, ests);
+ size = sizeof(*phy_txts);
+
+ } else {
+ size = 0;
+ break;
+ }
+ ptr += size;
+ }
+}
+
+static int match(struct sk_buff *skb, unsigned int type, struct rxts *rxts)
+{
+ u16 *seqid;
+ unsigned int offset;
+ u8 *msgtype, *data = skb_mac_header(skb);
+
+ /* check sequenceID, messageType, 12 bit hash of offset 20-29 */
+
+ switch (type) {
+ case PTP_CLASS_V1_IPV4:
+ case PTP_CLASS_V2_IPV4:
+ offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN;
+ break;
+ case PTP_CLASS_V1_IPV6:
+ case PTP_CLASS_V2_IPV6:
+ offset = OFF_PTP6;
+ break;
+ case PTP_CLASS_V2_L2:
+ offset = ETH_HLEN;
+ break;
+ case PTP_CLASS_V2_VLAN:
+ offset = ETH_HLEN + VLAN_HLEN;
+ break;
+ default:
+ return 0;
+ }
+
+ if (skb->len + ETH_HLEN < offset + OFF_PTP_SEQUENCE_ID + sizeof(*seqid))
+ return 0;
+
+ if (unlikely(type & PTP_CLASS_V1))
+ msgtype = data + offset + OFF_PTP_CONTROL;
+ else
+ msgtype = data + offset;
+
+ seqid = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID);
+
+ return (rxts->msgtype == (*msgtype & 0xf) &&
+ rxts->seqid == ntohs(*seqid));
+}
+
+static void dp83640_free_clocks(void)
+{
+ struct dp83640_clock *clock;
+ struct list_head *this, *next;
+
+ mutex_lock(&phyter_clocks_lock);
+
+ list_for_each_safe(this, next, &phyter_clocks) {
+ clock = list_entry(this, struct dp83640_clock, list);
+ if (!list_empty(&clock->phylist)) {
+ pr_warning("phy list non-empty while unloading");
+ BUG();
+ }
+ list_del(&clock->list);
+ mutex_destroy(&clock->extreg_lock);
+ mutex_destroy(&clock->clock_lock);
+ put_device(&clock->bus->dev);
+ kfree(clock);
+ }
+
+ mutex_unlock(&phyter_clocks_lock);
+}
+
+static void dp83640_clock_init(struct dp83640_clock *clock, struct mii_bus *bus)
+{
+ INIT_LIST_HEAD(&clock->list);
+ clock->bus = bus;
+ mutex_init(&clock->extreg_lock);
+ mutex_init(&clock->clock_lock);
+ INIT_LIST_HEAD(&clock->phylist);
+ clock->caps.owner = THIS_MODULE;
+ sprintf(clock->caps.name, "dp83640 timer");
+ clock->caps.max_adj = 1953124;
+ clock->caps.n_alarm = 0;
+ clock->caps.n_ext_ts = N_EXT_TS;
+ clock->caps.n_per_out = 0;
+ clock->caps.pps = 0;
+ clock->caps.adjfreq = ptp_dp83640_adjfreq;
+ clock->caps.adjtime = ptp_dp83640_adjtime;
+ clock->caps.gettime = ptp_dp83640_gettime;
+ clock->caps.settime = ptp_dp83640_settime;
+ clock->caps.enable = ptp_dp83640_enable;
+ /*
+ * Get a reference to this bus instance.
+ */
+ get_device(&bus->dev);
+}
+
+static int choose_this_phy(struct dp83640_clock *clock,
+ struct phy_device *phydev)
+{
+ if (chosen_phy == -1 && !clock->chosen)
+ return 1;
+
+ if (chosen_phy == phydev->addr)
+ return 1;
+
+ return 0;
+}
+
+static struct dp83640_clock *dp83640_clock_get(struct dp83640_clock *clock)
+{
+ if (clock)
+ mutex_lock(&clock->clock_lock);
+ return clock;
+}
+
+/*
+ * Look up and lock a clock by bus instance.
+ * If there is no clock for this bus, then create it first.
+ */
+static struct dp83640_clock *dp83640_clock_get_bus(struct mii_bus *bus)
+{
+ struct dp83640_clock *clock = NULL, *tmp;
+ struct list_head *this;
+
+ mutex_lock(&phyter_clocks_lock);
+
+ list_for_each(this, &phyter_clocks) {
+ tmp = list_entry(this, struct dp83640_clock, list);
+ if (tmp->bus == bus) {
+ clock = tmp;
+ break;
+ }
+ }
+ if (clock)
+ goto out;
+
+ clock = kzalloc(sizeof(struct dp83640_clock), GFP_KERNEL);
+ if (!clock)
+ goto out;
+
+ dp83640_clock_init(clock, bus);
+ list_add_tail(&phyter_clocks, &clock->list);
+out:
+ mutex_unlock(&phyter_clocks_lock);
+
+ return dp83640_clock_get(clock);
+}
+
+static void dp83640_clock_put(struct dp83640_clock *clock)
+{
+ mutex_unlock(&clock->clock_lock);
+}
+
+static int dp83640_probe(struct phy_device *phydev)
+{
+ struct dp83640_clock *clock;
+ struct dp83640_private *dp83640;
+ int err = -ENOMEM, i;
+
+ if (phydev->addr == BROADCAST_ADDR)
+ return 0;
+
+ clock = dp83640_clock_get_bus(phydev->bus);
+ if (!clock)
+ goto no_clock;
+
+ dp83640 = kzalloc(sizeof(struct dp83640_private), GFP_KERNEL);
+ if (!dp83640)
+ goto no_memory;
+
+ dp83640->phydev = phydev;
+ INIT_WORK(&dp83640->ts_work, rx_timestamp_work);
+
+ INIT_LIST_HEAD(&dp83640->rxts);
+ INIT_LIST_HEAD(&dp83640->rxpool);
+ for (i = 0; i < MAX_RXTS; i++)
+ list_add(&dp83640->rx_pool_data[i].list, &dp83640->rxpool);
+
+ phydev->priv = dp83640;
+
+ spin_lock_init(&dp83640->rx_lock);
+ skb_queue_head_init(&dp83640->rx_queue);
+ skb_queue_head_init(&dp83640->tx_queue);
+
+ dp83640->clock = clock;
+
+ if (choose_this_phy(clock, phydev)) {
+ clock->chosen = dp83640;
+ clock->ptp_clock = ptp_clock_register(&clock->caps);
+ if (IS_ERR(clock->ptp_clock)) {
+ err = PTR_ERR(clock->ptp_clock);
+ goto no_register;
+ }
+ } else
+ list_add_tail(&dp83640->list, &clock->phylist);
+
+ if (clock->chosen && !list_empty(&clock->phylist))
+ recalibrate(clock);
+ else
+ enable_broadcast(dp83640->phydev, clock->page, 1);
+
+ dp83640_clock_put(clock);
+ return 0;
+
+no_register:
+ clock->chosen = NULL;
+ kfree(dp83640);
+no_memory:
+ dp83640_clock_put(clock);
+no_clock:
+ return err;
+}
+
+static void dp83640_remove(struct phy_device *phydev)
+{
+ struct dp83640_clock *clock;
+ struct list_head *this, *next;
+ struct dp83640_private *tmp, *dp83640 = phydev->priv;
+
+ if (phydev->addr == BROADCAST_ADDR)
+ return;
+
+ enable_status_frames(phydev, false);
+ cancel_work_sync(&dp83640->ts_work);
+
+ clock = dp83640_clock_get(dp83640->clock);
+
+ if (dp83640 == clock->chosen) {
+ ptp_clock_unregister(clock->ptp_clock);
+ clock->chosen = NULL;
+ } else {
+ list_for_each_safe(this, next, &clock->phylist) {
+ tmp = list_entry(this, struct dp83640_private, list);
+ if (tmp == dp83640) {
+ list_del_init(&tmp->list);
+ break;
+ }
+ }
+ }
+
+ dp83640_clock_put(clock);
+ kfree(dp83640);
+}
+
+static int dp83640_hwtstamp(struct phy_device *phydev, struct ifreq *ifr)
+{
+ struct dp83640_private *dp83640 = phydev->priv;
+ struct hwtstamp_config cfg;
+ u16 txcfg0, rxcfg0;
+
+ if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
+ return -EFAULT;
+
+ if (cfg.flags) /* reserved for future extensions */
+ return -EINVAL;
+
+ switch (cfg.tx_type) {
+ case HWTSTAMP_TX_OFF:
+ dp83640->hwts_tx_en = 0;
+ break;
+ case HWTSTAMP_TX_ON:
+ dp83640->hwts_tx_en = 1;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ switch (cfg.rx_filter) {
+ case HWTSTAMP_FILTER_NONE:
+ dp83640->hwts_rx_en = 0;
+ dp83640->layer = 0;
+ dp83640->version = 0;
+ break;
+ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+ dp83640->hwts_rx_en = 1;
+ dp83640->layer = LAYER4;
+ dp83640->version = 1;
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+ dp83640->hwts_rx_en = 1;
+ dp83640->layer = LAYER4;
+ dp83640->version = 2;
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+ dp83640->hwts_rx_en = 1;
+ dp83640->layer = LAYER2;
+ dp83640->version = 2;
+ break;
+ case HWTSTAMP_FILTER_PTP_V2_EVENT:
+ case HWTSTAMP_FILTER_PTP_V2_SYNC:
+ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+ dp83640->hwts_rx_en = 1;
+ dp83640->layer = LAYER4|LAYER2;
+ dp83640->version = 2;
+ break;
+ default:
+ return -ERANGE;
+ }
+
+ txcfg0 = (dp83640->version & TX_PTP_VER_MASK) << TX_PTP_VER_SHIFT;
+ rxcfg0 = (dp83640->version & TX_PTP_VER_MASK) << TX_PTP_VER_SHIFT;
+
+ if (dp83640->layer & LAYER2) {
+ txcfg0 |= TX_L2_EN;
+ rxcfg0 |= RX_L2_EN;
+ }
+ if (dp83640->layer & LAYER4) {
+ txcfg0 |= TX_IPV6_EN | TX_IPV4_EN;
+ rxcfg0 |= RX_IPV6_EN | RX_IPV4_EN;
+ }
+
+ if (dp83640->hwts_tx_en)
+ txcfg0 |= TX_TS_EN;
+
+ if (dp83640->hwts_rx_en)
+ rxcfg0 |= RX_TS_EN;
+
+ mutex_lock(&dp83640->clock->extreg_lock);
+
+ if (dp83640->hwts_tx_en || dp83640->hwts_rx_en) {
+ enable_status_frames(phydev, true);
+ ext_write(0, phydev, PAGE4, PTP_CTL, PTP_ENABLE);
+ }
+
+ ext_write(0, phydev, PAGE5, PTP_TXCFG0, txcfg0);
+ ext_write(0, phydev, PAGE5, PTP_RXCFG0, rxcfg0);
+
+ mutex_unlock(&dp83640->clock->extreg_lock);
+
+ return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
+}
+
+static void rx_timestamp_work(struct work_struct *work)
+{
+ struct dp83640_private *dp83640 =
+ container_of(work, struct dp83640_private, ts_work);
+ struct list_head *this, *next;
+ struct rxts *rxts;
+ struct skb_shared_hwtstamps *shhwtstamps;
+ struct sk_buff *skb;
+ unsigned int type;
+ unsigned long flags;
+
+ /* Deliver each deferred packet, with or without a time stamp. */
+
+ while ((skb = skb_dequeue(&dp83640->rx_queue)) != NULL) {
+ type = SKB_PTP_TYPE(skb);
+ spin_lock_irqsave(&dp83640->rx_lock, flags);
+ list_for_each_safe(this, next, &dp83640->rxts) {
+ rxts = list_entry(this, struct rxts, list);
+ if (match(skb, type, rxts)) {
+ shhwtstamps = skb_hwtstamps(skb);
+ memset(shhwtstamps, 0, sizeof(*shhwtstamps));
+ shhwtstamps->hwtstamp = ns_to_ktime(rxts->ns);
+ list_del_init(&rxts->list);
+ list_add(&rxts->list, &dp83640->rxpool);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&dp83640->rx_lock, flags);
+ netif_rx(skb);
+ }
+
+ /* Clear out expired time stamps. */
+
+ spin_lock_irqsave(&dp83640->rx_lock, flags);
+ prune_rx_ts(dp83640);
+ spin_unlock_irqrestore(&dp83640->rx_lock, flags);
+}
+
+static bool dp83640_rxtstamp(struct phy_device *phydev,
+ struct sk_buff *skb, int type)
+{
+ struct dp83640_private *dp83640 = phydev->priv;
+
+ if (!dp83640->hwts_rx_en)
+ return false;
+
+ if (is_status_frame(skb, type)) {
+ decode_status_frame(dp83640, skb);
+ /* Let the stack drop this frame. */
+ return false;
+ }
+
+ SKB_PTP_TYPE(skb) = type;
+ skb_queue_tail(&dp83640->rx_queue, skb);
+ schedule_work(&dp83640->ts_work);
+
+ return true;
+}
+
+static void dp83640_txtstamp(struct phy_device *phydev,
+ struct sk_buff *skb, int type)
+{
+ struct dp83640_private *dp83640 = phydev->priv;
+
+ if (!dp83640->hwts_tx_en) {
+ kfree_skb(skb);
+ return;
+ }
+ skb_queue_tail(&dp83640->tx_queue, skb);
+ schedule_work(&dp83640->ts_work);
+}
+
+static struct phy_driver dp83640_driver = {
+ .phy_id = DP83640_PHY_ID,
+ .phy_id_mask = 0xfffffff0,
+ .name = "NatSemi DP83640",
+ .features = PHY_BASIC_FEATURES,
+ .flags = 0,
+ .probe = dp83640_probe,
+ .remove = dp83640_remove,
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .hwtstamp = dp83640_hwtstamp,
+ .rxtstamp = dp83640_rxtstamp,
+ .txtstamp = dp83640_txtstamp,
+ .driver = {.owner = THIS_MODULE,}
+};
+
+static int __init dp83640_init(void)
+{
+ return phy_driver_register(&dp83640_driver);
+}
+
+static void __exit dp83640_exit(void)
+{
+ dp83640_free_clocks();
+ phy_driver_unregister(&dp83640_driver);
+}
+
+MODULE_DESCRIPTION("National Semiconductor DP83640 PHY driver");
+MODULE_AUTHOR("Richard Cochran <richard.cochran@omicron.at>");
+MODULE_LICENSE("GPL");
+
+module_init(dp83640_init);
+module_exit(dp83640_exit);
+
+static struct mdio_device_id __maybe_unused dp83640_tbl[] = {
+ { DP83640_PHY_ID, 0xfffffff0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(mdio, dp83640_tbl);
diff --git a/drivers/net/phy/dp83640_reg.h b/drivers/net/phy/dp83640_reg.h
new file mode 100644
index 000000000000..e7fe41117003
--- /dev/null
+++ b/drivers/net/phy/dp83640_reg.h
@@ -0,0 +1,267 @@
+/* dp83640_reg.h
+ * Generated by regen.tcl on Thu Feb 17 10:02:48 AM CET 2011
+ */
+#ifndef HAVE_DP83640_REGISTERS
+#define HAVE_DP83640_REGISTERS
+
+#define PAGE0 0x0000
+#define PHYCR2 0x001c /* PHY Control Register 2 */
+
+#define PAGE4 0x0004
+#define PTP_CTL 0x0014 /* PTP Control Register */
+#define PTP_TDR 0x0015 /* PTP Time Data Register */
+#define PTP_STS 0x0016 /* PTP Status Register */
+#define PTP_TSTS 0x0017 /* PTP Trigger Status Register */
+#define PTP_RATEL 0x0018 /* PTP Rate Low Register */
+#define PTP_RATEH 0x0019 /* PTP Rate High Register */
+#define PTP_RDCKSUM 0x001a /* PTP Read Checksum */
+#define PTP_WRCKSUM 0x001b /* PTP Write Checksum */
+#define PTP_TXTS 0x001c /* PTP Transmit Timestamp Register, in four 16-bit reads */
+#define PTP_RXTS 0x001d /* PTP Receive Timestamp Register, in six? 16-bit reads */
+#define PTP_ESTS 0x001e /* PTP Event Status Register */
+#define PTP_EDATA 0x001f /* PTP Event Data Register */
+
+#define PAGE5 0x0005
+#define PTP_TRIG 0x0014 /* PTP Trigger Configuration Register */
+#define PTP_EVNT 0x0015 /* PTP Event Configuration Register */
+#define PTP_TXCFG0 0x0016 /* PTP Transmit Configuration Register 0 */
+#define PTP_TXCFG1 0x0017 /* PTP Transmit Configuration Register 1 */
+#define PSF_CFG0 0x0018 /* PHY Status Frame Configuration Register 0 */
+#define PTP_RXCFG0 0x0019 /* PTP Receive Configuration Register 0 */
+#define PTP_RXCFG1 0x001a /* PTP Receive Configuration Register 1 */
+#define PTP_RXCFG2 0x001b /* PTP Receive Configuration Register 2 */
+#define PTP_RXCFG3 0x001c /* PTP Receive Configuration Register 3 */
+#define PTP_RXCFG4 0x001d /* PTP Receive Configuration Register 4 */
+#define PTP_TRDL 0x001e /* PTP Temporary Rate Duration Low Register */
+#define PTP_TRDH 0x001f /* PTP Temporary Rate Duration High Register */
+
+#define PAGE6 0x0006
+#define PTP_COC 0x0014 /* PTP Clock Output Control Register */
+#define PSF_CFG1 0x0015 /* PHY Status Frame Configuration Register 1 */
+#define PSF_CFG2 0x0016 /* PHY Status Frame Configuration Register 2 */
+#define PSF_CFG3 0x0017 /* PHY Status Frame Configuration Register 3 */
+#define PSF_CFG4 0x0018 /* PHY Status Frame Configuration Register 4 */
+#define PTP_SFDCFG 0x0019 /* PTP SFD Configuration Register */
+#define PTP_INTCTL 0x001a /* PTP Interrupt Control Register */
+#define PTP_CLKSRC 0x001b /* PTP Clock Source Register */
+#define PTP_ETR 0x001c /* PTP Ethernet Type Register */
+#define PTP_OFF 0x001d /* PTP Offset Register */
+#define PTP_GPIOMON 0x001e /* PTP GPIO Monitor Register */
+#define PTP_RXHASH 0x001f /* PTP Receive Hash Register */
+
+/* Bit definitions for the PHYCR2 register */
+#define BC_WRITE (1<<11) /* Broadcast Write Enable */
+
+/* Bit definitions for the PTP_CTL register */
+#define TRIG_SEL_SHIFT (10) /* PTP Trigger Select */
+#define TRIG_SEL_MASK (0x7)
+#define TRIG_DIS (1<<9) /* Disable PTP Trigger */
+#define TRIG_EN (1<<8) /* Enable PTP Trigger */
+#define TRIG_READ (1<<7) /* Read PTP Trigger */
+#define TRIG_LOAD (1<<6) /* Load PTP Trigger */
+#define PTP_RD_CLK (1<<5) /* Read PTP Clock */
+#define PTP_LOAD_CLK (1<<4) /* Load PTP Clock */
+#define PTP_STEP_CLK (1<<3) /* Step PTP Clock */
+#define PTP_ENABLE (1<<2) /* Enable PTP Clock */
+#define PTP_DISABLE (1<<1) /* Disable PTP Clock */
+#define PTP_RESET (1<<0) /* Reset PTP Clock */
+
+/* Bit definitions for the PTP_STS register */
+#define TXTS_RDY (1<<11) /* Transmit Timestamp Ready */
+#define RXTS_RDY (1<<10) /* Receive Timestamp Ready */
+#define TRIG_DONE (1<<9) /* PTP Trigger Done */
+#define EVENT_RDY (1<<8) /* PTP Event Timestamp Ready */
+#define TXTS_IE (1<<3) /* Transmit Timestamp Interrupt Enable */
+#define RXTS_IE (1<<2) /* Receive Timestamp Interrupt Enable */
+#define TRIG_IE (1<<1) /* Trigger Interrupt Enable */
+#define EVENT_IE (1<<0) /* Event Interrupt Enable */
+
+/* Bit definitions for the PTP_TSTS register */
+#define TRIG7_ERROR (1<<15) /* Trigger 7 Error */
+#define TRIG7_ACTIVE (1<<14) /* Trigger 7 Active */
+#define TRIG6_ERROR (1<<13) /* Trigger 6 Error */
+#define TRIG6_ACTIVE (1<<12) /* Trigger 6 Active */
+#define TRIG5_ERROR (1<<11) /* Trigger 5 Error */
+#define TRIG5_ACTIVE (1<<10) /* Trigger 5 Active */
+#define TRIG4_ERROR (1<<9) /* Trigger 4 Error */
+#define TRIG4_ACTIVE (1<<8) /* Trigger 4 Active */
+#define TRIG3_ERROR (1<<7) /* Trigger 3 Error */
+#define TRIG3_ACTIVE (1<<6) /* Trigger 3 Active */
+#define TRIG2_ERROR (1<<5) /* Trigger 2 Error */
+#define TRIG2_ACTIVE (1<<4) /* Trigger 2 Active */
+#define TRIG1_ERROR (1<<3) /* Trigger 1 Error */
+#define TRIG1_ACTIVE (1<<2) /* Trigger 1 Active */
+#define TRIG0_ERROR (1<<1) /* Trigger 0 Error */
+#define TRIG0_ACTIVE (1<<0) /* Trigger 0 Active */
+
+/* Bit definitions for the PTP_RATEH register */
+#define PTP_RATE_DIR (1<<15) /* PTP Rate Direction */
+#define PTP_TMP_RATE (1<<14) /* PTP Temporary Rate */
+#define PTP_RATE_HI_SHIFT (0) /* PTP Rate High 10-bits */
+#define PTP_RATE_HI_MASK (0x3ff)
+
+/* Bit definitions for the PTP_ESTS register */
+#define EVNTS_MISSED_SHIFT (8) /* Indicates number of events missed */
+#define EVNTS_MISSED_MASK (0x7)
+#define EVNT_TS_LEN_SHIFT (6) /* Indicates length of the Timestamp field in 16-bit words minus 1 */
+#define EVNT_TS_LEN_MASK (0x3)
+#define EVNT_RF (1<<5) /* Indicates whether the event is a rise or falling event */
+#define EVNT_NUM_SHIFT (2) /* Indicates Event Timestamp Unit which detected an event */
+#define EVNT_NUM_MASK (0x7)
+#define MULT_EVNT (1<<1) /* Indicates multiple events were detected at the same time */
+#define EVENT_DET (1<<0) /* PTP Event Detected */
+
+/* Bit definitions for the PTP_EDATA register */
+#define E7_RISE (1<<15) /* Indicates direction of Event 7 */
+#define E7_DET (1<<14) /* Indicates Event 7 detected */
+#define E6_RISE (1<<13) /* Indicates direction of Event 6 */
+#define E6_DET (1<<12) /* Indicates Event 6 detected */
+#define E5_RISE (1<<11) /* Indicates direction of Event 5 */
+#define E5_DET (1<<10) /* Indicates Event 5 detected */
+#define E4_RISE (1<<9) /* Indicates direction of Event 4 */
+#define E4_DET (1<<8) /* Indicates Event 4 detected */
+#define E3_RISE (1<<7) /* Indicates direction of Event 3 */
+#define E3_DET (1<<6) /* Indicates Event 3 detected */
+#define E2_RISE (1<<5) /* Indicates direction of Event 2 */
+#define E2_DET (1<<4) /* Indicates Event 2 detected */
+#define E1_RISE (1<<3) /* Indicates direction of Event 1 */
+#define E1_DET (1<<2) /* Indicates Event 1 detected */
+#define E0_RISE (1<<1) /* Indicates direction of Event 0 */
+#define E0_DET (1<<0) /* Indicates Event 0 detected */
+
+/* Bit definitions for the PTP_TRIG register */
+#define TRIG_PULSE (1<<15) /* generate a Pulse rather than a single edge */
+#define TRIG_PER (1<<14) /* generate a periodic signal */
+#define TRIG_IF_LATE (1<<13) /* trigger immediately if already past */
+#define TRIG_NOTIFY (1<<12) /* Trigger Notification Enable */
+#define TRIG_GPIO_SHIFT (8) /* Trigger GPIO Connection, value 1-12 */
+#define TRIG_GPIO_MASK (0xf)
+#define TRIG_TOGGLE (1<<7) /* Trigger Toggle Mode Enable */
+#define TRIG_CSEL_SHIFT (1) /* Trigger Configuration Select */
+#define TRIG_CSEL_MASK (0x7)
+#define TRIG_WR (1<<0) /* Trigger Configuration Write */
+
+/* Bit definitions for the PTP_EVNT register */
+#define EVNT_RISE (1<<14) /* Event Rise Detect Enable */
+#define EVNT_FALL (1<<13) /* Event Fall Detect Enable */
+#define EVNT_SINGLE (1<<12) /* enable single event capture operation */
+#define EVNT_GPIO_SHIFT (8) /* Event GPIO Connection, value 1-12 */
+#define EVNT_GPIO_MASK (0xf)
+#define EVNT_SEL_SHIFT (1) /* Event Select */
+#define EVNT_SEL_MASK (0x7)
+#define EVNT_WR (1<<0) /* Event Configuration Write */
+
+/* Bit definitions for the PTP_TXCFG0 register */
+#define SYNC_1STEP (1<<15) /* insert timestamp into transmit Sync Messages */
+#define DR_INSERT (1<<13) /* Insert Delay_Req Timestamp in Delay_Resp (dangerous) */
+#define NTP_TS_EN (1<<12) /* Enable Timestamping of NTP Packets */
+#define IGNORE_2STEP (1<<11) /* Ignore Two_Step flag for One-Step operation */
+#define CRC_1STEP (1<<10) /* Disable checking of CRC for One-Step operation */
+#define CHK_1STEP (1<<9) /* Enable UDP Checksum correction for One-Step Operation */
+#define IP1588_EN (1<<8) /* Enable IEEE 1588 defined IP address filter */
+#define TX_L2_EN (1<<7) /* Layer2 Timestamp Enable */
+#define TX_IPV6_EN (1<<6) /* IPv6 Timestamp Enable */
+#define TX_IPV4_EN (1<<5) /* IPv4 Timestamp Enable */
+#define TX_PTP_VER_SHIFT (1) /* Enable Timestamp capture for IEEE 1588 version X */
+#define TX_PTP_VER_MASK (0xf)
+#define TX_TS_EN (1<<0) /* Transmit Timestamp Enable */
+
+/* Bit definitions for the PTP_TXCFG1 register */
+#define BYTE0_MASK_SHIFT (8) /* Bit mask to be used for matching Byte0 of the PTP Message */
+#define BYTE0_MASK_MASK (0xff)
+#define BYTE0_DATA_SHIFT (0) /* Data to be used for matching Byte0 of the PTP Message */
+#define BYTE0_DATA_MASK (0xff)
+
+/* Bit definitions for the PSF_CFG0 register */
+#define MAC_SRC_ADD_SHIFT (11) /* Status Frame Mac Source Address */
+#define MAC_SRC_ADD_MASK (0x3)
+#define MIN_PRE_SHIFT (8) /* Status Frame Minimum Preamble */
+#define MIN_PRE_MASK (0x7)
+#define PSF_ENDIAN (1<<7) /* Status Frame Endian Control */
+#define PSF_IPV4 (1<<6) /* Status Frame IPv4 Enable */
+#define PSF_PCF_RD (1<<5) /* Control Frame Read PHY Status Frame Enable */
+#define PSF_ERR_EN (1<<4) /* Error PHY Status Frame Enable */
+#define PSF_TXTS_EN (1<<3) /* Transmit Timestamp PHY Status Frame Enable */
+#define PSF_RXTS_EN (1<<2) /* Receive Timestamp PHY Status Frame Enable */
+#define PSF_TRIG_EN (1<<1) /* Trigger PHY Status Frame Enable */
+#define PSF_EVNT_EN (1<<0) /* Event PHY Status Frame Enable */
+
+/* Bit definitions for the PTP_RXCFG0 register */
+#define DOMAIN_EN (1<<15) /* Domain Match Enable */
+#define ALT_MAST_DIS (1<<14) /* Alternate Master Timestamp Disable */
+#define USER_IP_SEL (1<<13) /* Selects portion of IP address accessible thru PTP_RXCFG2 */
+#define USER_IP_EN (1<<12) /* Enable User-programmed IP address filter */
+#define RX_SLAVE (1<<11) /* Receive Slave Only */
+#define IP1588_EN_SHIFT (8) /* Enable IEEE 1588 defined IP address filters */
+#define IP1588_EN_MASK (0xf)
+#define RX_L2_EN (1<<7) /* Layer2 Timestamp Enable */
+#define RX_IPV6_EN (1<<6) /* IPv6 Timestamp Enable */
+#define RX_IPV4_EN (1<<5) /* IPv4 Timestamp Enable */
+#define RX_PTP_VER_SHIFT (1) /* Enable Timestamp capture for IEEE 1588 version X */
+#define RX_PTP_VER_MASK (0xf)
+#define RX_TS_EN (1<<0) /* Receive Timestamp Enable */
+
+/* Bit definitions for the PTP_RXCFG1 register */
+#define BYTE0_MASK_SHIFT (8) /* Bit mask to be used for matching Byte0 of the PTP Message */
+#define BYTE0_MASK_MASK (0xff)
+#define BYTE0_DATA_SHIFT (0) /* Data to be used for matching Byte0 of the PTP Message */
+#define BYTE0_DATA_MASK (0xff)
+
+/* Bit definitions for the PTP_RXCFG3 register */
+#define TS_MIN_IFG_SHIFT (12) /* Minimum Inter-frame Gap */
+#define TS_MIN_IFG_MASK (0xf)
+#define ACC_UDP (1<<11) /* Record Timestamp if UDP Checksum Error */
+#define ACC_CRC (1<<10) /* Record Timestamp if CRC Error */
+#define TS_APPEND (1<<9) /* Append Timestamp for L2 */
+#define TS_INSERT (1<<8) /* Enable Timestamp Insertion */
+#define PTP_DOMAIN_SHIFT (0) /* PTP Message domainNumber field */
+#define PTP_DOMAIN_MASK (0xff)
+
+/* Bit definitions for the PTP_RXCFG4 register */
+#define IPV4_UDP_MOD (1<<15) /* Enable IPV4 UDP Modification */
+#define TS_SEC_EN (1<<14) /* Enable Timestamp Seconds */
+#define TS_SEC_LEN_SHIFT (12) /* Inserted Timestamp Seconds Length */
+#define TS_SEC_LEN_MASK (0x3)
+#define RXTS_NS_OFF_SHIFT (6) /* Receive Timestamp Nanoseconds offset */
+#define RXTS_NS_OFF_MASK (0x3f)
+#define RXTS_SEC_OFF_SHIFT (0) /* Receive Timestamp Seconds offset */
+#define RXTS_SEC_OFF_MASK (0x3f)
+
+/* Bit definitions for the PTP_COC register */
+#define PTP_CLKOUT_EN (1<<15) /* PTP Clock Output Enable */
+#define PTP_CLKOUT_SEL (1<<14) /* PTP Clock Output Source Select */
+#define PTP_CLKOUT_SPEEDSEL (1<<13) /* PTP Clock Output I/O Speed Select */
+#define PTP_CLKDIV_SHIFT (0) /* PTP Clock Divide-by Value */
+#define PTP_CLKDIV_MASK (0xff)
+
+/* Bit definitions for the PSF_CFG1 register */
+#define PTPRESERVED_SHIFT (12) /* PTP v2 reserved field */
+#define PTPRESERVED_MASK (0xf)
+#define VERSIONPTP_SHIFT (8) /* PTP v2 versionPTP field */
+#define VERSIONPTP_MASK (0xf)
+#define TRANSPORT_SPECIFIC_SHIFT (4) /* PTP v2 Header transportSpecific field */
+#define TRANSPORT_SPECIFIC_MASK (0xf)
+#define MESSAGETYPE_SHIFT (0) /* PTP v2 messageType field */
+#define MESSAGETYPE_MASK (0xf)
+
+/* Bit definitions for the PTP_SFDCFG register */
+#define TX_SFD_GPIO_SHIFT (4) /* TX SFD GPIO Select, value 1-12 */
+#define TX_SFD_GPIO_MASK (0xf)
+#define RX_SFD_GPIO_SHIFT (0) /* RX SFD GPIO Select, value 1-12 */
+#define RX_SFD_GPIO_MASK (0xf)
+
+/* Bit definitions for the PTP_INTCTL register */
+#define PTP_INT_GPIO_SHIFT (0) /* PTP Interrupt GPIO Select */
+#define PTP_INT_GPIO_MASK (0xf)
+
+/* Bit definitions for the PTP_CLKSRC register */
+#define CLK_SRC_SHIFT (14) /* PTP Clock Source Select */
+#define CLK_SRC_MASK (0x3)
+#define CLK_SRC_PER_SHIFT (0) /* PTP Clock Source Period */
+#define CLK_SRC_PER_MASK (0x7f)
+
+/* Bit definitions for the PTP_OFF register */
+#define PTP_OFFSET_SHIFT (0) /* PTP Message offset from preceding header */
+#define PTP_OFFSET_MASK (0xff)
+
+#endif
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index f7670330f988..a47595760751 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -238,6 +238,8 @@ static void phy_sanitize_settings(struct phy_device *phydev)
*/
int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd)
{
+ u32 speed = ethtool_cmd_speed(cmd);
+
if (cmd->phy_address != phydev->addr)
return -EINVAL;
@@ -253,16 +255,16 @@ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd)
return -EINVAL;
if (cmd->autoneg == AUTONEG_DISABLE &&
- ((cmd->speed != SPEED_1000 &&
- cmd->speed != SPEED_100 &&
- cmd->speed != SPEED_10) ||
+ ((speed != SPEED_1000 &&
+ speed != SPEED_100 &&
+ speed != SPEED_10) ||
(cmd->duplex != DUPLEX_HALF &&
cmd->duplex != DUPLEX_FULL)))
return -EINVAL;
phydev->autoneg = cmd->autoneg;
- phydev->speed = cmd->speed;
+ phydev->speed = speed;
phydev->advertising = cmd->advertising;
@@ -286,7 +288,7 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd)
cmd->advertising = phydev->advertising;
- cmd->speed = phydev->speed;
+ ethtool_cmd_speed_set(cmd, phydev->speed);
cmd->duplex = phydev->duplex;
cmd->port = PORT_MII;
cmd->phy_address = phydev->addr;
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
index a1b82c9c67d2..53872d7d7382 100644
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp_async.c
@@ -340,7 +340,7 @@ ppp_asynctty_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
}
/* May sleep, don't call from interrupt level or with interrupts disabled */
-static void
+static unsigned int
ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
char *cflags, int count)
{
@@ -348,7 +348,7 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
unsigned long flags;
if (!ap)
- return;
+ return -ENODEV;
spin_lock_irqsave(&ap->recv_lock, flags);
ppp_async_input(ap, buf, cflags, count);
spin_unlock_irqrestore(&ap->recv_lock, flags);
@@ -356,6 +356,8 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
tasklet_schedule(&ap->tsk);
ap_put(ap);
tty_unthrottle(tty);
+
+ return count;
}
static void
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c
index 2573f525f11c..0815790a5cf9 100644
--- a/drivers/net/ppp_synctty.c
+++ b/drivers/net/ppp_synctty.c
@@ -381,7 +381,7 @@ ppp_sync_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
}
/* May sleep, don't call from interrupt level or with interrupts disabled */
-static void
+static unsigned int
ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
char *cflags, int count)
{
@@ -389,7 +389,7 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
unsigned long flags;
if (!ap)
- return;
+ return -ENODEV;
spin_lock_irqsave(&ap->recv_lock, flags);
ppp_sync_input(ap, buf, cflags, count);
spin_unlock_irqrestore(&ap->recv_lock, flags);
@@ -397,6 +397,8 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
tasklet_schedule(&ap->tsk);
sp_put(ap);
tty_unthrottle(tty);
+
+ return count;
}
static void
diff --git a/drivers/net/pptp.c b/drivers/net/pptp.c
index 51dfcf8023c7..1286fe212dc4 100644
--- a/drivers/net/pptp.c
+++ b/drivers/net/pptp.c
@@ -175,6 +175,7 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
struct pptp_opt *opt = &po->proto.pptp;
struct pptp_gre_header *hdr;
unsigned int header_len = sizeof(*hdr);
+ struct flowi4 fl4;
int islcp;
int len;
unsigned char *data;
@@ -189,7 +190,7 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
if (sk_pppox(po)->sk_state & PPPOX_DEAD)
goto tx_error;
- rt = ip_route_output_ports(&init_net, NULL,
+ rt = ip_route_output_ports(&init_net, &fl4, NULL,
opt->dst_addr.sin_addr.s_addr,
opt->src_addr.sin_addr.s_addr,
0, 0, IPPROTO_GRE,
@@ -270,8 +271,8 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
iph->frag_off = 0;
iph->protocol = IPPROTO_GRE;
iph->tos = 0;
- iph->daddr = rt->rt_dst;
- iph->saddr = rt->rt_src;
+ iph->daddr = fl4.daddr;
+ iph->saddr = fl4.saddr;
iph->ttl = ip4_dst_hoplimit(&rt->dst);
iph->tot_len = htons(skb->len);
@@ -434,6 +435,7 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr,
struct pppox_sock *po = pppox_sk(sk);
struct pptp_opt *opt = &po->proto.pptp;
struct rtable *rt;
+ struct flowi4 fl4;
int error = 0;
if (sp->sa_protocol != PX_PROTO_PPTP)
@@ -463,7 +465,7 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr,
po->chan.private = sk;
po->chan.ops = &pptp_chan_ops;
- rt = ip_route_output_ports(&init_net, sk,
+ rt = ip_route_output_ports(&init_net, &fl4, sk,
opt->dst_addr.sin_addr.s_addr,
opt->src_addr.sin_addr.s_addr,
0, 0,
diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c
index ffdf7349ef7a..b1f251da1535 100644
--- a/drivers/net/ps3_gelic_net.c
+++ b/drivers/net/ps3_gelic_net.c
@@ -951,7 +951,7 @@ static void gelic_net_pass_skb_up(struct gelic_descr *descr,
skb->protocol = eth_type_trans(skb, netdev);
/* checksum offload */
- if (card->rx_csum) {
+ if (netdev->features & NETIF_F_RXCSUM) {
if ((data_status & GELIC_DESCR_DATA_STATUS_CHK_MASK) &&
(!(data_error & GELIC_DESCR_DATA_ERROR_CHK_MASK)))
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -1243,17 +1243,17 @@ static int gelic_ether_get_settings(struct net_device *netdev,
switch (card->ether_port_status & GELIC_LV1_ETHER_SPEED_MASK) {
case GELIC_LV1_ETHER_SPEED_10:
- cmd->speed = SPEED_10;
+ ethtool_cmd_speed_set(cmd, SPEED_10);
break;
case GELIC_LV1_ETHER_SPEED_100:
- cmd->speed = SPEED_100;
+ ethtool_cmd_speed_set(cmd, SPEED_100);
break;
case GELIC_LV1_ETHER_SPEED_1000:
- cmd->speed = SPEED_1000;
+ ethtool_cmd_speed_set(cmd, SPEED_1000);
break;
default:
pr_info("%s: speed unknown\n", __func__);
- cmd->speed = SPEED_10;
+ ethtool_cmd_speed_set(cmd, SPEED_10);
break;
}
@@ -1312,21 +1312,6 @@ static int gelic_ether_set_settings(struct net_device *netdev,
return 0;
}
-u32 gelic_net_get_rx_csum(struct net_device *netdev)
-{
- struct gelic_card *card = netdev_card(netdev);
-
- return card->rx_csum;
-}
-
-int gelic_net_set_rx_csum(struct net_device *netdev, u32 data)
-{
- struct gelic_card *card = netdev_card(netdev);
-
- card->rx_csum = data;
- return 0;
-}
-
static void gelic_net_get_wol(struct net_device *netdev,
struct ethtool_wolinfo *wol)
{
@@ -1411,10 +1396,6 @@ static const struct ethtool_ops gelic_ether_ethtool_ops = {
.get_settings = gelic_ether_get_settings,
.set_settings = gelic_ether_set_settings,
.get_link = ethtool_op_get_link,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = ethtool_op_set_tx_csum,
- .get_rx_csum = gelic_net_get_rx_csum,
- .set_rx_csum = gelic_net_set_rx_csum,
.get_wol = gelic_net_get_wol,
.set_wol = gelic_net_set_wol,
};
@@ -1512,7 +1493,11 @@ int __devinit gelic_net_setup_netdev(struct net_device *netdev,
int status;
u64 v1, v2;
+ netdev->hw_features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
+
netdev->features = NETIF_F_IP_CSUM;
+ if (GELIC_CARD_RX_CSUM_DEFAULT)
+ netdev->features |= NETIF_F_RXCSUM;
status = lv1_net_control(bus_id(card), dev_id(card),
GELIC_LV1_GET_MAC_ADDRESS,
@@ -1756,7 +1741,6 @@ static int __devinit ps3_gelic_driver_probe(struct ps3_system_bus_device *dev)
/* setup card structure */
card->irq_mask = GELIC_CARD_RXINT | GELIC_CARD_TXINT |
GELIC_CARD_PORT_STATUS_CHANGED;
- card->rx_csum = GELIC_CARD_RX_CSUM_DEFAULT;
if (gelic_card_init_chain(card, &card->tx_chain,
diff --git a/drivers/net/ps3_gelic_net.h b/drivers/net/ps3_gelic_net.h
index fadadf9097a3..d9a55b93898b 100644
--- a/drivers/net/ps3_gelic_net.h
+++ b/drivers/net/ps3_gelic_net.h
@@ -290,7 +290,6 @@ struct gelic_card {
struct gelic_descr_chain tx_chain;
struct gelic_descr_chain rx_chain;
int rx_dma_restart_required;
- int rx_csum;
/*
* tx_lock guards tx descriptor list and
* tx_dma_progress.
@@ -377,8 +376,6 @@ extern int gelic_net_setup_netdev(struct net_device *netdev,
/* shared ethtool ops */
extern void gelic_net_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *info);
-extern u32 gelic_net_get_rx_csum(struct net_device *netdev);
-extern int gelic_net_set_rx_csum(struct net_device *netdev, u32 data);
extern void gelic_net_poll_controller(struct net_device *netdev);
#endif /* _GELIC_NET_H */
diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c
index b5ae29d20f2e..2e62938c0f82 100644
--- a/drivers/net/ps3_gelic_wireless.c
+++ b/drivers/net/ps3_gelic_wireless.c
@@ -2581,10 +2581,6 @@ static const struct net_device_ops gelic_wl_netdevice_ops = {
static const struct ethtool_ops gelic_wl_ethtool_ops = {
.get_drvinfo = gelic_net_get_drvinfo,
.get_link = gelic_wl_get_link,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = ethtool_op_set_tx_csum,
- .get_rx_csum = gelic_net_get_rx_csum,
- .set_rx_csum = gelic_net_set_rx_csum,
};
static void __devinit gelic_wl_setup_netdev_ops(struct net_device *netdev)
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index 348b4f1367c9..771bb614ccc9 100644
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -35,6 +35,7 @@
#include <linux/if_vlan.h>
#include <linux/delay.h>
#include <linux/mm.h>
+#include <linux/prefetch.h>
#include "qla3xxx.h"
@@ -1725,7 +1726,7 @@ static int ql_get_settings(struct net_device *ndev, struct ethtool_cmd *ecmd)
}
ecmd->advertising = ql_supported_modes(qdev);
ecmd->autoneg = ql_get_auto_cfg_status(qdev);
- ecmd->speed = ql_get_speed(qdev);
+ ethtool_cmd_speed_set(ecmd, ql_get_speed(qdev));
ecmd->duplex = ql_get_full_dup(qdev);
return 0;
}
@@ -3468,7 +3469,7 @@ static int ql_adapter_up(struct ql3_adapter *qdev)
{
struct net_device *ndev = qdev->ndev;
int err;
- unsigned long irq_flags = IRQF_SAMPLE_RANDOM | IRQF_SHARED;
+ unsigned long irq_flags = IRQF_SHARED;
unsigned long hw_flags;
if (ql_alloc_mem_resources(qdev)) {
diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
index b0dead00b2d1..480ef5cb6ef9 100644
--- a/drivers/net/qlcnic/qlcnic.h
+++ b/drivers/net/qlcnic/qlcnic.h
@@ -29,13 +29,15 @@
#include <linux/io.h>
#include <asm/byteorder.h>
+#include <linux/bitops.h>
+#include <linux/if_vlan.h>
#include "qlcnic_hdr.h"
#define _QLCNIC_LINUX_MAJOR 5
#define _QLCNIC_LINUX_MINOR 0
-#define _QLCNIC_LINUX_SUBVERSION 15
-#define QLCNIC_LINUX_VERSIONID "5.0.15"
+#define _QLCNIC_LINUX_SUBVERSION 18
+#define QLCNIC_LINUX_VERSIONID "5.0.18"
#define QLCNIC_DRV_IDC_VER 0x01
#define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\
(_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION))
@@ -93,8 +95,6 @@
#define TX_IP_PKT 0x04
#define TX_TCP_LSO 0x05
#define TX_TCP_LSO6 0x06
-#define TX_IPSEC 0x07
-#define TX_IPSEC_CMD 0x0a
#define TX_TCPV6_PKT 0x0b
#define TX_UDPV6_PKT 0x0c
@@ -118,7 +118,6 @@
#define PHAN_PEG_RCV_INITIALIZED 0xff01
#define NUM_RCV_DESC_RINGS 3
-#define NUM_STS_DESC_RINGS 4
#define RCV_RING_NORMAL 0
#define RCV_RING_JUMBO 1
@@ -201,7 +200,7 @@ struct rcv_desc {
__le16 reserved;
__le32 buffer_length; /* allocated buffer length (usually 2K) */
__le64 addr_buffer;
-};
+} __packed;
/* opcode field in status_desc */
#define QLCNIC_SYN_OFFLOAD 0x03
@@ -293,6 +292,7 @@ struct uni_data_desc{
/* Flash Defines and Structures */
#define QLCNIC_FLT_LOCATION 0x3F1000
#define QLCNIC_FW_IMAGE_REGION 0x74
+#define QLCNIC_BOOTLD_REGION 0X72
struct qlcnic_flt_header {
u16 version;
u16 len;
@@ -307,7 +307,7 @@ struct qlcnic_flt_entry {
u8 reserved1;
u32 size;
u32 start_addr;
- u32 end_add;
+ u32 end_addr;
};
/* Magic number to let user know flash is programmed */
@@ -366,12 +366,6 @@ struct qlcnic_skb_frag {
u64 length;
};
-struct qlcnic_recv_crb {
- u32 crb_rcv_producer[NUM_RCV_DESC_RINGS];
- u32 crb_sts_consumer[NUM_STS_DESC_RINGS];
- u32 sw_int_mask[NUM_STS_DESC_RINGS];
-};
-
/* Following defines are for the state of the buffers */
#define QLCNIC_BUFFER_FREE 0
#define QLCNIC_BUFFER_BUSY 1
@@ -388,10 +382,10 @@ struct qlcnic_cmd_buffer {
/* In rx_buffer, we do not need multiple fragments as is a single buffer */
struct qlcnic_rx_buffer {
- struct list_head list;
+ u16 ref_handle;
struct sk_buff *skb;
+ struct list_head list;
u64 dma;
- u16 ref_handle;
};
/* Board types */
@@ -399,6 +393,48 @@ struct qlcnic_rx_buffer {
#define QLCNIC_XGBE 0x02
/*
+ * Interrupt coalescing defaults. The defaults are for 1500 MTU. It is
+ * adjusted based on configured MTU.
+ */
+#define QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US 3
+#define QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS 256
+
+#define QLCNIC_INTR_DEFAULT 0x04
+#define QLCNIC_CONFIG_INTR_COALESCE 3
+
+struct qlcnic_nic_intr_coalesce {
+ u8 type;
+ u8 sts_ring_mask;
+ u16 rx_packets;
+ u16 rx_time_us;
+ u16 flag;
+ u32 timer_out;
+};
+
+struct qlcnic_dump_template_hdr {
+ __le32 type;
+ __le32 offset;
+ __le32 size;
+ __le32 cap_mask;
+ __le32 num_entries;
+ __le32 version;
+ __le32 timestamp;
+ __le32 checksum;
+ __le32 drv_cap_mask;
+ __le32 sys_info[3];
+ __le32 saved_state[16];
+ __le32 cap_sizes[8];
+ __le32 rsvd[0];
+};
+
+struct qlcnic_fw_dump {
+ u8 clr; /* flag to indicate if dump is cleared */
+ u32 size; /* total size of the dump */
+ void *data; /* dump data area */
+ struct qlcnic_dump_template_hdr *tmpl_hdr;
+};
+
+/*
* One hardware_context{} per adapter
* contains interrupt info as well shared hardware info.
*/
@@ -416,6 +452,9 @@ struct qlcnic_hardware_context {
u8 linkup;
u16 port_type;
u16 board_type;
+
+ struct qlcnic_nic_intr_coalesce coal;
+ struct qlcnic_fw_dump fw_dump;
};
struct qlcnic_adapter_stats {
@@ -443,50 +482,49 @@ struct qlcnic_adapter_stats {
* be one Rcv Descriptor for normal packets, one for jumbo and may be others.
*/
struct qlcnic_host_rds_ring {
- u32 producer;
+ void __iomem *crb_rcv_producer;
+ struct rcv_desc *desc_head;
+ struct qlcnic_rx_buffer *rx_buf_arr;
u32 num_desc;
+ u32 producer;
u32 dma_size;
u32 skb_size;
u32 flags;
- void __iomem *crb_rcv_producer;
- struct rcv_desc *desc_head;
- struct qlcnic_rx_buffer *rx_buf_arr;
struct list_head free_list;
spinlock_t lock;
dma_addr_t phys_addr;
-};
+} ____cacheline_internodealigned_in_smp;
struct qlcnic_host_sds_ring {
u32 consumer;
u32 num_desc;
void __iomem *crb_sts_consumer;
- void __iomem *crb_intr_mask;
struct status_desc *desc_head;
struct qlcnic_adapter *adapter;
struct napi_struct napi;
struct list_head free_list[NUM_RCV_DESC_RINGS];
+ void __iomem *crb_intr_mask;
int irq;
dma_addr_t phys_addr;
char name[IFNAMSIZ+4];
-};
+} ____cacheline_internodealigned_in_smp;
struct qlcnic_host_tx_ring {
u32 producer;
- __le32 *hw_consumer;
u32 sw_consumer;
- void __iomem *crb_cmd_producer;
u32 num_desc;
-
- struct netdev_queue *txq;
-
- struct qlcnic_cmd_buffer *cmd_buf_arr;
+ void __iomem *crb_cmd_producer;
struct cmd_desc_type0 *desc_head;
+ struct qlcnic_cmd_buffer *cmd_buf_arr;
+ __le32 *hw_consumer;
+
dma_addr_t phys_addr;
dma_addr_t hw_cons_phys_addr;
-};
+ struct netdev_queue *txq;
+} ____cacheline_internodealigned_in_smp;
/*
* Receive context. There is one such structure per instance of the
@@ -495,12 +533,12 @@ struct qlcnic_host_tx_ring {
* present elsewhere.
*/
struct qlcnic_recv_context {
+ struct qlcnic_host_rds_ring *rds_rings;
+ struct qlcnic_host_sds_ring *sds_rings;
u32 state;
u16 context_id;
u16 virt_port;
- struct qlcnic_host_rds_ring *rds_rings;
- struct qlcnic_host_sds_ring *sds_rings;
};
/* HW context creation */
@@ -539,9 +577,6 @@ struct qlcnic_recv_context {
#define QLCNIC_CDRP_CMD_DESTROY_RX_CTX 0x00000008
#define QLCNIC_CDRP_CMD_CREATE_TX_CTX 0x00000009
#define QLCNIC_CDRP_CMD_DESTROY_TX_CTX 0x0000000a
-#define QLCNIC_CDRP_CMD_SETUP_STATISTICS 0x0000000e
-#define QLCNIC_CDRP_CMD_GET_STATISTICS 0x0000000f
-#define QLCNIC_CDRP_CMD_DELETE_STATISTICS 0x00000010
#define QLCNIC_CDRP_CMD_SET_MTU 0x00000012
#define QLCNIC_CDRP_CMD_READ_PHY 0x00000013
#define QLCNIC_CDRP_CMD_WRITE_PHY 0x00000014
@@ -550,17 +585,11 @@ struct qlcnic_recv_context {
#define QLCNIC_CDRP_CMD_SET_FLOW_CTL 0x00000017
#define QLCNIC_CDRP_CMD_READ_MAX_MTU 0x00000018
#define QLCNIC_CDRP_CMD_READ_MAX_LRO 0x00000019
-#define QLCNIC_CDRP_CMD_CONFIGURE_TOE 0x0000001a
-#define QLCNIC_CDRP_CMD_FUNC_ATTRIB 0x0000001b
-#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_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
@@ -568,8 +597,12 @@ struct qlcnic_recv_context {
#define QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH 0x00000028
#define QLCNIC_CDRP_CMD_GET_ESWITCH_PORT_CONFIG 0x00000029
#define QLCNIC_CDRP_CMD_GET_ESWITCH_STATS 0x0000002a
+#define QLCNIC_CDRP_CMD_CONFIG_PORT 0x0000002E
+#define QLCNIC_CDRP_CMD_TEMP_SIZE 0x0000002f
+#define QLCNIC_CDRP_CMD_GET_TEMP_HDR 0x00000030
#define QLCNIC_RCODE_SUCCESS 0
+#define QLCNIC_RCODE_NOT_SUPPORTED 9
#define QLCNIC_RCODE_TIMEOUT 17
#define QLCNIC_DESTROY_CTX_RESET 0
@@ -598,14 +631,14 @@ struct qlcnic_hostrq_sds_ring {
__le32 ring_size; /* Ring entries */
__le16 msi_index;
__le16 rsvd; /* Padding */
-};
+} __packed;
struct qlcnic_hostrq_rds_ring {
__le64 host_phys_addr; /* Ring base addr */
__le64 buff_size; /* Packet buffer size */
__le32 ring_size; /* Ring entries */
__le32 ring_kind; /* Class of ring */
-};
+} __packed;
struct qlcnic_hostrq_rx_ctx {
__le64 host_rsp_dma_addr; /* Response dma'd here */
@@ -626,17 +659,17 @@ struct qlcnic_hostrq_rx_ctx {
- N hostrq_rds_rings
- N hostrq_sds_rings */
char data[0];
-};
+} __packed;
struct qlcnic_cardrsp_rds_ring{
__le32 host_producer_crb; /* Crb to use */
__le32 rsvd1; /* Padding */
-};
+} __packed;
struct qlcnic_cardrsp_sds_ring {
__le32 host_consumer_crb; /* Crb to use */
__le32 interrupt_crb; /* Crb to use */
-};
+} __packed;
struct qlcnic_cardrsp_rx_ctx {
/* These ring offsets are relative to data[0] below */
@@ -655,7 +688,7 @@ struct qlcnic_cardrsp_rx_ctx {
- N cardrsp_rds_rings
- N cardrs_sds_rings */
char data[0];
-};
+} __packed;
#define SIZEOF_HOSTRQ_RX(HOSTRQ_RX, rds_rings, sds_rings) \
(sizeof(HOSTRQ_RX) + \
@@ -675,7 +708,7 @@ struct qlcnic_hostrq_cds_ring {
__le64 host_phys_addr; /* Ring base addr */
__le32 ring_size; /* Ring entries */
__le32 rsvd; /* Padding */
-};
+} __packed;
struct qlcnic_hostrq_tx_ctx {
__le64 host_rsp_dma_addr; /* Response dma'd here */
@@ -690,12 +723,12 @@ struct qlcnic_hostrq_tx_ctx {
__le16 rsvd3; /* Padding */
struct qlcnic_hostrq_cds_ring cds_ring; /* Desc of cds ring */
u8 reserved[128]; /* future expansion */
-};
+} __packed;
struct qlcnic_cardrsp_cds_ring {
__le32 host_producer_crb; /* Crb to use */
__le32 interrupt_crb; /* Crb to use */
-};
+} __packed;
struct qlcnic_cardrsp_tx_ctx {
__le32 host_ctx_state; /* Starting state */
@@ -704,7 +737,7 @@ struct qlcnic_cardrsp_tx_ctx {
u8 virt_port; /* Virtual/Logical id of port */
struct qlcnic_cardrsp_cds_ring cds_ring; /* Card cds settings */
u8 reserved[128]; /* future expansion */
-};
+} __packed;
#define SIZEOF_HOSTRQ_TX(HOSTRQ_TX) (sizeof(HOSTRQ_TX))
#define SIZEOF_CARDRSP_TX(CARDRSP_TX) (sizeof(CARDRSP_TX))
@@ -738,40 +771,6 @@ struct qlcnic_mac_list_s {
uint8_t mac_addr[ETH_ALEN+2];
};
-/*
- * Interrupt coalescing defaults. The defaults are for 1500 MTU. It is
- * adjusted based on configured MTU.
- */
-#define QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US 3
-#define QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS 256
-#define QLCNIC_DEFAULT_INTR_COALESCE_TX_PACKETS 64
-#define QLCNIC_DEFAULT_INTR_COALESCE_TX_TIME_US 4
-
-#define QLCNIC_INTR_DEFAULT 0x04
-
-union qlcnic_nic_intr_coalesce_data {
- struct {
- u16 rx_packets;
- u16 rx_time_us;
- u16 tx_packets;
- u16 tx_time_us;
- } data;
- u64 word;
-};
-
-struct qlcnic_nic_intr_coalesce {
- u16 stats_time_us;
- u16 rate_sample_time;
- u16 flags;
- u16 rsvd_1;
- u32 low_threshold;
- u32 high_threshold;
- union qlcnic_nic_intr_coalesce_data normal;
- union qlcnic_nic_intr_coalesce_data low;
- union qlcnic_nic_intr_coalesce_data high;
- union qlcnic_nic_intr_coalesce_data irq;
-};
-
#define QLCNIC_HOST_REQUEST 0x13
#define QLCNIC_REQUEST 0x14
@@ -783,50 +782,20 @@ struct qlcnic_nic_intr_coalesce {
/*
* Driver --> Firmware
*/
-#define QLCNIC_H2C_OPCODE_START 0
-#define QLCNIC_H2C_OPCODE_CONFIG_RSS 1
-#define QLCNIC_H2C_OPCODE_CONFIG_RSS_TBL 2
-#define QLCNIC_H2C_OPCODE_CONFIG_INTR_COALESCE 3
-#define QLCNIC_H2C_OPCODE_CONFIG_LED 4
-#define QLCNIC_H2C_OPCODE_CONFIG_PROMISCUOUS 5
-#define QLCNIC_H2C_OPCODE_CONFIG_L2_MAC 6
-#define QLCNIC_H2C_OPCODE_LRO_REQUEST 7
-#define QLCNIC_H2C_OPCODE_GET_SNMP_STATS 8
-#define QLCNIC_H2C_OPCODE_PROXY_START_REQUEST 9
-#define QLCNIC_H2C_OPCODE_PROXY_STOP_REQUEST 10
-#define QLCNIC_H2C_OPCODE_PROXY_SET_MTU 11
-#define QLCNIC_H2C_OPCODE_PROXY_SET_VPORT_MISS_MODE 12
-#define QLCNIC_H2C_OPCODE_GET_FINGER_PRINT_REQUEST 13
-#define QLCNIC_H2C_OPCODE_INSTALL_LICENSE_REQUEST 14
-#define QLCNIC_H2C_OPCODE_GET_LICENSE_CAPABILITY_REQUEST 15
-#define QLCNIC_H2C_OPCODE_GET_NET_STATS 16
-#define QLCNIC_H2C_OPCODE_PROXY_UPDATE_P2V 17
-#define QLCNIC_H2C_OPCODE_CONFIG_IPADDR 18
-#define QLCNIC_H2C_OPCODE_PROXY_STOP_DONE 20
-#define QLCNIC_H2C_OPCODE_GET_LINKEVENT 21
-#define QLCNIC_C2C_OPCODE 22
-#define QLCNIC_H2C_OPCODE_CONFIG_BRIDGING 23
-#define QLCNIC_H2C_OPCODE_CONFIG_HW_LRO 24
-#define QLCNIC_H2C_OPCODE_LAST 25
+#define QLCNIC_H2C_OPCODE_CONFIG_RSS 0x1
+#define QLCNIC_H2C_OPCODE_CONFIG_INTR_COALESCE 0x3
+#define QLCNIC_H2C_OPCODE_CONFIG_LED 0x4
+#define QLCNIC_H2C_OPCODE_LRO_REQUEST 0x7
+#define QLCNIC_H2C_OPCODE_SET_MAC_RECEIVE_MODE 0xc
+#define QLCNIC_H2C_OPCODE_CONFIG_IPADDR 0x12
+#define QLCNIC_H2C_OPCODE_GET_LINKEVENT 0x15
+#define QLCNIC_H2C_OPCODE_CONFIG_BRIDGING 0x17
+#define QLCNIC_H2C_OPCODE_CONFIG_HW_LRO 0x18
/*
* Firmware --> Driver
*/
-#define QLCNIC_C2H_OPCODE_START 128
-#define QLCNIC_C2H_OPCODE_CONFIG_RSS_RESPONSE 129
-#define QLCNIC_C2H_OPCODE_CONFIG_RSS_TBL_RESPONSE 130
-#define QLCNIC_C2H_OPCODE_CONFIG_MAC_RESPONSE 131
-#define QLCNIC_C2H_OPCODE_CONFIG_PROMISCUOUS_RESPONSE 132
-#define QLCNIC_C2H_OPCODE_CONFIG_L2_MAC_RESPONSE 133
-#define QLCNIC_C2H_OPCODE_LRO_DELETE_RESPONSE 134
-#define QLCNIC_C2H_OPCODE_LRO_ADD_FAILURE_RESPONSE 135
-#define QLCNIC_C2H_OPCODE_GET_SNMP_STATS 136
-#define QLCNIC_C2H_OPCODE_GET_FINGER_PRINT_REPLY 137
-#define QLCNIC_C2H_OPCODE_INSTALL_LICENSE_REPLY 138
-#define QLCNIC_C2H_OPCODE_GET_LICENSE_CAPABILITIES_REPLY 139
-#define QLCNIC_C2H_OPCODE_GET_NET_STATS_RESPONSE 140
#define QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE 141
-#define QLCNIC_C2H_OPCODE_LAST 142
#define VPORT_MISS_MODE_DROP 0 /* drop all unmatched */
#define VPORT_MISS_MODE_ACCEPT_ALL 1 /* accept all packets */
@@ -895,7 +864,7 @@ struct qlcnic_nic_req {
__le64 qhdr;
__le64 req_hdr;
__le64 words[6];
-};
+} __packed;
struct qlcnic_mac_req {
u8 op;
@@ -906,7 +875,7 @@ struct qlcnic_mac_req {
struct qlcnic_vlan_req {
__le16 vlan_id;
__le16 rsvd[3];
-};
+} __packed;
struct qlcnic_ipaddr {
__be32 ipv4;
@@ -929,7 +898,8 @@ struct qlcnic_ipaddr {
#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_DEF_NUM_STS_DESC_RINGS 4
+#define QLCNIC_MIN_NUM_RSS_RINGS 2
#define QLCNIC_MSIX_TBL_SPACE 8192
#define QLCNIC_PCI_REG_MSIX_TBL 0x44
#define QLCNIC_MSIX_TBL_PGSIZE 4096
@@ -942,6 +912,7 @@ struct qlcnic_ipaddr {
#define __QLCNIC_RESETTING 2
#define __QLCNIC_START_FW 4
#define __QLCNIC_AER 5
+#define __QLCNIC_DIAG_RES_ALLOC 6
#define QLCNIC_INTERRUPT_TEST 1
#define QLCNIC_LOOPBACK_TEST 2
@@ -965,14 +936,14 @@ struct qlcnic_filter_hash {
};
struct qlcnic_adapter {
- struct qlcnic_hardware_context ahw;
-
+ struct qlcnic_hardware_context *ahw;
+ struct qlcnic_recv_context *recv_ctx;
+ struct qlcnic_host_tx_ring *tx_ring;
struct net_device *netdev;
struct pci_dev *pdev;
- struct list_head mac_list;
- spinlock_t tx_clean_lock;
- spinlock_t mac_learn_lock;
+ unsigned long state;
+ u32 flags;
u16 num_txd;
u16 num_rxd;
@@ -983,14 +954,12 @@ struct qlcnic_adapter {
u8 max_rds_rings;
u8 max_sds_rings;
u8 msix_supported;
- u8 rx_csum;
u8 portnum;
u8 physical_port;
u8 reset_context;
u8 mc_enabled;
u8 max_mc_count;
- u8 rss_supported;
u8 fw_wait_cnt;
u8 fw_fail_cnt;
u8 tx_timeo_cnt;
@@ -1015,7 +984,6 @@ struct qlcnic_adapter {
u32 fw_hal_version;
u32 capabilities;
- u32 flags;
u32 irq;
u32 temp;
@@ -1033,31 +1001,29 @@ struct qlcnic_adapter {
u8 mac_addr[ETH_ALEN];
u64 dev_rst_time;
+ unsigned long vlans[BITS_TO_LONGS(VLAN_N_VID)];
- struct vlan_group *vlgrp;
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;
- struct qlcnic_host_tx_ring *tx_ring;
+ struct list_head mac_list;
void __iomem *tgt_mask_reg;
void __iomem *tgt_status_reg;
void __iomem *crb_int_state_reg;
void __iomem *isr_int_vec;
- struct msix_entry msix_entries[MSIX_ENTRIES_PER_ADAPTER];
+ struct msix_entry *msix_entries;
struct delayed_work fw_work;
- struct qlcnic_nic_intr_coalesce coal;
struct qlcnic_filter_hash fhash;
- unsigned long state;
+ spinlock_t tx_clean_lock;
+ spinlock_t mac_learn_lock;
__le32 file_prd_off; /*File fw product offset*/
u32 fw_version;
const struct firmware *fw;
@@ -1079,7 +1045,7 @@ struct qlcnic_info {
__le16 min_tx_bw;
__le16 max_tx_bw;
u8 reserved2[104];
-};
+} __packed;
struct qlcnic_pci_info {
__le16 id; /* pci function id */
@@ -1093,7 +1059,7 @@ struct qlcnic_pci_info {
u8 mac[ETH_ALEN];
u8 reserved2[106];
-};
+} __packed;
struct qlcnic_npar_info {
u16 pvid;
@@ -1210,15 +1176,160 @@ struct __qlcnic_esw_statistics {
__le64 local_frames;
__le64 numbytes;
__le64 rsvd[3];
-};
+} __packed;
struct qlcnic_esw_statistics {
struct __qlcnic_esw_statistics rx;
struct __qlcnic_esw_statistics tx;
};
-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);
+struct qlcnic_common_entry_hdr {
+ __le32 type;
+ __le32 offset;
+ __le32 cap_size;
+ u8 mask;
+ u8 rsvd[2];
+ u8 flags;
+} __packed;
+
+struct __crb {
+ __le32 addr;
+ u8 stride;
+ u8 rsvd1[3];
+ __le32 data_size;
+ __le32 no_ops;
+ __le32 rsvd2[4];
+} __packed;
+
+struct __ctrl {
+ __le32 addr;
+ u8 stride;
+ u8 index_a;
+ __le16 timeout;
+ __le32 data_size;
+ __le32 no_ops;
+ u8 opcode;
+ u8 index_v;
+ u8 shl_val;
+ u8 shr_val;
+ __le32 val1;
+ __le32 val2;
+ __le32 val3;
+} __packed;
+
+struct __cache {
+ __le32 addr;
+ u8 stride;
+ u8 rsvd;
+ __le16 init_tag_val;
+ __le32 size;
+ __le32 no_ops;
+ __le32 ctrl_addr;
+ __le32 ctrl_val;
+ __le32 read_addr;
+ u8 read_addr_stride;
+ u8 read_addr_num;
+ u8 rsvd1[2];
+} __packed;
+
+struct __ocm {
+ u8 rsvd[8];
+ __le32 size;
+ __le32 no_ops;
+ u8 rsvd1[8];
+ __le32 read_addr;
+ __le32 read_addr_stride;
+} __packed;
+
+struct __mem {
+ u8 rsvd[24];
+ __le32 addr;
+ __le32 size;
+} __packed;
+
+struct __mux {
+ __le32 addr;
+ u8 rsvd[4];
+ __le32 size;
+ __le32 no_ops;
+ __le32 val;
+ __le32 val_stride;
+ __le32 read_addr;
+ u8 rsvd2[4];
+} __packed;
+
+struct __queue {
+ __le32 sel_addr;
+ __le16 stride;
+ u8 rsvd[2];
+ __le32 size;
+ __le32 no_ops;
+ u8 rsvd2[8];
+ __le32 read_addr;
+ u8 read_addr_stride;
+ u8 read_addr_cnt;
+ u8 rsvd3[2];
+} __packed;
+
+struct qlcnic_dump_entry {
+ struct qlcnic_common_entry_hdr hdr;
+ union {
+ struct __crb crb;
+ struct __cache cache;
+ struct __ocm ocm;
+ struct __mem mem;
+ struct __mux mux;
+ struct __queue que;
+ struct __ctrl ctrl;
+ } region;
+} __packed;
+
+enum op_codes {
+ QLCNIC_DUMP_NOP = 0,
+ QLCNIC_DUMP_READ_CRB = 1,
+ QLCNIC_DUMP_READ_MUX = 2,
+ QLCNIC_DUMP_QUEUE = 3,
+ QLCNIC_DUMP_BRD_CONFIG = 4,
+ QLCNIC_DUMP_READ_OCM = 6,
+ QLCNIC_DUMP_PEG_REG = 7,
+ QLCNIC_DUMP_L1_DTAG = 8,
+ QLCNIC_DUMP_L1_ITAG = 9,
+ QLCNIC_DUMP_L1_DATA = 11,
+ QLCNIC_DUMP_L1_INST = 12,
+ QLCNIC_DUMP_L2_DTAG = 21,
+ QLCNIC_DUMP_L2_ITAG = 22,
+ QLCNIC_DUMP_L2_DATA = 23,
+ QLCNIC_DUMP_L2_INST = 24,
+ QLCNIC_DUMP_READ_ROM = 71,
+ QLCNIC_DUMP_READ_MEM = 72,
+ QLCNIC_DUMP_READ_CTRL = 98,
+ QLCNIC_DUMP_TLHDR = 99,
+ QLCNIC_DUMP_RDEND = 255
+};
+
+#define QLCNIC_DUMP_WCRB BIT_0
+#define QLCNIC_DUMP_RWCRB BIT_1
+#define QLCNIC_DUMP_ANDCRB BIT_2
+#define QLCNIC_DUMP_ORCRB BIT_3
+#define QLCNIC_DUMP_POLLCRB BIT_4
+#define QLCNIC_DUMP_RD_SAVE BIT_5
+#define QLCNIC_DUMP_WRT_SAVED BIT_6
+#define QLCNIC_DUMP_MOD_SAVE_ST BIT_7
+#define QLCNIC_DUMP_SKIP BIT_7
+
+#define QLCNIC_DUMP_MASK_MIN 3
+#define QLCNIC_DUMP_MASK_DEF 0x0f
+#define QLCNIC_DUMP_MASK_MAX 0xff
+#define QLCNIC_FORCE_FW_DUMP_KEY 0xdeadfeed
+
+struct qlcnic_dump_operations {
+ enum op_codes opcode;
+ u32 (*handler)(struct qlcnic_adapter *,
+ struct qlcnic_dump_entry *, u32 *);
+};
+
+int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter);
+int qlcnic_fw_cmd_set_port(struct qlcnic_adapter *adapter, u32 config);
u32 qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off);
int qlcnic_hw_write_wx_2M(struct qlcnic_adapter *, ulong off, u32 data);
@@ -1264,6 +1375,7 @@ int qlcnic_wol_supported(struct qlcnic_adapter *adapter);
int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate);
void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter);
void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter);
+int qlcnic_dump_fw(struct qlcnic_adapter *);
/* Functions from qlcnic_init.c */
int qlcnic_load_firmware(struct qlcnic_adapter *adapter);
@@ -1274,7 +1386,7 @@ 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(struct qlcnic_adapter *adapter, u32 addr, u32 *valp);
int qlcnic_rom_fast_read_words(struct qlcnic_adapter *adapter, int addr,
u8 *bytes, size_t size);
int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter);
@@ -1294,7 +1406,7 @@ void qlcnic_release_tx_buffers(struct qlcnic_adapter *adapter);
int qlcnic_check_fw_status(struct qlcnic_adapter *adapter);
void qlcnic_watchdog_task(struct work_struct *work);
-void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, u32 ringid,
+void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter,
struct qlcnic_host_rds_ring *rds_ring);
int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max);
void qlcnic_set_multi(struct net_device *netdev);
@@ -1308,6 +1420,8 @@ 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);
+u32 qlcnic_fix_features(struct net_device *netdev, u32 features);
+int qlcnic_set_features(struct net_device *netdev, u32 features);
int qlcnic_config_hw_lro(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);
@@ -1322,6 +1436,9 @@ u32 qlcnic_issue_cmd(struct qlcnic_adapter *adapter,
void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings);
int qlcnic_diag_alloc_res(struct net_device *netdev, int test);
netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
+int qlcnic_validate_max_rss(struct net_device *netdev, u8 max_hw, u8 val);
+int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data);
+void qlcnic_dev_request_reset(struct qlcnic_adapter *);
/* Management functions */
int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*);
@@ -1379,8 +1496,7 @@ static const struct qlcnic_brdinfo qlcnic_boards[] = {
static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring)
{
- smp_mb();
- if (tx_ring->producer < tx_ring->sw_consumer)
+ if (likely(tx_ring->producer < tx_ring->sw_consumer))
return tx_ring->sw_consumer - tx_ring->producer;
else
return tx_ring->sw_consumer + tx_ring->num_desc -
diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c
index 27631f23b3fd..bab041a5c758 100644
--- a/drivers/net/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/qlcnic/qlcnic_ctx.c
@@ -64,14 +64,105 @@ qlcnic_issue_cmd(struct qlcnic_adapter *adapter,
return rcode;
}
+static uint32_t qlcnic_temp_checksum(uint32_t *temp_buffer, u16 temp_size)
+{
+ uint64_t sum = 0;
+ int count = temp_size / sizeof(uint32_t);
+ while (count-- > 0)
+ sum += *temp_buffer++;
+ while (sum >> 32)
+ sum = (sum & 0xFFFFFFFF) + (sum >> 32);
+ return ~sum;
+}
+
+int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter)
+{
+ int err, i;
+ u16 temp_size;
+ void *tmp_addr;
+ u32 version, csum, *template, *tmp_buf;
+ struct qlcnic_hardware_context *ahw;
+ struct qlcnic_dump_template_hdr *tmpl_hdr, *tmp_tmpl;
+ dma_addr_t tmp_addr_t = 0;
+
+ ahw = adapter->ahw;
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw->pci_func,
+ adapter->fw_hal_version,
+ 0,
+ 0,
+ 0,
+ QLCNIC_CDRP_CMD_TEMP_SIZE);
+ if (err != QLCNIC_RCODE_SUCCESS) {
+ err = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
+ dev_err(&adapter->pdev->dev,
+ "Failed to get template size %d\n", err);
+ err = -EIO;
+ return err;
+ }
+ version = QLCRD32(adapter, QLCNIC_ARG3_CRB_OFFSET);
+ temp_size = QLCRD32(adapter, QLCNIC_ARG2_CRB_OFFSET);
+ if (!temp_size)
+ return -EIO;
+
+ tmp_addr = dma_alloc_coherent(&adapter->pdev->dev, temp_size,
+ &tmp_addr_t, GFP_KERNEL);
+ if (!tmp_addr) {
+ dev_err(&adapter->pdev->dev,
+ "Can't get memory for FW dump template\n");
+ return -ENOMEM;
+ }
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw->pci_func,
+ adapter->fw_hal_version,
+ LSD(tmp_addr_t),
+ MSD(tmp_addr_t),
+ temp_size,
+ QLCNIC_CDRP_CMD_GET_TEMP_HDR);
+
+ if (err != QLCNIC_RCODE_SUCCESS) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to get mini dump template header %d\n", err);
+ err = -EIO;
+ goto error;
+ }
+ tmp_tmpl = (struct qlcnic_dump_template_hdr *) tmp_addr;
+ csum = qlcnic_temp_checksum((uint32_t *) tmp_addr, temp_size);
+ if (csum) {
+ dev_err(&adapter->pdev->dev,
+ "Template header checksum validation failed\n");
+ err = -EIO;
+ goto error;
+ }
+ ahw->fw_dump.tmpl_hdr = vzalloc(temp_size);
+ if (!ahw->fw_dump.tmpl_hdr) {
+ err = -EIO;
+ goto error;
+ }
+ tmp_buf = (u32 *) tmp_addr;
+ template = (u32 *) ahw->fw_dump.tmpl_hdr;
+ for (i = 0; i < temp_size/sizeof(u32); i++)
+ *template++ = __le32_to_cpu(*tmp_buf++);
+
+ tmpl_hdr = ahw->fw_dump.tmpl_hdr;
+ if (tmpl_hdr->cap_mask > QLCNIC_DUMP_MASK_DEF &&
+ tmpl_hdr->cap_mask <= QLCNIC_DUMP_MASK_MAX)
+ tmpl_hdr->drv_cap_mask = tmpl_hdr->cap_mask;
+ else
+ tmpl_hdr->drv_cap_mask = QLCNIC_DUMP_MASK_DEF;
+error:
+ dma_free_coherent(&adapter->pdev->dev, temp_size, tmp_addr, tmp_addr_t);
+ return err;
+}
+
int
qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu)
{
- struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
if (recv_ctx->state == QLCNIC_HOST_CTX_STATE_ACTIVE) {
if (qlcnic_issue_cmd(adapter,
- adapter->ahw.pci_func,
+ adapter->ahw->pci_func,
adapter->fw_hal_version,
recv_ctx->context_id,
mtu,
@@ -102,12 +193,12 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
dma_addr_t hostrq_phys_addr, cardrsp_phys_addr;
u64 phys_addr;
- int i, nrds_rings, nsds_rings;
+ u8 i, nrds_rings, nsds_rings;
size_t rq_size, rsp_size;
u32 cap, reg, val, reg2;
int err;
- struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
nrds_rings = adapter->max_rds_rings;
nsds_rings = adapter->max_sds_rings;
@@ -119,14 +210,14 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
SIZEOF_CARDRSP_RX(struct qlcnic_cardrsp_rx_ctx, nrds_rings,
nsds_rings);
- addr = pci_alloc_consistent(adapter->pdev,
- rq_size, &hostrq_phys_addr);
+ addr = dma_alloc_coherent(&adapter->pdev->dev, rq_size,
+ &hostrq_phys_addr, GFP_KERNEL);
if (addr == NULL)
return -ENOMEM;
prq = (struct qlcnic_hostrq_rx_ctx *)addr;
- addr = pci_alloc_consistent(adapter->pdev,
- rsp_size, &cardrsp_phys_addr);
+ addr = dma_alloc_coherent(&adapter->pdev->dev, rsp_size,
+ &cardrsp_phys_addr, GFP_KERNEL);
if (addr == NULL) {
err = -ENOMEM;
goto out_free_rq;
@@ -151,7 +242,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
prq->num_rds_rings = cpu_to_le16(nrds_rings);
prq->num_sds_rings = cpu_to_le16(nsds_rings);
- prq->rds_ring_offset = cpu_to_le32(0);
+ prq->rds_ring_offset = 0;
val = le32_to_cpu(prq->rds_ring_offset) +
(sizeof(struct qlcnic_hostrq_rds_ring) * nrds_rings);
@@ -187,7 +278,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,
+ adapter->ahw->pci_func,
adapter->fw_hal_version,
(u32)(phys_addr >> 32),
(u32)(phys_addr & 0xffffffff),
@@ -207,7 +298,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 = adapter->ahw.pci_base0 + reg;
+ rds_ring->crb_rcv_producer = adapter->ahw->pci_base0 + reg;
}
prsp_sds = ((struct qlcnic_cardrsp_sds_ring *)
@@ -219,8 +310,8 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
reg = le32_to_cpu(prsp_sds[i].host_consumer_crb);
reg2 = le32_to_cpu(prsp_sds[i].interrupt_crb);
- sds_ring->crb_sts_consumer = adapter->ahw.pci_base0 + reg;
- sds_ring->crb_intr_mask = adapter->ahw.pci_base0 + reg2;
+ 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);
@@ -228,19 +319,20 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
recv_ctx->virt_port = prsp->virt_port;
out_free_rsp:
- pci_free_consistent(adapter->pdev, rsp_size, prsp, cardrsp_phys_addr);
+ dma_free_coherent(&adapter->pdev->dev, rsp_size, prsp,
+ cardrsp_phys_addr);
out_free_rq:
- pci_free_consistent(adapter->pdev, rq_size, prq, hostrq_phys_addr);
+ dma_free_coherent(&adapter->pdev->dev, rq_size, prq, hostrq_phys_addr);
return err;
}
static void
qlcnic_fw_cmd_destroy_rx_ctx(struct qlcnic_adapter *adapter)
{
- struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
if (qlcnic_issue_cmd(adapter,
- adapter->ahw.pci_func,
+ adapter->ahw->pci_func,
adapter->fw_hal_version,
recv_ctx->context_id,
QLCNIC_DESTROY_CTX_RESET,
@@ -274,14 +366,14 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
*(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);
+ rq_addr = dma_alloc_coherent(&adapter->pdev->dev, rq_size,
+ &rq_phys_addr, GFP_KERNEL);
if (!rq_addr)
return -ENOMEM;
rsp_size = SIZEOF_CARDRSP_TX(struct qlcnic_cardrsp_tx_ctx);
- rsp_addr = pci_alloc_consistent(adapter->pdev,
- rsp_size, &rsp_phys_addr);
+ rsp_addr = dma_alloc_coherent(&adapter->pdev->dev, rsp_size,
+ &rsp_phys_addr, GFP_KERNEL);
if (!rsp_addr) {
err = -ENOMEM;
goto out_free_rq;
@@ -313,7 +405,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,
+ adapter->ahw->pci_func,
adapter->fw_hal_version,
(u32)(phys_addr >> 32),
((u32)phys_addr & 0xffffffff),
@@ -322,7 +414,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 = adapter->ahw.pci_base0 + temp;
+ tx_ring->crb_cmd_producer = adapter->ahw->pci_base0 + temp;
adapter->tx_context_id =
le16_to_cpu(prsp->context_id);
@@ -332,10 +424,11 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
err = -EIO;
}
- pci_free_consistent(adapter->pdev, rsp_size, rsp_addr, rsp_phys_addr);
+ dma_free_coherent(&adapter->pdev->dev, rsp_size, rsp_addr,
+ rsp_phys_addr);
out_free_rq:
- pci_free_consistent(adapter->pdev, rq_size, rq_addr, rq_phys_addr);
+ dma_free_coherent(&adapter->pdev->dev, rq_size, rq_addr, rq_phys_addr);
return err;
}
@@ -344,7 +437,7 @@ static void
qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter)
{
if (qlcnic_issue_cmd(adapter,
- adapter->ahw.pci_func,
+ adapter->ahw->pci_func,
adapter->fw_hal_version,
adapter->tx_context_id,
QLCNIC_DESTROY_CTX_RESET,
@@ -357,33 +450,15 @@ qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter)
}
int
-qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val)
-{
-
- if (qlcnic_issue_cmd(adapter,
- adapter->ahw.pci_func,
- adapter->fw_hal_version,
- reg,
- 0,
- 0,
- QLCNIC_CDRP_CMD_READ_PHY)) {
-
- return -EIO;
- }
-
- return QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
-}
-
-int
-qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val)
+qlcnic_fw_cmd_set_port(struct qlcnic_adapter *adapter, u32 config)
{
return qlcnic_issue_cmd(adapter,
- adapter->ahw.pci_func,
+ adapter->ahw->pci_func,
adapter->fw_hal_version,
- reg,
- val,
+ config,
+ 0,
0,
- QLCNIC_CDRP_CMD_WRITE_PHY);
+ QLCNIC_CDRP_CMD_CONFIG_PORT);
}
int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter)
@@ -398,20 +473,19 @@ int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter)
struct pci_dev *pdev = adapter->pdev;
- recv_ctx = &adapter->recv_ctx;
+ recv_ctx = adapter->recv_ctx;
tx_ring = adapter->tx_ring;
- tx_ring->hw_consumer = (__le32 *)pci_alloc_consistent(pdev, sizeof(u32),
- &tx_ring->hw_cons_phys_addr);
+ tx_ring->hw_consumer = (__le32 *) dma_alloc_coherent(&pdev->dev,
+ sizeof(u32), &tx_ring->hw_cons_phys_addr, GFP_KERNEL);
if (tx_ring->hw_consumer == NULL) {
dev_err(&pdev->dev, "failed to allocate tx consumer\n");
return -ENOMEM;
}
- *(tx_ring->hw_consumer) = 0;
/* cmd desc ring */
- addr = pci_alloc_consistent(pdev, TX_DESC_RINGSIZE(tx_ring),
- &tx_ring->phys_addr);
+ addr = dma_alloc_coherent(&pdev->dev, TX_DESC_RINGSIZE(tx_ring),
+ &tx_ring->phys_addr, GFP_KERNEL);
if (addr == NULL) {
dev_err(&pdev->dev, "failed to allocate tx desc ring\n");
@@ -423,9 +497,9 @@ int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter)
for (ring = 0; ring < adapter->max_rds_rings; ring++) {
rds_ring = &recv_ctx->rds_rings[ring];
- addr = pci_alloc_consistent(adapter->pdev,
+ addr = dma_alloc_coherent(&adapter->pdev->dev,
RCV_DESC_RINGSIZE(rds_ring),
- &rds_ring->phys_addr);
+ &rds_ring->phys_addr, GFP_KERNEL);
if (addr == NULL) {
dev_err(&pdev->dev,
"failed to allocate rds ring [%d]\n", ring);
@@ -439,9 +513,9 @@ int qlcnic_alloc_hw_resources(struct qlcnic_adapter *adapter)
for (ring = 0; ring < adapter->max_sds_rings; ring++) {
sds_ring = &recv_ctx->sds_rings[ring];
- addr = pci_alloc_consistent(adapter->pdev,
+ addr = dma_alloc_coherent(&adapter->pdev->dev,
STATUS_DESC_RINGSIZE(sds_ring),
- &sds_ring->phys_addr);
+ &sds_ring->phys_addr, GFP_KERNEL);
if (addr == NULL) {
dev_err(&pdev->dev,
"failed to allocate sds ring [%d]\n", ring);
@@ -501,11 +575,11 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
struct qlcnic_host_tx_ring *tx_ring;
int ring;
- recv_ctx = &adapter->recv_ctx;
+ recv_ctx = adapter->recv_ctx;
tx_ring = adapter->tx_ring;
if (tx_ring->hw_consumer != NULL) {
- pci_free_consistent(adapter->pdev,
+ dma_free_coherent(&adapter->pdev->dev,
sizeof(u32),
tx_ring->hw_consumer,
tx_ring->hw_cons_phys_addr);
@@ -513,7 +587,7 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
}
if (tx_ring->desc_head != NULL) {
- pci_free_consistent(adapter->pdev,
+ dma_free_coherent(&adapter->pdev->dev,
TX_DESC_RINGSIZE(tx_ring),
tx_ring->desc_head, tx_ring->phys_addr);
tx_ring->desc_head = NULL;
@@ -523,7 +597,7 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
rds_ring = &recv_ctx->rds_rings[ring];
if (rds_ring->desc_head != NULL) {
- pci_free_consistent(adapter->pdev,
+ dma_free_coherent(&adapter->pdev->dev,
RCV_DESC_RINGSIZE(rds_ring),
rds_ring->desc_head,
rds_ring->phys_addr);
@@ -535,7 +609,7 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
sds_ring = &recv_ctx->sds_rings[ring];
if (sds_ring->desc_head != NULL) {
- pci_free_consistent(adapter->pdev,
+ dma_free_coherent(&adapter->pdev->dev,
STATUS_DESC_RINGSIZE(sds_ring),
sds_ring->desc_head,
sds_ring->phys_addr);
@@ -551,9 +625,9 @@ int qlcnic_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
int err;
u32 arg1;
- arg1 = adapter->ahw.pci_func | BIT_8;
+ arg1 = adapter->ahw->pci_func | BIT_8;
err = qlcnic_issue_cmd(adapter,
- adapter->ahw.pci_func,
+ adapter->ahw->pci_func,
adapter->fw_hal_version,
arg1,
0,
@@ -582,15 +656,15 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter,
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);
+ nic_info_addr = dma_alloc_coherent(&adapter->pdev->dev, nic_size,
+ &nic_dma_t, GFP_KERNEL);
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->ahw->pci_func,
adapter->fw_hal_version,
MSD(nic_dma_t),
LSD(nic_dma_t),
@@ -623,7 +697,8 @@ int qlcnic_get_nic_info(struct qlcnic_adapter *adapter,
err = -EIO;
}
- pci_free_consistent(adapter->pdev, nic_size, nic_info_addr, nic_dma_t);
+ dma_free_coherent(&adapter->pdev->dev, nic_size, nic_info_addr,
+ nic_dma_t);
return err;
}
@@ -639,8 +714,8 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
if (adapter->op_mode != QLCNIC_MGMT_FUNC)
return err;
- nic_info_addr = pci_alloc_consistent(adapter->pdev, nic_size,
- &nic_dma_t);
+ nic_info_addr = dma_alloc_coherent(&adapter->pdev->dev, nic_size,
+ &nic_dma_t, GFP_KERNEL);
if (!nic_info_addr)
return -ENOMEM;
@@ -659,7 +734,7 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
nic_info->max_tx_bw = cpu_to_le16(nic->max_tx_bw);
err = qlcnic_issue_cmd(adapter,
- adapter->ahw.pci_func,
+ adapter->ahw->pci_func,
adapter->fw_hal_version,
MSD(nic_dma_t),
LSD(nic_dma_t),
@@ -672,7 +747,8 @@ int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
err = -EIO;
}
- pci_free_consistent(adapter->pdev, nic_size, nic_info_addr, nic_dma_t);
+ dma_free_coherent(&adapter->pdev->dev, nic_size, nic_info_addr,
+ nic_dma_t);
return err;
}
@@ -687,15 +763,15 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter,
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);
+ pci_info_addr = dma_alloc_coherent(&adapter->pdev->dev, pci_size,
+ &pci_info_dma_t, GFP_KERNEL);
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->ahw->pci_func,
adapter->fw_hal_version,
MSD(pci_info_dma_t),
LSD(pci_info_dma_t),
@@ -721,7 +797,7 @@ int qlcnic_get_pci_info(struct qlcnic_adapter *adapter,
err = -EIO;
}
- pci_free_consistent(adapter->pdev, pci_size, pci_info_addr,
+ dma_free_coherent(&adapter->pdev->dev, pci_size, pci_info_addr,
pci_info_dma_t);
return err;
}
@@ -741,7 +817,7 @@ int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id,
arg1 |= pci_func << 8;
err = qlcnic_issue_cmd(adapter,
- adapter->ahw.pci_func,
+ adapter->ahw->pci_func,
adapter->fw_hal_version,
arg1,
0,
@@ -775,14 +851,14 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func,
return -ENOMEM;
if (adapter->op_mode != QLCNIC_MGMT_FUNC &&
- func != adapter->ahw.pci_func) {
+ func != adapter->ahw->pci_func) {
dev_err(&adapter->pdev->dev,
"Not privilege to query stats for func=%d", func);
return -EIO;
}
- stats_addr = pci_alloc_consistent(adapter->pdev, stats_size,
- &stats_dma_t);
+ stats_addr = dma_alloc_coherent(&adapter->pdev->dev, stats_size,
+ &stats_dma_t, GFP_KERNEL);
if (!stats_addr) {
dev_err(&adapter->pdev->dev, "Unable to allocate memory\n");
return -ENOMEM;
@@ -793,7 +869,7 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func,
arg1 |= rx_tx << 15 | stats_size << 16;
err = qlcnic_issue_cmd(adapter,
- adapter->ahw.pci_func,
+ adapter->ahw->pci_func,
adapter->fw_hal_version,
arg1,
MSD(stats_dma_t),
@@ -816,7 +892,7 @@ int qlcnic_get_port_stats(struct qlcnic_adapter *adapter, const u8 func,
esw_stats->numbytes = le64_to_cpu(stats->numbytes);
}
- pci_free_consistent(adapter->pdev, stats_size, stats_addr,
+ dma_free_coherent(&adapter->pdev->dev, stats_size, stats_addr,
stats_dma_t);
return err;
}
@@ -900,7 +976,7 @@ int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, const u8 func_esw,
arg1 |= BIT_14 | rx_tx << 15;
return qlcnic_issue_cmd(adapter,
- adapter->ahw.pci_func,
+ adapter->ahw->pci_func,
adapter->fw_hal_version,
arg1,
0,
@@ -921,7 +997,7 @@ __qlcnic_get_eswitch_port_config(struct qlcnic_adapter *adapter,
u8 pci_func;
pci_func = (*arg1 >> 8);
err = qlcnic_issue_cmd(adapter,
- adapter->ahw.pci_func,
+ adapter->ahw->pci_func,
adapter->fw_hal_version,
*arg1,
0,
@@ -999,7 +1075,7 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter,
}
err = qlcnic_issue_cmd(adapter,
- adapter->ahw.pci_func,
+ adapter->ahw->pci_func,
adapter->fw_hal_version,
arg1,
arg2,
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c
index 45b2755d6cba..9efc690a289f 100644
--- a/drivers/net/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/qlcnic/qlcnic_ethtool.c
@@ -150,10 +150,10 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
int check_sfp_module = 0;
- u16 pcifn = adapter->ahw.pci_func;
+ u16 pcifn = adapter->ahw->pci_func;
/* read which mode */
- if (adapter->ahw.port_type == QLCNIC_GBE) {
+ if (adapter->ahw->port_type == QLCNIC_GBE) {
ecmd->supported = (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
@@ -166,11 +166,11 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
ADVERTISED_1000baseT_Half |
ADVERTISED_1000baseT_Full);
- ecmd->speed = adapter->link_speed;
+ ethtool_cmd_speed_set(ecmd, adapter->link_speed);
ecmd->duplex = adapter->link_duplex;
ecmd->autoneg = adapter->link_autoneg;
- } else if (adapter->ahw.port_type == QLCNIC_XGBE) {
+ } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
u32 val;
val = QLCRD32(adapter, QLCNIC_PORT_MODE_ADDR);
@@ -183,15 +183,15 @@ qlcnic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
}
if (netif_running(dev) && adapter->has_link_events) {
- ecmd->speed = adapter->link_speed;
+ ethtool_cmd_speed_set(ecmd, adapter->link_speed);
ecmd->autoneg = adapter->link_autoneg;
ecmd->duplex = adapter->link_duplex;
goto skip;
}
val = QLCRD32(adapter, P3P_LINK_SPEED_REG(pcifn));
- ecmd->speed = P3P_LINK_SPEED_MHZ *
- P3P_LINK_SPEED_VAL(pcifn, val);
+ ethtool_cmd_speed_set(ecmd, P3P_LINK_SPEED_MHZ *
+ P3P_LINK_SPEED_VAL(pcifn, val));
ecmd->duplex = DUPLEX_FULL;
ecmd->autoneg = AUTONEG_DISABLE;
} else
@@ -201,7 +201,7 @@ skip:
ecmd->phy_address = adapter->physical_port;
ecmd->transceiver = XCVR_EXTERNAL;
- switch (adapter->ahw.board_type) {
+ switch (adapter->ahw->board_type) {
case QLCNIC_BRDTYPE_P3P_REF_QG:
case QLCNIC_BRDTYPE_P3P_4_GB:
case QLCNIC_BRDTYPE_P3P_4_GB_MM:
@@ -238,7 +238,7 @@ skip:
ecmd->autoneg = AUTONEG_DISABLE;
break;
case QLCNIC_BRDTYPE_P3P_10G_TP:
- if (adapter->ahw.port_type == QLCNIC_XGBE) {
+ if (adapter->ahw->port_type == QLCNIC_XGBE) {
ecmd->autoneg = AUTONEG_DISABLE;
ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP);
ecmd->advertising |=
@@ -256,7 +256,7 @@ skip:
break;
default:
dev_err(&adapter->pdev->dev, "Unsupported board model %d\n",
- adapter->ahw.board_type);
+ adapter->ahw->board_type);
return -EIO;
}
@@ -284,50 +284,44 @@ skip:
static int
qlcnic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
{
+ u32 config = 0;
+ u32 ret = 0;
struct qlcnic_adapter *adapter = netdev_priv(dev);
- __u32 status;
+
+ if (adapter->ahw->port_type != QLCNIC_GBE)
+ return -EOPNOTSUPP;
/* read which mode */
- if (adapter->ahw.port_type == QLCNIC_GBE) {
- /* autonegotiation */
- if (qlcnic_fw_cmd_set_phy(adapter,
- QLCNIC_NIU_GB_MII_MGMT_ADDR_AUTONEG,
- ecmd->autoneg) != 0)
- return -EIO;
- else
- adapter->link_autoneg = ecmd->autoneg;
+ if (ecmd->duplex)
+ config |= 0x1;
- if (qlcnic_fw_cmd_query_phy(adapter,
- QLCNIC_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
- &status) != 0)
- return -EIO;
+ if (ecmd->autoneg)
+ config |= 0x2;
- switch (ecmd->speed) {
- case SPEED_10:
- qlcnic_set_phy_speed(status, 0);
- break;
- case SPEED_100:
- qlcnic_set_phy_speed(status, 1);
- break;
- case SPEED_1000:
- qlcnic_set_phy_speed(status, 2);
- break;
- }
+ switch (ethtool_cmd_speed(ecmd)) {
+ case SPEED_10:
+ config |= (0 << 8);
+ break;
+ case SPEED_100:
+ config |= (1 << 8);
+ break;
+ case SPEED_1000:
+ config |= (10 << 8);
+ break;
+ default:
+ return -EIO;
+ }
- if (ecmd->duplex == DUPLEX_HALF)
- qlcnic_clear_phy_duplex(status);
- if (ecmd->duplex == DUPLEX_FULL)
- qlcnic_set_phy_duplex(status);
- if (qlcnic_fw_cmd_set_phy(adapter,
- QLCNIC_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
- *((int *)&status)) != 0)
- return -EIO;
- else {
- adapter->link_speed = ecmd->speed;
- adapter->link_duplex = ecmd->duplex;
- }
- } else
+ ret = qlcnic_fw_cmd_set_port(adapter, config);
+
+ if (ret == QLCNIC_RCODE_NOT_SUPPORTED)
return -EOPNOTSUPP;
+ else if (ret)
+ return -EIO;
+
+ adapter->link_speed = ethtool_cmd_speed(ecmd);
+ adapter->link_duplex = ecmd->duplex;
+ adapter->link_autoneg = ecmd->autoneg;
if (!netif_running(dev))
return 0;
@@ -340,14 +334,14 @@ static void
qlcnic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p)
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
- struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
struct qlcnic_host_sds_ring *sds_ring;
u32 *regs_buff = p;
int ring, i = 0, j = 0;
memset(p, 0, qlcnic_get_regs_len(dev));
regs->version = (QLCNIC_ETHTOOL_REGS_VER << 24) |
- (adapter->ahw.revision_id << 16) | (adapter->pdev)->device;
+ (adapter->ahw->revision_id << 16) | (adapter->pdev)->device;
regs_buff[0] = (0xcafe0000 | (QLCNIC_DEV_INFO_SIZE & 0xffff));
regs_buff[1] = QLCNIC_MGMT_API_VERSION;
@@ -382,7 +376,7 @@ static u32 qlcnic_test_link(struct net_device *dev)
u32 val;
val = QLCRD32(adapter, CRB_XG_STATE_P3P);
- val = XG_LINK_STATE_P3P(adapter->ahw.pci_func, val);
+ val = XG_LINK_STATE_P3P(adapter->ahw->pci_func, val);
return (val == XG_LINK_UP_P3P) ? 0 : 1;
}
@@ -474,6 +468,39 @@ qlcnic_set_ringparam(struct net_device *dev,
return qlcnic_reset_context(adapter);
}
+static void qlcnic_get_channels(struct net_device *dev,
+ struct ethtool_channels *channel)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
+
+ channel->max_rx = rounddown_pow_of_two(min_t(int,
+ adapter->max_rx_ques, num_online_cpus()));
+ channel->max_tx = adapter->max_tx_ques;
+
+ channel->rx_count = adapter->max_sds_rings;
+ channel->tx_count = adapter->max_tx_ques;
+}
+
+static int qlcnic_set_channels(struct net_device *dev,
+ struct ethtool_channels *channel)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(dev);
+ int err;
+
+ if (channel->other_count || channel->combined_count ||
+ channel->tx_count != channel->max_tx)
+ return -EINVAL;
+
+ err = qlcnic_validate_max_rss(dev, channel->max_rx, channel->rx_count);
+ if (err)
+ return err;
+
+ err = qlcnic_set_max_rss(adapter, channel->rx_count);
+ netdev_info(dev, "allocated 0x%x sds rings\n",
+ adapter->max_sds_rings);
+ return err;
+}
+
static void
qlcnic_get_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause)
@@ -482,7 +509,7 @@ qlcnic_get_pauseparam(struct net_device *netdev,
int port = adapter->physical_port;
__u32 val;
- if (adapter->ahw.port_type == QLCNIC_GBE) {
+ if (adapter->ahw->port_type == QLCNIC_GBE) {
if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
return;
/* get flow control settings */
@@ -504,7 +531,7 @@ qlcnic_get_pauseparam(struct net_device *netdev,
pause->tx_pause = !(qlcnic_gb_get_gb3_mask(val));
break;
}
- } else if (adapter->ahw.port_type == QLCNIC_XGBE) {
+ } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
if ((port < 0) || (port > QLCNIC_NIU_MAX_XG_PORTS))
return;
pause->rx_pause = 1;
@@ -515,7 +542,7 @@ qlcnic_get_pauseparam(struct net_device *netdev,
pause->tx_pause = !(qlcnic_xg_get_xg1_mask(val));
} else {
dev_err(&netdev->dev, "Unknown board type: %x\n",
- adapter->ahw.port_type);
+ adapter->ahw->port_type);
}
}
@@ -528,7 +555,7 @@ qlcnic_set_pauseparam(struct net_device *netdev,
__u32 val;
/* read mode */
- if (adapter->ahw.port_type == QLCNIC_GBE) {
+ if (adapter->ahw->port_type == QLCNIC_GBE) {
if ((port < 0) || (port > QLCNIC_NIU_MAX_GBE_PORTS))
return -EIO;
/* set flow control */
@@ -571,7 +598,7 @@ qlcnic_set_pauseparam(struct net_device *netdev,
break;
}
QLCWR32(adapter, QLCNIC_NIU_GB_PAUSE_CTL, val);
- } else if (adapter->ahw.port_type == QLCNIC_XGBE) {
+ } else if (adapter->ahw->port_type == QLCNIC_XGBE) {
if (!pause->rx_pause || pause->autoneg)
return -EOPNOTSUPP;
@@ -593,7 +620,7 @@ qlcnic_set_pauseparam(struct net_device *netdev,
QLCWR32(adapter, QLCNIC_NIU_XG_PAUSE_CTL, val);
} else {
dev_err(&netdev->dev, "Unknown board type: %x\n",
- adapter->ahw.port_type);
+ adapter->ahw->port_type);
}
return 0;
}
@@ -639,8 +666,8 @@ static int qlcnic_irq_test(struct net_device *netdev)
goto clear_it;
adapter->diag_cnt = 0;
- ret = qlcnic_issue_cmd(adapter, adapter->ahw.pci_func,
- adapter->fw_hal_version, adapter->portnum,
+ ret = qlcnic_issue_cmd(adapter, adapter->ahw->pci_func,
+ adapter->fw_hal_version, adapter->ahw->pci_func,
0, 0, 0x00000011);
if (ret)
goto done;
@@ -749,14 +776,14 @@ qlcnic_get_ethtool_stats(struct net_device *dev,
return;
memset(&port_stats, 0, sizeof(struct qlcnic_esw_statistics));
- ret = qlcnic_get_port_stats(adapter, adapter->ahw.pci_func,
+ ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
QLCNIC_QUERY_RX_COUNTER, &port_stats.rx);
if (ret)
return;
qlcnic_fill_device_stats(&index, data, &port_stats.rx);
- ret = qlcnic_get_port_stats(adapter, adapter->ahw.pci_func,
+ ret = qlcnic_get_port_stats(adapter, adapter->ahw->pci_func,
QLCNIC_QUERY_TX_COUNTER, &port_stats.tx);
if (ret)
return;
@@ -764,115 +791,49 @@ qlcnic_get_ethtool_stats(struct net_device *dev,
qlcnic_fill_device_stats(&index, data, &port_stats.tx);
}
-static int qlcnic_set_tx_csum(struct net_device *dev, u32 data)
-{
- struct qlcnic_adapter *adapter = netdev_priv(dev);
-
- if ((adapter->flags & QLCNIC_ESWITCH_ENABLED))
- return -EOPNOTSUPP;
- if (data)
- dev->features |= (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
- else
- dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
-
- return 0;
-
-}
-static u32 qlcnic_get_tx_csum(struct net_device *dev)
-{
- return dev->features & NETIF_F_IP_CSUM;
-}
-
-static u32 qlcnic_get_rx_csum(struct net_device *dev)
-{
- struct qlcnic_adapter *adapter = netdev_priv(dev);
- return adapter->rx_csum;
-}
-
-static int qlcnic_set_rx_csum(struct net_device *dev, u32 data)
-{
- struct qlcnic_adapter *adapter = netdev_priv(dev);
-
- if ((adapter->flags & QLCNIC_ESWITCH_ENABLED))
- return -EOPNOTSUPP;
- if (!!data) {
- adapter->rx_csum = !!data;
- return 0;
- }
-
- if (dev->features & NETIF_F_LRO) {
- if (qlcnic_config_hw_lro(adapter, QLCNIC_LRO_DISABLED))
- return -EIO;
-
- dev->features &= ~NETIF_F_LRO;
- qlcnic_send_lro_cleanup(adapter);
- dev_info(&adapter->pdev->dev,
- "disabling LRO as rx_csum is off\n");
- }
- adapter->rx_csum = !!data;
- return 0;
-}
-
-static u32 qlcnic_get_tso(struct net_device *dev)
-{
- return (dev->features & (NETIF_F_TSO | NETIF_F_TSO6)) != 0;
-}
-
-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
- dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
-
- return 0;
-}
-
-static int qlcnic_blink_led(struct net_device *dev, u32 val)
+static int qlcnic_set_led(struct net_device *dev,
+ enum ethtool_phys_id_state state)
{
struct qlcnic_adapter *adapter = netdev_priv(dev);
int max_sds_rings = adapter->max_sds_rings;
- int dev_down = 0;
- int ret;
-
- if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
- dev_down = 1;
- if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
- return -EIO;
- ret = qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST);
- if (ret) {
- clear_bit(__QLCNIC_RESETTING, &adapter->state);
- return ret;
+ switch (state) {
+ case ETHTOOL_ID_ACTIVE:
+ if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
+ if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+ return -EIO;
+
+ if (qlcnic_diag_alloc_res(dev, QLCNIC_LED_TEST)) {
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ return -EIO;
+ }
+ set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
}
- }
- ret = adapter->nic_ops->config_led(adapter, 1, 0xf);
- if (ret) {
+ if (adapter->nic_ops->config_led(adapter, 1, 0xf) == 0)
+ return 0;
+
dev_err(&adapter->pdev->dev,
"Failed to set LED blink state.\n");
- goto done;
- }
+ break;
- msleep_interruptible(val * 1000);
+ case ETHTOOL_ID_INACTIVE:
+ if (adapter->nic_ops->config_led(adapter, 0, 0xf))
+ dev_err(&adapter->pdev->dev,
+ "Failed to reset LED blink state.\n");
- ret = adapter->nic_ops->config_led(adapter, 0, 0xf);
- if (ret) {
- dev_err(&adapter->pdev->dev,
- "Failed to reset LED blink state.\n");
- goto done;
+ break;
+
+ default:
+ return -EINVAL;
}
-done:
- if (dev_down) {
+ if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state)) {
qlcnic_diag_free_res(dev, max_sds_rings);
clear_bit(__QLCNIC_RESETTING, &adapter->state);
}
- return ret;
+ return -EIO;
}
static void
@@ -936,8 +897,8 @@ static int qlcnic_set_intr_coalesce(struct net_device *netdev,
*/
if (ethcoal->rx_coalesce_usecs > 0xffff ||
ethcoal->rx_max_coalesced_frames > 0xffff ||
- ethcoal->tx_coalesce_usecs > 0xffff ||
- ethcoal->tx_max_coalesced_frames > 0xffff ||
+ ethcoal->tx_coalesce_usecs ||
+ ethcoal->tx_max_coalesced_frames ||
ethcoal->rx_coalesce_usecs_irq ||
ethcoal->rx_max_coalesced_frames_irq ||
ethcoal->tx_coalesce_usecs_irq ||
@@ -959,21 +920,17 @@ static int qlcnic_set_intr_coalesce(struct net_device *netdev,
if (!ethcoal->rx_coalesce_usecs ||
!ethcoal->rx_max_coalesced_frames) {
- adapter->coal.flags = QLCNIC_INTR_DEFAULT;
- adapter->coal.normal.data.rx_time_us =
+ adapter->ahw->coal.flag = QLCNIC_INTR_DEFAULT;
+ adapter->ahw->coal.rx_time_us =
QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US;
- adapter->coal.normal.data.rx_packets =
+ adapter->ahw->coal.rx_packets =
QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS;
} else {
- adapter->coal.flags = 0;
- adapter->coal.normal.data.rx_time_us =
- ethcoal->rx_coalesce_usecs;
- adapter->coal.normal.data.rx_packets =
- ethcoal->rx_max_coalesced_frames;
+ adapter->ahw->coal.flag = 0;
+ adapter->ahw->coal.rx_time_us = ethcoal->rx_coalesce_usecs;
+ adapter->ahw->coal.rx_packets =
+ ethcoal->rx_max_coalesced_frames;
}
- adapter->coal.normal.data.tx_time_us = ethcoal->tx_coalesce_usecs;
- adapter->coal.normal.data.tx_packets =
- ethcoal->tx_max_coalesced_frames;
qlcnic_config_intr_coalesce(adapter);
@@ -988,66 +945,102 @@ static int qlcnic_get_intr_coalesce(struct net_device *netdev,
if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
return -EINVAL;
- ethcoal->rx_coalesce_usecs = adapter->coal.normal.data.rx_time_us;
- ethcoal->tx_coalesce_usecs = adapter->coal.normal.data.tx_time_us;
- ethcoal->rx_max_coalesced_frames =
- adapter->coal.normal.data.rx_packets;
- ethcoal->tx_max_coalesced_frames =
- adapter->coal.normal.data.tx_packets;
+ ethcoal->rx_coalesce_usecs = adapter->ahw->coal.rx_time_us;
+ ethcoal->rx_max_coalesced_frames = adapter->ahw->coal.rx_packets;
return 0;
}
-static int qlcnic_set_flags(struct net_device *netdev, u32 data)
+static u32 qlcnic_get_msglevel(struct net_device *netdev)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
- int hw_lro;
-
- if (ethtool_invalid_flags(netdev, data, ETH_FLAG_LRO))
- return -EINVAL;
-
- if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO))
- return -EINVAL;
-
- if (!adapter->rx_csum) {
- dev_info(&adapter->pdev->dev, "rx csum is off, "
- "cannot toggle lro\n");
- return -EINVAL;
- }
- if ((data & ETH_FLAG_LRO) && (netdev->features & NETIF_F_LRO))
- return 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;
- }
+ return adapter->msg_enable;
+}
- if (qlcnic_config_hw_lro(adapter, hw_lro))
- return -EIO;
+static void qlcnic_set_msglevel(struct net_device *netdev, u32 msglvl)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
- if ((hw_lro == 0) && qlcnic_send_lro_cleanup(adapter))
- return -EIO;
+ adapter->msg_enable = msglvl;
+}
+static int
+qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
+ dump->len = fw_dump->tmpl_hdr->size + fw_dump->size;
+ dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
+ dump->version = adapter->fw_version;
return 0;
}
-static u32 qlcnic_get_msglevel(struct net_device *netdev)
+static int
+qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump,
+ void *buffer)
{
+ int i, copy_sz;
+ u32 *hdr_ptr, *data;
struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
- return adapter->msg_enable;
+ if (qlcnic_api_lock(adapter))
+ return -EIO;
+ if (!fw_dump->clr) {
+ netdev_info(netdev, "Dump not available\n");
+ qlcnic_api_unlock(adapter);
+ return -EINVAL;
+ }
+ /* Copy template header first */
+ copy_sz = fw_dump->tmpl_hdr->size;
+ hdr_ptr = (u32 *) fw_dump->tmpl_hdr;
+ data = (u32 *) buffer;
+ for (i = 0; i < copy_sz/sizeof(u32); i++)
+ *data++ = cpu_to_le32(*hdr_ptr++);
+
+ /* Copy captured dump data */
+ memcpy(buffer + copy_sz, fw_dump->data, fw_dump->size);
+ dump->len = copy_sz + fw_dump->size;
+ dump->flag = fw_dump->tmpl_hdr->drv_cap_mask;
+
+ /* Free dump area once data has been captured */
+ vfree(fw_dump->data);
+ fw_dump->data = NULL;
+ fw_dump->clr = 0;
+ qlcnic_api_unlock(adapter);
+
+ return 0;
}
-static void qlcnic_set_msglevel(struct net_device *netdev, u32 msglvl)
+static int
+qlcnic_set_dump(struct net_device *netdev, struct ethtool_dump *val)
{
+ int ret = 0;
struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
- adapter->msg_enable = msglvl;
+ if (val->flag == QLCNIC_FORCE_FW_DUMP_KEY) {
+ netdev_info(netdev, "Forcing a FW dump\n");
+ qlcnic_dev_request_reset(adapter);
+ } else {
+ if (val->flag > QLCNIC_DUMP_MASK_MAX ||
+ val->flag < QLCNIC_DUMP_MASK_MIN) {
+ netdev_info(netdev,
+ "Invalid dump level: 0x%x\n", val->flag);
+ ret = -EINVAL;
+ goto out;
+ }
+ if (qlcnic_api_lock(adapter))
+ return -EIO;
+ fw_dump->tmpl_hdr->drv_cap_mask = val->flag & 0xff;
+ qlcnic_api_unlock(adapter);
+ netdev_info(netdev, "Driver mask changed to: 0x%x\n",
+ fw_dump->tmpl_hdr->drv_cap_mask);
+ }
+out:
+ return ret;
}
const struct ethtool_ops qlcnic_ethtool_ops = {
@@ -1061,26 +1054,22 @@ const struct ethtool_ops qlcnic_ethtool_ops = {
.get_eeprom = qlcnic_get_eeprom,
.get_ringparam = qlcnic_get_ringparam,
.set_ringparam = qlcnic_set_ringparam,
+ .get_channels = qlcnic_get_channels,
+ .set_channels = qlcnic_set_channels,
.get_pauseparam = qlcnic_get_pauseparam,
.set_pauseparam = qlcnic_set_pauseparam,
- .get_tx_csum = qlcnic_get_tx_csum,
- .set_tx_csum = qlcnic_set_tx_csum,
- .set_sg = ethtool_op_set_sg,
- .get_tso = qlcnic_get_tso,
- .set_tso = qlcnic_set_tso,
.get_wol = qlcnic_get_wol,
.set_wol = qlcnic_set_wol,
.self_test = qlcnic_diag_test,
.get_strings = qlcnic_get_strings,
.get_ethtool_stats = qlcnic_get_ethtool_stats,
.get_sset_count = qlcnic_get_sset_count,
- .get_rx_csum = qlcnic_get_rx_csum,
- .set_rx_csum = qlcnic_set_rx_csum,
.get_coalesce = qlcnic_get_intr_coalesce,
.set_coalesce = qlcnic_set_intr_coalesce,
- .get_flags = ethtool_op_get_flags,
- .set_flags = qlcnic_set_flags,
- .phys_id = qlcnic_blink_led,
+ .set_phys_id = qlcnic_set_led,
.set_msglevel = qlcnic_set_msglevel,
.get_msglevel = qlcnic_get_msglevel,
+ .get_dump_flag = qlcnic_get_dump_flag,
+ .get_dump_data = qlcnic_get_dump_data,
+ .set_dump = qlcnic_set_dump,
};
diff --git a/drivers/net/qlcnic/qlcnic_hdr.h b/drivers/net/qlcnic/qlcnic_hdr.h
index 726ef555b6bc..d14506f764e0 100644
--- a/drivers/net/qlcnic/qlcnic_hdr.h
+++ b/drivers/net/qlcnic/qlcnic_hdr.h
@@ -492,10 +492,10 @@ enum {
#define TEST_AGT_CTRL (0x00)
-#define TA_CTL_START 1
-#define TA_CTL_ENABLE 2
-#define TA_CTL_WRITE 4
-#define TA_CTL_BUSY 8
+#define TA_CTL_START BIT_0
+#define TA_CTL_ENABLE BIT_1
+#define TA_CTL_WRITE BIT_2
+#define TA_CTL_BUSY BIT_3
/*
* Register offsets for MN
@@ -765,6 +765,38 @@ struct qlcnic_legacy_intr_set {
#define QLCNIC_MAX_PCI_FUNC 8
#define QLCNIC_MAX_VLAN_FILTERS 64
+/* FW dump defines */
+#define MIU_TEST_CTR 0x41000090
+#define MIU_TEST_ADDR_LO 0x41000094
+#define MIU_TEST_ADDR_HI 0x41000098
+#define FLASH_ROM_WINDOW 0x42110030
+#define FLASH_ROM_DATA 0x42150000
+
+static const u32 MIU_TEST_READ_DATA[] = {
+ 0x410000A8, 0x410000AC, 0x410000B8, 0x410000BC, };
+
+#define QLCNIC_FW_DUMP_REG1 0x00130060
+#define QLCNIC_FW_DUMP_REG2 0x001e0000
+#define QLCNIC_FLASH_SEM2_LK 0x0013C010
+#define QLCNIC_FLASH_SEM2_ULK 0x0013C014
+#define QLCNIC_FLASH_LOCK_ID 0x001B2100
+
+#define QLCNIC_RD_DUMP_REG(addr, bar0, data) do { \
+ writel((addr & 0xFFFF0000), (void *) (bar0 + \
+ QLCNIC_FW_DUMP_REG1)); \
+ readl((void *) (bar0 + QLCNIC_FW_DUMP_REG1)); \
+ *data = readl((void *) (bar0 + QLCNIC_FW_DUMP_REG2 + \
+ LSW(addr))); \
+} while (0)
+
+#define QLCNIC_WR_DUMP_REG(addr, bar0, data) do { \
+ writel((addr & 0xFFFF0000), (void *) (bar0 + \
+ QLCNIC_FW_DUMP_REG1)); \
+ readl((void *) (bar0 + QLCNIC_FW_DUMP_REG1)); \
+ writel(data, (void *) (bar0 + QLCNIC_FW_DUMP_REG2 + LSW(addr)));\
+ readl((void *) (bar0 + QLCNIC_FW_DUMP_REG2 + LSW(addr))); \
+} while (0)
+
/* PCI function operational mode */
enum {
QLCNIC_MGMT_FUNC = 0,
diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c
index 616940f0a8d0..e9656616f2a2 100644
--- a/drivers/net/qlcnic/qlcnic_hw.c
+++ b/drivers/net/qlcnic/qlcnic_hw.c
@@ -9,6 +9,7 @@
#include <linux/slab.h>
#include <net/ip.h>
+#include <linux/bitops.h>
#define MASK(n) ((1ULL<<(n))-1)
#define OCM_WIN_P3P(addr) (addr & 0xffc0000)
@@ -457,7 +458,7 @@ int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
- word = QLCNIC_H2C_OPCODE_PROXY_SET_VPORT_MISS_MODE |
+ word = QLCNIC_H2C_OPCODE_SET_MAC_RECEIVE_MODE |
((u64)adapter->portnum << 16);
req.req_hdr = cpu_to_le64(word);
@@ -532,33 +533,31 @@ void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter)
}
}
-#define QLCNIC_CONFIG_INTR_COALESCE 3
-
/*
* Send the interrupt coalescing parameter set by ethtool to the card.
*/
int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter)
{
struct qlcnic_nic_req req;
- u64 word[6];
- int rv, i;
+ int rv;
memset(&req, 0, sizeof(struct qlcnic_nic_req));
req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
- word[0] = QLCNIC_CONFIG_INTR_COALESCE | ((u64)adapter->portnum << 16);
- req.req_hdr = cpu_to_le64(word[0]);
-
- memcpy(&word[0], &adapter->coal, sizeof(adapter->coal));
- for (i = 0; i < 6; i++)
- req.words[i] = cpu_to_le64(word[i]);
+ req.req_hdr = cpu_to_le64(QLCNIC_CONFIG_INTR_COALESCE |
+ ((u64) adapter->portnum << 16));
+ req.words[0] = cpu_to_le64(((u64) adapter->ahw->coal.flag) << 32);
+ req.words[2] = cpu_to_le64(adapter->ahw->coal.rx_packets |
+ ((u64) adapter->ahw->coal.rx_time_us) << 16);
+ req.words[5] = cpu_to_le64(adapter->ahw->coal.timer_out |
+ ((u64) adapter->ahw->coal.type) << 32 |
+ ((u64) adapter->ahw->coal.sts_ring_mask) << 40);
rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
if (rv != 0)
dev_err(&adapter->netdev->dev,
"Could not send interrupt coalescing parameters\n");
-
return rv;
}
@@ -568,6 +567,9 @@ int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable)
u64 word;
int rv;
+ if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
+ return 0;
+
memset(&req, 0, sizeof(struct qlcnic_nic_req));
req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
@@ -713,6 +715,9 @@ int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter)
u64 word;
int rv;
+ if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
+ return 0;
+
memset(&req, 0, sizeof(struct qlcnic_nic_req));
req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
@@ -754,6 +759,43 @@ int qlcnic_change_mtu(struct net_device *netdev, int mtu)
return rc;
}
+
+u32 qlcnic_fix_features(struct net_device *netdev, u32 features)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+
+ if ((adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
+ u32 changed = features ^ netdev->features;
+ features ^= changed & (NETIF_F_ALL_CSUM | NETIF_F_RXCSUM);
+ }
+
+ if (!(features & NETIF_F_RXCSUM))
+ features &= ~NETIF_F_LRO;
+
+ return features;
+}
+
+
+int qlcnic_set_features(struct net_device *netdev, u32 features)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ u32 changed = netdev->features ^ features;
+ int hw_lro = (features & NETIF_F_LRO) ? QLCNIC_LRO_ENABLED : 0;
+
+ if (!(changed & NETIF_F_LRO))
+ return 0;
+
+ netdev->features = features ^ NETIF_F_LRO;
+
+ if (qlcnic_config_hw_lro(adapter, hw_lro))
+ return -EIO;
+
+ if ((hw_lro == 0) && qlcnic_send_lro_cleanup(adapter))
+ return -EIO;
+
+ return 0;
+}
+
/*
* Changes the CRB window to the specified window.
*/
@@ -780,7 +822,7 @@ qlcnic_pci_get_crb_addr_2M(struct qlcnic_adapter *adapter,
m = &crb_128M_2M_map[CRB_BLK(off)].sub_block[CRB_SUBBLK(off)];
if (m->valid && (m->start_128M <= off) && (m->end_128M > off)) {
- *addr = adapter->ahw.pci_base0 + m->start_2M +
+ *addr = adapter->ahw->pci_base0 + m->start_2M +
(off - m->start_128M);
return 0;
}
@@ -788,7 +830,7 @@ qlcnic_pci_get_crb_addr_2M(struct qlcnic_adapter *adapter,
/*
* Not in direct map, use crb window
*/
- *addr = adapter->ahw.pci_base0 + CRB_INDIRECT_2M + (off & MASK(16));
+ *addr = adapter->ahw->pci_base0 + CRB_INDIRECT_2M + (off & MASK(16));
return 1;
}
@@ -801,7 +843,7 @@ static int
qlcnic_pci_set_crbwindow_2M(struct qlcnic_adapter *adapter, ulong off)
{
u32 window;
- void __iomem *addr = adapter->ahw.pci_base0 + CRB_WINDOW_2M;
+ void __iomem *addr = adapter->ahw->pci_base0 + CRB_WINDOW_2M;
off -= QLCNIC_PCI_CRBSPACE;
@@ -838,13 +880,13 @@ qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off, u32 data)
if (rv > 0) {
/* indirect access */
- write_lock_irqsave(&adapter->ahw.crb_lock, flags);
+ write_lock_irqsave(&adapter->ahw->crb_lock, flags);
crb_win_lock(adapter);
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);
+ write_unlock_irqrestore(&adapter->ahw->crb_lock, flags);
return rv;
}
@@ -869,12 +911,12 @@ qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off)
if (rv > 0) {
/* indirect access */
- write_lock_irqsave(&adapter->ahw.crb_lock, flags);
+ write_lock_irqsave(&adapter->ahw->crb_lock, flags);
crb_win_lock(adapter);
if (!qlcnic_pci_set_crbwindow_2M(adapter, off))
data = readl(addr);
crb_win_unlock(adapter);
- write_unlock_irqrestore(&adapter->ahw.crb_lock, flags);
+ write_unlock_irqrestore(&adapter->ahw->crb_lock, flags);
return data;
}
@@ -904,9 +946,9 @@ qlcnic_pci_set_window_2M(struct qlcnic_adapter *adapter,
window = OCM_WIN_P3P(addr);
- writel(window, adapter->ahw.ocm_win_crb);
+ writel(window, adapter->ahw->ocm_win_crb);
/* read back to flush */
- readl(adapter->ahw.ocm_win_crb);
+ readl(adapter->ahw->ocm_win_crb);
*start = QLCNIC_PCI_OCM0_2M + GET_MEM_OFFS_2M(addr);
return 0;
@@ -920,13 +962,13 @@ qlcnic_pci_mem_access_direct(struct qlcnic_adapter *adapter, u64 off,
int ret;
u32 start;
- mutex_lock(&adapter->ahw.mem_lock);
+ mutex_lock(&adapter->ahw->mem_lock);
ret = qlcnic_pci_set_window_2M(adapter, off, &start);
if (ret != 0)
goto unlock;
- addr = adapter->ahw.pci_base0 + start;
+ addr = adapter->ahw->pci_base0 + start;
if (op == 0) /* read */
*data = readq(addr);
@@ -934,7 +976,7 @@ qlcnic_pci_mem_access_direct(struct qlcnic_adapter *adapter, u64 off,
writeq(*data, addr);
unlock:
- mutex_unlock(&adapter->ahw.mem_lock);
+ mutex_unlock(&adapter->ahw->mem_lock);
return ret;
}
@@ -942,23 +984,23 @@ unlock:
void
qlcnic_pci_camqm_read_2M(struct qlcnic_adapter *adapter, u64 off, u64 *data)
{
- void __iomem *addr = adapter->ahw.pci_base0 +
+ void __iomem *addr = adapter->ahw->pci_base0 +
QLCNIC_PCI_CAMQM_2M_BASE + (off - QLCNIC_PCI_CAMQM);
- mutex_lock(&adapter->ahw.mem_lock);
+ mutex_lock(&adapter->ahw->mem_lock);
*data = readq(addr);
- mutex_unlock(&adapter->ahw.mem_lock);
+ mutex_unlock(&adapter->ahw->mem_lock);
}
void
qlcnic_pci_camqm_write_2M(struct qlcnic_adapter *adapter, u64 off, u64 data)
{
- void __iomem *addr = adapter->ahw.pci_base0 +
+ void __iomem *addr = adapter->ahw->pci_base0 +
QLCNIC_PCI_CAMQM_2M_BASE + (off - QLCNIC_PCI_CAMQM);
- mutex_lock(&adapter->ahw.mem_lock);
+ mutex_lock(&adapter->ahw->mem_lock);
writeq(data, addr);
- mutex_unlock(&adapter->ahw.mem_lock);
+ mutex_unlock(&adapter->ahw->mem_lock);
}
#define MAX_CTL_CHECK 1000
@@ -997,7 +1039,7 @@ qlcnic_pci_mem_write_2M(struct qlcnic_adapter *adapter,
correct:
off8 = off & ~0xf;
- mutex_lock(&adapter->ahw.mem_lock);
+ mutex_lock(&adapter->ahw->mem_lock);
writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO));
writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI));
@@ -1049,7 +1091,7 @@ correct:
ret = 0;
done:
- mutex_unlock(&adapter->ahw.mem_lock);
+ mutex_unlock(&adapter->ahw->mem_lock);
return ret;
}
@@ -1091,7 +1133,7 @@ qlcnic_pci_mem_read_2M(struct qlcnic_adapter *adapter,
correct:
off8 = off & ~0xf;
- mutex_lock(&adapter->ahw.mem_lock);
+ mutex_lock(&adapter->ahw->mem_lock);
writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO));
writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI));
@@ -1121,7 +1163,7 @@ correct:
ret = 0;
}
- mutex_unlock(&adapter->ahw.mem_lock);
+ mutex_unlock(&adapter->ahw->mem_lock);
return ret;
}
@@ -1145,7 +1187,7 @@ int qlcnic_get_board_info(struct qlcnic_adapter *adapter)
if (qlcnic_rom_fast_read(adapter, offset, &board_type))
return -EIO;
- adapter->ahw.board_type = board_type;
+ adapter->ahw->board_type = board_type;
if (board_type == QLCNIC_BRDTYPE_P3P_4_GB_MM) {
u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I);
@@ -1164,20 +1206,20 @@ int qlcnic_get_board_info(struct qlcnic_adapter *adapter)
case QLCNIC_BRDTYPE_P3P_10G_SFP_QT:
case QLCNIC_BRDTYPE_P3P_10G_XFP:
case QLCNIC_BRDTYPE_P3P_10000_BASE_T:
- adapter->ahw.port_type = QLCNIC_XGBE;
+ adapter->ahw->port_type = QLCNIC_XGBE;
break;
case QLCNIC_BRDTYPE_P3P_REF_QG:
case QLCNIC_BRDTYPE_P3P_4_GB:
case QLCNIC_BRDTYPE_P3P_4_GB_MM:
- adapter->ahw.port_type = QLCNIC_GBE;
+ adapter->ahw->port_type = QLCNIC_GBE;
break;
case QLCNIC_BRDTYPE_P3P_10G_TP:
- adapter->ahw.port_type = (adapter->portnum < 2) ?
+ adapter->ahw->port_type = (adapter->portnum < 2) ?
QLCNIC_XGBE : QLCNIC_GBE;
break;
default:
dev_err(&pdev->dev, "unknown board type %x\n", board_type);
- adapter->ahw.port_type = QLCNIC_XGBE;
+ adapter->ahw->port_type = QLCNIC_XGBE;
break;
}
@@ -1220,3 +1262,461 @@ int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
return rv;
}
+
+/* FW dump related functions */
+static u32
+qlcnic_dump_crb(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry,
+ u32 *buffer)
+{
+ int i;
+ u32 addr, data;
+ struct __crb *crb = &entry->region.crb;
+ void __iomem *base = adapter->ahw->pci_base0;
+
+ addr = crb->addr;
+
+ for (i = 0; i < crb->no_ops; i++) {
+ QLCNIC_RD_DUMP_REG(addr, base, &data);
+ *buffer++ = cpu_to_le32(addr);
+ *buffer++ = cpu_to_le32(data);
+ addr += crb->stride;
+ }
+ return crb->no_ops * 2 * sizeof(u32);
+}
+
+static u32
+qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
+ struct qlcnic_dump_entry *entry, u32 *buffer)
+{
+ int i, k, timeout = 0;
+ void __iomem *base = adapter->ahw->pci_base0;
+ u32 addr, data;
+ u8 opcode, no_ops;
+ struct __ctrl *ctr = &entry->region.ctrl;
+ struct qlcnic_dump_template_hdr *t_hdr = adapter->ahw->fw_dump.tmpl_hdr;
+
+ addr = ctr->addr;
+ no_ops = ctr->no_ops;
+
+ for (i = 0; i < no_ops; i++) {
+ k = 0;
+ opcode = 0;
+ for (k = 0; k < 8; k++) {
+ if (!(ctr->opcode & (1 << k)))
+ continue;
+ switch (1 << k) {
+ case QLCNIC_DUMP_WCRB:
+ QLCNIC_WR_DUMP_REG(addr, base, ctr->val1);
+ break;
+ case QLCNIC_DUMP_RWCRB:
+ QLCNIC_RD_DUMP_REG(addr, base, &data);
+ QLCNIC_WR_DUMP_REG(addr, base, data);
+ break;
+ case QLCNIC_DUMP_ANDCRB:
+ QLCNIC_RD_DUMP_REG(addr, base, &data);
+ QLCNIC_WR_DUMP_REG(addr, base,
+ (data & ctr->val2));
+ break;
+ case QLCNIC_DUMP_ORCRB:
+ QLCNIC_RD_DUMP_REG(addr, base, &data);
+ QLCNIC_WR_DUMP_REG(addr, base,
+ (data | ctr->val3));
+ break;
+ case QLCNIC_DUMP_POLLCRB:
+ while (timeout <= ctr->timeout) {
+ QLCNIC_RD_DUMP_REG(addr, base, &data);
+ if ((data & ctr->val2) == ctr->val1)
+ break;
+ msleep(1);
+ timeout++;
+ }
+ if (timeout > ctr->timeout) {
+ dev_info(&adapter->pdev->dev,
+ "Timed out, aborting poll CRB\n");
+ return -EINVAL;
+ }
+ break;
+ case QLCNIC_DUMP_RD_SAVE:
+ if (ctr->index_a)
+ addr = t_hdr->saved_state[ctr->index_a];
+ QLCNIC_RD_DUMP_REG(addr, base, &data);
+ t_hdr->saved_state[ctr->index_v] = data;
+ break;
+ case QLCNIC_DUMP_WRT_SAVED:
+ if (ctr->index_v)
+ data = t_hdr->saved_state[ctr->index_v];
+ else
+ data = ctr->val1;
+ if (ctr->index_a)
+ addr = t_hdr->saved_state[ctr->index_a];
+ QLCNIC_WR_DUMP_REG(addr, base, data);
+ break;
+ case QLCNIC_DUMP_MOD_SAVE_ST:
+ data = t_hdr->saved_state[ctr->index_v];
+ data <<= ctr->shl_val;
+ data >>= ctr->shr_val;
+ if (ctr->val2)
+ data &= ctr->val2;
+ data |= ctr->val3;
+ data += ctr->val1;
+ t_hdr->saved_state[ctr->index_v] = data;
+ break;
+ default:
+ dev_info(&adapter->pdev->dev,
+ "Unknown opcode\n");
+ break;
+ }
+ }
+ addr += ctr->stride;
+ }
+ return 0;
+}
+
+static u32
+qlcnic_dump_mux(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry,
+ u32 *buffer)
+{
+ int loop;
+ u32 val, data = 0;
+ struct __mux *mux = &entry->region.mux;
+ void __iomem *base = adapter->ahw->pci_base0;
+
+ val = mux->val;
+ for (loop = 0; loop < mux->no_ops; loop++) {
+ QLCNIC_WR_DUMP_REG(mux->addr, base, val);
+ QLCNIC_RD_DUMP_REG(mux->read_addr, base, &data);
+ *buffer++ = cpu_to_le32(val);
+ *buffer++ = cpu_to_le32(data);
+ val += mux->val_stride;
+ }
+ return 2 * mux->no_ops * sizeof(u32);
+}
+
+static u32
+qlcnic_dump_que(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry,
+ u32 *buffer)
+{
+ int i, loop;
+ u32 cnt, addr, data, que_id = 0;
+ void __iomem *base = adapter->ahw->pci_base0;
+ struct __queue *que = &entry->region.que;
+
+ addr = que->read_addr;
+ cnt = que->read_addr_cnt;
+
+ for (loop = 0; loop < que->no_ops; loop++) {
+ QLCNIC_WR_DUMP_REG(que->sel_addr, base, que_id);
+ for (i = 0; i < cnt; i++) {
+ QLCNIC_RD_DUMP_REG(addr, base, &data);
+ *buffer++ = cpu_to_le32(data);
+ addr += que->read_addr_stride;
+ }
+ que_id += que->stride;
+ }
+ return que->no_ops * cnt * sizeof(u32);
+}
+
+static u32
+qlcnic_dump_ocm(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry,
+ u32 *buffer)
+{
+ int i;
+ u32 data;
+ void __iomem *addr;
+ struct __ocm *ocm = &entry->region.ocm;
+
+ addr = adapter->ahw->pci_base0 + ocm->read_addr;
+ for (i = 0; i < ocm->no_ops; i++) {
+ data = readl(addr);
+ *buffer++ = cpu_to_le32(data);
+ addr += ocm->read_addr_stride;
+ }
+ return ocm->no_ops * sizeof(u32);
+}
+
+static u32
+qlcnic_read_rom(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry,
+ u32 *buffer)
+{
+ int i, count = 0;
+ u32 fl_addr, size, val, lck_val, addr;
+ struct __mem *rom = &entry->region.mem;
+ void __iomem *base = adapter->ahw->pci_base0;
+
+ fl_addr = rom->addr;
+ size = rom->size/4;
+lock_try:
+ lck_val = readl(base + QLCNIC_FLASH_SEM2_LK);
+ if (!lck_val && count < MAX_CTL_CHECK) {
+ msleep(10);
+ count++;
+ goto lock_try;
+ }
+ writel(adapter->ahw->pci_func, (base + QLCNIC_FLASH_LOCK_ID));
+ for (i = 0; i < size; i++) {
+ addr = fl_addr & 0xFFFF0000;
+ QLCNIC_WR_DUMP_REG(FLASH_ROM_WINDOW, base, addr);
+ addr = LSW(fl_addr) + FLASH_ROM_DATA;
+ QLCNIC_RD_DUMP_REG(addr, base, &val);
+ fl_addr += 4;
+ *buffer++ = cpu_to_le32(val);
+ }
+ readl(base + QLCNIC_FLASH_SEM2_ULK);
+ return rom->size;
+}
+
+static u32
+qlcnic_dump_l1_cache(struct qlcnic_adapter *adapter,
+ struct qlcnic_dump_entry *entry, u32 *buffer)
+{
+ int i;
+ u32 cnt, val, data, addr;
+ void __iomem *base = adapter->ahw->pci_base0;
+ struct __cache *l1 = &entry->region.cache;
+
+ val = l1->init_tag_val;
+
+ for (i = 0; i < l1->no_ops; i++) {
+ QLCNIC_WR_DUMP_REG(l1->addr, base, val);
+ QLCNIC_WR_DUMP_REG(l1->ctrl_addr, base, LSW(l1->ctrl_val));
+ addr = l1->read_addr;
+ cnt = l1->read_addr_num;
+ while (cnt) {
+ QLCNIC_RD_DUMP_REG(addr, base, &data);
+ *buffer++ = cpu_to_le32(data);
+ addr += l1->read_addr_stride;
+ cnt--;
+ }
+ val += l1->stride;
+ }
+ return l1->no_ops * l1->read_addr_num * sizeof(u32);
+}
+
+static u32
+qlcnic_dump_l2_cache(struct qlcnic_adapter *adapter,
+ struct qlcnic_dump_entry *entry, u32 *buffer)
+{
+ int i;
+ u32 cnt, val, data, addr;
+ u8 poll_mask, poll_to, time_out = 0;
+ void __iomem *base = adapter->ahw->pci_base0;
+ struct __cache *l2 = &entry->region.cache;
+
+ val = l2->init_tag_val;
+ poll_mask = LSB(MSW(l2->ctrl_val));
+ poll_to = MSB(MSW(l2->ctrl_val));
+
+ for (i = 0; i < l2->no_ops; i++) {
+ QLCNIC_WR_DUMP_REG(l2->addr, base, val);
+ do {
+ QLCNIC_WR_DUMP_REG(l2->ctrl_addr, base,
+ LSW(l2->ctrl_val));
+ QLCNIC_RD_DUMP_REG(l2->ctrl_addr, base, &data);
+ if (!(data & poll_mask))
+ break;
+ msleep(1);
+ time_out++;
+ } while (time_out <= poll_to);
+ if (time_out > poll_to)
+ return -EINVAL;
+
+ addr = l2->read_addr;
+ cnt = l2->read_addr_num;
+ while (cnt) {
+ QLCNIC_RD_DUMP_REG(addr, base, &data);
+ *buffer++ = cpu_to_le32(data);
+ addr += l2->read_addr_stride;
+ cnt--;
+ }
+ val += l2->stride;
+ }
+ return l2->no_ops * l2->read_addr_num * sizeof(u32);
+}
+
+static u32
+qlcnic_read_memory(struct qlcnic_adapter *adapter,
+ struct qlcnic_dump_entry *entry, u32 *buffer)
+{
+ u32 addr, data, test, ret = 0;
+ int i, reg_read;
+ struct __mem *mem = &entry->region.mem;
+ void __iomem *base = adapter->ahw->pci_base0;
+
+ reg_read = mem->size;
+ addr = mem->addr;
+ /* check for data size of multiple of 16 and 16 byte alignment */
+ if ((addr & 0xf) || (reg_read%16)) {
+ dev_info(&adapter->pdev->dev,
+ "Unaligned memory addr:0x%x size:0x%x\n",
+ addr, reg_read);
+ return -EINVAL;
+ }
+
+ mutex_lock(&adapter->ahw->mem_lock);
+
+ while (reg_read != 0) {
+ QLCNIC_WR_DUMP_REG(MIU_TEST_ADDR_LO, base, addr);
+ QLCNIC_WR_DUMP_REG(MIU_TEST_ADDR_HI, base, 0);
+ QLCNIC_WR_DUMP_REG(MIU_TEST_CTR, base,
+ TA_CTL_ENABLE | TA_CTL_START);
+
+ for (i = 0; i < MAX_CTL_CHECK; i++) {
+ QLCNIC_RD_DUMP_REG(MIU_TEST_CTR, base, &test);
+ if (!(test & TA_CTL_BUSY))
+ break;
+ }
+ if (i == MAX_CTL_CHECK) {
+ if (printk_ratelimit()) {
+ dev_err(&adapter->pdev->dev,
+ "failed to read through agent\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+ for (i = 0; i < 4; i++) {
+ QLCNIC_RD_DUMP_REG(MIU_TEST_READ_DATA[i], base, &data);
+ *buffer++ = cpu_to_le32(data);
+ }
+ addr += 16;
+ reg_read -= 16;
+ ret += 16;
+ }
+out:
+ mutex_unlock(&adapter->ahw->mem_lock);
+ return mem->size;
+}
+
+static u32
+qlcnic_dump_nop(struct qlcnic_adapter *adapter,
+ struct qlcnic_dump_entry *entry, u32 *buffer)
+{
+ entry->hdr.flags |= QLCNIC_DUMP_SKIP;
+ return 0;
+}
+
+struct qlcnic_dump_operations fw_dump_ops[] = {
+ { QLCNIC_DUMP_NOP, qlcnic_dump_nop },
+ { QLCNIC_DUMP_READ_CRB, qlcnic_dump_crb },
+ { QLCNIC_DUMP_READ_MUX, qlcnic_dump_mux },
+ { QLCNIC_DUMP_QUEUE, qlcnic_dump_que },
+ { QLCNIC_DUMP_BRD_CONFIG, qlcnic_read_rom },
+ { QLCNIC_DUMP_READ_OCM, qlcnic_dump_ocm },
+ { QLCNIC_DUMP_PEG_REG, qlcnic_dump_ctrl },
+ { QLCNIC_DUMP_L1_DTAG, qlcnic_dump_l1_cache },
+ { QLCNIC_DUMP_L1_ITAG, qlcnic_dump_l1_cache },
+ { QLCNIC_DUMP_L1_DATA, qlcnic_dump_l1_cache },
+ { QLCNIC_DUMP_L1_INST, qlcnic_dump_l1_cache },
+ { QLCNIC_DUMP_L2_DTAG, qlcnic_dump_l2_cache },
+ { QLCNIC_DUMP_L2_ITAG, qlcnic_dump_l2_cache },
+ { QLCNIC_DUMP_L2_DATA, qlcnic_dump_l2_cache },
+ { QLCNIC_DUMP_L2_INST, qlcnic_dump_l2_cache },
+ { QLCNIC_DUMP_READ_ROM, qlcnic_read_rom },
+ { QLCNIC_DUMP_READ_MEM, qlcnic_read_memory },
+ { QLCNIC_DUMP_READ_CTRL, qlcnic_dump_ctrl },
+ { QLCNIC_DUMP_TLHDR, qlcnic_dump_nop },
+ { QLCNIC_DUMP_RDEND, qlcnic_dump_nop },
+};
+
+/* Walk the template and collect dump for each entry in the dump template */
+static int
+qlcnic_valid_dump_entry(struct device *dev, struct qlcnic_dump_entry *entry,
+ u32 size)
+{
+ int ret = 1;
+ if (size != entry->hdr.cap_size) {
+ dev_info(dev,
+ "Invalidate dump, Type:%d\tMask:%d\tSize:%dCap_size:%d\n",
+ entry->hdr.type, entry->hdr.mask, size, entry->hdr.cap_size);
+ dev_info(dev, "Aborting further dump capture\n");
+ ret = 0;
+ }
+ return ret;
+}
+
+int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
+{
+ u32 *buffer;
+ char mesg[64];
+ char *msg[] = {mesg, NULL};
+ int i, k, ops_cnt, ops_index, dump_size = 0;
+ u32 entry_offset, dump, no_entries, buf_offset = 0;
+ struct qlcnic_dump_entry *entry;
+ struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
+ struct qlcnic_dump_template_hdr *tmpl_hdr = fw_dump->tmpl_hdr;
+
+ if (fw_dump->clr) {
+ dev_info(&adapter->pdev->dev,
+ "Previous dump not cleared, not capturing dump\n");
+ return -EIO;
+ }
+ /* Calculate the size for dump data area only */
+ for (i = 2, k = 1; (i & QLCNIC_DUMP_MASK_MAX); i <<= 1, k++)
+ if (i & tmpl_hdr->drv_cap_mask)
+ dump_size += tmpl_hdr->cap_sizes[k];
+ if (!dump_size)
+ return -EIO;
+
+ fw_dump->data = vzalloc(dump_size);
+ if (!fw_dump->data) {
+ dev_info(&adapter->pdev->dev,
+ "Unable to allocate (%d KB) for fw dump\n",
+ dump_size/1024);
+ return -ENOMEM;
+ }
+ buffer = fw_dump->data;
+ fw_dump->size = dump_size;
+ no_entries = tmpl_hdr->num_entries;
+ ops_cnt = ARRAY_SIZE(fw_dump_ops);
+ entry_offset = tmpl_hdr->offset;
+ tmpl_hdr->sys_info[0] = QLCNIC_DRIVER_VERSION;
+ tmpl_hdr->sys_info[1] = adapter->fw_version;
+
+ for (i = 0; i < no_entries; i++) {
+ entry = (struct qlcnic_dump_entry *) ((void *) tmpl_hdr +
+ entry_offset);
+ if (!(entry->hdr.mask & tmpl_hdr->drv_cap_mask)) {
+ entry->hdr.flags |= QLCNIC_DUMP_SKIP;
+ entry_offset += entry->hdr.offset;
+ continue;
+ }
+ /* Find the handler for this entry */
+ ops_index = 0;
+ while (ops_index < ops_cnt) {
+ if (entry->hdr.type == fw_dump_ops[ops_index].opcode)
+ break;
+ ops_index++;
+ }
+ if (ops_index == ops_cnt) {
+ dev_info(&adapter->pdev->dev,
+ "Invalid entry type %d, exiting dump\n",
+ entry->hdr.type);
+ goto error;
+ }
+ /* Collect dump for this entry */
+ dump = fw_dump_ops[ops_index].handler(adapter, entry, buffer);
+ if (dump && !qlcnic_valid_dump_entry(&adapter->pdev->dev, entry,
+ dump))
+ entry->hdr.flags |= QLCNIC_DUMP_SKIP;
+ buf_offset += entry->hdr.cap_size;
+ entry_offset += entry->hdr.offset;
+ buffer = fw_dump->data + buf_offset;
+ }
+ if (dump_size != buf_offset) {
+ dev_info(&adapter->pdev->dev,
+ "Captured(%d) and expected size(%d) do not match\n",
+ buf_offset, dump_size);
+ goto error;
+ } else {
+ fw_dump->clr = 1;
+ snprintf(mesg, sizeof(mesg), "FW dump for device: %d\n",
+ adapter->pdev->devfn);
+ dev_info(&adapter->pdev->dev, "Dump data, %d bytes captured\n",
+ fw_dump->size);
+ /* Send a udev event to notify availability of FW dump */
+ kobject_uevent_env(&adapter->pdev->dev.kobj, KOBJ_CHANGE, msg);
+ return 0;
+ }
+error:
+ vfree(fw_dump->data);
+ return -EINVAL;
+}
diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c
index a7f1d5b7e811..5b8bbcf904d5 100644
--- a/drivers/net/qlcnic/qlcnic_init.c
+++ b/drivers/net/qlcnic/qlcnic_init.c
@@ -94,7 +94,7 @@ void qlcnic_release_rx_buffers(struct qlcnic_adapter *adapter)
struct qlcnic_rx_buffer *rx_buf;
int i, ring;
- recv_ctx = &adapter->recv_ctx;
+ recv_ctx = adapter->recv_ctx;
for (ring = 0; ring < adapter->max_rds_rings; ring++) {
rds_ring = &recv_ctx->rds_rings[ring];
for (i = 0; i < rds_ring->num_desc; ++i) {
@@ -119,7 +119,7 @@ void qlcnic_reset_rx_buffers_list(struct qlcnic_adapter *adapter)
struct qlcnic_rx_buffer *rx_buf;
int i, ring;
- recv_ctx = &adapter->recv_ctx;
+ recv_ctx = adapter->recv_ctx;
for (ring = 0; ring < adapter->max_rds_rings; ring++) {
rds_ring = &recv_ctx->rds_rings[ring];
@@ -173,7 +173,7 @@ void qlcnic_free_sw_resources(struct qlcnic_adapter *adapter)
struct qlcnic_host_tx_ring *tx_ring;
int ring;
- recv_ctx = &adapter->recv_ctx;
+ recv_ctx = adapter->recv_ctx;
if (recv_ctx->rds_rings == NULL)
goto skip_rds;
@@ -226,7 +226,7 @@ int qlcnic_alloc_sw_resources(struct qlcnic_adapter *adapter)
}
tx_ring->cmd_buf_arr = cmd_buf_arr;
- recv_ctx = &adapter->recv_ctx;
+ recv_ctx = adapter->recv_ctx;
size = adapter->max_rds_rings * sizeof(struct qlcnic_host_rds_ring);
rds_ring = kzalloc(size, GFP_KERNEL);
@@ -345,7 +345,7 @@ static int qlcnic_wait_rom_done(struct qlcnic_adapter *adapter)
}
static int do_rom_fast_read(struct qlcnic_adapter *adapter,
- int addr, int *valp)
+ u32 addr, u32 *valp)
{
QLCWR32(adapter, QLCNIC_ROMUSB_ROM_ADDRESS, addr);
QLCWR32(adapter, QLCNIC_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
@@ -398,7 +398,7 @@ qlcnic_rom_fast_read_words(struct qlcnic_adapter *adapter, int addr,
return ret;
}
-int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, int addr, int *valp)
+int qlcnic_rom_fast_read(struct qlcnic_adapter *adapter, u32 addr, u32 *valp)
{
int ret;
@@ -864,7 +864,7 @@ nomn:
for (i = 0; i < entries; i++) {
__le32 flags, file_chiprev, offs;
- u8 chiprev = adapter->ahw.revision_id;
+ u8 chiprev = adapter->ahw->revision_id;
u32 flagbit;
offs = cpu_to_le32(ptab_descr->findex) +
@@ -1130,9 +1130,20 @@ qlcnic_load_firmware(struct qlcnic_adapter *adapter)
} else {
u64 data;
u32 hi, lo;
-
- size = (QLCNIC_IMAGE_START - QLCNIC_BOOTLD_START) / 8;
- flashaddr = QLCNIC_BOOTLD_START;
+ int ret;
+ struct qlcnic_flt_entry bootld_entry;
+
+ ret = qlcnic_get_flt_entry(adapter, QLCNIC_BOOTLD_REGION,
+ &bootld_entry);
+ if (!ret) {
+ size = bootld_entry.size / 8;
+ flashaddr = bootld_entry.start_addr;
+ } else {
+ size = (QLCNIC_IMAGE_START - QLCNIC_BOOTLD_START) / 8;
+ flashaddr = QLCNIC_BOOTLD_START;
+ dev_info(&pdev->dev,
+ "using legacy method to get flash fw region");
+ }
for (i = 0; i < size; i++) {
if (qlcnic_rom_fast_read(adapter,
@@ -1379,8 +1390,8 @@ static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
skb = buffer->skb;
- if (likely(adapter->rx_csum && (cksum == STATUS_CKSUM_OK ||
- cksum == STATUS_CKSUM_LOOP))) {
+ if (likely((adapter->netdev->features & NETIF_F_RXCSUM) &&
+ (cksum == STATUS_CKSUM_OK || cksum == STATUS_CKSUM_LOOP))) {
adapter->stats.csummed++;
skb->ip_summed = CHECKSUM_UNNECESSARY;
} else {
@@ -1394,7 +1405,7 @@ static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
return skb;
}
-static int
+static inline int
qlcnic_check_rx_tagging(struct qlcnic_adapter *adapter, struct sk_buff *skb,
u16 *vlan_tag)
{
@@ -1425,7 +1436,7 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter,
int ring, u64 sts_data0)
{
struct net_device *netdev = adapter->netdev;
- struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
struct qlcnic_rx_buffer *buffer;
struct sk_buff *skb;
struct qlcnic_host_rds_ring *rds_ring;
@@ -1467,10 +1478,10 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter,
skb->protocol = eth_type_trans(skb, netdev);
- if ((vid != 0xffff) && adapter->vlgrp)
- vlan_gro_receive(&sds_ring->napi, adapter->vlgrp, vid, skb);
- else
- napi_gro_receive(&sds_ring->napi, skb);
+ if (vid != 0xffff)
+ __vlan_hwaccel_put_tag(skb, vid);
+
+ napi_gro_receive(&sds_ring->napi, skb);
adapter->stats.rx_pkts++;
adapter->stats.rxbytes += length;
@@ -1488,7 +1499,7 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
int ring, u64 sts_data0, u64 sts_data1)
{
struct net_device *netdev = adapter->netdev;
- struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
struct qlcnic_rx_buffer *buffer;
struct sk_buff *skb;
struct qlcnic_host_rds_ring *rds_ring;
@@ -1552,10 +1563,9 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
length = skb->len;
- if ((vid != 0xffff) && adapter->vlgrp)
- vlan_hwaccel_receive_skb(skb, adapter->vlgrp, vid);
- else
- netif_receive_skb(skb);
+ if (vid != 0xffff)
+ __vlan_hwaccel_put_tag(skb, vid);
+ netif_receive_skb(skb);
adapter->stats.lro_pkts++;
adapter->stats.lrobytes += length;
@@ -1625,7 +1635,7 @@ skip:
for (ring = 0; ring < adapter->max_rds_rings; ring++) {
struct qlcnic_host_rds_ring *rds_ring =
- &adapter->recv_ctx.rds_rings[ring];
+ &adapter->recv_ctx->rds_rings[ring];
if (!list_empty(&sds_ring->free_list[ring])) {
list_for_each(cur, &sds_ring->free_list[ring]) {
@@ -1651,12 +1661,13 @@ skip:
}
void
-qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, u32 ringid,
+qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter,
struct qlcnic_host_rds_ring *rds_ring)
{
struct rcv_desc *pdesc;
struct qlcnic_rx_buffer *buffer;
- int producer, count = 0;
+ int count = 0;
+ u32 producer;
struct list_head *head;
producer = rds_ring->producer;
@@ -1696,7 +1707,8 @@ qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
{
struct rcv_desc *pdesc;
struct qlcnic_rx_buffer *buffer;
- int producer, count = 0;
+ int count = 0;
+ uint32_t producer;
struct list_head *head;
if (!spin_trylock(&rds_ring->lock))
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index cb1a1ef36c0a..3ab7d2c7baf2 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -13,12 +13,12 @@
#include <linux/swab.h>
#include <linux/dma-mapping.h>
-#include <linux/if_vlan.h>
#include <net/ip.h>
#include <linux/ipv6.h>
#include <linux/inetdevice.h>
#include <linux/sysfs.h>
#include <linux/aer.h>
+#include <linux/log2.h>
MODULE_DESCRIPTION("QLogic 1/10 GbE Converged/Intelligent Ethernet Driver");
MODULE_LICENSE("GPL");
@@ -98,6 +98,9 @@ static int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32);
static int qlcnicvf_start_firmware(struct qlcnic_adapter *);
static void qlcnic_set_netdev_features(struct qlcnic_adapter *,
struct qlcnic_esw_func_cfg *);
+static void qlcnic_vlan_rx_add(struct net_device *, u16);
+static void qlcnic_vlan_rx_del(struct net_device *, u16);
+
/* PCI Device ID Table */
#define ENTRY(device) \
{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, (device)), \
@@ -113,7 +116,7 @@ static DEFINE_PCI_DEVICE_TABLE(qlcnic_pci_tbl) = {
MODULE_DEVICE_TABLE(pci, qlcnic_pci_tbl);
-void
+inline void
qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter,
struct qlcnic_host_tx_ring *tx_ring)
{
@@ -169,7 +172,7 @@ qlcnic_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev)
{
int ring;
struct qlcnic_host_sds_ring *sds_ring;
- struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
if (qlcnic_alloc_sds_rings(recv_ctx, adapter->max_sds_rings))
return -ENOMEM;
@@ -193,14 +196,14 @@ qlcnic_napi_del(struct qlcnic_adapter *adapter)
{
int ring;
struct qlcnic_host_sds_ring *sds_ring;
- struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
for (ring = 0; ring < adapter->max_sds_rings; ring++) {
sds_ring = &recv_ctx->sds_rings[ring];
netif_napi_del(&sds_ring->napi);
}
- qlcnic_free_sds_rings(&adapter->recv_ctx);
+ qlcnic_free_sds_rings(adapter->recv_ctx);
}
static void
@@ -208,7 +211,7 @@ qlcnic_napi_enable(struct qlcnic_adapter *adapter)
{
int ring;
struct qlcnic_host_sds_ring *sds_ring;
- struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
return;
@@ -225,7 +228,7 @@ qlcnic_napi_disable(struct qlcnic_adapter *adapter)
{
int ring;
struct qlcnic_host_sds_ring *sds_ring;
- struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
return;
@@ -317,13 +320,6 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p)
return 0;
}
-static void qlcnic_vlan_rx_register(struct net_device *netdev,
- struct vlan_group *grp)
-{
- struct qlcnic_adapter *adapter = netdev_priv(netdev);
- adapter->vlgrp = grp;
-}
-
static const struct net_device_ops qlcnic_netdev_ops = {
.ndo_open = qlcnic_open,
.ndo_stop = qlcnic_close,
@@ -333,8 +329,11 @@ static const struct net_device_ops qlcnic_netdev_ops = {
.ndo_set_multicast_list = qlcnic_set_multi,
.ndo_set_mac_address = qlcnic_set_mac,
.ndo_change_mtu = qlcnic_change_mtu,
+ .ndo_fix_features = qlcnic_fix_features,
+ .ndo_set_features = qlcnic_set_features,
.ndo_tx_timeout = qlcnic_tx_timeout,
- .ndo_vlan_rx_register = qlcnic_vlan_rx_register,
+ .ndo_vlan_rx_add_vid = qlcnic_vlan_rx_add,
+ .ndo_vlan_rx_kill_vid = qlcnic_vlan_rx_del,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = qlcnic_poll_controller,
#endif
@@ -352,72 +351,87 @@ static struct qlcnic_nic_template qlcnic_vf_ops = {
.start_firmware = qlcnicvf_start_firmware
};
-static void
-qlcnic_setup_intr(struct qlcnic_adapter *adapter)
+static int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix)
{
- const struct qlcnic_legacy_intr_set *legacy_intrp;
struct pci_dev *pdev = adapter->pdev;
- int err, num_msix;
-
- if (adapter->rss_supported) {
- num_msix = (num_online_cpus() >= MSIX_ENTRIES_PER_ADAPTER) ?
- MSIX_ENTRIES_PER_ADAPTER : 2;
- } else
- num_msix = 1;
+ int err = -1;
adapter->max_sds_rings = 1;
-
adapter->flags &= ~(QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED);
-
- legacy_intrp = &legacy_intr[adapter->ahw.pci_func];
-
- adapter->int_vec_bit = legacy_intrp->int_vec_bit;
- adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter,
- legacy_intrp->tgt_status_reg);
- adapter->tgt_mask_reg = qlcnic_get_ioaddr(adapter,
- legacy_intrp->tgt_mask_reg);
- adapter->isr_int_vec = qlcnic_get_ioaddr(adapter, ISR_INT_VECTOR);
-
- adapter->crb_int_state_reg = qlcnic_get_ioaddr(adapter,
- ISR_INT_STATE_REG);
-
qlcnic_set_msix_bit(pdev, 0);
if (adapter->msix_supported) {
-
+ enable_msix:
qlcnic_init_msix_entries(adapter, num_msix);
err = pci_enable_msix(pdev, adapter->msix_entries, num_msix);
if (err == 0) {
adapter->flags |= QLCNIC_MSIX_ENABLED;
qlcnic_set_msix_bit(pdev, 1);
- if (adapter->rss_supported)
- adapter->max_sds_rings = num_msix;
+ adapter->max_sds_rings = num_msix;
dev_info(&pdev->dev, "using msi-x interrupts\n");
- return;
+ return err;
}
+ if (err > 0) {
+ num_msix = rounddown_pow_of_two(err);
+ if (num_msix)
+ goto enable_msix;
+ }
+ }
+ return err;
+}
- if (err > 0)
- pci_disable_msix(pdev);
- /* fall through for msi */
- }
+static void qlcnic_enable_msi_legacy(struct qlcnic_adapter *adapter)
+{
+ const struct qlcnic_legacy_intr_set *legacy_intrp;
+ struct pci_dev *pdev = adapter->pdev;
if (use_msi && !pci_enable_msi(pdev)) {
adapter->flags |= QLCNIC_MSI_ENABLED;
adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter,
- msi_tgt_status[adapter->ahw.pci_func]);
+ msi_tgt_status[adapter->ahw->pci_func]);
dev_info(&pdev->dev, "using msi interrupts\n");
adapter->msix_entries[0].vector = pdev->irq;
return;
}
+ legacy_intrp = &legacy_intr[adapter->ahw->pci_func];
+
+ adapter->int_vec_bit = legacy_intrp->int_vec_bit;
+ adapter->tgt_status_reg = qlcnic_get_ioaddr(adapter,
+ legacy_intrp->tgt_status_reg);
+ adapter->tgt_mask_reg = qlcnic_get_ioaddr(adapter,
+ legacy_intrp->tgt_mask_reg);
+ adapter->isr_int_vec = qlcnic_get_ioaddr(adapter, ISR_INT_VECTOR);
+
+ adapter->crb_int_state_reg = qlcnic_get_ioaddr(adapter,
+ ISR_INT_STATE_REG);
dev_info(&pdev->dev, "using legacy interrupts\n");
adapter->msix_entries[0].vector = pdev->irq;
}
static void
+qlcnic_setup_intr(struct qlcnic_adapter *adapter)
+{
+ int num_msix;
+
+ if (adapter->msix_supported) {
+ num_msix = (num_online_cpus() >=
+ QLCNIC_DEF_NUM_STS_DESC_RINGS) ?
+ QLCNIC_DEF_NUM_STS_DESC_RINGS :
+ QLCNIC_MIN_NUM_RSS_RINGS;
+ } else
+ num_msix = 1;
+
+ if (!qlcnic_enable_msix(adapter, num_msix))
+ return;
+
+ qlcnic_enable_msi_legacy(adapter);
+}
+
+static void
qlcnic_teardown_intr(struct qlcnic_adapter *adapter)
{
if (adapter->flags & QLCNIC_MSIX_ENABLED)
@@ -429,8 +443,8 @@ qlcnic_teardown_intr(struct qlcnic_adapter *adapter)
static void
qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter)
{
- if (adapter->ahw.pci_base0 != NULL)
- iounmap(adapter->ahw.pci_base0);
+ if (adapter->ahw->pci_base0 != NULL)
+ iounmap(adapter->ahw->pci_base0);
}
static int
@@ -464,8 +478,10 @@ qlcnic_init_pci_info(struct qlcnic_adapter *adapter)
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;
+ if (pfn > QLCNIC_MAX_PCI_FUNC) {
+ ret = QL_STATUS_INVALID_PARAM;
+ goto err_eswitch;
+ }
adapter->npars[pfn].active = (u8)pci_info[i].active;
adapter->npars[pfn].type = (u8)pci_info[i].type;
adapter->npars[pfn].phy_port = (u8)pci_info[i].default_port;
@@ -498,7 +514,7 @@ qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
u32 ref_count;
int i, ret = 1;
u32 data = QLCNIC_MGMT_FUNC;
- void __iomem *priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
+ 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_DRV_ACTIVE);
@@ -510,16 +526,16 @@ qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
id = i;
if (adapter->npars[i].type != QLCNIC_TYPE_NIC ||
- id == adapter->ahw.pci_func)
+ 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)) |
+ data = (data & ~QLC_DEV_SET_DRV(0xf, adapter->ahw->pci_func)) |
(QLC_DEV_SET_DRV(QLCNIC_MGMT_FUNC,
- adapter->ahw.pci_func));
+ adapter->ahw->pci_func));
}
writel(data, priv_op);
qlcnic_api_unlock(adapter);
@@ -537,22 +553,23 @@ qlcnic_check_vf(struct qlcnic_adapter *adapter)
u32 op_mode, priv_level;
/* Determine FW API version */
- adapter->fw_hal_version = readl(adapter->ahw.pci_base0 + QLCNIC_FW_API);
+ 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_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;
+ adapter->ahw->pci_func = func;
/* Determine function privilege level */
- priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
+ 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);
+ priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw->pci_func);
if (priv_level == QLCNIC_NON_PRIV_FUNC) {
adapter->op_mode = QLCNIC_NON_PRIV_FUNC;
@@ -591,13 +608,14 @@ qlcnic_setup_pci_map(struct qlcnic_adapter *adapter)
dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20));
- adapter->ahw.pci_base0 = mem_ptr0;
- adapter->ahw.pci_len0 = pci_len0;
+ adapter->ahw->pci_base0 = mem_ptr0;
+ adapter->ahw->pci_len0 = pci_len0;
qlcnic_check_vf(adapter);
- adapter->ahw.ocm_win_crb = qlcnic_get_ioaddr(adapter,
- QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(adapter->ahw.pci_func)));
+ adapter->ahw->ocm_win_crb = qlcnic_get_ioaddr(adapter,
+ QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(
+ adapter->ahw->pci_func)));
return 0;
}
@@ -639,7 +657,7 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
dev_info(&pdev->dev, "firmware v%d.%d.%d\n",
fw_major, fw_minor, fw_build);
- if (adapter->ahw.port_type == QLCNIC_XGBE) {
+ if (adapter->ahw->port_type == QLCNIC_XGBE) {
if (adapter->flags & QLCNIC_ESWITCH_ENABLED) {
adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_VF;
adapter->max_rxd = MAX_RCV_DESCRIPTORS_VF;
@@ -651,7 +669,7 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
- } else if (adapter->ahw.port_type == QLCNIC_GBE) {
+ } else if (adapter->ahw->port_type == QLCNIC_GBE) {
adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G;
adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
adapter->max_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
@@ -659,7 +677,6 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
}
adapter->msix_supported = !!use_msi_x;
- adapter->rss_supported = !!use_msi_x;
adapter->num_txd = MAX_CMD_DESCRIPTORS;
@@ -672,7 +689,7 @@ qlcnic_initialize_nic(struct qlcnic_adapter *adapter)
int err;
struct qlcnic_info nic_info;
- err = qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw.pci_func);
+ err = qlcnic_get_nic_info(adapter, &nic_info, adapter->ahw->pci_func);
if (err)
return err;
@@ -708,6 +725,22 @@ qlcnic_set_vlan_config(struct qlcnic_adapter *adapter,
}
static void
+qlcnic_vlan_rx_add(struct net_device *netdev, u16 vid)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ set_bit(vid, adapter->vlans);
+}
+
+static void
+qlcnic_vlan_rx_del(struct net_device *netdev, u16 vid)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+
+ qlcnic_restore_indev_addr(netdev, NETDEV_DOWN);
+ clear_bit(vid, adapter->vlans);
+}
+
+static void
qlcnic_set_eswitch_port_features(struct qlcnic_adapter *adapter,
struct qlcnic_esw_func_cfg *esw_cfg)
{
@@ -734,7 +767,7 @@ qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter)
if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
return 0;
- esw_cfg.pci_func = adapter->ahw.pci_func;
+ esw_cfg.pci_func = adapter->ahw->pci_func;
if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg))
return -EIO;
qlcnic_set_vlan_config(adapter, &esw_cfg);
@@ -750,28 +783,27 @@ qlcnic_set_netdev_features(struct qlcnic_adapter *adapter,
struct net_device *netdev = adapter->netdev;
unsigned long features, vlan_features;
- features = (NETIF_F_SG | NETIF_F_IP_CSUM |
+ features = (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
NETIF_F_IPV6_CSUM | NETIF_F_GRO);
vlan_features = (NETIF_F_SG | NETIF_F_IP_CSUM |
- NETIF_F_IPV6_CSUM);
+ NETIF_F_IPV6_CSUM | NETIF_F_HW_VLAN_FILTER);
if (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO) {
features |= (NETIF_F_TSO | NETIF_F_TSO6);
vlan_features |= (NETIF_F_TSO | NETIF_F_TSO6);
}
- if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
+
+ if (netdev->features & NETIF_F_LRO)
features |= NETIF_F_LRO;
if (esw_cfg->offload_flags & BIT_0) {
netdev->features |= features;
- adapter->rx_csum = 1;
if (!(esw_cfg->offload_flags & BIT_1))
netdev->features &= ~NETIF_F_TSO;
if (!(esw_cfg->offload_flags & BIT_2))
netdev->features &= ~NETIF_F_TSO6;
} else {
netdev->features &= ~features;
- adapter->rx_csum = 0;
}
netdev->vlan_features = (features & vlan_features);
@@ -791,14 +823,14 @@ qlcnic_check_eswitch_mode(struct qlcnic_adapter *adapter)
if (adapter->flags & QLCNIC_ADAPTER_INITIALIZED)
return 0;
- priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
+ priv_op = adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE;
op_mode = readl(priv_op);
- priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func);
+ priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw->pci_func);
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);
+ priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw->pci_func);
if (adapter->flags & QLCNIC_ESWITCH_ENABLED) {
if (priv_level == QLCNIC_MGMT_FUNC) {
@@ -1038,7 +1070,7 @@ qlcnic_request_irq(struct qlcnic_adapter *adapter)
unsigned long flags = 0;
struct net_device *netdev = adapter->netdev;
- struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
handler = qlcnic_tmp_intr;
@@ -1075,7 +1107,7 @@ qlcnic_free_irq(struct qlcnic_adapter *adapter)
int ring;
struct qlcnic_host_sds_ring *sds_ring;
- struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
for (ring = 0; ring < adapter->max_sds_rings; ring++) {
sds_ring = &recv_ctx->sds_rings[ring];
@@ -1083,20 +1115,6 @@ qlcnic_free_irq(struct qlcnic_adapter *adapter)
}
}
-static void
-qlcnic_init_coalesce_defaults(struct qlcnic_adapter *adapter)
-{
- adapter->coal.flags = QLCNIC_INTR_DEFAULT;
- adapter->coal.normal.data.rx_time_us =
- QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US;
- adapter->coal.normal.data.rx_packets =
- QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS;
- adapter->coal.normal.data.tx_time_us =
- QLCNIC_DEFAULT_INTR_COALESCE_TX_TIME_US;
- adapter->coal.normal.data.tx_packets =
- QLCNIC_DEFAULT_INTR_COALESCE_TX_PACKETS;
-}
-
static int
__qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
{
@@ -1115,14 +1133,14 @@ __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
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);
+ rds_ring = &adapter->recv_ctx->rds_rings[ring];
+ qlcnic_post_rx_buffers(adapter, rds_ring);
}
qlcnic_set_multi(netdev);
qlcnic_fw_cmd_set_mtu(adapter, netdev->mtu);
- adapter->ahw.linkup = 0;
+ adapter->ahw->linkup = 0;
if (adapter->max_sds_rings > 1)
qlcnic_config_rss(adapter, 1);
@@ -1230,8 +1248,6 @@ qlcnic_attach(struct qlcnic_adapter *adapter)
goto err_out_free_hw;
}
- qlcnic_init_coalesce_defaults(adapter);
-
qlcnic_create_sysfs_entries(adapter);
adapter->is_up = QLCNIC_ADAPTER_UP_MAGIC;
@@ -1272,7 +1288,7 @@ void qlcnic_diag_free_res(struct net_device *netdev, int max_sds_rings)
clear_bit(__QLCNIC_DEV_UP, &adapter->state);
if (adapter->diag_test == QLCNIC_INTERRUPT_TEST) {
for (ring = 0; ring < adapter->max_sds_rings; ring++) {
- sds_ring = &adapter->recv_ctx.sds_rings[ring];
+ sds_ring = &adapter->recv_ctx->sds_rings[ring];
qlcnic_disable_int(sds_ring);
}
}
@@ -1293,6 +1309,48 @@ out:
netif_device_attach(netdev);
}
+static int qlcnic_alloc_adapter_resources(struct qlcnic_adapter *adapter)
+{
+ int err = 0;
+ adapter->ahw = kzalloc(sizeof(struct qlcnic_hardware_context),
+ GFP_KERNEL);
+ if (!adapter->ahw) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to allocate recv ctx resources for adapter\n");
+ err = -ENOMEM;
+ goto err_out;
+ }
+ adapter->recv_ctx = kzalloc(sizeof(struct qlcnic_recv_context),
+ GFP_KERNEL);
+ if (!adapter->recv_ctx) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to allocate recv ctx resources for adapter\n");
+ kfree(adapter->ahw);
+ adapter->ahw = NULL;
+ err = -ENOMEM;
+ goto err_out;
+ }
+ /* Initialize interrupt coalesce parameters */
+ adapter->ahw->coal.flag = QLCNIC_INTR_DEFAULT;
+ adapter->ahw->coal.rx_time_us = QLCNIC_DEFAULT_INTR_COALESCE_RX_TIME_US;
+ adapter->ahw->coal.rx_packets = QLCNIC_DEFAULT_INTR_COALESCE_RX_PACKETS;
+err_out:
+ return err;
+}
+
+static void qlcnic_free_adapter_resources(struct qlcnic_adapter *adapter)
+{
+ kfree(adapter->recv_ctx);
+ adapter->recv_ctx = NULL;
+
+ if (adapter->ahw->fw_dump.tmpl_hdr) {
+ vfree(adapter->ahw->fw_dump.tmpl_hdr);
+ adapter->ahw->fw_dump.tmpl_hdr = NULL;
+ }
+ kfree(adapter->ahw);
+ adapter->ahw = NULL;
+}
+
int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
@@ -1325,13 +1383,13 @@ int qlcnic_diag_alloc_res(struct net_device *netdev, int test)
}
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);
+ rds_ring = &adapter->recv_ctx->rds_rings[ring];
+ qlcnic_post_rx_buffers(adapter, 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];
+ sds_ring = &adapter->recv_ctx->sds_rings[ring];
qlcnic_enable_int(sds_ring);
}
}
@@ -1399,7 +1457,6 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
int err;
struct pci_dev *pdev = adapter->pdev;
- adapter->rx_csum = 1;
adapter->mc_enabled = 0;
adapter->max_mc_count = 38;
@@ -1410,26 +1467,24 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops);
- netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
- NETIF_F_IPV6_CSUM | NETIF_F_GRO | NETIF_F_HW_VLAN_RX);
- netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
- NETIF_F_IPV6_CSUM);
+ netdev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM |
+ NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM;
- 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 (adapter->capabilities & QLCNIC_FW_CAPABILITY_TSO)
+ netdev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6;
+ if (pci_using_dac)
+ netdev->hw_features |= NETIF_F_HIGHDMA;
- if (pci_using_dac) {
- netdev->features |= NETIF_F_HIGHDMA;
- netdev->vlan_features |= NETIF_F_HIGHDMA;
- }
+ netdev->vlan_features = netdev->hw_features;
if (adapter->capabilities & QLCNIC_FW_CAPABILITY_FVLANTX)
- netdev->features |= (NETIF_F_HW_VLAN_TX);
-
+ netdev->hw_features |= NETIF_F_HW_VLAN_TX;
if (adapter->capabilities & QLCNIC_FW_CAPABILITY_HW_LRO)
- netdev->features |= NETIF_F_LRO;
+ netdev->hw_features |= NETIF_F_LRO;
+
+ netdev->features |= netdev->hw_features |
+ NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
+
netdev->irq = adapter->msix_entries[0].vector;
netif_carrier_off(netdev);
@@ -1459,6 +1514,19 @@ static int qlcnic_set_dma_mask(struct pci_dev *pdev, u8 *pci_using_dac)
return 0;
}
+static int
+qlcnic_alloc_msix_entries(struct qlcnic_adapter *adapter, u16 count)
+{
+ adapter->msix_entries = kcalloc(count, sizeof(struct msix_entry),
+ GFP_KERNEL);
+
+ if (adapter->msix_entries)
+ return 0;
+
+ dev_err(&adapter->pdev->dev, "failed allocating msix_entries\n");
+ return -ENOMEM;
+}
+
static int __devinit
qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -1501,23 +1569,30 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter = netdev_priv(netdev);
adapter->netdev = netdev;
adapter->pdev = pdev;
- adapter->dev_rst_time = jiffies;
+ if (qlcnic_alloc_adapter_resources(adapter))
+ goto err_out_free_netdev;
+
+ adapter->dev_rst_time = jiffies;
revision_id = pdev->revision;
- adapter->ahw.revision_id = revision_id;
+ adapter->ahw->revision_id = revision_id;
- rwlock_init(&adapter->ahw.crb_lock);
- mutex_init(&adapter->ahw.mem_lock);
+ rwlock_init(&adapter->ahw->crb_lock);
+ mutex_init(&adapter->ahw->mem_lock);
spin_lock_init(&adapter->tx_clean_lock);
INIT_LIST_HEAD(&adapter->mac_list);
err = qlcnic_setup_pci_map(adapter);
if (err)
- goto err_out_free_netdev;
+ goto err_out_free_hw;
/* This will be reset for mezz cards */
- adapter->portnum = adapter->ahw.pci_func;
+ adapter->portnum = adapter->ahw->pci_func;
+
+ /* Get FW dump template and store it */
+ if (adapter->op_mode != QLCNIC_NON_PRIV_FUNC)
+ qlcnic_fw_cmd_get_minidump_temp(adapter);
err = qlcnic_get_board_info(adapter);
if (err) {
@@ -1545,11 +1620,15 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pr_info("%s: %s Board Chip rev 0x%x\n",
module_name(THIS_MODULE),
- brd_name, adapter->ahw.revision_id);
+ brd_name, adapter->ahw->revision_id);
}
qlcnic_clear_stats(adapter);
+ err = qlcnic_alloc_msix_entries(adapter, adapter->max_rx_ques);
+ if (err)
+ goto err_out_decr_ref;
+
qlcnic_setup_intr(adapter);
err = qlcnic_setup_netdev(adapter, netdev, pci_using_dac);
@@ -1560,7 +1639,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
- switch (adapter->ahw.port_type) {
+ switch (adapter->ahw->port_type) {
case QLCNIC_GBE:
dev_info(&adapter->pdev->dev, "%s: GbE port initialized\n",
adapter->netdev->name);
@@ -1578,6 +1657,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err_out_disable_msi:
qlcnic_teardown_intr(adapter);
+ kfree(adapter->msix_entries);
err_out_decr_ref:
qlcnic_clr_all_drv_state(adapter, 0);
@@ -1585,6 +1665,9 @@ err_out_decr_ref:
err_out_iounmap:
qlcnic_cleanup_pci_map(adapter);
+err_out_free_hw:
+ qlcnic_free_adapter_resources(adapter);
+
err_out_free_netdev:
free_netdev(netdev);
@@ -1626,6 +1709,7 @@ static void __devexit qlcnic_remove(struct pci_dev *pdev)
qlcnic_free_lb_filters_mem(adapter);
qlcnic_teardown_intr(adapter);
+ kfree(adapter->msix_entries);
qlcnic_remove_diag_entries(adapter);
@@ -1638,6 +1722,7 @@ static void __devexit qlcnic_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
+ qlcnic_free_adapter_resources(adapter);
free_netdev(netdev);
}
static int __qlcnic_shutdown(struct pci_dev *pdev)
@@ -1819,6 +1904,7 @@ static void qlcnic_change_filter(struct qlcnic_adapter *adapter,
vlan_req->vlan_id = vlan_id;
tx_ring->producer = get_next_index(producer, tx_ring->num_desc);
+ smp_mb();
}
#define QLCNIC_MAC_HASH(MAC)\
@@ -1879,58 +1965,122 @@ qlcnic_send_filter(struct qlcnic_adapter *adapter,
spin_unlock(&adapter->mac_learn_lock);
}
-static void
-qlcnic_tso_check(struct net_device *netdev,
- struct qlcnic_host_tx_ring *tx_ring,
+static int
+qlcnic_tx_pkt(struct qlcnic_adapter *adapter,
struct cmd_desc_type0 *first_desc,
struct sk_buff *skb)
{
- u8 opcode = TX_ETHER_PKT;
- __be16 protocol = skb->protocol;
- u16 flags = 0;
- int copied, offset, copy_len, hdr_len = 0, tso = 0;
+ u8 opcode = 0, hdr_len = 0;
+ u16 flags = 0, vlan_tci = 0;
+ int copied, offset, copy_len;
struct cmd_desc_type0 *hwdesc;
struct vlan_ethhdr *vh;
- struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
+ u16 protocol = ntohs(skb->protocol);
u32 producer = tx_ring->producer;
- __le16 vlan_oob = first_desc->flags_opcode &
- cpu_to_le16(FLAGS_VLAN_OOB);
+
+ if (protocol == ETH_P_8021Q) {
+ vh = (struct vlan_ethhdr *)skb->data;
+ flags = FLAGS_VLAN_TAGGED;
+ vlan_tci = vh->h_vlan_TCI;
+ } else if (vlan_tx_tag_present(skb)) {
+ flags = FLAGS_VLAN_OOB;
+ vlan_tci = vlan_tx_tag_get(skb);
+ }
+ if (unlikely(adapter->pvid)) {
+ if (vlan_tci && !(adapter->flags & QLCNIC_TAGGING_ENABLED))
+ return -EIO;
+ if (vlan_tci && (adapter->flags & QLCNIC_TAGGING_ENABLED))
+ goto set_flags;
+
+ flags = FLAGS_VLAN_OOB;
+ vlan_tci = adapter->pvid;
+ }
+set_flags:
+ qlcnic_set_tx_vlan_tci(first_desc, vlan_tci);
+ qlcnic_set_tx_flags_opcode(first_desc, flags, opcode);
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)) &&
+ opcode = TX_ETHER_PKT;
+ if ((adapter->netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
skb_shinfo(skb)->gso_size > 0) {
hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
first_desc->total_hdr_length = hdr_len;
- if (vlan_oob) {
+
+ opcode = (protocol == ETH_P_IPV6) ? TX_TCP_LSO6 : TX_TCP_LSO;
+
+ /* For LSO, we need to copy the MAC/IP/TCP headers into
+ * the descriptor ring */
+ copied = 0;
+ offset = 2;
+
+ if (flags & FLAGS_VLAN_OOB) {
first_desc->total_hdr_length += VLAN_HLEN;
first_desc->tcp_hdr_offset = VLAN_HLEN;
first_desc->ip_hdr_offset = VLAN_HLEN;
/* Only in case of TSO on vlan device */
flags |= FLAGS_VLAN_TAGGED;
+
+ /* Create a TSO vlan header template for firmware */
+
+ hwdesc = &tx_ring->desc_head[producer];
+ tx_ring->cmd_buf_arr[producer].skb = NULL;
+
+ copy_len = min((int)sizeof(struct cmd_desc_type0) -
+ offset, hdr_len + VLAN_HLEN);
+
+ vh = (struct vlan_ethhdr *)((char *) hwdesc + 2);
+ skb_copy_from_linear_data(skb, vh, 12);
+ vh->h_vlan_proto = htons(ETH_P_8021Q);
+ vh->h_vlan_TCI = htons(vlan_tci);
+
+ skb_copy_from_linear_data_offset(skb, 12,
+ (char *)vh + 16, copy_len - 16);
+
+ copied = copy_len - VLAN_HLEN;
+ offset = 0;
+
+ producer = get_next_index(producer, tx_ring->num_desc);
}
- opcode = (protocol == cpu_to_be16(ETH_P_IPV6)) ?
- TX_TCP_LSO6 : TX_TCP_LSO;
- tso = 1;
+ while (copied < hdr_len) {
+
+ copy_len = min((int)sizeof(struct cmd_desc_type0) -
+ offset, (hdr_len - copied));
+
+ hwdesc = &tx_ring->desc_head[producer];
+ tx_ring->cmd_buf_arr[producer].skb = NULL;
+
+ skb_copy_from_linear_data_offset(skb, copied,
+ (char *) hwdesc + offset, copy_len);
+
+ copied += copy_len;
+ offset = 0;
+
+ producer = get_next_index(producer, tx_ring->num_desc);
+ }
+
+ tx_ring->producer = producer;
+ smp_mb();
+ adapter->stats.lso_frames++;
} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
u8 l4proto;
- if (protocol == cpu_to_be16(ETH_P_IP)) {
+ if (protocol == ETH_P_IP) {
l4proto = ip_hdr(skb)->protocol;
if (l4proto == IPPROTO_TCP)
opcode = TX_TCP_PKT;
else if (l4proto == IPPROTO_UDP)
opcode = TX_UDP_PKT;
- } else if (protocol == cpu_to_be16(ETH_P_IPV6)) {
+ } else if (protocol == ETH_P_IPV6) {
l4proto = ipv6_hdr(skb)->nexthdr;
if (l4proto == IPPROTO_TCP)
@@ -1939,63 +2089,11 @@ qlcnic_tso_check(struct net_device *netdev,
opcode = TX_UDPV6_PKT;
}
}
-
first_desc->tcp_hdr_offset += skb_transport_offset(skb);
first_desc->ip_hdr_offset += skb_network_offset(skb);
qlcnic_set_tx_flags_opcode(first_desc, flags, opcode);
- if (!tso)
- return;
-
- /* For LSO, we need to copy the MAC/IP/TCP headers into
- * the descriptor ring
- */
- copied = 0;
- offset = 2;
-
- if (vlan_oob) {
- /* Create a TSO vlan header template for firmware */
-
- hwdesc = &tx_ring->desc_head[producer];
- tx_ring->cmd_buf_arr[producer].skb = NULL;
-
- copy_len = min((int)sizeof(struct cmd_desc_type0) - offset,
- hdr_len + VLAN_HLEN);
-
- vh = (struct vlan_ethhdr *)((char *)hwdesc + 2);
- skb_copy_from_linear_data(skb, vh, 12);
- vh->h_vlan_proto = htons(ETH_P_8021Q);
- vh->h_vlan_TCI = (__be16)swab16((u16)first_desc->vlan_TCI);
-
- skb_copy_from_linear_data_offset(skb, 12,
- (char *)vh + 16, copy_len - 16);
-
- copied = copy_len - VLAN_HLEN;
- offset = 0;
-
- producer = get_next_index(producer, tx_ring->num_desc);
- }
-
- while (copied < hdr_len) {
-
- copy_len = min((int)sizeof(struct cmd_desc_type0) - offset,
- (hdr_len - copied));
-
- hwdesc = &tx_ring->desc_head[producer];
- tx_ring->cmd_buf_arr[producer].skb = NULL;
-
- skb_copy_from_linear_data_offset(skb, copied,
- (char *)hwdesc + offset, copy_len);
-
- copied += copy_len;
- offset = 0;
-
- producer = get_next_index(producer, tx_ring->num_desc);
- }
-
- tx_ring->producer = producer;
- barrier();
- adapter->stats.lso_frames++;
+ return 0;
}
static int
@@ -2046,39 +2144,21 @@ out_err:
return -ENOMEM;
}
-static int
-qlcnic_check_tx_tagging(struct qlcnic_adapter *adapter,
- struct sk_buff *skb,
- struct cmd_desc_type0 *first_desc)
+static void
+qlcnic_unmap_buffers(struct pci_dev *pdev, struct sk_buff *skb,
+ struct qlcnic_cmd_buffer *pbuf)
{
- u8 opcode = 0;
- u16 flags = 0;
- __be16 protocol = skb->protocol;
- struct vlan_ethhdr *vh;
+ struct qlcnic_skb_frag *nf = &pbuf->frag_array[0];
+ int nr_frags = skb_shinfo(skb)->nr_frags;
+ int i;
- if (protocol == cpu_to_be16(ETH_P_8021Q)) {
- vh = (struct vlan_ethhdr *)skb->data;
- protocol = vh->h_vlan_encapsulated_proto;
- flags = FLAGS_VLAN_TAGGED;
- qlcnic_set_tx_vlan_tci(first_desc, ntohs(vh->h_vlan_TCI));
- } else if (vlan_tx_tag_present(skb)) {
- flags = FLAGS_VLAN_OOB;
- qlcnic_set_tx_vlan_tci(first_desc, vlan_tx_tag_get(skb));
+ for (i = 0; i < nr_frags; i++) {
+ nf = &pbuf->frag_array[i+1];
+ pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE);
}
- if (unlikely(adapter->pvid)) {
- if (first_desc->vlan_TCI &&
- !(adapter->flags & QLCNIC_TAGGING_ENABLED))
- return -EIO;
- if (first_desc->vlan_TCI &&
- (adapter->flags & QLCNIC_TAGGING_ENABLED))
- goto set_flags;
- flags = FLAGS_VLAN_OOB;
- qlcnic_set_tx_vlan_tci(first_desc, adapter->pvid);
- }
-set_flags:
- qlcnic_set_tx_flags_opcode(first_desc, flags, opcode);
- return 0;
+ nf = &pbuf->frag_array[0];
+ pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE);
}
static inline void
@@ -2103,7 +2183,7 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
int i, k;
u32 producer;
- int frag_count, no_of_desc;
+ int frag_count;
u32 num_txd = tx_ring->num_desc;
if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
@@ -2133,12 +2213,8 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
frag_count = 1 + skb_shinfo(skb)->nr_frags;
}
- /* 4 fragments per cmd des */
- no_of_desc = (frag_count + 3) >> 2;
-
if (unlikely(qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH)) {
netif_stop_queue(netdev);
- smp_mb();
if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH)
netif_start_queue(netdev);
else {
@@ -2155,9 +2231,6 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
first_desc = hwdesc = &tx_ring->desc_head[producer];
qlcnic_clear_cmddesc((u64 *)hwdesc);
- if (qlcnic_check_tx_tagging(adapter, skb, first_desc))
- goto drop_packet;
-
if (qlcnic_map_tx_skb(pdev, skb, pbuf)) {
adapter->stats.tx_dma_map_error++;
goto drop_packet;
@@ -2201,8 +2274,10 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
}
tx_ring->producer = get_next_index(producer, num_txd);
+ smp_mb();
- qlcnic_tso_check(netdev, tx_ring, first_desc, skb);
+ if (unlikely(qlcnic_tx_pkt(adapter, first_desc, skb)))
+ goto unwind_buff;
if (qlcnic_mac_learn)
qlcnic_send_filter(adapter, tx_ring, first_desc, skb);
@@ -2214,6 +2289,8 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
return NETDEV_TX_OK;
+unwind_buff:
+ qlcnic_unmap_buffers(pdev, skb, pbuf);
drop_packet:
adapter->stats.txdropped++;
dev_kfree_skb_any(skb);
@@ -2260,16 +2337,16 @@ void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup)
{
struct net_device *netdev = adapter->netdev;
- if (adapter->ahw.linkup && !linkup) {
+ if (adapter->ahw->linkup && !linkup) {
netdev_info(netdev, "NIC Link is down\n");
- adapter->ahw.linkup = 0;
+ adapter->ahw->linkup = 0;
if (netif_running(netdev)) {
netif_carrier_off(netdev);
netif_stop_queue(netdev);
}
- } else if (!adapter->ahw.linkup && linkup) {
+ } else if (!adapter->ahw->linkup && linkup) {
netdev_info(netdev, "NIC Link is up\n");
- adapter->ahw.linkup = 1;
+ adapter->ahw->linkup = 1;
if (netif_running(netdev)) {
netif_carrier_on(netdev);
netif_wake_queue(netdev);
@@ -2505,7 +2582,7 @@ static void qlcnic_poll_controller(struct net_device *netdev)
int ring;
struct qlcnic_host_sds_ring *sds_ring;
struct qlcnic_adapter *adapter = netdev_priv(netdev);
- struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
disable_irq(adapter->irq);
for (ring = 0; ring < adapter->max_sds_rings; ring++) {
@@ -2756,6 +2833,8 @@ skip_ack_check:
set_bit(__QLCNIC_START_FW, &adapter->state);
QLCDB(adapter, DRV, "Restarting fw\n");
qlcnic_idc_debug_info(adapter, 0);
+ QLCDB(adapter, DRV, "Take FW dump\n");
+ qlcnic_dump_fw(adapter);
}
qlcnic_api_unlock(adapter);
@@ -2854,7 +2933,7 @@ qlcnic_set_npar_non_operational(struct qlcnic_adapter *adapter)
}
/*Transit to RESET state from READY state only */
-static void
+void
qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
{
u32 state;
@@ -3266,6 +3345,56 @@ static struct device_attribute dev_attr_diag_mode = {
.store = qlcnic_store_diag_mode,
};
+int qlcnic_validate_max_rss(struct net_device *netdev, u8 max_hw, u8 val)
+{
+ if (!use_msi_x && !use_msi) {
+ netdev_info(netdev, "no msix or msi support, hence no rss\n");
+ return -EINVAL;
+ }
+
+ if ((val > max_hw) || (val < 2) || !is_power_of_2(val)) {
+ netdev_info(netdev, "rss_ring valid range [2 - %x] in "
+ " powers of 2\n", max_hw);
+ return -EINVAL;
+ }
+ return 0;
+
+}
+
+int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data)
+{
+ struct net_device *netdev = adapter->netdev;
+ int err = 0;
+
+ if (test_and_set_bit(__QLCNIC_RESETTING, &adapter->state))
+ return -EBUSY;
+
+ netif_device_detach(netdev);
+ if (netif_running(netdev))
+ __qlcnic_down(adapter, netdev);
+ qlcnic_detach(adapter);
+ qlcnic_teardown_intr(adapter);
+
+ if (qlcnic_enable_msix(adapter, data)) {
+ netdev_info(netdev, "failed setting max_rss; rss disabled\n");
+ qlcnic_enable_msi_legacy(adapter);
+ }
+
+ if (netif_running(netdev)) {
+ err = qlcnic_attach(adapter);
+ if (err)
+ goto done;
+ err = __qlcnic_up(adapter, netdev);
+ if (err)
+ goto done;
+ qlcnic_restore_indev_addr(netdev, NETDEV_UP);
+ }
+ done:
+ netif_device_attach(netdev);
+ clear_bit(__QLCNIC_RESETTING, &adapter->state);
+ return err;
+}
+
static int
qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter,
loff_t offset, size_t size)
@@ -3396,7 +3525,6 @@ qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj,
return size;
}
-
static struct bin_attribute bin_attr_crb = {
.attr = {.name = "crb", .mode = (S_IRUGO | S_IWUSR)},
.size = 0,
@@ -3515,7 +3643,7 @@ validate_esw_config(struct qlcnic_adapter *adapter,
u8 pci_func;
int i;
- op_mode = readl(adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE);
+ op_mode = readl(adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE);
for (i = 0; i < count; i++) {
pci_func = esw_cfg[i].pci_func;
@@ -3581,13 +3709,13 @@ qlcnic_sysfs_write_esw_config(struct file *file, struct kobject *kobj,
if (qlcnic_config_switch_port(adapter, &esw_cfg[i]))
return QL_STATUS_INVALID_PARAM;
- if (adapter->ahw.pci_func != esw_cfg[i].pci_func)
+ if (adapter->ahw->pci_func != esw_cfg[i].pci_func)
continue;
op_mode = esw_cfg[i].op_mode;
qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]);
esw_cfg[i].op_mode = op_mode;
- esw_cfg[i].pci_func = adapter->ahw.pci_func;
+ esw_cfg[i].pci_func = adapter->ahw->pci_func;
switch (esw_cfg[i].op_mode) {
case QLCNIC_PORT_DEFAULTS:
@@ -3968,14 +4096,14 @@ qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
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 (device_create_bin_file(dev, &bin_attr_pci_config))
+ dev_info(dev, "failed to create pci config sysfs entry");
if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
return;
if (device_create_bin_file(dev, &bin_attr_esw_config))
dev_info(dev, "failed to create esw config sysfs entry");
if (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_pm_config))
@@ -3996,12 +4124,12 @@ qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
device_remove_file(dev, &dev_attr_diag_mode);
device_remove_bin_file(dev, &bin_attr_crb);
device_remove_bin_file(dev, &bin_attr_mem);
+ device_remove_bin_file(dev, &bin_attr_pci_config);
if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
return;
device_remove_bin_file(dev, &bin_attr_esw_config);
if (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_pm_config);
device_remove_bin_file(dev, &bin_attr_esw_stats);
@@ -4048,14 +4176,10 @@ qlcnic_restore_indev_addr(struct net_device *netdev, unsigned long event)
qlcnic_config_indev_addr(adapter, netdev, event);
- if (!adapter->vlgrp)
- return;
-
- for (vid = 0; vid < VLAN_N_VID; vid++) {
- dev = vlan_group_get_device(adapter->vlgrp, vid);
+ for_each_set_bit(vid, adapter->vlans, VLAN_N_VID) {
+ dev = vlan_find_dev(netdev, vid);
if (!dev)
continue;
-
qlcnic_config_indev_addr(adapter, dev, event);
}
}
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
index 4757c59a07a2..d32850715f5c 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -2134,7 +2134,7 @@ struct ql_adapter {
struct delayed_work mpi_idc_work;
struct delayed_work mpi_core_to_log;
struct completion ide_completion;
- struct nic_operations *nic_ops;
+ const struct nic_operations *nic_ops;
u16 device_id;
struct timer_list timer;
atomic_t lb_count;
diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c
index 8149cc9de4ca..19b00fa0eaf0 100644
--- a/drivers/net/qlge/qlge_ethtool.c
+++ b/drivers/net/qlge/qlge_ethtool.c
@@ -356,7 +356,7 @@ static int ql_get_settings(struct net_device *ndev,
ecmd->port = PORT_FIBRE;
}
- ecmd->speed = SPEED_10000;
+ ethtool_cmd_speed_set(ecmd, SPEED_10000);
ecmd->duplex = DUPLEX_FULL;
return 0;
@@ -412,31 +412,31 @@ static int ql_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
return 0;
}
-static int ql_phys_id(struct net_device *ndev, u32 data)
+static int ql_set_phys_id(struct net_device *ndev,
+ enum ethtool_phys_id_state state)
+
{
struct ql_adapter *qdev = netdev_priv(ndev);
- u32 led_reg, i;
- int status;
-
- /* Save the current LED settings */
- status = ql_mb_get_led_cfg(qdev);
- if (status)
- return status;
- led_reg = qdev->led_config;
- /* Start blinking the led */
- if (!data || data > 300)
- data = 300;
+ switch (state) {
+ case ETHTOOL_ID_ACTIVE:
+ /* Save the current LED settings */
+ if (ql_mb_get_led_cfg(qdev))
+ return -EIO;
- for (i = 0; i < (data * 10); i++)
+ /* Start blinking */
ql_mb_set_led_cfg(qdev, QL_LED_BLINK);
+ return 0;
- /* Restore LED settings */
- status = ql_mb_set_led_cfg(qdev, led_reg);
- if (status)
- return status;
+ case ETHTOOL_ID_INACTIVE:
+ /* Restore LED settings */
+ if (ql_mb_set_led_cfg(qdev, qdev->led_config))
+ return -EIO;
+ return 0;
- return 0;
+ default:
+ return -EINVAL;
+ }
}
static int ql_start_loopback(struct ql_adapter *qdev)
@@ -655,32 +655,6 @@ static int ql_set_pauseparam(struct net_device *netdev,
return status;
}
-static u32 ql_get_rx_csum(struct net_device *netdev)
-{
- struct ql_adapter *qdev = netdev_priv(netdev);
- return qdev->rx_csum;
-}
-
-static int ql_set_rx_csum(struct net_device *netdev, uint32_t data)
-{
- struct ql_adapter *qdev = netdev_priv(netdev);
- qdev->rx_csum = data;
- return 0;
-}
-
-static int ql_set_tso(struct net_device *ndev, uint32_t data)
-{
-
- if (data) {
- ndev->features |= NETIF_F_TSO;
- ndev->features |= NETIF_F_TSO6;
- } else {
- ndev->features &= ~NETIF_F_TSO;
- ndev->features &= ~NETIF_F_TSO6;
- }
- return 0;
-}
-
static u32 ql_get_msglevel(struct net_device *ndev)
{
struct ql_adapter *qdev = netdev_priv(ndev);
@@ -703,18 +677,10 @@ const struct ethtool_ops qlge_ethtool_ops = {
.get_msglevel = ql_get_msglevel,
.set_msglevel = ql_set_msglevel,
.get_link = ethtool_op_get_link,
- .phys_id = ql_phys_id,
+ .set_phys_id = ql_set_phys_id,
.self_test = ql_self_test,
.get_pauseparam = ql_get_pauseparam,
.set_pauseparam = ql_set_pauseparam,
- .get_rx_csum = ql_get_rx_csum,
- .set_rx_csum = ql_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = ethtool_op_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
- .set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
- .set_tso = ql_set_tso,
.get_coalesce = ql_get_coalesce,
.set_coalesce = ql_set_coalesce,
.get_sset_count = ql_get_sset_count,
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 5bb311945436..930ae45457bb 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -38,6 +38,7 @@
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
+#include <linux/prefetch.h>
#include <net/ip6_checksum.h>
#include "qlge.h"
@@ -1571,7 +1572,7 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev,
skb->protocol = eth_type_trans(skb, ndev);
skb_checksum_none_assert(skb);
- if (qdev->rx_csum &&
+ if ((ndev->features & NETIF_F_RXCSUM) &&
!(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) {
/* TCP frame. */
if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) {
@@ -1684,7 +1685,7 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev,
/* If rx checksum is on, and there are no
* csum or frame errors.
*/
- if (qdev->rx_csum &&
+ if ((ndev->features & NETIF_F_RXCSUM) &&
!(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) {
/* TCP frame. */
if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) {
@@ -2004,7 +2005,7 @@ static void ql_process_mac_split_rx_intr(struct ql_adapter *qdev,
/* If rx checksum is on, and there are no
* csum or frame errors.
*/
- if (qdev->rx_csum &&
+ if ((ndev->features & NETIF_F_RXCSUM) &&
!(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) {
/* TCP frame. */
if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) {
@@ -4412,12 +4413,12 @@ error:
rtnl_unlock();
}
-static struct nic_operations qla8012_nic_ops = {
+static const struct nic_operations qla8012_nic_ops = {
.get_flash = ql_get_8012_flash_params,
.port_initialize = ql_8012_port_initialize,
};
-static struct nic_operations qla8000_nic_ops = {
+static const struct nic_operations qla8000_nic_ops = {
.get_flash = ql_get_8000_flash_params,
.port_initialize = ql_8000_port_initialize,
};
@@ -4621,7 +4622,6 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
/*
* Set up the operating parameters.
*/
- qdev->rx_csum = 1;
qdev->workqueue = create_singlethread_workqueue(ndev->name);
INIT_DELAYED_WORK(&qdev->asic_reset_work, ql_asic_reset_work);
INIT_DELAYED_WORK(&qdev->mpi_reset_work, ql_mpi_reset_work);
@@ -4695,15 +4695,11 @@ static int __devinit qlge_probe(struct pci_dev *pdev,
qdev = netdev_priv(ndev);
SET_NETDEV_DEV(ndev, &pdev->dev);
- ndev->features = (0
- | NETIF_F_IP_CSUM
- | NETIF_F_SG
- | NETIF_F_TSO
- | NETIF_F_TSO6
- | NETIF_F_TSO_ECN
- | NETIF_F_HW_VLAN_TX
- | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER);
- ndev->features |= NETIF_F_GRO;
+ ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM |
+ NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN |
+ NETIF_F_HW_VLAN_TX | NETIF_F_RXCSUM;
+ ndev->features = ndev->hw_features |
+ NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
if (test_bit(QL_DMA64, &qdev->flags))
ndev->features |= NETIF_F_HIGHDMA;
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 397c36810a15..ef1ce2ebeb4a 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -26,6 +26,7 @@
#include <linux/pm_runtime.h>
#include <linux/firmware.h>
#include <linux/pci-aspm.h>
+#include <linux/prefetch.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -37,6 +38,8 @@
#define FIRMWARE_8168D_1 "rtl_nic/rtl8168d-1.fw"
#define FIRMWARE_8168D_2 "rtl_nic/rtl8168d-2.fw"
+#define FIRMWARE_8168E_1 "rtl_nic/rtl8168e-1.fw"
+#define FIRMWARE_8168E_2 "rtl_nic/rtl8168e-2.fw"
#define FIRMWARE_8105E_1 "rtl_nic/rtl8105e-1.fw"
#ifdef RTL8169_DEBUG
@@ -96,89 +99,125 @@ static const int multicast_filter_limit = 32;
#define RTL_R32(reg) readl (ioaddr + (reg))
enum mac_version {
- RTL_GIGA_MAC_NONE = 0x00,
- RTL_GIGA_MAC_VER_01 = 0x01, // 8169
- RTL_GIGA_MAC_VER_02 = 0x02, // 8169S
- RTL_GIGA_MAC_VER_03 = 0x03, // 8110S
- RTL_GIGA_MAC_VER_04 = 0x04, // 8169SB
- RTL_GIGA_MAC_VER_05 = 0x05, // 8110SCd
- RTL_GIGA_MAC_VER_06 = 0x06, // 8110SCe
- RTL_GIGA_MAC_VER_07 = 0x07, // 8102e
- RTL_GIGA_MAC_VER_08 = 0x08, // 8102e
- RTL_GIGA_MAC_VER_09 = 0x09, // 8102e
- RTL_GIGA_MAC_VER_10 = 0x0a, // 8101e
- RTL_GIGA_MAC_VER_11 = 0x0b, // 8168Bb
- RTL_GIGA_MAC_VER_12 = 0x0c, // 8168Be
- RTL_GIGA_MAC_VER_13 = 0x0d, // 8101Eb
- RTL_GIGA_MAC_VER_14 = 0x0e, // 8101 ?
- RTL_GIGA_MAC_VER_15 = 0x0f, // 8101 ?
- RTL_GIGA_MAC_VER_16 = 0x11, // 8101Ec
- RTL_GIGA_MAC_VER_17 = 0x10, // 8168Bf
- RTL_GIGA_MAC_VER_18 = 0x12, // 8168CP
- RTL_GIGA_MAC_VER_19 = 0x13, // 8168C
- RTL_GIGA_MAC_VER_20 = 0x14, // 8168C
- RTL_GIGA_MAC_VER_21 = 0x15, // 8168C
- RTL_GIGA_MAC_VER_22 = 0x16, // 8168C
- RTL_GIGA_MAC_VER_23 = 0x17, // 8168CP
- RTL_GIGA_MAC_VER_24 = 0x18, // 8168CP
- RTL_GIGA_MAC_VER_25 = 0x19, // 8168D
- RTL_GIGA_MAC_VER_26 = 0x1a, // 8168D
- RTL_GIGA_MAC_VER_27 = 0x1b, // 8168DP
- RTL_GIGA_MAC_VER_28 = 0x1c, // 8168DP
- RTL_GIGA_MAC_VER_29 = 0x1d, // 8105E
- RTL_GIGA_MAC_VER_30 = 0x1e, // 8105E
+ RTL_GIGA_MAC_VER_01 = 0,
+ RTL_GIGA_MAC_VER_02,
+ RTL_GIGA_MAC_VER_03,
+ RTL_GIGA_MAC_VER_04,
+ RTL_GIGA_MAC_VER_05,
+ RTL_GIGA_MAC_VER_06,
+ RTL_GIGA_MAC_VER_07,
+ RTL_GIGA_MAC_VER_08,
+ RTL_GIGA_MAC_VER_09,
+ RTL_GIGA_MAC_VER_10,
+ RTL_GIGA_MAC_VER_11,
+ RTL_GIGA_MAC_VER_12,
+ RTL_GIGA_MAC_VER_13,
+ RTL_GIGA_MAC_VER_14,
+ RTL_GIGA_MAC_VER_15,
+ RTL_GIGA_MAC_VER_16,
+ RTL_GIGA_MAC_VER_17,
+ RTL_GIGA_MAC_VER_18,
+ RTL_GIGA_MAC_VER_19,
+ RTL_GIGA_MAC_VER_20,
+ RTL_GIGA_MAC_VER_21,
+ RTL_GIGA_MAC_VER_22,
+ RTL_GIGA_MAC_VER_23,
+ RTL_GIGA_MAC_VER_24,
+ RTL_GIGA_MAC_VER_25,
+ RTL_GIGA_MAC_VER_26,
+ RTL_GIGA_MAC_VER_27,
+ RTL_GIGA_MAC_VER_28,
+ RTL_GIGA_MAC_VER_29,
+ RTL_GIGA_MAC_VER_30,
+ RTL_GIGA_MAC_VER_31,
+ RTL_GIGA_MAC_VER_32,
+ RTL_GIGA_MAC_VER_33,
+ RTL_GIGA_MAC_NONE = 0xff,
};
-#define _R(NAME,MAC,MASK) \
- { .name = NAME, .mac_version = MAC, .RxConfigMask = MASK }
+enum rtl_tx_desc_version {
+ RTL_TD_0 = 0,
+ RTL_TD_1 = 1,
+};
+
+#define _R(NAME,TD,FW) \
+ { .name = NAME, .txd_version = TD, .fw_name = FW }
static const struct {
const char *name;
- u8 mac_version;
- u32 RxConfigMask; /* Clears the bits supported by this chip */
-} rtl_chip_info[] = {
- _R("RTL8169", RTL_GIGA_MAC_VER_01, 0xff7e1880), // 8169
- _R("RTL8169s", RTL_GIGA_MAC_VER_02, 0xff7e1880), // 8169S
- _R("RTL8110s", RTL_GIGA_MAC_VER_03, 0xff7e1880), // 8110S
- _R("RTL8169sb/8110sb", RTL_GIGA_MAC_VER_04, 0xff7e1880), // 8169SB
- _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_05, 0xff7e1880), // 8110SCd
- _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_06, 0xff7e1880), // 8110SCe
- _R("RTL8102e", RTL_GIGA_MAC_VER_07, 0xff7e1880), // PCI-E
- _R("RTL8102e", RTL_GIGA_MAC_VER_08, 0xff7e1880), // PCI-E
- _R("RTL8102e", RTL_GIGA_MAC_VER_09, 0xff7e1880), // PCI-E
- _R("RTL8101e", RTL_GIGA_MAC_VER_10, 0xff7e1880), // PCI-E
- _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_11, 0xff7e1880), // PCI-E
- _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_12, 0xff7e1880), // PCI-E
- _R("RTL8101e", RTL_GIGA_MAC_VER_13, 0xff7e1880), // PCI-E 8139
- _R("RTL8100e", RTL_GIGA_MAC_VER_14, 0xff7e1880), // PCI-E 8139
- _R("RTL8100e", RTL_GIGA_MAC_VER_15, 0xff7e1880), // PCI-E 8139
- _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_17, 0xff7e1880), // PCI-E
- _R("RTL8101e", RTL_GIGA_MAC_VER_16, 0xff7e1880), // PCI-E
- _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_18, 0xff7e1880), // PCI-E
- _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_19, 0xff7e1880), // PCI-E
- _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_20, 0xff7e1880), // PCI-E
- _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_21, 0xff7e1880), // PCI-E
- _R("RTL8168c/8111c", RTL_GIGA_MAC_VER_22, 0xff7e1880), // PCI-E
- _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_23, 0xff7e1880), // PCI-E
- _R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_24, 0xff7e1880), // PCI-E
- _R("RTL8168d/8111d", RTL_GIGA_MAC_VER_25, 0xff7e1880), // PCI-E
- _R("RTL8168d/8111d", RTL_GIGA_MAC_VER_26, 0xff7e1880), // PCI-E
- _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_27, 0xff7e1880), // PCI-E
- _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_28, 0xff7e1880), // PCI-E
- _R("RTL8105e", RTL_GIGA_MAC_VER_29, 0xff7e1880), // PCI-E
- _R("RTL8105e", RTL_GIGA_MAC_VER_30, 0xff7e1880) // PCI-E
-};
-#undef _R
-
-static const struct rtl_firmware_info {
- int mac_version;
+ enum rtl_tx_desc_version txd_version;
const char *fw_name;
-} rtl_firmware_infos[] = {
- { .mac_version = RTL_GIGA_MAC_VER_25, .fw_name = FIRMWARE_8168D_1 },
- { .mac_version = RTL_GIGA_MAC_VER_26, .fw_name = FIRMWARE_8168D_2 },
- { .mac_version = RTL_GIGA_MAC_VER_29, .fw_name = FIRMWARE_8105E_1 },
- { .mac_version = RTL_GIGA_MAC_VER_30, .fw_name = FIRMWARE_8105E_1 }
+} rtl_chip_infos[] = {
+ /* PCI devices. */
+ [RTL_GIGA_MAC_VER_01] =
+ _R("RTL8169", RTL_TD_0, NULL),
+ [RTL_GIGA_MAC_VER_02] =
+ _R("RTL8169s", RTL_TD_0, NULL),
+ [RTL_GIGA_MAC_VER_03] =
+ _R("RTL8110s", RTL_TD_0, NULL),
+ [RTL_GIGA_MAC_VER_04] =
+ _R("RTL8169sb/8110sb", RTL_TD_0, NULL),
+ [RTL_GIGA_MAC_VER_05] =
+ _R("RTL8169sc/8110sc", RTL_TD_0, NULL),
+ [RTL_GIGA_MAC_VER_06] =
+ _R("RTL8169sc/8110sc", RTL_TD_0, NULL),
+ /* PCI-E devices. */
+ [RTL_GIGA_MAC_VER_07] =
+ _R("RTL8102e", RTL_TD_1, NULL),
+ [RTL_GIGA_MAC_VER_08] =
+ _R("RTL8102e", RTL_TD_1, NULL),
+ [RTL_GIGA_MAC_VER_09] =
+ _R("RTL8102e", RTL_TD_1, NULL),
+ [RTL_GIGA_MAC_VER_10] =
+ _R("RTL8101e", RTL_TD_0, NULL),
+ [RTL_GIGA_MAC_VER_11] =
+ _R("RTL8168b/8111b", RTL_TD_0, NULL),
+ [RTL_GIGA_MAC_VER_12] =
+ _R("RTL8168b/8111b", RTL_TD_0, NULL),
+ [RTL_GIGA_MAC_VER_13] =
+ _R("RTL8101e", RTL_TD_0, NULL),
+ [RTL_GIGA_MAC_VER_14] =
+ _R("RTL8100e", RTL_TD_0, NULL),
+ [RTL_GIGA_MAC_VER_15] =
+ _R("RTL8100e", RTL_TD_0, NULL),
+ [RTL_GIGA_MAC_VER_16] =
+ _R("RTL8101e", RTL_TD_0, NULL),
+ [RTL_GIGA_MAC_VER_17] =
+ _R("RTL8168b/8111b", RTL_TD_0, NULL),
+ [RTL_GIGA_MAC_VER_18] =
+ _R("RTL8168cp/8111cp", RTL_TD_1, NULL),
+ [RTL_GIGA_MAC_VER_19] =
+ _R("RTL8168c/8111c", RTL_TD_1, NULL),
+ [RTL_GIGA_MAC_VER_20] =
+ _R("RTL8168c/8111c", RTL_TD_1, NULL),
+ [RTL_GIGA_MAC_VER_21] =
+ _R("RTL8168c/8111c", RTL_TD_1, NULL),
+ [RTL_GIGA_MAC_VER_22] =
+ _R("RTL8168c/8111c", RTL_TD_1, NULL),
+ [RTL_GIGA_MAC_VER_23] =
+ _R("RTL8168cp/8111cp", RTL_TD_1, NULL),
+ [RTL_GIGA_MAC_VER_24] =
+ _R("RTL8168cp/8111cp", RTL_TD_1, NULL),
+ [RTL_GIGA_MAC_VER_25] =
+ _R("RTL8168d/8111d", RTL_TD_1, FIRMWARE_8168D_1),
+ [RTL_GIGA_MAC_VER_26] =
+ _R("RTL8168d/8111d", RTL_TD_1, FIRMWARE_8168D_2),
+ [RTL_GIGA_MAC_VER_27] =
+ _R("RTL8168dp/8111dp", RTL_TD_1, NULL),
+ [RTL_GIGA_MAC_VER_28] =
+ _R("RTL8168dp/8111dp", RTL_TD_1, NULL),
+ [RTL_GIGA_MAC_VER_29] =
+ _R("RTL8105e", RTL_TD_1, FIRMWARE_8105E_1),
+ [RTL_GIGA_MAC_VER_30] =
+ _R("RTL8105e", RTL_TD_1, FIRMWARE_8105E_1),
+ [RTL_GIGA_MAC_VER_31] =
+ _R("RTL8168dp/8111dp", RTL_TD_1, NULL),
+ [RTL_GIGA_MAC_VER_32] =
+ _R("RTL8168e/8111e", RTL_TD_1, FIRMWARE_8168E_1),
+ [RTL_GIGA_MAC_VER_33] =
+ _R("RTL8168e/8111e", RTL_TD_1, FIRMWARE_8168E_2)
};
+#undef _R
enum cfg_version {
RTL_CFG_0 = 0x00,
@@ -232,6 +271,9 @@ enum rtl_registers {
IntrStatus = 0x3e,
TxConfig = 0x40,
RxConfig = 0x44,
+
+#define RTL_RX_CONFIG_MASK 0xff7e1880u
+
RxMissed = 0x4c,
Cfg9346 = 0x50,
Config0 = 0x51,
@@ -325,7 +367,9 @@ enum rtl8168_registers {
#define OCPAR_FLAG 0x80000000
#define OCPAR_GPHY_WRITE_CMD 0x8000f060
#define OCPAR_GPHY_READ_CMD 0x0000f060
- RDSAR1 = 0xd0 /* 8168c only. Undocumented on 8168dp */
+ RDSAR1 = 0xd0, /* 8168c only. Undocumented on 8168dp */
+ MISC = 0xf0, /* 8168e only. */
+#define TXPLA_RST (1 << 29)
};
enum rtl_register_content {
@@ -403,6 +447,7 @@ enum rtl_register_content {
BWF = (1 << 6), /* Accept Broadcast wakeup frame */
MWF = (1 << 5), /* Accept Multicast wakeup frame */
UWF = (1 << 4), /* Accept Unicast wakeup frame */
+ Spi_en = (1 << 3),
LanWake = (1 << 1), /* LanWake enable/disable */
PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */
@@ -451,21 +496,69 @@ enum rtl_register_content {
CounterDump = 0x8,
};
-enum desc_status_bit {
+enum rtl_desc_bit {
+ /* First doubleword. */
DescOwn = (1 << 31), /* Descriptor is owned by NIC */
RingEnd = (1 << 30), /* End of descriptor ring */
FirstFrag = (1 << 29), /* First segment of a packet */
LastFrag = (1 << 28), /* Final segment of a packet */
+};
+
+/* Generic case. */
+enum rtl_tx_desc_bit {
+ /* First doubleword. */
+ TD_LSO = (1 << 27), /* Large Send Offload */
+#define TD_MSS_MAX 0x07ffu /* MSS value */
- /* Tx private */
- LargeSend = (1 << 27), /* TCP Large Send Offload (TSO) */
- MSSShift = 16, /* MSS value position */
- MSSMask = 0xfff, /* MSS value + LargeSend bit: 12 bits */
- IPCS = (1 << 18), /* Calculate IP checksum */
- UDPCS = (1 << 17), /* Calculate UDP/IP checksum */
- TCPCS = (1 << 16), /* Calculate TCP/IP checksum */
- TxVlanTag = (1 << 17), /* Add VLAN tag */
+ /* Second doubleword. */
+ TxVlanTag = (1 << 17), /* Add VLAN tag */
+};
+
+/* 8169, 8168b and 810x except 8102e. */
+enum rtl_tx_desc_bit_0 {
+ /* First doubleword. */
+#define TD0_MSS_SHIFT 16 /* MSS position (11 bits) */
+ TD0_TCP_CS = (1 << 16), /* Calculate TCP/IP checksum */
+ TD0_UDP_CS = (1 << 17), /* Calculate UDP/IP checksum */
+ TD0_IP_CS = (1 << 18), /* Calculate IP checksum */
+};
+
+/* 8102e, 8168c and beyond. */
+enum rtl_tx_desc_bit_1 {
+ /* Second doubleword. */
+#define TD1_MSS_SHIFT 18 /* MSS position (11 bits) */
+ TD1_IP_CS = (1 << 29), /* Calculate IP checksum */
+ TD1_TCP_CS = (1 << 30), /* Calculate TCP/IP checksum */
+ TD1_UDP_CS = (1 << 31), /* Calculate UDP/IP checksum */
+};
+static const struct rtl_tx_desc_info {
+ struct {
+ u32 udp;
+ u32 tcp;
+ } checksum;
+ u16 mss_shift;
+ u16 opts_offset;
+} tx_desc_info [] = {
+ [RTL_TD_0] = {
+ .checksum = {
+ .udp = TD0_IP_CS | TD0_UDP_CS,
+ .tcp = TD0_IP_CS | TD0_TCP_CS
+ },
+ .mss_shift = TD0_MSS_SHIFT,
+ .opts_offset = 0
+ },
+ [RTL_TD_1] = {
+ .checksum = {
+ .udp = TD1_IP_CS | TD1_UDP_CS,
+ .tcp = TD1_IP_CS | TD1_TCP_CS
+ },
+ .mss_shift = TD1_MSS_SHIFT,
+ .opts_offset = 1
+ }
+};
+
+enum rtl_rx_desc_bit {
/* Rx private */
PID1 = (1 << 18), /* Protocol ID bit 1/2 */
PID0 = (1 << 17), /* Protocol ID bit 2/2 */
@@ -525,13 +618,13 @@ struct rtl8169_counters {
struct rtl8169_private {
void __iomem *mmio_addr; /* memory map physical address */
- struct pci_dev *pci_dev; /* Index of PCI device */
+ struct pci_dev *pci_dev;
struct net_device *dev;
struct napi_struct napi;
- spinlock_t lock; /* spin lock flag */
+ spinlock_t lock;
u32 msg_enable;
- int chipset;
- int mac_version;
+ u16 txd_version;
+ u16 mac_version;
u32 cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
u32 cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
u32 dirty_rx;
@@ -547,7 +640,6 @@ struct rtl8169_private {
u16 intr_event;
u16 napi_event;
u16 intr_mask;
- int phy_1000_ctrl_reg;
struct mdio_ops {
void (*write)(void __iomem *, int, int);
@@ -588,6 +680,8 @@ MODULE_LICENSE("GPL");
MODULE_VERSION(RTL8169_VERSION);
MODULE_FIRMWARE(FIRMWARE_8168D_1);
MODULE_FIRMWARE(FIRMWARE_8168D_2);
+MODULE_FIRMWARE(FIRMWARE_8168E_1);
+MODULE_FIRMWARE(FIRMWARE_8168E_2);
MODULE_FIRMWARE(FIRMWARE_8105E_1);
static int rtl8169_open(struct net_device *dev);
@@ -659,32 +753,49 @@ static void rtl8168_oob_notify(struct rtl8169_private *tp, u8 cmd)
#define OOB_CMD_DRIVER_START 0x05
#define OOB_CMD_DRIVER_STOP 0x06
+static u16 rtl8168_get_ocp_reg(struct rtl8169_private *tp)
+{
+ return (tp->mac_version == RTL_GIGA_MAC_VER_31) ? 0xb8 : 0x10;
+}
+
static void rtl8168_driver_start(struct rtl8169_private *tp)
{
+ u16 reg;
int i;
rtl8168_oob_notify(tp, OOB_CMD_DRIVER_START);
+ reg = rtl8168_get_ocp_reg(tp);
+
for (i = 0; i < 10; i++) {
msleep(10);
- if (ocp_read(tp, 0x0f, 0x0010) & 0x00000800)
+ if (ocp_read(tp, 0x0f, reg) & 0x00000800)
break;
}
}
static void rtl8168_driver_stop(struct rtl8169_private *tp)
{
+ u16 reg;
int i;
rtl8168_oob_notify(tp, OOB_CMD_DRIVER_STOP);
+ reg = rtl8168_get_ocp_reg(tp);
+
for (i = 0; i < 10; i++) {
msleep(10);
- if ((ocp_read(tp, 0x0f, 0x0010) & 0x00000800) == 0)
+ if ((ocp_read(tp, 0x0f, reg) & 0x00000800) == 0)
break;
}
}
+static int r8168dp_check_dash(struct rtl8169_private *tp)
+{
+ u16 reg = rtl8168_get_ocp_reg(tp);
+
+ return (ocp_read(tp, 0x0f, reg) & 0x00008000) ? 1 : 0;
+}
static void r8169_mdio_write(void __iomem *ioaddr, int reg_addr, int value)
{
@@ -983,9 +1094,8 @@ static void rtl8169_xmii_reset_enable(struct rtl8169_private *tp)
}
static void __rtl8169_check_link_status(struct net_device *dev,
- struct rtl8169_private *tp,
- void __iomem *ioaddr,
- bool pm)
+ struct rtl8169_private *tp,
+ void __iomem *ioaddr, bool pm)
{
unsigned long flags;
@@ -1102,6 +1212,11 @@ static int rtl8169_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
return 0;
}
+static const char *rtl_lookup_firmware_name(struct rtl8169_private *tp)
+{
+ return rtl_chip_infos[tp->mac_version].fw_name;
+}
+
static void rtl8169_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
@@ -1110,6 +1225,8 @@ static void rtl8169_get_drvinfo(struct net_device *dev,
strcpy(info->driver, MODULENAME);
strcpy(info->version, RTL8169_VERSION);
strcpy(info->bus_info, pci_name(tp->pci_dev));
+ strncpy(info->fw_version, IS_ERR_OR_NULL(tp->fw) ? "N/A" :
+ rtl_lookup_firmware_name(tp), sizeof(info->fw_version) - 1);
}
static int rtl8169_get_regs_len(struct net_device *dev)
@@ -1171,16 +1288,7 @@ static int rtl8169_set_speed_xmii(struct net_device *dev,
giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
/* The 8100e/8101e/8102e do Fast Ethernet only. */
- if ((tp->mac_version != RTL_GIGA_MAC_VER_07) &&
- (tp->mac_version != RTL_GIGA_MAC_VER_08) &&
- (tp->mac_version != RTL_GIGA_MAC_VER_09) &&
- (tp->mac_version != RTL_GIGA_MAC_VER_10) &&
- (tp->mac_version != RTL_GIGA_MAC_VER_13) &&
- (tp->mac_version != RTL_GIGA_MAC_VER_14) &&
- (tp->mac_version != RTL_GIGA_MAC_VER_15) &&
- (tp->mac_version != RTL_GIGA_MAC_VER_16) &&
- (tp->mac_version != RTL_GIGA_MAC_VER_29) &&
- (tp->mac_version != RTL_GIGA_MAC_VER_30)) {
+ if (tp->mii.supports_gmii) {
if (adv & ADVERTISED_1000baseT_Half)
giga_ctrl |= ADVERTISE_1000HALF;
if (adv & ADVERTISED_1000baseT_Full)
@@ -1210,12 +1318,10 @@ static int rtl8169_set_speed_xmii(struct net_device *dev,
bmcr |= BMCR_FULLDPLX;
}
- tp->phy_1000_ctrl_reg = giga_ctrl;
-
rtl_writephy(tp, MII_BMCR, bmcr);
- if ((tp->mac_version == RTL_GIGA_MAC_VER_02) ||
- (tp->mac_version == RTL_GIGA_MAC_VER_03)) {
+ if (tp->mac_version == RTL_GIGA_MAC_VER_02 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_03) {
if ((speed == SPEED_100) && (autoneg != AUTONEG_ENABLE)) {
rtl_writephy(tp, 0x17, 0x2138);
rtl_writephy(tp, 0x0e, 0x0260);
@@ -1237,10 +1343,14 @@ static int rtl8169_set_speed(struct net_device *dev,
int ret;
ret = tp->set_speed(dev, autoneg, speed, duplex, advertising);
+ if (ret < 0)
+ goto out;
- if (netif_running(dev) && (tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL))
+ if (netif_running(dev) && (autoneg == AUTONEG_ENABLE) &&
+ (advertising & ADVERTISED_1000baseT_Full)) {
mod_timer(&tp->timer, jiffies + RTL8169_PHY_TIMEOUT);
-
+ }
+out:
return ret;
}
@@ -1250,22 +1360,25 @@ static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
unsigned long flags;
int ret;
+ del_timer_sync(&tp->timer);
+
spin_lock_irqsave(&tp->lock, flags);
- ret = rtl8169_set_speed(dev,
- cmd->autoneg, cmd->speed, cmd->duplex, cmd->advertising);
+ ret = rtl8169_set_speed(dev, cmd->autoneg, ethtool_cmd_speed(cmd),
+ cmd->duplex, cmd->advertising);
spin_unlock_irqrestore(&tp->lock, flags);
return ret;
}
-static u32 rtl8169_get_rx_csum(struct net_device *dev)
+static u32 rtl8169_fix_features(struct net_device *dev, u32 features)
{
- struct rtl8169_private *tp = netdev_priv(dev);
+ if (dev->mtu > TD_MSS_MAX)
+ features &= ~NETIF_F_ALL_TSO;
- return tp->cp_cmd & RxChkSum;
+ return features;
}
-static int rtl8169_set_rx_csum(struct net_device *dev, u32 data)
+static int rtl8169_set_features(struct net_device *dev, u32 features)
{
struct rtl8169_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
@@ -1273,11 +1386,16 @@ static int rtl8169_set_rx_csum(struct net_device *dev, u32 data)
spin_lock_irqsave(&tp->lock, flags);
- if (data)
+ if (features & NETIF_F_RXCSUM)
tp->cp_cmd |= RxChkSum;
else
tp->cp_cmd &= ~RxChkSum;
+ if (dev->features & NETIF_F_HW_VLAN_RX)
+ tp->cp_cmd |= RxVlan;
+ else
+ tp->cp_cmd &= ~RxVlan;
+
RTL_W16(CPlusCmd, tp->cp_cmd);
RTL_R16(CPlusCmd);
@@ -1293,27 +1411,6 @@ static inline u32 rtl8169_tx_vlan_tag(struct rtl8169_private *tp,
TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00;
}
-#define NETIF_F_HW_VLAN_TX_RX (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX)
-
-static void rtl8169_vlan_mode(struct net_device *dev)
-{
- struct rtl8169_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
- unsigned long flags;
-
- spin_lock_irqsave(&tp->lock, flags);
- if (dev->features & NETIF_F_HW_VLAN_RX)
- tp->cp_cmd |= RxVlan;
- else
- tp->cp_cmd &= ~RxVlan;
- RTL_W16(CPlusCmd, tp->cp_cmd);
- /* PCI commit */
- RTL_R16(CPlusCmd);
- spin_unlock_irqrestore(&tp->lock, flags);
-
- dev->vlan_features = dev->features &~ NETIF_F_HW_VLAN_TX_RX;
-}
-
static void rtl8169_rx_vlan_tag(struct RxDesc *desc, struct sk_buff *skb)
{
u32 opts2 = le32_to_cpu(desc->opts2);
@@ -1339,7 +1436,7 @@ static int rtl8169_gset_tbi(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->advertising = (status & TBINwEnable) ? ADVERTISED_Autoneg : 0;
cmd->autoneg = !!(status & TBINwEnable);
- cmd->speed = SPEED_1000;
+ ethtool_cmd_speed_set(cmd, SPEED_1000);
cmd->duplex = DUPLEX_FULL; /* Always set */
return 0;
@@ -1424,11 +1521,11 @@ static void rtl8169_update_counters(struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
+ struct device *d = &tp->pci_dev->dev;
struct rtl8169_counters *counters;
dma_addr_t paddr;
u32 cmd;
int wait = 1000;
- struct device *d = &tp->pci_dev->dev;
/*
* Some chips are unable to dump tally counters when the receiver
@@ -1448,7 +1545,6 @@ static void rtl8169_update_counters(struct net_device *dev)
while (wait--) {
if ((RTL_R32(CounterAddrLow) & CounterDump) == 0) {
- /* copy updated counters */
memcpy(&tp->counters, counters, sizeof(*counters));
break;
}
@@ -1494,28 +1590,6 @@ static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data)
}
}
-static int rtl8169_set_flags(struct net_device *dev, u32 data)
-{
- struct rtl8169_private *tp = netdev_priv(dev);
- unsigned long old_feat = dev->features;
- int rc;
-
- if ((tp->mac_version == RTL_GIGA_MAC_VER_05) &&
- !(data & ETH_FLAG_RXVLAN)) {
- netif_info(tp, drv, dev, "8110SCd requires hardware Rx VLAN\n");
- return -EINVAL;
- }
-
- rc = ethtool_op_set_flags(dev, data, ETH_FLAG_TXVLAN | ETH_FLAG_RXVLAN);
- if (rc)
- return rc;
-
- if ((old_feat ^ dev->features) & NETIF_F_HW_VLAN_RX)
- rtl8169_vlan_mode(dev);
-
- return 0;
-}
-
static const struct ethtool_ops rtl8169_ethtool_ops = {
.get_drvinfo = rtl8169_get_drvinfo,
.get_regs_len = rtl8169_get_regs_len,
@@ -1524,24 +1598,18 @@ static const struct ethtool_ops rtl8169_ethtool_ops = {
.set_settings = rtl8169_set_settings,
.get_msglevel = rtl8169_get_msglevel,
.set_msglevel = rtl8169_set_msglevel,
- .get_rx_csum = rtl8169_get_rx_csum,
- .set_rx_csum = rtl8169_set_rx_csum,
- .set_tx_csum = ethtool_op_set_tx_csum,
- .set_sg = ethtool_op_set_sg,
- .set_tso = ethtool_op_set_tso,
.get_regs = rtl8169_get_regs,
.get_wol = rtl8169_get_wol,
.set_wol = rtl8169_set_wol,
.get_strings = rtl8169_get_strings,
.get_sset_count = rtl8169_get_sset_count,
.get_ethtool_stats = rtl8169_get_ethtool_stats,
- .set_flags = rtl8169_set_flags,
- .get_flags = ethtool_op_get_flags,
};
static void rtl8169_get_mac_version(struct rtl8169_private *tp,
- void __iomem *ioaddr)
+ struct net_device *dev, u8 default_version)
{
+ void __iomem *ioaddr = tp->mmio_addr;
/*
* The driver currently handles the 8168Bf and the 8168Be identically
* but they can be identified more specifically through the test below
@@ -1558,6 +1626,11 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
u32 val;
int mac_version;
} mac_info[] = {
+ /* 8168E family. */
+ { 0x7cf00000, 0x2c200000, RTL_GIGA_MAC_VER_33 },
+ { 0x7cf00000, 0x2c100000, RTL_GIGA_MAC_VER_32 },
+ { 0x7c800000, 0x2c000000, RTL_GIGA_MAC_VER_33 },
+
/* 8168D family. */
{ 0x7cf00000, 0x28300000, RTL_GIGA_MAC_VER_26 },
{ 0x7cf00000, 0x28100000, RTL_GIGA_MAC_VER_25 },
@@ -1566,6 +1639,7 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
/* 8168DP family. */
{ 0x7cf00000, 0x28800000, RTL_GIGA_MAC_VER_27 },
{ 0x7cf00000, 0x28a00000, RTL_GIGA_MAC_VER_28 },
+ { 0x7cf00000, 0x28b00000, RTL_GIGA_MAC_VER_31 },
/* 8168C family. */
{ 0x7cf00000, 0x3cb00000, RTL_GIGA_MAC_VER_24 },
@@ -1585,6 +1659,7 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
{ 0x7c800000, 0x30000000, RTL_GIGA_MAC_VER_11 },
/* 8101 family. */
+ { 0x7cf00000, 0x40b00000, RTL_GIGA_MAC_VER_30 },
{ 0x7cf00000, 0x40a00000, RTL_GIGA_MAC_VER_30 },
{ 0x7cf00000, 0x40900000, RTL_GIGA_MAC_VER_29 },
{ 0x7c800000, 0x40800000, RTL_GIGA_MAC_VER_30 },
@@ -1621,6 +1696,12 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
while ((reg & p->mask) != p->val)
p++;
tp->mac_version = p->mac_version;
+
+ if (tp->mac_version == RTL_GIGA_MAC_NONE) {
+ netif_notice(tp, probe, dev,
+ "unknown MAC, using family default\n");
+ tp->mac_version = default_version;
+ }
}
static void rtl8169_print_mac_version(struct rtl8169_private *tp)
@@ -1690,14 +1771,14 @@ rtl_phy_write_fw(struct rtl8169_private *tp, const struct firmware *fw)
case PHY_BJMPN:
if (regno > index) {
netif_err(tp, probe, tp->dev,
- "Out of range of firmware\n");
+ "Out of range of firmware\n");
return;
}
break;
case PHY_READCOUNT_EQ_SKIP:
if (index + 2 >= fw_size) {
netif_err(tp, probe, tp->dev,
- "Out of range of firmware\n");
+ "Out of range of firmware\n");
return;
}
break;
@@ -1706,7 +1787,7 @@ rtl_phy_write_fw(struct rtl8169_private *tp, const struct firmware *fw)
case PHY_SKIPN:
if (index + 1 + regno >= fw_size) {
netif_err(tp, probe, tp->dev,
- "Out of range of firmware\n");
+ "Out of range of firmware\n");
return;
}
break;
@@ -1762,10 +1843,7 @@ rtl_phy_write_fw(struct rtl8169_private *tp, const struct firmware *fw)
index++;
break;
case PHY_READCOUNT_EQ_SKIP:
- if (count == data)
- index += 2;
- else
- index += 1;
+ index += (count == data) ? 2 : 1;
break;
case PHY_COMP_EQ_SKIPN:
if (predata == data)
@@ -2176,7 +2254,7 @@ static void rtl8168d_1_hw_phy_config(struct rtl8169_private *tp)
/*
* Tx Error Issue
- * enhance line driver power
+ * Enhance line driver power
*/
{ 0x1f, 0x0002 },
{ 0x06, 0x5561 },
@@ -2288,7 +2366,7 @@ static void rtl8168d_2_hw_phy_config(struct rtl8169_private *tp)
/*
* Tx Error Issue
- * enhance line driver power
+ * Enhance line driver power
*/
{ 0x1f, 0x0002 },
{ 0x06, 0x5561 },
@@ -2444,6 +2522,79 @@ static void rtl8168d_4_hw_phy_config(struct rtl8169_private *tp)
rtl_patchphy(tp, 0x0d, 1 << 5);
}
+static void rtl8168e_hw_phy_config(struct rtl8169_private *tp)
+{
+ static const struct phy_reg phy_reg_init[] = {
+ /* Enable Delay cap */
+ { 0x1f, 0x0005 },
+ { 0x05, 0x8b80 },
+ { 0x06, 0xc896 },
+ { 0x1f, 0x0000 },
+
+ /* Channel estimation fine tune */
+ { 0x1f, 0x0001 },
+ { 0x0b, 0x6c20 },
+ { 0x07, 0x2872 },
+ { 0x1c, 0xefff },
+ { 0x1f, 0x0003 },
+ { 0x14, 0x6420 },
+ { 0x1f, 0x0000 },
+
+ /* Update PFM & 10M TX idle timer */
+ { 0x1f, 0x0007 },
+ { 0x1e, 0x002f },
+ { 0x15, 0x1919 },
+ { 0x1f, 0x0000 },
+
+ { 0x1f, 0x0007 },
+ { 0x1e, 0x00ac },
+ { 0x18, 0x0006 },
+ { 0x1f, 0x0000 }
+ };
+
+ rtl_apply_firmware(tp);
+
+ rtl_writephy_batch(tp, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+ /* DCO enable for 10M IDLE Power */
+ rtl_writephy(tp, 0x1f, 0x0007);
+ rtl_writephy(tp, 0x1e, 0x0023);
+ rtl_w1w0_phy(tp, 0x17, 0x0006, 0x0000);
+ rtl_writephy(tp, 0x1f, 0x0000);
+
+ /* For impedance matching */
+ rtl_writephy(tp, 0x1f, 0x0002);
+ rtl_w1w0_phy(tp, 0x08, 0x8000, 0x7f00);
+ rtl_writephy(tp, 0x1f, 0x0000);
+
+ /* PHY auto speed down */
+ rtl_writephy(tp, 0x1f, 0x0007);
+ rtl_writephy(tp, 0x1e, 0x002d);
+ rtl_w1w0_phy(tp, 0x18, 0x0050, 0x0000);
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_w1w0_phy(tp, 0x14, 0x8000, 0x0000);
+
+ rtl_writephy(tp, 0x1f, 0x0005);
+ rtl_writephy(tp, 0x05, 0x8b86);
+ rtl_w1w0_phy(tp, 0x06, 0x0001, 0x0000);
+ rtl_writephy(tp, 0x1f, 0x0000);
+
+ rtl_writephy(tp, 0x1f, 0x0005);
+ rtl_writephy(tp, 0x05, 0x8b85);
+ rtl_w1w0_phy(tp, 0x06, 0x0000, 0x2000);
+ rtl_writephy(tp, 0x1f, 0x0007);
+ rtl_writephy(tp, 0x1e, 0x0020);
+ rtl_w1w0_phy(tp, 0x15, 0x0000, 0x1100);
+ rtl_writephy(tp, 0x1f, 0x0006);
+ rtl_writephy(tp, 0x00, 0x5a00);
+ rtl_writephy(tp, 0x1f, 0x0000);
+ rtl_writephy(tp, 0x0d, 0x0007);
+ rtl_writephy(tp, 0x0e, 0x003c);
+ rtl_writephy(tp, 0x0d, 0x4007);
+ rtl_writephy(tp, 0x0e, 0x0000);
+ rtl_writephy(tp, 0x0d, 0x0000);
+}
+
static void rtl8102e_hw_phy_config(struct rtl8169_private *tp)
{
static const struct phy_reg phy_reg_init[] = {
@@ -2558,6 +2709,13 @@ static void rtl_hw_phy_config(struct net_device *dev)
case RTL_GIGA_MAC_VER_30:
rtl8105e_hw_phy_config(tp);
break;
+ case RTL_GIGA_MAC_VER_31:
+ /* None. */
+ break;
+ case RTL_GIGA_MAC_VER_32:
+ case RTL_GIGA_MAC_VER_33:
+ rtl8168e_hw_phy_config(tp);
+ break;
default:
break;
@@ -2574,9 +2732,6 @@ static void rtl8169_phy_timer(unsigned long __opaque)
assert(tp->mac_version > RTL_GIGA_MAC_VER_01);
- if (!(tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL))
- return;
-
spin_lock_irq(&tp->lock);
if (tp->phy_reset_pending(tp)) {
@@ -2601,28 +2756,6 @@ out_unlock:
spin_unlock_irq(&tp->lock);
}
-static inline void rtl8169_delete_timer(struct net_device *dev)
-{
- struct rtl8169_private *tp = netdev_priv(dev);
- struct timer_list *timer = &tp->timer;
-
- if (tp->mac_version <= RTL_GIGA_MAC_VER_01)
- return;
-
- del_timer_sync(timer);
-}
-
-static inline void rtl8169_request_timer(struct net_device *dev)
-{
- struct rtl8169_private *tp = netdev_priv(dev);
- struct timer_list *timer = &tp->timer;
-
- if (tp->mac_version <= RTL_GIGA_MAC_VER_01)
- return;
-
- mod_timer(timer, jiffies + RTL8169_PHY_TIMEOUT);
-}
-
#ifdef CONFIG_NET_POLL_CONTROLLER
/*
* Polling 'interrupt' - used by things like netconsole to send skbs
@@ -2690,11 +2823,11 @@ static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
rtl8169_phy_reset(dev, tp);
rtl8169_set_speed(dev, AUTONEG_ENABLE, SPEED_1000, DUPLEX_FULL,
- ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
- ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |
- (tp->mii.supports_gmii ?
- ADVERTISED_1000baseT_Half |
- ADVERTISED_1000baseT_Full : 0));
+ ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |
+ (tp->mii.supports_gmii ?
+ ADVERTISED_1000baseT_Half |
+ ADVERTISED_1000baseT_Full : 0));
if (RTL_R8(PHYstatus) & TBI_Enable)
netif_info(tp, link, dev, "TBI auto-negotiating\n");
@@ -2747,7 +2880,8 @@ static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return netif_running(dev) ? tp->do_ioctl(tp, data, cmd) : -ENODEV;
}
-static int rtl_xmii_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd)
+static int rtl_xmii_ioctl(struct rtl8169_private *tp,
+ struct mii_ioctl_data *data, int cmd)
{
switch (cmd) {
case SIOCGMIIPHY:
@@ -2847,6 +2981,8 @@ static const struct net_device_ops rtl8169_netdev_ops = {
.ndo_tx_timeout = rtl8169_tx_timeout,
.ndo_validate_addr = eth_validate_addr,
.ndo_change_mtu = rtl8169_change_mtu,
+ .ndo_fix_features = rtl8169_fix_features,
+ .ndo_set_features = rtl8169_set_features,
.ndo_set_mac_address = rtl_set_mac_address,
.ndo_do_ioctl = rtl8169_ioctl,
.ndo_set_multicast_list = rtl_set_rx_mode,
@@ -2866,6 +3002,7 @@ static void __devinit rtl_init_mdio_ops(struct rtl8169_private *tp)
ops->read = r8168dp_1_mdio_read;
break;
case RTL_GIGA_MAC_VER_28:
+ case RTL_GIGA_MAC_VER_31:
ops->write = r8168dp_2_mdio_write;
ops->read = r8168dp_2_mdio_read;
break;
@@ -2907,33 +3044,82 @@ static void r810x_pll_power_up(struct rtl8169_private *tp)
static void r8168_phy_power_up(struct rtl8169_private *tp)
{
rtl_writephy(tp, 0x1f, 0x0000);
- rtl_writephy(tp, 0x0e, 0x0000);
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_11:
+ case RTL_GIGA_MAC_VER_12:
+ case RTL_GIGA_MAC_VER_17:
+ case RTL_GIGA_MAC_VER_18:
+ case RTL_GIGA_MAC_VER_19:
+ case RTL_GIGA_MAC_VER_20:
+ case RTL_GIGA_MAC_VER_21:
+ case RTL_GIGA_MAC_VER_22:
+ case RTL_GIGA_MAC_VER_23:
+ case RTL_GIGA_MAC_VER_24:
+ case RTL_GIGA_MAC_VER_25:
+ case RTL_GIGA_MAC_VER_26:
+ case RTL_GIGA_MAC_VER_27:
+ case RTL_GIGA_MAC_VER_28:
+ case RTL_GIGA_MAC_VER_31:
+ rtl_writephy(tp, 0x0e, 0x0000);
+ break;
+ default:
+ break;
+ }
rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE);
}
static void r8168_phy_power_down(struct rtl8169_private *tp)
{
rtl_writephy(tp, 0x1f, 0x0000);
- rtl_writephy(tp, 0x0e, 0x0200);
- rtl_writephy(tp, MII_BMCR, BMCR_PDOWN);
+ switch (tp->mac_version) {
+ case RTL_GIGA_MAC_VER_32:
+ case RTL_GIGA_MAC_VER_33:
+ rtl_writephy(tp, MII_BMCR, BMCR_ANENABLE | BMCR_PDOWN);
+ break;
+
+ case RTL_GIGA_MAC_VER_11:
+ case RTL_GIGA_MAC_VER_12:
+ case RTL_GIGA_MAC_VER_17:
+ case RTL_GIGA_MAC_VER_18:
+ case RTL_GIGA_MAC_VER_19:
+ case RTL_GIGA_MAC_VER_20:
+ case RTL_GIGA_MAC_VER_21:
+ case RTL_GIGA_MAC_VER_22:
+ case RTL_GIGA_MAC_VER_23:
+ case RTL_GIGA_MAC_VER_24:
+ case RTL_GIGA_MAC_VER_25:
+ case RTL_GIGA_MAC_VER_26:
+ case RTL_GIGA_MAC_VER_27:
+ case RTL_GIGA_MAC_VER_28:
+ case RTL_GIGA_MAC_VER_31:
+ rtl_writephy(tp, 0x0e, 0x0200);
+ default:
+ rtl_writephy(tp, MII_BMCR, BMCR_PDOWN);
+ break;
+ }
}
static void r8168_pll_power_down(struct rtl8169_private *tp)
{
void __iomem *ioaddr = tp->mmio_addr;
- if (((tp->mac_version == RTL_GIGA_MAC_VER_27) ||
- (tp->mac_version == RTL_GIGA_MAC_VER_28)) &&
- (ocp_read(tp, 0x0f, 0x0010) & 0x00008000)) {
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_27 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_28 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_31) &&
+ r8168dp_check_dash(tp)) {
return;
}
- if (((tp->mac_version == RTL_GIGA_MAC_VER_23) ||
- (tp->mac_version == RTL_GIGA_MAC_VER_24)) &&
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_23 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_24) &&
(RTL_R16(CPlusCmd) & ASF)) {
return;
}
+ if (tp->mac_version == RTL_GIGA_MAC_VER_32 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_33)
+ rtl_ephy_write(ioaddr, 0x19, 0xff64);
+
if (__rtl8169_get_wol(tp) & WAKE_ANY) {
rtl_writephy(tp, 0x1f, 0x0000);
rtl_writephy(tp, MII_BMCR, 0x0000);
@@ -2950,6 +3136,9 @@ static void r8168_pll_power_down(struct rtl8169_private *tp)
case RTL_GIGA_MAC_VER_26:
case RTL_GIGA_MAC_VER_27:
case RTL_GIGA_MAC_VER_28:
+ case RTL_GIGA_MAC_VER_31:
+ case RTL_GIGA_MAC_VER_32:
+ case RTL_GIGA_MAC_VER_33:
RTL_W8(PMCH, RTL_R8(PMCH) & ~0x80);
break;
}
@@ -2959,9 +3148,10 @@ static void r8168_pll_power_up(struct rtl8169_private *tp)
{
void __iomem *ioaddr = tp->mmio_addr;
- if (((tp->mac_version == RTL_GIGA_MAC_VER_27) ||
- (tp->mac_version == RTL_GIGA_MAC_VER_28)) &&
- (ocp_read(tp, 0x0f, 0x0010) & 0x00008000)) {
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_27 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_28 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_31) &&
+ r8168dp_check_dash(tp)) {
return;
}
@@ -2970,6 +3160,9 @@ static void r8168_pll_power_up(struct rtl8169_private *tp)
case RTL_GIGA_MAC_VER_26:
case RTL_GIGA_MAC_VER_27:
case RTL_GIGA_MAC_VER_28:
+ case RTL_GIGA_MAC_VER_31:
+ case RTL_GIGA_MAC_VER_32:
+ case RTL_GIGA_MAC_VER_33:
RTL_W8(PMCH, RTL_R8(PMCH) | 0x80);
break;
}
@@ -3024,6 +3217,9 @@ static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp)
case RTL_GIGA_MAC_VER_26:
case RTL_GIGA_MAC_VER_27:
case RTL_GIGA_MAC_VER_28:
+ case RTL_GIGA_MAC_VER_31:
+ case RTL_GIGA_MAC_VER_32:
+ case RTL_GIGA_MAC_VER_33:
ops->down = r8168_pll_power_down;
ops->up = r8168_pll_power_up;
break;
@@ -3035,6 +3231,22 @@ static void __devinit rtl_init_pll_power_ops(struct rtl8169_private *tp)
}
}
+static void rtl_hw_reset(struct rtl8169_private *tp)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+ int i;
+
+ /* Soft reset the chip. */
+ RTL_W8(ChipCmd, CmdReset);
+
+ /* Check that the chip has finished the reset. */
+ for (i = 0; i < 100; i++) {
+ if ((RTL_R8(ChipCmd) & CmdReset) == 0)
+ break;
+ msleep_interruptible(1);
+ }
+}
+
static int __devinit
rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -3044,7 +3256,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
struct mii_if_info *mii;
struct net_device *dev;
void __iomem *ioaddr;
- unsigned int i;
+ int chipset, i;
int rc;
if (netif_msg_drv(&debug)) {
@@ -3134,6 +3346,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
rc = -EIO;
goto err_out_free_res_3;
}
+ tp->mmio_addr = ioaddr;
tp->pcie_cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
if (!tp->pcie_cap)
@@ -3141,22 +3354,14 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
RTL_W16(IntrMask, 0x0000);
- /* Soft reset the chip. */
- RTL_W8(ChipCmd, CmdReset);
-
- /* Check that the chip has finished the reset. */
- for (i = 0; i < 100; i++) {
- if ((RTL_R8(ChipCmd) & CmdReset) == 0)
- break;
- msleep_interruptible(1);
- }
+ rtl_hw_reset(tp);
RTL_W16(IntrStatus, 0xffff);
pci_set_master(pdev);
/* Identify chip attached to board */
- rtl8169_get_mac_version(tp, ioaddr);
+ rtl8169_get_mac_version(tp, dev, cfg->default_ver);
/*
* Pretend we are using VLANs; This bypasses a nasty bug where
@@ -3168,25 +3373,10 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
rtl_init_mdio_ops(tp);
rtl_init_pll_power_ops(tp);
- /* Use appropriate default if unknown */
- if (tp->mac_version == RTL_GIGA_MAC_NONE) {
- netif_notice(tp, probe, dev,
- "unknown MAC, using family default\n");
- tp->mac_version = cfg->default_ver;
- }
-
rtl8169_print_mac_version(tp);
- for (i = 0; i < ARRAY_SIZE(rtl_chip_info); i++) {
- if (tp->mac_version == rtl_chip_info[i].mac_version)
- break;
- }
- if (i == ARRAY_SIZE(rtl_chip_info)) {
- dev_err(&pdev->dev,
- "driver bug, MAC version not found in rtl_chip_info\n");
- goto err_out_msi_4;
- }
- tp->chipset = i;
+ chipset = tp->mac_version;
+ tp->txd_version = rtl_chip_infos[chipset].txd_version;
RTL_W8(Cfg9346, Cfg9346_Unlock);
RTL_W8(Config1, RTL_R8(Config1) | PMEnable);
@@ -3206,8 +3396,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
tp->phy_reset_pending = rtl8169_tbi_reset_pending;
tp->link_ok = rtl8169_tbi_link_ok;
tp->do_ioctl = rtl_tbi_ioctl;
-
- tp->phy_1000_ctrl_reg = ADVERTISE_1000FULL; /* Implied by TBI */
} else {
tp->set_speed = rtl8169_set_speed_xmii;
tp->get_settings = rtl8169_gset_xmii;
@@ -3219,8 +3407,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
spin_lock_init(&tp->lock);
- tp->mmio_addr = ioaddr;
-
/* Get MAC address */
for (i = 0; i < MAC_ADDR_LEN; i++)
dev->dev_addr[i] = RTL_R8(MAC0 + i);
@@ -3233,7 +3419,19 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
netif_napi_add(dev, &tp->napi, rtl8169_poll, R8169_NAPI_WEIGHT);
- dev->features |= NETIF_F_HW_VLAN_TX_RX | NETIF_F_GRO;
+ /* don't enable SG, IP_CSUM and TSO by default - it might not work
+ * properly for all devices */
+ dev->features |= NETIF_F_RXCSUM |
+ NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+
+ dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
+ NETIF_F_RXCSUM | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
+ NETIF_F_HIGHDMA;
+
+ if (tp->mac_version == RTL_GIGA_MAC_VER_05)
+ /* 8110SCd requires hardware Rx VLAN - disallow toggling */
+ dev->hw_features &= ~NETIF_F_HW_VLAN_RX;
tp->intr_mask = 0xffff;
tp->hw_start = cfg->hw_start;
@@ -3253,12 +3451,12 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_drvdata(pdev, dev);
netif_info(tp, probe, dev, "%s at 0x%lx, %pM, XID %08x IRQ %d\n",
- rtl_chip_info[tp->chipset].name,
- dev->base_addr, dev->dev_addr,
+ rtl_chip_infos[chipset].name, dev->base_addr, dev->dev_addr,
(u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), dev->irq);
- if ((tp->mac_version == RTL_GIGA_MAC_VER_27) ||
- (tp->mac_version == RTL_GIGA_MAC_VER_28)) {
+ if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_28 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_31) {
rtl8168_driver_start(tp);
}
@@ -3290,8 +3488,9 @@ 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);
- if ((tp->mac_version == RTL_GIGA_MAC_VER_27) ||
- (tp->mac_version == RTL_GIGA_MAC_VER_28)) {
+ if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_28 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_31) {
rtl8168_driver_stop(tp);
}
@@ -3314,33 +3513,23 @@ static void __devexit rtl8169_remove_one(struct pci_dev *pdev)
static void rtl_request_firmware(struct rtl8169_private *tp)
{
- int i;
-
/* Return early if the firmware is already loaded / cached. */
- if (!IS_ERR(tp->fw))
- goto out;
-
- for (i = 0; i < ARRAY_SIZE(rtl_firmware_infos); i++) {
- const struct rtl_firmware_info *info = rtl_firmware_infos + i;
+ if (IS_ERR(tp->fw)) {
+ const char *name;
- if (info->mac_version == tp->mac_version) {
- const char *name = info->fw_name;
+ name = rtl_lookup_firmware_name(tp);
+ if (name) {
int rc;
rc = request_firmware(&tp->fw, name, &tp->pci_dev->dev);
- if (rc < 0) {
- netif_warn(tp, ifup, tp->dev, "unable to load "
- "firmware patch %s (%d)\n", name, rc);
- goto out_disable_request_firmware;
- }
- goto out;
+ if (rc >= 0)
+ return;
+
+ netif_warn(tp, ifup, tp->dev, "unable to load "
+ "firmware patch %s (%d)\n", name, rc);
}
+ tp->fw = NULL;
}
-
-out_disable_request_firmware:
- tp->fw = NULL;
-out:
- return;
}
static int rtl8169_open(struct net_device *dev)
@@ -3386,14 +3575,12 @@ static int rtl8169_open(struct net_device *dev)
rtl8169_init_phy(dev, tp);
- rtl8169_vlan_mode(dev);
+ rtl8169_set_features(dev, dev->features);
rtl_pll_power_up(tp);
rtl_hw_start(dev);
- rtl8169_request_timer(dev);
-
tp->saved_wolopts = 0;
pm_runtime_put_noidle(&pdev->dev);
@@ -3425,7 +3612,8 @@ static void rtl8169_hw_reset(struct rtl8169_private *tp)
rtl8169_irq_mask_and_ack(ioaddr);
if (tp->mac_version == RTL_GIGA_MAC_VER_27 ||
- tp->mac_version == RTL_GIGA_MAC_VER_28) {
+ tp->mac_version == RTL_GIGA_MAC_VER_28 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_31) {
while (RTL_R8(TxPoll) & NPQ)
udelay(20);
@@ -3443,7 +3631,7 @@ static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp)
void __iomem *ioaddr = tp->mmio_addr;
u32 cfg = rtl8169_rx_config;
- cfg |= (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
+ cfg |= (RTL_R32(RxConfig) & RTL_RX_CONFIG_MASK);
RTL_W32(RxConfig, cfg);
/* Set DMA burst size and Interframe Gap Time */
@@ -3454,25 +3642,14 @@ static void rtl_set_rx_tx_config_registers(struct rtl8169_private *tp)
static void rtl_hw_start(struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
- void __iomem *ioaddr = tp->mmio_addr;
- unsigned int i;
- /* Soft reset the chip. */
- RTL_W8(ChipCmd, CmdReset);
-
- /* Check that the chip has finished the reset. */
- for (i = 0; i < 100; i++) {
- if ((RTL_R8(ChipCmd) & CmdReset) == 0)
- break;
- msleep_interruptible(1);
- }
+ rtl_hw_reset(tp);
tp->hw_start(dev);
netif_start_queue(dev);
}
-
static void rtl_set_rx_tx_desc_registers(struct rtl8169_private *tp,
void __iomem *ioaddr)
{
@@ -3538,26 +3715,26 @@ static void rtl_hw_start_8169(struct net_device *dev)
}
RTL_W8(Cfg9346, Cfg9346_Unlock);
- if ((tp->mac_version == RTL_GIGA_MAC_VER_01) ||
- (tp->mac_version == RTL_GIGA_MAC_VER_02) ||
- (tp->mac_version == RTL_GIGA_MAC_VER_03) ||
- (tp->mac_version == RTL_GIGA_MAC_VER_04))
+ if (tp->mac_version == RTL_GIGA_MAC_VER_01 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_02 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_03 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_04)
RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
RTL_W8(EarlyTxThres, NoEarlyTx);
rtl_set_rx_max_size(ioaddr, rx_buf_sz);
- if ((tp->mac_version == RTL_GIGA_MAC_VER_01) ||
- (tp->mac_version == RTL_GIGA_MAC_VER_02) ||
- (tp->mac_version == RTL_GIGA_MAC_VER_03) ||
- (tp->mac_version == RTL_GIGA_MAC_VER_04))
+ if (tp->mac_version == RTL_GIGA_MAC_VER_01 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_02 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_03 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_04)
rtl_set_rx_tx_config_registers(tp);
tp->cp_cmd |= rtl_rw_cpluscmd(ioaddr) | PCIMulRW;
- if ((tp->mac_version == RTL_GIGA_MAC_VER_02) ||
- (tp->mac_version == RTL_GIGA_MAC_VER_03)) {
+ if (tp->mac_version == RTL_GIGA_MAC_VER_02 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_03) {
dprintk("Set MAC Reg C+CR Offset 0xE0. "
"Bit-3 and bit-14 MUST be 1\n");
tp->cp_cmd |= (1 << 14);
@@ -3575,10 +3752,10 @@ static void rtl_hw_start_8169(struct net_device *dev)
rtl_set_rx_tx_desc_registers(tp, ioaddr);
- if ((tp->mac_version != RTL_GIGA_MAC_VER_01) &&
- (tp->mac_version != RTL_GIGA_MAC_VER_02) &&
- (tp->mac_version != RTL_GIGA_MAC_VER_03) &&
- (tp->mac_version != RTL_GIGA_MAC_VER_04)) {
+ if (tp->mac_version != RTL_GIGA_MAC_VER_01 &&
+ tp->mac_version != RTL_GIGA_MAC_VER_02 &&
+ tp->mac_version != RTL_GIGA_MAC_VER_03 &&
+ tp->mac_version != RTL_GIGA_MAC_VER_04) {
RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
rtl_set_rx_tx_config_registers(tp);
}
@@ -3822,6 +3999,17 @@ static void rtl_hw_start_8168d(void __iomem *ioaddr, struct pci_dev *pdev)
RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) & ~R8168_CPCMD_QUIRK_MASK);
}
+static void rtl_hw_start_8168dp(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+ rtl_csi_access_enable_1(ioaddr);
+
+ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+ RTL_W8(MaxTxPacketSize, TxPacketMax);
+
+ rtl_disable_clock_request(pdev);
+}
+
static void rtl_hw_start_8168d_4(void __iomem *ioaddr, struct pci_dev *pdev)
{
static const struct ephy_info e_info_8168d_4[] = {
@@ -3848,6 +4036,41 @@ static void rtl_hw_start_8168d_4(void __iomem *ioaddr, struct pci_dev *pdev)
rtl_enable_clock_request(pdev);
}
+static void rtl_hw_start_8168e(void __iomem *ioaddr, struct pci_dev *pdev)
+{
+ static const struct ephy_info e_info_8168e[] = {
+ { 0x00, 0x0200, 0x0100 },
+ { 0x00, 0x0000, 0x0004 },
+ { 0x06, 0x0002, 0x0001 },
+ { 0x06, 0x0000, 0x0030 },
+ { 0x07, 0x0000, 0x2000 },
+ { 0x00, 0x0000, 0x0020 },
+ { 0x03, 0x5800, 0x2000 },
+ { 0x03, 0x0000, 0x0001 },
+ { 0x01, 0x0800, 0x1000 },
+ { 0x07, 0x0000, 0x4000 },
+ { 0x1e, 0x0000, 0x2000 },
+ { 0x19, 0xffff, 0xfe6c },
+ { 0x0a, 0x0000, 0x0040 }
+ };
+
+ rtl_csi_access_enable_2(ioaddr);
+
+ rtl_ephy_init(ioaddr, e_info_8168e, ARRAY_SIZE(e_info_8168e));
+
+ rtl_tx_performance_tweak(pdev, 0x5 << MAX_READ_REQUEST_SHIFT);
+
+ RTL_W8(MaxTxPacketSize, TxPacketMax);
+
+ rtl_disable_clock_request(pdev);
+
+ /* Reset tx FIFO pointer */
+ RTL_W32(MISC, RTL_R32(MISC) | TXPLA_RST);
+ RTL_W32(MISC, RTL_R32(MISC) & ~TXPLA_RST);
+
+ RTL_W8(Config5, RTL_R8(Config5) & ~Spi_en);
+}
+
static void rtl_hw_start_8168(struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
@@ -3885,55 +4108,64 @@ static void rtl_hw_start_8168(struct net_device *dev)
switch (tp->mac_version) {
case RTL_GIGA_MAC_VER_11:
rtl_hw_start_8168bb(ioaddr, pdev);
- break;
+ break;
case RTL_GIGA_MAC_VER_12:
case RTL_GIGA_MAC_VER_17:
rtl_hw_start_8168bef(ioaddr, pdev);
- break;
+ break;
case RTL_GIGA_MAC_VER_18:
rtl_hw_start_8168cp_1(ioaddr, pdev);
- break;
+ break;
case RTL_GIGA_MAC_VER_19:
rtl_hw_start_8168c_1(ioaddr, pdev);
- break;
+ break;
case RTL_GIGA_MAC_VER_20:
rtl_hw_start_8168c_2(ioaddr, pdev);
- break;
+ break;
case RTL_GIGA_MAC_VER_21:
rtl_hw_start_8168c_3(ioaddr, pdev);
- break;
+ break;
case RTL_GIGA_MAC_VER_22:
rtl_hw_start_8168c_4(ioaddr, pdev);
- break;
+ break;
case RTL_GIGA_MAC_VER_23:
rtl_hw_start_8168cp_2(ioaddr, pdev);
- break;
+ break;
case RTL_GIGA_MAC_VER_24:
rtl_hw_start_8168cp_3(ioaddr, pdev);
- break;
+ break;
case RTL_GIGA_MAC_VER_25:
case RTL_GIGA_MAC_VER_26:
case RTL_GIGA_MAC_VER_27:
rtl_hw_start_8168d(ioaddr, pdev);
- break;
+ break;
case RTL_GIGA_MAC_VER_28:
rtl_hw_start_8168d_4(ioaddr, pdev);
- break;
+ break;
+
+ case RTL_GIGA_MAC_VER_31:
+ rtl_hw_start_8168dp(ioaddr, pdev);
+ break;
+
+ case RTL_GIGA_MAC_VER_32:
+ case RTL_GIGA_MAC_VER_33:
+ rtl_hw_start_8168e(ioaddr, pdev);
+ break;
default:
printk(KERN_ERR PFX "%s: unknown chipset (mac_version = %d).\n",
dev->name, tp->mac_version);
- break;
+ break;
}
RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
@@ -4017,10 +4249,10 @@ static void rtl_hw_start_8105e_1(void __iomem *ioaddr, struct pci_dev *pdev)
{ 0x0a, 0, 0x0020 }
};
- /* Force LAN exit from ASPM if Rx/Tx are not idel */
+ /* Force LAN exit from ASPM if Rx/Tx are not idle */
RTL_W32(FuncEvent, RTL_R32(FuncEvent) | 0x002800);
- /* disable Early Tally Counter */
+ /* Disable Early Tally Counter */
RTL_W32(FuncEvent, RTL_R32(FuncEvent) & ~0x010000);
RTL_W8(MCU, RTL_R8(MCU) | EN_NDP | EN_OOB_RESET);
@@ -4041,8 +4273,8 @@ static void rtl_hw_start_8101(struct net_device *dev)
void __iomem *ioaddr = tp->mmio_addr;
struct pci_dev *pdev = tp->pci_dev;
- if ((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
- (tp->mac_version == RTL_GIGA_MAC_VER_16)) {
+ if (tp->mac_version == RTL_GIGA_MAC_VER_13 ||
+ tp->mac_version == RTL_GIGA_MAC_VER_16) {
int cap = tp->pcie_cap;
if (cap) {
@@ -4105,6 +4337,8 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu)
return -EINVAL;
dev->mtu = new_mtu;
+ netdev_update_features(dev);
+
return 0;
}
@@ -4342,6 +4576,7 @@ static void rtl8169_reset_task(struct work_struct *work)
struct rtl8169_private *tp =
container_of(work, struct rtl8169_private, task.work);
struct net_device *dev = tp->dev;
+ int i;
rtnl_lock();
@@ -4350,19 +4585,15 @@ static void rtl8169_reset_task(struct work_struct *work)
rtl8169_wait_for_quiescence(dev);
- rtl8169_rx_interrupt(dev, tp, tp->mmio_addr, ~(u32)0);
+ for (i = 0; i < NUM_RX_DESC; i++)
+ rtl8169_mark_to_asic(tp->RxDescArray + i, rx_buf_sz);
+
rtl8169_tx_clear(tp);
- if (tp->dirty_rx == tp->cur_rx) {
- rtl8169_init_ring_indexes(tp);
- rtl_hw_start(dev);
- netif_wake_queue(dev);
- rtl8169_check_link_status(dev, tp, tp->mmio_addr);
- } else {
- if (net_ratelimit())
- netif_emerg(tp, intr, dev, "Rx buffers shortage\n");
- rtl8169_schedule_work(dev, rtl8169_reset_task);
- }
+ rtl8169_init_ring_indexes(tp);
+ rtl_hw_start(dev);
+ netif_wake_queue(dev);
+ rtl8169_check_link_status(dev, tp, tp->mmio_addr);
out_unlock:
rtnl_unlock();
@@ -4379,7 +4610,7 @@ static void rtl8169_tx_timeout(struct net_device *dev)
}
static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb,
- u32 opts1)
+ u32 *opts)
{
struct skb_shared_info *info = skb_shinfo(skb);
unsigned int cur_frag, entry;
@@ -4406,10 +4637,12 @@ static int rtl8169_xmit_frags(struct rtl8169_private *tp, struct sk_buff *skb,
goto err_out;
}
- /* anti gcc 2.95.3 bugware (sic) */
- status = opts1 | len | (RingEnd * !((entry + 1) % NUM_TX_DESC));
+ /* Anti gcc 2.95.3 bugware (sic) */
+ status = opts[0] | len |
+ (RingEnd * !((entry + 1) % NUM_TX_DESC));
txd->opts1 = cpu_to_le32(status);
+ txd->opts2 = cpu_to_le32(opts[1]);
txd->addr = cpu_to_le64(mapping);
tp->tx_skb[entry].len = len;
@@ -4427,24 +4660,26 @@ err_out:
return -EIO;
}
-static inline u32 rtl8169_tso_csum(struct sk_buff *skb, struct net_device *dev)
+static inline void rtl8169_tso_csum(struct rtl8169_private *tp,
+ struct sk_buff *skb, u32 *opts)
{
- if (dev->features & NETIF_F_TSO) {
- u32 mss = skb_shinfo(skb)->gso_size;
+ const struct rtl_tx_desc_info *info = tx_desc_info + tp->txd_version;
+ u32 mss = skb_shinfo(skb)->gso_size;
+ int offset = info->opts_offset;
- if (mss)
- return LargeSend | ((mss & MSSMask) << MSSShift);
- }
- if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ if (mss) {
+ opts[0] |= TD_LSO;
+ opts[offset] |= min(mss, TD_MSS_MAX) << info->mss_shift;
+ } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
const struct iphdr *ip = ip_hdr(skb);
if (ip->protocol == IPPROTO_TCP)
- return IPCS | TCPCS;
+ opts[offset] |= info->checksum.tcp;
else if (ip->protocol == IPPROTO_UDP)
- return IPCS | UDPCS;
- WARN_ON(1); /* we need a WARN() */
+ opts[offset] |= info->checksum.udp;
+ else
+ WARN_ON_ONCE(1);
}
- return 0;
}
static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
@@ -4457,7 +4692,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
struct device *d = &tp->pci_dev->dev;
dma_addr_t mapping;
u32 status, len;
- u32 opts1;
+ u32 opts[2];
int frags;
if (unlikely(TX_BUFFS_AVAIL(tp) < skb_shinfo(skb)->nr_frags)) {
@@ -4478,31 +4713,35 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
tp->tx_skb[entry].len = len;
txd->addr = cpu_to_le64(mapping);
- txd->opts2 = cpu_to_le32(rtl8169_tx_vlan_tag(tp, skb));
- opts1 = DescOwn | rtl8169_tso_csum(skb, dev);
+ opts[1] = cpu_to_le32(rtl8169_tx_vlan_tag(tp, skb));
+ opts[0] = DescOwn;
- frags = rtl8169_xmit_frags(tp, skb, opts1);
+ rtl8169_tso_csum(tp, skb, opts);
+
+ frags = rtl8169_xmit_frags(tp, skb, opts);
if (frags < 0)
goto err_dma_1;
else if (frags)
- opts1 |= FirstFrag;
+ opts[0] |= FirstFrag;
else {
- opts1 |= FirstFrag | LastFrag;
+ opts[0] |= FirstFrag | LastFrag;
tp->tx_skb[entry].skb = skb;
}
+ txd->opts2 = cpu_to_le32(opts[1]);
+
wmb();
- /* anti gcc 2.95.3 bugware (sic) */
- status = opts1 | len | (RingEnd * !((entry + 1) % NUM_TX_DESC));
+ /* Anti gcc 2.95.3 bugware (sic) */
+ status = opts[0] | len | (RingEnd * !((entry + 1) % NUM_TX_DESC));
txd->opts1 = cpu_to_le32(status);
tp->cur_tx += frags + 1;
wmb();
- RTL_W8(TxPoll, NPQ); /* set polling bit */
+ RTL_W8(TxPoll, NPQ);
if (TX_BUFFS_AVAIL(tp) < MAX_SKB_FRAGS) {
netif_stop_queue(dev);
@@ -4659,20 +4898,12 @@ static struct sk_buff *rtl8169_try_rx_copy(void *data,
return skb;
}
-/*
- * Warning : rtl8169_rx_interrupt() might be called :
- * 1) from NAPI (softirq) context
- * (polling = 1 : we should call netif_receive_skb())
- * 2) from process context (rtl8169_reset_task())
- * (polling = 0 : we must call netif_rx() instead)
- */
static int rtl8169_rx_interrupt(struct net_device *dev,
struct rtl8169_private *tp,
void __iomem *ioaddr, u32 budget)
{
unsigned int cur_rx, rx_left;
unsigned int count;
- int polling = (budget != ~(u32)0) ? 1 : 0;
cur_rx = tp->cur_rx;
rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx;
@@ -4732,10 +4963,7 @@ static int rtl8169_rx_interrupt(struct net_device *dev,
rtl8169_rx_vlan_tag(desc, skb);
- if (likely(polling))
- napi_gro_receive(&tp->napi, skb);
- else
- netif_rx(skb);
+ napi_gro_receive(&tp->napi, skb);
dev->stats.rx_bytes += pkt_size;
dev->stats.rx_packets++;
@@ -4798,6 +5026,7 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
case RTL_GIGA_MAC_VER_24:
case RTL_GIGA_MAC_VER_27:
case RTL_GIGA_MAC_VER_28:
+ case RTL_GIGA_MAC_VER_31:
/* Experimental science. Pktgen proof. */
case RTL_GIGA_MAC_VER_12:
case RTL_GIGA_MAC_VER_25:
@@ -4890,7 +5119,7 @@ static void rtl8169_down(struct net_device *dev)
struct rtl8169_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
- rtl8169_delete_timer(dev);
+ del_timer_sync(&tp->timer);
netif_stop_queue(dev);
@@ -4927,7 +5156,7 @@ static int rtl8169_close(struct net_device *dev)
pm_runtime_get_sync(&pdev->dev);
- /* update counters before going down */
+ /* Update counters before going down */
rtl8169_update_counters(dev);
rtl8169_down(dev);
@@ -4982,7 +5211,7 @@ static void rtl_set_rx_mode(struct net_device *dev)
spin_lock_irqsave(&tp->lock, flags);
tmp = rtl8169_rx_config | rx_mode |
- (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
+ (RTL_R32(RxConfig) & RTL_RX_CONFIG_MASK);
if (tp->mac_version > RTL_GIGA_MAC_VER_06) {
u32 data = mc_filter[0];
@@ -5120,15 +5349,15 @@ static int rtl8169_runtime_idle(struct device *device)
}
static const struct dev_pm_ops rtl8169_pm_ops = {
- .suspend = rtl8169_suspend,
- .resume = rtl8169_resume,
- .freeze = rtl8169_suspend,
- .thaw = rtl8169_resume,
- .poweroff = rtl8169_suspend,
- .restore = rtl8169_resume,
- .runtime_suspend = rtl8169_runtime_suspend,
- .runtime_resume = rtl8169_runtime_resume,
- .runtime_idle = rtl8169_runtime_idle,
+ .suspend = rtl8169_suspend,
+ .resume = rtl8169_resume,
+ .freeze = rtl8169_suspend,
+ .thaw = rtl8169_resume,
+ .poweroff = rtl8169_suspend,
+ .restore = rtl8169_resume,
+ .runtime_suspend = rtl8169_runtime_suspend,
+ .runtime_resume = rtl8169_runtime_resume,
+ .runtime_idle = rtl8169_runtime_idle,
};
#define RTL8169_PM_OPS (&rtl8169_pm_ops)
@@ -5147,7 +5376,7 @@ static void rtl_shutdown(struct pci_dev *pdev)
rtl8169_net_suspend(dev);
- /* restore original MAC address */
+ /* Restore original MAC address */
rtl_rar_set(tp, dev->perm_addr);
spin_lock_irq(&tp->lock);
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c
index 26afbaae23f0..77c5092a6a40 100644
--- a/drivers/net/rionet.c
+++ b/drivers/net/rionet.c
@@ -162,8 +162,8 @@ static int rionet_queue_tx_msg(struct sk_buff *skb, struct net_device *ndev,
rnet->tx_slot &= (RIONET_TX_RING_SIZE - 1);
if (netif_msg_tx_queued(rnet))
- printk(KERN_INFO "%s: queued skb %8.8x len %8.8x\n", DRV_NAME,
- (u32) skb, skb->len);
+ printk(KERN_INFO "%s: queued skb len %8.8x\n", DRV_NAME,
+ skb->len);
return 0;
}
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 337bdcd5abc9..df0d2c8ecc09 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -78,6 +78,7 @@
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/prefetch.h>
#include <net/tcp.h>
#include <asm/system.h>
@@ -2244,13 +2245,12 @@ static int verify_xena_quiescence(struct s2io_nic *sp)
static void fix_mac_address(struct s2io_nic *sp)
{
struct XENA_dev_config __iomem *bar0 = sp->bar0;
- u64 val64;
int i = 0;
while (fix_mac[i] != END_SIGN) {
writeq(fix_mac[i++], &bar0->gpio_control);
udelay(10);
- val64 = readq(&bar0->gpio_control);
+ (void) readq(&bar0->gpio_control);
}
}
@@ -2727,7 +2727,6 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
int j;
struct sk_buff *skb;
struct RxD_t *rxdp;
- struct buffAdd *ba;
struct RxD1 *rxdp1;
struct RxD3 *rxdp3;
struct mac_info *mac_control = &sp->mac_control;
@@ -2751,7 +2750,6 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
memset(rxdp, 0, sizeof(struct RxD1));
} else if (sp->rxd_mode == RXD_MODE_3B) {
rxdp3 = (struct RxD3 *)rxdp;
- ba = &mac_control->rings[ring_no].ba[blk][j];
pci_unmap_single(sp->pdev,
(dma_addr_t)rxdp3->Buffer0_ptr,
BUF0_LEN,
@@ -5383,7 +5381,7 @@ static int s2io_ethtool_sset(struct net_device *dev,
{
struct s2io_nic *sp = netdev_priv(dev);
if ((info->autoneg == AUTONEG_ENABLE) ||
- (info->speed != SPEED_10000) ||
+ (ethtool_cmd_speed(info) != SPEED_10000) ||
(info->duplex != DUPLEX_FULL))
return -EINVAL;
else {
@@ -5417,10 +5415,10 @@ static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
info->transceiver = XCVR_EXTERNAL;
if (netif_carrier_ok(sp->dev)) {
- info->speed = 10000;
+ ethtool_cmd_speed_set(info, SPEED_10000);
info->duplex = DUPLEX_FULL;
} else {
- info->speed = -1;
+ ethtool_cmd_speed_set(info, -1);
info->duplex = -1;
}
@@ -5484,83 +5482,79 @@ static void s2io_ethtool_gregs(struct net_device *dev,
}
}
-/**
- * s2io_phy_id - timer function that alternates adapter LED.
- * @data : address of the private member of the device structure, which
- * is a pointer to the s2io_nic structure, provided as an u32.
- * Description: This is actually the timer function that alternates the
- * adapter LED bit of the adapter control bit to set/reset every time on
- * invocation. The timer is set for 1/2 a second, hence tha NIC blinks
- * once every second.
+/*
+ * s2io_set_led - control NIC led
*/
-static void s2io_phy_id(unsigned long data)
+static void s2io_set_led(struct s2io_nic *sp, bool on)
{
- struct s2io_nic *sp = (struct s2io_nic *)data;
struct XENA_dev_config __iomem *bar0 = sp->bar0;
- u64 val64 = 0;
- u16 subid;
+ u16 subid = sp->pdev->subsystem_device;
+ u64 val64;
- subid = sp->pdev->subsystem_device;
if ((sp->device_type == XFRAME_II_DEVICE) ||
((subid & 0xFF) >= 0x07)) {
val64 = readq(&bar0->gpio_control);
- val64 ^= GPIO_CTRL_GPIO_0;
+ if (on)
+ val64 |= GPIO_CTRL_GPIO_0;
+ else
+ val64 &= ~GPIO_CTRL_GPIO_0;
+
writeq(val64, &bar0->gpio_control);
} else {
val64 = readq(&bar0->adapter_control);
- val64 ^= ADAPTER_LED_ON;
+ if (on)
+ val64 |= ADAPTER_LED_ON;
+ else
+ val64 &= ~ADAPTER_LED_ON;
+
writeq(val64, &bar0->adapter_control);
}
- mod_timer(&sp->id_timer, jiffies + HZ / 2);
}
/**
- * s2io_ethtool_idnic - To physically identify the nic on the system.
- * @sp : private member of the device structure, which is a pointer to the
- * s2io_nic structure.
- * @id : pointer to the structure with identification parameters given by
- * ethtool.
+ * s2io_ethtool_set_led - To physically identify the nic on the system.
+ * @dev : network device
+ * @state: led setting
+ *
* Description: Used to physically identify the NIC on the system.
* The Link LED will blink for a time specified by the user for
* identification.
* NOTE: The Link has to be Up to be able to blink the LED. Hence
* identification is possible only if it's link is up.
- * Return value:
- * int , returns 0 on success
*/
-static int s2io_ethtool_idnic(struct net_device *dev, u32 data)
+static int s2io_ethtool_set_led(struct net_device *dev,
+ enum ethtool_phys_id_state state)
{
- u64 val64 = 0, last_gpio_ctrl_val;
struct s2io_nic *sp = netdev_priv(dev);
struct XENA_dev_config __iomem *bar0 = sp->bar0;
- u16 subid;
+ u16 subid = sp->pdev->subsystem_device;
- subid = sp->pdev->subsystem_device;
- last_gpio_ctrl_val = readq(&bar0->gpio_control);
if ((sp->device_type == XFRAME_I_DEVICE) && ((subid & 0xFF) < 0x07)) {
- val64 = readq(&bar0->adapter_control);
+ u64 val64 = readq(&bar0->adapter_control);
if (!(val64 & ADAPTER_CNTL_EN)) {
pr_err("Adapter Link down, cannot blink LED\n");
- return -EFAULT;
+ return -EAGAIN;
}
}
- if (sp->id_timer.function == NULL) {
- init_timer(&sp->id_timer);
- sp->id_timer.function = s2io_phy_id;
- sp->id_timer.data = (unsigned long)sp;
- }
- mod_timer(&sp->id_timer, jiffies);
- if (data)
- msleep_interruptible(data * HZ);
- else
- msleep_interruptible(MAX_FLICKER_TIME);
- del_timer_sync(&sp->id_timer);
- if (CARDS_WITH_FAULTY_LINK_INDICATORS(sp->device_type, subid)) {
- writeq(last_gpio_ctrl_val, &bar0->gpio_control);
- last_gpio_ctrl_val = readq(&bar0->gpio_control);
+ switch (state) {
+ case ETHTOOL_ID_ACTIVE:
+ sp->adapt_ctrl_org = readq(&bar0->gpio_control);
+ return 1; /* cycle on/off once per second */
+
+ case ETHTOOL_ID_ON:
+ s2io_set_led(sp, true);
+ break;
+
+ case ETHTOOL_ID_OFF:
+ s2io_set_led(sp, false);
+ break;
+
+ case ETHTOOL_ID_INACTIVE:
+ if (CARDS_WITH_FAULTY_LINK_INDICATORS(sp->device_type, subid))
+ writeq(sp->adapt_ctrl_org, &bar0->gpio_control);
}
return 0;
@@ -6625,25 +6619,6 @@ static int s2io_ethtool_get_regs_len(struct net_device *dev)
}
-static u32 s2io_ethtool_get_rx_csum(struct net_device *dev)
-{
- struct s2io_nic *sp = netdev_priv(dev);
-
- return sp->rx_csum;
-}
-
-static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
-{
- struct s2io_nic *sp = netdev_priv(dev);
-
- if (data)
- sp->rx_csum = 1;
- else
- sp->rx_csum = 0;
-
- return 0;
-}
-
static int s2io_get_eeprom_len(struct net_device *dev)
{
return XENA_EEPROM_SPACE;
@@ -6695,61 +6670,27 @@ static void s2io_ethtool_get_strings(struct net_device *dev,
}
}
-static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
-{
- if (data)
- dev->features |= NETIF_F_IP_CSUM;
- else
- dev->features &= ~NETIF_F_IP_CSUM;
-
- return 0;
-}
-
-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)
- dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
- else
- dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
-
- return 0;
-}
-
-static int s2io_ethtool_set_flags(struct net_device *dev, u32 data)
+static int s2io_set_features(struct net_device *dev, u32 features)
{
struct s2io_nic *sp = netdev_priv(dev);
- int rc = 0;
- int changed = 0;
-
- if (ethtool_invalid_flags(dev, data, ETH_FLAG_LRO))
- return -EINVAL;
-
- if (data & ETH_FLAG_LRO) {
- if (!(dev->features & NETIF_F_LRO)) {
- dev->features |= NETIF_F_LRO;
- changed = 1;
- }
- } else if (dev->features & NETIF_F_LRO) {
- dev->features &= ~NETIF_F_LRO;
- changed = 1;
- }
+ u32 changed = (features ^ dev->features) & NETIF_F_LRO;
if (changed && netif_running(dev)) {
+ int rc;
+
s2io_stop_all_tx_queue(sp);
s2io_card_down(sp);
+ dev->features = features;
rc = s2io_card_up(sp);
if (rc)
s2io_reset(sp);
else
s2io_start_all_tx_queue(sp);
+
+ return rc ? rc : 1;
}
- return rc;
+ return 0;
}
static const struct ethtool_ops netdev_ethtool_ops = {
@@ -6765,18 +6706,9 @@ static const struct ethtool_ops netdev_ethtool_ops = {
.get_ringparam = s2io_ethtool_gringparam,
.get_pauseparam = s2io_ethtool_getpause_data,
.set_pauseparam = s2io_ethtool_setpause_data,
- .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,
- .set_ufo = ethtool_op_set_ufo,
.self_test = s2io_ethtool_test,
.get_strings = s2io_ethtool_get_strings,
- .phys_id = s2io_ethtool_idnic,
+ .set_phys_id = s2io_ethtool_set_led,
.get_ethtool_stats = s2io_get_ethtool_stats,
.get_sset_count = s2io_get_sset_count,
};
@@ -7231,7 +7163,7 @@ static void do_s2io_card_down(struct s2io_nic *sp, int do_io)
/* As per the HW requirement we need to replenish the
* receive buffer to avoid the ring bump. Since there is
* no intention of processing the Rx frame at this pointwe are
- * just settting the ownership bit of rxd in Each Rx
+ * just setting the ownership bit of rxd in Each Rx
* ring to HW and set the appropriate buffer size
* based on the ring mode
*/
@@ -7545,7 +7477,7 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) &&
((!ring_data->lro) ||
(ring_data->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) &&
- (sp->rx_csum)) {
+ (dev->features & NETIF_F_RXCSUM)) {
l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1);
l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1);
if ((l3_csum == L3_CKSUM_OK) && (l4_csum == L4_CKSUM_OK)) {
@@ -7806,6 +7738,7 @@ static const struct net_device_ops s2io_netdev_ops = {
.ndo_do_ioctl = s2io_ioctl,
.ndo_set_mac_address = s2io_set_mac_addr,
.ndo_change_mtu = s2io_change_mtu,
+ .ndo_set_features = s2io_set_features,
.ndo_vlan_rx_register = s2io_vlan_rx_register,
.ndo_vlan_rx_kill_vid = s2io_vlan_rx_kill_vid,
.ndo_tx_timeout = s2io_tx_watchdog,
@@ -8047,17 +7980,18 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
/* Driver entry points */
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;
- dev->features |= NETIF_F_LRO;
- dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+ dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM |
+ NETIF_F_TSO | NETIF_F_TSO6 |
+ NETIF_F_RXCSUM | NETIF_F_LRO;
+ dev->features |= dev->hw_features |
+ NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ if (sp->device_type & XFRAME_II_DEVICE) {
+ dev->hw_features |= NETIF_F_UFO;
+ if (ufo)
+ dev->features |= NETIF_F_UFO;
+ }
if (sp->high_dma_flag == true)
dev->features |= NETIF_F_HIGHDMA;
- dev->features |= NETIF_F_TSO;
- dev->features |= NETIF_F_TSO6;
- if ((sp->device_type & XFRAME_II_DEVICE) && (ufo)) {
- dev->features |= NETIF_F_UFO;
- dev->features |= NETIF_F_HW_CSUM;
- }
dev->watchdog_timeo = WATCH_DOG_TIMEOUT;
INIT_WORK(&sp->rst_timer_task, s2io_restart_nic);
INIT_WORK(&sp->set_link_task, s2io_set_link);
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 2d144979f6f8..800b3a44e653 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -893,9 +893,6 @@ struct s2io_nic {
u16 all_multi_pos;
u16 promisc_flg;
- /* Id timer, used to blink NIC to physically identify NIC. */
- struct timer_list id_timer;
-
/* Restart timer, used to restart NIC if the device is stuck and
* a schedule task that will set the correct Link state once the
* NIC's PHY has stabilized after a state change.
@@ -1005,18 +1002,16 @@ static inline void writeq(u64 val, void __iomem *addr)
#define LF 2
static inline void SPECIAL_REG_WRITE(u64 val, void __iomem *addr, int order)
{
- u32 ret;
-
if (order == LF) {
writel((u32) (val), addr);
- ret = readl(addr);
+ (void) readl(addr);
writel((u32) (val >> 32), (addr + 4));
- ret = readl(addr + 4);
+ (void) readl(addr + 4);
} else {
writel((u32) (val >> 32), (addr + 4));
- ret = readl(addr + 4);
+ (void) readl(addr + 4);
writel((u32) (val), addr);
- ret = readl(addr);
+ (void) readl(addr);
}
}
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
index d96d2f7a3f14..68d50429ddf3 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -43,6 +43,7 @@
#include <linux/mii.h>
#include <linux/phy.h>
#include <linux/platform_device.h>
+#include <linux/prefetch.h>
#include <asm/cache.h>
#include <asm/io.h>
diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c
index 76290a8c3c14..fa74314ef789 100644
--- a/drivers/net/sc92031.c
+++ b/drivers/net/sc92031.c
@@ -1173,7 +1173,8 @@ static int sc92031_ethtool_get_settings(struct net_device *dev,
if (phy_ctrl & PhyCtrlAne)
cmd->advertising |= ADVERTISED_Autoneg;
- cmd->speed = (output_status & 0x2) ? SPEED_100 : SPEED_10;
+ ethtool_cmd_speed_set(cmd,
+ (output_status & 0x2) ? SPEED_100 : SPEED_10);
cmd->duplex = (output_status & 0x4) ? DUPLEX_FULL : DUPLEX_HALF;
cmd->port = PORT_MII;
cmd->phy_address = phy_address;
@@ -1188,10 +1189,11 @@ static int sc92031_ethtool_set_settings(struct net_device *dev,
{
struct sc92031_priv *priv = netdev_priv(dev);
void __iomem *port_base = priv->port_base;
+ u32 speed = ethtool_cmd_speed(cmd);
u32 phy_ctrl;
u32 old_phy_ctrl;
- if (!(cmd->speed == SPEED_10 || cmd->speed == SPEED_100))
+ if (!(speed == SPEED_10 || speed == SPEED_100))
return -EINVAL;
if (!(cmd->duplex == DUPLEX_HALF || cmd->duplex == DUPLEX_FULL))
return -EINVAL;
@@ -1229,7 +1231,7 @@ static int sc92031_ethtool_set_settings(struct net_device *dev,
// FIXME: Whole branch guessed
phy_ctrl = 0;
- if (cmd->speed == SPEED_10)
+ if (speed == SPEED_10)
phy_ctrl |= PhyCtrlSpd10;
else /* cmd->speed == SPEED_100 */
phy_ctrl |= PhyCtrlSpd100;
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index a3c2aab53de8..c914729f9554 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -798,11 +798,6 @@ void efx_link_status_changed(struct efx_nic *efx)
if (!netif_running(efx->net_dev))
return;
- if (efx->port_inhibited) {
- netif_carrier_off(efx->net_dev);
- return;
- }
-
if (link_state->up != netif_carrier_ok(efx->net_dev)) {
efx->n_link_state_changes++;
@@ -838,7 +833,7 @@ void efx_link_set_advertising(struct efx_nic *efx, u32 advertising)
}
}
-void efx_link_set_wanted_fc(struct efx_nic *efx, enum efx_fc_type wanted_fc)
+void efx_link_set_wanted_fc(struct efx_nic *efx, u8 wanted_fc)
{
efx->wanted_fc = wanted_fc;
if (efx->link_advertising) {
@@ -1319,8 +1314,20 @@ static void efx_remove_interrupts(struct efx_nic *efx)
static void efx_set_channels(struct efx_nic *efx)
{
+ struct efx_channel *channel;
+ struct efx_tx_queue *tx_queue;
+
efx->tx_channel_offset =
separate_tx_channels ? efx->n_channels - efx->n_tx_channels : 0;
+
+ /* We need to adjust the TX queue numbers if we have separate
+ * RX-only and TX-only channels.
+ */
+ efx_for_each_channel(channel, efx) {
+ efx_for_each_channel_tx_queue(tx_queue, channel)
+ tx_queue->queue -= (efx->tx_channel_offset *
+ EFX_TXQ_TYPES);
+ }
}
static int efx_probe_nic(struct efx_nic *efx)
@@ -1438,7 +1445,7 @@ static void efx_start_all(struct efx_nic *efx)
* restart the transmit interface early so the watchdog timer stops */
efx_start_port(efx);
- if (efx_dev_registered(efx) && !efx->port_inhibited)
+ if (efx_dev_registered(efx) && netif_device_present(efx->net_dev))
netif_tx_wake_all_queues(efx->net_dev);
efx_for_each_channel(channel, efx)
@@ -1876,6 +1883,17 @@ static void efx_set_multicast_list(struct net_device *net_dev)
/* Otherwise efx_start_port() will do this */
}
+static int efx_set_features(struct net_device *net_dev, u32 data)
+{
+ struct efx_nic *efx = netdev_priv(net_dev);
+
+ /* If disabling RX n-tuple filtering, clear existing filters */
+ if (net_dev->features & ~data & NETIF_F_NTUPLE)
+ efx_filter_clear_rx(efx, EFX_FILTER_PRI_MANUAL);
+
+ return 0;
+}
+
static const struct net_device_ops efx_netdev_ops = {
.ndo_open = efx_net_open,
.ndo_stop = efx_net_stop,
@@ -1887,6 +1905,7 @@ static const struct net_device_ops efx_netdev_ops = {
.ndo_change_mtu = efx_change_mtu,
.ndo_set_mac_address = efx_set_mac_address,
.ndo_set_multicast_list = efx_set_multicast_list,
+ .ndo_set_features = efx_set_features,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = efx_netpoll,
#endif
@@ -2090,6 +2109,7 @@ int efx_reset(struct efx_nic *efx, enum reset_type method)
netif_info(efx, drv, efx->net_dev, "resetting (%s)\n",
RESET_TYPE(method));
+ netif_device_detach(efx->net_dev);
efx_reset_down(efx, method);
rc = efx->type->reset(efx, method);
@@ -2123,6 +2143,7 @@ out:
efx->state = STATE_DISABLED;
} else {
netif_dbg(efx, drv, efx->net_dev, "reset complete\n");
+ netif_device_attach(efx->net_dev);
}
return rc;
}
@@ -2235,7 +2256,7 @@ static bool efx_port_dummy_op_poll(struct efx_nic *efx)
return false;
}
-static struct efx_phy_operations efx_dummy_phy_operations = {
+static const struct efx_phy_operations efx_dummy_phy_operations = {
.init = efx_port_dummy_op_int,
.reconfigure = efx_port_dummy_op_int,
.poll = efx_port_dummy_op_poll,
@@ -2251,7 +2272,7 @@ static struct efx_phy_operations efx_dummy_phy_operations = {
/* This zeroes out and then fills in the invariants in a struct
* efx_nic (including all sub-structures).
*/
-static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
+static int efx_init_struct(struct efx_nic *efx, const struct efx_nic_type *type,
struct pci_dev *pci_dev, struct net_device *net_dev)
{
int i;
@@ -2271,7 +2292,6 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
strlcpy(efx->name, pci_name(pci_dev), sizeof(efx->name));
efx->net_dev = net_dev;
- efx->rx_checksum_enabled = true;
spin_lock_init(&efx->stats_lock);
mutex_init(&efx->mac_lock);
efx->mac_op = type->default_mac_ops;
@@ -2442,7 +2462,7 @@ static int efx_pci_probe_main(struct efx_nic *efx)
static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
const struct pci_device_id *entry)
{
- struct efx_nic_type *type = (struct efx_nic_type *) entry->driver_data;
+ const struct efx_nic_type *type = (const struct efx_nic_type *) entry->driver_data;
struct net_device *net_dev;
struct efx_nic *efx;
int i, rc;
@@ -2454,12 +2474,15 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
return -ENOMEM;
net_dev->features |= (type->offload_features | NETIF_F_SG |
NETIF_F_HIGHDMA | NETIF_F_TSO |
- NETIF_F_GRO);
+ NETIF_F_RXCSUM);
if (type->offload_features & NETIF_F_V6_CSUM)
net_dev->features |= NETIF_F_TSO6;
/* Mask for features that also apply to VLAN devices */
net_dev->vlan_features |= (NETIF_F_ALL_CSUM | NETIF_F_SG |
- NETIF_F_HIGHDMA | NETIF_F_TSO);
+ NETIF_F_HIGHDMA | NETIF_F_ALL_TSO |
+ NETIF_F_RXCSUM);
+ /* All offloads can be toggled */
+ net_dev->hw_features = net_dev->features & ~NETIF_F_HIGHDMA;
efx = netdev_priv(net_dev);
pci_set_drvdata(pci_dev, efx);
SET_NETDEV_DEV(net_dev, &pci_dev->dev);
diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h
index 3d83a1f74fef..b0d1209ea18d 100644
--- a/drivers/net/sfc/efx.h
+++ b/drivers/net/sfc/efx.h
@@ -142,6 +142,6 @@ static inline void efx_schedule_channel(struct efx_channel *channel)
extern void efx_link_status_changed(struct efx_nic *efx);
extern void efx_link_set_advertising(struct efx_nic *efx, u32);
-extern void efx_link_set_wanted_fc(struct efx_nic *efx, enum efx_fc_type);
+extern void efx_link_set_wanted_fc(struct efx_nic *efx, u8);
#endif /* EFX_EFX_H */
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
index 807178ef65ad..d229027dc363 100644
--- a/drivers/net/sfc/ethtool.c
+++ b/drivers/net/sfc/ethtool.c
@@ -178,19 +178,27 @@ static struct efx_ethtool_stat efx_ethtool_stats[] = {
*/
/* Identify device by flashing LEDs */
-static int efx_ethtool_phys_id(struct net_device *net_dev, u32 count)
+static int efx_ethtool_phys_id(struct net_device *net_dev,
+ enum ethtool_phys_id_state state)
{
struct efx_nic *efx = netdev_priv(net_dev);
+ enum efx_led_mode mode = EFX_LED_DEFAULT;
- do {
- efx->type->set_id_led(efx, EFX_LED_ON);
- schedule_timeout_interruptible(HZ / 2);
-
- efx->type->set_id_led(efx, EFX_LED_OFF);
- schedule_timeout_interruptible(HZ / 2);
- } while (!signal_pending(current) && --count != 0);
+ switch (state) {
+ case ETHTOOL_ID_ON:
+ mode = EFX_LED_ON;
+ break;
+ case ETHTOOL_ID_OFF:
+ mode = EFX_LED_OFF;
+ break;
+ case ETHTOOL_ID_INACTIVE:
+ mode = EFX_LED_DEFAULT;
+ break;
+ case ETHTOOL_ID_ACTIVE:
+ return 1; /* cycle on/off once per second */
+ }
- efx->type->set_id_led(efx, EFX_LED_DEFAULT);
+ efx->type->set_id_led(efx, mode);
return 0;
}
@@ -211,7 +219,7 @@ static int efx_ethtool_get_settings(struct net_device *net_dev,
ecmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
if (LOOPBACK_INTERNAL(efx)) {
- ecmd->speed = link_state->speed;
+ ethtool_cmd_speed_set(ecmd, link_state->speed);
ecmd->duplex = link_state->fd ? DUPLEX_FULL : DUPLEX_HALF;
}
@@ -226,7 +234,8 @@ static int efx_ethtool_set_settings(struct net_device *net_dev,
int rc;
/* GMAC does not support 1000Mbps HD */
- if (ecmd->speed == SPEED_1000 && ecmd->duplex != DUPLEX_FULL) {
+ if ((ethtool_cmd_speed(ecmd) == SPEED_1000) &&
+ (ecmd->duplex != DUPLEX_FULL)) {
netif_dbg(efx, drv, efx->net_dev,
"rejecting unsupported 1000Mbps HD setting\n");
return -EINVAL;
@@ -518,72 +527,6 @@ static void efx_ethtool_get_stats(struct net_device *net_dev,
}
}
-static int efx_ethtool_set_tso(struct net_device *net_dev, u32 enable)
-{
- struct efx_nic *efx __attribute__ ((unused)) = netdev_priv(net_dev);
- u32 features;
-
- features = NETIF_F_TSO;
- if (efx->type->offload_features & NETIF_F_V6_CSUM)
- features |= NETIF_F_TSO6;
-
- if (enable)
- net_dev->features |= features;
- else
- net_dev->features &= ~features;
-
- return 0;
-}
-
-static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable)
-{
- struct efx_nic *efx = netdev_priv(net_dev);
- u32 features = efx->type->offload_features & NETIF_F_ALL_CSUM;
-
- if (enable)
- net_dev->features |= features;
- else
- net_dev->features &= ~features;
-
- return 0;
-}
-
-static int efx_ethtool_set_rx_csum(struct net_device *net_dev, u32 enable)
-{
- struct efx_nic *efx = netdev_priv(net_dev);
-
- /* No way to stop the hardware doing the checks; we just
- * ignore the result.
- */
- efx->rx_checksum_enabled = !!enable;
-
- return 0;
-}
-
-static u32 efx_ethtool_get_rx_csum(struct net_device *net_dev)
-{
- struct efx_nic *efx = netdev_priv(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 | ETH_FLAG_NTUPLE));
- int rc;
-
- rc = ethtool_op_set_flags(net_dev, data, supported);
- if (rc)
- return rc;
-
- if (!(data & ETH_FLAG_NTUPLE))
- efx_filter_clear_rx(efx, EFX_FILTER_PRI_MANUAL);
-
- return 0;
-}
-
static void efx_ethtool_self_test(struct net_device *net_dev,
struct ethtool_test *test, u64 *data)
{
@@ -755,7 +698,7 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
struct ethtool_pauseparam *pause)
{
struct efx_nic *efx = netdev_priv(net_dev);
- enum efx_fc_type wanted_fc, old_fc;
+ u8 wanted_fc, old_fc;
u32 old_adv;
bool reset;
int rc = 0;
@@ -1012,8 +955,9 @@ static int efx_ethtool_set_rx_ntuple(struct net_device *net_dev,
if (ntuple->fs.action == ETHTOOL_RXNTUPLE_ACTION_CLEAR)
return efx_filter_remove_filter(efx, &filter);
- else
- return efx_filter_insert_filter(efx, &filter, true);
+
+ rc = efx_filter_insert_filter(efx, &filter, true);
+ return rc < 0 ? rc : 0;
}
static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev,
@@ -1070,22 +1014,10 @@ const struct ethtool_ops efx_ethtool_ops = {
.set_ringparam = efx_ethtool_set_ringparam,
.get_pauseparam = efx_ethtool_get_pauseparam,
.set_pauseparam = efx_ethtool_set_pauseparam,
- .get_rx_csum = efx_ethtool_get_rx_csum,
- .set_rx_csum = efx_ethtool_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
- /* Need to enable/disable IPv6 too */
- .set_tx_csum = efx_ethtool_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
- .set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
- /* Need to enable/disable TSO-IPv6 too */
- .set_tso = efx_ethtool_set_tso,
- .get_flags = ethtool_op_get_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,
- .phys_id = efx_ethtool_phys_id,
+ .set_phys_id = efx_ethtool_phys_id,
.get_ethtool_stats = efx_ethtool_get_stats,
.get_wol = efx_ethtool_get_wol,
.set_wol = efx_ethtool_set_wol,
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index d96b23769bd1..60176e873d62 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -1703,7 +1703,7 @@ static int falcon_set_wol(struct efx_nic *efx, u32 type)
**************************************************************************
*/
-struct efx_nic_type falcon_a1_nic_type = {
+const struct efx_nic_type falcon_a1_nic_type = {
.probe = falcon_probe_nic,
.remove = falcon_remove_nic,
.init = falcon_init_nic,
@@ -1744,7 +1744,7 @@ struct efx_nic_type falcon_a1_nic_type = {
.reset_world_flags = ETH_RESET_IRQ,
};
-struct efx_nic_type falcon_b0_nic_type = {
+const struct efx_nic_type falcon_b0_nic_type = {
.probe = falcon_probe_nic,
.remove = falcon_remove_nic,
.init = falcon_init_nic,
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c
index 2c9ee5db3bf7..9516452c079c 100644
--- a/drivers/net/sfc/falcon_xmac.c
+++ b/drivers/net/sfc/falcon_xmac.c
@@ -362,7 +362,7 @@ void falcon_poll_xmac(struct efx_nic *efx)
falcon_ack_status_intr(efx);
}
-struct efx_mac_operations falcon_xmac_operations = {
+const struct efx_mac_operations falcon_xmac_operations = {
.reconfigure = falcon_reconfigure_xmac,
.update_stats = falcon_update_stats_xmac,
.check_fault = falcon_xmac_check_fault,
diff --git a/drivers/net/sfc/mac.h b/drivers/net/sfc/mac.h
index 6886cdf87c12..d6a255d0856b 100644
--- a/drivers/net/sfc/mac.h
+++ b/drivers/net/sfc/mac.h
@@ -13,8 +13,8 @@
#include "net_driver.h"
-extern struct efx_mac_operations falcon_xmac_operations;
-extern struct efx_mac_operations efx_mcdi_mac_operations;
+extern const struct efx_mac_operations falcon_xmac_operations;
+extern const struct efx_mac_operations efx_mcdi_mac_operations;
extern int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr,
u32 dma_len, int enable, int clear);
diff --git a/drivers/net/sfc/mcdi_mac.c b/drivers/net/sfc/mcdi_mac.c
index 33f7294edb47..50c20777a564 100644
--- a/drivers/net/sfc/mcdi_mac.c
+++ b/drivers/net/sfc/mcdi_mac.c
@@ -138,7 +138,7 @@ static bool efx_mcdi_mac_check_fault(struct efx_nic *efx)
}
-struct efx_mac_operations efx_mcdi_mac_operations = {
+const struct efx_mac_operations efx_mcdi_mac_operations = {
.reconfigure = efx_mcdi_mac_reconfigure,
.update_stats = efx_port_dummy_op_void,
.check_fault = efx_mcdi_mac_check_fault,
diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c
index 7e3c65b0c99f..6c63ab0710af 100644
--- a/drivers/net/sfc/mcdi_phy.c
+++ b/drivers/net/sfc/mcdi_phy.c
@@ -513,7 +513,7 @@ static void efx_mcdi_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *e
ecmd->supported =
mcdi_to_ethtool_cap(phy_cfg->media, phy_cfg->supported_cap);
ecmd->advertising = efx->link_advertising;
- ecmd->speed = efx->link_state.speed;
+ ethtool_cmd_speed_set(ecmd, efx->link_state.speed);
ecmd->duplex = efx->link_state.fd;
ecmd->port = mcdi_to_ethtool_media(phy_cfg->media);
ecmd->phy_address = phy_cfg->port;
@@ -545,7 +545,7 @@ static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ec
caps = (ethtool_to_mcdi_cap(ecmd->advertising) |
1 << MC_CMD_PHY_CAP_AN_LBN);
} else if (ecmd->duplex) {
- switch (ecmd->speed) {
+ switch (ethtool_cmd_speed(ecmd)) {
case 10: caps = 1 << MC_CMD_PHY_CAP_10FDX_LBN; break;
case 100: caps = 1 << MC_CMD_PHY_CAP_100FDX_LBN; break;
case 1000: caps = 1 << MC_CMD_PHY_CAP_1000FDX_LBN; break;
@@ -553,7 +553,7 @@ static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ec
default: return -EINVAL;
}
} else {
- switch (ecmd->speed) {
+ switch (ethtool_cmd_speed(ecmd)) {
case 10: caps = 1 << MC_CMD_PHY_CAP_10HDX_LBN; break;
case 100: caps = 1 << MC_CMD_PHY_CAP_100HDX_LBN; break;
case 1000: caps = 1 << MC_CMD_PHY_CAP_1000HDX_LBN; break;
@@ -739,7 +739,7 @@ static const char *efx_mcdi_phy_test_name(struct efx_nic *efx,
return NULL;
}
-struct efx_phy_operations efx_mcdi_phy_ops = {
+const struct efx_phy_operations efx_mcdi_phy_ops = {
.probe = efx_mcdi_phy_probe,
.init = efx_port_dummy_op_int,
.reconfigure = efx_mcdi_phy_reconfigure,
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c
index 19e68c26d103..7ab385c8136d 100644
--- a/drivers/net/sfc/mdio_10g.c
+++ b/drivers/net/sfc/mdio_10g.c
@@ -232,12 +232,12 @@ void efx_mdio_set_mmds_lpower(struct efx_nic *efx,
*/
int efx_mdio_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
{
- struct ethtool_cmd prev;
+ struct ethtool_cmd prev = { .cmd = ETHTOOL_GSET };
efx->phy_op->get_settings(efx, &prev);
if (ecmd->advertising == prev.advertising &&
- ecmd->speed == prev.speed &&
+ ethtool_cmd_speed(ecmd) == ethtool_cmd_speed(&prev) &&
ecmd->duplex == prev.duplex &&
ecmd->port == prev.port &&
ecmd->autoneg == prev.autoneg)
@@ -284,7 +284,7 @@ void efx_mdio_an_reconfigure(struct efx_nic *efx)
efx_mdio_write(efx, MDIO_MMD_AN, MDIO_CTRL1, reg);
}
-enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx)
+u8 efx_mdio_get_pause(struct efx_nic *efx)
{
BUILD_BUG_ON(EFX_FC_AUTO & (EFX_FC_RX | EFX_FC_TX));
diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h
index df0703940c83..a97dbbd2de99 100644
--- a/drivers/net/sfc/mdio_10g.h
+++ b/drivers/net/sfc/mdio_10g.h
@@ -92,7 +92,7 @@ extern void efx_mdio_an_reconfigure(struct efx_nic *efx);
/* Get pause parameters from AN if available (otherwise return
* requested pause parameters)
*/
-enum efx_fc_type efx_mdio_get_pause(struct efx_nic *efx);
+u8 efx_mdio_get_pause(struct efx_nic *efx);
/* Wait for specified MMDs to exit reset within a timeout */
extern int efx_mdio_wait_reset_mmds(struct efx_nic *efx,
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 191a311da2dc..e8d5f03a89fe 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -449,11 +449,9 @@ enum nic_state {
struct efx_nic;
/* Pseudo bit-mask flow control field */
-enum efx_fc_type {
- EFX_FC_RX = FLOW_CTRL_RX,
- EFX_FC_TX = FLOW_CTRL_TX,
- EFX_FC_AUTO = 4,
-};
+#define EFX_FC_RX FLOW_CTRL_RX
+#define EFX_FC_TX FLOW_CTRL_TX
+#define EFX_FC_AUTO 4
/**
* struct efx_link_state - Current state of the link
@@ -465,7 +463,7 @@ enum efx_fc_type {
struct efx_link_state {
bool up;
bool fd;
- enum efx_fc_type fc;
+ u8 fc;
unsigned int speed;
};
@@ -670,16 +668,14 @@ struct efx_filter_state;
* @mtd_list: List of MTDs attached to the NIC
* @nic_data: Hardware dependent state
* @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode,
- * @port_inhibited, efx_monitor() and efx_reconfigure_port()
+ * efx_monitor() and efx_reconfigure_port()
* @port_enabled: Port enabled indicator.
* Serialises efx_stop_all(), efx_start_all(), efx_monitor() and
* efx_mac_work() with kernel interfaces. Safe to read under any
* one of the rtnl_lock, mac_lock, or netif_tx_lock, but all three must
* be held to modify it.
- * @port_inhibited: If set, the netif_carrier is always off. Hold the mac_lock
* @port_initialized: Port initialized?
* @net_dev: Operating system network device. Consider holding the rtnl lock
- * @rx_checksum_enabled: RX checksumming enabled
* @stats_buffer: DMA buffer for statistics
* @mac_op: MAC interface
* @phy_type: PHY type
@@ -765,18 +761,16 @@ struct efx_nic {
struct mutex mac_lock;
struct work_struct mac_work;
bool port_enabled;
- bool port_inhibited;
bool port_initialized;
struct net_device *net_dev;
- bool rx_checksum_enabled;
struct efx_buffer stats_buffer;
- struct efx_mac_operations *mac_op;
+ const struct efx_mac_operations *mac_op;
unsigned int phy_type;
- struct efx_phy_operations *phy_op;
+ const struct efx_phy_operations *phy_op;
void *phy_data;
struct mdio_if_info mdio;
unsigned int mdio_bus;
@@ -788,7 +782,7 @@ struct efx_nic {
bool promiscuous;
union efx_multicast_hash multicast_hash;
- enum efx_fc_type wanted_fc;
+ u8 wanted_fc;
atomic_t rx_reset;
enum efx_loopback_mode loopback_mode;
@@ -897,7 +891,7 @@ struct efx_nic_type {
void (*resume_wol)(struct efx_nic *efx);
int (*test_registers)(struct efx_nic *efx);
int (*test_nvram)(struct efx_nic *efx);
- struct efx_mac_operations *default_mac_ops;
+ const struct efx_mac_operations *default_mac_ops;
int revision;
unsigned int mem_map_size;
diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c
index 9b29a8d7c449..f2a2b947f860 100644
--- a/drivers/net/sfc/nic.c
+++ b/drivers/net/sfc/nic.c
@@ -852,7 +852,6 @@ efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event)
unsigned expected_ptr;
bool rx_ev_pkt_ok, discard = false, checksummed;
struct efx_rx_queue *rx_queue;
- struct efx_nic *efx = channel->efx;
/* Basic packet information */
rx_ev_byte_cnt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_BYTE_CNT);
@@ -875,9 +874,8 @@ efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event)
* UDP/IP, then we can rely on the hardware checksum.
*/
checksummed =
- likely(efx->rx_checksum_enabled) &&
- (rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_TCP ||
- rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_UDP);
+ rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_TCP ||
+ rx_ev_hdr_type == FSE_CZ_RX_EV_HDR_TYPE_IPV4V6_UDP;
} else {
efx_handle_rx_not_ok(rx_queue, event, &rx_ev_pkt_ok, &discard);
checksummed = false;
diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h
index d91701abd331..4bd1f2839dfe 100644
--- a/drivers/net/sfc/nic.h
+++ b/drivers/net/sfc/nic.h
@@ -152,9 +152,9 @@ struct siena_nic_data {
int wol_filter_id;
};
-extern struct efx_nic_type falcon_a1_nic_type;
-extern struct efx_nic_type falcon_b0_nic_type;
-extern struct efx_nic_type siena_a0_nic_type;
+extern const struct efx_nic_type falcon_a1_nic_type;
+extern const struct efx_nic_type falcon_b0_nic_type;
+extern const struct efx_nic_type siena_a0_nic_type;
/**************************************************************************
*
diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h
index b3b79472421e..11d148cd8441 100644
--- a/drivers/net/sfc/phy.h
+++ b/drivers/net/sfc/phy.h
@@ -13,14 +13,14 @@
/****************************************************************************
* 10Xpress (SFX7101) PHY
*/
-extern struct efx_phy_operations falcon_sfx7101_phy_ops;
+extern const struct efx_phy_operations falcon_sfx7101_phy_ops;
extern void tenxpress_set_id_led(struct efx_nic *efx, enum efx_led_mode mode);
/****************************************************************************
* AMCC/Quake QT202x PHYs
*/
-extern struct efx_phy_operations falcon_qt202x_phy_ops;
+extern const struct efx_phy_operations falcon_qt202x_phy_ops;
/* These PHYs provide various H/W control states for LEDs */
#define QUAKE_LED_LINK_INVAL (0)
@@ -39,7 +39,7 @@ extern void falcon_qt202x_set_led(struct efx_nic *p, int led, int state);
/****************************************************************************
* Transwitch CX4 retimer
*/
-extern struct efx_phy_operations falcon_txc_phy_ops;
+extern const struct efx_phy_operations falcon_txc_phy_ops;
#define TXC_GPIO_DIR_INPUT 0
#define TXC_GPIO_DIR_OUTPUT 1
@@ -50,7 +50,7 @@ extern void falcon_txc_set_gpio_val(struct efx_nic *efx, int pin, int val);
/****************************************************************************
* Siena managed PHYs
*/
-extern struct efx_phy_operations efx_mcdi_phy_ops;
+extern const struct efx_phy_operations efx_mcdi_phy_ops;
extern int efx_mcdi_mdio_read(struct efx_nic *efx, unsigned int bus,
unsigned int prtad, unsigned int devad,
diff --git a/drivers/net/sfc/qt202x_phy.c b/drivers/net/sfc/qt202x_phy.c
index 55f90924247e..7ad97e397406 100644
--- a/drivers/net/sfc/qt202x_phy.c
+++ b/drivers/net/sfc/qt202x_phy.c
@@ -449,7 +449,7 @@ static void qt202x_phy_remove(struct efx_nic *efx)
efx->phy_data = NULL;
}
-struct efx_phy_operations falcon_qt202x_phy_ops = {
+const struct efx_phy_operations falcon_qt202x_phy_ops = {
.probe = qt202x_phy_probe,
.init = qt202x_phy_init,
.reconfigure = qt202x_phy_reconfigure,
diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c
index c0fdb59030fb..62e43649466e 100644
--- a/drivers/net/sfc/rx.c
+++ b/drivers/net/sfc/rx.c
@@ -14,6 +14,7 @@
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
+#include <linux/prefetch.h>
#include <net/ip.h>
#include <net/checksum.h>
#include "net_driver.h"
@@ -605,6 +606,9 @@ void __efx_rx_packet(struct efx_channel *channel,
skb_record_rx_queue(skb, channel->channel);
}
+ if (unlikely(!(efx->net_dev->features & NETIF_F_RXCSUM)))
+ checksummed = false;
+
if (likely(checksummed || rx_buf->is_page)) {
efx_rx_packet_gro(channel, rx_buf, eh, checksummed);
return;
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
index 50ad3bcaf68a..822f6c2a6a7c 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/sfc/selftest.c
@@ -695,12 +695,12 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
/* Offline (i.e. disruptive) testing
* This checks MAC and PHY loopback on the specified port. */
- /* force the carrier state off so the kernel doesn't transmit during
- * the loopback test, and the watchdog timeout doesn't fire. Also put
- * falcon into loopback for the register test.
+ /* Detach the device so the kernel doesn't transmit during the
+ * loopback test and the watchdog timeout doesn't fire.
*/
+ netif_device_detach(efx->net_dev);
+
mutex_lock(&efx->mac_lock);
- efx->port_inhibited = true;
if (efx->loopback_modes) {
/* We need the 312 clock from the PHY to test the XMAC
* registers, so move into XGMII loopback if available */
@@ -750,12 +750,11 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
/* restore the PHY to the previous state */
mutex_lock(&efx->mac_lock);
efx->phy_mode = phy_mode;
- efx->port_inhibited = false;
efx->loopback_mode = loopback_mode;
__efx_reconfigure_port(efx);
mutex_unlock(&efx->mac_lock);
- netif_tx_wake_all_queues(efx->net_dev);
+ netif_device_attach(efx->net_dev);
return rc_test;
}
diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c
index 837869b71db9..fb4721f780ff 100644
--- a/drivers/net/sfc/siena.c
+++ b/drivers/net/sfc/siena.c
@@ -599,7 +599,7 @@ static void siena_init_wol(struct efx_nic *efx)
**************************************************************************
*/
-struct efx_nic_type siena_a0_nic_type = {
+const struct efx_nic_type siena_a0_nic_type = {
.probe = siena_probe_nic,
.remove = siena_remove_nic,
.init = siena_init_nic,
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
index efdceb35aaae..7b0fd89e7b85 100644
--- a/drivers/net/sfc/tenxpress.c
+++ b/drivers/net/sfc/tenxpress.c
@@ -460,7 +460,7 @@ tenxpress_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
/* In loopback, the PHY automatically brings up the correct interface,
* but doesn't advertise the correct speed. So override it */
if (LOOPBACK_EXTERNAL(efx))
- ecmd->speed = SPEED_10000;
+ ethtool_cmd_speed_set(ecmd, SPEED_10000);
}
static int tenxpress_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
@@ -478,7 +478,7 @@ static void sfx7101_set_npage_adv(struct efx_nic *efx, u32 advertising)
advertising & ADVERTISED_10000baseT_Full);
}
-struct efx_phy_operations falcon_sfx7101_phy_ops = {
+const struct efx_phy_operations falcon_sfx7101_phy_ops = {
.probe = tenxpress_phy_probe,
.init = tenxpress_phy_init,
.reconfigure = tenxpress_phy_reconfigure,
diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c
index d2c85dfdf3bf..84eb99e0f8d2 100644
--- a/drivers/net/sfc/tx.c
+++ b/drivers/net/sfc/tx.c
@@ -205,7 +205,9 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb)
goto unwind;
}
smp_mb();
- netif_tx_start_queue(tx_queue->core_txq);
+ if (likely(!efx->loopback_selftest))
+ netif_tx_start_queue(
+ tx_queue->core_txq);
}
insert_ptr = tx_queue->insert_count & tx_queue->ptr_mask;
@@ -338,8 +340,7 @@ netdev_tx_t efx_hard_start_xmit(struct sk_buff *skb,
struct efx_tx_queue *tx_queue;
unsigned index, type;
- if (unlikely(efx->port_inhibited))
- return NETDEV_TX_BUSY;
+ EFX_WARN_ON_PARANOID(!netif_device_present(net_dev));
index = skb_get_queue_mapping(skb);
type = skb->ip_summed == CHECKSUM_PARTIAL ? EFX_TXQ_TYPE_OFFLOAD : 0;
@@ -436,7 +437,7 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
smp_mb();
if (unlikely(netif_tx_queue_stopped(tx_queue->core_txq)) &&
likely(efx->port_enabled) &&
- likely(!efx->port_inhibited)) {
+ likely(netif_device_present(efx->net_dev))) {
fill_level = tx_queue->insert_count - tx_queue->read_count;
if (fill_level < EFX_TXQ_THRESHOLD(efx)) {
EFX_BUG_ON_PARANOID(!efx_dev_registered(efx));
diff --git a/drivers/net/sfc/txc43128_phy.c b/drivers/net/sfc/txc43128_phy.c
index d9886addcc99..7c21b334a75b 100644
--- a/drivers/net/sfc/txc43128_phy.c
+++ b/drivers/net/sfc/txc43128_phy.c
@@ -545,7 +545,7 @@ static void txc43128_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
mdio45_ethtool_gset(&efx->mdio, ecmd);
}
-struct efx_phy_operations falcon_txc_phy_ops = {
+const struct efx_phy_operations falcon_txc_phy_ops = {
.probe = txc43128_phy_probe,
.init = txc43128_phy_init,
.reconfigure = txc43128_phy_reconfigure,
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index dd03bf619988..54415c7b84a2 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -1,7 +1,7 @@
/*
* sgiseeq.c: Seeq8003 ethernet driver for SGI machines.
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
*/
#undef DEBUG
diff --git a/drivers/net/sgiseeq.h b/drivers/net/sgiseeq.h
index 523104de6830..2211e2987a8d 100644
--- a/drivers/net/sgiseeq.h
+++ b/drivers/net/sgiseeq.h
@@ -1,7 +1,7 @@
/*
* sgiseeq.h: Defines for the Seeq8003 ethernet controller.
*
- * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
*/
#ifndef _SGISEEQ_H
#define _SGISEEQ_H
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 35b28f42d208..f4be5c78ebfd 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -44,6 +44,7 @@
#include <linux/mii.h>
#include <linux/slab.h>
#include <linux/dmi.h>
+#include <linux/prefetch.h>
#include <asm/irq.h>
#include "skge.h"
@@ -303,7 +304,7 @@ static int skge_get_settings(struct net_device *dev,
ecmd->advertising = skge->advertising;
ecmd->autoneg = skge->autoneg;
- ecmd->speed = skge->speed;
+ ethtool_cmd_speed_set(ecmd, skge->speed);
ecmd->duplex = skge->duplex;
return 0;
}
@@ -321,8 +322,9 @@ static int skge_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
skge->speed = -1;
} else {
u32 setting;
+ u32 speed = ethtool_cmd_speed(ecmd);
- switch (ecmd->speed) {
+ switch (speed) {
case SPEED_1000:
if (ecmd->duplex == DUPLEX_FULL)
setting = SUPPORTED_1000baseT_Full;
@@ -355,7 +357,7 @@ static int skge_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
if ((setting & supported) == 0)
return -EINVAL;
- skge->speed = ecmd->speed;
+ skge->speed = speed;
skge->duplex = ecmd->duplex;
}
@@ -537,46 +539,6 @@ static int skge_nway_reset(struct net_device *dev)
return 0;
}
-static int skge_set_sg(struct net_device *dev, u32 data)
-{
- struct skge_port *skge = netdev_priv(dev);
- struct skge_hw *hw = skge->hw;
-
- if (hw->chip_id == CHIP_ID_GENESIS && data)
- return -EOPNOTSUPP;
- return ethtool_op_set_sg(dev, data);
-}
-
-static int skge_set_tx_csum(struct net_device *dev, u32 data)
-{
- struct skge_port *skge = netdev_priv(dev);
- struct skge_hw *hw = skge->hw;
-
- if (hw->chip_id == CHIP_ID_GENESIS && data)
- return -EOPNOTSUPP;
-
- return ethtool_op_set_tx_csum(dev, data);
-}
-
-static u32 skge_get_rx_csum(struct net_device *dev)
-{
- struct skge_port *skge = netdev_priv(dev);
-
- return skge->rx_csum;
-}
-
-/* Only Yukon supports checksum offload. */
-static int skge_set_rx_csum(struct net_device *dev, u32 data)
-{
- struct skge_port *skge = netdev_priv(dev);
-
- if (skge->hw->chip_id == CHIP_ID_GENESIS && data)
- return -EOPNOTSUPP;
-
- skge->rx_csum = data;
- return 0;
-}
-
static void skge_get_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *ecmd)
{
@@ -786,28 +748,27 @@ static void skge_led(struct skge_port *skge, enum led_mode mode)
}
/* blink LED's for finding board */
-static int skge_phys_id(struct net_device *dev, u32 data)
+static int skge_set_phys_id(struct net_device *dev,
+ enum ethtool_phys_id_state state)
{
struct skge_port *skge = netdev_priv(dev);
- unsigned long ms;
- enum led_mode mode = LED_MODE_TST;
- if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
- ms = jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT / HZ) * 1000;
- else
- ms = data * 1000;
+ switch (state) {
+ case ETHTOOL_ID_ACTIVE:
+ return 2; /* cycle on/off twice per second */
- while (ms > 0) {
- skge_led(skge, mode);
- mode ^= LED_MODE_TST;
+ case ETHTOOL_ID_ON:
+ skge_led(skge, LED_MODE_TST);
+ break;
- if (msleep_interruptible(BLINK_MS))
- break;
- ms -= BLINK_MS;
- }
+ case ETHTOOL_ID_OFF:
+ skge_led(skge, LED_MODE_OFF);
+ break;
- /* back to regular LED state */
- skge_led(skge, netif_running(dev) ? LED_MODE_ON : LED_MODE_OFF);
+ case ETHTOOL_ID_INACTIVE:
+ /* back to regular LED state */
+ skge_led(skge, netif_running(dev) ? LED_MODE_ON : LED_MODE_OFF);
+ }
return 0;
}
@@ -925,12 +886,8 @@ static const struct ethtool_ops skge_ethtool_ops = {
.set_pauseparam = skge_set_pauseparam,
.get_coalesce = skge_get_coalesce,
.set_coalesce = skge_set_coalesce,
- .set_sg = skge_set_sg,
- .set_tx_csum = skge_set_tx_csum,
- .get_rx_csum = skge_get_rx_csum,
- .set_rx_csum = skge_set_rx_csum,
.get_strings = skge_get_strings,
- .phys_id = skge_phys_id,
+ .set_phys_id = skge_set_phys_id,
.get_sset_count = skge_get_sset_count,
.get_ethtool_stats = skge_get_ethtool_stats,
};
@@ -3085,7 +3042,8 @@ static struct sk_buff *skge_rx_get(struct net_device *dev,
}
skb_put(skb, len);
- if (skge->rx_csum) {
+
+ if (dev->features & NETIF_F_RXCSUM) {
skb->csum = csum;
skb->ip_summed = CHECKSUM_COMPLETE;
}
@@ -3847,10 +3805,10 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
setup_timer(&skge->link_timer, xm_link_timer, (unsigned long) skge);
if (hw->chip_id != CHIP_ID_GENESIS) {
- dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
- skge->rx_csum = 1;
+ dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
+ NETIF_F_RXCSUM;
+ dev->features |= dev->hw_features;
}
- dev->features |= NETIF_F_GRO;
/* read the mac address */
memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port*8, ETH_ALEN);
diff --git a/drivers/net/skge.h b/drivers/net/skge.h
index 51c0214ac25c..598bf7a1a55e 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/skge.h
@@ -2460,7 +2460,6 @@ struct skge_port {
struct timer_list link_timer;
enum pause_control flow_control;
enum pause_status flow_status;
- u8 rx_csum;
u8 blink_on;
u8 wol;
u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index ff8d262dc276..3ee41da130c2 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -1198,12 +1198,12 @@ static void rx_set_checksum(struct sky2_port *sky2)
sky2_write32(sky2->hw,
Q_ADDR(rxqaddr[sky2->port], Q_CSR),
- (sky2->flags & SKY2_FLAG_RX_CHECKSUM)
+ (sky2->netdev->features & NETIF_F_RXCSUM)
? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
}
/* Enable/disable receive hash calculation (RSS) */
-static void rx_set_rss(struct net_device *dev)
+static void rx_set_rss(struct net_device *dev, u32 features)
{
struct sky2_port *sky2 = netdev_priv(dev);
struct sky2_hw *hw = sky2->hw;
@@ -1216,7 +1216,7 @@ static void rx_set_rss(struct net_device *dev)
}
/* Program RSS initial values */
- if (dev->features & NETIF_F_RXHASH) {
+ if (features & NETIF_F_RXHASH) {
u32 key[nkeys];
get_random_bytes(key, nkeys * sizeof(u32));
@@ -1322,32 +1322,32 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return err;
}
-#define NETIF_F_ALL_VLAN (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX)
+#define SKY2_VLAN_OFFLOADS (NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO)
-static void sky2_vlan_mode(struct net_device *dev)
+static void sky2_vlan_mode(struct net_device *dev, u32 features)
{
struct sky2_port *sky2 = netdev_priv(dev);
struct sky2_hw *hw = sky2->hw;
u16 port = sky2->port;
- if (dev->features & NETIF_F_HW_VLAN_RX)
+ if (features & NETIF_F_HW_VLAN_RX)
sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T),
RX_VLAN_STRIP_ON);
else
sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T),
RX_VLAN_STRIP_OFF);
- dev->vlan_features = dev->features &~ NETIF_F_ALL_VLAN;
- if (dev->features & NETIF_F_HW_VLAN_TX)
+ if (features & NETIF_F_HW_VLAN_TX) {
sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
TX_VLAN_TAG_ON);
- else {
+
+ dev->vlan_features |= SKY2_VLAN_OFFLOADS;
+ } else {
sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
TX_VLAN_TAG_OFF);
/* Can't do transmit offload of vlan without hw vlan */
- dev->vlan_features &= ~(NETIF_F_TSO | NETIF_F_SG
- | NETIF_F_ALL_CSUM);
+ dev->vlan_features &= ~SKY2_VLAN_OFFLOADS;
}
}
@@ -1463,7 +1463,7 @@ static void sky2_rx_start(struct sky2_port *sky2)
rx_set_checksum(sky2);
if (!(hw->flags & SKY2_HW_RSS_BROKEN))
- rx_set_rss(sky2->netdev);
+ rx_set_rss(sky2->netdev, sky2->netdev->features);
/* submit Rx ring */
for (i = 0; i < sky2->rx_pending; i++) {
@@ -1626,7 +1626,8 @@ static void sky2_hw_up(struct sky2_port *sky2)
sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map,
sky2->tx_ring_size - 1);
- sky2_vlan_mode(sky2->netdev);
+ sky2_vlan_mode(sky2->netdev, sky2->netdev->features);
+ netdev_update_features(sky2->netdev);
sky2_rx_start(sky2);
}
@@ -2261,12 +2262,9 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
hw->chip_id == CHIP_ID_YUKON_FE_P))
return -EINVAL;
- /* TSO, etc on Yukon Ultra and MTU > 1500 not supported */
- if (new_mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_EC_U)
- dev->features &= ~(NETIF_F_TSO|NETIF_F_SG|NETIF_F_ALL_CSUM);
-
if (!netif_running(dev)) {
dev->mtu = new_mtu;
+ netdev_update_features(dev);
return 0;
}
@@ -2288,6 +2286,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
sky2_rx_clean(sky2);
dev->mtu = new_mtu;
+ netdev_update_features(dev);
mode = DATA_BLIND_VAL(DATA_BLIND_DEF) |
GM_SMOD_VLAN_ENA | IPG_DATA_VAL(IPG_DATA_DEF);
@@ -2535,8 +2534,11 @@ static void sky2_rx_checksum(struct sky2_port *sky2, u32 status)
"%s: receive checksum problem (status = %#x)\n",
sky2->netdev->name, status);
- /* Disable checksum offload */
- sky2->flags &= ~SKY2_FLAG_RX_CHECKSUM;
+ /* Disable checksum offload
+ * It will be reenabled on next ndo_set_features, but if it's
+ * really broken, will get disabled again
+ */
+ sky2->netdev->features &= ~NETIF_F_RXCSUM;
sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR),
BMU_DIS_RX_CHKSUM);
}
@@ -2591,7 +2593,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
/* This chip reports checksum status differently */
if (hw->flags & SKY2_HW_NEW_LE) {
- if ((sky2->flags & SKY2_FLAG_RX_CHECKSUM) &&
+ if ((dev->features & NETIF_F_RXCSUM) &&
(le->css & (CSS_ISIPV4 | CSS_ISIPV6)) &&
(le->css & CSS_TCPUDPCSOK))
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -2616,7 +2618,7 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do, u16 idx)
sky2->rx_tag = length;
/* fall through */
case OP_RXCHKS:
- if (likely(sky2->flags & SKY2_FLAG_RX_CHECKSUM))
+ if (likely(dev->features & NETIF_F_RXCSUM))
sky2_rx_checksum(sky2, status);
break;
@@ -3411,10 +3413,10 @@ static int sky2_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
ecmd->phy_address = PHY_ADDR_MARV;
if (sky2_is_copper(hw)) {
ecmd->port = PORT_TP;
- ecmd->speed = sky2->speed;
+ ethtool_cmd_speed_set(ecmd, sky2->speed);
ecmd->supported |= SUPPORTED_Autoneg | SUPPORTED_TP;
} else {
- ecmd->speed = SPEED_1000;
+ ethtool_cmd_speed_set(ecmd, SPEED_1000);
ecmd->port = PORT_FIBRE;
ecmd->supported |= SUPPORTED_Autoneg | SUPPORTED_FIBRE;
}
@@ -3450,8 +3452,9 @@ static int sky2_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
sky2->speed = -1;
} else {
u32 setting;
+ u32 speed = ethtool_cmd_speed(ecmd);
- switch (ecmd->speed) {
+ switch (speed) {
case SPEED_1000:
if (ecmd->duplex == DUPLEX_FULL)
setting = SUPPORTED_1000baseT_Full;
@@ -3484,7 +3487,7 @@ static int sky2_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
if ((setting & supported) == 0)
return -EINVAL;
- sky2->speed = ecmd->speed;
+ sky2->speed = speed;
sky2->duplex = ecmd->duplex;
sky2->flags &= ~SKY2_FLAG_AUTO_SPEED;
}
@@ -3552,28 +3555,6 @@ static const struct sky2_stat {
{ "tx_fifo_underrun", GM_TXE_FIFO_UR },
};
-static u32 sky2_get_rx_csum(struct net_device *dev)
-{
- struct sky2_port *sky2 = netdev_priv(dev);
-
- return !!(sky2->flags & SKY2_FLAG_RX_CHECKSUM);
-}
-
-static int sky2_set_rx_csum(struct net_device *dev, u32 data)
-{
- struct sky2_port *sky2 = netdev_priv(dev);
-
- if (data)
- sky2->flags |= SKY2_FLAG_RX_CHECKSUM;
- else
- sky2->flags &= ~SKY2_FLAG_RX_CHECKSUM;
-
- sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR),
- data ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
-
- return 0;
-}
-
static u32 sky2_get_msglevel(struct net_device *netdev)
{
struct sky2_port *sky2 = netdev_priv(netdev);
@@ -3826,23 +3807,24 @@ static void sky2_led(struct sky2_port *sky2, enum led_mode mode)
}
/* blink LED's for finding board */
-static int sky2_phys_id(struct net_device *dev, u32 data)
+static int sky2_set_phys_id(struct net_device *dev,
+ enum ethtool_phys_id_state state)
{
struct sky2_port *sky2 = netdev_priv(dev);
- unsigned int i;
-
- if (data == 0)
- data = UINT_MAX;
- for (i = 0; i < data; i++) {
+ switch (state) {
+ case ETHTOOL_ID_ACTIVE:
+ return 1; /* cycle on/off once per second */
+ case ETHTOOL_ID_INACTIVE:
+ sky2_led(sky2, MO_LED_NORM);
+ break;
+ case ETHTOOL_ID_ON:
sky2_led(sky2, MO_LED_ON);
- if (msleep_interruptible(500))
- break;
+ break;
+ case ETHTOOL_ID_OFF:
sky2_led(sky2, MO_LED_OFF);
- if (msleep_interruptible(500))
- break;
+ break;
}
- sky2_led(sky2, MO_LED_NORM);
return 0;
}
@@ -4083,34 +4065,6 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs,
}
}
-/* In order to do Jumbo packets on these chips, need to turn off the
- * transmit store/forward. Therefore checksum offload won't work.
- */
-static int no_tx_offload(struct net_device *dev)
-{
- const struct sky2_port *sky2 = netdev_priv(dev);
- const struct sky2_hw *hw = sky2->hw;
-
- return dev->mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_EC_U;
-}
-
-static int sky2_set_tx_csum(struct net_device *dev, u32 data)
-{
- if (data && no_tx_offload(dev))
- return -EINVAL;
-
- return ethtool_op_set_tx_csum(dev, data);
-}
-
-
-static int sky2_set_tso(struct net_device *dev, u32 data)
-{
- if (data && no_tx_offload(dev))
- return -EINVAL;
-
- return ethtool_op_set_tso(dev, data);
-}
-
static int sky2_get_eeprom_len(struct net_device *dev)
{
struct sky2_port *sky2 = netdev_priv(dev);
@@ -4213,31 +4167,36 @@ static int sky2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom
return sky2_vpd_write(sky2->hw, cap, data, eeprom->offset, eeprom->len);
}
-static int sky2_set_flags(struct net_device *dev, u32 data)
+static u32 sky2_fix_features(struct net_device *dev, u32 features)
{
- struct sky2_port *sky2 = netdev_priv(dev);
- unsigned long old_feat = dev->features;
- u32 supported = 0;
- int rc;
+ const struct sky2_port *sky2 = netdev_priv(dev);
+ const struct sky2_hw *hw = sky2->hw;
- if (!(sky2->hw->flags & SKY2_HW_RSS_BROKEN))
- supported |= ETH_FLAG_RXHASH;
+ /* In order to do Jumbo packets on these chips, need to turn off the
+ * transmit store/forward. Therefore checksum offload won't work.
+ */
+ if (dev->mtu > ETH_DATA_LEN && hw->chip_id == CHIP_ID_YUKON_EC_U)
+ features &= ~(NETIF_F_TSO|NETIF_F_SG|NETIF_F_ALL_CSUM);
- if (!(sky2->hw->flags & SKY2_HW_VLAN_BROKEN))
- supported |= ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN;
+ return features;
+}
- printk(KERN_DEBUG "sky2 set_flags: supported %x data %x\n",
- supported, data);
+static int sky2_set_features(struct net_device *dev, u32 features)
+{
+ struct sky2_port *sky2 = netdev_priv(dev);
+ u32 changed = dev->features ^ features;
- rc = ethtool_op_set_flags(dev, data, supported);
- if (rc)
- return rc;
+ if (changed & NETIF_F_RXCSUM) {
+ u32 on = features & NETIF_F_RXCSUM;
+ sky2_write32(sky2->hw, Q_ADDR(rxqaddr[sky2->port], Q_CSR),
+ on ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM);
+ }
- if ((old_feat ^ dev->features) & NETIF_F_RXHASH)
- rx_set_rss(dev);
+ if (changed & NETIF_F_RXHASH)
+ rx_set_rss(dev, features);
- if ((old_feat ^ dev->features) & NETIF_F_ALL_VLAN)
- sky2_vlan_mode(dev);
+ if (changed & (NETIF_F_HW_VLAN_TX|NETIF_F_HW_VLAN_RX))
+ sky2_vlan_mode(dev, features);
return 0;
}
@@ -4257,11 +4216,6 @@ static const struct ethtool_ops sky2_ethtool_ops = {
.get_eeprom_len = sky2_get_eeprom_len,
.get_eeprom = sky2_get_eeprom,
.set_eeprom = sky2_set_eeprom,
- .set_sg = ethtool_op_set_sg,
- .set_tx_csum = sky2_set_tx_csum,
- .set_tso = sky2_set_tso,
- .get_rx_csum = sky2_get_rx_csum,
- .set_rx_csum = sky2_set_rx_csum,
.get_strings = sky2_get_strings,
.get_coalesce = sky2_get_coalesce,
.set_coalesce = sky2_set_coalesce,
@@ -4269,11 +4223,9 @@ static const struct ethtool_ops sky2_ethtool_ops = {
.set_ringparam = sky2_set_ringparam,
.get_pauseparam = sky2_get_pauseparam,
.set_pauseparam = sky2_set_pauseparam,
- .phys_id = sky2_phys_id,
+ .set_phys_id = sky2_set_phys_id,
.get_sset_count = sky2_get_sset_count,
.get_ethtool_stats = sky2_get_ethtool_stats,
- .set_flags = sky2_set_flags,
- .get_flags = ethtool_op_get_flags,
};
#ifdef CONFIG_SKY2_DEBUG
@@ -4553,6 +4505,8 @@ static const struct net_device_ops sky2_netdev_ops[2] = {
.ndo_set_mac_address = sky2_set_mac_address,
.ndo_set_multicast_list = sky2_set_multicast,
.ndo_change_mtu = sky2_change_mtu,
+ .ndo_fix_features = sky2_fix_features,
+ .ndo_set_features = sky2_set_features,
.ndo_tx_timeout = sky2_tx_timeout,
.ndo_get_stats64 = sky2_get_stats,
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -4568,6 +4522,8 @@ static const struct net_device_ops sky2_netdev_ops[2] = {
.ndo_set_mac_address = sky2_set_mac_address,
.ndo_set_multicast_list = sky2_set_multicast,
.ndo_change_mtu = sky2_change_mtu,
+ .ndo_fix_features = sky2_fix_features,
+ .ndo_set_features = sky2_set_features,
.ndo_tx_timeout = sky2_tx_timeout,
.ndo_get_stats64 = sky2_get_stats,
},
@@ -4600,7 +4556,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
/* Auto speed and flow control */
sky2->flags = SKY2_FLAG_AUTO_SPEED | SKY2_FLAG_AUTO_PAUSE;
if (hw->chip_id != CHIP_ID_YUKON_XL)
- sky2->flags |= SKY2_FLAG_RX_CHECKSUM;
+ dev->hw_features |= NETIF_F_RXCSUM;
sky2->flow_mode = FC_BOTH;
@@ -4619,18 +4575,21 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
sky2->port = port;
- dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG
- | NETIF_F_TSO | NETIF_F_GRO;
+ dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO;
if (highmem)
dev->features |= NETIF_F_HIGHDMA;
/* Enable receive hashing unless hardware is known broken */
if (!(hw->flags & SKY2_HW_RSS_BROKEN))
- dev->features |= NETIF_F_RXHASH;
+ dev->hw_features |= NETIF_F_RXHASH;
+
+ if (!(hw->flags & SKY2_HW_VLAN_BROKEN)) {
+ dev->hw_features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ dev->vlan_features |= SKY2_VLAN_OFFLOADS;
+ }
- if (!(hw->flags & SKY2_HW_VLAN_BROKEN))
- dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+ dev->features |= dev->hw_features;
/* read the mac address */
memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8, ETH_ALEN);
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 0c6d10c5f053..318c9ae7bf91 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -2254,7 +2254,6 @@ struct sky2_port {
u8 wol; /* WAKE_ bits */
u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */
u16 flags;
-#define SKY2_FLAG_RX_CHECKSUM 0x0001
#define SKY2_FLAG_AUTO_SPEED 0x0002
#define SKY2_FLAG_AUTO_PAUSE 0x0004
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 8ec1a9a0bb9a..584809c656d5 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -670,16 +670,17 @@ static void sl_setup(struct net_device *dev)
* in parallel
*/
-static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp,
- char *fp, int count)
+static unsigned int slip_receive_buf(struct tty_struct *tty,
+ const unsigned char *cp, char *fp, int count)
{
struct slip *sl = tty->disc_data;
+ int bytes = count;
if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev))
- return;
+ return -ENODEV;
/* Read the characters out of the buffer */
- while (count--) {
+ while (bytes--) {
if (fp && *fp++) {
if (!test_and_set_bit(SLF_ERROR, &sl->flags))
sl->dev->stats.rx_errors++;
@@ -693,6 +694,8 @@ static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp,
#endif
slip_unesc(sl, *cp++);
}
+
+ return count;
}
/************************************
diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c
index d07c39cb4daf..0f29f261fcfe 100644
--- a/drivers/net/smc-mca.c
+++ b/drivers/net/smc-mca.c
@@ -156,7 +156,7 @@ static const struct {
{ 14, 15 }
};
-static short smc_mca_adapter_ids[] __initdata = {
+static const short smc_mca_adapter_ids[] __devinitconst = {
0x61c8,
0x61c9,
0x6fc0,
@@ -168,7 +168,7 @@ static short smc_mca_adapter_ids[] __initdata = {
0x0000
};
-static char *smc_mca_adapter_names[] __initdata = {
+static const char *const smc_mca_adapter_names[] __devinitconst = {
"SMC Ethercard PLUS Elite/A BNC/AUI (WD8013EP/A)",
"SMC Ethercard PLUS Elite/A UTP/AUI (WD8013WP/A)",
"WD Ethercard PLUS/A (WD8003E/A or WD8003ET/A)",
@@ -199,7 +199,7 @@ static const struct net_device_ops ultramca_netdev_ops = {
#endif
};
-static int __init ultramca_probe(struct device *gen_dev)
+static int __devinit ultramca_probe(struct device *gen_dev)
{
unsigned short ioaddr;
struct net_device *dev;
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 66831f378396..053863aefb12 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -1488,9 +1488,9 @@ smc911x_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd)
SUPPORTED_TP | SUPPORTED_AUI;
if (lp->ctl_rspeed == 10)
- cmd->speed = SPEED_10;
+ ethtool_cmd_speed_set(cmd, SPEED_10);
else if (lp->ctl_rspeed == 100)
- cmd->speed = SPEED_100;
+ ethtool_cmd_speed_set(cmd, SPEED_100);
cmd->autoneg = AUTONEG_DISABLE;
if (lp->mii.phy_id==1)
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index 43654a3bb0ec..dc4805f473e3 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -1565,9 +1565,9 @@ smc_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd)
SUPPORTED_TP | SUPPORTED_AUI;
if (lp->ctl_rspeed == 10)
- cmd->speed = SPEED_10;
+ ethtool_cmd_speed_set(cmd, SPEED_10);
else if (lp->ctl_rspeed == 100)
- cmd->speed = SPEED_100;
+ ethtool_cmd_speed_set(cmd, SPEED_100);
cmd->autoneg = AUTONEG_DISABLE;
cmd->transceiver = XCVR_INTERNAL;
diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c
index 4b42ecc63dcf..c6d47d10590c 100644
--- a/drivers/net/smsc911x.c
+++ b/drivers/net/smsc911x.c
@@ -29,6 +29,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/crc32.h>
#include <linux/delay.h>
#include <linux/errno.h>
@@ -69,6 +71,17 @@ static int debug = 3;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+struct smsc911x_data;
+
+struct smsc911x_ops {
+ u32 (*reg_read)(struct smsc911x_data *pdata, u32 reg);
+ void (*reg_write)(struct smsc911x_data *pdata, u32 reg, u32 val);
+ void (*rx_readfifo)(struct smsc911x_data *pdata,
+ unsigned int *buf, unsigned int wordcount);
+ void (*tx_writefifo)(struct smsc911x_data *pdata,
+ unsigned int *buf, unsigned int wordcount);
+};
+
struct smsc911x_data {
void __iomem *ioaddr;
@@ -116,8 +129,14 @@ struct smsc911x_data {
unsigned int clear_bits_mask;
unsigned int hashhi;
unsigned int hashlo;
+
+ /* register access functions */
+ const struct smsc911x_ops *ops;
};
+/* Easy access to information */
+#define __smsc_shift(pdata, reg) ((reg) << ((pdata)->config.shift))
+
static inline u32 __smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg)
{
if (pdata->config.flags & SMSC911X_USE_32BIT)
@@ -131,13 +150,29 @@ static inline u32 __smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg)
return 0;
}
+static inline u32
+__smsc911x_reg_read_shift(struct smsc911x_data *pdata, u32 reg)
+{
+ if (pdata->config.flags & SMSC911X_USE_32BIT)
+ return readl(pdata->ioaddr + __smsc_shift(pdata, reg));
+
+ if (pdata->config.flags & SMSC911X_USE_16BIT)
+ return (readw(pdata->ioaddr +
+ __smsc_shift(pdata, reg)) & 0xFFFF) |
+ ((readw(pdata->ioaddr +
+ __smsc_shift(pdata, reg + 2)) & 0xFFFF) << 16);
+
+ BUG();
+ return 0;
+}
+
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);
+ data = pdata->ops->reg_read(pdata, reg);
spin_unlock_irqrestore(&pdata->dev_lock, flags);
return data;
@@ -160,13 +195,32 @@ static inline void __smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg,
BUG();
}
+static inline void
+__smsc911x_reg_write_shift(struct smsc911x_data *pdata, u32 reg, u32 val)
+{
+ if (pdata->config.flags & SMSC911X_USE_32BIT) {
+ writel(val, pdata->ioaddr + __smsc_shift(pdata, reg));
+ return;
+ }
+
+ if (pdata->config.flags & SMSC911X_USE_16BIT) {
+ writew(val & 0xFFFF,
+ pdata->ioaddr + __smsc_shift(pdata, reg));
+ writew((val >> 16) & 0xFFFF,
+ pdata->ioaddr + __smsc_shift(pdata, reg + 2));
+ 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);
+ pdata->ops->reg_write(pdata, reg, val);
spin_unlock_irqrestore(&pdata->dev_lock, flags);
}
@@ -202,6 +256,40 @@ out:
spin_unlock_irqrestore(&pdata->dev_lock, flags);
}
+/* Writes a packet to the TX_DATA_FIFO - shifted version */
+static inline void
+smsc911x_tx_writefifo_shift(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_shift(pdata, TX_DATA_FIFO,
+ swab32(*buf++));
+ goto out;
+ }
+
+ if (pdata->config.flags & SMSC911X_USE_32BIT) {
+ writesl(pdata->ioaddr + __smsc_shift(pdata,
+ TX_DATA_FIFO), buf, wordcount);
+ goto out;
+ }
+
+ if (pdata->config.flags & SMSC911X_USE_16BIT) {
+ while (wordcount--)
+ __smsc911x_reg_write_shift(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 */
static inline void
smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf,
@@ -234,6 +322,40 @@ out:
spin_unlock_irqrestore(&pdata->dev_lock, flags);
}
+/* Reads a packet out of the RX_DATA_FIFO - shifted version */
+static inline void
+smsc911x_rx_readfifo_shift(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_shift(pdata,
+ RX_DATA_FIFO));
+ goto out;
+ }
+
+ if (pdata->config.flags & SMSC911X_USE_32BIT) {
+ readsl(pdata->ioaddr + __smsc_shift(pdata,
+ RX_DATA_FIFO), buf, wordcount);
+ goto out;
+ }
+
+ if (pdata->config.flags & SMSC911X_USE_16BIT) {
+ while (wordcount--)
+ *buf++ = __smsc911x_reg_read_shift(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
* and smsc911x_mac_write, so assumes mac_lock is held */
static int smsc911x_mac_complete(struct smsc911x_data *pdata)
@@ -248,8 +370,8 @@ static int smsc911x_mac_complete(struct smsc911x_data *pdata)
if (!(val & MAC_CSR_CMD_CSR_BUSY_))
return 0;
}
- SMSC_WARNING(HW, "Timed out waiting for MAC not BUSY. "
- "MAC_CSR_CMD: 0x%08X", val);
+ SMSC_WARN(pdata, hw, "Timed out waiting for MAC not BUSY. "
+ "MAC_CSR_CMD: 0x%08X", val);
return -EIO;
}
@@ -262,7 +384,7 @@ static u32 smsc911x_mac_read(struct smsc911x_data *pdata, unsigned int offset)
temp = smsc911x_reg_read(pdata, MAC_CSR_CMD);
if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) {
- SMSC_WARNING(HW, "MAC busy at entry");
+ SMSC_WARN(pdata, hw, "MAC busy at entry");
return 0xFFFFFFFF;
}
@@ -277,7 +399,7 @@ static u32 smsc911x_mac_read(struct smsc911x_data *pdata, unsigned int offset)
if (likely(smsc911x_mac_complete(pdata) == 0))
return smsc911x_reg_read(pdata, MAC_CSR_DATA);
- SMSC_WARNING(HW, "MAC busy after read");
+ SMSC_WARN(pdata, hw, "MAC busy after read");
return 0xFFFFFFFF;
}
@@ -291,8 +413,8 @@ static void smsc911x_mac_write(struct smsc911x_data *pdata,
temp = smsc911x_reg_read(pdata, MAC_CSR_CMD);
if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) {
- SMSC_WARNING(HW,
- "smsc911x_mac_write failed, MAC busy at entry");
+ SMSC_WARN(pdata, hw,
+ "smsc911x_mac_write failed, MAC busy at entry");
return;
}
@@ -310,8 +432,7 @@ static void smsc911x_mac_write(struct smsc911x_data *pdata,
if (likely(smsc911x_mac_complete(pdata) == 0))
return;
- SMSC_WARNING(HW,
- "smsc911x_mac_write failed, MAC busy after write");
+ SMSC_WARN(pdata, hw, "smsc911x_mac_write failed, MAC busy after write");
}
/* Get a phy register */
@@ -326,8 +447,7 @@ static int smsc911x_mii_read(struct mii_bus *bus, int phyaddr, int regidx)
/* Confirm MII not busy */
if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) {
- SMSC_WARNING(HW,
- "MII is busy in smsc911x_mii_read???");
+ SMSC_WARN(pdata, hw, "MII is busy in smsc911x_mii_read???");
reg = -EIO;
goto out;
}
@@ -343,7 +463,7 @@ static int smsc911x_mii_read(struct mii_bus *bus, int phyaddr, int regidx)
goto out;
}
- SMSC_WARNING(HW, "Timed out waiting for MII read to finish");
+ SMSC_WARN(pdata, hw, "Timed out waiting for MII read to finish");
reg = -EIO;
out:
@@ -364,8 +484,7 @@ static int smsc911x_mii_write(struct mii_bus *bus, int phyaddr, int regidx,
/* Confirm MII not busy */
if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) {
- SMSC_WARNING(HW,
- "MII is busy in smsc911x_mii_write???");
+ SMSC_WARN(pdata, hw, "MII is busy in smsc911x_mii_write???");
reg = -EIO;
goto out;
}
@@ -385,7 +504,7 @@ static int smsc911x_mii_write(struct mii_bus *bus, int phyaddr, int regidx,
goto out;
}
- SMSC_WARNING(HW, "Timed out waiting for MII write to finish");
+ SMSC_WARN(pdata, hw, "Timed out waiting for MII write to finish");
reg = -EIO;
out:
@@ -426,18 +545,20 @@ static void smsc911x_phy_initialise_external(struct smsc911x_data *pdata)
unsigned int hwcfg = smsc911x_reg_read(pdata, HW_CFG);
if (pdata->config.flags & SMSC911X_FORCE_INTERNAL_PHY) {
- SMSC_TRACE(HW, "Forcing internal PHY");
+ SMSC_TRACE(pdata, hw, "Forcing internal PHY");
pdata->using_extphy = 0;
} else if (pdata->config.flags & SMSC911X_FORCE_EXTERNAL_PHY) {
- SMSC_TRACE(HW, "Forcing external PHY");
+ SMSC_TRACE(pdata, hw, "Forcing external PHY");
smsc911x_phy_enable_external(pdata);
pdata->using_extphy = 1;
} else if (hwcfg & HW_CFG_EXT_PHY_DET_) {
- SMSC_TRACE(HW, "HW_CFG EXT_PHY_DET set, using external PHY");
+ SMSC_TRACE(pdata, hw,
+ "HW_CFG EXT_PHY_DET set, using external PHY");
smsc911x_phy_enable_external(pdata);
pdata->using_extphy = 1;
} else {
- SMSC_TRACE(HW, "HW_CFG EXT_PHY_DET clear, using internal PHY");
+ SMSC_TRACE(pdata, hw,
+ "HW_CFG EXT_PHY_DET clear, using internal PHY");
pdata->using_extphy = 0;
}
}
@@ -499,7 +620,7 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata)
wrsz += (u32)((ulong)pdata->loopback_tx_pkt & 0x3);
wrsz >>= 2;
- smsc911x_tx_writefifo(pdata, (unsigned int *)bufp, wrsz);
+ pdata->ops->tx_writefifo(pdata, (unsigned int *)bufp, wrsz);
/* Wait till transmit is done */
i = 60;
@@ -509,13 +630,13 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata)
} while ((i--) && (!status));
if (!status) {
- SMSC_WARNING(HW, "Failed to transmit "
- "during loopback test");
+ SMSC_WARN(pdata, hw,
+ "Failed to transmit during loopback test");
continue;
}
if (status & TX_STS_ES_) {
- SMSC_WARNING(HW, "Transmit encountered "
- "errors during loopback test");
+ SMSC_WARN(pdata, hw,
+ "Transmit encountered errors during loopback test");
continue;
}
@@ -527,13 +648,13 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata)
} while ((i--) && (!status));
if (!status) {
- SMSC_WARNING(HW,
- "Failed to receive during loopback test");
+ SMSC_WARN(pdata, hw,
+ "Failed to receive during loopback test");
continue;
}
if (status & RX_STS_ES_) {
- SMSC_WARNING(HW, "Receive encountered "
- "errors during loopback test");
+ SMSC_WARN(pdata, hw,
+ "Receive encountered errors during loopback test");
continue;
}
@@ -543,12 +664,12 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata)
rdsz += (u32)((ulong)pdata->loopback_rx_pkt & 0x3);
rdsz >>= 2;
- smsc911x_rx_readfifo(pdata, (unsigned int *)bufp, rdsz);
+ pdata->ops->rx_readfifo(pdata, (unsigned int *)bufp, rdsz);
if (pktlength != (MIN_PACKET_SIZE + 4)) {
- SMSC_WARNING(HW, "Unexpected packet size "
- "during loop back test, size=%d, will retry",
- pktlength);
+ SMSC_WARN(pdata, hw, "Unexpected packet size "
+ "during loop back test, size=%d, will retry",
+ pktlength);
} else {
unsigned int j;
int mismatch = 0;
@@ -560,12 +681,12 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata)
}
}
if (!mismatch) {
- SMSC_TRACE(HW, "Successfully verified "
+ SMSC_TRACE(pdata, hw, "Successfully verified "
"loopback packet");
return 0;
} else {
- SMSC_WARNING(HW, "Data mismatch "
- "during loop back test, will retry");
+ SMSC_WARN(pdata, hw, "Data mismatch "
+ "during loop back test, will retry");
}
}
}
@@ -582,7 +703,7 @@ static int smsc911x_phy_reset(struct smsc911x_data *pdata)
BUG_ON(!phy_dev);
BUG_ON(!phy_dev->bus);
- SMSC_TRACE(HW, "Performing PHY BCR Reset");
+ SMSC_TRACE(pdata, hw, "Performing PHY BCR Reset");
smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, BMCR_RESET);
do {
msleep(1);
@@ -591,7 +712,7 @@ static int smsc911x_phy_reset(struct smsc911x_data *pdata)
} while ((i--) && (temp & BMCR_RESET));
if (temp & BMCR_RESET) {
- SMSC_WARNING(HW, "PHY reset failed to complete.");
+ SMSC_WARN(pdata, hw, "PHY reset failed to complete");
return -EIO;
}
/* Extra delay required because the phy may not be completed with
@@ -695,11 +816,11 @@ static void smsc911x_phy_update_flowcontrol(struct smsc911x_data *pdata)
else
afc &= ~0xF;
- SMSC_TRACE(HW, "rx pause %s, tx pause %s",
- (cap & FLOW_CTRL_RX ? "enabled" : "disabled"),
- (cap & FLOW_CTRL_TX ? "enabled" : "disabled"));
+ SMSC_TRACE(pdata, hw, "rx pause %s, tx pause %s",
+ (cap & FLOW_CTRL_RX ? "enabled" : "disabled"),
+ (cap & FLOW_CTRL_TX ? "enabled" : "disabled"));
} else {
- SMSC_TRACE(HW, "half duplex");
+ SMSC_TRACE(pdata, hw, "half duplex");
flow = 0;
afc |= 0xF;
}
@@ -722,17 +843,17 @@ static void smsc911x_phy_adjust_link(struct net_device *dev)
if (phy_dev->duplex != pdata->last_duplex) {
unsigned int mac_cr;
- SMSC_TRACE(HW, "duplex state has changed");
+ SMSC_TRACE(pdata, hw, "duplex state has changed");
spin_lock_irqsave(&pdata->mac_lock, flags);
mac_cr = smsc911x_mac_read(pdata, MAC_CR);
if (phy_dev->duplex) {
- SMSC_TRACE(HW,
- "configuring for full duplex mode");
+ SMSC_TRACE(pdata, hw,
+ "configuring for full duplex mode");
mac_cr |= MAC_CR_FDPX_;
} else {
- SMSC_TRACE(HW,
- "configuring for half duplex mode");
+ SMSC_TRACE(pdata, hw,
+ "configuring for half duplex mode");
mac_cr &= ~MAC_CR_FDPX_;
}
smsc911x_mac_write(pdata, MAC_CR, mac_cr);
@@ -744,9 +865,9 @@ static void smsc911x_phy_adjust_link(struct net_device *dev)
carrier = netif_carrier_ok(dev);
if (carrier != pdata->last_carrier) {
- SMSC_TRACE(HW, "carrier state has changed");
+ SMSC_TRACE(pdata, hw, "carrier state has changed");
if (carrier) {
- SMSC_TRACE(HW, "configuring for carrier OK");
+ SMSC_TRACE(pdata, hw, "configuring for carrier OK");
if ((pdata->gpio_orig_setting & GPIO_CFG_LED1_EN_) &&
(!pdata->using_extphy)) {
/* Restore original GPIO configuration */
@@ -755,7 +876,7 @@ static void smsc911x_phy_adjust_link(struct net_device *dev)
pdata->gpio_setting);
}
} else {
- SMSC_TRACE(HW, "configuring for no carrier");
+ SMSC_TRACE(pdata, hw, "configuring for no carrier");
/* Check global setting that LED1
* usage is 10/100 indicator */
pdata->gpio_setting = smsc911x_reg_read(pdata,
@@ -787,25 +908,25 @@ static int smsc911x_mii_probe(struct net_device *dev)
/* find the first phy */
phydev = phy_find_first(pdata->mii_bus);
if (!phydev) {
- pr_err("%s: no PHY found\n", dev->name);
+ netdev_err(dev, "no PHY found\n");
return -ENODEV;
}
- SMSC_TRACE(PROBE, "PHY: addr %d, phy_id 0x%08X",
- phydev->addr, phydev->phy_id);
+ SMSC_TRACE(pdata, probe, "PHY: addr %d, phy_id 0x%08X",
+ phydev->addr, phydev->phy_id);
ret = phy_connect_direct(dev, phydev,
&smsc911x_phy_adjust_link, 0,
pdata->config.phy_interface);
if (ret) {
- pr_err("%s: Could not attach to PHY\n", dev->name);
+ netdev_err(dev, "Could not attach to PHY\n");
return ret;
}
- pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
- dev->name, phydev->drv->name,
- dev_name(&phydev->dev), phydev->irq);
+ netdev_info(dev,
+ "attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
+ phydev->drv->name, dev_name(&phydev->dev), phydev->irq);
/* mask with MAC supported features */
phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause |
@@ -818,13 +939,13 @@ static int smsc911x_mii_probe(struct net_device *dev)
#ifdef USE_PHY_WORK_AROUND
if (smsc911x_phy_loopbacktest(dev) < 0) {
- SMSC_WARNING(HW, "Failed Loop Back Test");
+ SMSC_WARN(pdata, hw, "Failed Loop Back Test");
return -ENODEV;
}
- SMSC_TRACE(HW, "Passed Loop Back Test");
+ SMSC_TRACE(pdata, hw, "Passed Loop Back Test");
#endif /* USE_PHY_WORK_AROUND */
- SMSC_TRACE(HW, "phy initialised successfully");
+ SMSC_TRACE(pdata, hw, "phy initialised successfully");
return 0;
}
@@ -860,8 +981,8 @@ static int __devinit smsc911x_mii_init(struct platform_device *pdev,
smsc911x_phy_initialise_external(pdata);
break;
default:
- SMSC_TRACE(HW, "External PHY is not supported, "
- "using internal PHY");
+ SMSC_TRACE(pdata, hw, "External PHY is not supported, "
+ "using internal PHY");
pdata->using_extphy = 0;
break;
}
@@ -872,12 +993,12 @@ static int __devinit smsc911x_mii_init(struct platform_device *pdev,
}
if (mdiobus_register(pdata->mii_bus)) {
- SMSC_WARNING(PROBE, "Error registering mii bus");
+ SMSC_WARN(pdata, probe, "Error registering mii bus");
goto err_out_free_bus_2;
}
if (smsc911x_mii_probe(dev) < 0) {
- SMSC_WARNING(PROBE, "Error registering mii bus");
+ SMSC_WARN(pdata, probe, "Error registering mii bus");
goto err_out_unregister_bus_3;
}
@@ -913,8 +1034,7 @@ static void smsc911x_tx_update_txcounters(struct net_device *dev)
* does not reference a hardware defined reserved bit
* but rather a driver defined one.
*/
- SMSC_WARNING(HW,
- "Packet tag reserved bit is high");
+ SMSC_WARN(pdata, hw, "Packet tag reserved bit is high");
} else {
if (unlikely(tx_stat & TX_STS_ES_)) {
dev->stats.tx_errors++;
@@ -977,8 +1097,8 @@ smsc911x_rx_fastforward(struct smsc911x_data *pdata, unsigned int pktbytes)
} while ((val & RX_DP_CTRL_RX_FFWD_) && --timeout);
if (unlikely(timeout == 0))
- SMSC_WARNING(HW, "Timed out waiting for "
- "RX FFWD to finish, RX_DP_CTRL: 0x%08X", val);
+ SMSC_WARN(pdata, hw, "Timed out waiting for "
+ "RX FFWD to finish, RX_DP_CTRL: 0x%08X", val);
} else {
unsigned int temp;
while (pktwords--)
@@ -1021,8 +1141,8 @@ static int smsc911x_poll(struct napi_struct *napi, int budget)
smsc911x_rx_counterrors(dev, rxstat);
if (unlikely(rxstat & RX_STS_ES_)) {
- SMSC_WARNING(RX_ERR,
- "Discarding packet with error bit set");
+ SMSC_WARN(pdata, rx_err,
+ "Discarding packet with error bit set");
/* Packet has an error, discard it and continue with
* the next */
smsc911x_rx_fastforward(pdata, pktwords);
@@ -1032,8 +1152,8 @@ static int smsc911x_poll(struct napi_struct *napi, int budget)
skb = netdev_alloc_skb(dev, pktlength + NET_IP_ALIGN);
if (unlikely(!skb)) {
- SMSC_WARNING(RX_ERR,
- "Unable to allocate skb for rx packet");
+ SMSC_WARN(pdata, rx_err,
+ "Unable to allocate skb for rx packet");
/* Drop the packet and stop this polling iteration */
smsc911x_rx_fastforward(pdata, pktwords);
dev->stats.rx_dropped++;
@@ -1046,8 +1166,8 @@ static int smsc911x_poll(struct napi_struct *napi, int budget)
/* Align IP on 16B boundary */
skb_reserve(skb, NET_IP_ALIGN);
skb_put(skb, pktlength - 4);
- smsc911x_rx_readfifo(pdata, (unsigned int *)skb->head,
- pktwords);
+ pdata->ops->rx_readfifo(pdata,
+ (unsigned int *)skb->head, pktwords);
skb->protocol = eth_type_trans(skb, dev);
skb_checksum_none_assert(skb);
netif_receive_skb(skb);
@@ -1083,8 +1203,8 @@ static void smsc911x_rx_multicast_update(struct smsc911x_data *pdata)
smsc911x_mac_write(pdata, MAC_CR, mac_cr);
smsc911x_mac_write(pdata, HASHH, pdata->hashhi);
smsc911x_mac_write(pdata, HASHL, pdata->hashlo);
- SMSC_TRACE(HW, "maccr 0x%08X, HASHH 0x%08X, HASHL 0x%08X",
- mac_cr, pdata->hashhi, pdata->hashlo);
+ SMSC_TRACE(pdata, hw, "maccr 0x%08X, HASHH 0x%08X, HASHL 0x%08X",
+ mac_cr, pdata->hashhi, pdata->hashlo);
}
static void smsc911x_rx_multicast_update_workaround(struct smsc911x_data *pdata)
@@ -1102,7 +1222,7 @@ static void smsc911x_rx_multicast_update_workaround(struct smsc911x_data *pdata)
/* Check Rx has stopped */
if (smsc911x_mac_read(pdata, MAC_CR) & MAC_CR_RXEN_)
- SMSC_WARNING(DRV, "Rx not stopped");
+ SMSC_WARN(pdata, drv, "Rx not stopped");
/* Perform the update - safe to do now Rx has stopped */
smsc911x_rx_multicast_update(pdata);
@@ -1131,7 +1251,7 @@ static int smsc911x_soft_reset(struct smsc911x_data *pdata)
} while ((--timeout) && (temp & HW_CFG_SRST_));
if (unlikely(temp & HW_CFG_SRST_)) {
- SMSC_WARNING(DRV, "Failed to complete reset");
+ SMSC_WARN(pdata, drv, "Failed to complete reset");
return -EIO;
}
return 0;
@@ -1160,18 +1280,18 @@ static int smsc911x_open(struct net_device *dev)
/* if the phy is not yet registered, retry later*/
if (!pdata->phy_dev) {
- SMSC_WARNING(HW, "phy_dev is NULL");
+ SMSC_WARN(pdata, hw, "phy_dev is NULL");
return -EAGAIN;
}
if (!is_valid_ether_addr(dev->dev_addr)) {
- SMSC_WARNING(HW, "dev_addr is not a valid MAC address");
+ SMSC_WARN(pdata, hw, "dev_addr is not a valid MAC address");
return -EADDRNOTAVAIL;
}
/* Reset the LAN911x */
if (smsc911x_soft_reset(pdata)) {
- SMSC_WARNING(HW, "soft reset failed");
+ SMSC_WARN(pdata, hw, "soft reset failed");
return -EIO;
}
@@ -1191,8 +1311,8 @@ static int smsc911x_open(struct net_device *dev)
}
if (unlikely(timeout == 0))
- SMSC_WARNING(IFUP,
- "Timed out waiting for EEPROM busy bit to clear");
+ SMSC_WARN(pdata, ifup,
+ "Timed out waiting for EEPROM busy bit to clear");
smsc911x_reg_write(pdata, GPIO_CFG, 0x70070000);
@@ -1210,22 +1330,22 @@ static int smsc911x_open(struct net_device *dev)
intcfg = ((10 << 24) | INT_CFG_IRQ_EN_);
if (pdata->config.irq_polarity) {
- SMSC_TRACE(IFUP, "irq polarity: active high");
+ SMSC_TRACE(pdata, ifup, "irq polarity: active high");
intcfg |= INT_CFG_IRQ_POL_;
} else {
- SMSC_TRACE(IFUP, "irq polarity: active low");
+ SMSC_TRACE(pdata, ifup, "irq polarity: active low");
}
if (pdata->config.irq_type) {
- SMSC_TRACE(IFUP, "irq type: push-pull");
+ SMSC_TRACE(pdata, ifup, "irq type: push-pull");
intcfg |= INT_CFG_IRQ_TYPE_;
} else {
- SMSC_TRACE(IFUP, "irq type: open drain");
+ SMSC_TRACE(pdata, ifup, "irq type: open drain");
}
smsc911x_reg_write(pdata, INT_CFG, intcfg);
- SMSC_TRACE(IFUP, "Testing irq handler using IRQ %d", dev->irq);
+ SMSC_TRACE(pdata, ifup, "Testing irq handler using IRQ %d", dev->irq);
pdata->software_irq_signal = 0;
smp_wmb();
@@ -1241,14 +1361,15 @@ static int smsc911x_open(struct net_device *dev)
}
if (!pdata->software_irq_signal) {
- dev_warn(&dev->dev, "ISR failed signaling test (IRQ %d)\n",
- dev->irq);
+ netdev_warn(dev, "ISR failed signaling test (IRQ %d)\n",
+ dev->irq);
return -ENODEV;
}
- SMSC_TRACE(IFUP, "IRQ handler passed test using IRQ %d", dev->irq);
+ SMSC_TRACE(pdata, ifup, "IRQ handler passed test using IRQ %d",
+ dev->irq);
- dev_info(&dev->dev, "SMSC911x/921x identified at %#08lx, IRQ: %d\n",
- (unsigned long)pdata->ioaddr, dev->irq);
+ netdev_info(dev, "SMSC911x/921x identified at %#08lx, IRQ: %d\n",
+ (unsigned long)pdata->ioaddr, dev->irq);
/* Reset the last known duplex and carrier */
pdata->last_duplex = -1;
@@ -1313,7 +1434,7 @@ static int smsc911x_stop(struct net_device *dev)
if (pdata->phy_dev)
phy_stop(pdata->phy_dev);
- SMSC_TRACE(IFDOWN, "Interface stopped");
+ SMSC_TRACE(pdata, ifdown, "Interface stopped");
return 0;
}
@@ -1331,8 +1452,8 @@ static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
freespace = smsc911x_reg_read(pdata, TX_FIFO_INF) & TX_FIFO_INF_TDFREE_;
if (unlikely(freespace < TX_FIFO_LOW_THRESHOLD))
- SMSC_WARNING(TX_ERR,
- "Tx data fifo low, space available: %d", freespace);
+ SMSC_WARN(pdata, tx_err,
+ "Tx data fifo low, space available: %d", freespace);
/* Word alignment adjustment */
tx_cmd_a = (u32)((ulong)skb->data & 0x03) << 16;
@@ -1350,7 +1471,7 @@ static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
wrsz += (u32)((ulong)skb->data & 0x3);
wrsz >>= 2;
- smsc911x_tx_writefifo(pdata, (unsigned int *)bufp, wrsz);
+ pdata->ops->tx_writefifo(pdata, (unsigned int *)bufp, wrsz);
freespace -= (skb->len + 32);
dev_kfree_skb(skb);
@@ -1432,7 +1553,7 @@ static void smsc911x_set_multicast_list(struct net_device *dev)
* receiving data */
if (!pdata->multicast_update_pending) {
unsigned int temp;
- SMSC_TRACE(HW, "scheduling mcast update");
+ SMSC_TRACE(pdata, hw, "scheduling mcast update");
pdata->multicast_update_pending = 1;
/* Request the hardware to stop, then perform the
@@ -1474,7 +1595,7 @@ static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id)
if (unlikely(intsts & inten & INT_STS_RXSTOP_INT_)) {
/* Called when there is a multicast update scheduled and
* it is now safe to complete the update */
- SMSC_TRACE(INTR, "RX Stop interrupt");
+ SMSC_TRACE(pdata, intr, "RX Stop interrupt");
smsc911x_reg_write(pdata, INT_STS, INT_STS_RXSTOP_INT_);
if (pdata->multicast_update_pending)
smsc911x_rx_multicast_update_workaround(pdata);
@@ -1491,7 +1612,7 @@ static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id)
}
if (unlikely(intsts & inten & INT_STS_RXE_)) {
- SMSC_TRACE(INTR, "RX Error interrupt");
+ SMSC_TRACE(pdata, intr, "RX Error interrupt");
smsc911x_reg_write(pdata, INT_STS, INT_STS_RXE_);
serviced = IRQ_HANDLED;
}
@@ -1505,8 +1626,7 @@ static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id)
/* Schedule a NAPI poll */
__napi_schedule(&pdata->napi);
} else {
- SMSC_WARNING(RX_ERR,
- "napi_schedule_prep failed");
+ SMSC_WARN(pdata, rx_err, "napi_schedule_prep failed");
}
serviced = IRQ_HANDLED;
}
@@ -1543,7 +1663,7 @@ static int smsc911x_set_mac_address(struct net_device *dev, void *p)
smsc911x_set_hw_mac_address(pdata, dev->dev_addr);
spin_unlock_irq(&pdata->mac_lock);
- dev_info(&dev->dev, "MAC Address: %pM\n", dev->dev_addr);
+ netdev_info(dev, "MAC Address: %pM\n", dev->dev_addr);
return 0;
}
@@ -1649,9 +1769,9 @@ static int smsc911x_eeprom_send_cmd(struct smsc911x_data *pdata, u32 op)
int timeout = 100;
u32 e2cmd;
- SMSC_TRACE(DRV, "op 0x%08x", op);
+ SMSC_TRACE(pdata, drv, "op 0x%08x", op);
if (smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_) {
- SMSC_WARNING(DRV, "Busy at start");
+ SMSC_WARN(pdata, drv, "Busy at start");
return -EBUSY;
}
@@ -1664,12 +1784,12 @@ static int smsc911x_eeprom_send_cmd(struct smsc911x_data *pdata, u32 op)
} while ((e2cmd & E2P_CMD_EPC_BUSY_) && (--timeout));
if (!timeout) {
- SMSC_TRACE(DRV, "TIMED OUT");
+ SMSC_TRACE(pdata, drv, "TIMED OUT");
return -EAGAIN;
}
if (e2cmd & E2P_CMD_EPC_TIMEOUT_) {
- SMSC_TRACE(DRV, "Error occurred during eeprom operation");
+ SMSC_TRACE(pdata, drv, "Error occurred during eeprom operation");
return -EINVAL;
}
@@ -1682,7 +1802,7 @@ static int smsc911x_eeprom_read_location(struct smsc911x_data *pdata,
u32 op = E2P_CMD_EPC_CMD_READ_ | address;
int ret;
- SMSC_TRACE(DRV, "address 0x%x", address);
+ SMSC_TRACE(pdata, drv, "address 0x%x", address);
ret = smsc911x_eeprom_send_cmd(pdata, op);
if (!ret)
@@ -1698,7 +1818,7 @@ static int smsc911x_eeprom_write_location(struct smsc911x_data *pdata,
u32 temp;
int ret;
- SMSC_TRACE(DRV, "address 0x%x, data 0x%x", address, data);
+ SMSC_TRACE(pdata, drv, "address 0x%x, data 0x%x", address, data);
ret = smsc911x_eeprom_send_cmd(pdata, op);
if (!ret) {
@@ -1811,26 +1931,26 @@ static int __devinit smsc911x_init(struct net_device *dev)
struct smsc911x_data *pdata = netdev_priv(dev);
unsigned int byte_test;
- SMSC_TRACE(PROBE, "Driver Parameters:");
- SMSC_TRACE(PROBE, "LAN base: 0x%08lX",
- (unsigned long)pdata->ioaddr);
- SMSC_TRACE(PROBE, "IRQ: %d", dev->irq);
- SMSC_TRACE(PROBE, "PHY will be autodetected.");
+ SMSC_TRACE(pdata, probe, "Driver Parameters:");
+ SMSC_TRACE(pdata, probe, "LAN base: 0x%08lX",
+ (unsigned long)pdata->ioaddr);
+ SMSC_TRACE(pdata, probe, "IRQ: %d", dev->irq);
+ SMSC_TRACE(pdata, probe, "PHY will be autodetected.");
spin_lock_init(&pdata->dev_lock);
spin_lock_init(&pdata->mac_lock);
if (pdata->ioaddr == 0) {
- SMSC_WARNING(PROBE, "pdata->ioaddr: 0x00000000");
+ SMSC_WARN(pdata, probe, "pdata->ioaddr: 0x00000000");
return -ENODEV;
}
/* Check byte ordering */
byte_test = smsc911x_reg_read(pdata, BYTE_TEST);
- SMSC_TRACE(PROBE, "BYTE_TEST: 0x%08X", byte_test);
+ SMSC_TRACE(pdata, probe, "BYTE_TEST: 0x%08X", byte_test);
if (byte_test == 0x43218765) {
- SMSC_TRACE(PROBE, "BYTE_TEST looks swapped, "
- "applying WORD_SWAP");
+ SMSC_TRACE(pdata, probe, "BYTE_TEST looks swapped, "
+ "applying WORD_SWAP");
smsc911x_reg_write(pdata, WORD_SWAP, 0xffffffff);
/* 1 dummy read of BYTE_TEST is needed after a write to
@@ -1841,12 +1961,13 @@ static int __devinit smsc911x_init(struct net_device *dev)
}
if (byte_test != 0x87654321) {
- SMSC_WARNING(DRV, "BYTE_TEST: 0x%08X", byte_test);
+ SMSC_WARN(pdata, drv, "BYTE_TEST: 0x%08X", byte_test);
if (((byte_test >> 16) & 0xFFFF) == (byte_test & 0xFFFF)) {
- SMSC_WARNING(PROBE,
- "top 16 bits equal to bottom 16 bits");
- SMSC_TRACE(PROBE, "This may mean the chip is set "
- "for 32 bit while the bus is reading 16 bit");
+ SMSC_WARN(pdata, probe,
+ "top 16 bits equal to bottom 16 bits");
+ SMSC_TRACE(pdata, probe,
+ "This may mean the chip is set "
+ "for 32 bit while the bus is reading 16 bit");
}
return -ENODEV;
}
@@ -1881,17 +2002,18 @@ static int __devinit smsc911x_init(struct net_device *dev)
break;
default:
- SMSC_WARNING(PROBE, "LAN911x not identified, idrev: 0x%08X",
- pdata->idrev);
+ SMSC_WARN(pdata, probe, "LAN911x not identified, idrev: 0x%08X",
+ pdata->idrev);
return -ENODEV;
}
- SMSC_TRACE(PROBE, "LAN911x identified, idrev: 0x%08X, generation: %d",
- pdata->idrev, pdata->generation);
+ SMSC_TRACE(pdata, probe,
+ "LAN911x identified, idrev: 0x%08X, generation: %d",
+ pdata->idrev, pdata->generation);
if (pdata->generation == 0)
- SMSC_WARNING(PROBE,
- "This driver is not intended for this chip revision");
+ SMSC_WARN(pdata, probe,
+ "This driver is not intended for this chip revision");
/* workaround for platforms without an eeprom, where the mac address
* is stored elsewhere and set by the bootloader. This saves the
@@ -1931,7 +2053,7 @@ static int __devexit smsc911x_drv_remove(struct platform_device *pdev)
BUG_ON(!pdata->ioaddr);
BUG_ON(!pdata->phy_dev);
- SMSC_TRACE(IFDOWN, "Stopping driver.");
+ SMSC_TRACE(pdata, ifdown, "Stopping driver");
phy_disconnect(pdata->phy_dev);
pdata->phy_dev = NULL;
@@ -1955,6 +2077,22 @@ static int __devexit smsc911x_drv_remove(struct platform_device *pdev)
return 0;
}
+/* standard register acces */
+static const struct smsc911x_ops standard_smsc911x_ops = {
+ .reg_read = __smsc911x_reg_read,
+ .reg_write = __smsc911x_reg_write,
+ .rx_readfifo = smsc911x_rx_readfifo,
+ .tx_writefifo = smsc911x_tx_writefifo,
+};
+
+/* shifted register access */
+static const struct smsc911x_ops shifted_smsc911x_ops = {
+ .reg_read = __smsc911x_reg_read_shift,
+ .reg_write = __smsc911x_reg_write_shift,
+ .rx_readfifo = smsc911x_rx_readfifo_shift,
+ .tx_writefifo = smsc911x_tx_writefifo_shift,
+};
+
static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
{
struct net_device *dev;
@@ -1965,11 +2103,11 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
int res_size, irq_flags;
int retval;
- pr_info("%s: Driver version %s.\n", SMSC_CHIPNAME, SMSC_DRV_VERSION);
+ pr_info("Driver version %s\n", SMSC_DRV_VERSION);
/* platform data specifies irq & dynamic bus configuration */
if (!pdev->dev.platform_data) {
- pr_warning("%s: platform_data not provided\n", SMSC_CHIPNAME);
+ pr_warn("platform_data not provided\n");
retval = -ENODEV;
goto out_0;
}
@@ -1979,8 +2117,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
if (!res)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
- pr_warning("%s: Could not allocate resource.\n",
- SMSC_CHIPNAME);
+ pr_warn("Could not allocate resource\n");
retval = -ENODEV;
goto out_0;
}
@@ -1988,8 +2125,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq_res) {
- pr_warning("%s: Could not allocate irq resource.\n",
- SMSC_CHIPNAME);
+ pr_warn("Could not allocate irq resource\n");
retval = -ENODEV;
goto out_0;
}
@@ -2001,7 +2137,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
dev = alloc_etherdev(sizeof(struct smsc911x_data));
if (!dev) {
- pr_warning("%s: Could not allocate device.\n", SMSC_CHIPNAME);
+ pr_warn("Could not allocate device\n");
retval = -ENOMEM;
goto out_release_io_1;
}
@@ -2021,12 +2157,17 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
pdata->msg_enable = ((1 << debug) - 1);
if (pdata->ioaddr == NULL) {
- SMSC_WARNING(PROBE,
- "Error smsc911x base address invalid");
+ SMSC_WARN(pdata, probe, "Error smsc911x base address invalid");
retval = -ENOMEM;
goto out_free_netdev_2;
}
+ /* assume standard, non-shifted, access to HW registers */
+ pdata->ops = &standard_smsc911x_ops;
+ /* apply the right access if shifting is needed */
+ if (config->shift)
+ pdata->ops = &shifted_smsc911x_ops;
+
retval = smsc911x_init(dev);
if (retval < 0)
goto out_unmap_io_3;
@@ -2047,8 +2188,8 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
retval = request_irq(dev->irq, smsc911x_irqhandler,
irq_flags | IRQF_SHARED, dev->name, dev);
if (retval) {
- SMSC_WARNING(PROBE,
- "Unable to claim requested irq: %d", dev->irq);
+ SMSC_WARN(pdata, probe,
+ "Unable to claim requested irq: %d", dev->irq);
goto out_unmap_io_3;
}
@@ -2056,17 +2197,16 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
retval = register_netdev(dev);
if (retval) {
- SMSC_WARNING(PROBE,
- "Error %i registering device", retval);
+ SMSC_WARN(pdata, probe, "Error %i registering device", retval);
goto out_unset_drvdata_4;
} else {
- SMSC_TRACE(PROBE, "Network interface: \"%s\"", dev->name);
+ SMSC_TRACE(pdata, probe,
+ "Network interface: \"%s\"", dev->name);
}
retval = smsc911x_mii_init(pdev, dev);
if (retval) {
- SMSC_WARNING(PROBE,
- "Error %i initialising mii", retval);
+ SMSC_WARN(pdata, probe, "Error %i initialising mii", retval);
goto out_unregister_netdev_5;
}
@@ -2075,10 +2215,12 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
/* Check if mac address has been specified when bringing interface up */
if (is_valid_ether_addr(dev->dev_addr)) {
smsc911x_set_hw_mac_address(pdata, dev->dev_addr);
- SMSC_TRACE(PROBE, "MAC Address is specified by configuration");
+ SMSC_TRACE(pdata, probe,
+ "MAC Address is specified by configuration");
} else if (is_valid_ether_addr(pdata->config.mac)) {
memcpy(dev->dev_addr, pdata->config.mac, 6);
- SMSC_TRACE(PROBE, "MAC Address specified by platform data");
+ SMSC_TRACE(pdata, probe,
+ "MAC Address specified by platform data");
} else {
/* Try reading mac address from device. if EEPROM is present
* it will already have been set */
@@ -2086,20 +2228,20 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
if (is_valid_ether_addr(dev->dev_addr)) {
/* eeprom values are valid so use them */
- SMSC_TRACE(PROBE,
- "Mac Address is read from LAN911x EEPROM");
+ SMSC_TRACE(pdata, probe,
+ "Mac Address is read from LAN911x EEPROM");
} else {
/* eeprom values are invalid, generate random MAC */
random_ether_addr(dev->dev_addr);
smsc911x_set_hw_mac_address(pdata, dev->dev_addr);
- SMSC_TRACE(PROBE,
- "MAC Address is set to random_ether_addr");
+ SMSC_TRACE(pdata, probe,
+ "MAC Address is set to random_ether_addr");
}
}
spin_unlock_irq(&pdata->mac_lock);
- dev_info(&dev->dev, "MAC Address: %pM\n", dev->dev_addr);
+ netdev_info(dev, "MAC Address: %pM\n", dev->dev_addr);
return 0;
diff --git a/drivers/net/smsc911x.h b/drivers/net/smsc911x.h
index 50f712e99e96..8d67aacf8867 100644
--- a/drivers/net/smsc911x.h
+++ b/drivers/net/smsc911x.h
@@ -33,25 +33,21 @@
* can be successfully looped back */
#define USE_PHY_WORK_AROUND
-#define DPRINTK(nlevel, klevel, fmt, args...) \
- ((void)((NETIF_MSG_##nlevel & pdata->msg_enable) && \
- printk(KERN_##klevel "%s: %s: " fmt "\n", \
- pdata->dev->name, __func__, ## args)))
-
#if USE_DEBUG >= 1
-#define SMSC_WARNING(nlevel, fmt, args...) \
- DPRINTK(nlevel, WARNING, fmt, ## args)
+#define SMSC_WARN(pdata, nlevel, fmt, args...) \
+ netif_warn(pdata, nlevel, (pdata)->dev, \
+ "%s: " fmt "\n", __func__, ##args)
#else
-#define SMSC_WARNING(nlevel, fmt, args...) \
- ({ do {} while (0); 0; })
+#define SMSC_WARN(pdata, nlevel, fmt, args...) \
+ no_printk(fmt "\n", ##args)
#endif
#if USE_DEBUG >= 2
-#define SMSC_TRACE(nlevel, fmt, args...) \
- DPRINTK(nlevel, INFO, fmt, ## args)
+#define SMSC_TRACE(pdata, nlevel, fmt, args...) \
+ netif_info(pdata, nlevel, pdata->dev, fmt "\n", ##args)
#else
-#define SMSC_TRACE(nlevel, fmt, args...) \
- ({ do {} while (0); 0; })
+#define SMSC_TRACE(pdata, nlevel, fmt, args...) \
+ no_printk(fmt "\n", ##args)
#endif
#ifdef CONFIG_DEBUG_SPINLOCK
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index cb6bcca9d541..949f124e1278 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -994,15 +994,13 @@ spider_net_pass_skb_up(struct spider_net_descr *descr,
skb->protocol = eth_type_trans(skb, netdev);
/* checksum offload */
- if (card->options.rx_csum) {
+ skb_checksum_none_assert(skb);
+ if (netdev->features & NETIF_F_RXCSUM) {
if ( ( (data_status & SPIDER_NET_DATA_STATUS_CKSUM_MASK) ==
SPIDER_NET_DATA_STATUS_CKSUM_MASK) &&
!(data_error & SPIDER_NET_DATA_ERR_CKSUM_MASK))
skb->ip_summed = CHECKSUM_UNNECESSARY;
- else
- skb_checksum_none_assert(skb);
- } else
- skb_checksum_none_assert(skb);
+ }
if (data_status & SPIDER_NET_VLAN_PACKET) {
/* further enhancements: HW-accel VLAN
@@ -2322,14 +2320,15 @@ spider_net_setup_netdev(struct spider_net_card *card)
card->aneg_timer.function = spider_net_link_phy;
card->aneg_timer.data = (unsigned long) card;
- card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT;
-
netif_napi_add(netdev, &card->napi,
spider_net_poll, SPIDER_NET_NAPI_WEIGHT);
spider_net_setup_netdev_ops(netdev);
- netdev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX;
+ netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM;
+ if (SPIDER_NET_RX_CSUM_DEFAULT)
+ netdev->features |= NETIF_F_RXCSUM;
+ netdev->features |= NETIF_F_IP_CSUM | NETIF_F_LLTX;
/* some time: NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
* NETIF_F_HW_VLAN_FILTER */
diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h
index 05f74cbdd617..020f64a8fcf7 100644
--- a/drivers/net/spider_net.h
+++ b/drivers/net/spider_net.h
@@ -429,12 +429,6 @@ struct spider_net_descr_chain {
* 701b8000 would be correct, but every packets gets that flag */
#define SPIDER_NET_DESTROY_RX_FLAGS 0x700b8000
-/* this will be bigger some time */
-struct spider_net_options {
- int rx_csum; /* for rx: if 0 ip_summed=NONE,
- if 1 and hw has verified, ip_summed=UNNECESSARY */
-};
-
#define SPIDER_NET_DEFAULT_MSG ( NETIF_MSG_DRV | \
NETIF_MSG_PROBE | \
NETIF_MSG_LINK | \
@@ -487,7 +481,6 @@ struct spider_net_card {
/* for ethtool */
int msg_enable;
struct spider_net_extra_stats spider_stats;
- struct spider_net_options options;
/* Must be last item in struct */
struct spider_net_descr darray[0];
diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c
index 5bae728c3820..9c288cd7d171 100644
--- a/drivers/net/spider_net_ethtool.c
+++ b/drivers/net/spider_net_ethtool.c
@@ -58,7 +58,7 @@ spider_net_ethtool_get_settings(struct net_device *netdev,
cmd->advertising = (ADVERTISED_1000baseT_Full |
ADVERTISED_FIBRE);
cmd->port = PORT_FIBRE;
- cmd->speed = card->phy.speed;
+ ethtool_cmd_speed_set(cmd, card->phy.speed);
cmd->duplex = DUPLEX_FULL;
return 0;
@@ -115,24 +115,6 @@ spider_net_ethtool_nway_reset(struct net_device *netdev)
return 0;
}
-static u32
-spider_net_ethtool_get_rx_csum(struct net_device *netdev)
-{
- struct spider_net_card *card = netdev_priv(netdev);
-
- return card->options.rx_csum;
-}
-
-static int
-spider_net_ethtool_set_rx_csum(struct net_device *netdev, u32 n)
-{
- struct spider_net_card *card = netdev_priv(netdev);
-
- card->options.rx_csum = n;
- return 0;
-}
-
-
static void
spider_net_ethtool_get_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ering)
@@ -189,9 +171,6 @@ const struct ethtool_ops spider_net_ethtool_ops = {
.set_msglevel = spider_net_ethtool_set_msglevel,
.get_link = ethtool_op_get_link,
.nway_reset = spider_net_ethtool_nway_reset,
- .get_rx_csum = spider_net_ethtool_get_rx_csum,
- .set_rx_csum = spider_net_ethtool_set_rx_csum,
- .set_tx_csum = ethtool_op_set_tx_csum,
.get_ringparam = spider_net_ethtool_get_ringparam,
.get_strings = spider_net_get_strings,
.get_sset_count = spider_net_get_sset_count,
diff --git a/drivers/net/stmmac/dwmac1000_core.c b/drivers/net/stmmac/dwmac1000_core.c
index 6ae4c3f4c63c..f20455cbfbbc 100644
--- a/drivers/net/stmmac/dwmac1000_core.c
+++ b/drivers/net/stmmac/dwmac1000_core.c
@@ -178,10 +178,11 @@ static void dwmac1000_pmt(void __iomem *ioaddr, unsigned long mode)
{
unsigned int pmt = 0;
- if (mode == WAKE_MAGIC) {
+ if (mode & WAKE_MAGIC) {
CHIP_DBG(KERN_DEBUG "GMAC: WOL Magic frame\n");
pmt |= power_down | magic_pkt_en;
- } else if (mode == WAKE_UCAST) {
+ }
+ if (mode & WAKE_UCAST) {
CHIP_DBG(KERN_DEBUG "GMAC: WOL on global unicast\n");
pmt |= global_unicast;
}
diff --git a/drivers/net/stmmac/stmmac.h b/drivers/net/stmmac/stmmac.h
index 5f06c4706abe..2b076b313622 100644
--- a/drivers/net/stmmac/stmmac.h
+++ b/drivers/net/stmmac/stmmac.h
@@ -21,7 +21,6 @@
*******************************************************************************/
#define DRV_MODULE_VERSION "Nov_2010"
-#include <linux/platform_device.h>
#include <linux/stmmac.h>
#include "common.h"
diff --git a/drivers/net/stmmac/stmmac_ethtool.c b/drivers/net/stmmac/stmmac_ethtool.c
index fd719edc7f7c..ae5213a8c4cd 100644
--- a/drivers/net/stmmac/stmmac_ethtool.c
+++ b/drivers/net/stmmac/stmmac_ethtool.c
@@ -197,13 +197,6 @@ static void stmmac_ethtool_gregs(struct net_device *dev,
}
}
-static u32 stmmac_ethtool_get_rx_csum(struct net_device *dev)
-{
- struct stmmac_priv *priv = netdev_priv(dev);
-
- return priv->rx_coe;
-}
-
static void
stmmac_get_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause)
@@ -241,20 +234,11 @@ stmmac_set_pauseparam(struct net_device *netdev,
new_pause |= FLOW_TX;
priv->flow_ctrl = new_pause;
+ phy->autoneg = pause->autoneg;
if (phy->autoneg) {
- if (netif_running(netdev)) {
- struct ethtool_cmd cmd;
- /* auto-negotiation automatically restarted */
- cmd.cmd = ETHTOOL_NWAY_RST;
- cmd.supported = phy->supported;
- cmd.advertising = phy->advertising;
- cmd.autoneg = phy->autoneg;
- cmd.speed = phy->speed;
- cmd.duplex = phy->duplex;
- cmd.phy_address = phy->addr;
- ret = phy_ethtool_sset(phy, &cmd);
- }
+ if (netif_running(netdev))
+ ret = phy_start_aneg(phy);
} else
priv->hw->mac->flow_ctrl(priv->ioaddr, phy->duplex,
priv->flow_ctrl, priv->pause);
@@ -315,7 +299,7 @@ static void stmmac_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
spin_lock_irq(&priv->lock);
if (device_can_wakeup(priv->device)) {
- wol->supported = WAKE_MAGIC;
+ wol->supported = WAKE_MAGIC | WAKE_UCAST;
wol->wolopts = priv->wolopts;
}
spin_unlock_irq(&priv->lock);
@@ -324,7 +308,7 @@ static void stmmac_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct stmmac_priv *priv = netdev_priv(dev);
- u32 support = WAKE_MAGIC;
+ u32 support = WAKE_MAGIC | WAKE_UCAST;
if (!device_can_wakeup(priv->device))
return -EINVAL;
@@ -358,11 +342,6 @@ static struct ethtool_ops stmmac_ethtool_ops = {
.get_regs = stmmac_ethtool_gregs,
.get_regs_len = stmmac_ethtool_get_regs_len,
.get_link = ethtool_op_get_link,
- .get_rx_csum = stmmac_ethtool_get_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = ethtool_op_set_tx_ipv6_csum,
- .get_sg = ethtool_op_get_sg,
- .set_sg = ethtool_op_set_sg,
.get_pauseparam = stmmac_get_pauseparam,
.set_pauseparam = stmmac_set_pauseparam,
.get_ethtool_stats = stmmac_get_ethtool_stats,
@@ -370,8 +349,6 @@ static struct ethtool_ops stmmac_ethtool_ops = {
.get_wol = stmmac_get_wol,
.set_wol = stmmac_set_wol,
.get_sset_count = stmmac_get_sset_count,
- .get_tso = ethtool_op_get_tso,
- .set_tso = ethtool_op_set_tso,
};
void stmmac_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c
index cc973fc38405..e25e44a45c28 100644
--- a/drivers/net/stmmac/stmmac_main.c
+++ b/drivers/net/stmmac/stmmac_main.c
@@ -45,6 +45,7 @@
#include <linux/if_vlan.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
+#include <linux/prefetch.h>
#include "stmmac.h"
#define STMMAC_RESOURCE_NAME "stmmaceth"
@@ -116,9 +117,6 @@ static int tc = TC_DEFAULT;
module_param(tc, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(tc, "DMA threshold control value");
-#define RX_NO_COALESCE 1 /* Always interrupt on completion */
-#define TX_NO_COALESCE -1 /* No moderation by default */
-
/* Pay attention to tune this parameter; take care of both
* hardware capability and network stabitily/performance impact.
* Many tests showed that ~4ms latency seems to be good enough. */
@@ -139,7 +137,6 @@ static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE |
NETIF_MSG_IFDOWN | NETIF_MSG_TIMER);
static irqreturn_t stmmac_interrupt(int irq, void *dev_id);
-static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev);
/**
* stmmac_verify_args - verify the driver parameters.
@@ -831,6 +828,7 @@ static int stmmac_open(struct net_device *dev)
pr_info("stmmac: Rx Checksum Offload Engine supported\n");
if (priv->plat->tx_coe)
pr_info("\tTX Checksum insertion supported\n");
+ netdev_update_features(dev);
/* Initialise the MMC (if present) to disable all interrupts. */
writel(0xffffffff, priv->ioaddr + MMC_HIGH_INTR_MASK);
@@ -934,46 +932,6 @@ static int stmmac_release(struct net_device *dev)
return 0;
}
-/*
- * To perform emulated hardware segmentation on skb.
- */
-static int stmmac_sw_tso(struct stmmac_priv *priv, struct sk_buff *skb)
-{
- struct sk_buff *segs, *curr_skb;
- int gso_segs = skb_shinfo(skb)->gso_segs;
-
- /* Estimate the number of fragments in the worst case */
- if (unlikely(stmmac_tx_avail(priv) < gso_segs)) {
- netif_stop_queue(priv->dev);
- TX_DBG(KERN_ERR "%s: TSO BUG! Tx Ring full when queue awake\n",
- __func__);
- if (stmmac_tx_avail(priv) < gso_segs)
- return NETDEV_TX_BUSY;
-
- netif_wake_queue(priv->dev);
- }
- TX_DBG("\tstmmac_sw_tso: segmenting: skb %p (len %d)\n",
- skb, skb->len);
-
- segs = skb_gso_segment(skb, priv->dev->features & ~NETIF_F_TSO);
- if (IS_ERR(segs))
- goto sw_tso_end;
-
- do {
- curr_skb = segs;
- segs = segs->next;
- TX_DBG("\t\tcurrent skb->len: %d, *curr %p,"
- "*next %p\n", curr_skb->len, curr_skb, segs);
- curr_skb->next = NULL;
- stmmac_xmit(curr_skb, priv->dev);
- } while (segs);
-
-sw_tso_end:
- dev_kfree_skb(skb);
-
- return NETDEV_TX_OK;
-}
-
static unsigned int stmmac_handle_jumbo_frames(struct sk_buff *skb,
struct net_device *dev,
int csum_insertion)
@@ -1051,16 +1009,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
!skb_is_gso(skb) ? "isn't" : "is");
#endif
- if (unlikely(skb_is_gso(skb)))
- return stmmac_sw_tso(priv, skb);
-
- if (likely((skb->ip_summed == CHECKSUM_PARTIAL))) {
- if (unlikely((!priv->plat->tx_coe) ||
- (priv->no_csum_insertion)))
- skb_checksum_help(skb);
- else
- csum_insertion = 1;
- }
+ csum_insertion = (skb->ip_summed == CHECKSUM_PARTIAL);
desc = priv->dma_tx + entry;
first = desc;
@@ -1380,18 +1329,29 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu)
return -EINVAL;
}
+ dev->mtu = new_mtu;
+ netdev_update_features(dev);
+
+ return 0;
+}
+
+static u32 stmmac_fix_features(struct net_device *dev, u32 features)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+
+ if (!priv->rx_coe)
+ features &= ~NETIF_F_RXCSUM;
+ if (!priv->plat->tx_coe)
+ features &= ~NETIF_F_ALL_CSUM;
+
/* Some GMAC devices have a bugged Jumbo frame support that
* needs to have the Tx COE disabled for oversized frames
* (due to limited buffer sizes). In this case we disable
* the TX csum insertionin the TDES and not use SF. */
- if ((priv->plat->bugged_jumbo) && (priv->dev->mtu > ETH_DATA_LEN))
- priv->no_csum_insertion = 1;
- else
- priv->no_csum_insertion = 0;
+ if (priv->plat->bugged_jumbo && (dev->mtu > ETH_DATA_LEN))
+ features &= ~NETIF_F_ALL_CSUM;
- dev->mtu = new_mtu;
-
- return 0;
+ return features;
}
static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
@@ -1471,6 +1431,7 @@ static const struct net_device_ops stmmac_netdev_ops = {
.ndo_start_xmit = stmmac_xmit,
.ndo_stop = stmmac_release,
.ndo_change_mtu = stmmac_change_mtu,
+ .ndo_fix_features = stmmac_fix_features,
.ndo_set_multicast_list = stmmac_multicast_list,
.ndo_tx_timeout = stmmac_tx_timeout,
.ndo_do_ioctl = stmmac_ioctl,
@@ -1501,8 +1462,8 @@ static int stmmac_probe(struct net_device *dev)
dev->netdev_ops = &stmmac_netdev_ops;
stmmac_set_ethtool_ops(dev);
- dev->features |= NETIF_F_SG | NETIF_F_HIGHDMA |
- NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+ dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+ dev->features |= dev->hw_features | NETIF_F_HIGHDMA;
dev->watchdog_timeo = msecs_to_jiffies(watchdog);
#ifdef STMMAC_VLAN_TAG_USED
/* Both mac100 and gmac support receive VLAN tag detection */
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index d3be735c4719..ab5930099267 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -1294,7 +1294,7 @@ static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep)
autoneg = 1;
} else {
autoneg = 0;
- speed = ep->speed;
+ speed = ethtool_cmd_speed(ep);
duplex = ep->duplex;
}
@@ -2642,7 +2642,7 @@ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
/* Return current PHY settings */
spin_lock_irq(&gp->lock);
cmd->autoneg = gp->want_autoneg;
- cmd->speed = gp->phy_mii.speed;
+ ethtool_cmd_speed_set(cmd, gp->phy_mii.speed);
cmd->duplex = gp->phy_mii.duplex;
cmd->advertising = gp->phy_mii.advertising;
@@ -2659,7 +2659,7 @@ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
SUPPORTED_Autoneg);
cmd->advertising = cmd->supported;
- cmd->speed = 0;
+ ethtool_cmd_speed_set(cmd, 0);
cmd->duplex = cmd->port = cmd->phy_address =
cmd->transceiver = cmd->autoneg = 0;
@@ -2673,7 +2673,7 @@ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->advertising = cmd->supported;
cmd->transceiver = XCVR_INTERNAL;
if (gp->lstate == link_up)
- cmd->speed = SPEED_1000;
+ ethtool_cmd_speed_set(cmd, SPEED_1000);
cmd->duplex = DUPLEX_FULL;
cmd->autoneg = 1;
}
@@ -2686,6 +2686,7 @@ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
static int gem_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct gem *gp = netdev_priv(dev);
+ u32 speed = ethtool_cmd_speed(cmd);
/* Verify the settings we care about. */
if (cmd->autoneg != AUTONEG_ENABLE &&
@@ -2697,9 +2698,9 @@ static int gem_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
return -EINVAL;
if (cmd->autoneg == AUTONEG_DISABLE &&
- ((cmd->speed != SPEED_1000 &&
- cmd->speed != SPEED_100 &&
- cmd->speed != SPEED_10) ||
+ ((speed != SPEED_1000 &&
+ speed != SPEED_100 &&
+ speed != SPEED_10) ||
(cmd->duplex != DUPLEX_HALF &&
cmd->duplex != DUPLEX_FULL)))
return -EINVAL;
@@ -3146,7 +3147,8 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
gp->phy_mii.def ? gp->phy_mii.def->name : "no");
/* GEM can do it all... */
- dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_LLTX;
+ dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM;
+ dev->features |= dev->hw_features | NETIF_F_RXCSUM | NETIF_F_LLTX;
if (pci_using_dac)
dev->features |= NETIF_F_HIGHDMA;
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index bff2f7999ff0..30aad54b1b3a 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -1383,7 +1383,7 @@ force_link:
if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) {
hp->sw_bmcr = BMCR_SPEED100;
} else {
- if (ep->speed == SPEED_100)
+ if (ethtool_cmd_speed(ep) == SPEED_100)
hp->sw_bmcr = BMCR_SPEED100;
else
hp->sw_bmcr = 0;
@@ -2401,6 +2401,7 @@ static void happy_meal_set_multicast(struct net_device *dev)
static int hme_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct happy_meal *hp = netdev_priv(dev);
+ u32 speed;
cmd->supported =
(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
@@ -2420,10 +2421,9 @@ static int hme_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
if (hp->sw_bmcr & BMCR_ANENABLE) {
cmd->autoneg = AUTONEG_ENABLE;
- cmd->speed =
- (hp->sw_lpa & (LPA_100HALF | LPA_100FULL)) ?
- SPEED_100 : SPEED_10;
- if (cmd->speed == SPEED_100)
+ speed = ((hp->sw_lpa & (LPA_100HALF | LPA_100FULL)) ?
+ SPEED_100 : SPEED_10);
+ if (speed == SPEED_100)
cmd->duplex =
(hp->sw_lpa & (LPA_100FULL)) ?
DUPLEX_FULL : DUPLEX_HALF;
@@ -2433,13 +2433,12 @@ static int hme_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
DUPLEX_FULL : DUPLEX_HALF;
} else {
cmd->autoneg = AUTONEG_DISABLE;
- cmd->speed =
- (hp->sw_bmcr & BMCR_SPEED100) ?
- SPEED_100 : SPEED_10;
+ speed = (hp->sw_bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10;
cmd->duplex =
(hp->sw_bmcr & BMCR_FULLDPLX) ?
DUPLEX_FULL : DUPLEX_HALF;
}
+ ethtool_cmd_speed_set(cmd, speed);
return 0;
}
@@ -2452,8 +2451,8 @@ static int hme_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->autoneg != AUTONEG_DISABLE)
return -EINVAL;
if (cmd->autoneg == AUTONEG_DISABLE &&
- ((cmd->speed != SPEED_100 &&
- cmd->speed != SPEED_10) ||
+ ((ethtool_cmd_speed(cmd) != SPEED_100 &&
+ ethtool_cmd_speed(cmd) != SPEED_10) ||
(cmd->duplex != DUPLEX_HALF &&
cmd->duplex != DUPLEX_FULL)))
return -EINVAL;
@@ -2788,7 +2787,8 @@ static int __devinit happy_meal_sbus_probe_one(struct platform_device *op, int i
dev->ethtool_ops = &hme_ethtool_ops;
/* Happy Meal can do it all... */
- dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
+ dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM;
+ dev->features |= dev->hw_features | NETIF_F_RXCSUM;
dev->irq = op->archdata.irqs[0];
@@ -3113,7 +3113,8 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
dev->dma = 0;
/* Happy Meal can do it all... */
- dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
+ dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM;
+ dev->features |= dev->hw_features | NETIF_F_RXCSUM;
#if defined(CONFIG_SBUS) && defined(CONFIG_PCI)
/* Hook up PCI register/descriptor accessors. */
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index 7ca51cebcddd..4a55a162dfe6 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -47,6 +47,7 @@ static const char *version = "tc35815.c:v" DRV_VERSION "\n";
#include <linux/phy.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
+#include <linux/prefetch.h>
#include <asm/io.h>
#include <asm/byteorder.h>
diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c
index 8564ec5cfb7f..80fbee0d40af 100644
--- a/drivers/net/tehuti.c
+++ b/drivers/net/tehuti.c
@@ -2017,9 +2017,11 @@ bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ndev->irq = pdev->irq;
ndev->features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO
| NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
- NETIF_F_HW_VLAN_FILTER
+ NETIF_F_HW_VLAN_FILTER | NETIF_F_RXCSUM
/*| NETIF_F_FRAGLIST */
;
+ ndev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG |
+ NETIF_F_TSO | NETIF_F_HW_VLAN_TX;
if (pci_using_dac)
ndev->features |= NETIF_F_HIGHDMA;
@@ -2149,7 +2151,7 @@ static int bdx_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
- ecmd->speed = SPEED_10000;
+ ethtool_cmd_speed_set(ecmd, SPEED_10000);
ecmd->duplex = DUPLEX_FULL;
ecmd->port = PORT_FIBRE;
ecmd->transceiver = XCVR_EXTERNAL; /* what does it mean? */
@@ -2188,24 +2190,6 @@ bdx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
}
/*
- * bdx_get_rx_csum - report whether receive checksums are turned on or off
- * @netdev
- */
-static u32 bdx_get_rx_csum(struct net_device *netdev)
-{
- return 1; /* always on */
-}
-
-/*
- * bdx_get_tx_csum - report whether transmit checksums are turned on or off
- * @netdev
- */
-static u32 bdx_get_tx_csum(struct net_device *netdev)
-{
- return (netdev->features & NETIF_F_IP_CSUM) != 0;
-}
-
-/*
* bdx_get_coalesce - get interrupt coalescing parameters
* @netdev
* @ecoal
@@ -2424,10 +2408,6 @@ static void bdx_set_ethtool_ops(struct net_device *netdev)
.set_coalesce = bdx_set_coalesce,
.get_ringparam = bdx_get_ringparam,
.set_ringparam = bdx_set_ringparam,
- .get_rx_csum = bdx_get_rx_csum,
- .get_tx_csum = bdx_get_tx_csum,
- .get_sg = ethtool_op_get_sg,
- .get_tso = ethtool_op_get_tso,
.get_strings = bdx_get_strings,
.get_sset_count = bdx_get_sset_count,
.get_ethtool_stats = bdx_get_ethtool_stats,
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 7a5daefb6f33..f4b01c638a33 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -62,12 +62,36 @@
#include "tg3.h"
+/* Functions & macros to verify TG3_FLAGS types */
+
+static inline int _tg3_flag(enum TG3_FLAGS flag, unsigned long *bits)
+{
+ return test_bit(flag, bits);
+}
+
+static inline void _tg3_flag_set(enum TG3_FLAGS flag, unsigned long *bits)
+{
+ set_bit(flag, bits);
+}
+
+static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits)
+{
+ clear_bit(flag, bits);
+}
+
+#define tg3_flag(tp, flag) \
+ _tg3_flag(TG3_FLAG_##flag, (tp)->tg3_flags)
+#define tg3_flag_set(tp, flag) \
+ _tg3_flag_set(TG3_FLAG_##flag, (tp)->tg3_flags)
+#define tg3_flag_clear(tp, flag) \
+ _tg3_flag_clear(TG3_FLAG_##flag, (tp)->tg3_flags)
+
#define DRV_MODULE_NAME "tg3"
#define TG3_MAJ_NUM 3
-#define TG3_MIN_NUM 117
+#define TG3_MIN_NUM 119
#define DRV_MODULE_VERSION \
__stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM)
-#define DRV_MODULE_RELDATE "January 25, 2011"
+#define DRV_MODULE_RELDATE "May 18, 2011"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -85,26 +109,25 @@
/* length of time before we decide the hardware is borked,
* and dev->tx_timeout() should be called to fix the problem
*/
+
#define TG3_TX_TIMEOUT (5 * HZ)
/* hardware minimum and maximum for a single frame's data payload */
#define TG3_MIN_MTU 60
#define TG3_MAX_MTU(tp) \
- ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) ? 9000 : 1500)
+ (tg3_flag(tp, JUMBO_CAPABLE) ? 9000 : 1500)
/* These numbers seem to be hard coded in the NIC firmware somehow.
* You can't change the ring sizes, but you can change where you place
* them in the NIC onboard memory.
*/
#define TG3_RX_STD_RING_SIZE(tp) \
- ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || \
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) ? \
- RX_STD_MAX_SIZE_5717 : 512)
+ (tg3_flag(tp, LRG_PROD_RING_CAP) ? \
+ TG3_RX_STD_MAX_SIZE_5717 : TG3_RX_STD_MAX_SIZE_5700)
#define TG3_DEF_RX_RING_PENDING 200
#define TG3_RX_JMB_RING_SIZE(tp) \
- ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || \
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) ? \
- 1024 : 256)
+ (tg3_flag(tp, LRG_PROD_RING_CAP) ? \
+ TG3_RX_JMB_MAX_SIZE_5717 : TG3_RX_JMB_MAX_SIZE_5700)
#define TG3_DEF_RX_JUMBO_RING_PENDING 100
#define TG3_RSS_INDIR_TBL_SIZE 128
@@ -167,11 +190,6 @@
#define TG3_RAW_IP_ALIGN 2
-/* number of ETHTOOL_GSTATS u64's */
-#define TG3_NUM_STATS (sizeof(struct tg3_ethtool_stats)/sizeof(u64))
-
-#define TG3_NUM_TEST 6
-
#define TG3_FW_UPDATE_TIMEOUT_SEC 5
#define FIRMWARE_TG3 "tigon/tg3.bin"
@@ -266,6 +284,7 @@ static DEFINE_PCI_DEVICE_TABLE(tg3_pci_tbl) = {
{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_BROADCOM, TG3PCI_DEVICE_TIGON3_5720)},
{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)},
@@ -273,6 +292,7 @@ static DEFINE_PCI_DEVICE_TABLE(tg3_pci_tbl) = {
{PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1003)},
{PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC9100)},
{PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_TIGON3)},
+ {PCI_DEVICE(0x10cf, 0x11a2)}, /* Fujitsu 1000base-SX with BCM5703SKHB */
{}
};
@@ -280,7 +300,7 @@ MODULE_DEVICE_TABLE(pci, tg3_pci_tbl);
static const struct {
const char string[ETH_GSTRING_LEN];
-} ethtool_stats_keys[TG3_NUM_STATS] = {
+} ethtool_stats_keys[] = {
{ "rx_octets" },
{ "rx_fragments" },
{ "rx_ucast_packets" },
@@ -356,12 +376,17 @@ static const struct {
{ "ring_status_update" },
{ "nic_irqs" },
{ "nic_avoided_irqs" },
- { "nic_tx_threshold_hit" }
+ { "nic_tx_threshold_hit" },
+
+ { "mbuf_lwm_thresh_hit" },
};
+#define TG3_NUM_STATS ARRAY_SIZE(ethtool_stats_keys)
+
+
static const struct {
const char string[ETH_GSTRING_LEN];
-} ethtool_test_keys[TG3_NUM_TEST] = {
+} ethtool_test_keys[] = {
{ "nvram test (online) " },
{ "link test (online) " },
{ "register test (offline)" },
@@ -370,6 +395,9 @@ static const struct {
{ "interrupt test (offline)" },
};
+#define TG3_NUM_TEST ARRAY_SIZE(ethtool_test_keys)
+
+
static void tg3_write32(struct tg3 *tp, u32 off, u32 val)
{
writel(val, tp->regs + off);
@@ -467,8 +495,7 @@ static u32 tg3_read_indirect_mbox(struct tg3 *tp, u32 off)
*/
static void _tw32_flush(struct tg3 *tp, u32 off, u32 val, u32 usec_wait)
{
- if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) ||
- (tp->tg3_flags2 & TG3_FLG2_ICH_WORKAROUND))
+ if (tg3_flag(tp, PCIX_TARGET_HWBUG) || tg3_flag(tp, ICH_WORKAROUND))
/* Non-posted methods */
tp->write32(tp, off, val);
else {
@@ -488,8 +515,7 @@ static void _tw32_flush(struct tg3 *tp, u32 off, u32 val, u32 usec_wait)
static inline void tw32_mailbox_flush(struct tg3 *tp, u32 off, u32 val)
{
tp->write32_mbox(tp, off, val);
- if (!(tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) &&
- !(tp->tg3_flags2 & TG3_FLG2_ICH_WORKAROUND))
+ if (!tg3_flag(tp, MBOX_WRITE_REORDER) && !tg3_flag(tp, ICH_WORKAROUND))
tp->read32_mbox(tp, off);
}
@@ -497,9 +523,9 @@ static void tg3_write32_tx_mbox(struct tg3 *tp, u32 off, u32 val)
{
void __iomem *mbox = tp->regs + off;
writel(val, mbox);
- if (tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG)
+ if (tg3_flag(tp, TXD_MBOX_HWBUG))
writel(val, mbox);
- if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+ if (tg3_flag(tp, MBOX_WRITE_REORDER))
readl(mbox);
}
@@ -528,12 +554,12 @@ static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val)
{
unsigned long flags;
- if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) &&
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 &&
(off >= NIC_SRAM_STATS_BLK) && (off < NIC_SRAM_TX_BUFFER_DESC))
return;
spin_lock_irqsave(&tp->indirect_lock, flags);
- if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) {
+ if (tg3_flag(tp, SRAM_USE_CONFIG)) {
pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
@@ -553,14 +579,14 @@ static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val)
{
unsigned long flags;
- if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) &&
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 &&
(off >= NIC_SRAM_STATS_BLK) && (off < NIC_SRAM_TX_BUFFER_DESC)) {
*val = 0;
return;
}
spin_lock_irqsave(&tp->indirect_lock, flags);
- if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) {
+ if (tg3_flag(tp, SRAM_USE_CONFIG)) {
pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
@@ -597,7 +623,7 @@ static int tg3_ape_lock(struct tg3 *tp, int locknum)
int ret = 0;
u32 status, req, gnt;
- if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
+ if (!tg3_flag(tp, ENABLE_APE))
return 0;
switch (locknum) {
@@ -643,7 +669,7 @@ static void tg3_ape_unlock(struct tg3 *tp, int locknum)
{
u32 gnt;
- if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
+ if (!tg3_flag(tp, ENABLE_APE))
return;
switch (locknum) {
@@ -687,14 +713,14 @@ static void tg3_enable_ints(struct tg3 *tp)
struct tg3_napi *tnapi = &tp->napi[i];
tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24);
- if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI)
+ if (tg3_flag(tp, 1SHOT_MSI))
tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24);
tp->coal_now |= tnapi->coal_now;
}
/* Force an initial interrupt */
- if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) &&
+ if (!tg3_flag(tp, TAGGED_STATUS) &&
(tp->napi[0].hw_status->status & SD_STATUS_UPDATED))
tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
else
@@ -710,9 +736,7 @@ static inline unsigned int tg3_has_work(struct tg3_napi *tnapi)
unsigned int work_exists = 0;
/* check for phy events */
- if (!(tp->tg3_flags &
- (TG3_FLAG_USE_LINKCHG_REG |
- TG3_FLAG_POLL_SERDES))) {
+ if (!(tg3_flag(tp, USE_LINKCHG_REG) || tg3_flag(tp, POLL_SERDES))) {
if (sblk->status & SD_STATUS_LINK_CHG)
work_exists = 1;
}
@@ -740,8 +764,7 @@ static void tg3_int_reenable(struct tg3_napi *tnapi)
* The last_tag we write above tells the chip which piece of
* work we've completed.
*/
- if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) &&
- tg3_has_work(tnapi))
+ if (!tg3_flag(tp, TAGGED_STATUS) && tg3_has_work(tnapi))
tw32(HOSTCC_MODE, tp->coalesce_mode |
HOSTCC_MODE_ENABLE | tnapi->coal_now);
}
@@ -751,8 +774,7 @@ static void tg3_switch_clocks(struct tg3 *tp)
u32 clock_ctrl;
u32 orig_clock_ctrl;
- if ((tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) ||
- (tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
+ if (tg3_flag(tp, CPMU_PRESENT) || tg3_flag(tp, 5780_CLASS))
return;
clock_ctrl = tr32(TG3PCI_CLOCK_CTRL);
@@ -763,7 +785,7 @@ static void tg3_switch_clocks(struct tg3 *tp)
0x1f);
tp->pci_clock_ctrl = clock_ctrl;
- if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
+ if (tg3_flag(tp, 5705_PLUS)) {
if (orig_clock_ctrl & CLOCK_CTRL_625_CORE) {
tw32_wait_f(TG3PCI_CLOCK_CTRL,
clock_ctrl | CLOCK_CTRL_625_CORE, 40);
@@ -880,6 +902,104 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
return ret;
}
+static int tg3_phy_cl45_write(struct tg3 *tp, u32 devad, u32 addr, u32 val)
+{
+ int err;
+
+ err = tg3_writephy(tp, MII_TG3_MMD_CTRL, devad);
+ if (err)
+ goto done;
+
+ err = tg3_writephy(tp, MII_TG3_MMD_ADDRESS, addr);
+ if (err)
+ goto done;
+
+ err = tg3_writephy(tp, MII_TG3_MMD_CTRL,
+ MII_TG3_MMD_CTRL_DATA_NOINC | devad);
+ if (err)
+ goto done;
+
+ err = tg3_writephy(tp, MII_TG3_MMD_ADDRESS, val);
+
+done:
+ return err;
+}
+
+static int tg3_phy_cl45_read(struct tg3 *tp, u32 devad, u32 addr, u32 *val)
+{
+ int err;
+
+ err = tg3_writephy(tp, MII_TG3_MMD_CTRL, devad);
+ if (err)
+ goto done;
+
+ err = tg3_writephy(tp, MII_TG3_MMD_ADDRESS, addr);
+ if (err)
+ goto done;
+
+ err = tg3_writephy(tp, MII_TG3_MMD_CTRL,
+ MII_TG3_MMD_CTRL_DATA_NOINC | devad);
+ if (err)
+ goto done;
+
+ err = tg3_readphy(tp, MII_TG3_MMD_ADDRESS, val);
+
+done:
+ return err;
+}
+
+static int tg3_phydsp_read(struct tg3 *tp, u32 reg, u32 *val)
+{
+ int err;
+
+ err = tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg);
+ if (!err)
+ err = tg3_readphy(tp, MII_TG3_DSP_RW_PORT, val);
+
+ return err;
+}
+
+static int tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 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 int tg3_phy_auxctl_read(struct tg3 *tp, int reg, u32 *val)
+{
+ int err;
+
+ err = tg3_writephy(tp, MII_TG3_AUX_CTRL,
+ (reg << MII_TG3_AUXCTL_MISC_RDSEL_SHIFT) |
+ MII_TG3_AUXCTL_SHDWSEL_MISC);
+ if (!err)
+ err = tg3_readphy(tp, MII_TG3_AUX_CTRL, val);
+
+ return err;
+}
+
+static int tg3_phy_auxctl_write(struct tg3 *tp, int reg, u32 set)
+{
+ if (reg == MII_TG3_AUXCTL_SHDWSEL_MISC)
+ set |= MII_TG3_AUXCTL_MISC_WREN;
+
+ return tg3_writephy(tp, MII_TG3_AUX_CTRL, set | reg);
+}
+
+#define TG3_PHY_AUXCTL_SMDSP_ENABLE(tp) \
+ tg3_phy_auxctl_write((tp), MII_TG3_AUXCTL_SHDWSEL_AUXCTL, \
+ MII_TG3_AUXCTL_ACTL_SMDSP_ENA | \
+ MII_TG3_AUXCTL_ACTL_TX_6DB)
+
+#define TG3_PHY_AUXCTL_SMDSP_DISABLE(tp) \
+ tg3_phy_auxctl_write((tp), MII_TG3_AUXCTL_SHDWSEL_AUXCTL, \
+ MII_TG3_AUXCTL_ACTL_TX_6DB);
+
static int tg3_bmcr_reset(struct tg3 *tp)
{
u32 phy_control;
@@ -982,7 +1102,7 @@ static void tg3_mdio_config_5785(struct tg3 *tp)
return;
}
- if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_INBAND_DISABLE))
+ if (!tg3_flag(tp, RGMII_INBAND_DISABLE))
val |= MAC_PHYCFG2_EMODE_MASK_MASK |
MAC_PHYCFG2_FMODE_MASK_MASK |
MAC_PHYCFG2_GMODE_MASK_MASK |
@@ -995,10 +1115,10 @@ static void tg3_mdio_config_5785(struct tg3 *tp)
val = tr32(MAC_PHYCFG1);
val &= ~(MAC_PHYCFG1_RXCLK_TO_MASK | MAC_PHYCFG1_TXCLK_TO_MASK |
MAC_PHYCFG1_RGMII_EXT_RX_DEC | MAC_PHYCFG1_RGMII_SND_STAT_EN);
- if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_INBAND_DISABLE)) {
- if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN)
+ if (!tg3_flag(tp, RGMII_INBAND_DISABLE)) {
+ if (tg3_flag(tp, RGMII_EXT_IBND_RX_EN))
val |= MAC_PHYCFG1_RGMII_EXT_RX_DEC;
- if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN)
+ if (tg3_flag(tp, RGMII_EXT_IBND_TX_EN))
val |= MAC_PHYCFG1_RGMII_SND_STAT_EN;
}
val |= MAC_PHYCFG1_RXCLK_TIMEOUT | MAC_PHYCFG1_TXCLK_TIMEOUT |
@@ -1013,13 +1133,13 @@ static void tg3_mdio_config_5785(struct tg3 *tp)
MAC_RGMII_MODE_TX_ENABLE |
MAC_RGMII_MODE_TX_LOWPWR |
MAC_RGMII_MODE_TX_RESET);
- if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_INBAND_DISABLE)) {
- if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN)
+ if (!tg3_flag(tp, RGMII_INBAND_DISABLE)) {
+ if (tg3_flag(tp, RGMII_EXT_IBND_RX_EN))
val |= MAC_RGMII_MODE_RX_INT_B |
MAC_RGMII_MODE_RX_QUALITY |
MAC_RGMII_MODE_RX_ACTIVITY |
MAC_RGMII_MODE_RX_ENG_DET;
- if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN)
+ if (tg3_flag(tp, RGMII_EXT_IBND_TX_EN))
val |= MAC_RGMII_MODE_TX_ENABLE |
MAC_RGMII_MODE_TX_LOWPWR |
MAC_RGMII_MODE_TX_RESET;
@@ -1033,7 +1153,7 @@ static void tg3_mdio_start(struct tg3 *tp)
tw32_f(MAC_MI_MODE, tp->mi_mode);
udelay(80);
- if ((tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) &&
+ if (tg3_flag(tp, MDIOBUS_INITED) &&
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
tg3_mdio_config_5785(tp);
}
@@ -1044,8 +1164,7 @@ 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 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) {
+ if (tg3_flag(tp, 5717_PLUS)) {
u32 is_serdes;
tp->phy_addr = PCI_FUNC(tp->pdev->devfn) + 1;
@@ -1062,8 +1181,7 @@ static int tg3_mdio_init(struct tg3 *tp)
tg3_mdio_start(tp);
- if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) ||
- (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED))
+ if (!tg3_flag(tp, USE_PHYLIB) || tg3_flag(tp, MDIOBUS_INITED))
return 0;
tp->mdio_bus = mdiobus_alloc();
@@ -1119,11 +1237,11 @@ static int tg3_mdio_init(struct tg3 *tp)
PHY_BRCM_RX_REFCLK_UNUSED |
PHY_BRCM_DIS_TXCRXC_NOENRGY |
PHY_BRCM_AUTO_PWRDWN_ENABLE;
- if (tp->tg3_flags3 & TG3_FLG3_RGMII_INBAND_DISABLE)
+ if (tg3_flag(tp, RGMII_INBAND_DISABLE))
phydev->dev_flags |= PHY_BRCM_STD_IBND_DISABLE;
- if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN)
+ if (tg3_flag(tp, RGMII_EXT_IBND_RX_EN))
phydev->dev_flags |= PHY_BRCM_EXT_IBND_RX_ENABLE;
- if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN)
+ if (tg3_flag(tp, RGMII_EXT_IBND_TX_EN))
phydev->dev_flags |= PHY_BRCM_EXT_IBND_TX_ENABLE;
/* fallthru */
case PHY_ID_RTL8211C:
@@ -1137,7 +1255,7 @@ static int tg3_mdio_init(struct tg3 *tp)
break;
}
- tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_INITED;
+ tg3_flag_set(tp, MDIOBUS_INITED);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
tg3_mdio_config_5785(tp);
@@ -1147,59 +1265,13 @@ static int tg3_mdio_init(struct tg3 *tp)
static void tg3_mdio_fini(struct tg3 *tp)
{
- if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) {
- tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_INITED;
+ if (tg3_flag(tp, MDIOBUS_INITED)) {
+ tg3_flag_clear(tp, MDIOBUS_INITED);
mdiobus_unregister(tp->mdio_bus);
mdiobus_free(tp->mdio_bus);
}
}
-static int tg3_phy_cl45_write(struct tg3 *tp, u32 devad, u32 addr, u32 val)
-{
- int err;
-
- err = tg3_writephy(tp, MII_TG3_MMD_CTRL, devad);
- if (err)
- goto done;
-
- err = tg3_writephy(tp, MII_TG3_MMD_ADDRESS, addr);
- if (err)
- goto done;
-
- err = tg3_writephy(tp, MII_TG3_MMD_CTRL,
- MII_TG3_MMD_CTRL_DATA_NOINC | devad);
- if (err)
- goto done;
-
- err = tg3_writephy(tp, MII_TG3_MMD_ADDRESS, val);
-
-done:
- return err;
-}
-
-static int tg3_phy_cl45_read(struct tg3 *tp, u32 devad, u32 addr, u32 *val)
-{
- int err;
-
- err = tg3_writephy(tp, MII_TG3_MMD_CTRL, devad);
- if (err)
- goto done;
-
- err = tg3_writephy(tp, MII_TG3_MMD_ADDRESS, addr);
- if (err)
- goto done;
-
- err = tg3_writephy(tp, MII_TG3_MMD_CTRL,
- MII_TG3_MMD_CTRL_DATA_NOINC | devad);
- if (err)
- goto done;
-
- err = tg3_readphy(tp, MII_TG3_MMD_ADDRESS, val);
-
-done:
- return err;
-}
-
/* tp->lock is held. */
static inline void tg3_generate_fw_event(struct tg3 *tp)
{
@@ -1247,8 +1319,7 @@ static void tg3_ump_link_report(struct tg3 *tp)
u32 reg;
u32 val;
- if (!(tp->tg3_flags2 & TG3_FLG2_5780_CLASS) ||
- !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
+ if (!tg3_flag(tp, 5780_CLASS) || !tg3_flag(tp, ENABLE_ASF))
return;
tg3_wait_for_event_ack(tp);
@@ -1308,6 +1379,11 @@ static void tg3_link_report(struct tg3 *tp)
"on" : "off",
(tp->link_config.active_flowctrl & FLOW_CTRL_RX) ?
"on" : "off");
+
+ if (tp->phy_flags & TG3_PHYFLG_EEE_CAP)
+ netdev_info(tp->dev, "EEE is %s\n",
+ tp->setlpicnt ? "enabled" : "disabled");
+
tg3_ump_link_report(tp);
}
}
@@ -1373,13 +1449,12 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv)
u32 old_rx_mode = tp->rx_mode;
u32 old_tx_mode = tp->tx_mode;
- if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)
+ if (tg3_flag(tp, USE_PHYLIB))
autoneg = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR]->autoneg;
else
autoneg = tp->link_config.autoneg;
- if (autoneg == AUTONEG_ENABLE &&
- (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) {
+ if (autoneg == AUTONEG_ENABLE && tg3_flag(tp, PAUSE_AUTONEG)) {
if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES)
flowctrl = tg3_resolve_flowctrl_1000X(lcladv, rmtadv);
else
@@ -1576,28 +1651,6 @@ static void tg3_phy_fini(struct tg3 *tp)
}
}
-static int tg3_phydsp_read(struct tg3 *tp, u32 reg, u32 *val)
-{
- int err;
-
- err = tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg);
- if (!err)
- err = tg3_readphy(tp, MII_TG3_DSP_RW_PORT, val);
-
- return err;
-}
-
-static int tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 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)
{
u32 phytest;
@@ -1622,9 +1675,8 @@ 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 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) &&
+ if (!tg3_flag(tp, 5705_PLUS) ||
+ (tg3_flag(tp, 5717_PLUS) &&
(tp->phy_flags & TG3_PHYFLG_MII_SERDES)))
return;
@@ -1658,7 +1710,7 @@ static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable)
{
u32 phy;
- if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
+ if (!tg3_flag(tp, 5705_PLUS) ||
(tp->phy_flags & TG3_PHYFLG_ANY_SERDES))
return;
@@ -1680,31 +1732,33 @@ static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable)
tg3_writephy(tp, MII_TG3_FET_TEST, ephy);
}
} else {
- phy = MII_TG3_AUXCTL_MISC_RDSEL_MISC |
- MII_TG3_AUXCTL_SHDWSEL_MISC;
- if (!tg3_writephy(tp, MII_TG3_AUX_CTRL, phy) &&
- !tg3_readphy(tp, MII_TG3_AUX_CTRL, &phy)) {
+ int ret;
+
+ ret = tg3_phy_auxctl_read(tp,
+ MII_TG3_AUXCTL_SHDWSEL_MISC, &phy);
+ if (!ret) {
if (enable)
phy |= MII_TG3_AUXCTL_MISC_FORCE_AMDIX;
else
phy &= ~MII_TG3_AUXCTL_MISC_FORCE_AMDIX;
- phy |= MII_TG3_AUXCTL_MISC_WREN;
- tg3_writephy(tp, MII_TG3_AUX_CTRL, phy);
+ tg3_phy_auxctl_write(tp,
+ MII_TG3_AUXCTL_SHDWSEL_MISC, phy);
}
}
}
static void tg3_phy_set_wirespeed(struct tg3 *tp)
{
+ int ret;
u32 val;
if (tp->phy_flags & TG3_PHYFLG_NO_ETH_WIRE_SPEED)
return;
- if (!tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x7007) &&
- !tg3_readphy(tp, MII_TG3_AUX_CTRL, &val))
- tg3_writephy(tp, MII_TG3_AUX_CTRL,
- (val | (1 << 15) | (1 << 4)));
+ ret = tg3_phy_auxctl_read(tp, MII_TG3_AUXCTL_SHDWSEL_MISC, &val);
+ if (!ret)
+ tg3_phy_auxctl_write(tp, MII_TG3_AUXCTL_SHDWSEL_MISC,
+ val | MII_TG3_AUXCTL_MISC_WIRESPD_EN);
}
static void tg3_phy_apply_otp(struct tg3 *tp)
@@ -1716,11 +1770,8 @@ static void tg3_phy_apply_otp(struct tg3 *tp)
otp = tp->phy_otp;
- /* Enable SM_DSP clock and tx 6dB coding. */
- phy = MII_TG3_AUXCTL_SHDWSEL_AUXCTL |
- MII_TG3_AUXCTL_ACTL_SMDSP_ENA |
- MII_TG3_AUXCTL_ACTL_TX_6DB;
- tg3_writephy(tp, MII_TG3_AUX_CTRL, phy);
+ if (TG3_PHY_AUXCTL_SMDSP_ENABLE(tp))
+ return;
phy = ((otp & TG3_OTP_AGCTGT_MASK) >> TG3_OTP_AGCTGT_SHIFT);
phy |= MII_TG3_DSP_TAP1_AGCTGT_DFLT;
@@ -1744,10 +1795,7 @@ static void tg3_phy_apply_otp(struct tg3 *tp)
((otp & TG3_OTP_RCOFF_MASK) >> TG3_OTP_RCOFF_SHIFT);
tg3_phydsp_write(tp, MII_TG3_DSP_EXP97, phy);
- /* Turn off SM_DSP clock. */
- phy = MII_TG3_AUXCTL_SHDWSEL_AUXCTL |
- MII_TG3_AUXCTL_ACTL_TX_6DB;
- tg3_writephy(tp, MII_TG3_AUX_CTRL, phy);
+ TG3_PHY_AUXCTL_SMDSP_DISABLE(tp);
}
static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up)
@@ -1776,29 +1824,9 @@ static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up)
tg3_phy_cl45_read(tp, MDIO_MMD_AN,
TG3_CL45_D7_EEERES_STAT, &val);
- switch (val) {
- case TG3_CL45_D7_EEERES_STAT_LP_1000T:
- switch (GET_ASIC_REV(tp->pci_chip_rev_id)) {
- case ASIC_REV_5717:
- case ASIC_REV_5719:
- case ASIC_REV_57765:
- /* Enable SM_DSP clock and tx 6dB coding. */
- val = MII_TG3_AUXCTL_SHDWSEL_AUXCTL |
- MII_TG3_AUXCTL_ACTL_SMDSP_ENA |
- MII_TG3_AUXCTL_ACTL_TX_6DB;
- tg3_writephy(tp, MII_TG3_AUX_CTRL, val);
-
- tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, 0x0000);
-
- /* Turn off SM_DSP clock. */
- val = MII_TG3_AUXCTL_SHDWSEL_AUXCTL |
- MII_TG3_AUXCTL_ACTL_TX_6DB;
- tg3_writephy(tp, MII_TG3_AUX_CTRL, val);
- }
- /* Fallthrough */
- case TG3_CL45_D7_EEERES_STAT_LP_100TX:
+ if (val == TG3_CL45_D7_EEERES_STAT_LP_1000T ||
+ val == TG3_CL45_D7_EEERES_STAT_LP_100TX)
tp->setlpicnt = 2;
- }
}
if (!tp->setlpicnt) {
@@ -1807,6 +1835,23 @@ static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up)
}
}
+static void tg3_phy_eee_enable(struct tg3 *tp)
+{
+ u32 val;
+
+ if (tp->link_config.active_speed == SPEED_1000 &&
+ (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) &&
+ !TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) {
+ tg3_phydsp_write(tp, MII_TG3_DSP_TAP26, 0x0003);
+ TG3_PHY_AUXCTL_SMDSP_DISABLE(tp);
+ }
+
+ val = tr32(TG3_CPMU_EEE_MODE);
+ tw32(TG3_CPMU_EEE_MODE, val | TG3_CPMU_EEEMD_LPI_ENABLE);
+}
+
static int tg3_wait_macro_done(struct tg3 *tp)
{
int limit = 100;
@@ -1945,8 +1990,9 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp)
(MII_TG3_CTRL_AS_MASTER |
MII_TG3_CTRL_ENABLE_AS_MASTER));
- /* Enable SM_DSP_CLOCK and 6dB. */
- tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
+ err = TG3_PHY_AUXCTL_SMDSP_ENABLE(tp);
+ if (err)
+ return err;
/* Block the PHY control access. */
tg3_phydsp_write(tp, 0x8005, 0x0800);
@@ -1965,13 +2011,7 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp)
tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8200);
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) {
- /* Set Extended packet length bit for jumbo frames */
- tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4400);
- } else {
- tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
- }
+ TG3_PHY_AUXCTL_SMDSP_DISABLE(tp);
tg3_writephy(tp, MII_TG3_CTRL, phy9_orig);
@@ -2047,8 +2087,7 @@ static int tg3_phy_reset(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_5719) &&
+ if (tg3_flag(tp, 5717_PLUS) &&
(tp->phy_flags & TG3_PHYFLG_MII_SERDES))
return 0;
@@ -2060,49 +2099,57 @@ static int tg3_phy_reset(struct tg3 *tp)
tg3_phy_toggle_apd(tp, false);
out:
- if (tp->phy_flags & TG3_PHYFLG_ADC_BUG) {
- tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
+ if ((tp->phy_flags & TG3_PHYFLG_ADC_BUG) &&
+ !TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) {
tg3_phydsp_write(tp, 0x201f, 0x2aaa);
tg3_phydsp_write(tp, 0x000a, 0x0323);
- tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
+ TG3_PHY_AUXCTL_SMDSP_DISABLE(tp);
}
+
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->phy_flags & TG3_PHYFLG_BER_BUG) {
- tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00);
- 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);
+ if (!TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) {
+ tg3_phydsp_write(tp, 0x000a, 0x310b);
+ tg3_phydsp_write(tp, 0x201f, 0x9506);
+ tg3_phydsp_write(tp, 0x401f, 0x14e2);
+ TG3_PHY_AUXCTL_SMDSP_DISABLE(tp);
+ }
} 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->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);
- } else
- tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x010b);
- tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400);
+ if (!TG3_PHY_AUXCTL_SMDSP_ENABLE(tp)) {
+ tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a);
+ 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);
+ } else
+ tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x010b);
+
+ TG3_PHY_AUXCTL_SMDSP_DISABLE(tp);
+ }
}
+
/* Set Extended packet length bit (bit 14) on all chips that */
/* support jumbo frames */
if ((tp->phy_id & TG3_PHY_ID_MASK) == TG3_PHY_ID_BCM5401) {
/* Cannot do read-modify-write on 5401 */
- tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4c20);
- } else if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) {
+ tg3_phy_auxctl_write(tp, MII_TG3_AUXCTL_SHDWSEL_AUXCTL, 0x4c20);
+ } else if (tg3_flag(tp, JUMBO_CAPABLE)) {
/* Set bit 14 with read-modify-write to preserve other bits */
- if (!tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0007) &&
- !tg3_readphy(tp, MII_TG3_AUX_CTRL, &val))
- tg3_writephy(tp, MII_TG3_AUX_CTRL, val | 0x4000);
+ err = tg3_phy_auxctl_read(tp,
+ MII_TG3_AUXCTL_SHDWSEL_AUXCTL, &val);
+ if (!err)
+ tg3_phy_auxctl_write(tp, MII_TG3_AUXCTL_SHDWSEL_AUXCTL,
+ val | MII_TG3_AUXCTL_ACTL_EXTPKTLEN);
}
/* Set phy register 0x10 bit 0 to high fifo elasticity to support
* jumbo frames transmission.
*/
- if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) {
+ if (tg3_flag(tp, JUMBO_CAPABLE)) {
if (!tg3_readphy(tp, MII_TG3_EXT_CTRL, &val))
tg3_writephy(tp, MII_TG3_EXT_CTRL,
val | MII_TG3_EXT_CTRL_FIFO_ELASTIC);
@@ -2123,14 +2170,15 @@ static void tg3_frob_aux_power(struct tg3 *tp)
bool need_vaux = false;
/* The GPIOs do something completely different on 57765. */
- if ((tp->tg3_flags2 & TG3_FLG2_IS_NIC) == 0 ||
+ if (!tg3_flag(tp, IS_NIC) ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
return;
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) &&
tp->pdev_peer != tp->pdev) {
struct net_device *dev_peer;
@@ -2140,17 +2188,16 @@ static void tg3_frob_aux_power(struct tg3 *tp)
if (dev_peer) {
struct tg3 *tp_peer = netdev_priv(dev_peer);
- if (tp_peer->tg3_flags & TG3_FLAG_INIT_COMPLETE)
+ if (tg3_flag(tp_peer, INIT_COMPLETE))
return;
- if ((tp_peer->tg3_flags & TG3_FLAG_WOL_ENABLE) ||
- (tp_peer->tg3_flags & TG3_FLAG_ENABLE_ASF))
+ if (tg3_flag(tp_peer, WOL_ENABLE) ||
+ tg3_flag(tp_peer, ENABLE_ASF))
need_vaux = true;
}
}
- if ((tp->tg3_flags & TG3_FLAG_WOL_ENABLE) ||
- (tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
+ if (tg3_flag(tp, WOL_ENABLE) || tg3_flag(tp, ENABLE_ASF))
need_vaux = true;
if (need_vaux) {
@@ -2304,11 +2351,10 @@ static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power)
tg3_writephy(tp, MII_TG3_EXT_CTRL,
MII_TG3_EXT_CTRL_FORCE_LED_OFF);
- tg3_writephy(tp, MII_TG3_AUX_CTRL,
- MII_TG3_AUXCTL_SHDWSEL_PWRCTL |
- MII_TG3_AUXCTL_PCTL_100TX_LPWR |
- MII_TG3_AUXCTL_PCTL_SPR_ISOLATE |
- MII_TG3_AUXCTL_PCTL_VREG_11V);
+ val = MII_TG3_AUXCTL_PCTL_100TX_LPWR |
+ MII_TG3_AUXCTL_PCTL_SPR_ISOLATE |
+ MII_TG3_AUXCTL_PCTL_VREG_11V;
+ tg3_phy_auxctl_write(tp, MII_TG3_AUXCTL_SHDWSEL_PWRCTL, val);
}
/* The PHY should not be powered down on some chips because
@@ -2334,7 +2380,7 @@ static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power)
/* tp->lock is held. */
static int tg3_nvram_lock(struct tg3 *tp)
{
- if (tp->tg3_flags & TG3_FLAG_NVRAM) {
+ if (tg3_flag(tp, NVRAM)) {
int i;
if (tp->nvram_lock_cnt == 0) {
@@ -2357,7 +2403,7 @@ static int tg3_nvram_lock(struct tg3 *tp)
/* tp->lock is held. */
static void tg3_nvram_unlock(struct tg3 *tp)
{
- if (tp->tg3_flags & TG3_FLAG_NVRAM) {
+ if (tg3_flag(tp, NVRAM)) {
if (tp->nvram_lock_cnt > 0)
tp->nvram_lock_cnt--;
if (tp->nvram_lock_cnt == 0)
@@ -2368,8 +2414,7 @@ static void tg3_nvram_unlock(struct tg3 *tp)
/* tp->lock is held. */
static void tg3_enable_nvram_access(struct tg3 *tp)
{
- if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
- !(tp->tg3_flags3 & TG3_FLG3_PROTECTED_NVRAM)) {
+ if (tg3_flag(tp, 5750_PLUS) && !tg3_flag(tp, PROTECTED_NVRAM)) {
u32 nvaccess = tr32(NVRAM_ACCESS);
tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE);
@@ -2379,8 +2424,7 @@ static void tg3_enable_nvram_access(struct tg3 *tp)
/* tp->lock is held. */
static void tg3_disable_nvram_access(struct tg3 *tp)
{
- if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
- !(tp->tg3_flags3 & TG3_FLG3_PROTECTED_NVRAM)) {
+ if (tg3_flag(tp, 5750_PLUS) && !tg3_flag(tp, PROTECTED_NVRAM)) {
u32 nvaccess = tr32(NVRAM_ACCESS);
tw32(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE);
@@ -2450,10 +2494,10 @@ static int tg3_nvram_exec_cmd(struct tg3 *tp, u32 nvram_cmd)
static u32 tg3_nvram_phys_addr(struct tg3 *tp, u32 addr)
{
- if ((tp->tg3_flags & TG3_FLAG_NVRAM) &&
- (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) &&
- (tp->tg3_flags2 & TG3_FLG2_FLASH) &&
- !(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM_ADDR_TRANS) &&
+ if (tg3_flag(tp, NVRAM) &&
+ tg3_flag(tp, NVRAM_BUFFERED) &&
+ tg3_flag(tp, FLASH) &&
+ !tg3_flag(tp, NO_NVRAM_ADDR_TRANS) &&
(tp->nvram_jedecnum == JEDEC_ATMEL))
addr = ((addr / tp->nvram_pagesize) <<
@@ -2465,10 +2509,10 @@ static u32 tg3_nvram_phys_addr(struct tg3 *tp, u32 addr)
static u32 tg3_nvram_logical_addr(struct tg3 *tp, u32 addr)
{
- if ((tp->tg3_flags & TG3_FLAG_NVRAM) &&
- (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) &&
- (tp->tg3_flags2 & TG3_FLG2_FLASH) &&
- !(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM_ADDR_TRANS) &&
+ if (tg3_flag(tp, NVRAM) &&
+ tg3_flag(tp, NVRAM_BUFFERED) &&
+ tg3_flag(tp, FLASH) &&
+ !tg3_flag(tp, NO_NVRAM_ADDR_TRANS) &&
(tp->nvram_jedecnum == JEDEC_ATMEL))
addr = ((addr >> ATMEL_AT45DB0X1B_PAGE_POS) *
@@ -2488,7 +2532,7 @@ static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val)
{
int ret;
- if (!(tp->tg3_flags & TG3_FLAG_NVRAM))
+ if (!tg3_flag(tp, NVRAM))
return tg3_nvram_read_using_eeprom(tp, offset, val);
offset = tg3_nvram_phys_addr(tp, offset);
@@ -2580,7 +2624,7 @@ static int tg3_power_up(struct tg3 *tp)
pci_set_power_state(tp->pdev, PCI_D0);
/* Switch out of Vaux if it is a NIC */
- if (tp->tg3_flags2 & TG3_FLG2_IS_NIC)
+ if (tg3_flag(tp, IS_NIC))
tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl, 100);
return 0;
@@ -2594,7 +2638,7 @@ static int tg3_power_down_prepare(struct tg3 *tp)
tg3_enable_register_access(tp);
/* Restore the CLKREQ setting. */
- if (tp->tg3_flags3 & TG3_FLG3_CLKREQ_BUG) {
+ if (tg3_flag(tp, CLKREQ_BUG)) {
u16 lnkctl;
pci_read_config_word(tp->pdev,
@@ -2611,9 +2655,9 @@ static int tg3_power_down_prepare(struct tg3 *tp)
misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT);
device_should_wake = device_may_wakeup(&tp->pdev->dev) &&
- (tp->tg3_flags & TG3_FLAG_WOL_ENABLE);
+ tg3_flag(tp, WOL_ENABLE);
- if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+ if (tg3_flag(tp, USE_PHYLIB)) {
do_low_power = false;
if ((tp->phy_flags & TG3_PHYFLG_IS_CONNECTED) &&
!(tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) {
@@ -2634,9 +2678,8 @@ static int tg3_power_down_prepare(struct tg3 *tp)
ADVERTISED_Autoneg |
ADVERTISED_10baseT_Half;
- if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
- device_should_wake) {
- if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB)
+ if (tg3_flag(tp, ENABLE_ASF) || device_should_wake) {
+ if (tg3_flag(tp, WOL_SPEED_100MB))
advertising |=
ADVERTISED_100baseT_Half |
ADVERTISED_100baseT_Full |
@@ -2681,7 +2724,7 @@ static int tg3_power_down_prepare(struct tg3 *tp)
val = tr32(GRC_VCPU_EXT_CTRL);
tw32(GRC_VCPU_EXT_CTRL, val | GRC_VCPU_EXT_CTRL_DISABLE_WOL);
- } else if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
+ } else if (!tg3_flag(tp, ENABLE_ASF)) {
int i;
u32 val;
@@ -2692,7 +2735,7 @@ static int tg3_power_down_prepare(struct tg3 *tp)
msleep(1);
}
}
- if (tp->tg3_flags & TG3_FLAG_WOL_CAP)
+ if (tg3_flag(tp, WOL_CAP))
tg3_write_mem(tp, NIC_SRAM_WOL_MBOX, WOL_SIGNATURE |
WOL_DRV_STATE_SHUTDOWN |
WOL_DRV_WOL |
@@ -2702,8 +2745,13 @@ static int tg3_power_down_prepare(struct tg3 *tp)
u32 mac_mode;
if (!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES)) {
- if (do_low_power) {
- tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a);
+ if (do_low_power &&
+ !(tp->phy_flags & TG3_PHYFLG_IS_FET)) {
+ tg3_phy_auxctl_write(tp,
+ MII_TG3_AUXCTL_SHDWSEL_PWRCTL,
+ MII_TG3_AUXCTL_PCTL_WOL_EN |
+ MII_TG3_AUXCTL_PCTL_100TX_LPWR |
+ MII_TG3_AUXCTL_PCTL_CL_AB_TXDAC);
udelay(40);
}
@@ -2715,8 +2763,7 @@ static int tg3_power_down_prepare(struct tg3 *tp)
mac_mode |= tp->mac_mode & MAC_MODE_LINK_POLARITY;
if (GET_ASIC_REV(tp->pci_chip_rev_id) ==
ASIC_REV_5700) {
- u32 speed = (tp->tg3_flags &
- TG3_FLAG_WOL_SPEED_100MB) ?
+ u32 speed = tg3_flag(tp, WOL_SPEED_100MB) ?
SPEED_100 : SPEED_10;
if (tg3_5700_link_polarity(tp, speed))
mac_mode |= MAC_MODE_LINK_POLARITY;
@@ -2727,17 +2774,15 @@ static int tg3_power_down_prepare(struct tg3 *tp)
mac_mode = MAC_MODE_PORT_MODE_TBI;
}
- if (!(tp->tg3_flags2 & TG3_FLG2_5750_PLUS))
+ if (!tg3_flag(tp, 5750_PLUS))
tw32(MAC_LED_CTRL, tp->led_ctrl);
mac_mode |= MAC_MODE_MAGIC_PKT_ENABLE;
- if (((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) &&
- !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) &&
- ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
- (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)))
+ if ((tg3_flag(tp, 5705_PLUS) && !tg3_flag(tp, 5780_CLASS)) &&
+ (tg3_flag(tp, ENABLE_ASF) || tg3_flag(tp, ENABLE_APE)))
mac_mode |= MAC_MODE_KEEP_FRAME_IN_WOL;
- if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
+ if (tg3_flag(tp, ENABLE_APE))
mac_mode |= MAC_MODE_APE_TX_EN |
MAC_MODE_APE_RX_EN |
MAC_MODE_TDE_ENABLE;
@@ -2749,7 +2794,7 @@ static int tg3_power_down_prepare(struct tg3 *tp)
udelay(10);
}
- if (!(tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB) &&
+ if (!tg3_flag(tp, WOL_SPEED_100MB) &&
(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) {
u32 base_val;
@@ -2760,12 +2805,11 @@ static int tg3_power_down_prepare(struct tg3 *tp)
tw32_wait_f(TG3PCI_CLOCK_CTRL, base_val | CLOCK_CTRL_ALTCLK |
CLOCK_CTRL_PWRDOWN_PLL133, 40);
- } else if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) ||
- (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) ||
- (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)) {
+ } else if (tg3_flag(tp, 5780_CLASS) ||
+ tg3_flag(tp, CPMU_PRESENT) ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
/* do nothing */
- } else if (!((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
- (tp->tg3_flags & TG3_FLAG_ENABLE_ASF))) {
+ } else if (!(tg3_flag(tp, 5750_PLUS) && tg3_flag(tp, ENABLE_ASF))) {
u32 newbits1, newbits2;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
@@ -2774,7 +2818,7 @@ static int tg3_power_down_prepare(struct tg3 *tp)
CLOCK_CTRL_TXCLK_DISABLE |
CLOCK_CTRL_ALTCLK);
newbits2 = newbits1 | CLOCK_CTRL_44MHZ_CORE;
- } else if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
+ } else if (tg3_flag(tp, 5705_PLUS)) {
newbits1 = CLOCK_CTRL_625_CORE;
newbits2 = newbits1 | CLOCK_CTRL_ALTCLK;
} else {
@@ -2788,7 +2832,7 @@ static int tg3_power_down_prepare(struct tg3 *tp)
tw32_wait_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl | newbits2,
40);
- if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
+ if (!tg3_flag(tp, 5705_PLUS)) {
u32 newbits3;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
@@ -2805,8 +2849,7 @@ static int tg3_power_down_prepare(struct tg3 *tp)
}
}
- if (!(device_should_wake) &&
- !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
+ if (!(device_should_wake) && !tg3_flag(tp, ENABLE_ASF))
tg3_power_down_phy(tp, do_low_power);
tg3_frob_aux_power(tp);
@@ -2818,7 +2861,7 @@ static int tg3_power_down_prepare(struct tg3 *tp)
val &= ~((1 << 16) | (1 << 4) | (1 << 2) | (1 << 1) | 1);
tw32(0x7d00, val);
- if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
+ if (!tg3_flag(tp, ENABLE_ASF)) {
int err;
err = tg3_nvram_lock(tp);
@@ -2837,7 +2880,7 @@ static void tg3_power_down(struct tg3 *tp)
{
tg3_power_down_prepare(tp);
- pci_wake_from_d3(tp->pdev, tp->tg3_flags & TG3_FLAG_WOL_ENABLE);
+ pci_wake_from_d3(tp->pdev, tg3_flag(tp, WOL_ENABLE));
pci_set_power_state(tp->pdev, PCI_D3hot);
}
@@ -2888,106 +2931,54 @@ static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8
}
}
-static void tg3_phy_copper_begin(struct tg3 *tp)
+static int tg3_phy_autoneg_cfg(struct tg3 *tp, u32 advertise, u32 flowctrl)
{
- u32 new_adv;
- int i;
+ int err = 0;
+ u32 val, new_adv;
- if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) {
- /* Entering low power mode. Disable gigabit and
- * 100baseT advertisements.
- */
- tg3_writephy(tp, MII_TG3_CTRL, 0);
+ new_adv = ADVERTISE_CSMA;
+ if (advertise & ADVERTISED_10baseT_Half)
+ new_adv |= ADVERTISE_10HALF;
+ if (advertise & ADVERTISED_10baseT_Full)
+ new_adv |= ADVERTISE_10FULL;
+ if (advertise & ADVERTISED_100baseT_Half)
+ new_adv |= ADVERTISE_100HALF;
+ if (advertise & ADVERTISED_100baseT_Full)
+ new_adv |= ADVERTISE_100FULL;
- new_adv = (ADVERTISE_10HALF | ADVERTISE_10FULL |
- ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
- if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB)
- new_adv |= (ADVERTISE_100HALF | ADVERTISE_100FULL);
+ new_adv |= tg3_advert_flowctrl_1000T(flowctrl);
- tg3_writephy(tp, MII_ADVERTISE, new_adv);
- } else if (tp->link_config.speed == SPEED_INVALID) {
- if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY)
- tp->link_config.advertising &=
- ~(ADVERTISED_1000baseT_Half |
- ADVERTISED_1000baseT_Full);
+ err = tg3_writephy(tp, MII_ADVERTISE, new_adv);
+ if (err)
+ goto done;
- new_adv = ADVERTISE_CSMA;
- if (tp->link_config.advertising & ADVERTISED_10baseT_Half)
- new_adv |= ADVERTISE_10HALF;
- if (tp->link_config.advertising & ADVERTISED_10baseT_Full)
- new_adv |= ADVERTISE_10FULL;
- if (tp->link_config.advertising & ADVERTISED_100baseT_Half)
- new_adv |= ADVERTISE_100HALF;
- if (tp->link_config.advertising & ADVERTISED_100baseT_Full)
- new_adv |= ADVERTISE_100FULL;
-
- new_adv |= tg3_advert_flowctrl_1000T(tp->link_config.flowctrl);
-
- tg3_writephy(tp, MII_ADVERTISE, new_adv);
-
- if (tp->link_config.advertising &
- (ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) {
- new_adv = 0;
- if (tp->link_config.advertising & ADVERTISED_1000baseT_Half)
- 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->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 |
- MII_TG3_CTRL_ENABLE_AS_MASTER);
- tg3_writephy(tp, MII_TG3_CTRL, new_adv);
- } else {
- tg3_writephy(tp, MII_TG3_CTRL, 0);
- }
- } else {
- new_adv = tg3_advert_flowctrl_1000T(tp->link_config.flowctrl);
- new_adv |= ADVERTISE_CSMA;
+ if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY)
+ goto done;
- /* Asking for a specific link mode. */
- if (tp->link_config.speed == SPEED_1000) {
- tg3_writephy(tp, MII_ADVERTISE, new_adv);
+ new_adv = 0;
+ if (advertise & ADVERTISED_1000baseT_Half)
+ new_adv |= MII_TG3_CTRL_ADV_1000_HALF;
+ if (advertise & ADVERTISED_1000baseT_Full)
+ new_adv |= MII_TG3_CTRL_ADV_1000_FULL;
- if (tp->link_config.duplex == DUPLEX_FULL)
- new_adv = MII_TG3_CTRL_ADV_1000_FULL;
- else
- new_adv = MII_TG3_CTRL_ADV_1000_HALF;
- if (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 |
- MII_TG3_CTRL_ENABLE_AS_MASTER);
- } else {
- if (tp->link_config.speed == SPEED_100) {
- if (tp->link_config.duplex == DUPLEX_FULL)
- new_adv |= ADVERTISE_100FULL;
- else
- new_adv |= ADVERTISE_100HALF;
- } else {
- if (tp->link_config.duplex == DUPLEX_FULL)
- new_adv |= ADVERTISE_10FULL;
- else
- new_adv |= ADVERTISE_10HALF;
- }
- tg3_writephy(tp, MII_ADVERTISE, new_adv);
-
- new_adv = 0;
- }
+ if (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 |
+ MII_TG3_CTRL_ENABLE_AS_MASTER);
- tg3_writephy(tp, MII_TG3_CTRL, new_adv);
- }
+ err = tg3_writephy(tp, MII_TG3_CTRL, new_adv);
+ if (err)
+ goto done;
- if (tp->phy_flags & TG3_PHYFLG_EEE_CAP) {
- u32 val;
+ if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP))
+ goto done;
- tw32(TG3_CPMU_EEE_MODE,
- tr32(TG3_CPMU_EEE_MODE) & ~TG3_CPMU_EEEMD_LPI_ENABLE);
+ tw32(TG3_CPMU_EEE_MODE,
+ tr32(TG3_CPMU_EEE_MODE) & ~TG3_CPMU_EEEMD_LPI_ENABLE);
- /* Enable SM_DSP clock and tx 6dB coding. */
- val = MII_TG3_AUXCTL_SHDWSEL_AUXCTL |
- MII_TG3_AUXCTL_ACTL_SMDSP_ENA |
- MII_TG3_AUXCTL_ACTL_TX_6DB;
- tg3_writephy(tp, MII_TG3_AUX_CTRL, val);
+ err = TG3_PHY_AUXCTL_SMDSP_ENABLE(tp);
+ if (!err) {
+ u32 err2;
switch (GET_ASIC_REV(tp->pci_chip_rev_id)) {
case ASIC_REV_5717:
@@ -3004,22 +2995,66 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
}
val = 0;
- if (tp->link_config.autoneg == AUTONEG_ENABLE) {
- /* Advertise 100-BaseTX EEE ability */
- if (tp->link_config.advertising &
- ADVERTISED_100baseT_Full)
- val |= MDIO_AN_EEE_ADV_100TX;
- /* Advertise 1000-BaseT EEE ability */
- if (tp->link_config.advertising &
- ADVERTISED_1000baseT_Full)
- val |= MDIO_AN_EEE_ADV_1000T;
+ /* Advertise 100-BaseTX EEE ability */
+ if (advertise & ADVERTISED_100baseT_Full)
+ val |= MDIO_AN_EEE_ADV_100TX;
+ /* Advertise 1000-BaseT EEE ability */
+ if (advertise & ADVERTISED_1000baseT_Full)
+ val |= MDIO_AN_EEE_ADV_1000T;
+ err = tg3_phy_cl45_write(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, val);
+
+ err2 = TG3_PHY_AUXCTL_SMDSP_DISABLE(tp);
+ if (!err)
+ err = err2;
+ }
+
+done:
+ return err;
+}
+
+static void tg3_phy_copper_begin(struct tg3 *tp)
+{
+ u32 new_adv;
+ int i;
+
+ if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) {
+ new_adv = ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full;
+ if (tg3_flag(tp, WOL_SPEED_100MB))
+ new_adv |= ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full;
+
+ tg3_phy_autoneg_cfg(tp, new_adv,
+ FLOW_CTRL_TX | FLOW_CTRL_RX);
+ } else if (tp->link_config.speed == SPEED_INVALID) {
+ if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY)
+ tp->link_config.advertising &=
+ ~(ADVERTISED_1000baseT_Half |
+ ADVERTISED_1000baseT_Full);
+
+ tg3_phy_autoneg_cfg(tp, tp->link_config.advertising,
+ tp->link_config.flowctrl);
+ } else {
+ /* Asking for a specific link mode. */
+ if (tp->link_config.speed == SPEED_1000) {
+ if (tp->link_config.duplex == DUPLEX_FULL)
+ new_adv = ADVERTISED_1000baseT_Full;
+ else
+ new_adv = ADVERTISED_1000baseT_Half;
+ } else if (tp->link_config.speed == SPEED_100) {
+ if (tp->link_config.duplex == DUPLEX_FULL)
+ new_adv = ADVERTISED_100baseT_Full;
+ else
+ new_adv = ADVERTISED_100baseT_Half;
+ } else {
+ if (tp->link_config.duplex == DUPLEX_FULL)
+ new_adv = ADVERTISED_10baseT_Full;
+ else
+ new_adv = ADVERTISED_10baseT_Half;
}
- tg3_phy_cl45_write(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, val);
- /* Turn off SM_DSP clock. */
- val = MII_TG3_AUXCTL_SHDWSEL_AUXCTL |
- MII_TG3_AUXCTL_ACTL_TX_6DB;
- tg3_writephy(tp, MII_TG3_AUX_CTRL, val);
+ tg3_phy_autoneg_cfg(tp, new_adv,
+ tp->link_config.flowctrl);
}
if (tp->link_config.autoneg == AUTONEG_DISABLE &&
@@ -3077,7 +3112,7 @@ static int tg3_init_5401phy_dsp(struct tg3 *tp)
/* Turn off tap power management. */
/* Set Extended packet length bit */
- err = tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4c20);
+ err = tg3_phy_auxctl_write(tp, MII_TG3_AUXCTL_SHDWSEL_AUXCTL, 0x4c20);
err |= tg3_phydsp_write(tp, 0x0012, 0x1804);
err |= tg3_phydsp_write(tp, 0x0013, 0x1204);
@@ -3140,7 +3175,7 @@ static int tg3_adv_1000T_flowctrl_ok(struct tg3 *tp, u32 *lcladv, u32 *rmtadv)
if (curadv != reqadv)
return 0;
- if (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)
+ if (tg3_flag(tp, PAUSE_AUTONEG))
tg3_readphy(tp, MII_LPA, rmtadv);
} else {
/* Reprogram the advertisement register, even if it
@@ -3183,7 +3218,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
udelay(80);
}
- tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x02);
+ tg3_phy_auxctl_write(tp, MII_TG3_AUXCTL_SHDWSEL_PWRCTL, 0);
/* Some third-party PHYs need to be reset on link going
* down.
@@ -3203,7 +3238,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
if ((tp->phy_id & TG3_PHY_ID_MASK) == TG3_PHY_ID_BCM5401) {
tg3_readphy(tp, MII_BMSR, &bmsr);
if (tg3_readphy(tp, MII_BMSR, &bmsr) ||
- !(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE))
+ !tg3_flag(tp, INIT_COMPLETE))
bmsr = 0;
if (!(bmsr & BMSR_LSTATUS)) {
@@ -3264,11 +3299,13 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
current_duplex = DUPLEX_INVALID;
if (tp->phy_flags & TG3_PHYFLG_CAPACITIVE_COUPLING) {
- tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4007);
- tg3_readphy(tp, MII_TG3_AUX_CTRL, &val);
- if (!(val & (1 << 10))) {
- val |= (1 << 10);
- tg3_writephy(tp, MII_TG3_AUX_CTRL, val);
+ err = tg3_phy_auxctl_read(tp,
+ MII_TG3_AUXCTL_SHDWSEL_MISCTEST,
+ &val);
+ if (!err && !(val & (1 << 10))) {
+ tg3_phy_auxctl_write(tp,
+ MII_TG3_AUXCTL_SHDWSEL_MISCTEST,
+ val | (1 << 10));
goto relink;
}
}
@@ -3341,8 +3378,8 @@ relink:
tg3_phy_copper_begin(tp);
tg3_readphy(tp, MII_BMSR, &bmsr);
- if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
- (bmsr & BMSR_LSTATUS))
+ if ((!tg3_readphy(tp, MII_BMSR, &bmsr) && (bmsr & BMSR_LSTATUS)) ||
+ (tp->mac_mode & MAC_MODE_PORT_INT_LPBACK))
current_link_up = 1;
}
@@ -3385,7 +3422,7 @@ relink:
tg3_phy_eee_adjust(tp, current_link_up);
- if (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) {
+ if (tg3_flag(tp, USE_LINKCHG_REG)) {
/* Polled via timer. */
tw32_f(MAC_EVENT, 0);
} else {
@@ -3396,8 +3433,7 @@ relink:
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 &&
current_link_up == 1 &&
tp->link_config.active_speed == SPEED_1000 &&
- ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) ||
- (tp->tg3_flags & TG3_FLAG_PCI_HIGH_SPEED))) {
+ (tg3_flag(tp, PCIX_MODE) || tg3_flag(tp, PCI_HIGH_SPEED))) {
udelay(120);
tw32_f(MAC_STATUS,
(MAC_STATUS_SYNC_CHANGED |
@@ -3409,7 +3445,7 @@ relink:
}
/* Prevent send BD corruption. */
- if (tp->tg3_flags3 & TG3_FLG3_CLKREQ_BUG) {
+ if (tg3_flag(tp, CLKREQ_BUG)) {
u16 oldlnkctl, newlnkctl;
pci_read_config_word(tp->pdev,
@@ -3804,7 +3840,7 @@ static void tg3_init_bcm8002(struct tg3 *tp)
int i;
/* Reset when initting first time or we have a link. */
- if ((tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) &&
+ if (tg3_flag(tp, INIT_COMPLETE) &&
!(mac_status & MAC_STATUS_PCS_SYNCED))
return;
@@ -4065,9 +4101,9 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
orig_active_speed = tp->link_config.active_speed;
orig_active_duplex = tp->link_config.active_duplex;
- if (!(tp->tg3_flags2 & TG3_FLG2_HW_AUTONEG) &&
+ if (!tg3_flag(tp, HW_AUTONEG) &&
netif_carrier_ok(tp->dev) &&
- (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE)) {
+ tg3_flag(tp, INIT_COMPLETE)) {
mac_status = tr32(MAC_STATUS);
mac_status &= (MAC_STATUS_PCS_SYNCED |
MAC_STATUS_SIGNAL_DET |
@@ -4098,7 +4134,7 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
current_link_up = 0;
mac_status = tr32(MAC_STATUS);
- if (tp->tg3_flags2 & TG3_FLG2_HW_AUTONEG)
+ if (tg3_flag(tp, HW_AUTONEG))
current_link_up = tg3_setup_fiber_hw_autoneg(tp, mac_status);
else
current_link_up = tg3_setup_fiber_by_hand(tp, mac_status);
@@ -4297,7 +4333,7 @@ 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)) {
+ } else if (!tg3_flag(tp, 5780_CLASS)) {
/* Link is up via parallel detect */
} else {
current_link_up = 0;
@@ -4394,6 +4430,7 @@ static void tg3_serdes_parallel_detect(struct tg3 *tp)
static int tg3_setup_phy(struct tg3 *tp, int force_reset)
{
+ u32 val;
int err;
if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)
@@ -4404,7 +4441,7 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset)
err = tg3_setup_copper_phy(tp, force_reset);
if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX) {
- u32 val, scale;
+ u32 scale;
val = tr32(TG3_CPMU_CLCK_STAT) & CPMU_CLCK_STAT_MAC_CLCK_MASK;
if (val == CPMU_CLCK_STAT_MAC_CLCK_62_5)
@@ -4419,19 +4456,22 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset)
tw32(GRC_MISC_CFG, val);
}
+ val = (2 << TX_LENGTHS_IPG_CRS_SHIFT) |
+ (6 << TX_LENGTHS_IPG_SHIFT);
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+ val |= tr32(MAC_TX_LENGTHS) &
+ (TX_LENGTHS_JMB_FRM_LEN_MSK |
+ TX_LENGTHS_CNT_DWN_VAL_MSK);
+
if (tp->link_config.active_speed == SPEED_1000 &&
tp->link_config.active_duplex == DUPLEX_HALF)
- tw32(MAC_TX_LENGTHS,
- ((2 << TX_LENGTHS_IPG_CRS_SHIFT) |
- (6 << TX_LENGTHS_IPG_SHIFT) |
- (0xff << TX_LENGTHS_SLOT_TIME_SHIFT)));
+ tw32(MAC_TX_LENGTHS, val |
+ (0xff << TX_LENGTHS_SLOT_TIME_SHIFT));
else
- tw32(MAC_TX_LENGTHS,
- ((2 << TX_LENGTHS_IPG_CRS_SHIFT) |
- (6 << TX_LENGTHS_IPG_SHIFT) |
- (32 << TX_LENGTHS_SLOT_TIME_SHIFT)));
+ tw32(MAC_TX_LENGTHS, val |
+ (32 << TX_LENGTHS_SLOT_TIME_SHIFT));
- if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
+ if (!tg3_flag(tp, 5705_PLUS)) {
if (netif_carrier_ok(tp->dev)) {
tw32(HOSTCC_STAT_COAL_TICKS,
tp->coal.stats_block_coalesce_usecs);
@@ -4440,8 +4480,8 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset)
}
}
- if (tp->tg3_flags & TG3_FLAG_ASPM_WORKAROUND) {
- u32 val = tr32(PCIE_PWR_MGMT_THRESH);
+ if (tg3_flag(tp, ASPM_WORKAROUND)) {
+ val = tr32(PCIE_PWR_MGMT_THRESH);
if (!netif_carrier_ok(tp->dev))
val = (val & ~PCIE_PWR_MGMT_L1_THRESH_MSK) |
tp->pwrmgmt_thresh;
@@ -4458,6 +4498,123 @@ static inline int tg3_irq_sync(struct tg3 *tp)
return tp->irq_sync;
}
+static inline void tg3_rd32_loop(struct tg3 *tp, u32 *dst, u32 off, u32 len)
+{
+ int i;
+
+ dst = (u32 *)((u8 *)dst + off);
+ for (i = 0; i < len; i += sizeof(u32))
+ *dst++ = tr32(off + i);
+}
+
+static void tg3_dump_legacy_regs(struct tg3 *tp, u32 *regs)
+{
+ tg3_rd32_loop(tp, regs, TG3PCI_VENDOR, 0xb0);
+ tg3_rd32_loop(tp, regs, MAILBOX_INTERRUPT_0, 0x200);
+ tg3_rd32_loop(tp, regs, MAC_MODE, 0x4f0);
+ tg3_rd32_loop(tp, regs, SNDDATAI_MODE, 0xe0);
+ tg3_rd32_loop(tp, regs, SNDDATAC_MODE, 0x04);
+ tg3_rd32_loop(tp, regs, SNDBDS_MODE, 0x80);
+ tg3_rd32_loop(tp, regs, SNDBDI_MODE, 0x48);
+ tg3_rd32_loop(tp, regs, SNDBDC_MODE, 0x04);
+ tg3_rd32_loop(tp, regs, RCVLPC_MODE, 0x20);
+ tg3_rd32_loop(tp, regs, RCVLPC_SELLST_BASE, 0x15c);
+ tg3_rd32_loop(tp, regs, RCVDBDI_MODE, 0x0c);
+ tg3_rd32_loop(tp, regs, RCVDBDI_JUMBO_BD, 0x3c);
+ tg3_rd32_loop(tp, regs, RCVDBDI_BD_PROD_IDX_0, 0x44);
+ tg3_rd32_loop(tp, regs, RCVDCC_MODE, 0x04);
+ tg3_rd32_loop(tp, regs, RCVBDI_MODE, 0x20);
+ tg3_rd32_loop(tp, regs, RCVCC_MODE, 0x14);
+ tg3_rd32_loop(tp, regs, RCVLSC_MODE, 0x08);
+ tg3_rd32_loop(tp, regs, MBFREE_MODE, 0x08);
+ tg3_rd32_loop(tp, regs, HOSTCC_MODE, 0x100);
+
+ if (tg3_flag(tp, SUPPORT_MSIX))
+ tg3_rd32_loop(tp, regs, HOSTCC_RXCOL_TICKS_VEC1, 0x180);
+
+ tg3_rd32_loop(tp, regs, MEMARB_MODE, 0x10);
+ tg3_rd32_loop(tp, regs, BUFMGR_MODE, 0x58);
+ tg3_rd32_loop(tp, regs, RDMAC_MODE, 0x08);
+ tg3_rd32_loop(tp, regs, WDMAC_MODE, 0x08);
+ tg3_rd32_loop(tp, regs, RX_CPU_MODE, 0x04);
+ tg3_rd32_loop(tp, regs, RX_CPU_STATE, 0x04);
+ tg3_rd32_loop(tp, regs, RX_CPU_PGMCTR, 0x04);
+ tg3_rd32_loop(tp, regs, RX_CPU_HWBKPT, 0x04);
+
+ if (!tg3_flag(tp, 5705_PLUS)) {
+ tg3_rd32_loop(tp, regs, TX_CPU_MODE, 0x04);
+ tg3_rd32_loop(tp, regs, TX_CPU_STATE, 0x04);
+ tg3_rd32_loop(tp, regs, TX_CPU_PGMCTR, 0x04);
+ }
+
+ tg3_rd32_loop(tp, regs, GRCMBOX_INTERRUPT_0, 0x110);
+ tg3_rd32_loop(tp, regs, FTQ_RESET, 0x120);
+ tg3_rd32_loop(tp, regs, MSGINT_MODE, 0x0c);
+ tg3_rd32_loop(tp, regs, DMAC_MODE, 0x04);
+ tg3_rd32_loop(tp, regs, GRC_MODE, 0x4c);
+
+ if (tg3_flag(tp, NVRAM))
+ tg3_rd32_loop(tp, regs, NVRAM_CMD, 0x24);
+}
+
+static void tg3_dump_state(struct tg3 *tp)
+{
+ int i;
+ u32 *regs;
+
+ regs = kzalloc(TG3_REG_BLK_SIZE, GFP_ATOMIC);
+ if (!regs) {
+ netdev_err(tp->dev, "Failed allocating register dump buffer\n");
+ return;
+ }
+
+ if (tg3_flag(tp, PCI_EXPRESS)) {
+ /* Read up to but not including private PCI registers */
+ for (i = 0; i < TG3_PCIE_TLDLPL_PORT; i += sizeof(u32))
+ regs[i / sizeof(u32)] = tr32(i);
+ } else
+ tg3_dump_legacy_regs(tp, regs);
+
+ for (i = 0; i < TG3_REG_BLK_SIZE / sizeof(u32); i += 4) {
+ if (!regs[i + 0] && !regs[i + 1] &&
+ !regs[i + 2] && !regs[i + 3])
+ continue;
+
+ netdev_err(tp->dev, "0x%08x: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
+ i * 4,
+ regs[i + 0], regs[i + 1], regs[i + 2], regs[i + 3]);
+ }
+
+ kfree(regs);
+
+ for (i = 0; i < tp->irq_cnt; i++) {
+ struct tg3_napi *tnapi = &tp->napi[i];
+
+ /* SW status block */
+ netdev_err(tp->dev,
+ "%d: Host status block [%08x:%08x:(%04x:%04x:%04x):(%04x:%04x)]\n",
+ i,
+ tnapi->hw_status->status,
+ tnapi->hw_status->status_tag,
+ tnapi->hw_status->rx_jumbo_consumer,
+ tnapi->hw_status->rx_consumer,
+ tnapi->hw_status->rx_mini_consumer,
+ tnapi->hw_status->idx[0].rx_producer,
+ tnapi->hw_status->idx[0].tx_consumer);
+
+ netdev_err(tp->dev,
+ "%d: NAPI info [%08x:%08x:(%04x:%04x:%04x):%04x:(%04x:%04x:%04x:%04x)]\n",
+ i,
+ tnapi->last_tag, tnapi->last_irq_tag,
+ tnapi->tx_prod, tnapi->tx_cons, tnapi->tx_pending,
+ tnapi->rx_rcb_ptr,
+ tnapi->prodring.rx_std_prod_idx,
+ tnapi->prodring.rx_std_cons_idx,
+ tnapi->prodring.rx_jmb_prod_idx,
+ tnapi->prodring.rx_jmb_cons_idx);
+ }
+}
+
/* This is called whenever we suspect that the system chipset is re-
* ordering the sequence of MMIO to the tx send mailbox. The symptom
* is bogus tx completions. We try to recover by setting the
@@ -4466,7 +4623,7 @@ static inline int tg3_irq_sync(struct tg3 *tp)
*/
static void tg3_tx_recover(struct tg3 *tp)
{
- BUG_ON((tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) ||
+ BUG_ON(tg3_flag(tp, MBOX_WRITE_REORDER) ||
tp->write32_tx_mbox == tg3_write_indirect_mbox);
netdev_warn(tp->dev,
@@ -4476,7 +4633,7 @@ static void tg3_tx_recover(struct tg3 *tp)
"and include system chipset information.\n");
spin_lock(&tp->lock);
- tp->tg3_flags |= TG3_FLAG_TX_RECOVERY_PENDING;
+ tg3_flag_set(tp, TX_RECOVERY_PENDING);
spin_unlock(&tp->lock);
}
@@ -4500,7 +4657,7 @@ static void tg3_tx(struct tg3_napi *tnapi)
struct netdev_queue *txq;
int index = tnapi - tp->napi;
- if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS)
+ if (tg3_flag(tp, ENABLE_TSS))
index--;
txq = netdev_get_tx_queue(tp->dev, index);
@@ -4815,7 +4972,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget)
skb = copy_skb;
}
- if ((tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) &&
+ if ((tp->dev->features & NETIF_F_RXCSUM) &&
(desc->type_flags & RXD_FLAG_TCPUDP_CSUM) &&
(((desc->ip_tcp_csum & RXD_TCPCSUM_MASK)
>> RXD_TCPCSUM_SHIFT) == 0xffff))
@@ -4868,7 +5025,7 @@ next_pkt_nopost:
tw32_rx_mbox(tnapi->consmbox, sw_idx);
/* Refill RX ring(s). */
- if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS)) {
+ if (!tg3_flag(tp, ENABLE_RSS)) {
if (work_mask & RXD_OPAQUE_RING_STD) {
tpr->rx_std_prod_idx = std_prod_idx &
tp->rx_std_ring_mask;
@@ -4901,16 +5058,14 @@ next_pkt_nopost:
static void tg3_poll_link(struct tg3 *tp)
{
/* handle link change and other phy events */
- if (!(tp->tg3_flags &
- (TG3_FLAG_USE_LINKCHG_REG |
- TG3_FLAG_POLL_SERDES))) {
+ if (!(tg3_flag(tp, USE_LINKCHG_REG) || tg3_flag(tp, POLL_SERDES))) {
struct tg3_hw_status *sblk = tp->napi[0].hw_status;
if (sblk->status & SD_STATUS_LINK_CHG) {
sblk->status = SD_STATUS_UPDATED |
(sblk->status & ~SD_STATUS_LINK_CHG);
spin_lock(&tp->lock);
- if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+ if (tg3_flag(tp, USE_PHYLIB)) {
tw32_f(MAC_STATUS,
(MAC_STATUS_SYNC_CHANGED |
MAC_STATUS_CFG_CHANGED |
@@ -5057,7 +5212,7 @@ static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget)
/* run TX completion thread */
if (tnapi->hw_status->idx[0].tx_consumer != tnapi->tx_cons) {
tg3_tx(tnapi);
- if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING))
+ if (unlikely(tg3_flag(tp, TX_RECOVERY_PENDING)))
return work_done;
}
@@ -5068,7 +5223,7 @@ static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget)
if (*(tnapi->rx_rcb_prod_idx) != tnapi->rx_rcb_ptr)
work_done += tg3_rx(tnapi, budget - work_done);
- if ((tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) && tnapi == &tp->napi[1]) {
+ if (tg3_flag(tp, ENABLE_RSS) && tnapi == &tp->napi[1]) {
struct tg3_rx_prodring_set *dpr = &tp->napi[0].prodring;
int i, err = 0;
u32 std_prod_idx = dpr->rx_std_prod_idx;
@@ -5107,7 +5262,7 @@ static int tg3_poll_msix(struct napi_struct *napi, int budget)
while (1) {
work_done = tg3_poll_work(tnapi, work_done, budget);
- if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING))
+ if (unlikely(tg3_flag(tp, TX_RECOVERY_PENDING)))
goto tx_recovery;
if (unlikely(work_done >= budget))
@@ -5141,6 +5296,40 @@ tx_recovery:
return work_done;
}
+static void tg3_process_error(struct tg3 *tp)
+{
+ u32 val;
+ bool real_error = false;
+
+ if (tg3_flag(tp, ERROR_PROCESSED))
+ return;
+
+ /* Check Flow Attention register */
+ val = tr32(HOSTCC_FLOW_ATTN);
+ if (val & ~HOSTCC_FLOW_ATTN_MBUF_LWM) {
+ netdev_err(tp->dev, "FLOW Attention error. Resetting chip.\n");
+ real_error = true;
+ }
+
+ if (tr32(MSGINT_STATUS) & ~MSGINT_STATUS_MSI_REQ) {
+ netdev_err(tp->dev, "MSI Status error. Resetting chip.\n");
+ real_error = true;
+ }
+
+ if (tr32(RDMAC_STATUS) || tr32(WDMAC_STATUS)) {
+ netdev_err(tp->dev, "DMA Status error. Resetting chip.\n");
+ real_error = true;
+ }
+
+ if (!real_error)
+ return;
+
+ tg3_dump_state(tp);
+
+ tg3_flag_set(tp, ERROR_PROCESSED);
+ schedule_work(&tp->reset_task);
+}
+
static int tg3_poll(struct napi_struct *napi, int budget)
{
struct tg3_napi *tnapi = container_of(napi, struct tg3_napi, napi);
@@ -5149,17 +5338,20 @@ static int tg3_poll(struct napi_struct *napi, int budget)
struct tg3_hw_status *sblk = tnapi->hw_status;
while (1) {
+ if (sblk->status & SD_STATUS_ERROR)
+ tg3_process_error(tp);
+
tg3_poll_link(tp);
work_done = tg3_poll_work(tnapi, work_done, budget);
- if (unlikely(tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING))
+ if (unlikely(tg3_flag(tp, TX_RECOVERY_PENDING)))
goto tx_recovery;
if (unlikely(work_done >= budget))
break;
- if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) {
+ if (tg3_flag(tp, TAGGED_STATUS)) {
/* tp->last_tag is used in tg3_int_reenable() below
* to tell the hw how much work has been processed,
* so we must read it before checking for more work.
@@ -5326,7 +5518,7 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id)
* interrupt is ours and will flush the status block.
*/
if (unlikely(!(sblk->status & SD_STATUS_UPDATED))) {
- if ((tp->tg3_flags & TG3_FLAG_CHIP_RESETTING) ||
+ if (tg3_flag(tp, CHIP_RESETTING) ||
(tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) {
handled = 0;
goto out;
@@ -5375,7 +5567,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id)
* interrupt is ours and will flush the status block.
*/
if (unlikely(sblk->status_tag == tnapi->last_irq_tag)) {
- if ((tp->tg3_flags & TG3_FLAG_CHIP_RESETTING) ||
+ if (tg3_flag(tp, CHIP_RESETTING) ||
(tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) {
handled = 0;
goto out;
@@ -5488,14 +5680,14 @@ static void tg3_reset_task(struct work_struct *work)
tg3_full_lock(tp, 1);
- restart_timer = tp->tg3_flags2 & TG3_FLG2_RESTART_TIMER;
- tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER;
+ restart_timer = tg3_flag(tp, RESTART_TIMER);
+ tg3_flag_clear(tp, RESTART_TIMER);
- if (tp->tg3_flags & TG3_FLAG_TX_RECOVERY_PENDING) {
+ if (tg3_flag(tp, TX_RECOVERY_PENDING)) {
tp->write32_tx_mbox = tg3_write32_tx_mbox;
tp->write32_rx_mbox = tg3_write_flush_reg32;
- tp->tg3_flags |= TG3_FLAG_MBOX_WRITE_REORDER;
- tp->tg3_flags &= ~TG3_FLAG_TX_RECOVERY_PENDING;
+ tg3_flag_set(tp, MBOX_WRITE_REORDER);
+ tg3_flag_clear(tp, TX_RECOVERY_PENDING);
}
tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
@@ -5515,21 +5707,13 @@ out:
tg3_phy_start(tp);
}
-static void tg3_dump_short_state(struct tg3 *tp)
-{
- netdev_err(tp->dev, "DEBUG: MAC_TX_STATUS[%08x] MAC_RX_STATUS[%08x]\n",
- tr32(MAC_TX_STATUS), tr32(MAC_RX_STATUS));
- netdev_err(tp->dev, "DEBUG: RDMAC_STATUS[%08x] WDMAC_STATUS[%08x]\n",
- tr32(RDMAC_STATUS), tr32(WDMAC_STATUS));
-}
-
static void tg3_tx_timeout(struct net_device *dev)
{
struct tg3 *tp = netdev_priv(dev);
if (netif_msg_tx_err(tp)) {
netdev_err(dev, "transmit timed out, resetting\n");
- tg3_dump_short_state(tp);
+ tg3_dump_state(tp);
}
schedule_work(&tp->reset_task);
@@ -5548,7 +5732,7 @@ static inline int tg3_40bit_overflow_test(struct tg3 *tp, dma_addr_t mapping,
int len)
{
#if defined(CONFIG_HIGHMEM) && (BITS_PER_LONG == 64)
- if (tp->tg3_flags & TG3_FLAG_40BIT_DMA_BUG)
+ if (tg3_flag(tp, 40BIT_DMA_BUG))
return ((u64) mapping + len) > DMA_BIT_MASK(40);
return 0;
#else
@@ -5556,18 +5740,62 @@ static inline int tg3_40bit_overflow_test(struct tg3 *tp, dma_addr_t mapping,
#endif
}
-static void tg3_set_txd(struct tg3_napi *, int, dma_addr_t, int, u32, u32);
+static void tg3_set_txd(struct tg3_napi *tnapi, int entry,
+ dma_addr_t mapping, int len, u32 flags,
+ u32 mss_and_is_end)
+{
+ struct tg3_tx_buffer_desc *txd = &tnapi->tx_ring[entry];
+ int is_end = (mss_and_is_end & 0x1);
+ u32 mss = (mss_and_is_end >> 1);
+ u32 vlan_tag = 0;
+
+ if (is_end)
+ flags |= TXD_FLAG_END;
+ if (flags & TXD_FLAG_VLAN) {
+ vlan_tag = flags >> 16;
+ flags &= 0xffff;
+ }
+ vlan_tag |= (mss << TXD_MSS_SHIFT);
+
+ txd->addr_hi = ((u64) mapping >> 32);
+ txd->addr_lo = ((u64) mapping & 0xffffffff);
+ txd->len_flags = (len << TXD_LEN_SHIFT) | flags;
+ txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT;
+}
+
+static void tg3_skb_error_unmap(struct tg3_napi *tnapi,
+ struct sk_buff *skb, int last)
+{
+ int i;
+ u32 entry = tnapi->tx_prod;
+ struct ring_info *txb = &tnapi->tx_buffers[entry];
+
+ pci_unmap_single(tnapi->tp->pdev,
+ dma_unmap_addr(txb, mapping),
+ skb_headlen(skb),
+ PCI_DMA_TODEVICE);
+ for (i = 0; i <= last; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+ entry = NEXT_TX(entry);
+ txb = &tnapi->tx_buffers[entry];
+
+ pci_unmap_page(tnapi->tp->pdev,
+ dma_unmap_addr(txb, mapping),
+ frag->size, PCI_DMA_TODEVICE);
+ }
+}
/* Workaround 4GB and 40-bit hardware DMA bugs. */
static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi,
- struct sk_buff *skb, u32 last_plus_one,
- u32 *start, u32 base_flags, u32 mss)
+ struct sk_buff *skb,
+ u32 base_flags, u32 mss)
{
struct tg3 *tp = tnapi->tp;
struct sk_buff *new_skb;
dma_addr_t new_addr = 0;
- u32 entry = *start;
- int i, ret = 0;
+ u32 entry = tnapi->tx_prod;
+ int ret = 0;
if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701)
new_skb = skb_copy(skb, GFP_ATOMIC);
@@ -5583,55 +5811,30 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi,
ret = -1;
} else {
/* New SKB is guaranteed to be linear. */
- entry = *start;
new_addr = pci_map_single(tp->pdev, new_skb->data, new_skb->len,
PCI_DMA_TODEVICE);
/* Make sure the mapping succeeded */
if (pci_dma_mapping_error(tp->pdev, new_addr)) {
ret = -1;
dev_kfree_skb(new_skb);
- new_skb = NULL;
/* Make sure new skb does not cross any 4G boundaries.
* Drop the packet if it does.
*/
- } else if ((tp->tg3_flags3 & TG3_FLG3_4G_DMA_BNDRY_BUG) &&
- tg3_4g_overflow_test(new_addr, new_skb->len)) {
+ } else if (tg3_flag(tp, 4G_DMA_BNDRY_BUG) &&
+ tg3_4g_overflow_test(new_addr, new_skb->len)) {
pci_unmap_single(tp->pdev, new_addr, new_skb->len,
PCI_DMA_TODEVICE);
ret = -1;
dev_kfree_skb(new_skb);
- new_skb = NULL;
} else {
+ tnapi->tx_buffers[entry].skb = new_skb;
+ dma_unmap_addr_set(&tnapi->tx_buffers[entry],
+ mapping, new_addr);
+
tg3_set_txd(tnapi, entry, new_addr, new_skb->len,
base_flags, 1 | (mss << 1));
- *start = NEXT_TX(entry);
- }
- }
-
- /* Now clean up the sw ring entries. */
- i = 0;
- while (entry != last_plus_one) {
- int len;
-
- if (i == 0)
- len = skb_headlen(skb);
- else
- len = skb_shinfo(skb)->frags[i-1].size;
-
- pci_unmap_single(tp->pdev,
- dma_unmap_addr(&tnapi->tx_buffers[entry],
- mapping),
- len, PCI_DMA_TODEVICE);
- if (i == 0) {
- tnapi->tx_buffers[entry].skb = new_skb;
- dma_unmap_addr_set(&tnapi->tx_buffers[entry], mapping,
- new_addr);
- } else {
- tnapi->tx_buffers[entry].skb = NULL;
}
- entry = NEXT_TX(entry);
- i++;
}
dev_kfree_skb(skb);
@@ -5639,202 +5842,7 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi,
return ret;
}
-static void tg3_set_txd(struct tg3_napi *tnapi, int entry,
- dma_addr_t mapping, int len, u32 flags,
- u32 mss_and_is_end)
-{
- struct tg3_tx_buffer_desc *txd = &tnapi->tx_ring[entry];
- int is_end = (mss_and_is_end & 0x1);
- u32 mss = (mss_and_is_end >> 1);
- u32 vlan_tag = 0;
-
- if (is_end)
- flags |= TXD_FLAG_END;
- if (flags & TXD_FLAG_VLAN) {
- vlan_tag = flags >> 16;
- flags &= 0xffff;
- }
- vlan_tag |= (mss << TXD_MSS_SHIFT);
-
- txd->addr_hi = ((u64) mapping >> 32);
- txd->addr_lo = ((u64) mapping & 0xffffffff);
- txd->len_flags = (len << TXD_LEN_SHIFT) | flags;
- txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT;
-}
-
-/* hard_start_xmit for devices that don't have any bugs and
- * support TG3_FLG2_HW_TSO_2 and TG3_FLG2_HW_TSO_3 only.
- */
-static netdev_tx_t tg3_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct tg3 *tp = netdev_priv(dev);
- u32 len, entry, base_flags, mss;
- dma_addr_t mapping;
- struct tg3_napi *tnapi;
- struct netdev_queue *txq;
- unsigned int i, last;
-
- txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
- tnapi = &tp->napi[skb_get_queue_mapping(skb)];
- if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS)
- tnapi++;
-
- /* We are running in BH disabled context with netif_tx_lock
- * and TX reclaim runs via tp->napi.poll inside of a software
- * interrupt. Furthermore, IRQ processing runs lockless so we have
- * no IRQ context deadlocks to worry about either. Rejoice!
- */
- if (unlikely(tg3_tx_avail(tnapi) <= (skb_shinfo(skb)->nr_frags + 1))) {
- if (!netif_tx_queue_stopped(txq)) {
- netif_tx_stop_queue(txq);
-
- /* This is a hard error, log it. */
- netdev_err(dev,
- "BUG! Tx Ring full when queue awake!\n");
- }
- return NETDEV_TX_BUSY;
- }
-
- entry = tnapi->tx_prod;
- base_flags = 0;
- mss = skb_shinfo(skb)->gso_size;
- if (mss) {
- int tcp_opt_len, ip_tcp_len;
- u32 hdrlen;
-
- if (skb_header_cloned(skb) &&
- pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
- dev_kfree_skb(skb);
- goto out_unlock;
- }
-
- if (skb_is_gso_v6(skb)) {
- hdrlen = skb_headlen(skb) - ETH_HLEN;
- } else {
- struct iphdr *iph = ip_hdr(skb);
-
- tcp_opt_len = tcp_optlen(skb);
- ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr);
-
- iph->check = 0;
- iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len);
- hdrlen = ip_tcp_len + tcp_opt_len;
- }
-
- if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) {
- mss |= (hdrlen & 0xc) << 12;
- if (hdrlen & 0x10)
- base_flags |= 0x00000010;
- base_flags |= (hdrlen & 0x3e0) << 5;
- } else
- mss |= hdrlen << 9;
-
- base_flags |= (TXD_FLAG_CPU_PRE_DMA |
- TXD_FLAG_CPU_POST_DMA);
-
- tcp_hdr(skb)->check = 0;
-
- } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
- base_flags |= TXD_FLAG_TCPUDP_CSUM;
- }
-
- if (vlan_tx_tag_present(skb))
- base_flags |= (TXD_FLAG_VLAN |
- (vlan_tx_tag_get(skb) << 16));
-
- len = skb_headlen(skb);
-
- /* Queue skb data, a.k.a. the main skb fragment. */
- mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(tp->pdev, mapping)) {
- dev_kfree_skb(skb);
- goto out_unlock;
- }
-
- tnapi->tx_buffers[entry].skb = skb;
- dma_unmap_addr_set(&tnapi->tx_buffers[entry], mapping, mapping);
-
- if ((tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) &&
- !mss && skb->len > VLAN_ETH_FRAME_LEN)
- base_flags |= TXD_FLAG_JMB_PKT;
-
- tg3_set_txd(tnapi, entry, mapping, len, base_flags,
- (skb_shinfo(skb)->nr_frags == 0) | (mss << 1));
-
- entry = NEXT_TX(entry);
-
- /* Now loop through additional data fragments, and queue them. */
- if (skb_shinfo(skb)->nr_frags > 0) {
- last = skb_shinfo(skb)->nr_frags - 1;
- for (i = 0; i <= last; i++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-
- len = frag->size;
- mapping = pci_map_page(tp->pdev,
- frag->page,
- frag->page_offset,
- len, PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(tp->pdev, mapping))
- goto dma_error;
-
- tnapi->tx_buffers[entry].skb = NULL;
- dma_unmap_addr_set(&tnapi->tx_buffers[entry], mapping,
- mapping);
-
- tg3_set_txd(tnapi, entry, mapping, len,
- base_flags, (i == last) | (mss << 1));
-
- entry = NEXT_TX(entry);
- }
- }
-
- /* Packets are ready, update Tx producer idx local and on card. */
- tw32_tx_mbox(tnapi->prodmbox, entry);
-
- 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);
- }
-
-out_unlock:
- mmiowb();
-
- return NETDEV_TX_OK;
-
-dma_error:
- last = i;
- entry = tnapi->tx_prod;
- tnapi->tx_buffers[entry].skb = NULL;
- pci_unmap_single(tp->pdev,
- dma_unmap_addr(&tnapi->tx_buffers[entry], mapping),
- skb_headlen(skb),
- PCI_DMA_TODEVICE);
- for (i = 0; i <= last; i++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- entry = NEXT_TX(entry);
-
- pci_unmap_page(tp->pdev,
- dma_unmap_addr(&tnapi->tx_buffers[entry],
- mapping),
- frag->size, PCI_DMA_TODEVICE);
- }
-
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
-}
-
-static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *,
- struct net_device *);
+static netdev_tx_t tg3_start_xmit(struct sk_buff *, struct net_device *);
/* Use GSO to workaround a rare TSO bug that may be triggered when the
* TSO header is greater than 80 bytes.
@@ -5868,7 +5876,7 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb)
nskb = segs;
segs = segs->next;
nskb->next = NULL;
- tg3_start_xmit_dma_bug(nskb, tp->dev);
+ tg3_start_xmit(nskb, tp->dev);
} while (segs);
tg3_tso_bug_end:
@@ -5878,22 +5886,21 @@ tg3_tso_bug_end:
}
/* hard_start_xmit for devices that have the 4G bug and/or 40-bit bug and
- * support TG3_FLG2_HW_TSO_1 or firmware TSO only.
+ * support TG3_FLAG_HW_TSO_1 or firmware TSO only.
*/
-static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
- struct net_device *dev)
+static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct tg3 *tp = netdev_priv(dev);
u32 len, entry, base_flags, mss;
- int would_hit_hwbug;
+ int i = -1, would_hit_hwbug;
dma_addr_t mapping;
struct tg3_napi *tnapi;
struct netdev_queue *txq;
- unsigned int i, last;
+ unsigned int last;
txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
tnapi = &tp->napi[skb_get_queue_mapping(skb)];
- if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS)
+ if (tg3_flag(tp, ENABLE_TSS))
tnapi++;
/* We are running in BH disabled context with netif_tx_lock
@@ -5944,13 +5951,15 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
}
if (unlikely((ETH_HLEN + hdr_len) > 80) &&
- (tp->tg3_flags2 & TG3_FLG2_TSO_BUG))
+ tg3_flag(tp, TSO_BUG))
return tg3_tso_bug(tp, skb);
base_flags |= (TXD_FLAG_CPU_PRE_DMA |
TXD_FLAG_CPU_POST_DMA);
- if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) {
+ if (tg3_flag(tp, HW_TSO_1) ||
+ tg3_flag(tp, HW_TSO_2) ||
+ tg3_flag(tp, HW_TSO_3)) {
tcp_hdr(skb)->check = 0;
base_flags &= ~TXD_FLAG_TCPUDP_CSUM;
} else
@@ -5959,14 +5968,14 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
IPPROTO_TCP,
0);
- if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) {
+ if (tg3_flag(tp, HW_TSO_3)) {
mss |= (hdr_len & 0xc) << 12;
if (hdr_len & 0x10)
base_flags |= 0x00000010;
base_flags |= (hdr_len & 0x3e0) << 5;
- } else if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_2)
+ } else if (tg3_flag(tp, HW_TSO_2))
mss |= hdr_len << 9;
- else if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_1) ||
+ else if (tg3_flag(tp, HW_TSO_1) ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
if (tcp_opt_len || iph->ihl > 5) {
int tsflags;
@@ -5988,7 +5997,7 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
base_flags |= (TXD_FLAG_VLAN |
(vlan_tx_tag_get(skb) << 16));
- if ((tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) &&
+ if (tg3_flag(tp, USE_JUMBO_BDFLAG) &&
!mss && skb->len > VLAN_ETH_FRAME_LEN)
base_flags |= TXD_FLAG_JMB_PKT;
@@ -6005,18 +6014,18 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
would_hit_hwbug = 0;
- if ((tp->tg3_flags3 & TG3_FLG3_SHORT_DMA_BUG) && len <= 8)
+ if (tg3_flag(tp, SHORT_DMA_BUG) && len <= 8)
would_hit_hwbug = 1;
- if ((tp->tg3_flags3 & TG3_FLG3_4G_DMA_BNDRY_BUG) &&
+ if (tg3_flag(tp, 4G_DMA_BNDRY_BUG) &&
tg3_4g_overflow_test(mapping, len))
would_hit_hwbug = 1;
- if ((tp->tg3_flags3 & TG3_FLG3_40BIT_DMA_LIMIT_BUG) &&
+ if (tg3_flag(tp, 40BIT_DMA_LIMIT_BUG) &&
tg3_40bit_overflow_test(tp, mapping, len))
would_hit_hwbug = 1;
- if (tp->tg3_flags3 & TG3_FLG3_5701_DMA_BUG)
+ if (tg3_flag(tp, 5701_DMA_BUG))
would_hit_hwbug = 1;
tg3_set_txd(tnapi, entry, mapping, len, base_flags,
@@ -6042,19 +6051,21 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
if (pci_dma_mapping_error(tp->pdev, mapping))
goto dma_error;
- if ((tp->tg3_flags3 & TG3_FLG3_SHORT_DMA_BUG) &&
+ if (tg3_flag(tp, SHORT_DMA_BUG) &&
len <= 8)
would_hit_hwbug = 1;
- if ((tp->tg3_flags3 & TG3_FLG3_4G_DMA_BNDRY_BUG) &&
+ if (tg3_flag(tp, 4G_DMA_BNDRY_BUG) &&
tg3_4g_overflow_test(mapping, len))
would_hit_hwbug = 1;
- if ((tp->tg3_flags3 & TG3_FLG3_40BIT_DMA_LIMIT_BUG) &&
+ if (tg3_flag(tp, 40BIT_DMA_LIMIT_BUG) &&
tg3_40bit_overflow_test(tp, mapping, len))
would_hit_hwbug = 1;
- if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
+ if (tg3_flag(tp, HW_TSO_1) ||
+ tg3_flag(tp, HW_TSO_2) ||
+ tg3_flag(tp, HW_TSO_3))
tg3_set_txd(tnapi, entry, mapping, len,
base_flags, (i == last)|(mss << 1));
else
@@ -6066,20 +6077,15 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
}
if (would_hit_hwbug) {
- u32 last_plus_one = entry;
- u32 start;
-
- start = entry - 1 - skb_shinfo(skb)->nr_frags;
- start &= (TG3_TX_RING_SIZE - 1);
+ tg3_skb_error_unmap(tnapi, skb, i);
/* If the workaround fails due to memory/mapping
* failure, silently drop this packet.
*/
- if (tigon3_dma_hwbug_workaround(tnapi, skb, last_plus_one,
- &start, base_flags, mss))
+ if (tigon3_dma_hwbug_workaround(tnapi, skb, base_flags, mss))
goto out_unlock;
- entry = start;
+ entry = NEXT_TX(tnapi->tx_prod);
}
/* Packets are ready, update Tx producer idx local and on card. */
@@ -6105,25 +6111,66 @@ out_unlock:
return NETDEV_TX_OK;
dma_error:
- last = i;
- entry = tnapi->tx_prod;
- tnapi->tx_buffers[entry].skb = NULL;
- pci_unmap_single(tp->pdev,
- dma_unmap_addr(&tnapi->tx_buffers[entry], mapping),
- skb_headlen(skb),
- PCI_DMA_TODEVICE);
- for (i = 0; i <= last; i++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- entry = NEXT_TX(entry);
+ tg3_skb_error_unmap(tnapi, skb, i);
+ dev_kfree_skb(skb);
+ tnapi->tx_buffers[tnapi->tx_prod].skb = NULL;
+ return NETDEV_TX_OK;
+}
- pci_unmap_page(tp->pdev,
- dma_unmap_addr(&tnapi->tx_buffers[entry],
- mapping),
- frag->size, PCI_DMA_TODEVICE);
+static void tg3_set_loopback(struct net_device *dev, u32 features)
+{
+ struct tg3 *tp = netdev_priv(dev);
+
+ if (features & NETIF_F_LOOPBACK) {
+ if (tp->mac_mode & MAC_MODE_PORT_INT_LPBACK)
+ return;
+
+ /*
+ * Clear MAC_MODE_HALF_DUPLEX or you won't get packets back in
+ * loopback mode if Half-Duplex mode was negotiated earlier.
+ */
+ tp->mac_mode &= ~MAC_MODE_HALF_DUPLEX;
+
+ /* Enable internal MAC loopback mode */
+ tp->mac_mode |= MAC_MODE_PORT_INT_LPBACK;
+ spin_lock_bh(&tp->lock);
+ tw32(MAC_MODE, tp->mac_mode);
+ netif_carrier_on(tp->dev);
+ spin_unlock_bh(&tp->lock);
+ netdev_info(dev, "Internal MAC loopback mode enabled.\n");
+ } else {
+ if (!(tp->mac_mode & MAC_MODE_PORT_INT_LPBACK))
+ return;
+
+ /* Disable internal MAC loopback mode */
+ tp->mac_mode &= ~MAC_MODE_PORT_INT_LPBACK;
+ spin_lock_bh(&tp->lock);
+ tw32(MAC_MODE, tp->mac_mode);
+ /* Force link status check */
+ tg3_setup_phy(tp, 1);
+ spin_unlock_bh(&tp->lock);
+ netdev_info(dev, "Internal MAC loopback mode disabled.\n");
}
+}
- dev_kfree_skb(skb);
- return NETDEV_TX_OK;
+static u32 tg3_fix_features(struct net_device *dev, u32 features)
+{
+ struct tg3 *tp = netdev_priv(dev);
+
+ if (dev->mtu > ETH_DATA_LEN && tg3_flag(tp, 5780_CLASS))
+ features &= ~NETIF_F_ALL_TSO;
+
+ return features;
+}
+
+static int tg3_set_features(struct net_device *dev, u32 features)
+{
+ u32 changed = dev->features ^ features;
+
+ if ((changed & NETIF_F_LOOPBACK) && netif_running(dev))
+ tg3_set_loopback(dev, features);
+
+ return 0;
}
static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp,
@@ -6132,16 +6179,18 @@ static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp,
dev->mtu = new_mtu;
if (new_mtu > ETH_DATA_LEN) {
- if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) {
- tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE;
- ethtool_op_set_tso(dev, 0);
+ if (tg3_flag(tp, 5780_CLASS)) {
+ netdev_update_features(dev);
+ tg3_flag_clear(tp, TSO_CAPABLE);
} else {
- tp->tg3_flags |= TG3_FLAG_JUMBO_RING_ENABLE;
+ tg3_flag_set(tp, JUMBO_RING_ENABLE);
}
} else {
- if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)
- tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE;
- tp->tg3_flags &= ~TG3_FLAG_JUMBO_RING_ENABLE;
+ if (tg3_flag(tp, 5780_CLASS)) {
+ tg3_flag_set(tp, TSO_CAPABLE);
+ netdev_update_features(dev);
+ }
+ tg3_flag_clear(tp, JUMBO_RING_ENABLE);
}
}
@@ -6195,7 +6244,7 @@ static void tg3_rx_prodring_free(struct tg3 *tp,
tg3_rx_skb_free(tp, &tpr->rx_std_buffers[i],
tp->rx_pkt_map_sz);
- if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) {
+ if (tg3_flag(tp, JUMBO_CAPABLE)) {
for (i = tpr->rx_jmb_cons_idx;
i != tpr->rx_jmb_prod_idx;
i = (i + 1) & tp->rx_jmb_ring_mask) {
@@ -6211,8 +6260,7 @@ static void tg3_rx_prodring_free(struct tg3 *tp,
tg3_rx_skb_free(tp, &tpr->rx_std_buffers[i],
tp->rx_pkt_map_sz);
- if ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) &&
- !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
+ if (tg3_flag(tp, JUMBO_CAPABLE) && !tg3_flag(tp, 5780_CLASS)) {
for (i = 0; i <= tp->rx_jmb_ring_mask; i++)
tg3_rx_skb_free(tp, &tpr->rx_jmb_buffers[i],
TG3_RX_JMB_MAP_SZ);
@@ -6249,7 +6297,7 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp,
memset(tpr->rx_std, 0, TG3_RX_STD_RING_BYTES(tp));
rx_pkt_dma_sz = TG3_RX_STD_DMA_SZ;
- if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) &&
+ if (tg3_flag(tp, 5780_CLASS) &&
tp->dev->mtu > ETH_DATA_LEN)
rx_pkt_dma_sz = TG3_RX_JMB_DMA_SZ;
tp->rx_pkt_map_sz = TG3_RX_DMA_TO_MAP_SZ(rx_pkt_dma_sz);
@@ -6282,13 +6330,12 @@ static int tg3_rx_prodring_alloc(struct tg3 *tp,
}
}
- if (!(tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) ||
- (tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
+ if (!tg3_flag(tp, JUMBO_CAPABLE) || tg3_flag(tp, 5780_CLASS))
goto done;
memset(tpr->rx_jmb, 0, TG3_RX_JMB_RING_BYTES(tp));
- if (!(tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE))
+ if (!tg3_flag(tp, JUMBO_RING_ENABLE))
goto done;
for (i = 0; i <= tp->rx_jmb_ring_mask; i++) {
@@ -6357,8 +6404,7 @@ static int tg3_rx_prodring_init(struct tg3 *tp,
if (!tpr->rx_std)
goto err_out;
- if ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) &&
- !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
+ if (tg3_flag(tp, JUMBO_CAPABLE) && !tg3_flag(tp, 5780_CLASS)) {
tpr->rx_jmb_buffers = kzalloc(TG3_RX_JMB_BUFF_RING_SIZE(tp),
GFP_KERNEL);
if (!tpr->rx_jmb_buffers)
@@ -6556,8 +6602,8 @@ static int tg3_alloc_consistent(struct tg3 *tp)
/* If multivector TSS is enabled, vector 0 does not handle
* tx interrupts. Don't allocate any resources for it.
*/
- if ((!i && !(tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS)) ||
- (i && (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS))) {
+ if ((!i && !tg3_flag(tp, ENABLE_TSS)) ||
+ (i && tg3_flag(tp, ENABLE_TSS))) {
tnapi->tx_buffers = kzalloc(sizeof(struct ring_info) *
TG3_TX_RING_SIZE,
GFP_KERNEL);
@@ -6597,7 +6643,7 @@ static int tg3_alloc_consistent(struct tg3 *tp)
* If multivector RSS is enabled, vector 0 does not handle
* rx or tx interrupts. Don't allocate any resources for it.
*/
- if (!i && (tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS))
+ if (!i && tg3_flag(tp, ENABLE_RSS))
continue;
tnapi->rx_rcb = dma_alloc_coherent(&tp->pdev->dev,
@@ -6627,7 +6673,7 @@ static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit, int
unsigned int i;
u32 val;
- if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
+ if (tg3_flag(tp, 5705_PLUS)) {
switch (ofs) {
case RCVLSC_MODE:
case DMAC_MODE:
@@ -6737,7 +6783,7 @@ static void tg3_ape_send_event(struct tg3 *tp, u32 event)
u32 apedata;
/* NCSI does not support APE events */
- if (tp->tg3_flags3 & TG3_FLG3_APE_HAS_NCSI)
+ if (tg3_flag(tp, APE_HAS_NCSI))
return;
apedata = tg3_ape_read32(tp, TG3_APE_SEG_SIG);
@@ -6776,7 +6822,7 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind)
u32 event;
u32 apedata;
- if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
+ if (!tg3_flag(tp, ENABLE_APE))
return;
switch (kind) {
@@ -6805,7 +6851,7 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind)
tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG, 0x0);
if (device_may_wakeup(&tp->pdev->dev) &&
- (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)) {
+ tg3_flag(tp, WOL_ENABLE)) {
tg3_ape_write32(tp, TG3_APE_HOST_WOL_SPEED,
TG3_APE_HOST_WOL_SPEED_AUTO);
apedata = TG3_APE_HOST_DRVR_STATE_WOL;
@@ -6834,7 +6880,7 @@ static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind)
tg3_write_mem(tp, NIC_SRAM_FIRMWARE_MBOX,
NIC_SRAM_FIRMWARE_MBOX_MAGIC1);
- if (tp->tg3_flags2 & TG3_FLG2_ASF_NEW_HANDSHAKE) {
+ if (tg3_flag(tp, ASF_NEW_HANDSHAKE)) {
switch (kind) {
case RESET_KIND_INIT:
tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
@@ -6864,7 +6910,7 @@ static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind)
/* tp->lock is held. */
static void tg3_write_sig_post_reset(struct tg3 *tp, int kind)
{
- if (tp->tg3_flags2 & TG3_FLG2_ASF_NEW_HANDSHAKE) {
+ if (tg3_flag(tp, ASF_NEW_HANDSHAKE)) {
switch (kind) {
case RESET_KIND_INIT:
tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
@@ -6888,7 +6934,7 @@ static void tg3_write_sig_post_reset(struct tg3 *tp, int kind)
/* tp->lock is held. */
static void tg3_write_sig_legacy(struct tg3 *tp, int kind)
{
- if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
+ if (tg3_flag(tp, ENABLE_ASF)) {
switch (kind) {
case RESET_KIND_INIT:
tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
@@ -6939,9 +6985,8 @@ static int tg3_poll_fw(struct tg3 *tp)
* of the above loop as an error, but do report the lack of
* running firmware once.
*/
- if (i >= 100000 &&
- !(tp->tg3_flags2 & TG3_FLG2_NO_FWARE_REPORTED)) {
- tp->tg3_flags2 |= TG3_FLG2_NO_FWARE_REPORTED;
+ if (i >= 100000 && !tg3_flag(tp, NO_FWARE_REPORTED)) {
+ tg3_flag_set(tp, NO_FWARE_REPORTED);
netdev_info(tp->dev, "No firmware running\n");
}
@@ -6974,10 +7019,10 @@ static void tg3_restore_pci_state(struct tg3 *tp)
/* Set MAX PCI retry to zero. */
val = (PCISTATE_ROM_ENABLE | PCISTATE_ROM_RETRY_ENABLE);
if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
- (tp->tg3_flags & TG3_FLAG_PCIX_MODE))
+ tg3_flag(tp, PCIX_MODE))
val |= PCISTATE_RETRY_SAME_DMA;
/* Allow reads and writes to the APE register and memory space. */
- if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
+ if (tg3_flag(tp, ENABLE_APE))
val |= PCISTATE_ALLOW_APE_CTLSPC_WR |
PCISTATE_ALLOW_APE_SHMEM_WR |
PCISTATE_ALLOW_APE_PSPACE_WR;
@@ -6986,7 +7031,7 @@ static void tg3_restore_pci_state(struct tg3 *tp)
pci_write_config_word(tp->pdev, PCI_COMMAND, tp->pci_cmd);
if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) {
- if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)
+ if (tg3_flag(tp, PCI_EXPRESS))
pcie_set_readrq(tp->pdev, tp->pcie_readrq);
else {
pci_write_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE,
@@ -6997,7 +7042,7 @@ static void tg3_restore_pci_state(struct tg3 *tp)
}
/* Make sure PCI-X relaxed ordering bit is clear. */
- if (tp->tg3_flags & TG3_FLAG_PCIX_MODE) {
+ if (tg3_flag(tp, PCIX_MODE)) {
u16 pcix_cmd;
pci_read_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD,
@@ -7007,12 +7052,12 @@ static void tg3_restore_pci_state(struct tg3 *tp)
pcix_cmd);
}
- if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) {
+ if (tg3_flag(tp, 5780_CLASS)) {
/* Chip reset on 5780 will reset MSI enable bit,
* so need to restore it.
*/
- if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
+ if (tg3_flag(tp, USING_MSI)) {
u16 ctrl;
pci_read_config_word(tp->pdev,
@@ -7052,7 +7097,7 @@ static int tg3_chip_reset(struct tg3 *tp)
tg3_save_pci_state(tp);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
- (tp->tg3_flags3 & TG3_FLG3_5755_PLUS))
+ tg3_flag(tp, 5755_PLUS))
tw32(GRC_FASTBOOT_PC, 0);
/*
@@ -7071,7 +7116,7 @@ static int tg3_chip_reset(struct tg3 *tp)
* at this time, but the irq handler may still be called due to irq
* sharing or irqpoll.
*/
- tp->tg3_flags |= TG3_FLAG_CHIP_RESETTING;
+ tg3_flag_set(tp, CHIP_RESETTING);
for (i = 0; i < tp->irq_cnt; i++) {
struct tg3_napi *tnapi = &tp->napi[i];
if (tnapi->hw_status) {
@@ -7094,10 +7139,10 @@ static int tg3_chip_reset(struct tg3 *tp)
/* do the reset */
val = GRC_MISC_CFG_CORECLK_RESET;
- if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
+ if (tg3_flag(tp, PCI_EXPRESS)) {
/* Force PCIe 1.0a mode */
if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 &&
- !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS) &&
+ !tg3_flag(tp, 57765_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);
@@ -7115,8 +7160,7 @@ static int tg3_chip_reset(struct tg3 *tp)
}
/* Manage gphy power for all CPMU absent PCIe devices. */
- if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) &&
- !(tp->tg3_flags & TG3_FLAG_CPMU_PRESENT))
+ if (tg3_flag(tp, 5705_PLUS) && !tg3_flag(tp, CPMU_PRESENT))
val |= GRC_MISC_CFG_KEEP_GPHY_POWER;
tw32(GRC_MISC_CFG, val);
@@ -7149,7 +7193,7 @@ static int tg3_chip_reset(struct tg3 *tp)
udelay(120);
- if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && tp->pcie_cap) {
+ if (tg3_flag(tp, PCI_EXPRESS) && tp->pcie_cap) {
u16 val16;
if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A0) {
@@ -7175,7 +7219,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))
+ if (!tg3_flag(tp, CPMU_PRESENT))
val16 &= ~PCI_EXP_DEVCTL_PAYLOAD;
pci_write_config_word(tp->pdev,
tp->pcie_cap + PCI_EXP_DEVCTL,
@@ -7194,10 +7238,11 @@ static int tg3_chip_reset(struct tg3 *tp)
tg3_restore_pci_state(tp);
- tp->tg3_flags &= ~TG3_FLAG_CHIP_RESETTING;
+ tg3_flag_clear(tp, CHIP_RESETTING);
+ tg3_flag_clear(tp, ERROR_PROCESSED);
val = 0;
- if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)
+ if (tg3_flag(tp, 5780_CLASS))
val = tr32(MEMARB_MODE);
tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE);
@@ -7222,7 +7267,7 @@ static int tg3_chip_reset(struct tg3 *tp)
tw32(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
}
- if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
+ if (tg3_flag(tp, ENABLE_APE))
tp->mac_mode = MAC_MODE_APE_TX_EN |
MAC_MODE_APE_RX_EN |
MAC_MODE_TDE_ENABLE;
@@ -7247,28 +7292,33 @@ static int tg3_chip_reset(struct tg3 *tp)
tg3_mdio_start(tp);
- if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) &&
+ if (tg3_flag(tp, PCI_EXPRESS) &&
tp->pci_chip_rev_id != CHIPREV_ID_5750_A0 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 &&
- !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) {
+ !tg3_flag(tp, 57765_PLUS)) {
val = tr32(0x7c00);
tw32(0x7c00, val | (1 << 25));
}
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) {
+ val = tr32(TG3_CPMU_CLCK_ORIDE);
+ tw32(TG3_CPMU_CLCK_ORIDE, val & ~CPMU_CLCK_ORIDE_MAC_ORIDE_EN);
+ }
+
/* Reprobe ASF enable state. */
- tp->tg3_flags &= ~TG3_FLAG_ENABLE_ASF;
- tp->tg3_flags2 &= ~TG3_FLG2_ASF_NEW_HANDSHAKE;
+ tg3_flag_clear(tp, ENABLE_ASF);
+ tg3_flag_clear(tp, ASF_NEW_HANDSHAKE);
tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val);
if (val == NIC_SRAM_DATA_SIG_MAGIC) {
u32 nic_cfg;
tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg);
if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE) {
- tp->tg3_flags |= TG3_FLAG_ENABLE_ASF;
+ tg3_flag_set(tp, ENABLE_ASF);
tp->last_event_jiffies = jiffies;
- if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
- tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE;
+ if (tg3_flag(tp, 5750_PLUS))
+ tg3_flag_set(tp, ASF_NEW_HANDSHAKE);
}
}
@@ -7278,8 +7328,7 @@ static int tg3_chip_reset(struct tg3 *tp)
/* tp->lock is held. */
static void tg3_stop_fw(struct tg3 *tp)
{
- if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
- !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) {
+ if (tg3_flag(tp, ENABLE_ASF) && !tg3_flag(tp, ENABLE_APE)) {
/* Wait for RX cpu to ACK the previous event. */
tg3_wait_for_event_ack(tp);
@@ -7325,8 +7374,7 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
{
int i;
- BUG_ON(offset == TX_CPU_BASE &&
- (tp->tg3_flags2 & TG3_FLG2_5705_PLUS));
+ BUG_ON(offset == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS));
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
u32 val = tr32(GRC_VCPU_EXT_CTRL);
@@ -7361,7 +7409,7 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
}
/* Clear firmware's nvram arbitration. */
- if (tp->tg3_flags & TG3_FLAG_NVRAM)
+ if (tg3_flag(tp, NVRAM))
tw32(NVRAM_SWARB, SWARB_REQ_CLR0);
return 0;
}
@@ -7379,15 +7427,14 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, u32 cpu_scratch_b
int err, lock_err, i;
void (*write_op)(struct tg3 *, u32, u32);
- if (cpu_base == TX_CPU_BASE &&
- (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
+ if (cpu_base == TX_CPU_BASE && tg3_flag(tp, 5705_PLUS)) {
netdev_err(tp->dev,
"%s: Trying to load TX cpu firmware which is 5705\n",
__func__);
return -EINVAL;
}
- if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
+ if (tg3_flag(tp, 5705_PLUS))
write_op = tg3_write_mem;
else
write_op = tg3_write_indirect_reg32;
@@ -7473,8 +7520,6 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
return 0;
}
-/* 5705 needs a special version of the TSO firmware. */
-
/* tp->lock is held. */
static int tg3_load_tso_firmware(struct tg3 *tp)
{
@@ -7483,7 +7528,9 @@ static int tg3_load_tso_firmware(struct tg3 *tp)
unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size;
int err, i;
- if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
+ if (tg3_flag(tp, HW_TSO_1) ||
+ tg3_flag(tp, HW_TSO_2) ||
+ tg3_flag(tp, HW_TSO_3))
return 0;
fw_data = (void *)tp->fw->data;
@@ -7552,7 +7599,7 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p)
if (!netif_running(dev))
return 0;
- if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
+ if (tg3_flag(tp, ENABLE_ASF)) {
u32 addr0_high, addr0_low, addr1_high, addr1_low;
addr0_high = tr32(MAC_ADDR_0_HIGH);
@@ -7587,7 +7634,7 @@ static void tg3_set_bdinfo(struct tg3 *tp, u32 bdinfo_addr,
(bdinfo_addr + TG3_BDINFO_MAXLEN_FLAGS),
maxlen_flags);
- if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
+ if (!tg3_flag(tp, 5705_PLUS))
tg3_write_mem(tp,
(bdinfo_addr + TG3_BDINFO_NIC_ADDR),
nic_addr);
@@ -7598,7 +7645,7 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec)
{
int i;
- if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS)) {
+ if (!tg3_flag(tp, ENABLE_TSS)) {
tw32(HOSTCC_TXCOL_TICKS, ec->tx_coalesce_usecs);
tw32(HOSTCC_TXMAX_FRAMES, ec->tx_max_coalesced_frames);
tw32(HOSTCC_TXCOAL_MAXF_INT, ec->tx_max_coalesced_frames_irq);
@@ -7608,7 +7655,7 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec)
tw32(HOSTCC_TXCOAL_MAXF_INT, 0);
}
- if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS)) {
+ if (!tg3_flag(tp, 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);
@@ -7618,7 +7665,7 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec)
tw32(HOSTCC_RXCOAL_MAXF_INT, 0);
}
- if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
+ if (!tg3_flag(tp, 5705_PLUS)) {
u32 val = ec->stats_block_coalesce_usecs;
tw32(HOSTCC_RXCOAL_TICK_INT, ec->rx_coalesce_usecs_irq);
@@ -7640,7 +7687,7 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec)
reg = HOSTCC_RXCOAL_MAXF_INT_VEC1 + i * 0x18;
tw32(reg, ec->rx_max_coalesced_frames_irq);
- if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) {
+ if (tg3_flag(tp, ENABLE_TSS)) {
reg = HOSTCC_TXCOL_TICKS_VEC1 + i * 0x18;
tw32(reg, ec->tx_coalesce_usecs);
reg = HOSTCC_TXMAX_FRAMES_VEC1 + i * 0x18;
@@ -7655,7 +7702,7 @@ static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec)
tw32(HOSTCC_RXMAX_FRAMES_VEC1 + i * 0x18, 0);
tw32(HOSTCC_RXCOAL_MAXF_INT_VEC1 + i * 0x18, 0);
- if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS) {
+ if (tg3_flag(tp, ENABLE_TSS)) {
tw32(HOSTCC_TXCOL_TICKS_VEC1 + i * 0x18, 0);
tw32(HOSTCC_TXMAX_FRAMES_VEC1 + i * 0x18, 0);
tw32(HOSTCC_TXCOAL_MAXF_INT_VEC1 + i * 0x18, 0);
@@ -7671,10 +7718,9 @@ static void tg3_rings_reset(struct tg3 *tp)
struct tg3_napi *tnapi = &tp->napi[0];
/* Disable all transmit rings but the first. */
- if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
+ if (!tg3_flag(tp, 5705_PLUS))
limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 16;
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
+ else if (tg3_flag(tp, 5717_PLUS))
limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 4;
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
limit = NIC_SRAM_SEND_RCB + TG3_BDINFO_SIZE * 2;
@@ -7688,10 +7734,9 @@ 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 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
+ if (tg3_flag(tp, 5717_PLUS))
limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 17;
- else if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
+ else if (!tg3_flag(tp, 5705_PLUS))
limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 16;
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
@@ -7708,16 +7753,16 @@ static void tg3_rings_reset(struct tg3 *tp)
tw32_mailbox_f(tp->napi[0].int_mbox, 1);
/* Zero mailbox registers. */
- if (tp->tg3_flags & TG3_FLAG_SUPPORT_MSIX) {
+ if (tg3_flag(tp, SUPPORT_MSIX)) {
for (i = 1; i < tp->irq_max; i++) {
tp->napi[i].tx_prod = 0;
tp->napi[i].tx_cons = 0;
- if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS)
+ if (tg3_flag(tp, ENABLE_TSS))
tw32_mailbox(tp->napi[i].prodmbox, 0);
tw32_rx_mbox(tp->napi[i].consmbox, 0);
tw32_mailbox_f(tp->napi[i].int_mbox, 1);
}
- if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS))
+ if (!tg3_flag(tp, ENABLE_TSS))
tw32_mailbox(tp->napi[0].prodmbox, 0);
} else {
tp->napi[0].tx_prod = 0;
@@ -7727,7 +7772,7 @@ static void tg3_rings_reset(struct tg3 *tp)
}
/* Make sure the NIC-based send BD rings are disabled. */
- if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
+ if (!tg3_flag(tp, 5705_PLUS)) {
u32 mbox = MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW;
for (i = 0; i < 16; i++)
tw32_tx_mbox(mbox + i * 8, 0);
@@ -7787,6 +7832,47 @@ static void tg3_rings_reset(struct tg3 *tp)
}
}
+static void tg3_setup_rxbd_thresholds(struct tg3 *tp)
+{
+ u32 val, bdcache_maxcnt, host_rep_thresh, nic_rep_thresh;
+
+ if (!tg3_flag(tp, 5750_PLUS) ||
+ tg3_flag(tp, 5780_CLASS) ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752)
+ bdcache_maxcnt = TG3_SRAM_RX_STD_BDCACHE_SIZE_5700;
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+ bdcache_maxcnt = TG3_SRAM_RX_STD_BDCACHE_SIZE_5755;
+ else
+ bdcache_maxcnt = TG3_SRAM_RX_STD_BDCACHE_SIZE_5906;
+
+ nic_rep_thresh = min(bdcache_maxcnt / 2, tp->rx_std_max_post);
+ host_rep_thresh = max_t(u32, tp->rx_pending / 8, 1);
+
+ val = min(nic_rep_thresh, host_rep_thresh);
+ tw32(RCVBDI_STD_THRESH, val);
+
+ if (tg3_flag(tp, 57765_PLUS))
+ tw32(STD_REPLENISH_LWM, bdcache_maxcnt);
+
+ if (!tg3_flag(tp, JUMBO_CAPABLE) || tg3_flag(tp, 5780_CLASS))
+ return;
+
+ if (!tg3_flag(tp, 5705_PLUS))
+ bdcache_maxcnt = TG3_SRAM_RX_JMB_BDCACHE_SIZE_5700;
+ else
+ bdcache_maxcnt = TG3_SRAM_RX_JMB_BDCACHE_SIZE_5717;
+
+ host_rep_thresh = max_t(u32, tp->rx_jumbo_pending / 8, 1);
+
+ val = min(bdcache_maxcnt / 2, host_rep_thresh);
+ tw32(RCVBDI_JUMBO_THRESH, val);
+
+ if (tg3_flag(tp, 57765_PLUS))
+ tw32(JMB_REPLENISH_LWM, bdcache_maxcnt);
+}
+
/* tp->lock is held. */
static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
{
@@ -7800,7 +7886,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tg3_write_sig_pre_reset(tp, RESET_KIND_INIT);
- if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE)
+ if (tg3_flag(tp, INIT_COMPLETE))
tg3_abort_hw(tp, 1);
/* Enable MAC control of LPI */
@@ -7820,7 +7906,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717)
val |= TG3_CPMU_EEEMD_SND_IDX_DET_EN;
- if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
+ if (tg3_flag(tp, ENABLE_APE))
val |= TG3_CPMU_EEEMD_APE_TX_DET_EN;
tw32_f(TG3_CPMU_EEE_MODE, val);
@@ -7879,7 +7965,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(TG3_PCIE_LNKCTL, val | TG3_PCIE_LNKCTL_L1_PLL_PD_DIS);
}
- if (tp->tg3_flags3 & TG3_FLG3_L1PLLPD_EN) {
+ if (tg3_flag(tp, L1PLLPD_EN)) {
u32 grc_mode = tr32(GRC_MODE);
/* Access the lower 1K of PL PCIE block registers. */
@@ -7909,6 +7995,22 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(GRC_MODE, grc_mode);
}
+ if (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_57765_AX) {
+ u32 grc_mode = tr32(GRC_MODE);
+
+ /* Access the lower 1K of DL PCIE block registers. */
+ val = grc_mode & ~GRC_MODE_PCIE_PORT_MASK;
+ tw32(GRC_MODE, val | GRC_MODE_PCIE_DL_SEL);
+
+ val = tr32(TG3_PCIE_TLDLPL_PORT +
+ TG3_PCIE_DL_LO_FTSMAX);
+ val &= ~TG3_PCIE_DL_LO_FTSMAX_MSK;
+ tw32(TG3_PCIE_TLDLPL_PORT + TG3_PCIE_DL_LO_FTSMAX,
+ val | TG3_PCIE_DL_LO_FTSMAX_VAL);
+
+ tw32(GRC_MODE, grc_mode);
+ }
+
val = tr32(TG3_CPMU_LSPD_10MB_CLK);
val &= ~CPMU_LSPD_10MB_MACCLK_MASK;
val |= CPMU_LSPD_10MB_MACCLK_6_25;
@@ -7920,20 +8022,20 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
* other revision. But do not set this on PCI Express
* chips and don't even touch the clocks if the CPMU is present.
*/
- if (!(tp->tg3_flags & TG3_FLAG_CPMU_PRESENT)) {
- if (!(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS))
+ if (!tg3_flag(tp, CPMU_PRESENT)) {
+ if (!tg3_flag(tp, PCI_EXPRESS))
tp->pci_clock_ctrl |= CLOCK_CTRL_DELAY_PCI_GRANT;
tw32_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl);
}
if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
- (tp->tg3_flags & TG3_FLAG_PCIX_MODE)) {
+ tg3_flag(tp, PCIX_MODE)) {
val = tr32(TG3PCI_PCISTATE);
val |= PCISTATE_RETRY_SAME_DMA;
tw32(TG3PCI_PCISTATE, val);
}
- if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
+ if (tg3_flag(tp, ENABLE_APE)) {
/* Allow reads and writes to the
* APE register and memory space.
*/
@@ -7960,11 +8062,14 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
if (err)
return err;
- if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) {
+ if (tg3_flag(tp, 57765_PLUS)) {
val = tr32(TG3PCI_DMA_RW_CTRL) &
~DMA_RWCTRL_DIS_CACHE_ALIGNMENT;
if (tp->pci_chip_rev_id == CHIPREV_ID_57765_A0)
val &= ~DMA_RWCTRL_CRDRDR_RDMA_MRRS_MSK;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57765 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717)
+ val |= DMA_RWCTRL_TAGGED_STAT_WA;
tw32(TG3PCI_DMA_RW_CTRL, val | tp->dma_rwctrl);
} else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) {
@@ -7999,7 +8104,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(GRC_MISC_CFG, val);
/* Initialize MBUF/DESC pool. */
- if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) {
+ if (tg3_flag(tp, 5750_PLUS)) {
/* Do nothing. */
} else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
tw32(BUFMGR_MB_POOL_ADDR, NIC_SRAM_MBUF_POOL_BASE);
@@ -8009,7 +8114,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE96);
tw32(BUFMGR_DMA_DESC_POOL_ADDR, NIC_SRAM_DMA_DESC_POOL_BASE);
tw32(BUFMGR_DMA_DESC_POOL_SIZE, NIC_SRAM_DMA_DESC_POOL_SIZE);
- } else if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) {
+ } else if (tg3_flag(tp, TSO_CAPABLE)) {
int fw_len;
fw_len = tp->fw_len;
@@ -8043,6 +8148,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
val = BUFMGR_MODE_ENABLE | BUFMGR_MODE_ATTN_ENABLE;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
val |= BUFMGR_MODE_NO_TX_UNDERRUN;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ tp->pci_chip_rev_id == CHIPREV_ID_5719_A0 ||
+ tp->pci_chip_rev_id == CHIPREV_ID_5720_A0)
+ val |= BUFMGR_MODE_MBLOW_ATTN_ENAB;
tw32(BUFMGR_MODE, val);
for (i = 0; i < 2000; i++) {
if (tr32(BUFMGR_MODE) & BUFMGR_MODE_ENABLE)
@@ -8054,21 +8163,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
return -ENODEV;
}
- /* Setup replenish threshold. */
- val = tp->rx_pending / 8;
- if (val == 0)
- val = 1;
- else if (val > tp->rx_std_max_post)
- val = tp->rx_std_max_post;
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
- if (tp->pci_chip_rev_id == CHIPREV_ID_5906_A1)
- tw32(ISO_PKT_TX, (tr32(ISO_PKT_TX) & ~0x3) | 0x2);
-
- if (val > (TG3_RX_INTERNAL_RING_SZ_5906 / 2))
- val = TG3_RX_INTERNAL_RING_SZ_5906 / 2;
- }
+ if (tp->pci_chip_rev_id == CHIPREV_ID_5906_A1)
+ tw32(ISO_PKT_TX, (tr32(ISO_PKT_TX) & ~0x3) | 0x2);
- tw32(RCVBDI_STD_THRESH, val);
+ tg3_setup_rxbd_thresholds(tp);
/* Initialize TG3_BDINFO's at:
* RCVDBDI_STD_BD: standard eth size rx ring
@@ -8091,13 +8189,12 @@ 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 &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719)
+ if (!tg3_flag(tp, 5717_PLUS))
tw32(RCVDBDI_STD_BD + TG3_BDINFO_NIC_ADDR,
NIC_SRAM_RX_BUFFER_DESC);
/* Disable the mini ring */
- if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
+ if (!tg3_flag(tp, 5705_PLUS))
tw32(RCVDBDI_MINI_BD + TG3_BDINFO_MAXLEN_FLAGS,
BDINFO_FLAGS_DISABLED);
@@ -8105,20 +8202,18 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
* blocks on those devices that have them.
*/
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
- ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) &&
- !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS))) {
- /* Setup replenish threshold. */
- tw32(RCVBDI_JUMBO_THRESH, tp->rx_jumbo_pending / 8);
+ (tg3_flag(tp, JUMBO_CAPABLE) && !tg3_flag(tp, 5780_CLASS))) {
- if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) {
+ if (tg3_flag(tp, JUMBO_RING_ENABLE)) {
tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_HIGH,
((u64) tpr->rx_jmb_mapping >> 32));
tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW,
((u64) tpr->rx_jmb_mapping & 0xffffffff));
+ val = TG3_RX_JMB_RING_SIZE(tp) <<
+ BDINFO_FLAGS_MAXLEN_SHIFT;
tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS,
- (RX_JUMBO_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT) |
- BDINFO_FLAGS_USE_EXT_RECV);
- if (!(tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) ||
+ val | BDINFO_FLAGS_USE_EXT_RECV);
+ if (!tg3_flag(tp, 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);
@@ -8127,32 +8222,27 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
BDINFO_FLAGS_DISABLED);
}
- if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) {
+ if (tg3_flag(tp, 57765_PLUS)) {
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
- val = RX_STD_MAX_SIZE_5705;
+ val = TG3_RX_STD_MAX_SIZE_5700;
else
- val = RX_STD_MAX_SIZE_5717;
+ val = TG3_RX_STD_MAX_SIZE_5717;
val <<= BDINFO_FLAGS_MAXLEN_SHIFT;
val |= (TG3_RX_STD_DMA_SZ << 2);
} else
val = TG3_RX_STD_DMA_SZ << BDINFO_FLAGS_MAXLEN_SHIFT;
} else
- val = RX_STD_MAX_SIZE_5705 << BDINFO_FLAGS_MAXLEN_SHIFT;
+ val = TG3_RX_STD_MAX_SIZE_5700 << BDINFO_FLAGS_MAXLEN_SHIFT;
tw32(RCVDBDI_STD_BD + TG3_BDINFO_MAXLEN_FLAGS, val);
tpr->rx_std_prod_idx = tp->rx_pending;
tw32_rx_mbox(TG3_RX_STD_PROD_IDX_REG, tpr->rx_std_prod_idx);
- tpr->rx_jmb_prod_idx = (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) ?
- tp->rx_jumbo_pending : 0;
+ tpr->rx_jmb_prod_idx =
+ tg3_flag(tp, JUMBO_RING_ENABLE) ? tp->rx_jumbo_pending : 0;
tw32_rx_mbox(TG3_RX_JMB_PROD_IDX_REG, tpr->rx_jmb_prod_idx);
- if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) {
- tw32(STD_REPLENISH_LWM, 32);
- tw32(JMB_REPLENISH_LWM, 16);
- }
-
tg3_rings_reset(tp);
/* Initialize MAC address and backoff seed. */
@@ -8165,10 +8255,16 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
/* The slot time is changed by tg3_setup_phy if we
* run at gigabit with half duplex.
*/
- tw32(MAC_TX_LENGTHS,
- (2 << TX_LENGTHS_IPG_CRS_SHIFT) |
- (6 << TX_LENGTHS_IPG_SHIFT) |
- (32 << TX_LENGTHS_SLOT_TIME_SHIFT));
+ val = (2 << TX_LENGTHS_IPG_CRS_SHIFT) |
+ (6 << TX_LENGTHS_IPG_SHIFT) |
+ (32 << TX_LENGTHS_SLOT_TIME_SHIFT);
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+ val |= tr32(MAC_TX_LENGTHS) &
+ (TX_LENGTHS_JMB_FRM_LEN_MSK |
+ TX_LENGTHS_CNT_DWN_VAL_MSK);
+
+ tw32(MAC_TX_LENGTHS, val);
/* Receive rules. */
tw32(MAC_RCV_RULE_CFG, RCV_RULE_CFG_DEFAULT_CLASS);
@@ -8195,33 +8291,39 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) {
- if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE &&
+ if (tg3_flag(tp, TSO_CAPABLE) &&
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
rdmac_mode |= RDMAC_MODE_FIFO_SIZE_128;
} else if (!(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH) &&
- !(tp->tg3_flags2 & TG3_FLG2_IS_5788)) {
+ !tg3_flag(tp, IS_5788)) {
rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST;
}
}
- if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)
+ if (tg3_flag(tp, PCI_EXPRESS))
rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST;
- if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
+ if (tg3_flag(tp, HW_TSO_1) ||
+ tg3_flag(tp, HW_TSO_2) ||
+ tg3_flag(tp, HW_TSO_3))
rdmac_mode |= RDMAC_MODE_IPV4_LSO_EN;
- if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) ||
+ if (tg3_flag(tp, 57765_PLUS) ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
rdmac_mode |= RDMAC_MODE_IPV6_LSO_EN;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+ rdmac_mode |= tr32(RDMAC_MODE) & RDMAC_MODE_H2BNC_VLAN_DET;
+
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
- (tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) {
+ tg3_flag(tp, 57765_PLUS)) {
val = tr32(TG3_RDMA_RSRVCTRL_REG);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) {
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) {
val &= ~(TG3_RDMA_RSRVCTRL_TXMRGN_MASK |
TG3_RDMA_RSRVCTRL_FIFO_LWM_MASK |
TG3_RDMA_RSRVCTRL_FIFO_HWM_MASK);
@@ -8233,7 +8335,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
val | TG3_RDMA_RSRVCTRL_FIFO_OFLW_FIX);
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) {
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) {
val = tr32(TG3_LSO_RD_DMA_CRPTEN_CTRL);
tw32(TG3_LSO_RD_DMA_CRPTEN_CTRL, val |
TG3_LSO_RD_DMA_CRPTEN_CTRL_BLEN_BD_4K |
@@ -8241,12 +8344,12 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
}
/* Receive/send statistics. */
- if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) {
+ if (tg3_flag(tp, 5750_PLUS)) {
val = tr32(RCVLPC_STATS_ENABLE);
val &= ~RCVLPC_STATSENAB_DACK_FIX;
tw32(RCVLPC_STATS_ENABLE, val);
} else if ((rdmac_mode & RDMAC_MODE_FIFO_SIZE_128) &&
- (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE)) {
+ tg3_flag(tp, TSO_CAPABLE)) {
val = tr32(RCVLPC_STATS_ENABLE);
val &= ~RCVLPC_STATSENAB_LNGBRST_RFIX;
tw32(RCVLPC_STATS_ENABLE, val);
@@ -8269,7 +8372,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
__tg3_set_coalesce(tp, &tp->coal);
- if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
+ if (!tg3_flag(tp, 5705_PLUS)) {
/* Status/statistics block address. See tg3_timer,
* the tg3_periodic_fetch_stats call there, and
* tg3_get_stats to see how this works for 5705/5750 chips.
@@ -8295,7 +8398,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(RCVCC_MODE, RCVCC_MODE_ENABLE | RCVCC_MODE_ATTN_ENABLE);
tw32(RCVLPC_MODE, RCVLPC_MODE_ENABLE);
- if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
+ if (!tg3_flag(tp, 5705_PLUS))
tw32(RCVLSC_MODE, RCVLSC_MODE_ENABLE | RCVLSC_MODE_ATTN_ENABLE);
if (tp->phy_flags & TG3_PHYFLG_MII_SERDES) {
@@ -8305,13 +8408,13 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
udelay(10);
}
- if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
+ if (tg3_flag(tp, ENABLE_APE))
tp->mac_mode = MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN;
else
tp->mac_mode = 0;
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) &&
+ if (!tg3_flag(tp, 5705_PLUS) &&
!(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;
@@ -8319,12 +8422,12 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
udelay(40);
/* tp->grc_local_ctrl is partially set up during tg3_get_invariants().
- * If TG3_FLG2_IS_NIC is zero, we should read the
+ * If TG3_FLAG_IS_NIC is zero, we should read the
* register to preserve the GPIO settings for LOMs. The GPIOs,
* whether used as inputs or outputs, are set by boot code after
* reset.
*/
- if (!(tp->tg3_flags2 & TG3_FLG2_IS_NIC)) {
+ if (!tg3_flag(tp, IS_NIC)) {
u32 gpio_mask;
gpio_mask = GRC_LCLCTRL_GPIO_OE0 | GRC_LCLCTRL_GPIO_OE1 |
@@ -8342,21 +8445,20 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tp->grc_local_ctrl |= tr32(GRC_LOCAL_CTRL) & gpio_mask;
/* GPIO1 must be driven high for eeprom write protect */
- if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT)
+ if (tg3_flag(tp, EEPROM_WRITE_PROT))
tp->grc_local_ctrl |= (GRC_LCLCTRL_GPIO_OE1 |
GRC_LCLCTRL_GPIO_OUTPUT1);
}
tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
udelay(100);
- if ((tp->tg3_flags2 & TG3_FLG2_USING_MSIX) &&
- tp->irq_cnt > 1) {
+ if (tg3_flag(tp, USING_MSIX) && tp->irq_cnt > 1) {
val = tr32(MSGINT_MODE);
val |= MSGINT_MODE_MULTIVEC_EN | MSGINT_MODE_ENABLE;
tw32(MSGINT_MODE, val);
}
- if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
+ if (!tg3_flag(tp, 5705_PLUS)) {
tw32_f(DMAC_MODE, DMAC_MODE_ENABLE);
udelay(40);
}
@@ -8369,18 +8471,18 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) {
- if ((tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) &&
+ if (tg3_flag(tp, TSO_CAPABLE) &&
(tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 ||
tp->pci_chip_rev_id == CHIPREV_ID_5705_A2)) {
/* nothing */
} else if (!(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH) &&
- !(tp->tg3_flags2 & TG3_FLG2_IS_5788)) {
+ !tg3_flag(tp, IS_5788)) {
val |= WDMAC_MODE_RX_ACCEL;
}
}
/* Enable host coalescing bug fix */
- if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)
+ if (tg3_flag(tp, 5755_PLUS))
val |= WDMAC_MODE_STATUS_TAG_FIX;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)
@@ -8389,7 +8491,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32_f(WDMAC_MODE, val);
udelay(40);
- if (tp->tg3_flags & TG3_FLAG_PCIX_MODE) {
+ if (tg3_flag(tp, PCIX_MODE)) {
u16 pcix_cmd;
pci_read_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD,
@@ -8409,7 +8511,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
udelay(40);
tw32(RCVDCC_MODE, RCVDCC_MODE_ENABLE | RCVDCC_MODE_ATTN_ENABLE);
- if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
+ if (!tg3_flag(tp, 5705_PLUS))
tw32(MBFREE_MODE, MBFREE_MODE_ENABLE);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
@@ -8421,15 +8523,16 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(SNDBDC_MODE, SNDBDC_MODE_ENABLE | SNDBDC_MODE_ATTN_ENABLE);
tw32(RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB);
val = RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
+ if (tg3_flag(tp, LRG_PROD_RING_CAP))
val |= RCVDBDI_MODE_LRG_RING_SZ;
tw32(RCVDBDI_MODE, val);
tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE);
- if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
+ if (tg3_flag(tp, HW_TSO_1) ||
+ tg3_flag(tp, HW_TSO_2) ||
+ tg3_flag(tp, HW_TSO_3))
tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE | 0x8);
val = SNDBDI_MODE_ENABLE | SNDBDI_MODE_ATTN_ENABLE;
- if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS)
+ if (tg3_flag(tp, ENABLE_TSS))
val |= SNDBDI_MODE_MULTI_TXQ_EN;
tw32(SNDBDI_MODE, val);
tw32(SNDBDS_MODE, SNDBDS_MODE_ENABLE | SNDBDS_MODE_ATTN_ENABLE);
@@ -8440,20 +8543,28 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
return err;
}
- if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) {
+ if (tg3_flag(tp, TSO_CAPABLE)) {
err = tg3_load_tso_firmware(tp);
if (err)
return err;
}
tp->tx_mode = TX_MODE_ENABLE;
- if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) ||
+
+ if (tg3_flag(tp, 5755_PLUS) ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
tp->tx_mode |= TX_MODE_MBUF_LOCKUP_FIX;
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) {
+ val = TX_MODE_JMB_FRM_LEN | TX_MODE_CNT_DN_MODE;
+ tp->tx_mode &= ~val;
+ tp->tx_mode |= tr32(MAC_TX_MODE) & val;
+ }
+
tw32_f(MAC_TX_MODE, tp->tx_mode);
udelay(100);
- if (tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS) {
+ if (tg3_flag(tp, ENABLE_RSS)) {
u32 reg = MAC_RSS_INDIR_TBL_0;
u8 *ent = (u8 *)&val;
@@ -8482,10 +8593,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
}
tp->rx_mode = RX_MODE_ENABLE;
- if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)
+ if (tg3_flag(tp, 5755_PLUS))
tp->rx_mode |= RX_MODE_IPV6_CSUM_ENABLE;
- if (tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS)
+ if (tg3_flag(tp, ENABLE_RSS))
tp->rx_mode |= RX_MODE_RSS_ENABLE |
RX_MODE_RSS_ITBL_HASH_BITS_7 |
RX_MODE_RSS_IPV6_HASH_EN |
@@ -8532,11 +8643,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 &&
(tp->phy_flags & TG3_PHYFLG_PHY_SERDES)) {
/* Use hardware link auto-negotiation */
- tp->tg3_flags2 |= TG3_FLG2_HW_AUTONEG;
+ tg3_flag_set(tp, HW_AUTONEG);
}
if ((tp->phy_flags & TG3_PHYFLG_MII_SERDES) &&
- (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)) {
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) {
u32 tmp;
tmp = tr32(SERDES_RX_CTRL);
@@ -8546,7 +8657,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
}
- if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) {
+ if (!tg3_flag(tp, USE_PHYLIB)) {
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;
@@ -8579,12 +8690,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(MAC_RCV_RULE_1, 0x86000004 & RCV_RULE_DISABLE_MASK);
tw32(MAC_RCV_VALUE_1, 0xffffffff & RCV_RULE_DISABLE_MASK);
- if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) &&
- !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
+ if (tg3_flag(tp, 5705_PLUS) && !tg3_flag(tp, 5780_CLASS))
limit = 8;
else
limit = 16;
- if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF)
+ if (tg3_flag(tp, ENABLE_ASF))
limit -= 4;
switch (limit) {
case 16:
@@ -8622,7 +8732,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
break;
}
- if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
+ if (tg3_flag(tp, ENABLE_APE))
/* Write our heartbeat update interval to APE. */
tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_INT_MS,
APE_HOST_HEARTBEAT_INT_DISABLE);
@@ -8688,7 +8798,21 @@ static void tg3_periodic_fetch_stats(struct tg3 *tp)
TG3_STAT_ADD32(&sp->rx_undersize_packets, MAC_RX_STATS_UNDERSIZE);
TG3_STAT_ADD32(&sp->rxbds_empty, RCVLPC_NO_RCV_BD_CNT);
- TG3_STAT_ADD32(&sp->rx_discards, RCVLPC_IN_DISCARDS_CNT);
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
+ tp->pci_chip_rev_id != CHIPREV_ID_5719_A0 &&
+ tp->pci_chip_rev_id != CHIPREV_ID_5720_A0) {
+ TG3_STAT_ADD32(&sp->rx_discards, RCVLPC_IN_DISCARDS_CNT);
+ } else {
+ u32 val = tr32(HOSTCC_FLOW_ATTN);
+ val = (val & HOSTCC_FLOW_ATTN_MBUF_LWM) ? 1 : 0;
+ if (val) {
+ tw32(HOSTCC_FLOW_ATTN, HOSTCC_FLOW_ATTN_MBUF_LWM);
+ sp->rx_discards.low += val;
+ if (sp->rx_discards.low < val)
+ sp->rx_discards.high += 1;
+ }
+ sp->mbuf_lwm_thresh_hit = sp->rx_discards;
+ }
TG3_STAT_ADD32(&sp->rx_errors, RCVLPC_IN_ERRORS_CNT);
}
@@ -8701,7 +8825,7 @@ static void tg3_timer(unsigned long __opaque)
spin_lock(&tp->lock);
- if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) {
+ if (!tg3_flag(tp, TAGGED_STATUS)) {
/* All of this garbage is because when using non-tagged
* IRQ status the mailbox/status_block protocol the chip
* uses with the cpu is race prone.
@@ -8715,7 +8839,7 @@ static void tg3_timer(unsigned long __opaque)
}
if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
- tp->tg3_flags2 |= TG3_FLG2_RESTART_TIMER;
+ tg3_flag_set(tp, RESTART_TIMER);
spin_unlock(&tp->lock);
schedule_work(&tp->reset_task);
return;
@@ -8724,16 +8848,13 @@ static void tg3_timer(unsigned long __opaque)
/* This part only runs once per second. */
if (!--tp->timer_counter) {
- if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
+ if (tg3_flag(tp, 5705_PLUS))
tg3_periodic_fetch_stats(tp);
- if (tp->setlpicnt && !--tp->setlpicnt) {
- u32 val = tr32(TG3_CPMU_EEE_MODE);
- tw32(TG3_CPMU_EEE_MODE,
- val | TG3_CPMU_EEEMD_LPI_ENABLE);
- }
+ if (tp->setlpicnt && !--tp->setlpicnt)
+ tg3_phy_eee_enable(tp);
- if (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) {
+ if (tg3_flag(tp, USE_LINKCHG_REG)) {
u32 mac_stat;
int phy_event;
@@ -8748,7 +8869,7 @@ static void tg3_timer(unsigned long __opaque)
if (phy_event)
tg3_setup_phy(tp, 0);
- } else if (tp->tg3_flags & TG3_FLAG_POLL_SERDES) {
+ } else if (tg3_flag(tp, POLL_SERDES)) {
u32 mac_stat = tr32(MAC_STATUS);
int need_setup = 0;
@@ -8773,7 +8894,7 @@ static void tg3_timer(unsigned long __opaque)
tg3_setup_phy(tp, 0);
}
} else if ((tp->phy_flags & TG3_PHYFLG_MII_SERDES) &&
- (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
+ tg3_flag(tp, 5780_CLASS)) {
tg3_serdes_parallel_detect(tp);
}
@@ -8798,8 +8919,7 @@ static void tg3_timer(unsigned long __opaque)
* resets.
*/
if (!--tp->asf_counter) {
- if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
- !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) {
+ if (tg3_flag(tp, ENABLE_ASF) && !tg3_flag(tp, ENABLE_APE)) {
tg3_wait_for_event_ack(tp);
tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX,
@@ -8835,16 +8955,16 @@ static int tg3_request_irq(struct tg3 *tp, int irq_num)
name[IFNAMSIZ-1] = 0;
}
- if (tp->tg3_flags2 & TG3_FLG2_USING_MSI_OR_MSIX) {
+ if (tg3_flag(tp, USING_MSI) || tg3_flag(tp, USING_MSIX)) {
fn = tg3_msi;
- if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI)
+ if (tg3_flag(tp, 1SHOT_MSI))
fn = tg3_msi_1shot;
- flags = IRQF_SAMPLE_RANDOM;
+ flags = 0;
} else {
fn = tg3_interrupt;
- if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)
+ if (tg3_flag(tp, TAGGED_STATUS))
fn = tg3_interrupt_tagged;
- flags = IRQF_SHARED | IRQF_SAMPLE_RANDOM;
+ flags = IRQF_SHARED;
}
return request_irq(tnapi->irq_vec, fn, flags, name, tnapi);
@@ -8868,8 +8988,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 ((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) &&
- (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) {
+ if (tg3_flag(tp, 57765_PLUS) && tg3_flag(tp, USING_MSI)) {
val = tr32(MSGINT_MODE) | MSGINT_MODE_ONE_SHOT_DISABLE;
tw32(MSGINT_MODE, val);
}
@@ -8911,8 +9030,7 @@ static int tg3_test_interrupt(struct tg3 *tp)
if (intr_ok) {
/* Reenable MSI one shot mode. */
- if ((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) &&
- (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) {
+ if (tg3_flag(tp, 57765_PLUS) && tg3_flag(tp, USING_MSI)) {
val = tr32(MSGINT_MODE) & ~MSGINT_MODE_ONE_SHOT_DISABLE;
tw32(MSGINT_MODE, val);
}
@@ -8930,7 +9048,7 @@ static int tg3_test_msi(struct tg3 *tp)
int err;
u16 pci_cmd;
- if (!(tp->tg3_flags2 & TG3_FLG2_USING_MSI))
+ if (!tg3_flag(tp, USING_MSI))
return 0;
/* Turn off SERR reporting in case MSI terminates with Master
@@ -8960,7 +9078,7 @@ static int tg3_test_msi(struct tg3 *tp)
pci_disable_msi(tp->pdev);
- tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI;
+ tg3_flag_clear(tp, USING_MSI);
tp->napi[0].irq_vec = tp->pdev->irq;
err = tg3_request_irq(tp, 0);
@@ -9057,9 +9175,11 @@ static bool tg3_enable_msix(struct tg3 *tp)
}
if (tp->irq_cnt > 1) {
- tp->tg3_flags3 |= TG3_FLG3_ENABLE_RSS;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) {
- tp->tg3_flags3 |= TG3_FLG3_ENABLE_TSS;
+ tg3_flag_set(tp, ENABLE_RSS);
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) {
+ tg3_flag_set(tp, ENABLE_TSS);
netif_set_real_num_tx_queues(tp->dev, tp->irq_cnt - 1);
}
}
@@ -9069,8 +9189,8 @@ static bool tg3_enable_msix(struct tg3 *tp)
static void tg3_ints_init(struct tg3 *tp)
{
- if ((tp->tg3_flags & TG3_FLAG_SUPPORT_MSI_OR_MSIX) &&
- !(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) {
+ if ((tg3_flag(tp, SUPPORT_MSI) || tg3_flag(tp, SUPPORT_MSIX)) &&
+ !tg3_flag(tp, TAGGED_STATUS)) {
/* All MSI supporting chips should support tagged
* status. Assert that this is the case.
*/
@@ -9079,21 +9199,19 @@ static void tg3_ints_init(struct tg3 *tp)
goto defcfg;
}
- if ((tp->tg3_flags & TG3_FLAG_SUPPORT_MSIX) && tg3_enable_msix(tp))
- tp->tg3_flags2 |= TG3_FLG2_USING_MSIX;
- else if ((tp->tg3_flags & TG3_FLAG_SUPPORT_MSI) &&
- pci_enable_msi(tp->pdev) == 0)
- tp->tg3_flags2 |= TG3_FLG2_USING_MSI;
+ if (tg3_flag(tp, SUPPORT_MSIX) && tg3_enable_msix(tp))
+ tg3_flag_set(tp, USING_MSIX);
+ else if (tg3_flag(tp, SUPPORT_MSI) && pci_enable_msi(tp->pdev) == 0)
+ tg3_flag_set(tp, USING_MSI);
- if (tp->tg3_flags2 & TG3_FLG2_USING_MSI_OR_MSIX) {
+ if (tg3_flag(tp, USING_MSI) || tg3_flag(tp, USING_MSIX)) {
u32 msi_mode = tr32(MSGINT_MODE);
- if ((tp->tg3_flags2 & TG3_FLG2_USING_MSIX) &&
- tp->irq_cnt > 1)
+ if (tg3_flag(tp, USING_MSIX) && tp->irq_cnt > 1)
msi_mode |= MSGINT_MODE_MULTIVEC_EN;
tw32(MSGINT_MODE, msi_mode | MSGINT_MODE_ENABLE);
}
defcfg:
- if (!(tp->tg3_flags2 & TG3_FLG2_USING_MSIX)) {
+ if (!tg3_flag(tp, USING_MSIX)) {
tp->irq_cnt = 1;
tp->napi[0].irq_vec = tp->pdev->irq;
netif_set_real_num_tx_queues(tp->dev, 1);
@@ -9103,12 +9221,14 @@ defcfg:
static void tg3_ints_fini(struct tg3 *tp)
{
- if (tp->tg3_flags2 & TG3_FLG2_USING_MSIX)
+ if (tg3_flag(tp, USING_MSIX))
pci_disable_msix(tp->pdev);
- else if (tp->tg3_flags2 & TG3_FLG2_USING_MSI)
+ else if (tg3_flag(tp, USING_MSI))
pci_disable_msi(tp->pdev);
- tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI_OR_MSIX;
- tp->tg3_flags3 &= ~(TG3_FLG3_ENABLE_RSS | TG3_FLG3_ENABLE_TSS);
+ tg3_flag_clear(tp, USING_MSI);
+ tg3_flag_clear(tp, USING_MSIX);
+ tg3_flag_clear(tp, ENABLE_RSS);
+ tg3_flag_clear(tp, ENABLE_TSS);
}
static int tg3_open(struct net_device *dev)
@@ -9123,10 +9243,10 @@ static int tg3_open(struct net_device *dev)
return err;
} else if (err) {
netdev_warn(tp->dev, "TSO capability disabled\n");
- tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE;
- } else if (!(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE)) {
+ tg3_flag_clear(tp, TSO_CAPABLE);
+ } else if (!tg3_flag(tp, TSO_CAPABLE)) {
netdev_notice(tp->dev, "TSO capability restored\n");
- tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE;
+ tg3_flag_set(tp, TSO_CAPABLE);
}
}
@@ -9139,7 +9259,7 @@ static int tg3_open(struct net_device *dev)
tg3_full_lock(tp, 0);
tg3_disable_ints(tp);
- tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
+ tg3_flag_clear(tp, INIT_COMPLETE);
tg3_full_unlock(tp);
@@ -9180,7 +9300,7 @@ static int tg3_open(struct net_device *dev)
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
tg3_free_rings(tp);
} else {
- if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)
+ if (tg3_flag(tp, TAGGED_STATUS))
tp->timer_offset = HZ;
else
tp->timer_offset = HZ / 10;
@@ -9202,7 +9322,7 @@ static int tg3_open(struct net_device *dev)
if (err)
goto err_out3;
- if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
+ if (tg3_flag(tp, USING_MSI)) {
err = tg3_test_msi(tp);
if (err) {
@@ -9214,8 +9334,7 @@ static int tg3_open(struct net_device *dev)
goto err_out2;
}
- if (!(tp->tg3_flags3 & TG3_FLG3_5717_PLUS) &&
- (tp->tg3_flags2 & TG3_FLG2_USING_MSI)) {
+ if (!tg3_flag(tp, 57765_PLUS) && tg3_flag(tp, USING_MSI)) {
u32 val = tr32(PCIE_TRANSACTION_CFG);
tw32(PCIE_TRANSACTION_CFG,
@@ -9228,13 +9347,20 @@ static int tg3_open(struct net_device *dev)
tg3_full_lock(tp, 0);
add_timer(&tp->timer);
- tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
+ tg3_flag_set(tp, INIT_COMPLETE);
tg3_enable_ints(tp);
tg3_full_unlock(tp);
netif_tx_start_all_queues(dev);
+ /*
+ * Reset loopback feature if it was turned on while the device was down
+ * make sure that it's installed properly now.
+ */
+ if (dev->features & NETIF_F_LOOPBACK)
+ tg3_set_loopback(dev, dev->features);
+
return 0;
err_out3:
@@ -9277,7 +9403,7 @@ static int tg3_close(struct net_device *dev)
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
tg3_free_rings(tp);
- tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
+ tg3_flag_clear(tp, INIT_COMPLETE);
tg3_full_unlock(tp);
@@ -9424,6 +9550,8 @@ static struct tg3_ethtool_stats *tg3_get_estats(struct tg3 *tp)
ESTAT_ADD(nic_avoided_irqs);
ESTAT_ADD(nic_tx_threshold_hit);
+ ESTAT_ADD(mbuf_lwm_thresh_hit);
+
return estats;
}
@@ -9534,7 +9662,7 @@ static void __tg3_set_rx_mode(struct net_device *dev)
/* When ASF is in use, we always keep the RX_MODE_KEEP_VLAN_TAG
* flag clear.
*/
- if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
+ if (!tg3_flag(tp, ENABLE_ASF))
rx_mode |= RX_MODE_KEEP_VLAN_TAG;
#endif
@@ -9588,82 +9716,26 @@ static void tg3_set_rx_mode(struct net_device *dev)
tg3_full_unlock(tp);
}
-#define TG3_REGDUMP_LEN (32 * 1024)
-
static int tg3_get_regs_len(struct net_device *dev)
{
- return TG3_REGDUMP_LEN;
+ return TG3_REG_BLK_SIZE;
}
static void tg3_get_regs(struct net_device *dev,
struct ethtool_regs *regs, void *_p)
{
- u32 *p = _p;
struct tg3 *tp = netdev_priv(dev);
- u8 *orig_p = _p;
- int i;
regs->version = 0;
- memset(p, 0, TG3_REGDUMP_LEN);
+ memset(_p, 0, TG3_REG_BLK_SIZE);
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) \
-do { p = (u32 *)(orig_p + (base)); \
- for (i = 0; i < len; i += 4) \
- __GET_REG32((base) + i); \
-} while (0)
-#define GET_REG32_1(reg) \
-do { p = (u32 *)(orig_p + (reg)); \
- __GET_REG32((reg)); \
-} while (0)
-
- GET_REG32_LOOP(TG3PCI_VENDOR, 0xb0);
- GET_REG32_LOOP(MAILBOX_INTERRUPT_0, 0x200);
- GET_REG32_LOOP(MAC_MODE, 0x4f0);
- GET_REG32_LOOP(SNDDATAI_MODE, 0xe0);
- GET_REG32_1(SNDDATAC_MODE);
- GET_REG32_LOOP(SNDBDS_MODE, 0x80);
- GET_REG32_LOOP(SNDBDI_MODE, 0x48);
- GET_REG32_1(SNDBDC_MODE);
- GET_REG32_LOOP(RCVLPC_MODE, 0x20);
- GET_REG32_LOOP(RCVLPC_SELLST_BASE, 0x15c);
- GET_REG32_LOOP(RCVDBDI_MODE, 0x0c);
- GET_REG32_LOOP(RCVDBDI_JUMBO_BD, 0x3c);
- GET_REG32_LOOP(RCVDBDI_BD_PROD_IDX_0, 0x44);
- GET_REG32_1(RCVDCC_MODE);
- GET_REG32_LOOP(RCVBDI_MODE, 0x20);
- GET_REG32_LOOP(RCVCC_MODE, 0x14);
- GET_REG32_LOOP(RCVLSC_MODE, 0x08);
- GET_REG32_1(MBFREE_MODE);
- GET_REG32_LOOP(HOSTCC_MODE, 0x100);
- GET_REG32_LOOP(MEMARB_MODE, 0x10);
- GET_REG32_LOOP(BUFMGR_MODE, 0x58);
- GET_REG32_LOOP(RDMAC_MODE, 0x08);
- GET_REG32_LOOP(WDMAC_MODE, 0x08);
- GET_REG32_1(RX_CPU_MODE);
- GET_REG32_1(RX_CPU_STATE);
- GET_REG32_1(RX_CPU_PGMCTR);
- GET_REG32_1(RX_CPU_HWBKPT);
- GET_REG32_1(TX_CPU_MODE);
- GET_REG32_1(TX_CPU_STATE);
- GET_REG32_1(TX_CPU_PGMCTR);
- GET_REG32_LOOP(GRCMBOX_INTERRUPT_0, 0x110);
- GET_REG32_LOOP(FTQ_RESET, 0x120);
- GET_REG32_LOOP(MSGINT_MODE, 0x0c);
- GET_REG32_1(DMAC_MODE);
- GET_REG32_LOOP(GRC_MODE, 0x4c);
- if (tp->tg3_flags & TG3_FLAG_NVRAM)
- GET_REG32_LOOP(NVRAM_CMD, 0x24);
-
-#undef __GET_REG32
-#undef GET_REG32_LOOP
-#undef GET_REG32_1
+ tg3_dump_legacy_regs(tp, (u32 *)_p);
tg3_full_unlock(tp);
}
@@ -9683,7 +9755,7 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
u32 i, offset, len, b_offset, b_count;
__be32 val;
- if (tp->tg3_flags3 & TG3_FLG3_NO_NVRAM)
+ if (tg3_flag(tp, NO_NVRAM))
return -EINVAL;
if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
@@ -9751,7 +9823,7 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)
return -EAGAIN;
- if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) ||
+ if (tg3_flag(tp, NO_NVRAM) ||
eeprom->magic != TG3_EEPROM_MAGIC)
return -EINVAL;
@@ -9803,7 +9875,7 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct tg3 *tp = netdev_priv(dev);
- if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+ if (tg3_flag(tp, USE_PHYLIB)) {
struct phy_device *phydev;
if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED))
return -EAGAIN;
@@ -9831,10 +9903,10 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->advertising = tp->link_config.advertising;
if (netif_running(dev)) {
- cmd->speed = tp->link_config.active_speed;
+ ethtool_cmd_speed_set(cmd, tp->link_config.active_speed);
cmd->duplex = tp->link_config.active_duplex;
} else {
- cmd->speed = SPEED_INVALID;
+ ethtool_cmd_speed_set(cmd, SPEED_INVALID);
cmd->duplex = DUPLEX_INVALID;
}
cmd->phy_address = tp->phy_addr;
@@ -9848,8 +9920,9 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct tg3 *tp = netdev_priv(dev);
+ u32 speed = ethtool_cmd_speed(cmd);
- if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+ if (tg3_flag(tp, USE_PHYLIB)) {
struct phy_device *phydev;
if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED))
return -EAGAIN;
@@ -9897,14 +9970,14 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->advertising &= mask;
} else {
if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES) {
- if (cmd->speed != SPEED_1000)
+ if (speed != SPEED_1000)
return -EINVAL;
if (cmd->duplex != DUPLEX_FULL)
return -EINVAL;
} else {
- if (cmd->speed != SPEED_100 &&
- cmd->speed != SPEED_10)
+ if (speed != SPEED_100 &&
+ speed != SPEED_10)
return -EINVAL;
}
}
@@ -9919,7 +9992,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
tp->link_config.duplex = DUPLEX_INVALID;
} else {
tp->link_config.advertising = 0;
- tp->link_config.speed = cmd->speed;
+ tp->link_config.speed = speed;
tp->link_config.duplex = cmd->duplex;
}
@@ -9949,14 +10022,12 @@ static void tg3_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct tg3 *tp = netdev_priv(dev);
- if ((tp->tg3_flags & TG3_FLAG_WOL_CAP) &&
- device_can_wakeup(&tp->pdev->dev))
+ if (tg3_flag(tp, WOL_CAP) && device_can_wakeup(&tp->pdev->dev))
wol->supported = WAKE_MAGIC;
else
wol->supported = 0;
wol->wolopts = 0;
- if ((tp->tg3_flags & TG3_FLAG_WOL_ENABLE) &&
- device_can_wakeup(&tp->pdev->dev))
+ if (tg3_flag(tp, WOL_ENABLE) && device_can_wakeup(&tp->pdev->dev))
wol->wolopts = WAKE_MAGIC;
memset(&wol->sopass, 0, sizeof(wol->sopass));
}
@@ -9969,19 +10040,18 @@ static int tg3_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
if (wol->wolopts & ~WAKE_MAGIC)
return -EINVAL;
if ((wol->wolopts & WAKE_MAGIC) &&
- !((tp->tg3_flags & TG3_FLAG_WOL_CAP) && device_can_wakeup(dp)))
+ !(tg3_flag(tp, WOL_CAP) && device_can_wakeup(dp)))
return -EINVAL;
device_set_wakeup_enable(dp, wol->wolopts & WAKE_MAGIC);
spin_lock_bh(&tp->lock);
if (device_may_wakeup(dp))
- tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
+ tg3_flag_set(tp, WOL_ENABLE);
else
- tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE;
+ tg3_flag_clear(tp, WOL_ENABLE);
spin_unlock_bh(&tp->lock);
-
return 0;
}
@@ -9997,33 +10067,6 @@ static void tg3_set_msglevel(struct net_device *dev, u32 value)
tp->msg_enable = value;
}
-static int tg3_set_tso(struct net_device *dev, u32 value)
-{
- struct tg3 *tp = netdev_priv(dev);
-
- if (!(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE)) {
- if (value)
- return -EINVAL;
- return 0;
- }
- if ((dev->features & NETIF_F_IPV6_CSUM) &&
- ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) ||
- (tp->tg3_flags2 & TG3_FLG2_HW_TSO_3))) {
- if (value) {
- dev->features |= 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)
- dev->features |= NETIF_F_TSO_ECN;
- } else
- dev->features &= ~(NETIF_F_TSO6 | NETIF_F_TSO_ECN);
- }
- return ethtool_op_set_tso(dev, value);
-}
-
static int tg3_nway_reset(struct net_device *dev)
{
struct tg3 *tp = netdev_priv(dev);
@@ -10035,7 +10078,7 @@ static int tg3_nway_reset(struct net_device *dev)
if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)
return -EINVAL;
- if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+ if (tg3_flag(tp, USE_PHYLIB)) {
if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED))
return -EAGAIN;
r = phy_start_aneg(tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR]);
@@ -10064,7 +10107,7 @@ static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam *
ering->rx_max_pending = tp->rx_std_ring_mask;
ering->rx_mini_max_pending = 0;
- if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE)
+ if (tg3_flag(tp, JUMBO_RING_ENABLE))
ering->rx_jumbo_max_pending = tp->rx_jmb_ring_mask;
else
ering->rx_jumbo_max_pending = 0;
@@ -10073,7 +10116,7 @@ static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam *
ering->rx_pending = tp->rx_pending;
ering->rx_mini_pending = 0;
- if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE)
+ if (tg3_flag(tp, JUMBO_RING_ENABLE))
ering->rx_jumbo_pending = tp->rx_jumbo_pending;
else
ering->rx_jumbo_pending = 0;
@@ -10090,7 +10133,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
(ering->rx_jumbo_pending > tp->rx_jmb_ring_mask) ||
(ering->tx_pending > TG3_TX_RING_SIZE - 1) ||
(ering->tx_pending <= MAX_SKB_FRAGS) ||
- ((tp->tg3_flags2 & TG3_FLG2_TSO_BUG) &&
+ (tg3_flag(tp, TSO_BUG) &&
(ering->tx_pending <= (MAX_SKB_FRAGS * 3))))
return -EINVAL;
@@ -10104,7 +10147,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
tp->rx_pending = ering->rx_pending;
- if ((tp->tg3_flags2 & TG3_FLG2_MAX_RXPEND_64) &&
+ if (tg3_flag(tp, MAX_RXPEND_64) &&
tp->rx_pending > 63)
tp->rx_pending = 63;
tp->rx_jumbo_pending = ering->rx_jumbo_pending;
@@ -10131,7 +10174,7 @@ static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam
{
struct tg3 *tp = netdev_priv(dev);
- epause->autoneg = (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) != 0;
+ epause->autoneg = !!tg3_flag(tp, PAUSE_AUTONEG);
if (tp->link_config.active_flowctrl & FLOW_CTRL_RX)
epause->rx_pause = 1;
@@ -10149,7 +10192,7 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
struct tg3 *tp = netdev_priv(dev);
int err = 0;
- if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+ if (tg3_flag(tp, USE_PHYLIB)) {
u32 newadv;
struct phy_device *phydev;
@@ -10177,9 +10220,9 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
newadv = 0;
if (epause->autoneg)
- tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
+ tg3_flag_set(tp, PAUSE_AUTONEG);
else
- tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG;
+ tg3_flag_clear(tp, PAUSE_AUTONEG);
if (tp->phy_flags & TG3_PHYFLG_IS_CONNECTED) {
u32 oldadv = phydev->advertising &
@@ -10221,9 +10264,9 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
tg3_full_lock(tp, irq_sync);
if (epause->autoneg)
- tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
+ tg3_flag_set(tp, PAUSE_AUTONEG);
else
- tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG;
+ tg3_flag_clear(tp, PAUSE_AUTONEG);
if (epause->rx_pause)
tp->link_config.flowctrl |= FLOW_CTRL_RX;
else
@@ -10246,50 +10289,6 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
return err;
}
-static u32 tg3_get_rx_csum(struct net_device *dev)
-{
- struct tg3 *tp = netdev_priv(dev);
- return (tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0;
-}
-
-static int tg3_set_rx_csum(struct net_device *dev, u32 data)
-{
- struct tg3 *tp = netdev_priv(dev);
-
- if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) {
- if (data != 0)
- return -EINVAL;
- return 0;
- }
-
- spin_lock_bh(&tp->lock);
- if (data)
- tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
- else
- tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS;
- spin_unlock_bh(&tp->lock);
-
- return 0;
-}
-
-static int tg3_set_tx_csum(struct net_device *dev, u32 data)
-{
- struct tg3 *tp = netdev_priv(dev);
-
- if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) {
- if (data != 0)
- return -EINVAL;
- return 0;
- }
-
- if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)
- ethtool_op_set_tx_ipv6_csum(dev, data);
- else
- ethtool_op_set_tx_csum(dev, data);
-
- return 0;
-}
-
static int tg3_get_sset_count(struct net_device *dev, int sset)
{
switch (sset) {
@@ -10317,35 +10316,38 @@ static void tg3_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
}
}
-static int tg3_phys_id(struct net_device *dev, u32 data)
+static int tg3_set_phys_id(struct net_device *dev,
+ enum ethtool_phys_id_state state)
{
struct tg3 *tp = netdev_priv(dev);
- int i;
if (!netif_running(tp->dev))
return -EAGAIN;
- if (data == 0)
- data = UINT_MAX / 2;
-
- for (i = 0; i < (data * 2); i++) {
- if ((i % 2) == 0)
- tw32(MAC_LED_CTRL, LED_CTRL_LNKLED_OVERRIDE |
- LED_CTRL_1000MBPS_ON |
- LED_CTRL_100MBPS_ON |
- LED_CTRL_10MBPS_ON |
- LED_CTRL_TRAFFIC_OVERRIDE |
- LED_CTRL_TRAFFIC_BLINK |
- LED_CTRL_TRAFFIC_LED);
+ switch (state) {
+ case ETHTOOL_ID_ACTIVE:
+ return 1; /* cycle on/off once per second */
+
+ case ETHTOOL_ID_ON:
+ tw32(MAC_LED_CTRL, LED_CTRL_LNKLED_OVERRIDE |
+ LED_CTRL_1000MBPS_ON |
+ LED_CTRL_100MBPS_ON |
+ LED_CTRL_10MBPS_ON |
+ LED_CTRL_TRAFFIC_OVERRIDE |
+ LED_CTRL_TRAFFIC_BLINK |
+ LED_CTRL_TRAFFIC_LED);
+ break;
- else
- tw32(MAC_LED_CTRL, LED_CTRL_LNKLED_OVERRIDE |
- LED_CTRL_TRAFFIC_OVERRIDE);
+ case ETHTOOL_ID_OFF:
+ tw32(MAC_LED_CTRL, LED_CTRL_LNKLED_OVERRIDE |
+ LED_CTRL_TRAFFIC_OVERRIDE);
+ break;
- if (msleep_interruptible(500))
- break;
+ case ETHTOOL_ID_INACTIVE:
+ tw32(MAC_LED_CTRL, tp->led_ctrl);
+ break;
}
- tw32(MAC_LED_CTRL, tp->led_ctrl);
+
return 0;
}
@@ -10356,6 +10358,80 @@ static void tg3_get_ethtool_stats(struct net_device *dev,
memcpy(tmp_stats, tg3_get_estats(tp), sizeof(tp->estats));
}
+static __be32 * tg3_vpd_readblock(struct tg3 *tp)
+{
+ int i;
+ __be32 *buf;
+ u32 offset = 0, len = 0;
+ u32 magic, val;
+
+ if (tg3_flag(tp, NO_NVRAM) || tg3_nvram_read(tp, 0, &magic))
+ return NULL;
+
+ if (magic == TG3_EEPROM_MAGIC) {
+ for (offset = TG3_NVM_DIR_START;
+ offset < TG3_NVM_DIR_END;
+ offset += TG3_NVM_DIRENT_SIZE) {
+ if (tg3_nvram_read(tp, offset, &val))
+ return NULL;
+
+ if ((val >> TG3_NVM_DIRTYPE_SHIFT) ==
+ TG3_NVM_DIRTYPE_EXTVPD)
+ break;
+ }
+
+ if (offset != TG3_NVM_DIR_END) {
+ len = (val & TG3_NVM_DIRTYPE_LENMSK) * 4;
+ if (tg3_nvram_read(tp, offset + 4, &offset))
+ return NULL;
+
+ offset = tg3_nvram_logical_addr(tp, offset);
+ }
+ }
+
+ if (!offset || !len) {
+ offset = TG3_NVM_VPD_OFF;
+ len = TG3_NVM_VPD_LEN;
+ }
+
+ buf = kmalloc(len, GFP_KERNEL);
+ if (buf == NULL)
+ return NULL;
+
+ if (magic == TG3_EEPROM_MAGIC) {
+ for (i = 0; i < len; i += 4) {
+ /* The data is in little-endian format in NVRAM.
+ * Use the big-endian read routines to preserve
+ * the byte order as it exists in NVRAM.
+ */
+ if (tg3_nvram_read_be32(tp, offset + i, &buf[i/4]))
+ goto error;
+ }
+ } else {
+ u8 *ptr;
+ ssize_t cnt;
+ unsigned int pos = 0;
+
+ ptr = (u8 *)&buf[0];
+ for (i = 0; pos < len && i < 3; i++, pos += cnt, ptr += cnt) {
+ cnt = pci_read_vpd(tp->pdev, pos,
+ len - pos, ptr);
+ if (cnt == -ETIMEDOUT || cnt == -EINTR)
+ cnt = 0;
+ else if (cnt < 0)
+ goto error;
+ }
+ if (pos != len)
+ goto error;
+ }
+
+ return buf;
+
+error:
+ kfree(buf);
+ return NULL;
+}
+
#define NVRAM_TEST_SIZE 0x100
#define NVRAM_SELFBOOT_FORMAT1_0_SIZE 0x14
#define NVRAM_SELFBOOT_FORMAT1_2_SIZE 0x18
@@ -10369,7 +10445,7 @@ static int tg3_test_nvram(struct tg3 *tp)
__be32 *buf;
int i, j, k, err = 0, size;
- if (tp->tg3_flags3 & TG3_FLG3_NO_NVRAM)
+ if (tg3_flag(tp, NO_NVRAM))
return 0;
if (tg3_nvram_read(tp, 0, &magic) != 0)
@@ -10495,14 +10571,11 @@ static int tg3_test_nvram(struct tg3 *tp)
if (csum != le32_to_cpu(buf[0xfc/4]))
goto out;
- for (i = 0; i < TG3_NVM_VPD_LEN; i += 4) {
- /* The data is in little-endian format in NVRAM.
- * Use the big-endian read routines to preserve
- * the byte order as it exists in NVRAM.
- */
- if (tg3_nvram_read_be32(tp, TG3_NVM_VPD_OFF + i, &buf[i/4]))
- goto out;
- }
+ kfree(buf);
+
+ buf = tg3_vpd_readblock(tp);
+ if (!buf)
+ return -ENOMEM;
i = pci_vpd_find_tag((u8 *)buf, 0, TG3_NVM_VPD_LEN,
PCI_VPD_LRDT_RO_DATA);
@@ -10714,9 +10787,9 @@ static int tg3_test_registers(struct tg3 *tp)
};
is_5705 = is_5750 = 0;
- if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
+ if (tg3_flag(tp, 5705_PLUS)) {
is_5705 = 1;
- if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
+ if (tg3_flag(tp, 5750_PLUS))
is_5750 = 1;
}
@@ -10727,7 +10800,7 @@ static int tg3_test_registers(struct tg3 *tp)
if (!is_5705 && (reg_tbl[i].flags & TG3_FL_5705))
continue;
- if ((tp->tg3_flags2 & TG3_FLG2_IS_5788) &&
+ if (tg3_flag(tp, IS_5788) &&
(reg_tbl[i].flags & TG3_FL_NOT_5788))
continue;
@@ -10850,16 +10923,15 @@ 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 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
+ if (tg3_flag(tp, 5717_PLUS))
mem_tbl = mem_tbl_5717;
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
mem_tbl = mem_tbl_57765;
- else if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)
+ else if (tg3_flag(tp, 5755_PLUS))
mem_tbl = mem_tbl_5755;
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
mem_tbl = mem_tbl_5906;
- else if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
+ else if (tg3_flag(tp, 5705_PLUS))
mem_tbl = mem_tbl_5705;
else
mem_tbl = mem_tbl_570x;
@@ -10875,11 +10947,35 @@ static int tg3_test_memory(struct tg3 *tp)
#define TG3_MAC_LOOPBACK 0
#define TG3_PHY_LOOPBACK 1
+#define TG3_TSO_LOOPBACK 2
+
+#define TG3_TSO_MSS 500
+
+#define TG3_TSO_IP_HDR_LEN 20
+#define TG3_TSO_TCP_HDR_LEN 20
+#define TG3_TSO_TCP_OPT_LEN 12
+
+static const u8 tg3_tso_header[] = {
+0x08, 0x00,
+0x45, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x40, 0x00,
+0x40, 0x06, 0x00, 0x00,
+0x0a, 0x00, 0x00, 0x01,
+0x0a, 0x00, 0x00, 0x02,
+0x0d, 0x00, 0xe0, 0x00,
+0x00, 0x00, 0x01, 0x00,
+0x00, 0x00, 0x02, 0x00,
+0x80, 0x10, 0x10, 0x00,
+0x14, 0x09, 0x00, 0x00,
+0x01, 0x01, 0x08, 0x0a,
+0x11, 0x11, 0x11, 0x11,
+0x11, 0x11, 0x11, 0x11,
+};
-static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
+static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode)
{
u32 mac_mode, rx_start_idx, rx_idx, tx_idx, opaque_key;
- u32 desc_idx, coal_now;
+ u32 base_flags = 0, mss = 0, desc_idx, coal_now, data_off, val;
struct sk_buff *skb, *rx_skb;
u8 *tx_data;
dma_addr_t map;
@@ -10891,9 +10987,9 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
tnapi = &tp->napi[0];
rnapi = &tp->napi[0];
if (tp->irq_cnt > 1) {
- if (tp->tg3_flags3 & TG3_FLG3_ENABLE_RSS)
+ if (tg3_flag(tp, ENABLE_RSS))
rnapi = &tp->napi[1];
- if (tp->tg3_flags3 & TG3_FLG3_ENABLE_TSS)
+ if (tg3_flag(tp, ENABLE_TSS))
tnapi = &tp->napi[1];
}
coal_now = tnapi->coal_now | rnapi->coal_now;
@@ -10905,22 +11001,20 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
* all newer ASIC revisions.
*/
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 ||
- (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT))
+ tg3_flag(tp, CPMU_PRESENT))
return 0;
mac_mode = tp->mac_mode &
~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX);
mac_mode |= MAC_MODE_PORT_INT_LPBACK;
- if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
+ if (!tg3_flag(tp, 5705_PLUS))
mac_mode |= MAC_MODE_LINK_POLARITY;
if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY)
mac_mode |= MAC_MODE_PORT_MODE_MII;
else
mac_mode |= MAC_MODE_PORT_MODE_GMII;
tw32(MAC_MODE, mac_mode);
- } else if (loopback_mode == TG3_PHY_LOOPBACK) {
- u32 val;
-
+ } else {
if (tp->phy_flags & TG3_PHYFLG_IS_FET) {
tg3_phy_fet_toggle_apd(tp, false);
val = BMCR_LOOPBACK | BMCR_FULLDPLX | BMCR_SPEED100;
@@ -10968,13 +11062,11 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
break;
mdelay(1);
}
- } else {
- return -EINVAL;
}
err = -EIO;
- tx_len = 1514;
+ tx_len = pktsz;
skb = netdev_alloc_skb(tp->dev, tx_len);
if (!skb)
return -ENOMEM;
@@ -10983,9 +11075,58 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
memcpy(tx_data, tp->dev->dev_addr, 6);
memset(tx_data + 6, 0x0, 8);
- tw32(MAC_RX_MTU_SIZE, tx_len + 4);
+ tw32(MAC_RX_MTU_SIZE, tx_len + ETH_FCS_LEN);
+
+ if (loopback_mode == TG3_TSO_LOOPBACK) {
+ struct iphdr *iph = (struct iphdr *)&tx_data[ETH_HLEN];
+
+ u32 hdr_len = TG3_TSO_IP_HDR_LEN + TG3_TSO_TCP_HDR_LEN +
+ TG3_TSO_TCP_OPT_LEN;
+
+ memcpy(tx_data + ETH_ALEN * 2, tg3_tso_header,
+ sizeof(tg3_tso_header));
+ mss = TG3_TSO_MSS;
+
+ val = tx_len - ETH_ALEN * 2 - sizeof(tg3_tso_header);
+ num_pkts = DIV_ROUND_UP(val, TG3_TSO_MSS);
+
+ /* Set the total length field in the IP header */
+ iph->tot_len = htons((u16)(mss + hdr_len));
+
+ base_flags = (TXD_FLAG_CPU_PRE_DMA |
+ TXD_FLAG_CPU_POST_DMA);
+
+ if (tg3_flag(tp, HW_TSO_1) ||
+ tg3_flag(tp, HW_TSO_2) ||
+ tg3_flag(tp, HW_TSO_3)) {
+ struct tcphdr *th;
+ val = ETH_HLEN + TG3_TSO_IP_HDR_LEN;
+ th = (struct tcphdr *)&tx_data[val];
+ th->check = 0;
+ } else
+ base_flags |= TXD_FLAG_TCPUDP_CSUM;
+
+ if (tg3_flag(tp, HW_TSO_3)) {
+ mss |= (hdr_len & 0xc) << 12;
+ if (hdr_len & 0x10)
+ base_flags |= 0x00000010;
+ base_flags |= (hdr_len & 0x3e0) << 5;
+ } else if (tg3_flag(tp, HW_TSO_2))
+ mss |= hdr_len << 9;
+ else if (tg3_flag(tp, HW_TSO_1) ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+ mss |= (TG3_TSO_TCP_OPT_LEN << 9);
+ } else {
+ base_flags |= (TG3_TSO_TCP_OPT_LEN << 10);
+ }
+
+ data_off = ETH_ALEN * 2 + sizeof(tg3_tso_header);
+ } else {
+ num_pkts = 1;
+ data_off = ETH_HLEN;
+ }
- for (i = 14; i < tx_len; i++)
+ for (i = data_off; i < tx_len; i++)
tx_data[i] = (u8) (i & 0xff);
map = pci_map_single(tp->pdev, skb->data, tx_len, PCI_DMA_TODEVICE);
@@ -11001,12 +11142,10 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
rx_start_idx = rnapi->hw_status->idx[0].rx_producer;
- num_pkts = 0;
-
- tg3_set_txd(tnapi, tnapi->tx_prod, map, tx_len, 0, 1);
+ tg3_set_txd(tnapi, tnapi->tx_prod, map, tx_len,
+ base_flags, (mss << 1) | 1);
tnapi->tx_prod++;
- num_pkts++;
tw32_tx_mbox(tnapi->prodmbox, tnapi->tx_prod);
tr32_mailbox(tnapi->prodmbox);
@@ -11036,29 +11175,56 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
if (rx_idx != rx_start_idx + num_pkts)
goto out;
- desc = &rnapi->rx_rcb[rx_start_idx];
- desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK;
- opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK;
- if (opaque_key != RXD_OPAQUE_RING_STD)
- goto out;
+ val = data_off;
+ while (rx_idx != rx_start_idx) {
+ desc = &rnapi->rx_rcb[rx_start_idx++];
+ desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK;
+ opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK;
- if ((desc->err_vlan & RXD_ERR_MASK) != 0 &&
- (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII))
- goto out;
+ if ((desc->err_vlan & RXD_ERR_MASK) != 0 &&
+ (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII))
+ goto out;
- rx_len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4;
- if (rx_len != tx_len)
- goto out;
+ rx_len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT)
+ - ETH_FCS_LEN;
- rx_skb = tpr->rx_std_buffers[desc_idx].skb;
+ if (loopback_mode != TG3_TSO_LOOPBACK) {
+ if (rx_len != tx_len)
+ goto out;
- map = dma_unmap_addr(&tpr->rx_std_buffers[desc_idx], mapping);
- pci_dma_sync_single_for_cpu(tp->pdev, map, rx_len, PCI_DMA_FROMDEVICE);
+ if (pktsz <= TG3_RX_STD_DMA_SZ - ETH_FCS_LEN) {
+ if (opaque_key != RXD_OPAQUE_RING_STD)
+ goto out;
+ } else {
+ if (opaque_key != RXD_OPAQUE_RING_JUMBO)
+ goto out;
+ }
+ } else if ((desc->type_flags & RXD_FLAG_TCPUDP_CSUM) &&
+ (desc->ip_tcp_csum & RXD_TCPCSUM_MASK)
+ >> RXD_TCPCSUM_SHIFT != 0xffff) {
+ goto out;
+ }
- for (i = 14; i < tx_len; i++) {
- if (*(rx_skb->data + i) != (u8) (i & 0xff))
+ if (opaque_key == RXD_OPAQUE_RING_STD) {
+ rx_skb = tpr->rx_std_buffers[desc_idx].skb;
+ map = dma_unmap_addr(&tpr->rx_std_buffers[desc_idx],
+ mapping);
+ } else if (opaque_key == RXD_OPAQUE_RING_JUMBO) {
+ rx_skb = tpr->rx_jmb_buffers[desc_idx].skb;
+ map = dma_unmap_addr(&tpr->rx_jmb_buffers[desc_idx],
+ mapping);
+ } else
goto out;
+
+ pci_dma_sync_single_for_cpu(tp->pdev, map, rx_len,
+ PCI_DMA_FROMDEVICE);
+
+ for (i = data_off; i < rx_len; i++, val++) {
+ if (*(rx_skb->data + i) != (u8) (val & 0xff))
+ goto out;
+ }
}
+
err = 0;
/* tg3_free_rings will unmap and free the rx_skb */
@@ -11066,10 +11232,13 @@ out:
return err;
}
-#define TG3_MAC_LOOPBACK_FAILED 1
-#define TG3_PHY_LOOPBACK_FAILED 2
-#define TG3_LOOPBACK_FAILED (TG3_MAC_LOOPBACK_FAILED | \
- TG3_PHY_LOOPBACK_FAILED)
+#define TG3_STD_LOOPBACK_FAILED 1
+#define TG3_JMB_LOOPBACK_FAILED 2
+#define TG3_TSO_LOOPBACK_FAILED 4
+
+#define TG3_MAC_LOOPBACK_SHIFT 0
+#define TG3_PHY_LOOPBACK_SHIFT 4
+#define TG3_LOOPBACK_FAILED 0x00000077
static int tg3_test_loopback(struct tg3 *tp)
{
@@ -11088,11 +11257,20 @@ static int tg3_test_loopback(struct tg3 *tp)
goto done;
}
+ if (tg3_flag(tp, ENABLE_RSS)) {
+ int i;
+
+ /* Reroute all rx packets to the 1st queue */
+ for (i = MAC_RSS_INDIR_TBL_0;
+ i < MAC_RSS_INDIR_TBL_0 + TG3_RSS_INDIR_TBL_SIZE; i += 4)
+ tw32(i, 0x0);
+ }
+
/* Turn off gphy autopowerdown. */
if (tp->phy_flags & TG3_PHYFLG_ENABLE_APD)
tg3_phy_toggle_apd(tp, false);
- if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) {
+ if (tg3_flag(tp, CPMU_PRESENT)) {
int i;
u32 status;
@@ -11118,10 +11296,14 @@ static int tg3_test_loopback(struct tg3 *tp)
CPMU_CTRL_LINK_AWARE_MODE));
}
- if (tg3_run_loopback(tp, TG3_MAC_LOOPBACK))
- err |= TG3_MAC_LOOPBACK_FAILED;
+ if (tg3_run_loopback(tp, ETH_FRAME_LEN, TG3_MAC_LOOPBACK))
+ err |= TG3_STD_LOOPBACK_FAILED << TG3_MAC_LOOPBACK_SHIFT;
- if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) {
+ if (tg3_flag(tp, JUMBO_RING_ENABLE) &&
+ tg3_run_loopback(tp, 9000 + ETH_HLEN, TG3_MAC_LOOPBACK))
+ err |= TG3_JMB_LOOPBACK_FAILED << TG3_MAC_LOOPBACK_SHIFT;
+
+ if (tg3_flag(tp, CPMU_PRESENT)) {
tw32(TG3_CPMU_CTRL, cpmuctrl);
/* Release the mutex */
@@ -11129,9 +11311,18 @@ static int tg3_test_loopback(struct tg3 *tp)
}
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;
+ !tg3_flag(tp, USE_PHYLIB)) {
+ if (tg3_run_loopback(tp, ETH_FRAME_LEN, TG3_PHY_LOOPBACK))
+ err |= TG3_STD_LOOPBACK_FAILED <<
+ TG3_PHY_LOOPBACK_SHIFT;
+ if (tg3_flag(tp, TSO_CAPABLE) &&
+ tg3_run_loopback(tp, ETH_FRAME_LEN, TG3_TSO_LOOPBACK))
+ err |= TG3_TSO_LOOPBACK_FAILED <<
+ TG3_PHY_LOOPBACK_SHIFT;
+ if (tg3_flag(tp, JUMBO_RING_ENABLE) &&
+ tg3_run_loopback(tp, 9000 + ETH_HLEN, TG3_PHY_LOOPBACK))
+ err |= TG3_JMB_LOOPBACK_FAILED <<
+ TG3_PHY_LOOPBACK_SHIFT;
}
/* Re-enable gphy autopowerdown. */
@@ -11176,7 +11367,7 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
tg3_halt(tp, RESET_KIND_SUSPEND, 1);
err = tg3_nvram_lock(tp);
tg3_halt_cpu(tp, RX_CPU_BASE);
- if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
+ if (!tg3_flag(tp, 5705_PLUS))
tg3_halt_cpu(tp, TX_CPU_BASE);
if (!err)
tg3_nvram_unlock(tp);
@@ -11206,7 +11397,7 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
if (netif_running(dev)) {
- tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
+ tg3_flag_set(tp, INIT_COMPLETE);
err2 = tg3_restart_hw(tp, 1);
if (!err2)
tg3_netif_start(tp);
@@ -11228,7 +11419,7 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
struct tg3 *tp = netdev_priv(dev);
int err;
- if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+ if (tg3_flag(tp, USE_PHYLIB)) {
struct phy_device *phydev;
if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED))
return -EAGAIN;
@@ -11247,9 +11438,7 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)
break; /* We have no PHY */
- if ((tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) ||
- ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
- !netif_running(dev)))
+ if (!netif_running(dev))
return -EAGAIN;
spin_lock_bh(&tp->lock);
@@ -11265,9 +11454,7 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)
break; /* We have no PHY */
- if ((tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) ||
- ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
- !netif_running(dev)))
+ if (!netif_running(dev))
return -EAGAIN;
spin_lock_bh(&tp->lock);
@@ -11297,7 +11484,7 @@ static int tg3_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec)
u32 max_rxcoal_tick_int = 0, max_txcoal_tick_int = 0;
u32 max_stat_coal_ticks = 0, min_stat_coal_ticks = 0;
- if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
+ if (!tg3_flag(tp, 5705_PLUS)) {
max_rxcoal_tick_int = MAX_RXCOAL_TICK_INT;
max_txcoal_tick_int = MAX_TXCOAL_TICK_INT;
max_stat_coal_ticks = MAX_STAT_COAL_TICKS;
@@ -11364,14 +11551,9 @@ static const struct ethtool_ops tg3_ethtool_ops = {
.set_ringparam = tg3_set_ringparam,
.get_pauseparam = tg3_get_pauseparam,
.set_pauseparam = tg3_set_pauseparam,
- .get_rx_csum = tg3_get_rx_csum,
- .set_rx_csum = tg3_set_rx_csum,
- .set_tx_csum = tg3_set_tx_csum,
- .set_sg = ethtool_op_set_sg,
- .set_tso = tg3_set_tso,
.self_test = tg3_self_test,
.get_strings = tg3_get_strings,
- .phys_id = tg3_phys_id,
+ .set_phys_id = tg3_set_phys_id,
.get_ethtool_stats = tg3_get_ethtool_stats,
.get_coalesce = tg3_get_coalesce,
.set_coalesce = tg3_set_coalesce,
@@ -11416,8 +11598,7 @@ static void __devinit tg3_get_nvram_size(struct tg3 *tp)
{
u32 val;
- if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) ||
- tg3_nvram_read(tp, 0, &val) != 0)
+ if (tg3_flag(tp, NO_NVRAM) || tg3_nvram_read(tp, 0, &val) != 0)
return;
/* Selfboot format */
@@ -11452,19 +11633,19 @@ static void __devinit tg3_get_nvram_info(struct tg3 *tp)
nvcfg1 = tr32(NVRAM_CFG1);
if (nvcfg1 & NVRAM_CFG1_FLASHIF_ENAB) {
- tp->tg3_flags2 |= TG3_FLG2_FLASH;
+ tg3_flag_set(tp, FLASH);
} else {
nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS;
tw32(NVRAM_CFG1, nvcfg1);
}
- if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) ||
- (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
+ tg3_flag(tp, 5780_CLASS)) {
switch (nvcfg1 & NVRAM_CFG1_VENDOR_MASK) {
case FLASH_VENDOR_ATMEL_FLASH_BUFFERED:
tp->nvram_jedecnum = JEDEC_ATMEL;
tp->nvram_pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE;
- tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+ tg3_flag_set(tp, NVRAM_BUFFERED);
break;
case FLASH_VENDOR_ATMEL_FLASH_UNBUFFERED:
tp->nvram_jedecnum = JEDEC_ATMEL;
@@ -11473,12 +11654,12 @@ static void __devinit tg3_get_nvram_info(struct tg3 *tp)
case FLASH_VENDOR_ATMEL_EEPROM:
tp->nvram_jedecnum = JEDEC_ATMEL;
tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE;
- tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+ tg3_flag_set(tp, NVRAM_BUFFERED);
break;
case FLASH_VENDOR_ST:
tp->nvram_jedecnum = JEDEC_ST;
tp->nvram_pagesize = ST_M45PEX0_PAGE_SIZE;
- tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+ tg3_flag_set(tp, NVRAM_BUFFERED);
break;
case FLASH_VENDOR_SAIFUN:
tp->nvram_jedecnum = JEDEC_SAIFUN;
@@ -11493,7 +11674,7 @@ static void __devinit tg3_get_nvram_info(struct tg3 *tp)
} else {
tp->nvram_jedecnum = JEDEC_ATMEL;
tp->nvram_pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE;
- tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+ tg3_flag_set(tp, NVRAM_BUFFERED);
}
}
@@ -11532,29 +11713,29 @@ static void __devinit tg3_get_5752_nvram_info(struct tg3 *tp)
/* NVRAM protection for TPM */
if (nvcfg1 & (1 << 27))
- tp->tg3_flags3 |= TG3_FLG3_PROTECTED_NVRAM;
+ tg3_flag_set(tp, PROTECTED_NVRAM);
switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) {
case FLASH_5752VENDOR_ATMEL_EEPROM_64KHZ:
case FLASH_5752VENDOR_ATMEL_EEPROM_376KHZ:
tp->nvram_jedecnum = JEDEC_ATMEL;
- tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+ tg3_flag_set(tp, NVRAM_BUFFERED);
break;
case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED:
tp->nvram_jedecnum = JEDEC_ATMEL;
- tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
- tp->tg3_flags2 |= TG3_FLG2_FLASH;
+ tg3_flag_set(tp, NVRAM_BUFFERED);
+ tg3_flag_set(tp, FLASH);
break;
case FLASH_5752VENDOR_ST_M45PE10:
case FLASH_5752VENDOR_ST_M45PE20:
case FLASH_5752VENDOR_ST_M45PE40:
tp->nvram_jedecnum = JEDEC_ST;
- tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
- tp->tg3_flags2 |= TG3_FLG2_FLASH;
+ tg3_flag_set(tp, NVRAM_BUFFERED);
+ tg3_flag_set(tp, FLASH);
break;
}
- if (tp->tg3_flags2 & TG3_FLG2_FLASH) {
+ if (tg3_flag(tp, FLASH)) {
tg3_nvram_get_pagesize(tp, nvcfg1);
} else {
/* For eeprom, set pagesize to maximum eeprom size */
@@ -11573,7 +11754,7 @@ static void __devinit tg3_get_5755_nvram_info(struct tg3 *tp)
/* NVRAM protection for TPM */
if (nvcfg1 & (1 << 27)) {
- tp->tg3_flags3 |= TG3_FLG3_PROTECTED_NVRAM;
+ tg3_flag_set(tp, PROTECTED_NVRAM);
protect = 1;
}
@@ -11584,8 +11765,8 @@ static void __devinit tg3_get_5755_nvram_info(struct tg3 *tp)
case FLASH_5755VENDOR_ATMEL_FLASH_3:
case FLASH_5755VENDOR_ATMEL_FLASH_5:
tp->nvram_jedecnum = JEDEC_ATMEL;
- tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
- tp->tg3_flags2 |= TG3_FLG2_FLASH;
+ tg3_flag_set(tp, NVRAM_BUFFERED);
+ tg3_flag_set(tp, FLASH);
tp->nvram_pagesize = 264;
if (nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_1 ||
nvcfg1 == FLASH_5755VENDOR_ATMEL_FLASH_5)
@@ -11602,8 +11783,8 @@ static void __devinit tg3_get_5755_nvram_info(struct tg3 *tp)
case FLASH_5752VENDOR_ST_M45PE20:
case FLASH_5752VENDOR_ST_M45PE40:
tp->nvram_jedecnum = JEDEC_ST;
- tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
- tp->tg3_flags2 |= TG3_FLG2_FLASH;
+ tg3_flag_set(tp, NVRAM_BUFFERED);
+ tg3_flag_set(tp, FLASH);
tp->nvram_pagesize = 256;
if (nvcfg1 == FLASH_5752VENDOR_ST_M45PE10)
tp->nvram_size = (protect ?
@@ -11633,7 +11814,7 @@ static void __devinit tg3_get_5787_nvram_info(struct tg3 *tp)
case FLASH_5787VENDOR_MICRO_EEPROM_64KHZ:
case FLASH_5787VENDOR_MICRO_EEPROM_376KHZ:
tp->nvram_jedecnum = JEDEC_ATMEL;
- tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+ tg3_flag_set(tp, NVRAM_BUFFERED);
tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE;
nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS;
@@ -11644,16 +11825,16 @@ static void __devinit tg3_get_5787_nvram_info(struct tg3 *tp)
case FLASH_5755VENDOR_ATMEL_FLASH_2:
case FLASH_5755VENDOR_ATMEL_FLASH_3:
tp->nvram_jedecnum = JEDEC_ATMEL;
- tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
- tp->tg3_flags2 |= TG3_FLG2_FLASH;
+ tg3_flag_set(tp, NVRAM_BUFFERED);
+ tg3_flag_set(tp, FLASH);
tp->nvram_pagesize = 264;
break;
case FLASH_5752VENDOR_ST_M45PE10:
case FLASH_5752VENDOR_ST_M45PE20:
case FLASH_5752VENDOR_ST_M45PE40:
tp->nvram_jedecnum = JEDEC_ST;
- tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
- tp->tg3_flags2 |= TG3_FLG2_FLASH;
+ tg3_flag_set(tp, NVRAM_BUFFERED);
+ tg3_flag_set(tp, FLASH);
tp->nvram_pagesize = 256;
break;
}
@@ -11667,7 +11848,7 @@ static void __devinit tg3_get_5761_nvram_info(struct tg3 *tp)
/* NVRAM protection for TPM */
if (nvcfg1 & (1 << 27)) {
- tp->tg3_flags3 |= TG3_FLG3_PROTECTED_NVRAM;
+ tg3_flag_set(tp, PROTECTED_NVRAM);
protect = 1;
}
@@ -11682,9 +11863,9 @@ static void __devinit tg3_get_5761_nvram_info(struct tg3 *tp)
case FLASH_5761VENDOR_ATMEL_MDB081D:
case FLASH_5761VENDOR_ATMEL_MDB161D:
tp->nvram_jedecnum = JEDEC_ATMEL;
- tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
- tp->tg3_flags2 |= TG3_FLG2_FLASH;
- tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS;
+ tg3_flag_set(tp, NVRAM_BUFFERED);
+ tg3_flag_set(tp, FLASH);
+ tg3_flag_set(tp, NO_NVRAM_ADDR_TRANS);
tp->nvram_pagesize = 256;
break;
case FLASH_5761VENDOR_ST_A_M45PE20:
@@ -11696,8 +11877,8 @@ static void __devinit tg3_get_5761_nvram_info(struct tg3 *tp)
case FLASH_5761VENDOR_ST_M_M45PE80:
case FLASH_5761VENDOR_ST_M_M45PE16:
tp->nvram_jedecnum = JEDEC_ST;
- tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
- tp->tg3_flags2 |= TG3_FLG2_FLASH;
+ tg3_flag_set(tp, NVRAM_BUFFERED);
+ tg3_flag_set(tp, FLASH);
tp->nvram_pagesize = 256;
break;
}
@@ -11737,7 +11918,7 @@ static void __devinit tg3_get_5761_nvram_info(struct tg3 *tp)
static void __devinit tg3_get_5906_nvram_info(struct tg3 *tp)
{
tp->nvram_jedecnum = JEDEC_ATMEL;
- tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+ tg3_flag_set(tp, NVRAM_BUFFERED);
tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE;
}
@@ -11751,7 +11932,7 @@ static void __devinit tg3_get_57780_nvram_info(struct tg3 *tp)
case FLASH_5787VENDOR_ATMEL_EEPROM_376KHZ:
case FLASH_5787VENDOR_MICRO_EEPROM_376KHZ:
tp->nvram_jedecnum = JEDEC_ATMEL;
- tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+ tg3_flag_set(tp, NVRAM_BUFFERED);
tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE;
nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS;
@@ -11765,8 +11946,8 @@ static void __devinit tg3_get_57780_nvram_info(struct tg3 *tp)
case FLASH_57780VENDOR_ATMEL_AT45DB041D:
case FLASH_57780VENDOR_ATMEL_AT45DB041B:
tp->nvram_jedecnum = JEDEC_ATMEL;
- tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
- tp->tg3_flags2 |= TG3_FLG2_FLASH;
+ tg3_flag_set(tp, NVRAM_BUFFERED);
+ tg3_flag_set(tp, FLASH);
switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) {
case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED:
@@ -11788,8 +11969,8 @@ static void __devinit tg3_get_57780_nvram_info(struct tg3 *tp)
case FLASH_5752VENDOR_ST_M45PE20:
case FLASH_5752VENDOR_ST_M45PE40:
tp->nvram_jedecnum = JEDEC_ST;
- tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
- tp->tg3_flags2 |= TG3_FLG2_FLASH;
+ tg3_flag_set(tp, NVRAM_BUFFERED);
+ tg3_flag_set(tp, FLASH);
switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) {
case FLASH_5752VENDOR_ST_M45PE10:
@@ -11804,13 +11985,13 @@ static void __devinit tg3_get_57780_nvram_info(struct tg3 *tp)
}
break;
default:
- tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM;
+ tg3_flag_set(tp, NO_NVRAM);
return;
}
tg3_nvram_get_pagesize(tp, nvcfg1);
if (tp->nvram_pagesize != 264 && tp->nvram_pagesize != 528)
- tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS;
+ tg3_flag_set(tp, NO_NVRAM_ADDR_TRANS);
}
@@ -11824,7 +12005,7 @@ static void __devinit tg3_get_5717_nvram_info(struct tg3 *tp)
case FLASH_5717VENDOR_ATMEL_EEPROM:
case FLASH_5717VENDOR_MICRO_EEPROM:
tp->nvram_jedecnum = JEDEC_ATMEL;
- tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+ tg3_flag_set(tp, NVRAM_BUFFERED);
tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE;
nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS;
@@ -11838,11 +12019,13 @@ static void __devinit tg3_get_5717_nvram_info(struct tg3 *tp)
case FLASH_5717VENDOR_ATMEL_ADB021D:
case FLASH_5717VENDOR_ATMEL_45USPT:
tp->nvram_jedecnum = JEDEC_ATMEL;
- tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
- tp->tg3_flags2 |= TG3_FLG2_FLASH;
+ tg3_flag_set(tp, NVRAM_BUFFERED);
+ tg3_flag_set(tp, FLASH);
switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) {
case FLASH_5717VENDOR_ATMEL_MDB021D:
+ /* Detect size with tg3_nvram_get_size() */
+ break;
case FLASH_5717VENDOR_ATMEL_ADB021B:
case FLASH_5717VENDOR_ATMEL_ADB021D:
tp->nvram_size = TG3_NVRAM_SIZE_256KB;
@@ -11863,13 +12046,15 @@ static void __devinit tg3_get_5717_nvram_info(struct tg3 *tp)
case FLASH_5717VENDOR_ST_25USPT:
case FLASH_5717VENDOR_ST_45USPT:
tp->nvram_jedecnum = JEDEC_ST;
- tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
- tp->tg3_flags2 |= TG3_FLG2_FLASH;
+ tg3_flag_set(tp, NVRAM_BUFFERED);
+ tg3_flag_set(tp, FLASH);
switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) {
case FLASH_5717VENDOR_ST_M_M25PE20:
- case FLASH_5717VENDOR_ST_A_M25PE20:
case FLASH_5717VENDOR_ST_M_M45PE20:
+ /* Detect size with tg3_nvram_get_size() */
+ break;
+ case FLASH_5717VENDOR_ST_A_M25PE20:
case FLASH_5717VENDOR_ST_A_M45PE20:
tp->nvram_size = TG3_NVRAM_SIZE_256KB;
break;
@@ -11879,13 +12064,125 @@ static void __devinit tg3_get_5717_nvram_info(struct tg3 *tp)
}
break;
default:
- tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM;
+ tg3_flag_set(tp, NO_NVRAM);
+ return;
+ }
+
+ tg3_nvram_get_pagesize(tp, nvcfg1);
+ if (tp->nvram_pagesize != 264 && tp->nvram_pagesize != 528)
+ tg3_flag_set(tp, NO_NVRAM_ADDR_TRANS);
+}
+
+static void __devinit tg3_get_5720_nvram_info(struct tg3 *tp)
+{
+ u32 nvcfg1, nvmpinstrp;
+
+ nvcfg1 = tr32(NVRAM_CFG1);
+ nvmpinstrp = nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK;
+
+ switch (nvmpinstrp) {
+ case FLASH_5720_EEPROM_HD:
+ case FLASH_5720_EEPROM_LD:
+ tp->nvram_jedecnum = JEDEC_ATMEL;
+ tg3_flag_set(tp, NVRAM_BUFFERED);
+
+ nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS;
+ tw32(NVRAM_CFG1, nvcfg1);
+ if (nvmpinstrp == FLASH_5720_EEPROM_HD)
+ tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE;
+ else
+ tp->nvram_pagesize = ATMEL_AT24C02_CHIP_SIZE;
+ return;
+ case FLASH_5720VENDOR_M_ATMEL_DB011D:
+ case FLASH_5720VENDOR_A_ATMEL_DB011B:
+ case FLASH_5720VENDOR_A_ATMEL_DB011D:
+ case FLASH_5720VENDOR_M_ATMEL_DB021D:
+ case FLASH_5720VENDOR_A_ATMEL_DB021B:
+ case FLASH_5720VENDOR_A_ATMEL_DB021D:
+ case FLASH_5720VENDOR_M_ATMEL_DB041D:
+ case FLASH_5720VENDOR_A_ATMEL_DB041B:
+ case FLASH_5720VENDOR_A_ATMEL_DB041D:
+ case FLASH_5720VENDOR_M_ATMEL_DB081D:
+ case FLASH_5720VENDOR_A_ATMEL_DB081D:
+ case FLASH_5720VENDOR_ATMEL_45USPT:
+ tp->nvram_jedecnum = JEDEC_ATMEL;
+ tg3_flag_set(tp, NVRAM_BUFFERED);
+ tg3_flag_set(tp, FLASH);
+
+ switch (nvmpinstrp) {
+ case FLASH_5720VENDOR_M_ATMEL_DB021D:
+ case FLASH_5720VENDOR_A_ATMEL_DB021B:
+ case FLASH_5720VENDOR_A_ATMEL_DB021D:
+ tp->nvram_size = TG3_NVRAM_SIZE_256KB;
+ break;
+ case FLASH_5720VENDOR_M_ATMEL_DB041D:
+ case FLASH_5720VENDOR_A_ATMEL_DB041B:
+ case FLASH_5720VENDOR_A_ATMEL_DB041D:
+ tp->nvram_size = TG3_NVRAM_SIZE_512KB;
+ break;
+ case FLASH_5720VENDOR_M_ATMEL_DB081D:
+ case FLASH_5720VENDOR_A_ATMEL_DB081D:
+ tp->nvram_size = TG3_NVRAM_SIZE_1MB;
+ break;
+ default:
+ tp->nvram_size = TG3_NVRAM_SIZE_128KB;
+ break;
+ }
+ break;
+ case FLASH_5720VENDOR_M_ST_M25PE10:
+ case FLASH_5720VENDOR_M_ST_M45PE10:
+ case FLASH_5720VENDOR_A_ST_M25PE10:
+ case FLASH_5720VENDOR_A_ST_M45PE10:
+ case FLASH_5720VENDOR_M_ST_M25PE20:
+ case FLASH_5720VENDOR_M_ST_M45PE20:
+ case FLASH_5720VENDOR_A_ST_M25PE20:
+ case FLASH_5720VENDOR_A_ST_M45PE20:
+ case FLASH_5720VENDOR_M_ST_M25PE40:
+ case FLASH_5720VENDOR_M_ST_M45PE40:
+ case FLASH_5720VENDOR_A_ST_M25PE40:
+ case FLASH_5720VENDOR_A_ST_M45PE40:
+ case FLASH_5720VENDOR_M_ST_M25PE80:
+ case FLASH_5720VENDOR_M_ST_M45PE80:
+ case FLASH_5720VENDOR_A_ST_M25PE80:
+ case FLASH_5720VENDOR_A_ST_M45PE80:
+ case FLASH_5720VENDOR_ST_25USPT:
+ case FLASH_5720VENDOR_ST_45USPT:
+ tp->nvram_jedecnum = JEDEC_ST;
+ tg3_flag_set(tp, NVRAM_BUFFERED);
+ tg3_flag_set(tp, FLASH);
+
+ switch (nvmpinstrp) {
+ case FLASH_5720VENDOR_M_ST_M25PE20:
+ case FLASH_5720VENDOR_M_ST_M45PE20:
+ case FLASH_5720VENDOR_A_ST_M25PE20:
+ case FLASH_5720VENDOR_A_ST_M45PE20:
+ tp->nvram_size = TG3_NVRAM_SIZE_256KB;
+ break;
+ case FLASH_5720VENDOR_M_ST_M25PE40:
+ case FLASH_5720VENDOR_M_ST_M45PE40:
+ case FLASH_5720VENDOR_A_ST_M25PE40:
+ case FLASH_5720VENDOR_A_ST_M45PE40:
+ tp->nvram_size = TG3_NVRAM_SIZE_512KB;
+ break;
+ case FLASH_5720VENDOR_M_ST_M25PE80:
+ case FLASH_5720VENDOR_M_ST_M45PE80:
+ case FLASH_5720VENDOR_A_ST_M25PE80:
+ case FLASH_5720VENDOR_A_ST_M45PE80:
+ tp->nvram_size = TG3_NVRAM_SIZE_1MB;
+ break;
+ default:
+ tp->nvram_size = TG3_NVRAM_SIZE_128KB;
+ break;
+ }
+ break;
+ default:
+ tg3_flag_set(tp, NO_NVRAM);
return;
}
tg3_nvram_get_pagesize(tp, nvcfg1);
if (tp->nvram_pagesize != 264 && tp->nvram_pagesize != 528)
- tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS;
+ tg3_flag_set(tp, NO_NVRAM_ADDR_TRANS);
}
/* Chips other than 5700/5701 use the NVRAM for fetching info. */
@@ -11905,7 +12202,7 @@ static void __devinit tg3_nvram_init(struct tg3 *tp)
if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) {
- tp->tg3_flags |= TG3_FLAG_NVRAM;
+ tg3_flag_set(tp, NVRAM);
if (tg3_nvram_lock(tp)) {
netdev_warn(tp->dev,
@@ -11935,6 +12232,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp)
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 if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+ tg3_get_5720_nvram_info(tp);
else
tg3_get_nvram_info(tp);
@@ -11945,7 +12244,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp)
tg3_nvram_unlock(tp);
} else {
- tp->tg3_flags &= ~(TG3_FLAG_NVRAM | TG3_FLAG_NVRAM_BUFFERED);
+ tg3_flag_clear(tp, NVRAM);
+ tg3_flag_clear(tp, NVRAM_BUFFERED);
tg3_get_eeprom_size(tp);
}
@@ -12128,7 +12428,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len,
nvram_cmd |= NVRAM_CMD_LAST;
if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 &&
- !(tp->tg3_flags3 & TG3_FLG3_5755_PLUS) &&
+ !tg3_flag(tp, 5755_PLUS) &&
(tp->nvram_jedecnum == JEDEC_ST) &&
(nvram_cmd & NVRAM_CMD_FIRST)) {
@@ -12138,7 +12438,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len,
break;
}
- if (!(tp->tg3_flags2 & TG3_FLG2_FLASH)) {
+ if (!tg3_flag(tp, FLASH)) {
/* We always do complete word writes to eeprom. */
nvram_cmd |= (NVRAM_CMD_FIRST | NVRAM_CMD_LAST);
}
@@ -12154,13 +12454,13 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf)
{
int ret;
- if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) {
+ if (tg3_flag(tp, EEPROM_WRITE_PROT)) {
tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl &
~GRC_LCLCTRL_GPIO_OUTPUT1);
udelay(40);
}
- if (!(tp->tg3_flags & TG3_FLAG_NVRAM)) {
+ if (!tg3_flag(tp, NVRAM)) {
ret = tg3_nvram_write_block_using_eeprom(tp, offset, len, buf);
} else {
u32 grc_mode;
@@ -12170,16 +12470,13 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf)
return ret;
tg3_enable_nvram_access(tp);
- if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
- !(tp->tg3_flags3 & TG3_FLG3_PROTECTED_NVRAM))
+ if (tg3_flag(tp, 5750_PLUS) && !tg3_flag(tp, PROTECTED_NVRAM))
tw32(NVRAM_WRITE1, 0x406);
grc_mode = tr32(GRC_MODE);
tw32(GRC_MODE, grc_mode | GRC_MODE_NVRAM_WR_ENABLE);
- if ((tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) ||
- !(tp->tg3_flags2 & TG3_FLG2_FLASH)) {
-
+ if (tg3_flag(tp, NVRAM_BUFFERED) || !tg3_flag(tp, FLASH)) {
ret = tg3_nvram_write_block_buffered(tp, offset, len,
buf);
} else {
@@ -12194,7 +12491,7 @@ static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf)
tg3_nvram_unlock(tp);
}
- if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) {
+ if (tg3_flag(tp, EEPROM_WRITE_PROT)) {
tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl);
udelay(40);
}
@@ -12316,19 +12613,20 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
tp->led_ctrl = LED_CTRL_MODE_PHY_1;
/* Assume an onboard device and WOL capable by default. */
- tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT | TG3_FLAG_WOL_CAP;
+ tg3_flag_set(tp, EEPROM_WRITE_PROT);
+ tg3_flag_set(tp, WOL_CAP);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
if (!(tr32(PCIE_TRANSACTION_CFG) & PCIE_TRANS_CFG_LOM)) {
- tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT;
- tp->tg3_flags2 |= TG3_FLG2_IS_NIC;
+ tg3_flag_clear(tp, EEPROM_WRITE_PROT);
+ tg3_flag_set(tp, IS_NIC);
}
val = tr32(VCPU_CFGSHDW);
if (val & VCPU_CFGSHDW_ASPM_DBNC)
- tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND;
+ tg3_flag_set(tp, ASPM_WORKAROUND);
if ((val & VCPU_CFGSHDW_WOL_ENABLE) &&
(val & VCPU_CFGSHDW_WOL_MAGPKT)) {
- tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
+ tg3_flag_set(tp, WOL_ENABLE);
device_set_wakeup_enable(&tp->pdev->dev, true);
}
goto done;
@@ -12345,9 +12643,9 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
tg3_read_mem(tp, NIC_SRAM_DATA_VER, &ver);
ver >>= NIC_SRAM_DATA_VER_SHIFT;
- if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) &&
- (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) &&
- (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5703) &&
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5703 &&
(ver > 0) && (ver < 0x100))
tg3_read_mem(tp, NIC_SRAM_DATA_CFG_2, &cfg2);
@@ -12371,13 +12669,13 @@ 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_5705_PLUS))
+ if (!tg3_flag(tp, 5705_PLUS))
tp->phy_flags |= TG3_PHYFLG_PHY_SERDES;
else
tp->phy_flags |= TG3_PHYFLG_MII_SERDES;
}
- if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
+ if (tg3_flag(tp, 5750_PLUS))
led_cfg = cfg2 & (NIC_SRAM_DATA_CFG_LED_MODE_MASK |
SHASTA_EXT_LED_MODE_MASK);
else
@@ -12437,34 +12735,34 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
tp->led_ctrl = LED_CTRL_MODE_PHY_1;
if (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP) {
- tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
+ tg3_flag_set(tp, EEPROM_WRITE_PROT);
if ((tp->pdev->subsystem_vendor ==
PCI_VENDOR_ID_ARIMA) &&
(tp->pdev->subsystem_device == 0x205a ||
tp->pdev->subsystem_device == 0x2063))
- tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT;
+ tg3_flag_clear(tp, EEPROM_WRITE_PROT);
} else {
- tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT;
- tp->tg3_flags2 |= TG3_FLG2_IS_NIC;
+ tg3_flag_clear(tp, EEPROM_WRITE_PROT);
+ tg3_flag_set(tp, IS_NIC);
}
if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE) {
- tp->tg3_flags |= TG3_FLAG_ENABLE_ASF;
- if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
- tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE;
+ tg3_flag_set(tp, ENABLE_ASF);
+ if (tg3_flag(tp, 5750_PLUS))
+ tg3_flag_set(tp, ASF_NEW_HANDSHAKE);
}
if ((nic_cfg & NIC_SRAM_DATA_CFG_APE_ENABLE) &&
- (tp->tg3_flags2 & TG3_FLG2_5750_PLUS))
- tp->tg3_flags3 |= TG3_FLG3_ENABLE_APE;
+ tg3_flag(tp, 5750_PLUS))
+ tg3_flag_set(tp, ENABLE_APE);
if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES &&
!(nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL))
- tp->tg3_flags &= ~TG3_FLAG_WOL_CAP;
+ tg3_flag_clear(tp, WOL_CAP);
- if ((tp->tg3_flags & TG3_FLAG_WOL_CAP) &&
+ if (tg3_flag(tp, WOL_CAP) &&
(nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE)) {
- tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
+ tg3_flag_set(tp, WOL_ENABLE);
device_set_wakeup_enable(&tp->pdev->dev, true);
}
@@ -12476,33 +12774,33 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
if (cfg2 & (1 << 18))
tp->phy_flags |= TG3_PHYFLG_SERDES_PREEMPHASIS;
- if (((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) ||
- ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 &&
- GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX))) &&
+ if ((tg3_flag(tp, 57765_PLUS) ||
+ (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->phy_flags |= TG3_PHYFLG_ENABLE_APD;
- if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) &&
+ if (tg3_flag(tp, PCI_EXPRESS) &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 &&
- !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) {
+ !tg3_flag(tp, 57765_PLUS)) {
u32 cfg3;
tg3_read_mem(tp, NIC_SRAM_DATA_CFG_3, &cfg3);
if (cfg3 & NIC_SRAM_ASPM_DEBOUNCE)
- tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND;
+ tg3_flag_set(tp, ASPM_WORKAROUND);
}
if (cfg4 & NIC_SRAM_RGMII_INBAND_DISABLE)
- tp->tg3_flags3 |= TG3_FLG3_RGMII_INBAND_DISABLE;
+ tg3_flag_set(tp, RGMII_INBAND_DISABLE);
if (cfg4 & NIC_SRAM_RGMII_EXT_IBND_RX_EN)
- tp->tg3_flags3 |= TG3_FLG3_RGMII_EXT_IBND_RX_EN;
+ tg3_flag_set(tp, RGMII_EXT_IBND_RX_EN);
if (cfg4 & NIC_SRAM_RGMII_EXT_IBND_TX_EN)
- tp->tg3_flags3 |= TG3_FLG3_RGMII_EXT_IBND_TX_EN;
+ tg3_flag_set(tp, RGMII_EXT_IBND_TX_EN);
}
done:
- if (tp->tg3_flags & TG3_FLAG_WOL_CAP)
+ if (tg3_flag(tp, WOL_CAP))
device_set_wakeup_enable(&tp->pdev->dev,
- tp->tg3_flags & TG3_FLAG_WOL_ENABLE);
+ tg3_flag(tp, WOL_ENABLE));
else
device_set_wakeup_capable(&tp->pdev->dev, false);
}
@@ -12592,18 +12890,17 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
int err;
/* flow control autonegotiation is default behavior */
- tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
+ tg3_flag_set(tp, PAUSE_AUTONEG);
tp->link_config.flowctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
- if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)
+ if (tg3_flag(tp, USE_PHYLIB))
return tg3_phy_init(tp);
/* Reading the PHY ID register can conflict with ASF
* firmware access to the PHY hardware.
*/
err = 0;
- if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
- (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) {
+ if (tg3_flag(tp, ENABLE_ASF) || tg3_flag(tp, ENABLE_APE)) {
hw_phy_id = hw_phy_id_masked = TG3_PHY_ID_INVALID;
} else {
/* Now read the physical PHY_ID from the chip and verify
@@ -12659,9 +12956,9 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
tg3_phy_init_link_config(tp);
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;
+ !tg3_flag(tp, ENABLE_APE) &&
+ !tg3_flag(tp, ENABLE_ASF)) {
+ u32 bmsr, mask;
tg3_readphy(tp, MII_BMSR, &bmsr);
if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
@@ -12672,36 +12969,18 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
if (err)
return err;
- adv_reg = (ADVERTISE_10HALF | ADVERTISE_10FULL |
- ADVERTISE_100HALF | ADVERTISE_100FULL |
- ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
- tg3_ctrl = 0;
- 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 ||
- tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)
- tg3_ctrl |= (MII_TG3_CTRL_AS_MASTER |
- MII_TG3_CTRL_ENABLE_AS_MASTER);
- }
+ tg3_phy_set_wirespeed(tp);
mask = (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |
ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full);
if (!tg3_copper_is_advertising_all(tp, mask)) {
- tg3_writephy(tp, MII_ADVERTISE, adv_reg);
-
- if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY))
- tg3_writephy(tp, MII_TG3_CTRL, tg3_ctrl);
+ tg3_phy_autoneg_cfg(tp, tp->link_config.advertising,
+ tp->link_config.flowctrl);
tg3_writephy(tp, MII_BMCR,
BMCR_ANENABLE | BMCR_ANRESTART);
}
- tg3_phy_set_wirespeed(tp);
-
- tg3_writephy(tp, MII_ADVERTISE, adv_reg);
- if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY))
- tg3_writephy(tp, MII_TG3_CTRL, tg3_ctrl);
}
skip_phy_reset:
@@ -12721,46 +13000,11 @@ static void __devinit tg3_read_vpd(struct tg3 *tp)
u8 *vpd_data;
unsigned int block_end, rosize, len;
int j, i = 0;
- u32 magic;
- if ((tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) ||
- tg3_nvram_read(tp, 0x0, &magic))
- goto out_no_vpd;
-
- vpd_data = kmalloc(TG3_NVM_VPD_LEN, GFP_KERNEL);
+ vpd_data = (u8 *)tg3_vpd_readblock(tp);
if (!vpd_data)
goto out_no_vpd;
- if (magic == TG3_EEPROM_MAGIC) {
- for (i = 0; i < TG3_NVM_VPD_LEN; i += 4) {
- u32 tmp;
-
- /* The data is in little-endian format in NVRAM.
- * Use the big-endian read routines to preserve
- * the byte order as it exists in NVRAM.
- */
- if (tg3_nvram_read_be32(tp, TG3_NVM_VPD_OFF + i, &tmp))
- goto out_not_found;
-
- memcpy(&vpd_data[i], &tmp, sizeof(tmp));
- }
- } else {
- ssize_t cnt;
- unsigned int pos = 0;
-
- for (; pos < TG3_NVM_VPD_LEN && i < 3; i++, pos += cnt) {
- cnt = pci_read_vpd(tp->pdev, pos,
- TG3_NVM_VPD_LEN - pos,
- &vpd_data[pos]);
- if (cnt == -ETIMEDOUT || cnt == -EINTR)
- cnt = 0;
- else if (cnt < 0)
- goto out_not_found;
- }
- if (pos != TG3_NVM_VPD_LEN)
- goto out_not_found;
- }
-
i = pci_vpd_find_tag(vpd_data, 0, TG3_NVM_VPD_LEN,
PCI_VPD_LRDT_RO_DATA);
if (i < 0)
@@ -13014,7 +13258,7 @@ static void __devinit tg3_read_mgmtfw_ver(struct tg3 *tp)
if (offset == TG3_NVM_DIR_END)
return;
- if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
+ if (!tg3_flag(tp, 5705_PLUS))
start = 0x08000000;
else if (tg3_nvram_read(tp, offset - 4, &start))
return;
@@ -13054,8 +13298,7 @@ static void __devinit tg3_read_dash_ver(struct tg3 *tp)
u32 apedata;
char *fwtype;
- if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) ||
- !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
+ if (!tg3_flag(tp, ENABLE_APE) || !tg3_flag(tp, ENABLE_ASF))
return;
apedata = tg3_ape_read32(tp, TG3_APE_SEG_SIG);
@@ -13069,7 +13312,7 @@ 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) {
- tp->tg3_flags3 |= TG3_FLG3_APE_HAS_NCSI;
+ tg3_flag_set(tp, APE_HAS_NCSI);
fwtype = "NCSI";
} else {
fwtype = "DASH";
@@ -13093,7 +13336,7 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp)
if (tp->fw_ver[0] != 0)
vpd_vers = true;
- if (tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) {
+ if (tg3_flag(tp, NO_NVRAM)) {
strcat(tp->fw_ver, "sb");
return;
}
@@ -13110,8 +13353,7 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp)
else
return;
- if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
- (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) || vpd_vers)
+ if (!tg3_flag(tp, ENABLE_ASF) || tg3_flag(tp, ENABLE_APE) || vpd_vers)
goto done;
tg3_read_mgmtfw_ver(tp);
@@ -13122,21 +13364,14 @@ done:
static struct pci_dev * __devinit tg3_find_peer(struct tg3 *);
-static inline void vlan_features_add(struct net_device *dev, unsigned long flags)
-{
- dev->vlan_features |= flags;
-}
-
static inline u32 tg3_rx_ret_ring_size(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_5719)
- return 4096;
- else if ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) &&
- !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
- return 1024;
+ if (tg3_flag(tp, LRG_PROD_RING_CAP))
+ return TG3_RX_RET_MAX_SIZE_5717;
+ else if (tg3_flag(tp, JUMBO_CAPABLE) && !tg3_flag(tp, 5780_CLASS))
+ return TG3_RX_RET_MAX_SIZE_5700;
else
- return 512;
+ return TG3_RX_RET_MAX_SIZE_5705;
}
static DEFINE_PCI_DEVICE_TABLE(tg3_write_reorder_chipsets) = {
@@ -13181,7 +13416,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_5719)
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_5719 ||
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_5720)
pci_read_config_dword(tp->pdev,
TG3PCI_GEN2_PRODID_ASICREV,
&prod_id_asic_rev);
@@ -13258,15 +13494,14 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (bridge->subordinate &&
(bridge->subordinate->number ==
tp->pdev->bus->number)) {
-
- tp->tg3_flags2 |= TG3_FLG2_ICH_WORKAROUND;
+ tg3_flag_set(tp, ICH_WORKAROUND);
pci_dev_put(bridge);
break;
}
}
}
- if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) {
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) {
static struct tg3_dev_id {
u32 vendor;
u32 device;
@@ -13291,7 +13526,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->pdev->bus->number) &&
(bridge->subordinate->subordinate >=
tp->pdev->bus->number)) {
- tp->tg3_flags3 |= TG3_FLG3_5701_DMA_BUG;
+ tg3_flag_set(tp, 5701_DMA_BUG);
pci_dev_put(bridge);
break;
}
@@ -13306,8 +13541,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
*/
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) {
- tp->tg3_flags2 |= TG3_FLG2_5780_CLASS;
- tp->tg3_flags |= TG3_FLAG_40BIT_DMA_BUG;
+ tg3_flag_set(tp, 5780_CLASS);
+ tg3_flag_set(tp, 40BIT_DMA_BUG);
tp->msi_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_MSI);
} else {
struct pci_dev *bridge = NULL;
@@ -13321,7 +13556,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->pdev->bus->number) &&
(bridge->subordinate->subordinate >=
tp->pdev->bus->number)) {
- tp->tg3_flags |= TG3_FLAG_40BIT_DMA_BUG;
+ tg3_flag_set(tp, 40BIT_DMA_BUG);
pci_dev_put(bridge);
break;
}
@@ -13336,13 +13571,18 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
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;
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+ tg3_flag_set(tp, 5717_PLUS);
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 ||
+ tg3_flag(tp, 5717_PLUS))
+ tg3_flag_set(tp, 57765_PLUS);
/* Intentionally exclude ASIC_REV_5906 */
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
@@ -13351,97 +13591,102 @@ 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 ||
- (tp->tg3_flags3 & TG3_FLG3_5717_PLUS))
- tp->tg3_flags3 |= TG3_FLG3_5755_PLUS;
+ tg3_flag(tp, 57765_PLUS))
+ tg3_flag_set(tp, 5755_PLUS);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 ||
- (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) ||
- (tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
- tp->tg3_flags2 |= TG3_FLG2_5750_PLUS;
-
- if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) ||
- (tp->tg3_flags2 & TG3_FLG2_5750_PLUS))
- tp->tg3_flags2 |= TG3_FLG2_5705_PLUS;
-
- /* 5700 B0 chips do not support checksumming correctly due
- * to hardware bugs.
- */
- 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;
+ tg3_flag(tp, 5755_PLUS) ||
+ tg3_flag(tp, 5780_CLASS))
+ tg3_flag_set(tp, 5750_PLUS);
- tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
- if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)
- features |= NETIF_F_IPV6_CSUM;
- tp->dev->features |= features;
- vlan_features_add(tp->dev, features);
- }
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
+ tg3_flag(tp, 5750_PLUS))
+ tg3_flag_set(tp, 5705_PLUS);
/* Determine TSO capabilities */
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
; /* Do nothing. HW bug. */
- else 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) ||
+ else if (tg3_flag(tp, 57765_PLUS))
+ tg3_flag_set(tp, HW_TSO_3);
+ else if (tg3_flag(tp, 5755_PLUS) ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
- tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2;
- else if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) {
- tp->tg3_flags2 |= TG3_FLG2_HW_TSO_1 | TG3_FLG2_TSO_BUG;
+ tg3_flag_set(tp, HW_TSO_2);
+ else if (tg3_flag(tp, 5750_PLUS)) {
+ tg3_flag_set(tp, HW_TSO_1);
+ tg3_flag_set(tp, TSO_BUG);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 &&
tp->pci_chip_rev_id >= CHIPREV_ID_5750_C2)
- tp->tg3_flags2 &= ~TG3_FLG2_TSO_BUG;
+ tg3_flag_clear(tp, TSO_BUG);
} else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701 &&
tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) {
- tp->tg3_flags2 |= TG3_FLG2_TSO_BUG;
+ tg3_flag_set(tp, TSO_BUG);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)
tp->fw_needed = FIRMWARE_TG3TSO5;
else
tp->fw_needed = FIRMWARE_TG3TSO;
}
+ /* Selectively allow TSO based on operating conditions */
+ if (tg3_flag(tp, HW_TSO_1) ||
+ tg3_flag(tp, HW_TSO_2) ||
+ tg3_flag(tp, HW_TSO_3) ||
+ (tp->fw_needed && !tg3_flag(tp, ENABLE_ASF)))
+ tg3_flag_set(tp, TSO_CAPABLE);
+ else {
+ tg3_flag_clear(tp, TSO_CAPABLE);
+ tg3_flag_clear(tp, TSO_BUG);
+ tp->fw_needed = NULL;
+ }
+
+ if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0)
+ tp->fw_needed = FIRMWARE_TG3;
+
tp->irq_max = 1;
- if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) {
- tp->tg3_flags |= TG3_FLAG_SUPPORT_MSI;
+ if (tg3_flag(tp, 5750_PLUS)) {
+ tg3_flag_set(tp, SUPPORT_MSI);
if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX ||
GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_BX ||
(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714 &&
tp->pci_chip_rev_id <= CHIPREV_ID_5714_A2 &&
tp->pdev_peer == tp->pdev))
- tp->tg3_flags &= ~TG3_FLAG_SUPPORT_MSI;
+ tg3_flag_clear(tp, SUPPORT_MSI);
- if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) ||
+ if (tg3_flag(tp, 5755_PLUS) ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
- tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI;
+ tg3_flag_set(tp, 1SHOT_MSI);
}
- if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) {
- tp->tg3_flags |= TG3_FLAG_SUPPORT_MSIX;
+ if (tg3_flag(tp, 57765_PLUS)) {
+ tg3_flag_set(tp, 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)) {
- tp->tg3_flags3 |= TG3_FLG3_4G_DMA_BNDRY_BUG;
- tp->tg3_flags3 |= TG3_FLG3_40BIT_DMA_LIMIT_BUG;
- }
+ /* All chips can get confused if TX buffers
+ * straddle the 4GB address boundary.
+ */
+ tg3_flag_set(tp, 4G_DMA_BNDRY_BUG);
+
+ if (tg3_flag(tp, 5755_PLUS))
+ tg3_flag_set(tp, SHORT_DMA_BUG);
+ else
+ tg3_flag_set(tp, 40BIT_DMA_LIMIT_BUG);
- if ((tp->tg3_flags3 & TG3_FLG3_5717_PLUS) &&
+ if (tg3_flag(tp, 5717_PLUS))
+ tg3_flag_set(tp, LRG_PROD_RING_CAP);
+
+ if (tg3_flag(tp, 57765_PLUS) &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719)
- tp->tg3_flags3 |= TG3_FLG3_USE_JUMBO_BDFLAG;
+ tg3_flag_set(tp, USE_JUMBO_BDFLAG);
- if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
- (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) ||
- (tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG))
- tp->tg3_flags |= TG3_FLAG_JUMBO_CAPABLE;
+ if (!tg3_flag(tp, 5705_PLUS) ||
+ tg3_flag(tp, 5780_CLASS) ||
+ tg3_flag(tp, USE_JUMBO_BDFLAG))
+ tg3_flag_set(tp, JUMBO_CAPABLE);
pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE,
&pci_state_reg);
@@ -13450,10 +13695,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (tp->pcie_cap != 0) {
u16 lnkctl;
- tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS;
+ tg3_flag_set(tp, PCI_EXPRESS);
tp->pcie_readrq = 4096;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
tp->pcie_readrq = 2048;
pcie_set_readrq(tp->pdev, tp->pcie_readrq);
@@ -13462,20 +13708,23 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->pcie_cap + PCI_EXP_LNKCTL,
&lnkctl);
if (lnkctl & PCI_EXP_LNKCTL_CLKREQ_EN) {
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
- tp->tg3_flags2 &= ~TG3_FLG2_HW_TSO_2;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) ==
+ ASIC_REV_5906) {
+ tg3_flag_clear(tp, HW_TSO_2);
+ tg3_flag_clear(tp, TSO_CAPABLE);
+ }
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 ||
tp->pci_chip_rev_id == CHIPREV_ID_57780_A0 ||
tp->pci_chip_rev_id == CHIPREV_ID_57780_A1)
- tp->tg3_flags3 |= TG3_FLG3_CLKREQ_BUG;
+ tg3_flag_set(tp, CLKREQ_BUG);
} else if (tp->pci_chip_rev_id == CHIPREV_ID_5717_A0) {
- tp->tg3_flags3 |= TG3_FLG3_L1PLLPD_EN;
+ tg3_flag_set(tp, L1PLLPD_EN);
}
} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) {
- tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS;
- } else if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
- (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
+ tg3_flag_set(tp, PCI_EXPRESS);
+ } else if (!tg3_flag(tp, 5705_PLUS) ||
+ tg3_flag(tp, 5780_CLASS)) {
tp->pcix_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_PCIX);
if (!tp->pcix_cap) {
dev_err(&tp->pdev->dev,
@@ -13484,7 +13733,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
}
if (!(pci_state_reg & PCISTATE_CONV_PCI_MODE))
- tp->tg3_flags |= TG3_FLAG_PCIX_MODE;
+ tg3_flag_set(tp, PCIX_MODE);
}
/* If we have an AMD 762 or VIA K8T800 chipset, write
@@ -13494,8 +13743,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
* posted to the chip in order.
*/
if (pci_dev_present(tg3_write_reorder_chipsets) &&
- !(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS))
- tp->tg3_flags |= TG3_FLAG_MBOX_WRITE_REORDER;
+ !tg3_flag(tp, PCI_EXPRESS))
+ tg3_flag_set(tp, MBOX_WRITE_REORDER);
pci_read_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE,
&tp->pci_cacheline_sz);
@@ -13512,17 +13761,17 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
/* 5700 BX chips need to have their TX producer index
* mailboxes written twice to workaround a bug.
*/
- tp->tg3_flags |= TG3_FLAG_TXD_MBOX_HWBUG;
+ tg3_flag_set(tp, TXD_MBOX_HWBUG);
/* If we are in PCI-X mode, enable register write workaround.
*
* The workaround is to use indirect register accesses
* for all chip writes not to mailbox registers.
*/
- if (tp->tg3_flags & TG3_FLAG_PCIX_MODE) {
+ if (tg3_flag(tp, PCIX_MODE)) {
u32 pm_reg;
- tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG;
+ tg3_flag_set(tp, PCIX_TARGET_HWBUG);
/* The chip can have it's power management PCI config
* space registers clobbered due to this bug.
@@ -13545,9 +13794,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
}
if ((pci_state_reg & PCISTATE_BUS_SPEED_HIGH) != 0)
- tp->tg3_flags |= TG3_FLAG_PCI_HIGH_SPEED;
+ tg3_flag_set(tp, PCI_HIGH_SPEED);
if ((pci_state_reg & PCISTATE_BUS_32BIT) != 0)
- tp->tg3_flags |= TG3_FLAG_PCI_32BIT;
+ tg3_flag_set(tp, PCI_32BIT);
/* Chip-specific fixup from Broadcom driver */
if ((tp->pci_chip_rev_id == CHIPREV_ID_5704_A0) &&
@@ -13565,10 +13814,10 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->write32_rx_mbox = tg3_write32;
/* Various workaround register access methods */
- if (tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG)
+ if (tg3_flag(tp, PCIX_TARGET_HWBUG))
tp->write32 = tg3_write_indirect_reg32;
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 ||
- ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) &&
+ (tg3_flag(tp, PCI_EXPRESS) &&
tp->pci_chip_rev_id == CHIPREV_ID_5750_A0)) {
/*
* Back to back register writes can cause problems on these
@@ -13580,14 +13829,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->write32 = tg3_write_flush_reg32;
}
- if ((tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) ||
- (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)) {
+ if (tg3_flag(tp, TXD_MBOX_HWBUG) || tg3_flag(tp, MBOX_WRITE_REORDER)) {
tp->write32_tx_mbox = tg3_write32_tx_mbox;
- if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
+ if (tg3_flag(tp, MBOX_WRITE_REORDER))
tp->write32_rx_mbox = tg3_write_flush_reg32;
}
- if (tp->tg3_flags2 & TG3_FLG2_ICH_WORKAROUND) {
+ if (tg3_flag(tp, ICH_WORKAROUND)) {
tp->read32 = tg3_read_indirect_reg32;
tp->write32 = tg3_write_indirect_reg32;
tp->read32_mbox = tg3_read_indirect_mbox;
@@ -13610,13 +13858,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
}
if (tp->write32 == tg3_write_indirect_reg32 ||
- ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) &&
+ (tg3_flag(tp, PCIX_MODE) &&
(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)))
- tp->tg3_flags |= TG3_FLAG_SRAM_USE_CONFIG;
+ tg3_flag_set(tp, SRAM_USE_CONFIG);
/* Get eeprom hw config before calling tg3_set_power_state().
- * In particular, the TG3_FLG2_IS_NIC flag must be
+ * In particular, the TG3_FLAG_IS_NIC flag must be
* determined before calling tg3_set_power_state() so that
* we know whether or not to switch out of Vaux power.
* When the flag is set, it means that GPIO1 is used for eeprom
@@ -13625,7 +13873,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
*/
tg3_get_eeprom_hw_cfg(tp);
- if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
+ if (tg3_flag(tp, ENABLE_APE)) {
/* Allow reads and writes to the
* APE register and memory space.
*/
@@ -13640,16 +13888,16 @@ 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 ||
- (tp->tg3_flags3 & TG3_FLG3_5717_PLUS))
- tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT;
+ tg3_flag(tp, 57765_PLUS))
+ tg3_flag_set(tp, CPMU_PRESENT);
- /* Set up tp->grc_local_ctrl before calling tg_power_up().
+ /* Set up tp->grc_local_ctrl before calling tg3_power_up().
* GPIO1 driven high will bring 5700's external PHY out of reset.
* It is also used as eeprom write protect on LOMs.
*/
tp->grc_local_ctrl = GRC_LCLCTRL_INT_ON_ATTN | GRC_LCLCTRL_AUTO_SEEPROM;
- if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) ||
- (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT))
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+ tg3_flag(tp, EEPROM_WRITE_PROT))
tp->grc_local_ctrl |= (GRC_LCLCTRL_GPIO_OE1 |
GRC_LCLCTRL_GPIO_OUTPUT1);
/* Unused GPIO3 must be driven as output on 5752 because there
@@ -13667,7 +13915,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->pdev->device == TG3PCI_DEVICE_TIGON3_5761S) {
/* Turn off the debug UART. */
tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL;
- if (tp->tg3_flags2 & TG3_FLG2_IS_NIC)
+ if (tg3_flag(tp, IS_NIC))
/* Keep VMain power. */
tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE0 |
GRC_LCLCTRL_GPIO_OUTPUT0;
@@ -13683,26 +13931,25 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
/* Derive initial jumbo mode from MTU assigned in
* ether_setup() via the alloc_etherdev() call
*/
- if (tp->dev->mtu > ETH_DATA_LEN &&
- !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
- tp->tg3_flags |= TG3_FLAG_JUMBO_RING_ENABLE;
+ if (tp->dev->mtu > ETH_DATA_LEN && !tg3_flag(tp, 5780_CLASS))
+ tg3_flag_set(tp, JUMBO_RING_ENABLE);
/* Determine WakeOnLan speed to use. */
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 ||
tp->pci_chip_rev_id == CHIPREV_ID_5701_B0 ||
tp->pci_chip_rev_id == CHIPREV_ID_5701_B2) {
- tp->tg3_flags &= ~(TG3_FLAG_WOL_SPEED_100MB);
+ tg3_flag_clear(tp, WOL_SPEED_100MB);
} else {
- tp->tg3_flags |= TG3_FLAG_WOL_SPEED_100MB;
+ tg3_flag_set(tp, WOL_SPEED_100MB);
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
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) &&
+ 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->phy_flags & TG3_PHYFLG_IS_FET) ||
@@ -13715,11 +13962,11 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0)
tp->phy_flags |= TG3_PHYFLG_5704_A0_BUG;
- if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) &&
+ if (tg3_flag(tp, 5705_PLUS) &&
!(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 &&
- !(tp->tg3_flags3 & TG3_FLG3_5717_PLUS)) {
+ !tg3_flag(tp, 57765_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 ||
@@ -13740,7 +13987,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->phy_otp = TG3_OTP_DEFAULT;
}
- if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT)
+ if (tg3_flag(tp, CPMU_PRESENT))
tp->mi_mode = MAC_MI_MODE_500KHZ_CONST;
else
tp->mi_mode = MAC_MI_MODE_BASE;
@@ -13750,9 +13997,17 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX)
tp->coalesce_mode |= HOSTCC_MODE_32BYTE;
+ /* Set these bits to enable statistics workaround. */
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ tp->pci_chip_rev_id == CHIPREV_ID_5719_A0 ||
+ tp->pci_chip_rev_id == CHIPREV_ID_5720_A0) {
+ tp->coalesce_mode |= HOSTCC_MODE_ATTN;
+ tp->grc_mode |= GRC_MODE_IRQ_ON_FLOW_ATTN;
+ }
+
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
- tp->tg3_flags3 |= TG3_FLG3_USE_PHYLIB;
+ tg3_flag_set(tp, USE_PHYLIB);
err = tg3_mdio_init(tp);
if (err)
@@ -13760,7 +14015,15 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
/* Initialize data/descriptor byte/word swapping. */
val = tr32(GRC_MODE);
- val &= GRC_MODE_HOST_STACKUP;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720)
+ val &= (GRC_MODE_BYTE_SWAP_B2HRX_DATA |
+ GRC_MODE_WORD_SWAP_B2HRX_DATA |
+ GRC_MODE_B2HRX_ENABLE |
+ GRC_MODE_HTX2B_ENABLE |
+ GRC_MODE_HOST_STACKUP);
+ else
+ val &= GRC_MODE_HOST_STACKUP;
+
tw32(GRC_MODE, val | tp->grc_mode);
tg3_switch_clocks(tp);
@@ -13771,7 +14034,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE,
&pci_state_reg);
if ((pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0 &&
- (tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) == 0) {
+ !tg3_flag(tp, PCIX_TARGET_HWBUG)) {
u32 chiprevid = GET_CHIP_REV_ID(tp->misc_host_ctrl);
if (chiprevid == CHIPREV_ID_5701_A0 ||
@@ -13790,7 +14053,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
writel(0x00000000, sram_base + 4);
writel(0xffffffff, sram_base + 4);
if (readl(sram_base) != 0x00000000)
- tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG;
+ tg3_flag_set(tp, PCIX_TARGET_HWBUG);
}
}
@@ -13803,12 +14066,12 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
(grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788 ||
grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788M))
- tp->tg3_flags2 |= TG3_FLG2_IS_5788;
+ tg3_flag_set(tp, IS_5788);
- if (!(tp->tg3_flags2 & TG3_FLG2_IS_5788) &&
- (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700))
- tp->tg3_flags |= TG3_FLAG_TAGGED_STATUS;
- if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) {
+ if (!tg3_flag(tp, IS_5788) &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700)
+ tg3_flag_set(tp, TAGGED_STATUS);
+ if (tg3_flag(tp, TAGGED_STATUS)) {
tp->coalesce_mode |= (HOSTCC_MODE_CLRTICK_RXBD |
HOSTCC_MODE_CLRTICK_TXBD);
@@ -13818,7 +14081,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
}
/* Preserve the APE MAC_MODE bits */
- if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
+ if (tg3_flag(tp, ENABLE_APE))
tp->mac_mode = MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN;
else
tp->mac_mode = TG3_DEF_MAC_MODE;
@@ -13865,9 +14128,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
* status register in those cases.
*/
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700)
- tp->tg3_flags |= TG3_FLAG_USE_LINKCHG_REG;
+ tg3_flag_set(tp, USE_LINKCHG_REG);
else
- tp->tg3_flags &= ~TG3_FLAG_USE_LINKCHG_REG;
+ tg3_flag_clear(tp, USE_LINKCHG_REG);
/* The led_ctrl is set during tg3_phy_probe, here we might
* have to force the link status polling mechanism based
@@ -13877,19 +14140,19 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES)) {
tp->phy_flags |= TG3_PHYFLG_USE_MI_INTERRUPT;
- tp->tg3_flags |= TG3_FLAG_USE_LINKCHG_REG;
+ tg3_flag_set(tp, USE_LINKCHG_REG);
}
/* For all SERDES we poll the MAC status register. */
if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES)
- tp->tg3_flags |= TG3_FLAG_POLL_SERDES;
+ tg3_flag_set(tp, POLL_SERDES);
else
- tp->tg3_flags &= ~TG3_FLAG_POLL_SERDES;
+ tg3_flag_clear(tp, POLL_SERDES);
tp->rx_offset = NET_IP_ALIGN;
tp->rx_copy_thresh = TG3_RX_COPY_THRESHOLD;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 &&
- (tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0) {
+ tg3_flag(tp, PCIX_MODE)) {
tp->rx_offset = 0;
#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
tp->rx_copy_thresh = ~(u16)0;
@@ -13910,7 +14173,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
tp->rx_std_max_post = 8;
- if (tp->tg3_flags & TG3_FLAG_ASPM_WORKAROUND)
+ if (tg3_flag(tp, ASPM_WORKAROUND))
tp->pwrmgmt_thresh = tr32(PCIE_PWR_MGMT_THRESH) &
PCIE_PWR_MGMT_L1_THRESH_MSK;
@@ -13957,16 +14220,15 @@ static int __devinit tg3_get_device_address(struct tg3 *tp)
#endif
mac_offset = 0x7c;
- if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) ||
- (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 ||
+ tg3_flag(tp, 5780_CLASS)) {
if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID)
mac_offset = 0xcc;
if (tg3_nvram_lock(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 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) {
+ } else if (tg3_flag(tp, 5717_PLUS)) {
if (PCI_FUNC(tp->pdev->devfn) & 1)
mac_offset = 0xcc;
if (PCI_FUNC(tp->pdev->devfn) > 1)
@@ -13991,7 +14253,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp)
}
if (!addr_ok) {
/* Next, try NVRAM. */
- if (!(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM) &&
+ if (!tg3_flag(tp, NO_NVRAM) &&
!tg3_nvram_read_be32(tp, mac_offset + 0, &hi) &&
!tg3_nvram_read_be32(tp, mac_offset + 4, &lo)) {
memcpy(&dev->dev_addr[0], ((char *)&hi) + 2, 2);
@@ -14042,7 +14304,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val)
*/
if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701 &&
- !(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS))
+ !tg3_flag(tp, PCI_EXPRESS))
goto out;
#if defined(CONFIG_PPC64) || defined(CONFIG_IA64) || defined(CONFIG_PARISC)
@@ -14055,7 +14317,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val)
#endif
#endif
- if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) {
+ if (tg3_flag(tp, 57765_PLUS)) {
val = goal ? 0 : DMA_RWCTRL_DIS_CACHE_ALIGNMENT;
goto out;
}
@@ -14074,8 +14336,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val)
* other than 5700 and 5701 which do not implement the
* boundary bits.
*/
- if ((tp->tg3_flags & TG3_FLAG_PCIX_MODE) &&
- !(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) {
+ if (tg3_flag(tp, PCIX_MODE) && !tg3_flag(tp, PCI_EXPRESS)) {
switch (cacheline_size) {
case 16:
case 32:
@@ -14100,7 +14361,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val)
DMA_RWCTRL_WRITE_BNDRY_384_PCIX);
break;
}
- } else if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
+ } else if (tg3_flag(tp, PCI_EXPRESS)) {
switch (cacheline_size) {
case 16:
case 32:
@@ -14272,13 +14533,13 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
tp->dma_rwctrl = tg3_calc_dma_bndry(tp, tp->dma_rwctrl);
- if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS)
+ if (tg3_flag(tp, 57765_PLUS))
goto out;
- if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
+ if (tg3_flag(tp, PCI_EXPRESS)) {
/* DMA read watermark not used on PCIE */
tp->dma_rwctrl |= 0x00180000;
- } else if (!(tp->tg3_flags & TG3_FLAG_PCIX_MODE)) {
+ } else if (!tg3_flag(tp, PCIX_MODE)) {
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
tp->dma_rwctrl |= 0x003f0000;
@@ -14294,7 +14555,7 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
* do the less restrictive ONE_DMA workaround for
* better performance.
*/
- if ((tp->tg3_flags & TG3_FLAG_40BIT_DMA_BUG) &&
+ if (tg3_flag(tp, 40BIT_DMA_BUG) &&
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704)
tp->dma_rwctrl |= 0x8000;
else if (ccval == 0x6 || ccval == 0x7)
@@ -14423,7 +14684,6 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
}
if ((tp->dma_rwctrl & DMA_RWCTRL_WRITE_BNDRY_MASK) !=
DMA_RWCTRL_WRITE_BNDRY_16) {
-
/* DMA test passed without adjusting DMA boundary,
* now look for chipsets that are known to expose the
* DMA bug without failing the test.
@@ -14447,7 +14707,7 @@ out_nofree:
static void __devinit tg3_init_bufmgr_config(struct tg3 *tp)
{
- if (tp->tg3_flags3 & TG3_FLG3_5717_PLUS) {
+ if (tg3_flag(tp, 57765_PLUS)) {
tp->bufmgr_config.mbuf_read_dma_low_water =
DEFAULT_MB_RDMA_LOW_WATER_5705;
tp->bufmgr_config.mbuf_mac_rx_low_water =
@@ -14461,7 +14721,7 @@ static void __devinit tg3_init_bufmgr_config(struct tg3 *tp)
DEFAULT_MB_MACRX_LOW_WATER_JUMBO_57765;
tp->bufmgr_config.mbuf_high_water_jumbo =
DEFAULT_MB_HIGH_WATER_JUMBO_57765;
- } else if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
+ } else if (tg3_flag(tp, 5705_PLUS)) {
tp->bufmgr_config.mbuf_read_dma_low_water =
DEFAULT_MB_RDMA_LOW_WATER_5705;
tp->bufmgr_config.mbuf_mac_rx_low_water =
@@ -14525,6 +14785,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp)
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_BCM5720C: return "5720C";
case TG3_PHY_ID_BCM8002: return "8002/serdes";
case 0: return "serdes";
default: return "unknown";
@@ -14533,10 +14794,10 @@ static char * __devinit tg3_phy_string(struct tg3 *tp)
static char * __devinit tg3_bus_string(struct tg3 *tp, char *str)
{
- if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
+ if (tg3_flag(tp, PCI_EXPRESS)) {
strcpy(str, "PCI Express");
return str;
- } else if (tp->tg3_flags & TG3_FLAG_PCIX_MODE) {
+ } else if (tg3_flag(tp, PCIX_MODE)) {
u32 clock_ctrl = tr32(TG3PCI_CLOCK_CTRL) & 0x1f;
strcpy(str, "PCIX:");
@@ -14555,12 +14816,12 @@ static char * __devinit tg3_bus_string(struct tg3 *tp, char *str)
strcat(str, "100MHz");
} else {
strcpy(str, "PCI:");
- if (tp->tg3_flags & TG3_FLAG_PCI_HIGH_SPEED)
+ if (tg3_flag(tp, PCI_HIGH_SPEED))
strcat(str, "66MHz");
else
strcat(str, "33MHz");
}
- if (tp->tg3_flags & TG3_FLAG_PCI_32BIT)
+ if (tg3_flag(tp, PCI_32BIT))
strcat(str, ":32-bit");
else
strcat(str, ":64-bit");
@@ -14619,7 +14880,7 @@ static void __devinit tg3_init_coal(struct tg3 *tp)
ec->tx_coalesce_usecs_irq = DEFAULT_TXCOAL_TICK_INT_CLRTCKS;
}
- if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
+ if (tg3_flag(tp, 5705_PLUS)) {
ec->rx_coalesce_usecs_irq = 0;
ec->tx_coalesce_usecs_irq = 0;
ec->stats_block_coalesce_usecs = 0;
@@ -14637,22 +14898,8 @@ static const struct net_device_ops tg3_netdev_ops = {
.ndo_do_ioctl = tg3_ioctl,
.ndo_tx_timeout = tg3_tx_timeout,
.ndo_change_mtu = tg3_change_mtu,
-#ifdef CONFIG_NET_POLL_CONTROLLER
- .ndo_poll_controller = tg3_poll_controller,
-#endif
-};
-
-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_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,
- .ndo_do_ioctl = tg3_ioctl,
- .ndo_tx_timeout = tg3_tx_timeout,
- .ndo_change_mtu = tg3_change_mtu,
+ .ndo_fix_features = tg3_fix_features,
+ .ndo_set_features = tg3_set_features,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = tg3_poll_controller,
#endif
@@ -14667,6 +14914,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
u32 sndmbx, rcvmbx, intmbx;
char str[40];
u64 dma_mask, persist_dma_mask;
+ u32 features = 0;
printk_once(KERN_INFO "%s\n", version);
@@ -14702,8 +14950,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
SET_NETDEV_DEV(dev, &pdev->dev);
- dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-
tp = netdev_priv(dev);
tp->pdev = pdev;
tp->dev = dev;
@@ -14753,6 +14999,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
dev->ethtool_ops = &tg3_ethtool_ops;
dev->watchdog_timeo = TG3_TX_TIMEOUT;
+ dev->netdev_ops = &tg3_netdev_ops;
dev->irq = pdev->irq;
err = tg3_get_invariants(tp);
@@ -14762,23 +15009,15 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
goto err_out_iounmap;
}
- if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
- 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;
-
-
/* The EPB bridge inside 5714, 5715, and 5780 and any
* device behind the EPB cannot support DMA addresses > 40-bit.
* On 64-bit systems with IOMMU, use 40-bit dma_mask.
* On 64-bit systems without IOMMU, use 64-bit dma_mask and
* do DMA address check in tg3_start_xmit().
*/
- if (tp->tg3_flags2 & TG3_FLG2_IS_5788)
+ if (tg3_flag(tp, IS_5788))
persist_dma_mask = dma_mask = DMA_BIT_MASK(32);
- else if (tp->tg3_flags & TG3_FLAG_40BIT_DMA_BUG) {
+ else if (tg3_flag(tp, 40BIT_DMA_BUG)) {
persist_dma_mask = dma_mask = DMA_BIT_MASK(40);
#ifdef CONFIG_HIGHMEM
dma_mask = DMA_BIT_MASK(64);
@@ -14790,7 +15029,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
if (dma_mask > DMA_BIT_MASK(32)) {
err = pci_set_dma_mask(pdev, dma_mask);
if (!err) {
- dev->features |= NETIF_F_HIGHDMA;
+ features |= NETIF_F_HIGHDMA;
err = pci_set_consistent_dma_mask(pdev,
persist_dma_mask);
if (err < 0) {
@@ -14811,48 +15050,58 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
tg3_init_bufmgr_config(tp);
- /* Selectively allow TSO based on operating conditions */
- if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO) ||
- (tp->fw_needed && !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)))
- tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE;
- else {
- tp->tg3_flags2 &= ~(TG3_FLG2_TSO_CAPABLE | TG3_FLG2_TSO_BUG);
- tp->fw_needed = NULL;
- }
+ features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
- if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0)
- tp->fw_needed = FIRMWARE_TG3;
+ /* 5700 B0 chips do not support checksumming correctly due
+ * to hardware bugs.
+ */
+ if (tp->pci_chip_rev_id != CHIPREV_ID_5700_B0) {
+ features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_RXCSUM;
+
+ if (tg3_flag(tp, 5755_PLUS))
+ features |= NETIF_F_IPV6_CSUM;
+ }
/* TSO is on by default on chips that support hardware TSO.
* Firmware TSO on older chips gives lower performance, so it
* 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_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) {
- dev->features |= NETIF_F_TSO6;
- vlan_features_add(dev, NETIF_F_TSO6);
- }
- if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) ||
+ if ((tg3_flag(tp, HW_TSO_1) ||
+ tg3_flag(tp, HW_TSO_2) ||
+ tg3_flag(tp, HW_TSO_3)) &&
+ (features & NETIF_F_IP_CSUM))
+ features |= NETIF_F_TSO;
+ if (tg3_flag(tp, HW_TSO_2) || tg3_flag(tp, HW_TSO_3)) {
+ if (features & NETIF_F_IPV6_CSUM)
+ features |= NETIF_F_TSO6;
+ if (tg3_flag(tp, 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) {
- dev->features |= NETIF_F_TSO_ECN;
- vlan_features_add(dev, NETIF_F_TSO_ECN);
- }
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780)
+ features |= NETIF_F_TSO_ECN;
}
+ dev->features |= features;
+ dev->vlan_features |= features;
+
+ /*
+ * Add loopback capability only for a subset of devices that support
+ * MAC-LOOPBACK. Eventually this need to be enhanced to allow INT-PHY
+ * loopback for the remaining devices.
+ */
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5780 &&
+ !tg3_flag(tp, CPMU_PRESENT))
+ /* Add the loopback capability */
+ features |= NETIF_F_LOOPBACK;
+
+ dev->hw_features |= features;
+
if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 &&
- !(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) &&
+ !tg3_flag(tp, TSO_CAPABLE) &&
!(tr32(TG3PCI_PCISTATE) & PCISTATE_BUS_SPEED_HIGH)) {
- tp->tg3_flags2 |= TG3_FLG2_MAX_RXPEND_64;
+ tg3_flag_set(tp, MAX_RXPEND_64);
tp->rx_pending = 63;
}
@@ -14863,7 +15112,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
goto err_out_iounmap;
}
- if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
+ if (tg3_flag(tp, ENABLE_APE)) {
tp->aperegs = pci_ioremap_bar(pdev, BAR_2);
if (!tp->aperegs) {
dev_err(&pdev->dev,
@@ -14874,7 +15123,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
tg3_ape_lock_init(tp);
- if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF)
+ if (tg3_flag(tp, ENABLE_ASF))
tg3_read_dash_ver(tp);
}
@@ -14918,7 +15167,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
else
tnapi->coal_now = HOSTCC_MODE_NOW;
- if (!(tp->tg3_flags & TG3_FLAG_SUPPORT_MSIX))
+ if (!tg3_flag(tp, SUPPORT_MSIX))
break;
/*
@@ -14972,21 +15221,25 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
ethtype = "10/100/1000Base-T";
netdev_info(dev, "attached PHY is %s (%s Ethernet) "
- "(WireSpeed[%d])\n", tg3_phy_string(tp), ethtype,
- (tp->phy_flags & TG3_PHYFLG_NO_ETH_WIRE_SPEED) == 0);
+ "(WireSpeed[%d], EEE[%d])\n",
+ tg3_phy_string(tp), ethtype,
+ (tp->phy_flags & TG3_PHYFLG_NO_ETH_WIRE_SPEED) == 0,
+ (tp->phy_flags & TG3_PHYFLG_EEE_CAP) != 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,
+ (dev->features & NETIF_F_RXCSUM) != 0,
+ tg3_flag(tp, USE_LINKCHG_REG) != 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);
+ tg3_flag(tp, ENABLE_ASF) != 0,
+ tg3_flag(tp, TSO_CAPABLE) != 0);
netdev_info(dev, "dma_rwctrl[%08x] dma_mask[%d-bit]\n",
tp->dma_rwctrl,
pdev->dma_mask == DMA_BIT_MASK(32) ? 32 :
((u64)pdev->dma_mask) == DMA_BIT_MASK(40) ? 40 : 64);
+ pci_save_state(pdev);
+
return 0;
err_out_apeunmap:
@@ -15025,7 +15278,7 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)
cancel_work_sync(&tp->reset_task);
- if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) {
+ if (!tg3_flag(tp, USE_PHYLIB)) {
tg3_phy_fini(tp);
tg3_mdio_fini(tp);
}
@@ -15071,7 +15324,7 @@ static int tg3_suspend(struct device *device)
tg3_full_lock(tp, 0);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
- tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
+ tg3_flag_clear(tp, INIT_COMPLETE);
tg3_full_unlock(tp);
err = tg3_power_down_prepare(tp);
@@ -15080,7 +15333,7 @@ static int tg3_suspend(struct device *device)
tg3_full_lock(tp, 0);
- tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
+ tg3_flag_set(tp, INIT_COMPLETE);
err2 = tg3_restart_hw(tp, 1);
if (err2)
goto out;
@@ -15115,7 +15368,7 @@ static int tg3_resume(struct device *device)
tg3_full_lock(tp, 0);
- tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
+ tg3_flag_set(tp, INIT_COMPLETE);
err = tg3_restart_hw(tp, 1);
if (err)
goto out;
@@ -15143,11 +15396,156 @@ static SIMPLE_DEV_PM_OPS(tg3_pm_ops, tg3_suspend, tg3_resume);
#endif /* CONFIG_PM_SLEEP */
+/**
+ * tg3_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci connection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev,
+ pci_channel_state_t state)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct tg3 *tp = netdev_priv(netdev);
+ pci_ers_result_t err = PCI_ERS_RESULT_NEED_RESET;
+
+ netdev_info(netdev, "PCI I/O error detected\n");
+
+ rtnl_lock();
+
+ if (!netif_running(netdev))
+ goto done;
+
+ tg3_phy_stop(tp);
+
+ tg3_netif_stop(tp);
+
+ del_timer_sync(&tp->timer);
+ tg3_flag_clear(tp, RESTART_TIMER);
+
+ /* Want to make sure that the reset task doesn't run */
+ cancel_work_sync(&tp->reset_task);
+ tg3_flag_clear(tp, TX_RECOVERY_PENDING);
+ tg3_flag_clear(tp, RESTART_TIMER);
+
+ netif_device_detach(netdev);
+
+ /* Clean up software state, even if MMIO is blocked */
+ tg3_full_lock(tp, 0);
+ tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
+ tg3_full_unlock(tp);
+
+done:
+ if (state == pci_channel_io_perm_failure)
+ err = PCI_ERS_RESULT_DISCONNECT;
+ else
+ pci_disable_device(pdev);
+
+ rtnl_unlock();
+
+ return err;
+}
+
+/**
+ * tg3_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot.
+ * At this point, the card has exprienced a hard reset,
+ * followed by fixups by BIOS, and has its config space
+ * set up identically to what it was at cold boot.
+ */
+static pci_ers_result_t tg3_io_slot_reset(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct tg3 *tp = netdev_priv(netdev);
+ pci_ers_result_t rc = PCI_ERS_RESULT_DISCONNECT;
+ int err;
+
+ rtnl_lock();
+
+ if (pci_enable_device(pdev)) {
+ netdev_err(netdev, "Cannot re-enable PCI device after reset.\n");
+ goto done;
+ }
+
+ pci_set_master(pdev);
+ pci_restore_state(pdev);
+ pci_save_state(pdev);
+
+ if (!netif_running(netdev)) {
+ rc = PCI_ERS_RESULT_RECOVERED;
+ goto done;
+ }
+
+ err = tg3_power_up(tp);
+ if (err) {
+ netdev_err(netdev, "Failed to restore register access.\n");
+ goto done;
+ }
+
+ rc = PCI_ERS_RESULT_RECOVERED;
+
+done:
+ rtnl_unlock();
+
+ return rc;
+}
+
+/**
+ * tg3_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells
+ * us that its OK to resume normal operation.
+ */
+static void tg3_io_resume(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct tg3 *tp = netdev_priv(netdev);
+ int err;
+
+ rtnl_lock();
+
+ if (!netif_running(netdev))
+ goto done;
+
+ tg3_full_lock(tp, 0);
+ tg3_flag_set(tp, INIT_COMPLETE);
+ err = tg3_restart_hw(tp, 1);
+ tg3_full_unlock(tp);
+ if (err) {
+ netdev_err(netdev, "Cannot restart hardware after reset.\n");
+ goto done;
+ }
+
+ netif_device_attach(netdev);
+
+ tp->timer.expires = jiffies + tp->timer_offset;
+ add_timer(&tp->timer);
+
+ tg3_netif_start(tp);
+
+ tg3_phy_start(tp);
+
+done:
+ rtnl_unlock();
+}
+
+static struct pci_error_handlers tg3_err_handler = {
+ .error_detected = tg3_io_error_detected,
+ .slot_reset = tg3_io_slot_reset,
+ .resume = tg3_io_resume
+};
+
static struct pci_driver tg3_driver = {
.name = DRV_MODULE_NAME,
.id_table = tg3_pci_tbl,
.probe = tg3_init_one,
.remove = __devexit_p(tg3_remove_one),
+ .err_handler = &tg3_err_handler,
.driver.pm = TG3_PM_OPS,
};
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 5e96706ad108..5b3d2f34da7a 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -23,11 +23,13 @@
#define TG3_BDINFO_NIC_ADDR 0xcUL /* 32-bit */
#define TG3_BDINFO_SIZE 0x10UL
-#define TG3_RX_INTERNAL_RING_SZ_5906 32
-
-#define RX_STD_MAX_SIZE_5705 512
-#define RX_STD_MAX_SIZE_5717 2048
-#define RX_JUMBO_MAX_SIZE 0xdeadbeef /* XXX */
+#define TG3_RX_STD_MAX_SIZE_5700 512
+#define TG3_RX_STD_MAX_SIZE_5717 2048
+#define TG3_RX_JMB_MAX_SIZE_5700 256
+#define TG3_RX_JMB_MAX_SIZE_5717 1024
+#define TG3_RX_RET_MAX_SIZE_5700 1024
+#define TG3_RX_RET_MAX_SIZE_5705 512
+#define TG3_RX_RET_MAX_SIZE_5717 4096
/* First 256 bytes are a mirror of PCI config space. */
#define TG3PCI_VENDOR 0x00000000
@@ -54,6 +56,7 @@
#define TG3PCI_DEVICE_TIGON3_57791 0x16b2
#define TG3PCI_DEVICE_TIGON3_57795 0x16b6
#define TG3PCI_DEVICE_TIGON3_5719 0x1657
+#define TG3PCI_DEVICE_TIGON3_5720 0x165f
/* 0x04 --> 0x2c unused */
#define TG3PCI_SUBVENDOR_ID_BROADCOM PCI_VENDOR_ID_BROADCOM
#define TG3PCI_SUBDEVICE_ID_BROADCOM_95700A6 0x1644
@@ -142,6 +145,7 @@
#define CHIPREV_ID_5717_A0 0x05717000
#define CHIPREV_ID_57765_A0 0x57785000
#define CHIPREV_ID_5719_A0 0x05719000
+#define CHIPREV_ID_5720_A0 0x05720000
#define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12)
#define ASIC_REV_5700 0x07
#define ASIC_REV_5701 0x00
@@ -163,6 +167,7 @@
#define ASIC_REV_5717 0x5717
#define ASIC_REV_57765 0x57785
#define ASIC_REV_5719 0x5719
+#define ASIC_REV_5720 0x5720
#define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8)
#define CHIPREV_5700_AX 0x70
#define CHIPREV_5700_BX 0x71
@@ -175,6 +180,7 @@
#define CHIPREV_5750_BX 0x41
#define CHIPREV_5784_AX 0x57840
#define CHIPREV_5761_AX 0x57610
+#define CHIPREV_57765_AX 0x577650
#define GET_METAL_REV(CHIP_REV_ID) ((CHIP_REV_ID) & 0xff)
#define METAL_REV_A0 0x00
#define METAL_REV_A1 0x01
@@ -183,6 +189,7 @@
#define METAL_REV_B2 0x02
#define TG3PCI_DMA_RW_CTRL 0x0000006c
#define DMA_RWCTRL_DIS_CACHE_ALIGNMENT 0x00000001
+#define DMA_RWCTRL_TAGGED_STAT_WA 0x00000080
#define DMA_RWCTRL_CRDRDR_RDMA_MRRS_MSK 0x00000380
#define DMA_RWCTRL_READ_BNDRY_MASK 0x00000700
#define DMA_RWCTRL_READ_BNDRY_DISAB 0x00000000
@@ -473,6 +480,8 @@
#define TX_MODE_BIG_BCKOFF_ENABLE 0x00000020
#define TX_MODE_LONG_PAUSE_ENABLE 0x00000040
#define TX_MODE_MBUF_LOCKUP_FIX 0x00000100
+#define TX_MODE_JMB_FRM_LEN 0x00400000
+#define TX_MODE_CNT_DN_MODE 0x00800000
#define MAC_TX_STATUS 0x00000460
#define TX_STATUS_XOFFED 0x00000001
#define TX_STATUS_SENT_XOFF 0x00000002
@@ -487,6 +496,8 @@
#define TX_LENGTHS_IPG_SHIFT 8
#define TX_LENGTHS_IPG_CRS_MASK 0x00003000
#define TX_LENGTHS_IPG_CRS_SHIFT 12
+#define TX_LENGTHS_JMB_FRM_LEN_MSK 0x00ff0000
+#define TX_LENGTHS_CNT_DWN_VAL_MSK 0xff000000
#define MAC_RX_MODE 0x00000468
#define RX_MODE_RESET 0x00000001
#define RX_MODE_ENABLE 0x00000002
@@ -1079,6 +1090,9 @@
#define CPMU_HST_ACC_MACCLK_6_25 0x00130000
/* 0x3620 --> 0x3630 unused */
+#define TG3_CPMU_CLCK_ORIDE 0x00003624
+#define CPMU_CLCK_ORIDE_MAC_ORIDE_EN 0x80000000
+
#define TG3_CPMU_CLCK_STAT 0x00003630
#define CPMU_CLCK_STAT_MAC_CLCK_MASK 0x001f0000
#define CPMU_CLCK_STAT_MAC_CLCK_62_5 0x00000000
@@ -1188,6 +1202,7 @@
#define HOSTCC_STATS_BLK_NIC_ADDR 0x00003c40
#define HOSTCC_STATUS_BLK_NIC_ADDR 0x00003c44
#define HOSTCC_FLOW_ATTN 0x00003c48
+#define HOSTCC_FLOW_ATTN_MBUF_LWM 0x00000040
/* 0x3c4c --> 0x3c50 unused */
#define HOSTCC_JUMBO_CON_IDX 0x00003c50
#define HOSTCC_STD_CON_IDX 0x00003c54
@@ -1321,6 +1336,7 @@
#define RDMAC_MODE_MULT_DMA_RD_DIS 0x01000000
#define RDMAC_MODE_IPV4_LSO_EN 0x08000000
#define RDMAC_MODE_IPV6_LSO_EN 0x10000000
+#define RDMAC_MODE_H2BNC_VLAN_DET 0x20000000
#define RDMAC_STATUS 0x00004804
#define RDMAC_STATUS_TGTABORT 0x00000004
#define RDMAC_STATUS_MSTABORT 0x00000008
@@ -1597,6 +1613,7 @@
#define MSGINT_MODE_ONE_SHOT_DISABLE 0x00000020
#define MSGINT_MODE_MULTIVEC_EN 0x00000080
#define MSGINT_STATUS 0x00006004
+#define MSGINT_STATUS_MSI_REQ 0x00000001
#define MSGINT_FIFO 0x00006008
/* 0x600c --> 0x6400 unused */
@@ -1613,6 +1630,8 @@
#define GRC_MODE_WSWAP_NONFRM_DATA 0x00000004
#define GRC_MODE_BSWAP_DATA 0x00000010
#define GRC_MODE_WSWAP_DATA 0x00000020
+#define GRC_MODE_BYTE_SWAP_B2HRX_DATA 0x00000040
+#define GRC_MODE_WORD_SWAP_B2HRX_DATA 0x00000080
#define GRC_MODE_SPLITHDR 0x00000100
#define GRC_MODE_NOFRM_CRACKING 0x00000200
#define GRC_MODE_INCL_CRC 0x00000400
@@ -1620,8 +1639,10 @@
#define GRC_MODE_NOIRQ_ON_SENDS 0x00002000
#define GRC_MODE_NOIRQ_ON_RCV 0x00004000
#define GRC_MODE_FORCE_PCI32BIT 0x00008000
+#define GRC_MODE_B2HRX_ENABLE 0x00008000
#define GRC_MODE_HOST_STACKUP 0x00010000
#define GRC_MODE_HOST_SENDBDS 0x00020000
+#define GRC_MODE_HTX2B_ENABLE 0x00040000
#define GRC_MODE_NO_TX_PHDR_CSUM 0x00100000
#define GRC_MODE_NVRAM_WR_ENABLE 0x00200000
#define GRC_MODE_PCIE_TL_SEL 0x00000000
@@ -1818,6 +1839,38 @@
#define FLASH_5717VENDOR_ATMEL_45USPT 0x03400000
#define FLASH_5717VENDOR_ST_25USPT 0x03400002
#define FLASH_5717VENDOR_ST_45USPT 0x03400001
+#define FLASH_5720_EEPROM_HD 0x00000001
+#define FLASH_5720_EEPROM_LD 0x00000003
+#define FLASH_5720VENDOR_M_ATMEL_DB011D 0x01000000
+#define FLASH_5720VENDOR_M_ATMEL_DB021D 0x01000002
+#define FLASH_5720VENDOR_M_ATMEL_DB041D 0x01000001
+#define FLASH_5720VENDOR_M_ATMEL_DB081D 0x01000003
+#define FLASH_5720VENDOR_M_ST_M25PE10 0x02000000
+#define FLASH_5720VENDOR_M_ST_M25PE20 0x02000002
+#define FLASH_5720VENDOR_M_ST_M25PE40 0x02000001
+#define FLASH_5720VENDOR_M_ST_M25PE80 0x02000003
+#define FLASH_5720VENDOR_M_ST_M45PE10 0x03000000
+#define FLASH_5720VENDOR_M_ST_M45PE20 0x03000002
+#define FLASH_5720VENDOR_M_ST_M45PE40 0x03000001
+#define FLASH_5720VENDOR_M_ST_M45PE80 0x03000003
+#define FLASH_5720VENDOR_A_ATMEL_DB011B 0x01800000
+#define FLASH_5720VENDOR_A_ATMEL_DB021B 0x01800002
+#define FLASH_5720VENDOR_A_ATMEL_DB041B 0x01800001
+#define FLASH_5720VENDOR_A_ATMEL_DB011D 0x01c00000
+#define FLASH_5720VENDOR_A_ATMEL_DB021D 0x01c00002
+#define FLASH_5720VENDOR_A_ATMEL_DB041D 0x01c00001
+#define FLASH_5720VENDOR_A_ATMEL_DB081D 0x01c00003
+#define FLASH_5720VENDOR_A_ST_M25PE10 0x02800000
+#define FLASH_5720VENDOR_A_ST_M25PE20 0x02800002
+#define FLASH_5720VENDOR_A_ST_M25PE40 0x02800001
+#define FLASH_5720VENDOR_A_ST_M25PE80 0x02800003
+#define FLASH_5720VENDOR_A_ST_M45PE10 0x02c00000
+#define FLASH_5720VENDOR_A_ST_M45PE20 0x02c00002
+#define FLASH_5720VENDOR_A_ST_M45PE40 0x02c00001
+#define FLASH_5720VENDOR_A_ST_M45PE80 0x02c00003
+#define FLASH_5720VENDOR_ATMEL_45USPT 0x03c00000
+#define FLASH_5720VENDOR_ST_25USPT 0x03c00002
+#define FLASH_5720VENDOR_ST_45USPT 0x03c00001
#define NVRAM_CFG1_5752PAGE_SIZE_MASK 0x70000000
#define FLASH_5752PAGE_SIZE_256 0x00000000
#define FLASH_5752PAGE_SIZE_512 0x10000000
@@ -1899,11 +1952,16 @@
/* Alternate PCIE definitions */
#define TG3_PCIE_TLDLPL_PORT 0x00007c00
+#define TG3_PCIE_DL_LO_FTSMAX 0x0000000c
+#define TG3_PCIE_DL_LO_FTSMAX_MSK 0x000000ff
+#define TG3_PCIE_DL_LO_FTSMAX_VAL 0x0000002c
#define TG3_PCIE_PL_LO_PHYCTL1 0x00000004
#define TG3_PCIE_PL_LO_PHYCTL1_L1PLLPD_EN 0x00001000
#define TG3_PCIE_PL_LO_PHYCTL5 0x00000014
#define TG3_PCIE_PL_LO_PHYCTL5_DIS_L2CLKREQ 0x80000000
+#define TG3_REG_BLK_SIZE 0x00008000
+
/* OTP bit definitions */
#define TG3_OTP_AGCTGT_MASK 0x000000e0
#define TG3_OTP_AGCTGT_SHIFT 1
@@ -1955,7 +2013,9 @@
#define TG3_NVM_DIR_END 0x78
#define TG3_NVM_DIRENT_SIZE 0xc
#define TG3_NVM_DIRTYPE_SHIFT 24
+#define TG3_NVM_DIRTYPE_LENMSK 0x003fffff
#define TG3_NVM_DIRTYPE_ASFINI 1
+#define TG3_NVM_DIRTYPE_EXTVPD 20
#define TG3_NVM_PTREV_BCVER 0x94
#define TG3_NVM_BCVER_MAJMSK 0x0000ff00
#define TG3_NVM_BCVER_MAJSFT 8
@@ -2079,6 +2139,13 @@
#define NIC_SRAM_MBUF_POOL_BASE5705 0x00010000
#define NIC_SRAM_MBUF_POOL_SIZE5705 0x0000e000
+#define TG3_SRAM_RX_STD_BDCACHE_SIZE_5700 128
+#define TG3_SRAM_RX_STD_BDCACHE_SIZE_5755 64
+#define TG3_SRAM_RX_STD_BDCACHE_SIZE_5906 32
+
+#define TG3_SRAM_RX_JMB_BDCACHE_SIZE_5700 64
+#define TG3_SRAM_RX_JMB_BDCACHE_SIZE_5717 16
+
/* Currently this is fixed. */
#define TG3_PHY_MII_ADDR 0x01
@@ -2119,7 +2186,7 @@
#define MII_TG3_DSP_TAP26_OPCSINPT 0x0004
#define MII_TG3_DSP_AADJ1CH0 0x001f
#define MII_TG3_DSP_CH34TP2 0x4022
-#define MII_TG3_DSP_CH34TP2_HIBW01 0x0010
+#define MII_TG3_DSP_CH34TP2_HIBW01 0x017b
#define MII_TG3_DSP_AADJ1CH3 0x601f
#define MII_TG3_DSP_AADJ1CH3_ADCCKADJ 0x0002
#define MII_TG3_DSP_EXP1_INT_STAT 0x0f01
@@ -2132,19 +2199,26 @@
#define MII_TG3_AUX_CTRL 0x18 /* auxiliary control register */
+#define MII_TG3_AUXCTL_SHDWSEL_AUXCTL 0x0000
+#define MII_TG3_AUXCTL_ACTL_TX_6DB 0x0400
+#define MII_TG3_AUXCTL_ACTL_SMDSP_ENA 0x0800
+#define MII_TG3_AUXCTL_ACTL_EXTPKTLEN 0x4000
+
+#define MII_TG3_AUXCTL_SHDWSEL_PWRCTL 0x0002
+#define MII_TG3_AUXCTL_PCTL_WOL_EN 0x0008
#define MII_TG3_AUXCTL_PCTL_100TX_LPWR 0x0010
#define MII_TG3_AUXCTL_PCTL_SPR_ISOLATE 0x0020
+#define MII_TG3_AUXCTL_PCTL_CL_AB_TXDAC 0x0040
#define MII_TG3_AUXCTL_PCTL_VREG_11V 0x0180
-#define MII_TG3_AUXCTL_SHDWSEL_PWRCTL 0x0002
-#define MII_TG3_AUXCTL_MISC_WREN 0x8000
-#define MII_TG3_AUXCTL_MISC_FORCE_AMDIX 0x0200
-#define MII_TG3_AUXCTL_MISC_RDSEL_MISC 0x7000
+#define MII_TG3_AUXCTL_SHDWSEL_MISCTEST 0x0004
+
#define MII_TG3_AUXCTL_SHDWSEL_MISC 0x0007
+#define MII_TG3_AUXCTL_MISC_WIRESPD_EN 0x0010
+#define MII_TG3_AUXCTL_MISC_FORCE_AMDIX 0x0200
+#define MII_TG3_AUXCTL_MISC_RDSEL_SHIFT 12
+#define MII_TG3_AUXCTL_MISC_WREN 0x8000
-#define MII_TG3_AUXCTL_ACTL_SMDSP_ENA 0x0800
-#define MII_TG3_AUXCTL_ACTL_TX_6DB 0x0400
-#define MII_TG3_AUXCTL_SHDWSEL_AUXCTL 0x0000
#define MII_TG3_AUX_STAT 0x19 /* auxiliary status register */
#define MII_TG3_AUX_STAT_LPASS 0x0004
@@ -2564,7 +2638,12 @@ struct tg3_hw_stats {
tg3_stat64_t nic_avoided_irqs;
tg3_stat64_t nic_tx_threshold_hit;
- u8 __reserved4[0xb00-0x9c0];
+ /* NOT a part of the hardware statistics block format.
+ * These stats are here as storage for tg3_periodic_fetch_stats().
+ */
+ tg3_stat64_t mbuf_lwm_thresh_hit;
+
+ u8 __reserved4[0xb00-0x9c8];
};
/* 'mapping' is superfluous as the chip does not write into
@@ -2696,6 +2775,8 @@ struct tg3_ethtool_stats {
u64 nic_irqs;
u64 nic_avoided_irqs;
u64 nic_tx_threshold_hit;
+
+ u64 mbuf_lwm_thresh_hit;
};
struct tg3_rx_prodring_set {
@@ -2745,6 +2826,86 @@ struct tg3_napi {
unsigned int irq_vec;
};
+enum TG3_FLAGS {
+ TG3_FLAG_TAGGED_STATUS = 0,
+ TG3_FLAG_TXD_MBOX_HWBUG,
+ TG3_FLAG_USE_LINKCHG_REG,
+ TG3_FLAG_ERROR_PROCESSED,
+ TG3_FLAG_ENABLE_ASF,
+ TG3_FLAG_ASPM_WORKAROUND,
+ TG3_FLAG_POLL_SERDES,
+ TG3_FLAG_MBOX_WRITE_REORDER,
+ TG3_FLAG_PCIX_TARGET_HWBUG,
+ TG3_FLAG_WOL_SPEED_100MB,
+ TG3_FLAG_WOL_ENABLE,
+ TG3_FLAG_EEPROM_WRITE_PROT,
+ TG3_FLAG_NVRAM,
+ TG3_FLAG_NVRAM_BUFFERED,
+ TG3_FLAG_SUPPORT_MSI,
+ TG3_FLAG_SUPPORT_MSIX,
+ TG3_FLAG_PCIX_MODE,
+ TG3_FLAG_PCI_HIGH_SPEED,
+ TG3_FLAG_PCI_32BIT,
+ TG3_FLAG_SRAM_USE_CONFIG,
+ TG3_FLAG_TX_RECOVERY_PENDING,
+ TG3_FLAG_WOL_CAP,
+ TG3_FLAG_JUMBO_RING_ENABLE,
+ TG3_FLAG_PAUSE_AUTONEG,
+ TG3_FLAG_CPMU_PRESENT,
+ TG3_FLAG_40BIT_DMA_BUG,
+ TG3_FLAG_BROKEN_CHECKSUMS,
+ TG3_FLAG_JUMBO_CAPABLE,
+ TG3_FLAG_CHIP_RESETTING,
+ TG3_FLAG_INIT_COMPLETE,
+ TG3_FLAG_RESTART_TIMER,
+ TG3_FLAG_TSO_BUG,
+ TG3_FLAG_IS_5788,
+ TG3_FLAG_MAX_RXPEND_64,
+ TG3_FLAG_TSO_CAPABLE,
+ TG3_FLAG_PCI_EXPRESS,
+ TG3_FLAG_ASF_NEW_HANDSHAKE,
+ TG3_FLAG_HW_AUTONEG,
+ TG3_FLAG_IS_NIC,
+ TG3_FLAG_FLASH,
+ TG3_FLAG_HW_TSO_1,
+ TG3_FLAG_5705_PLUS,
+ TG3_FLAG_5750_PLUS,
+ TG3_FLAG_HW_TSO_3,
+ TG3_FLAG_USING_MSI,
+ TG3_FLAG_USING_MSIX,
+ TG3_FLAG_ICH_WORKAROUND,
+ TG3_FLAG_5780_CLASS,
+ TG3_FLAG_HW_TSO_2,
+ TG3_FLAG_1SHOT_MSI,
+ TG3_FLAG_NO_FWARE_REPORTED,
+ TG3_FLAG_NO_NVRAM_ADDR_TRANS,
+ TG3_FLAG_ENABLE_APE,
+ TG3_FLAG_PROTECTED_NVRAM,
+ TG3_FLAG_5701_DMA_BUG,
+ TG3_FLAG_USE_PHYLIB,
+ TG3_FLAG_MDIOBUS_INITED,
+ TG3_FLAG_LRG_PROD_RING_CAP,
+ TG3_FLAG_RGMII_INBAND_DISABLE,
+ TG3_FLAG_RGMII_EXT_IBND_RX_EN,
+ TG3_FLAG_RGMII_EXT_IBND_TX_EN,
+ TG3_FLAG_CLKREQ_BUG,
+ TG3_FLAG_5755_PLUS,
+ TG3_FLAG_NO_NVRAM,
+ TG3_FLAG_ENABLE_RSS,
+ TG3_FLAG_ENABLE_TSS,
+ TG3_FLAG_4G_DMA_BNDRY_BUG,
+ TG3_FLAG_40BIT_DMA_LIMIT_BUG,
+ TG3_FLAG_SHORT_DMA_BUG,
+ TG3_FLAG_USE_JUMBO_BDFLAG,
+ TG3_FLAG_L1PLLPD_EN,
+ TG3_FLAG_57765_PLUS,
+ TG3_FLAG_APE_HAS_NCSI,
+ TG3_FLAG_5717_PLUS,
+
+ /* Add new flags before this comment and TG3_FLAG_NUMBER_OF_FLAGS */
+ TG3_FLAG_NUMBER_OF_FLAGS, /* Last entry in enum TG3_FLAGS */
+};
+
struct tg3 {
/* begin "general, frequently-used members" cacheline section */
@@ -2768,7 +2929,7 @@ struct tg3 {
/* SMP locking strategy:
*
* lock: Held during reset, PHY access, timer, and when
- * updating tg3_flags and tg3_flags2.
+ * updating tg3_flags.
*
* netif_tx_lock: Held during tg3_start_xmit. tg3_tx holds
* netif_tx_lock when it needs to call
@@ -2825,94 +2986,13 @@ struct tg3 {
struct tg3_ethtool_stats estats;
struct tg3_ethtool_stats estats_prev;
+ DECLARE_BITMAP(tg3_flags, TG3_FLAG_NUMBER_OF_FLAGS);
+
union {
unsigned long phy_crc_errors;
unsigned long last_event_jiffies;
};
- u32 tg3_flags;
-#define TG3_FLAG_TAGGED_STATUS 0x00000001
-#define TG3_FLAG_TXD_MBOX_HWBUG 0x00000002
-#define TG3_FLAG_RX_CHECKSUMS 0x00000004
-#define TG3_FLAG_USE_LINKCHG_REG 0x00000008
-#define TG3_FLAG_ENABLE_ASF 0x00000020
-#define TG3_FLAG_ASPM_WORKAROUND 0x00000040
-#define TG3_FLAG_POLL_SERDES 0x00000080
-#define TG3_FLAG_MBOX_WRITE_REORDER 0x00000100
-#define TG3_FLAG_PCIX_TARGET_HWBUG 0x00000200
-#define TG3_FLAG_WOL_SPEED_100MB 0x00000400
-#define TG3_FLAG_WOL_ENABLE 0x00000800
-#define TG3_FLAG_EEPROM_WRITE_PROT 0x00001000
-#define TG3_FLAG_NVRAM 0x00002000
-#define TG3_FLAG_NVRAM_BUFFERED 0x00004000
-#define TG3_FLAG_SUPPORT_MSI 0x00008000
-#define TG3_FLAG_SUPPORT_MSIX 0x00010000
-#define TG3_FLAG_SUPPORT_MSI_OR_MSIX (TG3_FLAG_SUPPORT_MSI | \
- TG3_FLAG_SUPPORT_MSIX)
-#define TG3_FLAG_PCIX_MODE 0x00020000
-#define TG3_FLAG_PCI_HIGH_SPEED 0x00040000
-#define TG3_FLAG_PCI_32BIT 0x00080000
-#define TG3_FLAG_SRAM_USE_CONFIG 0x00100000
-#define TG3_FLAG_TX_RECOVERY_PENDING 0x00200000
-#define TG3_FLAG_WOL_CAP 0x00400000
-#define TG3_FLAG_JUMBO_RING_ENABLE 0x00800000
-#define TG3_FLAG_PAUSE_AUTONEG 0x02000000
-#define TG3_FLAG_CPMU_PRESENT 0x04000000
-#define TG3_FLAG_40BIT_DMA_BUG 0x08000000
-#define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000
-#define TG3_FLAG_JUMBO_CAPABLE 0x20000000
-#define TG3_FLAG_CHIP_RESETTING 0x40000000
-#define TG3_FLAG_INIT_COMPLETE 0x80000000
- u32 tg3_flags2;
-#define TG3_FLG2_RESTART_TIMER 0x00000001
-#define TG3_FLG2_TSO_BUG 0x00000002
-#define TG3_FLG2_IS_5788 0x00000008
-#define TG3_FLG2_MAX_RXPEND_64 0x00000010
-#define TG3_FLG2_TSO_CAPABLE 0x00000020
-#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_FLASH 0x00008000
-#define TG3_FLG2_HW_TSO_1 0x00010000
-#define TG3_FLG2_5705_PLUS 0x00040000
-#define TG3_FLG2_5750_PLUS 0x00080000
-#define TG3_FLG2_HW_TSO_3 0x00100000
-#define TG3_FLG2_USING_MSI 0x00200000
-#define TG3_FLG2_USING_MSIX 0x00400000
-#define TG3_FLG2_USING_MSI_OR_MSIX (TG3_FLG2_USING_MSI | \
- TG3_FLG2_USING_MSIX)
-#define TG3_FLG2_ICH_WORKAROUND 0x02000000
-#define TG3_FLG2_5780_CLASS 0x04000000
-#define TG3_FLG2_HW_TSO_2 0x08000000
-#define TG3_FLG2_HW_TSO (TG3_FLG2_HW_TSO_1 | \
- TG3_FLG2_HW_TSO_2 | \
- TG3_FLG2_HW_TSO_3)
-#define TG3_FLG2_1SHOT_MSI 0x10000000
-#define TG3_FLG2_NO_FWARE_REPORTED 0x40000000
- u32 tg3_flags3;
-#define TG3_FLG3_NO_NVRAM_ADDR_TRANS 0x00000001
-#define TG3_FLG3_ENABLE_APE 0x00000002
-#define TG3_FLG3_PROTECTED_NVRAM 0x00000004
-#define TG3_FLG3_5701_DMA_BUG 0x00000008
-#define TG3_FLG3_USE_PHYLIB 0x00000010
-#define TG3_FLG3_MDIOBUS_INITED 0x00000020
-#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_5755_PLUS 0x00002000
-#define TG3_FLG3_NO_NVRAM 0x00004000
-#define TG3_FLG3_ENABLE_RSS 0x00020000
-#define TG3_FLG3_ENABLE_TSS 0x00040000
-#define TG3_FLG3_4G_DMA_BNDRY_BUG 0x00080000
-#define TG3_FLG3_40BIT_DMA_LIMIT_BUG 0x00100000
-#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
-#define TG3_FLG3_APE_HAS_NCSI 0x02000000
-
struct timer_list timer;
u16 timer_counter;
u16 timer_multiplier;
@@ -2983,6 +3063,7 @@ struct tg3 {
#define TG3_PHY_ID_BCM5718S 0xbc050ff0
#define TG3_PHY_ID_BCM57765 0x5c0d8a40
#define TG3_PHY_ID_BCM5719C 0x5c0d8a20
+#define TG3_PHY_ID_BCM5720C 0x5c0d8b60
#define TG3_PHY_ID_BCM5906 0xdc00ac40
#define TG3_PHY_ID_BCM8002 0x60010140
#define TG3_PHY_ID_INVALID 0xffffffff
@@ -3049,6 +3130,7 @@ struct tg3 {
int nvram_lock_cnt;
u32 nvram_size;
+#define TG3_NVRAM_SIZE_2KB 0x00000800
#define TG3_NVRAM_SIZE_64KB 0x00010000
#define TG3_NVRAM_SIZE_128KB 0x00020000
#define TG3_NVRAM_SIZE_256KB 0x00040000
@@ -3064,6 +3146,9 @@ struct tg3 {
#define JEDEC_SAIFUN 0x4f
#define JEDEC_SST 0xbf
+#define ATMEL_AT24C02_CHIP_SIZE TG3_NVRAM_SIZE_2KB
+#define ATMEL_AT24C02_PAGE_SIZE (8)
+
#define ATMEL_AT24C64_CHIP_SIZE TG3_NVRAM_SIZE_64KB
#define ATMEL_AT24C64_PAGE_SIZE (32)
diff --git a/drivers/net/tile/tilepro.c b/drivers/net/tile/tilepro.c
index 0825db6d883f..1e2af96fc29c 100644
--- a/drivers/net/tile/tilepro.c
+++ b/drivers/net/tile/tilepro.c
@@ -1658,11 +1658,9 @@ static int tile_net_stop(struct net_device *dev)
while (tile_net_lepp_free_comps(dev, true))
/* loop */;
- /* Wipe the EPP queue. */
+ /* Wipe the EPP queue, and wait till the stores hit the EPP. */
memset(priv->eq, 0, sizeof(lepp_queue_t));
-
- /* Evict the EPP queue. */
- finv_buffer(priv->eq, EQ_SIZE);
+ mb();
return 0;
}
@@ -1930,7 +1928,7 @@ static int tile_net_tx(struct sk_buff *skb, struct net_device *dev)
unsigned int len = skb->len;
unsigned char *data = skb->data;
- unsigned int csum_start = skb->csum_start - skb_headroom(skb);
+ unsigned int csum_start = skb_checksum_start_offset(skb);
lepp_frag_t frags[LEPP_MAX_FRAGS];
@@ -2398,7 +2396,7 @@ static void tile_net_cleanup(void)
struct net_device *dev = tile_net_devs[i];
struct tile_net_priv *priv = netdev_priv(dev);
unregister_netdev(dev);
- finv_buffer(priv->eq, EQ_SIZE);
+ finv_buffer_remote(priv->eq, EQ_SIZE, 0);
__free_pages(priv->eq_pages, EQ_ORDER);
free_netdev(dev);
}
diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c
index 2bedc0ace812..1313aa1315f0 100644
--- a/drivers/net/tokenring/madgemc.c
+++ b/drivers/net/tokenring/madgemc.c
@@ -727,7 +727,7 @@ static int __devexit madgemc_remove(struct device *device)
return 0;
}
-static short madgemc_adapter_ids[] __initdata = {
+static const short madgemc_adapter_ids[] __devinitconst = {
0x002d,
0x0000
};
diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
index 2684003b8ab6..e3855aeb13d4 100644
--- a/drivers/net/tokenring/olympic.c
+++ b/drivers/net/tokenring/olympic.c
@@ -86,6 +86,7 @@
#include <linux/timer.h>
#include <linux/in.h>
#include <linux/ioport.h>
+#include <linux/seq_file.h>
#include <linux/string.h>
#include <linux/proc_fs.h>
#include <linux/ptrace.h>
@@ -193,7 +194,7 @@ static void olympic_arb_cmd(struct net_device *dev);
static int olympic_change_mtu(struct net_device *dev, int mtu);
static void olympic_srb_bh(struct net_device *dev) ;
static void olympic_asb_bh(struct net_device *dev) ;
-static int olympic_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data) ;
+static const struct file_operations olympic_proc_ops;
static const struct net_device_ops olympic_netdev_ops = {
.ndo_open = olympic_open,
@@ -272,7 +273,7 @@ static int __devinit olympic_probe(struct pci_dev *pdev, const struct pci_device
char proc_name[20] ;
strcpy(proc_name,"olympic_") ;
strcat(proc_name,dev->name) ;
- create_proc_read_entry(proc_name,0,init_net.proc_net,olympic_proc_info,(void *)dev) ;
+ proc_create_data(proc_name, 0, init_net.proc_net, &olympic_proc_ops, dev);
printk("Olympic: Network Monitor information: /proc/%s\n",proc_name);
}
return 0 ;
@@ -1615,29 +1616,25 @@ static int olympic_change_mtu(struct net_device *dev, int mtu)
return 0 ;
}
-static int olympic_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
+static int olympic_proc_show(struct seq_file *m, void *v)
{
- struct net_device *dev = (struct net_device *)data ;
+ struct net_device *dev = m->private;
struct olympic_private *olympic_priv=netdev_priv(dev);
u8 __iomem *oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr) ;
u8 __iomem *opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr) ;
- int size = 0 ;
- int len=0;
- off_t begin=0;
- off_t pos=0;
u8 addr[6];
u8 addr2[6];
int i;
- size = sprintf(buffer,
+ seq_printf(m,
"IBM Pit/Pit-Phy/Olympic Chipset Token Ring Adapter %s\n",dev->name);
- size += sprintf(buffer+size, "\n%6s: Adapter Address : Node Address : Functional Addr\n",
+ seq_printf(m, "\n%6s: Adapter Address : Node Address : Functional Addr\n",
dev->name);
for (i = 0 ; i < 6 ; i++)
addr[i] = readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr) + i);
- size += sprintf(buffer+size, "%6s: %pM : %pM : %02x:%02x:%02x:%02x\n",
+ seq_printf(m, "%6s: %pM : %pM : %02x:%02x:%02x:%02x\n",
dev->name,
dev->dev_addr, addr,
readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)),
@@ -1645,9 +1642,9 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt
readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2),
readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+3));
- size += sprintf(buffer+size, "\n%6s: Token Ring Parameters Table:\n", dev->name);
+ seq_printf(m, "\n%6s: Token Ring Parameters Table:\n", dev->name);
- size += sprintf(buffer+size, "%6s: Physical Addr : Up Node Address : Poll Address : AccPri : Auth Src : Att Code :\n",
+ seq_printf(m, "%6s: Physical Addr : Up Node Address : Poll Address : AccPri : Auth Src : Att Code :\n",
dev->name) ;
for (i = 0 ; i < 6 ; i++)
@@ -1655,7 +1652,7 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt
for (i = 0 ; i < 6 ; i++)
addr2[i] = readb(opt+offsetof(struct olympic_parameters_table, poll_addr) + i);
- size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x : %pM : %pM : %04x : %04x : %04x :\n",
+ seq_printf(m, "%6s: %02x:%02x:%02x:%02x : %pM : %pM : %04x : %04x : %04x :\n",
dev->name,
readb(opt+offsetof(struct olympic_parameters_table, phys_addr)),
readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+1),
@@ -1666,12 +1663,12 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt
swab16(readw(opt+offsetof(struct olympic_parameters_table, auth_source_class))),
swab16(readw(opt+offsetof(struct olympic_parameters_table, att_code))));
- size += sprintf(buffer+size, "%6s: Source Address : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n",
+ seq_printf(m, "%6s: Source Address : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n",
dev->name) ;
for (i = 0 ; i < 6 ; i++)
addr[i] = readb(opt+offsetof(struct olympic_parameters_table, source_addr) + i);
- size += sprintf(buffer+size, "%6s: %pM : %04x : %04x : %04x : %04x : %04x : %04x : \n",
+ seq_printf(m, "%6s: %pM : %04x : %04x : %04x : %04x : %04x : %04x : \n",
dev->name, addr,
swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_type))),
swab16(readw(opt+offsetof(struct olympic_parameters_table, major_vector))),
@@ -1680,12 +1677,12 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt
swab16(readw(opt+offsetof(struct olympic_parameters_table, mon_error))),
swab16(readw(opt+offsetof(struct olympic_parameters_table, frame_correl))));
- size += sprintf(buffer+size, "%6s: Beacon Details : Tx : Rx : NAUN Node Address : NAUN Node Phys : \n",
+ seq_printf(m, "%6s: Beacon Details : Tx : Rx : NAUN Node Address : NAUN Node Phys : \n",
dev->name) ;
for (i = 0 ; i < 6 ; i++)
addr[i] = readb(opt+offsetof(struct olympic_parameters_table, beacon_naun) + i);
- size += sprintf(buffer+size, "%6s: : %02x : %02x : %pM : %02x:%02x:%02x:%02x : \n",
+ seq_printf(m, "%6s: : %02x : %02x : %pM : %02x:%02x:%02x:%02x : \n",
dev->name,
swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_transmit))),
swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_receive))),
@@ -1695,19 +1692,21 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt
readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+2),
readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+3));
- len=size;
- pos=begin+size;
- if (pos<offset) {
- len=0;
- begin=pos;
- }
- *start=buffer+(offset-begin); /* Start of wanted data */
- len-=(offset-begin); /* Start slop */
- if(len>length)
- len=length; /* Ending slop */
- return len;
+ return 0;
}
+static int olympic_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, olympic_proc_show, PDE(inode)->data);
+}
+
+static const struct file_operations olympic_proc_ops = {
+ .open = olympic_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static void __devexit olympic_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev) ;
diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c
index 007d8e75666d..092c3faa882a 100644
--- a/drivers/net/tulip/21142.c
+++ b/drivers/net/tulip/21142.c
@@ -122,8 +122,8 @@ void t21142_start_nway(struct net_device *dev)
tp->nway = tp->mediasense = 1;
tp->nwayset = tp->lpar = 0;
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, csr14=%08x\n",
- dev->name, csr14);
+ netdev_dbg(dev, "Restarting 21143 autonegotiation, csr14=%08x\n",
+ csr14);
iowrite32(0x0001, ioaddr + CSR13);
udelay(100);
iowrite32(csr14, ioaddr + CSR14);
@@ -206,14 +206,14 @@ void t21142_lnk_change(struct net_device *dev, int csr5)
#if 0 /* Restart shouldn't be needed. */
iowrite32(tp->csr6 | RxOn, ioaddr + CSR6);
if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: Restarting Tx and Rx, CSR5 is %08x\n",
- dev->name, ioread32(ioaddr + CSR5));
+ netdev_dbg(dev, " Restarting Tx and Rx, CSR5 is %08x\n",
+ ioread32(ioaddr + CSR5));
#endif
tulip_start_rxtx(tp);
if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: Setting CSR6 %08x/%x CSR12 %08x\n",
- dev->name, tp->csr6, ioread32(ioaddr + CSR6),
- ioread32(ioaddr + CSR12));
+ netdev_dbg(dev, " Setting CSR6 %08x/%x CSR12 %08x\n",
+ tp->csr6, ioread32(ioaddr + CSR6),
+ ioread32(ioaddr + CSR12));
} else if ((tp->nwayset && (csr5 & 0x08000000) &&
(dev->if_port == 3 || dev->if_port == 5) &&
(csr12 & 2) == 2) ||
diff --git a/drivers/net/tulip/Makefile b/drivers/net/tulip/Makefile
index 200cbf7c815c..5e8be38b45bb 100644
--- a/drivers/net/tulip/Makefile
+++ b/drivers/net/tulip/Makefile
@@ -2,6 +2,8 @@
# Makefile for the Linux "Tulip" family network device drivers.
#
+ccflags-$(CONFIG_NET_TULIP) := -DDEBUG
+
obj-$(CONFIG_PCMCIA_XIRCOM) += xircom_cb.o
obj-$(CONFIG_DM9102) += dmfe.o
obj-$(CONFIG_WINBOND_840) += winbond-840.o
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index b13c6b040be3..e2f692351180 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -27,6 +27,8 @@
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#define DRV_NAME "de2104x"
#define DRV_VERSION "0.7"
#define DRV_RELDATE "Mar 17, 2004"
@@ -51,7 +53,7 @@
/* These identify the driver base version and may not be removed. */
static char version[] =
-KERN_INFO DRV_NAME " PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")\n";
+"PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")";
MODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>");
MODULE_DESCRIPTION("Intel/Digital 21040/1 series PCI Ethernet driver");
@@ -73,8 +75,6 @@ static int rx_copybreak = 100;
module_param (rx_copybreak, int, 0);
MODULE_PARM_DESC (rx_copybreak, "de2104x Breakpoint at which Rx packets are copied");
-#define PFX DRV_NAME ": "
-
#define DE_DEF_MSG_ENABLE (NETIF_MSG_DRV | \
NETIF_MSG_PROBE | \
NETIF_MSG_LINK | \
@@ -377,18 +377,16 @@ static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
static void de_rx_err_acct (struct de_private *de, unsigned rx_tail,
u32 status, u32 len)
{
- if (netif_msg_rx_err (de))
- printk (KERN_DEBUG
- "%s: rx err, slot %d status 0x%x len %d\n",
- de->dev->name, rx_tail, status, len);
+ netif_dbg(de, rx_err, de->dev,
+ "rx err, slot %d status 0x%x len %d\n",
+ rx_tail, status, len);
if ((status & 0x38000300) != 0x0300) {
/* Ingore earlier buffers. */
if ((status & 0xffff) != 0x7fff) {
- if (netif_msg_rx_err(de))
- dev_warn(&de->dev->dev,
- "Oversized Ethernet frame spanned multiple buffers, status %08x!\n",
- status);
+ netif_warn(de, rx_err, de->dev,
+ "Oversized Ethernet frame spanned multiple buffers, status %08x!\n",
+ status);
de->net_stats.rx_length_errors++;
}
} else if (status & RxError) {
@@ -435,10 +433,9 @@ static void de_rx (struct de_private *de)
copying_skb = (len <= rx_copybreak);
- if (unlikely(netif_msg_rx_status(de)))
- printk(KERN_DEBUG "%s: rx slot %d status 0x%x len %d copying? %d\n",
- de->dev->name, rx_tail, status, len,
- copying_skb);
+ netif_dbg(de, rx_status, de->dev,
+ "rx slot %d status 0x%x len %d copying? %d\n",
+ rx_tail, status, len, copying_skb);
buflen = copying_skb ? (len + RX_OFFSET) : de->rx_buf_sz;
copy_skb = dev_alloc_skb (buflen);
@@ -491,7 +488,7 @@ rx_next:
}
if (!rx_work)
- dev_warn(&de->dev->dev, "rx work limit reached\n");
+ netdev_warn(de->dev, "rx work limit reached\n");
de->rx_tail = rx_tail;
}
@@ -506,10 +503,9 @@ static irqreturn_t de_interrupt (int irq, void *dev_instance)
if ((!(status & (IntrOK|IntrErr))) || (status == 0xFFFF))
return IRQ_NONE;
- if (netif_msg_intr(de))
- printk(KERN_DEBUG "%s: intr, status %08x mode %08x desc %u/%u/%u\n",
- dev->name, status, dr32(MacMode),
- de->rx_tail, de->tx_head, de->tx_tail);
+ netif_dbg(de, intr, dev, "intr, status %08x mode %08x desc %u/%u/%u\n",
+ status, dr32(MacMode),
+ de->rx_tail, de->tx_head, de->tx_tail);
dw32(MacStatus, status);
@@ -534,9 +530,9 @@ static irqreturn_t de_interrupt (int irq, void *dev_instance)
pci_read_config_word(de->pdev, PCI_STATUS, &pci_status);
pci_write_config_word(de->pdev, PCI_STATUS, pci_status);
- dev_err(&de->dev->dev,
- "PCI bus error, status=%08x, PCI status=%04x\n",
- status, pci_status);
+ netdev_err(de->dev,
+ "PCI bus error, status=%08x, PCI status=%04x\n",
+ status, pci_status);
}
return IRQ_HANDLED;
@@ -572,9 +568,9 @@ static void de_tx (struct de_private *de)
if (status & LastFrag) {
if (status & TxError) {
- if (netif_msg_tx_err(de))
- printk(KERN_DEBUG "%s: tx err, status 0x%x\n",
- de->dev->name, status);
+ netif_dbg(de, tx_err, de->dev,
+ "tx err, status 0x%x\n",
+ status);
de->net_stats.tx_errors++;
if (status & TxOWC)
de->net_stats.tx_window_errors++;
@@ -587,9 +583,8 @@ static void de_tx (struct de_private *de)
} else {
de->net_stats.tx_packets++;
de->net_stats.tx_bytes += skb->len;
- if (netif_msg_tx_done(de))
- printk(KERN_DEBUG "%s: tx done, slot %d\n",
- de->dev->name, tx_tail);
+ netif_dbg(de, tx_done, de->dev,
+ "tx done, slot %d\n", tx_tail);
}
dev_kfree_skb_irq(skb);
}
@@ -646,9 +641,8 @@ static netdev_tx_t de_start_xmit (struct sk_buff *skb,
wmb();
de->tx_head = NEXT_TX(entry);
- if (netif_msg_tx_queued(de))
- printk(KERN_DEBUG "%s: tx queued, slot %d, skblen %d\n",
- dev->name, entry, skb->len);
+ netif_dbg(de, tx_queued, dev, "tx queued, slot %d, skblen %d\n",
+ entry, skb->len);
if (tx_free == 0)
netif_stop_queue(dev);
@@ -873,7 +867,7 @@ static void de_stop_rxtx (struct de_private *de)
udelay(100);
}
- dev_warn(&de->dev->dev, "timeout expired stopping DMA\n");
+ netdev_warn(de->dev, "timeout expired, stopping DMA\n");
}
static inline void de_start_rxtx (struct de_private *de)
@@ -907,9 +901,8 @@ static void de_link_up(struct de_private *de)
{
if (!netif_carrier_ok(de->dev)) {
netif_carrier_on(de->dev);
- if (netif_msg_link(de))
- dev_info(&de->dev->dev, "link up, media %s\n",
- media_name[de->media_type]);
+ netif_info(de, link, de->dev, "link up, media %s\n",
+ media_name[de->media_type]);
}
}
@@ -917,8 +910,7 @@ static void de_link_down(struct de_private *de)
{
if (netif_carrier_ok(de->dev)) {
netif_carrier_off(de->dev);
- if (netif_msg_link(de))
- dev_info(&de->dev->dev, "link down\n");
+ netif_info(de, link, de->dev, "link down\n");
}
}
@@ -928,8 +920,7 @@ static void de_set_media (struct de_private *de)
u32 macmode = dr32(MacMode);
if (de_is_running(de))
- dev_warn(&de->dev->dev,
- "chip is running while changing media!\n");
+ netdev_warn(de->dev, "chip is running while changing media!\n");
if (de->de21040)
dw32(CSR11, FULL_DUPLEX_MAGIC);
@@ -948,18 +939,13 @@ static void de_set_media (struct de_private *de)
else
macmode &= ~FullDuplex;
- if (netif_msg_link(de))
- dev_info(&de->dev->dev, "set link %s\n", media_name[media]);
- if (netif_msg_hw(de)) {
- dev_info(&de->dev->dev, "mode 0x%x, sia 0x%x,0x%x,0x%x,0x%x\n",
- dr32(MacMode), dr32(SIAStatus),
- dr32(CSR13), dr32(CSR14), dr32(CSR15));
-
- dev_info(&de->dev->dev,
- "set mode 0x%x, set sia 0x%x,0x%x,0x%x\n",
- macmode, de->media[media].csr13,
- de->media[media].csr14, de->media[media].csr15);
- }
+ netif_info(de, link, de->dev, "set link %s\n", media_name[media]);
+ netif_info(de, hw, de->dev, "mode 0x%x, sia 0x%x,0x%x,0x%x,0x%x\n",
+ dr32(MacMode), dr32(SIAStatus),
+ dr32(CSR13), dr32(CSR14), dr32(CSR15));
+ netif_info(de, hw, de->dev, "set mode 0x%x, set sia 0x%x,0x%x,0x%x\n",
+ macmode, de->media[media].csr13,
+ de->media[media].csr14, de->media[media].csr15);
if (macmode != dr32(MacMode))
dw32(MacMode, macmode);
}
@@ -996,9 +982,8 @@ static void de21040_media_timer (unsigned long data)
if (!netif_carrier_ok(dev))
de_link_up(de);
else
- if (netif_msg_timer(de))
- dev_info(&dev->dev, "%s link ok, status %x\n",
- media_name[de->media_type], status);
+ netif_info(de, timer, dev, "%s link ok, status %x\n",
+ media_name[de->media_type], status);
return;
}
@@ -1025,9 +1010,8 @@ no_link_yet:
de->media_timer.expires = jiffies + DE_TIMER_NO_LINK;
add_timer(&de->media_timer);
- if (netif_msg_timer(de))
- dev_info(&dev->dev, "no link, trying media %s, status %x\n",
- media_name[de->media_type], status);
+ netif_info(de, timer, dev, "no link, trying media %s, status %x\n",
+ media_name[de->media_type], status);
}
static unsigned int de_ok_to_advertise (struct de_private *de, u32 new_media)
@@ -1085,11 +1069,10 @@ static void de21041_media_timer (unsigned long data)
if (!netif_carrier_ok(dev))
de_link_up(de);
else
- if (netif_msg_timer(de))
- dev_info(&dev->dev,
- "%s link ok, mode %x status %x\n",
- media_name[de->media_type],
- dr32(MacMode), status);
+ netif_info(de, timer, dev,
+ "%s link ok, mode %x status %x\n",
+ media_name[de->media_type],
+ dr32(MacMode), status);
return;
}
@@ -1163,9 +1146,8 @@ no_link_yet:
de->media_timer.expires = jiffies + DE_TIMER_NO_LINK;
add_timer(&de->media_timer);
- if (netif_msg_timer(de))
- dev_info(&dev->dev, "no link, trying media %s, status %x\n",
- media_name[de->media_type], status);
+ netif_info(de, timer, dev, "no link, trying media %s, status %x\n",
+ media_name[de->media_type], status);
}
static void de_media_interrupt (struct de_private *de, u32 status)
@@ -1401,14 +1383,13 @@ static int de_open (struct net_device *dev)
struct de_private *de = netdev_priv(dev);
int rc;
- if (netif_msg_ifup(de))
- printk(KERN_DEBUG "%s: enabling interface\n", dev->name);
+ netif_dbg(de, ifup, dev, "enabling interface\n");
de->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
rc = de_alloc_rings(de);
if (rc) {
- dev_err(&dev->dev, "ring allocation failure, err=%d\n", rc);
+ netdev_err(dev, "ring allocation failure, err=%d\n", rc);
return rc;
}
@@ -1416,14 +1397,14 @@ static int de_open (struct net_device *dev)
rc = request_irq(dev->irq, de_interrupt, IRQF_SHARED, dev->name, dev);
if (rc) {
- dev_err(&dev->dev, "IRQ %d request failure, err=%d\n",
- dev->irq, rc);
+ netdev_err(dev, "IRQ %d request failure, err=%d\n",
+ dev->irq, rc);
goto err_out_free;
}
rc = de_init_hw(de);
if (rc) {
- dev_err(&dev->dev, "h/w init failure, err=%d\n", rc);
+ netdev_err(dev, "h/w init failure, err=%d\n", rc);
goto err_out_free_irq;
}
@@ -1444,8 +1425,7 @@ static int de_close (struct net_device *dev)
struct de_private *de = netdev_priv(dev);
unsigned long flags;
- if (netif_msg_ifdown(de))
- printk(KERN_DEBUG "%s: disabling interface\n", dev->name);
+ netif_dbg(de, ifdown, dev, "disabling interface\n");
del_timer_sync(&de->media_timer);
@@ -1466,9 +1446,9 @@ static void de_tx_timeout (struct net_device *dev)
{
struct de_private *de = netdev_priv(dev);
- printk(KERN_DEBUG "%s: NIC status %08x mode %08x sia %08x desc %u/%u/%u\n",
- dev->name, dr32(MacStatus), dr32(MacMode), dr32(SIAStatus),
- de->rx_tail, de->tx_head, de->tx_tail);
+ netdev_dbg(dev, "NIC status %08x mode %08x sia %08x desc %u/%u/%u\n",
+ dr32(MacStatus), dr32(MacMode), dr32(SIAStatus),
+ de->rx_tail, de->tx_head, de->tx_tail);
del_timer_sync(&de->media_timer);
@@ -1518,18 +1498,17 @@ static int __de_get_settings(struct de_private *de, struct ethtool_cmd *ecmd)
switch (de->media_type) {
case DE_MEDIA_AUI:
ecmd->port = PORT_AUI;
- ecmd->speed = 5;
break;
case DE_MEDIA_BNC:
ecmd->port = PORT_BNC;
- ecmd->speed = 2;
break;
default:
ecmd->port = PORT_TP;
- ecmd->speed = SPEED_10;
break;
}
+ ethtool_cmd_speed_set(ecmd, 10);
+
if (dr32(MacMode) & FullDuplex)
ecmd->duplex = DUPLEX_FULL;
else
@@ -1550,9 +1529,7 @@ static int __de_set_settings(struct de_private *de, struct ethtool_cmd *ecmd)
u32 new_media;
unsigned int media_lock;
- if (ecmd->speed != SPEED_10 && ecmd->speed != 5 && ecmd->speed != 2)
- return -EINVAL;
- if (de->de21040 && ecmd->speed == 2)
+ if (ethtool_cmd_speed(ecmd) != 10)
return -EINVAL;
if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
return -EINVAL;
@@ -1696,9 +1673,8 @@ static int de_nway_reset(struct net_device *dev)
status = dr32(SIAStatus);
dw32(SIAStatus, (status & ~NWayState) | NWayRestart);
- if (netif_msg_link(de))
- dev_info(&de->dev->dev, "link nway restart, status %x,%x\n",
- status, dr32(SIAStatus));
+ netif_info(de, link, dev, "link nway restart, status %x,%x\n",
+ status, dr32(SIAStatus));
return 0;
}
@@ -1743,7 +1719,8 @@ static void __devinit de21040_get_mac_address (struct de_private *de)
de->dev->dev_addr[i] = value;
udelay(1);
if (boguscnt <= 0)
- pr_warning(PFX "timeout reading 21040 MAC address byte %u\n", i);
+ pr_warn("timeout reading 21040 MAC address byte %u\n",
+ i);
}
}
@@ -1929,8 +1906,10 @@ static void __devinit de21041_get_srom_info (struct de_private *de)
de->media[idx].csr14,
de->media[idx].csr15);
- } else if (netif_msg_probe(de))
- pr_cont("\n");
+ } else {
+ if (netif_msg_probe(de))
+ pr_cont("\n");
+ }
if (bufp > ((void *)&ee_data[DE_EEPROM_SIZE - 3]))
break;
@@ -1999,7 +1978,7 @@ static int __devinit de_init_one (struct pci_dev *pdev,
#ifndef MODULE
if (board_idx == 0)
- printk("%s", version);
+ pr_info("%s\n", version);
#endif
/* allocate a new ethernet device structure, and fill in defaults */
@@ -2041,7 +2020,7 @@ static int __devinit de_init_one (struct pci_dev *pdev,
/* check for invalid IRQ value */
if (pdev->irq < 2) {
rc = -EIO;
- pr_err(PFX "invalid irq (%d) for pci dev %s\n",
+ pr_err("invalid irq (%d) for pci dev %s\n",
pdev->irq, pci_name(pdev));
goto err_out_res;
}
@@ -2052,12 +2031,12 @@ static int __devinit de_init_one (struct pci_dev *pdev,
pciaddr = pci_resource_start(pdev, 1);
if (!pciaddr) {
rc = -EIO;
- pr_err(PFX "no MMIO resource for pci dev %s\n", pci_name(pdev));
+ pr_err("no MMIO resource for pci dev %s\n", pci_name(pdev));
goto err_out_res;
}
if (pci_resource_len(pdev, 1) < DE_REGS_SIZE) {
rc = -EIO;
- pr_err(PFX "MMIO resource (%llx) too small on pci dev %s\n",
+ pr_err("MMIO resource (%llx) too small on pci dev %s\n",
(unsigned long long)pci_resource_len(pdev, 1),
pci_name(pdev));
goto err_out_res;
@@ -2067,7 +2046,7 @@ static int __devinit de_init_one (struct pci_dev *pdev,
regs = ioremap_nocache(pciaddr, DE_REGS_SIZE);
if (!regs) {
rc = -EIO;
- pr_err(PFX "Cannot map PCI MMIO (%llx@%lx) on pci dev %s\n",
+ pr_err("Cannot map PCI MMIO (%llx@%lx) on pci dev %s\n",
(unsigned long long)pci_resource_len(pdev, 1),
pciaddr, pci_name(pdev));
goto err_out_res;
@@ -2080,7 +2059,7 @@ static int __devinit de_init_one (struct pci_dev *pdev,
/* make sure hardware is not running */
rc = de_reset_mac(de);
if (rc) {
- pr_err(PFX "Cannot reset MAC, pci dev %s\n", pci_name(pdev));
+ pr_err("Cannot reset MAC, pci dev %s\n", pci_name(pdev));
goto err_out_iomap;
}
@@ -2100,11 +2079,11 @@ static int __devinit de_init_one (struct pci_dev *pdev,
goto err_out_iomap;
/* print info about board and interface just registered */
- dev_info(&dev->dev, "%s at 0x%lx, %pM, IRQ %d\n",
- de->de21040 ? "21040" : "21041",
- dev->base_addr,
- dev->dev_addr,
- dev->irq);
+ netdev_info(dev, "%s at 0x%lx, %pM, IRQ %d\n",
+ de->de21040 ? "21040" : "21041",
+ dev->base_addr,
+ dev->dev_addr,
+ dev->irq);
pci_set_drvdata(pdev, dev);
@@ -2192,7 +2171,7 @@ static int de_resume (struct pci_dev *pdev)
if (!netif_running(dev))
goto out_attach;
if ((retval = pci_enable_device(pdev))) {
- dev_err(&dev->dev, "pci_enable_device failed in resume\n");
+ netdev_err(dev, "pci_enable_device failed in resume\n");
goto out;
}
pci_set_master(pdev);
@@ -2221,7 +2200,7 @@ static struct pci_driver de_driver = {
static int __init de_init (void)
{
#ifdef MODULE
- printk("%s", version);
+ pr_info("%s\n", version);
#endif
return pci_register_driver(&de_driver);
}
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index efaa1d69b720..45144d5bd11b 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -1995,7 +1995,7 @@ SetMulticastFilter(struct net_device *dev)
static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST;
-static int __init de4x5_eisa_probe (struct device *gendev)
+static int __devinit de4x5_eisa_probe (struct device *gendev)
{
struct eisa_device *edev;
u_long iobase;
@@ -2097,7 +2097,7 @@ static int __devexit de4x5_eisa_remove (struct device *device)
return 0;
}
-static struct eisa_device_id de4x5_eisa_ids[] = {
+static const struct eisa_device_id de4x5_eisa_ids[] __devinitconst = {
{ "DEC4250", 0 }, /* 0 is the board name index... */
{ "" }
};
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index fb07f48910ae..468512731966 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -295,8 +295,7 @@ enum dmfe_CR6_bits {
/* Global variable declaration ----------------------------- */
static int __devinitdata printed_version;
static const char version[] __devinitconst =
- KERN_INFO DRV_NAME ": Davicom DM9xxx net driver, version "
- DRV_VERSION " (" DRV_RELDATE ")\n";
+ "Davicom DM9xxx net driver, version " DRV_VERSION " (" DRV_RELDATE ")";
static int dmfe_debug;
static unsigned char dmfe_media_mode = DMFE_AUTO;
@@ -381,7 +380,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
DMFE_DBUG(0, "dmfe_init_one()", 0);
if (!printed_version++)
- printk(version);
+ pr_info("%s\n", version);
/*
* SPARC on-board DM910x chips should be handled by the main
@@ -406,7 +405,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
SET_NETDEV_DEV(dev, &pdev->dev);
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
- pr_warning("32-bit PCI DMA not available\n");
+ pr_warn("32-bit PCI DMA not available\n");
err = -ENODEV;
goto err_out_free;
}
@@ -2203,7 +2202,7 @@ static int __init dmfe_init_module(void)
{
int rc;
- printk(version);
+ pr_info("%s\n", version);
printed_version = 1;
DMFE_DBUG(0, "init_module() ", debug);
diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c
index 296486bf0956..fa5eee925f25 100644
--- a/drivers/net/tulip/eeprom.c
+++ b/drivers/net/tulip/eeprom.c
@@ -222,8 +222,8 @@ subsequent_board:
/* there is no phy information, don't even try to build mtable */
if (count == 0) {
if (tulip_debug > 0)
- pr_warning("%s: no phy info, aborting mtable build\n",
- dev->name);
+ pr_warn("%s: no phy info, aborting mtable build\n",
+ dev->name);
return;
}
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
index 0013642903ee..5350d753e0ff 100644
--- a/drivers/net/tulip/interrupt.c
+++ b/drivers/net/tulip/interrupt.c
@@ -125,12 +125,12 @@ int tulip_poll(struct napi_struct *napi, int budget)
#endif
if (tulip_debug > 4)
- printk(KERN_DEBUG " In tulip_rx(), entry %d %08x\n",
- entry, tp->rx_ring[entry].status);
+ netdev_dbg(dev, " In tulip_rx(), entry %d %08x\n",
+ entry, tp->rx_ring[entry].status);
do {
if (ioread32(tp->base_addr + CSR5) == 0xffffffff) {
- printk(KERN_DEBUG " In tulip_poll(), hardware disappeared\n");
+ netdev_dbg(dev, " In tulip_poll(), hardware disappeared\n");
break;
}
/* Acknowledge current RX interrupt sources. */
@@ -145,9 +145,9 @@ int tulip_poll(struct napi_struct *napi, int budget)
if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx)
break;
- if (tulip_debug > 5)
- printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %08x\n",
- dev->name, entry, status);
+ if (tulip_debug > 5)
+ netdev_dbg(dev, "In tulip_rx(), entry %d %08x\n",
+ entry, status);
if (++work_done >= budget)
goto not_done;
@@ -184,9 +184,9 @@ int tulip_poll(struct napi_struct *napi, int budget)
}
} else {
/* There was a fatal error. */
- if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: Receive error, Rx status %08x\n",
- dev->name, status);
+ if (tulip_debug > 2)
+ netdev_dbg(dev, "Receive error, Rx status %08x\n",
+ status);
dev->stats.rx_errors++; /* end of a packet.*/
if (pkt_len > 1518 ||
(status & RxDescRunt))
@@ -367,16 +367,16 @@ static int tulip_rx(struct net_device *dev)
int received = 0;
if (tulip_debug > 4)
- printk(KERN_DEBUG " In tulip_rx(), entry %d %08x\n",
- entry, tp->rx_ring[entry].status);
+ netdev_dbg(dev, "In tulip_rx(), entry %d %08x\n",
+ entry, tp->rx_ring[entry].status);
/* If we own the next entry, it is a new packet. Send it up. */
while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) {
s32 status = le32_to_cpu(tp->rx_ring[entry].status);
short pkt_len;
if (tulip_debug > 5)
- printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %08x\n",
- dev->name, entry, status);
+ netdev_dbg(dev, "In tulip_rx(), entry %d %08x\n",
+ entry, status);
if (--rx_work_limit < 0)
break;
@@ -404,16 +404,16 @@ static int tulip_rx(struct net_device *dev)
/* Ingore earlier buffers. */
if ((status & 0xffff) != 0x7fff) {
if (tulip_debug > 1)
- dev_warn(&dev->dev,
- "Oversized Ethernet frame spanned multiple buffers, status %08x!\n",
- status);
+ netdev_warn(dev,
+ "Oversized Ethernet frame spanned multiple buffers, status %08x!\n",
+ status);
dev->stats.rx_length_errors++;
}
} else {
/* There was a fatal error. */
if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: Receive error, Rx status %08x\n",
- dev->name, status);
+ netdev_dbg(dev, "Receive error, Rx status %08x\n",
+ status);
dev->stats.rx_errors++; /* end of a packet.*/
if (pkt_len > 1518 ||
(status & RxDescRunt))
@@ -573,8 +573,8 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
#endif /* CONFIG_TULIP_NAPI */
if (tulip_debug > 4)
- printk(KERN_DEBUG "%s: interrupt csr5=%#8.8x new csr5=%#8.8x\n",
- dev->name, csr5, ioread32(ioaddr + CSR5));
+ netdev_dbg(dev, "interrupt csr5=%#8.8x new csr5=%#8.8x\n",
+ csr5, ioread32(ioaddr + CSR5));
if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) {
@@ -605,8 +605,8 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
/* There was an major error, log it. */
#ifndef final_version
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Transmit error, Tx status %08x\n",
- dev->name, status);
+ netdev_dbg(dev, "Transmit error, Tx status %08x\n",
+ status);
#endif
dev->stats.tx_errors++;
if (status & 0x4104)
@@ -804,8 +804,8 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance)
}
if (tulip_debug > 4)
- printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#04x\n",
- dev->name, ioread32(ioaddr + CSR5));
+ netdev_dbg(dev, "exiting interrupt, csr5=%#04x\n",
+ ioread32(ioaddr + CSR5));
return IRQ_HANDLED;
}
diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c
index a0c770ee4b64..4bd13922875d 100644
--- a/drivers/net/tulip/media.c
+++ b/drivers/net/tulip/media.c
@@ -182,8 +182,8 @@ void tulip_select_media(struct net_device *dev, int startup)
switch (mleaf->type) {
case 0: /* 21140 non-MII xcvr. */
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver with control setting %02x\n",
- dev->name, p[1]);
+ netdev_dbg(dev, "Using a 21140 non-MII transceiver with control setting %02x\n",
+ p[1]);
dev->if_port = p[0];
if (startup)
iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12);
@@ -204,15 +204,14 @@ void tulip_select_media(struct net_device *dev, int startup)
struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset];
unsigned char *rst = rleaf->leafdata;
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Resetting the transceiver\n",
- dev->name);
+ netdev_dbg(dev, "Resetting the transceiver\n");
for (i = 0; i < rst[0]; i++)
iowrite32(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15);
}
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control %04x/%04x\n",
- dev->name, medianame[dev->if_port],
- setup[0], setup[1]);
+ netdev_dbg(dev, "21143 non-MII %s transceiver control %04x/%04x\n",
+ medianame[dev->if_port],
+ setup[0], setup[1]);
if (p[0] & 0x40) { /* SIA (CSR13-15) setup values are provided. */
csr13val = setup[0];
csr14val = setup[1];
@@ -239,8 +238,8 @@ void tulip_select_media(struct net_device *dev, int startup)
if (startup) iowrite32(csr13val, ioaddr + CSR13);
}
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Setting CSR15 to %08x/%08x\n",
- dev->name, csr15dir, csr15val);
+ netdev_dbg(dev, "Setting CSR15 to %08x/%08x\n",
+ csr15dir, csr15val);
if (mleaf->type == 4)
new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18);
else
@@ -316,9 +315,9 @@ void tulip_select_media(struct net_device *dev, int startup)
if (tp->mii_advertise == 0)
tp->mii_advertise = tp->advertising[phy_num];
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Advertising %04x on MII %d\n",
- dev->name, tp->mii_advertise,
- tp->phys[phy_num]);
+ netdev_dbg(dev, " Advertising %04x on MII %d\n",
+ tp->mii_advertise,
+ tp->phys[phy_num]);
tulip_mdio_write(dev, tp->phys[phy_num], 4, tp->mii_advertise);
}
break;
@@ -335,8 +334,7 @@ void tulip_select_media(struct net_device *dev, int startup)
struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset];
unsigned char *rst = rleaf->leafdata;
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Resetting the transceiver\n",
- dev->name);
+ netdev_dbg(dev, "Resetting the transceiver\n");
for (i = 0; i < rst[0]; i++)
iowrite32(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15);
}
@@ -344,20 +342,21 @@ void tulip_select_media(struct net_device *dev, int startup)
break;
}
default:
- printk(KERN_DEBUG "%s: Invalid media table selection %d\n",
- dev->name, mleaf->type);
+ netdev_dbg(dev, " Invalid media table selection %d\n",
+ mleaf->type);
new_csr6 = 0x020E0000;
}
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %02x\n",
- dev->name, medianame[dev->if_port],
+ netdev_dbg(dev, "Using media type %s, CSR12 is %02x\n",
+ medianame[dev->if_port],
ioread32(ioaddr + CSR12) & 0xff);
} else if (tp->chip_id == LC82C168) {
if (startup && ! tp->medialock)
dev->if_port = tp->mii_cnt ? 11 : 0;
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, media %s\n",
- dev->name, ioread32(ioaddr + 0xB8), medianame[dev->if_port]);
+ netdev_dbg(dev, "PNIC PHY status is %3.3x, media %s\n",
+ ioread32(ioaddr + 0xB8),
+ medianame[dev->if_port]);
if (tp->mii_cnt) {
new_csr6 = 0x810C0000;
iowrite32(0x0001, ioaddr + CSR15);
@@ -388,9 +387,9 @@ void tulip_select_media(struct net_device *dev, int startup)
} else
new_csr6 = 0x03860000;
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: No media description table, assuming %s transceiver, CSR12 %02x\n",
- dev->name, medianame[dev->if_port],
- ioread32(ioaddr + CSR12));
+ netdev_dbg(dev, "No media description table, assuming %s transceiver, CSR12 %02x\n",
+ medianame[dev->if_port],
+ ioread32(ioaddr + CSR12));
}
tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0);
@@ -504,8 +503,8 @@ void __devinit tulip_find_mii (struct net_device *dev, int board_idx)
/* Fixup for DLink with miswired PHY. */
if (mii_advert != to_advert) {
- printk(KERN_DEBUG "tulip%d: Advertising %04x on PHY %d, previously advertising %04x\n",
- board_idx, to_advert, phy, mii_advert);
+ pr_debug("tulip%d: Advertising %04x on PHY %d, previously advertising %04x\n",
+ board_idx, to_advert, phy, mii_advert);
tulip_mdio_write (dev, phy, 4, to_advert);
}
diff --git a/drivers/net/tulip/pnic.c b/drivers/net/tulip/pnic.c
index a63e64b6863d..aa4d9dad0395 100644
--- a/drivers/net/tulip/pnic.c
+++ b/drivers/net/tulip/pnic.c
@@ -40,8 +40,8 @@ void pnic_do_nway(struct net_device *dev)
new_csr6 |= 0x00000200;
}
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: PNIC autonegotiated status %08x, %s\n",
- dev->name, phy_reg, medianame[dev->if_port]);
+ netdev_dbg(dev, "PNIC autonegotiated status %08x, %s\n",
+ phy_reg, medianame[dev->if_port]);
if (tp->csr6 != new_csr6) {
tp->csr6 = new_csr6;
/* Restart Tx */
@@ -58,8 +58,8 @@ void pnic_lnk_change(struct net_device *dev, int csr5)
int phy_reg = ioread32(ioaddr + 0xB8);
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: PNIC link changed state %08x, CSR5 %08x\n",
- dev->name, phy_reg, csr5);
+ netdev_dbg(dev, "PNIC link changed state %08x, CSR5 %08x\n",
+ phy_reg, csr5);
if (ioread32(ioaddr + CSR5) & TPLnkFail) {
iowrite32((ioread32(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7);
/* If we use an external MII, then we mustn't use the
@@ -114,8 +114,8 @@ void pnic_timer(unsigned long data)
int csr5 = ioread32(ioaddr + CSR5);
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: PNIC timer PHY status %08x, %s CSR5 %08x\n",
- dev->name, phy_reg, medianame[dev->if_port], csr5);
+ netdev_dbg(dev, "PNIC timer PHY status %08x, %s CSR5 %08x\n",
+ phy_reg, medianame[dev->if_port], csr5);
if (phy_reg & 0x04000000) { /* Remote link fault */
iowrite32(0x0201F078, ioaddr + 0xB8);
next_tick = 1*HZ;
@@ -125,11 +125,11 @@ void pnic_timer(unsigned long data)
next_tick = 60*HZ;
} else if (csr5 & TPLnkFail) { /* 100baseTx link beat */
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %04x, CSR5 %08x, PHY %03x\n",
- dev->name, medianame[dev->if_port],
- csr12,
- ioread32(ioaddr + CSR5),
- ioread32(ioaddr + 0xB8));
+ netdev_dbg(dev, "%s link beat failed, CSR12 %04x, CSR5 %08x, PHY %03x\n",
+ medianame[dev->if_port],
+ csr12,
+ ioread32(ioaddr + CSR5),
+ ioread32(ioaddr + 0xB8));
next_tick = 3*HZ;
if (tp->medialock) {
} else if (tp->nwayset && (dev->if_port & 1)) {
diff --git a/drivers/net/tulip/pnic2.c b/drivers/net/tulip/pnic2.c
index 4690c8e69207..93358ee4d830 100644
--- a/drivers/net/tulip/pnic2.c
+++ b/drivers/net/tulip/pnic2.c
@@ -125,8 +125,8 @@ void pnic2_start_nway(struct net_device *dev)
csr14 |= 0x00001184;
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Restarting PNIC2 autonegotiation, csr14=%08x\n",
- dev->name, csr14);
+ netdev_dbg(dev, "Restarting PNIC2 autonegotiation, csr14=%08x\n",
+ csr14);
/* tell pnic2_lnk_change we are doing an nway negotiation */
dev->if_port = 0;
@@ -137,8 +137,7 @@ void pnic2_start_nway(struct net_device *dev)
tp->csr6 = ioread32(ioaddr + CSR6);
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: On Entry to Nway, csr6=%08x\n",
- dev->name, tp->csr6);
+ netdev_dbg(dev, "On Entry to Nway, csr6=%08x\n", tp->csr6);
/* mask off any bits not to touch
* comment at top of file explains mask value
@@ -271,9 +270,10 @@ void pnic2_lnk_change(struct net_device *dev, int csr5)
iowrite32(1, ioaddr + CSR13);
if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: Setting CSR6 %08x/%x CSR12 %08x\n",
- dev->name, tp->csr6,
- ioread32(ioaddr + CSR6), ioread32(ioaddr + CSR12));
+ netdev_dbg(dev, "Setting CSR6 %08x/%x CSR12 %08x\n",
+ tp->csr6,
+ ioread32(ioaddr + CSR6),
+ ioread32(ioaddr + CSR12));
/* now the following actually writes out the
* new csr6 values
@@ -324,7 +324,7 @@ void pnic2_lnk_change(struct net_device *dev, int csr5)
/* Link blew? Maybe restart NWay. */
if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: Ugh! Link blew?\n", dev->name);
+ netdev_dbg(dev, "Ugh! Link blew?\n");
del_timer_sync(&tp->timer);
pnic2_start_nway(dev);
diff --git a/drivers/net/tulip/timer.c b/drivers/net/tulip/timer.c
index 36c2725ec886..2017faf2d0e6 100644
--- a/drivers/net/tulip/timer.c
+++ b/drivers/net/tulip/timer.c
@@ -28,11 +28,11 @@ void tulip_media_task(struct work_struct *work)
unsigned long flags;
if (tulip_debug > 2) {
- printk(KERN_DEBUG "%s: Media selection tick, %s, status %08x mode %08x SIA %08x %08x %08x %08x\n",
- dev->name, medianame[dev->if_port],
- ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR6),
- csr12, ioread32(ioaddr + CSR13),
- ioread32(ioaddr + CSR14), ioread32(ioaddr + CSR15));
+ netdev_dbg(dev, "Media selection tick, %s, status %08x mode %08x SIA %08x %08x %08x %08x\n",
+ medianame[dev->if_port],
+ ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR6),
+ csr12, ioread32(ioaddr + CSR13),
+ ioread32(ioaddr + CSR14), ioread32(ioaddr + CSR15));
}
switch (tp->chip_id) {
case DC21140:
@@ -48,9 +48,9 @@ void tulip_media_task(struct work_struct *work)
Assume this a generic MII or SYM transceiver. */
next_tick = 60*HZ;
if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: network media monitor CSR6 %08x CSR12 0x%02x\n",
- dev->name,
- ioread32(ioaddr + CSR6), csr12 & 0xff);
+ netdev_dbg(dev, "network media monitor CSR6 %08x CSR12 0x%02x\n",
+ ioread32(ioaddr + CSR6),
+ csr12 & 0xff);
break;
}
mleaf = &tp->mtable->mleaf[tp->cur_index];
@@ -62,8 +62,8 @@ void tulip_media_task(struct work_struct *work)
s8 bitnum = p[offset];
if (p[offset+1] & 0x80) {
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Transceiver monitor tick CSR12=%#02x, no media sense\n",
- dev->name, csr12);
+ netdev_dbg(dev, "Transceiver monitor tick CSR12=%#02x, no media sense\n",
+ csr12);
if (mleaf->type == 4) {
if (mleaf->media == 3 && (csr12 & 0x02))
goto select_next_media;
@@ -71,17 +71,16 @@ void tulip_media_task(struct work_struct *work)
break;
}
if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#02x bit %d is %d, expecting %d\n",
- dev->name, csr12, (bitnum >> 1) & 7,
- (csr12 & (1 << ((bitnum >> 1) & 7))) != 0,
- (bitnum >= 0));
+ netdev_dbg(dev, "Transceiver monitor tick: CSR12=%#02x bit %d is %d, expecting %d\n",
+ csr12, (bitnum >> 1) & 7,
+ (csr12 & (1 << ((bitnum >> 1) & 7))) != 0,
+ (bitnum >= 0));
/* Check that the specified bit has the proper value. */
if ((bitnum < 0) !=
((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) {
if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: Link beat detected for %s\n",
- dev->name,
- medianame[mleaf->media & MEDIA_MASK]);
+ netdev_dbg(dev, "Link beat detected for %s\n",
+ medianame[mleaf->media & MEDIA_MASK]);
if ((p[2] & 0x61) == 0x01) /* Bogus Znyx board. */
goto actually_mii;
netif_carrier_on(dev);
@@ -99,10 +98,9 @@ void tulip_media_task(struct work_struct *work)
if (tulip_media_cap[dev->if_port] & MediaIsFD)
goto select_next_media; /* Skip FD entries. */
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: No link beat on media %s, trying transceiver type %s\n",
- dev->name,
- medianame[mleaf->media & MEDIA_MASK],
- medianame[tp->mtable->mleaf[tp->cur_index].media]);
+ netdev_dbg(dev, "No link beat on media %s, trying transceiver type %s\n",
+ medianame[mleaf->media & MEDIA_MASK],
+ medianame[tp->mtable->mleaf[tp->cur_index].media]);
tulip_select_media(dev, 0);
/* Restart the transmit process. */
tulip_restart_rxtx(tp);
@@ -166,10 +164,9 @@ void comet_timer(unsigned long data)
int next_tick = 60*HZ;
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: Comet link status %04x partner capability %04x\n",
- dev->name,
- tulip_mdio_read(dev, tp->phys[0], 1),
- tulip_mdio_read(dev, tp->phys[0], 5));
+ netdev_dbg(dev, "Comet link status %04x partner capability %04x\n",
+ tulip_mdio_read(dev, tp->phys[0], 1),
+ tulip_mdio_read(dev, tp->phys[0], 5));
/* mod_timer synchronizes us with potential add_timer calls
* from interrupts.
*/
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
index ed66a16711dc..9db528967da9 100644
--- a/drivers/net/tulip/tulip.h
+++ b/drivers/net/tulip/tulip.h
@@ -547,11 +547,9 @@ static inline void tulip_stop_rxtx(struct tulip_private *tp)
udelay(10);
if (!i)
- printk(KERN_DEBUG "%s: tulip_stop_rxtx() failed"
- " (CSR5 0x%x CSR6 0x%x)\n",
- pci_name(tp->pdev),
- ioread32(ioaddr + CSR5),
- ioread32(ioaddr + CSR6));
+ netdev_dbg(tp->dev, "tulip_stop_rxtx() failed (CSR5 0x%x CSR6 0x%x)\n",
+ ioread32(ioaddr + CSR5),
+ ioread32(ioaddr + CSR6));
}
}
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index 5c01e260f1ba..82f87647207e 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -12,6 +12,7 @@
Please submit bugs to http://bugzilla.kernel.org/ .
*/
+#define pr_fmt(fmt) "tulip: " fmt
#define DRV_NAME "tulip"
#ifdef CONFIG_TULIP_NAPI
@@ -119,8 +120,6 @@ module_param(csr0, int, 0);
module_param_array(options, int, NULL, 0);
module_param_array(full_duplex, int, NULL, 0);
-#define PFX DRV_NAME ": "
-
#ifdef TULIP_DEBUG
int tulip_debug = TULIP_DEBUG;
#else
@@ -331,8 +330,7 @@ static void tulip_up(struct net_device *dev)
udelay(100);
if (tulip_debug > 1)
- printk(KERN_DEBUG "%s: tulip_up(), irq==%d\n",
- dev->name, dev->irq);
+ netdev_dbg(dev, "tulip_up(), irq==%d\n", dev->irq);
iowrite32(tp->rx_ring_dma, ioaddr + CSR3);
iowrite32(tp->tx_ring_dma, ioaddr + CSR4);
@@ -499,10 +497,10 @@ media_picked:
iowrite32(0, ioaddr + CSR2); /* Rx poll demand */
if (tulip_debug > 2) {
- printk(KERN_DEBUG "%s: Done tulip_up(), CSR0 %08x, CSR5 %08x CSR6 %08x\n",
- dev->name, ioread32(ioaddr + CSR0),
- ioread32(ioaddr + CSR5),
- ioread32(ioaddr + CSR6));
+ netdev_dbg(dev, "Done tulip_up(), CSR0 %08x, CSR5 %08x CSR6 %08x\n",
+ ioread32(ioaddr + CSR0),
+ ioread32(ioaddr + CSR5),
+ ioread32(ioaddr + CSR6));
}
/* Set the timer to switch to check for link beat and perhaps switch
@@ -843,8 +841,7 @@ static int tulip_close (struct net_device *dev)
tulip_down (dev);
if (tulip_debug > 1)
- dev_printk(KERN_DEBUG, &dev->dev,
- "Shutting down ethercard, status was %02x\n",
+ netdev_dbg(dev, "Shutting down ethercard, status was %02x\n",
ioread32 (ioaddr + CSR5));
free_irq (dev->irq, dev);
@@ -1207,7 +1204,7 @@ static void __devinit tulip_mwi_config (struct pci_dev *pdev,
u32 csr0;
if (tulip_debug > 3)
- printk(KERN_DEBUG "%s: tulip_mwi_config()\n", pci_name(pdev));
+ netdev_dbg(dev, "tulip_mwi_config()\n");
tp->csr0 = csr0 = 0;
@@ -1269,8 +1266,8 @@ static void __devinit tulip_mwi_config (struct pci_dev *pdev,
out:
tp->csr0 = csr0;
if (tulip_debug > 2)
- printk(KERN_DEBUG "%s: MWI config cacheline=%d, csr0=%08x\n",
- pci_name(pdev), cache, csr0);
+ netdev_dbg(dev, "MWI config cacheline=%d, csr0=%08x\n",
+ cache, csr0);
}
#endif
@@ -1340,13 +1337,13 @@ 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");
+ pr_err("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");
+ pr_err("skipping SBE T3E3 port\n");
return -ENODEV;
}
@@ -1362,13 +1359,13 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
if (pdev->vendor == 0x1282 && pdev->device == 0x9100 &&
pdev->revision < 0x30) {
- pr_info(PFX "skipping early DM9100 with Crc bug (use dmfe)\n");
+ pr_info("skipping early DM9100 with Crc bug (use dmfe)\n");
return -ENODEV;
}
dp = pci_device_to_OF_node(pdev);
if (!(dp && of_get_property(dp, "local-mac-address", NULL))) {
- pr_info(PFX "skipping DM910x expansion card (use dmfe)\n");
+ pr_info("skipping DM910x expansion card (use dmfe)\n");
return -ENODEV;
}
}
@@ -1415,16 +1412,14 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
i = pci_enable_device(pdev);
if (i) {
- pr_err(PFX "Cannot enable tulip board #%d, aborting\n",
- board_idx);
+ pr_err("Cannot enable tulip board #%d, aborting\n", board_idx);
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");
+ pr_notice("Failed to set power state to D0\n");
}
irq = pdev->irq;
@@ -1432,13 +1427,13 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
/* alloc_etherdev ensures aligned and zeroed private structures */
dev = alloc_etherdev (sizeof (*tp));
if (!dev) {
- pr_err(PFX "ether device alloc failed, aborting\n");
+ pr_err("ether device alloc failed, aborting\n");
return -ENOMEM;
}
SET_NETDEV_DEV(dev, &pdev->dev);
if (pci_resource_len (pdev, 0) < tulip_tbl[chip_idx].io_size) {
- pr_err(PFX "%s: I/O region (0x%llx@0x%llx) too small, aborting\n",
+ pr_err("%s: I/O region (0x%llx@0x%llx) too small, aborting\n",
pci_name(pdev),
(unsigned long long)pci_resource_len (pdev, 0),
(unsigned long long)pci_resource_start (pdev, 0));
@@ -1483,7 +1478,8 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
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");
+ pr_info("%s: Enabled WOL support for AN983B\n",
+ __func__);
}
}
tp->pdev = pdev;
@@ -1879,7 +1875,7 @@ save_state:
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);
+ pr_err("pci_enable_wake failed (%d)\n", rc);
}
pci_set_power_state(pdev, pstate);
@@ -1905,12 +1901,12 @@ static int tulip_resume(struct pci_dev *pdev)
return 0;
if ((retval = pci_enable_device(pdev))) {
- pr_err(PFX "pci_enable_device failed in resume\n");
+ pr_err("pci_enable_device failed in resume\n");
return retval;
}
if ((retval = request_irq(dev->irq, tulip_interrupt, IRQF_SHARED, dev->name, dev))) {
- pr_err(PFX "request_irq failed in resume\n");
+ pr_err("request_irq failed in resume\n");
return retval;
}
diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c
index 74217dbf0143..9e63f406f72d 100644
--- a/drivers/net/tulip/uli526x.c
+++ b/drivers/net/tulip/uli526x.c
@@ -209,8 +209,7 @@ enum uli526x_CR6_bits {
/* Global variable declaration ----------------------------- */
static int __devinitdata printed_version;
static const char version[] __devinitconst =
- KERN_INFO DRV_NAME ": ULi M5261/M5263 net driver, version "
- DRV_VERSION " (" DRV_RELDATE ")\n";
+ "ULi M5261/M5263 net driver, version " DRV_VERSION " (" DRV_RELDATE ")";
static int uli526x_debug;
static unsigned char uli526x_media_mode = ULI526X_AUTO;
@@ -283,7 +282,7 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
ULI526X_DBUG(0, "uli526x_init_one()", 0);
if (!printed_version++)
- printk(version);
+ pr_info("%s\n", version);
/* Init network device */
dev = alloc_etherdev(sizeof(*db));
@@ -292,7 +291,7 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
SET_NETDEV_DEV(dev, &pdev->dev);
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
- pr_warning("32-bit PCI DMA not available\n");
+ pr_warn("32-bit PCI DMA not available\n");
err = -ENODEV;
goto err_out_free;
}
@@ -390,9 +389,9 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev,
if (err)
goto err_out_res;
- dev_info(&dev->dev, "ULi M%04lx at pci%s, %pM, irq %d\n",
- ent->driver_data >> 16, pci_name(pdev),
- dev->dev_addr, dev->irq);
+ netdev_info(dev, "ULi M%04lx at pci%s, %pM, irq %d\n",
+ ent->driver_data >> 16, pci_name(pdev),
+ dev->dev_addr, dev->irq);
pci_set_master(pdev);
@@ -524,7 +523,7 @@ static void uli526x_init(struct net_device *dev)
}
}
if(phy_tmp == 32)
- pr_warning("Can not find the phy address!!!");
+ pr_warn("Can not find the phy address!!!\n");
/* Parser SROM and media mode */
db->media_mode = uli526x_media_mode;
@@ -590,7 +589,7 @@ static netdev_tx_t uli526x_start_xmit(struct sk_buff *skb,
/* Too large packet check */
if (skb->len > MAX_PACKET_SIZE) {
- pr_err("big packet = %d\n", (u16)skb->len);
+ netdev_err(dev, "big packet = %d\n", (u16)skb->len);
dev_kfree_skb(skb);
return NETDEV_TX_OK;
}
@@ -600,7 +599,7 @@ static netdev_tx_t uli526x_start_xmit(struct sk_buff *skb,
/* No Tx resource check, it never happen nromally */
if (db->tx_packet_cnt >= TX_FREE_DESC_CNT) {
spin_unlock_irqrestore(&db->lock, flags);
- pr_err("No Tx resource %ld\n", db->tx_packet_cnt);
+ netdev_err(dev, "No Tx resource %ld\n", db->tx_packet_cnt);
return NETDEV_TX_BUSY;
}
@@ -667,15 +666,6 @@ static int uli526x_stop(struct net_device *dev)
/* free allocated rx buffer */
uli526x_free_rxbuffer(db);
-#if 0
- /* show statistic counter */
- printk(DRV_NAME ": FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n",
- db->tx_fifo_underrun, db->tx_excessive_collision,
- db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier,
- db->tx_jabber_timeout, db->reset_count, db->reset_cr8,
- db->reset_fatal, db->reset_TXtimeout);
-#endif
-
return 0;
}
@@ -755,7 +745,6 @@ static void uli526x_free_tx_pkt(struct net_device *dev,
txptr = db->tx_remove_ptr;
while(db->tx_packet_cnt) {
tdes0 = le32_to_cpu(txptr->tdes0);
- /* printk(DRV_NAME ": tdes0=%x\n", tdes0); */
if (tdes0 & 0x80000000)
break;
@@ -765,7 +754,6 @@ static void uli526x_free_tx_pkt(struct net_device *dev,
/* Transmit statistic counter */
if ( tdes0 != 0x7fffffff ) {
- /* printk(DRV_NAME ": tdes0=%x\n", tdes0); */
dev->stats.collisions += (tdes0 >> 3) & 0xf;
dev->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff;
if (tdes0 & TDES0_ERR_MASK) {
@@ -838,7 +826,6 @@ static void uli526x_rx_packet(struct net_device *dev, struct uli526x_board_info
/* error summary bit check */
if (rdes0 & 0x8000) {
/* This is a error packet */
- //printk(DRV_NAME ": rdes0: %lx\n", rdes0);
dev->stats.rx_errors++;
if (rdes0 & 1)
dev->stats.rx_fifo_errors++;
@@ -945,12 +932,12 @@ ULi_ethtool_gset(struct uli526x_board_info *db, struct ethtool_cmd *ecmd)
ecmd->transceiver = XCVR_EXTERNAL;
- ecmd->speed = 10;
+ ethtool_cmd_speed_set(ecmd, SPEED_10);
ecmd->duplex = DUPLEX_HALF;
if(db->op_mode==ULI526X_100MHF || db->op_mode==ULI526X_100MFD)
{
- ecmd->speed = 100;
+ ethtool_cmd_speed_set(ecmd, SPEED_100);
}
if(db->op_mode==ULI526X_10MFD || db->op_mode==ULI526X_100MFD)
{
@@ -958,7 +945,7 @@ ULi_ethtool_gset(struct uli526x_board_info *db, struct ethtool_cmd *ecmd)
}
if(db->link_failed)
{
- ecmd->speed = -1;
+ ethtool_cmd_speed_set(ecmd, -1);
ecmd->duplex = -1;
}
@@ -1024,7 +1011,6 @@ static void uli526x_timer(unsigned long data)
struct net_device *dev = (struct net_device *) data;
struct uli526x_board_info *db = netdev_priv(dev);
unsigned long flags;
- u8 TmpSpeed=10;
//ULI526X_DBUG(0, "uli526x_timer()", 0);
spin_lock_irqsave(&db->lock, flags);
@@ -1047,8 +1033,7 @@ static void uli526x_timer(unsigned long data)
if ( time_after(jiffies, dev_trans_start(dev) + ULI526X_TX_TIMEOUT) ) {
db->reset_TXtimeout++;
db->wait_reset = 1;
- printk( "%s: Tx timeout - resetting\n",
- dev->name);
+ netdev_err(dev, " Tx timeout - resetting\n");
}
}
@@ -1070,7 +1055,7 @@ static void uli526x_timer(unsigned long data)
/* Link Failed */
ULI526X_DBUG(0, "Link Failed", tmp_cr12);
netif_carrier_off(dev);
- pr_info("%s NIC Link is Down\n",dev->name);
+ netdev_info(dev, "NIC Link is Down\n");
db->link_failed = 1;
/* For Force 10/100M Half/Full mode: Enable Auto-Nego mode */
@@ -1096,18 +1081,13 @@ static void uli526x_timer(unsigned long data)
if(db->link_failed==0)
{
- if(db->op_mode==ULI526X_100MHF || db->op_mode==ULI526X_100MFD)
- {
- TmpSpeed = 100;
- }
- if(db->op_mode==ULI526X_10MFD || db->op_mode==ULI526X_100MFD)
- {
- pr_info("%s NIC Link is Up %d Mbps Full duplex\n",dev->name,TmpSpeed);
- }
- else
- {
- pr_info("%s NIC Link is Up %d Mbps Half duplex\n",dev->name,TmpSpeed);
- }
+ netdev_info(dev, "NIC Link is Up %d Mbps %s duplex\n",
+ (db->op_mode == ULI526X_100MHF ||
+ db->op_mode == ULI526X_100MFD)
+ ? 100 : 10,
+ (db->op_mode == ULI526X_10MFD ||
+ db->op_mode == ULI526X_100MFD)
+ ? "Full" : "Half");
netif_carrier_on(dev);
}
/* SHOW_MEDIA_TYPE(db->op_mode); */
@@ -1116,7 +1096,7 @@ static void uli526x_timer(unsigned long data)
{
if(db->init==1)
{
- pr_info("%s NIC Link is Down\n",dev->name);
+ netdev_info(dev, "NIC Link is Down\n");
netif_carrier_off(dev);
}
}
@@ -1242,7 +1222,7 @@ static int uli526x_resume(struct pci_dev *pdev)
err = pci_set_power_state(pdev, PCI_D0);
if (err) {
- dev_warn(&dev->dev, "Could not put device into D0\n");
+ netdev_warn(dev, "Could not put device into D0\n");
return err;
}
@@ -1443,7 +1423,7 @@ static void send_filter_frame(struct net_device *dev, int mc_cnt)
update_cr6(db->cr6_data, dev->base_addr);
dev->trans_start = jiffies;
} else
- pr_err("No Tx resource - Send_filter_frame!\n");
+ netdev_err(dev, "No Tx resource - Send_filter_frame!\n");
}
@@ -1540,7 +1520,6 @@ static u8 uli526x_sense_speed(struct uli526x_board_info * db)
else
phy_mode = 0x1000;
- /* printk(DRV_NAME ": Phy_mode %x ",phy_mode); */
switch (phy_mode) {
case 0x1000: db->op_mode = ULI526X_10MHF; break;
case 0x2000: db->op_mode = ULI526X_10MFD; break;
@@ -1829,7 +1808,7 @@ MODULE_PARM_DESC(mode, "ULi M5261/M5263: Bit 0: 10/100Mbps, bit 2: duplex, bit 8
static int __init uli526x_init_module(void)
{
- printk(version);
+ pr_info("%s\n", version);
printed_version = 1;
ULI526X_DBUG(0, "init_module() ", debug);
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index f0b231035dee..862eadf07191 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -44,6 +44,8 @@
* Wake-On-LAN
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#define DRV_NAME "winbond-840"
#define DRV_VERSION "1.01-e"
#define DRV_RELDATE "Sep-11-2006"
@@ -139,7 +141,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
/* These identify the driver base version and may not be removed. */
static const char version[] __initconst =
- KERN_INFO DRV_NAME ".c:v" DRV_VERSION " (2.4 port) "
+ "v" DRV_VERSION " (2.4 port) "
DRV_RELDATE " Donald Becker <becker@scyld.com>\n"
" http://www.scyld.com/network/drivers.html\n";
@@ -375,8 +377,8 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
irq = pdev->irq;
if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
- pr_warning("Winbond-840: Device %s disabled due to DMA limitations\n",
- pci_name(pdev));
+ pr_warn("Device %s disabled due to DMA limitations\n",
+ pci_name(pdev));
return -EIO;
}
dev = alloc_etherdev(sizeof(*np));
@@ -643,8 +645,7 @@ static int netdev_open(struct net_device *dev)
goto out_err;
if (debug > 1)
- printk(KERN_DEBUG "%s: w89c840_open() irq %d\n",
- dev->name, dev->irq);
+ netdev_dbg(dev, "w89c840_open() irq %d\n", dev->irq);
if((i=alloc_ringdesc(dev)))
goto out_err;
@@ -656,7 +657,7 @@ static int netdev_open(struct net_device *dev)
netif_start_queue(dev);
if (debug > 2)
- printk(KERN_DEBUG "%s: Done netdev_open()\n", dev->name);
+ netdev_dbg(dev, "Done netdev_open()\n");
/* Set the timer to check for link beat. */
init_timer(&np->timer);
@@ -785,9 +786,9 @@ static void netdev_timer(unsigned long data)
void __iomem *ioaddr = np->base_addr;
if (debug > 2)
- printk(KERN_DEBUG "%s: Media selection timer tick, status %08x config %08x\n",
- dev->name, ioread32(ioaddr + IntrStatus),
- ioread32(ioaddr + NetworkConfig));
+ netdev_dbg(dev, "Media selection timer tick, status %08x config %08x\n",
+ ioread32(ioaddr + IntrStatus),
+ ioread32(ioaddr + NetworkConfig));
spin_lock_irq(&np->lock);
update_csr6(dev, update_link(dev));
spin_unlock_irq(&np->lock);
@@ -1054,8 +1055,8 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
spin_unlock_irq(&np->lock);
if (debug > 4) {
- printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d\n",
- dev->name, np->cur_tx, entry);
+ netdev_dbg(dev, "Transmit frame #%d queued in slot %d\n",
+ np->cur_tx, entry);
}
return NETDEV_TX_OK;
}
@@ -1072,8 +1073,8 @@ static void netdev_tx_done(struct net_device *dev)
if (tx_status & 0x8000) { /* There was an error, log it. */
#ifndef final_version
if (debug > 1)
- printk(KERN_DEBUG "%s: Transmit error, Tx status %08x\n",
- dev->name, tx_status);
+ netdev_dbg(dev, "Transmit error, Tx status %08x\n",
+ tx_status);
#endif
np->stats.tx_errors++;
if (tx_status & 0x0104) np->stats.tx_aborted_errors++;
@@ -1085,8 +1086,8 @@ static void netdev_tx_done(struct net_device *dev)
} else {
#ifndef final_version
if (debug > 3)
- printk(KERN_DEBUG "%s: Transmit slot %d ok, Tx status %08x\n",
- dev->name, entry, tx_status);
+ netdev_dbg(dev, "Transmit slot %d ok, Tx status %08x\n",
+ entry, tx_status);
#endif
np->stats.tx_bytes += np->tx_skbuff[entry]->len;
np->stats.collisions += (tx_status >> 3) & 15;
@@ -1129,8 +1130,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
iowrite32(intr_status & 0x001ffff, ioaddr + IntrStatus);
if (debug > 4)
- printk(KERN_DEBUG "%s: Interrupt, status %04x\n",
- dev->name, intr_status);
+ netdev_dbg(dev, "Interrupt, status %04x\n", intr_status);
if ((intr_status & (NormalIntr|AbnormalIntr)) == 0)
break;
@@ -1171,8 +1171,8 @@ static irqreturn_t intr_handler(int irq, void *dev_instance)
} while (1);
if (debug > 3)
- printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x\n",
- dev->name, ioread32(ioaddr + IntrStatus));
+ netdev_dbg(dev, "exiting interrupt, status=%#4.4x\n",
+ ioread32(ioaddr + IntrStatus));
return IRQ_RETVAL(handled);
}
@@ -1185,8 +1185,8 @@ static int netdev_rx(struct net_device *dev)
int work_limit = np->dirty_rx + RX_RING_SIZE - np->cur_rx;
if (debug > 4) {
- printk(KERN_DEBUG " In netdev_rx(), entry %d status %04x\n",
- entry, np->rx_ring[entry].status);
+ netdev_dbg(dev, " In netdev_rx(), entry %d status %04x\n",
+ entry, np->rx_ring[entry].status);
}
/* If EOP is set on the next entry, it's a new packet. Send it up. */
@@ -1195,8 +1195,8 @@ static int netdev_rx(struct net_device *dev)
s32 status = desc->status;
if (debug > 4)
- printk(KERN_DEBUG " netdev_rx() status was %08x\n",
- status);
+ netdev_dbg(dev, " netdev_rx() status was %08x\n",
+ status);
if (status < 0)
break;
if ((status & 0x38008300) != 0x0300) {
@@ -1211,8 +1211,8 @@ static int netdev_rx(struct net_device *dev)
} else if (status & 0x8000) {
/* There was a fatal error. */
if (debug > 2)
- printk(KERN_DEBUG "%s: Receive error, Rx status %08x\n",
- dev->name, status);
+ netdev_dbg(dev, "Receive error, Rx status %08x\n",
+ status);
np->stats.rx_errors++; /* end of a packet.*/
if (status & 0x0890) np->stats.rx_length_errors++;
if (status & 0x004C) np->stats.rx_frame_errors++;
@@ -1225,8 +1225,8 @@ static int netdev_rx(struct net_device *dev)
#ifndef final_version
if (debug > 4)
- printk(KERN_DEBUG " netdev_rx() normal Rx pkt length %d status %x\n",
- pkt_len, status);
+ netdev_dbg(dev, " netdev_rx() normal Rx pkt length %d status %x\n",
+ pkt_len, status);
#endif
/* Check if the packet is long enough to accept without copying
to a minimally-sized skbuff. */
@@ -1251,10 +1251,10 @@ static int netdev_rx(struct net_device *dev)
#ifndef final_version /* Remove after testing. */
/* You will want this info for the initial debug. */
if (debug > 5)
- printk(KERN_DEBUG " Rx data %pM %pM %02x%02x %pI4\n",
- &skb->data[0], &skb->data[6],
- skb->data[12], skb->data[13],
- &skb->data[14]);
+ netdev_dbg(dev, " Rx data %pM %pM %02x%02x %pI4\n",
+ &skb->data[0], &skb->data[6],
+ skb->data[12], skb->data[13],
+ &skb->data[14]);
#endif
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
@@ -1292,8 +1292,7 @@ static void netdev_error(struct net_device *dev, int intr_status)
void __iomem *ioaddr = np->base_addr;
if (debug > 2)
- printk(KERN_DEBUG "%s: Abnormal event, %08x\n",
- dev->name, intr_status);
+ netdev_dbg(dev, "Abnormal event, %08x\n", intr_status);
if (intr_status == 0xffffffff)
return;
spin_lock(&np->lock);
@@ -1313,8 +1312,7 @@ static void netdev_error(struct net_device *dev, int intr_status)
new = 127; /* load full packet before starting */
new = (np->csr6 & ~(0x7F << 14)) | (new<<14);
#endif
- printk(KERN_DEBUG "%s: Tx underflow, new csr6 %08x\n",
- dev->name, new);
+ netdev_dbg(dev, "Tx underflow, new csr6 %08x\n", new);
update_csr6(dev, new);
}
if (intr_status & RxDied) { /* Missed a Rx frame. */
@@ -1487,13 +1485,12 @@ static int netdev_close(struct net_device *dev)
netif_stop_queue(dev);
if (debug > 1) {
- printk(KERN_DEBUG "%s: Shutting down ethercard, status was %08x Config %08x\n",
- dev->name, ioread32(ioaddr + IntrStatus),
- ioread32(ioaddr + NetworkConfig));
- printk(KERN_DEBUG "%s: Queue pointers were Tx %d / %d, Rx %d / %d\n",
- dev->name,
- np->cur_tx, np->dirty_tx,
- np->cur_rx, np->dirty_rx);
+ netdev_dbg(dev, "Shutting down ethercard, status was %08x Config %08x\n",
+ ioread32(ioaddr + IntrStatus),
+ ioread32(ioaddr + NetworkConfig));
+ netdev_dbg(dev, "Queue pointers were Tx %d / %d, Rx %d / %d\n",
+ np->cur_tx, np->dirty_tx,
+ np->cur_rx, np->dirty_rx);
}
/* Stop the chip's Tx and Rx processes. */
diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c
index 5a73752be2ca..988b8eb24d37 100644
--- a/drivers/net/tulip/xircom_cb.c
+++ b/drivers/net/tulip/xircom_cb.c
@@ -37,15 +37,6 @@
#include <asm/irq.h>
#endif
-#ifdef DEBUG
-#define enter(x) printk("Enter: %s, %s line %i\n",x,__FILE__,__LINE__)
-#define leave(x) printk("Leave: %s, %s line %i\n",x,__FILE__,__LINE__)
-#else
-#define enter(x) do {} while (0)
-#define leave(x) do {} while (0)
-#endif
-
-
MODULE_DESCRIPTION("Xircom Cardbus ethernet driver");
MODULE_AUTHOR("Arjan van de Ven <arjanv@redhat.com>");
MODULE_LICENSE("GPL");
@@ -161,7 +152,7 @@ static struct pci_driver xircom_ops = {
};
-#ifdef DEBUG
+#if defined DEBUG && DEBUG > 1
static void print_binary(unsigned int number)
{
int i,i2;
@@ -176,7 +167,7 @@ static void print_binary(unsigned int number)
if ((i&3)==0)
buffer[i2++]=' ';
}
- printk("%s\n",buffer);
+ pr_debug("%s\n",buffer);
}
#endif
@@ -205,7 +196,6 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
struct xircom_private *private;
unsigned long flags;
unsigned short tmp16;
- enter("xircom_probe");
/* First do the PCI initialisation */
@@ -272,8 +262,8 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
goto reg_fail;
}
- dev_info(&dev->dev, "Xircom cardbus revision %i at irq %i\n",
- pdev->revision, pdev->irq);
+ netdev_info(dev, "Xircom cardbus revision %i at irq %i\n",
+ pdev->revision, pdev->irq);
/* start the transmitter to get a heartbeat */
/* TODO: send 2 dummy packets here */
transceiver_voodoo(private);
@@ -285,7 +275,6 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_
trigger_receive(private);
- leave("xircom_probe");
return 0;
reg_fail:
@@ -310,7 +299,6 @@ static void __devexit xircom_remove(struct pci_dev *pdev)
struct net_device *dev = pci_get_drvdata(pdev);
struct xircom_private *card = netdev_priv(dev);
- enter("xircom_remove");
pci_free_consistent(pdev,8192,card->rx_buffer,card->rx_dma_handle);
pci_free_consistent(pdev,8192,card->tx_buffer,card->tx_dma_handle);
@@ -318,7 +306,6 @@ static void __devexit xircom_remove(struct pci_dev *pdev)
unregister_netdev(dev);
free_netdev(dev);
pci_set_drvdata(pdev, NULL);
- leave("xircom_remove");
}
static irqreturn_t xircom_interrupt(int irq, void *dev_instance)
@@ -328,17 +315,15 @@ static irqreturn_t xircom_interrupt(int irq, void *dev_instance)
unsigned int status;
int i;
- enter("xircom_interrupt\n");
-
spin_lock(&card->lock);
status = inl(card->io_port+CSR5);
-#ifdef DEBUG
+#if defined DEBUG && DEBUG > 1
print_binary(status);
- printk("tx status 0x%08x 0x%08x\n",
- card->tx_buffer[0], card->tx_buffer[4]);
- printk("rx status 0x%08x 0x%08x\n",
- card->rx_buffer[0], card->rx_buffer[4]);
+ pr_debug("tx status 0x%08x 0x%08x\n",
+ card->tx_buffer[0], card->tx_buffer[4]);
+ pr_debug("rx status 0x%08x 0x%08x\n",
+ card->rx_buffer[0], card->rx_buffer[4]);
#endif
/* Handle shared irq and hotplug */
if (status == 0 || status == 0xffffffff) {
@@ -348,9 +333,9 @@ static irqreturn_t xircom_interrupt(int irq, void *dev_instance)
if (link_status_changed(card)) {
int newlink;
- printk(KERN_DEBUG "xircom_cb: Link status has changed\n");
+ netdev_dbg(dev, "Link status has changed\n");
newlink = link_status(card);
- dev_info(&dev->dev, "Link is %i mbit\n", newlink);
+ netdev_info(dev, "Link is %d mbit\n", newlink);
if (newlink)
netif_carrier_on(dev);
else
@@ -369,9 +354,7 @@ static irqreturn_t xircom_interrupt(int irq, void *dev_instance)
for (i=0;i<NUMDESCRIPTORS;i++)
investigate_read_descriptor(dev,card,i,bufferoffsets[i]);
-
spin_unlock(&card->lock);
- leave("xircom_interrupt");
return IRQ_HANDLED;
}
@@ -382,7 +365,6 @@ static netdev_tx_t xircom_start_xmit(struct sk_buff *skb,
unsigned long flags;
int nextdescriptor;
int desc;
- enter("xircom_start_xmit");
card = netdev_priv(dev);
spin_lock_irqsave(&card->lock,flags);
@@ -424,13 +406,10 @@ static netdev_tx_t xircom_start_xmit(struct sk_buff *skb,
netif_stop_queue(dev);
}
card->transmit_used = nextdescriptor;
- leave("xircom-start_xmit - sent");
spin_unlock_irqrestore(&card->lock,flags);
return NETDEV_TX_OK;
}
-
-
/* Uh oh... no free descriptor... drop the packet */
netif_stop_queue(dev);
spin_unlock_irqrestore(&card->lock,flags);
@@ -446,18 +425,16 @@ static int xircom_open(struct net_device *dev)
{
struct xircom_private *xp = netdev_priv(dev);
int retval;
- enter("xircom_open");
- pr_info("xircom cardbus adaptor found, registering as %s, using irq %i\n",
- dev->name, dev->irq);
+
+ netdev_info(dev, "xircom cardbus adaptor found, using irq %i\n",
+ dev->irq);
retval = request_irq(dev->irq, xircom_interrupt, IRQF_SHARED, dev->name, dev);
- if (retval) {
- leave("xircom_open - No IRQ");
+ if (retval)
return retval;
- }
xircom_up(xp);
xp->open = 1;
- leave("xircom_open");
+
return 0;
}
@@ -466,7 +443,6 @@ static int xircom_close(struct net_device *dev)
struct xircom_private *card;
unsigned long flags;
- enter("xircom_close");
card = netdev_priv(dev);
netif_stop_queue(dev); /* we don't want new packets */
@@ -486,8 +462,6 @@ static int xircom_close(struct net_device *dev)
card->open = 0;
free_irq(dev->irq,dev);
- leave("xircom_close");
-
return 0;
}
@@ -507,8 +481,6 @@ static void initialize_card(struct xircom_private *card)
{
unsigned int val;
unsigned long flags;
- enter("initialize_card");
-
spin_lock_irqsave(&card->lock, flags);
@@ -534,8 +506,6 @@ static void initialize_card(struct xircom_private *card)
deactivate_transmitter(card);
spin_unlock_irqrestore(&card->lock, flags);
-
- leave("initialize_card");
}
/*
@@ -547,12 +517,9 @@ ignored; I chose zero.
static void trigger_transmit(struct xircom_private *card)
{
unsigned int val;
- enter("trigger_transmit");
val = 0;
outl(val, card->io_port + CSR1);
-
- leave("trigger_transmit");
}
/*
@@ -565,12 +532,9 @@ ignored; I chose zero.
static void trigger_receive(struct xircom_private *card)
{
unsigned int val;
- enter("trigger_receive");
val = 0;
outl(val, card->io_port + CSR2);
-
- leave("trigger_receive");
}
/*
@@ -581,8 +545,6 @@ static void setup_descriptors(struct xircom_private *card)
{
u32 address;
int i;
- enter("setup_descriptors");
-
BUG_ON(card->rx_buffer == NULL);
BUG_ON(card->tx_buffer == NULL);
@@ -636,8 +598,6 @@ static void setup_descriptors(struct xircom_private *card)
/* wite the transmit descriptor ring to the card */
address = card->tx_dma_handle;
outl(address, card->io_port + CSR4); /* xmit descr list address */
-
- leave("setup_descriptors");
}
/*
@@ -647,13 +607,10 @@ valid by setting the address in the card to 0x00.
static void remove_descriptors(struct xircom_private *card)
{
unsigned int val;
- enter("remove_descriptors");
val = 0;
outl(val, card->io_port + CSR3); /* Receive descriptor address */
outl(val, card->io_port + CSR4); /* Send descriptor address */
-
- leave("remove_descriptors");
}
/*
@@ -665,21 +622,17 @@ This function also clears the status-bit.
static int link_status_changed(struct xircom_private *card)
{
unsigned int val;
- enter("link_status_changed");
val = inl(card->io_port + CSR5); /* Status register */
- if ((val & (1 << 27)) == 0) { /* no change */
- leave("link_status_changed - nochange");
+ if ((val & (1 << 27)) == 0) /* no change */
return 0;
- }
/* clear the event by writing a 1 to the bit in the
status register. */
val = (1 << 27);
outl(val, card->io_port + CSR5);
- leave("link_status_changed - changed");
return 1;
}
@@ -691,16 +644,12 @@ in a non-stopped state.
static int transmit_active(struct xircom_private *card)
{
unsigned int val;
- enter("transmit_active");
val = inl(card->io_port + CSR5); /* Status register */
- if ((val & (7 << 20)) == 0) { /* transmitter disabled */
- leave("transmit_active - inactive");
+ if ((val & (7 << 20)) == 0) /* transmitter disabled */
return 0;
- }
- leave("transmit_active - active");
return 1;
}
@@ -711,17 +660,12 @@ in a non-stopped state.
static int receive_active(struct xircom_private *card)
{
unsigned int val;
- enter("receive_active");
-
val = inl(card->io_port + CSR5); /* Status register */
- if ((val & (7 << 17)) == 0) { /* receiver disabled */
- leave("receive_active - inactive");
+ if ((val & (7 << 17)) == 0) /* receiver disabled */
return 0;
- }
- leave("receive_active - active");
return 1;
}
@@ -739,8 +683,6 @@ static void activate_receiver(struct xircom_private *card)
{
unsigned int val;
int counter;
- enter("activate_receiver");
-
val = inl(card->io_port + CSR6); /* Operation mode */
@@ -761,7 +703,7 @@ static void activate_receiver(struct xircom_private *card)
udelay(50);
counter--;
if (counter <= 0)
- pr_err("Receiver failed to deactivate\n");
+ netdev_err(card->dev, "Receiver failed to deactivate\n");
}
/* enable the receiver */
@@ -778,10 +720,9 @@ static void activate_receiver(struct xircom_private *card)
udelay(50);
counter--;
if (counter <= 0)
- pr_err("Receiver failed to re-activate\n");
+ netdev_err(card->dev,
+ "Receiver failed to re-activate\n");
}
-
- leave("activate_receiver");
}
/*
@@ -795,7 +736,6 @@ static void deactivate_receiver(struct xircom_private *card)
{
unsigned int val;
int counter;
- enter("deactivate_receiver");
val = inl(card->io_port + CSR6); /* Operation mode */
val = val & ~2; /* disable the receiver */
@@ -809,11 +749,8 @@ static void deactivate_receiver(struct xircom_private *card)
udelay(50);
counter--;
if (counter <= 0)
- pr_err("Receiver failed to deactivate\n");
+ netdev_err(card->dev, "Receiver failed to deactivate\n");
}
-
-
- leave("deactivate_receiver");
}
@@ -831,8 +768,6 @@ static void activate_transmitter(struct xircom_private *card)
{
unsigned int val;
int counter;
- enter("activate_transmitter");
-
val = inl(card->io_port + CSR6); /* Operation mode */
@@ -852,7 +787,8 @@ static void activate_transmitter(struct xircom_private *card)
udelay(50);
counter--;
if (counter <= 0)
- pr_err("Transmitter failed to deactivate\n");
+ netdev_err(card->dev,
+ "Transmitter failed to deactivate\n");
}
/* enable the transmitter */
@@ -869,10 +805,9 @@ static void activate_transmitter(struct xircom_private *card)
udelay(50);
counter--;
if (counter <= 0)
- pr_err("Transmitter failed to re-activate\n");
+ netdev_err(card->dev,
+ "Transmitter failed to re-activate\n");
}
-
- leave("activate_transmitter");
}
/*
@@ -886,7 +821,6 @@ static void deactivate_transmitter(struct xircom_private *card)
{
unsigned int val;
int counter;
- enter("deactivate_transmitter");
val = inl(card->io_port + CSR6); /* Operation mode */
val = val & ~2; /* disable the transmitter */
@@ -900,11 +834,9 @@ static void deactivate_transmitter(struct xircom_private *card)
udelay(50);
counter--;
if (counter <= 0)
- pr_err("Transmitter failed to deactivate\n");
+ netdev_err(card->dev,
+ "Transmitter failed to deactivate\n");
}
-
-
- leave("deactivate_transmitter");
}
@@ -916,13 +848,10 @@ must be called with the lock held and interrupts disabled.
static void enable_transmit_interrupt(struct xircom_private *card)
{
unsigned int val;
- enter("enable_transmit_interrupt");
val = inl(card->io_port + CSR7); /* Interrupt enable register */
val |= 1; /* enable the transmit interrupt */
outl(val, card->io_port + CSR7);
-
- leave("enable_transmit_interrupt");
}
@@ -934,13 +863,10 @@ must be called with the lock held and interrupts disabled.
static void enable_receive_interrupt(struct xircom_private *card)
{
unsigned int val;
- enter("enable_receive_interrupt");
val = inl(card->io_port + CSR7); /* Interrupt enable register */
val = val | (1 << 6); /* enable the receive interrupt */
outl(val, card->io_port + CSR7);
-
- leave("enable_receive_interrupt");
}
/*
@@ -951,13 +877,10 @@ must be called with the lock held and interrupts disabled.
static void enable_link_interrupt(struct xircom_private *card)
{
unsigned int val;
- enter("enable_link_interrupt");
val = inl(card->io_port + CSR7); /* Interrupt enable register */
val = val | (1 << 27); /* enable the link status chage interrupt */
outl(val, card->io_port + CSR7);
-
- leave("enable_link_interrupt");
}
@@ -970,12 +893,9 @@ must be called with the lock held and interrupts disabled.
static void disable_all_interrupts(struct xircom_private *card)
{
unsigned int val;
- enter("enable_all_interrupts");
val = 0; /* disable all interrupts */
outl(val, card->io_port + CSR7);
-
- leave("disable_all_interrupts");
}
/*
@@ -986,7 +906,6 @@ must be called with the lock held and interrupts disabled.
static void enable_common_interrupts(struct xircom_private *card)
{
unsigned int val;
- enter("enable_link_interrupt");
val = inl(card->io_port + CSR7); /* Interrupt enable register */
val |= (1<<16); /* Normal Interrupt Summary */
@@ -998,8 +917,6 @@ static void enable_common_interrupts(struct xircom_private *card)
val |= (1<<2); /* Transmit Buffer Unavailable */
val |= (1<<1); /* Transmit Process Stopped */
outl(val, card->io_port + CSR7);
-
- leave("enable_link_interrupt");
}
/*
@@ -1010,13 +927,11 @@ must be called with the lock held and interrupts disabled.
static int enable_promisc(struct xircom_private *card)
{
unsigned int val;
- enter("enable_promisc");
val = inl(card->io_port + CSR6);
val = val | (1 << 6);
outl(val, card->io_port + CSR6);
- leave("enable_promisc");
return 1;
}
@@ -1031,7 +946,6 @@ Must be called in locked state with interrupts disabled
static int link_status(struct xircom_private *card)
{
unsigned int val;
- enter("link_status");
val = inb(card->io_port + CSR12);
@@ -1042,7 +956,6 @@ static int link_status(struct xircom_private *card)
/* If we get here -> no link at all */
- leave("link_status");
return 0;
}
@@ -1061,8 +974,6 @@ static void read_mac_address(struct xircom_private *card)
unsigned long flags;
int i;
- enter("read_mac_address");
-
spin_lock_irqsave(&card->lock, flags);
outl(1 << 12, card->io_port + CSR9); /* enable boot rom access */
@@ -1090,7 +1001,6 @@ static void read_mac_address(struct xircom_private *card)
}
spin_unlock_irqrestore(&card->lock, flags);
pr_debug(" %pM\n", card->dev->dev_addr);
- leave("read_mac_address");
}
@@ -1103,8 +1013,6 @@ static void transceiver_voodoo(struct xircom_private *card)
{
unsigned long flags;
- enter("transceiver_voodoo");
-
/* disable all powermanagement */
pci_write_config_dword(card->pdev, PCI_POWERMGMT, 0x0000);
@@ -1122,7 +1030,6 @@ static void transceiver_voodoo(struct xircom_private *card)
spin_unlock_irqrestore(&card->lock, flags);
netif_start_queue(card->dev);
- leave("transceiver_voodoo");
}
@@ -1131,8 +1038,6 @@ static void xircom_up(struct xircom_private *card)
unsigned long flags;
int i;
- enter("xircom_up");
-
/* disable all powermanagement */
pci_write_config_dword(card->pdev, PCI_POWERMGMT, 0x0000);
@@ -1156,87 +1061,84 @@ static void xircom_up(struct xircom_private *card)
trigger_receive(card);
trigger_transmit(card);
netif_start_queue(card->dev);
- leave("xircom_up");
}
/* Bufferoffset is in BYTES */
-static void investigate_read_descriptor(struct net_device *dev,struct xircom_private *card, int descnr, unsigned int bufferoffset)
+static void
+investigate_read_descriptor(struct net_device *dev, struct xircom_private *card,
+ int descnr, unsigned int bufferoffset)
{
- int status;
-
- enter("investigate_read_descriptor");
- status = le32_to_cpu(card->rx_buffer[4*descnr]);
+ int status;
- if ((status > 0)) { /* packet received */
+ status = le32_to_cpu(card->rx_buffer[4*descnr]);
- /* TODO: discard error packets */
+ if (status > 0) { /* packet received */
- short pkt_len = ((status >> 16) & 0x7ff) - 4; /* minus 4, we don't want the CRC */
- struct sk_buff *skb;
+ /* TODO: discard error packets */
- if (pkt_len > 1518) {
- pr_err("Packet length %i is bogus\n", pkt_len);
- pkt_len = 1518;
- }
+ short pkt_len = ((status >> 16) & 0x7ff) - 4;
+ /* minus 4, we don't want the CRC */
+ struct sk_buff *skb;
- skb = dev_alloc_skb(pkt_len + 2);
- if (skb == NULL) {
- dev->stats.rx_dropped++;
- goto out;
- }
- skb_reserve(skb, 2);
- skb_copy_to_linear_data(skb, (unsigned char*)&card->rx_buffer[bufferoffset / 4], pkt_len);
- skb_put(skb, pkt_len);
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- dev->stats.rx_packets++;
- dev->stats.rx_bytes += pkt_len;
-
- out:
- /* give the buffer back to the card */
- card->rx_buffer[4*descnr] = cpu_to_le32(0x80000000);
- trigger_receive(card);
+ if (pkt_len > 1518) {
+ netdev_err(dev, "Packet length %i is bogus\n", pkt_len);
+ pkt_len = 1518;
}
- leave("investigate_read_descriptor");
-
+ skb = dev_alloc_skb(pkt_len + 2);
+ if (skb == NULL) {
+ dev->stats.rx_dropped++;
+ goto out;
+ }
+ skb_reserve(skb, 2);
+ skb_copy_to_linear_data(skb,
+ &card->rx_buffer[bufferoffset / 4],
+ pkt_len);
+ skb_put(skb, pkt_len);
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
+
+out:
+ /* give the buffer back to the card */
+ card->rx_buffer[4*descnr] = cpu_to_le32(0x80000000);
+ trigger_receive(card);
+ }
}
/* Bufferoffset is in BYTES */
-static void investigate_write_descriptor(struct net_device *dev, struct xircom_private *card, int descnr, unsigned int bufferoffset)
+static void
+investigate_write_descriptor(struct net_device *dev,
+ struct xircom_private *card,
+ int descnr, unsigned int bufferoffset)
{
- int status;
-
- enter("investigate_write_descriptor");
+ int status;
- status = le32_to_cpu(card->tx_buffer[4*descnr]);
+ status = le32_to_cpu(card->tx_buffer[4*descnr]);
#if 0
- if (status & 0x8000) { /* Major error */
- pr_err("Major transmit error status %x\n", status);
- card->tx_buffer[4*descnr] = 0;
- netif_wake_queue (dev);
- }
+ if (status & 0x8000) { /* Major error */
+ pr_err("Major transmit error status %x\n", status);
+ card->tx_buffer[4*descnr] = 0;
+ netif_wake_queue (dev);
+ }
#endif
- if (status > 0) { /* bit 31 is 0 when done */
- if (card->tx_skb[descnr]!=NULL) {
- dev->stats.tx_bytes += card->tx_skb[descnr]->len;
- dev_kfree_skb_irq(card->tx_skb[descnr]);
- }
- card->tx_skb[descnr] = NULL;
- /* Bit 8 in the status field is 1 if there was a collision */
- if (status&(1<<8))
- dev->stats.collisions++;
- card->tx_buffer[4*descnr] = 0; /* descriptor is free again */
- netif_wake_queue (dev);
- dev->stats.tx_packets++;
+ if (status > 0) { /* bit 31 is 0 when done */
+ if (card->tx_skb[descnr]!=NULL) {
+ dev->stats.tx_bytes += card->tx_skb[descnr]->len;
+ dev_kfree_skb_irq(card->tx_skb[descnr]);
}
-
- leave("investigate_write_descriptor");
-
+ card->tx_skb[descnr] = NULL;
+ /* Bit 8 in the status field is 1 if there was a collision */
+ if (status & (1 << 8))
+ dev->stats.collisions++;
+ card->tx_buffer[4*descnr] = 0; /* descriptor is free again */
+ netif_wake_queue (dev);
+ dev->stats.tx_packets++;
+ }
}
-
static int __init xircom_init(void)
{
return pci_register_driver(&xircom_ops);
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index f5e9ac00a07b..74e94054ab1a 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -123,6 +123,9 @@ struct tun_struct {
gid_t group;
struct net_device *dev;
+ u32 set_features;
+#define TUN_USER_FEATURES (NETIF_F_HW_CSUM|NETIF_F_TSO_ECN|NETIF_F_TSO| \
+ NETIF_F_TSO6|NETIF_F_UFO)
struct fasync_struct *fasync;
struct tap_filter txflt;
@@ -451,12 +454,20 @@ tun_net_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}
+static u32 tun_net_fix_features(struct net_device *dev, u32 features)
+{
+ struct tun_struct *tun = netdev_priv(dev);
+
+ return (features & tun->set_features) | (features & ~TUN_USER_FEATURES);
+}
+
static const struct net_device_ops tun_netdev_ops = {
.ndo_uninit = tun_net_uninit,
.ndo_open = tun_net_open,
.ndo_stop = tun_net_close,
.ndo_start_xmit = tun_net_xmit,
.ndo_change_mtu = tun_net_change_mtu,
+ .ndo_fix_features = tun_net_fix_features,
};
static const struct net_device_ops tap_netdev_ops = {
@@ -465,6 +476,7 @@ static const struct net_device_ops tap_netdev_ops = {
.ndo_stop = tun_net_close,
.ndo_start_xmit = tun_net_xmit,
.ndo_change_mtu = tun_net_change_mtu,
+ .ndo_fix_features = tun_net_fix_features,
.ndo_set_multicast_list = tun_net_mclist,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
@@ -628,8 +640,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun,
kfree_skb(skb);
return -EINVAL;
}
- } else if (tun->flags & TUN_NOCHECKSUM)
- skb->ip_summed = CHECKSUM_UNNECESSARY;
+ }
switch (tun->flags & TUN_TYPE_MASK) {
case TUN_TUN_DEV:
@@ -1088,11 +1099,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
tun_net_init(dev);
- if (strchr(dev->name, '%')) {
- err = dev_alloc_name(dev, dev->name);
- if (err < 0)
- goto err_free_sk;
- }
+ dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST |
+ TUN_USER_FEATURES;
+ dev->features = dev->hw_features;
err = register_netdevice(tun->dev);
if (err < 0)
@@ -1158,18 +1167,12 @@ static int tun_get_iff(struct net *net, struct tun_struct *tun,
/* This is like a cut-down ethtool ops, except done via tun fd so no
* privs required. */
-static int set_offload(struct net_device *dev, unsigned long arg)
+static int set_offload(struct tun_struct *tun, unsigned long arg)
{
- u32 old_features, features;
-
- old_features = dev->features;
- /* Unset features, set them as we chew on the arg. */
- features = (old_features & ~(NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST
- |NETIF_F_TSO_ECN|NETIF_F_TSO|NETIF_F_TSO6
- |NETIF_F_UFO));
+ u32 features = 0;
if (arg & TUN_F_CSUM) {
- features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
+ features |= NETIF_F_HW_CSUM;
arg &= ~TUN_F_CSUM;
if (arg & (TUN_F_TSO4|TUN_F_TSO6)) {
@@ -1195,9 +1198,8 @@ static int set_offload(struct net_device *dev, unsigned long arg)
if (arg)
return -EINVAL;
- dev->features = features;
- if (old_features != dev->features)
- netdev_features_change(dev);
+ tun->set_features = features;
+ netdev_update_features(tun->dev);
return 0;
}
@@ -1262,12 +1264,9 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
case TUNSETNOCSUM:
/* Disable/Enable checksum */
- if (arg)
- tun->flags |= TUN_NOCHECKSUM;
- else
- tun->flags &= ~TUN_NOCHECKSUM;
- tun_debug(KERN_INFO, tun, "checksum %s\n",
+ /* [unimplemented] */
+ tun_debug(KERN_INFO, tun, "ignored: set checksum %s\n",
arg ? "disabled" : "enabled");
break;
@@ -1316,7 +1315,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
break;
#endif
case TUNSETOFFLOAD:
- ret = set_offload(tun->dev, arg);
+ ret = set_offload(tun, arg);
break;
case TUNSETTXFILTER:
@@ -1548,7 +1547,7 @@ static int tun_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
cmd->supported = 0;
cmd->advertising = 0;
- cmd->speed = SPEED_10;
+ ethtool_cmd_speed_set(cmd, SPEED_10);
cmd->duplex = DUPLEX_FULL;
cmd->port = PORT_TP;
cmd->phy_address = 0;
@@ -1595,30 +1594,12 @@ static void tun_set_msglevel(struct net_device *dev, u32 value)
#endif
}
-static u32 tun_get_rx_csum(struct net_device *dev)
-{
- struct tun_struct *tun = netdev_priv(dev);
- return (tun->flags & TUN_NOCHECKSUM) == 0;
-}
-
-static int tun_set_rx_csum(struct net_device *dev, u32 data)
-{
- struct tun_struct *tun = netdev_priv(dev);
- if (data)
- tun->flags &= ~TUN_NOCHECKSUM;
- else
- tun->flags |= TUN_NOCHECKSUM;
- return 0;
-}
-
static const struct ethtool_ops tun_ethtool_ops = {
.get_settings = tun_get_settings,
.get_drvinfo = tun_get_drvinfo,
.get_msglevel = tun_get_msglevel,
.set_msglevel = tun_set_msglevel,
.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 82653cb07857..3de4283344e9 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -1050,7 +1050,7 @@ typhoon_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
/* need to get stats to make these link speed/duplex valid */
typhoon_do_get_stats(tp);
- cmd->speed = tp->speed;
+ ethtool_cmd_speed_set(cmd, tp->speed);
cmd->duplex = tp->duplex;
cmd->phy_address = 0;
cmd->transceiver = XCVR_INTERNAL;
@@ -1068,25 +1068,26 @@ static int
typhoon_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct typhoon *tp = netdev_priv(dev);
+ u32 speed = ethtool_cmd_speed(cmd);
struct cmd_desc xp_cmd;
__le16 xcvr;
int err;
err = -EINVAL;
- if(cmd->autoneg == AUTONEG_ENABLE) {
+ if (cmd->autoneg == AUTONEG_ENABLE) {
xcvr = TYPHOON_XCVR_AUTONEG;
} else {
- if(cmd->duplex == DUPLEX_HALF) {
- if(cmd->speed == SPEED_10)
+ if (cmd->duplex == DUPLEX_HALF) {
+ if (speed == SPEED_10)
xcvr = TYPHOON_XCVR_10HALF;
- else if(cmd->speed == SPEED_100)
+ else if (speed == SPEED_100)
xcvr = TYPHOON_XCVR_100HALF;
else
goto out;
- } else if(cmd->duplex == DUPLEX_FULL) {
- if(cmd->speed == SPEED_10)
+ } else if (cmd->duplex == DUPLEX_FULL) {
+ if (speed == SPEED_10)
xcvr = TYPHOON_XCVR_10FULL;
- else if(cmd->speed == SPEED_100)
+ else if (speed == SPEED_100)
xcvr = TYPHOON_XCVR_100FULL;
else
goto out;
@@ -1105,7 +1106,7 @@ typhoon_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
tp->speed = 0xff; /* invalid */
tp->duplex = 0xff; /* invalid */
} else {
- tp->speed = cmd->speed;
+ tp->speed = speed;
tp->duplex = cmd->duplex;
}
@@ -1144,28 +1145,6 @@ typhoon_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
return 0;
}
-static u32
-typhoon_get_rx_csum(struct net_device *dev)
-{
- /* For now, we don't allow turning off RX checksums.
- */
- return 1;
-}
-
-static int
-typhoon_set_flags(struct net_device *dev, u32 data)
-{
- /* There's no way to turn off the RX VLAN offloading and stripping
- * on the current 3XP firmware -- it does not respect the offload
- * settings -- so we only allow the user to toggle the TX processing.
- */
- if (!(data & ETH_FLAG_RXVLAN))
- return -EINVAL;
-
- return ethtool_op_set_flags(dev, data,
- ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN);
-}
-
static void
typhoon_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
{
@@ -1187,13 +1166,7 @@ static const struct ethtool_ops typhoon_ethtool_ops = {
.get_wol = typhoon_get_wol,
.set_wol = typhoon_set_wol,
.get_link = ethtool_op_get_link,
- .get_rx_csum = typhoon_get_rx_csum,
- .set_tx_csum = ethtool_op_set_tx_csum,
- .set_sg = ethtool_op_set_sg,
- .set_tso = ethtool_op_set_tso,
.get_ringparam = typhoon_get_ringparam,
- .set_flags = typhoon_set_flags,
- .get_flags = ethtool_op_get_flags,
};
static int
@@ -2482,10 +2455,15 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* We can handle scatter gather, up to 16 entries, and
* we can do IP checksumming (only version 4, doh...)
+ *
+ * There's no way to turn off the RX VLAN offloading and stripping
+ * on the current 3XP firmware -- it does not respect the offload
+ * settings -- so we only allow the user to toggle the TX processing.
*/
- dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
- dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
- dev->features |= NETIF_F_TSO;
+ dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
+ NETIF_F_HW_VLAN_TX;
+ dev->features = dev->hw_features |
+ NETIF_F_HW_VLAN_RX | NETIF_F_RXCSUM;
if(register_netdev(dev) < 0) {
err_msg = "unable to register netdev";
diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c
index 6f92e48f02d3..a97257f91a3d 100644
--- a/drivers/net/ucc_geth_ethtool.c
+++ b/drivers/net/ucc_geth_ethtool.c
@@ -6,7 +6,7 @@
* Author: Li Yang <leoli@freescale.com>
*
* Limitation:
- * Can only get/set setttings of the first queue.
+ * Can only get/set settings of the first queue.
* Need to re-open the interface manually after changing some parameters.
*
* This program is free software; you can redistribute it and/or modify it
@@ -410,7 +410,6 @@ static const struct ethtool_ops uec_ethtool_ops = {
.set_ringparam = uec_set_ringparam,
.get_pauseparam = uec_get_pauseparam,
.set_pauseparam = uec_set_pauseparam,
- .set_sg = ethtool_op_set_sg,
.get_sset_count = uec_get_sset_count,
.get_strings = uec_get_strings,
.get_ethtool_stats = uec_get_ethtool_stats,
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 3ec22c307797..9d4f9117260f 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -258,7 +258,7 @@ config USB_NET_NET1080
optionally with LEDs that indicate traffic
config USB_NET_PLUSB
- tristate "Prolific PL-2301/2302 based cables"
+ tristate "Prolific PL-2301/2302/25A1 based cables"
# if the handshake/init/reset problems, from original 'plusb',
# are ever resolved ... then remove "experimental"
depends on USB_USBNET && EXPERIMENTAL
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index 6140b56cce53..6998aa6b7bb7 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -847,7 +847,7 @@ static void ax88172_set_multicast(struct net_device *net)
static int ax88172_link_reset(struct usbnet *dev)
{
u8 mode;
- struct ethtool_cmd ecmd;
+ struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
mii_check_media(&dev->mii, 1, 1);
mii_ethtool_gset(&dev->mii, &ecmd);
@@ -856,8 +856,8 @@ static int ax88172_link_reset(struct usbnet *dev)
if (ecmd.duplex != DUPLEX_FULL)
mode |= ~AX88172_MEDIUM_FD;
- netdev_dbg(dev->net, "ax88172_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n",
- ecmd.speed, ecmd.duplex, mode);
+ netdev_dbg(dev->net, "ax88172_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
+ ethtool_cmd_speed(&ecmd), ecmd.duplex, mode);
asix_write_medium_mode(dev, mode);
@@ -947,20 +947,20 @@ static const struct ethtool_ops ax88772_ethtool_ops = {
static int ax88772_link_reset(struct usbnet *dev)
{
u16 mode;
- struct ethtool_cmd ecmd;
+ struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
mii_check_media(&dev->mii, 1, 1);
mii_ethtool_gset(&dev->mii, &ecmd);
mode = AX88772_MEDIUM_DEFAULT;
- if (ecmd.speed != SPEED_100)
+ if (ethtool_cmd_speed(&ecmd) != SPEED_100)
mode &= ~AX_MEDIUM_PS;
if (ecmd.duplex != DUPLEX_FULL)
mode &= ~AX_MEDIUM_FD;
- netdev_dbg(dev->net, "ax88772_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n",
- ecmd.speed, ecmd.duplex, mode);
+ netdev_dbg(dev->net, "ax88772_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
+ ethtool_cmd_speed(&ecmd), ecmd.duplex, mode);
asix_write_medium_mode(dev, mode);
@@ -1173,18 +1173,20 @@ static int marvell_led_status(struct usbnet *dev, u16 speed)
static int ax88178_link_reset(struct usbnet *dev)
{
u16 mode;
- struct ethtool_cmd ecmd;
+ struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
struct asix_data *data = (struct asix_data *)&dev->data;
+ u32 speed;
netdev_dbg(dev->net, "ax88178_link_reset()\n");
mii_check_media(&dev->mii, 1, 1);
mii_ethtool_gset(&dev->mii, &ecmd);
mode = AX88178_MEDIUM_DEFAULT;
+ speed = ethtool_cmd_speed(&ecmd);
- if (ecmd.speed == SPEED_1000)
+ if (speed == SPEED_1000)
mode |= AX_MEDIUM_GM;
- else if (ecmd.speed == SPEED_100)
+ else if (speed == SPEED_100)
mode |= AX_MEDIUM_PS;
else
mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM);
@@ -1196,13 +1198,13 @@ static int ax88178_link_reset(struct usbnet *dev)
else
mode &= ~AX_MEDIUM_FD;
- netdev_dbg(dev->net, "ax88178_link_reset() speed: %d duplex: %d setting mode to 0x%04x\n",
- ecmd.speed, ecmd.duplex, mode);
+ netdev_dbg(dev->net, "ax88178_link_reset() speed: %u duplex: %d setting mode to 0x%04x\n",
+ speed, ecmd.duplex, mode);
asix_write_medium_mode(dev, mode);
if (data->phymode == PHY_MODE_MARVELL && data->ledmode)
- marvell_led_status(dev, ecmd.speed);
+ marvell_led_status(dev, speed);
return 0;
}
diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c
index 97687d335903..d7221c4a5dcf 100644
--- a/drivers/net/usb/catc.c
+++ b/drivers/net/usb/catc.c
@@ -686,7 +686,7 @@ static int catc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_TP;
cmd->advertising = ADVERTISED_10baseT_Half | ADVERTISED_TP;
- cmd->speed = SPEED_10;
+ ethtool_cmd_speed_set(cmd, SPEED_10);
cmd->duplex = DUPLEX_HALF;
cmd->port = PORT_TP;
cmd->phy_address = 0;
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 1033ef6476a4..cdd3ae486109 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -54,13 +54,13 @@
#include <linux/usb/usbnet.h>
#include <linux/usb/cdc.h>
-#define DRIVER_VERSION "23-Apr-2011"
+#define DRIVER_VERSION "24-May-2011"
/* CDC NCM subclass 3.2.1 */
#define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10
/* Maximum NTB length */
-#define CDC_NCM_NTB_MAX_SIZE_TX (16384 + 4) /* bytes, must be short terminated */
+#define CDC_NCM_NTB_MAX_SIZE_TX 16384 /* bytes */
#define CDC_NCM_NTB_MAX_SIZE_RX 16384 /* bytes */
/* Minimum value for MaxDatagramSize, ch. 6.2.9 */
@@ -134,8 +134,6 @@ struct cdc_ncm_ctx {
u16 tx_ndp_modulus;
u16 tx_seq;
u16 connected;
- u8 data_claimed;
- u8 control_claimed;
};
static void cdc_ncm_tx_timeout(unsigned long arg);
@@ -460,17 +458,6 @@ static void cdc_ncm_free(struct cdc_ncm_ctx *ctx)
del_timer_sync(&ctx->tx_timer);
- if (ctx->data_claimed) {
- usb_set_intfdata(ctx->data, NULL);
- usb_driver_release_interface(driver_of(ctx->intf), ctx->data);
- }
-
- if (ctx->control_claimed) {
- usb_set_intfdata(ctx->control, NULL);
- usb_driver_release_interface(driver_of(ctx->intf),
- ctx->control);
- }
-
if (ctx->tx_rem_skb != NULL) {
dev_kfree_skb_any(ctx->tx_rem_skb);
ctx->tx_rem_skb = NULL;
@@ -495,7 +482,7 @@ static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
if (ctx == NULL)
- goto error;
+ return -ENODEV;
memset(ctx, 0, sizeof(*ctx));
@@ -568,46 +555,36 @@ advance:
/* check if we got everything */
if ((ctx->control == NULL) || (ctx->data == NULL) ||
- (ctx->ether_desc == NULL))
+ (ctx->ether_desc == NULL) || (ctx->control != intf))
goto error;
/* claim interfaces, if any */
- if (ctx->data != intf) {
- temp = usb_driver_claim_interface(driver, ctx->data, dev);
- if (temp)
- goto error;
- ctx->data_claimed = 1;
- }
-
- if (ctx->control != intf) {
- temp = usb_driver_claim_interface(driver, ctx->control, dev);
- if (temp)
- goto error;
- ctx->control_claimed = 1;
- }
+ temp = usb_driver_claim_interface(driver, ctx->data, dev);
+ if (temp)
+ goto error;
iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber;
/* reset data interface */
temp = usb_set_interface(dev->udev, iface_no, 0);
if (temp)
- goto error;
+ goto error2;
/* initialize data interface */
if (cdc_ncm_setup(ctx))
- goto error;
+ goto error2;
/* configure data interface */
temp = usb_set_interface(dev->udev, iface_no, 1);
if (temp)
- goto error;
+ goto error2;
cdc_ncm_find_endpoints(ctx, ctx->data);
cdc_ncm_find_endpoints(ctx, ctx->control);
if ((ctx->in_ep == NULL) || (ctx->out_ep == NULL) ||
(ctx->status_ep == NULL))
- goto error;
+ goto error2;
dev->net->ethtool_ops = &cdc_ncm_ethtool_ops;
@@ -617,7 +594,7 @@ advance:
temp = usbnet_get_ethernet_addr(dev, ctx->ether_desc->iMACAddress);
if (temp)
- goto error;
+ goto error2;
dev_info(&dev->udev->dev, "MAC-Address: "
"0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
@@ -642,38 +619,38 @@ advance:
ctx->tx_speed = ctx->rx_speed = 0;
return 0;
+error2:
+ usb_set_intfdata(ctx->control, NULL);
+ usb_set_intfdata(ctx->data, NULL);
+ usb_driver_release_interface(driver, ctx->data);
error:
cdc_ncm_free((struct cdc_ncm_ctx *)dev->data[0]);
dev->data[0] = 0;
- dev_info(&dev->udev->dev, "Descriptor failure\n");
+ dev_info(&dev->udev->dev, "bind() failure\n");
return -ENODEV;
}
static void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf)
{
struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
- struct usb_driver *driver;
+ struct usb_driver *driver = driver_of(intf);
if (ctx == NULL)
return; /* no setup */
- driver = driver_of(intf);
-
- usb_set_intfdata(ctx->data, NULL);
- usb_set_intfdata(ctx->control, NULL);
- usb_set_intfdata(ctx->intf, NULL);
-
- /* release interfaces, if any */
- if (ctx->data_claimed) {
+ /* disconnect master --> disconnect slave */
+ if (intf == ctx->control && ctx->data) {
+ usb_set_intfdata(ctx->data, NULL);
usb_driver_release_interface(driver, ctx->data);
- ctx->data_claimed = 0;
- }
+ ctx->data = NULL;
- if (ctx->control_claimed) {
+ } else if (intf == ctx->data && ctx->control) {
+ usb_set_intfdata(ctx->control, NULL);
usb_driver_release_interface(driver, ctx->control);
- ctx->control_claimed = 0;
+ ctx->control = NULL;
}
+ usb_set_intfdata(ctx->intf, NULL);
cdc_ncm_free(ctx);
}
@@ -722,7 +699,7 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
} else {
/* reset variables */
- skb_out = alloc_skb(ctx->tx_max, GFP_ATOMIC);
+ skb_out = alloc_skb((ctx->tx_max + 1), GFP_ATOMIC);
if (skb_out == NULL) {
if (skb != NULL) {
dev_kfree_skb_any(skb);
@@ -861,8 +838,11 @@ cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
/* store last offset */
last_offset = offset;
- if ((last_offset < ctx->tx_max) && ((last_offset %
- le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) {
+ if (((last_offset < ctx->tx_max) && ((last_offset %
+ le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) ||
+ (((last_offset == ctx->tx_max) && ((ctx->tx_max %
+ le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) &&
+ (ctx->tx_max < le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize)))) {
/* force short packet */
*(((u8 *)skb_out->data) + last_offset) = 0;
last_offset++;
diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c
index 5002f5be47be..1d93133e9b74 100644
--- a/drivers/net/usb/dm9601.c
+++ b/drivers/net/usb/dm9601.c
@@ -599,13 +599,13 @@ static void dm9601_status(struct usbnet *dev, struct urb *urb)
static int dm9601_link_reset(struct usbnet *dev)
{
- struct ethtool_cmd ecmd;
+ struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
mii_check_media(&dev->mii, 1, 1);
mii_ethtool_gset(&dev->mii, &ecmd);
- netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n",
- ecmd.speed, ecmd.duplex);
+ netdev_dbg(dev->net, "link_reset() speed: %u duplex: %d\n",
+ ethtool_cmd_speed(&ecmd), ecmd.duplex);
return 0;
}
diff --git a/drivers/net/usb/plusb.c b/drivers/net/usb/plusb.c
index 823c53751307..217aec8a768f 100644
--- a/drivers/net/usb/plusb.c
+++ b/drivers/net/usb/plusb.c
@@ -45,6 +45,14 @@
* seems to get wedged under load. Prolific docs are weak, and
* don't identify differences between PL2301 and PL2302, much less
* anything to explain the different PL2302 versions observed.
+ *
+ * NOTE: pl2501 has several modes, including pl2301 and pl2302
+ * compatibility. Some docs suggest the difference between 2301
+ * and 2302 is only to make MS-Windows use a different driver...
+ *
+ * pl25a1 glue based on patch from Tony Gibbs. Prolific "docs" on
+ * this chip are as usual incomplete about what control messages
+ * are supported.
*/
/*
@@ -86,16 +94,20 @@ pl_set_QuickLink_features(struct usbnet *dev, int val)
static int pl_reset(struct usbnet *dev)
{
+ int status;
+
/* some units seem to need this reset, others reject it utterly.
* FIXME be more like "naplink" or windows drivers.
*/
- (void) pl_set_QuickLink_features(dev,
+ status = pl_set_QuickLink_features(dev,
PL_S_EN|PL_RESET_OUT|PL_RESET_IN|PL_PEER_E);
+ if (status != 0 && netif_msg_probe(dev))
+ netif_dbg(dev, link, dev->net, "pl_reset --> %d\n", status);
return 0;
}
static const struct driver_info prolific_info = {
- .description = "Prolific PL-2301/PL-2302",
+ .description = "Prolific PL-2301/PL-2302/PL-25A1",
.flags = FLAG_POINTTOPOINT | FLAG_NO_SETINT,
/* some PL-2302 versions seem to fail usb_set_interface() */
.reset = pl_reset,
@@ -111,6 +123,7 @@ static const struct driver_info prolific_info = {
static const struct usb_device_id products [] = {
+/* full speed cables */
{
USB_DEVICE(0x067b, 0x0000), // PL-2301
.driver_info = (unsigned long) &prolific_info,
@@ -119,6 +132,15 @@ static const struct usb_device_id products [] = {
.driver_info = (unsigned long) &prolific_info,
},
+/* high speed cables */
+{
+ USB_DEVICE(0x067b, 0x25a1), /* PL-25A1, no eeprom */
+ .driver_info = (unsigned long) &prolific_info,
+}, {
+ USB_DEVICE(0x050d, 0x258a), /* Belkin F5U258/F5U279 (PL-25A1) */
+ .driver_info = (unsigned long) &prolific_info,
+},
+
{ }, // END
};
MODULE_DEVICE_TABLE(usb, products);
@@ -134,16 +156,16 @@ static struct usb_driver plusb_driver = {
static int __init plusb_init(void)
{
- return usb_register(&plusb_driver);
+ return usb_register(&plusb_driver);
}
module_init(plusb_init);
static void __exit plusb_exit(void)
{
- usb_deregister(&plusb_driver);
+ usb_deregister(&plusb_driver);
}
module_exit(plusb_exit);
MODULE_AUTHOR("David Brownell");
-MODULE_DESCRIPTION("Prolific PL-2301/2302 USB Host to Host Link Driver");
+MODULE_DESCRIPTION("Prolific PL-2301/2302/25A1 USB Host to Host Link Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
index 5994a25c56ac..255d6a424a6b 100644
--- a/drivers/net/usb/rndis_host.c
+++ b/drivers/net/usb/rndis_host.c
@@ -104,8 +104,10 @@ static void rndis_msg_indicate(struct usbnet *dev, struct rndis_indicate *msg,
int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen)
{
struct cdc_state *info = (void *) &dev->data;
+ struct usb_cdc_notification notification;
int master_ifnum;
int retval;
+ int partial;
unsigned count;
__le32 rsp;
u32 xid = 0, msg_len, request_id;
@@ -133,13 +135,20 @@ int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf, int buflen)
if (unlikely(retval < 0 || xid == 0))
return retval;
- // FIXME Seems like some devices discard responses when
- // we time out and cancel our "get response" requests...
- // so, this is fragile. Probably need to poll for status.
+ /* Some devices don't respond on the control channel until
+ * polled on the status channel, so do that first. */
+ if (dev->driver_info->data & RNDIS_DRIVER_DATA_POLL_STATUS) {
+ retval = usb_interrupt_msg(
+ dev->udev,
+ usb_rcvintpipe(dev->udev,
+ dev->status->desc.bEndpointAddress),
+ &notification, sizeof(notification), &partial,
+ RNDIS_CONTROL_TIMEOUT_MS);
+ if (unlikely(retval < 0))
+ return retval;
+ }
- /* ignore status endpoint, just poll the control channel;
- * the request probably completed immediately
- */
+ /* Poll the control channel; the request probably completed immediately */
rsp = buf->msg_type | RNDIS_MSG_COMPLETION;
for (count = 0; count < 10; count++) {
memset(buf, 0, CONTROL_BUFFER_SIZE);
@@ -581,17 +590,33 @@ static const struct driver_info rndis_info = {
.tx_fixup = rndis_tx_fixup,
};
+static const struct driver_info rndis_poll_status_info = {
+ .description = "RNDIS device (poll status before control)",
+ .flags = FLAG_ETHER | FLAG_POINTTOPOINT | FLAG_FRAMING_RN | FLAG_NO_SETINT,
+ .data = RNDIS_DRIVER_DATA_POLL_STATUS,
+ .bind = rndis_bind,
+ .unbind = rndis_unbind,
+ .status = rndis_status,
+ .rx_fixup = rndis_rx_fixup,
+ .tx_fixup = rndis_tx_fixup,
+};
+
/*-------------------------------------------------------------------------*/
static const struct usb_device_id products [] = {
{
+ /* 2Wire HomePortal 1000SW */
+ USB_DEVICE_AND_INTERFACE_INFO(0x1630, 0x0042,
+ USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
+ .driver_info = (unsigned long) &rndis_poll_status_info,
+}, {
/* RNDIS is MSFT's un-official variant of CDC ACM */
USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
.driver_info = (unsigned long) &rndis_info,
}, {
/* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */
USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1),
- .driver_info = (unsigned long) &rndis_info,
+ .driver_info = (unsigned long) &rndis_poll_status_info,
}, {
/* RNDIS for tethering */
USB_INTERFACE_INFO(USB_CLASS_WIRELESS_CONTROLLER, 1, 3),
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index e85c89c6706d..041fb7d43c4f 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -843,10 +843,11 @@ static int rtl8150_get_settings(struct net_device *netdev, struct ethtool_cmd *e
get_registers(dev, BMCR, 2, &bmcr);
get_registers(dev, ANLP, 2, &lpa);
if (bmcr & BMCR_ANENABLE) {
+ u32 speed = ((lpa & (LPA_100HALF | LPA_100FULL)) ?
+ SPEED_100 : SPEED_10);
+ ethtool_cmd_speed_set(ecmd, speed);
ecmd->autoneg = AUTONEG_ENABLE;
- ecmd->speed = (lpa & (LPA_100HALF | LPA_100FULL)) ?
- SPEED_100 : SPEED_10;
- if (ecmd->speed == SPEED_100)
+ if (speed == SPEED_100)
ecmd->duplex = (lpa & LPA_100FULL) ?
DUPLEX_FULL : DUPLEX_HALF;
else
@@ -854,8 +855,8 @@ static int rtl8150_get_settings(struct net_device *netdev, struct ethtool_cmd *e
DUPLEX_FULL : DUPLEX_HALF;
} else {
ecmd->autoneg = AUTONEG_DISABLE;
- ecmd->speed = (bmcr & BMCR_SPEED100) ?
- SPEED_100 : SPEED_10;
+ ethtool_cmd_speed_set(ecmd, ((bmcr & BMCR_SPEED100) ?
+ SPEED_100 : SPEED_10));
ecmd->duplex = (bmcr & BMCR_FULLDPLX) ?
DUPLEX_FULL : DUPLEX_HALF;
}
diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c
index 753ee6eb7edd..15b3d6888ae9 100644
--- a/drivers/net/usb/smsc75xx.c
+++ b/drivers/net/usb/smsc75xx.c
@@ -65,7 +65,6 @@ struct smsc75xx_priv {
struct usbnet *dev;
u32 rfe_ctl;
u32 multicast_hash_table[DP_SEL_VHF_HASH_LEN];
- bool use_rx_csum;
struct mutex dataport_mutex;
spinlock_t rfe_ctl_lock;
struct work_struct set_multicast;
@@ -504,7 +503,7 @@ static int smsc75xx_update_flowcontrol(struct usbnet *dev, u8 duplex,
static int smsc75xx_link_reset(struct usbnet *dev)
{
struct mii_if_info *mii = &dev->mii;
- struct ethtool_cmd ecmd;
+ struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
u16 lcladv, rmtadv;
int ret;
@@ -520,8 +519,9 @@ static int smsc75xx_link_reset(struct usbnet *dev)
lcladv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE);
rmtadv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_LPA);
- netif_dbg(dev, link, dev->net, "speed: %d duplex: %d lcladv: %04x"
- " rmtadv: %04x", ecmd.speed, ecmd.duplex, lcladv, rmtadv);
+ netif_dbg(dev, link, dev->net, "speed: %u duplex: %d lcladv: %04x"
+ " rmtadv: %04x", ethtool_cmd_speed(&ecmd),
+ ecmd.duplex, lcladv, rmtadv);
return smsc75xx_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv);
}
@@ -548,28 +548,6 @@ static void smsc75xx_status(struct usbnet *dev, struct urb *urb)
"unexpected interrupt, intdata=0x%08X", intdata);
}
-/* Enable or disable Rx checksum offload engine */
-static int smsc75xx_set_rx_csum_offload(struct usbnet *dev)
-{
- struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(&pdata->rfe_ctl_lock, flags);
-
- if (pdata->use_rx_csum)
- pdata->rfe_ctl |= RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM;
- else
- pdata->rfe_ctl &= ~(RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM);
-
- spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags);
-
- ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl);
- check_warn_return(ret, "Error writing RFE_CTL");
-
- return 0;
-}
-
static int smsc75xx_ethtool_get_eeprom_len(struct net_device *net)
{
return MAX_EEPROM_SIZE;
@@ -599,34 +577,6 @@ static int smsc75xx_ethtool_set_eeprom(struct net_device *netdev,
return smsc75xx_write_eeprom(dev, ee->offset, ee->len, data);
}
-static u32 smsc75xx_ethtool_get_rx_csum(struct net_device *netdev)
-{
- struct usbnet *dev = netdev_priv(netdev);
- struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
-
- return pdata->use_rx_csum;
-}
-
-static int smsc75xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val)
-{
- struct usbnet *dev = netdev_priv(netdev);
- struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
-
- pdata->use_rx_csum = !!val;
-
- return smsc75xx_set_rx_csum_offload(dev);
-}
-
-static int smsc75xx_ethtool_set_tso(struct net_device *netdev, u32 data)
-{
- if (data)
- netdev->features |= NETIF_F_TSO | NETIF_F_TSO6;
- else
- netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
-
- return 0;
-}
-
static const struct ethtool_ops smsc75xx_ethtool_ops = {
.get_link = usbnet_get_link,
.nway_reset = usbnet_nway_reset,
@@ -638,12 +588,6 @@ static const struct ethtool_ops smsc75xx_ethtool_ops = {
.get_eeprom_len = smsc75xx_ethtool_get_eeprom_len,
.get_eeprom = smsc75xx_ethtool_get_eeprom,
.set_eeprom = smsc75xx_ethtool_set_eeprom,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = ethtool_op_set_tx_hw_csum,
- .get_rx_csum = smsc75xx_ethtool_get_rx_csum,
- .set_rx_csum = smsc75xx_ethtool_set_rx_csum,
- .get_tso = ethtool_op_get_tso,
- .set_tso = smsc75xx_ethtool_set_tso,
};
static int smsc75xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
@@ -782,6 +726,30 @@ static int smsc75xx_change_mtu(struct net_device *netdev, int new_mtu)
return usbnet_change_mtu(netdev, new_mtu);
}
+/* Enable or disable Rx checksum offload engine */
+static int smsc75xx_set_features(struct net_device *netdev, u32 features)
+{
+ struct usbnet *dev = netdev_priv(netdev);
+ struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&pdata->rfe_ctl_lock, flags);
+
+ if (features & NETIF_F_RXCSUM)
+ pdata->rfe_ctl |= RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM;
+ else
+ pdata->rfe_ctl &= ~(RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM);
+
+ spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags);
+ /* it's racing here! */
+
+ ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl);
+ check_warn_return(ret, "Error writing RFE_CTL");
+
+ return 0;
+}
+
static int smsc75xx_reset(struct usbnet *dev)
{
struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
@@ -960,11 +928,7 @@ static int smsc75xx_reset(struct usbnet *dev)
netif_dbg(dev, ifup, dev->net, "RFE_CTL set to 0x%08x", pdata->rfe_ctl);
/* Enable or disable checksum offload engines */
- ethtool_op_set_tx_hw_csum(dev->net, DEFAULT_TX_CSUM_ENABLE);
- ret = smsc75xx_set_rx_csum_offload(dev);
- check_warn_return(ret, "Failed to set rx csum offload: %d", ret);
-
- smsc75xx_ethtool_set_tso(dev->net, DEFAULT_TSO_ENABLE);
+ smsc75xx_set_features(dev->net, dev->net->features);
smsc75xx_set_multicast(dev->net);
@@ -1037,6 +1001,7 @@ static const struct net_device_ops smsc75xx_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = smsc75xx_ioctl,
.ndo_set_multicast_list = smsc75xx_set_multicast,
+ .ndo_set_features = smsc75xx_set_features,
};
static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf)
@@ -1065,10 +1030,17 @@ static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf)
INIT_WORK(&pdata->set_multicast, smsc75xx_deferred_multicast_write);
- pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE;
+ if (DEFAULT_TX_CSUM_ENABLE) {
+ dev->net->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+ if (DEFAULT_TSO_ENABLE)
+ dev->net->features |= NETIF_F_SG |
+ NETIF_F_TSO | NETIF_F_TSO6;
+ }
+ if (DEFAULT_RX_CSUM_ENABLE)
+ dev->net->features |= NETIF_F_RXCSUM;
- /* We have to advertise SG otherwise TSO cannot be enabled */
- dev->net->features |= NETIF_F_SG;
+ dev->net->hw_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+ NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_RXCSUM;
/* Init all registers */
ret = smsc75xx_reset(dev);
@@ -1091,10 +1063,11 @@ static void smsc75xx_unbind(struct usbnet *dev, struct usb_interface *intf)
}
}
-static void smsc75xx_rx_csum_offload(struct sk_buff *skb, u32 rx_cmd_a,
- u32 rx_cmd_b)
+static void smsc75xx_rx_csum_offload(struct usbnet *dev, struct sk_buff *skb,
+ u32 rx_cmd_a, u32 rx_cmd_b)
{
- if (unlikely(rx_cmd_a & RX_CMD_A_LCSM)) {
+ if (!(dev->net->features & NETIF_F_RXCSUM) ||
+ unlikely(rx_cmd_a & RX_CMD_A_LCSM)) {
skb->ip_summed = CHECKSUM_NONE;
} else {
skb->csum = ntohs((u16)(rx_cmd_b >> RX_CMD_B_CSUM_SHIFT));
@@ -1104,8 +1077,6 @@ static void smsc75xx_rx_csum_offload(struct sk_buff *skb, u32 rx_cmd_a,
static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
- struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]);
-
while (skb->len > 0) {
u32 rx_cmd_a, rx_cmd_b, align_count, size;
struct sk_buff *ax_skb;
@@ -1145,11 +1116,8 @@ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
/* last frame in this batch */
if (skb->len == size) {
- if (pdata->use_rx_csum)
- smsc75xx_rx_csum_offload(skb, rx_cmd_a,
- rx_cmd_b);
- else
- skb->ip_summed = CHECKSUM_NONE;
+ smsc75xx_rx_csum_offload(dev, skb, rx_cmd_a,
+ rx_cmd_b);
skb_trim(skb, skb->len - 4); /* remove fcs */
skb->truesize = size + sizeof(struct sk_buff);
@@ -1167,11 +1135,8 @@ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
ax_skb->data = packet;
skb_set_tail_pointer(ax_skb, size);
- if (pdata->use_rx_csum)
- smsc75xx_rx_csum_offload(ax_skb, rx_cmd_a,
- rx_cmd_b);
- else
- ax_skb->ip_summed = CHECKSUM_NONE;
+ smsc75xx_rx_csum_offload(dev, ax_skb, rx_cmd_a,
+ rx_cmd_b);
skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */
ax_skb->truesize = size + sizeof(struct sk_buff);
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 48d4efdb4959..f74f3ce71526 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -52,8 +52,6 @@ struct smsc95xx_priv {
u32 hash_hi;
u32 hash_lo;
spinlock_t mac_cr_lock;
- bool use_tx_csum;
- bool use_rx_csum;
};
struct usb_context {
@@ -459,7 +457,7 @@ static int smsc95xx_link_reset(struct usbnet *dev)
{
struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
struct mii_if_info *mii = &dev->mii;
- struct ethtool_cmd ecmd;
+ struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
unsigned long flags;
u16 lcladv, rmtadv;
u32 intdata;
@@ -474,8 +472,9 @@ static int smsc95xx_link_reset(struct usbnet *dev)
lcladv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE);
rmtadv = smsc95xx_mdio_read(dev->net, mii->phy_id, MII_LPA);
- netif_dbg(dev, link, dev->net, "speed: %d duplex: %d lcladv: %04x rmtadv: %04x\n",
- ecmd.speed, ecmd.duplex, lcladv, rmtadv);
+ netif_dbg(dev, link, dev->net,
+ "speed: %u duplex: %d lcladv: %04x rmtadv: %04x\n",
+ ethtool_cmd_speed(&ecmd), ecmd.duplex, lcladv, rmtadv);
spin_lock_irqsave(&pdata->mac_cr_lock, flags);
if (ecmd.duplex != DUPLEX_FULL) {
@@ -517,22 +516,24 @@ static void smsc95xx_status(struct usbnet *dev, struct urb *urb)
}
/* Enable or disable Tx & Rx checksum offload engines */
-static int smsc95xx_set_csums(struct usbnet *dev)
+static int smsc95xx_set_features(struct net_device *netdev, u32 features)
{
- struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+ struct usbnet *dev = netdev_priv(netdev);
u32 read_buf;
- int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf);
+ int ret;
+
+ ret = smsc95xx_read_reg(dev, COE_CR, &read_buf);
if (ret < 0) {
netdev_warn(dev->net, "Failed to read COE_CR: %d\n", ret);
return ret;
}
- if (pdata->use_tx_csum)
+ if (features & NETIF_F_HW_CSUM)
read_buf |= Tx_COE_EN_;
else
read_buf &= ~Tx_COE_EN_;
- if (pdata->use_rx_csum)
+ if (features & NETIF_F_RXCSUM)
read_buf |= Rx_COE_EN_;
else
read_buf &= ~Rx_COE_EN_;
@@ -576,43 +577,6 @@ static int smsc95xx_ethtool_set_eeprom(struct net_device *netdev,
return smsc95xx_write_eeprom(dev, ee->offset, ee->len, data);
}
-static u32 smsc95xx_ethtool_get_rx_csum(struct net_device *netdev)
-{
- struct usbnet *dev = netdev_priv(netdev);
- struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-
- return pdata->use_rx_csum;
-}
-
-static int smsc95xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val)
-{
- struct usbnet *dev = netdev_priv(netdev);
- struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-
- pdata->use_rx_csum = !!val;
-
- return smsc95xx_set_csums(dev);
-}
-
-static u32 smsc95xx_ethtool_get_tx_csum(struct net_device *netdev)
-{
- struct usbnet *dev = netdev_priv(netdev);
- struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-
- return pdata->use_tx_csum;
-}
-
-static int smsc95xx_ethtool_set_tx_csum(struct net_device *netdev, u32 val)
-{
- struct usbnet *dev = netdev_priv(netdev);
- struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-
- pdata->use_tx_csum = !!val;
-
- ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum);
- return smsc95xx_set_csums(dev);
-}
-
static const struct ethtool_ops smsc95xx_ethtool_ops = {
.get_link = usbnet_get_link,
.nway_reset = usbnet_nway_reset,
@@ -624,10 +588,6 @@ static const struct ethtool_ops smsc95xx_ethtool_ops = {
.get_eeprom_len = smsc95xx_ethtool_get_eeprom_len,
.get_eeprom = smsc95xx_ethtool_get_eeprom,
.set_eeprom = smsc95xx_ethtool_set_eeprom,
- .get_tx_csum = smsc95xx_ethtool_get_tx_csum,
- .set_tx_csum = smsc95xx_ethtool_set_tx_csum,
- .get_rx_csum = smsc95xx_ethtool_get_rx_csum,
- .set_rx_csum = smsc95xx_ethtool_set_rx_csum,
};
static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
@@ -755,7 +715,6 @@ static int smsc95xx_phy_initialize(struct usbnet *dev)
static int smsc95xx_reset(struct usbnet *dev)
{
struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
- struct net_device *netdev = dev->net;
u32 read_buf, write_buf, burst_cap;
int ret = 0, timeout;
@@ -975,12 +934,7 @@ static int smsc95xx_reset(struct usbnet *dev)
}
/* Enable or disable checksum offload engines */
- ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum);
- ret = smsc95xx_set_csums(dev);
- if (ret < 0) {
- netdev_warn(dev->net, "Failed to set csum offload: %d\n", ret);
- return ret;
- }
+ smsc95xx_set_features(dev->net, dev->net->features);
smsc95xx_set_multicast(dev->net);
@@ -1019,6 +973,7 @@ static const struct net_device_ops smsc95xx_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = smsc95xx_ioctl,
.ndo_set_multicast_list = smsc95xx_set_multicast,
+ .ndo_set_features = smsc95xx_set_features,
};
static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
@@ -1045,8 +1000,12 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
spin_lock_init(&pdata->mac_cr_lock);
- pdata->use_tx_csum = DEFAULT_TX_CSUM_ENABLE;
- pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE;
+ if (DEFAULT_TX_CSUM_ENABLE)
+ dev->net->features |= NETIF_F_HW_CSUM;
+ if (DEFAULT_RX_CSUM_ENABLE)
+ dev->net->features |= NETIF_F_RXCSUM;
+
+ dev->net->hw_features = NETIF_F_HW_CSUM | NETIF_F_RXCSUM;
smsc95xx_init_mac_address(dev);
@@ -1056,7 +1015,7 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
dev->net->netdev_ops = &smsc95xx_netdev_ops;
dev->net->ethtool_ops = &smsc95xx_ethtool_ops;
dev->net->flags |= IFF_MULTICAST;
- dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD;
+ dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD_CSUM;
return 0;
}
@@ -1080,8 +1039,6 @@ static void smsc95xx_rx_csum_offload(struct sk_buff *skb)
static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
{
- struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
-
while (skb->len > 0) {
u32 header, align_count;
struct sk_buff *ax_skb;
@@ -1123,7 +1080,7 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
/* last frame in this batch */
if (skb->len == size) {
- if (pdata->use_rx_csum)
+ if (dev->net->features & NETIF_F_RXCSUM)
smsc95xx_rx_csum_offload(skb);
skb_trim(skb, skb->len - 4); /* remove fcs */
skb->truesize = size + sizeof(struct sk_buff);
@@ -1141,7 +1098,7 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
ax_skb->data = packet;
skb_set_tail_pointer(ax_skb, size);
- if (pdata->use_rx_csum)
+ if (dev->net->features & NETIF_F_RXCSUM)
smsc95xx_rx_csum_offload(ax_skb);
skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */
ax_skb->truesize = size + sizeof(struct sk_buff);
@@ -1174,8 +1131,7 @@ static u32 smsc95xx_calc_csum_preamble(struct sk_buff *skb)
static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev,
struct sk_buff *skb, gfp_t flags)
{
- struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
- bool csum = pdata->use_tx_csum && (skb->ip_summed == CHECKSUM_PARTIAL);
+ bool csum = skb->ip_summed == CHECKSUM_PARTIAL;
int overhead = csum ? SMSC95XX_TX_OVERHEAD_CSUM : SMSC95XX_TX_OVERHEAD;
u32 tx_cmd_a, tx_cmd_b;
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 9ab439d144ed..ce395fe5de26 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -109,7 +109,7 @@ int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf)
/* take the first altsetting with in-bulk + out-bulk;
* remember any status endpoint, just in case;
- * ignore other endpoints and altsetttings.
+ * ignore other endpoints and altsettings.
*/
for (ep = 0; ep < alt->desc.bNumEndpoints; ep++) {
struct usb_host_endpoint *e;
@@ -1541,9 +1541,9 @@ EXPORT_SYMBOL_GPL(usbnet_resume);
static int __init usbnet_init(void)
{
- /* compiler should optimize this out */
- BUILD_BUG_ON (sizeof (((struct sk_buff *)0)->cb)
- < sizeof (struct skb_data));
+ /* Compiler should optimize this out. */
+ BUILD_BUG_ON(
+ FIELD_SIZEOF(struct sk_buff, cb) < sizeof(struct skb_data));
random_ether_addr(node_id);
return 0;
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 3b99f64104fd..8461576fa015 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -22,7 +22,6 @@
#define MIN_MTU 68 /* Min L3 MTU */
#define MAX_MTU 65535 /* Max L3 MTU (arbitrary) */
-#define MTU_PAD (ETH_HLEN + 4) /* Max difference between L2 and L3 size MTU */
struct veth_net_stats {
unsigned long rx_packets;
@@ -36,7 +35,6 @@ struct veth_net_stats {
struct veth_priv {
struct net_device *peer;
struct veth_net_stats __percpu *stats;
- unsigned ip_summed;
};
/*
@@ -53,7 +51,7 @@ static int veth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
cmd->supported = 0;
cmd->advertising = 0;
- cmd->speed = SPEED_10000;
+ ethtool_cmd_speed_set(cmd, SPEED_10000);
cmd->duplex = DUPLEX_FULL;
cmd->port = PORT_TP;
cmd->phy_address = 0;
@@ -99,47 +97,10 @@ static void veth_get_ethtool_stats(struct net_device *dev,
data[0] = priv->peer->ifindex;
}
-static u32 veth_get_rx_csum(struct net_device *dev)
-{
- struct veth_priv *priv;
-
- priv = netdev_priv(dev);
- return priv->ip_summed == CHECKSUM_UNNECESSARY;
-}
-
-static int veth_set_rx_csum(struct net_device *dev, u32 data)
-{
- struct veth_priv *priv;
-
- priv = netdev_priv(dev);
- priv->ip_summed = data ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE;
- return 0;
-}
-
-static u32 veth_get_tx_csum(struct net_device *dev)
-{
- return (dev->features & NETIF_F_NO_CSUM) != 0;
-}
-
-static int veth_set_tx_csum(struct net_device *dev, u32 data)
-{
- if (data)
- dev->features |= NETIF_F_NO_CSUM;
- else
- dev->features &= ~NETIF_F_NO_CSUM;
- return 0;
-}
-
static const struct ethtool_ops veth_ethtool_ops = {
.get_settings = veth_get_settings,
.get_drvinfo = veth_get_drvinfo,
.get_link = ethtool_op_get_link,
- .get_rx_csum = veth_get_rx_csum,
- .set_rx_csum = veth_set_rx_csum,
- .get_tx_csum = veth_get_tx_csum,
- .set_tx_csum = veth_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
- .set_sg = ethtool_op_set_sg,
.get_strings = veth_get_strings,
.get_sset_count = veth_get_sset_count,
.get_ethtool_stats = veth_get_ethtool_stats,
@@ -168,8 +129,9 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
/* don't change ip_summed == CHECKSUM_PARTIAL, as that
will cause bad checksum on forwarded packets */
- if (skb->ip_summed == CHECKSUM_NONE)
- skb->ip_summed = rcv_priv->ip_summed;
+ if (skb->ip_summed == CHECKSUM_NONE &&
+ rcv->features & NETIF_F_RXCSUM)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
length = skb->len;
if (dev_forward_skb(rcv, skb) != NET_RX_SUCCESS)
@@ -304,6 +266,8 @@ static void veth_setup(struct net_device *dev)
dev->ethtool_ops = &veth_ethtool_ops;
dev->features |= NETIF_F_LLTX;
dev->destructor = veth_dev_free;
+
+ dev->hw_features = NETIF_F_NO_CSUM | NETIF_F_SG | NETIF_F_RXCSUM;
}
/*
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index eb5d75df5d5d..7f23ab913fd9 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -29,6 +29,8 @@
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#define DRV_NAME "via-rhine"
#define DRV_VERSION "1.5.0"
#define DRV_RELDATE "2010-10-09"
@@ -37,6 +39,7 @@
/* A few user-configurable values.
These may be modified when a driver module is loaded. */
+#define DEBUG
static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
static int max_interrupt_work = 20;
@@ -111,8 +114,7 @@ static const int multicast_filter_limit = 32;
/* These identify the driver base version and may not be removed. */
static const char version[] __devinitconst =
- KERN_INFO DRV_NAME ".c:v1.10-LK" DRV_VERSION " " DRV_RELDATE
- " Written by Donald Becker\n";
+ "v1.10-LK" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker";
/* This driver was written to use PCI memory space. Some early versions
of the Rhine may only work correctly with I/O space accesses. */
@@ -495,14 +497,15 @@ static void rhine_set_vlan_cam_mask(void __iomem *ioaddr, u32 mask);
static void rhine_init_cam_filter(struct net_device *dev);
static void rhine_update_vcam(struct net_device *dev);
-#define RHINE_WAIT_FOR(condition) do { \
- int i=1024; \
- while (!(condition) && --i) \
- ; \
- if (debug > 1 && i < 512) \
- printk(KERN_INFO "%s: %4d cycles used @ %s:%d\n", \
- DRV_NAME, 1024-i, __func__, __LINE__); \
-} while(0)
+#define RHINE_WAIT_FOR(condition) \
+do { \
+ int i = 1024; \
+ while (!(condition) && --i) \
+ ; \
+ if (debug > 1 && i < 512) \
+ pr_info("%4d cycles used @ %s:%d\n", \
+ 1024 - i, __func__, __LINE__); \
+} while (0)
static inline u32 get_intr_status(struct net_device *dev)
{
@@ -571,8 +574,8 @@ static void rhine_power_init(struct net_device *dev)
default:
reason = "Unknown";
}
- printk(KERN_INFO "%s: Woke system up. Reason: %s.\n",
- DRV_NAME, reason);
+ netdev_info(dev, "Woke system up. Reason: %s\n",
+ reason);
}
}
}
@@ -586,8 +589,7 @@ static void rhine_chip_reset(struct net_device *dev)
IOSYNC;
if (ioread8(ioaddr + ChipCmd1) & Cmd1Reset) {
- printk(KERN_INFO "%s: Reset not complete yet. "
- "Trying harder.\n", DRV_NAME);
+ netdev_info(dev, "Reset not complete yet. Trying harder.\n");
/* Force reset */
if (rp->quirks & rqForceReset)
@@ -598,9 +600,9 @@ static void rhine_chip_reset(struct net_device *dev)
}
if (debug > 1)
- printk(KERN_INFO "%s: Reset %s.\n", dev->name,
- (ioread8(ioaddr + ChipCmd1) & Cmd1Reset) ?
- "failed" : "succeeded");
+ netdev_info(dev, "Reset %s\n",
+ (ioread8(ioaddr + ChipCmd1) & Cmd1Reset) ?
+ "failed" : "succeeded");
}
#ifdef USE_MMIO
@@ -728,9 +730,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
- static int printed_version;
- if (!printed_version++)
- printk(version);
+ pr_info_once("%s\n", version);
#endif
io_size = 256;
@@ -765,8 +765,8 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
/* this should always be supported */
rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc) {
- printk(KERN_ERR "32-bit PCI DMA addresses not supported by "
- "the card!?\n");
+ dev_err(&pdev->dev,
+ "32-bit PCI DMA addresses not supported by the card!?\n");
goto err_out;
}
@@ -774,7 +774,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
if ((pci_resource_len(pdev, 0) < io_size) ||
(pci_resource_len(pdev, 1) < io_size)) {
rc = -EIO;
- printk(KERN_ERR "Insufficient PCI resources, aborting\n");
+ dev_err(&pdev->dev, "Insufficient PCI resources, aborting\n");
goto err_out;
}
@@ -786,7 +786,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
dev = alloc_etherdev(sizeof(struct rhine_private));
if (!dev) {
rc = -ENOMEM;
- printk(KERN_ERR "alloc_etherdev failed\n");
+ dev_err(&pdev->dev, "alloc_etherdev failed\n");
goto err_out;
}
SET_NETDEV_DEV(dev, &pdev->dev);
@@ -804,8 +804,9 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
ioaddr = pci_iomap(pdev, bar, io_size);
if (!ioaddr) {
rc = -EIO;
- printk(KERN_ERR "ioremap failed for device %s, region 0x%X "
- "@ 0x%lX\n", pci_name(pdev), io_size, memaddr);
+ dev_err(&pdev->dev,
+ "ioremap failed for device %s, region 0x%X @ 0x%lX\n",
+ pci_name(pdev), io_size, memaddr);
goto err_out_free_res;
}
@@ -820,8 +821,9 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
unsigned char b = readb(ioaddr+reg);
if (a != b) {
rc = -EIO;
- printk(KERN_ERR "MMIO do not match PIO [%02x] "
- "(%02x != %02x)\n", reg, a, b);
+ dev_err(&pdev->dev,
+ "MMIO do not match PIO [%02x] (%02x != %02x)\n",
+ reg, a, b);
goto err_out_unmap;
}
}
@@ -836,13 +838,15 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
for (i = 0; i < 6; i++)
dev->dev_addr[i] = ioread8(ioaddr + StationAddr + i);
- memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
- if (!is_valid_ether_addr(dev->perm_addr)) {
- rc = -EIO;
- printk(KERN_ERR "Invalid MAC address\n");
- goto err_out_unmap;
+ if (!is_valid_ether_addr(dev->dev_addr)) {
+ /* Report it and use a random ethernet address instead */
+ netdev_err(dev, "Invalid MAC address: %pM\n", dev->dev_addr);
+ random_ether_addr(dev->dev_addr);
+ netdev_info(dev, "Using random MAC address: %pM\n",
+ dev->dev_addr);
}
+ memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
/* For Rhine-I/II, phy_id is loaded from EEPROM */
if (!phy_id)
@@ -878,14 +882,14 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
if (rc)
goto err_out_unmap;
- printk(KERN_INFO "%s: VIA %s at 0x%lx, %pM, IRQ %d.\n",
- dev->name, name,
+ netdev_info(dev, "VIA %s at 0x%lx, %pM, IRQ %d\n",
+ name,
#ifdef USE_MMIO
- memaddr,
+ memaddr,
#else
- (long)ioaddr,
+ (long)ioaddr,
#endif
- dev->dev_addr, pdev->irq);
+ dev->dev_addr, pdev->irq);
pci_set_drvdata(pdev, dev);
@@ -896,11 +900,11 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
mdio_write(dev, phy_id, MII_BMCR, mii_cmd);
if (mii_status != 0xffff && mii_status != 0x0000) {
rp->mii_if.advertising = mdio_read(dev, phy_id, 4);
- printk(KERN_INFO "%s: MII PHY found at address "
- "%d, status 0x%4.4x advertising %4.4x "
- "Link %4.4x.\n", dev->name, phy_id,
- mii_status, rp->mii_if.advertising,
- mdio_read(dev, phy_id, 5));
+ netdev_info(dev,
+ "MII PHY found at address %d, status 0x%04x advertising %04x Link %04x\n",
+ phy_id,
+ mii_status, rp->mii_if.advertising,
+ mdio_read(dev, phy_id, 5));
/* set IFF_RUNNING */
if (mii_status & BMSR_LSTATUS)
@@ -912,8 +916,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
}
rp->mii_if.phy_id = phy_id;
if (debug > 1 && avoid_D3)
- printk(KERN_INFO "%s: No D3 power state at shutdown.\n",
- dev->name);
+ netdev_info(dev, "No D3 power state at shutdown\n");
return 0;
@@ -938,7 +941,7 @@ static int alloc_ring(struct net_device* dev)
TX_RING_SIZE * sizeof(struct tx_desc),
&ring_dma);
if (!ring) {
- printk(KERN_ERR "Could not allocate DMA memory.\n");
+ netdev_err(dev, "Could not allocate DMA memory\n");
return -ENOMEM;
}
if (rp->quirks & rqRhineI) {
@@ -1098,8 +1101,8 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media)
iowrite8(ioread8(ioaddr + ChipCmd1) & ~Cmd1FDuplex,
ioaddr + ChipCmd1);
if (debug > 1)
- printk(KERN_INFO "%s: force_media %d, carrier %d\n", dev->name,
- rp->mii_if.force_media, netif_carrier_ok(dev));
+ netdev_info(dev, "force_media %d, carrier %d\n",
+ rp->mii_if.force_media, netif_carrier_ok(dev));
}
/* Called after status of force_media possibly changed */
@@ -1113,9 +1116,8 @@ static void rhine_set_carrier(struct mii_if_info *mii)
else /* Let MMI library update carrier status */
rhine_check_media(mii->dev, 0);
if (debug > 1)
- printk(KERN_INFO "%s: force_media %d, carrier %d\n",
- mii->dev->name, mii->force_media,
- netif_carrier_ok(mii->dev));
+ netdev_info(mii->dev, "force_media %d, carrier %d\n",
+ mii->force_media, netif_carrier_ok(mii->dev));
}
/**
@@ -1402,8 +1404,7 @@ static int rhine_open(struct net_device *dev)
return rc;
if (debug > 1)
- printk(KERN_DEBUG "%s: rhine_open() irq %d.\n",
- dev->name, rp->pdev->irq);
+ netdev_dbg(dev, "%s() irq %d\n", __func__, rp->pdev->irq);
rc = alloc_ring(dev);
if (rc) {
@@ -1415,10 +1416,9 @@ static int rhine_open(struct net_device *dev)
rhine_chip_reset(dev);
init_registers(dev);
if (debug > 2)
- printk(KERN_DEBUG "%s: Done rhine_open(), status %4.4x "
- "MII status: %4.4x.\n",
- dev->name, ioread16(ioaddr + ChipCmd),
- mdio_read(dev, rp->mii_if.phy_id, MII_BMSR));
+ netdev_dbg(dev, "%s() Done - status %04x MII status: %04x\n",
+ __func__, ioread16(ioaddr + ChipCmd),
+ mdio_read(dev, rp->mii_if.phy_id, MII_BMSR));
netif_start_queue(dev);
@@ -1461,10 +1461,9 @@ static void rhine_tx_timeout(struct net_device *dev)
struct rhine_private *rp = netdev_priv(dev);
void __iomem *ioaddr = rp->base;
- printk(KERN_WARNING "%s: Transmit timed out, status %4.4x, PHY status "
- "%4.4x, resetting...\n",
- dev->name, ioread16(ioaddr + IntrStatus),
- mdio_read(dev, rp->mii_if.phy_id, MII_BMSR));
+ netdev_warn(dev, "Transmit timed out, status %04x, PHY status %04x, resetting...\n",
+ ioread16(ioaddr + IntrStatus),
+ mdio_read(dev, rp->mii_if.phy_id, MII_BMSR));
schedule_work(&rp->reset_task);
}
@@ -1551,8 +1550,8 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
spin_unlock_irqrestore(&rp->lock, flags);
if (debug > 4) {
- printk(KERN_DEBUG "%s: Transmit frame #%d queued in slot %d.\n",
- dev->name, rp->cur_tx-1, entry);
+ netdev_dbg(dev, "Transmit frame #%d queued in slot %d\n",
+ rp->cur_tx-1, entry);
}
return NETDEV_TX_OK;
}
@@ -1578,8 +1577,8 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance)
IOSYNC;
if (debug > 4)
- printk(KERN_DEBUG "%s: Interrupt, status %8.8x.\n",
- dev->name, intr_status);
+ netdev_dbg(dev, "Interrupt, status %08x\n",
+ intr_status);
if (intr_status & (IntrRxDone | IntrRxErr | IntrRxDropped |
IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf)) {
@@ -1597,9 +1596,9 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance)
RHINE_WAIT_FOR(!(ioread8(ioaddr+ChipCmd) & CmdTxOn));
if (debug > 2 &&
ioread8(ioaddr+ChipCmd) & CmdTxOn)
- printk(KERN_WARNING "%s: "
- "rhine_interrupt() Tx engine "
- "still on.\n", dev->name);
+ netdev_warn(dev,
+ "%s: Tx engine still on\n",
+ __func__);
}
rhine_tx(dev);
}
@@ -1611,16 +1610,15 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance)
rhine_error(dev, intr_status);
if (--boguscnt < 0) {
- printk(KERN_WARNING "%s: Too much work at interrupt, "
- "status=%#8.8x.\n",
- dev->name, intr_status);
+ netdev_warn(dev, "Too much work at interrupt, status=%#08x\n",
+ intr_status);
break;
}
}
if (debug > 3)
- printk(KERN_DEBUG "%s: exiting interrupt, status=%8.8x.\n",
- dev->name, ioread16(ioaddr + IntrStatus));
+ netdev_dbg(dev, "exiting interrupt, status=%08x\n",
+ ioread16(ioaddr + IntrStatus));
return IRQ_RETVAL(handled);
}
@@ -1637,15 +1635,14 @@ static void rhine_tx(struct net_device *dev)
while (rp->dirty_tx != rp->cur_tx) {
txstatus = le32_to_cpu(rp->tx_ring[entry].tx_status);
if (debug > 6)
- printk(KERN_DEBUG "Tx scavenge %d status %8.8x.\n",
- entry, txstatus);
+ netdev_dbg(dev, "Tx scavenge %d status %08x\n",
+ entry, txstatus);
if (txstatus & DescOwn)
break;
if (txstatus & 0x8000) {
if (debug > 1)
- printk(KERN_DEBUG "%s: Transmit error, "
- "Tx status %8.8x.\n",
- dev->name, txstatus);
+ netdev_dbg(dev, "Transmit error, Tx status %08x\n",
+ txstatus);
dev->stats.tx_errors++;
if (txstatus & 0x0400)
dev->stats.tx_carrier_errors++;
@@ -1668,9 +1665,9 @@ static void rhine_tx(struct net_device *dev)
else
dev->stats.collisions += txstatus & 0x0F;
if (debug > 6)
- printk(KERN_DEBUG "collisions: %1.1x:%1.1x\n",
- (txstatus >> 3) & 0xF,
- txstatus & 0xF);
+ netdev_dbg(dev, "collisions: %1.1x:%1.1x\n",
+ (txstatus >> 3) & 0xF,
+ txstatus & 0xF);
dev->stats.tx_bytes += rp->tx_skbuff[entry]->len;
dev->stats.tx_packets++;
}
@@ -1703,7 +1700,7 @@ static void rhine_tx(struct net_device *dev)
static inline u16 rhine_get_vlan_tci(struct sk_buff *skb, int data_size)
{
u8 *trailer = (u8 *)skb->data + ((data_size + 3) & ~3) + 2;
- return ntohs(*(u16 *)trailer);
+ return be16_to_cpup((__be16 *)trailer);
}
/* Process up to limit frames from receive ring */
@@ -1714,9 +1711,9 @@ static int rhine_rx(struct net_device *dev, int limit)
int entry = rp->cur_rx % RX_RING_SIZE;
if (debug > 4) {
- printk(KERN_DEBUG "%s: rhine_rx(), entry %d status %8.8x.\n",
- dev->name, entry,
- le32_to_cpu(rp->rx_head_desc->rx_status));
+ netdev_dbg(dev, "%s(), entry %d status %08x\n",
+ __func__, entry,
+ le32_to_cpu(rp->rx_head_desc->rx_status));
}
/* If EOP is set on the next entry, it's a new packet. Send it up. */
@@ -1730,26 +1727,26 @@ static int rhine_rx(struct net_device *dev, int limit)
break;
if (debug > 4)
- printk(KERN_DEBUG "rhine_rx() status is %8.8x.\n",
- desc_status);
+ netdev_dbg(dev, "%s() status is %08x\n",
+ __func__, desc_status);
if ((desc_status & (RxWholePkt | RxErr)) != RxWholePkt) {
if ((desc_status & RxWholePkt) != RxWholePkt) {
- printk(KERN_WARNING "%s: Oversized Ethernet "
- "frame spanned multiple buffers, entry "
- "%#x length %d status %8.8x!\n",
- dev->name, entry, data_size,
- desc_status);
- printk(KERN_WARNING "%s: Oversized Ethernet "
- "frame %p vs %p.\n", dev->name,
- rp->rx_head_desc, &rp->rx_ring[entry]);
+ netdev_warn(dev,
+ "Oversized Ethernet frame spanned multiple buffers, "
+ "entry %#x length %d status %08x!\n",
+ entry, data_size,
+ desc_status);
+ netdev_warn(dev,
+ "Oversized Ethernet frame %p vs %p\n",
+ rp->rx_head_desc,
+ &rp->rx_ring[entry]);
dev->stats.rx_length_errors++;
} else if (desc_status & RxErr) {
/* There was a error. */
if (debug > 2)
- printk(KERN_DEBUG "rhine_rx() Rx "
- "error was %8.8x.\n",
- desc_status);
+ netdev_dbg(dev, "%s() Rx error was %08x\n",
+ __func__, desc_status);
dev->stats.rx_errors++;
if (desc_status & 0x0030)
dev->stats.rx_length_errors++;
@@ -1791,9 +1788,7 @@ static int rhine_rx(struct net_device *dev, int limit)
} else {
skb = rp->rx_skbuff[entry];
if (skb == NULL) {
- printk(KERN_ERR "%s: Inconsistent Rx "
- "descriptor chain.\n",
- dev->name);
+ netdev_err(dev, "Inconsistent Rx descriptor chain\n");
break;
}
rp->rx_skbuff[entry] = NULL;
@@ -1886,9 +1881,8 @@ static void rhine_restart_tx(struct net_device *dev) {
else {
/* This should never happen */
if (debug > 1)
- printk(KERN_WARNING "%s: rhine_restart_tx() "
- "Another error occurred %8.8x.\n",
- dev->name, intr_status);
+ netdev_warn(dev, "%s() Another error occurred %08x\n",
+ __func__, intr_status);
}
}
@@ -1909,21 +1903,19 @@ static void rhine_error(struct net_device *dev, int intr_status)
}
if (intr_status & IntrTxAborted) {
if (debug > 1)
- printk(KERN_INFO "%s: Abort %8.8x, frame dropped.\n",
- dev->name, intr_status);
+ netdev_info(dev, "Abort %08x, frame dropped\n",
+ intr_status);
}
if (intr_status & IntrTxUnderrun) {
if (rp->tx_thresh < 0xE0)
BYTE_REG_BITS_SET((rp->tx_thresh += 0x20), 0x80, ioaddr + TxConfig);
if (debug > 1)
- printk(KERN_INFO "%s: Transmitter underrun, Tx "
- "threshold now %2.2x.\n",
- dev->name, rp->tx_thresh);
+ netdev_info(dev, "Transmitter underrun, Tx threshold now %02x\n",
+ rp->tx_thresh);
}
if (intr_status & IntrTxDescRace) {
if (debug > 2)
- printk(KERN_INFO "%s: Tx descriptor write-back race.\n",
- dev->name);
+ netdev_info(dev, "Tx descriptor write-back race\n");
}
if ((intr_status & IntrTxError) &&
(intr_status & (IntrTxAborted |
@@ -1932,9 +1924,8 @@ static void rhine_error(struct net_device *dev, int intr_status)
BYTE_REG_BITS_SET((rp->tx_thresh += 0x20), 0x80, ioaddr + TxConfig);
}
if (debug > 1)
- printk(KERN_INFO "%s: Unspecified error. Tx "
- "threshold now %2.2x.\n",
- dev->name, rp->tx_thresh);
+ netdev_info(dev, "Unspecified error. Tx threshold now %02x\n",
+ rp->tx_thresh);
}
if (intr_status & (IntrTxAborted | IntrTxUnderrun | IntrTxDescRace |
IntrTxError))
@@ -1944,8 +1935,8 @@ static void rhine_error(struct net_device *dev, int intr_status)
IntrTxError | IntrTxAborted | IntrNormalSummary |
IntrTxDescRace)) {
if (debug > 1)
- printk(KERN_ERR "%s: Something Wicked happened! "
- "%8.8x.\n", dev->name, intr_status);
+ netdev_err(dev, "Something Wicked happened! %08x\n",
+ intr_status);
}
spin_unlock(&rp->lock);
@@ -2145,9 +2136,8 @@ static int rhine_close(struct net_device *dev)
spin_lock_irq(&rp->lock);
if (debug > 1)
- printk(KERN_DEBUG "%s: Shutting down ethercard, "
- "status was %4.4x.\n",
- dev->name, ioread16(ioaddr + ChipCmd));
+ netdev_dbg(dev, "Shutting down ethercard, status was %04x\n",
+ ioread16(ioaddr + ChipCmd));
/* Switch to loopback mode to avoid hardware races. */
iowrite8(rp->tx_thresh | 0x02, ioaddr + TxConfig);
@@ -2265,12 +2255,12 @@ static int rhine_resume(struct pci_dev *pdev)
return 0;
if (request_irq(dev->irq, rhine_interrupt, IRQF_SHARED, dev->name, dev))
- printk(KERN_ERR "via-rhine %s: request_irq failed\n", dev->name);
+ netdev_err(dev, "request_irq failed\n");
ret = pci_set_power_state(pdev, PCI_D0);
if (debug > 1)
- printk(KERN_INFO "%s: Entering power state D0 %s (%d).\n",
- dev->name, ret ? "failed" : "succeeded", ret);
+ netdev_info(dev, "Entering power state D0 %s (%d)\n",
+ ret ? "failed" : "succeeded", ret);
pci_restore_state(pdev);
@@ -2326,17 +2316,15 @@ static int __init rhine_init(void)
{
/* when a module, this is printed whether or not devices are found in probe */
#ifdef MODULE
- printk(version);
+ pr_info("%s\n", version);
#endif
if (dmi_check_system(rhine_dmi_table)) {
/* these BIOSes fail at PXE boot if chip is in D3 */
avoid_D3 = 1;
- printk(KERN_WARNING "%s: Broken BIOS detected, avoid_D3 "
- "enabled.\n",
- DRV_NAME);
+ pr_warn("Broken BIOS detected, avoid_D3 enabled\n");
}
else if (avoid_D3)
- printk(KERN_INFO "%s: avoid_D3 set.\n", DRV_NAME);
+ pr_info("avoid_D3 set\n");
return pci_register_driver(&rhine_driver);
}
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 4fe051753842..06daa9d6fee8 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -2600,8 +2600,7 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb,
/*
* Handle hardware checksum
*/
- if ((dev->features & NETIF_F_IP_CSUM) &&
- (skb->ip_summed == CHECKSUM_PARTIAL)) {
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
const struct iphdr *ip = ip_hdr(skb);
if (ip->protocol == IPPROTO_TCP)
td_ptr->tdesc1.TCR |= TCR0_TCPCK;
@@ -2841,6 +2840,7 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
dev->ethtool_ops = &velocity_ethtool_ops;
netif_napi_add(dev, &vptr->napi, velocity_poll, VELOCITY_NAPI_WEIGHT);
+ dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_HW_VLAN_TX;
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER |
NETIF_F_HW_VLAN_RX | NETIF_F_IP_CSUM;
@@ -3182,7 +3182,8 @@ static void velocity_ethtool_down(struct net_device *dev)
pci_set_power_state(vptr->pdev, PCI_D3hot);
}
-static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int velocity_get_settings(struct net_device *dev,
+ struct ethtool_cmd *cmd)
{
struct velocity_info *vptr = netdev_priv(dev);
struct mac_regs __iomem *regs = vptr->mac_regs;
@@ -3228,12 +3229,14 @@ static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd
break;
}
}
+
if (status & VELOCITY_SPEED_1000)
- cmd->speed = SPEED_1000;
+ ethtool_cmd_speed_set(cmd, SPEED_1000);
else if (status & VELOCITY_SPEED_100)
- cmd->speed = SPEED_100;
+ ethtool_cmd_speed_set(cmd, SPEED_100);
else
- cmd->speed = SPEED_10;
+ ethtool_cmd_speed_set(cmd, SPEED_10);
+
cmd->autoneg = (status & VELOCITY_AUTONEG_ENABLE) ? AUTONEG_ENABLE : AUTONEG_DISABLE;
cmd->port = PORT_TP;
cmd->transceiver = XCVR_INTERNAL;
@@ -3247,9 +3250,11 @@ static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd
return 0;
}
-static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int velocity_set_settings(struct net_device *dev,
+ struct ethtool_cmd *cmd)
{
struct velocity_info *vptr = netdev_priv(dev);
+ u32 speed = ethtool_cmd_speed(cmd);
u32 curr_status;
u32 new_status = 0;
int ret = 0;
@@ -3258,9 +3263,9 @@ static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd
curr_status &= (~VELOCITY_LINK_FAIL);
new_status |= ((cmd->autoneg) ? VELOCITY_AUTONEG_ENABLE : 0);
- new_status |= ((cmd->speed == SPEED_1000) ? VELOCITY_SPEED_1000 : 0);
- new_status |= ((cmd->speed == SPEED_100) ? VELOCITY_SPEED_100 : 0);
- new_status |= ((cmd->speed == SPEED_10) ? VELOCITY_SPEED_10 : 0);
+ new_status |= ((speed == SPEED_1000) ? VELOCITY_SPEED_1000 : 0);
+ new_status |= ((speed == SPEED_100) ? VELOCITY_SPEED_100 : 0);
+ new_status |= ((speed == SPEED_10) ? VELOCITY_SPEED_10 : 0);
new_status |= ((cmd->duplex == DUPLEX_FULL) ? VELOCITY_DUPLEX_FULL : 0);
if ((new_status & VELOCITY_AUTONEG_ENABLE) &&
@@ -3457,13 +3462,10 @@ static const struct ethtool_ops velocity_ethtool_ops = {
.get_settings = velocity_get_settings,
.set_settings = velocity_set_settings,
.get_drvinfo = velocity_get_drvinfo,
- .set_tx_csum = ethtool_op_set_tx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
.get_wol = velocity_ethtool_get_wol,
.set_wol = velocity_ethtool_set_wol,
.get_msglevel = velocity_get_msglevel,
.set_msglevel = velocity_set_msglevel,
- .set_sg = ethtool_op_set_sg,
.get_link = velocity_get_link,
.get_coalesce = velocity_get_coalesce,
.set_coalesce = velocity_set_coalesce,
diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
index d7227539484e..0f1f05f6c4f8 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/via-velocity.h
@@ -1096,7 +1096,7 @@ struct mac_regs {
volatile __le16 PatternCRC[8]; /* 0xB0 */
volatile __le32 ByteMask[4][4]; /* 0xC0 */
-} __packed;
+};
enum hw_mib {
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 82dba5aaf423..0cb0b0632672 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -710,17 +710,6 @@ static int virtnet_close(struct net_device *dev)
return 0;
}
-static int virtnet_set_tx_csum(struct net_device *dev, u32 data)
-{
- struct virtnet_info *vi = netdev_priv(dev);
- struct virtio_device *vdev = vi->vdev;
-
- if (data && !virtio_has_feature(vdev, VIRTIO_NET_F_CSUM))
- return -ENOSYS;
-
- return ethtool_op_set_tx_hw_csum(dev, data);
-}
-
static void virtnet_set_rx_mode(struct net_device *dev)
{
struct virtnet_info *vi = netdev_priv(dev);
@@ -822,10 +811,6 @@ static void virtnet_vlan_rx_kill_vid(struct net_device *dev, u16 vid)
}
static const struct ethtool_ops virtnet_ethtool_ops = {
- .set_tx_csum = virtnet_set_tx_csum,
- .set_sg = ethtool_op_set_sg,
- .set_tso = ethtool_op_set_tso,
- .set_ufo = ethtool_op_set_ufo,
.get_link = ethtool_op_get_link,
};
@@ -912,22 +897,29 @@ static int virtnet_probe(struct virtio_device *vdev)
SET_NETDEV_DEV(dev, &vdev->dev);
/* Do we support "hardware" checksums? */
- if (csum && virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) {
+ if (virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) {
/* This opens up the world of extra features. */
- dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
- if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
- dev->features |= NETIF_F_TSO | NETIF_F_UFO
+ dev->hw_features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
+ if (csum)
+ dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
+
+ if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
+ dev->hw_features |= NETIF_F_TSO | NETIF_F_UFO
| NETIF_F_TSO_ECN | NETIF_F_TSO6;
}
/* Individual feature bits: what can host handle? */
- if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO4))
- dev->features |= NETIF_F_TSO;
- if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO6))
- dev->features |= NETIF_F_TSO6;
- if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
- dev->features |= NETIF_F_TSO_ECN;
- if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UFO))
- dev->features |= NETIF_F_UFO;
+ if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO4))
+ dev->hw_features |= NETIF_F_TSO;
+ if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO6))
+ dev->hw_features |= NETIF_F_TSO6;
+ if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
+ dev->hw_features |= NETIF_F_TSO_ECN;
+ if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UFO))
+ dev->hw_features |= NETIF_F_UFO;
+
+ if (gso)
+ dev->features |= dev->hw_features & (NETIF_F_ALL_TSO|NETIF_F_UFO);
+ /* (!csum && gso) case will be fixed by register_netdev() */
}
/* Configuration may specify what MAC to use. Otherwise random. */
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index c16ed961153a..fa6e2ac7475a 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -1083,7 +1083,7 @@ vmxnet3_rx_csum(struct vmxnet3_adapter *adapter,
struct sk_buff *skb,
union Vmxnet3_GenericDesc *gdesc)
{
- if (!gdesc->rcd.cnc && adapter->rxcsum) {
+ if (!gdesc->rcd.cnc && adapter->netdev->features & NETIF_F_RXCSUM) {
/* typical case: TCP/UDP over IP and both csums are correct */
if ((le32_to_cpu(gdesc->dword[3]) & VMXNET3_RCD_CSUM_OK) ==
VMXNET3_RCD_CSUM_OK) {
@@ -2082,10 +2082,10 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)
devRead->misc.ddLen = cpu_to_le32(sizeof(struct vmxnet3_adapter));
/* set up feature flags */
- if (adapter->rxcsum)
+ if (adapter->netdev->features & NETIF_F_RXCSUM)
devRead->misc.uptFeatures |= UPT1_F_RXCSUM;
- if (adapter->lro) {
+ if (adapter->netdev->features & NETIF_F_LRO) {
devRead->misc.uptFeatures |= UPT1_F_LRO;
devRead->misc.maxNumRxSG = cpu_to_le16(1 + MAX_SKB_FRAGS);
}
@@ -2594,9 +2594,6 @@ vmxnet3_change_mtu(struct net_device *netdev, int new_mtu)
if (new_mtu < VMXNET3_MIN_MTU || new_mtu > VMXNET3_MAX_MTU)
return -EINVAL;
- if (new_mtu > 1500 && !adapter->jumbo_frame)
- return -EINVAL;
-
netdev->mtu = new_mtu;
/*
@@ -2642,28 +2639,18 @@ vmxnet3_declare_features(struct vmxnet3_adapter *adapter, bool dma64)
{
struct net_device *netdev = adapter->netdev;
- netdev->features = NETIF_F_SG |
- NETIF_F_HW_CSUM |
- NETIF_F_HW_VLAN_TX |
- NETIF_F_HW_VLAN_RX |
- NETIF_F_HW_VLAN_FILTER |
- NETIF_F_TSO |
- NETIF_F_TSO6 |
- NETIF_F_LRO;
-
- printk(KERN_INFO "features: sg csum vlan jf tso tsoIPv6 lro");
-
- adapter->rxcsum = true;
- adapter->jumbo_frame = true;
- adapter->lro = true;
-
- if (dma64) {
+ netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM |
+ NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_TX |
+ NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_LRO;
+ if (dma64)
netdev->features |= NETIF_F_HIGHDMA;
- printk(" highDMA");
- }
+ netdev->vlan_features = netdev->hw_features & ~NETIF_F_HW_VLAN_TX;
+ netdev->features = netdev->hw_features |
+ NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
- netdev->vlan_features = netdev->features;
- printk("\n");
+ netdev_info(adapter->netdev,
+ "features: sg csum vlan jf tso tsoIPv6 lro%s\n",
+ dma64 ? " highDMA" : "");
}
@@ -2876,6 +2863,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,
.ndo_start_xmit = vmxnet3_xmit_frame,
.ndo_set_mac_address = vmxnet3_set_mac_addr,
.ndo_change_mtu = vmxnet3_change_mtu,
+ .ndo_set_features = vmxnet3_set_features,
.ndo_get_stats = vmxnet3_get_stats,
.ndo_tx_timeout = vmxnet3_tx_timeout,
.ndo_set_multicast_list = vmxnet3_set_mc,
@@ -2896,6 +2884,9 @@ vmxnet3_probe_device(struct pci_dev *pdev,
int num_tx_queues;
int num_rx_queues;
+ if (!pci_msi_enabled())
+ enable_mq = 0;
+
#ifdef VMXNET3_RSS
if (enable_mq)
num_rx_queues = min(VMXNET3_DEVICE_MAX_RX_QUEUES,
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
index 976467253d20..dc959fe27aa5 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethtool.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -33,40 +33,6 @@ struct vmxnet3_stat_desc {
};
-static u32
-vmxnet3_get_rx_csum(struct net_device *netdev)
-{
- struct vmxnet3_adapter *adapter = netdev_priv(netdev);
- return adapter->rxcsum;
-}
-
-
-static int
-vmxnet3_set_rx_csum(struct net_device *netdev, u32 val)
-{
- struct vmxnet3_adapter *adapter = netdev_priv(netdev);
- unsigned long flags;
-
- if (adapter->rxcsum != val) {
- adapter->rxcsum = val;
- if (netif_running(netdev)) {
- if (val)
- adapter->shared->devRead.misc.uptFeatures |=
- UPT1_F_RXCSUM;
- else
- adapter->shared->devRead.misc.uptFeatures &=
- ~UPT1_F_RXCSUM;
-
- spin_lock_irqsave(&adapter->cmd_lock, flags);
- VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
- VMXNET3_CMD_UPDATE_FEATURE);
- spin_unlock_irqrestore(&adapter->cmd_lock, flags);
- }
- }
- return 0;
-}
-
-
/* per tq stats maintained by the device */
static const struct vmxnet3_stat_desc
vmxnet3_tq_dev_stats[] = {
@@ -296,31 +262,28 @@ vmxnet3_get_strings(struct net_device *netdev, u32 stringset, u8 *buf)
}
}
-static int
-vmxnet3_set_flags(struct net_device *netdev, u32 data)
+int vmxnet3_set_features(struct net_device *netdev, u32 features)
{
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;
unsigned long flags;
+ u32 changed = features ^ netdev->features;
- if (ethtool_invalid_flags(netdev, data, ETH_FLAG_LRO))
- return -EINVAL;
-
- if (lro_requested ^ lro_present) {
- /* toggle the LRO feature*/
- netdev->features ^= NETIF_F_LRO;
-
- /* Update private LRO flag */
- adapter->lro = lro_requested;
+ if (changed & (NETIF_F_RXCSUM|NETIF_F_LRO)) {
+ if (features & NETIF_F_RXCSUM)
+ adapter->shared->devRead.misc.uptFeatures |=
+ UPT1_F_RXCSUM;
+ else
+ adapter->shared->devRead.misc.uptFeatures &=
+ ~UPT1_F_RXCSUM;
/* update harware LRO capability accordingly */
- if (lro_requested)
+ if (features & NETIF_F_LRO)
adapter->shared->devRead.misc.uptFeatures |=
UPT1_F_LRO;
else
adapter->shared->devRead.misc.uptFeatures &=
~UPT1_F_LRO;
+
spin_lock_irqsave(&adapter->cmd_lock, flags);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
VMXNET3_CMD_UPDATE_FEATURE);
@@ -462,10 +425,10 @@ vmxnet3_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
ecmd->transceiver = XCVR_INTERNAL;
if (adapter->link_speed) {
- ecmd->speed = adapter->link_speed;
+ ethtool_cmd_speed_set(ecmd, adapter->link_speed);
ecmd->duplex = DUPLEX_FULL;
} else {
- ecmd->speed = -1;
+ ethtool_cmd_speed_set(ecmd, -1);
ecmd->duplex = -1;
}
return 0;
@@ -657,17 +620,7 @@ static struct ethtool_ops vmxnet3_ethtool_ops = {
.get_wol = vmxnet3_get_wol,
.set_wol = vmxnet3_set_wol,
.get_link = ethtool_op_get_link,
- .get_rx_csum = vmxnet3_get_rx_csum,
- .set_rx_csum = vmxnet3_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = ethtool_op_set_tx_hw_csum,
- .get_sg = ethtool_op_get_sg,
- .set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
- .set_tso = ethtool_op_set_tso,
.get_strings = vmxnet3_get_strings,
- .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,
.get_ringparam = vmxnet3_get_ringparam,
diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h
index fb5d245ac878..f50d36fdf405 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.25.0-k"
+#define VMXNET3_DRIVER_VERSION_STRING "1.1.9.0-k"
/* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
-#define VMXNET3_DRIVER_VERSION_NUM 0x01001900
+#define VMXNET3_DRIVER_VERSION_NUM 0x01010900
#if defined(CONFIG_PCI_MSI)
/* RSS only makes sense if MSI-X is supported. */
@@ -329,10 +329,6 @@ struct vmxnet3_adapter {
u8 __iomem *hw_addr0; /* for BAR 0 */
u8 __iomem *hw_addr1; /* for BAR 1 */
- /* feature control */
- bool rxcsum;
- bool lro;
- bool jumbo_frame;
#ifdef VMXNET3_RSS
struct UPT1_RSSConf *rss_conf;
bool rss;
@@ -404,6 +400,9 @@ void
vmxnet3_rq_destroy_all(struct vmxnet3_adapter *adapter);
int
+vmxnet3_set_features(struct net_device *netdev, u32 features);
+
+int
vmxnet3_create_queues(struct vmxnet3_adapter *adapter,
u32 tx_ring_size, u32 rx_ring_size, u32 rx_ring2_size);
diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c
index 401bebf59502..32763b2dd73f 100644
--- a/drivers/net/vxge/vxge-config.c
+++ b/drivers/net/vxge/vxge-config.c
@@ -159,16 +159,15 @@ vxge_hw_vpath_fw_api(struct __vxge_hw_virtualpath *vpath, u32 action,
u32 fw_memo, u32 offset, u64 *data0, u64 *data1,
u64 *steer_ctrl)
{
- struct vxge_hw_vpath_reg __iomem *vp_reg;
+ struct vxge_hw_vpath_reg __iomem *vp_reg = vpath->vp_reg;
enum vxge_hw_status status;
u64 val64;
- u32 retry = 0, max_retry = 100;
-
- vp_reg = vpath->vp_reg;
+ u32 retry = 0, max_retry = 3;
- if (vpath->vp_open) {
- max_retry = 3;
- spin_lock(&vpath->lock);
+ spin_lock(&vpath->lock);
+ if (!vpath->vp_open) {
+ spin_unlock(&vpath->lock);
+ max_retry = 100;
}
writeq(*data0, &vp_reg->rts_access_steer_data0);
@@ -1000,7 +999,7 @@ exit:
/**
* vxge_hw_device_hw_info_get - Get the hw information
* Returns the vpath mask that has the bits set for each vpath allocated
- * for the driver, FW version information and the first mac addresse for
+ * for the driver, FW version information, and the first mac address for
* each vpath
*/
enum vxge_hw_status __devinit
@@ -1064,9 +1063,10 @@ vxge_hw_device_hw_info_get(void __iomem *bar0,
val64 = readq(&toc->toc_vpath_pointer[i]);
+ spin_lock_init(&vpath.lock);
vpath.vp_reg = (struct vxge_hw_vpath_reg __iomem *)
(bar0 + val64);
- vpath.vp_open = 0;
+ vpath.vp_open = VXGE_HW_VP_NOT_OPEN;
status = __vxge_hw_vpath_pci_func_mode_get(&vpath, hw_info);
if (status != VXGE_HW_OK)
@@ -1090,7 +1090,7 @@ vxge_hw_device_hw_info_get(void __iomem *bar0,
val64 = readq(&toc->toc_vpath_pointer[i]);
vpath.vp_reg = (struct vxge_hw_vpath_reg __iomem *)
(bar0 + val64);
- vpath.vp_open = 0;
+ vpath.vp_open = VXGE_HW_VP_NOT_OPEN;
status = __vxge_hw_vpath_addr_get(&vpath,
hw_info->mac_addrs[i],
@@ -4646,7 +4646,27 @@ static void __vxge_hw_vp_terminate(struct __vxge_hw_device *hldev, u32 vp_id)
vpath->hldev->tim_int_mask1, vpath->vp_id);
hldev->stats.hw_dev_info_stats.vpath_info[vpath->vp_id] = NULL;
- memset(vpath, 0, sizeof(struct __vxge_hw_virtualpath));
+ /* If the whole struct __vxge_hw_virtualpath is zeroed, nothing will
+ * work after the interface is brought down.
+ */
+ spin_lock(&vpath->lock);
+ vpath->vp_open = VXGE_HW_VP_NOT_OPEN;
+ spin_unlock(&vpath->lock);
+
+ vpath->vpmgmt_reg = NULL;
+ vpath->nofl_db = NULL;
+ vpath->max_mtu = 0;
+ vpath->vsport_number = 0;
+ vpath->max_kdfc_db = 0;
+ vpath->max_nofl_db = 0;
+ vpath->ringh = NULL;
+ vpath->fifoh = NULL;
+ memset(&vpath->vpath_handles, 0, sizeof(struct list_head));
+ vpath->stats_block = 0;
+ vpath->hw_stats = NULL;
+ vpath->hw_stats_sav = NULL;
+ vpath->sw_stats = NULL;
+
exit:
return;
}
@@ -4670,7 +4690,7 @@ __vxge_hw_vp_initialize(struct __vxge_hw_device *hldev, u32 vp_id,
vpath = &hldev->virtual_paths[vp_id];
- spin_lock_init(&hldev->virtual_paths[vp_id].lock);
+ spin_lock_init(&vpath->lock);
vpath->vp_id = vp_id;
vpath->vp_open = VXGE_HW_VP_OPEN;
vpath->hldev = hldev;
@@ -5019,10 +5039,6 @@ enum vxge_hw_status vxge_hw_vpath_close(struct __vxge_hw_vpath_handle *vp)
__vxge_hw_vp_terminate(devh, vp_id);
- spin_lock(&vpath->lock);
- vpath->vp_open = VXGE_HW_VP_NOT_OPEN;
- spin_unlock(&vpath->lock);
-
vpath_close_exit:
return status;
}
diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h
index 3c53aa732c9d..359b9b9f8041 100644
--- a/drivers/net/vxge/vxge-config.h
+++ b/drivers/net/vxge/vxge-config.h
@@ -412,44 +412,48 @@ struct vxge_hw_vp_config {
* See also: struct vxge_hw_tim_intr_config{}.
*/
struct vxge_hw_device_config {
- u32 dma_blockpool_initial;
- u32 dma_blockpool_max;
-#define VXGE_HW_MIN_DMA_BLOCK_POOL_SIZE 0
-#define VXGE_HW_INITIAL_DMA_BLOCK_POOL_SIZE 0
-#define VXGE_HW_INCR_DMA_BLOCK_POOL_SIZE 4
-#define VXGE_HW_MAX_DMA_BLOCK_POOL_SIZE 4096
-
-#define VXGE_HW_MAX_PAYLOAD_SIZE_512 2
-
- u32 intr_mode;
-#define VXGE_HW_INTR_MODE_IRQLINE 0
-#define VXGE_HW_INTR_MODE_MSIX 1
-#define VXGE_HW_INTR_MODE_MSIX_ONE_SHOT 2
-
-#define VXGE_HW_INTR_MODE_DEF 0
-
- u32 rth_en;
-#define VXGE_HW_RTH_DISABLE 0
-#define VXGE_HW_RTH_ENABLE 1
-#define VXGE_HW_RTH_DEFAULT 0
-
- u32 rth_it_type;
-#define VXGE_HW_RTH_IT_TYPE_SOLO_IT 0
-#define VXGE_HW_RTH_IT_TYPE_MULTI_IT 1
-#define VXGE_HW_RTH_IT_TYPE_DEFAULT 0
-
- u32 rts_mac_en;
+ u32 device_poll_millis;
+#define VXGE_HW_MIN_DEVICE_POLL_MILLIS 1
+#define VXGE_HW_MAX_DEVICE_POLL_MILLIS 100000
+#define VXGE_HW_DEF_DEVICE_POLL_MILLIS 1000
+
+ u32 dma_blockpool_initial;
+ u32 dma_blockpool_max;
+#define VXGE_HW_MIN_DMA_BLOCK_POOL_SIZE 0
+#define VXGE_HW_INITIAL_DMA_BLOCK_POOL_SIZE 0
+#define VXGE_HW_INCR_DMA_BLOCK_POOL_SIZE 4
+#define VXGE_HW_MAX_DMA_BLOCK_POOL_SIZE 4096
+
+#define VXGE_HW_MAX_PAYLOAD_SIZE_512 2
+
+ u32 intr_mode:2,
+#define VXGE_HW_INTR_MODE_IRQLINE 0
+#define VXGE_HW_INTR_MODE_MSIX 1
+#define VXGE_HW_INTR_MODE_MSIX_ONE_SHOT 2
+
+#define VXGE_HW_INTR_MODE_DEF 0
+
+ rth_en:1,
+#define VXGE_HW_RTH_DISABLE 0
+#define VXGE_HW_RTH_ENABLE 1
+#define VXGE_HW_RTH_DEFAULT 0
+
+ rth_it_type:1,
+#define VXGE_HW_RTH_IT_TYPE_SOLO_IT 0
+#define VXGE_HW_RTH_IT_TYPE_MULTI_IT 1
+#define VXGE_HW_RTH_IT_TYPE_DEFAULT 0
+
+ rts_mac_en:1,
#define VXGE_HW_RTS_MAC_DISABLE 0
#define VXGE_HW_RTS_MAC_ENABLE 1
#define VXGE_HW_RTS_MAC_DEFAULT 0
- struct vxge_hw_vp_config vp_config[VXGE_HW_MAX_VIRTUAL_PATHS];
-
- u32 device_poll_millis;
-#define VXGE_HW_MIN_DEVICE_POLL_MILLIS 1
-#define VXGE_HW_MAX_DEVICE_POLL_MILLIS 100000
-#define VXGE_HW_DEF_DEVICE_POLL_MILLIS 1000
+ hwts_en:1;
+#define VXGE_HW_HWTS_DISABLE 0
+#define VXGE_HW_HWTS_ENABLE 1
+#define VXGE_HW_HWTS_DEFAULT 1
+ struct vxge_hw_vp_config vp_config[VXGE_HW_MAX_VIRTUAL_PATHS];
};
/**
diff --git a/drivers/net/vxge/vxge-ethtool.c b/drivers/net/vxge/vxge-ethtool.c
index c5eb034107fd..92dd72d3f9de 100644
--- a/drivers/net/vxge/vxge-ethtool.c
+++ b/drivers/net/vxge/vxge-ethtool.c
@@ -33,7 +33,8 @@ static int vxge_ethtool_sset(struct net_device *dev, struct ethtool_cmd *info)
{
/* We currently only support 10Gb/FULL */
if ((info->autoneg == AUTONEG_ENABLE) ||
- (info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL))
+ (ethtool_cmd_speed(info) != SPEED_10000) ||
+ (info->duplex != DUPLEX_FULL))
return -EINVAL;
return 0;
@@ -58,10 +59,10 @@ static int vxge_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
info->transceiver = XCVR_EXTERNAL;
if (netif_carrier_ok(dev)) {
- info->speed = SPEED_10000;
+ ethtool_cmd_speed_set(info, SPEED_10000);
info->duplex = DUPLEX_FULL;
} else {
- info->speed = -1;
+ ethtool_cmd_speed_set(info, -1);
info->duplex = -1;
}
@@ -134,22 +135,29 @@ static void vxge_ethtool_gregs(struct net_device *dev,
/**
* vxge_ethtool_idnic - To physically identify the nic on the system.
* @dev : device pointer.
- * @id : pointer to the structure with identification parameters given by
- * ethtool.
+ * @state : requested LED state
*
* Used to physically identify the NIC on the system.
- * The Link LED will blink for a time specified by the user.
- * Return value:
* 0 on success
*/
-static int vxge_ethtool_idnic(struct net_device *dev, u32 data)
+static int vxge_ethtool_idnic(struct net_device *dev,
+ enum ethtool_phys_id_state state)
{
struct vxgedev *vdev = netdev_priv(dev);
struct __vxge_hw_device *hldev = vdev->devh;
- vxge_hw_device_flick_link_led(hldev, VXGE_FLICKER_ON);
- msleep_interruptible(data ? (data * HZ) : VXGE_MAX_FLICKER_TIME);
- vxge_hw_device_flick_link_led(hldev, VXGE_FLICKER_OFF);
+ switch (state) {
+ case ETHTOOL_ID_ACTIVE:
+ vxge_hw_device_flick_link_led(hldev, VXGE_FLICKER_ON);
+ break;
+
+ case ETHTOOL_ID_INACTIVE:
+ vxge_hw_device_flick_link_led(hldev, VXGE_FLICKER_OFF);
+ break;
+
+ default:
+ return -EINVAL;
+ }
return 0;
}
@@ -1064,35 +1072,6 @@ static int vxge_ethtool_get_regs_len(struct net_device *dev)
return sizeof(struct vxge_hw_vpath_reg) * vdev->no_of_vpath;
}
-static u32 vxge_get_rx_csum(struct net_device *dev)
-{
- struct vxgedev *vdev = netdev_priv(dev);
-
- return vdev->rx_csum;
-}
-
-static int vxge_set_rx_csum(struct net_device *dev, u32 data)
-{
- struct vxgedev *vdev = netdev_priv(dev);
-
- if (data)
- vdev->rx_csum = 1;
- else
- vdev->rx_csum = 0;
-
- return 0;
-}
-
-static int vxge_ethtool_op_set_tso(struct net_device *dev, u32 data)
-{
- if (data)
- dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
- else
- dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
-
- return 0;
-}
-
static int vxge_ethtool_get_sset_count(struct net_device *dev, int sset)
{
struct vxgedev *vdev = netdev_priv(dev);
@@ -1112,40 +1091,6 @@ static int vxge_ethtool_get_sset_count(struct net_device *dev, int sset)
}
}
-static int vxge_set_flags(struct net_device *dev, u32 data)
-{
- struct vxgedev *vdev = netdev_priv(dev);
- enum vxge_hw_status status;
-
- if (ethtool_invalid_flags(dev, data, ETH_FLAG_RXHASH))
- return -EINVAL;
-
- if (!!(data & ETH_FLAG_RXHASH) == vdev->devh->config.rth_en)
- return 0;
-
- if (netif_running(dev) || (vdev->config.rth_steering == NO_STEERING))
- return -EINVAL;
-
- vdev->devh->config.rth_en = !!(data & ETH_FLAG_RXHASH);
-
- /* Enabling RTH requires some of the logic in vxge_device_register and a
- * vpath reset. Due to these restrictions, only allow modification
- * while the interface is down.
- */
- status = vxge_reset_all_vpaths(vdev);
- if (status != VXGE_HW_OK) {
- vdev->devh->config.rth_en = !vdev->devh->config.rth_en;
- return -EFAULT;
- }
-
- if (vdev->devh->config.rth_en)
- dev->features |= NETIF_F_RXHASH;
- else
- dev->features &= ~NETIF_F_RXHASH;
-
- return 0;
-}
-
static int vxge_fw_flash(struct net_device *dev, struct ethtool_flash *parms)
{
struct vxgedev *vdev = netdev_priv(dev);
@@ -1174,19 +1119,10 @@ static const struct ethtool_ops vxge_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_pauseparam = vxge_ethtool_getpause_data,
.set_pauseparam = vxge_ethtool_setpause_data,
- .get_rx_csum = vxge_get_rx_csum,
- .set_rx_csum = vxge_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = ethtool_op_set_tx_ipv6_csum,
- .get_sg = ethtool_op_get_sg,
- .set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
- .set_tso = vxge_ethtool_op_set_tso,
.get_strings = vxge_ethtool_get_strings,
- .phys_id = vxge_ethtool_idnic,
+ .set_phys_id = vxge_ethtool_idnic,
.get_sset_count = vxge_ethtool_get_sset_count,
.get_ethtool_stats = vxge_get_ethtool_stats,
- .set_flags = vxge_set_flags,
.flash_device = vxge_fw_flash,
};
diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c
index aff68c1118d4..8ab870a2ad02 100644
--- a/drivers/net/vxge/vxge-main.c
+++ b/drivers/net/vxge/vxge-main.c
@@ -52,6 +52,7 @@
#include <linux/etherdevice.h>
#include <linux/firmware.h>
#include <linux/net_tstamp.h>
+#include <linux/prefetch.h>
#include "vxge-main.h"
#include "vxge-reg.h"
@@ -304,22 +305,14 @@ vxge_rx_complete(struct vxge_ring *ring, struct sk_buff *skb, u16 vlan,
"%s: %s:%d skb protocol = %d",
ring->ndev->name, __func__, __LINE__, skb->protocol);
- if (ring->gro_enable) {
- if (ring->vlgrp && ext_info->vlan &&
- (ring->vlan_tag_strip ==
- VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE))
- vlan_gro_receive(ring->napi_p, ring->vlgrp,
- ext_info->vlan, skb);
- else
- napi_gro_receive(ring->napi_p, skb);
- } else {
- if (ring->vlgrp && vlan &&
- (ring->vlan_tag_strip ==
- VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE))
- vlan_hwaccel_receive_skb(skb, ring->vlgrp, vlan);
- else
- netif_receive_skb(skb);
- }
+ if (ring->vlgrp && ext_info->vlan &&
+ (ring->vlan_tag_strip ==
+ VXGE_HW_VPATH_RPA_STRIP_VLAN_TAG_ENABLE))
+ vlan_gro_receive(ring->napi_p, ring->vlgrp,
+ ext_info->vlan, skb);
+ else
+ napi_gro_receive(ring->napi_p, skb);
+
vxge_debug_entryexit(VXGE_TRACE,
"%s: %s:%d Exiting...", ring->ndev->name, __func__, __LINE__);
}
@@ -490,7 +483,7 @@ vxge_rx_1b_compl(struct __vxge_hw_ring *ringh, void *dtr,
if ((ext_info.proto & VXGE_HW_FRAME_PROTO_TCP_OR_UDP) &&
!(ext_info.proto & VXGE_HW_FRAME_PROTO_IP_FRAG) &&
- ring->rx_csum && /* Offload Rx side CSUM */
+ (dev->features & NETIF_F_RXCSUM) && /* Offload Rx side CSUM */
ext_info.l3_cksum == VXGE_HW_L3_CKSUM_OK &&
ext_info.l4_cksum == VXGE_HW_L4_CKSUM_OK)
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -2094,11 +2087,9 @@ static int vxge_open_vpaths(struct vxgedev *vdev)
vdev->config.fifo_indicate_max_pkts;
vpath->fifo.tx_vector_no = 0;
vpath->ring.rx_vector_no = 0;
- vpath->ring.rx_csum = vdev->rx_csum;
vpath->ring.rx_hwts = vdev->rx_hwts;
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 {
@@ -2670,6 +2661,40 @@ static void vxge_poll_vp_lockup(unsigned long data)
mod_timer(&vdev->vp_lockup_timer, jiffies + HZ / 1000);
}
+static u32 vxge_fix_features(struct net_device *dev, u32 features)
+{
+ u32 changed = dev->features ^ features;
+
+ /* Enabling RTH requires some of the logic in vxge_device_register and a
+ * vpath reset. Due to these restrictions, only allow modification
+ * while the interface is down.
+ */
+ if ((changed & NETIF_F_RXHASH) && netif_running(dev))
+ features ^= NETIF_F_RXHASH;
+
+ return features;
+}
+
+static int vxge_set_features(struct net_device *dev, u32 features)
+{
+ struct vxgedev *vdev = netdev_priv(dev);
+ u32 changed = dev->features ^ features;
+
+ if (!(changed & NETIF_F_RXHASH))
+ return 0;
+
+ /* !netif_running() ensured by vxge_fix_features() */
+
+ vdev->devh->config.rth_en = !!(features & NETIF_F_RXHASH);
+ if (vxge_reset_all_vpaths(vdev) != VXGE_HW_OK) {
+ dev->features = features ^ NETIF_F_RXHASH;
+ vdev->devh->config.rth_en = !!(dev->features & NETIF_F_RXHASH);
+ return -EIO;
+ }
+
+ return 0;
+}
+
/**
* vxge_open
* @dev: pointer to the device structure.
@@ -3112,8 +3137,7 @@ vxge_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats)
return net_stats;
}
-static enum vxge_hw_status vxge_timestamp_config(struct vxgedev *vdev,
- int enable)
+static enum vxge_hw_status vxge_timestamp_config(struct __vxge_hw_device *devh)
{
enum vxge_hw_status status;
u64 val64;
@@ -3123,27 +3147,24 @@ static enum vxge_hw_status vxge_timestamp_config(struct vxgedev *vdev,
* required for the driver to load (due to a hardware bug),
* there is no need to do anything special here.
*/
- if (enable)
- val64 = VXGE_HW_XMAC_TIMESTAMP_EN |
- VXGE_HW_XMAC_TIMESTAMP_USE_LINK_ID(0) |
- VXGE_HW_XMAC_TIMESTAMP_INTERVAL(0);
- else
- val64 = 0;
+ val64 = VXGE_HW_XMAC_TIMESTAMP_EN |
+ VXGE_HW_XMAC_TIMESTAMP_USE_LINK_ID(0) |
+ VXGE_HW_XMAC_TIMESTAMP_INTERVAL(0);
- status = vxge_hw_mgmt_reg_write(vdev->devh,
+ status = vxge_hw_mgmt_reg_write(devh,
vxge_hw_mgmt_reg_type_mrpcim,
0,
offsetof(struct vxge_hw_mrpcim_reg,
xmac_timestamp),
val64);
- vxge_hw_device_flush_io(vdev->devh);
+ vxge_hw_device_flush_io(devh);
+ devh->config.hwts_en = VXGE_HW_HWTS_ENABLE;
return status;
}
static int vxge_hwtstamp_ioctl(struct vxgedev *vdev, void __user *data)
{
struct hwtstamp_config config;
- enum vxge_hw_status status;
int i;
if (copy_from_user(&config, data, sizeof(config)))
@@ -3164,10 +3185,6 @@ static int vxge_hwtstamp_ioctl(struct vxgedev *vdev, void __user *data)
switch (config.rx_filter) {
case HWTSTAMP_FILTER_NONE:
- status = vxge_timestamp_config(vdev, 0);
- if (status != VXGE_HW_OK)
- return -EFAULT;
-
vdev->rx_hwts = 0;
config.rx_filter = HWTSTAMP_FILTER_NONE;
break;
@@ -3186,8 +3203,7 @@ static int vxge_hwtstamp_ioctl(struct vxgedev *vdev, void __user *data)
case HWTSTAMP_FILTER_PTP_V2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
- status = vxge_timestamp_config(vdev, 1);
- if (status != VXGE_HW_OK)
+ if (vdev->devh->config.hwts_en != VXGE_HW_HWTS_ENABLE)
return -EFAULT;
vdev->rx_hwts = 1;
@@ -3378,6 +3394,8 @@ static const struct net_device_ops vxge_netdev_ops = {
.ndo_do_ioctl = vxge_ioctl,
.ndo_set_mac_address = vxge_set_mac_addr,
.ndo_change_mtu = vxge_change_mtu,
+ .ndo_fix_features = vxge_fix_features,
+ .ndo_set_features = vxge_set_features,
.ndo_vlan_rx_register = vxge_vlan_rx_register,
.ndo_vlan_rx_kill_vid = vxge_vlan_rx_kill_vid,
.ndo_vlan_rx_add_vid = vxge_vlan_rx_add_vid,
@@ -3424,14 +3442,21 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev,
vdev->devh = hldev;
vdev->pdev = hldev->pdev;
memcpy(&vdev->config, config, sizeof(struct vxge_config));
- vdev->rx_csum = 1; /* Enable Rx CSUM by default. */
vdev->rx_hwts = 0;
vdev->titan1 = (vdev->pdev->revision == VXGE_HW_TITAN1_PCI_REVISION);
SET_NETDEV_DEV(ndev, &vdev->pdev->dev);
- ndev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
- NETIF_F_HW_VLAN_FILTER;
+ ndev->hw_features = NETIF_F_RXCSUM | NETIF_F_SG |
+ NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+ NETIF_F_TSO | NETIF_F_TSO6 |
+ NETIF_F_HW_VLAN_TX;
+ if (vdev->config.rth_steering != NO_STEERING)
+ ndev->hw_features |= NETIF_F_RXHASH;
+
+ ndev->features |= ndev->hw_features |
+ NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
+
/* Driver entry points */
ndev->irq = vdev->pdev->irq;
ndev->base_addr = (unsigned long) hldev->bar0;
@@ -3443,11 +3468,6 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev,
vxge_initialize_ethtool_ops(ndev);
- if (vdev->config.rth_steering != NO_STEERING) {
- ndev->features |= NETIF_F_RXHASH;
- hldev->config.rth_en = VXGE_HW_RTH_ENABLE;
- }
-
/* Allocate memory for vpath */
vdev->vpaths = kzalloc((sizeof(struct vxge_vpath)) *
no_of_vpath, GFP_KERNEL);
@@ -3459,9 +3479,6 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev,
goto _out1;
}
- ndev->features |= NETIF_F_SG;
-
- ndev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
vxge_debug_init(vxge_hw_device_trace_level_get(hldev),
"%s : checksuming enabled", __func__);
@@ -3471,11 +3488,6 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev,
"%s : using High DMA", __func__);
}
- ndev->features |= NETIF_F_TSO | NETIF_F_TSO6;
-
- if (vdev->config.gro_enable)
- ndev->features |= NETIF_F_GRO;
-
ret = register_netdev(ndev);
if (ret) {
vxge_debug_init(vxge_hw_device_trace_level_get(hldev),
@@ -4005,15 +4017,6 @@ static void __devinit vxge_print_parm(struct vxgedev *vdev, u64 vpath_mask)
vdev->config.tx_steering_type = 0;
}
- if (vdev->config.gro_enable) {
- vxge_debug_init(VXGE_ERR,
- "%s: Generic receive offload enabled",
- vdev->ndev->name);
- } else
- vxge_debug_init(VXGE_TRACE,
- "%s: Generic receive offload disabled",
- vdev->ndev->name);
-
if (vdev->config.addr_learn_en)
vxge_debug_init(VXGE_TRACE,
"%s: MAC Address learning enabled", vdev->ndev->name);
@@ -4575,12 +4578,29 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
goto _exit4;
}
+ /* Always enable HWTS. This will always cause the FCS to be invalid,
+ * due to the fact that HWTS is using the FCS as the location of the
+ * timestamp. The HW FCS checking will still correctly determine if
+ * there is a valid checksum, and the FCS is being removed by the driver
+ * anyway. So no fucntionality is being lost. Since it is always
+ * enabled, we now simply use the ioctl call to set whether or not the
+ * driver should be paying attention to the HWTS.
+ */
+ if (is_privileged == VXGE_HW_OK) {
+ status = vxge_timestamp_config(hldev);
+ if (status != VXGE_HW_OK) {
+ vxge_debug_init(VXGE_ERR, "%s: HWTS enable failed",
+ VXGE_DRIVER_NAME);
+ ret = -EFAULT;
+ goto _exit4;
+ }
+ }
+
vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_LL);
/* 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;
diff --git a/drivers/net/vxge/vxge-main.h b/drivers/net/vxge/vxge-main.h
index 40474f0da576..ed120aba443d 100644
--- a/drivers/net/vxge/vxge-main.h
+++ b/drivers/net/vxge/vxge-main.h
@@ -168,9 +168,6 @@ struct vxge_config {
#define NEW_NAPI_WEIGHT 64
int napi_weight;
-#define VXGE_GRO_DONOT_AGGREGATE 0
-#define VXGE_GRO_ALWAYS_AGGREGATE 1
- int gro_enable;
int intr_type;
#define INTA 0
#define MSI 1
@@ -290,13 +287,11 @@ struct vxge_ring {
unsigned long interrupt_count;
unsigned long jiffies;
- /* copy of the flag indicating whether rx_csum is to be used */
- u32 rx_csum:1,
- rx_hwts:1;
+ /* copy of the flag indicating whether rx_hwts is to be used */
+ u32 rx_hwts:1;
int pkts_processed;
int budget;
- int gro_enable;
struct napi_struct napi;
struct napi_struct *napi_p;
@@ -369,9 +364,8 @@ struct vxgedev {
*/
u16 all_multi_flg;
- /* A flag indicating whether rx_csum is to be used or not. */
- u32 rx_csum:1,
- rx_hwts:1,
+ /* A flag indicating whether rx_hwts is to be used or not. */
+ u32 rx_hwts:1,
titan1:1;
struct vxge_msix_entry *vxge_entries;
diff --git a/drivers/net/vxge/vxge-traffic.c b/drivers/net/vxge/vxge-traffic.c
index 2638b8d97b8f..f93517055162 100644
--- a/drivers/net/vxge/vxge-traffic.c
+++ b/drivers/net/vxge/vxge-traffic.c
@@ -12,6 +12,7 @@
* Copyright(c) 2002-2010 Exar Corp.
******************************************************************************/
#include <linux/etherdevice.h>
+#include <linux/prefetch.h>
#include "vxge-traffic.h"
#include "vxge-config.h"
diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h
index 6c2fc0b72af5..4a518a3b131c 100644
--- a/drivers/net/vxge/vxge-traffic.h
+++ b/drivers/net/vxge/vxge-traffic.h
@@ -240,7 +240,7 @@ struct vxge_hw_tim_intr_config {
u32 btimer_val;
#define VXGE_HW_MIN_TIM_BTIMER_VAL 0
#define VXGE_HW_MAX_TIM_BTIMER_VAL 67108864
-#define VXGE_HW_USE_FLASH_DEFAULT 0xffffffff
+#define VXGE_HW_USE_FLASH_DEFAULT (~0)
u32 timer_ac_en;
#define VXGE_HW_TIM_TIMER_AC_ENABLE 1
diff --git a/drivers/net/vxge/vxge-version.h b/drivers/net/vxge/vxge-version.h
index 581e21525e85..b9efa28bab3e 100644
--- a/drivers/net/vxge/vxge-version.h
+++ b/drivers/net/vxge/vxge-version.h
@@ -16,8 +16,8 @@
#define VXGE_VERSION_MAJOR "2"
#define VXGE_VERSION_MINOR "5"
-#define VXGE_VERSION_FIX "2"
-#define VXGE_VERSION_BUILD "22259"
+#define VXGE_VERSION_FIX "3"
+#define VXGE_VERSION_BUILD "22640"
#define VXGE_VERSION_FOR "k"
#define VXGE_FW_VER(maj, min, bld) (((maj) << 16) + ((min) << 8) + (bld))
diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c
index 1481a446fefb..21b104db5a90 100644
--- a/drivers/net/wan/dlci.c
+++ b/drivers/net/wan/dlci.c
@@ -341,10 +341,6 @@ static int dlci_add(struct dlci_add *dlci)
}
}
- err = dev_alloc_name(master, master->name);
- if (err < 0)
- goto err2;
-
*(short *)(master->dev_addr) = dlci->dlci;
dlp = netdev_priv(master);
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index 0edb535bb2b5..fc433f28c047 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -1070,7 +1070,7 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
hdlc_device *hdlc = dev_to_hdlc(frad);
pvc_device *pvc;
struct net_device *dev;
- int result, used;
+ int used;
if ((pvc = add_pvc(frad, dlci)) == NULL) {
printk(KERN_WARNING "%s: Memory squeeze on fr_add_pvc()\n",
@@ -1106,13 +1106,6 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
dev->tx_queue_len = 0;
dev->ml_priv = pvc;
- result = dev_alloc_name(dev, dev->name);
- if (result < 0) {
- free_netdev(dev);
- delete_unused_pvcs(hdlc);
- return result;
- }
-
if (register_netdevice(dev) != 0) {
free_netdev(dev);
delete_unused_pvcs(hdlc);
diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c
index 7f5bb913c8b9..eec463f99c09 100644
--- a/drivers/net/wan/lapbether.c
+++ b/drivers/net/wan/lapbether.c
@@ -338,10 +338,6 @@ static int lapbeth_new_device(struct net_device *dev)
dev_hold(dev);
lapbeth->ethdev = dev;
- rc = dev_alloc_name(ndev, ndev->name);
- if (rc < 0)
- goto fail;
-
rc = -EIO;
if (register_netdevice(ndev))
goto fail;
diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c
index f875cfae3093..9617d3d0ee39 100644
--- a/drivers/net/wan/pc300_drv.c
+++ b/drivers/net/wan/pc300_drv.c
@@ -1445,7 +1445,7 @@ static void falc_update_stats(pc300_t * card, int ch)
* Description: In the remote loopback mode the clock and data recovered
* from the line inputs RL1/2 or RDIP/RDIN are routed back
* to the line outputs XL1/2 or XDOP/XDON via the analog
- * transmitter. As in normal mode they are processsed by
+ * transmitter. As in normal mode they are processed by
* the synchronizer and then sent to the system interface.
*----------------------------------------------------------------------------
*/
@@ -3242,8 +3242,7 @@ static inline void show_version(void)
rcsdate++;
tmp = strrchr(rcsdate, ' ');
*tmp = '\0';
- printk(KERN_INFO "Cyclades-PC300 driver %s %s (built %s %s)\n",
- rcsvers, rcsdate, __DATE__, __TIME__);
+ printk(KERN_INFO "Cyclades-PC300 driver %s %s\n", rcsvers, rcsdate);
} /* show_version */
static const struct net_device_ops cpc_netdev_ops = {
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index 24297b274cd4..40398bf7d036 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -517,17 +517,18 @@ static int x25_asy_close(struct net_device *dev)
* and sent on to some IP layer for further processing.
*/
-static void x25_asy_receive_buf(struct tty_struct *tty,
+static unsigned int x25_asy_receive_buf(struct tty_struct *tty,
const unsigned char *cp, char *fp, int count)
{
struct x25_asy *sl = tty->disc_data;
+ int bytes = count;
if (!sl || sl->magic != X25_ASY_MAGIC || !netif_running(sl->dev))
return;
/* Read the characters out of the buffer */
- while (count--) {
+ while (bytes--) {
if (fp && *fp++) {
if (!test_and_set_bit(SLF_ERROR, &sl->flags))
sl->dev->stats.rx_errors++;
@@ -536,6 +537,8 @@ static void x25_asy_receive_buf(struct tty_struct *tty,
}
x25_asy_unesc(sl, *cp++);
}
+
+ return count;
}
/*
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 7aeb113cbb90..f354bd4e121e 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -284,5 +284,6 @@ source "drivers/net/wireless/rtlwifi/Kconfig"
source "drivers/net/wireless/wl1251/Kconfig"
source "drivers/net/wireless/wl12xx/Kconfig"
source "drivers/net/wireless/zd1211rw/Kconfig"
+source "drivers/net/wireless/mwifiex/Kconfig"
endif # WLAN
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index ddd3fb6ba1d3..7bba6a82b875 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -56,3 +56,5 @@ obj-$(CONFIG_WL12XX) += wl12xx/
obj-$(CONFIG_WL12XX_PLATFORM_DATA) += wl12xx/
obj-$(CONFIG_IWM) += iwmc3200wifi/
+
+obj-$(CONFIG_MWIFIEX) += mwifiex/
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 4e5c7a11f04a..55cf71fbffe3 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -242,9 +242,8 @@ static int airo_perm = 0555;
static int proc_perm = 0644;
MODULE_AUTHOR("Benjamin Reed");
-MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet \
-cards. Direct support for ISA/PCI/MPI cards and support \
-for PCMCIA when used with airo_cs.");
+MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet cards. "
+ "Direct support for ISA/PCI/MPI cards and support for PCMCIA when used with airo_cs.");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340/350");
module_param_array(io, int, NULL, 0);
@@ -252,18 +251,20 @@ module_param_array(irq, int, NULL, 0);
module_param_array(rates, int, NULL, 0);
module_param_array(ssids, charp, NULL, 0);
module_param(auto_wep, int, 0);
-MODULE_PARM_DESC(auto_wep, "If non-zero, the driver will keep looping through \
-the authentication options until an association is made. The value of \
-auto_wep is number of the wep keys to check. A value of 2 will try using \
-the key at index 0 and index 1.");
+MODULE_PARM_DESC(auto_wep,
+ "If non-zero, the driver will keep looping through the authentication options until an association is made. "
+ "The value of auto_wep is number of the wep keys to check. "
+ "A value of 2 will try using the key at index 0 and index 1.");
module_param(aux_bap, int, 0);
-MODULE_PARM_DESC(aux_bap, "If non-zero, the driver will switch into a mode \
-than seems to work better for older cards with some older buses. Before \
-switching it checks that the switch is needed.");
+MODULE_PARM_DESC(aux_bap,
+ "If non-zero, the driver will switch into a mode that seems to work better for older cards with some older buses. "
+ "Before switching it checks that the switch is needed.");
module_param(maxencrypt, int, 0);
-MODULE_PARM_DESC(maxencrypt, "The maximum speed that the card can do \
-encryption. Units are in 512kbs. Zero (default) means there is no limit. \
-Older cards used to be limited to 2mbs (4).");
+MODULE_PARM_DESC(maxencrypt,
+ "The maximum speed that the card can do encryption. "
+ "Units are in 512kbs. "
+ "Zero (default) means there is no limit. "
+ "Older cards used to be limited to 2mbs (4).");
module_param(adhoc, int, 0);
MODULE_PARM_DESC(adhoc, "If non-zero, the card will start in adhoc mode.");
module_param(probe, int, 0);
@@ -4500,17 +4501,15 @@ static int setup_proc_entry( struct net_device *dev,
struct proc_dir_entry *entry;
/* First setup the device directory */
strcpy(apriv->proc_name,dev->name);
- apriv->proc_entry = create_proc_entry(apriv->proc_name,
- S_IFDIR|airo_perm,
- airo_entry);
+ apriv->proc_entry = proc_mkdir_mode(apriv->proc_name, airo_perm,
+ airo_entry);
if (!apriv->proc_entry)
goto fail;
apriv->proc_entry->uid = proc_uid;
apriv->proc_entry->gid = proc_gid;
/* Setup the StatsDelta */
- entry = proc_create_data("StatsDelta",
- S_IFREG | (S_IRUGO&proc_perm),
+ entry = proc_create_data("StatsDelta", S_IRUGO & proc_perm,
apriv->proc_entry, &proc_statsdelta_ops, dev);
if (!entry)
goto fail_stats_delta;
@@ -4518,8 +4517,7 @@ static int setup_proc_entry( struct net_device *dev,
entry->gid = proc_gid;
/* Setup the Stats */
- entry = proc_create_data("Stats",
- S_IFREG | (S_IRUGO&proc_perm),
+ entry = proc_create_data("Stats", S_IRUGO & proc_perm,
apriv->proc_entry, &proc_stats_ops, dev);
if (!entry)
goto fail_stats;
@@ -4527,8 +4525,7 @@ static int setup_proc_entry( struct net_device *dev,
entry->gid = proc_gid;
/* Setup the Status */
- entry = proc_create_data("Status",
- S_IFREG | (S_IRUGO&proc_perm),
+ entry = proc_create_data("Status", S_IRUGO & proc_perm,
apriv->proc_entry, &proc_status_ops, dev);
if (!entry)
goto fail_status;
@@ -4536,8 +4533,7 @@ static int setup_proc_entry( struct net_device *dev,
entry->gid = proc_gid;
/* Setup the Config */
- entry = proc_create_data("Config",
- S_IFREG | proc_perm,
+ entry = proc_create_data("Config", proc_perm,
apriv->proc_entry, &proc_config_ops, dev);
if (!entry)
goto fail_config;
@@ -4545,8 +4541,7 @@ static int setup_proc_entry( struct net_device *dev,
entry->gid = proc_gid;
/* Setup the SSID */
- entry = proc_create_data("SSID",
- S_IFREG | proc_perm,
+ entry = proc_create_data("SSID", proc_perm,
apriv->proc_entry, &proc_SSID_ops, dev);
if (!entry)
goto fail_ssid;
@@ -4554,8 +4549,7 @@ static int setup_proc_entry( struct net_device *dev,
entry->gid = proc_gid;
/* Setup the APList */
- entry = proc_create_data("APList",
- S_IFREG | proc_perm,
+ entry = proc_create_data("APList", proc_perm,
apriv->proc_entry, &proc_APList_ops, dev);
if (!entry)
goto fail_aplist;
@@ -4563,8 +4557,7 @@ static int setup_proc_entry( struct net_device *dev,
entry->gid = proc_gid;
/* Setup the BSSList */
- entry = proc_create_data("BSSList",
- S_IFREG | proc_perm,
+ entry = proc_create_data("BSSList", proc_perm,
apriv->proc_entry, &proc_BSSList_ops, dev);
if (!entry)
goto fail_bsslist;
@@ -4572,8 +4565,7 @@ static int setup_proc_entry( struct net_device *dev,
entry->gid = proc_gid;
/* Setup the WepKey */
- entry = proc_create_data("WepKey",
- S_IFREG | proc_perm,
+ entry = proc_create_data("WepKey", proc_perm,
apriv->proc_entry, &proc_wepkey_ops, dev);
if (!entry)
goto fail_wepkey;
@@ -5705,9 +5697,7 @@ static int __init airo_init_module( void )
{
int i;
- airo_entry = create_proc_entry("driver/aironet",
- S_IFDIR | airo_perm,
- NULL);
+ airo_entry = proc_mkdir_mode("driver/aironet", airo_perm, NULL);
if (airo_entry) {
airo_entry->uid = proc_uid;
diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c
index df2484d45474..c983c10e0f6a 100644
--- a/drivers/net/wireless/airo_cs.c
+++ b/drivers/net/wireless/airo_cs.c
@@ -164,7 +164,7 @@ static int airo_resume(struct pcmcia_device *link)
return 0;
}
-static struct pcmcia_device_id airo_ids[] = {
+static const struct pcmcia_device_id airo_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x015f, 0x000a),
PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0005),
PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0007),
diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig
index 92c216263ee9..d1b23067619f 100644
--- a/drivers/net/wireless/ath/Kconfig
+++ b/drivers/net/wireless/ath/Kconfig
@@ -24,7 +24,6 @@ config ATH_DEBUG
source "drivers/net/wireless/ath/ath5k/Kconfig"
source "drivers/net/wireless/ath/ath9k/Kconfig"
-source "drivers/net/wireless/ath/ar9170/Kconfig"
source "drivers/net/wireless/ath/carl9170/Kconfig"
endif
diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile
index 6d711ec97ec2..0e8f528c81c0 100644
--- a/drivers/net/wireless/ath/Makefile
+++ b/drivers/net/wireless/ath/Makefile
@@ -1,6 +1,5 @@
obj-$(CONFIG_ATH5K) += ath5k/
obj-$(CONFIG_ATH9K_HW) += ath9k/
-obj-$(CONFIG_AR9170_USB) += ar9170/
obj-$(CONFIG_CARL9170) += carl9170/
obj-$(CONFIG_ATH_COMMON) += ath.o
diff --git a/drivers/net/wireless/ath/ar9170/Kconfig b/drivers/net/wireless/ath/ar9170/Kconfig
deleted file mode 100644
index 7b9672b0d090..000000000000
--- a/drivers/net/wireless/ath/ar9170/Kconfig
+++ /dev/null
@@ -1,20 +0,0 @@
-config AR9170_USB
- tristate "Atheros AR9170 802.11n USB support (OBSOLETE)"
- depends on USB && MAC80211
- select FW_LOADER
- help
- This driver is going to get replaced by carl9170.
-
- This is a driver for the Atheros "otus" 802.11n USB devices.
-
- These devices require additional firmware (2 files).
- For now, these files can be downloaded from here:
-
- http://wireless.kernel.org/en/users/Drivers/ar9170
-
- If you choose to build a module, it'll be called ar9170usb.
-
-config AR9170_LEDS
- bool
- depends on AR9170_USB && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = AR9170_USB)
- default y
diff --git a/drivers/net/wireless/ath/ar9170/Makefile b/drivers/net/wireless/ath/ar9170/Makefile
deleted file mode 100644
index 8d91c7ee3215..000000000000
--- a/drivers/net/wireless/ath/ar9170/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-ar9170usb-objs := usb.o main.o cmd.o mac.o phy.o led.o
-
-obj-$(CONFIG_AR9170_USB) += ar9170usb.o
diff --git a/drivers/net/wireless/ath/ar9170/ar9170.h b/drivers/net/wireless/ath/ar9170/ar9170.h
deleted file mode 100644
index 371e4ce49528..000000000000
--- a/drivers/net/wireless/ath/ar9170/ar9170.h
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Atheros AR9170 driver
- *
- * Driver specific definitions
- *
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License 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; see the file COPYING. If not, see
- * http://www.gnu.org/licenses/.
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- * Copyright (c) 2007-2008 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 __AR9170_H
-#define __AR9170_H
-
-#include <linux/completion.h>
-#include <linux/spinlock.h>
-#include <net/cfg80211.h>
-#include <net/mac80211.h>
-#ifdef CONFIG_AR9170_LEDS
-#include <linux/leds.h>
-#endif /* CONFIG_AR9170_LEDS */
-#include "eeprom.h"
-#include "hw.h"
-
-#include "../regd.h"
-
-#define PAYLOAD_MAX (AR9170_MAX_CMD_LEN/4 - 1)
-
-enum ar9170_bw {
- AR9170_BW_20,
- AR9170_BW_40_BELOW,
- AR9170_BW_40_ABOVE,
-
- __AR9170_NUM_BW,
-};
-
-static inline enum ar9170_bw nl80211_to_ar9170(enum nl80211_channel_type type)
-{
- switch (type) {
- case NL80211_CHAN_NO_HT:
- case NL80211_CHAN_HT20:
- return AR9170_BW_20;
- case NL80211_CHAN_HT40MINUS:
- return AR9170_BW_40_BELOW;
- case NL80211_CHAN_HT40PLUS:
- return AR9170_BW_40_ABOVE;
- default:
- BUG();
- }
-}
-
-enum ar9170_rf_init_mode {
- AR9170_RFI_NONE,
- AR9170_RFI_WARM,
- AR9170_RFI_COLD,
-};
-
-#define AR9170_MAX_RX_BUFFER_SIZE 8192
-
-#ifdef CONFIG_AR9170_LEDS
-struct ar9170;
-
-struct ar9170_led {
- struct ar9170 *ar;
- struct led_classdev l;
- char name[32];
- unsigned int toggled;
- bool last_state;
- bool registered;
-};
-
-#endif /* CONFIG_AR9170_LEDS */
-
-enum ar9170_device_state {
- AR9170_UNKNOWN_STATE,
- AR9170_STOPPED,
- AR9170_IDLE,
- AR9170_STARTED,
-};
-
-struct ar9170_rxstream_mpdu_merge {
- struct ar9170_rx_head plcp;
- bool has_plcp;
-};
-
-struct ar9170_tx_queue_stats {
- unsigned int len;
- unsigned int limit;
- unsigned int count;
-};
-
-#define AR9170_QUEUE_TIMEOUT 64
-#define AR9170_TX_TIMEOUT 8
-#define AR9170_JANITOR_DELAY 128
-#define AR9170_TX_INVALID_RATE 0xffffffff
-
-#define AR9170_NUM_TX_LIMIT_HARD AR9170_TXQ_DEPTH
-#define AR9170_NUM_TX_LIMIT_SOFT (AR9170_TXQ_DEPTH - 10)
-
-struct ar9170 {
- struct ieee80211_hw *hw;
- struct ath_common common;
- struct mutex mutex;
- enum ar9170_device_state state;
- bool registered;
- unsigned long bad_hw_nagger;
-
- int (*open)(struct ar9170 *);
- void (*stop)(struct ar9170 *);
- int (*tx)(struct ar9170 *, struct sk_buff *);
- int (*exec_cmd)(struct ar9170 *, enum ar9170_cmd, u32 ,
- void *, u32 , void *);
- void (*callback_cmd)(struct ar9170 *, u32 , void *);
- int (*flush)(struct ar9170 *);
-
- /* interface mode settings */
- struct ieee80211_vif *vif;
-
- /* beaconing */
- struct sk_buff *beacon;
- struct work_struct beacon_work;
- bool enable_beacon;
-
- /* cryptographic engine */
- u64 usedkeys;
- bool rx_software_decryption;
- bool disable_offload;
-
- /* filter settings */
- u64 cur_mc_hash;
- u32 cur_filter;
- unsigned int filter_state;
- bool sniffer_enabled;
-
- /* PHY */
- struct ieee80211_channel *channel;
- int noise[4];
-
- /* power calibration data */
- u8 power_5G_leg[4];
- u8 power_2G_cck[4];
- u8 power_2G_ofdm[4];
- u8 power_5G_ht20[8];
- u8 power_5G_ht40[8];
- u8 power_2G_ht20[8];
- u8 power_2G_ht40[8];
-
- u8 phy_heavy_clip;
-
-#ifdef CONFIG_AR9170_LEDS
- struct delayed_work led_work;
- struct ar9170_led leds[AR9170_NUM_LEDS];
-#endif /* CONFIG_AR9170_LEDS */
-
- /* qos queue settings */
- spinlock_t tx_stats_lock;
- struct ar9170_tx_queue_stats tx_stats[5];
- struct ieee80211_tx_queue_params edcf[5];
-
- spinlock_t cmdlock;
- __le32 cmdbuf[PAYLOAD_MAX + 1];
-
- /* MAC statistics */
- struct ieee80211_low_level_stats stats;
-
- /* EEPROM */
- struct ar9170_eeprom eeprom;
-
- /* tx queues - as seen by hw - */
- struct sk_buff_head tx_pending[__AR9170_NUM_TXQ];
- struct sk_buff_head tx_status[__AR9170_NUM_TXQ];
- struct delayed_work tx_janitor;
-
- /* rxstream mpdu merge */
- struct ar9170_rxstream_mpdu_merge rx_mpdu;
- struct sk_buff *rx_failover;
- int rx_failover_missing;
-
- /* (cached) HW A-MPDU settings */
- u8 global_ampdu_density;
- u8 global_ampdu_factor;
-};
-
-struct ar9170_tx_info {
- unsigned long timeout;
-};
-
-#define IS_STARTED(a) (((struct ar9170 *)a)->state >= AR9170_STARTED)
-#define IS_ACCEPTING_CMD(a) (((struct ar9170 *)a)->state >= AR9170_IDLE)
-
-/* exported interface */
-void *ar9170_alloc(size_t priv_size);
-int ar9170_register(struct ar9170 *ar, struct device *pdev);
-void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb);
-void ar9170_unregister(struct ar9170 *ar);
-void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb);
-void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len);
-int ar9170_nag_limiter(struct ar9170 *ar);
-
-/* MAC */
-void ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
-int ar9170_init_mac(struct ar9170 *ar);
-int ar9170_set_qos(struct ar9170 *ar);
-int ar9170_update_multicast(struct ar9170 *ar, const u64 mc_hast);
-int ar9170_update_frame_filter(struct ar9170 *ar, const u32 filter);
-int ar9170_set_operating_mode(struct ar9170 *ar);
-int ar9170_set_beacon_timers(struct ar9170 *ar);
-int ar9170_set_dyn_sifs_ack(struct ar9170 *ar);
-int ar9170_set_slot_time(struct ar9170 *ar);
-int ar9170_set_basic_rates(struct ar9170 *ar);
-int ar9170_set_hwretry_limit(struct ar9170 *ar, u32 max_retry);
-int ar9170_update_beacon(struct ar9170 *ar);
-void ar9170_new_beacon(struct work_struct *work);
-int ar9170_upload_key(struct ar9170 *ar, u8 id, const u8 *mac, u8 ktype,
- u8 keyidx, u8 *keydata, int keylen);
-int ar9170_disable_key(struct ar9170 *ar, u8 id);
-
-/* LEDs */
-#ifdef CONFIG_AR9170_LEDS
-int ar9170_register_leds(struct ar9170 *ar);
-void ar9170_unregister_leds(struct ar9170 *ar);
-#endif /* CONFIG_AR9170_LEDS */
-int ar9170_init_leds(struct ar9170 *ar);
-int ar9170_set_leds_state(struct ar9170 *ar, u32 led_state);
-
-/* PHY / RF */
-int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band);
-int ar9170_init_rf(struct ar9170 *ar);
-int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
- enum ar9170_rf_init_mode rfi, enum ar9170_bw bw);
-
-#endif /* __AR9170_H */
diff --git a/drivers/net/wireless/ath/ar9170/cmd.c b/drivers/net/wireless/ath/ar9170/cmd.c
deleted file mode 100644
index 6452c5055a63..000000000000
--- a/drivers/net/wireless/ath/ar9170/cmd.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Atheros AR9170 driver
- *
- * Basic HW register/memory/command access functions
- *
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License 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; see the file COPYING. If not, see
- * http://www.gnu.org/licenses/.
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- * Copyright (c) 2007-2008 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 "ar9170.h"
-#include "cmd.h"
-
-int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len)
-{
- int err;
-
- if (unlikely(!IS_ACCEPTING_CMD(ar)))
- return 0;
-
- err = ar->exec_cmd(ar, AR9170_CMD_WMEM, len, (u8 *) data, 0, NULL);
- if (err)
- wiphy_debug(ar->hw->wiphy, "writing memory failed\n");
- return err;
-}
-
-int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val)
-{
- const __le32 buf[2] = {
- cpu_to_le32(reg),
- cpu_to_le32(val),
- };
- int err;
-
- if (unlikely(!IS_ACCEPTING_CMD(ar)))
- return 0;
-
- err = ar->exec_cmd(ar, AR9170_CMD_WREG, sizeof(buf),
- (u8 *) buf, 0, NULL);
- if (err)
- wiphy_debug(ar->hw->wiphy, "writing reg %#x (val %#x) failed\n",
- reg, val);
- return err;
-}
-
-int ar9170_read_mreg(struct ar9170 *ar, int nregs, const u32 *regs, u32 *out)
-{
- int i, err;
- __le32 *offs, *res;
-
- if (unlikely(!IS_ACCEPTING_CMD(ar)))
- return 0;
-
- /* abuse "out" for the register offsets, must be same length */
- offs = (__le32 *)out;
- for (i = 0; i < nregs; i++)
- offs[i] = cpu_to_le32(regs[i]);
-
- /* also use the same buffer for the input */
- res = (__le32 *)out;
-
- err = ar->exec_cmd(ar, AR9170_CMD_RREG,
- 4 * nregs, (u8 *)offs,
- 4 * nregs, (u8 *)res);
- if (err)
- return err;
-
- /* convert result to cpu endian */
- for (i = 0; i < nregs; i++)
- out[i] = le32_to_cpu(res[i]);
-
- return 0;
-}
-
-int ar9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val)
-{
- return ar9170_read_mreg(ar, 1, &reg, val);
-}
-
-int ar9170_echo_test(struct ar9170 *ar, u32 v)
-{
- __le32 echobuf = cpu_to_le32(v);
- __le32 echores;
- int err;
-
- if (unlikely(!IS_ACCEPTING_CMD(ar)))
- return -ENODEV;
-
- err = ar->exec_cmd(ar, AR9170_CMD_ECHO,
- 4, (u8 *)&echobuf,
- 4, (u8 *)&echores);
- if (err)
- return err;
-
- if (echobuf != echores)
- return -EINVAL;
-
- return 0;
-}
diff --git a/drivers/net/wireless/ath/ar9170/cmd.h b/drivers/net/wireless/ath/ar9170/cmd.h
deleted file mode 100644
index ec8134b4b949..000000000000
--- a/drivers/net/wireless/ath/ar9170/cmd.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Atheros AR9170 driver
- *
- * Basic HW register/memory/command access functions
- *
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License 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; see the file COPYING. If not, see
- * http://www.gnu.org/licenses/.
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- * Copyright (c) 2007-2008 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 __CMD_H
-#define __CMD_H
-
-#include "ar9170.h"
-
-/* basic HW access */
-int ar9170_write_mem(struct ar9170 *ar, const __le32 *data, size_t len);
-int ar9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val);
-int ar9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val);
-int ar9170_read_mreg(struct ar9170 *ar, int nregs, const u32 *regs, u32 *out);
-int ar9170_echo_test(struct ar9170 *ar, u32 v);
-
-/*
- * Macros to facilitate writing multiple registers in a single
- * write-combining USB command. Note that when the first group
- * fails the whole thing will fail without any others attempted,
- * but you won't know which write in the group failed.
- */
-#define ar9170_regwrite_begin(ar) \
-do { \
- int __nreg = 0, __err = 0; \
- struct ar9170 *__ar = ar;
-
-#define ar9170_regwrite(r, v) do { \
- __ar->cmdbuf[2 * __nreg + 1] = cpu_to_le32(r); \
- __ar->cmdbuf[2 * __nreg + 2] = cpu_to_le32(v); \
- __nreg++; \
- if ((__nreg >= PAYLOAD_MAX/2)) { \
- if (IS_ACCEPTING_CMD(__ar)) \
- __err = ar->exec_cmd(__ar, AR9170_CMD_WREG, \
- 8 * __nreg, \
- (u8 *) &__ar->cmdbuf[1], \
- 0, NULL); \
- __nreg = 0; \
- if (__err) \
- goto __regwrite_out; \
- } \
-} while (0)
-
-#define ar9170_regwrite_finish() \
-__regwrite_out : \
- if (__nreg) { \
- if (IS_ACCEPTING_CMD(__ar)) \
- __err = ar->exec_cmd(__ar, AR9170_CMD_WREG, \
- 8 * __nreg, \
- (u8 *) &__ar->cmdbuf[1], \
- 0, NULL); \
- __nreg = 0; \
- }
-
-#define ar9170_regwrite_result() \
- __err; \
-} while (0);
-
-#endif /* __CMD_H */
diff --git a/drivers/net/wireless/ath/ar9170/eeprom.h b/drivers/net/wireless/ath/ar9170/eeprom.h
deleted file mode 100644
index 6c4663883423..000000000000
--- a/drivers/net/wireless/ath/ar9170/eeprom.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Atheros AR9170 driver
- *
- * EEPROM layout
- *
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License 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; see the file COPYING. If not, see
- * http://www.gnu.org/licenses/.
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- * Copyright (c) 2007-2008 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 __AR9170_EEPROM_H
-#define __AR9170_EEPROM_H
-
-#define AR5416_MAX_CHAINS 2
-#define AR5416_MODAL_SPURS 5
-
-struct ar9170_eeprom_modal {
- __le32 antCtrlChain[AR5416_MAX_CHAINS];
- __le32 antCtrlCommon;
- s8 antennaGainCh[AR5416_MAX_CHAINS];
- u8 switchSettling;
- u8 txRxAttenCh[AR5416_MAX_CHAINS];
- u8 rxTxMarginCh[AR5416_MAX_CHAINS];
- s8 adcDesiredSize;
- s8 pgaDesiredSize;
- u8 xlnaGainCh[AR5416_MAX_CHAINS];
- u8 txEndToXpaOff;
- u8 txEndToRxOn;
- u8 txFrameToXpaOn;
- u8 thresh62;
- s8 noiseFloorThreshCh[AR5416_MAX_CHAINS];
- u8 xpdGain;
- u8 xpd;
- s8 iqCalICh[AR5416_MAX_CHAINS];
- s8 iqCalQCh[AR5416_MAX_CHAINS];
- u8 pdGainOverlap;
- u8 ob;
- u8 db;
- u8 xpaBiasLvl;
- u8 pwrDecreaseFor2Chain;
- u8 pwrDecreaseFor3Chain;
- u8 txFrameToDataStart;
- u8 txFrameToPaOn;
- u8 ht40PowerIncForPdadc;
- u8 bswAtten[AR5416_MAX_CHAINS];
- u8 bswMargin[AR5416_MAX_CHAINS];
- u8 swSettleHt40;
- u8 reserved[22];
- struct spur_channel {
- __le16 spurChan;
- u8 spurRangeLow;
- u8 spurRangeHigh;
- } __packed spur_channels[AR5416_MODAL_SPURS];
-} __packed;
-
-#define AR5416_NUM_PD_GAINS 4
-#define AR5416_PD_GAIN_ICEPTS 5
-
-struct ar9170_calibration_data_per_freq {
- u8 pwr_pdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
- u8 vpd_pdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS];
-} __packed;
-
-#define AR5416_NUM_5G_CAL_PIERS 8
-#define AR5416_NUM_2G_CAL_PIERS 4
-
-#define AR5416_NUM_5G_TARGET_PWRS 8
-#define AR5416_NUM_2G_CCK_TARGET_PWRS 3
-#define AR5416_NUM_2G_OFDM_TARGET_PWRS 4
-#define AR5416_MAX_NUM_TGT_PWRS 8
-
-struct ar9170_calibration_target_power_legacy {
- u8 freq;
- u8 power[4];
-} __packed;
-
-struct ar9170_calibration_target_power_ht {
- u8 freq;
- u8 power[8];
-} __packed;
-
-#define AR5416_NUM_CTLS 24
-
-struct ar9170_calctl_edges {
- u8 channel;
-#define AR9170_CALCTL_EDGE_FLAGS 0xC0
- u8 power_flags;
-} __packed;
-
-#define AR5416_NUM_BAND_EDGES 8
-
-struct ar9170_calctl_data {
- struct ar9170_calctl_edges
- control_edges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES];
-} __packed;
-
-
-struct ar9170_eeprom {
- __le16 length;
- __le16 checksum;
- __le16 version;
- u8 operating_flags;
-#define AR9170_OPFLAG_5GHZ 1
-#define AR9170_OPFLAG_2GHZ 2
- u8 misc;
- __le16 reg_domain[2];
- u8 mac_address[6];
- u8 rx_mask;
- u8 tx_mask;
- __le16 rf_silent;
- __le16 bluetooth_options;
- __le16 device_capabilities;
- __le32 build_number;
- u8 deviceType;
- u8 reserved[33];
-
- u8 customer_data[64];
-
- struct ar9170_eeprom_modal
- modal_header[2];
-
- u8 cal_freq_pier_5G[AR5416_NUM_5G_CAL_PIERS];
- u8 cal_freq_pier_2G[AR5416_NUM_2G_CAL_PIERS];
-
- struct ar9170_calibration_data_per_freq
- cal_pier_data_5G[AR5416_MAX_CHAINS][AR5416_NUM_5G_CAL_PIERS],
- cal_pier_data_2G[AR5416_MAX_CHAINS][AR5416_NUM_2G_CAL_PIERS];
-
- /* power calibration data */
- struct ar9170_calibration_target_power_legacy
- cal_tgt_pwr_5G[AR5416_NUM_5G_TARGET_PWRS];
- struct ar9170_calibration_target_power_ht
- cal_tgt_pwr_5G_ht20[AR5416_NUM_5G_TARGET_PWRS],
- cal_tgt_pwr_5G_ht40[AR5416_NUM_5G_TARGET_PWRS];
-
- struct ar9170_calibration_target_power_legacy
- cal_tgt_pwr_2G_cck[AR5416_NUM_2G_CCK_TARGET_PWRS],
- cal_tgt_pwr_2G_ofdm[AR5416_NUM_2G_OFDM_TARGET_PWRS];
- struct ar9170_calibration_target_power_ht
- cal_tgt_pwr_2G_ht20[AR5416_NUM_2G_OFDM_TARGET_PWRS],
- cal_tgt_pwr_2G_ht40[AR5416_NUM_2G_OFDM_TARGET_PWRS];
-
- /* conformance testing limits */
- u8 ctl_index[AR5416_NUM_CTLS];
- struct ar9170_calctl_data
- ctl_data[AR5416_NUM_CTLS];
-
- u8 pad;
- __le16 subsystem_id;
-} __packed;
-
-#endif /* __AR9170_EEPROM_H */
diff --git a/drivers/net/wireless/ath/ar9170/hw.h b/drivers/net/wireless/ath/ar9170/hw.h
deleted file mode 100644
index 06f1f3c951a4..000000000000
--- a/drivers/net/wireless/ath/ar9170/hw.h
+++ /dev/null
@@ -1,430 +0,0 @@
-/*
- * Atheros AR9170 driver
- *
- * Hardware-specific definitions
- *
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License 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; see the file COPYING. If not, see
- * http://www.gnu.org/licenses/.
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- * Copyright (c) 2007-2008 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 __AR9170_HW_H
-#define __AR9170_HW_H
-
-#define AR9170_MAX_CMD_LEN 64
-
-enum ar9170_cmd {
- AR9170_CMD_RREG = 0x00,
- AR9170_CMD_WREG = 0x01,
- AR9170_CMD_RMEM = 0x02,
- AR9170_CMD_WMEM = 0x03,
- AR9170_CMD_BITAND = 0x04,
- AR9170_CMD_BITOR = 0x05,
- AR9170_CMD_EKEY = 0x28,
- AR9170_CMD_DKEY = 0x29,
- AR9170_CMD_FREQUENCY = 0x30,
- AR9170_CMD_RF_INIT = 0x31,
- AR9170_CMD_SYNTH = 0x32,
- AR9170_CMD_FREQ_START = 0x33,
- AR9170_CMD_ECHO = 0x80,
- AR9170_CMD_TALLY = 0x81,
- AR9170_CMD_TALLY_APD = 0x82,
- AR9170_CMD_CONFIG = 0x83,
- AR9170_CMD_RESET = 0x90,
- AR9170_CMD_DKRESET = 0x91,
- AR9170_CMD_DKTX_STATUS = 0x92,
- AR9170_CMD_FDC = 0xA0,
- AR9170_CMD_WREEPROM = 0xB0,
- AR9170_CMD_WFLASH = 0xB0,
- AR9170_CMD_FLASH_ERASE = 0xB1,
- AR9170_CMD_FLASH_PROG = 0xB2,
- AR9170_CMD_FLASH_CHKSUM = 0xB3,
- AR9170_CMD_FLASH_READ = 0xB4,
- AR9170_CMD_FW_DL_INIT = 0xB5,
- AR9170_CMD_MEM_WREEPROM = 0xBB,
-};
-
-/* endpoints */
-#define AR9170_EP_TX 1
-#define AR9170_EP_RX 2
-#define AR9170_EP_IRQ 3
-#define AR9170_EP_CMD 4
-
-#define AR9170_EEPROM_START 0x1600
-
-#define AR9170_GPIO_REG_BASE 0x1d0100
-#define AR9170_GPIO_REG_PORT_TYPE AR9170_GPIO_REG_BASE
-#define AR9170_GPIO_REG_DATA (AR9170_GPIO_REG_BASE + 4)
-#define AR9170_NUM_LEDS 2
-
-
-#define AR9170_USB_REG_BASE 0x1e1000
-#define AR9170_USB_REG_DMA_CTL (AR9170_USB_REG_BASE + 0x108)
-#define AR9170_DMA_CTL_ENABLE_TO_DEVICE 0x1
-#define AR9170_DMA_CTL_ENABLE_FROM_DEVICE 0x2
-#define AR9170_DMA_CTL_HIGH_SPEED 0x4
-#define AR9170_DMA_CTL_PACKET_MODE 0x8
-
-#define AR9170_USB_REG_MAX_AGG_UPLOAD (AR9170_USB_REG_BASE + 0x110)
-#define AR9170_USB_REG_UPLOAD_TIME_CTL (AR9170_USB_REG_BASE + 0x114)
-
-
-
-#define AR9170_MAC_REG_BASE 0x1c3000
-
-#define AR9170_MAC_REG_TSF_L (AR9170_MAC_REG_BASE + 0x514)
-#define AR9170_MAC_REG_TSF_H (AR9170_MAC_REG_BASE + 0x518)
-
-#define AR9170_MAC_REG_ATIM_WINDOW (AR9170_MAC_REG_BASE + 0x51C)
-#define AR9170_MAC_REG_BCN_PERIOD (AR9170_MAC_REG_BASE + 0x520)
-#define AR9170_MAC_REG_PRETBTT (AR9170_MAC_REG_BASE + 0x524)
-
-#define AR9170_MAC_REG_MAC_ADDR_L (AR9170_MAC_REG_BASE + 0x610)
-#define AR9170_MAC_REG_MAC_ADDR_H (AR9170_MAC_REG_BASE + 0x614)
-#define AR9170_MAC_REG_BSSID_L (AR9170_MAC_REG_BASE + 0x618)
-#define AR9170_MAC_REG_BSSID_H (AR9170_MAC_REG_BASE + 0x61c)
-
-#define AR9170_MAC_REG_GROUP_HASH_TBL_L (AR9170_MAC_REG_BASE + 0x624)
-#define AR9170_MAC_REG_GROUP_HASH_TBL_H (AR9170_MAC_REG_BASE + 0x628)
-
-#define AR9170_MAC_REG_RX_TIMEOUT (AR9170_MAC_REG_BASE + 0x62C)
-
-#define AR9170_MAC_REG_BASIC_RATE (AR9170_MAC_REG_BASE + 0x630)
-#define AR9170_MAC_REG_MANDATORY_RATE (AR9170_MAC_REG_BASE + 0x634)
-#define AR9170_MAC_REG_RTS_CTS_RATE (AR9170_MAC_REG_BASE + 0x638)
-#define AR9170_MAC_REG_BACKOFF_PROTECT (AR9170_MAC_REG_BASE + 0x63c)
-#define AR9170_MAC_REG_RX_THRESHOLD (AR9170_MAC_REG_BASE + 0x640)
-#define AR9170_MAC_REG_RX_PE_DELAY (AR9170_MAC_REG_BASE + 0x64C)
-
-#define AR9170_MAC_REG_DYNAMIC_SIFS_ACK (AR9170_MAC_REG_BASE + 0x658)
-#define AR9170_MAC_REG_SNIFFER (AR9170_MAC_REG_BASE + 0x674)
-#define AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC BIT(0)
-#define AR9170_MAC_REG_SNIFFER_DEFAULTS 0x02000000
-#define AR9170_MAC_REG_ENCRYPTION (AR9170_MAC_REG_BASE + 0x678)
-#define AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE BIT(3)
-#define AR9170_MAC_REG_ENCRYPTION_DEFAULTS 0x70
-
-#define AR9170_MAC_REG_MISC_680 (AR9170_MAC_REG_BASE + 0x680)
-#define AR9170_MAC_REG_TX_UNDERRUN (AR9170_MAC_REG_BASE + 0x688)
-
-#define AR9170_MAC_REG_FRAMETYPE_FILTER (AR9170_MAC_REG_BASE + 0x68c)
-#define AR9170_MAC_REG_FTF_ASSOC_REQ BIT(0)
-#define AR9170_MAC_REG_FTF_ASSOC_RESP BIT(1)
-#define AR9170_MAC_REG_FTF_REASSOC_REQ BIT(2)
-#define AR9170_MAC_REG_FTF_REASSOC_RESP BIT(3)
-#define AR9170_MAC_REG_FTF_PRB_REQ BIT(4)
-#define AR9170_MAC_REG_FTF_PRB_RESP BIT(5)
-#define AR9170_MAC_REG_FTF_BIT6 BIT(6)
-#define AR9170_MAC_REG_FTF_BIT7 BIT(7)
-#define AR9170_MAC_REG_FTF_BEACON BIT(8)
-#define AR9170_MAC_REG_FTF_ATIM BIT(9)
-#define AR9170_MAC_REG_FTF_DEASSOC BIT(10)
-#define AR9170_MAC_REG_FTF_AUTH BIT(11)
-#define AR9170_MAC_REG_FTF_DEAUTH BIT(12)
-#define AR9170_MAC_REG_FTF_BIT13 BIT(13)
-#define AR9170_MAC_REG_FTF_BIT14 BIT(14)
-#define AR9170_MAC_REG_FTF_BIT15 BIT(15)
-#define AR9170_MAC_REG_FTF_BAR BIT(24)
-#define AR9170_MAC_REG_FTF_BA BIT(25)
-#define AR9170_MAC_REG_FTF_PSPOLL BIT(26)
-#define AR9170_MAC_REG_FTF_RTS BIT(27)
-#define AR9170_MAC_REG_FTF_CTS BIT(28)
-#define AR9170_MAC_REG_FTF_ACK BIT(29)
-#define AR9170_MAC_REG_FTF_CFE BIT(30)
-#define AR9170_MAC_REG_FTF_CFE_ACK BIT(31)
-#define AR9170_MAC_REG_FTF_DEFAULTS 0x0700ffff
-#define AR9170_MAC_REG_FTF_MONITOR 0xfd00ffff
-
-#define AR9170_MAC_REG_RX_TOTAL (AR9170_MAC_REG_BASE + 0x6A0)
-#define AR9170_MAC_REG_RX_CRC32 (AR9170_MAC_REG_BASE + 0x6A4)
-#define AR9170_MAC_REG_RX_CRC16 (AR9170_MAC_REG_BASE + 0x6A8)
-#define AR9170_MAC_REG_RX_ERR_DECRYPTION_UNI (AR9170_MAC_REG_BASE + 0x6AC)
-#define AR9170_MAC_REG_RX_OVERRUN (AR9170_MAC_REG_BASE + 0x6B0)
-#define AR9170_MAC_REG_RX_ERR_DECRYPTION_MUL (AR9170_MAC_REG_BASE + 0x6BC)
-#define AR9170_MAC_REG_TX_RETRY (AR9170_MAC_REG_BASE + 0x6CC)
-#define AR9170_MAC_REG_TX_TOTAL (AR9170_MAC_REG_BASE + 0x6F4)
-
-
-#define AR9170_MAC_REG_ACK_EXTENSION (AR9170_MAC_REG_BASE + 0x690)
-#define AR9170_MAC_REG_EIFS_AND_SIFS (AR9170_MAC_REG_BASE + 0x698)
-
-#define AR9170_MAC_REG_SLOT_TIME (AR9170_MAC_REG_BASE + 0x6F0)
-
-#define AR9170_MAC_REG_POWERMANAGEMENT (AR9170_MAC_REG_BASE + 0x700)
-#define AR9170_MAC_REG_POWERMGT_IBSS 0xe0
-#define AR9170_MAC_REG_POWERMGT_AP 0xa1
-#define AR9170_MAC_REG_POWERMGT_STA 0x2
-#define AR9170_MAC_REG_POWERMGT_AP_WDS 0x3
-#define AR9170_MAC_REG_POWERMGT_DEFAULTS (0xf << 24)
-
-#define AR9170_MAC_REG_ROLL_CALL_TBL_L (AR9170_MAC_REG_BASE + 0x704)
-#define AR9170_MAC_REG_ROLL_CALL_TBL_H (AR9170_MAC_REG_BASE + 0x708)
-
-#define AR9170_MAC_REG_AC0_CW (AR9170_MAC_REG_BASE + 0xB00)
-#define AR9170_MAC_REG_AC1_CW (AR9170_MAC_REG_BASE + 0xB04)
-#define AR9170_MAC_REG_AC2_CW (AR9170_MAC_REG_BASE + 0xB08)
-#define AR9170_MAC_REG_AC3_CW (AR9170_MAC_REG_BASE + 0xB0C)
-#define AR9170_MAC_REG_AC4_CW (AR9170_MAC_REG_BASE + 0xB10)
-#define AR9170_MAC_REG_AC1_AC0_AIFS (AR9170_MAC_REG_BASE + 0xB14)
-#define AR9170_MAC_REG_AC3_AC2_AIFS (AR9170_MAC_REG_BASE + 0xB18)
-
-#define AR9170_MAC_REG_RETRY_MAX (AR9170_MAC_REG_BASE + 0xB28)
-
-#define AR9170_MAC_REG_FCS_SELECT (AR9170_MAC_REG_BASE + 0xBB0)
-#define AR9170_MAC_FCS_SWFCS 0x1
-#define AR9170_MAC_FCS_FIFO_PROT 0x4
-
-
-#define AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND (AR9170_MAC_REG_BASE + 0xB30)
-
-#define AR9170_MAC_REG_AC1_AC0_TXOP (AR9170_MAC_REG_BASE + 0xB44)
-#define AR9170_MAC_REG_AC3_AC2_TXOP (AR9170_MAC_REG_BASE + 0xB48)
-
-#define AR9170_MAC_REG_AMPDU_FACTOR (AR9170_MAC_REG_BASE + 0xB9C)
-#define AR9170_MAC_REG_AMPDU_DENSITY (AR9170_MAC_REG_BASE + 0xBA0)
-
-#define AR9170_MAC_REG_ACK_TABLE (AR9170_MAC_REG_BASE + 0xC00)
-#define AR9170_MAC_REG_AMPDU_RX_THRESH (AR9170_MAC_REG_BASE + 0xC50)
-
-#define AR9170_MAC_REG_TXRX_MPI (AR9170_MAC_REG_BASE + 0xD7C)
-#define AR9170_MAC_TXRX_MPI_TX_MPI_MASK 0x0000000f
-#define AR9170_MAC_TXRX_MPI_TX_TO_MASK 0x0000fff0
-#define AR9170_MAC_TXRX_MPI_RX_MPI_MASK 0x000f0000
-#define AR9170_MAC_TXRX_MPI_RX_TO_MASK 0xfff00000
-
-#define AR9170_MAC_REG_BCN_ADDR (AR9170_MAC_REG_BASE + 0xD84)
-#define AR9170_MAC_REG_BCN_LENGTH (AR9170_MAC_REG_BASE + 0xD88)
-#define AR9170_MAC_REG_BCN_PLCP (AR9170_MAC_REG_BASE + 0xD90)
-#define AR9170_MAC_REG_BCN_CTRL (AR9170_MAC_REG_BASE + 0xD94)
-#define AR9170_MAC_REG_BCN_HT1 (AR9170_MAC_REG_BASE + 0xDA0)
-#define AR9170_MAC_REG_BCN_HT2 (AR9170_MAC_REG_BASE + 0xDA4)
-
-
-#define AR9170_PWR_REG_BASE 0x1D4000
-
-#define AR9170_PWR_REG_CLOCK_SEL (AR9170_PWR_REG_BASE + 0x008)
-#define AR9170_PWR_CLK_AHB_40MHZ 0
-#define AR9170_PWR_CLK_AHB_20_22MHZ 1
-#define AR9170_PWR_CLK_AHB_40_44MHZ 2
-#define AR9170_PWR_CLK_AHB_80_88MHZ 3
-#define AR9170_PWR_CLK_DAC_160_INV_DLY 0x70
-
-
-/* put beacon here in memory */
-#define AR9170_BEACON_BUFFER_ADDRESS 0x117900
-
-
-struct ar9170_tx_control {
- __le16 length;
- __le16 mac_control;
- __le32 phy_control;
- u8 frame_data[0];
-} __packed;
-
-/* these are either-or */
-#define AR9170_TX_MAC_PROT_RTS 0x0001
-#define AR9170_TX_MAC_PROT_CTS 0x0002
-
-#define AR9170_TX_MAC_NO_ACK 0x0004
-/* if unset, MAC will only do SIFS space before frame */
-#define AR9170_TX_MAC_BACKOFF 0x0008
-#define AR9170_TX_MAC_BURST 0x0010
-#define AR9170_TX_MAC_AGGR 0x0020
-
-/* encryption is a two-bit field */
-#define AR9170_TX_MAC_ENCR_NONE 0x0000
-#define AR9170_TX_MAC_ENCR_RC4 0x0040
-#define AR9170_TX_MAC_ENCR_CENC 0x0080
-#define AR9170_TX_MAC_ENCR_AES 0x00c0
-
-#define AR9170_TX_MAC_MMIC 0x0100
-#define AR9170_TX_MAC_HW_DURATION 0x0200
-#define AR9170_TX_MAC_QOS_SHIFT 10
-#define AR9170_TX_MAC_QOS_MASK (3 << AR9170_TX_MAC_QOS_SHIFT)
-#define AR9170_TX_MAC_AGGR_QOS_BIT1 0x0400
-#define AR9170_TX_MAC_AGGR_QOS_BIT2 0x0800
-#define AR9170_TX_MAC_DISABLE_TXOP 0x1000
-#define AR9170_TX_MAC_TXOP_RIFS 0x2000
-#define AR9170_TX_MAC_IMM_AMPDU 0x4000
-#define AR9170_TX_MAC_RATE_PROBE 0x8000
-
-/* either-or */
-#define AR9170_TX_PHY_MOD_MASK 0x00000003
-#define AR9170_TX_PHY_MOD_CCK 0x00000000
-#define AR9170_TX_PHY_MOD_OFDM 0x00000001
-#define AR9170_TX_PHY_MOD_HT 0x00000002
-
-/* depends on modulation */
-#define AR9170_TX_PHY_SHORT_PREAMBLE 0x00000004
-#define AR9170_TX_PHY_GREENFIELD 0x00000004
-
-#define AR9170_TX_PHY_BW_SHIFT 3
-#define AR9170_TX_PHY_BW_MASK (3 << AR9170_TX_PHY_BW_SHIFT)
-#define AR9170_TX_PHY_BW_20MHZ 0
-#define AR9170_TX_PHY_BW_40MHZ 2
-#define AR9170_TX_PHY_BW_40MHZ_DUP 3
-
-#define AR9170_TX_PHY_TX_HEAVY_CLIP_SHIFT 6
-#define AR9170_TX_PHY_TX_HEAVY_CLIP_MASK (7 << AR9170_TX_PHY_TX_HEAVY_CLIP_SHIFT)
-
-#define AR9170_TX_PHY_TX_PWR_SHIFT 9
-#define AR9170_TX_PHY_TX_PWR_MASK (0x3f << AR9170_TX_PHY_TX_PWR_SHIFT)
-
-/* not part of the hw-spec */
-#define AR9170_TX_PHY_QOS_SHIFT 25
-#define AR9170_TX_PHY_QOS_MASK (3 << AR9170_TX_PHY_QOS_SHIFT)
-
-#define AR9170_TX_PHY_TXCHAIN_SHIFT 15
-#define AR9170_TX_PHY_TXCHAIN_MASK (7 << AR9170_TX_PHY_TXCHAIN_SHIFT)
-#define AR9170_TX_PHY_TXCHAIN_1 1
-/* use for cck, ofdm 6/9/12/18/24 and HT if capable */
-#define AR9170_TX_PHY_TXCHAIN_2 5
-
-#define AR9170_TX_PHY_MCS_SHIFT 18
-#define AR9170_TX_PHY_MCS_MASK (0x7f << AR9170_TX_PHY_MCS_SHIFT)
-
-#define AR9170_TX_PHY_SHORT_GI 0x80000000
-
-#define AR5416_MAX_RATE_POWER 63
-
-struct ar9170_rx_head {
- u8 plcp[12];
-} __packed;
-
-struct ar9170_rx_phystatus {
- union {
- struct {
- u8 rssi_ant0, rssi_ant1, rssi_ant2,
- rssi_ant0x, rssi_ant1x, rssi_ant2x,
- rssi_combined;
- } __packed;
- u8 rssi[7];
- } __packed;
-
- u8 evm_stream0[6], evm_stream1[6];
- u8 phy_err;
-} __packed;
-
-struct ar9170_rx_macstatus {
- u8 SAidx, DAidx;
- u8 error;
- u8 status;
-} __packed;
-
-#define AR9170_ENC_ALG_NONE 0x0
-#define AR9170_ENC_ALG_WEP64 0x1
-#define AR9170_ENC_ALG_TKIP 0x2
-#define AR9170_ENC_ALG_AESCCMP 0x4
-#define AR9170_ENC_ALG_WEP128 0x5
-#define AR9170_ENC_ALG_WEP256 0x6
-#define AR9170_ENC_ALG_CENC 0x7
-
-#define AR9170_RX_ENC_SOFTWARE 0x8
-
-static inline u8 ar9170_get_decrypt_type(struct ar9170_rx_macstatus *t)
-{
- return (t->SAidx & 0xc0) >> 4 |
- (t->DAidx & 0xc0) >> 6;
-}
-
-#define AR9170_RX_STATUS_MODULATION_MASK 0x03
-#define AR9170_RX_STATUS_MODULATION_CCK 0x00
-#define AR9170_RX_STATUS_MODULATION_OFDM 0x01
-#define AR9170_RX_STATUS_MODULATION_HT 0x02
-#define AR9170_RX_STATUS_MODULATION_DUPOFDM 0x03
-
-/* depends on modulation */
-#define AR9170_RX_STATUS_SHORT_PREAMBLE 0x08
-#define AR9170_RX_STATUS_GREENFIELD 0x08
-
-#define AR9170_RX_STATUS_MPDU_MASK 0x30
-#define AR9170_RX_STATUS_MPDU_SINGLE 0x00
-#define AR9170_RX_STATUS_MPDU_FIRST 0x20
-#define AR9170_RX_STATUS_MPDU_MIDDLE 0x30
-#define AR9170_RX_STATUS_MPDU_LAST 0x10
-
-#define AR9170_RX_ERROR_RXTO 0x01
-#define AR9170_RX_ERROR_OVERRUN 0x02
-#define AR9170_RX_ERROR_DECRYPT 0x04
-#define AR9170_RX_ERROR_FCS 0x08
-#define AR9170_RX_ERROR_WRONG_RA 0x10
-#define AR9170_RX_ERROR_PLCP 0x20
-#define AR9170_RX_ERROR_MMIC 0x40
-#define AR9170_RX_ERROR_FATAL 0x80
-
-struct ar9170_cmd_tx_status {
- u8 dst[ETH_ALEN];
- __le32 rate;
- __le16 status;
-} __packed;
-
-#define AR9170_TX_STATUS_COMPLETE 0x00
-#define AR9170_TX_STATUS_RETRY 0x01
-#define AR9170_TX_STATUS_FAILED 0x02
-
-struct ar9170_cmd_ba_failed_count {
- __le16 failed;
- __le16 rate;
-} __packed;
-
-struct ar9170_cmd_response {
- u8 flag;
- u8 type;
- __le16 padding;
-
- union {
- struct ar9170_cmd_tx_status tx_status;
- struct ar9170_cmd_ba_failed_count ba_fail_cnt;
- u8 data[0];
- };
-} __packed;
-
-/* QoS */
-
-/* mac80211 queue to HW/FW map */
-static const u8 ar9170_qos_hwmap[4] = { 3, 2, 0, 1 };
-
-/* HW/FW queue to mac80211 map */
-static const u8 ar9170_qos_mac80211map[4] = { 2, 3, 1, 0 };
-
-enum ar9170_txq {
- AR9170_TXQ_BE,
- AR9170_TXQ_BK,
- AR9170_TXQ_VI,
- AR9170_TXQ_VO,
-
- __AR9170_NUM_TXQ,
-};
-
-#define AR9170_TXQ_DEPTH 32
-#define AR9170_TX_MAX_PENDING 128
-#define AR9170_RX_STREAM_MAX_SIZE 65535
-
-#endif /* __AR9170_HW_H */
diff --git a/drivers/net/wireless/ath/ar9170/led.c b/drivers/net/wireless/ath/ar9170/led.c
deleted file mode 100644
index 832d90087f8a..000000000000
--- a/drivers/net/wireless/ath/ar9170/led.c
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Atheros AR9170 driver
- *
- * LED handling
- *
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License 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; see the file COPYING. If not, see
- * http://www.gnu.org/licenses/.
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- * Copyright (c) 2007-2008 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 "ar9170.h"
-#include "cmd.h"
-
-int ar9170_set_leds_state(struct ar9170 *ar, u32 led_state)
-{
- return ar9170_write_reg(ar, AR9170_GPIO_REG_DATA, led_state);
-}
-
-int ar9170_init_leds(struct ar9170 *ar)
-{
- int err;
-
- /* disable LEDs */
- /* GPIO [0/1 mode: output, 2/3: input] */
- err = ar9170_write_reg(ar, AR9170_GPIO_REG_PORT_TYPE, 3);
- if (err)
- goto out;
-
- /* GPIO 0/1 value: off */
- err = ar9170_set_leds_state(ar, 0);
-
-out:
- return err;
-}
-
-#ifdef CONFIG_AR9170_LEDS
-static void ar9170_update_leds(struct work_struct *work)
-{
- struct ar9170 *ar = container_of(work, struct ar9170, led_work.work);
- int i, tmp, blink_delay = 1000;
- u32 led_val = 0;
- bool rerun = false;
-
- if (unlikely(!IS_ACCEPTING_CMD(ar)))
- return ;
-
- mutex_lock(&ar->mutex);
- for (i = 0; i < AR9170_NUM_LEDS; i++)
- if (ar->leds[i].registered && ar->leds[i].toggled) {
- led_val |= 1 << i;
-
- tmp = 70 + 200 / (ar->leds[i].toggled);
- if (tmp < blink_delay)
- blink_delay = tmp;
-
- if (ar->leds[i].toggled > 1)
- ar->leds[i].toggled = 0;
-
- rerun = true;
- }
-
- ar9170_set_leds_state(ar, led_val);
- mutex_unlock(&ar->mutex);
-
- if (!rerun)
- return;
-
- ieee80211_queue_delayed_work(ar->hw,
- &ar->led_work,
- msecs_to_jiffies(blink_delay));
-}
-
-static void ar9170_led_brightness_set(struct led_classdev *led,
- enum led_brightness brightness)
-{
- struct ar9170_led *arl = container_of(led, struct ar9170_led, l);
- struct ar9170 *ar = arl->ar;
-
- if (unlikely(!arl->registered))
- return ;
-
- if (arl->last_state != !!brightness) {
- arl->toggled++;
- arl->last_state = !!brightness;
- }
-
- if (likely(IS_ACCEPTING_CMD(ar) && arl->toggled))
- ieee80211_queue_delayed_work(ar->hw, &ar->led_work, HZ/10);
-}
-
-static int ar9170_register_led(struct ar9170 *ar, int i, char *name,
- char *trigger)
-{
- int err;
-
- snprintf(ar->leds[i].name, sizeof(ar->leds[i].name),
- "ar9170-%s::%s", wiphy_name(ar->hw->wiphy), name);
-
- ar->leds[i].ar = ar;
- ar->leds[i].l.name = ar->leds[i].name;
- ar->leds[i].l.brightness_set = ar9170_led_brightness_set;
- ar->leds[i].l.brightness = 0;
- ar->leds[i].l.default_trigger = trigger;
-
- err = led_classdev_register(wiphy_dev(ar->hw->wiphy),
- &ar->leds[i].l);
- if (err)
- wiphy_err(ar->hw->wiphy, "failed to register %s LED (%d).\n",
- ar->leds[i].name, err);
- else
- ar->leds[i].registered = true;
-
- return err;
-}
-
-void ar9170_unregister_leds(struct ar9170 *ar)
-{
- int i;
-
- for (i = 0; i < AR9170_NUM_LEDS; i++)
- if (ar->leds[i].registered) {
- led_classdev_unregister(&ar->leds[i].l);
- ar->leds[i].registered = false;
- ar->leds[i].toggled = 0;
- }
-
- cancel_delayed_work_sync(&ar->led_work);
-}
-
-int ar9170_register_leds(struct ar9170 *ar)
-{
- int err;
-
- INIT_DELAYED_WORK(&ar->led_work, ar9170_update_leds);
-
- err = ar9170_register_led(ar, 0, "tx",
- ieee80211_get_tx_led_name(ar->hw));
- if (err)
- goto fail;
-
- err = ar9170_register_led(ar, 1, "assoc",
- ieee80211_get_assoc_led_name(ar->hw));
- if (err)
- goto fail;
-
- return 0;
-
-fail:
- ar9170_unregister_leds(ar);
- return err;
-}
-
-#endif /* CONFIG_AR9170_LEDS */
diff --git a/drivers/net/wireless/ath/ar9170/mac.c b/drivers/net/wireless/ath/ar9170/mac.c
deleted file mode 100644
index 857e86104295..000000000000
--- a/drivers/net/wireless/ath/ar9170/mac.c
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- * Atheros AR9170 driver
- *
- * MAC programming
- *
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License 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; see the file COPYING. If not, see
- * http://www.gnu.org/licenses/.
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- * Copyright (c) 2007-2008 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 <asm/unaligned.h>
-
-#include "ar9170.h"
-#include "cmd.h"
-
-int ar9170_set_dyn_sifs_ack(struct ar9170 *ar)
-{
- u32 val;
-
- if (conf_is_ht40(&ar->hw->conf))
- val = 0x010a;
- else {
- if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ)
- val = 0x105;
- else
- val = 0x104;
- }
-
- return ar9170_write_reg(ar, AR9170_MAC_REG_DYNAMIC_SIFS_ACK, val);
-}
-
-int ar9170_set_slot_time(struct ar9170 *ar)
-{
- u32 slottime = 20;
-
- if (!ar->vif)
- return 0;
-
- if ((ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ) ||
- ar->vif->bss_conf.use_short_slot)
- slottime = 9;
-
- return ar9170_write_reg(ar, AR9170_MAC_REG_SLOT_TIME, slottime << 10);
-}
-
-int ar9170_set_basic_rates(struct ar9170 *ar)
-{
- u8 cck, ofdm;
-
- if (!ar->vif)
- return 0;
-
- ofdm = ar->vif->bss_conf.basic_rates >> 4;
-
- /* FIXME: is still necessary? */
- if (ar->hw->conf.channel->band == IEEE80211_BAND_5GHZ)
- cck = 0;
- else
- cck = ar->vif->bss_conf.basic_rates & 0xf;
-
- return ar9170_write_reg(ar, AR9170_MAC_REG_BASIC_RATE,
- ofdm << 8 | cck);
-}
-
-int ar9170_set_qos(struct ar9170 *ar)
-{
- ar9170_regwrite_begin(ar);
-
- ar9170_regwrite(AR9170_MAC_REG_AC0_CW, ar->edcf[0].cw_min |
- (ar->edcf[0].cw_max << 16));
- ar9170_regwrite(AR9170_MAC_REG_AC1_CW, ar->edcf[1].cw_min |
- (ar->edcf[1].cw_max << 16));
- ar9170_regwrite(AR9170_MAC_REG_AC2_CW, ar->edcf[2].cw_min |
- (ar->edcf[2].cw_max << 16));
- ar9170_regwrite(AR9170_MAC_REG_AC3_CW, ar->edcf[3].cw_min |
- (ar->edcf[3].cw_max << 16));
- ar9170_regwrite(AR9170_MAC_REG_AC4_CW, ar->edcf[4].cw_min |
- (ar->edcf[4].cw_max << 16));
-
- ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_AIFS,
- ((ar->edcf[0].aifs * 9 + 10)) |
- ((ar->edcf[1].aifs * 9 + 10) << 12) |
- ((ar->edcf[2].aifs * 9 + 10) << 24));
- ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_AIFS,
- ((ar->edcf[2].aifs * 9 + 10) >> 8) |
- ((ar->edcf[3].aifs * 9 + 10) << 4) |
- ((ar->edcf[4].aifs * 9 + 10) << 16));
-
- ar9170_regwrite(AR9170_MAC_REG_AC1_AC0_TXOP,
- ar->edcf[0].txop | ar->edcf[1].txop << 16);
- ar9170_regwrite(AR9170_MAC_REG_AC3_AC2_TXOP,
- ar->edcf[2].txop | ar->edcf[3].txop << 16);
-
- ar9170_regwrite_finish();
-
- return ar9170_regwrite_result();
-}
-
-static int ar9170_set_ampdu_density(struct ar9170 *ar, u8 mpdudensity)
-{
- u32 val;
-
- /* don't allow AMPDU density > 8us */
- if (mpdudensity > 6)
- return -EINVAL;
-
- /* Watch out! Otus uses slightly different density values. */
- val = 0x140a00 | (mpdudensity ? (mpdudensity + 1) : 0);
-
- ar9170_regwrite_begin(ar);
- ar9170_regwrite(AR9170_MAC_REG_AMPDU_DENSITY, val);
- ar9170_regwrite_finish();
-
- return ar9170_regwrite_result();
-}
-
-int ar9170_init_mac(struct ar9170 *ar)
-{
- ar9170_regwrite_begin(ar);
-
- ar9170_regwrite(AR9170_MAC_REG_ACK_EXTENSION, 0x40);
-
- ar9170_regwrite(AR9170_MAC_REG_RETRY_MAX, 0);
-
- /* enable MMIC */
- ar9170_regwrite(AR9170_MAC_REG_SNIFFER,
- AR9170_MAC_REG_SNIFFER_DEFAULTS);
-
- ar9170_regwrite(AR9170_MAC_REG_RX_THRESHOLD, 0xc1f80);
-
- ar9170_regwrite(AR9170_MAC_REG_RX_PE_DELAY, 0x70);
- ar9170_regwrite(AR9170_MAC_REG_EIFS_AND_SIFS, 0xa144000);
- ar9170_regwrite(AR9170_MAC_REG_SLOT_TIME, 9 << 10);
-
- /* CF-END mode */
- ar9170_regwrite(0x1c3b2c, 0x19000000);
-
- /* NAV protects ACK only (in TXOP) */
- ar9170_regwrite(0x1c3b38, 0x201);
-
- /* Set Beacon PHY CTRL's TPC to 0x7, TA1=1 */
- /* OTUS set AM to 0x1 */
- ar9170_regwrite(AR9170_MAC_REG_BCN_HT1, 0x8000170);
-
- ar9170_regwrite(AR9170_MAC_REG_BACKOFF_PROTECT, 0x105);
-
- /* AGG test code*/
- /* Aggregation MAX number and timeout */
- ar9170_regwrite(0x1c3b9c, 0x10000a);
-
- ar9170_regwrite(AR9170_MAC_REG_FRAMETYPE_FILTER,
- AR9170_MAC_REG_FTF_DEFAULTS);
-
- /* Enable deaggregator, response in sniffer mode */
- ar9170_regwrite(0x1c3c40, 0x1 | 1<<30);
-
- /* rate sets */
- ar9170_regwrite(AR9170_MAC_REG_BASIC_RATE, 0x150f);
- ar9170_regwrite(AR9170_MAC_REG_MANDATORY_RATE, 0x150f);
- ar9170_regwrite(AR9170_MAC_REG_RTS_CTS_RATE, 0x10b01bb);
-
- /* MIMO response control */
- ar9170_regwrite(0x1c3694, 0x4003C1E);/* bit 26~28 otus-AM */
-
- /* switch MAC to OTUS interface */
- ar9170_regwrite(0x1c3600, 0x3);
-
- ar9170_regwrite(AR9170_MAC_REG_AMPDU_RX_THRESH, 0xffff);
-
- /* set PHY register read timeout (??) */
- ar9170_regwrite(AR9170_MAC_REG_MISC_680, 0xf00008);
-
- /* Disable Rx TimeOut, workaround for BB. */
- ar9170_regwrite(AR9170_MAC_REG_RX_TIMEOUT, 0x0);
-
- /* Set CPU clock frequency to 88/80MHz */
- ar9170_regwrite(AR9170_PWR_REG_CLOCK_SEL,
- AR9170_PWR_CLK_AHB_80_88MHZ |
- AR9170_PWR_CLK_DAC_160_INV_DLY);
-
- /* Set WLAN DMA interrupt mode: generate int per packet */
- ar9170_regwrite(AR9170_MAC_REG_TXRX_MPI, 0x110011);
-
- ar9170_regwrite(AR9170_MAC_REG_FCS_SELECT,
- AR9170_MAC_FCS_FIFO_PROT);
-
- /* Disables the CF_END frame, undocumented register */
- ar9170_regwrite(AR9170_MAC_REG_TXOP_NOT_ENOUGH_IND,
- 0x141E0F48);
-
- ar9170_regwrite_finish();
-
- return ar9170_regwrite_result();
-}
-
-static int ar9170_set_mac_reg(struct ar9170 *ar, const u32 reg, const u8 *mac)
-{
- static const u8 zero[ETH_ALEN] = { 0 };
-
- if (!mac)
- mac = zero;
-
- ar9170_regwrite_begin(ar);
-
- ar9170_regwrite(reg, get_unaligned_le32(mac));
- ar9170_regwrite(reg + 4, get_unaligned_le16(mac + 4));
-
- ar9170_regwrite_finish();
-
- return ar9170_regwrite_result();
-}
-
-int ar9170_update_multicast(struct ar9170 *ar, const u64 mc_hash)
-{
- int err;
-
- ar9170_regwrite_begin(ar);
- ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_H, mc_hash >> 32);
- ar9170_regwrite(AR9170_MAC_REG_GROUP_HASH_TBL_L, mc_hash);
- ar9170_regwrite_finish();
- err = ar9170_regwrite_result();
- if (err)
- return err;
-
- ar->cur_mc_hash = mc_hash;
- return 0;
-}
-
-int ar9170_update_frame_filter(struct ar9170 *ar, const u32 filter)
-{
- int err;
-
- err = ar9170_write_reg(ar, AR9170_MAC_REG_FRAMETYPE_FILTER, filter);
- if (err)
- return err;
-
- ar->cur_filter = filter;
- return 0;
-}
-
-static int ar9170_set_promiscouous(struct ar9170 *ar)
-{
- u32 encr_mode, sniffer;
- int err;
-
- err = ar9170_read_reg(ar, AR9170_MAC_REG_SNIFFER, &sniffer);
- if (err)
- return err;
-
- err = ar9170_read_reg(ar, AR9170_MAC_REG_ENCRYPTION, &encr_mode);
- if (err)
- return err;
-
- if (ar->sniffer_enabled) {
- sniffer |= AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC;
-
- /*
- * Rx decryption works in place.
- *
- * If we don't disable it, the hardware will render all
- * encrypted frames which are encrypted with an unknown
- * key useless.
- */
-
- encr_mode |= AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE;
- ar->sniffer_enabled = true;
- } else {
- sniffer &= ~AR9170_MAC_REG_SNIFFER_ENABLE_PROMISC;
-
- if (ar->rx_software_decryption)
- encr_mode |= AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE;
- else
- encr_mode &= ~AR9170_MAC_REG_ENCRYPTION_RX_SOFTWARE;
- }
-
- ar9170_regwrite_begin(ar);
- ar9170_regwrite(AR9170_MAC_REG_ENCRYPTION, encr_mode);
- ar9170_regwrite(AR9170_MAC_REG_SNIFFER, sniffer);
- ar9170_regwrite_finish();
-
- return ar9170_regwrite_result();
-}
-
-int ar9170_set_operating_mode(struct ar9170 *ar)
-{
- struct ath_common *common = &ar->common;
- u32 pm_mode = AR9170_MAC_REG_POWERMGT_DEFAULTS;
- u8 *mac_addr, *bssid;
- int err;
-
- if (ar->vif) {
- mac_addr = common->macaddr;
- bssid = common->curbssid;
-
- switch (ar->vif->type) {
- case NL80211_IFTYPE_MESH_POINT:
- case NL80211_IFTYPE_ADHOC:
- pm_mode |= AR9170_MAC_REG_POWERMGT_IBSS;
- break;
- case NL80211_IFTYPE_AP:
- pm_mode |= AR9170_MAC_REG_POWERMGT_AP;
- break;
- case NL80211_IFTYPE_WDS:
- pm_mode |= AR9170_MAC_REG_POWERMGT_AP_WDS;
- break;
- case NL80211_IFTYPE_MONITOR:
- ar->sniffer_enabled = true;
- ar->rx_software_decryption = true;
- break;
- default:
- pm_mode |= AR9170_MAC_REG_POWERMGT_STA;
- break;
- }
- } else {
- mac_addr = NULL;
- bssid = NULL;
- }
-
- err = ar9170_set_mac_reg(ar, AR9170_MAC_REG_MAC_ADDR_L, mac_addr);
- if (err)
- return err;
-
- err = ar9170_set_mac_reg(ar, AR9170_MAC_REG_BSSID_L, bssid);
- if (err)
- return err;
-
- err = ar9170_set_promiscouous(ar);
- if (err)
- return err;
-
- /* set AMPDU density to 8us. */
- err = ar9170_set_ampdu_density(ar, 6);
- if (err)
- return err;
-
- ar9170_regwrite_begin(ar);
-
- ar9170_regwrite(AR9170_MAC_REG_POWERMANAGEMENT, pm_mode);
- ar9170_regwrite_finish();
-
- return ar9170_regwrite_result();
-}
-
-int ar9170_set_hwretry_limit(struct ar9170 *ar, unsigned int max_retry)
-{
- u32 tmp = min_t(u32, 0x33333, max_retry * 0x11111);
-
- return ar9170_write_reg(ar, AR9170_MAC_REG_RETRY_MAX, tmp);
-}
-
-int ar9170_set_beacon_timers(struct ar9170 *ar)
-{
- u32 v = 0;
- u32 pretbtt = 0;
-
- if (ar->vif) {
- v |= ar->vif->bss_conf.beacon_int;
-
- if (ar->enable_beacon) {
- switch (ar->vif->type) {
- case NL80211_IFTYPE_MESH_POINT:
- case NL80211_IFTYPE_ADHOC:
- v |= BIT(25);
- break;
- case NL80211_IFTYPE_AP:
- v |= BIT(24);
- pretbtt = (ar->vif->bss_conf.beacon_int - 6) <<
- 16;
- break;
- default:
- break;
- }
- }
-
- v |= ar->vif->bss_conf.dtim_period << 16;
- }
-
- ar9170_regwrite_begin(ar);
- ar9170_regwrite(AR9170_MAC_REG_PRETBTT, pretbtt);
- ar9170_regwrite(AR9170_MAC_REG_BCN_PERIOD, v);
- ar9170_regwrite_finish();
- return ar9170_regwrite_result();
-}
-
-int ar9170_update_beacon(struct ar9170 *ar)
-{
- struct sk_buff *skb;
- __le32 *data, *old = NULL;
- u32 word;
- int i;
-
- skb = ieee80211_beacon_get(ar->hw, ar->vif);
- if (!skb)
- return -ENOMEM;
-
- data = (__le32 *)skb->data;
- if (ar->beacon)
- old = (__le32 *)ar->beacon->data;
-
- ar9170_regwrite_begin(ar);
- for (i = 0; i < DIV_ROUND_UP(skb->len, 4); i++) {
- /*
- * XXX: This accesses beyond skb data for up
- * to the last 3 bytes!!
- */
-
- if (old && (data[i] == old[i]))
- continue;
-
- word = le32_to_cpu(data[i]);
- ar9170_regwrite(AR9170_BEACON_BUFFER_ADDRESS + 4 * i, word);
- }
-
- /* XXX: use skb->cb info */
- if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ)
- ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP,
- ((skb->len + 4) << (3 + 16)) + 0x0400);
- else
- ar9170_regwrite(AR9170_MAC_REG_BCN_PLCP,
- ((skb->len + 4) << 16) + 0x001b);
-
- ar9170_regwrite(AR9170_MAC_REG_BCN_LENGTH, skb->len + 4);
- ar9170_regwrite(AR9170_MAC_REG_BCN_ADDR, AR9170_BEACON_BUFFER_ADDRESS);
- ar9170_regwrite(AR9170_MAC_REG_BCN_CTRL, 1);
-
- ar9170_regwrite_finish();
-
- dev_kfree_skb(ar->beacon);
- ar->beacon = skb;
-
- return ar9170_regwrite_result();
-}
-
-void ar9170_new_beacon(struct work_struct *work)
-{
- struct ar9170 *ar = container_of(work, struct ar9170,
- beacon_work);
- struct sk_buff *skb;
-
- if (unlikely(!IS_STARTED(ar)))
- return ;
-
- mutex_lock(&ar->mutex);
-
- if (!ar->vif)
- goto out;
-
- ar9170_update_beacon(ar);
-
- rcu_read_lock();
- while ((skb = ieee80211_get_buffered_bc(ar->hw, ar->vif)))
- ar9170_op_tx(ar->hw, skb);
-
- rcu_read_unlock();
-
- out:
- mutex_unlock(&ar->mutex);
-}
-
-int ar9170_upload_key(struct ar9170 *ar, u8 id, const u8 *mac, u8 ktype,
- u8 keyidx, u8 *keydata, int keylen)
-{
- __le32 vals[7];
- static const u8 bcast[ETH_ALEN] =
- { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- u8 dummy;
-
- mac = mac ? : bcast;
-
- vals[0] = cpu_to_le32((keyidx << 16) + id);
- vals[1] = cpu_to_le32(mac[1] << 24 | mac[0] << 16 | ktype);
- vals[2] = cpu_to_le32(mac[5] << 24 | mac[4] << 16 |
- mac[3] << 8 | mac[2]);
- memset(&vals[3], 0, 16);
- if (keydata)
- memcpy(&vals[3], keydata, keylen);
-
- return ar->exec_cmd(ar, AR9170_CMD_EKEY,
- sizeof(vals), (u8 *)vals,
- 1, &dummy);
-}
-
-int ar9170_disable_key(struct ar9170 *ar, u8 id)
-{
- __le32 val = cpu_to_le32(id);
- u8 dummy;
-
- return ar->exec_cmd(ar, AR9170_CMD_EKEY,
- sizeof(val), (u8 *)&val,
- 1, &dummy);
-}
diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c
deleted file mode 100644
index ccc2edaaeda0..000000000000
--- a/drivers/net/wireless/ath/ar9170/main.c
+++ /dev/null
@@ -1,2190 +0,0 @@
-/*
- * Atheros AR9170 driver
- *
- * mac80211 interaction code
- *
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- * Copyright 2009, Christian Lamparter <chunkeey@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; see the file COPYING. If not, see
- * http://www.gnu.org/licenses/.
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- * Copyright (c) 2007-2008 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 <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/etherdevice.h>
-#include <net/mac80211.h>
-#include "ar9170.h"
-#include "hw.h"
-#include "cmd.h"
-
-static int modparam_nohwcrypt;
-module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
-MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
-
-#define RATE(_bitrate, _hw_rate, _txpidx, _flags) { \
- .bitrate = (_bitrate), \
- .flags = (_flags), \
- .hw_value = (_hw_rate) | (_txpidx) << 4, \
-}
-
-static struct ieee80211_rate __ar9170_ratetable[] = {
- RATE(10, 0, 0, 0),
- RATE(20, 1, 1, IEEE80211_RATE_SHORT_PREAMBLE),
- RATE(55, 2, 2, IEEE80211_RATE_SHORT_PREAMBLE),
- RATE(110, 3, 3, IEEE80211_RATE_SHORT_PREAMBLE),
- RATE(60, 0xb, 0, 0),
- RATE(90, 0xf, 0, 0),
- RATE(120, 0xa, 0, 0),
- RATE(180, 0xe, 0, 0),
- RATE(240, 0x9, 0, 0),
- RATE(360, 0xd, 1, 0),
- RATE(480, 0x8, 2, 0),
- RATE(540, 0xc, 3, 0),
-};
-#undef RATE
-
-#define ar9170_g_ratetable (__ar9170_ratetable + 0)
-#define ar9170_g_ratetable_size 12
-#define ar9170_a_ratetable (__ar9170_ratetable + 4)
-#define ar9170_a_ratetable_size 8
-
-/*
- * NB: The hw_value is used as an index into the ar9170_phy_freq_params
- * array in phy.c so that we don't have to do frequency lookups!
- */
-#define CHAN(_freq, _idx) { \
- .center_freq = (_freq), \
- .hw_value = (_idx), \
- .max_power = 18, /* XXX */ \
-}
-
-static struct ieee80211_channel ar9170_2ghz_chantable[] = {
- CHAN(2412, 0),
- CHAN(2417, 1),
- CHAN(2422, 2),
- CHAN(2427, 3),
- CHAN(2432, 4),
- CHAN(2437, 5),
- CHAN(2442, 6),
- CHAN(2447, 7),
- CHAN(2452, 8),
- CHAN(2457, 9),
- CHAN(2462, 10),
- CHAN(2467, 11),
- CHAN(2472, 12),
- CHAN(2484, 13),
-};
-
-static struct ieee80211_channel ar9170_5ghz_chantable[] = {
- CHAN(4920, 14),
- CHAN(4940, 15),
- CHAN(4960, 16),
- CHAN(4980, 17),
- CHAN(5040, 18),
- CHAN(5060, 19),
- CHAN(5080, 20),
- CHAN(5180, 21),
- CHAN(5200, 22),
- CHAN(5220, 23),
- CHAN(5240, 24),
- CHAN(5260, 25),
- CHAN(5280, 26),
- CHAN(5300, 27),
- CHAN(5320, 28),
- CHAN(5500, 29),
- CHAN(5520, 30),
- CHAN(5540, 31),
- CHAN(5560, 32),
- CHAN(5580, 33),
- CHAN(5600, 34),
- CHAN(5620, 35),
- CHAN(5640, 36),
- CHAN(5660, 37),
- CHAN(5680, 38),
- CHAN(5700, 39),
- CHAN(5745, 40),
- CHAN(5765, 41),
- CHAN(5785, 42),
- CHAN(5805, 43),
- CHAN(5825, 44),
- CHAN(5170, 45),
- CHAN(5190, 46),
- CHAN(5210, 47),
- CHAN(5230, 48),
-};
-#undef CHAN
-
-#define AR9170_HT_CAP \
-{ \
- .ht_supported = true, \
- .cap = IEEE80211_HT_CAP_MAX_AMSDU | \
- IEEE80211_HT_CAP_SUP_WIDTH_20_40 | \
- IEEE80211_HT_CAP_SGI_40 | \
- IEEE80211_HT_CAP_GRN_FLD | \
- IEEE80211_HT_CAP_DSSSCCK40 | \
- IEEE80211_HT_CAP_SM_PS, \
- .ampdu_factor = 3, \
- .ampdu_density = 6, \
- .mcs = { \
- .rx_mask = { 0xff, 0xff, 0, 0, 0x1, 0, 0, 0, 0, 0, }, \
- .rx_highest = cpu_to_le16(300), \
- .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
- }, \
-}
-
-static struct ieee80211_supported_band ar9170_band_2GHz = {
- .channels = ar9170_2ghz_chantable,
- .n_channels = ARRAY_SIZE(ar9170_2ghz_chantable),
- .bitrates = ar9170_g_ratetable,
- .n_bitrates = ar9170_g_ratetable_size,
- .ht_cap = AR9170_HT_CAP,
-};
-
-static struct ieee80211_supported_band ar9170_band_5GHz = {
- .channels = ar9170_5ghz_chantable,
- .n_channels = ARRAY_SIZE(ar9170_5ghz_chantable),
- .bitrates = ar9170_a_ratetable,
- .n_bitrates = ar9170_a_ratetable_size,
- .ht_cap = AR9170_HT_CAP,
-};
-
-static void ar9170_tx(struct ar9170 *ar);
-
-static inline u16 ar9170_get_seq_h(struct ieee80211_hdr *hdr)
-{
- return le16_to_cpu(hdr->seq_ctrl) >> 4;
-}
-
-static inline u16 ar9170_get_seq(struct sk_buff *skb)
-{
- struct ar9170_tx_control *txc = (void *) skb->data;
- return ar9170_get_seq_h((void *) txc->frame_data);
-}
-
-#ifdef AR9170_QUEUE_DEBUG
-static void ar9170_print_txheader(struct ar9170 *ar, struct sk_buff *skb)
-{
- struct ar9170_tx_control *txc = (void *) skb->data;
- struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
- struct ar9170_tx_info *arinfo = (void *) txinfo->rate_driver_data;
- struct ieee80211_hdr *hdr = (void *) txc->frame_data;
-
- 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,
- struct sk_buff_head *queue)
-{
- struct sk_buff *skb;
- int i = 0;
-
- printk(KERN_DEBUG "---[ cut here ]---\n");
- 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++);
- ar9170_print_txheader(ar, skb);
- }
- if (i != skb_queue_len(queue))
- printk(KERN_DEBUG "WARNING: queue frame counter "
- "mismatch %d != %d\n", skb_queue_len(queue), i);
- printk(KERN_DEBUG "---[ end ]---\n");
-}
-#endif /* AR9170_QUEUE_DEBUG */
-
-#ifdef AR9170_QUEUE_DEBUG
-static void ar9170_dump_txqueue(struct ar9170 *ar,
- struct sk_buff_head *queue)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&queue->lock, flags);
- __ar9170_dump_txqueue(ar, queue);
- spin_unlock_irqrestore(&queue->lock, flags);
-}
-#endif /* AR9170_QUEUE_DEBUG */
-
-#ifdef AR9170_QUEUE_STOP_DEBUG
-static void __ar9170_dump_txstats(struct ar9170 *ar)
-{
- int i;
-
- wiphy_debug(ar->hw->wiphy, "QoS queue stats\n");
-
- for (i = 0; i < __AR9170_NUM_TXQ; 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 */
-
-/* caller must guarantee exclusive access for _bin_ queue. */
-static void ar9170_recycle_expired(struct ar9170 *ar,
- struct sk_buff_head *queue,
- struct sk_buff_head *bin)
-{
- struct sk_buff *skb, *old = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&queue->lock, flags);
- while ((skb = skb_peek(queue))) {
- struct ieee80211_tx_info *txinfo;
- struct ar9170_tx_info *arinfo;
-
- txinfo = IEEE80211_SKB_CB(skb);
- arinfo = (void *) txinfo->rate_driver_data;
-
- if (time_is_before_jiffies(arinfo->timeout)) {
-#ifdef AR9170_QUEUE_DEBUG
- 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);
- __skb_queue_tail(bin, skb);
- } else {
- break;
- }
-
- if (unlikely(old == skb)) {
- /* bail out - queue is shot. */
-
- WARN_ON(1);
- break;
- }
- old = skb;
- }
- spin_unlock_irqrestore(&queue->lock, flags);
-}
-
-static void ar9170_tx_status(struct ar9170 *ar, struct sk_buff *skb,
- u16 tx_status)
-{
- struct ieee80211_tx_info *txinfo;
- unsigned int retries = 0;
-
- txinfo = IEEE80211_SKB_CB(skb);
- ieee80211_tx_info_clear_status(txinfo);
-
- switch (tx_status) {
- case AR9170_TX_STATUS_RETRY:
- retries = 2;
- case AR9170_TX_STATUS_COMPLETE:
- txinfo->flags |= IEEE80211_TX_STAT_ACK;
- break;
-
- case AR9170_TX_STATUS_FAILED:
- retries = ar->hw->conf.long_frame_max_tx_count;
- break;
-
- default:
- wiphy_err(ar->hw->wiphy,
- "invalid tx_status response (%x)\n", tx_status);
- break;
- }
-
- txinfo->status.rates[0].count = retries + 1;
- skb_pull(skb, sizeof(struct ar9170_tx_control));
- ieee80211_tx_status_irqsafe(ar->hw, skb);
-}
-
-void ar9170_tx_callback(struct ar9170 *ar, struct sk_buff *skb)
-{
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ar9170_tx_info *arinfo = (void *) info->rate_driver_data;
- unsigned int queue = skb_get_queue_mapping(skb);
- unsigned long flags;
-
- spin_lock_irqsave(&ar->tx_stats_lock, flags);
- ar->tx_stats[queue].len--;
-
- if (ar->tx_stats[queue].len < AR9170_NUM_TX_LIMIT_SOFT) {
-#ifdef AR9170_QUEUE_STOP_DEBUG
- 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);
- }
- spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
-
- if (info->flags & IEEE80211_TX_CTL_NO_ACK) {
- ar9170_tx_status(ar, skb, AR9170_TX_STATUS_FAILED);
- } else {
- arinfo->timeout = jiffies +
- msecs_to_jiffies(AR9170_TX_TIMEOUT);
-
- skb_queue_tail(&ar->tx_status[queue], skb);
- }
-
- if (!ar->tx_stats[queue].len &&
- !skb_queue_empty(&ar->tx_pending[queue])) {
- ar9170_tx(ar);
- }
-}
-
-static struct sk_buff *ar9170_get_queued_skb(struct ar9170 *ar,
- const u8 *mac,
- struct sk_buff_head *queue,
- const u32 rate)
-{
- unsigned long flags;
- struct sk_buff *skb;
-
- /*
- * Unfortunately, the firmware does not tell to which (queued) frame
- * this transmission status report belongs to.
- *
- * So we have to make risky guesses - with the scarce information
- * the firmware provided (-> destination MAC, and phy_control) -
- * and hope that we picked the right one...
- */
-
- spin_lock_irqsave(&queue->lock, flags);
- skb_queue_walk(queue, skb) {
- struct ar9170_tx_control *txc = (void *) skb->data;
- struct ieee80211_hdr *hdr = (void *) txc->frame_data;
- u32 r;
-
- if (mac && compare_ether_addr(ieee80211_get_DA(hdr), mac)) {
-#ifdef AR9170_QUEUE_DEBUG
- 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;
- }
-
- r = (le32_to_cpu(txc->phy_control) & AR9170_TX_PHY_MCS_MASK) >>
- AR9170_TX_PHY_MCS_SHIFT;
-
- if ((rate != AR9170_TX_INVALID_RATE) && (r != rate)) {
-#ifdef AR9170_QUEUE_DEBUG
- wiphy_debug(ar->hw->wiphy,
- "skip frame => rate %d != %d\n", rate, r);
- ar9170_print_txheader(ar, skb);
-#endif /* AR9170_QUEUE_DEBUG */
- continue;
- }
-
- __skb_unlink(skb, queue);
- spin_unlock_irqrestore(&queue->lock, flags);
- return skb;
- }
-
-#ifdef AR9170_QUEUE_DEBUG
- 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);
-
- return NULL;
-}
-
-/*
- * This worker tries to keeps an maintain tx_status queues.
- * So we can guarantee that incoming tx_status reports are
- * actually for a pending frame.
- */
-
-static void ar9170_tx_janitor(struct work_struct *work)
-{
- struct ar9170 *ar = container_of(work, struct ar9170,
- tx_janitor.work);
- struct sk_buff_head waste;
- unsigned int i;
- bool resched = false;
-
- if (unlikely(!IS_STARTED(ar)))
- return ;
-
- skb_queue_head_init(&waste);
-
- for (i = 0; i < __AR9170_NUM_TXQ; i++) {
-#ifdef AR9170_QUEUE_DEBUG
- 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 */
-
- ar9170_recycle_expired(ar, &ar->tx_status[i], &waste);
- ar9170_recycle_expired(ar, &ar->tx_pending[i], &waste);
- skb_queue_purge(&waste);
-
- if (!skb_queue_empty(&ar->tx_status[i]) ||
- !skb_queue_empty(&ar->tx_pending[i]))
- resched = true;
- }
-
- if (!resched)
- return;
-
- ieee80211_queue_delayed_work(ar->hw,
- &ar->tx_janitor,
- msecs_to_jiffies(AR9170_JANITOR_DELAY));
-}
-
-void ar9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
-{
- struct ar9170_cmd_response *cmd = (void *) buf;
-
- if ((cmd->type & 0xc0) != 0xc0) {
- ar->callback_cmd(ar, len, buf);
- return;
- }
-
- /* hardware event handlers */
- switch (cmd->type) {
- case 0xc1: {
- /*
- * TX status notification:
- * bytes: 0c c1 XX YY M1 M2 M3 M4 M5 M6 R4 R3 R2 R1 S2 S1
- *
- * XX always 81
- * YY always 00
- * M1-M6 is the MAC address
- * R1-R4 is the transmit rate
- * S1-S2 is the transmit status
- */
-
- struct sk_buff *skb;
- u32 phy = le32_to_cpu(cmd->tx_status.rate);
- u32 q = (phy & AR9170_TX_PHY_QOS_MASK) >>
- AR9170_TX_PHY_QOS_SHIFT;
-#ifdef AR9170_QUEUE_DEBUG
- 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,
- &ar->tx_status[q],
- AR9170_TX_INVALID_RATE);
- if (unlikely(!skb))
- return ;
-
- ar9170_tx_status(ar, skb, le16_to_cpu(cmd->tx_status.status));
- break;
- }
-
- case 0xc0:
- /*
- * pre-TBTT event
- */
- if (ar->vif && ar->vif->type == NL80211_IFTYPE_AP)
- ieee80211_queue_work(ar->hw, &ar->beacon_work);
- break;
-
- case 0xc2:
- /*
- * (IBSS) beacon send notification
- * bytes: 04 c2 XX YY B4 B3 B2 B1
- *
- * XX always 80
- * YY always 00
- * B1-B4 "should" be the number of send out beacons.
- */
- break;
-
- case 0xc3:
- /* End of Atim Window */
- break;
-
- case 0xc4:
- /* BlockACK bitmap */
- break;
-
- case 0xc5:
- /* BlockACK events */
- break;
-
- case 0xc6:
- /* Watchdog Interrupt */
- break;
-
- case 0xc9:
- /* retransmission issue / SIFS/EIFS collision ?! */
- break;
-
- /* firmware debug */
- case 0xca:
- printk(KERN_DEBUG "ar9170 FW: %.*s\n", len - 4,
- (char *)buf + 4);
- break;
- case 0xcb:
- len -= 4;
-
- switch (len) {
- case 1:
- printk(KERN_DEBUG "ar9170 FW: u8: %#.2x\n",
- *((char *)buf + 4));
- break;
- case 2:
- printk(KERN_DEBUG "ar9170 FW: u8: %#.4x\n",
- le16_to_cpup((__le16 *)((char *)buf + 4)));
- break;
- case 4:
- printk(KERN_DEBUG "ar9170 FW: u8: %#.8x\n",
- le32_to_cpup((__le32 *)((char *)buf + 4)));
- break;
- case 8:
- printk(KERN_DEBUG "ar9170 FW: u8: %#.16lx\n",
- (unsigned long)le64_to_cpup(
- (__le64 *)((char *)buf + 4)));
- break;
- }
- break;
- case 0xcc:
- print_hex_dump_bytes("ar9170 FW:", DUMP_PREFIX_NONE,
- (char *)buf + 4, len - 4);
- break;
-
- default:
- pr_info("received unhandled event %x\n", cmd->type);
- print_hex_dump_bytes("dump:", DUMP_PREFIX_NONE, buf, len);
- break;
- }
-}
-
-static void ar9170_rx_reset_rx_mpdu(struct ar9170 *ar)
-{
- memset(&ar->rx_mpdu.plcp, 0, sizeof(struct ar9170_rx_head));
- ar->rx_mpdu.has_plcp = false;
-}
-
-int ar9170_nag_limiter(struct ar9170 *ar)
-{
- bool print_message;
-
- /*
- * we expect all sorts of errors in promiscuous mode.
- * don't bother with it, it's OK!
- */
- if (ar->sniffer_enabled)
- return false;
-
- /*
- * only go for frequent errors! The hardware tends to
- * do some stupid thing once in a while under load, in
- * noisy environments or just for fun!
- */
- if (time_before(jiffies, ar->bad_hw_nagger) && net_ratelimit())
- print_message = true;
- else
- print_message = false;
-
- /* reset threshold for "once in a while" */
- ar->bad_hw_nagger = jiffies + HZ / 4;
- return print_message;
-}
-
-static int ar9170_rx_mac_status(struct ar9170 *ar,
- struct ar9170_rx_head *head,
- struct ar9170_rx_macstatus *mac,
- struct ieee80211_rx_status *status)
-{
- u8 error, decrypt;
-
- BUILD_BUG_ON(sizeof(struct ar9170_rx_head) != 12);
- BUILD_BUG_ON(sizeof(struct ar9170_rx_macstatus) != 4);
-
- error = mac->error;
- if (error & AR9170_RX_ERROR_MMIC) {
- status->flag |= RX_FLAG_MMIC_ERROR;
- error &= ~AR9170_RX_ERROR_MMIC;
- }
-
- if (error & AR9170_RX_ERROR_PLCP) {
- status->flag |= RX_FLAG_FAILED_PLCP_CRC;
- error &= ~AR9170_RX_ERROR_PLCP;
-
- if (!(ar->filter_state & FIF_PLCPFAIL))
- return -EINVAL;
- }
-
- if (error & AR9170_RX_ERROR_FCS) {
- status->flag |= RX_FLAG_FAILED_FCS_CRC;
- error &= ~AR9170_RX_ERROR_FCS;
-
- if (!(ar->filter_state & FIF_FCSFAIL))
- return -EINVAL;
- }
-
- decrypt = ar9170_get_decrypt_type(mac);
- if (!(decrypt & AR9170_RX_ENC_SOFTWARE) &&
- decrypt != AR9170_ENC_ALG_NONE)
- status->flag |= RX_FLAG_DECRYPTED;
-
- /* ignore wrong RA errors */
- error &= ~AR9170_RX_ERROR_WRONG_RA;
-
- if (error & AR9170_RX_ERROR_DECRYPT) {
- error &= ~AR9170_RX_ERROR_DECRYPT;
- /*
- * Rx decryption is done in place,
- * the original data is lost anyway.
- */
-
- return -EINVAL;
- }
-
- /* drop any other error frames */
- if (unlikely(error)) {
- /* TODO: update netdevice's RX dropped/errors statistics */
-
- if (ar9170_nag_limiter(ar))
- wiphy_debug(ar->hw->wiphy,
- "received frame with suspicious error code (%#x).\n",
- error);
-
- return -EINVAL;
- }
-
- status->band = ar->channel->band;
- status->freq = ar->channel->center_freq;
-
- switch (mac->status & AR9170_RX_STATUS_MODULATION_MASK) {
- case AR9170_RX_STATUS_MODULATION_CCK:
- if (mac->status & AR9170_RX_STATUS_SHORT_PREAMBLE)
- status->flag |= RX_FLAG_SHORTPRE;
- switch (head->plcp[0]) {
- case 0x0a:
- status->rate_idx = 0;
- break;
- case 0x14:
- status->rate_idx = 1;
- break;
- case 0x37:
- status->rate_idx = 2;
- break;
- case 0x6e:
- status->rate_idx = 3;
- break;
- default:
- if (ar9170_nag_limiter(ar))
- wiphy_err(ar->hw->wiphy,
- "invalid plcp cck rate (%x).\n",
- head->plcp[0]);
- return -EINVAL;
- }
- break;
-
- case AR9170_RX_STATUS_MODULATION_DUPOFDM:
- case AR9170_RX_STATUS_MODULATION_OFDM:
- switch (head->plcp[0] & 0xf) {
- case 0xb:
- status->rate_idx = 0;
- break;
- case 0xf:
- status->rate_idx = 1;
- break;
- case 0xa:
- status->rate_idx = 2;
- break;
- case 0xe:
- status->rate_idx = 3;
- break;
- case 0x9:
- status->rate_idx = 4;
- break;
- case 0xd:
- status->rate_idx = 5;
- break;
- case 0x8:
- status->rate_idx = 6;
- break;
- case 0xc:
- status->rate_idx = 7;
- break;
- default:
- if (ar9170_nag_limiter(ar))
- wiphy_err(ar->hw->wiphy,
- "invalid plcp ofdm rate (%x).\n",
- head->plcp[0]);
- return -EINVAL;
- }
- if (status->band == IEEE80211_BAND_2GHZ)
- status->rate_idx += 4;
- break;
-
- case AR9170_RX_STATUS_MODULATION_HT:
- if (head->plcp[3] & 0x80)
- status->flag |= RX_FLAG_40MHZ;
- if (head->plcp[6] & 0x80)
- status->flag |= RX_FLAG_SHORT_GI;
-
- status->rate_idx = clamp(0, 75, head->plcp[6] & 0x7f);
- status->flag |= RX_FLAG_HT;
- break;
-
- default:
- if (ar9170_nag_limiter(ar))
- wiphy_err(ar->hw->wiphy, "invalid modulation\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-static void ar9170_rx_phy_status(struct ar9170 *ar,
- struct ar9170_rx_phystatus *phy,
- struct ieee80211_rx_status *status)
-{
- int i;
-
- BUILD_BUG_ON(sizeof(struct ar9170_rx_phystatus) != 20);
-
- for (i = 0; i < 3; i++)
- if (phy->rssi[i] != 0x80)
- status->antenna |= BIT(i);
-
- /* post-process RSSI */
- for (i = 0; i < 7; i++)
- if (phy->rssi[i] & 0x80)
- phy->rssi[i] = ((phy->rssi[i] & 0x7f) + 1) & 0x7f;
-
- /* TODO: we could do something with phy_errors */
- status->signal = ar->noise[0] + phy->rssi_combined;
-}
-
-static struct sk_buff *ar9170_rx_copy_data(u8 *buf, int len)
-{
- struct sk_buff *skb;
- int reserved = 0;
- struct ieee80211_hdr *hdr = (void *) buf;
-
- if (ieee80211_is_data_qos(hdr->frame_control)) {
- u8 *qc = ieee80211_get_qos_ctl(hdr);
- reserved += NET_IP_ALIGN;
-
- if (*qc & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)
- reserved += NET_IP_ALIGN;
- }
-
- if (ieee80211_has_a4(hdr->frame_control))
- reserved += NET_IP_ALIGN;
-
- reserved = 32 + (reserved & NET_IP_ALIGN);
-
- skb = dev_alloc_skb(len + reserved);
- if (likely(skb)) {
- skb_reserve(skb, reserved);
- memcpy(skb_put(skb, len), buf, len);
- }
-
- return skb;
-}
-
-/*
- * If the frame alignment is right (or the kernel has
- * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS), and there
- * is only a single MPDU in the USB frame, then we could
- * submit to mac80211 the SKB directly. However, since
- * there may be multiple packets in one SKB in stream
- * mode, and we need to observe the proper ordering,
- * this is non-trivial.
- */
-
-static void ar9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len)
-{
- struct ar9170_rx_head *head;
- struct ar9170_rx_macstatus *mac;
- struct ar9170_rx_phystatus *phy = NULL;
- struct ieee80211_rx_status status;
- struct sk_buff *skb;
- int mpdu_len;
-
- if (unlikely(!IS_STARTED(ar) || len < (sizeof(*mac))))
- return ;
-
- /* Received MPDU */
- mpdu_len = len - sizeof(*mac);
-
- mac = (void *)(buf + mpdu_len);
- if (unlikely(mac->error & AR9170_RX_ERROR_FATAL)) {
- /* this frame is too damaged and can't be used - drop it */
-
- return ;
- }
-
- switch (mac->status & AR9170_RX_STATUS_MPDU_MASK) {
- case AR9170_RX_STATUS_MPDU_FIRST:
- /* first mpdu packet has the plcp header */
- if (likely(mpdu_len >= sizeof(struct ar9170_rx_head))) {
- head = (void *) buf;
- memcpy(&ar->rx_mpdu.plcp, (void *) buf,
- sizeof(struct ar9170_rx_head));
-
- mpdu_len -= sizeof(struct ar9170_rx_head);
- buf += sizeof(struct ar9170_rx_head);
- ar->rx_mpdu.has_plcp = true;
- } else {
- if (ar9170_nag_limiter(ar))
- wiphy_err(ar->hw->wiphy,
- "plcp info is clipped.\n");
- return ;
- }
- break;
-
- case AR9170_RX_STATUS_MPDU_LAST:
- /* last mpdu has a extra tail with phy status information */
-
- if (likely(mpdu_len >= sizeof(struct ar9170_rx_phystatus))) {
- mpdu_len -= sizeof(struct ar9170_rx_phystatus);
- phy = (void *)(buf + mpdu_len);
- } else {
- if (ar9170_nag_limiter(ar))
- wiphy_err(ar->hw->wiphy,
- "frame tail is clipped.\n");
- return ;
- }
-
- case AR9170_RX_STATUS_MPDU_MIDDLE:
- /* middle mpdus are just data */
- if (unlikely(!ar->rx_mpdu.has_plcp)) {
- if (!ar9170_nag_limiter(ar))
- return ;
-
- wiphy_err(ar->hw->wiphy,
- "rx stream did not start with a first_mpdu frame tag.\n");
-
- return ;
- }
-
- head = &ar->rx_mpdu.plcp;
- break;
-
- case AR9170_RX_STATUS_MPDU_SINGLE:
- /* single mpdu - has plcp (head) and phy status (tail) */
- head = (void *) buf;
-
- mpdu_len -= sizeof(struct ar9170_rx_head);
- mpdu_len -= sizeof(struct ar9170_rx_phystatus);
-
- buf += sizeof(struct ar9170_rx_head);
- phy = (void *)(buf + mpdu_len);
- break;
-
- default:
- BUG_ON(1);
- break;
- }
-
- if (unlikely(mpdu_len < FCS_LEN))
- return ;
-
- memset(&status, 0, sizeof(status));
- if (unlikely(ar9170_rx_mac_status(ar, head, mac, &status)))
- return ;
-
- if (phy)
- ar9170_rx_phy_status(ar, phy, &status);
-
- skb = ar9170_rx_copy_data(buf, mpdu_len);
- if (likely(skb)) {
- memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
- ieee80211_rx_irqsafe(ar->hw, skb);
- }
-}
-
-void ar9170_rx(struct ar9170 *ar, struct sk_buff *skb)
-{
- unsigned int i, tlen, resplen, wlen = 0, clen = 0;
- u8 *tbuf, *respbuf;
-
- tbuf = skb->data;
- tlen = skb->len;
-
- while (tlen >= 4) {
- clen = tbuf[1] << 8 | tbuf[0];
- wlen = ALIGN(clen, 4);
-
- /* check if this is stream has a valid tag.*/
- if (tbuf[2] != 0 || tbuf[3] != 0x4e) {
- /*
- * TODO: handle the highly unlikely event that the
- * corrupted stream has the TAG at the right position.
- */
-
- /* check if the frame can be repaired. */
- if (!ar->rx_failover_missing) {
- /* this is no "short read". */
- if (ar9170_nag_limiter(ar)) {
- wiphy_err(ar->hw->wiphy,
- "missing tag!\n");
- goto err_telluser;
- } else
- goto err_silent;
- }
-
- if (ar->rx_failover_missing > tlen) {
- if (ar9170_nag_limiter(ar)) {
- wiphy_err(ar->hw->wiphy,
- "possible multi stream corruption!\n");
- goto err_telluser;
- } else
- goto err_silent;
- }
-
- memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen);
- ar->rx_failover_missing -= tlen;
-
- if (ar->rx_failover_missing <= 0) {
- /*
- * nested ar9170_rx call!
- * termination is guaranteed, even when the
- * combined frame also have a element with
- * a bad tag.
- */
-
- ar->rx_failover_missing = 0;
- ar9170_rx(ar, ar->rx_failover);
-
- skb_reset_tail_pointer(ar->rx_failover);
- skb_trim(ar->rx_failover, 0);
- }
-
- return ;
- }
-
- /* check if stream is clipped */
- if (wlen > tlen - 4) {
- if (ar->rx_failover_missing) {
- /* TODO: handle double stream corruption. */
- if (ar9170_nag_limiter(ar)) {
- wiphy_err(ar->hw->wiphy,
- "double rx stream corruption!\n");
- goto err_telluser;
- } else
- goto err_silent;
- }
-
- /*
- * save incomplete data set.
- * the firmware will resend the missing bits when
- * the rx - descriptor comes round again.
- */
-
- memcpy(skb_put(ar->rx_failover, tlen), tbuf, tlen);
- ar->rx_failover_missing = clen - tlen;
- return ;
- }
- resplen = clen;
- respbuf = tbuf + 4;
- tbuf += wlen + 4;
- tlen -= wlen + 4;
-
- i = 0;
-
- /* weird thing, but this is the same in the original driver */
- while (resplen > 2 && i < 12 &&
- respbuf[0] == 0xff && respbuf[1] == 0xff) {
- i += 2;
- resplen -= 2;
- respbuf += 2;
- }
-
- if (resplen < 4)
- continue;
-
- /* found the 6 * 0xffff marker? */
- if (i == 12)
- ar9170_handle_command_response(ar, respbuf, resplen);
- else
- ar9170_handle_mpdu(ar, respbuf, clen);
- }
-
- if (tlen) {
- if (net_ratelimit())
- wiphy_err(ar->hw->wiphy,
- "%d bytes of unprocessed data left in rx stream!\n",
- tlen);
-
- goto err_telluser;
- }
-
- return ;
-
-err_telluser:
- 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,
- ar->rx_failover->data,
- ar->rx_failover->len);
-
- print_hex_dump_bytes("stream:", DUMP_PREFIX_OFFSET,
- skb->data, skb->len);
-
- 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) {
- skb_reset_tail_pointer(ar->rx_failover);
- skb_trim(ar->rx_failover, 0);
- ar->rx_failover_missing = 0;
- }
-}
-
-#define AR9170_FILL_QUEUE(queue, ai_fs, cwmin, cwmax, _txop) \
-do { \
- queue.aifs = ai_fs; \
- queue.cw_min = cwmin; \
- queue.cw_max = cwmax; \
- queue.txop = _txop; \
-} while (0)
-
-static int ar9170_op_start(struct ieee80211_hw *hw)
-{
- struct ar9170 *ar = hw->priv;
- int err, i;
-
- mutex_lock(&ar->mutex);
-
- /* reinitialize queues statistics */
- memset(&ar->tx_stats, 0, sizeof(ar->tx_stats));
- for (i = 0; i < __AR9170_NUM_TXQ; i++)
- ar->tx_stats[i].limit = AR9170_TXQ_DEPTH;
-
- /* reset QoS defaults */
- AR9170_FILL_QUEUE(ar->edcf[0], 3, 15, 1023, 0); /* BEST EFFORT*/
- AR9170_FILL_QUEUE(ar->edcf[1], 7, 15, 1023, 0); /* BACKGROUND */
- AR9170_FILL_QUEUE(ar->edcf[2], 2, 7, 15, 94); /* VIDEO */
- AR9170_FILL_QUEUE(ar->edcf[3], 2, 3, 7, 47); /* VOICE */
- AR9170_FILL_QUEUE(ar->edcf[4], 2, 3, 7, 0); /* SPECIAL */
-
- /* set sane AMPDU defaults */
- ar->global_ampdu_density = 6;
- ar->global_ampdu_factor = 3;
-
- ar->bad_hw_nagger = jiffies;
-
- err = ar->open(ar);
- if (err)
- goto out;
-
- err = ar9170_init_mac(ar);
- if (err)
- goto out;
-
- err = ar9170_set_qos(ar);
- if (err)
- goto out;
-
- err = ar9170_init_phy(ar, IEEE80211_BAND_2GHZ);
- if (err)
- goto out;
-
- err = ar9170_init_rf(ar);
- if (err)
- goto out;
-
- /* start DMA */
- err = ar9170_write_reg(ar, 0x1c3d30, 0x100);
- if (err)
- goto out;
-
- ar->state = AR9170_STARTED;
-
-out:
- mutex_unlock(&ar->mutex);
- return err;
-}
-
-static void ar9170_op_stop(struct ieee80211_hw *hw)
-{
- struct ar9170 *ar = hw->priv;
- unsigned int i;
-
- if (IS_STARTED(ar))
- ar->state = AR9170_IDLE;
-
- cancel_delayed_work_sync(&ar->tx_janitor);
-#ifdef CONFIG_AR9170_LEDS
- cancel_delayed_work_sync(&ar->led_work);
-#endif
- cancel_work_sync(&ar->beacon_work);
-
- mutex_lock(&ar->mutex);
-
- if (IS_ACCEPTING_CMD(ar)) {
- ar9170_set_leds_state(ar, 0);
-
- /* stop DMA */
- ar9170_write_reg(ar, 0x1c3d30, 0);
- ar->stop(ar);
- }
-
- for (i = 0; i < __AR9170_NUM_TXQ; i++) {
- skb_queue_purge(&ar->tx_pending[i]);
- skb_queue_purge(&ar->tx_status[i]);
- }
-
- mutex_unlock(&ar->mutex);
-}
-
-static int ar9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
-{
- struct ieee80211_hdr *hdr;
- struct ar9170_tx_control *txc;
- struct ieee80211_tx_info *info;
- struct ieee80211_tx_rate *txrate;
- struct ar9170_tx_info *arinfo;
- unsigned int queue = skb_get_queue_mapping(skb);
- u16 keytype = 0;
- u16 len, icv = 0;
-
- BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data));
-
- hdr = (void *)skb->data;
- info = IEEE80211_SKB_CB(skb);
- len = skb->len;
-
- txc = (void *)skb_push(skb, sizeof(*txc));
-
- if (info->control.hw_key) {
- icv = info->control.hw_key->icv_len;
-
- switch (info->control.hw_key->cipher) {
- case WLAN_CIPHER_SUITE_WEP40:
- case WLAN_CIPHER_SUITE_WEP104:
- case WLAN_CIPHER_SUITE_TKIP:
- keytype = AR9170_TX_MAC_ENCR_RC4;
- break;
- case WLAN_CIPHER_SUITE_CCMP:
- keytype = AR9170_TX_MAC_ENCR_AES;
- break;
- default:
- WARN_ON(1);
- goto err_out;
- }
- }
-
- /* Length */
- txc->length = cpu_to_le16(len + icv + 4);
-
- txc->mac_control = cpu_to_le16(AR9170_TX_MAC_HW_DURATION |
- AR9170_TX_MAC_BACKOFF);
- txc->mac_control |= cpu_to_le16(ar9170_qos_hwmap[queue] <<
- AR9170_TX_MAC_QOS_SHIFT);
- txc->mac_control |= cpu_to_le16(keytype);
- txc->phy_control = cpu_to_le32(0);
-
- if (info->flags & IEEE80211_TX_CTL_NO_ACK)
- txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_NO_ACK);
-
- txrate = &info->control.rates[0];
- if (txrate->flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
- txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_CTS);
- else if (txrate->flags & IEEE80211_TX_RC_USE_RTS_CTS)
- txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_PROT_RTS);
-
- arinfo = (void *)info->rate_driver_data;
- arinfo->timeout = jiffies + msecs_to_jiffies(AR9170_QUEUE_TIMEOUT);
-
- if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
- (is_valid_ether_addr(ieee80211_get_DA(hdr)))) {
- /*
- * WARNING:
- * Putting the QoS queue bits into an unexplored territory is
- * certainly not elegant.
- *
- * In my defense: This idea provides a reasonable way to
- * smuggle valuable information to the tx_status callback.
- * Also, the idea behind this bit-abuse came straight from
- * the original driver code.
- */
-
- txc->phy_control |=
- cpu_to_le32(queue << AR9170_TX_PHY_QOS_SHIFT);
-
- txc->mac_control |= cpu_to_le16(AR9170_TX_MAC_RATE_PROBE);
- }
-
- return 0;
-
-err_out:
- skb_pull(skb, sizeof(*txc));
- return -EINVAL;
-}
-
-static void ar9170_tx_prepare_phy(struct ar9170 *ar, struct sk_buff *skb)
-{
- struct ar9170_tx_control *txc;
- struct ieee80211_tx_info *info;
- struct ieee80211_rate *rate = NULL;
- struct ieee80211_tx_rate *txrate;
- u32 power, chains;
-
- txc = (void *) skb->data;
- info = IEEE80211_SKB_CB(skb);
- txrate = &info->control.rates[0];
-
- if (txrate->flags & IEEE80211_TX_RC_GREEN_FIELD)
- txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_GREENFIELD);
-
- if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
- txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_SHORT_PREAMBLE);
-
- if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
- txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_BW_40MHZ);
- /* this works because 40 MHz is 2 and dup is 3 */
- if (txrate->flags & IEEE80211_TX_RC_DUP_DATA)
- txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_BW_40MHZ_DUP);
-
- if (txrate->flags & IEEE80211_TX_RC_SHORT_GI)
- txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_SHORT_GI);
-
- if (txrate->flags & IEEE80211_TX_RC_MCS) {
- u32 r = txrate->idx;
- u8 *txpower;
-
- /* heavy clip control */
- txc->phy_control |= cpu_to_le32((r & 0x7) << 7);
-
- r <<= AR9170_TX_PHY_MCS_SHIFT;
- BUG_ON(r & ~AR9170_TX_PHY_MCS_MASK);
-
- txc->phy_control |= cpu_to_le32(r & AR9170_TX_PHY_MCS_MASK);
- txc->phy_control |= cpu_to_le32(AR9170_TX_PHY_MOD_HT);
-
- if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) {
- if (info->band == IEEE80211_BAND_5GHZ)
- txpower = ar->power_5G_ht40;
- else
- txpower = ar->power_2G_ht40;
- } else {
- if (info->band == IEEE80211_BAND_5GHZ)
- txpower = ar->power_5G_ht20;
- else
- txpower = ar->power_2G_ht20;
- }
-
- power = txpower[(txrate->idx) & 7];
- } else {
- u8 *txpower;
- u32 mod;
- u32 phyrate;
- u8 idx = txrate->idx;
-
- if (info->band != IEEE80211_BAND_2GHZ) {
- idx += 4;
- txpower = ar->power_5G_leg;
- mod = AR9170_TX_PHY_MOD_OFDM;
- } else {
- if (idx < 4) {
- txpower = ar->power_2G_cck;
- mod = AR9170_TX_PHY_MOD_CCK;
- } else {
- mod = AR9170_TX_PHY_MOD_OFDM;
- txpower = ar->power_2G_ofdm;
- }
- }
-
- rate = &__ar9170_ratetable[idx];
-
- phyrate = rate->hw_value & 0xF;
- power = txpower[(rate->hw_value & 0x30) >> 4];
- phyrate <<= AR9170_TX_PHY_MCS_SHIFT;
-
- txc->phy_control |= cpu_to_le32(mod);
- txc->phy_control |= cpu_to_le32(phyrate);
- }
-
- power <<= AR9170_TX_PHY_TX_PWR_SHIFT;
- power &= AR9170_TX_PHY_TX_PWR_MASK;
- txc->phy_control |= cpu_to_le32(power);
-
- /* set TX chains */
- if (ar->eeprom.tx_mask == 1) {
- chains = AR9170_TX_PHY_TXCHAIN_1;
- } else {
- chains = AR9170_TX_PHY_TXCHAIN_2;
-
- /* >= 36M legacy OFDM - use only one chain */
- if (rate && rate->bitrate >= 360)
- chains = AR9170_TX_PHY_TXCHAIN_1;
- }
- txc->phy_control |= cpu_to_le32(chains << AR9170_TX_PHY_TXCHAIN_SHIFT);
-}
-
-static void ar9170_tx(struct ar9170 *ar)
-{
- struct sk_buff *skb;
- unsigned long flags;
- struct ieee80211_tx_info *info;
- struct ar9170_tx_info *arinfo;
- unsigned int i, frames, frames_failed, remaining_space;
- int err;
- bool schedule_garbagecollector = false;
-
- BUILD_BUG_ON(sizeof(*arinfo) > sizeof(info->rate_driver_data));
-
- if (unlikely(!IS_STARTED(ar)))
- return ;
-
- remaining_space = AR9170_TX_MAX_PENDING;
-
- for (i = 0; i < __AR9170_NUM_TXQ; i++) {
- spin_lock_irqsave(&ar->tx_stats_lock, flags);
- frames = min(ar->tx_stats[i].limit - ar->tx_stats[i].len,
- skb_queue_len(&ar->tx_pending[i]));
-
- if (remaining_space < frames) {
-#ifdef AR9170_QUEUE_DEBUG
- 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;
- }
-
- ar->tx_stats[i].len += frames;
- ar->tx_stats[i].count += frames;
- if (ar->tx_stats[i].len >= ar->tx_stats[i].limit) {
-#ifdef AR9170_QUEUE_DEBUG
- 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
- 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);
- }
-
- spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
-
- if (!frames)
- continue;
-
- frames_failed = 0;
- while (frames) {
- skb = skb_dequeue(&ar->tx_pending[i]);
- if (unlikely(!skb)) {
- frames_failed += frames;
- frames = 0;
- break;
- }
-
- info = IEEE80211_SKB_CB(skb);
- arinfo = (void *) info->rate_driver_data;
-
- /* TODO: cancel stuck frames */
- arinfo->timeout = jiffies +
- msecs_to_jiffies(AR9170_TX_TIMEOUT);
-
-#ifdef AR9170_QUEUE_DEBUG
- wiphy_debug(ar->hw->wiphy, "send frame q:%d =>\n", i);
- ar9170_print_txheader(ar, skb);
-#endif /* AR9170_QUEUE_DEBUG */
-
- err = ar->tx(ar, skb);
- if (unlikely(err)) {
- frames_failed++;
- dev_kfree_skb_any(skb);
- } else {
- remaining_space--;
- schedule_garbagecollector = true;
- }
-
- frames--;
- }
-
-#ifdef AR9170_QUEUE_DEBUG
- wiphy_debug(ar->hw->wiphy,
- "ar9170_tx report for queue %d\n", i);
-
- 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
- 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
- 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);
- spin_unlock_irqrestore(&ar->tx_stats_lock, flags);
- }
- }
-
- if (!schedule_garbagecollector)
- return;
-
- ieee80211_queue_delayed_work(ar->hw,
- &ar->tx_janitor,
- msecs_to_jiffies(AR9170_JANITOR_DELAY));
-}
-
-void ar9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
- struct ar9170 *ar = hw->priv;
- struct ieee80211_tx_info *info;
- unsigned int queue;
-
- if (unlikely(!IS_STARTED(ar)))
- goto err_free;
-
- if (unlikely(ar9170_tx_prepare(ar, skb)))
- goto err_free;
-
- queue = skb_get_queue_mapping(skb);
- info = IEEE80211_SKB_CB(skb);
- ar9170_tx_prepare_phy(ar, skb);
- skb_queue_tail(&ar->tx_pending[queue], skb);
-
- ar9170_tx(ar);
- return;
-
-err_free:
- dev_kfree_skb_any(skb);
-}
-
-static int ar9170_op_add_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
-{
- struct ar9170 *ar = hw->priv;
- struct ath_common *common = &ar->common;
- int err = 0;
-
- mutex_lock(&ar->mutex);
-
- if (ar->vif) {
- err = -EBUSY;
- goto unlock;
- }
-
- ar->vif = vif;
- memcpy(common->macaddr, vif->addr, ETH_ALEN);
-
- if (modparam_nohwcrypt || (ar->vif->type != NL80211_IFTYPE_STATION)) {
- ar->rx_software_decryption = true;
- ar->disable_offload = true;
- }
-
- ar->cur_filter = 0;
- err = ar9170_update_frame_filter(ar, AR9170_MAC_REG_FTF_DEFAULTS);
- if (err)
- goto unlock;
-
- err = ar9170_set_operating_mode(ar);
-
-unlock:
- mutex_unlock(&ar->mutex);
- return err;
-}
-
-static void ar9170_op_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
-{
- struct ar9170 *ar = hw->priv;
-
- mutex_lock(&ar->mutex);
- ar->vif = NULL;
- ar9170_update_frame_filter(ar, 0);
- ar9170_set_beacon_timers(ar);
- dev_kfree_skb(ar->beacon);
- ar->beacon = NULL;
- ar->sniffer_enabled = false;
- ar->rx_software_decryption = false;
- ar9170_set_operating_mode(ar);
- mutex_unlock(&ar->mutex);
-}
-
-static int ar9170_op_config(struct ieee80211_hw *hw, u32 changed)
-{
- struct ar9170 *ar = hw->priv;
- int err = 0;
-
- mutex_lock(&ar->mutex);
-
- if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) {
- /* TODO */
- err = 0;
- }
-
- if (changed & IEEE80211_CONF_CHANGE_PS) {
- /* TODO */
- err = 0;
- }
-
- if (changed & IEEE80211_CONF_CHANGE_POWER) {
- /* TODO */
- err = 0;
- }
-
- if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) {
- /*
- * is it long_frame_max_tx_count or short_frame_max_tx_count?
- */
-
- err = ar9170_set_hwretry_limit(ar,
- ar->hw->conf.long_frame_max_tx_count);
- if (err)
- goto out;
- }
-
- if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
-
- /* adjust slot time for 5 GHz */
- err = ar9170_set_slot_time(ar);
- if (err)
- goto out;
-
- err = ar9170_set_dyn_sifs_ack(ar);
- if (err)
- goto out;
-
- err = ar9170_set_channel(ar, hw->conf.channel,
- AR9170_RFI_NONE,
- nl80211_to_ar9170(hw->conf.channel_type));
- if (err)
- goto out;
- }
-
-out:
- mutex_unlock(&ar->mutex);
- return err;
-}
-
-static u64 ar9170_op_prepare_multicast(struct ieee80211_hw *hw,
- struct netdev_hw_addr_list *mc_list)
-{
- u64 mchash;
- struct netdev_hw_addr *ha;
-
- /* always get broadcast frames */
- mchash = 1ULL << (0xff >> 2);
-
- netdev_hw_addr_list_for_each(ha, mc_list)
- mchash |= 1ULL << (ha->addr[5] >> 2);
-
- return mchash;
-}
-
-static void ar9170_op_configure_filter(struct ieee80211_hw *hw,
- unsigned int changed_flags,
- unsigned int *new_flags,
- u64 multicast)
-{
- struct ar9170 *ar = hw->priv;
-
- if (unlikely(!IS_ACCEPTING_CMD(ar)))
- return ;
-
- mutex_lock(&ar->mutex);
-
- /* mask supported flags */
- *new_flags &= FIF_ALLMULTI | FIF_CONTROL | FIF_BCN_PRBRESP_PROMISC |
- FIF_PROMISC_IN_BSS | FIF_FCSFAIL | FIF_PLCPFAIL;
- ar->filter_state = *new_flags;
- /*
- * We can support more by setting the sniffer bit and
- * then checking the error flags, later.
- */
-
- if (changed_flags & FIF_ALLMULTI && *new_flags & FIF_ALLMULTI)
- multicast = ~0ULL;
-
- if (multicast != ar->cur_mc_hash)
- ar9170_update_multicast(ar, multicast);
-
- if (changed_flags & FIF_CONTROL) {
- u32 filter = AR9170_MAC_REG_FTF_PSPOLL |
- AR9170_MAC_REG_FTF_RTS |
- AR9170_MAC_REG_FTF_CTS |
- AR9170_MAC_REG_FTF_ACK |
- AR9170_MAC_REG_FTF_CFE |
- AR9170_MAC_REG_FTF_CFE_ACK;
-
- if (*new_flags & FIF_CONTROL)
- filter |= ar->cur_filter;
- else
- filter &= (~ar->cur_filter);
-
- ar9170_update_frame_filter(ar, filter);
- }
-
- if (changed_flags & FIF_PROMISC_IN_BSS) {
- ar->sniffer_enabled = ((*new_flags) & FIF_PROMISC_IN_BSS) != 0;
- ar9170_set_operating_mode(ar);
- }
-
- mutex_unlock(&ar->mutex);
-}
-
-
-static void ar9170_op_bss_info_changed(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *bss_conf,
- u32 changed)
-{
- struct ar9170 *ar = hw->priv;
- struct ath_common *common = &ar->common;
- int err = 0;
-
- mutex_lock(&ar->mutex);
-
- if (changed & BSS_CHANGED_BSSID) {
- memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
- err = ar9170_set_operating_mode(ar);
- if (err)
- goto out;
- }
-
- if (changed & BSS_CHANGED_BEACON_ENABLED)
- ar->enable_beacon = bss_conf->enable_beacon;
-
- if (changed & BSS_CHANGED_BEACON) {
- err = ar9170_update_beacon(ar);
- if (err)
- goto out;
- }
-
- if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON |
- BSS_CHANGED_BEACON_INT)) {
- err = ar9170_set_beacon_timers(ar);
- if (err)
- goto out;
- }
-
- if (changed & BSS_CHANGED_ASSOC) {
-#ifndef CONFIG_AR9170_LEDS
- /* enable assoc LED. */
- err = ar9170_set_leds_state(ar, bss_conf->assoc ? 2 : 0);
-#endif /* CONFIG_AR9170_LEDS */
- }
-
- if (changed & BSS_CHANGED_HT) {
- /* TODO */
- err = 0;
- }
-
- if (changed & BSS_CHANGED_ERP_SLOT) {
- err = ar9170_set_slot_time(ar);
- if (err)
- goto out;
- }
-
- if (changed & BSS_CHANGED_BASIC_RATES) {
- err = ar9170_set_basic_rates(ar);
- if (err)
- goto out;
- }
-
-out:
- mutex_unlock(&ar->mutex);
-}
-
-static u64 ar9170_op_get_tsf(struct ieee80211_hw *hw)
-{
- struct ar9170 *ar = hw->priv;
- int err;
- u64 tsf;
-#define NR 3
- static const u32 addr[NR] = { AR9170_MAC_REG_TSF_H,
- AR9170_MAC_REG_TSF_L,
- AR9170_MAC_REG_TSF_H };
- u32 val[NR];
- int loops = 0;
-
- mutex_lock(&ar->mutex);
-
- while (loops++ < 10) {
- err = ar9170_read_mreg(ar, NR, addr, val);
- if (err || val[0] == val[2])
- break;
- }
-
- mutex_unlock(&ar->mutex);
-
- if (WARN_ON(err))
- return 0;
- tsf = val[0];
- tsf = (tsf << 32) | val[1];
- return tsf;
-#undef NR
-}
-
-static int ar9170_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
- struct ieee80211_vif *vif, struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key)
-{
- struct ar9170 *ar = hw->priv;
- int err = 0, i;
- u8 ktype;
-
- if ((!ar->vif) || (ar->disable_offload))
- return -EOPNOTSUPP;
-
- switch (key->cipher) {
- case WLAN_CIPHER_SUITE_WEP40:
- ktype = AR9170_ENC_ALG_WEP64;
- break;
- case WLAN_CIPHER_SUITE_WEP104:
- ktype = AR9170_ENC_ALG_WEP128;
- break;
- case WLAN_CIPHER_SUITE_TKIP:
- ktype = AR9170_ENC_ALG_TKIP;
- break;
- case WLAN_CIPHER_SUITE_CCMP:
- ktype = AR9170_ENC_ALG_AESCCMP;
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- mutex_lock(&ar->mutex);
- if (cmd == SET_KEY) {
- if (unlikely(!IS_STARTED(ar))) {
- err = -EOPNOTSUPP;
- goto out;
- }
-
- /* group keys need all-zeroes address */
- if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
- sta = NULL;
-
- if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
- for (i = 0; i < 64; i++)
- if (!(ar->usedkeys & BIT(i)))
- break;
- if (i == 64) {
- ar->rx_software_decryption = true;
- ar9170_set_operating_mode(ar);
- err = -ENOSPC;
- goto out;
- }
- } else {
- i = 64 + key->keyidx;
- }
-
- key->hw_key_idx = i;
-
- err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL, ktype, 0,
- key->key, min_t(u8, 16, key->keylen));
- if (err)
- goto out;
-
- if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
- err = ar9170_upload_key(ar, i, sta ? sta->addr : NULL,
- ktype, 1, key->key + 16, 16);
- if (err)
- goto out;
-
- /*
- * hardware is not capable generating the MMIC
- * for fragmented frames!
- */
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
- }
-
- if (i < 64)
- ar->usedkeys |= BIT(i);
-
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- } else {
- if (unlikely(!IS_STARTED(ar))) {
- /* The device is gone... together with the key ;-) */
- err = 0;
- goto out;
- }
-
- err = ar9170_disable_key(ar, key->hw_key_idx);
- if (err)
- goto out;
-
- if (key->hw_key_idx < 64) {
- ar->usedkeys &= ~BIT(key->hw_key_idx);
- } else {
- err = ar9170_upload_key(ar, key->hw_key_idx, NULL,
- AR9170_ENC_ALG_NONE, 0,
- NULL, 0);
- if (err)
- goto out;
-
- if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
- err = ar9170_upload_key(ar, key->hw_key_idx,
- NULL,
- AR9170_ENC_ALG_NONE, 1,
- NULL, 0);
- if (err)
- goto out;
- }
-
- }
- }
-
- ar9170_regwrite_begin(ar);
- ar9170_regwrite(AR9170_MAC_REG_ROLL_CALL_TBL_L, ar->usedkeys);
- ar9170_regwrite(AR9170_MAC_REG_ROLL_CALL_TBL_H, ar->usedkeys >> 32);
- ar9170_regwrite_finish();
- err = ar9170_regwrite_result();
-
-out:
- mutex_unlock(&ar->mutex);
-
- return err;
-}
-
-static int ar9170_get_stats(struct ieee80211_hw *hw,
- struct ieee80211_low_level_stats *stats)
-{
- struct ar9170 *ar = hw->priv;
- u32 val;
- int err;
-
- mutex_lock(&ar->mutex);
- err = ar9170_read_reg(ar, AR9170_MAC_REG_TX_RETRY, &val);
- ar->stats.dot11ACKFailureCount += val;
-
- memcpy(stats, &ar->stats, sizeof(*stats));
- mutex_unlock(&ar->mutex);
-
- 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)
-{
- struct ar9170 *ar = hw->priv;
- int ret;
-
- mutex_lock(&ar->mutex);
- if (queue < __AR9170_NUM_TXQ) {
- memcpy(&ar->edcf[ar9170_qos_hwmap[queue]],
- param, sizeof(*param));
-
- ret = ar9170_set_qos(ar);
- } else {
- ret = -EINVAL;
- }
-
- mutex_unlock(&ar->mutex);
- return ret;
-}
-
-static int ar9170_ampdu_action(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- enum ieee80211_ampdu_mlme_action action,
- struct ieee80211_sta *sta, u16 tid, u16 *ssn,
- u8 buf_size)
-{
- switch (action) {
- case IEEE80211_AMPDU_RX_START:
- case IEEE80211_AMPDU_RX_STOP:
- /* Handled by firmware */
- break;
-
- default:
- return -EOPNOTSUPP;
- }
-
- return 0;
-}
-
-static const struct ieee80211_ops ar9170_ops = {
- .start = ar9170_op_start,
- .stop = ar9170_op_stop,
- .tx = ar9170_op_tx,
- .add_interface = ar9170_op_add_interface,
- .remove_interface = ar9170_op_remove_interface,
- .config = ar9170_op_config,
- .prepare_multicast = ar9170_op_prepare_multicast,
- .configure_filter = ar9170_op_configure_filter,
- .conf_tx = ar9170_conf_tx,
- .bss_info_changed = ar9170_op_bss_info_changed,
- .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,
-};
-
-void *ar9170_alloc(size_t priv_size)
-{
- struct ieee80211_hw *hw;
- struct ar9170 *ar;
- struct sk_buff *skb;
- int i;
-
- /*
- * this buffer is used for rx stream reconstruction.
- * Under heavy load this device (or the transport layer?)
- * tends to split the streams into separate rx descriptors.
- */
-
- skb = __dev_alloc_skb(AR9170_RX_STREAM_MAX_SIZE, GFP_KERNEL);
- if (!skb)
- goto err_nomem;
-
- hw = ieee80211_alloc_hw(priv_size, &ar9170_ops);
- if (!hw)
- goto err_nomem;
-
- ar = hw->priv;
- ar->hw = hw;
- ar->rx_failover = skb;
-
- mutex_init(&ar->mutex);
- spin_lock_init(&ar->cmdlock);
- spin_lock_init(&ar->tx_stats_lock);
- for (i = 0; i < __AR9170_NUM_TXQ; i++) {
- skb_queue_head_init(&ar->tx_status[i]);
- skb_queue_head_init(&ar->tx_pending[i]);
- }
- ar9170_rx_reset_rx_mpdu(ar);
- INIT_WORK(&ar->beacon_work, ar9170_new_beacon);
- INIT_DELAYED_WORK(&ar->tx_janitor, ar9170_tx_janitor);
-
- /* all hw supports 2.4 GHz, so set channel to 1 by default */
- ar->channel = &ar9170_2ghz_chantable[0];
-
- /* first part of wiphy init */
- ar->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_WDS) |
- BIT(NL80211_IFTYPE_ADHOC);
- ar->hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
- IEEE80211_HW_SIGNAL_DBM;
-
- ar->hw->queues = __AR9170_NUM_TXQ;
- ar->hw->extra_tx_headroom = 8;
-
- ar->hw->max_rates = 1;
- ar->hw->max_rate_tries = 3;
-
- for (i = 0; i < ARRAY_SIZE(ar->noise); i++)
- ar->noise[i] = -95; /* ATH_DEFAULT_NOISE_FLOOR */
-
- return ar;
-
-err_nomem:
- kfree_skb(skb);
- return ERR_PTR(-ENOMEM);
-}
-
-static int ar9170_read_eeprom(struct ar9170 *ar)
-{
-#define RW 8 /* number of words to read at once */
-#define RB (sizeof(u32) * RW)
- struct ath_regulatory *regulatory = &ar->common.regulatory;
- u8 *eeprom = (void *)&ar->eeprom;
- u8 *addr = ar->eeprom.mac_address;
- __le32 offsets[RW];
- unsigned int rx_streams, tx_streams, tx_params = 0;
- int i, j, err, bands = 0;
-
- BUILD_BUG_ON(sizeof(ar->eeprom) & 3);
-
- BUILD_BUG_ON(RB > AR9170_MAX_CMD_LEN - 4);
-#ifndef __CHECKER__
- /* don't want to handle trailing remains */
- BUILD_BUG_ON(sizeof(ar->eeprom) % RB);
-#endif
-
- for (i = 0; i < sizeof(ar->eeprom)/RB; i++) {
- for (j = 0; j < RW; j++)
- offsets[j] = cpu_to_le32(AR9170_EEPROM_START +
- RB * i + 4 * j);
-
- err = ar->exec_cmd(ar, AR9170_CMD_RREG,
- RB, (u8 *) &offsets,
- RB, eeprom + RB * i);
- if (err)
- return err;
- }
-
-#undef RW
-#undef RB
-
- if (ar->eeprom.length == cpu_to_le16(0xFFFF))
- return -ENODATA;
-
- if (ar->eeprom.operating_flags & AR9170_OPFLAG_2GHZ) {
- ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &ar9170_band_2GHz;
- bands++;
- }
- if (ar->eeprom.operating_flags & AR9170_OPFLAG_5GHZ) {
- ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &ar9170_band_5GHz;
- bands++;
- }
-
- rx_streams = hweight8(ar->eeprom.rx_mask);
- tx_streams = hweight8(ar->eeprom.tx_mask);
-
- if (rx_streams != tx_streams)
- tx_params = IEEE80211_HT_MCS_TX_RX_DIFF;
-
- if (tx_streams >= 1 && tx_streams <= IEEE80211_HT_MCS_TX_MAX_STREAMS)
- tx_params = (tx_streams - 1) <<
- IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT;
-
- ar9170_band_2GHz.ht_cap.mcs.tx_params |= tx_params;
- ar9170_band_5GHz.ht_cap.mcs.tx_params |= tx_params;
-
- /*
- * I measured this, a bandswitch takes roughly
- * 135 ms and a frequency switch about 80.
- *
- * FIXME: measure these values again once EEPROM settings
- * are used, that will influence them!
- */
- if (bands == 2)
- ar->hw->channel_change_time = 135 * 1000;
- else
- ar->hw->channel_change_time = 80 * 1000;
-
- regulatory->current_rd = le16_to_cpu(ar->eeprom.reg_domain[0]);
- regulatory->current_rd_ext = le16_to_cpu(ar->eeprom.reg_domain[1]);
-
- /* second part of wiphy init */
- SET_IEEE80211_PERM_ADDR(ar->hw, addr);
-
- return bands ? 0 : -EINVAL;
-}
-
-static int ar9170_reg_notifier(struct wiphy *wiphy,
- struct regulatory_request *request)
-{
- struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
- struct ar9170 *ar = hw->priv;
-
- return ath_reg_notifier_apply(wiphy, request, &ar->common.regulatory);
-}
-
-int ar9170_register(struct ar9170 *ar, struct device *pdev)
-{
- struct ath_regulatory *regulatory = &ar->common.regulatory;
- int err;
-
- /* try to read EEPROM, init MAC addr */
- err = ar9170_read_eeprom(ar);
- if (err)
- goto err_out;
-
- err = ath_regd_init(regulatory, ar->hw->wiphy,
- ar9170_reg_notifier);
- if (err)
- goto err_out;
-
- err = ieee80211_register_hw(ar->hw);
- if (err)
- goto err_out;
-
- if (!ath_is_world_regd(regulatory))
- regulatory_hint(ar->hw->wiphy, regulatory->alpha2);
-
- err = ar9170_init_leds(ar);
- if (err)
- goto err_unreg;
-
-#ifdef CONFIG_AR9170_LEDS
- err = ar9170_register_leds(ar);
- if (err)
- goto err_unreg;
-#endif /* CONFIG_AR9170_LEDS */
-
- dev_info(pdev, "Atheros AR9170 is registered as '%s'\n",
- wiphy_name(ar->hw->wiphy));
-
- ar->registered = true;
- return 0;
-
-err_unreg:
- ieee80211_unregister_hw(ar->hw);
-
-err_out:
- return err;
-}
-
-void ar9170_unregister(struct ar9170 *ar)
-{
- if (ar->registered) {
-#ifdef CONFIG_AR9170_LEDS
- ar9170_unregister_leds(ar);
-#endif /* CONFIG_AR9170_LEDS */
-
- ieee80211_unregister_hw(ar->hw);
- }
-
- kfree_skb(ar->rx_failover);
- mutex_destroy(&ar->mutex);
-}
diff --git a/drivers/net/wireless/ath/ar9170/phy.c b/drivers/net/wireless/ath/ar9170/phy.c
deleted file mode 100644
index aa8d06ba1ee4..000000000000
--- a/drivers/net/wireless/ath/ar9170/phy.c
+++ /dev/null
@@ -1,1719 +0,0 @@
-/*
- * Atheros AR9170 driver
- *
- * PHY and RF code
- *
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License 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; see the file COPYING. If not, see
- * http://www.gnu.org/licenses/.
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- * Copyright (c) 2007-2008 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 <linux/bitrev.h>
-#include "ar9170.h"
-#include "cmd.h"
-
-static int ar9170_init_power_cal(struct ar9170 *ar)
-{
- ar9170_regwrite_begin(ar);
-
- ar9170_regwrite(0x1bc000 + 0x993c, 0x7f);
- ar9170_regwrite(0x1bc000 + 0x9934, 0x3f3f3f3f);
- ar9170_regwrite(0x1bc000 + 0x9938, 0x3f3f3f3f);
- ar9170_regwrite(0x1bc000 + 0xa234, 0x3f3f3f3f);
- ar9170_regwrite(0x1bc000 + 0xa238, 0x3f3f3f3f);
- ar9170_regwrite(0x1bc000 + 0xa38c, 0x3f3f3f3f);
- ar9170_regwrite(0x1bc000 + 0xa390, 0x3f3f3f3f);
- ar9170_regwrite(0x1bc000 + 0xa3cc, 0x3f3f3f3f);
- ar9170_regwrite(0x1bc000 + 0xa3d0, 0x3f3f3f3f);
- ar9170_regwrite(0x1bc000 + 0xa3d4, 0x3f3f3f3f);
-
- ar9170_regwrite_finish();
- return ar9170_regwrite_result();
-}
-
-struct ar9170_phy_init {
- u32 reg, _5ghz_20, _5ghz_40, _2ghz_40, _2ghz_20;
-};
-
-static struct ar9170_phy_init ar5416_phy_init[] = {
- { 0x1c5800, 0x00000007, 0x00000007, 0x00000007, 0x00000007, },
- { 0x1c5804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, },
- { 0x1c5808, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c580c, 0xad848e19, 0xad848e19, 0xad848e19, 0xad848e19, },
- { 0x1c5810, 0x7d14e000, 0x7d14e000, 0x7d14e000, 0x7d14e000, },
- { 0x1c5814, 0x9c0a9f6b, 0x9c0a9f6b, 0x9c0a9f6b, 0x9c0a9f6b, },
- { 0x1c5818, 0x00000090, 0x00000090, 0x00000090, 0x00000090, },
- { 0x1c581c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, },
- { 0x1c5824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, },
- { 0x1c5828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, },
- { 0x1c582c, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, },
- { 0x1c5830, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, },
- { 0x1c5838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, },
- { 0x1c583c, 0x00200400, 0x00200400, 0x00200400, 0x00200400, },
- { 0x1c5840, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e, },
- { 0x1c5844, 0x1372161e, 0x13721c1e, 0x13721c24, 0x137216a4, },
- { 0x1c5848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, },
- { 0x1c584c, 0x1284233c, 0x1284233c, 0x1284233c, 0x1284233c, },
- { 0x1c5850, 0x6c48b4e4, 0x6c48b4e4, 0x6c48b0e4, 0x6c48b0e4, },
- { 0x1c5854, 0x00000859, 0x00000859, 0x00000859, 0x00000859, },
- { 0x1c5858, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, },
- { 0x1c585c, 0x31395c5e, 0x31395c5e, 0x31395c5e, 0x31395c5e, },
- { 0x1c5860, 0x0004dd10, 0x0004dd10, 0x0004dd20, 0x0004dd20, },
- { 0x1c5868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, },
- { 0x1c586c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, },
- { 0x1c5900, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5904, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5908, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c590c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, },
- { 0x1c5918, 0x00000118, 0x00000230, 0x00000268, 0x00000134, },
- { 0x1c591c, 0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff, },
- { 0x1c5920, 0x0510081c, 0x0510081c, 0x0510001c, 0x0510001c, },
- { 0x1c5924, 0xd0058a15, 0xd0058a15, 0xd0058a15, 0xd0058a15, },
- { 0x1c5928, 0x00000001, 0x00000001, 0x00000001, 0x00000001, },
- { 0x1c592c, 0x00000004, 0x00000004, 0x00000004, 0x00000004, },
- { 0x1c5934, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
- { 0x1c5938, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
- { 0x1c593c, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f, },
- { 0x1c5944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, },
- { 0x1c5948, 0x9280b212, 0x9280b212, 0x9280b212, 0x9280b212, },
- { 0x1c594c, 0x00020028, 0x00020028, 0x00020028, 0x00020028, },
- { 0x1c5954, 0x5d50e188, 0x5d50e188, 0x5d50e188, 0x5d50e188, },
- { 0x1c5958, 0x00081fff, 0x00081fff, 0x00081fff, 0x00081fff, },
- { 0x1c5960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, },
- { 0x1c5964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, },
- { 0x1c5970, 0x190fb515, 0x190fb515, 0x190fb515, 0x190fb515, },
- { 0x1c5974, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5978, 0x00000001, 0x00000001, 0x00000001, 0x00000001, },
- { 0x1c597c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5980, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5984, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5988, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c598c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5990, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5994, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5998, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c599c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c59a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c59a4, 0x00000007, 0x00000007, 0x00000007, 0x00000007, },
- { 0x1c59a8, 0x001fff00, 0x001fff00, 0x001fff00, 0x001fff00, },
- { 0x1c59ac, 0x006f00c4, 0x006f00c4, 0x006f00c4, 0x006f00c4, },
- { 0x1c59b0, 0x03051000, 0x03051000, 0x03051000, 0x03051000, },
- { 0x1c59b4, 0x00000820, 0x00000820, 0x00000820, 0x00000820, },
- { 0x1c59c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, },
- { 0x1c59c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, },
- { 0x1c59c8, 0x60f6532c, 0x60f6532c, 0x60f6532c, 0x60f6532c, },
- { 0x1c59cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, },
- { 0x1c59d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, },
- { 0x1c59d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c59d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c59dc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c59e0, 0x00000200, 0x00000200, 0x00000200, 0x00000200, },
- { 0x1c59e4, 0x64646464, 0x64646464, 0x64646464, 0x64646464, },
- { 0x1c59e8, 0x3c787878, 0x3c787878, 0x3c787878, 0x3c787878, },
- { 0x1c59ec, 0x000000aa, 0x000000aa, 0x000000aa, 0x000000aa, },
- { 0x1c59f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c59fc, 0x00001042, 0x00001042, 0x00001042, 0x00001042, },
- { 0x1c5a00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5a04, 0x00000040, 0x00000040, 0x00000040, 0x00000040, },
- { 0x1c5a08, 0x00000080, 0x00000080, 0x00000080, 0x00000080, },
- { 0x1c5a0c, 0x000001a1, 0x000001a1, 0x00000141, 0x00000141, },
- { 0x1c5a10, 0x000001e1, 0x000001e1, 0x00000181, 0x00000181, },
- { 0x1c5a14, 0x00000021, 0x00000021, 0x000001c1, 0x000001c1, },
- { 0x1c5a18, 0x00000061, 0x00000061, 0x00000001, 0x00000001, },
- { 0x1c5a1c, 0x00000168, 0x00000168, 0x00000041, 0x00000041, },
- { 0x1c5a20, 0x000001a8, 0x000001a8, 0x000001a8, 0x000001a8, },
- { 0x1c5a24, 0x000001e8, 0x000001e8, 0x000001e8, 0x000001e8, },
- { 0x1c5a28, 0x00000028, 0x00000028, 0x00000028, 0x00000028, },
- { 0x1c5a2c, 0x00000068, 0x00000068, 0x00000068, 0x00000068, },
- { 0x1c5a30, 0x00000189, 0x00000189, 0x000000a8, 0x000000a8, },
- { 0x1c5a34, 0x000001c9, 0x000001c9, 0x00000169, 0x00000169, },
- { 0x1c5a38, 0x00000009, 0x00000009, 0x000001a9, 0x000001a9, },
- { 0x1c5a3c, 0x00000049, 0x00000049, 0x000001e9, 0x000001e9, },
- { 0x1c5a40, 0x00000089, 0x00000089, 0x00000029, 0x00000029, },
- { 0x1c5a44, 0x00000170, 0x00000170, 0x00000069, 0x00000069, },
- { 0x1c5a48, 0x000001b0, 0x000001b0, 0x00000190, 0x00000190, },
- { 0x1c5a4c, 0x000001f0, 0x000001f0, 0x000001d0, 0x000001d0, },
- { 0x1c5a50, 0x00000030, 0x00000030, 0x00000010, 0x00000010, },
- { 0x1c5a54, 0x00000070, 0x00000070, 0x00000050, 0x00000050, },
- { 0x1c5a58, 0x00000191, 0x00000191, 0x00000090, 0x00000090, },
- { 0x1c5a5c, 0x000001d1, 0x000001d1, 0x00000151, 0x00000151, },
- { 0x1c5a60, 0x00000011, 0x00000011, 0x00000191, 0x00000191, },
- { 0x1c5a64, 0x00000051, 0x00000051, 0x000001d1, 0x000001d1, },
- { 0x1c5a68, 0x00000091, 0x00000091, 0x00000011, 0x00000011, },
- { 0x1c5a6c, 0x000001b8, 0x000001b8, 0x00000051, 0x00000051, },
- { 0x1c5a70, 0x000001f8, 0x000001f8, 0x00000198, 0x00000198, },
- { 0x1c5a74, 0x00000038, 0x00000038, 0x000001d8, 0x000001d8, },
- { 0x1c5a78, 0x00000078, 0x00000078, 0x00000018, 0x00000018, },
- { 0x1c5a7c, 0x00000199, 0x00000199, 0x00000058, 0x00000058, },
- { 0x1c5a80, 0x000001d9, 0x000001d9, 0x00000098, 0x00000098, },
- { 0x1c5a84, 0x00000019, 0x00000019, 0x00000159, 0x00000159, },
- { 0x1c5a88, 0x00000059, 0x00000059, 0x00000199, 0x00000199, },
- { 0x1c5a8c, 0x00000099, 0x00000099, 0x000001d9, 0x000001d9, },
- { 0x1c5a90, 0x000000d9, 0x000000d9, 0x00000019, 0x00000019, },
- { 0x1c5a94, 0x000000f9, 0x000000f9, 0x00000059, 0x00000059, },
- { 0x1c5a98, 0x000000f9, 0x000000f9, 0x00000099, 0x00000099, },
- { 0x1c5a9c, 0x000000f9, 0x000000f9, 0x000000d9, 0x000000d9, },
- { 0x1c5aa0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
- { 0x1c5aa4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
- { 0x1c5aa8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
- { 0x1c5aac, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
- { 0x1c5ab0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
- { 0x1c5ab4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
- { 0x1c5ab8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
- { 0x1c5abc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
- { 0x1c5ac0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
- { 0x1c5ac4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
- { 0x1c5ac8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
- { 0x1c5acc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
- { 0x1c5ad0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
- { 0x1c5ad4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
- { 0x1c5ad8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
- { 0x1c5adc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
- { 0x1c5ae0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
- { 0x1c5ae4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
- { 0x1c5ae8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
- { 0x1c5aec, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
- { 0x1c5af0, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
- { 0x1c5af4, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
- { 0x1c5af8, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
- { 0x1c5afc, 0x000000f9, 0x000000f9, 0x000000f9, 0x000000f9, },
- { 0x1c5b00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5b04, 0x00000001, 0x00000001, 0x00000001, 0x00000001, },
- { 0x1c5b08, 0x00000002, 0x00000002, 0x00000002, 0x00000002, },
- { 0x1c5b0c, 0x00000003, 0x00000003, 0x00000003, 0x00000003, },
- { 0x1c5b10, 0x00000004, 0x00000004, 0x00000004, 0x00000004, },
- { 0x1c5b14, 0x00000005, 0x00000005, 0x00000005, 0x00000005, },
- { 0x1c5b18, 0x00000008, 0x00000008, 0x00000008, 0x00000008, },
- { 0x1c5b1c, 0x00000009, 0x00000009, 0x00000009, 0x00000009, },
- { 0x1c5b20, 0x0000000a, 0x0000000a, 0x0000000a, 0x0000000a, },
- { 0x1c5b24, 0x0000000b, 0x0000000b, 0x0000000b, 0x0000000b, },
- { 0x1c5b28, 0x0000000c, 0x0000000c, 0x0000000c, 0x0000000c, },
- { 0x1c5b2c, 0x0000000d, 0x0000000d, 0x0000000d, 0x0000000d, },
- { 0x1c5b30, 0x00000010, 0x00000010, 0x00000010, 0x00000010, },
- { 0x1c5b34, 0x00000011, 0x00000011, 0x00000011, 0x00000011, },
- { 0x1c5b38, 0x00000012, 0x00000012, 0x00000012, 0x00000012, },
- { 0x1c5b3c, 0x00000013, 0x00000013, 0x00000013, 0x00000013, },
- { 0x1c5b40, 0x00000014, 0x00000014, 0x00000014, 0x00000014, },
- { 0x1c5b44, 0x00000015, 0x00000015, 0x00000015, 0x00000015, },
- { 0x1c5b48, 0x00000018, 0x00000018, 0x00000018, 0x00000018, },
- { 0x1c5b4c, 0x00000019, 0x00000019, 0x00000019, 0x00000019, },
- { 0x1c5b50, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, },
- { 0x1c5b54, 0x0000001b, 0x0000001b, 0x0000001b, 0x0000001b, },
- { 0x1c5b58, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, },
- { 0x1c5b5c, 0x0000001d, 0x0000001d, 0x0000001d, 0x0000001d, },
- { 0x1c5b60, 0x00000020, 0x00000020, 0x00000020, 0x00000020, },
- { 0x1c5b64, 0x00000021, 0x00000021, 0x00000021, 0x00000021, },
- { 0x1c5b68, 0x00000022, 0x00000022, 0x00000022, 0x00000022, },
- { 0x1c5b6c, 0x00000023, 0x00000023, 0x00000023, 0x00000023, },
- { 0x1c5b70, 0x00000024, 0x00000024, 0x00000024, 0x00000024, },
- { 0x1c5b74, 0x00000025, 0x00000025, 0x00000025, 0x00000025, },
- { 0x1c5b78, 0x00000028, 0x00000028, 0x00000028, 0x00000028, },
- { 0x1c5b7c, 0x00000029, 0x00000029, 0x00000029, 0x00000029, },
- { 0x1c5b80, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a, },
- { 0x1c5b84, 0x0000002b, 0x0000002b, 0x0000002b, 0x0000002b, },
- { 0x1c5b88, 0x0000002c, 0x0000002c, 0x0000002c, 0x0000002c, },
- { 0x1c5b8c, 0x0000002d, 0x0000002d, 0x0000002d, 0x0000002d, },
- { 0x1c5b90, 0x00000030, 0x00000030, 0x00000030, 0x00000030, },
- { 0x1c5b94, 0x00000031, 0x00000031, 0x00000031, 0x00000031, },
- { 0x1c5b98, 0x00000032, 0x00000032, 0x00000032, 0x00000032, },
- { 0x1c5b9c, 0x00000033, 0x00000033, 0x00000033, 0x00000033, },
- { 0x1c5ba0, 0x00000034, 0x00000034, 0x00000034, 0x00000034, },
- { 0x1c5ba4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
- { 0x1c5ba8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
- { 0x1c5bac, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
- { 0x1c5bb0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
- { 0x1c5bb4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
- { 0x1c5bb8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
- { 0x1c5bbc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
- { 0x1c5bc0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
- { 0x1c5bc4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
- { 0x1c5bc8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
- { 0x1c5bcc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
- { 0x1c5bd0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
- { 0x1c5bd4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
- { 0x1c5bd8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
- { 0x1c5bdc, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
- { 0x1c5be0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
- { 0x1c5be4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
- { 0x1c5be8, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
- { 0x1c5bec, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
- { 0x1c5bf0, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
- { 0x1c5bf4, 0x00000035, 0x00000035, 0x00000035, 0x00000035, },
- { 0x1c5bf8, 0x00000010, 0x00000010, 0x00000010, 0x00000010, },
- { 0x1c5bfc, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, },
- { 0x1c5c00, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5c0c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5c10, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5c14, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5c18, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5c1c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5c20, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5c24, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5c28, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5c2c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5c30, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5c34, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5c38, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5c3c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5cf0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5cf4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5cf8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c5cfc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c6200, 0x00000008, 0x00000008, 0x0000000e, 0x0000000e, },
- { 0x1c6204, 0x00000440, 0x00000440, 0x00000440, 0x00000440, },
- { 0x1c6208, 0xd6be4788, 0xd6be4788, 0xd03e4788, 0xd03e4788, },
- { 0x1c620c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, },
- { 0x1c6210, 0x40806333, 0x40806333, 0x40806333, 0x40806333, },
- { 0x1c6214, 0x00106c10, 0x00106c10, 0x00106c10, 0x00106c10, },
- { 0x1c6218, 0x009c4060, 0x009c4060, 0x009c4060, 0x009c4060, },
- { 0x1c621c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, },
- { 0x1c6220, 0x018830c6, 0x018830c6, 0x018830c6, 0x018830c6, },
- { 0x1c6224, 0x00000400, 0x00000400, 0x00000400, 0x00000400, },
- { 0x1c6228, 0x000009b5, 0x000009b5, 0x000009b5, 0x000009b5, },
- { 0x1c622c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c6230, 0x00000108, 0x00000210, 0x00000210, 0x00000108, },
- { 0x1c6234, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
- { 0x1c6238, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
- { 0x1c623c, 0x13c889af, 0x13c889af, 0x13c889af, 0x13c889af, },
- { 0x1c6240, 0x38490a20, 0x38490a20, 0x38490a20, 0x38490a20, },
- { 0x1c6244, 0x00007bb6, 0x00007bb6, 0x00007bb6, 0x00007bb6, },
- { 0x1c6248, 0x0fff3ffc, 0x0fff3ffc, 0x0fff3ffc, 0x0fff3ffc, },
- { 0x1c624c, 0x00000001, 0x00000001, 0x00000001, 0x00000001, },
- { 0x1c6250, 0x0000a000, 0x0000a000, 0x0000a000, 0x0000a000, },
- { 0x1c6254, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c6258, 0x0cc75380, 0x0cc75380, 0x0cc75380, 0x0cc75380, },
- { 0x1c625c, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, 0x0f0f0f01, },
- { 0x1c6260, 0xdfa91f01, 0xdfa91f01, 0xdfa91f01, 0xdfa91f01, },
- { 0x1c6264, 0x00418a11, 0x00418a11, 0x00418a11, 0x00418a11, },
- { 0x1c6268, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c626c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, },
- { 0x1c6274, 0x0a1a9caa, 0x0a1a9caa, 0x0a1a7caa, 0x0a1a7caa, },
- { 0x1c6278, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, },
- { 0x1c627c, 0x051701ce, 0x051701ce, 0x051701ce, 0x051701ce, },
- { 0x1c6300, 0x18010000, 0x18010000, 0x18010000, 0x18010000, },
- { 0x1c6304, 0x30032602, 0x30032602, 0x2e032402, 0x2e032402, },
- { 0x1c6308, 0x48073e06, 0x48073e06, 0x4a0a3c06, 0x4a0a3c06, },
- { 0x1c630c, 0x560b4c0a, 0x560b4c0a, 0x621a540b, 0x621a540b, },
- { 0x1c6310, 0x641a600f, 0x641a600f, 0x764f6c1b, 0x764f6c1b, },
- { 0x1c6314, 0x7a4f6e1b, 0x7a4f6e1b, 0x845b7a5a, 0x845b7a5a, },
- { 0x1c6318, 0x8c5b7e5a, 0x8c5b7e5a, 0x950f8ccf, 0x950f8ccf, },
- { 0x1c631c, 0x9d0f96cf, 0x9d0f96cf, 0xa5cf9b4f, 0xa5cf9b4f, },
- { 0x1c6320, 0xb51fa69f, 0xb51fa69f, 0xbddfaf1f, 0xbddfaf1f, },
- { 0x1c6324, 0xcb3fbd07, 0xcb3fbcbf, 0xd1ffc93f, 0xd1ffc93f, },
- { 0x1c6328, 0x0000d7bf, 0x0000d7bf, 0x00000000, 0x00000000, },
- { 0x1c632c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c6330, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c6334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c6338, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c633c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c6340, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c6344, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c6348, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, },
- { 0x1c634c, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, },
- { 0x1c6350, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, },
- { 0x1c6354, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, },
- { 0x1c6358, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, 0x79a8aa1f, },
- { 0x1c6388, 0x08000000, 0x08000000, 0x08000000, 0x08000000, },
- { 0x1c638c, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
- { 0x1c6390, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
- { 0x1c6394, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, },
- { 0x1c6398, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, },
- { 0x1c639c, 0x00000007, 0x00000007, 0x00000007, 0x00000007, },
- { 0x1c63a0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c63a4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c63a8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c63ac, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c63b0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c63b4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c63b8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c63bc, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c63c0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c63c4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c63c8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c63cc, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
- { 0x1c63d0, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
- { 0x1c63d4, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, 0x3f3f3f3f, },
- { 0x1c63d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, },
- { 0x1c63dc, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, },
- { 0x1c63e0, 0x000000c0, 0x000000c0, 0x000000c0, 0x000000c0, },
- { 0x1c6848, 0x00180a65, 0x00180a65, 0x00180a68, 0x00180a68, },
- { 0x1c6920, 0x0510001c, 0x0510001c, 0x0510001c, 0x0510001c, },
- { 0x1c6960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, },
- { 0x1c720c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, },
- { 0x1c726c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, },
- { 0x1c7848, 0x00180a65, 0x00180a65, 0x00180a68, 0x00180a68, },
- { 0x1c7920, 0x0510001c, 0x0510001c, 0x0510001c, 0x0510001c, },
- { 0x1c7960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, },
- { 0x1c820c, 0x012e8160, 0x012e8160, 0x012a8160, 0x012a8160, },
- { 0x1c826c, 0x09249126, 0x09249126, 0x09249126, 0x09249126, },
-/* { 0x1c8864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, }, */
- { 0x1c8864, 0x0001c600, 0x0001c600, 0x0001c600, 0x0001c600, },
- { 0x1c895c, 0x004b6a8e, 0x004b6a8e, 0x004b6a8e, 0x004b6a8e, },
- { 0x1c8968, 0x000003ce, 0x000003ce, 0x000003ce, 0x000003ce, },
- { 0x1c89bc, 0x00181400, 0x00181400, 0x00181400, 0x00181400, },
- { 0x1c9270, 0x00820820, 0x00820820, 0x00820820, 0x00820820, },
- { 0x1c935c, 0x066c420f, 0x066c420f, 0x066c420f, 0x066c420f, },
- { 0x1c9360, 0x0f282207, 0x0f282207, 0x0f282207, 0x0f282207, },
- { 0x1c9364, 0x17601685, 0x17601685, 0x17601685, 0x17601685, },
- { 0x1c9368, 0x1f801104, 0x1f801104, 0x1f801104, 0x1f801104, },
- { 0x1c936c, 0x37a00c03, 0x37a00c03, 0x37a00c03, 0x37a00c03, },
- { 0x1c9370, 0x3fc40883, 0x3fc40883, 0x3fc40883, 0x3fc40883, },
- { 0x1c9374, 0x57c00803, 0x57c00803, 0x57c00803, 0x57c00803, },
- { 0x1c9378, 0x5fd80682, 0x5fd80682, 0x5fd80682, 0x5fd80682, },
- { 0x1c937c, 0x7fe00482, 0x7fe00482, 0x7fe00482, 0x7fe00482, },
- { 0x1c9380, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, 0x7f3c7bba, },
- { 0x1c9384, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, 0xf3307ff0, }
-};
-
-/*
- * look up a certain register in ar5416_phy_init[] and return the init. value
- * for the band and bandwidth given. Return 0 if register address not found.
- */
-static u32 ar9170_get_default_phy_reg_val(u32 reg, bool is_2ghz, bool is_40mhz)
-{
- unsigned int i;
- for (i = 0; i < ARRAY_SIZE(ar5416_phy_init); i++) {
- if (ar5416_phy_init[i].reg != reg)
- continue;
-
- if (is_2ghz) {
- if (is_40mhz)
- return ar5416_phy_init[i]._2ghz_40;
- else
- return ar5416_phy_init[i]._2ghz_20;
- } else {
- if (is_40mhz)
- return ar5416_phy_init[i]._5ghz_40;
- else
- return ar5416_phy_init[i]._5ghz_20;
- }
- }
- return 0;
-}
-
-/*
- * initialize some phy regs from eeprom values in modal_header[]
- * acc. to band and bandwidth
- */
-static int ar9170_init_phy_from_eeprom(struct ar9170 *ar,
- bool is_2ghz, bool is_40mhz)
-{
- static const u8 xpd2pd[16] = {
- 0x2, 0x2, 0x2, 0x1, 0x2, 0x2, 0x6, 0x2,
- 0x2, 0x3, 0x7, 0x2, 0xB, 0x2, 0x2, 0x2
- };
- u32 defval, newval;
- /* pointer to the modal_header acc. to band */
- struct ar9170_eeprom_modal *m = &ar->eeprom.modal_header[is_2ghz];
-
- ar9170_regwrite_begin(ar);
-
- /* ant common control (index 0) */
- newval = le32_to_cpu(m->antCtrlCommon);
- ar9170_regwrite(0x1c5964, newval);
-
- /* ant control chain 0 (index 1) */
- newval = le32_to_cpu(m->antCtrlChain[0]);
- ar9170_regwrite(0x1c5960, newval);
-
- /* ant control chain 2 (index 2) */
- newval = le32_to_cpu(m->antCtrlChain[1]);
- ar9170_regwrite(0x1c7960, newval);
-
- /* SwSettle (index 3) */
- if (!is_40mhz) {
- defval = ar9170_get_default_phy_reg_val(0x1c5844,
- is_2ghz, is_40mhz);
- newval = (defval & ~0x3f80) |
- ((m->switchSettling & 0x7f) << 7);
- ar9170_regwrite(0x1c5844, newval);
- }
-
- /* adcDesired, pdaDesired (index 4) */
- defval = ar9170_get_default_phy_reg_val(0x1c5850, is_2ghz, is_40mhz);
- newval = (defval & ~0xffff) | ((u8)m->pgaDesiredSize << 8) |
- ((u8)m->adcDesiredSize);
- ar9170_regwrite(0x1c5850, newval);
-
- /* TxEndToXpaOff, TxFrameToXpaOn (index 5) */
- defval = ar9170_get_default_phy_reg_val(0x1c5834, is_2ghz, is_40mhz);
- newval = (m->txEndToXpaOff << 24) | (m->txEndToXpaOff << 16) |
- (m->txFrameToXpaOn << 8) | m->txFrameToXpaOn;
- ar9170_regwrite(0x1c5834, newval);
-
- /* TxEndToRxOn (index 6) */
- defval = ar9170_get_default_phy_reg_val(0x1c5828, is_2ghz, is_40mhz);
- newval = (defval & ~0xff0000) | (m->txEndToRxOn << 16);
- ar9170_regwrite(0x1c5828, newval);
-
- /* thresh62 (index 7) */
- defval = ar9170_get_default_phy_reg_val(0x1c8864, is_2ghz, is_40mhz);
- newval = (defval & ~0x7f000) | (m->thresh62 << 12);
- ar9170_regwrite(0x1c8864, newval);
-
- /* tx/rx attenuation chain 0 (index 8) */
- defval = ar9170_get_default_phy_reg_val(0x1c5848, is_2ghz, is_40mhz);
- newval = (defval & ~0x3f000) | ((m->txRxAttenCh[0] & 0x3f) << 12);
- ar9170_regwrite(0x1c5848, newval);
-
- /* tx/rx attenuation chain 2 (index 9) */
- defval = ar9170_get_default_phy_reg_val(0x1c7848, is_2ghz, is_40mhz);
- newval = (defval & ~0x3f000) | ((m->txRxAttenCh[1] & 0x3f) << 12);
- ar9170_regwrite(0x1c7848, newval);
-
- /* tx/rx margin chain 0 (index 10) */
- defval = ar9170_get_default_phy_reg_val(0x1c620c, is_2ghz, is_40mhz);
- newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[0] & 0x3f) << 18);
- /* bsw margin chain 0 for 5GHz only */
- if (!is_2ghz)
- newval = (newval & ~0x3c00) | ((m->bswMargin[0] & 0xf) << 10);
- ar9170_regwrite(0x1c620c, newval);
-
- /* tx/rx margin chain 2 (index 11) */
- defval = ar9170_get_default_phy_reg_val(0x1c820c, is_2ghz, is_40mhz);
- newval = (defval & ~0xfc0000) | ((m->rxTxMarginCh[1] & 0x3f) << 18);
- ar9170_regwrite(0x1c820c, newval);
-
- /* iqCall, iqCallq chain 0 (index 12) */
- defval = ar9170_get_default_phy_reg_val(0x1c5920, is_2ghz, is_40mhz);
- newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[0] & 0x3f) << 5) |
- ((u8)m->iqCalQCh[0] & 0x1f);
- ar9170_regwrite(0x1c5920, newval);
-
- /* iqCall, iqCallq chain 2 (index 13) */
- defval = ar9170_get_default_phy_reg_val(0x1c7920, is_2ghz, is_40mhz);
- newval = (defval & ~0x7ff) | (((u8)m->iqCalICh[1] & 0x3f) << 5) |
- ((u8)m->iqCalQCh[1] & 0x1f);
- ar9170_regwrite(0x1c7920, newval);
-
- /* xpd gain mask (index 14) */
- defval = ar9170_get_default_phy_reg_val(0x1c6258, is_2ghz, is_40mhz);
- newval = (defval & ~0xf0000) | (xpd2pd[m->xpdGain & 0xf] << 16);
- ar9170_regwrite(0x1c6258, newval);
- ar9170_regwrite_finish();
-
- return ar9170_regwrite_result();
-}
-
-int ar9170_init_phy(struct ar9170 *ar, enum ieee80211_band band)
-{
- int i, err;
- u32 val;
- bool is_2ghz = band == IEEE80211_BAND_2GHZ;
- bool is_40mhz = conf_is_ht40(&ar->hw->conf);
-
- ar9170_regwrite_begin(ar);
-
- for (i = 0; i < ARRAY_SIZE(ar5416_phy_init); i++) {
- if (is_40mhz) {
- if (is_2ghz)
- val = ar5416_phy_init[i]._2ghz_40;
- else
- val = ar5416_phy_init[i]._5ghz_40;
- } else {
- if (is_2ghz)
- val = ar5416_phy_init[i]._2ghz_20;
- else
- val = ar5416_phy_init[i]._5ghz_20;
- }
-
- ar9170_regwrite(ar5416_phy_init[i].reg, val);
- }
-
- ar9170_regwrite_finish();
- err = ar9170_regwrite_result();
- if (err)
- return err;
-
- err = ar9170_init_phy_from_eeprom(ar, is_2ghz, is_40mhz);
- if (err)
- return err;
-
- err = ar9170_init_power_cal(ar);
- if (err)
- return err;
-
- /* XXX: remove magic! */
- if (is_2ghz)
- err = ar9170_write_reg(ar, 0x1d4014, 0x5163);
- else
- err = ar9170_write_reg(ar, 0x1d4014, 0x5143);
-
- return err;
-}
-
-struct ar9170_rf_init {
- u32 reg, _5ghz, _2ghz;
-};
-
-static struct ar9170_rf_init ar9170_rf_init[] = {
- /* bank 0 */
- { 0x1c58b0, 0x1e5795e5, 0x1e5795e5},
- { 0x1c58e0, 0x02008020, 0x02008020},
- /* bank 1 */
- { 0x1c58b0, 0x02108421, 0x02108421},
- { 0x1c58ec, 0x00000008, 0x00000008},
- /* bank 2 */
- { 0x1c58b0, 0x0e73ff17, 0x0e73ff17},
- { 0x1c58e0, 0x00000420, 0x00000420},
- /* bank 3 */
- { 0x1c58f0, 0x01400018, 0x01c00018},
- /* bank 4 */
- { 0x1c58b0, 0x000001a1, 0x000001a1},
- { 0x1c58e8, 0x00000001, 0x00000001},
- /* bank 5 */
- { 0x1c58b0, 0x00000013, 0x00000013},
- { 0x1c58e4, 0x00000002, 0x00000002},
- /* bank 6 */
- { 0x1c58b0, 0x00000000, 0x00000000},
- { 0x1c58b0, 0x00000000, 0x00000000},
- { 0x1c58b0, 0x00000000, 0x00000000},
- { 0x1c58b0, 0x00000000, 0x00000000},
- { 0x1c58b0, 0x00000000, 0x00000000},
- { 0x1c58b0, 0x00004000, 0x00004000},
- { 0x1c58b0, 0x00006c00, 0x00006c00},
- { 0x1c58b0, 0x00002c00, 0x00002c00},
- { 0x1c58b0, 0x00004800, 0x00004800},
- { 0x1c58b0, 0x00004000, 0x00004000},
- { 0x1c58b0, 0x00006000, 0x00006000},
- { 0x1c58b0, 0x00001000, 0x00001000},
- { 0x1c58b0, 0x00004000, 0x00004000},
- { 0x1c58b0, 0x00007c00, 0x00007c00},
- { 0x1c58b0, 0x00007c00, 0x00007c00},
- { 0x1c58b0, 0x00007c00, 0x00007c00},
- { 0x1c58b0, 0x00007c00, 0x00007c00},
- { 0x1c58b0, 0x00007c00, 0x00007c00},
- { 0x1c58b0, 0x00087c00, 0x00087c00},
- { 0x1c58b0, 0x00007c00, 0x00007c00},
- { 0x1c58b0, 0x00005400, 0x00005400},
- { 0x1c58b0, 0x00000c00, 0x00000c00},
- { 0x1c58b0, 0x00001800, 0x00001800},
- { 0x1c58b0, 0x00007c00, 0x00007c00},
- { 0x1c58b0, 0x00006c00, 0x00006c00},
- { 0x1c58b0, 0x00006c00, 0x00006c00},
- { 0x1c58b0, 0x00007c00, 0x00007c00},
- { 0x1c58b0, 0x00002c00, 0x00002c00},
- { 0x1c58b0, 0x00003c00, 0x00003c00},
- { 0x1c58b0, 0x00003800, 0x00003800},
- { 0x1c58b0, 0x00001c00, 0x00001c00},
- { 0x1c58b0, 0x00000800, 0x00000800},
- { 0x1c58b0, 0x00000408, 0x00000408},
- { 0x1c58b0, 0x00004c15, 0x00004c15},
- { 0x1c58b0, 0x00004188, 0x00004188},
- { 0x1c58b0, 0x0000201e, 0x0000201e},
- { 0x1c58b0, 0x00010408, 0x00010408},
- { 0x1c58b0, 0x00000801, 0x00000801},
- { 0x1c58b0, 0x00000c08, 0x00000c08},
- { 0x1c58b0, 0x0000181e, 0x0000181e},
- { 0x1c58b0, 0x00001016, 0x00001016},
- { 0x1c58b0, 0x00002800, 0x00002800},
- { 0x1c58b0, 0x00004010, 0x00004010},
- { 0x1c58b0, 0x0000081c, 0x0000081c},
- { 0x1c58b0, 0x00000115, 0x00000115},
- { 0x1c58b0, 0x00000015, 0x00000015},
- { 0x1c58b0, 0x00000066, 0x00000066},
- { 0x1c58b0, 0x0000001c, 0x0000001c},
- { 0x1c58b0, 0x00000000, 0x00000000},
- { 0x1c58b0, 0x00000004, 0x00000004},
- { 0x1c58b0, 0x00000015, 0x00000015},
- { 0x1c58b0, 0x0000001f, 0x0000001f},
- { 0x1c58e0, 0x00000000, 0x00000400},
- /* bank 7 */
- { 0x1c58b0, 0x000000a0, 0x000000a0},
- { 0x1c58b0, 0x00000000, 0x00000000},
- { 0x1c58b0, 0x00000040, 0x00000040},
- { 0x1c58f0, 0x0000001c, 0x0000001c},
-};
-
-static int ar9170_init_rf_banks_0_7(struct ar9170 *ar, bool band5ghz)
-{
- int err, i;
-
- ar9170_regwrite_begin(ar);
-
- for (i = 0; i < ARRAY_SIZE(ar9170_rf_init); i++)
- ar9170_regwrite(ar9170_rf_init[i].reg,
- band5ghz ? ar9170_rf_init[i]._5ghz
- : ar9170_rf_init[i]._2ghz);
-
- ar9170_regwrite_finish();
- err = ar9170_regwrite_result();
- if (err)
- wiphy_err(ar->hw->wiphy, "rf init failed\n");
- return err;
-}
-
-static int ar9170_init_rf_bank4_pwr(struct ar9170 *ar, bool band5ghz,
- u32 freq, enum ar9170_bw bw)
-{
- int err;
- u32 d0, d1, td0, td1, fd0, fd1;
- u8 chansel;
- u8 refsel0 = 1, refsel1 = 0;
- u8 lf_synth = 0;
-
- switch (bw) {
- case AR9170_BW_40_ABOVE:
- freq += 10;
- break;
- case AR9170_BW_40_BELOW:
- freq -= 10;
- break;
- case AR9170_BW_20:
- break;
- case __AR9170_NUM_BW:
- BUG();
- }
-
- if (band5ghz) {
- if (freq % 10) {
- chansel = (freq - 4800) / 5;
- } else {
- chansel = ((freq - 4800) / 10) * 2;
- refsel0 = 0;
- refsel1 = 1;
- }
- chansel = byte_rev_table[chansel];
- } else {
- if (freq == 2484) {
- chansel = 10 + (freq - 2274) / 5;
- lf_synth = 1;
- } else
- chansel = 16 + (freq - 2272) / 5;
- chansel *= 4;
- chansel = byte_rev_table[chansel];
- }
-
- d1 = chansel;
- d0 = 0x21 |
- refsel0 << 3 |
- refsel1 << 2 |
- lf_synth << 1;
- td0 = d0 & 0x1f;
- td1 = d1 & 0x1f;
- fd0 = td1 << 5 | td0;
-
- td0 = (d0 >> 5) & 0x7;
- td1 = (d1 >> 5) & 0x7;
- fd1 = td1 << 5 | td0;
-
- ar9170_regwrite_begin(ar);
-
- ar9170_regwrite(0x1c58b0, fd0);
- ar9170_regwrite(0x1c58e8, fd1);
-
- ar9170_regwrite_finish();
- err = ar9170_regwrite_result();
- if (err)
- return err;
-
- msleep(10);
-
- return 0;
-}
-
-struct ar9170_phy_freq_params {
- u8 coeff_exp;
- u16 coeff_man;
- u8 coeff_exp_shgi;
- u16 coeff_man_shgi;
-};
-
-struct ar9170_phy_freq_entry {
- u16 freq;
- struct ar9170_phy_freq_params params[__AR9170_NUM_BW];
-};
-
-/* NB: must be in sync with channel tables in main! */
-static const struct ar9170_phy_freq_entry ar9170_phy_freq_params[] = {
-/*
- * freq,
- * 20MHz,
- * 40MHz (below),
- * 40Mhz (above),
- */
- { 2412, {
- { 3, 21737, 3, 19563, },
- { 3, 21827, 3, 19644, },
- { 3, 21647, 3, 19482, },
- } },
- { 2417, {
- { 3, 21692, 3, 19523, },
- { 3, 21782, 3, 19604, },
- { 3, 21602, 3, 19442, },
- } },
- { 2422, {
- { 3, 21647, 3, 19482, },
- { 3, 21737, 3, 19563, },
- { 3, 21558, 3, 19402, },
- } },
- { 2427, {
- { 3, 21602, 3, 19442, },
- { 3, 21692, 3, 19523, },
- { 3, 21514, 3, 19362, },
- } },
- { 2432, {
- { 3, 21558, 3, 19402, },
- { 3, 21647, 3, 19482, },
- { 3, 21470, 3, 19323, },
- } },
- { 2437, {
- { 3, 21514, 3, 19362, },
- { 3, 21602, 3, 19442, },
- { 3, 21426, 3, 19283, },
- } },
- { 2442, {
- { 3, 21470, 3, 19323, },
- { 3, 21558, 3, 19402, },
- { 3, 21382, 3, 19244, },
- } },
- { 2447, {
- { 3, 21426, 3, 19283, },
- { 3, 21514, 3, 19362, },
- { 3, 21339, 3, 19205, },
- } },
- { 2452, {
- { 3, 21382, 3, 19244, },
- { 3, 21470, 3, 19323, },
- { 3, 21295, 3, 19166, },
- } },
- { 2457, {
- { 3, 21339, 3, 19205, },
- { 3, 21426, 3, 19283, },
- { 3, 21252, 3, 19127, },
- } },
- { 2462, {
- { 3, 21295, 3, 19166, },
- { 3, 21382, 3, 19244, },
- { 3, 21209, 3, 19088, },
- } },
- { 2467, {
- { 3, 21252, 3, 19127, },
- { 3, 21339, 3, 19205, },
- { 3, 21166, 3, 19050, },
- } },
- { 2472, {
- { 3, 21209, 3, 19088, },
- { 3, 21295, 3, 19166, },
- { 3, 21124, 3, 19011, },
- } },
- { 2484, {
- { 3, 21107, 3, 18996, },
- { 3, 21192, 3, 19073, },
- { 3, 21022, 3, 18920, },
- } },
- { 4920, {
- { 4, 21313, 4, 19181, },
- { 4, 21356, 4, 19220, },
- { 4, 21269, 4, 19142, },
- } },
- { 4940, {
- { 4, 21226, 4, 19104, },
- { 4, 21269, 4, 19142, },
- { 4, 21183, 4, 19065, },
- } },
- { 4960, {
- { 4, 21141, 4, 19027, },
- { 4, 21183, 4, 19065, },
- { 4, 21098, 4, 18988, },
- } },
- { 4980, {
- { 4, 21056, 4, 18950, },
- { 4, 21098, 4, 18988, },
- { 4, 21014, 4, 18912, },
- } },
- { 5040, {
- { 4, 20805, 4, 18725, },
- { 4, 20846, 4, 18762, },
- { 4, 20764, 4, 18687, },
- } },
- { 5060, {
- { 4, 20723, 4, 18651, },
- { 4, 20764, 4, 18687, },
- { 4, 20682, 4, 18614, },
- } },
- { 5080, {
- { 4, 20641, 4, 18577, },
- { 4, 20682, 4, 18614, },
- { 4, 20601, 4, 18541, },
- } },
- { 5180, {
- { 4, 20243, 4, 18219, },
- { 4, 20282, 4, 18254, },
- { 4, 20204, 4, 18183, },
- } },
- { 5200, {
- { 4, 20165, 4, 18148, },
- { 4, 20204, 4, 18183, },
- { 4, 20126, 4, 18114, },
- } },
- { 5220, {
- { 4, 20088, 4, 18079, },
- { 4, 20126, 4, 18114, },
- { 4, 20049, 4, 18044, },
- } },
- { 5240, {
- { 4, 20011, 4, 18010, },
- { 4, 20049, 4, 18044, },
- { 4, 19973, 4, 17976, },
- } },
- { 5260, {
- { 4, 19935, 4, 17941, },
- { 4, 19973, 4, 17976, },
- { 4, 19897, 4, 17907, },
- } },
- { 5280, {
- { 4, 19859, 4, 17873, },
- { 4, 19897, 4, 17907, },
- { 4, 19822, 4, 17840, },
- } },
- { 5300, {
- { 4, 19784, 4, 17806, },
- { 4, 19822, 4, 17840, },
- { 4, 19747, 4, 17772, },
- } },
- { 5320, {
- { 4, 19710, 4, 17739, },
- { 4, 19747, 4, 17772, },
- { 4, 19673, 4, 17706, },
- } },
- { 5500, {
- { 4, 19065, 4, 17159, },
- { 4, 19100, 4, 17190, },
- { 4, 19030, 4, 17127, },
- } },
- { 5520, {
- { 4, 18996, 4, 17096, },
- { 4, 19030, 4, 17127, },
- { 4, 18962, 4, 17065, },
- } },
- { 5540, {
- { 4, 18927, 4, 17035, },
- { 4, 18962, 4, 17065, },
- { 4, 18893, 4, 17004, },
- } },
- { 5560, {
- { 4, 18859, 4, 16973, },
- { 4, 18893, 4, 17004, },
- { 4, 18825, 4, 16943, },
- } },
- { 5580, {
- { 4, 18792, 4, 16913, },
- { 4, 18825, 4, 16943, },
- { 4, 18758, 4, 16882, },
- } },
- { 5600, {
- { 4, 18725, 4, 16852, },
- { 4, 18758, 4, 16882, },
- { 4, 18691, 4, 16822, },
- } },
- { 5620, {
- { 4, 18658, 4, 16792, },
- { 4, 18691, 4, 16822, },
- { 4, 18625, 4, 16762, },
- } },
- { 5640, {
- { 4, 18592, 4, 16733, },
- { 4, 18625, 4, 16762, },
- { 4, 18559, 4, 16703, },
- } },
- { 5660, {
- { 4, 18526, 4, 16673, },
- { 4, 18559, 4, 16703, },
- { 4, 18493, 4, 16644, },
- } },
- { 5680, {
- { 4, 18461, 4, 16615, },
- { 4, 18493, 4, 16644, },
- { 4, 18428, 4, 16586, },
- } },
- { 5700, {
- { 4, 18396, 4, 16556, },
- { 4, 18428, 4, 16586, },
- { 4, 18364, 4, 16527, },
- } },
- { 5745, {
- { 4, 18252, 4, 16427, },
- { 4, 18284, 4, 16455, },
- { 4, 18220, 4, 16398, },
- } },
- { 5765, {
- { 4, 18189, 5, 32740, },
- { 4, 18220, 4, 16398, },
- { 4, 18157, 5, 32683, },
- } },
- { 5785, {
- { 4, 18126, 5, 32626, },
- { 4, 18157, 5, 32683, },
- { 4, 18094, 5, 32570, },
- } },
- { 5805, {
- { 4, 18063, 5, 32514, },
- { 4, 18094, 5, 32570, },
- { 4, 18032, 5, 32458, },
- } },
- { 5825, {
- { 4, 18001, 5, 32402, },
- { 4, 18032, 5, 32458, },
- { 4, 17970, 5, 32347, },
- } },
- { 5170, {
- { 4, 20282, 4, 18254, },
- { 4, 20321, 4, 18289, },
- { 4, 20243, 4, 18219, },
- } },
- { 5190, {
- { 4, 20204, 4, 18183, },
- { 4, 20243, 4, 18219, },
- { 4, 20165, 4, 18148, },
- } },
- { 5210, {
- { 4, 20126, 4, 18114, },
- { 4, 20165, 4, 18148, },
- { 4, 20088, 4, 18079, },
- } },
- { 5230, {
- { 4, 20049, 4, 18044, },
- { 4, 20088, 4, 18079, },
- { 4, 20011, 4, 18010, },
- } },
-};
-
-static const struct ar9170_phy_freq_params *
-ar9170_get_hw_dyn_params(struct ieee80211_channel *channel,
- enum ar9170_bw bw)
-{
- unsigned int chanidx = 0;
- u16 freq = 2412;
-
- if (channel) {
- chanidx = channel->hw_value;
- freq = channel->center_freq;
- }
-
- BUG_ON(chanidx >= ARRAY_SIZE(ar9170_phy_freq_params));
-
- BUILD_BUG_ON(__AR9170_NUM_BW != 3);
-
- WARN_ON(ar9170_phy_freq_params[chanidx].freq != freq);
-
- return &ar9170_phy_freq_params[chanidx].params[bw];
-}
-
-
-int ar9170_init_rf(struct ar9170 *ar)
-{
- const struct ar9170_phy_freq_params *freqpar;
- __le32 cmd[7];
- int err;
-
- err = ar9170_init_rf_banks_0_7(ar, false);
- if (err)
- return err;
-
- err = ar9170_init_rf_bank4_pwr(ar, false, 2412, AR9170_BW_20);
- if (err)
- return err;
-
- freqpar = ar9170_get_hw_dyn_params(NULL, AR9170_BW_20);
-
- cmd[0] = cpu_to_le32(2412 * 1000);
- cmd[1] = cpu_to_le32(0);
- cmd[2] = cpu_to_le32(1);
- cmd[3] = cpu_to_le32(freqpar->coeff_exp);
- cmd[4] = cpu_to_le32(freqpar->coeff_man);
- cmd[5] = cpu_to_le32(freqpar->coeff_exp_shgi);
- cmd[6] = cpu_to_le32(freqpar->coeff_man_shgi);
-
- /* RF_INIT echoes the command back to us */
- err = ar->exec_cmd(ar, AR9170_CMD_RF_INIT,
- sizeof(cmd), (u8 *)cmd,
- sizeof(cmd), (u8 *)cmd);
- if (err)
- return err;
-
- msleep(1000);
-
- return ar9170_echo_test(ar, 0xaabbccdd);
-}
-
-static int ar9170_find_freq_idx(int nfreqs, u8 *freqs, u8 f)
-{
- int idx = nfreqs - 2;
-
- while (idx >= 0) {
- if (f >= freqs[idx])
- return idx;
- idx--;
- }
-
- return 0;
-}
-
-static s32 ar9170_interpolate_s32(s32 x, s32 x1, s32 y1, s32 x2, s32 y2)
-{
- /* nothing to interpolate, it's horizontal */
- if (y2 == y1)
- return y1;
-
- /* check if we hit one of the edges */
- if (x == x1)
- return y1;
- if (x == x2)
- return y2;
-
- /* x1 == x2 is bad, hopefully == x */
- if (x2 == x1)
- return y1;
-
- return y1 + (((y2 - y1) * (x - x1)) / (x2 - x1));
-}
-
-static u8 ar9170_interpolate_u8(u8 x, u8 x1, u8 y1, u8 x2, u8 y2)
-{
-#define SHIFT 8
- s32 y;
-
- y = ar9170_interpolate_s32(x << SHIFT,
- x1 << SHIFT, y1 << SHIFT,
- x2 << SHIFT, y2 << SHIFT);
-
- /*
- * XXX: unwrap this expression
- * Isn't it just DIV_ROUND_UP(y, 1<<SHIFT)?
- * Can we rely on the compiler to optimise away the div?
- */
- return (y >> SHIFT) + ((y & (1<<(SHIFT-1))) >> (SHIFT - 1));
-#undef SHIFT
-}
-
-static u8 ar9170_interpolate_val(u8 x, u8 *x_array, u8 *y_array)
-{
- int i;
-
- for (i = 0; i < 3; i++)
- if (x <= x_array[i + 1])
- break;
-
- return ar9170_interpolate_u8(x,
- x_array[i],
- y_array[i],
- x_array[i + 1],
- y_array[i + 1]);
-}
-
-static int ar9170_set_freq_cal_data(struct ar9170 *ar,
- struct ieee80211_channel *channel)
-{
- u8 *cal_freq_pier;
- u8 vpds[2][AR5416_PD_GAIN_ICEPTS];
- u8 pwrs[2][AR5416_PD_GAIN_ICEPTS];
- int chain, idx, i;
- u32 phy_data = 0;
- u8 f, tmp;
-
- switch (channel->band) {
- case IEEE80211_BAND_2GHZ:
- f = channel->center_freq - 2300;
- cal_freq_pier = ar->eeprom.cal_freq_pier_2G;
- i = AR5416_NUM_2G_CAL_PIERS - 1;
- break;
-
- case IEEE80211_BAND_5GHZ:
- f = (channel->center_freq - 4800) / 5;
- cal_freq_pier = ar->eeprom.cal_freq_pier_5G;
- i = AR5416_NUM_5G_CAL_PIERS - 1;
- break;
-
- default:
- return -EINVAL;
- break;
- }
-
- for (; i >= 0; i--) {
- if (cal_freq_pier[i] != 0xff)
- break;
- }
- if (i < 0)
- return -EINVAL;
-
- idx = ar9170_find_freq_idx(i, cal_freq_pier, f);
-
- ar9170_regwrite_begin(ar);
-
- for (chain = 0; chain < AR5416_MAX_CHAINS; chain++) {
- for (i = 0; i < AR5416_PD_GAIN_ICEPTS; i++) {
- struct ar9170_calibration_data_per_freq *cal_pier_data;
- int j;
-
- switch (channel->band) {
- case IEEE80211_BAND_2GHZ:
- cal_pier_data = &ar->eeprom.
- cal_pier_data_2G[chain][idx];
- break;
-
- case IEEE80211_BAND_5GHZ:
- cal_pier_data = &ar->eeprom.
- cal_pier_data_5G[chain][idx];
- break;
-
- default:
- return -EINVAL;
- }
-
- for (j = 0; j < 2; j++) {
- vpds[j][i] = ar9170_interpolate_u8(f,
- cal_freq_pier[idx],
- cal_pier_data->vpd_pdg[j][i],
- cal_freq_pier[idx + 1],
- cal_pier_data[1].vpd_pdg[j][i]);
-
- pwrs[j][i] = ar9170_interpolate_u8(f,
- cal_freq_pier[idx],
- cal_pier_data->pwr_pdg[j][i],
- cal_freq_pier[idx + 1],
- cal_pier_data[1].pwr_pdg[j][i]) / 2;
- }
- }
-
- for (i = 0; i < 76; i++) {
- if (i < 25) {
- tmp = ar9170_interpolate_val(i, &pwrs[0][0],
- &vpds[0][0]);
- } else {
- tmp = ar9170_interpolate_val(i - 12,
- &pwrs[1][0],
- &vpds[1][0]);
- }
-
- phy_data |= tmp << ((i & 3) << 3);
- if ((i & 3) == 3) {
- ar9170_regwrite(0x1c6280 + chain * 0x1000 +
- (i & ~3), phy_data);
- phy_data = 0;
- }
- }
-
- for (i = 19; i < 32; i++)
- ar9170_regwrite(0x1c6280 + chain * 0x1000 + (i << 2),
- 0x0);
- }
-
- ar9170_regwrite_finish();
- return ar9170_regwrite_result();
-}
-
-static u8 ar9170_get_max_edge_power(struct ar9170 *ar,
- struct ar9170_calctl_edges edges[],
- u32 freq)
-{
- int i;
- u8 rc = AR5416_MAX_RATE_POWER;
- u8 f;
- if (freq < 3000)
- f = freq - 2300;
- else
- f = (freq - 4800) / 5;
-
- for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) {
- if (edges[i].channel == 0xff)
- break;
- if (f == edges[i].channel) {
- /* exact freq match */
- rc = edges[i].power_flags & ~AR9170_CALCTL_EDGE_FLAGS;
- break;
- }
- if (i > 0 && f < edges[i].channel) {
- if (f > edges[i - 1].channel &&
- edges[i - 1].power_flags &
- AR9170_CALCTL_EDGE_FLAGS) {
- /* lower channel has the inband flag set */
- rc = edges[i - 1].power_flags &
- ~AR9170_CALCTL_EDGE_FLAGS;
- }
- break;
- }
- }
-
- if (i == AR5416_NUM_BAND_EDGES) {
- if (f > edges[i - 1].channel &&
- edges[i - 1].power_flags & AR9170_CALCTL_EDGE_FLAGS) {
- /* lower channel has the inband flag set */
- rc = edges[i - 1].power_flags &
- ~AR9170_CALCTL_EDGE_FLAGS;
- }
- }
- return rc;
-}
-
-static u8 ar9170_get_heavy_clip(struct ar9170 *ar,
- struct ar9170_calctl_edges edges[],
- u32 freq, enum ar9170_bw bw)
-{
- u8 f;
- int i;
- u8 rc = 0;
-
- if (freq < 3000)
- f = freq - 2300;
- else
- f = (freq - 4800) / 5;
-
- if (bw == AR9170_BW_40_BELOW || bw == AR9170_BW_40_ABOVE)
- rc |= 0xf0;
-
- for (i = 0; i < AR5416_NUM_BAND_EDGES; i++) {
- if (edges[i].channel == 0xff)
- break;
- if (f == edges[i].channel) {
- if (!(edges[i].power_flags & AR9170_CALCTL_EDGE_FLAGS))
- rc |= 0x0f;
- break;
- }
- }
-
- return rc;
-}
-
-/*
- * calculate the conformance test limits and the heavy clip parameter
- * and apply them to ar->power* (derived from otus hal/hpmain.c, line 3706)
- */
-static void ar9170_calc_ctl(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
-{
- u8 ctl_grp; /* CTL group */
- u8 ctl_idx; /* CTL index */
- int i, j;
- struct ctl_modes {
- u8 ctl_mode;
- u8 max_power;
- u8 *pwr_cal_data;
- int pwr_cal_len;
- } *modes;
-
- /*
- * order is relevant in the mode_list_*: we fall back to the
- * lower indices if any mode is missed in the EEPROM.
- */
- struct ctl_modes mode_list_2ghz[] = {
- { CTL_11B, 0, ar->power_2G_cck, 4 },
- { CTL_11G, 0, ar->power_2G_ofdm, 4 },
- { CTL_2GHT20, 0, ar->power_2G_ht20, 8 },
- { CTL_2GHT40, 0, ar->power_2G_ht40, 8 },
- };
- struct ctl_modes mode_list_5ghz[] = {
- { CTL_11A, 0, ar->power_5G_leg, 4 },
- { CTL_5GHT20, 0, ar->power_5G_ht20, 8 },
- { CTL_5GHT40, 0, ar->power_5G_ht40, 8 },
- };
- int nr_modes;
-
-#define EDGES(c, n) (ar->eeprom.ctl_data[c].control_edges[n])
-
- ar->phy_heavy_clip = 0;
-
- /*
- * TODO: investigate the differences between OTUS'
- * hpreg.c::zfHpGetRegulatoryDomain() and
- * ath/regd.c::ath_regd_get_band_ctl() -
- * e.g. for FCC3_WORLD the OTUS procedure
- * always returns CTL_FCC, while the one in ath/ delivers
- * CTL_ETSI for 2GHz and CTL_FCC for 5GHz.
- */
- ctl_grp = ath_regd_get_band_ctl(&ar->common.regulatory,
- ar->hw->conf.channel->band);
-
- /* ctl group not found - either invalid band (NO_CTL) or ww roaming */
- if (ctl_grp == NO_CTL || ctl_grp == SD_NO_CTL)
- ctl_grp = CTL_FCC;
-
- if (ctl_grp != CTL_FCC)
- /* skip CTL and heavy clip for CTL_MKK and CTL_ETSI */
- return;
-
- if (ar->hw->conf.channel->band == IEEE80211_BAND_2GHZ) {
- modes = mode_list_2ghz;
- nr_modes = ARRAY_SIZE(mode_list_2ghz);
- } else {
- modes = mode_list_5ghz;
- nr_modes = ARRAY_SIZE(mode_list_5ghz);
- }
-
- for (i = 0; i < nr_modes; i++) {
- u8 c = ctl_grp | modes[i].ctl_mode;
- for (ctl_idx = 0; ctl_idx < AR5416_NUM_CTLS; ctl_idx++)
- if (c == ar->eeprom.ctl_index[ctl_idx])
- break;
- if (ctl_idx < AR5416_NUM_CTLS) {
- int f_off = 0;
-
- /* determine heav clip parameter from
- the 11G edges array */
- if (modes[i].ctl_mode == CTL_11G) {
- ar->phy_heavy_clip =
- ar9170_get_heavy_clip(ar,
- EDGES(ctl_idx, 1),
- freq, bw);
- }
-
- /* adjust freq for 40MHz */
- if (modes[i].ctl_mode == CTL_2GHT40 ||
- modes[i].ctl_mode == CTL_5GHT40) {
- if (bw == AR9170_BW_40_BELOW)
- f_off = -10;
- else
- f_off = 10;
- }
-
- modes[i].max_power =
- ar9170_get_max_edge_power(ar, EDGES(ctl_idx, 1),
- freq+f_off);
-
- /*
- * TODO: check if the regulatory max. power is
- * controlled by cfg80211 for DFS
- * (hpmain applies it to max_power itself for DFS freq)
- */
-
- } else {
- /*
- * Workaround in otus driver, hpmain.c, line 3906:
- * if no data for 5GHT20 are found, take the
- * legacy 5G value.
- * We extend this here to fallback from any other *HT or
- * 11G, too.
- */
- int k = i;
-
- modes[i].max_power = AR5416_MAX_RATE_POWER;
- while (k-- > 0) {
- if (modes[k].max_power !=
- AR5416_MAX_RATE_POWER) {
- modes[i].max_power = modes[k].max_power;
- break;
- }
- }
- }
-
- /* apply max power to pwr_cal_data (ar->power_*) */
- for (j = 0; j < modes[i].pwr_cal_len; j++) {
- modes[i].pwr_cal_data[j] = min(modes[i].pwr_cal_data[j],
- modes[i].max_power);
- }
- }
-
- if (ar->phy_heavy_clip & 0xf0) {
- ar->power_2G_ht40[0]--;
- ar->power_2G_ht40[1]--;
- ar->power_2G_ht40[2]--;
- }
- if (ar->phy_heavy_clip & 0xf) {
- ar->power_2G_ht20[0]++;
- ar->power_2G_ht20[1]++;
- ar->power_2G_ht20[2]++;
- }
-
-
-#undef EDGES
-}
-
-static int ar9170_set_power_cal(struct ar9170 *ar, u32 freq, enum ar9170_bw bw)
-{
- struct ar9170_calibration_target_power_legacy *ctpl;
- struct ar9170_calibration_target_power_ht *ctph;
- u8 *ctpres;
- int ntargets;
- int idx, i, n;
- u8 ackpower, ackchains, f;
- u8 pwr_freqs[AR5416_MAX_NUM_TGT_PWRS];
-
- if (freq < 3000)
- f = freq - 2300;
- else
- f = (freq - 4800)/5;
-
- /*
- * cycle through the various modes
- *
- * legacy modes first: 5G, 2G CCK, 2G OFDM
- */
- for (i = 0; i < 3; i++) {
- switch (i) {
- case 0: /* 5 GHz legacy */
- ctpl = &ar->eeprom.cal_tgt_pwr_5G[0];
- ntargets = AR5416_NUM_5G_TARGET_PWRS;
- ctpres = ar->power_5G_leg;
- break;
- case 1: /* 2.4 GHz CCK */
- ctpl = &ar->eeprom.cal_tgt_pwr_2G_cck[0];
- ntargets = AR5416_NUM_2G_CCK_TARGET_PWRS;
- ctpres = ar->power_2G_cck;
- break;
- case 2: /* 2.4 GHz OFDM */
- ctpl = &ar->eeprom.cal_tgt_pwr_2G_ofdm[0];
- ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS;
- ctpres = ar->power_2G_ofdm;
- break;
- default:
- BUG();
- }
-
- for (n = 0; n < ntargets; n++) {
- if (ctpl[n].freq == 0xff)
- break;
- pwr_freqs[n] = ctpl[n].freq;
- }
- ntargets = n;
- idx = ar9170_find_freq_idx(ntargets, pwr_freqs, f);
- for (n = 0; n < 4; n++)
- ctpres[n] = ar9170_interpolate_u8(
- f,
- ctpl[idx + 0].freq,
- ctpl[idx + 0].power[n],
- ctpl[idx + 1].freq,
- ctpl[idx + 1].power[n]);
- }
-
- /*
- * HT modes now: 5G HT20, 5G HT40, 2G CCK, 2G OFDM, 2G HT20, 2G HT40
- */
- for (i = 0; i < 4; i++) {
- switch (i) {
- case 0: /* 5 GHz HT 20 */
- ctph = &ar->eeprom.cal_tgt_pwr_5G_ht20[0];
- ntargets = AR5416_NUM_5G_TARGET_PWRS;
- ctpres = ar->power_5G_ht20;
- break;
- case 1: /* 5 GHz HT 40 */
- ctph = &ar->eeprom.cal_tgt_pwr_5G_ht40[0];
- ntargets = AR5416_NUM_5G_TARGET_PWRS;
- ctpres = ar->power_5G_ht40;
- break;
- case 2: /* 2.4 GHz HT 20 */
- ctph = &ar->eeprom.cal_tgt_pwr_2G_ht20[0];
- ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS;
- ctpres = ar->power_2G_ht20;
- break;
- case 3: /* 2.4 GHz HT 40 */
- ctph = &ar->eeprom.cal_tgt_pwr_2G_ht40[0];
- ntargets = AR5416_NUM_2G_OFDM_TARGET_PWRS;
- ctpres = ar->power_2G_ht40;
- break;
- default:
- BUG();
- }
-
- for (n = 0; n < ntargets; n++) {
- if (ctph[n].freq == 0xff)
- break;
- pwr_freqs[n] = ctph[n].freq;
- }
- ntargets = n;
- idx = ar9170_find_freq_idx(ntargets, pwr_freqs, f);
- for (n = 0; n < 8; n++)
- ctpres[n] = ar9170_interpolate_u8(
- f,
- ctph[idx + 0].freq,
- ctph[idx + 0].power[n],
- ctph[idx + 1].freq,
- ctph[idx + 1].power[n]);
- }
-
-
- /* calc. conformance test limits and apply to ar->power*[] */
- ar9170_calc_ctl(ar, freq, bw);
-
- /* set ACK/CTS TX power */
- ar9170_regwrite_begin(ar);
-
- if (ar->eeprom.tx_mask != 1)
- ackchains = AR9170_TX_PHY_TXCHAIN_2;
- else
- ackchains = AR9170_TX_PHY_TXCHAIN_1;
-
- if (freq < 3000)
- ackpower = ar->power_2G_ofdm[0] & 0x3f;
- else
- ackpower = ar->power_5G_leg[0] & 0x3f;
-
- ar9170_regwrite(0x1c3694, ackpower << 20 | ackchains << 26);
- ar9170_regwrite(0x1c3bb4, ackpower << 5 | ackchains << 11 |
- ackpower << 21 | ackchains << 27);
-
- ar9170_regwrite_finish();
- return ar9170_regwrite_result();
-}
-
-static int ar9170_calc_noise_dbm(u32 raw_noise)
-{
- if (raw_noise & 0x100)
- return ~((raw_noise & 0x0ff) >> 1);
- else
- return (raw_noise & 0xff) >> 1;
-}
-
-int ar9170_set_channel(struct ar9170 *ar, struct ieee80211_channel *channel,
- enum ar9170_rf_init_mode rfi, enum ar9170_bw bw)
-{
- const struct ar9170_phy_freq_params *freqpar;
- u32 cmd, tmp, offs;
- __le32 vals[8];
- int i, err;
- bool bandswitch;
-
- /* clear BB heavy clip enable */
- err = ar9170_write_reg(ar, 0x1c59e0, 0x200);
- if (err)
- return err;
-
- /* may be NULL at first setup */
- if (ar->channel)
- bandswitch = ar->channel->band != channel->band;
- else
- bandswitch = true;
-
- /* HW workaround */
- if (!ar->hw->wiphy->bands[IEEE80211_BAND_5GHZ] &&
- channel->center_freq <= 2417)
- bandswitch = true;
-
- err = ar->exec_cmd(ar, AR9170_CMD_FREQ_START, 0, NULL, 0, NULL);
- if (err)
- return err;
-
- if (rfi != AR9170_RFI_NONE || bandswitch) {
- u32 val = 0x400;
-
- if (rfi == AR9170_RFI_COLD)
- val = 0x800;
-
- /* warm/cold reset BB/ADDA */
- err = ar9170_write_reg(ar, 0x1d4004, val);
- if (err)
- return err;
-
- err = ar9170_write_reg(ar, 0x1d4004, 0x0);
- if (err)
- return err;
-
- err = ar9170_init_phy(ar, channel->band);
- if (err)
- return err;
-
- err = ar9170_init_rf_banks_0_7(ar,
- channel->band == IEEE80211_BAND_5GHZ);
- if (err)
- return err;
-
- cmd = AR9170_CMD_RF_INIT;
- } else {
- cmd = AR9170_CMD_FREQUENCY;
- }
-
- err = ar9170_init_rf_bank4_pwr(ar,
- channel->band == IEEE80211_BAND_5GHZ,
- channel->center_freq, bw);
- if (err)
- return err;
-
- switch (bw) {
- case AR9170_BW_20:
- tmp = 0x240;
- offs = 0;
- break;
- case AR9170_BW_40_BELOW:
- tmp = 0x2c4;
- offs = 3;
- break;
- case AR9170_BW_40_ABOVE:
- tmp = 0x2d4;
- offs = 1;
- break;
- default:
- BUG();
- return -ENOSYS;
- }
-
- if (ar->eeprom.tx_mask != 1)
- tmp |= 0x100;
-
- err = ar9170_write_reg(ar, 0x1c5804, tmp);
- if (err)
- return err;
-
- err = ar9170_set_freq_cal_data(ar, channel);
- if (err)
- return err;
-
- err = ar9170_set_power_cal(ar, channel->center_freq, bw);
- if (err)
- return err;
-
- freqpar = ar9170_get_hw_dyn_params(channel, bw);
-
- vals[0] = cpu_to_le32(channel->center_freq * 1000);
- vals[1] = cpu_to_le32(conf_is_ht40(&ar->hw->conf));
- vals[2] = cpu_to_le32(offs << 2 | 1);
- vals[3] = cpu_to_le32(freqpar->coeff_exp);
- vals[4] = cpu_to_le32(freqpar->coeff_man);
- vals[5] = cpu_to_le32(freqpar->coeff_exp_shgi);
- vals[6] = cpu_to_le32(freqpar->coeff_man_shgi);
- vals[7] = cpu_to_le32(1000);
-
- err = ar->exec_cmd(ar, cmd, sizeof(vals), (u8 *)vals,
- sizeof(vals), (u8 *)vals);
- if (err)
- return err;
-
- if (ar->phy_heavy_clip) {
- err = ar9170_write_reg(ar, 0x1c59e0,
- 0x200 | ar->phy_heavy_clip);
- if (err) {
- if (ar9170_nag_limiter(ar))
- wiphy_err(ar->hw->wiphy,
- "failed to set heavy clip\n");
- }
- }
-
- for (i = 0; i < 2; i++) {
- ar->noise[i] = ar9170_calc_noise_dbm(
- (le32_to_cpu(vals[2 + i]) >> 19) & 0x1ff);
-
- ar->noise[i + 2] = ar9170_calc_noise_dbm(
- (le32_to_cpu(vals[5 + i]) >> 23) & 0x1ff);
- }
-
- ar->channel = channel;
- return 0;
-}
diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c
deleted file mode 100644
index d3be6f9816b5..000000000000
--- a/drivers/net/wireless/ath/ar9170/usb.c
+++ /dev/null
@@ -1,1008 +0,0 @@
-/*
- * Atheros AR9170 driver
- *
- * USB - frontend
- *
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- * Copyright 2009, Christian Lamparter <chunkeey@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; see the file COPYING. If not, see
- * http://www.gnu.org/licenses/.
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- * Copyright (c) 2007-2008 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 <linux/module.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/firmware.h>
-#include <linux/etherdevice.h>
-#include <linux/device.h>
-#include <net/mac80211.h>
-#include "ar9170.h"
-#include "cmd.h"
-#include "hw.h"
-#include "usb.h"
-
-MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
-MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Atheros AR9170 802.11n USB wireless");
-MODULE_FIRMWARE("ar9170.fw");
-
-enum ar9170_requirements {
- AR9170_REQ_FW1_ONLY = 1,
-};
-
-static struct usb_device_id ar9170_usb_ids[] = {
- /* Atheros 9170 */
- { USB_DEVICE(0x0cf3, 0x9170) },
- /* Atheros TG121N */
- { USB_DEVICE(0x0cf3, 0x1001) },
- /* TP-Link TL-WN821N v2 */
- { USB_DEVICE(0x0cf3, 0x1002) },
- /* 3Com Dual Band 802.11n USB Adapter */
- { USB_DEVICE(0x0cf3, 0x1010) },
- /* H3C Dual Band 802.11n USB Adapter */
- { USB_DEVICE(0x0cf3, 0x1011) },
- /* Cace Airpcap NX */
- { USB_DEVICE(0xcace, 0x0300) },
- /* D-Link DWA 160 A1 */
- { USB_DEVICE(0x07d1, 0x3c10) },
- /* D-Link DWA 160 A2 */
- { USB_DEVICE(0x07d1, 0x3a09) },
- /* Netgear WNA1000 */
- { USB_DEVICE(0x0846, 0x9040) },
- /* Netgear WNDA3100 */
- { USB_DEVICE(0x0846, 0x9010) },
- /* Netgear WN111 v2 */
- { USB_DEVICE(0x0846, 0x9001) },
- /* Zydas ZD1221 */
- { USB_DEVICE(0x0ace, 0x1221) },
- /* Proxim ORiNOCO 802.11n USB */
- { USB_DEVICE(0x1435, 0x0804) },
- /* WNC Generic 11n USB Dongle */
- { USB_DEVICE(0x1435, 0x0326) },
- /* ZyXEL NWD271N */
- { USB_DEVICE(0x0586, 0x3417) },
- /* Z-Com UB81 BG */
- { USB_DEVICE(0x0cde, 0x0023) },
- /* Z-Com UB82 ABG */
- { USB_DEVICE(0x0cde, 0x0026) },
- /* Sphairon Homelink 1202 */
- { USB_DEVICE(0x0cde, 0x0027) },
- /* Arcadyan WN7512 */
- { USB_DEVICE(0x083a, 0xf522) },
- /* Planex GWUS300 */
- { USB_DEVICE(0x2019, 0x5304) },
- /* IO-Data WNGDNUS2 */
- { USB_DEVICE(0x04bb, 0x093f) },
- /* AVM FRITZ!WLAN USB Stick N */
- { USB_DEVICE(0x057C, 0x8401) },
- /* NEC WL300NU-G */
- { USB_DEVICE(0x0409, 0x0249) },
- /* AVM FRITZ!WLAN USB Stick N 2.4 */
- { USB_DEVICE(0x057C, 0x8402), .driver_info = AR9170_REQ_FW1_ONLY },
- /* Qwest/Actiontec 802AIN Wireless N USB Network Adapter */
- { USB_DEVICE(0x1668, 0x1200) },
-
- /* terminate */
- {}
-};
-MODULE_DEVICE_TABLE(usb, ar9170_usb_ids);
-
-static void ar9170_usb_submit_urb(struct ar9170_usb *aru)
-{
- struct urb *urb;
- unsigned long flags;
- int err;
-
- if (unlikely(!IS_STARTED(&aru->common)))
- return ;
-
- spin_lock_irqsave(&aru->tx_urb_lock, flags);
- if (atomic_read(&aru->tx_submitted_urbs) >= AR9170_NUM_TX_URBS) {
- spin_unlock_irqrestore(&aru->tx_urb_lock, flags);
- return ;
- }
- atomic_inc(&aru->tx_submitted_urbs);
-
- urb = usb_get_from_anchor(&aru->tx_pending);
- if (!urb) {
- atomic_dec(&aru->tx_submitted_urbs);
- spin_unlock_irqrestore(&aru->tx_urb_lock, flags);
-
- return ;
- }
- spin_unlock_irqrestore(&aru->tx_urb_lock, flags);
-
- aru->tx_pending_urbs--;
- usb_anchor_urb(urb, &aru->tx_submitted);
-
- err = usb_submit_urb(urb, GFP_ATOMIC);
- if (unlikely(err)) {
- if (ar9170_nag_limiter(&aru->common))
- dev_err(&aru->udev->dev, "submit_urb failed (%d).\n",
- err);
-
- usb_unanchor_urb(urb);
- atomic_dec(&aru->tx_submitted_urbs);
- ar9170_tx_callback(&aru->common, urb->context);
- }
-
- usb_free_urb(urb);
-}
-
-static void ar9170_usb_tx_urb_complete_frame(struct urb *urb)
-{
- struct sk_buff *skb = urb->context;
- struct ar9170_usb *aru = usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
-
- if (unlikely(!aru)) {
- dev_kfree_skb_irq(skb);
- return ;
- }
-
- atomic_dec(&aru->tx_submitted_urbs);
-
- ar9170_tx_callback(&aru->common, skb);
-
- ar9170_usb_submit_urb(aru);
-}
-
-static void ar9170_usb_tx_urb_complete(struct urb *urb)
-{
-}
-
-static void ar9170_usb_irq_completed(struct urb *urb)
-{
- struct ar9170_usb *aru = urb->context;
-
- switch (urb->status) {
- /* everything is fine */
- case 0:
- break;
-
- /* disconnect */
- case -ENOENT:
- case -ECONNRESET:
- case -ENODEV:
- case -ESHUTDOWN:
- goto free;
-
- default:
- goto resubmit;
- }
-
- ar9170_handle_command_response(&aru->common, urb->transfer_buffer,
- urb->actual_length);
-
-resubmit:
- usb_anchor_urb(urb, &aru->rx_submitted);
- if (usb_submit_urb(urb, GFP_ATOMIC)) {
- usb_unanchor_urb(urb);
- goto free;
- }
-
- return;
-
-free:
- usb_free_coherent(aru->udev, 64, urb->transfer_buffer, urb->transfer_dma);
-}
-
-static void ar9170_usb_rx_completed(struct urb *urb)
-{
- struct sk_buff *skb = urb->context;
- struct ar9170_usb *aru = usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
- int err;
-
- if (!aru)
- goto free;
-
- switch (urb->status) {
- /* everything is fine */
- case 0:
- break;
-
- /* disconnect */
- case -ENOENT:
- case -ECONNRESET:
- case -ENODEV:
- case -ESHUTDOWN:
- goto free;
-
- default:
- goto resubmit;
- }
-
- skb_put(skb, urb->actual_length);
- ar9170_rx(&aru->common, skb);
-
-resubmit:
- skb_reset_tail_pointer(skb);
- skb_trim(skb, 0);
-
- usb_anchor_urb(urb, &aru->rx_submitted);
- err = usb_submit_urb(urb, GFP_ATOMIC);
- if (unlikely(err)) {
- usb_unanchor_urb(urb);
- goto free;
- }
-
- return ;
-
-free:
- dev_kfree_skb_irq(skb);
-}
-
-static int ar9170_usb_prep_rx_urb(struct ar9170_usb *aru,
- struct urb *urb, gfp_t gfp)
-{
- struct sk_buff *skb;
-
- skb = __dev_alloc_skb(AR9170_MAX_RX_BUFFER_SIZE + 32, gfp);
- if (!skb)
- return -ENOMEM;
-
- /* reserve some space for mac80211's radiotap */
- skb_reserve(skb, 32);
-
- usb_fill_bulk_urb(urb, aru->udev,
- usb_rcvbulkpipe(aru->udev, AR9170_EP_RX),
- skb->data, min(skb_tailroom(skb),
- AR9170_MAX_RX_BUFFER_SIZE),
- ar9170_usb_rx_completed, skb);
-
- return 0;
-}
-
-static int ar9170_usb_alloc_rx_irq_urb(struct ar9170_usb *aru)
-{
- struct urb *urb = NULL;
- void *ibuf;
- int err = -ENOMEM;
-
- /* initialize interrupt endpoint */
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb)
- goto out;
-
- ibuf = usb_alloc_coherent(aru->udev, 64, GFP_KERNEL, &urb->transfer_dma);
- if (!ibuf)
- goto out;
-
- usb_fill_int_urb(urb, aru->udev,
- usb_rcvintpipe(aru->udev, AR9170_EP_IRQ), ibuf,
- 64, ar9170_usb_irq_completed, aru, 1);
- urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
- usb_anchor_urb(urb, &aru->rx_submitted);
- err = usb_submit_urb(urb, GFP_KERNEL);
- if (err) {
- usb_unanchor_urb(urb);
- usb_free_coherent(aru->udev, 64, urb->transfer_buffer,
- urb->transfer_dma);
- }
-
-out:
- usb_free_urb(urb);
- return err;
-}
-
-static int ar9170_usb_alloc_rx_bulk_urbs(struct ar9170_usb *aru)
-{
- struct urb *urb;
- int i;
- int err = -EINVAL;
-
- for (i = 0; i < AR9170_NUM_RX_URBS; i++) {
- err = -ENOMEM;
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb)
- goto err_out;
-
- err = ar9170_usb_prep_rx_urb(aru, urb, GFP_KERNEL);
- if (err) {
- usb_free_urb(urb);
- goto err_out;
- }
-
- usb_anchor_urb(urb, &aru->rx_submitted);
- err = usb_submit_urb(urb, GFP_KERNEL);
- if (err) {
- usb_unanchor_urb(urb);
- dev_kfree_skb_any((void *) urb->transfer_buffer);
- usb_free_urb(urb);
- goto err_out;
- }
- usb_free_urb(urb);
- }
-
- /* the device now waiting for a firmware. */
- aru->common.state = AR9170_IDLE;
- return 0;
-
-err_out:
-
- usb_kill_anchored_urbs(&aru->rx_submitted);
- return err;
-}
-
-static int ar9170_usb_flush(struct ar9170 *ar)
-{
- struct ar9170_usb *aru = (void *) ar;
- struct urb *urb;
- int ret, err = 0;
-
- if (IS_STARTED(ar))
- aru->common.state = AR9170_IDLE;
-
- usb_wait_anchor_empty_timeout(&aru->tx_pending,
- msecs_to_jiffies(800));
- while ((urb = usb_get_from_anchor(&aru->tx_pending))) {
- ar9170_tx_callback(&aru->common, (void *) urb->context);
- usb_free_urb(urb);
- }
-
- /* lets wait a while until the tx - queues are dried out */
- ret = usb_wait_anchor_empty_timeout(&aru->tx_submitted,
- msecs_to_jiffies(100));
- if (ret == 0)
- err = -ETIMEDOUT;
-
- usb_kill_anchored_urbs(&aru->tx_submitted);
-
- if (IS_ACCEPTING_CMD(ar))
- aru->common.state = AR9170_STARTED;
-
- return err;
-}
-
-static void ar9170_usb_cancel_urbs(struct ar9170_usb *aru)
-{
- int err;
-
- aru->common.state = AR9170_UNKNOWN_STATE;
-
- err = ar9170_usb_flush(&aru->common);
- if (err)
- dev_err(&aru->udev->dev, "stuck tx urbs!\n");
-
- usb_poison_anchored_urbs(&aru->tx_submitted);
- usb_poison_anchored_urbs(&aru->rx_submitted);
-}
-
-static int ar9170_usb_exec_cmd(struct ar9170 *ar, enum ar9170_cmd cmd,
- unsigned int plen, void *payload,
- unsigned int outlen, void *out)
-{
- struct ar9170_usb *aru = (void *) ar;
- struct urb *urb = NULL;
- unsigned long flags;
- int err = -ENOMEM;
-
- if (unlikely(!IS_ACCEPTING_CMD(ar)))
- return -EPERM;
-
- if (WARN_ON(plen > AR9170_MAX_CMD_LEN - 4))
- return -EINVAL;
-
- urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (unlikely(!urb))
- goto err_free;
-
- ar->cmdbuf[0] = cpu_to_le32(plen);
- ar->cmdbuf[0] |= cpu_to_le32(cmd << 8);
- /* writing multiple regs fills this buffer already */
- if (plen && payload != (u8 *)(&ar->cmdbuf[1]))
- memcpy(&ar->cmdbuf[1], payload, plen);
-
- spin_lock_irqsave(&aru->common.cmdlock, flags);
- aru->readbuf = (u8 *)out;
- aru->readlen = outlen;
- spin_unlock_irqrestore(&aru->common.cmdlock, flags);
-
- usb_fill_int_urb(urb, aru->udev,
- usb_sndintpipe(aru->udev, AR9170_EP_CMD),
- aru->common.cmdbuf, plen + 4,
- ar9170_usb_tx_urb_complete, NULL, 1);
-
- usb_anchor_urb(urb, &aru->tx_submitted);
- err = usb_submit_urb(urb, GFP_ATOMIC);
- if (unlikely(err)) {
- usb_unanchor_urb(urb);
- usb_free_urb(urb);
- goto err_unbuf;
- }
- usb_free_urb(urb);
-
- err = wait_for_completion_timeout(&aru->cmd_wait, HZ);
- if (err == 0) {
- err = -ETIMEDOUT;
- goto err_unbuf;
- }
-
- if (aru->readlen != outlen) {
- err = -EMSGSIZE;
- goto err_unbuf;
- }
-
- return 0;
-
-err_unbuf:
- /* Maybe the device was removed in the second we were waiting? */
- if (IS_STARTED(ar)) {
- dev_err(&aru->udev->dev, "no command feedback "
- "received (%d).\n", err);
-
- /* provide some maybe useful debug information */
- print_hex_dump_bytes("ar9170 cmd: ", DUMP_PREFIX_NONE,
- aru->common.cmdbuf, plen + 4);
- dump_stack();
- }
-
- /* invalidate to avoid completing the next prematurely */
- spin_lock_irqsave(&aru->common.cmdlock, flags);
- aru->readbuf = NULL;
- aru->readlen = 0;
- spin_unlock_irqrestore(&aru->common.cmdlock, flags);
-
-err_free:
-
- return err;
-}
-
-static int ar9170_usb_tx(struct ar9170 *ar, struct sk_buff *skb)
-{
- struct ar9170_usb *aru = (struct ar9170_usb *) ar;
- struct urb *urb;
-
- if (unlikely(!IS_STARTED(ar))) {
- /* Seriously, what were you drink... err... thinking!? */
- return -EPERM;
- }
-
- urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (unlikely(!urb))
- return -ENOMEM;
-
- usb_fill_bulk_urb(urb, aru->udev,
- usb_sndbulkpipe(aru->udev, AR9170_EP_TX),
- skb->data, skb->len,
- ar9170_usb_tx_urb_complete_frame, skb);
- urb->transfer_flags |= URB_ZERO_PACKET;
-
- usb_anchor_urb(urb, &aru->tx_pending);
- aru->tx_pending_urbs++;
-
- usb_free_urb(urb);
-
- ar9170_usb_submit_urb(aru);
- return 0;
-}
-
-static void ar9170_usb_callback_cmd(struct ar9170 *ar, u32 len , void *buffer)
-{
- struct ar9170_usb *aru = (void *) ar;
- unsigned long flags;
- u32 in, out;
-
- if (unlikely(!buffer))
- return ;
-
- in = le32_to_cpup((__le32 *)buffer);
- out = le32_to_cpu(ar->cmdbuf[0]);
-
- /* mask off length byte */
- out &= ~0xFF;
-
- if (aru->readlen >= 0) {
- /* add expected length */
- out |= aru->readlen;
- } else {
- /* add obtained length */
- out |= in & 0xFF;
- }
-
- /*
- * Some commands (e.g: AR9170_CMD_FREQUENCY) have a variable response
- * length and we cannot predict the correct length in advance.
- * So we only check if we provided enough space for the data.
- */
- if (unlikely(out < in)) {
- dev_warn(&aru->udev->dev, "received invalid command response "
- "got %d bytes, instead of %d bytes "
- "and the resp length is %d bytes\n",
- in, out, len);
- print_hex_dump_bytes("ar9170 invalid resp: ",
- DUMP_PREFIX_OFFSET, buffer, len);
- /*
- * Do not complete, then the command times out,
- * and we get a stack trace from there.
- */
- return ;
- }
-
- spin_lock_irqsave(&aru->common.cmdlock, flags);
- if (aru->readbuf && len > 0) {
- memcpy(aru->readbuf, buffer + 4, len - 4);
- aru->readbuf = NULL;
- }
- complete(&aru->cmd_wait);
- spin_unlock_irqrestore(&aru->common.cmdlock, flags);
-}
-
-static int ar9170_usb_upload(struct ar9170_usb *aru, const void *data,
- size_t len, u32 addr, bool complete)
-{
- int transfer, err;
- u8 *buf = kmalloc(4096, GFP_KERNEL);
-
- if (!buf)
- return -ENOMEM;
-
- while (len) {
- transfer = min_t(int, len, 4096);
- memcpy(buf, data, transfer);
-
- err = usb_control_msg(aru->udev, usb_sndctrlpipe(aru->udev, 0),
- 0x30 /* FW DL */, 0x40 | USB_DIR_OUT,
- addr >> 8, 0, buf, transfer, 1000);
-
- if (err < 0) {
- kfree(buf);
- return err;
- }
-
- len -= transfer;
- data += transfer;
- addr += transfer;
- }
- kfree(buf);
-
- if (complete) {
- err = usb_control_msg(aru->udev, usb_sndctrlpipe(aru->udev, 0),
- 0x31 /* FW DL COMPLETE */,
- 0x40 | USB_DIR_OUT, 0, 0, NULL, 0, 5000);
- }
-
- return 0;
-}
-
-static int ar9170_usb_reset(struct ar9170_usb *aru)
-{
- int ret, lock = (aru->intf->condition != USB_INTERFACE_BINDING);
-
- if (lock) {
- ret = usb_lock_device_for_reset(aru->udev, aru->intf);
- if (ret < 0) {
- dev_err(&aru->udev->dev, "unable to lock device "
- "for reset (%d).\n", ret);
- return ret;
- }
- }
-
- ret = usb_reset_device(aru->udev);
- if (lock)
- usb_unlock_device(aru->udev);
-
- /* let it rest - for a second - */
- msleep(1000);
-
- return ret;
-}
-
-static int ar9170_usb_upload_firmware(struct ar9170_usb *aru)
-{
- int err;
-
- if (!aru->init_values)
- goto upload_fw_start;
-
- /* First, upload initial values to device RAM */
- err = ar9170_usb_upload(aru, aru->init_values->data,
- aru->init_values->size, 0x102800, false);
- if (err) {
- dev_err(&aru->udev->dev, "firmware part 1 "
- "upload failed (%d).\n", err);
- return err;
- }
-
-upload_fw_start:
-
- /* Then, upload the firmware itself and start it */
- return ar9170_usb_upload(aru, aru->firmware->data, aru->firmware->size,
- 0x200000, true);
-}
-
-static int ar9170_usb_init_transport(struct ar9170_usb *aru)
-{
- struct ar9170 *ar = (void *) &aru->common;
- int err;
-
- ar9170_regwrite_begin(ar);
-
- /* Set USB Rx stream mode MAX packet number to 2 */
- ar9170_regwrite(AR9170_USB_REG_MAX_AGG_UPLOAD, 0x4);
-
- /* Set USB Rx stream mode timeout to 10us */
- ar9170_regwrite(AR9170_USB_REG_UPLOAD_TIME_CTL, 0x80);
-
- ar9170_regwrite_finish();
-
- err = ar9170_regwrite_result();
- if (err)
- dev_err(&aru->udev->dev, "USB setup failed (%d).\n", err);
-
- return err;
-}
-
-static void ar9170_usb_stop(struct ar9170 *ar)
-{
- struct ar9170_usb *aru = (void *) ar;
- int ret;
-
- if (IS_ACCEPTING_CMD(ar))
- aru->common.state = AR9170_STOPPED;
-
- ret = ar9170_usb_flush(ar);
- if (ret)
- dev_err(&aru->udev->dev, "kill pending tx urbs.\n");
-
- usb_poison_anchored_urbs(&aru->tx_submitted);
-
- /*
- * Note:
- * So far we freed all tx urbs, but we won't dare to touch any rx urbs.
- * Else we would end up with a unresponsive device...
- */
-}
-
-static int ar9170_usb_open(struct ar9170 *ar)
-{
- struct ar9170_usb *aru = (void *) ar;
- int err;
-
- usb_unpoison_anchored_urbs(&aru->tx_submitted);
- err = ar9170_usb_init_transport(aru);
- if (err) {
- usb_poison_anchored_urbs(&aru->tx_submitted);
- return err;
- }
-
- aru->common.state = AR9170_IDLE;
- return 0;
-}
-
-static int ar9170_usb_init_device(struct ar9170_usb *aru)
-{
- int err;
-
- err = ar9170_usb_alloc_rx_irq_urb(aru);
- if (err)
- goto err_out;
-
- err = ar9170_usb_alloc_rx_bulk_urbs(aru);
- if (err)
- goto err_unrx;
-
- err = ar9170_usb_upload_firmware(aru);
- if (err) {
- err = ar9170_echo_test(&aru->common, 0x60d43110);
- if (err) {
- /* force user invention, by disabling the device */
- err = usb_driver_set_configuration(aru->udev, -1);
- dev_err(&aru->udev->dev, "device is in a bad state. "
- "please reconnect it!\n");
- goto err_unrx;
- }
- }
-
- return 0;
-
-err_unrx:
- ar9170_usb_cancel_urbs(aru);
-
-err_out:
- return err;
-}
-
-static void ar9170_usb_firmware_failed(struct ar9170_usb *aru)
-{
- struct device *parent = aru->udev->dev.parent;
- struct usb_device *udev;
-
- /*
- * Store a copy of the usb_device pointer locally.
- * This is because device_release_driver initiates
- * ar9170_usb_disconnect, which in turn frees our
- * driver context (aru).
- */
- udev = aru->udev;
-
- complete(&aru->firmware_loading_complete);
-
- /* unbind anything failed */
- if (parent)
- device_lock(parent);
-
- device_release_driver(&udev->dev);
- if (parent)
- device_unlock(parent);
-
- usb_put_dev(udev);
-}
-
-static void ar9170_usb_firmware_finish(const struct firmware *fw, void *context)
-{
- struct ar9170_usb *aru = context;
- int err;
-
- aru->firmware = fw;
-
- if (!fw) {
- dev_err(&aru->udev->dev, "firmware file not found.\n");
- goto err_freefw;
- }
-
- err = ar9170_usb_init_device(aru);
- if (err)
- goto err_freefw;
-
- err = ar9170_usb_open(&aru->common);
- if (err)
- goto err_unrx;
-
- err = ar9170_register(&aru->common, &aru->udev->dev);
-
- ar9170_usb_stop(&aru->common);
- if (err)
- goto err_unrx;
-
- complete(&aru->firmware_loading_complete);
- usb_put_dev(aru->udev);
- return;
-
- err_unrx:
- ar9170_usb_cancel_urbs(aru);
-
- err_freefw:
- ar9170_usb_firmware_failed(aru);
-}
-
-static void ar9170_usb_firmware_inits(const struct firmware *fw,
- void *context)
-{
- struct ar9170_usb *aru = context;
- int err;
-
- if (!fw) {
- dev_err(&aru->udev->dev, "file with init values not found.\n");
- ar9170_usb_firmware_failed(aru);
- return;
- }
-
- aru->init_values = fw;
-
- /* ok so we have the init values -- get code for two-stage */
-
- err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-2.fw",
- &aru->udev->dev, GFP_KERNEL, aru,
- ar9170_usb_firmware_finish);
- if (err)
- ar9170_usb_firmware_failed(aru);
-}
-
-static void ar9170_usb_firmware_step2(const struct firmware *fw, void *context)
-{
- struct ar9170_usb *aru = context;
- int err;
-
- if (fw) {
- ar9170_usb_firmware_finish(fw, context);
- return;
- }
-
- if (aru->req_one_stage_fw) {
- dev_err(&aru->udev->dev, "ar9170.fw firmware file "
- "not found and is required for this device\n");
- ar9170_usb_firmware_failed(aru);
- return;
- }
-
- dev_err(&aru->udev->dev, "ar9170.fw firmware file "
- "not found, trying old firmware...\n");
-
- err = request_firmware_nowait(THIS_MODULE, 1, "ar9170-1.fw",
- &aru->udev->dev, GFP_KERNEL, aru,
- ar9170_usb_firmware_inits);
- if (err)
- ar9170_usb_firmware_failed(aru);
-}
-
-static bool ar9170_requires_one_stage(const struct usb_device_id *id)
-{
- if (!id->driver_info)
- return false;
- if (id->driver_info == AR9170_REQ_FW1_ONLY)
- return true;
- return false;
-}
-
-static int ar9170_usb_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct ar9170_usb *aru;
- struct ar9170 *ar;
- struct usb_device *udev;
- int err;
-
- aru = ar9170_alloc(sizeof(*aru));
- if (IS_ERR(aru)) {
- err = PTR_ERR(aru);
- goto out;
- }
-
- udev = interface_to_usbdev(intf);
- usb_get_dev(udev);
- aru->udev = udev;
- aru->intf = intf;
- ar = &aru->common;
-
- aru->req_one_stage_fw = ar9170_requires_one_stage(id);
-
- usb_set_intfdata(intf, aru);
- SET_IEEE80211_DEV(ar->hw, &intf->dev);
-
- init_usb_anchor(&aru->rx_submitted);
- init_usb_anchor(&aru->tx_pending);
- init_usb_anchor(&aru->tx_submitted);
- init_completion(&aru->cmd_wait);
- init_completion(&aru->firmware_loading_complete);
- spin_lock_init(&aru->tx_urb_lock);
-
- aru->tx_pending_urbs = 0;
- atomic_set(&aru->tx_submitted_urbs, 0);
-
- aru->common.stop = ar9170_usb_stop;
- aru->common.flush = ar9170_usb_flush;
- aru->common.open = ar9170_usb_open;
- aru->common.tx = ar9170_usb_tx;
- aru->common.exec_cmd = ar9170_usb_exec_cmd;
- aru->common.callback_cmd = ar9170_usb_callback_cmd;
-
-#ifdef CONFIG_PM
- udev->reset_resume = 1;
-#endif /* CONFIG_PM */
- err = ar9170_usb_reset(aru);
- if (err)
- goto err_freehw;
-
- usb_get_dev(aru->udev);
- return request_firmware_nowait(THIS_MODULE, 1, "ar9170.fw",
- &aru->udev->dev, GFP_KERNEL, aru,
- ar9170_usb_firmware_step2);
-err_freehw:
- usb_set_intfdata(intf, NULL);
- usb_put_dev(udev);
- ieee80211_free_hw(ar->hw);
-out:
- return err;
-}
-
-static void ar9170_usb_disconnect(struct usb_interface *intf)
-{
- struct ar9170_usb *aru = usb_get_intfdata(intf);
-
- if (!aru)
- return;
-
- aru->common.state = AR9170_IDLE;
-
- wait_for_completion(&aru->firmware_loading_complete);
-
- ar9170_unregister(&aru->common);
- ar9170_usb_cancel_urbs(aru);
-
- usb_put_dev(aru->udev);
- usb_set_intfdata(intf, NULL);
- ieee80211_free_hw(aru->common.hw);
-
- release_firmware(aru->init_values);
- release_firmware(aru->firmware);
-}
-
-#ifdef CONFIG_PM
-static int ar9170_suspend(struct usb_interface *intf,
- pm_message_t message)
-{
- struct ar9170_usb *aru = usb_get_intfdata(intf);
-
- if (!aru)
- return -ENODEV;
-
- aru->common.state = AR9170_IDLE;
- ar9170_usb_cancel_urbs(aru);
-
- return 0;
-}
-
-static int ar9170_resume(struct usb_interface *intf)
-{
- struct ar9170_usb *aru = usb_get_intfdata(intf);
- int err;
-
- if (!aru)
- return -ENODEV;
-
- usb_unpoison_anchored_urbs(&aru->rx_submitted);
- usb_unpoison_anchored_urbs(&aru->tx_submitted);
-
- err = ar9170_usb_init_device(aru);
- if (err)
- goto err_unrx;
-
- err = ar9170_usb_open(&aru->common);
- if (err)
- goto err_unrx;
-
- return 0;
-
-err_unrx:
- aru->common.state = AR9170_IDLE;
- ar9170_usb_cancel_urbs(aru);
-
- return err;
-}
-#endif /* CONFIG_PM */
-
-static struct usb_driver ar9170_driver = {
- .name = "ar9170usb",
- .probe = ar9170_usb_probe,
- .disconnect = ar9170_usb_disconnect,
- .id_table = ar9170_usb_ids,
- .soft_unbind = 1,
-#ifdef CONFIG_PM
- .suspend = ar9170_suspend,
- .resume = ar9170_resume,
- .reset_resume = ar9170_resume,
-#endif /* CONFIG_PM */
-};
-
-static int __init ar9170_init(void)
-{
- return usb_register(&ar9170_driver);
-}
-
-static void __exit ar9170_exit(void)
-{
- usb_deregister(&ar9170_driver);
-}
-
-module_init(ar9170_init);
-module_exit(ar9170_exit);
diff --git a/drivers/net/wireless/ath/ar9170/usb.h b/drivers/net/wireless/ath/ar9170/usb.h
deleted file mode 100644
index 919b06046eb3..000000000000
--- a/drivers/net/wireless/ath/ar9170/usb.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Atheros AR9170 USB driver
- *
- * Driver specific definitions
- *
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- * Copyright 2009, Christian Lamparter <chunkeey@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; see the file COPYING. If not, see
- * http://www.gnu.org/licenses/.
- *
- * This file incorporates work covered by the following copyright and
- * permission notice:
- * Copyright (c) 2007-2008 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 __USB_H
-#define __USB_H
-
-#include <linux/usb.h>
-#include <linux/completion.h>
-#include <linux/spinlock.h>
-#include <linux/leds.h>
-#include <net/cfg80211.h>
-#include <net/mac80211.h>
-#include <linux/firmware.h>
-#include "eeprom.h"
-#include "hw.h"
-#include "ar9170.h"
-
-#define AR9170_NUM_RX_URBS 16
-#define AR9170_NUM_TX_URBS 8
-
-struct firmware;
-
-struct ar9170_usb {
- struct ar9170 common;
- struct usb_device *udev;
- struct usb_interface *intf;
-
- struct usb_anchor rx_submitted;
- struct usb_anchor tx_pending;
- struct usb_anchor tx_submitted;
-
- bool req_one_stage_fw;
-
- spinlock_t tx_urb_lock;
- atomic_t tx_submitted_urbs;
- unsigned int tx_pending_urbs;
-
- struct completion cmd_wait;
- struct completion firmware_loading_complete;
- int readlen;
- u8 *readbuf;
-
- const struct firmware *init_values;
- const struct firmware *firmware;
-};
-
-#endif /* __USB_H */
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index a6c6a466000f..7cf4317a2a84 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -119,17 +119,11 @@ struct ath_ops {
void (*write)(void *, u32 val, u32 reg_offset);
void (*enable_write_buffer)(void *);
void (*write_flush) (void *);
+ u32 (*rmw)(void *, u32 reg_offset, u32 set, u32 clr);
};
struct ath_common;
-
-struct ath_bus_ops {
- enum ath_bus_type ath_bus_type;
- void (*read_cachesize)(struct ath_common *common, int *csz);
- bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
- void (*bt_coex_prep)(struct ath_common *common);
- void (*extn_synch_en)(struct ath_common *common);
-};
+struct ath_bus_ops;
struct ath_common {
void *ah;
diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c
index 82324e98efef..ea9982781559 100644
--- a/drivers/net/wireless/ath/ath5k/ahb.c
+++ b/drivers/net/wireless/ath/ath5k/ahb.c
@@ -18,6 +18,7 @@
#include <linux/nl80211.h>
#include <linux/platform_device.h>
+#include <linux/etherdevice.h>
#include <ar231x_platform.h>
#include "ath5k.h"
#include "debug.h"
@@ -62,10 +63,27 @@ int ath5k_hw_read_srev(struct ath5k_hw *ah)
return 0;
}
+static int ath5k_ahb_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
+{
+ struct ath5k_softc *sc = ah->ah_sc;
+ struct platform_device *pdev = to_platform_device(sc->dev);
+ struct ar231x_board_config *bcfg = pdev->dev.platform_data;
+ u8 *cfg_mac;
+
+ if (to_platform_device(sc->dev)->id == 0)
+ cfg_mac = bcfg->config->wlan0_mac;
+ else
+ cfg_mac = bcfg->config->wlan1_mac;
+
+ memcpy(mac, cfg_mac, ETH_ALEN);
+ return 0;
+}
+
static const struct ath_bus_ops ath_ahb_bus_ops = {
.ath_bus_type = ATH_AHB,
.read_cachesize = ath5k_ahb_read_cachesize,
.eeprom_read = ath5k_ahb_eeprom_read,
+ .eeprom_read_mac = ath5k_ahb_eeprom_read_mac,
};
/*Initialization*/
@@ -142,6 +160,16 @@ static int ath_ahb_probe(struct platform_device *pdev)
else
reg |= AR5K_AR5312_ENABLE_WLAN1;
__raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE);
+
+ /*
+ * On a dual-band AR5312, the multiband radio is only
+ * used as pass-through. Disable 2 GHz support in the
+ * driver for it
+ */
+ if (to_platform_device(sc->dev)->id == 0 &&
+ (bcfg->config->flags & (BD_WLAN0|BD_WLAN1)) ==
+ (BD_WLAN1|BD_WLAN0))
+ __set_bit(ATH_STAT_2G_DISABLED, sc->status);
}
ret = ath5k_init_softc(sc, &ath_ahb_bus_ops);
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 8a06dbd39629..bb50700436fe 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -224,8 +224,7 @@
/* SIFS */
#define AR5K_INIT_SIFS_TURBO 6
-/* XXX: 8 from initvals 10 from standard */
-#define AR5K_INIT_SIFS_DEFAULT_BG 8
+#define AR5K_INIT_SIFS_DEFAULT_BG 10
#define AR5K_INIT_SIFS_DEFAULT_A 16
#define AR5K_INIT_SIFS_HALF_RATE 32
#define AR5K_INIT_SIFS_QUARTER_RATE 64
@@ -453,12 +452,10 @@ struct ath5k_tx_status {
u16 ts_seqnum;
u16 ts_tstamp;
u8 ts_status;
- u8 ts_rate[4];
- u8 ts_retry[4];
u8 ts_final_idx;
+ u8 ts_final_retry;
s8 ts_rssi;
u8 ts_shortretry;
- u8 ts_longretry;
u8 ts_virtcol;
u8 ts_antenna;
};
@@ -875,6 +872,19 @@ enum ath5k_int {
AR5K_INT_QTRIG = 0x40000000, /* Non common */
AR5K_INT_GLOBAL = 0x80000000,
+ AR5K_INT_TX_ALL = AR5K_INT_TXOK
+ | AR5K_INT_TXDESC
+ | AR5K_INT_TXERR
+ | AR5K_INT_TXEOL
+ | AR5K_INT_TXURN,
+
+ AR5K_INT_RX_ALL = AR5K_INT_RXOK
+ | AR5K_INT_RXDESC
+ | AR5K_INT_RXERR
+ | AR5K_INT_RXNOFRM
+ | AR5K_INT_RXEOL
+ | AR5K_INT_RXORN,
+
AR5K_INT_COMMON = AR5K_INT_RXOK
| AR5K_INT_RXDESC
| AR5K_INT_RXERR
@@ -1058,6 +1068,7 @@ struct ath5k_hw {
u8 ah_coverage_class;
bool ah_ack_bitrate_high;
u8 ah_bwmode;
+ bool ah_short_slot;
/* Antenna Control */
u32 ah_ant_ctl[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
@@ -1144,6 +1155,13 @@ struct ath5k_hw {
struct ath5k_rx_status *);
};
+struct ath_bus_ops {
+ enum ath_bus_type ath_bus_type;
+ void (*read_cachesize)(struct ath_common *common, int *csz);
+ bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
+ int (*eeprom_read_mac)(struct ath5k_hw *ah, u8 *mac);
+};
+
/*
* Prototypes
*/
@@ -1227,13 +1245,12 @@ int ath5k_hw_dma_stop(struct ath5k_hw *ah);
/* EEPROM access functions */
int ath5k_eeprom_init(struct ath5k_hw *ah);
void ath5k_eeprom_detach(struct ath5k_hw *ah);
-int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac);
/* Protocol Control Unit Functions */
/* Helpers */
int ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
- int len, struct ieee80211_rate *rate);
+ int len, struct ieee80211_rate *rate, bool shortpre);
unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah);
unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah);
extern int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype opmode);
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index bc8240560488..1588401de3c4 100644
--- a/drivers/net/wireless/ath/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
@@ -313,12 +313,17 @@ int ath5k_hw_init(struct ath5k_softc *sc)
goto err;
}
+ if (test_bit(ATH_STAT_2G_DISABLED, sc->status)) {
+ __clear_bit(AR5K_MODE_11B, ah->ah_capabilities.cap_mode);
+ __clear_bit(AR5K_MODE_11G, ah->ah_capabilities.cap_mode);
+ }
+
/* Crypto settings */
common->keymax = (sc->ah->ah_version == AR5K_AR5210 ?
AR5K_KEYTABLE_SIZE_5210 : AR5K_KEYTABLE_SIZE_5211);
if (srev >= AR5K_SREV_AR5212_V4 &&
- (ee->ee_version >= AR5K_EEPROM_VERSION_5_0 &&
+ (ee->ee_version < AR5K_EEPROM_VERSION_5_0 ||
!AR5K_EEPROM_AES_DIS(ee->ee_misc5)))
common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM;
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 349a5963931b..22047628ccfa 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -1444,6 +1444,21 @@ ath5k_receive_frame_ok(struct ath5k_softc *sc, struct ath5k_rx_status *rs)
}
static void
+ath5k_set_current_imask(struct ath5k_softc *sc)
+{
+ enum ath5k_int imask = sc->imask;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sc->irqlock, flags);
+ if (sc->rx_pending)
+ imask &= ~AR5K_INT_RX_ALL;
+ if (sc->tx_pending)
+ imask &= ~AR5K_INT_TX_ALL;
+ ath5k_hw_set_imr(sc->ah, imask);
+ spin_unlock_irqrestore(&sc->irqlock, flags);
+}
+
+static void
ath5k_tasklet_rx(unsigned long data)
{
struct ath5k_rx_status rs = {};
@@ -1506,6 +1521,8 @@ next:
} while (ath5k_rxbuf_setup(sc, bf) == 0);
unlock:
spin_unlock(&sc->rxbuflock);
+ sc->rx_pending = false;
+ ath5k_set_current_imask(sc);
}
@@ -1573,28 +1590,28 @@ ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb,
struct ath5k_txq *txq, struct ath5k_tx_status *ts)
{
struct ieee80211_tx_info *info;
+ u8 tries[3];
int i;
sc->stats.tx_all_count++;
sc->stats.tx_bytes_count += skb->len;
info = IEEE80211_SKB_CB(skb);
+ tries[0] = info->status.rates[0].count;
+ tries[1] = info->status.rates[1].count;
+ tries[2] = info->status.rates[2].count;
+
ieee80211_tx_info_clear_status(info);
- for (i = 0; i < 4; i++) {
+
+ for (i = 0; i < ts->ts_final_idx; i++) {
struct ieee80211_tx_rate *r =
&info->status.rates[i];
- if (ts->ts_rate[i]) {
- r->idx = ath5k_hw_to_driver_rix(sc, ts->ts_rate[i]);
- r->count = ts->ts_retry[i];
- } else {
- r->idx = -1;
- r->count = 0;
- }
+ r->count = tries[i];
}
- /* count the successful attempt as well */
- info->status.rates[ts->ts_final_idx].count++;
+ info->status.rates[ts->ts_final_idx].count = ts->ts_final_retry;
+ info->status.rates[ts->ts_final_idx + 1].idx = -1;
if (unlikely(ts->ts_status)) {
sc->stats.ack_fail++;
@@ -1609,6 +1626,9 @@ ath5k_tx_frame_completed(struct ath5k_softc *sc, struct sk_buff *skb,
} else {
info->flags |= IEEE80211_TX_STAT_ACK;
info->status.ack_signal = ts->ts_rssi;
+
+ /* count the successful attempt as well */
+ info->status.rates[ts->ts_final_idx].count++;
}
/*
@@ -1690,6 +1710,9 @@ ath5k_tasklet_tx(unsigned long data)
for (i=0; i < AR5K_NUM_TX_QUEUES; i++)
if (sc->txqs[i].setup && (sc->ah->ah_txq_isr & BIT(i)))
ath5k_tx_processq(sc, &sc->txqs[i]);
+
+ sc->tx_pending = false;
+ ath5k_set_current_imask(sc);
}
@@ -2119,6 +2142,20 @@ ath5k_intr_calibration_poll(struct ath5k_hw *ah)
* AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */
}
+static void
+ath5k_schedule_rx(struct ath5k_softc *sc)
+{
+ sc->rx_pending = true;
+ tasklet_schedule(&sc->rxtq);
+}
+
+static void
+ath5k_schedule_tx(struct ath5k_softc *sc)
+{
+ sc->tx_pending = true;
+ tasklet_schedule(&sc->txtq);
+}
+
irqreturn_t
ath5k_intr(int irq, void *dev_id)
{
@@ -2161,7 +2198,7 @@ ath5k_intr(int irq, void *dev_id)
ieee80211_queue_work(sc->hw, &sc->reset_work);
}
else
- tasklet_schedule(&sc->rxtq);
+ ath5k_schedule_rx(sc);
} else {
if (status & AR5K_INT_SWBA) {
tasklet_hi_schedule(&sc->beacontq);
@@ -2179,10 +2216,10 @@ ath5k_intr(int irq, void *dev_id)
ath5k_hw_update_tx_triglevel(ah, true);
}
if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR))
- tasklet_schedule(&sc->rxtq);
+ ath5k_schedule_rx(sc);
if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC
| AR5K_INT_TXERR | AR5K_INT_TXEOL))
- tasklet_schedule(&sc->txtq);
+ ath5k_schedule_tx(sc);
if (status & AR5K_INT_BMISS) {
/* TODO */
}
@@ -2201,6 +2238,9 @@ ath5k_intr(int irq, void *dev_id)
} while (ath5k_hw_is_intr_pending(ah) && --counter > 0);
+ if (sc->rx_pending || sc->tx_pending)
+ ath5k_set_current_imask(sc);
+
if (unlikely(!counter))
ATH5K_WARN(sc, "too many interrupts, giving up for now\n");
@@ -2354,7 +2394,7 @@ ath5k_init_softc(struct ath5k_softc *sc, const struct ath_bus_ops *bus_ops)
spin_lock_init(&sc->rxbuflock);
spin_lock_init(&sc->txbuflock);
spin_lock_init(&sc->block);
-
+ spin_lock_init(&sc->irqlock);
/* Setup interrupt handler */
ret = request_irq(sc->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
@@ -2572,6 +2612,8 @@ done:
static void stop_tasklets(struct ath5k_softc *sc)
{
+ sc->rx_pending = false;
+ sc->tx_pending = false;
tasklet_kill(&sc->rxtq);
tasklet_kill(&sc->txtq);
tasklet_kill(&sc->calib);
@@ -2838,7 +2880,7 @@ ath5k_init(struct ieee80211_hw *hw)
INIT_WORK(&sc->reset_work, ath5k_reset_work);
INIT_DELAYED_WORK(&sc->tx_complete_work, ath5k_tx_complete_poll_work);
- ret = ath5k_eeprom_read_mac(ah, mac);
+ ret = ath5k_hw_common(ah)->bus_ops->eeprom_read_mac(ah, mac);
if (ret) {
ATH5K_ERR(sc, "unable to read address from EEPROM\n");
goto err_queues;
@@ -2898,7 +2940,6 @@ ath5k_deinit_softc(struct ath5k_softc *sc)
* XXX: ??? detach ath5k_hw ???
* Other than that, it's straightforward...
*/
- ath5k_debug_finish_device(sc);
ieee80211_unregister_hw(hw);
ath5k_desc_free(sc);
ath5k_txq_release(sc);
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index 978f1f4ac2f3..b294f3305011 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -193,12 +193,13 @@ struct ath5k_softc {
dma_addr_t desc_daddr; /* DMA (physical) address */
size_t desc_len; /* size of TX/RX descriptors */
- DECLARE_BITMAP(status, 5);
+ DECLARE_BITMAP(status, 6);
#define ATH_STAT_INVALID 0 /* disable hardware accesses */
#define ATH_STAT_MRRETRY 1 /* multi-rate retry support */
#define ATH_STAT_PROMISC 2
#define ATH_STAT_LEDSOFT 3 /* enable LED gpio status */
#define ATH_STAT_STARTED 4 /* opened & irqs enabled */
+#define ATH_STAT_2G_DISABLED 5 /* multiband radio without 2G */
unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */
struct ieee80211_channel *curchan; /* current h/w channel */
@@ -207,6 +208,10 @@ struct ath5k_softc {
enum ath5k_int imask; /* interrupt mask copy */
+ spinlock_t irqlock;
+ bool rx_pending; /* rx tasklet pending */
+ bool tx_pending; /* tx tasklet pending */
+
u8 lladdr[ETH_ALEN];
u8 bssidmask[ETH_ALEN];
diff --git a/drivers/net/wireless/ath/ath5k/caps.c b/drivers/net/wireless/ath/ath5k/caps.c
index f77e8a703c5c..7dd88e1c3ff8 100644
--- a/drivers/net/wireless/ath/ath5k/caps.c
+++ b/drivers/net/wireless/ath/ath5k/caps.c
@@ -94,6 +94,9 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
}
}
+ if ((ah->ah_radio_5ghz_revision & 0xf0) == AR5K_SREV_RAD_2112)
+ __clear_bit(AR5K_MODE_11A, caps->cap_mode);
+
/* Set number of supported TX queues */
if (ah->ah_version == AR5K_AR5210)
caps->cap_queues.q_tx_num = AR5K_NUM_TX_QUEUES_NOQCU;
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index 0230f30e9e9a..0bf7313b8a17 100644
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -888,65 +888,38 @@ static const struct file_operations fops_queue = {
void
ath5k_debug_init_device(struct ath5k_softc *sc)
{
- sc->debug.level = ath5k_debug;
+ struct dentry *phydir;
- sc->debug.debugfs_phydir = debugfs_create_dir("ath5k",
- sc->hw->wiphy->debugfsdir);
+ sc->debug.level = ath5k_debug;
- sc->debug.debugfs_debug = debugfs_create_file("debug",
- S_IWUSR | S_IRUSR,
- sc->debug.debugfs_phydir, sc, &fops_debug);
+ phydir = debugfs_create_dir("ath5k", sc->hw->wiphy->debugfsdir);
+ if (!phydir)
+ return;
- sc->debug.debugfs_registers = debugfs_create_file("registers", S_IRUSR,
- sc->debug.debugfs_phydir, sc, &fops_registers);
+ debugfs_create_file("debug", S_IWUSR | S_IRUSR, phydir, sc,
+ &fops_debug);
- sc->debug.debugfs_beacon = debugfs_create_file("beacon",
- S_IWUSR | S_IRUSR,
- sc->debug.debugfs_phydir, sc, &fops_beacon);
+ debugfs_create_file("registers", S_IRUSR, phydir, sc, &fops_registers);
- sc->debug.debugfs_reset = debugfs_create_file("reset", S_IWUSR,
- sc->debug.debugfs_phydir, sc, &fops_reset);
+ debugfs_create_file("beacon", S_IWUSR | S_IRUSR, phydir, sc,
+ &fops_beacon);
- sc->debug.debugfs_antenna = debugfs_create_file("antenna",
- S_IWUSR | S_IRUSR,
- sc->debug.debugfs_phydir, sc, &fops_antenna);
+ debugfs_create_file("reset", S_IWUSR, phydir, sc, &fops_reset);
- sc->debug.debugfs_misc = debugfs_create_file("misc",
- S_IRUSR,
- sc->debug.debugfs_phydir, sc, &fops_misc);
+ debugfs_create_file("antenna", S_IWUSR | S_IRUSR, phydir, sc,
+ &fops_antenna);
- sc->debug.debugfs_frameerrors = debugfs_create_file("frameerrors",
- S_IWUSR | S_IRUSR,
- sc->debug.debugfs_phydir, sc,
- &fops_frameerrors);
+ debugfs_create_file("misc", S_IRUSR, phydir, sc, &fops_misc);
- sc->debug.debugfs_ani = debugfs_create_file("ani",
- S_IWUSR | S_IRUSR,
- sc->debug.debugfs_phydir, sc,
- &fops_ani);
+ debugfs_create_file("frameerrors", S_IWUSR | S_IRUSR, phydir, sc,
+ &fops_frameerrors);
- sc->debug.debugfs_queue = debugfs_create_file("queue",
- S_IWUSR | S_IRUSR,
- sc->debug.debugfs_phydir, sc,
- &fops_queue);
-}
+ debugfs_create_file("ani", S_IWUSR | S_IRUSR, phydir, sc, &fops_ani);
-void
-ath5k_debug_finish_device(struct ath5k_softc *sc)
-{
- debugfs_remove(sc->debug.debugfs_debug);
- debugfs_remove(sc->debug.debugfs_registers);
- debugfs_remove(sc->debug.debugfs_beacon);
- debugfs_remove(sc->debug.debugfs_reset);
- debugfs_remove(sc->debug.debugfs_antenna);
- debugfs_remove(sc->debug.debugfs_misc);
- debugfs_remove(sc->debug.debugfs_frameerrors);
- debugfs_remove(sc->debug.debugfs_ani);
- debugfs_remove(sc->debug.debugfs_queue);
- debugfs_remove(sc->debug.debugfs_phydir);
+ debugfs_create_file("queue", S_IWUSR | S_IRUSR, phydir, sc,
+ &fops_queue);
}
-
/* functions used in other places */
void
diff --git a/drivers/net/wireless/ath/ath5k/debug.h b/drivers/net/wireless/ath/ath5k/debug.h
index b0355aef68d3..193dd2d4ea3c 100644
--- a/drivers/net/wireless/ath/ath5k/debug.h
+++ b/drivers/net/wireless/ath/ath5k/debug.h
@@ -68,17 +68,6 @@ struct ath5k_buf;
struct ath5k_dbg_info {
unsigned int level; /* debug level */
- /* debugfs entries */
- struct dentry *debugfs_phydir;
- struct dentry *debugfs_debug;
- struct dentry *debugfs_registers;
- struct dentry *debugfs_beacon;
- struct dentry *debugfs_reset;
- struct dentry *debugfs_antenna;
- struct dentry *debugfs_misc;
- struct dentry *debugfs_frameerrors;
- struct dentry *debugfs_ani;
- struct dentry *debugfs_queue;
};
/**
@@ -141,9 +130,6 @@ void
ath5k_debug_init_device(struct ath5k_softc *sc);
void
-ath5k_debug_finish_device(struct ath5k_softc *sc);
-
-void
ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah);
void
@@ -167,9 +153,6 @@ static inline void
ath5k_debug_init_device(struct ath5k_softc *sc) {}
static inline void
-ath5k_debug_finish_device(struct ath5k_softc *sc) {}
-
-static inline void
ath5k_debug_printrxbuffs(struct ath5k_softc *sc, struct ath5k_hw *ah) {}
static inline void
diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c
index a8fcc94269f7..62172d585723 100644
--- a/drivers/net/wireless/ath/ath5k/desc.c
+++ b/drivers/net/wireless/ath/ath5k/desc.c
@@ -185,6 +185,12 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
struct ath5k_hw_4w_tx_ctl *tx_ctl;
unsigned int frame_len;
+ /*
+ * Use local variables for these to reduce load/store access on
+ * uncached memory
+ */
+ u32 txctl0 = 0, txctl1 = 0, txctl2 = 0, txctl3 = 0;
+
tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
/*
@@ -208,8 +214,9 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
if (tx_power > AR5K_TUNE_MAX_TXPOWER)
tx_power = AR5K_TUNE_MAX_TXPOWER;
- /* Clear descriptor */
- memset(&desc->ud.ds_tx5212, 0, sizeof(struct ath5k_hw_5212_tx_desc));
+ /* Clear descriptor status area */
+ memset(&desc->ud.ds_tx5212.tx_stat, 0,
+ sizeof(desc->ud.ds_tx5212.tx_stat));
/* Setup control descriptor */
@@ -221,7 +228,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN)
return -EINVAL;
- tx_ctl->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
+ txctl0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN;
/* Verify and set buffer length */
@@ -232,21 +239,17 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN)
return -EINVAL;
- tx_ctl->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
+ txctl1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN;
- tx_ctl->tx_control_0 |=
- AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) |
- AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT);
- tx_ctl->tx_control_1 |= AR5K_REG_SM(type,
- AR5K_4W_TX_DESC_CTL1_FRAME_TYPE);
- tx_ctl->tx_control_2 = AR5K_REG_SM(tx_tries0,
- AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0);
- tx_ctl->tx_control_3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
+ txctl0 |= AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) |
+ AR5K_REG_SM(antenna_mode, AR5K_4W_TX_DESC_CTL0_ANT_MODE_XMIT);
+ txctl1 |= AR5K_REG_SM(type, AR5K_4W_TX_DESC_CTL1_FRAME_TYPE);
+ txctl2 = AR5K_REG_SM(tx_tries0, AR5K_4W_TX_DESC_CTL2_XMIT_TRIES0);
+ txctl3 = tx_rate0 & AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
#define _TX_FLAGS(_c, _flag) \
if (flags & AR5K_TXDESC_##_flag) { \
- tx_ctl->tx_control_##_c |= \
- AR5K_4W_TX_DESC_CTL##_c##_##_flag; \
+ txctl##_c |= AR5K_4W_TX_DESC_CTL##_c##_##_flag; \
}
_TX_FLAGS(0, CLRDMASK);
@@ -262,8 +265,8 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
* WEP crap
*/
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,
+ txctl0 |= AR5K_4W_TX_DESC_CTL0_ENCRYPT_KEY_VALID;
+ txctl1 |= AR5K_REG_SM(key_index,
AR5K_4W_TX_DESC_CTL1_ENCRYPT_KEY_IDX);
}
@@ -274,12 +277,16 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
if ((flags & AR5K_TXDESC_RTSENA) &&
(flags & AR5K_TXDESC_CTSENA))
return -EINVAL;
- tx_ctl->tx_control_2 |= rtscts_duration &
- AR5K_4W_TX_DESC_CTL2_RTS_DURATION;
- tx_ctl->tx_control_3 |= AR5K_REG_SM(rtscts_rate,
+ txctl2 |= rtscts_duration & AR5K_4W_TX_DESC_CTL2_RTS_DURATION;
+ txctl3 |= AR5K_REG_SM(rtscts_rate,
AR5K_4W_TX_DESC_CTL3_RTS_CTS_RATE);
}
+ tx_ctl->tx_control_0 = txctl0;
+ tx_ctl->tx_control_1 = txctl1;
+ tx_ctl->tx_control_2 = txctl2;
+ tx_ctl->tx_control_3 = txctl3;
+
return 0;
}
@@ -364,7 +371,7 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah,
AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
- ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
+ ts->ts_final_retry = AR5K_REG_MS(tx_status->tx_status_0,
AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
/*TODO: ts->ts_virtcol + test*/
ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
@@ -373,9 +380,6 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah,
AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
ts->ts_antenna = 1;
ts->ts_status = 0;
- ts->ts_rate[0] = AR5K_REG_MS(tx_ctl->tx_control_0,
- AR5K_2W_TX_DESC_CTL0_XMIT_RATE);
- ts->ts_retry[0] = ts->ts_longretry;
ts->ts_final_idx = 0;
if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
@@ -401,81 +405,48 @@ 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;
+ u32 txstat0, txstat1;
tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
tx_status = &desc->ud.ds_tx5212.tx_stat;
+ txstat1 = ACCESS_ONCE(tx_status->tx_status_1);
+
/* No frame has been send or error */
- if (unlikely(!(tx_status->tx_status_1 & AR5K_DESC_TX_STATUS1_DONE)))
+ if (unlikely(!(txstat1 & AR5K_DESC_TX_STATUS1_DONE)))
return -EINPROGRESS;
+ txstat0 = ACCESS_ONCE(tx_status->tx_status_0);
+
/*
* Get descriptor status
*/
- ts->ts_tstamp = AR5K_REG_MS(tx_status->tx_status_0,
+ ts->ts_tstamp = AR5K_REG_MS(txstat0,
AR5K_DESC_TX_STATUS0_SEND_TIMESTAMP);
- ts->ts_shortretry = AR5K_REG_MS(tx_status->tx_status_0,
+ ts->ts_shortretry = AR5K_REG_MS(txstat0,
AR5K_DESC_TX_STATUS0_SHORT_RETRY_COUNT);
- ts->ts_longretry = AR5K_REG_MS(tx_status->tx_status_0,
+ ts->ts_final_retry = AR5K_REG_MS(txstat0,
AR5K_DESC_TX_STATUS0_LONG_RETRY_COUNT);
- ts->ts_seqnum = AR5K_REG_MS(tx_status->tx_status_1,
+ ts->ts_seqnum = AR5K_REG_MS(txstat1,
AR5K_DESC_TX_STATUS1_SEQ_NUM);
- ts->ts_rssi = AR5K_REG_MS(tx_status->tx_status_1,
+ ts->ts_rssi = AR5K_REG_MS(txstat1,
AR5K_DESC_TX_STATUS1_ACK_SIG_STRENGTH);
- ts->ts_antenna = (tx_status->tx_status_1 &
+ ts->ts_antenna = (txstat1 &
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,
+ ts->ts_final_idx = AR5K_REG_MS(txstat1,
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
- * we have to add the retry counters for the other rates
- * as well
- */
- ts->ts_retry[ts->ts_final_idx] = ts->ts_longretry;
- switch (ts->ts_final_idx) {
- case 3:
- ts->ts_rate[3] = AR5K_REG_MS(tx_ctl->tx_control_3,
- AR5K_4W_TX_DESC_CTL3_XMIT_RATE3);
-
- ts->ts_retry[2] = AR5K_REG_MS(tx_ctl->tx_control_2,
- AR5K_4W_TX_DESC_CTL2_XMIT_TRIES2);
- ts->ts_longretry += ts->ts_retry[2];
- /* fall through */
- case 2:
- ts->ts_rate[2] = AR5K_REG_MS(tx_ctl->tx_control_3,
- AR5K_4W_TX_DESC_CTL3_XMIT_RATE2);
-
- ts->ts_retry[1] = AR5K_REG_MS(tx_ctl->tx_control_2,
- AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
- ts->ts_longretry += ts->ts_retry[1];
- /* fall through */
- case 1:
- ts->ts_rate[1] = AR5K_REG_MS(tx_ctl->tx_control_3,
- AR5K_4W_TX_DESC_CTL3_XMIT_RATE1);
-
- ts->ts_retry[0] = AR5K_REG_MS(tx_ctl->tx_control_2,
- AR5K_4W_TX_DESC_CTL2_XMIT_TRIES1);
- ts->ts_longretry += ts->ts_retry[0];
- /* fall through */
- case 0:
- ts->ts_rate[0] = tx_ctl->tx_control_3 &
- AR5K_4W_TX_DESC_CTL3_XMIT_RATE0;
- break;
- }
-
/* TX error */
- if (!(tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
- if (tx_status->tx_status_0 &
- AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
+ if (!(txstat0 & AR5K_DESC_TX_STATUS0_FRAME_XMIT_OK)) {
+ if (txstat0 & AR5K_DESC_TX_STATUS0_EXCESSIVE_RETRIES)
ts->ts_status |= AR5K_TXERR_XRETRY;
- if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
+ if (txstat0 & AR5K_DESC_TX_STATUS0_FIFO_UNDERRUN)
ts->ts_status |= AR5K_TXERR_FIFO;
- if (tx_status->tx_status_0 & AR5K_DESC_TX_STATUS0_FILTERED)
+ if (txstat0 & AR5K_DESC_TX_STATUS0_FILTERED)
ts->ts_status |= AR5K_TXERR_FILT;
}
@@ -609,37 +580,37 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
struct ath5k_rx_status *rs)
{
struct ath5k_hw_rx_status *rx_status;
+ u32 rxstat0, rxstat1;
rx_status = &desc->ud.ds_rx.rx_stat;
+ rxstat1 = ACCESS_ONCE(rx_status->rx_status_1);
/* No frame received / not ready */
- if (unlikely(!(rx_status->rx_status_1 &
- AR5K_5212_RX_DESC_STATUS1_DONE)))
+ if (unlikely(!(rxstat1 & AR5K_5212_RX_DESC_STATUS1_DONE)))
return -EINPROGRESS;
memset(rs, 0, sizeof(struct ath5k_rx_status));
+ rxstat0 = ACCESS_ONCE(rx_status->rx_status_0);
/*
* Frame receive status
*/
- rs->rs_datalen = rx_status->rx_status_0 &
- AR5K_5212_RX_DESC_STATUS0_DATA_LEN;
- rs->rs_rssi = AR5K_REG_MS(rx_status->rx_status_0,
+ rs->rs_datalen = rxstat0 & AR5K_5212_RX_DESC_STATUS0_DATA_LEN;
+ rs->rs_rssi = AR5K_REG_MS(rxstat0,
AR5K_5212_RX_DESC_STATUS0_RECEIVE_SIGNAL);
- rs->rs_rate = AR5K_REG_MS(rx_status->rx_status_0,
+ rs->rs_rate = AR5K_REG_MS(rxstat0,
AR5K_5212_RX_DESC_STATUS0_RECEIVE_RATE);
- rs->rs_antenna = AR5K_REG_MS(rx_status->rx_status_0,
+ rs->rs_antenna = AR5K_REG_MS(rxstat0,
AR5K_5212_RX_DESC_STATUS0_RECEIVE_ANTENNA);
- rs->rs_more = !!(rx_status->rx_status_0 &
- AR5K_5212_RX_DESC_STATUS0_MORE);
- rs->rs_tstamp = AR5K_REG_MS(rx_status->rx_status_1,
+ rs->rs_more = !!(rxstat0 & AR5K_5212_RX_DESC_STATUS0_MORE);
+ rs->rs_tstamp = AR5K_REG_MS(rxstat1,
AR5K_5212_RX_DESC_STATUS1_RECEIVE_TIMESTAMP);
/*
* 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,
+ if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_KEY_INDEX_VALID)
+ rs->rs_keyix = AR5K_REG_MS(rxstat1,
AR5K_5212_RX_DESC_STATUS1_KEY_INDEX);
else
rs->rs_keyix = AR5K_RXKEYIX_INVALID;
@@ -647,27 +618,22 @@ 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)) {
- if (rx_status->rx_status_1 &
- AR5K_5212_RX_DESC_STATUS1_CRC_ERROR)
+ if (!(rxstat1 & AR5K_5212_RX_DESC_STATUS1_FRAME_RECEIVE_OK)) {
+ if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_CRC_ERROR)
rs->rs_status |= AR5K_RXERR_CRC;
- if (rx_status->rx_status_1 &
- AR5K_5212_RX_DESC_STATUS1_PHY_ERROR) {
+ if (rxstat1 & AR5K_5212_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(rxstat1,
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 &
- AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
+ if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_DECRYPT_CRC_ERROR)
rs->rs_status |= AR5K_RXERR_DECRYPT;
- if (rx_status->rx_status_1 &
- AR5K_5212_RX_DESC_STATUS1_MIC_ERROR)
+ if (rxstat1 & AR5K_5212_RX_DESC_STATUS1_MIC_ERROR)
rs->rs_status |= AR5K_RXERR_MIC;
}
return 0;
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c
index efb672cb31e4..1fef84f87c78 100644
--- a/drivers/net/wireless/ath/ath5k/eeprom.c
+++ b/drivers/net/wireless/ath/ath5k/eeprom.c
@@ -660,6 +660,53 @@ ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp)
vp[i] = (ip[i] * max + (100 - ip[i]) * min) / 100;
}
+static int
+ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode)
+{
+ struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+ struct ath5k_chan_pcal_info *chinfo;
+ u8 pier, pdg;
+
+ switch (mode) {
+ case AR5K_EEPROM_MODE_11A:
+ if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
+ return 0;
+ chinfo = ee->ee_pwr_cal_a;
+ break;
+ case AR5K_EEPROM_MODE_11B:
+ if (!AR5K_EEPROM_HDR_11B(ee->ee_header))
+ return 0;
+ chinfo = ee->ee_pwr_cal_b;
+ break;
+ case AR5K_EEPROM_MODE_11G:
+ if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
+ return 0;
+ chinfo = ee->ee_pwr_cal_g;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
+ if (!chinfo[pier].pd_curves)
+ continue;
+
+ for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
+ struct ath5k_pdgain_info *pd =
+ &chinfo[pier].pd_curves[pdg];
+
+ if (pd != NULL) {
+ kfree(pd->pd_step);
+ kfree(pd->pd_pwr);
+ }
+ }
+
+ kfree(chinfo[pier].pd_curves);
+ }
+
+ return 0;
+}
+
/* Convert RF5111 specific data to generic raw data
* used by interpolation code */
static int
@@ -684,7 +731,7 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode,
GFP_KERNEL);
if (!chinfo[pier].pd_curves)
- return -ENOMEM;
+ goto err_out;
/* Only one curve for RF5111
* find out which one and place
@@ -708,12 +755,12 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode,
pd->pd_step = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111,
sizeof(u8), GFP_KERNEL);
if (!pd->pd_step)
- return -ENOMEM;
+ goto err_out;
pd->pd_pwr = kcalloc(AR5K_EEPROM_N_PWR_POINTS_5111,
sizeof(s16), GFP_KERNEL);
if (!pd->pd_pwr)
- return -ENOMEM;
+ goto err_out;
/* Fill raw dataset
* (convert power to 0.25dB units
@@ -734,6 +781,10 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode,
}
return 0;
+
+err_out:
+ ath5k_eeprom_free_pcal_info(ah, mode);
+ return -ENOMEM;
}
/* Parse EEPROM data */
@@ -867,7 +918,7 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode,
GFP_KERNEL);
if (!chinfo[pier].pd_curves)
- return -ENOMEM;
+ goto err_out;
/* Fill pd_curves */
for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
@@ -886,14 +937,13 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode,
sizeof(u8), GFP_KERNEL);
if (!pd->pd_step)
- return -ENOMEM;
+ goto err_out;
pd->pd_pwr = kcalloc(pd->pd_points,
sizeof(s16), GFP_KERNEL);
if (!pd->pd_pwr)
- return -ENOMEM;
-
+ goto err_out;
/* Fill raw dataset
* (all power levels are in 0.25dB units) */
@@ -925,13 +975,13 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode,
sizeof(u8), GFP_KERNEL);
if (!pd->pd_step)
- return -ENOMEM;
+ goto err_out;
pd->pd_pwr = kcalloc(pd->pd_points,
sizeof(s16), GFP_KERNEL);
if (!pd->pd_pwr)
- return -ENOMEM;
+ goto err_out;
/* Fill raw dataset
* (all power levels are in 0.25dB units) */
@@ -954,6 +1004,10 @@ ath5k_eeprom_convert_pcal_info_5112(struct ath5k_hw *ah, int mode,
}
return 0;
+
+err_out:
+ ath5k_eeprom_free_pcal_info(ah, mode);
+ return -ENOMEM;
}
/* Parse EEPROM data */
@@ -1156,7 +1210,7 @@ ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode,
GFP_KERNEL);
if (!chinfo[pier].pd_curves)
- return -ENOMEM;
+ goto err_out;
/* Fill pd_curves */
for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
@@ -1177,13 +1231,13 @@ ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode,
sizeof(u8), GFP_KERNEL);
if (!pd->pd_step)
- return -ENOMEM;
+ goto err_out;
pd->pd_pwr = kcalloc(pd->pd_points,
sizeof(s16), GFP_KERNEL);
if (!pd->pd_pwr)
- return -ENOMEM;
+ goto err_out;
/* Fill raw dataset
* convert all pwr levels to
@@ -1213,6 +1267,10 @@ ath5k_eeprom_convert_pcal_info_2413(struct ath5k_hw *ah, int mode,
}
return 0;
+
+err_out:
+ ath5k_eeprom_free_pcal_info(ah, mode);
+ return -ENOMEM;
}
/* Parse EEPROM data */
@@ -1534,53 +1592,6 @@ ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah)
return 0;
}
-static int
-ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode)
-{
- struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
- struct ath5k_chan_pcal_info *chinfo;
- u8 pier, pdg;
-
- switch (mode) {
- case AR5K_EEPROM_MODE_11A:
- if (!AR5K_EEPROM_HDR_11A(ee->ee_header))
- return 0;
- chinfo = ee->ee_pwr_cal_a;
- break;
- case AR5K_EEPROM_MODE_11B:
- if (!AR5K_EEPROM_HDR_11B(ee->ee_header))
- return 0;
- chinfo = ee->ee_pwr_cal_b;
- break;
- case AR5K_EEPROM_MODE_11G:
- if (!AR5K_EEPROM_HDR_11G(ee->ee_header))
- return 0;
- chinfo = ee->ee_pwr_cal_g;
- break;
- default:
- return -EINVAL;
- }
-
- for (pier = 0; pier < ee->ee_n_piers[mode]; pier++) {
- if (!chinfo[pier].pd_curves)
- continue;
-
- for (pdg = 0; pdg < ee->ee_pd_gains[mode]; pdg++) {
- struct ath5k_pdgain_info *pd =
- &chinfo[pier].pd_curves[pdg];
-
- if (pd != NULL) {
- kfree(pd->pd_step);
- kfree(pd->pd_pwr);
- }
- }
-
- kfree(chinfo[pier].pd_curves);
- }
-
- return 0;
-}
-
/* Read conformance test limits used for regulatory control */
static int
ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah)
@@ -1721,35 +1732,6 @@ ath5k_eeprom_read_spur_chans(struct ath5k_hw *ah)
return ret;
}
-/*
- * Read the MAC address from eeprom
- */
-int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
-{
- u8 mac_d[ETH_ALEN] = {};
- u32 total, offset;
- u16 data;
- int octet;
-
- AR5K_EEPROM_READ(0x20, data);
-
- for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
- AR5K_EEPROM_READ(offset, data);
-
- total += data;
- mac_d[octet + 1] = data & 0xff;
- mac_d[octet] = data >> 8;
- octet += 2;
- }
-
- if (!total || total == 3 * 0xffff)
- return -EINVAL;
-
- memcpy(mac, mac_d, ETH_ALEN);
-
- return 0;
-}
-
/***********************\
* Init/Detach functions *
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
index 9be29b728b1c..807bd6440169 100644
--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
@@ -282,6 +282,15 @@ ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (changes & BSS_CHANGED_BEACON_INT)
sc->bintval = bss_conf->beacon_int;
+ if (changes & BSS_CHANGED_ERP_SLOT) {
+ int slot_time;
+
+ ah->ah_short_slot = bss_conf->use_short_slot;
+ slot_time = ath5k_hw_get_default_slottime(ah) +
+ 3 * ah->ah_coverage_class;
+ ath5k_hw_set_ifs_intervals(ah, slot_time);
+ }
+
if (changes & BSS_CHANGED_ASSOC) {
avf->assoc = bss_conf->assoc;
if (bss_conf->assoc)
diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c
index 3c44689a700b..296c316a8341 100644
--- a/drivers/net/wireless/ath/ath5k/pci.c
+++ b/drivers/net/wireless/ath/ath5k/pci.c
@@ -17,6 +17,7 @@
#include <linux/nl80211.h>
#include <linux/pci.h>
#include <linux/pci-aspm.h>
+#include <linux/etherdevice.h>
#include "../ath.h"
#include "ath5k.h"
#include "debug.h"
@@ -108,11 +109,42 @@ int ath5k_hw_read_srev(struct ath5k_hw *ah)
return 0;
}
+/*
+ * Read the MAC address from eeprom or platform_data
+ */
+static int ath5k_pci_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
+{
+ u8 mac_d[ETH_ALEN] = {};
+ u32 total, offset;
+ u16 data;
+ int octet;
+
+ AR5K_EEPROM_READ(0x20, data);
+
+ for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
+ AR5K_EEPROM_READ(offset, data);
+
+ total += data;
+ mac_d[octet + 1] = data & 0xff;
+ mac_d[octet] = data >> 8;
+ octet += 2;
+ }
+
+ if (!total || total == 3 * 0xffff)
+ return -EINVAL;
+
+ memcpy(mac, mac_d, ETH_ALEN);
+
+ return 0;
+}
+
+
/* Common ath_bus_opts structure */
static const struct ath_bus_ops ath_pci_bus_ops = {
.ath_bus_type = ATH_PCI,
.read_cachesize = ath5k_pci_read_cachesize,
.eeprom_read = ath5k_pci_eeprom_read,
+ .eeprom_read_mac = ath5k_pci_eeprom_read_mac,
};
/********************\
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c
index d9b3f828455a..712a9ac4000e 100644
--- a/drivers/net/wireless/ath/ath5k/pcu.c
+++ b/drivers/net/wireless/ath/ath5k/pcu.c
@@ -75,7 +75,7 @@ static const unsigned int ack_rates_high[] =
* bwmodes.
*/
int ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
- int len, struct ieee80211_rate *rate)
+ int len, struct ieee80211_rate *rate, bool shortpre)
{
struct ath5k_softc *sc = ah->ah_sc;
int sifs, preamble, plcp_bits, sym_time;
@@ -84,9 +84,15 @@ int ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
/* Fallback */
if (!ah->ah_bwmode) {
- dur = ieee80211_generic_frame_duration(sc->hw,
- NULL, len, rate);
- return le16_to_cpu(dur);
+ __le16 raw_dur = ieee80211_generic_frame_duration(sc->hw,
+ NULL, len, rate);
+
+ /* subtract difference between long and short preamble */
+ dur = le16_to_cpu(raw_dur);
+ if (shortpre)
+ dur -= 96;
+
+ return dur;
}
bitrate = rate->bitrate;
@@ -145,9 +151,9 @@ unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah)
slot_time = AR5K_INIT_SLOT_TIME_QUARTER_RATE;
break;
case AR5K_BWMODE_DEFAULT:
- slot_time = AR5K_INIT_SLOT_TIME_DEFAULT;
default:
- if (channel->hw_value & CHANNEL_CCK)
+ slot_time = AR5K_INIT_SLOT_TIME_DEFAULT;
+ if ((channel->hw_value & CHANNEL_CCK) && !ah->ah_short_slot)
slot_time = AR5K_INIT_SLOT_TIME_B;
break;
}
@@ -263,27 +269,14 @@ static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah)
* actual rate for this rate. See mac80211 tx.c
* ieee80211_duration() for a brief description of
* what rate we should choose to TX ACKs. */
- tx_time = ath5k_hw_get_frame_duration(ah, 10, rate);
+ tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false);
ath5k_hw_reg_write(ah, tx_time, reg);
if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE))
continue;
- /*
- * We're not distinguishing short preamble here,
- * This is true, all we'll get is a longer value here
- * which is not necessarilly bad. We could use
- * export ieee80211_frame_duration() but that needs to be
- * fixed first to be properly used by mac802111 drivers:
- *
- * - remove erp stuff and let the routine figure ofdm
- * erp rates
- * - remove passing argument ieee80211_local as
- * drivers don't have access to it
- * - move drivers using ieee80211_generic_frame_duration()
- * to this
- */
+ tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, true);
ath5k_hw_reg_write(ah, tx_time,
reg + (AR5K_SET_SHORT_PREAMBLE << 2));
}
diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c
index 3343fb9e4940..b18c5021aac3 100644
--- a/drivers/net/wireless/ath/ath5k/qcu.c
+++ b/drivers/net/wireless/ath/ath5k/qcu.c
@@ -519,7 +519,7 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time)
return -EINVAL;
sifs = ath5k_hw_get_default_sifs(ah);
- sifs_clock = ath5k_hw_htoclock(ah, sifs);
+ sifs_clock = ath5k_hw_htoclock(ah, sifs - 2);
/* EIFS
* Txtime of ack at lowest rate + SIFS + DIFS
@@ -550,7 +550,7 @@ int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time)
else
rate = &sc->sbands[IEEE80211_BAND_2GHZ].bitrates[0];
- ack_tx_time = ath5k_hw_get_frame_duration(ah, 10, rate);
+ ack_tx_time = ath5k_hw_get_frame_duration(ah, 10, rate, false);
/* ack_tx_time includes an SIFS already */
eifs = ack_tx_time + sifs + 2 * slot_time;
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index 84206898f77d..3510de2cf622 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -159,6 +159,11 @@ static void ath5k_hw_init_core_clock(struct ath5k_hw *ah)
rxlat = AR5K_REG_MS(usec_reg, AR5K_USEC_RX_LATENCY_5211);
/*
+ * Set default Tx frame to Tx data start delay
+ */
+ txf2txs = AR5K_INIT_TXF2TXD_START_DEFAULT;
+
+ /*
* 5210 initvals don't include usec settings
* so we need to use magic values here for
* tx/rx latencies
diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig
index ad57a6d23110..d9ff8413ab9a 100644
--- a/drivers/net/wireless/ath/ath9k/Kconfig
+++ b/drivers/net/wireless/ath/ath9k/Kconfig
@@ -5,7 +5,7 @@ config ATH9K_COMMON
config ATH9K
tristate "Atheros 802.11n wireless cards support"
- depends on PCI && MAC80211
+ depends on MAC80211
select ATH9K_HW
select MAC80211_LEDS
select LEDS_CLASS
@@ -23,6 +23,25 @@ config ATH9K
If you choose to build a module, it'll be called ath9k.
+config ATH9K_PCI
+ bool "Atheros ath9k PCI/PCIe bus support"
+ depends on ATH9K && PCI
+ default PCI
+ ---help---
+ This option enables the PCI bus support in ath9k.
+
+ Say Y, if you have a compatible PCI/PCIe wireless card.
+
+config ATH9K_AHB
+ bool "Atheros ath9k AHB bus support"
+ depends on ATH9K
+ default n
+ ---help---
+ This option enables the AHB bus support in ath9k.
+
+ Say Y, if you have a SoC with a compatible built-in
+ wireless MAC. Say N if unsure.
+
config ATH9K_DEBUGFS
bool "Atheros ath9k debugging"
depends on ATH9K && DEBUG_FS
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index 4d66ca8042eb..05a6fade7b1c 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -6,8 +6,8 @@ ath9k-y += beacon.o \
xmit.o \
ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o
-ath9k-$(CONFIG_PCI) += pci.o
-ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o
+ath9k-$(CONFIG_ATH9K_PCI) += pci.o
+ath9k-$(CONFIG_ATH9K_AHB) += ahb.o
ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o
obj-$(CONFIG_ATH9K) += ath9k.o
@@ -48,4 +48,6 @@ ath9k_htc-y += htc_hst.o \
htc_drv_init.o \
htc_drv_gpio.o
+ath9k_htc-$(CONFIG_ATH9K_HTC_DEBUGFS) += htc_drv_debug.o
+
obj-$(CONFIG_ATH9K_HTC) += ath9k_htc.o
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c
index 9cb0efa9b4c0..5b49cd03bfdf 100644
--- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 Atheros Communications Inc.
* Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
* Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org>
*
@@ -21,6 +21,18 @@
#include <linux/ath9k_platform.h>
#include "ath9k.h"
+static const struct platform_device_id ath9k_platform_id_table[] = {
+ {
+ .name = "ath9k",
+ .driver_data = AR5416_AR9100_DEVID,
+ },
+ {
+ .name = "ar934x_wmac",
+ .driver_data = AR9300_DEVID_AR9340,
+ },
+ {},
+};
+
/* return bus cachesize in 4B word units */
static void ath_ahb_read_cachesize(struct ath_common *common, int *csz)
{
@@ -57,6 +69,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
struct ath_softc *sc;
struct ieee80211_hw *hw;
struct resource *res;
+ const struct platform_device_id *id = platform_get_device_id(pdev);
int irq;
int ret = 0;
struct ath_hw *ah;
@@ -116,7 +129,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
goto err_free_hw;
}
- ret = ath9k_init_device(AR5416_AR9100_DEVID, sc, 0x0, &ath_ahb_bus_ops);
+ ret = ath9k_init_device(id->driver_data, sc, 0x0, &ath_ahb_bus_ops);
if (ret) {
dev_err(&pdev->dev, "failed to initialize device\n");
goto err_irq;
@@ -165,8 +178,11 @@ static struct platform_driver ath_ahb_driver = {
.name = "ath9k",
.owner = THIS_MODULE,
},
+ .id_table = ath9k_platform_id_table,
};
+MODULE_DEVICE_TABLE(platform, ath9k_platform_id_table);
+
int ath_ahb_init(void)
{
return platform_driver_register(&ath_ahb_driver);
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index 2e31c775351f..bfb6481f01f9 100644
--- a/drivers/net/wireless/ath/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -899,12 +899,6 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
* check here default level should not modify INI setting.
*/
if (use_new_ani(ah)) {
- 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 {
diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h
index 0cd6783de883..dbab5b9ce494 100644
--- a/drivers/net/wireless/ath/ath9k/ani.h
+++ b/drivers/net/wireless/ath/ath9k/ani.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_initvals.h b/drivers/net/wireless/ath/ath9k/ar5008_initvals.h
index 36f7d0639db3..234617c948a1 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) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 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
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
index 106c0b06cf55..441bb33f17ad 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -44,6 +44,34 @@ static const int m1ThreshExt_off = 127;
static const int m2ThreshExt_off = 127;
+static void ar5008_rf_bank_setup(u32 *bank, struct ar5416IniArray *array,
+ int col)
+{
+ int i;
+
+ for (i = 0; i < array->ia_rows; i++)
+ bank[i] = INI_RA(array, i, col);
+}
+
+
+#define REG_WRITE_RF_ARRAY(iniarray, regData, regWr) \
+ ar5008_write_rf_array(ah, iniarray, regData, &(regWr))
+
+static void ar5008_write_rf_array(struct ath_hw *ah, struct ar5416IniArray *array,
+ u32 *data, unsigned int *writecnt)
+{
+ int r;
+
+ ENABLE_REGWRITE_BUFFER(ah);
+
+ for (r = 0; r < array->ia_rows; r++) {
+ REG_WRITE(ah, INI_RA(array, r, 0), data[r]);
+ DO_DELAY(*writecnt);
+ }
+
+ REGWRITE_BUFFER_FLUSH(ah);
+}
+
/**
* ar5008_hw_phy_modify_rx_buffer() - perform analog swizzling of parameters
* @rfbuf:
@@ -530,16 +558,16 @@ static bool ar5008_hw_set_rf_regs(struct ath_hw *ah,
eepMinorRev = ah->eep_ops->get_eeprom(ah, EEP_MINOR_REV);
/* Setup Bank 0 Write */
- RF_BANK_SETUP(ah->analogBank0Data, &ah->iniBank0, 1);
+ ar5008_rf_bank_setup(ah->analogBank0Data, &ah->iniBank0, 1);
/* Setup Bank 1 Write */
- RF_BANK_SETUP(ah->analogBank1Data, &ah->iniBank1, 1);
+ ar5008_rf_bank_setup(ah->analogBank1Data, &ah->iniBank1, 1);
/* Setup Bank 2 Write */
- RF_BANK_SETUP(ah->analogBank2Data, &ah->iniBank2, 1);
+ ar5008_rf_bank_setup(ah->analogBank2Data, &ah->iniBank2, 1);
/* Setup Bank 6 Write */
- RF_BANK_SETUP(ah->analogBank3Data, &ah->iniBank3,
+ ar5008_rf_bank_setup(ah->analogBank3Data, &ah->iniBank3,
modesIndex);
{
int i;
@@ -569,7 +597,7 @@ static bool ar5008_hw_set_rf_regs(struct ath_hw *ah,
}
/* Setup Bank 7 Setup */
- RF_BANK_SETUP(ah->analogBank7Data, &ah->iniBank7, 1);
+ ar5008_rf_bank_setup(ah->analogBank7Data, &ah->iniBank7, 1);
/* Write Analog registers */
REG_WRITE_RF_ARRAY(&ah->iniBank0, ah->analogBank0Data,
@@ -729,6 +757,7 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
struct ath9k_channel *chan)
{
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+ struct ath_common *common = ath9k_hw_common(ah);
int i, regWrites = 0;
struct ieee80211_channel *channel = chan->chan;
u32 modesIndex, freqIndex;
@@ -805,7 +834,8 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
REG_WRITE(ah, reg, val);
if (reg >= 0x7800 && reg < 0x78a0
- && ah->config.analog_shiftreg) {
+ && ah->config.analog_shiftreg
+ && (common->bus_ops->ath_bus_type != ATH_USB)) {
udelay(100);
}
@@ -835,7 +865,8 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
REG_WRITE(ah, reg, val);
if (reg >= 0x7800 && reg < 0x78a0
- && ah->config.analog_shiftreg) {
+ && ah->config.analog_shiftreg
+ && (common->bus_ops->ath_bus_type != ATH_USB)) {
udelay(100);
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h
index 69a94c7e45cb..6d2e2f3303f9 100644
--- a/drivers/net/wireless/ath/ath9k/ar9001_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9001_initvals.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 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
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
index 76388c6d6692..015d97439935 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -26,6 +26,27 @@ enum ar9002_cal_types {
IQ_MISMATCH_CAL = BIT(2),
};
+static bool ar9002_hw_is_cal_supported(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ enum ar9002_cal_types cal_type)
+{
+ bool supported = false;
+ switch (ah->supp_cals & cal_type) {
+ case IQ_MISMATCH_CAL:
+ /* Run IQ Mismatch for non-CCK only */
+ if (!IS_CHAN_B(chan))
+ supported = true;
+ break;
+ case ADC_GAIN_CAL:
+ case ADC_DC_CAL:
+ /* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */
+ if (!IS_CHAN_B(chan) &&
+ !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan)))
+ supported = true;
+ break;
+ }
+ return supported;
+}
static void ar9002_hw_setup_calibration(struct ath_hw *ah,
struct ath9k_cal_list *currCal)
@@ -858,26 +879,32 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) {
ah->supp_cals = IQ_MISMATCH_CAL;
- if (AR_SREV_9160_10_OR_LATER(ah) &&
- !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) {
+ if (AR_SREV_9160_10_OR_LATER(ah))
ah->supp_cals |= ADC_GAIN_CAL | ADC_DC_CAL;
+ if (AR_SREV_9287(ah))
+ ah->supp_cals &= ~ADC_GAIN_CAL;
+ if (ar9002_hw_is_cal_supported(ah, chan, ADC_GAIN_CAL)) {
INIT_CAL(&ah->adcgain_caldata);
INSERT_CAL(ah, &ah->adcgain_caldata);
ath_dbg(common, ATH_DBG_CALIBRATE,
- "enabling ADC Gain Calibration.\n");
+ "enabling ADC Gain Calibration.\n");
+ }
+ if (ar9002_hw_is_cal_supported(ah, chan, ADC_DC_CAL)) {
INIT_CAL(&ah->adcdc_caldata);
INSERT_CAL(ah, &ah->adcdc_caldata);
ath_dbg(common, ATH_DBG_CALIBRATE,
- "enabling ADC DC Calibration.\n");
+ "enabling ADC DC Calibration.\n");
}
- INIT_CAL(&ah->iq_caldata);
- INSERT_CAL(ah, &ah->iq_caldata);
- ath_dbg(common, ATH_DBG_CALIBRATE,
- "enabling IQ Calibration.\n");
+ if (ar9002_hw_is_cal_supported(ah, chan, IQ_MISMATCH_CAL)) {
+ INIT_CAL(&ah->iq_caldata);
+ INSERT_CAL(ah, &ah->iq_caldata);
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "enabling IQ Calibration.\n");
+ }
ah->cal_list_curr = ah->cal_list;
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
index f44c84ab5dce..f344cc2b3d59 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h
index 6203eed860dd..7573257731b6 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 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
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
index 399ab3bb299b..077e8a6983fa 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -290,7 +290,6 @@ static void ar9002_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
| (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
| SM(txPower, AR_XmitPower)
| (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
- | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
| (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0)
| (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0);
@@ -311,6 +310,16 @@ static void ar9002_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
}
}
+static void ar9002_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
+{
+ struct ar5416_desc *ads = AR5416DESC(ds);
+
+ if (val)
+ ads->ds_ctl0 |= AR_ClrDestMask;
+ else
+ ads->ds_ctl0 &= ~AR_ClrDestMask;
+}
+
static void ar9002_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
void *lastds,
u32 durUpdateEn, u32 rtsctsRate,
@@ -406,26 +415,6 @@ static void ar9002_hw_clr11n_aggr(struct ath_hw *ah, void *ds)
ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
}
-static void ar9002_hw_set11n_burstduration(struct ath_hw *ah, void *ds,
- u32 burstDuration)
-{
- struct ar5416_desc *ads = AR5416DESC(ds);
-
- ads->ds_ctl2 &= ~AR_BurstDur;
- ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur);
-}
-
-static void ar9002_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds,
- u32 vmf)
-{
- struct ar5416_desc *ads = AR5416DESC(ds);
-
- if (vmf)
- ads->ds_ctl0 |= AR_VirtMoreFrag;
- else
- ads->ds_ctl0 &= ~AR_VirtMoreFrag;
-}
-
void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
u32 size, u32 flags)
{
@@ -458,6 +447,5 @@ void ar9002_hw_attach_mac_ops(struct ath_hw *ah)
ops->set11n_aggr_middle = ar9002_hw_set11n_aggr_middle;
ops->set11n_aggr_last = ar9002_hw_set11n_aggr_last;
ops->clr11n_aggr = ar9002_hw_clr11n_aggr;
- ops->set11n_burstduration = ar9002_hw_set11n_burstduration;
- ops->set11n_virtualmorefrag = ar9002_hw_set11n_virtualmorefrag;
+ ops->set_clrdmask = ar9002_hw_set_clrdmask;
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
index 7d68d61e406b..2fe0a34cbabc 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -517,23 +517,7 @@ static void ar9002_hw_set_nf_limits(struct ath_hw *ah)
}
}
-void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
-{
- struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
-
- priv_ops->set_rf_regs = NULL;
- priv_ops->rf_alloc_ext_banks = NULL;
- priv_ops->rf_free_ext_banks = NULL;
- priv_ops->rf_set_freq = ar9002_hw_set_channel;
- priv_ops->spur_mitigate_freq = ar9002_hw_spur_mitigate;
- 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);
-}
-
-void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah,
+static void ar9002_hw_antdiv_comb_conf_get(struct ath_hw *ah,
struct ath_hw_antcomb_conf *antconf)
{
u32 regval;
@@ -545,10 +529,11 @@ void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah,
AR_PHY_9285_ANT_DIV_ALT_LNACONF_S;
antconf->fast_div_bias = (regval & AR_PHY_9285_FAST_DIV_BIAS) >>
AR_PHY_9285_FAST_DIV_BIAS_S;
+ antconf->lna1_lna2_delta = -3;
+ antconf->div_group = 0;
}
-EXPORT_SYMBOL(ath9k_hw_antdiv_comb_conf_get);
-void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah,
+static void ar9002_hw_antdiv_comb_conf_set(struct ath_hw *ah,
struct ath_hw_antcomb_conf *antconf)
{
u32 regval;
@@ -566,4 +551,23 @@ void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah,
REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval);
}
-EXPORT_SYMBOL(ath9k_hw_antdiv_comb_conf_set);
+
+void ar9002_hw_attach_phy_ops(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->set_rf_regs = NULL;
+ priv_ops->rf_alloc_ext_banks = NULL;
+ priv_ops->rf_free_ext_banks = NULL;
+ priv_ops->rf_set_freq = ar9002_hw_set_channel;
+ priv_ops->spur_mitigate_freq = ar9002_hw_spur_mitigate;
+ 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;
+
+ ops->antdiv_comb_conf_get = ar9002_hw_antdiv_comb_conf_get;
+ ops->antdiv_comb_conf_set = ar9002_hw_antdiv_comb_conf_set;
+
+ 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 37663dbbcf57..453af6dc514b 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -483,7 +483,11 @@
#define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN 0x01F80000
#define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN_S 19
+#define AR_PHY_TX_PWRCTRL8 0xa278
+
#define AR_PHY_TX_PWRCTRL9 0xa27C
+
+#define AR_PHY_TX_PWRCTRL10 0xa394
#define AR_PHY_TX_DESIRED_SCALE_CCK 0x00007C00
#define AR_PHY_TX_DESIRED_SCALE_CCK_S 10
#define AR_PHY_TX_PWRCTRL9_RES_DC_REMOVAL 0x80000000
@@ -495,6 +499,8 @@
#define AR_PHY_CH0_TX_PWRCTRL11 0xa398
#define AR_PHY_CH1_TX_PWRCTRL11 0xb398
+#define AR_PHY_CH0_TX_PWRCTRL12 0xa3dc
+#define AR_PHY_CH0_TX_PWRCTRL13 0xa3e0
#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP 0x0000FC00
#define AR_PHY_TX_PWRCTRL_OLPC_TEMP_COMP_S 10
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
index 9ecca93392e8..e8ac70da5ac7 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 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
@@ -34,10 +34,10 @@ static const u32 ar9300_2p2_radio_postamble[][5] = {
static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
- {0x0000a2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800},
- {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000},
- {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000},
- {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+ {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+ {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+ {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
@@ -119,14 +119,14 @@ static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = {
{0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
{0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
{0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
- {0x0000b2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800},
- {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000},
- {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000},
- {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000c2dc, 0x00033800, 0x00033800, 0x00637800, 0x00637800},
- {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03838000, 0x03838000},
- {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03fc0000, 0x03fc0000},
- {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+ {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+ {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+ {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+ {0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+ {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+ {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+ {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
{0x00016048, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
@@ -835,10 +835,10 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
- {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
- {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
- {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
- {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+ {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+ {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+ {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
@@ -920,14 +920,14 @@ static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = {
{0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
{0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
{0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
- {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
- {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
- {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
- {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
- {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
- {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
- {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+ {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+ {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+ {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+ {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352},
+ {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584},
+ {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800},
+ {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
{0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
{0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
@@ -941,10 +941,10 @@ static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = {
static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
- {0x0000a2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800},
- {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000},
- {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000},
- {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
+ {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
+ {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
+ {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
{0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002},
@@ -1026,14 +1026,14 @@ static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = {
{0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
{0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
{0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005},
- {0x0000b2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800},
- {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000},
- {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000},
- {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000c2dc, 0x01feee00, 0x01feee00, 0x00637800, 0x00637800},
- {0x0000c2e0, 0x0000f000, 0x0000f000, 0x03838000, 0x03838000},
- {0x0000c2e4, 0x01ff0000, 0x01ff0000, 0x03fc0000, 0x03fc0000},
- {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
+ {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
+ {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
+ {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+ {0x0000c2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352},
+ {0x0000c2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584},
+ {0x0000c2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800},
+ {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
{0x00016048, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
@@ -1307,10 +1307,10 @@ static const u32 ar9300Common_rx_gain_table_2p2[][2] = {
static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
- {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
- {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
- {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
- {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+ {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+ {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+ {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
@@ -1329,21 +1329,21 @@ static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = {
{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},
+ {0x0000a544, 0x52022470, 0x52022470, 0x3f001861, 0x3f001861},
+ {0x0000a548, 0x55022490, 0x55022490, 0x43001a81, 0x43001a81},
+ {0x0000a54c, 0x59022492, 0x59022492, 0x47001a83, 0x47001a83},
+ {0x0000a550, 0x5d022692, 0x5d022692, 0x4a001c84, 0x4a001c84},
+ {0x0000a554, 0x61022892, 0x61022892, 0x4e001ce3, 0x4e001ce3},
+ {0x0000a558, 0x65024890, 0x65024890, 0x52001ce5, 0x52001ce5},
+ {0x0000a55c, 0x69024892, 0x69024892, 0x56001ce9, 0x56001ce9},
+ {0x0000a560, 0x6e024c92, 0x6e024c92, 0x5a001ceb, 0x5a001ceb},
+ {0x0000a564, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a568, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a56c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a570, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a574, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a578, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a57c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
@@ -1361,45 +1361,45 @@ static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = {
{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},
+ {0x0000a5c4, 0x52822470, 0x52822470, 0x3f801861, 0x3f801861},
+ {0x0000a5c8, 0x55822490, 0x55822490, 0x43801a81, 0x43801a81},
+ {0x0000a5cc, 0x59822492, 0x59822492, 0x47801a83, 0x47801a83},
+ {0x0000a5d0, 0x5d822692, 0x5d822692, 0x4a801c84, 0x4a801c84},
+ {0x0000a5d4, 0x61822892, 0x61822892, 0x4e801ce3, 0x4e801ce3},
+ {0x0000a5d8, 0x65824890, 0x65824890, 0x52801ce5, 0x52801ce5},
+ {0x0000a5dc, 0x69824892, 0x69824892, 0x56801ce9, 0x56801ce9},
+ {0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x5a801ceb, 0x5a801ceb},
+ {0x0000a5e4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5e8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5ec, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f0, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5fc, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000},
- {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501},
- {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501},
- {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03},
- {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
- {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04},
- {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005},
- {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
- {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
- {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
- {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005},
- {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
- {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
- {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
- {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x00637800, 0x00637800},
- {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03838000, 0x03838000},
- {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03fc0000, 0x03fc0000},
- {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a614, 0x02004000, 0x02004000, 0x01404000, 0x01404000},
+ {0x0000a618, 0x02004801, 0x02004801, 0x01404501, 0x01404501},
+ {0x0000a61c, 0x02808a02, 0x02808a02, 0x02008501, 0x02008501},
+ {0x0000a620, 0x0380ce03, 0x0380ce03, 0x0280ca03, 0x0280ca03},
+ {0x0000a624, 0x04411104, 0x04411104, 0x03010c04, 0x03010c04},
+ {0x0000a628, 0x04411104, 0x04411104, 0x04014c04, 0x04014c04},
+ {0x0000a62c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+ {0x0000a630, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+ {0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+ {0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+ {0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+ {0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+ {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+ {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+ {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
+ {0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+ {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+ {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
+ {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
{0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index 4a4cd88429c0..f48051c50092 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 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
@@ -18,13 +18,13 @@
#include "hw-ops.h"
#include "ar9003_phy.h"
-#define MPASS 3
#define MAX_MEASUREMENT 8
-#define MAX_DIFFERENCE 10
+#define MAX_MAG_DELTA 11
+#define MAX_PHS_DELTA 10
struct coeff {
- int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MPASS];
- int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT][MPASS];
+ int mag_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT];
+ int phs_coeff[AR9300_MAX_CHAINS][MAX_MEASUREMENT];
int iqc_coeff[2];
};
@@ -185,17 +185,19 @@ static void ar9003_hw_iqcal_collect(struct ath_hw *ah)
/* Accumulate IQ cal measures for active chains */
for (i = 0; i < AR5416_MAX_CHAINS; i++) {
- ah->totalPowerMeasI[i] +=
- REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
- ah->totalPowerMeasQ[i] +=
- REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
- ah->totalIqCorrMeas[i] +=
- (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
- ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
- "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
- ah->cal_samples, i, ah->totalPowerMeasI[i],
- ah->totalPowerMeasQ[i],
- ah->totalIqCorrMeas[i]);
+ if (ah->txchainmask & BIT(i)) {
+ ah->totalPowerMeasI[i] +=
+ REG_READ(ah, AR_PHY_CAL_MEAS_0(i));
+ ah->totalPowerMeasQ[i] +=
+ REG_READ(ah, AR_PHY_CAL_MEAS_1(i));
+ ah->totalIqCorrMeas[i] +=
+ (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i));
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_CALIBRATE,
+ "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n",
+ ah->cal_samples, i, ah->totalPowerMeasI[i],
+ ah->totalPowerMeasQ[i],
+ ah->totalIqCorrMeas[i]);
+ }
}
}
@@ -608,36 +610,48 @@ static bool ar9003_hw_calc_iq_corr(struct ath_hw *ah,
return true;
}
-static bool ar9003_hw_compute_closest_pass_and_avg(int *mp_coeff, int *mp_avg)
+static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,
+ int max_delta)
{
- int diff[MPASS];
-
- diff[0] = abs(mp_coeff[0] - mp_coeff[1]);
- diff[1] = abs(mp_coeff[1] - mp_coeff[2]);
- diff[2] = abs(mp_coeff[2] - mp_coeff[0]);
-
- if (diff[0] > MAX_DIFFERENCE &&
- diff[1] > MAX_DIFFERENCE &&
- diff[2] > MAX_DIFFERENCE)
- return false;
+ int mp_max = -64, max_idx = 0;
+ int mp_min = 63, min_idx = 0;
+ int mp_avg = 0, i, outlier_idx = 0;
+
+ /* find min/max mismatch across all calibrated gains */
+ for (i = 0; i < nmeasurement; i++) {
+ mp_avg += mp_coeff[i];
+ if (mp_coeff[i] > mp_max) {
+ mp_max = mp_coeff[i];
+ max_idx = i;
+ } else if (mp_coeff[i] < mp_min) {
+ mp_min = mp_coeff[i];
+ min_idx = i;
+ }
+ }
- if (diff[0] <= diff[1] && diff[0] <= diff[2])
- *mp_avg = (mp_coeff[0] + mp_coeff[1]) / 2;
- else if (diff[1] <= diff[2])
- *mp_avg = (mp_coeff[1] + mp_coeff[2]) / 2;
- else
- *mp_avg = (mp_coeff[2] + mp_coeff[0]) / 2;
+ /* find average (exclude max abs value) */
+ for (i = 0; i < nmeasurement; i++) {
+ if ((abs(mp_coeff[i]) < abs(mp_max)) ||
+ (abs(mp_coeff[i]) < abs(mp_min)))
+ mp_avg += mp_coeff[i];
+ }
+ mp_avg /= (nmeasurement - 1);
- return true;
+ /* detect outlier */
+ if (abs(mp_max - mp_min) > max_delta) {
+ if (abs(mp_max - mp_avg) > abs(mp_min - mp_avg))
+ outlier_idx = max_idx;
+ else
+ outlier_idx = min_idx;
+ }
+ mp_coeff[outlier_idx] = mp_avg;
}
static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
u8 num_chains,
struct coeff *coeff)
{
- struct ath_common *common = ath9k_hw_common(ah);
int i, im, nmeasurement;
- int magnitude, phase;
u32 tx_corr_coeff[MAX_MEASUREMENT][AR9300_MAX_CHAINS];
memset(tx_corr_coeff, 0, sizeof(tx_corr_coeff));
@@ -657,37 +671,28 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
/* Load the average of 2 passes */
for (i = 0; i < num_chains; i++) {
- if (AR_SREV_9485(ah))
- nmeasurement = REG_READ_FIELD(ah,
- AR_PHY_TX_IQCAL_STATUS_B0_9485,
- AR_PHY_CALIBRATED_GAINS_0);
- else
- nmeasurement = REG_READ_FIELD(ah,
- AR_PHY_TX_IQCAL_STATUS_B0,
- AR_PHY_CALIBRATED_GAINS_0);
+ nmeasurement = REG_READ_FIELD(ah,
+ AR_PHY_TX_IQCAL_STATUS_B0,
+ AR_PHY_CALIBRATED_GAINS_0);
if (nmeasurement > MAX_MEASUREMENT)
nmeasurement = MAX_MEASUREMENT;
- for (im = 0; im < nmeasurement; im++) {
- /*
- * Determine which 2 passes are closest and compute avg
- * magnitude
- */
- if (!ar9003_hw_compute_closest_pass_and_avg(coeff->mag_coeff[i][im],
- &magnitude))
- goto disable_txiqcal;
+ /* detect outlier only if nmeasurement > 1 */
+ if (nmeasurement > 1) {
+ /* Detect magnitude outlier */
+ ar9003_hw_detect_outlier(coeff->mag_coeff[i],
+ nmeasurement, MAX_MAG_DELTA);
- /*
- * Determine which 2 passes are closest and compute avg
- * phase
- */
- if (!ar9003_hw_compute_closest_pass_and_avg(coeff->phs_coeff[i][im],
- &phase))
- goto disable_txiqcal;
+ /* Detect phase outlier */
+ ar9003_hw_detect_outlier(coeff->phs_coeff[i],
+ nmeasurement, MAX_PHS_DELTA);
+ }
+
+ for (im = 0; im < nmeasurement; im++) {
- coeff->iqc_coeff[0] = (magnitude & 0x7f) |
- ((phase & 0x7f) << 7);
+ coeff->iqc_coeff[0] = (coeff->mag_coeff[i][im] & 0x7f) |
+ ((coeff->phs_coeff[i][im] & 0x7f) << 7);
if ((im % 2) == 0)
REG_RMW_FIELD(ah, tx_corr_coeff[im][i],
@@ -707,141 +712,37 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
return;
-disable_txiqcal:
- REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_3,
- AR_PHY_TX_IQCAL_CONTROL_3_IQCORR_EN, 0x0);
- REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,
- AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x0);
-
- ath_dbg(common, ATH_DBG_CALIBRATE, "TX IQ Cal disabled\n");
}
-static void ar9003_hw_tx_iq_cal(struct ath_hw *ah)
+static bool ar9003_hw_tx_iq_cal_run(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
- static const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
- AR_PHY_TX_IQCAL_STATUS_B0,
- AR_PHY_TX_IQCAL_STATUS_B1,
- AR_PHY_TX_IQCAL_STATUS_B2,
- };
- static const u32 chan_info_tab[] = {
- AR_PHY_CHAN_INFO_TAB_0,
- AR_PHY_CHAN_INFO_TAB_1,
- AR_PHY_CHAN_INFO_TAB_2,
- };
- struct coeff coeff;
- s32 iq_res[6];
- s32 i, j, ip, im, nmeasurement;
- u8 nchains = get_streams(common->tx_chainmask);
-
- for (ip = 0; ip < MPASS; ip++) {
- REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1,
- AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT,
- DELPT);
- REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START,
- AR_PHY_TX_IQCAL_START_DO_CAL,
- AR_PHY_TX_IQCAL_START_DO_CAL);
-
- if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START,
- AR_PHY_TX_IQCAL_START_DO_CAL,
- 0, AH_WAIT_TIMEOUT)) {
- ath_dbg(common, ATH_DBG_CALIBRATE,
- "Tx IQ Cal not complete.\n");
- goto TX_IQ_CAL_FAILED;
- }
-
- nmeasurement = REG_READ_FIELD(ah, AR_PHY_TX_IQCAL_STATUS_B0,
- AR_PHY_CALIBRATED_GAINS_0);
- if (nmeasurement > MAX_MEASUREMENT)
- nmeasurement = MAX_MEASUREMENT;
-
- for (i = 0; i < nchains; i++) {
- ath_dbg(common, ATH_DBG_CALIBRATE,
- "Doing Tx IQ Cal for chain %d.\n", i);
- for (im = 0; im < nmeasurement; im++) {
- if (REG_READ(ah, txiqcal_status[i]) &
- AR_PHY_TX_IQCAL_STATUS_FAILED) {
- ath_dbg(common, ATH_DBG_CALIBRATE,
- "Tx IQ Cal failed for chain %d.\n", i);
- goto TX_IQ_CAL_FAILED;
- }
-
- for (j = 0; j < 3; j++) {
- u8 idx = 2 * j,
- offset = 4 * (3 * im + j);
-
- REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,
- AR_PHY_CHAN_INFO_TAB_S2_READ,
- 0);
-
- /* 32 bits */
- iq_res[idx] = REG_READ(ah,
- chan_info_tab[i] +
- offset);
-
- REG_RMW_FIELD(ah, AR_PHY_CHAN_INFO_MEMORY,
- AR_PHY_CHAN_INFO_TAB_S2_READ,
- 1);
-
- /* 16 bits */
- iq_res[idx+1] = 0xffff & REG_READ(ah,
- chan_info_tab[i] +
- offset);
-
- ath_dbg(common, ATH_DBG_CALIBRATE,
- "IQ RES[%d]=0x%x IQ_RES[%d]=0x%x\n",
- idx, iq_res[idx], idx+1, iq_res[idx+1]);
- }
-
- if (!ar9003_hw_calc_iq_corr(ah, i, iq_res,
- coeff.iqc_coeff)) {
- ath_dbg(common, ATH_DBG_CALIBRATE,
- "Failed in calculation of IQ correction.\n");
- goto TX_IQ_CAL_FAILED;
- }
- coeff.mag_coeff[i][im][ip] =
- coeff.iqc_coeff[0] & 0x7f;
- coeff.phs_coeff[i][im][ip] =
- (coeff.iqc_coeff[0] >> 7) & 0x7f;
-
- if (coeff.mag_coeff[i][im][ip] > 63)
- coeff.mag_coeff[i][im][ip] -= 128;
- if (coeff.phs_coeff[i][im][ip] > 63)
- coeff.phs_coeff[i][im][ip] -= 128;
-
- }
- }
- }
-
- ar9003_hw_tx_iqcal_load_avg_2_passes(ah, nchains, &coeff);
-
- return;
-
-TX_IQ_CAL_FAILED:
- ath_dbg(common, ATH_DBG_CALIBRATE, "Tx IQ Cal failed\n");
-}
-
-static void ar9003_hw_tx_iq_cal_run(struct ath_hw *ah)
-{
u8 tx_gain_forced;
- REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1_9485,
- AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT, DELPT);
tx_gain_forced = REG_READ_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
AR_PHY_TXGAIN_FORCE);
if (tx_gain_forced)
REG_RMW_FIELD(ah, AR_PHY_TX_FORCED_GAIN,
AR_PHY_TXGAIN_FORCE, 0);
- REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START_9485,
- AR_PHY_TX_IQCAL_START_DO_CAL_9485, 1);
+ REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_START,
+ AR_PHY_TX_IQCAL_START_DO_CAL, 1);
+
+ if (!ath9k_hw_wait(ah, AR_PHY_TX_IQCAL_START,
+ AR_PHY_TX_IQCAL_START_DO_CAL, 0,
+ AH_WAIT_TIMEOUT)) {
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Tx IQ Cal is not completed.\n");
+ return false;
+ }
+ return true;
}
static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
const u32 txiqcal_status[AR9300_MAX_CHAINS] = {
- AR_PHY_TX_IQCAL_STATUS_B0_9485,
+ AR_PHY_TX_IQCAL_STATUS_B0,
AR_PHY_TX_IQCAL_STATUS_B1,
AR_PHY_TX_IQCAL_STATUS_B2,
};
@@ -853,7 +754,7 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah)
struct coeff coeff;
s32 iq_res[6];
u8 num_chains = 0;
- int i, ip, im, j;
+ int i, im, j;
int nmeasurement;
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
@@ -861,71 +762,69 @@ static void ar9003_hw_tx_iq_cal_post_proc(struct ath_hw *ah)
num_chains++;
}
- for (ip = 0; ip < MPASS; ip++) {
- for (i = 0; i < num_chains; i++) {
- nmeasurement = REG_READ_FIELD(ah,
- AR_PHY_TX_IQCAL_STATUS_B0_9485,
- AR_PHY_CALIBRATED_GAINS_0);
- if (nmeasurement > MAX_MEASUREMENT)
- nmeasurement = MAX_MEASUREMENT;
+ for (i = 0; i < num_chains; i++) {
+ nmeasurement = REG_READ_FIELD(ah,
+ AR_PHY_TX_IQCAL_STATUS_B0,
+ AR_PHY_CALIBRATED_GAINS_0);
+ if (nmeasurement > MAX_MEASUREMENT)
+ nmeasurement = MAX_MEASUREMENT;
- for (im = 0; im < nmeasurement; im++) {
- ath_dbg(common, ATH_DBG_CALIBRATE,
- "Doing Tx IQ Cal for chain %d.\n", i);
+ for (im = 0; im < nmeasurement; im++) {
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Doing Tx IQ Cal for chain %d.\n", i);
- if (REG_READ(ah, txiqcal_status[i]) &
- AR_PHY_TX_IQCAL_STATUS_FAILED) {
- ath_dbg(common, ATH_DBG_CALIBRATE,
+ if (REG_READ(ah, txiqcal_status[i]) &
+ AR_PHY_TX_IQCAL_STATUS_FAILED) {
+ ath_dbg(common, ATH_DBG_CALIBRATE,
"Tx IQ Cal failed for chain %d.\n", i);
- goto tx_iqcal_fail;
- }
+ goto tx_iqcal_fail;
+ }
- for (j = 0; j < 3; j++) {
- u32 idx = 2 * j, offset = 4 * (3 * im + j);
+ for (j = 0; j < 3; j++) {
+ u32 idx = 2 * j, offset = 4 * (3 * im + j);
- REG_RMW_FIELD(ah,
+ REG_RMW_FIELD(ah,
AR_PHY_CHAN_INFO_MEMORY,
AR_PHY_CHAN_INFO_TAB_S2_READ,
0);
- /* 32 bits */
- iq_res[idx] = REG_READ(ah,
- chan_info_tab[i] +
- offset);
+ /* 32 bits */
+ iq_res[idx] = REG_READ(ah,
+ chan_info_tab[i] +
+ offset);
- REG_RMW_FIELD(ah,
+ REG_RMW_FIELD(ah,
AR_PHY_CHAN_INFO_MEMORY,
AR_PHY_CHAN_INFO_TAB_S2_READ,
1);
- /* 16 bits */
- iq_res[idx + 1] = 0xffff & REG_READ(ah,
- chan_info_tab[i] + offset);
+ /* 16 bits */
+ iq_res[idx + 1] = 0xffff & REG_READ(ah,
+ chan_info_tab[i] + offset);
- ath_dbg(common, ATH_DBG_CALIBRATE,
- "IQ RES[%d]=0x%x"
- "IQ_RES[%d]=0x%x\n",
- idx, iq_res[idx], idx + 1,
- iq_res[idx + 1]);
- }
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "IQ RES[%d]=0x%x"
+ "IQ_RES[%d]=0x%x\n",
+ idx, iq_res[idx], idx + 1,
+ iq_res[idx + 1]);
+ }
- if (!ar9003_hw_calc_iq_corr(ah, i, iq_res,
- coeff.iqc_coeff)) {
- ath_dbg(common, ATH_DBG_CALIBRATE,
- "Failed in calculation of IQ correction.\n");
- goto tx_iqcal_fail;
- }
+ if (!ar9003_hw_calc_iq_corr(ah, i, iq_res,
+ coeff.iqc_coeff)) {
+ ath_dbg(common, ATH_DBG_CALIBRATE,
+ "Failed in calculation of \
+ IQ correction.\n");
+ goto tx_iqcal_fail;
+ }
- coeff.mag_coeff[i][im][ip] =
- coeff.iqc_coeff[0] & 0x7f;
- coeff.phs_coeff[i][im][ip] =
- (coeff.iqc_coeff[0] >> 7) & 0x7f;
+ coeff.mag_coeff[i][im] = coeff.iqc_coeff[0] & 0x7f;
+ coeff.phs_coeff[i][im] =
+ (coeff.iqc_coeff[0] >> 7) & 0x7f;
- if (coeff.mag_coeff[i][im][ip] > 63)
- coeff.mag_coeff[i][im][ip] -= 128;
- if (coeff.phs_coeff[i][im][ip] > 63)
- coeff.phs_coeff[i][im][ip] -= 128;
- }
+ if (coeff.mag_coeff[i][im] > 63)
+ coeff.mag_coeff[i][im] -= 128;
+ if (coeff.phs_coeff[i][im] > 63)
+ coeff.phs_coeff[i][im] -= 128;
}
}
ar9003_hw_tx_iqcal_load_avg_2_passes(ah, num_chains, &coeff);
@@ -940,31 +839,37 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
struct ath9k_channel *chan)
{
struct ath_common *common = ath9k_hw_common(ah);
+ struct ath9k_hw_capabilities *pCap = &ah->caps;
int val;
+ bool txiqcal_done = false;
val = REG_READ(ah, AR_ENT_OTP);
ath_dbg(common, ATH_DBG_CALIBRATE, "ath9k: AR_ENT_OTP 0x%x\n", val);
- if (AR_SREV_9485(ah))
- ar9003_hw_set_chain_masks(ah, 0x1, 0x1);
- else if (val & AR_ENT_OTP_CHAIN2_DISABLE)
+ /* Configure rx/tx chains before running AGC/TxiQ cals */
+ if (val & AR_ENT_OTP_CHAIN2_DISABLE)
ar9003_hw_set_chain_masks(ah, 0x3, 0x3);
else
- /*
- * 0x7 = 0b111 , AR9003 needs to be configured for 3-chain
- * mode before running AGC/TxIQ cals
- */
- ar9003_hw_set_chain_masks(ah, 0x7, 0x7);
+ ar9003_hw_set_chain_masks(ah, pCap->rx_chainmask,
+ pCap->tx_chainmask);
/* Do Tx IQ Calibration */
- if (AR_SREV_9485(ah))
- ar9003_hw_tx_iq_cal_run(ah);
- else
- ar9003_hw_tx_iq_cal(ah);
+ REG_RMW_FIELD(ah, AR_PHY_TX_IQCAL_CONTROL_1,
+ AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT,
+ DELPT);
- REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
- udelay(5);
- REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+ /*
+ * For AR9485 or later chips, TxIQ cal runs as part of
+ * AGC calibration
+ */
+ if (AR_SREV_9485_OR_LATER(ah))
+ txiqcal_done = true;
+ else {
+ txiqcal_done = ar9003_hw_tx_iq_cal_run(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,
@@ -979,7 +884,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
return false;
}
- if (AR_SREV_9485(ah))
+ if (txiqcal_done)
ar9003_hw_tx_iq_cal_post_proc(ah);
/* Revert chainmasks to their original values before NF cal */
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index 6eadf975ae48..0ca7635d0669 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 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
@@ -652,7 +652,7 @@ static const struct ar9300_eeprom ar9300_x113 = {
.regDmn = { LE16(0), LE16(0x1f) },
.txrxMask = 0x77, /* 4 bits tx and 4 bits rx */
.opCapFlags = {
- .opFlags = AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A,
+ .opFlags = AR5416_OPFLAGS_11A,
.eepMisc = 0,
},
.rfSilent = 0,
@@ -922,7 +922,7 @@ static const struct ar9300_eeprom ar9300_x113 = {
.db_stage2 = {3, 3, 3}, /* 3 chain */
.db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
.db_stage4 = {3, 3, 3}, /* don't exist for 2G */
- .xpaBiasLvl = 0,
+ .xpaBiasLvl = 0xf,
.txFrameToDataStart = 0x0e,
.txFrameToPaOn = 0x0e,
.txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */
@@ -3217,7 +3217,6 @@ static int ar9300_compress_decision(struct ath_hw *ah,
u8 *word, int length, int mdata_size)
{
struct ath_common *common = ath9k_hw_common(ah);
- u8 *dptr;
const struct ar9300_eeprom *eep = NULL;
switch (code) {
@@ -3235,7 +3234,6 @@ static int ar9300_compress_decision(struct ath_hw *ah,
break;
case _CompressBlock:
if (reference == 0) {
- dptr = mptr;
} else {
eep = ar9003_eeprom_struct_find_by_id(reference);
if (eep == NULL) {
@@ -3329,26 +3327,26 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah,
else
cptr = AR9300_BASE_ADDR;
ath_dbg(common, ATH_DBG_EEPROM,
- "Trying EEPROM accesss at Address 0x%04x\n", cptr);
+ "Trying EEPROM access at Address 0x%04x\n", cptr);
if (ar9300_check_eeprom_header(ah, read, cptr))
goto found;
cptr = AR9300_BASE_ADDR_512;
ath_dbg(common, ATH_DBG_EEPROM,
- "Trying EEPROM accesss at Address 0x%04x\n", cptr);
+ "Trying EEPROM access at Address 0x%04x\n", cptr);
if (ar9300_check_eeprom_header(ah, read, cptr))
goto found;
read = ar9300_read_otp;
cptr = AR9300_BASE_ADDR;
ath_dbg(common, ATH_DBG_EEPROM,
- "Trying OTP accesss at Address 0x%04x\n", cptr);
+ "Trying OTP access at Address 0x%04x\n", cptr);
if (ar9300_check_eeprom_header(ah, read, cptr))
goto found;
cptr = AR9300_BASE_ADDR_512;
ath_dbg(common, ATH_DBG_EEPROM,
- "Trying OTP accesss at Address 0x%04x\n", cptr);
+ "Trying OTP access at Address 0x%04x\n", cptr);
if (ar9300_check_eeprom_header(ah, read, cptr))
goto found;
@@ -3444,13 +3442,15 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz)
{
int bias = ar9003_hw_xpa_bias_level_get(ah, is2ghz);
- if (AR_SREV_9485(ah))
+ if (AR_SREV_9485(ah) || AR_SREV_9340(ah))
REG_RMW_FIELD(ah, AR_CH0_TOP2, AR_CH0_TOP2_XPABIASLVL, bias);
else {
REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias);
- REG_RMW_FIELD(ah, AR_CH0_THERM, AR_CH0_THERM_XPABIASLVL_MSB,
- bias >> 2);
- REG_RMW_FIELD(ah, AR_CH0_THERM, AR_CH0_THERM_XPASHORT2GND, 1);
+ REG_RMW_FIELD(ah, AR_CH0_THERM,
+ AR_CH0_THERM_XPABIASLVL_MSB,
+ bias >> 2);
+ REG_RMW_FIELD(ah, AR_CH0_THERM,
+ AR_CH0_THERM_XPASHORT2GND, 1);
}
}
@@ -3497,34 +3497,77 @@ static u16 ar9003_hw_ant_ctrl_chain_get(struct ath_hw *ah,
static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
{
+ int chain;
+ u32 regval;
+ u32 ant_div_ctl1;
+ static const u32 switch_chain_reg[AR9300_MAX_CHAINS] = {
+ AR_PHY_SWITCH_CHAIN_0,
+ AR_PHY_SWITCH_CHAIN_1,
+ AR_PHY_SWITCH_CHAIN_2,
+ };
+
u32 value = ar9003_hw_ant_ctrl_common_get(ah, is2ghz);
+
REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, AR_SWITCH_TABLE_COM_ALL, value);
value = ar9003_hw_ant_ctrl_common_2_get(ah, is2ghz);
REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM_2, AR_SWITCH_TABLE_COM2_ALL, value);
- value = ar9003_hw_ant_ctrl_chain_get(ah, 0, is2ghz);
- REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_0, AR_SWITCH_TABLE_ALL, value);
-
- if (!AR_SREV_9485(ah)) {
- value = ar9003_hw_ant_ctrl_chain_get(ah, 1, is2ghz);
- REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_1, AR_SWITCH_TABLE_ALL,
- value);
-
- value = ar9003_hw_ant_ctrl_chain_get(ah, 2, is2ghz);
- REG_RMW_FIELD(ah, AR_PHY_SWITCH_CHAIN_2, AR_SWITCH_TABLE_ALL,
- value);
+ for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
+ if ((ah->rxchainmask & BIT(chain)) ||
+ (ah->txchainmask & BIT(chain))) {
+ value = ar9003_hw_ant_ctrl_chain_get(ah, chain,
+ is2ghz);
+ REG_RMW_FIELD(ah, switch_chain_reg[chain],
+ AR_SWITCH_TABLE_ALL, value);
+ }
}
if (AR_SREV_9485(ah)) {
value = ath9k_hw_ar9300_get_eeprom(ah, EEP_ANT_DIV_CTL1);
- REG_RMW_FIELD(ah, AR_PHY_MC_GAIN_CTRL, AR_ANT_DIV_CTRL_ALL,
- value);
- REG_RMW_FIELD(ah, AR_PHY_MC_GAIN_CTRL, AR_ANT_DIV_ENABLE,
- value >> 6);
- REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, AR_FAST_DIV_ENABLE,
- value >> 7);
+ /*
+ * main_lnaconf, alt_lnaconf, main_tb, alt_tb
+ * are the fields present
+ */
+ regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
+ regval &= (~AR_ANT_DIV_CTRL_ALL);
+ regval |= (value & 0x3f) << AR_ANT_DIV_CTRL_ALL_S;
+ /* enable_lnadiv */
+ regval &= (~AR_PHY_9485_ANT_DIV_LNADIV);
+ regval |= ((value >> 6) & 0x1) <<
+ AR_PHY_9485_ANT_DIV_LNADIV_S;
+ REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
+
+ /*enable fast_div */
+ regval = REG_READ(ah, AR_PHY_CCK_DETECT);
+ regval &= (~AR_FAST_DIV_ENABLE);
+ regval |= ((value >> 7) & 0x1) <<
+ AR_FAST_DIV_ENABLE_S;
+ REG_WRITE(ah, AR_PHY_CCK_DETECT, regval);
+ ant_div_ctl1 =
+ ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1);
+ /* check whether antenna diversity is enabled */
+ if ((ant_div_ctl1 >> 0x6) == 0x3) {
+ regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
+ /*
+ * clear bits 25-30 main_lnaconf, alt_lnaconf,
+ * main_tb, alt_tb
+ */
+ regval &= (~(AR_PHY_9485_ANT_DIV_MAIN_LNACONF |
+ AR_PHY_9485_ANT_DIV_ALT_LNACONF |
+ AR_PHY_9485_ANT_DIV_ALT_GAINTB |
+ AR_PHY_9485_ANT_DIV_MAIN_GAINTB));
+ /* by default use LNA1 for the main antenna */
+ regval |= (AR_PHY_9485_ANT_DIV_LNA1 <<
+ AR_PHY_9485_ANT_DIV_MAIN_LNACONF_S);
+ regval |= (AR_PHY_9485_ANT_DIV_LNA2 <<
+ AR_PHY_9485_ANT_DIV_ALT_LNACONF_S);
+ REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
+ }
+
+
}
+
}
static void ar9003_hw_drive_strength_apply(struct ath_hw *ah)
@@ -3634,13 +3677,16 @@ static void ar9003_hw_atten_apply(struct ath_hw *ah, struct ath9k_channel *chan)
/* Test value. if 0 then attenuation is unused. Don't load anything. */
for (i = 0; i < 3; i++) {
- value = ar9003_hw_atten_chain_get(ah, i, chan);
- REG_RMW_FIELD(ah, ext_atten_reg[i],
- AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value);
-
- value = ar9003_hw_atten_chain_get_margin(ah, i, chan);
- REG_RMW_FIELD(ah, ext_atten_reg[i],
- AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN, value);
+ if (ah->txchainmask & BIT(i)) {
+ value = ar9003_hw_atten_chain_get(ah, i, chan);
+ REG_RMW_FIELD(ah, ext_atten_reg[i],
+ AR_PHY_EXT_ATTEN_CTL_XATTEN1_DB, value);
+
+ value = ar9003_hw_atten_chain_get_margin(ah, i, chan);
+ REG_RMW_FIELD(ah, ext_atten_reg[i],
+ AR_PHY_EXT_ATTEN_CTL_XATTEN1_MARGIN,
+ value);
+ }
}
}
@@ -3749,8 +3795,9 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah,
ar9003_hw_ant_ctrl_apply(ah, IS_CHAN_2GHZ(chan));
ar9003_hw_drive_strength_apply(ah);
ar9003_hw_atten_apply(ah, chan);
- ar9003_hw_internal_regulator_apply(ah);
- if (AR_SREV_9485(ah))
+ if (!AR_SREV_9340(ah))
+ ar9003_hw_internal_regulator_apply(ah);
+ if (AR_SREV_9485(ah) || AR_SREV_9340(ah))
ar9003_hw_apply_tuning_caps(ah);
}
@@ -3994,6 +4041,16 @@ static int ar9003_hw_tx_power_regwrite(struct ath_hw *ah, u8 * pPwrArray)
POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 0)
);
+ /* Write the power for duplicated frames - HT40 */
+
+ /* dup40_cck (LSB), dup40_ofdm, ext20_cck, ext20_ofdm (MSB) */
+ REG_WRITE(ah, 0xa3e0,
+ POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 24) |
+ POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 16) |
+ POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 8) |
+ POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 0)
+ );
+
/* Write the HT20 power per rate set */
/* 0/8/16 (LSB), 1-3/9-11/17-19, 4, 5 (MSB) */
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
index afb0b5ee1865..ab21a4915981 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
@@ -1,3 +1,19 @@
+/*
+ * Copyright (c) 2010-2011 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 AR9003_EEPROM_H
#define AR9003_EEPROM_H
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
index 7f5de6e4448b..392bf0f8ff16 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -18,6 +18,7 @@
#include "ar9003_mac.h"
#include "ar9003_2p2_initvals.h"
#include "ar9485_initvals.h"
+#include "ar9340_initvals.h"
/* General hardware code for the AR9003 hadware family */
@@ -28,109 +29,105 @@
*/
static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
{
- if (AR_SREV_9485_11(ah)) {
+ if (AR_SREV_9340(ah)) {
/* mac */
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
- ar9485_1_1_mac_core,
- ARRAY_SIZE(ar9485_1_1_mac_core), 2);
+ ar9340_1p0_mac_core,
+ ARRAY_SIZE(ar9340_1p0_mac_core), 2);
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
- ar9485_1_1_mac_postamble,
- ARRAY_SIZE(ar9485_1_1_mac_postamble), 5);
+ ar9340_1p0_mac_postamble,
+ ARRAY_SIZE(ar9340_1p0_mac_postamble), 5);
/* bb */
- INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], ar9485_1_1,
- ARRAY_SIZE(ar9485_1_1), 2);
+ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0);
INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
- ar9485_1_1_baseband_core,
- ARRAY_SIZE(ar9485_1_1_baseband_core), 2);
+ ar9340_1p0_baseband_core,
+ ARRAY_SIZE(ar9340_1p0_baseband_core), 2);
INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
- ar9485_1_1_baseband_postamble,
- ARRAY_SIZE(ar9485_1_1_baseband_postamble), 5);
+ ar9340_1p0_baseband_postamble,
+ ARRAY_SIZE(ar9340_1p0_baseband_postamble), 5);
/* radio */
INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0);
INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
- ar9485_1_1_radio_core,
- ARRAY_SIZE(ar9485_1_1_radio_core), 2);
+ ar9340_1p0_radio_core,
+ ARRAY_SIZE(ar9340_1p0_radio_core), 2);
INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
- ar9485_1_1_radio_postamble,
- ARRAY_SIZE(ar9485_1_1_radio_postamble), 2);
+ ar9340_1p0_radio_postamble,
+ ARRAY_SIZE(ar9340_1p0_radio_postamble), 5);
/* soc */
INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
- ar9485_1_1_soc_preamble,
- ARRAY_SIZE(ar9485_1_1_soc_preamble), 2);
+ ar9340_1p0_soc_preamble,
+ ARRAY_SIZE(ar9340_1p0_soc_preamble), 2);
INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0);
- INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], NULL, 0, 0);
+ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
+ ar9340_1p0_soc_postamble,
+ ARRAY_SIZE(ar9340_1p0_soc_postamble), 5);
/* rx/tx gain */
INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9485_common_rx_gain_1_1,
- ARRAY_SIZE(ar9485_common_rx_gain_1_1), 2);
+ ar9340Common_wo_xlna_rx_gain_table_1p0,
+ ARRAY_SIZE(ar9340Common_wo_xlna_rx_gain_table_1p0),
+ 5);
INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9485_modes_lowest_ob_db_tx_gain_1_1,
- ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1),
+ ar9340Modes_high_ob_db_tx_gain_table_1p0,
+ ARRAY_SIZE(ar9340Modes_high_ob_db_tx_gain_table_1p0),
5);
- /* Load PCIE SERDES settings from INI */
-
- /* Awake Setting */
-
- INIT_INI_ARRAY(&ah->iniPcieSerdes,
- ar9485_1_1_pcie_phy_clkreq_disable_L1,
- ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1),
- 2);
-
- /* Sleep Setting */
+ INIT_INI_ARRAY(&ah->iniModesAdditional,
+ ar9340Modes_fast_clock_1p0,
+ ARRAY_SIZE(ar9340Modes_fast_clock_1p0),
+ 3);
- INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
- ar9485_1_1_pcie_phy_clkreq_disable_L1,
- ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1),
+ INIT_INI_ARRAY(&ah->iniModesAdditional_40M,
+ ar9340_1p0_radio_core_40M,
+ ARRAY_SIZE(ar9340_1p0_radio_core_40M),
2);
- } else if (AR_SREV_9485(ah)) {
+ } else if (AR_SREV_9485_11(ah)) {
/* mac */
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
- ar9485_1_0_mac_core,
- ARRAY_SIZE(ar9485_1_0_mac_core), 2);
+ ar9485_1_1_mac_core,
+ ARRAY_SIZE(ar9485_1_1_mac_core), 2);
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
- ar9485_1_0_mac_postamble,
- ARRAY_SIZE(ar9485_1_0_mac_postamble), 5);
+ ar9485_1_1_mac_postamble,
+ ARRAY_SIZE(ar9485_1_1_mac_postamble), 5);
/* bb */
- INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], ar9485_1_0,
- ARRAY_SIZE(ar9485_1_0), 2);
+ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], ar9485_1_1,
+ ARRAY_SIZE(ar9485_1_1), 2);
INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
- ar9485_1_0_baseband_core,
- ARRAY_SIZE(ar9485_1_0_baseband_core), 2);
+ ar9485_1_1_baseband_core,
+ ARRAY_SIZE(ar9485_1_1_baseband_core), 2);
INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
- ar9485_1_0_baseband_postamble,
- ARRAY_SIZE(ar9485_1_0_baseband_postamble), 5);
+ ar9485_1_1_baseband_postamble,
+ ARRAY_SIZE(ar9485_1_1_baseband_postamble), 5);
/* radio */
INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0);
INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
- ar9485_1_0_radio_core,
- ARRAY_SIZE(ar9485_1_0_radio_core), 2);
+ ar9485_1_1_radio_core,
+ ARRAY_SIZE(ar9485_1_1_radio_core), 2);
INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
- ar9485_1_0_radio_postamble,
- ARRAY_SIZE(ar9485_1_0_radio_postamble), 2);
+ ar9485_1_1_radio_postamble,
+ ARRAY_SIZE(ar9485_1_1_radio_postamble), 2);
/* soc */
INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
- ar9485_1_0_soc_preamble,
- ARRAY_SIZE(ar9485_1_0_soc_preamble), 2);
+ ar9485_1_1_soc_preamble,
+ ARRAY_SIZE(ar9485_1_1_soc_preamble), 2);
INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0);
INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], NULL, 0, 0);
/* rx/tx gain */
INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9485Common_rx_gain_1_0,
- ARRAY_SIZE(ar9485Common_rx_gain_1_0), 2);
+ ar9485Common_wo_xlna_rx_gain_1_1,
+ ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), 2);
INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9485Modes_lowest_ob_db_tx_gain_1_0,
- ARRAY_SIZE(ar9485Modes_lowest_ob_db_tx_gain_1_0),
+ ar9485_modes_lowest_ob_db_tx_gain_1_1,
+ ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1),
5);
/* Load PCIE SERDES settings from INI */
@@ -138,15 +135,15 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
/* Awake Setting */
INIT_INI_ARRAY(&ah->iniPcieSerdes,
- ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1,
- ARRAY_SIZE(ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1),
+ ar9485_1_1_pcie_phy_clkreq_disable_L1,
+ ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1),
2);
/* Sleep Setting */
INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
- ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1,
- ARRAY_SIZE(ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1),
+ ar9485_1_1_pcie_phy_clkreq_disable_L1,
+ ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1),
2);
} else {
/* mac */
@@ -223,15 +220,15 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
switch (ar9003_hw_get_tx_gain_idx(ah)) {
case 0:
default:
- if (AR_SREV_9485_11(ah))
+ if (AR_SREV_9340(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9485_modes_lowest_ob_db_tx_gain_1_1,
- ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1),
+ ar9340Modes_lowest_ob_db_tx_gain_table_1p0,
+ ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0),
5);
- else if (AR_SREV_9485(ah))
+ else if (AR_SREV_9485_11(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9485Modes_lowest_ob_db_tx_gain_1_0,
- ARRAY_SIZE(ar9485Modes_lowest_ob_db_tx_gain_1_0),
+ ar9485_modes_lowest_ob_db_tx_gain_1_1,
+ ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1),
5);
else
INIT_INI_ARRAY(&ah->iniModesTxGain,
@@ -240,15 +237,15 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
5);
break;
case 1:
- if (AR_SREV_9485_11(ah))
+ if (AR_SREV_9340(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9485Modes_high_ob_db_tx_gain_1_1,
- ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_1),
+ ar9340Modes_lowest_ob_db_tx_gain_table_1p0,
+ ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0),
5);
- else if (AR_SREV_9485(ah))
+ else if (AR_SREV_9485_11(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9485Modes_high_ob_db_tx_gain_1_0,
- ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_0),
+ ar9485Modes_high_ob_db_tx_gain_1_1,
+ ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_1),
5);
else
INIT_INI_ARRAY(&ah->iniModesTxGain,
@@ -257,15 +254,15 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
5);
break;
case 2:
- if (AR_SREV_9485_11(ah))
+ if (AR_SREV_9340(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9485Modes_low_ob_db_tx_gain_1_1,
- ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_1),
+ ar9340Modes_lowest_ob_db_tx_gain_table_1p0,
+ ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0),
5);
- else if (AR_SREV_9485(ah))
+ else if (AR_SREV_9485_11(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9485Modes_low_ob_db_tx_gain_1_0,
- ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_0),
+ ar9485Modes_low_ob_db_tx_gain_1_1,
+ ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_1),
5);
else
INIT_INI_ARRAY(&ah->iniModesTxGain,
@@ -274,15 +271,15 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
5);
break;
case 3:
- if (AR_SREV_9485_11(ah))
+ if (AR_SREV_9340(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9485Modes_high_power_tx_gain_1_1,
- ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_1),
+ ar9340Modes_lowest_ob_db_tx_gain_table_1p0,
+ ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0),
5);
- else if (AR_SREV_9485(ah))
+ else if (AR_SREV_9485_11(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9485Modes_high_power_tx_gain_1_0,
- ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_0),
+ ar9485Modes_high_power_tx_gain_1_1,
+ ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_1),
5);
else
INIT_INI_ARRAY(&ah->iniModesTxGain,
@@ -298,15 +295,15 @@ static void ar9003_rx_gain_table_apply(struct ath_hw *ah)
switch (ar9003_hw_get_rx_gain_idx(ah)) {
case 0:
default:
- if (AR_SREV_9485_11(ah))
+ if (AR_SREV_9340(ah))
INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9485_common_rx_gain_1_1,
- ARRAY_SIZE(ar9485_common_rx_gain_1_1),
+ ar9340Common_rx_gain_table_1p0,
+ ARRAY_SIZE(ar9340Common_rx_gain_table_1p0),
2);
- else if (AR_SREV_9485(ah))
+ else if (AR_SREV_9485_11(ah))
INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9485Common_rx_gain_1_0,
- ARRAY_SIZE(ar9485Common_rx_gain_1_0),
+ ar9485Common_wo_xlna_rx_gain_1_1,
+ ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1),
2);
else
INIT_INI_ARRAY(&ah->iniModesRxGain,
@@ -315,15 +312,15 @@ static void ar9003_rx_gain_table_apply(struct ath_hw *ah)
2);
break;
case 1:
- if (AR_SREV_9485_11(ah))
+ if (AR_SREV_9340(ah))
INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9485Common_wo_xlna_rx_gain_1_1,
- ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1),
+ ar9340Common_wo_xlna_rx_gain_table_1p0,
+ ARRAY_SIZE(ar9340Common_wo_xlna_rx_gain_table_1p0),
2);
- else if (AR_SREV_9485(ah))
+ else if (AR_SREV_9485_11(ah))
INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9485Common_wo_xlna_rx_gain_1_0,
- ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_0),
+ ar9485Common_wo_xlna_rx_gain_1_1,
+ ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1),
2);
else
INIT_INI_ARRAY(&ah->iniModesRxGain,
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
index 038a0cbfc6e7..10d71f7d3fc2 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 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
@@ -329,7 +329,6 @@ static void ar9003_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
| (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0)
| SM(txpower, AR_XmitPower)
| (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0)
- | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0)
| (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0)
| (flags & ATH9K_TXDESC_LOWRXCHAIN ? AR_LowRxChain : 0);
@@ -350,6 +349,16 @@ static void ar9003_hw_set11n_txdesc(struct ath_hw *ah, void *ds,
ads->ctl22 = 0;
}
+static void ar9003_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
+{
+ struct ar9003_txc *ads = (struct ar9003_txc *) ds;
+
+ if (val)
+ ads->ctl11 |= AR_ClrDestMask;
+ else
+ ads->ctl11 &= ~AR_ClrDestMask;
+}
+
static void ar9003_hw_set11n_ratescenario(struct ath_hw *ah, void *ds,
void *lastds,
u32 durUpdateEn, u32 rtsctsRate,
@@ -475,27 +484,6 @@ static void ar9003_hw_clr11n_aggr(struct ath_hw *ah, void *ds)
ads->ctl12 &= (~AR_IsAggr & ~AR_MoreAggr);
}
-static void ar9003_hw_set11n_burstduration(struct ath_hw *ah, void *ds,
- u32 burstDuration)
-{
- struct ar9003_txc *ads = (struct ar9003_txc *) ds;
-
- ads->ctl13 &= ~AR_BurstDur;
- ads->ctl13 |= SM(burstDuration, AR_BurstDur);
-
-}
-
-static void ar9003_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds,
- u32 vmf)
-{
- struct ar9003_txc *ads = (struct ar9003_txc *) ds;
-
- if (vmf)
- ads->ctl11 |= AR_VirtMoreFrag;
- else
- ads->ctl11 &= ~AR_VirtMoreFrag;
-}
-
void ar9003_hw_set_paprd_txdesc(struct ath_hw *ah, void *ds, u8 chains)
{
struct ar9003_txc *ads = ds;
@@ -520,8 +508,7 @@ void ar9003_hw_attach_mac_ops(struct ath_hw *hw)
ops->set11n_aggr_middle = ar9003_hw_set11n_aggr_middle;
ops->set11n_aggr_last = ar9003_hw_set11n_aggr_last;
ops->clr11n_aggr = ar9003_hw_clr11n_aggr;
- ops->set11n_burstduration = ar9003_hw_set11n_burstduration;
- ops->set11n_virtualmorefrag = ar9003_hw_set11n_virtualmorefrag;
+ ops->set_clrdmask = ar9003_hw_set_clrdmask;
}
void ath9k_hw_set_rx_bufsize(struct ath_hw *ah, u16 buf_size)
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.h b/drivers/net/wireless/ath/ath9k/ar9003_mac.h
index 45cc7e80436c..c50449387bf1 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 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
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
index 356d2fd78822..e4d6a87ec538 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 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
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index eb250d6b8038..eee23ecd118a 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 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
@@ -75,16 +75,42 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
freq = centers.synth_center;
if (freq < 4800) { /* 2 GHz, fractional mode */
- if (AR_SREV_9485(ah))
- channelSel = CHANSEL_2G_9485(freq);
- else
+ if (AR_SREV_9485(ah)) {
+ u32 chan_frac;
+
+ /*
+ * freq_ref = 40 / (refdiva >> amoderefsel); where refdiva=1 and amoderefsel=0
+ * ndiv = ((chan_mhz * 4) / 3) / freq_ref;
+ * chansel = int(ndiv), chanfrac = (ndiv - chansel) * 0x20000
+ */
+ channelSel = (freq * 4) / 120;
+ chan_frac = (((freq * 4) % 120) * 0x20000) / 120;
+ channelSel = (channelSel << 17) | chan_frac;
+ } else if (AR_SREV_9340(ah)) {
+ if (ah->is_clk_25mhz) {
+ u32 chan_frac;
+
+ channelSel = (freq * 2) / 75;
+ chan_frac = (((freq * 2) % 75) * 0x20000) / 75;
+ channelSel = (channelSel << 17) | chan_frac;
+ } else
+ channelSel = CHANSEL_2G(freq) >> 1;
+ } else
channelSel = CHANSEL_2G(freq);
/* Set to 2G mode */
bMode = 1;
} else {
- channelSel = CHANSEL_5G(freq);
- /* Doubler is ON, so, divide channelSel by 2. */
- channelSel >>= 1;
+ if (AR_SREV_9340(ah) && ah->is_clk_25mhz) {
+ u32 chan_frac;
+
+ channelSel = (freq * 2) / 75;
+ chan_frac = ((freq % 75) * 0x20000) / 75;
+ channelSel = (channelSel << 17) | chan_frac;
+ } else {
+ channelSel = CHANSEL_5G(freq);
+ /* Doubler is ON, so, divide channelSel by 2. */
+ channelSel >>= 1;
+ }
/* Set to 5G mode */
bMode = 0;
}
@@ -142,7 +168,7 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah,
* is out-of-band and can be ignored.
*/
- if (AR_SREV_9485(ah)) {
+ if (AR_SREV_9485(ah) || AR_SREV_9340(ah)) {
spur_fbin_ptr = ar9003_get_spur_chan_ptr(ah,
IS_CHAN_2GHZ(chan));
if (spur_fbin_ptr[0] == 0) /* No spur */
@@ -167,7 +193,7 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah,
for (i = 0; i < max_spur_cnts; i++) {
negative = 0;
- if (AR_SREV_9485(ah))
+ if (AR_SREV_9485(ah) || AR_SREV_9340(ah))
cur_bb_spur = FBIN2FREQ(spur_fbin_ptr[i],
IS_CHAN_2GHZ(chan)) - synth_freq;
else
@@ -401,7 +427,7 @@ static void ar9003_hw_spur_mitigate_ofdm(struct ath_hw *ah,
ar9003_hw_spur_ofdm_clear(ah);
- for (i = 0; spurChansPtr[i] && i < 5; i++) {
+ for (i = 0; i < AR_EEPROM_MODAL_SPURS && spurChansPtr[i]; i++) {
freq_offset = FBIN2FREQ(spurChansPtr[i], mode) - synth_freq;
if (abs(freq_offset) < range) {
ar9003_hw_spur_ofdm_work(ah, chan, freq_offset);
@@ -590,29 +616,25 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
unsigned int regWrites = 0, i;
struct ieee80211_channel *channel = chan->chan;
- u32 modesIndex, freqIndex;
+ u32 modesIndex;
switch (chan->chanmode) {
case CHANNEL_A:
case CHANNEL_A_HT20:
modesIndex = 1;
- freqIndex = 1;
break;
case CHANNEL_A_HT40PLUS:
case CHANNEL_A_HT40MINUS:
modesIndex = 2;
- freqIndex = 1;
break;
case CHANNEL_G:
case CHANNEL_G_HT20:
case CHANNEL_B:
modesIndex = 4;
- freqIndex = 2;
break;
case CHANNEL_G_HT40PLUS:
case CHANNEL_G_HT40MINUS:
modesIndex = 3;
- freqIndex = 2;
break;
default:
@@ -637,6 +659,9 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
REG_WRITE_ARRAY(&ah->iniModesAdditional,
modesIndex, regWrites);
+ if (AR_SREV_9340(ah) && !ah->is_clk_25mhz)
+ REG_WRITE_ARRAY(&ah->iniModesAdditional_40M, 1, regWrites);
+
ar9003_hw_override_ini(ah);
ar9003_hw_set_channel_regs(ah, chan);
ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
@@ -1159,9 +1184,52 @@ static void ar9003_hw_set_radar_conf(struct ath_hw *ah)
conf->radar_inband = 8;
}
+static void ar9003_hw_antdiv_comb_conf_get(struct ath_hw *ah,
+ struct ath_hw_antcomb_conf *antconf)
+{
+ u32 regval;
+
+ regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
+ antconf->main_lna_conf = (regval & AR_PHY_9485_ANT_DIV_MAIN_LNACONF) >>
+ AR_PHY_9485_ANT_DIV_MAIN_LNACONF_S;
+ antconf->alt_lna_conf = (regval & AR_PHY_9485_ANT_DIV_ALT_LNACONF) >>
+ AR_PHY_9485_ANT_DIV_ALT_LNACONF_S;
+ antconf->fast_div_bias = (regval & AR_PHY_9485_ANT_FAST_DIV_BIAS) >>
+ AR_PHY_9485_ANT_FAST_DIV_BIAS_S;
+ antconf->lna1_lna2_delta = -9;
+ antconf->div_group = 2;
+}
+
+static void ar9003_hw_antdiv_comb_conf_set(struct ath_hw *ah,
+ struct ath_hw_antcomb_conf *antconf)
+{
+ u32 regval;
+
+ regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
+ regval &= ~(AR_PHY_9485_ANT_DIV_MAIN_LNACONF |
+ AR_PHY_9485_ANT_DIV_ALT_LNACONF |
+ AR_PHY_9485_ANT_FAST_DIV_BIAS |
+ AR_PHY_9485_ANT_DIV_MAIN_GAINTB |
+ AR_PHY_9485_ANT_DIV_ALT_GAINTB);
+ regval |= ((antconf->main_lna_conf <<
+ AR_PHY_9485_ANT_DIV_MAIN_LNACONF_S)
+ & AR_PHY_9485_ANT_DIV_MAIN_LNACONF);
+ regval |= ((antconf->alt_lna_conf << AR_PHY_9485_ANT_DIV_ALT_LNACONF_S)
+ & AR_PHY_9485_ANT_DIV_ALT_LNACONF);
+ regval |= ((antconf->fast_div_bias << AR_PHY_9485_ANT_FAST_DIV_BIAS_S)
+ & AR_PHY_9485_ANT_FAST_DIV_BIAS);
+ regval |= ((antconf->main_gaintb << AR_PHY_9485_ANT_DIV_MAIN_GAINTB_S)
+ & AR_PHY_9485_ANT_DIV_MAIN_GAINTB);
+ regval |= ((antconf->alt_gaintb << AR_PHY_9485_ANT_DIV_ALT_GAINTB_S)
+ & AR_PHY_9485_ANT_DIV_ALT_GAINTB);
+
+ REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
+}
+
void ar9003_hw_attach_phy_ops(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);
static const u32 ar9300_cca_regs[6] = {
AR_PHY_CCA_0,
AR_PHY_CCA_1,
@@ -1188,6 +1256,9 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
priv_ops->ani_cache_ini_regs = ar9003_hw_ani_cache_ini_regs;
priv_ops->set_radar_params = ar9003_hw_set_radar_params;
+ ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get;
+ ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set;
+
ar9003_hw_set_nf_limits(ah);
ar9003_hw_set_radar_conf(ah);
memcpy(ah->nf_regs, ar9300_cca_regs, sizeof(ah->nf_regs));
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
index 8bdda2cf9dd7..443090d278e3 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002-2010 Atheros Communications, Inc.
+ * Copyright (c) 2010-2011 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
@@ -261,12 +261,34 @@
#define AR_PHY_EXT_CCA0 (AR_AGC_BASE + 0x20)
#define AR_PHY_RESTART (AR_AGC_BASE + 0x24)
+/*
+ * Antenna Diversity settings
+ */
#define AR_PHY_MC_GAIN_CTRL (AR_AGC_BASE + 0x28)
#define AR_ANT_DIV_CTRL_ALL 0x7e000000
#define AR_ANT_DIV_CTRL_ALL_S 25
#define AR_ANT_DIV_ENABLE 0x1000000
#define AR_ANT_DIV_ENABLE_S 24
+
+#define AR_PHY_9485_ANT_FAST_DIV_BIAS 0x00007e00
+#define AR_PHY_9485_ANT_FAST_DIV_BIAS_S 9
+#define AR_PHY_9485_ANT_DIV_LNADIV 0x01000000
+#define AR_PHY_9485_ANT_DIV_LNADIV_S 24
+#define AR_PHY_9485_ANT_DIV_ALT_LNACONF 0x06000000
+#define AR_PHY_9485_ANT_DIV_ALT_LNACONF_S 25
+#define AR_PHY_9485_ANT_DIV_MAIN_LNACONF 0x18000000
+#define AR_PHY_9485_ANT_DIV_MAIN_LNACONF_S 27
+#define AR_PHY_9485_ANT_DIV_ALT_GAINTB 0x20000000
+#define AR_PHY_9485_ANT_DIV_ALT_GAINTB_S 29
+#define AR_PHY_9485_ANT_DIV_MAIN_GAINTB 0x40000000
+#define AR_PHY_9485_ANT_DIV_MAIN_GAINTB_S 30
+
+#define AR_PHY_9485_ANT_DIV_LNA1_MINUS_LNA2 0x0
+#define AR_PHY_9485_ANT_DIV_LNA2 0x1
+#define AR_PHY_9485_ANT_DIV_LNA1 0x2
+#define AR_PHY_9485_ANT_DIV_LNA1_PLUS_LNA2 0x3
+
#define AR_PHY_EXTCHN_PWRTHR1 (AR_AGC_BASE + 0x2c)
#define AR_PHY_EXT_CHN_WIN (AR_AGC_BASE + 0x30)
#define AR_PHY_20_40_DET_THR (AR_AGC_BASE + 0x34)
@@ -548,15 +570,12 @@
#define AR_PHY_TXGAIN_TABLE (AR_SM_BASE + 0x300)
-#define AR_PHY_TX_IQCAL_START_9485 (AR_SM_BASE + 0x3c4)
-#define AR_PHY_TX_IQCAL_START_DO_CAL_9485 0x80000000
-#define AR_PHY_TX_IQCAL_START_DO_CAL_9485_S 31
-#define AR_PHY_TX_IQCAL_CONTROL_1_9485 (AR_SM_BASE + 0x3c8)
-#define AR_PHY_TX_IQCAL_STATUS_B0_9485 (AR_SM_BASE + 0x3f0)
-
-#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_CONTROL_1 (AR_SM_BASE + AR_SREV_9485(ah) ? \
+ 0x3c8 : 0x448)
+#define AR_PHY_TX_IQCAL_START (AR_SM_BASE + AR_SREV_9485(ah) ? \
+ 0x3c4 : 0x440)
+#define AR_PHY_TX_IQCAL_STATUS_B0 (AR_SM_BASE + AR_SREV_9485(ah) ? \
+ 0x3f0 : 0x48c)
#define AR_PHY_TX_IQCAL_CORR_COEFF_B0(_i) (AR_SM_BASE + \
(AR_SREV_9485(ah) ? \
0x3d0 : 0x450) + ((_i) << 2))
@@ -588,7 +607,7 @@
#define AR_PHY_65NM_CH0_BIAS2 0x160c4
#define AR_PHY_65NM_CH0_BIAS4 0x160cc
#define AR_PHY_65NM_CH0_RXTX4 0x1610c
-#define AR_PHY_65NM_CH0_THERM (AR_SREV_9485(ah) ? 0x1628c : 0x16290)
+#define AR_PHY_65NM_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 : 0x1628c)
#define AR_PHY_65NM_CH0_THERM_LOCAL 0x80000000
#define AR_PHY_65NM_CH0_THERM_LOCAL_S 31
@@ -758,10 +777,10 @@
#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT 0x01000000
#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24
#define AR_PHY_CHANNEL_STATUS_RX_CLEAR 0x00000004
-#define AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT 0x01fc0000
-#define AR_PHY_TX_IQCAQL_CONTROL_1_IQCORR_I_Q_COFF_DELPT_S 18
-#define AR_PHY_TX_IQCAL_START_DO_CAL 0x00000001
-#define AR_PHY_TX_IQCAL_START_DO_CAL_S 0
+#define AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT 0x01fc0000
+#define AR_PHY_TX_IQCAL_CONTROL_1_IQCORR_I_Q_COFF_DELPT_S 18
+#define AR_PHY_TX_IQCAL_START_DO_CAL 0x00000001
+#define AR_PHY_TX_IQCAL_START_DO_CAL_S 0
#define AR_PHY_TX_IQCAL_STATUS_FAILED 0x00000001
#define AR_PHY_CALIBRATED_GAINS_0 0x3e
diff --git a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h
new file mode 100644
index 000000000000..815a8af1beef
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h
@@ -0,0 +1,1525 @@
+/*
+ * Copyright (c) 2011 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_9340_H
+#define INITVALS_9340_H
+
+static const u32 ar9340_1p0_radio_postamble[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x000160ac, 0xa4646800, 0xa4646800, 0xa4646800, 0xa4646800},
+ {0x0001610c, 0x08000000, 0x08000000, 0x00000000, 0x00000000},
+ {0x00016140, 0x10804000, 0x10804000, 0x50804000, 0x50804000},
+ {0x0001650c, 0x08000000, 0x08000000, 0x00000000, 0x00000000},
+ {0x00016540, 0x10804000, 0x10804000, 0x50804000, 0x50804000},
+};
+
+static const u32 ar9340Modes_lowest_ob_db_tx_gain_table_1p0[][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, 0x21020220, 0x21020220, 0x16000402, 0x16000402},
+ {0x0000a51c, 0x27020223, 0x27020223, 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, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83},
+ {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84},
+ {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3},
+ {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5},
+ {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9},
+ {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb},
+ {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+ {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+ {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+ {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+ {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+ {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+ {0x0000a57c, 0x770a308c, 0x770a308c, 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, 0x21820220, 0x21820220, 0x16800402, 0x16800402},
+ {0x0000a59c, 0x27820223, 0x27820223, 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, 0x5c84286b, 0x5c84286b, 0x47801a83, 0x47801a83},
+ {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4a801c84, 0x4a801c84},
+ {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4e801ce3, 0x4e801ce3},
+ {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x52801ce5, 0x52801ce5},
+ {0x0000a5dc, 0x7086308c, 0x7086308c, 0x56801ce9, 0x56801ce9},
+ {0x0000a5e0, 0x738a308a, 0x738a308a, 0x5a801ceb, 0x5a801ceb},
+ {0x0000a5e4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5e8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5ec, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f0, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+ {0x00016044, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db},
+ {0x00016048, 0x24925266, 0x24925266, 0x24925266, 0x24925266},
+ {0x00016444, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db},
+ {0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266},
+};
+
+static const u32 ar9340Modes_fast_clock_1p0[][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 ar9340_1p0_radio_core[][2] = {
+ /* Addr allmodes */
+ {0x00016000, 0x36db6db6},
+ {0x00016004, 0x6db6db40},
+ {0x00016008, 0x73f00000},
+ {0x0001600c, 0x00000000},
+ {0x00016040, 0x7f80fff8},
+ {0x00016044, 0x03b6d2db},
+ {0x00016048, 0x24925266},
+ {0x0001604c, 0x000f0278},
+ {0x00016050, 0x6db6db6c},
+ {0x00016054, 0x6db60000},
+ {0x00016080, 0x00080000},
+ {0x00016084, 0x0e48048c},
+ {0x00016088, 0x14214514},
+ {0x0001608c, 0x119f081c},
+ {0x00016090, 0x24926490},
+ {0x00016094, 0x00000000},
+ {0x00016098, 0xd411eb84},
+ {0x0001609c, 0x03e47f32},
+ {0x000160a0, 0xc2108ffe},
+ {0x000160a4, 0x812fc370},
+ {0x000160a8, 0x423c8000},
+ {0x000160ac, 0xa4646800},
+ {0x000160b0, 0x00fe7f46},
+ {0x000160b4, 0x92480000},
+ {0x000160c0, 0x006db6db},
+ {0x000160c4, 0x6db6db60},
+ {0x000160c8, 0x6db6db6c},
+ {0x000160cc, 0x6de6db6c},
+ {0x000160d0, 0xb6da4924},
+ {0x00016100, 0x04cb0001},
+ {0x00016104, 0xfff80000},
+ {0x00016108, 0x00080010},
+ {0x0001610c, 0x00000000},
+ {0x00016140, 0x50804008},
+ {0x00016144, 0x01884080},
+ {0x00016148, 0x000080c0},
+ {0x00016280, 0x01000015},
+ {0x00016284, 0x05530000},
+ {0x00016288, 0x00318000},
+ {0x0001628c, 0x50000000},
+ {0x00016290, 0x4080294f},
+ {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},
+ {0x00016444, 0x03b6d2db},
+ {0x00016448, 0x24927266},
+ {0x0001644c, 0x000f0278},
+ {0x00016450, 0x6db6db6c},
+ {0x00016454, 0x6db60000},
+ {0x00016500, 0x04cb0001},
+ {0x00016504, 0xfff80000},
+ {0x00016508, 0x00080010},
+ {0x0001650c, 0x00000000},
+ {0x00016540, 0x50804008},
+ {0x00016544, 0x01884080},
+ {0x00016548, 0x000080c0},
+ {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},
+};
+
+static const u32 ar9340_1p0_radio_core_40M[][2] = {
+ {0x0001609c, 0x02566f3a},
+ {0x000160ac, 0xa4647c00},
+ {0x000160b0, 0x01885f5a},
+};
+
+static const u32 ar9340_1p0_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 ar9340_1p0_soc_postamble[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023},
+};
+
+static const u32 ar9340_1p0_baseband_postamble[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011},
+ {0x00009820, 0x206a022e, 0x206a022e, 0x206a022e, 0x206a022e},
+ {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+ {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
+ {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+ {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
+ {0x00009c00, 0x00000044, 0x000000c4, 0x000000c4, 0x00000044},
+ {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0},
+ {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020},
+ {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
+ {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e},
+ {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, 0x00003fc0, 0x00003fc4, 0x00003fc4, 0x00003fc0},
+ {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
+ {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
+ {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, 0x00000220, 0x00000220, 0x00000110, 0x00000110},
+ {0x0000a28c, 0x00011111, 0x00011111, 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, 0x00180000, 0x00180000, 0x00180000, 0x00180000},
+ {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+ {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
+ {0x0000b284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
+};
+
+static const u32 ar9340_1p0_baseband_core[][2] = {
+ /* Addr allmodes */
+ {0x00009800, 0xafe68e30},
+ {0x00009804, 0xfd14e000},
+ {0x00009808, 0x9c0a9f6b},
+ {0x0000980c, 0x04900000},
+ {0x00009814, 0xb280c00a},
+ {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},
+ {0x0000a234, 0x10000fff},
+ {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, 0x04000080},
+ {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, 0x00000000},
+ {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},
+};
+
+static const u32 ar9340Modes_high_power_tx_gain_table_1p0[][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, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db},
+ {0x00016048, 0x24925266, 0x24925266, 0x24925266, 0x24925266},
+ {0x00016444, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db},
+ {0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266},
+};
+
+static const u32 ar9340Modes_high_ob_db_tx_gain_table_1p0[][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, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4},
+ {0x00016048, 0x8e481266, 0x8e481266, 0x8e481266, 0x8e481266},
+ {0x00016444, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4},
+ {0x00016448, 0x8e481266, 0x8e481266, 0x8e481266, 0x8e481266},
+};
+static const u32 ar9340Modes_ub124_tx_gain_table_1p0[][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, 0x036db2db, 0x036db2db, 0x036db2db, 0x036db2db},
+ {0x00016048, 0x69b65266, 0x69b65266, 0x69b65266, 0x69b65266},
+ {0x00016444, 0x036db2db, 0x036db2db, 0x036db2db, 0x036db2db},
+ {0x00016448, 0x69b65266, 0x69b65266, 0x69b65266, 0x69b65266},
+};
+
+
+static const u32 ar9340Common_rx_gain_table_1p0[][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 ar9340Modes_low_ob_db_tx_gain_table_1p0[][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, 0x21020220, 0x21020220, 0x16000402, 0x16000402},
+ {0x0000a51c, 0x27020223, 0x27020223, 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, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83},
+ {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84},
+ {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3},
+ {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5},
+ {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9},
+ {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb},
+ {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+ {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+ {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+ {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+ {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+ {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec},
+ {0x0000a57c, 0x770a308c, 0x770a308c, 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, 0x21820220, 0x21820220, 0x16800402, 0x16800402},
+ {0x0000a59c, 0x27820223, 0x27820223, 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, 0x5c84286b, 0x5c84286b, 0x47801a83, 0x47801a83},
+ {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x4a801c84, 0x4a801c84},
+ {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x4e801ce3, 0x4e801ce3},
+ {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x52801ce5, 0x52801ce5},
+ {0x0000a5dc, 0x7086308c, 0x7086308c, 0x56801ce9, 0x56801ce9},
+ {0x0000a5e0, 0x738a308a, 0x738a308a, 0x5a801ceb, 0x5a801ceb},
+ {0x0000a5e4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5e8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5ec, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f0, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec},
+ {0x00016044, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db},
+ {0x00016048, 0x24925266, 0x24925266, 0x24925266, 0x24925266},
+ {0x00016444, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db},
+ {0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266},
+};
+
+static const u32 ar9340Modes_mixed_ob_db_tx_gain_table_1p0[][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, 0x11000400, 0x11000400},
+ {0x0000a518, 0x21020220, 0x21020220, 0x15000402, 0x15000402},
+ {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404},
+ {0x0000a520, 0x2b022220, 0x2b022220, 0x1b000603, 0x1b000603},
+ {0x0000a524, 0x2f022222, 0x2f022222, 0x1f000a02, 0x1f000a02},
+ {0x0000a528, 0x34022225, 0x34022225, 0x23000a04, 0x23000a04},
+ {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x26000a20, 0x26000a20},
+ {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2a000e20, 0x2a000e20},
+ {0x0000a534, 0x4202242a, 0x4202242a, 0x2e000e22, 0x2e000e22},
+ {0x0000a538, 0x4702244a, 0x4702244a, 0x31000e24, 0x31000e24},
+ {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x34001640, 0x34001640},
+ {0x0000a540, 0x4e02246c, 0x4e02246c, 0x38001660, 0x38001660},
+ {0x0000a544, 0x5302266c, 0x5302266c, 0x3b001861, 0x3b001861},
+ {0x0000a548, 0x5702286c, 0x5702286c, 0x3e001a81, 0x3e001a81},
+ {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x42001a83, 0x42001a83},
+ {0x0000a550, 0x61042a6c, 0x61042a6c, 0x44001c84, 0x44001c84},
+ {0x0000a554, 0x66062a6c, 0x66062a6c, 0x48001ce3, 0x48001ce3},
+ {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x4c001ce5, 0x4c001ce5},
+ {0x0000a55c, 0x7006308c, 0x7006308c, 0x50001ce9, 0x50001ce9},
+ {0x0000a560, 0x730a308a, 0x730a308a, 0x54001ceb, 0x54001ceb},
+ {0x0000a564, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
+ {0x0000a568, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
+ {0x0000a56c, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
+ {0x0000a570, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
+ {0x0000a574, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
+ {0x0000a578, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
+ {0x0000a57c, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec},
+ {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, 0x11800400, 0x11800400},
+ {0x0000a598, 0x21820220, 0x21820220, 0x15800402, 0x15800402},
+ {0x0000a59c, 0x27820223, 0x27820223, 0x19800404, 0x19800404},
+ {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1b800603, 0x1b800603},
+ {0x0000a5a4, 0x2f822222, 0x2f822222, 0x1f800a02, 0x1f800a02},
+ {0x0000a5a8, 0x34822225, 0x34822225, 0x23800a04, 0x23800a04},
+ {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x26800a20, 0x26800a20},
+ {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2a800e20, 0x2a800e20},
+ {0x0000a5b4, 0x4282242a, 0x4282242a, 0x2e800e22, 0x2e800e22},
+ {0x0000a5b8, 0x4782244a, 0x4782244a, 0x31800e24, 0x31800e24},
+ {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x34801640, 0x34801640},
+ {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x38801660, 0x38801660},
+ {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3b801861, 0x3b801861},
+ {0x0000a5c8, 0x5782286c, 0x5782286c, 0x3e801a81, 0x3e801a81},
+ {0x0000a5cc, 0x5c84286b, 0x5c84286b, 0x42801a83, 0x42801a83},
+ {0x0000a5d0, 0x61842a6c, 0x61842a6c, 0x44801c84, 0x44801c84},
+ {0x0000a5d4, 0x66862a6c, 0x66862a6c, 0x48801ce3, 0x48801ce3},
+ {0x0000a5d8, 0x6b862e6c, 0x6b862e6c, 0x4c801ce5, 0x4c801ce5},
+ {0x0000a5dc, 0x7086308c, 0x7086308c, 0x50801ce9, 0x50801ce9},
+ {0x0000a5e0, 0x738a308a, 0x738a308a, 0x54801ceb, 0x54801ceb},
+ {0x0000a5e4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+ {0x0000a5e8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+ {0x0000a5ec, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+ {0x0000a5f0, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+ {0x0000a5f4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+ {0x0000a5f8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+ {0x0000a5fc, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec},
+ {0x00016044, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4},
+ {0x00016048, 0x24927266, 0x24927266, 0x8e483266, 0x8e483266},
+ {0x00016444, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4},
+ {0x00016448, 0x24927266, 0x24927266, 0x8e482266, 0x8e482266},
+};
+
+static const u32 ar9340_1p0_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, 0x9d400010},
+ {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 ar9340Common_wo_xlna_rx_gain_table_1p0[][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 ar9340_1p0_soc_preamble[][2] = {
+ /* Addr allmodes */
+ {0x000040a4, 0x00a0c1c9},
+ {0x00007008, 0x00000000},
+ {0x00007020, 0x00000000},
+ {0x00007034, 0x00000002},
+ {0x00007038, 0x000004c2},
+};
+
+#endif
diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
index 71cc0a3a29fb..611ea6ce8508 100644
--- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 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,931 +17,6 @@
#ifndef INITVALS_9485_H
#define INITVALS_9485_H
-static const u32 ar9485Common_1_0[][2] = {
- /* Addr allmodes */
- {0x00007010, 0x00000022},
- {0x00007020, 0x00000000},
- {0x00007034, 0x00000002},
- {0x00007038, 0x000004c2},
-};
-
-static const u32 ar9485_1_0_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 ar9485_1_0_pcie_phy_pll_on_clkreq_disable_L1[][2] = {
- /* Addr allmodes */
- {0x00018c00, 0x10212e5e},
- {0x00018c04, 0x000801d8},
- {0x00018c08, 0x0000580c},
-};
-
-static const u32 ar9485Common_wo_xlna_rx_gain_1_0[][2] = {
- /* Addr allmodes */
- {0x0000a000, 0x00010000},
- {0x0000a004, 0x00030002},
- {0x0000a008, 0x00050004},
- {0x0000a00c, 0x00810080},
- {0x0000a010, 0x01800082},
- {0x0000a014, 0x01820181},
- {0x0000a018, 0x01840183},
- {0x0000a01c, 0x01880185},
- {0x0000a020, 0x018a0189},
- {0x0000a024, 0x02850284},
- {0x0000a028, 0x02890288},
- {0x0000a02c, 0x03850384},
- {0x0000a030, 0x03890388},
- {0x0000a034, 0x038b038a},
- {0x0000a038, 0x038d038c},
- {0x0000a03c, 0x03910390},
- {0x0000a040, 0x03930392},
- {0x0000a044, 0x03950394},
- {0x0000a048, 0x00000396},
- {0x0000a04c, 0x00000000},
- {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, 0x28282828},
- {0x0000a084, 0x28282828},
- {0x0000a088, 0x28282828},
- {0x0000a08c, 0x28282828},
- {0x0000a090, 0x28282828},
- {0x0000a094, 0x21212128},
- {0x0000a098, 0x171c1c1c},
- {0x0000a09c, 0x02020212},
- {0x0000a0a0, 0x00000202},
- {0x0000a0a4, 0x00000000},
- {0x0000a0a8, 0x00000000},
- {0x0000a0ac, 0x00000000},
- {0x0000a0b0, 0x00000000},
- {0x0000a0b4, 0x00000000},
- {0x0000a0b8, 0x00000000},
- {0x0000a0bc, 0x00000000},
- {0x0000a0c0, 0x001f0000},
- {0x0000a0c4, 0x111f1100},
- {0x0000a0c8, 0x111d111e},
- {0x0000a0cc, 0x111b111c},
- {0x0000a0d0, 0x22032204},
- {0x0000a0d4, 0x22012202},
- {0x0000a0d8, 0x221f2200},
- {0x0000a0dc, 0x221d221e},
- {0x0000a0e0, 0x33013302},
- {0x0000a0e4, 0x331f3300},
- {0x0000a0e8, 0x4402331e},
- {0x0000a0ec, 0x44004401},
- {0x0000a0f0, 0x441e441f},
- {0x0000a0f4, 0x55015502},
- {0x0000a0f8, 0x551f5500},
- {0x0000a0fc, 0x6602551e},
- {0x0000a100, 0x66006601},
- {0x0000a104, 0x661e661f},
- {0x0000a108, 0x7703661d},
- {0x0000a10c, 0x77017702},
- {0x0000a110, 0x00007700},
- {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, 0x111f1100},
- {0x0000a148, 0x111d111e},
- {0x0000a14c, 0x111b111c},
- {0x0000a150, 0x22032204},
- {0x0000a154, 0x22012202},
- {0x0000a158, 0x221f2200},
- {0x0000a15c, 0x221d221e},
- {0x0000a160, 0x33013302},
- {0x0000a164, 0x331f3300},
- {0x0000a168, 0x4402331e},
- {0x0000a16c, 0x44004401},
- {0x0000a170, 0x441e441f},
- {0x0000a174, 0x55015502},
- {0x0000a178, 0x551f5500},
- {0x0000a17c, 0x6602551e},
- {0x0000a180, 0x66006601},
- {0x0000a184, 0x661e661f},
- {0x0000a188, 0x7703661d},
- {0x0000a18c, 0x77017702},
- {0x0000a190, 0x00007700},
- {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, 0x00000296},
-};
-
-static const u32 ar9485Modes_high_power_tx_gain_1_0[][5] = {
- /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
- {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
- {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
- {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
- {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
- {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
- {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
- {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
- {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
- {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
- {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603},
- {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605},
- {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03},
- {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04},
- {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20},
- {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20},
- {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22},
- {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24},
- {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26},
- {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640},
- {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660},
- {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861},
- {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81},
- {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83},
- {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85},
- {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5},
- {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9},
- {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb},
- {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
- {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
- {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
- {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
- {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
- {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
- {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db},
-};
-
-static const u32 ar9485_1_0[][2] = {
- /* Addr allmodes */
- {0x0000a580, 0x00000000},
- {0x0000a584, 0x00000000},
- {0x0000a588, 0x00000000},
- {0x0000a58c, 0x00000000},
- {0x0000a590, 0x00000000},
- {0x0000a594, 0x00000000},
- {0x0000a598, 0x00000000},
- {0x0000a59c, 0x00000000},
- {0x0000a5a0, 0x00000000},
- {0x0000a5a4, 0x00000000},
- {0x0000a5a8, 0x00000000},
- {0x0000a5ac, 0x00000000},
- {0x0000a5b0, 0x00000000},
- {0x0000a5b4, 0x00000000},
- {0x0000a5b8, 0x00000000},
- {0x0000a5bc, 0x00000000},
-};
-
-static const u32 ar9485_1_0_radio_core[][2] = {
- /* Addr allmodes */
- {0x00016000, 0x36db6db6},
- {0x00016004, 0x6db6db40},
- {0x00016008, 0x73800000},
- {0x0001600c, 0x00000000},
- {0x00016040, 0x7f80fff8},
- {0x00016048, 0x6c92426e},
- {0x0001604c, 0x000f0278},
- {0x00016050, 0x6db6db6c},
- {0x00016054, 0x6db60000},
- {0x00016080, 0x00080000},
- {0x00016084, 0x0e48048c},
- {0x00016088, 0x14214514},
- {0x0001608c, 0x119f081e},
- {0x00016090, 0x24926490},
- {0x00016098, 0xd28b3330},
- {0x000160a0, 0xc2108ffe},
- {0x000160a4, 0x812fc370},
- {0x000160a8, 0x423c8000},
- {0x000160b4, 0x92480040},
- {0x000160c0, 0x006db6db},
- {0x000160c4, 0x0186db60},
- {0x000160c8, 0x6db6db6c},
- {0x000160cc, 0x6de6fbe0},
- {0x000160d0, 0xf7dfcf3c},
- {0x00016100, 0x04cb0001},
- {0x00016104, 0xfff80015},
- {0x00016108, 0x00080010},
- {0x00016144, 0x01884080},
- {0x00016148, 0x00008040},
- {0x00016180, 0x08453333},
- {0x00016184, 0x18e82f01},
- {0x00016188, 0x00000000},
- {0x0001618c, 0x00000000},
- {0x00016240, 0x08400000},
- {0x00016244, 0x1bf90f00},
- {0x00016248, 0x00000000},
- {0x0001624c, 0x00000000},
- {0x00016280, 0x01000015},
- {0x00016284, 0x00d30000},
- {0x00016288, 0x00318000},
- {0x0001628c, 0x50000000},
- {0x00016290, 0x4b96210f},
- {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},
- {0x00016c40, 0x1319c178},
- {0x00016c44, 0x10000000},
-};
-
-static const u32 ar9485Modes_lowest_ob_db_tx_gain_1_0[][5] = {
- /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
- {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
- {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
- {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
- {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
- {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
- {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
- {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
- {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
- {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
- {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603},
- {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605},
- {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03},
- {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04},
- {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20},
- {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20},
- {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22},
- {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24},
- {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26},
- {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640},
- {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660},
- {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861},
- {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81},
- {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83},
- {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85},
- {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5},
- {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9},
- {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb},
- {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
- {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
- {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
- {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
- {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
- {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
- {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db},
-};
-
-static const u32 ar9485_1_0_baseband_core[][2] = {
- /* Addr allmodes */
- {0x00009800, 0xafe68e30},
- {0x00009804, 0xfd14e000},
- {0x00009808, 0x9c0a8f6b},
- {0x0000980c, 0x04800000},
- {0x00009814, 0x9280c00a},
- {0x00009818, 0x00000000},
- {0x0000981c, 0x00020028},
- {0x00009834, 0x5f3ca3de},
- {0x00009838, 0x0108ecff},
- {0x0000983c, 0x14750600},
- {0x00009880, 0x201fff00},
- {0x00009884, 0x00001042},
- {0x000098a4, 0x00200400},
- {0x000098b0, 0x52440bbe},
- {0x000098bc, 0x00000002},
- {0x000098d0, 0x004b6a8e},
- {0x000098d4, 0x00000820},
- {0x000098dc, 0x00000000},
- {0x000098f0, 0x00000000},
- {0x000098f4, 0x00000000},
- {0x00009c04, 0x00000000},
- {0x00009c08, 0x03200000},
- {0x00009c0c, 0x00000000},
- {0x00009c10, 0x00000000},
- {0x00009c14, 0x00046384},
- {0x00009c18, 0x05b6b440},
- {0x00009c1c, 0x00b6b440},
- {0x00009d00, 0xc080a333},
- {0x00009d04, 0x40206c10},
- {0x00009d08, 0x009c4060},
- {0x00009d0c, 0x1883800a},
- {0x00009d10, 0x01834061},
- {0x00009d14, 0x00c00400},
- {0x00009d18, 0x00000000},
- {0x00009d1c, 0x00000000},
- {0x00009e08, 0x0038233c},
- {0x00009e24, 0x990bb515},
- {0x00009e28, 0x0a6f0000},
- {0x00009e30, 0x06336f77},
- {0x00009e34, 0x6af6532f},
- {0x00009e38, 0x0cc80c00},
- {0x00009e40, 0x0d261820},
- {0x00009e4c, 0x00001004},
- {0x00009e50, 0x00ff03f1},
- {0x00009fc0, 0x80be4788},
- {0x00009fc4, 0x0001efb5},
- {0x00009fcc, 0x40000014},
- {0x0000a20c, 0x00000000},
- {0x0000a210, 0x00000000},
- {0x0000a220, 0x00000000},
- {0x0000a224, 0x00000000},
- {0x0000a228, 0x10002310},
- {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, 0x00000006},
- {0x0000a3f8, 0x0cdbd380},
- {0x0000a3fc, 0x000f0f01},
- {0x0000a400, 0x8fa91f01},
- {0x0000a404, 0x00000000},
- {0x0000a408, 0x0e79e5c6},
- {0x0000a40c, 0x00820820},
- {0x0000a414, 0x1ce739ce},
- {0x0000a418, 0x2d0011ce},
- {0x0000a41c, 0x1ce739ce},
- {0x0000a420, 0x000001ce},
- {0x0000a424, 0x1ce739ce},
- {0x0000a428, 0x000001ce},
- {0x0000a42c, 0x1ce739ce},
- {0x0000a430, 0x1ce739ce},
- {0x0000a434, 0x00000000},
- {0x0000a438, 0x00001801},
- {0x0000a43c, 0x00000000},
- {0x0000a440, 0x00000000},
- {0x0000a444, 0x00000000},
- {0x0000a448, 0x04000000},
- {0x0000a44c, 0x00000001},
- {0x0000a450, 0x00010000},
- {0x0000a458, 0x00000000},
- {0x0000a5c4, 0x3fad9d74},
- {0x0000a5c8, 0x0048060a},
- {0x0000a5cc, 0x00000637},
- {0x0000a760, 0x03020100},
- {0x0000a764, 0x09080504},
- {0x0000a768, 0x0d0c0b0a},
- {0x0000a76c, 0x13121110},
- {0x0000a770, 0x31301514},
- {0x0000a774, 0x35343332},
- {0x0000a778, 0x00000036},
- {0x0000a780, 0x00000838},
- {0x0000a7c0, 0x00000000},
- {0x0000a7c4, 0xfffffffc},
- {0x0000a7c8, 0x00000000},
- {0x0000a7cc, 0x00000000},
- {0x0000a7d0, 0x00000000},
- {0x0000a7d4, 0x00000004},
- {0x0000a7dc, 0x00000001},
-};
-
-static const u32 ar9485Modes_high_ob_db_tx_gain_1_0[][5] = {
- /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
- {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
- {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
- {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
- {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
- {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
- {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
- {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
- {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
- {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
- {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603},
- {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605},
- {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03},
- {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04},
- {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20},
- {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20},
- {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22},
- {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24},
- {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26},
- {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640},
- {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660},
- {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861},
- {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81},
- {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83},
- {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85},
- {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5},
- {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9},
- {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb},
- {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
- {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
- {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
- {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
- {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
- {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
- {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db},
-};
-
-static const u32 ar9485Common_rx_gain_1_0[][2] = {
- /* Addr allmodes */
- {0x0000a000, 0x00010000},
- {0x0000a004, 0x00030002},
- {0x0000a008, 0x00050004},
- {0x0000a00c, 0x00810080},
- {0x0000a010, 0x01800082},
- {0x0000a014, 0x01820181},
- {0x0000a018, 0x01840183},
- {0x0000a01c, 0x01880185},
- {0x0000a020, 0x018a0189},
- {0x0000a024, 0x02850284},
- {0x0000a028, 0x02890288},
- {0x0000a02c, 0x03850384},
- {0x0000a030, 0x03890388},
- {0x0000a034, 0x038b038a},
- {0x0000a038, 0x038d038c},
- {0x0000a03c, 0x03910390},
- {0x0000a040, 0x03930392},
- {0x0000a044, 0x03950394},
- {0x0000a048, 0x00000396},
- {0x0000a04c, 0x00000000},
- {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, 0x28282828},
- {0x0000a084, 0x28282828},
- {0x0000a088, 0x28282828},
- {0x0000a08c, 0x28282828},
- {0x0000a090, 0x28282828},
- {0x0000a094, 0x21212128},
- {0x0000a098, 0x171c1c1c},
- {0x0000a09c, 0x02020212},
- {0x0000a0a0, 0x00000202},
- {0x0000a0a4, 0x00000000},
- {0x0000a0a8, 0x00000000},
- {0x0000a0ac, 0x00000000},
- {0x0000a0b0, 0x00000000},
- {0x0000a0b4, 0x00000000},
- {0x0000a0b8, 0x00000000},
- {0x0000a0bc, 0x00000000},
- {0x0000a0c0, 0x001f0000},
- {0x0000a0c4, 0x111f1100},
- {0x0000a0c8, 0x111d111e},
- {0x0000a0cc, 0x111b111c},
- {0x0000a0d0, 0x22032204},
- {0x0000a0d4, 0x22012202},
- {0x0000a0d8, 0x221f2200},
- {0x0000a0dc, 0x221d221e},
- {0x0000a0e0, 0x33013302},
- {0x0000a0e4, 0x331f3300},
- {0x0000a0e8, 0x4402331e},
- {0x0000a0ec, 0x44004401},
- {0x0000a0f0, 0x441e441f},
- {0x0000a0f4, 0x55015502},
- {0x0000a0f8, 0x551f5500},
- {0x0000a0fc, 0x6602551e},
- {0x0000a100, 0x66006601},
- {0x0000a104, 0x661e661f},
- {0x0000a108, 0x7703661d},
- {0x0000a10c, 0x77017702},
- {0x0000a110, 0x00007700},
- {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, 0x111f1100},
- {0x0000a148, 0x111d111e},
- {0x0000a14c, 0x111b111c},
- {0x0000a150, 0x22032204},
- {0x0000a154, 0x22012202},
- {0x0000a158, 0x221f2200},
- {0x0000a15c, 0x221d221e},
- {0x0000a160, 0x33013302},
- {0x0000a164, 0x331f3300},
- {0x0000a168, 0x4402331e},
- {0x0000a16c, 0x44004401},
- {0x0000a170, 0x441e441f},
- {0x0000a174, 0x55015502},
- {0x0000a178, 0x551f5500},
- {0x0000a17c, 0x6602551e},
- {0x0000a180, 0x66006601},
- {0x0000a184, 0x661e661f},
- {0x0000a188, 0x7703661d},
- {0x0000a18c, 0x77017702},
- {0x0000a190, 0x00007700},
- {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, 0x00000296},
-};
-
-static const u32 ar9485_1_0_pcie_phy_pll_on_clkreq_enable_L1[][2] = {
- /* Addr allmodes */
- {0x00018c00, 0x10252e5e},
- {0x00018c04, 0x000801d8},
- {0x00018c08, 0x0000580c},
-};
-
-static const u32 ar9485_1_0_pcie_phy_clkreq_enable_L1[][2] = {
- /* Addr allmodes */
- {0x00018c00, 0x10253e5e},
- {0x00018c04, 0x000801d8},
- {0x00018c08, 0x0000580c},
-};
-
-static const u32 ar9485_1_0_soc_preamble[][2] = {
- /* Addr allmodes */
- {0x00004090, 0x00aa10aa},
- {0x000040a4, 0x00a0c9c9},
- {0x00007048, 0x00000004},
-};
-
-static const u32 ar9485_fast_clock_1_0_baseband_postamble[][3] = {
- /* Addr 5G_HT20 5G_HT40 */
- {0x00009e00, 0x03721821, 0x03721821},
- {0x0000a230, 0x0000400b, 0x00004016},
- {0x0000a254, 0x00000898, 0x00001130},
-};
-
-static const u32 ar9485_1_0_baseband_postamble[][5] = {
- /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
- {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005},
- {0x00009820, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e},
- {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
- {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
- {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
- {0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c},
- {0x00009c00, 0x00000044, 0x00000044, 0x00000044, 0x00000044},
- {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0},
- {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020},
- {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
- {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec80d2e, 0x7ec80d2e},
- {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},
- {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222},
- {0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324},
- {0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010},
- {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
- {0x0000a204, 0x01303fc0, 0x01303fc4, 0x01303fc4, 0x01303fc0},
- {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
- {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b},
- {0x0000a234, 0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff},
- {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, 0x3a021501, 0x3a021501, 0x3a021501, 0x3a021501},
- {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
- {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b},
- {0x0000a284, 0x00000000, 0x00000000, 0x000002a0, 0x000002a0},
- {0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
- {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982},
- {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a},
- {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000be04, 0x00802020, 0x00802020, 0x00802020, 0x00802020},
- {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-};
-
-static const u32 ar9485Modes_low_ob_db_tx_gain_1_0[][5] = {
- /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
- {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
- {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
- {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
- {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
- {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
- {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
- {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
- {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
- {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
- {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603},
- {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605},
- {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03},
- {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04},
- {0x0000a530, 0x48023ec6, 0x48023ec6, 0x2e000a20, 0x2e000a20},
- {0x0000a534, 0x4d023f01, 0x4d023f01, 0x34000e20, 0x34000e20},
- {0x0000a538, 0x53023f4b, 0x53023f4b, 0x38000e22, 0x38000e22},
- {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x3c000e24, 0x3c000e24},
- {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x40000e26, 0x40000e26},
- {0x0000a544, 0x6502feca, 0x6502feca, 0x43001640, 0x43001640},
- {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x46001660, 0x46001660},
- {0x0000a54c, 0x7203feca, 0x7203feca, 0x49001861, 0x49001861},
- {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x4c001a81, 0x4c001a81},
- {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x4f001a83, 0x4f001a83},
- {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x54001c85, 0x54001c85},
- {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x58001ce5, 0x58001ce5},
- {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5b001ce9, 0x5b001ce9},
- {0x0000a564, 0x960fffcb, 0x960fffcb, 0x60001eeb, 0x60001eeb},
- {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
- {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
- {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
- {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
- {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
- {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x60001eeb, 0x60001eeb},
- {0x00016044, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db, 0x05b6b2db},
-};
-
-static const u32 ar9485_1_0_pcie_phy_clkreq_disable_L1[][2] = {
- /* Addr allmodes */
- {0x00018c00, 0x10213e5e},
- {0x00018c04, 0x000801d8},
- {0x00018c08, 0x0000580c},
-};
-
-static const u32 ar9485_1_0_radio_postamble[][2] = {
- /* Addr allmodes */
- {0x0001609c, 0x0b283f31},
- {0x000160ac, 0x24611800},
- {0x000160b0, 0x03284f3e},
- {0x0001610c, 0x00170000},
- {0x00016140, 0x10804008},
-};
-
-static const u32 ar9485_1_0_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, 0x0010f400},
- {0x00008248, 0x00000800},
- {0x0000824c, 0x0001e800},
- {0x00008250, 0x00000000},
- {0x00008254, 0x00000000},
- {0x00008258, 0x00000000},
- {0x0000825c, 0x40000000},
- {0x00008260, 0x00080922},
- {0x00008264, 0x9ca00010},
- {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, 0xa248105b},
- {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 ar9485_1_1_mac_core[][2] = {
/* Addr allmodes */
{0x00000008, 0x00000000},
@@ -1321,7 +396,7 @@ static const u32 ar9485Modes_high_ob_db_tx_gain_1_1[][5] = {
{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
- {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb},
+ {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
@@ -1394,7 +469,7 @@ static const u32 ar9485_modes_lowest_ob_db_tx_gain_1_1[][5] = {
{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
- {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb},
+ {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
@@ -1560,7 +635,7 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = {
{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
- {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb},
+ {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
@@ -1653,7 +728,7 @@ static const u32 ar9485_modes_green_ob_db_tx_gain_1_1[][5] = {
{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
- {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb},
+ {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
@@ -1752,7 +827,7 @@ static const u32 ar9485Modes_low_ob_db_tx_gain_1_1[][5] = {
{0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
{0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
{0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
- {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001eeb, 0x5a001eeb},
+ {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
{0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
{0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
{0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 099bd4183ad0..f75068b4b310 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -62,7 +62,6 @@ struct ath_node;
#define ATH_TXQ_SETUP(sc, i) ((sc)->tx.txqsetup & (1<<i))
struct ath_config {
- u32 ath_aggr_prot;
u16 txpowlimit;
u8 cabqReadytime;
};
@@ -120,13 +119,11 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
/* RX / TX */
/***********/
-#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
#define TID_TO_WME_AC(_tid) \
((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \
@@ -202,6 +199,7 @@ struct ath_atx_ac {
int sched;
struct list_head list;
struct list_head tid_q;
+ bool clear_ps_filter;
};
struct ath_frame_info {
@@ -257,8 +255,12 @@ struct ath_node {
#endif
struct ath_atx_tid tid[WME_NUM_TID];
struct ath_atx_ac ac[WME_NUM_AC];
+ int ps_key;
+
u16 maxampdu;
u8 mpdudensity;
+
+ bool sleeping;
};
#define AGGR_CLEANUP BIT(1)
@@ -340,17 +342,18 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid);
+void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an);
+bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an);
+
/********/
/* VIFs */
/********/
struct ath_vif {
int av_bslot;
- bool is_bslot_active;
+ bool is_bslot_active, primary_sta_vif;
__le64 tsf_adjust; /* TSF adjustment for staggered beacons */
- enum nl80211_iftype av_opmode;
struct ath_buf *av_bcbuf;
- u8 bssid[ETH_ALEN]; /* current BSSID from config_interface */
};
/*******************/
@@ -362,7 +365,7 @@ struct ath_vif {
* number of BSSIDs) if a given beacon does not go out even after waiting this
* number of beacon intervals, the game's up.
*/
-#define BSTUCK_THRESH (9 * ATH_BCBUF)
+#define BSTUCK_THRESH 9
#define ATH_BCBUF 4
#define ATH_DEFAULT_BINTVAL 100 /* TU */
#define ATH_DEFAULT_BMISS_LIMIT 10
@@ -386,7 +389,7 @@ struct ath_beacon {
u32 beaconq;
u32 bmisscnt;
u32 ast_be_xmit;
- u64 bc_tstamp;
+ u32 bc_tstamp;
struct ieee80211_vif *bslot[ATH_BCBUF];
int slottime;
int slotupdate;
@@ -394,6 +397,9 @@ struct ath_beacon {
struct ath_descdma bdma;
struct ath_txq *cabq;
struct list_head bbuf;
+
+ bool tx_processed;
+ bool tx_last;
};
void ath_beacon_tasklet(unsigned long data);
@@ -401,6 +407,7 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif);
int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif);
void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp);
int ath_beaconq_config(struct ath_softc *sc);
+void ath_set_beacon(struct ath_softc *sc);
void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
/*******/
@@ -418,6 +425,7 @@ void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
#define ATH_PAPRD_TIMEOUT 100 /* msecs */
void ath_hw_check(struct work_struct *work);
+void ath_hw_pll_work(struct work_struct *work);
void ath_paprd_calibrate(struct work_struct *work);
void ath_ani_calibrate(unsigned long data);
@@ -448,6 +456,7 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc);
#define ATH_LED_PIN_DEF 1
#define ATH_LED_PIN_9287 8
+#define ATH_LED_PIN_9300 10
#define ATH_LED_PIN_9485 6
#ifdef CONFIG_MAC80211_LEDS
@@ -477,7 +486,6 @@ static inline void ath_deinit_leds(struct ath_softc *sc)
#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO 30
#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO2 20
-#define ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA -3
#define ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA -1
#define ATH_ANT_DIV_COMB_LNA1_DELTA_HI -4
#define ATH_ANT_DIV_COMB_LNA1_DELTA_MID -2
@@ -550,6 +558,7 @@ struct ath_ant_comb {
#define SC_OP_BT_SCAN BIT(13)
#define SC_OP_ANI_RUN BIT(14)
#define SC_OP_ENABLE_APM BIT(15)
+#define SC_OP_PRIM_STA_VIF BIT(16)
/* Powersave flags */
#define PS_WAIT_FOR_BEACON BIT(0)
@@ -557,6 +566,7 @@ struct ath_ant_comb {
#define PS_WAIT_FOR_PSPOLL_DATA BIT(2)
#define PS_WAIT_FOR_TX_ACK BIT(3)
#define PS_BEACON_SYNC BIT(4)
+#define PS_TSFOOR_SYNC BIT(5)
struct ath_rate_table;
@@ -667,7 +677,7 @@ void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw);
bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode);
bool ath9k_uses_beacons(int type);
-#ifdef CONFIG_PCI
+#ifdef CONFIG_ATH9K_PCI
int ath_pci_init(void);
void ath_pci_exit(void);
#else
@@ -675,7 +685,7 @@ static inline int ath_pci_init(void) { return 0; };
static inline void ath_pci_exit(void) {};
#endif
-#ifdef CONFIG_ATHEROS_AR71XX
+#ifdef CONFIG_ATH9K_AHB
int ath_ahb_init(void);
void ath_ahb_exit(void);
#else
@@ -688,8 +698,6 @@ void ath9k_ps_restore(struct ath_softc *sc);
u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate);
-void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
-
void ath_start_rfkill_poll(struct ath_softc *sc);
extern void ath9k_rfkill_poll_state(struct ieee80211_hw *hw);
void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 6d2a545fc35e..d4d8ceced89b 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -18,6 +18,12 @@
#define FUDGE 2
+static void ath9k_reset_beacon_status(struct ath_softc *sc)
+{
+ sc->beacon.tx_processed = false;
+ sc->beacon.tx_last = false;
+}
+
/*
* This function will modify certain transmit queue properties depending on
* the operating mode of the station (AP or AdHoc). Parameters are AIFS
@@ -57,8 +63,8 @@ int ath_beaconq_config(struct ath_softc *sc)
/*
* Associates the beacon frame buffer with a transmit descriptor. Will set
- * up all required antenna switch parameters, rate codes, and channel flags.
- * Beacons are always sent out at the lowest rate, and are not retried.
+ * up rate codes, and channel flags. Beacons are always sent out at the
+ * lowest rate, and are not retried.
*/
static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
struct ath_buf *bf, int rateidx)
@@ -68,20 +74,16 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
struct ath_common *common = ath9k_hw_common(ah);
struct ath_desc *ds;
struct ath9k_11n_rate_series series[4];
- int flags, antenna, ctsrate = 0, ctsduration = 0;
+ int flags, ctsrate = 0, ctsduration = 0;
struct ieee80211_supported_band *sband;
u8 rate = 0;
+ ath9k_reset_beacon_status(sc);
+
ds = bf->bf_desc;
flags = ATH9K_TXDESC_NOACK;
ds->ds_link = 0;
- /*
- * Switch antenna every beacon.
- * Should only switch every beacon period, not for every SWBA
- * XXX assumes two antennae
- */
- antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1);
sband = &sc->sbands[common->hw->conf.channel->band];
rate = sband->bitrates[rateidx].hw_value;
@@ -140,6 +142,8 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info;
int cabq_depth;
+ ath9k_reset_beacon_status(sc);
+
avp = (void *)vif->drv_priv;
cabq = sc->beacon.cabq;
@@ -278,7 +282,7 @@ int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif)
return -ENOMEM;
tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
- sc->beacon.bc_tstamp = le64_to_cpu(tstamp);
+ sc->beacon.bc_tstamp = (u32) le64_to_cpu(tstamp);
/* Calculate a TSF adjustment factor required for staggered beacons. */
if (avp->av_bslot > 0) {
u64 tsfadjust;
@@ -294,8 +298,8 @@ int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif)
* adjustment. Other slots are adjusted to get the timestamp
* close to the TBTT for the BSS.
*/
- tsfadjust = intval * avp->av_bslot / ATH_BCBUF;
- avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust));
+ tsfadjust = TU_TO_USEC(intval * avp->av_bslot) / ATH_BCBUF;
+ avp->tsf_adjust = cpu_to_le64(tsfadjust);
ath_dbg(common, ATH_DBG_BEACON,
"stagger beacons, bslot %d intval %u tsfadjust %llu\n",
@@ -326,9 +330,11 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp)
if (avp->av_bcbuf != NULL) {
struct ath_buf *bf;
+ avp->is_bslot_active = false;
if (avp->av_bslot != -1) {
sc->beacon.bslot[avp->av_bslot] = NULL;
sc->nbcnvifs--;
+ avp->av_bslot = -1;
}
bf = avp->av_bcbuf;
@@ -355,9 +361,7 @@ void ath_beacon_tasklet(unsigned long data)
struct ath_buf *bf = NULL;
struct ieee80211_vif *vif;
int slot;
- u32 bfaddr, bc = 0, tsftu;
- u64 tsf;
- u16 intval;
+ u32 bfaddr, bc = 0;
/*
* Check if the previous beacon has gone out. If
@@ -369,12 +373,13 @@ void ath_beacon_tasklet(unsigned long data)
if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) {
sc->beacon.bmisscnt++;
- if (sc->beacon.bmisscnt < BSTUCK_THRESH) {
+ if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) {
ath_dbg(common, ATH_DBG_BSTUCK,
"missed %u consecutive beacons\n",
sc->beacon.bmisscnt);
ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
- ath9k_hw_bstuck_nfcal(ah);
+ if (sc->beacon.bmisscnt > 3)
+ ath9k_hw_bstuck_nfcal(ah);
} else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
ath_dbg(common, ATH_DBG_BSTUCK,
"beacon is officially stuck\n");
@@ -385,37 +390,33 @@ void ath_beacon_tasklet(unsigned long data)
return;
}
- if (sc->beacon.bmisscnt != 0) {
- ath_dbg(common, ATH_DBG_BSTUCK,
- "resume beacon xmit after %u misses\n",
- sc->beacon.bmisscnt);
- sc->beacon.bmisscnt = 0;
- }
-
/*
* Generate beacon frames. we are sending frames
* staggered so calculate the slot for this frame based
* on the tsf to safeguard against missing an swba.
*/
- intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
- tsf = ath9k_hw_gettsf64(ah);
- tsftu = TSF_TO_TU(tsf>>32, tsf);
- slot = ((tsftu % intval) * ATH_BCBUF) / intval;
- /*
- * Reverse the slot order to get slot 0 on the TBTT offset that does
- * not require TSF adjustment and other slots adding
- * slot/ATH_BCBUF * beacon_int to timestamp. For example, with
- * ATH_BCBUF = 4, we process beacon slots as follows: 3 2 1 0 3 2 1 ..
- * and slot 0 is at correct offset to TBTT.
- */
- slot = ATH_BCBUF - slot - 1;
- vif = sc->beacon.bslot[slot];
+ if (ah->opmode == NL80211_IFTYPE_AP) {
+ u16 intval;
+ u32 tsftu;
+ u64 tsf;
+
+ intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL;
+ tsf = ath9k_hw_gettsf64(ah);
+ tsf += TU_TO_USEC(ah->config.sw_beacon_response_time);
+ tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF);
+ slot = (tsftu % (intval * ATH_BCBUF)) / intval;
+ vif = sc->beacon.bslot[slot];
+
+ ath_dbg(common, ATH_DBG_BEACON,
+ "slot %d [tsf %llu tsftu %u intval %u] vif %p\n",
+ slot, tsf, tsftu / ATH_BCBUF, intval, vif);
+ } else {
+ slot = 0;
+ vif = sc->beacon.bslot[slot];
+ }
- ath_dbg(common, ATH_DBG_BEACON,
- "slot %d [tsf %llu tsftu %u intval %u] vif %p\n",
- slot, tsf, tsftu, intval, vif);
bfaddr = 0;
if (vif) {
@@ -424,6 +425,13 @@ void ath_beacon_tasklet(unsigned long data)
bfaddr = bf->bf_daddr;
bc = 1;
}
+
+ if (sc->beacon.bmisscnt != 0) {
+ ath_dbg(common, ATH_DBG_BSTUCK,
+ "resume beacon xmit after %u misses\n",
+ sc->beacon.bmisscnt);
+ sc->beacon.bmisscnt = 0;
+ }
}
/*
@@ -463,13 +471,17 @@ static void ath9k_beacon_init(struct ath_softc *sc,
u32 next_beacon,
u32 beacon_period)
{
- if (beacon_period & ATH9K_BEACON_RESET_TSF)
+ if (sc->sc_flags & SC_OP_TSF_RESET) {
ath9k_ps_wakeup(sc);
+ ath9k_hw_reset_tsf(sc->sc_ah);
+ }
ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period);
- if (beacon_period & ATH9K_BEACON_RESET_TSF)
+ if (sc->sc_flags & SC_OP_TSF_RESET) {
ath9k_ps_restore(sc);
+ sc->sc_flags &= ~SC_OP_TSF_RESET;
+ }
}
/*
@@ -484,18 +496,14 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
u32 nexttbtt, intval;
/* NB: the beacon interval is kept internally in TU's */
- intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
+ intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD);
intval /= ATH_BCBUF; /* for staggered beacons */
nexttbtt = intval;
- if (sc->sc_flags & SC_OP_TSF_RESET)
- intval |= ATH9K_BEACON_RESET_TSF;
-
/*
* In AP mode we enable the beacon timers and SWBA interrupts to
* prepare beacon frames.
*/
- intval |= ATH9K_BEACON_ENA;
ah->imask |= ATH9K_INT_SWBA;
ath_beaconq_config(sc);
@@ -505,11 +513,6 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
ath9k_beacon_init(sc, nexttbtt, intval);
sc->beacon.bmisscnt = 0;
ath9k_hw_set_interrupts(ah, ah->imask);
-
- /* Clear the reset TSF flag, so that subsequent beacon updation
- will not reset the HW TSF. */
-
- sc->sc_flags &= ~SC_OP_TSF_RESET;
}
/*
@@ -635,7 +638,13 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
ath9k_hw_disable_interrupts(ah);
ath9k_hw_set_sta_beacon_timers(ah, &bs);
ah->imask |= ATH9K_INT_BMISS;
- ath9k_hw_set_interrupts(ah, ah->imask);
+
+ /*
+ * If the beacon config is called beacause of TSFOOR,
+ * Interrupts will be enabled back at the end of ath9k_tasklet
+ */
+ if (!(sc->ps_flags & PS_TSFOOR_SYNC))
+ ath9k_hw_set_interrupts(ah, ah->imask);
}
static void ath_beacon_config_adhoc(struct ath_softc *sc,
@@ -643,25 +652,22 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
- u64 tsf;
- u32 tsftu, intval, nexttbtt;
+ u32 tsf, delta, intval, nexttbtt;
- intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
-
-
- /* Pull nexttbtt forward to reflect the current TSF */
+ ath9k_reset_beacon_status(sc);
- nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp);
- if (nexttbtt == 0)
- nexttbtt = intval;
- else if (intval)
- nexttbtt = roundup(nexttbtt, intval);
+ tsf = ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE);
+ intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD);
- tsf = ath9k_hw_gettsf64(ah);
- tsftu = TSF_TO_TU((u32)(tsf>>32), (u32)tsf) + FUDGE;
- do {
- nexttbtt += intval;
- } while (nexttbtt < tsftu);
+ if (!sc->beacon.bc_tstamp)
+ nexttbtt = tsf + intval;
+ else {
+ if (tsf > sc->beacon.bc_tstamp)
+ delta = (tsf - sc->beacon.bc_tstamp);
+ else
+ delta = (tsf + 1 + (~0U - sc->beacon.bc_tstamp));
+ nexttbtt = tsf + intval - (delta % intval);
+ }
ath_dbg(common, ATH_DBG_BEACON,
"IBSS nexttbtt %u intval %u (%u)\n",
@@ -672,7 +678,6 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
* if we need to manually prepare beacon frames. Otherwise we use a
* self-linked tx descriptor and let the hardware deal with things.
*/
- intval |= ATH9K_BEACON_ENA;
ah->imask |= ATH9K_INT_SWBA;
ath_beaconq_config(sc);
@@ -682,25 +687,71 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
ath9k_hw_disable_interrupts(ah);
ath9k_beacon_init(sc, nexttbtt, intval);
sc->beacon.bmisscnt = 0;
- ath9k_hw_set_interrupts(ah, ah->imask);
+ /*
+ * If the beacon config is called beacause of TSFOOR,
+ * Interrupts will be enabled back at the end of ath9k_tasklet
+ */
+ if (!(sc->ps_flags & PS_TSFOOR_SYNC))
+ ath9k_hw_set_interrupts(ah, ah->imask);
}
-void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
+static bool ath9k_allow_beacon_config(struct ath_softc *sc,
+ struct ieee80211_vif *vif)
{
struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- enum nl80211_iftype iftype;
+ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+ struct ath_vif *avp = (void *)vif->drv_priv;
- /* Setup the beacon configuration parameters */
- if (vif) {
- struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
- iftype = vif->type;
- cur_conf->beacon_interval = bss_conf->beacon_int;
- cur_conf->dtim_period = bss_conf->dtim_period;
- } else {
- iftype = sc->sc_ah->opmode;
+ /*
+ * Can not have different beacon interval on multiple
+ * AP interface case
+ */
+ if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
+ (sc->nbcnvifs > 1) &&
+ (vif->type == NL80211_IFTYPE_AP) &&
+ (cur_conf->beacon_interval != bss_conf->beacon_int)) {
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Changing beacon interval of multiple \
+ AP interfaces !\n");
+ return false;
+ }
+ /*
+ * Can not configure station vif's beacon config
+ * while on AP opmode
+ */
+ if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
+ (vif->type != NL80211_IFTYPE_AP)) {
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "STA vif's beacon not allowed on AP mode\n");
+ return false;
+ }
+ /*
+ * Do not allow beacon config if HW was already configured
+ * with another STA vif
+ */
+ if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
+ (vif->type == NL80211_IFTYPE_STATION) &&
+ (sc->sc_flags & SC_OP_BEACONS) &&
+ !avp->primary_sta_vif) {
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Beacon already configured for a station interface\n");
+ return false;
}
+ return true;
+}
+
+void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
+{
+ struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
+ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+ if (!ath9k_allow_beacon_config(sc, vif))
+ return;
+
+ /* Setup the beacon configuration parameters */
+ cur_conf->beacon_interval = bss_conf->beacon_int;
+ cur_conf->dtim_period = bss_conf->dtim_period;
cur_conf->listen_interval = 1;
cur_conf->dtim_count = 1;
cur_conf->bmiss_timeout =
@@ -723,9 +774,37 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
if (cur_conf->dtim_period == 0)
cur_conf->dtim_period = 1;
- switch (iftype) {
+ ath_set_beacon(sc);
+}
+
+static bool ath_has_valid_bslot(struct ath_softc *sc)
+{
+ struct ath_vif *avp;
+ int slot;
+ bool found = false;
+
+ for (slot = 0; slot < ATH_BCBUF; slot++) {
+ if (sc->beacon.bslot[slot]) {
+ avp = (void *)sc->beacon.bslot[slot]->drv_priv;
+ if (avp->is_bslot_active) {
+ found = true;
+ break;
+ }
+ }
+ }
+ return found;
+}
+
+
+void ath_set_beacon(struct ath_softc *sc)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
+
+ switch (sc->sc_ah->opmode) {
case NL80211_IFTYPE_AP:
- ath_beacon_config_ap(sc, cur_conf);
+ if (ath_has_valid_bslot(sc))
+ ath_beacon_config_ap(sc, cur_conf);
break;
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
@@ -746,26 +825,15 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
{
struct ath_hw *ah = sc->sc_ah;
- struct ath_vif *avp;
- int slot;
- bool found = false;
+
+ if (!ath_has_valid_bslot(sc))
+ return;
ath9k_ps_wakeup(sc);
if (status) {
- for (slot = 0; slot < ATH_BCBUF; slot++) {
- if (sc->beacon.bslot[slot]) {
- avp = (void *)sc->beacon.bslot[slot]->drv_priv;
- if (avp->is_bslot_active) {
- found = true;
- break;
- }
- }
- }
- if (found) {
- /* Re-enable beaconing */
- ah->imask |= ATH9K_INT_SWBA;
- ath9k_hw_set_interrupts(ah, ah->imask);
- }
+ /* Re-enable beaconing */
+ ah->imask |= ATH9K_INT_SWBA;
+ ath9k_hw_set_interrupts(ah, ah->imask);
} else {
/* Disable SWBA interrupt */
ah->imask &= ~ATH9K_INT_SWBA;
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c
index d33bf204c995..41ce0b139886 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.c
+++ b/drivers/net/wireless/ath/ath9k/btcoex.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009 Atheros Communications Inc.
+ * Copyright (c) 2009-2011 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
@@ -51,6 +51,10 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum)
.bt_hold_rx_clear = true,
};
u32 i;
+ bool rxclear_polarity = ath_bt_config.bt_rxclear_polarity;
+
+ if (AR_SREV_9300_20_OR_LATER(ah))
+ rxclear_polarity = !ath_bt_config.bt_rxclear_polarity;
btcoex_hw->bt_coex_mode =
(btcoex_hw->bt_coex_mode & AR_BT_QCU_THRESH) |
@@ -59,7 +63,7 @@ void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum)
SM(ath_bt_config.bt_txframe_extend, AR_BT_TX_FRAME_EXTEND) |
SM(ath_bt_config.bt_mode, AR_BT_MODE) |
SM(ath_bt_config.bt_quiet_collision, AR_BT_QUIET) |
- SM(ath_bt_config.bt_rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) |
+ SM(rxclear_polarity, AR_BT_RX_CLEAR_POLARITY) |
SM(ath_bt_config.bt_priority_time, AR_BT_PRIORITY_TIME) |
SM(ath_bt_config.bt_first_slot_time, AR_BT_FIRST_SLOT_TIME) |
SM(qnum, AR_BT_QCU_THRESH);
@@ -142,6 +146,7 @@ void ath9k_hw_btcoex_set_weight(struct ath_hw *ah,
}
EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight);
+
static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah)
{
struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
@@ -152,9 +157,22 @@ static void ath9k_hw_btcoex_enable_3wire(struct ath_hw *ah)
* enable coex 3-wire
*/
REG_WRITE(ah, AR_BT_COEX_MODE, btcoex_hw->bt_coex_mode);
- REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_hw->bt_coex_weights);
REG_WRITE(ah, AR_BT_COEX_MODE2, btcoex_hw->bt_coex_mode2);
+
+ if (AR_SREV_9300_20_OR_LATER(ah)) {
+ REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS0, ah->bt_coex_wlan_weight[0]);
+ REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS1, ah->bt_coex_wlan_weight[1]);
+ REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS0, ah->bt_coex_bt_weight[0]);
+ REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS1, ah->bt_coex_bt_weight[1]);
+ REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS2, ah->bt_coex_bt_weight[2]);
+ REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS3, ah->bt_coex_bt_weight[3]);
+
+ } else
+ REG_WRITE(ah, AR_BT_COEX_WEIGHT, btcoex_hw->bt_coex_weights);
+
+
+
if (AR_SREV_9271(ah)) {
val = REG_READ(ah, 0x50040);
val &= 0xFFFFFEFF;
@@ -202,10 +220,86 @@ void ath9k_hw_btcoex_disable(struct ath_hw *ah)
if (btcoex_hw->scheme == ATH_BTCOEX_CFG_3WIRE) {
REG_WRITE(ah, AR_BT_COEX_MODE, AR_BT_QUIET | AR_BT_MODE);
- REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0);
REG_WRITE(ah, AR_BT_COEX_MODE2, 0);
+
+ if (AR_SREV_9300_20_OR_LATER(ah)) {
+ REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS0, 0);
+ REG_WRITE(ah, AR_BT_COEX_WL_WEIGHTS1, 0);
+ REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS0, 0);
+ REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS1, 0);
+ REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS2, 0);
+ REG_WRITE(ah, AR_BT_COEX_BT_WEIGHTS3, 0);
+ } else
+ REG_WRITE(ah, AR_BT_COEX_WEIGHT, 0);
+
}
ah->btcoex_hw.enabled = false;
}
EXPORT_SYMBOL(ath9k_hw_btcoex_disable);
+
+static void ar9003_btcoex_bt_stomp(struct ath_hw *ah,
+ enum ath_stomp_type stomp_type)
+{
+ ah->bt_coex_bt_weight[0] = AR9300_BT_WGHT;
+ ah->bt_coex_bt_weight[1] = AR9300_BT_WGHT;
+ ah->bt_coex_bt_weight[2] = AR9300_BT_WGHT;
+ ah->bt_coex_bt_weight[3] = AR9300_BT_WGHT;
+
+
+ switch (stomp_type) {
+ case ATH_BTCOEX_STOMP_ALL:
+ ah->bt_coex_wlan_weight[0] = AR9300_STOMP_ALL_WLAN_WGHT0;
+ ah->bt_coex_wlan_weight[1] = AR9300_STOMP_ALL_WLAN_WGHT1;
+ break;
+ case ATH_BTCOEX_STOMP_LOW:
+ ah->bt_coex_wlan_weight[0] = AR9300_STOMP_LOW_WLAN_WGHT0;
+ ah->bt_coex_wlan_weight[1] = AR9300_STOMP_LOW_WLAN_WGHT1;
+ break;
+ case ATH_BTCOEX_STOMP_NONE:
+ ah->bt_coex_wlan_weight[0] = AR9300_STOMP_NONE_WLAN_WGHT0;
+ ah->bt_coex_wlan_weight[1] = AR9300_STOMP_NONE_WLAN_WGHT1;
+ break;
+
+ default:
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
+ "Invalid Stomptype\n");
+ break;
+ }
+
+ ath9k_hw_btcoex_enable(ah);
+}
+
+/*
+ * Configures appropriate weight based on stomp type.
+ */
+void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah,
+ enum ath_stomp_type stomp_type)
+{
+ if (AR_SREV_9300_20_OR_LATER(ah)) {
+ ar9003_btcoex_bt_stomp(ah, stomp_type);
+ return;
+ }
+
+ switch (stomp_type) {
+ case ATH_BTCOEX_STOMP_ALL:
+ ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+ AR_STOMP_ALL_WLAN_WGHT);
+ break;
+ case ATH_BTCOEX_STOMP_LOW:
+ ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+ AR_STOMP_LOW_WLAN_WGHT);
+ break;
+ case ATH_BTCOEX_STOMP_NONE:
+ ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+ AR_STOMP_NONE_WLAN_WGHT);
+ break;
+ default:
+ ath_dbg(ath9k_hw_common(ah), ATH_DBG_BTCOEX,
+ "Invalid Stomptype\n");
+ break;
+ }
+
+ ath9k_hw_btcoex_enable(ah);
+}
+EXPORT_SYMBOL(ath9k_hw_btcoex_bt_stomp);
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h
index 588dfd464dd1..234f77689b14 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.h
+++ b/drivers/net/wireless/ath/ath9k/btcoex.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009 Atheros Communications Inc.
+ * Copyright (c) 2009-2011 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
@@ -19,9 +19,13 @@
#include "hw.h"
-#define ATH_WLANACTIVE_GPIO 5
-#define ATH_BTACTIVE_GPIO 6
-#define ATH_BTPRIORITY_GPIO 7
+#define ATH_WLANACTIVE_GPIO_9280 5
+#define ATH_BTACTIVE_GPIO_9280 6
+#define ATH_BTPRIORITY_GPIO_9285 7
+
+#define ATH_WLANACTIVE_GPIO_9300 5
+#define ATH_BTACTIVE_GPIO_9300 4
+#define ATH_BTPRIORITY_GPIO_9300 8
#define ATH_BTCOEX_DEF_BT_PERIOD 45
#define ATH_BTCOEX_DEF_DUTY_CYCLE 55
@@ -32,6 +36,14 @@
#define ATH_BT_CNT_THRESHOLD 3
#define ATH_BT_CNT_SCAN_THRESHOLD 15
+/* Defines the BT AR_BT_COEX_WGHT used */
+enum ath_stomp_type {
+ ATH_BTCOEX_NO_STOMP,
+ ATH_BTCOEX_STOMP_ALL,
+ ATH_BTCOEX_STOMP_LOW,
+ ATH_BTCOEX_STOMP_NONE
+};
+
enum ath_btcoex_scheme {
ATH_BTCOEX_CFG_NONE,
ATH_BTCOEX_CFG_2WIRE,
@@ -57,5 +69,7 @@ void ath9k_hw_btcoex_set_weight(struct ath_hw *ah,
u32 wlan_weight);
void ath9k_hw_btcoex_enable(struct ath_hw *ah);
void ath9k_hw_btcoex_disable(struct ath_hw *ah);
+void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah,
+ enum ath_stomp_type stomp_type);
#endif
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index 8649581fa4dd..a1250c586e40 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -69,15 +69,21 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah,
int16_t *nfarray)
{
struct ath_common *common = ath9k_hw_common(ah);
+ struct ieee80211_conf *conf = &common->hw->conf;
struct ath_nf_limits *limit;
struct ath9k_nfcal_hist *h;
bool high_nf_mid = false;
+ u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
int i;
h = cal->nfCalHist;
limit = ath9k_hw_get_nf_limits(ah, ah->curchan);
for (i = 0; i < NUM_NF_READINGS; i++) {
+ if (!(chainmask & (1 << i)) ||
+ ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf)))
+ continue;
+
h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX)
@@ -225,6 +231,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
int32_t val;
u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
struct ath_common *common = ath9k_hw_common(ah);
+ struct ieee80211_conf *conf = &common->hw->conf;
s16 default_nf = ath9k_hw_get_default_nf(ah, chan);
if (ah->caldata)
@@ -234,6 +241,9 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
if (chainmask & (1 << i)) {
s16 nfval;
+ if ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf))
+ continue;
+
if (h)
nfval = h[i].privNF;
else
@@ -293,6 +303,9 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
ENABLE_REGWRITE_BUFFER(ah);
for (i = 0; i < NUM_NF_READINGS; i++) {
if (chainmask & (1 << i)) {
+ if ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf))
+ continue;
+
val = REG_READ(ah, ah->nf_regs[i]);
val &= 0xFFFFFE00;
val |= (((u32) (-50) << 1) & 0x1ff);
@@ -396,14 +409,6 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
}
}
-s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan)
-{
- if (!ah->curchan || !ah->curchan->noisefloor)
- return ath9k_hw_get_default_nf(ah, chan);
-
- return ah->curchan->noisefloor;
-}
-EXPORT_SYMBOL(ath9k_hw_getchan_noise);
void ath9k_hw_bstuck_nfcal(struct ath_hw *ah)
{
diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h
index b8973eb8d858..1bef41d1b1ff 100644
--- a/drivers/net/wireless/ath/ath9k/calib.h
+++ b/drivers/net/wireless/ath/ath9k/calib.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -106,7 +106,6 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan);
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
struct ath9k_channel *chan);
void ath9k_hw_bstuck_nfcal(struct ath_hw *ah);
-s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan);
void ath9k_hw_reset_calibration(struct ath_hw *ah,
struct ath9k_cal_list *currCal);
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c
index 615e68276e72..fa6bd2d189e5 100644
--- a/drivers/net/wireless/ath/ath9k/common.c
+++ b/drivers/net/wireless/ath/ath9k/common.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009 Atheros Communications Inc.
+ * Copyright (c) 2009-2011 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
@@ -116,7 +116,7 @@ void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan,
if (chan->band == IEEE80211_BAND_2GHZ) {
ichan->chanmode = CHANNEL_G;
- ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM | CHANNEL_G;
+ ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM;
} else {
ichan->chanmode = CHANNEL_A;
ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM;
@@ -158,37 +158,6 @@ int ath9k_cmn_count_streams(unsigned int chainmask, int max)
}
EXPORT_SYMBOL(ath9k_cmn_count_streams);
-/*
- * Configures appropriate weight based on stomp type.
- */
-void ath9k_cmn_btcoex_bt_stomp(struct ath_common *common,
- enum ath_stomp_type stomp_type)
-{
- struct ath_hw *ah = common->ah;
-
- switch (stomp_type) {
- case ATH_BTCOEX_STOMP_ALL:
- ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
- AR_STOMP_ALL_WLAN_WGHT);
- break;
- case ATH_BTCOEX_STOMP_LOW:
- ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
- AR_STOMP_LOW_WLAN_WGHT);
- break;
- case ATH_BTCOEX_STOMP_NONE:
- ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
- AR_STOMP_NONE_WLAN_WGHT);
- break;
- default:
- ath_dbg(common, ATH_DBG_BTCOEX,
- "Invalid Stomptype\n");
- break;
- }
-
- ath9k_hw_btcoex_enable(ah);
-}
-EXPORT_SYMBOL(ath9k_cmn_btcoex_bt_stomp);
-
void ath9k_cmn_update_txpow(struct ath_hw *ah, u16 cur_txpow,
u16 new_txpow, u16 *txpower)
{
diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h
index b2f7b5f89097..77ec288b5a70 100644
--- a/drivers/net/wireless/ath/ath9k/common.h
+++ b/drivers/net/wireless/ath/ath9k/common.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009 Atheros Communications Inc.
+ * Copyright (c) 2009-2011 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
@@ -50,14 +50,6 @@
#define ATH_EP_RND(x, mul) \
((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
-/* Defines the BT AR_BT_COEX_WGHT used */
-enum ath_stomp_type {
- ATH_BTCOEX_NO_STOMP,
- ATH_BTCOEX_STOMP_ALL,
- ATH_BTCOEX_STOMP_LOW,
- ATH_BTCOEX_STOMP_NONE
-};
-
int ath9k_cmn_padpos(__le16 frame_control);
int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb);
void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan,
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 8df5a92a20f1..d55ffd7d4bd2 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -326,6 +326,8 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status)
sc->debug.stats.istats.dtimsync++;
if (status & ATH9K_INT_DTIM)
sc->debug.stats.istats.dtim++;
+ if (status & ATH9K_INT_TSFOOR)
+ sc->debug.stats.istats.tsfoor++;
}
static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
@@ -380,8 +382,11 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
len += snprintf(buf + len, sizeof(buf) - len,
"%8s: %10u\n", "DTIM", sc->debug.stats.istats.dtim);
len += snprintf(buf + len, sizeof(buf) - len,
+ "%8s: %10u\n", "TSFOOR", sc->debug.stats.istats.tsfoor);
+ len += snprintf(buf + len, sizeof(buf) - len,
"%8s: %10u\n", "TOTAL", sc->debug.stats.istats.total);
+
if (len > sizeof(buf))
len = sizeof(buf);
@@ -430,6 +435,7 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
conf->channel_type,
channel_type_str(conf->channel_type));
+ ath9k_ps_wakeup(sc);
put_unaligned_le32(REG_READ_D(sc->sc_ah, AR_STA_ID0), addr);
put_unaligned_le16(REG_READ_D(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4);
len += snprintf(buf + len, sizeof(buf) - len,
@@ -439,6 +445,7 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
len += snprintf(buf + len, sizeof(buf) - len,
"addrmask: %pM\n", addr);
tmp = ath9k_hw_getrxfilter(sc->sc_ah);
+ ath9k_ps_restore(sc);
len += snprintf(buf + len, sizeof(buf) - len,
"rfilt: 0x%x", tmp);
if (tmp & ATH9K_RX_FILTER_UCAST)
@@ -720,6 +727,7 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf,
break;
}
+ ath9k_ps_wakeup(sc);
len += snprintf(buf + len, size - len,
"curbssid: %pM\n"
"OP-Mode: %s(%i)\n"
@@ -729,6 +737,7 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf,
REG_READ(ah, AR_BEACON_PERIOD));
reg = REG_READ(ah, AR_TIMER_MODE);
+ ath9k_ps_restore(sc);
len += snprintf(buf + len, size - len, "Timer-Mode-Register: 0x%x (",
reg);
if (reg & AR_TBTT_TIMER_EN)
@@ -845,7 +854,7 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
struct ath_softc *sc = file->private_data;
char *buf;
- unsigned int len = 0, size = 1152;
+ unsigned int len = 0, size = 1400;
ssize_t retval = 0;
buf = kzalloc(size, GFP_KERNEL);
@@ -874,6 +883,34 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
"%18s : %10u\n", "DECRYPT BUSY ERR",
sc->debug.stats.rxstats.decrypt_busy_err);
+ len += snprintf(buf + len, size - len,
+ "%18s : %10d\n", "RSSI-CTL0",
+ sc->debug.stats.rxstats.rs_rssi_ctl0);
+
+ len += snprintf(buf + len, size - len,
+ "%18s : %10d\n", "RSSI-CTL1",
+ sc->debug.stats.rxstats.rs_rssi_ctl1);
+
+ len += snprintf(buf + len, size - len,
+ "%18s : %10d\n", "RSSI-CTL2",
+ sc->debug.stats.rxstats.rs_rssi_ctl2);
+
+ len += snprintf(buf + len, size - len,
+ "%18s : %10d\n", "RSSI-EXT0",
+ sc->debug.stats.rxstats.rs_rssi_ext0);
+
+ len += snprintf(buf + len, size - len,
+ "%18s : %10d\n", "RSSI-EXT1",
+ sc->debug.stats.rxstats.rs_rssi_ext1);
+
+ len += snprintf(buf + len, size - len,
+ "%18s : %10d\n", "RSSI-EXT2",
+ sc->debug.stats.rxstats.rs_rssi_ext2);
+
+ len += snprintf(buf + len, size - len,
+ "%18s : %10d\n", "Rx Antenna",
+ sc->debug.stats.rxstats.rs_antenna);
+
PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN);
PHY_ERR("TIMING", ATH9K_PHYERR_TIMING);
PHY_ERR("PARITY", ATH9K_PHYERR_PARITY);
@@ -948,6 +985,16 @@ void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs)
RX_PHY_ERR_INC(phyerr);
}
+ sc->debug.stats.rxstats.rs_rssi_ctl0 = rs->rs_rssi_ctl0;
+ sc->debug.stats.rxstats.rs_rssi_ctl1 = rs->rs_rssi_ctl1;
+ sc->debug.stats.rxstats.rs_rssi_ctl2 = rs->rs_rssi_ctl2;
+
+ sc->debug.stats.rxstats.rs_rssi_ext0 = rs->rs_rssi_ext0;
+ sc->debug.stats.rxstats.rs_rssi_ext1 = rs->rs_rssi_ext1;
+ sc->debug.stats.rxstats.rs_rssi_ext2 = rs->rs_rssi_ext2;
+
+ sc->debug.stats.rxstats.rs_antenna = rs->rs_antenna;
+
#undef RX_STAT_INC
#undef RX_PHY_ERR_INC
}
@@ -1007,7 +1054,9 @@ static ssize_t read_file_regval(struct file *file, char __user *user_buf,
unsigned int len;
u32 regval;
+ ath9k_ps_wakeup(sc);
regval = REG_READ_D(ah, sc->debug.regidx);
+ ath9k_ps_restore(sc);
len = sprintf(buf, "0x%08x\n", regval);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -1029,7 +1078,9 @@ static ssize_t write_file_regval(struct file *file, const char __user *user_buf,
if (strict_strtoul(buf, 0, &regval))
return -EINVAL;
+ ath9k_ps_wakeup(sc);
REG_WRITE_D(ah, sc->debug.regidx, regval);
+ ath9k_ps_restore(sc);
return count;
}
@@ -1088,67 +1139,43 @@ int ath9k_init_debug(struct ath_hw *ah)
return -ENOMEM;
#ifdef CONFIG_ATH_DEBUG
- if (!debugfs_create_file("debug", S_IRUSR | S_IWUSR,
- sc->debug.debugfs_phy, sc, &fops_debug))
- goto err;
+ debugfs_create_file("debug", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
+ sc, &fops_debug);
#endif
-
- if (!debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy,
- sc, &fops_dma))
- goto err;
-
- if (!debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy,
- sc, &fops_interrupt))
- goto err;
-
- if (!debugfs_create_file("wiphy", S_IRUSR | S_IWUSR,
- sc->debug.debugfs_phy, sc, &fops_wiphy))
- goto err;
-
- if (!debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy,
- sc, &fops_xmit))
- goto err;
-
- if (!debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy,
- sc, &fops_stations))
- goto err;
-
- if (!debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy,
- sc, &fops_misc))
- goto err;
-
- if (!debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy,
- sc, &fops_recv))
- goto err;
-
- if (!debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR,
- sc->debug.debugfs_phy, sc, &fops_rx_chainmask))
- goto err;
-
- if (!debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR,
- sc->debug.debugfs_phy, sc, &fops_tx_chainmask))
- goto err;
-
- if (!debugfs_create_file("regidx", S_IRUSR | S_IWUSR,
- sc->debug.debugfs_phy, sc, &fops_regidx))
- goto err;
-
- if (!debugfs_create_file("regval", S_IRUSR | S_IWUSR,
- 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;
-
- if (!debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy,
- sc, &fops_regdump))
- goto err;
+ debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc,
+ &fops_dma);
+ debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, sc,
+ &fops_interrupt);
+ debugfs_create_file("wiphy", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
+ sc, &fops_wiphy);
+ debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, sc,
+ &fops_xmit);
+ debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, sc,
+ &fops_stations);
+ debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, sc,
+ &fops_misc);
+ debugfs_create_file("recv", S_IRUSR, sc->debug.debugfs_phy, sc,
+ &fops_recv);
+ debugfs_create_file("rx_chainmask", S_IRUSR | S_IWUSR,
+ sc->debug.debugfs_phy, sc, &fops_rx_chainmask);
+ debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR,
+ sc->debug.debugfs_phy, sc, &fops_tx_chainmask);
+ debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
+ sc, &fops_regidx);
+ debugfs_create_file("regval", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
+ sc, &fops_regval);
+ debugfs_create_bool("ignore_extcca", S_IRUSR | S_IWUSR,
+ sc->debug.debugfs_phy,
+ &ah->config.cwm_ignore_extcca);
+ debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, sc,
+ &fops_regdump);
+
+ debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR,
+ sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask);
+
+ debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR,
+ sc->debug.debugfs_phy, &sc->sc_ah->gpio_val);
sc->debug.regidx = 0;
return 0;
-err:
- debugfs_remove_recursive(sc->debug.debugfs_phy);
- sc->debug.debugfs_phy = NULL;
- return -ENOMEM;
}
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 59338de0ce19..8ce6ad80f4e2 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -54,6 +54,9 @@ struct ath_buf;
* @dtimsync: DTIM sync lossage
* @dtim: RX Beacon with DTIM
* @bb_watchdog: Baseband watchdog
+ * @tsfoor: TSF out of range, indicates that the corrected TSF received
+ * from a beacon differs from the PCU's internal TSF by more than a
+ * (programmable) threshold
*/
struct ath_interrupt_stats {
u32 total;
@@ -78,6 +81,7 @@ struct ath_interrupt_stats {
u32 dtimsync;
u32 dtim;
u32 bb_watchdog;
+ u32 tsfoor;
};
/**
@@ -157,6 +161,13 @@ struct ath_rx_stats {
u32 post_delim_crc_err;
u32 decrypt_busy_err;
u32 phy_err_stats[ATH9K_PHYERR_MAX];
+ int8_t rs_rssi_ctl0;
+ int8_t rs_rssi_ctl1;
+ int8_t rs_rssi_ctl2;
+ int8_t rs_rssi_ext0;
+ int8_t rs_rssi_ext1;
+ int8_t rs_rssi_ext2;
+ u8 rs_antenna;
};
struct ath_stats {
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c
index 8c18bed3a558..e61404dda8c5 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h
index bd82447f5b78..de99c0da52e4 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/eeprom.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -436,7 +436,11 @@ struct modal_eep_4k_header {
u8 db2_2:4, db2_3:4;
u8 db2_4:4, reserved:4;
#endif
- u8 futureModal[4];
+ u8 tx_diversity;
+ u8 flc_pwr_thresh;
+ u8 bb_scale_smrt_antenna;
+#define EEP_4K_BB_DESIRED_SCALE_MASK 0x1f
+ u8 futureModal[1];
struct spur_chan spurChans[AR_EEPROM_MODAL_SPURS];
} __packed;
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
index bc77a308c901..5b1e894f3d67 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -781,6 +781,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
{
struct modal_eep_4k_header *pModal;
struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
+ struct base_eep_header_4k *pBase = &eep->baseEepHeader;
u8 txRxAttenLocal;
u8 ob[5], db1[5], db2[5];
u8 ant_div_control1, ant_div_control2;
@@ -1003,6 +1004,31 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
AR_PHY_SETTLING_SWITCH,
pModal->swSettleHt40);
}
+ if (AR_SREV_9271(ah) || AR_SREV_9285(ah)) {
+ u8 bb_desired_scale = (pModal->bb_scale_smrt_antenna &
+ EEP_4K_BB_DESIRED_SCALE_MASK);
+ if ((pBase->txGainType == 0) && (bb_desired_scale != 0)) {
+ u32 pwrctrl, mask, clr;
+
+ mask = BIT(0)|BIT(5)|BIT(10)|BIT(15)|BIT(20)|BIT(25);
+ pwrctrl = mask * bb_desired_scale;
+ clr = mask * 0x1f;
+ REG_RMW(ah, AR_PHY_TX_PWRCTRL8, pwrctrl, clr);
+ REG_RMW(ah, AR_PHY_TX_PWRCTRL10, pwrctrl, clr);
+ REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL12, pwrctrl, clr);
+
+ mask = BIT(0)|BIT(5)|BIT(15);
+ pwrctrl = mask * bb_desired_scale;
+ clr = mask * 0x1f;
+ REG_RMW(ah, AR_PHY_TX_PWRCTRL9, pwrctrl, clr);
+
+ mask = BIT(0)|BIT(5);
+ pwrctrl = mask * bb_desired_scale;
+ clr = mask * 0x1f;
+ REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL11, pwrctrl, clr);
+ REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL13, pwrctrl, clr);
+ }
+ }
}
static u16 ath9k_hw_4k_get_spur_channel(struct ath_hw *ah, u16 i, bool is2GHz)
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
index 8cd8333cc086..7856f0d4512d 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -319,10 +319,9 @@ static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah,
u16 numXpdGain, xpdMask;
u16 xpdGainValues[AR5416_NUM_PD_GAINS] = {0, 0, 0, 0};
u32 reg32, regOffset, regChainOffset, regval;
- int16_t modalIdx, diff = 0;
+ int16_t 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) >=
@@ -392,6 +391,8 @@ static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah,
numXpdGain);
}
+ ENABLE_REGWRITE_BUFFER(ah);
+
if (i == 0) {
if (!ath9k_hw_ar9287_get_eeprom(ah,
EEP_OL_PWRCTRL)) {
@@ -442,6 +443,7 @@ static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah,
regOffset += 4;
}
}
+ REGWRITE_BUFFER_FLUSH(ah);
}
}
@@ -757,6 +759,8 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2;
}
+ ENABLE_REGWRITE_BUFFER(ah);
+
/* OFDM power per rate */
REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
ATH9K_POW_SM(ratesArray[rate18mb], 24)
@@ -840,6 +844,7 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
| ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
| ATH9K_POW_SM(ratesArray[rateDupCck], 0));
}
+ REGWRITE_BUFFER_FLUSH(ah);
}
static void ath9k_hw_ar9287_set_addac(struct ath_hw *ah,
@@ -852,35 +857,12 @@ static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah,
{
struct ar9287_eeprom *eep = &ah->eeprom.map9287;
struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
- u16 antWrites[AR9287_ANT_16S];
u32 regChainOffset, regval;
u8 txRxAttenLocal;
- int i, j, offset_num;
+ int i;
pModal = &eep->modalHeader;
- antWrites[0] = (u16)((pModal->antCtrlCommon >> 28) & 0xF);
- antWrites[1] = (u16)((pModal->antCtrlCommon >> 24) & 0xF);
- antWrites[2] = (u16)((pModal->antCtrlCommon >> 20) & 0xF);
- antWrites[3] = (u16)((pModal->antCtrlCommon >> 16) & 0xF);
- antWrites[4] = (u16)((pModal->antCtrlCommon >> 12) & 0xF);
- antWrites[5] = (u16)((pModal->antCtrlCommon >> 8) & 0xF);
- antWrites[6] = (u16)((pModal->antCtrlCommon >> 4) & 0xF);
- antWrites[7] = (u16)(pModal->antCtrlCommon & 0xF);
-
- offset_num = 8;
-
- for (i = 0, j = offset_num; i < AR9287_MAX_CHAINS; i++) {
- antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 28) & 0xf);
- antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 10) & 0x3);
- antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 8) & 0x3);
- antWrites[j++] = 0;
- antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 6) & 0x3);
- antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 4) & 0x3);
- antWrites[j++] = (u16)((pModal->antCtrlChain[i] >> 2) & 0x3);
- antWrites[j++] = (u16)(pModal->antCtrlChain[i] & 0x3);
- }
-
REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon);
for (i = 0; i < AR9287_MAX_CHAINS; i++) {
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c
index fccd87df7300..17f0a6806207 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -231,6 +231,10 @@ static int ath9k_hw_def_check_eeprom(struct ath_hw *ah)
integer = swab32(pModal->antCtrlChain[i]);
pModal->antCtrlChain[i] = integer;
}
+ for (i = 0; i < 3; i++) {
+ word = swab16(pModal->xpaBiasLvlFreq[i]);
+ pModal->xpaBiasLvlFreq[i] = word;
+ }
for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) {
word = swab16(pModal->spurChans[i].spurChan);
@@ -799,6 +803,8 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
pwr_table_offset,
&diff);
+ ENABLE_REGWRITE_BUFFER(ah);
+
if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) {
if (OLC_FOR_AR9280_20_LATER) {
REG_WRITE(ah,
@@ -847,6 +853,7 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
regOffset += 4;
}
+ REGWRITE_BUFFER_FLUSH(ah);
}
}
@@ -1205,6 +1212,8 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
}
}
+ ENABLE_REGWRITE_BUFFER(ah);
+
REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
ATH9K_POW_SM(ratesArray[rate18mb], 24)
| ATH9K_POW_SM(ratesArray[rate12mb], 16)
@@ -1291,6 +1300,8 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6)
| ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0));
+
+ REGWRITE_BUFFER_FLUSH(ah);
}
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 0fb8f8ac275a..bc713fc28191 100644
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -41,12 +41,16 @@ void ath_init_leds(struct ath_softc *sc)
{
int ret;
- if (AR_SREV_9287(sc->sc_ah))
- sc->sc_ah->led_pin = ATH_LED_PIN_9287;
- else if (AR_SREV_9485(sc->sc_ah))
- sc->sc_ah->led_pin = ATH_LED_PIN_9485;
- else
- sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
+ if (sc->sc_ah->led_pin < 0) {
+ if (AR_SREV_9287(sc->sc_ah))
+ sc->sc_ah->led_pin = ATH_LED_PIN_9287;
+ else if (AR_SREV_9485(sc->sc_ah))
+ sc->sc_ah->led_pin = ATH_LED_PIN_9485;
+ else if (AR_SREV_9300(sc->sc_ah))
+ sc->sc_ah->led_pin = ATH_LED_PIN_9300;
+ else
+ sc->sc_ah->led_pin = ATH_LED_PIN_DEF;
+ }
/* Configure gpio 1 for output */
ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin,
@@ -136,10 +140,10 @@ static void ath_detect_bt_priority(struct ath_softc *sc)
static void ath9k_gen_timer_start(struct ath_hw *ah,
struct ath_gen_timer *timer,
- u32 timer_next,
+ u32 trig_timeout,
u32 timer_period)
{
- ath9k_hw_gen_timer_start(ah, timer, timer_next, timer_period);
+ ath9k_hw_gen_timer_start(ah, timer, trig_timeout, timer_period);
if ((ah->imask & ATH9K_INT_GENTIMER) == 0) {
ath9k_hw_disable_interrupts(ah);
@@ -172,17 +176,17 @@ static void ath_btcoex_period_timer(unsigned long data)
struct ath_softc *sc = (struct ath_softc *) data;
struct ath_hw *ah = sc->sc_ah;
struct ath_btcoex *btcoex = &sc->btcoex;
- struct ath_common *common = ath9k_hw_common(ah);
u32 timer_period;
bool is_btscan;
+ ath9k_ps_wakeup(sc);
ath_detect_bt_priority(sc);
is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
spin_lock_bh(&btcoex->btcoex_lock);
- ath9k_cmn_btcoex_bt_stomp(common, is_btscan ? ATH_BTCOEX_STOMP_ALL :
+ ath9k_hw_btcoex_bt_stomp(ah, is_btscan ? ATH_BTCOEX_STOMP_ALL :
btcoex->bt_stomp_type);
spin_unlock_bh(&btcoex->btcoex_lock);
@@ -193,11 +197,12 @@ static void ath_btcoex_period_timer(unsigned long data)
timer_period = is_btscan ? btcoex->btscan_no_stomp :
btcoex->btcoex_no_stomp;
- ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, 0,
+ ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, timer_period,
timer_period * 10);
btcoex->hw_timer_enabled = true;
}
+ ath9k_ps_restore(sc);
mod_timer(&btcoex->period_timer, jiffies +
msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD));
}
@@ -217,14 +222,16 @@ static void ath_btcoex_no_stomp_timer(void *arg)
ath_dbg(common, ATH_DBG_BTCOEX,
"no stomp timer running\n");
+ ath9k_ps_wakeup(sc);
spin_lock_bh(&btcoex->btcoex_lock);
if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan)
- ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_NONE);
+ ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
- ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_LOW);
+ ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW);
spin_unlock_bh(&btcoex->btcoex_lock);
+ ath9k_ps_restore(sc);
}
int ath_init_btcoex_timer(struct ath_softc *sc)
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 2d10239ce829..260f1f37a60e 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 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,11 +17,9 @@
#include "htc.h"
/* identify firmware images */
-#define FIRMWARE_AR7010 "ar7010.fw"
-#define FIRMWARE_AR7010_1_1 "ar7010_1_1.fw"
-#define FIRMWARE_AR9271 "ar9271.fw"
+#define FIRMWARE_AR7010_1_1 "htc_7010.fw"
+#define FIRMWARE_AR9271 "htc_9271.fw"
-MODULE_FIRMWARE(FIRMWARE_AR7010);
MODULE_FIRMWARE(FIRMWARE_AR7010_1_1);
MODULE_FIRMWARE(FIRMWARE_AR9271);
@@ -80,7 +78,7 @@ static void hif_usb_regout_cb(struct urb *urb)
if (cmd) {
ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle,
- cmd->skb, 1);
+ cmd->skb, true);
kfree(cmd);
}
@@ -126,6 +124,90 @@ static int hif_usb_send_regout(struct hif_device_usb *hif_dev,
return ret;
}
+static void hif_usb_mgmt_cb(struct urb *urb)
+{
+ struct cmd_buf *cmd = (struct cmd_buf *)urb->context;
+ struct hif_device_usb *hif_dev = cmd->hif_dev;
+ bool txok = true;
+
+ if (!cmd || !cmd->skb || !cmd->hif_dev)
+ return;
+
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ENOENT:
+ case -ECONNRESET:
+ case -ENODEV:
+ case -ESHUTDOWN:
+ txok = false;
+
+ /*
+ * If the URBs are being flushed, no need to complete
+ * this packet.
+ */
+ spin_lock(&hif_dev->tx.tx_lock);
+ if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) {
+ spin_unlock(&hif_dev->tx.tx_lock);
+ dev_kfree_skb_any(cmd->skb);
+ kfree(cmd);
+ return;
+ }
+ spin_unlock(&hif_dev->tx.tx_lock);
+
+ break;
+ default:
+ txok = false;
+ break;
+ }
+
+ skb_pull(cmd->skb, 4);
+ ath9k_htc_txcompletion_cb(cmd->hif_dev->htc_handle,
+ cmd->skb, txok);
+ kfree(cmd);
+}
+
+static int hif_usb_send_mgmt(struct hif_device_usb *hif_dev,
+ struct sk_buff *skb)
+{
+ struct urb *urb;
+ struct cmd_buf *cmd;
+ int ret = 0;
+ __le16 *hdr;
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (urb == NULL)
+ return -ENOMEM;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_ATOMIC);
+ if (cmd == NULL) {
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
+
+ cmd->skb = skb;
+ cmd->hif_dev = hif_dev;
+
+ hdr = (__le16 *) skb_push(skb, 4);
+ *hdr++ = cpu_to_le16(skb->len - 4);
+ *hdr++ = cpu_to_le16(ATH_USB_TX_STREAM_MODE_TAG);
+
+ usb_fill_bulk_urb(urb, hif_dev->udev,
+ usb_sndbulkpipe(hif_dev->udev, USB_WLAN_TX_PIPE),
+ skb->data, skb->len,
+ hif_usb_mgmt_cb, cmd);
+
+ usb_anchor_urb(urb, &hif_dev->mgmt_submitted);
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret) {
+ usb_unanchor_urb(urb);
+ kfree(cmd);
+ }
+ usb_free_urb(urb);
+
+ return ret;
+}
+
static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev,
struct sk_buff_head *list)
{
@@ -133,7 +215,22 @@ static inline void ath9k_skb_queue_purge(struct hif_device_usb *hif_dev,
while ((skb = __skb_dequeue(list)) != NULL) {
dev_kfree_skb_any(skb);
- TX_STAT_INC(skb_dropped);
+ }
+}
+
+static inline void ath9k_skb_queue_complete(struct hif_device_usb *hif_dev,
+ struct sk_buff_head *queue,
+ bool txok)
+{
+ struct sk_buff *skb;
+
+ while ((skb = __skb_dequeue(queue)) != NULL) {
+ ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
+ skb, txok);
+ if (txok)
+ TX_STAT_INC(skb_success);
+ else
+ TX_STAT_INC(skb_failed);
}
}
@@ -141,7 +238,7 @@ static void hif_usb_tx_cb(struct urb *urb)
{
struct tx_buf *tx_buf = (struct tx_buf *) urb->context;
struct hif_device_usb *hif_dev;
- struct sk_buff *skb;
+ bool txok = true;
if (!tx_buf || !tx_buf->hif_dev)
return;
@@ -155,10 +252,7 @@ static void hif_usb_tx_cb(struct urb *urb)
case -ECONNRESET:
case -ENODEV:
case -ESHUTDOWN:
- /*
- * The URB has been killed, free the SKBs.
- */
- ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
+ txok = false;
/*
* If the URBs are being flushed, no need to add this
@@ -167,41 +261,19 @@ static void hif_usb_tx_cb(struct urb *urb)
spin_lock(&hif_dev->tx.tx_lock);
if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) {
spin_unlock(&hif_dev->tx.tx_lock);
+ ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
return;
}
spin_unlock(&hif_dev->tx.tx_lock);
- /*
- * In the stop() case, this URB has to be added to
- * the free list.
- */
- goto add_free;
+ break;
default:
+ txok = false;
break;
}
- /*
- * Check if TX has been stopped, this is needed because
- * this CB could have been invoked just after the TX lock
- * was released in hif_stop() and kill_urb() hasn't been
- * called yet.
- */
- spin_lock(&hif_dev->tx.tx_lock);
- if (hif_dev->tx.flags & HIF_USB_TX_STOP) {
- spin_unlock(&hif_dev->tx.tx_lock);
- ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
- goto add_free;
- }
- spin_unlock(&hif_dev->tx.tx_lock);
-
- /* Complete the queued SKBs. */
- while ((skb = __skb_dequeue(&tx_buf->skb_queue)) != NULL) {
- ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
- skb, 1);
- TX_STAT_INC(skb_completed);
- }
+ ath9k_skb_queue_complete(hif_dev, &tx_buf->skb_queue, txok);
-add_free:
/* Re-initialize the SKB queue */
tx_buf->len = tx_buf->offset = 0;
__skb_queue_head_init(&tx_buf->skb_queue);
@@ -274,7 +346,7 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev)
ret = usb_submit_urb(tx_buf->urb, GFP_ATOMIC);
if (ret) {
tx_buf->len = tx_buf->offset = 0;
- ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
+ ath9k_skb_queue_complete(hif_dev, &tx_buf->skb_queue, false);
__skb_queue_head_init(&tx_buf->skb_queue);
list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf);
hif_dev->tx.tx_buf_cnt++;
@@ -286,10 +358,11 @@ static int __hif_usb_tx(struct hif_device_usb *hif_dev)
return ret;
}
-static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb,
- struct ath9k_htc_tx_ctl *tx_ctl)
+static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb)
{
+ struct ath9k_htc_tx_ctl *tx_ctl;
unsigned long flags;
+ int ret = 0;
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
@@ -304,26 +377,36 @@ static int hif_usb_send_tx(struct hif_device_usb *hif_dev, struct sk_buff *skb,
return -ENOMEM;
}
- __skb_queue_tail(&hif_dev->tx.tx_skb_queue, skb);
- hif_dev->tx.tx_skb_cnt++;
+ spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
- /* Send normal frames immediately */
- if (!tx_ctl || (tx_ctl && (tx_ctl->type == ATH9K_HTC_NORMAL)))
- __hif_usb_tx(hif_dev);
+ tx_ctl = HTC_SKB_CB(skb);
+
+ /* Mgmt/Beacon frames don't use the TX buffer pool */
+ if ((tx_ctl->type == ATH9K_HTC_MGMT) ||
+ (tx_ctl->type == ATH9K_HTC_BEACON)) {
+ ret = hif_usb_send_mgmt(hif_dev, skb);
+ }
+
+ spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
+
+ if ((tx_ctl->type == ATH9K_HTC_NORMAL) ||
+ (tx_ctl->type == ATH9K_HTC_AMPDU)) {
+ __skb_queue_tail(&hif_dev->tx.tx_skb_queue, skb);
+ hif_dev->tx.tx_skb_cnt++;
+ }
/* Check if AMPDUs have to be sent immediately */
- if (tx_ctl && (tx_ctl->type == ATH9K_HTC_AMPDU) &&
- (hif_dev->tx.tx_buf_cnt == MAX_TX_URB_NUM) &&
+ if ((hif_dev->tx.tx_buf_cnt == MAX_TX_URB_NUM) &&
(hif_dev->tx.tx_skb_cnt < 2)) {
__hif_usb_tx(hif_dev);
}
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
- return 0;
+ return ret;
}
-static void hif_usb_start(void *hif_handle, u8 pipe_id)
+static void hif_usb_start(void *hif_handle)
{
struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
unsigned long flags;
@@ -335,14 +418,14 @@ static void hif_usb_start(void *hif_handle, u8 pipe_id)
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
}
-static void hif_usb_stop(void *hif_handle, u8 pipe_id)
+static void hif_usb_stop(void *hif_handle)
{
struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
struct tx_buf *tx_buf = NULL, *tx_buf_tmp = NULL;
unsigned long flags;
spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
- ath9k_skb_queue_purge(hif_dev, &hif_dev->tx.tx_skb_queue);
+ ath9k_skb_queue_complete(hif_dev, &hif_dev->tx.tx_skb_queue, false);
hif_dev->tx.tx_skb_cnt = 0;
hif_dev->tx.flags |= HIF_USB_TX_STOP;
spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
@@ -352,17 +435,18 @@ static void hif_usb_stop(void *hif_handle, u8 pipe_id)
&hif_dev->tx.tx_pending, list) {
usb_kill_urb(tx_buf->urb);
}
+
+ usb_kill_anchored_urbs(&hif_dev->mgmt_submitted);
}
-static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb,
- struct ath9k_htc_tx_ctl *tx_ctl)
+static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb)
{
struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
int ret = 0;
switch (pipe_id) {
case USB_WLAN_TX_PIPE:
- ret = hif_usb_send_tx(hif_dev, skb, tx_ctl);
+ ret = hif_usb_send_tx(hif_dev, skb);
break;
case USB_REG_OUT_PIPE:
ret = hif_usb_send_regout(hif_dev, skb);
@@ -377,6 +461,40 @@ static int hif_usb_send(void *hif_handle, u8 pipe_id, struct sk_buff *skb,
return ret;
}
+static inline bool check_index(struct sk_buff *skb, u8 idx)
+{
+ struct ath9k_htc_tx_ctl *tx_ctl;
+
+ tx_ctl = HTC_SKB_CB(skb);
+
+ if ((tx_ctl->type == ATH9K_HTC_AMPDU) &&
+ (tx_ctl->sta_idx == idx))
+ return true;
+
+ return false;
+}
+
+static void hif_usb_sta_drain(void *hif_handle, u8 idx)
+{
+ struct hif_device_usb *hif_dev = (struct hif_device_usb *)hif_handle;
+ struct sk_buff *skb, *tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
+
+ skb_queue_walk_safe(&hif_dev->tx.tx_skb_queue, skb, tmp) {
+ if (check_index(skb, idx)) {
+ __skb_unlink(skb, &hif_dev->tx.tx_skb_queue);
+ ath9k_htc_txcompletion_cb(hif_dev->htc_handle,
+ skb, false);
+ hif_dev->tx.tx_skb_cnt--;
+ TX_STAT_INC(skb_failed);
+ }
+ }
+
+ spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
+}
+
static struct ath9k_htc_hif hif_usb = {
.transport = ATH9K_HIF_USB,
.name = "ath9k_hif_usb",
@@ -386,6 +504,7 @@ static struct ath9k_htc_hif hif_usb = {
.start = hif_usb_start,
.stop = hif_usb_stop,
+ .sta_drain = hif_usb_sta_drain,
.send = hif_usb_send,
};
@@ -567,6 +686,9 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
case -ESHUTDOWN:
goto free;
default:
+ skb_reset_tail_pointer(skb);
+ skb_trim(skb, 0);
+
goto resubmit;
}
@@ -591,23 +713,15 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
USB_REG_IN_PIPE),
nskb->data, MAX_REG_IN_BUF_SIZE,
ath9k_hif_usb_reg_in_cb, nskb);
-
- ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret) {
- kfree_skb(nskb);
- urb->context = NULL;
- }
-
- return;
}
resubmit:
- skb_reset_tail_pointer(skb);
- skb_trim(skb, 0);
-
+ usb_anchor_urb(urb, &hif_dev->reg_in_submitted);
ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret)
+ if (ret) {
+ usb_unanchor_urb(urb);
goto free;
+ }
return;
free:
@@ -641,6 +755,8 @@ static void ath9k_hif_usb_dealloc_tx_urbs(struct hif_device_usb *hif_dev)
kfree(tx_buf->buf);
kfree(tx_buf);
}
+
+ usb_kill_anchored_urbs(&hif_dev->mgmt_submitted);
}
static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev)
@@ -652,6 +768,7 @@ static int ath9k_hif_usb_alloc_tx_urbs(struct hif_device_usb *hif_dev)
INIT_LIST_HEAD(&hif_dev->tx.tx_pending);
spin_lock_init(&hif_dev->tx.tx_lock);
__skb_queue_head_init(&hif_dev->tx.tx_skb_queue);
+ init_usb_anchor(&hif_dev->mgmt_submitted);
for (i = 0; i < MAX_TX_URB_NUM; i++) {
tx_buf = kzalloc(sizeof(struct tx_buf), GFP_KERNEL);
@@ -748,43 +865,67 @@ err_urb:
return ret;
}
-static void ath9k_hif_usb_dealloc_reg_in_urb(struct hif_device_usb *hif_dev)
+static void ath9k_hif_usb_dealloc_reg_in_urbs(struct hif_device_usb *hif_dev)
{
- if (hif_dev->reg_in_urb) {
- usb_kill_urb(hif_dev->reg_in_urb);
- if (hif_dev->reg_in_urb->context)
- kfree_skb((void *)hif_dev->reg_in_urb->context);
- usb_free_urb(hif_dev->reg_in_urb);
- hif_dev->reg_in_urb = NULL;
- }
+ usb_kill_anchored_urbs(&hif_dev->reg_in_submitted);
}
-static int ath9k_hif_usb_alloc_reg_in_urb(struct hif_device_usb *hif_dev)
+static int ath9k_hif_usb_alloc_reg_in_urbs(struct hif_device_usb *hif_dev)
{
- struct sk_buff *skb;
+ struct urb *urb = NULL;
+ struct sk_buff *skb = NULL;
+ int i, ret;
- hif_dev->reg_in_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (hif_dev->reg_in_urb == NULL)
- return -ENOMEM;
+ init_usb_anchor(&hif_dev->reg_in_submitted);
- skb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_KERNEL);
- if (!skb)
- goto err;
+ for (i = 0; i < MAX_REG_IN_URB_NUM; i++) {
- usb_fill_bulk_urb(hif_dev->reg_in_urb, hif_dev->udev,
- usb_rcvbulkpipe(hif_dev->udev,
- USB_REG_IN_PIPE),
- skb->data, MAX_REG_IN_BUF_SIZE,
- ath9k_hif_usb_reg_in_cb, skb);
+ /* Allocate URB */
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (urb == NULL) {
+ ret = -ENOMEM;
+ goto err_urb;
+ }
- if (usb_submit_urb(hif_dev->reg_in_urb, GFP_KERNEL) != 0)
- goto err;
+ /* Allocate buffer */
+ skb = alloc_skb(MAX_REG_IN_BUF_SIZE, GFP_KERNEL);
+ if (!skb) {
+ ret = -ENOMEM;
+ goto err_skb;
+ }
+
+ usb_fill_bulk_urb(urb, hif_dev->udev,
+ usb_rcvbulkpipe(hif_dev->udev,
+ USB_REG_IN_PIPE),
+ skb->data, MAX_REG_IN_BUF_SIZE,
+ ath9k_hif_usb_reg_in_cb, skb);
+
+ /* Anchor URB */
+ usb_anchor_urb(urb, &hif_dev->reg_in_submitted);
+
+ /* Submit URB */
+ ret = usb_submit_urb(urb, GFP_KERNEL);
+ if (ret) {
+ usb_unanchor_urb(urb);
+ goto err_submit;
+ }
+
+ /*
+ * Drop reference count.
+ * This ensures that the URB is freed when killing them.
+ */
+ usb_free_urb(urb);
+ }
return 0;
-err:
- ath9k_hif_usb_dealloc_reg_in_urb(hif_dev);
- return -ENOMEM;
+err_submit:
+ kfree_skb(skb);
+err_skb:
+ usb_free_urb(urb);
+err_urb:
+ ath9k_hif_usb_dealloc_reg_in_urbs(hif_dev);
+ return ret;
}
static int ath9k_hif_usb_alloc_urbs(struct hif_device_usb *hif_dev)
@@ -801,7 +942,7 @@ static int ath9k_hif_usb_alloc_urbs(struct hif_device_usb *hif_dev)
goto err_rx;
/* Register Read */
- if (ath9k_hif_usb_alloc_reg_in_urb(hif_dev) < 0)
+ if (ath9k_hif_usb_alloc_reg_in_urbs(hif_dev) < 0)
goto err_reg;
return 0;
@@ -816,7 +957,7 @@ err:
static void ath9k_hif_usb_dealloc_urbs(struct hif_device_usb *hif_dev)
{
usb_kill_anchored_urbs(&hif_dev->regout_submitted);
- ath9k_hif_usb_dealloc_reg_in_urb(hif_dev);
+ ath9k_hif_usb_dealloc_reg_in_urbs(hif_dev);
ath9k_hif_usb_dealloc_tx_urbs(hif_dev);
ath9k_hif_usb_dealloc_rx_urbs(hif_dev);
}
@@ -1026,10 +1167,7 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
/* Find out which firmware to load */
if (IS_AR7010_DEVICE(id->driver_info))
- if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x0202)
- hif_dev->fw_name = FIRMWARE_AR7010_1_1;
- else
- hif_dev->fw_name = FIRMWARE_AR7010;
+ hif_dev->fw_name = FIRMWARE_AR7010_1_1;
else
hif_dev->fw_name = FIRMWARE_AR9271;
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h
index 7b9d863d4035..794f63094e5d 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.h
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 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,6 +17,9 @@
#ifndef HTC_USB_H
#define HTC_USB_H
+#define MAJOR_VERSION_REQ 1
+#define MINOR_VERSION_REQ 3
+
#define IS_AR7010_DEVICE(_v) (((_v) == AR9280_USB) || ((_v) == AR9287_USB))
#define AR9271_FIRMWARE 0x501000
@@ -31,7 +34,7 @@
/* FIXME: Verify these numbers (with Windows) */
#define MAX_TX_URB_NUM 8
-#define MAX_TX_BUF_NUM 1024
+#define MAX_TX_BUF_NUM 256
#define MAX_TX_BUF_SIZE 32768
#define MAX_TX_AGGR_NUM 20
@@ -40,7 +43,7 @@
#define MAX_PKT_NUM_IN_TRANSFER 10
#define MAX_REG_OUT_URB_NUM 1
-#define MAX_REG_OUT_BUF_NUM 8
+#define MAX_REG_IN_URB_NUM 64
#define MAX_REG_IN_BUF_SIZE 64
@@ -90,9 +93,10 @@ struct hif_device_usb {
const struct firmware *firmware;
struct htc_target *htc_handle;
struct hif_usb_tx tx;
- struct urb *reg_in_urb;
struct usb_anchor regout_submitted;
struct usb_anchor rx_submitted;
+ struct usb_anchor reg_in_submitted;
+ struct usb_anchor mgmt_submitted;
struct sk_buff *remain_skb;
const char *fw_name;
int rx_remain_len;
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index 753a245c5ad1..5bc022087e65 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 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
@@ -46,15 +46,8 @@ extern struct ieee80211_ops ath9k_htc_ops;
extern int htc_modparam_nohwcrypt;
enum htc_phymode {
- HTC_MODE_AUTO = 0,
- HTC_MODE_11A = 1,
- HTC_MODE_11B = 2,
- HTC_MODE_11G = 3,
- HTC_MODE_FH = 4,
- HTC_MODE_TURBO_A = 5,
- HTC_MODE_TURBO_G = 6,
- HTC_MODE_11NA = 7,
- HTC_MODE_11NG = 8
+ HTC_MODE_11NA = 0,
+ HTC_MODE_11NG = 1
};
enum htc_opmode {
@@ -66,13 +59,13 @@ enum htc_opmode {
HTC_M_WDS = 2
};
-#define ATH9K_HTC_HDRSPACE sizeof(struct htc_frame_hdr)
-#define ATH9K_HTC_AMPDU 1
+#define ATH9K_HTC_AMPDU 1
#define ATH9K_HTC_NORMAL 2
+#define ATH9K_HTC_BEACON 3
+#define ATH9K_HTC_MGMT 4
#define ATH9K_HTC_TX_CTSONLY 0x1
#define ATH9K_HTC_TX_RTSCTS 0x2
-#define ATH9K_HTC_TX_USE_MIN_RATE 0x100
struct tx_frame_hdr {
u8 data_type;
@@ -82,7 +75,8 @@ struct tx_frame_hdr {
__be32 flags; /* ATH9K_HTC_TX_* */
u8 key_type;
u8 keyix;
- u8 reserved[26];
+ u8 cookie;
+ u8 pad;
} __packed;
struct tx_mgmt_hdr {
@@ -92,78 +86,46 @@ struct tx_mgmt_hdr {
u8 flags;
u8 key_type;
u8 keyix;
- u16 reserved;
+ u8 cookie;
+ u8 pad;
} __packed;
struct tx_beacon_header {
- u8 len_changed;
u8 vif_index;
+ u8 len_changed;
u16 rev;
} __packed;
-struct ath9k_htc_target_hw {
- u32 flags;
- u32 flags_ext;
- u32 ampdu_limit;
- u8 ampdu_subframes;
- u8 tx_chainmask;
- u8 tx_chainmask_legacy;
- u8 rtscts_ratecode;
- u8 protmode;
-} __packed;
+#define MAX_TX_AMPDU_SUBFRAMES_9271 17
+#define MAX_TX_AMPDU_SUBFRAMES_7010 22
struct ath9k_htc_cap_target {
- u32 flags;
- u32 flags_ext;
- u32 ampdu_limit;
+ __be32 ampdu_limit;
u8 ampdu_subframes;
+ u8 enable_coex;
u8 tx_chainmask;
- u8 tx_chainmask_legacy;
- u8 rtscts_ratecode;
- u8 protmode;
+ u8 pad;
} __packed;
struct ath9k_htc_target_vif {
u8 index;
- u8 des_bssid[ETH_ALEN];
- __be32 opmode;
+ u8 opmode;
u8 myaddr[ETH_ALEN];
- u8 bssid[ETH_ALEN];
- u32 flags;
- u32 flags_ext;
- u16 ps_sta;
- __be16 rtsthreshold;
u8 ath_cap;
- u8 node;
- s8 mcast_rate;
+ __be16 rtsthreshold;
+ u8 pad;
} __packed;
-#define ATH_HTC_STA_AUTH 0x0001
-#define ATH_HTC_STA_QOS 0x0002
-#define ATH_HTC_STA_ERP 0x0004
-#define ATH_HTC_STA_HT 0x0008
-
-/* FIXME: UAPSD variables */
struct ath9k_htc_target_sta {
- u16 associd;
- u16 txpower;
- u32 ucastkey;
u8 macaddr[ETH_ALEN];
u8 bssid[ETH_ALEN];
u8 sta_index;
u8 vif_index;
- u8 vif_sta;
- __be16 flags; /* ATH_HTC_STA_* */
- u16 htcap;
- u8 valid;
- u16 capinfo;
- struct ath9k_htc_target_hw *hw;
- struct ath9k_htc_target_vif *vif;
- u16 txseqmgmt;
u8 is_vif_sta;
- u16 maxampdu;
- u16 iv16;
- u32 iv32;
+ __be16 flags;
+ __be16 htcap;
+ __be16 maxampdu;
+ u8 pad;
} __packed;
struct ath9k_htc_target_aggr {
@@ -197,12 +159,38 @@ struct ath9k_htc_target_rate {
struct ath9k_htc_rate rates;
};
-struct ath9k_htc_target_stats {
- __be32 tx_shortretry;
- __be32 tx_longretry;
- __be32 tx_xretries;
- __be32 ht_txunaggr_xretry;
- __be32 ht_tx_xretries;
+struct ath9k_htc_target_rate_mask {
+ u8 vif_index;
+ u8 band;
+ __be32 mask;
+ u16 pad;
+} __packed;
+
+struct ath9k_htc_target_int_stats {
+ __be32 rx;
+ __be32 rxorn;
+ __be32 rxeol;
+ __be32 txurn;
+ __be32 txto;
+ __be32 cst;
+} __packed;
+
+struct ath9k_htc_target_tx_stats {
+ __be32 xretries;
+ __be32 fifoerr;
+ __be32 filtered;
+ __be32 timer_exp;
+ __be32 shortretries;
+ __be32 longretries;
+ __be32 qnull;
+ __be32 encap_fail;
+ __be32 nobuf;
+} __packed;
+
+struct ath9k_htc_target_rx_stats {
+ __be32 nobuf;
+ __be32 host_send;
+ __be32 host_done;
} __packed;
#define ATH9K_HTC_MAX_VIF 2
@@ -244,6 +232,8 @@ struct ath9k_htc_vif {
u8 index;
u16 seq_no;
bool beacon_configured;
+ int bslot;
+ __le64 tsfadjust;
};
struct ath9k_vif_iter_data {
@@ -282,23 +272,65 @@ struct ath9k_htc_rx {
spinlock_t rxbuflock;
};
+#define ATH9K_HTC_TX_CLEANUP_INTERVAL 50 /* ms */
+#define ATH9K_HTC_TX_TIMEOUT_INTERVAL 3000 /* ms */
+#define ATH9K_HTC_TX_RESERVE 10
+#define ATH9K_HTC_TX_TIMEOUT_COUNT 40
+#define ATH9K_HTC_TX_THRESHOLD (MAX_TX_BUF_NUM - ATH9K_HTC_TX_RESERVE)
+
+#define ATH9K_HTC_OP_TX_QUEUES_STOP BIT(0)
+#define ATH9K_HTC_OP_TX_DRAIN BIT(1)
+
+struct ath9k_htc_tx {
+ u8 flags;
+ int queued_cnt;
+ struct sk_buff_head mgmt_ep_queue;
+ struct sk_buff_head cab_ep_queue;
+ struct sk_buff_head data_be_queue;
+ struct sk_buff_head data_bk_queue;
+ struct sk_buff_head data_vi_queue;
+ struct sk_buff_head data_vo_queue;
+ struct sk_buff_head tx_failed;
+ DECLARE_BITMAP(tx_slot, MAX_TX_BUF_NUM);
+ struct timer_list cleanup_timer;
+ spinlock_t tx_lock;
+};
+
struct ath9k_htc_tx_ctl {
u8 type; /* ATH9K_HTC_* */
+ u8 epid;
+ u8 txok;
+ u8 sta_idx;
+ unsigned long timestamp;
};
+static inline struct ath9k_htc_tx_ctl *HTC_SKB_CB(struct sk_buff *skb)
+{
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+
+ BUILD_BUG_ON(sizeof(struct ath9k_htc_tx_ctl) >
+ IEEE80211_TX_INFO_DRIVER_DATA_SIZE);
+ return (struct ath9k_htc_tx_ctl *) &tx_info->driver_data;
+}
+
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
#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 CAB_STAT_INC priv->debug.tx_stats.cab_queued++
#define TX_QSTAT_INC(q) (priv->debug.tx_stats.queue_stats[q]++)
+void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv,
+ struct ath_htc_rx_status *rxs);
+
struct ath_tx_stats {
u32 buf_queued;
u32 buf_completed;
u32 skb_queued;
- u32 skb_completed;
- u32 skb_dropped;
+ u32 skb_success;
+ u32 skb_failed;
+ u32 cab_queued;
u32 queue_stats[WME_NUM_AC];
};
@@ -306,55 +338,57 @@ struct ath_rx_stats {
u32 skb_allocated;
u32 skb_completed;
u32 skb_dropped;
+ u32 err_crc;
+ u32 err_decrypt_crc;
+ u32 err_mic;
+ u32 err_pre_delim;
+ u32 err_post_delim;
+ u32 err_decrypt_busy;
+ u32 err_phy;
+ u32 err_phy_stats[ATH9K_PHYERR_MAX];
};
struct ath9k_debug {
struct dentry *debugfs_phy;
- struct dentry *debugfs_tgt_stats;
- struct dentry *debugfs_xmit;
- struct dentry *debugfs_recv;
struct ath_tx_stats tx_stats;
struct ath_rx_stats rx_stats;
- u32 txrate;
};
#else
#define TX_STAT_INC(c) do { } while (0)
#define RX_STAT_INC(c) do { } while (0)
+#define CAB_STAT_INC do { } while (0)
#define TX_QSTAT_INC(c) do { } while (0)
+static inline void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv,
+ struct ath_htc_rx_status *rxs)
+{
+}
+
#endif /* CONFIG_ATH9K_HTC_DEBUGFS */
#define ATH_LED_PIN_DEF 1
-#define ATH_LED_PIN_9287 8
+#define ATH_LED_PIN_9287 10
#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 */
-
-enum ath_led_type {
- ATH_LED_RADIO,
- ATH_LED_ASSOC,
- ATH_LED_TX,
- ATH_LED_RX
-};
-struct ath_led {
- struct ath9k_htc_priv *priv;
- struct led_classdev led_cdev;
- enum ath_led_type led_type;
- struct delayed_work brightness_work;
- char name[32];
- bool registered;
- int brightness;
-};
+#define BSTUCK_THRESHOLD 10
+
+/*
+ * Adjust these when the max. no of beaconing interfaces is
+ * increased.
+ */
+#define DEFAULT_SWBA_RESPONSE 40 /* in TUs */
+#define MIN_SWBA_RESPONSE 10 /* in TUs */
struct htc_beacon_config {
+ struct ieee80211_vif *bslot[ATH9K_HTC_MAX_BCN_VIF];
u16 beacon_interval;
u16 dtim_period;
u16 bmiss_timeout;
+ u32 bmiss_cnt;
};
struct ath_btcoex {
@@ -372,14 +406,11 @@ void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv);
#define OP_INVALID BIT(0)
#define OP_SCANNING BIT(1)
-#define OP_LED_ASSOCIATED BIT(2)
-#define OP_LED_ON BIT(3)
-#define OP_ENABLE_BEACON BIT(4)
-#define OP_LED_DEINIT BIT(5)
-#define OP_BT_PRIORITY_DETECTED BIT(6)
-#define OP_BT_SCAN BIT(7)
-#define OP_ANI_RUNNING BIT(8)
-#define OP_TSF_RESET BIT(9)
+#define OP_ENABLE_BEACON BIT(2)
+#define OP_BT_PRIORITY_DETECTED BIT(3)
+#define OP_BT_SCAN BIT(4)
+#define OP_ANI_RUNNING BIT(5)
+#define OP_TSF_RESET BIT(6)
struct ath9k_htc_priv {
struct device *dev;
@@ -388,6 +419,9 @@ struct ath9k_htc_priv {
struct htc_target *htc;
struct wmi *wmi;
+ u16 fw_version_major;
+ u16 fw_version_minor;
+
enum htc_endpoint_id wmi_cmd_ep;
enum htc_endpoint_id beacon_ep;
enum htc_endpoint_id cab_ep;
@@ -404,6 +438,7 @@ struct ath9k_htc_priv {
u8 vif_sta_pos[ATH9K_HTC_MAX_VIF];
u8 num_ibss_vif;
u8 num_sta_vif;
+ u8 num_sta_assoc_vif;
u8 num_ap_vif;
u16 op_flags;
@@ -411,27 +446,23 @@ struct ath9k_htc_priv {
u16 txpowlimit;
u16 nvifs;
u16 nstations;
- u32 bmiss_cnt;
bool rearm_ani;
bool reconfig_beacon;
+ unsigned int rxfilter;
struct ath9k_hw_cal_data caldata;
+ struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
spinlock_t beacon_lock;
+ struct htc_beacon_config cur_beacon_conf;
- bool tx_queues_stop;
- spinlock_t tx_lock;
+ struct ath9k_htc_rx rx;
+ struct ath9k_htc_tx tx;
- struct ieee80211_vif *vif;
- struct htc_beacon_config cur_beacon_conf;
- unsigned int rxfilter;
struct tasklet_struct swba_tasklet;
struct tasklet_struct rx_tasklet;
- struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS];
- struct ath9k_htc_rx rx;
- struct tasklet_struct tx_tasklet;
- struct sk_buff_head tx_queue;
struct delayed_work ani_work;
+ struct tasklet_struct tx_failed_tasklet;
struct work_struct ps_work;
struct work_struct fatal_work;
@@ -440,15 +471,13 @@ struct ath9k_htc_priv {
bool ps_enabled;
bool ps_idle;
- struct ath_led radio_led;
- struct ath_led assoc_led;
- struct ath_led tx_led;
- struct ath_led rx_led;
- struct delayed_work ath9k_led_blink_work;
- int led_on_duration;
- int led_off_duration;
- int led_on_cnt;
- int led_off_cnt;
+#ifdef CONFIG_MAC80211_LEDS
+ enum led_brightness brightness;
+ bool led_registered;
+ char led_name[32];
+ struct led_classdev led_cdev;
+ struct work_struct led_work;
+#endif
int beaconq;
int cabq;
@@ -470,11 +499,18 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz)
void ath9k_htc_reset(struct ath9k_htc_priv *priv);
+void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv,
+ struct ieee80211_vif *vif);
+void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv,
+ struct ieee80211_vif *vif);
+void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv,
+ struct ieee80211_vif *vif);
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_beacon_reconfig(struct ath9k_htc_priv *priv);
-void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending);
+void ath9k_htc_swba(struct ath9k_htc_priv *priv,
+ struct wmi_event_swba *swba);
void ath9k_htc_rxep(void *priv, struct sk_buff *skb,
enum htc_endpoint_id ep_id);
@@ -483,7 +519,8 @@ void ath9k_htc_txep(void *priv, struct sk_buff *skb, enum htc_endpoint_id ep_id,
void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb,
enum htc_endpoint_id ep_id, bool txok);
-int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv);
+int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv,
+ u8 enable_coex);
void ath9k_htc_station_work(struct work_struct *work);
void ath9k_htc_aggr_work(struct work_struct *work);
void ath9k_htc_ani_work(struct work_struct *work);
@@ -491,14 +528,23 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv);
void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv);
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);
+int ath9k_htc_tx_start(struct ath9k_htc_priv *priv,
+ struct sk_buff *skb, u8 slot, bool is_cab);
void ath9k_tx_cleanup(struct ath9k_htc_priv *priv);
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);
+void ath9k_htc_check_stop_queues(struct ath9k_htc_priv *priv);
+void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv);
+int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv);
+void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot);
+void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv);
+void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event);
+void ath9k_htc_tx_failed(struct ath9k_htc_priv *priv);
+void ath9k_tx_failed_tasklet(unsigned long data);
+void ath9k_htc_tx_cleanup_timer(unsigned long data);
int ath9k_rx_init(struct ath9k_htc_priv *priv);
void ath9k_rx_cleanup(struct ath9k_htc_priv *priv);
@@ -516,9 +562,24 @@ void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv);
void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw);
void ath9k_htc_radio_enable(struct ieee80211_hw *hw);
void ath9k_htc_radio_disable(struct ieee80211_hw *hw);
-void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv);
+
+#ifdef CONFIG_MAC80211_LEDS
void ath9k_init_leds(struct ath9k_htc_priv *priv);
void ath9k_deinit_leds(struct ath9k_htc_priv *priv);
+void ath9k_led_work(struct work_struct *work);
+#else
+static inline void ath9k_init_leds(struct ath9k_htc_priv *priv)
+{
+}
+
+static inline void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
+{
+}
+
+static inline void ath9k_led_work(struct work_struct *work)
+{
+}
+#endif
int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
u16 devid, char *product, u32 drv_info);
@@ -528,15 +589,9 @@ void ath9k_htc_suspend(struct htc_target *htc_handle);
int ath9k_htc_resume(struct htc_target *htc_handle);
#endif
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
-int ath9k_htc_debug_create_root(void);
-void ath9k_htc_debug_remove_root(void);
int ath9k_htc_init_debug(struct ath_hw *ah);
-void ath9k_htc_exit_debug(struct ath_hw *ah);
#else
-static inline int ath9k_htc_debug_create_root(void) { return 0; };
-static inline void ath9k_htc_debug_remove_root(void) {};
static inline int ath9k_htc_init_debug(struct ath_hw *ah) { return 0; };
-static inline void ath9k_htc_exit_debug(struct ath_hw *ah) {};
#endif /* CONFIG_ATH9K_HTC_DEBUGFS */
#endif /* HTC_H */
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
index 8d1d8792436d..aa6a73118706 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 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
@@ -18,6 +18,50 @@
#define FUDGE 2
+void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
+{
+ struct ath_hw *ah = priv->ah;
+ struct ath9k_tx_queue_info qi, qi_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, priv->beaconq, &qi);
+
+ if (priv->ah->opmode == NL80211_IFTYPE_AP) {
+ qi.tqi_aifs = 1;
+ qi.tqi_cwmin = 0;
+ qi.tqi_cwmax = 0;
+ } else if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) {
+ int qnum = priv->hwq_map[WME_AC_BE];
+
+ ath9k_hw_get_txq_props(ah, qnum, &qi_be);
+
+ qi.tqi_aifs = qi_be.tqi_aifs;
+
+ /*
+ * For WIFI Beacon Distribution
+ * Long slot time : 2x cwmin
+ * Short slot time : 4x cwmin
+ */
+ if (ah->slottime == ATH9K_SLOT_TIME_20)
+ qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
+ else
+ 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_err(ath9k_hw_common(ah),
+ "Unable to update beacon queue %u!\n", priv->beaconq);
+ } else {
+ ath9k_hw_resettxqueue(ah, priv->beaconq);
+ }
+}
+
+
static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
struct htc_beacon_config *bss_conf)
{
@@ -30,7 +74,7 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
__be32 htc_imask = 0;
u64 tsf;
int num_beacons, offset, dtim_dec_count, cfp_dec_count;
- int ret;
+ int ret __attribute__ ((unused));
u8 cmd_rsp;
memset(&bs, 0, sizeof(bs));
@@ -146,7 +190,7 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv,
enum ath9k_int imask = 0;
u32 nexttbtt, intval, tsftu;
__be32 htc_imask = 0;
- int ret;
+ int ret __attribute__ ((unused));
u8 cmd_rsp;
u64 tsf;
@@ -154,8 +198,17 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv,
intval /= ATH9K_HTC_MAX_BCN_VIF;
nexttbtt = intval;
+ /*
+ * To reduce beacon misses under heavy TX load,
+ * set the beacon response time to a larger value.
+ */
+ if (intval > DEFAULT_SWBA_RESPONSE)
+ priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE;
+ else
+ priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE;
+
if (priv->op_flags & OP_TSF_RESET) {
- intval |= ATH9K_BEACON_RESET_TSF;
+ ath9k_hw_reset_tsf(priv->ah);
priv->op_flags &= ~OP_TSF_RESET;
} else {
/*
@@ -168,18 +221,20 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv,
} while (nexttbtt < tsftu);
}
- intval |= ATH9K_BEACON_ENA;
-
if (priv->op_flags & OP_ENABLE_BEACON)
imask |= ATH9K_INT_SWBA;
ath_dbg(common, ATH_DBG_CONFIG,
- "AP Beacon config, intval: %d, nexttbtt: %u imask: 0x%x\n",
- bss_conf->beacon_interval, nexttbtt, imask);
+ "AP Beacon config, intval: %d, nexttbtt: %u, resp_time: %d "
+ "imask: 0x%x\n",
+ bss_conf->beacon_interval, nexttbtt,
+ priv->ah->config.sw_beacon_response_time, imask);
+
+ ath9k_htc_beaconq_config(priv);
WMI_CMD(WMI_DISABLE_INTR_CMDID);
- ath9k_hw_beaconinit(priv->ah, nexttbtt, intval);
- priv->bmiss_cnt = 0;
+ ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval));
+ priv->cur_beacon_conf.bmiss_cnt = 0;
htc_imask = cpu_to_be32(imask);
WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
}
@@ -191,7 +246,7 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
enum ath9k_int imask = 0;
u32 nexttbtt, intval, tsftu;
__be32 htc_imask = 0;
- int ret;
+ int ret __attribute__ ((unused));
u8 cmd_rsp;
u64 tsf;
@@ -207,17 +262,26 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
nexttbtt += intval;
} while (nexttbtt < tsftu);
- intval |= ATH9K_BEACON_ENA;
+ /*
+ * Only one IBSS interfce is allowed.
+ */
+ if (intval > DEFAULT_SWBA_RESPONSE)
+ priv->ah->config.sw_beacon_response_time = DEFAULT_SWBA_RESPONSE;
+ else
+ priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE;
+
if (priv->op_flags & OP_ENABLE_BEACON)
imask |= ATH9K_INT_SWBA;
ath_dbg(common, ATH_DBG_CONFIG,
- "IBSS Beacon config, intval: %d, nexttbtt: %u, imask: 0x%x\n",
- bss_conf->beacon_interval, nexttbtt, imask);
+ "IBSS Beacon config, intval: %d, nexttbtt: %u, "
+ "resp_time: %d, imask: 0x%x\n",
+ bss_conf->beacon_interval, nexttbtt,
+ priv->ah->config.sw_beacon_response_time, imask);
WMI_CMD(WMI_DISABLE_INTR_CMDID);
- ath9k_hw_beaconinit(priv->ah, nexttbtt, intval);
- priv->bmiss_cnt = 0;
+ ath9k_hw_beaconinit(priv->ah, TU_TO_USEC(nexttbtt), TU_TO_USEC(intval));
+ priv->cur_beacon_conf.bmiss_cnt = 0;
htc_imask = cpu_to_be32(imask);
WMI_CMD_BUF(WMI_ENABLE_INTR_CMDID, &htc_imask);
}
@@ -228,38 +292,101 @@ void ath9k_htc_beaconep(void *drv_priv, struct sk_buff *skb,
dev_kfree_skb_any(skb);
}
-void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending)
+static void ath9k_htc_send_buffered(struct ath9k_htc_priv *priv,
+ int slot)
{
- struct ath9k_htc_vif *avp = (void *)priv->vif->drv_priv;
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ieee80211_vif *vif;
+ struct sk_buff *skb;
+ struct ieee80211_hdr *hdr;
+ int padpos, padsize, ret, tx_slot;
+
+ spin_lock_bh(&priv->beacon_lock);
+
+ vif = priv->cur_beacon_conf.bslot[slot];
+
+ skb = ieee80211_get_buffered_bc(priv->hw, vif);
+
+ while(skb) {
+ hdr = (struct ieee80211_hdr *) skb->data;
+
+ padpos = ath9k_cmn_padpos(hdr->frame_control);
+ padsize = padpos & 3;
+ if (padsize && skb->len > padpos) {
+ if (skb_headroom(skb) < padsize) {
+ dev_kfree_skb_any(skb);
+ goto next;
+ }
+ skb_push(skb, padsize);
+ memmove(skb->data, skb->data + padsize, padpos);
+ }
+
+ tx_slot = ath9k_htc_tx_get_slot(priv);
+ if (tx_slot < 0) {
+ ath_dbg(common, ATH_DBG_XMIT, "No free CAB slot\n");
+ dev_kfree_skb_any(skb);
+ goto next;
+ }
+
+ ret = ath9k_htc_tx_start(priv, skb, tx_slot, true);
+ if (ret != 0) {
+ ath9k_htc_tx_clear_slot(priv, tx_slot);
+ dev_kfree_skb_any(skb);
+
+ ath_dbg(common, ATH_DBG_XMIT,
+ "Failed to send CAB frame\n");
+ } else {
+ spin_lock_bh(&priv->tx.tx_lock);
+ priv->tx.queued_cnt++;
+ spin_unlock_bh(&priv->tx.tx_lock);
+ }
+ next:
+ skb = ieee80211_get_buffered_bc(priv->hw, vif);
+ }
+
+ spin_unlock_bh(&priv->beacon_lock);
+}
+
+static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv,
+ int slot)
+{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ieee80211_vif *vif;
+ struct ath9k_htc_vif *avp;
struct tx_beacon_header beacon_hdr;
- struct ath9k_htc_tx_ctl tx_ctl;
+ struct ath9k_htc_tx_ctl *tx_ctl;
struct ieee80211_tx_info *info;
+ struct ieee80211_mgmt *mgmt;
struct sk_buff *beacon;
u8 *tx_fhdr;
+ int ret;
memset(&beacon_hdr, 0, sizeof(struct tx_beacon_header));
- memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl));
-
- /* FIXME: Handle BMISS */
- if (beacon_pending != 0) {
- priv->bmiss_cnt++;
- return;
- }
spin_lock_bh(&priv->beacon_lock);
+ vif = priv->cur_beacon_conf.bslot[slot];
+ avp = (struct ath9k_htc_vif *)vif->drv_priv;
+
if (unlikely(priv->op_flags & OP_SCANNING)) {
spin_unlock_bh(&priv->beacon_lock);
return;
}
/* Get a new beacon */
- beacon = ieee80211_beacon_get(priv->hw, priv->vif);
+ beacon = ieee80211_beacon_get(priv->hw, vif);
if (!beacon) {
spin_unlock_bh(&priv->beacon_lock);
return;
}
+ /*
+ * Update the TSF adjust value here, the HW will
+ * add this value for every beacon.
+ */
+ mgmt = (struct ieee80211_mgmt *)beacon->data;
+ mgmt->u.beacon.timestamp = avp->tsfadjust;
+
info = IEEE80211_SKB_CB(beacon);
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
struct ieee80211_hdr *hdr =
@@ -269,45 +396,149 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending)
hdr->seq_ctrl |= cpu_to_le16(avp->seq_no);
}
- tx_ctl.type = ATH9K_HTC_NORMAL;
+ tx_ctl = HTC_SKB_CB(beacon);
+ memset(tx_ctl, 0, sizeof(*tx_ctl));
+
+ tx_ctl->type = ATH9K_HTC_BEACON;
+ tx_ctl->epid = priv->beacon_ep;
+
beacon_hdr.vif_index = avp->index;
tx_fhdr = skb_push(beacon, sizeof(beacon_hdr));
memcpy(tx_fhdr, (u8 *) &beacon_hdr, sizeof(beacon_hdr));
- htc_send(priv->htc, beacon, priv->beacon_ep, &tx_ctl);
+ ret = htc_send(priv->htc, beacon);
+ if (ret != 0) {
+ if (ret == -ENOMEM) {
+ ath_dbg(common, ATH_DBG_BSTUCK,
+ "Failed to send beacon, no free TX buffer\n");
+ }
+ dev_kfree_skb_any(beacon);
+ }
spin_unlock_bh(&priv->beacon_lock);
}
-/* Currently, only for IBSS */
-void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
+static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv,
+ struct wmi_event_swba *swba)
{
- struct ath_hw *ah = priv->ah;
- struct ath9k_tx_queue_info qi, qi_be;
- int qnum = priv->hwq_map[WME_AC_BE];
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ u64 tsf;
+ u32 tsftu;
+ u16 intval;
+ int slot;
- memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
- memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info));
+ intval = priv->cur_beacon_conf.beacon_interval & ATH9K_BEACON_PERIOD;
- ath9k_hw_get_txq_props(ah, qnum, &qi_be);
+ tsf = be64_to_cpu(swba->tsf);
+ tsftu = TSF_TO_TU(tsf >> 32, tsf);
+ slot = ((tsftu % intval) * ATH9K_HTC_MAX_BCN_VIF) / intval;
+ slot = ATH9K_HTC_MAX_BCN_VIF - slot - 1;
- qi.tqi_aifs = qi_be.tqi_aifs;
- /* For WIFI Beacon Distribution
- * Long slot time : 2x cwmin
- * Short slot time : 4x cwmin
- */
- if (ah->slottime == ATH9K_SLOT_TIME_20)
- qi.tqi_cwmin = 2*qi_be.tqi_cwmin;
- else
- qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
- qi.tqi_cwmax = qi_be.tqi_cwmax;
+ ath_dbg(common, ATH_DBG_BEACON,
+ "Choose slot: %d, tsf: %llu, tsftu: %u, intval: %u\n",
+ slot, tsf, tsftu, intval);
- if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) {
- ath_err(ath9k_hw_common(ah),
- "Unable to update beacon queue %u!\n", qnum);
- } else {
- ath9k_hw_resettxqueue(ah, priv->beaconq);
+ return slot;
+}
+
+void ath9k_htc_swba(struct ath9k_htc_priv *priv,
+ struct wmi_event_swba *swba)
+{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ int slot;
+
+ if (swba->beacon_pending != 0) {
+ priv->cur_beacon_conf.bmiss_cnt++;
+ if (priv->cur_beacon_conf.bmiss_cnt > BSTUCK_THRESHOLD) {
+ ath_dbg(common, ATH_DBG_BSTUCK,
+ "Beacon stuck, HW reset\n");
+ ieee80211_queue_work(priv->hw,
+ &priv->fatal_work);
+ }
+ return;
}
+
+ if (priv->cur_beacon_conf.bmiss_cnt) {
+ ath_dbg(common, ATH_DBG_BSTUCK,
+ "Resuming beacon xmit after %u misses\n",
+ priv->cur_beacon_conf.bmiss_cnt);
+ priv->cur_beacon_conf.bmiss_cnt = 0;
+ }
+
+ slot = ath9k_htc_choose_bslot(priv, swba);
+ spin_lock_bh(&priv->beacon_lock);
+ if (priv->cur_beacon_conf.bslot[slot] == NULL) {
+ spin_unlock_bh(&priv->beacon_lock);
+ return;
+ }
+ spin_unlock_bh(&priv->beacon_lock);
+
+ ath9k_htc_send_buffered(priv, slot);
+ ath9k_htc_send_beacon(priv, slot);
+}
+
+void ath9k_htc_assign_bslot(struct ath9k_htc_priv *priv,
+ struct ieee80211_vif *vif)
+{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv;
+ int i = 0;
+
+ spin_lock_bh(&priv->beacon_lock);
+ for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++) {
+ if (priv->cur_beacon_conf.bslot[i] == NULL) {
+ avp->bslot = i;
+ break;
+ }
+ }
+
+ priv->cur_beacon_conf.bslot[avp->bslot] = vif;
+ spin_unlock_bh(&priv->beacon_lock);
+
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Added interface at beacon slot: %d\n", avp->bslot);
+}
+
+void ath9k_htc_remove_bslot(struct ath9k_htc_priv *priv,
+ struct ieee80211_vif *vif)
+{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv;
+
+ spin_lock_bh(&priv->beacon_lock);
+ priv->cur_beacon_conf.bslot[avp->bslot] = NULL;
+ spin_unlock_bh(&priv->beacon_lock);
+
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Removed interface at beacon slot: %d\n", avp->bslot);
+}
+
+/*
+ * Calculate the TSF adjustment value for all slots
+ * other than zero.
+ */
+void ath9k_htc_set_tsfadjust(struct ath9k_htc_priv *priv,
+ struct ieee80211_vif *vif)
+{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ath9k_htc_vif *avp = (struct ath9k_htc_vif *)vif->drv_priv;
+ struct htc_beacon_config *cur_conf = &priv->cur_beacon_conf;
+ u64 tsfadjust;
+
+ if (avp->bslot == 0)
+ return;
+
+ /*
+ * The beacon interval cannot be different for multi-AP mode,
+ * and we reach here only for VIF slots greater than zero,
+ * so beacon_interval is guaranteed to be set in cur_conf.
+ */
+ tsfadjust = cur_conf->beacon_interval * avp->bslot / ATH9K_HTC_MAX_BCN_VIF;
+ avp->tsfadjust = cpu_to_le64(TU_TO_USEC(tsfadjust));
+
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "tsfadjust is: %llu for bslot: %d\n",
+ (unsigned long long)tsfadjust, avp->bslot);
}
static void ath9k_htc_beacon_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
new file mode 100644
index 000000000000..aa48b3abbc48
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
@@ -0,0 +1,960 @@
+/*
+ * Copyright (c) 2010-2011 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 "htc.h"
+
+static int ath9k_debugfs_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t read_file_tgt_int_stats(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ struct ath9k_htc_target_int_stats cmd_rsp;
+ char buf[512];
+ unsigned int len = 0;
+ int ret = 0;
+
+ memset(&cmd_rsp, 0, sizeof(cmd_rsp));
+
+ ath9k_htc_ps_wakeup(priv);
+
+ WMI_CMD(WMI_INT_STATS_CMDID);
+ if (ret) {
+ ath9k_htc_ps_restore(priv);
+ return -EINVAL;
+ }
+
+ ath9k_htc_ps_restore(priv);
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "RX",
+ be32_to_cpu(cmd_rsp.rx));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "RXORN",
+ be32_to_cpu(cmd_rsp.rxorn));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "RXEOL",
+ be32_to_cpu(cmd_rsp.rxeol));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "TXURN",
+ be32_to_cpu(cmd_rsp.txurn));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "TXTO",
+ be32_to_cpu(cmd_rsp.txto));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "CST",
+ be32_to_cpu(cmd_rsp.cst));
+
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_tgt_int_stats = {
+ .read = read_file_tgt_int_stats,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_tgt_tx_stats(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ struct ath9k_htc_target_tx_stats cmd_rsp;
+ char buf[512];
+ unsigned int len = 0;
+ int ret = 0;
+
+ memset(&cmd_rsp, 0, sizeof(cmd_rsp));
+
+ ath9k_htc_ps_wakeup(priv);
+
+ WMI_CMD(WMI_TX_STATS_CMDID);
+ if (ret) {
+ ath9k_htc_ps_restore(priv);
+ return -EINVAL;
+ }
+
+ ath9k_htc_ps_restore(priv);
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "Xretries",
+ be32_to_cpu(cmd_rsp.xretries));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "FifoErr",
+ be32_to_cpu(cmd_rsp.fifoerr));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "Filtered",
+ be32_to_cpu(cmd_rsp.filtered));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "TimerExp",
+ be32_to_cpu(cmd_rsp.timer_exp));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "ShortRetries",
+ be32_to_cpu(cmd_rsp.shortretries));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "LongRetries",
+ be32_to_cpu(cmd_rsp.longretries));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "QueueNull",
+ be32_to_cpu(cmd_rsp.qnull));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "EncapFail",
+ be32_to_cpu(cmd_rsp.encap_fail));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "NoBuf",
+ be32_to_cpu(cmd_rsp.nobuf));
+
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_tgt_tx_stats = {
+ .read = read_file_tgt_tx_stats,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_tgt_rx_stats(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ struct ath9k_htc_target_rx_stats cmd_rsp;
+ char buf[512];
+ unsigned int len = 0;
+ int ret = 0;
+
+ memset(&cmd_rsp, 0, sizeof(cmd_rsp));
+
+ ath9k_htc_ps_wakeup(priv);
+
+ WMI_CMD(WMI_RX_STATS_CMDID);
+ if (ret) {
+ ath9k_htc_ps_restore(priv);
+ return -EINVAL;
+ }
+
+ ath9k_htc_ps_restore(priv);
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "NoBuf",
+ be32_to_cpu(cmd_rsp.nobuf));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "HostSend",
+ be32_to_cpu(cmd_rsp.host_send));
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "HostDone",
+ be32_to_cpu(cmd_rsp.host_done));
+
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_tgt_rx_stats = {
+ .read = read_file_tgt_rx_stats,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ char buf[512];
+ unsigned int len = 0;
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "Buffers queued",
+ priv->debug.tx_stats.buf_queued);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "Buffers completed",
+ priv->debug.tx_stats.buf_completed);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "SKBs queued",
+ priv->debug.tx_stats.skb_queued);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "SKBs success",
+ priv->debug.tx_stats.skb_success);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "SKBs failed",
+ priv->debug.tx_stats.skb_failed);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "CAB queued",
+ priv->debug.tx_stats.cab_queued);
+
+ 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);
+}
+
+static const struct file_operations fops_xmit = {
+ .read = read_file_xmit,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+void ath9k_htc_err_stat_rx(struct ath9k_htc_priv *priv,
+ struct ath_htc_rx_status *rxs)
+{
+#define RX_PHY_ERR_INC(c) priv->debug.rx_stats.err_phy_stats[c]++
+
+ if (rxs->rs_status & ATH9K_RXERR_CRC)
+ priv->debug.rx_stats.err_crc++;
+ if (rxs->rs_status & ATH9K_RXERR_DECRYPT)
+ priv->debug.rx_stats.err_decrypt_crc++;
+ if (rxs->rs_status & ATH9K_RXERR_MIC)
+ priv->debug.rx_stats.err_mic++;
+ if (rxs->rs_status & ATH9K_RX_DELIM_CRC_PRE)
+ priv->debug.rx_stats.err_pre_delim++;
+ if (rxs->rs_status & ATH9K_RX_DELIM_CRC_POST)
+ priv->debug.rx_stats.err_post_delim++;
+ if (rxs->rs_status & ATH9K_RX_DECRYPT_BUSY)
+ priv->debug.rx_stats.err_decrypt_busy++;
+
+ if (rxs->rs_status & ATH9K_RXERR_PHY) {
+ priv->debug.rx_stats.err_phy++;
+ if (rxs->rs_phyerr < ATH9K_PHYERR_MAX)
+ RX_PHY_ERR_INC(rxs->rs_phyerr);
+ }
+
+#undef RX_PHY_ERR_INC
+}
+
+static ssize_t read_file_recv(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+#define PHY_ERR(s, p) \
+ len += snprintf(buf + len, size - len, "%20s : %10u\n", s, \
+ priv->debug.rx_stats.err_phy_stats[p]);
+
+ struct ath9k_htc_priv *priv = file->private_data;
+ char *buf;
+ unsigned int len = 0, size = 1500;
+ ssize_t retval = 0;
+
+ buf = kzalloc(size, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ len += snprintf(buf + len, size - len,
+ "%20s : %10u\n", "SKBs allocated",
+ priv->debug.rx_stats.skb_allocated);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10u\n", "SKBs completed",
+ priv->debug.rx_stats.skb_completed);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10u\n", "SKBs Dropped",
+ priv->debug.rx_stats.skb_dropped);
+
+ len += snprintf(buf + len, size - len,
+ "%20s : %10u\n", "CRC ERR",
+ priv->debug.rx_stats.err_crc);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10u\n", "DECRYPT CRC ERR",
+ priv->debug.rx_stats.err_decrypt_crc);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10u\n", "MIC ERR",
+ priv->debug.rx_stats.err_mic);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10u\n", "PRE-DELIM CRC ERR",
+ priv->debug.rx_stats.err_pre_delim);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10u\n", "POST-DELIM CRC ERR",
+ priv->debug.rx_stats.err_post_delim);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10u\n", "DECRYPT BUSY ERR",
+ priv->debug.rx_stats.err_decrypt_busy);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10u\n", "TOTAL PHY ERR",
+ priv->debug.rx_stats.err_phy);
+
+
+ PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN);
+ PHY_ERR("TIMING", ATH9K_PHYERR_TIMING);
+ PHY_ERR("PARITY", ATH9K_PHYERR_PARITY);
+ PHY_ERR("RATE", ATH9K_PHYERR_RATE);
+ PHY_ERR("LENGTH", ATH9K_PHYERR_LENGTH);
+ PHY_ERR("RADAR", ATH9K_PHYERR_RADAR);
+ PHY_ERR("SERVICE", ATH9K_PHYERR_SERVICE);
+ PHY_ERR("TOR", ATH9K_PHYERR_TOR);
+ PHY_ERR("OFDM-TIMING", ATH9K_PHYERR_OFDM_TIMING);
+ PHY_ERR("OFDM-SIGNAL-PARITY", ATH9K_PHYERR_OFDM_SIGNAL_PARITY);
+ PHY_ERR("OFDM-RATE", ATH9K_PHYERR_OFDM_RATE_ILLEGAL);
+ PHY_ERR("OFDM-LENGTH", ATH9K_PHYERR_OFDM_LENGTH_ILLEGAL);
+ PHY_ERR("OFDM-POWER-DROP", ATH9K_PHYERR_OFDM_POWER_DROP);
+ PHY_ERR("OFDM-SERVICE", ATH9K_PHYERR_OFDM_SERVICE);
+ PHY_ERR("OFDM-RESTART", ATH9K_PHYERR_OFDM_RESTART);
+ PHY_ERR("FALSE-RADAR-EXT", ATH9K_PHYERR_FALSE_RADAR_EXT);
+ PHY_ERR("CCK-TIMING", ATH9K_PHYERR_CCK_TIMING);
+ PHY_ERR("CCK-HEADER-CRC", ATH9K_PHYERR_CCK_HEADER_CRC);
+ PHY_ERR("CCK-RATE", ATH9K_PHYERR_CCK_RATE_ILLEGAL);
+ PHY_ERR("CCK-SERVICE", ATH9K_PHYERR_CCK_SERVICE);
+ PHY_ERR("CCK-RESTART", ATH9K_PHYERR_CCK_RESTART);
+ PHY_ERR("CCK-LENGTH", ATH9K_PHYERR_CCK_LENGTH_ILLEGAL);
+ PHY_ERR("CCK-POWER-DROP", ATH9K_PHYERR_CCK_POWER_DROP);
+ PHY_ERR("HT-CRC", ATH9K_PHYERR_HT_CRC_ERROR);
+ 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);
+
+ return retval;
+
+#undef PHY_ERR
+}
+
+static const struct file_operations fops_recv = {
+ .read = read_file_recv,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_slot(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ char buf[512];
+ unsigned int len = 0;
+
+ spin_lock_bh(&priv->tx.tx_lock);
+
+ len += snprintf(buf + len, sizeof(buf) - len, "TX slot bitmap : ");
+
+ len += bitmap_scnprintf(buf + len, sizeof(buf) - len,
+ priv->tx.tx_slot, MAX_TX_BUF_NUM);
+
+ len += snprintf(buf + len, sizeof(buf) - len, "\n");
+
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "Used slots : %d\n",
+ bitmap_weight(priv->tx.tx_slot, MAX_TX_BUF_NUM));
+
+ spin_unlock_bh(&priv->tx.tx_lock);
+
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_slot = {
+ .read = read_file_slot,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_queue(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ char buf[512];
+ unsigned int len = 0;
+
+ len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+ "Mgmt endpoint", skb_queue_len(&priv->tx.mgmt_ep_queue));
+
+ len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+ "Cab endpoint", skb_queue_len(&priv->tx.cab_ep_queue));
+
+ len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+ "Data BE endpoint", skb_queue_len(&priv->tx.data_be_queue));
+
+ len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+ "Data BK endpoint", skb_queue_len(&priv->tx.data_bk_queue));
+
+ len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+ "Data VI endpoint", skb_queue_len(&priv->tx.data_vi_queue));
+
+ len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+ "Data VO endpoint", skb_queue_len(&priv->tx.data_vo_queue));
+
+ len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+ "Failed queue", skb_queue_len(&priv->tx.tx_failed));
+
+ spin_lock_bh(&priv->tx.tx_lock);
+ len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+ "Queued count", priv->tx.queued_cnt);
+ spin_unlock_bh(&priv->tx.tx_lock);
+
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+
+}
+
+static const struct file_operations fops_queue = {
+ .read = read_file_queue,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_debug(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ char buf[32];
+ unsigned int len;
+
+ len = sprintf(buf, "0x%08x\n", common->debug_mask);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_debug(struct file *file, const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ unsigned long mask;
+ char buf[32];
+ ssize_t len;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ buf[len] = '\0';
+ if (strict_strtoul(buf, 0, &mask))
+ return -EINVAL;
+
+ common->debug_mask = mask;
+ return count;
+}
+
+static const struct file_operations fops_debug = {
+ .read = read_file_debug,
+ .write = write_file_debug,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct base_eep_header *pBase = NULL;
+ unsigned int len = 0, size = 1500;
+ ssize_t retval = 0;
+ char *buf;
+
+ /*
+ * This can be done since all the 3 EEPROM families have the
+ * same base header upto a certain point, and we are interested in
+ * the data only upto that point.
+ */
+
+ if (AR_SREV_9271(priv->ah))
+ pBase = (struct base_eep_header *)
+ &priv->ah->eeprom.map4k.baseEepHeader;
+ else if (priv->ah->hw_version.usbdev == AR9280_USB)
+ pBase = (struct base_eep_header *)
+ &priv->ah->eeprom.def.baseEepHeader;
+ else if (priv->ah->hw_version.usbdev == AR9287_USB)
+ pBase = (struct base_eep_header *)
+ &priv->ah->eeprom.map9287.baseEepHeader;
+
+ if (pBase == NULL) {
+ ath_err(common, "Unknown EEPROM type\n");
+ return 0;
+ }
+
+ buf = kzalloc(size, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ len += snprintf(buf + len, size - len,
+ "%20s : %10d\n", "Major Version",
+ pBase->version >> 12);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10d\n", "Minor Version",
+ pBase->version & 0xFFF);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10d\n", "Checksum",
+ pBase->checksum);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10d\n", "Length",
+ pBase->length);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10d\n", "RegDomain1",
+ pBase->regDmn[0]);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10d\n", "RegDomain2",
+ pBase->regDmn[1]);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10d\n",
+ "TX Mask", pBase->txMask);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10d\n",
+ "RX Mask", pBase->rxMask);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10d\n",
+ "Allow 5GHz",
+ !!(pBase->opCapFlags & AR5416_OPFLAGS_11A));
+ len += snprintf(buf + len, size - len,
+ "%20s : %10d\n",
+ "Allow 2GHz",
+ !!(pBase->opCapFlags & AR5416_OPFLAGS_11G));
+ len += snprintf(buf + len, size - len,
+ "%20s : %10d\n",
+ "Disable 2GHz HT20",
+ !!(pBase->opCapFlags & AR5416_OPFLAGS_N_2G_HT20));
+ len += snprintf(buf + len, size - len,
+ "%20s : %10d\n",
+ "Disable 2GHz HT40",
+ !!(pBase->opCapFlags & AR5416_OPFLAGS_N_2G_HT40));
+ len += snprintf(buf + len, size - len,
+ "%20s : %10d\n",
+ "Disable 5Ghz HT20",
+ !!(pBase->opCapFlags & AR5416_OPFLAGS_N_5G_HT20));
+ len += snprintf(buf + len, size - len,
+ "%20s : %10d\n",
+ "Disable 5Ghz HT40",
+ !!(pBase->opCapFlags & AR5416_OPFLAGS_N_5G_HT40));
+ len += snprintf(buf + len, size - len,
+ "%20s : %10d\n",
+ "Big Endian",
+ !!(pBase->eepMisc & 0x01));
+ len += snprintf(buf + len, size - len,
+ "%20s : %10d\n",
+ "Cal Bin Major Ver",
+ (pBase->binBuildNumber >> 24) & 0xFF);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10d\n",
+ "Cal Bin Minor Ver",
+ (pBase->binBuildNumber >> 16) & 0xFF);
+ len += snprintf(buf + len, size - len,
+ "%20s : %10d\n",
+ "Cal Bin Build",
+ (pBase->binBuildNumber >> 8) & 0xFF);
+
+ /*
+ * UB91 specific data.
+ */
+ if (AR_SREV_9271(priv->ah)) {
+ struct base_eep_header_4k *pBase4k =
+ &priv->ah->eeprom.map4k.baseEepHeader;
+
+ len += snprintf(buf + len, size - len,
+ "%20s : %10d\n",
+ "TX Gain type",
+ pBase4k->txGainType);
+ }
+
+ /*
+ * UB95 specific data.
+ */
+ if (priv->ah->hw_version.usbdev == AR9287_USB) {
+ struct base_eep_ar9287_header *pBase9287 =
+ &priv->ah->eeprom.map9287.baseEepHeader;
+
+ len += snprintf(buf + len, size - len,
+ "%20s : %10ddB\n",
+ "Power Table Offset",
+ pBase9287->pwrTableOffset);
+
+ len += snprintf(buf + len, size - len,
+ "%20s : %10d\n",
+ "OpenLoop Power Ctrl",
+ pBase9287->openLoopPwrCntl);
+ }
+
+ len += snprintf(buf + len, size - len,
+ "%20s : %02X:%02X:%02X:%02X:%02X:%02X\n",
+ "MacAddress",
+ pBase->macAddr[0], pBase->macAddr[1], pBase->macAddr[2],
+ pBase->macAddr[3], pBase->macAddr[4], pBase->macAddr[5]);
+ if (len > size)
+ len = size;
+
+ retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+
+ return retval;
+}
+
+static const struct file_operations fops_base_eeprom = {
+ .read = read_file_base_eeprom,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t read_4k_modal_eeprom(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+#define PR_EEP(_s, _val) \
+ do { \
+ len += snprintf(buf + len, size - len, "%20s : %10d\n", \
+ _s, (_val)); \
+ } while (0)
+
+ struct ath9k_htc_priv *priv = file->private_data;
+ struct modal_eep_4k_header *pModal = &priv->ah->eeprom.map4k.modalHeader;
+ unsigned int len = 0, size = 2048;
+ ssize_t retval = 0;
+ char *buf;
+
+ buf = kzalloc(size, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]);
+ PR_EEP("Ant. Common Control", pModal->antCtrlCommon);
+ PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]);
+ PR_EEP("Switch Settle", pModal->switchSettling);
+ PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]);
+ PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]);
+ PR_EEP("ADC Desired size", pModal->adcDesiredSize);
+ PR_EEP("PGA Desired size", pModal->pgaDesiredSize);
+ PR_EEP("Chain0 xlna Gain", pModal->xlnaGainCh[0]);
+ PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff);
+ PR_EEP("txEndToRxOn", pModal->txEndToRxOn);
+ PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn);
+ PR_EEP("CCA Threshold)", pModal->thresh62);
+ PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]);
+ PR_EEP("xpdGain", pModal->xpdGain);
+ PR_EEP("External PD", pModal->xpd);
+ PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]);
+ PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]);
+ PR_EEP("pdGainOverlap", pModal->pdGainOverlap);
+ PR_EEP("O/D Bias Version", pModal->version);
+ PR_EEP("CCK OutputBias", pModal->ob_0);
+ PR_EEP("BPSK OutputBias", pModal->ob_1);
+ PR_EEP("QPSK OutputBias", pModal->ob_2);
+ PR_EEP("16QAM OutputBias", pModal->ob_3);
+ PR_EEP("64QAM OutputBias", pModal->ob_4);
+ PR_EEP("CCK Driver1_Bias", pModal->db1_0);
+ PR_EEP("BPSK Driver1_Bias", pModal->db1_1);
+ PR_EEP("QPSK Driver1_Bias", pModal->db1_2);
+ PR_EEP("16QAM Driver1_Bias", pModal->db1_3);
+ PR_EEP("64QAM Driver1_Bias", pModal->db1_4);
+ PR_EEP("CCK Driver2_Bias", pModal->db2_0);
+ PR_EEP("BPSK Driver2_Bias", pModal->db2_1);
+ PR_EEP("QPSK Driver2_Bias", pModal->db2_2);
+ PR_EEP("16QAM Driver2_Bias", pModal->db2_3);
+ PR_EEP("64QAM Driver2_Bias", pModal->db2_4);
+ PR_EEP("xPA Bias Level", pModal->xpaBiasLvl);
+ PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart);
+ PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn);
+ PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc);
+ PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]);
+ PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]);
+ PR_EEP("HT40 Switch Settle", pModal->swSettleHt40);
+ PR_EEP("Chain0 xatten2Db", pModal->xatten2Db[0]);
+ PR_EEP("Chain0 xatten2Margin", pModal->xatten2Margin[0]);
+ PR_EEP("Ant. Diversity ctl1", pModal->antdiv_ctl1);
+ PR_EEP("Ant. Diversity ctl2", pModal->antdiv_ctl2);
+ PR_EEP("TX Diversity", pModal->tx_diversity);
+
+ if (len > size)
+ len = size;
+
+ retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+
+ return retval;
+
+#undef PR_EEP
+}
+
+static ssize_t read_def_modal_eeprom(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+#define PR_EEP(_s, _val) \
+ do { \
+ if (pBase->opCapFlags & AR5416_OPFLAGS_11G) { \
+ pModal = &priv->ah->eeprom.def.modalHeader[1]; \
+ len += snprintf(buf + len, size - len, "%20s : %8d%7s", \
+ _s, (_val), "|"); \
+ } \
+ if (pBase->opCapFlags & AR5416_OPFLAGS_11A) { \
+ pModal = &priv->ah->eeprom.def.modalHeader[0]; \
+ len += snprintf(buf + len, size - len, "%9d\n", \
+ (_val)); \
+ } \
+ } while (0)
+
+ struct ath9k_htc_priv *priv = file->private_data;
+ struct base_eep_header *pBase = &priv->ah->eeprom.def.baseEepHeader;
+ struct modal_eep_header *pModal = NULL;
+ unsigned int len = 0, size = 3500;
+ ssize_t retval = 0;
+ char *buf;
+
+ buf = kzalloc(size, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ len += snprintf(buf + len, size - len,
+ "%31s %15s\n", "2G", "5G");
+ len += snprintf(buf + len, size - len,
+ "%32s %16s\n", "====", "====\n");
+
+ PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]);
+ PR_EEP("Chain1 Ant. Control", pModal->antCtrlChain[1]);
+ PR_EEP("Chain2 Ant. Control", pModal->antCtrlChain[2]);
+ PR_EEP("Ant. Common Control", pModal->antCtrlCommon);
+ PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]);
+ PR_EEP("Chain1 Ant. Gain", pModal->antennaGainCh[1]);
+ PR_EEP("Chain2 Ant. Gain", pModal->antennaGainCh[2]);
+ PR_EEP("Switch Settle", pModal->switchSettling);
+ PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]);
+ PR_EEP("Chain1 TxRxAtten", pModal->txRxAttenCh[1]);
+ PR_EEP("Chain2 TxRxAtten", pModal->txRxAttenCh[2]);
+ PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]);
+ PR_EEP("Chain1 RxTxMargin", pModal->rxTxMarginCh[1]);
+ PR_EEP("Chain2 RxTxMargin", pModal->rxTxMarginCh[2]);
+ PR_EEP("ADC Desired size", pModal->adcDesiredSize);
+ PR_EEP("PGA Desired size", pModal->pgaDesiredSize);
+ PR_EEP("Chain0 xlna Gain", pModal->xlnaGainCh[0]);
+ PR_EEP("Chain1 xlna Gain", pModal->xlnaGainCh[1]);
+ PR_EEP("Chain2 xlna Gain", pModal->xlnaGainCh[2]);
+ PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff);
+ PR_EEP("txEndToRxOn", pModal->txEndToRxOn);
+ PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn);
+ PR_EEP("CCA Threshold)", pModal->thresh62);
+ PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]);
+ PR_EEP("Chain1 NF Threshold", pModal->noiseFloorThreshCh[1]);
+ PR_EEP("Chain2 NF Threshold", pModal->noiseFloorThreshCh[2]);
+ PR_EEP("xpdGain", pModal->xpdGain);
+ PR_EEP("External PD", pModal->xpd);
+ PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]);
+ PR_EEP("Chain1 I Coefficient", pModal->iqCalICh[1]);
+ PR_EEP("Chain2 I Coefficient", pModal->iqCalICh[2]);
+ PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]);
+ PR_EEP("Chain1 Q Coefficient", pModal->iqCalQCh[1]);
+ PR_EEP("Chain2 Q Coefficient", pModal->iqCalQCh[2]);
+ PR_EEP("pdGainOverlap", pModal->pdGainOverlap);
+ PR_EEP("Chain0 OutputBias", pModal->ob);
+ PR_EEP("Chain0 DriverBias", pModal->db);
+ PR_EEP("xPA Bias Level", pModal->xpaBiasLvl);
+ PR_EEP("2chain pwr decrease", pModal->pwrDecreaseFor2Chain);
+ PR_EEP("3chain pwr decrease", pModal->pwrDecreaseFor3Chain);
+ PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart);
+ PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn);
+ PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc);
+ PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]);
+ PR_EEP("Chain1 bswAtten", pModal->bswAtten[1]);
+ PR_EEP("Chain2 bswAtten", pModal->bswAtten[2]);
+ PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]);
+ PR_EEP("Chain1 bswMargin", pModal->bswMargin[1]);
+ PR_EEP("Chain2 bswMargin", pModal->bswMargin[2]);
+ PR_EEP("HT40 Switch Settle", pModal->swSettleHt40);
+ PR_EEP("Chain0 xatten2Db", pModal->xatten2Db[0]);
+ PR_EEP("Chain1 xatten2Db", pModal->xatten2Db[1]);
+ PR_EEP("Chain2 xatten2Db", pModal->xatten2Db[2]);
+ PR_EEP("Chain0 xatten2Margin", pModal->xatten2Margin[0]);
+ PR_EEP("Chain1 xatten2Margin", pModal->xatten2Margin[1]);
+ PR_EEP("Chain2 xatten2Margin", pModal->xatten2Margin[2]);
+ PR_EEP("Chain1 OutputBias", pModal->ob_ch1);
+ PR_EEP("Chain1 DriverBias", pModal->db_ch1);
+ PR_EEP("LNA Control", pModal->lna_ctl);
+ PR_EEP("XPA Bias Freq0", pModal->xpaBiasLvlFreq[0]);
+ PR_EEP("XPA Bias Freq1", pModal->xpaBiasLvlFreq[1]);
+ PR_EEP("XPA Bias Freq2", pModal->xpaBiasLvlFreq[2]);
+
+ if (len > size)
+ len = size;
+
+ retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+
+ return retval;
+
+#undef PR_EEP
+}
+
+static ssize_t read_9287_modal_eeprom(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+#define PR_EEP(_s, _val) \
+ do { \
+ len += snprintf(buf + len, size - len, "%20s : %10d\n", \
+ _s, (_val)); \
+ } while (0)
+
+ struct ath9k_htc_priv *priv = file->private_data;
+ struct modal_eep_ar9287_header *pModal = &priv->ah->eeprom.map9287.modalHeader;
+ unsigned int len = 0, size = 3000;
+ ssize_t retval = 0;
+ char *buf;
+
+ buf = kzalloc(size, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]);
+ PR_EEP("Chain1 Ant. Control", pModal->antCtrlChain[1]);
+ PR_EEP("Ant. Common Control", pModal->antCtrlCommon);
+ PR_EEP("Chain0 Ant. Gain", pModal->antennaGainCh[0]);
+ PR_EEP("Chain1 Ant. Gain", pModal->antennaGainCh[1]);
+ PR_EEP("Switch Settle", pModal->switchSettling);
+ PR_EEP("Chain0 TxRxAtten", pModal->txRxAttenCh[0]);
+ PR_EEP("Chain1 TxRxAtten", pModal->txRxAttenCh[1]);
+ PR_EEP("Chain0 RxTxMargin", pModal->rxTxMarginCh[0]);
+ PR_EEP("Chain1 RxTxMargin", pModal->rxTxMarginCh[1]);
+ PR_EEP("ADC Desired size", pModal->adcDesiredSize);
+ PR_EEP("txEndToXpaOff", pModal->txEndToXpaOff);
+ PR_EEP("txEndToRxOn", pModal->txEndToRxOn);
+ PR_EEP("txFrameToXpaOn", pModal->txFrameToXpaOn);
+ PR_EEP("CCA Threshold)", pModal->thresh62);
+ PR_EEP("Chain0 NF Threshold", pModal->noiseFloorThreshCh[0]);
+ PR_EEP("Chain1 NF Threshold", pModal->noiseFloorThreshCh[1]);
+ PR_EEP("xpdGain", pModal->xpdGain);
+ PR_EEP("External PD", pModal->xpd);
+ PR_EEP("Chain0 I Coefficient", pModal->iqCalICh[0]);
+ PR_EEP("Chain1 I Coefficient", pModal->iqCalICh[1]);
+ PR_EEP("Chain0 Q Coefficient", pModal->iqCalQCh[0]);
+ PR_EEP("Chain1 Q Coefficient", pModal->iqCalQCh[1]);
+ PR_EEP("pdGainOverlap", pModal->pdGainOverlap);
+ PR_EEP("xPA Bias Level", pModal->xpaBiasLvl);
+ PR_EEP("txFrameToDataStart", pModal->txFrameToDataStart);
+ PR_EEP("txFrameToPaOn", pModal->txFrameToPaOn);
+ PR_EEP("HT40 Power Inc.", pModal->ht40PowerIncForPdadc);
+ PR_EEP("Chain0 bswAtten", pModal->bswAtten[0]);
+ PR_EEP("Chain1 bswAtten", pModal->bswAtten[1]);
+ PR_EEP("Chain0 bswMargin", pModal->bswMargin[0]);
+ PR_EEP("Chain1 bswMargin", pModal->bswMargin[1]);
+ PR_EEP("HT40 Switch Settle", pModal->swSettleHt40);
+ PR_EEP("AR92x7 Version", pModal->version);
+ PR_EEP("DriverBias1", pModal->db1);
+ PR_EEP("DriverBias2", pModal->db1);
+ PR_EEP("CCK OutputBias", pModal->ob_cck);
+ PR_EEP("PSK OutputBias", pModal->ob_psk);
+ PR_EEP("QAM OutputBias", pModal->ob_qam);
+ PR_EEP("PAL_OFF OutputBias", pModal->ob_pal_off);
+
+ if (len > size)
+ len = size;
+
+ retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+
+ return retval;
+
+#undef PR_EEP
+}
+
+static ssize_t read_file_modal_eeprom(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath9k_htc_priv *priv = file->private_data;
+
+ if (AR_SREV_9271(priv->ah))
+ return read_4k_modal_eeprom(file, user_buf, count, ppos);
+ else if (priv->ah->hw_version.usbdev == AR9280_USB)
+ return read_def_modal_eeprom(file, user_buf, count, ppos);
+ else if (priv->ah->hw_version.usbdev == AR9287_USB)
+ return read_9287_modal_eeprom(file, user_buf, count, ppos);
+
+ return 0;
+}
+
+static const struct file_operations fops_modal_eeprom = {
+ .read = read_file_modal_eeprom,
+ .open = ath9k_debugfs_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+int ath9k_htc_init_debug(struct ath_hw *ah)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
+
+ priv->debug.debugfs_phy = debugfs_create_dir(KBUILD_MODNAME,
+ priv->hw->wiphy->debugfsdir);
+ if (!priv->debug.debugfs_phy)
+ return -ENOMEM;
+
+ debugfs_create_file("tgt_int_stats", S_IRUSR, priv->debug.debugfs_phy,
+ priv, &fops_tgt_int_stats);
+ debugfs_create_file("tgt_tx_stats", S_IRUSR, priv->debug.debugfs_phy,
+ priv, &fops_tgt_tx_stats);
+ debugfs_create_file("tgt_rx_stats", S_IRUSR, priv->debug.debugfs_phy,
+ priv, &fops_tgt_rx_stats);
+ debugfs_create_file("xmit", S_IRUSR, priv->debug.debugfs_phy,
+ priv, &fops_xmit);
+ debugfs_create_file("recv", S_IRUSR, priv->debug.debugfs_phy,
+ priv, &fops_recv);
+ debugfs_create_file("slot", S_IRUSR, priv->debug.debugfs_phy,
+ priv, &fops_slot);
+ debugfs_create_file("queue", S_IRUSR, priv->debug.debugfs_phy,
+ priv, &fops_queue);
+ debugfs_create_file("debug", S_IRUSR | S_IWUSR, priv->debug.debugfs_phy,
+ priv, &fops_debug);
+ debugfs_create_file("base_eeprom", S_IRUSR, priv->debug.debugfs_phy,
+ priv, &fops_base_eeprom);
+ debugfs_create_file("modal_eeprom", S_IRUSR, priv->debug.debugfs_phy,
+ priv, &fops_modal_eeprom);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
index 7e630a81b453..db2352e5cc0d 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 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
@@ -65,17 +65,19 @@ static void ath_btcoex_period_work(struct work_struct *work)
u32 timer_period;
bool is_btscan;
int ret;
- u8 cmd_rsp, aggr;
ath_detect_bt_priority(priv);
is_btscan = !!(priv->op_flags & OP_BT_SCAN);
- aggr = priv->op_flags & OP_BT_PRIORITY_DETECTED;
-
- WMI_CMD_BUF(WMI_AGGR_LIMIT_CMD, &aggr);
+ ret = ath9k_htc_update_cap_target(priv,
+ !!(priv->op_flags & OP_BT_PRIORITY_DETECTED));
+ if (ret) {
+ ath_err(common, "Unable to set BTCOEX parameters\n");
+ return;
+ }
- ath9k_cmn_btcoex_bt_stomp(common, is_btscan ? ATH_BTCOEX_STOMP_ALL :
+ ath9k_hw_btcoex_bt_stomp(priv->ah, is_btscan ? ATH_BTCOEX_STOMP_ALL :
btcoex->bt_stomp_type);
timer_period = is_btscan ? btcoex->btscan_no_stomp :
@@ -103,9 +105,9 @@ static void ath_btcoex_duty_cycle_work(struct work_struct *work)
"time slice work for bt and wlan\n");
if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan)
- ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_NONE);
+ ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
- ath9k_cmn_btcoex_bt_stomp(common, ATH_BTCOEX_STOMP_LOW);
+ ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW);
}
void ath_htc_init_btcoex_work(struct ath9k_htc_priv *priv)
@@ -152,140 +154,41 @@ void ath_htc_cancel_btcoex_work(struct ath9k_htc_priv *priv)
/* LED */
/*******/
-static void ath9k_led_blink_work(struct work_struct *work)
+#ifdef CONFIG_MAC80211_LEDS
+void ath9k_led_work(struct work_struct *work)
{
- struct ath9k_htc_priv *priv = container_of(work, struct ath9k_htc_priv,
- ath9k_led_blink_work.work);
+ struct ath9k_htc_priv *priv = container_of(work,
+ struct ath9k_htc_priv,
+ led_work);
- if (!(priv->op_flags & OP_LED_ASSOCIATED))
- return;
-
- if ((priv->led_on_duration == ATH_LED_ON_DURATION_IDLE) ||
- (priv->led_off_duration == ATH_LED_OFF_DURATION_IDLE))
- ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
- else
- ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
- (priv->op_flags & OP_LED_ON) ? 1 : 0);
-
- ieee80211_queue_delayed_work(priv->hw,
- &priv->ath9k_led_blink_work,
- (priv->op_flags & OP_LED_ON) ?
- msecs_to_jiffies(priv->led_off_duration) :
- msecs_to_jiffies(priv->led_on_duration));
-
- priv->led_on_duration = priv->led_on_cnt ?
- max((ATH_LED_ON_DURATION_IDLE - priv->led_on_cnt), 25) :
- ATH_LED_ON_DURATION_IDLE;
- priv->led_off_duration = priv->led_off_cnt ?
- max((ATH_LED_OFF_DURATION_IDLE - priv->led_off_cnt), 10) :
- ATH_LED_OFF_DURATION_IDLE;
- priv->led_on_cnt = priv->led_off_cnt = 0;
-
- if (priv->op_flags & OP_LED_ON)
- priv->op_flags &= ~OP_LED_ON;
- else
- priv->op_flags |= OP_LED_ON;
-}
-
-static void ath9k_led_brightness_work(struct work_struct *work)
-{
- struct ath_led *led = container_of(work, struct ath_led,
- brightness_work.work);
- struct ath9k_htc_priv *priv = led->priv;
-
- switch (led->brightness) {
- case LED_OFF:
- if (led->led_type == ATH_LED_ASSOC ||
- led->led_type == ATH_LED_RADIO) {
- ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
- (led->led_type == ATH_LED_RADIO));
- priv->op_flags &= ~OP_LED_ASSOCIATED;
- if (led->led_type == ATH_LED_RADIO)
- priv->op_flags &= ~OP_LED_ON;
- } else {
- priv->led_off_cnt++;
- }
- break;
- case LED_FULL:
- if (led->led_type == ATH_LED_ASSOC) {
- priv->op_flags |= OP_LED_ASSOCIATED;
- ieee80211_queue_delayed_work(priv->hw,
- &priv->ath9k_led_blink_work, 0);
- } else if (led->led_type == ATH_LED_RADIO) {
- ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 0);
- priv->op_flags |= OP_LED_ON;
- } else {
- priv->led_on_cnt++;
- }
- break;
- default:
- break;
- }
+ ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin,
+ (priv->brightness == LED_OFF));
}
static void ath9k_led_brightness(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
- struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
- struct ath9k_htc_priv *priv = led->priv;
-
- led->brightness = brightness;
- if (!(priv->op_flags & OP_LED_DEINIT))
- ieee80211_queue_delayed_work(priv->hw,
- &led->brightness_work, 0);
-}
-
-void ath9k_led_stop_brightness(struct ath9k_htc_priv *priv)
-{
- cancel_delayed_work_sync(&priv->radio_led.brightness_work);
- cancel_delayed_work_sync(&priv->assoc_led.brightness_work);
- cancel_delayed_work_sync(&priv->tx_led.brightness_work);
- cancel_delayed_work_sync(&priv->rx_led.brightness_work);
-}
-
-static int ath9k_register_led(struct ath9k_htc_priv *priv, struct ath_led *led,
- char *trigger)
-{
- int ret;
-
- led->priv = priv;
- led->led_cdev.name = led->name;
- led->led_cdev.default_trigger = trigger;
- led->led_cdev.brightness_set = ath9k_led_brightness;
+ struct ath9k_htc_priv *priv = container_of(led_cdev,
+ struct ath9k_htc_priv,
+ led_cdev);
- ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_cdev);
- if (ret)
- ath_err(ath9k_hw_common(priv->ah),
- "Failed to register led:%s", led->name);
- else
- led->registered = 1;
-
- INIT_DELAYED_WORK(&led->brightness_work, ath9k_led_brightness_work);
-
- return ret;
-}
-
-static void ath9k_unregister_led(struct ath_led *led)
-{
- if (led->registered) {
- led_classdev_unregister(&led->led_cdev);
- led->registered = 0;
- }
+ /* Not locked, but it's just a tiny green light..*/
+ priv->brightness = brightness;
+ ieee80211_queue_work(priv->hw, &priv->led_work);
}
void ath9k_deinit_leds(struct ath9k_htc_priv *priv)
{
- priv->op_flags |= OP_LED_DEINIT;
- ath9k_unregister_led(&priv->assoc_led);
- priv->op_flags &= ~OP_LED_ASSOCIATED;
- ath9k_unregister_led(&priv->tx_led);
- ath9k_unregister_led(&priv->rx_led);
- ath9k_unregister_led(&priv->radio_led);
+ if (!priv->led_registered)
+ return;
+
+ ath9k_led_brightness(&priv->led_cdev, LED_OFF);
+ led_classdev_unregister(&priv->led_cdev);
+ cancel_work_sync(&priv->led_work);
}
void ath9k_init_leds(struct ath9k_htc_priv *priv)
{
- char *trigger;
int ret;
if (AR_SREV_9287(priv->ah))
@@ -303,48 +206,21 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv)
/* LED off, active low */
ath9k_hw_set_gpio(priv->ah, priv->ah->led_pin, 1);
- INIT_DELAYED_WORK(&priv->ath9k_led_blink_work, ath9k_led_blink_work);
-
- trigger = ieee80211_get_radio_led_name(priv->hw);
- snprintf(priv->radio_led.name, sizeof(priv->radio_led.name),
- "ath9k-%s::radio", wiphy_name(priv->hw->wiphy));
- ret = ath9k_register_led(priv, &priv->radio_led, trigger);
- priv->radio_led.led_type = ATH_LED_RADIO;
- if (ret)
- goto fail;
-
- trigger = ieee80211_get_assoc_led_name(priv->hw);
- snprintf(priv->assoc_led.name, sizeof(priv->assoc_led.name),
- "ath9k-%s::assoc", wiphy_name(priv->hw->wiphy));
- ret = ath9k_register_led(priv, &priv->assoc_led, trigger);
- priv->assoc_led.led_type = ATH_LED_ASSOC;
- if (ret)
- goto fail;
-
- trigger = ieee80211_get_tx_led_name(priv->hw);
- snprintf(priv->tx_led.name, sizeof(priv->tx_led.name),
- "ath9k-%s::tx", wiphy_name(priv->hw->wiphy));
- ret = ath9k_register_led(priv, &priv->tx_led, trigger);
- priv->tx_led.led_type = ATH_LED_TX;
- if (ret)
- goto fail;
-
- trigger = ieee80211_get_rx_led_name(priv->hw);
- snprintf(priv->rx_led.name, sizeof(priv->rx_led.name),
- "ath9k-%s::rx", wiphy_name(priv->hw->wiphy));
- ret = ath9k_register_led(priv, &priv->rx_led, trigger);
- priv->rx_led.led_type = ATH_LED_RX;
- if (ret)
- goto fail;
-
- priv->op_flags &= ~OP_LED_DEINIT;
+ snprintf(priv->led_name, sizeof(priv->led_name),
+ "ath9k_htc-%s", wiphy_name(priv->hw->wiphy));
+ priv->led_cdev.name = priv->led_name;
+ priv->led_cdev.brightness_set = ath9k_led_brightness;
- return;
+ ret = led_classdev_register(wiphy_dev(priv->hw->wiphy), &priv->led_cdev);
+ if (ret < 0)
+ return;
+
+ INIT_WORK(&priv->led_work, ath9k_led_work);
+ priv->led_registered = true;
-fail:
- cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
- ath9k_deinit_leds(priv);
+ return;
}
+#endif
/*******************/
/* Rfkill */
@@ -398,9 +274,9 @@ void ath9k_htc_radio_enable(struct ieee80211_hw *hw)
/* Start TX */
htc_start(priv->htc);
- spin_lock_bh(&priv->tx_lock);
- priv->tx_queues_stop = false;
- spin_unlock_bh(&priv->tx_lock);
+ spin_lock_bh(&priv->tx.tx_lock);
+ priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP;
+ spin_unlock_bh(&priv->tx.tx_lock);
ieee80211_wake_queues(hw);
WMI_CMD(WMI_ENABLE_INTR_CMDID);
@@ -429,13 +305,15 @@ void ath9k_htc_radio_disable(struct ieee80211_hw *hw)
/* Stop TX */
ieee80211_stop_queues(hw);
- htc_stop(priv->htc);
+ ath9k_htc_tx_drain(priv);
WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
- skb_queue_purge(&priv->tx_queue);
/* Stop RX */
WMI_CMD(WMI_STOP_RECV_CMDID);
+ /* Clear the WMI event queue */
+ ath9k_wmi_event_drain(priv);
+
/*
* The MIB counters have to be disabled here,
* since the target doesn't do it.
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index fc67c937e172..61e6d3950718 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 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
@@ -117,6 +117,21 @@ static struct ieee80211_rate ath9k_legacy_rates[] = {
RATE(540, 0x0c, 0),
};
+#ifdef CONFIG_MAC80211_LEDS
+static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = {
+ { .throughput = 0 * 1024, .blink_time = 334 },
+ { .throughput = 1 * 1024, .blink_time = 260 },
+ { .throughput = 5 * 1024, .blink_time = 220 },
+ { .throughput = 10 * 1024, .blink_time = 190 },
+ { .throughput = 20 * 1024, .blink_time = 170 },
+ { .throughput = 50 * 1024, .blink_time = 150 },
+ { .throughput = 70 * 1024, .blink_time = 130 },
+ { .throughput = 100 * 1024, .blink_time = 110 },
+ { .throughput = 200 * 1024, .blink_time = 80 },
+ { .throughput = 300 * 1024, .blink_time = 50 },
+};
+#endif
+
static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv)
{
int time_left;
@@ -140,7 +155,6 @@ static int ath9k_htc_wait_for_target(struct ath9k_htc_priv *priv)
static void ath9k_deinit_priv(struct ath9k_htc_priv *priv)
{
- ath9k_htc_exit_debug(priv->ah);
ath9k_hw_deinit(priv->ah);
kfree(priv->ah);
priv->ah = NULL;
@@ -430,13 +444,16 @@ static void ath9k_regwrite_flush(void *hw_priv)
mutex_unlock(&priv->wmi->multi_write_mutex);
}
-static const struct ath_ops ath9k_common_ops = {
- .read = ath9k_regread,
- .multi_read = ath9k_multi_regread,
- .write = ath9k_regwrite,
- .enable_write_buffer = ath9k_enable_regwrite_buffer,
- .write_flush = ath9k_regwrite_flush,
-};
+static u32 ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr)
+{
+ u32 val;
+
+ val = ath9k_regread(hw_priv, reg_offset);
+ val &= ~clr;
+ val |= set;
+ ath9k_regwrite(hw_priv, val, reg_offset);
+ return val;
+}
static void ath_usb_read_cachesize(struct ath_common *common, int *csz)
{
@@ -561,13 +578,7 @@ static void ath9k_init_crypto(struct ath9k_htc_priv *priv)
int i = 0;
/* Get the hardware key cache size. */
- common->keymax = priv->ah->caps.keycache_size;
- if (common->keymax > ATH_KEYMAX) {
- ath_dbg(common, ATH_DBG_ANY,
- "Warning, using only %u entries in %u key cache\n",
- ATH_KEYMAX, common->keymax);
- common->keymax = ATH_KEYMAX;
- }
+ common->keymax = AR_KEYTABLE_SIZE;
if (priv->ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA)
common->crypt_caps |= ATH_CRYPT_CAP_MIC_COMBINED;
@@ -646,7 +657,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
{
struct ath_hw *ah = NULL;
struct ath_common *common;
- int ret = 0, csz = 0;
+ int i, ret = 0, csz = 0;
priv->op_flags |= OP_INVALID;
@@ -658,30 +669,35 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
ah->hw_version.subsysid = 0; /* FIXME */
ah->hw_version.usbdev = drv_info;
ah->ah_flags |= AH_USE_EEPROM;
+ ah->reg_ops.read = ath9k_regread;
+ ah->reg_ops.multi_read = ath9k_multi_regread;
+ ah->reg_ops.write = ath9k_regwrite;
+ ah->reg_ops.enable_write_buffer = ath9k_enable_regwrite_buffer;
+ ah->reg_ops.write_flush = ath9k_regwrite_flush;
+ ah->reg_ops.rmw = ath9k_reg_rmw;
priv->ah = ah;
common = ath9k_hw_common(ah);
- common->ops = &ath9k_common_ops;
+ common->ops = &ah->reg_ops;
common->bus_ops = &ath9k_usb_bus_ops;
common->ah = ah;
common->hw = priv->hw;
common->priv = priv;
common->debug_mask = ath9k_debug;
- spin_lock_init(&priv->wmi->wmi_lock);
spin_lock_init(&priv->beacon_lock);
- spin_lock_init(&priv->tx_lock);
+ spin_lock_init(&priv->tx.tx_lock);
mutex_init(&priv->mutex);
mutex_init(&priv->htc_pm_lock);
- tasklet_init(&priv->swba_tasklet, ath9k_swba_tasklet,
- (unsigned long)priv);
tasklet_init(&priv->rx_tasklet, ath9k_rx_tasklet,
(unsigned long)priv);
- tasklet_init(&priv->tx_tasklet, ath9k_tx_tasklet,
+ tasklet_init(&priv->tx_failed_tasklet, ath9k_tx_failed_tasklet,
(unsigned long)priv);
INIT_DELAYED_WORK(&priv->ani_work, ath9k_htc_ani_work);
INIT_WORK(&priv->ps_work, ath9k_ps_work);
INIT_WORK(&priv->fatal_work, ath9k_fatal_work);
+ setup_timer(&priv->tx.cleanup_timer, ath9k_htc_tx_cleanup_timer,
+ (unsigned long)priv);
/*
* Cache line size is used to size and align various
@@ -698,16 +714,13 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
goto err_hw;
}
- ret = ath9k_htc_init_debug(ah);
- if (ret) {
- ath_err(common, "Unable to create debugfs files\n");
- goto err_debug;
- }
-
ret = ath9k_init_queues(priv);
if (ret)
goto err_queues;
+ for (i = 0; i < ATH9K_HTC_MAX_BCN_VIF; i++)
+ priv->cur_beacon_conf.bslot[i] = NULL;
+
ath9k_init_crypto(priv);
ath9k_init_channels_rates(priv);
ath9k_init_misc(priv);
@@ -720,8 +733,6 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv,
return 0;
err_queues:
- ath9k_htc_exit_debug(ah);
-err_debug:
ath9k_hw_deinit(ah);
err_hw:
@@ -742,17 +753,22 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
IEEE80211_HW_HAS_RATE_CONTROL |
IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_PS_NULLFUNC_STACK;
+ IEEE80211_HW_PS_NULLFUNC_STACK |
+ IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING;
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_ADHOC);
+ BIT(NL80211_IFTYPE_ADHOC) |
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_P2P_GO) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT);
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
hw->queues = 4;
hw->channel_change_time = 5000;
hw->max_listen_interval = 10;
+
hw->vif_data_size = sizeof(struct ath9k_htc_vif);
hw->sta_data_size = sizeof(struct ath9k_htc_sta);
@@ -779,6 +795,43 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
}
+static int ath9k_init_firmware_version(struct ath9k_htc_priv *priv)
+{
+ struct ieee80211_hw *hw = priv->hw;
+ struct wmi_fw_version cmd_rsp;
+ int ret;
+
+ memset(&cmd_rsp, 0, sizeof(cmd_rsp));
+
+ WMI_CMD(WMI_GET_FW_VERSION);
+ if (ret)
+ return -EINVAL;
+
+ priv->fw_version_major = be16_to_cpu(cmd_rsp.major);
+ priv->fw_version_minor = be16_to_cpu(cmd_rsp.minor);
+
+ snprintf(hw->wiphy->fw_version, ETHTOOL_BUSINFO_LEN, "%d.%d",
+ priv->fw_version_major,
+ priv->fw_version_minor);
+
+ dev_info(priv->dev, "ath9k_htc: FW Version: %d.%d\n",
+ priv->fw_version_major,
+ priv->fw_version_minor);
+
+ /*
+ * Check if the available FW matches the driver's
+ * required version.
+ */
+ if (priv->fw_version_major != MAJOR_VERSION_REQ ||
+ priv->fw_version_minor != MINOR_VERSION_REQ) {
+ dev_err(priv->dev, "ath9k_htc: Please upgrade to FW version %d.%d\n",
+ MAJOR_VERSION_REQ, MINOR_VERSION_REQ);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int ath9k_init_device(struct ath9k_htc_priv *priv,
u16 devid, char *product, u32 drv_info)
{
@@ -798,6 +851,10 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv,
common = ath9k_hw_common(ah);
ath9k_set_hw_capab(priv, hw);
+ error = ath9k_init_firmware_version(priv);
+ if (error != 0)
+ goto err_fw;
+
/* Initialize regulatory */
error = ath_regd_init(&common->regulatory, priv->hw->wiphy,
ath9k_reg_notifier);
@@ -816,6 +873,13 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv,
if (error != 0)
goto err_rx;
+#ifdef CONFIG_MAC80211_LEDS
+ /* must be initialized before ieee80211_register_hw */
+ priv->led_cdev.default_trigger = ieee80211_create_tpt_led_trigger(priv->hw,
+ IEEE80211_TPT_LEDTRIG_FL_RADIO, ath9k_htc_tpt_blink,
+ ARRAY_SIZE(ath9k_htc_tpt_blink));
+#endif
+
/* Register with mac80211 */
error = ieee80211_register_hw(hw);
if (error)
@@ -828,6 +892,12 @@ static int ath9k_init_device(struct ath9k_htc_priv *priv,
goto err_world;
}
+ error = ath9k_htc_init_debug(priv->ah);
+ if (error) {
+ ath_err(common, "Unable to create debugfs files\n");
+ goto err_world;
+ }
+
ath_dbg(common, ATH_DBG_CONFIG,
"WMI:%d, BCN:%d, CAB:%d, UAPSD:%d, MGMT:%d, "
"BE:%d, BK:%d, VI:%d, VO:%d\n",
@@ -858,6 +928,8 @@ err_rx:
err_tx:
/* Nothing */
err_regd:
+ /* Nothing */
+err_fw:
ath9k_deinit_priv(priv);
err_init:
return error;
@@ -946,38 +1018,20 @@ int ath9k_htc_resume(struct htc_target *htc_handle)
static int __init ath9k_htc_init(void)
{
- int error;
-
- error = ath9k_htc_debug_create_root();
- if (error < 0) {
- printk(KERN_ERR
- "ath9k_htc: Unable to create debugfs root: %d\n",
- error);
- goto err_dbg;
- }
-
- error = ath9k_hif_usb_init();
- if (error < 0) {
+ if (ath9k_hif_usb_init() < 0) {
printk(KERN_ERR
"ath9k_htc: No USB devices found,"
" driver not installed.\n");
- error = -ENODEV;
- goto err_usb;
+ return -ENODEV;
}
return 0;
-
-err_usb:
- ath9k_htc_debug_remove_root();
-err_dbg:
- return error;
}
module_init(ath9k_htc_init);
static void __exit ath9k_htc_exit(void)
{
ath9k_hif_usb_exit();
- ath9k_htc_debug_remove_root();
printk(KERN_INFO "ath9k_htc: Driver unloaded\n");
}
module_exit(ath9k_htc_exit);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index db8c0c044e9e..7b7796895432 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 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
@@ -16,10 +16,6 @@
#include "htc.h"
-#ifdef CONFIG_ATH9K_HTC_DEBUGFS
-static struct dentry *ath9k_debugfs_root;
-#endif
-
/*************/
/* Utilities */
/*************/
@@ -30,7 +26,7 @@ static enum htc_phymode ath9k_htc_get_curmode(struct ath9k_htc_priv *priv,
{
enum htc_phymode mode;
- mode = HTC_MODE_AUTO;
+ mode = -EINVAL;
switch (ichan->chanmode) {
case CHANNEL_G:
@@ -49,6 +45,8 @@ static enum htc_phymode ath9k_htc_get_curmode(struct ath9k_htc_priv *priv,
break;
}
+ WARN_ON(mode < 0);
+
return mode;
}
@@ -197,11 +195,16 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv)
ath9k_htc_stop_ani(priv);
ieee80211_stop_queues(priv->hw);
- htc_stop(priv->htc);
+
+ del_timer_sync(&priv->tx.cleanup_timer);
+ ath9k_htc_tx_drain(priv);
+
WMI_CMD(WMI_DISABLE_INTR_CMDID);
WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
WMI_CMD(WMI_STOP_RECV_CMDID);
+ ath9k_wmi_event_drain(priv);
+
caldata = &priv->caldata;
ret = ath9k_hw_reset(ah, ah->curchan, caldata, false);
if (ret) {
@@ -225,6 +228,9 @@ void ath9k_htc_reset(struct ath9k_htc_priv *priv)
ath9k_htc_vif_reconfig(priv);
ieee80211_wake_queues(priv->hw);
+ mod_timer(&priv->tx.cleanup_timer,
+ jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL));
+
ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex);
}
@@ -250,11 +256,16 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL);
ath9k_htc_ps_wakeup(priv);
- htc_stop(priv->htc);
+
+ del_timer_sync(&priv->tx.cleanup_timer);
+ ath9k_htc_tx_drain(priv);
+
WMI_CMD(WMI_DISABLE_INTR_CMDID);
WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
WMI_CMD(WMI_STOP_RECV_CMDID);
+ ath9k_wmi_event_drain(priv);
+
ath_dbg(common, ATH_DBG_CONFIG,
"(%u MHz) -> (%u MHz), HT: %d, HT40: %d fastcc: %d\n",
priv->ah->curchan->channel,
@@ -263,6 +274,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
if (!fastcc)
caldata = &priv->caldata;
+
ret = ath9k_hw_reset(ah, hchan, caldata, fastcc);
if (ret) {
ath_err(common,
@@ -296,6 +308,9 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
ath9k_htc_vif_reconfig(priv);
+ mod_timer(&priv->tx.cleanup_timer,
+ jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL));
+
err:
ath9k_htc_ps_restore(priv);
return ret;
@@ -319,6 +334,11 @@ static void __ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv)
memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
hvif.index = priv->mon_vif_idx;
WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
+ if (ret) {
+ ath_err(common, "Unable to remove monitor interface at idx: %d\n",
+ priv->mon_vif_idx);
+ }
+
priv->nvifs--;
priv->vif_slot &= ~(1 << priv->mon_vif_idx);
}
@@ -349,7 +369,7 @@ static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv)
memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
- hvif.opmode = cpu_to_be32(HTC_M_MONITOR);
+ hvif.opmode = HTC_M_MONITOR;
hvif.index = ffz(priv->vif_slot);
WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif);
@@ -382,7 +402,7 @@ static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv)
tsta.is_vif_sta = 1;
tsta.sta_index = sta_idx;
tsta.vif_index = hvif.index;
- tsta.maxampdu = 0xffff;
+ tsta.maxampdu = cpu_to_be16(0xffff);
WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta);
if (ret) {
@@ -449,6 +469,7 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv,
struct ath9k_htc_sta *ista;
int ret, sta_idx;
u8 cmd_rsp;
+ u16 maxampdu;
if (priv->nstations >= ATH9K_HTC_MAX_STA)
return -ENOBUFS;
@@ -463,9 +484,7 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv,
ista = (struct ath9k_htc_sta *) sta->drv_priv;
memcpy(&tsta.macaddr, sta->addr, ETH_ALEN);
memcpy(&tsta.bssid, common->curbssid, ETH_ALEN);
- tsta.associd = common->curaid;
tsta.is_vif_sta = 0;
- tsta.valid = true;
ista->index = sta_idx;
} else {
memcpy(&tsta.macaddr, vif->addr, ETH_ALEN);
@@ -474,9 +493,14 @@ static int ath9k_htc_add_station(struct ath9k_htc_priv *priv,
tsta.sta_index = sta_idx;
tsta.vif_index = avp->index;
- tsta.maxampdu = 0xffff;
- if (sta && sta->ht_cap.ht_supported)
- tsta.flags = cpu_to_be16(ATH_HTC_STA_HT);
+
+ if (!sta) {
+ tsta.maxampdu = cpu_to_be16(0xffff);
+ } else {
+ maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
+ sta->ht_cap.ampdu_factor);
+ tsta.maxampdu = cpu_to_be16(maxampdu);
+ }
WMI_CMD_BUF(WMI_NODE_CREATE_CMDID, &tsta);
if (ret) {
@@ -547,7 +571,8 @@ static int ath9k_htc_remove_station(struct ath9k_htc_priv *priv,
return 0;
}
-int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv)
+int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv,
+ u8 enable_coex)
{
struct ath9k_htc_cap_target tcap;
int ret;
@@ -555,13 +580,9 @@ int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv)
memset(&tcap, 0, sizeof(struct ath9k_htc_cap_target));
- /* FIXME: Values are hardcoded */
- tcap.flags = 0x240c40;
- tcap.flags_ext = 0x80601000;
- tcap.ampdu_limit = 0xffff0000;
- tcap.ampdu_subframes = 20;
- tcap.tx_chainmask_legacy = priv->ah->caps.tx_chainmask;
- tcap.protmode = 1;
+ tcap.ampdu_limit = cpu_to_be32(0xffff);
+ tcap.ampdu_subframes = 0xff;
+ tcap.enable_coex = enable_coex;
tcap.tx_chainmask = priv->ah->caps.tx_chainmask;
WMI_CMD_BUF(WMI_TARGET_IC_UPDATE_CMDID, &tcap);
@@ -709,218 +730,13 @@ static int ath9k_htc_tx_aggr_oper(struct ath9k_htc_priv *priv,
(aggr.aggr_enable) ? "Starting" : "Stopping",
sta->addr, tid);
- spin_lock_bh(&priv->tx_lock);
+ spin_lock_bh(&priv->tx.tx_lock);
ista->tid_state[tid] = (aggr.aggr_enable && !ret) ? AGGR_START : AGGR_STOP;
- spin_unlock_bh(&priv->tx_lock);
+ spin_unlock_bh(&priv->tx.tx_lock);
return ret;
}
-/*********/
-/* DEBUG */
-/*********/
-
-#ifdef CONFIG_ATH9K_HTC_DEBUGFS
-
-static int ath9k_debugfs_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
-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 = file->private_data;
- struct ath9k_htc_target_stats cmd_rsp;
- char buf[512];
- unsigned int len = 0;
- int ret = 0;
-
- memset(&cmd_rsp, 0, sizeof(cmd_rsp));
-
- WMI_CMD(WMI_TGT_STATS_CMDID);
- if (ret)
- return -EINVAL;
-
-
- len += snprintf(buf + len, sizeof(buf) - len,
- "%19s : %10u\n", "TX Short Retries",
- be32_to_cpu(cmd_rsp.tx_shortretry));
- len += snprintf(buf + len, sizeof(buf) - len,
- "%19s : %10u\n", "TX Long Retries",
- be32_to_cpu(cmd_rsp.tx_longretry));
- len += snprintf(buf + len, sizeof(buf) - len,
- "%19s : %10u\n", "TX Xretries",
- be32_to_cpu(cmd_rsp.tx_xretries));
- len += snprintf(buf + len, sizeof(buf) - len,
- "%19s : %10u\n", "TX Unaggr. Xretries",
- be32_to_cpu(cmd_rsp.ht_txunaggr_xretry));
- len += snprintf(buf + len, sizeof(buf) - len,
- "%19s : %10u\n", "TX Xretries (HT)",
- be32_to_cpu(cmd_rsp.ht_tx_xretries));
- 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);
-}
-
-static const struct file_operations fops_tgt_stats = {
- .read = read_file_tgt_stats,
- .open = ath9k_debugfs_open,
- .owner = THIS_MODULE,
- .llseek = default_llseek,
-};
-
-static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ath9k_htc_priv *priv = file->private_data;
- char buf[512];
- unsigned int len = 0;
-
- len += snprintf(buf + len, sizeof(buf) - len,
- "%20s : %10u\n", "Buffers queued",
- priv->debug.tx_stats.buf_queued);
- len += snprintf(buf + len, sizeof(buf) - len,
- "%20s : %10u\n", "Buffers completed",
- priv->debug.tx_stats.buf_completed);
- len += snprintf(buf + len, sizeof(buf) - len,
- "%20s : %10u\n", "SKBs queued",
- priv->debug.tx_stats.skb_queued);
- len += snprintf(buf + len, sizeof(buf) - len,
- "%20s : %10u\n", "SKBs completed",
- priv->debug.tx_stats.skb_completed);
- len += snprintf(buf + len, sizeof(buf) - len,
- "%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);
-}
-
-static const struct file_operations fops_xmit = {
- .read = read_file_xmit,
- .open = ath9k_debugfs_open,
- .owner = THIS_MODULE,
- .llseek = default_llseek,
-};
-
-static ssize_t read_file_recv(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct ath9k_htc_priv *priv = file->private_data;
- char buf[512];
- unsigned int len = 0;
-
- len += snprintf(buf + len, sizeof(buf) - len,
- "%20s : %10u\n", "SKBs allocated",
- priv->debug.rx_stats.skb_allocated);
- len += snprintf(buf + len, sizeof(buf) - len,
- "%20s : %10u\n", "SKBs completed",
- priv->debug.rx_stats.skb_completed);
- len += snprintf(buf + len, sizeof(buf) - len,
- "%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);
-}
-
-static const struct file_operations fops_recv = {
- .read = read_file_recv,
- .open = ath9k_debugfs_open,
- .owner = THIS_MODULE,
- .llseek = default_llseek,
-};
-
-int ath9k_htc_init_debug(struct ath_hw *ah)
-{
- struct ath_common *common = ath9k_hw_common(ah);
- struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
-
- if (!ath9k_debugfs_root)
- return -ENOENT;
-
- priv->debug.debugfs_phy = debugfs_create_dir(wiphy_name(priv->hw->wiphy),
- ath9k_debugfs_root);
- if (!priv->debug.debugfs_phy)
- goto err;
-
- priv->debug.debugfs_tgt_stats = debugfs_create_file("tgt_stats", S_IRUSR,
- priv->debug.debugfs_phy,
- priv, &fops_tgt_stats);
- if (!priv->debug.debugfs_tgt_stats)
- goto err;
-
-
- priv->debug.debugfs_xmit = debugfs_create_file("xmit", S_IRUSR,
- priv->debug.debugfs_phy,
- priv, &fops_xmit);
- if (!priv->debug.debugfs_xmit)
- goto err;
-
- priv->debug.debugfs_recv = debugfs_create_file("recv", S_IRUSR,
- priv->debug.debugfs_phy,
- priv, &fops_recv);
- if (!priv->debug.debugfs_recv)
- goto err;
-
- return 0;
-
-err:
- ath9k_htc_exit_debug(ah);
- return -ENOMEM;
-}
-
-void ath9k_htc_exit_debug(struct ath_hw *ah)
-{
- struct ath_common *common = ath9k_hw_common(ah);
- struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) common->priv;
-
- debugfs_remove(priv->debug.debugfs_recv);
- debugfs_remove(priv->debug.debugfs_xmit);
- debugfs_remove(priv->debug.debugfs_tgt_stats);
- debugfs_remove(priv->debug.debugfs_phy);
-}
-
-int ath9k_htc_debug_create_root(void)
-{
- ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
- if (!ath9k_debugfs_root)
- return -ENOENT;
-
- return 0;
-}
-
-void ath9k_htc_debug_remove_root(void)
-{
- debugfs_remove(ath9k_debugfs_root);
- ath9k_debugfs_root = NULL;
-}
-
-#endif /* CONFIG_ATH9K_HTC_DEBUGFS */
-
/*******/
/* ANI */
/*******/
@@ -1040,7 +856,8 @@ static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
struct ath9k_htc_priv *priv = hw->priv;
- int padpos, padsize, ret;
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ int padpos, padsize, ret, slot;
hdr = (struct ieee80211_hdr *) skb->data;
@@ -1048,30 +865,32 @@ static void ath9k_htc_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
padpos = ath9k_cmn_padpos(hdr->frame_control);
padsize = padpos & 3;
if (padsize && skb->len > padpos) {
- if (skb_headroom(skb) < padsize)
+ if (skb_headroom(skb) < padsize) {
+ ath_dbg(common, ATH_DBG_XMIT, "No room for padding\n");
goto fail_tx;
+ }
skb_push(skb, padsize);
memmove(skb->data, skb->data + padsize, padpos);
}
- ret = ath9k_htc_tx_start(priv, skb);
- if (ret != 0) {
- if (ret == -ENOMEM) {
- ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
- "Stopping TX queues\n");
- ieee80211_stop_queues(hw);
- spin_lock_bh(&priv->tx_lock);
- priv->tx_queues_stop = true;
- spin_unlock_bh(&priv->tx_lock);
- } else {
- ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
- "Tx failed\n");
- }
+ slot = ath9k_htc_tx_get_slot(priv);
+ if (slot < 0) {
+ ath_dbg(common, ATH_DBG_XMIT, "No free TX slot\n");
goto fail_tx;
}
+ ret = ath9k_htc_tx_start(priv, skb, slot, false);
+ if (ret != 0) {
+ ath_dbg(common, ATH_DBG_XMIT, "Tx failed\n");
+ goto clear_slot;
+ }
+
+ ath9k_htc_check_stop_queues(priv);
+
return;
+clear_slot:
+ ath9k_htc_tx_clear_slot(priv, slot);
fail_tx:
dev_kfree_skb_any(skb);
}
@@ -1122,7 +941,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
ath9k_host_rx_init(priv);
- ret = ath9k_htc_update_cap_target(priv);
+ ret = ath9k_htc_update_cap_target(priv, 0);
if (ret)
ath_dbg(common, ATH_DBG_CONFIG,
"Failed to update capability in target\n");
@@ -1130,12 +949,15 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
priv->op_flags &= ~OP_INVALID;
htc_start(priv->htc);
- spin_lock_bh(&priv->tx_lock);
- priv->tx_queues_stop = false;
- spin_unlock_bh(&priv->tx_lock);
+ spin_lock_bh(&priv->tx.tx_lock);
+ priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP;
+ spin_unlock_bh(&priv->tx.tx_lock);
ieee80211_wake_queues(hw);
+ mod_timer(&priv->tx.cleanup_timer,
+ jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL));
+
if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) {
ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
AR_STOMP_LOW_WLAN_WGHT);
@@ -1152,7 +974,7 @@ static void ath9k_htc_stop(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 = 0;
+ int ret __attribute__ ((unused));
u8 cmd_rsp;
mutex_lock(&priv->mutex);
@@ -1164,25 +986,27 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
}
ath9k_htc_ps_wakeup(priv);
- htc_stop(priv->htc);
+
WMI_CMD(WMI_DISABLE_INTR_CMDID);
WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
WMI_CMD(WMI_STOP_RECV_CMDID);
- tasklet_kill(&priv->swba_tasklet);
tasklet_kill(&priv->rx_tasklet);
- tasklet_kill(&priv->tx_tasklet);
- skb_queue_purge(&priv->tx_queue);
+ del_timer_sync(&priv->tx.cleanup_timer);
+ ath9k_htc_tx_drain(priv);
+ ath9k_wmi_event_drain(priv);
mutex_unlock(&priv->mutex);
/* Cancel all the running timers/work .. */
cancel_work_sync(&priv->fatal_work);
cancel_work_sync(&priv->ps_work);
- cancel_delayed_work_sync(&priv->ath9k_led_blink_work);
+
+#ifdef CONFIG_MAC80211_LEDS
+ cancel_work_sync(&priv->led_work);
+#endif
ath9k_htc_stop_ani(priv);
- ath9k_led_stop_brightness(priv);
mutex_lock(&priv->mutex);
@@ -1245,13 +1069,13 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
switch (vif->type) {
case NL80211_IFTYPE_STATION:
- hvif.opmode = cpu_to_be32(HTC_M_STA);
+ hvif.opmode = HTC_M_STA;
break;
case NL80211_IFTYPE_ADHOC:
- hvif.opmode = cpu_to_be32(HTC_M_IBSS);
+ hvif.opmode = HTC_M_IBSS;
break;
case NL80211_IFTYPE_AP:
- hvif.opmode = cpu_to_be32(HTC_M_HOSTAP);
+ hvif.opmode = HTC_M_HOSTAP;
break;
default:
ath_err(common,
@@ -1281,14 +1105,20 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
priv->vif_slot |= (1 << avp->index);
priv->nvifs++;
- priv->vif = vif;
INC_VIF(priv, vif->type);
+
+ if ((vif->type == NL80211_IFTYPE_AP) ||
+ (vif->type == NL80211_IFTYPE_ADHOC))
+ ath9k_htc_assign_bslot(priv, vif);
+
ath9k_htc_set_opmode(priv);
if ((priv->ah->opmode == NL80211_IFTYPE_AP) &&
- !(priv->op_flags & OP_ANI_RUNNING))
+ !(priv->op_flags & OP_ANI_RUNNING)) {
+ ath9k_hw_set_tsfadjust(priv->ah, 1);
ath9k_htc_start_ani(priv);
+ }
ath_dbg(common, ATH_DBG_CONFIG,
"Attach a VIF of type: %d at idx: %d\n", vif->type, avp->index);
@@ -1317,15 +1147,25 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
hvif.index = avp->index;
WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
+ if (ret) {
+ ath_err(common, "Unable to remove interface at idx: %d\n",
+ avp->index);
+ }
priv->nvifs--;
priv->vif_slot &= ~(1 << avp->index);
ath9k_htc_remove_station(priv, vif, NULL);
- priv->vif = NULL;
DEC_VIF(priv, vif->type);
+
+ if ((vif->type == NL80211_IFTYPE_AP) ||
+ (vif->type == NL80211_IFTYPE_ADHOC))
+ ath9k_htc_remove_bslot(priv, vif);
+
ath9k_htc_set_opmode(priv);
+ ath9k_htc_set_bssid_mask(priv, vif);
+
/*
* Stop ANI only if there are no associated station interfaces.
*/
@@ -1493,10 +1333,13 @@ static int ath9k_htc_sta_remove(struct ieee80211_hw *hw,
struct ieee80211_sta *sta)
{
struct ath9k_htc_priv *priv = hw->priv;
+ struct ath9k_htc_sta *ista;
int ret;
mutex_lock(&priv->mutex);
ath9k_htc_ps_wakeup(priv);
+ ista = (struct ath9k_htc_sta *) sta->drv_priv;
+ htc_sta_drain(priv->htc, ista->index);
ret = ath9k_htc_remove_station(priv, vif, sta);
ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex);
@@ -1593,6 +1436,37 @@ static int ath9k_htc_set_key(struct ieee80211_hw *hw,
return ret;
}
+static void ath9k_htc_set_bssid(struct ath9k_htc_priv *priv)
+{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+
+ ath9k_hw_write_associd(priv->ah);
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "BSSID: %pM aid: 0x%x\n",
+ common->curbssid, common->curaid);
+}
+
+static void ath9k_htc_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
+{
+ struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+
+ if ((vif->type == NL80211_IFTYPE_STATION) && bss_conf->assoc) {
+ common->curaid = bss_conf->aid;
+ memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
+ }
+}
+
+static void ath9k_htc_choose_set_bssid(struct ath9k_htc_priv *priv)
+{
+ if (priv->num_sta_assoc_vif == 1) {
+ ieee80211_iterate_active_interfaces_atomic(priv->hw,
+ ath9k_htc_bss_iter, priv);
+ ath9k_htc_set_bssid(priv);
+ }
+}
+
static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
@@ -1601,49 +1475,39 @@ static void ath9k_htc_bss_info_changed(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);
- bool set_assoc;
mutex_lock(&priv->mutex);
ath9k_htc_ps_wakeup(priv);
- /*
- * Set the HW AID/BSSID only for the first station interface
- * or in IBSS mode.
- */
- set_assoc = !!((priv->ah->opmode == NL80211_IFTYPE_ADHOC) ||
- ((priv->ah->opmode == NL80211_IFTYPE_STATION) &&
- (priv->num_sta_vif == 1)));
-
-
if (changed & BSS_CHANGED_ASSOC) {
- if (set_assoc) {
- ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
- bss_conf->assoc);
+ ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
+ bss_conf->assoc);
- common->curaid = bss_conf->assoc ?
- bss_conf->aid : 0;
+ bss_conf->assoc ?
+ priv->num_sta_assoc_vif++ : priv->num_sta_assoc_vif--;
- if (bss_conf->assoc)
+ if (priv->ah->opmode == NL80211_IFTYPE_STATION) {
+ if (bss_conf->assoc && (priv->num_sta_assoc_vif == 1))
ath9k_htc_start_ani(priv);
- else
+ else if (priv->num_sta_assoc_vif == 0)
ath9k_htc_stop_ani(priv);
}
}
if (changed & BSS_CHANGED_BSSID) {
- if (set_assoc) {
+ if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) {
+ common->curaid = bss_conf->aid;
memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
- ath9k_hw_write_associd(ah);
-
- ath_dbg(common, ATH_DBG_CONFIG,
- "BSSID: %pM aid: 0x%x\n",
- common->curbssid, common->curaid);
+ ath9k_htc_set_bssid(priv);
+ } else if (priv->ah->opmode == NL80211_IFTYPE_STATION) {
+ ath9k_htc_choose_set_bssid(priv);
}
}
if ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon) {
ath_dbg(common, ATH_DBG_CONFIG,
"Beacon enabled for BSS: %pM\n", bss_conf->bssid);
+ ath9k_htc_set_tsfadjust(priv, vif);
priv->op_flags |= OP_ENABLE_BEACON;
ath9k_htc_beacon_config(priv, vif);
}
@@ -1741,6 +1605,7 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
int ret = 0;
mutex_lock(&priv->mutex);
+ ath9k_htc_ps_wakeup(priv);
switch (action) {
case IEEE80211_AMPDU_RX_START:
@@ -1758,14 +1623,15 @@ static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
ista = (struct ath9k_htc_sta *) sta->drv_priv;
- spin_lock_bh(&priv->tx_lock);
+ spin_lock_bh(&priv->tx.tx_lock);
ista->tid_state[tid] = AGGR_OPERATIONAL;
- spin_unlock_bh(&priv->tx_lock);
+ spin_unlock_bh(&priv->tx.tx_lock);
break;
default:
ath_err(ath9k_hw_common(priv->ah), "Unknown AMPDU action\n");
}
+ ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex);
return ret;
@@ -1816,6 +1682,55 @@ static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw,
mutex_unlock(&priv->mutex);
}
+/*
+ * Currently, this is used only for selecting the minimum rate
+ * for management frames, rate selection for data frames remain
+ * unaffected.
+ */
+static int ath9k_htc_set_bitrate_mask(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ const struct cfg80211_bitrate_mask *mask)
+{
+ struct ath9k_htc_priv *priv = hw->priv;
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ath9k_htc_target_rate_mask tmask;
+ struct ath9k_htc_vif *avp = (void *)vif->drv_priv;
+ int ret = 0;
+ u8 cmd_rsp;
+
+ memset(&tmask, 0, sizeof(struct ath9k_htc_target_rate_mask));
+
+ tmask.vif_index = avp->index;
+ tmask.band = IEEE80211_BAND_2GHZ;
+ tmask.mask = cpu_to_be32(mask->control[IEEE80211_BAND_2GHZ].legacy);
+
+ WMI_CMD_BUF(WMI_BITRATE_MASK_CMDID, &tmask);
+ if (ret) {
+ ath_err(common,
+ "Unable to set 2G rate mask for "
+ "interface at idx: %d\n", avp->index);
+ goto out;
+ }
+
+ tmask.band = IEEE80211_BAND_5GHZ;
+ tmask.mask = cpu_to_be32(mask->control[IEEE80211_BAND_5GHZ].legacy);
+
+ WMI_CMD_BUF(WMI_BITRATE_MASK_CMDID, &tmask);
+ if (ret) {
+ ath_err(common,
+ "Unable to set 5G rate mask for "
+ "interface at idx: %d\n", avp->index);
+ goto out;
+ }
+
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Set bitrate masks: 0x%x, 0x%x\n",
+ mask->control[IEEE80211_BAND_2GHZ].legacy,
+ mask->control[IEEE80211_BAND_5GHZ].legacy);
+out:
+ return ret;
+}
+
struct ieee80211_ops ath9k_htc_ops = {
.tx = ath9k_htc_tx,
.start = ath9k_htc_start,
@@ -1838,4 +1753,5 @@ struct ieee80211_ops ath9k_htc_ops = {
.set_rts_threshold = ath9k_htc_set_rts_threshold,
.rfkill_poll = ath9k_htc_rfkill_poll_state,
.set_coverage_class = ath9k_htc_set_coverage_class,
+ .set_bitrate_mask = ath9k_htc_set_bitrate_mask,
};
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index 4a4f27ba96af..2d81c700e201 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 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
@@ -53,6 +53,138 @@ int get_hw_qnum(u16 queue, int *hwq_map)
}
}
+void ath9k_htc_check_stop_queues(struct ath9k_htc_priv *priv)
+{
+ spin_lock_bh(&priv->tx.tx_lock);
+ priv->tx.queued_cnt++;
+ if ((priv->tx.queued_cnt >= ATH9K_HTC_TX_THRESHOLD) &&
+ !(priv->tx.flags & ATH9K_HTC_OP_TX_QUEUES_STOP)) {
+ priv->tx.flags |= ATH9K_HTC_OP_TX_QUEUES_STOP;
+ ieee80211_stop_queues(priv->hw);
+ }
+ spin_unlock_bh(&priv->tx.tx_lock);
+}
+
+void ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv)
+{
+ spin_lock_bh(&priv->tx.tx_lock);
+ if ((priv->tx.queued_cnt < ATH9K_HTC_TX_THRESHOLD) &&
+ (priv->tx.flags & ATH9K_HTC_OP_TX_QUEUES_STOP)) {
+ priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP;
+ ieee80211_wake_queues(priv->hw);
+ }
+ spin_unlock_bh(&priv->tx.tx_lock);
+}
+
+int ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv)
+{
+ int slot;
+
+ spin_lock_bh(&priv->tx.tx_lock);
+ slot = find_first_zero_bit(priv->tx.tx_slot, MAX_TX_BUF_NUM);
+ if (slot >= MAX_TX_BUF_NUM) {
+ spin_unlock_bh(&priv->tx.tx_lock);
+ return -ENOBUFS;
+ }
+ __set_bit(slot, priv->tx.tx_slot);
+ spin_unlock_bh(&priv->tx.tx_lock);
+
+ return slot;
+}
+
+void ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot)
+{
+ spin_lock_bh(&priv->tx.tx_lock);
+ __clear_bit(slot, priv->tx.tx_slot);
+ spin_unlock_bh(&priv->tx.tx_lock);
+}
+
+static inline enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv,
+ u16 qnum)
+{
+ enum htc_endpoint_id epid;
+
+ switch (qnum) {
+ case 0:
+ TX_QSTAT_INC(WME_AC_VO);
+ epid = priv->data_vo_ep;
+ break;
+ case 1:
+ TX_QSTAT_INC(WME_AC_VI);
+ epid = priv->data_vi_ep;
+ break;
+ case 2:
+ TX_QSTAT_INC(WME_AC_BE);
+ epid = priv->data_be_ep;
+ break;
+ case 3:
+ default:
+ TX_QSTAT_INC(WME_AC_BK);
+ epid = priv->data_bk_ep;
+ break;
+ }
+
+ return epid;
+}
+
+static inline struct sk_buff_head*
+get_htc_epid_queue(struct ath9k_htc_priv *priv, u8 epid)
+{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct sk_buff_head *epid_queue = NULL;
+
+ if (epid == priv->mgmt_ep)
+ epid_queue = &priv->tx.mgmt_ep_queue;
+ else if (epid == priv->cab_ep)
+ epid_queue = &priv->tx.cab_ep_queue;
+ else if (epid == priv->data_be_ep)
+ epid_queue = &priv->tx.data_be_queue;
+ else if (epid == priv->data_bk_ep)
+ epid_queue = &priv->tx.data_bk_queue;
+ else if (epid == priv->data_vi_ep)
+ epid_queue = &priv->tx.data_vi_queue;
+ else if (epid == priv->data_vo_ep)
+ epid_queue = &priv->tx.data_vo_queue;
+ else
+ ath_err(common, "Invalid EPID: %d\n", epid);
+
+ return epid_queue;
+}
+
+/*
+ * Removes the driver header and returns the TX slot number
+ */
+static inline int strip_drv_header(struct ath9k_htc_priv *priv,
+ struct sk_buff *skb)
+{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ath9k_htc_tx_ctl *tx_ctl;
+ int slot;
+
+ tx_ctl = HTC_SKB_CB(skb);
+
+ if (tx_ctl->epid == priv->mgmt_ep) {
+ struct tx_mgmt_hdr *tx_mhdr =
+ (struct tx_mgmt_hdr *)skb->data;
+ slot = tx_mhdr->cookie;
+ skb_pull(skb, sizeof(struct tx_mgmt_hdr));
+ } else if ((tx_ctl->epid == priv->data_bk_ep) ||
+ (tx_ctl->epid == priv->data_be_ep) ||
+ (tx_ctl->epid == priv->data_vi_ep) ||
+ (tx_ctl->epid == priv->data_vo_ep) ||
+ (tx_ctl->epid == priv->cab_ep)) {
+ struct tx_frame_hdr *tx_fhdr =
+ (struct tx_frame_hdr *)skb->data;
+ slot = tx_fhdr->cookie;
+ skb_pull(skb, sizeof(struct tx_frame_hdr));
+ } else {
+ ath_err(common, "Unsupported EPID: %d\n", tx_ctl->epid);
+ slot = -EINVAL;
+ }
+
+ return slot;
+}
+
int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum,
struct ath9k_tx_queue_info *qinfo)
{
@@ -79,23 +211,140 @@ int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum,
return error;
}
-int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
+static void ath9k_htc_tx_mgmt(struct ath9k_htc_priv *priv,
+ struct ath9k_htc_vif *avp,
+ struct sk_buff *skb,
+ u8 sta_idx, u8 vif_idx, u8 slot)
+{
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_mgmt *mgmt;
+ struct ieee80211_hdr *hdr;
+ struct tx_mgmt_hdr mgmt_hdr;
+ struct ath9k_htc_tx_ctl *tx_ctl;
+ u8 *tx_fhdr;
+
+ tx_ctl = HTC_SKB_CB(skb);
+ hdr = (struct ieee80211_hdr *) skb->data;
+
+ memset(tx_ctl, 0, sizeof(*tx_ctl));
+ memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr));
+
+ /*
+ * Set the TSF adjust value for probe response
+ * frame also.
+ */
+ if (avp && unlikely(ieee80211_is_probe_resp(hdr->frame_control))) {
+ mgmt = (struct ieee80211_mgmt *)skb->data;
+ mgmt->u.probe_resp.timestamp = avp->tsfadjust;
+ }
+
+ tx_ctl->type = ATH9K_HTC_MGMT;
+
+ mgmt_hdr.node_idx = sta_idx;
+ mgmt_hdr.vif_idx = vif_idx;
+ mgmt_hdr.tidno = 0;
+ mgmt_hdr.flags = 0;
+ mgmt_hdr.cookie = slot;
+
+ mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
+ if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
+ mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
+ else
+ mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
+
+ tx_fhdr = skb_push(skb, sizeof(mgmt_hdr));
+ memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr));
+ tx_ctl->epid = priv->mgmt_ep;
+}
+
+static void ath9k_htc_tx_data(struct ath9k_htc_priv *priv,
+ struct ieee80211_vif *vif,
+ struct sk_buff *skb,
+ u8 sta_idx, u8 vif_idx, u8 slot,
+ bool is_cab)
+{
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_hdr *hdr;
+ struct ath9k_htc_tx_ctl *tx_ctl;
+ struct tx_frame_hdr tx_hdr;
+ u32 flags = 0;
+ u8 *qc, *tx_fhdr;
+ u16 qnum;
+
+ tx_ctl = HTC_SKB_CB(skb);
+ hdr = (struct ieee80211_hdr *) skb->data;
+
+ memset(tx_ctl, 0, sizeof(*tx_ctl));
+ memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr));
+
+ tx_hdr.node_idx = sta_idx;
+ tx_hdr.vif_idx = vif_idx;
+ tx_hdr.cookie = slot;
+
+ /*
+ * This is a bit redundant but it helps to get
+ * the per-packet index quickly when draining the
+ * TX queue in the HIF layer. Otherwise we would
+ * have to parse the packet contents ...
+ */
+ tx_ctl->sta_idx = sta_idx;
+
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+ tx_ctl->type = ATH9K_HTC_AMPDU;
+ tx_hdr.data_type = ATH9K_HTC_AMPDU;
+ } else {
+ tx_ctl->type = ATH9K_HTC_NORMAL;
+ tx_hdr.data_type = ATH9K_HTC_NORMAL;
+ }
+
+ if (ieee80211_is_data_qos(hdr->frame_control)) {
+ qc = ieee80211_get_qos_ctl(hdr);
+ tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+ }
+
+ /* Check for RTS protection */
+ if (priv->hw->wiphy->rts_threshold != (u32) -1)
+ if (skb->len > priv->hw->wiphy->rts_threshold)
+ flags |= ATH9K_HTC_TX_RTSCTS;
+
+ /* CTS-to-self */
+ if (!(flags & ATH9K_HTC_TX_RTSCTS) &&
+ (vif && vif->bss_conf.use_cts_prot))
+ flags |= ATH9K_HTC_TX_CTSONLY;
+
+ tx_hdr.flags = cpu_to_be32(flags);
+ tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
+ if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
+ tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
+ else
+ tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
+
+ tx_fhdr = skb_push(skb, sizeof(tx_hdr));
+ memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr));
+
+ if (is_cab) {
+ CAB_STAT_INC;
+ tx_ctl->epid = priv->cab_ep;
+ return;
+ }
+
+ qnum = skb_get_queue_mapping(skb);
+ tx_ctl->epid = get_htc_epid(priv, qnum);
+}
+
+int ath9k_htc_tx_start(struct ath9k_htc_priv *priv,
+ struct sk_buff *skb,
+ u8 slot, bool is_cab)
{
struct ieee80211_hdr *hdr;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_sta *sta = tx_info->control.sta;
struct ieee80211_vif *vif = tx_info->control.vif;
struct ath9k_htc_sta *ista;
- struct ath9k_htc_vif *avp;
- struct ath9k_htc_tx_ctl tx_ctl;
- enum htc_endpoint_id epid;
- u16 qnum;
- __le16 fc;
- u8 *tx_fhdr;
+ struct ath9k_htc_vif *avp = NULL;
u8 sta_idx, vif_idx;
hdr = (struct ieee80211_hdr *) skb->data;
- fc = hdr->frame_control;
/*
* Find out on which interface this packet has to be
@@ -124,218 +373,430 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
sta_idx = priv->vif_sta_pos[vif_idx];
}
- memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl));
+ if (ieee80211_is_data(hdr->frame_control))
+ ath9k_htc_tx_data(priv, vif, skb,
+ sta_idx, vif_idx, slot, is_cab);
+ else
+ ath9k_htc_tx_mgmt(priv, avp, skb,
+ sta_idx, vif_idx, slot);
- if (ieee80211_is_data(fc)) {
- struct tx_frame_hdr tx_hdr;
- u32 flags = 0;
- u8 *qc;
- memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr));
+ return htc_send(priv->htc, skb);
+}
- tx_hdr.node_idx = sta_idx;
- tx_hdr.vif_idx = vif_idx;
+static inline bool __ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv,
+ struct ath9k_htc_sta *ista, u8 tid)
+{
+ bool ret = false;
- if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
- tx_ctl.type = ATH9K_HTC_AMPDU;
- tx_hdr.data_type = ATH9K_HTC_AMPDU;
- } else {
- tx_ctl.type = ATH9K_HTC_NORMAL;
- tx_hdr.data_type = ATH9K_HTC_NORMAL;
- }
+ spin_lock_bh(&priv->tx.tx_lock);
+ if ((tid < ATH9K_HTC_MAX_TID) && (ista->tid_state[tid] == AGGR_STOP))
+ ret = true;
+ spin_unlock_bh(&priv->tx.tx_lock);
+
+ return ret;
+}
+
+static void ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv,
+ struct ieee80211_vif *vif,
+ struct sk_buff *skb)
+{
+ struct ieee80211_sta *sta;
+ struct ieee80211_hdr *hdr;
+ __le16 fc;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ fc = hdr->frame_control;
+
+ rcu_read_lock();
+
+ sta = ieee80211_find_sta(vif, hdr->addr1);
+ if (!sta) {
+ rcu_read_unlock();
+ return;
+ }
+ if (sta && conf_is_ht(&priv->hw->conf) &&
+ !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
if (ieee80211_is_data_qos(fc)) {
+ u8 *qc, tid;
+ struct ath9k_htc_sta *ista;
+
qc = ieee80211_get_qos_ctl(hdr);
- tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+ tid = qc[0] & 0xf;
+ ista = (struct ath9k_htc_sta *)sta->drv_priv;
+ if (__ath9k_htc_check_tx_aggr(priv, ista, tid)) {
+ ieee80211_start_tx_ba_session(sta, tid, 0);
+ spin_lock_bh(&priv->tx.tx_lock);
+ ista->tid_state[tid] = AGGR_PROGRESS;
+ spin_unlock_bh(&priv->tx.tx_lock);
+ }
}
+ }
- /* Check for RTS protection */
- if (priv->hw->wiphy->rts_threshold != (u32) -1)
- if (skb->len > priv->hw->wiphy->rts_threshold)
- flags |= ATH9K_HTC_TX_RTSCTS;
+ rcu_read_unlock();
+}
- /* CTS-to-self */
- if (!(flags & ATH9K_HTC_TX_RTSCTS) &&
- (vif && vif->bss_conf.use_cts_prot))
- flags |= ATH9K_HTC_TX_CTSONLY;
+static void ath9k_htc_tx_process(struct ath9k_htc_priv *priv,
+ struct sk_buff *skb,
+ struct __wmi_event_txstatus *txs)
+{
+ struct ieee80211_vif *vif;
+ struct ath9k_htc_tx_ctl *tx_ctl;
+ struct ieee80211_tx_info *tx_info;
+ struct ieee80211_tx_rate *rate;
+ struct ieee80211_conf *cur_conf = &priv->hw->conf;
+ bool txok;
+ int slot;
- tx_hdr.flags = cpu_to_be32(flags);
- tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
- if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
- tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
- else
- tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
+ slot = strip_drv_header(priv, skb);
+ if (slot < 0) {
+ dev_kfree_skb_any(skb);
+ return;
+ }
- tx_fhdr = skb_push(skb, sizeof(tx_hdr));
- memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr));
+ tx_ctl = HTC_SKB_CB(skb);
+ txok = tx_ctl->txok;
+ tx_info = IEEE80211_SKB_CB(skb);
+ vif = tx_info->control.vif;
+ rate = &tx_info->status.rates[0];
- qnum = skb_get_queue_mapping(skb);
+ memset(&tx_info->status, 0, sizeof(tx_info->status));
- switch (qnum) {
- case 0:
- TX_QSTAT_INC(WME_AC_VO);
- epid = priv->data_vo_ep;
- break;
- case 1:
- TX_QSTAT_INC(WME_AC_VI);
- epid = priv->data_vi_ep;
- break;
- case 2:
- TX_QSTAT_INC(WME_AC_BE);
- epid = priv->data_be_ep;
- break;
- case 3:
- default:
- TX_QSTAT_INC(WME_AC_BK);
- epid = priv->data_bk_ep;
- break;
- }
- } else {
- struct tx_mgmt_hdr mgmt_hdr;
+ /*
+ * URB submission failed for this frame, it never reached
+ * the target.
+ */
+ if (!txok || !vif || !txs)
+ goto send_mac80211;
+
+ if (txs->ts_flags & ATH9K_HTC_TXSTAT_ACK)
+ tx_info->flags |= IEEE80211_TX_STAT_ACK;
- memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr));
+ if (txs->ts_flags & ATH9K_HTC_TXSTAT_FILT)
+ tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
- tx_ctl.type = ATH9K_HTC_NORMAL;
+ if (txs->ts_flags & ATH9K_HTC_TXSTAT_RTC_CTS)
+ rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS;
- mgmt_hdr.node_idx = sta_idx;
- mgmt_hdr.vif_idx = vif_idx;
- mgmt_hdr.tidno = 0;
- mgmt_hdr.flags = 0;
+ rate->count = 1;
+ rate->idx = MS(txs->ts_rate, ATH9K_HTC_TXSTAT_RATE);
- mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb);
- if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR)
- mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID;
- else
- mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx;
+ if (txs->ts_flags & ATH9K_HTC_TXSTAT_MCS) {
+ rate->flags |= IEEE80211_TX_RC_MCS;
- tx_fhdr = skb_push(skb, sizeof(mgmt_hdr));
- memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr));
- epid = priv->mgmt_ep;
+ if (txs->ts_flags & ATH9K_HTC_TXSTAT_CW40)
+ rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+ if (txs->ts_flags & ATH9K_HTC_TXSTAT_SGI)
+ rate->flags |= IEEE80211_TX_RC_SHORT_GI;
+ } else {
+ if (cur_conf->channel->band == IEEE80211_BAND_5GHZ)
+ rate->idx += 4; /* No CCK rates */
}
- return htc_send(priv->htc, skb, epid, &tx_ctl);
+ ath9k_htc_check_tx_aggr(priv, vif, skb);
+
+send_mac80211:
+ spin_lock_bh(&priv->tx.tx_lock);
+ if (WARN_ON(--priv->tx.queued_cnt < 0))
+ priv->tx.queued_cnt = 0;
+ spin_unlock_bh(&priv->tx.tx_lock);
+
+ ath9k_htc_tx_clear_slot(priv, slot);
+
+ /* Send status to mac80211 */
+ ieee80211_tx_status(priv->hw, skb);
}
-static bool ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv,
- struct ath9k_htc_sta *ista, u8 tid)
+static inline void ath9k_htc_tx_drainq(struct ath9k_htc_priv *priv,
+ struct sk_buff_head *queue)
{
- bool ret = false;
+ struct sk_buff *skb;
- 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);
+ while ((skb = skb_dequeue(queue)) != NULL) {
+ ath9k_htc_tx_process(priv, skb, NULL);
+ }
+}
- return ret;
+void ath9k_htc_tx_drain(struct ath9k_htc_priv *priv)
+{
+ struct ath9k_htc_tx_event *event, *tmp;
+
+ spin_lock_bh(&priv->tx.tx_lock);
+ priv->tx.flags |= ATH9K_HTC_OP_TX_DRAIN;
+ spin_unlock_bh(&priv->tx.tx_lock);
+
+ /*
+ * Ensure that all pending TX frames are flushed,
+ * and that the TX completion/failed tasklets is killed.
+ */
+ htc_stop(priv->htc);
+ tasklet_kill(&priv->wmi->wmi_event_tasklet);
+ tasklet_kill(&priv->tx_failed_tasklet);
+
+ ath9k_htc_tx_drainq(priv, &priv->tx.mgmt_ep_queue);
+ ath9k_htc_tx_drainq(priv, &priv->tx.cab_ep_queue);
+ ath9k_htc_tx_drainq(priv, &priv->tx.data_be_queue);
+ ath9k_htc_tx_drainq(priv, &priv->tx.data_bk_queue);
+ ath9k_htc_tx_drainq(priv, &priv->tx.data_vi_queue);
+ ath9k_htc_tx_drainq(priv, &priv->tx.data_vo_queue);
+ ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed);
+
+ /*
+ * The TX cleanup timer has already been killed.
+ */
+ spin_lock_bh(&priv->wmi->event_lock);
+ list_for_each_entry_safe(event, tmp, &priv->wmi->pending_tx_events, list) {
+ list_del(&event->list);
+ kfree(event);
+ }
+ spin_unlock_bh(&priv->wmi->event_lock);
+
+ spin_lock_bh(&priv->tx.tx_lock);
+ priv->tx.flags &= ~ATH9K_HTC_OP_TX_DRAIN;
+ spin_unlock_bh(&priv->tx.tx_lock);
}
-void ath9k_tx_tasklet(unsigned long data)
+void ath9k_tx_failed_tasklet(unsigned long data)
{
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
- struct ieee80211_vif *vif;
- struct ieee80211_sta *sta;
- struct ieee80211_hdr *hdr;
- struct ieee80211_tx_info *tx_info;
- struct sk_buff *skb = NULL;
- __le16 fc;
- while ((skb = skb_dequeue(&priv->tx_queue)) != NULL) {
+ spin_lock_bh(&priv->tx.tx_lock);
+ if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) {
+ spin_unlock_bh(&priv->tx.tx_lock);
+ return;
+ }
+ spin_unlock_bh(&priv->tx.tx_lock);
- hdr = (struct ieee80211_hdr *) skb->data;
- fc = hdr->frame_control;
- tx_info = IEEE80211_SKB_CB(skb);
- vif = tx_info->control.vif;
+ ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed);
+}
- memset(&tx_info->status, 0, sizeof(tx_info->status));
+static inline bool check_cookie(struct ath9k_htc_priv *priv,
+ struct sk_buff *skb,
+ u8 cookie, u8 epid)
+{
+ u8 fcookie = 0;
+
+ if (epid == priv->mgmt_ep) {
+ struct tx_mgmt_hdr *hdr;
+ hdr = (struct tx_mgmt_hdr *) skb->data;
+ fcookie = hdr->cookie;
+ } else if ((epid == priv->data_bk_ep) ||
+ (epid == priv->data_be_ep) ||
+ (epid == priv->data_vi_ep) ||
+ (epid == priv->data_vo_ep) ||
+ (epid == priv->cab_ep)) {
+ struct tx_frame_hdr *hdr;
+ hdr = (struct tx_frame_hdr *) skb->data;
+ fcookie = hdr->cookie;
+ }
- if (!vif)
- goto send_mac80211;
+ if (fcookie == cookie)
+ return true;
- rcu_read_lock();
+ return false;
+}
- sta = ieee80211_find_sta(vif, hdr->addr1);
- if (!sta) {
- rcu_read_unlock();
- ieee80211_tx_status(priv->hw, skb);
- continue;
+static struct sk_buff* ath9k_htc_tx_get_packet(struct ath9k_htc_priv *priv,
+ struct __wmi_event_txstatus *txs)
+{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct sk_buff_head *epid_queue;
+ struct sk_buff *skb, *tmp;
+ unsigned long flags;
+ u8 epid = MS(txs->ts_rate, ATH9K_HTC_TXSTAT_EPID);
+
+ epid_queue = get_htc_epid_queue(priv, epid);
+ if (!epid_queue)
+ return NULL;
+
+ spin_lock_irqsave(&epid_queue->lock, flags);
+ skb_queue_walk_safe(epid_queue, skb, tmp) {
+ if (check_cookie(priv, skb, txs->cookie, epid)) {
+ __skb_unlink(skb, epid_queue);
+ spin_unlock_irqrestore(&epid_queue->lock, flags);
+ return skb;
}
+ }
+ spin_unlock_irqrestore(&epid_queue->lock, flags);
- /* Check if we need to start aggregation */
+ ath_dbg(common, ATH_DBG_XMIT,
+ "No matching packet for cookie: %d, epid: %d\n",
+ txs->cookie, epid);
- if (sta && conf_is_ht(&priv->hw->conf) &&
- !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
- if (ieee80211_is_data_qos(fc)) {
- u8 *qc, tid;
- struct ath9k_htc_sta *ista;
+ return NULL;
+}
- qc = ieee80211_get_qos_ctl(hdr);
- tid = qc[0] & 0xf;
- ista = (struct ath9k_htc_sta *)sta->drv_priv;
+void ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event)
+{
+ struct wmi_event_txstatus *txs = (struct wmi_event_txstatus *)wmi_event;
+ struct __wmi_event_txstatus *__txs;
+ struct sk_buff *skb;
+ struct ath9k_htc_tx_event *tx_pend;
+ int i;
- if (ath9k_htc_check_tx_aggr(priv, ista, tid)) {
- ieee80211_start_tx_ba_session(sta, tid, 0);
- spin_lock_bh(&priv->tx_lock);
- ista->tid_state[tid] = AGGR_PROGRESS;
- spin_unlock_bh(&priv->tx_lock);
- }
- }
- }
+ for (i = 0; i < txs->cnt; i++) {
+ WARN_ON(txs->cnt > HTC_MAX_TX_STATUS);
- rcu_read_unlock();
+ __txs = &txs->txstatus[i];
+
+ skb = ath9k_htc_tx_get_packet(priv, __txs);
+ if (!skb) {
+ /*
+ * Store this event, so that the TX cleanup
+ * routine can check later for the needed packet.
+ */
+ tx_pend = kzalloc(sizeof(struct ath9k_htc_tx_event),
+ GFP_ATOMIC);
+ if (!tx_pend)
+ continue;
+
+ memcpy(&tx_pend->txs, __txs,
+ sizeof(struct __wmi_event_txstatus));
+
+ spin_lock(&priv->wmi->event_lock);
+ list_add_tail(&tx_pend->list,
+ &priv->wmi->pending_tx_events);
+ spin_unlock(&priv->wmi->event_lock);
+
+ continue;
+ }
- send_mac80211:
- /* Send status to mac80211 */
- ieee80211_tx_status(priv->hw, skb);
+ ath9k_htc_tx_process(priv, skb, __txs);
}
/* Wake TX queues if needed */
- spin_lock_bh(&priv->tx_lock);
- if (priv->tx_queues_stop) {
- priv->tx_queues_stop = false;
- spin_unlock_bh(&priv->tx_lock);
- ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT,
- "Waking up TX queues\n");
- ieee80211_wake_queues(priv->hw);
- return;
- }
- spin_unlock_bh(&priv->tx_lock);
+ ath9k_htc_check_wake_queues(priv);
}
void ath9k_htc_txep(void *drv_priv, struct sk_buff *skb,
enum htc_endpoint_id ep_id, bool txok)
{
struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv;
- struct ath_common *common = ath9k_hw_common(priv->ah);
- struct ieee80211_tx_info *tx_info;
+ struct ath9k_htc_tx_ctl *tx_ctl;
+ struct sk_buff_head *epid_queue;
+
+ tx_ctl = HTC_SKB_CB(skb);
+ tx_ctl->txok = txok;
+ tx_ctl->timestamp = jiffies;
- if (!skb)
+ if (!txok) {
+ skb_queue_tail(&priv->tx.tx_failed, skb);
+ tasklet_schedule(&priv->tx_failed_tasklet);
return;
+ }
- if (ep_id == priv->mgmt_ep) {
- skb_pull(skb, sizeof(struct tx_mgmt_hdr));
- } else if ((ep_id == priv->data_bk_ep) ||
- (ep_id == priv->data_be_ep) ||
- (ep_id == priv->data_vi_ep) ||
- (ep_id == priv->data_vo_ep)) {
- skb_pull(skb, sizeof(struct tx_frame_hdr));
- } else {
- ath_err(common, "Unsupported TX EPID: %d\n", ep_id);
+ epid_queue = get_htc_epid_queue(priv, ep_id);
+ if (!epid_queue) {
dev_kfree_skb_any(skb);
return;
}
- tx_info = IEEE80211_SKB_CB(skb);
+ skb_queue_tail(epid_queue, skb);
+}
- if (txok)
- tx_info->flags |= IEEE80211_TX_STAT_ACK;
+static inline bool check_packet(struct ath9k_htc_priv *priv, struct sk_buff *skb)
+{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ath9k_htc_tx_ctl *tx_ctl;
+
+ tx_ctl = HTC_SKB_CB(skb);
+
+ if (time_after(jiffies,
+ tx_ctl->timestamp +
+ msecs_to_jiffies(ATH9K_HTC_TX_TIMEOUT_INTERVAL))) {
+ ath_dbg(common, ATH_DBG_XMIT,
+ "Dropping a packet due to TX timeout\n");
+ return true;
+ }
- skb_queue_tail(&priv->tx_queue, skb);
- tasklet_schedule(&priv->tx_tasklet);
+ return false;
+}
+
+static void ath9k_htc_tx_cleanup_queue(struct ath9k_htc_priv *priv,
+ struct sk_buff_head *epid_queue)
+{
+ bool process = false;
+ unsigned long flags;
+ struct sk_buff *skb, *tmp;
+ struct sk_buff_head queue;
+
+ skb_queue_head_init(&queue);
+
+ spin_lock_irqsave(&epid_queue->lock, flags);
+ skb_queue_walk_safe(epid_queue, skb, tmp) {
+ if (check_packet(priv, skb)) {
+ __skb_unlink(skb, epid_queue);
+ __skb_queue_tail(&queue, skb);
+ process = true;
+ }
+ }
+ spin_unlock_irqrestore(&epid_queue->lock, flags);
+
+ if (process) {
+ skb_queue_walk_safe(&queue, skb, tmp) {
+ __skb_unlink(skb, &queue);
+ ath9k_htc_tx_process(priv, skb, NULL);
+ }
+ }
+}
+
+void ath9k_htc_tx_cleanup_timer(unsigned long data)
+{
+ struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) data;
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ath9k_htc_tx_event *event, *tmp;
+ struct sk_buff *skb;
+
+ spin_lock(&priv->wmi->event_lock);
+ list_for_each_entry_safe(event, tmp, &priv->wmi->pending_tx_events, list) {
+
+ skb = ath9k_htc_tx_get_packet(priv, &event->txs);
+ if (skb) {
+ ath_dbg(common, ATH_DBG_XMIT,
+ "Found packet for cookie: %d, epid: %d\n",
+ event->txs.cookie,
+ MS(event->txs.ts_rate, ATH9K_HTC_TXSTAT_EPID));
+
+ ath9k_htc_tx_process(priv, skb, &event->txs);
+ list_del(&event->list);
+ kfree(event);
+ continue;
+ }
+
+ if (++event->count >= ATH9K_HTC_TX_TIMEOUT_COUNT) {
+ list_del(&event->list);
+ kfree(event);
+ }
+ }
+ spin_unlock(&priv->wmi->event_lock);
+
+ /*
+ * Check if status-pending packets have to be cleaned up.
+ */
+ ath9k_htc_tx_cleanup_queue(priv, &priv->tx.mgmt_ep_queue);
+ ath9k_htc_tx_cleanup_queue(priv, &priv->tx.cab_ep_queue);
+ ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_be_queue);
+ ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_bk_queue);
+ ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_vi_queue);
+ ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_vo_queue);
+
+ /* Wake TX queues if needed */
+ ath9k_htc_check_wake_queues(priv);
+
+ mod_timer(&priv->tx.cleanup_timer,
+ jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL));
}
int ath9k_tx_init(struct ath9k_htc_priv *priv)
{
- skb_queue_head_init(&priv->tx_queue);
+ skb_queue_head_init(&priv->tx.mgmt_ep_queue);
+ skb_queue_head_init(&priv->tx.cab_ep_queue);
+ skb_queue_head_init(&priv->tx.data_be_queue);
+ skb_queue_head_init(&priv->tx.data_bk_queue);
+ skb_queue_head_init(&priv->tx.data_vi_queue);
+ skb_queue_head_init(&priv->tx.data_vo_queue);
+ skb_queue_head_init(&priv->tx.tx_failed);
return 0;
}
@@ -414,6 +875,7 @@ u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv)
rfilt |= ATH9K_RX_FILTER_CONTROL;
if ((ah->opmode == NL80211_IFTYPE_STATION) &&
+ (priv->nvifs <= 1) &&
!(priv->rxfilter & FIF_BCN_PRBRESP_PROMISC))
rfilt |= ATH9K_RX_FILTER_MYBEACON;
else
@@ -427,6 +889,9 @@ u32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv)
if (priv->rxfilter & FIF_PSPOLL)
rfilt |= ATH9K_RX_FILTER_PSPOLL;
+ if (priv->nvifs > 1)
+ rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL;
+
return rfilt;
#undef RX_FILTER_PRESERVE
@@ -507,8 +972,9 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
int last_rssi = ATH_RSSI_DUMMY_MARKER;
__le16 fc;
- if (skb->len <= HTC_RX_FRAME_HEADER_SIZE) {
- ath_err(common, "Corrupted RX frame, dropping\n");
+ if (skb->len < HTC_RX_FRAME_HEADER_SIZE) {
+ ath_err(common, "Corrupted RX frame, dropping (len: %d)\n",
+ skb->len);
goto rx_next;
}
@@ -522,6 +988,8 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
goto rx_next;
}
+ ath9k_htc_err_stat_rx(priv, rxstatus);
+
/* Get the RX status information */
memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE);
skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE);
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c
index 62e139a30a74..1b90ed8795c3 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.c
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 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,8 @@
#include "htc.h"
static int htc_issue_send(struct htc_target *target, struct sk_buff* skb,
- u16 len, u8 flags, u8 epid,
- struct ath9k_htc_tx_ctl *tx_ctl)
+ u16 len, u8 flags, u8 epid)
+
{
struct htc_frame_hdr *hdr;
struct htc_endpoint *endpoint = &target->endpoint[epid];
@@ -30,8 +30,8 @@ static int htc_issue_send(struct htc_target *target, struct sk_buff* skb,
hdr->flags = flags;
hdr->payload_len = cpu_to_be16(len);
- status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb,
- tx_ctl);
+ status = target->hif->send(target->hif_dev, endpoint->ul_pipeid, skb);
+
return status;
}
@@ -162,7 +162,7 @@ static int htc_config_pipe_credits(struct htc_target *target)
target->htc_flags |= HTC_OP_CONFIG_PIPE_CREDITS;
- ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL);
+ ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
if (ret)
goto err;
@@ -197,7 +197,7 @@ static int htc_setup_complete(struct htc_target *target)
target->htc_flags |= HTC_OP_START_WAIT;
- ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL);
+ ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
if (ret)
goto err;
@@ -268,7 +268,7 @@ int htc_connect_service(struct htc_target *target,
conn_msg->dl_pipeid = endpoint->dl_pipeid;
conn_msg->ul_pipeid = endpoint->ul_pipeid;
- ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0, NULL);
+ ret = htc_issue_send(target, skb, skb->len, 0, ENDPOINT0);
if (ret)
goto err;
@@ -286,35 +286,33 @@ err:
return ret;
}
-int htc_send(struct htc_target *target, struct sk_buff *skb,
- enum htc_endpoint_id epid, struct ath9k_htc_tx_ctl *tx_ctl)
+int htc_send(struct htc_target *target, struct sk_buff *skb)
{
- return htc_issue_send(target, skb, skb->len, 0, epid, tx_ctl);
+ struct ath9k_htc_tx_ctl *tx_ctl;
+
+ tx_ctl = HTC_SKB_CB(skb);
+ return htc_issue_send(target, skb, skb->len, 0, tx_ctl->epid);
}
-void htc_stop(struct htc_target *target)
+int htc_send_epid(struct htc_target *target, struct sk_buff *skb,
+ enum htc_endpoint_id epid)
{
- enum htc_endpoint_id epid;
- struct htc_endpoint *endpoint;
+ return htc_issue_send(target, skb, skb->len, 0, epid);
+}
- for (epid = ENDPOINT0; epid < ENDPOINT_MAX; epid++) {
- endpoint = &target->endpoint[epid];
- if (endpoint->service_id != 0)
- target->hif->stop(target->hif_dev, endpoint->ul_pipeid);
- }
+void htc_stop(struct htc_target *target)
+{
+ target->hif->stop(target->hif_dev);
}
void htc_start(struct htc_target *target)
{
- enum htc_endpoint_id epid;
- struct htc_endpoint *endpoint;
+ target->hif->start(target->hif_dev);
+}
- for (epid = ENDPOINT0; epid < ENDPOINT_MAX; epid++) {
- endpoint = &target->endpoint[epid];
- if (endpoint->service_id != 0)
- target->hif->start(target->hif_dev,
- endpoint->ul_pipeid);
- }
+void htc_sta_drain(struct htc_target *target, u8 idx)
+{
+ target->hif->sta_drain(target->hif_dev, idx);
}
void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle,
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.h b/drivers/net/wireless/ath/ath9k/htc_hst.h
index ecd018798c47..e1ffbb6bd636 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.h
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 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
@@ -33,10 +33,10 @@ struct ath9k_htc_hif {
u8 control_dl_pipe;
u8 control_ul_pipe;
- void (*start) (void *hif_handle, u8 pipe);
- void (*stop) (void *hif_handle, u8 pipe);
- int (*send) (void *hif_handle, u8 pipe, struct sk_buff *buf,
- struct ath9k_htc_tx_ctl *tx_ctl);
+ void (*start) (void *hif_handle);
+ void (*stop) (void *hif_handle);
+ void (*sta_drain) (void *hif_handle, u8 idx);
+ int (*send) (void *hif_handle, u8 pipe, struct sk_buff *buf);
};
enum htc_endpoint_id {
@@ -83,21 +83,10 @@ struct htc_ep_callbacks {
void (*rx) (void *, struct sk_buff *, enum htc_endpoint_id);
};
-#define HTC_TX_QUEUE_SIZE 256
-
-struct htc_txq {
- struct sk_buff *buf[HTC_TX_QUEUE_SIZE];
- u32 txqdepth;
- u16 txbuf_cnt;
- u16 txq_head;
- u16 txq_tail;
-};
-
struct htc_endpoint {
u16 service_id;
struct htc_ep_callbacks ep_callbacks;
- struct htc_txq htc_txq;
u32 max_txqdepth;
int max_msglen;
@@ -205,10 +194,12 @@ int htc_init(struct htc_target *target);
int htc_connect_service(struct htc_target *target,
struct htc_service_connreq *service_connreq,
enum htc_endpoint_id *conn_rsp_eid);
-int htc_send(struct htc_target *target, struct sk_buff *skb,
- enum htc_endpoint_id eid, struct ath9k_htc_tx_ctl *tx_ctl);
+int htc_send(struct htc_target *target, struct sk_buff *skb);
+int htc_send_epid(struct htc_target *target, struct sk_buff *skb,
+ enum htc_endpoint_id epid);
void htc_stop(struct htc_target *target);
void htc_start(struct htc_target *target);
+void htc_sta_drain(struct htc_target *target, u8 idx);
void ath9k_htc_rx_msg(struct htc_target *htc_handle,
struct sk_buff *skb, u32 len, u8 pipe_id);
diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h
index c8f254fe0f0b..2f3e07263fcb 100644
--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 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
@@ -116,16 +116,21 @@ static inline void ath9k_hw_clr11n_aggr(struct ath_hw *ah, void *ds)
ath9k_hw_ops(ah)->clr11n_aggr(ah, ds);
}
-static inline void ath9k_hw_set11n_burstduration(struct ath_hw *ah, void *ds,
- u32 burstDuration)
+static inline void ath9k_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
{
- ath9k_hw_ops(ah)->set11n_burstduration(ah, ds, burstDuration);
+ ath9k_hw_ops(ah)->set_clrdmask(ah, ds, val);
}
-static inline void ath9k_hw_set11n_virtualmorefrag(struct ath_hw *ah, void *ds,
- u32 vmf)
+static inline void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah,
+ struct ath_hw_antcomb_conf *antconf)
{
- ath9k_hw_ops(ah)->set11n_virtualmorefrag(ah, ds, vmf);
+ ath9k_hw_ops(ah)->antdiv_comb_conf_get(ah, antconf);
+}
+
+static inline void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah,
+ struct ath_hw_antcomb_conf *antconf)
+{
+ ath9k_hw_ops(ah)->antdiv_comb_conf_set(ah, antconf);
}
/* Private hardware call ops */
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index c95bc5cc1a1f..72543ce8f616 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -130,6 +130,20 @@ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout)
}
EXPORT_SYMBOL(ath9k_hw_wait);
+void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array,
+ int column, unsigned int *writecnt)
+{
+ int r;
+
+ ENABLE_REGWRITE_BUFFER(ah);
+ for (r = 0; r < array->ia_rows; r++) {
+ REG_WRITE(ah, INI_RA(array, r, 0),
+ INI_RA(array, r, column));
+ DO_DELAY(*writecnt);
+ }
+ REGWRITE_BUFFER_FLUSH(ah);
+}
+
u32 ath9k_hw_reverse_bits(u32 val, u32 n)
{
u32 retval;
@@ -142,25 +156,6 @@ u32 ath9k_hw_reverse_bits(u32 val, u32 n)
return retval;
}
-bool ath9k_get_channel_edges(struct ath_hw *ah,
- u16 flags, u16 *low,
- u16 *high)
-{
- struct ath9k_hw_capabilities *pCap = &ah->caps;
-
- if (flags & CHANNEL_5GHZ) {
- *low = pCap->low_5ghz_chan;
- *high = pCap->high_5ghz_chan;
- return true;
- }
- if ((flags & CHANNEL_2GHZ)) {
- *low = pCap->low_2ghz_chan;
- *high = pCap->high_2ghz_chan;
- return true;
- }
- return false;
-}
-
u16 ath9k_hw_computetxtime(struct ath_hw *ah,
u8 phy, int kbps,
u32 frameLen, u16 rateix,
@@ -252,6 +247,17 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah)
{
u32 val;
+ switch (ah->hw_version.devid) {
+ case AR5416_AR9100_DEVID:
+ ah->hw_version.macVersion = AR_SREV_VERSION_9100;
+ break;
+ case AR9300_DEVID_AR9340:
+ ah->hw_version.macVersion = AR_SREV_VERSION_9340;
+ val = REG_READ(ah, AR_SREV);
+ ah->hw_version.macRev = MS(val, AR_SREV_REVISION2);
+ return;
+ }
+
val = REG_READ(ah, AR_SREV) & AR_SREV_ID;
if (val == 0xFF) {
@@ -364,11 +370,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
ah->config.spurchans[i][1] = AR_NO_SPUR;
}
- if (ah->hw_version.devid != AR2427_DEVID_PCIE)
- ah->config.ht_enable = 1;
- else
- ah->config.ht_enable = 0;
-
/* PAPRD needs some more work to be enabled */
ah->config.paprd_disable = 1;
@@ -410,6 +411,8 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
ah->sta_id1_defaults =
AR_STA_ID1_CRPT_MIC_ENABLE |
AR_STA_ID1_MCAST_KSRCH;
+ if (AR_SREV_9100(ah))
+ ah->sta_id1_defaults |= AR_STA_ID1_AR9100_BA_FIX;
ah->enable_32kHz_clock = DONT_USE_32KHZ;
ah->slottime = 20;
ah->globaltxtimeout = (u32) -1;
@@ -470,7 +473,7 @@ static int ath9k_hw_post_init(struct ath_hw *ah)
return ecode;
}
- if (!AR_SREV_9100(ah)) {
+ if (!AR_SREV_9100(ah) && !AR_SREV_9340(ah)) {
ath9k_hw_ani_setup(ah);
ath9k_hw_ani_init(ah);
}
@@ -492,9 +495,6 @@ static int __ath9k_hw_init(struct ath_hw *ah)
struct ath_common *common = ath9k_hw_common(ah);
int r = 0;
- if (ah->hw_version.devid == AR5416_AR9100_DEVID)
- ah->hw_version.macVersion = AR_SREV_VERSION_9100;
-
ath9k_hw_read_revisions(ah);
/*
@@ -552,6 +552,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
case AR_SREV_VERSION_9271:
case AR_SREV_VERSION_9300:
case AR_SREV_VERSION_9485:
+ case AR_SREV_VERSION_9340:
break;
default:
ath_err(common,
@@ -560,7 +561,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
return -EOPNOTSUPP;
}
- if (AR_SREV_9271(ah) || AR_SREV_9100(ah))
+ if (AR_SREV_9271(ah) || AR_SREV_9100(ah) || AR_SREV_9340(ah))
ah->is_pciexpress = false;
ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID);
@@ -629,6 +630,7 @@ int ath9k_hw_init(struct ath_hw *ah)
case AR2427_DEVID_PCIE:
case AR9300_DEVID_PCIE:
case AR9300_DEVID_AR9485_PCIE:
+ case AR9300_DEVID_AR9340:
break;
default:
if (common->bus_ops->ath_bus_type == ATH_USB)
@@ -671,48 +673,89 @@ static void ath9k_hw_init_qos(struct ath_hw *ah)
REGWRITE_BUFFER_FLUSH(ah);
}
-unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah)
+u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah)
{
- REG_WRITE(ah, PLL3, (REG_READ(ah, PLL3) & ~(PLL3_DO_MEAS_MASK)));
- udelay(100);
- REG_WRITE(ah, PLL3, (REG_READ(ah, PLL3) | PLL3_DO_MEAS_MASK));
+ REG_CLR_BIT(ah, PLL3, PLL3_DO_MEAS_MASK);
+ udelay(100);
+ REG_SET_BIT(ah, PLL3, PLL3_DO_MEAS_MASK);
- while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0)
- udelay(100);
+ while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0)
+ udelay(100);
- return (REG_READ(ah, PLL3) & SQSUM_DVC_MASK) >> 3;
+ return (REG_READ(ah, PLL3) & SQSUM_DVC_MASK) >> 3;
}
EXPORT_SYMBOL(ar9003_get_pll_sqsum_dvc);
-#define DPLL2_KD_VAL 0x3D
-#define DPLL2_KI_VAL 0x06
-#define DPLL3_PHASE_SHIFT_VAL 0x1
-
static void ath9k_hw_init_pll(struct ath_hw *ah,
struct ath9k_channel *chan)
{
u32 pll;
if (AR_SREV_9485(ah)) {
- REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666);
- REG_WRITE(ah, AR_CH0_DDR_DPLL2, 0x19e82f01);
- REG_RMW_FIELD(ah, AR_CH0_DDR_DPLL3,
- AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL);
-
- REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c);
- udelay(1000);
+ /* program BB PLL ki and kd value, ki=0x4, kd=0x40 */
+ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
+ AR_CH0_BB_DPLL2_PLL_PWD, 0x1);
+ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
+ AR_CH0_DPLL2_KD, 0x40);
+ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
+ AR_CH0_DPLL2_KI, 0x4);
- REG_WRITE(ah, AR_RTC_PLL_CONTROL2, 0x886666);
+ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1,
+ AR_CH0_BB_DPLL1_REFDIV, 0x5);
+ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1,
+ AR_CH0_BB_DPLL1_NINI, 0x58);
+ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL1,
+ AR_CH0_BB_DPLL1_NFRAC, 0x0);
REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
- AR_CH0_DPLL2_KD, DPLL2_KD_VAL);
+ AR_CH0_BB_DPLL2_OUTDIV, 0x1);
+ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
+ AR_CH0_BB_DPLL2_LOCAL_PLL, 0x1);
REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
- AR_CH0_DPLL2_KI, DPLL2_KI_VAL);
+ AR_CH0_BB_DPLL2_EN_NEGTRIG, 0x1);
+ /* program BB PLL phase_shift to 0x6 */
REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3,
- AR_CH0_DPLL3_PHASE_SHIFT, DPLL3_PHASE_SHIFT_VAL);
- REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x142c);
+ AR_CH0_BB_DPLL3_PHASE_SHIFT, 0x6);
+
+ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL2,
+ AR_CH0_BB_DPLL2_PLL_PWD, 0x0);
+ udelay(1000);
+ } else if (AR_SREV_9340(ah)) {
+ u32 regval, pll2_divint, pll2_divfrac, refdiv;
+
+ REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c);
+ udelay(1000);
+
+ REG_SET_BIT(ah, AR_PHY_PLL_MODE, 0x1 << 16);
+ udelay(100);
+
+ if (ah->is_clk_25mhz) {
+ pll2_divint = 0x54;
+ pll2_divfrac = 0x1eb85;
+ refdiv = 3;
+ } else {
+ pll2_divint = 88;
+ pll2_divfrac = 0;
+ refdiv = 5;
+ }
+
+ regval = REG_READ(ah, AR_PHY_PLL_MODE);
+ regval |= (0x1 << 16);
+ REG_WRITE(ah, AR_PHY_PLL_MODE, regval);
+ udelay(100);
+
+ REG_WRITE(ah, AR_PHY_PLL_CONTROL, (refdiv << 27) |
+ (pll2_divint << 18) | pll2_divfrac);
+ udelay(100);
+
+ regval = REG_READ(ah, AR_PHY_PLL_MODE);
+ regval = (regval & 0x80071fff) | (0x1 << 30) | (0x1 << 13) |
+ (0x4 << 26) | (0x18 << 19);
+ REG_WRITE(ah, AR_PHY_PLL_MODE, regval);
+ REG_WRITE(ah, AR_PHY_PLL_MODE,
+ REG_READ(ah, AR_PHY_PLL_MODE) & 0xfffeffff);
udelay(1000);
}
@@ -720,6 +763,9 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll);
+ if (AR_SREV_9485(ah) || AR_SREV_9340(ah))
+ udelay(1000);
+
/* Switch the core clock for ar9271 to 117Mhz */
if (AR_SREV_9271(ah)) {
udelay(500);
@@ -729,17 +775,34 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
udelay(RTC_PLL_SETTLE_DELAY);
REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK);
+
+ if (AR_SREV_9340(ah)) {
+ if (ah->is_clk_25mhz) {
+ REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x17c << 1);
+ REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7);
+ REG_WRITE(ah, AR_SLP32_INC, 0x0001e7ae);
+ } else {
+ REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x261 << 1);
+ REG_WRITE(ah, AR_SLP32_MODE, 0x0010f400);
+ REG_WRITE(ah, AR_SLP32_INC, 0x0001e800);
+ }
+ udelay(100);
+ }
}
static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
enum nl80211_iftype opmode)
{
+ u32 sync_default = AR_INTR_SYNC_DEFAULT;
u32 imr_reg = AR_IMR_TXERR |
AR_IMR_TXURN |
AR_IMR_RXERR |
AR_IMR_RXORN |
AR_IMR_BCNMISC;
+ if (AR_SREV_9340(ah))
+ sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
+
if (AR_SREV_9300_20_OR_LATER(ah)) {
imr_reg |= AR_IMR_RXOK_HP;
if (ah->config.rx_intr_mitigation)
@@ -770,7 +833,7 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
if (!AR_SREV_9100(ah)) {
REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF);
- REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT);
+ REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default);
REG_WRITE(ah, AR_INTR_SYNC_MASK, 0);
}
@@ -830,8 +893,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
ah->misc_mode);
if (ah->misc_mode != 0)
- REG_WRITE(ah, AR_PCU_MISC,
- REG_READ(ah, AR_PCU_MISC) | ah->misc_mode);
+ REG_SET_BIT(ah, AR_PCU_MISC, ah->misc_mode);
if (conf->channel && conf->channel->band == IEEE80211_BAND_5GHZ)
sifstime = 16;
@@ -899,23 +961,19 @@ u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan)
static inline void ath9k_hw_set_dma(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
- u32 regval;
ENABLE_REGWRITE_BUFFER(ah);
/*
* set AHB_MODE not to do cacheline prefetches
*/
- if (!AR_SREV_9300_20_OR_LATER(ah)) {
- regval = REG_READ(ah, AR_AHB_MODE);
- REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN);
- }
+ if (!AR_SREV_9300_20_OR_LATER(ah))
+ REG_SET_BIT(ah, AR_AHB_MODE, AR_AHB_PREFETCH_RD_EN);
/*
* let mac dma reads be in 128 byte chunks
*/
- regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK;
- REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B);
+ REG_RMW(ah, AR_TXCFG, AR_TXCFG_DMASZ_128B, AR_TXCFG_DMASZ_MASK);
REGWRITE_BUFFER_FLUSH(ah);
@@ -932,8 +990,7 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
/*
* let mac dma writes be in 128 byte chunks
*/
- regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK;
- REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B);
+ REG_RMW(ah, AR_RXCFG, AR_RXCFG_DMASZ_128B, AR_RXCFG_DMASZ_MASK);
/*
* Setup receive FIFO threshold to hold off TX activities
@@ -972,30 +1029,27 @@ static inline void ath9k_hw_set_dma(struct ath_hw *ah)
static void ath9k_hw_set_operating_mode(struct ath_hw *ah, int opmode)
{
- u32 val;
+ u32 mask = AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC;
+ u32 set = AR_STA_ID1_KSRCH_MODE;
- val = REG_READ(ah, AR_STA_ID1);
- val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC);
switch (opmode) {
- case NL80211_IFTYPE_AP:
- REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP
- | AR_STA_ID1_KSRCH_MODE);
- REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
- break;
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
- REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC
- | AR_STA_ID1_KSRCH_MODE);
+ set |= AR_STA_ID1_ADHOC;
REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
break;
+ case NL80211_IFTYPE_AP:
+ set |= AR_STA_ID1_STA_AP;
+ /* fall through */
case NL80211_IFTYPE_STATION:
- REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE);
+ REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION);
break;
default:
- if (ah->is_monitoring)
- REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE);
+ if (!ah->is_monitoring)
+ set = 0;
break;
}
+ REG_RMW(ah, AR_STA_ID1, set, mask);
}
void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled,
@@ -1021,10 +1075,8 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
u32 tmpReg;
if (AR_SREV_9100(ah)) {
- u32 val = REG_READ(ah, AR_RTC_DERIVED_CLK);
- val &= ~AR_RTC_DERIVED_CLK_PERIOD;
- val |= SM(1, AR_RTC_DERIVED_CLK_PERIOD);
- REG_WRITE(ah, AR_RTC_DERIVED_CLK, val);
+ REG_RMW_FIELD(ah, AR_RTC_DERIVED_CLK,
+ AR_RTC_DERIVED_CLK_PERIOD, 1);
(void)REG_READ(ah, AR_RTC_DERIVED_CLK);
}
@@ -1212,6 +1264,20 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
return true;
}
+static void ath9k_hw_apply_gpio_override(struct ath_hw *ah)
+{
+ u32 gpio_mask = ah->gpio_mask;
+ int i;
+
+ for (i = 0; gpio_mask; i++, gpio_mask >>= 1) {
+ if (!(gpio_mask & 1))
+ continue;
+
+ ath9k_hw_cfg_output(ah, i, AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+ ath9k_hw_set_gpio(ah, i, !!(ah->gpio_val & BIT(i)));
+ }
+}
+
bool ath9k_hw_check_alive(struct ath_hw *ah)
{
int count = 50;
@@ -1409,7 +1475,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
REGWRITE_BUFFER_FLUSH(ah);
ah->intr_txqs = 0;
- for (i = 0; i < ah->caps.total_queues; i++)
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
ath9k_hw_resettxqueue(ah, i);
ath9k_hw_init_interrupt_masks(ah, ah->opmode);
@@ -1426,8 +1492,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ar9002_hw_enable_wep_aggregation(ah);
}
- REG_WRITE(ah, AR_STA_ID1,
- REG_READ(ah, AR_STA_ID1) | AR_STA_ID1_PRESERVE_SEQNUM);
+ REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM);
ath9k_hw_set_dma(ah);
@@ -1480,7 +1545,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
}
#ifdef __BIG_ENDIAN
- else
+ else if (AR_SREV_9340(ah))
+ REG_RMW(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB, 0);
+ else
REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
#endif
}
@@ -1491,6 +1558,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (AR_SREV_9300_20_OR_LATER(ah))
ar9003_hw_bb_watchdog_config(ah);
+ ath9k_hw_apply_gpio_override(ah);
+
return 0;
}
EXPORT_SYMBOL(ath9k_hw_reset);
@@ -1670,21 +1739,15 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
case NL80211_IFTYPE_MESH_POINT:
REG_SET_BIT(ah, AR_TXCFG,
AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY);
- REG_WRITE(ah, AR_NEXT_NDP_TIMER,
- TU_TO_USEC(next_beacon +
- (ah->atim_window ? ah->
- atim_window : 1)));
+ REG_WRITE(ah, AR_NEXT_NDP_TIMER, next_beacon +
+ TU_TO_USEC(ah->atim_window ? ah->atim_window : 1));
flags |= AR_NDP_TIMER_EN;
case NL80211_IFTYPE_AP:
- REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon));
- REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT,
- TU_TO_USEC(next_beacon -
- ah->config.
- dma_beacon_response_time));
- REG_WRITE(ah, AR_NEXT_SWBA,
- TU_TO_USEC(next_beacon -
- ah->config.
- sw_beacon_response_time));
+ REG_WRITE(ah, AR_NEXT_TBTT_TIMER, next_beacon);
+ REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, next_beacon -
+ TU_TO_USEC(ah->config.dma_beacon_response_time));
+ REG_WRITE(ah, AR_NEXT_SWBA, next_beacon -
+ TU_TO_USEC(ah->config.sw_beacon_response_time));
flags |=
AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN;
break;
@@ -1696,18 +1759,13 @@ void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period)
break;
}
- REG_WRITE(ah, AR_BEACON_PERIOD, TU_TO_USEC(beacon_period));
- REG_WRITE(ah, AR_DMA_BEACON_PERIOD, TU_TO_USEC(beacon_period));
- REG_WRITE(ah, AR_SWBA_PERIOD, TU_TO_USEC(beacon_period));
- REG_WRITE(ah, AR_NDP_PERIOD, TU_TO_USEC(beacon_period));
+ REG_WRITE(ah, AR_BEACON_PERIOD, beacon_period);
+ REG_WRITE(ah, AR_DMA_BEACON_PERIOD, beacon_period);
+ REG_WRITE(ah, AR_SWBA_PERIOD, beacon_period);
+ REG_WRITE(ah, AR_NDP_PERIOD, beacon_period);
REGWRITE_BUFFER_FLUSH(ah);
- beacon_period &= ~ATH9K_BEACON_ENA;
- if (beacon_period & ATH9K_BEACON_RESET_TSF) {
- ath9k_hw_reset_tsf(ah);
- }
-
REG_SET_BIT(ah, AR_TIMER_MODE, flags);
}
EXPORT_SYMBOL(ath9k_hw_beaconinit);
@@ -1795,7 +1853,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
struct ath_common *common = ath9k_hw_common(ah);
struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
- u16 capField = 0, eeval;
+ u16 eeval;
u8 ant_div_ctl1, tx_chainmask, rx_chainmask;
eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0);
@@ -1806,8 +1864,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
eeval |= AR9285_RDEXT_DEFAULT;
regulatory->current_rd_ext = eeval;
- capField = ah->eep_ops->get_eeprom(ah, EEP_OP_CAP);
-
if (ah->opmode != NL80211_IFTYPE_AP &&
ah->hw_version.subvendorid == AR_SUBVENDOR_ID_NEW_A) {
if (regulatory->current_rd == 0x64 ||
@@ -1842,6 +1898,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
!(AR_SREV_9271(ah)))
/* CB71: GPIO 0 is pulled down to indicate 3 rx chains */
pCap->rx_chainmask = ath9k_hw_gpio_get(ah, 0) ? 0x5 : 0x7;
+ else if (AR_SREV_9100(ah))
+ pCap->rx_chainmask = 0x7;
else
/* Use rx_chainmask from EEPROM. */
pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK);
@@ -1852,36 +1910,13 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
if (AR_SREV_9300_20_OR_LATER(ah))
ah->misc_mode |= AR_PCU_ALWAYS_PERFORM_KEYSEARCH;
- pCap->low_2ghz_chan = 2312;
- pCap->high_2ghz_chan = 2732;
-
- pCap->low_5ghz_chan = 4920;
- pCap->high_5ghz_chan = 6100;
-
common->crypt_caps |= ATH_CRYPT_CAP_CIPHER_AESCCM;
- if (ah->config.ht_enable)
+ if (ah->hw_version.devid != AR2427_DEVID_PCIE)
pCap->hw_caps |= ATH9K_HW_CAP_HT;
else
pCap->hw_caps &= ~ATH9K_HW_CAP_HT;
- if (capField & AR_EEPROM_EEPCAP_MAXQCU)
- pCap->total_queues =
- MS(capField, AR_EEPROM_EEPCAP_MAXQCU);
- else
- pCap->total_queues = ATH9K_NUM_TX_QUEUES;
-
- if (capField & AR_EEPROM_EEPCAP_KC_ENTRIES)
- pCap->keycache_size =
- 1 << MS(capField, AR_EEPROM_EEPCAP_KC_ENTRIES);
- else
- pCap->keycache_size = AR_KEYTABLE_SIZE;
-
- if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
- pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD >> 1;
- else
- pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD;
-
if (AR_SREV_9271(ah))
pCap->num_gpio_pins = AR9271_NUM_GPIO;
else if (AR_DEVID_7010(ah))
@@ -1900,8 +1935,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
pCap->rts_aggr_limit = (8 * 1024);
}
- pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM;
-
#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
ah->rfsilent = ah->eep_ops->get_eeprom(ah, EEP_RF_SILENT);
if (ah->rfsilent & EEP_RFSILENT_ENABLED) {
@@ -1923,32 +1956,23 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
else
pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS;
- if (regulatory->current_rd_ext & (1 << REG_EXT_JAPAN_MIDBAND)) {
- pCap->reg_cap =
- AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
- AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN |
- AR_EEPROM_EEREGCAP_EN_KK_U2 |
- AR_EEPROM_EEREGCAP_EN_KK_MIDBAND;
- } else {
- pCap->reg_cap =
- AR_EEPROM_EEREGCAP_EN_KK_NEW_11A |
- AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN;
- }
-
- /* Advertise midband for AR5416 with FCC midband set in eeprom */
- if (regulatory->current_rd_ext & (1 << REG_EXT_FCC_MIDBAND) &&
- AR_SREV_5416(ah))
- pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND;
-
- if (AR_SREV_9280_20_OR_LATER(ah) && common->btcoex_enabled) {
- btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO;
- btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO;
-
- if (AR_SREV_9285(ah)) {
+ if (common->btcoex_enabled) {
+ if (AR_SREV_9300_20_OR_LATER(ah)) {
btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
- btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO;
- } else {
- btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE;
+ btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9300;
+ btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9300;
+ btcoex_hw->btpriority_gpio = ATH_BTPRIORITY_GPIO_9300;
+ } else if (AR_SREV_9280_20_OR_LATER(ah)) {
+ btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO_9280;
+ btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO_9280;
+
+ if (AR_SREV_9285(ah)) {
+ btcoex_hw->scheme = ATH_BTCOEX_CFG_3WIRE;
+ btcoex_hw->btpriority_gpio =
+ ATH_BTPRIORITY_GPIO_9285;
+ } else {
+ btcoex_hw->scheme = ATH_BTCOEX_CFG_2WIRE;
+ }
}
} else {
btcoex_hw->scheme = ATH_BTCOEX_CFG_NONE;
@@ -1998,6 +2022,22 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
}
+ if (AR_SREV_9485(ah)) {
+ ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1);
+ /*
+ * enable the diversity-combining algorithm only when
+ * both enable_lna_div and enable_fast_div are set
+ * Table for Diversity
+ * ant_div_alt_lnaconf bit 0-1
+ * ant_div_main_lnaconf bit 2-3
+ * ant_div_alt_gaintb bit 4
+ * ant_div_main_gaintb bit 5
+ * enable_ant_div_lnadiv bit 6
+ * enable_ant_fast_div bit 7
+ */
+ if ((ant_div_ctl1 >> 0x6) == 0x3)
+ pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB;
+ }
if (AR_SREV_9485_10(ah)) {
pCap->pcie_lcr_extsync_en = true;
@@ -2186,11 +2226,9 @@ void ath9k_hw_setrxfilter(struct ath_hw *ah, u32 bits)
REG_WRITE(ah, AR_PHY_ERR, phybits);
if (phybits)
- REG_WRITE(ah, AR_RXCFG,
- REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA);
+ REG_SET_BIT(ah, AR_RXCFG, AR_RXCFG_ZLFDMA);
else
- REG_WRITE(ah, AR_RXCFG,
- REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA);
+ REG_CLR_BIT(ah, AR_RXCFG, AR_RXCFG_ZLFDMA);
REGWRITE_BUFFER_FLUSH(ah);
}
@@ -2366,10 +2404,11 @@ static u32 rightmost_index(struct ath_gen_timer_table *timer_table, u32 *mask)
return timer_table->gen_timer_index[b];
}
-static u32 ath9k_hw_gettsf32(struct ath_hw *ah)
+u32 ath9k_hw_gettsf32(struct ath_hw *ah)
{
return REG_READ(ah, AR_TSF_L32);
}
+EXPORT_SYMBOL(ath9k_hw_gettsf32);
struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah,
void (*trigger)(void *),
@@ -2402,11 +2441,11 @@ EXPORT_SYMBOL(ath_gen_timer_alloc);
void ath9k_hw_gen_timer_start(struct ath_hw *ah,
struct ath_gen_timer *timer,
- u32 timer_next,
+ u32 trig_timeout,
u32 timer_period)
{
struct ath_gen_timer_table *timer_table = &ah->hw_gen_timers;
- u32 tsf;
+ u32 tsf, timer_next;
BUG_ON(!timer_period);
@@ -2414,18 +2453,13 @@ void ath9k_hw_gen_timer_start(struct ath_hw *ah,
tsf = ath9k_hw_gettsf32(ah);
+ timer_next = tsf + trig_timeout;
+
ath_dbg(ath9k_hw_common(ah), ATH_DBG_HWTIMER,
"current tsf %x period %x timer_next %x\n",
tsf, timer_period, timer_next);
/*
- * Pull timer_next forward if the current TSF already passed it
- * because of software latency
- */
- if (timer_next < tsf)
- timer_next = tsf + timer_period;
-
- /*
* Program generic timer registers
*/
REG_WRITE(ah, gen_tmr_configuration[timer->index].next_addr,
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 6650fd48415c..57435ce62792 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2010 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -43,6 +43,7 @@
#define AR9287_DEVID_PCI 0x002d
#define AR9287_DEVID_PCIE 0x002e
#define AR9300_DEVID_PCIE 0x0030
+#define AR9300_DEVID_AR9340 0x0031
#define AR9300_DEVID_AR9485_PCIE 0x0032
#define AR5416_AR9100_DEVID 0x000b
@@ -55,6 +56,9 @@
#define AT9285_COEX3WIRE_SA_SUBSYSID 0x30aa
#define AT9285_COEX3WIRE_DA_SUBSYSID 0x30ab
+#define AR9300_NUM_BT_WEIGHTS 4
+#define AR9300_NUM_WLAN_WEIGHTS 4
+
#define ATH_AMPDU_LIMIT_MAX (64 * 1024 - 1)
#define ATH_DEFAULT_NOISE_FLOOR -95
@@ -65,53 +69,49 @@
/* Register read/write primitives */
#define REG_WRITE(_ah, _reg, _val) \
- ath9k_hw_common(_ah)->ops->write((_ah), (_val), (_reg))
+ (_ah)->reg_ops.write((_ah), (_val), (_reg))
#define REG_READ(_ah, _reg) \
- ath9k_hw_common(_ah)->ops->read((_ah), (_reg))
+ (_ah)->reg_ops.read((_ah), (_reg))
#define REG_READ_MULTI(_ah, _addr, _val, _cnt) \
- ath9k_hw_common(_ah)->ops->multi_read((_ah), (_addr), (_val), (_cnt))
+ (_ah)->reg_ops.multi_read((_ah), (_addr), (_val), (_cnt))
+
+#define REG_RMW(_ah, _reg, _set, _clr) \
+ (_ah)->reg_ops.rmw((_ah), (_reg), (_set), (_clr))
#define ENABLE_REGWRITE_BUFFER(_ah) \
do { \
- if (ath9k_hw_common(_ah)->ops->enable_write_buffer) \
- ath9k_hw_common(_ah)->ops->enable_write_buffer((_ah)); \
+ if ((_ah)->reg_ops.enable_write_buffer) \
+ (_ah)->reg_ops.enable_write_buffer((_ah)); \
} while (0)
#define REGWRITE_BUFFER_FLUSH(_ah) \
do { \
- if (ath9k_hw_common(_ah)->ops->write_flush) \
- ath9k_hw_common(_ah)->ops->write_flush((_ah)); \
+ if ((_ah)->reg_ops.write_flush) \
+ (_ah)->reg_ops.write_flush((_ah)); \
} while (0)
#define SM(_v, _f) (((_v) << _f##_S) & _f)
#define MS(_v, _f) (((_v) & _f) >> _f##_S)
-#define REG_RMW(_a, _r, _set, _clr) \
- REG_WRITE(_a, _r, (REG_READ(_a, _r) & ~(_clr)) | (_set))
#define REG_RMW_FIELD(_a, _r, _f, _v) \
- REG_WRITE(_a, _r, \
- (REG_READ(_a, _r) & ~_f) | (((_v) << _f##_S) & _f))
+ REG_RMW(_a, _r, (((_v) << _f##_S) & _f), (_f))
#define REG_READ_FIELD(_a, _r, _f) \
(((REG_READ(_a, _r) & _f) >> _f##_S))
#define REG_SET_BIT(_a, _r, _f) \
- REG_WRITE(_a, _r, REG_READ(_a, _r) | (_f))
+ REG_RMW(_a, _r, (_f), 0)
#define REG_CLR_BIT(_a, _r, _f) \
- REG_WRITE(_a, _r, REG_READ(_a, _r) & ~(_f))
+ REG_RMW(_a, _r, 0, (_f))
-#define DO_DELAY(x) do { \
- if ((++(x) % 64) == 0) \
- udelay(1); \
+#define DO_DELAY(x) do { \
+ if (((++(x) % 64) == 0) && \
+ (ath9k_hw_common(ah)->bus_ops->ath_bus_type \
+ != ATH_USB)) \
+ udelay(1); \
} while (0)
-#define REG_WRITE_ARRAY(iniarray, column, regWr) do { \
- int r; \
- for (r = 0; r < ((iniarray)->ia_rows); r++) { \
- REG_WRITE(ah, INI_RA((iniarray), (r), 0), \
- INI_RA((iniarray), r, (column))); \
- DO_DELAY(regWr); \
- } \
- } while (0)
+#define REG_WRITE_ARRAY(iniarray, column, regWr) \
+ ath9k_hw_write_array(ah, iniarray, column, &(regWr))
#define AR_GPIO_OUTPUT_MUX_AS_OUTPUT 0
#define AR_GPIO_OUTPUT_MUX_AS_PCIE_ATTENTION_LED 1
@@ -125,7 +125,7 @@
#define AR_GPIO_BIT(_gpio) (1 << (_gpio))
#define BASE_ACTIVATE_DELAY 100
-#define RTC_PLL_SETTLE_DELAY 100
+#define RTC_PLL_SETTLE_DELAY (AR_SREV_9340(ah) ? 1000 : 100)
#define COEF_SCALE_S 24
#define HT40_CHANNEL_CENTER_SHIFT 10
@@ -178,7 +178,6 @@ enum ath9k_hw_caps {
ATH9K_HW_CAP_HT = BIT(0),
ATH9K_HW_CAP_RFSILENT = BIT(1),
ATH9K_HW_CAP_CST = BIT(2),
- ATH9K_HW_CAP_ENHANCEDPM = BIT(3),
ATH9K_HW_CAP_AUTOSLEEP = BIT(4),
ATH9K_HW_CAP_4KB_SPLITTRANS = BIT(5),
ATH9K_HW_CAP_EDMA = BIT(6),
@@ -195,17 +194,11 @@ enum ath9k_hw_caps {
struct ath9k_hw_capabilities {
u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */
- u16 total_queues;
- u16 keycache_size;
- u16 low_5ghz_chan, high_5ghz_chan;
- u16 low_2ghz_chan, high_2ghz_chan;
u16 rts_aggr_limit;
u8 tx_chainmask;
u8 rx_chainmask;
u8 max_txchains;
u8 max_rxchains;
- u16 tx_triglevel_max;
- u16 reg_cap;
u8 num_gpio_pins;
u8 rx_hp_qdepth;
u8 rx_lp_qdepth;
@@ -227,7 +220,6 @@ struct ath9k_ops_config {
u8 pcie_clock_req;
u32 pcie_waen;
u8 analog_shiftreg;
- u8 ht_enable;
u8 paprd_disable;
u32 ofdm_trig_low;
u32 ofdm_trig_high;
@@ -412,8 +404,6 @@ struct ath9k_beacon_state {
u32 bs_nextdtim;
u32 bs_intval;
#define ATH9K_BEACON_PERIOD 0x0000ffff
-#define ATH9K_BEACON_ENA 0x00800000
-#define ATH9K_BEACON_RESET_TSF 0x01000000
#define ATH9K_TSFOOR_THRESHOLD 0x00004240 /* 16k us */
u32 bs_dtimperiod;
u16 bs_cfpperiod;
@@ -489,6 +479,10 @@ struct ath_hw_antcomb_conf {
u8 main_lna_conf;
u8 alt_lna_conf;
u8 fast_div_bias;
+ u8 main_gaintb;
+ u8 alt_gaintb;
+ int lna1_lna2_delta;
+ u8 div_group;
};
/**
@@ -638,10 +632,12 @@ struct ath_hw_ops {
u32 numDelims);
void (*set11n_aggr_last)(struct ath_hw *ah, void *ds);
void (*clr11n_aggr)(struct ath_hw *ah, void *ds);
- void (*set11n_burstduration)(struct ath_hw *ah, void *ds,
- u32 burstDuration);
- void (*set11n_virtualmorefrag)(struct ath_hw *ah, void *ds,
- u32 vmf);
+ void (*set_clrdmask)(struct ath_hw *ah, void *ds, bool val);
+ void (*antdiv_comb_conf_get)(struct ath_hw *ah,
+ struct ath_hw_antcomb_conf *antconf);
+ void (*antdiv_comb_conf_set)(struct ath_hw *ah,
+ struct ath_hw_antcomb_conf *antconf);
+
};
struct ath_nf_limits {
@@ -655,6 +651,8 @@ struct ath_nf_limits {
#define AH_UNPLUGGED 0x2 /* The card has been physically removed. */
struct ath_hw {
+ struct ath_ops reg_ops;
+
struct ieee80211_hw *hw;
struct ath_common common;
struct ath9k_hw_version hw_version;
@@ -784,6 +782,8 @@ struct ath_hw {
/* Bluetooth coexistance */
struct ath_btcoex_hw btcoex_hw;
+ u32 bt_coex_bt_weight[AR9300_NUM_BT_WEIGHTS];
+ u32 bt_coex_wlan_weight[AR9300_NUM_WLAN_WEIGHTS];
u32 intr_txqs;
u8 txchainmask;
@@ -794,7 +794,9 @@ struct ath_hw {
u32 originalGain[22];
int initPDADC;
int PDADCdelta;
- u8 led_pin;
+ int led_pin;
+ u32 gpio_mask;
+ u32 gpio_val;
struct ar5416IniArray iniModes;
struct ar5416IniArray iniCommon;
@@ -810,6 +812,7 @@ struct ath_hw {
struct ar5416IniArray iniPcieSerdes;
struct ar5416IniArray iniPcieSerdesLowPower;
struct ar5416IniArray iniModesAdditional;
+ struct ar5416IniArray iniModesAdditional_40M;
struct ar5416IniArray iniModesRxGain;
struct ar5416IniArray iniModesTxGain;
struct ar5416IniArray iniModes_9271_1_0_only;
@@ -856,6 +859,16 @@ struct ath_hw {
/* Enterprise mode cap */
u32 ent_mode;
+
+ bool is_clk_25mhz;
+};
+
+struct ath_bus_ops {
+ enum ath_bus_type ath_bus_type;
+ void (*read_cachesize)(struct ath_common *common, int *csz);
+ bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
+ void (*bt_coex_prep)(struct ath_common *common);
+ void (*extn_synch_en)(struct ath_common *common);
};
static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah)
@@ -900,15 +913,12 @@ void ath9k_hw_cfg_output(struct ath_hw *ah, u32 gpio,
void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val);
u32 ath9k_hw_getdefantenna(struct ath_hw *ah);
void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna);
-void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah,
- struct ath_hw_antcomb_conf *antconf);
-void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah,
- struct ath_hw_antcomb_conf *antconf);
/* General Operation */
bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout);
+void ath9k_hw_write_array(struct ath_hw *ah, struct ar5416IniArray *array,
+ int column, unsigned int *writecnt);
u32 ath9k_hw_reverse_bits(u32 val, u32 n);
-bool ath9k_get_channel_edges(struct ath_hw *ah, u16 flags, u16 *low, u16 *high);
u16 ath9k_hw_computetxtime(struct ath_hw *ah,
u8 phy, int kbps,
u32 frameLen, u16 rateix, bool shortPreamble);
@@ -924,12 +934,13 @@ 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);
void ath9k_hw_write_associd(struct ath_hw *ah);
+u32 ath9k_hw_gettsf32(struct ath_hw *ah);
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);
void ath9k_hw_init_global_settings(struct ath_hw *ah);
-unsigned long ar9003_get_pll_sqsum_dvc(struct ath_hw *ah);
+u32 ar9003_get_pll_sqsum_dvc(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);
void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index 79aec983279f..45c585a337e9 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -15,6 +15,7 @@
*/
#include <linux/slab.h>
+#include <linux/ath9k_platform.h>
#include "ath9k.h"
@@ -195,10 +196,27 @@ static unsigned int ath9k_ioread32(void *hw_priv, u32 reg_offset)
return val;
}
-static const struct ath_ops ath9k_common_ops = {
- .read = ath9k_ioread32,
- .write = ath9k_iowrite32,
-};
+static unsigned int ath9k_reg_rmw(void *hw_priv, u32 reg_offset, u32 set, u32 clr)
+{
+ struct ath_hw *ah = (struct ath_hw *) hw_priv;
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_softc *sc = (struct ath_softc *) common->priv;
+ unsigned long uninitialized_var(flags);
+ u32 val;
+
+ if (ah->config.serialize_regmode == SER_REG_MODE_ON)
+ spin_lock_irqsave(&sc->sc_serial_rw, flags);
+
+ val = ioread32(sc->mem + reg_offset);
+ val &= ~clr;
+ val |= set;
+ iowrite32(val, sc->mem + reg_offset);
+
+ if (ah->config.serialize_regmode == SER_REG_MODE_ON)
+ spin_unlock_irqrestore(&sc->sc_serial_rw, flags);
+
+ return val;
+}
/**************************/
/* Initialization */
@@ -389,13 +407,7 @@ void ath9k_init_crypto(struct ath_softc *sc)
int i = 0;
/* Get the hardware key cache size. */
- common->keymax = sc->sc_ah->caps.keycache_size;
- if (common->keymax > ATH_KEYMAX) {
- ath_dbg(common, ATH_DBG_ANY,
- "Warning, using only %u entries in %u key cache\n",
- ATH_KEYMAX, common->keymax);
- common->keymax = ATH_KEYMAX;
- }
+ common->keymax = AR_KEYTABLE_SIZE;
/*
* Reset the key cache since some parts do not
@@ -537,6 +549,7 @@ static void ath9k_init_misc(struct ath_softc *sc)
static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
const struct ath_bus_ops *bus_ops)
{
+ struct ath9k_platform_data *pdata = sc->dev->platform_data;
struct ath_hw *ah = NULL;
struct ath_common *common;
int ret = 0, i;
@@ -549,13 +562,23 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
ah->hw = sc->hw;
ah->hw_version.devid = devid;
ah->hw_version.subsysid = subsysid;
+ ah->reg_ops.read = ath9k_ioread32;
+ ah->reg_ops.write = ath9k_iowrite32;
+ ah->reg_ops.rmw = ath9k_reg_rmw;
sc->sc_ah = ah;
- if (!sc->dev->platform_data)
+ if (!pdata) {
ah->ah_flags |= AH_USE_EEPROM;
+ sc->sc_ah->led_pin = -1;
+ } else {
+ sc->sc_ah->gpio_mask = pdata->gpio_mask;
+ sc->sc_ah->gpio_val = pdata->gpio_val;
+ sc->sc_ah->led_pin = pdata->led_pin;
+ ah->is_clk_25mhz = pdata->is_clk_25mhz;
+ }
common = ath9k_hw_common(ah);
- common->ops = &ath9k_common_ops;
+ common->ops = &ah->reg_ops;
common->bus_ops = bus_ops;
common->ah = ah;
common->hw = sc->hw;
@@ -587,6 +610,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
if (ret)
goto err_hw;
+ if (pdata && pdata->macaddr)
+ memcpy(common->macaddr, pdata->macaddr, ETH_ALEN);
+
ret = ath9k_init_queues(sc);
if (ret)
goto err_queues;
@@ -679,6 +705,8 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
if (AR_SREV_5416(sc->sc_ah))
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+ hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+
hw->queues = 4;
hw->max_rates = 4;
hw->channel_change_time = 5000;
@@ -773,6 +801,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
INIT_WORK(&sc->hw_check_work, ath_hw_check);
INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
+ INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
ath_init_leds(sc);
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index edc1cbbfecaf..c2091f1f4096 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -209,15 +209,8 @@ bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q,
{
u32 cw;
struct ath_common *common = ath9k_hw_common(ah);
- struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath9k_tx_queue_info *qi;
- if (q >= pCap->total_queues) {
- ath_dbg(common, ATH_DBG_QUEUE,
- "Set TXQ properties, invalid queue: %u\n", q);
- return false;
- }
-
qi = &ah->txq[q];
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
ath_dbg(common, ATH_DBG_QUEUE,
@@ -280,15 +273,8 @@ bool ath9k_hw_get_txq_props(struct ath_hw *ah, int q,
struct ath9k_tx_queue_info *qinfo)
{
struct ath_common *common = ath9k_hw_common(ah);
- struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath9k_tx_queue_info *qi;
- if (q >= pCap->total_queues) {
- ath_dbg(common, ATH_DBG_QUEUE,
- "Get TXQ properties, invalid queue: %u\n", q);
- return false;
- }
-
qi = &ah->txq[q];
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
ath_dbg(common, ATH_DBG_QUEUE,
@@ -320,28 +306,27 @@ int ath9k_hw_setuptxqueue(struct ath_hw *ah, enum ath9k_tx_queue type,
{
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_tx_queue_info *qi;
- struct ath9k_hw_capabilities *pCap = &ah->caps;
int q;
switch (type) {
case ATH9K_TX_QUEUE_BEACON:
- q = pCap->total_queues - 1;
+ q = ATH9K_NUM_TX_QUEUES - 1;
break;
case ATH9K_TX_QUEUE_CAB:
- q = pCap->total_queues - 2;
+ q = ATH9K_NUM_TX_QUEUES - 2;
break;
case ATH9K_TX_QUEUE_PSPOLL:
q = 1;
break;
case ATH9K_TX_QUEUE_UAPSD:
- q = pCap->total_queues - 3;
+ q = ATH9K_NUM_TX_QUEUES - 3;
break;
case ATH9K_TX_QUEUE_DATA:
- for (q = 0; q < pCap->total_queues; q++)
+ for (q = 0; q < ATH9K_NUM_TX_QUEUES; q++)
if (ah->txq[q].tqi_type ==
ATH9K_TX_QUEUE_INACTIVE)
break;
- if (q == pCap->total_queues) {
+ if (q == ATH9K_NUM_TX_QUEUES) {
ath_err(common, "No available TX queue\n");
return -1;
}
@@ -382,15 +367,9 @@ EXPORT_SYMBOL(ath9k_hw_setuptxqueue);
bool ath9k_hw_releasetxqueue(struct ath_hw *ah, u32 q)
{
- struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_tx_queue_info *qi;
- if (q >= pCap->total_queues) {
- ath_dbg(common, ATH_DBG_QUEUE,
- "Release TXQ, invalid queue: %u\n", q);
- return false;
- }
qi = &ah->txq[q];
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
ath_dbg(common, ATH_DBG_QUEUE,
@@ -414,18 +393,11 @@ EXPORT_SYMBOL(ath9k_hw_releasetxqueue);
bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
{
- struct ath9k_hw_capabilities *pCap = &ah->caps;
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_channel *chan = ah->curchan;
struct ath9k_tx_queue_info *qi;
u32 cwMin, chanCwMin, value;
- if (q >= pCap->total_queues) {
- ath_dbg(common, ATH_DBG_QUEUE,
- "Reset TXQ, invalid queue: %u\n", q);
- return false;
- }
-
qi = &ah->txq[q];
if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) {
ath_dbg(common, ATH_DBG_QUEUE,
@@ -458,17 +430,21 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH));
REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
- REG_WRITE(ah, AR_DMISC(q),
- AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
+
+ if (AR_SREV_9340(ah))
+ REG_WRITE(ah, AR_DMISC(q),
+ AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x1);
+ else
+ REG_WRITE(ah, AR_DMISC(q),
+ AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
if (qi->tqi_cbrPeriod) {
REG_WRITE(ah, AR_QCBRCFG(q),
SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) |
SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH));
- REG_WRITE(ah, AR_QMISC(q),
- REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_CBR |
- (qi->tqi_cbrOverflowLimit ?
- AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0));
+ REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_FSP_CBR |
+ (qi->tqi_cbrOverflowLimit ?
+ AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0));
}
if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) {
REG_WRITE(ah, AR_QRDYTIMECFG(q),
@@ -481,40 +457,31 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
(qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0));
if (qi->tqi_burstTime
- && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) {
- REG_WRITE(ah, AR_QMISC(q),
- REG_READ(ah, AR_QMISC(q)) |
- AR_Q_MISC_RDYTIME_EXP_POLICY);
+ && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE))
+ REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_RDYTIME_EXP_POLICY);
- }
-
- if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) {
- REG_WRITE(ah, AR_DMISC(q),
- REG_READ(ah, AR_DMISC(q)) |
- AR_D_MISC_POST_FR_BKOFF_DIS);
- }
+ if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE)
+ REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_POST_FR_BKOFF_DIS);
REGWRITE_BUFFER_FLUSH(ah);
- if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) {
- REG_WRITE(ah, AR_DMISC(q),
- REG_READ(ah, AR_DMISC(q)) |
- AR_D_MISC_FRAG_BKOFF_EN);
- }
+ if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
+ REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_FRAG_BKOFF_EN);
+
switch (qi->tqi_type) {
case ATH9K_TX_QUEUE_BEACON:
ENABLE_REGWRITE_BUFFER(ah);
- REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
- | AR_Q_MISC_FSP_DBA_GATED
- | AR_Q_MISC_BEACON_USE
- | AR_Q_MISC_CBR_INCR_DIS1);
+ REG_SET_BIT(ah, AR_QMISC(q),
+ AR_Q_MISC_FSP_DBA_GATED
+ | AR_Q_MISC_BEACON_USE
+ | AR_Q_MISC_CBR_INCR_DIS1);
- REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
- | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
+ REG_SET_BIT(ah, AR_DMISC(q),
+ (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
AR_D_MISC_ARB_LOCKOUT_CNTRL_S)
- | AR_D_MISC_BEACON_USE
- | AR_D_MISC_POST_FR_BKOFF_DIS);
+ | AR_D_MISC_BEACON_USE
+ | AR_D_MISC_POST_FR_BKOFF_DIS);
REGWRITE_BUFFER_FLUSH(ah);
@@ -533,41 +500,38 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
case ATH9K_TX_QUEUE_CAB:
ENABLE_REGWRITE_BUFFER(ah);
- REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q))
- | AR_Q_MISC_FSP_DBA_GATED
- | AR_Q_MISC_CBR_INCR_DIS1
- | AR_Q_MISC_CBR_INCR_DIS0);
+ REG_SET_BIT(ah, AR_QMISC(q),
+ AR_Q_MISC_FSP_DBA_GATED
+ | AR_Q_MISC_CBR_INCR_DIS1
+ | AR_Q_MISC_CBR_INCR_DIS0);
value = (qi->tqi_readyTime -
(ah->config.sw_beacon_response_time -
ah->config.dma_beacon_response_time) -
ah->config.additional_swba_backoff) * 1024;
REG_WRITE(ah, AR_QRDYTIMECFG(q),
value | AR_Q_RDYTIMECFG_EN);
- REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q))
- | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
+ REG_SET_BIT(ah, AR_DMISC(q),
+ (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL <<
AR_D_MISC_ARB_LOCKOUT_CNTRL_S));
REGWRITE_BUFFER_FLUSH(ah);
break;
case ATH9K_TX_QUEUE_PSPOLL:
- REG_WRITE(ah, AR_QMISC(q),
- REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1);
+ REG_SET_BIT(ah, AR_QMISC(q), AR_Q_MISC_CBR_INCR_DIS1);
break;
case ATH9K_TX_QUEUE_UAPSD:
- REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) |
- AR_D_MISC_POST_FR_BKOFF_DIS);
+ REG_SET_BIT(ah, AR_DMISC(q), AR_D_MISC_POST_FR_BKOFF_DIS);
break;
default:
break;
}
if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) {
- REG_WRITE(ah, AR_DMISC(q),
- REG_READ(ah, AR_DMISC(q)) |
- SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
- AR_D_MISC_ARB_LOCKOUT_CNTRL) |
- AR_D_MISC_POST_FR_BKOFF_DIS);
+ REG_SET_BIT(ah, AR_DMISC(q),
+ SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL,
+ AR_D_MISC_ARB_LOCKOUT_CNTRL) |
+ AR_D_MISC_POST_FR_BKOFF_DIS);
}
if (AR_SREV_9300_20_OR_LATER(ah))
@@ -754,7 +718,6 @@ EXPORT_SYMBOL(ath9k_hw_abortpcurecv);
bool ath9k_hw_stopdmarecv(struct ath_hw *ah, bool *reset)
{
#define AH_RX_STOP_DMA_TIMEOUT 10000 /* usec */
-#define AH_RX_TIME_QUANTUM 100 /* usec */
struct ath_common *common = ath9k_hw_common(ah);
u32 mac_status, last_mac_status = 0;
int i;
@@ -797,7 +760,6 @@ bool ath9k_hw_stopdmarecv(struct ath_hw *ah, bool *reset)
return true;
}
-#undef AH_RX_TIME_QUANTUM
#undef AH_RX_STOP_DMA_TIMEOUT
}
EXPORT_SYMBOL(ath9k_hw_stopdmarecv);
@@ -855,10 +817,14 @@ EXPORT_SYMBOL(ath9k_hw_disable_interrupts);
void ath9k_hw_enable_interrupts(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
+ u32 sync_default = AR_INTR_SYNC_DEFAULT;
if (!(ah->imask & ATH9K_INT_GLOBAL))
return;
+ if (AR_SREV_9340(ah))
+ sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
+
ath_dbg(common, ATH_DBG_INTERRUPT, "enable IER\n");
REG_WRITE(ah, AR_IER, AR_IER_ENABLE);
if (!AR_SREV_9100(ah)) {
@@ -867,10 +833,8 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah)
REG_WRITE(ah, AR_INTR_ASYNC_MASK, AR_INTR_MAC_IRQ);
- REG_WRITE(ah, AR_INTR_SYNC_ENABLE,
- AR_INTR_SYNC_DEFAULT);
- REG_WRITE(ah, AR_INTR_SYNC_MASK,
- AR_INTR_SYNC_DEFAULT);
+ REG_WRITE(ah, AR_INTR_SYNC_ENABLE, sync_default);
+ REG_WRITE(ah, AR_INTR_SYNC_MASK, sync_default);
}
ath_dbg(common, ATH_DBG_INTERRUPT, "AR_IMR 0x%x IER 0x%x\n",
REG_READ(ah, AR_IMR), REG_READ(ah, AR_IER));
@@ -926,6 +890,9 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
mask |= AR_IMR_GENTMR;
}
+ if (ints & ATH9K_INT_GENTIMER)
+ mask |= AR_IMR_GENTMR;
+
if (ints & (ATH9K_INT_BMISC)) {
mask |= AR_IMR_BCNMISC;
if (ints & ATH9K_INT_TIM)
diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h
index c2a59386fb9c..8e848c4d16ba 100644
--- a/drivers/net/wireless/ath/ath9k/mac.h
+++ b/drivers/net/wireless/ath/ath9k/mac.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -239,7 +239,6 @@ struct ath_desc {
void *ds_vdata;
} __packed __aligned(4);
-#define ATH9K_TXDESC_CLRDMASK 0x0001
#define ATH9K_TXDESC_NOACK 0x0002
#define ATH9K_TXDESC_RTSENA 0x0004
#define ATH9K_TXDESC_CTSENA 0x0008
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 1482fa650833..a198ee374b05 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -299,7 +299,7 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
if (!(sc->sc_flags & (SC_OP_OFFCHANNEL))) {
if (sc->sc_flags & SC_OP_BEACONS)
- ath_beacon_config(sc, NULL);
+ ath_set_beacon(sc);
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2);
ath_start_ani(common);
@@ -624,6 +624,43 @@ out:
ath9k_ps_restore(sc);
}
+static void ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum)
+{
+ static int count;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+
+ if (pll_sqsum >= 0x40000) {
+ count++;
+ if (count == 3) {
+ /* Rx is hung for more than 500ms. Reset it */
+ ath_dbg(common, ATH_DBG_RESET,
+ "Possible RX hang, resetting");
+ ath_reset(sc, true);
+ count = 0;
+ }
+ } else
+ count = 0;
+}
+
+void ath_hw_pll_work(struct work_struct *work)
+{
+ struct ath_softc *sc = container_of(work, struct ath_softc,
+ hw_pll_work.work);
+ u32 pll_sqsum;
+
+ if (AR_SREV_9485(sc->sc_ah)) {
+
+ ath9k_ps_wakeup(sc);
+ pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah);
+ ath9k_ps_restore(sc);
+
+ ath_hw_pll_rx_hang_check(sc, pll_sqsum);
+
+ ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5);
+ }
+}
+
+
void ath9k_tasklet(unsigned long data)
{
struct ath_softc *sc = (struct ath_softc *)data;
@@ -652,6 +689,17 @@ void ath9k_tasklet(unsigned long data)
!ath9k_hw_check_alive(ah))
ieee80211_queue_work(sc->hw, &sc->hw_check_work);
+ if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) {
+ /*
+ * TSF sync does not look correct; remain awake to sync with
+ * the next Beacon.
+ */
+ ath_dbg(common, ATH_DBG_PS,
+ "TSFOOR - Sync with next Beacon\n");
+ sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC |
+ PS_TSFOOR_SYNC;
+ }
+
if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL |
ATH9K_INT_RXORN);
@@ -674,16 +722,6 @@ void ath9k_tasklet(unsigned long data)
ath_tx_tasklet(sc);
}
- if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) {
- /*
- * TSF sync does not look correct; remain awake to sync with
- * the next Beacon.
- */
- ath_dbg(common, ATH_DBG_PS,
- "TSFOOR - Sync with next Beacon\n");
- sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC;
- }
-
if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
if (status & ATH9K_INT_GENTIMER)
ath_gen_timer_isr(sc->sc_ah);
@@ -828,48 +866,6 @@ chip_reset:
#undef SCHED_INTR
}
-static void ath9k_bss_assoc_info(struct ath_softc *sc,
- struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *bss_conf)
-{
- struct ath_hw *ah = sc->sc_ah;
- struct ath_common *common = ath9k_hw_common(ah);
-
- if (bss_conf->assoc) {
- ath_dbg(common, ATH_DBG_CONFIG,
- "Bss Info ASSOC %d, bssid: %pM\n",
- bss_conf->aid, common->curbssid);
-
- /* New association, store aid */
- common->curaid = bss_conf->aid;
- ath9k_hw_write_associd(ah);
-
- /*
- * Request a re-configuration of Beacon related timers
- * on the receipt of the first Beacon frame (i.e.,
- * after time sync with the AP).
- */
- sc->ps_flags |= PS_BEACON_SYNC;
-
- /* Configure the beacon */
- ath_beacon_config(sc, vif);
-
- /* Reset rssi stats */
- sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
- sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
-
- sc->sc_flags |= SC_OP_ANI_RUN;
- ath_start_ani(common);
- } else {
- ath_dbg(common, ATH_DBG_CONFIG, "Bss Info DISASSOC\n");
- common->curaid = 0;
- /* Stop ANI */
- sc->sc_flags &= ~SC_OP_ANI_RUN;
- del_timer_sync(&common->ani.timer);
- }
-}
-
void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
{
struct ath_hw *ah = sc->sc_ah;
@@ -899,7 +895,7 @@ void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
goto out;
}
if (sc->sc_flags & SC_OP_BEACONS)
- ath_beacon_config(sc, NULL); /* restart beacons */
+ ath_set_beacon(sc); /* restart beacons */
/* Re-Enable interrupts */
ath9k_hw_set_interrupts(ah, ah->imask);
@@ -1006,7 +1002,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
sc->config.txpowlimit, &sc->curtxpow);
if ((sc->sc_flags & SC_OP_BEACONS) || !(sc->sc_flags & (SC_OP_OFFCHANNEL)))
- ath_beacon_config(sc, NULL); /* restart beacons */
+ ath_set_beacon(sc); /* restart beacons */
ath9k_hw_set_interrupts(ah, ah->imask);
@@ -1389,7 +1385,9 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
ath9k_hw_set_tsfadjust(ah, 0);
sc->sc_flags &= ~SC_OP_TSF_RESET;
- if (iter_data.nwds + iter_data.nmeshes)
+ if (iter_data.nmeshes)
+ ah->opmode = NL80211_IFTYPE_MESH_POINT;
+ else if (iter_data.nwds)
ah->opmode = NL80211_IFTYPE_AP;
else if (iter_data.nadhocs)
ah->opmode = NL80211_IFTYPE_ADHOC;
@@ -1413,6 +1411,7 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
/* Set up ANI */
if ((iter_data.naps + iter_data.nadhocs) > 0) {
+ sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
sc->sc_flags |= SC_OP_ANI_RUN;
ath_start_ani(common);
} else {
@@ -1452,7 +1451,6 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
- struct ath_vif *avp = (void *)vif->drv_priv;
int ret = 0;
ath9k_ps_wakeup(sc);
@@ -1482,8 +1480,9 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
}
}
- if ((vif->type == NL80211_IFTYPE_ADHOC) &&
- sc->nvifs > 0) {
+ if ((ah->opmode == NL80211_IFTYPE_ADHOC) ||
+ ((vif->type == NL80211_IFTYPE_ADHOC) &&
+ sc->nvifs > 0)) {
ath_err(common, "Cannot create ADHOC interface when other"
" interfaces already exist.\n");
ret = -EINVAL;
@@ -1493,10 +1492,6 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
ath_dbg(common, ATH_DBG_CONFIG,
"Attach a VIF of type: %d\n", vif->type);
- /* Set the VIF opmode */
- avp->av_opmode = vif->type;
- avp->av_bslot = -1;
-
sc->nvifs++;
ath9k_do_vif_add_setup(hw, vif);
@@ -1782,23 +1777,68 @@ static int ath9k_sta_add(struct ieee80211_hw *hw,
struct ieee80211_sta *sta)
{
struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_node *an = (struct ath_node *) sta->drv_priv;
+ struct ieee80211_key_conf ps_key = { };
ath_node_attach(sc, sta);
+ if (vif->type != NL80211_IFTYPE_AP &&
+ vif->type != NL80211_IFTYPE_AP_VLAN)
+ return 0;
+
+ an->ps_key = ath_key_config(common, vif, sta, &ps_key);
+
return 0;
}
+static void ath9k_del_ps_key(struct ath_softc *sc,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_node *an = (struct ath_node *) sta->drv_priv;
+ struct ieee80211_key_conf ps_key = { .hw_key_idx = an->ps_key };
+
+ if (!an->ps_key)
+ return;
+
+ ath_key_delete(common, &ps_key);
+}
+
static int ath9k_sta_remove(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct ath_softc *sc = hw->priv;
+ ath9k_del_ps_key(sc, vif, sta);
ath_node_detach(sc, sta);
return 0;
}
+static void ath9k_sta_notify(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum sta_notify_cmd cmd,
+ struct ieee80211_sta *sta)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_node *an = (struct ath_node *) sta->drv_priv;
+
+ switch (cmd) {
+ case STA_NOTIFY_SLEEP:
+ an->sleeping = true;
+ if (ath_tx_aggr_sleep(sc, an))
+ ieee80211_sta_set_tim(sta);
+ break;
+ case STA_NOTIFY_AWAKE:
+ an->sleeping = false;
+ ath_tx_aggr_wakeup(sc, an);
+ break;
+ }
+}
+
static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
@@ -1855,12 +1895,29 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
if (ath9k_modparam_nohwcrypt)
return -ENOSPC;
+ if (vif->type == NL80211_IFTYPE_ADHOC &&
+ (key->cipher == WLAN_CIPHER_SUITE_TKIP ||
+ key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
+ !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
+ /*
+ * For now, disable hw crypto for the RSN IBSS group keys. This
+ * could be optimized in the future to use a modified key cache
+ * design to support per-STA RX GTK, but until that gets
+ * implemented, use of software crypto for group addressed
+ * frames is a acceptable to allow RSN IBSS to be used.
+ */
+ return -EOPNOTSUPP;
+ }
+
mutex_lock(&sc->mutex);
ath9k_ps_wakeup(sc);
ath_dbg(common, ATH_DBG_CONFIG, "Set HW Key\n");
switch (cmd) {
case SET_KEY:
+ if (sta)
+ ath9k_del_ps_key(sc, vif, sta);
+
ret = ath_key_config(common, vif, sta, key);
if (ret >= 0) {
key->hw_key_idx = ret;
@@ -1886,6 +1943,92 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
return ret;
}
+static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
+{
+ struct ath_softc *sc = data;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+ struct ath_vif *avp = (void *)vif->drv_priv;
+
+ switch (sc->sc_ah->opmode) {
+ case NL80211_IFTYPE_ADHOC:
+ /* There can be only one vif available */
+ memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
+ common->curaid = bss_conf->aid;
+ ath9k_hw_write_associd(sc->sc_ah);
+ /* configure beacon */
+ if (bss_conf->enable_beacon)
+ ath_beacon_config(sc, vif);
+ break;
+ case NL80211_IFTYPE_STATION:
+ /*
+ * Skip iteration if primary station vif's bss info
+ * was not changed
+ */
+ if (sc->sc_flags & SC_OP_PRIM_STA_VIF)
+ break;
+
+ if (bss_conf->assoc) {
+ sc->sc_flags |= SC_OP_PRIM_STA_VIF;
+ avp->primary_sta_vif = true;
+ memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
+ common->curaid = bss_conf->aid;
+ ath9k_hw_write_associd(sc->sc_ah);
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Bss Info ASSOC %d, bssid: %pM\n",
+ bss_conf->aid, common->curbssid);
+ ath_beacon_config(sc, vif);
+ /*
+ * Request a re-configuration of Beacon related timers
+ * on the receipt of the first Beacon frame (i.e.,
+ * after time sync with the AP).
+ */
+ sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
+ /* Reset rssi stats */
+ sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
+ sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
+
+ sc->sc_flags |= SC_OP_ANI_RUN;
+ ath_start_ani(common);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif)
+{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+ struct ath_vif *avp = (void *)vif->drv_priv;
+
+ /* Reconfigure bss info */
+ if (avp->primary_sta_vif && !bss_conf->assoc) {
+ ath_dbg(common, ATH_DBG_CONFIG,
+ "Bss Info DISASSOC %d, bssid %pM\n",
+ common->curaid, common->curbssid);
+ sc->sc_flags &= ~(SC_OP_PRIM_STA_VIF | SC_OP_BEACONS);
+ avp->primary_sta_vif = false;
+ memset(common->curbssid, 0, ETH_ALEN);
+ common->curaid = 0;
+ }
+
+ ieee80211_iterate_active_interfaces_atomic(
+ sc->hw, ath9k_bss_iter, sc);
+
+ /*
+ * None of station vifs are associated.
+ * Clear bssid & aid
+ */
+ if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
+ !(sc->sc_flags & SC_OP_PRIM_STA_VIF)) {
+ ath9k_hw_write_associd(sc->sc_ah);
+ /* Stop ANI */
+ sc->sc_flags &= ~SC_OP_ANI_RUN;
+ del_timer_sync(&common->ani.timer);
+ }
+}
static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
@@ -1893,7 +2036,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
u32 changed)
{
struct ath_softc *sc = hw->priv;
- struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ath_vif *avp = (void *)vif->drv_priv;
@@ -1904,20 +2046,10 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
mutex_lock(&sc->mutex);
if (changed & BSS_CHANGED_BSSID) {
- /* Set BSSID */
- memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
- memcpy(avp->bssid, bss_conf->bssid, ETH_ALEN);
- common->curaid = 0;
- ath9k_hw_write_associd(ah);
-
- /* Set aggregation protection mode parameters */
- sc->config.ath_aggr_prot = 0;
+ ath9k_config_bss(sc, vif);
ath_dbg(common, ATH_DBG_CONFIG, "BSSID: %pM aid: 0x%x\n",
common->curbssid, common->curaid);
-
- /* need to reconfigure the beacon */
- sc->sc_flags &= ~SC_OP_BEACONS ;
}
/* Enable transmission of beacons (AP, IBSS, MESH) */
@@ -1958,7 +2090,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
}
if (changed & BSS_CHANGED_BEACON_INT) {
- cur_conf->beacon_interval = bss_conf->beacon_int;
/*
* In case of AP mode, the HW TSF has to be reset
* when the beacon interval changes.
@@ -1970,9 +2101,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
if (!error)
ath_beacon_config(sc, vif);
ath9k_set_beaconing_status(sc, true);
- } else {
+ } else
ath_beacon_config(sc, vif);
- }
}
if (changed & BSS_CHANGED_ERP_PREAMBLE) {
@@ -1994,12 +2124,6 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
sc->sc_flags &= ~SC_OP_PROTECT_ENABLE;
}
- if (changed & BSS_CHANGED_ASSOC) {
- ath_dbg(common, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n",
- bss_conf->assoc);
- ath9k_bss_assoc_info(sc, hw, vif, bss_conf);
- }
-
mutex_unlock(&sc->mutex);
ath9k_ps_restore(sc);
}
@@ -2145,10 +2269,9 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
struct ath_common *common = ath9k_hw_common(ah);
int timeout = 200; /* ms */
int i, j;
+ bool drain_txq;
- ath9k_ps_wakeup(sc);
mutex_lock(&sc->mutex);
-
cancel_delayed_work_sync(&sc->tx_complete_work);
if (sc->sc_flags & SC_OP_INVALID) {
@@ -2161,7 +2284,7 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
timeout = 1;
for (j = 0; j < timeout; j++) {
- int npend = 0;
+ bool npend = false;
if (j)
usleep_range(1000, 2000);
@@ -2170,22 +2293,82 @@ static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
if (!ATH_TXQ_SETUP(sc, i))
continue;
- npend += ath9k_has_pending_frames(sc, &sc->tx.txq[i]);
+ npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]);
+
+ if (npend)
+ break;
}
if (!npend)
goto out;
}
- if (!ath_drain_all_txq(sc, false))
+ ath9k_ps_wakeup(sc);
+ spin_lock_bh(&sc->sc_pcu_lock);
+ drain_txq = ath_drain_all_txq(sc, false);
+ spin_unlock_bh(&sc->sc_pcu_lock);
+ if (!drain_txq)
ath_reset(sc, false);
-
+ ath9k_ps_restore(sc);
ieee80211_wake_queues(hw);
out:
ieee80211_queue_delayed_work(hw, &sc->tx_complete_work, 0);
mutex_unlock(&sc->mutex);
- ath9k_ps_restore(sc);
+}
+
+static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw)
+{
+ struct ath_softc *sc = hw->priv;
+ int i;
+
+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+ if (!ATH_TXQ_SETUP(sc, i))
+ continue;
+
+ if (ath9k_has_pending_frames(sc, &sc->tx.txq[i]))
+ return true;
+ }
+ return false;
+}
+
+int ath9k_tx_last_beacon(struct ieee80211_hw *hw)
+{
+ struct ath_softc *sc = hw->priv;
+ struct ath_hw *ah = sc->sc_ah;
+ struct ieee80211_vif *vif;
+ struct ath_vif *avp;
+ struct ath_buf *bf;
+ struct ath_tx_status ts;
+ int status;
+
+ vif = sc->beacon.bslot[0];
+ if (!vif)
+ return 0;
+
+ avp = (void *)vif->drv_priv;
+ if (!avp->is_bslot_active)
+ return 0;
+
+ if (!sc->beacon.tx_processed) {
+ tasklet_disable(&sc->bcon_tasklet);
+
+ bf = avp->av_bcbuf;
+ if (!bf || !bf->bf_mpdu)
+ goto skip;
+
+ status = ath9k_hw_txprocdesc(ah, bf->bf_desc, &ts);
+ if (status == -EINPROGRESS)
+ goto skip;
+
+ sc->beacon.tx_processed = true;
+ sc->beacon.tx_last = !(ts.ts_status & ATH9K_TXERR_MASK);
+
+skip:
+ tasklet_enable(&sc->bcon_tasklet);
+ }
+
+ return sc->beacon.tx_last;
}
struct ieee80211_ops ath9k_ops = {
@@ -2199,6 +2382,7 @@ struct ieee80211_ops ath9k_ops = {
.configure_filter = ath9k_configure_filter,
.sta_add = ath9k_sta_add,
.sta_remove = ath9k_sta_remove,
+ .sta_notify = ath9k_sta_notify,
.conf_tx = ath9k_conf_tx,
.bss_info_changed = ath9k_bss_info_changed,
.set_key = ath9k_set_key,
@@ -2210,4 +2394,6 @@ struct ieee80211_ops ath9k_ops = {
.rfkill_poll = ath9k_rfkill_poll_state,
.set_coverage_class = ath9k_set_coverage_class,
.flush = ath9k_flush,
+ .tx_frames_pending = ath9k_tx_frames_pending,
+ .tx_last_beacon = ath9k_tx_last_beacon,
};
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index 9c65459be100..b8cbfc707213 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
diff --git a/drivers/net/wireless/ath/ath9k/phy.h b/drivers/net/wireless/ath/ath9k/phy.h
index 5e3d7496986e..8b380305b0fc 100644
--- a/drivers/net/wireless/ath/ath9k/phy.h
+++ b/drivers/net/wireless/ath/ath9k/phy.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -19,7 +19,6 @@
#define CHANSEL_DIV 15
#define CHANSEL_2G(_freq) (((_freq) * 0x10000) / CHANSEL_DIV)
-#define CHANSEL_2G_9485(_freq) ((((_freq) * 0x10000) - 215) / CHANSEL_DIV)
#define CHANSEL_5G(_freq) (((_freq) * 0x8000) / CHANSEL_DIV)
#define AR_PHY_BASE 0x9800
@@ -38,26 +37,15 @@
#define AR_PHY_CLC_Q0 0x0000ffd0
#define AR_PHY_CLC_Q0_S 5
-#define REG_WRITE_RF_ARRAY(iniarray, regData, regWr) do { \
- int r; \
- for (r = 0; r < ((iniarray)->ia_rows); r++) { \
- REG_WRITE(ah, INI_RA((iniarray), r, 0), (regData)[r]); \
- DO_DELAY(regWr); \
- } \
- } while (0)
-
#define ANTSWAP_AB 0x0001
#define REDUCE_CHAIN_0 0x00000050
#define REDUCE_CHAIN_1 0x00000051
#define AR_PHY_CHIP_ID 0x9818
-#define RF_BANK_SETUP(_bank, _iniarray, _col) do { \
- int i; \
- for (i = 0; i < (_iniarray)->ia_rows; i++) \
- (_bank)[i] = INI_RA((_iniarray), i, _col);; \
- } while (0)
-
#define AR_PHY_TIMING11_SPUR_FREQ_SD 0x3FF00000
#define AR_PHY_TIMING11_SPUR_FREQ_SD_S 20
+#define AR_PHY_PLL_CONTROL 0x16180
+#define AR_PHY_PLL_MODE 0x16184
+
#endif
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index 4c0d36a6980f..17542214c93f 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2004 Video54 Technologies, Inc.
- * Copyright (c) 2004-2009 Atheros Communications, Inc.
+ * Copyright (c) 2004-2011 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
@@ -854,14 +854,13 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
ath_rc_rate_set_rtscts(sc, rate_table, tx_info);
}
-static bool ath_rc_update_per(struct ath_softc *sc,
+static void ath_rc_update_per(struct ath_softc *sc,
const struct ath_rate_table *rate_table,
struct ath_rate_priv *ath_rc_priv,
struct ieee80211_tx_info *tx_info,
int tx_rate, int xretries, int retries,
u32 now_msec)
{
- bool state_change = false;
int count, n_bad_frames;
u8 last_per;
static const u32 nretry_to_per_lookup[10] = {
@@ -992,8 +991,6 @@ static bool ath_rc_update_per(struct ath_softc *sc,
}
}
-
- return state_change;
}
static void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix,
@@ -1017,7 +1014,6 @@ static void ath_rc_update_ht(struct ath_softc *sc,
u32 now_msec = jiffies_to_msecs(jiffies);
int rate;
u8 last_per;
- bool state_change = false;
const struct ath_rate_table *rate_table = ath_rc_priv->rate_table;
int size = ath_rc_priv->rate_table_size;
@@ -1027,9 +1023,9 @@ static void ath_rc_update_ht(struct ath_softc *sc,
last_per = ath_rc_priv->per[tx_rate];
/* Update PER first */
- state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv,
- tx_info, tx_rate, xretries,
- retries, now_msec);
+ ath_rc_update_per(sc, rate_table, ath_rc_priv,
+ tx_info, tx_rate, xretries,
+ retries, now_msec);
/*
* If this rate looks bad (high PER) then stop using it for
@@ -1092,8 +1088,7 @@ static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table,
if (!(rate->flags & IEEE80211_TX_RC_MCS))
return rate->idx;
- while (rate->idx > mcs_rix_off[i] &&
- i < ARRAY_SIZE(mcs_rix_off)) {
+ while (i < ARRAY_SIZE(mcs_rix_off) && rate->idx > mcs_rix_off[i]) {
rix++; i++;
}
diff --git a/drivers/net/wireless/ath/ath9k/rc.h b/drivers/net/wireless/ath/ath9k/rc.h
index 5d984b8acdb1..c3d850207bee 100644
--- a/drivers/net/wireless/ath/ath9k/rc.h
+++ b/drivers/net/wireless/ath/ath9k/rc.h
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2004 Sam Leffler, Errno Consulting
* Copyright (c) 2004 Video54 Technologies, Inc.
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index b29c80def35e..07e35e59c9e3 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -28,6 +28,33 @@ static inline bool ath_is_alt_ant_ratio_better(int alt_ratio, int maxdelta,
(alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50);
}
+static inline bool ath_ant_div_comb_alt_check(u8 div_group, int alt_ratio,
+ int curr_main_set, int curr_alt_set,
+ int alt_rssi_avg, int main_rssi_avg)
+{
+ bool result = false;
+ switch (div_group) {
+ case 0:
+ if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
+ result = true;
+ break;
+ case 1:
+ if ((((curr_main_set == ATH_ANT_DIV_COMB_LNA2) &&
+ (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) &&
+ (alt_rssi_avg >= (main_rssi_avg - 5))) ||
+ ((curr_main_set == ATH_ANT_DIV_COMB_LNA1) &&
+ (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) &&
+ (alt_rssi_avg >= (main_rssi_avg - 2)))) &&
+ (alt_rssi_avg >= 4))
+ result = true;
+ else
+ result = false;
+ break;
+ }
+
+ return result;
+}
+
static inline bool ath9k_check_auto_sleep(struct ath_softc *sc)
{
return sc->ps_enabled &&
@@ -75,7 +102,6 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
*sc->rx.rxlink = bf->bf_daddr;
sc->rx.rxlink = &ds->ds_link;
- ath9k_hw_rxena(ah);
}
static void ath_setdefantenna(struct ath_softc *sc, u32 antenna)
@@ -426,9 +452,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
else
rfilt |= ATH9K_RX_FILTER_BEACON;
- if ((AR_SREV_9280_20_OR_LATER(sc->sc_ah) ||
- AR_SREV_9285_12_OR_LATER(sc->sc_ah)) &&
- (sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
+ if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) ||
(sc->rx.rxfilter & FIF_PSPOLL))
rfilt |= ATH9K_RX_FILTER_PSPOLL;
@@ -574,7 +598,8 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
sc->ps_flags &= ~PS_BEACON_SYNC;
ath_dbg(common, ATH_DBG_PS,
"Reconfigure Beacon timers based on timestamp from the AP\n");
- ath_beacon_config(sc, NULL);
+ ath_set_beacon(sc);
+ sc->ps_flags &= ~PS_TSFOOR_SYNC;
}
if (ath_beacon_dtim_pending_cab(skb)) {
@@ -919,7 +944,8 @@ static void ath9k_process_rssi(struct ath_common *common,
int last_rssi;
__le16 fc;
- if (ah->opmode != NL80211_IFTYPE_STATION)
+ if ((ah->opmode != NL80211_IFTYPE_STATION) &&
+ (ah->opmode != NL80211_IFTYPE_ADHOC))
return;
fc = hdr->frame_control;
@@ -1291,49 +1317,138 @@ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
}
}
-static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf)
+static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
+ struct ath_ant_comb *antcomb, int alt_ratio)
{
- /* Adjust the fast_div_bias based on main and alt lna conf */
- switch ((ant_conf->main_lna_conf << 4) | ant_conf->alt_lna_conf) {
- case (0x01): /* A-B LNA2 */
- ant_conf->fast_div_bias = 0x3b;
- break;
- case (0x02): /* A-B LNA1 */
- ant_conf->fast_div_bias = 0x3d;
- break;
- case (0x03): /* A-B A+B */
- ant_conf->fast_div_bias = 0x1;
- break;
- case (0x10): /* LNA2 A-B */
- ant_conf->fast_div_bias = 0x7;
- break;
- case (0x12): /* LNA2 LNA1 */
- ant_conf->fast_div_bias = 0x2;
- break;
- case (0x13): /* LNA2 A+B */
- ant_conf->fast_div_bias = 0x7;
- break;
- case (0x20): /* LNA1 A-B */
- ant_conf->fast_div_bias = 0x6;
- break;
- case (0x21): /* LNA1 LNA2 */
- ant_conf->fast_div_bias = 0x0;
- break;
- case (0x23): /* LNA1 A+B */
- ant_conf->fast_div_bias = 0x6;
- break;
- case (0x30): /* A+B A-B */
- ant_conf->fast_div_bias = 0x1;
- break;
- case (0x31): /* A+B LNA2 */
- ant_conf->fast_div_bias = 0x3b;
- break;
- case (0x32): /* A+B LNA1 */
- ant_conf->fast_div_bias = 0x3d;
- break;
- default:
- break;
+ if (ant_conf->div_group == 0) {
+ /* Adjust the fast_div_bias based on main and alt lna conf */
+ switch ((ant_conf->main_lna_conf << 4) |
+ ant_conf->alt_lna_conf) {
+ case (0x01): /* A-B LNA2 */
+ ant_conf->fast_div_bias = 0x3b;
+ break;
+ case (0x02): /* A-B LNA1 */
+ ant_conf->fast_div_bias = 0x3d;
+ break;
+ case (0x03): /* A-B A+B */
+ ant_conf->fast_div_bias = 0x1;
+ break;
+ case (0x10): /* LNA2 A-B */
+ ant_conf->fast_div_bias = 0x7;
+ break;
+ case (0x12): /* LNA2 LNA1 */
+ ant_conf->fast_div_bias = 0x2;
+ break;
+ case (0x13): /* LNA2 A+B */
+ ant_conf->fast_div_bias = 0x7;
+ break;
+ case (0x20): /* LNA1 A-B */
+ ant_conf->fast_div_bias = 0x6;
+ break;
+ case (0x21): /* LNA1 LNA2 */
+ ant_conf->fast_div_bias = 0x0;
+ break;
+ case (0x23): /* LNA1 A+B */
+ ant_conf->fast_div_bias = 0x6;
+ break;
+ case (0x30): /* A+B A-B */
+ ant_conf->fast_div_bias = 0x1;
+ break;
+ case (0x31): /* A+B LNA2 */
+ ant_conf->fast_div_bias = 0x3b;
+ break;
+ case (0x32): /* A+B LNA1 */
+ ant_conf->fast_div_bias = 0x3d;
+ break;
+ default:
+ break;
+ }
+ } else if (ant_conf->div_group == 2) {
+ /* Adjust the fast_div_bias based on main and alt_lna_conf */
+ switch ((ant_conf->main_lna_conf << 4) |
+ ant_conf->alt_lna_conf) {
+ case (0x01): /* A-B LNA2 */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case (0x02): /* A-B LNA1 */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case (0x03): /* A-B A+B */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case (0x10): /* LNA2 A-B */
+ if (!(antcomb->scan) &&
+ (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+ ant_conf->fast_div_bias = 0x1;
+ else
+ ant_conf->fast_div_bias = 0x2;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case (0x12): /* LNA2 LNA1 */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case (0x13): /* LNA2 A+B */
+ if (!(antcomb->scan) &&
+ (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+ ant_conf->fast_div_bias = 0x1;
+ else
+ ant_conf->fast_div_bias = 0x2;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case (0x20): /* LNA1 A-B */
+ if (!(antcomb->scan) &&
+ (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+ ant_conf->fast_div_bias = 0x1;
+ else
+ ant_conf->fast_div_bias = 0x2;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case (0x21): /* LNA1 LNA2 */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case (0x23): /* LNA1 A+B */
+ if (!(antcomb->scan) &&
+ (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+ ant_conf->fast_div_bias = 0x1;
+ else
+ ant_conf->fast_div_bias = 0x2;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case (0x30): /* A+B A-B */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case (0x31): /* A+B LNA2 */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case (0x32): /* A+B LNA1 */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ default:
+ break;
+ }
+
}
+
}
/* Antenna diversity and combining */
@@ -1342,7 +1457,7 @@ static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
struct ath_hw_antcomb_conf div_ant_conf;
struct ath_ant_comb *antcomb = &sc->ant_comb;
int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
- int curr_main_set, curr_bias;
+ int curr_main_set;
int main_rssi = rs->rs_rssi_ctl0;
int alt_rssi = rs->rs_rssi_ctl1;
int rx_ant_conf, main_ant_conf;
@@ -1353,8 +1468,8 @@ static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
ATH_ANT_RX_MASK;
- /* Record packet only when alt_rssi is positive */
- if (alt_rssi > 0) {
+ /* Record packet only when both main_rssi and alt_rssi is positive */
+ if (main_rssi > 0 && alt_rssi > 0) {
antcomb->total_pkt_count++;
antcomb->main_total_rssi += main_rssi;
antcomb->alt_total_rssi += alt_rssi;
@@ -1396,7 +1511,6 @@ static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
ath9k_hw_antdiv_comb_conf_get(sc->sc_ah, &div_ant_conf);
curr_alt_set = div_ant_conf.alt_lna_conf;
curr_main_set = div_ant_conf.main_lna_conf;
- curr_bias = div_ant_conf.fast_div_bias;
antcomb->count++;
@@ -1415,7 +1529,9 @@ static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
}
if (!antcomb->scan) {
- if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
+ if (ath_ant_div_comb_alt_check(div_ant_conf.div_group,
+ alt_ratio, curr_main_set, curr_alt_set,
+ alt_rssi_avg, main_rssi_avg)) {
if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
/* Switch main and alt LNA */
div_ant_conf.main_lna_conf =
@@ -1444,7 +1560,7 @@ static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
}
if ((alt_rssi_avg < (main_rssi_avg +
- ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA)))
+ div_ant_conf.lna1_lna2_delta)))
goto div_comb_done;
}
@@ -1558,8 +1674,7 @@ static void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs)
antcomb->quick_scan_cnt++;
div_comb_done:
- ath_ant_div_conf_fast_divbias(&div_ant_conf);
-
+ ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio);
ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
antcomb->scan_start_time = jiffies;
@@ -1746,7 +1861,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
if ((sc->ps_flags & (PS_WAIT_FOR_BEACON |
PS_WAIT_FOR_CAB |
PS_WAIT_FOR_PSPOLL_DATA)) ||
- unlikely(ath9k_check_auto_sleep(sc)))
+ ath9k_check_auto_sleep(sc))
ath_rx_ps(sc, skb);
spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
@@ -1767,6 +1882,7 @@ requeue:
} else {
list_move_tail(&bf->list, &sc->rx.rxbuf);
ath_rx_buf_link(sc, bf);
+ ath9k_hw_rxena(ah);
}
} while (1);
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index 8fa8acfde62e..c18ee9921fb1 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -693,7 +693,7 @@
#define AR_RC_APB 0x00000002
#define AR_RC_HOSTIF 0x00000100
-#define AR_WA 0x4004
+#define AR_WA (AR_SREV_9340(ah) ? 0x40c4 : 0x4004)
#define AR_WA_BIT6 (1 << 6)
#define AR_WA_BIT7 (1 << 7)
#define AR_WA_BIT23 (1 << 23)
@@ -712,7 +712,7 @@
#define AR_PM_STATE 0x4008
#define AR_PM_STATE_PME_D3COLD_VAUX 0x00100000
-#define AR_HOST_TIMEOUT 0x4018
+#define AR_HOST_TIMEOUT (AR_SREV_9340(ah) ? 0x4008 : 0x4018)
#define AR_HOST_TIMEOUT_APB_CNTR 0x0000FFFF
#define AR_HOST_TIMEOUT_APB_CNTR_S 0
#define AR_HOST_TIMEOUT_LCL_CNTR 0xFFFF0000
@@ -742,7 +742,8 @@
#define EEPROM_PROTECT_WP_1024_2047 0x8000
#define AR_SREV \
- ((AR_SREV_9100(ah)) ? 0x0600 : 0x4020)
+ ((AR_SREV_9100(ah)) ? 0x0600 : (AR_SREV_9340(ah) \
+ ? 0x400c : 0x4020))
#define AR_SREV_ID \
((AR_SREV_9100(ah)) ? 0x00000FFF : 0x000000FF)
@@ -790,6 +791,7 @@
#define AR_SREV_VERSION_9485 0x240
#define AR_SREV_REVISION_9485_10 0
#define AR_SREV_REVISION_9485_11 1
+#define AR_SREV_VERSION_9340 0x300
#define AR_SREV_5416(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \
@@ -858,9 +860,7 @@
#define AR_SREV_9300(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300))
#define AR_SREV_9300_20_OR_LATER(_ah) \
- (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9300) || \
- (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9300) && \
- ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9300_20)))
+ ((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9300)
#define AR_SREV_9485(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485))
@@ -870,6 +870,11 @@
#define AR_SREV_9485_11(_ah) \
(AR_SREV_9485(_ah) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9485_11))
+#define AR_SREV_9485_OR_LATER(_ah) \
+ (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9485))
+
+#define AR_SREV_9340(_ah) \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9340))
#define AR_SREV_9285E_20(_ah) \
(AR_SREV_9285_12_OR_LATER(_ah) && \
@@ -912,11 +917,11 @@ enum ath_usb_dev {
#define AR_INTR_SPURIOUS 0xFFFFFFFF
-#define AR_INTR_SYNC_CAUSE_CLR 0x4028
+#define AR_INTR_SYNC_CAUSE (AR_SREV_9340(ah) ? 0x4010 : 0x4028)
+#define AR_INTR_SYNC_CAUSE_CLR (AR_SREV_9340(ah) ? 0x4010 : 0x4028)
-#define AR_INTR_SYNC_CAUSE 0x4028
-#define AR_INTR_SYNC_ENABLE 0x402c
+#define AR_INTR_SYNC_ENABLE (AR_SREV_9340(ah) ? 0x4014 : 0x402c)
#define AR_INTR_SYNC_ENABLE_GPIO 0xFFFC0000
#define AR_INTR_SYNC_ENABLE_GPIO_S 18
@@ -956,24 +961,24 @@ enum {
};
-#define AR_INTR_ASYNC_MASK 0x4030
+#define AR_INTR_ASYNC_MASK (AR_SREV_9340(ah) ? 0x4018 : 0x4030)
#define AR_INTR_ASYNC_MASK_GPIO 0xFFFC0000
#define AR_INTR_ASYNC_MASK_GPIO_S 18
-#define AR_INTR_SYNC_MASK 0x4034
+#define AR_INTR_SYNC_MASK (AR_SREV_9340(ah) ? 0x401c : 0x4034)
#define AR_INTR_SYNC_MASK_GPIO 0xFFFC0000
#define AR_INTR_SYNC_MASK_GPIO_S 18
-#define AR_INTR_ASYNC_CAUSE_CLR 0x4038
-#define AR_INTR_ASYNC_CAUSE 0x4038
+#define AR_INTR_ASYNC_CAUSE_CLR (AR_SREV_9340(ah) ? 0x4020 : 0x4038)
+#define AR_INTR_ASYNC_CAUSE (AR_SREV_9340(ah) ? 0x4020 : 0x4038)
-#define AR_INTR_ASYNC_ENABLE 0x403c
+#define AR_INTR_ASYNC_ENABLE (AR_SREV_9340(ah) ? 0x4024 : 0x403c)
#define AR_INTR_ASYNC_ENABLE_GPIO 0xFFFC0000
#define AR_INTR_ASYNC_ENABLE_GPIO_S 18
#define AR_PCIE_SERDES 0x4040
#define AR_PCIE_SERDES2 0x4044
-#define AR_PCIE_PM_CTRL 0x4014
+#define AR_PCIE_PM_CTRL (AR_SREV_9340(ah) ? 0x4004 : 0x4014)
#define AR_PCIE_PM_CTRL_ENA 0x00080000
#define AR_NUM_GPIO 14
@@ -984,7 +989,7 @@ enum {
#define AR9300_NUM_GPIO 17
#define AR7010_NUM_GPIO 16
-#define AR_GPIO_IN_OUT 0x4048
+#define AR_GPIO_IN_OUT (AR_SREV_9340(ah) ? 0x4028 : 0x4048)
#define AR_GPIO_IN_VAL 0x0FFFC000
#define AR_GPIO_IN_VAL_S 14
#define AR928X_GPIO_IN_VAL 0x000FFC00
@@ -998,11 +1003,12 @@ enum {
#define AR7010_GPIO_IN_VAL 0x0000FFFF
#define AR7010_GPIO_IN_VAL_S 0
-#define AR_GPIO_IN 0x404c
+#define AR_GPIO_IN (AR_SREV_9340(ah) ? 0x402c : 0x404c)
#define AR9300_GPIO_IN_VAL 0x0001FFFF
#define AR9300_GPIO_IN_VAL_S 0
-#define AR_GPIO_OE_OUT (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c)
+#define AR_GPIO_OE_OUT (AR_SREV_9340(ah) ? 0x4030 : \
+ (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c))
#define AR_GPIO_OE_OUT_DRV 0x3
#define AR_GPIO_OE_OUT_DRV_NO 0x0
#define AR_GPIO_OE_OUT_DRV_LOW 0x1
@@ -1024,11 +1030,13 @@ enum {
#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 (AR_SREV_9340(ah) ? 0x4038 : \
+ (AR_SREV_9300_20_OR_LATER(ah) ? 0x4058 : 0x4050))
#define AR_GPIO_INTR_POL_VAL 0x0001FFFF
#define AR_GPIO_INTR_POL_VAL_S 0
-#define AR_GPIO_INPUT_EN_VAL (AR_SREV_9300_20_OR_LATER(ah) ? 0x405c : 0x4054)
+#define AR_GPIO_INPUT_EN_VAL (AR_SREV_9340(ah) ? 0x403c : \
+ (AR_SREV_9300_20_OR_LATER(ah) ? 0x405c : 0x4054))
#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_DEF 0x00000004
#define AR_GPIO_INPUT_EN_VAL_BT_PRIORITY_S 2
#define AR_GPIO_INPUT_EN_VAL_BT_FREQUENCY_DEF 0x00000008
@@ -1046,13 +1054,15 @@ enum {
#define AR_GPIO_RTC_RESET_OVERRIDE_ENABLE 0x00010000
#define AR_GPIO_JTAG_DISABLE 0x00020000
-#define AR_GPIO_INPUT_MUX1 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4060 : 0x4058)
+#define AR_GPIO_INPUT_MUX1 (AR_SREV_9340(ah) ? 0x4040 : \
+ (AR_SREV_9300_20_OR_LATER(ah) ? 0x4060 : 0x4058))
#define AR_GPIO_INPUT_MUX1_BT_ACTIVE 0x000f0000
#define AR_GPIO_INPUT_MUX1_BT_ACTIVE_S 16
#define AR_GPIO_INPUT_MUX1_BT_PRIORITY 0x00000f00
#define AR_GPIO_INPUT_MUX1_BT_PRIORITY_S 8
-#define AR_GPIO_INPUT_MUX2 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4064 : 0x405c)
+#define AR_GPIO_INPUT_MUX2 (AR_SREV_9340(ah) ? 0x4044 : \
+ (AR_SREV_9300_20_OR_LATER(ah) ? 0x4064 : 0x405c))
#define AR_GPIO_INPUT_MUX2_CLK25 0x0000000f
#define AR_GPIO_INPUT_MUX2_CLK25_S 0
#define AR_GPIO_INPUT_MUX2_RFSILENT 0x000000f0
@@ -1060,13 +1070,18 @@ enum {
#define AR_GPIO_INPUT_MUX2_RTC_RESET 0x00000f00
#define AR_GPIO_INPUT_MUX2_RTC_RESET_S 8
-#define AR_GPIO_OUTPUT_MUX1 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4068 : 0x4060)
-#define AR_GPIO_OUTPUT_MUX2 (AR_SREV_9300_20_OR_LATER(ah) ? 0x406c : 0x4064)
-#define AR_GPIO_OUTPUT_MUX3 (AR_SREV_9300_20_OR_LATER(ah) ? 0x4070 : 0x4068)
+#define AR_GPIO_OUTPUT_MUX1 (AR_SREV_9340(ah) ? 0x4048 : \
+ (AR_SREV_9300_20_OR_LATER(ah) ? 0x4068 : 0x4060))
+#define AR_GPIO_OUTPUT_MUX2 (AR_SREV_9340(ah) ? 0x404c : \
+ (AR_SREV_9300_20_OR_LATER(ah) ? 0x406c : 0x4064))
+#define AR_GPIO_OUTPUT_MUX3 (AR_SREV_9340(ah) ? 0x4050 : \
+ (AR_SREV_9300_20_OR_LATER(ah) ? 0x4070 : 0x4068))
-#define AR_INPUT_STATE (AR_SREV_9300_20_OR_LATER(ah) ? 0x4074 : 0x406c)
+#define AR_INPUT_STATE (AR_SREV_9340(ah) ? 0x4054 : \
+ (AR_SREV_9300_20_OR_LATER(ah) ? 0x4074 : 0x406c))
-#define AR_EEPROM_STATUS_DATA (AR_SREV_9300_20_OR_LATER(ah) ? 0x4084 : 0x407c)
+#define AR_EEPROM_STATUS_DATA (AR_SREV_9340(ah) ? 0x40c8 : \
+ (AR_SREV_9300_20_OR_LATER(ah) ? 0x4084 : 0x407c))
#define AR_EEPROM_STATUS_DATA_VAL 0x0000ffff
#define AR_EEPROM_STATUS_DATA_VAL_S 0
#define AR_EEPROM_STATUS_DATA_BUSY 0x00010000
@@ -1074,28 +1089,51 @@ enum {
#define AR_EEPROM_STATUS_DATA_PROT_ACCESS 0x00040000
#define AR_EEPROM_STATUS_DATA_ABSENT_ACCESS 0x00080000
-#define AR_OBS (AR_SREV_9300_20_OR_LATER(ah) ? 0x4088 : 0x4080)
+#define AR_OBS (AR_SREV_9340(ah) ? 0x405c : \
+ (AR_SREV_9300_20_OR_LATER(ah) ? 0x4088 : 0x4080))
#define AR_GPIO_PDPU (AR_SREV_9300_20_OR_LATER(ah) ? 0x4090 : 0x4088)
-#define AR_PCIE_MSI (AR_SREV_9300_20_OR_LATER(ah) ? 0x40a4 : 0x4094)
+#define AR_PCIE_MSI (AR_SREV_9340(ah) ? 0x40d8 : \
+ (AR_SREV_9300_20_OR_LATER(ah) ? 0x40a4 : 0x4094))
#define AR_PCIE_MSI_ENABLE 0x00000001
-#define AR_INTR_PRIO_SYNC_ENABLE 0x40c4
-#define AR_INTR_PRIO_ASYNC_MASK 0x40c8
-#define AR_INTR_PRIO_SYNC_MASK 0x40cc
-#define AR_INTR_PRIO_ASYNC_ENABLE 0x40d4
+#define AR_INTR_PRIO_SYNC_ENABLE (AR_SREV_9340(ah) ? 0x4088 : 0x40c4)
+#define AR_INTR_PRIO_ASYNC_MASK (AR_SREV_9340(ah) ? 0x408c : 0x40c8)
+#define AR_INTR_PRIO_SYNC_MASK (AR_SREV_9340(ah) ? 0x4090 : 0x40cc)
+#define AR_INTR_PRIO_ASYNC_ENABLE (AR_SREV_9340(ah) ? 0x4094 : 0x40d4)
#define AR_ENT_OTP 0x40d8
#define AR_ENT_OTP_CHAIN2_DISABLE 0x00020000
#define AR_ENT_OTP_MPSD 0x00800000
-#define AR_CH0_BB_DPLL2 0x16184
+
+#define AR_CH0_BB_DPLL1 0x16180
+#define AR_CH0_BB_DPLL1_REFDIV 0xF8000000
+#define AR_CH0_BB_DPLL1_REFDIV_S 27
+#define AR_CH0_BB_DPLL1_NINI 0x07FC0000
+#define AR_CH0_BB_DPLL1_NINI_S 18
+#define AR_CH0_BB_DPLL1_NFRAC 0x0003FFFF
+#define AR_CH0_BB_DPLL1_NFRAC_S 0
+
+#define AR_CH0_BB_DPLL2 0x16184
+#define AR_CH0_BB_DPLL2_LOCAL_PLL 0x40000000
+#define AR_CH0_BB_DPLL2_LOCAL_PLL_S 30
+#define AR_CH0_DPLL2_KI 0x3C000000
+#define AR_CH0_DPLL2_KI_S 26
+#define AR_CH0_DPLL2_KD 0x03F80000
+#define AR_CH0_DPLL2_KD_S 19
+#define AR_CH0_BB_DPLL2_EN_NEGTRIG 0x00040000
+#define AR_CH0_BB_DPLL2_EN_NEGTRIG_S 18
+#define AR_CH0_BB_DPLL2_PLL_PWD 0x00010000
+#define AR_CH0_BB_DPLL2_PLL_PWD_S 16
+#define AR_CH0_BB_DPLL2_OUTDIV 0x0000E000
+#define AR_CH0_BB_DPLL2_OUTDIV_S 13
+
#define AR_CH0_BB_DPLL3 0x16188
+#define AR_CH0_BB_DPLL3_PHASE_SHIFT 0x3F800000
+#define AR_CH0_BB_DPLL3_PHASE_SHIFT_S 23
+
#define AR_CH0_DDR_DPLL2 0x16244
#define AR_CH0_DDR_DPLL3 0x16248
-#define AR_CH0_DPLL2_KD 0x03F80000
-#define AR_CH0_DPLL2_KD_S 19
-#define AR_CH0_DPLL2_KI 0x3C000000
-#define AR_CH0_DPLL2_KI_S 26
#define AR_CH0_DPLL3_PHASE_SHIFT 0x3F800000
#define AR_CH0_DPLL3_PHASE_SHIFT_S 23
#define AR_PHY_CCA_NOM_VAL_2GHZ -118
@@ -1144,6 +1182,7 @@ enum {
#define AR_RTC_PLL_REFDIV_5 0x000000c0
#define AR_RTC_PLL_CLKSEL 0x00000300
#define AR_RTC_PLL_CLKSEL_S 8
+#define AR_RTC_PLL_BYPASS 0x00010000
#define PLL3 0x16188
#define PLL3_DO_MEAS_MASK 0x40000000
@@ -1190,7 +1229,8 @@ enum {
/* RTC_DERIVED_* - only for AR9100 */
-#define AR_RTC_DERIVED_CLK (AR_RTC_BASE + 0x0038)
+#define AR_RTC_DERIVED_CLK \
+ (AR_SREV_9100(ah) ? (AR_RTC_BASE + 0x0038) : 0x7038)
#define AR_RTC_DERIVED_CLK_PERIOD 0x0000fffe
#define AR_RTC_DERIVED_CLK_PERIOD_S 1
@@ -1396,6 +1436,7 @@ enum {
#define AR_STA_ID1_PCF 0x00100000
#define AR_STA_ID1_USE_DEFANT 0x00200000
#define AR_STA_ID1_DEFANT_UPDATE 0x00400000
+#define AR_STA_ID1_AR9100_BA_FIX 0x00400000
#define AR_STA_ID1_RTS_USE_DEF 0x00800000
#define AR_STA_ID1_ACKCTS_6MB 0x01000000
#define AR_STA_ID1_BASE_RATE_11B 0x02000000
@@ -1668,6 +1709,22 @@ enum {
#define AR_BTCOEX_WL_WGHT 0xffff0000
#define AR_BTCOEX_WL_WGHT_S 16
+#define AR_BT_COEX_WL_WEIGHTS0 0x8174
+#define AR_BT_COEX_WL_WEIGHTS1 0x81c4
+
+#define AR_BT_COEX_BT_WEIGHTS0 0x83ac
+#define AR_BT_COEX_BT_WEIGHTS1 0x83b0
+#define AR_BT_COEX_BT_WEIGHTS2 0x83b4
+#define AR_BT_COEX_BT_WEIGHTS3 0x83b8
+
+#define AR9300_BT_WGHT 0xcccc4444
+#define AR9300_STOMP_ALL_WLAN_WGHT0 0xfffffff0
+#define AR9300_STOMP_ALL_WLAN_WGHT1 0xfffffff0
+#define AR9300_STOMP_LOW_WLAN_WGHT0 0x88888880
+#define AR9300_STOMP_LOW_WLAN_WGHT1 0x88888880
+#define AR9300_STOMP_NONE_WLAN_WGHT0 0x00000000
+#define AR9300_STOMP_NONE_WLAN_WGHT1 0x00000000
+
#define AR_BT_COEX_MODE2 0x817c
#define AR_BT_BCN_MISS_THRESH 0x000000ff
#define AR_BT_BCN_MISS_THRESH_S 0
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index d3d24904f62f..35422fc1f2ce 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.c
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 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
@@ -23,20 +23,18 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd)
return "WMI_ECHO_CMDID";
case WMI_ACCESS_MEMORY_CMDID:
return "WMI_ACCESS_MEMORY_CMDID";
+ case WMI_GET_FW_VERSION:
+ return "WMI_GET_FW_VERSION";
case WMI_DISABLE_INTR_CMDID:
return "WMI_DISABLE_INTR_CMDID";
case WMI_ENABLE_INTR_CMDID:
return "WMI_ENABLE_INTR_CMDID";
- case WMI_RX_LINK_CMDID:
- return "WMI_RX_LINK_CMDID";
case WMI_ATH_INIT_CMDID:
return "WMI_ATH_INIT_CMDID";
case WMI_ABORT_TXQ_CMDID:
return "WMI_ABORT_TXQ_CMDID";
case WMI_STOP_TX_DMA_CMDID:
return "WMI_STOP_TX_DMA_CMDID";
- case WMI_STOP_DMA_RECV_CMDID:
- return "WMI_STOP_DMA_RECV_CMDID";
case WMI_ABORT_TX_DMA_CMDID:
return "WMI_ABORT_TX_DMA_CMDID";
case WMI_DRAIN_TXQ_CMDID:
@@ -51,8 +49,6 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd)
return "WMI_FLUSH_RECV_CMDID";
case WMI_SET_MODE_CMDID:
return "WMI_SET_MODE_CMDID";
- case WMI_RESET_CMDID:
- return "WMI_RESET_CMDID";
case WMI_NODE_CREATE_CMDID:
return "WMI_NODE_CREATE_CMDID";
case WMI_NODE_REMOVE_CMDID:
@@ -61,8 +57,6 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd)
return "WMI_VAP_REMOVE_CMDID";
case WMI_VAP_CREATE_CMDID:
return "WMI_VAP_CREATE_CMDID";
- case WMI_BEACON_UPDATE_CMDID:
- return "WMI_BEACON_UPDATE_CMDID";
case WMI_REG_READ_CMDID:
return "WMI_REG_READ_CMDID";
case WMI_REG_WRITE_CMDID:
@@ -71,22 +65,22 @@ static const char *wmi_cmd_to_name(enum wmi_cmd_id wmi_cmd)
return "WMI_RC_STATE_CHANGE_CMDID";
case WMI_RC_RATE_UPDATE_CMDID:
return "WMI_RC_RATE_UPDATE_CMDID";
- case WMI_DEBUG_INFO_CMDID:
- return "WMI_DEBUG_INFO_CMDID";
- case WMI_HOST_ATTACH:
- return "WMI_HOST_ATTACH";
case WMI_TARGET_IC_UPDATE_CMDID:
return "WMI_TARGET_IC_UPDATE_CMDID";
- case WMI_TGT_STATS_CMDID:
- return "WMI_TGT_STATS_CMDID";
case WMI_TX_AGGR_ENABLE_CMDID:
return "WMI_TX_AGGR_ENABLE_CMDID";
case WMI_TGT_DETACH_CMDID:
return "WMI_TGT_DETACH_CMDID";
- case WMI_TGT_TXQ_ENABLE_CMDID:
- return "WMI_TGT_TXQ_ENABLE_CMDID";
- case WMI_AGGR_LIMIT_CMD:
- return "WMI_AGGR_LIMIT_CMD";
+ case WMI_NODE_UPDATE_CMDID:
+ return "WMI_NODE_UPDATE_CMDID";
+ case WMI_INT_STATS_CMDID:
+ return "WMI_INT_STATS_CMDID";
+ case WMI_TX_STATS_CMDID:
+ return "WMI_TX_STATS_CMDID";
+ case WMI_RX_STATS_CMDID:
+ return "WMI_RX_STATS_CMDID";
+ case WMI_BITRATE_MASK_CMDID:
+ return "WMI_BITRATE_MASK_CMDID";
}
return "Bogus";
@@ -102,9 +96,15 @@ struct wmi *ath9k_init_wmi(struct ath9k_htc_priv *priv)
wmi->drv_priv = priv;
wmi->stopped = false;
+ skb_queue_head_init(&wmi->wmi_event_queue);
+ spin_lock_init(&wmi->wmi_lock);
+ spin_lock_init(&wmi->event_lock);
mutex_init(&wmi->op_mutex);
mutex_init(&wmi->multi_write_mutex);
init_completion(&wmi->cmd_wait);
+ INIT_LIST_HEAD(&wmi->pending_tx_events);
+ tasklet_init(&wmi->wmi_event_tasklet, ath9k_wmi_event_tasklet,
+ (unsigned long)wmi);
return wmi;
}
@@ -120,11 +120,65 @@ void ath9k_deinit_wmi(struct ath9k_htc_priv *priv)
kfree(priv->wmi);
}
-void ath9k_swba_tasklet(unsigned long data)
+void ath9k_wmi_event_drain(struct ath9k_htc_priv *priv)
{
- struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data;
+ unsigned long flags;
- ath9k_htc_swba(priv, priv->wmi->beacon_pending);
+ tasklet_kill(&priv->wmi->wmi_event_tasklet);
+ spin_lock_irqsave(&priv->wmi->wmi_lock, flags);
+ __skb_queue_purge(&priv->wmi->wmi_event_queue);
+ spin_unlock_irqrestore(&priv->wmi->wmi_lock, flags);
+}
+
+void ath9k_wmi_event_tasklet(unsigned long data)
+{
+ struct wmi *wmi = (struct wmi *)data;
+ struct ath9k_htc_priv *priv = wmi->drv_priv;
+ struct wmi_cmd_hdr *hdr;
+ void *wmi_event;
+ struct wmi_event_swba *swba;
+ struct sk_buff *skb = NULL;
+ unsigned long flags;
+ u16 cmd_id;
+
+ do {
+ spin_lock_irqsave(&wmi->wmi_lock, flags);
+ skb = __skb_dequeue(&wmi->wmi_event_queue);
+ if (!skb) {
+ spin_unlock_irqrestore(&wmi->wmi_lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&wmi->wmi_lock, flags);
+
+ hdr = (struct wmi_cmd_hdr *) skb->data;
+ cmd_id = be16_to_cpu(hdr->command_id);
+ wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr));
+
+ switch (cmd_id) {
+ case WMI_SWBA_EVENTID:
+ swba = (struct wmi_event_swba *) wmi_event;
+ ath9k_htc_swba(priv, swba);
+ break;
+ case WMI_FATAL_EVENTID:
+ ieee80211_queue_work(wmi->drv_priv->hw,
+ &wmi->drv_priv->fatal_work);
+ break;
+ case WMI_TXSTATUS_EVENTID:
+ spin_lock_bh(&priv->tx.tx_lock);
+ if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) {
+ spin_unlock_bh(&priv->tx.tx_lock);
+ break;
+ }
+ spin_unlock_bh(&priv->tx.tx_lock);
+
+ ath9k_htc_txstatus(priv, wmi_event);
+ break;
+ default:
+ break;
+ }
+
+ kfree_skb(skb);
+ } while (1);
}
void ath9k_fatal_work(struct work_struct *work)
@@ -153,10 +207,6 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
struct wmi *wmi = (struct wmi *) priv;
struct wmi_cmd_hdr *hdr;
u16 cmd_id;
- void *wmi_event;
-#ifdef CONFIG_ATH9K_HTC_DEBUGFS
- __be32 txrate;
-#endif
if (unlikely(wmi->stopped))
goto free_skb;
@@ -165,26 +215,10 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
cmd_id = be16_to_cpu(hdr->command_id);
if (cmd_id & 0x1000) {
- wmi_event = skb_pull(skb, sizeof(struct wmi_cmd_hdr));
- switch (cmd_id) {
- case WMI_SWBA_EVENTID:
- wmi->beacon_pending = *(u8 *)wmi_event;
- tasklet_schedule(&wmi->drv_priv->swba_tasklet);
- break;
- case WMI_FATAL_EVENTID:
- ieee80211_queue_work(wmi->drv_priv->hw,
- &wmi->drv_priv->fatal_work);
- break;
- case WMI_TXRATE_EVENTID:
-#ifdef CONFIG_ATH9K_HTC_DEBUGFS
- txrate = ((struct wmi_event_txrate *)wmi_event)->txrate;
- wmi->drv_priv->debug.txrate = be32_to_cpu(txrate);
-#endif
- break;
- default:
- break;
- }
- kfree_skb(skb);
+ spin_lock(&wmi->wmi_lock);
+ __skb_queue_tail(&wmi->wmi_event_queue, skb);
+ spin_unlock(&wmi->wmi_lock);
+ tasklet_schedule(&wmi->wmi_event_tasklet);
return;
}
@@ -243,7 +277,7 @@ static int ath9k_wmi_cmd_issue(struct wmi *wmi,
hdr->command_id = cpu_to_be16(cmd);
hdr->seq_no = cpu_to_be16(++wmi->tx_seq_id);
- return htc_send(wmi->htc, skb, wmi->ctrl_epid, NULL);
+ return htc_send_epid(wmi->htc, skb, wmi->ctrl_epid);
}
int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
diff --git a/drivers/net/wireless/ath/ath9k/wmi.h b/drivers/net/wireless/ath/ath9k/wmi.h
index 42084277522d..fde6da619f30 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.h
+++ b/drivers/net/wireless/ath/ath9k/wmi.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Atheros Communications Inc.
+ * Copyright (c) 2010-2011 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,7 +17,6 @@
#ifndef WMI_H
#define WMI_H
-
struct wmi_event_txrate {
__be32 txrate;
struct {
@@ -31,18 +30,65 @@ struct wmi_cmd_hdr {
__be16 seq_no;
} __packed;
+struct wmi_fw_version {
+ __be16 major;
+ __be16 minor;
+
+} __packed;
+
+struct wmi_event_swba {
+ __be64 tsf;
+ u8 beacon_pending;
+};
+
+/*
+ * 64 - HTC header - WMI header - 1 / txstatus
+ * And some other hdr. space is also accounted for.
+ * 12 seems to be the magic number.
+ */
+#define HTC_MAX_TX_STATUS 12
+
+#define ATH9K_HTC_TXSTAT_ACK BIT(0)
+#define ATH9K_HTC_TXSTAT_FILT BIT(1)
+#define ATH9K_HTC_TXSTAT_RTC_CTS BIT(2)
+#define ATH9K_HTC_TXSTAT_MCS BIT(3)
+#define ATH9K_HTC_TXSTAT_CW40 BIT(4)
+#define ATH9K_HTC_TXSTAT_SGI BIT(5)
+
+/*
+ * Legacy rates are indicated as indices.
+ * HT rates are indicated as dot11 numbers.
+ * This allows us to resrict the rate field
+ * to 4 bits.
+ */
+#define ATH9K_HTC_TXSTAT_RATE 0x0f
+#define ATH9K_HTC_TXSTAT_RATE_S 0
+
+#define ATH9K_HTC_TXSTAT_EPID 0xf0
+#define ATH9K_HTC_TXSTAT_EPID_S 4
+
+struct __wmi_event_txstatus {
+ u8 cookie;
+ u8 ts_rate; /* Also holds EP ID */
+ u8 ts_flags;
+};
+
+struct wmi_event_txstatus {
+ u8 cnt;
+ struct __wmi_event_txstatus txstatus[HTC_MAX_TX_STATUS];
+} __packed;
+
enum wmi_cmd_id {
WMI_ECHO_CMDID = 0x0001,
WMI_ACCESS_MEMORY_CMDID,
/* Commands to Target */
+ WMI_GET_FW_VERSION,
WMI_DISABLE_INTR_CMDID,
WMI_ENABLE_INTR_CMDID,
- WMI_RX_LINK_CMDID,
WMI_ATH_INIT_CMDID,
WMI_ABORT_TXQ_CMDID,
WMI_STOP_TX_DMA_CMDID,
- WMI_STOP_DMA_RECV_CMDID,
WMI_ABORT_TX_DMA_CMDID,
WMI_DRAIN_TXQ_CMDID,
WMI_DRAIN_TXQ_ALL_CMDID,
@@ -50,24 +96,22 @@ enum wmi_cmd_id {
WMI_STOP_RECV_CMDID,
WMI_FLUSH_RECV_CMDID,
WMI_SET_MODE_CMDID,
- WMI_RESET_CMDID,
WMI_NODE_CREATE_CMDID,
WMI_NODE_REMOVE_CMDID,
WMI_VAP_REMOVE_CMDID,
WMI_VAP_CREATE_CMDID,
- WMI_BEACON_UPDATE_CMDID,
WMI_REG_READ_CMDID,
WMI_REG_WRITE_CMDID,
WMI_RC_STATE_CHANGE_CMDID,
WMI_RC_RATE_UPDATE_CMDID,
- WMI_DEBUG_INFO_CMDID,
- WMI_HOST_ATTACH,
WMI_TARGET_IC_UPDATE_CMDID,
- WMI_TGT_STATS_CMDID,
WMI_TX_AGGR_ENABLE_CMDID,
WMI_TGT_DETACH_CMDID,
- WMI_TGT_TXQ_ENABLE_CMDID,
- WMI_AGGR_LIMIT_CMD = 0x0026,
+ WMI_NODE_UPDATE_CMDID,
+ WMI_INT_STATS_CMDID,
+ WMI_TX_STATS_CMDID,
+ WMI_RX_STATS_CMDID,
+ WMI_BITRATE_MASK_CMDID,
};
enum wmi_event_id {
@@ -76,9 +120,8 @@ enum wmi_event_id {
WMI_FATAL_EVENTID,
WMI_TXTO_EVENTID,
WMI_BMISS_EVENTID,
- WMI_WLAN_TXCOMP_EVENTID,
WMI_DELBA_EVENTID,
- WMI_TXRATE_EVENTID,
+ WMI_TXSTATUS_EVENTID,
};
#define MAX_CMD_NUMBER 62
@@ -88,6 +131,12 @@ struct register_write {
__be32 val;
};
+struct ath9k_htc_tx_event {
+ int count;
+ struct __wmi_event_txstatus txs;
+ struct list_head list;
+};
+
struct wmi {
struct ath9k_htc_priv *drv_priv;
struct htc_target *htc;
@@ -95,12 +144,16 @@ struct wmi {
struct mutex op_mutex;
struct completion cmd_wait;
enum wmi_cmd_id last_cmd_id;
+ struct sk_buff_head wmi_event_queue;
+ struct tasklet_struct wmi_event_tasklet;
u16 tx_seq_id;
u8 *cmd_rsp_buf;
u32 cmd_rsp_len;
bool stopped;
- u8 beacon_pending;
+ struct list_head pending_tx_events;
+ spinlock_t event_lock;
+
spinlock_t wmi_lock;
atomic_t mwrite_cnt;
@@ -117,8 +170,9 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
u8 *cmd_buf, u32 cmd_len,
u8 *rsp_buf, u32 rsp_len,
u32 timeout);
-void ath9k_swba_tasklet(unsigned long data);
+void ath9k_wmi_event_tasklet(unsigned long data);
void ath9k_fatal_work(struct work_struct *work);
+void ath9k_wmi_event_drain(struct ath9k_htc_priv *priv);
#define WMI_CMD(_wmi_cmd) \
do { \
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 88fa7fdffd05..3779b8977d47 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2008-2011 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
@@ -357,6 +357,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ath_frame_info *fi;
int nframes;
u8 tidno;
+ bool clear_filter;
skb = bf->bf_mpdu;
hdr = (struct ieee80211_hdr *)skb->data;
@@ -441,22 +442,24 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
/* transmit completion */
acked_cnt++;
} else {
- if (!(tid->state & AGGR_CLEANUP) && retry) {
- if (fi->retries < ATH_MAX_SW_RETRIES) {
- ath_tx_set_retry(sc, txq, bf->bf_mpdu);
- txpending = 1;
- } else {
- bf->bf_state.bf_type |= BUF_XRETRY;
- txfail = 1;
- sendbar = 1;
- txfail_cnt++;
- }
- } else {
+ if ((tid->state & AGGR_CLEANUP) || !retry) {
/*
* cleanup in progress, just fail
* the un-acked sub-frames
*/
txfail = 1;
+ } else if (fi->retries < ATH_MAX_SW_RETRIES) {
+ if (!(ts->ts_status & ATH9K_TXERR_FILT) ||
+ !an->sleeping)
+ ath_tx_set_retry(sc, txq, bf->bf_mpdu);
+
+ clear_filter = true;
+ txpending = 1;
+ } else {
+ bf->bf_state.bf_type |= BUF_XRETRY;
+ txfail = 1;
+ sendbar = 1;
+ txfail_cnt++;
}
}
@@ -496,6 +499,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
!txfail, sendbar);
} else {
/* retry the un-acked ones */
+ ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, false);
if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
if (bf->bf_next == NULL && bf_last->bf_stale) {
struct ath_buf *tbf;
@@ -546,7 +550,12 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
/* prepend un-acked frames to the beginning of the pending frame queue */
if (!list_empty(&bf_pending)) {
+ if (an->sleeping)
+ ieee80211_sta_set_tim(sta);
+
spin_lock_bh(&txq->axq_lock);
+ if (clear_filter)
+ tid->ac->clear_ps_filter = true;
list_splice(&bf_pending, &tid->buf_q);
ath_tx_queue_tid(txq, tid);
spin_unlock_bh(&txq->axq_lock);
@@ -816,6 +825,11 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
bf = list_first_entry(&bf_q, struct ath_buf, list);
bf->bf_lastbf = list_entry(bf_q.prev, struct ath_buf, list);
+ if (tid->ac->clear_ps_filter) {
+ tid->ac->clear_ps_filter = false;
+ ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true);
+ }
+
/* if only one frame, send as non-aggregate */
if (bf == bf->bf_lastbf) {
fi = get_frame_info(bf->bf_mpdu);
@@ -896,6 +910,67 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
ath_tx_flush_tid(sc, txtid);
}
+bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an)
+{
+ struct ath_atx_tid *tid;
+ struct ath_atx_ac *ac;
+ struct ath_txq *txq;
+ bool buffered = false;
+ int tidno;
+
+ for (tidno = 0, tid = &an->tid[tidno];
+ tidno < WME_NUM_TID; tidno++, tid++) {
+
+ if (!tid->sched)
+ continue;
+
+ ac = tid->ac;
+ txq = ac->txq;
+
+ spin_lock_bh(&txq->axq_lock);
+
+ if (!list_empty(&tid->buf_q))
+ buffered = true;
+
+ tid->sched = false;
+ list_del(&tid->list);
+
+ if (ac->sched) {
+ ac->sched = false;
+ list_del(&ac->list);
+ }
+
+ spin_unlock_bh(&txq->axq_lock);
+ }
+
+ return buffered;
+}
+
+void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an)
+{
+ struct ath_atx_tid *tid;
+ struct ath_atx_ac *ac;
+ struct ath_txq *txq;
+ int tidno;
+
+ for (tidno = 0, tid = &an->tid[tidno];
+ tidno < WME_NUM_TID; tidno++, tid++) {
+
+ ac = tid->ac;
+ txq = ac->txq;
+
+ spin_lock_bh(&txq->axq_lock);
+ ac->clear_ps_filter = true;
+
+ if (!list_empty(&tid->buf_q) && !tid->paused) {
+ ath_tx_queue_tid(txq, tid);
+ ath_txq_schedule(sc, txq);
+ }
+
+ spin_unlock_bh(&txq->axq_lock);
+ }
+}
+
void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
{
struct ath_atx_tid *txtid;
@@ -1451,7 +1526,7 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
struct ieee80211_hdr *hdr;
struct ath_frame_info *fi = get_frame_info(skb);
- struct ath_node *an;
+ struct ath_node *an = NULL;
struct ath_atx_tid *tid;
enum ath9k_key_type keytype;
u16 seqno = 0;
@@ -1459,11 +1534,13 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
+ if (sta)
+ an = (struct ath_node *) sta->drv_priv;
+
hdr = (struct ieee80211_hdr *)skb->data;
- if (sta && ieee80211_is_data_qos(hdr->frame_control) &&
+ if (an && ieee80211_is_data_qos(hdr->frame_control) &&
conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR)) {
- an = (struct ath_node *) sta->drv_priv;
tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
/*
@@ -1479,6 +1556,8 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
memset(fi, 0, sizeof(*fi));
if (hw_key)
fi->keyix = hw_key->hw_key_idx;
+ else if (an && ieee80211_is_data(hdr->frame_control) && an->ps_key > 0)
+ fi->keyix = an->ps_key;
else
fi->keyix = ATH9K_TXKEYIX_INVALID;
fi->keytype = keytype;
@@ -1491,7 +1570,6 @@ static int setup_tx_flags(struct sk_buff *skb)
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
int flags = 0;
- flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */
flags |= ATH9K_TXDESC_INTREQ;
if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
@@ -1585,8 +1663,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
rix = rates[i].idx;
series[i].Tries = rates[i].count;
- if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) ||
- (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) {
+ if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
flags |= ATH9K_TXDESC_RTSENA;
} else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
@@ -1655,8 +1732,6 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
!is_pspoll, ctsrate,
0, series, 4, flags);
- if (sc->config.ath_aggr_prot && flags)
- ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192);
}
static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
@@ -1754,6 +1829,9 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
if (txctl->paprd)
bf->bf_state.bfs_paprd_timestamp = jiffies;
+ if (tx_info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
+ ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, true);
+
ath_tx_send_normal(sc, txctl->txq, tid, &bf_head);
}
@@ -1767,6 +1845,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_sta *sta = info->control.sta;
+ struct ieee80211_vif *vif = info->control.vif;
struct ath_softc *sc = hw->priv;
struct ath_txq *txq = txctl->txq;
struct ath_buf *bf;
@@ -1804,6 +1883,11 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
memmove(skb->data, skb->data + padsize, padpos);
}
+ if ((vif && vif->type != NL80211_IFTYPE_AP &&
+ vif->type != NL80211_IFTYPE_AP_VLAN) ||
+ !ieee80211_is_data(hdr->frame_control))
+ info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
+
setup_frame_info(hw, skb, frmlen);
/*
@@ -1980,7 +2064,7 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
if (ieee80211_is_data(hdr->frame_control) &&
(ts->ts_flags & (ATH9K_TX_DATA_UNDERRUN |
ATH9K_TX_DELIM_UNDERRUN)) &&
- ah->tx_trig_level >= sc->sc_ah->caps.tx_triglevel_max)
+ ah->tx_trig_level >= sc->sc_ah->config.max_txtrig_level)
tx_info->status.rates[tx_rateindex].count =
hw->max_rate_tries;
}
@@ -2099,28 +2183,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
}
}
-static void ath_hw_pll_work(struct work_struct *work)
-{
- struct ath_softc *sc = container_of(work, struct ath_softc,
- hw_pll_work.work);
- static int count;
-
- if (AR_SREV_9485(sc->sc_ah)) {
- if (ar9003_get_pll_sqsum_dvc(sc->sc_ah) >= 0x40000) {
- count++;
-
- if (count == 3) {
- /* Rx is hung for more than 500ms. Reset it */
- ath_reset(sc, true);
- count = 0;
- }
- } else
- count = 0;
-
- ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5);
- }
-}
-
static void ath_tx_complete_poll_work(struct work_struct *work)
{
struct ath_softc *sc = container_of(work, struct ath_softc,
@@ -2144,33 +2206,6 @@ static void ath_tx_complete_poll_work(struct work_struct *work)
} else {
txq->axq_tx_inprogress = true;
}
- } else {
- /* If the queue has pending buffers, then it
- * should be doing tx work (and have axq_depth).
- * Shouldn't get to this state I think..but
- * we do.
- */
- if (!(sc->sc_flags & (SC_OP_OFFCHANNEL)) &&
- (txq->pending_frames > 0 ||
- !list_empty(&txq->axq_acq) ||
- txq->stopped)) {
- ath_err(ath9k_hw_common(sc->sc_ah),
- "txq: %p axq_qnum: %u,"
- " mac80211_qnum: %i"
- " axq_link: %p"
- " pending frames: %i"
- " axq_acq empty: %i"
- " stopped: %i"
- " axq_depth: 0 Attempting to"
- " restart tx logic.\n",
- txq, txq->axq_qnum,
- txq->mac80211_qnum,
- txq->axq_link,
- txq->pending_frames,
- list_empty(&txq->axq_acq),
- txq->stopped);
- ath_txq_schedule(sc, txq);
- }
}
spin_unlock_bh(&txq->axq_lock);
}
@@ -2342,7 +2377,6 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
}
INIT_DELAYED_WORK(&sc->tx_complete_work, ath_tx_complete_poll_work);
- INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
error = ath_tx_edma_init(sc);
diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h
index 3d4ed5863732..4da01a9f5680 100644
--- a/drivers/net/wireless/ath/carl9170/carl9170.h
+++ b/drivers/net/wireless/ath/carl9170/carl9170.h
@@ -286,6 +286,10 @@ struct ar9170 {
unsigned int tx_seq_table;
} fw;
+ /* interface configuration combinations */
+ struct ieee80211_iface_limit if_comb_limits[1];
+ struct ieee80211_iface_combination if_combs[1];
+
/* reset / stuck frames/queue detection */
struct work_struct restart_work;
struct work_struct ping_work;
@@ -448,6 +452,8 @@ struct carl9170_ba_stats {
struct carl9170_sta_info {
bool ht_sta;
+ bool sleeping;
+ atomic_t pending_frames;
unsigned int ampdu_max_len;
struct carl9170_sta_tid *agg[CARL9170_NUM_TID];
struct carl9170_ba_stats stats[CARL9170_NUM_TID];
diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c
index 9517ede9e2df..221957c5d373 100644
--- a/drivers/net/wireless/ath/carl9170/fw.c
+++ b/drivers/net/wireless/ath/carl9170/fw.c
@@ -151,6 +151,7 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
const struct carl9170fw_chk_desc *chk_desc;
const struct carl9170fw_last_desc *last_desc;
const struct carl9170fw_txsq_desc *txsq_desc;
+ u16 if_comb_types;
last_desc = carl9170_fw_find_desc(ar, LAST_MAGIC,
sizeof(*last_desc), CARL9170FW_LAST_DESC_CUR_VER);
@@ -268,6 +269,9 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
if (SUPP(CARL9170FW_WOL))
device_set_wakeup_enable(&ar->udev->dev, true);
+ if_comb_types = BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_P2P_CLIENT);
+
ar->fw.vif_num = otus_desc->vif_num;
ar->fw.cmd_bufs = otus_desc->cmd_bufs;
ar->fw.address = le32_to_cpu(otus_desc->fw_address);
@@ -294,12 +298,25 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
if (SUPP(CARL9170FW_WLANTX_CAB)) {
- ar->hw->wiphy->interface_modes |=
+ if_comb_types |=
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_GO);
}
}
+ ar->if_comb_limits[0].max = ar->fw.vif_num;
+ ar->if_comb_limits[0].types = if_comb_types;
+
+ ar->if_combs[0].num_different_channels = 1;
+ ar->if_combs[0].max_interfaces = ar->fw.vif_num;
+ ar->if_combs[0].limits = ar->if_comb_limits;
+ ar->if_combs[0].n_limits = ARRAY_SIZE(ar->if_comb_limits);
+
+ ar->hw->wiphy->iface_combinations = ar->if_combs;
+ ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ar->if_combs);
+
+ ar->hw->wiphy->interface_modes |= if_comb_types;
+
txsq_desc = carl9170_fw_find_desc(ar, TXSQ_MAGIC,
sizeof(*txsq_desc), CARL9170FW_TXSQ_DESC_CUR_VER);
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index 89fe60accf85..54d093c2ab44 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -883,7 +883,7 @@ static void carl9170_op_configure_filter(struct ieee80211_hw *hw,
* then checking the error flags, later.
*/
- if (changed_flags & FIF_ALLMULTI && *new_flags & FIF_ALLMULTI)
+ if (*new_flags & FIF_ALLMULTI)
multicast = ~0ULL;
if (multicast != ar->cur_mc_hash)
@@ -1193,6 +1193,8 @@ static int carl9170_op_sta_add(struct ieee80211_hw *hw,
struct carl9170_sta_info *sta_info = (void *) sta->drv_priv;
unsigned int i;
+ atomic_set(&sta_info->pending_frames, 0);
+
if (sta->ht_cap.ht_supported) {
if (sta->ht_cap.ampdu_density > 6) {
/*
@@ -1467,99 +1469,17 @@ static void carl9170_op_sta_notify(struct ieee80211_hw *hw,
enum sta_notify_cmd cmd,
struct ieee80211_sta *sta)
{
- struct ar9170 *ar = hw->priv;
struct carl9170_sta_info *sta_info = (void *) sta->drv_priv;
- struct sk_buff *skb, *tmp;
- struct sk_buff_head free;
- int i;
switch (cmd) {
case STA_NOTIFY_SLEEP:
- /*
- * Since the peer is no longer listening, we have to return
- * as many SKBs as possible back to the mac80211 stack.
- * It will deal with the retry procedure, once the peer
- * has become available again.
- *
- * NB: Ideally, the driver should return the all frames in
- * the correct, ascending order. However, I think that this
- * functionality should be implemented in the stack and not
- * here...
- */
-
- __skb_queue_head_init(&free);
-
- if (sta->ht_cap.ht_supported) {
- rcu_read_lock();
- for (i = 0; i < CARL9170_NUM_TID; i++) {
- struct carl9170_sta_tid *tid_info;
-
- tid_info = rcu_dereference(sta_info->agg[i]);
-
- if (!tid_info)
- continue;
-
- spin_lock_bh(&ar->tx_ampdu_list_lock);
- if (tid_info->state >
- CARL9170_TID_STATE_SUSPEND)
- tid_info->state =
- CARL9170_TID_STATE_SUSPEND;
- spin_unlock_bh(&ar->tx_ampdu_list_lock);
-
- spin_lock_bh(&tid_info->lock);
- while ((skb = __skb_dequeue(&tid_info->queue)))
- __skb_queue_tail(&free, skb);
- spin_unlock_bh(&tid_info->lock);
- }
- rcu_read_unlock();
- }
-
- for (i = 0; i < ar->hw->queues; i++) {
- spin_lock_bh(&ar->tx_pending[i].lock);
- skb_queue_walk_safe(&ar->tx_pending[i], skb, tmp) {
- struct _carl9170_tx_superframe *super;
- struct ieee80211_hdr *hdr;
- struct ieee80211_tx_info *info;
-
- super = (void *) skb->data;
- hdr = (void *) super->frame_data;
-
- if (compare_ether_addr(hdr->addr1, sta->addr))
- continue;
-
- __skb_unlink(skb, &ar->tx_pending[i]);
-
- info = IEEE80211_SKB_CB(skb);
- if (info->flags & IEEE80211_TX_CTL_AMPDU)
- atomic_dec(&ar->tx_ampdu_upload);
-
- carl9170_tx_status(ar, skb, false);
- }
- spin_unlock_bh(&ar->tx_pending[i].lock);
- }
-
- while ((skb = __skb_dequeue(&free)))
- carl9170_tx_status(ar, skb, false);
-
+ sta_info->sleeping = true;
+ if (atomic_read(&sta_info->pending_frames))
+ ieee80211_sta_block_awake(hw, sta, true);
break;
case STA_NOTIFY_AWAKE:
- if (!sta->ht_cap.ht_supported)
- return;
-
- rcu_read_lock();
- for (i = 0; i < CARL9170_NUM_TID; i++) {
- struct carl9170_sta_tid *tid_info;
-
- tid_info = rcu_dereference(sta_info->agg[i]);
-
- if (!tid_info)
- continue;
-
- if ((tid_info->state == CARL9170_TID_STATE_SUSPEND))
- tid_info->state = CARL9170_TID_STATE_IDLE;
- }
- rcu_read_unlock();
+ sta_info->sleeping = false;
break;
}
}
@@ -1650,14 +1570,8 @@ void *carl9170_alloc(size_t priv_size)
INIT_LIST_HEAD(&ar->vif_list);
init_completion(&ar->tx_flush);
- /*
- * Note:
- * IBSS/ADHOC and AP mode are only enabled, if the firmware
- * supports these modes. The code which will add the
- * additional interface_modes is in fw.c.
- */
- hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
- BIT(NL80211_IFTYPE_P2P_CLIENT);
+ /* firmware decides which modes we support */
+ hw->wiphy->interface_modes = 0;
hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS |
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c
index cb70ed7ec5cc..e94084fcf6f5 100644
--- a/drivers/net/wireless/ath/carl9170/tx.c
+++ b/drivers/net/wireless/ath/carl9170/tx.c
@@ -104,12 +104,60 @@ static void carl9170_tx_accounting(struct ar9170 *ar, struct sk_buff *skb)
spin_unlock_bh(&ar->tx_stats_lock);
}
+/* needs rcu_read_lock */
+static struct ieee80211_sta *__carl9170_get_tx_sta(struct ar9170 *ar,
+ struct sk_buff *skb)
+{
+ struct _carl9170_tx_superframe *super = (void *) skb->data;
+ struct ieee80211_hdr *hdr = (void *) super->frame_data;
+ struct ieee80211_vif *vif;
+ unsigned int vif_id;
+
+ vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >>
+ CARL9170_TX_SUPER_MISC_VIF_ID_S;
+
+ if (WARN_ON_ONCE(vif_id >= AR9170_MAX_VIRTUAL_MAC))
+ return NULL;
+
+ vif = rcu_dereference(ar->vif_priv[vif_id].vif);
+ if (unlikely(!vif))
+ return NULL;
+
+ /*
+ * Normally we should use wrappers like ieee80211_get_DA to get
+ * the correct peer ieee80211_sta.
+ *
+ * But there is a problem with indirect traffic (broadcasts, or
+ * data which is designated for other stations) in station mode.
+ * The frame will be directed to the AP for distribution and not
+ * to the actual destination.
+ */
+
+ return ieee80211_find_sta(vif, hdr->addr1);
+}
+
+static void carl9170_tx_ps_unblock(struct ar9170 *ar, struct sk_buff *skb)
+{
+ struct ieee80211_sta *sta;
+ struct carl9170_sta_info *sta_info;
+
+ rcu_read_lock();
+ sta = __carl9170_get_tx_sta(ar, skb);
+ if (unlikely(!sta))
+ goto out_rcu;
+
+ sta_info = (struct carl9170_sta_info *) sta->drv_priv;
+ if (atomic_dec_return(&sta_info->pending_frames) == 0)
+ ieee80211_sta_block_awake(ar->hw, sta, false);
+
+out_rcu:
+ rcu_read_unlock();
+}
+
static void carl9170_tx_accounting_free(struct ar9170 *ar, struct sk_buff *skb)
{
- struct ieee80211_tx_info *txinfo;
int queue;
- txinfo = IEEE80211_SKB_CB(skb);
queue = skb_get_queue_mapping(skb);
spin_lock_bh(&ar->tx_stats_lock);
@@ -135,6 +183,7 @@ static void carl9170_tx_accounting_free(struct ar9170 *ar, struct sk_buff *skb)
}
spin_unlock_bh(&ar->tx_stats_lock);
+
if (atomic_dec_and_test(&ar->tx_total_queued))
complete(&ar->tx_flush);
}
@@ -329,13 +378,9 @@ static void carl9170_tx_status_process_ampdu(struct ar9170 *ar,
{
struct _carl9170_tx_superframe *super = (void *) skb->data;
struct ieee80211_hdr *hdr = (void *) super->frame_data;
- struct ieee80211_tx_info *tx_info;
- struct carl9170_tx_info *ar_info;
- struct carl9170_sta_info *sta_info;
struct ieee80211_sta *sta;
+ struct carl9170_sta_info *sta_info;
struct carl9170_sta_tid *tid_info;
- struct ieee80211_vif *vif;
- unsigned int vif_id;
u8 tid;
if (!(txinfo->flags & IEEE80211_TX_CTL_AMPDU) ||
@@ -343,30 +388,8 @@ static void carl9170_tx_status_process_ampdu(struct ar9170 *ar,
(!(super->f.mac_control & cpu_to_le16(AR9170_TX_MAC_AGGR))))
return;
- tx_info = IEEE80211_SKB_CB(skb);
- ar_info = (void *) tx_info->rate_driver_data;
-
- vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >>
- CARL9170_TX_SUPER_MISC_VIF_ID_S;
-
- if (WARN_ON_ONCE(vif_id >= AR9170_MAX_VIRTUAL_MAC))
- return;
-
rcu_read_lock();
- vif = rcu_dereference(ar->vif_priv[vif_id].vif);
- if (unlikely(!vif))
- goto out_rcu;
-
- /*
- * Normally we should use wrappers like ieee80211_get_DA to get
- * the correct peer ieee80211_sta.
- *
- * But there is a problem with indirect traffic (broadcasts, or
- * data which is designated for other stations) in station mode.
- * The frame will be directed to the AP for distribution and not
- * to the actual destination.
- */
- sta = ieee80211_find_sta(vif, hdr->addr1);
+ sta = __carl9170_get_tx_sta(ar, skb);
if (unlikely(!sta))
goto out_rcu;
@@ -427,6 +450,7 @@ void carl9170_tx_status(struct ar9170 *ar, struct sk_buff *skb,
if (txinfo->flags & IEEE80211_TX_CTL_AMPDU)
carl9170_tx_status_process_ampdu(ar, skb, txinfo);
+ carl9170_tx_ps_unblock(ar, skb);
carl9170_tx_put_skb(skb);
}
@@ -540,11 +564,7 @@ static void carl9170_tx_ampdu_timeout(struct ar9170 *ar)
struct sk_buff *skb;
struct ieee80211_tx_info *txinfo;
struct carl9170_tx_info *arinfo;
- struct _carl9170_tx_superframe *super;
struct ieee80211_sta *sta;
- struct ieee80211_vif *vif;
- struct ieee80211_hdr *hdr;
- unsigned int vif_id;
rcu_read_lock();
list_for_each_entry_rcu(iter, &ar->tx_ampdu_list, list) {
@@ -562,20 +582,7 @@ static void carl9170_tx_ampdu_timeout(struct ar9170 *ar)
msecs_to_jiffies(CARL9170_QUEUE_TIMEOUT)))
goto unlock;
- super = (void *) skb->data;
- hdr = (void *) super->frame_data;
-
- vif_id = (super->s.misc & CARL9170_TX_SUPER_MISC_VIF_ID) >>
- CARL9170_TX_SUPER_MISC_VIF_ID_S;
-
- if (WARN_ON(vif_id >= AR9170_MAX_VIRTUAL_MAC))
- goto unlock;
-
- vif = rcu_dereference(ar->vif_priv[vif_id].vif);
- if (WARN_ON(!vif))
- goto unlock;
-
- sta = ieee80211_find_sta(vif, hdr->addr1);
+ sta = __carl9170_get_tx_sta(ar, skb);
if (WARN_ON(!sta))
goto unlock;
@@ -611,7 +618,6 @@ static void __carl9170_tx_process_status(struct ar9170 *ar,
{
struct sk_buff *skb;
struct ieee80211_tx_info *txinfo;
- struct carl9170_tx_info *arinfo;
unsigned int r, t, q;
bool success = true;
@@ -627,7 +633,6 @@ static void __carl9170_tx_process_status(struct ar9170 *ar,
}
txinfo = IEEE80211_SKB_CB(skb);
- arinfo = (void *) txinfo->rate_driver_data;
if (!(info & CARL9170_TX_STATUS_SUCCESS))
success = false;
@@ -1199,15 +1204,6 @@ static struct sk_buff *carl9170_tx_pick_skb(struct ar9170 *ar,
arinfo = (void *) info->rate_driver_data;
arinfo->timeout = jiffies;
-
- /*
- * increase ref count to "2".
- * Ref counting is the easiest way to solve the race between
- * the the urb's completion routine: carl9170_tx_callback and
- * wlan tx status functions: carl9170_tx_status/janitor.
- */
- carl9170_tx_get_skb(skb);
-
return skb;
err_unlock:
@@ -1228,6 +1224,36 @@ void carl9170_tx_drop(struct ar9170 *ar, struct sk_buff *skb)
__carl9170_tx_process_status(ar, super->s.cookie, q);
}
+static bool carl9170_tx_ps_drop(struct ar9170 *ar, struct sk_buff *skb)
+{
+ struct ieee80211_sta *sta;
+ struct carl9170_sta_info *sta_info;
+
+ rcu_read_lock();
+ sta = __carl9170_get_tx_sta(ar, skb);
+ if (!sta)
+ goto out_rcu;
+
+ sta_info = (void *) sta->drv_priv;
+ if (unlikely(sta_info->sleeping)) {
+ struct ieee80211_tx_info *tx_info;
+
+ rcu_read_unlock();
+
+ tx_info = IEEE80211_SKB_CB(skb);
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU)
+ atomic_dec(&ar->tx_ampdu_upload);
+
+ tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+ carl9170_tx_status(ar, skb, false);
+ return true;
+ }
+
+out_rcu:
+ rcu_read_unlock();
+ return false;
+}
+
static void carl9170_tx(struct ar9170 *ar)
{
struct sk_buff *skb;
@@ -1247,6 +1273,9 @@ static void carl9170_tx(struct ar9170 *ar)
if (unlikely(!skb))
break;
+ if (unlikely(carl9170_tx_ps_drop(ar, skb)))
+ continue;
+
atomic_inc(&ar->tx_total_pending);
q = __carl9170_get_queue(ar, i);
@@ -1256,6 +1285,16 @@ static void carl9170_tx(struct ar9170 *ar)
*/
skb_queue_tail(&ar->tx_status[q], skb);
+ /*
+ * increase ref count to "2".
+ * Ref counting is the easiest way to solve the
+ * race between the urb's completion routine:
+ * carl9170_tx_callback
+ * and wlan tx status functions:
+ * carl9170_tx_status/janitor.
+ */
+ carl9170_tx_get_skb(skb);
+
carl9170_usb_tx(ar, skb);
schedule_garbagecollector = true;
}
@@ -1275,7 +1314,6 @@ static bool carl9170_tx_ampdu_queue(struct ar9170 *ar,
struct carl9170_sta_info *sta_info;
struct carl9170_sta_tid *agg;
struct sk_buff *iter;
- unsigned int max;
u16 tid, seq, qseq, off;
bool run = false;
@@ -1285,7 +1323,6 @@ static bool carl9170_tx_ampdu_queue(struct ar9170 *ar,
rcu_read_lock();
agg = rcu_dereference(sta_info->agg[tid]);
- max = sta_info->ampdu_max_len;
if (!agg)
goto err_unlock_rcu;
@@ -1368,6 +1405,11 @@ void carl9170_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
* all ressouces which are associated with the frame.
*/
+ if (sta) {
+ struct carl9170_sta_info *stai = (void *) sta->drv_priv;
+ atomic_inc(&stai->pending_frames);
+ }
+
if (info->flags & IEEE80211_TX_CTL_AMPDU) {
run = carl9170_tx_ampdu_queue(ar, sta, skb);
if (run)
diff --git a/drivers/net/wireless/ath/hw.c b/drivers/net/wireless/ath/hw.c
index cc11d66f15bc..3f508e59f146 100644
--- a/drivers/net/wireless/ath/hw.c
+++ b/drivers/net/wireless/ath/hw.c
@@ -43,7 +43,7 @@
* set of ~ ( MAC XOR BSSID ) for all bssids we handle.
*
* When you do this you are essentially computing the common bits of all your
- * BSSes. Later it is assumed the harware will "and" (&) the BSSID mask with
+ * BSSes. Later it is assumed the hardware will "and" (&) the BSSID mask with
* the MAC address to obtain the relevant bits and compare the result with
* (frame's BSSID & mask) to see if they match.
*
@@ -71,8 +71,8 @@
* On loop iteration for BSSID-02:
* bssid_mask &= ~(0001 ^ 1001)
* bssid_mask = (1010) & ~(0001 ^ 1001)
- * bssid_mask = (1010) & ~(1001)
- * bssid_mask = (1010) & (0110)
+ * bssid_mask = (1010) & ~(1000)
+ * bssid_mask = (1010) & (0111)
* bssid_mask = 0010
*
* A bssid_mask of 0010 means "only pay attention to the second least
@@ -102,11 +102,9 @@
*
* IFRAME-02: 0001 (we should allow)
*
- * allow = (0001 & 1010) == 1010
- *
* allow = (IFRAME-02 & bssid_mask) == (bssid_mask & MAC) ? 1 : 0;
* --> allow = (0001 & 0010) == (0010 & 0001) ? 1 :0;
- * --> allow = (0010) == (0010)
+ * --> allow = (0000) == (0000)
* --> allow = 1
*
* Other examples:
diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c
index 37b8e115375a..a61ef3d6d89c 100644
--- a/drivers/net/wireless/ath/key.c
+++ b/drivers/net/wireless/ath/key.c
@@ -23,6 +23,14 @@
#define REG_READ (common->ops->read)
#define REG_WRITE(_ah, _reg, _val) (common->ops->write)(_ah, _val, _reg)
+#define ENABLE_REGWRITE_BUFFER(_ah) \
+ if (common->ops->enable_write_buffer) \
+ common->ops->enable_write_buffer((_ah));
+
+#define REGWRITE_BUFFER_FLUSH(_ah) \
+ if (common->ops->write_flush) \
+ common->ops->write_flush((_ah));
+
#define IEEE80211_WEP_NKID 4 /* number of key ids */
@@ -42,6 +50,8 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry)
keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry));
+ ENABLE_REGWRITE_BUFFER(ah);
+
REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0);
REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0);
REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0);
@@ -66,6 +76,8 @@ bool ath_hw_keyreset(struct ath_common *common, u16 entry)
}
+ REGWRITE_BUFFER_FLUSH(ah);
+
return true;
}
EXPORT_SYMBOL(ath_hw_keyreset);
@@ -104,9 +116,13 @@ static bool ath_hw_keysetmac(struct ath_common *common,
} else {
macLo = macHi = 0;
}
+ ENABLE_REGWRITE_BUFFER(ah);
+
REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo);
REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | unicast_flag);
+ REGWRITE_BUFFER_FLUSH(ah);
+
return true;
}
@@ -223,6 +239,8 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry,
mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff;
mic4 = get_unaligned_le32(k->kv_txmic + 4);
+ ENABLE_REGWRITE_BUFFER(ah);
+
/* Write RX[31:0] and TX[31:16] */
REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1);
@@ -236,6 +254,8 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry,
REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
AR_KEYTABLE_TYPE_CLR);
+ REGWRITE_BUFFER_FLUSH(ah);
+
} else {
/*
* TKIP uses four key cache entries (two for group
@@ -258,6 +278,8 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry,
mic0 = get_unaligned_le32(k->kv_mic + 0);
mic2 = get_unaligned_le32(k->kv_mic + 4);
+ ENABLE_REGWRITE_BUFFER(ah);
+
/* Write MIC key[31:0] */
REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
@@ -270,8 +292,12 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry,
REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0);
REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
AR_KEYTABLE_TYPE_CLR);
+
+ REGWRITE_BUFFER_FLUSH(ah);
}
+ ENABLE_REGWRITE_BUFFER(ah);
+
/* MAC address registers are reserved for the MIC entry */
REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0);
REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0);
@@ -283,7 +309,11 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry,
*/
REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
+
+ REGWRITE_BUFFER_FLUSH(ah);
} else {
+ ENABLE_REGWRITE_BUFFER(ah);
+
/* Write key[47:0] */
REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
@@ -296,6 +326,8 @@ static bool ath_hw_set_keycache_entry(struct ath_common *common, u16 entry,
REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
+ REGWRITE_BUFFER_FLUSH(ah);
+
/* Write MAC address for the entry */
(void) ath_hw_keysetmac(common, entry, mac);
}
@@ -451,6 +483,9 @@ int ath_key_config(struct ath_common *common,
memset(&hk, 0, sizeof(hk));
switch (key->cipher) {
+ case 0:
+ hk.kv_type = ATH_CIPHER_CLR;
+ break;
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
hk.kv_type = ATH_CIPHER_WEP;
@@ -466,7 +501,8 @@ int ath_key_config(struct ath_common *common,
}
hk.kv_len = key->keylen;
- memcpy(hk.kv_val, key->key, key->keylen);
+ if (key->keylen)
+ memcpy(hk.kv_val, key->key, key->keylen);
if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
switch (vif->type) {
diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c
index 0e1b8793c864..028310f263c8 100644
--- a/drivers/net/wireless/ath/regd.c
+++ b/drivers/net/wireless/ath/regd.c
@@ -97,8 +97,8 @@ static const struct ieee80211_regdomain ath_world_regdom_66_69 = {
}
};
-/* Can be used by 0x67, 0x6A and 0x68 */
-static const struct ieee80211_regdomain ath_world_regdom_67_68_6A = {
+/* Can be used by 0x67, 0x68, 0x6A and 0x6C */
+static const struct ieee80211_regdomain ath_world_regdom_67_68_6A_6C = {
.n_reg_rules = 4,
.alpha2 = "99",
.reg_rules = {
@@ -151,7 +151,8 @@ ieee80211_regdomain *ath_world_regdomain(struct ath_regulatory *reg)
case 0x67:
case 0x68:
case 0x6A:
- return &ath_world_regdom_67_68_6A;
+ case 0x6C:
+ return &ath_world_regdom_67_68_6A_6C;
default:
WARN_ON(1);
return ath_default_world_regdomain();
@@ -333,6 +334,7 @@ static void ath_reg_apply_world_flags(struct wiphy *wiphy,
case 0x63:
case 0x66:
case 0x67:
+ case 0x6C:
ath_reg_apply_beaconing_flags(wiphy, initiator);
break;
case 0x68:
diff --git a/drivers/net/wireless/ath/regd_common.h b/drivers/net/wireless/ath/regd_common.h
index 5c2cfe694152..24b53839fc3a 100644
--- a/drivers/net/wireless/ath/regd_common.h
+++ b/drivers/net/wireless/ath/regd_common.h
@@ -86,6 +86,7 @@ enum EnumRd {
WOR9_WORLD = 0x69,
WORA_WORLD = 0x6A,
WORB_WORLD = 0x6B,
+ WORC_WORLD = 0x6C,
MKK3_MKKB = 0x80,
MKK3_MKKA2 = 0x81,
@@ -282,6 +283,7 @@ static struct reg_dmn_pair_mapping regDomainPairs[] = {
{WOR9_WORLD, NO_CTL, NO_CTL},
{WORA_WORLD, NO_CTL, NO_CTL},
{WORB_WORLD, NO_CTL, NO_CTL},
+ {WORC_WORLD, NO_CTL, NO_CTL},
};
static struct country_code_to_enum_rd allCountries[] = {
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c
index 05263516c113..ec295c4f677d 100644
--- a/drivers/net/wireless/atmel_cs.c
+++ b/drivers/net/wireless/atmel_cs.c
@@ -122,7 +122,7 @@ static int atmel_config(struct pcmcia_device *link)
{
local_info_t *dev;
int ret;
- struct pcmcia_device_id *did;
+ const struct pcmcia_device_id *did;
dev = link->priv;
did = dev_get_drvdata(&link->dev);
@@ -211,7 +211,7 @@ static int atmel_resume(struct pcmcia_device *link)
.prod_id_hash = { (vh1), (vh2), 0, 0 }, \
.driver_info = (kernel_ulong_t)(info), }
-static struct pcmcia_device_id atmel_ids[] = {
+static const struct pcmcia_device_id atmel_ids[] = {
PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0620, ATMEL_FW_TYPE_502_3COM),
PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0696, ATMEL_FW_TYPE_502_3COM),
PCMCIA_DEVICE_MANF_CARD_INFO(0x01bf, 0x3302, ATMEL_FW_TYPE_502E),
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 229f4388f790..25a78cfb7d15 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -567,6 +567,8 @@ struct b43_dma {
struct b43_dmaring *tx_ring_mcast; /* Multicast */
struct b43_dmaring *rx_ring;
+
+ u32 translation; /* Routing bits */
};
struct b43_pio_txqueue;
@@ -648,8 +650,8 @@ struct b43_request_fw_context {
char errors[B43_NR_FWTYPES][128];
/* Temporary buffer for storing the firmware name. */
char fwname[64];
- /* A fatal error occurred while requesting. Firmware reqest
- * can not continue, as any other reqest will also fail. */
+ /* A fatal error occurred while requesting. Firmware request
+ * can not continue, as any other request will also fail. */
int fatal_failure;
};
@@ -705,7 +707,7 @@ enum {
/* Data structure for one wireless device (802.11 core) */
struct b43_wldev {
- struct ssb_device *dev;
+ struct ssb_device *sdev;
struct b43_wl *wl;
/* The device initialization status.
@@ -879,22 +881,34 @@ static inline enum ieee80211_band b43_current_band(struct b43_wl *wl)
static inline u16 b43_read16(struct b43_wldev *dev, u16 offset)
{
- return ssb_read16(dev->dev, offset);
+ return ssb_read16(dev->sdev, offset);
}
static inline void b43_write16(struct b43_wldev *dev, u16 offset, u16 value)
{
- ssb_write16(dev->dev, offset, value);
+ ssb_write16(dev->sdev, offset, value);
}
static inline u32 b43_read32(struct b43_wldev *dev, u16 offset)
{
- return ssb_read32(dev->dev, offset);
+ return ssb_read32(dev->sdev, offset);
}
static inline void b43_write32(struct b43_wldev *dev, u16 offset, u32 value)
{
- ssb_write32(dev->dev, offset, value);
+ ssb_write32(dev->sdev, offset, value);
+}
+
+static inline void b43_block_read(struct b43_wldev *dev, void *buffer,
+ size_t count, u16 offset, u8 reg_width)
+{
+ ssb_block_read(dev->sdev, buffer, count, offset, reg_width);
+}
+
+static inline void b43_block_write(struct b43_wldev *dev, const void *buffer,
+ size_t count, u16 offset, u8 reg_width)
+{
+ ssb_block_write(dev->sdev, buffer, count, offset, reg_width);
}
static inline bool b43_using_pio_transfers(struct b43_wldev *dev)
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index ff0f5ba14b2c..47d44bcff37d 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -80,7 +80,7 @@ static void op32_fill_descriptor(struct b43_dmaring *ring,
addr = (u32) (dmaaddr & ~SSB_DMA_TRANSLATION_MASK);
addrext = (u32) (dmaaddr & SSB_DMA_TRANSLATION_MASK)
>> SSB_DMA_TRANSLATION_SHIFT;
- addr |= ssb_dma_translation(ring->dev->dev);
+ addr |= ring->dev->dma.translation;
ctl = bufsize & B43_DMA32_DCTL_BYTECNT;
if (slot == ring->nr_slots - 1)
ctl |= B43_DMA32_DCTL_DTABLEEND;
@@ -174,7 +174,7 @@ static void op64_fill_descriptor(struct b43_dmaring *ring,
addrhi = (((u64) dmaaddr >> 32) & ~SSB_DMA_TRANSLATION_MASK);
addrext = (((u64) dmaaddr >> 32) & SSB_DMA_TRANSLATION_MASK)
>> SSB_DMA_TRANSLATION_SHIFT;
- addrhi |= (ssb_dma_translation(ring->dev->dev) << 1);
+ addrhi |= (ring->dev->dma.translation << 1);
if (slot == ring->nr_slots - 1)
ctl0 |= B43_DMA64_DCTL0_DTABLEEND;
if (start)
@@ -333,10 +333,10 @@ static inline
dma_addr_t dmaaddr;
if (tx) {
- dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
+ dmaaddr = dma_map_single(ring->dev->sdev->dma_dev,
buf, len, DMA_TO_DEVICE);
} else {
- dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
+ dmaaddr = dma_map_single(ring->dev->sdev->dma_dev,
buf, len, DMA_FROM_DEVICE);
}
@@ -348,10 +348,10 @@ static inline
dma_addr_t addr, size_t len, int tx)
{
if (tx) {
- dma_unmap_single(ring->dev->dev->dma_dev,
+ dma_unmap_single(ring->dev->sdev->dma_dev,
addr, len, DMA_TO_DEVICE);
} else {
- dma_unmap_single(ring->dev->dev->dma_dev,
+ dma_unmap_single(ring->dev->sdev->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);
- dma_sync_single_for_cpu(ring->dev->dev->dma_dev,
+ dma_sync_single_for_cpu(ring->dev->sdev->dma_dev,
addr, len, DMA_FROM_DEVICE);
}
@@ -370,7 +370,7 @@ static inline
dma_addr_t addr, size_t len)
{
B43_WARN_ON(ring->tx);
- dma_sync_single_for_device(ring->dev->dev->dma_dev,
+ dma_sync_single_for_device(ring->dev->sdev->dma_dev,
addr, len, DMA_FROM_DEVICE);
}
@@ -401,7 +401,7 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
*/
if (ring->type == B43_DMA_64BIT)
flags |= GFP_DMA;
- ring->descbase = dma_alloc_coherent(ring->dev->dev->dma_dev,
+ ring->descbase = dma_alloc_coherent(ring->dev->sdev->dma_dev,
B43_DMA_RINGMEMSIZE,
&(ring->dmabase), flags);
if (!ring->descbase) {
@@ -415,7 +415,7 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
static void free_ringmemory(struct b43_dmaring *ring)
{
- dma_free_coherent(ring->dev->dev->dma_dev, B43_DMA_RINGMEMSIZE,
+ dma_free_coherent(ring->dev->sdev->dma_dev, B43_DMA_RINGMEMSIZE,
ring->descbase, ring->dmabase);
}
@@ -523,7 +523,7 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring,
dma_addr_t addr,
size_t buffersize, bool dma_to_device)
{
- if (unlikely(dma_mapping_error(ring->dev->dev->dma_dev, addr)))
+ if (unlikely(dma_mapping_error(ring->dev->sdev->dma_dev, addr)))
return 1;
switch (ring->type) {
@@ -658,7 +658,7 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
int err = 0;
u32 value;
u32 addrext;
- u32 trans = ssb_dma_translation(ring->dev->dev);
+ u32 trans = ring->dev->dma.translation;
if (ring->tx) {
if (ring->type == B43_DMA_64BIT) {
@@ -869,7 +869,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
goto err_kfree_meta;
/* test for ability to dma to txhdr_cache */
- dma_test = dma_map_single(dev->dev->dma_dev,
+ dma_test = dma_map_single(dev->sdev->dma_dev,
ring->txhdr_cache,
b43_txhdr_size(dev),
DMA_TO_DEVICE);
@@ -884,7 +884,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
if (!ring->txhdr_cache)
goto err_kfree_meta;
- dma_test = dma_map_single(dev->dev->dma_dev,
+ dma_test = dma_map_single(dev->sdev->dma_dev,
ring->txhdr_cache,
b43_txhdr_size(dev),
DMA_TO_DEVICE);
@@ -898,7 +898,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
}
}
- dma_unmap_single(dev->dev->dma_dev,
+ dma_unmap_single(dev->sdev->dma_dev,
dma_test, b43_txhdr_size(dev),
DMA_TO_DEVICE);
}
@@ -1013,9 +1013,9 @@ 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 = dma_set_mask(dev->dev->dma_dev, mask);
+ err = dma_set_mask(dev->sdev->dma_dev, mask);
if (!err) {
- err = dma_set_coherent_mask(dev->dev->dma_dev, mask);
+ err = dma_set_coherent_mask(dev->sdev->dma_dev, mask);
if (!err)
break;
}
@@ -1055,6 +1055,7 @@ int b43_dma_init(struct b43_wldev *dev)
err = b43_dma_set_mask(dev, dmamask);
if (err)
return err;
+ dma->translation = ssb_dma_translation(dev->sdev);
err = -ENOMEM;
/* setup TX DMA channels. */
@@ -1084,7 +1085,7 @@ int b43_dma_init(struct b43_wldev *dev)
goto err_destroy_mcast;
/* No support for the TX status DMA ring. */
- B43_WARN_ON(dev->dev->id.revision < 5);
+ B43_WARN_ON(dev->sdev->id.revision < 5);
b43dbg(dev->wl, "%u-bit DMA initialized\n",
(unsigned int)type);
diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c
index c587115dd2b9..0cafafe368af 100644
--- a/drivers/net/wireless/b43/leds.c
+++ b/drivers/net/wireless/b43/leds.c
@@ -138,7 +138,7 @@ static int b43_register_led(struct b43_wldev *dev, struct b43_led *led,
led->led_dev.default_trigger = default_trigger;
led->led_dev.brightness_set = b43_led_brightness_set;
- err = led_classdev_register(dev->dev->dev, &led->led_dev);
+ err = led_classdev_register(dev->sdev->dev, &led->led_dev);
if (err) {
b43warn(dev->wl, "LEDs: Failed to register %s\n", name);
led->wl = NULL;
@@ -215,7 +215,7 @@ static void b43_led_get_sprominfo(struct b43_wldev *dev,
enum b43_led_behaviour *behaviour,
bool *activelow)
{
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
u8 sprom[4];
sprom[0] = bus->sprom.gpio0;
diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c
index 94e4f1378fc3..2ef7d4b38540 100644
--- a/drivers/net/wireless/b43/lo.c
+++ b/drivers/net/wireless/b43/lo.c
@@ -98,7 +98,7 @@ static u16 lo_measure_feedthrough(struct b43_wldev *dev,
rfover |= pga;
rfover |= lna;
rfover |= trsw_rx;
- if ((dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA)
+ if ((dev->sdev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA)
&& phy->rev > 6)
rfover |= B43_PHY_RFOVERVAL_EXTLNA;
@@ -387,7 +387,7 @@ struct lo_g_saved_values {
static void lo_measure_setup(struct b43_wldev *dev,
struct lo_g_saved_values *sav)
{
- struct ssb_sprom *sprom = &dev->dev->bus->sprom;
+ struct ssb_sprom *sprom = &dev->sdev->bus->sprom;
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = phy->g;
struct b43_txpower_lo_control *lo = gphy->lo_control;
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 5af40d9170a0..eb4159686985 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -548,7 +548,7 @@ void b43_tsf_read(struct b43_wldev *dev, u64 *tsf)
{
u32 low, high;
- B43_WARN_ON(dev->dev->id.revision < 3);
+ B43_WARN_ON(dev->sdev->id.revision < 3);
/* The hardware guarantees us an atomic read, if we
* read the low register first. */
@@ -586,7 +586,7 @@ static void b43_tsf_write_locked(struct b43_wldev *dev, u64 tsf)
{
u32 low, high;
- B43_WARN_ON(dev->dev->id.revision < 3);
+ B43_WARN_ON(dev->sdev->id.revision < 3);
low = tsf;
high = (tsf >> 32);
@@ -714,7 +714,7 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on)
b43_ram_write(dev, i * 4, buffer[i]);
b43_write16(dev, 0x0568, 0x0000);
- if (dev->dev->id.revision < 11)
+ if (dev->sdev->id.revision < 11)
b43_write16(dev, 0x07C0, 0x0000);
else
b43_write16(dev, 0x07C0, 0x0100);
@@ -1132,7 +1132,7 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
b43_write32(dev, B43_MMIO_MACCTL, macctl);
/* Commit write */
b43_read32(dev, B43_MMIO_MACCTL);
- if (awake && dev->dev->id.revision >= 5) {
+ if (awake && dev->sdev->id.revision >= 5) {
/* Wait for the microcode to wake up. */
for (i = 0; i < 100; i++) {
ucstat = b43_shm_read16(dev, B43_SHM_SHARED,
@@ -1144,29 +1144,35 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
}
}
-void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags)
+static void b43_ssb_wireless_core_reset(struct b43_wldev *dev, u32 flags)
{
u32 tmslow;
- u32 macctl;
flags |= B43_TMSLOW_PHYCLKEN;
flags |= B43_TMSLOW_PHYRESET;
if (dev->phy.type == B43_PHYTYPE_N)
flags |= B43_TMSLOW_PHY_BANDWIDTH_20MHZ; /* Make 20 MHz def */
- ssb_device_enable(dev->dev, flags);
+ ssb_device_enable(dev->sdev, flags);
msleep(2); /* Wait for the PLL to turn on. */
/* Now take the PHY out of Reset again */
- tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
+ tmslow = ssb_read32(dev->sdev, SSB_TMSLOW);
tmslow |= SSB_TMSLOW_FGC;
tmslow &= ~B43_TMSLOW_PHYRESET;
- ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
- ssb_read32(dev->dev, SSB_TMSLOW); /* flush */
+ ssb_write32(dev->sdev, SSB_TMSLOW, tmslow);
+ ssb_read32(dev->sdev, SSB_TMSLOW); /* flush */
msleep(1);
tmslow &= ~SSB_TMSLOW_FGC;
- ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
- ssb_read32(dev->dev, SSB_TMSLOW); /* flush */
+ ssb_write32(dev->sdev, SSB_TMSLOW, tmslow);
+ ssb_read32(dev->sdev, SSB_TMSLOW); /* flush */
msleep(1);
+}
+
+void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags)
+{
+ u32 macctl;
+
+ b43_ssb_wireless_core_reset(dev, flags);
/* Turn Analog ON, but only if we already know the PHY-type.
* This protects against very early setup where we don't know the
@@ -1215,7 +1221,7 @@ static void drain_txstatus_queue(struct b43_wldev *dev)
{
u32 dummy;
- if (dev->dev->id.revision < 5)
+ if (dev->sdev->id.revision < 5)
return;
/* Read all entries from the microcode TXstatus FIFO
* and throw them away.
@@ -1421,9 +1427,9 @@ u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev,
/* Get the mask of available antennas. */
if (dev->phy.gmode)
- antenna_mask = dev->dev->bus->sprom.ant_available_bg;
+ antenna_mask = dev->sdev->bus->sprom.ant_available_bg;
else
- antenna_mask = dev->dev->bus->sprom.ant_available_a;
+ antenna_mask = dev->sdev->bus->sprom.ant_available_a;
if (!(antenna_mask & (1 << (antenna_nr - 1)))) {
/* This antenna is not available. Fall back to default. */
@@ -1638,7 +1644,7 @@ static void b43_beacon_update_trigger_work(struct work_struct *work)
mutex_lock(&wl->mutex);
dev = wl->current_dev;
if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) {
- if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
+ if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) {
/* wl->mutex is enough. */
b43_do_beacon_update_trigger_work(dev);
mmiowb();
@@ -1683,7 +1689,7 @@ static void b43_update_templates(struct b43_wl *wl)
static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
{
b43_time_lock(dev);
- if (dev->dev->id.revision >= 3) {
+ if (dev->sdev->id.revision >= 3) {
b43_write32(dev, B43_MMIO_TSF_CFP_REP, (beacon_int << 16));
b43_write32(dev, B43_MMIO_TSF_CFP_START, (beacon_int << 10));
} else {
@@ -2057,7 +2063,7 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx,
B43_WARN_ON(1);
return -ENOSYS;
}
- err = request_firmware(&blob, ctx->fwname, ctx->dev->dev->dev);
+ err = request_firmware(&blob, ctx->fwname, ctx->dev->sdev->dev);
if (err == -ENOENT) {
snprintf(ctx->errors[ctx->req_type],
sizeof(ctx->errors[ctx->req_type]),
@@ -2107,13 +2113,12 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
{
struct b43_wldev *dev = ctx->dev;
struct b43_firmware *fw = &ctx->dev->fw;
- const u8 rev = ctx->dev->dev->id.revision;
+ const u8 rev = ctx->dev->sdev->id.revision;
const char *filename;
u32 tmshigh;
int err;
/* Get microcode */
- tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
if ((rev >= 5) && (rev <= 10))
filename = "ucode5";
else if ((rev >= 11) && (rev <= 12))
@@ -2152,6 +2157,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
switch (dev->phy.type) {
case B43_PHYTYPE_A:
if ((rev >= 5) && (rev <= 10)) {
+ tmshigh = ssb_read32(dev->sdev, SSB_TMSHIGH);
if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
filename = "a0g1initvals5";
else
@@ -2196,6 +2202,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
switch (dev->phy.type) {
case B43_PHYTYPE_A:
if ((rev >= 5) && (rev <= 10)) {
+ tmshigh = ssb_read32(dev->sdev, SSB_TMSHIGH);
if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
filename = "a0g1bsinitvals5";
else
@@ -2441,7 +2448,7 @@ static int b43_upload_microcode(struct b43_wldev *dev)
snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "%u.%u",
dev->fw.rev, dev->fw.patch);
- wiphy->hw_version = dev->dev->id.coreid;
+ wiphy->hw_version = dev->sdev->id.coreid;
if (b43_is_old_txhdr_format(dev)) {
/* We're over the deadline, but we keep support for old fw
@@ -2557,10 +2564,20 @@ out:
/* Initialize the GPIOs
* http://bcm-specs.sipsolutions.net/GPIO
*/
+static struct ssb_device *b43_ssb_gpio_dev(struct b43_wldev *dev)
+{
+ struct ssb_bus *bus = dev->sdev->bus;
+
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+ return (bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev);
+#else
+ return bus->chipco.dev;
+#endif
+}
+
static int b43_gpio_init(struct b43_wldev *dev)
{
- struct ssb_bus *bus = dev->dev->bus;
- struct ssb_device *gpiodev, *pcidev = NULL;
+ struct ssb_device *gpiodev;
u32 mask, set;
b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
@@ -2571,7 +2588,7 @@ static int b43_gpio_init(struct b43_wldev *dev)
mask = 0x0000001F;
set = 0x0000000F;
- if (dev->dev->bus->chip_id == 0x4301) {
+ if (dev->sdev->bus->chip_id == 0x4301) {
mask |= 0x0060;
set |= 0x0060;
}
@@ -2582,25 +2599,21 @@ static int b43_gpio_init(struct b43_wldev *dev)
mask |= 0x0180;
set |= 0x0180;
}
- if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) {
+ if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) {
b43_write16(dev, B43_MMIO_GPIO_MASK,
b43_read16(dev, B43_MMIO_GPIO_MASK)
| 0x0200);
mask |= 0x0200;
set |= 0x0200;
}
- if (dev->dev->id.revision >= 2)
+ if (dev->sdev->id.revision >= 2)
mask |= 0x0010; /* FIXME: This is redundant. */
-#ifdef CONFIG_SSB_DRIVER_PCICORE
- pcidev = bus->pcicore.dev;
-#endif
- gpiodev = bus->chipco.dev ? : pcidev;
- if (!gpiodev)
- return 0;
- ssb_write32(gpiodev, B43_GPIO_CONTROL,
- (ssb_read32(gpiodev, B43_GPIO_CONTROL)
- & mask) | set);
+ gpiodev = b43_ssb_gpio_dev(dev);
+ if (gpiodev)
+ ssb_write32(gpiodev, B43_GPIO_CONTROL,
+ (ssb_read32(gpiodev, B43_GPIO_CONTROL)
+ & mask) | set);
return 0;
}
@@ -2608,16 +2621,11 @@ static int b43_gpio_init(struct b43_wldev *dev)
/* Turn off all GPIO stuff. Call this on module unload, for example. */
static void b43_gpio_cleanup(struct b43_wldev *dev)
{
- struct ssb_bus *bus = dev->dev->bus;
- struct ssb_device *gpiodev, *pcidev = NULL;
+ struct ssb_device *gpiodev;
-#ifdef CONFIG_SSB_DRIVER_PCICORE
- pcidev = bus->pcicore.dev;
-#endif
- gpiodev = bus->chipco.dev ? : pcidev;
- if (!gpiodev)
- return;
- ssb_write32(gpiodev, B43_GPIO_CONTROL, 0);
+ gpiodev = b43_ssb_gpio_dev(dev);
+ if (gpiodev)
+ ssb_write32(gpiodev, B43_GPIO_CONTROL, 0);
}
/* http://bcm-specs.sipsolutions.net/EnableMac */
@@ -2686,6 +2694,17 @@ out:
dev->mac_suspended++;
}
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MacPhyClkSet */
+void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on)
+{
+ u32 tmslow = ssb_read32(dev->sdev, SSB_TMSLOW);
+ if (on)
+ tmslow |= B43_TMSLOW_MACPHYCLKEN;
+ else
+ tmslow &= ~B43_TMSLOW_MACPHYCLKEN;
+ ssb_write32(dev->sdev, SSB_TMSLOW, tmslow);
+}
+
static void b43_adjust_opmode(struct b43_wldev *dev)
{
struct b43_wl *wl = dev->wl;
@@ -2722,15 +2741,15 @@ static void b43_adjust_opmode(struct b43_wldev *dev)
/* Workaround: On old hardware the HW-MAC-address-filter
* doesn't work properly, so always run promisc in filter
* it in software. */
- if (dev->dev->id.revision <= 4)
+ if (dev->sdev->id.revision <= 4)
ctl |= B43_MACCTL_PROMISC;
b43_write32(dev, B43_MMIO_MACCTL, ctl);
cfp_pretbtt = 2;
if ((ctl & B43_MACCTL_INFRA) && !(ctl & B43_MACCTL_AP)) {
- if (dev->dev->bus->chip_id == 0x4306 &&
- dev->dev->bus->chip_rev == 3)
+ if (dev->sdev->bus->chip_id == 0x4306 &&
+ dev->sdev->bus->chip_rev == 3)
cfp_pretbtt = 100;
else
cfp_pretbtt = 50;
@@ -2842,7 +2861,7 @@ static int b43_chip_init(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
int err;
- u32 value32, macctl;
+ u32 macctl;
u16 value16;
/* Initialize the MAC control */
@@ -2888,7 +2907,7 @@ static int b43_chip_init(struct b43_wldev *dev)
b43_write16(dev, 0x005E, value16);
}
b43_write32(dev, 0x0100, 0x01000000);
- if (dev->dev->id.revision < 5)
+ if (dev->sdev->id.revision < 5)
b43_write32(dev, 0x010C, 0x01000000);
b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
@@ -2903,7 +2922,7 @@ static int b43_chip_init(struct b43_wldev *dev)
/* Initially set the wireless operation mode. */
b43_adjust_opmode(dev);
- if (dev->dev->id.revision < 3) {
+ if (dev->sdev->id.revision < 3) {
b43_write16(dev, 0x060E, 0x0000);
b43_write16(dev, 0x0610, 0x8000);
b43_write16(dev, 0x0604, 0x0000);
@@ -2920,12 +2939,10 @@ static int b43_chip_init(struct b43_wldev *dev)
b43_write32(dev, B43_MMIO_DMA4_IRQ_MASK, 0x0000DC00);
b43_write32(dev, B43_MMIO_DMA5_IRQ_MASK, 0x0000DC00);
- value32 = ssb_read32(dev->dev, SSB_TMSLOW);
- value32 |= 0x00100000;
- ssb_write32(dev->dev, SSB_TMSLOW, value32);
+ b43_mac_phy_clock_set(dev, true);
b43_write16(dev, B43_MMIO_POWERUP_DELAY,
- dev->dev->bus->chipco.fast_pwrup_delay);
+ dev->sdev->bus->chipco.fast_pwrup_delay);
err = 0;
b43dbg(dev->wl, "Chip initialized\n");
@@ -3088,7 +3105,7 @@ static int b43_validate_chipaccess(struct b43_wldev *dev)
b43_shm_write32(dev, B43_SHM_SHARED, 0, backup0);
b43_shm_write32(dev, B43_SHM_SHARED, 4, backup4);
- if ((dev->dev->id.revision >= 3) && (dev->dev->id.revision <= 10)) {
+ if ((dev->sdev->id.revision >= 3) && (dev->sdev->id.revision <= 10)) {
/* The 32bit register shadows the two 16bit registers
* with update sideeffects. Validate this. */
b43_write16(dev, B43_MMIO_TSF_CFP_START, 0xAAAA);
@@ -3441,7 +3458,7 @@ static void b43_op_set_tsf(struct ieee80211_hw *hw, u64 tsf)
static void b43_put_phy_into_reset(struct b43_wldev *dev)
{
- struct ssb_device *sdev = dev->dev;
+ struct ssb_device *sdev = dev->sdev;
u32 tmslow;
tmslow = ssb_read32(sdev, SSB_TMSLOW);
@@ -3937,7 +3954,7 @@ redo:
/* Disable interrupts on the device. */
b43_set_status(dev, B43_STAT_INITIALIZED);
- if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
+ if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) {
/* wl->mutex is locked. That is enough. */
b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */
@@ -3950,11 +3967,11 @@ redo:
/* Synchronize and free the interrupt handlers. Unlock to avoid deadlocks. */
orig_dev = dev;
mutex_unlock(&wl->mutex);
- if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
+ if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) {
b43_sdio_free_irq(dev);
} else {
- synchronize_irq(dev->dev->irq);
- free_irq(dev->dev->irq, dev);
+ synchronize_irq(dev->sdev->irq);
+ free_irq(dev->sdev->irq, dev);
}
mutex_lock(&wl->mutex);
dev = wl->current_dev;
@@ -3987,18 +4004,19 @@ static int b43_wireless_core_start(struct b43_wldev *dev)
B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED);
drain_txstatus_queue(dev);
- if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
+ if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) {
err = b43_sdio_request_irq(dev, b43_sdio_interrupt_handler);
if (err) {
b43err(dev->wl, "Cannot request SDIO IRQ\n");
goto out;
}
} else {
- err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler,
+ err = request_threaded_irq(dev->sdev->irq, b43_interrupt_handler,
b43_interrupt_thread_handler,
IRQF_SHARED, KBUILD_MODNAME, dev);
if (err) {
- b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq);
+ b43err(dev->wl, "Cannot request IRQ-%d\n",
+ dev->sdev->irq);
goto out;
}
}
@@ -4078,10 +4096,10 @@ static int b43_phy_versioning(struct b43_wldev *dev)
analog_type, phy_type, phy_rev);
/* Get RADIO versioning */
- if (dev->dev->bus->chip_id == 0x4317) {
- if (dev->dev->bus->chip_rev == 0)
+ if (dev->sdev->bus->chip_id == 0x4317) {
+ if (dev->sdev->bus->chip_rev == 0)
tmp = 0x3205017F;
- else if (dev->dev->bus->chip_rev == 1)
+ else if (dev->sdev->bus->chip_rev == 1)
tmp = 0x4205017F;
else
tmp = 0x5205017F;
@@ -4186,7 +4204,7 @@ static void setup_struct_wldev_for_init(struct b43_wldev *dev)
static void b43_bluetooth_coext_enable(struct b43_wldev *dev)
{
- struct ssb_sprom *sprom = &dev->dev->bus->sprom;
+ struct ssb_sprom *sprom = &dev->sdev->bus->sprom;
u64 hf;
if (!modparam_btcoex)
@@ -4213,33 +4231,18 @@ static void b43_bluetooth_coext_disable(struct b43_wldev *dev)
static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev)
{
-#ifdef CONFIG_SSB_DRIVER_PCICORE
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
u32 tmp;
- if (bus->pcicore.dev &&
- bus->pcicore.dev->id.coreid == SSB_DEV_PCI &&
- bus->pcicore.dev->id.revision <= 5) {
- /* IMCFGLO timeouts workaround. */
- tmp = ssb_read32(dev->dev, SSB_IMCFGLO);
- switch (bus->bustype) {
- case SSB_BUSTYPE_PCI:
- case SSB_BUSTYPE_PCMCIA:
- tmp &= ~SSB_IMCFGLO_REQTO;
- tmp &= ~SSB_IMCFGLO_SERTO;
- tmp |= 0x32;
- break;
- case SSB_BUSTYPE_SSB:
- tmp &= ~SSB_IMCFGLO_REQTO;
- tmp &= ~SSB_IMCFGLO_SERTO;
- tmp |= 0x53;
- break;
- default:
- break;
- }
- ssb_write32(dev->dev, SSB_IMCFGLO, tmp);
+ if ((bus->chip_id == 0x4311 && bus->chip_rev == 2) ||
+ (bus->chip_id == 0x4312)) {
+ tmp = ssb_read32(dev->sdev, SSB_IMCFGLO);
+ tmp &= ~SSB_IMCFGLO_REQTO;
+ tmp &= ~SSB_IMCFGLO_SERTO;
+ tmp |= 0x3;
+ ssb_write32(dev->sdev, SSB_IMCFGLO, tmp);
+ ssb_commit_settings(bus);
}
-#endif /* CONFIG_SSB_DRIVER_PCICORE */
}
static void b43_set_synth_pu_delay(struct b43_wldev *dev, bool idle)
@@ -4307,14 +4310,14 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
dev->wl->current_beacon = NULL;
}
- ssb_device_disable(dev->dev, 0);
- ssb_bus_may_powerdown(dev->dev->bus);
+ ssb_device_disable(dev->sdev, 0);
+ ssb_bus_may_powerdown(dev->sdev->bus);
}
/* Initialize a wireless core */
static int b43_wireless_core_init(struct b43_wldev *dev)
{
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
struct ssb_sprom *sprom = &bus->sprom;
struct b43_phy *phy = &dev->phy;
int err;
@@ -4326,7 +4329,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
err = ssb_bus_powerup(bus, 0);
if (err)
goto out;
- if (!ssb_device_is_enabled(dev->dev)) {
+ if (!ssb_device_is_enabled(dev->sdev)) {
tmp = phy->gmode ? B43_TMSLOW_GMODE : 0;
b43_wireless_core_reset(dev, tmp);
}
@@ -4336,7 +4339,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
phy->ops->prepare_structs(dev);
/* Enable IRQ routing to this device. */
- ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev);
+ ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->sdev);
b43_imcfglo_timeouts_workaround(dev);
b43_bluetooth_coext_disable(dev);
@@ -4349,7 +4352,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
if (err)
goto err_busdown;
b43_shm_write16(dev, B43_SHM_SHARED,
- B43_SHM_SH_WLCOREREV, dev->dev->id.revision);
+ B43_SHM_SH_WLCOREREV, dev->sdev->id.revision);
hf = b43_hf_read(dev);
if (phy->type == B43_PHYTYPE_G) {
hf |= B43_HF_SYMW;
@@ -4396,8 +4399,8 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
/* Maximum Contention Window */
b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
- if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) ||
- (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) ||
+ if ((dev->sdev->bus->bustype == SSB_BUSTYPE_PCMCIA) ||
+ (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) ||
dev->use_pio) {
dev->__using_pio_transfers = 1;
err = b43_pio_init(dev);
@@ -4734,7 +4737,7 @@ static void b43_wireless_core_detach(struct b43_wldev *dev)
static int b43_wireless_core_attach(struct b43_wldev *dev)
{
struct b43_wl *wl = dev->wl;
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
struct pci_dev *pdev = (bus->bustype == SSB_BUSTYPE_PCI) ? bus->host_pci : NULL;
int err;
bool have_2ghz_phy = 0, have_5ghz_phy = 0;
@@ -4753,10 +4756,10 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
goto out;
}
/* Get the PHY type. */
- if (dev->dev->id.revision >= 5) {
+ if (dev->sdev->id.revision >= 5) {
u32 tmshigh;
- tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
+ tmshigh = ssb_read32(dev->sdev, SSB_TMSHIGH);
have_2ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY);
have_5ghz_phy = !!(tmshigh & B43_TMSHIGH_HAVE_5GHZ_PHY);
} else
@@ -4829,7 +4832,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
INIT_WORK(&dev->restart_work, b43_chip_reset);
dev->phy.ops->switch_analog(dev, 0);
- ssb_device_disable(dev->dev, 0);
+ ssb_device_disable(dev->sdev, 0);
ssb_bus_may_powerdown(bus);
out:
@@ -4863,31 +4866,14 @@ static void b43_one_core_detach(struct ssb_device *dev)
static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
{
struct b43_wldev *wldev;
- struct pci_dev *pdev;
int err = -ENOMEM;
- if (!list_empty(&wl->devlist)) {
- /* We are not the first core on this chip. */
- pdev = (dev->bus->bustype == SSB_BUSTYPE_PCI) ? dev->bus->host_pci : NULL;
- /* Only special chips support more than one wireless
- * core, although some of the other chips have more than
- * one wireless core as well. Check for this and
- * bail out early.
- */
- if (!pdev ||
- ((pdev->device != 0x4321) &&
- (pdev->device != 0x4313) && (pdev->device != 0x431A))) {
- b43dbg(wl, "Ignoring unconnected 802.11 core\n");
- return -ENODEV;
- }
- }
-
wldev = kzalloc(sizeof(*wldev), GFP_KERNEL);
if (!wldev)
goto out;
wldev->use_pio = b43_modparam_pio;
- wldev->dev = dev;
+ wldev->sdev = dev;
wldev->wl = wl;
b43_set_status(wldev, B43_STAT_UNINIT);
wldev->bad_frames_preempt = modparam_bad_frames_preempt;
@@ -4948,19 +4934,16 @@ static void b43_wireless_exit(struct ssb_device *dev, struct b43_wl *wl)
ieee80211_free_hw(hw);
}
-static int b43_wireless_init(struct ssb_device *dev)
+static struct b43_wl *b43_wireless_init(struct ssb_device *dev)
{
struct ssb_sprom *sprom = &dev->bus->sprom;
struct ieee80211_hw *hw;
struct b43_wl *wl;
- int err = -ENOMEM;
-
- b43_sprom_fixup(dev->bus);
hw = ieee80211_alloc_hw(sizeof(*wl), &b43_hw_ops);
if (!hw) {
b43err(NULL, "Could not allocate ieee80211 device\n");
- goto out;
+ return ERR_PTR(-ENOMEM);
}
wl = hw_to_b43_wl(hw);
@@ -4994,15 +4977,12 @@ static int b43_wireless_init(struct ssb_device *dev)
INIT_WORK(&wl->tx_work, b43_tx_work);
skb_queue_head_init(&wl->tx_queue);
- ssb_set_devtypedata(dev, wl);
b43info(wl, "Broadcom %04X WLAN found (core revision %u)\n",
dev->bus->chip_id, dev->id.revision);
- err = 0;
-out:
- return err;
+ return wl;
}
-static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id)
+static int b43_ssb_probe(struct ssb_device *dev, const struct ssb_device_id *id)
{
struct b43_wl *wl;
int err;
@@ -5012,11 +4992,14 @@ static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id)
if (!wl) {
/* Probing the first core. Must setup common struct b43_wl */
first = 1;
- err = b43_wireless_init(dev);
- if (err)
+ b43_sprom_fixup(dev->bus);
+ wl = b43_wireless_init(dev);
+ if (IS_ERR(wl)) {
+ err = PTR_ERR(wl);
goto out;
- wl = ssb_get_devtypedata(dev);
- B43_WARN_ON(!wl);
+ }
+ ssb_set_devtypedata(dev, wl);
+ B43_WARN_ON(ssb_get_devtypedata(dev) != wl);
}
err = b43_one_core_attach(dev, wl);
if (err)
@@ -5040,7 +5023,7 @@ static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id)
return err;
}
-static void b43_remove(struct ssb_device *dev)
+static void b43_ssb_remove(struct ssb_device *dev)
{
struct b43_wl *wl = ssb_get_devtypedata(dev);
struct b43_wldev *wldev = ssb_get_drvdata(dev);
@@ -5083,8 +5066,8 @@ void b43_controller_restart(struct b43_wldev *dev, const char *reason)
static struct ssb_driver b43_ssb_driver = {
.name = KBUILD_MODNAME,
.id_table = b43_ssb_tbl,
- .probe = b43_probe,
- .remove = b43_remove,
+ .probe = b43_ssb_probe,
+ .remove = b43_ssb_remove,
};
static void b43_print_driverinfo(void)
diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h
index 40db03678d9f..a0d327f13183 100644
--- a/drivers/net/wireless/b43/main.h
+++ b/drivers/net/wireless/b43/main.h
@@ -133,6 +133,7 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags);
void b43_mac_suspend(struct b43_wldev *dev);
void b43_mac_enable(struct b43_wldev *dev);
+void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on);
struct b43_request_fw_context;
diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c
index 7dcba5fafdc7..2c8461dcf1b0 100644
--- a/drivers/net/wireless/b43/pcmcia.c
+++ b/drivers/net/wireless/b43/pcmcia.c
@@ -32,7 +32,7 @@
#include <pcmcia/cisreg.h>
-static /*const */ struct pcmcia_device_id b43_pcmcia_tbl[] = {
+static const struct pcmcia_device_id b43_pcmcia_tbl[] = {
PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448),
PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x476),
PCMCIA_DEVICE_NULL,
diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c
index b6428ec16dd6..b01c8ced57c3 100644
--- a/drivers/net/wireless/b43/phy_a.c
+++ b/drivers/net/wireless/b43/phy_a.c
@@ -265,7 +265,7 @@ static void hardware_pctl_init_aphy(struct b43_wldev *dev)
void b43_phy_inita(struct b43_wldev *dev)
{
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
struct b43_phy *phy = &dev->phy;
/* This lowlevel A-PHY init is also called from G-PHY init.
@@ -311,7 +311,7 @@ void b43_phy_inita(struct b43_wldev *dev)
}
if ((phy->type == B43_PHYTYPE_G) &&
- (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) {
+ (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) {
b43_phy_maskset(dev, B43_PHY_OFDM(0x6E), 0xE000, 0x3CF);
}
}
@@ -323,17 +323,17 @@ static int b43_aphy_init_tssi2dbm_table(struct b43_wldev *dev)
struct b43_phy_a *aphy = phy->a;
s16 pab0, pab1, pab2;
- pab0 = (s16) (dev->dev->bus->sprom.pa1b0);
- pab1 = (s16) (dev->dev->bus->sprom.pa1b1);
- pab2 = (s16) (dev->dev->bus->sprom.pa1b2);
+ pab0 = (s16) (dev->sdev->bus->sprom.pa1b0);
+ pab1 = (s16) (dev->sdev->bus->sprom.pa1b1);
+ pab2 = (s16) (dev->sdev->bus->sprom.pa1b2);
if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
pab0 != -1 && pab1 != -1 && pab2 != -1) {
/* The pabX values are set in SPROM. Use them. */
- if ((s8) dev->dev->bus->sprom.itssi_a != 0 &&
- (s8) dev->dev->bus->sprom.itssi_a != -1)
+ if ((s8) dev->sdev->bus->sprom.itssi_a != 0 &&
+ (s8) dev->sdev->bus->sprom.itssi_a != -1)
aphy->tgt_idle_tssi =
- (s8) (dev->dev->bus->sprom.itssi_a);
+ (s8) (dev->sdev->bus->sprom.itssi_a);
else
aphy->tgt_idle_tssi = 62;
aphy->tssi2dbm = b43_generate_dyn_tssi2dbm_tab(dev, pab0,
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c
index b5c5ce94d3fd..e46b2f4f0920 100644
--- a/drivers/net/wireless/b43/phy_common.c
+++ b/drivers/net/wireless/b43/phy_common.c
@@ -168,7 +168,7 @@ void b43_phy_lock(struct b43_wldev *dev)
B43_WARN_ON(dev->phy.phy_locked);
dev->phy.phy_locked = 1;
#endif
- B43_WARN_ON(dev->dev->id.revision < 3);
+ B43_WARN_ON(dev->sdev->id.revision < 3);
if (!b43_is_mode(dev->wl, NL80211_IFTYPE_AP))
b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
@@ -180,7 +180,7 @@ void b43_phy_unlock(struct b43_wldev *dev)
B43_WARN_ON(!dev->phy.phy_locked);
dev->phy.phy_locked = 0;
#endif
- B43_WARN_ON(dev->dev->id.revision < 3);
+ B43_WARN_ON(dev->sdev->id.revision < 3);
if (!b43_is_mode(dev->wl, NL80211_IFTYPE_AP))
b43_power_saving_ctl_bits(dev, 0);
@@ -368,8 +368,8 @@ void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags)
/* The next check will be needed in two seconds, or later. */
phy->next_txpwr_check_time = round_jiffies(now + (HZ * 2));
- if ((dev->dev->bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
- (dev->dev->bus->boardinfo.type == SSB_BOARD_BU4306))
+ if ((dev->sdev->bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
+ (dev->sdev->bus->boardinfo.type == SSB_BOARD_BU4306))
return; /* No software txpower adjustment needed */
result = phy->ops->recalc_txpower(dev, !!(flags & B43_TXPWR_IGNORE_TSSI));
diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c
index be4828167012..1758a282f913 100644
--- a/drivers/net/wireless/b43/phy_g.c
+++ b/drivers/net/wireless/b43/phy_g.c
@@ -718,7 +718,7 @@ static void b43_calc_nrssi_threshold(struct b43_wldev *dev)
B43_WARN_ON(phy->type != B43_PHYTYPE_G);
if (!phy->gmode ||
- !(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
+ !(dev->sdev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
tmp16 = b43_nrssi_hw_read(dev, 0x20);
if (tmp16 >= 0x20)
tmp16 -= 0x40;
@@ -1114,7 +1114,7 @@ static u16 radio2050_rfover_val(struct b43_wldev *dev,
{
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = phy->g;
- struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
+ struct ssb_sprom *sprom = &(dev->sdev->bus->sprom);
if (!phy->gmode)
return 0;
@@ -1491,7 +1491,7 @@ static u16 b43_radio_init2050(struct b43_wldev *dev)
static void b43_phy_initb5(struct b43_wldev *dev)
{
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = phy->g;
u16 offset, value;
@@ -1620,7 +1620,7 @@ static void b43_phy_initb6(struct b43_wldev *dev)
b43_radio_write16(dev, 0x5A, 0x88);
b43_radio_write16(dev, 0x5B, 0x6B);
b43_radio_write16(dev, 0x5C, 0x0F);
- if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_ALTIQ) {
+ if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_ALTIQ) {
b43_radio_write16(dev, 0x5D, 0xFA);
b43_radio_write16(dev, 0x5E, 0xD8);
} else {
@@ -1787,7 +1787,7 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
b43_phy_set(dev, B43_PHY_RFOVER, 0x0100);
b43_phy_mask(dev, B43_PHY_RFOVERVAL, 0xCFFF);
- if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) {
+ if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) {
if (phy->rev >= 7) {
b43_phy_set(dev, B43_PHY_RFOVER, 0x0800);
b43_phy_set(dev, B43_PHY_RFOVERVAL, 0x8000);
@@ -1922,7 +1922,7 @@ static void b43_hardware_pctl_init_gphy(struct b43_wldev *dev)
/* Initialize B/G PHY power control */
static void b43_phy_init_pctl(struct b43_wldev *dev)
{
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
struct b43_phy *phy = &dev->phy;
struct b43_phy_g *gphy = phy->g;
struct b43_rfatt old_rfatt;
@@ -2053,7 +2053,7 @@ static void b43_phy_initg(struct b43_wldev *dev)
if (phy->rev >= 6) {
b43_phy_maskset(dev, B43_PHY_CCK(0x36), 0x0FFF, (gphy->lo_control->tx_bias << 12));
}
- if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
+ if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075);
else
b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F);
@@ -2066,7 +2066,7 @@ static void b43_phy_initg(struct b43_wldev *dev)
b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
}
- if (!(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
+ if (!(dev->sdev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
/* The specs state to update the NRSSI LT with
* the value 0x7FFFFFFF here. I think that is some weird
* compiler optimization in the original driver.
@@ -2088,8 +2088,8 @@ static void b43_phy_initg(struct b43_wldev *dev)
/* FIXME: The spec says in the following if, the 0 should be replaced
'if OFDM may not be used in the current locale'
but OFDM is legal everywhere */
- if ((dev->dev->bus->chip_id == 0x4306
- && dev->dev->bus->chip_package == 2) || 0) {
+ if ((dev->sdev->bus->chip_id == 0x4306
+ && dev->sdev->bus->chip_package == 2) || 0) {
b43_phy_mask(dev, B43_PHY_CRS0, 0xBFFF);
b43_phy_mask(dev, B43_PHY_OFDM(0xC3), 0x7FFF);
}
@@ -2105,7 +2105,7 @@ void b43_gphy_channel_switch(struct b43_wldev *dev,
b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel));
if (channel == 14) {
- if (dev->dev->bus->sprom.country_code ==
+ if (dev->sdev->bus->sprom.country_code ==
SSB_SPROM1CCODE_JAPAN)
b43_hf_write(dev,
b43_hf_read(dev) & ~B43_HF_ACPR);
@@ -2136,7 +2136,7 @@ static void default_baseband_attenuation(struct b43_wldev *dev,
static void default_radio_attenuation(struct b43_wldev *dev,
struct b43_rfatt *rf)
{
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
struct b43_phy *phy = &dev->phy;
rf->with_padmix = 0;
@@ -2384,11 +2384,11 @@ static int b43_gphy_init_tssi2dbm_table(struct b43_wldev *dev)
struct b43_phy_g *gphy = phy->g;
s16 pab0, pab1, pab2;
- pab0 = (s16) (dev->dev->bus->sprom.pa0b0);
- pab1 = (s16) (dev->dev->bus->sprom.pa0b1);
- pab2 = (s16) (dev->dev->bus->sprom.pa0b2);
+ pab0 = (s16) (dev->sdev->bus->sprom.pa0b0);
+ pab1 = (s16) (dev->sdev->bus->sprom.pa0b1);
+ pab2 = (s16) (dev->sdev->bus->sprom.pa0b2);
- B43_WARN_ON((dev->dev->bus->chip_id == 0x4301) &&
+ B43_WARN_ON((dev->sdev->bus->chip_id == 0x4301) &&
(phy->radio_ver != 0x2050)); /* Not supported anymore */
gphy->dyn_tssi_tbl = 0;
@@ -2396,10 +2396,10 @@ static int b43_gphy_init_tssi2dbm_table(struct b43_wldev *dev)
if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
pab0 != -1 && pab1 != -1 && pab2 != -1) {
/* The pabX values are set in SPROM. Use them. */
- if ((s8) dev->dev->bus->sprom.itssi_bg != 0 &&
- (s8) dev->dev->bus->sprom.itssi_bg != -1) {
+ if ((s8) dev->sdev->bus->sprom.itssi_bg != 0 &&
+ (s8) dev->sdev->bus->sprom.itssi_bg != -1) {
gphy->tgt_idle_tssi =
- (s8) (dev->dev->bus->sprom.itssi_bg);
+ (s8) (dev->sdev->bus->sprom.itssi_bg);
} else
gphy->tgt_idle_tssi = 62;
gphy->tssi2dbm = b43_generate_dyn_tssi2dbm_tab(dev, pab0,
@@ -2840,7 +2840,7 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev)
B43_TXCTL_TXMIX;
rfatt += 2;
bbatt += 2;
- } else if (dev->dev->bus->sprom.
+ } else if (dev->sdev->bus->sprom.
boardflags_lo &
B43_BFL_PACTRL) {
bbatt += 4 * (rfatt - 2);
@@ -2914,14 +2914,14 @@ static enum b43_txpwr_result b43_gphy_op_recalc_txpower(struct b43_wldev *dev,
estimated_pwr = b43_gphy_estimate_power_out(dev, average_tssi);
B43_WARN_ON(phy->type != B43_PHYTYPE_G);
- max_pwr = dev->dev->bus->sprom.maxpwr_bg;
- if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
+ max_pwr = dev->sdev->bus->sprom.maxpwr_bg;
+ if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
max_pwr -= 3; /* minus 0.75 */
if (unlikely(max_pwr >= INT_TO_Q52(30/*dBm*/))) {
b43warn(dev->wl,
"Invalid max-TX-power value in SPROM.\n");
max_pwr = INT_TO_Q52(20); /* fake it */
- dev->dev->bus->sprom.maxpwr_bg = max_pwr;
+ dev->sdev->bus->sprom.maxpwr_bg = max_pwr;
}
/* Get desired power (in Q5.2) */
@@ -3014,7 +3014,7 @@ static void b43_gphy_op_pwork_60sec(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
- if (!(dev->dev->bus->sprom.boardflags_lo & B43_BFL_RSSI))
+ if (!(dev->sdev->bus->sprom.boardflags_lo & B43_BFL_RSSI))
return;
b43_mac_suspend(dev);
diff --git a/drivers/net/wireless/b43/phy_lp.c b/drivers/net/wireless/b43/phy_lp.c
index fd50eb116243..012c8da2f944 100644
--- a/drivers/net/wireless/b43/phy_lp.c
+++ b/drivers/net/wireless/b43/phy_lp.c
@@ -86,7 +86,7 @@ static void b43_lpphy_op_free(struct b43_wldev *dev)
static void lpphy_read_band_sprom(struct b43_wldev *dev)
{
struct b43_phy_lp *lpphy = dev->phy.lp;
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
u16 cckpo, maxpwr;
u32 ofdmpo;
int i;
@@ -214,7 +214,7 @@ static void lpphy_table_init(struct b43_wldev *dev)
static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
{
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
struct b43_phy_lp *lpphy = dev->phy.lp;
u16 tmp, tmp2;
@@ -412,7 +412,7 @@ static void lpphy_restore_dig_flt_state(struct b43_wldev *dev)
static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
{
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
struct b43_phy_lp *lpphy = dev->phy.lp;
b43_phy_write(dev, B43_LPPHY_AFE_DAC_CTL, 0x50);
@@ -519,7 +519,7 @@ struct b2062_freqdata {
static void lpphy_2062_init(struct b43_wldev *dev)
{
struct b43_phy_lp *lpphy = dev->phy.lp;
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
u32 crystalfreq, tmp, ref;
unsigned int i;
const struct b2062_freqdata *fd = NULL;
@@ -697,7 +697,7 @@ static void lpphy_radio_init(struct b43_wldev *dev)
lpphy_sync_stx(dev);
b43_phy_write(dev, B43_PHY_OFDM(0xF0), 0x5F80);
b43_phy_write(dev, B43_PHY_OFDM(0xF1), 0);
- if (dev->dev->bus->chip_id == 0x4325) {
+ if (dev->sdev->bus->chip_id == 0x4325) {
// TODO SSB PMU recalibration
}
}
@@ -1289,7 +1289,7 @@ finish:
static void lpphy_rev2plus_rc_calib(struct b43_wldev *dev)
{
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
u8 tmp = b43_radio_read(dev, B2063_RX_BB_SP8) & 0xFF;
int i;
@@ -1840,7 +1840,7 @@ static void lpphy_papd_cal(struct b43_wldev *dev, struct lpphy_tx_gains gains,
static void lpphy_papd_cal_txpwr(struct b43_wldev *dev)
{
struct b43_phy_lp *lpphy = dev->phy.lp;
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
struct lpphy_tx_gains gains, oldgains;
int old_txpctl, old_afe_ovr, old_rf, old_bbmult;
@@ -1870,7 +1870,7 @@ static int lpphy_rx_iq_cal(struct b43_wldev *dev, bool noise, bool tx,
bool rx, bool pa, struct lpphy_tx_gains *gains)
{
struct b43_phy_lp *lpphy = dev->phy.lp;
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
const struct lpphy_rx_iq_comp *iqcomp = NULL;
struct lpphy_tx_gains nogains, oldgains;
u16 tmp;
@@ -2408,7 +2408,7 @@ static const struct b206x_channel b2063_chantbl[] = {
static void lpphy_b2062_reset_pll_bias(struct b43_wldev *dev)
{
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0xFF);
udelay(20);
@@ -2432,7 +2432,7 @@ static int lpphy_b2062_tune(struct b43_wldev *dev,
unsigned int channel)
{
struct b43_phy_lp *lpphy = dev->phy.lp;
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
const struct b206x_channel *chandata = NULL;
u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9;
@@ -2522,7 +2522,7 @@ static void lpphy_b2063_vco_calib(struct b43_wldev *dev)
static int lpphy_b2063_tune(struct b43_wldev *dev,
unsigned int channel)
{
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
static const struct b206x_channel *chandata = NULL;
u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c
index 8a00f9a95dbb..9ed65157bef5 100644
--- a/drivers/net/wireless/b43/phy_n.c
+++ b/drivers/net/wireless/b43/phy_n.c
@@ -299,7 +299,7 @@ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable)
static void b43_nphy_tx_power_fix(struct b43_wldev *dev)
{
struct b43_phy_n *nphy = dev->phy.n;
- struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
+ struct ssb_sprom *sprom = &(dev->sdev->bus->sprom);
u8 txpi[2], bbmult, i;
u16 tmp, radio_gain, dac_gain;
@@ -423,8 +423,8 @@ static void b43_radio_init2055_pre(struct b43_wldev *dev)
static void b43_radio_init2055_post(struct b43_wldev *dev)
{
struct b43_phy_n *nphy = dev->phy.n;
- struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
- struct ssb_boardinfo *binfo = &(dev->dev->bus->boardinfo);
+ struct ssb_sprom *sprom = &(dev->sdev->bus->sprom);
+ struct ssb_boardinfo *binfo = &(dev->sdev->bus->boardinfo);
int i;
u16 val;
bool workaround = false;
@@ -609,12 +609,12 @@ static void b43_nphy_bmac_clock_fgc(struct b43_wldev *dev, bool force)
if (dev->phy.type != B43_PHYTYPE_N)
return;
- tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
+ tmslow = ssb_read32(dev->sdev, SSB_TMSLOW);
if (force)
tmslow |= SSB_TMSLOW_FGC;
else
tmslow &= ~SSB_TMSLOW_FGC;
- ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
+ ssb_write32(dev->sdev, SSB_TMSLOW, tmslow);
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CCA */
@@ -959,7 +959,7 @@ static void b43_nphy_superswitch_init(struct b43_wldev *dev, bool init)
b43_phy_write(dev, B43_NPHY_GPIO_LOOEN, 0);
b43_phy_write(dev, B43_NPHY_GPIO_HIOEN, 0);
- ssb_chipco_gpio_control(&dev->dev->bus->chipco, 0xFC00,
+ ssb_chipco_gpio_control(&dev->sdev->bus->chipco, 0xFC00,
0xFC00);
b43_write32(dev, B43_MMIO_MACCTL,
b43_read32(dev, B43_MMIO_MACCTL) &
@@ -983,7 +983,7 @@ static u16 b43_nphy_classifier(struct b43_wldev *dev, u16 mask, u16 val)
{
u16 tmp;
- if (dev->dev->id.revision == 16)
+ if (dev->sdev->id.revision == 16)
b43_mac_suspend(dev);
tmp = b43_phy_read(dev, B43_NPHY_CLASSCTL);
@@ -993,7 +993,7 @@ static u16 b43_nphy_classifier(struct b43_wldev *dev, u16 mask, u16 val)
tmp |= (val & mask);
b43_phy_maskset(dev, B43_NPHY_CLASSCTL, 0xFFF8, tmp);
- if (dev->dev->id.revision == 16)
+ if (dev->sdev->id.revision == 16)
b43_mac_enable(dev);
return tmp;
@@ -1168,7 +1168,7 @@ static void b43_nphy_adjust_lna_gain_table(struct b43_wldev *dev)
static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev)
{
struct b43_phy_n *nphy = dev->phy.n;
- struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
+ struct ssb_sprom *sprom = &(dev->sdev->bus->sprom);
/* PHY rev 0, 1, 2 */
u8 i, j;
@@ -1373,7 +1373,7 @@ static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev)
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Workarounds */
static void b43_nphy_workarounds(struct b43_wldev *dev)
{
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
struct b43_phy *phy = &dev->phy;
struct b43_phy_n *nphy = phy->n;
@@ -2281,6 +2281,7 @@ static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf,
save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER);
save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B1S0);
save_regs_phy[7] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B32S1);
+ save_regs_phy[8] = 0;
} else {
save_regs_phy[0] = b43_phy_read(dev, B43_NPHY_AFECTL_C1);
save_regs_phy[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C2);
@@ -2289,6 +2290,8 @@ static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf,
save_regs_phy[4] = b43_phy_read(dev, B43_NPHY_RFCTL_OVER);
save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO1);
save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO2);
+ save_regs_phy[7] = 0;
+ save_regs_phy[8] = 0;
}
b43_nphy_rssi_select(dev, 5, type);
@@ -3537,17 +3540,6 @@ static int b43_nphy_cal_rx_iq(struct b43_wldev *dev,
return b43_nphy_rev2_cal_rx_iq(dev, target, type, debug);
}
-/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MacPhyClkSet */
-static void b43_nphy_mac_phy_clock_set(struct b43_wldev *dev, bool on)
-{
- u32 tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
- if (on)
- tmslow |= B43_TMSLOW_MACPHYCLKEN;
- else
- tmslow &= ~B43_TMSLOW_MACPHYCLKEN;
- ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
-}
-
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCoreSetState */
static void b43_nphy_set_rx_core_state(struct b43_wldev *dev, u8 mask)
{
@@ -3594,7 +3586,7 @@ static void b43_nphy_set_rx_core_state(struct b43_wldev *dev, u8 mask)
*/
int b43_phy_initn(struct b43_wldev *dev)
{
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
struct b43_phy *phy = &dev->phy;
struct b43_phy_n *nphy = phy->n;
u8 tx_pwr_state;
@@ -3609,7 +3601,7 @@ int b43_phy_initn(struct b43_wldev *dev)
if ((dev->phy.rev >= 3) &&
(bus->sprom.boardflags_lo & B43_BFL_EXTLNA) &&
(b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)) {
- chipco_set32(&dev->dev->bus->chipco, SSB_CHIPCO_CHIPCTL, 0x40);
+ chipco_set32(&dev->sdev->bus->chipco, SSB_CHIPCO_CHIPCTL, 0x40);
}
nphy->deaf_count = 0;
b43_nphy_tables_init(dev);
@@ -3688,7 +3680,7 @@ int b43_phy_initn(struct b43_wldev *dev)
b43_phy_write(dev, B43_NPHY_BBCFG, tmp & ~B43_NPHY_BBCFG_RSTCCA);
b43_nphy_bmac_clock_fgc(dev, 0);
- b43_nphy_mac_phy_clock_set(dev, true);
+ b43_mac_phy_clock_set(dev, true);
b43_nphy_pa_override(dev, false);
b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX);
@@ -3845,8 +3837,8 @@ static int b43_nphy_set_channel(struct b43_wldev *dev,
{
struct b43_phy *phy = &dev->phy;
- const struct b43_nphy_channeltab_entry_rev2 *tabent_r2;
- const struct b43_nphy_channeltab_entry_rev3 *tabent_r3;
+ const struct b43_nphy_channeltab_entry_rev2 *tabent_r2 = NULL;
+ const struct b43_nphy_channeltab_entry_rev3 *tabent_r3 = NULL;
u8 tmp;
diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c
index aa12273ae716..72ab94df7569 100644
--- a/drivers/net/wireless/b43/pio.c
+++ b/drivers/net/wireless/b43/pio.c
@@ -111,7 +111,7 @@ static u16 index_to_pioqueue_base(struct b43_wldev *dev,
B43_MMIO_PIO11_BASE5,
};
- if (dev->dev->id.revision >= 11) {
+ if (dev->sdev->id.revision >= 11) {
B43_WARN_ON(index >= ARRAY_SIZE(bases_rev11));
return bases_rev11[index];
}
@@ -121,14 +121,14 @@ static u16 index_to_pioqueue_base(struct b43_wldev *dev,
static u16 pio_txqueue_offset(struct b43_wldev *dev)
{
- if (dev->dev->id.revision >= 11)
+ if (dev->sdev->id.revision >= 11)
return 0x18;
return 0;
}
static u16 pio_rxqueue_offset(struct b43_wldev *dev)
{
- if (dev->dev->id.revision >= 11)
+ if (dev->sdev->id.revision >= 11)
return 0x38;
return 8;
}
@@ -144,7 +144,7 @@ static struct b43_pio_txqueue *b43_setup_pioqueue_tx(struct b43_wldev *dev,
if (!q)
return NULL;
q->dev = dev;
- q->rev = dev->dev->id.revision;
+ q->rev = dev->sdev->id.revision;
q->mmio_base = index_to_pioqueue_base(dev, index) +
pio_txqueue_offset(dev);
q->index = index;
@@ -178,7 +178,7 @@ static struct b43_pio_rxqueue *b43_setup_pioqueue_rx(struct b43_wldev *dev,
if (!q)
return NULL;
q->dev = dev;
- q->rev = dev->dev->id.revision;
+ q->rev = dev->sdev->id.revision;
q->mmio_base = index_to_pioqueue_base(dev, index) +
pio_rxqueue_offset(dev);
@@ -339,7 +339,7 @@ static u16 tx_write_2byte_queue(struct b43_pio_txqueue *q,
ctl |= B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_WRITEHI;
b43_piotx_write16(q, B43_PIO_TXCTL, ctl);
- ssb_block_write(dev->dev, data, (data_len & ~1),
+ b43_block_write(dev, data, (data_len & ~1),
q->mmio_base + B43_PIO_TXDATA,
sizeof(u16));
if (data_len & 1) {
@@ -351,7 +351,7 @@ static u16 tx_write_2byte_queue(struct b43_pio_txqueue *q,
b43_piotx_write16(q, B43_PIO_TXCTL, ctl);
tail[0] = data[data_len - 1];
tail[1] = 0;
- ssb_block_write(dev->dev, tail, 2,
+ b43_block_write(dev, tail, 2,
q->mmio_base + B43_PIO_TXDATA,
sizeof(u16));
}
@@ -393,7 +393,7 @@ static u32 tx_write_4byte_queue(struct b43_pio_txqueue *q,
B43_PIO8_TXCTL_16_23 | B43_PIO8_TXCTL_24_31;
b43_piotx_write32(q, B43_PIO8_TXCTL, ctl);
- ssb_block_write(dev->dev, data, (data_len & ~3),
+ b43_block_write(dev, data, (data_len & ~3),
q->mmio_base + B43_PIO8_TXDATA,
sizeof(u32));
if (data_len & 3) {
@@ -421,7 +421,7 @@ static u32 tx_write_4byte_queue(struct b43_pio_txqueue *q,
break;
}
b43_piotx_write32(q, B43_PIO8_TXCTL, ctl);
- ssb_block_write(dev->dev, tail, 4,
+ b43_block_write(dev, tail, 4,
q->mmio_base + B43_PIO8_TXDATA,
sizeof(u32));
}
@@ -657,11 +657,11 @@ data_ready:
/* Get the preamble (RX header) */
if (q->rev >= 8) {
- ssb_block_read(dev->dev, rxhdr, sizeof(*rxhdr),
+ b43_block_read(dev, rxhdr, sizeof(*rxhdr),
q->mmio_base + B43_PIO8_RXDATA,
sizeof(u32));
} else {
- ssb_block_read(dev->dev, rxhdr, sizeof(*rxhdr),
+ b43_block_read(dev, rxhdr, sizeof(*rxhdr),
q->mmio_base + B43_PIO_RXDATA,
sizeof(u16));
}
@@ -697,7 +697,7 @@ data_ready:
skb_reserve(skb, 2);
skb_put(skb, len + padding);
if (q->rev >= 8) {
- ssb_block_read(dev->dev, skb->data + padding, (len & ~3),
+ b43_block_read(dev, skb->data + padding, (len & ~3),
q->mmio_base + B43_PIO8_RXDATA,
sizeof(u32));
if (len & 3) {
@@ -705,7 +705,7 @@ data_ready:
BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 4);
/* Read the last few bytes. */
- ssb_block_read(dev->dev, tail, 4,
+ b43_block_read(dev, tail, 4,
q->mmio_base + B43_PIO8_RXDATA,
sizeof(u32));
switch (len & 3) {
@@ -724,7 +724,7 @@ data_ready:
}
}
} else {
- ssb_block_read(dev->dev, skb->data + padding, (len & ~1),
+ b43_block_read(dev, skb->data + padding, (len & ~1),
q->mmio_base + B43_PIO_RXDATA,
sizeof(u16));
if (len & 1) {
@@ -732,7 +732,7 @@ data_ready:
BUILD_BUG_ON(sizeof(wl->pio_tailspace) < 2);
/* Read the last byte. */
- ssb_block_read(dev->dev, tail, 2,
+ b43_block_read(dev, tail, 2,
q->mmio_base + B43_PIO_RXDATA,
sizeof(u16));
skb->data[len + padding - 1] = tail[0];
diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c
index 86bc0a0f735c..a617efe38289 100644
--- a/drivers/net/wireless/b43/rfkill.c
+++ b/drivers/net/wireless/b43/rfkill.c
@@ -37,7 +37,7 @@ void b43_rfkill_poll(struct ieee80211_hw *hw)
{
struct b43_wl *wl = hw_to_b43_wl(hw);
struct b43_wldev *dev = wl->current_dev;
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
bool enabled;
bool brought_up = false;
@@ -47,7 +47,7 @@ void b43_rfkill_poll(struct ieee80211_hw *hw)
mutex_unlock(&wl->mutex);
return;
}
- ssb_device_enable(dev->dev, 0);
+ ssb_device_enable(dev->sdev, 0);
brought_up = true;
}
@@ -63,7 +63,7 @@ void b43_rfkill_poll(struct ieee80211_hw *hw)
}
if (brought_up) {
- ssb_device_disable(dev->dev, 0);
+ ssb_device_disable(dev->sdev, 0);
ssb_bus_may_powerdown(bus);
}
diff --git a/drivers/net/wireless/b43/sdio.c b/drivers/net/wireless/b43/sdio.c
index 09e2dfd7b175..808e25b79703 100644
--- a/drivers/net/wireless/b43/sdio.c
+++ b/drivers/net/wireless/b43/sdio.c
@@ -66,7 +66,7 @@ static void b43_sdio_interrupt_dispatcher(struct sdio_func *func)
int b43_sdio_request_irq(struct b43_wldev *dev,
void (*handler)(struct b43_wldev *dev))
{
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
struct sdio_func *func = bus->host_sdio;
struct b43_sdio *sdio = sdio_get_drvdata(func);
int err;
@@ -82,7 +82,7 @@ int b43_sdio_request_irq(struct b43_wldev *dev,
void b43_sdio_free_irq(struct b43_wldev *dev)
{
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
struct sdio_func *func = bus->host_sdio;
struct b43_sdio *sdio = sdio_get_drvdata(func);
diff --git a/drivers/net/wireless/b43/sysfs.c b/drivers/net/wireless/b43/sysfs.c
index f1ae4e05a32c..57af619725c3 100644
--- a/drivers/net/wireless/b43/sysfs.c
+++ b/drivers/net/wireless/b43/sysfs.c
@@ -140,7 +140,7 @@ static DEVICE_ATTR(interference, 0644,
int b43_sysfs_register(struct b43_wldev *wldev)
{
- struct device *dev = wldev->dev->dev;
+ struct device *dev = wldev->sdev->dev;
B43_WARN_ON(b43_status(wldev) != B43_STAT_INITIALIZED);
@@ -149,7 +149,7 @@ int b43_sysfs_register(struct b43_wldev *wldev)
void b43_sysfs_unregister(struct b43_wldev *wldev)
{
- struct device *dev = wldev->dev->dev;
+ struct device *dev = wldev->sdev->dev;
device_remove_file(dev, &dev_attr_interference);
}
diff --git a/drivers/net/wireless/b43/tables_lpphy.c b/drivers/net/wireless/b43/tables_lpphy.c
index 61027ee84fb5..59df3c64af63 100644
--- a/drivers/net/wireless/b43/tables_lpphy.c
+++ b/drivers/net/wireless/b43/tables_lpphy.c
@@ -2304,7 +2304,7 @@ void lpphy_rev0_1_table_init(struct b43_wldev *dev)
void lpphy_rev2plus_table_init(struct b43_wldev *dev)
{
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
int i;
B43_WARN_ON(dev->phy.rev < 2);
@@ -2416,7 +2416,7 @@ void lpphy_write_gain_table_bulk(struct b43_wldev *dev, int offset, int count,
void lpphy_init_tx_gain_table(struct b43_wldev *dev)
{
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
switch (dev->phy.rev) {
case 0:
diff --git a/drivers/net/wireless/b43/wa.c b/drivers/net/wireless/b43/wa.c
index 9a335da65b42..8f4db448ec33 100644
--- a/drivers/net/wireless/b43/wa.c
+++ b/drivers/net/wireless/b43/wa.c
@@ -458,7 +458,7 @@ static void b43_wa_rssi_adc(struct b43_wldev *dev)
static void b43_wa_boards_a(struct b43_wldev *dev)
{
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
bus->boardinfo.type == SSB_BOARD_BU4306 &&
@@ -486,7 +486,7 @@ static void b43_wa_boards_a(struct b43_wldev *dev)
static void b43_wa_boards_g(struct b43_wldev *dev)
{
- struct ssb_bus *bus = dev->dev->bus;
+ struct ssb_bus *bus = dev->sdev->bus;
struct b43_phy *phy = &dev->phy;
if (bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM ||
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
index e5be381c17bc..c8f99aebe01f 100644
--- a/drivers/net/wireless/b43/xmit.c
+++ b/drivers/net/wireless/b43/xmit.c
@@ -547,7 +547,7 @@ static s8 b43_rssi_postprocess(struct b43_wldev *dev,
else
tmp -= 3;
} else {
- if (dev->dev->bus->sprom.
+ if (dev->sdev->bus->sprom.
boardflags_lo & B43_BFL_RSSI) {
if (in_rssi > 63)
in_rssi = 63;
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index c7fd73e3ad76..1ab8861dd43a 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -2234,7 +2234,7 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev)
b43legacy_write32(dev, B43legacy_MMIO_DMA5_IRQ_MASK, 0x0000DC00);
value32 = ssb_read32(dev->dev, SSB_TMSLOW);
- value32 |= 0x00100000;
+ value32 |= B43legacy_TMSLOW_MACPHYCLKEN;
ssb_write32(dev->dev, SSB_TMSLOW, value32);
b43legacy_write16(dev, B43legacy_MMIO_POWERUP_DELAY,
@@ -3104,37 +3104,6 @@ static void setup_struct_wldev_for_init(struct b43legacy_wldev *dev)
memset(&dev->noisecalc, 0, sizeof(dev->noisecalc));
}
-static void b43legacy_imcfglo_timeouts_workaround(struct b43legacy_wldev *dev)
-{
-#ifdef CONFIG_SSB_DRIVER_PCICORE
- struct ssb_bus *bus = dev->dev->bus;
- u32 tmp;
-
- if (bus->pcicore.dev &&
- bus->pcicore.dev->id.coreid == SSB_DEV_PCI &&
- bus->pcicore.dev->id.revision <= 5) {
- /* IMCFGLO timeouts workaround. */
- tmp = ssb_read32(dev->dev, SSB_IMCFGLO);
- switch (bus->bustype) {
- case SSB_BUSTYPE_PCI:
- case SSB_BUSTYPE_PCMCIA:
- tmp &= ~SSB_IMCFGLO_REQTO;
- tmp &= ~SSB_IMCFGLO_SERTO;
- tmp |= 0x32;
- break;
- case SSB_BUSTYPE_SSB:
- tmp &= ~SSB_IMCFGLO_REQTO;
- tmp &= ~SSB_IMCFGLO_SERTO;
- tmp |= 0x53;
- break;
- default:
- break;
- }
- ssb_write32(dev->dev, SSB_IMCFGLO, tmp);
- }
-#endif /* CONFIG_SSB_DRIVER_PCICORE */
-}
-
static void b43legacy_set_synth_pu_delay(struct b43legacy_wldev *dev,
bool idle) {
u16 pu_delay = 1050;
@@ -3278,7 +3247,6 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev)
/* Enable IRQ routing to this device. */
ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev);
- b43legacy_imcfglo_timeouts_workaround(dev);
prepare_phy_data_for_init(dev);
b43legacy_phy_calibrate(dev);
err = b43legacy_chip_init(dev);
@@ -3728,26 +3696,8 @@ static int b43legacy_one_core_attach(struct ssb_device *dev,
struct b43legacy_wl *wl)
{
struct b43legacy_wldev *wldev;
- struct pci_dev *pdev;
int err = -ENOMEM;
- if (!list_empty(&wl->devlist)) {
- /* We are not the first core on this chip. */
- pdev = (dev->bus->bustype == SSB_BUSTYPE_PCI) ? dev->bus->host_pci : NULL;
- /* Only special chips support more than one wireless
- * core, although some of the other chips have more than
- * one wireless core as well. Check for this and
- * bail out early.
- */
- if (!pdev ||
- ((pdev->device != 0x4321) &&
- (pdev->device != 0x4313) &&
- (pdev->device != 0x431A))) {
- b43legacydbg(wl, "Ignoring unconnected 802.11 core\n");
- return -ENODEV;
- }
- }
-
wldev = kzalloc(sizeof(*wldev), GFP_KERNEL);
if (!wldev)
goto out;
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index 2176edede39b..c052a0d5cbdd 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -620,7 +620,7 @@ static int hostap_cs_resume(struct pcmcia_device *link)
return 0;
}
-static struct pcmcia_device_id hostap_cs_ids[] = {
+static const struct pcmcia_device_id hostap_cs_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100),
PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300),
PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777),
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index 1d9aed645723..d5084829c9e5 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -79,13 +79,8 @@ struct net_device * hostap_add_interface(struct local_info *local,
if (!rtnl_locked)
rtnl_lock();
- ret = 0;
- if (strchr(dev->name, '%'))
- ret = dev_alloc_name(dev, dev->name);
-
SET_NETDEV_DEV(dev, mdev->dev.parent);
- if (ret >= 0)
- ret = register_netdevice(dev);
+ ret = register_netdevice(dev);
if (!rtnl_locked)
rtnl_unlock();
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index 42c3fe37af64..87813c33bdc2 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -7430,7 +7430,7 @@ static int ipw_associate_network(struct ipw_priv *priv,
priv->assoc_request.capability &=
~cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT_TIME);
- IPW_DEBUG_ASSOC("%sssocation attempt: '%s', channel %d, "
+ IPW_DEBUG_ASSOC("%ssociation attempt: '%s', channel %d, "
"802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n",
roaming ? "Rea" : "A",
print_ssid(ssid, priv->essid, priv->essid_len),
diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-calib.c b/drivers/net/wireless/iwlegacy/iwl-4965-calib.c
index 81d6a25eb04f..162d877e6869 100644
--- a/drivers/net/wireless/iwlegacy/iwl-4965-calib.c
+++ b/drivers/net/wireless/iwlegacy/iwl-4965-calib.c
@@ -713,8 +713,8 @@ iwl4965_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig,
iwl4965_find_first_chain(priv->cfg->valid_tx_ant);
data->disconn_array[first_chain] = 0;
active_chains |= BIT(first_chain);
- IWL_DEBUG_CALIB(priv, "All Tx chains are disconnected \
- W/A - declare %d as connected\n",
+ IWL_DEBUG_CALIB(priv,
+ "All Tx chains are disconnected W/A - declare %d as connected\n",
first_chain);
break;
}
diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-lib.c b/drivers/net/wireless/iwlegacy/iwl-4965-lib.c
index 5a8a3cce27bc..7e5e85a017b5 100644
--- a/drivers/net/wireless/iwlegacy/iwl-4965-lib.c
+++ b/drivers/net/wireless/iwlegacy/iwl-4965-lib.c
@@ -955,9 +955,6 @@ int iwl4965_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
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] = iwl4965_toggle_tx_ant(priv,
priv->scan_tx_ant[band],
scan_tx_antennas);
diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-rs.c b/drivers/net/wireless/iwlegacy/iwl-4965-rs.c
index 31ac672b64e1..24d149909ba3 100644
--- a/drivers/net/wireless/iwlegacy/iwl-4965-rs.c
+++ b/drivers/net/wireless/iwlegacy/iwl-4965-rs.c
@@ -2604,7 +2604,7 @@ static ssize_t iwl4965_rs_sta_dbgfs_scale_table_write(struct file *file,
struct iwl_lq_sta *lq_sta = file->private_data;
struct iwl_priv *priv;
char buf[64];
- int buf_size;
+ size_t buf_size;
u32 parsed_rate;
struct iwl_station_priv *sta_priv =
container_of(lq_sta, struct iwl_station_priv, lq_sta);
@@ -2860,7 +2860,6 @@ static struct rate_control_ops rs_4965_ops = {
int iwl4965_rate_control_register(void)
{
- pr_err("Registering 4965 rate control operations\n");
return ieee80211_rate_control_register(&rs_4965_ops);
}
diff --git a/drivers/net/wireless/iwlegacy/iwl-core.c b/drivers/net/wireless/iwlegacy/iwl-core.c
index 42db0fc8b921..42df8321dae8 100644
--- a/drivers/net/wireless/iwlegacy/iwl-core.c
+++ b/drivers/net/wireless/iwlegacy/iwl-core.c
@@ -211,10 +211,7 @@ int iwl_legacy_init_geos(struct iwl_priv *priv)
if (!iwl_legacy_is_channel_valid(ch))
continue;
- if (iwl_legacy_is_channel_a_band(ch))
- sband = &priv->bands[IEEE80211_BAND_5GHZ];
- else
- sband = &priv->bands[IEEE80211_BAND_2GHZ];
+ sband = &priv->bands[ch->band];
geo_ch = &sband->channels[sband->n_channels++];
@@ -2117,10 +2114,9 @@ int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed)
IWL_DEBUG_MAC80211(priv, "enter to channel %d changed 0x%X\n",
channel->hw_value, changed);
- if (unlikely(!priv->cfg->mod_params->disable_hw_scan &&
- test_bit(STATUS_SCANNING, &priv->status))) {
+ if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) {
scan_active = 1;
- IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
+ IWL_DEBUG_MAC80211(priv, "scan active\n");
}
if (changed & (IEEE80211_CONF_CHANGE_SMPS |
@@ -2440,11 +2436,13 @@ void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw,
IWL_DEBUG_MAC80211(priv, "changes = 0x%X\n", changes);
- if (!iwl_legacy_is_alive(priv))
- return;
-
mutex_lock(&priv->mutex);
+ if (!iwl_legacy_is_alive(priv)) {
+ mutex_unlock(&priv->mutex);
+ return;
+ }
+
if (changes & BSS_CHANGED_QOS) {
unsigned long flags;
@@ -2653,7 +2651,7 @@ unplugged:
none:
/* re-enable interrupts here since we don't have anything to service. */
- /* only Re-enable if diabled by irq */
+ /* only Re-enable if disabled by irq */
if (test_bit(STATUS_INT_ENABLED, &priv->status))
iwl_legacy_enable_interrupts(priv);
spin_unlock_irqrestore(&priv->lock, flags);
diff --git a/drivers/net/wireless/iwlegacy/iwl-core.h b/drivers/net/wireless/iwlegacy/iwl-core.h
index f03b463e4378..bc66c604106c 100644
--- a/drivers/net/wireless/iwlegacy/iwl-core.h
+++ b/drivers/net/wireless/iwlegacy/iwl-core.h
@@ -287,7 +287,6 @@ struct iwl_cfg {
struct iwl_base_params *base_params;
/* params likely to change within a device family */
u8 scan_rx_antennas[IEEE80211_NUM_BANDS];
- u8 scan_tx_antennas[IEEE80211_NUM_BANDS];
enum iwl_led_mode led_mode;
};
diff --git a/drivers/net/wireless/iwlegacy/iwl-dev.h b/drivers/net/wireless/iwlegacy/iwl-dev.h
index f43ac1eb9014..be0106c6a2da 100644
--- a/drivers/net/wireless/iwlegacy/iwl-dev.h
+++ b/drivers/net/wireless/iwlegacy/iwl-dev.h
@@ -134,7 +134,7 @@ struct iwl_queue {
* space more than this */
int high_mark; /* high watermark, stop queue if free
* space less than this */
-} __packed;
+};
/* One for each TFD */
struct iwl_tx_info {
@@ -290,6 +290,7 @@ enum {
CMD_SIZE_HUGE = (1 << 0),
CMD_ASYNC = (1 << 1),
CMD_WANT_SKB = (1 << 2),
+ CMD_MAPPED = (1 << 3),
};
#define DEF_CMD_PAYLOAD_SIZE 320
@@ -1076,7 +1077,6 @@ struct iwl_priv {
spinlock_t hcmd_lock; /* protect hcmd */
spinlock_t reg_lock; /* protect hw register access */
struct mutex mutex;
- struct mutex sync_cmd_mutex; /* enable serialization of sync commands */
/* basic pci-network driver stuff */
struct pci_dev *pci_dev;
diff --git a/drivers/net/wireless/iwlegacy/iwl-hcmd.c b/drivers/net/wireless/iwlegacy/iwl-hcmd.c
index 9d721cbda5bb..62b4b09122cb 100644
--- a/drivers/net/wireless/iwlegacy/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlegacy/iwl-hcmd.c
@@ -145,6 +145,8 @@ int iwl_legacy_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
int cmd_idx;
int ret;
+ lockdep_assert_held(&priv->mutex);
+
BUG_ON(cmd->flags & CMD_ASYNC);
/* A synchronous command can not have a callback set. */
@@ -152,7 +154,6 @@ int iwl_legacy_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n",
iwl_legacy_get_cmd_string(cmd->id));
- mutex_lock(&priv->sync_cmd_mutex);
set_bit(STATUS_HCMD_ACTIVE, &priv->status);
IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n",
@@ -224,7 +225,6 @@ fail:
cmd->reply_page = 0;
}
out:
- mutex_unlock(&priv->sync_cmd_mutex);
return ret;
}
EXPORT_SYMBOL(iwl_legacy_send_cmd_sync);
diff --git a/drivers/net/wireless/iwlegacy/iwl-helpers.h b/drivers/net/wireless/iwlegacy/iwl-helpers.h
index 02132e755831..a6effdae63f9 100644
--- a/drivers/net/wireless/iwlegacy/iwl-helpers.h
+++ b/drivers/net/wireless/iwlegacy/iwl-helpers.h
@@ -149,6 +149,12 @@ static inline void iwl_legacy_disable_interrupts(struct iwl_priv *priv)
IWL_DEBUG_ISR(priv, "Disabled interrupts\n");
}
+static inline void iwl_legacy_enable_rfkill_int(struct iwl_priv *priv)
+{
+ IWL_DEBUG_ISR(priv, "Enabling rfkill interrupt\n");
+ iwl_write32(priv, CSR_INT_MASK, CSR_INT_BIT_RF_KILL);
+}
+
static inline void iwl_legacy_enable_interrupts(struct iwl_priv *priv)
{
IWL_DEBUG_ISR(priv, "Enabling interrupts\n");
diff --git a/drivers/net/wireless/iwlegacy/iwl-tx.c b/drivers/net/wireless/iwlegacy/iwl-tx.c
index a227773cb384..4fff995c6f3e 100644
--- a/drivers/net/wireless/iwlegacy/iwl-tx.c
+++ b/drivers/net/wireless/iwlegacy/iwl-tx.c
@@ -146,33 +146,32 @@ void iwl_legacy_cmd_queue_unmap(struct iwl_priv *priv)
{
struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
struct iwl_queue *q = &txq->q;
- bool huge = false;
int i;
if (q->n_bd == 0)
return;
while (q->read_ptr != q->write_ptr) {
- /* we have no way to tell if it is a huge cmd ATM */
i = iwl_legacy_get_cmd_index(q, q->read_ptr, 0);
- if (txq->meta[i].flags & CMD_SIZE_HUGE)
- huge = true;
- else
+ if (txq->meta[i].flags & CMD_MAPPED) {
pci_unmap_single(priv->pci_dev,
dma_unmap_addr(&txq->meta[i], mapping),
dma_unmap_len(&txq->meta[i], len),
PCI_DMA_BIDIRECTIONAL);
+ txq->meta[i].flags = 0;
+ }
q->read_ptr = iwl_legacy_queue_inc_wrap(q->read_ptr, q->n_bd);
}
- if (huge) {
- i = q->n_window;
+ i = q->n_window;
+ if (txq->meta[i].flags & CMD_MAPPED) {
pci_unmap_single(priv->pci_dev,
dma_unmap_addr(&txq->meta[i], mapping),
dma_unmap_len(&txq->meta[i], len),
PCI_DMA_BIDIRECTIONAL);
+ txq->meta[i].flags = 0;
}
}
EXPORT_SYMBOL(iwl_legacy_cmd_queue_unmap);
@@ -467,29 +466,27 @@ int iwl_legacy_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
return -EIO;
}
+ spin_lock_irqsave(&priv->hcmd_lock, flags);
+
if (iwl_legacy_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
- IWL_ERR(priv, "No space in command queue\n");
- IWL_ERR(priv, "Restarting adapter due to queue full\n");
+ spin_unlock_irqrestore(&priv->hcmd_lock, flags);
+
+ IWL_ERR(priv, "Restarting adapter due to command queue full\n");
queue_work(priv->workqueue, &priv->restart);
return -ENOSPC;
}
- spin_lock_irqsave(&priv->hcmd_lock, flags);
-
- /* If this is a huge cmd, mark the huge flag also on the meta.flags
- * of the _original_ cmd. This is used for DMA mapping clean up.
- */
- if (cmd->flags & CMD_SIZE_HUGE) {
- idx = iwl_legacy_get_cmd_index(q, q->write_ptr, 0);
- txq->meta[idx].flags = CMD_SIZE_HUGE;
- }
-
idx = iwl_legacy_get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE);
out_cmd = txq->cmd[idx];
out_meta = &txq->meta[idx];
+ if (WARN_ON(out_meta->flags & CMD_MAPPED)) {
+ spin_unlock_irqrestore(&priv->hcmd_lock, flags);
+ return -ENOSPC;
+ }
+
memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */
- out_meta->flags = cmd->flags;
+ out_meta->flags = cmd->flags | CMD_MAPPED;
if (cmd->flags & CMD_WANT_SKB)
out_meta->source = cmd;
if (cmd->flags & CMD_ASYNC)
@@ -610,6 +607,7 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
struct iwl_device_cmd *cmd;
struct iwl_cmd_meta *meta;
struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
+ unsigned long flags;
/* If a Tx command is being handled and it isn't in the actual
* command queue then there a command routing bug has been introduced
@@ -623,14 +621,6 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
return;
}
- /* If this is a huge cmd, clear the huge flag on the meta.flags
- * of the _original_ cmd. So that iwl_legacy_cmd_queue_free won't unmap
- * the DMA buffer for the scan (huge) command.
- */
- if (huge) {
- cmd_index = iwl_legacy_get_cmd_index(&txq->q, index, 0);
- txq->meta[cmd_index].flags = 0;
- }
cmd_index = iwl_legacy_get_cmd_index(&txq->q, index, huge);
cmd = txq->cmd[cmd_index];
meta = &txq->meta[cmd_index];
@@ -647,6 +637,8 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
} else if (meta->callback)
meta->callback(priv, cmd, pkt);
+ spin_lock_irqsave(&priv->hcmd_lock, flags);
+
iwl_legacy_hcmd_queue_reclaim(priv, txq_id, index, cmd_index);
if (!(meta->flags & CMD_ASYNC)) {
@@ -655,6 +647,10 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
iwl_legacy_get_cmd_string(cmd->hdr.cmd));
wake_up_interruptible(&priv->wait_command_queue);
}
+
+ /* Mark as unmapped */
meta->flags = 0;
+
+ spin_unlock_irqrestore(&priv->hcmd_lock, flags);
}
EXPORT_SYMBOL(iwl_legacy_tx_cmd_complete);
diff --git a/drivers/net/wireless/iwlegacy/iwl3945-base.c b/drivers/net/wireless/iwlegacy/iwl3945-base.c
index cc7ebcee60e5..0ee6be6a9c5d 100644
--- a/drivers/net/wireless/iwlegacy/iwl3945-base.c
+++ b/drivers/net/wireless/iwlegacy/iwl3945-base.c
@@ -2748,11 +2748,12 @@ static void iwl3945_bg_init_alive_start(struct work_struct *data)
struct iwl_priv *priv =
container_of(data, struct iwl_priv, init_alive_start.work);
+ mutex_lock(&priv->mutex);
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
+ goto out;
- mutex_lock(&priv->mutex);
iwl3945_init_alive_start(priv);
+out:
mutex_unlock(&priv->mutex);
}
@@ -2761,11 +2762,12 @@ static void iwl3945_bg_alive_start(struct work_struct *data)
struct iwl_priv *priv =
container_of(data, struct iwl_priv, alive_start.work);
+ mutex_lock(&priv->mutex);
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
+ goto out;
- mutex_lock(&priv->mutex);
iwl3945_alive_start(priv);
+out:
mutex_unlock(&priv->mutex);
}
@@ -2995,10 +2997,12 @@ static void iwl3945_bg_restart(struct work_struct *data)
} else {
iwl3945_down(priv);
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ mutex_lock(&priv->mutex);
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+ mutex_unlock(&priv->mutex);
return;
+ }
- mutex_lock(&priv->mutex);
__iwl3945_up(priv);
mutex_unlock(&priv->mutex);
}
@@ -3009,11 +3013,12 @@ static void iwl3945_bg_rx_replenish(struct work_struct *data)
struct iwl_priv *priv =
container_of(data, struct iwl_priv, rx_replenish);
+ mutex_lock(&priv->mutex);
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
+ goto out;
- mutex_lock(&priv->mutex);
iwl3945_rx_replenish(priv);
+out:
mutex_unlock(&priv->mutex);
}
@@ -3810,7 +3815,6 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
INIT_LIST_HEAD(&priv->free_frames);
mutex_init(&priv->mutex);
- mutex_init(&priv->sync_cmd_mutex);
priv->ieee_channels = NULL;
priv->ieee_rates = NULL;
diff --git a/drivers/net/wireless/iwlegacy/iwl4965-base.c b/drivers/net/wireless/iwlegacy/iwl4965-base.c
index a62fe24ee594..af2ae22fcfd3 100644
--- a/drivers/net/wireless/iwlegacy/iwl4965-base.c
+++ b/drivers/net/wireless/iwlegacy/iwl4965-base.c
@@ -1069,9 +1069,12 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
}
/* Re-enable all interrupts */
- /* only Re-enable if diabled by irq */
+ /* only Re-enable if disabled by irq */
if (test_bit(STATUS_INT_ENABLED, &priv->status))
iwl_legacy_enable_interrupts(priv);
+ /* Re-enable RF_KILL if it occurred */
+ else if (handled & CSR_INT_BIT_RF_KILL)
+ iwl_legacy_enable_rfkill_int(priv);
#ifdef CONFIG_IWLWIFI_LEGACY_DEBUG
if (iwl_legacy_get_debug_level(priv) & (IWL_DL_ISR)) {
@@ -2139,7 +2142,7 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv);
static void __iwl4965_down(struct iwl_priv *priv)
{
unsigned long flags;
- int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status);
+ int exit_pending;
IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n");
@@ -2401,11 +2404,12 @@ static void iwl4965_bg_init_alive_start(struct work_struct *data)
struct iwl_priv *priv =
container_of(data, struct iwl_priv, init_alive_start.work);
+ mutex_lock(&priv->mutex);
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
+ goto out;
- mutex_lock(&priv->mutex);
priv->cfg->ops->lib->init_alive_start(priv);
+out:
mutex_unlock(&priv->mutex);
}
@@ -2414,11 +2418,12 @@ static void iwl4965_bg_alive_start(struct work_struct *data)
struct iwl_priv *priv =
container_of(data, struct iwl_priv, alive_start.work);
+ mutex_lock(&priv->mutex);
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
+ goto out;
- mutex_lock(&priv->mutex);
iwl4965_alive_start(priv);
+out:
mutex_unlock(&priv->mutex);
}
@@ -2468,10 +2473,12 @@ static void iwl4965_bg_restart(struct work_struct *data)
} else {
iwl4965_down(priv);
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ mutex_lock(&priv->mutex);
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+ mutex_unlock(&priv->mutex);
return;
+ }
- mutex_lock(&priv->mutex);
__iwl4965_up(priv);
mutex_unlock(&priv->mutex);
}
@@ -2624,9 +2631,10 @@ void iwl4965_mac_stop(struct ieee80211_hw *hw)
flush_workqueue(priv->workqueue);
- /* enable interrupts again in order to receive rfkill changes */
+ /* User space software may expect getting rfkill changes
+ * even if interface is down */
iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
- iwl_legacy_enable_interrupts(priv);
+ iwl_legacy_enable_rfkill_int(priv);
IWL_DEBUG_MAC80211(priv, "leave\n");
}
@@ -2847,21 +2855,22 @@ void iwl4965_mac_channel_switch(struct ieee80211_hw *hw,
IWL_DEBUG_MAC80211(priv, "enter\n");
+ mutex_lock(&priv->mutex);
+
if (iwl_legacy_is_rfkill(priv))
- goto out_exit;
+ goto out;
if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
test_bit(STATUS_SCANNING, &priv->status))
- goto out_exit;
+ goto out;
if (!iwl_legacy_is_associated_ctx(ctx))
- goto out_exit;
+ goto out;
/* channel switch in progress */
if (priv->switch_rxon.switch_in_progress == true)
- goto out_exit;
+ goto out;
- mutex_lock(&priv->mutex);
if (priv->cfg->ops->lib->set_channel_switch) {
ch = channel->hw_value;
@@ -2917,7 +2926,6 @@ void iwl4965_mac_channel_switch(struct ieee80211_hw *hw,
}
out:
mutex_unlock(&priv->mutex);
-out_exit:
if (!priv->switch_rxon.switch_in_progress)
ieee80211_chswitch_done(ctx->vif, false);
IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -3116,7 +3124,6 @@ static int iwl4965_init_drv(struct iwl_priv *priv)
INIT_LIST_HEAD(&priv->free_frames);
mutex_init(&priv->mutex);
- mutex_init(&priv->sync_cmd_mutex);
priv->ieee_channels = NULL;
priv->ieee_rates = NULL;
@@ -3173,7 +3180,7 @@ static void iwl4965_hw_detect(struct iwl_priv *priv)
{
priv->hw_rev = _iwl_legacy_read32(priv, CSR_HW_REV);
priv->hw_wa_rev = _iwl_legacy_read32(priv, CSR_HW_REV_WA_REG);
- pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &priv->rev_id);
+ priv->rev_id = priv->pci_dev->revision;
IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", priv->rev_id);
}
@@ -3406,14 +3413,14 @@ iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
* 8. Enable interrupts and read RFKILL state
*********************************************/
- /* enable interrupts if needed: hw bug w/a */
+ /* enable rfkill interrupt: hw bug w/a */
pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd);
if (pci_cmd & PCI_COMMAND_INTX_DISABLE) {
pci_cmd &= ~PCI_COMMAND_INTX_DISABLE;
pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd);
}
- iwl_legacy_enable_interrupts(priv);
+ iwl_legacy_enable_rfkill_int(priv);
/* If platform's RF_KILL switch is NOT set to KILL */
if (iwl_read32(priv, CSR_GP_CNTRL) &
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index 17d555f2215a..ad3bdba6beed 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -102,6 +102,16 @@ config IWLWIFI_DEVICE_TRACING
occur.
endmenu
+config IWLWIFI_DEVICE_SVTOOL
+ bool "iwlwifi device svtool support"
+ depends on IWLAGN
+ select NL80211_TESTMODE
+ help
+ This option enables the svtool support for iwlwifi device through
+ NL80211_TESTMODE. svtool is a software validation tool that runs in
+ the user space and interacts with the device in the kernel space
+ through the generic netlink message via NL80211_TESTMODE channel.
+
config IWL_P2P
bool "iwlwifi experimental P2P support"
depends on IWLAGN
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 9d6ee836426c..822660483f9f 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -1,8 +1,8 @@
# AGN
obj-$(CONFIG_IWLAGN) += iwlagn.o
-iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-led.o
+iwlagn-objs := iwl-agn.o iwl-agn-rs.o
iwlagn-objs += iwl-agn-ucode.o iwl-agn-tx.o
-iwlagn-objs += iwl-agn-lib.o iwl-agn-calib.o
+iwlagn-objs += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o
iwlagn-objs += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-eeprom.o
iwlagn-objs += iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o
@@ -14,9 +14,9 @@ iwlagn-objs += iwl-6000.o
iwlagn-objs += iwl-1000.o
iwlagn-objs += iwl-2000.o
-iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-agn-debugfs.o
iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
iwlagn-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
+iwlagn-$(CONFIG_IWLWIFI_DEVICE_SVTOOL) += iwl-sv-open.o
CFLAGS_iwl-devtrace.o := -I$(src)
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 27c5007e577c..61d4a11f566b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 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
@@ -45,8 +45,6 @@
#include "iwl-agn.h"
#include "iwl-helpers.h"
#include "iwl-agn-hw.h"
-#include "iwl-agn-led.h"
-#include "iwl-agn-debugfs.h"
/* Highest firmware API version supported */
#define IWL1000_UCODE_API_MAX 5
@@ -57,12 +55,10 @@
#define IWL100_UCODE_API_MIN 5
#define IWL1000_FW_PRE "iwlwifi-1000-"
-#define _IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode"
-#define IWL1000_MODULE_FIRMWARE(api) _IWL1000_MODULE_FIRMWARE(api)
+#define IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode"
#define IWL100_FW_PRE "iwlwifi-100-"
-#define _IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE #api ".ucode"
-#define IWL100_MODULE_FIRMWARE(api) _IWL100_MODULE_FIRMWARE(api)
+#define IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE #api ".ucode"
/*
@@ -124,10 +120,10 @@ static struct iwl_sensitivity_ranges iwl1000_sensitivity = {
static int iwl1000_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)
+ if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES &&
+ iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES)
priv->cfg->base_params->num_of_queues =
- priv->cfg->mod_params->num_of_queues;
+ iwlagn_mod_params.num_of_queues;
priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
@@ -141,7 +137,6 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
priv->hw_params.max_inst_size = IWLAGN_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;
@@ -176,24 +171,9 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
static struct iwl_lib_ops iwl1000_lib = {
.set_hw_params = iwl1000_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,
.apm_ops = {
@@ -208,45 +188,21 @@ static struct iwl_lib_ops iwl1000_lib = {
EEPROM_REG_BAND_4_CHANNELS,
EEPROM_REG_BAND_5_CHANNELS,
EEPROM_REG_BAND_24_HT40_CHANNELS,
- EEPROM_REG_BAND_52_HT40_CHANNELS
+ EEPROM_REGULATORY_BAND_NO_HT40,
},
- .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
- .release_semaphore = iwlcore_eeprom_release_semaphore,
- .calib_version = iwlagn_eeprom_calib_version,
.query_addr = iwlagn_eeprom_query_addr,
},
- .isr_ops = {
- .isr = iwl_isr_ict,
- .free = iwl_free_isr_ict,
- .alloc = iwl_alloc_isr_ict,
- .reset = iwl_reset_ict,
- .disable = iwl_disable_ict,
- },
.temp_ops = {
.temperature = iwlagn_temperature,
},
- .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,
- .reply_tx_error = iwl_reply_tx_error_read,
- },
.txfifo_flush = iwlagn_txfifo_flush,
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
- .tt_ops = {
- .lower_power_detection = iwl_tt_is_low_power_state,
- .tt_power_mode = iwl_tt_current_power_mode,
- .ct_kill_check = iwl_check_for_ct_kill,
- }
};
static const struct iwl_ops iwl1000_ops = {
.lib = &iwl1000_lib,
.hcmd = &iwlagn_hcmd,
.utils = &iwlagn_hcmd_utils,
- .led = &iwlagn_led_ops,
- .ieee80211_ops = &iwlagn_hw_ops,
};
static struct iwl_base_params iwl1000_base_params = {
@@ -254,8 +210,6 @@ static struct iwl_base_params iwl1000_base_params = {
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
.eeprom_size = OTP_LOW_IMAGE_SIZE,
.pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
- .set_l0s = true,
- .use_bsm = false,
.max_ll_items = OTP_MAX_LL_ITEMS_1000,
.shadow_ram_support = false,
.led_compensation = 51,
@@ -265,9 +219,6 @@ static struct iwl_base_params iwl1000_base_params = {
.chain_noise_scale = 1000,
.wd_timeout = IWL_DEF_WD_TIMEOUT,
.max_event_log_size = 128,
- .ucode_tracing = true,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
};
static struct iwl_ht_params iwl1000_ht_params = {
.ht_greenfield_support = true,
@@ -281,7 +232,6 @@ static struct iwl_ht_params iwl1000_ht_params = {
.eeprom_ver = EEPROM_1000_EEPROM_VERSION, \
.eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \
.ops = &iwl1000_ops, \
- .mod_params = &iwlagn_mod_params, \
.base_params = &iwl1000_base_params, \
.led_mode = IWL_LED_BLINK
@@ -303,7 +253,6 @@ struct iwl_cfg iwl1000_bg_cfg = {
.eeprom_ver = EEPROM_1000_EEPROM_VERSION, \
.eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION, \
.ops = &iwl1000_ops, \
- .mod_params = &iwlagn_mod_params, \
.base_params = &iwl1000_base_params, \
.led_mode = IWL_LED_RF_STATE, \
.rx_with_siso_diversity = true
diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c
index d7b6126408c9..86feec86d130 100644
--- a/drivers/net/wireless/iwlwifi/iwl-2000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-2000.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 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
@@ -46,30 +46,25 @@
#include "iwl-helpers.h"
#include "iwl-agn-hw.h"
#include "iwl-6000-hw.h"
-#include "iwl-agn-led.h"
-#include "iwl-agn-debugfs.h"
/* Highest firmware API version supported */
#define IWL2030_UCODE_API_MAX 5
#define IWL2000_UCODE_API_MAX 5
-#define IWL200_UCODE_API_MAX 5
+#define IWL105_UCODE_API_MAX 5
/* Lowest firmware API version supported */
#define IWL2030_UCODE_API_MIN 5
#define IWL2000_UCODE_API_MIN 5
-#define IWL200_UCODE_API_MIN 5
+#define IWL105_UCODE_API_MIN 5
#define IWL2030_FW_PRE "iwlwifi-2030-"
-#define _IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE #api ".ucode"
-#define IWL2030_MODULE_FIRMWARE(api) _IWL2030_MODULE_FIRMWARE(api)
+#define IWL2030_MODULE_FIRMWARE(api) IWL2030_FW_PRE #api ".ucode"
#define IWL2000_FW_PRE "iwlwifi-2000-"
-#define _IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE #api ".ucode"
-#define IWL2000_MODULE_FIRMWARE(api) _IWL2000_MODULE_FIRMWARE(api)
+#define IWL2000_MODULE_FIRMWARE(api) IWL2000_FW_PRE #api ".ucode"
-#define IWL200_FW_PRE "iwlwifi-200-"
-#define _IWL200_MODULE_FIRMWARE(api) IWL200_FW_PRE #api ".ucode"
-#define IWL200_MODULE_FIRMWARE(api) _IWL200_MODULE_FIRMWARE(api)
+#define IWL105_FW_PRE "iwlwifi-105-"
+#define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE #api ".ucode"
static void iwl2000_set_ct_threshold(struct iwl_priv *priv)
{
@@ -101,6 +96,8 @@ static void iwl2000_nic_config(struct iwl_priv *priv)
iwl_set_bit(priv, CSR_GP_DRIVER_REG,
CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER);
+ if (priv->cfg->disable_otp_refresh)
+ iwl_write_prph(priv, APMG_ANALOG_SVR_REG, 0x80000010);
}
static struct iwl_sensitivity_ranges iwl2000_sensitivity = {
@@ -130,10 +127,10 @@ static struct iwl_sensitivity_ranges iwl2000_sensitivity = {
static int iwl2000_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)
+ if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES &&
+ iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES)
priv->cfg->base_params->num_of_queues =
- priv->cfg->mod_params->num_of_queues;
+ iwlagn_mod_params.num_of_queues;
priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
@@ -147,7 +144,6 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv)
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;
@@ -199,9 +195,9 @@ static int iwl2030_hw_channel_switch(struct iwl_priv *priv,
struct ieee80211_vif *vif = ctx->vif;
struct iwl_host_cmd hcmd = {
.id = REPLY_CHANNEL_SWITCH,
- .len = sizeof(cmd),
+ .len = { sizeof(cmd), },
.flags = CMD_SYNC,
- .data = &cmd,
+ .data = { &cmd, },
};
cmd.band = priv->band == IEEE80211_BAND_2GHZ;
@@ -256,25 +252,10 @@ static int iwl2030_hw_channel_switch(struct iwl_priv *priv,
static struct iwl_lib_ops iwl2000_lib = {
.set_hw_params = iwl2000_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_bt_setup_deferred_work,
.cancel_deferred_work = iwlagn_bt_cancel_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 = iwl2030_hw_channel_switch,
@@ -290,70 +271,40 @@ static struct iwl_lib_ops iwl2000_lib = {
EEPROM_REG_BAND_4_CHANNELS,
EEPROM_REG_BAND_5_CHANNELS,
EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
- EEPROM_REG_BAND_52_HT40_CHANNELS
+ EEPROM_REGULATORY_BAND_NO_HT40,
},
- .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,
},
- .isr_ops = {
- .isr = iwl_isr_ict,
- .free = iwl_free_isr_ict,
- .alloc = iwl_alloc_isr_ict,
- .reset = iwl_reset_ict,
- .disable = iwl_disable_ict,
- },
.temp_ops = {
.temperature = iwlagn_temperature,
},
- .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,
- .reply_tx_error = iwl_reply_tx_error_read,
- },
.txfifo_flush = iwlagn_txfifo_flush,
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
- .tt_ops = {
- .lower_power_detection = iwl_tt_is_low_power_state,
- .tt_power_mode = iwl_tt_current_power_mode,
- .ct_kill_check = iwl_check_for_ct_kill,
- }
};
static const struct iwl_ops iwl2000_ops = {
.lib = &iwl2000_lib,
.hcmd = &iwlagn_hcmd,
.utils = &iwlagn_hcmd_utils,
- .led = &iwlagn_led_ops,
- .ieee80211_ops = &iwlagn_hw_ops,
};
static const struct iwl_ops iwl2030_ops = {
.lib = &iwl2000_lib,
.hcmd = &iwlagn_bt_hcmd,
.utils = &iwlagn_hcmd_utils,
- .led = &iwlagn_led_ops,
- .ieee80211_ops = &iwlagn_hw_ops,
};
-static const struct iwl_ops iwl200_ops = {
+static const struct iwl_ops iwl105_ops = {
.lib = &iwl2000_lib,
.hcmd = &iwlagn_hcmd,
.utils = &iwlagn_hcmd_utils,
- .led = &iwlagn_led_ops,
- .ieee80211_ops = &iwlagn_hw_ops,
};
-static const struct iwl_ops iwl230_ops = {
+static const struct iwl_ops iwl135_ops = {
.lib = &iwl2000_lib,
.hcmd = &iwlagn_bt_hcmd,
.utils = &iwlagn_hcmd_utils,
- .led = &iwlagn_led_ops,
- .ieee80211_ops = &iwlagn_hw_ops,
};
static struct iwl_base_params iwl2000_base_params = {
@@ -361,8 +312,6 @@ static struct iwl_base_params iwl2000_base_params = {
.num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
.pll_cfg_val = 0,
- .set_l0s = true,
- .use_bsm = false,
.max_ll_items = OTP_MAX_LL_ITEMS_2x00,
.shadow_ram_support = true,
.led_compensation = 51,
@@ -373,9 +322,6 @@ static struct iwl_base_params iwl2000_base_params = {
.chain_noise_scale = 1000,
.wd_timeout = IWL_DEF_WD_TIMEOUT,
.max_event_log_size = 512,
- .ucode_tracing = true,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
.shadow_reg_enable = true,
};
@@ -385,8 +331,6 @@ static struct iwl_base_params iwl2030_base_params = {
.num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
.pll_cfg_val = 0,
- .set_l0s = true,
- .use_bsm = false,
.max_ll_items = OTP_MAX_LL_ITEMS_2x00,
.shadow_ram_support = true,
.led_compensation = 57,
@@ -397,9 +341,6 @@ static struct iwl_base_params iwl2030_base_params = {
.chain_noise_scale = 1000,
.wd_timeout = IWL_LONG_WD_TIMEOUT,
.max_event_log_size = 512,
- .ucode_tracing = true,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
.shadow_reg_enable = true,
};
@@ -409,7 +350,6 @@ static struct iwl_ht_params iwl2000_ht_params = {
};
static struct iwl_bt_params iwl2030_bt_params = {
- .bt_statistics = true,
/* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
.advanced_bt_coexist = true,
.agg_time_limit = BT_AGG_THRESHOLD_DEF,
@@ -426,12 +366,12 @@ static struct iwl_bt_params iwl2030_bt_params = {
.eeprom_ver = EEPROM_2000_EEPROM_VERSION, \
.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
.ops = &iwl2000_ops, \
- .mod_params = &iwlagn_mod_params, \
.base_params = &iwl2000_base_params, \
.need_dc_calib = true, \
.need_temp_offset_calib = true, \
.led_mode = IWL_LED_RF_STATE, \
- .iq_invert = true \
+ .iq_invert = true, \
+ .disable_otp_refresh = true \
struct iwl_cfg iwl2000_2bgn_cfg = {
.name = "2000 Series 2x2 BGN",
@@ -451,7 +391,6 @@ struct iwl_cfg iwl2000_2bg_cfg = {
.eeprom_ver = EEPROM_2000_EEPROM_VERSION, \
.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
.ops = &iwl2030_ops, \
- .mod_params = &iwlagn_mod_params, \
.base_params = &iwl2030_base_params, \
.bt_params = &iwl2030_bt_params, \
.need_dc_calib = true, \
@@ -471,45 +410,13 @@ struct iwl_cfg iwl2030_2bg_cfg = {
IWL_DEVICE_2030,
};
-#define IWL_DEVICE_6035 \
- .fw_name_pre = IWL2030_FW_PRE, \
- .ucode_api_max = IWL2030_UCODE_API_MAX, \
- .ucode_api_min = IWL2030_UCODE_API_MIN, \
- .eeprom_ver = EEPROM_6035_EEPROM_VERSION, \
- .eeprom_calib_ver = EEPROM_6035_TX_POWER_VERSION, \
- .ops = &iwl2030_ops, \
- .mod_params = &iwlagn_mod_params, \
- .base_params = &iwl2030_base_params, \
- .bt_params = &iwl2030_bt_params, \
- .need_dc_calib = true, \
- .need_temp_offset_calib = true, \
- .led_mode = IWL_LED_RF_STATE, \
- .adv_pm = true \
-
-struct iwl_cfg iwl6035_2agn_cfg = {
- .name = "2000 Series 2x2 AGN/BT",
- IWL_DEVICE_6035,
- .ht_params = &iwl2000_ht_params,
-};
-
-struct iwl_cfg iwl6035_2abg_cfg = {
- .name = "2000 Series 2x2 ABG/BT",
- IWL_DEVICE_6035,
-};
-
-struct iwl_cfg iwl6035_2bg_cfg = {
- .name = "2000 Series 2x2 BG/BT",
- IWL_DEVICE_6035,
-};
-
-#define IWL_DEVICE_200 \
- .fw_name_pre = IWL200_FW_PRE, \
- .ucode_api_max = IWL200_UCODE_API_MAX, \
- .ucode_api_min = IWL200_UCODE_API_MIN, \
+#define IWL_DEVICE_105 \
+ .fw_name_pre = IWL105_FW_PRE, \
+ .ucode_api_max = IWL105_UCODE_API_MAX, \
+ .ucode_api_min = IWL105_UCODE_API_MIN, \
.eeprom_ver = EEPROM_2000_EEPROM_VERSION, \
.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
- .ops = &iwl200_ops, \
- .mod_params = &iwlagn_mod_params, \
+ .ops = &iwl105_ops, \
.base_params = &iwl2000_base_params, \
.need_dc_calib = true, \
.need_temp_offset_calib = true, \
@@ -517,25 +424,24 @@ struct iwl_cfg iwl6035_2bg_cfg = {
.adv_pm = true, \
.rx_with_siso_diversity = true \
-struct iwl_cfg iwl200_bg_cfg = {
- .name = "200 Series 1x1 BG",
- IWL_DEVICE_200,
+struct iwl_cfg iwl105_bg_cfg = {
+ .name = "105 Series 1x1 BG",
+ IWL_DEVICE_105,
};
-struct iwl_cfg iwl200_bgn_cfg = {
- .name = "200 Series 1x1 BGN",
- IWL_DEVICE_200,
+struct iwl_cfg iwl105_bgn_cfg = {
+ .name = "105 Series 1x1 BGN",
+ IWL_DEVICE_105,
.ht_params = &iwl2000_ht_params,
};
-#define IWL_DEVICE_230 \
- .fw_name_pre = IWL200_FW_PRE, \
- .ucode_api_max = IWL200_UCODE_API_MAX, \
- .ucode_api_min = IWL200_UCODE_API_MIN, \
+#define IWL_DEVICE_135 \
+ .fw_name_pre = IWL105_FW_PRE, \
+ .ucode_api_max = IWL105_UCODE_API_MAX, \
+ .ucode_api_min = IWL105_UCODE_API_MIN, \
.eeprom_ver = EEPROM_2000_EEPROM_VERSION, \
.eeprom_calib_ver = EEPROM_2000_TX_POWER_VERSION, \
- .ops = &iwl230_ops, \
- .mod_params = &iwlagn_mod_params, \
+ .ops = &iwl135_ops, \
.base_params = &iwl2030_base_params, \
.bt_params = &iwl2030_bt_params, \
.need_dc_calib = true, \
@@ -544,17 +450,17 @@ struct iwl_cfg iwl200_bgn_cfg = {
.adv_pm = true, \
.rx_with_siso_diversity = true \
-struct iwl_cfg iwl230_bg_cfg = {
- .name = "200 Series 1x1 BG/BT",
- IWL_DEVICE_230,
+struct iwl_cfg iwl135_bg_cfg = {
+ .name = "105 Series 1x1 BG/BT",
+ IWL_DEVICE_135,
};
-struct iwl_cfg iwl230_bgn_cfg = {
- .name = "200 Series 1x1 BGN/BT",
- IWL_DEVICE_230,
+struct iwl_cfg iwl135_bgn_cfg = {
+ .name = "105 Series 1x1 BGN/BT",
+ IWL_DEVICE_135,
.ht_params = &iwl2000_ht_params,
};
MODULE_FIRMWARE(IWL2000_MODULE_FIRMWARE(IWL2000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL2030_MODULE_FIRMWARE(IWL2030_UCODE_API_MAX));
-MODULE_FIRMWARE(IWL200_MODULE_FIRMWARE(IWL200_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL105_MODULE_FIRMWARE(IWL105_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
index 3975e45e7500..05ad47628b63 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2011 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
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 22e045b5bcee..a70b8cfafda1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2011 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
@@ -45,10 +45,8 @@
#include "iwl-sta.h"
#include "iwl-helpers.h"
#include "iwl-agn.h"
-#include "iwl-agn-led.h"
#include "iwl-agn-hw.h"
#include "iwl-5000-hw.h"
-#include "iwl-agn-debugfs.h"
/* Highest firmware API version supported */
#define IWL5000_UCODE_API_MAX 5
@@ -59,12 +57,10 @@
#define IWL5150_UCODE_API_MIN 1
#define IWL5000_FW_PRE "iwlwifi-5000-"
-#define _IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE #api ".ucode"
-#define IWL5000_MODULE_FIRMWARE(api) _IWL5000_MODULE_FIRMWARE(api)
+#define IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE #api ".ucode"
#define IWL5150_FW_PRE "iwlwifi-5150-"
-#define _IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE #api ".ucode"
-#define IWL5150_MODULE_FIRMWARE(api) _IWL5150_MODULE_FIRMWARE(api)
+#define IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE #api ".ucode"
/* NIC configuration for 5000 series */
static void iwl5000_nic_config(struct iwl_priv *priv)
@@ -168,10 +164,10 @@ static void iwl5000_set_ct_threshold(struct iwl_priv *priv)
static int iwl5000_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)
+ if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES &&
+ iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES)
priv->cfg->base_params->num_of_queues =
- priv->cfg->mod_params->num_of_queues;
+ iwlagn_mod_params.num_of_queues;
priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
@@ -185,7 +181,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
priv->hw_params.max_inst_size = IWLAGN_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;
@@ -214,10 +209,10 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
static int iwl5150_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)
+ if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES &&
+ iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES)
priv->cfg->base_params->num_of_queues =
- priv->cfg->mod_params->num_of_queues;
+ iwlagn_mod_params.num_of_queues;
priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
@@ -231,7 +226,6 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv)
priv->hw_params.max_data_size = IWLAGN_RTC_DATA_SIZE;
priv->hw_params.max_inst_size = IWLAGN_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;
@@ -263,7 +257,7 @@ static void iwl5150_temperature(struct iwl_priv *priv)
u32 vt = 0;
s32 offset = iwl_temp_calib_to_offset(priv);
- vt = le32_to_cpu(priv->_agn.statistics.general.common.temperature);
+ vt = le32_to_cpu(priv->statistics.common.temperature);
vt = vt / IWL_5150_VOLTAGE_TO_TEMPERATURE_COEFF + offset;
/* now vt hold the temperature in Kelvin */
priv->temperature = KELVIN_TO_CELSIUS(vt);
@@ -288,9 +282,9 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
struct ieee80211_vif *vif = ctx->vif;
struct iwl_host_cmd hcmd = {
.id = REPLY_CHANNEL_SWITCH,
- .len = sizeof(cmd),
+ .len = { sizeof(cmd), },
.flags = CMD_SYNC,
- .data = &cmd,
+ .data = { &cmd, },
};
cmd.band = priv->band == IEEE80211_BAND_2GHZ;
@@ -345,24 +339,9 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
static struct iwl_lib_ops iwl5000_lib = {
.set_hw_params = iwl5000_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,
- .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,
- .load_ucode = iwlagn_load_ucode,
- .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 = iwl5000_hw_channel_switch,
@@ -380,56 +359,20 @@ static struct iwl_lib_ops iwl5000_lib = {
EEPROM_REG_BAND_24_HT40_CHANNELS,
EEPROM_REG_BAND_52_HT40_CHANNELS
},
- .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
- .release_semaphore = iwlcore_eeprom_release_semaphore,
- .calib_version = iwlagn_eeprom_calib_version,
.query_addr = iwlagn_eeprom_query_addr,
},
- .isr_ops = {
- .isr = iwl_isr_ict,
- .free = iwl_free_isr_ict,
- .alloc = iwl_alloc_isr_ict,
- .reset = iwl_reset_ict,
- .disable = iwl_disable_ict,
- },
.temp_ops = {
.temperature = iwlagn_temperature,
},
- .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,
- .reply_tx_error = iwl_reply_tx_error_read,
- },
.txfifo_flush = iwlagn_txfifo_flush,
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
- .tt_ops = {
- .lower_power_detection = iwl_tt_is_low_power_state,
- .tt_power_mode = iwl_tt_current_power_mode,
- .ct_kill_check = iwl_check_for_ct_kill,
- }
};
static struct iwl_lib_ops iwl5150_lib = {
.set_hw_params = iwl5150_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,
- .dump_nic_event_log = iwl_dump_nic_event_log,
- .dump_nic_error_log = iwl_dump_nic_error_log,
- .dump_csr = iwl_dump_csr,
- .load_ucode = iwlagn_load_ucode,
- .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 = iwl5000_hw_channel_switch,
@@ -447,51 +390,25 @@ static struct iwl_lib_ops iwl5150_lib = {
EEPROM_REG_BAND_24_HT40_CHANNELS,
EEPROM_REG_BAND_52_HT40_CHANNELS
},
- .acquire_semaphore = iwlcore_eeprom_acquire_semaphore,
- .release_semaphore = iwlcore_eeprom_release_semaphore,
- .calib_version = iwlagn_eeprom_calib_version,
.query_addr = iwlagn_eeprom_query_addr,
},
- .isr_ops = {
- .isr = iwl_isr_ict,
- .free = iwl_free_isr_ict,
- .alloc = iwl_alloc_isr_ict,
- .reset = iwl_reset_ict,
- .disable = iwl_disable_ict,
- },
.temp_ops = {
.temperature = iwl5150_temperature,
},
- .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,
- .reply_tx_error = iwl_reply_tx_error_read,
- },
.txfifo_flush = iwlagn_txfifo_flush,
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
- .tt_ops = {
- .lower_power_detection = iwl_tt_is_low_power_state,
- .tt_power_mode = iwl_tt_current_power_mode,
- .ct_kill_check = iwl_check_for_ct_kill,
- }
};
static const struct iwl_ops iwl5000_ops = {
.lib = &iwl5000_lib,
.hcmd = &iwlagn_hcmd,
.utils = &iwlagn_hcmd_utils,
- .led = &iwlagn_led_ops,
- .ieee80211_ops = &iwlagn_hw_ops,
};
static const struct iwl_ops iwl5150_ops = {
.lib = &iwl5150_lib,
.hcmd = &iwlagn_hcmd,
.utils = &iwlagn_hcmd_utils,
- .led = &iwlagn_led_ops,
- .ieee80211_ops = &iwlagn_hw_ops,
};
static struct iwl_base_params iwl5000_base_params = {
@@ -499,17 +416,12 @@ static struct iwl_base_params iwl5000_base_params = {
.num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
.pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
- .set_l0s = true,
- .use_bsm = false,
.led_compensation = 51,
.chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
.chain_noise_scale = 1000,
.wd_timeout = IWL_LONG_WD_TIMEOUT,
.max_event_log_size = 512,
- .ucode_tracing = true,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
};
static struct iwl_ht_params iwl5000_ht_params = {
.ht_greenfield_support = true,
@@ -523,7 +435,6 @@ static struct iwl_ht_params iwl5000_ht_params = {
.eeprom_ver = EEPROM_5000_EEPROM_VERSION, \
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, \
.ops = &iwl5000_ops, \
- .mod_params = &iwlagn_mod_params, \
.base_params = &iwl5000_base_params, \
.led_mode = IWL_LED_BLINK
@@ -567,7 +478,6 @@ struct iwl_cfg iwl5350_agn_cfg = {
.eeprom_ver = EEPROM_5050_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
.ops = &iwl5000_ops,
- .mod_params = &iwlagn_mod_params,
.base_params = &iwl5000_base_params,
.ht_params = &iwl5000_ht_params,
.led_mode = IWL_LED_BLINK,
@@ -581,7 +491,6 @@ struct iwl_cfg iwl5350_agn_cfg = {
.eeprom_ver = EEPROM_5050_EEPROM_VERSION, \
.eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, \
.ops = &iwl5150_ops, \
- .mod_params = &iwlagn_mod_params, \
.base_params = &iwl5000_base_params, \
.need_dc_calib = true, \
.led_mode = IWL_LED_BLINK, \
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000-hw.h b/drivers/net/wireless/iwlwifi/iwl-6000-hw.h
index 47891e16a758..b27986e57c92 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-6000-hw.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2011 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
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index a745b01c0ec1..f8c710db6e6f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 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
@@ -46,8 +46,6 @@
#include "iwl-helpers.h"
#include "iwl-agn-hw.h"
#include "iwl-6000-hw.h"
-#include "iwl-agn-led.h"
-#include "iwl-agn-debugfs.h"
/* Highest firmware API version supported */
#define IWL6000_UCODE_API_MAX 4
@@ -60,20 +58,16 @@
#define IWL6000G2_UCODE_API_MIN 4
#define IWL6000_FW_PRE "iwlwifi-6000-"
-#define _IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode"
-#define IWL6000_MODULE_FIRMWARE(api) _IWL6000_MODULE_FIRMWARE(api)
+#define IWL6000_MODULE_FIRMWARE(api) IWL6000_FW_PRE #api ".ucode"
#define IWL6050_FW_PRE "iwlwifi-6050-"
-#define _IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode"
-#define IWL6050_MODULE_FIRMWARE(api) _IWL6050_MODULE_FIRMWARE(api)
+#define IWL6050_MODULE_FIRMWARE(api) IWL6050_FW_PRE #api ".ucode"
#define IWL6005_FW_PRE "iwlwifi-6000g2a-"
-#define _IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE #api ".ucode"
-#define IWL6005_MODULE_FIRMWARE(api) _IWL6005_MODULE_FIRMWARE(api)
+#define IWL6005_MODULE_FIRMWARE(api) IWL6005_FW_PRE #api ".ucode"
#define IWL6030_FW_PRE "iwlwifi-6000g2b-"
-#define _IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE #api ".ucode"
-#define IWL6030_MODULE_FIRMWARE(api) _IWL6030_MODULE_FIRMWARE(api)
+#define IWL6030_MODULE_FIRMWARE(api) IWL6030_FW_PRE #api ".ucode"
static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
{
@@ -85,7 +79,7 @@ static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
static void iwl6050_additional_nic_config(struct iwl_priv *priv)
{
/* Indicate calibration version to uCode. */
- if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6)
+ if (iwlagn_eeprom_calib_version(priv) >= 6)
iwl_set_bit(priv, CSR_GP_DRIVER_REG,
CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
}
@@ -93,7 +87,7 @@ static void iwl6050_additional_nic_config(struct iwl_priv *priv)
static void iwl6150_additional_nic_config(struct iwl_priv *priv)
{
/* Indicate calibration version to uCode. */
- if (priv->cfg->ops->lib->eeprom_ops.calib_version(priv) >= 6)
+ if (iwlagn_eeprom_calib_version(priv) >= 6)
iwl_set_bit(priv, CSR_GP_DRIVER_REG,
CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6);
iwl_set_bit(priv, CSR_GP_DRIVER_REG,
@@ -159,10 +153,10 @@ static struct iwl_sensitivity_ranges iwl6000_sensitivity = {
static int iwl6000_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)
+ if (iwlagn_mod_params.num_of_queues >= IWL_MIN_NUM_QUEUES &&
+ iwlagn_mod_params.num_of_queues <= IWLAGN_NUM_QUEUES)
priv->cfg->base_params->num_of_queues =
- priv->cfg->mod_params->num_of_queues;
+ iwlagn_mod_params.num_of_queues;
priv->hw_params.max_txq_num = priv->cfg->base_params->num_of_queues;
priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM;
@@ -176,7 +170,6 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
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;
@@ -228,9 +221,9 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
struct ieee80211_vif *vif = ctx->vif;
struct iwl_host_cmd hcmd = {
.id = REPLY_CHANNEL_SWITCH,
- .len = sizeof(cmd),
+ .len = { sizeof(cmd), },
.flags = CMD_SYNC,
- .data = &cmd,
+ .data = { &cmd, },
};
cmd.band = priv->band == IEEE80211_BAND_2GHZ;
@@ -285,24 +278,9 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
static struct iwl_lib_ops iwl6000_lib = {
.set_hw_params = iwl6000_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,
@@ -320,59 +298,22 @@ static struct iwl_lib_ops iwl6000_lib = {
EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
EEPROM_REG_BAND_52_HT40_CHANNELS
},
- .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,
},
- .isr_ops = {
- .isr = iwl_isr_ict,
- .free = iwl_free_isr_ict,
- .alloc = iwl_alloc_isr_ict,
- .reset = iwl_reset_ict,
- .disable = iwl_disable_ict,
- },
.temp_ops = {
.temperature = iwlagn_temperature,
},
- .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,
- .reply_tx_error = iwl_reply_tx_error_read,
- },
.txfifo_flush = iwlagn_txfifo_flush,
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
- .tt_ops = {
- .lower_power_detection = iwl_tt_is_low_power_state,
- .tt_power_mode = iwl_tt_current_power_mode,
- .ct_kill_check = iwl_check_for_ct_kill,
- }
};
static struct iwl_lib_ops iwl6030_lib = {
.set_hw_params = iwl6000_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_bt_rx_handler_setup,
.setup_deferred_work = iwlagn_bt_setup_deferred_work,
.cancel_deferred_work = iwlagn_bt_cancel_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,
@@ -390,36 +331,14 @@ static struct iwl_lib_ops iwl6030_lib = {
EEPROM_6000_REG_BAND_24_HT40_CHANNELS,
EEPROM_REG_BAND_52_HT40_CHANNELS
},
- .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,
},
- .isr_ops = {
- .isr = iwl_isr_ict,
- .free = iwl_free_isr_ict,
- .alloc = iwl_alloc_isr_ict,
- .reset = iwl_reset_ict,
- .disable = iwl_disable_ict,
- },
.temp_ops = {
.temperature = iwlagn_temperature,
},
- .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,
- .reply_tx_error = iwl_reply_tx_error_read,
- },
.txfifo_flush = iwlagn_txfifo_flush,
.dev_txfifo_flush = iwlagn_dev_txfifo_flush,
- .tt_ops = {
- .lower_power_detection = iwl_tt_is_low_power_state,
- .tt_power_mode = iwl_tt_current_power_mode,
- .ct_kill_check = iwl_check_for_ct_kill,
- }
};
static struct iwl_nic_ops iwl6050_nic_ops = {
@@ -434,34 +353,26 @@ static const struct iwl_ops iwl6000_ops = {
.lib = &iwl6000_lib,
.hcmd = &iwlagn_hcmd,
.utils = &iwlagn_hcmd_utils,
- .led = &iwlagn_led_ops,
- .ieee80211_ops = &iwlagn_hw_ops,
};
static const struct iwl_ops iwl6050_ops = {
.lib = &iwl6000_lib,
.hcmd = &iwlagn_hcmd,
.utils = &iwlagn_hcmd_utils,
- .led = &iwlagn_led_ops,
.nic = &iwl6050_nic_ops,
- .ieee80211_ops = &iwlagn_hw_ops,
};
static const struct iwl_ops iwl6150_ops = {
.lib = &iwl6000_lib,
.hcmd = &iwlagn_hcmd,
.utils = &iwlagn_hcmd_utils,
- .led = &iwlagn_led_ops,
.nic = &iwl6150_nic_ops,
- .ieee80211_ops = &iwlagn_hw_ops,
};
static const struct iwl_ops iwl6030_ops = {
.lib = &iwl6030_lib,
.hcmd = &iwlagn_bt_hcmd,
.utils = &iwlagn_hcmd_utils,
- .led = &iwlagn_led_ops,
- .ieee80211_ops = &iwlagn_hw_ops,
};
static struct iwl_base_params iwl6000_base_params = {
@@ -469,8 +380,6 @@ static struct iwl_base_params iwl6000_base_params = {
.num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
.pll_cfg_val = 0,
- .set_l0s = true,
- .use_bsm = false,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true,
.led_compensation = 51,
@@ -481,9 +390,6 @@ static struct iwl_base_params iwl6000_base_params = {
.chain_noise_scale = 1000,
.wd_timeout = IWL_DEF_WD_TIMEOUT,
.max_event_log_size = 512,
- .ucode_tracing = true,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
.shadow_reg_enable = true,
};
@@ -492,8 +398,6 @@ static struct iwl_base_params iwl6050_base_params = {
.num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
.pll_cfg_val = 0,
- .set_l0s = true,
- .use_bsm = false,
.max_ll_items = OTP_MAX_LL_ITEMS_6x50,
.shadow_ram_support = true,
.led_compensation = 51,
@@ -504,9 +408,6 @@ static struct iwl_base_params iwl6050_base_params = {
.chain_noise_scale = 1500,
.wd_timeout = IWL_DEF_WD_TIMEOUT,
.max_event_log_size = 1024,
- .ucode_tracing = true,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
.shadow_reg_enable = true,
};
static struct iwl_base_params iwl6000_g2_base_params = {
@@ -514,8 +415,6 @@ static struct iwl_base_params iwl6000_g2_base_params = {
.num_of_queues = IWLAGN_NUM_QUEUES,
.num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
.pll_cfg_val = 0,
- .set_l0s = true,
- .use_bsm = false,
.max_ll_items = OTP_MAX_LL_ITEMS_6x00,
.shadow_ram_support = true,
.led_compensation = 57,
@@ -526,9 +425,6 @@ static struct iwl_base_params iwl6000_g2_base_params = {
.chain_noise_scale = 1000,
.wd_timeout = IWL_LONG_WD_TIMEOUT,
.max_event_log_size = 512,
- .ucode_tracing = true,
- .sensitivity_calib_by_driver = true,
- .chain_noise_calib_by_driver = true,
.shadow_reg_enable = true,
};
@@ -538,7 +434,6 @@ static struct iwl_ht_params iwl6000_ht_params = {
};
static struct iwl_bt_params iwl6000_bt_params = {
- .bt_statistics = true,
/* Due to bluetooth, we transmit 2.4 GHz probes only on antenna A */
.advanced_bt_coexist = true,
.agg_time_limit = BT_AGG_THRESHOLD_DEF,
@@ -554,7 +449,6 @@ static struct iwl_bt_params iwl6000_bt_params = {
.eeprom_ver = EEPROM_6005_EEPROM_VERSION, \
.eeprom_calib_ver = EEPROM_6005_TX_POWER_VERSION, \
.ops = &iwl6000_ops, \
- .mod_params = &iwlagn_mod_params, \
.base_params = &iwl6000_g2_base_params, \
.need_dc_calib = true, \
.need_temp_offset_calib = true, \
@@ -583,7 +477,6 @@ struct iwl_cfg iwl6005_2bg_cfg = {
.eeprom_ver = EEPROM_6030_EEPROM_VERSION, \
.eeprom_calib_ver = EEPROM_6030_TX_POWER_VERSION, \
.ops = &iwl6030_ops, \
- .mod_params = &iwlagn_mod_params, \
.base_params = &iwl6000_g2_base_params, \
.bt_params = &iwl6000_bt_params, \
.need_dc_calib = true, \
@@ -613,6 +506,22 @@ struct iwl_cfg iwl6030_2bg_cfg = {
IWL_DEVICE_6030,
};
+struct iwl_cfg iwl6035_2agn_cfg = {
+ .name = "6035 Series 2x2 AGN/BT",
+ IWL_DEVICE_6030,
+ .ht_params = &iwl6000_ht_params,
+};
+
+struct iwl_cfg iwl6035_2abg_cfg = {
+ .name = "6035 Series 2x2 ABG/BT",
+ IWL_DEVICE_6030,
+};
+
+struct iwl_cfg iwl6035_2bg_cfg = {
+ .name = "6035 Series 2x2 BG/BT",
+ IWL_DEVICE_6030,
+};
+
struct iwl_cfg iwl1030_bgn_cfg = {
.name = "Intel(R) Centrino(R) Wireless-N 1030 BGN",
IWL_DEVICE_6030,
@@ -649,7 +558,6 @@ struct iwl_cfg iwl130_bg_cfg = {
.eeprom_ver = EEPROM_6000_EEPROM_VERSION, \
.eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION, \
.ops = &iwl6000_ops, \
- .mod_params = &iwlagn_mod_params, \
.base_params = &iwl6000_base_params, \
.pa_type = IWL_PA_INTERNAL, \
.led_mode = IWL_LED_BLINK
@@ -679,7 +587,6 @@ struct iwl_cfg iwl6000i_2bg_cfg = {
.ops = &iwl6050_ops, \
.eeprom_ver = EEPROM_6050_EEPROM_VERSION, \
.eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION, \
- .mod_params = &iwlagn_mod_params, \
.base_params = &iwl6050_base_params, \
.need_dc_calib = true, \
.led_mode = IWL_LED_BLINK, \
@@ -704,7 +611,6 @@ struct iwl_cfg iwl6150_bgn_cfg = {
.eeprom_ver = EEPROM_6150_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_6150_TX_POWER_VERSION,
.ops = &iwl6150_ops,
- .mod_params = &iwlagn_mod_params,
.base_params = &iwl6050_base_params,
.ht_params = &iwl6000_ht_params,
.need_dc_calib = true,
@@ -720,7 +626,6 @@ struct iwl_cfg iwl6000_3agn_cfg = {
.eeprom_ver = EEPROM_6000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
.ops = &iwl6000_ops,
- .mod_params = &iwlagn_mod_params,
.base_params = &iwl6000_base_params,
.ht_params = &iwl6000_ht_params,
.need_dc_calib = true,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
index 9006293e740c..c9255def1080 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.c
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 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
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -87,14 +87,14 @@ int iwl_send_calib_results(struct iwl_priv *priv)
struct iwl_host_cmd hcmd = {
.id = REPLY_PHY_CALIBRATION_CMD,
- .flags = CMD_SIZE_HUGE,
};
for (i = 0; i < IWL_CALIB_MAX; i++) {
if ((BIT(i) & priv->hw_params.calib_init_cfg) &&
priv->calib_results[i].buf) {
- hcmd.len = priv->calib_results[i].buf_len;
- hcmd.data = priv->calib_results[i].buf;
+ hcmd.len[0] = priv->calib_results[i].buf_len;
+ hcmd.data[0] = priv->calib_results[i].buf;
+ hcmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
ret = iwl_send_cmd_sync(priv, &hcmd);
if (ret) {
IWL_ERR(priv, "Error %d iteration %d\n",
@@ -456,9 +456,9 @@ static int iwl_sensitivity_write(struct iwl_priv *priv)
struct iwl_sensitivity_data *data = NULL;
struct iwl_host_cmd cmd_out = {
.id = SENSITIVITY_CMD,
- .len = sizeof(struct iwl_sensitivity_cmd),
+ .len = { sizeof(struct iwl_sensitivity_cmd), },
.flags = CMD_ASYNC,
- .data = &cmd,
+ .data = { &cmd, },
};
data = &(priv->sensitivity_data);
@@ -491,9 +491,9 @@ static int iwl_enhance_sensitivity_write(struct iwl_priv *priv)
struct iwl_sensitivity_data *data = NULL;
struct iwl_host_cmd cmd_out = {
.id = SENSITIVITY_CMD,
- .len = sizeof(struct iwl_enhance_sensitivity_cmd),
+ .len = { sizeof(struct iwl_enhance_sensitivity_cmd), },
.flags = CMD_ASYNC,
- .data = &cmd,
+ .data = { &cmd, },
};
data = &(priv->sensitivity_data);
@@ -605,7 +605,7 @@ void iwl_init_sensitivity(struct iwl_priv *priv)
IWL_DEBUG_CALIB(priv, "<<return 0x%X\n", ret);
}
-void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp)
+void iwl_sensitivity_calibration(struct iwl_priv *priv)
{
u32 rx_enable_time;
u32 fa_cck;
@@ -631,16 +631,9 @@ void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp)
}
spin_lock_irqsave(&priv->lock, flags);
- if (iwl_bt_statistics(priv)) {
- 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);
- }
+ rx_info = &priv->statistics.rx_non_phy;
+ ofdm = &priv->statistics.rx_ofdm;
+ cck = &priv->statistics.rx_cck;
if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
IWL_DEBUG_CALIB(priv, "<< invalid data.\n");
spin_unlock_irqrestore(&priv->lock, flags);
@@ -824,8 +817,8 @@ static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig,
find_first_chain(priv->cfg->valid_tx_ant);
data->disconn_array[first_chain] = 0;
active_chains |= BIT(first_chain);
- IWL_DEBUG_CALIB(priv, "All Tx chains are disconnected \
- W/A - declare %d as connected\n",
+ IWL_DEBUG_CALIB(priv,
+ "All Tx chains are disconnected W/A - declare %d as connected\n",
first_chain);
break;
}
@@ -851,7 +844,7 @@ static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig,
* 1) Which antennas are connected.
* 2) Differential rx gain settings to balance the 3 receivers.
*/
-void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
+void iwl_chain_noise_calibration(struct iwl_priv *priv)
{
struct iwl_chain_noise_data *data = NULL;
@@ -896,13 +889,9 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
}
spin_lock_irqsave(&priv->lock, flags);
- if (iwl_bt_statistics(priv)) {
- rx_info = &(((struct iwl_bt_notif_statistics *)stat_resp)->
- rx.general.common);
- } else {
- rx_info = &(((struct iwl_notif_statistics *)stat_resp)->
- rx.general);
- }
+
+ rx_info = &priv->statistics.rx_non_phy;
+
if (rx_info->interference_data_flag != INTERFERENCE_DATA_AVAILABLE) {
IWL_DEBUG_CALIB(priv, " << Interference data unavailable\n");
spin_unlock_irqrestore(&priv->lock, flags);
@@ -911,19 +900,9 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp)
rxon_band24 = !!(ctx->staging.flags & RXON_FLG_BAND_24G_MSK);
rxon_chnum = le16_to_cpu(ctx->staging.channel);
- if (iwl_bt_statistics(priv)) {
- 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;
- }
+ stat_band24 =
+ !!(priv->statistics.flag & STATISTICS_REPLY_FLG_BAND_24G_MSK);
+ stat_chnum = le32_to_cpu(priv->statistics.flag) >> 16;
/* Make sure we accumulate data for just the associated channel
* (even if scanning). */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-calib.h b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h
index e37ae7261630..4ef4dd934254 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-calib.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-calib.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 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
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -66,8 +66,8 @@
#include "iwl-core.h"
#include "iwl-commands.h"
-void iwl_chain_noise_calibration(struct iwl_priv *priv, void *stat_resp);
-void iwl_sensitivity_calibration(struct iwl_priv *priv, void *resp);
+void iwl_chain_noise_calibration(struct iwl_priv *priv);
+void iwl_sensitivity_calibration(struct iwl_priv *priv);
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-agn-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
deleted file mode 100644
index b500aaae53ec..000000000000
--- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
+++ /dev/null
@@ -1,1073 +0,0 @@
-/******************************************************************************
-*
-* 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 "iwl-agn.h"
-#include "iwl-agn-debugfs.h"
-
-static const char *fmt_value = " %-30s %10u\n";
-static const char *fmt_hex = " %-30s 0x%02X\n";
-static const char *fmt_table = " %-30s %10u %10u %10u %10u\n";
-static const char *fmt_header =
- "%-32s current cumulative delta max\n";
-
-static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
-{
- int p = 0;
- u32 flag;
-
- if (iwl_bt_statistics(priv))
- 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)
- {
- struct iwl_priv *priv = file->private_data;
- int pos = 0;
- char *buf;
- int bufsz = sizeof(struct statistics_rx_phy) * 40 +
- sizeof(struct statistics_rx_non_phy) * 40 +
- sizeof(struct statistics_rx_ht_phy) * 40 + 400;
- ssize_t ret;
- struct statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm;
- struct statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck;
- struct statistics_rx_non_phy *general, *accum_general;
- struct statistics_rx_non_phy *delta_general, *max_general;
- struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht;
-
- if (!iwl_is_alive(priv))
- 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
- */
- if (iwl_bt_statistics(priv)) {
- 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,
- fmt_header, "Statistics_Rx - OFDM:");
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "ina_cnt:",
- le32_to_cpu(ofdm->ina_cnt),
- accum_ofdm->ina_cnt,
- delta_ofdm->ina_cnt, max_ofdm->ina_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "fina_cnt:",
- le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt,
- delta_ofdm->fina_cnt, max_ofdm->fina_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "plcp_err:",
- le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err,
- delta_ofdm->plcp_err, max_ofdm->plcp_err);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "crc32_err:",
- le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err,
- delta_ofdm->crc32_err, max_ofdm->crc32_err);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "overrun_err:",
- le32_to_cpu(ofdm->overrun_err),
- accum_ofdm->overrun_err, delta_ofdm->overrun_err,
- max_ofdm->overrun_err);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "early_overrun_err:",
- le32_to_cpu(ofdm->early_overrun_err),
- accum_ofdm->early_overrun_err,
- delta_ofdm->early_overrun_err,
- max_ofdm->early_overrun_err);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "crc32_good:",
- le32_to_cpu(ofdm->crc32_good),
- accum_ofdm->crc32_good, delta_ofdm->crc32_good,
- max_ofdm->crc32_good);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "false_alarm_cnt:",
- le32_to_cpu(ofdm->false_alarm_cnt),
- accum_ofdm->false_alarm_cnt,
- delta_ofdm->false_alarm_cnt,
- max_ofdm->false_alarm_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "fina_sync_err_cnt:",
- le32_to_cpu(ofdm->fina_sync_err_cnt),
- accum_ofdm->fina_sync_err_cnt,
- delta_ofdm->fina_sync_err_cnt,
- max_ofdm->fina_sync_err_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "sfd_timeout:",
- le32_to_cpu(ofdm->sfd_timeout),
- accum_ofdm->sfd_timeout, delta_ofdm->sfd_timeout,
- max_ofdm->sfd_timeout);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "fina_timeout:",
- le32_to_cpu(ofdm->fina_timeout),
- accum_ofdm->fina_timeout, delta_ofdm->fina_timeout,
- max_ofdm->fina_timeout);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "unresponded_rts:",
- le32_to_cpu(ofdm->unresponded_rts),
- accum_ofdm->unresponded_rts,
- delta_ofdm->unresponded_rts,
- max_ofdm->unresponded_rts);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "rxe_frame_lmt_ovrun:",
- le32_to_cpu(ofdm->rxe_frame_limit_overrun),
- accum_ofdm->rxe_frame_limit_overrun,
- delta_ofdm->rxe_frame_limit_overrun,
- max_ofdm->rxe_frame_limit_overrun);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "sent_ack_cnt:",
- le32_to_cpu(ofdm->sent_ack_cnt),
- accum_ofdm->sent_ack_cnt, delta_ofdm->sent_ack_cnt,
- max_ofdm->sent_ack_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "sent_cts_cnt:",
- le32_to_cpu(ofdm->sent_cts_cnt),
- accum_ofdm->sent_cts_cnt, delta_ofdm->sent_cts_cnt,
- max_ofdm->sent_cts_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "sent_ba_rsp_cnt:",
- le32_to_cpu(ofdm->sent_ba_rsp_cnt),
- accum_ofdm->sent_ba_rsp_cnt,
- delta_ofdm->sent_ba_rsp_cnt,
- max_ofdm->sent_ba_rsp_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "dsp_self_kill:",
- le32_to_cpu(ofdm->dsp_self_kill),
- accum_ofdm->dsp_self_kill,
- delta_ofdm->dsp_self_kill,
- max_ofdm->dsp_self_kill);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "mh_format_err:",
- le32_to_cpu(ofdm->mh_format_err),
- accum_ofdm->mh_format_err,
- delta_ofdm->mh_format_err,
- max_ofdm->mh_format_err);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "re_acq_main_rssi_sum:",
- le32_to_cpu(ofdm->re_acq_main_rssi_sum),
- accum_ofdm->re_acq_main_rssi_sum,
- delta_ofdm->re_acq_main_rssi_sum,
- max_ofdm->re_acq_main_rssi_sum);
-
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_header, "Statistics_Rx - CCK:");
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "ina_cnt:",
- le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt,
- delta_cck->ina_cnt, max_cck->ina_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "fina_cnt:",
- le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt,
- delta_cck->fina_cnt, max_cck->fina_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "plcp_err:",
- le32_to_cpu(cck->plcp_err), accum_cck->plcp_err,
- delta_cck->plcp_err, max_cck->plcp_err);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "crc32_err:",
- le32_to_cpu(cck->crc32_err), accum_cck->crc32_err,
- delta_cck->crc32_err, max_cck->crc32_err);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "overrun_err:",
- le32_to_cpu(cck->overrun_err),
- accum_cck->overrun_err, delta_cck->overrun_err,
- max_cck->overrun_err);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "early_overrun_err:",
- le32_to_cpu(cck->early_overrun_err),
- accum_cck->early_overrun_err,
- delta_cck->early_overrun_err,
- max_cck->early_overrun_err);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "crc32_good:",
- le32_to_cpu(cck->crc32_good), accum_cck->crc32_good,
- delta_cck->crc32_good, max_cck->crc32_good);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "false_alarm_cnt:",
- le32_to_cpu(cck->false_alarm_cnt),
- accum_cck->false_alarm_cnt,
- delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "fina_sync_err_cnt:",
- le32_to_cpu(cck->fina_sync_err_cnt),
- accum_cck->fina_sync_err_cnt,
- delta_cck->fina_sync_err_cnt,
- max_cck->fina_sync_err_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "sfd_timeout:",
- le32_to_cpu(cck->sfd_timeout),
- accum_cck->sfd_timeout, delta_cck->sfd_timeout,
- max_cck->sfd_timeout);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "fina_timeout:",
- le32_to_cpu(cck->fina_timeout),
- accum_cck->fina_timeout, delta_cck->fina_timeout,
- max_cck->fina_timeout);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "unresponded_rts:",
- le32_to_cpu(cck->unresponded_rts),
- accum_cck->unresponded_rts, delta_cck->unresponded_rts,
- max_cck->unresponded_rts);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "rxe_frame_lmt_ovrun:",
- le32_to_cpu(cck->rxe_frame_limit_overrun),
- accum_cck->rxe_frame_limit_overrun,
- delta_cck->rxe_frame_limit_overrun,
- max_cck->rxe_frame_limit_overrun);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "sent_ack_cnt:",
- le32_to_cpu(cck->sent_ack_cnt),
- accum_cck->sent_ack_cnt, delta_cck->sent_ack_cnt,
- max_cck->sent_ack_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "sent_cts_cnt:",
- le32_to_cpu(cck->sent_cts_cnt),
- accum_cck->sent_cts_cnt, delta_cck->sent_cts_cnt,
- max_cck->sent_cts_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "sent_ba_rsp_cnt:",
- le32_to_cpu(cck->sent_ba_rsp_cnt),
- accum_cck->sent_ba_rsp_cnt,
- delta_cck->sent_ba_rsp_cnt,
- max_cck->sent_ba_rsp_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "dsp_self_kill:",
- le32_to_cpu(cck->dsp_self_kill),
- accum_cck->dsp_self_kill, delta_cck->dsp_self_kill,
- max_cck->dsp_self_kill);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "mh_format_err:",
- le32_to_cpu(cck->mh_format_err),
- accum_cck->mh_format_err, delta_cck->mh_format_err,
- max_cck->mh_format_err);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "re_acq_main_rssi_sum:",
- le32_to_cpu(cck->re_acq_main_rssi_sum),
- accum_cck->re_acq_main_rssi_sum,
- delta_cck->re_acq_main_rssi_sum,
- max_cck->re_acq_main_rssi_sum);
-
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_header, "Statistics_Rx - GENERAL:");
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "bogus_cts:",
- le32_to_cpu(general->bogus_cts),
- accum_general->bogus_cts, delta_general->bogus_cts,
- max_general->bogus_cts);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "bogus_ack:",
- le32_to_cpu(general->bogus_ack),
- accum_general->bogus_ack, delta_general->bogus_ack,
- max_general->bogus_ack);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "non_bssid_frames:",
- le32_to_cpu(general->non_bssid_frames),
- accum_general->non_bssid_frames,
- delta_general->non_bssid_frames,
- max_general->non_bssid_frames);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "filtered_frames:",
- le32_to_cpu(general->filtered_frames),
- accum_general->filtered_frames,
- delta_general->filtered_frames,
- max_general->filtered_frames);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "non_channel_beacons:",
- le32_to_cpu(general->non_channel_beacons),
- accum_general->non_channel_beacons,
- delta_general->non_channel_beacons,
- max_general->non_channel_beacons);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "channel_beacons:",
- le32_to_cpu(general->channel_beacons),
- accum_general->channel_beacons,
- delta_general->channel_beacons,
- max_general->channel_beacons);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "num_missed_bcon:",
- le32_to_cpu(general->num_missed_bcon),
- accum_general->num_missed_bcon,
- delta_general->num_missed_bcon,
- max_general->num_missed_bcon);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "adc_rx_saturation_time:",
- le32_to_cpu(general->adc_rx_saturation_time),
- accum_general->adc_rx_saturation_time,
- delta_general->adc_rx_saturation_time,
- max_general->adc_rx_saturation_time);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "ina_detect_search_tm:",
- le32_to_cpu(general->ina_detection_search_time),
- accum_general->ina_detection_search_time,
- delta_general->ina_detection_search_time,
- max_general->ina_detection_search_time);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "beacon_silence_rssi_a:",
- le32_to_cpu(general->beacon_silence_rssi_a),
- accum_general->beacon_silence_rssi_a,
- delta_general->beacon_silence_rssi_a,
- max_general->beacon_silence_rssi_a);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "beacon_silence_rssi_b:",
- le32_to_cpu(general->beacon_silence_rssi_b),
- accum_general->beacon_silence_rssi_b,
- delta_general->beacon_silence_rssi_b,
- max_general->beacon_silence_rssi_b);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "beacon_silence_rssi_c:",
- le32_to_cpu(general->beacon_silence_rssi_c),
- accum_general->beacon_silence_rssi_c,
- delta_general->beacon_silence_rssi_c,
- max_general->beacon_silence_rssi_c);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "interference_data_flag:",
- le32_to_cpu(general->interference_data_flag),
- accum_general->interference_data_flag,
- delta_general->interference_data_flag,
- max_general->interference_data_flag);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "channel_load:",
- le32_to_cpu(general->channel_load),
- accum_general->channel_load,
- delta_general->channel_load,
- max_general->channel_load);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "dsp_false_alarms:",
- le32_to_cpu(general->dsp_false_alarms),
- accum_general->dsp_false_alarms,
- delta_general->dsp_false_alarms,
- max_general->dsp_false_alarms);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "beacon_rssi_a:",
- le32_to_cpu(general->beacon_rssi_a),
- accum_general->beacon_rssi_a,
- delta_general->beacon_rssi_a,
- max_general->beacon_rssi_a);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "beacon_rssi_b:",
- le32_to_cpu(general->beacon_rssi_b),
- accum_general->beacon_rssi_b,
- delta_general->beacon_rssi_b,
- max_general->beacon_rssi_b);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "beacon_rssi_c:",
- le32_to_cpu(general->beacon_rssi_c),
- accum_general->beacon_rssi_c,
- delta_general->beacon_rssi_c,
- max_general->beacon_rssi_c);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "beacon_energy_a:",
- le32_to_cpu(general->beacon_energy_a),
- accum_general->beacon_energy_a,
- delta_general->beacon_energy_a,
- max_general->beacon_energy_a);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "beacon_energy_b:",
- le32_to_cpu(general->beacon_energy_b),
- accum_general->beacon_energy_b,
- delta_general->beacon_energy_b,
- max_general->beacon_energy_b);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "beacon_energy_c:",
- le32_to_cpu(general->beacon_energy_c),
- accum_general->beacon_energy_c,
- delta_general->beacon_energy_c,
- max_general->beacon_energy_c);
-
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_header, "Statistics_Rx - OFDM_HT:");
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "plcp_err:",
- le32_to_cpu(ht->plcp_err), accum_ht->plcp_err,
- delta_ht->plcp_err, max_ht->plcp_err);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "overrun_err:",
- le32_to_cpu(ht->overrun_err), accum_ht->overrun_err,
- delta_ht->overrun_err, max_ht->overrun_err);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "early_overrun_err:",
- le32_to_cpu(ht->early_overrun_err),
- accum_ht->early_overrun_err,
- delta_ht->early_overrun_err,
- max_ht->early_overrun_err);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "crc32_good:",
- le32_to_cpu(ht->crc32_good), accum_ht->crc32_good,
- delta_ht->crc32_good, max_ht->crc32_good);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "crc32_err:",
- le32_to_cpu(ht->crc32_err), accum_ht->crc32_err,
- delta_ht->crc32_err, max_ht->crc32_err);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "mh_format_err:",
- le32_to_cpu(ht->mh_format_err),
- accum_ht->mh_format_err,
- delta_ht->mh_format_err, max_ht->mh_format_err);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "agg_crc32_good:",
- le32_to_cpu(ht->agg_crc32_good),
- accum_ht->agg_crc32_good,
- delta_ht->agg_crc32_good, max_ht->agg_crc32_good);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "agg_mpdu_cnt:",
- le32_to_cpu(ht->agg_mpdu_cnt),
- accum_ht->agg_mpdu_cnt,
- delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "agg_cnt:",
- le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt,
- delta_ht->agg_cnt, max_ht->agg_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "unsupport_mcs:",
- le32_to_cpu(ht->unsupport_mcs),
- accum_ht->unsupport_mcs,
- delta_ht->unsupport_mcs, max_ht->unsupport_mcs);
-
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
- kfree(buf);
- return ret;
-}
-
-ssize_t iwl_ucode_tx_stats_read(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct iwl_priv *priv = file->private_data;
- int pos = 0;
- char *buf;
- int bufsz = (sizeof(struct statistics_tx) * 48) + 250;
- ssize_t ret;
- struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx;
-
- if (!iwl_is_alive(priv))
- 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
- */
- if (iwl_bt_statistics(priv)) {
- 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,
- fmt_header, "Statistics_Tx:");
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "preamble:",
- le32_to_cpu(tx->preamble_cnt),
- accum_tx->preamble_cnt,
- delta_tx->preamble_cnt, max_tx->preamble_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "rx_detected_cnt:",
- le32_to_cpu(tx->rx_detected_cnt),
- accum_tx->rx_detected_cnt,
- delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "bt_prio_defer_cnt:",
- le32_to_cpu(tx->bt_prio_defer_cnt),
- accum_tx->bt_prio_defer_cnt,
- delta_tx->bt_prio_defer_cnt,
- max_tx->bt_prio_defer_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "bt_prio_kill_cnt:",
- le32_to_cpu(tx->bt_prio_kill_cnt),
- accum_tx->bt_prio_kill_cnt,
- delta_tx->bt_prio_kill_cnt,
- max_tx->bt_prio_kill_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "few_bytes_cnt:",
- le32_to_cpu(tx->few_bytes_cnt),
- accum_tx->few_bytes_cnt,
- delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "cts_timeout:",
- le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout,
- delta_tx->cts_timeout, max_tx->cts_timeout);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "ack_timeout:",
- le32_to_cpu(tx->ack_timeout),
- accum_tx->ack_timeout,
- delta_tx->ack_timeout, max_tx->ack_timeout);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "expected_ack_cnt:",
- le32_to_cpu(tx->expected_ack_cnt),
- accum_tx->expected_ack_cnt,
- delta_tx->expected_ack_cnt,
- max_tx->expected_ack_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "actual_ack_cnt:",
- le32_to_cpu(tx->actual_ack_cnt),
- accum_tx->actual_ack_cnt,
- delta_tx->actual_ack_cnt,
- max_tx->actual_ack_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "dump_msdu_cnt:",
- le32_to_cpu(tx->dump_msdu_cnt),
- accum_tx->dump_msdu_cnt,
- delta_tx->dump_msdu_cnt,
- max_tx->dump_msdu_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "abort_nxt_frame_mismatch:",
- le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt),
- accum_tx->burst_abort_next_frame_mismatch_cnt,
- delta_tx->burst_abort_next_frame_mismatch_cnt,
- max_tx->burst_abort_next_frame_mismatch_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "abort_missing_nxt_frame:",
- le32_to_cpu(tx->burst_abort_missing_next_frame_cnt),
- accum_tx->burst_abort_missing_next_frame_cnt,
- delta_tx->burst_abort_missing_next_frame_cnt,
- max_tx->burst_abort_missing_next_frame_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "cts_timeout_collision:",
- le32_to_cpu(tx->cts_timeout_collision),
- accum_tx->cts_timeout_collision,
- delta_tx->cts_timeout_collision,
- max_tx->cts_timeout_collision);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "ack_ba_timeout_collision:",
- le32_to_cpu(tx->ack_or_ba_timeout_collision),
- accum_tx->ack_or_ba_timeout_collision,
- delta_tx->ack_or_ba_timeout_collision,
- max_tx->ack_or_ba_timeout_collision);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "agg ba_timeout:",
- le32_to_cpu(tx->agg.ba_timeout),
- accum_tx->agg.ba_timeout,
- delta_tx->agg.ba_timeout,
- max_tx->agg.ba_timeout);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "agg ba_resched_frames:",
- le32_to_cpu(tx->agg.ba_reschedule_frames),
- accum_tx->agg.ba_reschedule_frames,
- delta_tx->agg.ba_reschedule_frames,
- max_tx->agg.ba_reschedule_frames);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "agg scd_query_agg_frame:",
- le32_to_cpu(tx->agg.scd_query_agg_frame_cnt),
- accum_tx->agg.scd_query_agg_frame_cnt,
- delta_tx->agg.scd_query_agg_frame_cnt,
- max_tx->agg.scd_query_agg_frame_cnt);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "agg scd_query_no_agg:",
- le32_to_cpu(tx->agg.scd_query_no_agg),
- accum_tx->agg.scd_query_no_agg,
- delta_tx->agg.scd_query_no_agg,
- max_tx->agg.scd_query_no_agg);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "agg scd_query_agg:",
- le32_to_cpu(tx->agg.scd_query_agg),
- accum_tx->agg.scd_query_agg,
- delta_tx->agg.scd_query_agg,
- max_tx->agg.scd_query_agg);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "agg scd_query_mismatch:",
- le32_to_cpu(tx->agg.scd_query_mismatch),
- accum_tx->agg.scd_query_mismatch,
- delta_tx->agg.scd_query_mismatch,
- max_tx->agg.scd_query_mismatch);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "agg frame_not_ready:",
- le32_to_cpu(tx->agg.frame_not_ready),
- accum_tx->agg.frame_not_ready,
- delta_tx->agg.frame_not_ready,
- max_tx->agg.frame_not_ready);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "agg underrun:",
- le32_to_cpu(tx->agg.underrun),
- accum_tx->agg.underrun,
- delta_tx->agg.underrun, max_tx->agg.underrun);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "agg bt_prio_kill:",
- le32_to_cpu(tx->agg.bt_prio_kill),
- accum_tx->agg.bt_prio_kill,
- delta_tx->agg.bt_prio_kill,
- max_tx->agg.bt_prio_kill);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "agg rx_ba_rsp_cnt:",
- le32_to_cpu(tx->agg.rx_ba_rsp_cnt),
- accum_tx->agg.rx_ba_rsp_cnt,
- delta_tx->agg.rx_ba_rsp_cnt,
- max_tx->agg.rx_ba_rsp_cnt);
-
- if (tx->tx_power.ant_a || tx->tx_power.ant_b || tx->tx_power.ant_c) {
- pos += scnprintf(buf + pos, bufsz - pos,
- "tx power: (1/2 dB step)\n");
- if ((priv->cfg->valid_tx_ant & ANT_A) && tx->tx_power.ant_a)
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_hex, "antenna A:",
- tx->tx_power.ant_a);
- if ((priv->cfg->valid_tx_ant & ANT_B) && tx->tx_power.ant_b)
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_hex, "antenna B:",
- tx->tx_power.ant_b);
- if ((priv->cfg->valid_tx_ant & ANT_C) && tx->tx_power.ant_c)
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_hex, "antenna C:",
- tx->tx_power.ant_c);
- }
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
- kfree(buf);
- return ret;
-}
-
-ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct iwl_priv *priv = file->private_data;
- int pos = 0;
- char *buf;
- int bufsz = sizeof(struct statistics_general) * 10 + 300;
- ssize_t ret;
- 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;
-
- if (!iwl_is_alive(priv))
- 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
- */
- if (iwl_bt_statistics(priv)) {
- 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,
- fmt_header, "Statistics_General:");
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_value, "temperature:",
- le32_to_cpu(general->temperature));
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_value, "temperature_m:",
- le32_to_cpu(general->temperature_m));
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_value, "ttl_timestamp:",
- le32_to_cpu(general->ttl_timestamp));
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "burst_check:",
- le32_to_cpu(dbg->burst_check),
- accum_dbg->burst_check,
- delta_dbg->burst_check, max_dbg->burst_check);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "burst_count:",
- le32_to_cpu(dbg->burst_count),
- accum_dbg->burst_count,
- delta_dbg->burst_count, max_dbg->burst_count);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "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,
- fmt_table, "sleep_time:",
- le32_to_cpu(general->sleep_time),
- accum_general->sleep_time,
- delta_general->sleep_time, max_general->sleep_time);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "slots_out:",
- le32_to_cpu(general->slots_out),
- accum_general->slots_out,
- delta_general->slots_out, max_general->slots_out);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "slots_idle:",
- le32_to_cpu(general->slots_idle),
- accum_general->slots_idle,
- delta_general->slots_idle, max_general->slots_idle);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "tx_on_a:",
- le32_to_cpu(div->tx_on_a), accum_div->tx_on_a,
- delta_div->tx_on_a, max_div->tx_on_a);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "tx_on_b:",
- le32_to_cpu(div->tx_on_b), accum_div->tx_on_b,
- delta_div->tx_on_b, max_div->tx_on_b);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "exec_time:",
- le32_to_cpu(div->exec_time), accum_div->exec_time,
- delta_div->exec_time, max_div->exec_time);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "probe_time:",
- le32_to_cpu(div->probe_time), accum_div->probe_time,
- delta_div->probe_time, max_div->probe_time);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "rx_enable_counter:",
- le32_to_cpu(general->rx_enable_counter),
- accum_general->rx_enable_counter,
- delta_general->rx_enable_counter,
- max_general->rx_enable_counter);
- pos += scnprintf(buf + pos, bufsz - pos,
- fmt_table, "num_of_sos_states:",
- le32_to_cpu(general->num_of_sos_states),
- accum_general->num_of_sos_states,
- delta_general->num_of_sos_states,
- max_general->num_of_sos_states);
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
- 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;
-
- if (!priv->bt_enable_flag)
- return -EINVAL;
-
- /* 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_tx_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;
-}
-
-ssize_t iwl_reply_tx_error_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 reply_tx_error_statistics) * 24) +
- (sizeof(struct reply_agg_tx_error_statistics) * 24) + 200;
- ssize_t ret;
-
- if (!iwl_is_alive(priv))
- return -EAGAIN;
-
- buf = kzalloc(bufsz, GFP_KERNEL);
- if (!buf) {
- IWL_ERR(priv, "Can not allocate Buffer\n");
- return -ENOMEM;
- }
-
- pos += scnprintf(buf + pos, bufsz - pos, "Statistics_TX_Error:\n");
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t\t%u\n",
- iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_DELAY),
- priv->_agn.reply_tx_stats.pp_delay);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_FEW_BYTES),
- priv->_agn.reply_tx_stats.pp_few_bytes);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_BT_PRIO),
- priv->_agn.reply_tx_stats.pp_bt_prio);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_QUIET_PERIOD),
- priv->_agn.reply_tx_stats.pp_quiet_period);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_CALC_TTAK),
- priv->_agn.reply_tx_stats.pp_calc_ttak);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
- iwl_get_tx_fail_reason(
- TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY),
- priv->_agn.reply_tx_stats.int_crossed_retry);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_tx_fail_reason(TX_STATUS_FAIL_SHORT_LIMIT),
- priv->_agn.reply_tx_stats.short_limit);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_tx_fail_reason(TX_STATUS_FAIL_LONG_LIMIT),
- priv->_agn.reply_tx_stats.long_limit);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_UNDERRUN),
- priv->_agn.reply_tx_stats.fifo_underrun);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_tx_fail_reason(TX_STATUS_FAIL_DRAIN_FLOW),
- priv->_agn.reply_tx_stats.drain_flow);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_tx_fail_reason(TX_STATUS_FAIL_RFKILL_FLUSH),
- priv->_agn.reply_tx_stats.rfkill_flush);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_tx_fail_reason(TX_STATUS_FAIL_LIFE_EXPIRE),
- priv->_agn.reply_tx_stats.life_expire);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_tx_fail_reason(TX_STATUS_FAIL_DEST_PS),
- priv->_agn.reply_tx_stats.dest_ps);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_tx_fail_reason(TX_STATUS_FAIL_HOST_ABORTED),
- priv->_agn.reply_tx_stats.host_abort);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_tx_fail_reason(TX_STATUS_FAIL_BT_RETRY),
- priv->_agn.reply_tx_stats.pp_delay);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_tx_fail_reason(TX_STATUS_FAIL_STA_INVALID),
- priv->_agn.reply_tx_stats.sta_invalid);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_tx_fail_reason(TX_STATUS_FAIL_FRAG_DROPPED),
- priv->_agn.reply_tx_stats.frag_drop);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_tx_fail_reason(TX_STATUS_FAIL_TID_DISABLE),
- priv->_agn.reply_tx_stats.tid_disable);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_FLUSHED),
- priv->_agn.reply_tx_stats.fifo_flush);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
- iwl_get_tx_fail_reason(
- TX_STATUS_FAIL_INSUFFICIENT_CF_POLL),
- priv->_agn.reply_tx_stats.insuff_cf_poll);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_tx_fail_reason(TX_STATUS_FAIL_PASSIVE_NO_RX),
- priv->_agn.reply_tx_stats.fail_hw_drop);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
- iwl_get_tx_fail_reason(
- TX_STATUS_FAIL_NO_BEACON_ON_RADAR),
- priv->_agn.reply_tx_stats.sta_color_mismatch);
- pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n",
- priv->_agn.reply_tx_stats.unknown);
-
- pos += scnprintf(buf + pos, bufsz - pos,
- "\nStatistics_Agg_TX_Error:\n");
-
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_agg_tx_fail_reason(AGG_TX_STATE_UNDERRUN_MSK),
- priv->_agn.reply_agg_tx_stats.underrun);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_agg_tx_fail_reason(AGG_TX_STATE_BT_PRIO_MSK),
- priv->_agn.reply_agg_tx_stats.bt_prio);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_agg_tx_fail_reason(AGG_TX_STATE_FEW_BYTES_MSK),
- priv->_agn.reply_agg_tx_stats.few_bytes);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_agg_tx_fail_reason(AGG_TX_STATE_ABORT_MSK),
- priv->_agn.reply_agg_tx_stats.abort);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
- iwl_get_agg_tx_fail_reason(
- AGG_TX_STATE_LAST_SENT_TTL_MSK),
- priv->_agn.reply_agg_tx_stats.last_sent_ttl);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
- iwl_get_agg_tx_fail_reason(
- AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK),
- priv->_agn.reply_agg_tx_stats.last_sent_try);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
- iwl_get_agg_tx_fail_reason(
- AGG_TX_STATE_LAST_SENT_BT_KILL_MSK),
- priv->_agn.reply_agg_tx_stats.last_sent_bt_kill);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_agg_tx_fail_reason(AGG_TX_STATE_SCD_QUERY_MSK),
- priv->_agn.reply_agg_tx_stats.scd_query);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
- iwl_get_agg_tx_fail_reason(
- AGG_TX_STATE_TEST_BAD_CRC32_MSK),
- priv->_agn.reply_agg_tx_stats.bad_crc32);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_agg_tx_fail_reason(AGG_TX_STATE_RESPONSE_MSK),
- priv->_agn.reply_agg_tx_stats.response);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DUMP_TX_MSK),
- priv->_agn.reply_agg_tx_stats.dump_tx);
- pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
- iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DELAY_TX_MSK),
- priv->_agn.reply_agg_tx_stats.delay_tx);
- pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n",
- priv->_agn.reply_agg_tx_stats.unknown);
-
- 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
deleted file mode 100644
index f2573b5486cd..000000000000
--- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/******************************************************************************
- *
- * 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 "iwl-dev.h"
-#include "iwl-core.h"
-#include "iwl-debug.h"
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos);
-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);
-ssize_t iwl_reply_tx_error_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)
-{
- return 0;
-}
-static ssize_t iwl_ucode_tx_stats_read(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- return 0;
-}
-static ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- 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;
-}
-static ssize_t iwl_reply_tx_error_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-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c
index 27b5a3eec9dc..2ef9448b1c20 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 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
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -81,52 +81,13 @@
*
******************************************************************************/
-/*
- * The device's EEPROM semaphore prevents conflicts between driver and uCode
- * when accessing the EEPROM; each access is a series of pulses to/from the
- * EEPROM chip, not a single event, so even reads could conflict if they
- * weren't arbitrated by the semaphore.
- */
-int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv)
-{
- u16 count;
- int ret;
-
- for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
- /* Request semaphore */
- iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
-
- /* See if we got it */
- ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
- CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
- EEPROM_SEM_TIMEOUT);
- if (ret >= 0) {
- IWL_DEBUG_IO(priv,
- "Acquired semaphore after %d tries.\n",
- count+1);
- return ret;
- }
- }
-
- return ret;
-}
-
-void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv)
-{
- iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
- CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
-
-}
-
int iwl_eeprom_check_version(struct iwl_priv *priv)
{
u16 eeprom_ver;
u16 calib_ver;
eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
- calib_ver = priv->cfg->ops->lib->eeprom_ops.calib_version(priv);
+ calib_ver = iwlagn_eeprom_calib_version(priv);
if (eeprom_ver < priv->cfg->eeprom_ver ||
calib_ver < priv->cfg->eeprom_calib_ver)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
index 41543ad4cb84..b12c72d63ccb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
@@ -2,7 +2,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 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
@@ -37,54 +37,6 @@
#include "iwl-io.h"
#include "iwl-agn.h"
-int iwlagn_send_rxon_assoc(struct iwl_priv *priv,
- struct iwl_rxon_context *ctx)
-{
- int ret = 0;
- struct iwl5000_rxon_assoc_cmd rxon_assoc;
- const struct iwl_rxon_cmd *rxon1 = &ctx->staging;
- const struct iwl_rxon_cmd *rxon2 = &ctx->active;
-
- if ((rxon1->flags == rxon2->flags) &&
- (rxon1->filter_flags == rxon2->filter_flags) &&
- (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
- (rxon1->ofdm_ht_single_stream_basic_rates ==
- rxon2->ofdm_ht_single_stream_basic_rates) &&
- (rxon1->ofdm_ht_dual_stream_basic_rates ==
- rxon2->ofdm_ht_dual_stream_basic_rates) &&
- (rxon1->ofdm_ht_triple_stream_basic_rates ==
- rxon2->ofdm_ht_triple_stream_basic_rates) &&
- (rxon1->acquisition_data == rxon2->acquisition_data) &&
- (rxon1->rx_chain == rxon2->rx_chain) &&
- (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
- IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC. Not resending.\n");
- return 0;
- }
-
- rxon_assoc.flags = ctx->staging.flags;
- rxon_assoc.filter_flags = ctx->staging.filter_flags;
- rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates;
- rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates;
- rxon_assoc.reserved1 = 0;
- rxon_assoc.reserved2 = 0;
- rxon_assoc.reserved3 = 0;
- rxon_assoc.ofdm_ht_single_stream_basic_rates =
- ctx->staging.ofdm_ht_single_stream_basic_rates;
- rxon_assoc.ofdm_ht_dual_stream_basic_rates =
- ctx->staging.ofdm_ht_dual_stream_basic_rates;
- rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain;
- rxon_assoc.ofdm_ht_triple_stream_basic_rates =
- ctx->staging.ofdm_ht_triple_stream_basic_rates;
- rxon_assoc.acquisition_data = ctx->staging.acquisition_data;
-
- ret = iwl_send_cmd_pdu_async(priv, ctx->rxon_assoc_cmd,
- sizeof(rxon_assoc), &rxon_assoc, NULL);
- if (ret)
- return ret;
-
- return ret;
-}
-
int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant)
{
struct iwl_tx_ant_config_cmd tx_ant_cmd = {
@@ -102,12 +54,6 @@ int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant)
}
}
-/* Currently this is the superset of everything */
-static u16 iwlagn_get_hcmd_size(u8 cmd_id, u16 len)
-{
- return len;
-}
-
static u16 iwlagn_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
{
u16 size = (u16)sizeof(struct iwl_addsta_cmd);
@@ -364,7 +310,6 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv)
}
struct iwl_hcmd_ops iwlagn_hcmd = {
- .rxon_assoc = iwlagn_send_rxon_assoc,
.commit_rxon = iwlagn_commit_rxon,
.set_rxon_chain = iwlagn_set_rxon_chain,
.set_tx_ant = iwlagn_send_tx_ant_config,
@@ -373,7 +318,6 @@ struct iwl_hcmd_ops iwlagn_hcmd = {
};
struct iwl_hcmd_ops iwlagn_bt_hcmd = {
- .rxon_assoc = iwlagn_send_rxon_assoc,
.commit_rxon = iwlagn_commit_rxon,
.set_rxon_chain = iwlagn_set_rxon_chain,
.set_tx_ant = iwlagn_send_tx_ant_config,
@@ -382,7 +326,6 @@ struct iwl_hcmd_ops iwlagn_bt_hcmd = {
};
struct iwl_hcmd_utils_ops iwlagn_hcmd_utils = {
- .get_hcmd_size = iwlagn_get_hcmd_size,
.build_addsta_hcmd = iwlagn_build_addsta_hcmd,
.gain_computation = iwlagn_gain_computation,
.chain_noise_reset = iwlagn_chain_noise_reset,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
index a52b82c8e7a6..7bd19f4e66de 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2011 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
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c
index ed0148d714de..0d5fda44c3a3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-ict.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-ict.c
@@ -2,7 +2,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 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
@@ -59,8 +59,6 @@ void iwl_free_isr_ict(struct iwl_priv *priv)
int iwl_alloc_isr_ict(struct iwl_priv *priv)
{
- if (priv->cfg->base_params->use_isr_legacy)
- return 0;
/* allocate shrared data table */
priv->_agn.ict_tbl_vir =
dma_alloc_coherent(&priv->pci_dev->dev,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.c b/drivers/net/wireless/iwlwifi/iwl-agn-led.c
deleted file mode 100644
index c1190d965614..000000000000
--- a/drivers/net/wireless/iwlwifi/iwl-agn-led.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 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.
- *
- * 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/pci.h>
-#include <linux/dma-mapping.h>
-#include <linux/delay.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/wireless.h>
-#include <net/mac80211.h>
-#include <linux/etherdevice.h>
-#include <asm/unaligned.h>
-
-#include "iwl-commands.h"
-#include "iwl-dev.h"
-#include "iwl-core.h"
-#include "iwl-io.h"
-#include "iwl-agn-led.h"
-
-/* Send led command */
-static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
-{
- struct iwl_host_cmd cmd = {
- .id = REPLY_LEDS_CMD,
- .len = sizeof(struct iwl_led_cmd),
- .data = led_cmd,
- .flags = CMD_ASYNC,
- .callback = NULL,
- };
- u32 reg;
-
- reg = iwl_read32(priv, CSR_LED_REG);
- if (reg != (reg & CSR_LED_BSM_CTRL_MSK))
- iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK);
-
- return iwl_send_cmd(priv, &cmd);
-}
-
-/* Set led register off */
-void iwlagn_led_enable(struct iwl_priv *priv)
-{
- iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
-}
-
-const struct iwl_led_ops iwlagn_led_ops = {
- .cmd = iwl_send_led_cmd,
-};
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index 08ccb9496f76..f803fb62f8bc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -2,7 +2,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 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
@@ -172,6 +172,7 @@ static void iwlagn_count_agg_tx_err_status(struct iwl_priv *priv, u16 status)
static void iwlagn_set_tx_status(struct iwl_priv *priv,
struct ieee80211_tx_info *info,
+ struct iwl_rxon_context *ctx,
struct iwlagn_tx_resp *tx_resp,
int txq_id, bool is_agg)
{
@@ -186,6 +187,13 @@ static void iwlagn_set_tx_status(struct iwl_priv *priv,
if (!iwl_is_tx_success(status))
iwlagn_count_tx_err_status(priv, status);
+ if (status == TX_STATUS_FAIL_PASSIVE_NO_RX &&
+ iwl_is_associated_ctx(ctx) && ctx->vif &&
+ ctx->vif->type == NL80211_IFTYPE_STATION) {
+ ctx->last_tx_rejected = true;
+ iwl_stop_queue(priv, &priv->txq[txq_id]);
+ }
+
IWL_DEBUG_TX_REPLY(priv, "TXQ %d status %s (0x%08x) rate_n_flags "
"0x%x retries %d\n",
txq_id,
@@ -242,15 +250,16 @@ static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv,
/* # frames attempted by Tx command */
if (agg->frame_count == 1) {
+ struct iwl_tx_info *txb;
+
/* Only one frame was attempted; no block-ack will arrive */
idx = start_idx;
IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n",
agg->frame_count, agg->start_idx, idx);
- iwlagn_set_tx_status(priv,
- IEEE80211_SKB_CB(
- priv->txq[txq_id].txb[idx].skb),
- tx_resp, txq_id, true);
+ txb = &priv->txq[txq_id].txb[idx];
+ iwlagn_set_tx_status(priv, IEEE80211_SKB_CB(txb->skb),
+ txb->ctx, tx_resp, txq_id, true);
agg->wait_for_ba = 0;
} else {
/* Two or more frames were attempted; expect block-ack */
@@ -391,7 +400,8 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
struct iwl_tx_queue *txq = &priv->txq[txq_id];
struct ieee80211_tx_info *info;
struct iwlagn_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
- u32 status = le16_to_cpu(tx_resp->status.status);
+ struct iwl_tx_info *txb;
+ u32 status = le16_to_cpu(tx_resp->status.status);
int tid;
int sta_id;
int freed;
@@ -406,7 +416,8 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
}
txq->time_stamp = jiffies;
- info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
+ txb = &txq->txb[txq->q.read_ptr];
+ info = IEEE80211_SKB_CB(txb->skb);
memset(&info->status, 0, sizeof(info->status));
tid = (tx_resp->ra_tid & IWLAGN_TX_RES_TID_MSK) >>
@@ -450,12 +461,14 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
iwl_wake_queue(priv, txq);
}
} else {
- iwlagn_set_tx_status(priv, info, tx_resp, txq_id, false);
+ iwlagn_set_tx_status(priv, info, txb->ctx, tx_resp,
+ txq_id, false);
freed = iwlagn_tx_queue_reclaim(priv, txq_id, index);
iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
if (priv->mac80211_registered &&
- (iwl_queue_space(&txq->q) > txq->q.low_mark))
+ iwl_queue_space(&txq->q) > txq->q.low_mark &&
+ status != TX_STATUS_FAIL_PASSIVE_NO_RX)
iwl_wake_queue(priv, txq);
}
@@ -470,8 +483,6 @@ void iwlagn_rx_handler_setup(struct iwl_priv *priv)
/* init calibration handlers */
priv->rx_handlers[CALIBRATION_RES_NOTIFICATION] =
iwlagn_rx_calib_result;
- priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] =
- iwlagn_rx_calib_complete;
priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx;
/* set up notification wait support */
@@ -482,8 +493,10 @@ void iwlagn_rx_handler_setup(struct iwl_priv *priv)
void iwlagn_setup_deferred_work(struct iwl_priv *priv)
{
- /* in agn, the tx power calibration is done in uCode */
- priv->disable_tx_power_cal = 1;
+ /*
+ * nothing need to be done here anymore
+ * still keep for future use if needed
+ */
}
int iwlagn_hw_valid_rtc_data_addr(u32 addr)
@@ -534,9 +547,7 @@ int iwlagn_send_tx_power(struct iwl_priv *priv)
void iwlagn_temperature(struct iwl_priv *priv)
{
/* store temperature from correct statistics (in Celsius) */
- priv->temperature = le32_to_cpu((iwl_bt_statistics(priv)) ?
- priv->_agn.statistics_bt.general.common.temperature :
- priv->_agn.statistics.general.common.temperature);
+ priv->temperature = le32_to_cpu(priv->statistics.common.temperature);
iwl_tt_handler(priv);
}
@@ -652,10 +663,9 @@ int iwlagn_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */
u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */
- if (!priv->cfg->base_params->use_isr_legacy)
- rb_timeout = RX_RB_TIMEOUT;
+ rb_timeout = RX_RB_TIMEOUT;
- if (priv->cfg->mod_params->amsdu_size_8K)
+ if (iwlagn_mod_params.amsdu_size_8K)
rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
else
rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
@@ -913,7 +923,6 @@ void iwlagn_rx_allocate(struct iwl_priv *priv, gfp_t priority)
list_add_tail(&rxb->list, &rxq->rx_free);
rxq->free_count++;
- priv->alloc_rxb_page++;
spin_unlock_irqrestore(&rxq->lock, flags);
}
@@ -1131,8 +1140,7 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
{
struct iwl_host_cmd cmd = {
.id = REPLY_SCAN_CMD,
- .len = sizeof(struct iwl_scan_cmd),
- .flags = CMD_SIZE_HUGE,
+ .len = { sizeof(struct iwl_scan_cmd), },
};
struct iwl_scan_cmd *scan;
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
@@ -1285,9 +1293,17 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
* mean we never reach it, but at the same time work around
* the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER
* here instead of IWL_GOOD_CRC_TH_DISABLED.
+ *
+ * This was fixed in later versions along with some other
+ * scan changes, and the threshold behaves as a flag in those
+ * versions.
*/
- scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
- IWL_GOOD_CRC_TH_NEVER;
+ if (priv->new_scan_threshold_behaviour)
+ scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
+ IWL_GOOD_CRC_TH_DISABLED;
+ else
+ scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
+ IWL_GOOD_CRC_TH_NEVER;
band = priv->scan_band;
@@ -1408,10 +1424,11 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
return -EIO;
}
- cmd.len += le16_to_cpu(scan->tx_cmd.len) +
+ cmd.len[0] += le16_to_cpu(scan->tx_cmd.len) +
scan->channel_count * sizeof(struct iwl_scan_channel);
- cmd.data = scan;
- scan->len = cpu_to_le16(cmd.len);
+ cmd.data[0] = scan;
+ cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
+ scan->len = cpu_to_le16(cmd.len[0]);
/* set scan bit here for PAN params */
set_bit(STATUS_SCAN_HW, &priv->status);
@@ -1503,9 +1520,9 @@ 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),
+ .len = { sizeof(struct iwl_txfifo_flush_cmd), },
.flags = CMD_SYNC,
- .data = &flush_cmd,
+ .data = { &flush_cmd, },
};
might_sleep();
@@ -2245,34 +2262,44 @@ int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display)
/* notification wait support */
void iwlagn_init_notification_wait(struct iwl_priv *priv,
struct iwl_notification_wait *wait_entry,
+ u8 cmd,
void (*fn)(struct iwl_priv *priv,
- struct iwl_rx_packet *pkt),
- u8 cmd)
+ struct iwl_rx_packet *pkt,
+ void *data),
+ void *fn_data)
{
wait_entry->fn = fn;
+ wait_entry->fn_data = fn_data;
wait_entry->cmd = cmd;
wait_entry->triggered = false;
+ wait_entry->aborted = false;
spin_lock_bh(&priv->_agn.notif_wait_lock);
list_add(&wait_entry->list, &priv->_agn.notif_waits);
spin_unlock_bh(&priv->_agn.notif_wait_lock);
}
-signed long iwlagn_wait_notification(struct iwl_priv *priv,
- struct iwl_notification_wait *wait_entry,
- unsigned long timeout)
+int iwlagn_wait_notification(struct iwl_priv *priv,
+ struct iwl_notification_wait *wait_entry,
+ unsigned long timeout)
{
int ret;
ret = wait_event_timeout(priv->_agn.notif_waitq,
- wait_entry->triggered,
+ wait_entry->triggered || wait_entry->aborted,
timeout);
spin_lock_bh(&priv->_agn.notif_wait_lock);
list_del(&wait_entry->list);
spin_unlock_bh(&priv->_agn.notif_wait_lock);
- return ret;
+ if (wait_entry->aborted)
+ return -EIO;
+
+ /* return value is always >= 0 */
+ if (ret <= 0)
+ return -ETIMEDOUT;
+ return 0;
}
void iwlagn_remove_notification(struct iwl_priv *priv,
@@ -2282,3 +2309,87 @@ void iwlagn_remove_notification(struct iwl_priv *priv,
list_del(&wait_entry->list);
spin_unlock_bh(&priv->_agn.notif_wait_lock);
}
+
+int iwlagn_start_device(struct iwl_priv *priv)
+{
+ int ret;
+
+ if (iwl_prepare_card_hw(priv)) {
+ IWL_WARN(priv, "Exit HW not ready\n");
+ return -EIO;
+ }
+
+ /* If platform's RF_KILL switch is NOT set to KILL */
+ if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
+ clear_bit(STATUS_RF_KILL_HW, &priv->status);
+ else
+ set_bit(STATUS_RF_KILL_HW, &priv->status);
+
+ if (iwl_is_rfkill(priv)) {
+ wiphy_rfkill_set_hw_state(priv->hw->wiphy, true);
+ iwl_enable_interrupts(priv);
+ return -ERFKILL;
+ }
+
+ iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+
+ ret = iwlagn_hw_nic_init(priv);
+ if (ret) {
+ IWL_ERR(priv, "Unable to init nic\n");
+ return ret;
+ }
+
+ /* make sure rfkill handshake bits are cleared */
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+ CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+ /* clear (again), then enable host interrupts */
+ iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
+ iwl_enable_interrupts(priv);
+
+ /* really make sure rfkill handshake bits are cleared */
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+ return 0;
+}
+
+void iwlagn_stop_device(struct iwl_priv *priv)
+{
+ unsigned long flags;
+
+ /* stop and reset the on-board processor */
+ iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
+
+ /* tell the device to stop sending interrupts */
+ spin_lock_irqsave(&priv->lock, flags);
+ iwl_disable_interrupts(priv);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ iwl_synchronize_irq(priv);
+
+ /* device going down, Stop using ICT table */
+ iwl_disable_ict(priv);
+
+ /*
+ * If a HW restart happens during firmware loading,
+ * then the firmware loading might call this function
+ * and later it might be called again due to the
+ * restart. So don't process again if the device is
+ * already dead.
+ */
+ if (test_bit(STATUS_DEVICE_ENABLED, &priv->status)) {
+ iwlagn_txq_ctx_stop(priv);
+ iwlagn_rxq_stop(priv);
+
+ /* Power-down device's busmaster DMA clocks */
+ iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
+ udelay(5);
+ }
+
+ /* Make sure (redundant) we've released our request to stay awake */
+ iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+
+ /* Stop the device, and put it in low power state */
+ iwl_apm_stop(priv);
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index d03b4734c892..592b0cfcf717 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 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
@@ -115,13 +115,18 @@ const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = {
/* FIXME:RS: ^^ should be INV (legacy) */
};
+static inline u8 rs_extract_rate(u32 rate_n_flags)
+{
+ return (u8)(rate_n_flags & RATE_MCS_RATE_MSK);
+}
+
static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
{
int idx = 0;
/* HT rate format */
if (rate_n_flags & RATE_MCS_HT_MSK) {
- idx = (rate_n_flags & 0xff);
+ idx = rs_extract_rate(rate_n_flags);
if (idx >= IWL_RATE_MIMO3_6M_PLCP)
idx = idx - IWL_RATE_MIMO3_6M_PLCP;
@@ -138,7 +143,8 @@ static int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
/* legacy rate format, search for match in table */
} else {
for (idx = 0; idx < ARRAY_SIZE(iwl_rates); idx++)
- if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF))
+ if (iwl_rates[idx].plcp ==
+ rs_extract_rate(rate_n_flags))
return idx;
}
@@ -239,11 +245,6 @@ static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = {
#define MCS_INDEX_PER_STREAM (8)
-static inline u8 rs_extract_rate(u32 rate_n_flags)
-{
- return (u8)(rate_n_flags & 0xFF);
-}
-
static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window)
{
window->data = 0;
@@ -334,6 +335,32 @@ static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data,
return tid;
}
+#ifdef CONFIG_MAC80211_DEBUGFS
+static void rs_program_fix_rate(struct iwl_priv *priv,
+ struct iwl_lq_sta *lq_sta)
+{
+ struct iwl_station_priv *sta_priv =
+ container_of(lq_sta, struct iwl_station_priv, lq_sta);
+ struct iwl_rxon_context *ctx = sta_priv->common.ctx;
+
+ lq_sta->active_legacy_rate = 0x0FFF; /* 1 - 54 MBits, includes CCK */
+ lq_sta->active_siso_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */
+ lq_sta->active_mimo2_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */
+ lq_sta->active_mimo3_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */
+
+ lq_sta->dbg_fixed_rate = priv->dbg_fixed_rate;
+
+ IWL_DEBUG_RATE(priv, "sta_id %d rate 0x%X\n",
+ lq_sta->lq.sta_id, priv->dbg_fixed_rate);
+
+ if (priv->dbg_fixed_rate) {
+ rs_fill_link_cmd(NULL, lq_sta, priv->dbg_fixed_rate);
+ iwl_send_lq_cmd(lq_sta->drv, ctx, &lq_sta->lq, CMD_ASYNC,
+ false);
+ }
+}
+#endif
+
/*
get the traffic load value for tid
*/
@@ -1045,7 +1072,10 @@ done:
/* See if there's a better rate or modulation mode to try. */
if (sta && sta->supp_rates[sband->band])
rs_rate_scale_perform(priv, skb, sta, lq_sta);
-
+#ifdef CONFIG_MAC80211_DEBUGFS
+ if (priv->dbg_fixed_rate != lq_sta->dbg_fixed_rate)
+ rs_program_fix_rate(priv, lq_sta);
+#endif
if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist)
rs_bt_update_lq(priv, ctx, lq_sta);
}
@@ -2169,11 +2199,11 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
* setup rate table in uCode
* return rate_n_flags as used in the table
*/
-static u32 rs_update_rate_tbl(struct iwl_priv *priv,
- struct iwl_rxon_context *ctx,
- struct iwl_lq_sta *lq_sta,
- struct iwl_scale_tbl_info *tbl,
- int index, u8 is_green)
+static void rs_update_rate_tbl(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx,
+ struct iwl_lq_sta *lq_sta,
+ struct iwl_scale_tbl_info *tbl,
+ int index, u8 is_green)
{
u32 rate;
@@ -2181,8 +2211,6 @@ static u32 rs_update_rate_tbl(struct iwl_priv *priv,
rate = rate_n_flags_from_tbl(priv, tbl, index, is_green);
rs_fill_link_cmd(priv, lq_sta, rate);
iwl_send_lq_cmd(priv, ctx, &lq_sta->lq, CMD_ASYNC, false);
-
- return rate;
}
/*
@@ -2211,7 +2239,6 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
u8 update_lq = 0;
struct iwl_scale_tbl_info *tbl, *tbl1;
u16 rate_scale_index_msk = 0;
- u32 rate;
u8 is_green = 0;
u8 active_tbl = 0;
u8 done_search = 0;
@@ -2298,8 +2325,8 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
/* get "active" rate info */
index = iwl_hwrate_to_plcp_idx(tbl->current_rate);
- rate = rs_update_rate_tbl(priv, ctx, lq_sta,
- tbl, index, is_green);
+ rs_update_rate_tbl(priv, ctx, lq_sta, tbl,
+ index, is_green);
}
return;
}
@@ -2540,8 +2567,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
lq_update:
/* Replace uCode's rate table for the destination station. */
if (update_lq)
- rate = rs_update_rate_tbl(priv, ctx, lq_sta,
- tbl, index, is_green);
+ rs_update_rate_tbl(priv, ctx, lq_sta, tbl, index, is_green);
if (iwl_tx_ant_restriction(priv) == IWL_ANT_OK_MULTI) {
/* Should we stay with this modulation mode,
@@ -2770,16 +2796,13 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta,
gfp_t gfp)
{
- struct iwl_lq_sta *lq_sta;
struct iwl_station_priv *sta_priv = (struct iwl_station_priv *) sta->drv_priv;
struct iwl_priv *priv;
priv = (struct iwl_priv *)priv_rate;
IWL_DEBUG_RATE(priv, "create station rate scale window\n");
- lq_sta = &sta_priv->lq_sta;
-
- return lq_sta;
+ return &sta_priv->lq_sta;
}
/*
@@ -2873,6 +2896,7 @@ void iwl_rs_rate_init(struct iwl_priv *priv, struct ieee80211_sta *sta, u8 sta_i
lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE;
lq_sta->is_agg = 0;
+ priv->dbg_fixed_rate = 0;
#ifdef CONFIG_MAC80211_DEBUGFS
lq_sta->dbg_fixed_rate = 0;
#endif
@@ -2912,7 +2936,8 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
ant_toggle_cnt = 1;
repeat_rate = IWL_NUMBER_TRY;
} else {
- repeat_rate = IWL_HT_NUMBER_TRY;
+ repeat_rate = min(IWL_HT_NUMBER_TRY,
+ LINK_QUAL_AGG_DISABLE_START_DEF - 1);
}
lq_cmd->general_params.mimo_delimiter =
@@ -3046,7 +3071,6 @@ static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta,
IWL_DEBUG_RATE(priv, "leave\n");
}
-
#ifdef CONFIG_MAC80211_DEBUGFS
static int open_file_generic(struct inode *inode, struct file *file)
{
@@ -3071,6 +3095,7 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
IWL_DEBUG_RATE(priv, "Fixed rate ON\n");
} else {
lq_sta->dbg_fixed_rate = 0;
+ priv->dbg_fixed_rate = 0;
IWL_ERR(priv,
"Invalid antenna selection 0x%X, Valid is 0x%X\n",
ant_sel_tx, valid_tx_ant);
@@ -3087,11 +3112,9 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
struct iwl_lq_sta *lq_sta = file->private_data;
struct iwl_priv *priv;
char buf[64];
- int buf_size;
+ size_t buf_size;
u32 parsed_rate;
- struct iwl_station_priv *sta_priv =
- container_of(lq_sta, struct iwl_station_priv, lq_sta);
- struct iwl_rxon_context *ctx = sta_priv->common.ctx;
+
priv = lq_sta->drv;
memset(buf, 0, sizeof(buf));
@@ -3100,23 +3123,11 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
return -EFAULT;
if (sscanf(buf, "%x", &parsed_rate) == 1)
- lq_sta->dbg_fixed_rate = parsed_rate;
+ priv->dbg_fixed_rate = lq_sta->dbg_fixed_rate = parsed_rate;
else
- lq_sta->dbg_fixed_rate = 0;
-
- lq_sta->active_legacy_rate = 0x0FFF; /* 1 - 54 MBits, includes CCK */
- lq_sta->active_siso_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */
- lq_sta->active_mimo2_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */
- lq_sta->active_mimo3_rate = 0x1FD0; /* 6 - 60 MBits, no 9, no CCK */
-
- IWL_DEBUG_RATE(priv, "sta_id %d rate 0x%X\n",
- lq_sta->lq.sta_id, lq_sta->dbg_fixed_rate);
+ priv->dbg_fixed_rate = lq_sta->dbg_fixed_rate = 0;
- if (lq_sta->dbg_fixed_rate) {
- rs_fill_link_cmd(NULL, lq_sta, lq_sta->dbg_fixed_rate);
- iwl_send_lq_cmd(lq_sta->drv, ctx, &lq_sta->lq, CMD_ASYNC,
- false);
- }
+ rs_program_fix_rate(priv, lq_sta);
return count;
}
@@ -3144,7 +3155,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
lq_sta->total_failed, lq_sta->total_success,
lq_sta->active_legacy_rate);
desc += sprintf(buff+desc, "fixed rate 0x%X\n",
- lq_sta->dbg_fixed_rate);
+ priv->dbg_fixed_rate);
desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n",
(priv->hw_params.valid_tx_ant & ANT_A) ? "ANT_A," : "",
(priv->hw_params.valid_tx_ant & ANT_B) ? "ANT_B," : "",
@@ -3255,15 +3266,10 @@ static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file,
char __user *user_buf, size_t count, loff_t *ppos)
{
- char buff[120];
- int desc = 0;
- ssize_t ret;
-
struct iwl_lq_sta *lq_sta = file->private_data;
- struct iwl_priv *priv;
struct iwl_scale_tbl_info *tbl = &lq_sta->lq_info[lq_sta->active_tbl];
-
- priv = lq_sta->drv;
+ char buff[120];
+ int desc = 0;
if (is_Ht(tbl->lq_type))
desc += sprintf(buff+desc,
@@ -3274,8 +3280,7 @@ static ssize_t rs_sta_dbgfs_rate_scale_data_read(struct file *file,
"Bit Rate= %d Mb/s\n",
iwl_rates[lq_sta->last_txrate_idx].ieee >> 1);
- ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
- return ret;
+ return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
}
static const struct file_operations rs_sta_dbgfs_rate_scale_data_ops = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
index 184828c72b31..bdae82e7fa90 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 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
@@ -41,20 +41,6 @@ struct iwl_rate_info {
u8 next_rs_tgg; /* next rate used in TGG rs algo */
};
-struct iwl3945_rate_info {
- u8 plcp; /* uCode API: IWL_RATE_6M_PLCP, etc. */
- u8 ieee; /* MAC header: IWL_RATE_6M_IEEE, etc. */
- u8 prev_ieee; /* previous rate in IEEE speeds */
- u8 next_ieee; /* next rate in IEEE speeds */
- u8 prev_rs; /* previous rate used in rs algo */
- u8 next_rs; /* next rate used in rs algo */
- u8 prev_rs_tgg; /* previous rate used in TGG rs algo */
- u8 next_rs_tgg; /* next rate used in TGG rs algo */
- u8 table_rs_index; /* index in rate scale table cmd */
- u8 prev_table_rs; /* prev in rate table cmd */
-};
-
-
/*
* These serve as indexes into
* struct iwl_rate_info iwl_rates[IWL_RATE_COUNT];
@@ -75,7 +61,6 @@ enum {
IWL_RATE_60M_INDEX,
IWL_RATE_COUNT, /*FIXME:RS:change to IWL_RATE_INDEX_COUNT,*/
IWL_RATE_COUNT_LEGACY = IWL_RATE_COUNT - 1, /* Excluding 60M */
- IWL_RATE_COUNT_3945 = IWL_RATE_COUNT - 1,
IWL_RATE_INVM_INDEX = IWL_RATE_COUNT,
IWL_RATE_INVALID = IWL_RATE_COUNT,
};
@@ -98,7 +83,6 @@ enum {
enum {
IWL_FIRST_OFDM_RATE = IWL_RATE_6M_INDEX,
- IWL39_LAST_OFDM_RATE = IWL_RATE_54M_INDEX,
IWL_LAST_OFDM_RATE = IWL_RATE_60M_INDEX,
IWL_FIRST_CCK_RATE = IWL_RATE_1M_INDEX,
IWL_LAST_CCK_RATE = IWL_RATE_11M_INDEX,
@@ -213,7 +197,6 @@ enum {
IWL_CCK_BASIC_RATES_MASK)
#define IWL_RATES_MASK ((1 << IWL_RATE_COUNT) - 1)
-#define IWL_RATES_MASK_3945 ((1 << IWL_RATE_COUNT_3945) - 1)
#define IWL_INVALID_VALUE -1
@@ -453,19 +436,9 @@ static inline u8 first_antenna(u8 mask)
}
-/**
- * iwl3945_rate_scale_init - Initialize the rate scale table based on assoc info
- *
- * The specific throughput table used is based on the type of network
- * the associated with, including A, B, G, and G w/ TGG protection
- */
-extern void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id);
-
/* Initialize station's rate scaling information after adding station */
extern void iwl_rs_rate_init(struct iwl_priv *priv,
struct ieee80211_sta *sta, u8 sta_id);
-extern void iwl3945_rs_rate_init(struct iwl_priv *priv,
- struct ieee80211_sta *sta, u8 sta_id);
/**
* iwl_rate_control_register - Register the rate control algorithm callbacks
@@ -478,7 +451,6 @@ extern void iwl3945_rs_rate_init(struct iwl_priv *priv,
*
*/
extern int iwlagn_rate_control_register(void);
-extern int iwl3945_rate_control_register(void);
/**
* iwl_rate_control_unregister - Unregister the rate control callbacks
@@ -487,6 +459,5 @@ extern int iwl3945_rate_control_register(void);
* the driver is unloaded.
*/
extern void iwlagn_rate_control_unregister(void);
-extern void iwl3945_rate_control_unregister(void);
#endif /* __iwl_agn__rs__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
index fbbde0712fa5..a95ad84c5377 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 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
@@ -29,6 +29,7 @@
#include "iwl-sta.h"
#include "iwl-core.h"
#include "iwl-agn-calib.h"
+#include "iwl-helpers.h"
static int iwlagn_disable_bss(struct iwl_priv *priv,
struct iwl_rxon_context *ctx,
@@ -57,8 +58,9 @@ static int iwlagn_disable_pan(struct iwl_priv *priv,
u8 old_dev_type = send->dev_type;
int ret;
- iwlagn_init_notification_wait(priv, &disable_wait, NULL,
- REPLY_WIPAN_DEACTIVATION_COMPLETE);
+ iwlagn_init_notification_wait(priv, &disable_wait,
+ REPLY_WIPAN_DEACTIVATION_COMPLETE,
+ NULL, NULL);
send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
send->dev_type = RXON_DEV_TYPE_P2P;
@@ -71,13 +73,9 @@ static int iwlagn_disable_pan(struct iwl_priv *priv,
IWL_ERR(priv, "Error disabling PAN (%d)\n", ret);
iwlagn_remove_notification(priv, &disable_wait);
} else {
- signed long wait_res;
-
- wait_res = iwlagn_wait_notification(priv, &disable_wait, HZ);
- if (wait_res == 0) {
+ ret = iwlagn_wait_notification(priv, &disable_wait, HZ);
+ if (ret)
IWL_ERR(priv, "Timed out waiting for PAN disable\n");
- ret = -EIO;
- }
}
return ret;
@@ -123,6 +121,151 @@ static int iwlagn_update_beacon(struct iwl_priv *priv,
return iwlagn_send_beacon_cmd(priv);
}
+static int iwlagn_send_rxon_assoc(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx)
+{
+ int ret = 0;
+ struct iwl_rxon_assoc_cmd rxon_assoc;
+ const struct iwl_rxon_cmd *rxon1 = &ctx->staging;
+ const struct iwl_rxon_cmd *rxon2 = &ctx->active;
+
+ if ((rxon1->flags == rxon2->flags) &&
+ (rxon1->filter_flags == rxon2->filter_flags) &&
+ (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
+ (rxon1->ofdm_ht_single_stream_basic_rates ==
+ rxon2->ofdm_ht_single_stream_basic_rates) &&
+ (rxon1->ofdm_ht_dual_stream_basic_rates ==
+ rxon2->ofdm_ht_dual_stream_basic_rates) &&
+ (rxon1->ofdm_ht_triple_stream_basic_rates ==
+ rxon2->ofdm_ht_triple_stream_basic_rates) &&
+ (rxon1->acquisition_data == rxon2->acquisition_data) &&
+ (rxon1->rx_chain == rxon2->rx_chain) &&
+ (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
+ IWL_DEBUG_INFO(priv, "Using current RXON_ASSOC. Not resending.\n");
+ return 0;
+ }
+
+ rxon_assoc.flags = ctx->staging.flags;
+ rxon_assoc.filter_flags = ctx->staging.filter_flags;
+ rxon_assoc.ofdm_basic_rates = ctx->staging.ofdm_basic_rates;
+ rxon_assoc.cck_basic_rates = ctx->staging.cck_basic_rates;
+ rxon_assoc.reserved1 = 0;
+ rxon_assoc.reserved2 = 0;
+ rxon_assoc.reserved3 = 0;
+ rxon_assoc.ofdm_ht_single_stream_basic_rates =
+ ctx->staging.ofdm_ht_single_stream_basic_rates;
+ rxon_assoc.ofdm_ht_dual_stream_basic_rates =
+ ctx->staging.ofdm_ht_dual_stream_basic_rates;
+ rxon_assoc.rx_chain_select_flags = ctx->staging.rx_chain;
+ rxon_assoc.ofdm_ht_triple_stream_basic_rates =
+ ctx->staging.ofdm_ht_triple_stream_basic_rates;
+ rxon_assoc.acquisition_data = ctx->staging.acquisition_data;
+
+ ret = iwl_send_cmd_pdu_async(priv, ctx->rxon_assoc_cmd,
+ sizeof(rxon_assoc), &rxon_assoc, NULL);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
+static int iwlagn_rxon_disconn(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx)
+{
+ int ret;
+ struct iwl_rxon_cmd *active = (void *)&ctx->active;
+
+ if (ctx->ctxid == IWL_RXON_CTX_BSS)
+ ret = iwlagn_disable_bss(priv, ctx, &ctx->staging);
+ else
+ ret = iwlagn_disable_pan(priv, ctx, &ctx->staging);
+ if (ret)
+ return ret;
+
+ /*
+ * Un-assoc RXON clears the station table and WEP
+ * keys, so we have to restore those afterwards.
+ */
+ iwl_clear_ucode_stations(priv, ctx);
+ iwl_restore_stations(priv, ctx);
+ ret = iwl_restore_default_wep_keys(priv, ctx);
+ if (ret) {
+ IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
+ return ret;
+ }
+
+ memcpy(active, &ctx->staging, sizeof(*active));
+ return 0;
+}
+
+static int iwlagn_rxon_connect(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx)
+{
+ int ret;
+ struct iwl_rxon_cmd *active = (void *)&ctx->active;
+
+ /* RXON timing must be before associated RXON */
+ ret = iwl_send_rxon_timing(priv, ctx);
+ if (ret) {
+ IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
+ return ret;
+ }
+ /* QoS info may be cleared by previous un-assoc RXON */
+ iwlagn_update_qos(priv, ctx);
+
+ /*
+ * We'll run into this code path when beaconing is
+ * enabled, but then we also need to send the beacon
+ * to the device.
+ */
+ if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) {
+ ret = iwlagn_update_beacon(priv, ctx->vif);
+ if (ret) {
+ IWL_ERR(priv,
+ "Error sending required beacon (%d)!\n",
+ ret);
+ return ret;
+ }
+ }
+
+ priv->start_calib = 0;
+ /*
+ * Apply the new configuration.
+ *
+ * Associated RXON doesn't clear the station table in uCode,
+ * so we don't need to restore stations etc. after this.
+ */
+ ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
+ sizeof(struct iwl_rxon_cmd), &ctx->staging);
+ if (ret) {
+ IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
+ return ret;
+ }
+ memcpy(active, &ctx->staging, sizeof(*active));
+
+ iwl_reprogram_ap_sta(priv, ctx);
+
+ /* IBSS beacon needs to be sent after setting assoc */
+ if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC))
+ if (iwlagn_update_beacon(priv, ctx->vif))
+ IWL_ERR(priv, "Error sending IBSS beacon\n");
+ iwl_init_sensitivity(priv);
+
+ /*
+ * If we issue a new RXON command which required a tune then
+ * we must send a new TXPOWER command or we won't be able to
+ * Tx any frames.
+ *
+ * It's expected we set power here if channel is changing.
+ */
+ ret = iwl_set_tx_power(priv, priv->tx_power_next, true);
+ if (ret) {
+ IWL_ERR(priv, "Error sending TX power (%d)\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
/**
* iwlagn_commit_rxon - commit staging_rxon to hardware
*
@@ -130,13 +273,22 @@ static int iwlagn_update_beacon(struct iwl_priv *priv,
* the active_rxon structure is updated with the new data. This
* function correctly transitions out of the RXON_ASSOC_MSK state if
* a HW tune is required based on the RXON structure changes.
+ *
+ * The connect/disconnect flow should be as the following:
+ *
+ * 1. make sure send RXON command with association bit unset if not connect
+ * this should include the channel and the band for the candidate
+ * to be connected to
+ * 2. Add Station before RXON association with the AP
+ * 3. RXON_timing has to send before RXON for connection
+ * 4. full RXON command - associated bit set
+ * 5. use RXON_ASSOC command to update any flags changes
*/
int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
{
/* cast away the const for active_rxon in this function */
struct iwl_rxon_cmd *active = (void *)&ctx->active;
bool new_assoc = !!(ctx->staging.filter_flags & RXON_FILTER_ASSOC_MSK);
- bool old_assoc = !!(ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK);
int ret;
lockdep_assert_held(&priv->mutex);
@@ -179,6 +331,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
else
ctx->staging.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
+ iwl_print_rx_config_cmd(priv, ctx);
ret = iwl_check_rxon_cmd(priv, ctx);
if (ret) {
IWL_ERR(priv, "Invalid RXON configuration. Not committing.\n");
@@ -202,14 +355,13 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
* and other flags for the current radio configuration.
*/
if (!iwl_full_rxon_required(priv, ctx)) {
- ret = iwl_send_rxon_assoc(priv, ctx);
+ ret = iwlagn_send_rxon_assoc(priv, ctx);
if (ret) {
IWL_ERR(priv, "Error setting RXON_ASSOC (%d)\n", ret);
return ret;
}
memcpy(active, &ctx->staging, sizeof(*active));
- iwl_print_rx_config_cmd(priv, ctx);
return 0;
}
@@ -219,7 +371,7 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
return ret;
}
- iwl_set_rxon_hwcrypto(priv, ctx, !priv->cfg->mod_params->sw_crypto);
+ iwl_set_rxon_hwcrypto(priv, ctx, !iwlagn_mod_params.sw_crypto);
IWL_DEBUG_INFO(priv,
"Going to commit RXON\n"
@@ -236,93 +388,12 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
* AP station must be done after the BSSID is set to correctly
* set up filters in the device.
*/
- if ((old_assoc && new_assoc) || !new_assoc) {
- if (ctx->ctxid == IWL_RXON_CTX_BSS)
- ret = iwlagn_disable_bss(priv, ctx, &ctx->staging);
- else
- ret = iwlagn_disable_pan(priv, ctx, &ctx->staging);
- if (ret)
- return ret;
-
- memcpy(active, &ctx->staging, sizeof(*active));
-
- /*
- * Un-assoc RXON clears the station table and WEP
- * keys, so we have to restore those afterwards.
- */
- iwl_clear_ucode_stations(priv, ctx);
- iwl_restore_stations(priv, ctx);
- ret = iwl_restore_default_wep_keys(priv, ctx);
- if (ret) {
- IWL_ERR(priv, "Failed to restore WEP keys (%d)\n", ret);
- return ret;
- }
- }
-
- /* RXON timing must be before associated RXON */
- ret = iwl_send_rxon_timing(priv, ctx);
- if (ret) {
- IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
+ ret = iwlagn_rxon_disconn(priv, ctx);
+ if (ret)
return ret;
- }
- if (new_assoc) {
- /* QoS info may be cleared by previous un-assoc RXON */
- iwlagn_update_qos(priv, ctx);
-
- /*
- * We'll run into this code path when beaconing is
- * enabled, but then we also need to send the beacon
- * to the device.
- */
- if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_AP)) {
- ret = iwlagn_update_beacon(priv, ctx->vif);
- if (ret) {
- IWL_ERR(priv,
- "Error sending required beacon (%d)!\n",
- ret);
- return ret;
- }
- }
-
- priv->start_calib = 0;
- /*
- * Apply the new configuration.
- *
- * Associated RXON doesn't clear the station table in uCode,
- * so we don't need to restore stations etc. after this.
- */
- ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd,
- sizeof(struct iwl_rxon_cmd), &ctx->staging);
- if (ret) {
- IWL_ERR(priv, "Error setting new RXON (%d)\n", ret);
- return ret;
- }
- memcpy(active, &ctx->staging, sizeof(*active));
-
- iwl_reprogram_ap_sta(priv, ctx);
-
- /* IBSS beacon needs to be sent after setting assoc */
- if (ctx->vif && (ctx->vif->type == NL80211_IFTYPE_ADHOC))
- if (iwlagn_update_beacon(priv, ctx->vif))
- IWL_ERR(priv, "Error sending IBSS beacon\n");
- }
-
- iwl_print_rx_config_cmd(priv, ctx);
-
- iwl_init_sensitivity(priv);
-
- /*
- * If we issue a new RXON command which required a tune then we must
- * send a new TXPOWER command or we won't be able to Tx any frames.
- *
- * It's expected we set power here if channel is changing.
- */
- ret = iwl_set_tx_power(priv, priv->tx_power_next, true);
- if (ret) {
- IWL_ERR(priv, "Error sending TX power (%d)\n", ret);
- return ret;
- }
+ if (new_assoc)
+ return iwlagn_rxon_connect(priv, ctx);
return 0;
}
@@ -595,6 +666,18 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
priv->timestamp = bss_conf->timestamp;
ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK;
} else {
+ /*
+ * If we disassociate while there are pending
+ * frames, just wake up the queues and let the
+ * frames "escape" ... This shouldn't really
+ * be happening to start with, but we should
+ * not get stuck in this case either since it
+ * can happen if userspace gets confused.
+ */
+ if (ctx->last_tx_rejected) {
+ ctx->last_tx_rejected = false;
+ iwl_wake_any_queue(priv, ctx);
+ }
ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
}
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
index 35f085ac336b..0bd722cee5ae 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
@@ -144,7 +144,7 @@ static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv,
size_t cmd_size = sizeof(struct iwl_wep_cmd);
struct iwl_host_cmd cmd = {
.id = ctx->wep_key_cmd,
- .data = wep_cmd,
+ .data = { wep_cmd, },
.flags = CMD_SYNC,
};
@@ -172,7 +172,7 @@ static int iwl_send_static_wepkey_cmd(struct iwl_priv *priv,
cmd_size += sizeof(struct iwl_wep_key) * WEP_KEYS_MAX;
- cmd.len = cmd_size;
+ cmd.len[0] = cmd_size;
if (not_empty || send_if_empty)
return iwl_send_cmd(priv, &cmd);
@@ -474,7 +474,7 @@ int iwl_remove_dynamic_key(struct iwl_priv *priv,
memset(&priv->stations[sta_id].keyinfo, 0,
sizeof(struct iwl_hw_key));
memset(&priv->stations[sta_id].sta.key, 0,
- sizeof(struct iwl4965_keyinfo));
+ sizeof(struct iwl_keyinfo));
priv->stations[sta_id].sta.key.key_flags =
STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID;
priv->stations[sta_id].sta.key.key_offset = WEP_INVALID_OFFSET;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c
index e3a8216a033c..348f74f1c8e8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tt.h b/drivers/net/wireless/iwlwifi/iwl-agn-tt.h
index d55060427cac..d118ed29bf3f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tt.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tt.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index 0712b67283a4..4974cd7837cb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -2,7 +2,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 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
@@ -98,9 +98,9 @@ static inline int get_fifo_from_tid(struct iwl_rxon_context *ctx, u16 tid)
/**
* iwlagn_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
*/
-void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
- struct iwl_tx_queue *txq,
- u16 byte_cnt)
+static void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq,
+ u16 byte_cnt)
{
struct iwlagn_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr;
int write_ptr = txq->q.write_ptr;
@@ -112,21 +112,19 @@ void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX);
- if (txq_id != priv->cmd_queue) {
- sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id;
- sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl;
-
- switch (sec_ctl & TX_CMD_SEC_MSK) {
- case TX_CMD_SEC_CCM:
- len += CCMP_MIC_LEN;
- break;
- case TX_CMD_SEC_TKIP:
- len += TKIP_ICV_LEN;
- break;
- case TX_CMD_SEC_WEP:
- len += WEP_IV_LEN + WEP_ICV_LEN;
- break;
- }
+ sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id;
+ sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl;
+
+ switch (sec_ctl & TX_CMD_SEC_MSK) {
+ case TX_CMD_SEC_CCM:
+ len += CCMP_MIC_LEN;
+ break;
+ case TX_CMD_SEC_TKIP:
+ len += TKIP_ICV_LEN;
+ break;
+ case TX_CMD_SEC_WEP:
+ len += WEP_IV_LEN + WEP_ICV_LEN;
+ break;
}
bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12));
@@ -138,8 +136,8 @@ void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent;
}
-void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
- struct iwl_tx_queue *txq)
+static void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq)
{
struct iwlagn_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr;
int txq_id = txq->q.id;
@@ -222,13 +220,8 @@ void iwlagn_tx_queue_set_status(struct iwl_priv *priv,
scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id);
}
-int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
- int tx_fifo, int sta_id, int tid, u16 ssn_idx)
+static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, int sta_id, int tid)
{
- unsigned long flags;
- u16 ra_tid;
- int ret;
-
if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) ||
(IWLAGN_FIRST_AMPDU_QUEUE +
priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) {
@@ -240,12 +233,33 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
return -EINVAL;
}
- ra_tid = BUILD_RAxTID(sta_id, tid);
-
/* Modify device's station table to Tx this TID */
- ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
- if (ret)
- return ret;
+ return iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
+}
+
+void iwlagn_txq_agg_queue_setup(struct iwl_priv *priv,
+ struct ieee80211_sta *sta,
+ int tid, int frame_limit)
+{
+ int sta_id, tx_fifo, txq_id, ssn_idx;
+ u16 ra_tid;
+ unsigned long flags;
+ struct iwl_tid_data *tid_data;
+
+ sta_id = iwl_sta_id(sta);
+ if (WARN_ON(sta_id == IWL_INVALID_STATION))
+ return;
+ if (WARN_ON(tid >= MAX_TID_COUNT))
+ return;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ tid_data = &priv->stations[sta_id].tid[tid];
+ ssn_idx = SEQ_TO_SN(tid_data->seq_number);
+ txq_id = tid_data->agg.txq_id;
+ tx_fifo = tid_data->agg.tx_fifo;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ ra_tid = BUILD_RAxTID(sta_id, tid);
spin_lock_irqsave(&priv->lock, flags);
@@ -271,10 +285,10 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
iwl_write_targ_mem(priv, priv->scd_base_addr +
IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(txq_id) +
sizeof(u32),
- ((SCD_WIN_SIZE <<
+ ((frame_limit <<
IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
- ((SCD_FRAME_LIMIT <<
+ ((frame_limit <<
IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
@@ -284,12 +298,10 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
iwlagn_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1);
spin_unlock_irqrestore(&priv->lock, flags);
-
- return 0;
}
-int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
- u16 ssn_idx, u8 tx_fifo)
+static int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
+ u16 ssn_idx, u8 tx_fifo)
{
if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) ||
(IWLAGN_FIRST_AMPDU_QUEUE +
@@ -525,7 +537,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
struct iwl_tx_cmd *tx_cmd;
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
int txq_id;
- dma_addr_t phys_addr;
+ dma_addr_t phys_addr = 0;
dma_addr_t txcmd_phys;
dma_addr_t scratch_phys;
u16 len, firstlen, secondlen;
@@ -552,7 +564,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
spin_lock_irqsave(&priv->lock, flags);
if (iwl_is_rfkill(priv)) {
IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n");
- goto drop_unlock;
+ goto drop_unlock_priv;
}
fc = hdr->frame_control;
@@ -577,7 +589,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
hdr->addr1);
- goto drop_unlock;
+ goto drop_unlock_priv;
}
}
@@ -621,10 +633,10 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
if (ieee80211_is_data_qos(fc)) {
qc = ieee80211_get_qos_ctl(hdr);
tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
- if (WARN_ON_ONCE(tid >= MAX_TID_COUNT)) {
- spin_unlock(&priv->sta_lock);
- goto drop_unlock;
- }
+
+ if (WARN_ON_ONCE(tid >= MAX_TID_COUNT))
+ goto drop_unlock_sta;
+
seq_number = priv->stations[sta_id].tid[tid].seq_number;
seq_number &= IEEE80211_SCTL_SEQ;
hdr->seq_ctrl = hdr->seq_ctrl &
@@ -642,18 +654,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
txq = &priv->txq[txq_id];
q = &txq->q;
- if (unlikely(iwl_queue_space(q) < q->high_mark)) {
- spin_unlock(&priv->sta_lock);
- goto drop_unlock;
- }
-
- 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);
+ if (unlikely(iwl_queue_space(q) < q->high_mark))
+ goto drop_unlock_sta;
/* Set up driver data for this TFD */
memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
@@ -717,12 +719,10 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
txcmd_phys = pci_map_single(priv->pci_dev,
&out_cmd->hdr, firstlen,
PCI_DMA_BIDIRECTIONAL);
+ if (unlikely(pci_dma_mapping_error(priv->pci_dev, txcmd_phys)))
+ goto drop_unlock_sta;
dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
dma_unmap_len_set(out_meta, len, firstlen);
- /* Add buffer containing Tx command and MAC(!) header to TFD's
- * first entry */
- priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
- txcmd_phys, firstlen, 1, 0);
if (!ieee80211_has_morefrags(hdr->frame_control)) {
txq->need_update = 1;
@@ -737,11 +737,29 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
if (secondlen > 0) {
phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
secondlen, PCI_DMA_TODEVICE);
- priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
- phys_addr, secondlen,
- 0, 0);
+ if (unlikely(pci_dma_mapping_error(priv->pci_dev, phys_addr))) {
+ pci_unmap_single(priv->pci_dev,
+ dma_unmap_addr(out_meta, mapping),
+ dma_unmap_len(out_meta, len),
+ PCI_DMA_BIDIRECTIONAL);
+ goto drop_unlock_sta;
+ }
+ }
+
+ 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);
+
+ /* Attach buffers to TFD */
+ iwlagn_txq_attach_buf_to_tfd(priv, txq, txcmd_phys, firstlen, 1);
+ if (secondlen > 0)
+ iwlagn_txq_attach_buf_to_tfd(priv, txq, phys_addr,
+ secondlen, 0);
+
scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
offsetof(struct iwl_tx_cmd, scratch);
@@ -759,8 +777,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Set up entry for this TFD in Tx byte-count array */
if (info->flags & IEEE80211_TX_CTL_AMPDU)
- priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq,
- le16_to_cpu(tx_cmd->len));
+ iwlagn_txq_update_byte_cnt_tbl(priv, txq,
+ le16_to_cpu(tx_cmd->len));
pci_dma_sync_single_for_device(priv->pci_dev, txcmd_phys,
firstlen, PCI_DMA_BIDIRECTIONAL);
@@ -806,7 +824,9 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
return 0;
-drop_unlock:
+drop_unlock_sta:
+ spin_unlock(&priv->sta_lock);
+drop_unlock_priv:
spin_unlock_irqrestore(&priv->lock, flags);
return -1;
}
@@ -894,7 +914,7 @@ int iwlagn_txq_ctx_alloc(struct iwl_priv *priv)
spin_lock_irqsave(&priv->lock, flags);
/* Turn off all Tx DMA fifos */
- priv->cfg->ops->lib->txq_set_sched(priv, 0);
+ iwlagn_txq_set_sched(priv, 0);
/* Tell NIC where to find the "keep warm" buffer */
iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
@@ -932,7 +952,7 @@ void iwlagn_txq_ctx_reset(struct iwl_priv *priv)
spin_lock_irqsave(&priv->lock, flags);
/* Turn off all Tx DMA fifos */
- priv->cfg->ops->lib->txq_set_sched(priv, 0);
+ iwlagn_txq_set_sched(priv, 0);
/* Tell NIC where to find the "keep warm" buffer */
iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
@@ -958,7 +978,7 @@ void iwlagn_txq_ctx_stop(struct iwl_priv *priv)
/* Turn off all Tx DMA fifos */
spin_lock_irqsave(&priv->lock, flags);
- priv->cfg->ops->lib->txq_set_sched(priv, 0);
+ iwlagn_txq_set_sched(priv, 0);
/* Stop each Tx DMA channel, and wait for it to be idle */
for (ch = 0; ch < priv->hw_params.dma_chnl_num; ch++) {
@@ -1039,11 +1059,11 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
tid_data = &priv->stations[sta_id].tid[tid];
*ssn = SEQ_TO_SN(tid_data->seq_number);
tid_data->agg.txq_id = txq_id;
+ tid_data->agg.tx_fifo = tx_fifo;
iwl_set_swq_id(&priv->txq[txq_id], get_ac_from_tid(tid), txq_id);
spin_unlock_irqrestore(&priv->sta_lock, flags);
- ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo,
- sta_id, tid, *ssn);
+ ret = iwlagn_txq_agg_enable(priv, txq_id, sta_id, tid);
if (ret)
return ret;
@@ -1130,8 +1150,7 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
* to deactivate the uCode queue, just return "success" to allow
* mac80211 to clean up it own data.
*/
- priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn,
- tx_fifo_id);
+ iwlagn_txq_agg_disable(priv, txq_id, ssn, tx_fifo_id);
spin_unlock_irqrestore(&priv->lock, flags);
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
@@ -1160,8 +1179,7 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
u16 ssn = SEQ_TO_SN(tid_data->seq_number);
int tx_fifo = get_fifo_from_tid(ctx, tid);
IWL_DEBUG_HT(priv, "HW queue empty: continue DELBA flow\n");
- priv->cfg->ops->lib->txq_agg_disable(priv, txq_id,
- ssn, tx_fifo);
+ iwlagn_txq_agg_disable(priv, txq_id, ssn, tx_fifo);
tid_data->agg.state = IWL_AGG_OFF;
ieee80211_stop_tx_ba_cb_irqsafe(ctx->vif, addr, tid);
}
@@ -1241,10 +1259,9 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
txq_id >= IWLAGN_FIRST_AMPDU_QUEUE);
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);
+ iwlagn_txq_inval_byte_cnt_tbl(priv, txq);
- priv->cfg->ops->lib->txq_free_tfd(priv, txq);
+ iwlagn_txq_free_tfd(priv, txq);
}
return nfreed;
}
@@ -1260,11 +1277,11 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv,
struct iwl_compressed_ba_resp *ba_resp)
{
- int i, sh, ack;
+ int sh;
u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl);
u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
- int successes = 0;
struct ieee80211_tx_info *info;
+ u64 bitmap, sent_bitmap;
if (unlikely(!agg->wait_for_ba)) {
if (unlikely(ba_resp->bitmap))
@@ -1278,70 +1295,42 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv,
/* Calculate shift to align block-ack bits with our Tx window bits */
sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4);
- if (sh < 0) /* tbw something is wrong with indices */
+ if (sh < 0)
sh += 0x100;
- if (agg->frame_count > (64 - sh)) {
- IWL_DEBUG_TX_REPLY(priv, "more frames than bitmap size");
- return -1;
- }
- if (!priv->cfg->base_params->no_agg_framecnt_info && ba_resp->txed) {
+ /*
+ * Check for success or failure according to the
+ * transmitted bitmap and block-ack bitmap
+ */
+ bitmap = le64_to_cpu(ba_resp->bitmap) >> sh;
+ sent_bitmap = bitmap & agg->bitmap;
+
+ /* Sanity check values reported by uCode */
+ if (ba_resp->txed_2_done > ba_resp->txed) {
+ IWL_DEBUG_TX_REPLY(priv,
+ "bogus sent(%d) and ack(%d) count\n",
+ ba_resp->txed, ba_resp->txed_2_done);
/*
- * sent and ack information provided by uCode
- * use it instead of figure out ourself
+ * set txed_2_done = txed,
+ * so it won't impact rate scale
*/
- if (ba_resp->txed_2_done > ba_resp->txed) {
- IWL_DEBUG_TX_REPLY(priv,
- "bogus sent(%d) and ack(%d) count\n",
- ba_resp->txed, ba_resp->txed_2_done);
- /*
- * set txed_2_done = txed,
- * so it won't impact rate scale
- */
- ba_resp->txed = ba_resp->txed_2_done;
- }
- IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n",
- ba_resp->txed, ba_resp->txed_2_done);
- } else {
- u64 bitmap, sent_bitmap;
-
- /* don't use 64-bit values for now */
- bitmap = le64_to_cpu(ba_resp->bitmap) >> sh;
-
- /* check for success or failure according to the
- * transmitted bitmap and block-ack bitmap */
- sent_bitmap = bitmap & agg->bitmap;
-
- /* For each frame attempted in aggregation,
- * update driver's record of tx frame's status. */
- 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;
- }
+ ba_resp->txed = ba_resp->txed_2_done;
+ }
+ IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n",
+ ba_resp->txed, ba_resp->txed_2_done);
- IWL_DEBUG_TX_REPLY(priv, "Bitmap %llx\n",
- (unsigned long long)bitmap);
+ /* Find the first ACKed frame to store the TX status */
+ while (sent_bitmap && !(sent_bitmap & 1)) {
+ agg->start_idx = (agg->start_idx + 1) & 0xff;
+ sent_bitmap >>= 1;
}
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;
- if (!priv->cfg->base_params->no_agg_framecnt_info && ba_resp->txed) {
- info->status.ampdu_ack_len = ba_resp->txed_2_done;
- info->status.ampdu_len = ba_resp->txed;
-
- } else {
- info->status.ampdu_ack_len = successes;
- info->status.ampdu_len = agg->frame_count;
- }
+ info->status.ampdu_ack_len = ba_resp->txed_2_done;
+ info->status.ampdu_len = ba_resp->txed;
iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info);
return 0;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
index d807e5e2b718..97de5d9de67b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
@@ -2,7 +2,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 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
@@ -161,47 +161,19 @@ static int iwlagn_load_section(struct iwl_priv *priv, const char *name,
}
static int iwlagn_load_given_ucode(struct iwl_priv *priv,
- struct fw_desc *inst_image,
- struct fw_desc *data_image)
+ struct fw_img *image)
{
int ret = 0;
- ret = iwlagn_load_section(priv, "INST", inst_image,
+ ret = iwlagn_load_section(priv, "INST", &image->code,
IWLAGN_RTC_INST_LOWER_BOUND);
if (ret)
return ret;
- return iwlagn_load_section(priv, "DATA", data_image,
+ return iwlagn_load_section(priv, "DATA", &image->data,
IWLAGN_RTC_DATA_LOWER_BOUND);
}
-int iwlagn_load_ucode(struct iwl_priv *priv)
-{
- int ret = 0;
-
- /* check whether init ucode should be loaded, or rather runtime ucode */
- if (priv->ucode_init.len && (priv->ucode_type == UCODE_NONE)) {
- IWL_DEBUG_INFO(priv, "Init ucode found. Loading init ucode...\n");
- ret = iwlagn_load_given_ucode(priv,
- &priv->ucode_init, &priv->ucode_init_data);
- if (!ret) {
- IWL_DEBUG_INFO(priv, "Init ucode load complete.\n");
- priv->ucode_type = UCODE_INIT;
- }
- } else {
- IWL_DEBUG_INFO(priv, "Init ucode not found, or already loaded. "
- "Loading runtime ucode...\n");
- ret = iwlagn_load_given_ucode(priv,
- &priv->ucode_code, &priv->ucode_data);
- if (!ret) {
- IWL_DEBUG_INFO(priv, "Runtime ucode load complete.\n");
- priv->ucode_type = UCODE_RT;
- }
- }
-
- return ret;
-}
-
/*
* Calibration
*/
@@ -245,8 +217,8 @@ static int iwlagn_send_calib_cfg(struct iwl_priv *priv)
struct iwl_calib_cfg_cmd calib_cfg_cmd;
struct iwl_host_cmd cmd = {
.id = CALIBRATION_CFG_CMD,
- .len = sizeof(struct iwl_calib_cfg_cmd),
- .data = &calib_cfg_cmd,
+ .len = { sizeof(struct iwl_calib_cfg_cmd), },
+ .data = { &calib_cfg_cmd, },
};
memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd));
@@ -297,33 +269,9 @@ void iwlagn_rx_calib_result(struct iwl_priv *priv,
iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len);
}
-void iwlagn_rx_calib_complete(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb)
+int iwlagn_init_alive_start(struct iwl_priv *priv)
{
- IWL_DEBUG_INFO(priv, "Init. calibration is completed, restarting fw.\n");
- queue_work(priv->workqueue, &priv->restart);
-}
-
-void iwlagn_init_alive_start(struct iwl_priv *priv)
-{
- int ret = 0;
-
- /* initialize uCode was loaded... verify inst image.
- * This is a paranoid check, because we would not have gotten the
- * "initialize" alive if code weren't properly loaded. */
- if (iwl_verify_ucode(priv)) {
- /* Runtime instruction load was bad;
- * take it all the way back down so we can try again */
- IWL_DEBUG_INFO(priv, "Bad \"initialize\" uCode load.\n");
- goto restart;
- }
-
- ret = priv->cfg->ops->lib->alive_notify(priv);
- if (ret) {
- IWL_WARN(priv,
- "Could not complete ALIVE transition: %d\n", ret);
- goto restart;
- }
+ int ret;
if (priv->cfg->bt_params &&
priv->cfg->bt_params->advanced_bt_coexist) {
@@ -333,24 +281,25 @@ void iwlagn_init_alive_start(struct iwl_priv *priv)
* no need to close the envlope since we are going
* to load the runtime uCode later.
*/
- iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
+ ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
+ if (ret)
+ return ret;
}
- iwlagn_send_calib_cfg(priv);
+
+ ret = iwlagn_send_calib_cfg(priv);
+ if (ret)
+ return ret;
/**
* temperature offset calibration is only needed for runtime ucode,
* so prepare the value now.
*/
if (priv->cfg->need_temp_offset_calib)
- iwlagn_set_temperature_offset_calib(priv);
+ return iwlagn_set_temperature_offset_calib(priv);
- return;
-
-restart:
- /* real restart (first load init_ucode) */
- queue_work(priv->workqueue, &priv->restart);
+ return 0;
}
static int iwlagn_send_wimax_coex(struct iwl_priv *priv)
@@ -413,25 +362,30 @@ void iwlagn_send_prio_tbl(struct iwl_priv *priv)
IWL_ERR(priv, "failed to send BT prio tbl command\n");
}
-void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
+int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type)
{
struct iwl_bt_coex_prot_env_cmd env_cmd;
+ int ret;
env_cmd.action = action;
env_cmd.type = type;
- if (iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PROT_ENV,
- sizeof(env_cmd), &env_cmd))
+ ret = iwl_send_cmd_pdu(priv, REPLY_BT_COEX_PROT_ENV,
+ sizeof(env_cmd), &env_cmd);
+ if (ret)
IWL_ERR(priv, "failed to send BT env command\n");
+ return ret;
}
-int iwlagn_alive_notify(struct iwl_priv *priv)
+static int iwlagn_alive_notify(struct iwl_priv *priv)
{
const struct queue_to_fifo_ac *queue_to_fifo;
+ struct iwl_rxon_context *ctx;
u32 a;
unsigned long flags;
int i, chan;
u32 reg_val;
+ int ret;
spin_lock_irqsave(&priv->lock, flags);
@@ -486,7 +440,7 @@ int iwlagn_alive_notify(struct iwl_priv *priv)
IWL_MASK(0, priv->hw_params.max_txq_num));
/* Activate all Tx DMA/FIFO channels */
- priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7));
+ iwlagn_txq_set_sched(priv, IWL_MASK(0, 7));
/* map queues to FIFOs */
if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))
@@ -500,6 +454,8 @@ int iwlagn_alive_notify(struct iwl_priv *priv)
memset(&priv->queue_stopped[0], 0, sizeof(priv->queue_stopped));
for (i = 0; i < 4; i++)
atomic_set(&priv->queue_stop_count[i], 0);
+ for_each_context(priv, ctx)
+ ctx->last_tx_rejected = false;
/* reset to 0 to enable all the queue first */
priv->txq_ctx_active_msk = 0;
@@ -527,12 +483,15 @@ int iwlagn_alive_notify(struct iwl_priv *priv)
iwl_clear_bits_prph(priv, APMG_PCIDEV_STT_REG,
APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
- iwlagn_send_wimax_coex(priv);
+ ret = iwlagn_send_wimax_coex(priv);
+ if (ret)
+ return ret;
- iwlagn_set_Xtal_calib(priv);
- iwl_send_calib_results(priv);
+ ret = iwlagn_set_Xtal_calib(priv);
+ if (ret)
+ return ret;
- return 0;
+ return iwl_send_calib_results(priv);
}
@@ -541,11 +500,12 @@ int iwlagn_alive_notify(struct iwl_priv *priv)
* 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)
+static int iwlcore_verify_inst_sparse(struct iwl_priv *priv,
+ struct fw_desc *fw_desc)
{
+ __le32 *image = (__le32 *)fw_desc->v_addr;
+ u32 len = fw_desc->len;
u32 val;
- int ret = 0;
- u32 errcnt = 0;
u32 i;
IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
@@ -556,104 +516,204 @@ static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32
* 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;
- }
+ val = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
+ if (val != le32_to_cpu(*image))
+ return -EIO;
}
- return ret;
+ return 0;
}
-/**
- * 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)
+static void iwl_print_mismatch_inst(struct iwl_priv *priv,
+ struct fw_desc *fw_desc)
{
+ __le32 *image = (__le32 *)fw_desc->v_addr;
+ u32 len = fw_desc->len;
u32 val;
- u32 save_len = len;
- int ret = 0;
- u32 errcnt;
+ u32 offs;
+ int errors = 0;
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++) {
+ for (offs = 0;
+ offs < len && errors < 20;
+ offs += 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);
+ val = iwl_read32(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;
+ IWL_ERR(priv, "uCode INST section at "
+ "offset 0x%x, is 0x%x, s/b 0x%x\n",
+ offs, val, le32_to_cpu(*image));
+ errors++;
}
}
-
- 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)
+static int iwl_verify_ucode(struct iwl_priv *priv, struct fw_img *img)
+{
+ if (!iwlcore_verify_inst_sparse(priv, &img->code)) {
+ IWL_DEBUG_INFO(priv, "uCode is good in inst SRAM\n");
+ return 0;
+ }
+
+ IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");
+
+ iwl_print_mismatch_inst(priv, &img->code);
+ return -EIO;
+}
+
+struct iwlagn_alive_data {
+ bool valid;
+ u8 subtype;
+};
+
+static void iwlagn_alive_fn(struct iwl_priv *priv,
+ struct iwl_rx_packet *pkt,
+ void *data)
{
- __le32 *image;
- u32 len;
+ struct iwlagn_alive_data *alive_data = data;
+ struct iwl_alive_resp *palive;
+
+ palive = &pkt->u.alive_frame;
+
+ IWL_DEBUG_INFO(priv, "Alive ucode status 0x%08X revision "
+ "0x%01X 0x%01X\n",
+ palive->is_valid, palive->ver_type,
+ palive->ver_subtype);
+
+ priv->device_pointers.error_event_table =
+ le32_to_cpu(palive->error_event_table_ptr);
+ priv->device_pointers.log_event_table =
+ le32_to_cpu(palive->log_event_table_ptr);
+
+ alive_data->subtype = palive->ver_subtype;
+ alive_data->valid = palive->is_valid == UCODE_VALID_OK;
+}
+
+#define UCODE_ALIVE_TIMEOUT HZ
+#define UCODE_CALIB_TIMEOUT (2*HZ)
+
+int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
+ struct fw_img *image,
+ int subtype, int alternate_subtype)
+{
+ struct iwl_notification_wait alive_wait;
+ struct iwlagn_alive_data alive_data;
int ret;
+ enum iwlagn_ucode_subtype old_type;
- /* 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;
+ ret = iwlagn_start_device(priv);
+ if (ret)
+ return ret;
+
+ iwlagn_init_notification_wait(priv, &alive_wait, REPLY_ALIVE,
+ iwlagn_alive_fn, &alive_data);
+
+ old_type = priv->ucode_type;
+ priv->ucode_type = subtype;
+
+ ret = iwlagn_load_given_ucode(priv, image);
+ if (ret) {
+ priv->ucode_type = old_type;
+ iwlagn_remove_notification(priv, &alive_wait);
+ return ret;
}
- /* 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;
+ /* Remove all resets to allow NIC to operate */
+ iwl_write32(priv, CSR_RESET, 0);
+
+ /*
+ * Some things may run in the background now, but we
+ * just wait for the ALIVE notification here.
+ */
+ ret = iwlagn_wait_notification(priv, &alive_wait, UCODE_ALIVE_TIMEOUT);
+ if (ret) {
+ priv->ucode_type = old_type;
+ return ret;
}
- /* 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;
+ if (!alive_data.valid) {
+ IWL_ERR(priv, "Loaded ucode is not valid!\n");
+ priv->ucode_type = old_type;
+ return -EIO;
+ }
+
+ if (alive_data.subtype != subtype &&
+ alive_data.subtype != alternate_subtype) {
+ IWL_ERR(priv,
+ "Loaded ucode is not expected type (got %d, expected %d)!\n",
+ alive_data.subtype, subtype);
+ priv->ucode_type = old_type;
+ return -EIO;
}
- IWL_ERR(priv, "NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
+ ret = iwl_verify_ucode(priv, image);
+ if (ret) {
+ priv->ucode_type = old_type;
+ return ret;
+ }
+
+ /* delay a bit to give rfkill time to run */
+ msleep(5);
+
+ ret = iwlagn_alive_notify(priv);
+ if (ret) {
+ IWL_WARN(priv,
+ "Could not complete ALIVE transition: %d\n", ret);
+ priv->ucode_type = old_type;
+ return ret;
+ }
+
+ return 0;
+}
+
+int iwlagn_run_init_ucode(struct iwl_priv *priv)
+{
+ struct iwl_notification_wait calib_wait;
+ int ret;
+
+ lockdep_assert_held(&priv->mutex);
+
+ /* No init ucode required? Curious, but maybe ok */
+ if (!priv->ucode_init.code.len)
+ return 0;
+
+ if (priv->ucode_type != UCODE_SUBTYPE_NONE_LOADED)
+ return 0;
+
+ iwlagn_init_notification_wait(priv, &calib_wait,
+ CALIBRATION_COMPLETE_NOTIFICATION,
+ NULL, NULL);
+
+ /* Will also start the device */
+ ret = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init,
+ UCODE_SUBTYPE_INIT, -1);
+ if (ret)
+ goto error;
+
+ ret = iwlagn_init_alive_start(priv);
+ if (ret)
+ goto error;
+
+ /*
+ * Some things may run in the background now, but we
+ * just wait for the calibration complete notification.
+ */
+ ret = iwlagn_wait_notification(priv, &calib_wait, UCODE_CALIB_TIMEOUT);
- /* 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);
+ goto out;
+ error:
+ iwlagn_remove_notification(priv, &calib_wait);
+ out:
+ /* Whatever happened, stop the device */
+ iwlagn_stop_device(priv);
return ret;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 321b18b59135..11c6c1169e78 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
@@ -59,7 +59,6 @@
#include "iwl-sta.h"
#include "iwl-agn-calib.h"
#include "iwl-agn.h"
-#include "iwl-agn-led.h"
/******************************************************************************
@@ -103,70 +102,6 @@ void iwl_update_chain_flags(struct iwl_priv *priv)
}
}
-static void iwl_clear_free_frames(struct iwl_priv *priv)
-{
- struct list_head *element;
-
- IWL_DEBUG_INFO(priv, "%d frames on pre-allocated heap on clear.\n",
- priv->frames_count);
-
- while (!list_empty(&priv->free_frames)) {
- element = priv->free_frames.next;
- list_del(element);
- kfree(list_entry(element, struct iwl_frame, list));
- priv->frames_count--;
- }
-
- if (priv->frames_count) {
- IWL_WARN(priv, "%d frames still in use. Did we lose one?\n",
- priv->frames_count);
- priv->frames_count = 0;
- }
-}
-
-static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv)
-{
- struct iwl_frame *frame;
- struct list_head *element;
- if (list_empty(&priv->free_frames)) {
- frame = kzalloc(sizeof(*frame), GFP_KERNEL);
- if (!frame) {
- IWL_ERR(priv, "Could not allocate frame!\n");
- return NULL;
- }
-
- priv->frames_count++;
- return frame;
- }
-
- element = priv->free_frames.next;
- list_del(element);
- return list_entry(element, struct iwl_frame, list);
-}
-
-static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame)
-{
- memset(frame, 0, sizeof(*frame));
- list_add(&frame->list, &priv->free_frames);
-}
-
-static u32 iwl_fill_beacon_frame(struct iwl_priv *priv,
- struct ieee80211_hdr *hdr,
- int left)
-{
- lockdep_assert_held(&priv->mutex);
-
- if (!priv->beacon_skb)
- return 0;
-
- if (priv->beacon_skb->len > left)
- return 0;
-
- memcpy(hdr, priv->beacon_skb->data, priv->beacon_skb->len);
-
- return priv->beacon_skb->len;
-}
-
/* Parse the beacon frame to find the TIM element and set tim_idx & tim_size */
static void iwl_set_beacon_tim(struct iwl_priv *priv,
struct iwl_tx_beacon_cmd *tx_beacon_cmd,
@@ -194,13 +129,16 @@ static void iwl_set_beacon_tim(struct iwl_priv *priv,
IWL_WARN(priv, "Unable to find TIM Element in beacon\n");
}
-static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
- struct iwl_frame *frame)
+int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
{
struct iwl_tx_beacon_cmd *tx_beacon_cmd;
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_TX_BEACON,
+ };
u32 frame_size;
u32 rate_flags;
u32 rate;
+
/*
* We have to set up the TX command, the TX Beacon command, and the
* beacon contents.
@@ -213,17 +151,17 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
return 0;
}
- /* Initialize memory */
- tx_beacon_cmd = &frame->u.beacon;
- memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
+ if (WARN_ON(!priv->beacon_skb))
+ return -EINVAL;
+
+ /* Allocate beacon command */
+ if (!priv->beacon_cmd)
+ priv->beacon_cmd = kzalloc(sizeof(*tx_beacon_cmd), GFP_KERNEL);
+ tx_beacon_cmd = priv->beacon_cmd;
+ if (!tx_beacon_cmd)
+ return -ENOMEM;
- /* Set up TX beacon contents */
- frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame,
- sizeof(frame->u) - sizeof(*tx_beacon_cmd));
- if (WARN_ON_ONCE(frame_size > MAX_MPDU_SIZE))
- return 0;
- if (!frame_size)
- return 0;
+ frame_size = priv->beacon_skb->len;
/* Set up TX command fields */
tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
@@ -233,7 +171,7 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
TX_CMD_FLG_TSF_MSK | TX_CMD_FLG_STA_RATE_MSK;
/* Set up TX beacon command fields */
- iwl_set_beacon_tim(priv, tx_beacon_cmd, (u8 *)tx_beacon_cmd->frame,
+ iwl_set_beacon_tim(priv, tx_beacon_cmd, priv->beacon_skb->data,
frame_size);
/* Set up packet rate and flags */
@@ -246,182 +184,15 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
tx_beacon_cmd->tx.rate_n_flags = iwl_hw_set_rate_n_flags(rate,
rate_flags);
- return sizeof(*tx_beacon_cmd) + frame_size;
-}
-
-int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
-{
- struct iwl_frame *frame;
- unsigned int frame_size;
- int rc;
-
- frame = iwl_get_free_frame(priv);
- if (!frame) {
- IWL_ERR(priv, "Could not obtain free frame buffer for beacon "
- "command.\n");
- return -ENOMEM;
- }
-
- frame_size = iwl_hw_get_beacon_cmd(priv, frame);
- if (!frame_size) {
- IWL_ERR(priv, "Error configuring the beacon command\n");
- iwl_free_frame(priv, frame);
- return -EINVAL;
- }
-
- rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size,
- &frame->u.cmd[0]);
-
- iwl_free_frame(priv, frame);
-
- return rc;
-}
-
-static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx)
-{
- struct iwl_tfd_tb *tb = &tfd->tbs[idx];
-
- dma_addr_t addr = get_unaligned_le32(&tb->lo);
- if (sizeof(dma_addr_t) > sizeof(u32))
- addr |=
- ((dma_addr_t)(le16_to_cpu(tb->hi_n_len) & 0xF) << 16) << 16;
-
- return addr;
-}
-
-static inline u16 iwl_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx)
-{
- struct iwl_tfd_tb *tb = &tfd->tbs[idx];
-
- return le16_to_cpu(tb->hi_n_len) >> 4;
-}
-
-static inline void iwl_tfd_set_tb(struct iwl_tfd *tfd, u8 idx,
- dma_addr_t addr, u16 len)
-{
- struct iwl_tfd_tb *tb = &tfd->tbs[idx];
- u16 hi_n_len = len << 4;
-
- put_unaligned_le32(addr, &tb->lo);
- if (sizeof(dma_addr_t) > sizeof(u32))
- hi_n_len |= ((addr >> 16) >> 16) & 0xF;
-
- tb->hi_n_len = cpu_to_le16(hi_n_len);
-
- tfd->num_tbs = idx + 1;
-}
-
-static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd)
-{
- return tfd->num_tbs & 0x1f;
-}
-
-/**
- * iwl_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
- * @priv - driver private data
- * @txq - tx queue
- *
- * Does NOT advance any TFD circular buffer read/write indexes
- * Does NOT free the TFD itself (which is within circular buffer)
- */
-void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
-{
- struct iwl_tfd *tfd_tmp = (struct iwl_tfd *)txq->tfds;
- struct iwl_tfd *tfd;
- struct pci_dev *dev = priv->pci_dev;
- int index = txq->q.read_ptr;
- int i;
- int num_tbs;
-
- tfd = &tfd_tmp[index];
-
- /* Sanity check on number of chunks */
- num_tbs = iwl_tfd_get_num_tbs(tfd);
-
- if (num_tbs >= IWL_NUM_OF_TBS) {
- IWL_ERR(priv, "Too many chunks: %i\n", num_tbs);
- /* @todo issue fatal error, it is quite serious situation */
- return;
- }
-
- /* Unmap tx_cmd */
- if (num_tbs)
- pci_unmap_single(dev,
- 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++)
- pci_unmap_single(dev, iwl_tfd_tb_get_addr(tfd, i),
- iwl_tfd_tb_get_len(tfd, i), PCI_DMA_TODEVICE);
-
- /* 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;
- }
- }
-}
-
-int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,
- struct iwl_tx_queue *txq,
- dma_addr_t addr, u16 len,
- u8 reset, u8 pad)
-{
- struct iwl_queue *q;
- struct iwl_tfd *tfd, *tfd_tmp;
- u32 num_tbs;
-
- q = &txq->q;
- tfd_tmp = (struct iwl_tfd *)txq->tfds;
- tfd = &tfd_tmp[q->write_ptr];
-
- if (reset)
- memset(tfd, 0, sizeof(*tfd));
-
- num_tbs = iwl_tfd_get_num_tbs(tfd);
-
- /* Each TFD can point to a maximum 20 Tx buffers */
- if (num_tbs >= IWL_NUM_OF_TBS) {
- IWL_ERR(priv, "Error can not send more than %d chunks\n",
- IWL_NUM_OF_TBS);
- return -EINVAL;
- }
-
- BUG_ON(addr & ~DMA_BIT_MASK(36));
- if (unlikely(addr & ~IWL_TX_DMA_MASK))
- IWL_ERR(priv, "Unaligned address = %llx\n",
- (unsigned long long)addr);
-
- iwl_tfd_set_tb(tfd, num_tbs, addr, len);
-
- return 0;
-}
+ /* Submit command */
+ cmd.len[0] = sizeof(*tx_beacon_cmd);
+ cmd.data[0] = tx_beacon_cmd;
+ cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
+ cmd.len[1] = frame_size;
+ cmd.data[1] = priv->beacon_skb->data;
+ cmd.dataflags[1] = IWL_HCMD_DFL_NOCOPY;
-/*
- * Tell nic where to find circular buffer of Tx Frame Descriptors for
- * given Tx queue, and enable the DMA channel used for that queue.
- *
- * 4965 supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA
- * channels supported in hardware.
- */
-int iwl_hw_tx_queue_init(struct iwl_priv *priv,
- struct iwl_tx_queue *txq)
-{
- int txq_id = txq->q.id;
-
- /* Circular buffer (TFD queue in DRAM) physical base address */
- iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
- txq->q.dma_addr >> 8);
-
- return 0;
+ return iwl_send_cmd_sync(priv, &cmd);
}
static void iwl_bg_beacon_update(struct work_struct *work)
@@ -483,12 +254,14 @@ static void iwl_bg_bt_full_concurrency(struct work_struct *work)
container_of(work, struct iwl_priv, bt_full_concurrency);
struct iwl_rxon_context *ctx;
+ mutex_lock(&priv->mutex);
+
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
+ goto out;
/* dont send host command if rf-kill is on */
if (!iwl_is_ready_rf(priv))
- return;
+ goto out;
IWL_DEBUG_INFO(priv, "BT coex in %s mode\n",
priv->bt_full_concurrent ?
@@ -498,15 +271,15 @@ static void iwl_bg_bt_full_concurrency(struct work_struct *work)
* LQ & RXON updated cmds must be sent before BT Config cmd
* to avoid 3-wire collisions
*/
- mutex_lock(&priv->mutex);
for_each_context(priv, ctx) {
if (priv->cfg->ops->hcmd->set_rxon_chain)
priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
iwlcore_commit_rxon(priv, ctx);
}
- mutex_unlock(&priv->mutex);
priv->cfg->ops->hcmd->send_bt_config(priv);
+out:
+ mutex_unlock(&priv->mutex);
}
/**
@@ -556,7 +329,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
}
/* Set starting address; reads will auto-increment */
- _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr);
+ iwl_write32(priv, HBUS_TARG_MEM_RADDR, ptr);
rmb();
/*
@@ -564,13 +337,13 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base,
* place event id # at far right for easier visual parsing.
*/
for (i = 0; i < num_events; i++) {
- ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
- time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+ ev = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
+ time = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
if (mode == 0) {
trace_iwlwifi_dev_ucode_cont_event(priv,
0, time, ev);
} else {
- data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+ data = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
trace_iwlwifi_dev_ucode_cont_event(priv,
time, data, ev);
}
@@ -588,10 +361,7 @@ static void iwl_continuous_event_trace(struct iwl_priv *priv)
u32 num_wraps; /* # times uCode wrapped to top of log */
u32 next_entry; /* index of next entry to be written by uCode */
- if (priv->ucode_type == UCODE_INIT)
- base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
- else
- base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+ base = priv->device_pointers.error_event_table;
if (priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
capacity = iwl_read_targ_mem(priv, base);
num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
@@ -720,7 +490,10 @@ static void iwl_rx_handle(struct iwl_priv *priv)
/* If an RXB doesn't have a Rx queue slot associated with it,
* then a bug has been introduced in the queue refilling
* routines -- catch it here */
- BUG_ON(rxb == NULL);
+ if (WARN_ON(rxb == NULL)) {
+ i = (i + 1) & RX_QUEUE_MASK;
+ continue;
+ }
rxq->queue[i] = NULL;
@@ -760,13 +533,15 @@ static void iwl_rx_handle(struct iwl_priv *priv)
if (w->cmd == pkt->hdr.cmd) {
w->triggered = true;
if (w->fn)
- w->fn(priv, pkt);
+ w->fn(priv, pkt, w->fn_data);
}
}
spin_unlock(&priv->_agn.notif_wait_lock);
wake_up_all(&priv->_agn.notif_waitq);
}
+ if (priv->pre_rx_handler)
+ priv->pre_rx_handler(priv, rxb);
/* Based on type of command response or notification,
* handle those that need handling via function in
@@ -837,199 +612,6 @@ static void iwl_rx_handle(struct iwl_priv *priv)
iwlagn_rx_queue_restock(priv);
}
-/* call this function to flush any scheduled tasklet */
-static inline void iwl_synchronize_irq(struct iwl_priv *priv)
-{
- /* wait to make sure we flush pending tasklet*/
- synchronize_irq(priv->pci_dev->irq);
- tasklet_kill(&priv->irq_tasklet);
-}
-
-static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
-{
- u32 inta, handled = 0;
- u32 inta_fh;
- unsigned long flags;
- u32 i;
-#ifdef CONFIG_IWLWIFI_DEBUG
- u32 inta_mask;
-#endif
-
- spin_lock_irqsave(&priv->lock, flags);
-
- /* Ack/clear/reset pending uCode interrupts.
- * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,
- * and will clear only when CSR_FH_INT_STATUS gets cleared. */
- inta = iwl_read32(priv, CSR_INT);
- iwl_write32(priv, CSR_INT, inta);
-
- /* Ack/clear/reset pending flow-handler (DMA) interrupts.
- * Any new interrupts that happen after this, either while we're
- * in this tasklet, or later, will show up in next ISR/tasklet. */
- inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
- iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
-
-#ifdef CONFIG_IWLWIFI_DEBUG
- if (iwl_get_debug_level(priv) & IWL_DL_ISR) {
- /* just for debug */
- inta_mask = iwl_read32(priv, CSR_INT_MASK);
- IWL_DEBUG_ISR(priv, "inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
- inta, inta_mask, inta_fh);
- }
-#endif
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- /* Since CSR_INT and CSR_FH_INT_STATUS reads and clears are not
- * atomic, make sure that inta covers all the interrupts that
- * we've discovered, even if FH interrupt came in just after
- * reading CSR_INT. */
- if (inta_fh & CSR49_FH_INT_RX_MASK)
- inta |= CSR_INT_BIT_FH_RX;
- if (inta_fh & CSR49_FH_INT_TX_MASK)
- inta |= CSR_INT_BIT_FH_TX;
-
- /* Now service all interrupt bits discovered above. */
- if (inta & CSR_INT_BIT_HW_ERR) {
- IWL_ERR(priv, "Hardware error detected. Restarting.\n");
-
- /* Tell the device to stop sending interrupts */
- iwl_disable_interrupts(priv);
-
- priv->isr_stats.hw++;
- iwl_irq_handle_error(priv);
-
- handled |= CSR_INT_BIT_HW_ERR;
-
- return;
- }
-
-#ifdef CONFIG_IWLWIFI_DEBUG
- if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) {
- /* NIC fires this, but we don't use it, redundant with WAKEUP */
- if (inta & CSR_INT_BIT_SCD) {
- IWL_DEBUG_ISR(priv, "Scheduler finished to transmit "
- "the frame/frames.\n");
- priv->isr_stats.sch++;
- }
-
- /* Alive notification via Rx interrupt will do the real work */
- if (inta & CSR_INT_BIT_ALIVE) {
- IWL_DEBUG_ISR(priv, "Alive interrupt\n");
- priv->isr_stats.alive++;
- }
- }
-#endif
- /* Safely ignore these bits for debug checks below */
- inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE);
-
- /* HW RF KILL switch toggled */
- if (inta & CSR_INT_BIT_RF_KILL) {
- int hw_rf_kill = 0;
- if (!(iwl_read32(priv, CSR_GP_CNTRL) &
- CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
- hw_rf_kill = 1;
-
- IWL_WARN(priv, "RF_KILL bit toggled to %s.\n",
- hw_rf_kill ? "disable radio" : "enable radio");
-
- priv->isr_stats.rfkill++;
-
- /* driver only loads ucode once setting the interface up.
- * the driver allows loading the ucode even if the radio
- * is killed. Hence update the killswitch state here. The
- * rfkill handler will care about restarting if needed.
- */
- if (!test_bit(STATUS_ALIVE, &priv->status)) {
- if (hw_rf_kill)
- 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_rf_kill);
- }
-
- handled |= CSR_INT_BIT_RF_KILL;
- }
-
- /* Chip got too hot and stopped itself */
- if (inta & CSR_INT_BIT_CT_KILL) {
- IWL_ERR(priv, "Microcode CT kill error detected.\n");
- priv->isr_stats.ctkill++;
- handled |= CSR_INT_BIT_CT_KILL;
- }
-
- /* Error detected by uCode */
- if (inta & CSR_INT_BIT_SW_ERR) {
- IWL_ERR(priv, "Microcode SW error detected. "
- " Restarting 0x%X.\n", inta);
- priv->isr_stats.sw++;
- iwl_irq_handle_error(priv);
- handled |= CSR_INT_BIT_SW_ERR;
- }
-
- /*
- * uCode wakes up after power-down sleep.
- * Tell device about any new tx or host commands enqueued,
- * and about any Rx buffers made available while asleep.
- */
- if (inta & CSR_INT_BIT_WAKEUP) {
- IWL_DEBUG_ISR(priv, "Wakeup interrupt\n");
- iwl_rx_queue_update_write_ptr(priv, &priv->rxq);
- for (i = 0; i < priv->hw_params.max_txq_num; i++)
- iwl_txq_update_write_ptr(priv, &priv->txq[i]);
- priv->isr_stats.wakeup++;
- handled |= CSR_INT_BIT_WAKEUP;
- }
-
- /* All uCode command responses, including Tx command responses,
- * Rx "responses" (frame-received notification), and other
- * notifications from uCode come through here*/
- if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
- iwl_rx_handle(priv);
- priv->isr_stats.rx++;
- handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
- }
-
- /* This "Tx" DMA channel is used only for loading uCode */
- if (inta & CSR_INT_BIT_FH_TX) {
- IWL_DEBUG_ISR(priv, "uCode load interrupt\n");
- priv->isr_stats.tx++;
- handled |= CSR_INT_BIT_FH_TX;
- /* Wake up uCode load routine, now that load is complete */
- priv->ucode_write_complete = 1;
- wake_up_interruptible(&priv->wait_command_queue);
- }
-
- if (inta & ~handled) {
- IWL_ERR(priv, "Unhandled INTA bits 0x%08x\n", inta & ~handled);
- priv->isr_stats.unhandled++;
- }
-
- if (inta & ~(priv->inta_mask)) {
- IWL_WARN(priv, "Disabled INTA bits 0x%08x were pending\n",
- inta & ~priv->inta_mask);
- IWL_WARN(priv, " with FH_INT = 0x%08x\n", inta_fh);
- }
-
- /* Re-enable all interrupts */
- /* only Re-enable if disabled by irq */
- if (test_bit(STATUS_INT_ENABLED, &priv->status))
- iwl_enable_interrupts(priv);
- /* Re-enable RF_KILL if it occurred */
- else if (handled & CSR_INT_BIT_RF_KILL)
- iwl_enable_rfkill_int(priv);
-
-#ifdef CONFIG_IWLWIFI_DEBUG
- if (iwl_get_debug_level(priv) & (IWL_DL_ISR)) {
- inta = iwl_read32(priv, CSR_INT);
- inta_mask = iwl_read32(priv, CSR_INT_MASK);
- inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
- IWL_DEBUG_ISR(priv, "End inta 0x%08x, enabled 0x%08x, fh 0x%08x, "
- "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags);
- }
-#endif
-}
-
/* tasklet for iwlagn interrupt */
static void iwl_irq_tasklet(struct iwl_priv *priv)
{
@@ -1171,7 +753,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) {
handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX);
iwl_write32(priv, CSR_FH_INT_STATUS,
- CSR49_FH_INT_RX_MASK);
+ CSR_FH_INT_RX_MASK);
}
if (inta & CSR_INT_BIT_RX_PERIODIC) {
handled |= CSR_INT_BIT_RX_PERIODIC;
@@ -1209,7 +791,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
/* This "Tx" DMA channel is used only for loading uCode */
if (inta & CSR_INT_BIT_FH_TX) {
- iwl_write32(priv, CSR_FH_INT_STATUS, CSR49_FH_INT_TX_MASK);
+ iwl_write32(priv, CSR_FH_INT_STATUS, CSR_FH_INT_TX_MASK);
IWL_DEBUG_ISR(priv, "uCode load interrupt\n");
priv->isr_stats.tx++;
handled |= CSR_INT_BIT_FH_TX;
@@ -1357,26 +939,48 @@ static struct attribute_group iwl_attribute_group = {
*
******************************************************************************/
-static void iwl_dealloc_ucode_pci(struct iwl_priv *priv)
+static void iwl_free_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc)
{
- iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code);
- iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data);
- iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
- iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init);
- iwl_free_fw_desc(priv->pci_dev, &priv->ucode_init_data);
- iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot);
+ if (desc->v_addr)
+ dma_free_coherent(&pci_dev->dev, desc->len,
+ desc->v_addr, desc->p_addr);
+ desc->v_addr = NULL;
+ desc->len = 0;
}
-static void iwl_nic_start(struct iwl_priv *priv)
+static void iwl_free_fw_img(struct pci_dev *pci_dev, struct fw_img *img)
{
- /* Remove all resets to allow NIC to operate */
- iwl_write32(priv, CSR_RESET, 0);
+ iwl_free_fw_desc(pci_dev, &img->code);
+ iwl_free_fw_desc(pci_dev, &img->data);
+}
+
+static int iwl_alloc_fw_desc(struct pci_dev *pci_dev, struct fw_desc *desc,
+ const void *data, size_t len)
+{
+ if (!len) {
+ desc->v_addr = NULL;
+ return -EINVAL;
+ }
+
+ desc->v_addr = dma_alloc_coherent(&pci_dev->dev, len,
+ &desc->p_addr, GFP_KERNEL);
+ if (!desc->v_addr)
+ return -ENOMEM;
+ desc->len = len;
+ memcpy(desc->v_addr, data, len);
+ return 0;
+}
+
+static void iwl_dealloc_ucode_pci(struct iwl_priv *priv)
+{
+ iwl_free_fw_img(priv->pci_dev, &priv->ucode_rt);
+ iwl_free_fw_img(priv->pci_dev, &priv->ucode_init);
}
struct iwlagn_ucode_capabilities {
u32 max_probe_length;
u32 standard_phy_calibration_size;
- bool pan;
+ u32 flags;
};
static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context);
@@ -1422,8 +1026,8 @@ static int __must_check iwl_request_firmware(struct iwl_priv *priv, bool first)
}
struct iwlagn_firmware_pieces {
- const void *inst, *data, *init, *init_data, *boot;
- size_t inst_size, data_size, init_size, init_data_size, boot_size;
+ const void *inst, *data, *init, *init_data;
+ size_t inst_size, data_size, init_size, init_data_size;
u32 build;
@@ -1444,28 +1048,18 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv,
switch (api_ver) {
default:
- /*
- * 4965 doesn't revision the firmware file format
- * along with the API version, it always uses v1
- * file format.
- */
- if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) !=
- CSR_HW_REV_TYPE_4965) {
- hdr_size = 28;
- if (ucode_raw->size < hdr_size) {
- IWL_ERR(priv, "File size too small!\n");
- return -EINVAL;
- }
- pieces->build = le32_to_cpu(ucode->u.v2.build);
- pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size);
- pieces->data_size = le32_to_cpu(ucode->u.v2.data_size);
- pieces->init_size = le32_to_cpu(ucode->u.v2.init_size);
- pieces->init_data_size = le32_to_cpu(ucode->u.v2.init_data_size);
- pieces->boot_size = le32_to_cpu(ucode->u.v2.boot_size);
- src = ucode->u.v2.data;
- break;
+ hdr_size = 28;
+ if (ucode_raw->size < hdr_size) {
+ IWL_ERR(priv, "File size too small!\n");
+ return -EINVAL;
}
- /* fall through for 4965 */
+ pieces->build = le32_to_cpu(ucode->u.v2.build);
+ pieces->inst_size = le32_to_cpu(ucode->u.v2.inst_size);
+ pieces->data_size = le32_to_cpu(ucode->u.v2.data_size);
+ pieces->init_size = le32_to_cpu(ucode->u.v2.init_size);
+ pieces->init_data_size = le32_to_cpu(ucode->u.v2.init_data_size);
+ src = ucode->u.v2.data;
+ break;
case 0:
case 1:
case 2:
@@ -1479,7 +1073,6 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv,
pieces->data_size = le32_to_cpu(ucode->u.v1.data_size);
pieces->init_size = le32_to_cpu(ucode->u.v1.init_size);
pieces->init_data_size = le32_to_cpu(ucode->u.v1.init_data_size);
- pieces->boot_size = le32_to_cpu(ucode->u.v1.boot_size);
src = ucode->u.v1.data;
break;
}
@@ -1487,7 +1080,7 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv,
/* Verify size of file vs. image size info in file's header */
if (ucode_raw->size != hdr_size + pieces->inst_size +
pieces->data_size + pieces->init_size +
- pieces->init_data_size + pieces->boot_size) {
+ pieces->init_data_size) {
IWL_ERR(priv,
"uCode file size %d does not match expected size\n",
@@ -1503,8 +1096,6 @@ static int iwlagn_load_legacy_firmware(struct iwl_priv *priv,
src += pieces->init_size;
pieces->init_data = src;
src += pieces->init_data_size;
- pieces->boot = src;
- src += pieces->boot_size;
return 0;
}
@@ -1605,8 +1196,7 @@ static int iwlagn_load_firmware(struct iwl_priv *priv,
pieces->init_data_size = tlv_len;
break;
case IWL_UCODE_TLV_BOOT:
- pieces->boot = tlv_data;
- pieces->boot_size = tlv_len;
+ IWL_ERR(priv, "Found unexpected BOOT ucode\n");
break;
case IWL_UCODE_TLV_PROBE_MAX_LEN:
if (tlv_len != sizeof(u32))
@@ -1617,7 +1207,23 @@ static int iwlagn_load_firmware(struct iwl_priv *priv,
case IWL_UCODE_TLV_PAN:
if (tlv_len)
goto invalid_tlv_len;
- capa->pan = true;
+ capa->flags |= IWL_UCODE_TLV_FLAGS_PAN;
+ break;
+ case IWL_UCODE_TLV_FLAGS:
+ /* must be at least one u32 */
+ if (tlv_len < sizeof(u32))
+ goto invalid_tlv_len;
+ /* and a proper number of u32s */
+ if (tlv_len % sizeof(u32))
+ goto invalid_tlv_len;
+ /*
+ * This driver only reads the first u32 as
+ * right now no more features are defined,
+ * if that changes then either the driver
+ * will not work with the new firmware, or
+ * it'll not take advantage of new features.
+ */
+ capa->flags = le32_to_cpup((__le32 *)tlv_data);
break;
case IWL_UCODE_TLV_INIT_EVTLOG_PTR:
if (tlv_len != sizeof(u32))
@@ -1667,7 +1273,7 @@ static int iwlagn_load_firmware(struct iwl_priv *priv,
le32_to_cpup((__le32 *)tlv_data);
break;
default:
- IWL_WARN(priv, "unknown TLV: %d\n", tlv_type);
+ IWL_DEBUG_INFO(priv, "unknown TLV: %d\n", tlv_type);
break;
}
}
@@ -1806,8 +1412,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
pieces.init_size);
IWL_DEBUG_INFO(priv, "f/w package hdr init data size = %Zd\n",
pieces.init_data_size);
- IWL_DEBUG_INFO(priv, "f/w package hdr boot inst size = %Zd\n",
- pieces.boot_size);
/* Verify that uCode images will fit in card's SRAM */
if (pieces.inst_size > priv->hw_params.max_inst_size) {
@@ -1834,48 +1438,25 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
goto try_again;
}
- if (pieces.boot_size > priv->hw_params.max_bsm_size) {
- IWL_ERR(priv, "uCode boot instr len %Zd too large to fit in\n",
- pieces.boot_size);
- goto try_again;
- }
-
/* Allocate ucode buffers for card's bus-master loading ... */
/* Runtime instructions and 2 copies of data:
* 1) unmodified from disk
* 2) backup cache for save/restore during power-downs */
- priv->ucode_code.len = pieces.inst_size;
- iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_code);
-
- priv->ucode_data.len = pieces.data_size;
- iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data);
-
- priv->ucode_data_backup.len = pieces.data_size;
- iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_data_backup);
-
- if (!priv->ucode_code.v_addr || !priv->ucode_data.v_addr ||
- !priv->ucode_data_backup.v_addr)
+ if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_rt.code,
+ pieces.inst, pieces.inst_size))
+ goto err_pci_alloc;
+ if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_rt.data,
+ pieces.data, pieces.data_size))
goto err_pci_alloc;
/* Initialization instructions and data */
if (pieces.init_size && pieces.init_data_size) {
- priv->ucode_init.len = pieces.init_size;
- iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init);
-
- priv->ucode_init_data.len = pieces.init_data_size;
- iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init_data);
-
- if (!priv->ucode_init.v_addr || !priv->ucode_init_data.v_addr)
+ if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init.code,
+ pieces.init, pieces.init_size))
goto err_pci_alloc;
- }
-
- /* Bootstrap (instructions only, no data) */
- if (pieces.boot_size) {
- priv->ucode_boot.len = pieces.boot_size;
- iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_boot);
-
- if (!priv->ucode_boot.v_addr)
+ if (iwl_alloc_fw_desc(priv->pci_dev, &priv->ucode_init.data,
+ pieces.init_data, pieces.init_data_size))
goto err_pci_alloc;
}
@@ -1901,50 +1482,19 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
priv->cfg->base_params->max_event_log_size;
priv->_agn.inst_errlog_ptr = pieces.inst_errlog_ptr;
- if (ucode_capa.pan) {
+ priv->new_scan_threshold_behaviour =
+ !!(ucode_capa.flags & IWL_UCODE_TLV_FLAGS_NEWSCAN);
+
+ if (ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN) {
priv->valid_contexts |= BIT(IWL_RXON_CTX_PAN);
priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN;
} else
priv->sta_key_max_num = STA_KEY_MAX_NUM;
- /* Copy images into buffers for card's bus-master reads ... */
-
- /* Runtime instructions (first block of data in file) */
- IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n",
- pieces.inst_size);
- memcpy(priv->ucode_code.v_addr, pieces.inst, pieces.inst_size);
-
- IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
- priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
-
- /*
- * Runtime data
- * NOTE: Copy into backup buffer will be done in iwl_up()
- */
- IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n",
- pieces.data_size);
- memcpy(priv->ucode_data.v_addr, pieces.data, pieces.data_size);
- memcpy(priv->ucode_data_backup.v_addr, pieces.data, pieces.data_size);
-
- /* Initialization instructions */
- if (pieces.init_size) {
- IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n",
- pieces.init_size);
- memcpy(priv->ucode_init.v_addr, pieces.init, pieces.init_size);
- }
-
- /* Initialization data */
- if (pieces.init_data_size) {
- IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n",
- pieces.init_data_size);
- memcpy(priv->ucode_init_data.v_addr, pieces.init_data,
- pieces.init_data_size);
- }
-
- /* Bootstrap instructions */
- IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n",
- pieces.boot_size);
- memcpy(priv->ucode_boot.v_addr, pieces.boot, pieces.boot_size);
+ if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))
+ priv->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM;
+ else
+ priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
/*
* figure out the offset of chain noise reset and gain commands
@@ -2062,7 +1612,7 @@ static const char *desc_lookup(u32 num)
max = ARRAY_SIZE(advanced_lookup) - 1;
for (i = 0; i < max; i++) {
if (advanced_lookup[i].num == num)
- break;;
+ break;
}
return advanced_lookup[i].name;
}
@@ -2072,17 +1622,14 @@ static const char *desc_lookup(u32 num)
void iwl_dump_nic_error_log(struct iwl_priv *priv)
{
- u32 data2, line;
- u32 desc, time, count, base, data1;
- u32 blink1, blink2, ilink1, ilink2;
- u32 pc, hcmd;
+ u32 base;
+ struct iwl_error_event_table table;
- if (priv->ucode_type == UCODE_INIT) {
- base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
+ base = priv->device_pointers.error_event_table;
+ if (priv->ucode_type == UCODE_SUBTYPE_INIT) {
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;
}
@@ -2090,41 +1637,48 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
IWL_ERR(priv,
"Not valid error log pointer 0x%08X for %s uCode\n",
- base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT");
+ base,
+ (priv->ucode_type == UCODE_SUBTYPE_INIT)
+ ? "Init" : "RT");
return;
}
- count = iwl_read_targ_mem(priv, base);
+ iwl_read_targ_mem_words(priv, base, &table, sizeof(table));
- if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
+ if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
IWL_ERR(priv, "Start IWL Error Log Dump:\n");
IWL_ERR(priv, "Status: 0x%08lX, count: %d\n",
- priv->status, count);
- }
-
- desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
- priv->isr_stats.err_code = desc;
- pc = iwl_read_targ_mem(priv, base + 2 * sizeof(u32));
- blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
- blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
- ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32));
- ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32));
- data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32));
- data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32));
- line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
- time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
- hcmd = iwl_read_targ_mem(priv, base + 22 * sizeof(u32));
-
- trace_iwlwifi_dev_ucode_error(priv, desc, time, data1, data2, line,
- blink1, blink2, ilink1, ilink2);
-
- IWL_ERR(priv, "Desc Time "
- "data1 data2 line\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",
- pc, blink1, blink2, ilink1, ilink2, hcmd);
+ priv->status, table.valid);
+ }
+
+ priv->isr_stats.err_code = table.error_id;
+
+ trace_iwlwifi_dev_ucode_error(priv, table.error_id, table.tsf_low,
+ table.data1, table.data2, table.line,
+ table.blink1, table.blink2, table.ilink1,
+ table.ilink2, table.bcon_time, table.gp1,
+ table.gp2, table.gp3, table.ucode_ver,
+ table.hw_ver, table.brd_ver);
+ IWL_ERR(priv, "0x%08X | %-28s\n", table.error_id,
+ desc_lookup(table.error_id));
+ IWL_ERR(priv, "0x%08X | uPc\n", table.pc);
+ IWL_ERR(priv, "0x%08X | branchlink1\n", table.blink1);
+ IWL_ERR(priv, "0x%08X | branchlink2\n", table.blink2);
+ IWL_ERR(priv, "0x%08X | interruptlink1\n", table.ilink1);
+ IWL_ERR(priv, "0x%08X | interruptlink2\n", table.ilink2);
+ IWL_ERR(priv, "0x%08X | data1\n", table.data1);
+ IWL_ERR(priv, "0x%08X | data2\n", table.data2);
+ IWL_ERR(priv, "0x%08X | line\n", table.line);
+ IWL_ERR(priv, "0x%08X | beacon time\n", table.bcon_time);
+ IWL_ERR(priv, "0x%08X | tsf low\n", table.tsf_low);
+ IWL_ERR(priv, "0x%08X | tsf hi\n", table.tsf_hi);
+ IWL_ERR(priv, "0x%08X | time gp1\n", table.gp1);
+ IWL_ERR(priv, "0x%08X | time gp2\n", table.gp2);
+ IWL_ERR(priv, "0x%08X | time gp3\n", table.gp3);
+ IWL_ERR(priv, "0x%08X | uCode version\n", table.ucode_ver);
+ IWL_ERR(priv, "0x%08X | hw version\n", table.hw_ver);
+ IWL_ERR(priv, "0x%08X | board version\n", table.brd_ver);
+ IWL_ERR(priv, "0x%08X | hcmd\n", table.hcmd);
}
#define EVENT_START_OFFSET (4 * sizeof(u32))
@@ -2147,12 +1701,11 @@ 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) {
- base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
+ base = priv->device_pointers.log_event_table;
+ if (priv->ucode_type == UCODE_SUBTYPE_INIT) {
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;
}
@@ -2169,14 +1722,14 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
iwl_grab_nic_access(priv);
/* Set starting address; reads will auto-increment */
- _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, ptr);
+ iwl_write32(priv, HBUS_TARG_MEM_RADDR, ptr);
rmb();
/* "time" is actually "data" for mode 0 (no timestamp).
* place event id # at far right for easier visual parsing. */
for (i = 0; i < num_events; i++) {
- ev = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
- time = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+ ev = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
+ time = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
if (mode == 0) {
/* data, ev */
if (bufsz) {
@@ -2190,7 +1743,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
time, ev);
}
} else {
- data = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+ data = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
if (bufsz) {
pos += scnprintf(*buf + pos, bufsz - pos,
"EVT_LOGT:%010u:0x%08x:%04u\n",
@@ -2261,13 +1814,12 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
int pos = 0;
size_t bufsz = 0;
- if (priv->ucode_type == UCODE_INIT) {
- base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
+ base = priv->device_pointers.log_event_table;
+ if (priv->ucode_type == UCODE_SUBTYPE_INIT) {
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;
@@ -2276,7 +1828,9 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
IWL_ERR(priv,
"Invalid event log pointer 0x%08X for %s uCode\n",
- base, (priv->ucode_type == UCODE_INIT) ? "Init" : "RT");
+ base,
+ (priv->ucode_type == UCODE_SUBTYPE_INIT)
+ ? "Init" : "RT");
return -EINVAL;
}
@@ -2406,8 +1960,8 @@ static int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg)
struct iwl_calib_cfg_cmd calib_cfg_cmd;
struct iwl_host_cmd cmd = {
.id = CALIBRATION_CFG_CMD,
- .len = sizeof(struct iwl_calib_cfg_cmd),
- .data = &calib_cfg_cmd,
+ .len = { sizeof(struct iwl_calib_cfg_cmd), },
+ .data = { &calib_cfg_cmd, },
};
memset(&calib_cfg_cmd, 0, sizeof(calib_cfg_cmd));
@@ -2423,30 +1977,14 @@ static int iwlagn_send_calib_cfg_rt(struct iwl_priv *priv, u32 cfg)
* from protocol/runtime uCode (initialization uCode's
* Alive gets handled by iwl_init_alive_start()).
*/
-static void iwl_alive_start(struct iwl_priv *priv)
+int iwl_alive_start(struct iwl_priv *priv)
{
int ret = 0;
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
- IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
-
- /* Initialize uCode has loaded Runtime uCode ... verify inst image.
- * This is a paranoid check, because we would not have gotten the
- * "runtime" alive if code weren't properly loaded. */
- if (iwl_verify_ucode(priv)) {
- /* Runtime instruction load was bad;
- * take it all the way back down so we can try again */
- IWL_DEBUG_INFO(priv, "Bad runtime uCode load.\n");
- goto restart;
- }
-
- ret = priv->cfg->ops->lib->alive_notify(priv);
- if (ret) {
- IWL_WARN(priv,
- "Could not complete ALIVE transition [ntf]: %d\n", ret);
- goto restart;
- }
+ iwl_reset_ict(priv);
+ IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
/* After the ALIVE response, we can send host commands to the uCode */
set_bit(STATUS_ALIVE, &priv->status);
@@ -2455,7 +1993,7 @@ static void iwl_alive_start(struct iwl_priv *priv)
iwl_setup_watchdog(priv);
if (iwl_is_rfkill(priv))
- return;
+ return -ERFKILL;
/* download priority table before any calibration request */
if (priv->cfg->bt_params &&
@@ -2469,10 +2007,14 @@ static void iwl_alive_start(struct iwl_priv *priv)
iwlagn_send_prio_tbl(priv);
/* FIXME: w/a to force change uCode BT state machine */
- iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
- BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
- iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE,
- BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
+ ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_OPEN,
+ BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
+ if (ret)
+ return ret;
+ ret = iwlagn_send_bt_env(priv, IWL_BT_COEX_ENV_CLOSE,
+ BT_COEX_PRIO_TBL_EVT_INIT_CALIB2);
+ if (ret)
+ return ret;
}
if (priv->hw_params.calib_rt_cfg)
iwlagn_send_calib_cfg_rt(priv, priv->hw_params.calib_rt_cfg);
@@ -2514,30 +2056,23 @@ static void iwl_alive_start(struct iwl_priv *priv)
set_bit(STATUS_READY, &priv->status);
/* Configure the adapter for unassociated operation */
- iwlcore_commit_rxon(priv, ctx);
+ ret = iwlcore_commit_rxon(priv, ctx);
+ if (ret)
+ return ret;
/* At this point, the NIC is initialized and operational */
iwl_rf_kill_ct_config(priv);
IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
- wake_up_interruptible(&priv->wait_command_queue);
-
- iwl_power_update_mode(priv, true);
- IWL_DEBUG_INFO(priv, "Updated power mode\n");
-
-
- return;
- restart:
- queue_work(priv->workqueue, &priv->restart);
+ return iwl_power_update_mode(priv, true);
}
static void iwl_cancel_deferred_work(struct iwl_priv *priv);
static void __iwl_down(struct iwl_priv *priv)
{
- unsigned long flags;
- int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status);
+ int exit_pending;
IWL_DEBUG_INFO(priv, DRV_NAME " is going down\n");
@@ -2563,40 +2098,15 @@ static void __iwl_down(struct iwl_priv *priv)
priv->bt_full_concurrent = false;
priv->bt_ci_compliance = 0;
- /* Unblock any waiting calls */
- wake_up_interruptible_all(&priv->wait_command_queue);
-
/* Wipe out the EXIT_PENDING status bit if we are not actually
* exiting the module */
if (!exit_pending)
clear_bit(STATUS_EXIT_PENDING, &priv->status);
- /* stop and reset the on-board processor */
- iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
-
- /* tell the device to stop sending interrupts */
- spin_lock_irqsave(&priv->lock, flags);
- iwl_disable_interrupts(priv);
- spin_unlock_irqrestore(&priv->lock, flags);
- iwl_synchronize_irq(priv);
-
if (priv->mac80211_registered)
ieee80211_stop_queues(priv->hw);
- /* If we have not previously called iwl_init() then
- * clear all bits but the RF Kill bit and return */
- if (!iwl_is_init(priv)) {
- priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) <<
- STATUS_RF_KILL_HW |
- test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
- STATUS_GEO_CONFIGURED |
- test_bit(STATUS_EXIT_PENDING, &priv->status) <<
- STATUS_EXIT_PENDING;
- goto exit;
- }
-
- /* ...otherwise clear out all the status bits but the RF Kill
- * bit and continue taking the NIC down. */
+ /* Clear out all status bits but a few that are stable across reset */
priv->status &= test_bit(STATUS_RF_KILL_HW, &priv->status) <<
STATUS_RF_KILL_HW |
test_bit(STATUS_GEO_CONFIGURED, &priv->status) <<
@@ -2606,31 +2116,10 @@ static void __iwl_down(struct iwl_priv *priv)
test_bit(STATUS_EXIT_PENDING, &priv->status) <<
STATUS_EXIT_PENDING;
- /* device going down, Stop using ICT table */
- if (priv->cfg->ops->lib->isr_ops.disable)
- priv->cfg->ops->lib->isr_ops.disable(priv);
-
- iwlagn_txq_ctx_stop(priv);
- iwlagn_rxq_stop(priv);
-
- /* Power-down device's busmaster DMA clocks */
- iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
- udelay(5);
-
- /* Make sure (redundant) we've released our request to stay awake */
- iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-
- /* Stop the device, and put it in low power state */
- iwl_apm_stop(priv);
-
- exit:
- memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp));
+ iwlagn_stop_device(priv);
dev_kfree_skb(priv->beacon_skb);
priv->beacon_skb = NULL;
-
- /* clear out any free frames */
- iwl_clear_free_frames(priv);
}
static void iwl_down(struct iwl_priv *priv)
@@ -2644,9 +2133,10 @@ static void iwl_down(struct iwl_priv *priv)
#define HW_READY_TIMEOUT (50)
+/* Note: returns poll_bit return value, which is >= 0 if success */
static int iwl_set_hw_ready(struct iwl_priv *priv)
{
- int ret = 0;
+ int ret;
iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_BIT_NIC_READY);
@@ -2656,25 +2146,21 @@ static int iwl_set_hw_ready(struct iwl_priv *priv)
CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
HW_READY_TIMEOUT);
- if (ret != -ETIMEDOUT)
- priv->hw_ready = true;
- else
- priv->hw_ready = false;
- IWL_DEBUG_INFO(priv, "hardware %s\n",
- (priv->hw_ready == 1) ? "ready" : "not ready");
+ IWL_DEBUG_INFO(priv, "hardware%s ready\n", ret < 0 ? " not" : "");
return ret;
}
-static int iwl_prepare_card_hw(struct iwl_priv *priv)
+/* Note: returns standard 0/-ERROR code */
+int iwl_prepare_card_hw(struct iwl_priv *priv)
{
- int ret = 0;
+ int ret;
IWL_DEBUG_INFO(priv, "iwl_prepare_card_hw enter\n");
ret = iwl_set_hw_ready(priv);
- if (priv->hw_ready)
- return ret;
+ if (ret >= 0)
+ return 0;
/* If HW is not ready, prepare the conditions to check again */
iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
@@ -2684,10 +2170,13 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv)
~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE,
CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000);
- /* HW should be ready by now, check again. */
- if (ret != -ETIMEDOUT)
- iwl_set_hw_ready(priv);
+ if (ret < 0)
+ return ret;
+ /* HW should be ready by now, check again. */
+ ret = iwl_set_hw_ready(priv);
+ if (ret >= 0)
+ return 0;
return ret;
}
@@ -2696,19 +2185,15 @@ static int iwl_prepare_card_hw(struct iwl_priv *priv)
static int __iwl_up(struct iwl_priv *priv)
{
struct iwl_rxon_context *ctx;
- int i;
int ret;
+ lockdep_assert_held(&priv->mutex);
+
if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
return -EIO;
}
- if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) {
- IWL_ERR(priv, "ucode not available for device bringup\n");
- return -EIO;
- }
-
for_each_context(priv, ctx) {
ret = iwlagn_alloc_bcast_station(priv, ctx);
if (ret) {
@@ -2717,89 +2202,33 @@ static int __iwl_up(struct iwl_priv *priv)
}
}
- iwl_prepare_card_hw(priv);
-
- if (!priv->hw_ready) {
- IWL_WARN(priv, "Exit HW not ready\n");
- return -EIO;
- }
-
- /* If platform's RF_KILL switch is NOT set to KILL */
- if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
- clear_bit(STATUS_RF_KILL_HW, &priv->status);
- else
- set_bit(STATUS_RF_KILL_HW, &priv->status);
-
- if (iwl_is_rfkill(priv)) {
- wiphy_rfkill_set_hw_state(priv->hw->wiphy, true);
-
- iwl_enable_interrupts(priv);
- IWL_WARN(priv, "Radio disabled by HW RF Kill switch\n");
- return 0;
+ ret = iwlagn_run_init_ucode(priv);
+ if (ret) {
+ IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret);
+ goto error;
}
- iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
-
- /* must be initialised before iwl_hw_nic_init */
- if (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS))
- priv->cmd_queue = IWL_IPAN_CMD_QUEUE_NUM;
- else
- priv->cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM;
-
- ret = iwlagn_hw_nic_init(priv);
+ ret = iwlagn_load_ucode_wait_alive(priv,
+ &priv->ucode_rt,
+ UCODE_SUBTYPE_REGULAR,
+ UCODE_SUBTYPE_REGULAR_NEW);
if (ret) {
- IWL_ERR(priv, "Unable to init nic\n");
- return ret;
+ IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret);
+ goto error;
}
- /* make sure rfkill handshake bits are cleared */
- iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
- iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
- CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
-
- /* clear (again), then enable host interrupts */
- iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
- iwl_enable_interrupts(priv);
-
- /* really make sure rfkill handshake bits are cleared */
- iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
- iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-
- /* Copy original ucode data image from disk into backup cache.
- * This will be used to initialize the on-board processor's
- * data SRAM for a clean start when the runtime program first loads. */
- memcpy(priv->ucode_data_backup.v_addr, priv->ucode_data.v_addr,
- priv->ucode_data.len);
-
- for (i = 0; i < MAX_HW_RESTARTS; i++) {
-
- /* load bootstrap state machine,
- * load bootstrap program into processor's memory,
- * prepare to load the "initialize" uCode */
- ret = priv->cfg->ops->lib->load_ucode(priv);
-
- if (ret) {
- IWL_ERR(priv, "Unable to set up bootstrap uCode: %d\n",
- ret);
- continue;
- }
-
- /* start card; "initialize" will load runtime ucode */
- iwl_nic_start(priv);
-
- IWL_DEBUG_INFO(priv, DRV_NAME " is coming up\n");
-
- return 0;
- }
+ ret = iwl_alive_start(priv);
+ if (ret)
+ goto error;
+ return 0;
+ error:
set_bit(STATUS_EXIT_PENDING, &priv->status);
__iwl_down(priv);
clear_bit(STATUS_EXIT_PENDING, &priv->status);
- /* tried to restart and config the device for as long as our
- * patience could withstand */
- IWL_ERR(priv, "Unable to initialize device after %d attempts.\n", i);
- return -EIO;
+ IWL_ERR(priv, "Unable to initialize device.\n");
+ return ret;
}
@@ -2809,36 +2238,6 @@ static int __iwl_up(struct iwl_priv *priv)
*
*****************************************************************************/
-static void iwl_bg_init_alive_start(struct work_struct *data)
-{
- struct iwl_priv *priv =
- container_of(data, struct iwl_priv, init_alive_start.work);
-
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
-
- mutex_lock(&priv->mutex);
- priv->cfg->ops->lib->init_alive_start(priv);
- mutex_unlock(&priv->mutex);
-}
-
-static void iwl_bg_alive_start(struct work_struct *data)
-{
- struct iwl_priv *priv =
- container_of(data, struct iwl_priv, alive_start.work);
-
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
-
- /* enable dram interrupt */
- if (priv->cfg->ops->lib->isr_ops.reset)
- priv->cfg->ops->lib->isr_ops.reset(priv);
-
- mutex_lock(&priv->mutex);
- iwl_alive_start(priv);
- mutex_unlock(&priv->mutex);
-}
-
static void iwl_bg_run_time_calib_work(struct work_struct *work)
{
struct iwl_priv *priv = container_of(work, struct iwl_priv,
@@ -2853,22 +2252,49 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work)
}
if (priv->start_calib) {
- if (iwl_bt_statistics(priv)) {
- 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);
- }
+ iwl_chain_noise_calibration(priv);
+ iwl_sensitivity_calibration(priv);
}
mutex_unlock(&priv->mutex);
}
+static void iwlagn_prepare_restart(struct iwl_priv *priv)
+{
+ struct iwl_rxon_context *ctx;
+ bool bt_full_concurrent;
+ u8 bt_ci_compliance;
+ u8 bt_load;
+ u8 bt_status;
+
+ lockdep_assert_held(&priv->mutex);
+
+ for_each_context(priv, ctx)
+ ctx->vif = NULL;
+ priv->is_open = 0;
+
+ /*
+ * __iwl_down() will clear the BT status variables,
+ * which is correct, but when we restart we really
+ * want to keep them so restore them afterwards.
+ *
+ * The restart process will later pick them up and
+ * re-configure the hw when we reconfigure the BT
+ * command.
+ */
+ bt_full_concurrent = priv->bt_full_concurrent;
+ bt_ci_compliance = priv->bt_ci_compliance;
+ bt_load = priv->bt_traffic_load;
+ bt_status = priv->bt_status;
+
+ __iwl_down(priv);
+
+ priv->bt_full_concurrent = bt_full_concurrent;
+ priv->bt_ci_compliance = bt_ci_compliance;
+ priv->bt_traffic_load = bt_load;
+ priv->bt_status = bt_status;
+}
+
static void iwl_bg_restart(struct work_struct *data)
{
struct iwl_priv *priv = container_of(data, struct iwl_priv, restart);
@@ -2877,50 +2303,13 @@ static void iwl_bg_restart(struct work_struct *data)
return;
if (test_and_clear_bit(STATUS_FW_ERROR, &priv->status)) {
- struct iwl_rxon_context *ctx;
- bool bt_full_concurrent;
- u8 bt_ci_compliance;
- u8 bt_load;
- u8 bt_status;
-
mutex_lock(&priv->mutex);
- for_each_context(priv, ctx)
- ctx->vif = NULL;
- priv->is_open = 0;
-
- /*
- * __iwl_down() will clear the BT status variables,
- * which is correct, but when we restart we really
- * want to keep them so restore them afterwards.
- *
- * The restart process will later pick them up and
- * re-configure the hw when we reconfigure the BT
- * command.
- */
- bt_full_concurrent = priv->bt_full_concurrent;
- bt_ci_compliance = priv->bt_ci_compliance;
- bt_load = priv->bt_traffic_load;
- bt_status = priv->bt_status;
-
- __iwl_down(priv);
-
- priv->bt_full_concurrent = bt_full_concurrent;
- priv->bt_ci_compliance = bt_ci_compliance;
- priv->bt_traffic_load = bt_load;
- priv->bt_status = bt_status;
-
+ iwlagn_prepare_restart(priv);
mutex_unlock(&priv->mutex);
iwl_cancel_deferred_work(priv);
ieee80211_restart_hw(priv->hw);
} else {
- iwl_down(priv);
-
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
-
- mutex_lock(&priv->mutex);
- __iwl_up(priv);
- mutex_unlock(&priv->mutex);
+ WARN_ON(1);
}
}
@@ -3031,8 +2420,6 @@ unlock:
*
*****************************************************************************/
-#define UCODE_READY_TIMEOUT (4 * HZ)
-
/*
* Not a mac80211 entry point function, but it fits in with all the
* other mac80211 functions grouped here.
@@ -3055,14 +2442,16 @@ static int iwl_mac_setup_register(struct iwl_priv *priv,
hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
- if (!priv->cfg->base_params->broken_powersave)
- hw->flags |= IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
+ hw->flags |= IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
if (priv->cfg->sku & IWL_SKU_N)
hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
IEEE80211_HW_SUPPORTS_STATIC_SMPS;
+ if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP)
+ hw->flags |= IEEE80211_HW_MFP_CAPABLE;
+
hw->sta_data_size = sizeof(struct iwl_station_priv);
hw->vif_data_size = sizeof(struct iwl_vif_priv);
@@ -3112,7 +2501,7 @@ static int iwl_mac_setup_register(struct iwl_priv *priv,
}
-int iwlagn_mac_start(struct ieee80211_hw *hw)
+static int iwlagn_mac_start(struct ieee80211_hw *hw)
{
struct iwl_priv *priv = hw->priv;
int ret;
@@ -3123,37 +2512,23 @@ int iwlagn_mac_start(struct ieee80211_hw *hw)
mutex_lock(&priv->mutex);
ret = __iwl_up(priv);
mutex_unlock(&priv->mutex);
-
if (ret)
return ret;
- if (iwl_is_rfkill(priv))
- goto out;
-
IWL_DEBUG_INFO(priv, "Start UP work done.\n");
- /* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from
- * mac80211 will not be run successfully. */
- ret = wait_event_interruptible_timeout(priv->wait_command_queue,
- test_bit(STATUS_READY, &priv->status),
- UCODE_READY_TIMEOUT);
- if (!ret) {
- if (!test_bit(STATUS_READY, &priv->status)) {
- IWL_ERR(priv, "START_ALIVE timeout after %dms.\n",
- jiffies_to_msecs(UCODE_READY_TIMEOUT));
- return -ETIMEDOUT;
- }
- }
+ /* Now we should be done, and the READY bit should be set. */
+ if (WARN_ON(!test_bit(STATUS_READY, &priv->status)))
+ ret = -EIO;
iwlagn_led_enable(priv);
-out:
priv->is_open = 1;
IWL_DEBUG_MAC80211(priv, "leave\n");
return 0;
}
-void iwlagn_mac_stop(struct ieee80211_hw *hw)
+static void iwlagn_mac_stop(struct ieee80211_hw *hw)
{
struct iwl_priv *priv = hw->priv;
@@ -3176,7 +2551,7 @@ void iwlagn_mac_stop(struct ieee80211_hw *hw)
IWL_DEBUG_MAC80211(priv, "leave\n");
}
-void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct iwl_priv *priv = hw->priv;
@@ -3191,11 +2566,11 @@ void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
IWL_DEBUG_MACDUMP(priv, "leave\n");
}
-void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_key_conf *keyconf,
- struct ieee80211_sta *sta,
- u32 iv32, u16 *phase1key)
+static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_key_conf *keyconf,
+ struct ieee80211_sta *sta,
+ u32 iv32, u16 *phase1key)
{
struct iwl_priv *priv = hw->priv;
struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
@@ -3208,9 +2583,10 @@ void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
IWL_DEBUG_MAC80211(priv, "leave\n");
}
-int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
- struct ieee80211_vif *vif, struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key)
+static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
{
struct iwl_priv *priv = hw->priv;
struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
@@ -3221,7 +2597,7 @@ int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
IWL_DEBUG_MAC80211(priv, "enter\n");
- if (priv->cfg->mod_params->sw_crypto) {
+ if (iwlagn_mod_params.sw_crypto) {
IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n");
return -EOPNOTSUPP;
}
@@ -3285,11 +2661,11 @@ int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
return ret;
}
-int iwlagn_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,
- u8 buf_size)
+static int iwlagn_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,
+ u8 buf_size)
{
struct iwl_priv *priv = hw->priv;
int ret = -EINVAL;
@@ -3348,6 +2724,10 @@ int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
}
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
+ buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF);
+
+ iwlagn_txq_agg_queue_setup(priv, sta, tid, buf_size);
+
/*
* If the limit is 0, then it wasn't initialised yet,
* use the default. We can do that since we take the
@@ -3392,9 +2772,9 @@ int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
return ret;
}
-int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
{
struct iwl_priv *priv = hw->priv;
struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
@@ -3435,8 +2815,8 @@ int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
return 0;
}
-void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
- struct ieee80211_channel_switch *ch_switch)
+static void iwlagn_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;
@@ -3457,21 +2837,22 @@ void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
IWL_DEBUG_MAC80211(priv, "enter\n");
+ mutex_lock(&priv->mutex);
+
if (iwl_is_rfkill(priv))
- goto out_exit;
+ goto out;
if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
test_bit(STATUS_SCANNING, &priv->status))
- goto out_exit;
+ goto out;
if (!iwl_is_associated_ctx(ctx))
- goto out_exit;
+ goto out;
/* channel switch in progress */
if (priv->switch_rxon.switch_in_progress == true)
- goto out_exit;
+ goto out;
- mutex_lock(&priv->mutex);
if (priv->cfg->ops->lib->set_channel_switch) {
ch = channel->hw_value;
@@ -3527,16 +2908,15 @@ void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
}
out:
mutex_unlock(&priv->mutex);
-out_exit:
if (!priv->switch_rxon.switch_in_progress)
ieee80211_chswitch_done(ctx->vif, false);
IWL_DEBUG_MAC80211(priv, "leave\n");
}
-void iwlagn_configure_filter(struct ieee80211_hw *hw,
- unsigned int changed_flags,
- unsigned int *total_flags,
- u64 multicast)
+static void iwlagn_configure_filter(struct ieee80211_hw *hw,
+ unsigned int changed_flags,
+ unsigned int *total_flags,
+ u64 multicast)
{
struct iwl_priv *priv = hw->priv;
__le32 filter_or = 0, filter_nand = 0;
@@ -3583,7 +2963,7 @@ void iwlagn_configure_filter(struct ieee80211_hw *hw,
FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
}
-void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
+static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
{
struct iwl_priv *priv = hw->priv;
@@ -3729,8 +3109,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush);
INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency);
INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config);
- INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start);
- INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start);
INIT_DELAYED_WORK(&priv->_agn.hw_roc_work, iwlagn_bg_roc_done);
iwl_setup_scan_deferred_work(priv);
@@ -3750,12 +3128,8 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
priv->watchdog.data = (unsigned long)priv;
priv->watchdog.function = iwl_bg_watchdog;
- if (!priv->cfg->base_params->use_isr_legacy)
- tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
- iwl_irq_tasklet, (unsigned long)priv);
- else
- tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
- iwl_irq_tasklet_legacy, (unsigned long)priv);
+ tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long))
+ iwl_irq_tasklet, (unsigned long)priv);
}
static void iwl_cancel_deferred_work(struct iwl_priv *priv)
@@ -3763,8 +3137,6 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv)
if (priv->cfg->ops->lib->cancel_deferred_work)
priv->cfg->ops->lib->cancel_deferred_work(priv);
- cancel_delayed_work_sync(&priv->init_alive_start);
- cancel_delayed_work(&priv->alive_start);
cancel_work_sync(&priv->run_time_calib_work);
cancel_work_sync(&priv->beacon_update);
@@ -3805,10 +3177,7 @@ static int iwl_init_drv(struct iwl_priv *priv)
spin_lock_init(&priv->sta_lock);
spin_lock_init(&priv->hcmd_lock);
- INIT_LIST_HEAD(&priv->free_frames);
-
mutex_init(&priv->mutex);
- mutex_init(&priv->sync_cmd_mutex);
priv->ieee_channels = NULL;
priv->ieee_rates = NULL;
@@ -3845,12 +3214,6 @@ static int iwl_init_drv(struct iwl_priv *priv)
priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF;
}
- /* Set the tx_power_user_lmt to the lowest power level
- * this value will get overwritten by channel max power avg
- * from eeprom */
- priv->tx_power_user_lmt = IWLAGN_TX_POWER_TARGET_POWER_MIN;
- priv->tx_power_next = IWLAGN_TX_POWER_TARGET_POWER_MIN;
-
ret = iwl_init_channel_map(priv);
if (ret) {
IWL_ERR(priv, "initializing regulatory failed: %d\n", ret);
@@ -3878,6 +3241,7 @@ static void iwl_uninit_drv(struct iwl_priv *priv)
iwlcore_free_geos(priv);
iwl_free_channel_map(priv);
kfree(priv->scan_cmd);
+ kfree(priv->beacon_cmd);
}
struct ieee80211_ops iwlagn_hw_ops = {
@@ -3905,28 +3269,30 @@ struct ieee80211_ops iwlagn_hw_ops = {
.cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel,
.offchannel_tx = iwl_mac_offchannel_tx,
.offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait,
+ CFG80211_TESTMODE_CMD(iwl_testmode_cmd)
};
-static void iwl_hw_detect(struct iwl_priv *priv)
+static u32 iwl_hw_detect(struct iwl_priv *priv)
{
- priv->hw_rev = _iwl_read32(priv, CSR_HW_REV);
- priv->hw_wa_rev = _iwl_read32(priv, CSR_HW_REV_WA_REG);
- priv->rev_id = priv->pci_dev->revision;
- IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", priv->rev_id);
+ u8 rev_id;
+
+ pci_read_config_byte(priv->pci_dev, PCI_REVISION_ID, &rev_id);
+ IWL_DEBUG_INFO(priv, "HW Revision ID = 0x%X\n", rev_id);
+ return iwl_read32(priv, CSR_HW_REV);
}
static int iwl_set_hw_params(struct iwl_priv *priv)
{
priv->hw_params.max_rxq_size = RX_QUEUE_SIZE;
priv->hw_params.max_rxq_log = RX_QUEUE_SIZE_LOG;
- if (priv->cfg->mod_params->amsdu_size_8K)
+ if (iwlagn_mod_params.amsdu_size_8K)
priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_8K);
else
priv->hw_params.rx_page_order = get_order(IWL_RX_BUF_SIZE_4K);
priv->hw_params.max_beacon_itrvl = IWL_MAX_UCODE_BEACON_INTERVAL;
- if (priv->cfg->mod_params->disable_11n)
+ if (iwlagn_mod_params.disable_11n)
priv->cfg->sku &= ~IWL_SKU_N;
/* Device-specific setup */
@@ -3955,6 +3321,28 @@ static const u8 iwlagn_pan_ac_to_queue[] = {
7, 6, 5, 4,
};
+/* This function both allocates and initializes hw and priv. */
+static struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg)
+{
+ struct iwl_priv *priv;
+ /* mac80211 allocates memory for this device instance, including
+ * space for this driver's private structure */
+ struct ieee80211_hw *hw;
+
+ hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwlagn_hw_ops);
+ if (hw == NULL) {
+ pr_err("%s: Can not allocate network device\n",
+ cfg->name);
+ goto out;
+ }
+
+ priv = hw->priv;
+ priv->hw = hw;
+
+out:
+ return hw;
+}
+
static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
int err = 0, i;
@@ -3963,19 +3351,12 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
unsigned long flags;
u16 pci_cmd, num_mac;
+ u32 hw_rev;
/************************
* 1. Allocating HW data
************************/
- /* Disabling hardware scan means that mac80211 will perform scans
- * "the hard way", rather than using device's scan. */
- if (cfg->mod_params->disable_hw_scan) {
- dev_printk(KERN_DEBUG, &(pdev->dev),
- "sw scan support is deprecated\n");
- iwlagn_hw_ops.hw_scan = NULL;
- }
-
hw = iwl_alloc_all(cfg);
if (!hw) {
err = -ENOMEM;
@@ -3984,6 +3365,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
priv = hw->priv;
/* At this point both hw and priv are allocated. */
+ priv->ucode_type = UCODE_SUBTYPE_NONE_LOADED;
+
/*
* The default context is always valid,
* more may be discovered when firmware
@@ -4116,16 +3499,15 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
*/
iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
- iwl_hw_detect(priv);
+ hw_rev = iwl_hw_detect(priv);
IWL_INFO(priv, "Detected %s, REV=0x%X\n",
- priv->cfg->name, priv->hw_rev);
+ priv->cfg->name, hw_rev);
/* We disable the RETRY_TIMEOUT register (0x41) to keep
* PCI Tx retries from interfering with C3 CPU state */
pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
- iwl_prepare_card_hw(priv);
- if (!priv->hw_ready) {
+ if (iwl_prepare_card_hw(priv)) {
IWL_WARN(priv, "Failed, HW not ready\n");
goto out_iounmap;
}
@@ -4134,7 +3516,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
* 4. Read EEPROM
*****************/
/* Read the EEPROM */
- err = iwl_eeprom_init(priv);
+ err = iwl_eeprom_init(priv, hw_rev);
if (err) {
IWL_ERR(priv, "Unable to init EEPROM\n");
goto out_iounmap;
@@ -4186,10 +3568,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_enable_msi(priv->pci_dev);
- if (priv->cfg->ops->lib->isr_ops.alloc)
- priv->cfg->ops->lib->isr_ops.alloc(priv);
+ iwl_alloc_isr_ict(priv);
- err = request_irq(priv->pci_dev->irq, priv->cfg->ops->lib->isr_ops.isr,
+ err = request_irq(priv->pci_dev->irq, iwl_isr_ict,
IRQF_SHARED, DRV_NAME, priv);
if (err) {
IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq);
@@ -4198,6 +3579,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
iwl_setup_deferred_work(priv);
iwl_setup_rx_handlers(priv);
+ iwl_testmode_init(priv);
/*********************************************
* 8. Enable interrupts and read RFKILL state
@@ -4236,8 +3618,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
destroy_workqueue(priv->workqueue);
priv->workqueue = NULL;
free_irq(priv->pci_dev->irq, priv);
- if (priv->cfg->ops->lib->isr_ops.free)
- priv->cfg->ops->lib->isr_ops.free(priv);
+ iwl_free_isr_ict(priv);
out_disable_msi:
pci_disable_msi(priv->pci_dev);
iwl_uninit_drv(priv);
@@ -4278,22 +3659,15 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
*/
set_bit(STATUS_EXIT_PENDING, &priv->status);
+ iwl_testmode_cleanup(priv);
iwl_leds_exit(priv);
if (priv->mac80211_registered) {
ieee80211_unregister_hw(priv->hw);
priv->mac80211_registered = 0;
- } else {
- iwl_down(priv);
}
- /*
- * Make sure device is reset to low power before unloading driver.
- * This may be redundant with iwl_down(), but there are paths to
- * run iwl_down() without calling apm_ops.stop(), and there are
- * paths to avoid running iwl_down() at all before leaving driver.
- * This (inexpensive) call *makes sure* device is reset.
- */
+ /* Reset to low power before unloading driver. */
iwl_apm_stop(priv);
iwl_tt_exit(priv);
@@ -4335,8 +3709,7 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
iwl_uninit_drv(priv);
- if (priv->cfg->ops->lib->isr_ops.free)
- priv->cfg->ops->lib->isr_ops.free(priv);
+ iwl_free_isr_ict(priv);
dev_kfree_skb(priv->beacon_skb);
@@ -4521,21 +3894,21 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
{IWL_PCI_DEVICE(0x088F, 0x4266, iwl6035_2bg_cfg)},
{IWL_PCI_DEVICE(0x088E, 0x4466, iwl6035_2bg_cfg)},
-/* 200 Series */
- {IWL_PCI_DEVICE(0x0894, 0x0022, iwl200_bgn_cfg)},
- {IWL_PCI_DEVICE(0x0895, 0x0222, iwl200_bgn_cfg)},
- {IWL_PCI_DEVICE(0x0894, 0x0422, iwl200_bgn_cfg)},
- {IWL_PCI_DEVICE(0x0894, 0x0026, iwl200_bg_cfg)},
- {IWL_PCI_DEVICE(0x0895, 0x0226, iwl200_bg_cfg)},
- {IWL_PCI_DEVICE(0x0894, 0x0426, iwl200_bg_cfg)},
-
-/* 230 Series */
- {IWL_PCI_DEVICE(0x0892, 0x0062, iwl230_bgn_cfg)},
- {IWL_PCI_DEVICE(0x0893, 0x0262, iwl230_bgn_cfg)},
- {IWL_PCI_DEVICE(0x0892, 0x0462, iwl230_bgn_cfg)},
- {IWL_PCI_DEVICE(0x0892, 0x0066, iwl230_bg_cfg)},
- {IWL_PCI_DEVICE(0x0893, 0x0266, iwl230_bg_cfg)},
- {IWL_PCI_DEVICE(0x0892, 0x0466, iwl230_bg_cfg)},
+/* 105 Series */
+ {IWL_PCI_DEVICE(0x0894, 0x0022, iwl105_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0895, 0x0222, iwl105_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0894, 0x0422, iwl105_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0894, 0x0026, iwl105_bg_cfg)},
+ {IWL_PCI_DEVICE(0x0895, 0x0226, iwl105_bg_cfg)},
+ {IWL_PCI_DEVICE(0x0894, 0x0426, iwl105_bg_cfg)},
+
+/* 135 Series */
+ {IWL_PCI_DEVICE(0x0892, 0x0062, iwl135_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0893, 0x0262, iwl135_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0892, 0x0462, iwl135_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0892, 0x0066, iwl135_bg_cfg)},
+ {IWL_PCI_DEVICE(0x0893, 0x0266, iwl135_bg_cfg)},
+ {IWL_PCI_DEVICE(0x0892, 0x0466, iwl135_bg_cfg)},
{0}
};
@@ -4585,43 +3958,21 @@ module_exit(iwl_exit);
module_init(iwl_init);
#ifdef CONFIG_IWLWIFI_DEBUG
-module_param_named(debug50, iwl_debug_level, uint, S_IRUGO);
-MODULE_PARM_DESC(debug50, "50XX debug output mask (deprecated)");
module_param_named(debug, iwl_debug_level, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "debug output mask");
#endif
-module_param_named(swcrypto50, iwlagn_mod_params.sw_crypto, bool, S_IRUGO);
-MODULE_PARM_DESC(swcrypto50,
- "using crypto in software (default 0 [hardware]) (deprecated)");
module_param_named(swcrypto, iwlagn_mod_params.sw_crypto, int, S_IRUGO);
MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])");
-module_param_named(queues_num50,
- iwlagn_mod_params.num_of_queues, int, S_IRUGO);
-MODULE_PARM_DESC(queues_num50,
- "number of hw queues in 50xx series (deprecated)");
module_param_named(queues_num, iwlagn_mod_params.num_of_queues, int, S_IRUGO);
MODULE_PARM_DESC(queues_num, "number of hw queues.");
-module_param_named(11n_disable50, iwlagn_mod_params.disable_11n, int, S_IRUGO);
-MODULE_PARM_DESC(11n_disable50, "disable 50XX 11n functionality (deprecated)");
module_param_named(11n_disable, iwlagn_mod_params.disable_11n, int, S_IRUGO);
MODULE_PARM_DESC(11n_disable, "disable 11n functionality");
-module_param_named(amsdu_size_8K50, iwlagn_mod_params.amsdu_size_8K,
- int, S_IRUGO);
-MODULE_PARM_DESC(amsdu_size_8K50,
- "enable 8K amsdu size in 50XX series (deprecated)");
module_param_named(amsdu_size_8K, iwlagn_mod_params.amsdu_size_8K,
int, S_IRUGO);
MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size");
-module_param_named(fw_restart50, iwlagn_mod_params.restart_fw, int, S_IRUGO);
-MODULE_PARM_DESC(fw_restart50,
- "restart firmware in case of error (deprecated)");
module_param_named(fw_restart, iwlagn_mod_params.restart_fw, int, S_IRUGO);
MODULE_PARM_DESC(fw_restart, "restart firmware in case of error");
-module_param_named(
- disable_hw_scan, iwlagn_mod_params.disable_hw_scan, int, S_IRUGO);
-MODULE_PARM_DESC(disable_hw_scan,
- "disable hardware scanning (default 0) (deprecated)");
module_param_named(ucode_alternative, iwlagn_wanted_ucode_alternative, int,
S_IRUGO);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index 20f8e4188994..2495fe7a58cb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 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
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -66,7 +66,6 @@
#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;
@@ -103,10 +102,10 @@ extern struct iwl_cfg iwl2030_2bg_cfg;
extern struct iwl_cfg iwl6035_2agn_cfg;
extern struct iwl_cfg iwl6035_2abg_cfg;
extern struct iwl_cfg iwl6035_2bg_cfg;
-extern struct iwl_cfg iwl200_bg_cfg;
-extern struct iwl_cfg iwl200_bgn_cfg;
-extern struct iwl_cfg iwl230_bg_cfg;
-extern struct iwl_cfg iwl230_bgn_cfg;
+extern struct iwl_cfg iwl105_bg_cfg;
+extern struct iwl_cfg iwl105_bgn_cfg;
+extern struct iwl_cfg iwl135_bg_cfg;
+extern struct iwl_cfg iwl135_bgn_cfg;
extern struct iwl_mod_params iwlagn_mod_params;
extern struct iwl_hcmd_ops iwlagn_hcmd;
@@ -114,7 +113,6 @@ extern struct iwl_hcmd_ops iwlagn_bt_hcmd;
extern struct iwl_hcmd_utils_ops iwlagn_hcmd_utils;
extern struct ieee80211_ops iwlagn_hw_ops;
-extern struct ieee80211_ops iwl4965_hw_ops;
int iwl_reset_ict(struct iwl_priv *priv);
void iwl_disable_ict(struct iwl_priv *priv);
@@ -122,21 +120,25 @@ int iwl_alloc_isr_ict(struct iwl_priv *priv);
void iwl_free_isr_ict(struct iwl_priv *priv);
irqreturn_t iwl_isr_ict(int irq, void *data);
+/* call this function to flush any scheduled tasklet */
+static inline void iwl_synchronize_irq(struct iwl_priv *priv)
+{
+ /* wait to make sure we flush pending tasklet*/
+ synchronize_irq(priv->pci_dev->irq);
+ tasklet_kill(&priv->irq_tasklet);
+}
+
+int iwl_prepare_card_hw(struct iwl_priv *priv);
+
+int iwlagn_start_device(struct iwl_priv *priv);
+void iwlagn_stop_device(struct iwl_priv *priv);
+
/* tx queue */
void iwlagn_set_wr_ptrs(struct iwl_priv *priv,
int txq_id, u32 index);
void iwlagn_tx_queue_set_status(struct iwl_priv *priv,
struct iwl_tx_queue *txq,
int tx_fifo_id, int scd_retry);
-void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
- struct iwl_tx_queue *txq,
- u16 byte_cnt);
-void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
- struct iwl_tx_queue *txq);
-int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
- int tx_fifo, int sta_id, int tid, u16 ssn_idx);
-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);
@@ -151,16 +153,14 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
u32 changes);
/* uCode */
-int iwlagn_load_ucode(struct iwl_priv *priv);
void iwlagn_rx_calib_result(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
-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);
-void iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
+int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
void iwlagn_send_prio_tbl(struct iwl_priv *priv);
+int iwlagn_run_init_ucode(struct iwl_priv *priv);
+int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
+ struct fw_img *image,
+ int subtype, int alternate_subtype);
/* lib */
void iwl_check_abort_status(struct iwl_priv *priv,
@@ -179,8 +179,6 @@ 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);
-void iwl_dump_csr(struct iwl_priv *priv);
-int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display);
/* rx */
void iwlagn_rx_queue_restock(struct iwl_priv *priv);
@@ -193,12 +191,10 @@ int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
void iwl_setup_rx_handlers(struct iwl_priv *priv);
/* tx */
-void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
-int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,
+void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
+int iwlagn_txq_attach_buf_to_tfd(struct iwl_priv *priv,
struct iwl_tx_queue *txq,
- 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);
+ dma_addr_t addr, u16 len, u8 reset);
void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags,
struct ieee80211_tx_info *info);
int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb);
@@ -206,6 +202,9 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid, u16 *ssn);
int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u16 tid);
+void iwlagn_txq_agg_queue_setup(struct iwl_priv *priv,
+ struct ieee80211_sta *sta,
+ int tid, int frame_limit);
int iwlagn_txq_check_empty(struct iwl_priv *priv,
int sta_id, u8 tid, int txq_id);
void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
@@ -225,6 +224,7 @@ static inline u32 iwl_tx_status_to_mac80211(u32 status)
case TX_STATUS_DIRECT_DONE:
return IEEE80211_TX_STAT_ACK;
case TX_STATUS_FAIL_DEST_PS:
+ case TX_STATUS_FAIL_PASSIVE_NO_RX:
return IEEE80211_TX_STAT_TX_FILTERED;
default:
return 0;
@@ -249,8 +249,6 @@ 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,
- struct iwl_rxon_context *ctx);
int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant);
int iwlagn_send_beacon_cmd(struct iwl_priv *priv);
@@ -311,7 +309,7 @@ static inline u32 iwl_ant_idx_to_flags(u8 ant_idx)
static inline u8 iwl_hw_get_rate(__le32 rate_n_flags)
{
- return le32_to_cpu(rate_n_flags) & 0xFF;
+ return le32_to_cpu(rate_n_flags) & RATE_MCS_RATE_MSK;
}
static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags)
@@ -322,50 +320,44 @@ static inline __le32 iwl_hw_set_rate_n_flags(u8 rate, u32 flags)
/* eeprom */
void iwlcore_eeprom_enhanced_txpower(struct iwl_priv *priv);
void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac);
-int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv);
-void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv);
/* notification wait support */
void __acquires(wait_entry)
iwlagn_init_notification_wait(struct iwl_priv *priv,
struct iwl_notification_wait *wait_entry,
+ u8 cmd,
void (*fn)(struct iwl_priv *priv,
- struct iwl_rx_packet *pkt),
- u8 cmd);
-signed long __releases(wait_entry)
+ struct iwl_rx_packet *pkt,
+ void *data),
+ void *fn_data);
+int __must_check __releases(wait_entry)
iwlagn_wait_notification(struct iwl_priv *priv,
struct iwl_notification_wait *wait_entry,
unsigned long timeout);
void __releases(wait_entry)
iwlagn_remove_notification(struct iwl_priv *priv,
struct iwl_notification_wait *wait_entry);
-
-/* mac80211 handlers (for 4965) */
-void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
-int iwlagn_mac_start(struct ieee80211_hw *hw);
-void iwlagn_mac_stop(struct ieee80211_hw *hw);
-void iwlagn_configure_filter(struct ieee80211_hw *hw,
- unsigned int changed_flags,
- unsigned int *total_flags,
- u64 multicast);
-int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
- struct ieee80211_vif *vif, struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key);
-void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_key_conf *keyconf,
- struct ieee80211_sta *sta,
- u32 iv32, u16 *phase1key);
-int iwlagn_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,
- u8 buf_size);
-int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta);
-void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
- struct ieee80211_channel_switch *ch_switch);
-void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop);
+extern int iwlagn_init_alive_start(struct iwl_priv *priv);
+extern int iwl_alive_start(struct iwl_priv *priv);
+/* svtool */
+#ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL
+extern int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len);
+extern void iwl_testmode_init(struct iwl_priv *priv);
+extern void iwl_testmode_cleanup(struct iwl_priv *priv);
+#else
+static inline
+int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
+{
+ return -ENOSYS;
+}
+static inline
+void iwl_testmode_init(struct iwl_priv *priv)
+{
+}
+static inline
+void iwl_testmode_cleanup(struct iwl_priv *priv)
+{
+}
+#endif
#endif /* __iwl_agn_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index ca42ffa63ed7..6ee5f1aa555c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 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
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -103,9 +103,7 @@ enum {
REPLY_WEPKEY = 0x20,
/* RX, TX, LEDs */
- REPLY_3945_RX = 0x1b, /* 3945 only */
REPLY_TX = 0x1c,
- REPLY_RATE_SCALE = 0x47, /* 3945 only */
REPLY_LEDS_CMD = 0x48,
REPLY_TX_LINK_QUALITY_CMD = 0x4e, /* for 4965 and up */
@@ -207,7 +205,6 @@ enum {
#define QUEUE_TO_SEQ(q) (((q) & 0x1f) << 8)
#define SEQ_TO_INDEX(s) ((s) & 0xff)
#define INDEX_TO_SEQ(i) ((i) & 0xff)
-#define SEQ_HUGE_FRAME cpu_to_le16(0x4000)
#define SEQ_RX_FRAME cpu_to_le16(0x8000)
/**
@@ -229,16 +226,14 @@ struct iwl_cmd_header {
* There is one exception: uCode sets bit 15 when it originates
* the response/notification, i.e. when the response/notification
* is not a direct response to a command sent by the driver. For
- * example, uCode issues REPLY_3945_RX when it sends a received frame
+ * example, uCode issues REPLY_RX when it sends a received frame
* to the driver; it is not a direct response to any driver command.
*
* The Linux driver uses the following format:
*
* 0:7 tfd index - position within TX queue
* 8:12 TX queue id
- * 13 reserved
- * 14 huge - driver sets this to indicate command is in the
- * 'huge' storage at the end of the command buffers
+ * 13:14 reserved
* 15 unsolicited RX or uCode-originated notification
*/
__le16 sequence;
@@ -249,36 +244,6 @@ struct iwl_cmd_header {
/**
- * struct iwl3945_tx_power
- *
- * Used in REPLY_TX_PWR_TABLE_CMD, REPLY_SCAN_CMD, REPLY_CHANNEL_SWITCH
- *
- * Each entry contains two values:
- * 1) DSP gain (or sometimes called DSP attenuation). This is a fine-grained
- * linear value that multiplies the output of the digital signal processor,
- * before being sent to the analog radio.
- * 2) Radio gain. This sets the analog gain of the radio Tx path.
- * It is a coarser setting, and behaves in a logarithmic (dB) fashion.
- *
- * Driver obtains values from struct iwl3945_tx_power power_gain_table[][].
- */
-struct iwl3945_tx_power {
- u8 tx_gain; /* gain for analog radio */
- u8 dsp_atten; /* gain for DSP */
-} __packed;
-
-/**
- * struct iwl3945_power_per_rate
- *
- * Used in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
- */
-struct iwl3945_power_per_rate {
- u8 rate; /* plcp */
- struct iwl3945_tx_power tpc;
- u8 reserved;
-} __packed;
-
-/**
* iwlagn rate_n_flags bit fields
*
* rate_n_flags format is used in following iwlagn commands:
@@ -324,6 +289,8 @@ struct iwl3945_power_per_rate {
#define RATE_MCS_SPATIAL_MSK 0x18
#define RATE_MCS_HT_DUP_POS 5
#define RATE_MCS_HT_DUP_MSK 0x20
+/* Both legacy and HT use bits 7:0 as the CCK/OFDM rate or HT MCS */
+#define RATE_MCS_RATE_MSK 0xff
/* Bit 8: (1) HT format, (0) legacy format in bits 7:0 */
#define RATE_MCS_FLAGS_POS 8
@@ -375,30 +342,6 @@ struct iwl3945_power_per_rate {
#define IWL_PWR_CCK_ENTRIES 2
/**
- * union iwl4965_tx_power_dual_stream
- *
- * Host format used for REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
- * Use __le32 version (struct tx_power_dual_stream) when building command.
- *
- * Driver provides radio gain and DSP attenuation settings to device in pairs,
- * one value for each transmitter chain. The first value is for transmitter A,
- * second for transmitter B.
- *
- * For SISO bit rates, both values in a pair should be identical.
- * For MIMO rates, one value may be different from the other,
- * in order to balance the Tx output between the two transmitters.
- *
- * See more details in doc for TXPOWER in iwl-4965-hw.h.
- */
-union iwl4965_tx_power_dual_stream {
- struct {
- u8 radio_tx_gain[2];
- u8 dsp_predis_atten[2];
- } s;
- u32 dw;
-};
-
-/**
* struct tx_power_dual_stream
*
* Table entries in REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
@@ -410,15 +353,6 @@ struct tx_power_dual_stream {
} __packed;
/**
- * struct iwl4965_tx_power_db
- *
- * Entire table within REPLY_TX_PWR_TABLE_CMD, REPLY_CHANNEL_SWITCH
- */
-struct iwl4965_tx_power_db {
- struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES];
-} __packed;
-
-/**
* Command REPLY_TX_POWER_DBM_CMD = 0x98
* struct iwlagn_tx_power_dbm_cmd
*/
@@ -449,55 +383,18 @@ struct iwl_tx_ant_config_cmd {
*****************************************************************************/
#define UCODE_VALID_OK cpu_to_le32(0x1)
-#define INITIALIZE_SUBTYPE (9)
-/*
- * ("Initialize") REPLY_ALIVE = 0x1 (response only, not a command)
- *
- * uCode issues this "initialize alive" notification once the initialization
- * uCode image has completed its work, and is ready to load the runtime image.
- * This is the *first* "alive" notification that the driver will receive after
- * rebooting uCode; the "initialize" alive is indicated by subtype field == 9.
- *
- * See comments documenting "BSM" (bootstrap state machine).
- *
- * For 4965, this notification contains important calibration data for
- * calculating txpower settings:
- *
- * 1) Power supply voltage indication. The voltage sensor outputs higher
- * values for lower voltage, and vice verse.
- *
- * 2) Temperature measurement parameters, for each of two channel widths
- * (20 MHz and 40 MHz) supported by the radios. Temperature sensing
- * is done via one of the receiver chains, and channel width influences
- * the results.
- *
- * 3) Tx gain compensation to balance 4965's 2 Tx chains for MIMO operation,
- * for each of 5 frequency ranges.
- */
-struct iwl_init_alive_resp {
- u8 ucode_minor;
- u8 ucode_major;
- __le16 reserved1;
- u8 sw_rev[8];
- u8 ver_type;
- u8 ver_subtype; /* "9" for initialize alive */
- __le16 reserved2;
- __le32 log_event_table_ptr;
- __le32 error_event_table_ptr;
- __le32 timestamp;
- __le32 is_valid;
-
- /* calibration values from "initialize" uCode */
- __le32 voltage; /* signed, higher value is lower voltage */
- __le32 therm_r1[2]; /* signed, 1st for normal, 2nd for HT40 */
- __le32 therm_r2[2]; /* signed */
- __le32 therm_r3[2]; /* signed */
- __le32 therm_r4[2]; /* signed */
- __le32 tx_atten[5][2]; /* signed MIMO gain comp, 5 freq groups,
- * 2 Tx chains */
-} __packed;
+enum iwlagn_ucode_subtype {
+ UCODE_SUBTYPE_REGULAR = 0,
+ UCODE_SUBTYPE_REGULAR_NEW = 1,
+ UCODE_SUBTYPE_INIT = 9,
+ /*
+ * Not a valid subtype, the ucode has just a u8, so
+ * we can use something > 0xff for this value.
+ */
+ UCODE_SUBTYPE_NONE_LOADED = 0x100,
+};
/**
* REPLY_ALIVE = 0x1 (response only, not a command)
@@ -533,49 +430,61 @@ struct iwl_init_alive_resp {
*
* 2) error_event_table_ptr indicates base of the error log. This contains
* information about any uCode error that occurs. For agn, the format
- * of the error log is:
- *
- * __le32 valid; (nonzero) valid, (0) log is empty
- * __le32 error_id; type of error
- * __le32 pc; program counter
- * __le32 blink1; branch link
- * __le32 blink2; branch link
- * __le32 ilink1; interrupt link
- * __le32 ilink2; interrupt link
- * __le32 data1; error-specific data
- * __le32 data2; error-specific data
- * __le32 line; source code line of error
- * __le32 bcon_time; beacon timer
- * __le32 tsf_low; network timestamp function timer
- * __le32 tsf_hi; network timestamp function timer
- * __le32 gp1; GP1 timer register
- * __le32 gp2; GP2 timer register
- * __le32 gp3; GP3 timer register
- * __le32 ucode_ver; uCode version
- * __le32 hw_ver; HW Silicon version
- * __le32 brd_ver; HW board version
- * __le32 log_pc; log program counter
- * __le32 frame_ptr; frame pointer
- * __le32 stack_ptr; stack pointer
- * __le32 hcmd; last host command
- * __le32 isr0; isr status register LMPM_NIC_ISR0: rxtx_flag
- * __le32 isr1; isr status register LMPM_NIC_ISR1: host_flag
- * __le32 isr2; isr status register LMPM_NIC_ISR2: enc_flag
- * __le32 isr3; isr status register LMPM_NIC_ISR3: time_flag
- * __le32 isr4; isr status register LMPM_NIC_ISR4: wico interrupt
- * __le32 isr_pref; isr status register LMPM_NIC_PREF_STAT
- * __le32 wait_event; wait event() caller address
- * __le32 l2p_control; L2pControlField
- * __le32 l2p_duration; L2pDurationField
- * __le32 l2p_mhvalid; L2pMhValidBits
- * __le32 l2p_addr_match; L2pAddrMatchStat
- * __le32 lmpm_pmg_sel; indicate which clocks are turned on (LMPM_PMG_SEL)
- * __le32 u_timestamp; indicate when the date and time of the compilation
- * __le32 reserved;
+ * of the error log is defined by struct iwl_error_event_table.
*
* The Linux driver can print both logs to the system log when a uCode error
* occurs.
*/
+
+/*
+ * Note: This structure is read from the device with IO accesses,
+ * and the reading already does the endian conversion. As it is
+ * read with u32-sized accesses, any members with a different size
+ * need to be ordered correctly though!
+ */
+struct iwl_error_event_table {
+ u32 valid; /* (nonzero) valid, (0) log is empty */
+ u32 error_id; /* type of error */
+ u32 pc; /* program counter */
+ u32 blink1; /* branch link */
+ u32 blink2; /* branch link */
+ u32 ilink1; /* interrupt link */
+ u32 ilink2; /* interrupt link */
+ u32 data1; /* error-specific data */
+ u32 data2; /* error-specific data */
+ u32 line; /* source code line of error */
+ u32 bcon_time; /* beacon timer */
+ u32 tsf_low; /* network timestamp function timer */
+ u32 tsf_hi; /* network timestamp function timer */
+ u32 gp1; /* GP1 timer register */
+ u32 gp2; /* GP2 timer register */
+ u32 gp3; /* GP3 timer register */
+ u32 ucode_ver; /* uCode version */
+ u32 hw_ver; /* HW Silicon version */
+ u32 brd_ver; /* HW board version */
+ u32 log_pc; /* log program counter */
+ u32 frame_ptr; /* frame pointer */
+ u32 stack_ptr; /* stack pointer */
+ u32 hcmd; /* last host command header */
+#if 0
+ /* no need to read the remainder, we don't use the values */
+ u32 isr0; /* isr status register LMPM_NIC_ISR0: rxtx_flag */
+ u32 isr1; /* isr status register LMPM_NIC_ISR1: host_flag */
+ u32 isr2; /* isr status register LMPM_NIC_ISR2: enc_flag */
+ u32 isr3; /* isr status register LMPM_NIC_ISR3: time_flag */
+ u32 isr4; /* isr status register LMPM_NIC_ISR4: wico interrupt */
+ u32 isr_pref; /* isr status register LMPM_NIC_PREF_STAT */
+ u32 wait_event; /* wait event() caller address */
+ u32 l2p_control; /* L2pControlField */
+ u32 l2p_duration; /* L2pDurationField */
+ u32 l2p_mhvalid; /* L2pMhValidBits */
+ u32 l2p_addr_match; /* L2pAddrMatchStat */
+ u32 lmpm_pmg_sel; /* indicate which clocks are turned on (LMPM_PMG_SEL) */
+ u32 u_timestamp; /* indicate when the date and time of the compilation */
+ u32 flow_handler; /* FH read/write pointers, RX credit */
+#endif
+} __packed;
+
struct iwl_alive_resp {
u8 ucode_minor;
u8 ucode_major;
@@ -722,46 +631,6 @@ enum {
* regardless of whether RXON_FILTER_ASSOC_MSK is set.
*/
-struct iwl3945_rxon_cmd {
- u8 node_addr[6];
- __le16 reserved1;
- u8 bssid_addr[6];
- __le16 reserved2;
- u8 wlap_bssid_addr[6];
- __le16 reserved3;
- u8 dev_type;
- u8 air_propagation;
- __le16 reserved4;
- u8 ofdm_basic_rates;
- u8 cck_basic_rates;
- __le16 assoc_id;
- __le32 flags;
- __le32 filter_flags;
- __le16 channel;
- __le16 reserved5;
-} __packed;
-
-struct iwl4965_rxon_cmd {
- u8 node_addr[6];
- __le16 reserved1;
- u8 bssid_addr[6];
- __le16 reserved2;
- u8 wlap_bssid_addr[6];
- __le16 reserved3;
- u8 dev_type;
- u8 air_propagation;
- __le16 rx_chain;
- u8 ofdm_basic_rates;
- u8 cck_basic_rates;
- __le16 assoc_id;
- __le32 flags;
- __le32 filter_flags;
- __le16 channel;
- u8 ofdm_ht_single_stream_basic_rates;
- u8 ofdm_ht_dual_stream_basic_rates;
-} __packed;
-
-/* 5000 HW just extend this command */
struct iwl_rxon_cmd {
u8 node_addr[6];
__le16 reserved1;
@@ -789,26 +658,7 @@ struct iwl_rxon_cmd {
/*
* REPLY_RXON_ASSOC = 0x11 (command, has simple generic response)
*/
-struct iwl3945_rxon_assoc_cmd {
- __le32 flags;
- __le32 filter_flags;
- u8 ofdm_basic_rates;
- u8 cck_basic_rates;
- __le16 reserved;
-} __packed;
-
-struct iwl4965_rxon_assoc_cmd {
- __le32 flags;
- __le32 filter_flags;
- u8 ofdm_basic_rates;
- u8 cck_basic_rates;
- u8 ofdm_ht_single_stream_basic_rates;
- u8 ofdm_ht_dual_stream_basic_rates;
- __le16 rx_chain_select_flags;
- __le16 reserved;
-} __packed;
-
-struct iwl5000_rxon_assoc_cmd {
+struct iwl_rxon_assoc_cmd {
__le32 flags;
__le32 filter_flags;
u8 ofdm_basic_rates;
@@ -843,26 +693,6 @@ struct iwl_rxon_time_cmd {
/*
* REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response)
*/
-struct iwl3945_channel_switch_cmd {
- u8 band;
- u8 expect_beacon;
- __le16 channel;
- __le32 rxon_flags;
- __le32 rxon_filter_flags;
- __le32 switch_time;
- struct iwl3945_power_per_rate power[IWL_MAX_RATES];
-} __packed;
-
-struct iwl4965_channel_switch_cmd {
- u8 band;
- u8 expect_beacon;
- __le16 channel;
- __le32 rxon_flags;
- __le32 rxon_filter_flags;
- __le32 switch_time;
- struct iwl4965_tx_power_db tx_power;
-} __packed;
-
/**
* struct iwl5000_channel_switch_cmd
* @band: 0- 5.2GHz, 1- 2.4GHz
@@ -976,15 +806,10 @@ struct iwl_qosparam_cmd {
#define IWL_AP_ID 0
#define IWL_AP_ID_PAN 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 IWLAGN_PAN_BCAST_ID 14
#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)
@@ -1032,16 +857,6 @@ struct iwl_qosparam_cmd {
* combined with Traffic ID (QOS priority), in format used by Tx Scheduler */
#define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid))
-struct iwl4965_keyinfo {
- __le16 key_flags;
- u8 tkip_rx_tsc_byte2; /* TSC[2] for key mix ph1 detection */
- u8 reserved1;
- __le16 tkip_rx_ttak[5]; /* 10-byte unicast TKIP TTAK */
- u8 key_offset;
- u8 reserved2;
- u8 key[16]; /* 16-byte unicast decryption key */
-} __packed;
-
/* agn */
struct iwl_keyinfo {
__le16 key_flags;
@@ -1083,7 +898,6 @@ struct sta_id_modify {
* with info on security keys, aggregation parameters, and Tx rates for
* initial Tx attempt and any retries (agn devices uses
* REPLY_TX_LINK_QUALITY_CMD,
- * 3945 uses REPLY_RATE_SCALE to set up rate tables).
*
* REPLY_ADD_STA sets up the table entry for one station, either creating
* a new entry, or modifying a pre-existing one.
@@ -1103,72 +917,6 @@ struct sta_id_modify {
* entries for all STAs in network, starting with index IWL_STA_ID.
*/
-struct iwl3945_addsta_cmd {
- u8 mode; /* 1: modify existing, 0: add new station */
- u8 reserved[3];
- struct sta_id_modify sta;
- struct iwl4965_keyinfo key;
- __le32 station_flags; /* STA_FLG_* */
- __le32 station_flags_msk; /* STA_FLG_* */
-
- /* bit field to disable (1) or enable (0) Tx for Traffic ID (TID)
- * corresponding to bit (e.g. bit 5 controls TID 5).
- * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */
- __le16 tid_disable_tx;
-
- __le16 rate_n_flags;
-
- /* TID for which to add block-ack support.
- * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
- u8 add_immediate_ba_tid;
-
- /* TID for which to remove block-ack support.
- * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */
- u8 remove_immediate_ba_tid;
-
- /* 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;
-} __packed;
-
-struct iwl4965_addsta_cmd {
- u8 mode; /* 1: modify existing, 0: add new station */
- u8 reserved[3];
- struct sta_id_modify sta;
- struct iwl4965_keyinfo key;
- __le32 station_flags; /* STA_FLG_* */
- __le32 station_flags_msk; /* STA_FLG_* */
-
- /* bit field to disable (1) or enable (0) Tx for Traffic ID (TID)
- * corresponding to bit (e.g. bit 5 controls TID 5).
- * Set modify_mask bit STA_MODIFY_TID_DISABLE_TX to use this field. */
- __le16 tid_disable_tx;
-
- __le16 reserved1;
-
- /* TID for which to add block-ack support.
- * Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
- u8 add_immediate_ba_tid;
-
- /* TID for which to remove block-ack support.
- * Set modify_mask bit STA_MODIFY_DELBA_TID_MSK to use this field. */
- u8 remove_immediate_ba_tid;
-
- /* 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;
-
- /*
- * Number of packets OK to transmit to station even though
- * it is asleep -- used to synchronise PS-poll and u-APSD
- * responses while ucode keeps track of STA sleep state.
- */
- __le16 sleep_tx_count;
-
- __le16 reserved2;
-} __packed;
-
-/* agn */
struct iwl_addsta_cmd {
u8 mode; /* 1: modify existing, 0: add new station */
u8 reserved[3];
@@ -1337,62 +1085,6 @@ struct iwl_wep_cmd {
#define RX_MPDU_RES_STATUS_DEC_DONE_MSK (0x800)
-struct iwl3945_rx_frame_stats {
- u8 phy_count;
- u8 id;
- u8 rssi;
- u8 agc;
- __le16 sig_avg;
- __le16 noise_diff;
- u8 payload[0];
-} __packed;
-
-struct iwl3945_rx_frame_hdr {
- __le16 channel;
- __le16 phy_flags;
- u8 reserved1;
- u8 rate;
- __le16 len;
- u8 payload[0];
-} __packed;
-
-struct iwl3945_rx_frame_end {
- __le32 status;
- __le64 timestamp;
- __le32 beacon_timestamp;
-} __packed;
-
-/*
- * REPLY_3945_RX = 0x1b (response only, not a command)
- *
- * NOTE: DO NOT dereference from casts to this structure
- * It is provided only for calculating minimum data set size.
- * The actual offsets of the hdr and end are dynamic based on
- * stats.phy_count
- */
-struct iwl3945_rx_frame {
- struct iwl3945_rx_frame_stats stats;
- struct iwl3945_rx_frame_hdr hdr;
- struct iwl3945_rx_frame_end end;
-} __packed;
-
-#define IWL39_RX_FRAME_SIZE (4 + sizeof(struct iwl3945_rx_frame))
-
-/* Fixed (non-configurable) rx data from phy */
-
-#define IWL49_RX_RES_PHY_CNT 14
-#define IWL49_RX_PHY_FLAGS_ANTENNAE_OFFSET (4)
-#define IWL49_RX_PHY_FLAGS_ANTENNAE_MASK (0x70)
-#define IWL49_AGC_DB_MASK (0x3f80) /* MASK(7,13) */
-#define IWL49_AGC_DB_POS (7)
-struct iwl4965_rx_non_cfg_phy {
- __le16 ant_selection; /* ant A bit 4, ant B bit 5, ant C bit 6 */
- __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];
-} __packed;
-
-
#define IWLAGN_RX_RES_PHY_CNT 8
#define IWLAGN_RX_RES_AGC_IDX 1
#define IWLAGN_RX_RES_RSSI_AB_IDX 2
@@ -1576,80 +1268,6 @@ struct iwl_rx_mpdu_res_start {
* REPLY_TX = 0x1c (command)
*/
-struct iwl3945_tx_cmd {
- /*
- * MPDU byte count:
- * MAC header (24/26/30/32 bytes) + 2 bytes pad if 26/30 header size,
- * + 8 byte IV for CCM or TKIP (not used for WEP)
- * + Data payload
- * + 8-byte MIC (not used for CCM/WEP)
- * NOTE: Does not include Tx command bytes, post-MAC pad bytes,
- * MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes.i
- * Range: 14-2342 bytes.
- */
- __le16 len;
-
- /*
- * MPDU or MSDU byte count for next frame.
- * Used for fragmentation and bursting, but not 11n aggregation.
- * Same as "len", but for next frame. Set to 0 if not applicable.
- */
- __le16 next_frame_len;
-
- __le32 tx_flags; /* TX_CMD_FLG_* */
-
- u8 rate;
-
- /* Index of recipient station in uCode's station table */
- u8 sta_id;
- u8 tid_tspec;
- u8 sec_ctl;
- u8 key[16];
- union {
- u8 byte[8];
- __le16 word[4];
- __le32 dw[2];
- } tkip_mic;
- __le32 next_frame_info;
- union {
- __le32 life_time;
- __le32 attempt;
- } stop_time;
- u8 supp_rates[2];
- u8 rts_retry_limit; /*byte 50 */
- u8 data_retry_limit; /*byte 51 */
- union {
- __le16 pm_frame_timeout;
- __le16 attempt_duration;
- } timeout;
-
- /*
- * Duration of EDCA burst Tx Opportunity, in 32-usec units.
- * Set this if txop time is not specified by HCCA protocol (e.g. by AP).
- */
- __le16 driver_txop;
-
- /*
- * MAC header goes here, followed by 2 bytes padding if MAC header
- * length is 26 or 30 bytes, followed by payload data
- */
- u8 payload[0];
- struct ieee80211_hdr hdr[0];
-} __packed;
-
-/*
- * REPLY_TX = 0x1c (response)
- */
-struct iwl3945_tx_resp {
- u8 failure_rts;
- u8 failure_frame;
- u8 bt_kill_count;
- u8 rate;
- __le32 wireless_media_time;
- __le32 status; /* TX status */
-} __packed;
-
-
/*
* 4965 uCode updates these Tx attempt count values in host DRAM.
* Used for managing Tx retries when expecting block-acks.
@@ -1740,54 +1358,6 @@ struct iwl_tx_cmd {
struct ieee80211_hdr hdr[0];
} __packed;
-/* TX command response is sent after *3945* transmission attempts.
- *
- * NOTES:
- *
- * TX_STATUS_FAIL_NEXT_FRAG
- *
- * If the fragment flag in the MAC header for the frame being transmitted
- * is set and there is insufficient time to transmit the next frame, the
- * TX status will be returned with 'TX_STATUS_FAIL_NEXT_FRAG'.
- *
- * TX_STATUS_FIFO_UNDERRUN
- *
- * Indicates the host did not provide bytes to the FIFO fast enough while
- * a TX was in progress.
- *
- * TX_STATUS_FAIL_MGMNT_ABORT
- *
- * This status is only possible if the ABORT ON MGMT RX parameter was
- * set to true with the TX command.
- *
- * If the MSB of the status parameter is set then an abort sequence is
- * required. This sequence consists of the host activating the TX Abort
- * control line, and then waiting for the TX Abort command response. This
- * indicates that a the device is no longer in a transmit state, and that the
- * command FIFO has been cleared. The host must then deactivate the TX Abort
- * control line. Receiving is still allowed in this case.
- */
-enum {
- TX_3945_STATUS_SUCCESS = 0x01,
- TX_3945_STATUS_DIRECT_DONE = 0x02,
- TX_3945_STATUS_FAIL_SHORT_LIMIT = 0x82,
- TX_3945_STATUS_FAIL_LONG_LIMIT = 0x83,
- TX_3945_STATUS_FAIL_FIFO_UNDERRUN = 0x84,
- TX_3945_STATUS_FAIL_MGMNT_ABORT = 0x85,
- TX_3945_STATUS_FAIL_NEXT_FRAG = 0x86,
- TX_3945_STATUS_FAIL_LIFE_EXPIRE = 0x87,
- TX_3945_STATUS_FAIL_DEST_PS = 0x88,
- TX_3945_STATUS_FAIL_ABORTED = 0x89,
- TX_3945_STATUS_FAIL_BT_RETRY = 0x8a,
- TX_3945_STATUS_FAIL_STA_INVALID = 0x8b,
- TX_3945_STATUS_FAIL_FRAG_DROPPED = 0x8c,
- TX_3945_STATUS_FAIL_TID_DISABLE = 0x8d,
- TX_3945_STATUS_FAIL_FRAME_FLUSHED = 0x8e,
- TX_3945_STATUS_FAIL_INSUFFICIENT_CF_POLL = 0x8f,
- TX_3945_STATUS_FAIL_TX_LOCKED = 0x90,
- TX_3945_STATUS_FAIL_NO_BEACON_ON_RADAR = 0x91,
-};
-
/*
* TX command response is sent after *agn* transmission attempts.
*
@@ -1905,43 +1475,6 @@ struct agg_tx_status {
__le16 sequence;
} __packed;
-struct iwl4965_tx_resp {
- u8 frame_count; /* 1 no aggregation, >1 aggregation */
- u8 bt_kill_count; /* # blocked by bluetooth (unused for agg) */
- u8 failure_rts; /* # failures due to unsuccessful RTS */
- u8 failure_frame; /* # failures due to no ACK (unused for agg) */
-
- /* For non-agg: Rate at which frame was successful.
- * For agg: Rate at which all frames were transmitted. */
- __le32 rate_n_flags; /* RATE_MCS_* */
-
- /* For non-agg: RTS + CTS + frame tx attempts time + ACK.
- * For agg: RTS + CTS + aggregation tx time + block-ack time. */
- __le16 wireless_media_time; /* uSecs */
-
- __le16 reserved;
- __le32 pa_power1; /* RF power amplifier measurement (not used) */
- __le32 pa_power2;
-
- /*
- * For non-agg: frame status TX_STATUS_*
- * For agg: status of 1st frame, AGG_TX_STATE_*; other frame status
- * fields follow this one, up to frame_count.
- * Bit fields:
- * 11- 0: AGG_TX_STATE_* status code
- * 15-12: Retry count for 1st frame in aggregation (retries
- * occur if tx failed for this frame when it was a
- * member of a previous aggregation block). If rate
- * scaling is used, retry count indicates the rate
- * table entry used for all frames in the new agg.
- * 31-16: Sequence # for this frame's Tx cmd (not SSN!)
- */
- union {
- __le32 status;
- struct agg_tx_status agg_status[0]; /* for each agg frame */
- } u;
-} __packed;
-
/*
* definitions for initial rate index field
* bits [3:0] initial rate index
@@ -2030,51 +1563,7 @@ struct iwl_compressed_ba_resp {
/*
* REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response)
*
- * See details under "TXPOWER" in iwl-4965-hw.h.
- */
-
-struct iwl3945_txpowertable_cmd {
- u8 band; /* 0: 5 GHz, 1: 2.4 GHz */
- u8 reserved;
- __le16 channel;
- struct iwl3945_power_per_rate power[IWL_MAX_RATES];
-} __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;
-} __packed;
-
-
-/**
- * struct iwl3945_rate_scaling_cmd - Rate Scaling Command & Response
- *
- * REPLY_RATE_SCALE = 0x47 (command, has simple generic response)
- *
- * NOTE: The table of rates passed to the uCode via the
- * RATE_SCALE command sets up the corresponding order of
- * rates used for all related commands, including rate
- * masks, etc.
- *
- * For example, if you set 9MB (PLCP 0x0f) as the first
- * rate in the rate table, the bit mask for that rate
- * when passed through ofdm_basic_rates on the REPLY_RXON
- * command would be bit 0 (1 << 0)
*/
-struct iwl3945_rate_scaling_info {
- __le16 rate_n_flags;
- u8 try_cnt;
- u8 next_rate_index;
-} __packed;
-
-struct iwl3945_rate_scaling_cmd {
- u8 table_id;
- u8 reserved[3];
- struct iwl3945_rate_scaling_info table[IWL_MAX_RATES];
-} __packed;
-
/*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */
#define LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK (1 << 0)
@@ -2130,7 +1619,7 @@ struct iwl_link_qual_general_params {
#define LINK_QUAL_AGG_DISABLE_START_MAX (255)
#define LINK_QUAL_AGG_DISABLE_START_MIN (0)
-#define LINK_QUAL_AGG_FRAME_LIMIT_DEF (31)
+#define LINK_QUAL_AGG_FRAME_LIMIT_DEF (63)
#define LINK_QUAL_AGG_FRAME_LIMIT_MAX (63)
#define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0)
@@ -2696,14 +2185,6 @@ struct iwl_spectrum_notification {
#define IWL_POWER_BT_SCO_ENA cpu_to_le16(BIT(8))
#define IWL_POWER_ADVANCE_PM_ENA_MSK cpu_to_le16(BIT(9))
-struct iwl3945_powertable_cmd {
- __le16 flags;
- u8 reserved[2];
- __le32 rx_data_timeout;
- __le32 tx_data_timeout;
- __le32 sleep_interval[IWL_POWER_VEC_SIZE];
-} __packed;
-
struct iwl_powertable_cmd {
__le16 flags;
u8 keep_alive_seconds; /* 3945 reserved */
@@ -2806,25 +2287,6 @@ struct iwl_ct_kill_throttling_config {
* active_dwell < max_out_time
*/
-/* FIXME: rename to AP1, remove tpc */
-struct iwl3945_scan_channel {
- /*
- * type is defined as:
- * 0:0 1 = active, 0 = passive
- * 1:4 SSID direct bit map; if a bit is set, then corresponding
- * SSID IE is transmitted in probe request.
- * 5:7 reserved
- */
- u8 type;
- u8 channel; /* band is selected by iwl3945_scan_cmd "flags" field */
- 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 */
-} __packed;
-
-/* set number of direct probes u8 type */
-#define IWL39_SCAN_PROBE_MASK(n) ((BIT(n) | (BIT(n) - BIT(1))))
-
struct iwl_scan_channel {
/*
* type is defined as:
@@ -2920,50 +2382,6 @@ struct iwl_ssid_ie {
* struct iwl_scan_channel.
*/
-struct iwl3945_scan_cmd {
- __le16 len;
- u8 reserved0;
- u8 channel_count; /* # channels in channel list */
- __le16 quiet_time; /* dwell only this # millisecs on quiet channel
- * (only for active scan) */
- __le16 quiet_plcp_th; /* quiet chnl is < this # pkts (typ. 1) */
- __le16 good_CRC_th; /* passive -> active promotion threshold */
- __le16 reserved1;
- __le32 max_out_time; /* max usec to be away from associated (service)
- * channel */
- __le32 suspend_time; /* pause scan this long (in "extended beacon
- * format") when returning to service channel:
- * 3945; 31:24 # beacons, 19:0 additional usec,
- * 4965; 31:22 # beacons, 21:0 additional usec.
- */
- __le32 flags; /* RXON_FLG_* */
- __le32 filter_flags; /* RXON_FILTER_* */
-
- /* For active scans (set to all-0s for passive scans).
- * Does not include payload. Must specify Tx rate; no rate scaling. */
- struct iwl3945_tx_cmd tx_cmd;
-
- /* For directed active scans (set to all-0s otherwise) */
- struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX_3945];
-
- /*
- * Probe request frame, followed by channel list.
- *
- * Size of probe request frame is specified by byte count in tx_cmd.
- * Channel list follows immediately after probe request frame.
- * Number of channels in list is specified by channel_count.
- * Each channel in list is of type:
- *
- * struct iwl3945_scan_channel channels[0];
- *
- * NOTE: Only one band of channels can be scanned per pass. You
- * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait
- * for one scan to complete (i.e. receive SCAN_COMPLETE_NOTIFICATION)
- * before requesting another scan.
- */
- u8 data[0];
-} __packed;
-
enum iwl_scan_flags {
/* BIT(0) currently unused */
IWL_SCAN_FLAGS_ACTION_FRAME_TX = BIT(1),
@@ -3090,20 +2508,6 @@ enum iwl_ibss_manager {
* BEACON_NOTIFICATION = 0x90 (notification only, not a command)
*/
-struct iwl3945_beacon_notif {
- struct iwl3945_tx_resp beacon_notify_hdr;
- __le32 low_tsf;
- __le32 high_tsf;
- __le32 ibss_mgr_status;
-} __packed;
-
-struct iwl4965_beacon_notif {
- struct iwl4965_tx_resp beacon_notify_hdr;
- __le32 low_tsf;
- __le32 high_tsf;
- __le32 ibss_mgr_status;
-} __packed;
-
struct iwlagn_beacon_notif {
struct iwlagn_tx_resp beacon_notify_hdr;
__le32 low_tsf;
@@ -3115,14 +2519,6 @@ struct iwlagn_beacon_notif {
* REPLY_TX_BEACON = 0x91 (command, has simple generic response)
*/
-struct iwl3945_tx_beacon_cmd {
- struct iwl3945_tx_cmd tx;
- __le16 tim_idx;
- u8 tim_size;
- u8 reserved1;
- struct ieee80211_hdr frame[0]; /* beacon frame */
-} __packed;
-
struct iwl_tx_beacon_cmd {
struct iwl_tx_cmd tx;
__le16 tim_idx;
@@ -3159,53 +2555,6 @@ struct rate_histogram {
/* statistics command response */
-struct iwl39_statistics_rx_phy {
- __le32 ina_cnt;
- __le32 fina_cnt;
- __le32 plcp_err;
- __le32 crc32_err;
- __le32 overrun_err;
- __le32 early_overrun_err;
- __le32 crc32_good;
- __le32 false_alarm_cnt;
- __le32 fina_sync_err_cnt;
- __le32 sfd_timeout;
- __le32 fina_timeout;
- __le32 unresponded_rts;
- __le32 rxe_frame_limit_overrun;
- __le32 sent_ack_cnt;
- __le32 sent_cts_cnt;
-} __packed;
-
-struct iwl39_statistics_rx_non_phy {
- __le32 bogus_cts; /* CTS received when not expecting CTS */
- __le32 bogus_ack; /* ACK received when not expecting ACK */
- __le32 non_bssid_frames; /* number of frames with BSSID that
- * doesn't belong to the STA BSSID */
- __le32 filtered_frames; /* count frames that were dumped in the
- * filtering process */
- __le32 non_channel_beacons; /* beacons with our bss id but not on
- * our serving channel */
-} __packed;
-
-struct iwl39_statistics_rx {
- struct iwl39_statistics_rx_phy ofdm;
- struct iwl39_statistics_rx_phy cck;
- struct iwl39_statistics_rx_non_phy general;
-} __packed;
-
-struct iwl39_statistics_tx {
- __le32 preamble_cnt;
- __le32 rx_detected_cnt;
- __le32 bt_prio_defer_cnt;
- __le32 bt_prio_kill_cnt;
- __le32 few_bytes_cnt;
- __le32 cts_timeout;
- __le32 ack_timeout;
- __le32 expected_ack_cnt;
- __le32 actual_ack_cnt;
-} __packed;
-
struct statistics_dbg {
__le32 burst_check;
__le32 burst_count;
@@ -3213,23 +2562,6 @@ struct statistics_dbg {
__le32 reserved[3];
} __packed;
-struct iwl39_statistics_div {
- __le32 tx_on_a;
- __le32 tx_on_b;
- __le32 exec_time;
- __le32 probe_time;
-} __packed;
-
-struct iwl39_statistics_general {
- __le32 temperature;
- struct statistics_dbg dbg;
- __le32 sleep_time;
- __le32 slots_out;
- __le32 slots_idle;
- __le32 ttl_timestamp;
- struct iwl39_statistics_div div;
-} __packed;
-
struct statistics_rx_phy {
__le32 ina_cnt;
__le32 fina_cnt;
@@ -3471,13 +2803,6 @@ struct iwl_statistics_cmd {
#define STATISTICS_REPLY_FLG_BAND_24G_MSK cpu_to_le32(0x2)
#define STATISTICS_REPLY_FLG_HT40_MODE_MSK cpu_to_le32(0x8)
-struct iwl3945_notif_statistics {
- __le32 flag;
- struct iwl39_statistics_rx rx;
- struct iwl39_statistics_tx tx;
- struct iwl39_statistics_general general;
-} __packed;
-
struct iwl_notif_statistics {
__le32 flag;
struct statistics_rx rx;
@@ -4451,10 +3776,6 @@ struct iwl_rx_packet {
__le32 len_n_flags;
struct iwl_cmd_header hdr;
union {
- struct iwl3945_rx_frame rx_frame;
- struct iwl3945_tx_resp tx_resp;
- struct iwl3945_beacon_notif beacon_status;
-
struct iwl_alive_resp alive_frame;
struct iwl_spectrum_notification spectrum_notif;
struct iwl_csa_notification csa_notif;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index bafbe57c9602..4653deada05b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -2,7 +2,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 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
@@ -41,6 +41,7 @@
#include "iwl-power.h"
#include "iwl-sta.h"
#include "iwl-helpers.h"
+#include "iwl-agn.h"
/*
@@ -67,30 +68,6 @@ u32 iwl_debug_level;
const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
-
-/* This function both allocates and initializes hw and priv. */
-struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg)
-{
- struct iwl_priv *priv;
- /* mac80211 allocates memory for this device instance, including
- * space for this driver's private structure */
- struct ieee80211_hw *hw;
-
- hw = ieee80211_alloc_hw(sizeof(struct iwl_priv),
- cfg->ops->ieee80211_ops);
- if (hw == NULL) {
- pr_err("%s: Can not allocate network device\n",
- cfg->name);
- goto out;
- }
-
- priv = hw->priv;
- priv->hw = hw;
-
-out:
- return hw;
-}
-
#define MAX_BIT_RATE_40_MHZ 150 /* Mbps */
#define MAX_BIT_RATE_20_MHZ 72 /* Mbps */
static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
@@ -118,7 +95,7 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv,
max_bit_rate = MAX_BIT_RATE_40_MHZ;
}
- if (priv->cfg->mod_params->amsdu_size_8K)
+ if (iwlagn_mod_params.amsdu_size_8K)
ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU;
ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF;
@@ -159,6 +136,7 @@ int iwlcore_init_geos(struct iwl_priv *priv)
struct ieee80211_channel *geo_ch;
struct ieee80211_rate *rates;
int i = 0;
+ s8 max_tx_power = IWLAGN_TX_POWER_TARGET_POWER_MIN;
if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates ||
priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) {
@@ -232,8 +210,8 @@ int iwlcore_init_geos(struct iwl_priv *priv)
geo_ch->flags |= ch->ht40_extension_channel;
- if (ch->max_power_avg > priv->tx_power_device_lmt)
- priv->tx_power_device_lmt = ch->max_power_avg;
+ if (ch->max_power_avg > max_tx_power)
+ max_tx_power = ch->max_power_avg;
} else {
geo_ch->flags |= IEEE80211_CHAN_DISABLED;
}
@@ -246,6 +224,10 @@ int iwlcore_init_geos(struct iwl_priv *priv)
geo_ch->flags);
}
+ priv->tx_power_device_lmt = max_tx_power;
+ priv->tx_power_user_lmt = max_tx_power;
+ priv->tx_power_next = max_tx_power;
+
if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) &&
priv->cfg->sku & IWL_SKU_A) {
IWL_INFO(priv, "Incorrectly detected BG card as ABG. "
@@ -434,72 +416,72 @@ void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
{
struct iwl_rxon_cmd *rxon = &ctx->staging;
- bool error = false;
+ u32 errors = 0;
if (rxon->flags & RXON_FLG_BAND_24G_MSK) {
if (rxon->flags & RXON_FLG_TGJ_NARROW_BAND_MSK) {
IWL_WARN(priv, "check 2.4G: wrong narrow\n");
- error = true;
+ errors |= BIT(0);
}
if (rxon->flags & RXON_FLG_RADAR_DETECT_MSK) {
IWL_WARN(priv, "check 2.4G: wrong radar\n");
- error = true;
+ errors |= BIT(1);
}
} else {
if (!(rxon->flags & RXON_FLG_SHORT_SLOT_MSK)) {
IWL_WARN(priv, "check 5.2G: not short slot!\n");
- error = true;
+ errors |= BIT(2);
}
if (rxon->flags & RXON_FLG_CCK_MSK) {
IWL_WARN(priv, "check 5.2G: CCK!\n");
- error = true;
+ errors |= BIT(3);
}
}
if ((rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1) {
IWL_WARN(priv, "mac/bssid mcast!\n");
- error = true;
+ errors |= BIT(4);
}
/* make sure basic rates 6Mbps and 1Mbps are supported */
if ((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0 &&
(rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0) {
IWL_WARN(priv, "neither 1 nor 6 are basic\n");
- error = true;
+ errors |= BIT(5);
}
if (le16_to_cpu(rxon->assoc_id) > 2007) {
IWL_WARN(priv, "aid > 2007\n");
- error = true;
+ errors |= BIT(6);
}
if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK))
== (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) {
IWL_WARN(priv, "CCK and short slot\n");
- error = true;
+ errors |= BIT(7);
}
if ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))
== (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) {
IWL_WARN(priv, "CCK and auto detect");
- error = true;
+ errors |= BIT(8);
}
if ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK |
RXON_FLG_TGG_PROTECT_MSK)) ==
RXON_FLG_TGG_PROTECT_MSK) {
IWL_WARN(priv, "TGg but no auto-detect\n");
- error = true;
+ errors |= BIT(9);
}
- if (error)
- IWL_WARN(priv, "Tuning to channel %d\n",
- le16_to_cpu(rxon->channel));
-
- if (error) {
- IWL_ERR(priv, "Invalid RXON\n");
- return -EINVAL;
+ if (rxon->channel == 0) {
+ IWL_WARN(priv, "zero channel is invalid\n");
+ errors |= BIT(10);
}
- return 0;
+
+ WARN(errors, "Invalid RXON (%#x), channel %d",
+ errors, le16_to_cpu(rxon->channel));
+
+ return errors ? -EINVAL : 0;
}
/**
@@ -890,10 +872,21 @@ void iwl_print_rx_config_cmd(struct iwl_priv *priv,
IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
}
#endif
-/**
- * iwl_irq_handle_error - called for HW or SW error interrupt from card
- */
-void iwl_irq_handle_error(struct iwl_priv *priv)
+
+static void iwlagn_abort_notification_waits(struct iwl_priv *priv)
+{
+ unsigned long flags;
+ struct iwl_notification_wait *wait_entry;
+
+ spin_lock_irqsave(&priv->_agn.notif_wait_lock, flags);
+ list_for_each_entry(wait_entry, &priv->_agn.notif_waits, list)
+ wait_entry->aborted = true;
+ spin_unlock_irqrestore(&priv->_agn.notif_wait_lock, flags);
+
+ wake_up_all(&priv->_agn.notif_waitq);
+}
+
+void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
{
unsigned int reload_msec;
unsigned long reload_jiffies;
@@ -904,18 +897,64 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
/* Cancel currently queued command. */
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+ iwlagn_abort_notification_waits(priv);
+
+ /* Keep the restart process from trying to send host
+ * commands by clearing the ready bit */
+ clear_bit(STATUS_READY, &priv->status);
+
+ wake_up_interruptible(&priv->wait_command_queue);
+
+ if (!ondemand) {
+ /*
+ * If firmware keep reloading, then it indicate something
+ * serious wrong and firmware having problem to recover
+ * from it. Instead of keep trying which will fill the syslog
+ * and hang the system, let's just stop it
+ */
+ reload_jiffies = jiffies;
+ reload_msec = jiffies_to_msecs((long) reload_jiffies -
+ (long) priv->reload_jiffies);
+ priv->reload_jiffies = reload_jiffies;
+ if (reload_msec <= IWL_MIN_RELOAD_DURATION) {
+ priv->reload_count++;
+ if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) {
+ IWL_ERR(priv, "BUG_ON, Stop restarting\n");
+ return;
+ }
+ } else
+ priv->reload_count = 0;
+ }
+
+ if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
+ if (iwlagn_mod_params.restart_fw) {
+ IWL_DEBUG(priv, IWL_DL_FW_ERRORS,
+ "Restarting adapter due to uCode error.\n");
+ queue_work(priv->workqueue, &priv->restart);
+ } else
+ IWL_DEBUG(priv, IWL_DL_FW_ERRORS,
+ "Detected FW error, but not restarting\n");
+ }
+}
+
+/**
+ * iwl_irq_handle_error - called for HW or SW error interrupt from card
+ */
+void iwl_irq_handle_error(struct iwl_priv *priv)
+{
/* W/A for WiFi/WiMAX coex and WiMAX own the RF */
if (priv->cfg->internal_wimax_coex &&
(!(iwl_read_prph(priv, APMG_CLK_CTRL_REG) &
APMS_CLK_VAL_MRB_FUNC_MODE) ||
(iwl_read_prph(priv, APMG_PS_CTRL_REG) &
APMG_PS_CTRL_VAL_RESET_REQ))) {
- wake_up_interruptible(&priv->wait_command_queue);
/*
- *Keep the restart process from trying to send host
- * commands by clearing the INIT status bit
+ * Keep the restart process from trying to send host
+ * commands by clearing the ready bit.
*/
clear_bit(STATUS_READY, &priv->status);
+ clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
+ wake_up_interruptible(&priv->wait_command_queue);
IWL_ERR(priv, "RF is used by WiMAX\n");
return;
}
@@ -923,50 +962,17 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
IWL_ERR(priv, "Loaded firmware version: %s\n",
priv->hw->wiphy->fw_version);
- priv->cfg->ops->lib->dump_nic_error_log(priv);
- if (priv->cfg->ops->lib->dump_csr)
- priv->cfg->ops->lib->dump_csr(priv);
- if (priv->cfg->ops->lib->dump_fh)
- priv->cfg->ops->lib->dump_fh(priv, NULL, false);
- priv->cfg->ops->lib->dump_nic_event_log(priv, false, NULL, false);
+ iwl_dump_nic_error_log(priv);
+ iwl_dump_csr(priv);
+ iwl_dump_fh(priv, NULL, false);
+ iwl_dump_nic_event_log(priv, false, NULL, false);
#ifdef CONFIG_IWLWIFI_DEBUG
if (iwl_get_debug_level(priv) & IWL_DL_FW_ERRORS)
iwl_print_rx_config_cmd(priv,
&priv->contexts[IWL_RXON_CTX_BSS]);
#endif
- wake_up_interruptible(&priv->wait_command_queue);
-
- /* Keep the restart process from trying to send host
- * commands by clearing the INIT status bit */
- clear_bit(STATUS_READY, &priv->status);
-
- /*
- * If firmware keep reloading, then it indicate something
- * serious wrong and firmware having problem to recover
- * from it. Instead of keep trying which will fill the syslog
- * and hang the system, let's just stop it
- */
- reload_jiffies = jiffies;
- reload_msec = jiffies_to_msecs((long) reload_jiffies -
- (long) priv->reload_jiffies);
- priv->reload_jiffies = reload_jiffies;
- if (reload_msec <= IWL_MIN_RELOAD_DURATION) {
- priv->reload_count++;
- if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) {
- IWL_ERR(priv, "BUG_ON, Stop restarting\n");
- return;
- }
- } else
- priv->reload_count = 0;
-
- if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
- IWL_DEBUG(priv, IWL_DL_FW_ERRORS,
- "Restarting adapter due to uCode error.\n");
-
- if (priv->cfg->mod_params->restart_fw)
- queue_work(priv->workqueue, &priv->restart);
- }
+ iwlagn_fw_error(priv, false);
}
static int iwl_apm_stop_master(struct iwl_priv *priv)
@@ -990,6 +996,8 @@ void iwl_apm_stop(struct iwl_priv *priv)
{
IWL_DEBUG_INFO(priv, "Stop card, put in low power state\n");
+ clear_bit(STATUS_DEVICE_ENABLED, &priv->status);
+
/* Stop device's DMA activity */
iwl_apm_stop_master(priv);
@@ -1040,7 +1048,6 @@ int iwl_apm_init(struct iwl_priv *priv)
/*
* Enable HAP INTA (interrupt from management bus) to
* wake device's PCI Express link L1a -> L0s
- * NOTE: This is no-op for 3945 (non-existent bit)
*/
iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
@@ -1053,20 +1060,18 @@ int iwl_apm_init(struct iwl_priv *priv)
* If not (unlikely), enable L0S, so there is at least some
* power savings, even without L1.
*/
- if (priv->cfg->base_params->set_l0s) {
- lctl = iwl_pcie_link_ctl(priv);
- if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) ==
- PCI_CFG_LINK_CTRL_VAL_L1_EN) {
- /* L1-ASPM enabled; disable(!) L0S */
- iwl_set_bit(priv, CSR_GIO_REG,
- CSR_GIO_REG_VAL_L0S_ENABLED);
- IWL_DEBUG_POWER(priv, "L1 Enabled; Disabling L0S\n");
- } else {
- /* L1-ASPM disabled; enable(!) L0S */
- iwl_clear_bit(priv, CSR_GIO_REG,
- CSR_GIO_REG_VAL_L0S_ENABLED);
- IWL_DEBUG_POWER(priv, "L1 Disabled; Enabling L0S\n");
- }
+ lctl = iwl_pcie_link_ctl(priv);
+ if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) ==
+ PCI_CFG_LINK_CTRL_VAL_L1_EN) {
+ /* L1-ASPM enabled; disable(!) L0S */
+ iwl_set_bit(priv, CSR_GIO_REG,
+ CSR_GIO_REG_VAL_L0S_ENABLED);
+ IWL_DEBUG_POWER(priv, "L1 Enabled; Disabling L0S\n");
+ } else {
+ /* L1-ASPM disabled; enable(!) L0S */
+ iwl_clear_bit(priv, CSR_GIO_REG,
+ CSR_GIO_REG_VAL_L0S_ENABLED);
+ IWL_DEBUG_POWER(priv, "L1 Disabled; Enabling L0S\n");
}
/* Configure analog phase-lock-loop before activating to D0A */
@@ -1094,27 +1099,21 @@ int iwl_apm_init(struct iwl_priv *priv)
}
/*
- * Enable DMA and BSM (if used) clocks, wait for them to stabilize.
- * BSM (Boostrap State Machine) is only in 3945 and 4965;
- * later devices (i.e. 5000 and later) have non-volatile SRAM,
- * and don't need BSM to restore data after power-saving sleep.
+ * Enable DMA clock and wait for it to stabilize.
*
* Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits
* do not disable clocks. This preserves any hardware bits already
* set by default in "CLK_CTRL_REG" after reset.
*/
- if (priv->cfg->base_params->use_bsm)
- iwl_write_prph(priv, APMG_CLK_EN_REG,
- APMG_CLK_VAL_DMA_CLK_RQT | APMG_CLK_VAL_BSM_CLK_RQT);
- else
- iwl_write_prph(priv, APMG_CLK_EN_REG,
- APMG_CLK_VAL_DMA_CLK_RQT);
+ iwl_write_prph(priv, APMG_CLK_EN_REG, APMG_CLK_VAL_DMA_CLK_RQT);
udelay(20);
/* Disable L1-Active */
iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+ set_bit(STATUS_DEVICE_ENABLED, &priv->status);
+
out:
return ret;
}
@@ -1430,7 +1429,6 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
iwl_teardown_interface(priv, vif, false);
- memset(priv->bssid, 0, ETH_ALEN);
mutex_unlock(&priv->mutex);
IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -1750,21 +1748,13 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external)
* detect failure), then fw_restart module parameter
* need to be check before performing firmware reload
*/
- if (!external && !priv->cfg->mod_params->restart_fw) {
+ if (!external && !iwlagn_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);
- wake_up_interruptible(&priv->wait_command_queue);
- /*
- * Keep the restart process from trying to send host
- * commands by clearing the INIT status bit
- */
- clear_bit(STATUS_READY, &priv->status);
- queue_work(priv->workqueue, &priv->restart);
+ iwlagn_fw_error(priv, true);
break;
}
return 0;
@@ -1775,6 +1765,7 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
{
struct iwl_priv *priv = hw->priv;
struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+ struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS];
struct iwl_rxon_context *tmp;
u32 interface_modes;
int err;
@@ -1783,6 +1774,15 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
mutex_lock(&priv->mutex);
+ if (!ctx->vif || !iwl_is_ready_rf(priv)) {
+ /*
+ * Huh? But wait ... this can maybe happen when
+ * we're in the middle of a firmware restart!
+ */
+ err = -EBUSY;
+ goto out;
+ }
+
interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes;
if (!(interface_modes & BIT(newtype))) {
@@ -1790,6 +1790,19 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
goto out;
}
+ /*
+ * Refuse a change that should be done by moving from the PAN
+ * context to the BSS context instead, if the BSS context is
+ * available and can support the new interface type.
+ */
+ if (ctx->ctxid == IWL_RXON_CTX_PAN && !bss_ctx->vif &&
+ (bss_ctx->interface_modes & BIT(newtype) ||
+ bss_ctx->exclusive_interface_modes & BIT(newtype))) {
+ BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+ err = -EBUSY;
+ goto out;
+ }
+
if (ctx->exclusive_interface_modes & BIT(newtype)) {
for_each_context(priv, tmp) {
if (ctx == tmp)
@@ -1810,6 +1823,7 @@ int iwl_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
/* success */
iwl_teardown_interface(priv, vif, true);
vif->type = newtype;
+ vif->p2p = newp2p;
err = iwl_setup_interface(priv, ctx);
WARN_ON(err);
/*
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index b316d833d9a2..3bb76f6ea410 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 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
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -73,7 +73,7 @@ struct iwl_cmd;
#define IWLWIFI_VERSION "in-tree:"
-#define DRV_COPYRIGHT "Copyright(c) 2003-2010 Intel Corporation"
+#define DRV_COPYRIGHT "Copyright(c) 2003-2011 Intel Corporation"
#define DRV_AUTHOR "<ilw@linux.intel.com>"
#define IWL_PCI_DEVICE(dev, subdev, cfg) \
@@ -90,7 +90,6 @@ struct iwl_cmd;
#define IWL_CMD(x) case x: return #x
struct iwl_hcmd_ops {
- int (*rxon_assoc)(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
int (*commit_rxon)(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
void (*set_rxon_chain)(struct iwl_priv *priv,
struct iwl_rxon_context *ctx);
@@ -100,7 +99,6 @@ struct iwl_hcmd_ops {
};
struct iwl_hcmd_utils_ops {
- u16 (*get_hcmd_size)(u8 cmd_id, u16 len);
u16 (*build_addsta_hcmd)(const struct iwl_addsta_cmd *cmd, u8 *data);
void (*gain_computation)(struct iwl_priv *priv,
u32 *average_noise,
@@ -122,79 +120,21 @@ struct iwl_apm_ops {
void (*config)(struct iwl_priv *priv);
};
-struct iwl_isr_ops {
- irqreturn_t (*isr) (int irq, void *data);
- void (*free)(struct iwl_priv *priv);
- int (*alloc)(struct iwl_priv *priv);
- int (*reset)(struct iwl_priv *priv);
- void (*disable)(struct iwl_priv *priv);
-};
-
-struct iwl_debugfs_ops {
- ssize_t (*rx_stats_read)(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos);
- ssize_t (*tx_stats_read)(struct file *file, char __user *user_buf,
- 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);
- ssize_t (*reply_tx_error)(struct file *file, char __user *user_buf,
- size_t count, loff_t *ppos);
-};
-
struct iwl_temp_ops {
void (*temperature)(struct iwl_priv *priv);
};
-struct iwl_tt_ops {
- bool (*lower_power_detection)(struct iwl_priv *priv);
- u8 (*tt_power_mode)(struct iwl_priv *priv);
- bool (*ct_kill_check)(struct iwl_priv *priv);
-};
-
struct iwl_lib_ops {
/* set hw dependent parameters */
int (*set_hw_params)(struct iwl_priv *priv);
- /* Handling TX */
- void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv,
- struct iwl_tx_queue *txq,
- u16 byte_cnt);
- void (*txq_inval_byte_cnt_tbl)(struct iwl_priv *priv,
- struct iwl_tx_queue *txq);
- void (*txq_set_sched)(struct iwl_priv *priv, u32 mask);
- int (*txq_attach_buf_to_tfd)(struct iwl_priv *priv,
- struct iwl_tx_queue *txq,
- dma_addr_t addr,
- u16 len, u8 reset, u8 pad);
- void (*txq_free_tfd)(struct iwl_priv *priv,
- struct iwl_tx_queue *txq);
- int (*txq_init)(struct iwl_priv *priv,
- struct iwl_tx_queue *txq);
- /* aggregations */
- int (*txq_agg_enable)(struct iwl_priv *priv, int txq_id, int tx_fifo,
- int sta_id, int tid, u16 ssn_idx);
- int (*txq_agg_disable)(struct iwl_priv *priv, u16 txq_id, u16 ssn_idx,
- u8 tx_fifo);
/* setup Rx handler */
void (*rx_handler_setup)(struct iwl_priv *priv);
/* setup deferred work */
void (*setup_deferred_work)(struct iwl_priv *priv);
/* cancel deferred work */
void (*cancel_deferred_work)(struct iwl_priv *priv);
- /* alive notification after init uCode load */
- void (*init_alive_start)(struct iwl_priv *priv);
- /* alive notification */
- int (*alive_notify)(struct iwl_priv *priv);
/* check validity of rtc data address */
int (*is_valid_rtc_data_addr)(u32 addr);
- /* 1st ucode load */
- int (*load_ucode)(struct iwl_priv *priv);
- int (*dump_nic_event_log)(struct iwl_priv *priv,
- bool full_log, char **buf, bool display);
- 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,
struct ieee80211_channel_switch *ch_switch);
/* power management */
@@ -204,9 +144,6 @@ struct iwl_lib_ops {
int (*send_tx_power) (struct iwl_priv *priv);
void (*update_chain_flags)(struct iwl_priv *priv);
- /* isr */
- struct iwl_isr_ops isr_ops;
-
/* eeprom operations (as defined in iwl-eeprom.h) */
struct iwl_eeprom_ops eeprom_ops;
@@ -216,14 +153,6 @@ struct iwl_lib_ops {
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;
-
- /* thermal throttling */
- struct iwl_tt_ops tt_ops;
-};
-
-struct iwl_led_ops {
- int (*cmd)(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd);
};
/* NIC specific ops */
@@ -231,28 +160,15 @@ struct iwl_nic_ops {
void (*additional_nic_config)(struct iwl_priv *priv);
};
-struct iwl_legacy_ops {
- void (*post_associate)(struct iwl_priv *priv);
- void (*config_ap)(struct iwl_priv *priv);
- /* station management */
- int (*update_bcast_stations)(struct iwl_priv *priv);
- int (*manage_ibss_station)(struct iwl_priv *priv,
- struct ieee80211_vif *vif, bool add);
-};
-
struct iwl_ops {
const struct iwl_lib_ops *lib;
const struct iwl_hcmd_ops *hcmd;
const struct iwl_hcmd_utils_ops *utils;
- const struct iwl_led_ops *led;
const struct iwl_nic_ops *nic;
- const struct iwl_legacy_ops *legacy;
- const struct ieee80211_ops *ieee80211_ops;
};
struct iwl_mod_params {
int sw_crypto; /* def: 0 = using hardware encryption */
- int disable_hw_scan; /* def: 0 = use h/w scan */
int num_of_queues; /* def: HW dependent */
int disable_11n; /* def: 0 = 11n capabilities enabled */
int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */
@@ -278,16 +194,7 @@ struct iwl_mod_params {
* @wd_timeout: TX queues watchdog timeout
* @temperature_kelvin: temperature report by uCode in kelvin
* @max_event_log_size: size of event log buffer size for ucode event logging
- * @tx_power_by_driver: tx power calibration performed by driver
- * instead of uCode
- * @ucode_tracing: support ucode continuous tracing
- * @sensitivity_calib_by_driver: driver has the capability to perform
- * sensitivity calibration operation
- * @chain_noise_calib_by_driver: driver has the capability to perform
- * chain noise calibration operation
* @shadow_reg_enable: HW shadhow register bit
- * @no_agg_framecnt_info: uCode do not provide aggregation frame count
- * information
*/
struct iwl_base_params {
int eeprom_size;
@@ -295,14 +202,10 @@ struct iwl_base_params {
int num_of_ampdu_queues;/* def: HW dependent */
/* for iwl_apm_init() */
u32 pll_cfg_val;
- bool set_l0s;
- bool use_bsm;
- bool use_isr_legacy;
const u16 max_ll_items;
const bool shadow_ram_support;
u16 led_compensation;
- const bool broken_powersave;
int chain_noise_num_beacons;
bool adv_thermal_throttle;
bool support_ct_kill_exit;
@@ -312,18 +215,12 @@ struct iwl_base_params {
unsigned int wd_timeout;
bool temperature_kelvin;
u32 max_event_log_size;
- const bool tx_power_by_driver;
- const bool ucode_tracing;
- const bool sensitivity_calib_by_driver;
- const bool chain_noise_calib_by_driver;
const bool shadow_reg_enable;
- const bool no_agg_framecnt_info;
};
/*
* @advanced_bt_coexist: support advanced bt coexist
* @bt_init_traffic_load: specify initial bt traffic load
* @bt_prio_boost: default bt priority boost value
- * @bt_statistics: use BT version of statistics notification
* @agg_time_limit: maximum number of uSec in aggregation
* @ampdu_factor: Maximum A-MPDU length factor
* @ampdu_density: Minimum A-MPDU spacing
@@ -333,7 +230,6 @@ struct iwl_bt_params {
bool advanced_bt_coexist;
u8 bt_init_traffic_load;
u8 bt_prio_boost;
- const bool bt_statistics;
u16 agg_time_limit;
u8 ampdu_factor;
u8 ampdu_density;
@@ -364,6 +260,7 @@ struct iwl_ht_params {
* @rx_with_siso_diversity: 1x1 device with rx antenna diversity
* @internal_wimax_coex: internal wifi/wimax combo device
* @iq_invert: I/Q inversion
+ * @disable_otp_refresh: disable OTP refresh current limit
*
* We enable the driver to be backward compatible wrt API version. The
* driver specifies which APIs it supports (with @ucode_api_max being the
@@ -398,8 +295,6 @@ struct iwl_cfg {
u16 eeprom_ver;
u16 eeprom_calib_ver;
const struct iwl_ops *ops;
- /* module based parameters which can be set from modprobe cmd */
- const struct iwl_mod_params *mod_params;
/* params not likely to change within a device family */
struct iwl_base_params *base_params;
/* params likely to change within a device family */
@@ -414,13 +309,13 @@ struct iwl_cfg {
const bool rx_with_siso_diversity;
const bool internal_wimax_coex;
const bool iq_invert;
+ const bool disable_otp_refresh;
};
/***************************
* L i b *
***************************/
-struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg);
int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params);
int iwl_mac_tx_last_beacon(struct ieee80211_hw *hw);
@@ -625,6 +520,8 @@ extern const struct dev_pm_ops iwl_pm_ops;
void iwl_dump_nic_error_log(struct iwl_priv *priv);
int iwl_dump_nic_event_log(struct iwl_priv *priv,
bool full_log, char **buf, bool display);
+void iwl_dump_csr(struct iwl_priv *priv);
+int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display);
#ifdef CONFIG_IWLWIFI_DEBUG
void iwl_print_rx_config_cmd(struct iwl_priv *priv,
struct iwl_rxon_context *ctx);
@@ -662,6 +559,7 @@ void iwlcore_free_geos(struct iwl_priv *priv);
#define STATUS_SCAN_HW 15
#define STATUS_POWER_PMI 16
#define STATUS_FW_ERROR 17
+#define STATUS_DEVICE_ENABLED 18
static inline int iwl_is_ready(struct iwl_priv *priv)
@@ -714,11 +612,6 @@ void iwl_apm_stop(struct iwl_priv *priv);
int iwl_apm_init(struct iwl_priv *priv);
int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
-static inline int iwl_send_rxon_assoc(struct iwl_priv *priv,
- struct iwl_rxon_context *ctx)
-{
- return priv->cfg->ops->hcmd->rxon_assoc(priv, ctx);
-}
static inline int iwlcore_commit_rxon(struct iwl_priv *priv,
struct iwl_rxon_context *ctx)
{
@@ -736,12 +629,10 @@ static inline bool iwl_advanced_bt_coexist(struct iwl_priv *priv)
priv->cfg->bt_params->advanced_bt_coexist;
}
-static inline bool iwl_bt_statistics(struct iwl_priv *priv)
-{
- return priv->cfg->bt_params && priv->cfg->bt_params->bt_statistics;
-}
-
extern bool bt_coex_active;
extern bool bt_siso_mode;
+
+void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand);
+
#endif /* __iwl_core_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index f52bc040bcbf..5ab90ba7a024 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 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
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -155,18 +155,10 @@
#define CSR_DBG_LINK_PWR_MGMT_REG (CSR_BASE+0x250)
/* Bits for CSR_HW_IF_CONFIG_REG */
-#define CSR49_HW_IF_CONFIG_REG_BIT_4965_R (0x00000010)
#define CSR_HW_IF_CONFIG_REG_MSK_BOARD_VER (0x00000C00)
#define CSR_HW_IF_CONFIG_REG_BIT_MAC_SI (0x00000100)
#define CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI (0x00000200)
-#define CSR39_HW_IF_CONFIG_REG_BIT_3945_MB (0x00000100)
-#define CSR39_HW_IF_CONFIG_REG_BIT_3945_MM (0x00000200)
-#define CSR39_HW_IF_CONFIG_REG_BIT_SKU_MRC (0x00000400)
-#define CSR39_HW_IF_CONFIG_REG_BIT_BOARD_TYPE (0x00000800)
-#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_A (0x00000000)
-#define CSR39_HW_IF_CONFIG_REG_BITS_SILICON_TYPE_B (0x00001000)
-
#define CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A (0x00080000)
#define CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM (0x00200000)
#define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */
@@ -186,7 +178,7 @@
#define CSR_INT_BIT_SW_ERR (1 << 25) /* uCode error */
#define CSR_INT_BIT_RF_KILL (1 << 7) /* HW RFKILL switch GP_CNTRL[27] toggled */
#define CSR_INT_BIT_CT_KILL (1 << 6) /* Critical temp (chip too hot) rfkill */
-#define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses, 3945 */
+#define CSR_INT_BIT_SW_RX (1 << 3) /* Rx, command responses */
#define CSR_INT_BIT_WAKEUP (1 << 1) /* NIC controller waking up (pwr mgmt) */
#define CSR_INT_BIT_ALIVE (1 << 0) /* uCode interrupts once it initializes */
@@ -202,29 +194,17 @@
/* interrupt flags in FH (flow handler) (PCI busmaster DMA) */
#define CSR_FH_INT_BIT_ERR (1 << 31) /* Error */
#define CSR_FH_INT_BIT_HI_PRIOR (1 << 30) /* High priority Rx, bypass coalescing */
-#define CSR39_FH_INT_BIT_RX_CHNL2 (1 << 18) /* Rx channel 2 (3945 only) */
#define CSR_FH_INT_BIT_RX_CHNL1 (1 << 17) /* Rx channel 1 */
#define CSR_FH_INT_BIT_RX_CHNL0 (1 << 16) /* Rx channel 0 */
-#define CSR39_FH_INT_BIT_TX_CHNL6 (1 << 6) /* Tx channel 6 (3945 only) */
#define CSR_FH_INT_BIT_TX_CHNL1 (1 << 1) /* Tx channel 1 */
#define CSR_FH_INT_BIT_TX_CHNL0 (1 << 0) /* Tx channel 0 */
-#define CSR39_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \
- CSR39_FH_INT_BIT_RX_CHNL2 | \
- CSR_FH_INT_BIT_RX_CHNL1 | \
- CSR_FH_INT_BIT_RX_CHNL0)
-
-
-#define CSR39_FH_INT_TX_MASK (CSR39_FH_INT_BIT_TX_CHNL6 | \
- CSR_FH_INT_BIT_TX_CHNL1 | \
- CSR_FH_INT_BIT_TX_CHNL0)
-
-#define CSR49_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \
- CSR_FH_INT_BIT_RX_CHNL1 | \
- CSR_FH_INT_BIT_RX_CHNL0)
+#define CSR_FH_INT_RX_MASK (CSR_FH_INT_BIT_HI_PRIOR | \
+ CSR_FH_INT_BIT_RX_CHNL1 | \
+ CSR_FH_INT_BIT_RX_CHNL0)
-#define CSR49_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL1 | \
- CSR_FH_INT_BIT_TX_CHNL0)
+#define CSR_FH_INT_TX_MASK (CSR_FH_INT_BIT_TX_CHNL1 | \
+ CSR_FH_INT_BIT_TX_CHNL0)
/* GPIO */
#define CSR_GPIO_IN_BIT_AUX_POWER (0x00000200)
@@ -268,7 +248,7 @@
* Indicates MAC (ucode processor, etc.) is powered up and can run.
* Internal resources are accessible.
* NOTE: This does not indicate that the processor is actually running.
- * NOTE: This does not indicate that 4965 or 3945 has completed
+ * NOTE: This does not indicate that device has completed
* init or post-power-down restore of internal SRAM memory.
* Use CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP as indication that
* SRAM is restored and uCode is in normal operation mode.
@@ -291,8 +271,6 @@
/* HW REV */
#define CSR_HW_REV_TYPE_MSK (0x00001F0)
-#define CSR_HW_REV_TYPE_3945 (0x00000D0)
-#define CSR_HW_REV_TYPE_4965 (0x0000000)
#define CSR_HW_REV_TYPE_5300 (0x0000020)
#define CSR_HW_REV_TYPE_5350 (0x0000030)
#define CSR_HW_REV_TYPE_5100 (0x0000050)
@@ -363,7 +341,7 @@
* 0: MAC_SLEEP
* uCode sets this when preparing a power-saving power-down.
* uCode resets this when power-up is complete and SRAM is sane.
- * NOTE: 3945/4965 saves internal SRAM data to host when powering down,
+ * NOTE: device saves internal SRAM data to host when powering down,
* and must restore this data after powering back up.
* MAC_SLEEP is the best indication that restore is complete.
* Later devices (5xxx/6xxx/1xxx) use non-volatile SRAM, and
@@ -394,7 +372,6 @@
#define CSR_LED_REG_TRUN_OFF (0x38)
/* ANA_PLL */
-#define CSR39_ANA_PLL_CFG_VAL (0x01000000)
#define CSR50_ANA_PLL_CFG_VAL (0x00880300)
/* HPET MEM debug */
diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h
index ebdea3be3ef9..2824ccbcc1fc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debug.h
+++ b/drivers/net/wireless/iwlwifi/iwl-debug.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project.
*
@@ -146,7 +146,6 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
#define IWL_DL_RX (1 << 24)
#define IWL_DL_ISR (1 << 25)
#define IWL_DL_HT (1 << 26)
-#define IWL_DL_IO (1 << 27)
/* 0xF0000000 - 0x10000000 */
#define IWL_DL_11H (1 << 28)
#define IWL_DL_STATS (1 << 29)
@@ -174,7 +173,6 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
IWL_DEBUG_LIMIT(p, IWL_DL_DROP, f, ## a)
#define IWL_DEBUG_AP(p, f, a...) IWL_DEBUG(p, IWL_DL_AP, f, ## a)
#define IWL_DEBUG_TXPOWER(p, f, a...) IWL_DEBUG(p, IWL_DL_TXPOWER, f, ## a)
-#define IWL_DEBUG_IO(p, f, a...) IWL_DEBUG(p, IWL_DL_IO, f, ## a)
#define IWL_DEBUG_RATE(p, f, a...) IWL_DEBUG(p, IWL_DL_RATE, f, ## a)
#define IWL_DEBUG_RATE_LIMIT(p, f, a...) \
IWL_DEBUG_LIMIT(p, IWL_DL_RATE, f, ## a)
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 8842411f1cf3..0e6a04b739ad 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -2,7 +2,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 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
@@ -39,6 +39,7 @@
#include "iwl-debug.h"
#include "iwl-core.h"
#include "iwl-io.h"
+#include "iwl-agn.h"
/* create and remove of files */
#define DEBUGFS_ADD_FILE(name, parent, mode) do { \
@@ -226,10 +227,10 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
/* default is to dump the entire data segment */
if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) {
priv->dbgfs_sram_offset = 0x800000;
- if (priv->ucode_type == UCODE_INIT)
- priv->dbgfs_sram_len = priv->ucode_init_data.len;
+ if (priv->ucode_type == UCODE_SUBTYPE_INIT)
+ priv->dbgfs_sram_len = priv->ucode_init.data.len;
else
- priv->dbgfs_sram_len = priv->ucode_data.len;
+ priv->dbgfs_sram_len = priv->ucode_rt.data.len;
}
len = priv->dbgfs_sram_len;
@@ -437,8 +438,7 @@ static ssize_t iwl_dbgfs_log_event_read(struct file *file,
int pos = 0;
ssize_t ret = -ENOMEM;
- ret = pos = priv->cfg->ops->lib->dump_nic_event_log(
- priv, true, &buf, true);
+ ret = pos = iwl_dump_nic_event_log(priv, true, &buf, true);
if (buf) {
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
kfree(buf);
@@ -462,8 +462,7 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file,
if (sscanf(buf, "%d", &event_log_flag) != 1)
return -EFAULT;
if (event_log_flag == 1)
- priv->cfg->ops->lib->dump_nic_event_log(priv, true,
- NULL, false);
+ iwl_dump_nic_event_log(priv, true, NULL, false);
return count;
}
@@ -1039,13 +1038,463 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
+static const char *fmt_value = " %-30s %10u\n";
+static const char *fmt_hex = " %-30s 0x%02X\n";
+static const char *fmt_table = " %-30s %10u %10u %10u %10u\n";
+static const char *fmt_header =
+ "%-32s current cumulative delta max\n";
+
+static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
+{
+ int p = 0;
+ u32 flag;
+
+ flag = le32_to_cpu(priv->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;
+}
+
static ssize_t iwl_dbgfs_ucode_rx_stats_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct iwl_priv *priv = file->private_data;
- return priv->cfg->ops->lib->debugfs_ops.rx_stats_read(file,
- user_buf, count, ppos);
+ int pos = 0;
+ char *buf;
+ int bufsz = sizeof(struct statistics_rx_phy) * 40 +
+ sizeof(struct statistics_rx_non_phy) * 40 +
+ sizeof(struct statistics_rx_ht_phy) * 40 + 400;
+ ssize_t ret;
+ struct statistics_rx_phy *ofdm, *accum_ofdm, *delta_ofdm, *max_ofdm;
+ struct statistics_rx_phy *cck, *accum_cck, *delta_cck, *max_cck;
+ struct statistics_rx_non_phy *general, *accum_general;
+ struct statistics_rx_non_phy *delta_general, *max_general;
+ struct statistics_rx_ht_phy *ht, *accum_ht, *delta_ht, *max_ht;
+
+ if (!iwl_is_alive(priv))
+ 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
+ */
+ ofdm = &priv->statistics.rx_ofdm;
+ cck = &priv->statistics.rx_cck;
+ general = &priv->statistics.rx_non_phy;
+ ht = &priv->statistics.rx_ofdm_ht;
+ accum_ofdm = &priv->accum_stats.rx_ofdm;
+ accum_cck = &priv->accum_stats.rx_cck;
+ accum_general = &priv->accum_stats.rx_non_phy;
+ accum_ht = &priv->accum_stats.rx_ofdm_ht;
+ delta_ofdm = &priv->delta_stats.rx_ofdm;
+ delta_cck = &priv->delta_stats.rx_cck;
+ delta_general = &priv->delta_stats.rx_non_phy;
+ delta_ht = &priv->delta_stats.rx_ofdm_ht;
+ max_ofdm = &priv->max_delta_stats.rx_ofdm;
+ max_cck = &priv->max_delta_stats.rx_cck;
+ max_general = &priv->max_delta_stats.rx_non_phy;
+ max_ht = &priv->max_delta_stats.rx_ofdm_ht;
+
+ pos += iwl_statistics_flag(priv, buf, bufsz);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_header, "Statistics_Rx - OFDM:");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "ina_cnt:",
+ le32_to_cpu(ofdm->ina_cnt),
+ accum_ofdm->ina_cnt,
+ delta_ofdm->ina_cnt, max_ofdm->ina_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "fina_cnt:",
+ le32_to_cpu(ofdm->fina_cnt), accum_ofdm->fina_cnt,
+ delta_ofdm->fina_cnt, max_ofdm->fina_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "plcp_err:",
+ le32_to_cpu(ofdm->plcp_err), accum_ofdm->plcp_err,
+ delta_ofdm->plcp_err, max_ofdm->plcp_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "crc32_err:",
+ le32_to_cpu(ofdm->crc32_err), accum_ofdm->crc32_err,
+ delta_ofdm->crc32_err, max_ofdm->crc32_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "overrun_err:",
+ le32_to_cpu(ofdm->overrun_err),
+ accum_ofdm->overrun_err, delta_ofdm->overrun_err,
+ max_ofdm->overrun_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "early_overrun_err:",
+ le32_to_cpu(ofdm->early_overrun_err),
+ accum_ofdm->early_overrun_err,
+ delta_ofdm->early_overrun_err,
+ max_ofdm->early_overrun_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "crc32_good:",
+ le32_to_cpu(ofdm->crc32_good),
+ accum_ofdm->crc32_good, delta_ofdm->crc32_good,
+ max_ofdm->crc32_good);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "false_alarm_cnt:",
+ le32_to_cpu(ofdm->false_alarm_cnt),
+ accum_ofdm->false_alarm_cnt,
+ delta_ofdm->false_alarm_cnt,
+ max_ofdm->false_alarm_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "fina_sync_err_cnt:",
+ le32_to_cpu(ofdm->fina_sync_err_cnt),
+ accum_ofdm->fina_sync_err_cnt,
+ delta_ofdm->fina_sync_err_cnt,
+ max_ofdm->fina_sync_err_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "sfd_timeout:",
+ le32_to_cpu(ofdm->sfd_timeout),
+ accum_ofdm->sfd_timeout, delta_ofdm->sfd_timeout,
+ max_ofdm->sfd_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "fina_timeout:",
+ le32_to_cpu(ofdm->fina_timeout),
+ accum_ofdm->fina_timeout, delta_ofdm->fina_timeout,
+ max_ofdm->fina_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "unresponded_rts:",
+ le32_to_cpu(ofdm->unresponded_rts),
+ accum_ofdm->unresponded_rts,
+ delta_ofdm->unresponded_rts,
+ max_ofdm->unresponded_rts);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "rxe_frame_lmt_ovrun:",
+ le32_to_cpu(ofdm->rxe_frame_limit_overrun),
+ accum_ofdm->rxe_frame_limit_overrun,
+ delta_ofdm->rxe_frame_limit_overrun,
+ max_ofdm->rxe_frame_limit_overrun);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "sent_ack_cnt:",
+ le32_to_cpu(ofdm->sent_ack_cnt),
+ accum_ofdm->sent_ack_cnt, delta_ofdm->sent_ack_cnt,
+ max_ofdm->sent_ack_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "sent_cts_cnt:",
+ le32_to_cpu(ofdm->sent_cts_cnt),
+ accum_ofdm->sent_cts_cnt, delta_ofdm->sent_cts_cnt,
+ max_ofdm->sent_cts_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "sent_ba_rsp_cnt:",
+ le32_to_cpu(ofdm->sent_ba_rsp_cnt),
+ accum_ofdm->sent_ba_rsp_cnt,
+ delta_ofdm->sent_ba_rsp_cnt,
+ max_ofdm->sent_ba_rsp_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "dsp_self_kill:",
+ le32_to_cpu(ofdm->dsp_self_kill),
+ accum_ofdm->dsp_self_kill,
+ delta_ofdm->dsp_self_kill,
+ max_ofdm->dsp_self_kill);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "mh_format_err:",
+ le32_to_cpu(ofdm->mh_format_err),
+ accum_ofdm->mh_format_err,
+ delta_ofdm->mh_format_err,
+ max_ofdm->mh_format_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "re_acq_main_rssi_sum:",
+ le32_to_cpu(ofdm->re_acq_main_rssi_sum),
+ accum_ofdm->re_acq_main_rssi_sum,
+ delta_ofdm->re_acq_main_rssi_sum,
+ max_ofdm->re_acq_main_rssi_sum);
+
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_header, "Statistics_Rx - CCK:");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "ina_cnt:",
+ le32_to_cpu(cck->ina_cnt), accum_cck->ina_cnt,
+ delta_cck->ina_cnt, max_cck->ina_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "fina_cnt:",
+ le32_to_cpu(cck->fina_cnt), accum_cck->fina_cnt,
+ delta_cck->fina_cnt, max_cck->fina_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "plcp_err:",
+ le32_to_cpu(cck->plcp_err), accum_cck->plcp_err,
+ delta_cck->plcp_err, max_cck->plcp_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "crc32_err:",
+ le32_to_cpu(cck->crc32_err), accum_cck->crc32_err,
+ delta_cck->crc32_err, max_cck->crc32_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "overrun_err:",
+ le32_to_cpu(cck->overrun_err),
+ accum_cck->overrun_err, delta_cck->overrun_err,
+ max_cck->overrun_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "early_overrun_err:",
+ le32_to_cpu(cck->early_overrun_err),
+ accum_cck->early_overrun_err,
+ delta_cck->early_overrun_err,
+ max_cck->early_overrun_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "crc32_good:",
+ le32_to_cpu(cck->crc32_good), accum_cck->crc32_good,
+ delta_cck->crc32_good, max_cck->crc32_good);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "false_alarm_cnt:",
+ le32_to_cpu(cck->false_alarm_cnt),
+ accum_cck->false_alarm_cnt,
+ delta_cck->false_alarm_cnt, max_cck->false_alarm_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "fina_sync_err_cnt:",
+ le32_to_cpu(cck->fina_sync_err_cnt),
+ accum_cck->fina_sync_err_cnt,
+ delta_cck->fina_sync_err_cnt,
+ max_cck->fina_sync_err_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "sfd_timeout:",
+ le32_to_cpu(cck->sfd_timeout),
+ accum_cck->sfd_timeout, delta_cck->sfd_timeout,
+ max_cck->sfd_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "fina_timeout:",
+ le32_to_cpu(cck->fina_timeout),
+ accum_cck->fina_timeout, delta_cck->fina_timeout,
+ max_cck->fina_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "unresponded_rts:",
+ le32_to_cpu(cck->unresponded_rts),
+ accum_cck->unresponded_rts, delta_cck->unresponded_rts,
+ max_cck->unresponded_rts);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "rxe_frame_lmt_ovrun:",
+ le32_to_cpu(cck->rxe_frame_limit_overrun),
+ accum_cck->rxe_frame_limit_overrun,
+ delta_cck->rxe_frame_limit_overrun,
+ max_cck->rxe_frame_limit_overrun);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "sent_ack_cnt:",
+ le32_to_cpu(cck->sent_ack_cnt),
+ accum_cck->sent_ack_cnt, delta_cck->sent_ack_cnt,
+ max_cck->sent_ack_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "sent_cts_cnt:",
+ le32_to_cpu(cck->sent_cts_cnt),
+ accum_cck->sent_cts_cnt, delta_cck->sent_cts_cnt,
+ max_cck->sent_cts_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "sent_ba_rsp_cnt:",
+ le32_to_cpu(cck->sent_ba_rsp_cnt),
+ accum_cck->sent_ba_rsp_cnt,
+ delta_cck->sent_ba_rsp_cnt,
+ max_cck->sent_ba_rsp_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "dsp_self_kill:",
+ le32_to_cpu(cck->dsp_self_kill),
+ accum_cck->dsp_self_kill, delta_cck->dsp_self_kill,
+ max_cck->dsp_self_kill);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "mh_format_err:",
+ le32_to_cpu(cck->mh_format_err),
+ accum_cck->mh_format_err, delta_cck->mh_format_err,
+ max_cck->mh_format_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "re_acq_main_rssi_sum:",
+ le32_to_cpu(cck->re_acq_main_rssi_sum),
+ accum_cck->re_acq_main_rssi_sum,
+ delta_cck->re_acq_main_rssi_sum,
+ max_cck->re_acq_main_rssi_sum);
+
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_header, "Statistics_Rx - GENERAL:");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "bogus_cts:",
+ le32_to_cpu(general->bogus_cts),
+ accum_general->bogus_cts, delta_general->bogus_cts,
+ max_general->bogus_cts);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "bogus_ack:",
+ le32_to_cpu(general->bogus_ack),
+ accum_general->bogus_ack, delta_general->bogus_ack,
+ max_general->bogus_ack);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "non_bssid_frames:",
+ le32_to_cpu(general->non_bssid_frames),
+ accum_general->non_bssid_frames,
+ delta_general->non_bssid_frames,
+ max_general->non_bssid_frames);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "filtered_frames:",
+ le32_to_cpu(general->filtered_frames),
+ accum_general->filtered_frames,
+ delta_general->filtered_frames,
+ max_general->filtered_frames);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "non_channel_beacons:",
+ le32_to_cpu(general->non_channel_beacons),
+ accum_general->non_channel_beacons,
+ delta_general->non_channel_beacons,
+ max_general->non_channel_beacons);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "channel_beacons:",
+ le32_to_cpu(general->channel_beacons),
+ accum_general->channel_beacons,
+ delta_general->channel_beacons,
+ max_general->channel_beacons);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "num_missed_bcon:",
+ le32_to_cpu(general->num_missed_bcon),
+ accum_general->num_missed_bcon,
+ delta_general->num_missed_bcon,
+ max_general->num_missed_bcon);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "adc_rx_saturation_time:",
+ le32_to_cpu(general->adc_rx_saturation_time),
+ accum_general->adc_rx_saturation_time,
+ delta_general->adc_rx_saturation_time,
+ max_general->adc_rx_saturation_time);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "ina_detect_search_tm:",
+ le32_to_cpu(general->ina_detection_search_time),
+ accum_general->ina_detection_search_time,
+ delta_general->ina_detection_search_time,
+ max_general->ina_detection_search_time);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "beacon_silence_rssi_a:",
+ le32_to_cpu(general->beacon_silence_rssi_a),
+ accum_general->beacon_silence_rssi_a,
+ delta_general->beacon_silence_rssi_a,
+ max_general->beacon_silence_rssi_a);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "beacon_silence_rssi_b:",
+ le32_to_cpu(general->beacon_silence_rssi_b),
+ accum_general->beacon_silence_rssi_b,
+ delta_general->beacon_silence_rssi_b,
+ max_general->beacon_silence_rssi_b);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "beacon_silence_rssi_c:",
+ le32_to_cpu(general->beacon_silence_rssi_c),
+ accum_general->beacon_silence_rssi_c,
+ delta_general->beacon_silence_rssi_c,
+ max_general->beacon_silence_rssi_c);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "interference_data_flag:",
+ le32_to_cpu(general->interference_data_flag),
+ accum_general->interference_data_flag,
+ delta_general->interference_data_flag,
+ max_general->interference_data_flag);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "channel_load:",
+ le32_to_cpu(general->channel_load),
+ accum_general->channel_load,
+ delta_general->channel_load,
+ max_general->channel_load);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "dsp_false_alarms:",
+ le32_to_cpu(general->dsp_false_alarms),
+ accum_general->dsp_false_alarms,
+ delta_general->dsp_false_alarms,
+ max_general->dsp_false_alarms);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "beacon_rssi_a:",
+ le32_to_cpu(general->beacon_rssi_a),
+ accum_general->beacon_rssi_a,
+ delta_general->beacon_rssi_a,
+ max_general->beacon_rssi_a);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "beacon_rssi_b:",
+ le32_to_cpu(general->beacon_rssi_b),
+ accum_general->beacon_rssi_b,
+ delta_general->beacon_rssi_b,
+ max_general->beacon_rssi_b);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "beacon_rssi_c:",
+ le32_to_cpu(general->beacon_rssi_c),
+ accum_general->beacon_rssi_c,
+ delta_general->beacon_rssi_c,
+ max_general->beacon_rssi_c);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "beacon_energy_a:",
+ le32_to_cpu(general->beacon_energy_a),
+ accum_general->beacon_energy_a,
+ delta_general->beacon_energy_a,
+ max_general->beacon_energy_a);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "beacon_energy_b:",
+ le32_to_cpu(general->beacon_energy_b),
+ accum_general->beacon_energy_b,
+ delta_general->beacon_energy_b,
+ max_general->beacon_energy_b);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "beacon_energy_c:",
+ le32_to_cpu(general->beacon_energy_c),
+ accum_general->beacon_energy_c,
+ delta_general->beacon_energy_c,
+ max_general->beacon_energy_c);
+
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_header, "Statistics_Rx - OFDM_HT:");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "plcp_err:",
+ le32_to_cpu(ht->plcp_err), accum_ht->plcp_err,
+ delta_ht->plcp_err, max_ht->plcp_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "overrun_err:",
+ le32_to_cpu(ht->overrun_err), accum_ht->overrun_err,
+ delta_ht->overrun_err, max_ht->overrun_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "early_overrun_err:",
+ le32_to_cpu(ht->early_overrun_err),
+ accum_ht->early_overrun_err,
+ delta_ht->early_overrun_err,
+ max_ht->early_overrun_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "crc32_good:",
+ le32_to_cpu(ht->crc32_good), accum_ht->crc32_good,
+ delta_ht->crc32_good, max_ht->crc32_good);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "crc32_err:",
+ le32_to_cpu(ht->crc32_err), accum_ht->crc32_err,
+ delta_ht->crc32_err, max_ht->crc32_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "mh_format_err:",
+ le32_to_cpu(ht->mh_format_err),
+ accum_ht->mh_format_err,
+ delta_ht->mh_format_err, max_ht->mh_format_err);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "agg_crc32_good:",
+ le32_to_cpu(ht->agg_crc32_good),
+ accum_ht->agg_crc32_good,
+ delta_ht->agg_crc32_good, max_ht->agg_crc32_good);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "agg_mpdu_cnt:",
+ le32_to_cpu(ht->agg_mpdu_cnt),
+ accum_ht->agg_mpdu_cnt,
+ delta_ht->agg_mpdu_cnt, max_ht->agg_mpdu_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "agg_cnt:",
+ le32_to_cpu(ht->agg_cnt), accum_ht->agg_cnt,
+ delta_ht->agg_cnt, max_ht->agg_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "unsupport_mcs:",
+ le32_to_cpu(ht->unsupport_mcs),
+ accum_ht->unsupport_mcs,
+ delta_ht->unsupport_mcs, max_ht->unsupport_mcs);
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ kfree(buf);
+ return ret;
}
static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
@@ -1053,8 +1502,190 @@ static ssize_t iwl_dbgfs_ucode_tx_stats_read(struct file *file,
size_t count, loff_t *ppos)
{
struct iwl_priv *priv = file->private_data;
- return priv->cfg->ops->lib->debugfs_ops.tx_stats_read(file,
- user_buf, count, ppos);
+ int pos = 0;
+ char *buf;
+ int bufsz = (sizeof(struct statistics_tx) * 48) + 250;
+ ssize_t ret;
+ struct statistics_tx *tx, *accum_tx, *delta_tx, *max_tx;
+
+ if (!iwl_is_alive(priv))
+ 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
+ */
+ tx = &priv->statistics.tx;
+ accum_tx = &priv->accum_stats.tx;
+ delta_tx = &priv->delta_stats.tx;
+ max_tx = &priv->max_delta_stats.tx;
+
+ pos += iwl_statistics_flag(priv, buf, bufsz);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_header, "Statistics_Tx:");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "preamble:",
+ le32_to_cpu(tx->preamble_cnt),
+ accum_tx->preamble_cnt,
+ delta_tx->preamble_cnt, max_tx->preamble_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "rx_detected_cnt:",
+ le32_to_cpu(tx->rx_detected_cnt),
+ accum_tx->rx_detected_cnt,
+ delta_tx->rx_detected_cnt, max_tx->rx_detected_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "bt_prio_defer_cnt:",
+ le32_to_cpu(tx->bt_prio_defer_cnt),
+ accum_tx->bt_prio_defer_cnt,
+ delta_tx->bt_prio_defer_cnt,
+ max_tx->bt_prio_defer_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "bt_prio_kill_cnt:",
+ le32_to_cpu(tx->bt_prio_kill_cnt),
+ accum_tx->bt_prio_kill_cnt,
+ delta_tx->bt_prio_kill_cnt,
+ max_tx->bt_prio_kill_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "few_bytes_cnt:",
+ le32_to_cpu(tx->few_bytes_cnt),
+ accum_tx->few_bytes_cnt,
+ delta_tx->few_bytes_cnt, max_tx->few_bytes_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "cts_timeout:",
+ le32_to_cpu(tx->cts_timeout), accum_tx->cts_timeout,
+ delta_tx->cts_timeout, max_tx->cts_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "ack_timeout:",
+ le32_to_cpu(tx->ack_timeout),
+ accum_tx->ack_timeout,
+ delta_tx->ack_timeout, max_tx->ack_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "expected_ack_cnt:",
+ le32_to_cpu(tx->expected_ack_cnt),
+ accum_tx->expected_ack_cnt,
+ delta_tx->expected_ack_cnt,
+ max_tx->expected_ack_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "actual_ack_cnt:",
+ le32_to_cpu(tx->actual_ack_cnt),
+ accum_tx->actual_ack_cnt,
+ delta_tx->actual_ack_cnt,
+ max_tx->actual_ack_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "dump_msdu_cnt:",
+ le32_to_cpu(tx->dump_msdu_cnt),
+ accum_tx->dump_msdu_cnt,
+ delta_tx->dump_msdu_cnt,
+ max_tx->dump_msdu_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "abort_nxt_frame_mismatch:",
+ le32_to_cpu(tx->burst_abort_next_frame_mismatch_cnt),
+ accum_tx->burst_abort_next_frame_mismatch_cnt,
+ delta_tx->burst_abort_next_frame_mismatch_cnt,
+ max_tx->burst_abort_next_frame_mismatch_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "abort_missing_nxt_frame:",
+ le32_to_cpu(tx->burst_abort_missing_next_frame_cnt),
+ accum_tx->burst_abort_missing_next_frame_cnt,
+ delta_tx->burst_abort_missing_next_frame_cnt,
+ max_tx->burst_abort_missing_next_frame_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "cts_timeout_collision:",
+ le32_to_cpu(tx->cts_timeout_collision),
+ accum_tx->cts_timeout_collision,
+ delta_tx->cts_timeout_collision,
+ max_tx->cts_timeout_collision);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "ack_ba_timeout_collision:",
+ le32_to_cpu(tx->ack_or_ba_timeout_collision),
+ accum_tx->ack_or_ba_timeout_collision,
+ delta_tx->ack_or_ba_timeout_collision,
+ max_tx->ack_or_ba_timeout_collision);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "agg ba_timeout:",
+ le32_to_cpu(tx->agg.ba_timeout),
+ accum_tx->agg.ba_timeout,
+ delta_tx->agg.ba_timeout,
+ max_tx->agg.ba_timeout);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "agg ba_resched_frames:",
+ le32_to_cpu(tx->agg.ba_reschedule_frames),
+ accum_tx->agg.ba_reschedule_frames,
+ delta_tx->agg.ba_reschedule_frames,
+ max_tx->agg.ba_reschedule_frames);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "agg scd_query_agg_frame:",
+ le32_to_cpu(tx->agg.scd_query_agg_frame_cnt),
+ accum_tx->agg.scd_query_agg_frame_cnt,
+ delta_tx->agg.scd_query_agg_frame_cnt,
+ max_tx->agg.scd_query_agg_frame_cnt);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "agg scd_query_no_agg:",
+ le32_to_cpu(tx->agg.scd_query_no_agg),
+ accum_tx->agg.scd_query_no_agg,
+ delta_tx->agg.scd_query_no_agg,
+ max_tx->agg.scd_query_no_agg);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "agg scd_query_agg:",
+ le32_to_cpu(tx->agg.scd_query_agg),
+ accum_tx->agg.scd_query_agg,
+ delta_tx->agg.scd_query_agg,
+ max_tx->agg.scd_query_agg);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "agg scd_query_mismatch:",
+ le32_to_cpu(tx->agg.scd_query_mismatch),
+ accum_tx->agg.scd_query_mismatch,
+ delta_tx->agg.scd_query_mismatch,
+ max_tx->agg.scd_query_mismatch);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "agg frame_not_ready:",
+ le32_to_cpu(tx->agg.frame_not_ready),
+ accum_tx->agg.frame_not_ready,
+ delta_tx->agg.frame_not_ready,
+ max_tx->agg.frame_not_ready);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "agg underrun:",
+ le32_to_cpu(tx->agg.underrun),
+ accum_tx->agg.underrun,
+ delta_tx->agg.underrun, max_tx->agg.underrun);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "agg bt_prio_kill:",
+ le32_to_cpu(tx->agg.bt_prio_kill),
+ accum_tx->agg.bt_prio_kill,
+ delta_tx->agg.bt_prio_kill,
+ max_tx->agg.bt_prio_kill);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "agg rx_ba_rsp_cnt:",
+ le32_to_cpu(tx->agg.rx_ba_rsp_cnt),
+ accum_tx->agg.rx_ba_rsp_cnt,
+ delta_tx->agg.rx_ba_rsp_cnt,
+ max_tx->agg.rx_ba_rsp_cnt);
+
+ if (tx->tx_power.ant_a || tx->tx_power.ant_b || tx->tx_power.ant_c) {
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "tx power: (1/2 dB step)\n");
+ if ((priv->cfg->valid_tx_ant & ANT_A) && tx->tx_power.ant_a)
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_hex, "antenna A:",
+ tx->tx_power.ant_a);
+ if ((priv->cfg->valid_tx_ant & ANT_B) && tx->tx_power.ant_b)
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_hex, "antenna B:",
+ tx->tx_power.ant_b);
+ if ((priv->cfg->valid_tx_ant & ANT_C) && tx->tx_power.ant_c)
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_hex, "antenna C:",
+ tx->tx_power.ant_c);
+ }
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ kfree(buf);
+ return ret;
}
static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
@@ -1062,8 +1693,347 @@ static ssize_t iwl_dbgfs_ucode_general_stats_read(struct file *file,
size_t count, loff_t *ppos)
{
struct iwl_priv *priv = file->private_data;
- return priv->cfg->ops->lib->debugfs_ops.general_stats_read(file,
- user_buf, count, ppos);
+ int pos = 0;
+ char *buf;
+ int bufsz = sizeof(struct statistics_general) * 10 + 300;
+ ssize_t ret;
+ 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;
+
+ if (!iwl_is_alive(priv))
+ 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
+ */
+ general = &priv->statistics.common;
+ dbg = &priv->statistics.common.dbg;
+ div = &priv->statistics.common.div;
+ accum_general = &priv->accum_stats.common;
+ accum_dbg = &priv->accum_stats.common.dbg;
+ accum_div = &priv->accum_stats.common.div;
+ delta_general = &priv->delta_stats.common;
+ max_general = &priv->max_delta_stats.common;
+ delta_dbg = &priv->delta_stats.common.dbg;
+ max_dbg = &priv->max_delta_stats.common.dbg;
+ delta_div = &priv->delta_stats.common.div;
+ max_div = &priv->max_delta_stats.common.div;
+
+ pos += iwl_statistics_flag(priv, buf, bufsz);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_header, "Statistics_General:");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_value, "temperature:",
+ le32_to_cpu(general->temperature));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_value, "temperature_m:",
+ le32_to_cpu(general->temperature_m));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_value, "ttl_timestamp:",
+ le32_to_cpu(general->ttl_timestamp));
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "burst_check:",
+ le32_to_cpu(dbg->burst_check),
+ accum_dbg->burst_check,
+ delta_dbg->burst_check, max_dbg->burst_check);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "burst_count:",
+ le32_to_cpu(dbg->burst_count),
+ accum_dbg->burst_count,
+ delta_dbg->burst_count, max_dbg->burst_count);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "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,
+ fmt_table, "sleep_time:",
+ le32_to_cpu(general->sleep_time),
+ accum_general->sleep_time,
+ delta_general->sleep_time, max_general->sleep_time);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "slots_out:",
+ le32_to_cpu(general->slots_out),
+ accum_general->slots_out,
+ delta_general->slots_out, max_general->slots_out);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "slots_idle:",
+ le32_to_cpu(general->slots_idle),
+ accum_general->slots_idle,
+ delta_general->slots_idle, max_general->slots_idle);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "tx_on_a:",
+ le32_to_cpu(div->tx_on_a), accum_div->tx_on_a,
+ delta_div->tx_on_a, max_div->tx_on_a);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "tx_on_b:",
+ le32_to_cpu(div->tx_on_b), accum_div->tx_on_b,
+ delta_div->tx_on_b, max_div->tx_on_b);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "exec_time:",
+ le32_to_cpu(div->exec_time), accum_div->exec_time,
+ delta_div->exec_time, max_div->exec_time);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "probe_time:",
+ le32_to_cpu(div->probe_time), accum_div->probe_time,
+ delta_div->probe_time, max_div->probe_time);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "rx_enable_counter:",
+ le32_to_cpu(general->rx_enable_counter),
+ accum_general->rx_enable_counter,
+ delta_general->rx_enable_counter,
+ max_general->rx_enable_counter);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ fmt_table, "num_of_sos_states:",
+ le32_to_cpu(general->num_of_sos_states),
+ accum_general->num_of_sos_states,
+ delta_general->num_of_sos_states,
+ max_general->num_of_sos_states);
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ kfree(buf);
+ return ret;
+}
+
+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;
+ 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;
+
+ if (!priv->bt_enable_flag)
+ return -EINVAL;
+
+ /* 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->statistics.bt_activity;
+ accum_bt = &priv->accum_stats.bt_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_tx_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->statistics.num_bt_kills),
+ priv->statistics.accum_num_bt_kills);
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ kfree(buf);
+ return ret;
+}
+
+static ssize_t iwl_dbgfs_reply_tx_error_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 reply_tx_error_statistics) * 24) +
+ (sizeof(struct reply_agg_tx_error_statistics) * 24) + 200;
+ ssize_t ret;
+
+ if (!iwl_is_alive(priv))
+ return -EAGAIN;
+
+ buf = kzalloc(bufsz, GFP_KERNEL);
+ if (!buf) {
+ IWL_ERR(priv, "Can not allocate Buffer\n");
+ return -ENOMEM;
+ }
+
+ pos += scnprintf(buf + pos, bufsz - pos, "Statistics_TX_Error:\n");
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_DELAY),
+ priv->_agn.reply_tx_stats.pp_delay);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_FEW_BYTES),
+ priv->_agn.reply_tx_stats.pp_few_bytes);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_BT_PRIO),
+ priv->_agn.reply_tx_stats.pp_bt_prio);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_QUIET_PERIOD),
+ priv->_agn.reply_tx_stats.pp_quiet_period);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_POSTPONE_CALC_TTAK),
+ priv->_agn.reply_tx_stats.pp_calc_ttak);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+ iwl_get_tx_fail_reason(
+ TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY),
+ priv->_agn.reply_tx_stats.int_crossed_retry);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_SHORT_LIMIT),
+ priv->_agn.reply_tx_stats.short_limit);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_LONG_LIMIT),
+ priv->_agn.reply_tx_stats.long_limit);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_UNDERRUN),
+ priv->_agn.reply_tx_stats.fifo_underrun);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_DRAIN_FLOW),
+ priv->_agn.reply_tx_stats.drain_flow);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_RFKILL_FLUSH),
+ priv->_agn.reply_tx_stats.rfkill_flush);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_LIFE_EXPIRE),
+ priv->_agn.reply_tx_stats.life_expire);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_DEST_PS),
+ priv->_agn.reply_tx_stats.dest_ps);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_HOST_ABORTED),
+ priv->_agn.reply_tx_stats.host_abort);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_BT_RETRY),
+ priv->_agn.reply_tx_stats.pp_delay);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_STA_INVALID),
+ priv->_agn.reply_tx_stats.sta_invalid);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_FRAG_DROPPED),
+ priv->_agn.reply_tx_stats.frag_drop);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_TID_DISABLE),
+ priv->_agn.reply_tx_stats.tid_disable);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_FIFO_FLUSHED),
+ priv->_agn.reply_tx_stats.fifo_flush);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+ iwl_get_tx_fail_reason(
+ TX_STATUS_FAIL_INSUFFICIENT_CF_POLL),
+ priv->_agn.reply_tx_stats.insuff_cf_poll);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_tx_fail_reason(TX_STATUS_FAIL_PASSIVE_NO_RX),
+ priv->_agn.reply_tx_stats.fail_hw_drop);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+ iwl_get_tx_fail_reason(
+ TX_STATUS_FAIL_NO_BEACON_ON_RADAR),
+ priv->_agn.reply_tx_stats.sta_color_mismatch);
+ pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n",
+ priv->_agn.reply_tx_stats.unknown);
+
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "\nStatistics_Agg_TX_Error:\n");
+
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_agg_tx_fail_reason(AGG_TX_STATE_UNDERRUN_MSK),
+ priv->_agn.reply_agg_tx_stats.underrun);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_agg_tx_fail_reason(AGG_TX_STATE_BT_PRIO_MSK),
+ priv->_agn.reply_agg_tx_stats.bt_prio);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_agg_tx_fail_reason(AGG_TX_STATE_FEW_BYTES_MSK),
+ priv->_agn.reply_agg_tx_stats.few_bytes);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_agg_tx_fail_reason(AGG_TX_STATE_ABORT_MSK),
+ priv->_agn.reply_agg_tx_stats.abort);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+ iwl_get_agg_tx_fail_reason(
+ AGG_TX_STATE_LAST_SENT_TTL_MSK),
+ priv->_agn.reply_agg_tx_stats.last_sent_ttl);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+ iwl_get_agg_tx_fail_reason(
+ AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK),
+ priv->_agn.reply_agg_tx_stats.last_sent_try);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+ iwl_get_agg_tx_fail_reason(
+ AGG_TX_STATE_LAST_SENT_BT_KILL_MSK),
+ priv->_agn.reply_agg_tx_stats.last_sent_bt_kill);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_agg_tx_fail_reason(AGG_TX_STATE_SCD_QUERY_MSK),
+ priv->_agn.reply_agg_tx_stats.scd_query);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t%u\n",
+ iwl_get_agg_tx_fail_reason(
+ AGG_TX_STATE_TEST_BAD_CRC32_MSK),
+ priv->_agn.reply_agg_tx_stats.bad_crc32);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_agg_tx_fail_reason(AGG_TX_STATE_RESPONSE_MSK),
+ priv->_agn.reply_agg_tx_stats.response);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DUMP_TX_MSK),
+ priv->_agn.reply_agg_tx_stats.dump_tx);
+ pos += scnprintf(buf + pos, bufsz - pos, "%s:\t\t\t%u\n",
+ iwl_get_agg_tx_fail_reason(AGG_TX_STATE_DELAY_TX_MSK),
+ priv->_agn.reply_agg_tx_stats.delay_tx);
+ pos += scnprintf(buf + pos, bufsz - pos, "UNKNOWN:\t\t\t%u\n",
+ priv->_agn.reply_agg_tx_stats.unknown);
+
+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+ kfree(buf);
+ return ret;
}
static ssize_t iwl_dbgfs_sensitivity_read(struct file *file,
@@ -1268,8 +2238,7 @@ static ssize_t iwl_dbgfs_csr_write(struct file *file,
if (sscanf(buf, "%d", &csr) != 1)
return -EFAULT;
- if (priv->cfg->ops->lib->dump_csr)
- priv->cfg->ops->lib->dump_csr(priv);
+ iwl_dump_csr(priv);
return count;
}
@@ -1359,13 +2328,11 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
int pos = 0;
ssize_t ret = -EFAULT;
- if (priv->cfg->ops->lib->dump_fh) {
- ret = pos = priv->cfg->ops->lib->dump_fh(priv, &buf, true);
- if (buf) {
- ret = simple_read_from_buffer(user_buf,
- count, ppos, buf, pos);
- kfree(buf);
- }
+ ret = pos = iwl_dump_fh(priv, &buf, true);
+ if (buf) {
+ ret = simple_read_from_buffer(user_buf,
+ count, ppos, buf, pos);
+ kfree(buf);
}
return ret;
@@ -1531,16 +2498,6 @@ static ssize_t iwl_dbgfs_txfifo_flush_write(struct file *file,
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);
-}
-
static ssize_t iwl_dbgfs_wd_timeout_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos) {
@@ -1572,12 +2529,10 @@ static ssize_t iwl_dbgfs_bt_traffic_read(struct file *file,
int pos = 0;
char buf[200];
const size_t bufsz = sizeof(buf);
- ssize_t ret;
if (!priv->bt_enable_flag) {
pos += scnprintf(buf + pos, bufsz - pos, "BT coex disabled\n");
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
- return ret;
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
pos += scnprintf(buf + pos, bufsz - pos, "BT enable flag: 0x%x\n",
priv->bt_enable_flag);
@@ -1608,8 +2563,7 @@ static ssize_t iwl_dbgfs_bt_traffic_read(struct file *file,
break;
}
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
- return ret;
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
static ssize_t iwl_dbgfs_protection_mode_read(struct file *file,
@@ -1658,18 +2612,6 @@ static ssize_t iwl_dbgfs_protection_mode_write(struct file *file,
return count;
}
-static ssize_t iwl_dbgfs_reply_tx_error_read(struct file *file,
- char __user *user_buf,
- size_t count, loff_t *ppos)
-{
- struct iwl_priv *priv = file->private_data;
-
- if (priv->cfg->ops->lib->debugfs_ops.reply_tx_error)
- return priv->cfg->ops->lib->debugfs_ops.reply_tx_error(
- file, user_buf, count, ppos);
- else
- return -ENODATA;
-}
DEBUGFS_READ_FILE_OPS(rx_statistics);
DEBUGFS_READ_FILE_OPS(tx_statistics);
DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
@@ -1731,11 +2673,8 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR);
DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR);
DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR);
- if (!priv->cfg->base_params->broken_powersave) {
- DEBUGFS_ADD_FILE(sleep_level_override, dir_data,
- S_IWUSR | S_IRUSR);
- DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR);
- }
+ DEBUGFS_ADD_FILE(sleep_level_override, dir_data, S_IWUSR | S_IRUSR);
+ DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR);
DEBUGFS_ADD_FILE(thermal_throttling, dir_data, S_IRUSR);
DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
DEBUGFS_ADD_FILE(rx_statistics, dir_debug, S_IRUSR);
@@ -1758,29 +2697,20 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, S_IWUSR);
DEBUGFS_ADD_FILE(protection_mode, dir_debug, S_IWUSR | S_IRUSR);
- if (priv->cfg->base_params->sensitivity_calib_by_driver)
- DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
- if (priv->cfg->base_params->chain_noise_calib_by_driver)
- DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
- if (priv->cfg->base_params->ucode_tracing)
- DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
- if (iwl_bt_statistics(priv))
- DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR);
+ DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
+ DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
+ DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
+ DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR);
DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, S_IRUSR);
DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR);
DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR);
DEBUGFS_ADD_FILE(wd_timeout, dir_debug, S_IWUSR);
if (iwl_advanced_bt_coexist(priv))
DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR);
- if (priv->cfg->base_params->sensitivity_calib_by_driver)
- DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf,
- &priv->disable_sens_cal);
- if (priv->cfg->base_params->chain_noise_calib_by_driver)
- DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
- &priv->disable_chain_noise_cal);
- if (priv->cfg->base_params->tx_power_by_driver)
- DEBUGFS_ADD_BOOL(disable_tx_power, dir_rf,
- &priv->disable_tx_power_cal);
+ DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf,
+ &priv->disable_sens_cal);
+ DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
+ &priv->disable_chain_noise_cal);
return 0;
err:
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 68b953f2bdc7..22a6e3ec7094 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 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
@@ -26,7 +26,6 @@
/*
* Please use this file (iwl-dev.h) for driver implementation definitions.
* Please use iwl-commands.h for uCode API definitions.
- * Please use iwl-4965-hw.h for hardware-related definitions.
*/
#ifndef __iwl_dev_h__
@@ -49,8 +48,6 @@
#include "iwl-agn-rs.h"
#include "iwl-agn-tt.h"
-#define U32_PAD(n) ((4-(n))&0x3)
-
struct iwl_tx_queue;
/* CT-KILL constants */
@@ -84,7 +81,7 @@ struct iwl_tx_queue;
#define MAX_RTS_THRESHOLD 2347U
#define MAX_MSDU_SIZE 2304U
#define MAX_MPDU_SIZE 2346U
-#define DEFAULT_BEACON_INTERVAL 100U
+#define DEFAULT_BEACON_INTERVAL 200U
#define DEFAULT_SHORT_RETRY_LIMIT 7U
#define DEFAULT_LONG_RETRY_LIMIT 4U
@@ -113,8 +110,6 @@ struct iwl_cmd_meta {
struct iwl_device_cmd *cmd,
struct iwl_rx_packet *pkt);
- /* The CMD_SIZE_HUGE flag bit indicates that the command
- * structure is stored at the end of the shared queue memory. */
u32 flags;
DEFINE_DMA_UNMAP_ADDR(mapping);
@@ -124,7 +119,23 @@ struct iwl_cmd_meta {
/*
* Generic queue structure
*
- * Contains common data for Rx and Tx queues
+ * Contains common data for Rx and Tx queues.
+ *
+ * Note the difference between n_bd and n_window: the hardware
+ * always assumes 256 descriptors, so n_bd is always 256 (unless
+ * there might be HW changes in the future). For the normal TX
+ * queues, n_window, which is the size of the software queue data
+ * is also 256; however, for the command queue, n_window is only
+ * 32 since we don't need so many commands pending. Since the HW
+ * still uses 256 BDs for DMA though, n_bd stays 256. As a result,
+ * the software buffers (in the variables @meta, @txb in struct
+ * iwl_tx_queue) only have 32 entries, while the HW buffers (@tfds
+ * in the same struct) have 256.
+ * This means that we end up with the following:
+ * HW entries: | 0 | ... | N * 32 | ... | N * 32 + 31 | ... | 255 |
+ * SW entries: | 0 | ... | 31 |
+ * where N is a number between 0 and 7. This means that the SW
+ * data is a window overlayed over the HW queue.
*/
struct iwl_queue {
int n_bd; /* number of BDs in this queue */
@@ -166,7 +177,7 @@ struct iwl_tx_info {
struct iwl_tx_queue {
struct iwl_queue q;
- void *tfds;
+ struct iwl_tfd *tfds;
struct iwl_device_cmd **cmd;
struct iwl_cmd_meta *meta;
struct iwl_tx_info *txb;
@@ -179,53 +190,12 @@ struct iwl_tx_queue {
#define IWL_NUM_SCAN_RATES (2)
-struct iwl4965_channel_tgd_info {
- u8 type;
- s8 max_power;
-};
-
-struct iwl4965_channel_tgh_info {
- s64 last_radar_time;
-};
-
-#define IWL4965_MAX_RATE (33)
-
-struct iwl3945_clip_group {
- /* maximum power level to prevent clipping for each rate, derived by
- * us from this band's saturation power in EEPROM */
- const s8 clip_powers[IWL_MAX_RATES];
-};
-
-/* current Tx power values to use, one for each rate for each channel.
- * requested power is limited by:
- * -- regulatory EEPROM limits for this channel
- * -- hardware capabilities (clip-powers)
- * -- spectrum management
- * -- user preference (e.g. iwconfig)
- * when requested power is set, base power index must also be set. */
-struct iwl3945_channel_power_info {
- struct iwl3945_tx_power tpc; /* actual radio and DSP gain settings */
- s8 power_table_index; /* actual (compenst'd) index into gain table */
- s8 base_power_index; /* gain index for power at factory temp. */
- s8 requested_power; /* power (dBm) requested for this chnl/rate */
-};
-
-/* current scan Tx power values to use, one for each scan rate for each
- * channel. */
-struct iwl3945_scan_power_info {
- struct iwl3945_tx_power tpc; /* actual radio and DSP gain settings */
- s8 power_table_index; /* actual (compenst'd) index into gain table */
- s8 requested_power; /* scan pwr (dBm) requested for chnl/rate */
-};
-
/*
* One for each channel, holds all channel setup data
* Some of the fields (e.g. eeprom and flags/max_power_avg) are redundant
* with one another!
*/
struct iwl_channel_info {
- struct iwl4965_channel_tgd_info tgd;
- struct iwl4965_channel_tgh_info tgh;
struct iwl_eeprom_channel eeprom; /* EEPROM regulatory limit */
struct iwl_eeprom_channel ht40_eeprom; /* EEPROM regulatory limit for
* HT40 channel */
@@ -245,14 +215,6 @@ struct iwl_channel_info {
s8 ht40_max_power_avg; /* (dBm) regul. eeprom, normal Tx, any rate */
u8 ht40_flags; /* flags copied from EEPROM */
u8 ht40_extension_channel; /* HT_IE_EXT_CHANNEL_* */
-
- /* Radio/DSP gain settings for each "normal" data Tx rate.
- * These include, in addition to RF and DSP gain, a few fields for
- * remembering/modifying gain settings (indexes). */
- struct iwl3945_channel_power_info power_info[IWL4965_MAX_RATE];
-
- /* Radio/DSP gain settings for each scan rate, for directed scans. */
- struct iwl3945_scan_power_info scan_pwr_info[IWL_NUM_SCAN_RATES];
};
#define IWL_TX_FIFO_BK 0 /* shared */
@@ -288,15 +250,6 @@ struct iwl_channel_info {
#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN)
#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN)
-struct iwl_frame {
- union {
- struct ieee80211_hdr frame;
- struct iwl_tx_beacon_cmd beacon;
- u8 raw[IEEE80211_FRAME_LEN];
- u8 cmd[360];
- } u;
- struct list_head list;
-};
#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
@@ -306,9 +259,9 @@ enum {
CMD_SYNC = 0,
CMD_SIZE_NORMAL = 0,
CMD_NO_SKB = 0,
- CMD_SIZE_HUGE = (1 << 0),
CMD_ASYNC = (1 << 1),
CMD_WANT_SKB = (1 << 2),
+ CMD_MAPPED = (1 << 3),
};
#define DEF_CMD_PAYLOAD_SIZE 320
@@ -317,8 +270,8 @@ enum {
* struct iwl_device_cmd
*
* For allocation of the command and tx queues, this establishes the overall
- * size of the largest command we send to uCode, except for a scan command
- * (which is relatively huge; space is allocated separately).
+ * size of the largest command we send to uCode, except for commands that
+ * aren't fully copied and use other TFD space.
*/
struct iwl_device_cmd {
struct iwl_cmd_header hdr; /* uCode API */
@@ -335,15 +288,21 @@ struct iwl_device_cmd {
#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd))
+#define IWL_MAX_CMD_TFDS 2
+
+enum iwl_hcmd_dataflag {
+ IWL_HCMD_DFL_NOCOPY = BIT(0),
+};
struct iwl_host_cmd {
- const void *data;
+ const void *data[IWL_MAX_CMD_TFDS];
unsigned long reply_page;
void (*callback)(struct iwl_priv *priv,
struct iwl_device_cmd *cmd,
struct iwl_rx_packet *pkt);
u32 flags;
- u16 len;
+ u16 len[IWL_MAX_CMD_TFDS];
+ u8 dataflags[IWL_MAX_CMD_TFDS];
u8 id;
};
@@ -416,6 +375,7 @@ struct iwl_ht_agg {
#define IWL_EMPTYING_HW_QUEUE_ADDBA 2
#define IWL_EMPTYING_HW_QUEUE_DELBA 3
u8 state;
+ u8 tx_fifo;
};
@@ -499,9 +459,6 @@ struct iwl_station_priv_common {
* When mac80211 creates a station it reserves some space (hw->sta_data_size)
* in the structure for use by driver. This structure is places in that
* space.
- *
- * The common struct MUST be first because it is shared between
- * 3945 and agn!
*/
struct iwl_station_priv {
struct iwl_station_priv_common common;
@@ -530,6 +487,10 @@ struct fw_desc {
u32 len; /* bytes */
};
+struct fw_img {
+ struct fw_desc code, data;
+};
+
/* v1/v2 uCode file layout */
struct iwl_ucode_header {
__le32 ver; /* major/minor/API/serial */
@@ -586,6 +547,22 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_INIT_ERRLOG_PTR = 13,
IWL_UCODE_TLV_ENHANCE_SENS_TBL = 14,
IWL_UCODE_TLV_PHY_CALIBRATION_SIZE = 15,
+ /* 16 and 17 reserved for future use */
+ IWL_UCODE_TLV_FLAGS = 18,
+};
+
+/**
+ * enum iwl_ucode_tlv_flag - ucode API flags
+ * @IWL_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously
+ * was a separate TLV but moved here to save space.
+ * @IWL_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID,
+ * treats good CRC threshold as a boolean
+ * @IWL_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w).
+ */
+enum iwl_ucode_tlv_flag {
+ IWL_UCODE_TLV_FLAGS_PAN = BIT(0),
+ IWL_UCODE_TLV_FLAGS_NEWSCAN = BIT(1),
+ IWL_UCODE_TLV_FLAGS_MFP = BIT(2),
};
struct iwl_ucode_tlv {
@@ -619,14 +596,6 @@ struct iwl_tlv_ucode_header {
u8 data[0];
};
-struct iwl4965_ibss_seq {
- u8 mac[ETH_ALEN];
- u16 seq_num;
- u16 frag_num;
- unsigned long packet_time;
- struct list_head list;
-};
-
struct iwl_sensitivity_ranges {
u16 min_nrg_cck;
u16 max_nrg_cck;
@@ -700,7 +669,6 @@ struct iwl_hw_params {
u8 max_beacon_itrvl; /* in 1024 ms */
u32 max_inst_size;
u32 max_data_size;
- u32 max_bsm_size;
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 */
@@ -722,8 +690,6 @@ struct iwl_hw_params {
* Naming convention --
* iwl_ <-- Is part of iwlwifi
* iwlXXXX_ <-- Hardware specific (implemented in iwl-XXXX.c for XXXX)
- * iwl4965_bg_ <-- Called from work queue context
- * iwl4965_mac_ <-- mac80211 callback
*
****************************************************************************/
extern void iwl_update_chain_flags(struct iwl_priv *priv);
@@ -739,17 +705,8 @@ static inline int iwl_queue_used(const struct iwl_queue *q, int i)
}
-static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge)
+static inline u8 get_cmd_index(struct iwl_queue *q, u32 index)
{
- /*
- * This is for init calibration result and scan command which
- * required buffer > TFD_MAX_PAYLOAD_SIZE,
- * the big buffer at end of command array
- */
- if (is_huge)
- return q->n_window; /* must be power of 2 */
-
- /* Otherwise, use normal size buffers */
return index & (q->n_window - 1);
}
@@ -772,7 +729,6 @@ struct iwl_dma_ptr {
/* Sensitivity and chain noise calibration */
#define INITIALIZATION_VALUE 0xFFFF
-#define IWL4965_CAL_NUM_BEACONS 20
#define IWL_CAL_NUM_BEACONS 16
#define MAXIMUM_ALLOWED_PATHLOSS 15
@@ -806,24 +762,19 @@ struct iwl_dma_ptr {
#define NRG_NUM_PREV_STAT_L 20
#define NUM_RX_CHAINS 3
-enum iwl4965_false_alarm_state {
+enum iwlagn_false_alarm_state {
IWL_FA_TOO_MANY = 0,
IWL_FA_TOO_FEW = 1,
IWL_FA_GOOD_RANGE = 2,
};
-enum iwl4965_chain_noise_state {
+enum iwlagn_chain_noise_state {
IWL_CHAIN_NOISE_ALIVE = 0, /* must be 0 */
IWL_CHAIN_NOISE_ACCUMULATE,
IWL_CHAIN_NOISE_CALIBRATED,
IWL_CHAIN_NOISE_DONE,
};
-enum iwl4965_calib_enabled_state {
- IWL_CALIB_DISABLED = 0, /* must be 0 */
- IWL_CALIB_ENABLED = 1,
-};
-
/*
* enum iwl_calib
@@ -847,12 +798,6 @@ struct iwl_calib_result {
size_t buf_len;
};
-enum ucode_type {
- UCODE_NONE = 0,
- UCODE_INIT,
- UCODE_RT
-};
-
/* Sensitivity calib data */
struct iwl_sensitivity_data {
u32 auto_corr_ofdm;
@@ -1131,12 +1076,6 @@ struct iwl_force_reset {
/* 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
@@ -1164,10 +1103,12 @@ struct iwl_force_reset {
struct iwl_notification_wait {
struct list_head list;
- void (*fn)(struct iwl_priv *priv, struct iwl_rx_packet *pkt);
+ void (*fn)(struct iwl_priv *priv, struct iwl_rx_packet *pkt,
+ void *data);
+ void *fn_data;
u8 cmd;
- bool triggered;
+ bool triggered, aborted;
};
enum iwl_rxon_context_id {
@@ -1228,6 +1169,8 @@ struct iwl_rxon_context {
bool enabled, is_40mhz;
u8 extension_chan_offset;
} ht;
+
+ bool last_tx_rejected;
};
enum iwl_scan_type {
@@ -1236,6 +1179,14 @@ enum iwl_scan_type {
IWL_SCAN_OFFCH_TX,
};
+#ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL
+struct iwl_testmode_trace {
+ u8 *cpu_addr;
+ u8 *trace_addr;
+ dma_addr_t dma_addr;
+ bool trace_enabled;
+};
+#endif
struct iwl_priv {
/* ieee device used by generic ieee processing code */
@@ -1244,13 +1195,10 @@ struct iwl_priv {
struct ieee80211_rate *ieee_rates;
struct iwl_cfg *cfg;
- /* temporary frame storage list */
- struct list_head free_frames;
- int frames_count;
-
enum ieee80211_band band;
- int alloc_rxb_page;
+ void (*pre_rx_handler)(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb);
void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
@@ -1305,16 +1253,12 @@ struct iwl_priv {
spinlock_t hcmd_lock; /* protect hcmd */
spinlock_t reg_lock; /* protect hw register access */
struct mutex mutex;
- struct mutex sync_cmd_mutex; /* enable serialization of sync commands */
/* basic pci-network driver stuff */
struct pci_dev *pci_dev;
/* pci hardware address support */
void __iomem *hw_base;
- u32 hw_rev;
- u32 hw_wa_rev;
- u8 rev_id;
/* microcode/device supports multiple contexts */
u8 valid_contexts;
@@ -1325,6 +1269,8 @@ struct iwl_priv {
/* max number of station keys */
u8 sta_key_max_num;
+ bool new_scan_threshold_behaviour;
+
/* EEPROM MAC addresses */
struct mac_address addresses[2];
@@ -1332,13 +1278,10 @@ struct iwl_priv {
int fw_index; /* firmware we're trying to load */
u32 ucode_ver; /* version of ucode, copy of
iwl_ucode.ver */
- struct fw_desc ucode_code; /* runtime inst */
- struct fw_desc ucode_data; /* runtime data original */
- struct fw_desc ucode_data_backup; /* runtime data save/restore */
- struct fw_desc ucode_init; /* initialization inst */
- struct fw_desc ucode_init_data; /* initialization data */
- struct fw_desc ucode_boot; /* bootstrap inst */
- enum ucode_type ucode_type;
+ struct fw_img ucode_rt;
+ struct fw_img ucode_init;
+
+ enum iwlagn_ucode_subtype ucode_type;
u8 ucode_write_complete; /* the image write is complete */
char firmware_name[25];
@@ -1346,10 +1289,10 @@ struct iwl_priv {
struct iwl_switch_rxon switch_rxon;
- /* 1st responses from initialize and runtime uCode images.
- * _agn's initialize alive response contains some calibration data. */
- struct iwl_init_alive_resp card_alive_init;
- struct iwl_alive_resp card_alive;
+ struct {
+ u32 error_event_table;
+ u32 log_event_table;
+ } device_pointers;
u16 active_rate;
@@ -1390,15 +1333,12 @@ struct iwl_priv {
struct iwl_power_mgr power_data;
struct iwl_tt_mgmt thermal_throttle;
- /* context information */
- u8 bssid[ETH_ALEN]; /* used only on 3945 but filled by core */
-
/* 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];
+ struct iwl_station_entry stations[IWLAGN_STATION_COUNT];
unsigned long ucode_key_table;
/* queue refcounts */
@@ -1422,101 +1362,81 @@ struct iwl_priv {
/* Last Rx'd beacon timestamp */
u64 timestamp;
- union {
-#if defined(CONFIG_IWL3945) || defined(CONFIG_IWL3945_MODULE)
- struct {
- void *shared_virt;
- dma_addr_t shared_phys;
-
- struct delayed_work thermal_periodic;
- struct delayed_work rfkill_poll;
-
- struct iwl3945_notif_statistics statistics;
+ struct {
+ __le32 flag;
+ struct statistics_general_common common;
+ struct statistics_rx_non_phy rx_non_phy;
+ struct statistics_rx_phy rx_ofdm;
+ struct statistics_rx_ht_phy rx_ofdm_ht;
+ struct statistics_rx_phy rx_cck;
+ struct statistics_tx tx;
#ifdef CONFIG_IWLWIFI_DEBUGFS
- struct iwl3945_notif_statistics accum_statistics;
- struct iwl3945_notif_statistics delta_statistics;
- struct iwl3945_notif_statistics max_delta;
-#endif
-
- u32 sta_supp_rates;
- int last_rx_rssi; /* From Rx packet statistics */
-
- /* Rx'd packet timing information */
- u32 last_beacon_time;
- u64 last_tsf;
-
- /*
- * each calibration channel group in the
- * EEPROM has a derived clip setting for
- * each rate.
- */
- const struct iwl3945_clip_group clip_groups[5];
-
- } _3945;
+ struct statistics_bt_activity bt_activity;
+ __le32 num_bt_kills, accum_num_bt_kills;
#endif
-#if defined(CONFIG_IWLAGN) || defined(CONFIG_IWLAGN_MODULE)
- struct {
- /* INT ICT Table */
- __le32 *ict_tbl;
- void *ict_tbl_vir;
- dma_addr_t ict_tbl_dma;
- dma_addr_t aligned_ict_tbl_dma;
- int ict_index;
- u32 inta;
- bool use_ict;
- /*
- * reporting the number of tids has AGG on. 0 means
- * no AGGREGATION
- */
- u8 agg_tids_count;
-
- struct iwl_rx_phy_res last_phy_res;
- 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;
- /* counts reply_tx error */
- struct reply_tx_error_statistics reply_tx_stats;
- struct reply_agg_tx_error_statistics reply_agg_tx_stats;
+ } statistics;
#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;
+ struct {
+ struct statistics_general_common common;
+ struct statistics_rx_non_phy rx_non_phy;
+ struct statistics_rx_phy rx_ofdm;
+ struct statistics_rx_ht_phy rx_ofdm_ht;
+ struct statistics_rx_phy rx_cck;
+ struct statistics_tx tx;
+ struct statistics_bt_activity bt_activity;
+ } accum_stats, delta_stats, max_delta_stats;
#endif
- /* notification wait support */
- struct list_head notif_waits;
- spinlock_t notif_wait_lock;
- wait_queue_head_t notif_waitq;
-
- /* remain-on-channel offload support */
- struct ieee80211_channel *hw_roc_channel;
- struct delayed_work hw_roc_work;
- enum nl80211_channel_type hw_roc_chantype;
- int hw_roc_duration;
-
- struct sk_buff *offchan_tx_skb;
- int offchan_tx_timeout;
- struct ieee80211_channel *offchan_tx_chan;
- } _agn;
-#endif
- };
+ struct {
+ /* INT ICT Table */
+ __le32 *ict_tbl;
+ void *ict_tbl_vir;
+ dma_addr_t ict_tbl_dma;
+ dma_addr_t aligned_ict_tbl_dma;
+ int ict_index;
+ u32 inta;
+ bool use_ict;
+ /*
+ * reporting the number of tids has AGG on. 0 means
+ * no AGGREGATION
+ */
+ u8 agg_tids_count;
+
+ struct iwl_rx_phy_res last_phy_res;
+ 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;
+
+ /* counts reply_tx error */
+ struct reply_tx_error_statistics reply_tx_stats;
+ struct reply_agg_tx_error_statistics reply_agg_tx_stats;
+ /* notification wait support */
+ struct list_head notif_waits;
+ spinlock_t notif_wait_lock;
+ wait_queue_head_t notif_waitq;
+
+ /* remain-on-channel offload support */
+ struct ieee80211_channel *hw_roc_channel;
+ struct delayed_work hw_roc_work;
+ enum nl80211_channel_type hw_roc_chantype;
+ int hw_roc_duration;
+ bool hw_roc_setup;
+
+ struct sk_buff *offchan_tx_skb;
+ int offchan_tx_timeout;
+ struct ieee80211_channel *offchan_tx_chan;
+ } _agn;
/* bt coex */
u8 bt_enable_flag;
@@ -1548,6 +1468,7 @@ struct iwl_priv {
struct work_struct beacon_update;
struct iwl_rxon_context *beacon_ctx;
struct sk_buff *beacon_skb;
+ void *beacon_cmd;
struct work_struct tt_work;
struct work_struct ct_enter;
@@ -1559,8 +1480,6 @@ struct iwl_priv {
struct tasklet_struct irq_tasklet;
- struct delayed_work init_alive_start;
- struct delayed_work alive_start;
struct delayed_work scan_check;
/* TX Power */
@@ -1589,18 +1508,21 @@ struct iwl_priv {
struct work_struct txpower_work;
u32 disable_sens_cal;
u32 disable_chain_noise_cal;
- u32 disable_tx_power_cal;
struct work_struct run_time_calib_work;
struct timer_list statistics_periodic;
struct timer_list ucode_trace;
struct timer_list watchdog;
- bool hw_ready;
struct iwl_event_log event_log;
struct led_classdev led;
unsigned long blink_on, blink_off;
bool led_registered;
+#ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL
+ struct iwl_testmode_trace testmode_trace;
+#endif
+ u32 dbg_fixed_rate;
+
}; /*iwl_priv */
static inline void iwl_txq_ctx_activate(struct iwl_priv *priv, int txq_id)
@@ -1658,21 +1580,24 @@ iwl_rxon_ctx_from_vif(struct ieee80211_vif *vif)
ctx < &priv->contexts[NUM_IWL_RXON_CTX]; ctx++) \
if (priv->valid_contexts & BIT(ctx->ctxid))
-static inline int iwl_is_associated(struct iwl_priv *priv,
- enum iwl_rxon_context_id ctxid)
+static inline int iwl_is_associated_ctx(struct iwl_rxon_context *ctx)
{
- return (priv->contexts[ctxid].active.filter_flags &
- RXON_FILTER_ASSOC_MSK) ? 1 : 0;
+ return (ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
}
-static inline int iwl_is_any_associated(struct iwl_priv *priv)
+static inline int iwl_is_associated(struct iwl_priv *priv,
+ enum iwl_rxon_context_id ctxid)
{
- return iwl_is_associated(priv, IWL_RXON_CTX_BSS);
+ return iwl_is_associated_ctx(&priv->contexts[ctxid]);
}
-static inline int iwl_is_associated_ctx(struct iwl_rxon_context *ctx)
+static inline int iwl_is_any_associated(struct iwl_priv *priv)
{
- return (ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
+ struct iwl_rxon_context *ctx;
+ for_each_context(priv, ctx)
+ if (iwl_is_associated_ctx(ctx))
+ return true;
+ return false;
}
static inline int is_channel_valid(const struct iwl_channel_info *ch_info)
@@ -1710,12 +1635,10 @@ static inline int is_channel_ibss(const struct iwl_channel_info *ch)
static inline void __iwl_free_pages(struct iwl_priv *priv, struct page *page)
{
__free_pages(page, priv->hw_params.rx_page_order);
- priv->alloc_rxb_page--;
}
static inline void iwl_free_pages(struct iwl_priv *priv, unsigned long page)
{
free_pages(page, priv->hw_params.rx_page_order);
- priv->alloc_rxb_page--;
}
#endif /* __iwl_dev_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c
index 4a487639d932..a635a7e75447 100644
--- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2009 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2009 - 2011 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
diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
index 4cf864c664ee..2c84ba95afca 100644
--- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h
+++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2009 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2009 - 2011 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
@@ -137,20 +137,27 @@ TRACE_EVENT(iwlwifi_dev_ucode_wrap_event,
#define TRACE_SYSTEM iwlwifi
TRACE_EVENT(iwlwifi_dev_hcmd,
- TP_PROTO(struct iwl_priv *priv, void *hcmd, size_t len, u32 flags),
- TP_ARGS(priv, hcmd, len, flags),
+ TP_PROTO(struct iwl_priv *priv, u32 flags,
+ const void *hcmd0, size_t len0,
+ const void *hcmd1, size_t len1,
+ const void *hcmd2, size_t len2),
+ TP_ARGS(priv, flags, hcmd0, len0, hcmd1, len1, hcmd2, len2),
TP_STRUCT__entry(
PRIV_ENTRY
- __dynamic_array(u8, hcmd, len)
+ __dynamic_array(u8, hcmd0, len0)
+ __dynamic_array(u8, hcmd1, len1)
+ __dynamic_array(u8, hcmd2, len2)
__field(u32, flags)
),
TP_fast_assign(
PRIV_ASSIGN;
- memcpy(__get_dynamic_array(hcmd), hcmd, len);
+ memcpy(__get_dynamic_array(hcmd0), hcmd0, len0);
+ memcpy(__get_dynamic_array(hcmd1), hcmd1, len1);
+ memcpy(__get_dynamic_array(hcmd2), hcmd2, len2);
__entry->flags = flags;
),
TP_printk("[%p] hcmd %#.2x (%ssync)",
- __entry->priv, ((u8 *)__get_dynamic_array(hcmd))[0],
+ __entry->priv, ((u8 *)__get_dynamic_array(hcmd0))[0],
__entry->flags & CMD_ASYNC ? "a" : "")
);
@@ -202,15 +209,18 @@ TRACE_EVENT(iwlwifi_dev_tx,
);
TRACE_EVENT(iwlwifi_dev_ucode_error,
- TP_PROTO(struct iwl_priv *priv, u32 desc, u32 time,
+ TP_PROTO(struct iwl_priv *priv, u32 desc, u32 tsf_low,
u32 data1, u32 data2, u32 line, u32 blink1,
- u32 blink2, u32 ilink1, u32 ilink2),
- TP_ARGS(priv, desc, time, data1, data2, line,
- blink1, blink2, ilink1, ilink2),
+ u32 blink2, u32 ilink1, u32 ilink2, u32 bcon_time,
+ u32 gp1, u32 gp2, u32 gp3, u32 ucode_ver, u32 hw_ver,
+ u32 brd_ver),
+ TP_ARGS(priv, desc, tsf_low, data1, data2, line,
+ blink1, blink2, ilink1, ilink2, bcon_time, gp1, gp2,
+ gp3, ucode_ver, hw_ver, brd_ver),
TP_STRUCT__entry(
PRIV_ENTRY
__field(u32, desc)
- __field(u32, time)
+ __field(u32, tsf_low)
__field(u32, data1)
__field(u32, data2)
__field(u32, line)
@@ -218,11 +228,18 @@ TRACE_EVENT(iwlwifi_dev_ucode_error,
__field(u32, blink2)
__field(u32, ilink1)
__field(u32, ilink2)
+ __field(u32, bcon_time)
+ __field(u32, gp1)
+ __field(u32, gp2)
+ __field(u32, gp3)
+ __field(u32, ucode_ver)
+ __field(u32, hw_ver)
+ __field(u32, brd_ver)
),
TP_fast_assign(
PRIV_ASSIGN;
__entry->desc = desc;
- __entry->time = time;
+ __entry->tsf_low = tsf_low;
__entry->data1 = data1;
__entry->data2 = data2;
__entry->line = line;
@@ -230,12 +247,25 @@ TRACE_EVENT(iwlwifi_dev_ucode_error,
__entry->blink2 = blink2;
__entry->ilink1 = ilink1;
__entry->ilink2 = ilink2;
+ __entry->bcon_time = bcon_time;
+ __entry->gp1 = gp1;
+ __entry->gp2 = gp2;
+ __entry->gp3 = gp3;
+ __entry->ucode_ver = ucode_ver;
+ __entry->hw_ver = hw_ver;
+ __entry->brd_ver = brd_ver;
),
TP_printk("[%p] #%02d %010u data 0x%08X 0x%08X line %u, "
- "blink 0x%05X 0x%05X ilink 0x%05X 0x%05X",
- __entry->priv, __entry->desc, __entry->time, __entry->data1,
+ "blink 0x%05X 0x%05X ilink 0x%05X 0x%05X "
+ "bcon_tm %010u gp 0x%08X 0x%08X 0x%08X uCode 0x%08X "
+ "hw 0x%08X brd 0x%08X",
+ __entry->priv, __entry->desc, __entry->tsf_low,
+ __entry->data1,
__entry->data2, __entry->line, __entry->blink1,
- __entry->blink2, __entry->ilink1, __entry->ilink2)
+ __entry->blink2, __entry->ilink1, __entry->ilink2,
+ __entry->bcon_time, __entry->gp1, __entry->gp2,
+ __entry->gp3, __entry->ucode_ver, __entry->hw_ver,
+ __entry->brd_ver)
);
TRACE_EVENT(iwlwifi_dev_ucode_event,
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index 833194a2c639..47a56bc1cd12 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 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
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -142,6 +142,45 @@ static const u8 iwl_eeprom_band_7[] = { /* 5.2 ht40 channel */
*
******************************************************************************/
+/*
+ * The device's EEPROM semaphore prevents conflicts between driver and uCode
+ * when accessing the EEPROM; each access is a series of pulses to/from the
+ * EEPROM chip, not a single event, so even reads could conflict if they
+ * weren't arbitrated by the semaphore.
+ */
+static int iwl_eeprom_acquire_semaphore(struct iwl_priv *priv)
+{
+ u16 count;
+ int ret;
+
+ for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
+ /* Request semaphore */
+ iwl_set_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
+
+ /* See if we got it */
+ ret = iwl_poll_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
+ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
+ EEPROM_SEM_TIMEOUT);
+ if (ret >= 0) {
+ IWL_DEBUG_EEPROM(priv,
+ "Acquired semaphore after %d tries.\n",
+ count+1);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static void iwl_eeprom_release_semaphore(struct iwl_priv *priv)
+{
+ iwl_clear_bit(priv, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
+
+}
+
static int iwl_eeprom_verify_signature(struct iwl_priv *priv)
{
u32 gp = iwl_read32(priv, CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK;
@@ -177,29 +216,26 @@ static int iwl_eeprom_verify_signature(struct iwl_priv *priv)
static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode)
{
- u32 otpgp;
+ iwl_read32(priv, CSR_OTP_GP_REG);
- otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
if (mode == IWL_OTP_ACCESS_ABSOLUTE)
iwl_clear_bit(priv, CSR_OTP_GP_REG,
- CSR_OTP_GP_REG_OTP_ACCESS_MODE);
+ CSR_OTP_GP_REG_OTP_ACCESS_MODE);
else
iwl_set_bit(priv, CSR_OTP_GP_REG,
- CSR_OTP_GP_REG_OTP_ACCESS_MODE);
+ CSR_OTP_GP_REG_OTP_ACCESS_MODE);
}
-static int iwlcore_get_nvm_type(struct iwl_priv *priv)
+static int iwlcore_get_nvm_type(struct iwl_priv *priv, u32 hw_rev)
{
u32 otpgp;
int nvm_type;
/* OTP only valid for CP/PP and after */
- switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) {
+ switch (hw_rev & CSR_HW_REV_TYPE_MSK) {
case CSR_HW_REV_TYPE_NONE:
IWL_ERR(priv, "Unknown hardware type\n");
return -ENOENT;
- case CSR_HW_REV_TYPE_3945:
- case CSR_HW_REV_TYPE_4965:
case CSR_HW_REV_TYPE_5300:
case CSR_HW_REV_TYPE_5350:
case CSR_HW_REV_TYPE_5100:
@@ -217,26 +253,20 @@ static int iwlcore_get_nvm_type(struct iwl_priv *priv)
return nvm_type;
}
-const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset)
-{
- BUG_ON(offset >= priv->cfg->base_params->eeprom_size);
- return &priv->eeprom[offset];
-}
-
static int iwl_init_otp_access(struct iwl_priv *priv)
{
int ret;
/* Enable 40MHz radio clock */
- _iwl_write32(priv, CSR_GP_CNTRL,
- _iwl_read32(priv, CSR_GP_CNTRL) |
- CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+ iwl_write32(priv, CSR_GP_CNTRL,
+ iwl_read32(priv, CSR_GP_CNTRL) |
+ CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
/* wait for clock to be ready */
ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
- 25000);
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
+ 25000);
if (ret < 0)
IWL_ERR(priv, "Time out access OTP\n");
else {
@@ -263,17 +293,17 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, __le16 *eeprom_dat
u32 r;
u32 otpgp;
- _iwl_write32(priv, CSR_EEPROM_REG,
- CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
+ iwl_write32(priv, CSR_EEPROM_REG,
+ CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
ret = iwl_poll_bit(priv, CSR_EEPROM_REG,
- CSR_EEPROM_REG_READ_VALID_MSK,
- CSR_EEPROM_REG_READ_VALID_MSK,
- IWL_EEPROM_ACCESS_TIMEOUT);
+ CSR_EEPROM_REG_READ_VALID_MSK,
+ CSR_EEPROM_REG_READ_VALID_MSK,
+ IWL_EEPROM_ACCESS_TIMEOUT);
if (ret < 0) {
IWL_ERR(priv, "Time out reading OTP[%d]\n", addr);
return ret;
}
- r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
+ r = iwl_read32(priv, CSR_EEPROM_REG);
/* check for ECC errors: */
otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
@@ -396,7 +426,7 @@ u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset)
*
* NOTE: This routine uses the non-debug IO access functions.
*/
-int iwl_eeprom_init(struct iwl_priv *priv)
+int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
{
__le16 *e;
u32 gp = iwl_read32(priv, CSR_EEPROM_GP);
@@ -406,7 +436,7 @@ int iwl_eeprom_init(struct iwl_priv *priv)
u16 validblockaddr = 0;
u16 cache_addr = 0;
- priv->nvm_device_type = iwlcore_get_nvm_type(priv);
+ priv->nvm_device_type = iwlcore_get_nvm_type(priv, hw_rev);
if (priv->nvm_device_type == -ENOENT)
return -ENOENT;
/* allocate eeprom */
@@ -429,7 +459,7 @@ int iwl_eeprom_init(struct iwl_priv *priv)
}
/* Make sure driver (instead of uCode) is allowed to read EEPROM */
- ret = priv->cfg->ops->lib->eeprom_ops.acquire_semaphore(priv);
+ ret = iwl_eeprom_acquire_semaphore(priv);
if (ret < 0) {
IWL_ERR(priv, "Failed to acquire EEPROM semaphore.\n");
ret = -ENOENT;
@@ -444,9 +474,9 @@ int iwl_eeprom_init(struct iwl_priv *priv)
ret = -ENOENT;
goto done;
}
- _iwl_write32(priv, CSR_EEPROM_GP,
- iwl_read32(priv, CSR_EEPROM_GP) &
- ~CSR_EEPROM_GP_IF_OWNER_MSK);
+ iwl_write32(priv, CSR_EEPROM_GP,
+ iwl_read32(priv, CSR_EEPROM_GP) &
+ ~CSR_EEPROM_GP_IF_OWNER_MSK);
iwl_set_bit(priv, CSR_OTP_GP_REG,
CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK |
@@ -473,8 +503,8 @@ int iwl_eeprom_init(struct iwl_priv *priv)
for (addr = 0; addr < sz; addr += sizeof(u16)) {
u32 r;
- _iwl_write32(priv, CSR_EEPROM_REG,
- CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
+ iwl_write32(priv, CSR_EEPROM_REG,
+ CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
ret = iwl_poll_bit(priv, CSR_EEPROM_REG,
CSR_EEPROM_REG_READ_VALID_MSK,
@@ -484,7 +514,7 @@ int iwl_eeprom_init(struct iwl_priv *priv)
IWL_ERR(priv, "Time out reading EEPROM[%d]\n", addr);
goto done;
}
- r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
+ r = iwl_read32(priv, CSR_EEPROM_REG);
e[addr / 2] = cpu_to_le16(r >> 16);
}
}
@@ -496,7 +526,7 @@ int iwl_eeprom_init(struct iwl_priv *priv)
ret = 0;
done:
- priv->cfg->ops->lib->eeprom_ops.release_semaphore(priv);
+ iwl_eeprom_release_semaphore(priv);
err:
if (ret)
@@ -719,13 +749,6 @@ int iwl_init_channel_map(struct iwl_priv *priv)
flags & EEPROM_CHANNEL_RADAR))
? "" : "not ");
- /* Set the tx_power_user_lmt to the highest power
- * supported by any channel */
- if (eeprom_ch_info[ch].max_power_avg >
- priv->tx_power_user_lmt)
- priv->tx_power_user_lmt =
- eeprom_ch_info[ch].max_power_avg;
-
ch_info++;
}
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index 20b66469d68f..c960c6fa009b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 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
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -110,10 +110,6 @@ enum {
};
/* SKU Capabilities */
-/* 3945 only */
-#define EEPROM_SKU_CAP_SW_RF_KILL_ENABLE (1 << 0)
-#define EEPROM_SKU_CAP_HW_RF_KILL_ENABLE (1 << 1)
-
/* 5000 and up */
#define EEPROM_SKU_CAP_BAND_POS (4)
#define EEPROM_SKU_CAP_BAND_SELECTION \
@@ -168,28 +164,6 @@ struct iwl_eeprom_enhanced_txpwr {
s8 mimo3_max;
} __packed;
-/* 3945 Specific */
-#define EEPROM_3945_EEPROM_VERSION (0x2f)
-
-/* 4965 has two radio transmitters (and 3 radio receivers) */
-#define EEPROM_TX_POWER_TX_CHAINS (2)
-
-/* 4965 has room for up to 8 sets of txpower calibration data */
-#define EEPROM_TX_POWER_BANDS (8)
-
-/* 4965 factory calibration measures txpower gain settings for
- * each of 3 target output levels */
-#define EEPROM_TX_POWER_MEASUREMENTS (3)
-
-/* 4965 Specific */
-/* 4965 driver does not work with txpower calibration version < 5 */
-#define EEPROM_4965_TX_POWER_VERSION (5)
-#define EEPROM_4965_EEPROM_VERSION (0x2f)
-#define EEPROM_4965_CALIB_VERSION_OFFSET (2*0xB6) /* 2 bytes */
-#define EEPROM_4965_CALIB_TXPOWER_OFFSET (2*0xE8) /* 48 bytes */
-#define EEPROM_4965_BOARD_REVISION (2*0x4F) /* 2 bytes */
-#define EEPROM_4965_BOARD_PBA (2*0x56+1) /* 9 bytes */
-
/* 5000 Specific */
#define EEPROM_5000_TX_POWER_VERSION (4)
#define EEPROM_5000_EEPROM_VERSION (0x11A)
@@ -282,90 +256,6 @@ struct iwl_eeprom_enhanced_txpwr {
/* 2.4 GHz */
extern const u8 iwl_eeprom_band_1[14];
-/*
- * factory calibration data for one txpower level, on one channel,
- * measured on one of the 2 tx chains (radio transmitter and associated
- * antenna). EEPROM contains:
- *
- * 1) Temperature (degrees Celsius) of device when measurement was made.
- *
- * 2) Gain table index used to achieve the target measurement power.
- * This refers to the "well-known" gain tables (see iwl-4965-hw.h).
- *
- * 3) Actual measured output power, in half-dBm ("34" = 17 dBm).
- *
- * 4) RF power amplifier detector level measurement (not used).
- */
-struct iwl_eeprom_calib_measure {
- u8 temperature; /* Device temperature (Celsius) */
- 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) */
-} __packed;
-
-
-/*
- * measurement set for one channel. EEPROM contains:
- *
- * 1) Channel number measured
- *
- * 2) Measurements for each of 3 power levels for each of 2 radio transmitters
- * (a.k.a. "tx chains") (6 measurements altogether)
- */
-struct iwl_eeprom_calib_ch_info {
- u8 ch_num;
- struct iwl_eeprom_calib_measure
- measurements[EEPROM_TX_POWER_TX_CHAINS]
- [EEPROM_TX_POWER_MEASUREMENTS];
-} __packed;
-
-/*
- * txpower subband info.
- *
- * For each frequency subband, EEPROM contains the following:
- *
- * 1) First and last channels within range of the subband. "0" values
- * indicate that this sample set is not being used.
- *
- * 2) Sample measurement sets for 2 channels close to the range endpoints.
- */
-struct iwl_eeprom_calib_subband_info {
- u8 ch_from; /* channel number of lowest channel in subband */
- u8 ch_to; /* channel number of highest channel in subband */
- struct iwl_eeprom_calib_ch_info ch1;
- struct iwl_eeprom_calib_ch_info ch2;
-} __packed;
-
-
-/*
- * txpower calibration info. EEPROM contains:
- *
- * 1) Factory-measured saturation power levels (maximum levels at which
- * tx power amplifier can output a signal without too much distortion).
- * There is one level for 2.4 GHz band and one for 5 GHz band. These
- * values apply to all channels within each of the bands.
- *
- * 2) Factory-measured power supply voltage level. This is assumed to be
- * constant (i.e. same value applies to all channels/bands) while the
- * factory measurements are being made.
- *
- * 3) Up to 8 sets of factory-measured txpower calibration values.
- * These are for different frequency ranges, since txpower gain
- * characteristics of the analog radio circuitry vary with frequency.
- *
- * Not all sets need to be filled with data;
- * struct iwl_eeprom_calib_subband_info contains range of channels
- * (0 if unused) for each set of data.
- */
-struct iwl_eeprom_calib_info {
- u8 saturation_power24; /* half-dBm (e.g. "34" = 17 dBm) */
- u8 saturation_power52; /* half-dBm */
- __le16 voltage; /* signed */
- struct iwl_eeprom_calib_subband_info
- band_info[EEPROM_TX_POWER_BANDS];
-} __packed;
-
-
#define ADDRESS_MSK 0x0000FFFF
#define INDIRECT_TYPE_MSK 0x000F0000
#define INDIRECT_HOST 0x00010000
@@ -398,103 +288,24 @@ struct iwl_eeprom_calib_info {
#define EEPROM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */
#define EEPROM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
-#define EEPROM_3945_RF_CFG_TYPE_MAX 0x0
-#define EEPROM_4965_RF_CFG_TYPE_MAX 0x1
-
-/* Radio Config for 5000 and up */
-#define EEPROM_RF_CONFIG_TYPE_R3x3 0x0
-#define EEPROM_RF_CONFIG_TYPE_R2x2 0x1
-#define EEPROM_RF_CONFIG_TYPE_R1x2 0x2
#define EEPROM_RF_CONFIG_TYPE_MAX 0x3
-/*
- * Per-channel regulatory data.
- *
- * Each channel that *might* be supported by iwl has a fixed location
- * in EEPROM containing EEPROM_CHANNEL_* usage flags (LSB) and max regulatory
- * txpower (MSB).
- *
- * Entries immediately below are for 20 MHz channel width. HT40 (40 MHz)
- * channels (only for 4965, not supported by 3945) appear later in the EEPROM.
- *
- * 2.4 GHz channels 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
- */
-#define EEPROM_REGULATORY_SKU_ID (2*0x60) /* 4 bytes */
-#define EEPROM_REGULATORY_BAND_1 (2*0x62) /* 2 bytes */
-#define EEPROM_REGULATORY_BAND_1_CHANNELS (2*0x63) /* 28 bytes */
-
-/*
- * 4.9 GHz channels 183, 184, 185, 187, 188, 189, 192, 196,
- * 5.0 GHz channels 7, 8, 11, 12, 16
- * (4915-5080MHz) (none of these is ever supported)
- */
-#define EEPROM_REGULATORY_BAND_2 (2*0x71) /* 2 bytes */
-#define EEPROM_REGULATORY_BAND_2_CHANNELS (2*0x72) /* 26 bytes */
-
-/*
- * 5.2 GHz channels 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64
- * (5170-5320MHz)
- */
-#define EEPROM_REGULATORY_BAND_3 (2*0x7F) /* 2 bytes */
-#define EEPROM_REGULATORY_BAND_3_CHANNELS (2*0x80) /* 24 bytes */
-
-/*
- * 5.5 GHz channels 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140
- * (5500-5700MHz)
- */
-#define EEPROM_REGULATORY_BAND_4 (2*0x8C) /* 2 bytes */
-#define EEPROM_REGULATORY_BAND_4_CHANNELS (2*0x8D) /* 22 bytes */
-
-/*
- * 5.7 GHz channels 145, 149, 153, 157, 161, 165
- * (5725-5825MHz)
- */
-#define EEPROM_REGULATORY_BAND_5 (2*0x98) /* 2 bytes */
-#define EEPROM_REGULATORY_BAND_5_CHANNELS (2*0x99) /* 12 bytes */
-
-/*
- * 2.4 GHz HT40 channels 1 (5), 2 (6), 3 (7), 4 (8), 5 (9), 6 (10), 7 (11)
- *
- * The channel listed is the center of the lower 20 MHz half of the channel.
- * The overall center frequency is actually 2 channels (10 MHz) above that,
- * and the upper half of each HT40 channel is centered 4 channels (20 MHz) away
- * from the lower half; e.g. the upper half of HT40 channel 1 is channel 5,
- * and the overall HT40 channel width centers on channel 3.
- *
- * NOTE: The RXON command uses 20 MHz channel numbers to specify the
- * control channel to which to tune. RXON also specifies whether the
- * control channel is the upper or lower half of a HT40 channel.
- *
- * NOTE: 4965 does not support HT40 channels on 2.4 GHz.
- */
-#define EEPROM_4965_REGULATORY_BAND_24_HT40_CHANNELS (2*0xA0) /* 14 bytes */
-
-/*
- * 5.2 GHz HT40 channels 36 (40), 44 (48), 52 (56), 60 (64),
- * 100 (104), 108 (112), 116 (120), 124 (128), 132 (136), 149 (153), 157 (161)
- */
-#define EEPROM_4965_REGULATORY_BAND_52_HT40_CHANNELS (2*0xA8) /* 22 bytes */
-
#define EEPROM_REGULATORY_BAND_NO_HT40 (0)
struct iwl_eeprom_ops {
const u32 regulatory_bands[7];
- int (*acquire_semaphore) (struct iwl_priv *priv);
- void (*release_semaphore) (struct iwl_priv *priv);
- u16 (*calib_version) (struct iwl_priv *priv);
const u8* (*query_addr) (const struct iwl_priv *priv, size_t offset);
void (*update_enhanced_txpower) (struct iwl_priv *priv);
};
-int iwl_eeprom_init(struct iwl_priv *priv);
+int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev);
void iwl_eeprom_free(struct iwl_priv *priv);
int iwl_eeprom_check_version(struct iwl_priv *priv);
int iwl_eeprom_check_sku(struct iwl_priv *priv);
const u8 *iwl_eeprom_query_addr(const struct iwl_priv *priv, size_t offset);
int iwlcore_eeprom_verify_signature(struct iwl_priv *priv);
u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset);
-const u8 *iwlcore_eeprom_query_addr(const struct iwl_priv *priv, size_t offset);
int iwl_init_channel_map(struct iwl_priv *priv);
void iwl_free_channel_map(struct iwl_priv *priv);
const struct iwl_channel_info *iwl_get_channel_info(
diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h
index 474009a244d4..6dfa806aefec 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fh.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fh.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 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
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -77,14 +77,14 @@
/**
* Keep-Warm (KW) buffer base address.
*
- * Driver must allocate a 4KByte buffer that is used by 4965 for keeping the
+ * Driver must allocate a 4KByte buffer that is for keeping the
* host DRAM powered on (via dummy accesses to DRAM) to maintain low-latency
- * DRAM access when 4965 is Txing or Rxing. The dummy accesses prevent host
+ * DRAM access when doing Txing or Rxing. The dummy accesses prevent host
* from going into a power-savings mode that would cause higher DRAM latency,
* and possible data over/under-runs, before all Tx/Rx is complete.
*
* Driver loads FH_KW_MEM_ADDR_REG with the physical address (bits 35:4)
- * of the buffer, which must be 4K aligned. Once this is set up, the 4965
+ * of the buffer, which must be 4K aligned. Once this is set up, the device
* automatically invokes keep-warm accesses when normal accesses might not
* be sufficient to maintain fast DRAM response.
*
@@ -97,7 +97,7 @@
/**
* TFD Circular Buffers Base (CBBC) addresses
*
- * 4965 has 16 base pointer registers, one for each of 16 host-DRAM-resident
+ * Device has 16 base pointer registers, one for each of 16 host-DRAM-resident
* circular buffers (CBs/queues) containing Transmit Frame Descriptors (TFDs)
* (see struct iwl_tfd_frame). These 16 pointer registers are offset by 0x04
* bytes from one another. Each TFD circular buffer in DRAM must be 256-byte
@@ -116,16 +116,16 @@
/**
* Rx SRAM Control and Status Registers (RSCSR)
*
- * These registers provide handshake between driver and 4965 for the Rx queue
+ * These registers provide handshake between driver and device for the Rx queue
* (this queue handles *all* command responses, notifications, Rx data, etc.
- * sent from 4965 uCode to host driver). Unlike Tx, there is only one Rx
+ * sent from uCode to host driver). Unlike Tx, there is only one Rx
* queue, and only one Rx DMA/FIFO channel. Also unlike Tx, which can
* concatenate up to 20 DRAM buffers to form a Tx frame, each Receive Buffer
* Descriptor (RBD) points to only one Rx Buffer (RB); there is a 1:1
* mapping between RBDs and RBs.
*
* Driver must allocate host DRAM memory for the following, and set the
- * physical address of each into 4965 registers:
+ * physical address of each into device registers:
*
* 1) Receive Buffer Descriptor (RBD) circular buffer (CB), typically with 256
* entries (although any power of 2, up to 4096, is selectable by driver).
@@ -140,20 +140,20 @@
* Driver sets physical address [35:8] of base of RBD circular buffer
* into FH_RSCSR_CHNL0_RBDCB_BASE_REG [27:0].
*
- * 2) Rx status buffer, 8 bytes, in which 4965 indicates which Rx Buffers
+ * 2) Rx status buffer, 8 bytes, in which uCode indicates which Rx Buffers
* (RBs) have been filled, via a "write pointer", actually the index of
* the RB's corresponding RBD within the circular buffer. Driver sets
* physical address [35:4] into FH_RSCSR_CHNL0_STTS_WPTR_REG [31:0].
*
* Bit fields in lower dword of Rx status buffer (upper dword not used
- * by driver; see struct iwl4965_shared, val0):
+ * by driver:
* 31-12: Not used by driver
* 11- 0: Index of last filled Rx buffer descriptor
- * (4965 writes, driver reads this value)
+ * (device writes, driver reads this value)
*
- * As the driver prepares Receive Buffers (RBs) for 4965 to fill, driver must
+ * As the driver prepares Receive Buffers (RBs) for device to fill, driver must
* enter pointers to these RBs into contiguous RBD circular buffer entries,
- * and update the 4965's "write" index register,
+ * and update the device's "write" index register,
* FH_RSCSR_CHNL0_RBDCB_WPTR_REG.
*
* This "write" index corresponds to the *next* RBD that the driver will make
@@ -162,12 +162,12 @@
* RBs), should be 8 after preparing the first 8 RBs (for example), and must
* wrap back to 0 at the end of the circular buffer (but don't wrap before
* "read" index has advanced past 1! See below).
- * NOTE: 4965 EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8.
+ * NOTE: DEVICE EXPECTS THE WRITE INDEX TO BE INCREMENTED IN MULTIPLES OF 8.
*
- * As the 4965 fills RBs (referenced from contiguous RBDs within the circular
+ * As the device fills RBs (referenced from contiguous RBDs within the circular
* buffer), it updates the Rx status buffer in host DRAM, 2) described above,
* to tell the driver the index of the latest filled RBD. The driver must
- * read this "read" index from DRAM after receiving an Rx interrupt from 4965.
+ * read this "read" index from DRAM after receiving an Rx interrupt from device
*
* The driver must also internally keep track of a third index, which is the
* next RBD to process. When receiving an Rx interrupt, driver should process
@@ -176,7 +176,7 @@
* driver may process the RB pointed to by RBD 0. Depending on volume of
* traffic, there may be many RBs to process.
*
- * If read index == write index, 4965 thinks there is no room to put new data.
+ * If read index == write index, device thinks there is no room to put new data.
* Due to this, the maximum number of filled RBs is 255, instead of 256. To
* be safe, make sure that there is a gap of at least 2 RBDs between "write"
* and "read" indexes; that is, make sure that there are no more than 254
@@ -303,7 +303,7 @@
/**
* Transmit DMA Channel Control/Status Registers (TCSR)
*
- * 4965 has one configuration register for each of 8 Tx DMA/FIFO channels
+ * Device has one configuration register for each of 8 Tx DMA/FIFO channels
* supported in hardware (don't confuse these with the 16 Tx queues in DRAM,
* which feed the DMA/FIFO channels); config regs are separated by 0x20 bytes.
*
@@ -326,7 +326,6 @@
#define FH_TCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xE60)
/* Find Control/Status reg for given Tx DMA/FIFO channel */
-#define FH49_TCSR_CHNL_NUM (7)
#define FH50_TCSR_CHNL_NUM (8)
/* TCSR: tx_config register values */
@@ -424,7 +423,6 @@
#define RX_LOW_WATERMARK 8
/* Size of one Rx buffer in host DRAM */
-#define IWL_RX_BUF_SIZE_3K (3 * 1000) /* 3945 only */
#define IWL_RX_BUF_SIZE_4K (4 * 1024)
#define IWL_RX_BUF_SIZE_8K (8 * 1024)
@@ -443,7 +441,7 @@ struct iwl_rb_status {
__le16 closed_fr_num;
__le16 finished_rb_num;
__le16 finished_fr_nam;
- __le32 __unused; /* 3945 only */
+ __le32 __unused;
} __packed;
diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
index 02499f684683..76f996623140 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
@@ -2,7 +2,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 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
@@ -51,9 +51,7 @@ const char *get_cmd_string(u8 cmd)
IWL_CMD(REPLY_REMOVE_ALL_STA);
IWL_CMD(REPLY_TXFIFO_FLUSH);
IWL_CMD(REPLY_WEPKEY);
- IWL_CMD(REPLY_3945_RX);
IWL_CMD(REPLY_TX);
- IWL_CMD(REPLY_RATE_SCALE);
IWL_CMD(REPLY_LEDS_CMD);
IWL_CMD(REPLY_TX_LINK_QUALITY_CMD);
IWL_CMD(COEX_PRIORITY_TABLE_CMD);
@@ -145,10 +143,12 @@ static int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
{
int ret;
- BUG_ON(!(cmd->flags & CMD_ASYNC));
+ if (WARN_ON(!(cmd->flags & CMD_ASYNC)))
+ return -EINVAL;
/* An asynchronous command can not expect an SKB to be set. */
- BUG_ON(cmd->flags & CMD_WANT_SKB);
+ if (WARN_ON(cmd->flags & CMD_WANT_SKB))
+ return -EINVAL;
/* Assign a generic callback if one is not provided */
if (!cmd->callback)
@@ -171,14 +171,15 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
int cmd_idx;
int ret;
- BUG_ON(cmd->flags & CMD_ASYNC);
+ if (WARN_ON(cmd->flags & CMD_ASYNC))
+ return -EINVAL;
/* A synchronous command can not have a callback set. */
- BUG_ON(cmd->callback);
+ if (WARN_ON(cmd->callback))
+ return -EINVAL;
IWL_DEBUG_INFO(priv, "Attempting to send sync command %s\n",
get_cmd_string(cmd->id));
- mutex_lock(&priv->sync_cmd_mutex);
set_bit(STATUS_HCMD_ACTIVE, &priv->status);
IWL_DEBUG_INFO(priv, "Setting HCMD_ACTIVE for command %s\n",
@@ -187,9 +188,10 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
cmd_idx = iwl_enqueue_hcmd(priv, cmd);
if (cmd_idx < 0) {
ret = cmd_idx;
+ clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
IWL_ERR(priv, "Error sending %s: enqueue_hcmd failed: %d\n",
get_cmd_string(cmd->id), ret);
- goto out;
+ return ret;
}
ret = wait_event_interruptible_timeout(priv->wait_command_queue,
@@ -229,8 +231,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
goto cancel;
}
- ret = 0;
- goto out;
+ return 0;
cancel:
if (cmd->flags & CMD_WANT_SKB) {
@@ -248,8 +249,7 @@ fail:
iwl_free_pages(priv, cmd->reply_page);
cmd->reply_page = 0;
}
-out:
- mutex_unlock(&priv->sync_cmd_mutex);
+
return ret;
}
@@ -265,8 +265,8 @@ int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data)
{
struct iwl_host_cmd cmd = {
.id = id,
- .len = len,
- .data = data,
+ .len = { len, },
+ .data = { data, },
};
return iwl_send_cmd_sync(priv, &cmd);
@@ -280,8 +280,8 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv,
{
struct iwl_host_cmd cmd = {
.id = id,
- .len = len,
- .data = data,
+ .len = { len, },
+ .data = { data, },
};
cmd.flags |= CMD_ASYNC;
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h
index 8821f088ba7f..41207a3645b8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-helpers.h
+++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
@@ -64,30 +64,6 @@ static inline int iwl_queue_dec_wrap(int index, int n_bd)
return --index & (n_bd - 1);
}
-/* TODO: Move fw_desc functions to iwl-pci.ko */
-static inline void iwl_free_fw_desc(struct pci_dev *pci_dev,
- struct fw_desc *desc)
-{
- if (desc->v_addr)
- dma_free_coherent(&pci_dev->dev, desc->len,
- desc->v_addr, desc->p_addr);
- desc->v_addr = NULL;
- desc->len = 0;
-}
-
-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;
-}
-
/*
* we have 8 bits used like this:
*
@@ -131,6 +107,19 @@ static inline void iwl_stop_queue(struct iwl_priv *priv,
ieee80211_stop_queue(priv->hw, ac);
}
+static inline void iwl_wake_any_queue(struct iwl_priv *priv,
+ struct iwl_rxon_context *ctx)
+{
+ u8 ac;
+
+ for (ac = 0; ac < AC_NUM; ac++) {
+ IWL_DEBUG_INFO(priv, "Queue Status: Q[%d] %s\n",
+ ac, (atomic_read(&priv->queue_stop_count[ac]) > 0)
+ ? "stopped" : "awake");
+ iwl_wake_queue(priv, &priv->txq[ctx->ac_to_queue[ac]]);
+ }
+}
+
#define ieee80211_stop_queue DO_NOT_USE_ieee80211_stop_queue
#define ieee80211_wake_queue DO_NOT_USE_ieee80211_wake_queue
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c
new file mode 100644
index 000000000000..aa4a90674452
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-io.c
@@ -0,0 +1,294 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project.
+ *
+ * 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:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+
+#include "iwl-io.h"
+
+#define IWL_POLL_INTERVAL 10 /* microseconds */
+
+static inline void __iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask)
+{
+ iwl_write32(priv, reg, iwl_read32(priv, reg) | mask);
+}
+
+static inline void __iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask)
+{
+ iwl_write32(priv, reg, iwl_read32(priv, reg) & ~mask);
+}
+
+void iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->reg_lock, flags);
+ __iwl_set_bit(priv, reg, mask);
+ spin_unlock_irqrestore(&priv->reg_lock, flags);
+}
+
+void iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->reg_lock, flags);
+ __iwl_clear_bit(priv, reg, mask);
+ spin_unlock_irqrestore(&priv->reg_lock, flags);
+}
+
+int iwl_poll_bit(struct iwl_priv *priv, u32 addr,
+ u32 bits, u32 mask, int timeout)
+{
+ int t = 0;
+
+ do {
+ if ((iwl_read32(priv, addr) & mask) == (bits & mask))
+ return t;
+ udelay(IWL_POLL_INTERVAL);
+ t += IWL_POLL_INTERVAL;
+ } while (t < timeout);
+
+ return -ETIMEDOUT;
+}
+
+int iwl_grab_nic_access_silent(struct iwl_priv *priv)
+{
+ int ret;
+
+ lockdep_assert_held(&priv->reg_lock);
+
+ /* this bit wakes up the NIC */
+ __iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+
+ /*
+ * These bits say the device is running, and should keep running for
+ * at least a short while (at least as long as MAC_ACCESS_REQ stays 1),
+ * but they do not indicate that embedded SRAM is restored yet;
+ * 3945 and 4965 have volatile SRAM, and must save/restore contents
+ * to/from host DRAM when sleeping/waking for power-saving.
+ * Each direction takes approximately 1/4 millisecond; with this
+ * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a
+ * series of register accesses are expected (e.g. reading Event Log),
+ * to keep device from sleeping.
+ *
+ * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that
+ * SRAM is okay/restored. We don't check that here because this call
+ * is just for hardware register access; but GP1 MAC_SLEEP check is a
+ * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log).
+ *
+ * 5000 series and later (including 1000 series) have non-volatile SRAM,
+ * and do not save/restore SRAM when power cycling.
+ */
+ ret = iwl_poll_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
+ (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
+ CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000);
+ if (ret < 0) {
+ iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+int iwl_grab_nic_access(struct iwl_priv *priv)
+{
+ int ret = iwl_grab_nic_access_silent(priv);
+ if (ret) {
+ u32 val = iwl_read32(priv, CSR_GP_CNTRL);
+ IWL_ERR(priv,
+ "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val);
+ }
+
+ return ret;
+}
+
+void iwl_release_nic_access(struct iwl_priv *priv)
+{
+ lockdep_assert_held(&priv->reg_lock);
+ __iwl_clear_bit(priv, CSR_GP_CNTRL,
+ CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+}
+
+u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg)
+{
+ u32 value;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->reg_lock, flags);
+ iwl_grab_nic_access(priv);
+ value = iwl_read32(priv, reg);
+ iwl_release_nic_access(priv);
+ spin_unlock_irqrestore(&priv->reg_lock, flags);
+
+ return value;
+}
+
+void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->reg_lock, flags);
+ if (!iwl_grab_nic_access(priv)) {
+ iwl_write32(priv, reg, value);
+ iwl_release_nic_access(priv);
+ }
+ spin_unlock_irqrestore(&priv->reg_lock, flags);
+}
+
+int iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask,
+ int timeout)
+{
+ int t = 0;
+
+ do {
+ if ((iwl_read_direct32(priv, addr) & mask) == mask)
+ return t;
+ udelay(IWL_POLL_INTERVAL);
+ t += IWL_POLL_INTERVAL;
+ } while (t < timeout);
+
+ return -ETIMEDOUT;
+}
+
+static inline u32 __iwl_read_prph(struct iwl_priv *priv, u32 reg)
+{
+ iwl_write32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
+ rmb();
+ return iwl_read32(priv, HBUS_TARG_PRPH_RDAT);
+}
+
+static inline void __iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val)
+{
+ iwl_write32(priv, HBUS_TARG_PRPH_WADDR,
+ ((addr & 0x0000FFFF) | (3 << 24)));
+ wmb();
+ iwl_write32(priv, HBUS_TARG_PRPH_WDAT, val);
+}
+
+u32 iwl_read_prph(struct iwl_priv *priv, u32 reg)
+{
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&priv->reg_lock, flags);
+ iwl_grab_nic_access(priv);
+ val = __iwl_read_prph(priv, reg);
+ iwl_release_nic_access(priv);
+ spin_unlock_irqrestore(&priv->reg_lock, flags);
+ return val;
+}
+
+void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->reg_lock, flags);
+ if (!iwl_grab_nic_access(priv)) {
+ __iwl_write_prph(priv, addr, val);
+ iwl_release_nic_access(priv);
+ }
+ spin_unlock_irqrestore(&priv->reg_lock, flags);
+}
+
+void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->reg_lock, flags);
+ iwl_grab_nic_access(priv);
+ __iwl_write_prph(priv, reg, __iwl_read_prph(priv, reg) | mask);
+ iwl_release_nic_access(priv);
+ spin_unlock_irqrestore(&priv->reg_lock, flags);
+}
+
+void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg,
+ u32 bits, u32 mask)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->reg_lock, flags);
+ iwl_grab_nic_access(priv);
+ __iwl_write_prph(priv, reg,
+ (__iwl_read_prph(priv, reg) & mask) | bits);
+ iwl_release_nic_access(priv);
+ spin_unlock_irqrestore(&priv->reg_lock, flags);
+}
+
+void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask)
+{
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&priv->reg_lock, flags);
+ iwl_grab_nic_access(priv);
+ val = __iwl_read_prph(priv, reg);
+ __iwl_write_prph(priv, reg, (val & ~mask));
+ iwl_release_nic_access(priv);
+ spin_unlock_irqrestore(&priv->reg_lock, flags);
+}
+
+void _iwl_read_targ_mem_words(struct iwl_priv *priv, u32 addr,
+ void *buf, int words)
+{
+ unsigned long flags;
+ int offs;
+ u32 *vals = buf;
+
+ spin_lock_irqsave(&priv->reg_lock, flags);
+ iwl_grab_nic_access(priv);
+
+ iwl_write32(priv, HBUS_TARG_MEM_RADDR, addr);
+ rmb();
+
+ for (offs = 0; offs < words; offs++)
+ vals[offs] = iwl_read32(priv, HBUS_TARG_MEM_RDAT);
+
+ iwl_release_nic_access(priv);
+ spin_unlock_irqrestore(&priv->reg_lock, flags);
+}
+
+u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr)
+{
+ u32 value;
+
+ _iwl_read_targ_mem_words(priv, addr, &value, 1);
+
+ return value;
+}
+
+void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->reg_lock, flags);
+ if (!iwl_grab_nic_access(priv)) {
+ iwl_write32(priv, HBUS_TARG_MEM_WADDR, addr);
+ wmb();
+ iwl_write32(priv, HBUS_TARG_MEM_WDAT, val);
+ iwl_release_nic_access(priv);
+ }
+ spin_unlock_irqrestore(&priv->reg_lock, flags);
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h
index 0203a3bbf872..869edc580ec6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.h
+++ b/drivers/net/wireless/iwlwifi/iwl-io.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project.
*
@@ -35,494 +35,58 @@
#include "iwl-debug.h"
#include "iwl-devtrace.h"
-/*
- * IO, register, and NIC memory access functions
- *
- * NOTE on naming convention and macro usage for these
- *
- * A single _ prefix before a an access function means that no state
- * check or debug information is printed when that function is called.
- *
- * A double __ prefix before an access function means that state is checked
- * and the current line number and caller function name are printed in addition
- * to any other debug output.
- *
- * The non-prefixed name is the #define that maps the caller into a
- * #define that provides the caller's name and __LINE__ to the double
- * prefix version.
- *
- * If you wish to call the function without any debug or state checking,
- * you should use the single _ prefix version (as is used by dependent IO
- * routines, for example _iwl_read_direct32 calls the non-check version of
- * _iwl_read32.)
- *
- * These declarations are *extremely* useful in quickly isolating code deltas
- * which result in misconfiguration of the hardware I/O. In combination with
- * git-bisect and the IO debug level you can quickly determine the specific
- * commit which breaks the IO sequence to the hardware.
- *
- */
-
-static inline void _iwl_write8(struct iwl_priv *priv, u32 ofs, u8 val)
+static inline void iwl_write8(struct iwl_priv *priv, u32 ofs, u8 val)
{
trace_iwlwifi_dev_iowrite8(priv, ofs, val);
iowrite8(val, priv->hw_base + ofs);
}
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline void __iwl_write8(const char *f, u32 l, struct iwl_priv *priv,
- u32 ofs, u8 val)
-{
- IWL_DEBUG_IO(priv, "write8(0x%08X, 0x%02X) - %s %d\n", ofs, val, f, l);
- _iwl_write8(priv, ofs, val);
-}
-#define iwl_write8(priv, ofs, val) \
- __iwl_write8(__FILE__, __LINE__, priv, ofs, val)
-#else
-#define iwl_write8(priv, ofs, val) _iwl_write8(priv, ofs, val)
-#endif
-
-
-static inline void _iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val)
+static inline void iwl_write32(struct iwl_priv *priv, u32 ofs, u32 val)
{
trace_iwlwifi_dev_iowrite32(priv, ofs, val);
iowrite32(val, priv->hw_base + ofs);
}
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline void __iwl_write32(const char *f, u32 l, struct iwl_priv *priv,
- u32 ofs, u32 val)
-{
- IWL_DEBUG_IO(priv, "write32(0x%08X, 0x%08X) - %s %d\n", ofs, val, f, l);
- _iwl_write32(priv, ofs, val);
-}
-#define iwl_write32(priv, ofs, val) \
- __iwl_write32(__FILE__, __LINE__, priv, ofs, val)
-#else
-#define iwl_write32(priv, ofs, val) _iwl_write32(priv, ofs, val)
-#endif
-
-static inline u32 _iwl_read32(struct iwl_priv *priv, u32 ofs)
+static inline u32 iwl_read32(struct iwl_priv *priv, u32 ofs)
{
u32 val = ioread32(priv->hw_base + ofs);
trace_iwlwifi_dev_ioread32(priv, ofs, val);
return val;
}
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *priv, u32 ofs)
-{
- IWL_DEBUG_IO(priv, "read_direct32(0x%08X) - %s %d\n", ofs, f, l);
- return _iwl_read32(priv, ofs);
-}
-#define iwl_read32(priv, ofs) __iwl_read32(__FILE__, __LINE__, priv, ofs)
-#else
-#define iwl_read32(p, o) _iwl_read32(p, o)
-#endif
-
-#define IWL_POLL_INTERVAL 10 /* microseconds */
-static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr,
- u32 bits, u32 mask, int timeout)
-{
- int t = 0;
-
- do {
- if ((_iwl_read32(priv, addr) & mask) == (bits & mask))
- return t;
- udelay(IWL_POLL_INTERVAL);
- t += IWL_POLL_INTERVAL;
- } while (t < timeout);
-
- return -ETIMEDOUT;
-}
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline int __iwl_poll_bit(const char *f, u32 l,
- struct iwl_priv *priv, u32 addr,
- u32 bits, u32 mask, int timeout)
-{
- int ret = _iwl_poll_bit(priv, addr, bits, mask, timeout);
- IWL_DEBUG_IO(priv, "poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n",
- addr, bits, mask,
- unlikely(ret == -ETIMEDOUT) ? "timeout" : "", f, l);
- return ret;
-}
-#define iwl_poll_bit(priv, addr, bits, mask, timeout) \
- __iwl_poll_bit(__FILE__, __LINE__, priv, addr, bits, mask, timeout)
-#else
-#define iwl_poll_bit(p, a, b, m, t) _iwl_poll_bit(p, a, b, m, t)
-#endif
-
-static inline void _iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask)
-{
- _iwl_write32(priv, reg, _iwl_read32(priv, reg) | mask);
-}
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline void __iwl_set_bit(const char *f, u32 l,
- struct iwl_priv *priv, u32 reg, u32 mask)
-{
- u32 val = _iwl_read32(priv, reg) | mask;
- IWL_DEBUG_IO(priv, "set_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
- _iwl_write32(priv, reg, val);
-}
-static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m)
-{
- unsigned long reg_flags;
-
- spin_lock_irqsave(&p->reg_lock, reg_flags);
- __iwl_set_bit(__FILE__, __LINE__, p, r, m);
- spin_unlock_irqrestore(&p->reg_lock, reg_flags);
-}
-#else
-static inline void iwl_set_bit(struct iwl_priv *p, u32 r, u32 m)
-{
- unsigned long reg_flags;
-
- spin_lock_irqsave(&p->reg_lock, reg_flags);
- _iwl_set_bit(p, r, m);
- spin_unlock_irqrestore(&p->reg_lock, reg_flags);
-}
-#endif
-
-static inline void _iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask)
-{
- _iwl_write32(priv, reg, _iwl_read32(priv, reg) & ~mask);
-}
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline void __iwl_clear_bit(const char *f, u32 l,
- struct iwl_priv *priv, u32 reg, u32 mask)
-{
- u32 val = _iwl_read32(priv, reg) & ~mask;
- IWL_DEBUG_IO(priv, "clear_bit(0x%08X, 0x%08X) = 0x%08X\n", reg, mask, val);
- _iwl_write32(priv, reg, val);
-}
-static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m)
-{
- unsigned long reg_flags;
-
- spin_lock_irqsave(&p->reg_lock, reg_flags);
- __iwl_clear_bit(__FILE__, __LINE__, p, r, m);
- spin_unlock_irqrestore(&p->reg_lock, reg_flags);
-}
-#else
-static inline void iwl_clear_bit(struct iwl_priv *p, u32 r, u32 m)
-{
- unsigned long reg_flags;
-
- spin_lock_irqsave(&p->reg_lock, reg_flags);
- _iwl_clear_bit(p, r, m);
- spin_unlock_irqrestore(&p->reg_lock, reg_flags);
-}
-#endif
-
-static inline int _iwl_grab_nic_access(struct iwl_priv *priv)
-{
- int ret;
- u32 val;
-
- /* this bit wakes up the NIC */
- _iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-
- /*
- * These bits say the device is running, and should keep running for
- * at least a short while (at least as long as MAC_ACCESS_REQ stays 1),
- * but they do not indicate that embedded SRAM is restored yet;
- * 3945 and 4965 have volatile SRAM, and must save/restore contents
- * to/from host DRAM when sleeping/waking for power-saving.
- * Each direction takes approximately 1/4 millisecond; with this
- * overhead, it's a good idea to grab and hold MAC_ACCESS_REQUEST if a
- * series of register accesses are expected (e.g. reading Event Log),
- * to keep device from sleeping.
- *
- * CSR_UCODE_DRV_GP1 register bit MAC_SLEEP == 0 indicates that
- * SRAM is okay/restored. We don't check that here because this call
- * is just for hardware register access; but GP1 MAC_SLEEP check is a
- * good idea before accessing 3945/4965 SRAM (e.g. reading Event Log).
- *
- * 5000 series and later (including 1000 series) have non-volatile SRAM,
- * and do not save/restore SRAM when power cycling.
- */
- ret = _iwl_poll_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
- (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
- CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000);
- if (ret < 0) {
- val = _iwl_read32(priv, CSR_GP_CNTRL);
- IWL_ERR(priv, "MAC is in deep sleep!. CSR_GP_CNTRL = 0x%08X\n", val);
- _iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_FORCE_NMI);
- return -EIO;
- }
-
- return 0;
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline int __iwl_grab_nic_access(const char *f, u32 l,
- struct iwl_priv *priv)
-{
- IWL_DEBUG_IO(priv, "grabbing nic access - %s %d\n", f, l);
- return _iwl_grab_nic_access(priv);
-}
-#define iwl_grab_nic_access(priv) \
- __iwl_grab_nic_access(__FILE__, __LINE__, priv)
-#else
-#define iwl_grab_nic_access(priv) \
- _iwl_grab_nic_access(priv)
-#endif
-
-static inline void _iwl_release_nic_access(struct iwl_priv *priv)
-{
- _iwl_clear_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-}
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline void __iwl_release_nic_access(const char *f, u32 l,
- struct iwl_priv *priv)
-{
-
- IWL_DEBUG_IO(priv, "releasing nic access - %s %d\n", f, l);
- _iwl_release_nic_access(priv);
-}
-#define iwl_release_nic_access(priv) \
- __iwl_release_nic_access(__FILE__, __LINE__, priv)
-#else
-#define iwl_release_nic_access(priv) \
- _iwl_release_nic_access(priv)
-#endif
-
-static inline u32 _iwl_read_direct32(struct iwl_priv *priv, u32 reg)
-{
- return _iwl_read32(priv, reg);
-}
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline u32 __iwl_read_direct32(const char *f, u32 l,
- struct iwl_priv *priv, u32 reg)
-{
- u32 value = _iwl_read_direct32(priv, reg);
- IWL_DEBUG_IO(priv, "read_direct32(0x%4X) = 0x%08x - %s %d\n", reg, value,
- f, l);
- return value;
-}
-static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg)
-{
- u32 value;
- unsigned long reg_flags;
-
- spin_lock_irqsave(&priv->reg_lock, reg_flags);
- iwl_grab_nic_access(priv);
- value = __iwl_read_direct32(__FILE__, __LINE__, priv, reg);
- iwl_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
- return value;
-}
-
-#else
-static inline u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg)
-{
- u32 value;
- unsigned long reg_flags;
-
- spin_lock_irqsave(&priv->reg_lock, reg_flags);
- iwl_grab_nic_access(priv);
- value = _iwl_read_direct32(priv, reg);
- iwl_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
- return value;
-
-}
-#endif
-
-static inline void _iwl_write_direct32(struct iwl_priv *priv,
- u32 reg, u32 value)
-{
- _iwl_write32(priv, reg, value);
-}
-static inline void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value)
-{
- unsigned long reg_flags;
-
- spin_lock_irqsave(&priv->reg_lock, reg_flags);
- if (!iwl_grab_nic_access(priv)) {
- _iwl_write_direct32(priv, reg, value);
- iwl_release_nic_access(priv);
- }
- spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
-}
-
-static inline void iwl_write_reg_buf(struct iwl_priv *priv,
- u32 reg, u32 len, u32 *values)
-{
- u32 count = sizeof(u32);
-
- if ((priv != NULL) && (values != NULL)) {
- for (; 0 < len; len -= count, reg += count, values++)
- iwl_write_direct32(priv, reg, *values);
- }
-}
-
-static inline int _iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr,
- u32 mask, int timeout)
-{
- int t = 0;
-
- do {
- if ((iwl_read_direct32(priv, addr) & mask) == mask)
- return t;
- udelay(IWL_POLL_INTERVAL);
- t += IWL_POLL_INTERVAL;
- } while (t < timeout);
-
- return -ETIMEDOUT;
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-static inline int __iwl_poll_direct_bit(const char *f, u32 l,
- struct iwl_priv *priv,
- u32 addr, u32 mask, int timeout)
-{
- int ret = _iwl_poll_direct_bit(priv, addr, mask, timeout);
-
- if (unlikely(ret == -ETIMEDOUT))
- IWL_DEBUG_IO(priv, "poll_direct_bit(0x%08X, 0x%08X) - "
- "timedout - %s %d\n", addr, mask, f, l);
- else
- IWL_DEBUG_IO(priv, "poll_direct_bit(0x%08X, 0x%08X) = 0x%08X "
- "- %s %d\n", addr, mask, ret, f, l);
- return ret;
-}
-#define iwl_poll_direct_bit(priv, addr, mask, timeout) \
- __iwl_poll_direct_bit(__FILE__, __LINE__, priv, addr, mask, timeout)
-#else
-#define iwl_poll_direct_bit _iwl_poll_direct_bit
-#endif
-
-static inline u32 _iwl_read_prph(struct iwl_priv *priv, u32 reg)
-{
- _iwl_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24));
- rmb();
- return _iwl_read_direct32(priv, HBUS_TARG_PRPH_RDAT);
-}
-static inline u32 iwl_read_prph(struct iwl_priv *priv, u32 reg)
-{
- unsigned long reg_flags;
- u32 val;
-
- spin_lock_irqsave(&priv->reg_lock, reg_flags);
- iwl_grab_nic_access(priv);
- val = _iwl_read_prph(priv, reg);
- iwl_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
- return val;
-}
-
-static inline void _iwl_write_prph(struct iwl_priv *priv,
- u32 addr, u32 val)
-{
- _iwl_write_direct32(priv, HBUS_TARG_PRPH_WADDR,
- ((addr & 0x0000FFFF) | (3 << 24)));
- wmb();
- _iwl_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val);
-}
-
-static inline void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val)
-{
- unsigned long reg_flags;
-
- spin_lock_irqsave(&priv->reg_lock, reg_flags);
- if (!iwl_grab_nic_access(priv)) {
- _iwl_write_prph(priv, addr, val);
- iwl_release_nic_access(priv);
- }
- spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
-}
-
-#define _iwl_set_bits_prph(priv, reg, mask) \
- _iwl_write_prph(priv, reg, (_iwl_read_prph(priv, reg) | mask))
-
-static inline void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask)
-{
- unsigned long reg_flags;
-
- spin_lock_irqsave(&priv->reg_lock, reg_flags);
- iwl_grab_nic_access(priv);
- _iwl_set_bits_prph(priv, reg, mask);
- iwl_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
-}
-
-#define _iwl_set_bits_mask_prph(priv, reg, bits, mask) \
- _iwl_write_prph(priv, reg, ((_iwl_read_prph(priv, reg) & mask) | bits))
+void iwl_set_bit(struct iwl_priv *priv, u32 reg, u32 mask);
+void iwl_clear_bit(struct iwl_priv *priv, u32 reg, u32 mask);
-static inline void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg,
- u32 bits, u32 mask)
-{
- unsigned long reg_flags;
+int iwl_poll_bit(struct iwl_priv *priv, u32 addr,
+ u32 bits, u32 mask, int timeout);
+int iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, u32 mask,
+ int timeout);
- spin_lock_irqsave(&priv->reg_lock, reg_flags);
- iwl_grab_nic_access(priv);
- _iwl_set_bits_mask_prph(priv, reg, bits, mask);
- iwl_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
-}
+int iwl_grab_nic_access_silent(struct iwl_priv *priv);
+int iwl_grab_nic_access(struct iwl_priv *priv);
+void iwl_release_nic_access(struct iwl_priv *priv);
-static inline void iwl_clear_bits_prph(struct iwl_priv
- *priv, u32 reg, u32 mask)
-{
- unsigned long reg_flags;
- u32 val;
+u32 iwl_read_direct32(struct iwl_priv *priv, u32 reg);
+void iwl_write_direct32(struct iwl_priv *priv, u32 reg, u32 value);
- spin_lock_irqsave(&priv->reg_lock, reg_flags);
- iwl_grab_nic_access(priv);
- val = _iwl_read_prph(priv, reg);
- _iwl_write_prph(priv, reg, (val & ~mask));
- iwl_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
-}
-
-static inline u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr)
-{
- unsigned long reg_flags;
- u32 value;
- spin_lock_irqsave(&priv->reg_lock, reg_flags);
- iwl_grab_nic_access(priv);
+u32 iwl_read_prph(struct iwl_priv *priv, u32 reg);
+void iwl_write_prph(struct iwl_priv *priv, u32 addr, u32 val);
+void iwl_set_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask);
+void iwl_set_bits_mask_prph(struct iwl_priv *priv, u32 reg,
+ u32 bits, u32 mask);
+void iwl_clear_bits_prph(struct iwl_priv *priv, u32 reg, u32 mask);
- _iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr);
- rmb();
- value = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+void _iwl_read_targ_mem_words(struct iwl_priv *priv, u32 addr,
+ void *buf, int words);
- iwl_release_nic_access(priv);
- spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
- return value;
-}
+#define iwl_read_targ_mem_words(priv, addr, buf, bufsize) \
+ do { \
+ BUILD_BUG_ON((bufsize) % sizeof(u32)); \
+ _iwl_read_targ_mem_words(priv, addr, buf, \
+ (bufsize) / sizeof(u32));\
+ } while (0)
-static inline void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val)
-{
- unsigned long reg_flags;
-
- spin_lock_irqsave(&priv->reg_lock, reg_flags);
- if (!iwl_grab_nic_access(priv)) {
- _iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
- wmb();
- _iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, val);
- iwl_release_nic_access(priv);
- }
- spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
-}
-
-static inline void iwl_write_targ_mem_buf(struct iwl_priv *priv, u32 addr,
- u32 len, u32 *values)
-{
- unsigned long reg_flags;
-
- spin_lock_irqsave(&priv->reg_lock, reg_flags);
- if (!iwl_grab_nic_access(priv)) {
- _iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr);
- wmb();
- for (; 0 < len; len -= sizeof(u32), values++)
- _iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values);
-
- iwl_release_nic_access(priv);
- }
- spin_unlock_irqrestore(&priv->reg_lock, reg_flags);
-}
+u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr);
+void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val);
#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
index d7f2a0bb32c9..7c23beb49d7c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 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
@@ -48,8 +48,21 @@ module_param(led_mode, int, S_IRUGO);
MODULE_PARM_DESC(led_mode, "0=system default, "
"1=On(RF On)/Off(RF Off), 2=blinking");
+/* Throughput OFF time(ms) ON time (ms)
+ * >300 25 25
+ * >200 to 300 40 40
+ * >100 to 200 55 55
+ * >70 to 100 65 65
+ * >50 to 70 75 75
+ * >20 to 50 85 85
+ * >10 to 20 95 95
+ * >5 to 10 110 110
+ * >1 to 5 130 130
+ * >0 to 1 167 167
+ * <=0 SOLID ON
+ */
static const struct ieee80211_tpt_blink iwl_blink[] = {
- { .throughput = 0 * 1024 - 1, .blink_time = 334 },
+ { .throughput = 0, .blink_time = 334 },
{ .throughput = 1 * 1024 - 1, .blink_time = 260 },
{ .throughput = 5 * 1024 - 1, .blink_time = 220 },
{ .throughput = 10 * 1024 - 1, .blink_time = 190 },
@@ -61,10 +74,16 @@ static const struct ieee80211_tpt_blink iwl_blink[] = {
{ .throughput = 300 * 1024 - 1, .blink_time = 50 },
};
+/* Set led register off */
+void iwlagn_led_enable(struct iwl_priv *priv)
+{
+ iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
+}
+
/*
* Adjust led blink rate to compensate on a MAC Clock difference on every HW
- * Led blink rate analysis showed an average deviation of 0% on 3945,
- * 5% on 4965 HW and 20% on 5000 series and up.
+ * Led blink rate analysis showed an average deviation of 20% on 5000 series
+ * and up.
* Need to compensate on the led on/off time per HW according to the deviation
* to achieve the desired led frequency
* The calculation is: (100-averageDeviation)/100 * blinkTime
@@ -84,6 +103,24 @@ static inline u8 iwl_blink_compensation(struct iwl_priv *priv,
return (u8)((time * compensation) >> 6);
}
+static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
+{
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_LEDS_CMD,
+ .len = { sizeof(struct iwl_led_cmd), },
+ .data = { led_cmd, },
+ .flags = CMD_ASYNC,
+ .callback = NULL,
+ };
+ u32 reg;
+
+ reg = iwl_read32(priv, CSR_LED_REG);
+ if (reg != (reg & CSR_LED_BSM_CTRL_MSK))
+ iwl_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK);
+
+ return iwl_send_cmd(priv, &cmd);
+}
+
/* Set led pattern command */
static int iwl_led_cmd(struct iwl_priv *priv,
unsigned long on,
@@ -101,6 +138,11 @@ static int iwl_led_cmd(struct iwl_priv *priv,
if (priv->blink_on == on && priv->blink_off == off)
return 0;
+ if (off == 0) {
+ /* led is SOLID_ON */
+ on = IWL_LED_SOLID;
+ }
+
IWL_DEBUG_LED(priv, "Led blink time compensation=%u\n",
priv->cfg->base_params->led_compensation);
led_cmd.on = iwl_blink_compensation(priv, on,
@@ -108,7 +150,7 @@ static int iwl_led_cmd(struct iwl_priv *priv,
led_cmd.off = iwl_blink_compensation(priv, off,
priv->cfg->base_params->led_compensation);
- ret = priv->cfg->ops->led->cmd(priv, &led_cmd);
+ ret = iwl_send_led_cmd(priv, &led_cmd);
if (!ret) {
priv->blink_on = on;
priv->blink_off = off;
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h
index 101eef12b3bb..1c93dfef6933 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.h
+++ b/drivers/net/wireless/iwlwifi/iwl-led.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 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
@@ -50,6 +50,7 @@ enum iwl_led_mode {
IWL_LED_BLINK,
};
+void iwlagn_led_enable(struct iwl_priv *priv);
void iwl_leds_init(struct iwl_priv *priv);
void iwl_leds_exit(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c
index 576795e2c75b..595c930b28ae 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
@@ -188,9 +188,10 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
table = range_0;
}
- BUG_ON(lvl < 0 || lvl >= IWL_POWER_NUM);
-
- *cmd = table[lvl].cmd;
+ if (WARN_ON(lvl < 0 || lvl >= IWL_POWER_NUM))
+ memset(cmd, 0, sizeof(*cmd));
+ else
+ *cmd = table[lvl].cmd;
if (period == 0) {
skip = 0;
@@ -354,16 +355,12 @@ static void iwl_power_build_cmd(struct iwl_priv *priv,
dtimper = priv->hw->conf.ps_dtim_period ?: 1;
- if (priv->cfg->base_params->broken_powersave)
- iwl_power_sleep_cam_cmd(priv, cmd);
- else if (priv->hw->conf.flags & IEEE80211_CONF_IDLE)
+ if (priv->hw->conf.flags & IEEE80211_CONF_IDLE)
iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_5, 20);
- else if (priv->cfg->ops->lib->tt_ops.lower_power_detection &&
- priv->cfg->ops->lib->tt_ops.tt_power_mode &&
- priv->cfg->ops->lib->tt_ops.lower_power_detection(priv)) {
+ else if (iwl_tt_is_low_power_state(priv)) {
/* in thermal throttling low power state */
iwl_static_sleep_cmd(priv, cmd,
- priv->cfg->ops->lib->tt_ops.tt_power_mode(priv), dtimper);
+ iwl_tt_current_power_mode(priv), dtimper);
} else if (!enabled)
iwl_power_sleep_cam_cmd(priv, cmd);
else if (priv->power_data.debug_sleep_level_override >= 0)
diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h
index fe012032c28c..59635d784e27 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.h
+++ b/drivers/net/wireless/iwlwifi/iwl-power.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2007 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2011 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index 86f5123bccda..f00d188b2cfc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -5,7 +5,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 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
@@ -30,7 +30,7 @@
*
* BSD LICENSE
*
- * Copyright(c) 2005 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -91,7 +91,6 @@
#define APMG_PS_CTRL_VAL_RESET_REQ (0x04000000)
#define APMG_PS_CTRL_MSK_PWR_SRC (0x03000000)
#define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000)
-#define APMG_PS_CTRL_VAL_PWR_SRC_MAX (0x01000000) /* 3945 only */
#define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x02000000)
#define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */
#define APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060)
@@ -99,152 +98,6 @@
#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800)
/**
- * BSM (Bootstrap State Machine)
- *
- * The Bootstrap State Machine (BSM) stores a short bootstrap uCode program
- * in special SRAM that does not power down when the embedded control
- * processor is sleeping (e.g. for periodic power-saving shutdowns of radio).
- *
- * When powering back up after sleeps (or during initial uCode load), the BSM
- * internally loads the short bootstrap program from the special SRAM into the
- * embedded processor's instruction SRAM, and starts the processor so it runs
- * the bootstrap program.
- *
- * This bootstrap program loads (via PCI busmaster DMA) instructions and data
- * images for a uCode program from host DRAM locations. The host driver
- * indicates DRAM locations and sizes for instruction and data images via the
- * four BSM_DRAM_* registers. Once the bootstrap program loads the new program,
- * the new program starts automatically.
- *
- * The uCode used for open-source drivers includes two programs:
- *
- * 1) Initialization -- performs hardware calibration and sets up some
- * internal data, then notifies host via "initialize alive" notification
- * (struct iwl_init_alive_resp) that it has completed all of its work.
- * After signal from host, it then loads and starts the runtime program.
- * The initialization program must be used when initially setting up the
- * NIC after loading the driver.
- *
- * 2) Runtime/Protocol -- performs all normal runtime operations. This
- * notifies host via "alive" notification (struct iwl_alive_resp) that it
- * is ready to be used.
- *
- * When initializing the NIC, the host driver does the following procedure:
- *
- * 1) Load bootstrap program (instructions only, no data image for bootstrap)
- * into bootstrap memory. Use dword writes starting at BSM_SRAM_LOWER_BOUND
- *
- * 2) Point (via BSM_DRAM_*) to the "initialize" uCode data and instruction
- * images in host DRAM.
- *
- * 3) Set up BSM to copy from BSM SRAM into uCode instruction SRAM when asked:
- * BSM_WR_MEM_SRC_REG = 0
- * BSM_WR_MEM_DST_REG = RTC_INST_LOWER_BOUND
- * BSM_WR_MEM_DWCOUNT_REG = # dwords in bootstrap instruction image
- *
- * 4) Load bootstrap into instruction SRAM:
- * BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START
- *
- * 5) Wait for load completion:
- * Poll BSM_WR_CTRL_REG for BSM_WR_CTRL_REG_BIT_START = 0
- *
- * 6) Enable future boot loads whenever NIC's power management triggers it:
- * BSM_WR_CTRL_REG = BSM_WR_CTRL_REG_BIT_START_EN
- *
- * 7) Start the NIC by removing all reset bits:
- * CSR_RESET = 0
- *
- * The bootstrap uCode (already in instruction SRAM) loads initialization
- * uCode. Initialization uCode performs data initialization, sends
- * "initialize alive" notification to host, and waits for a signal from
- * host to load runtime code.
- *
- * 4) Point (via BSM_DRAM_*) to the "runtime" uCode data and instruction
- * images in host DRAM. The last register loaded must be the instruction
- * byte count register ("1" in MSbit tells initialization uCode to load
- * the runtime uCode):
- * BSM_DRAM_INST_BYTECOUNT_REG = byte count | BSM_DRAM_INST_LOAD
- *
- * 5) Wait for "alive" notification, then issue normal runtime commands.
- *
- * Data caching during power-downs:
- *
- * Just before the embedded controller powers down (e.g for automatic
- * power-saving modes, or for RFKILL), uCode stores (via PCI busmaster DMA)
- * a current snapshot of the embedded processor's data SRAM into host DRAM.
- * This caches the data while the embedded processor's memory is powered down.
- * Location and size are controlled by BSM_DRAM_DATA_* registers.
- *
- * NOTE: Instruction SRAM does not need to be saved, since that doesn't
- * change during operation; the original image (from uCode distribution
- * file) can be used for reload.
- *
- * When powering back up, the BSM loads the bootstrap program. Bootstrap looks
- * at the BSM_DRAM_* registers, which now point to the runtime instruction
- * image and the cached (modified) runtime data (*not* the initialization
- * uCode). Bootstrap reloads these runtime images into SRAM, and restarts the
- * uCode from where it left off before the power-down.
- *
- * NOTE: Initialization uCode does *not* run as part of the save/restore
- * procedure.
- *
- * This save/restore method is mostly for autonomous power management during
- * normal operation (result of POWER_TABLE_CMD). Platform suspend/resume and
- * RFKILL should use complete restarts (with total re-initialization) of uCode,
- * allowing total shutdown (including BSM memory).
- *
- * Note that, during normal operation, the host DRAM that held the initial
- * startup data for the runtime code is now being used as a backup data cache
- * for modified data! If you need to completely re-initialize the NIC, make
- * sure that you use the runtime data image from the uCode distribution file,
- * not the modified/saved runtime data. You may want to store a separate
- * "clean" runtime data image in DRAM to avoid disk reads of distribution file.
- */
-
-/* BSM bit fields */
-#define BSM_WR_CTRL_REG_BIT_START (0x80000000) /* start boot load now */
-#define BSM_WR_CTRL_REG_BIT_START_EN (0x40000000) /* enable boot after pwrup*/
-#define BSM_DRAM_INST_LOAD (0x80000000) /* start program load now */
-
-/* BSM addresses */
-#define BSM_BASE (PRPH_BASE + 0x3400)
-#define BSM_END (PRPH_BASE + 0x3800)
-
-#define BSM_WR_CTRL_REG (BSM_BASE + 0x000) /* ctl and status */
-#define BSM_WR_MEM_SRC_REG (BSM_BASE + 0x004) /* source in BSM mem */
-#define BSM_WR_MEM_DST_REG (BSM_BASE + 0x008) /* dest in SRAM mem */
-#define BSM_WR_DWCOUNT_REG (BSM_BASE + 0x00C) /* bytes */
-#define BSM_WR_STATUS_REG (BSM_BASE + 0x010) /* bit 0: 1 == done */
-
-/*
- * Pointers and size regs for bootstrap load and data SRAM save/restore.
- * NOTE: 3945 pointers use bits 31:0 of DRAM address.
- * 4965 pointers use bits 35:4 of DRAM address.
- */
-#define BSM_DRAM_INST_PTR_REG (BSM_BASE + 0x090)
-#define BSM_DRAM_INST_BYTECOUNT_REG (BSM_BASE + 0x094)
-#define BSM_DRAM_DATA_PTR_REG (BSM_BASE + 0x098)
-#define BSM_DRAM_DATA_BYTECOUNT_REG (BSM_BASE + 0x09C)
-
-/*
- * BSM special memory, stays powered on during power-save sleeps.
- * Read/write, address range from LOWER_BOUND to (LOWER_BOUND + SIZE -1)
- */
-#define BSM_SRAM_LOWER_BOUND (PRPH_BASE + 0x3800)
-#define BSM_SRAM_SIZE (1024) /* bytes */
-
-
-/* 3945 Tx scheduler registers */
-#define ALM_SCD_BASE (PRPH_BASE + 0x2E00)
-#define ALM_SCD_MODE_REG (ALM_SCD_BASE + 0x000)
-#define ALM_SCD_ARASTAT_REG (ALM_SCD_BASE + 0x004)
-#define ALM_SCD_TXFACT_REG (ALM_SCD_BASE + 0x010)
-#define ALM_SCD_TXF4MF_REG (ALM_SCD_BASE + 0x014)
-#define ALM_SCD_TXF5MF_REG (ALM_SCD_BASE + 0x020)
-#define ALM_SCD_SBYP_MODE_1_REG (ALM_SCD_BASE + 0x02C)
-#define ALM_SCD_SBYP_MODE_2_REG (ALM_SCD_BASE + 0x030)
-
-/**
* Tx Scheduler
*
* The Tx Scheduler selects the next frame to be transmitted, choosing TFDs
@@ -254,17 +107,7 @@
* device. A queue maps to only one (selectable by driver) Tx DMA channel,
* but one DMA channel may take input from several queues.
*
- * Tx DMA FIFOs have dedicated purposes. For 4965, they are used as follows
- * (cf. default_queue_to_tx_fifo in iwl-4965.c):
- *
- * 0 -- EDCA BK (background) frames, lowest priority
- * 1 -- EDCA BE (best effort) frames, normal priority
- * 2 -- EDCA VI (video) frames, higher priority
- * 3 -- EDCA VO (voice) and management frames, highest priority
- * 4 -- Commands (e.g. RXON, etc.)
- * 5 -- unused (HCCA)
- * 6 -- unused (HCCA)
- * 7 -- not used by driver (device-internal only)
+ * Tx DMA FIFOs have dedicated purposes.
*
* For 5000 series and up, they are used differently
* (cf. iwl5000_default_queue_to_tx_fifo in iwl-5000.c):
@@ -298,7 +141,7 @@
* Tx completion may end up being out-of-order).
*
* The driver must maintain the queue's Byte Count table in host DRAM
- * (struct iwl4965_sched_queue_byte_cnt_tbl) for this mode.
+ * for this mode.
* This mode does not support fragmentation.
*
* 2) FIFO (a.k.a. non-Scheduler-ACK), in which each TFD is processed in order.
@@ -311,7 +154,7 @@
*
* Driver controls scheduler operation via 3 means:
* 1) Scheduler registers
- * 2) Shared scheduler data base in internal 4956 SRAM
+ * 2) Shared scheduler data base in internal SRAM
* 3) Shared data in host DRAM
*
* Initialization:
@@ -330,201 +173,10 @@
* Max Tx window size is the max number of contiguous TFDs that the scheduler
* can keep track of at one time when creating block-ack chains of frames.
* Note that "64" matches the number of ack bits in a block-ack packet.
- * Driver should use SCD_WIN_SIZE and SCD_FRAME_LIMIT values to initialize
- * IWL49_SCD_CONTEXT_QUEUE_OFFSET(x) values.
*/
#define SCD_WIN_SIZE 64
#define SCD_FRAME_LIMIT 64
-/* SCD registers are internal, must be accessed via HBUS_TARG_PRPH regs */
-#define IWL49_SCD_START_OFFSET 0xa02c00
-
-/*
- * 4965 tells driver SRAM address for internal scheduler structs via this reg.
- * Value is valid only after "Alive" response from uCode.
- */
-#define IWL49_SCD_SRAM_BASE_ADDR (IWL49_SCD_START_OFFSET + 0x0)
-
-/*
- * Driver may need to update queue-empty bits after changing queue's
- * write and read pointers (indexes) during (re-)initialization (i.e. when
- * scheduler is not tracking what's happening).
- * Bit fields:
- * 31-16: Write mask -- 1: update empty bit, 0: don't change empty bit
- * 15-00: Empty state, one for each queue -- 1: empty, 0: non-empty
- * NOTE: This register is not used by Linux driver.
- */
-#define IWL49_SCD_EMPTY_BITS (IWL49_SCD_START_OFFSET + 0x4)
-
-/*
- * Physical base address of array of byte count (BC) circular buffers (CBs).
- * Each Tx queue has a BC CB in host DRAM to support Scheduler-ACK mode.
- * This register points to BC CB for queue 0, must be on 1024-byte boundary.
- * Others are spaced by 1024 bytes.
- * Each BC CB is 2 bytes * (256 + 64) = 740 bytes, followed by 384 bytes pad.
- * (Index into a queue's BC CB) = (index into queue's TFD CB) = (SSN & 0xff).
- * Bit fields:
- * 25-00: Byte Count CB physical address [35:10], must be 1024-byte aligned.
- */
-#define IWL49_SCD_DRAM_BASE_ADDR (IWL49_SCD_START_OFFSET + 0x10)
-
-/*
- * Enables any/all Tx DMA/FIFO channels.
- * Scheduler generates requests for only the active channels.
- * Set this to 0xff to enable all 8 channels (normal usage).
- * Bit fields:
- * 7- 0: Enable (1), disable (0), one bit for each channel 0-7
- */
-#define IWL49_SCD_TXFACT (IWL49_SCD_START_OFFSET + 0x1c)
-/*
- * Queue (x) Write Pointers (indexes, really!), one for each Tx queue.
- * Initialized and updated by driver as new TFDs are added to queue.
- * NOTE: If using Block Ack, index must correspond to frame's
- * Start Sequence Number; index = (SSN & 0xff)
- * NOTE: Alternative to HBUS_TARG_WRPTR, which is what Linux driver uses?
- */
-#define IWL49_SCD_QUEUE_WRPTR(x) (IWL49_SCD_START_OFFSET + 0x24 + (x) * 4)
-
-/*
- * Queue (x) Read Pointers (indexes, really!), one for each Tx queue.
- * For FIFO mode, index indicates next frame to transmit.
- * For Scheduler-ACK mode, index indicates first frame in Tx window.
- * Initialized by driver, updated by scheduler.
- */
-#define IWL49_SCD_QUEUE_RDPTR(x) (IWL49_SCD_START_OFFSET + 0x64 + (x) * 4)
-
-/*
- * Select which queues work in chain mode (1) vs. not (0).
- * Use chain mode to build chains of aggregated frames.
- * Bit fields:
- * 31-16: Reserved
- * 15-00: Mode, one bit for each queue -- 1: Chain mode, 0: one-at-a-time
- * NOTE: If driver sets up queue for chain mode, it should be also set up
- * Scheduler-ACK mode as well, via SCD_QUEUE_STATUS_BITS(x).
- */
-#define IWL49_SCD_QUEUECHAIN_SEL (IWL49_SCD_START_OFFSET + 0xd0)
-
-/*
- * Select which queues interrupt driver when scheduler increments
- * a queue's read pointer (index).
- * Bit fields:
- * 31-16: Reserved
- * 15-00: Interrupt enable, one bit for each queue -- 1: enabled, 0: disabled
- * NOTE: This functionality is apparently a no-op; driver relies on interrupts
- * from Rx queue to read Tx command responses and update Tx queues.
- */
-#define IWL49_SCD_INTERRUPT_MASK (IWL49_SCD_START_OFFSET + 0xe4)
-
-/*
- * Queue search status registers. One for each queue.
- * Sets up queue mode and assigns queue to Tx DMA channel.
- * Bit fields:
- * 19-10: Write mask/enable bits for bits 0-9
- * 9: Driver should init to "0"
- * 8: Scheduler-ACK mode (1), non-Scheduler-ACK (i.e. FIFO) mode (0).
- * Driver should init to "1" for aggregation mode, or "0" otherwise.
- * 7-6: Driver should init to "0"
- * 5: Window Size Left; indicates whether scheduler can request
- * another TFD, based on window size, etc. Driver should init
- * this bit to "1" for aggregation mode, or "0" for non-agg.
- * 4-1: Tx FIFO to use (range 0-7).
- * 0: Queue is active (1), not active (0).
- * Other bits should be written as "0"
- *
- * NOTE: If enabling Scheduler-ACK mode, chain mode should also be enabled
- * via SCD_QUEUECHAIN_SEL.
- */
-#define IWL49_SCD_QUEUE_STATUS_BITS(x)\
- (IWL49_SCD_START_OFFSET + 0x104 + (x) * 4)
-
-/* Bit field positions */
-#define IWL49_SCD_QUEUE_STTS_REG_POS_ACTIVE (0)
-#define IWL49_SCD_QUEUE_STTS_REG_POS_TXF (1)
-#define IWL49_SCD_QUEUE_STTS_REG_POS_WSL (5)
-#define IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACK (8)
-
-/* Write masks */
-#define IWL49_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN (10)
-#define IWL49_SCD_QUEUE_STTS_REG_MSK (0x0007FC00)
-
-/**
- * 4965 internal SRAM structures for scheduler, shared with driver ...
- *
- * Driver should clear and initialize the following areas after receiving
- * "Alive" response from 4965 uCode, i.e. after initial
- * uCode load, or after a uCode load done for error recovery:
- *
- * SCD_CONTEXT_DATA_OFFSET (size 128 bytes)
- * SCD_TX_STTS_BITMAP_OFFSET (size 256 bytes)
- * SCD_TRANSLATE_TBL_OFFSET (size 32 bytes)
- *
- * Driver accesses SRAM via HBUS_TARG_MEM_* registers.
- * Driver reads base address of this scheduler area from SCD_SRAM_BASE_ADDR.
- * All OFFSET values must be added to this base address.
- */
-
-/*
- * Queue context. One 8-byte entry for each of 16 queues.
- *
- * Driver should clear this entire area (size 0x80) to 0 after receiving
- * "Alive" notification from uCode. Additionally, driver should init
- * each queue's entry as follows:
- *
- * LS Dword bit fields:
- * 0-06: Max Tx window size for Scheduler-ACK. Driver should init to 64.
- *
- * MS Dword bit fields:
- * 16-22: Frame limit. Driver should init to 10 (0xa).
- *
- * Driver should init all other bits to 0.
- *
- * Init must be done after driver receives "Alive" response from 4965 uCode,
- * and when setting up queue for aggregation.
- */
-#define IWL49_SCD_CONTEXT_DATA_OFFSET 0x380
-#define IWL49_SCD_CONTEXT_QUEUE_OFFSET(x) \
- (IWL49_SCD_CONTEXT_DATA_OFFSET + ((x) * 8))
-
-#define IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_POS (0)
-#define IWL49_SCD_QUEUE_CTX_REG1_WIN_SIZE_MSK (0x0000007F)
-#define IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16)
-#define IWL49_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000)
-
-/*
- * Tx Status Bitmap
- *
- * Driver should clear this entire area (size 0x100) to 0 after receiving
- * "Alive" notification from uCode. Area is used only by device itself;
- * no other support (besides clearing) is required from driver.
- */
-#define IWL49_SCD_TX_STTS_BITMAP_OFFSET 0x400
-
-/*
- * RAxTID to queue translation mapping.
- *
- * When queue is in Scheduler-ACK mode, frames placed in a that queue must be
- * for only one combination of receiver address (RA) and traffic ID (TID), i.e.
- * one QOS priority level destined for one station (for this wireless link,
- * not final destination). The SCD_TRANSLATE_TABLE area provides 16 16-bit
- * mappings, one for each of the 16 queues. If queue is not in Scheduler-ACK
- * mode, the device ignores the mapping value.
- *
- * Bit fields, for each 16-bit map:
- * 15-9: Reserved, set to 0
- * 8-4: Index into device's station table for recipient station
- * 3-0: Traffic ID (tid), range 0-15
- *
- * Driver should clear this entire area (size 32 bytes) to 0 after receiving
- * "Alive" notification from uCode. To update a 16-bit map value, driver
- * must read a dword-aligned value from device SRAM, replace the 16-bit map
- * value of interest, and write the dword value back into device SRAM.
- */
-#define IWL49_SCD_TRANSLATE_TBL_OFFSET 0x500
-
-/* Find translation table dword to read/write for given queue */
-#define IWL49_SCD_TRANSLATE_TBL_OFFSET_QUEUE(x) \
- ((IWL49_SCD_TRANSLATE_TBL_OFFSET + ((x) * 2)) & 0xfffffffc)
-
#define IWL_SCD_TXFIFO_POS_TID (0)
#define IWL_SCD_TXFIFO_POS_RA (4)
#define IWL_SCD_QUEUE_RA_TID_MAP_RATID_MSK (0x01FF)
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 6f9a2fa04763..0053e9ea9021 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
@@ -225,55 +225,6 @@ err_bd:
*
******************************************************************************/
-static void iwl_rx_reply_alive(struct iwl_priv *priv,
- struct iwl_rx_mem_buffer *rxb)
-{
- struct iwl_rx_packet *pkt = rxb_addr(rxb);
- struct iwl_alive_resp *palive;
- struct delayed_work *pwork;
-
- palive = &pkt->u.alive_frame;
-
- IWL_DEBUG_INFO(priv, "Alive ucode status 0x%08X revision "
- "0x%01X 0x%01X\n",
- palive->is_valid, palive->ver_type,
- palive->ver_subtype);
-
- if (palive->ver_subtype == INITIALIZE_SUBTYPE) {
- IWL_DEBUG_INFO(priv, "Initialization Alive received.\n");
- memcpy(&priv->card_alive_init,
- &pkt->u.alive_frame,
- sizeof(struct iwl_init_alive_resp));
- pwork = &priv->init_alive_start;
- } else {
- IWL_DEBUG_INFO(priv, "Runtime Alive received.\n");
- memcpy(&priv->card_alive, &pkt->u.alive_frame,
- sizeof(struct iwl_alive_resp));
- pwork = &priv->alive_start;
- }
-
- /* We delay the ALIVE response by 5ms to
- * give the HW RF Kill time to activate... */
- if (palive->is_valid == UCODE_VALID_OK)
- queue_delayed_work(priv->workqueue, pwork,
- msecs_to_jiffies(5));
- else {
- IWL_WARN(priv, "%s uCode did not respond OK.\n",
- (palive->ver_subtype == INITIALIZE_SUBTYPE) ?
- "init" : "runtime");
- /*
- * If fail to load init uCode,
- * let's try to load the init uCode again.
- * We should not get into this situation, but if it
- * does happen, we should not move on and loading "runtime"
- * without proper calibrate the device.
- */
- if (palive->ver_subtype == INITIALIZE_SUBTYPE)
- priv->ucode_type = UCODE_NONE;
- queue_work(priv->workqueue, &priv->restart);
- }
-}
-
static void iwl_rx_reply_error(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
@@ -390,21 +341,16 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv,
* the BA_TIMEOUT_MAX, reload firmware and bring system back to normal
* operation state.
*/
-static bool iwl_good_ack_health(struct iwl_priv *priv, struct iwl_rx_packet *pkt)
+static bool iwl_good_ack_health(struct iwl_priv *priv,
+ struct statistics_tx *cur)
{
int actual_delta, expected_delta, ba_timeout_delta;
- struct statistics_tx *cur, *old;
+ struct statistics_tx *old;
if (priv->_agn.agg_tids_count)
return true;
- if (iwl_bt_statistics(priv)) {
- cur = &pkt->u.stats_bt.tx;
- old = &priv->_agn.statistics_bt.tx;
- } else {
- cur = &pkt->u.stats.tx;
- old = &priv->_agn.statistics.tx;
- }
+ old = &priv->statistics.tx;
actual_delta = le32_to_cpu(cur->actual_ack_cnt) -
le32_to_cpu(old->actual_ack_cnt);
@@ -430,10 +376,10 @@ static bool iwl_good_ack_health(struct iwl_priv *priv, struct iwl_rx_packet *pkt
* DEBUG is not, these will just compile out.
*/
IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta %d\n",
- priv->_agn.delta_statistics.tx.rx_detected_cnt);
+ priv->delta_stats.tx.rx_detected_cnt);
IWL_DEBUG_RADIO(priv,
"ack_or_ba_timeout_collision delta %d\n",
- priv->_agn.delta_statistics.tx.ack_or_ba_timeout_collision);
+ priv->delta_stats.tx.ack_or_ba_timeout_collision);
#endif
if (ba_timeout_delta >= BA_TIMEOUT_MAX)
@@ -450,7 +396,9 @@ static bool iwl_good_ack_health(struct iwl_priv *priv, struct iwl_rx_packet *pkt
* to improve the throughput.
*/
static bool iwl_good_plcp_health(struct iwl_priv *priv,
- struct iwl_rx_packet *pkt, unsigned int msecs)
+ struct statistics_rx_phy *cur_ofdm,
+ struct statistics_rx_ht_phy *cur_ofdm_ht,
+ unsigned int msecs)
{
int delta;
int threshold = priv->cfg->base_params->plcp_delta_threshold;
@@ -460,29 +408,12 @@ static bool iwl_good_plcp_health(struct iwl_priv *priv,
return true;
}
- if (iwl_bt_statistics(priv)) {
- struct statistics_rx_bt *cur, *old;
-
- cur = &pkt->u.stats_bt.rx;
- old = &priv->_agn.statistics_bt.rx;
+ delta = le32_to_cpu(cur_ofdm->plcp_err) -
+ le32_to_cpu(priv->statistics.rx_ofdm.plcp_err) +
+ le32_to_cpu(cur_ofdm_ht->plcp_err) -
+ le32_to_cpu(priv->statistics.rx_ofdm_ht.plcp_err);
- delta = le32_to_cpu(cur->ofdm.plcp_err) -
- le32_to_cpu(old->ofdm.plcp_err) +
- le32_to_cpu(cur->ofdm_ht.plcp_err) -
- le32_to_cpu(old->ofdm_ht.plcp_err);
- } else {
- struct statistics_rx *cur, *old;
-
- cur = &pkt->u.stats.rx;
- old = &priv->_agn.statistics.rx;
-
- delta = le32_to_cpu(cur->ofdm.plcp_err) -
- le32_to_cpu(old->ofdm.plcp_err) +
- le32_to_cpu(cur->ofdm_ht.plcp_err) -
- le32_to_cpu(old->ofdm_ht.plcp_err);
- }
-
- /* Can be negative if firmware reseted statistics */
+ /* Can be negative if firmware reset statistics */
if (delta <= 0)
return true;
@@ -497,44 +428,35 @@ static bool iwl_good_plcp_health(struct iwl_priv *priv,
}
static void iwl_recover_from_statistics(struct iwl_priv *priv,
- struct iwl_rx_packet *pkt)
+ struct statistics_rx_phy *cur_ofdm,
+ struct statistics_rx_ht_phy *cur_ofdm_ht,
+ struct statistics_tx *tx,
+ unsigned long stamp)
{
- const struct iwl_mod_params *mod_params = priv->cfg->mod_params;
unsigned int msecs;
- unsigned long stamp;
if (test_bit(STATUS_EXIT_PENDING, &priv->status))
return;
- stamp = jiffies;
msecs = jiffies_to_msecs(stamp - priv->rx_statistics_jiffies);
/* Only gather statistics and update time stamp when not associated */
if (!iwl_is_any_associated(priv))
- goto out;
+ return;
/* Do not check/recover when do not have enough statistics data */
if (msecs < 99)
return;
- if (mod_params->ack_check && !iwl_good_ack_health(priv, pkt)) {
+ if (iwlagn_mod_params.ack_check && !iwl_good_ack_health(priv, tx)) {
IWL_ERR(priv, "low ack count detected, restart firmware\n");
if (!iwl_force_reset(priv, IWL_FW_RESET, false))
return;
}
- if (mod_params->plcp_check && !iwl_good_plcp_health(priv, pkt, msecs))
+ if (iwlagn_mod_params.plcp_check &&
+ !iwl_good_plcp_health(priv, cur_ofdm, cur_ofdm_ht, msecs))
iwl_force_reset(priv, IWL_RF_RESET, false);
-
-out:
- if (iwl_bt_statistics(priv))
- 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));
-
- priv->rx_statistics_jiffies = stamp;
}
/* Calculate noise level, based on measurements during network silence just
@@ -548,10 +470,8 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv)
int bcn_silence_a, bcn_silence_b, bcn_silence_c;
int last_rx_noise;
- if (iwl_bt_statistics(priv))
- rx_info = &(priv->_agn.statistics_bt.rx.general.common);
- else
- rx_info = &(priv->_agn.statistics.rx.general);
+ rx_info = &priv->statistics.rx_non_phy;
+
bcn_silence_a =
le32_to_cpu(rx_info->beacon_silence_rssi_a) & IN_BAND_FILTER;
bcn_silence_b =
@@ -583,105 +503,153 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv)
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)
+static void accum_stats(__le32 *prev, __le32 *cur, __le32 *delta,
+ __le32 *max_delta, __le32 *accum, int size)
{
-#ifdef CONFIG_IWLWIFI_DEBUGFS
- 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 (iwl_bt_statistics(priv)) {
- 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)
+ int i;
+
+ for (i = 0;
+ i < size / sizeof(__le32);
+ i++, prev++, cur++, delta++, max_delta++, accum++) {
+ if (le32_to_cpu(*cur) > le32_to_cpu(*prev)) {
+ *delta = cpu_to_le32(
+ le32_to_cpu(*cur) - le32_to_cpu(*prev));
+ le32_add_cpu(accum, le32_to_cpu(*delta));
+ if (le32_to_cpu(*delta) > le32_to_cpu(*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
+static void
+iwl_accumulative_statistics(struct iwl_priv *priv,
+ struct statistics_general_common *common,
+ struct statistics_rx_non_phy *rx_non_phy,
+ struct statistics_rx_phy *rx_ofdm,
+ struct statistics_rx_ht_phy *rx_ofdm_ht,
+ struct statistics_rx_phy *rx_cck,
+ struct statistics_tx *tx,
+ struct statistics_bt_activity *bt_activity)
+{
+#define ACCUM(_name) \
+ accum_stats((__le32 *)&priv->statistics._name, \
+ (__le32 *)_name, \
+ (__le32 *)&priv->delta_stats._name, \
+ (__le32 *)&priv->max_delta_stats._name, \
+ (__le32 *)&priv->accum_stats._name, \
+ sizeof(*_name));
+
+ ACCUM(common);
+ ACCUM(rx_non_phy);
+ ACCUM(rx_ofdm);
+ ACCUM(rx_ofdm_ht);
+ ACCUM(rx_cck);
+ ACCUM(tx);
+ if (bt_activity)
+ ACCUM(bt_activity);
+#undef ACCUM
+}
+#else
+static inline void
+iwl_accumulative_statistics(struct iwl_priv *priv,
+ struct statistics_general_common *common,
+ struct statistics_rx_non_phy *rx_non_phy,
+ struct statistics_rx_phy *rx_ofdm,
+ struct statistics_rx_ht_phy *rx_ofdm_ht,
+ struct statistics_rx_phy *rx_cck,
+ struct statistics_tx *tx,
+ struct statistics_bt_activity *bt_activity)
+{
}
+#endif
static void iwl_rx_statistics(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb)
{
+ unsigned long stamp = jiffies;
const int reg_recalib_period = 60;
int change;
struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ u32 len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+ __le32 *flag;
+ struct statistics_general_common *common;
+ struct statistics_rx_non_phy *rx_non_phy;
+ struct statistics_rx_phy *rx_ofdm;
+ struct statistics_rx_ht_phy *rx_ofdm_ht;
+ struct statistics_rx_phy *rx_cck;
+ struct statistics_tx *tx;
+ struct statistics_bt_activity *bt_activity;
+
+ len -= sizeof(struct iwl_cmd_header); /* skip header */
+
+ IWL_DEBUG_RX(priv, "Statistics notification received (%d bytes).\n",
+ len);
+
+ if (len == sizeof(struct iwl_bt_notif_statistics)) {
+ struct iwl_bt_notif_statistics *stats;
+ stats = &pkt->u.stats_bt;
+ flag = &stats->flag;
+ common = &stats->general.common;
+ rx_non_phy = &stats->rx.general.common;
+ rx_ofdm = &stats->rx.ofdm;
+ rx_ofdm_ht = &stats->rx.ofdm_ht;
+ rx_cck = &stats->rx.cck;
+ tx = &stats->tx;
+ bt_activity = &stats->general.activity;
- if (iwl_bt_statistics(priv)) {
- 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)));
-
- iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats_bt);
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ /* handle this exception directly */
+ priv->statistics.num_bt_kills = stats->rx.general.num_bt_kills;
+ le32_add_cpu(&priv->statistics.accum_num_bt_kills,
+ le32_to_cpu(stats->rx.general.num_bt_kills));
+#endif
+ } else if (len == sizeof(struct iwl_notif_statistics)) {
+ struct iwl_notif_statistics *stats;
+ stats = &pkt->u.stats;
+ flag = &stats->flag;
+ common = &stats->general.common;
+ rx_non_phy = &stats->rx.general;
+ rx_ofdm = &stats->rx.ofdm;
+ rx_ofdm_ht = &stats->rx.ofdm_ht;
+ rx_cck = &stats->rx.cck;
+ tx = &stats->tx;
+ bt_activity = NULL;
} 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)));
-
- iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
+ WARN_ONCE(1, "len %d doesn't match BT (%zu) or normal (%zu)\n",
+ len, sizeof(struct iwl_bt_notif_statistics),
+ sizeof(struct iwl_notif_statistics));
+ return;
}
- iwl_recover_from_statistics(priv, pkt);
+ change = common->temperature != priv->statistics.common.temperature ||
+ (*flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
+ (priv->statistics.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK);
+
+ iwl_accumulative_statistics(priv, common, rx_non_phy, rx_ofdm,
+ rx_ofdm_ht, rx_cck, tx, bt_activity);
+
+ iwl_recover_from_statistics(priv, rx_ofdm, rx_ofdm_ht, tx, stamp);
+
+ priv->statistics.flag = *flag;
+ memcpy(&priv->statistics.common, common, sizeof(*common));
+ memcpy(&priv->statistics.rx_non_phy, rx_non_phy, sizeof(*rx_non_phy));
+ memcpy(&priv->statistics.rx_ofdm, rx_ofdm, sizeof(*rx_ofdm));
+ memcpy(&priv->statistics.rx_ofdm_ht, rx_ofdm_ht, sizeof(*rx_ofdm_ht));
+ memcpy(&priv->statistics.rx_cck, rx_cck, sizeof(*rx_cck));
+ memcpy(&priv->statistics.tx, tx, sizeof(*tx));
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ if (bt_activity)
+ memcpy(&priv->statistics.bt_activity, bt_activity,
+ sizeof(*bt_activity));
+#endif
+
+ priv->rx_statistics_jiffies = stamp;
set_bit(STATUS_STATISTICS, &priv->status);
@@ -708,18 +676,12 @@ static void iwl_rx_reply_statistics(struct iwl_priv *priv,
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));
+ memset(&priv->accum_stats, 0,
+ sizeof(priv->accum_stats));
+ memset(&priv->delta_stats, 0,
+ sizeof(priv->delta_stats));
+ memset(&priv->max_delta_stats, 0,
+ sizeof(priv->max_delta_stats));
#endif
IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
}
@@ -873,6 +835,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
{
struct sk_buff *skb;
__le16 fc = hdr->frame_control;
+ struct iwl_rxon_context *ctx;
/* We only process data packets if the interface is open */
if (unlikely(!priv->is_open)) {
@@ -882,7 +845,7 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
}
/* In case of HW accelerated crypto and bad decryption, drop */
- if (!priv->cfg->mod_params->sw_crypto &&
+ if (!iwlagn_mod_params.sw_crypto &&
iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats))
return;
@@ -895,10 +858,29 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv,
skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len);
iwl_update_stats(priv, false, fc, len);
+
+ /*
+ * Wake any queues that were stopped due to a passive channel tx
+ * failure. This can happen because the regulatory enforcement in
+ * the device waits for a beacon before allowing transmission,
+ * sometimes even after already having transmitted frames for the
+ * association because the new RXON may reset the information.
+ */
+ if (unlikely(ieee80211_is_beacon(fc))) {
+ for_each_context(priv, ctx) {
+ if (!ctx->last_tx_rejected)
+ continue;
+ if (compare_ether_addr(hdr->addr3,
+ ctx->active.bssid_addr))
+ continue;
+ ctx->last_tx_rejected = false;
+ iwl_wake_any_queue(priv, ctx);
+ }
+ }
+
memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
ieee80211_rx(priv->hw, skb);
- priv->alloc_rxb_page--;
rxb->page = NULL;
}
@@ -1093,7 +1075,6 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv)
handlers = priv->rx_handlers;
- handlers[REPLY_ALIVE] = iwl_rx_reply_alive;
handlers[REPLY_ERROR] = iwl_rx_reply_error;
handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa;
handlers[SPECTRUM_MEASURE_NOTIFICATION] = iwl_rx_spectrum_measure_notif;
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index 914c77e44588..d60d630cb93a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -2,7 +2,7 @@
*
* GPL LICENSE SUMMARY
*
- * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2011 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
diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h
deleted file mode 100644
index c4ca0b5d77da..000000000000
--- a/drivers/net/wireless/iwlwifi/iwl-spectrum.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/******************************************************************************
- *
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
- *
- * Portions of this file are derived from the ieee80211 subsystem header files.
- *
- * 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:
- * Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- *****************************************************************************/
-
-#ifndef __iwl_spectrum_h__
-#define __iwl_spectrum_h__
-enum { /* ieee80211_basic_report.map */
- IEEE80211_BASIC_MAP_BSS = (1 << 0),
- IEEE80211_BASIC_MAP_OFDM = (1 << 1),
- IEEE80211_BASIC_MAP_UNIDENTIFIED = (1 << 2),
- IEEE80211_BASIC_MAP_RADAR = (1 << 3),
- IEEE80211_BASIC_MAP_UNMEASURED = (1 << 4),
- /* Bits 5-7 are reserved */
-
-};
-struct ieee80211_basic_report {
- u8 channel;
- __le64 start_time;
- __le16 duration;
- u8 map;
-} __packed;
-
-enum { /* ieee80211_measurement_request.mode */
- /* Bit 0 is reserved */
- IEEE80211_MEASUREMENT_ENABLE = (1 << 1),
- IEEE80211_MEASUREMENT_REQUEST = (1 << 2),
- IEEE80211_MEASUREMENT_REPORT = (1 << 3),
- /* Bits 4-7 are reserved */
-};
-
-enum {
- IEEE80211_REPORT_BASIC = 0, /* required */
- IEEE80211_REPORT_CCA = 1, /* optional */
- IEEE80211_REPORT_RPI = 2, /* optional */
- /* 3-255 reserved */
-};
-
-struct ieee80211_measurement_params {
- u8 channel;
- __le64 start_time;
- __le16 duration;
-} __packed;
-
-struct ieee80211_info_element {
- u8 id;
- u8 len;
- u8 data[0];
-} __packed;
-
-struct ieee80211_measurement_request {
- struct ieee80211_info_element ie;
- u8 token;
- u8 mode;
- u8 type;
- struct ieee80211_measurement_params params[0];
-} __packed;
-
-struct ieee80211_measurement_report {
- struct ieee80211_info_element ie;
- u8 token;
- u8 mode;
- u8 type;
- union {
- struct ieee80211_basic_report basic[0];
- } u;
-} __packed;
-
-#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index bc90a12408a3..7df2814fd4f8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
@@ -141,7 +141,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
struct iwl_host_cmd cmd = {
.id = REPLY_ADD_STA,
.flags = flags,
- .data = data,
+ .data = { data, },
};
u8 sta_id __maybe_unused = sta->sta.sta_id;
@@ -155,7 +155,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
might_sleep();
}
- cmd.len = priv->cfg->ops->utils->build_addsta_hcmd(sta, data);
+ cmd.len[0] = priv->cfg->ops->utils->build_addsta_hcmd(sta, data);
ret = iwl_send_cmd(priv, &cmd);
if (ret || (flags & CMD_ASYNC))
@@ -233,7 +233,6 @@ u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
struct iwl_station_entry *station;
int i;
u8 sta_id = IWL_INVALID_STATION;
- u16 rate;
if (is_ap)
sta_id = ctx->ap_sta_id;
@@ -306,12 +305,6 @@ u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
*/
iwl_set_ht_add_station(priv, sta_id, sta, ctx);
- /* 3945 only */
- rate = (priv->band == IEEE80211_BAND_5GHZ) ?
- IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP;
- /* Turn on both antennas for the station... */
- station->sta.rate_n_flags = cpu_to_le16(rate | RATE_MCS_ANT_AB_MSK);
-
return sta_id;
}
@@ -408,9 +401,9 @@ static int iwl_send_remove_station(struct iwl_priv *priv,
struct iwl_host_cmd cmd = {
.id = REPLY_REMOVE_STA,
- .len = sizeof(struct iwl_rem_sta_cmd),
+ .len = { sizeof(struct iwl_rem_sta_cmd), },
.flags = CMD_SYNC,
- .data = &rm_sta_cmd,
+ .data = { &rm_sta_cmd, },
};
memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd));
@@ -501,7 +494,8 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
priv->num_stations--;
- BUG_ON(priv->num_stations < 0);
+ if (WARN_ON(priv->num_stations < 0))
+ priv->num_stations = 0;
spin_unlock_irqrestore(&priv->sta_lock, flags);
@@ -686,7 +680,8 @@ void iwl_dealloc_bcast_stations(struct iwl_priv *priv)
priv->stations[i].used &= ~IWL_STA_UCODE_ACTIVE;
priv->num_stations--;
- BUG_ON(priv->num_stations < 0);
+ if (WARN_ON(priv->num_stations < 0))
+ priv->num_stations = 0;
kfree(priv->stations[i].lq);
priv->stations[i].lq = NULL;
}
@@ -765,9 +760,9 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
struct iwl_host_cmd cmd = {
.id = REPLY_TX_LINK_QUALITY_CMD,
- .len = sizeof(struct iwl_link_quality_cmd),
+ .len = { sizeof(struct iwl_link_quality_cmd), },
.flags = flags,
- .data = lq,
+ .data = { lq, },
};
if (WARN_ON(lq->sta_id == IWL_INVALID_STATION))
@@ -782,7 +777,8 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
iwl_dump_lq_cmd(priv, lq);
- BUG_ON(init && (cmd.flags & CMD_ASYNC));
+ if (WARN_ON(init && (cmd.flags & CMD_ASYNC)))
+ return -EINVAL;
if (is_lq_table_valid(priv, ctx, lq))
ret = iwl_send_cmd(priv, &cmd);
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h
index 206f1e1a0caf..ff64027ff4cb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.h
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
diff --git a/drivers/net/wireless/iwlwifi/iwl-sv-open.c b/drivers/net/wireless/iwlwifi/iwl-sv-open.c
new file mode 100644
index 000000000000..69b7e6bf2d6f
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-sv-open.c
@@ -0,0 +1,640 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2010 - 2011 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
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * 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.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <net/net_namespace.h>
+#include <linux/netdevice.h>
+#include <net/cfg80211.h>
+#include <net/mac80211.h>
+#include <net/netlink.h>
+
+
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-debug.h"
+#include "iwl-fh.h"
+#include "iwl-io.h"
+#include "iwl-agn.h"
+#include "iwl-testmode.h"
+
+
+/* The TLVs used in the gnl message policy between the kernel module and
+ * user space application. iwl_testmode_gnl_msg_policy is to be carried
+ * through the NL80211_CMD_TESTMODE channel regulated by nl80211.
+ * See iwl-testmode.h
+ */
+static
+struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = {
+ [IWL_TM_ATTR_COMMAND] = { .type = NLA_U32, },
+
+ [IWL_TM_ATTR_UCODE_CMD_ID] = { .type = NLA_U8, },
+ [IWL_TM_ATTR_UCODE_CMD_DATA] = { .type = NLA_UNSPEC, },
+
+ [IWL_TM_ATTR_REG_OFFSET] = { .type = NLA_U32, },
+ [IWL_TM_ATTR_REG_VALUE8] = { .type = NLA_U8, },
+ [IWL_TM_ATTR_REG_VALUE32] = { .type = NLA_U32, },
+
+ [IWL_TM_ATTR_SYNC_RSP] = { .type = NLA_UNSPEC, },
+ [IWL_TM_ATTR_UCODE_RX_PKT] = { .type = NLA_UNSPEC, },
+
+ [IWL_TM_ATTR_EEPROM] = { .type = NLA_UNSPEC, },
+
+ [IWL_TM_ATTR_TRACE_ADDR] = { .type = NLA_UNSPEC, },
+ [IWL_TM_ATTR_TRACE_DATA] = { .type = NLA_UNSPEC, },
+
+ [IWL_TM_ATTR_FIXRATE] = { .type = NLA_U32, },
+};
+
+/*
+ * See the struct iwl_rx_packet in iwl-commands.h for the format of the
+ * received events from the device
+ */
+static inline int get_event_length(struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ if (pkt)
+ return le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+ else
+ return 0;
+}
+
+
+/*
+ * This function multicasts the spontaneous messages from the device to the
+ * user space. It is invoked whenever there is a received messages
+ * from the device. This function is called within the ISR of the rx handlers
+ * in iwlagn driver.
+ *
+ * The parsing of the message content is left to the user space application,
+ * The message content is treated as unattacked raw data and is encapsulated
+ * with IWL_TM_ATTR_UCODE_RX_PKT multicasting to the user space.
+ *
+ * @priv: the instance of iwlwifi device
+ * @rxb: pointer to rx data content received by the ISR
+ *
+ * See the message policies and TLVs in iwl_testmode_gnl_msg_policy[].
+ * For the messages multicasting to the user application, the mandatory
+ * TLV fields are :
+ * IWL_TM_ATTR_COMMAND must be IWL_TM_CMD_DEV2APP_UCODE_RX_PKT
+ * IWL_TM_ATTR_UCODE_RX_PKT for carrying the message content
+ */
+
+static void iwl_testmode_ucode_rx_pkt(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct ieee80211_hw *hw = priv->hw;
+ struct sk_buff *skb;
+ void *data;
+ int length;
+
+ data = (void *)rxb_addr(rxb);
+ length = get_event_length(rxb);
+
+ if (!data || length == 0)
+ return;
+
+ skb = cfg80211_testmode_alloc_event_skb(hw->wiphy, 20 + length,
+ GFP_ATOMIC);
+ if (skb == NULL) {
+ IWL_DEBUG_INFO(priv,
+ "Run out of memory for messages to user space ?\n");
+ return;
+ }
+ NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_UCODE_RX_PKT);
+ NLA_PUT(skb, IWL_TM_ATTR_UCODE_RX_PKT, length, data);
+ cfg80211_testmode_event(skb, GFP_ATOMIC);
+ return;
+
+nla_put_failure:
+ kfree_skb(skb);
+ IWL_DEBUG_INFO(priv, "Ouch, overran buffer, check allocation!\n");
+}
+
+void iwl_testmode_init(struct iwl_priv *priv)
+{
+ priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt;
+ priv->testmode_trace.trace_enabled = false;
+}
+
+static void iwl_trace_cleanup(struct iwl_priv *priv)
+{
+ struct device *dev = &priv->pci_dev->dev;
+
+ if (priv->testmode_trace.trace_enabled) {
+ if (priv->testmode_trace.cpu_addr &&
+ priv->testmode_trace.dma_addr)
+ dma_free_coherent(dev,
+ TRACE_TOTAL_SIZE,
+ priv->testmode_trace.cpu_addr,
+ priv->testmode_trace.dma_addr);
+ priv->testmode_trace.trace_enabled = false;
+ priv->testmode_trace.cpu_addr = NULL;
+ priv->testmode_trace.trace_addr = NULL;
+ priv->testmode_trace.dma_addr = 0;
+ }
+}
+
+
+void iwl_testmode_cleanup(struct iwl_priv *priv)
+{
+ iwl_trace_cleanup(priv);
+}
+
+/*
+ * This function handles the user application commands to the ucode.
+ *
+ * It retrieves the mandatory fields IWL_TM_ATTR_UCODE_CMD_ID and
+ * IWL_TM_ATTR_UCODE_CMD_DATA and calls to the handler to send the
+ * host command to the ucode.
+ *
+ * If any mandatory field is missing, -ENOMSG is replied to the user space
+ * application; otherwise, the actual execution result of the host command to
+ * ucode is replied.
+ *
+ * @hw: ieee80211_hw object that represents the device
+ * @tb: gnl message fields from the user space
+ */
+static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb)
+{
+ struct iwl_priv *priv = hw->priv;
+ struct iwl_host_cmd cmd;
+
+ memset(&cmd, 0, sizeof(struct iwl_host_cmd));
+
+ if (!tb[IWL_TM_ATTR_UCODE_CMD_ID] ||
+ !tb[IWL_TM_ATTR_UCODE_CMD_DATA]) {
+ IWL_DEBUG_INFO(priv,
+ "Error finding ucode command mandatory fields\n");
+ return -ENOMSG;
+ }
+
+ cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]);
+ cmd.data[0] = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
+ cmd.len[0] = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
+ cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
+ IWL_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x,"
+ " len %d\n", cmd.id, cmd.flags, cmd.len[0]);
+ /* ok, let's submit the command to ucode */
+ return iwl_send_cmd(priv, &cmd);
+}
+
+
+/*
+ * This function handles the user application commands for register access.
+ *
+ * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
+ * handlers respectively.
+ *
+ * If it's an unknown commdn ID, -ENOSYS is returned; or -ENOMSG if the
+ * mandatory fields(IWL_TM_ATTR_REG_OFFSET,IWL_TM_ATTR_REG_VALUE32,
+ * IWL_TM_ATTR_REG_VALUE8) are missing; Otherwise 0 is replied indicating
+ * the success of the command execution.
+ *
+ * If IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_REG_READ32, the register read
+ * value is returned with IWL_TM_ATTR_REG_VALUE32.
+ *
+ * @hw: ieee80211_hw object that represents the device
+ * @tb: gnl message fields from the user space
+ */
+static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)
+{
+ struct iwl_priv *priv = hw->priv;
+ u32 ofs, val32;
+ u8 val8;
+ struct sk_buff *skb;
+ int status = 0;
+
+ if (!tb[IWL_TM_ATTR_REG_OFFSET]) {
+ IWL_DEBUG_INFO(priv, "Error finding register offset\n");
+ return -ENOMSG;
+ }
+ ofs = nla_get_u32(tb[IWL_TM_ATTR_REG_OFFSET]);
+ IWL_INFO(priv, "testmode register access command offset 0x%x\n", ofs);
+
+ switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
+ case IWL_TM_CMD_APP2DEV_REG_READ32:
+ val32 = iwl_read32(priv, ofs);
+ IWL_INFO(priv, "32bit value to read 0x%x\n", val32);
+
+ skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
+ if (!skb) {
+ IWL_DEBUG_INFO(priv, "Error allocating memory\n");
+ return -ENOMEM;
+ }
+ NLA_PUT_U32(skb, IWL_TM_ATTR_REG_VALUE32, val32);
+ status = cfg80211_testmode_reply(skb);
+ if (status < 0)
+ IWL_DEBUG_INFO(priv,
+ "Error sending msg : %d\n", status);
+ break;
+ case IWL_TM_CMD_APP2DEV_REG_WRITE32:
+ if (!tb[IWL_TM_ATTR_REG_VALUE32]) {
+ IWL_DEBUG_INFO(priv,
+ "Error finding value to write\n");
+ return -ENOMSG;
+ } else {
+ val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]);
+ IWL_INFO(priv, "32bit value to write 0x%x\n", val32);
+ iwl_write32(priv, ofs, val32);
+ }
+ break;
+ case IWL_TM_CMD_APP2DEV_REG_WRITE8:
+ if (!tb[IWL_TM_ATTR_REG_VALUE8]) {
+ IWL_DEBUG_INFO(priv, "Error finding value to write\n");
+ return -ENOMSG;
+ } else {
+ val8 = nla_get_u8(tb[IWL_TM_ATTR_REG_VALUE8]);
+ IWL_INFO(priv, "8bit value to write 0x%x\n", val8);
+ iwl_write8(priv, ofs, val8);
+ }
+ break;
+ default:
+ IWL_DEBUG_INFO(priv, "Unknown testmode register command ID\n");
+ return -ENOSYS;
+ }
+
+ return status;
+
+nla_put_failure:
+ kfree_skb(skb);
+ return -EMSGSIZE;
+}
+
+
+static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv)
+{
+ struct iwl_notification_wait calib_wait;
+ int ret;
+
+ iwlagn_init_notification_wait(priv, &calib_wait,
+ CALIBRATION_COMPLETE_NOTIFICATION,
+ NULL, NULL);
+ ret = iwlagn_init_alive_start(priv);
+ if (ret) {
+ IWL_DEBUG_INFO(priv,
+ "Error configuring init calibration: %d\n", ret);
+ goto cfg_init_calib_error;
+ }
+
+ ret = iwlagn_wait_notification(priv, &calib_wait, 2 * HZ);
+ if (ret)
+ IWL_DEBUG_INFO(priv, "Error detecting"
+ " CALIBRATION_COMPLETE_NOTIFICATION: %d\n", ret);
+ return ret;
+
+cfg_init_calib_error:
+ iwlagn_remove_notification(priv, &calib_wait);
+ return ret;
+}
+
+/*
+ * This function handles the user application commands for driver.
+ *
+ * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
+ * handlers respectively.
+ *
+ * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned
+ * value of the actual command execution is replied to the user application.
+ *
+ * If there's any message responding to the user space, IWL_TM_ATTR_SYNC_RSP
+ * is used for carry the message while IWL_TM_ATTR_COMMAND must set to
+ * IWL_TM_CMD_DEV2APP_SYNC_RSP.
+ *
+ * @hw: ieee80211_hw object that represents the device
+ * @tb: gnl message fields from the user space
+ */
+static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
+{
+ struct iwl_priv *priv = hw->priv;
+ struct sk_buff *skb;
+ unsigned char *rsp_data_ptr = NULL;
+ int status = 0, rsp_data_len = 0;
+
+ switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
+ case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
+ rsp_data_ptr = (unsigned char *)priv->cfg->name;
+ rsp_data_len = strlen(priv->cfg->name);
+ skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
+ rsp_data_len + 20);
+ if (!skb) {
+ IWL_DEBUG_INFO(priv,
+ "Error allocating memory\n");
+ return -ENOMEM;
+ }
+ NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND,
+ IWL_TM_CMD_DEV2APP_SYNC_RSP);
+ NLA_PUT(skb, IWL_TM_ATTR_SYNC_RSP,
+ rsp_data_len, rsp_data_ptr);
+ status = cfg80211_testmode_reply(skb);
+ if (status < 0)
+ IWL_DEBUG_INFO(priv, "Error sending msg : %d\n",
+ status);
+ break;
+
+ case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
+ status = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init,
+ UCODE_SUBTYPE_INIT, -1);
+ if (status)
+ IWL_DEBUG_INFO(priv,
+ "Error loading init ucode: %d\n", status);
+ break;
+
+ case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
+ iwl_testmode_cfg_init_calib(priv);
+ iwlagn_stop_device(priv);
+ break;
+
+ case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
+ status = iwlagn_load_ucode_wait_alive(priv,
+ &priv->ucode_rt,
+ UCODE_SUBTYPE_REGULAR,
+ UCODE_SUBTYPE_REGULAR_NEW);
+ if (status) {
+ IWL_DEBUG_INFO(priv,
+ "Error loading runtime ucode: %d\n", status);
+ break;
+ }
+ status = iwl_alive_start(priv);
+ if (status)
+ IWL_DEBUG_INFO(priv,
+ "Error starting the device: %d\n", status);
+ break;
+
+ case IWL_TM_CMD_APP2DEV_GET_EEPROM:
+ if (priv->eeprom) {
+ skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
+ priv->cfg->base_params->eeprom_size + 20);
+ if (!skb) {
+ IWL_DEBUG_INFO(priv,
+ "Error allocating memory\n");
+ return -ENOMEM;
+ }
+ NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND,
+ IWL_TM_CMD_DEV2APP_EEPROM_RSP);
+ NLA_PUT(skb, IWL_TM_ATTR_EEPROM,
+ priv->cfg->base_params->eeprom_size,
+ priv->eeprom);
+ status = cfg80211_testmode_reply(skb);
+ if (status < 0)
+ IWL_DEBUG_INFO(priv,
+ "Error sending msg : %d\n",
+ status);
+ } else
+ return -EFAULT;
+ break;
+
+ case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
+ if (!tb[IWL_TM_ATTR_FIXRATE]) {
+ IWL_DEBUG_INFO(priv,
+ "Error finding fixrate setting\n");
+ return -ENOMSG;
+ }
+ priv->dbg_fixed_rate = nla_get_u32(tb[IWL_TM_ATTR_FIXRATE]);
+ break;
+
+ default:
+ IWL_DEBUG_INFO(priv, "Unknown testmode driver command ID\n");
+ return -ENOSYS;
+ }
+ return status;
+
+nla_put_failure:
+ kfree_skb(skb);
+ return -EMSGSIZE;
+}
+
+
+/*
+ * This function handles the user application commands for uCode trace
+ *
+ * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
+ * handlers respectively.
+ *
+ * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned
+ * value of the actual command execution is replied to the user application.
+ *
+ * @hw: ieee80211_hw object that represents the device
+ * @tb: gnl message fields from the user space
+ */
+static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb)
+{
+ struct iwl_priv *priv = hw->priv;
+ struct sk_buff *skb;
+ int status = 0;
+ struct device *dev = &priv->pci_dev->dev;
+
+ switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
+ case IWL_TM_CMD_APP2DEV_BEGIN_TRACE:
+ if (priv->testmode_trace.trace_enabled)
+ return -EBUSY;
+
+ priv->testmode_trace.cpu_addr =
+ dma_alloc_coherent(dev,
+ TRACE_TOTAL_SIZE,
+ &priv->testmode_trace.dma_addr,
+ GFP_KERNEL);
+ if (!priv->testmode_trace.cpu_addr)
+ return -ENOMEM;
+ priv->testmode_trace.trace_enabled = true;
+ priv->testmode_trace.trace_addr = (u8 *)PTR_ALIGN(
+ priv->testmode_trace.cpu_addr, 0x100);
+ memset(priv->testmode_trace.trace_addr, 0x03B,
+ TRACE_BUFF_SIZE);
+ skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
+ sizeof(priv->testmode_trace.dma_addr) + 20);
+ if (!skb) {
+ IWL_DEBUG_INFO(priv,
+ "Error allocating memory\n");
+ iwl_trace_cleanup(priv);
+ return -ENOMEM;
+ }
+ NLA_PUT(skb, IWL_TM_ATTR_TRACE_ADDR,
+ sizeof(priv->testmode_trace.dma_addr),
+ (u64 *)&priv->testmode_trace.dma_addr);
+ status = cfg80211_testmode_reply(skb);
+ if (status < 0) {
+ IWL_DEBUG_INFO(priv,
+ "Error sending msg : %d\n",
+ status);
+ }
+ break;
+
+ case IWL_TM_CMD_APP2DEV_END_TRACE:
+ iwl_trace_cleanup(priv);
+ break;
+
+ case IWL_TM_CMD_APP2DEV_READ_TRACE:
+ if (priv->testmode_trace.trace_enabled &&
+ priv->testmode_trace.trace_addr) {
+ skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
+ 20 + TRACE_BUFF_SIZE);
+ if (skb == NULL) {
+ IWL_DEBUG_INFO(priv,
+ "Error allocating memory\n");
+ return -ENOMEM;
+ }
+ NLA_PUT(skb, IWL_TM_ATTR_TRACE_DATA,
+ TRACE_BUFF_SIZE,
+ priv->testmode_trace.trace_addr);
+ status = cfg80211_testmode_reply(skb);
+ if (status < 0) {
+ IWL_DEBUG_INFO(priv,
+ "Error sending msg : %d\n", status);
+ }
+ } else
+ return -EFAULT;
+ break;
+
+ default:
+ IWL_DEBUG_INFO(priv, "Unknown testmode mem command ID\n");
+ return -ENOSYS;
+ }
+ return status;
+
+nla_put_failure:
+ kfree_skb(skb);
+ if (nla_get_u32(tb[IWL_TM_ATTR_COMMAND]) ==
+ IWL_TM_CMD_APP2DEV_BEGIN_TRACE)
+ iwl_trace_cleanup(priv);
+ return -EMSGSIZE;
+}
+
+/* The testmode gnl message handler that takes the gnl message from the
+ * user space and parses it per the policy iwl_testmode_gnl_msg_policy, then
+ * invoke the corresponding handlers.
+ *
+ * This function is invoked when there is user space application sending
+ * gnl message through the testmode tunnel NL80211_CMD_TESTMODE regulated
+ * by nl80211.
+ *
+ * It retrieves the mandatory field, IWL_TM_ATTR_COMMAND, before
+ * dispatching it to the corresponding handler.
+ *
+ * If IWL_TM_ATTR_COMMAND is missing, -ENOMSG is replied to user application;
+ * -ENOSYS is replied to the user application if the command is unknown;
+ * Otherwise, the command is dispatched to the respective handler.
+ *
+ * @hw: ieee80211_hw object that represents the device
+ * @data: pointer to user space message
+ * @len: length in byte of @data
+ */
+int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
+{
+ struct nlattr *tb[IWL_TM_ATTR_MAX - 1];
+ struct iwl_priv *priv = hw->priv;
+ int result;
+
+ result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len,
+ iwl_testmode_gnl_msg_policy);
+ if (result != 0) {
+ IWL_DEBUG_INFO(priv,
+ "Error parsing the gnl message : %d\n", result);
+ return result;
+ }
+
+ /* IWL_TM_ATTR_COMMAND is absolutely mandatory */
+ if (!tb[IWL_TM_ATTR_COMMAND]) {
+ IWL_DEBUG_INFO(priv, "Error finding testmode command type\n");
+ return -ENOMSG;
+ }
+ /* in case multiple accesses to the device happens */
+ mutex_lock(&priv->mutex);
+
+ switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
+ case IWL_TM_CMD_APP2DEV_UCODE:
+ IWL_DEBUG_INFO(priv, "testmode cmd to uCode\n");
+ result = iwl_testmode_ucode(hw, tb);
+ break;
+ case IWL_TM_CMD_APP2DEV_REG_READ32:
+ case IWL_TM_CMD_APP2DEV_REG_WRITE32:
+ case IWL_TM_CMD_APP2DEV_REG_WRITE8:
+ IWL_DEBUG_INFO(priv, "testmode cmd to register\n");
+ result = iwl_testmode_reg(hw, tb);
+ break;
+ case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
+ case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
+ case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
+ case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
+ case IWL_TM_CMD_APP2DEV_GET_EEPROM:
+ case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
+ IWL_DEBUG_INFO(priv, "testmode cmd to driver\n");
+ result = iwl_testmode_driver(hw, tb);
+ break;
+
+ case IWL_TM_CMD_APP2DEV_BEGIN_TRACE:
+ case IWL_TM_CMD_APP2DEV_END_TRACE:
+ case IWL_TM_CMD_APP2DEV_READ_TRACE:
+ IWL_DEBUG_INFO(priv, "testmode uCode trace cmd to driver\n");
+ result = iwl_testmode_trace(hw, tb);
+ break;
+
+ default:
+ IWL_DEBUG_INFO(priv, "Unknown testmode command\n");
+ result = -ENOSYS;
+ break;
+ }
+
+ mutex_unlock(&priv->mutex);
+ return result;
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.h b/drivers/net/wireless/iwlwifi/iwl-testmode.h
new file mode 100644
index 000000000000..a88085e9b361
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-testmode.h
@@ -0,0 +1,185 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2010 - 2011 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
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * 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.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+#ifndef __IWL_TESTMODE_H__
+#define __IWL_TESTMODE_H__
+
+#include <linux/types.h>
+
+
+/* Commands from user space to kernel space(IWL_TM_CMD_ID_APP2DEV_XX) and
+ * from and kernel space to user space(IWL_TM_CMD_ID_DEV2APP_XX).
+ * The command ID is carried with IWL_TM_ATTR_COMMAND. There are three types of
+ * of command from user space and two types of command from kernel space.
+ * See below.
+ */
+enum iwl_tm_cmd_t {
+ /* commands from user application to the uCode,
+ * the actual uCode host command ID is carried with
+ * IWL_TM_ATTR_UCODE_CMD_ID */
+ IWL_TM_CMD_APP2DEV_UCODE = 1,
+
+ /* commands from user applicaiton to access register */
+ IWL_TM_CMD_APP2DEV_REG_READ32,
+ IWL_TM_CMD_APP2DEV_REG_WRITE32,
+ IWL_TM_CMD_APP2DEV_REG_WRITE8,
+
+ /* commands fom user space for pure driver level operations */
+ IWL_TM_CMD_APP2DEV_GET_DEVICENAME,
+ IWL_TM_CMD_APP2DEV_LOAD_INIT_FW,
+ IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB,
+ IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW,
+ IWL_TM_CMD_APP2DEV_GET_EEPROM,
+ IWL_TM_CMD_APP2DEV_FIXRATE_REQ,
+ /* if there is other new command for the driver layer operation,
+ * append them here */
+
+ /* commands fom user space for uCode trace operations */
+ IWL_TM_CMD_APP2DEV_BEGIN_TRACE,
+ IWL_TM_CMD_APP2DEV_END_TRACE,
+ IWL_TM_CMD_APP2DEV_READ_TRACE,
+
+ /* commands from kernel space to carry the synchronous response
+ * to user application */
+ IWL_TM_CMD_DEV2APP_SYNC_RSP,
+
+ /* commands from kernel space to multicast the spontaneous messages
+ * to user application */
+ IWL_TM_CMD_DEV2APP_UCODE_RX_PKT,
+
+ /* commands from kernel space to carry the eeprom response
+ * to user application */
+ IWL_TM_CMD_DEV2APP_EEPROM_RSP,
+
+ IWL_TM_CMD_MAX,
+};
+
+enum iwl_tm_attr_t {
+ IWL_TM_ATTR_NOT_APPLICABLE = 0,
+
+ /* From user space to kernel space:
+ * the command either destines to ucode, driver, or register;
+ * See enum iwl_tm_cmd_t.
+ *
+ * From kernel space to user space:
+ * the command either carries synchronous response,
+ * or the spontaneous message multicast from the device;
+ * See enum iwl_tm_cmd_t. */
+ IWL_TM_ATTR_COMMAND,
+
+ /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_UCODE,
+ * The mandatory fields are :
+ * IWL_TM_ATTR_UCODE_CMD_ID for recognizable command ID;
+ * IWL_TM_ATTR_COMMAND_FLAG for the flags of the commands;
+ * The optional fields are:
+ * IWL_TM_ATTR_UCODE_CMD_DATA for the actual command payload
+ * to the ucode */
+ IWL_TM_ATTR_UCODE_CMD_ID,
+ IWL_TM_ATTR_UCODE_CMD_DATA,
+
+ /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_REG_XXX,
+ * The mandatory fields are:
+ * IWL_TM_ATTR_REG_OFFSET for the offset of the target register;
+ * IWL_TM_ATTR_REG_VALUE8 or IWL_TM_ATTR_REG_VALUE32 for value */
+ IWL_TM_ATTR_REG_OFFSET,
+ IWL_TM_ATTR_REG_VALUE8,
+ IWL_TM_ATTR_REG_VALUE32,
+
+ /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_SYNC_RSP,
+ * The mandatory fields are:
+ * IWL_TM_ATTR_SYNC_RSP for the data content responding to the user
+ * application command */
+ IWL_TM_ATTR_SYNC_RSP,
+ /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_UCODE_RX_PKT,
+ * The mandatory fields are:
+ * IWL_TM_ATTR_UCODE_RX_PKT for the data content multicast to the user
+ * application */
+ IWL_TM_ATTR_UCODE_RX_PKT,
+
+ /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_EEPROM,
+ * The mandatory fields are:
+ * IWL_TM_ATTR_EEPROM for the data content responging to the user
+ * application */
+ IWL_TM_ATTR_EEPROM,
+
+ /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_XXX_TRACE,
+ * The mandatory fields are:
+ * IWL_TM_ATTR_MEM_TRACE_ADDR for the trace address
+ */
+ IWL_TM_ATTR_TRACE_ADDR,
+ IWL_TM_ATTR_TRACE_DATA,
+
+ /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_FIXRATE_REQ,
+ * The mandatory fields are:
+ * IWL_TM_ATTR_FIXRATE for the fixed rate
+ */
+ IWL_TM_ATTR_FIXRATE,
+
+ IWL_TM_ATTR_MAX,
+};
+
+/* uCode trace buffer */
+#define TRACE_BUFF_SIZE 0x20000
+#define TRACE_BUFF_PADD 0x2000
+#define TRACE_TOTAL_SIZE (TRACE_BUFF_SIZE + TRACE_BUFF_PADD)
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 277c9175dcf6..686e176b5ebd 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
*
* Portions of this file are derived from the ipw3945 project, as well
* as portions of the ieee80211 subsystem header files.
@@ -32,6 +32,7 @@
#include <linux/slab.h>
#include <net/mac80211.h>
#include "iwl-eeprom.h"
+#include "iwl-agn.h"
#include "iwl-dev.h"
#include "iwl-core.h"
#include "iwl-sta.h"
@@ -85,6 +86,158 @@ void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
txq->need_update = 0;
}
+static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx)
+{
+ struct iwl_tfd_tb *tb = &tfd->tbs[idx];
+
+ dma_addr_t addr = get_unaligned_le32(&tb->lo);
+ if (sizeof(dma_addr_t) > sizeof(u32))
+ addr |=
+ ((dma_addr_t)(le16_to_cpu(tb->hi_n_len) & 0xF) << 16) << 16;
+
+ return addr;
+}
+
+static inline u16 iwl_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx)
+{
+ struct iwl_tfd_tb *tb = &tfd->tbs[idx];
+
+ return le16_to_cpu(tb->hi_n_len) >> 4;
+}
+
+static inline void iwl_tfd_set_tb(struct iwl_tfd *tfd, u8 idx,
+ dma_addr_t addr, u16 len)
+{
+ struct iwl_tfd_tb *tb = &tfd->tbs[idx];
+ u16 hi_n_len = len << 4;
+
+ put_unaligned_le32(addr, &tb->lo);
+ if (sizeof(dma_addr_t) > sizeof(u32))
+ hi_n_len |= ((addr >> 16) >> 16) & 0xF;
+
+ tb->hi_n_len = cpu_to_le16(hi_n_len);
+
+ tfd->num_tbs = idx + 1;
+}
+
+static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd)
+{
+ return tfd->num_tbs & 0x1f;
+}
+
+static void iwlagn_unmap_tfd(struct iwl_priv *priv, struct iwl_cmd_meta *meta,
+ struct iwl_tfd *tfd)
+{
+ struct pci_dev *dev = priv->pci_dev;
+ int i;
+ int num_tbs;
+
+ /* Sanity check on number of chunks */
+ num_tbs = iwl_tfd_get_num_tbs(tfd);
+
+ if (num_tbs >= IWL_NUM_OF_TBS) {
+ IWL_ERR(priv, "Too many chunks: %i\n", num_tbs);
+ /* @todo issue fatal error, it is quite serious situation */
+ return;
+ }
+
+ /* Unmap tx_cmd */
+ if (num_tbs)
+ pci_unmap_single(dev,
+ dma_unmap_addr(meta, mapping),
+ dma_unmap_len(meta, len),
+ PCI_DMA_BIDIRECTIONAL);
+
+ /* Unmap chunks, if any. */
+ 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);
+}
+
+/**
+ * iwlagn_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
+ * @priv - driver private data
+ * @txq - tx queue
+ *
+ * Does NOT advance any TFD circular buffer read/write indexes
+ * Does NOT free the TFD itself (which is within circular buffer)
+ */
+void iwlagn_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+ struct iwl_tfd *tfd_tmp = txq->tfds;
+ int index = txq->q.read_ptr;
+
+ iwlagn_unmap_tfd(priv, &txq->meta[index], &tfd_tmp[index]);
+
+ /* 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;
+ }
+ }
+}
+
+int iwlagn_txq_attach_buf_to_tfd(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq,
+ dma_addr_t addr, u16 len,
+ u8 reset)
+{
+ struct iwl_queue *q;
+ struct iwl_tfd *tfd, *tfd_tmp;
+ u32 num_tbs;
+
+ q = &txq->q;
+ tfd_tmp = txq->tfds;
+ tfd = &tfd_tmp[q->write_ptr];
+
+ if (reset)
+ memset(tfd, 0, sizeof(*tfd));
+
+ num_tbs = iwl_tfd_get_num_tbs(tfd);
+
+ /* Each TFD can point to a maximum 20 Tx buffers */
+ if (num_tbs >= IWL_NUM_OF_TBS) {
+ IWL_ERR(priv, "Error can not send more than %d chunks\n",
+ IWL_NUM_OF_TBS);
+ return -EINVAL;
+ }
+
+ if (WARN_ON(addr & ~DMA_BIT_MASK(36)))
+ return -EINVAL;
+
+ if (unlikely(addr & ~IWL_TX_DMA_MASK))
+ IWL_ERR(priv, "Unaligned address = %llx\n",
+ (unsigned long long)addr);
+
+ iwl_tfd_set_tb(tfd, num_tbs, addr, len);
+
+ return 0;
+}
+
+/*
+ * Tell nic where to find circular buffer of Tx Frame Descriptors for
+ * given Tx queue, and enable the DMA channel used for that queue.
+ *
+ * supports up to 16 Tx queues in DRAM, mapped to up to 8 Tx DMA
+ * channels supported in hardware.
+ */
+static int iwlagn_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq)
+{
+ int txq_id = txq->q.id;
+
+ /* Circular buffer (TFD queue in DRAM) physical base address */
+ iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id),
+ txq->q.dma_addr >> 8);
+
+ return 0;
+}
+
/**
* iwl_tx_queue_unmap - Unmap any remaining DMA mappings and free skb's
*/
@@ -97,7 +250,7 @@ void iwl_tx_queue_unmap(struct iwl_priv *priv, int txq_id)
return;
while (q->write_ptr != q->read_ptr) {
- priv->cfg->ops->lib->txq_free_tfd(priv, txq);
+ iwlagn_txq_free_tfd(priv, txq);
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
}
}
@@ -149,32 +302,22 @@ void iwl_cmd_queue_unmap(struct iwl_priv *priv)
struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
struct iwl_queue *q = &txq->q;
int i;
- bool huge = false;
if (q->n_bd == 0)
return;
while (q->read_ptr != q->write_ptr) {
- /* we have no way to tell if it is a huge cmd ATM */
- i = get_cmd_index(q, q->read_ptr, 0);
+ i = get_cmd_index(q, q->read_ptr);
- if (txq->meta[i].flags & CMD_SIZE_HUGE)
- huge = true;
- else
+ if (txq->meta[i].flags & CMD_MAPPED) {
pci_unmap_single(priv->pci_dev,
dma_unmap_addr(&txq->meta[i], mapping),
dma_unmap_len(&txq->meta[i], len),
PCI_DMA_BIDIRECTIONAL);
+ txq->meta[i].flags = 0;
+ }
- q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
- }
-
- if (huge) {
- i = q->n_window;
- pci_unmap_single(priv->pci_dev,
- dma_unmap_addr(&txq->meta[i], mapping),
- dma_unmap_len(&txq->meta[i], len),
- PCI_DMA_BIDIRECTIONAL);
+ q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
}
}
@@ -195,7 +338,7 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
iwl_cmd_queue_unmap(priv);
/* De-alloc array of command/tx buffers */
- for (i = 0; i <= TFD_CMD_SLOTS; i++)
+ for (i = 0; i < TFD_CMD_SLOTS; i++)
kfree(txq->cmd[i]);
/* De-alloc circular buffer of TFDs */
@@ -233,7 +376,6 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
* reclaiming packets (on 'tx done IRQ), if free space become > high mark,
* Tx queue resumed.
*
- * See more detailed info in iwl-4965-hw.h.
***************************************************/
int iwl_queue_space(const struct iwl_queue *q)
@@ -265,11 +407,13 @@ static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
/* count must be power-of-two size, otherwise iwl_queue_inc_wrap
* and iwl_queue_dec_wrap are broken. */
- BUG_ON(!is_power_of_2(count));
+ if (WARN_ON(!is_power_of_2(count)))
+ return -EINVAL;
/* slots_num must be power-of-two size, otherwise
* get_cmd_index is broken. */
- BUG_ON(!is_power_of_2(slots_num));
+ if (WARN_ON(!is_power_of_2(slots_num)))
+ return -EINVAL;
q->low_mark = q->n_window / 4;
if (q->low_mark < 4)
@@ -334,33 +478,17 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
{
int i, len;
int ret;
- int actual_slots = slots_num;
- /*
- * Alloc buffer array for commands (Tx or other types of commands).
- * For the command queue (#4/#9), allocate command space + one big
- * command for scan, since scan command is very huge; the system will
- * not have two scans at the same time, so only one is needed.
- * For normal Tx queues (all other queues), no super-size command
- * space is needed.
- */
- if (txq_id == priv->cmd_queue)
- actual_slots++;
-
- txq->meta = kzalloc(sizeof(struct iwl_cmd_meta) * actual_slots,
+ txq->meta = kzalloc(sizeof(struct iwl_cmd_meta) * slots_num,
GFP_KERNEL);
- txq->cmd = kzalloc(sizeof(struct iwl_device_cmd *) * actual_slots,
+ txq->cmd = kzalloc(sizeof(struct iwl_device_cmd *) * slots_num,
GFP_KERNEL);
if (!txq->meta || !txq->cmd)
goto out_free_arrays;
len = sizeof(struct iwl_device_cmd);
- for (i = 0; i < actual_slots; i++) {
- /* only happens for cmd queue */
- if (i == slots_num)
- len = IWL_MAX_CMD_SIZE;
-
+ for (i = 0; i < slots_num; i++) {
txq->cmd[i] = kmalloc(len, GFP_KERNEL);
if (!txq->cmd[i])
goto err;
@@ -386,14 +514,16 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
/* Initialize queue's high/low-water marks, and head/tail indexes */
- iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
+ ret = iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
+ if (ret)
+ return ret;
/* Tell device where to find queue */
- priv->cfg->ops->lib->txq_init(priv, txq);
+ iwlagn_tx_queue_init(priv, txq);
return 0;
err:
- for (i = 0; i < actual_slots; i++)
+ for (i = 0; i < slots_num; i++)
kfree(txq->cmd[i]);
out_free_arrays:
kfree(txq->meta);
@@ -418,7 +548,7 @@ void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq,
iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
/* Tell device where to find queue */
- priv->cfg->ops->lib->txq_init(priv, txq);
+ iwlagn_tx_queue_init(priv, txq);
}
/*************** HOST COMMAND QUEUE FUNCTIONS *****/
@@ -440,22 +570,51 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
struct iwl_cmd_meta *out_meta;
dma_addr_t phys_addr;
unsigned long flags;
- int len;
u32 idx;
- u16 fix_size;
+ u16 copy_size, cmd_size;
bool is_ct_kill = false;
+ bool had_nocopy = false;
+ int i;
+ u8 *cmd_dest;
+#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
+ const void *trace_bufs[IWL_MAX_CMD_TFDS + 1] = {};
+ int trace_lens[IWL_MAX_CMD_TFDS + 1] = {};
+ int trace_idx;
+#endif
- cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len);
- fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
+ if (test_bit(STATUS_FW_ERROR, &priv->status)) {
+ IWL_WARN(priv, "fw recovery, no hcmd send\n");
+ return -EIO;
+ }
+
+ copy_size = sizeof(out_cmd->hdr);
+ cmd_size = sizeof(out_cmd->hdr);
+
+ /* need one for the header if the first is NOCOPY */
+ BUILD_BUG_ON(IWL_MAX_CMD_TFDS > IWL_NUM_OF_TBS - 1);
+
+ for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
+ if (!cmd->len[i])
+ continue;
+ if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) {
+ had_nocopy = true;
+ } else {
+ /* NOCOPY must not be followed by normal! */
+ if (WARN_ON(had_nocopy))
+ return -EINVAL;
+ copy_size += cmd->len[i];
+ }
+ cmd_size += cmd->len[i];
+ }
- /* If any of the command structures end up being larger than
- * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then
- * we will need to increase the size of the TFD entries
- * Also, check to see if command buffer should not exceed the size
- * of device_cmd and max_cmd_size. */
- BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&
- !(cmd->flags & CMD_SIZE_HUGE));
- BUG_ON(fix_size > IWL_MAX_CMD_SIZE);
+ /*
+ * If any of the command structures end up being larger than
+ * the TFD_MAX_PAYLOAD_SIZE and they aren't dynamically
+ * allocated into separate TFDs, then we will need to
+ * increase the size of the buffers.
+ */
+ if (WARN_ON(copy_size > TFD_MAX_PAYLOAD_SIZE))
+ return -EINVAL;
if (iwl_is_rfkill(priv) || iwl_is_ctkill(priv)) {
IWL_WARN(priv, "Not sending command - %s KILL\n",
@@ -463,96 +622,119 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
return -EIO;
}
+ spin_lock_irqsave(&priv->hcmd_lock, flags);
+
if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) {
+ spin_unlock_irqrestore(&priv->hcmd_lock, flags);
+
IWL_ERR(priv, "No space in command queue\n");
- if (priv->cfg->ops->lib->tt_ops.ct_kill_check) {
- is_ct_kill =
- priv->cfg->ops->lib->tt_ops.ct_kill_check(priv);
- }
+ is_ct_kill = iwl_check_for_ct_kill(priv);
if (!is_ct_kill) {
IWL_ERR(priv, "Restarting adapter due to queue full\n");
- queue_work(priv->workqueue, &priv->restart);
+ iwlagn_fw_error(priv, false);
}
return -ENOSPC;
}
- spin_lock_irqsave(&priv->hcmd_lock, flags);
-
- /* If this is a huge cmd, mark the huge flag also on the meta.flags
- * of the _original_ cmd. This is used for DMA mapping clean up.
- */
- if (cmd->flags & CMD_SIZE_HUGE) {
- idx = get_cmd_index(q, q->write_ptr, 0);
- txq->meta[idx].flags = CMD_SIZE_HUGE;
- }
-
- idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE);
+ idx = get_cmd_index(q, q->write_ptr);
out_cmd = txq->cmd[idx];
out_meta = &txq->meta[idx];
+ if (WARN_ON(out_meta->flags & CMD_MAPPED)) {
+ spin_unlock_irqrestore(&priv->hcmd_lock, flags);
+ return -ENOSPC;
+ }
+
memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */
- out_meta->flags = cmd->flags;
if (cmd->flags & CMD_WANT_SKB)
out_meta->source = cmd;
if (cmd->flags & CMD_ASYNC)
out_meta->callback = cmd->callback;
- out_cmd->hdr.cmd = cmd->id;
- memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len);
-
- /* At this point, the out_cmd now has all of the incoming cmd
- * information */
+ /* set up the header */
+ out_cmd->hdr.cmd = cmd->id;
out_cmd->hdr.flags = 0;
out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(priv->cmd_queue) |
- INDEX_TO_SEQ(q->write_ptr));
- if (cmd->flags & CMD_SIZE_HUGE)
- out_cmd->hdr.sequence |= SEQ_HUGE_FRAME;
- len = sizeof(struct iwl_device_cmd);
- if (idx == TFD_CMD_SLOTS)
- len = IWL_MAX_CMD_SIZE;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
- switch (out_cmd->hdr.cmd) {
- case REPLY_TX_LINK_QUALITY_CMD:
- case SENSITIVITY_CMD:
- IWL_DEBUG_HC_DUMP(priv, "Sending command %s (#%x), seq: 0x%04X, "
- "%d bytes at %d[%d]:%d\n",
- get_cmd_string(out_cmd->hdr.cmd),
- out_cmd->hdr.cmd,
- le16_to_cpu(out_cmd->hdr.sequence), fix_size,
- q->write_ptr, idx, priv->cmd_queue);
- break;
- default:
- IWL_DEBUG_HC(priv, "Sending command %s (#%x), seq: 0x%04X, "
- "%d bytes at %d[%d]:%d\n",
- get_cmd_string(out_cmd->hdr.cmd),
- out_cmd->hdr.cmd,
- le16_to_cpu(out_cmd->hdr.sequence), fix_size,
- q->write_ptr, idx, priv->cmd_queue);
+ INDEX_TO_SEQ(q->write_ptr));
+
+ /* and copy the data that needs to be copied */
+
+ cmd_dest = &out_cmd->cmd.payload[0];
+ for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
+ if (!cmd->len[i])
+ continue;
+ if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY)
+ break;
+ memcpy(cmd_dest, cmd->data[i], cmd->len[i]);
+ cmd_dest += cmd->len[i];
}
-#endif
- txq->need_update = 1;
- if (priv->cfg->ops->lib->txq_update_byte_cnt_tbl)
- /* Set up entry in queue's byte count circular buffer */
- priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, 0);
+ IWL_DEBUG_HC(priv, "Sending command %s (#%x), seq: 0x%04X, "
+ "%d bytes at %d[%d]:%d\n",
+ get_cmd_string(out_cmd->hdr.cmd),
+ out_cmd->hdr.cmd,
+ le16_to_cpu(out_cmd->hdr.sequence), cmd_size,
+ q->write_ptr, idx, priv->cmd_queue);
phys_addr = pci_map_single(priv->pci_dev, &out_cmd->hdr,
- fix_size, PCI_DMA_BIDIRECTIONAL);
+ copy_size, PCI_DMA_BIDIRECTIONAL);
+ if (unlikely(pci_dma_mapping_error(priv->pci_dev, phys_addr))) {
+ idx = -ENOMEM;
+ goto out;
+ }
+
dma_unmap_addr_set(out_meta, mapping, phys_addr);
- dma_unmap_len_set(out_meta, len, fix_size);
+ dma_unmap_len_set(out_meta, len, copy_size);
+
+ iwlagn_txq_attach_buf_to_tfd(priv, txq, phys_addr, copy_size, 1);
+#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
+ trace_bufs[0] = &out_cmd->hdr;
+ trace_lens[0] = copy_size;
+ trace_idx = 1;
+#endif
+
+ for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
+ if (!cmd->len[i])
+ continue;
+ if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY))
+ continue;
+ phys_addr = pci_map_single(priv->pci_dev, (void *)cmd->data[i],
+ cmd->len[i], PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(priv->pci_dev, phys_addr)) {
+ iwlagn_unmap_tfd(priv, out_meta,
+ &txq->tfds[q->write_ptr]);
+ idx = -ENOMEM;
+ goto out;
+ }
+
+ iwlagn_txq_attach_buf_to_tfd(priv, txq, phys_addr,
+ cmd->len[i], 0);
+#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
+ trace_bufs[trace_idx] = cmd->data[i];
+ trace_lens[trace_idx] = cmd->len[i];
+ trace_idx++;
+#endif
+ }
- trace_iwlwifi_dev_hcmd(priv, &out_cmd->hdr, fix_size, cmd->flags);
+ out_meta->flags = cmd->flags | CMD_MAPPED;
- priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
- phys_addr, fix_size, 1,
- U32_PAD(cmd->len));
+ txq->need_update = 1;
+
+ /* check that tracing gets all possible blocks */
+ BUILD_BUG_ON(IWL_MAX_CMD_TFDS + 1 != 3);
+#ifdef CONFIG_IWLWIFI_DEVICE_TRACING
+ trace_iwlwifi_dev_hcmd(priv, cmd->flags,
+ trace_bufs[0], trace_lens[0],
+ trace_bufs[1], trace_lens[1],
+ trace_bufs[2], trace_lens[2]);
+#endif
/* Increment and update queue's write index */
q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
iwl_txq_update_write_ptr(priv, txq);
+ out:
spin_unlock_irqrestore(&priv->hcmd_lock, flags);
return idx;
}
@@ -564,8 +746,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
* need to be reclaimed. As result, some free space forms. If there is
* enough free space (> low mark), wake the stack that feeds us.
*/
-static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id,
- int idx, int cmd_idx)
+static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, int idx)
{
struct iwl_tx_queue *txq = &priv->txq[txq_id];
struct iwl_queue *q = &txq->q;
@@ -584,7 +765,7 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id,
if (nfreed++ > 0) {
IWL_ERR(priv, "HCMD skipped: index (%d) %d %d\n", idx,
q->write_ptr, q->read_ptr);
- queue_work(priv->workqueue, &priv->restart);
+ iwlagn_fw_error(priv, false);
}
}
@@ -605,10 +786,10 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
int txq_id = SEQ_TO_QUEUE(sequence);
int index = SEQ_TO_INDEX(sequence);
int cmd_index;
- bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME);
struct iwl_device_cmd *cmd;
struct iwl_cmd_meta *meta;
struct iwl_tx_queue *txq = &priv->txq[priv->cmd_queue];
+ unsigned long flags;
/* If a Tx command is being handled and it isn't in the actual
* command queue then there a command routing bug has been introduced
@@ -622,22 +803,11 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
return;
}
- /* If this is a huge cmd, clear the huge flag on the meta.flags
- * of the _original_ cmd. So that iwl_cmd_queue_free won't unmap
- * the DMA buffer for the scan (huge) command.
- */
- if (huge) {
- cmd_index = get_cmd_index(&txq->q, index, 0);
- txq->meta[cmd_index].flags = 0;
- }
- cmd_index = get_cmd_index(&txq->q, index, huge);
+ cmd_index = get_cmd_index(&txq->q, index);
cmd = txq->cmd[cmd_index];
meta = &txq->meta[cmd_index];
- pci_unmap_single(priv->pci_dev,
- dma_unmap_addr(meta, mapping),
- dma_unmap_len(meta, len),
- PCI_DMA_BIDIRECTIONAL);
+ iwlagn_unmap_tfd(priv, meta, &txq->tfds[index]);
/* Input error checking is done when commands are added to queue. */
if (meta->flags & CMD_WANT_SKB) {
@@ -646,7 +816,9 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
} else if (meta->callback)
meta->callback(priv, cmd, pkt);
- iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index);
+ spin_lock_irqsave(&priv->hcmd_lock, flags);
+
+ iwl_hcmd_queue_reclaim(priv, txq_id, index);
if (!(meta->flags & CMD_ASYNC)) {
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
@@ -654,5 +826,9 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
get_cmd_string(cmd->hdr.cmd));
wake_up_interruptible(&priv->wait_command_queue);
}
+
+ /* Mark as unmapped */
meta->flags = 0;
+
+ spin_unlock_irqrestore(&priv->hcmd_lock, flags);
}
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index 9a57cf6a488f..a414768f40f1 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -565,7 +565,7 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status)
&& iwm->conf.mode == UMAC_MODE_BSS) {
cancel_delayed_work(&iwm->disconnect);
- cfg80211_roamed(iwm_to_ndev(iwm),
+ cfg80211_roamed(iwm_to_ndev(iwm), NULL,
complete->bssid,
iwm->req_ie, iwm->req_ie_len,
iwm->resp_ie, iwm->resp_ie_len,
@@ -586,7 +586,7 @@ static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf,
WLAN_STATUS_SUCCESS,
GFP_KERNEL);
else
- cfg80211_roamed(iwm_to_ndev(iwm),
+ cfg80211_roamed(iwm_to_ndev(iwm), NULL,
complete->bssid,
iwm->req_ie, iwm->req_ie_len,
iwm->resp_ie, iwm->resp_ie_len,
@@ -1576,7 +1576,8 @@ static void iwm_rx_process_amsdu(struct iwm_priv *iwm, struct sk_buff *skb)
IWM_HEXDUMP(iwm, DBG, RX, "A-MSDU: ", skb->data, skb->len);
__skb_queue_head_init(&list);
- ieee80211_amsdu_to_8023s(skb, &list, ndev->dev_addr, wdev->iftype, 0);
+ ieee80211_amsdu_to_8023s(skb, &list, ndev->dev_addr, wdev->iftype, 0,
+ true);
while ((frame = __skb_dequeue(&list))) {
ndev->stats.rx_packets++;
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 5caa2ac14d61..5d637af2d7c3 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -6,6 +6,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/slab.h>
@@ -122,8 +124,10 @@ static u8 lbs_auth_to_authtype(enum nl80211_auth_type auth_type)
}
-/* Various firmware commands need the list of supported rates, but with
- the hight-bit set for basic rates */
+/*
+ * 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;
@@ -425,7 +429,7 @@ static int lbs_add_wpa_tlv(u8 *tlv, const u8 *ie, u8 ie_len)
return ie_len + 2;
}
-/***************************************************************************
+/*
* Set Channel
*/
@@ -452,7 +456,7 @@ static int lbs_cfg_set_channel(struct wiphy *wiphy,
-/***************************************************************************
+/*
* Scanning
*/
@@ -538,8 +542,10 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
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 */
+ /*
+ * 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) {
@@ -581,8 +587,10 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
/* 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 */
+ /*
+ * 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;
@@ -790,7 +798,7 @@ static int lbs_cfg_scan(struct wiphy *wiphy,
-/***************************************************************************
+/*
* Events
*/
@@ -825,7 +833,7 @@ void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event)
-/***************************************************************************
+/*
* Connect/disconnect
*/
@@ -950,8 +958,10 @@ static int lbs_enable_rsn(struct lbs_private *priv, int enable)
* 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 */
+/*
+ * 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;
@@ -1314,8 +1324,8 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
sme->ssid, sme->ssid_len,
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
if (!bss) {
- lbs_pr_err("assoc: bss %pM not in scan results\n",
- sme->bssid);
+ wiphy_err(wiphy, "assoc: bss %pM not in scan results\n",
+ sme->bssid);
ret = -ENOENT;
goto done;
}
@@ -1372,8 +1382,8 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
lbs_enable_rsn(priv, sme->crypto.cipher_group != 0);
break;
default:
- lbs_pr_err("unsupported cipher group 0x%x\n",
- sme->crypto.cipher_group);
+ wiphy_err(wiphy, "unsupported cipher group 0x%x\n",
+ sme->crypto.cipher_group);
ret = -ENOTSUPP;
goto done;
}
@@ -1491,7 +1501,7 @@ static int lbs_cfg_add_key(struct wiphy *wiphy, struct net_device *netdev,
params->key, params->key_len);
break;
default:
- lbs_pr_err("unhandled cipher 0x%x\n", params->cipher);
+ wiphy_err(wiphy, "unhandled cipher 0x%x\n", params->cipher);
ret = -ENOTSUPP;
break;
}
@@ -1536,7 +1546,7 @@ static int lbs_cfg_del_key(struct wiphy *wiphy, struct net_device *netdev,
}
-/***************************************************************************
+/*
* Get station
*/
@@ -1581,7 +1591,7 @@ static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev,
-/***************************************************************************
+/*
* "Site survey", here just current channel and noise level
*/
@@ -1614,7 +1624,7 @@ static int lbs_get_survey(struct wiphy *wiphy, struct net_device *dev,
-/***************************************************************************
+/*
* Change interface
*/
@@ -1656,11 +1666,12 @@ static int lbs_change_intf(struct wiphy *wiphy, struct net_device *dev,
-/***************************************************************************
+/*
* IBSS (Ad-Hoc)
*/
-/* The firmware needs the following bits masked out of the beacon-derived
+/*
+ * 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)
*/
@@ -1999,7 +2010,7 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
-/***************************************************************************
+/*
* Initialization
*/
@@ -2118,13 +2129,13 @@ int lbs_cfg_register(struct lbs_private *priv)
ret = wiphy_register(wdev->wiphy);
if (ret < 0)
- lbs_pr_err("cannot register wiphy device\n");
+ pr_err("cannot register wiphy device\n");
priv->wiphy_registered = true;
ret = register_netdev(priv->dev);
if (ret)
- lbs_pr_err("cannot register network device\n");
+ pr_err("cannot register network device\n");
INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index f3ac62431a30..84566db486d2 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -1,7 +1,7 @@
-/**
- * This file contains the handling of command.
- * It prepares command and sends it to firmware when it is ready.
- */
+/*
+ * This file contains the handling of command.
+ * It prepares command and sends it to firmware when it is ready.
+ */
#include <linux/kfifo.h>
#include <linux/sched.h>
@@ -16,14 +16,14 @@
#define CAL_RSSI(snr, nf) ((s32)((s32)(snr) + CAL_NF(nf)))
/**
- * @brief Simple callback that copies response back into command
+ * lbs_cmd_copyback - Simple callback that copies response back into command
*
- * @param priv A pointer to struct lbs_private structure
- * @param extra A pointer to the original command structure for which
- * 'resp' is a response
- * @param resp A pointer to the command response
+ * @priv: A pointer to &struct lbs_private structure
+ * @extra: A pointer to the original command structure for which
+ * 'resp' is a response
+ * @resp: A pointer to the command response
*
- * @return 0 on success, error on failure
+ * returns: 0 on success, error on failure
*/
int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
struct cmd_header *resp)
@@ -38,15 +38,15 @@ int lbs_cmd_copyback(struct lbs_private *priv, unsigned long extra,
EXPORT_SYMBOL_GPL(lbs_cmd_copyback);
/**
- * @brief Simple callback that ignores the result. Use this if
- * you just want to send a command to the hardware, but don't
+ * lbs_cmd_async_callback - Simple callback that ignores the result.
+ * Use this if you just want to send a command to the hardware, but don't
* care for the result.
*
- * @param priv ignored
- * @param extra ignored
- * @param resp ignored
+ * @priv: ignored
+ * @extra: ignored
+ * @resp: ignored
*
- * @return 0 for success
+ * returns: 0 for success
*/
static int lbs_cmd_async_callback(struct lbs_private *priv, unsigned long extra,
struct cmd_header *resp)
@@ -56,10 +56,11 @@ static int lbs_cmd_async_callback(struct lbs_private *priv, unsigned long extra,
/**
- * @brief Checks whether a command is allowed in Power Save mode
+ * is_command_allowed_in_ps - tests if a command is allowed in Power Save mode
+ *
+ * @cmd: the command ID
*
- * @param command the command ID
- * @return 1 if allowed, 0 if not allowed
+ * returns: 1 if allowed, 0 if not allowed
*/
static u8 is_command_allowed_in_ps(u16 cmd)
{
@@ -75,11 +76,12 @@ static u8 is_command_allowed_in_ps(u16 cmd)
}
/**
- * @brief Updates the hardware details like MAC address and regulatory region
+ * lbs_update_hw_spec - Updates the hardware details like MAC address
+ * and regulatory region
*
- * @param priv A pointer to struct lbs_private structure
+ * @priv: A pointer to &struct lbs_private structure
*
- * @return 0 on success, error on failure
+ * returns: 0 on success, error on failure
*/
int lbs_update_hw_spec(struct lbs_private *priv)
{
@@ -108,7 +110,7 @@ int lbs_update_hw_spec(struct lbs_private *priv)
* CF card firmware 5.0.16p0: cap 0x00000303
* USB dongle firmware 5.110.17p2: cap 0x00000303
*/
- lbs_pr_info("%pM, fw %u.%u.%up%u, cap 0x%08x\n",
+ netdev_info(priv->dev, "%pM, fw %u.%u.%up%u, cap 0x%08x\n",
cmd.permanentaddr,
priv->fwrelease >> 24 & 0xff,
priv->fwrelease >> 16 & 0xff,
@@ -139,7 +141,8 @@ int lbs_update_hw_spec(struct lbs_private *priv)
/* if it's unidentified region code, use the default (USA) */
if (i >= MRVDRV_MAX_REGION_CODE) {
priv->regioncode = 0x10;
- lbs_pr_info("unidentified region code; using the default (USA)\n");
+ netdev_info(priv->dev,
+ "unidentified region code; using the default (USA)\n");
}
if (priv->current_addr[0] == 0xff)
@@ -209,7 +212,7 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
(uint8_t *)&cmd_config.wol_conf,
sizeof(struct wol_config));
} else {
- lbs_pr_info("HOST_SLEEP_CFG failed %d\n", ret);
+ netdev_info(priv->dev, "HOST_SLEEP_CFG failed %d\n", ret);
}
return ret;
@@ -217,14 +220,14 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
EXPORT_SYMBOL_GPL(lbs_host_sleep_cfg);
/**
- * @brief Sets the Power Save mode
+ * lbs_set_ps_mode - 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
+ * @priv: A pointer to &struct lbs_private structure
+ * @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
+ * @block: Whether to block on a response or not
*
- * @return 0 on success, error on failure
+ * returns: 0 on success, error on failure
*/
int lbs_set_ps_mode(struct lbs_private *priv, u16 cmd_action, bool block)
{
@@ -312,7 +315,7 @@ static int lbs_wait_for_ds_awake(struct lbs_private *priv)
if (priv->is_deep_sleep) {
if (!wait_event_interruptible_timeout(priv->ds_awake_q,
!priv->is_deep_sleep, (10 * HZ))) {
- lbs_pr_err("ds_awake_q: timer expired\n");
+ netdev_err(priv->dev, "ds_awake_q: timer expired\n");
ret = -1;
}
}
@@ -337,7 +340,7 @@ int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
netif_carrier_off(priv->dev);
}
} else {
- lbs_pr_err("deep sleep: already enabled\n");
+ netdev_err(priv->dev, "deep sleep: already enabled\n");
}
} else {
if (priv->is_deep_sleep) {
@@ -347,8 +350,8 @@ int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
if (!ret) {
ret = lbs_wait_for_ds_awake(priv);
if (ret)
- lbs_pr_err("deep sleep: wakeup"
- "failed\n");
+ netdev_err(priv->dev,
+ "deep sleep: wakeup failed\n");
}
}
}
@@ -382,8 +385,9 @@ int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep)
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);
+ netdev_info(priv->dev,
+ "Host sleep configuration failed: %d\n",
+ ret);
return ret;
}
if (priv->psstate == PS_STATE_FULL_POWER) {
@@ -393,19 +397,21 @@ int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep)
sizeof(cmd),
lbs_ret_host_sleep_activate, 0);
if (ret)
- lbs_pr_info("HOST_SLEEP_ACTIVATE "
- "failed: %d\n", ret);
+ netdev_info(priv->dev,
+ "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");
+ netdev_err(priv->dev,
+ "host_sleep_q: timer expired\n");
ret = -1;
}
} else {
- lbs_pr_err("host sleep: already enabled\n");
+ netdev_err(priv->dev, "host sleep: already enabled\n");
}
} else {
if (priv->is_host_sleep_activated)
@@ -417,13 +423,13 @@ int lbs_set_host_sleep(struct lbs_private *priv, int host_sleep)
}
/**
- * @brief Set an SNMP MIB value
+ * lbs_set_snmp_mib - Set an SNMP MIB value
*
- * @param priv A pointer to struct lbs_private structure
- * @param oid The OID to set in the firmware
- * @param val Value to set the OID to
+ * @priv: A pointer to &struct lbs_private structure
+ * @oid: The OID to set in the firmware
+ * @val: Value to set the OID to
*
- * @return 0 on success, error on failure
+ * returns: 0 on success, error on failure
*/
int lbs_set_snmp_mib(struct lbs_private *priv, u32 oid, u16 val)
{
@@ -467,13 +473,13 @@ out:
}
/**
- * @brief Get an SNMP MIB value
+ * lbs_get_snmp_mib - Get an SNMP MIB value
*
- * @param priv A pointer to struct lbs_private structure
- * @param oid The OID to retrieve from the firmware
- * @param out_val Location for the returned value
+ * @priv: A pointer to &struct lbs_private structure
+ * @oid: The OID to retrieve from the firmware
+ * @out_val: Location for the returned value
*
- * @return 0 on success, error on failure
+ * returns: 0 on success, error on failure
*/
int lbs_get_snmp_mib(struct lbs_private *priv, u32 oid, u16 *out_val)
{
@@ -510,14 +516,14 @@ out:
}
/**
- * @brief Get the min, max, and current TX power
+ * lbs_get_tx_power - Get the min, max, and current TX power
*
- * @param priv A pointer to struct lbs_private structure
- * @param curlevel Current power level in dBm
- * @param minlevel Minimum supported power level in dBm (optional)
- * @param maxlevel Maximum supported power level in dBm (optional)
+ * @priv: A pointer to &struct lbs_private structure
+ * @curlevel: Current power level in dBm
+ * @minlevel: Minimum supported power level in dBm (optional)
+ * @maxlevel: Maximum supported power level in dBm (optional)
*
- * @return 0 on success, error on failure
+ * returns: 0 on success, error on failure
*/
int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
s16 *maxlevel)
@@ -545,12 +551,12 @@ int lbs_get_tx_power(struct lbs_private *priv, s16 *curlevel, s16 *minlevel,
}
/**
- * @brief Set the TX power
+ * lbs_set_tx_power - Set the TX power
*
- * @param priv A pointer to struct lbs_private structure
- * @param dbm The desired power level in dBm
+ * @priv: A pointer to &struct lbs_private structure
+ * @dbm: The desired power level in dBm
*
- * @return 0 on success, error on failure
+ * returns: 0 on success, error on failure
*/
int lbs_set_tx_power(struct lbs_private *priv, s16 dbm)
{
@@ -573,12 +579,13 @@ int lbs_set_tx_power(struct lbs_private *priv, s16 dbm)
}
/**
- * @brief Enable or disable monitor mode (only implemented on OLPC usb8388 FW)
+ * lbs_set_monitor_mode - 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
+ * @priv: A pointer to &struct lbs_private structure
+ * @enable: 1 to enable monitor mode, 0 to disable
*
- * @return 0 on success, error on failure
+ * returns: 0 on success, error on failure
*/
int lbs_set_monitor_mode(struct lbs_private *priv, int enable)
{
@@ -604,11 +611,11 @@ int lbs_set_monitor_mode(struct lbs_private *priv, int enable)
}
/**
- * @brief Get the radio channel
+ * lbs_get_channel - Get the radio channel
*
- * @param priv A pointer to struct lbs_private structure
+ * @priv: A pointer to &struct lbs_private structure
*
- * @return The channel on success, error on failure
+ * returns: The channel on success, error on failure
*/
static int lbs_get_channel(struct lbs_private *priv)
{
@@ -650,12 +657,12 @@ int lbs_update_channel(struct lbs_private *priv)
}
/**
- * @brief Set the radio channel
+ * lbs_set_channel - Set the radio channel
*
- * @param priv A pointer to struct lbs_private structure
- * @param channel The desired channel, or 0 to clear a locked channel
+ * @priv: A pointer to &struct lbs_private structure
+ * @channel: The desired channel, or 0 to clear a locked channel
*
- * @return 0 on success, error on failure
+ * returns: 0 on success, error on failure
*/
int lbs_set_channel(struct lbs_private *priv, u8 channel)
{
@@ -686,12 +693,13 @@ out:
}
/**
- * @brief Get current RSSI and noise floor
+ * lbs_get_rssi - Get current RSSI and noise floor
*
- * @param priv A pointer to struct lbs_private structure
- * @param rssi On successful return, signal level in mBm
+ * @priv: A pointer to &struct lbs_private structure
+ * @rssi: On successful return, signal level in mBm
+ * @nf: On successful return, Noise floor
*
- * @return The channel on success, error on failure
+ * returns: The channel on success, error on failure
*/
int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf)
{
@@ -719,13 +727,14 @@ int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf)
}
/**
- * @brief Send regulatory and 802.11d domain information to the firmware
+ * lbs_set_11d_domain_info - 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
+ * @priv: pointer to &struct lbs_private
+ * @request: cfg80211 regulatory request structure
+ * @bands: the device's supported bands and channels
*
- * @return 0 on success, error code on failure
+ * returns: 0 on success, error code on failure
*/
int lbs_set_11d_domain_info(struct lbs_private *priv,
struct regulatory_request *request,
@@ -842,15 +851,15 @@ int lbs_set_11d_domain_info(struct lbs_private *priv,
}
/**
- * @brief Read a MAC, Baseband, or RF register
+ * lbs_get_reg - 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'
+ * @priv: pointer to &struct lbs_private
+ * @reg: register command, one of CMD_MAC_REG_ACCESS,
+ * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS
+ * @offset: byte offset of the register to get
+ * @value: on success, the value of the register at 'offset'
*
- * @return 0 on success, error code on failure
+ * returns: 0 on success, error code on failure
*/
int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value)
{
@@ -886,15 +895,15 @@ out:
}
/**
- * @brief Write a MAC, Baseband, or RF register
+ * lbs_set_reg - 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'
+ * @priv: pointer to &struct lbs_private
+ * @reg: register command, one of CMD_MAC_REG_ACCESS,
+ * CMD_BBP_REG_ACCESS, or CMD_RF_REG_ACCESS
+ * @offset: byte offset of the register to set
+ * @value: the value to write to the register at 'offset'
*
- * @return 0 on success, error code on failure
+ * returns: 0 on success, error code on failure
*/
int lbs_set_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 value)
{
@@ -1002,7 +1011,8 @@ static void lbs_submit_command(struct lbs_private *priv,
ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
if (ret) {
- lbs_pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret);
+ netdev_info(priv->dev, "DNLD_CMD: hw_host_to_card failed: %d\n",
+ ret);
/* Let the timer kick in and retry, and potentially reset
the whole thing if the condition persists */
timeo = HZ/4;
@@ -1023,7 +1033,7 @@ static void lbs_submit_command(struct lbs_private *priv,
lbs_deb_leave(LBS_DEB_HOST);
}
-/**
+/*
* This function inserts command node to cmdfreeq
* after cleans it. Requires priv->driver_lock held.
*/
@@ -1125,11 +1135,12 @@ void lbs_set_mac_control(struct lbs_private *priv)
}
/**
- * @brief This function allocates the command buffer and link
- * it to command free queue.
+ * lbs_allocate_cmd_buffer - allocates the command buffer and links
+ * it to command free queue
+ *
+ * @priv: A pointer to &struct lbs_private structure
*
- * @param priv A pointer to struct lbs_private structure
- * @return 0 or -1
+ * returns: 0 for success or -1 on error
*/
int lbs_allocate_cmd_buffer(struct lbs_private *priv)
{
@@ -1171,10 +1182,11 @@ done:
}
/**
- * @brief This function frees the command buffer.
+ * lbs_free_cmd_buffer - free the command buffer
*
- * @param priv A pointer to struct lbs_private structure
- * @return 0 or -1
+ * @priv: A pointer to &struct lbs_private structure
+ *
+ * returns: 0 for success
*/
int lbs_free_cmd_buffer(struct lbs_private *priv)
{
@@ -1211,11 +1223,13 @@ done:
}
/**
- * @brief This function gets a free command node if available in
- * command free queue.
+ * lbs_get_free_cmd_node - gets a free command node if available in
+ * command free queue
+ *
+ * @priv: A pointer to &struct lbs_private structure
*
- * @param priv A pointer to struct lbs_private structure
- * @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL
+ * returns: A pointer to &cmd_ctrl_node structure on success
+ * or %NULL on error
*/
static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv)
{
@@ -1245,12 +1259,12 @@ static struct cmd_ctrl_node *lbs_get_free_cmd_node(struct lbs_private *priv)
}
/**
- * @brief This function executes next command in command
- * pending queue. It will put firmware back to PS mode
- * if applicable.
+ * lbs_execute_next_command - execute next command in command
+ * pending queue. Will put firmware back to PS mode if applicable.
*
- * @param priv A pointer to struct lbs_private structure
- * @return 0 or -1
+ * @priv: A pointer to &struct lbs_private structure
+ *
+ * returns: 0 on success or -1 on error
*/
int lbs_execute_next_command(struct lbs_private *priv)
{
@@ -1267,7 +1281,8 @@ int lbs_execute_next_command(struct lbs_private *priv)
spin_lock_irqsave(&priv->driver_lock, flags);
if (priv->cur_cmd) {
- lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n");
+ netdev_alert(priv->dev,
+ "EXEC_NEXT_CMD: already processing command!\n");
spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = -1;
goto done;
@@ -1431,7 +1446,7 @@ static void lbs_send_confirmsleep(struct lbs_private *priv)
ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &confirm_sleep,
sizeof(confirm_sleep));
if (ret) {
- lbs_pr_alert("confirm_sleep failed\n");
+ netdev_alert(priv->dev, "confirm_sleep failed\n");
goto out;
}
@@ -1456,12 +1471,12 @@ out:
}
/**
- * @brief This function checks condition and prepares to
- * send sleep confirm command to firmware if ok.
+ * lbs_ps_confirm_sleep - checks condition and prepares to
+ * send sleep confirm command to firmware if ok
+ *
+ * @priv: A pointer to &struct lbs_private structure
*
- * @param priv A pointer to struct lbs_private structure
- * @param psmode Power Saving mode
- * @return n/a
+ * returns: n/a
*/
void lbs_ps_confirm_sleep(struct lbs_private *priv)
{
@@ -1501,16 +1516,16 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv)
/**
- * @brief Configures the transmission power control functionality.
+ * lbs_set_tpc_cfg - Configures the transmission power control functionality
*
- * @param priv A pointer to struct lbs_private structure
- * @param enable Transmission power control enable
- * @param p0 Power level when link quality is good (dBm).
- * @param p1 Power level when link quality is fair (dBm).
- * @param p2 Power level when link quality is poor (dBm).
- * @param usesnr Use Signal to Noise Ratio in TPC
+ * @priv: A pointer to &struct lbs_private structure
+ * @enable: Transmission power control enable
+ * @p0: Power level when link quality is good (dBm).
+ * @p1: Power level when link quality is fair (dBm).
+ * @p2: Power level when link quality is poor (dBm).
+ * @usesnr: Use Signal to Noise Ratio in TPC
*
- * @return 0 on success
+ * returns: 0 on success
*/
int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
int8_t p2, int usesnr)
@@ -1533,15 +1548,15 @@ int lbs_set_tpc_cfg(struct lbs_private *priv, int enable, int8_t p0, int8_t p1,
}
/**
- * @brief Configures the power adaptation settings.
+ * lbs_set_power_adapt_cfg - Configures the power adaptation settings
*
- * @param priv A pointer to struct lbs_private structure
- * @param enable Power adaptation enable
- * @param p0 Power level for 1, 2, 5.5 and 11 Mbps (dBm).
- * @param p1 Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm).
- * @param p2 Power level for 48 and 54 Mbps (dBm).
+ * @priv: A pointer to &struct lbs_private structure
+ * @enable: Power adaptation enable
+ * @p0: Power level for 1, 2, 5.5 and 11 Mbps (dBm).
+ * @p1: Power level for 6, 9, 12, 18, 22, 24 and 36 Mbps (dBm).
+ * @p2: Power level for 48 and 54 Mbps (dBm).
*
- * @return 0 on Success
+ * returns: 0 on Success
*/
int lbs_set_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
@@ -1657,7 +1672,7 @@ int __lbs_cmd(struct lbs_private *priv, uint16_t command,
spin_lock_irqsave(&priv->driver_lock, flags);
ret = cmdnode->result;
if (ret)
- lbs_pr_info("PREP_CMD: command 0x%04x failed: %d\n",
+ netdev_info(priv->dev, "PREP_CMD: command 0x%04x failed: %d\n",
command, ret);
__lbs_cleanup_and_insert_cmd(priv, cmdnode);
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 5e95da9dcc2e..207fc361db84 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -1,7 +1,8 @@
-/**
- * This file contains the handling of command
- * responses as well as events generated by firmware.
- */
+/*
+ * This file contains the handling of command
+ * responses as well as events generated by firmware.
+ */
+
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/sched.h>
@@ -12,12 +13,13 @@
#include "cmd.h"
/**
- * @brief This function handles disconnect event. it
- * reports disconnect to upper layer, clean tx/rx packets,
- * reset link state etc.
+ * lbs_mac_event_disconnected - handles disconnect event. It
+ * reports disconnect to upper layer, clean tx/rx packets,
+ * reset link state etc.
+ *
+ * @priv: A pointer to struct lbs_private structure
*
- * @param priv A pointer to struct lbs_private structure
- * @return n/a
+ * returns: n/a
*/
void lbs_mac_event_disconnected(struct lbs_private *priv)
{
@@ -84,15 +86,18 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, len);
if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
- lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n",
- le16_to_cpu(resp->seqnum), le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum));
+ netdev_info(priv->dev,
+ "Received CMD_RESP with invalid sequence %d (expected %d)\n",
+ le16_to_cpu(resp->seqnum),
+ le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum));
spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = -1;
goto done;
}
if (respcmd != CMD_RET(curcmd) &&
respcmd != CMD_RET_802_11_ASSOCIATE && curcmd != CMD_802_11_ASSOCIATE) {
- lbs_pr_info("Invalid CMD_RESP %x to command %x!\n", respcmd, curcmd);
+ netdev_info(priv->dev, "Invalid CMD_RESP %x to command %x!\n",
+ respcmd, curcmd);
spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = -1;
goto done;
@@ -101,7 +106,8 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
if (resp->result == cpu_to_le16(0x0004)) {
/* 0x0004 means -EAGAIN. Drop the response, let it time out
and be resubmitted */
- lbs_pr_info("Firmware returns DEFER to command %x. Will let it time out...\n",
+ netdev_info(priv->dev,
+ "Firmware returns DEFER to command %x. Will let it time out...\n",
le16_to_cpu(resp->command));
spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = -1;
@@ -313,28 +319,28 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
lbs_deb_cmd("EVENT: ADHOC beacon lost\n");
break;
case MACREG_INT_CODE_RSSI_LOW:
- lbs_pr_alert("EVENT: rssi low\n");
+ netdev_alert(priv->dev, "EVENT: rssi low\n");
break;
case MACREG_INT_CODE_SNR_LOW:
- lbs_pr_alert("EVENT: snr low\n");
+ netdev_alert(priv->dev, "EVENT: snr low\n");
break;
case MACREG_INT_CODE_MAX_FAIL:
- lbs_pr_alert("EVENT: max fail\n");
+ netdev_alert(priv->dev, "EVENT: max fail\n");
break;
case MACREG_INT_CODE_RSSI_HIGH:
- lbs_pr_alert("EVENT: rssi high\n");
+ netdev_alert(priv->dev, "EVENT: rssi high\n");
break;
case MACREG_INT_CODE_SNR_HIGH:
- lbs_pr_alert("EVENT: snr high\n");
+ netdev_alert(priv->dev, "EVENT: snr high\n");
break;
case MACREG_INT_CODE_MESH_AUTO_STARTED:
/* Ignore spurious autostart events */
- lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
+ netdev_info(priv->dev, "EVENT: MESH_AUTO_STARTED (ignoring)\n");
break;
default:
- lbs_pr_alert("EVENT: unknown event id %d\n", event);
+ netdev_alert(priv->dev, "EVENT: unknown event id %d\n", event);
break;
}
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index fbf3b0332bb7..23250f621761 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -151,13 +151,14 @@ static ssize_t lbs_host_sleep_write(struct file *file,
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");
+ netdev_info(priv->dev,
+ "wake parameters not configured\n");
ret = -EINVAL;
goto out_unlock;
}
ret = lbs_set_host_sleep(priv, 1);
} else {
- lbs_pr_err("invalid option\n");
+ netdev_err(priv->dev, "invalid option\n");
ret = -EINVAL;
}
@@ -849,15 +850,14 @@ static struct debug_data items[] = {
static int num_of_items = ARRAY_SIZE(items);
/**
- * @brief proc read function
+ * lbs_debugfs_read - proc read function
*
- * @param page pointer to buffer
- * @param s read data starting position
- * @param off offset
- * @param cnt counter
- * @param eof end of file flag
- * @param data data to output
- * @return number of output data
+ * @file: file to read
+ * @userbuf: pointer to buffer
+ * @count: number of bytes to read
+ * @ppos: read data starting position
+ *
+ * returns: amount of data read or negative error code
*/
static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
@@ -897,13 +897,14 @@ static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
}
/**
- * @brief proc write function
+ * lbs_debugfs_write - proc write function
+ *
+ * @f: file pointer
+ * @buf: pointer to data buffer
+ * @cnt: data number to write
+ * @ppos: file position
*
- * @param f file pointer
- * @param buf pointer to data buffer
- * @param cnt data number to write
- * @param data data to write
- * @return number of data
+ * returns: amount of data written
*/
static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
size_t cnt, loff_t *ppos)
@@ -966,11 +967,11 @@ static const struct file_operations lbs_debug_fops = {
};
/**
- * @brief create debug proc file
+ * lbs_debug_init - create debug proc file
+ *
+ * @priv: pointer to &struct lbs_private
*
- * @param priv pointer struct lbs_private
- * @param dev pointer net_device
- * @return N/A
+ * returns: N/A
*/
static void lbs_debug_init(struct lbs_private *priv)
{
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 2ae752d10065..da0b05bb89fe 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -1,8 +1,8 @@
-/**
- * This file contains declaration referring to
- * functions defined in other source files
- */
+/*
+ * This file contains declaration referring to
+ * functions defined in other source files
+ */
#ifndef _LBS_DECL_H_
#define _LBS_DECL_H_
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index d00c728cec47..ab966f08024a 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -1,7 +1,7 @@
-/**
- * This header file contains global constant/enum definitions,
- * global variable declaration.
- */
+/*
+ * This header file contains global constant/enum definitions,
+ * global variable declaration.
+ */
#ifndef _LBS_DEFS_H_
#define _LBS_DEFS_H_
@@ -89,13 +89,6 @@ do { if ((lbs_debug & (grp)) == (grp)) \
#define lbs_deb_spi(fmt, args...) LBS_DEB_LL(LBS_DEB_SPI, " spi", fmt, ##args)
#define lbs_deb_cfg80211(fmt, args...) LBS_DEB_LL(LBS_DEB_CFG80211, " cfg80211", fmt, ##args)
-#define lbs_pr_info(format, args...) \
- printk(KERN_INFO DRV_NAME": " format, ## args)
-#define lbs_pr_err(format, args...) \
- printk(KERN_ERR DRV_NAME": " format, ## args)
-#define lbs_pr_alert(format, args...) \
- printk(KERN_ALERT DRV_NAME": " format, ## args)
-
#ifdef DEBUG
static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, int len)
{
@@ -123,19 +116,19 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
-/** Buffer Constants */
+/* Buffer Constants */
/* The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical
-* addresses of TxPD buffers. Station has only 8 TxPD available, Whereas
-* driver has more local TxPDs. Each TxPD on the host memory is associated
-* with a Tx control node. The driver maintains 8 RxPD descriptors for
-* station firmware to store Rx packet information.
-*
-* Current version of MAC has a 32x6 multicast address buffer.
-*
-* 802.11b can have up to 14 channels, the driver keeps the
-* BSSID(MAC address) of each APs or Ad hoc stations it has sensed.
-*/
+ * addresses of TxPD buffers. Station has only 8 TxPD available, Whereas
+ * driver has more local TxPDs. Each TxPD on the host memory is associated
+ * with a Tx control node. The driver maintains 8 RxPD descriptors for
+ * station firmware to store Rx packet information.
+ *
+ * Current version of MAC has a 32x6 multicast address buffer.
+ *
+ * 802.11b can have up to 14 channels, the driver keeps the
+ * BSSID(MAC address) of each APs or Ad hoc stations it has sensed.
+ */
#define MRVDRV_MAX_MULTICAST_LIST_SIZE 32
#define LBS_NUM_CMD_BUFFERS 10
@@ -166,7 +159,7 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
#define WOL_RESULT_NOSPC_ERR 1
#define WOL_RESULT_EEXIST_ERR 2
-/** Misc constants */
+/* Misc constants */
/* This section defines 802.11 specific contants */
#define MRVDRV_MAX_BSS_DESCRIPTS 16
@@ -183,7 +176,8 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
#define MARVELL_MESH_IE_LENGTH 9
-/* Values used to populate the struct mrvl_mesh_ie. The only time you need this
+/*
+ * Values used to populate the struct mrvl_mesh_ie. The only time you need this
* is when enabling the mesh using CMD_MESH_CONFIG.
*/
#define MARVELL_MESH_IE_TYPE 4
@@ -193,7 +187,7 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
#define MARVELL_MESH_METRIC_ID 0
#define MARVELL_MESH_CAPABILITY 0
-/** INT status Bit Definition*/
+/* INT status Bit Definition */
#define MRVDRV_TX_DNLD_RDY 0x0001
#define MRVDRV_RX_UPLD_RDY 0x0002
#define MRVDRV_CMD_DNLD_RDY 0x0004
@@ -208,59 +202,63 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
#define TPC_DEFAULT_P1 10
#define TPC_DEFAULT_P2 13
-/** TxPD status */
+/* TxPD status */
-/* Station firmware use TxPD status field to report final Tx transmit
-* result, Bit masks are used to present combined situations.
-*/
+/*
+ * Station firmware use TxPD status field to report final Tx transmit
+ * result, Bit masks are used to present combined situations.
+ */
#define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01
#define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08
-/** Tx mesh flag */
-/* Currently we are using normal WDS flag as mesh flag.
+/* Tx mesh flag */
+/*
+ * Currently we are using normal WDS flag as mesh flag.
* TODO: change to proper mesh flag when MAC understands it.
*/
#define TxPD_CONTROL_WDS_FRAME (1<<17)
#define TxPD_MESH_FRAME TxPD_CONTROL_WDS_FRAME
-/** Mesh interface ID */
+/* Mesh interface ID */
#define MESH_IFACE_ID 0x0001
-/** Mesh id should be in bits 14-13-12 */
+/* Mesh id should be in bits 14-13-12 */
#define MESH_IFACE_BIT_OFFSET 0x000c
-/** Mesh enable bit in FW capability */
+/* Mesh enable bit in FW capability */
#define MESH_CAPINFO_ENABLE_MASK (1<<16)
-/** FW definition from Marvell v4 */
+/* FW definition from Marvell v4 */
#define MRVL_FW_V4 (0x04)
-/** FW definition from Marvell v5 */
+/* FW definition from Marvell v5 */
#define MRVL_FW_V5 (0x05)
-/** FW definition from Marvell v10 */
+/* FW definition from Marvell v10 */
#define MRVL_FW_V10 (0x0a)
-/** FW major revision definition */
+/* FW major revision definition */
#define MRVL_FW_MAJOR_REV(x) ((x)>>24)
-/** RxPD status */
+/* RxPD status */
#define MRVDRV_RXPD_STATUS_OK 0x0001
-/** RxPD status - Received packet types */
-/** Rx mesh flag */
-/* Currently we are using normal WDS flag as mesh flag.
+/* RxPD status - Received packet types */
+/* Rx mesh flag */
+/*
+ * Currently we are using normal WDS flag as mesh flag.
* TODO: change to proper mesh flag when MAC understands it.
*/
#define RxPD_CONTROL_WDS_FRAME (0x40)
#define RxPD_MESH_FRAME RxPD_CONTROL_WDS_FRAME
-/** RSSI-related defines */
-/* RSSI constants are used to implement 802.11 RSSI threshold
-* indication. if the Rx packet signal got too weak for 5 consecutive
-* times, miniport driver (driver) will report this event to wrapper
-*/
+/* RSSI-related defines */
+/*
+ * RSSI constants are used to implement 802.11 RSSI threshold
+ * indication. if the Rx packet signal got too weak for 5 consecutive
+ * times, miniport driver (driver) will report this event to wrapper
+ */
#define MRVDRV_NF_DEFAULT_SCAN_VALUE (-96)
-/** RTS/FRAG related defines */
+/* RTS/FRAG related defines */
#define MRVDRV_RTS_MIN_VALUE 0
#define MRVDRV_RTS_MAX_VALUE 2347
#define MRVDRV_FRAG_MIN_VALUE 256
@@ -300,36 +298,36 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
#define MAX_LEDS 8
-/** Global Variable Declaration */
+/* Global Variable Declaration */
extern const char lbs_driver_version[];
extern u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE];
-/** ENUM definition*/
-/** SNRNF_TYPE */
+/* ENUM definition */
+/* SNRNF_TYPE */
enum SNRNF_TYPE {
TYPE_BEACON = 0,
TYPE_RXPD,
MAX_TYPE_B
};
-/** SNRNF_DATA*/
+/* SNRNF_DATA */
enum SNRNF_DATA {
TYPE_NOAVG = 0,
TYPE_AVG,
MAX_TYPE_AVG
};
-/** LBS_802_11_POWER_MODE */
+/* LBS_802_11_POWER_MODE */
enum LBS_802_11_POWER_MODE {
LBS802_11POWERMODECAM,
LBS802_11POWERMODEMAX_PSP,
LBS802_11POWERMODEFAST_PSP,
- /*not a real mode, defined as an upper bound */
+ /* not a real mode, defined as an upper bound */
LBS802_11POWEMODEMAX
};
-/** PS_STATE */
+/* PS_STATE */
enum PS_STATE {
PS_STATE_FULL_POWER,
PS_STATE_AWAKE,
@@ -337,7 +335,7 @@ enum PS_STATE {
PS_STATE_SLEEP
};
-/** DNLD_STATE */
+/* DNLD_STATE */
enum DNLD_STATE {
DNLD_RES_RECEIVED,
DNLD_DATA_SENT,
@@ -345,19 +343,19 @@ enum DNLD_STATE {
DNLD_BOOTCMD_SENT,
};
-/** LBS_MEDIA_STATE */
+/* LBS_MEDIA_STATE */
enum LBS_MEDIA_STATE {
LBS_CONNECTED,
LBS_DISCONNECTED
};
-/** LBS_802_11_PRIVACY_FILTER */
+/* LBS_802_11_PRIVACY_FILTER */
enum LBS_802_11_PRIVACY_FILTER {
LBS802_11PRIVFILTERACCEPTALL,
LBS802_11PRIVFILTER8021XWEP
};
-/** mv_ms_type */
+/* mv_ms_type */
enum mv_ms_type {
MVMS_DAT = 0,
MVMS_CMD = 1,
@@ -365,14 +363,14 @@ enum mv_ms_type {
MVMS_EVENT
};
-/** KEY_TYPE_ID */
+/* KEY_TYPE_ID */
enum KEY_TYPE_ID {
KEY_TYPE_ID_WEP = 0,
KEY_TYPE_ID_TKIP,
KEY_TYPE_ID_AES
};
-/** KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */
+/* KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */
enum KEY_INFO_WPA {
KEY_INFO_WPA_MCAST = 0x01,
KEY_INFO_WPA_UNICAST = 0x02,
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index bc461eb39660..76d018beebf4 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -1,8 +1,8 @@
-/**
- * This file contains definitions and data structures specific
- * to Marvell 802.11 NIC. It contains the Device Information
- * structure struct lbs_private..
- */
+/*
+ * This file contains definitions and data structures specific
+ * to Marvell 802.11 NIC. It contains the Device Information
+ * structure struct lbs_private..
+ */
#ifndef _LBS_DEV_H_
#define _LBS_DEV_H_
@@ -12,7 +12,7 @@
#include <linux/kfifo.h>
-/** sleep_params */
+/* sleep_params */
struct sleep_params {
uint16_t sp_error;
uint16_t sp_offset;
@@ -23,7 +23,7 @@ struct sleep_params {
};
-/** Private structure for the MV device */
+/* Private structure for the MV device */
struct lbs_private {
/* Basic networking */
@@ -125,12 +125,12 @@ struct lbs_private {
/* Events sent from hardware to driver */
struct kfifo event_fifo;
- /** thread to service interrupts */
+ /* thread to service interrupts */
struct task_struct *main_thread;
wait_queue_head_t waitq;
struct workqueue_struct *work_thread;
- /** Encryption stuff */
+ /* Encryption stuff */
u8 authtype_auto;
u8 wep_tx_key;
u8 wep_key[4][WLAN_KEY_LEN_WEP104];
@@ -162,7 +162,7 @@ struct lbs_private {
s16 txpower_min;
s16 txpower_max;
- /** Scanning */
+ /* Scanning */
struct delayed_work scan_work;
int scan_channel;
/* Queue of things waiting for scan completion */
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
index 50193aac679e..29dbce4a9f86 100644
--- a/drivers/net/wireless/libertas/ethtool.c
+++ b/drivers/net/wireless/libertas/ethtool.c
@@ -20,7 +20,8 @@ static void lbs_ethtool_get_drvinfo(struct net_device *dev,
strcpy(info->version, lbs_driver_version);
}
-/* All 8388 parts have 16KiB EEPROM size at the time of writing.
+/*
+ * All 8388 parts have 16KiB EEPROM size at the time of writing.
* In case that changes this needs fixing.
*/
#define LBS_EEPROM_LEN 16384
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index 6cb6935ee4a3..2e2dbfa2ee50 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -1,7 +1,7 @@
-/**
- * This file function prototypes, data structure
- * and definitions for all the host/station commands
- */
+/*
+ * This file function prototypes, data structure
+ * and definitions for all the host/station commands
+ */
#ifndef _LBS_HOST_H_
#define _LBS_HOST_H_
@@ -13,9 +13,10 @@
#define CMD_OPTION_WAITFORRSP 0x0002
-/** Host command IDs */
+/* Host command IDs */
-/* Return command are almost always the same as the host command, but with
+/*
+ * Return command are almost always the same as the host command, but with
* bit 15 set high. There are a few exceptions, though...
*/
#define CMD_RET(cmd) (0x8000 | cmd)
@@ -251,7 +252,7 @@ enum cmd_mesh_config_types {
CMD_TYPE_MESH_GET_MESH_IE, /* GET_DEFAULTS is superset of GET_MESHIE */
};
-/** Card Event definition */
+/* Card Event definition */
#define MACREG_INT_CODE_TX_PPA_FREE 0
#define MACREG_INT_CODE_TX_DMA_DONE 1
#define MACREG_INT_CODE_LINK_LOST_W_SCAN 2
@@ -624,12 +625,14 @@ struct cmd_ds_802_11_rf_channel {
struct cmd_ds_802_11_rssi {
struct cmd_header hdr;
- /* request: number of beacons (N) to average the SNR and NF over
+ /*
+ * request: number of beacons (N) to average the SNR and NF over
* response: SNR of most recent beacon
*/
__le16 n_or_snr;
- /* The following fields are only set in the response.
+ /*
+ * 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 */
@@ -680,14 +683,16 @@ struct cmd_ds_802_11_ps_mode {
__le16 action;
- /* Interval for keepalive in PS mode:
+ /*
+ * 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:
+ /*
+ * Number of DTIM intervals to wake up for:
* 0 = don't change
* 1 = firmware default
* 5 = max
@@ -697,7 +702,8 @@ struct cmd_ds_802_11_ps_mode {
__le16 reserved;
__le16 locallisteninterval;
- /* AdHoc awake period (FW v9+ only):
+ /*
+ * 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
@@ -771,7 +777,8 @@ struct adhoc_bssdesc {
__le16 capability;
u8 rates[MAX_RATES];
- /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the
+ /*
+ * DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the
* Adhoc join command and will cause a binary layout mismatch with
* the firmware
*/
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index 8712cb213f2f..e26935179861 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -21,6 +21,8 @@
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
@@ -312,7 +314,8 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r
#define CF8385_MANFID 0x02df
#define CF8385_CARDID 0x8103
-/* FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when
+/*
+ * FIXME: just use the 'driver_info' field of 'struct pcmcia_device_id' when
* that gets fixed. Currently there's no way to access it from the probe hook.
*/
static inline u32 get_model(u16 manf_id, u16 card_id)
@@ -361,7 +364,7 @@ static int if_cs_send_cmd(struct lbs_private *priv, u8 *buf, u16 nb)
if (status & IF_CS_BIT_COMMAND)
break;
if (++loops > 100) {
- lbs_pr_err("card not ready for commands\n");
+ netdev_err(priv->dev, "card not ready for commands\n");
goto done;
}
mdelay(1);
@@ -431,14 +434,16 @@ static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len)
/* is hardware ready? */
status = if_cs_read16(priv->card, IF_CS_CARD_STATUS);
if ((status & IF_CS_BIT_RESP) == 0) {
- lbs_pr_err("no cmd response in card\n");
+ netdev_err(priv->dev, "no cmd response in card\n");
*len = 0;
goto out;
}
*len = if_cs_read16(priv->card, IF_CS_RESP_LEN);
if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) {
- lbs_pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len);
+ netdev_err(priv->dev,
+ "card cmd buffer has invalid # of bytes (%d)\n",
+ *len);
goto out;
}
@@ -472,7 +477,9 @@ static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
len = if_cs_read16(priv->card, IF_CS_READ_LEN);
if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
- lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len);
+ netdev_err(priv->dev,
+ "card data buffer has invalid # of bytes (%d)\n",
+ len);
priv->dev->stats.rx_dropped++;
goto dat_err;
}
@@ -621,8 +628,10 @@ static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw)
if (remain < count)
count = remain;
- /* "write the number of bytes to be sent to the I/O Command
- * write length register" */
+ /*
+ * "write the number of bytes to be sent to the I/O Command
+ * write length register"
+ */
if_cs_write16(card, IF_CS_CMD_LEN, count);
/* "write this to I/O Command port register as 16 bit writes */
@@ -631,21 +640,27 @@ static int if_cs_prog_helper(struct if_cs_card *card, const struct firmware *fw)
&fw->data[sent],
count >> 1);
- /* "Assert the download over interrupt command in the Host
- * status register" */
+ /*
+ * "Assert the download over interrupt command in the Host
+ * status register"
+ */
if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_BIT_COMMAND);
- /* "Assert the download over interrupt command in the Card
- * interrupt case register" */
+ /*
+ * "Assert the download over interrupt command in the Card
+ * interrupt case register"
+ */
if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_BIT_COMMAND);
- /* "The host polls the Card Status register ... for 50 ms before
- declaring a failure */
+ /*
+ * "The host polls the Card Status register ... for 50 ms before
+ * declaring a failure"
+ */
ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS,
IF_CS_BIT_COMMAND);
if (ret < 0) {
- lbs_pr_err("can't download helper at 0x%x, ret %d\n",
- sent, ret);
+ pr_err("can't download helper at 0x%x, ret %d\n",
+ sent, ret);
goto done;
}
@@ -675,7 +690,7 @@ static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw)
ret = if_cs_poll_while_fw_download(card, IF_CS_SQ_READ_LOW,
IF_CS_SQ_HELPER_OK);
if (ret < 0) {
- lbs_pr_err("helper firmware doesn't answer\n");
+ pr_err("helper firmware doesn't answer\n");
goto done;
}
@@ -683,13 +698,13 @@ static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw)
len = if_cs_read16(card, IF_CS_SQ_READ_LOW);
if (len & 1) {
retry++;
- lbs_pr_info("odd, need to retry this firmware block\n");
+ pr_info("odd, need to retry this firmware block\n");
} else {
retry = 0;
}
if (retry > 20) {
- lbs_pr_err("could not download firmware\n");
+ pr_err("could not download firmware\n");
ret = -ENODEV;
goto done;
}
@@ -709,14 +724,14 @@ static int if_cs_prog_real(struct if_cs_card *card, const struct firmware *fw)
ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS,
IF_CS_BIT_COMMAND);
if (ret < 0) {
- lbs_pr_err("can't download firmware at 0x%x\n", sent);
+ pr_err("can't download firmware at 0x%x\n", sent);
goto done;
}
}
ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a);
if (ret < 0)
- lbs_pr_err("firmware download failed\n");
+ pr_err("firmware download failed\n");
done:
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
@@ -750,7 +765,8 @@ static int if_cs_host_to_card(struct lbs_private *priv,
ret = if_cs_send_cmd(priv, buf, nb);
break;
default:
- lbs_pr_err("%s: unsupported type %d\n", __func__, type);
+ netdev_err(priv->dev, "%s: unsupported type %d\n",
+ __func__, type);
}
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
@@ -779,7 +795,7 @@ static int if_cs_ioprobe(struct pcmcia_device *p_dev, void *priv_data)
p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
if (p_dev->resource[1]->end) {
- lbs_pr_err("wrong CIS (check number of IO windows)\n");
+ pr_err("wrong CIS (check number of IO windows)\n");
return -ENODEV;
}
@@ -800,7 +816,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL);
if (!card) {
- lbs_pr_err("error in kzalloc\n");
+ pr_err("error in kzalloc\n");
goto out;
}
card->p_dev = p_dev;
@@ -809,7 +825,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
if (pcmcia_loop_config(p_dev, if_cs_ioprobe, NULL)) {
- lbs_pr_err("error in pcmcia_loop_config\n");
+ pr_err("error in pcmcia_loop_config\n");
goto out1;
}
@@ -825,14 +841,14 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
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");
+ pr_err("error in ioport_map\n");
ret = -EIO;
goto out1;
}
ret = pcmcia_enable_device(p_dev);
if (ret) {
- lbs_pr_err("error in pcmcia_enable_device\n");
+ pr_err("error in pcmcia_enable_device\n");
goto out2;
}
@@ -841,14 +857,14 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
/*
* Most of the libertas cards can do unaligned register access, but some
- * weird ones can not. That's especially true for the CF8305 card.
+ * weird ones cannot. That's especially true for the CF8305 card.
*/
card->align_regs = 0;
card->model = get_model(p_dev->manf_id, p_dev->card_id);
if (card->model == MODEL_UNKNOWN) {
- lbs_pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n",
- p_dev->manf_id, p_dev->card_id);
+ pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n",
+ p_dev->manf_id, p_dev->card_id);
goto out2;
}
@@ -857,20 +873,20 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
if (card->model == MODEL_8305) {
card->align_regs = 1;
if (prod_id < IF_CS_CF8305_B1_REV) {
- lbs_pr_err("8305 rev B0 and older are not supported\n");
+ pr_err("8305 rev B0 and older are not supported\n");
ret = -ENODEV;
goto out2;
}
}
if ((card->model == MODEL_8381) && prod_id < IF_CS_CF8381_B3_REV) {
- lbs_pr_err("8381 rev B2 and older are not supported\n");
+ pr_err("8381 rev B2 and older are not supported\n");
ret = -ENODEV;
goto out2;
}
if ((card->model == MODEL_8385) && prod_id < IF_CS_CF8385_B1_REV) {
- lbs_pr_err("8385 rev B0 and older are not supported\n");
+ pr_err("8385 rev B0 and older are not supported\n");
ret = -ENODEV;
goto out2;
}
@@ -878,7 +894,7 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
ret = lbs_get_firmware(&p_dev->dev, NULL, NULL, card->model,
&fw_table[0], &helper, &mainfw);
if (ret) {
- lbs_pr_err("failed to find firmware (%d)\n", ret);
+ pr_err("failed to find firmware (%d)\n", ret);
goto out2;
}
@@ -909,18 +925,20 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
ret = request_irq(p_dev->irq, if_cs_interrupt,
IRQF_SHARED, DRV_NAME, card);
if (ret) {
- lbs_pr_err("error in request_irq\n");
+ pr_err("error in request_irq\n");
goto out3;
}
- /* Clear any interrupt cause that happened while sending
- * firmware/initializing card */
+ /*
+ * Clear any interrupt cause that happened while sending
+ * firmware/initializing card
+ */
if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_BIT_MASK);
if_cs_enable_ints(card);
/* And finally bring the card up */
if (lbs_start_card(priv) != 0) {
- lbs_pr_err("could not activate card\n");
+ pr_err("could not activate card\n");
goto out3;
}
@@ -965,7 +983,7 @@ static void if_cs_detach(struct pcmcia_device *p_dev)
/* Module initialization */
/********************************************************************/
-static struct pcmcia_device_id if_cs_ids[] = {
+static const struct pcmcia_device_id if_cs_ids[] = {
PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID),
PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID),
PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID),
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index b4de0ca10feb..a7b5cb0c2753 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -26,6 +26,8 @@
* if_sdio_card_to_host() to pad the data.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
@@ -409,7 +411,7 @@ static int if_sdio_card_to_host(struct if_sdio_card *card)
out:
if (ret)
- lbs_pr_err("problem fetching packet from firmware\n");
+ pr_err("problem fetching packet from firmware\n");
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
@@ -446,7 +448,7 @@ static void if_sdio_host_to_card_worker(struct work_struct *work)
}
if (ret)
- lbs_pr_err("error %d sending packet to firmware\n", ret);
+ pr_err("error %d sending packet to firmware\n", ret);
sdio_release_host(card->func);
@@ -555,7 +557,7 @@ release:
out:
if (ret)
- lbs_pr_err("failed to load helper firmware\n");
+ pr_err("failed to load helper firmware\n");
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
return ret;
@@ -669,7 +671,7 @@ release:
out:
if (ret)
- lbs_pr_err("failed to load firmware\n");
+ pr_err("failed to load firmware\n");
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
return ret;
@@ -723,7 +725,7 @@ static int if_sdio_prog_firmware(struct if_sdio_card *card)
ret = lbs_get_firmware(&card->func->dev, lbs_helper_name, lbs_fw_name,
card->model, &fw_table[0], &helper, &mainfw);
if (ret) {
- lbs_pr_err("failed to find firmware (%d)\n", ret);
+ pr_err("failed to find firmware (%d)\n", ret);
goto out;
}
@@ -849,7 +851,7 @@ static int if_sdio_enter_deep_sleep(struct lbs_private *priv)
ret = __lbs_cmd(priv, CMD_802_11_DEEP_SLEEP, &cmd, sizeof(cmd),
lbs_cmd_copyback, (unsigned long) &cmd);
if (ret)
- lbs_pr_err("DEEP_SLEEP cmd failed\n");
+ netdev_err(priv->dev, "DEEP_SLEEP cmd failed\n");
mdelay(200);
return ret;
@@ -865,7 +867,7 @@ static int if_sdio_exit_deep_sleep(struct lbs_private *priv)
sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret);
if (ret)
- lbs_pr_err("sdio_writeb failed!\n");
+ netdev_err(priv->dev, "sdio_writeb failed!\n");
sdio_release_host(card->func);
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
@@ -882,7 +884,7 @@ static int if_sdio_reset_deep_sleep_wakeup(struct lbs_private *priv)
sdio_writeb(card->func, 0, CONFIGURATION_REG, &ret);
if (ret)
- lbs_pr_err("sdio_writeb failed!\n");
+ netdev_err(priv->dev, "sdio_writeb failed!\n");
sdio_release_host(card->func);
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
@@ -961,7 +963,7 @@ static int if_sdio_probe(struct sdio_func *func,
}
if (i == func->card->num_info) {
- lbs_pr_err("unable to identify card model\n");
+ pr_err("unable to identify card model\n");
return -ENODEV;
}
@@ -995,7 +997,7 @@ static int if_sdio_probe(struct sdio_func *func,
break;
}
if (i == ARRAY_SIZE(fw_table)) {
- lbs_pr_err("unknown card model 0x%x\n", card->model);
+ pr_err("unknown card model 0x%x\n", card->model);
ret = -ENODEV;
goto free;
}
@@ -1101,7 +1103,7 @@ static int if_sdio_probe(struct sdio_func *func,
lbs_deb_sdio("send function INIT command\n");
if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd),
lbs_cmd_copyback, (unsigned long) &cmd))
- lbs_pr_alert("CMD_FUNC_INIT cmd failed\n");
+ netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n");
}
ret = lbs_start_card(priv);
@@ -1163,7 +1165,7 @@ static void if_sdio_remove(struct sdio_func *func)
if (__lbs_cmd(card->priv, CMD_FUNC_SHUTDOWN,
&cmd, sizeof(cmd), lbs_cmd_copyback,
(unsigned long) &cmd))
- lbs_pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n");
+ pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n");
}
@@ -1202,20 +1204,19 @@ static int if_sdio_suspend(struct device *dev)
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);
+ dev_info(dev, "%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.");
+ dev_info(dev, "Suspend without wake params -- powering down card\n");
return -ENOSYS;
}
if (!(flags & MMC_PM_KEEP_POWER)) {
- lbs_pr_err("%s: cannot remain alive while host is suspended\n",
+ dev_err(dev, "%s: cannot remain alive while host is suspended\n",
sdio_func_id(func));
return -ENOSYS;
}
@@ -1237,7 +1238,7 @@ static int if_sdio_resume(struct device *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));
+ dev_info(dev, "%s: resume: we're back\n", sdio_func_id(func));
ret = lbs_resume(card->priv);
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index f6c2cd665f49..463352c890d7 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -17,6 +17,8 @@
* (at your option) any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/moduleparam.h>
#include <linux/firmware.h>
#include <linux/jiffies.h>
@@ -57,6 +59,7 @@ struct if_spi_card {
/* Handles all SPI communication (except for FW load) */
struct workqueue_struct *workqueue;
struct work_struct packet_work;
+ struct work_struct resume_work;
u8 cmd_buffer[IF_SPI_CMD_BUF_SIZE];
@@ -68,6 +71,9 @@ struct if_spi_card {
/* Protects cmd_packet_list and data_packet_list */
spinlock_t buffer_lock;
+
+ /* True is card suspended */
+ u8 suspended;
};
static void free_if_spi_card(struct if_spi_card *card)
@@ -139,8 +145,10 @@ static void spu_transaction_finish(struct if_spi_card *card)
card->prev_xfer_time = jiffies;
}
-/* Write out a byte buffer to an SPI register,
- * using a series of 16-bit transfers. */
+/*
+ * Write out a byte buffer to an SPI register,
+ * using a series of 16-bit transfers.
+ */
static int spu_write(struct if_spi_card *card, u16 reg, const u8 *buf, int len)
{
int err = 0;
@@ -204,8 +212,10 @@ static int spu_read(struct if_spi_card *card, u16 reg, u8 *buf, int len)
struct spi_transfer dummy_trans;
struct spi_transfer data_trans;
- /* You must take an even number of bytes from the SPU, even if you
- * don't care about the last one. */
+ /*
+ * You must take an even number of bytes from the SPU, even if you
+ * don't care about the last one.
+ */
BUG_ON(len & 0x1);
spu_transaction_init(card);
@@ -254,8 +264,10 @@ static inline int spu_read_u16(struct if_spi_card *card, u16 reg, u16 *val)
return ret;
}
-/* Read 32 bits from an SPI register.
- * The low 16 bits are read first. */
+/*
+ * Read 32 bits from an SPI register.
+ * The low 16 bits are read first.
+ */
static int spu_read_u32(struct if_spi_card *card, u16 reg, u32 *val)
{
__le32 buf;
@@ -267,13 +279,15 @@ static int spu_read_u32(struct if_spi_card *card, u16 reg, u32 *val)
return err;
}
-/* Keep reading 16 bits from an SPI register until you get the correct result.
+/*
+ * Keep reading 16 bits from an SPI register until you get the correct result.
*
* If mask = 0, the correct result is any non-zero number.
* If mask != 0, the correct result is any number where
* number & target_mask == target
*
- * Returns -ETIMEDOUT if a second passes without the correct result. */
+ * Returns -ETIMEDOUT if a second passes without the correct result.
+ */
static int spu_wait_for_u16(struct if_spi_card *card, u16 reg,
u16 target_mask, u16 target)
{
@@ -293,16 +307,17 @@ static int spu_wait_for_u16(struct if_spi_card *card, u16 reg,
}
udelay(100);
if (time_after(jiffies, timeout)) {
- lbs_pr_err("%s: timeout with val=%02x, "
- "target_mask=%02x, target=%02x\n",
+ pr_err("%s: timeout with val=%02x, target_mask=%02x, target=%02x\n",
__func__, val, target_mask, target);
return -ETIMEDOUT;
}
}
}
-/* Read 16 bits from an SPI register until you receive a specific value.
- * Returns -ETIMEDOUT if a 4 tries pass without success. */
+/*
+ * Read 16 bits from an SPI register until you receive a specific value.
+ * Returns -ETIMEDOUT if a 4 tries pass without success.
+ */
static int spu_wait_for_u32(struct if_spi_card *card, u32 reg, u32 target)
{
int err, try;
@@ -324,8 +339,10 @@ static int spu_set_interrupt_mode(struct if_spi_card *card,
{
int err = 0;
- /* We can suppress a host interrupt by clearing the appropriate
- * bit in the "host interrupt status mask" register */
+ /*
+ * We can suppress a host interrupt by clearing the appropriate
+ * bit in the "host interrupt status mask" register
+ */
if (suppress_host_int) {
err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_MASK_REG, 0);
if (err)
@@ -341,10 +358,12 @@ static int spu_set_interrupt_mode(struct if_spi_card *card,
return err;
}
- /* If auto-interrupts are on, the completion of certain transactions
+ /*
+ * If auto-interrupts are on, the completion of certain transactions
* will trigger an interrupt automatically. If auto-interrupts
* are off, we need to set the "Card Interrupt Cause" register to
- * trigger a card interrupt. */
+ * trigger a card interrupt.
+ */
if (auto_int) {
err = spu_write_u16(card, IF_SPI_HOST_INT_CTRL_REG,
IF_SPI_HICT_TX_DOWNLOAD_OVER_AUTO |
@@ -387,7 +406,7 @@ static int spu_set_bus_mode(struct if_spi_card *card, u16 mode)
if (err)
return err;
if ((rval & 0xF) != mode) {
- lbs_pr_err("Can't read bus mode register.\n");
+ pr_err("Can't read bus mode register\n");
return -EIO;
}
return 0;
@@ -398,8 +417,10 @@ static int spu_init(struct if_spi_card *card, int use_dummy_writes)
int err = 0;
u32 delay;
- /* We have to start up in timed delay mode so that we can safely
- * read the Delay Read Register. */
+ /*
+ * We have to start up in timed delay mode so that we can safely
+ * read the Delay Read Register.
+ */
card->use_dummy_writes = 0;
err = spu_set_bus_mode(card,
IF_SPI_BUS_MODE_SPI_CLOCK_PHASE_RISING |
@@ -455,8 +476,10 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card,
/* Load helper firmware image */
while (bytes_remaining > 0) {
- /* Scratch pad 1 should contain the number of bytes we
- * want to download to the firmware */
+ /*
+ * Scratch pad 1 should contain the number of bytes we
+ * want to download to the firmware
+ */
err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG,
HELPER_FW_LOAD_CHUNK_SZ);
if (err)
@@ -468,8 +491,10 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card,
if (err)
goto out;
- /* Feed the data into the command read/write port reg
- * in chunks of 64 bytes */
+ /*
+ * Feed the data into the command read/write port reg
+ * in chunks of 64 bytes
+ */
memset(temp, 0, sizeof(temp));
memcpy(temp, fw,
min(bytes_remaining, HELPER_FW_LOAD_CHUNK_SZ));
@@ -491,9 +516,11 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card,
fw += HELPER_FW_LOAD_CHUNK_SZ;
}
- /* Once the helper / single stage firmware download is complete,
+ /*
+ * Once the helper / single stage firmware download is complete,
* write 0 to scratch pad 1 and interrupt the
- * bootloader. This completes the helper download. */
+ * bootloader. This completes the helper download.
+ */
err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG, FIRMWARE_DNLD_OK);
if (err)
goto out;
@@ -508,26 +535,30 @@ static int if_spi_prog_helper_firmware(struct if_spi_card *card,
out:
if (err)
- lbs_pr_err("failed to load helper firmware (err=%d)\n", err);
+ pr_err("failed to load helper firmware (err=%d)\n", err);
lbs_deb_leave_args(LBS_DEB_SPI, "err %d", err);
return err;
}
-/* Returns the length of the next packet the firmware expects us to send
- * Sets crc_err if the previous transfer had a CRC error. */
+/*
+ * Returns the length of the next packet the firmware expects us to send.
+ * Sets crc_err if the previous transfer had a CRC error.
+ */
static int if_spi_prog_main_firmware_check_len(struct if_spi_card *card,
int *crc_err)
{
u16 len;
int err = 0;
- /* wait until the host interrupt status register indicates
- * that we are ready to download */
+ /*
+ * wait until the host interrupt status register indicates
+ * that we are ready to download
+ */
err = spu_wait_for_u16(card, IF_SPI_HOST_INT_STATUS_REG,
IF_SPI_HIST_CMD_DOWNLOAD_RDY,
IF_SPI_HIST_CMD_DOWNLOAD_RDY);
if (err) {
- lbs_pr_err("timed out waiting for host_int_status\n");
+ pr_err("timed out waiting for host_int_status\n");
return err;
}
@@ -537,9 +568,8 @@ static int if_spi_prog_main_firmware_check_len(struct if_spi_card *card,
return err;
if (len > IF_SPI_CMD_BUF_SIZE) {
- lbs_pr_err("firmware load device requested a larger "
- "tranfer than we are prepared to "
- "handle. (len = %d)\n", len);
+ pr_err("firmware load device requested a larger transfer than we are prepared to handle (len = %d)\n",
+ len);
return -EIO;
}
if (len & 0x1) {
@@ -555,6 +585,7 @@ static int if_spi_prog_main_firmware_check_len(struct if_spi_card *card,
static int if_spi_prog_main_firmware(struct if_spi_card *card,
const struct firmware *firmware)
{
+ struct lbs_private *priv = card->priv;
int len, prev_len;
int bytes, crc_err = 0, err = 0;
const u8 *fw;
@@ -568,8 +599,9 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card,
err = spu_wait_for_u16(card, IF_SPI_SCRATCH_1_REG, 0, 0);
if (err) {
- lbs_pr_err("%s: timed out waiting for initial "
- "scratch reg = 0\n", __func__);
+ netdev_err(priv->dev,
+ "%s: timed out waiting for initial scratch reg = 0\n",
+ __func__);
goto out;
}
@@ -583,17 +615,18 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card,
goto out;
}
if (bytes < 0) {
- /* If there are no more bytes left, we would normally
- * expect to have terminated with len = 0 */
- lbs_pr_err("Firmware load wants more bytes "
- "than we have to offer.\n");
+ /*
+ * If there are no more bytes left, we would normally
+ * expect to have terminated with len = 0
+ */
+ netdev_err(priv->dev,
+ "Firmware load wants more bytes than we have to offer.\n");
break;
}
if (crc_err) {
/* Previous transfer failed. */
if (++num_crc_errs > MAX_MAIN_FW_LOAD_CRC_ERR) {
- lbs_pr_err("Too many CRC errors encountered "
- "in firmware load.\n");
+ pr_err("Too many CRC errors encountered in firmware load.\n");
err = -EIO;
goto out;
}
@@ -622,21 +655,20 @@ static int if_spi_prog_main_firmware(struct if_spi_card *card,
prev_len = len;
}
if (bytes > prev_len) {
- lbs_pr_err("firmware load wants fewer bytes than "
- "we have to offer.\n");
+ pr_err("firmware load wants fewer bytes than we have to offer\n");
}
/* Confirm firmware download */
err = spu_wait_for_u32(card, IF_SPI_SCRATCH_4_REG,
SUCCESSFUL_FW_DOWNLOAD_MAGIC);
if (err) {
- lbs_pr_err("failed to confirm the firmware download\n");
+ pr_err("failed to confirm the firmware download\n");
goto out;
}
out:
if (err)
- lbs_pr_err("failed to load firmware (err=%d)\n", err);
+ pr_err("failed to load firmware (err=%d)\n", err);
lbs_deb_leave_args(LBS_DEB_SPI, "err %d", err);
return err;
}
@@ -656,14 +688,18 @@ static int if_spi_c2h_cmd(struct if_spi_card *card)
u16 len;
u8 i;
- /* We need a buffer big enough to handle whatever people send to
- * hw_host_to_card */
+ /*
+ * We need a buffer big enough to handle whatever people send to
+ * hw_host_to_card
+ */
BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE < LBS_CMD_BUFFER_SIZE);
BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE < LBS_UPLD_SIZE);
- /* It's just annoying if the buffer size isn't a multiple of 4, because
- * then we might have len < IF_SPI_CMD_BUF_SIZE but
- * ALIGN(len, 4) > IF_SPI_CMD_BUF_SIZE */
+ /*
+ * It's just annoying if the buffer size isn't a multiple of 4, because
+ * then we might have len < IF_SPI_CMD_BUF_SIZE but
+ * ALIGN(len, 4) > IF_SPI_CMD_BUF_SIZE
+ */
BUILD_BUG_ON(IF_SPI_CMD_BUF_SIZE % 4 != 0);
lbs_deb_enter(LBS_DEB_SPI);
@@ -673,13 +709,13 @@ static int if_spi_c2h_cmd(struct if_spi_card *card)
if (err)
goto out;
if (!len) {
- lbs_pr_err("%s: error: card has no data for host\n",
+ netdev_err(priv->dev, "%s: error: card has no data for host\n",
__func__);
err = -EINVAL;
goto out;
} else if (len > IF_SPI_CMD_BUF_SIZE) {
- lbs_pr_err("%s: error: response packet too large: "
- "%d bytes, but maximum is %d\n",
+ netdev_err(priv->dev,
+ "%s: error: response packet too large: %d bytes, but maximum is %d\n",
__func__, len, IF_SPI_CMD_BUF_SIZE);
err = -EINVAL;
goto out;
@@ -701,7 +737,7 @@ static int if_spi_c2h_cmd(struct if_spi_card *card)
out:
if (err)
- lbs_pr_err("%s: err=%d\n", __func__, err);
+ netdev_err(priv->dev, "%s: err=%d\n", __func__, err);
lbs_deb_leave(LBS_DEB_SPI);
return err;
}
@@ -709,6 +745,7 @@ out:
/* Move data from the card to the host */
static int if_spi_c2h_data(struct if_spi_card *card)
{
+ struct lbs_private *priv = card->priv;
struct sk_buff *skb;
char *data;
u16 len;
@@ -721,13 +758,13 @@ static int if_spi_c2h_data(struct if_spi_card *card)
if (err)
goto out;
if (!len) {
- lbs_pr_err("%s: error: card has no data for host\n",
+ netdev_err(priv->dev, "%s: error: card has no data for host\n",
__func__);
err = -EINVAL;
goto out;
} else if (len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
- lbs_pr_err("%s: error: card has %d bytes of data, but "
- "our maximum skb size is %zu\n",
+ netdev_err(priv->dev,
+ "%s: error: card has %d bytes of data, but our maximum skb size is %zu\n",
__func__, len, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE);
err = -EINVAL;
goto out;
@@ -759,7 +796,7 @@ free_skb:
dev_kfree_skb(skb);
out:
if (err)
- lbs_pr_err("%s: err=%d\n", __func__, err);
+ netdev_err(priv->dev, "%s: err=%d\n", __func__, err);
lbs_deb_leave(LBS_DEB_SPI);
return err;
}
@@ -768,6 +805,7 @@ out:
static void if_spi_h2c(struct if_spi_card *card,
struct if_spi_packet *packet, int type)
{
+ struct lbs_private *priv = card->priv;
int err = 0;
u16 int_type, port_reg;
@@ -781,7 +819,8 @@ static void if_spi_h2c(struct if_spi_card *card,
port_reg = IF_SPI_CMD_RDWRPORT_REG;
break;
default:
- lbs_pr_err("can't transfer buffer of type %d\n", type);
+ netdev_err(priv->dev, "can't transfer buffer of type %d\n",
+ type);
err = -EINVAL;
goto out;
}
@@ -795,7 +834,7 @@ out:
kfree(packet);
if (err)
- lbs_pr_err("%s: error %d\n", __func__, err);
+ netdev_err(priv->dev, "%s: error %d\n", __func__, err);
}
/* Inform the host about a card event */
@@ -819,7 +858,7 @@ static void if_spi_e2h(struct if_spi_card *card)
lbs_queue_event(priv, cause & 0xff);
out:
if (err)
- lbs_pr_err("%s: error %d\n", __func__, err);
+ netdev_err(priv->dev, "%s: error %d\n", __func__, err);
}
static void if_spi_host_to_card_worker(struct work_struct *work)
@@ -829,17 +868,21 @@ static void if_spi_host_to_card_worker(struct work_struct *work)
u16 hiStatus;
unsigned long flags;
struct if_spi_packet *packet;
+ struct lbs_private *priv;
card = container_of(work, struct if_spi_card, packet_work);
+ priv = card->priv;
lbs_deb_enter(LBS_DEB_SPI);
- /* Read the host interrupt status register to see what we
- * can do. */
+ /*
+ * Read the host interrupt status register to see what we
+ * can do.
+ */
err = spu_read_u16(card, IF_SPI_HOST_INT_STATUS_REG,
&hiStatus);
if (err) {
- lbs_pr_err("I/O error\n");
+ netdev_err(priv->dev, "I/O error\n");
goto err;
}
@@ -854,12 +897,15 @@ static void if_spi_host_to_card_worker(struct work_struct *work)
goto err;
}
- /* workaround: in PS mode, the card does not set the Command
- * Download Ready bit, but it sets TX Download Ready. */
+ /*
+ * workaround: in PS mode, the card does not set the Command
+ * Download Ready bit, but it sets TX Download Ready.
+ */
if (hiStatus & IF_SPI_HIST_CMD_DOWNLOAD_RDY ||
(card->priv->psstate != PS_STATE_FULL_POWER &&
(hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY))) {
- /* This means two things. First of all,
+ /*
+ * This means two things. First of all,
* if there was a previous command sent, the card has
* successfully received it.
* Secondly, it is now ready to download another
@@ -867,8 +913,7 @@ static void if_spi_host_to_card_worker(struct work_struct *work)
*/
lbs_host_to_card_done(card->priv);
- /* Do we have any command packets from the host to
- * send? */
+ /* Do we have any command packets from the host to send? */
packet = NULL;
spin_lock_irqsave(&card->buffer_lock, flags);
if (!list_empty(&card->cmd_packet_list)) {
@@ -882,8 +927,7 @@ static void if_spi_host_to_card_worker(struct work_struct *work)
if_spi_h2c(card, packet, MVMS_CMD);
}
if (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY) {
- /* Do we have any data packets from the host to
- * send? */
+ /* Do we have any data packets from the host to send? */
packet = NULL;
spin_lock_irqsave(&card->buffer_lock, flags);
if (!list_empty(&card->data_packet_list)) {
@@ -901,7 +945,7 @@ static void if_spi_host_to_card_worker(struct work_struct *work)
err:
if (err)
- lbs_pr_err("%s: got error %d\n", __func__, err);
+ netdev_err(priv->dev, "%s: got error %d\n", __func__, err);
lbs_deb_leave(LBS_DEB_SPI);
}
@@ -910,7 +954,8 @@ err:
* Host to Card
*
* Called from Libertas to transfer some data to the WLAN device
- * We can't sleep here. */
+ * We can't sleep here.
+ */
static int if_spi_host_to_card(struct lbs_private *priv,
u8 type, u8 *buf, u16 nb)
{
@@ -923,7 +968,8 @@ static int if_spi_host_to_card(struct lbs_private *priv,
lbs_deb_enter_args(LBS_DEB_SPI, "type %d, bytes %d", type, nb);
if (nb == 0) {
- lbs_pr_err("%s: invalid size requested: %d\n", __func__, nb);
+ netdev_err(priv->dev, "%s: invalid size requested: %d\n",
+ __func__, nb);
err = -EINVAL;
goto out;
}
@@ -951,7 +997,8 @@ static int if_spi_host_to_card(struct lbs_private *priv,
spin_unlock_irqrestore(&card->buffer_lock, flags);
break;
default:
- lbs_pr_err("can't transfer buffer of type %d", type);
+ netdev_err(priv->dev, "can't transfer buffer of type %d\n",
+ type);
err = -EINVAL;
break;
}
@@ -984,6 +1031,7 @@ static irqreturn_t if_spi_host_interrupt(int irq, void *dev_id)
static int if_spi_init_card(struct if_spi_card *card)
{
+ struct lbs_private *priv = card->priv;
struct spi_device *spi = card->spi;
int err, i;
u32 scratch;
@@ -1012,8 +1060,8 @@ static int if_spi_init_card(struct if_spi_card *card)
break;
}
if (i == ARRAY_SIZE(fw_table)) {
- lbs_pr_err("Unsupported chip_id: 0x%02x\n",
- card->card_id);
+ netdev_err(priv->dev, "Unsupported chip_id: 0x%02x\n",
+ card->card_id);
err = -ENODEV;
goto out;
}
@@ -1022,7 +1070,8 @@ static int if_spi_init_card(struct if_spi_card *card)
card->card_id, &fw_table[0], &helper,
&mainfw);
if (err) {
- lbs_pr_err("failed to find firmware (%d)\n", err);
+ netdev_err(priv->dev, "failed to find firmware (%d)\n",
+ err);
goto out;
}
@@ -1057,6 +1106,28 @@ out:
return err;
}
+static void if_spi_resume_worker(struct work_struct *work)
+{
+ struct if_spi_card *card;
+
+ card = container_of(work, struct if_spi_card, resume_work);
+
+ if (card->suspended) {
+ if (card->pdata->setup)
+ card->pdata->setup(card->spi);
+
+ /* Init card ... */
+ if_spi_init_card(card);
+
+ enable_irq(card->spi->irq);
+
+ /* And resume it ... */
+ lbs_resume(card->priv);
+
+ card->suspended = 0;
+ }
+}
+
static int __devinit if_spi_probe(struct spi_device *spi)
{
struct if_spi_card *card;
@@ -1099,14 +1170,17 @@ static int __devinit if_spi_probe(struct spi_device *spi)
if (err)
goto free_card;
- /* Register our card with libertas.
- * This will call alloc_etherdev */
+ /*
+ * Register our card with libertas.
+ * This will call alloc_etherdev.
+ */
priv = lbs_add_card(card, &spi->dev);
if (!priv) {
err = -ENOMEM;
goto free_card;
}
card->priv = priv;
+ priv->setup_fw_on_resume = 1;
priv->card = card;
priv->hw_host_to_card = if_spi_host_to_card;
priv->enter_deep_sleep = NULL;
@@ -1117,17 +1191,20 @@ static int __devinit if_spi_probe(struct spi_device *spi)
/* Initialize interrupt handling stuff. */
card->workqueue = create_workqueue("libertas_spi");
INIT_WORK(&card->packet_work, if_spi_host_to_card_worker);
+ INIT_WORK(&card->resume_work, if_spi_resume_worker);
err = request_irq(spi->irq, if_spi_host_interrupt,
IRQF_TRIGGER_FALLING, "libertas_spi", card);
if (err) {
- lbs_pr_err("can't get host irq line-- request_irq failed\n");
+ pr_err("can't get host irq line-- request_irq failed\n");
goto terminate_workqueue;
}
- /* Start the card.
+ /*
+ * Start the card.
* This will call register_netdev, and we'll start
- * getting interrupts... */
+ * getting interrupts...
+ */
err = lbs_start_card(priv);
if (err)
goto release_irq;
@@ -1161,6 +1238,8 @@ static int __devexit libertas_spi_remove(struct spi_device *spi)
lbs_deb_spi("libertas_spi_remove\n");
lbs_deb_enter(LBS_DEB_SPI);
+ cancel_work_sync(&card->resume_work);
+
lbs_stop_card(priv);
lbs_remove_card(priv); /* will call free_netdev */
@@ -1174,6 +1253,40 @@ static int __devexit libertas_spi_remove(struct spi_device *spi)
return 0;
}
+static int if_spi_suspend(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct if_spi_card *card = spi_get_drvdata(spi);
+
+ if (!card->suspended) {
+ lbs_suspend(card->priv);
+ flush_workqueue(card->workqueue);
+ disable_irq(spi->irq);
+
+ if (card->pdata->teardown)
+ card->pdata->teardown(spi);
+ card->suspended = 1;
+ }
+
+ return 0;
+}
+
+static int if_spi_resume(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct if_spi_card *card = spi_get_drvdata(spi);
+
+ /* Schedule delayed work */
+ schedule_work(&card->resume_work);
+
+ return 0;
+}
+
+static const struct dev_pm_ops if_spi_pm_ops = {
+ .suspend = if_spi_suspend,
+ .resume = if_spi_resume,
+};
+
static struct spi_driver libertas_spi_driver = {
.probe = if_spi_probe,
.remove = __devexit_p(libertas_spi_remove),
@@ -1181,6 +1294,7 @@ static struct spi_driver libertas_spi_driver = {
.name = "libertas_spi",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
+ .pm = &if_spi_pm_ops,
},
};
diff --git a/drivers/net/wireless/libertas/if_spi.h b/drivers/net/wireless/libertas/if_spi.h
index d2ac1dcd7e2e..e450e31fd11d 100644
--- a/drivers/net/wireless/libertas/if_spi.h
+++ b/drivers/net/wireless/libertas/if_spi.h
@@ -86,34 +86,34 @@
#define IF_SPI_DEVICEID_CTRL_REG_TO_CARD_REV(dc) (dc & 0x000000ff)
/***************** IF_SPI_HOST_INT_CTRL_REG *****************/
-/** Host Interrupt Control bit : Wake up */
+/* Host Interrupt Control bit : Wake up */
#define IF_SPI_HICT_WAKE_UP (1<<0)
-/** Host Interrupt Control bit : WLAN ready */
+/* Host Interrupt Control bit : WLAN ready */
#define IF_SPI_HICT_WLAN_READY (1<<1)
/*#define IF_SPI_HICT_FIFO_FIRST_HALF_EMPTY (1<<2) */
/*#define IF_SPI_HICT_FIFO_SECOND_HALF_EMPTY (1<<3) */
/*#define IF_SPI_HICT_IRQSRC_WLAN (1<<4) */
-/** Host Interrupt Control bit : Tx auto download */
+/* Host Interrupt Control bit : Tx auto download */
#define IF_SPI_HICT_TX_DOWNLOAD_OVER_AUTO (1<<5)
-/** Host Interrupt Control bit : Rx auto upload */
+/* Host Interrupt Control bit : Rx auto upload */
#define IF_SPI_HICT_RX_UPLOAD_OVER_AUTO (1<<6)
-/** Host Interrupt Control bit : Command auto download */
+/* Host Interrupt Control bit : Command auto download */
#define IF_SPI_HICT_CMD_DOWNLOAD_OVER_AUTO (1<<7)
-/** Host Interrupt Control bit : Command auto upload */
+/* Host Interrupt Control bit : Command auto upload */
#define IF_SPI_HICT_CMD_UPLOAD_OVER_AUTO (1<<8)
/***************** IF_SPI_CARD_INT_CAUSE_REG *****************/
-/** Card Interrupt Case bit : Tx download over */
+/* Card Interrupt Case bit : Tx download over */
#define IF_SPI_CIC_TX_DOWNLOAD_OVER (1<<0)
-/** Card Interrupt Case bit : Rx upload over */
+/* Card Interrupt Case bit : Rx upload over */
#define IF_SPI_CIC_RX_UPLOAD_OVER (1<<1)
-/** Card Interrupt Case bit : Command download over */
+/* Card Interrupt Case bit : Command download over */
#define IF_SPI_CIC_CMD_DOWNLOAD_OVER (1<<2)
-/** Card Interrupt Case bit : Host event */
+/* Card Interrupt Case bit : Host event */
#define IF_SPI_CIC_HOST_EVENT (1<<3)
-/** Card Interrupt Case bit : Command upload over */
+/* Card Interrupt Case bit : Command upload over */
#define IF_SPI_CIC_CMD_UPLOAD_OVER (1<<4)
-/** Card Interrupt Case bit : Power down */
+/* Card Interrupt Case bit : Power down */
#define IF_SPI_CIC_POWER_DOWN (1<<5)
/***************** IF_SPI_CARD_INT_STATUS_REG *****************/
@@ -138,51 +138,51 @@
#define IF_SPI_HICU_CMD_RD_FIFO_UNDERFLOW (1<<10)
/***************** IF_SPI_HOST_INT_STATUS_REG *****************/
-/** Host Interrupt Status bit : Tx download ready */
+/* Host Interrupt Status bit : Tx download ready */
#define IF_SPI_HIST_TX_DOWNLOAD_RDY (1<<0)
-/** Host Interrupt Status bit : Rx upload ready */
+/* Host Interrupt Status bit : Rx upload ready */
#define IF_SPI_HIST_RX_UPLOAD_RDY (1<<1)
-/** Host Interrupt Status bit : Command download ready */
+/* Host Interrupt Status bit : Command download ready */
#define IF_SPI_HIST_CMD_DOWNLOAD_RDY (1<<2)
-/** Host Interrupt Status bit : Card event */
+/* Host Interrupt Status bit : Card event */
#define IF_SPI_HIST_CARD_EVENT (1<<3)
-/** Host Interrupt Status bit : Command upload ready */
+/* Host Interrupt Status bit : Command upload ready */
#define IF_SPI_HIST_CMD_UPLOAD_RDY (1<<4)
-/** Host Interrupt Status bit : I/O write FIFO overflow */
+/* Host Interrupt Status bit : I/O write FIFO overflow */
#define IF_SPI_HIST_IO_WR_FIFO_OVERFLOW (1<<5)
-/** Host Interrupt Status bit : I/O read FIFO underflow */
+/* Host Interrupt Status bit : I/O read FIFO underflow */
#define IF_SPI_HIST_IO_RD_FIFO_UNDRFLOW (1<<6)
-/** Host Interrupt Status bit : Data write FIFO overflow */
+/* Host Interrupt Status bit : Data write FIFO overflow */
#define IF_SPI_HIST_DATA_WR_FIFO_OVERFLOW (1<<7)
-/** Host Interrupt Status bit : Data read FIFO underflow */
+/* Host Interrupt Status bit : Data read FIFO underflow */
#define IF_SPI_HIST_DATA_RD_FIFO_UNDERFLOW (1<<8)
-/** Host Interrupt Status bit : Command write FIFO overflow */
+/* Host Interrupt Status bit : Command write FIFO overflow */
#define IF_SPI_HIST_CMD_WR_FIFO_OVERFLOW (1<<9)
-/** Host Interrupt Status bit : Command read FIFO underflow */
+/* Host Interrupt Status bit : Command read FIFO underflow */
#define IF_SPI_HIST_CMD_RD_FIFO_UNDERFLOW (1<<10)
/***************** IF_SPI_HOST_INT_STATUS_MASK_REG *****************/
-/** Host Interrupt Status Mask bit : Tx download ready */
+/* Host Interrupt Status Mask bit : Tx download ready */
#define IF_SPI_HISM_TX_DOWNLOAD_RDY (1<<0)
-/** Host Interrupt Status Mask bit : Rx upload ready */
+/* Host Interrupt Status Mask bit : Rx upload ready */
#define IF_SPI_HISM_RX_UPLOAD_RDY (1<<1)
-/** Host Interrupt Status Mask bit : Command download ready */
+/* Host Interrupt Status Mask bit : Command download ready */
#define IF_SPI_HISM_CMD_DOWNLOAD_RDY (1<<2)
-/** Host Interrupt Status Mask bit : Card event */
+/* Host Interrupt Status Mask bit : Card event */
#define IF_SPI_HISM_CARDEVENT (1<<3)
-/** Host Interrupt Status Mask bit : Command upload ready */
+/* Host Interrupt Status Mask bit : Command upload ready */
#define IF_SPI_HISM_CMD_UPLOAD_RDY (1<<4)
-/** Host Interrupt Status Mask bit : I/O write FIFO overflow */
+/* Host Interrupt Status Mask bit : I/O write FIFO overflow */
#define IF_SPI_HISM_IO_WR_FIFO_OVERFLOW (1<<5)
-/** Host Interrupt Status Mask bit : I/O read FIFO underflow */
+/* Host Interrupt Status Mask bit : I/O read FIFO underflow */
#define IF_SPI_HISM_IO_RD_FIFO_UNDERFLOW (1<<6)
-/** Host Interrupt Status Mask bit : Data write FIFO overflow */
+/* Host Interrupt Status Mask bit : Data write FIFO overflow */
#define IF_SPI_HISM_DATA_WR_FIFO_OVERFLOW (1<<7)
-/** Host Interrupt Status Mask bit : Data write FIFO underflow */
+/* Host Interrupt Status Mask bit : Data write FIFO underflow */
#define IF_SPI_HISM_DATA_RD_FIFO_UNDERFLOW (1<<8)
-/** Host Interrupt Status Mask bit : Command write FIFO overflow */
+/* Host Interrupt Status Mask bit : Command write FIFO overflow */
#define IF_SPI_HISM_CMD_WR_FIFO_OVERFLOW (1<<9)
-/** Host Interrupt Status Mask bit : Command write FIFO underflow */
+/* Host Interrupt Status Mask bit : Command write FIFO underflow */
#define IF_SPI_HISM_CMD_RD_FIFO_UNDERFLOW (1<<10)
/***************** IF_SPI_SPU_BUS_MODE_REG *****************/
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 6524c70363d9..b5acc393a65a 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -1,6 +1,9 @@
-/**
- * This file contains functions used in USB interface module.
- */
+/*
+ * This file contains functions used in USB interface module.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/firmware.h>
@@ -66,7 +69,7 @@ static int if_usb_reset_device(struct if_usb_card *cardp);
/* sysfs hooks */
-/**
+/*
* Set function to write firmware to device's persistent memory
*/
static ssize_t if_usb_firmware_set(struct device *dev,
@@ -85,7 +88,7 @@ static ssize_t if_usb_firmware_set(struct device *dev,
return ret;
}
-/**
+/*
* lbs_flash_fw attribute to be exported per ethX interface through sysfs
* (/sys/class/net/ethX/lbs_flash_fw). Use this like so to write firmware to
* the device's persistent memory:
@@ -94,7 +97,14 @@ static ssize_t if_usb_firmware_set(struct device *dev,
static DEVICE_ATTR(lbs_flash_fw, 0200, NULL, if_usb_firmware_set);
/**
- * Set function to write firmware to device's persistent memory
+ * if_usb_boot2_set - write firmware to device's persistent memory
+ *
+ * @dev: target device
+ * @attr: device attributes
+ * @buf: firmware buffer to write
+ * @count: number of bytes to write
+ *
+ * returns: number of bytes written or negative error code
*/
static ssize_t if_usb_boot2_set(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
@@ -112,7 +122,7 @@ static ssize_t if_usb_boot2_set(struct device *dev,
return ret;
}
-/**
+/*
* lbs_flash_boot2 attribute to be exported per ethX interface through sysfs
* (/sys/class/net/ethX/lbs_flash_boot2). Use this like so to write firmware
* to the device's persistent memory:
@@ -121,9 +131,10 @@ static ssize_t if_usb_boot2_set(struct device *dev,
static DEVICE_ATTR(lbs_flash_boot2, 0200, NULL, if_usb_boot2_set);
/**
- * @brief call back function to handle the status of the URB
- * @param urb pointer to urb structure
- * @return N/A
+ * if_usb_write_bulk_callback - callback function to handle the status
+ * of the URB
+ * @urb: pointer to &urb structure
+ * returns: N/A
*/
static void if_usb_write_bulk_callback(struct urb *urb)
{
@@ -145,14 +156,14 @@ static void if_usb_write_bulk_callback(struct urb *urb)
lbs_host_to_card_done(priv);
} else {
/* print the failure status number for debug */
- lbs_pr_info("URB in failure status: %d\n", urb->status);
+ pr_info("URB in failure status: %d\n", urb->status);
}
}
/**
- * @brief free tx/rx urb, skb and rx buffer
- * @param cardp pointer if_usb_card
- * @return N/A
+ * if_usb_free - free tx/rx urb, skb and rx buffer
+ * @cardp: pointer to &if_usb_card
+ * returns: N/A
*/
static void if_usb_free(struct if_usb_card *cardp)
{
@@ -195,7 +206,7 @@ static void if_usb_setup_firmware(struct lbs_private *priv)
wake_method.hdr.size = cpu_to_le16(sizeof(wake_method));
wake_method.action = cpu_to_le16(CMD_ACT_GET);
if (lbs_cmd_with_response(priv, CMD_802_11_FW_WAKE_METHOD, &wake_method)) {
- lbs_pr_info("Firmware does not seem to support PS mode\n");
+ netdev_info(priv->dev, "Firmware does not seem to support PS mode\n");
priv->fwcapinfo &= ~FW_CAPINFO_PS;
} else {
if (le16_to_cpu(wake_method.method) == CMD_WAKE_METHOD_COMMAND_INT) {
@@ -204,7 +215,8 @@ static void if_usb_setup_firmware(struct lbs_private *priv)
/* The versions which boot up this way don't seem to
work even if we set it to the command interrupt */
priv->fwcapinfo &= ~FW_CAPINFO_PS;
- lbs_pr_info("Firmware doesn't wake via command interrupt; disabling PS mode\n");
+ netdev_info(priv->dev,
+ "Firmware doesn't wake via command interrupt; disabling PS mode\n");
}
}
}
@@ -216,7 +228,7 @@ static void if_usb_fw_timeo(unsigned long priv)
if (cardp->fwdnldover) {
lbs_deb_usb("Download complete, no event. Assuming success\n");
} else {
- lbs_pr_err("Download timed out\n");
+ pr_err("Download timed out\n");
cardp->surprise_removed = 1;
}
wake_up(&cardp->fw_wq);
@@ -231,10 +243,10 @@ static void if_usb_reset_olpc_card(struct lbs_private *priv)
#endif
/**
- * @brief sets the configuration values
- * @param ifnum interface number
- * @param id pointer to usb_device_id
- * @return 0 on success, error code on failure
+ * if_usb_probe - sets the configuration values
+ * @intf: &usb_interface pointer
+ * @id: pointer to usb_device_id
+ * returns: 0 on success, error code on failure
*/
static int if_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -250,7 +262,7 @@ static int if_usb_probe(struct usb_interface *intf,
cardp = kzalloc(sizeof(struct if_usb_card), GFP_KERNEL);
if (!cardp) {
- lbs_pr_err("Out of memory allocating private data.\n");
+ pr_err("Out of memory allocating private data\n");
goto error;
}
@@ -340,10 +352,12 @@ static int if_usb_probe(struct usb_interface *intf,
usb_set_intfdata(intf, cardp);
if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_fw))
- lbs_pr_err("cannot register lbs_flash_fw attribute\n");
+ netdev_err(priv->dev,
+ "cannot register lbs_flash_fw attribute\n");
if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_boot2))
- lbs_pr_err("cannot register lbs_flash_boot2 attribute\n");
+ netdev_err(priv->dev,
+ "cannot register lbs_flash_boot2 attribute\n");
/*
* EHS_REMOVE_WAKEUP is not supported on all versions of the firmware.
@@ -366,9 +380,9 @@ error:
}
/**
- * @brief free resource and cleanup
- * @param intf USB interface structure
- * @return N/A
+ * if_usb_disconnect - free resource and cleanup
+ * @intf: USB interface structure
+ * returns: N/A
*/
static void if_usb_disconnect(struct usb_interface *intf)
{
@@ -398,9 +412,9 @@ static void if_usb_disconnect(struct usb_interface *intf)
}
/**
- * @brief This function download FW
- * @param priv pointer to struct lbs_private
- * @return 0
+ * if_usb_send_fw_pkt - download FW
+ * @cardp: pointer to &struct if_usb_card
+ * returns: 0
*/
static int if_usb_send_fw_pkt(struct if_usb_card *cardp)
{
@@ -486,11 +500,11 @@ static int if_usb_reset_device(struct if_usb_card *cardp)
}
/**
- * @brief This function transfer the data to the device.
- * @param priv pointer to struct lbs_private
- * @param payload pointer to payload data
- * @param nb data length
- * @return 0 or -1
+ * usb_tx_block - transfer the data to the device
+ * @cardp: pointer to &struct if_usb_card
+ * @payload: pointer to payload data
+ * @nb: data length
+ * returns: 0 for success or negative error code
*/
static int usb_tx_block(struct if_usb_card *cardp, uint8_t *payload, uint16_t nb)
{
@@ -528,7 +542,7 @@ static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
int ret = -1;
if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) {
- lbs_pr_err("No free skb\n");
+ pr_err("No free skb\n");
goto rx_ret;
}
@@ -587,7 +601,7 @@ static void if_usb_receive_fwload(struct urb *urb)
if (tmp[0] == cpu_to_le32(CMD_TYPE_INDICATION) &&
tmp[1] == cpu_to_le32(MACREG_INT_CODE_FIRMWARE_READY)) {
- lbs_pr_info("Firmware ready event received\n");
+ pr_info("Firmware ready event received\n");
wake_up(&cardp->fw_wq);
} else {
lbs_deb_usb("Waiting for confirmation; got %x %x\n",
@@ -614,20 +628,20 @@ static void if_usb_receive_fwload(struct urb *urb)
bootcmdresp.magic == cpu_to_le32(CMD_TYPE_DATA) ||
bootcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION)) {
if (!cardp->bootcmdresp)
- lbs_pr_info("Firmware already seems alive; resetting\n");
+ pr_info("Firmware already seems alive; resetting\n");
cardp->bootcmdresp = -1;
} else {
- lbs_pr_info("boot cmd response wrong magic number (0x%x)\n",
+ pr_info("boot cmd response wrong magic number (0x%x)\n",
le32_to_cpu(bootcmdresp.magic));
}
} else if ((bootcmdresp.cmd != BOOT_CMD_FW_BY_USB) &&
(bootcmdresp.cmd != BOOT_CMD_UPDATE_FW) &&
(bootcmdresp.cmd != BOOT_CMD_UPDATE_BOOT2)) {
- lbs_pr_info("boot cmd response cmd_tag error (%d)\n",
- bootcmdresp.cmd);
+ pr_info("boot cmd response cmd_tag error (%d)\n",
+ bootcmdresp.cmd);
} else if (bootcmdresp.result != BOOT_CMD_RESP_OK) {
- lbs_pr_info("boot cmd response result error (%d)\n",
- bootcmdresp.result);
+ pr_info("boot cmd response result error (%d)\n",
+ bootcmdresp.result);
} else {
cardp->bootcmdresp = 1;
lbs_deb_usbd(&cardp->udev->dev,
@@ -727,11 +741,11 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
}
/**
- * @brief This function reads of the packet into the upload buff,
- * wake up the main thread and initialise the Rx callack.
+ * if_usb_receive - read the packet into the upload buffer,
+ * wake up the main thread and initialise the Rx callack
*
- * @param urb pointer to struct urb
- * @return N/A
+ * @urb: pointer to &struct urb
+ * returns: N/A
*/
static void if_usb_receive(struct urb *urb)
{
@@ -802,12 +816,12 @@ rx_exit:
}
/**
- * @brief This function downloads data to FW
- * @param priv pointer to struct lbs_private structure
- * @param type type of data
- * @param buf pointer to data buffer
- * @param len number of bytes
- * @return 0 or -1
+ * if_usb_host_to_card - downloads data to FW
+ * @priv: pointer to &struct lbs_private structure
+ * @type: type of data
+ * @payload: pointer to data buffer
+ * @nb: number of bytes
+ * returns: 0 for success or negative error code
*/
static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
uint8_t *payload, uint16_t nb)
@@ -831,10 +845,11 @@ static int if_usb_host_to_card(struct lbs_private *priv, uint8_t type,
}
/**
- * @brief This function issues Boot command to the Boot2 code
- * @param ivalue 1:Boot from FW by USB-Download
- * 2:Boot from FW in EEPROM
- * @return 0
+ * if_usb_issue_boot_command - issues Boot command to the Boot2 code
+ * @cardp: pointer to &if_usb_card
+ * @ivalue: 1:Boot from FW by USB-Download
+ * 2:Boot from FW in EEPROM
+ * returns: 0 for success or negative error code
*/
static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue)
{
@@ -853,11 +868,11 @@ static int if_usb_issue_boot_command(struct if_usb_card *cardp, int ivalue)
/**
- * @brief This function checks the validity of Boot2/FW image.
+ * check_fwfile_format - check the validity of Boot2/FW image
*
- * @param data pointer to image
- * len image length
- * @return 0 or -1
+ * @data: pointer to image
+ * @totlen: image length
+ * returns: 0 (good) or 1 (failure)
*/
static int check_fwfile_format(const uint8_t *data, uint32_t totlen)
{
@@ -892,7 +907,7 @@ static int check_fwfile_format(const uint8_t *data, uint32_t totlen)
} while (!exit);
if (ret)
- lbs_pr_err("firmware file format check FAIL\n");
+ pr_err("firmware file format check FAIL\n");
else
lbs_deb_fw("firmware file format check PASS\n");
@@ -901,13 +916,13 @@ static int check_fwfile_format(const uint8_t *data, uint32_t totlen)
/**
-* @brief This function programs the firmware subject to cmd
+* if_usb_prog_firmware - programs the firmware subject to cmd
*
-* @param cardp the if_usb_card descriptor
-* fwname firmware or boot2 image file name
-* cmd either BOOT_CMD_FW_BY_USB, BOOT_CMD_UPDATE_FW,
-* or BOOT_CMD_UPDATE_BOOT2.
-* @return 0 or error code
+* @cardp: the if_usb_card descriptor
+* @fwname: firmware or boot2 image file name
+* @cmd: either BOOT_CMD_FW_BY_USB, BOOT_CMD_UPDATE_FW,
+* or BOOT_CMD_UPDATE_BOOT2.
+* returns: 0 or error code
*/
static int if_usb_prog_firmware(struct if_usb_card *cardp,
const char *fwname, int cmd)
@@ -989,7 +1004,7 @@ static int __if_usb_prog_firmware(struct if_usb_card *cardp,
ret = get_fw(cardp, fwname);
if (ret) {
- lbs_pr_err("failed to find firmware (%d)\n", ret);
+ pr_err("failed to find firmware (%d)\n", ret);
goto done;
}
@@ -1064,13 +1079,13 @@ restart:
usb_kill_urb(cardp->rx_urb);
if (!cardp->fwdnldover) {
- lbs_pr_info("failed to load fw, resetting device!\n");
+ pr_info("failed to load fw, resetting device!\n");
if (--reset_count >= 0) {
if_usb_reset_device(cardp);
goto restart;
}
- lbs_pr_info("FW download failure, time = %d ms\n", i * 100);
+ pr_info("FW download failure, time = %d ms\n", i * 100);
ret = -EIO;
goto release_fw;
}
diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h
index d819e7e3c9aa..6e42eac331de 100644
--- a/drivers/net/wireless/libertas/if_usb.h
+++ b/drivers/net/wireless/libertas/if_usb.h
@@ -6,9 +6,9 @@
struct lbs_private;
-/**
- * This file contains definition for USB interface.
- */
+/*
+ * This file contains definition for USB interface.
+ */
#define CMD_TYPE_REQUEST 0xF00DFACE
#define CMD_TYPE_DATA 0xBEADC0DE
#define CMD_TYPE_INDICATION 0xBEEFFACE
@@ -40,7 +40,7 @@ struct bootcmdresp
uint8_t pad[2];
};
-/** USB card description structure*/
+/* USB card description structure*/
struct if_usb_card {
struct usb_device *udev;
uint32_t model; /* MODEL_* */
@@ -77,7 +77,7 @@ struct if_usb_card {
__le16 boot2_version;
};
-/** fwheader */
+/* fwheader */
struct fwheader {
__le32 dnldcmd;
__le32 baseaddr;
@@ -86,14 +86,14 @@ struct fwheader {
};
#define FW_MAX_DATA_BLK_SIZE 600
-/** FWData */
+/* FWData */
struct fwdata {
struct fwheader hdr;
__le32 seqnum;
uint8_t data[0];
};
-/** fwsyncheader */
+/* fwsyncheader */
struct fwsyncheader {
__le32 cmd;
__le32 seqnum;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index ca8149cd5bd9..8c40949cb076 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -1,8 +1,10 @@
-/**
- * This file contains the major functions in WLAN
- * driver. It includes init, exit, open, close and main
- * thread etc..
- */
+/*
+ * This file contains the major functions in WLAN
+ * driver. It includes init, exit, open, close and main
+ * thread etc..
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/moduleparam.h>
#include <linux/delay.h>
@@ -34,19 +36,25 @@ unsigned int lbs_debug;
EXPORT_SYMBOL_GPL(lbs_debug);
module_param_named(libertas_debug, lbs_debug, int, 0644);
+unsigned int lbs_disablemesh;
+EXPORT_SYMBOL_GPL(lbs_disablemesh);
+module_param_named(libertas_disablemesh, lbs_disablemesh, int, 0644);
-/* This global structure is used to send the confirm_sleep command as
- * fast as possible down to the firmware. */
+
+/*
+ * This global structure is used to send the confirm_sleep command as
+ * fast as possible down to the firmware.
+ */
struct cmd_confirm_sleep confirm_sleep;
-/**
+/*
* the table to keep region code
*/
u16 lbs_region_code_to_index[MRVDRV_MAX_REGION_CODE] =
{ 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 };
-/**
+/*
* FW rate table. FW refers to rates by their index in this table, not by the
* rate value itself. Values of 0x00 are
* reserved positions.
@@ -57,10 +65,10 @@ static u8 fw_data_rates[MAX_RATES] =
};
/**
- * @brief use index to get the data rate
+ * lbs_fw_index_to_data_rate - use index to get the data rate
*
- * @param idx The index of data rate
- * @return data rate or 0
+ * @idx: The index of data rate
+ * returns: data rate or 0
*/
u32 lbs_fw_index_to_data_rate(u8 idx)
{
@@ -70,10 +78,10 @@ u32 lbs_fw_index_to_data_rate(u8 idx)
}
/**
- * @brief use rate to get the index
+ * lbs_data_rate_to_fw_index - use rate to get the index
*
- * @param rate data rate
- * @return index or 0
+ * @rate: data rate
+ * returns: index or 0
*/
u8 lbs_data_rate_to_fw_index(u32 rate)
{
@@ -91,10 +99,10 @@ u8 lbs_data_rate_to_fw_index(u32 rate)
/**
- * @brief This function opens the ethX interface
+ * lbs_dev_open - open the ethX interface
*
- * @param dev A pointer to net_device structure
- * @return 0 or -EBUSY if monitor mode active
+ * @dev: A pointer to &net_device structure
+ * returns: 0 or -EBUSY if monitor mode active
*/
static int lbs_dev_open(struct net_device *dev)
{
@@ -120,10 +128,10 @@ static int lbs_dev_open(struct net_device *dev)
}
/**
- * @brief This function closes the ethX interface
+ * lbs_eth_stop - close the ethX interface
*
- * @param dev A pointer to net_device structure
- * @return 0
+ * @dev: A pointer to &net_device structure
+ * returns: 0
*/
static int lbs_eth_stop(struct net_device *dev)
{
@@ -147,28 +155,6 @@ static int lbs_eth_stop(struct net_device *dev)
return 0;
}
-static void lbs_tx_timeout(struct net_device *dev)
-{
- struct lbs_private *priv = dev->ml_priv;
-
- lbs_deb_enter(LBS_DEB_TX);
-
- lbs_pr_err("tx watch dog timeout\n");
-
- dev->trans_start = jiffies; /* prevent tx timeout */
-
- if (priv->currenttxskb)
- lbs_send_tx_feedback(priv, 0);
-
- /* XX: Shouldn't we also call into the hw-specific driver
- to kick it somehow? */
- lbs_host_to_card_done(priv);
-
- /* FIXME: reset the card */
-
- lbs_deb_leave(LBS_DEB_TX);
-}
-
void lbs_host_to_card_done(struct lbs_private *priv)
{
unsigned long flags;
@@ -336,12 +322,12 @@ void lbs_set_multicast_list(struct net_device *dev)
}
/**
- * @brief This function handles the major jobs in the LBS driver.
+ * lbs_thread - handles the major jobs in the LBS driver.
* It handles all events generated by firmware, RX data received
* from firmware and TX data sent from kernel.
*
- * @param data A pointer to lbs_thread structure
- * @return 0
+ * @data: A pointer to &lbs_thread structure
+ * returns: 0
*/
static int lbs_thread(void *data)
{
@@ -462,8 +448,8 @@ static int lbs_thread(void *data)
if (priv->cmd_timed_out && priv->cur_cmd) {
struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
- lbs_pr_info("Timeout submitting command 0x%04x\n",
- le16_to_cpu(cmdnode->cmdbuf->command));
+ netdev_info(dev, "Timeout submitting command 0x%04x\n",
+ le16_to_cpu(cmdnode->cmdbuf->command));
lbs_complete_command(priv, cmdnode, -ETIMEDOUT);
if (priv->reset_card)
priv->reset_card(priv);
@@ -490,8 +476,8 @@ static int lbs_thread(void *data)
* after firmware fixes it
*/
priv->psstate = PS_STATE_AWAKE;
- lbs_pr_alert("ignore PS_SleepConfirm in "
- "non-connected state\n");
+ netdev_alert(dev,
+ "ignore PS_SleepConfirm in non-connected state\n");
}
}
@@ -540,11 +526,11 @@ static int lbs_thread(void *data)
}
/**
- * @brief This function gets the HW spec from the firmware and sets
- * some basic parameters.
+ * lbs_setup_firmware - gets the HW spec from the firmware and sets
+ * some basic parameters
*
- * @param priv A pointer to struct lbs_private structure
- * @return 0 or -1
+ * @priv: A pointer to &struct lbs_private structure
+ * returns: 0 or -1
*/
static int lbs_setup_firmware(struct lbs_private *priv)
{
@@ -585,7 +571,8 @@ int lbs_suspend(struct lbs_private *priv)
if (priv->is_deep_sleep) {
ret = lbs_set_deep_sleep(priv, 0);
if (ret) {
- lbs_pr_err("deep sleep cancellation failed: %d\n", ret);
+ netdev_err(priv->dev,
+ "deep sleep cancellation failed: %d\n", ret);
return ret;
}
priv->deep_sleep_required = 1;
@@ -618,7 +605,8 @@ int lbs_resume(struct lbs_private *priv)
priv->deep_sleep_required = 0;
ret = lbs_set_deep_sleep(priv, 1);
if (ret)
- lbs_pr_err("deep sleep activation failed: %d\n", ret);
+ netdev_err(priv->dev,
+ "deep sleep activation failed: %d\n", ret);
}
if (priv->setup_fw_on_resume)
@@ -630,8 +618,10 @@ int lbs_resume(struct lbs_private *priv)
EXPORT_SYMBOL_GPL(lbs_resume);
/**
- * This function handles the timeout of command sending.
- * It will re-send the same command again.
+ * lbs_cmd_timeout_handler - handles the timeout of command sending.
+ * It will re-send the same command again.
+ *
+ * @data: &struct lbs_private pointer
*/
static void lbs_cmd_timeout_handler(unsigned long data)
{
@@ -644,8 +634,8 @@ static void lbs_cmd_timeout_handler(unsigned long data)
if (!priv->cur_cmd)
goto out;
- lbs_pr_info("command 0x%04x timed out\n",
- le16_to_cpu(priv->cur_cmd->cmdbuf->command));
+ netdev_info(priv->dev, "command 0x%04x timed out\n",
+ le16_to_cpu(priv->cur_cmd->cmdbuf->command));
priv->cmd_timed_out = 1;
wake_up_interruptible(&priv->waitq);
@@ -655,8 +645,10 @@ out:
}
/**
- * This function put the device back to deep sleep mode when timer expires
- * and no activity (command, event, data etc.) is detected.
+ * auto_deepsleep_timer_fn - put the device back to deep sleep mode when
+ * timer expires and no activity (command, event, data etc.) is detected.
+ * @data: &struct lbs_private pointer
+ * returns: N/A
*/
static void auto_deepsleep_timer_fn(unsigned long data)
{
@@ -748,7 +740,7 @@ static int lbs_init_adapter(struct lbs_private *priv)
/* Allocate the command buffers */
if (lbs_allocate_cmd_buffer(priv)) {
- lbs_pr_err("Out of memory allocating command buffers\n");
+ pr_err("Out of memory allocating command buffers\n");
ret = -ENOMEM;
goto out;
}
@@ -758,7 +750,7 @@ static int lbs_init_adapter(struct lbs_private *priv)
/* Create the event FIFO */
ret = kfifo_alloc(&priv->event_fifo, sizeof(u32) * 16, GFP_KERNEL);
if (ret) {
- lbs_pr_err("Out of memory allocating event FIFO buffer\n");
+ pr_err("Out of memory allocating event FIFO buffer\n");
goto out;
}
@@ -785,18 +777,18 @@ static const struct net_device_ops lbs_netdev_ops = {
.ndo_stop = lbs_eth_stop,
.ndo_start_xmit = lbs_hard_start_xmit,
.ndo_set_mac_address = lbs_set_mac_address,
- .ndo_tx_timeout = lbs_tx_timeout,
.ndo_set_multicast_list = lbs_set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
};
/**
- * @brief This function adds the card. it will probe the
+ * lbs_add_card - adds the card. It will probe the
* card, allocate the lbs_priv and initialize the device.
*
- * @param card A pointer to card
- * @return A pointer to struct lbs_private structure
+ * @card: A pointer to card
+ * @dmdev: A pointer to &struct device
+ * returns: A pointer to &struct lbs_private structure
*/
struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
{
@@ -809,7 +801,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
/* Allocate an Ethernet device and register it */
wdev = lbs_cfg_alloc(dmdev);
if (IS_ERR(wdev)) {
- lbs_pr_err("cfg80211 init failed\n");
+ pr_err("cfg80211 init failed\n");
goto done;
}
@@ -818,7 +810,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
priv->wdev = wdev;
if (lbs_init_adapter(priv)) {
- lbs_pr_err("failed to initialize adapter structure.\n");
+ pr_err("failed to initialize adapter structure\n");
goto err_wdev;
}
@@ -950,17 +942,20 @@ int lbs_start_card(struct lbs_private *priv)
goto done;
if (lbs_cfg_register(priv)) {
- lbs_pr_err("cannot register device\n");
+ pr_err("cannot register device\n");
goto done;
}
lbs_update_channel(priv);
- lbs_init_mesh(priv);
+ if (!lbs_disablemesh)
+ lbs_init_mesh(priv);
+ else
+ pr_info("%s: mesh disabled\n", dev->name);
lbs_debugfs_init_one(priv, dev);
- lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name);
+ netdev_info(dev, "Marvell WLAN 802.11 adapter\n");
ret = 0;
@@ -1057,19 +1052,19 @@ void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx)
EXPORT_SYMBOL_GPL(lbs_notify_command_response);
/**
- * @brief Retrieves two-stage firmware
+ * lbs_get_firmware - Retrieves two-stage firmware
*
- * @param dev A pointer to device structure
- * @param user_helper User-defined helper firmware file
- * @param user_mainfw User-defined main firmware file
- * @param card_model Bus-specific card model ID used to filter firmware table
- * elements
- * @param fw_table Table of firmware file names and device model numbers
- * terminated by an entry with a NULL helper name
- * @param helper On success, the helper firmware; caller must free
- * @param mainfw On success, the main firmware; caller must free
+ * @dev: A pointer to &device structure
+ * @user_helper: User-defined helper firmware file
+ * @user_mainfw: User-defined main firmware file
+ * @card_model: Bus-specific card model ID used to filter firmware table
+ * elements
+ * @fw_table: Table of firmware file names and device model numbers
+ * terminated by an entry with a NULL helper name
+ * @helper: On success, the helper firmware; caller must free
+ * @mainfw: On success, the main firmware; caller must free
*
- * @return 0 on success, non-zero on failure
+ * returns: 0 on success, non-zero on failure
*/
int lbs_get_firmware(struct device *dev, const char *user_helper,
const char *user_mainfw, u32 card_model,
@@ -1087,16 +1082,16 @@ int lbs_get_firmware(struct device *dev, const char *user_helper,
if (user_helper) {
ret = request_firmware(helper, user_helper, dev);
if (ret) {
- lbs_pr_err("couldn't find helper firmware %s",
- user_helper);
+ dev_err(dev, "couldn't find helper firmware %s\n",
+ user_helper);
goto fail;
}
}
if (user_mainfw) {
ret = request_firmware(mainfw, user_mainfw, dev);
if (ret) {
- lbs_pr_err("couldn't find main firmware %s",
- user_mainfw);
+ dev_err(dev, "couldn't find main firmware %s\n",
+ user_mainfw);
goto fail;
}
}
diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c
index 9d097b9c8005..24cf06680c6b 100644
--- a/drivers/net/wireless/libertas/mesh.c
+++ b/drivers/net/wireless/libertas/mesh.c
@@ -1,3 +1,5 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/netdevice.h>
@@ -16,12 +18,15 @@
* Mesh sysfs support
*/
-/**
+/*
* Attributes exported through sysfs
*/
/**
- * @brief Get function for sysfs attribute anycast_mask
+ * lbs_anycast_get - Get function for sysfs attribute anycast_mask
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
*/
static ssize_t lbs_anycast_get(struct device *dev,
struct device_attribute *attr, char * buf)
@@ -40,7 +45,11 @@ static ssize_t lbs_anycast_get(struct device *dev,
}
/**
- * @brief Set function for sysfs attribute anycast_mask
+ * lbs_anycast_set - Set function for sysfs attribute anycast_mask
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
*/
static ssize_t lbs_anycast_set(struct device *dev,
struct device_attribute *attr, const char * buf, size_t count)
@@ -62,7 +71,10 @@ static ssize_t lbs_anycast_set(struct device *dev,
}
/**
- * @brief Get function for sysfs attribute prb_rsp_limit
+ * lbs_prb_rsp_limit_get - Get function for sysfs attribute prb_rsp_limit
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
*/
static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -85,7 +97,11 @@ static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
}
/**
- * @brief Set function for sysfs attribute prb_rsp_limit
+ * lbs_prb_rsp_limit_set - Set function for sysfs attribute prb_rsp_limit
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
*/
static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
@@ -114,7 +130,10 @@ static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
}
/**
- * Get function for sysfs attribute mesh
+ * lbs_mesh_get - Get function for sysfs attribute mesh
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
*/
static ssize_t lbs_mesh_get(struct device *dev,
struct device_attribute *attr, char * buf)
@@ -124,7 +143,11 @@ static ssize_t lbs_mesh_get(struct device *dev,
}
/**
- * Set function for sysfs attribute mesh
+ * lbs_mesh_set - Set function for sysfs attribute mesh
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
*/
static ssize_t lbs_mesh_set(struct device *dev,
struct device_attribute *attr, const char * buf, size_t count)
@@ -151,19 +174,19 @@ static ssize_t lbs_mesh_set(struct device *dev,
return count;
}
-/**
+/*
* lbs_mesh attribute to be exported per ethX interface
* through sysfs (/sys/class/net/ethX/lbs_mesh)
*/
static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set);
-/**
+/*
* anycast_mask attribute to be exported per mshX interface
* through sysfs (/sys/class/net/mshX/anycast_mask)
*/
static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set);
-/**
+/*
* prb_rsp_limit attribute to be exported per mshX interface
* through sysfs (/sys/class/net/mshX/prb_rsp_limit)
*/
@@ -246,7 +269,7 @@ int lbs_init_mesh(struct lbs_private *priv)
lbs_add_mesh(priv);
if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
- lbs_pr_err("cannot register lbs_mesh attribute\n");
+ netdev_err(dev, "cannot register lbs_mesh attribute\n");
ret = 1;
}
@@ -274,10 +297,10 @@ int lbs_deinit_mesh(struct lbs_private *priv)
/**
- * @brief This function closes the mshX interface
+ * lbs_mesh_stop - close the mshX interface
*
- * @param dev A pointer to net_device structure
- * @return 0
+ * @dev: A pointer to &net_device structure
+ * returns: 0
*/
static int lbs_mesh_stop(struct net_device *dev)
{
@@ -301,10 +324,10 @@ static int lbs_mesh_stop(struct net_device *dev)
}
/**
- * @brief This function opens the mshX interface
+ * lbs_mesh_dev_open - open the mshX interface
*
- * @param dev A pointer to net_device structure
- * @return 0 or -EBUSY if monitor mode active
+ * @dev: A pointer to &net_device structure
+ * returns: 0 or -EBUSY if monitor mode active
*/
static int lbs_mesh_dev_open(struct net_device *dev)
{
@@ -342,10 +365,10 @@ static const struct net_device_ops mesh_netdev_ops = {
};
/**
- * @brief This function adds mshX interface
+ * lbs_add_mesh - add mshX interface
*
- * @param priv A pointer to the struct lbs_private structure
- * @return 0 if successful, -X otherwise
+ * @priv: A pointer to the &struct lbs_private structure
+ * returns: 0 if successful, -X otherwise
*/
int lbs_add_mesh(struct lbs_private *priv)
{
@@ -374,7 +397,7 @@ int lbs_add_mesh(struct lbs_private *priv)
/* Register virtual mesh interface */
ret = register_netdev(mesh_dev);
if (ret) {
- lbs_pr_err("cannot register mshX virtual interface\n");
+ pr_err("cannot register mshX virtual interface\n");
goto err_free;
}
@@ -456,13 +479,13 @@ void lbs_mesh_set_txpd(struct lbs_private *priv,
*/
/**
- * @brief Add or delete Mesh Blinding Table entries
+ * lbs_mesh_bt_add_del - 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
+ * @priv: A pointer to &struct lbs_private structure
+ * @add: TRUE to add the entry, FALSE to delete it
+ * @addr1: Destination address to blind or unblind
*
- * @return 0 on success, error on failure
+ * returns: 0 on success, error on failure
*/
int lbs_mesh_bt_add_del(struct lbs_private *priv, bool add, u8 *addr1)
{
@@ -493,11 +516,11 @@ int lbs_mesh_bt_add_del(struct lbs_private *priv, bool add, u8 *addr1)
}
/**
- * @brief Reset/clear the mesh blinding table
+ * lbs_mesh_bt_reset - Reset/clear the mesh blinding table
*
- * @param priv A pointer to struct lbs_private structure
+ * @priv: A pointer to &struct lbs_private structure
*
- * @return 0 on success, error on failure
+ * returns: 0 on success, error on failure
*/
int lbs_mesh_bt_reset(struct lbs_private *priv)
{
@@ -517,17 +540,18 @@ int lbs_mesh_bt_reset(struct lbs_private *priv)
}
/**
- * @brief Gets the inverted status of the mesh blinding table
+ * lbs_mesh_bt_get_inverted - 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.
+ * 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
+ * @priv: A pointer to &struct lbs_private structure
+ * @inverted: On success, TRUE if the blinding table is inverted,
+ * FALSE if it is not inverted
*
- * @return 0 on success, error on failure
+ * returns: 0 on success, error on failure
*/
int lbs_mesh_bt_get_inverted(struct lbs_private *priv, bool *inverted)
{
@@ -551,18 +575,19 @@ int lbs_mesh_bt_get_inverted(struct lbs_private *priv, bool *inverted)
}
/**
- * @brief Sets the inverted status of the mesh blinding table
+ * lbs_mesh_bt_set_inverted - 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.
+ * 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)
+ * @priv: A pointer to &struct lbs_private structure
+ * @inverted: 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
+ * returns: 0 on success, error on failure
*/
int lbs_mesh_bt_set_inverted(struct lbs_private *priv, bool inverted)
{
@@ -583,13 +608,13 @@ int lbs_mesh_bt_set_inverted(struct lbs_private *priv, bool inverted)
}
/**
- * @brief List an entry in the mesh blinding table
+ * lbs_mesh_bt_get_entry - 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
+ * @priv: A pointer to &struct lbs_private structure
+ * @id: The ID of the entry to list
+ * @addr1: MAC address associated with the table entry
*
- * @return 0 on success, error on failure
+ * returns: 0 on success, error on failure
*/
int lbs_mesh_bt_get_entry(struct lbs_private *priv, u32 id, u8 *addr1)
{
@@ -614,14 +639,14 @@ int lbs_mesh_bt_get_entry(struct lbs_private *priv, u32 id, u8 *addr1)
}
/**
- * @brief Access the mesh forwarding table
+ * lbs_cmd_fwt_access - 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
+ * @priv: A pointer to &struct lbs_private structure
+ * @cmd_action: The forwarding table action to perform
+ * @cmd: The pre-filled FWT_ACCESS command
*
- * @return 0 on success and 'cmd' will be filled with the
- * firmware's response
+ * returns: 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)
@@ -774,7 +799,10 @@ static int mesh_get_default_parameters(struct device *dev,
}
/**
- * @brief Get function for sysfs attribute bootflag
+ * bootflag_get - Get function for sysfs attribute bootflag
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
*/
static ssize_t bootflag_get(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -791,7 +819,11 @@ static ssize_t bootflag_get(struct device *dev,
}
/**
- * @brief Set function for sysfs attribute bootflag
+ * bootflag_set - Set function for sysfs attribute bootflag
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
*/
static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
@@ -817,7 +849,10 @@ static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
}
/**
- * @brief Get function for sysfs attribute boottime
+ * boottime_get - Get function for sysfs attribute boottime
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
*/
static ssize_t boottime_get(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -834,7 +869,11 @@ static ssize_t boottime_get(struct device *dev,
}
/**
- * @brief Set function for sysfs attribute boottime
+ * boottime_set - Set function for sysfs attribute boottime
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
*/
static ssize_t boottime_set(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
@@ -869,7 +908,10 @@ static ssize_t boottime_set(struct device *dev,
}
/**
- * @brief Get function for sysfs attribute channel
+ * channel_get - Get function for sysfs attribute channel
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
*/
static ssize_t channel_get(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -886,7 +928,11 @@ static ssize_t channel_get(struct device *dev,
}
/**
- * @brief Set function for sysfs attribute channel
+ * channel_set - Set function for sysfs attribute channel
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
*/
static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
@@ -912,7 +958,10 @@ static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
}
/**
- * @brief Get function for sysfs attribute mesh_id
+ * mesh_id_get - Get function for sysfs attribute mesh_id
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
*/
static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -926,7 +975,7 @@ static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
return ret;
if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
- lbs_pr_err("inconsistent mesh ID length");
+ dev_err(dev, "inconsistent mesh ID length\n");
defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
}
@@ -938,7 +987,11 @@ static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
}
/**
- * @brief Set function for sysfs attribute mesh_id
+ * mesh_id_set - Set function for sysfs attribute mesh_id
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
*/
static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
@@ -980,7 +1033,10 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
}
/**
- * @brief Get function for sysfs attribute protocol_id
+ * protocol_id_get - Get function for sysfs attribute protocol_id
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
*/
static ssize_t protocol_id_get(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -997,7 +1053,11 @@ static ssize_t protocol_id_get(struct device *dev,
}
/**
- * @brief Set function for sysfs attribute protocol_id
+ * protocol_id_set - Set function for sysfs attribute protocol_id
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
*/
static ssize_t protocol_id_set(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
@@ -1034,7 +1094,10 @@ static ssize_t protocol_id_set(struct device *dev,
}
/**
- * @brief Get function for sysfs attribute metric_id
+ * metric_id_get - Get function for sysfs attribute metric_id
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
*/
static ssize_t metric_id_get(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -1051,7 +1114,11 @@ static ssize_t metric_id_get(struct device *dev,
}
/**
- * @brief Set function for sysfs attribute metric_id
+ * metric_id_set - Set function for sysfs attribute metric_id
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
*/
static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
@@ -1088,7 +1155,10 @@ static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
}
/**
- * @brief Get function for sysfs attribute capability
+ * capability_get - Get function for sysfs attribute capability
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer where data will be returned
*/
static ssize_t capability_get(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -1105,7 +1175,11 @@ static ssize_t capability_get(struct device *dev,
}
/**
- * @brief Set function for sysfs attribute capability
+ * capability_set - Set function for sysfs attribute capability
+ * @dev: the &struct device
+ * @attr: device attributes
+ * @buf: buffer that contains new attribute value
+ * @count: size of buffer
*/
static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
diff --git a/drivers/net/wireless/libertas/mesh.h b/drivers/net/wireless/libertas/mesh.h
index afb2e8dead3f..ee95c73ed5f4 100644
--- a/drivers/net/wireless/libertas/mesh.h
+++ b/drivers/net/wireless/libertas/mesh.h
@@ -1,6 +1,6 @@
-/**
- * Contains all definitions needed for the Libertas' MESH implementation.
- */
+/*
+ * Contains all definitions needed for the Libertas' MESH implementation.
+ */
#ifndef _LBS_MESH_H_
#define _LBS_MESH_H_
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
index a2b1df21d286..fdb0448301a0 100644
--- a/drivers/net/wireless/libertas/rx.c
+++ b/drivers/net/wireless/libertas/rx.c
@@ -1,6 +1,9 @@
-/**
- * This file contains the handling of RX in wlan driver.
- */
+/*
+ * This file contains the handling of RX in wlan driver.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/etherdevice.h>
#include <linux/slab.h>
#include <linux/types.h>
@@ -40,12 +43,12 @@ static int process_rxed_802_11_packet(struct lbs_private *priv,
struct sk_buff *skb);
/**
- * @brief This function processes received packet and forwards it
- * to kernel/upper layer
+ * lbs_process_rxed_packet - processes received packet and forwards it
+ * to kernel/upper layer
*
- * @param priv A pointer to struct lbs_private
- * @param skb A pointer to skb which includes the received packet
- * @return 0 or -1
+ * @priv: A pointer to &struct lbs_private
+ * @skb: A pointer to skb which includes the received packet
+ * returns: 0 or -1
*/
int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
{
@@ -156,11 +159,11 @@ done:
EXPORT_SYMBOL_GPL(lbs_process_rxed_packet);
/**
- * @brief This function converts Tx/Rx rates from the Marvell WLAN format
- * (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s)
+ * convert_mv_rate_to_radiotap - converts Tx/Rx rates from Marvell WLAN format
+ * (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s)
*
- * @param rate Input rate
- * @return Output Rate (0 if invalid)
+ * @rate: Input rate
+ * returns: Output Rate (0 if invalid)
*/
static u8 convert_mv_rate_to_radiotap(u8 rate)
{
@@ -191,17 +194,17 @@ static u8 convert_mv_rate_to_radiotap(u8 rate)
case 12: /* 54 Mbps */
return 108;
}
- lbs_pr_alert("Invalid Marvell WLAN rate %i\n", rate);
+ pr_alert("Invalid Marvell WLAN rate %i\n", rate);
return 0;
}
/**
- * @brief This function processes a received 802.11 packet and forwards it
- * to kernel/upper layer
+ * process_rxed_802_11_packet - processes a received 802.11 packet and forwards
+ * it to kernel/upper layer
*
- * @param priv A pointer to struct lbs_private
- * @param skb A pointer to skb which includes the received packet
- * @return 0 or -1
+ * @priv: A pointer to &struct lbs_private
+ * @skb: A pointer to skb which includes the received packet
+ * returns: 0 or -1
*/
static int process_rxed_802_11_packet(struct lbs_private *priv,
struct sk_buff *skb)
@@ -248,7 +251,7 @@ static int process_rxed_802_11_packet(struct lbs_private *priv,
/* add space for the new radio header */
if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) &&
pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0, GFP_ATOMIC)) {
- lbs_pr_alert("%s: couldn't pskb_expand_head\n", __func__);
+ netdev_alert(dev, "%s: couldn't pskb_expand_head\n", __func__);
ret = -ENOMEM;
kfree_skb(skb);
goto done;
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
index 8000ca6165d0..bbb95f88dc01 100644
--- a/drivers/net/wireless/libertas/tx.c
+++ b/drivers/net/wireless/libertas/tx.c
@@ -1,6 +1,6 @@
-/**
- * This file contains the handling of TX in wlan driver.
- */
+/*
+ * This file contains the handling of TX in wlan driver.
+ */
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/sched.h>
@@ -13,11 +13,11 @@
#include "dev.h"
/**
- * @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE
- * units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1)
+ * convert_radiotap_rate_to_mv - converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE
+ * units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1)
*
- * @param rate Input rate
- * @return Output Rate (0 if invalid)
+ * @rate: Input rate
+ * returns: Output Rate (0 if invalid)
*/
static u32 convert_radiotap_rate_to_mv(u8 rate)
{
@@ -51,12 +51,12 @@ static u32 convert_radiotap_rate_to_mv(u8 rate)
}
/**
- * @brief This function checks the conditions and sends packet to IF
- * layer if everything is ok.
+ * lbs_hard_start_xmit - checks the conditions and sends packet to IF
+ * layer if everything is ok
*
- * @param priv A pointer to struct lbs_private structure
- * @param skb A pointer to skb which includes TX packet
- * @return 0 or -1
+ * @skb: A pointer to skb which includes TX packet
+ * @dev: A pointer to the &struct net_device
+ * returns: 0 or -1
*/
netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
@@ -168,13 +168,13 @@ netdev_tx_t lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
/**
- * @brief This function sends to the host the last transmitted packet,
- * filling the radiotap headers with transmission information.
+ * lbs_send_tx_feedback - sends to the host the last transmitted packet,
+ * filling the radiotap headers with transmission information.
*
- * @param priv A pointer to struct lbs_private structure
- * @param status A 32 bit value containing transmission status.
+ * @priv: A pointer to &struct lbs_private structure
+ * @try_count: A 32-bit value containing transmission retry status.
*
- * @returns void
+ * returns: void
*/
void lbs_send_tx_feedback(struct lbs_private *priv, u32 try_count)
{
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
index 462fbb4cb743..cf1d9b047ee6 100644
--- a/drivers/net/wireless/libertas/types.h
+++ b/drivers/net/wireless/libertas/types.h
@@ -1,6 +1,6 @@
-/**
- * This header file contains definition for global types
- */
+/*
+ * This header file contains definition for global types
+ */
#ifndef _LBS_TYPES_H_
#define _LBS_TYPES_H_
@@ -54,7 +54,7 @@ union ieee_phy_param_set {
struct ieee_ie_ds_param_set ds;
} __packed;
-/** TLV type ID definition */
+/* TLV type ID definition */
#define PROPRIETARY_TLV_BASE_ID 0x0100
/* Terminating TLV type */
@@ -96,7 +96,7 @@ union ieee_phy_param_set {
#define TLV_TYPE_MESH_ID (PROPRIETARY_TLV_BASE_ID + 37)
#define TLV_TYPE_OLD_MESH_ID (PROPRIETARY_TLV_BASE_ID + 291)
-/** TLV related data structures*/
+/* TLV related data structures */
struct mrvl_ie_header {
__le16 type;
__le16 len;
@@ -177,7 +177,7 @@ struct mrvl_ie_auth_type {
__le16 auth;
} __packed;
-/** Local Power capability */
+/* Local Power capability */
struct mrvl_ie_power_capability {
struct mrvl_ie_header header;
s8 minpower;
@@ -235,9 +235,11 @@ struct mrvl_ie_ledbhv {
struct led_bhv ledbhv[1];
} __packed;
-/* Meant to be packed as the value member of a struct ieee80211_info_element.
+/*
+ * 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
- * the mesh_id_len */
+ * the mesh_id_len
+ */
struct mrvl_meshie_val {
uint8_t oui[3];
uint8_t type;
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index f4f4257a9d67..9d4a40ee16c4 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -1515,19 +1515,10 @@ static int __init init_mac80211_hwsim(void)
if (hwsim_mon == NULL)
goto failed;
- rtnl_lock();
-
- err = dev_alloc_name(hwsim_mon, hwsim_mon->name);
+ err = register_netdev(hwsim_mon);
if (err < 0)
goto failed_mon;
-
- err = register_netdevice(hwsim_mon);
- if (err < 0)
- goto failed_mon;
-
- rtnl_unlock();
-
return 0;
failed_mon:
diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c
new file mode 100644
index 000000000000..916183d39009
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11n.c
@@ -0,0 +1,744 @@
+/*
+ * Marvell Wireless LAN device driver: 802.11n
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+
+/*
+ * Fills HT capability information field, AMPDU Parameters field, HT extended
+ * capability field, and supported MCS set fields.
+ *
+ * HT capability information field, AMPDU Parameters field, supported MCS set
+ * fields are retrieved from cfg80211 stack
+ *
+ * RD responder bit to set to clear in the extended capability header.
+ */
+void
+mwifiex_fill_cap_info(struct mwifiex_private *priv, u8 radio_type,
+ struct mwifiex_ie_types_htcap *ht_cap)
+{
+ uint16_t ht_ext_cap = le16_to_cpu(ht_cap->ht_cap.extended_ht_cap_info);
+ struct ieee80211_supported_band *sband =
+ priv->wdev->wiphy->bands[radio_type];
+
+ ht_cap->ht_cap.ampdu_params_info =
+ (sband->ht_cap.ampdu_factor &
+ IEEE80211_HT_AMPDU_PARM_FACTOR)|
+ ((sband->ht_cap.ampdu_density <<
+ IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT) &
+ IEEE80211_HT_AMPDU_PARM_DENSITY);
+
+ memcpy((u8 *) &ht_cap->ht_cap.mcs, &sband->ht_cap.mcs,
+ sizeof(sband->ht_cap.mcs));
+
+ if (priv->bss_mode == NL80211_IFTYPE_STATION ||
+ (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
+ /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */
+ SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask);
+
+ /* Clear RD responder bit */
+ ht_ext_cap &= ~IEEE80211_HT_EXT_CAP_RD_RESPONDER;
+
+ ht_cap->ht_cap.cap_info = cpu_to_le16(sband->ht_cap.cap);
+ ht_cap->ht_cap.extended_ht_cap_info = cpu_to_le16(ht_ext_cap);
+}
+
+/*
+ * This function returns the pointer to an entry in BA Stream
+ * table which matches the requested BA status.
+ */
+static struct mwifiex_tx_ba_stream_tbl *
+mwifiex_11n_get_tx_ba_stream_status(struct mwifiex_private *priv,
+ enum mwifiex_ba_status ba_status)
+{
+ struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+ list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
+ if (tx_ba_tsr_tbl->ba_status == ba_status) {
+ spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock,
+ flags);
+ return tx_ba_tsr_tbl;
+ }
+ }
+ spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
+ return NULL;
+}
+
+/*
+ * This function handles the command response of delete a block
+ * ack request.
+ *
+ * The function checks the response success status and takes action
+ * accordingly (send an add BA request in case of success, or recreate
+ * the deleted stream in case of failure, if the add BA was also
+ * initiated by us).
+ */
+int mwifiex_ret_11n_delba(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
+{
+ int tid;
+ struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl;
+ struct host_cmd_ds_11n_delba *del_ba =
+ (struct host_cmd_ds_11n_delba *) &resp->params.del_ba;
+ uint16_t del_ba_param_set = le16_to_cpu(del_ba->del_ba_param_set);
+
+ tid = del_ba_param_set >> DELBA_TID_POS;
+ if (del_ba->del_result == BA_RESULT_SUCCESS) {
+ mwifiex_11n_delete_ba_stream_tbl(priv, tid,
+ del_ba->peer_mac_addr, TYPE_DELBA_SENT,
+ INITIATOR_BIT(del_ba_param_set));
+
+ tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_status(priv,
+ BA_STREAM_SETUP_INPROGRESS);
+ if (tx_ba_tbl)
+ mwifiex_send_addba(priv, tx_ba_tbl->tid,
+ tx_ba_tbl->ra);
+ } else { /*
+ * In case of failure, recreate the deleted stream in case
+ * we initiated the ADDBA
+ */
+ if (INITIATOR_BIT(del_ba_param_set)) {
+ mwifiex_11n_create_tx_ba_stream_tbl(priv,
+ del_ba->peer_mac_addr, tid,
+ BA_STREAM_SETUP_INPROGRESS);
+
+ tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_status(priv,
+ BA_STREAM_SETUP_INPROGRESS);
+ if (tx_ba_tbl)
+ mwifiex_11n_delete_ba_stream_tbl(priv,
+ tx_ba_tbl->tid, tx_ba_tbl->ra,
+ TYPE_DELBA_SENT, true);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * This function handles the command response of add a block
+ * ack request.
+ *
+ * Handling includes changing the header fields to CPU formats, checking
+ * the response success status and taking actions accordingly (delete the
+ * BA stream table in case of failure).
+ */
+int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
+{
+ int tid;
+ struct host_cmd_ds_11n_addba_rsp *add_ba_rsp =
+ (struct host_cmd_ds_11n_addba_rsp *) &resp->params.add_ba_rsp;
+ struct mwifiex_tx_ba_stream_tbl *tx_ba_tbl;
+
+ add_ba_rsp->ssn = cpu_to_le16((le16_to_cpu(add_ba_rsp->ssn))
+ & SSN_MASK);
+
+ tid = (le16_to_cpu(add_ba_rsp->block_ack_param_set)
+ & IEEE80211_ADDBA_PARAM_TID_MASK)
+ >> BLOCKACKPARAM_TID_POS;
+ if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) {
+ tx_ba_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid,
+ add_ba_rsp->peer_mac_addr);
+ if (tx_ba_tbl) {
+ dev_dbg(priv->adapter->dev, "info: BA stream complete\n");
+ tx_ba_tbl->ba_status = BA_STREAM_SETUP_COMPLETE;
+ } else {
+ dev_err(priv->adapter->dev, "BA stream not created\n");
+ }
+ } else {
+ mwifiex_11n_delete_ba_stream_tbl(priv, tid,
+ add_ba_rsp->peer_mac_addr,
+ TYPE_DELBA_SENT, true);
+ if (add_ba_rsp->add_rsp_result != BA_RESULT_TIMEOUT)
+ priv->aggr_prio_tbl[tid].ampdu_ap =
+ BA_STREAM_NOT_ALLOWED;
+ }
+
+ return 0;
+}
+
+/*
+ * This function handles the command response of 11n configuration request.
+ *
+ * Handling includes changing the header fields into CPU format.
+ */
+int mwifiex_ret_11n_cfg(struct host_cmd_ds_command *resp, void *data_buf)
+{
+ struct mwifiex_ds_11n_tx_cfg *tx_cfg;
+ struct host_cmd_ds_11n_cfg *htcfg = &resp->params.htcfg;
+
+ if (data_buf) {
+ tx_cfg = (struct mwifiex_ds_11n_tx_cfg *) data_buf;
+ tx_cfg->tx_htcap = le16_to_cpu(htcfg->ht_tx_cap);
+ tx_cfg->tx_htinfo = le16_to_cpu(htcfg->ht_tx_info);
+ }
+ return 0;
+}
+
+/*
+ * This function prepares command of reconfigure Tx buffer.
+ *
+ * Preparation includes -
+ * - Setting command ID, action and proper size
+ * - Setting Tx buffer size (for SET only)
+ * - Ensuring correct endian-ness
+ */
+int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd, int cmd_action,
+ void *data_buf)
+{
+ struct host_cmd_ds_txbuf_cfg *tx_buf = &cmd->params.tx_buf;
+ u16 action = (u16) cmd_action;
+ u16 buf_size = *((u16 *) data_buf);
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_RECONFIGURE_TX_BUFF);
+ cmd->size =
+ cpu_to_le16(sizeof(struct host_cmd_ds_txbuf_cfg) + S_DS_GEN);
+ tx_buf->action = cpu_to_le16(action);
+ switch (action) {
+ case HostCmd_ACT_GEN_SET:
+ dev_dbg(priv->adapter->dev, "cmd: set tx_buf=%d\n", buf_size);
+ tx_buf->buff_size = cpu_to_le16(buf_size);
+ break;
+ case HostCmd_ACT_GEN_GET:
+ default:
+ tx_buf->buff_size = 0;
+ break;
+ }
+ return 0;
+}
+
+/*
+ * This function prepares command of AMSDU aggregation control.
+ *
+ * Preparation includes -
+ * - Setting command ID, action and proper size
+ * - Setting AMSDU control parameters (for SET only)
+ * - Ensuring correct endian-ness
+ */
+int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd,
+ int cmd_action, void *data_buf)
+{
+ struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl =
+ &cmd->params.amsdu_aggr_ctrl;
+ u16 action = (u16) cmd_action;
+ struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl =
+ (struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_AMSDU_AGGR_CTRL);
+ cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_amsdu_aggr_ctrl)
+ + S_DS_GEN);
+ amsdu_ctrl->action = cpu_to_le16(action);
+ switch (action) {
+ case HostCmd_ACT_GEN_SET:
+ amsdu_ctrl->enable = cpu_to_le16(aa_ctrl->enable);
+ amsdu_ctrl->curr_buf_size = 0;
+ break;
+ case HostCmd_ACT_GEN_GET:
+ default:
+ amsdu_ctrl->curr_buf_size = 0;
+ break;
+ }
+ return 0;
+}
+
+/*
+ * This function handles the command response of AMSDU aggregation
+ * control request.
+ *
+ * Handling includes changing the header fields into CPU format.
+ */
+int mwifiex_ret_amsdu_aggr_ctrl(struct host_cmd_ds_command *resp,
+ void *data_buf)
+{
+ struct mwifiex_ds_11n_amsdu_aggr_ctrl *amsdu_aggr_ctrl;
+ struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl =
+ &resp->params.amsdu_aggr_ctrl;
+
+ if (data_buf) {
+ amsdu_aggr_ctrl =
+ (struct mwifiex_ds_11n_amsdu_aggr_ctrl *) data_buf;
+ amsdu_aggr_ctrl->enable = le16_to_cpu(amsdu_ctrl->enable);
+ amsdu_aggr_ctrl->curr_buf_size =
+ le16_to_cpu(amsdu_ctrl->curr_buf_size);
+ }
+ return 0;
+}
+
+/*
+ * This function prepares 11n configuration command.
+ *
+ * Preparation includes -
+ * - Setting command ID, action and proper size
+ * - Setting HT Tx capability and HT Tx information fields
+ * - Ensuring correct endian-ness
+ */
+int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd,
+ u16 cmd_action, void *data_buf)
+{
+ struct host_cmd_ds_11n_cfg *htcfg = &cmd->params.htcfg;
+ struct mwifiex_ds_11n_tx_cfg *txcfg =
+ (struct mwifiex_ds_11n_tx_cfg *) data_buf;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_11N_CFG);
+ cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_11n_cfg) + S_DS_GEN);
+ htcfg->action = cpu_to_le16(cmd_action);
+ htcfg->ht_tx_cap = cpu_to_le16(txcfg->tx_htcap);
+ htcfg->ht_tx_info = cpu_to_le16(txcfg->tx_htinfo);
+ return 0;
+}
+
+/*
+ * This function appends an 11n TLV to a buffer.
+ *
+ * Buffer allocation is responsibility of the calling
+ * function. No size validation is made here.
+ *
+ * The function fills up the following sections, if applicable -
+ * - HT capability IE
+ * - HT information IE (with channel list)
+ * - 20/40 BSS Coexistence IE
+ * - HT Extended Capabilities IE
+ */
+int
+mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
+ struct mwifiex_bssdescriptor *bss_desc,
+ u8 **buffer)
+{
+ struct mwifiex_ie_types_htcap *ht_cap;
+ struct mwifiex_ie_types_htinfo *ht_info;
+ struct mwifiex_ie_types_chan_list_param_set *chan_list;
+ struct mwifiex_ie_types_2040bssco *bss_co_2040;
+ struct mwifiex_ie_types_extcap *ext_cap;
+ int ret_len = 0;
+ struct ieee80211_supported_band *sband;
+ u8 radio_type;
+
+ if (!buffer || !*buffer)
+ return ret_len;
+
+ radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
+ sband = priv->wdev->wiphy->bands[radio_type];
+
+ if (bss_desc->bcn_ht_cap) {
+ ht_cap = (struct mwifiex_ie_types_htcap *) *buffer;
+ memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap));
+ ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY);
+ ht_cap->header.len =
+ cpu_to_le16(sizeof(struct ieee80211_ht_cap));
+ memcpy((u8 *) ht_cap + sizeof(struct mwifiex_ie_types_header),
+ (u8 *) bss_desc->bcn_ht_cap +
+ sizeof(struct ieee_types_header),
+ le16_to_cpu(ht_cap->header.len));
+
+ mwifiex_fill_cap_info(priv, radio_type, ht_cap);
+
+ *buffer += sizeof(struct mwifiex_ie_types_htcap);
+ ret_len += sizeof(struct mwifiex_ie_types_htcap);
+ }
+
+ if (bss_desc->bcn_ht_info) {
+ if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
+ ht_info = (struct mwifiex_ie_types_htinfo *) *buffer;
+ memset(ht_info, 0,
+ sizeof(struct mwifiex_ie_types_htinfo));
+ ht_info->header.type =
+ cpu_to_le16(WLAN_EID_HT_INFORMATION);
+ ht_info->header.len =
+ cpu_to_le16(sizeof(struct ieee80211_ht_info));
+
+ memcpy((u8 *) ht_info +
+ sizeof(struct mwifiex_ie_types_header),
+ (u8 *) bss_desc->bcn_ht_info +
+ sizeof(struct ieee_types_header),
+ le16_to_cpu(ht_info->header.len));
+
+ if (!(sband->ht_cap.cap &
+ IEEE80211_HT_CAP_SUP_WIDTH_20_40))
+ ht_info->ht_info.ht_param &=
+ ~(IEEE80211_HT_PARAM_CHAN_WIDTH_ANY |
+ IEEE80211_HT_PARAM_CHA_SEC_OFFSET);
+
+ *buffer += sizeof(struct mwifiex_ie_types_htinfo);
+ ret_len += sizeof(struct mwifiex_ie_types_htinfo);
+ }
+
+ chan_list =
+ (struct mwifiex_ie_types_chan_list_param_set *) *buffer;
+ memset(chan_list, 0,
+ sizeof(struct mwifiex_ie_types_chan_list_param_set));
+ chan_list->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
+ chan_list->header.len = cpu_to_le16(
+ sizeof(struct mwifiex_ie_types_chan_list_param_set) -
+ sizeof(struct mwifiex_ie_types_header));
+ chan_list->chan_scan_param[0].chan_number =
+ bss_desc->bcn_ht_info->control_chan;
+ chan_list->chan_scan_param[0].radio_type =
+ mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
+
+ if ((sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
+ && (bss_desc->bcn_ht_info->ht_param &
+ IEEE80211_HT_PARAM_CHAN_WIDTH_ANY))
+ SET_SECONDARYCHAN(chan_list->chan_scan_param[0].
+ radio_type,
+ (bss_desc->bcn_ht_info->ht_param &
+ IEEE80211_HT_PARAM_CHA_SEC_OFFSET));
+
+ *buffer += sizeof(struct mwifiex_ie_types_chan_list_param_set);
+ ret_len += sizeof(struct mwifiex_ie_types_chan_list_param_set);
+ }
+
+ if (bss_desc->bcn_bss_co_2040) {
+ bss_co_2040 = (struct mwifiex_ie_types_2040bssco *) *buffer;
+ memset(bss_co_2040, 0,
+ sizeof(struct mwifiex_ie_types_2040bssco));
+ bss_co_2040->header.type = cpu_to_le16(WLAN_EID_BSS_COEX_2040);
+ bss_co_2040->header.len =
+ cpu_to_le16(sizeof(bss_co_2040->bss_co_2040));
+
+ memcpy((u8 *) bss_co_2040 +
+ sizeof(struct mwifiex_ie_types_header),
+ (u8 *) bss_desc->bcn_bss_co_2040 +
+ sizeof(struct ieee_types_header),
+ le16_to_cpu(bss_co_2040->header.len));
+
+ *buffer += sizeof(struct mwifiex_ie_types_2040bssco);
+ ret_len += sizeof(struct mwifiex_ie_types_2040bssco);
+ }
+
+ if (bss_desc->bcn_ext_cap) {
+ ext_cap = (struct mwifiex_ie_types_extcap *) *buffer;
+ memset(ext_cap, 0, sizeof(struct mwifiex_ie_types_extcap));
+ ext_cap->header.type = cpu_to_le16(WLAN_EID_EXT_CAPABILITY);
+ ext_cap->header.len = cpu_to_le16(sizeof(ext_cap->ext_cap));
+
+ memcpy((u8 *) ext_cap +
+ sizeof(struct mwifiex_ie_types_header),
+ (u8 *) bss_desc->bcn_ext_cap +
+ sizeof(struct ieee_types_header),
+ le16_to_cpu(ext_cap->header.len));
+
+ *buffer += sizeof(struct mwifiex_ie_types_extcap);
+ ret_len += sizeof(struct mwifiex_ie_types_extcap);
+ }
+
+ return ret_len;
+}
+
+/*
+ * This function reconfigures the Tx buffer size in firmware.
+ *
+ * This function prepares a firmware command and issues it, if
+ * the current Tx buffer size is different from the one requested.
+ * Maximum configurable Tx buffer size is limited by the HT capability
+ * field value.
+ */
+void
+mwifiex_cfg_tx_buf(struct mwifiex_private *priv,
+ struct mwifiex_bssdescriptor *bss_desc)
+{
+ u16 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_2K;
+ u16 tx_buf, curr_tx_buf_size = 0;
+
+ if (bss_desc->bcn_ht_cap) {
+ if (le16_to_cpu(bss_desc->bcn_ht_cap->cap_info) &
+ IEEE80211_HT_CAP_MAX_AMSDU)
+ max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_8K;
+ else
+ max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_4K;
+ }
+
+ tx_buf = min(priv->adapter->max_tx_buf_size, max_amsdu);
+
+ dev_dbg(priv->adapter->dev, "info: max_amsdu=%d, max_tx_buf=%d\n",
+ max_amsdu, priv->adapter->max_tx_buf_size);
+
+ if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_2K)
+ curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
+ else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_4K)
+ curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K;
+ else if (priv->adapter->curr_tx_buf_size <= MWIFIEX_TX_DATA_BUF_SIZE_8K)
+ curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_8K;
+ if (curr_tx_buf_size != tx_buf)
+ mwifiex_send_cmd_async(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF,
+ HostCmd_ACT_GEN_SET, 0, &tx_buf);
+}
+
+/*
+ * This function checks if the given pointer is valid entry of
+ * Tx BA Stream table.
+ */
+static int mwifiex_is_tx_ba_stream_ptr_valid(struct mwifiex_private *priv,
+ struct mwifiex_tx_ba_stream_tbl *tx_tbl_ptr)
+{
+ struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
+
+ list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
+ if (tx_ba_tsr_tbl == tx_tbl_ptr)
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * This function deletes the given entry in Tx BA Stream table.
+ *
+ * The function also performs a validity check on the supplied
+ * pointer before trying to delete.
+ */
+void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv,
+ struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl)
+{
+ if (!tx_ba_tsr_tbl &&
+ mwifiex_is_tx_ba_stream_ptr_valid(priv, tx_ba_tsr_tbl))
+ return;
+
+ dev_dbg(priv->adapter->dev, "info: tx_ba_tsr_tbl %p\n", tx_ba_tsr_tbl);
+
+ list_del(&tx_ba_tsr_tbl->list);
+
+ kfree(tx_ba_tsr_tbl);
+}
+
+/*
+ * This function deletes all the entries in Tx BA Stream table.
+ */
+void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv)
+{
+ int i;
+ struct mwifiex_tx_ba_stream_tbl *del_tbl_ptr, *tmp_node;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+ list_for_each_entry_safe(del_tbl_ptr, tmp_node,
+ &priv->tx_ba_stream_tbl_ptr, list)
+ mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, del_tbl_ptr);
+ spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
+
+ INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr);
+
+ for (i = 0; i < MAX_NUM_TID; ++i)
+ priv->aggr_prio_tbl[i].ampdu_ap =
+ priv->aggr_prio_tbl[i].ampdu_user;
+}
+
+/*
+ * This function returns the pointer to an entry in BA Stream
+ * table which matches the given RA/TID pair.
+ */
+struct mwifiex_tx_ba_stream_tbl *
+mwifiex_11n_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
+ int tid, u8 *ra)
+{
+ struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+ list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
+ if ((!memcmp(tx_ba_tsr_tbl->ra, ra, ETH_ALEN))
+ && (tx_ba_tsr_tbl->tid == tid)) {
+ spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock,
+ flags);
+ return tx_ba_tsr_tbl;
+ }
+ }
+ spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
+ return NULL;
+}
+
+/*
+ * This function creates an entry in Tx BA stream table for the
+ * given RA/TID pair.
+ */
+void mwifiex_11n_create_tx_ba_stream_tbl(struct mwifiex_private *priv,
+ u8 *ra, int tid,
+ enum mwifiex_ba_status ba_status)
+{
+ struct mwifiex_tx_ba_stream_tbl *new_node;
+ unsigned long flags;
+
+ if (!mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, ra)) {
+ new_node = kzalloc(sizeof(struct mwifiex_tx_ba_stream_tbl),
+ GFP_ATOMIC);
+ if (!new_node) {
+ dev_err(priv->adapter->dev,
+ "%s: failed to alloc new_node\n", __func__);
+ return;
+ }
+
+ INIT_LIST_HEAD(&new_node->list);
+
+ new_node->tid = tid;
+ new_node->ba_status = ba_status;
+ memcpy(new_node->ra, ra, ETH_ALEN);
+
+ spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+ list_add_tail(&new_node->list, &priv->tx_ba_stream_tbl_ptr);
+ spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
+ }
+}
+
+/*
+ * This function sends an add BA request to the given TID/RA pair.
+ */
+int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac)
+{
+ struct host_cmd_ds_11n_addba_req add_ba_req;
+ static u8 dialog_tok;
+ int ret;
+
+ dev_dbg(priv->adapter->dev, "cmd: %s: tid %d\n", __func__, tid);
+
+ add_ba_req.block_ack_param_set = cpu_to_le16(
+ (u16) ((tid << BLOCKACKPARAM_TID_POS) |
+ (priv->add_ba_param.
+ tx_win_size << BLOCKACKPARAM_WINSIZE_POS) |
+ IMMEDIATE_BLOCK_ACK));
+ add_ba_req.block_ack_tmo = cpu_to_le16((u16)priv->add_ba_param.timeout);
+
+ ++dialog_tok;
+
+ if (dialog_tok == 0)
+ dialog_tok = 1;
+
+ add_ba_req.dialog_token = dialog_tok;
+ memcpy(&add_ba_req.peer_mac_addr, peer_mac, ETH_ALEN);
+
+ /* We don't wait for the response of this command */
+ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_REQ,
+ 0, 0, &add_ba_req);
+
+ return ret;
+}
+
+/*
+ * This function sends a delete BA request to the given TID/RA pair.
+ */
+int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac,
+ int initiator)
+{
+ struct host_cmd_ds_11n_delba delba;
+ int ret;
+ uint16_t del_ba_param_set;
+
+ memset(&delba, 0, sizeof(delba));
+ delba.del_ba_param_set = cpu_to_le16(tid << DELBA_TID_POS);
+
+ del_ba_param_set = le16_to_cpu(delba.del_ba_param_set);
+ if (initiator)
+ del_ba_param_set |= IEEE80211_DELBA_PARAM_INITIATOR_MASK;
+ else
+ del_ba_param_set &= ~IEEE80211_DELBA_PARAM_INITIATOR_MASK;
+
+ memcpy(&delba.peer_mac_addr, peer_mac, ETH_ALEN);
+
+ /* We don't wait for the response of this command */
+ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA,
+ HostCmd_ACT_GEN_SET, 0, &delba);
+
+ return ret;
+}
+
+/*
+ * This function handles the command response of a delete BA request.
+ */
+void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba)
+{
+ struct host_cmd_ds_11n_delba *cmd_del_ba =
+ (struct host_cmd_ds_11n_delba *) del_ba;
+ uint16_t del_ba_param_set = le16_to_cpu(cmd_del_ba->del_ba_param_set);
+ int tid;
+
+ tid = del_ba_param_set >> DELBA_TID_POS;
+
+ mwifiex_11n_delete_ba_stream_tbl(priv, tid, cmd_del_ba->peer_mac_addr,
+ TYPE_DELBA_RECEIVE,
+ INITIATOR_BIT(del_ba_param_set));
+}
+
+/*
+ * This function retrieves the Rx reordering table.
+ */
+int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv,
+ struct mwifiex_ds_rx_reorder_tbl *buf)
+{
+ int i;
+ struct mwifiex_ds_rx_reorder_tbl *rx_reo_tbl = buf;
+ struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr;
+ int count = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+ list_for_each_entry(rx_reorder_tbl_ptr, &priv->rx_reorder_tbl_ptr,
+ list) {
+ rx_reo_tbl->tid = (u16) rx_reorder_tbl_ptr->tid;
+ memcpy(rx_reo_tbl->ta, rx_reorder_tbl_ptr->ta, ETH_ALEN);
+ rx_reo_tbl->start_win = rx_reorder_tbl_ptr->start_win;
+ rx_reo_tbl->win_size = rx_reorder_tbl_ptr->win_size;
+ for (i = 0; i < rx_reorder_tbl_ptr->win_size; ++i) {
+ if (rx_reorder_tbl_ptr->rx_reorder_ptr[i])
+ rx_reo_tbl->buffer[i] = true;
+ else
+ rx_reo_tbl->buffer[i] = false;
+ }
+ rx_reo_tbl++;
+ count++;
+
+ if (count >= MWIFIEX_MAX_RX_BASTREAM_SUPPORTED)
+ break;
+ }
+ spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+
+ return count;
+}
+
+/*
+ * This function retrieves the Tx BA stream table.
+ */
+int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
+ struct mwifiex_ds_tx_ba_stream_tbl *buf)
+{
+ struct mwifiex_tx_ba_stream_tbl *tx_ba_tsr_tbl;
+ struct mwifiex_ds_tx_ba_stream_tbl *rx_reo_tbl = buf;
+ int count = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+ list_for_each_entry(tx_ba_tsr_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
+ rx_reo_tbl->tid = (u16) tx_ba_tsr_tbl->tid;
+ dev_dbg(priv->adapter->dev, "data: %s tid=%d\n",
+ __func__, rx_reo_tbl->tid);
+ memcpy(rx_reo_tbl->ra, tx_ba_tsr_tbl->ra, ETH_ALEN);
+ rx_reo_tbl++;
+ count++;
+ if (count >= MWIFIEX_MAX_TX_BASTREAM_SUPPORTED)
+ break;
+ }
+ spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
+
+ return count;
+}
diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h
new file mode 100644
index 000000000000..a4390a1a2a9f
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11n.h
@@ -0,0 +1,161 @@
+/*
+ * Marvell Wireless LAN device driver: 802.11n
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef _MWIFIEX_11N_H_
+#define _MWIFIEX_11N_H_
+
+#include "11n_aggr.h"
+#include "11n_rxreorder.h"
+#include "wmm.h"
+
+int mwifiex_ret_11n_delba(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp);
+int mwifiex_ret_11n_addba_req(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp);
+int mwifiex_ret_11n_cfg(struct host_cmd_ds_command *resp,
+ void *data_buf);
+int mwifiex_cmd_11n_cfg(struct host_cmd_ds_command *cmd,
+ u16 cmd_action, void *data_buf);
+
+int mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
+ struct mwifiex_bssdescriptor *bss_desc,
+ u8 **buffer);
+void mwifiex_cfg_tx_buf(struct mwifiex_private *priv,
+ struct mwifiex_bssdescriptor *bss_desc);
+void mwifiex_fill_cap_info(struct mwifiex_private *, u8 radio_type,
+ struct mwifiex_ie_types_htcap *);
+int mwifiex_set_get_11n_htcap_cfg(struct mwifiex_private *priv,
+ u16 action, int *htcap_cfg);
+void mwifiex_11n_delete_tx_ba_stream_tbl_entry(struct mwifiex_private *priv,
+ struct mwifiex_tx_ba_stream_tbl
+ *tx_tbl);
+void mwifiex_11n_delete_all_tx_ba_stream_tbl(struct mwifiex_private *priv);
+struct mwifiex_tx_ba_stream_tbl *mwifiex_11n_get_tx_ba_stream_tbl(struct
+ mwifiex_private
+ *priv, int tid,
+ u8 *ra);
+void mwifiex_11n_create_tx_ba_stream_tbl(struct mwifiex_private *priv, u8 *ra,
+ int tid,
+ enum mwifiex_ba_status ba_status);
+int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac);
+int mwifiex_send_delba(struct mwifiex_private *priv, int tid, u8 *peer_mac,
+ int initiator);
+void mwifiex_11n_delete_ba_stream(struct mwifiex_private *priv, u8 *del_ba);
+int mwifiex_get_rx_reorder_tbl(struct mwifiex_private *priv,
+ struct mwifiex_ds_rx_reorder_tbl *buf);
+int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
+ struct mwifiex_ds_tx_ba_stream_tbl *buf);
+int mwifiex_ret_amsdu_aggr_ctrl(struct host_cmd_ds_command *resp,
+ void *data_buf);
+int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ int cmd_action, void *data_buf);
+int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd,
+ int cmd_action, void *data_buf);
+
+/*
+ * This function checks whether AMPDU is allowed or not for a particular TID.
+ */
+static inline u8
+mwifiex_is_ampdu_allowed(struct mwifiex_private *priv, int tid)
+{
+ return ((priv->aggr_prio_tbl[tid].ampdu_ap != BA_STREAM_NOT_ALLOWED)
+ ? true : false);
+}
+
+/*
+ * This function checks whether AMSDU is allowed or not for a particular TID.
+ */
+static inline u8
+mwifiex_is_amsdu_allowed(struct mwifiex_private *priv, int tid)
+{
+ return (((priv->aggr_prio_tbl[tid].amsdu != BA_STREAM_NOT_ALLOWED)
+ && ((priv->is_data_rate_auto)
+ || !((priv->bitmap_rates[2]) & 0x03)))
+ ? true : false);
+}
+
+/*
+ * This function checks whether a space is available for new BA stream or not.
+ */
+static inline u8 mwifiex_space_avail_for_new_ba_stream(
+ struct mwifiex_adapter *adapter)
+{
+ struct mwifiex_private *priv;
+ u8 i;
+ u32 ba_stream_num = 0;
+
+ for (i = 0; i < adapter->priv_num; i++) {
+ priv = adapter->priv[i];
+ if (priv)
+ ba_stream_num += mwifiex_wmm_list_len(
+ (struct list_head *)
+ &priv->tx_ba_stream_tbl_ptr);
+ }
+
+ return ((ba_stream_num <
+ MWIFIEX_MAX_TX_BASTREAM_SUPPORTED) ? true : false);
+}
+
+/*
+ * This function finds the correct Tx BA stream to delete.
+ *
+ * Upon successfully locating, both the TID and the RA are returned.
+ */
+static inline u8
+mwifiex_find_stream_to_delete(struct mwifiex_private *priv, int ptr_tid,
+ int *ptid, u8 *ra)
+{
+ int tid;
+ u8 ret = false;
+ struct mwifiex_tx_ba_stream_tbl *tx_tbl;
+ unsigned long flags;
+
+ tid = priv->aggr_prio_tbl[ptr_tid].ampdu_user;
+
+ spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+ list_for_each_entry(tx_tbl, &priv->tx_ba_stream_tbl_ptr, list) {
+ if (tid > priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user) {
+ tid = priv->aggr_prio_tbl[tx_tbl->tid].ampdu_user;
+ *ptid = tx_tbl->tid;
+ memcpy(ra, tx_tbl->ra, ETH_ALEN);
+ ret = true;
+ }
+ }
+ spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
+
+ return ret;
+}
+
+/*
+ * This function checks whether BA stream is set up or not.
+ */
+static inline int
+mwifiex_is_ba_stream_setup(struct mwifiex_private *priv,
+ struct mwifiex_ra_list_tbl *ptr, int tid)
+{
+ struct mwifiex_tx_ba_stream_tbl *tx_tbl;
+
+ tx_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, ptr->ra);
+ if (tx_tbl && IS_BASTREAM_SETUP(tx_tbl))
+ return true;
+
+ return false;
+}
+#endif /* !_MWIFIEX_11N_H_ */
diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c
new file mode 100644
index 000000000000..f807447e4d99
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11n_aggr.c
@@ -0,0 +1,302 @@
+/*
+ * Marvell Wireless LAN device driver: 802.11n Aggregation
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+#include "11n_aggr.h"
+
+/*
+ * Creates an AMSDU subframe for aggregation into one AMSDU packet.
+ *
+ * The resultant AMSDU subframe format is -
+ *
+ * +---- ~ -----+---- ~ ------+---- ~ -----+----- ~ -----+---- ~ -----+
+ * | DA | SA | Length | SNAP header | MSDU |
+ * | data[0..5] | data[6..11] | | | data[14..] |
+ * +---- ~ -----+---- ~ ------+---- ~ -----+----- ~ -----+---- ~ -----+
+ * <--6-bytes--> <--6-bytes--> <--2-bytes--><--8-bytes--> <--n-bytes-->
+ *
+ * This function also computes the amount of padding required to make the
+ * buffer length multiple of 4 bytes.
+ *
+ * Data => |DA|SA|SNAP-TYPE|........ .|
+ * MSDU => |DA|SA|Length|SNAP|...... ..|
+ */
+static int
+mwifiex_11n_form_amsdu_pkt(struct sk_buff *skb_aggr,
+ struct sk_buff *skb_src, int *pad)
+
+{
+ int dt_offset;
+ struct rfc_1042_hdr snap = {
+ 0xaa, /* LLC DSAP */
+ 0xaa, /* LLC SSAP */
+ 0x03, /* LLC CTRL */
+ {0x00, 0x00, 0x00}, /* SNAP OUI */
+ 0x0000 /* SNAP type */
+ /*
+ * This field will be overwritten
+ * later with ethertype
+ */
+ };
+ struct tx_packet_hdr *tx_header;
+
+ skb_put(skb_aggr, sizeof(*tx_header));
+
+ tx_header = (struct tx_packet_hdr *) skb_aggr->data;
+
+ /* Copy DA and SA */
+ dt_offset = 2 * ETH_ALEN;
+ memcpy(&tx_header->eth803_hdr, skb_src->data, dt_offset);
+
+ /* Copy SNAP header */
+ snap.snap_type = *(u16 *) ((u8 *)skb_src->data + dt_offset);
+ dt_offset += sizeof(u16);
+
+ memcpy(&tx_header->rfc1042_hdr, &snap, sizeof(struct rfc_1042_hdr));
+
+ skb_pull(skb_src, dt_offset);
+
+ /* Update Length field */
+ tx_header->eth803_hdr.h_proto = htons(skb_src->len + LLC_SNAP_LEN);
+
+ /* Add payload */
+ skb_put(skb_aggr, skb_src->len);
+ memcpy(skb_aggr->data + sizeof(*tx_header), skb_src->data,
+ skb_src->len);
+ *pad = (((skb_src->len + LLC_SNAP_LEN) & 3)) ? (4 - (((skb_src->len +
+ LLC_SNAP_LEN)) & 3)) : 0;
+ skb_put(skb_aggr, *pad);
+
+ return skb_aggr->len + *pad;
+}
+
+/*
+ * Adds TxPD to AMSDU header.
+ *
+ * Each AMSDU packet will contain one TxPD at the beginning,
+ * followed by multiple AMSDU subframes.
+ */
+static void
+mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv,
+ struct sk_buff *skb)
+{
+ struct txpd *local_tx_pd;
+
+ skb_push(skb, sizeof(*local_tx_pd));
+
+ local_tx_pd = (struct txpd *) skb->data;
+ memset(local_tx_pd, 0, sizeof(struct txpd));
+
+ /* Original priority has been overwritten */
+ local_tx_pd->priority = (u8) skb->priority;
+ local_tx_pd->pkt_delay_2ms =
+ mwifiex_wmm_compute_drv_pkt_delay(priv, skb);
+ local_tx_pd->bss_num = priv->bss_num;
+ local_tx_pd->bss_type = priv->bss_type;
+ /* Always zero as the data is followed by struct txpd */
+ local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd));
+ local_tx_pd->tx_pkt_type = cpu_to_le16(PKT_TYPE_AMSDU);
+ local_tx_pd->tx_pkt_length = cpu_to_le16(skb->len -
+ sizeof(*local_tx_pd));
+
+ if (local_tx_pd->tx_control == 0)
+ /* TxCtrl set by user or default */
+ local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl);
+
+ if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
+ (priv->adapter->pps_uapsd_mode)) {
+ if (true == mwifiex_check_last_packet_indication(priv)) {
+ priv->adapter->tx_lock_flag = true;
+ local_tx_pd->flags =
+ MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET;
+ }
+ }
+}
+
+/*
+ * Create aggregated packet.
+ *
+ * This function creates an aggregated MSDU packet, by combining buffers
+ * from the RA list. Each individual buffer is encapsulated as an AMSDU
+ * subframe and all such subframes are concatenated together to form the
+ * AMSDU packet.
+ *
+ * A TxPD is also added to the front of the resultant AMSDU packets for
+ * transmission. The resultant packets format is -
+ *
+ * +---- ~ ----+------ ~ ------+------ ~ ------+-..-+------ ~ ------+
+ * | TxPD |AMSDU sub-frame|AMSDU sub-frame| .. |AMSDU sub-frame|
+ * | | 1 | 2 | .. | n |
+ * +---- ~ ----+------ ~ ------+------ ~ ------+ .. +------ ~ ------+
+ */
+int
+mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
+ struct mwifiex_ra_list_tbl *pra_list, int headroom,
+ int ptrindex, unsigned long ra_list_flags)
+ __releases(&priv->wmm.ra_list_spinlock)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct sk_buff *skb_aggr, *skb_src;
+ struct mwifiex_txinfo *tx_info_aggr, *tx_info_src;
+ int pad = 0, ret;
+ struct mwifiex_tx_param tx_param;
+ struct txpd *ptx_pd = NULL;
+
+ if (skb_queue_empty(&pra_list->skb_head)) {
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+ ra_list_flags);
+ return 0;
+ }
+ skb_src = skb_peek(&pra_list->skb_head);
+ tx_info_src = MWIFIEX_SKB_TXCB(skb_src);
+ skb_aggr = dev_alloc_skb(adapter->tx_buf_size);
+ if (!skb_aggr) {
+ dev_err(adapter->dev, "%s: alloc skb_aggr\n", __func__);
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+ ra_list_flags);
+ return -1;
+ }
+ skb_reserve(skb_aggr, headroom + sizeof(struct txpd));
+ tx_info_aggr = MWIFIEX_SKB_TXCB(skb_aggr);
+
+ tx_info_aggr->bss_index = tx_info_src->bss_index;
+ skb_aggr->priority = skb_src->priority;
+
+ while (skb_src && ((skb_headroom(skb_aggr) + skb_src->len
+ + LLC_SNAP_LEN)
+ <= adapter->tx_buf_size)) {
+
+ if (!skb_queue_empty(&pra_list->skb_head))
+ skb_src = skb_dequeue(&pra_list->skb_head);
+ else
+ skb_src = NULL;
+
+ if (skb_src)
+ pra_list->total_pkts_size -= skb_src->len;
+
+ atomic_dec(&priv->wmm.tx_pkts_queued);
+
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+ ra_list_flags);
+ mwifiex_11n_form_amsdu_pkt(skb_aggr, skb_src, &pad);
+
+ mwifiex_write_data_complete(adapter, skb_src, 0);
+
+ spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
+
+ if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) {
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+ ra_list_flags);
+ return -1;
+ }
+
+ if (!skb_queue_empty(&pra_list->skb_head))
+ skb_src = skb_peek(&pra_list->skb_head);
+ else
+ skb_src = NULL;
+ }
+
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags);
+
+ /* Last AMSDU packet does not need padding */
+ skb_trim(skb_aggr, skb_aggr->len - pad);
+
+ /* Form AMSDU */
+ mwifiex_11n_form_amsdu_txpd(priv, skb_aggr);
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)
+ ptx_pd = (struct txpd *)skb_aggr->data;
+
+ skb_push(skb_aggr, headroom);
+
+ tx_param.next_pkt_len = ((pra_list->total_pkts_size) ?
+ (((pra_list->total_pkts_size) >
+ adapter->tx_buf_size) ? adapter->
+ tx_buf_size : pra_list->total_pkts_size +
+ LLC_SNAP_LEN + sizeof(struct txpd)) : 0);
+ ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
+ skb_aggr->data,
+ skb_aggr->len, &tx_param);
+ switch (ret) {
+ case -EBUSY:
+ spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
+ if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) {
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+ ra_list_flags);
+ mwifiex_write_data_complete(adapter, skb_aggr, -1);
+ return -1;
+ }
+ if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
+ (adapter->pps_uapsd_mode) &&
+ (adapter->tx_lock_flag)) {
+ priv->adapter->tx_lock_flag = false;
+ if (ptx_pd)
+ ptx_pd->flags = 0;
+ }
+
+ skb_queue_tail(&pra_list->skb_head, skb_aggr);
+
+ pra_list->total_pkts_size += skb_aggr->len;
+
+ atomic_inc(&priv->wmm.tx_pkts_queued);
+
+ tx_info_aggr->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+ ra_list_flags);
+ dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
+ break;
+ case -1:
+ adapter->data_sent = false;
+ dev_err(adapter->dev, "%s: host_to_card failed: %#x\n",
+ __func__, ret);
+ adapter->dbg.num_tx_host_to_card_failure++;
+ mwifiex_write_data_complete(adapter, skb_aggr, ret);
+ return 0;
+ case -EINPROGRESS:
+ adapter->data_sent = false;
+ break;
+ case 0:
+ mwifiex_write_data_complete(adapter, skb_aggr, ret);
+ break;
+ default:
+ break;
+ }
+ if (ret != -EBUSY) {
+ spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
+ if (mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) {
+ priv->wmm.packets_out[ptrindex]++;
+ priv->wmm.tid_tbl_ptr[ptrindex].ra_list_curr = pra_list;
+ }
+ /* Now bss_prio_cur pointer points to next node */
+ adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur =
+ list_first_entry(
+ &adapter->bss_prio_tbl[priv->bss_priority]
+ .bss_prio_cur->list,
+ struct mwifiex_bss_prio_node, list);
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+ ra_list_flags);
+ }
+
+ return 0;
+}
diff --git a/drivers/net/wireless/mwifiex/11n_aggr.h b/drivers/net/wireless/mwifiex/11n_aggr.h
new file mode 100644
index 000000000000..9c6dca7ab02c
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11n_aggr.h
@@ -0,0 +1,32 @@
+/*
+ * Marvell Wireless LAN device driver: 802.11n Aggregation
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef _MWIFIEX_11N_AGGR_H_
+#define _MWIFIEX_11N_AGGR_H_
+
+#define PKT_TYPE_AMSDU 0xE6
+
+int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv,
+ struct sk_buff *skb);
+int mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
+ struct mwifiex_ra_list_tbl *ptr, int headroom,
+ int ptr_index, unsigned long flags)
+ __releases(&priv->wmm.ra_list_spinlock);
+
+#endif /* !_MWIFIEX_11N_AGGR_H_ */
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c
new file mode 100644
index 000000000000..e5dfdc39a921
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c
@@ -0,0 +1,616 @@
+/*
+ * Marvell Wireless LAN device driver: 802.11n RX Re-ordering
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+#include "11n_rxreorder.h"
+
+/*
+ * This function dispatches all packets in the Rx reorder table.
+ *
+ * There could be holes in the buffer, which are skipped by the function.
+ * Since the buffer is linear, the function uses rotation to simulate
+ * circular buffer.
+ */
+static int
+mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
+ struct mwifiex_rx_reorder_tbl
+ *rx_reor_tbl_ptr, int start_win)
+{
+ int no_pkt_to_send, i;
+ void *rx_tmp_ptr;
+ unsigned long flags;
+
+ no_pkt_to_send = (start_win > rx_reor_tbl_ptr->start_win) ?
+ min((start_win - rx_reor_tbl_ptr->start_win),
+ rx_reor_tbl_ptr->win_size) : rx_reor_tbl_ptr->win_size;
+
+ for (i = 0; i < no_pkt_to_send; ++i) {
+ spin_lock_irqsave(&priv->rx_pkt_lock, flags);
+ rx_tmp_ptr = NULL;
+ if (rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
+ rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
+ rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL;
+ }
+ spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
+ if (rx_tmp_ptr)
+ mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr);
+ }
+
+ spin_lock_irqsave(&priv->rx_pkt_lock, flags);
+ /*
+ * We don't have a circular buffer, hence use rotation to simulate
+ * circular buffer
+ */
+ for (i = 0; i < rx_reor_tbl_ptr->win_size - no_pkt_to_send; ++i) {
+ rx_reor_tbl_ptr->rx_reorder_ptr[i] =
+ rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i];
+ rx_reor_tbl_ptr->rx_reorder_ptr[no_pkt_to_send + i] = NULL;
+ }
+
+ rx_reor_tbl_ptr->start_win = start_win;
+ spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
+
+ return 0;
+}
+
+/*
+ * This function dispatches all packets in the Rx reorder table until
+ * a hole is found.
+ *
+ * The start window is adjusted automatically when a hole is located.
+ * Since the buffer is linear, the function uses rotation to simulate
+ * circular buffer.
+ */
+static int
+mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
+ struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr)
+{
+ int i, j, xchg;
+ void *rx_tmp_ptr;
+ unsigned long flags;
+
+ for (i = 0; i < rx_reor_tbl_ptr->win_size; ++i) {
+ spin_lock_irqsave(&priv->rx_pkt_lock, flags);
+ if (!rx_reor_tbl_ptr->rx_reorder_ptr[i]) {
+ spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
+ break;
+ }
+ rx_tmp_ptr = rx_reor_tbl_ptr->rx_reorder_ptr[i];
+ rx_reor_tbl_ptr->rx_reorder_ptr[i] = NULL;
+ spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
+ mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr);
+ }
+
+ spin_lock_irqsave(&priv->rx_pkt_lock, flags);
+ /*
+ * We don't have a circular buffer, hence use rotation to simulate
+ * circular buffer
+ */
+ if (i > 0) {
+ xchg = rx_reor_tbl_ptr->win_size - i;
+ for (j = 0; j < xchg; ++j) {
+ rx_reor_tbl_ptr->rx_reorder_ptr[j] =
+ rx_reor_tbl_ptr->rx_reorder_ptr[i + j];
+ rx_reor_tbl_ptr->rx_reorder_ptr[i + j] = NULL;
+ }
+ }
+ rx_reor_tbl_ptr->start_win = (rx_reor_tbl_ptr->start_win + i)
+ &(MAX_TID_VALUE - 1);
+ spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
+ return 0;
+}
+
+/*
+ * This function deletes the Rx reorder table and frees the memory.
+ *
+ * The function stops the associated timer and dispatches all the
+ * pending packets in the Rx reorder table before deletion.
+ */
+static void
+mwifiex_11n_delete_rx_reorder_tbl_entry(struct mwifiex_private *priv,
+ struct mwifiex_rx_reorder_tbl
+ *rx_reor_tbl_ptr)
+{
+ unsigned long flags;
+
+ if (!rx_reor_tbl_ptr)
+ return;
+
+ mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr,
+ (rx_reor_tbl_ptr->start_win +
+ rx_reor_tbl_ptr->win_size)
+ &(MAX_TID_VALUE - 1));
+
+ del_timer(&rx_reor_tbl_ptr->timer_context.timer);
+
+ spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+ list_del(&rx_reor_tbl_ptr->list);
+ spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+
+ kfree(rx_reor_tbl_ptr->rx_reorder_ptr);
+ kfree(rx_reor_tbl_ptr);
+}
+
+/*
+ * This function returns the pointer to an entry in Rx reordering
+ * table which matches the given TA/TID pair.
+ */
+static struct mwifiex_rx_reorder_tbl *
+mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta)
+{
+ struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+ list_for_each_entry(rx_reor_tbl_ptr, &priv->rx_reorder_tbl_ptr, list) {
+ if ((!memcmp(rx_reor_tbl_ptr->ta, ta, ETH_ALEN))
+ && (rx_reor_tbl_ptr->tid == tid)) {
+ spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
+ flags);
+ return rx_reor_tbl_ptr;
+ }
+ }
+ spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+
+ return NULL;
+}
+
+/*
+ * This function finds the last sequence number used in the packets
+ * buffered in Rx reordering table.
+ */
+static int
+mwifiex_11n_find_last_seq_num(struct mwifiex_rx_reorder_tbl *rx_reorder_tbl_ptr)
+{
+ int i;
+
+ for (i = (rx_reorder_tbl_ptr->win_size - 1); i >= 0; --i)
+ if (rx_reorder_tbl_ptr->rx_reorder_ptr[i])
+ return i;
+
+ return -1;
+}
+
+/*
+ * This function flushes all the packets in Rx reordering table.
+ *
+ * The function checks if any packets are currently buffered in the
+ * table or not. In case there are packets available, it dispatches
+ * them and then dumps the Rx reordering table.
+ */
+static void
+mwifiex_flush_data(unsigned long context)
+{
+ struct reorder_tmr_cnxt *reorder_cnxt =
+ (struct reorder_tmr_cnxt *) context;
+ int start_win;
+
+ start_win = mwifiex_11n_find_last_seq_num(reorder_cnxt->ptr);
+ if (start_win >= 0) {
+ dev_dbg(reorder_cnxt->priv->adapter->dev,
+ "info: flush data %d\n", start_win);
+ mwifiex_11n_dispatch_pkt_until_start_win(reorder_cnxt->priv,
+ reorder_cnxt->ptr,
+ ((reorder_cnxt->ptr->start_win +
+ start_win + 1) & (MAX_TID_VALUE - 1)));
+ }
+}
+
+/*
+ * This function creates an entry in Rx reordering table for the
+ * given TA/TID.
+ *
+ * The function also initializes the entry with sequence number, window
+ * size as well as initializes the timer.
+ *
+ * If the received TA/TID pair is already present, all the packets are
+ * dispatched and the window size is moved until the SSN.
+ */
+static void
+mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
+ int tid, int win_size, int seq_num)
+{
+ int i;
+ struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr, *new_node;
+ u16 last_seq = 0;
+ unsigned long flags;
+
+ /*
+ * If we get a TID, ta pair which is already present dispatch all the
+ * the packets and move the window size until the ssn
+ */
+ rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
+ if (rx_reor_tbl_ptr) {
+ mwifiex_11n_dispatch_pkt_until_start_win(priv, rx_reor_tbl_ptr,
+ seq_num);
+ return;
+ }
+ /* if !rx_reor_tbl_ptr then create one */
+ new_node = kzalloc(sizeof(struct mwifiex_rx_reorder_tbl), GFP_KERNEL);
+ if (!new_node) {
+ dev_err(priv->adapter->dev, "%s: failed to alloc new_node\n",
+ __func__);
+ return;
+ }
+
+ INIT_LIST_HEAD(&new_node->list);
+ new_node->tid = tid;
+ memcpy(new_node->ta, ta, ETH_ALEN);
+ new_node->start_win = seq_num;
+ if (mwifiex_queuing_ra_based(priv))
+ /* TODO for adhoc */
+ dev_dbg(priv->adapter->dev,
+ "info: ADHOC:last_seq=%d start_win=%d\n",
+ last_seq, new_node->start_win);
+ else
+ last_seq = priv->rx_seq[tid];
+
+ if (last_seq >= new_node->start_win)
+ new_node->start_win = last_seq + 1;
+
+ new_node->win_size = win_size;
+
+ new_node->rx_reorder_ptr = kzalloc(sizeof(void *) * win_size,
+ GFP_KERNEL);
+ if (!new_node->rx_reorder_ptr) {
+ kfree((u8 *) new_node);
+ dev_err(priv->adapter->dev,
+ "%s: failed to alloc reorder_ptr\n", __func__);
+ return;
+ }
+
+ new_node->timer_context.ptr = new_node;
+ new_node->timer_context.priv = priv;
+
+ init_timer(&new_node->timer_context.timer);
+ new_node->timer_context.timer.function = mwifiex_flush_data;
+ new_node->timer_context.timer.data =
+ (unsigned long) &new_node->timer_context;
+
+ for (i = 0; i < win_size; ++i)
+ new_node->rx_reorder_ptr[i] = NULL;
+
+ spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+ list_add_tail(&new_node->list, &priv->rx_reorder_tbl_ptr);
+ spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+}
+
+/*
+ * This function prepares command for adding a BA request.
+ *
+ * Preparation includes -
+ * - Setting command ID and proper size
+ * - Setting add BA request buffer
+ * - Ensuring correct endian-ness
+ */
+int mwifiex_cmd_11n_addba_req(struct host_cmd_ds_command *cmd, void *data_buf)
+{
+ struct host_cmd_ds_11n_addba_req *add_ba_req =
+ (struct host_cmd_ds_11n_addba_req *)
+ &cmd->params.add_ba_req;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_REQ);
+ cmd->size = cpu_to_le16(sizeof(*add_ba_req) + S_DS_GEN);
+ memcpy(add_ba_req, data_buf, sizeof(*add_ba_req));
+
+ return 0;
+}
+
+/*
+ * This function prepares command for adding a BA response.
+ *
+ * Preparation includes -
+ * - Setting command ID and proper size
+ * - Setting add BA response buffer
+ * - Ensuring correct endian-ness
+ */
+int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ void *data_buf)
+{
+ struct host_cmd_ds_11n_addba_rsp *add_ba_rsp =
+ (struct host_cmd_ds_11n_addba_rsp *)
+ &cmd->params.add_ba_rsp;
+ struct host_cmd_ds_11n_addba_req *cmd_addba_req =
+ (struct host_cmd_ds_11n_addba_req *) data_buf;
+ u8 tid;
+ int win_size;
+ uint16_t block_ack_param_set;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP);
+ cmd->size = cpu_to_le16(sizeof(*add_ba_rsp) + S_DS_GEN);
+
+ memcpy(add_ba_rsp->peer_mac_addr, cmd_addba_req->peer_mac_addr,
+ ETH_ALEN);
+ add_ba_rsp->dialog_token = cmd_addba_req->dialog_token;
+ add_ba_rsp->block_ack_tmo = cmd_addba_req->block_ack_tmo;
+ add_ba_rsp->ssn = cmd_addba_req->ssn;
+
+ block_ack_param_set = le16_to_cpu(cmd_addba_req->block_ack_param_set);
+ tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
+ >> BLOCKACKPARAM_TID_POS;
+ add_ba_rsp->status_code = cpu_to_le16(ADDBA_RSP_STATUS_ACCEPT);
+ block_ack_param_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
+ /* We donot support AMSDU inside AMPDU, hence reset the bit */
+ block_ack_param_set &= ~BLOCKACKPARAM_AMSDU_SUPP_MASK;
+ block_ack_param_set |= (priv->add_ba_param.rx_win_size <<
+ BLOCKACKPARAM_WINSIZE_POS);
+ add_ba_rsp->block_ack_param_set = cpu_to_le16(block_ack_param_set);
+ win_size = (le16_to_cpu(add_ba_rsp->block_ack_param_set)
+ & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
+ >> BLOCKACKPARAM_WINSIZE_POS;
+ cmd_addba_req->block_ack_param_set = cpu_to_le16(block_ack_param_set);
+
+ mwifiex_11n_create_rx_reorder_tbl(priv, cmd_addba_req->peer_mac_addr,
+ tid, win_size, le16_to_cpu(cmd_addba_req->ssn));
+ return 0;
+}
+
+/*
+ * This function prepares command for deleting a BA request.
+ *
+ * Preparation includes -
+ * - Setting command ID and proper size
+ * - Setting del BA request buffer
+ * - Ensuring correct endian-ness
+ */
+int mwifiex_cmd_11n_delba(struct host_cmd_ds_command *cmd, void *data_buf)
+{
+ struct host_cmd_ds_11n_delba *del_ba = (struct host_cmd_ds_11n_delba *)
+ &cmd->params.del_ba;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_11N_DELBA);
+ cmd->size = cpu_to_le16(sizeof(*del_ba) + S_DS_GEN);
+ memcpy(del_ba, data_buf, sizeof(*del_ba));
+
+ return 0;
+}
+
+/*
+ * This function identifies if Rx reordering is needed for a received packet.
+ *
+ * In case reordering is required, the function will do the reordering
+ * before sending it to kernel.
+ *
+ * The Rx reorder table is checked first with the received TID/TA pair. If
+ * not found, the received packet is dispatched immediately. But if found,
+ * the packet is reordered and all the packets in the updated Rx reordering
+ * table is dispatched until a hole is found.
+ *
+ * For sequence number less than the starting window, the packet is dropped.
+ */
+int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
+ u16 seq_num, u16 tid,
+ u8 *ta, u8 pkt_type, void *payload)
+{
+ struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
+ int start_win, end_win, win_size, ret;
+ u16 pkt_index;
+
+ rx_reor_tbl_ptr =
+ mwifiex_11n_get_rx_reorder_tbl((struct mwifiex_private *) priv,
+ tid, ta);
+ if (!rx_reor_tbl_ptr) {
+ if (pkt_type != PKT_TYPE_BAR)
+ mwifiex_process_rx_packet(priv->adapter, payload);
+ return 0;
+ }
+ start_win = rx_reor_tbl_ptr->start_win;
+ win_size = rx_reor_tbl_ptr->win_size;
+ end_win = ((start_win + win_size) - 1) & (MAX_TID_VALUE - 1);
+ del_timer(&rx_reor_tbl_ptr->timer_context.timer);
+ mod_timer(&rx_reor_tbl_ptr->timer_context.timer, jiffies
+ + (MIN_FLUSH_TIMER_MS * win_size * HZ) / 1000);
+
+ /*
+ * If seq_num is less then starting win then ignore and drop the
+ * packet
+ */
+ if ((start_win + TWOPOW11) > (MAX_TID_VALUE - 1)) {/* Wrap */
+ if (seq_num >= ((start_win + (TWOPOW11)) & (MAX_TID_VALUE - 1))
+ && (seq_num < start_win))
+ return -1;
+ } else if ((seq_num < start_win)
+ || (seq_num > (start_win + (TWOPOW11)))) {
+ return -1;
+ }
+
+ /*
+ * If this packet is a BAR we adjust seq_num as
+ * WinStart = seq_num
+ */
+ if (pkt_type == PKT_TYPE_BAR)
+ seq_num = ((seq_num + win_size) - 1) & (MAX_TID_VALUE - 1);
+
+ if (((end_win < start_win)
+ && (seq_num < (TWOPOW11 - (MAX_TID_VALUE - start_win)))
+ && (seq_num > end_win)) || ((end_win > start_win)
+ && ((seq_num > end_win) || (seq_num < start_win)))) {
+ end_win = seq_num;
+ if (((seq_num - win_size) + 1) >= 0)
+ start_win = (end_win - win_size) + 1;
+ else
+ start_win = (MAX_TID_VALUE - (win_size - seq_num)) + 1;
+ ret = mwifiex_11n_dispatch_pkt_until_start_win(priv,
+ rx_reor_tbl_ptr, start_win);
+
+ if (ret)
+ return ret;
+ }
+
+ if (pkt_type != PKT_TYPE_BAR) {
+ if (seq_num >= start_win)
+ pkt_index = seq_num - start_win;
+ else
+ pkt_index = (seq_num+MAX_TID_VALUE) - start_win;
+
+ if (rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index])
+ return -1;
+
+ rx_reor_tbl_ptr->rx_reorder_ptr[pkt_index] = payload;
+ }
+
+ /*
+ * Dispatch all packets sequentially from start_win until a
+ * hole is found and adjust the start_win appropriately
+ */
+ ret = mwifiex_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr);
+
+ return ret;
+}
+
+/*
+ * This function deletes an entry for a given TID/TA pair.
+ *
+ * The TID/TA are taken from del BA event body.
+ */
+void
+mwifiex_11n_delete_ba_stream_tbl(struct mwifiex_private *priv, int tid,
+ u8 *peer_mac, u8 type, int initiator)
+{
+ struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
+ struct mwifiex_tx_ba_stream_tbl *ptx_tbl;
+ u8 cleanup_rx_reorder_tbl;
+ unsigned long flags;
+
+ if (type == TYPE_DELBA_RECEIVE)
+ cleanup_rx_reorder_tbl = (initiator) ? true : false;
+ else
+ cleanup_rx_reorder_tbl = (initiator) ? false : true;
+
+ dev_dbg(priv->adapter->dev, "event: DELBA: %pM tid=%d, "
+ "initiator=%d\n", peer_mac, tid, initiator);
+
+ if (cleanup_rx_reorder_tbl) {
+ rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv, tid,
+ peer_mac);
+ if (!rx_reor_tbl_ptr) {
+ dev_dbg(priv->adapter->dev,
+ "event: TID, TA not found in table\n");
+ return;
+ }
+ mwifiex_11n_delete_rx_reorder_tbl_entry(priv, rx_reor_tbl_ptr);
+ } else {
+ ptx_tbl = mwifiex_11n_get_tx_ba_stream_tbl(priv, tid, peer_mac);
+ if (!ptx_tbl) {
+ dev_dbg(priv->adapter->dev,
+ "event: TID, RA not found in table\n");
+ return;
+ }
+
+ spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+ mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, ptx_tbl);
+ spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
+ }
+}
+
+/*
+ * This function handles the command response of an add BA response.
+ *
+ * Handling includes changing the header fields into CPU format and
+ * creating the stream, provided the add BA is accepted.
+ */
+int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
+{
+ struct host_cmd_ds_11n_addba_rsp *add_ba_rsp =
+ (struct host_cmd_ds_11n_addba_rsp *)
+ &resp->params.add_ba_rsp;
+ int tid, win_size;
+ struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
+ uint16_t block_ack_param_set;
+
+ block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set);
+
+ tid = (block_ack_param_set & IEEE80211_ADDBA_PARAM_TID_MASK)
+ >> BLOCKACKPARAM_TID_POS;
+ /*
+ * Check if we had rejected the ADDBA, if yes then do not create
+ * the stream
+ */
+ if (le16_to_cpu(add_ba_rsp->status_code) == BA_RESULT_SUCCESS) {
+ win_size = (block_ack_param_set &
+ IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK)
+ >> BLOCKACKPARAM_WINSIZE_POS;
+
+ dev_dbg(priv->adapter->dev, "cmd: ADDBA RSP: %pM"
+ " tid=%d ssn=%d win_size=%d\n",
+ add_ba_rsp->peer_mac_addr,
+ tid, add_ba_rsp->ssn, win_size);
+ } else {
+ dev_err(priv->adapter->dev, "ADDBA RSP: failed %pM tid=%d)\n",
+ add_ba_rsp->peer_mac_addr, tid);
+
+ rx_reor_tbl_ptr = mwifiex_11n_get_rx_reorder_tbl(priv,
+ tid, add_ba_rsp->peer_mac_addr);
+ if (rx_reor_tbl_ptr)
+ mwifiex_11n_delete_rx_reorder_tbl_entry(priv,
+ rx_reor_tbl_ptr);
+ }
+
+ return 0;
+}
+
+/*
+ * This function handles BA stream timeout event by preparing and sending
+ * a command to the firmware.
+ */
+void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv,
+ struct host_cmd_ds_11n_batimeout *event)
+{
+ struct host_cmd_ds_11n_delba delba;
+
+ memset(&delba, 0, sizeof(struct host_cmd_ds_11n_delba));
+ memcpy(delba.peer_mac_addr, event->peer_mac_addr, ETH_ALEN);
+
+ delba.del_ba_param_set |=
+ cpu_to_le16((u16) event->tid << DELBA_TID_POS);
+ delba.del_ba_param_set |= cpu_to_le16(
+ (u16) event->origninator << DELBA_INITIATOR_POS);
+ delba.reason_code = cpu_to_le16(WLAN_REASON_QSTA_TIMEOUT);
+ mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_DELBA, 0, 0, &delba);
+}
+
+/*
+ * This function cleans up the Rx reorder table by deleting all the entries
+ * and re-initializing.
+ */
+void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv)
+{
+ struct mwifiex_rx_reorder_tbl *del_tbl_ptr, *tmp_node;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+ list_for_each_entry_safe(del_tbl_ptr, tmp_node,
+ &priv->rx_reorder_tbl_ptr, list) {
+ spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+ mwifiex_11n_delete_rx_reorder_tbl_entry(priv, del_tbl_ptr);
+ spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+ }
+ spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+
+ INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
+ memset(priv->rx_seq, 0, sizeof(priv->rx_seq));
+}
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.h b/drivers/net/wireless/mwifiex/11n_rxreorder.h
new file mode 100644
index 000000000000..f3ca8c8c18f9
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.h
@@ -0,0 +1,65 @@
+/*
+ * Marvell Wireless LAN device driver: 802.11n RX Re-ordering
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef _MWIFIEX_11N_RXREORDER_H_
+#define _MWIFIEX_11N_RXREORDER_H_
+
+#define MIN_FLUSH_TIMER_MS 50
+
+#define PKT_TYPE_BAR 0xE7
+#define MAX_TID_VALUE (2 << 11)
+#define TWOPOW11 (2 << 10)
+
+#define BLOCKACKPARAM_TID_POS 2
+#define BLOCKACKPARAM_AMSDU_SUPP_MASK 0x1
+#define BLOCKACKPARAM_WINSIZE_POS 6
+#define DELBA_TID_POS 12
+#define DELBA_INITIATOR_POS 11
+#define TYPE_DELBA_SENT 1
+#define TYPE_DELBA_RECEIVE 2
+#define IMMEDIATE_BLOCK_ACK 0x2
+
+#define ADDBA_RSP_STATUS_ACCEPT 0
+
+int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *,
+ u16 seqNum,
+ u16 tid, u8 *ta,
+ u8 pkttype, void *payload);
+void mwifiex_11n_delete_ba_stream_tbl(struct mwifiex_private *priv, int Tid,
+ u8 *PeerMACAddr, u8 type,
+ int initiator);
+void mwifiex_11n_ba_stream_timeout(struct mwifiex_private *priv,
+ struct host_cmd_ds_11n_batimeout *event);
+int mwifiex_ret_11n_addba_resp(struct mwifiex_private *priv,
+ struct host_cmd_ds_command
+ *resp);
+int mwifiex_cmd_11n_delba(struct host_cmd_ds_command *cmd,
+ void *data_buf);
+int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
+ struct host_cmd_ds_command
+ *cmd, void *data_buf);
+int mwifiex_cmd_11n_addba_req(struct host_cmd_ds_command *cmd,
+ void *data_buf);
+void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv);
+struct mwifiex_rx_reorder_tbl *mwifiex_11n_get_rxreorder_tbl(struct
+ mwifiex_private
+ *priv, int tid,
+ u8 *ta);
+
+#endif /* _MWIFIEX_11N_RXREORDER_H_ */
diff --git a/drivers/net/wireless/mwifiex/Kconfig b/drivers/net/wireless/mwifiex/Kconfig
new file mode 100644
index 000000000000..86962920cef3
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/Kconfig
@@ -0,0 +1,21 @@
+config MWIFIEX
+ tristate "Marvell WiFi-Ex Driver"
+ depends on CFG80211
+ select LIB80211
+ ---help---
+ This adds support for wireless adapters based on Marvell
+ 802.11n chipsets.
+
+ If you choose to build it as a module, it will be called
+ mwifiex.
+
+config MWIFIEX_SDIO
+ tristate "Marvell WiFi-Ex Driver for SD8787"
+ depends on MWIFIEX && MMC
+ select FW_LOADER
+ ---help---
+ This adds support for wireless adapters based on Marvell
+ 8787 chipset with SDIO interface.
+
+ If you choose to build it as a module, it will be called
+ mwifiex_sdio.
diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile
new file mode 100644
index 000000000000..42cb733ea33a
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/Makefile
@@ -0,0 +1,41 @@
+#
+# Copyright (C) 2011, Marvell International Ltd.
+#
+# This software file (the "File") is distributed by Marvell International
+# Ltd. under the terms of the GNU General Public License Version 2, June 1991
+# (the "License"). You may use, redistribute and/or modify this File in
+# accordance with the terms and conditions of the License, a copy of which
+# is available by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+# worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+#
+# THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+# ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+# this warranty disclaimer.
+
+
+mwifiex-y += main.o
+mwifiex-y += init.o
+mwifiex-y += cfp.o
+mwifiex-y += cmdevt.o
+mwifiex-y += util.o
+mwifiex-y += txrx.o
+mwifiex-y += wmm.o
+mwifiex-y += 11n.o
+mwifiex-y += 11n_aggr.o
+mwifiex-y += 11n_rxreorder.o
+mwifiex-y += scan.o
+mwifiex-y += join.o
+mwifiex-y += sta_ioctl.o
+mwifiex-y += sta_cmd.o
+mwifiex-y += sta_cmdresp.o
+mwifiex-y += sta_event.o
+mwifiex-y += sta_tx.o
+mwifiex-y += sta_rx.o
+mwifiex-y += cfg80211.o
+mwifiex-$(CONFIG_DEBUG_FS) += debugfs.o
+obj-$(CONFIG_MWIFIEX) += mwifiex.o
+
+mwifiex_sdio-y += sdio.o
+obj-$(CONFIG_MWIFIEX_SDIO) += mwifiex_sdio.o
diff --git a/drivers/net/wireless/mwifiex/README b/drivers/net/wireless/mwifiex/README
new file mode 100644
index 000000000000..b55badef4660
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/README
@@ -0,0 +1,204 @@
+# Copyright (C) 2011, Marvell International Ltd.
+#
+# This software file (the "File") is distributed by Marvell International
+# Ltd. under the terms of the GNU General Public License Version 2, June 1991
+# (the "License"). You may use, redistribute and/or modify this File in
+# accordance with the terms and conditions of the License, a copy of which
+# is available by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+# worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+#
+# THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+# ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+# this warranty disclaimer.
+
+
+===============================================================================
+ U S E R M A N U A L
+
+1) FOR DRIVER INSTALL
+
+ a) Copy sd8787.bin to /lib/firmware/mrvl/ directory,
+ create the directory if it doesn't exist.
+ b) Install WLAN driver,
+ insmod mwifiex.ko
+ c) Uninstall WLAN driver,
+ ifconfig mlanX down
+ rmmod mwifiex
+
+
+2) FOR DRIVER CONFIGURATION AND INFO
+ The configurations can be done either using the 'iw' user space
+ utility or debugfs.
+
+ a) 'iw' utility commands
+
+ Following are some useful iw commands:-
+
+iw dev mlan0 scan
+
+ This command will trigger a scan.
+ The command will then display the scan table entries
+
+iw dev mlan0 connect -w <SSID> [<freq in MHz>] [<bssid>] [key 0:abcde d:1123456789a]
+ The above command can be used to connect to an AP with a particular SSID.
+ Ap's operating frequency can be specified or even the bssid. If the AP is using
+ WEP encryption, wep keys can be specified in the command.
+ Note: Every time before connecting to an AP scan command (iw dev mlan0 scan) should be used by user.
+
+iw dev mlan0 disconnect
+ This command will be used to disconnect from an AP.
+
+
+iw dev mlan0 ibss join <SSID> <freq in MHz> [fixed-freq] [fixed-bssid] [key 0:abcde]
+ The command will be used to join or create an ibss. Optionally, operating frequency,
+ bssid and the security related parameters can be specified while joining/creating
+ and ibss.
+
+iw dev mlan0 ibss leave
+ The command will be used to leave an ibss network.
+
+iw dev mlan0 link
+ The command will be used to get the connection status. The command will return parameters
+ such as SSID, operating frequency, rx/tx packets, signal strength, tx bitrate.
+
+ Apart from the iw utility all standard configurations using the 'iwconfig' utility are also supported.
+
+ b) Debugfs interface
+
+ The debugfs interface can be used for configurations and for getting
+ some useful information from the driver.
+ The section below explains the configurations that can be
+ done.
+
+ Mount debugfs to /debugfs mount point:
+
+ mkdir /debugfs
+ mount -t debugfs debugfs /debugfs
+
+ The information is provided in /debugfs/mwifiex/mlanX/:
+
+iw reg set <country code>
+ The command will be used to change the regulatory domain.
+
+iw reg get
+ The command will be used to get current regulatory domain.
+
+info
+ This command is used to get driver info.
+
+ Usage:
+ cat info
+
+ driver_name = "mwifiex"
+ driver_version = <driver_name, driver_version, (firmware_version)>
+ interface_name = "mlanX"
+ bss_mode = "Ad-hoc" | "Managed" | "Auto" | "Unknown"
+ media_state = "Disconnected" | "Connected"
+ mac_address = <6-byte adapter MAC address>
+ multicase_count = <multicast address count>
+ essid = <current SSID>
+ bssid = <current BSSID>
+ channel = <current channel>
+ region_code = <current region code>
+ multicasr_address[n] = <multicast address>
+ num_tx_bytes = <number of bytes sent to device>
+ num_rx_bytes = <number of bytes received from device and sent to kernel>
+ num_tx_pkts = <number of packets sent to device>
+ num_rx_pkts = <number of packets received from device and sent to kernel>
+ num_tx_pkts_dropped = <number of Tx packets dropped by driver>
+ num_rx_pkts_dropped = <number of Rx packets dropped by driver>
+ num_tx_pkts_err = <number of Tx packets failed to send to device>
+ num_rx_pkts_err = <number of Rx packets failed to receive from device>
+ carrier "on" | "off"
+ tx queue "stopped" | "started"
+
+ The following debug info are provided in /debugfs/mwifiex/mlanX/debug:
+
+ int_counter = <interrupt count, cleared when interrupt handled>
+ wmm_ac_vo = <number of packets sent to device from WMM AcVo queue>
+ wmm_ac_vi = <number of packets sent to device from WMM AcVi queue>
+ wmm_ac_be = <number of packets sent to device from WMM AcBE queue>
+ wmm_ac_bk = <number of packets sent to device from WMM AcBK queue>
+ max_tx_buf_size = <maximum Tx buffer size>
+ tx_buf_size = <current Tx buffer size>
+ curr_tx_buf_size = <current Tx buffer size>
+ ps_mode = <0/1, CAM mode/PS mode>
+ ps_state = <0/1/2/3, full power state/awake state/pre-sleep state/sleep state>
+ is_deep_sleep = <0/1, not deep sleep state/deep sleep state>
+ wakeup_dev_req = <0/1, wakeup device not required/required>
+ wakeup_tries = <wakeup device count, cleared when device awake>
+ hs_configured = <0/1, host sleep not configured/configured>
+ hs_activated = <0/1, extended host sleep not activated/activated>
+ num_tx_timeout = <number of Tx timeout>
+ num_cmd_timeout = <number of timeout commands>
+ timeout_cmd_id = <command id of the last timeout command>
+ timeout_cmd_act = <command action of the last timeout command>
+ last_cmd_id = <command id of the last several commands sent to device>
+ last_cmd_act = <command action of the last several commands sent to device>
+ last_cmd_index = <0 based last command index>
+ last_cmd_resp_id = <command id of the last several command responses received from device>
+ last_cmd_resp_index = <0 based last command response index>
+ last_event = <event id of the last several events received from device>
+ last_event_index = <0 based last event index>
+ num_cmd_h2c_fail = <number of commands failed to send to device>
+ num_cmd_sleep_cfm_fail = <number of sleep confirm failed to send to device>
+ num_tx_h2c_fail = <number of data packets failed to send to device>
+ num_evt_deauth = <number of deauthenticated events received from device>
+ num_evt_disassoc = <number of disassociated events received from device>
+ num_evt_link_lost = <number of link lost events received from device>
+ num_cmd_deauth = <number of deauthenticate commands sent to device>
+ num_cmd_assoc_ok = <number of associate commands with success return>
+ num_cmd_assoc_fail = <number of associate commands with failure return>
+ cmd_sent = <0/1, send command resources available/sending command to device>
+ data_sent = <0/1, send data resources available/sending data to device>
+ mp_rd_bitmap = <SDIO multi-port read bitmap>
+ mp_wr_bitmap = <SDIO multi-port write bitmap>
+ cmd_resp_received = <0/1, no cmd response to process/response received and yet to process>
+ event_received = <0/1, no event to process/event received and yet to process>
+ cmd_pending = <number of cmd pending>
+ tx_pending = <number of Tx packet pending>
+ rx_pending = <number of Rx packet pending>
+
+
+3) FOR DRIVER CONFIGURATION
+
+regrdwr
+ This command is used to read/write the adapter register.
+
+ Usage:
+ echo " <type> <offset> [value]" > regrdwr
+ cat regrdwr
+
+ where the parameters are,
+ <type>: 1:MAC/SOC, 2:BBP, 3:RF, 4:PMIC, 5:CAU
+ <offset>: offset of register
+ [value]: value to be written
+
+ Examples:
+ echo "1 0xa060" > regrdwr : Read the MAC register
+ echo "1 0xa060 0x12" > regrdwr : Write the MAC register
+ echo "1 0xa794 0x80000000" > regrdwr
+ : Write 0x80000000 to MAC register
+rdeeprom
+ This command is used to read the EEPROM contents of the card.
+
+ Usage:
+ echo "<offset> <length>" > rdeeprom
+ cat rdeeprom
+
+ where the parameters are,
+ <offset>: multiples of 4
+ <length>: 4-20, multiples of 4
+
+ Example:
+ echo "0 20" > rdeeprom : Read 20 bytes of EEPROM data from offset 0
+
+getlog
+ This command is used to get the statistics available in the station.
+ Usage:
+
+ cat getlog
+
+===============================================================================
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
new file mode 100644
index 000000000000..660831ce293c
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -0,0 +1,1417 @@
+/*
+ * Marvell Wireless LAN device driver: CFG80211
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "cfg80211.h"
+#include "main.h"
+
+/*
+ * This function maps the nl802.11 channel type into driver channel type.
+ *
+ * The mapping is as follows -
+ * NL80211_CHAN_NO_HT -> NO_SEC_CHANNEL
+ * NL80211_CHAN_HT20 -> NO_SEC_CHANNEL
+ * NL80211_CHAN_HT40PLUS -> SEC_CHANNEL_ABOVE
+ * NL80211_CHAN_HT40MINUS -> SEC_CHANNEL_BELOW
+ * Others -> NO_SEC_CHANNEL
+ */
+static int
+mwifiex_cfg80211_channel_type_to_mwifiex_channels(enum nl80211_channel_type
+ channel_type)
+{
+ switch (channel_type) {
+ case NL80211_CHAN_NO_HT:
+ case NL80211_CHAN_HT20:
+ return NO_SEC_CHANNEL;
+ case NL80211_CHAN_HT40PLUS:
+ return SEC_CHANNEL_ABOVE;
+ case NL80211_CHAN_HT40MINUS:
+ return SEC_CHANNEL_BELOW;
+ default:
+ return NO_SEC_CHANNEL;
+ }
+}
+
+/*
+ * This function maps the driver channel type into nl802.11 channel type.
+ *
+ * The mapping is as follows -
+ * NO_SEC_CHANNEL -> NL80211_CHAN_HT20
+ * SEC_CHANNEL_ABOVE -> NL80211_CHAN_HT40PLUS
+ * SEC_CHANNEL_BELOW -> NL80211_CHAN_HT40MINUS
+ * Others -> NL80211_CHAN_HT20
+ */
+static enum nl80211_channel_type
+mwifiex_channels_to_cfg80211_channel_type(int channel_type)
+{
+ switch (channel_type) {
+ case NO_SEC_CHANNEL:
+ return NL80211_CHAN_HT20;
+ case SEC_CHANNEL_ABOVE:
+ return NL80211_CHAN_HT40PLUS;
+ case SEC_CHANNEL_BELOW:
+ return NL80211_CHAN_HT40MINUS;
+ default:
+ return NL80211_CHAN_HT20;
+ }
+}
+
+/*
+ * This function checks whether WEP is set.
+ */
+static int
+mwifiex_is_alg_wep(u32 cipher)
+{
+ switch (cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * This function retrieves the private structure from kernel wiphy structure.
+ */
+static void *mwifiex_cfg80211_get_priv(struct wiphy *wiphy)
+{
+ return (void *) (*(unsigned long *) wiphy_priv(wiphy));
+}
+
+/*
+ * CFG802.11 operation handler to delete a network key.
+ */
+static int
+mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev,
+ u8 key_index, bool pairwise, const u8 *mac_addr)
+{
+ struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+
+ if (mwifiex_set_encode(priv, NULL, 0, key_index, 1)) {
+ wiphy_err(wiphy, "deleting the crypto keys\n");
+ return -EFAULT;
+ }
+
+ wiphy_dbg(wiphy, "info: crypto keys deleted\n");
+ return 0;
+}
+
+/*
+ * CFG802.11 operation handler to set Tx power.
+ */
+static int
+mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy,
+ enum nl80211_tx_power_setting type,
+ int dbm)
+{
+ struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+ struct mwifiex_power_cfg power_cfg;
+
+ if (type == NL80211_TX_POWER_FIXED) {
+ power_cfg.is_power_auto = 0;
+ power_cfg.power_level = dbm;
+ } else {
+ power_cfg.is_power_auto = 1;
+ }
+
+ return mwifiex_set_tx_power(priv, &power_cfg);
+}
+
+/*
+ * CFG802.11 operation handler to set Power Save option.
+ *
+ * The timeout value, if provided, is currently ignored.
+ */
+static int
+mwifiex_cfg80211_set_power_mgmt(struct wiphy *wiphy,
+ struct net_device *dev,
+ bool enabled, int timeout)
+{
+ struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+ u32 ps_mode;
+
+ if (timeout)
+ wiphy_dbg(wiphy,
+ "info: ignoring the timeout value"
+ " for IEEE power save\n");
+
+ ps_mode = enabled;
+
+ return mwifiex_drv_set_power(priv, &ps_mode);
+}
+
+/*
+ * CFG802.11 operation handler to set the default network key.
+ */
+static int
+mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
+ u8 key_index, bool unicast,
+ bool multicast)
+{
+ struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+
+ /* Return if WEP key not configured */
+ if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED)
+ return 0;
+
+ if (mwifiex_set_encode(priv, NULL, 0, key_index, 0)) {
+ wiphy_err(wiphy, "set default Tx key index\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+/*
+ * CFG802.11 operation handler to add a network key.
+ */
+static int
+mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev,
+ u8 key_index, bool pairwise, const u8 *mac_addr,
+ struct key_params *params)
+{
+ struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+
+ if (mwifiex_set_encode(priv, params->key, params->key_len,
+ key_index, 0)) {
+ wiphy_err(wiphy, "crypto keys added\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+/*
+ * This function sends domain information to the firmware.
+ *
+ * The following information are passed to the firmware -
+ * - Country codes
+ * - Sub bands (first channel, number of channels, maximum Tx power)
+ */
+static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
+{
+ u8 no_of_triplet = 0;
+ struct ieee80211_country_ie_triplet *t;
+ u8 no_of_parsed_chan = 0;
+ u8 first_chan = 0, next_chan = 0, max_pwr = 0;
+ u8 i, flag = 0;
+ enum ieee80211_band band;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *ch;
+ struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_802_11d_domain_reg *domain_info = &adapter->domain_reg;
+
+ /* Set country code */
+ domain_info->country_code[0] = priv->country_code[0];
+ domain_info->country_code[1] = priv->country_code[1];
+ domain_info->country_code[2] = ' ';
+
+ band = mwifiex_band_to_radio_type(adapter->config_bands);
+ if (!wiphy->bands[band]) {
+ wiphy_err(wiphy, "11D: setting domain info in FW\n");
+ return -1;
+ }
+
+ sband = wiphy->bands[band];
+
+ for (i = 0; i < sband->n_channels ; i++) {
+ ch = &sband->channels[i];
+ if (ch->flags & IEEE80211_CHAN_DISABLED)
+ continue;
+
+ if (!flag) {
+ flag = 1;
+ first_chan = (u32) ch->hw_value;
+ next_chan = first_chan;
+ max_pwr = ch->max_power;
+ no_of_parsed_chan = 1;
+ continue;
+ }
+
+ if (ch->hw_value == next_chan + 1 &&
+ ch->max_power == max_pwr) {
+ next_chan++;
+ no_of_parsed_chan++;
+ } else {
+ t = &domain_info->triplet[no_of_triplet];
+ t->chans.first_channel = first_chan;
+ t->chans.num_channels = no_of_parsed_chan;
+ t->chans.max_power = max_pwr;
+ no_of_triplet++;
+ first_chan = (u32) ch->hw_value;
+ next_chan = first_chan;
+ max_pwr = ch->max_power;
+ no_of_parsed_chan = 1;
+ }
+ }
+
+ if (flag) {
+ t = &domain_info->triplet[no_of_triplet];
+ t->chans.first_channel = first_chan;
+ t->chans.num_channels = no_of_parsed_chan;
+ t->chans.max_power = max_pwr;
+ no_of_triplet++;
+ }
+
+ domain_info->no_of_triplet = no_of_triplet;
+
+ if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
+ HostCmd_ACT_GEN_SET, 0, NULL)) {
+ wiphy_err(wiphy, "11D: setting domain info in FW\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * CFG802.11 regulatory domain callback function.
+ *
+ * This function is called when the regulatory domain is changed due to the
+ * following reasons -
+ * - Set by driver
+ * - Set by system core
+ * - Set by user
+ * - Set bt Country IE
+ */
+static int mwifiex_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request)
+{
+ struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+
+ wiphy_dbg(wiphy, "info: cfg80211 regulatory domain callback for domain"
+ " %c%c\n", request->alpha2[0], request->alpha2[1]);
+
+ memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2));
+
+ switch (request->initiator) {
+ case NL80211_REGDOM_SET_BY_DRIVER:
+ case NL80211_REGDOM_SET_BY_CORE:
+ case NL80211_REGDOM_SET_BY_USER:
+ break;
+ /* Todo: apply driver specific changes in channel flags based
+ on the request initiator if necessary. */
+ case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+ break;
+ }
+ mwifiex_send_domain_info_cmd_fw(wiphy);
+
+ return 0;
+}
+
+/*
+ * This function sets the RF channel.
+ *
+ * This function creates multiple IOCTL requests, populates them accordingly
+ * and issues them to set the band/channel and frequency.
+ */
+static int
+mwifiex_set_rf_channel(struct mwifiex_private *priv,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
+{
+ struct mwifiex_chan_freq_power cfp;
+ struct mwifiex_ds_band_cfg band_cfg;
+ u32 config_bands = 0;
+ struct wiphy *wiphy = priv->wdev->wiphy;
+
+ if (chan) {
+ memset(&band_cfg, 0, sizeof(band_cfg));
+ /* Set appropriate bands */
+ if (chan->band == IEEE80211_BAND_2GHZ)
+ config_bands = BAND_B | BAND_G | BAND_GN;
+ else
+ config_bands = BAND_AN | BAND_A;
+ if (priv->bss_mode == NL80211_IFTYPE_STATION
+ || priv->bss_mode == NL80211_IFTYPE_UNSPECIFIED) {
+ band_cfg.config_bands = config_bands;
+ } else if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
+ band_cfg.config_bands = config_bands;
+ band_cfg.adhoc_start_band = config_bands;
+ }
+
+ band_cfg.sec_chan_offset =
+ mwifiex_cfg80211_channel_type_to_mwifiex_channels
+ (channel_type);
+
+ if (mwifiex_set_radio_band_cfg(priv, &band_cfg))
+ return -EFAULT;
+
+ mwifiex_send_domain_info_cmd_fw(wiphy);
+ }
+
+ wiphy_dbg(wiphy, "info: setting band %d, channel offset %d and "
+ "mode %d\n", config_bands, band_cfg.sec_chan_offset,
+ priv->bss_mode);
+ if (!chan)
+ return 0;
+
+ memset(&cfp, 0, sizeof(cfp));
+ cfp.freq = chan->center_freq;
+ cfp.channel = ieee80211_frequency_to_channel(chan->center_freq);
+
+ if (mwifiex_bss_set_channel(priv, &cfp))
+ return -EFAULT;
+
+ return mwifiex_drv_change_adhoc_chan(priv, cfp.channel);
+}
+
+/*
+ * CFG802.11 operation handler to set channel.
+ *
+ * This function can only be used when station is not connected.
+ */
+static int
+mwifiex_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
+ struct ieee80211_channel *chan,
+ enum nl80211_channel_type channel_type)
+{
+ struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+
+ if (priv->media_connected) {
+ wiphy_err(wiphy, "This setting is valid only when station "
+ "is not connected\n");
+ return -EINVAL;
+ }
+
+ return mwifiex_set_rf_channel(priv, chan, channel_type);
+}
+
+/*
+ * This function sets the fragmentation threshold.
+ *
+ * The fragmentation threshold value must lie between MWIFIEX_FRAG_MIN_VALUE
+ * and MWIFIEX_FRAG_MAX_VALUE.
+ */
+static int
+mwifiex_set_frag(struct mwifiex_private *priv, u32 frag_thr)
+{
+ int ret;
+
+ if (frag_thr < MWIFIEX_FRAG_MIN_VALUE
+ || frag_thr > MWIFIEX_FRAG_MAX_VALUE)
+ return -EINVAL;
+
+ /* Send request to firmware */
+ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET, FRAG_THRESH_I,
+ &frag_thr);
+
+ return ret;
+}
+
+/*
+ * This function sets the RTS threshold.
+
+ * The rts value must lie between MWIFIEX_RTS_MIN_VALUE
+ * and MWIFIEX_RTS_MAX_VALUE.
+ */
+static int
+mwifiex_set_rts(struct mwifiex_private *priv, u32 rts_thr)
+{
+ if (rts_thr < MWIFIEX_RTS_MIN_VALUE || rts_thr > MWIFIEX_RTS_MAX_VALUE)
+ rts_thr = MWIFIEX_RTS_MAX_VALUE;
+
+ return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET, RTS_THRESH_I,
+ &rts_thr);
+}
+
+/*
+ * CFG802.11 operation handler to set wiphy parameters.
+ *
+ * This function can be used to set the RTS threshold and the
+ * Fragmentation threshold of the driver.
+ */
+static int
+mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+ struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+ int ret = 0;
+
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
+ ret = mwifiex_set_rts(priv, wiphy->rts_threshold);
+ if (ret)
+ return ret;
+ }
+
+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
+ ret = mwifiex_set_frag(priv, wiphy->frag_threshold);
+
+ return ret;
+}
+
+/*
+ * CFG802.11 operation handler to change interface type.
+ */
+static int
+mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
+ struct net_device *dev,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
+{
+ int ret;
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+
+ if (priv->bss_mode == type) {
+ wiphy_warn(wiphy, "already set to required type\n");
+ return 0;
+ }
+
+ priv->bss_mode = type;
+
+ switch (type) {
+ case NL80211_IFTYPE_ADHOC:
+ dev->ieee80211_ptr->iftype = NL80211_IFTYPE_ADHOC;
+ wiphy_dbg(wiphy, "info: setting interface type to adhoc\n");
+ break;
+ case NL80211_IFTYPE_STATION:
+ dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
+ wiphy_dbg(wiphy, "info: setting interface type to managed\n");
+ break;
+ case NL80211_IFTYPE_UNSPECIFIED:
+ dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
+ wiphy_dbg(wiphy, "info: setting interface type to auto\n");
+ return 0;
+ default:
+ wiphy_err(wiphy, "unknown interface type: %d\n", type);
+ return -EINVAL;
+ }
+
+ mwifiex_deauthenticate(priv, NULL);
+
+ priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM;
+
+ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_SET_BSS_MODE,
+ HostCmd_ACT_GEN_SET, 0, NULL);
+
+ return ret;
+}
+
+/*
+ * This function dumps the station information on a buffer.
+ *
+ * The following information are shown -
+ * - Total bytes transmitted
+ * - Total bytes received
+ * - Total packets transmitted
+ * - Total packets received
+ * - Signal quality level
+ * - Transmission rate
+ */
+static int
+mwifiex_dump_station_info(struct mwifiex_private *priv,
+ struct station_info *sinfo)
+{
+ struct mwifiex_ds_get_signal signal;
+ struct mwifiex_rate_cfg rate;
+ int ret = 0;
+
+ sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES |
+ STATION_INFO_RX_PACKETS |
+ STATION_INFO_TX_PACKETS
+ | STATION_INFO_SIGNAL | STATION_INFO_TX_BITRATE;
+
+ /* Get signal information from the firmware */
+ memset(&signal, 0, sizeof(struct mwifiex_ds_get_signal));
+ if (mwifiex_get_signal_info(priv, &signal)) {
+ dev_err(priv->adapter->dev, "getting signal information\n");
+ ret = -EFAULT;
+ }
+
+ if (mwifiex_drv_get_data_rate(priv, &rate)) {
+ dev_err(priv->adapter->dev, "getting data rate\n");
+ ret = -EFAULT;
+ }
+
+ sinfo->rx_bytes = priv->stats.rx_bytes;
+ sinfo->tx_bytes = priv->stats.tx_bytes;
+ sinfo->rx_packets = priv->stats.rx_packets;
+ sinfo->tx_packets = priv->stats.tx_packets;
+ sinfo->signal = priv->w_stats.qual.level;
+ sinfo->txrate.legacy = rate.rate;
+
+ return ret;
+}
+
+/*
+ * CFG802.11 operation handler to get station information.
+ *
+ * This function only works in connected mode, and dumps the
+ * requested station information, if available.
+ */
+static int
+mwifiex_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev,
+ u8 *mac, struct station_info *sinfo)
+{
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+
+ mwifiex_dump_station_info(priv, sinfo);
+
+ if (!priv->media_connected)
+ return -ENOENT;
+ if (memcmp(mac, priv->cfg_bssid, ETH_ALEN))
+ return -ENOENT;
+
+ return mwifiex_dump_station_info(priv, sinfo);
+}
+
+/* Supported rates to be advertised to the cfg80211 */
+
+static struct ieee80211_rate mwifiex_rates[] = {
+ {.bitrate = 10, .hw_value = 2, },
+ {.bitrate = 20, .hw_value = 4, },
+ {.bitrate = 55, .hw_value = 11, },
+ {.bitrate = 110, .hw_value = 22, },
+ {.bitrate = 220, .hw_value = 44, },
+ {.bitrate = 60, .hw_value = 12, },
+ {.bitrate = 90, .hw_value = 18, },
+ {.bitrate = 120, .hw_value = 24, },
+ {.bitrate = 180, .hw_value = 36, },
+ {.bitrate = 240, .hw_value = 48, },
+ {.bitrate = 360, .hw_value = 72, },
+ {.bitrate = 480, .hw_value = 96, },
+ {.bitrate = 540, .hw_value = 108, },
+ {.bitrate = 720, .hw_value = 144, },
+};
+
+/* Channel definitions to be advertised to cfg80211 */
+
+static struct ieee80211_channel mwifiex_channels_2ghz[] = {
+ {.center_freq = 2412, .hw_value = 1, },
+ {.center_freq = 2417, .hw_value = 2, },
+ {.center_freq = 2422, .hw_value = 3, },
+ {.center_freq = 2427, .hw_value = 4, },
+ {.center_freq = 2432, .hw_value = 5, },
+ {.center_freq = 2437, .hw_value = 6, },
+ {.center_freq = 2442, .hw_value = 7, },
+ {.center_freq = 2447, .hw_value = 8, },
+ {.center_freq = 2452, .hw_value = 9, },
+ {.center_freq = 2457, .hw_value = 10, },
+ {.center_freq = 2462, .hw_value = 11, },
+ {.center_freq = 2467, .hw_value = 12, },
+ {.center_freq = 2472, .hw_value = 13, },
+ {.center_freq = 2484, .hw_value = 14, },
+};
+
+static struct ieee80211_supported_band mwifiex_band_2ghz = {
+ .channels = mwifiex_channels_2ghz,
+ .n_channels = ARRAY_SIZE(mwifiex_channels_2ghz),
+ .bitrates = mwifiex_rates,
+ .n_bitrates = 14,
+};
+
+static struct ieee80211_channel mwifiex_channels_5ghz[] = {
+ {.center_freq = 5040, .hw_value = 8, },
+ {.center_freq = 5060, .hw_value = 12, },
+ {.center_freq = 5080, .hw_value = 16, },
+ {.center_freq = 5170, .hw_value = 34, },
+ {.center_freq = 5190, .hw_value = 38, },
+ {.center_freq = 5210, .hw_value = 42, },
+ {.center_freq = 5230, .hw_value = 46, },
+ {.center_freq = 5180, .hw_value = 36, },
+ {.center_freq = 5200, .hw_value = 40, },
+ {.center_freq = 5220, .hw_value = 44, },
+ {.center_freq = 5240, .hw_value = 48, },
+ {.center_freq = 5260, .hw_value = 52, },
+ {.center_freq = 5280, .hw_value = 56, },
+ {.center_freq = 5300, .hw_value = 60, },
+ {.center_freq = 5320, .hw_value = 64, },
+ {.center_freq = 5500, .hw_value = 100, },
+ {.center_freq = 5520, .hw_value = 104, },
+ {.center_freq = 5540, .hw_value = 108, },
+ {.center_freq = 5560, .hw_value = 112, },
+ {.center_freq = 5580, .hw_value = 116, },
+ {.center_freq = 5600, .hw_value = 120, },
+ {.center_freq = 5620, .hw_value = 124, },
+ {.center_freq = 5640, .hw_value = 128, },
+ {.center_freq = 5660, .hw_value = 132, },
+ {.center_freq = 5680, .hw_value = 136, },
+ {.center_freq = 5700, .hw_value = 140, },
+ {.center_freq = 5745, .hw_value = 149, },
+ {.center_freq = 5765, .hw_value = 153, },
+ {.center_freq = 5785, .hw_value = 157, },
+ {.center_freq = 5805, .hw_value = 161, },
+ {.center_freq = 5825, .hw_value = 165, },
+};
+
+static struct ieee80211_supported_band mwifiex_band_5ghz = {
+ .channels = mwifiex_channels_5ghz,
+ .n_channels = ARRAY_SIZE(mwifiex_channels_5ghz),
+ .bitrates = mwifiex_rates - 4,
+ .n_bitrates = ARRAY_SIZE(mwifiex_rates) + 4,
+};
+
+
+/* Supported crypto cipher suits to be advertised to cfg80211 */
+
+static const u32 mwifiex_cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
+};
+
+/*
+ * CFG802.11 operation handler for disconnection request.
+ *
+ * This function does not work when there is already a disconnection
+ * procedure going on.
+ */
+static int
+mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
+ u16 reason_code)
+{
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+
+ if (priv->disconnect)
+ return -EBUSY;
+
+ priv->disconnect = 1;
+ if (mwifiex_deauthenticate(priv, NULL))
+ return -EFAULT;
+
+ wiphy_dbg(wiphy, "info: successfully disconnected from %pM:"
+ " reason code %d\n", priv->cfg_bssid, reason_code);
+
+ queue_work(priv->workqueue, &priv->cfg_workqueue);
+
+ return 0;
+}
+
+/*
+ * This function informs the CFG802.11 subsystem of a new IBSS.
+ *
+ * The following information are sent to the CFG802.11 subsystem
+ * to register the new IBSS. If we do not register the new IBSS,
+ * a kernel panic will result.
+ * - SSID
+ * - SSID length
+ * - BSSID
+ * - Channel
+ */
+static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
+{
+ struct ieee80211_channel *chan;
+ struct mwifiex_bss_info bss_info;
+ int ie_len;
+ u8 ie_buf[IEEE80211_MAX_SSID_LEN + sizeof(struct ieee_types_header)];
+
+ if (mwifiex_get_bss_info(priv, &bss_info))
+ return -1;
+
+ ie_buf[0] = WLAN_EID_SSID;
+ ie_buf[1] = bss_info.ssid.ssid_len;
+
+ memcpy(&ie_buf[sizeof(struct ieee_types_header)],
+ &bss_info.ssid.ssid,
+ bss_info.ssid.ssid_len);
+ ie_len = ie_buf[1] + sizeof(struct ieee_types_header);
+
+ chan = __ieee80211_get_channel(priv->wdev->wiphy,
+ ieee80211_channel_to_frequency(bss_info.bss_chan,
+ priv->curr_bss_params.band));
+
+ cfg80211_inform_bss(priv->wdev->wiphy, chan,
+ bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
+ 0, ie_buf, ie_len, 0, GFP_KERNEL);
+ memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN);
+
+ return 0;
+}
+
+/*
+ * This function informs the CFG802.11 subsystem of a new BSS connection.
+ *
+ * The following information are sent to the CFG802.11 subsystem
+ * to register the new BSS connection. If we do not register the new BSS,
+ * a kernel panic will result.
+ * - MAC address
+ * - Capabilities
+ * - Beacon period
+ * - RSSI value
+ * - Channel
+ * - Supported rates IE
+ * - Extended capabilities IE
+ * - DS parameter set IE
+ * - HT Capability IE
+ * - Vendor Specific IE (221)
+ * - WPA IE
+ * - RSN IE
+ */
+static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv,
+ struct mwifiex_802_11_ssid *ssid)
+{
+ struct mwifiex_bssdescriptor *scan_table;
+ int i, j;
+ struct ieee80211_channel *chan;
+ u8 *ie, *ie_buf;
+ u32 ie_len;
+ u8 *beacon;
+ int beacon_size;
+ u8 element_id, element_len;
+
+#define MAX_IE_BUF 2048
+ ie_buf = kzalloc(MAX_IE_BUF, GFP_KERNEL);
+ if (!ie_buf) {
+ dev_err(priv->adapter->dev, "%s: failed to alloc ie_buf\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ scan_table = priv->adapter->scan_table;
+ for (i = 0; i < priv->adapter->num_in_scan_table; i++) {
+ if (ssid) {
+ /* Inform specific BSS only */
+ if (memcmp(ssid->ssid, scan_table[i].ssid.ssid,
+ ssid->ssid_len))
+ continue;
+ }
+ memset(ie_buf, 0, MAX_IE_BUF);
+ ie_buf[0] = WLAN_EID_SSID;
+ ie_buf[1] = scan_table[i].ssid.ssid_len;
+ memcpy(&ie_buf[sizeof(struct ieee_types_header)],
+ scan_table[i].ssid.ssid, ie_buf[1]);
+
+ ie = ie_buf + ie_buf[1] + sizeof(struct ieee_types_header);
+ ie_len = ie_buf[1] + sizeof(struct ieee_types_header);
+
+ ie[0] = WLAN_EID_SUPP_RATES;
+
+ for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) {
+ if (!scan_table[i].supported_rates[j])
+ break;
+ else
+ ie[j + sizeof(struct ieee_types_header)] =
+ scan_table[i].supported_rates[j];
+ }
+
+ ie[1] = j;
+ ie_len += ie[1] + sizeof(struct ieee_types_header);
+
+ beacon = scan_table[i].beacon_buf;
+ beacon_size = scan_table[i].beacon_buf_size;
+
+ /* Skip time stamp, beacon interval and capability */
+
+ if (beacon) {
+ beacon += sizeof(scan_table[i].beacon_period)
+ + sizeof(scan_table[i].time_stamp) +
+ +sizeof(scan_table[i].cap_info_bitmap);
+
+ beacon_size -= sizeof(scan_table[i].beacon_period)
+ + sizeof(scan_table[i].time_stamp)
+ + sizeof(scan_table[i].cap_info_bitmap);
+ }
+
+ while (beacon_size >= sizeof(struct ieee_types_header)) {
+ ie = ie_buf + ie_len;
+ element_id = *beacon;
+ element_len = *(beacon + 1);
+ if (beacon_size < (int) element_len +
+ sizeof(struct ieee_types_header)) {
+ dev_err(priv->adapter->dev, "%s: in processing"
+ " IE, bytes left < IE length\n",
+ __func__);
+ break;
+ }
+ switch (element_id) {
+ case WLAN_EID_EXT_CAPABILITY:
+ case WLAN_EID_DS_PARAMS:
+ case WLAN_EID_HT_CAPABILITY:
+ case WLAN_EID_VENDOR_SPECIFIC:
+ case WLAN_EID_RSN:
+ case WLAN_EID_BSS_AC_ACCESS_DELAY:
+ ie[0] = element_id;
+ ie[1] = element_len;
+ memcpy(&ie[sizeof(struct ieee_types_header)],
+ (u8 *) beacon
+ + sizeof(struct ieee_types_header),
+ element_len);
+ ie_len += ie[1] +
+ sizeof(struct ieee_types_header);
+ break;
+ default:
+ break;
+ }
+ beacon += element_len +
+ sizeof(struct ieee_types_header);
+ beacon_size -= element_len +
+ sizeof(struct ieee_types_header);
+ }
+ chan = ieee80211_get_channel(priv->wdev->wiphy,
+ scan_table[i].freq);
+ cfg80211_inform_bss(priv->wdev->wiphy, chan,
+ scan_table[i].mac_address,
+ 0, scan_table[i].cap_info_bitmap,
+ scan_table[i].beacon_period,
+ ie_buf, ie_len,
+ scan_table[i].rssi, GFP_KERNEL);
+ }
+
+ kfree(ie_buf);
+ return 0;
+}
+
+/*
+ * This function connects with a BSS.
+ *
+ * This function handles both Infra and Ad-Hoc modes. It also performs
+ * validity checking on the provided parameters, disconnects from the
+ * current BSS (if any), sets up the association/scan parameters,
+ * including security settings, and performs specific SSID scan before
+ * trying to connect.
+ *
+ * For Infra mode, the function returns failure if the specified SSID
+ * is not found in scan table. However, for Ad-Hoc mode, it can create
+ * the IBSS if it does not exist. On successful completion in either case,
+ * the function notifies the CFG802.11 subsystem of the new BSS connection,
+ * otherwise the kernel will panic.
+ */
+static int
+mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
+ u8 *bssid, int mode, struct ieee80211_channel *channel,
+ struct cfg80211_connect_params *sme, bool privacy)
+{
+ struct mwifiex_802_11_ssid req_ssid;
+ struct mwifiex_ssid_bssid ssid_bssid;
+ int ret, auth_type = 0;
+
+ memset(&req_ssid, 0, sizeof(struct mwifiex_802_11_ssid));
+ memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid));
+
+ req_ssid.ssid_len = ssid_len;
+ if (ssid_len > IEEE80211_MAX_SSID_LEN) {
+ dev_err(priv->adapter->dev, "invalid SSID - aborting\n");
+ return -EINVAL;
+ }
+
+ memcpy(req_ssid.ssid, ssid, ssid_len);
+ if (!req_ssid.ssid_len || req_ssid.ssid[0] < 0x20) {
+ dev_err(priv->adapter->dev, "invalid SSID - aborting\n");
+ return -EINVAL;
+ }
+
+ /* disconnect before try to associate */
+ mwifiex_deauthenticate(priv, NULL);
+
+ if (channel)
+ ret = mwifiex_set_rf_channel(priv, channel,
+ mwifiex_channels_to_cfg80211_channel_type
+ (priv->adapter->chan_offset));
+
+ ret = mwifiex_set_encode(priv, NULL, 0, 0, 1); /* Disable keys */
+
+ if (mode == NL80211_IFTYPE_ADHOC) {
+ /* "privacy" is set only for ad-hoc mode */
+ if (privacy) {
+ /*
+ * Keep WLAN_CIPHER_SUITE_WEP104 for now so that
+ * the firmware can find a matching network from the
+ * scan. The cfg80211 does not give us the encryption
+ * mode at this stage so just setting it to WEP here.
+ */
+ priv->sec_info.encryption_mode =
+ WLAN_CIPHER_SUITE_WEP104;
+ priv->sec_info.authentication_mode =
+ NL80211_AUTHTYPE_OPEN_SYSTEM;
+ }
+
+ goto done;
+ }
+
+ /* Now handle infra mode. "sme" is valid for infra mode only */
+ if (sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC
+ || sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM)
+ auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM;
+ else if (sme->auth_type == NL80211_AUTHTYPE_SHARED_KEY)
+ auth_type = NL80211_AUTHTYPE_SHARED_KEY;
+
+ if (sme->crypto.n_ciphers_pairwise) {
+ priv->sec_info.encryption_mode =
+ sme->crypto.ciphers_pairwise[0];
+ priv->sec_info.authentication_mode = auth_type;
+ }
+
+ if (sme->crypto.cipher_group) {
+ priv->sec_info.encryption_mode = sme->crypto.cipher_group;
+ priv->sec_info.authentication_mode = auth_type;
+ }
+ if (sme->ie)
+ ret = mwifiex_set_gen_ie(priv, sme->ie, sme->ie_len);
+
+ if (sme->key) {
+ if (mwifiex_is_alg_wep(0) | mwifiex_is_alg_wep(0)) {
+ dev_dbg(priv->adapter->dev,
+ "info: setting wep encryption"
+ " with key len %d\n", sme->key_len);
+ ret = mwifiex_set_encode(priv, sme->key, sme->key_len,
+ sme->key_idx, 0);
+ }
+ }
+done:
+ /* Do specific SSID scanning */
+ if (mwifiex_request_scan(priv, &req_ssid)) {
+ dev_err(priv->adapter->dev, "scan error\n");
+ return -EFAULT;
+ }
+
+
+ memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(struct mwifiex_802_11_ssid));
+
+ if (mode != NL80211_IFTYPE_ADHOC) {
+ if (mwifiex_find_best_bss(priv, &ssid_bssid))
+ return -EFAULT;
+ /* Inform the BSS information to kernel, otherwise
+ * kernel will give a panic after successful assoc */
+ if (mwifiex_inform_bss_from_scan_result(priv, &req_ssid))
+ return -EFAULT;
+ }
+
+ dev_dbg(priv->adapter->dev, "info: trying to associate to %s and bssid %pM\n",
+ (char *) req_ssid.ssid, ssid_bssid.bssid);
+
+ memcpy(&priv->cfg_bssid, ssid_bssid.bssid, 6);
+
+ /* Connect to BSS by ESSID */
+ memset(&ssid_bssid.bssid, 0, ETH_ALEN);
+
+ if (!netif_queue_stopped(priv->netdev))
+ netif_stop_queue(priv->netdev);
+
+ if (mwifiex_bss_start(priv, &ssid_bssid))
+ return -EFAULT;
+
+ if (mode == NL80211_IFTYPE_ADHOC) {
+ /* Inform the BSS information to kernel, otherwise
+ * kernel will give a panic after successful assoc */
+ if (mwifiex_cfg80211_inform_ibss_bss(priv))
+ return -EFAULT;
+ }
+
+ return ret;
+}
+
+/*
+ * CFG802.11 operation handler for association request.
+ *
+ * This function does not work when the current mode is set to Ad-Hoc, or
+ * when there is already an association procedure going on. The given BSS
+ * information is used to associate.
+ */
+static int
+mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_connect_params *sme)
+{
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+ int ret = 0;
+
+ if (priv->assoc_request)
+ return -EBUSY;
+
+ if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
+ wiphy_err(wiphy, "received infra assoc request "
+ "when station is in ibss mode\n");
+ goto done;
+ }
+
+ priv->assoc_request = -EINPROGRESS;
+
+ wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n",
+ (char *) sme->ssid, sme->bssid);
+
+ ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid,
+ priv->bss_mode, sme->channel, sme, 0);
+
+ priv->assoc_request = 1;
+done:
+ priv->assoc_result = ret;
+ queue_work(priv->workqueue, &priv->cfg_workqueue);
+ return ret;
+}
+
+/*
+ * CFG802.11 operation handler to join an IBSS.
+ *
+ * This function does not work in any mode other than Ad-Hoc, or if
+ * a join operation is already in progress.
+ */
+static int
+mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_ibss_params *params)
+{
+ struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+ int ret = 0;
+
+ if (priv->ibss_join_request)
+ return -EBUSY;
+
+ if (priv->bss_mode != NL80211_IFTYPE_ADHOC) {
+ wiphy_err(wiphy, "request to join ibss received "
+ "when station is not in ibss mode\n");
+ goto done;
+ }
+
+ priv->ibss_join_request = -EINPROGRESS;
+
+ wiphy_dbg(wiphy, "info: trying to join to %s and bssid %pM\n",
+ (char *) params->ssid, params->bssid);
+
+ ret = mwifiex_cfg80211_assoc(priv, params->ssid_len, params->ssid,
+ params->bssid, priv->bss_mode,
+ params->channel, NULL, params->privacy);
+
+ priv->ibss_join_request = 1;
+done:
+ priv->ibss_join_result = ret;
+ queue_work(priv->workqueue, &priv->cfg_workqueue);
+ return ret;
+}
+
+/*
+ * CFG802.11 operation handler to leave an IBSS.
+ *
+ * This function does not work if a leave operation is
+ * already in progress.
+ */
+static int
+mwifiex_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
+{
+ struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
+
+ if (priv->disconnect)
+ return -EBUSY;
+
+ priv->disconnect = 1;
+
+ wiphy_dbg(wiphy, "info: disconnecting from essid %pM\n",
+ priv->cfg_bssid);
+ if (mwifiex_deauthenticate(priv, NULL))
+ return -EFAULT;
+
+ queue_work(priv->workqueue, &priv->cfg_workqueue);
+
+ return 0;
+}
+
+/*
+ * CFG802.11 operation handler for scan request.
+ *
+ * This function issues a scan request to the firmware based upon
+ * the user specified scan configuration. On successfull completion,
+ * it also informs the results.
+ */
+static int
+mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_scan_request *request)
+{
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+
+ wiphy_dbg(wiphy, "info: received scan request on %s\n", dev->name);
+
+ if (priv->scan_request && priv->scan_request != request)
+ return -EBUSY;
+
+ priv->scan_request = request;
+
+ queue_work(priv->workqueue, &priv->cfg_workqueue);
+ return 0;
+}
+
+/*
+ * This function sets up the CFG802.11 specific HT capability fields
+ * with default values.
+ *
+ * The following default values are set -
+ * - HT Supported = True
+ * - Maximum AMPDU length factor = IEEE80211_HT_MAX_AMPDU_64K
+ * - Minimum AMPDU spacing = IEEE80211_HT_MPDU_DENSITY_NONE
+ * - HT Capabilities supported by firmware
+ * - MCS information, Rx mask = 0xff
+ * - MCD information, Tx parameters = IEEE80211_HT_MCS_TX_DEFINED (0x01)
+ */
+static void
+mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info,
+ struct mwifiex_private *priv)
+{
+ int rx_mcs_supp;
+ struct ieee80211_mcs_info mcs_set;
+ u8 *mcs = (u8 *)&mcs_set;
+ struct mwifiex_adapter *adapter = priv->adapter;
+
+ ht_info->ht_supported = true;
+ ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+ ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE;
+
+ memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
+
+ /* Fill HT capability information */
+ if (ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap))
+ ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ else
+ ht_info->cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+
+ if (ISSUPP_SHORTGI20(adapter->hw_dot_11n_dev_cap))
+ ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
+ else
+ ht_info->cap &= ~IEEE80211_HT_CAP_SGI_20;
+
+ if (ISSUPP_SHORTGI40(adapter->hw_dot_11n_dev_cap))
+ ht_info->cap |= IEEE80211_HT_CAP_SGI_40;
+ else
+ ht_info->cap &= ~IEEE80211_HT_CAP_SGI_40;
+
+ if (ISSUPP_RXSTBC(adapter->hw_dot_11n_dev_cap))
+ ht_info->cap |= 1 << IEEE80211_HT_CAP_RX_STBC_SHIFT;
+ else
+ ht_info->cap &= ~(3 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
+
+ if (ISSUPP_TXSTBC(adapter->hw_dot_11n_dev_cap))
+ ht_info->cap |= IEEE80211_HT_CAP_TX_STBC;
+ else
+ ht_info->cap &= ~IEEE80211_HT_CAP_TX_STBC;
+
+ ht_info->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU;
+ ht_info->cap |= IEEE80211_HT_CAP_SM_PS;
+
+ rx_mcs_supp = GET_RXMCSSUPP(adapter->hw_dev_mcs_support);
+ /* Set MCS for 1x1 */
+ memset(mcs, 0xff, rx_mcs_supp);
+ /* Clear all the other values */
+ memset(&mcs[rx_mcs_supp], 0,
+ sizeof(struct ieee80211_mcs_info) - rx_mcs_supp);
+ if (priv->bss_mode == NL80211_IFTYPE_STATION ||
+ ISSUPP_CHANWIDTH40(adapter->hw_dot_11n_dev_cap))
+ /* Set MCS32 for infra mode or ad-hoc mode with 40MHz support */
+ SETHT_MCS32(mcs_set.rx_mask);
+
+ memcpy((u8 *) &ht_info->mcs, mcs, sizeof(struct ieee80211_mcs_info));
+
+ ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+}
+
+/* station cfg80211 operations */
+static struct cfg80211_ops mwifiex_cfg80211_ops = {
+ .change_virtual_intf = mwifiex_cfg80211_change_virtual_intf,
+ .scan = mwifiex_cfg80211_scan,
+ .connect = mwifiex_cfg80211_connect,
+ .disconnect = mwifiex_cfg80211_disconnect,
+ .get_station = mwifiex_cfg80211_get_station,
+ .set_wiphy_params = mwifiex_cfg80211_set_wiphy_params,
+ .set_channel = mwifiex_cfg80211_set_channel,
+ .join_ibss = mwifiex_cfg80211_join_ibss,
+ .leave_ibss = mwifiex_cfg80211_leave_ibss,
+ .add_key = mwifiex_cfg80211_add_key,
+ .del_key = mwifiex_cfg80211_del_key,
+ .set_default_key = mwifiex_cfg80211_set_default_key,
+ .set_power_mgmt = mwifiex_cfg80211_set_power_mgmt,
+ .set_tx_power = mwifiex_cfg80211_set_tx_power,
+};
+
+/*
+ * This function registers the device with CFG802.11 subsystem.
+ *
+ * The function creates the wireless device/wiphy, populates it with
+ * default parameters and handler function pointers, and finally
+ * registers the device.
+ */
+int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac,
+ struct mwifiex_private *priv)
+{
+ int ret;
+ void *wdev_priv;
+ struct wireless_dev *wdev;
+
+ wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+ if (!wdev) {
+ dev_err(priv->adapter->dev, "%s: allocating wireless device\n",
+ __func__);
+ return -ENOMEM;
+ }
+ wdev->wiphy =
+ wiphy_new(&mwifiex_cfg80211_ops,
+ sizeof(struct mwifiex_private *));
+ if (!wdev->wiphy) {
+ kfree(wdev);
+ return -ENOMEM;
+ }
+ wdev->iftype = NL80211_IFTYPE_STATION;
+ wdev->wiphy->max_scan_ssids = 10;
+ wdev->wiphy->interface_modes =
+ BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
+
+ wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &mwifiex_band_2ghz;
+ mwifiex_setup_ht_caps(
+ &wdev->wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap, priv);
+
+ if (priv->adapter->config_bands & BAND_A) {
+ wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &mwifiex_band_5ghz;
+ mwifiex_setup_ht_caps(
+ &wdev->wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap, priv);
+ } else {
+ wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
+ }
+
+ /* Initialize cipher suits */
+ wdev->wiphy->cipher_suites = mwifiex_cipher_suites;
+ wdev->wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites);
+
+ memcpy(wdev->wiphy->perm_addr, mac, 6);
+ wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+
+ /* We are using custom domains */
+ wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
+
+ wdev->wiphy->reg_notifier = mwifiex_reg_notifier;
+
+ /* Set struct mwifiex_private pointer in wiphy_priv */
+ wdev_priv = wiphy_priv(wdev->wiphy);
+
+ *(unsigned long *) wdev_priv = (unsigned long) priv;
+
+ ret = wiphy_register(wdev->wiphy);
+ if (ret < 0) {
+ dev_err(priv->adapter->dev, "%s: registering cfg80211 device\n",
+ __func__);
+ wiphy_free(wdev->wiphy);
+ kfree(wdev);
+ return ret;
+ } else {
+ dev_dbg(priv->adapter->dev,
+ "info: successfully registered wiphy device\n");
+ }
+
+ dev_net_set(dev, wiphy_net(wdev->wiphy));
+ dev->ieee80211_ptr = wdev;
+ memcpy(dev->dev_addr, wdev->wiphy->perm_addr, 6);
+ memcpy(dev->perm_addr, wdev->wiphy->perm_addr, 6);
+ SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy));
+ priv->wdev = wdev;
+
+ dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
+ dev->watchdog_timeo = MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT;
+ dev->hard_header_len += MWIFIEX_MIN_DATA_HEADER_LEN;
+
+ return ret;
+}
+
+/*
+ * This function handles the result of different pending network operations.
+ *
+ * The following operations are handled and CFG802.11 subsystem is
+ * notified accordingly -
+ * - Scan request completion
+ * - Association request completion
+ * - IBSS join request completion
+ * - Disconnect request completion
+ */
+void
+mwifiex_cfg80211_results(struct work_struct *work)
+{
+ struct mwifiex_private *priv =
+ container_of(work, struct mwifiex_private, cfg_workqueue);
+ struct mwifiex_user_scan_cfg *scan_req;
+ int ret = 0, i;
+ struct ieee80211_channel *chan;
+
+ if (priv->scan_request) {
+ scan_req = kzalloc(sizeof(struct mwifiex_user_scan_cfg),
+ GFP_KERNEL);
+ if (!scan_req) {
+ dev_err(priv->adapter->dev, "failed to alloc "
+ "scan_req\n");
+ return;
+ }
+ for (i = 0; i < priv->scan_request->n_ssids; i++) {
+ memcpy(scan_req->ssid_list[i].ssid,
+ priv->scan_request->ssids[i].ssid,
+ priv->scan_request->ssids[i].ssid_len);
+ scan_req->ssid_list[i].max_len =
+ priv->scan_request->ssids[i].ssid_len;
+ }
+ for (i = 0; i < priv->scan_request->n_channels; i++) {
+ chan = priv->scan_request->channels[i];
+ scan_req->chan_list[i].chan_number = chan->hw_value;
+ scan_req->chan_list[i].radio_type = chan->band;
+ if (chan->flags & IEEE80211_CHAN_DISABLED)
+ scan_req->chan_list[i].scan_type =
+ MWIFIEX_SCAN_TYPE_PASSIVE;
+ else
+ scan_req->chan_list[i].scan_type =
+ MWIFIEX_SCAN_TYPE_ACTIVE;
+ scan_req->chan_list[i].scan_time = 0;
+ }
+ if (mwifiex_set_user_scan_ioctl(priv, scan_req)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (mwifiex_inform_bss_from_scan_result(priv, NULL))
+ ret = -EFAULT;
+done:
+ priv->scan_result_status = ret;
+ dev_dbg(priv->adapter->dev, "info: %s: sending scan results\n",
+ __func__);
+ cfg80211_scan_done(priv->scan_request,
+ (priv->scan_result_status < 0));
+ priv->scan_request = NULL;
+ kfree(scan_req);
+ }
+
+ if (priv->assoc_request == 1) {
+ if (!priv->assoc_result) {
+ cfg80211_connect_result(priv->netdev, priv->cfg_bssid,
+ NULL, 0, NULL, 0,
+ WLAN_STATUS_SUCCESS,
+ GFP_KERNEL);
+ dev_dbg(priv->adapter->dev,
+ "info: associated to bssid %pM successfully\n",
+ priv->cfg_bssid);
+ } else {
+ dev_dbg(priv->adapter->dev,
+ "info: association to bssid %pM failed\n",
+ priv->cfg_bssid);
+ memset(priv->cfg_bssid, 0, ETH_ALEN);
+ }
+ priv->assoc_request = 0;
+ priv->assoc_result = 0;
+ }
+
+ if (priv->ibss_join_request == 1) {
+ if (!priv->ibss_join_result) {
+ cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid,
+ GFP_KERNEL);
+ dev_dbg(priv->adapter->dev,
+ "info: joined/created adhoc network with bssid"
+ " %pM successfully\n", priv->cfg_bssid);
+ } else {
+ dev_dbg(priv->adapter->dev,
+ "info: failed creating/joining adhoc network\n");
+ }
+ priv->ibss_join_request = 0;
+ priv->ibss_join_result = 0;
+ }
+
+ if (priv->disconnect) {
+ memset(priv->cfg_bssid, 0, ETH_ALEN);
+ priv->disconnect = 0;
+ }
+}
diff --git a/drivers/net/wireless/mwifiex/cfg80211.h b/drivers/net/wireless/mwifiex/cfg80211.h
new file mode 100644
index 000000000000..c4db8f36aa16
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/cfg80211.h
@@ -0,0 +1,31 @@
+/*
+ * Marvell Wireless LAN device driver: CFG80211
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef __MWIFIEX_CFG80211__
+#define __MWIFIEX_CFG80211__
+
+#include <net/cfg80211.h>
+
+#include "main.h"
+
+int mwifiex_register_cfg80211(struct net_device *, u8 *,
+ struct mwifiex_private *);
+
+void mwifiex_cfg80211_results(struct work_struct *work);
+#endif
diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c
new file mode 100644
index 000000000000..d0cada5a29a0
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/cfp.c
@@ -0,0 +1,360 @@
+/*
+ * Marvell Wireless LAN device driver: Channel, Frequence and Power
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "cfg80211.h"
+
+/* 100mW */
+#define MWIFIEX_TX_PWR_DEFAULT 20
+/* 100mW */
+#define MWIFIEX_TX_PWR_US_DEFAULT 20
+/* 50mW */
+#define MWIFIEX_TX_PWR_JP_DEFAULT 16
+/* 100mW */
+#define MWIFIEX_TX_PWR_FR_100MW 20
+/* 10mW */
+#define MWIFIEX_TX_PWR_FR_10MW 10
+/* 100mW */
+#define MWIFIEX_TX_PWR_EMEA_DEFAULT 20
+
+static u8 adhoc_rates_b[B_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96, 0 };
+
+static u8 adhoc_rates_g[G_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24,
+ 0xb0, 0x48, 0x60, 0x6c, 0 };
+
+static u8 adhoc_rates_bg[BG_SUPPORTED_RATES] = { 0x82, 0x84, 0x8b, 0x96,
+ 0x0c, 0x12, 0x18, 0x24,
+ 0x30, 0x48, 0x60, 0x6c, 0 };
+
+static u8 adhoc_rates_a[A_SUPPORTED_RATES] = { 0x8c, 0x12, 0x98, 0x24,
+ 0xb0, 0x48, 0x60, 0x6c, 0 };
+u8 supported_rates_a[A_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24,
+ 0xb0, 0x48, 0x60, 0x6c, 0 };
+static u16 mwifiex_data_rates[MWIFIEX_SUPPORTED_RATES_EXT] = { 0x02, 0x04,
+ 0x0B, 0x16, 0x00, 0x0C, 0x12, 0x18,
+ 0x24, 0x30, 0x48, 0x60, 0x6C, 0x90,
+ 0x0D, 0x1A, 0x27, 0x34, 0x4E, 0x68,
+ 0x75, 0x82, 0x0C, 0x1B, 0x36, 0x51,
+ 0x6C, 0xA2, 0xD8, 0xF3, 0x10E, 0x00 };
+
+u8 supported_rates_b[B_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0 };
+
+u8 supported_rates_g[G_SUPPORTED_RATES] = { 0x0c, 0x12, 0x18, 0x24,
+ 0x30, 0x48, 0x60, 0x6c, 0 };
+
+u8 supported_rates_bg[BG_SUPPORTED_RATES] = { 0x02, 0x04, 0x0b, 0x0c,
+ 0x12, 0x16, 0x18, 0x24, 0x30, 0x48,
+ 0x60, 0x6c, 0 };
+
+u16 region_code_index[MWIFIEX_MAX_REGION_CODE] = { 0x10, 0x20, 0x30,
+ 0x32, 0x40, 0x41, 0xff };
+
+u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 };
+
+/*
+ * This function maps an index in supported rates table into
+ * the corresponding data rate.
+ */
+u32 mwifiex_index_to_data_rate(u8 index, u8 ht_info)
+{
+ u16 mcs_rate[4][8] = {
+ {0x1b, 0x36, 0x51, 0x6c, 0xa2, 0xd8, 0xf3, 0x10e}
+ , /* LG 40M */
+ {0x1e, 0x3c, 0x5a, 0x78, 0xb4, 0xf0, 0x10e, 0x12c}
+ , /* SG 40M */
+ {0x0d, 0x1a, 0x27, 0x34, 0x4e, 0x68, 0x75, 0x82}
+ , /* LG 20M */
+ {0x0e, 0x1c, 0x2b, 0x39, 0x56, 0x73, 0x82, 0x90}
+ }; /* SG 20M */
+
+ u32 rate;
+
+ if (ht_info & BIT(0)) {
+ if (index == MWIFIEX_RATE_BITMAP_MCS0) {
+ if (ht_info & BIT(2))
+ rate = 0x0D; /* MCS 32 SGI rate */
+ else
+ rate = 0x0C; /* MCS 32 LGI rate */
+ } else if (index < 8) {
+ if (ht_info & BIT(1)) {
+ if (ht_info & BIT(2))
+ /* SGI, 40M */
+ rate = mcs_rate[1][index];
+ else
+ /* LGI, 40M */
+ rate = mcs_rate[0][index];
+ } else {
+ if (ht_info & BIT(2))
+ /* SGI, 20M */
+ rate = mcs_rate[3][index];
+ else
+ /* LGI, 20M */
+ rate = mcs_rate[2][index];
+ }
+ } else
+ rate = mwifiex_data_rates[0];
+ } else {
+ if (index >= MWIFIEX_SUPPORTED_RATES_EXT)
+ index = 0;
+ rate = mwifiex_data_rates[index];
+ }
+ return rate;
+}
+
+/*
+ * This function maps a data rate value into corresponding index in supported
+ * rates table.
+ */
+u8 mwifiex_data_rate_to_index(u32 rate)
+{
+ u16 *ptr;
+
+ if (rate) {
+ ptr = memchr(mwifiex_data_rates, rate,
+ sizeof(mwifiex_data_rates));
+ if (ptr)
+ return (u8) (ptr - mwifiex_data_rates);
+ }
+ return 0;
+}
+
+/*
+ * This function returns the current active data rates.
+ *
+ * The result may vary depending upon connection status.
+ */
+u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv, u8 *rates)
+{
+ if (!priv->media_connected)
+ return mwifiex_get_supported_rates(priv, rates);
+ else
+ return mwifiex_copy_rates(rates, 0,
+ priv->curr_bss_params.data_rates,
+ priv->curr_bss_params.num_of_rates);
+}
+
+/*
+ * This function locates the Channel-Frequency-Power triplet based upon
+ * band and channel parameters.
+ */
+struct mwifiex_chan_freq_power *
+mwifiex_get_cfp_by_band_and_channel_from_cfg80211(struct mwifiex_private
+ *priv, u8 band, u16 channel)
+{
+ struct mwifiex_chan_freq_power *cfp = NULL;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *ch;
+ int i;
+
+ if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG)
+ sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ];
+ else
+ sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ];
+
+ if (!sband) {
+ dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d"
+ " & channel %d\n", __func__, band, channel);
+ return cfp;
+ }
+
+ for (i = 0; i < sband->n_channels; i++) {
+ ch = &sband->channels[i];
+ if (((ch->hw_value == channel) ||
+ (channel == FIRST_VALID_CHANNEL))
+ && !(ch->flags & IEEE80211_CHAN_DISABLED)) {
+ priv->cfp.channel = channel;
+ priv->cfp.freq = ch->center_freq;
+ priv->cfp.max_tx_power = ch->max_power;
+ cfp = &priv->cfp;
+ break;
+ }
+ }
+ if (i == sband->n_channels)
+ dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d"
+ " & channel %d\n", __func__, band, channel);
+
+ return cfp;
+}
+
+/*
+ * This function locates the Channel-Frequency-Power triplet based upon
+ * band and frequency parameters.
+ */
+struct mwifiex_chan_freq_power *
+mwifiex_get_cfp_by_band_and_freq_from_cfg80211(struct mwifiex_private *priv,
+ u8 band, u32 freq)
+{
+ struct mwifiex_chan_freq_power *cfp = NULL;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *ch;
+ int i;
+
+ if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG)
+ sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ];
+ else
+ sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ];
+
+ if (!sband) {
+ dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d"
+ " & freq %d\n", __func__, band, freq);
+ return cfp;
+ }
+
+ for (i = 0; i < sband->n_channels; i++) {
+ ch = &sband->channels[i];
+ if ((ch->center_freq == freq) &&
+ !(ch->flags & IEEE80211_CHAN_DISABLED)) {
+ priv->cfp.channel = ch->hw_value;
+ priv->cfp.freq = freq;
+ priv->cfp.max_tx_power = ch->max_power;
+ cfp = &priv->cfp;
+ break;
+ }
+ }
+ if (i == sband->n_channels)
+ dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d"
+ " & freq %d\n", __func__, band, freq);
+
+ return cfp;
+}
+
+/*
+ * This function checks if the data rate is set to auto.
+ */
+u8
+mwifiex_is_rate_auto(struct mwifiex_private *priv)
+{
+ u32 i;
+ int rate_num = 0;
+
+ for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates); i++)
+ if (priv->bitmap_rates[i])
+ rate_num++;
+
+ if (rate_num > 1)
+ return true;
+ else
+ return false;
+}
+
+/*
+ * This function converts rate bitmap into rate index.
+ */
+int mwifiex_get_rate_index(u16 *rate_bitmap, int size)
+{
+ int i;
+
+ for (i = 0; i < size * 8; i++)
+ if (rate_bitmap[i / 16] & (1 << (i % 16)))
+ return i;
+
+ return 0;
+}
+
+/*
+ * This function gets the supported data rates.
+ *
+ * The function works in both Ad-Hoc and infra mode by printing the
+ * band and returning the data rates.
+ */
+u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
+{
+ u32 k = 0;
+ struct mwifiex_adapter *adapter = priv->adapter;
+ if (priv->bss_mode == NL80211_IFTYPE_STATION) {
+ switch (adapter->config_bands) {
+ case BAND_B:
+ dev_dbg(adapter->dev, "info: infra band=%d "
+ "supported_rates_b\n", adapter->config_bands);
+ k = mwifiex_copy_rates(rates, k, supported_rates_b,
+ sizeof(supported_rates_b));
+ break;
+ case BAND_G:
+ case BAND_G | BAND_GN:
+ dev_dbg(adapter->dev, "info: infra band=%d "
+ "supported_rates_g\n", adapter->config_bands);
+ k = mwifiex_copy_rates(rates, k, supported_rates_g,
+ sizeof(supported_rates_g));
+ break;
+ case BAND_B | BAND_G:
+ case BAND_A | BAND_B | BAND_G:
+ case BAND_A | BAND_B:
+ case BAND_A | BAND_B | BAND_G | BAND_GN | BAND_AN:
+ case BAND_B | BAND_G | BAND_GN:
+ dev_dbg(adapter->dev, "info: infra band=%d "
+ "supported_rates_bg\n", adapter->config_bands);
+ k = mwifiex_copy_rates(rates, k, supported_rates_bg,
+ sizeof(supported_rates_bg));
+ break;
+ case BAND_A:
+ case BAND_A | BAND_G:
+ dev_dbg(adapter->dev, "info: infra band=%d "
+ "supported_rates_a\n", adapter->config_bands);
+ k = mwifiex_copy_rates(rates, k, supported_rates_a,
+ sizeof(supported_rates_a));
+ break;
+ case BAND_A | BAND_AN:
+ case BAND_A | BAND_G | BAND_AN | BAND_GN:
+ dev_dbg(adapter->dev, "info: infra band=%d "
+ "supported_rates_a\n", adapter->config_bands);
+ k = mwifiex_copy_rates(rates, k, supported_rates_a,
+ sizeof(supported_rates_a));
+ break;
+ case BAND_GN:
+ dev_dbg(adapter->dev, "info: infra band=%d "
+ "supported_rates_n\n", adapter->config_bands);
+ k = mwifiex_copy_rates(rates, k, supported_rates_n,
+ sizeof(supported_rates_n));
+ break;
+ }
+ } else {
+ /* Ad-hoc mode */
+ switch (adapter->adhoc_start_band) {
+ case BAND_B:
+ dev_dbg(adapter->dev, "info: adhoc B\n");
+ k = mwifiex_copy_rates(rates, k, adhoc_rates_b,
+ sizeof(adhoc_rates_b));
+ break;
+ case BAND_G:
+ case BAND_G | BAND_GN:
+ dev_dbg(adapter->dev, "info: adhoc G only\n");
+ k = mwifiex_copy_rates(rates, k, adhoc_rates_g,
+ sizeof(adhoc_rates_g));
+ break;
+ case BAND_B | BAND_G:
+ case BAND_B | BAND_G | BAND_GN:
+ dev_dbg(adapter->dev, "info: adhoc BG\n");
+ k = mwifiex_copy_rates(rates, k, adhoc_rates_bg,
+ sizeof(adhoc_rates_bg));
+ break;
+ case BAND_A:
+ case BAND_A | BAND_AN:
+ dev_dbg(adapter->dev, "info: adhoc A\n");
+ k = mwifiex_copy_rates(rates, k, adhoc_rates_a,
+ sizeof(adhoc_rates_a));
+ break;
+ }
+ }
+
+ return k;
+}
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
new file mode 100644
index 000000000000..cd89fed206ae
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -0,0 +1,1414 @@
+/*
+ * Marvell Wireless LAN device driver: commands and events
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+
+/*
+ * This function initializes a command node.
+ *
+ * The actual allocation of the node is not done by this function. It only
+ * initiates a node by filling it with default parameters. Similarly,
+ * allocation of the different buffers used (IOCTL buffer, data buffer) are
+ * not done by this function either.
+ */
+static void
+mwifiex_init_cmd_node(struct mwifiex_private *priv,
+ struct cmd_ctrl_node *cmd_node,
+ u32 cmd_oid, void *data_buf)
+{
+ cmd_node->priv = priv;
+ cmd_node->cmd_oid = cmd_oid;
+ cmd_node->wait_q_enabled = priv->adapter->cmd_wait_q_required;
+ priv->adapter->cmd_wait_q_required = false;
+ cmd_node->data_buf = data_buf;
+ cmd_node->cmd_skb = cmd_node->skb;
+}
+
+/*
+ * This function returns a command node from the free queue depending upon
+ * availability.
+ */
+static struct cmd_ctrl_node *
+mwifiex_get_cmd_node(struct mwifiex_adapter *adapter)
+{
+ struct cmd_ctrl_node *cmd_node;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->cmd_free_q_lock, flags);
+ if (list_empty(&adapter->cmd_free_q)) {
+ dev_err(adapter->dev, "GET_CMD_NODE: cmd node not available\n");
+ spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags);
+ return NULL;
+ }
+ cmd_node = list_first_entry(&adapter->cmd_free_q,
+ struct cmd_ctrl_node, list);
+ list_del(&cmd_node->list);
+ spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags);
+
+ return cmd_node;
+}
+
+/*
+ * This function cleans up a command node.
+ *
+ * The function resets the fields including the buffer pointers.
+ * This function does not try to free the buffers. They must be
+ * freed before calling this function.
+ *
+ * This function will however call the receive completion callback
+ * in case a response buffer is still available before resetting
+ * the pointer.
+ */
+static void
+mwifiex_clean_cmd_node(struct mwifiex_adapter *adapter,
+ struct cmd_ctrl_node *cmd_node)
+{
+ cmd_node->cmd_oid = 0;
+ cmd_node->cmd_flag = 0;
+ cmd_node->data_buf = NULL;
+ cmd_node->wait_q_enabled = false;
+
+ if (cmd_node->resp_skb) {
+ dev_kfree_skb_any(cmd_node->resp_skb);
+ cmd_node->resp_skb = NULL;
+ }
+}
+
+/*
+ * This function sends a host command to the firmware.
+ *
+ * The function copies the host command into the driver command
+ * buffer, which will be transferred to the firmware later by the
+ * main thread.
+ */
+static int mwifiex_cmd_host_cmd(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd, void *data_buf)
+{
+ struct mwifiex_ds_misc_cmd *pcmd_ptr =
+ (struct mwifiex_ds_misc_cmd *) data_buf;
+
+ /* Copy the HOST command to command buffer */
+ memcpy((void *) cmd, pcmd_ptr->cmd, pcmd_ptr->len);
+ dev_dbg(priv->adapter->dev, "cmd: host cmd size = %d\n", pcmd_ptr->len);
+ return 0;
+}
+
+/*
+ * This function downloads a command to the firmware.
+ *
+ * The function performs sanity tests, sets the command sequence
+ * number and size, converts the header fields to CPU format before
+ * sending. Afterwards, it logs the command ID and action for debugging
+ * and sets up the command timeout timer.
+ */
+static int mwifiex_dnld_cmd_to_fw(struct mwifiex_private *priv,
+ struct cmd_ctrl_node *cmd_node)
+{
+
+ struct mwifiex_adapter *adapter = priv->adapter;
+ int ret;
+ struct host_cmd_ds_command *host_cmd;
+ uint16_t cmd_code;
+ uint16_t cmd_size;
+ struct timeval tstamp;
+ unsigned long flags;
+
+ if (!adapter || !cmd_node)
+ return -1;
+
+ host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data);
+
+ /* Sanity test */
+ if (host_cmd == NULL || host_cmd->size == 0) {
+ dev_err(adapter->dev, "DNLD_CMD: host_cmd is null"
+ " or cmd size is 0, not sending\n");
+ if (cmd_node->wait_q_enabled)
+ adapter->cmd_wait_q.status = -1;
+ mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+ return -1;
+ }
+
+ /* Set command sequence number */
+ adapter->seq_num++;
+ host_cmd->seq_num = cpu_to_le16(HostCmd_SET_SEQ_NO_BSS_INFO
+ (adapter->seq_num, cmd_node->priv->bss_num,
+ cmd_node->priv->bss_type));
+
+ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ adapter->curr_cmd = cmd_node;
+ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+
+ cmd_code = le16_to_cpu(host_cmd->command);
+ cmd_size = le16_to_cpu(host_cmd->size);
+
+ skb_trim(cmd_node->cmd_skb, cmd_size);
+
+ do_gettimeofday(&tstamp);
+ dev_dbg(adapter->dev, "cmd: DNLD_CMD: (%lu.%lu): %#x, act %#x, len %d,"
+ " seqno %#x\n",
+ tstamp.tv_sec, tstamp.tv_usec, cmd_code,
+ le16_to_cpu(*(__le16 *) ((u8 *) host_cmd + S_DS_GEN)), cmd_size,
+ le16_to_cpu(host_cmd->seq_num));
+
+ skb_push(cmd_node->cmd_skb, INTF_HEADER_LEN);
+
+ ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD,
+ cmd_node->cmd_skb->data,
+ cmd_node->cmd_skb->len, NULL);
+
+ skb_pull(cmd_node->cmd_skb, INTF_HEADER_LEN);
+
+ if (ret == -1) {
+ dev_err(adapter->dev, "DNLD_CMD: host to card failed\n");
+ if (cmd_node->wait_q_enabled)
+ adapter->cmd_wait_q.status = -1;
+ mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
+
+ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ adapter->curr_cmd = NULL;
+ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+
+ adapter->dbg.num_cmd_host_to_card_failure++;
+ return -1;
+ }
+
+ /* Save the last command id and action to debug log */
+ adapter->dbg.last_cmd_index =
+ (adapter->dbg.last_cmd_index + 1) % DBG_CMD_NUM;
+ adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index] = cmd_code;
+ adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index] =
+ le16_to_cpu(*(__le16 *) ((u8 *) host_cmd + S_DS_GEN));
+
+ /* Clear BSS_NO_BITS from HostCmd */
+ cmd_code &= HostCmd_CMD_ID_MASK;
+
+ /* Setup the timer after transmit command */
+ mod_timer(&adapter->cmd_timer,
+ jiffies + (MWIFIEX_TIMER_10S * HZ) / 1000);
+
+ return 0;
+}
+
+/*
+ * This function downloads a sleep confirm command to the firmware.
+ *
+ * The function performs sanity tests, sets the command sequence
+ * number and size, converts the header fields to CPU format before
+ * sending.
+ *
+ * No responses are needed for sleep confirm command.
+ */
+static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter)
+{
+ int ret;
+ struct mwifiex_private *priv;
+ struct mwifiex_opt_sleep_confirm *sleep_cfm_buf =
+ (struct mwifiex_opt_sleep_confirm *)
+ adapter->sleep_cfm->data;
+ priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+
+ sleep_cfm_buf->seq_num =
+ cpu_to_le16((HostCmd_SET_SEQ_NO_BSS_INFO
+ (adapter->seq_num, priv->bss_num,
+ priv->bss_type)));
+ adapter->seq_num++;
+
+ skb_push(adapter->sleep_cfm, INTF_HEADER_LEN);
+ ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD,
+ adapter->sleep_cfm->data,
+ adapter->sleep_cfm->len, NULL);
+ skb_pull(adapter->sleep_cfm, INTF_HEADER_LEN);
+
+ if (ret == -1) {
+ dev_err(adapter->dev, "SLEEP_CFM: failed\n");
+ adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++;
+ return -1;
+ }
+ if (GET_BSS_ROLE(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY))
+ == MWIFIEX_BSS_ROLE_STA) {
+ if (!sleep_cfm_buf->resp_ctrl)
+ /* Response is not needed for sleep
+ confirm command */
+ adapter->ps_state = PS_STATE_SLEEP;
+ else
+ adapter->ps_state = PS_STATE_SLEEP_CFM;
+
+ if (!sleep_cfm_buf->resp_ctrl
+ && (adapter->is_hs_configured
+ && !adapter->sleep_period.period)) {
+ adapter->pm_wakeup_card_req = true;
+ mwifiex_hs_activated_event(mwifiex_get_priv(adapter,
+ MWIFIEX_BSS_ROLE_STA), true);
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * This function allocates the command buffers and links them to
+ * the command free queue.
+ *
+ * The driver uses a pre allocated number of command buffers, which
+ * are created at driver initializations and freed at driver cleanup.
+ * Every command needs to obtain a command buffer from this pool before
+ * it can be issued. The command free queue lists the command buffers
+ * currently free to use, while the command pending queue lists the
+ * command buffers already in use and awaiting handling. Command buffers
+ * are returned to the free queue after use.
+ */
+int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter)
+{
+ struct cmd_ctrl_node *cmd_array;
+ u32 buf_size;
+ u32 i;
+
+ /* Allocate and initialize struct cmd_ctrl_node */
+ buf_size = sizeof(struct cmd_ctrl_node) * MWIFIEX_NUM_OF_CMD_BUFFER;
+ cmd_array = kzalloc(buf_size, GFP_KERNEL);
+ if (!cmd_array) {
+ dev_err(adapter->dev, "%s: failed to alloc cmd_array\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ adapter->cmd_pool = cmd_array;
+ memset(adapter->cmd_pool, 0, buf_size);
+
+ /* Allocate and initialize command buffers */
+ for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) {
+ cmd_array[i].skb = dev_alloc_skb(MWIFIEX_SIZE_OF_CMD_BUFFER);
+ if (!cmd_array[i].skb) {
+ dev_err(adapter->dev, "ALLOC_CMD_BUF: out of memory\n");
+ return -1;
+ }
+ }
+
+ for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++)
+ mwifiex_insert_cmd_to_free_q(adapter, &cmd_array[i]);
+
+ return 0;
+}
+
+/*
+ * This function frees the command buffers.
+ *
+ * The function calls the completion callback for all the command
+ * buffers that still have response buffers associated with them.
+ */
+int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter)
+{
+ struct cmd_ctrl_node *cmd_array;
+ u32 i;
+
+ /* Need to check if cmd pool is allocated or not */
+ if (!adapter->cmd_pool) {
+ dev_dbg(adapter->dev, "info: FREE_CMD_BUF: cmd_pool is null\n");
+ return 0;
+ }
+
+ cmd_array = adapter->cmd_pool;
+
+ /* Release shared memory buffers */
+ for (i = 0; i < MWIFIEX_NUM_OF_CMD_BUFFER; i++) {
+ if (cmd_array[i].skb) {
+ dev_dbg(adapter->dev, "cmd: free cmd buffer %d\n", i);
+ dev_kfree_skb_any(cmd_array[i].skb);
+ }
+ if (!cmd_array[i].resp_skb)
+ continue;
+ dev_kfree_skb_any(cmd_array[i].resp_skb);
+ }
+ /* Release struct cmd_ctrl_node */
+ if (adapter->cmd_pool) {
+ dev_dbg(adapter->dev, "cmd: free cmd pool\n");
+ kfree(adapter->cmd_pool);
+ adapter->cmd_pool = NULL;
+ }
+
+ return 0;
+}
+
+/*
+ * This function handles events generated by firmware.
+ *
+ * Event body of events received from firmware are not used (though they are
+ * saved), only the event ID is used. Some events are re-invoked by
+ * the driver, with a new event body.
+ *
+ * After processing, the function calls the completion callback
+ * for cleanup.
+ */
+int mwifiex_process_event(struct mwifiex_adapter *adapter)
+{
+ int ret;
+ struct mwifiex_private *priv =
+ mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+ struct sk_buff *skb = adapter->event_skb;
+ u32 eventcause = adapter->event_cause;
+ struct timeval tstamp;
+ struct mwifiex_rxinfo *rx_info;
+
+ /* Save the last event to debug log */
+ adapter->dbg.last_event_index =
+ (adapter->dbg.last_event_index + 1) % DBG_CMD_NUM;
+ adapter->dbg.last_event[adapter->dbg.last_event_index] =
+ (u16) eventcause;
+
+ /* Get BSS number and corresponding priv */
+ priv = mwifiex_get_priv_by_id(adapter, EVENT_GET_BSS_NUM(eventcause),
+ EVENT_GET_BSS_TYPE(eventcause));
+ if (!priv)
+ priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+ /* Clear BSS_NO_BITS from event */
+ eventcause &= EVENT_ID_MASK;
+ adapter->event_cause = eventcause;
+
+ if (skb) {
+ rx_info = MWIFIEX_SKB_RXCB(skb);
+ rx_info->bss_index = priv->bss_index;
+ }
+
+ if (eventcause != EVENT_PS_SLEEP && eventcause != EVENT_PS_AWAKE) {
+ do_gettimeofday(&tstamp);
+ dev_dbg(adapter->dev, "event: %lu.%lu: cause: %#x\n",
+ tstamp.tv_sec, tstamp.tv_usec, eventcause);
+ }
+
+ ret = mwifiex_process_sta_event(priv);
+
+ adapter->event_cause = 0;
+ adapter->event_skb = NULL;
+
+ dev_kfree_skb_any(skb);
+
+ return ret;
+}
+
+/*
+ * This function is used to send synchronous command to the firmware.
+ *
+ * it allocates a wait queue for the command and wait for the command
+ * response.
+ */
+int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no,
+ u16 cmd_action, u32 cmd_oid, void *data_buf)
+{
+ int ret = 0;
+ struct mwifiex_adapter *adapter = priv->adapter;
+
+ adapter->cmd_wait_q_required = true;
+ adapter->cmd_wait_q.condition = false;
+
+ ret = mwifiex_send_cmd_async(priv, cmd_no, cmd_action, cmd_oid,
+ data_buf);
+ if (!ret)
+ ret = mwifiex_wait_queue_complete(adapter);
+
+ return ret;
+}
+
+
+/*
+ * This function prepares a command and asynchronously send it to the firmware.
+ *
+ * Preparation includes -
+ * - Sanity tests to make sure the card is still present or the FW
+ * is not reset
+ * - Getting a new command node from the command free queue
+ * - Initializing the command node for default parameters
+ * - Fill up the non-default parameters and buffer pointers
+ * - Add the command to pending queue
+ */
+int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
+ u16 cmd_action, u32 cmd_oid, void *data_buf)
+{
+ int ret;
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *cmd_node;
+ struct host_cmd_ds_command *cmd_ptr;
+
+ if (!adapter) {
+ pr_err("PREP_CMD: adapter is NULL\n");
+ return -1;
+ }
+
+ if (adapter->is_suspended) {
+ dev_err(adapter->dev, "PREP_CMD: device in suspended state\n");
+ return -1;
+ }
+
+ if (adapter->surprise_removed) {
+ dev_err(adapter->dev, "PREP_CMD: card is removed\n");
+ return -1;
+ }
+
+ if (adapter->hw_status == MWIFIEX_HW_STATUS_RESET) {
+ if (cmd_no != HostCmd_CMD_FUNC_INIT) {
+ dev_err(adapter->dev, "PREP_CMD: FW in reset state\n");
+ return -1;
+ }
+ }
+
+ /* Get a new command node */
+ cmd_node = mwifiex_get_cmd_node(adapter);
+
+ if (!cmd_node) {
+ dev_err(adapter->dev, "PREP_CMD: no free cmd node\n");
+ return -1;
+ }
+
+ /* Initialize the command node */
+ mwifiex_init_cmd_node(priv, cmd_node, cmd_oid, data_buf);
+
+ if (!cmd_node->cmd_skb) {
+ dev_err(adapter->dev, "PREP_CMD: no free cmd buf\n");
+ return -1;
+ }
+
+ memset(skb_put(cmd_node->cmd_skb, sizeof(struct host_cmd_ds_command)),
+ 0, sizeof(struct host_cmd_ds_command));
+
+ cmd_ptr = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data);
+ cmd_ptr->command = cpu_to_le16(cmd_no);
+ cmd_ptr->result = 0;
+
+ /* Prepare command */
+ if (cmd_no) {
+ ret = mwifiex_sta_prepare_cmd(priv, cmd_no, cmd_action,
+ cmd_oid, data_buf, cmd_ptr);
+ } else {
+ ret = mwifiex_cmd_host_cmd(priv, cmd_ptr, data_buf);
+ cmd_node->cmd_flag |= CMD_F_HOSTCMD;
+ }
+
+ /* Return error, since the command preparation failed */
+ if (ret) {
+ dev_err(adapter->dev, "PREP_CMD: cmd %#x preparation failed\n",
+ cmd_no);
+ mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+ return -1;
+ }
+
+ /* Send command */
+ if (cmd_no == HostCmd_CMD_802_11_SCAN)
+ mwifiex_queue_scan_cmd(priv, cmd_node);
+ else
+ mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
+
+ return ret;
+}
+
+/*
+ * This function returns a command to the command free queue.
+ *
+ * The function also calls the completion callback if required, before
+ * cleaning the command node and re-inserting it into the free queue.
+ */
+void
+mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
+ struct cmd_ctrl_node *cmd_node)
+{
+ unsigned long flags;
+
+ if (!cmd_node)
+ return;
+
+ if (cmd_node->wait_q_enabled)
+ mwifiex_complete_cmd(adapter);
+ /* Clean the node */
+ mwifiex_clean_cmd_node(adapter, cmd_node);
+
+ /* Insert node into cmd_free_q */
+ spin_lock_irqsave(&adapter->cmd_free_q_lock, flags);
+ list_add_tail(&cmd_node->list, &adapter->cmd_free_q);
+ spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags);
+}
+
+/*
+ * This function queues a command to the command pending queue.
+ *
+ * This in effect adds the command to the command list to be executed.
+ * Exit PS command is handled specially, by placing it always to the
+ * front of the command queue.
+ */
+void
+mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter,
+ struct cmd_ctrl_node *cmd_node, u32 add_tail)
+{
+ struct host_cmd_ds_command *host_cmd = NULL;
+ u16 command;
+ unsigned long flags;
+
+ host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data);
+ if (!host_cmd) {
+ dev_err(adapter->dev, "QUEUE_CMD: host_cmd is NULL\n");
+ return;
+ }
+
+ command = le16_to_cpu(host_cmd->command);
+
+ /* Exit_PS command needs to be queued in the header always. */
+ if (command == HostCmd_CMD_802_11_PS_MODE_ENH) {
+ struct host_cmd_ds_802_11_ps_mode_enh *pm =
+ &host_cmd->params.psmode_enh;
+ if ((le16_to_cpu(pm->action) == DIS_PS)
+ || (le16_to_cpu(pm->action) == DIS_AUTO_PS)) {
+ if (adapter->ps_state != PS_STATE_AWAKE)
+ add_tail = false;
+ }
+ }
+
+ spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
+ if (add_tail)
+ list_add_tail(&cmd_node->list, &adapter->cmd_pending_q);
+ else
+ list_add(&cmd_node->list, &adapter->cmd_pending_q);
+ spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
+
+ dev_dbg(adapter->dev, "cmd: QUEUE_CMD: cmd=%#x is queued\n", command);
+}
+
+/*
+ * This function executes the next command in command pending queue.
+ *
+ * This function will fail if a command is already in processing stage,
+ * otherwise it will dequeue the first command from the command pending
+ * queue and send to the firmware.
+ *
+ * If the device is currently in host sleep mode, any commands, except the
+ * host sleep configuration command will de-activate the host sleep. For PS
+ * mode, the function will put the firmware back to sleep if applicable.
+ */
+int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter)
+{
+ struct mwifiex_private *priv;
+ struct cmd_ctrl_node *cmd_node;
+ int ret = 0;
+ struct host_cmd_ds_command *host_cmd;
+ unsigned long cmd_flags;
+ unsigned long cmd_pending_q_flags;
+
+ /* Check if already in processing */
+ if (adapter->curr_cmd) {
+ dev_err(adapter->dev, "EXEC_NEXT_CMD: cmd in processing\n");
+ return -1;
+ }
+
+ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
+ /* Check if any command is pending */
+ spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_pending_q_flags);
+ if (list_empty(&adapter->cmd_pending_q)) {
+ spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
+ cmd_pending_q_flags);
+ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
+ return 0;
+ }
+ cmd_node = list_first_entry(&adapter->cmd_pending_q,
+ struct cmd_ctrl_node, list);
+ spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
+ cmd_pending_q_flags);
+
+ host_cmd = (struct host_cmd_ds_command *) (cmd_node->cmd_skb->data);
+ priv = cmd_node->priv;
+
+ if (adapter->ps_state != PS_STATE_AWAKE) {
+ dev_err(adapter->dev, "%s: cannot send cmd in sleep state,"
+ " this should not happen\n", __func__);
+ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
+ return ret;
+ }
+
+ spin_lock_irqsave(&adapter->cmd_pending_q_lock, cmd_pending_q_flags);
+ list_del(&cmd_node->list);
+ spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
+ cmd_pending_q_flags);
+
+ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
+ ret = mwifiex_dnld_cmd_to_fw(priv, cmd_node);
+ priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+ /* Any command sent to the firmware when host is in sleep
+ * mode should de-configure host sleep. We should skip the
+ * host sleep configuration command itself though
+ */
+ if (priv && (host_cmd->command !=
+ cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH))) {
+ if (adapter->hs_activated) {
+ adapter->is_hs_configured = false;
+ mwifiex_hs_activated_event(priv, false);
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * This function handles the command response.
+ *
+ * After processing, the function cleans the command node and puts
+ * it back to the command free queue.
+ */
+int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
+{
+ struct host_cmd_ds_command *resp;
+ struct mwifiex_private *priv =
+ mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+ int ret = 0;
+ uint16_t orig_cmdresp_no;
+ uint16_t cmdresp_no;
+ uint16_t cmdresp_result;
+ struct timeval tstamp;
+ unsigned long flags;
+
+ /* Now we got response from FW, cancel the command timer */
+ del_timer(&adapter->cmd_timer);
+
+ if (!adapter->curr_cmd || !adapter->curr_cmd->resp_skb) {
+ resp = (struct host_cmd_ds_command *) adapter->upld_buf;
+ dev_err(adapter->dev, "CMD_RESP: NULL curr_cmd, %#x\n",
+ le16_to_cpu(resp->command));
+ return -1;
+ }
+
+ adapter->num_cmd_timeout = 0;
+
+ resp = (struct host_cmd_ds_command *) adapter->curr_cmd->resp_skb->data;
+ if (adapter->curr_cmd->cmd_flag & CMD_F_CANCELED) {
+ dev_err(adapter->dev, "CMD_RESP: %#x been canceled\n",
+ le16_to_cpu(resp->command));
+ mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
+ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ adapter->curr_cmd = NULL;
+ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+ return -1;
+ }
+
+ if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) {
+ /* Copy original response back to response buffer */
+ struct mwifiex_ds_misc_cmd *hostcmd = NULL;
+ uint16_t size = le16_to_cpu(resp->size);
+ dev_dbg(adapter->dev, "info: host cmd resp size = %d\n", size);
+ size = min_t(u16, size, MWIFIEX_SIZE_OF_CMD_BUFFER);
+ if (adapter->curr_cmd->data_buf) {
+ hostcmd = (struct mwifiex_ds_misc_cmd *)
+ adapter->curr_cmd->data_buf;
+ hostcmd->len = size;
+ memcpy(hostcmd->cmd, (void *) resp, size);
+ }
+ }
+ orig_cmdresp_no = le16_to_cpu(resp->command);
+
+ /* Get BSS number and corresponding priv */
+ priv = mwifiex_get_priv_by_id(adapter,
+ HostCmd_GET_BSS_NO(le16_to_cpu(resp->seq_num)),
+ HostCmd_GET_BSS_TYPE(le16_to_cpu(resp->seq_num)));
+ if (!priv)
+ priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+ /* Clear RET_BIT from HostCmd */
+ resp->command = cpu_to_le16(orig_cmdresp_no & HostCmd_CMD_ID_MASK);
+
+ cmdresp_no = le16_to_cpu(resp->command);
+ cmdresp_result = le16_to_cpu(resp->result);
+
+ /* Save the last command response to debug log */
+ adapter->dbg.last_cmd_resp_index =
+ (adapter->dbg.last_cmd_resp_index + 1) % DBG_CMD_NUM;
+ adapter->dbg.last_cmd_resp_id[adapter->dbg.last_cmd_resp_index] =
+ orig_cmdresp_no;
+
+ do_gettimeofday(&tstamp);
+ dev_dbg(adapter->dev, "cmd: CMD_RESP: (%lu.%lu): 0x%x, result %d,"
+ " len %d, seqno 0x%x\n",
+ tstamp.tv_sec, tstamp.tv_usec, orig_cmdresp_no, cmdresp_result,
+ le16_to_cpu(resp->size), le16_to_cpu(resp->seq_num));
+
+ if (!(orig_cmdresp_no & HostCmd_RET_BIT)) {
+ dev_err(adapter->dev, "CMD_RESP: invalid cmd resp\n");
+ if (adapter->curr_cmd->wait_q_enabled)
+ adapter->cmd_wait_q.status = -1;
+
+ mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
+ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ adapter->curr_cmd = NULL;
+ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+ return -1;
+ }
+
+ if (adapter->curr_cmd->cmd_flag & CMD_F_HOSTCMD) {
+ adapter->curr_cmd->cmd_flag &= ~CMD_F_HOSTCMD;
+ if ((cmdresp_result == HostCmd_RESULT_OK)
+ && (cmdresp_no == HostCmd_CMD_802_11_HS_CFG_ENH))
+ ret = mwifiex_ret_802_11_hs_cfg(priv, resp);
+ } else {
+ /* handle response */
+ ret = mwifiex_process_sta_cmdresp(priv, cmdresp_no, resp);
+ }
+
+ /* Check init command response */
+ if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) {
+ if (ret == -1) {
+ dev_err(adapter->dev, "%s: cmd %#x failed during "
+ "initialization\n", __func__, cmdresp_no);
+ mwifiex_init_fw_complete(adapter);
+ return -1;
+ } else if (adapter->last_init_cmd == cmdresp_no)
+ adapter->hw_status = MWIFIEX_HW_STATUS_INIT_DONE;
+ }
+
+ if (adapter->curr_cmd) {
+ if (adapter->curr_cmd->wait_q_enabled && (!ret))
+ adapter->cmd_wait_q.status = 0;
+ else if (adapter->curr_cmd->wait_q_enabled && (ret == -1))
+ adapter->cmd_wait_q.status = -1;
+
+ /* Clean up and put current command back to cmd_free_q */
+ mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
+
+ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ adapter->curr_cmd = NULL;
+ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+ }
+
+ return ret;
+}
+
+/*
+ * This function handles the timeout of command sending.
+ *
+ * It will re-send the same command again.
+ */
+void
+mwifiex_cmd_timeout_func(unsigned long function_context)
+{
+ struct mwifiex_adapter *adapter =
+ (struct mwifiex_adapter *) function_context;
+ struct cmd_ctrl_node *cmd_node;
+ struct timeval tstamp;
+
+ adapter->num_cmd_timeout++;
+ adapter->dbg.num_cmd_timeout++;
+ if (!adapter->curr_cmd) {
+ dev_dbg(adapter->dev, "cmd: empty curr_cmd\n");
+ return;
+ }
+ cmd_node = adapter->curr_cmd;
+ if (cmd_node->wait_q_enabled)
+ adapter->cmd_wait_q.status = -ETIMEDOUT;
+
+ if (cmd_node) {
+ adapter->dbg.timeout_cmd_id =
+ adapter->dbg.last_cmd_id[adapter->dbg.last_cmd_index];
+ adapter->dbg.timeout_cmd_act =
+ adapter->dbg.last_cmd_act[adapter->dbg.last_cmd_index];
+ do_gettimeofday(&tstamp);
+ dev_err(adapter->dev, "%s: Timeout cmd id (%lu.%lu) = %#x,"
+ " act = %#x\n", __func__,
+ tstamp.tv_sec, tstamp.tv_usec,
+ adapter->dbg.timeout_cmd_id,
+ adapter->dbg.timeout_cmd_act);
+
+ dev_err(adapter->dev, "num_data_h2c_failure = %d\n",
+ adapter->dbg.num_tx_host_to_card_failure);
+ dev_err(adapter->dev, "num_cmd_h2c_failure = %d\n",
+ adapter->dbg.num_cmd_host_to_card_failure);
+
+ dev_err(adapter->dev, "num_cmd_timeout = %d\n",
+ adapter->dbg.num_cmd_timeout);
+ dev_err(adapter->dev, "num_tx_timeout = %d\n",
+ adapter->dbg.num_tx_timeout);
+
+ dev_err(adapter->dev, "last_cmd_index = %d\n",
+ adapter->dbg.last_cmd_index);
+ print_hex_dump_bytes("last_cmd_id: ", DUMP_PREFIX_OFFSET,
+ adapter->dbg.last_cmd_id, DBG_CMD_NUM);
+ print_hex_dump_bytes("last_cmd_act: ", DUMP_PREFIX_OFFSET,
+ adapter->dbg.last_cmd_act, DBG_CMD_NUM);
+
+ dev_err(adapter->dev, "last_cmd_resp_index = %d\n",
+ adapter->dbg.last_cmd_resp_index);
+ print_hex_dump_bytes("last_cmd_resp_id: ", DUMP_PREFIX_OFFSET,
+ adapter->dbg.last_cmd_resp_id, DBG_CMD_NUM);
+
+ dev_err(adapter->dev, "last_event_index = %d\n",
+ adapter->dbg.last_event_index);
+ print_hex_dump_bytes("last_event: ", DUMP_PREFIX_OFFSET,
+ adapter->dbg.last_event, DBG_CMD_NUM);
+
+ dev_err(adapter->dev, "data_sent=%d cmd_sent=%d\n",
+ adapter->data_sent, adapter->cmd_sent);
+
+ dev_err(adapter->dev, "ps_mode=%d ps_state=%d\n",
+ adapter->ps_mode, adapter->ps_state);
+ }
+ if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING)
+ mwifiex_init_fw_complete(adapter);
+}
+
+/*
+ * This function cancels all the pending commands.
+ *
+ * The current command, all commands in command pending queue and all scan
+ * commands in scan pending queue are cancelled. All the completion callbacks
+ * are called with failure status to ensure cleanup.
+ */
+void
+mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
+{
+ struct cmd_ctrl_node *cmd_node = NULL, *tmp_node;
+ unsigned long flags;
+
+ /* Cancel current cmd */
+ if ((adapter->curr_cmd) && (adapter->curr_cmd->wait_q_enabled)) {
+ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ adapter->curr_cmd->wait_q_enabled = false;
+ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+ adapter->cmd_wait_q.status = -1;
+ mwifiex_complete_cmd(adapter);
+ }
+ /* Cancel all pending command */
+ spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
+ list_for_each_entry_safe(cmd_node, tmp_node,
+ &adapter->cmd_pending_q, list) {
+ list_del(&cmd_node->list);
+ spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
+
+ if (cmd_node->wait_q_enabled) {
+ adapter->cmd_wait_q.status = -1;
+ mwifiex_complete_cmd(adapter);
+ cmd_node->wait_q_enabled = false;
+ }
+ mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+ spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
+ }
+ spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
+
+ /* Cancel all pending scan command */
+ spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+ list_for_each_entry_safe(cmd_node, tmp_node,
+ &adapter->scan_pending_q, list) {
+ list_del(&cmd_node->list);
+ spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+
+ cmd_node->wait_q_enabled = false;
+ mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+ spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+ }
+ spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+
+ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ adapter->scan_processing = false;
+ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+}
+
+/*
+ * This function cancels all pending commands that matches with
+ * the given IOCTL request.
+ *
+ * Both the current command buffer and the pending command queue are
+ * searched for matching IOCTL request. The completion callback of
+ * the matched command is called with failure status to ensure cleanup.
+ * In case of scan commands, all pending commands in scan pending queue
+ * are cancelled.
+ */
+void
+mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
+{
+ struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL;
+ unsigned long cmd_flags;
+ unsigned long cmd_pending_q_flags;
+ unsigned long scan_pending_q_flags;
+ uint16_t cancel_scan_cmd = false;
+
+ if ((adapter->curr_cmd) &&
+ (adapter->curr_cmd->wait_q_enabled)) {
+ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
+ cmd_node = adapter->curr_cmd;
+ cmd_node->wait_q_enabled = false;
+ cmd_node->cmd_flag |= CMD_F_CANCELED;
+ spin_lock_irqsave(&adapter->cmd_pending_q_lock,
+ cmd_pending_q_flags);
+ list_del(&cmd_node->list);
+ spin_unlock_irqrestore(&adapter->cmd_pending_q_lock,
+ cmd_pending_q_flags);
+ mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
+ }
+
+ /* Cancel all pending scan command */
+ spin_lock_irqsave(&adapter->scan_pending_q_lock,
+ scan_pending_q_flags);
+ list_for_each_entry_safe(cmd_node, tmp_node,
+ &adapter->scan_pending_q, list) {
+ list_del(&cmd_node->list);
+ spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+ scan_pending_q_flags);
+ cmd_node->wait_q_enabled = false;
+ mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+ spin_lock_irqsave(&adapter->scan_pending_q_lock,
+ scan_pending_q_flags);
+ cancel_scan_cmd = true;
+ }
+ spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+ scan_pending_q_flags);
+
+ if (cancel_scan_cmd) {
+ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
+ adapter->scan_processing = false;
+ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
+ }
+ adapter->cmd_wait_q.status = -1;
+ mwifiex_complete_cmd(adapter);
+}
+
+/*
+ * This function sends the sleep confirm command to firmware, if
+ * possible.
+ *
+ * The sleep confirm command cannot be issued if command response,
+ * data response or event response is awaiting handling, or if we
+ * are in the middle of sending a command, or expecting a command
+ * response.
+ */
+void
+mwifiex_check_ps_cond(struct mwifiex_adapter *adapter)
+{
+ if (!adapter->cmd_sent &&
+ !adapter->curr_cmd && !IS_CARD_RX_RCVD(adapter))
+ mwifiex_dnld_sleep_confirm_cmd(adapter);
+ else
+ dev_dbg(adapter->dev,
+ "cmd: Delay Sleep Confirm (%s%s%s)\n",
+ (adapter->cmd_sent) ? "D" : "",
+ (adapter->curr_cmd) ? "C" : "",
+ (IS_CARD_RX_RCVD(adapter)) ? "R" : "");
+}
+
+/*
+ * This function sends a Host Sleep activated event to applications.
+ *
+ * This event is generated by the driver, with a blank event body.
+ */
+void
+mwifiex_hs_activated_event(struct mwifiex_private *priv, u8 activated)
+{
+ if (activated) {
+ if (priv->adapter->is_hs_configured) {
+ priv->adapter->hs_activated = true;
+ dev_dbg(priv->adapter->dev, "event: hs_activated\n");
+ priv->adapter->hs_activate_wait_q_woken = true;
+ wake_up_interruptible(
+ &priv->adapter->hs_activate_wait_q);
+ } else {
+ dev_dbg(priv->adapter->dev, "event: HS not configured\n");
+ }
+ } else {
+ dev_dbg(priv->adapter->dev, "event: hs_deactivated\n");
+ priv->adapter->hs_activated = false;
+ }
+}
+
+/*
+ * This function handles the command response of a Host Sleep configuration
+ * command.
+ *
+ * Handling includes changing the header fields into CPU format
+ * and setting the current host sleep activation status in driver.
+ *
+ * In case host sleep status change, the function generates an event to
+ * notify the applications.
+ */
+int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct host_cmd_ds_802_11_hs_cfg_enh *phs_cfg =
+ &resp->params.opt_hs_cfg;
+ uint32_t conditions = le32_to_cpu(phs_cfg->params.hs_config.conditions);
+
+ if (phs_cfg->action == cpu_to_le16(HS_ACTIVATE)) {
+ mwifiex_hs_activated_event(priv, true);
+ return 0;
+ } else {
+ dev_dbg(adapter->dev, "cmd: CMD_RESP: HS_CFG cmd reply"
+ " result=%#x, conditions=0x%x gpio=0x%x gap=0x%x\n",
+ resp->result, conditions,
+ phs_cfg->params.hs_config.gpio,
+ phs_cfg->params.hs_config.gap);
+ }
+ if (conditions != HOST_SLEEP_CFG_CANCEL) {
+ adapter->is_hs_configured = true;
+ } else {
+ adapter->is_hs_configured = false;
+ if (adapter->hs_activated)
+ mwifiex_hs_activated_event(priv, false);
+ }
+
+ return 0;
+}
+
+/*
+ * This function wakes up the adapter and generates a Host Sleep
+ * cancel event on receiving the power up interrupt.
+ */
+void
+mwifiex_process_hs_config(struct mwifiex_adapter *adapter)
+{
+ dev_dbg(adapter->dev, "info: %s: auto cancelling host sleep"
+ " since there is interrupt from the firmware\n", __func__);
+
+ adapter->if_ops.wakeup(adapter);
+ adapter->hs_activated = false;
+ adapter->is_hs_configured = false;
+ mwifiex_hs_activated_event(mwifiex_get_priv(adapter,
+ MWIFIEX_BSS_ROLE_ANY), false);
+}
+
+/*
+ * This function handles the command response of a sleep confirm command.
+ *
+ * The function sets the card state to SLEEP if the response indicates success.
+ */
+void
+mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *adapter,
+ u8 *pbuf, u32 upld_len)
+{
+ struct host_cmd_ds_command *cmd = (struct host_cmd_ds_command *) pbuf;
+ struct mwifiex_private *priv =
+ mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+ uint16_t result = le16_to_cpu(cmd->result);
+ uint16_t command = le16_to_cpu(cmd->command);
+ uint16_t seq_num = le16_to_cpu(cmd->seq_num);
+
+ if (!upld_len) {
+ dev_err(adapter->dev, "%s: cmd size is 0\n", __func__);
+ return;
+ }
+
+ /* Get BSS number and corresponding priv */
+ priv = mwifiex_get_priv_by_id(adapter, HostCmd_GET_BSS_NO(seq_num),
+ HostCmd_GET_BSS_TYPE(seq_num));
+ if (!priv)
+ priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+
+ /* Update sequence number */
+ seq_num = HostCmd_GET_SEQ_NO(seq_num);
+ /* Clear RET_BIT from HostCmd */
+ command &= HostCmd_CMD_ID_MASK;
+
+ if (command != HostCmd_CMD_802_11_PS_MODE_ENH) {
+ dev_err(adapter->dev, "%s: received unexpected response for"
+ " cmd %x, result = %x\n", __func__, command, result);
+ return;
+ }
+
+ if (result) {
+ dev_err(adapter->dev, "%s: sleep confirm cmd failed\n",
+ __func__);
+ adapter->pm_wakeup_card_req = false;
+ adapter->ps_state = PS_STATE_AWAKE;
+ return;
+ }
+ adapter->pm_wakeup_card_req = true;
+ if (adapter->is_hs_configured)
+ mwifiex_hs_activated_event(mwifiex_get_priv(adapter,
+ MWIFIEX_BSS_ROLE_ANY), true);
+ adapter->ps_state = PS_STATE_SLEEP;
+ cmd->command = cpu_to_le16(command);
+ cmd->seq_num = cpu_to_le16(seq_num);
+}
+EXPORT_SYMBOL_GPL(mwifiex_process_sleep_confirm_resp);
+
+/*
+ * This function prepares an enhanced power mode command.
+ *
+ * This function can be used to disable power save or to configure
+ * power save with auto PS or STA PS or auto deep sleep.
+ *
+ * Preparation includes -
+ * - Setting command ID, action and proper size
+ * - Setting Power Save bitmap, PS parameters TLV, PS mode TLV,
+ * auto deep sleep TLV (as required)
+ * - Ensuring correct endian-ness
+ */
+int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ u16 cmd_action, uint16_t ps_bitmap,
+ void *data_buf)
+{
+ struct host_cmd_ds_802_11_ps_mode_enh *psmode_enh =
+ &cmd->params.psmode_enh;
+ u8 *tlv;
+ u16 cmd_size = 0;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH);
+ if (cmd_action == DIS_AUTO_PS) {
+ psmode_enh->action = cpu_to_le16(DIS_AUTO_PS);
+ psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap);
+ cmd->size = cpu_to_le16(S_DS_GEN + sizeof(psmode_enh->action) +
+ sizeof(psmode_enh->params.ps_bitmap));
+ } else if (cmd_action == GET_PS) {
+ psmode_enh->action = cpu_to_le16(GET_PS);
+ psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap);
+ cmd->size = cpu_to_le16(S_DS_GEN + sizeof(psmode_enh->action) +
+ sizeof(psmode_enh->params.ps_bitmap));
+ } else if (cmd_action == EN_AUTO_PS) {
+ psmode_enh->action = cpu_to_le16(EN_AUTO_PS);
+ psmode_enh->params.ps_bitmap = cpu_to_le16(ps_bitmap);
+ cmd_size = S_DS_GEN + sizeof(psmode_enh->action) +
+ sizeof(psmode_enh->params.ps_bitmap);
+ tlv = (u8 *) cmd + cmd_size;
+ if (ps_bitmap & BITMAP_STA_PS) {
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_ie_types_ps_param *ps_tlv =
+ (struct mwifiex_ie_types_ps_param *) tlv;
+ struct mwifiex_ps_param *ps_mode = &ps_tlv->param;
+ ps_tlv->header.type = cpu_to_le16(TLV_TYPE_PS_PARAM);
+ ps_tlv->header.len = cpu_to_le16(sizeof(*ps_tlv) -
+ sizeof(struct mwifiex_ie_types_header));
+ cmd_size += sizeof(*ps_tlv);
+ tlv += sizeof(*ps_tlv);
+ dev_dbg(adapter->dev, "cmd: PS Command: Enter PS\n");
+ ps_mode->null_pkt_interval =
+ cpu_to_le16(adapter->null_pkt_interval);
+ ps_mode->multiple_dtims =
+ cpu_to_le16(adapter->multiple_dtim);
+ ps_mode->bcn_miss_timeout =
+ cpu_to_le16(adapter->bcn_miss_time_out);
+ ps_mode->local_listen_interval =
+ cpu_to_le16(adapter->local_listen_interval);
+ ps_mode->adhoc_wake_period =
+ cpu_to_le16(adapter->adhoc_awake_period);
+ ps_mode->delay_to_ps =
+ cpu_to_le16(adapter->delay_to_ps);
+ ps_mode->mode =
+ cpu_to_le16(adapter->enhanced_ps_mode);
+
+ }
+ if (ps_bitmap & BITMAP_AUTO_DS) {
+ struct mwifiex_ie_types_auto_ds_param *auto_ds_tlv =
+ (struct mwifiex_ie_types_auto_ds_param *) tlv;
+ u16 idletime = 0;
+
+ auto_ds_tlv->header.type =
+ cpu_to_le16(TLV_TYPE_AUTO_DS_PARAM);
+ auto_ds_tlv->header.len =
+ cpu_to_le16(sizeof(*auto_ds_tlv) -
+ sizeof(struct mwifiex_ie_types_header));
+ cmd_size += sizeof(*auto_ds_tlv);
+ tlv += sizeof(*auto_ds_tlv);
+ if (data_buf)
+ idletime = ((struct mwifiex_ds_auto_ds *)
+ data_buf)->idle_time;
+ dev_dbg(priv->adapter->dev,
+ "cmd: PS Command: Enter Auto Deep Sleep\n");
+ auto_ds_tlv->deep_sleep_timeout = cpu_to_le16(idletime);
+ }
+ cmd->size = cpu_to_le16(cmd_size);
+ }
+ return 0;
+}
+
+/*
+ * This function handles the command response of an enhanced power mode
+ * command.
+ *
+ * Handling includes changing the header fields into CPU format
+ * and setting the current enhanced power mode in driver.
+ */
+int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp,
+ void *data_buf)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct host_cmd_ds_802_11_ps_mode_enh *ps_mode =
+ &resp->params.psmode_enh;
+ uint16_t action = le16_to_cpu(ps_mode->action);
+ uint16_t ps_bitmap = le16_to_cpu(ps_mode->params.ps_bitmap);
+ uint16_t auto_ps_bitmap =
+ le16_to_cpu(ps_mode->params.ps_bitmap);
+
+ dev_dbg(adapter->dev, "info: %s: PS_MODE cmd reply result=%#x action=%#X\n",
+ __func__, resp->result, action);
+ if (action == EN_AUTO_PS) {
+ if (auto_ps_bitmap & BITMAP_AUTO_DS) {
+ dev_dbg(adapter->dev, "cmd: Enabled auto deep sleep\n");
+ priv->adapter->is_deep_sleep = true;
+ }
+ if (auto_ps_bitmap & BITMAP_STA_PS) {
+ dev_dbg(adapter->dev, "cmd: Enabled STA power save\n");
+ if (adapter->sleep_period.period)
+ dev_dbg(adapter->dev, "cmd: set to uapsd/pps mode\n");
+ }
+ } else if (action == DIS_AUTO_PS) {
+ if (ps_bitmap & BITMAP_AUTO_DS) {
+ priv->adapter->is_deep_sleep = false;
+ dev_dbg(adapter->dev, "cmd: Disabled auto deep sleep\n");
+ }
+ if (ps_bitmap & BITMAP_STA_PS) {
+ dev_dbg(adapter->dev, "cmd: Disabled STA power save\n");
+ if (adapter->sleep_period.period) {
+ adapter->delay_null_pkt = false;
+ adapter->tx_lock_flag = false;
+ adapter->pps_uapsd_mode = false;
+ }
+ }
+ } else if (action == GET_PS) {
+ if (ps_bitmap & BITMAP_STA_PS)
+ adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
+ else
+ adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
+
+ dev_dbg(adapter->dev, "cmd: ps_bitmap=%#x\n", ps_bitmap);
+
+ if (data_buf) {
+ /* This section is for get power save mode */
+ struct mwifiex_ds_pm_cfg *pm_cfg =
+ (struct mwifiex_ds_pm_cfg *)data_buf;
+ if (ps_bitmap & BITMAP_STA_PS)
+ pm_cfg->param.ps_mode = 1;
+ else
+ pm_cfg->param.ps_mode = 0;
+ }
+ }
+ return 0;
+}
+
+/*
+ * This function prepares command to get hardware specifications.
+ *
+ * Preparation includes -
+ * - Setting command ID, action and proper size
+ * - Setting permanent address parameter
+ * - Ensuring correct endian-ness
+ */
+int mwifiex_cmd_get_hw_spec(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd)
+{
+ struct host_cmd_ds_get_hw_spec *hw_spec = &cmd->params.hw_spec;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_GET_HW_SPEC);
+ cmd->size =
+ cpu_to_le16(sizeof(struct host_cmd_ds_get_hw_spec) + S_DS_GEN);
+ memcpy(hw_spec->permanent_addr, priv->curr_addr, ETH_ALEN);
+
+ return 0;
+}
+
+/*
+ * This function handles the command response of get hardware
+ * specifications.
+ *
+ * Handling includes changing the header fields into CPU format
+ * and saving/updating the following parameters in driver -
+ * - Firmware capability information
+ * - Firmware band settings
+ * - Ad-hoc start band and channel
+ * - Ad-hoc 11n activation status
+ * - Firmware release number
+ * - Number of antennas
+ * - Hardware address
+ * - Hardware interface version
+ * - Firmware version
+ * - Region code
+ * - 11n capabilities
+ * - MCS support fields
+ * - MP end port
+ */
+int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
+{
+ struct host_cmd_ds_get_hw_spec *hw_spec = &resp->params.hw_spec;
+ struct mwifiex_adapter *adapter = priv->adapter;
+ int i;
+
+ adapter->fw_cap_info = le32_to_cpu(hw_spec->fw_cap_info);
+
+ if (IS_SUPPORT_MULTI_BANDS(adapter))
+ adapter->fw_bands = (u8) GET_FW_DEFAULT_BANDS(adapter);
+ else
+ adapter->fw_bands = BAND_B;
+
+ adapter->config_bands = adapter->fw_bands;
+
+ if (adapter->fw_bands & BAND_A) {
+ if (adapter->fw_bands & BAND_GN) {
+ adapter->config_bands |= BAND_AN;
+ adapter->fw_bands |= BAND_AN;
+ }
+ if (adapter->fw_bands & BAND_AN) {
+ adapter->adhoc_start_band = BAND_A | BAND_AN;
+ adapter->adhoc_11n_enabled = true;
+ } else {
+ adapter->adhoc_start_band = BAND_A;
+ }
+ priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL_A;
+ } else if (adapter->fw_bands & BAND_GN) {
+ adapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN;
+ priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
+ adapter->adhoc_11n_enabled = true;
+ } else if (adapter->fw_bands & BAND_G) {
+ adapter->adhoc_start_band = BAND_G | BAND_B;
+ priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
+ } else if (adapter->fw_bands & BAND_B) {
+ adapter->adhoc_start_band = BAND_B;
+ priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
+ }
+
+ adapter->fw_release_number = le32_to_cpu(hw_spec->fw_release_number);
+ adapter->number_of_antenna = le16_to_cpu(hw_spec->number_of_antenna);
+
+ dev_dbg(adapter->dev, "info: GET_HW_SPEC: fw_release_number- %#x\n",
+ adapter->fw_release_number);
+ dev_dbg(adapter->dev, "info: GET_HW_SPEC: permanent addr: %pM\n",
+ hw_spec->permanent_addr);
+ dev_dbg(adapter->dev, "info: GET_HW_SPEC: hw_if_version=%#x version=%#x\n",
+ le16_to_cpu(hw_spec->hw_if_version),
+ le16_to_cpu(hw_spec->version));
+
+ if (priv->curr_addr[0] == 0xff)
+ memmove(priv->curr_addr, hw_spec->permanent_addr, ETH_ALEN);
+
+ adapter->region_code = le16_to_cpu(hw_spec->region_code);
+
+ for (i = 0; i < MWIFIEX_MAX_REGION_CODE; i++)
+ /* Use the region code to search for the index */
+ if (adapter->region_code == region_code_index[i])
+ break;
+
+ /* If it's unidentified region code, use the default (USA) */
+ if (i >= MWIFIEX_MAX_REGION_CODE) {
+ adapter->region_code = 0x10;
+ dev_dbg(adapter->dev, "cmd: unknown region code, use default (USA)\n");
+ }
+
+ adapter->hw_dot_11n_dev_cap = le32_to_cpu(hw_spec->dot_11n_dev_cap);
+ adapter->hw_dev_mcs_support = hw_spec->dev_mcs_support;
+
+ if (adapter->if_ops.update_mp_end_port)
+ adapter->if_ops.update_mp_end_port(adapter,
+ le16_to_cpu(hw_spec->mp_end_port));
+
+ return 0;
+}
diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c
new file mode 100644
index 000000000000..46d65e02c7ba
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/debugfs.c
@@ -0,0 +1,770 @@
+/*
+ * Marvell Wireless LAN device driver: debugfs
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include <linux/debugfs.h>
+
+#include "main.h"
+#include "11n.h"
+
+
+static struct dentry *mwifiex_dfs_dir;
+
+static char *bss_modes[] = {
+ "Unknown",
+ "Managed",
+ "Ad-hoc",
+ "Auto"
+};
+
+/* size/addr for mwifiex_debug_info */
+#define item_size(n) (FIELD_SIZEOF(struct mwifiex_debug_info, n))
+#define item_addr(n) (offsetof(struct mwifiex_debug_info, n))
+
+/* size/addr for struct mwifiex_adapter */
+#define adapter_item_size(n) (FIELD_SIZEOF(struct mwifiex_adapter, n))
+#define adapter_item_addr(n) (offsetof(struct mwifiex_adapter, n))
+
+struct mwifiex_debug_data {
+ char name[32]; /* variable/array name */
+ u32 size; /* size of the variable/array */
+ size_t addr; /* address of the variable/array */
+ int num; /* number of variables in an array */
+};
+
+static struct mwifiex_debug_data items[] = {
+ {"int_counter", item_size(int_counter),
+ item_addr(int_counter), 1},
+ {"wmm_ac_vo", item_size(packets_out[WMM_AC_VO]),
+ item_addr(packets_out[WMM_AC_VO]), 1},
+ {"wmm_ac_vi", item_size(packets_out[WMM_AC_VI]),
+ item_addr(packets_out[WMM_AC_VI]), 1},
+ {"wmm_ac_be", item_size(packets_out[WMM_AC_BE]),
+ item_addr(packets_out[WMM_AC_BE]), 1},
+ {"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]),
+ item_addr(packets_out[WMM_AC_BK]), 1},
+ {"max_tx_buf_size", item_size(max_tx_buf_size),
+ item_addr(max_tx_buf_size), 1},
+ {"tx_buf_size", item_size(tx_buf_size),
+ item_addr(tx_buf_size), 1},
+ {"curr_tx_buf_size", item_size(curr_tx_buf_size),
+ item_addr(curr_tx_buf_size), 1},
+ {"ps_mode", item_size(ps_mode),
+ item_addr(ps_mode), 1},
+ {"ps_state", item_size(ps_state),
+ item_addr(ps_state), 1},
+ {"is_deep_sleep", item_size(is_deep_sleep),
+ item_addr(is_deep_sleep), 1},
+ {"wakeup_dev_req", item_size(pm_wakeup_card_req),
+ item_addr(pm_wakeup_card_req), 1},
+ {"wakeup_tries", item_size(pm_wakeup_fw_try),
+ item_addr(pm_wakeup_fw_try), 1},
+ {"hs_configured", item_size(is_hs_configured),
+ item_addr(is_hs_configured), 1},
+ {"hs_activated", item_size(hs_activated),
+ item_addr(hs_activated), 1},
+ {"num_tx_timeout", item_size(num_tx_timeout),
+ item_addr(num_tx_timeout), 1},
+ {"num_cmd_timeout", item_size(num_cmd_timeout),
+ item_addr(num_cmd_timeout), 1},
+ {"timeout_cmd_id", item_size(timeout_cmd_id),
+ item_addr(timeout_cmd_id), 1},
+ {"timeout_cmd_act", item_size(timeout_cmd_act),
+ item_addr(timeout_cmd_act), 1},
+ {"last_cmd_id", item_size(last_cmd_id),
+ item_addr(last_cmd_id), DBG_CMD_NUM},
+ {"last_cmd_act", item_size(last_cmd_act),
+ item_addr(last_cmd_act), DBG_CMD_NUM},
+ {"last_cmd_index", item_size(last_cmd_index),
+ item_addr(last_cmd_index), 1},
+ {"last_cmd_resp_id", item_size(last_cmd_resp_id),
+ item_addr(last_cmd_resp_id), DBG_CMD_NUM},
+ {"last_cmd_resp_index", item_size(last_cmd_resp_index),
+ item_addr(last_cmd_resp_index), 1},
+ {"last_event", item_size(last_event),
+ item_addr(last_event), DBG_CMD_NUM},
+ {"last_event_index", item_size(last_event_index),
+ item_addr(last_event_index), 1},
+ {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure),
+ item_addr(num_cmd_host_to_card_failure), 1},
+ {"num_cmd_sleep_cfm_fail",
+ item_size(num_cmd_sleep_cfm_host_to_card_failure),
+ item_addr(num_cmd_sleep_cfm_host_to_card_failure), 1},
+ {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure),
+ item_addr(num_tx_host_to_card_failure), 1},
+ {"num_evt_deauth", item_size(num_event_deauth),
+ item_addr(num_event_deauth), 1},
+ {"num_evt_disassoc", item_size(num_event_disassoc),
+ item_addr(num_event_disassoc), 1},
+ {"num_evt_link_lost", item_size(num_event_link_lost),
+ item_addr(num_event_link_lost), 1},
+ {"num_cmd_deauth", item_size(num_cmd_deauth),
+ item_addr(num_cmd_deauth), 1},
+ {"num_cmd_assoc_ok", item_size(num_cmd_assoc_success),
+ item_addr(num_cmd_assoc_success), 1},
+ {"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure),
+ item_addr(num_cmd_assoc_failure), 1},
+ {"cmd_sent", item_size(cmd_sent),
+ item_addr(cmd_sent), 1},
+ {"data_sent", item_size(data_sent),
+ item_addr(data_sent), 1},
+ {"cmd_resp_received", item_size(cmd_resp_received),
+ item_addr(cmd_resp_received), 1},
+ {"event_received", item_size(event_received),
+ item_addr(event_received), 1},
+
+ /* variables defined in struct mwifiex_adapter */
+ {"cmd_pending", adapter_item_size(cmd_pending),
+ adapter_item_addr(cmd_pending), 1},
+ {"tx_pending", adapter_item_size(tx_pending),
+ adapter_item_addr(tx_pending), 1},
+ {"rx_pending", adapter_item_size(rx_pending),
+ adapter_item_addr(rx_pending), 1},
+};
+
+static int num_of_items = ARRAY_SIZE(items);
+
+/*
+ * Generic proc file open handler.
+ *
+ * This function is called every time a file is accessed for read or write.
+ */
+static int
+mwifiex_open_generic(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+/*
+ * Proc info file read handler.
+ *
+ * This function is called when the 'info' file is opened for reading.
+ * It prints the following driver related information -
+ * - Driver name
+ * - Driver version
+ * - Driver extended version
+ * - Interface name
+ * - BSS mode
+ * - Media state (connected or disconnected)
+ * - MAC address
+ * - Total number of Tx bytes
+ * - Total number of Rx bytes
+ * - Total number of Tx packets
+ * - Total number of Rx packets
+ * - Total number of dropped Tx packets
+ * - Total number of dropped Rx packets
+ * - Total number of corrupted Tx packets
+ * - Total number of corrupted Rx packets
+ * - Carrier status (on or off)
+ * - Tx queue status (started or stopped)
+ *
+ * For STA mode drivers, it also prints the following extra -
+ * - ESSID
+ * - BSSID
+ * - Channel
+ * - Region code
+ * - Multicast count
+ * - Multicast addresses
+ */
+static ssize_t
+mwifiex_info_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct mwifiex_private *priv =
+ (struct mwifiex_private *) file->private_data;
+ struct net_device *netdev = priv->netdev;
+ struct netdev_hw_addr *ha;
+ unsigned long page = get_zeroed_page(GFP_KERNEL);
+ char *p = (char *) page, fmt[64];
+ struct mwifiex_bss_info info;
+ ssize_t ret;
+ int i = 0;
+
+ if (!p)
+ return -ENOMEM;
+
+ memset(&info, 0, sizeof(info));
+ ret = mwifiex_get_bss_info(priv, &info);
+ if (ret)
+ goto free_and_exit;
+
+ mwifiex_drv_get_driver_version(priv->adapter, fmt, sizeof(fmt) - 1);
+
+ if (!priv->version_str[0])
+ mwifiex_get_ver_ext(priv);
+
+ p += sprintf(p, "driver_name = " "\"mwifiex\"\n");
+ p += sprintf(p, "driver_version = %s", fmt);
+ p += sprintf(p, "\nverext = %s", priv->version_str);
+ p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name);
+ p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]);
+ p += sprintf(p, "media_state=\"%s\"\n",
+ (!priv->media_connected ? "Disconnected" : "Connected"));
+ p += sprintf(p, "mac_address=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
+ netdev->dev_addr[0], netdev->dev_addr[1],
+ netdev->dev_addr[2], netdev->dev_addr[3],
+ netdev->dev_addr[4], netdev->dev_addr[5]);
+
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) {
+ p += sprintf(p, "multicast_count=\"%d\"\n",
+ netdev_mc_count(netdev));
+ p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid);
+ p += sprintf(p, "bssid=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n",
+ info.bssid[0], info.bssid[1],
+ info.bssid[2], info.bssid[3],
+ info.bssid[4], info.bssid[5]);
+ p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan);
+ p += sprintf(p, "region_code = \"%02x\"\n", info.region_code);
+
+ netdev_for_each_mc_addr(ha, netdev)
+ p += sprintf(p, "multicast_address[%d]="
+ "\"%02x:%02x:%02x:%02x:%02x:%02x\"\n", i++,
+ ha->addr[0], ha->addr[1],
+ ha->addr[2], ha->addr[3],
+ ha->addr[4], ha->addr[5]);
+ }
+
+ p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes);
+ p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes);
+ p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets);
+ p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets);
+ p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped);
+ p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped);
+ p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors);
+ p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
+ p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev))
+ ? "on" : "off"));
+ p += sprintf(p, "tx queue %s\n", ((netif_queue_stopped(priv->netdev))
+ ? "stopped" : "started"));
+
+ ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
+ (unsigned long) p - page);
+
+free_and_exit:
+ free_page(page);
+ return ret;
+}
+
+/*
+ * Proc getlog file read handler.
+ *
+ * This function is called when the 'getlog' file is opened for reading
+ * It prints the following log information -
+ * - Number of multicast Tx frames
+ * - Number of failed packets
+ * - Number of Tx retries
+ * - Number of multicast Tx retries
+ * - Number of duplicate frames
+ * - Number of RTS successes
+ * - Number of RTS failures
+ * - Number of ACK failures
+ * - Number of fragmented Rx frames
+ * - Number of multicast Rx frames
+ * - Number of FCS errors
+ * - Number of Tx frames
+ * - WEP ICV error counts
+ */
+static ssize_t
+mwifiex_getlog_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct mwifiex_private *priv =
+ (struct mwifiex_private *) file->private_data;
+ unsigned long page = get_zeroed_page(GFP_KERNEL);
+ char *p = (char *) page;
+ ssize_t ret;
+ struct mwifiex_ds_get_stats stats;
+
+ if (!p)
+ return -ENOMEM;
+
+ memset(&stats, 0, sizeof(stats));
+ ret = mwifiex_get_stats_info(priv, &stats);
+ if (ret)
+ goto free_and_exit;
+
+ p += sprintf(p, "\n"
+ "mcasttxframe %u\n"
+ "failed %u\n"
+ "retry %u\n"
+ "multiretry %u\n"
+ "framedup %u\n"
+ "rtssuccess %u\n"
+ "rtsfailure %u\n"
+ "ackfailure %u\n"
+ "rxfrag %u\n"
+ "mcastrxframe %u\n"
+ "fcserror %u\n"
+ "txframe %u\n"
+ "wepicverrcnt-1 %u\n"
+ "wepicverrcnt-2 %u\n"
+ "wepicverrcnt-3 %u\n"
+ "wepicverrcnt-4 %u\n",
+ stats.mcast_tx_frame,
+ stats.failed,
+ stats.retry,
+ stats.multi_retry,
+ stats.frame_dup,
+ stats.rts_success,
+ stats.rts_failure,
+ stats.ack_failure,
+ stats.rx_frag,
+ stats.mcast_rx_frame,
+ stats.fcs_error,
+ stats.tx_frame,
+ stats.wep_icv_error[0],
+ stats.wep_icv_error[1],
+ stats.wep_icv_error[2],
+ stats.wep_icv_error[3]);
+
+
+ ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
+ (unsigned long) p - page);
+
+free_and_exit:
+ free_page(page);
+ return ret;
+}
+
+static struct mwifiex_debug_info info;
+
+/*
+ * Proc debug file read handler.
+ *
+ * This function is called when the 'debug' file is opened for reading
+ * It prints the following log information -
+ * - Interrupt count
+ * - WMM AC VO packets count
+ * - WMM AC VI packets count
+ * - WMM AC BE packets count
+ * - WMM AC BK packets count
+ * - Maximum Tx buffer size
+ * - Tx buffer size
+ * - Current Tx buffer size
+ * - Power Save mode
+ * - Power Save state
+ * - Deep Sleep status
+ * - Device wakeup required status
+ * - Number of wakeup tries
+ * - Host Sleep configured status
+ * - Host Sleep activated status
+ * - Number of Tx timeouts
+ * - Number of command timeouts
+ * - Last timed out command ID
+ * - Last timed out command action
+ * - Last command ID
+ * - Last command action
+ * - Last command index
+ * - Last command response ID
+ * - Last command response index
+ * - Last event
+ * - Last event index
+ * - Number of host to card command failures
+ * - Number of sleep confirm command failures
+ * - Number of host to card data failure
+ * - Number of deauthentication events
+ * - Number of disassociation events
+ * - Number of link lost events
+ * - Number of deauthentication commands
+ * - Number of association success commands
+ * - Number of association failure commands
+ * - Number of commands sent
+ * - Number of data packets sent
+ * - Number of command responses received
+ * - Number of events received
+ * - Tx BA stream table (TID, RA)
+ * - Rx reorder table (TID, TA, Start window, Window size, Buffer)
+ */
+static ssize_t
+mwifiex_debug_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct mwifiex_private *priv =
+ (struct mwifiex_private *) file->private_data;
+ struct mwifiex_debug_data *d = &items[0];
+ unsigned long page = get_zeroed_page(GFP_KERNEL);
+ char *p = (char *) page;
+ ssize_t ret;
+ size_t size, addr;
+ long val;
+ int i, j;
+
+ if (!p)
+ return -ENOMEM;
+
+ ret = mwifiex_get_debug_info(priv, &info);
+ if (ret)
+ goto free_and_exit;
+
+ for (i = 0; i < num_of_items; i++) {
+ p += sprintf(p, "%s=", d[i].name);
+
+ size = d[i].size / d[i].num;
+
+ if (i < (num_of_items - 3))
+ addr = d[i].addr + (size_t) &info;
+ else /* The last 3 items are struct mwifiex_adapter variables */
+ addr = d[i].addr + (size_t) priv->adapter;
+
+ for (j = 0; j < d[i].num; j++) {
+ switch (size) {
+ case 1:
+ val = *((u8 *) addr);
+ break;
+ case 2:
+ val = *((u16 *) addr);
+ break;
+ case 4:
+ val = *((u32 *) addr);
+ break;
+ case 8:
+ val = *((long long *) addr);
+ break;
+ default:
+ val = -1;
+ break;
+ }
+
+ p += sprintf(p, "%#lx ", val);
+ addr += size;
+ }
+
+ p += sprintf(p, "\n");
+ }
+
+ if (info.tx_tbl_num) {
+ p += sprintf(p, "Tx BA stream table:\n");
+ for (i = 0; i < info.tx_tbl_num; i++)
+ p += sprintf(p, "tid = %d, "
+ "ra = %02x:%02x:%02x:%02x:%02x:%02x\n",
+ info.tx_tbl[i].tid, info.tx_tbl[i].ra[0],
+ info.tx_tbl[i].ra[1], info.tx_tbl[i].ra[2],
+ info.tx_tbl[i].ra[3], info.tx_tbl[i].ra[4],
+ info.tx_tbl[i].ra[5]);
+ }
+
+ if (info.rx_tbl_num) {
+ p += sprintf(p, "Rx reorder table:\n");
+ for (i = 0; i < info.rx_tbl_num; i++) {
+
+ p += sprintf(p, "tid = %d, "
+ "ta = %02x:%02x:%02x:%02x:%02x:%02x, "
+ "start_win = %d, "
+ "win_size = %d, buffer: ",
+ info.rx_tbl[i].tid,
+ info.rx_tbl[i].ta[0], info.rx_tbl[i].ta[1],
+ info.rx_tbl[i].ta[2], info.rx_tbl[i].ta[3],
+ info.rx_tbl[i].ta[4], info.rx_tbl[i].ta[5],
+ info.rx_tbl[i].start_win,
+ info.rx_tbl[i].win_size);
+
+ for (j = 0; j < info.rx_tbl[i].win_size; j++)
+ p += sprintf(p, "%c ",
+ info.rx_tbl[i].buffer[j] ?
+ '1' : '0');
+
+ p += sprintf(p, "\n");
+ }
+ }
+
+ ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
+ (unsigned long) p - page);
+
+free_and_exit:
+ free_page(page);
+ return ret;
+}
+
+static u32 saved_reg_type, saved_reg_offset, saved_reg_value;
+
+/*
+ * Proc regrdwr file write handler.
+ *
+ * This function is called when the 'regrdwr' file is opened for writing
+ *
+ * This function can be used to write to a register.
+ */
+static ssize_t
+mwifiex_regrdwr_write(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *) addr;
+ size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1));
+ int ret;
+ u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX;
+
+ if (!buf)
+ return -ENOMEM;
+
+
+ if (copy_from_user(buf, ubuf, buf_size)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ sscanf(buf, "%u %x %x", &reg_type, &reg_offset, &reg_value);
+
+ if (reg_type == 0 || reg_offset == 0) {
+ ret = -EINVAL;
+ goto done;
+ } else {
+ saved_reg_type = reg_type;
+ saved_reg_offset = reg_offset;
+ saved_reg_value = reg_value;
+ ret = count;
+ }
+done:
+ free_page(addr);
+ return ret;
+}
+
+/*
+ * Proc regrdwr file read handler.
+ *
+ * This function is called when the 'regrdwr' file is opened for reading
+ *
+ * This function can be used to read from a register.
+ */
+static ssize_t
+mwifiex_regrdwr_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct mwifiex_private *priv =
+ (struct mwifiex_private *) file->private_data;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *) addr;
+ int pos = 0, ret = 0;
+ u32 reg_value;
+
+ if (!buf)
+ return -ENOMEM;
+
+ if (!saved_reg_type) {
+ /* No command has been given */
+ pos += snprintf(buf, PAGE_SIZE, "0");
+ goto done;
+ }
+ /* Set command has been given */
+ if (saved_reg_value != UINT_MAX) {
+ ret = mwifiex_reg_write(priv, saved_reg_type, saved_reg_offset,
+ saved_reg_value);
+
+ pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n",
+ saved_reg_type, saved_reg_offset,
+ saved_reg_value);
+
+ ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
+
+ goto done;
+ }
+ /* Get command has been given */
+ ret = mwifiex_reg_read(priv, saved_reg_type,
+ saved_reg_offset, &reg_value);
+ if (ret) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", saved_reg_type,
+ saved_reg_offset, reg_value);
+
+ ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
+
+done:
+ free_page(addr);
+ return ret;
+}
+
+static u32 saved_offset = -1, saved_bytes = -1;
+
+/*
+ * Proc rdeeprom file write handler.
+ *
+ * This function is called when the 'rdeeprom' file is opened for writing
+ *
+ * This function can be used to write to a RDEEPROM location.
+ */
+static ssize_t
+mwifiex_rdeeprom_write(struct file *file,
+ const char __user *ubuf, size_t count, loff_t *ppos)
+{
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *) addr;
+ size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1));
+ int ret = 0;
+ int offset = -1, bytes = -1;
+
+ if (!buf)
+ return -ENOMEM;
+
+
+ if (copy_from_user(buf, ubuf, buf_size)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ sscanf(buf, "%d %d", &offset, &bytes);
+
+ if (offset == -1 || bytes == -1) {
+ ret = -EINVAL;
+ goto done;
+ } else {
+ saved_offset = offset;
+ saved_bytes = bytes;
+ ret = count;
+ }
+done:
+ free_page(addr);
+ return ret;
+}
+
+/*
+ * Proc rdeeprom read write handler.
+ *
+ * This function is called when the 'rdeeprom' file is opened for reading
+ *
+ * This function can be used to read from a RDEEPROM location.
+ */
+static ssize_t
+mwifiex_rdeeprom_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct mwifiex_private *priv =
+ (struct mwifiex_private *) file->private_data;
+ unsigned long addr = get_zeroed_page(GFP_KERNEL);
+ char *buf = (char *) addr;
+ int pos = 0, ret = 0, i;
+ u8 value[MAX_EEPROM_DATA];
+
+ if (!buf)
+ return -ENOMEM;
+
+ if (saved_offset == -1) {
+ /* No command has been given */
+ pos += snprintf(buf, PAGE_SIZE, "0");
+ goto done;
+ }
+
+ /* Get command has been given */
+ ret = mwifiex_eeprom_read(priv, (u16) saved_offset,
+ (u16) saved_bytes, value);
+ if (ret) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ pos += snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes);
+
+ for (i = 0; i < saved_bytes; i++)
+ pos += snprintf(buf + strlen(buf), PAGE_SIZE, "%d ", value[i]);
+
+ ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
+
+done:
+ free_page(addr);
+ return ret;
+}
+
+
+#define MWIFIEX_DFS_ADD_FILE(name) do { \
+ if (!debugfs_create_file(#name, 0644, priv->dfs_dev_dir, \
+ priv, &mwifiex_dfs_##name##_fops)) \
+ return; \
+} while (0);
+
+#define MWIFIEX_DFS_FILE_OPS(name) \
+static const struct file_operations mwifiex_dfs_##name##_fops = { \
+ .read = mwifiex_##name##_read, \
+ .write = mwifiex_##name##_write, \
+ .open = mwifiex_open_generic, \
+};
+
+#define MWIFIEX_DFS_FILE_READ_OPS(name) \
+static const struct file_operations mwifiex_dfs_##name##_fops = { \
+ .read = mwifiex_##name##_read, \
+ .open = mwifiex_open_generic, \
+};
+
+#define MWIFIEX_DFS_FILE_WRITE_OPS(name) \
+static const struct file_operations mwifiex_dfs_##name##_fops = { \
+ .write = mwifiex_##name##_write, \
+ .open = mwifiex_open_generic, \
+};
+
+
+MWIFIEX_DFS_FILE_READ_OPS(info);
+MWIFIEX_DFS_FILE_READ_OPS(debug);
+MWIFIEX_DFS_FILE_READ_OPS(getlog);
+MWIFIEX_DFS_FILE_OPS(regrdwr);
+MWIFIEX_DFS_FILE_OPS(rdeeprom);
+
+/*
+ * This function creates the debug FS directory structure and the files.
+ */
+void
+mwifiex_dev_debugfs_init(struct mwifiex_private *priv)
+{
+ if (!mwifiex_dfs_dir || !priv)
+ return;
+
+ priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name,
+ mwifiex_dfs_dir);
+
+ if (!priv->dfs_dev_dir)
+ return;
+
+ MWIFIEX_DFS_ADD_FILE(info);
+ MWIFIEX_DFS_ADD_FILE(debug);
+ MWIFIEX_DFS_ADD_FILE(getlog);
+ MWIFIEX_DFS_ADD_FILE(regrdwr);
+ MWIFIEX_DFS_ADD_FILE(rdeeprom);
+}
+
+/*
+ * This function removes the debug FS directory structure and the files.
+ */
+void
+mwifiex_dev_debugfs_remove(struct mwifiex_private *priv)
+{
+ if (!priv)
+ return;
+
+ debugfs_remove_recursive(priv->dfs_dev_dir);
+}
+
+/*
+ * This function creates the top level proc directory.
+ */
+void
+mwifiex_debugfs_init(void)
+{
+ if (!mwifiex_dfs_dir)
+ mwifiex_dfs_dir = debugfs_create_dir("mwifiex", NULL);
+}
+
+/*
+ * This function removes the top level proc directory.
+ */
+void
+mwifiex_debugfs_remove(void)
+{
+ if (mwifiex_dfs_dir)
+ debugfs_remove(mwifiex_dfs_dir);
+}
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h
new file mode 100644
index 000000000000..0e90b0986ed8
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/decl.h
@@ -0,0 +1,129 @@
+/*
+ * Marvell Wireless LAN device driver: generic data structures and APIs
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef _MWIFIEX_DECL_H_
+#define _MWIFIEX_DECL_H_
+
+#undef pr_fmt
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/wait.h>
+#include <linux/timer.h>
+#include <linux/ieee80211.h>
+
+
+#define MWIFIEX_MAX_BSS_NUM (1)
+
+#define MWIFIEX_MIN_DATA_HEADER_LEN 32 /* (sizeof(mwifiex_txpd)) */
+
+#define MWIFIEX_MAX_TX_BASTREAM_SUPPORTED 2
+#define MWIFIEX_MAX_RX_BASTREAM_SUPPORTED 16
+
+#define MWIFIEX_AMPDU_DEF_TXWINSIZE 32
+#define MWIFIEX_AMPDU_DEF_RXWINSIZE 16
+#define MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT 0xffff
+
+#define MWIFIEX_RATE_INDEX_HRDSSS0 0
+#define MWIFIEX_RATE_INDEX_HRDSSS3 3
+#define MWIFIEX_RATE_INDEX_OFDM0 4
+#define MWIFIEX_RATE_INDEX_OFDM7 11
+#define MWIFIEX_RATE_INDEX_MCS0 12
+
+#define MWIFIEX_RATE_BITMAP_OFDM0 16
+#define MWIFIEX_RATE_BITMAP_OFDM7 23
+#define MWIFIEX_RATE_BITMAP_MCS0 32
+#define MWIFIEX_RATE_BITMAP_MCS127 159
+
+#define MWIFIEX_RX_DATA_BUF_SIZE (4 * 1024)
+
+#define MWIFIEX_RTS_MIN_VALUE (0)
+#define MWIFIEX_RTS_MAX_VALUE (2347)
+#define MWIFIEX_FRAG_MIN_VALUE (256)
+#define MWIFIEX_FRAG_MAX_VALUE (2346)
+
+#define MWIFIEX_SDIO_BLOCK_SIZE 256
+
+#define MWIFIEX_BUF_FLAG_REQUEUED_PKT BIT(0)
+
+enum mwifiex_bss_type {
+ MWIFIEX_BSS_TYPE_STA = 0,
+ MWIFIEX_BSS_TYPE_UAP = 1,
+ MWIFIEX_BSS_TYPE_ANY = 0xff,
+};
+
+enum mwifiex_bss_role {
+ MWIFIEX_BSS_ROLE_STA = 0,
+ MWIFIEX_BSS_ROLE_UAP = 1,
+ MWIFIEX_BSS_ROLE_ANY = 0xff,
+};
+
+#define BSS_ROLE_BIT_MASK BIT(0)
+
+#define GET_BSS_ROLE(priv) ((priv)->bss_role & BSS_ROLE_BIT_MASK)
+
+enum mwifiex_data_frame_type {
+ MWIFIEX_DATA_FRAME_TYPE_ETH_II = 0,
+ MWIFIEX_DATA_FRAME_TYPE_802_11,
+};
+
+struct mwifiex_fw_image {
+ u8 *helper_buf;
+ u32 helper_len;
+ u8 *fw_buf;
+ u32 fw_len;
+};
+
+struct mwifiex_802_11_ssid {
+ u32 ssid_len;
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+};
+
+struct mwifiex_wait_queue {
+ wait_queue_head_t wait;
+ u16 condition;
+ int status;
+};
+
+struct mwifiex_rxinfo {
+ u8 bss_index;
+ struct sk_buff *parent;
+ u8 use_count;
+};
+
+struct mwifiex_txinfo {
+ u32 status_code;
+ u8 flags;
+ u8 bss_index;
+};
+
+struct mwifiex_bss_attr {
+ u8 bss_type;
+ u8 frame_type;
+ u8 active;
+ u8 bss_priority;
+ u8 bss_num;
+};
+
+enum mwifiex_wmm_ac_e {
+ WMM_AC_BK,
+ WMM_AC_BE,
+ WMM_AC_VI,
+ WMM_AC_VO
+} __packed;
+#endif /* !_MWIFIEX_DECL_H_ */
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
new file mode 100644
index 000000000000..afdd145dff0b
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -0,0 +1,1187 @@
+/*
+ * Marvell Wireless LAN device driver: Firmware specific macros & structures
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef _MWIFIEX_FW_H_
+#define _MWIFIEX_FW_H_
+
+#include <linux/if_ether.h>
+
+
+#define INTF_HEADER_LEN 4
+
+struct rfc_1042_hdr {
+ u8 llc_dsap;
+ u8 llc_ssap;
+ u8 llc_ctrl;
+ u8 snap_oui[3];
+ u16 snap_type;
+};
+
+struct rx_packet_hdr {
+ struct ethhdr eth803_hdr;
+ struct rfc_1042_hdr rfc1042_hdr;
+};
+
+struct tx_packet_hdr {
+ struct ethhdr eth803_hdr;
+ struct rfc_1042_hdr rfc1042_hdr;
+};
+
+#define B_SUPPORTED_RATES 5
+#define G_SUPPORTED_RATES 9
+#define BG_SUPPORTED_RATES 13
+#define A_SUPPORTED_RATES 9
+#define HOSTCMD_SUPPORTED_RATES 14
+#define N_SUPPORTED_RATES 3
+#define ALL_802_11_BANDS (BAND_A | BAND_B | BAND_G | BAND_GN)
+
+#define FW_MULTI_BANDS_SUPPORT (BIT(8) | BIT(9) | BIT(10) | BIT(11))
+#define IS_SUPPORT_MULTI_BANDS(adapter) \
+ (adapter->fw_cap_info & FW_MULTI_BANDS_SUPPORT)
+#define GET_FW_DEFAULT_BANDS(adapter) \
+ ((adapter->fw_cap_info >> 8) & ALL_802_11_BANDS)
+
+extern u8 supported_rates_b[B_SUPPORTED_RATES];
+extern u8 supported_rates_g[G_SUPPORTED_RATES];
+extern u8 supported_rates_bg[BG_SUPPORTED_RATES];
+extern u8 supported_rates_a[A_SUPPORTED_RATES];
+extern u8 supported_rates_n[N_SUPPORTED_RATES];
+
+#define HostCmd_WEP_KEY_INDEX_MASK 0x3fff
+
+#define KEY_INFO_ENABLED 0x01
+enum KEY_TYPE_ID {
+ KEY_TYPE_ID_WEP = 0,
+ KEY_TYPE_ID_TKIP,
+ KEY_TYPE_ID_AES,
+ KEY_TYPE_ID_WAPI,
+};
+#define KEY_MCAST BIT(0)
+#define KEY_UNICAST BIT(1)
+#define KEY_ENABLED BIT(2)
+
+#define WAPI_KEY_LEN 50
+
+#define MAX_POLL_TRIES 100
+
+#define MAX_MULTI_INTERFACE_POLL_TRIES 1000
+
+#define MAX_FIRMWARE_POLL_TRIES 100
+
+#define FIRMWARE_READY 0xfedc
+
+enum MWIFIEX_802_11_PRIVACY_FILTER {
+ MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL,
+ MWIFIEX_802_11_PRIV_FILTER_8021X_WEP
+};
+
+enum MWIFIEX_802_11_WEP_STATUS {
+ MWIFIEX_802_11_WEP_ENABLED,
+ MWIFIEX_802_11_WEP_DISABLED,
+};
+
+#define CAL_SNR(RSSI, NF) ((s16)((s16)(RSSI)-(s16)(NF)))
+
+#define PROPRIETARY_TLV_BASE_ID 0x0100
+#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0)
+#define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 1)
+#define TLV_TYPE_NUMPROBES (PROPRIETARY_TLV_BASE_ID + 2)
+#define TLV_TYPE_PASSTHROUGH (PROPRIETARY_TLV_BASE_ID + 10)
+#define TLV_TYPE_WMMQSTATUS (PROPRIETARY_TLV_BASE_ID + 16)
+#define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18)
+#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19)
+#define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31)
+#define TLV_TYPE_CHANNELBANDLIST (PROPRIETARY_TLV_BASE_ID + 42)
+#define TLV_TYPE_RATE_DROP_CONTROL (PROPRIETARY_TLV_BASE_ID + 82)
+#define TLV_TYPE_RATE_SCOPE (PROPRIETARY_TLV_BASE_ID + 83)
+#define TLV_TYPE_POWER_GROUP (PROPRIETARY_TLV_BASE_ID + 84)
+#define TLV_TYPE_WAPI_IE (PROPRIETARY_TLV_BASE_ID + 94)
+#define TLV_TYPE_AUTO_DS_PARAM (PROPRIETARY_TLV_BASE_ID + 113)
+#define TLV_TYPE_PS_PARAM (PROPRIETARY_TLV_BASE_ID + 114)
+
+#define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048
+
+#define SSN_MASK 0xfff0
+
+#define BA_RESULT_SUCCESS 0x0
+#define BA_RESULT_TIMEOUT 0x2
+
+#define IS_BASTREAM_SETUP(ptr) (ptr->ba_status)
+
+#define BA_STREAM_NOT_ALLOWED 0xff
+
+#define IS_11N_ENABLED(priv) ((priv->adapter->config_bands & BAND_GN || \
+ priv->adapter->config_bands & BAND_AN) \
+ && priv->curr_bss_params.bss_descriptor.bcn_ht_cap)
+#define INITIATOR_BIT(DelBAParamSet) (((DelBAParamSet) &\
+ BIT(DELBA_INITIATOR_POS)) >> DELBA_INITIATOR_POS)
+
+#define MWIFIEX_TX_DATA_BUF_SIZE_4K 4096
+#define MWIFIEX_TX_DATA_BUF_SIZE_8K 8192
+
+#define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & BIT(11))
+
+/* dev_cap bitmap
+ * BIT
+ * 0-16 reserved
+ * 17 IEEE80211_HT_CAP_SUP_WIDTH_20_40
+ * 18-22 reserved
+ * 23 IEEE80211_HT_CAP_SGI_20
+ * 24 IEEE80211_HT_CAP_SGI_40
+ * 25 IEEE80211_HT_CAP_TX_STBC
+ * 26 IEEE80211_HT_CAP_RX_STBC
+ * 27-28 reserved
+ * 29 IEEE80211_HT_CAP_GRN_FLD
+ * 30-31 reserved
+ */
+#define ISSUPP_CHANWIDTH40(Dot11nDevCap) (Dot11nDevCap & BIT(17))
+#define ISSUPP_SHORTGI20(Dot11nDevCap) (Dot11nDevCap & BIT(23))
+#define ISSUPP_SHORTGI40(Dot11nDevCap) (Dot11nDevCap & BIT(24))
+#define ISSUPP_TXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(25))
+#define ISSUPP_RXSTBC(Dot11nDevCap) (Dot11nDevCap & BIT(26))
+#define ISSUPP_GREENFIELD(Dot11nDevCap) (Dot11nDevCap & BIT(29))
+
+#define GET_RXMCSSUPP(DevMCSSupported) (DevMCSSupported & 0x0f)
+#define SETHT_MCS32(x) (x[4] |= 1)
+
+#define SET_SECONDARYCHAN(RadioType, SECCHAN) (RadioType |= (SECCHAN << 4))
+
+#define LLC_SNAP_LEN 8
+
+#define MOD_CLASS_HR_DSSS 0x03
+#define MOD_CLASS_OFDM 0x07
+#define MOD_CLASS_HT 0x08
+#define HT_BW_20 0
+#define HT_BW_40 1
+
+#define HostCmd_CMD_GET_HW_SPEC 0x0003
+#define HostCmd_CMD_802_11_SCAN 0x0006
+#define HostCmd_CMD_802_11_GET_LOG 0x000b
+#define HostCmd_CMD_MAC_MULTICAST_ADR 0x0010
+#define HostCmd_CMD_802_11_EEPROM_ACCESS 0x0059
+#define HostCmd_CMD_802_11_ASSOCIATE 0x0012
+#define HostCmd_CMD_802_11_SNMP_MIB 0x0016
+#define HostCmd_CMD_MAC_REG_ACCESS 0x0019
+#define HostCmd_CMD_BBP_REG_ACCESS 0x001a
+#define HostCmd_CMD_RF_REG_ACCESS 0x001b
+#define HostCmd_CMD_PMIC_REG_ACCESS 0x00ad
+#define HostCmd_CMD_802_11_RF_CHANNEL 0x001d
+#define HostCmd_CMD_802_11_DEAUTHENTICATE 0x0024
+#define HostCmd_CMD_MAC_CONTROL 0x0028
+#define HostCmd_CMD_802_11_AD_HOC_START 0x002b
+#define HostCmd_CMD_802_11_AD_HOC_JOIN 0x002c
+#define HostCmd_CMD_802_11_AD_HOC_STOP 0x0040
+#define HostCmd_CMD_802_11_MAC_ADDRESS 0x004D
+#define HostCmd_CMD_802_11D_DOMAIN_INFO 0x005b
+#define HostCmd_CMD_802_11_KEY_MATERIAL 0x005e
+#define HostCmd_CMD_802_11_BG_SCAN_QUERY 0x006c
+#define HostCmd_CMD_WMM_GET_STATUS 0x0071
+#define HostCmd_CMD_802_11_TX_RATE_QUERY 0x007f
+#define HostCmd_CMD_802_11_IBSS_COALESCING_STATUS 0x0083
+#define HostCmd_CMD_VERSION_EXT 0x0097
+#define HostCmd_CMD_RSSI_INFO 0x00a4
+#define HostCmd_CMD_FUNC_INIT 0x00a9
+#define HostCmd_CMD_FUNC_SHUTDOWN 0x00aa
+#define HostCmd_CMD_11N_CFG 0x00cd
+#define HostCmd_CMD_11N_ADDBA_REQ 0x00ce
+#define HostCmd_CMD_11N_ADDBA_RSP 0x00cf
+#define HostCmd_CMD_11N_DELBA 0x00d0
+#define HostCmd_CMD_RECONFIGURE_TX_BUFF 0x00d9
+#define HostCmd_CMD_AMSDU_AGGR_CTRL 0x00df
+#define HostCmd_CMD_TXPWR_CFG 0x00d1
+#define HostCmd_CMD_TX_RATE_CFG 0x00d6
+#define HostCmd_CMD_802_11_PS_MODE_ENH 0x00e4
+#define HostCmd_CMD_802_11_HS_CFG_ENH 0x00e5
+#define HostCmd_CMD_CAU_REG_ACCESS 0x00ed
+#define HostCmd_CMD_SET_BSS_MODE 0x00f7
+
+
+enum ENH_PS_MODES {
+ EN_PS = 1,
+ DIS_PS = 2,
+ EN_AUTO_DS = 3,
+ DIS_AUTO_DS = 4,
+ SLEEP_CONFIRM = 5,
+ GET_PS = 0,
+ EN_AUTO_PS = 0xff,
+ DIS_AUTO_PS = 0xfe,
+};
+
+#define HostCmd_RET_BIT 0x8000
+#define HostCmd_ACT_GEN_GET 0x0000
+#define HostCmd_ACT_GEN_SET 0x0001
+#define HostCmd_RESULT_OK 0x0000
+
+#define HostCmd_ACT_MAC_RX_ON 0x0001
+#define HostCmd_ACT_MAC_TX_ON 0x0002
+#define HostCmd_ACT_MAC_WEP_ENABLE 0x0008
+#define HostCmd_ACT_MAC_ETHERNETII_ENABLE 0x0010
+#define HostCmd_ACT_MAC_PROMISCUOUS_ENABLE 0x0080
+#define HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE 0x0100
+#define HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON 0x2000
+
+#define HostCmd_BSS_MODE_IBSS 0x0002
+#define HostCmd_BSS_MODE_ANY 0x0003
+
+#define HostCmd_SCAN_RADIO_TYPE_BG 0
+#define HostCmd_SCAN_RADIO_TYPE_A 1
+
+#define HOST_SLEEP_CFG_CANCEL 0xffffffff
+#define HOST_SLEEP_CFG_COND_DEF 0x0000000f
+#define HOST_SLEEP_CFG_GPIO_DEF 0xff
+#define HOST_SLEEP_CFG_GAP_DEF 0
+
+#define CMD_F_HOSTCMD (1 << 0)
+#define CMD_F_CANCELED (1 << 1)
+
+#define HostCmd_CMD_ID_MASK 0x0fff
+
+#define HostCmd_SEQ_NUM_MASK 0x00ff
+
+#define HostCmd_BSS_NUM_MASK 0x0f00
+
+#define HostCmd_BSS_TYPE_MASK 0xf000
+
+#define HostCmd_SET_SEQ_NO_BSS_INFO(seq, num, type) { \
+ (((seq) & 0x00ff) | \
+ (((num) & 0x000f) << 8)) | \
+ (((type) & 0x000f) << 12); }
+
+#define HostCmd_GET_SEQ_NO(seq) \
+ ((seq) & HostCmd_SEQ_NUM_MASK)
+
+#define HostCmd_GET_BSS_NO(seq) \
+ (((seq) & HostCmd_BSS_NUM_MASK) >> 8)
+
+#define HostCmd_GET_BSS_TYPE(seq) \
+ (((seq) & HostCmd_BSS_TYPE_MASK) >> 12)
+
+#define EVENT_DUMMY_HOST_WAKEUP_SIGNAL 0x00000001
+#define EVENT_LINK_LOST 0x00000003
+#define EVENT_LINK_SENSED 0x00000004
+#define EVENT_MIB_CHANGED 0x00000006
+#define EVENT_INIT_DONE 0x00000007
+#define EVENT_DEAUTHENTICATED 0x00000008
+#define EVENT_DISASSOCIATED 0x00000009
+#define EVENT_PS_AWAKE 0x0000000a
+#define EVENT_PS_SLEEP 0x0000000b
+#define EVENT_MIC_ERR_MULTICAST 0x0000000d
+#define EVENT_MIC_ERR_UNICAST 0x0000000e
+#define EVENT_DEEP_SLEEP_AWAKE 0x00000010
+#define EVENT_ADHOC_BCN_LOST 0x00000011
+
+#define EVENT_WMM_STATUS_CHANGE 0x00000017
+#define EVENT_BG_SCAN_REPORT 0x00000018
+#define EVENT_RSSI_LOW 0x00000019
+#define EVENT_SNR_LOW 0x0000001a
+#define EVENT_MAX_FAIL 0x0000001b
+#define EVENT_RSSI_HIGH 0x0000001c
+#define EVENT_SNR_HIGH 0x0000001d
+#define EVENT_IBSS_COALESCED 0x0000001e
+#define EVENT_DATA_RSSI_LOW 0x00000024
+#define EVENT_DATA_SNR_LOW 0x00000025
+#define EVENT_DATA_RSSI_HIGH 0x00000026
+#define EVENT_DATA_SNR_HIGH 0x00000027
+#define EVENT_LINK_QUALITY 0x00000028
+#define EVENT_PORT_RELEASE 0x0000002b
+#define EVENT_PRE_BEACON_LOST 0x00000031
+#define EVENT_ADDBA 0x00000033
+#define EVENT_DELBA 0x00000034
+#define EVENT_BA_STREAM_TIEMOUT 0x00000037
+#define EVENT_AMSDU_AGGR_CTRL 0x00000042
+#define EVENT_WEP_ICV_ERR 0x00000046
+#define EVENT_HS_ACT_REQ 0x00000047
+#define EVENT_BW_CHANGE 0x00000048
+
+#define EVENT_HOSTWAKE_STAIE 0x0000004d
+
+#define EVENT_ID_MASK 0xffff
+#define BSS_NUM_MASK 0xf
+
+#define EVENT_GET_BSS_NUM(event_cause) \
+ (((event_cause) >> 16) & BSS_NUM_MASK)
+
+#define EVENT_GET_BSS_TYPE(event_cause) \
+ (((event_cause) >> 24) & 0x00ff)
+
+struct mwifiex_ie_types_header {
+ __le16 type;
+ __le16 len;
+} __packed;
+
+struct mwifiex_ie_types_data {
+ struct mwifiex_ie_types_header header;
+ u8 data[1];
+} __packed;
+
+#define MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET 0x01
+#define MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET 0x08
+
+struct txpd {
+ u8 bss_type;
+ u8 bss_num;
+ __le16 tx_pkt_length;
+ __le16 tx_pkt_offset;
+ __le16 tx_pkt_type;
+ __le32 tx_control;
+ u8 priority;
+ u8 flags;
+ u8 pkt_delay_2ms;
+ u8 reserved1;
+} __packed;
+
+struct rxpd {
+ u8 bss_type;
+ u8 bss_num;
+ u16 rx_pkt_length;
+ u16 rx_pkt_offset;
+ u16 rx_pkt_type;
+ u16 seq_num;
+ u8 priority;
+ u8 rx_rate;
+ s8 snr;
+ s8 nf;
+ /* Ht Info [Bit 0] RxRate format: LG=0, HT=1
+ * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1
+ * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */
+ u8 ht_info;
+ u8 reserved;
+} __packed;
+
+enum mwifiex_chan_scan_mode_bitmasks {
+ MWIFIEX_PASSIVE_SCAN = BIT(0),
+ MWIFIEX_DISABLE_CHAN_FILT = BIT(1),
+};
+
+#define SECOND_CHANNEL_BELOW 0x30
+#define SECOND_CHANNEL_ABOVE 0x10
+struct mwifiex_chan_scan_param_set {
+ u8 radio_type;
+ u8 chan_number;
+ u8 chan_scan_mode_bitmap;
+ __le16 min_scan_time;
+ __le16 max_scan_time;
+} __packed;
+
+struct mwifiex_ie_types_chan_list_param_set {
+ struct mwifiex_ie_types_header header;
+ struct mwifiex_chan_scan_param_set chan_scan_param[1];
+} __packed;
+
+struct chan_band_param_set {
+ u8 radio_type;
+ u8 chan_number;
+};
+
+struct mwifiex_ie_types_chan_band_list_param_set {
+ struct mwifiex_ie_types_header header;
+ struct chan_band_param_set chan_band_param[1];
+} __packed;
+
+struct mwifiex_ie_types_rates_param_set {
+ struct mwifiex_ie_types_header header;
+ u8 rates[1];
+} __packed;
+
+struct mwifiex_ie_types_ssid_param_set {
+ struct mwifiex_ie_types_header header;
+ u8 ssid[1];
+} __packed;
+
+struct mwifiex_ie_types_num_probes {
+ struct mwifiex_ie_types_header header;
+ __le16 num_probes;
+} __packed;
+
+struct mwifiex_ie_types_wildcard_ssid_params {
+ struct mwifiex_ie_types_header header;
+ u8 max_ssid_length;
+ u8 ssid[1];
+} __packed;
+
+#define TSF_DATA_SIZE 8
+struct mwifiex_ie_types_tsf_timestamp {
+ struct mwifiex_ie_types_header header;
+ u8 tsf_data[1];
+} __packed;
+
+struct mwifiex_cf_param_set {
+ u8 cfp_cnt;
+ u8 cfp_period;
+ u16 cfp_max_duration;
+ u16 cfp_duration_remaining;
+} __packed;
+
+struct mwifiex_ibss_param_set {
+ u16 atim_window;
+} __packed;
+
+struct mwifiex_ie_types_ss_param_set {
+ struct mwifiex_ie_types_header header;
+ union {
+ struct mwifiex_cf_param_set cf_param_set[1];
+ struct mwifiex_ibss_param_set ibss_param_set[1];
+ } cf_ibss;
+} __packed;
+
+struct mwifiex_fh_param_set {
+ u16 dwell_time;
+ u8 hop_set;
+ u8 hop_pattern;
+ u8 hop_index;
+} __packed;
+
+struct mwifiex_ds_param_set {
+ u8 current_chan;
+} __packed;
+
+struct mwifiex_ie_types_phy_param_set {
+ struct mwifiex_ie_types_header header;
+ union {
+ struct mwifiex_fh_param_set fh_param_set[1];
+ struct mwifiex_ds_param_set ds_param_set[1];
+ } fh_ds;
+} __packed;
+
+struct mwifiex_ie_types_auth_type {
+ struct mwifiex_ie_types_header header;
+ __le16 auth_type;
+} __packed;
+
+struct mwifiex_ie_types_vendor_param_set {
+ struct mwifiex_ie_types_header header;
+ u8 ie[MWIFIEX_MAX_VSIE_LEN];
+};
+
+struct mwifiex_ie_types_rsn_param_set {
+ struct mwifiex_ie_types_header header;
+ u8 rsn_ie[1];
+} __packed;
+
+#define KEYPARAMSET_FIXED_LEN 6
+
+struct mwifiex_ie_type_key_param_set {
+ __le16 type;
+ __le16 length;
+ __le16 key_type_id;
+ __le16 key_info;
+ __le16 key_len;
+ u8 key[50];
+} __packed;
+
+struct host_cmd_ds_802_11_key_material {
+ __le16 action;
+ struct mwifiex_ie_type_key_param_set key_param_set;
+} __packed;
+
+struct host_cmd_ds_gen {
+ u16 command;
+ u16 size;
+ u16 seq_num;
+ u16 result;
+};
+
+#define S_DS_GEN sizeof(struct host_cmd_ds_gen)
+
+enum sleep_resp_ctrl {
+ RESP_NOT_NEEDED = 0,
+ RESP_NEEDED,
+};
+
+struct mwifiex_ps_param {
+ __le16 null_pkt_interval;
+ __le16 multiple_dtims;
+ __le16 bcn_miss_timeout;
+ __le16 local_listen_interval;
+ __le16 adhoc_wake_period;
+ __le16 mode;
+ __le16 delay_to_ps;
+};
+
+#define BITMAP_AUTO_DS 0x01
+#define BITMAP_STA_PS 0x10
+
+struct mwifiex_ie_types_auto_ds_param {
+ struct mwifiex_ie_types_header header;
+ __le16 deep_sleep_timeout;
+} __packed;
+
+struct mwifiex_ie_types_ps_param {
+ struct mwifiex_ie_types_header header;
+ struct mwifiex_ps_param param;
+} __packed;
+
+struct host_cmd_ds_802_11_ps_mode_enh {
+ __le16 action;
+
+ union {
+ struct mwifiex_ps_param opt_ps;
+ __le16 ps_bitmap;
+ } params;
+} __packed;
+
+struct host_cmd_ds_get_hw_spec {
+ __le16 hw_if_version;
+ __le16 version;
+ __le16 reserved;
+ __le16 num_of_mcast_adr;
+ u8 permanent_addr[ETH_ALEN];
+ __le16 region_code;
+ __le16 number_of_antenna;
+ __le32 fw_release_number;
+ __le32 reserved_1;
+ __le32 reserved_2;
+ __le32 reserved_3;
+ __le32 fw_cap_info;
+ __le32 dot_11n_dev_cap;
+ u8 dev_mcs_support;
+ __le16 mp_end_port; /* SDIO only, reserved for other interfacces */
+ __le16 reserved_4;
+} __packed;
+
+struct host_cmd_ds_802_11_rssi_info {
+ __le16 action;
+ __le16 ndata;
+ __le16 nbcn;
+ __le16 reserved[9];
+ long long reserved_1;
+};
+
+struct host_cmd_ds_802_11_rssi_info_rsp {
+ __le16 action;
+ __le16 ndata;
+ __le16 nbcn;
+ __le16 data_rssi_last;
+ __le16 data_nf_last;
+ __le16 data_rssi_avg;
+ __le16 data_nf_avg;
+ __le16 bcn_rssi_last;
+ __le16 bcn_nf_last;
+ __le16 bcn_rssi_avg;
+ __le16 bcn_nf_avg;
+ long long tsf_bcn;
+};
+
+struct host_cmd_ds_802_11_mac_address {
+ __le16 action;
+ u8 mac_addr[ETH_ALEN];
+};
+
+struct host_cmd_ds_mac_control {
+ __le16 action;
+ __le16 reserved;
+};
+
+struct host_cmd_ds_mac_multicast_adr {
+ __le16 action;
+ __le16 num_of_adrs;
+ u8 mac_list[MWIFIEX_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
+} __packed;
+
+struct host_cmd_ds_802_11_deauthenticate {
+ u8 mac_addr[ETH_ALEN];
+ __le16 reason_code;
+} __packed;
+
+struct host_cmd_ds_802_11_associate {
+ u8 peer_sta_addr[ETH_ALEN];
+ __le16 cap_info_bitmap;
+ __le16 listen_interval;
+ __le16 beacon_period;
+ u8 dtim_period;
+} __packed;
+
+struct ieee_types_assoc_rsp {
+ __le16 cap_info_bitmap;
+ __le16 status_code;
+ __le16 a_id;
+ u8 ie_buffer[1];
+} __packed;
+
+struct host_cmd_ds_802_11_associate_rsp {
+ struct ieee_types_assoc_rsp assoc_rsp;
+} __packed;
+
+struct ieee_types_cf_param_set {
+ u8 element_id;
+ u8 len;
+ u8 cfp_cnt;
+ u8 cfp_period;
+ u16 cfp_max_duration;
+ u16 cfp_duration_remaining;
+} __packed;
+
+struct ieee_types_ibss_param_set {
+ u8 element_id;
+ u8 len;
+ __le16 atim_window;
+} __packed;
+
+union ieee_types_ss_param_set {
+ struct ieee_types_cf_param_set cf_param_set;
+ struct ieee_types_ibss_param_set ibss_param_set;
+} __packed;
+
+struct ieee_types_fh_param_set {
+ u8 element_id;
+ u8 len;
+ __le16 dwell_time;
+ u8 hop_set;
+ u8 hop_pattern;
+ u8 hop_index;
+} __packed;
+
+struct ieee_types_ds_param_set {
+ u8 element_id;
+ u8 len;
+ u8 current_chan;
+} __packed;
+
+union ieee_types_phy_param_set {
+ struct ieee_types_fh_param_set fh_param_set;
+ struct ieee_types_ds_param_set ds_param_set;
+} __packed;
+
+struct host_cmd_ds_802_11_ad_hoc_start {
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+ u8 bss_mode;
+ __le16 beacon_period;
+ u8 dtim_period;
+ union ieee_types_ss_param_set ss_param_set;
+ union ieee_types_phy_param_set phy_param_set;
+ u16 reserved1;
+ __le16 cap_info_bitmap;
+ u8 DataRate[HOSTCMD_SUPPORTED_RATES];
+} __packed;
+
+struct host_cmd_ds_802_11_ad_hoc_result {
+ u8 pad[3];
+ u8 bssid[ETH_ALEN];
+} __packed;
+
+struct adhoc_bss_desc {
+ u8 bssid[ETH_ALEN];
+ u8 ssid[IEEE80211_MAX_SSID_LEN];
+ u8 bss_mode;
+ __le16 beacon_period;
+ u8 dtim_period;
+ u8 time_stamp[8];
+ u8 local_time[8];
+ union ieee_types_phy_param_set phy_param_set;
+ union ieee_types_ss_param_set ss_param_set;
+ __le16 cap_info_bitmap;
+ u8 data_rates[HOSTCMD_SUPPORTED_RATES];
+
+ /*
+ * DO NOT ADD ANY FIELDS TO THIS STRUCTURE.
+ * It is used in the Adhoc join command and will cause a
+ * binary layout mismatch with the firmware
+ */
+} __packed;
+
+struct host_cmd_ds_802_11_ad_hoc_join {
+ struct adhoc_bss_desc bss_descriptor;
+ u16 reserved1;
+ u16 reserved2;
+} __packed;
+
+struct host_cmd_ds_802_11_get_log {
+ __le32 mcast_tx_frame;
+ __le32 failed;
+ __le32 retry;
+ __le32 multi_retry;
+ __le32 frame_dup;
+ __le32 rts_success;
+ __le32 rts_failure;
+ __le32 ack_failure;
+ __le32 rx_frag;
+ __le32 mcast_rx_frame;
+ __le32 fcs_error;
+ __le32 tx_frame;
+ __le32 reserved;
+ __le32 wep_icv_err_cnt[4];
+};
+
+struct host_cmd_ds_tx_rate_query {
+ u8 tx_rate;
+ /* Ht Info [Bit 0] RxRate format: LG=0, HT=1
+ * [Bit 1] HT Bandwidth: BW20 = 0, BW40 = 1
+ * [Bit 2] HT Guard Interval: LGI = 0, SGI = 1 */
+ u8 ht_info;
+} __packed;
+
+enum Host_Sleep_Action {
+ HS_CONFIGURE = 0x0001,
+ HS_ACTIVATE = 0x0002,
+};
+
+struct mwifiex_hs_config_param {
+ __le32 conditions;
+ u8 gpio;
+ u8 gap;
+} __packed;
+
+struct hs_activate_param {
+ u16 resp_ctrl;
+} __packed;
+
+struct host_cmd_ds_802_11_hs_cfg_enh {
+ __le16 action;
+
+ union {
+ struct mwifiex_hs_config_param hs_config;
+ struct hs_activate_param hs_activate;
+ } params;
+} __packed;
+
+enum SNMP_MIB_INDEX {
+ OP_RATE_SET_I = 1,
+ DTIM_PERIOD_I = 3,
+ RTS_THRESH_I = 5,
+ SHORT_RETRY_LIM_I = 6,
+ LONG_RETRY_LIM_I = 7,
+ FRAG_THRESH_I = 8,
+ DOT11D_I = 9,
+};
+
+#define MAX_SNMP_BUF_SIZE 128
+
+struct host_cmd_ds_802_11_snmp_mib {
+ __le16 query_type;
+ __le16 oid;
+ __le16 buf_size;
+ u8 value[1];
+} __packed;
+
+struct mwifiex_rate_scope {
+ __le16 type;
+ __le16 length;
+ __le16 hr_dsss_rate_bitmap;
+ __le16 ofdm_rate_bitmap;
+ __le16 ht_mcs_rate_bitmap[8];
+} __packed;
+
+struct mwifiex_rate_drop_pattern {
+ __le16 type;
+ __le16 length;
+ __le32 rate_drop_mode;
+} __packed;
+
+struct host_cmd_ds_tx_rate_cfg {
+ __le16 action;
+ __le16 cfg_index;
+} __packed;
+
+struct mwifiex_power_group {
+ u8 modulation_class;
+ u8 first_rate_code;
+ u8 last_rate_code;
+ s8 power_step;
+ s8 power_min;
+ s8 power_max;
+ u8 ht_bandwidth;
+ u8 reserved;
+} __packed;
+
+struct mwifiex_types_power_group {
+ u16 type;
+ u16 length;
+} __packed;
+
+struct host_cmd_ds_txpwr_cfg {
+ __le16 action;
+ __le16 cfg_index;
+ __le32 mode;
+} __packed;
+
+#define MWIFIEX_USER_SCAN_CHAN_MAX 50
+
+#define MWIFIEX_MAX_SSID_LIST_LENGTH 10
+
+struct mwifiex_scan_cmd_config {
+ /*
+ * BSS mode to be sent in the firmware command
+ */
+ u8 bss_mode;
+
+ /* Specific BSSID used to filter scan results in the firmware */
+ u8 specific_bssid[ETH_ALEN];
+
+ /* Length of TLVs sent in command starting at tlvBuffer */
+ u32 tlv_buf_len;
+
+ /*
+ * SSID TLV(s) and ChanList TLVs to be sent in the firmware command
+ *
+ * TLV_TYPE_CHANLIST, mwifiex_ie_types_chan_list_param_set
+ * WLAN_EID_SSID, mwifiex_ie_types_ssid_param_set
+ */
+ u8 tlv_buf[1]; /* SSID TLV(s) and ChanList TLVs are stored
+ here */
+} __packed;
+
+struct mwifiex_user_scan_chan {
+ u8 chan_number;
+ u8 radio_type;
+ u8 scan_type;
+ u8 reserved;
+ u32 scan_time;
+} __packed;
+
+struct mwifiex_user_scan_ssid {
+ u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
+ u8 max_len;
+} __packed;
+
+struct mwifiex_user_scan_cfg {
+ /*
+ * Flag set to keep the previous scan table intact
+ *
+ * If set, the scan results will accumulate, replacing any previous
+ * matched entries for a BSS with the new scan data
+ */
+ u8 keep_previous_scan;
+ /*
+ * BSS mode to be sent in the firmware command
+ */
+ u8 bss_mode;
+ /* Configure the number of probe requests for active chan scans */
+ u8 num_probes;
+ u8 reserved;
+ /* BSSID filter sent in the firmware command to limit the results */
+ u8 specific_bssid[ETH_ALEN];
+ /* SSID filter list used in the to limit the scan results */
+ struct mwifiex_user_scan_ssid ssid_list[MWIFIEX_MAX_SSID_LIST_LENGTH];
+ /* Variable number (fixed maximum) of channels to scan up */
+ struct mwifiex_user_scan_chan chan_list[MWIFIEX_USER_SCAN_CHAN_MAX];
+} __packed;
+
+struct ie_body {
+ u8 grp_key_oui[4];
+ u8 ptk_cnt[2];
+ u8 ptk_body[4];
+} __packed;
+
+struct host_cmd_ds_802_11_scan {
+ u8 bss_mode;
+ u8 bssid[ETH_ALEN];
+ u8 tlv_buffer[1];
+} __packed;
+
+struct host_cmd_ds_802_11_scan_rsp {
+ __le16 bss_descript_size;
+ u8 number_of_sets;
+ u8 bss_desc_and_tlv_buffer[1];
+} __packed;
+
+struct host_cmd_ds_802_11_bg_scan_query {
+ u8 flush;
+} __packed;
+
+struct host_cmd_ds_802_11_bg_scan_query_rsp {
+ u32 report_condition;
+ struct host_cmd_ds_802_11_scan_rsp scan_resp;
+} __packed;
+
+struct mwifiex_ietypes_domain_param_set {
+ struct mwifiex_ie_types_header header;
+ u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
+ struct ieee80211_country_ie_triplet triplet[1];
+} __packed;
+
+struct host_cmd_ds_802_11d_domain_info {
+ __le16 action;
+ struct mwifiex_ietypes_domain_param_set domain;
+} __packed;
+
+struct host_cmd_ds_802_11d_domain_info_rsp {
+ __le16 action;
+ struct mwifiex_ietypes_domain_param_set domain;
+} __packed;
+
+struct host_cmd_ds_11n_addba_req {
+ u8 add_req_result;
+ u8 peer_mac_addr[ETH_ALEN];
+ u8 dialog_token;
+ __le16 block_ack_param_set;
+ __le16 block_ack_tmo;
+ __le16 ssn;
+} __packed;
+
+struct host_cmd_ds_11n_addba_rsp {
+ u8 add_rsp_result;
+ u8 peer_mac_addr[ETH_ALEN];
+ u8 dialog_token;
+ __le16 status_code;
+ __le16 block_ack_param_set;
+ __le16 block_ack_tmo;
+ __le16 ssn;
+} __packed;
+
+struct host_cmd_ds_11n_delba {
+ u8 del_result;
+ u8 peer_mac_addr[ETH_ALEN];
+ __le16 del_ba_param_set;
+ __le16 reason_code;
+ u8 reserved;
+} __packed;
+
+struct host_cmd_ds_11n_batimeout {
+ u8 tid;
+ u8 peer_mac_addr[ETH_ALEN];
+ u8 origninator;
+} __packed;
+
+struct host_cmd_ds_11n_cfg {
+ __le16 action;
+ __le16 ht_tx_cap;
+ __le16 ht_tx_info;
+} __packed;
+
+struct host_cmd_ds_txbuf_cfg {
+ __le16 action;
+ __le16 buff_size;
+ __le16 mp_end_port; /* SDIO only, reserved for other interfacces */
+ __le16 reserved3;
+} __packed;
+
+struct host_cmd_ds_amsdu_aggr_ctrl {
+ __le16 action;
+ __le16 enable;
+ __le16 curr_buf_size;
+} __packed;
+
+struct mwifiex_ie_types_wmm_param_set {
+ struct mwifiex_ie_types_header header;
+ u8 wmm_ie[1];
+};
+
+struct mwifiex_ie_types_wmm_queue_status {
+ struct mwifiex_ie_types_header header;
+ u8 queue_index;
+ u8 disabled;
+ u16 medium_time;
+ u8 flow_required;
+ u8 flow_created;
+ u32 reserved;
+};
+
+struct ieee_types_vendor_header {
+ u8 element_id;
+ u8 len;
+ u8 oui[3];
+ u8 oui_type;
+ u8 oui_subtype;
+ u8 version;
+} __packed;
+
+struct ieee_types_wmm_ac_parameters {
+ u8 aci_aifsn_bitmap;
+ u8 ecw_bitmap;
+ __le16 tx_op_limit;
+} __packed;
+
+struct ieee_types_wmm_parameter {
+ /*
+ * WMM Parameter IE - Vendor Specific Header:
+ * element_id [221/0xdd]
+ * Len [24]
+ * Oui [00:50:f2]
+ * OuiType [2]
+ * OuiSubType [1]
+ * Version [1]
+ */
+ struct ieee_types_vendor_header vend_hdr;
+ u8 qos_info_bitmap;
+ u8 reserved;
+ struct ieee_types_wmm_ac_parameters ac_params[IEEE80211_MAX_QUEUES];
+} __packed;
+
+struct ieee_types_wmm_info {
+
+ /*
+ * WMM Info IE - Vendor Specific Header:
+ * element_id [221/0xdd]
+ * Len [7]
+ * Oui [00:50:f2]
+ * OuiType [2]
+ * OuiSubType [0]
+ * Version [1]
+ */
+ struct ieee_types_vendor_header vend_hdr;
+
+ u8 qos_info_bitmap;
+} __packed;
+
+struct host_cmd_ds_wmm_get_status {
+ u8 queue_status_tlv[sizeof(struct mwifiex_ie_types_wmm_queue_status) *
+ IEEE80211_MAX_QUEUES];
+ u8 wmm_param_tlv[sizeof(struct ieee_types_wmm_parameter) + 2];
+} __packed;
+
+struct mwifiex_wmm_ac_status {
+ u8 disabled;
+ u8 flow_required;
+ u8 flow_created;
+};
+
+struct mwifiex_ie_types_htcap {
+ struct mwifiex_ie_types_header header;
+ struct ieee80211_ht_cap ht_cap;
+} __packed;
+
+struct mwifiex_ie_types_htinfo {
+ struct mwifiex_ie_types_header header;
+ struct ieee80211_ht_info ht_info;
+} __packed;
+
+struct mwifiex_ie_types_2040bssco {
+ struct mwifiex_ie_types_header header;
+ u8 bss_co_2040;
+} __packed;
+
+struct mwifiex_ie_types_extcap {
+ struct mwifiex_ie_types_header header;
+ u8 ext_cap;
+} __packed;
+
+struct host_cmd_ds_mac_reg_access {
+ __le16 action;
+ __le16 offset;
+ __le32 value;
+} __packed;
+
+struct host_cmd_ds_bbp_reg_access {
+ __le16 action;
+ __le16 offset;
+ u8 value;
+ u8 reserved[3];
+} __packed;
+
+struct host_cmd_ds_rf_reg_access {
+ __le16 action;
+ __le16 offset;
+ u8 value;
+ u8 reserved[3];
+} __packed;
+
+struct host_cmd_ds_pmic_reg_access {
+ __le16 action;
+ __le16 offset;
+ u8 value;
+ u8 reserved[3];
+} __packed;
+
+struct host_cmd_ds_802_11_eeprom_access {
+ __le16 action;
+
+ __le16 offset;
+ __le16 byte_count;
+ u8 value;
+} __packed;
+
+struct host_cmd_ds_802_11_rf_channel {
+ __le16 action;
+ __le16 current_channel;
+ __le16 rf_type;
+ __le16 reserved;
+ u8 reserved_1[32];
+} __packed;
+
+struct host_cmd_ds_version_ext {
+ u8 version_str_sel;
+ char version_str[128];
+} __packed;
+
+struct host_cmd_ds_802_11_ibss_status {
+ __le16 action;
+ __le16 enable;
+ u8 bssid[ETH_ALEN];
+ __le16 beacon_interval;
+ __le16 atim_window;
+ __le16 use_g_rate_protect;
+} __packed;
+
+#define CONNECTION_TYPE_INFRA 0
+#define CONNECTION_TYPE_ADHOC 1
+
+struct host_cmd_ds_set_bss_mode {
+ u8 con_type;
+} __packed;
+
+struct host_cmd_ds_command {
+ __le16 command;
+ __le16 size;
+ __le16 seq_num;
+ __le16 result;
+ union {
+ struct host_cmd_ds_get_hw_spec hw_spec;
+ struct host_cmd_ds_mac_control mac_ctrl;
+ struct host_cmd_ds_802_11_mac_address mac_addr;
+ struct host_cmd_ds_mac_multicast_adr mc_addr;
+ struct host_cmd_ds_802_11_get_log get_log;
+ struct host_cmd_ds_802_11_rssi_info rssi_info;
+ struct host_cmd_ds_802_11_rssi_info_rsp rssi_info_rsp;
+ struct host_cmd_ds_802_11_snmp_mib smib;
+ struct host_cmd_ds_802_11_rf_channel rf_channel;
+ struct host_cmd_ds_tx_rate_query tx_rate;
+ struct host_cmd_ds_tx_rate_cfg tx_rate_cfg;
+ struct host_cmd_ds_txpwr_cfg txp_cfg;
+ struct host_cmd_ds_802_11_ps_mode_enh psmode_enh;
+ struct host_cmd_ds_802_11_hs_cfg_enh opt_hs_cfg;
+ struct host_cmd_ds_802_11_scan scan;
+ struct host_cmd_ds_802_11_scan_rsp scan_resp;
+ struct host_cmd_ds_802_11_bg_scan_query bg_scan_query;
+ struct host_cmd_ds_802_11_bg_scan_query_rsp bg_scan_query_resp;
+ struct host_cmd_ds_802_11_associate associate;
+ struct host_cmd_ds_802_11_associate_rsp associate_rsp;
+ struct host_cmd_ds_802_11_deauthenticate deauth;
+ struct host_cmd_ds_802_11_ad_hoc_start adhoc_start;
+ struct host_cmd_ds_802_11_ad_hoc_result adhoc_result;
+ struct host_cmd_ds_802_11_ad_hoc_join adhoc_join;
+ struct host_cmd_ds_802_11d_domain_info domain_info;
+ struct host_cmd_ds_802_11d_domain_info_rsp domain_info_resp;
+ struct host_cmd_ds_11n_addba_req add_ba_req;
+ struct host_cmd_ds_11n_addba_rsp add_ba_rsp;
+ struct host_cmd_ds_11n_delba del_ba;
+ struct host_cmd_ds_txbuf_cfg tx_buf;
+ struct host_cmd_ds_amsdu_aggr_ctrl amsdu_aggr_ctrl;
+ struct host_cmd_ds_11n_cfg htcfg;
+ struct host_cmd_ds_wmm_get_status get_wmm_status;
+ struct host_cmd_ds_802_11_key_material key_material;
+ struct host_cmd_ds_version_ext verext;
+ struct host_cmd_ds_802_11_ibss_status ibss_coalescing;
+ struct host_cmd_ds_mac_reg_access mac_reg;
+ struct host_cmd_ds_bbp_reg_access bbp_reg;
+ struct host_cmd_ds_rf_reg_access rf_reg;
+ struct host_cmd_ds_pmic_reg_access pmic_reg;
+ struct host_cmd_ds_set_bss_mode bss_mode;
+ struct host_cmd_ds_802_11_eeprom_access eeprom;
+ } params;
+} __packed;
+
+struct mwifiex_opt_sleep_confirm {
+ __le16 command;
+ __le16 size;
+ __le16 seq_num;
+ __le16 result;
+ __le16 action;
+ __le16 resp_ctrl;
+} __packed;
+#endif /* !_MWIFIEX_FW_H_ */
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
new file mode 100644
index 000000000000..3f1559e61320
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -0,0 +1,645 @@
+/*
+ * Marvell Wireless LAN device driver: HW/FW Initialization
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+
+/*
+ * This function adds a BSS priority table to the table list.
+ *
+ * The function allocates a new BSS priority table node and adds it to
+ * the end of BSS priority table list, kept in driver memory.
+ */
+static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_bss_prio_node *bss_prio;
+ unsigned long flags;
+
+ bss_prio = kzalloc(sizeof(struct mwifiex_bss_prio_node), GFP_KERNEL);
+ if (!bss_prio) {
+ dev_err(adapter->dev, "%s: failed to alloc bss_prio\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ bss_prio->priv = priv;
+ INIT_LIST_HEAD(&bss_prio->list);
+ if (!adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur)
+ adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur =
+ bss_prio;
+
+ spin_lock_irqsave(&adapter->bss_prio_tbl[priv->bss_priority]
+ .bss_prio_lock, flags);
+ list_add_tail(&bss_prio->list,
+ &adapter->bss_prio_tbl[priv->bss_priority]
+ .bss_prio_head);
+ spin_unlock_irqrestore(&adapter->bss_prio_tbl[priv->bss_priority]
+ .bss_prio_lock, flags);
+
+ return 0;
+}
+
+/*
+ * This function initializes the private structure and sets default
+ * values to the members.
+ *
+ * Additionally, it also initializes all the locks and sets up all the
+ * lists.
+ */
+static int mwifiex_init_priv(struct mwifiex_private *priv)
+{
+ u32 i;
+
+ priv->media_connected = false;
+ memset(priv->curr_addr, 0xff, ETH_ALEN);
+
+ priv->pkt_tx_ctrl = 0;
+ priv->bss_mode = NL80211_IFTYPE_STATION;
+ priv->data_rate = 0; /* Initially indicate the rate as auto */
+ priv->is_data_rate_auto = true;
+ priv->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR;
+ priv->data_avg_factor = DEFAULT_DATA_AVG_FACTOR;
+
+ priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED;
+ priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM;
+ priv->sec_info.encryption_mode = 0;
+ for (i = 0; i < ARRAY_SIZE(priv->wep_key); i++)
+ memset(&priv->wep_key[i], 0, sizeof(struct mwifiex_wep_key));
+ priv->wep_key_curr_index = 0;
+ priv->curr_pkt_filter = HostCmd_ACT_MAC_RX_ON | HostCmd_ACT_MAC_TX_ON |
+ HostCmd_ACT_MAC_ETHERNETII_ENABLE;
+
+ priv->beacon_period = 100; /* beacon interval */ ;
+ priv->attempted_bss_desc = NULL;
+ memset(&priv->curr_bss_params, 0, sizeof(priv->curr_bss_params));
+ priv->listen_interval = MWIFIEX_DEFAULT_LISTEN_INTERVAL;
+
+ memset(&priv->prev_ssid, 0, sizeof(priv->prev_ssid));
+ memset(&priv->prev_bssid, 0, sizeof(priv->prev_bssid));
+ memset(&priv->assoc_rsp_buf, 0, sizeof(priv->assoc_rsp_buf));
+ priv->assoc_rsp_size = 0;
+ priv->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
+ priv->atim_window = 0;
+ priv->adhoc_state = ADHOC_IDLE;
+ priv->tx_power_level = 0;
+ priv->max_tx_power_level = 0;
+ priv->min_tx_power_level = 0;
+ priv->tx_rate = 0;
+ priv->rxpd_htinfo = 0;
+ priv->rxpd_rate = 0;
+ priv->rate_bitmap = 0;
+ priv->data_rssi_last = 0;
+ priv->data_rssi_avg = 0;
+ priv->data_nf_avg = 0;
+ priv->data_nf_last = 0;
+ priv->bcn_rssi_last = 0;
+ priv->bcn_rssi_avg = 0;
+ priv->bcn_nf_avg = 0;
+ priv->bcn_nf_last = 0;
+ memset(&priv->wpa_ie, 0, sizeof(priv->wpa_ie));
+ memset(&priv->aes_key, 0, sizeof(priv->aes_key));
+ priv->wpa_ie_len = 0;
+ priv->wpa_is_gtk_set = false;
+
+ memset(&priv->assoc_tlv_buf, 0, sizeof(priv->assoc_tlv_buf));
+ priv->assoc_tlv_buf_len = 0;
+ memset(&priv->wps, 0, sizeof(priv->wps));
+ memset(&priv->gen_ie_buf, 0, sizeof(priv->gen_ie_buf));
+ priv->gen_ie_buf_len = 0;
+ memset(priv->vs_ie, 0, sizeof(priv->vs_ie));
+
+ priv->wmm_required = true;
+ priv->wmm_enabled = false;
+ priv->wmm_qosinfo = 0;
+ priv->curr_bcn_buf = NULL;
+ priv->curr_bcn_size = 0;
+
+ priv->scan_block = false;
+
+ return mwifiex_add_bss_prio_tbl(priv);
+}
+
+/*
+ * This function allocates buffers for members of the adapter
+ * structure.
+ *
+ * The memory allocated includes scan table, command buffers, and
+ * sleep confirm command buffer. In addition, the queues are
+ * also initialized.
+ */
+static int mwifiex_allocate_adapter(struct mwifiex_adapter *adapter)
+{
+ int ret;
+ u32 buf_size;
+ struct mwifiex_bssdescriptor *temp_scan_table;
+
+ /* Allocate buffer to store the BSSID list */
+ buf_size = sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP;
+ temp_scan_table = kzalloc(buf_size, GFP_KERNEL);
+ if (!temp_scan_table) {
+ dev_err(adapter->dev, "%s: failed to alloc temp_scan_table\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ adapter->scan_table = temp_scan_table;
+
+ /* Allocate command buffer */
+ ret = mwifiex_alloc_cmd_buffer(adapter);
+ if (ret) {
+ dev_err(adapter->dev, "%s: failed to alloc cmd buffer\n",
+ __func__);
+ return -1;
+ }
+
+ adapter->sleep_cfm =
+ dev_alloc_skb(sizeof(struct mwifiex_opt_sleep_confirm)
+ + INTF_HEADER_LEN);
+
+ if (!adapter->sleep_cfm) {
+ dev_err(adapter->dev, "%s: failed to alloc sleep cfm"
+ " cmd buffer\n", __func__);
+ return -1;
+ }
+ skb_reserve(adapter->sleep_cfm, INTF_HEADER_LEN);
+
+ return 0;
+}
+
+/*
+ * This function initializes the adapter structure and sets default
+ * values to the members of adapter.
+ *
+ * This also initializes the WMM related parameters in the driver private
+ * structures.
+ */
+static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
+{
+ struct mwifiex_opt_sleep_confirm *sleep_cfm_buf = NULL;
+
+ skb_put(adapter->sleep_cfm, sizeof(struct mwifiex_opt_sleep_confirm));
+ sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm *)
+ (adapter->sleep_cfm->data);
+
+ adapter->cmd_sent = false;
+ adapter->data_sent = true;
+ adapter->cmd_resp_received = false;
+ adapter->event_received = false;
+ adapter->data_received = false;
+
+ adapter->surprise_removed = false;
+
+ adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING;
+
+ adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
+ adapter->ps_state = PS_STATE_AWAKE;
+ adapter->need_to_wakeup = false;
+
+ adapter->scan_mode = HostCmd_BSS_MODE_ANY;
+ adapter->specific_scan_time = MWIFIEX_SPECIFIC_SCAN_CHAN_TIME;
+ adapter->active_scan_time = MWIFIEX_ACTIVE_SCAN_CHAN_TIME;
+ adapter->passive_scan_time = MWIFIEX_PASSIVE_SCAN_CHAN_TIME;
+
+ adapter->num_in_scan_table = 0;
+ memset(adapter->scan_table, 0,
+ (sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP));
+ adapter->scan_probes = 1;
+
+ memset(adapter->bcn_buf, 0, sizeof(adapter->bcn_buf));
+ adapter->bcn_buf_end = adapter->bcn_buf;
+
+ adapter->multiple_dtim = 1;
+
+ adapter->local_listen_interval = 0; /* default value in firmware
+ will be used */
+
+ adapter->is_deep_sleep = false;
+
+ adapter->delay_null_pkt = false;
+ adapter->delay_to_ps = 1000;
+ adapter->enhanced_ps_mode = PS_MODE_AUTO;
+
+ adapter->gen_null_pkt = false; /* Disable NULL Pkg generation by
+ default */
+ adapter->pps_uapsd_mode = false; /* Disable pps/uapsd mode by
+ default */
+ adapter->pm_wakeup_card_req = false;
+
+ adapter->pm_wakeup_fw_try = false;
+
+ adapter->max_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
+ adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
+ adapter->curr_tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
+
+ adapter->is_hs_configured = false;
+ adapter->hs_cfg.conditions = cpu_to_le32(HOST_SLEEP_CFG_COND_DEF);
+ adapter->hs_cfg.gpio = HOST_SLEEP_CFG_GPIO_DEF;
+ adapter->hs_cfg.gap = HOST_SLEEP_CFG_GAP_DEF;
+ adapter->hs_activated = false;
+
+ memset(adapter->event_body, 0, sizeof(adapter->event_body));
+ adapter->hw_dot_11n_dev_cap = 0;
+ adapter->hw_dev_mcs_support = 0;
+ adapter->chan_offset = 0;
+ adapter->adhoc_11n_enabled = false;
+
+ mwifiex_wmm_init(adapter);
+
+ if (adapter->sleep_cfm) {
+ memset(sleep_cfm_buf, 0, adapter->sleep_cfm->len);
+ sleep_cfm_buf->command =
+ cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH);
+ sleep_cfm_buf->size =
+ cpu_to_le16(adapter->sleep_cfm->len);
+ sleep_cfm_buf->result = 0;
+ sleep_cfm_buf->action = cpu_to_le16(SLEEP_CONFIRM);
+ sleep_cfm_buf->resp_ctrl = cpu_to_le16(RESP_NEEDED);
+ }
+ memset(&adapter->sleep_params, 0, sizeof(adapter->sleep_params));
+ memset(&adapter->sleep_period, 0, sizeof(adapter->sleep_period));
+ adapter->tx_lock_flag = false;
+ adapter->null_pkt_interval = 0;
+ adapter->fw_bands = 0;
+ adapter->config_bands = 0;
+ adapter->adhoc_start_band = 0;
+ adapter->scan_channels = NULL;
+ adapter->fw_release_number = 0;
+ adapter->fw_cap_info = 0;
+ memset(&adapter->upld_buf, 0, sizeof(adapter->upld_buf));
+ adapter->event_cause = 0;
+ adapter->region_code = 0;
+ adapter->bcn_miss_time_out = DEFAULT_BCN_MISS_TIMEOUT;
+ adapter->adhoc_awake_period = 0;
+ memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter));
+ adapter->arp_filter_size = 0;
+}
+
+/*
+ * This function frees the adapter structure.
+ *
+ * The freeing operation is done recursively, by canceling all
+ * pending commands, freeing the member buffers previously
+ * allocated (command buffers, scan table buffer, sleep confirm
+ * command buffer), stopping the timers and calling the cleanup
+ * routines for every interface, before the actual adapter
+ * structure is freed.
+ */
+static void
+mwifiex_free_adapter(struct mwifiex_adapter *adapter)
+{
+ if (!adapter) {
+ pr_err("%s: adapter is NULL\n", __func__);
+ return;
+ }
+
+ mwifiex_cancel_all_pending_cmd(adapter);
+
+ /* Free lock variables */
+ mwifiex_free_lock_list(adapter);
+
+ /* Free command buffer */
+ dev_dbg(adapter->dev, "info: free cmd buffer\n");
+ mwifiex_free_cmd_buffer(adapter);
+
+ del_timer(&adapter->cmd_timer);
+
+ dev_dbg(adapter->dev, "info: free scan table\n");
+ kfree(adapter->scan_table);
+ adapter->scan_table = NULL;
+
+ adapter->if_ops.cleanup_if(adapter);
+
+ dev_kfree_skb_any(adapter->sleep_cfm);
+}
+
+/*
+ * This function intializes the lock variables and
+ * the list heads.
+ */
+int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
+{
+ struct mwifiex_private *priv;
+ s32 i, j;
+
+ spin_lock_init(&adapter->mwifiex_lock);
+ spin_lock_init(&adapter->int_lock);
+ spin_lock_init(&adapter->main_proc_lock);
+ spin_lock_init(&adapter->mwifiex_cmd_lock);
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (adapter->priv[i]) {
+ priv = adapter->priv[i];
+ spin_lock_init(&priv->rx_pkt_lock);
+ spin_lock_init(&priv->wmm.ra_list_spinlock);
+ spin_lock_init(&priv->curr_bcn_buf_lock);
+ }
+ }
+
+ /* Initialize cmd_free_q */
+ INIT_LIST_HEAD(&adapter->cmd_free_q);
+ /* Initialize cmd_pending_q */
+ INIT_LIST_HEAD(&adapter->cmd_pending_q);
+ /* Initialize scan_pending_q */
+ INIT_LIST_HEAD(&adapter->scan_pending_q);
+
+ spin_lock_init(&adapter->cmd_free_q_lock);
+ spin_lock_init(&adapter->cmd_pending_q_lock);
+ spin_lock_init(&adapter->scan_pending_q_lock);
+
+ for (i = 0; i < adapter->priv_num; ++i) {
+ INIT_LIST_HEAD(&adapter->bss_prio_tbl[i].bss_prio_head);
+ adapter->bss_prio_tbl[i].bss_prio_cur = NULL;
+ spin_lock_init(&adapter->bss_prio_tbl[i].bss_prio_lock);
+ }
+
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (!adapter->priv[i])
+ continue;
+ priv = adapter->priv[i];
+ for (j = 0; j < MAX_NUM_TID; ++j) {
+ INIT_LIST_HEAD(&priv->wmm.tid_tbl_ptr[j].ra_list);
+ spin_lock_init(&priv->wmm.tid_tbl_ptr[j].tid_tbl_lock);
+ }
+ INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr);
+ INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
+
+ spin_lock_init(&priv->tx_ba_stream_tbl_lock);
+ spin_lock_init(&priv->rx_reorder_tbl_lock);
+ }
+
+ return 0;
+}
+
+/*
+ * This function releases the lock variables and frees the locks and
+ * associated locks.
+ */
+void mwifiex_free_lock_list(struct mwifiex_adapter *adapter)
+{
+ struct mwifiex_private *priv;
+ s32 i, j;
+
+ /* Free lists */
+ list_del(&adapter->cmd_free_q);
+ list_del(&adapter->cmd_pending_q);
+ list_del(&adapter->scan_pending_q);
+
+ for (i = 0; i < adapter->priv_num; i++)
+ list_del(&adapter->bss_prio_tbl[i].bss_prio_head);
+
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (adapter->priv[i]) {
+ priv = adapter->priv[i];
+ for (j = 0; j < MAX_NUM_TID; ++j)
+ list_del(&priv->wmm.tid_tbl_ptr[j].ra_list);
+ list_del(&priv->tx_ba_stream_tbl_ptr);
+ list_del(&priv->rx_reorder_tbl_ptr);
+ }
+ }
+}
+
+/*
+ * This function initializes the firmware.
+ *
+ * The following operations are performed sequentially -
+ * - Allocate adapter structure
+ * - Initialize the adapter structure
+ * - Initialize the private structure
+ * - Add BSS priority tables to the adapter structure
+ * - For each interface, send the init commands to firmware
+ * - Send the first command in command pending queue, if available
+ */
+int mwifiex_init_fw(struct mwifiex_adapter *adapter)
+{
+ int ret;
+ struct mwifiex_private *priv;
+ u8 i, first_sta = true;
+ int is_cmd_pend_q_empty;
+ unsigned long flags;
+
+ adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING;
+
+ /* Allocate memory for member of adapter structure */
+ ret = mwifiex_allocate_adapter(adapter);
+ if (ret)
+ return -1;
+
+ /* Initialize adapter structure */
+ mwifiex_init_adapter(adapter);
+
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (adapter->priv[i]) {
+ priv = adapter->priv[i];
+
+ /* Initialize private structure */
+ ret = mwifiex_init_priv(priv);
+ if (ret)
+ return -1;
+ }
+ }
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (adapter->priv[i]) {
+ ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta);
+ if (ret == -1)
+ return -1;
+
+ first_sta = false;
+ }
+ }
+
+ spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
+ is_cmd_pend_q_empty = list_empty(&adapter->cmd_pending_q);
+ spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
+ if (!is_cmd_pend_q_empty) {
+ /* Send the first command in queue and return */
+ if (mwifiex_main_process(adapter) != -1)
+ ret = -EINPROGRESS;
+ } else {
+ adapter->hw_status = MWIFIEX_HW_STATUS_READY;
+ }
+
+ return ret;
+}
+
+/*
+ * This function deletes the BSS priority tables.
+ *
+ * The function traverses through all the allocated BSS priority nodes
+ * in every BSS priority table and frees them.
+ */
+static void mwifiex_delete_bss_prio_tbl(struct mwifiex_private *priv)
+{
+ int i;
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_bss_prio_node *bssprio_node, *tmp_node, **cur;
+ struct list_head *head;
+ spinlock_t *lock;
+ unsigned long flags;
+
+ for (i = 0; i < adapter->priv_num; ++i) {
+ head = &adapter->bss_prio_tbl[i].bss_prio_head;
+ cur = &adapter->bss_prio_tbl[i].bss_prio_cur;
+ lock = &adapter->bss_prio_tbl[i].bss_prio_lock;
+ dev_dbg(adapter->dev, "info: delete BSS priority table,"
+ " index = %d, i = %d, head = %p, cur = %p\n",
+ priv->bss_index, i, head, *cur);
+ if (*cur) {
+ spin_lock_irqsave(lock, flags);
+ if (list_empty(head)) {
+ spin_unlock_irqrestore(lock, flags);
+ continue;
+ }
+ bssprio_node = list_first_entry(head,
+ struct mwifiex_bss_prio_node, list);
+ spin_unlock_irqrestore(lock, flags);
+
+ list_for_each_entry_safe(bssprio_node, tmp_node, head,
+ list) {
+ if (bssprio_node->priv == priv) {
+ dev_dbg(adapter->dev, "info: Delete "
+ "node %p, next = %p\n",
+ bssprio_node, tmp_node);
+ spin_lock_irqsave(lock, flags);
+ list_del(&bssprio_node->list);
+ spin_unlock_irqrestore(lock, flags);
+ kfree(bssprio_node);
+ }
+ }
+ *cur = (struct mwifiex_bss_prio_node *)head;
+ }
+ }
+}
+
+/*
+ * This function is used to shutdown the driver.
+ *
+ * The following operations are performed sequentially -
+ * - Check if already shut down
+ * - Make sure the main process has stopped
+ * - Clean up the Tx and Rx queues
+ * - Delete BSS priority tables
+ * - Free the adapter
+ * - Notify completion
+ */
+int
+mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
+{
+ int ret = -EINPROGRESS;
+ struct mwifiex_private *priv;
+ s32 i;
+ unsigned long flags;
+
+ /* mwifiex already shutdown */
+ if (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY)
+ return 0;
+
+ adapter->hw_status = MWIFIEX_HW_STATUS_CLOSING;
+ /* wait for mwifiex_process to complete */
+ if (adapter->mwifiex_processing) {
+ dev_warn(adapter->dev, "main process is still running\n");
+ return ret;
+ }
+
+ /* shut down mwifiex */
+ dev_dbg(adapter->dev, "info: shutdown mwifiex...\n");
+
+ /* Clean up Tx/Rx queues and delete BSS priority table */
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (adapter->priv[i]) {
+ priv = adapter->priv[i];
+
+ mwifiex_clean_txrx(priv);
+ mwifiex_delete_bss_prio_tbl(priv);
+ }
+ }
+
+ spin_lock_irqsave(&adapter->mwifiex_lock, flags);
+
+ /* Free adapter structure */
+ mwifiex_free_adapter(adapter);
+
+ spin_unlock_irqrestore(&adapter->mwifiex_lock, flags);
+
+ /* Notify completion */
+ ret = mwifiex_shutdown_fw_complete(adapter);
+
+ return ret;
+}
+
+/*
+ * This function downloads the firmware to the card.
+ *
+ * The actual download is preceded by two sanity checks -
+ * - Check if firmware is already running
+ * - Check if the interface is the winner to download the firmware
+ *
+ * ...and followed by another -
+ * - Check if the firmware is downloaded successfully
+ *
+ * After download is successfully completed, the host interrupts are enabled.
+ */
+int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
+ struct mwifiex_fw_image *pmfw)
+{
+ int ret, winner;
+ u32 poll_num = 1;
+
+ /* Check if firmware is already running */
+ ret = adapter->if_ops.check_fw_status(adapter, poll_num, &winner);
+ if (!ret) {
+ dev_notice(adapter->dev,
+ "WLAN FW already running! Skip FW download\n");
+ goto done;
+ }
+ poll_num = MAX_FIRMWARE_POLL_TRIES;
+
+ /* Check if we are the winner for downloading FW */
+ if (!winner) {
+ dev_notice(adapter->dev,
+ "Other interface already running!"
+ " Skip FW download\n");
+ poll_num = MAX_MULTI_INTERFACE_POLL_TRIES;
+ goto poll_fw;
+ }
+ if (pmfw) {
+ /* Download firmware with helper */
+ ret = adapter->if_ops.prog_fw(adapter, pmfw);
+ if (ret) {
+ dev_err(adapter->dev, "prog_fw failed ret=%#x\n", ret);
+ return ret;
+ }
+ }
+
+poll_fw:
+ /* Check if the firmware is downloaded successfully or not */
+ ret = adapter->if_ops.check_fw_status(adapter, poll_num, NULL);
+ if (ret) {
+ dev_err(adapter->dev, "FW failed to be active in time\n");
+ return -1;
+ }
+done:
+ /* re-enable host interrupt for mwifiex after fw dnld is successful */
+ adapter->if_ops.enable_int(adapter);
+ return ret;
+}
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h
new file mode 100644
index 000000000000..7c1c5ee40eb9
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/ioctl.h
@@ -0,0 +1,331 @@
+/*
+ * Marvell Wireless LAN device driver: ioctl data structures & APIs
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef _MWIFIEX_IOCTL_H_
+#define _MWIFIEX_IOCTL_H_
+
+#include <net/mac80211.h>
+
+enum {
+ MWIFIEX_SCAN_TYPE_UNCHANGED = 0,
+ MWIFIEX_SCAN_TYPE_ACTIVE,
+ MWIFIEX_SCAN_TYPE_PASSIVE
+};
+
+struct mwifiex_user_scan {
+ u32 scan_cfg_len;
+ u8 scan_cfg_buf[1];
+};
+
+#define MWIFIEX_PROMISC_MODE 1
+#define MWIFIEX_MULTICAST_MODE 2
+#define MWIFIEX_ALL_MULTI_MODE 4
+#define MWIFIEX_MAX_MULTICAST_LIST_SIZE 32
+
+struct mwifiex_multicast_list {
+ u32 mode;
+ u32 num_multicast_addr;
+ u8 mac_list[MWIFIEX_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
+};
+
+struct mwifiex_chan_freq {
+ u32 channel;
+ u32 freq;
+};
+
+struct mwifiex_ssid_bssid {
+ struct mwifiex_802_11_ssid ssid;
+ u8 bssid[ETH_ALEN];
+};
+
+enum {
+ BAND_B = 1,
+ BAND_G = 2,
+ BAND_A = 4,
+ BAND_GN = 8,
+ BAND_AN = 16,
+};
+
+#define NO_SEC_CHANNEL 0
+#define SEC_CHANNEL_ABOVE 1
+#define SEC_CHANNEL_BELOW 3
+
+struct mwifiex_ds_band_cfg {
+ u32 config_bands;
+ u32 adhoc_start_band;
+ u32 adhoc_channel;
+ u32 sec_chan_offset;
+};
+
+enum {
+ ADHOC_IDLE,
+ ADHOC_STARTED,
+ ADHOC_JOINED,
+ ADHOC_COALESCED
+};
+
+struct mwifiex_ds_get_stats {
+ u32 mcast_tx_frame;
+ u32 failed;
+ u32 retry;
+ u32 multi_retry;
+ u32 frame_dup;
+ u32 rts_success;
+ u32 rts_failure;
+ u32 ack_failure;
+ u32 rx_frag;
+ u32 mcast_rx_frame;
+ u32 fcs_error;
+ u32 tx_frame;
+ u32 wep_icv_error[4];
+};
+
+#define BCN_RSSI_AVG_MASK 0x00000002
+#define BCN_NF_AVG_MASK 0x00000200
+#define ALL_RSSI_INFO_MASK 0x00000fff
+
+struct mwifiex_ds_get_signal {
+ /*
+ * Bit0: Last Beacon RSSI, Bit1: Average Beacon RSSI,
+ * Bit2: Last Data RSSI, Bit3: Average Data RSSI,
+ * Bit4: Last Beacon SNR, Bit5: Average Beacon SNR,
+ * Bit6: Last Data SNR, Bit7: Average Data SNR,
+ * Bit8: Last Beacon NF, Bit9: Average Beacon NF,
+ * Bit10: Last Data NF, Bit11: Average Data NF
+ */
+ u16 selector;
+ s16 bcn_rssi_last;
+ s16 bcn_rssi_avg;
+ s16 data_rssi_last;
+ s16 data_rssi_avg;
+ s16 bcn_snr_last;
+ s16 bcn_snr_avg;
+ s16 data_snr_last;
+ s16 data_snr_avg;
+ s16 bcn_nf_last;
+ s16 bcn_nf_avg;
+ s16 data_nf_last;
+ s16 data_nf_avg;
+};
+
+#define MWIFIEX_MAX_VER_STR_LEN 128
+
+struct mwifiex_ver_ext {
+ u32 version_str_sel;
+ char version_str[MWIFIEX_MAX_VER_STR_LEN];
+};
+
+struct mwifiex_bss_info {
+ u32 bss_mode;
+ struct mwifiex_802_11_ssid ssid;
+ u32 scan_table_idx;
+ u32 bss_chan;
+ u32 region_code;
+ u32 media_connected;
+ u32 max_power_level;
+ u32 min_power_level;
+ u32 adhoc_state;
+ signed int bcn_nf_last;
+ u32 wep_status;
+ u32 is_hs_configured;
+ u32 is_deep_sleep;
+ u8 bssid[ETH_ALEN];
+};
+
+#define MAX_NUM_TID 8
+
+#define MAX_RX_WINSIZE 64
+
+struct mwifiex_ds_rx_reorder_tbl {
+ u16 tid;
+ u8 ta[ETH_ALEN];
+ u32 start_win;
+ u32 win_size;
+ u32 buffer[MAX_RX_WINSIZE];
+};
+
+struct mwifiex_ds_tx_ba_stream_tbl {
+ u16 tid;
+ u8 ra[ETH_ALEN];
+};
+
+#define DBG_CMD_NUM 5
+
+struct mwifiex_debug_info {
+ u32 int_counter;
+ u32 packets_out[MAX_NUM_TID];
+ u32 max_tx_buf_size;
+ u32 tx_buf_size;
+ u32 curr_tx_buf_size;
+ u32 tx_tbl_num;
+ struct mwifiex_ds_tx_ba_stream_tbl
+ tx_tbl[MWIFIEX_MAX_TX_BASTREAM_SUPPORTED];
+ u32 rx_tbl_num;
+ struct mwifiex_ds_rx_reorder_tbl rx_tbl
+ [MWIFIEX_MAX_RX_BASTREAM_SUPPORTED];
+ u16 ps_mode;
+ u32 ps_state;
+ u8 is_deep_sleep;
+ u8 pm_wakeup_card_req;
+ u32 pm_wakeup_fw_try;
+ u8 is_hs_configured;
+ u8 hs_activated;
+ u32 num_cmd_host_to_card_failure;
+ u32 num_cmd_sleep_cfm_host_to_card_failure;
+ u32 num_tx_host_to_card_failure;
+ u32 num_event_deauth;
+ u32 num_event_disassoc;
+ u32 num_event_link_lost;
+ u32 num_cmd_deauth;
+ u32 num_cmd_assoc_success;
+ u32 num_cmd_assoc_failure;
+ u32 num_tx_timeout;
+ u32 num_cmd_timeout;
+ u16 timeout_cmd_id;
+ u16 timeout_cmd_act;
+ u16 last_cmd_id[DBG_CMD_NUM];
+ u16 last_cmd_act[DBG_CMD_NUM];
+ u16 last_cmd_index;
+ u16 last_cmd_resp_id[DBG_CMD_NUM];
+ u16 last_cmd_resp_index;
+ u16 last_event[DBG_CMD_NUM];
+ u16 last_event_index;
+ u8 data_sent;
+ u8 cmd_sent;
+ u8 cmd_resp_received;
+ u8 event_received;
+};
+
+#define MWIFIEX_KEY_INDEX_UNICAST 0x40000000
+#define WAPI_RXPN_LEN 16
+
+struct mwifiex_ds_encrypt_key {
+ u32 key_disable;
+ u32 key_index;
+ u32 key_len;
+ u8 key_material[WLAN_MAX_KEY_LEN];
+ u8 mac_addr[ETH_ALEN];
+ u32 is_wapi_key;
+ u8 wapi_rxpn[WAPI_RXPN_LEN];
+};
+
+struct mwifiex_rate_cfg {
+ u32 action;
+ u32 is_rate_auto;
+ u32 rate;
+};
+
+struct mwifiex_power_cfg {
+ u32 is_power_auto;
+ u32 power_level;
+};
+
+struct mwifiex_ds_hs_cfg {
+ u32 is_invoke_hostcmd;
+ /* Bit0: non-unicast data
+ * Bit1: unicast data
+ * Bit2: mac events
+ * Bit3: magic packet
+ */
+ u32 conditions;
+ u32 gpio;
+ u32 gap;
+};
+
+#define DEEP_SLEEP_ON 1
+#define DEEP_SLEEP_IDLE_TIME 100
+#define PS_MODE_AUTO 1
+
+struct mwifiex_ds_auto_ds {
+ u16 auto_ds;
+ u16 idle_time;
+};
+
+struct mwifiex_ds_pm_cfg {
+ union {
+ u32 ps_mode;
+ struct mwifiex_ds_hs_cfg hs_cfg;
+ struct mwifiex_ds_auto_ds auto_deep_sleep;
+ u32 sleep_period;
+ } param;
+};
+
+struct mwifiex_ds_11n_tx_cfg {
+ u16 tx_htcap;
+ u16 tx_htinfo;
+};
+
+struct mwifiex_ds_11n_amsdu_aggr_ctrl {
+ u16 enable;
+ u16 curr_buf_size;
+};
+
+#define MWIFIEX_NUM_OF_CMD_BUFFER 20
+#define MWIFIEX_SIZE_OF_CMD_BUFFER 2048
+
+enum {
+ MWIFIEX_IE_TYPE_GEN_IE = 0,
+ MWIFIEX_IE_TYPE_ARP_FILTER,
+};
+
+enum {
+ MWIFIEX_REG_MAC = 1,
+ MWIFIEX_REG_BBP,
+ MWIFIEX_REG_RF,
+ MWIFIEX_REG_PMIC,
+ MWIFIEX_REG_CAU,
+};
+
+struct mwifiex_ds_reg_rw {
+ __le32 type;
+ __le32 offset;
+ __le32 value;
+};
+
+#define MAX_EEPROM_DATA 256
+
+struct mwifiex_ds_read_eeprom {
+ __le16 offset;
+ __le16 byte_count;
+ u8 value[MAX_EEPROM_DATA];
+};
+
+struct mwifiex_ds_misc_gen_ie {
+ u32 type;
+ u32 len;
+ u8 ie_data[IW_CUSTOM_MAX];
+};
+
+struct mwifiex_ds_misc_cmd {
+ u32 len;
+ u8 cmd[MWIFIEX_SIZE_OF_CMD_BUFFER];
+};
+
+#define MWIFIEX_MAX_VSIE_LEN (256)
+#define MWIFIEX_MAX_VSIE_NUM (8)
+#define MWIFIEX_VSIE_MASK_SCAN 0x01
+#define MWIFIEX_VSIE_MASK_ASSOC 0x02
+#define MWIFIEX_VSIE_MASK_ADHOC 0x04
+
+enum {
+ MWIFIEX_FUNC_INIT = 1,
+ MWIFIEX_FUNC_SHUTDOWN,
+};
+
+#endif /* !_MWIFIEX_IOCTL_H_ */
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c
new file mode 100644
index 000000000000..5eab3dc29b1c
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -0,0 +1,1423 @@
+/*
+ * Marvell Wireless LAN device driver: association and ad-hoc start/join
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+
+#define CAPINFO_MASK (~(BIT(15) | BIT(14) | BIT(12) | BIT(11) | BIT(9)))
+
+/*
+ * Append a generic IE as a pass through TLV to a TLV buffer.
+ *
+ * This function is called from the network join command preparation routine.
+ *
+ * If the IE buffer has been setup by the application, this routine appends
+ * the buffer as a pass through TLV type to the request.
+ */
+static int
+mwifiex_cmd_append_generic_ie(struct mwifiex_private *priv, u8 **buffer)
+{
+ int ret_len = 0;
+ struct mwifiex_ie_types_header ie_header;
+
+ /* Null Checks */
+ if (!buffer)
+ return 0;
+ if (!(*buffer))
+ return 0;
+
+ /*
+ * If there is a generic ie buffer setup, append it to the return
+ * parameter buffer pointer.
+ */
+ if (priv->gen_ie_buf_len) {
+ dev_dbg(priv->adapter->dev, "info: %s: append generic %d to %p\n",
+ __func__, priv->gen_ie_buf_len, *buffer);
+
+ /* Wrap the generic IE buffer with a pass through TLV type */
+ ie_header.type = cpu_to_le16(TLV_TYPE_PASSTHROUGH);
+ ie_header.len = cpu_to_le16(priv->gen_ie_buf_len);
+ memcpy(*buffer, &ie_header, sizeof(ie_header));
+
+ /* Increment the return size and the return buffer pointer
+ param */
+ *buffer += sizeof(ie_header);
+ ret_len += sizeof(ie_header);
+
+ /* Copy the generic IE buffer to the output buffer, advance
+ pointer */
+ memcpy(*buffer, priv->gen_ie_buf, priv->gen_ie_buf_len);
+
+ /* Increment the return size and the return buffer pointer
+ param */
+ *buffer += priv->gen_ie_buf_len;
+ ret_len += priv->gen_ie_buf_len;
+
+ /* Reset the generic IE buffer */
+ priv->gen_ie_buf_len = 0;
+ }
+
+ /* return the length appended to the buffer */
+ return ret_len;
+}
+
+/*
+ * Append TSF tracking info from the scan table for the target AP.
+ *
+ * This function is called from the network join command preparation routine.
+ *
+ * The TSF table TSF sent to the firmware contains two TSF values:
+ * - The TSF of the target AP from its previous beacon/probe response
+ * - The TSF timestamp of our local MAC at the time we observed the
+ * beacon/probe response.
+ *
+ * The firmware uses the timestamp values to set an initial TSF value
+ * in the MAC for the new association after a reassociation attempt.
+ */
+static int
+mwifiex_cmd_append_tsf_tlv(struct mwifiex_private *priv, u8 **buffer,
+ struct mwifiex_bssdescriptor *bss_desc)
+{
+ struct mwifiex_ie_types_tsf_timestamp tsf_tlv;
+ __le64 tsf_val;
+
+ /* Null Checks */
+ if (buffer == NULL)
+ return 0;
+ if (*buffer == NULL)
+ return 0;
+
+ memset(&tsf_tlv, 0x00, sizeof(struct mwifiex_ie_types_tsf_timestamp));
+
+ tsf_tlv.header.type = cpu_to_le16(TLV_TYPE_TSFTIMESTAMP);
+ tsf_tlv.header.len = cpu_to_le16(2 * sizeof(tsf_val));
+
+ memcpy(*buffer, &tsf_tlv, sizeof(tsf_tlv.header));
+ *buffer += sizeof(tsf_tlv.header);
+
+ /* TSF at the time when beacon/probe_response was received */
+ tsf_val = cpu_to_le64(bss_desc->network_tsf);
+ memcpy(*buffer, &tsf_val, sizeof(tsf_val));
+ *buffer += sizeof(tsf_val);
+
+ memcpy(&tsf_val, bss_desc->time_stamp, sizeof(tsf_val));
+
+ dev_dbg(priv->adapter->dev, "info: %s: TSF offset calc: %016llx - "
+ "%016llx\n", __func__, tsf_val, bss_desc->network_tsf);
+
+ memcpy(*buffer, &tsf_val, sizeof(tsf_val));
+ *buffer += sizeof(tsf_val);
+
+ return sizeof(tsf_tlv.header) + (2 * sizeof(tsf_val));
+}
+
+/*
+ * This function finds out the common rates between rate1 and rate2.
+ *
+ * It will fill common rates in rate1 as output if found.
+ *
+ * NOTE: Setting the MSB of the basic rates needs to be taken
+ * care of, either before or after calling this function.
+ */
+static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1,
+ u32 rate1_size, u8 *rate2, u32 rate2_size)
+{
+ int ret;
+ u8 *ptr = rate1, *tmp;
+ u32 i, j;
+
+ tmp = kmalloc(rate1_size, GFP_KERNEL);
+ if (!tmp) {
+ dev_err(priv->adapter->dev, "failed to alloc tmp buf\n");
+ return -ENOMEM;
+ }
+
+ memcpy(tmp, rate1, rate1_size);
+ memset(rate1, 0, rate1_size);
+
+ for (i = 0; rate2[i] && i < rate2_size; i++) {
+ for (j = 0; tmp[j] && j < rate1_size; j++) {
+ /* Check common rate, excluding the bit for
+ basic rate */
+ if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) {
+ *rate1++ = tmp[j];
+ break;
+ }
+ }
+ }
+
+ dev_dbg(priv->adapter->dev, "info: Tx data rate set to %#x\n",
+ priv->data_rate);
+
+ if (!priv->is_data_rate_auto) {
+ while (*ptr) {
+ if ((*ptr & 0x7f) == priv->data_rate) {
+ ret = 0;
+ goto done;
+ }
+ ptr++;
+ }
+ dev_err(priv->adapter->dev, "previously set fixed data rate %#x"
+ " is not compatible with the network\n",
+ priv->data_rate);
+
+ ret = -1;
+ goto done;
+ }
+
+ ret = 0;
+done:
+ kfree(tmp);
+ return ret;
+}
+
+/*
+ * This function creates the intersection of the rates supported by a
+ * target BSS and our adapter settings for use in an assoc/join command.
+ */
+static int
+mwifiex_setup_rates_from_bssdesc(struct mwifiex_private *priv,
+ struct mwifiex_bssdescriptor *bss_desc,
+ u8 *out_rates, u32 *out_rates_size)
+{
+ u8 card_rates[MWIFIEX_SUPPORTED_RATES];
+ u32 card_rates_size;
+
+ /* Copy AP supported rates */
+ memcpy(out_rates, bss_desc->supported_rates, MWIFIEX_SUPPORTED_RATES);
+ /* Get the STA supported rates */
+ card_rates_size = mwifiex_get_active_data_rates(priv, card_rates);
+ /* Get the common rates between AP and STA supported rates */
+ if (mwifiex_get_common_rates(priv, out_rates, MWIFIEX_SUPPORTED_RATES,
+ card_rates, card_rates_size)) {
+ *out_rates_size = 0;
+ dev_err(priv->adapter->dev, "%s: cannot get common rates\n",
+ __func__);
+ return -1;
+ }
+
+ *out_rates_size =
+ min_t(size_t, strlen(out_rates), MWIFIEX_SUPPORTED_RATES);
+
+ return 0;
+}
+
+/*
+ * This function updates the scan entry TSF timestamps to reflect
+ * a new association.
+ */
+static void
+mwifiex_update_tsf_timestamps(struct mwifiex_private *priv,
+ struct mwifiex_bssdescriptor *new_bss_desc)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ u32 table_idx;
+ long long new_tsf_base;
+ signed long long tsf_delta;
+
+ memcpy(&new_tsf_base, new_bss_desc->time_stamp, sizeof(new_tsf_base));
+
+ tsf_delta = new_tsf_base - new_bss_desc->network_tsf;
+
+ dev_dbg(adapter->dev, "info: TSF: update TSF timestamps, "
+ "0x%016llx -> 0x%016llx\n",
+ new_bss_desc->network_tsf, new_tsf_base);
+
+ for (table_idx = 0; table_idx < adapter->num_in_scan_table;
+ table_idx++)
+ adapter->scan_table[table_idx].network_tsf += tsf_delta;
+}
+
+/*
+ * This function appends a WAPI IE.
+ *
+ * This function is called from the network join command preparation routine.
+ *
+ * If the IE buffer has been setup by the application, this routine appends
+ * the buffer as a WAPI TLV type to the request.
+ */
+static int
+mwifiex_cmd_append_wapi_ie(struct mwifiex_private *priv, u8 **buffer)
+{
+ int retLen = 0;
+ struct mwifiex_ie_types_header ie_header;
+
+ /* Null Checks */
+ if (buffer == NULL)
+ return 0;
+ if (*buffer == NULL)
+ return 0;
+
+ /*
+ * If there is a wapi ie buffer setup, append it to the return
+ * parameter buffer pointer.
+ */
+ if (priv->wapi_ie_len) {
+ dev_dbg(priv->adapter->dev, "cmd: append wapi ie %d to %p\n",
+ priv->wapi_ie_len, *buffer);
+
+ /* Wrap the generic IE buffer with a pass through TLV type */
+ ie_header.type = cpu_to_le16(TLV_TYPE_WAPI_IE);
+ ie_header.len = cpu_to_le16(priv->wapi_ie_len);
+ memcpy(*buffer, &ie_header, sizeof(ie_header));
+
+ /* Increment the return size and the return buffer pointer
+ param */
+ *buffer += sizeof(ie_header);
+ retLen += sizeof(ie_header);
+
+ /* Copy the wapi IE buffer to the output buffer, advance
+ pointer */
+ memcpy(*buffer, priv->wapi_ie, priv->wapi_ie_len);
+
+ /* Increment the return size and the return buffer pointer
+ param */
+ *buffer += priv->wapi_ie_len;
+ retLen += priv->wapi_ie_len;
+
+ }
+ /* return the length appended to the buffer */
+ return retLen;
+}
+
+/*
+ * This function appends rsn ie tlv for wpa/wpa2 security modes.
+ * It is called from the network join command preparation routine.
+ */
+static int mwifiex_append_rsn_ie_wpa_wpa2(struct mwifiex_private *priv,
+ u8 **buffer)
+{
+ struct mwifiex_ie_types_rsn_param_set *rsn_ie_tlv;
+ int rsn_ie_len;
+
+ if (!buffer || !(*buffer))
+ return 0;
+
+ rsn_ie_tlv = (struct mwifiex_ie_types_rsn_param_set *) (*buffer);
+ rsn_ie_tlv->header.type = cpu_to_le16((u16) priv->wpa_ie[0]);
+ rsn_ie_tlv->header.type = cpu_to_le16(
+ le16_to_cpu(rsn_ie_tlv->header.type) & 0x00FF);
+ rsn_ie_tlv->header.len = cpu_to_le16((u16) priv->wpa_ie[1]);
+ rsn_ie_tlv->header.len = cpu_to_le16(le16_to_cpu(rsn_ie_tlv->header.len)
+ & 0x00FF);
+ if (le16_to_cpu(rsn_ie_tlv->header.len) <= (sizeof(priv->wpa_ie) - 2))
+ memcpy(rsn_ie_tlv->rsn_ie, &priv->wpa_ie[2],
+ le16_to_cpu(rsn_ie_tlv->header.len));
+ else
+ return -1;
+
+ rsn_ie_len = sizeof(rsn_ie_tlv->header) +
+ le16_to_cpu(rsn_ie_tlv->header.len);
+ *buffer += rsn_ie_len;
+
+ return rsn_ie_len;
+}
+
+/*
+ * This function prepares command for association.
+ *
+ * This sets the following parameters -
+ * - Peer MAC address
+ * - Listen interval
+ * - Beacon interval
+ * - Capability information
+ *
+ * ...and the following TLVs, as required -
+ * - SSID TLV
+ * - PHY TLV
+ * - SS TLV
+ * - Rates TLV
+ * - Authentication TLV
+ * - Channel TLV
+ * - WPA/WPA2 IE
+ * - 11n TLV
+ * - Vendor specific TLV
+ * - WMM TLV
+ * - WAPI IE
+ * - Generic IE
+ * - TSF TLV
+ *
+ * Preparation also includes -
+ * - Setting command ID and proper size
+ * - Ensuring correct endian-ness
+ */
+int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ void *data_buf)
+{
+ struct host_cmd_ds_802_11_associate *assoc = &cmd->params.associate;
+ struct mwifiex_bssdescriptor *bss_desc;
+ struct mwifiex_ie_types_ssid_param_set *ssid_tlv;
+ struct mwifiex_ie_types_phy_param_set *phy_tlv;
+ struct mwifiex_ie_types_ss_param_set *ss_tlv;
+ struct mwifiex_ie_types_rates_param_set *rates_tlv;
+ struct mwifiex_ie_types_auth_type *auth_tlv;
+ struct mwifiex_ie_types_chan_list_param_set *chan_tlv;
+ u8 rates[MWIFIEX_SUPPORTED_RATES];
+ u32 rates_size;
+ u16 tmp_cap;
+ u8 *pos;
+ int rsn_ie_len = 0;
+
+ bss_desc = (struct mwifiex_bssdescriptor *) data_buf;
+ pos = (u8 *) assoc;
+
+ mwifiex_cfg_tx_buf(priv, bss_desc);
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE);
+
+ /* Save so we know which BSS Desc to use in the response handler */
+ priv->attempted_bss_desc = bss_desc;
+
+ memcpy(assoc->peer_sta_addr,
+ bss_desc->mac_address, sizeof(assoc->peer_sta_addr));
+ pos += sizeof(assoc->peer_sta_addr);
+
+ /* Set the listen interval */
+ assoc->listen_interval = cpu_to_le16(priv->listen_interval);
+ /* Set the beacon period */
+ assoc->beacon_period = cpu_to_le16(bss_desc->beacon_period);
+
+ pos += sizeof(assoc->cap_info_bitmap);
+ pos += sizeof(assoc->listen_interval);
+ pos += sizeof(assoc->beacon_period);
+ pos += sizeof(assoc->dtim_period);
+
+ ssid_tlv = (struct mwifiex_ie_types_ssid_param_set *) pos;
+ ssid_tlv->header.type = cpu_to_le16(WLAN_EID_SSID);
+ ssid_tlv->header.len = cpu_to_le16((u16) bss_desc->ssid.ssid_len);
+ memcpy(ssid_tlv->ssid, bss_desc->ssid.ssid,
+ le16_to_cpu(ssid_tlv->header.len));
+ pos += sizeof(ssid_tlv->header) + le16_to_cpu(ssid_tlv->header.len);
+
+ phy_tlv = (struct mwifiex_ie_types_phy_param_set *) pos;
+ phy_tlv->header.type = cpu_to_le16(WLAN_EID_DS_PARAMS);
+ phy_tlv->header.len = cpu_to_le16(sizeof(phy_tlv->fh_ds.ds_param_set));
+ memcpy(&phy_tlv->fh_ds.ds_param_set,
+ &bss_desc->phy_param_set.ds_param_set.current_chan,
+ sizeof(phy_tlv->fh_ds.ds_param_set));
+ pos += sizeof(phy_tlv->header) + le16_to_cpu(phy_tlv->header.len);
+
+ ss_tlv = (struct mwifiex_ie_types_ss_param_set *) pos;
+ ss_tlv->header.type = cpu_to_le16(WLAN_EID_CF_PARAMS);
+ ss_tlv->header.len = cpu_to_le16(sizeof(ss_tlv->cf_ibss.cf_param_set));
+ pos += sizeof(ss_tlv->header) + le16_to_cpu(ss_tlv->header.len);
+
+ /* Get the common rates supported between the driver and the BSS Desc */
+ if (mwifiex_setup_rates_from_bssdesc
+ (priv, bss_desc, rates, &rates_size))
+ return -1;
+
+ /* Save the data rates into Current BSS state structure */
+ priv->curr_bss_params.num_of_rates = rates_size;
+ memcpy(&priv->curr_bss_params.data_rates, rates, rates_size);
+
+ /* Setup the Rates TLV in the association command */
+ rates_tlv = (struct mwifiex_ie_types_rates_param_set *) pos;
+ rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES);
+ rates_tlv->header.len = cpu_to_le16((u16) rates_size);
+ memcpy(rates_tlv->rates, rates, rates_size);
+ pos += sizeof(rates_tlv->header) + rates_size;
+ dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: rates size = %d\n",
+ rates_size);
+
+ /* Add the Authentication type to be used for Auth frames */
+ auth_tlv = (struct mwifiex_ie_types_auth_type *) pos;
+ auth_tlv->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
+ auth_tlv->header.len = cpu_to_le16(sizeof(auth_tlv->auth_type));
+ if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED)
+ auth_tlv->auth_type = cpu_to_le16(
+ (u16) priv->sec_info.authentication_mode);
+ else
+ auth_tlv->auth_type = cpu_to_le16(NL80211_AUTHTYPE_OPEN_SYSTEM);
+
+ pos += sizeof(auth_tlv->header) + le16_to_cpu(auth_tlv->header.len);
+
+ if (IS_SUPPORT_MULTI_BANDS(priv->adapter)
+ && !(ISSUPP_11NENABLED(priv->adapter->fw_cap_info)
+ && (!bss_desc->disable_11n)
+ && (priv->adapter->config_bands & BAND_GN
+ || priv->adapter->config_bands & BAND_AN)
+ && (bss_desc->bcn_ht_cap)
+ )
+ ) {
+ /* Append a channel TLV for the channel the attempted AP was
+ found on */
+ chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos;
+ chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
+ chan_tlv->header.len =
+ cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set));
+
+ memset(chan_tlv->chan_scan_param, 0x00,
+ sizeof(struct mwifiex_chan_scan_param_set));
+ chan_tlv->chan_scan_param[0].chan_number =
+ (bss_desc->phy_param_set.ds_param_set.current_chan);
+ dev_dbg(priv->adapter->dev, "info: Assoc: TLV Chan = %d\n",
+ chan_tlv->chan_scan_param[0].chan_number);
+
+ chan_tlv->chan_scan_param[0].radio_type =
+ mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
+
+ dev_dbg(priv->adapter->dev, "info: Assoc: TLV Band = %d\n",
+ chan_tlv->chan_scan_param[0].radio_type);
+ pos += sizeof(chan_tlv->header) +
+ sizeof(struct mwifiex_chan_scan_param_set);
+ }
+
+ if (!priv->wps.session_enable) {
+ if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled)
+ rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos);
+
+ if (rsn_ie_len == -1)
+ return -1;
+ }
+
+ if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info)
+ && (!bss_desc->disable_11n)
+ && (priv->adapter->config_bands & BAND_GN
+ || priv->adapter->config_bands & BAND_AN))
+ mwifiex_cmd_append_11n_tlv(priv, bss_desc, &pos);
+
+ /* Append vendor specific IE TLV */
+ mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_ASSOC, &pos);
+
+ mwifiex_wmm_process_association_req(priv, &pos, &bss_desc->wmm_ie,
+ bss_desc->bcn_ht_cap);
+ if (priv->sec_info.wapi_enabled && priv->wapi_ie_len)
+ mwifiex_cmd_append_wapi_ie(priv, &pos);
+
+
+ mwifiex_cmd_append_generic_ie(priv, &pos);
+
+ mwifiex_cmd_append_tsf_tlv(priv, &pos, bss_desc);
+
+ cmd->size = cpu_to_le16((u16) (pos - (u8 *) assoc) + S_DS_GEN);
+
+ /* Set the Capability info at last */
+ tmp_cap = bss_desc->cap_info_bitmap;
+
+ if (priv->adapter->config_bands == BAND_B)
+ tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME;
+
+ tmp_cap &= CAPINFO_MASK;
+ dev_dbg(priv->adapter->dev, "info: ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n",
+ tmp_cap, CAPINFO_MASK);
+ assoc->cap_info_bitmap = cpu_to_le16(tmp_cap);
+
+ return 0;
+}
+
+/*
+ * Association firmware command response handler
+ *
+ * The response buffer for the association command has the following
+ * memory layout.
+ *
+ * For cases where an association response was not received (indicated
+ * by the CapInfo and AId field):
+ *
+ * .------------------------------------------------------------.
+ * | Header(4 * sizeof(t_u16)): Standard command response hdr |
+ * .------------------------------------------------------------.
+ * | cap_info/Error Return(t_u16): |
+ * | 0xFFFF(-1): Internal error |
+ * | 0xFFFE(-2): Authentication unhandled message |
+ * | 0xFFFD(-3): Authentication refused |
+ * | 0xFFFC(-4): Timeout waiting for AP response |
+ * .------------------------------------------------------------.
+ * | status_code(t_u16): |
+ * | If cap_info is -1: |
+ * | An internal firmware failure prevented the |
+ * | command from being processed. The status_code |
+ * | will be set to 1. |
+ * | |
+ * | If cap_info is -2: |
+ * | An authentication frame was received but was |
+ * | not handled by the firmware. IEEE Status |
+ * | code for the failure is returned. |
+ * | |
+ * | If cap_info is -3: |
+ * | An authentication frame was received and the |
+ * | status_code is the IEEE Status reported in the |
+ * | response. |
+ * | |
+ * | If cap_info is -4: |
+ * | (1) Association response timeout |
+ * | (2) Authentication response timeout |
+ * .------------------------------------------------------------.
+ * | a_id(t_u16): 0xFFFF |
+ * .------------------------------------------------------------.
+ *
+ *
+ * For cases where an association response was received, the IEEE
+ * standard association response frame is returned:
+ *
+ * .------------------------------------------------------------.
+ * | Header(4 * sizeof(t_u16)): Standard command response hdr |
+ * .------------------------------------------------------------.
+ * | cap_info(t_u16): IEEE Capability |
+ * .------------------------------------------------------------.
+ * | status_code(t_u16): IEEE Status Code |
+ * .------------------------------------------------------------.
+ * | a_id(t_u16): IEEE Association ID |
+ * .------------------------------------------------------------.
+ * | IEEE IEs(variable): Any received IEs comprising the |
+ * | remaining portion of a received |
+ * | association response frame. |
+ * .------------------------------------------------------------.
+ *
+ * For simplistic handling, the status_code field can be used to determine
+ * an association success (0) or failure (non-zero).
+ */
+int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ int ret = 0;
+ struct ieee_types_assoc_rsp *assoc_rsp;
+ struct mwifiex_bssdescriptor *bss_desc;
+ u8 enable_data = true;
+
+ assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params;
+
+ priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN,
+ sizeof(priv->assoc_rsp_buf));
+
+ memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size);
+
+ if (le16_to_cpu(assoc_rsp->status_code)) {
+ priv->adapter->dbg.num_cmd_assoc_failure++;
+ dev_err(priv->adapter->dev, "ASSOC_RESP: association failed, "
+ "status code = %d, error = 0x%x, a_id = 0x%x\n",
+ le16_to_cpu(assoc_rsp->status_code),
+ le16_to_cpu(assoc_rsp->cap_info_bitmap),
+ le16_to_cpu(assoc_rsp->a_id));
+
+ ret = -1;
+ goto done;
+ }
+
+ /* Send a Media Connected event, according to the Spec */
+ priv->media_connected = true;
+
+ priv->adapter->ps_state = PS_STATE_AWAKE;
+ priv->adapter->pps_uapsd_mode = false;
+ priv->adapter->tx_lock_flag = false;
+
+ /* Set the attempted BSSID Index to current */
+ bss_desc = priv->attempted_bss_desc;
+
+ dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: %s\n",
+ bss_desc->ssid.ssid);
+
+ /* Make a copy of current BSSID descriptor */
+ memcpy(&priv->curr_bss_params.bss_descriptor,
+ bss_desc, sizeof(struct mwifiex_bssdescriptor));
+
+ /* Update curr_bss_params */
+ priv->curr_bss_params.bss_descriptor.channel
+ = bss_desc->phy_param_set.ds_param_set.current_chan;
+
+ priv->curr_bss_params.band = (u8) bss_desc->bss_band;
+
+ /*
+ * Adjust the timestamps in the scan table to be relative to the newly
+ * associated AP's TSF
+ */
+ mwifiex_update_tsf_timestamps(priv, bss_desc);
+
+ if (bss_desc->wmm_ie.vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC)
+ priv->curr_bss_params.wmm_enabled = true;
+ else
+ priv->curr_bss_params.wmm_enabled = false;
+
+ if ((priv->wmm_required || bss_desc->bcn_ht_cap)
+ && priv->curr_bss_params.wmm_enabled)
+ priv->wmm_enabled = true;
+ else
+ priv->wmm_enabled = false;
+
+ priv->curr_bss_params.wmm_uapsd_enabled = false;
+
+ if (priv->wmm_enabled)
+ priv->curr_bss_params.wmm_uapsd_enabled
+ = ((bss_desc->wmm_ie.qos_info_bitmap &
+ IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) ? 1 : 0);
+
+ dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: curr_pkt_filter is %#x\n",
+ priv->curr_pkt_filter);
+ if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled)
+ priv->wpa_is_gtk_set = false;
+
+ if (priv->wmm_enabled) {
+ /* Don't re-enable carrier until we get the WMM_GET_STATUS
+ event */
+ enable_data = false;
+ } else {
+ /* Since WMM is not enabled, setup the queues with the
+ defaults */
+ mwifiex_wmm_setup_queue_priorities(priv, NULL);
+ mwifiex_wmm_setup_ac_downgrade(priv);
+ }
+
+ if (enable_data)
+ dev_dbg(priv->adapter->dev,
+ "info: post association, re-enabling data flow\n");
+
+ /* Reset SNR/NF/RSSI values */
+ priv->data_rssi_last = 0;
+ priv->data_nf_last = 0;
+ priv->data_rssi_avg = 0;
+ priv->data_nf_avg = 0;
+ priv->bcn_rssi_last = 0;
+ priv->bcn_nf_last = 0;
+ priv->bcn_rssi_avg = 0;
+ priv->bcn_nf_avg = 0;
+ priv->rxpd_rate = 0;
+ priv->rxpd_htinfo = 0;
+
+ mwifiex_save_curr_bcn(priv);
+
+ priv->adapter->dbg.num_cmd_assoc_success++;
+
+ dev_dbg(priv->adapter->dev, "info: ASSOC_RESP: associated\n");
+
+ /* Add the ra_list here for infra mode as there will be only 1 ra
+ always */
+ mwifiex_ralist_add(priv,
+ priv->curr_bss_params.bss_descriptor.mac_address);
+
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ if (netif_queue_stopped(priv->netdev))
+ netif_wake_queue(priv->netdev);
+
+ if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled)
+ priv->scan_block = true;
+
+done:
+ /* Need to indicate IOCTL complete */
+ if (adapter->curr_cmd->wait_q_enabled) {
+ if (ret)
+ adapter->cmd_wait_q.status = -1;
+ else
+ adapter->cmd_wait_q.status = 0;
+ }
+
+ return ret;
+}
+
+/*
+ * This function prepares command for ad-hoc start.
+ *
+ * Driver will fill up SSID, BSS mode, IBSS parameters, physical
+ * parameters, probe delay, and capability information. Firmware
+ * will fill up beacon period, basic rates and operational rates.
+ *
+ * In addition, the following TLVs are added -
+ * - Channel TLV
+ * - Vendor specific IE
+ * - WPA/WPA2 IE
+ * - HT Capabilities IE
+ * - HT Information IE
+ *
+ * Preparation also includes -
+ * - Setting command ID and proper size
+ * - Ensuring correct endian-ness
+ */
+int
+mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd, void *data_buf)
+{
+ int rsn_ie_len = 0;
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct host_cmd_ds_802_11_ad_hoc_start *adhoc_start =
+ &cmd->params.adhoc_start;
+ struct mwifiex_bssdescriptor *bss_desc;
+ u32 cmd_append_size = 0;
+ u32 i;
+ u16 tmp_cap;
+ uint16_t ht_cap_info;
+ struct mwifiex_ie_types_chan_list_param_set *chan_tlv;
+
+ struct mwifiex_ie_types_htcap *ht_cap;
+ struct mwifiex_ie_types_htinfo *ht_info;
+ u8 *pos = (u8 *) adhoc_start +
+ sizeof(struct host_cmd_ds_802_11_ad_hoc_start);
+
+ if (!adapter)
+ return -1;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_START);
+
+ bss_desc = &priv->curr_bss_params.bss_descriptor;
+ priv->attempted_bss_desc = bss_desc;
+
+ /*
+ * Fill in the parameters for 2 data structures:
+ * 1. struct host_cmd_ds_802_11_ad_hoc_start command
+ * 2. bss_desc
+ * Driver will fill up SSID, bss_mode,IBSS param, Physical Param,
+ * probe delay, and Cap info.
+ * Firmware will fill up beacon period, Basic rates
+ * and operational rates.
+ */
+
+ memset(adhoc_start->ssid, 0, IEEE80211_MAX_SSID_LEN);
+
+ memcpy(adhoc_start->ssid,
+ ((struct mwifiex_802_11_ssid *) data_buf)->ssid,
+ ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len);
+
+ dev_dbg(adapter->dev, "info: ADHOC_S_CMD: SSID = %s\n",
+ adhoc_start->ssid);
+
+ memset(bss_desc->ssid.ssid, 0, IEEE80211_MAX_SSID_LEN);
+ memcpy(bss_desc->ssid.ssid,
+ ((struct mwifiex_802_11_ssid *) data_buf)->ssid,
+ ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len);
+
+ bss_desc->ssid.ssid_len =
+ ((struct mwifiex_802_11_ssid *) data_buf)->ssid_len;
+
+ /* Set the BSS mode */
+ adhoc_start->bss_mode = HostCmd_BSS_MODE_IBSS;
+ bss_desc->bss_mode = NL80211_IFTYPE_ADHOC;
+ adhoc_start->beacon_period = cpu_to_le16(priv->beacon_period);
+ bss_desc->beacon_period = priv->beacon_period;
+
+ /* Set Physical param set */
+/* Parameter IE Id */
+#define DS_PARA_IE_ID 3
+/* Parameter IE length */
+#define DS_PARA_IE_LEN 1
+
+ adhoc_start->phy_param_set.ds_param_set.element_id = DS_PARA_IE_ID;
+ adhoc_start->phy_param_set.ds_param_set.len = DS_PARA_IE_LEN;
+
+ if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211
+ (priv, adapter->adhoc_start_band, (u16)
+ priv->adhoc_channel)) {
+ struct mwifiex_chan_freq_power *cfp;
+ cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv,
+ adapter->adhoc_start_band, FIRST_VALID_CHANNEL);
+ if (cfp)
+ priv->adhoc_channel = (u8) cfp->channel;
+ }
+
+ if (!priv->adhoc_channel) {
+ dev_err(adapter->dev, "ADHOC_S_CMD: adhoc_channel cannot be 0\n");
+ return -1;
+ }
+
+ dev_dbg(adapter->dev, "info: ADHOC_S_CMD: creating ADHOC on channel %d\n",
+ priv->adhoc_channel);
+
+ priv->curr_bss_params.bss_descriptor.channel = priv->adhoc_channel;
+ priv->curr_bss_params.band = adapter->adhoc_start_band;
+
+ bss_desc->channel = priv->adhoc_channel;
+ adhoc_start->phy_param_set.ds_param_set.current_chan =
+ priv->adhoc_channel;
+
+ memcpy(&bss_desc->phy_param_set, &adhoc_start->phy_param_set,
+ sizeof(union ieee_types_phy_param_set));
+
+ /* Set IBSS param set */
+/* IBSS parameter IE Id */
+#define IBSS_PARA_IE_ID 6
+/* IBSS parameter IE length */
+#define IBSS_PARA_IE_LEN 2
+
+ adhoc_start->ss_param_set.ibss_param_set.element_id = IBSS_PARA_IE_ID;
+ adhoc_start->ss_param_set.ibss_param_set.len = IBSS_PARA_IE_LEN;
+ adhoc_start->ss_param_set.ibss_param_set.atim_window
+ = cpu_to_le16(priv->atim_window);
+ memcpy(&bss_desc->ss_param_set, &adhoc_start->ss_param_set,
+ sizeof(union ieee_types_ss_param_set));
+
+ /* Set Capability info */
+ bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_IBSS;
+ tmp_cap = le16_to_cpu(adhoc_start->cap_info_bitmap);
+ tmp_cap &= ~WLAN_CAPABILITY_ESS;
+ tmp_cap |= WLAN_CAPABILITY_IBSS;
+
+ /* Set up privacy in bss_desc */
+ if (priv->sec_info.encryption_mode) {
+ /* Ad-Hoc capability privacy on */
+ dev_dbg(adapter->dev,
+ "info: ADHOC_S_CMD: wep_status set privacy to WEP\n");
+ bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
+ tmp_cap |= WLAN_CAPABILITY_PRIVACY;
+ } else {
+ dev_dbg(adapter->dev, "info: ADHOC_S_CMD: wep_status NOT set,"
+ " setting privacy to ACCEPT ALL\n");
+ bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL;
+ }
+
+ memset(adhoc_start->DataRate, 0, sizeof(adhoc_start->DataRate));
+ mwifiex_get_active_data_rates(priv, adhoc_start->DataRate);
+ if ((adapter->adhoc_start_band & BAND_G) &&
+ (priv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) {
+ if (mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET, 0,
+ &priv->curr_pkt_filter)) {
+ dev_err(adapter->dev,
+ "ADHOC_S_CMD: G Protection config failed\n");
+ return -1;
+ }
+ }
+ /* Find the last non zero */
+ for (i = 0; i < sizeof(adhoc_start->DataRate) &&
+ adhoc_start->DataRate[i];
+ i++)
+ ;
+
+ priv->curr_bss_params.num_of_rates = i;
+
+ /* Copy the ad-hoc creating rates into Current BSS rate structure */
+ memcpy(&priv->curr_bss_params.data_rates,
+ &adhoc_start->DataRate, priv->curr_bss_params.num_of_rates);
+
+ dev_dbg(adapter->dev, "info: ADHOC_S_CMD: rates=%02x %02x %02x %02x\n",
+ adhoc_start->DataRate[0], adhoc_start->DataRate[1],
+ adhoc_start->DataRate[2], adhoc_start->DataRate[3]);
+
+ dev_dbg(adapter->dev, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n");
+
+ if (IS_SUPPORT_MULTI_BANDS(adapter)) {
+ /* Append a channel TLV */
+ chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos;
+ chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
+ chan_tlv->header.len =
+ cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set));
+
+ memset(chan_tlv->chan_scan_param, 0x00,
+ sizeof(struct mwifiex_chan_scan_param_set));
+ chan_tlv->chan_scan_param[0].chan_number =
+ (u8) priv->curr_bss_params.bss_descriptor.channel;
+
+ dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Chan = %d\n",
+ chan_tlv->chan_scan_param[0].chan_number);
+
+ chan_tlv->chan_scan_param[0].radio_type
+ = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
+ if (adapter->adhoc_start_band & BAND_GN
+ || adapter->adhoc_start_band & BAND_AN) {
+ if (adapter->chan_offset == SEC_CHANNEL_ABOVE)
+ chan_tlv->chan_scan_param[0].radio_type |=
+ SECOND_CHANNEL_ABOVE;
+ else if (adapter->chan_offset == SEC_CHANNEL_BELOW)
+ chan_tlv->chan_scan_param[0].radio_type |=
+ SECOND_CHANNEL_BELOW;
+ }
+ dev_dbg(adapter->dev, "info: ADHOC_S_CMD: TLV Band = %d\n",
+ chan_tlv->chan_scan_param[0].radio_type);
+ pos += sizeof(chan_tlv->header) +
+ sizeof(struct mwifiex_chan_scan_param_set);
+ cmd_append_size +=
+ sizeof(chan_tlv->header) +
+ sizeof(struct mwifiex_chan_scan_param_set);
+ }
+
+ /* Append vendor specific IE TLV */
+ cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv,
+ MWIFIEX_VSIE_MASK_ADHOC, &pos);
+
+ if (priv->sec_info.wpa_enabled) {
+ rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos);
+ if (rsn_ie_len == -1)
+ return -1;
+ cmd_append_size += rsn_ie_len;
+ }
+
+ if (adapter->adhoc_11n_enabled) {
+ {
+ ht_cap = (struct mwifiex_ie_types_htcap *) pos;
+ memset(ht_cap, 0,
+ sizeof(struct mwifiex_ie_types_htcap));
+ ht_cap->header.type =
+ cpu_to_le16(WLAN_EID_HT_CAPABILITY);
+ ht_cap->header.len =
+ cpu_to_le16(sizeof(struct ieee80211_ht_cap));
+ ht_cap_info = le16_to_cpu(ht_cap->ht_cap.cap_info);
+
+ ht_cap_info |= IEEE80211_HT_CAP_SGI_20;
+ if (adapter->chan_offset) {
+ ht_cap_info |= IEEE80211_HT_CAP_SGI_40;
+ ht_cap_info |= IEEE80211_HT_CAP_DSSSCCK40;
+ ht_cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask);
+ }
+
+ ht_cap->ht_cap.ampdu_params_info
+ = IEEE80211_HT_MAX_AMPDU_64K;
+ ht_cap->ht_cap.mcs.rx_mask[0] = 0xff;
+ pos += sizeof(struct mwifiex_ie_types_htcap);
+ cmd_append_size +=
+ sizeof(struct mwifiex_ie_types_htcap);
+ }
+ {
+ ht_info = (struct mwifiex_ie_types_htinfo *) pos;
+ memset(ht_info, 0,
+ sizeof(struct mwifiex_ie_types_htinfo));
+ ht_info->header.type =
+ cpu_to_le16(WLAN_EID_HT_INFORMATION);
+ ht_info->header.len =
+ cpu_to_le16(sizeof(struct ieee80211_ht_info));
+ ht_info->ht_info.control_chan =
+ (u8) priv->curr_bss_params.bss_descriptor.
+ channel;
+ if (adapter->chan_offset) {
+ ht_info->ht_info.ht_param =
+ adapter->chan_offset;
+ ht_info->ht_info.ht_param |=
+ IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
+ }
+ ht_info->ht_info.operation_mode =
+ cpu_to_le16(IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
+ ht_info->ht_info.basic_set[0] = 0xff;
+ pos += sizeof(struct mwifiex_ie_types_htinfo);
+ cmd_append_size +=
+ sizeof(struct mwifiex_ie_types_htinfo);
+ }
+ }
+
+ cmd->size = cpu_to_le16((u16)
+ (sizeof(struct host_cmd_ds_802_11_ad_hoc_start)
+ + S_DS_GEN + cmd_append_size));
+
+ if (adapter->adhoc_start_band == BAND_B)
+ tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME;
+ else
+ tmp_cap |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
+
+ adhoc_start->cap_info_bitmap = cpu_to_le16(tmp_cap);
+
+ return 0;
+}
+
+/*
+ * This function prepares command for ad-hoc join.
+ *
+ * Most of the parameters are set up by copying from the target BSS descriptor
+ * from the scan response.
+ *
+ * In addition, the following TLVs are added -
+ * - Channel TLV
+ * - Vendor specific IE
+ * - WPA/WPA2 IE
+ * - 11n IE
+ *
+ * Preparation also includes -
+ * - Setting command ID and proper size
+ * - Ensuring correct endian-ness
+ */
+int
+mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd, void *data_buf)
+{
+ int rsn_ie_len = 0;
+ struct host_cmd_ds_802_11_ad_hoc_join *adhoc_join =
+ &cmd->params.adhoc_join;
+ struct mwifiex_bssdescriptor *bss_desc =
+ (struct mwifiex_bssdescriptor *) data_buf;
+ struct mwifiex_ie_types_chan_list_param_set *chan_tlv;
+ u32 cmd_append_size = 0;
+ u16 tmp_cap;
+ u32 i, rates_size = 0;
+ u16 curr_pkt_filter;
+ u8 *pos =
+ (u8 *) adhoc_join +
+ sizeof(struct host_cmd_ds_802_11_ad_hoc_join);
+
+/* Use G protection */
+#define USE_G_PROTECTION 0x02
+ if (bss_desc->erp_flags & USE_G_PROTECTION) {
+ curr_pkt_filter =
+ priv->
+ curr_pkt_filter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON;
+
+ if (mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET, 0,
+ &curr_pkt_filter)) {
+ dev_err(priv->adapter->dev,
+ "ADHOC_J_CMD: G Protection config failed\n");
+ return -1;
+ }
+ }
+
+ priv->attempted_bss_desc = bss_desc;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_JOIN);
+
+ adhoc_join->bss_descriptor.bss_mode = HostCmd_BSS_MODE_IBSS;
+
+ adhoc_join->bss_descriptor.beacon_period
+ = cpu_to_le16(bss_desc->beacon_period);
+
+ memcpy(&adhoc_join->bss_descriptor.bssid,
+ &bss_desc->mac_address, ETH_ALEN);
+
+ memcpy(&adhoc_join->bss_descriptor.ssid,
+ &bss_desc->ssid.ssid, bss_desc->ssid.ssid_len);
+
+ memcpy(&adhoc_join->bss_descriptor.phy_param_set,
+ &bss_desc->phy_param_set,
+ sizeof(union ieee_types_phy_param_set));
+
+ memcpy(&adhoc_join->bss_descriptor.ss_param_set,
+ &bss_desc->ss_param_set, sizeof(union ieee_types_ss_param_set));
+
+ tmp_cap = bss_desc->cap_info_bitmap;
+
+ tmp_cap &= CAPINFO_MASK;
+
+ dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: tmp_cap=%4X"
+ " CAPINFO_MASK=%4lX\n", tmp_cap, CAPINFO_MASK);
+
+ /* Information on BSSID descriptor passed to FW */
+ dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: BSSID = %pM, SSID = %s\n",
+ adhoc_join->bss_descriptor.bssid,
+ adhoc_join->bss_descriptor.ssid);
+
+ for (i = 0; bss_desc->supported_rates[i] &&
+ i < MWIFIEX_SUPPORTED_RATES;
+ i++)
+ ;
+ rates_size = i;
+
+ /* Copy Data Rates from the Rates recorded in scan response */
+ memset(adhoc_join->bss_descriptor.data_rates, 0,
+ sizeof(adhoc_join->bss_descriptor.data_rates));
+ memcpy(adhoc_join->bss_descriptor.data_rates,
+ bss_desc->supported_rates, rates_size);
+
+ /* Copy the adhoc join rates into Current BSS state structure */
+ priv->curr_bss_params.num_of_rates = rates_size;
+ memcpy(&priv->curr_bss_params.data_rates, bss_desc->supported_rates,
+ rates_size);
+
+ /* Copy the channel information */
+ priv->curr_bss_params.bss_descriptor.channel = bss_desc->channel;
+ priv->curr_bss_params.band = (u8) bss_desc->bss_band;
+
+ if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED
+ || priv->sec_info.wpa_enabled)
+ tmp_cap |= WLAN_CAPABILITY_PRIVACY;
+
+ if (IS_SUPPORT_MULTI_BANDS(priv->adapter)) {
+ /* Append a channel TLV */
+ chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos;
+ chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
+ chan_tlv->header.len =
+ cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set));
+
+ memset(chan_tlv->chan_scan_param, 0x00,
+ sizeof(struct mwifiex_chan_scan_param_set));
+ chan_tlv->chan_scan_param[0].chan_number =
+ (bss_desc->phy_param_set.ds_param_set.current_chan);
+ dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: TLV Chan = %d\n",
+ chan_tlv->chan_scan_param[0].chan_number);
+
+ chan_tlv->chan_scan_param[0].radio_type =
+ mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
+
+ dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: TLV Band = %d\n",
+ chan_tlv->chan_scan_param[0].radio_type);
+ pos += sizeof(chan_tlv->header) +
+ sizeof(struct mwifiex_chan_scan_param_set);
+ cmd_append_size += sizeof(chan_tlv->header) +
+ sizeof(struct mwifiex_chan_scan_param_set);
+ }
+
+ if (priv->sec_info.wpa_enabled)
+ rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos);
+ if (rsn_ie_len == -1)
+ return -1;
+ cmd_append_size += rsn_ie_len;
+
+ if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info))
+ cmd_append_size += mwifiex_cmd_append_11n_tlv(priv,
+ bss_desc, &pos);
+
+ /* Append vendor specific IE TLV */
+ cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv,
+ MWIFIEX_VSIE_MASK_ADHOC, &pos);
+
+ cmd->size = cpu_to_le16((u16)
+ (sizeof(struct host_cmd_ds_802_11_ad_hoc_join)
+ + S_DS_GEN + cmd_append_size));
+
+ adhoc_join->bss_descriptor.cap_info_bitmap = cpu_to_le16(tmp_cap);
+
+ return 0;
+}
+
+/*
+ * This function handles the command response of ad-hoc start and
+ * ad-hoc join.
+ *
+ * The function generates a device-connected event to notify
+ * the applications, in case of successful ad-hoc start/join, and
+ * saves the beacon buffer.
+ */
+int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
+{
+ int ret = 0;
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct host_cmd_ds_802_11_ad_hoc_result *adhoc_result;
+ struct mwifiex_bssdescriptor *bss_desc;
+
+ adhoc_result = &resp->params.adhoc_result;
+
+ bss_desc = priv->attempted_bss_desc;
+
+ /* Join result code 0 --> SUCCESS */
+ if (le16_to_cpu(resp->result)) {
+ dev_err(priv->adapter->dev, "ADHOC_RESP: failed\n");
+ if (priv->media_connected)
+ mwifiex_reset_connect_state(priv);
+
+ memset(&priv->curr_bss_params.bss_descriptor,
+ 0x00, sizeof(struct mwifiex_bssdescriptor));
+
+ ret = -1;
+ goto done;
+ }
+
+ /* Send a Media Connected event, according to the Spec */
+ priv->media_connected = true;
+
+ if (le16_to_cpu(resp->command) == HostCmd_CMD_802_11_AD_HOC_START) {
+ dev_dbg(priv->adapter->dev, "info: ADHOC_S_RESP %s\n",
+ bss_desc->ssid.ssid);
+
+ /* Update the created network descriptor with the new BSSID */
+ memcpy(bss_desc->mac_address,
+ adhoc_result->bssid, ETH_ALEN);
+
+ priv->adhoc_state = ADHOC_STARTED;
+ } else {
+ /*
+ * Now the join cmd should be successful.
+ * If BSSID has changed use SSID to compare instead of BSSID
+ */
+ dev_dbg(priv->adapter->dev, "info: ADHOC_J_RESP %s\n",
+ bss_desc->ssid.ssid);
+
+ /*
+ * Make a copy of current BSSID descriptor, only needed for
+ * join since the current descriptor is already being used
+ * for adhoc start
+ */
+ memcpy(&priv->curr_bss_params.bss_descriptor,
+ bss_desc, sizeof(struct mwifiex_bssdescriptor));
+
+ priv->adhoc_state = ADHOC_JOINED;
+ }
+
+ dev_dbg(priv->adapter->dev, "info: ADHOC_RESP: channel = %d\n",
+ priv->adhoc_channel);
+ dev_dbg(priv->adapter->dev, "info: ADHOC_RESP: BSSID = %pM\n",
+ priv->curr_bss_params.bss_descriptor.mac_address);
+
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ if (netif_queue_stopped(priv->netdev))
+ netif_wake_queue(priv->netdev);
+
+ mwifiex_save_curr_bcn(priv);
+
+done:
+ /* Need to indicate IOCTL complete */
+ if (adapter->curr_cmd->wait_q_enabled) {
+ if (ret)
+ adapter->cmd_wait_q.status = -1;
+ else
+ adapter->cmd_wait_q.status = 0;
+
+ }
+
+ return ret;
+}
+
+/*
+ * This function associates to a specific BSS discovered in a scan.
+ *
+ * It clears any past association response stored for application
+ * retrieval and calls the command preparation routine to send the
+ * command to firmware.
+ */
+int mwifiex_associate(struct mwifiex_private *priv,
+ struct mwifiex_bssdescriptor *bss_desc)
+{
+ u8 current_bssid[ETH_ALEN];
+
+ /* Return error if the adapter or table entry is not marked as infra */
+ if ((priv->bss_mode != NL80211_IFTYPE_STATION) ||
+ (bss_desc->bss_mode != NL80211_IFTYPE_STATION))
+ return -1;
+
+ memcpy(&current_bssid,
+ &priv->curr_bss_params.bss_descriptor.mac_address,
+ sizeof(current_bssid));
+
+ /* Clear any past association response stored for application
+ retrieval */
+ priv->assoc_rsp_size = 0;
+
+ return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_ASSOCIATE,
+ HostCmd_ACT_GEN_SET, 0, bss_desc);
+}
+
+/*
+ * This function starts an ad-hoc network.
+ *
+ * It calls the command preparation routine to send the command to firmware.
+ */
+int
+mwifiex_adhoc_start(struct mwifiex_private *priv,
+ struct mwifiex_802_11_ssid *adhoc_ssid)
+{
+ dev_dbg(priv->adapter->dev, "info: Adhoc Channel = %d\n",
+ priv->adhoc_channel);
+ dev_dbg(priv->adapter->dev, "info: curr_bss_params.channel = %d\n",
+ priv->curr_bss_params.bss_descriptor.channel);
+ dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %d\n",
+ priv->curr_bss_params.band);
+
+ return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_AD_HOC_START,
+ HostCmd_ACT_GEN_SET, 0, adhoc_ssid);
+}
+
+/*
+ * This function joins an ad-hoc network found in a previous scan.
+ *
+ * It calls the command preparation routine to send the command to firmware,
+ * if already not connected to the requested SSID.
+ */
+int mwifiex_adhoc_join(struct mwifiex_private *priv,
+ struct mwifiex_bssdescriptor *bss_desc)
+{
+ dev_dbg(priv->adapter->dev, "info: adhoc join: curr_bss ssid =%s\n",
+ priv->curr_bss_params.bss_descriptor.ssid.ssid);
+ dev_dbg(priv->adapter->dev, "info: adhoc join: curr_bss ssid_len =%u\n",
+ priv->curr_bss_params.bss_descriptor.ssid.ssid_len);
+ dev_dbg(priv->adapter->dev, "info: adhoc join: ssid =%s\n",
+ bss_desc->ssid.ssid);
+ dev_dbg(priv->adapter->dev, "info: adhoc join: ssid_len =%u\n",
+ bss_desc->ssid.ssid_len);
+
+ /* Check if the requested SSID is already joined */
+ if (priv->curr_bss_params.bss_descriptor.ssid.ssid_len &&
+ !mwifiex_ssid_cmp(&bss_desc->ssid,
+ &priv->curr_bss_params.bss_descriptor.ssid) &&
+ (priv->curr_bss_params.bss_descriptor.bss_mode ==
+ NL80211_IFTYPE_ADHOC)) {
+ dev_dbg(priv->adapter->dev, "info: ADHOC_J_CMD: new ad-hoc SSID"
+ " is the same as current; not attempting to re-join\n");
+ return -1;
+ }
+
+ dev_dbg(priv->adapter->dev, "info: curr_bss_params.channel = %d\n",
+ priv->curr_bss_params.bss_descriptor.channel);
+ dev_dbg(priv->adapter->dev, "info: curr_bss_params.band = %c\n",
+ priv->curr_bss_params.band);
+
+ return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_AD_HOC_JOIN,
+ HostCmd_ACT_GEN_SET, 0, bss_desc);
+}
+
+/*
+ * This function deauthenticates/disconnects from infra network by sending
+ * deauthentication request.
+ */
+static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, u8 *mac)
+{
+ u8 mac_address[ETH_ALEN];
+ int ret;
+ u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+
+ if (mac) {
+ if (!memcmp(mac, zero_mac, sizeof(zero_mac)))
+ memcpy((u8 *) &mac_address,
+ (u8 *) &priv->curr_bss_params.bss_descriptor.
+ mac_address, ETH_ALEN);
+ else
+ memcpy((u8 *) &mac_address, (u8 *) mac, ETH_ALEN);
+ } else {
+ memcpy((u8 *) &mac_address, (u8 *) &priv->curr_bss_params.
+ bss_descriptor.mac_address, ETH_ALEN);
+ }
+
+ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_DEAUTHENTICATE,
+ HostCmd_ACT_GEN_SET, 0, &mac_address);
+
+ return ret;
+}
+
+/*
+ * This function deauthenticates/disconnects from a BSS.
+ *
+ * In case of infra made, it sends deauthentication request, and
+ * in case of ad-hoc mode, a stop network request is sent to the firmware.
+ */
+int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac)
+{
+ int ret = 0;
+
+ if (priv->media_connected) {
+ if (priv->bss_mode == NL80211_IFTYPE_STATION) {
+ ret = mwifiex_deauthenticate_infra(priv, mac);
+ } else if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
+ ret = mwifiex_send_cmd_sync(priv,
+ HostCmd_CMD_802_11_AD_HOC_STOP,
+ HostCmd_ACT_GEN_SET, 0, NULL);
+ }
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mwifiex_deauthenticate);
+
+/*
+ * This function converts band to radio type used in channel TLV.
+ */
+u8
+mwifiex_band_to_radio_type(u8 band)
+{
+ switch (band) {
+ case BAND_A:
+ case BAND_AN:
+ case BAND_A | BAND_AN:
+ return HostCmd_SCAN_RADIO_TYPE_A;
+ case BAND_B:
+ case BAND_G:
+ case BAND_B | BAND_G:
+ default:
+ return HostCmd_SCAN_RADIO_TYPE_BG;
+ }
+}
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
new file mode 100644
index 000000000000..f0582259c935
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -0,0 +1,1055 @@
+/*
+ * Marvell Wireless LAN device driver: major functions
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "main.h"
+#include "wmm.h"
+#include "cfg80211.h"
+#include "11n.h"
+
+#define VERSION "1.0"
+
+const char driver_version[] = "mwifiex " VERSION " (%s) ";
+
+struct mwifiex_adapter *g_adapter;
+EXPORT_SYMBOL_GPL(g_adapter);
+
+static struct mwifiex_bss_attr mwifiex_bss_sta[] = {
+ {MWIFIEX_BSS_TYPE_STA, MWIFIEX_DATA_FRAME_TYPE_ETH_II, true, 0, 0},
+};
+
+static int drv_mode = DRV_MODE_STA;
+
+static char fw_name[32] = DEFAULT_FW_NAME;
+
+/* Supported drv_mode table */
+static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = {
+ {
+ .drv_mode = DRV_MODE_STA,
+ .intf_num = ARRAY_SIZE(mwifiex_bss_sta),
+ .bss_attr = mwifiex_bss_sta,
+ },
+};
+
+/*
+ * This function registers the device and performs all the necessary
+ * initializations.
+ *
+ * The following initialization operations are performed -
+ * - Allocate adapter structure
+ * - Save interface specific operations table in adapter
+ * - Call interface specific initialization routine
+ * - Allocate private structures
+ * - Set default adapter structure parameters
+ * - Initialize locks
+ *
+ * In case of any errors during inittialization, this function also ensures
+ * proper cleanup before exiting.
+ */
+static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
+ struct mwifiex_drv_mode *drv_mode_ptr)
+{
+ struct mwifiex_adapter *adapter;
+ int i;
+
+ adapter = kzalloc(sizeof(struct mwifiex_adapter), GFP_KERNEL);
+ if (!adapter)
+ return -ENOMEM;
+
+ g_adapter = adapter;
+ adapter->card = card;
+
+ /* Save interface specific operations in adapter */
+ memmove(&adapter->if_ops, if_ops, sizeof(struct mwifiex_if_ops));
+
+ /* card specific initialization has been deferred until now .. */
+ if (adapter->if_ops.init_if(adapter))
+ goto error;
+
+ adapter->priv_num = 0;
+ for (i = 0; i < drv_mode_ptr->intf_num; i++) {
+ adapter->priv[i] = NULL;
+
+ if (!drv_mode_ptr->bss_attr[i].active)
+ continue;
+
+ /* Allocate memory for private structure */
+ adapter->priv[i] = kzalloc(sizeof(struct mwifiex_private),
+ GFP_KERNEL);
+ if (!adapter->priv[i]) {
+ dev_err(adapter->dev, "%s: failed to alloc priv[%d]\n",
+ __func__, i);
+ goto error;
+ }
+
+ adapter->priv_num++;
+ adapter->priv[i]->adapter = adapter;
+ /* Save bss_type, frame_type & bss_priority */
+ adapter->priv[i]->bss_type = drv_mode_ptr->bss_attr[i].bss_type;
+ adapter->priv[i]->frame_type =
+ drv_mode_ptr->bss_attr[i].frame_type;
+ adapter->priv[i]->bss_priority =
+ drv_mode_ptr->bss_attr[i].bss_priority;
+
+ if (drv_mode_ptr->bss_attr[i].bss_type == MWIFIEX_BSS_TYPE_STA)
+ adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_STA;
+ else if (drv_mode_ptr->bss_attr[i].bss_type ==
+ MWIFIEX_BSS_TYPE_UAP)
+ adapter->priv[i]->bss_role = MWIFIEX_BSS_ROLE_UAP;
+
+ /* Save bss_index & bss_num */
+ adapter->priv[i]->bss_index = i;
+ adapter->priv[i]->bss_num = drv_mode_ptr->bss_attr[i].bss_num;
+ }
+ adapter->drv_mode = drv_mode_ptr;
+
+ if (mwifiex_init_lock_list(adapter))
+ goto error;
+
+ init_timer(&adapter->cmd_timer);
+ adapter->cmd_timer.function = mwifiex_cmd_timeout_func;
+ adapter->cmd_timer.data = (unsigned long) adapter;
+
+ return 0;
+
+error:
+ dev_dbg(adapter->dev, "info: leave mwifiex_register with error\n");
+
+ mwifiex_free_lock_list(adapter);
+ for (i = 0; i < drv_mode_ptr->intf_num; i++)
+ kfree(adapter->priv[i]);
+ kfree(adapter);
+
+ return -1;
+}
+
+/*
+ * This function unregisters the device and performs all the necessary
+ * cleanups.
+ *
+ * The following cleanup operations are performed -
+ * - Free the timers
+ * - Free beacon buffers
+ * - Free private structures
+ * - Free adapter structure
+ */
+static int mwifiex_unregister(struct mwifiex_adapter *adapter)
+{
+ s32 i;
+
+ del_timer(&adapter->cmd_timer);
+
+ /* Free private structures */
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (adapter->priv[i]) {
+ mwifiex_free_curr_bcn(adapter->priv[i]);
+ kfree(adapter->priv[i]);
+ }
+ }
+
+ kfree(adapter);
+ return 0;
+}
+
+/*
+ * The main process.
+ *
+ * This function is the main procedure of the driver and handles various driver
+ * operations. It runs in a loop and provides the core functionalities.
+ *
+ * The main responsibilities of this function are -
+ * - Ensure concurrency control
+ * - Handle pending interrupts and call interrupt handlers
+ * - Wake up the card if required
+ * - Handle command responses and call response handlers
+ * - Handle events and call event handlers
+ * - Execute pending commands
+ * - Transmit pending data packets
+ */
+int mwifiex_main_process(struct mwifiex_adapter *adapter)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->main_proc_lock, flags);
+
+ /* Check if already processing */
+ if (adapter->mwifiex_processing) {
+ spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
+ goto exit_main_proc;
+ } else {
+ adapter->mwifiex_processing = true;
+ spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
+ }
+process_start:
+ do {
+ if ((adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING) ||
+ (adapter->hw_status == MWIFIEX_HW_STATUS_NOT_READY))
+ break;
+
+ /* Handle pending interrupt if any */
+ if (adapter->int_status) {
+ if (adapter->hs_activated)
+ mwifiex_process_hs_config(adapter);
+ adapter->if_ops.process_int_status(adapter);
+ }
+
+ /* Need to wake up the card ? */
+ if ((adapter->ps_state == PS_STATE_SLEEP) &&
+ (adapter->pm_wakeup_card_req &&
+ !adapter->pm_wakeup_fw_try) &&
+ (is_command_pending(adapter)
+ || !mwifiex_wmm_lists_empty(adapter))) {
+ adapter->pm_wakeup_fw_try = true;
+ adapter->if_ops.wakeup(adapter);
+ continue;
+ }
+ if (IS_CARD_RX_RCVD(adapter)) {
+ adapter->pm_wakeup_fw_try = false;
+ if (adapter->ps_state == PS_STATE_SLEEP)
+ adapter->ps_state = PS_STATE_AWAKE;
+ } else {
+ /* We have tried to wakeup the card already */
+ if (adapter->pm_wakeup_fw_try)
+ break;
+ if (adapter->ps_state != PS_STATE_AWAKE ||
+ adapter->tx_lock_flag)
+ break;
+
+ if (adapter->scan_processing || adapter->data_sent
+ || mwifiex_wmm_lists_empty(adapter)) {
+ if (adapter->cmd_sent || adapter->curr_cmd
+ || (!is_command_pending(adapter)))
+ break;
+ }
+ }
+
+ /* Check for Cmd Resp */
+ if (adapter->cmd_resp_received) {
+ adapter->cmd_resp_received = false;
+ mwifiex_process_cmdresp(adapter);
+
+ /* call mwifiex back when init_fw is done */
+ if (adapter->hw_status == MWIFIEX_HW_STATUS_INIT_DONE) {
+ adapter->hw_status = MWIFIEX_HW_STATUS_READY;
+ mwifiex_init_fw_complete(adapter);
+ }
+ }
+
+ /* Check for event */
+ if (adapter->event_received) {
+ adapter->event_received = false;
+ mwifiex_process_event(adapter);
+ }
+
+ /* Check if we need to confirm Sleep Request
+ received previously */
+ if (adapter->ps_state == PS_STATE_PRE_SLEEP) {
+ if (!adapter->cmd_sent && !adapter->curr_cmd)
+ mwifiex_check_ps_cond(adapter);
+ }
+
+ /* * The ps_state may have been changed during processing of
+ * Sleep Request event.
+ */
+ if ((adapter->ps_state == PS_STATE_SLEEP)
+ || (adapter->ps_state == PS_STATE_PRE_SLEEP)
+ || (adapter->ps_state == PS_STATE_SLEEP_CFM)
+ || adapter->tx_lock_flag)
+ continue;
+
+ if (!adapter->cmd_sent && !adapter->curr_cmd) {
+ if (mwifiex_exec_next_cmd(adapter) == -1) {
+ ret = -1;
+ break;
+ }
+ }
+
+ if (!adapter->scan_processing && !adapter->data_sent &&
+ !mwifiex_wmm_lists_empty(adapter)) {
+ mwifiex_wmm_process_tx(adapter);
+ if (adapter->hs_activated) {
+ adapter->is_hs_configured = false;
+ mwifiex_hs_activated_event
+ (mwifiex_get_priv
+ (adapter, MWIFIEX_BSS_ROLE_ANY),
+ false);
+ }
+ }
+
+ if (adapter->delay_null_pkt && !adapter->cmd_sent &&
+ !adapter->curr_cmd && !is_command_pending(adapter)
+ && mwifiex_wmm_lists_empty(adapter)) {
+ if (!mwifiex_send_null_packet
+ (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
+ MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET |
+ MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET)) {
+ adapter->delay_null_pkt = false;
+ adapter->ps_state = PS_STATE_SLEEP;
+ }
+ break;
+ }
+ } while (true);
+
+ if ((adapter->int_status) || IS_CARD_RX_RCVD(adapter))
+ goto process_start;
+
+ spin_lock_irqsave(&adapter->main_proc_lock, flags);
+ adapter->mwifiex_processing = false;
+ spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
+
+exit_main_proc:
+ if (adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING)
+ mwifiex_shutdown_drv(adapter);
+ return ret;
+}
+
+/*
+ * This function initializes the software.
+ *
+ * The main work includes allocating and initializing the adapter structure
+ * and initializing the private structures.
+ */
+static int
+mwifiex_init_sw(void *card, struct mwifiex_if_ops *if_ops)
+{
+ int i;
+ struct mwifiex_drv_mode *drv_mode_ptr;
+
+ /* find mwifiex_drv_mode entry from mwifiex_drv_mode_tbl */
+ drv_mode_ptr = NULL;
+ for (i = 0; i < ARRAY_SIZE(mwifiex_drv_mode_tbl); i++) {
+ if (mwifiex_drv_mode_tbl[i].drv_mode == drv_mode) {
+ drv_mode_ptr = &mwifiex_drv_mode_tbl[i];
+ break;
+ }
+ }
+
+ if (!drv_mode_ptr) {
+ pr_err("invalid drv_mode=%d\n", drv_mode);
+ return -1;
+ }
+
+ if (mwifiex_register(card, if_ops, drv_mode_ptr))
+ return -1;
+
+ return 0;
+}
+
+/*
+ * This function frees the adapter structure.
+ *
+ * Additionally, this closes the netlink socket, frees the timers
+ * and private structures.
+ */
+static void mwifiex_free_adapter(struct mwifiex_adapter *adapter)
+{
+ if (!adapter) {
+ pr_err("%s: adapter is NULL\n", __func__);
+ return;
+ }
+
+ mwifiex_unregister(adapter);
+ pr_debug("info: %s: free adapter\n", __func__);
+}
+
+/*
+ * This function initializes the hardware and firmware.
+ *
+ * The main initialization steps followed are -
+ * - Download the correct firmware to card
+ * - Allocate and initialize the adapter structure
+ * - Initialize the private structures
+ * - Issue the init commands to firmware
+ */
+static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)
+{
+ int ret, err;
+ struct mwifiex_fw_image fw;
+
+ memset(&fw, 0, sizeof(struct mwifiex_fw_image));
+
+ switch (adapter->revision_id) {
+ case SD8787_W0:
+ case SD8787_W1:
+ strcpy(fw_name, SD8787_W1_FW_NAME);
+ break;
+ case SD8787_A0:
+ case SD8787_A1:
+ strcpy(fw_name, SD8787_AX_FW_NAME);
+ break;
+ default:
+ break;
+ }
+
+ err = request_firmware(&adapter->firmware, fw_name, adapter->dev);
+ if (err < 0) {
+ dev_err(adapter->dev, "request_firmware() returned"
+ " error code %#x\n", err);
+ ret = -1;
+ goto done;
+ }
+ fw.fw_buf = (u8 *) adapter->firmware->data;
+ fw.fw_len = adapter->firmware->size;
+
+ ret = mwifiex_dnld_fw(adapter, &fw);
+ if (ret == -1)
+ goto done;
+
+ dev_notice(adapter->dev, "WLAN FW is active\n");
+
+ adapter->init_wait_q_woken = false;
+ ret = mwifiex_init_fw(adapter);
+ if (ret == -1) {
+ goto done;
+ } else if (!ret) {
+ adapter->hw_status = MWIFIEX_HW_STATUS_READY;
+ goto done;
+ }
+ /* Wait for mwifiex_init to complete */
+ wait_event_interruptible(adapter->init_wait_q,
+ adapter->init_wait_q_woken);
+ if (adapter->hw_status != MWIFIEX_HW_STATUS_READY) {
+ ret = -1;
+ goto done;
+ }
+ ret = 0;
+
+done:
+ if (adapter->firmware)
+ release_firmware(adapter->firmware);
+ if (ret)
+ ret = -1;
+ return ret;
+}
+
+/*
+ * This function fills a driver buffer.
+ *
+ * The function associates a given SKB with the provided driver buffer
+ * and also updates some of the SKB parameters, including IP header,
+ * priority and timestamp.
+ */
+static void
+mwifiex_fill_buffer(struct sk_buff *skb)
+{
+ struct ethhdr *eth;
+ struct iphdr *iph;
+ struct timeval tv;
+ u8 tid = 0;
+
+ eth = (struct ethhdr *) skb->data;
+ switch (eth->h_proto) {
+ case __constant_htons(ETH_P_IP):
+ iph = ip_hdr(skb);
+ tid = IPTOS_PREC(iph->tos);
+ pr_debug("data: packet type ETH_P_IP: %04x, tid=%#x prio=%#x\n",
+ eth->h_proto, tid, skb->priority);
+ break;
+ case __constant_htons(ETH_P_ARP):
+ pr_debug("data: ARP packet: %04x\n", eth->h_proto);
+ default:
+ break;
+ }
+/* Offset for TOS field in the IP header */
+#define IPTOS_OFFSET 5
+ tid = (tid >> IPTOS_OFFSET);
+ skb->priority = tid;
+ /* Record the current time the packet was queued; used to
+ determine the amount of time the packet was queued in
+ the driver before it was sent to the firmware.
+ The delay is then sent along with the packet to the
+ firmware for aggregate delay calculation for stats and
+ MSDU lifetime expiry.
+ */
+ do_gettimeofday(&tv);
+ skb->tstamp = timeval_to_ktime(tv);
+}
+
+/*
+ * CFG802.11 network device handler for open.
+ *
+ * Starts the data queue.
+ */
+static int
+mwifiex_open(struct net_device *dev)
+{
+ netif_start_queue(dev);
+ return 0;
+}
+
+/*
+ * CFG802.11 network device handler for close.
+ */
+static int
+mwifiex_close(struct net_device *dev)
+{
+ return 0;
+}
+
+/*
+ * CFG802.11 network device handler for data transmission.
+ */
+static int
+mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+ struct sk_buff *new_skb;
+ struct mwifiex_txinfo *tx_info;
+
+ dev_dbg(priv->adapter->dev, "data: %lu BSS(%d): Data <= kernel\n",
+ jiffies, priv->bss_index);
+
+ if (priv->adapter->surprise_removed) {
+ kfree_skb(skb);
+ priv->stats.tx_dropped++;
+ return 0;
+ }
+ if (!skb->len || (skb->len > ETH_FRAME_LEN)) {
+ dev_err(priv->adapter->dev, "Tx: bad skb len %d\n", skb->len);
+ kfree_skb(skb);
+ priv->stats.tx_dropped++;
+ return 0;
+ }
+ if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN) {
+ dev_dbg(priv->adapter->dev,
+ "data: Tx: insufficient skb headroom %d\n",
+ skb_headroom(skb));
+ /* Insufficient skb headroom - allocate a new skb */
+ new_skb =
+ skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
+ if (unlikely(!new_skb)) {
+ dev_err(priv->adapter->dev, "Tx: cannot alloca new_skb\n");
+ kfree_skb(skb);
+ priv->stats.tx_dropped++;
+ return 0;
+ }
+ kfree_skb(skb);
+ skb = new_skb;
+ dev_dbg(priv->adapter->dev, "info: new skb headroomd %d\n",
+ skb_headroom(skb));
+ }
+
+ tx_info = MWIFIEX_SKB_TXCB(skb);
+ tx_info->bss_index = priv->bss_index;
+ mwifiex_fill_buffer(skb);
+
+ mwifiex_wmm_add_buf_txqueue(priv->adapter, skb);
+ atomic_inc(&priv->adapter->tx_pending);
+
+ if (atomic_read(&priv->adapter->tx_pending) >= MAX_TX_PENDING) {
+ netif_stop_queue(priv->netdev);
+ dev->trans_start = jiffies;
+ }
+
+ queue_work(priv->adapter->workqueue, &priv->adapter->main_work);
+
+ return 0;
+}
+
+/*
+ * CFG802.11 network device handler for setting MAC address.
+ */
+static int
+mwifiex_set_mac_address(struct net_device *dev, void *addr)
+{
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+ struct sockaddr *hw_addr = (struct sockaddr *) addr;
+ int ret;
+
+ memcpy(priv->curr_addr, hw_addr->sa_data, ETH_ALEN);
+
+ /* Send request to firmware */
+ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_MAC_ADDRESS,
+ HostCmd_ACT_GEN_SET, 0, NULL);
+
+ if (!ret)
+ memcpy(priv->netdev->dev_addr, priv->curr_addr, ETH_ALEN);
+ else
+ dev_err(priv->adapter->dev, "set mac address failed: ret=%d"
+ "\n", ret);
+
+ memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN);
+
+ return ret;
+}
+
+/*
+ * CFG802.11 network device handler for setting multicast list.
+ */
+static void mwifiex_set_multicast_list(struct net_device *dev)
+{
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+ struct mwifiex_multicast_list mcast_list;
+
+ if (dev->flags & IFF_PROMISC) {
+ mcast_list.mode = MWIFIEX_PROMISC_MODE;
+ } else if (dev->flags & IFF_ALLMULTI ||
+ netdev_mc_count(dev) > MWIFIEX_MAX_MULTICAST_LIST_SIZE) {
+ mcast_list.mode = MWIFIEX_ALL_MULTI_MODE;
+ } else {
+ mcast_list.mode = MWIFIEX_MULTICAST_MODE;
+ if (netdev_mc_count(dev))
+ mcast_list.num_multicast_addr =
+ mwifiex_copy_mcast_addr(&mcast_list, dev);
+ }
+ mwifiex_request_set_multicast_list(priv, &mcast_list);
+}
+
+/*
+ * CFG802.11 network device handler for transmission timeout.
+ */
+static void
+mwifiex_tx_timeout(struct net_device *dev)
+{
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+
+ dev_err(priv->adapter->dev, "%lu : Tx timeout, bss_index=%d\n",
+ jiffies, priv->bss_index);
+ dev->trans_start = jiffies;
+ priv->num_tx_timeout++;
+}
+
+/*
+ * CFG802.11 network device handler for statistics retrieval.
+ */
+static struct net_device_stats *mwifiex_get_stats(struct net_device *dev)
+{
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+
+ return &priv->stats;
+}
+
+/* Network device handlers */
+static const struct net_device_ops mwifiex_netdev_ops = {
+ .ndo_open = mwifiex_open,
+ .ndo_stop = mwifiex_close,
+ .ndo_start_xmit = mwifiex_hard_start_xmit,
+ .ndo_set_mac_address = mwifiex_set_mac_address,
+ .ndo_tx_timeout = mwifiex_tx_timeout,
+ .ndo_get_stats = mwifiex_get_stats,
+ .ndo_set_multicast_list = mwifiex_set_multicast_list,
+};
+
+/*
+ * This function initializes the private structure parameters.
+ *
+ * The following wait queues are initialized -
+ * - IOCTL wait queue
+ * - Command wait queue
+ * - Statistics wait queue
+ *
+ * ...and the following default parameters are set -
+ * - Current key index : Set to 0
+ * - Rate index : Set to auto
+ * - Media connected : Set to disconnected
+ * - Adhoc link sensed : Set to false
+ * - Nick name : Set to null
+ * - Number of Tx timeout : Set to 0
+ * - Device address : Set to current address
+ *
+ * In addition, the CFG80211 work queue is also created.
+ */
+static void
+mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev)
+{
+ dev->netdev_ops = &mwifiex_netdev_ops;
+ /* Initialize private structure */
+ priv->current_key_index = 0;
+ priv->media_connected = false;
+ memset(&priv->nick_name, 0, sizeof(priv->nick_name));
+ priv->num_tx_timeout = 0;
+ priv->workqueue = create_singlethread_workqueue("cfg80211_wq");
+ INIT_WORK(&priv->cfg_workqueue, mwifiex_cfg80211_results);
+ memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN);
+}
+
+/*
+ * This function adds a new logical interface.
+ *
+ * It allocates, initializes and registers the interface by performing
+ * the following opearations -
+ * - Allocate a new net device structure
+ * - Assign device name
+ * - Register the new device with CFG80211 subsystem
+ * - Initialize semaphore and private structure
+ * - Register the new device with kernel
+ * - Create the complete debug FS structure if configured
+ */
+static struct mwifiex_private *mwifiex_add_interface(
+ struct mwifiex_adapter *adapter,
+ u8 bss_index, u8 bss_type)
+{
+ struct net_device *dev;
+ struct mwifiex_private *priv;
+ void *mdev_priv;
+
+ dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), "mlan%d",
+ ether_setup, 1);
+ if (!dev) {
+ dev_err(adapter->dev, "no memory available for netdevice\n");
+ goto error;
+ }
+
+ if (mwifiex_register_cfg80211(dev, adapter->priv[bss_index]->curr_addr,
+ adapter->priv[bss_index]) != 0) {
+ dev_err(adapter->dev, "cannot register netdevice with cfg80211\n");
+ goto error;
+ }
+ /* Save the priv pointer in netdev */
+ priv = adapter->priv[bss_index];
+ mdev_priv = netdev_priv(dev);
+ *((unsigned long *) mdev_priv) = (unsigned long) priv;
+
+ priv->netdev = dev;
+
+ sema_init(&priv->async_sem, 1);
+ priv->scan_pending_on_block = false;
+
+ mwifiex_init_priv_params(priv, dev);
+
+ SET_NETDEV_DEV(dev, adapter->dev);
+
+ /* Register network device */
+ if (register_netdev(dev)) {
+ dev_err(adapter->dev, "cannot register virtual network device\n");
+ goto error;
+ }
+
+ dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name);
+#ifdef CONFIG_DEBUG_FS
+ mwifiex_dev_debugfs_init(priv);
+#endif
+ return priv;
+error:
+ if (dev)
+ free_netdev(dev);
+ return NULL;
+}
+
+/*
+ * This function removes a logical interface.
+ *
+ * It deregisters, resets and frees the interface by performing
+ * the following operations -
+ * - Disconnect the device if connected, send wireless event to
+ * notify applications.
+ * - Remove the debug FS structure if configured
+ * - Unregister the device from kernel
+ * - Free the net device structure
+ * - Cancel all works and destroy work queue
+ * - Unregister and free the wireless device from CFG80211 subsystem
+ */
+static void
+mwifiex_remove_interface(struct mwifiex_adapter *adapter, u8 bss_index)
+{
+ struct net_device *dev;
+ struct mwifiex_private *priv = adapter->priv[bss_index];
+
+ if (!priv)
+ return;
+ dev = priv->netdev;
+
+ if (priv->media_connected)
+ priv->media_connected = false;
+
+#ifdef CONFIG_DEBUG_FS
+ mwifiex_dev_debugfs_remove(priv);
+#endif
+ /* Last reference is our one */
+ dev_dbg(adapter->dev, "info: %s: refcnt = %d\n",
+ dev->name, netdev_refcnt_read(dev));
+
+ if (dev->reg_state == NETREG_REGISTERED)
+ unregister_netdev(dev);
+
+ /* Clear the priv in adapter */
+ priv->netdev = NULL;
+ if (dev)
+ free_netdev(dev);
+
+ cancel_work_sync(&priv->cfg_workqueue);
+ flush_workqueue(priv->workqueue);
+ destroy_workqueue(priv->workqueue);
+ wiphy_unregister(priv->wdev->wiphy);
+ wiphy_free(priv->wdev->wiphy);
+ kfree(priv->wdev);
+}
+
+/*
+ * This function check if command is pending.
+ */
+int is_command_pending(struct mwifiex_adapter *adapter)
+{
+ unsigned long flags;
+ int is_cmd_pend_q_empty;
+
+ spin_lock_irqsave(&adapter->cmd_pending_q_lock, flags);
+ is_cmd_pend_q_empty = list_empty(&adapter->cmd_pending_q);
+ spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
+
+ return !is_cmd_pend_q_empty;
+}
+
+/*
+ * This function returns the correct private structure pointer based
+ * upon the BSS number.
+ */
+struct mwifiex_private *
+mwifiex_bss_index_to_priv(struct mwifiex_adapter *adapter, u8 bss_index)
+{
+ if (!adapter || (bss_index >= adapter->priv_num))
+ return NULL;
+ return adapter->priv[bss_index];
+}
+
+/*
+ * This is the main work queue function.
+ *
+ * It handles the main process, which in turn handles the complete
+ * driver operations.
+ */
+static void mwifiex_main_work_queue(struct work_struct *work)
+{
+ struct mwifiex_adapter *adapter =
+ container_of(work, struct mwifiex_adapter, main_work);
+
+ if (adapter->surprise_removed)
+ return;
+ mwifiex_main_process(adapter);
+}
+
+/*
+ * This function cancels all works in the queue and destroys
+ * the main workqueue.
+ */
+static void
+mwifiex_terminate_workqueue(struct mwifiex_adapter *adapter)
+{
+ flush_workqueue(adapter->workqueue);
+ destroy_workqueue(adapter->workqueue);
+ adapter->workqueue = NULL;
+}
+
+/*
+ * This function adds the card.
+ *
+ * This function follows the following major steps to set up the device -
+ * - Initialize software. This includes probing the card, registering
+ * the interface operations table, and allocating/initializing the
+ * adapter structure
+ * - Set up the netlink socket
+ * - Create and start the main work queue
+ * - Register the device
+ * - Initialize firmware and hardware
+ * - Add logical interfaces
+ */
+int
+mwifiex_add_card(void *card, struct semaphore *sem,
+ struct mwifiex_if_ops *if_ops)
+{
+ int i;
+ struct mwifiex_adapter *adapter;
+
+ if (down_interruptible(sem))
+ goto exit_sem_err;
+
+ if (mwifiex_init_sw(card, if_ops)) {
+ pr_err("%s: software init failed\n", __func__);
+ goto err_init_sw;
+ }
+
+ adapter = g_adapter;
+
+ adapter->hw_status = MWIFIEX_HW_STATUS_INITIALIZING;
+ adapter->surprise_removed = false;
+ init_waitqueue_head(&adapter->init_wait_q);
+ adapter->is_suspended = false;
+ adapter->hs_activated = false;
+ init_waitqueue_head(&adapter->hs_activate_wait_q);
+ adapter->cmd_wait_q_required = false;
+ init_waitqueue_head(&adapter->cmd_wait_q.wait);
+ adapter->cmd_wait_q.condition = false;
+ adapter->cmd_wait_q.status = 0;
+
+ adapter->workqueue = create_workqueue("MWIFIEX_WORK_QUEUE");
+ if (!adapter->workqueue)
+ goto err_kmalloc;
+
+ INIT_WORK(&adapter->main_work, mwifiex_main_work_queue);
+
+ /* Register the device. Fill up the private data structure with relevant
+ information from the card and request for the required IRQ. */
+ if (adapter->if_ops.register_dev(adapter)) {
+ pr_err("%s: failed to register mwifiex device\n", __func__);
+ goto err_registerdev;
+ }
+
+ if (mwifiex_init_hw_fw(adapter)) {
+ pr_err("%s: firmware init failed\n", __func__);
+ goto err_init_fw;
+ }
+
+ /* Add interfaces */
+ for (i = 0; i < adapter->drv_mode->intf_num; i++) {
+ if (!mwifiex_add_interface(adapter, i,
+ adapter->drv_mode->bss_attr[i].bss_type)) {
+ goto err_add_intf;
+ }
+ }
+
+ up(sem);
+
+ return 0;
+
+err_add_intf:
+ for (i = 0; i < adapter->priv_num; i++)
+ mwifiex_remove_interface(adapter, i);
+err_init_fw:
+ pr_debug("info: %s: unregister device\n", __func__);
+ adapter->if_ops.unregister_dev(adapter);
+err_registerdev:
+ adapter->surprise_removed = true;
+ mwifiex_terminate_workqueue(adapter);
+err_kmalloc:
+ if ((adapter->hw_status == MWIFIEX_HW_STATUS_FW_READY) ||
+ (adapter->hw_status == MWIFIEX_HW_STATUS_READY)) {
+ pr_debug("info: %s: shutdown mwifiex\n", __func__);
+ adapter->init_wait_q_woken = false;
+
+ if (mwifiex_shutdown_drv(adapter) == -EINPROGRESS)
+ wait_event_interruptible(adapter->init_wait_q,
+ adapter->init_wait_q_woken);
+ }
+
+ mwifiex_free_adapter(adapter);
+
+err_init_sw:
+ up(sem);
+
+exit_sem_err:
+ return -1;
+}
+EXPORT_SYMBOL_GPL(mwifiex_add_card);
+
+/*
+ * This function removes the card.
+ *
+ * This function follows the following major steps to remove the device -
+ * - Stop data traffic
+ * - Shutdown firmware
+ * - Remove the logical interfaces
+ * - Terminate the work queue
+ * - Unregister the device
+ * - Free the adapter structure
+ */
+int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
+{
+ struct mwifiex_private *priv = NULL;
+ int i;
+
+ if (down_interruptible(sem))
+ goto exit_sem_err;
+
+ if (!adapter)
+ goto exit_remove;
+
+ adapter->surprise_removed = true;
+
+ /* Stop data */
+ for (i = 0; i < adapter->priv_num; i++) {
+ priv = adapter->priv[i];
+ if (priv) {
+ if (!netif_queue_stopped(priv->netdev))
+ netif_stop_queue(priv->netdev);
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ }
+ }
+
+ dev_dbg(adapter->dev, "cmd: calling mwifiex_shutdown_drv...\n");
+ adapter->init_wait_q_woken = false;
+
+ if (mwifiex_shutdown_drv(adapter) == -EINPROGRESS)
+ wait_event_interruptible(adapter->init_wait_q,
+ adapter->init_wait_q_woken);
+ dev_dbg(adapter->dev, "cmd: mwifiex_shutdown_drv done\n");
+ if (atomic_read(&adapter->rx_pending) ||
+ atomic_read(&adapter->tx_pending) ||
+ atomic_read(&adapter->cmd_pending)) {
+ dev_err(adapter->dev, "rx_pending=%d, tx_pending=%d, "
+ "cmd_pending=%d\n",
+ atomic_read(&adapter->rx_pending),
+ atomic_read(&adapter->tx_pending),
+ atomic_read(&adapter->cmd_pending));
+ }
+
+ /* Remove interface */
+ for (i = 0; i < adapter->priv_num; i++)
+ mwifiex_remove_interface(adapter, i);
+
+ mwifiex_terminate_workqueue(adapter);
+
+ /* Unregister device */
+ dev_dbg(adapter->dev, "info: unregister device\n");
+ adapter->if_ops.unregister_dev(adapter);
+ /* Free adapter structure */
+ dev_dbg(adapter->dev, "info: free adapter\n");
+ mwifiex_free_adapter(adapter);
+
+exit_remove:
+ up(sem);
+exit_sem_err:
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mwifiex_remove_card);
+
+/*
+ * This function initializes the module.
+ *
+ * The debug FS is also initialized if configured.
+ */
+static int
+mwifiex_init_module(void)
+{
+#ifdef CONFIG_DEBUG_FS
+ mwifiex_debugfs_init();
+#endif
+ return 0;
+}
+
+/*
+ * This function cleans up the module.
+ *
+ * The debug FS is removed if available.
+ */
+static void
+mwifiex_cleanup_module(void)
+{
+#ifdef CONFIG_DEBUG_FS
+ mwifiex_debugfs_remove();
+#endif
+}
+
+module_init(mwifiex_init_module);
+module_exit(mwifiex_cleanup_module);
+
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_DESCRIPTION("Marvell WiFi-Ex Driver version " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
new file mode 100644
index 000000000000..8316b3cd92cd
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -0,0 +1,1009 @@
+/*
+ * Marvell Wireless LAN device driver: major data structures and prototypes
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef _MWIFIEX_MAIN_H_
+#define _MWIFIEX_MAIN_H_
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/ip.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <net/sock.h>
+#include <net/lib80211.h>
+#include <linux/firmware.h>
+#include <linux/ctype.h>
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+
+extern const char driver_version[];
+extern struct mwifiex_adapter *g_adapter;
+
+enum {
+ MWIFIEX_ASYNC_CMD,
+ MWIFIEX_SYNC_CMD
+};
+
+#define DRV_MODE_STA 0x1
+
+#define SD8787_W0 0x30
+#define SD8787_W1 0x31
+#define SD8787_A0 0x40
+#define SD8787_A1 0x41
+
+#define DEFAULT_FW_NAME "mrvl/sd8787_uapsta.bin"
+#define SD8787_W1_FW_NAME "mrvl/sd8787_uapsta_w1.bin"
+#define SD8787_AX_FW_NAME "mrvl/sd8787_uapsta.bin"
+
+struct mwifiex_drv_mode {
+ u16 drv_mode;
+ u16 intf_num;
+ struct mwifiex_bss_attr *bss_attr;
+};
+
+
+#define MWIFIEX_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ)
+
+#define MWIFIEX_TIMER_10S 10000
+#define MWIFIEX_TIMER_1S 1000
+
+#define MAX_TX_PENDING 100
+#define LOW_TX_PENDING 80
+
+#define MWIFIEX_UPLD_SIZE (2312)
+
+#define MAX_EVENT_SIZE 1024
+
+#define ARP_FILTER_MAX_BUF_SIZE 68
+
+#define MWIFIEX_KEY_BUFFER_SIZE 16
+#define MWIFIEX_DEFAULT_LISTEN_INTERVAL 10
+#define MWIFIEX_MAX_REGION_CODE 7
+
+#define DEFAULT_BCN_AVG_FACTOR 8
+#define DEFAULT_DATA_AVG_FACTOR 8
+
+#define FIRST_VALID_CHANNEL 0xff
+#define DEFAULT_AD_HOC_CHANNEL 6
+#define DEFAULT_AD_HOC_CHANNEL_A 36
+
+#define DEFAULT_BCN_MISS_TIMEOUT 5
+
+#define MAX_SCAN_BEACON_BUFFER 8000
+
+#define SCAN_BEACON_ENTRY_PAD 6
+
+#define MWIFIEX_PASSIVE_SCAN_CHAN_TIME 200
+#define MWIFIEX_ACTIVE_SCAN_CHAN_TIME 200
+#define MWIFIEX_SPECIFIC_SCAN_CHAN_TIME 110
+
+#define SCAN_RSSI(RSSI) (0x100 - ((u8)(RSSI)))
+
+#define MWIFIEX_MAX_TOTAL_SCAN_TIME (MWIFIEX_TIMER_10S - MWIFIEX_TIMER_1S)
+
+#define RSN_GTK_OUI_OFFSET 2
+
+#define MWIFIEX_OUI_NOT_PRESENT 0
+#define MWIFIEX_OUI_PRESENT 1
+
+#define IS_CARD_RX_RCVD(adapter) (adapter->cmd_resp_received || \
+ adapter->event_received || \
+ adapter->data_received)
+
+#define MWIFIEX_TYPE_CMD 1
+#define MWIFIEX_TYPE_DATA 0
+#define MWIFIEX_TYPE_EVENT 3
+
+#define DBG_CMD_NUM 5
+
+#define MAX_BITMAP_RATES_SIZE 10
+
+#define MAX_CHANNEL_BAND_BG 14
+
+#define MAX_FREQUENCY_BAND_BG 2484
+
+struct mwifiex_dbg {
+ u32 num_cmd_host_to_card_failure;
+ u32 num_cmd_sleep_cfm_host_to_card_failure;
+ u32 num_tx_host_to_card_failure;
+ u32 num_event_deauth;
+ u32 num_event_disassoc;
+ u32 num_event_link_lost;
+ u32 num_cmd_deauth;
+ u32 num_cmd_assoc_success;
+ u32 num_cmd_assoc_failure;
+ u32 num_tx_timeout;
+ u32 num_cmd_timeout;
+ u16 timeout_cmd_id;
+ u16 timeout_cmd_act;
+ u16 last_cmd_id[DBG_CMD_NUM];
+ u16 last_cmd_act[DBG_CMD_NUM];
+ u16 last_cmd_index;
+ u16 last_cmd_resp_id[DBG_CMD_NUM];
+ u16 last_cmd_resp_index;
+ u16 last_event[DBG_CMD_NUM];
+ u16 last_event_index;
+};
+
+enum MWIFIEX_HARDWARE_STATUS {
+ MWIFIEX_HW_STATUS_READY,
+ MWIFIEX_HW_STATUS_INITIALIZING,
+ MWIFIEX_HW_STATUS_FW_READY,
+ MWIFIEX_HW_STATUS_INIT_DONE,
+ MWIFIEX_HW_STATUS_RESET,
+ MWIFIEX_HW_STATUS_CLOSING,
+ MWIFIEX_HW_STATUS_NOT_READY
+};
+
+enum MWIFIEX_802_11_POWER_MODE {
+ MWIFIEX_802_11_POWER_MODE_CAM,
+ MWIFIEX_802_11_POWER_MODE_PSP
+};
+
+struct mwifiex_tx_param {
+ u32 next_pkt_len;
+};
+
+enum MWIFIEX_PS_STATE {
+ PS_STATE_AWAKE,
+ PS_STATE_PRE_SLEEP,
+ PS_STATE_SLEEP_CFM,
+ PS_STATE_SLEEP
+};
+
+struct mwifiex_add_ba_param {
+ u32 tx_win_size;
+ u32 rx_win_size;
+ u32 timeout;
+};
+
+struct mwifiex_tx_aggr {
+ u8 ampdu_user;
+ u8 ampdu_ap;
+ u8 amsdu;
+};
+
+struct mwifiex_ra_list_tbl {
+ struct list_head list;
+ struct sk_buff_head skb_head;
+ u8 ra[ETH_ALEN];
+ u32 total_pkts_size;
+ u32 is_11n_enabled;
+};
+
+struct mwifiex_tid_tbl {
+ struct list_head ra_list;
+ /* spin lock for tid table */
+ spinlock_t tid_tbl_lock;
+ struct mwifiex_ra_list_tbl *ra_list_curr;
+};
+
+#define WMM_HIGHEST_PRIORITY 7
+#define HIGH_PRIO_TID 7
+#define LOW_PRIO_TID 0
+#define NO_PKT_PRIO_TID (-1)
+
+struct mwifiex_wmm_desc {
+ struct mwifiex_tid_tbl tid_tbl_ptr[MAX_NUM_TID];
+ u32 packets_out[MAX_NUM_TID];
+ /* spin lock to protect ra_list */
+ spinlock_t ra_list_spinlock;
+ struct mwifiex_wmm_ac_status ac_status[IEEE80211_MAX_QUEUES];
+ enum mwifiex_wmm_ac_e ac_down_graded_vals[IEEE80211_MAX_QUEUES];
+ u32 drv_pkt_delay_max;
+ u8 queue_priority[IEEE80211_MAX_QUEUES];
+ u32 user_pri_pkt_tx_ctrl[WMM_HIGHEST_PRIORITY + 1]; /* UP: 0 to 7 */
+ /* Number of transmit packets queued */
+ atomic_t tx_pkts_queued;
+ /* Tracks highest priority with a packet queued */
+ atomic_t highest_queued_prio;
+};
+
+struct mwifiex_802_11_security {
+ u8 wpa_enabled;
+ u8 wpa2_enabled;
+ u8 wapi_enabled;
+ u8 wapi_key_on;
+ enum MWIFIEX_802_11_WEP_STATUS wep_status;
+ u32 authentication_mode;
+ u32 encryption_mode;
+};
+
+struct ieee_types_header {
+ u8 element_id;
+ u8 len;
+} __packed;
+
+struct ieee_obss_scan_param {
+ u16 obss_scan_passive_dwell;
+ u16 obss_scan_active_dwell;
+ u16 bss_chan_width_trigger_scan_int;
+ u16 obss_scan_passive_total;
+ u16 obss_scan_active_total;
+ u16 bss_width_chan_trans_delay;
+ u16 obss_scan_active_threshold;
+} __packed;
+
+struct ieee_types_obss_scan_param {
+ struct ieee_types_header ieee_hdr;
+ struct ieee_obss_scan_param obss_scan;
+} __packed;
+
+#define MWIFIEX_SUPPORTED_RATES 14
+
+#define MWIFIEX_SUPPORTED_RATES_EXT 32
+
+#define IEEE_MAX_IE_SIZE 256
+
+struct ieee_types_vendor_specific {
+ struct ieee_types_vendor_header vend_hdr;
+ u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_vendor_header)];
+} __packed;
+
+struct ieee_types_generic {
+ struct ieee_types_header ieee_hdr;
+ u8 data[IEEE_MAX_IE_SIZE - sizeof(struct ieee_types_header)];
+} __packed;
+
+struct mwifiex_bssdescriptor {
+ u8 mac_address[ETH_ALEN];
+ struct mwifiex_802_11_ssid ssid;
+ u32 privacy;
+ s32 rssi;
+ u32 channel;
+ u32 freq;
+ u16 beacon_period;
+ u8 erp_flags;
+ u32 bss_mode;
+ u8 supported_rates[MWIFIEX_SUPPORTED_RATES];
+ u8 data_rates[MWIFIEX_SUPPORTED_RATES];
+ /* Network band.
+ * BAND_B(0x01): 'b' band
+ * BAND_G(0x02): 'g' band
+ * BAND_A(0X04): 'a' band
+ */
+ u16 bss_band;
+ u64 network_tsf;
+ u8 time_stamp[8];
+ union ieee_types_phy_param_set phy_param_set;
+ union ieee_types_ss_param_set ss_param_set;
+ u16 cap_info_bitmap;
+ struct ieee_types_wmm_parameter wmm_ie;
+ u8 disable_11n;
+ struct ieee80211_ht_cap *bcn_ht_cap;
+ u16 ht_cap_offset;
+ struct ieee80211_ht_info *bcn_ht_info;
+ u16 ht_info_offset;
+ u8 *bcn_bss_co_2040;
+ u16 bss_co_2040_offset;
+ u8 *bcn_ext_cap;
+ u16 ext_cap_offset;
+ struct ieee_types_obss_scan_param *bcn_obss_scan;
+ u16 overlap_bss_offset;
+ struct ieee_types_vendor_specific *bcn_wpa_ie;
+ u16 wpa_offset;
+ struct ieee_types_generic *bcn_rsn_ie;
+ u16 rsn_offset;
+ struct ieee_types_generic *bcn_wapi_ie;
+ u16 wapi_offset;
+ u8 *beacon_buf;
+ u32 beacon_buf_size;
+ u32 beacon_buf_size_max;
+
+};
+
+struct mwifiex_current_bss_params {
+ struct mwifiex_bssdescriptor bss_descriptor;
+ u8 wmm_enabled;
+ u8 wmm_uapsd_enabled;
+ u8 band;
+ u32 num_of_rates;
+ u8 data_rates[MWIFIEX_SUPPORTED_RATES];
+};
+
+struct mwifiex_sleep_params {
+ u16 sp_error;
+ u16 sp_offset;
+ u16 sp_stable_time;
+ u8 sp_cal_control;
+ u8 sp_ext_sleep_clk;
+ u16 sp_reserved;
+};
+
+struct mwifiex_sleep_period {
+ u16 period;
+ u16 reserved;
+};
+
+struct mwifiex_wep_key {
+ u32 length;
+ u32 key_index;
+ u32 key_length;
+ u8 key_material[MWIFIEX_KEY_BUFFER_SIZE];
+};
+
+#define MAX_REGION_CHANNEL_NUM 2
+
+struct mwifiex_chan_freq_power {
+ u16 channel;
+ u32 freq;
+ u16 max_tx_power;
+ u8 unsupported;
+};
+
+enum state_11d_t {
+ DISABLE_11D = 0,
+ ENABLE_11D = 1,
+};
+
+#define MWIFIEX_MAX_TRIPLET_802_11D 83
+
+struct mwifiex_802_11d_domain_reg {
+ u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
+ u8 no_of_triplet;
+ struct ieee80211_country_ie_triplet
+ triplet[MWIFIEX_MAX_TRIPLET_802_11D];
+};
+
+struct mwifiex_vendor_spec_cfg_ie {
+ u16 mask;
+ u16 flag;
+ u8 ie[MWIFIEX_MAX_VSIE_LEN];
+};
+
+struct wps {
+ u8 session_enable;
+};
+
+struct mwifiex_adapter;
+struct mwifiex_private;
+
+struct mwifiex_private {
+ struct mwifiex_adapter *adapter;
+ u8 bss_index;
+ u8 bss_type;
+ u8 bss_role;
+ u8 bss_priority;
+ u8 bss_num;
+ u8 frame_type;
+ u8 curr_addr[ETH_ALEN];
+ u8 media_connected;
+ u32 num_tx_timeout;
+ struct net_device *netdev;
+ struct net_device_stats stats;
+ u16 curr_pkt_filter;
+ u32 bss_mode;
+ u32 pkt_tx_ctrl;
+ u16 tx_power_level;
+ u8 max_tx_power_level;
+ u8 min_tx_power_level;
+ u8 tx_rate;
+ u8 tx_htinfo;
+ u8 rxpd_htinfo;
+ u8 rxpd_rate;
+ u16 rate_bitmap;
+ u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+ u32 data_rate;
+ u8 is_data_rate_auto;
+ u16 bcn_avg_factor;
+ u16 data_avg_factor;
+ s16 data_rssi_last;
+ s16 data_nf_last;
+ s16 data_rssi_avg;
+ s16 data_nf_avg;
+ s16 bcn_rssi_last;
+ s16 bcn_nf_last;
+ s16 bcn_rssi_avg;
+ s16 bcn_nf_avg;
+ struct mwifiex_bssdescriptor *attempted_bss_desc;
+ struct mwifiex_802_11_ssid prev_ssid;
+ u8 prev_bssid[ETH_ALEN];
+ struct mwifiex_current_bss_params curr_bss_params;
+ u16 beacon_period;
+ u16 listen_interval;
+ u16 atim_window;
+ u8 adhoc_channel;
+ u8 adhoc_is_link_sensed;
+ u8 adhoc_state;
+ struct mwifiex_802_11_security sec_info;
+ struct mwifiex_wep_key wep_key[NUM_WEP_KEYS];
+ u16 wep_key_curr_index;
+ u8 wpa_ie[256];
+ u8 wpa_ie_len;
+ u8 wpa_is_gtk_set;
+ struct host_cmd_ds_802_11_key_material aes_key;
+ u8 wapi_ie[256];
+ u8 wapi_ie_len;
+ u8 wmm_required;
+ u8 wmm_enabled;
+ u8 wmm_qosinfo;
+ struct mwifiex_wmm_desc wmm;
+ struct list_head tx_ba_stream_tbl_ptr;
+ /* spin lock for tx_ba_stream_tbl_ptr queue */
+ spinlock_t tx_ba_stream_tbl_lock;
+ struct mwifiex_tx_aggr aggr_prio_tbl[MAX_NUM_TID];
+ struct mwifiex_add_ba_param add_ba_param;
+ u16 rx_seq[MAX_NUM_TID];
+ struct list_head rx_reorder_tbl_ptr;
+ /* spin lock for rx_reorder_tbl_ptr queue */
+ spinlock_t rx_reorder_tbl_lock;
+ /* spin lock for Rx packets */
+ spinlock_t rx_pkt_lock;
+
+#define MWIFIEX_ASSOC_RSP_BUF_SIZE 500
+ u8 assoc_rsp_buf[MWIFIEX_ASSOC_RSP_BUF_SIZE];
+ u32 assoc_rsp_size;
+
+#define MWIFIEX_GENIE_BUF_SIZE 256
+ u8 gen_ie_buf[MWIFIEX_GENIE_BUF_SIZE];
+ u8 gen_ie_buf_len;
+
+ struct mwifiex_vendor_spec_cfg_ie vs_ie[MWIFIEX_MAX_VSIE_NUM];
+
+#define MWIFIEX_ASSOC_TLV_BUF_SIZE 256
+ u8 assoc_tlv_buf[MWIFIEX_ASSOC_TLV_BUF_SIZE];
+ u8 assoc_tlv_buf_len;
+
+ u8 *curr_bcn_buf;
+ u32 curr_bcn_size;
+ /* spin lock for beacon buffer */
+ spinlock_t curr_bcn_buf_lock;
+ struct wireless_dev *wdev;
+ struct mwifiex_chan_freq_power cfp;
+ char version_str[128];
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *dfs_dev_dir;
+#endif
+ u8 nick_name[16];
+ struct iw_statistics w_stats;
+ u16 current_key_index;
+ struct semaphore async_sem;
+ u8 scan_pending_on_block;
+ u8 report_scan_result;
+ struct cfg80211_scan_request *scan_request;
+ int scan_result_status;
+ int assoc_request;
+ u16 assoc_result;
+ int ibss_join_request;
+ u16 ibss_join_result;
+ bool disconnect;
+ u8 cfg_bssid[6];
+ struct workqueue_struct *workqueue;
+ struct work_struct cfg_workqueue;
+ u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
+ struct wps wps;
+ u8 scan_block;
+};
+
+enum mwifiex_ba_status {
+ BA_STREAM_NOT_SETUP = 0,
+ BA_STREAM_SETUP_INPROGRESS,
+ BA_STREAM_SETUP_COMPLETE
+};
+
+struct mwifiex_tx_ba_stream_tbl {
+ struct list_head list;
+ int tid;
+ u8 ra[ETH_ALEN];
+ enum mwifiex_ba_status ba_status;
+};
+
+struct mwifiex_rx_reorder_tbl;
+
+struct reorder_tmr_cnxt {
+ struct timer_list timer;
+ struct mwifiex_rx_reorder_tbl *ptr;
+ struct mwifiex_private *priv;
+};
+
+struct mwifiex_rx_reorder_tbl {
+ struct list_head list;
+ int tid;
+ u8 ta[ETH_ALEN];
+ int start_win;
+ int win_size;
+ void **rx_reorder_ptr;
+ struct reorder_tmr_cnxt timer_context;
+};
+
+struct mwifiex_bss_prio_node {
+ struct list_head list;
+ struct mwifiex_private *priv;
+};
+
+struct mwifiex_bss_prio_tbl {
+ struct list_head bss_prio_head;
+ /* spin lock for bss priority */
+ spinlock_t bss_prio_lock;
+ struct mwifiex_bss_prio_node *bss_prio_cur;
+};
+
+struct cmd_ctrl_node {
+ struct list_head list;
+ struct mwifiex_private *priv;
+ u32 cmd_oid;
+ u32 cmd_flag;
+ struct sk_buff *cmd_skb;
+ struct sk_buff *resp_skb;
+ void *data_buf;
+ u32 wait_q_enabled;
+ struct sk_buff *skb;
+};
+
+struct mwifiex_if_ops {
+ int (*init_if) (struct mwifiex_adapter *);
+ void (*cleanup_if) (struct mwifiex_adapter *);
+ int (*check_fw_status) (struct mwifiex_adapter *, u32, int *);
+ int (*prog_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *);
+ int (*register_dev) (struct mwifiex_adapter *);
+ void (*unregister_dev) (struct mwifiex_adapter *);
+ int (*enable_int) (struct mwifiex_adapter *);
+ int (*process_int_status) (struct mwifiex_adapter *);
+ int (*host_to_card) (struct mwifiex_adapter *, u8,
+ u8 *payload, u32 pkt_len,
+ struct mwifiex_tx_param *);
+ int (*wakeup) (struct mwifiex_adapter *);
+ int (*wakeup_complete) (struct mwifiex_adapter *);
+
+ void (*update_mp_end_port) (struct mwifiex_adapter *, u16);
+ void (*cleanup_mpa_buf) (struct mwifiex_adapter *);
+};
+
+struct mwifiex_adapter {
+ struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM];
+ u8 priv_num;
+ struct mwifiex_drv_mode *drv_mode;
+ const struct firmware *firmware;
+ struct device *dev;
+ bool surprise_removed;
+ u32 fw_release_number;
+ u32 revision_id;
+ u16 init_wait_q_woken;
+ wait_queue_head_t init_wait_q;
+ void *card;
+ struct mwifiex_if_ops if_ops;
+ atomic_t rx_pending;
+ atomic_t tx_pending;
+ atomic_t cmd_pending;
+ struct workqueue_struct *workqueue;
+ struct work_struct main_work;
+ struct mwifiex_bss_prio_tbl bss_prio_tbl[MWIFIEX_MAX_BSS_NUM];
+ /* spin lock for init/shutdown */
+ spinlock_t mwifiex_lock;
+ /* spin lock for main process */
+ spinlock_t main_proc_lock;
+ u32 mwifiex_processing;
+ u16 max_tx_buf_size;
+ u16 tx_buf_size;
+ u16 curr_tx_buf_size;
+ u32 ioport;
+ enum MWIFIEX_HARDWARE_STATUS hw_status;
+ u16 number_of_antenna;
+ u32 fw_cap_info;
+ /* spin lock for interrupt handling */
+ spinlock_t int_lock;
+ u8 int_status;
+ u32 event_cause;
+ struct sk_buff *event_skb;
+ u8 upld_buf[MWIFIEX_UPLD_SIZE];
+ u8 data_sent;
+ u8 cmd_sent;
+ u8 cmd_resp_received;
+ u8 event_received;
+ u8 data_received;
+ u16 seq_num;
+ struct cmd_ctrl_node *cmd_pool;
+ struct cmd_ctrl_node *curr_cmd;
+ /* spin lock for command */
+ spinlock_t mwifiex_cmd_lock;
+ u32 num_cmd_timeout;
+ u16 last_init_cmd;
+ struct timer_list cmd_timer;
+ struct list_head cmd_free_q;
+ /* spin lock for cmd_free_q */
+ spinlock_t cmd_free_q_lock;
+ struct list_head cmd_pending_q;
+ /* spin lock for cmd_pending_q */
+ spinlock_t cmd_pending_q_lock;
+ struct list_head scan_pending_q;
+ /* spin lock for scan_pending_q */
+ spinlock_t scan_pending_q_lock;
+ u32 scan_processing;
+ u16 region_code;
+ struct mwifiex_802_11d_domain_reg domain_reg;
+ struct mwifiex_bssdescriptor *scan_table;
+ u32 num_in_scan_table;
+ u16 scan_probes;
+ u32 scan_mode;
+ u16 specific_scan_time;
+ u16 active_scan_time;
+ u16 passive_scan_time;
+ u8 bcn_buf[MAX_SCAN_BEACON_BUFFER];
+ u8 *bcn_buf_end;
+ u8 fw_bands;
+ u8 adhoc_start_band;
+ u8 config_bands;
+ struct mwifiex_chan_scan_param_set *scan_channels;
+ u8 tx_lock_flag;
+ struct mwifiex_sleep_params sleep_params;
+ struct mwifiex_sleep_period sleep_period;
+ u16 ps_mode;
+ u32 ps_state;
+ u8 need_to_wakeup;
+ u16 multiple_dtim;
+ u16 local_listen_interval;
+ u16 null_pkt_interval;
+ struct sk_buff *sleep_cfm;
+ u16 bcn_miss_time_out;
+ u16 adhoc_awake_period;
+ u8 is_deep_sleep;
+ u8 delay_null_pkt;
+ u16 delay_to_ps;
+ u16 enhanced_ps_mode;
+ u8 pm_wakeup_card_req;
+ u16 gen_null_pkt;
+ u16 pps_uapsd_mode;
+ u32 pm_wakeup_fw_try;
+ u8 is_hs_configured;
+ struct mwifiex_hs_config_param hs_cfg;
+ u8 hs_activated;
+ u16 hs_activate_wait_q_woken;
+ wait_queue_head_t hs_activate_wait_q;
+ bool is_suspended;
+ u8 event_body[MAX_EVENT_SIZE];
+ u32 hw_dot_11n_dev_cap;
+ u8 hw_dev_mcs_support;
+ u8 adhoc_11n_enabled;
+ u8 chan_offset;
+ struct mwifiex_dbg dbg;
+ u8 arp_filter[ARP_FILTER_MAX_BUF_SIZE];
+ u32 arp_filter_size;
+ u16 cmd_wait_q_required;
+ struct mwifiex_wait_queue cmd_wait_q;
+};
+
+int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
+void mwifiex_free_lock_list(struct mwifiex_adapter *adapter);
+
+int mwifiex_init_fw(struct mwifiex_adapter *adapter);
+
+int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter);
+
+int mwifiex_shutdown_drv(struct mwifiex_adapter *adapter);
+
+int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter);
+
+int mwifiex_dnld_fw(struct mwifiex_adapter *, struct mwifiex_fw_image *);
+
+int mwifiex_recv_packet(struct mwifiex_adapter *, struct sk_buff *skb);
+
+int mwifiex_process_event(struct mwifiex_adapter *adapter);
+
+int mwifiex_complete_cmd(struct mwifiex_adapter *adapter);
+
+int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
+ u16 cmd_action, u32 cmd_oid, void *data_buf);
+
+int mwifiex_send_cmd_sync(struct mwifiex_private *priv, uint16_t cmd_no,
+ u16 cmd_action, u32 cmd_oid, void *data_buf);
+
+void mwifiex_cmd_timeout_func(unsigned long function_context);
+
+int mwifiex_get_debug_info(struct mwifiex_private *,
+ struct mwifiex_debug_info *);
+
+int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter);
+int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter);
+void mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter);
+void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter);
+
+void mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
+ struct cmd_ctrl_node *cmd_node);
+
+void mwifiex_insert_cmd_to_pending_q(struct mwifiex_adapter *adapter,
+ struct cmd_ctrl_node *cmd_node,
+ u32 addtail);
+
+int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter);
+int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter);
+int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter,
+ struct sk_buff *skb);
+int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
+ struct mwifiex_tx_param *tx_param);
+int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags);
+int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
+ struct sk_buff *skb, int status);
+int mwifiex_recv_packet_complete(struct mwifiex_adapter *,
+ struct sk_buff *skb, int status);
+void mwifiex_clean_txrx(struct mwifiex_private *priv);
+u8 mwifiex_check_last_packet_indication(struct mwifiex_private *priv);
+void mwifiex_check_ps_cond(struct mwifiex_adapter *adapter);
+void mwifiex_process_sleep_confirm_resp(struct mwifiex_adapter *, u8 *,
+ u32);
+int mwifiex_cmd_enh_power_mode(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ u16 cmd_action, uint16_t ps_bitmap,
+ void *data_buf);
+int mwifiex_ret_enh_power_mode(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp,
+ void *data_buf);
+void mwifiex_process_hs_config(struct mwifiex_adapter *adapter);
+void mwifiex_hs_activated_event(struct mwifiex_private *priv,
+ u8 activated);
+int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp);
+int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter,
+ struct sk_buff *skb);
+int mwifiex_sta_prepare_cmd(struct mwifiex_private *, uint16_t cmd_no,
+ u16 cmd_action, u32 cmd_oid,
+ void *data_buf, void *cmd_buf);
+int mwifiex_process_sta_cmdresp(struct mwifiex_private *, u16 cmdresp_no,
+ void *cmd_buf);
+int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *,
+ struct sk_buff *skb);
+int mwifiex_process_sta_event(struct mwifiex_private *);
+void *mwifiex_process_sta_txpd(struct mwifiex_private *, struct sk_buff *skb);
+int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta);
+int mwifiex_scan_networks(struct mwifiex_private *priv,
+ const struct mwifiex_user_scan_cfg *user_scan_in);
+int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd,
+ void *data_buf);
+void mwifiex_queue_scan_cmd(struct mwifiex_private *priv,
+ struct cmd_ctrl_node *cmd_node);
+int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp);
+s32 mwifiex_find_ssid_in_list(struct mwifiex_private *priv,
+ struct mwifiex_802_11_ssid *ssid, u8 *bssid,
+ u32 mode);
+s32 mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid,
+ u32 mode);
+int mwifiex_find_best_network(struct mwifiex_private *priv,
+ struct mwifiex_ssid_bssid *req_ssid_bssid);
+s32 mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1,
+ struct mwifiex_802_11_ssid *ssid2);
+int mwifiex_associate(struct mwifiex_private *priv,
+ struct mwifiex_bssdescriptor *bss_desc);
+int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
+ struct host_cmd_ds_command
+ *cmd, void *data_buf);
+int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp);
+void mwifiex_reset_connect_state(struct mwifiex_private *priv);
+void mwifiex_2040_coex_event(struct mwifiex_private *priv);
+u8 mwifiex_band_to_radio_type(u8 band);
+int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac);
+int mwifiex_adhoc_start(struct mwifiex_private *priv,
+ struct mwifiex_802_11_ssid *adhoc_ssid);
+int mwifiex_adhoc_join(struct mwifiex_private *priv,
+ struct mwifiex_bssdescriptor *bss_desc);
+int mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ void *data_buf);
+int mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ void *data_buf);
+int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp);
+int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd);
+struct mwifiex_chan_freq_power *
+ mwifiex_get_cfp_by_band_and_channel_from_cfg80211(
+ struct mwifiex_private *priv,
+ u8 band, u16 channel);
+struct mwifiex_chan_freq_power *mwifiex_get_cfp_by_band_and_freq_from_cfg80211(
+ struct mwifiex_private *priv,
+ u8 band, u32 freq);
+u32 mwifiex_index_to_data_rate(u8 index, u8 ht_info);
+u32 mwifiex_find_freq_from_band_chan(u8, u8);
+int mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv, u16 vsie_mask,
+ u8 **buffer);
+u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv,
+ u8 *rates);
+u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates);
+u8 mwifiex_data_rate_to_index(u32 rate);
+u8 mwifiex_is_rate_auto(struct mwifiex_private *priv);
+int mwifiex_get_rate_index(u16 *rateBitmap, int size);
+extern u16 region_code_index[MWIFIEX_MAX_REGION_CODE];
+void mwifiex_save_curr_bcn(struct mwifiex_private *priv);
+void mwifiex_free_curr_bcn(struct mwifiex_private *priv);
+int mwifiex_cmd_get_hw_spec(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd);
+int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp);
+int is_command_pending(struct mwifiex_adapter *adapter);
+
+/*
+ * This function checks if the queuing is RA based or not.
+ */
+static inline u8
+mwifiex_queuing_ra_based(struct mwifiex_private *priv)
+{
+ /*
+ * Currently we assume if we are in Infra, then DA=RA. This might not be
+ * true in the future
+ */
+ if ((priv->bss_mode == NL80211_IFTYPE_STATION) &&
+ (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA))
+ return false;
+
+ return true;
+}
+
+/*
+ * This function copies rates.
+ */
+static inline u32
+mwifiex_copy_rates(u8 *dest, u32 pos, u8 *src, int len)
+{
+ int i;
+
+ for (i = 0; i < len && src[i]; i++, pos++) {
+ if (pos >= MWIFIEX_SUPPORTED_RATES)
+ break;
+ dest[pos] = src[i];
+ }
+
+ return pos;
+}
+
+/*
+ * This function returns the correct private structure pointer based
+ * upon the BSS type and BSS number.
+ */
+static inline struct mwifiex_private *
+mwifiex_get_priv_by_id(struct mwifiex_adapter *adapter,
+ u8 bss_num, u8 bss_type)
+{
+ int i;
+
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (adapter->priv[i]) {
+ if ((adapter->priv[i]->bss_num == bss_num)
+ && (adapter->priv[i]->bss_type == bss_type))
+ break;
+ }
+ }
+ return ((i < adapter->priv_num) ? adapter->priv[i] : NULL);
+}
+
+/*
+ * This function returns the first available private structure pointer
+ * based upon the BSS role.
+ */
+static inline struct mwifiex_private *
+mwifiex_get_priv(struct mwifiex_adapter *adapter,
+ enum mwifiex_bss_role bss_role)
+{
+ int i;
+
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (adapter->priv[i]) {
+ if (bss_role == MWIFIEX_BSS_ROLE_ANY ||
+ GET_BSS_ROLE(adapter->priv[i]) == bss_role)
+ break;
+ }
+ }
+
+ return ((i < adapter->priv_num) ? adapter->priv[i] : NULL);
+}
+
+/*
+ * This function returns the driver private structure of a network device.
+ */
+static inline struct mwifiex_private *
+mwifiex_netdev_get_priv(struct net_device *dev)
+{
+ return (struct mwifiex_private *) (*(unsigned long *) netdev_priv(dev));
+}
+
+struct mwifiex_private *mwifiex_bss_index_to_priv(struct mwifiex_adapter
+ *adapter, u8 bss_index);
+int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
+ u32 func_init_shutdown);
+int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *);
+int mwifiex_remove_card(struct mwifiex_adapter *, struct semaphore *);
+
+void mwifiex_get_version(struct mwifiex_adapter *adapter, char *version,
+ int maxlen);
+int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
+ struct mwifiex_multicast_list *mcast_list);
+int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,
+ struct net_device *dev);
+int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter);
+int mwifiex_bss_start(struct mwifiex_private *priv,
+ struct mwifiex_ssid_bssid *ssid_bssid);
+int mwifiex_set_hs_params(struct mwifiex_private *priv,
+ u16 action, int cmd_type,
+ struct mwifiex_ds_hs_cfg *hscfg);
+int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type);
+int mwifiex_enable_hs(struct mwifiex_adapter *adapter);
+int mwifiex_get_signal_info(struct mwifiex_private *priv,
+ struct mwifiex_ds_get_signal *signal);
+int mwifiex_drv_get_data_rate(struct mwifiex_private *priv,
+ struct mwifiex_rate_cfg *rate);
+int mwifiex_find_best_bss(struct mwifiex_private *priv,
+ struct mwifiex_ssid_bssid *ssid_bssid);
+int mwifiex_request_scan(struct mwifiex_private *priv,
+ struct mwifiex_802_11_ssid *req_ssid);
+int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv,
+ struct mwifiex_user_scan_cfg *scan_req);
+int mwifiex_change_adhoc_chan(struct mwifiex_private *priv, int channel);
+int mwifiex_set_radio(struct mwifiex_private *priv, u8 option);
+
+int mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel);
+
+int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key,
+ int key_len, u8 key_index, int disable);
+
+int mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len);
+
+int mwifiex_get_ver_ext(struct mwifiex_private *priv);
+
+int mwifiex_get_stats_info(struct mwifiex_private *priv,
+ struct mwifiex_ds_get_stats *log);
+
+int mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type,
+ u32 reg_offset, u32 reg_value);
+
+int mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type,
+ u32 reg_offset, u32 *value);
+
+int mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes,
+ u8 *value);
+
+int mwifiex_set_11n_httx_cfg(struct mwifiex_private *priv, int data);
+
+int mwifiex_get_11n_httx_cfg(struct mwifiex_private *priv, int *data);
+
+int mwifiex_set_tx_rate_cfg(struct mwifiex_private *priv, int tx_rate_index);
+
+int mwifiex_get_tx_rate_cfg(struct mwifiex_private *priv, int *tx_rate_index);
+
+int mwifiex_drv_set_power(struct mwifiex_private *priv, u32 *ps_mode);
+
+int mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter,
+ char *version, int max_len);
+
+int mwifiex_set_tx_power(struct mwifiex_private *priv,
+ struct mwifiex_power_cfg *power_cfg);
+
+int mwifiex_main_process(struct mwifiex_adapter *);
+
+int mwifiex_bss_set_channel(struct mwifiex_private *,
+ struct mwifiex_chan_freq_power *cfp);
+int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *,
+ struct mwifiex_ssid_bssid *);
+int mwifiex_set_radio_band_cfg(struct mwifiex_private *,
+ struct mwifiex_ds_band_cfg *);
+int mwifiex_get_bss_info(struct mwifiex_private *,
+ struct mwifiex_bss_info *);
+
+#ifdef CONFIG_DEBUG_FS
+void mwifiex_debugfs_init(void);
+void mwifiex_debugfs_remove(void);
+
+void mwifiex_dev_debugfs_init(struct mwifiex_private *priv);
+void mwifiex_dev_debugfs_remove(struct mwifiex_private *priv);
+#endif
+#endif /* !_MWIFIEX_MAIN_H_ */
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
new file mode 100644
index 000000000000..5c22860fb40a
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -0,0 +1,3025 @@
+/*
+ * Marvell Wireless LAN device driver: scan ioctl and command handling
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "11n.h"
+#include "cfg80211.h"
+
+/* The maximum number of channels the firmware can scan per command */
+#define MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN 14
+
+#define MWIFIEX_CHANNELS_PER_SCAN_CMD 4
+
+/* Memory needed to store a max sized Channel List TLV for a firmware scan */
+#define CHAN_TLV_MAX_SIZE (sizeof(struct mwifiex_ie_types_header) \
+ + (MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN \
+ *sizeof(struct mwifiex_chan_scan_param_set)))
+
+/* Memory needed to store supported rate */
+#define RATE_TLV_MAX_SIZE (sizeof(struct mwifiex_ie_types_rates_param_set) \
+ + HOSTCMD_SUPPORTED_RATES)
+
+/* Memory needed to store a max number/size WildCard SSID TLV for a firmware
+ scan */
+#define WILDCARD_SSID_TLV_MAX_SIZE \
+ (MWIFIEX_MAX_SSID_LIST_LENGTH * \
+ (sizeof(struct mwifiex_ie_types_wildcard_ssid_params) \
+ + IEEE80211_MAX_SSID_LEN))
+
+/* Maximum memory needed for a mwifiex_scan_cmd_config with all TLVs at max */
+#define MAX_SCAN_CFG_ALLOC (sizeof(struct mwifiex_scan_cmd_config) \
+ + sizeof(struct mwifiex_ie_types_num_probes) \
+ + sizeof(struct mwifiex_ie_types_htcap) \
+ + CHAN_TLV_MAX_SIZE \
+ + RATE_TLV_MAX_SIZE \
+ + WILDCARD_SSID_TLV_MAX_SIZE)
+
+
+union mwifiex_scan_cmd_config_tlv {
+ /* Scan configuration (variable length) */
+ struct mwifiex_scan_cmd_config config;
+ /* Max allocated block */
+ u8 config_alloc_buf[MAX_SCAN_CFG_ALLOC];
+};
+
+enum cipher_suite {
+ CIPHER_SUITE_TKIP,
+ CIPHER_SUITE_CCMP,
+ CIPHER_SUITE_MAX
+};
+static u8 mwifiex_wpa_oui[CIPHER_SUITE_MAX][4] = {
+ { 0x00, 0x50, 0xf2, 0x02 }, /* TKIP */
+ { 0x00, 0x50, 0xf2, 0x04 }, /* AES */
+};
+static u8 mwifiex_rsn_oui[CIPHER_SUITE_MAX][4] = {
+ { 0x00, 0x0f, 0xac, 0x02 }, /* TKIP */
+ { 0x00, 0x0f, 0xac, 0x04 }, /* AES */
+};
+
+/*
+ * This function parses a given IE for a given OUI.
+ *
+ * This is used to parse a WPA/RSN IE to find if it has
+ * a given oui in PTK.
+ */
+static u8
+mwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui)
+{
+ u8 count;
+
+ count = iebody->ptk_cnt[0];
+
+ /* There could be multiple OUIs for PTK hence
+ 1) Take the length.
+ 2) Check all the OUIs for AES.
+ 3) If one of them is AES then pass success. */
+ while (count) {
+ if (!memcmp(iebody->ptk_body, oui, sizeof(iebody->ptk_body)))
+ return MWIFIEX_OUI_PRESENT;
+
+ --count;
+ if (count)
+ iebody = (struct ie_body *) ((u8 *) iebody +
+ sizeof(iebody->ptk_body));
+ }
+
+ pr_debug("info: %s: OUI is not found in PTK\n", __func__);
+ return MWIFIEX_OUI_NOT_PRESENT;
+}
+
+/*
+ * This function checks if a given OUI is present in a RSN IE.
+ *
+ * The function first checks if a RSN IE is present or not in the
+ * BSS descriptor. It tries to locate the OUI only if such an IE is
+ * present.
+ */
+static u8
+mwifiex_is_rsn_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
+{
+ u8 *oui;
+ struct ie_body *iebody;
+ u8 ret = MWIFIEX_OUI_NOT_PRESENT;
+
+ if (((bss_desc->bcn_rsn_ie) && ((*(bss_desc->bcn_rsn_ie)).
+ ieee_hdr.element_id == WLAN_EID_RSN))) {
+ iebody = (struct ie_body *)
+ (((u8 *) bss_desc->bcn_rsn_ie->data) +
+ RSN_GTK_OUI_OFFSET);
+ oui = &mwifiex_rsn_oui[cipher][0];
+ ret = mwifiex_search_oui_in_ie(iebody, oui);
+ if (ret)
+ return ret;
+ }
+ return ret;
+}
+
+/*
+ * This function checks if a given OUI is present in a WPA IE.
+ *
+ * The function first checks if a WPA IE is present or not in the
+ * BSS descriptor. It tries to locate the OUI only if such an IE is
+ * present.
+ */
+static u8
+mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
+{
+ u8 *oui;
+ struct ie_body *iebody;
+ u8 ret = MWIFIEX_OUI_NOT_PRESENT;
+
+ if (((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)).
+ vend_hdr.element_id == WLAN_EID_WPA))) {
+ iebody = (struct ie_body *) bss_desc->bcn_wpa_ie->data;
+ oui = &mwifiex_wpa_oui[cipher][0];
+ ret = mwifiex_search_oui_in_ie(iebody, oui);
+ if (ret)
+ return ret;
+ }
+ return ret;
+}
+
+/*
+ * This function compares two SSIDs and checks if they match.
+ */
+s32
+mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1,
+ struct mwifiex_802_11_ssid *ssid2)
+{
+ if (!ssid1 || !ssid2 || (ssid1->ssid_len != ssid2->ssid_len))
+ return -1;
+ return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssid_len);
+}
+
+/*
+ * Sends IOCTL request to get the best BSS.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int mwifiex_find_best_bss(struct mwifiex_private *priv,
+ struct mwifiex_ssid_bssid *ssid_bssid)
+{
+ struct mwifiex_ssid_bssid tmp_ssid_bssid;
+ u8 *mac;
+
+ if (!ssid_bssid)
+ return -1;
+
+ memcpy(&tmp_ssid_bssid, ssid_bssid,
+ sizeof(struct mwifiex_ssid_bssid));
+
+ if (!mwifiex_bss_ioctl_find_bss(priv, &tmp_ssid_bssid)) {
+ memcpy(ssid_bssid, &tmp_ssid_bssid,
+ sizeof(struct mwifiex_ssid_bssid));
+ mac = (u8 *) &ssid_bssid->bssid;
+ dev_dbg(priv->adapter->dev, "cmd: found network: ssid=%s,"
+ " %pM\n", ssid_bssid->ssid.ssid, mac);
+ return 0;
+ }
+
+ return -1;
+}
+
+/*
+ * Sends IOCTL request to start a scan with user configurations.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ *
+ * Upon completion, it also generates a wireless event to notify
+ * applications.
+ */
+int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv,
+ struct mwifiex_user_scan_cfg *scan_req)
+{
+ int status;
+
+ priv->adapter->cmd_wait_q.condition = false;
+
+ status = mwifiex_scan_networks(priv, scan_req);
+ if (!status)
+ status = mwifiex_wait_queue_complete(priv->adapter);
+
+ return status;
+}
+
+/*
+ * This function checks if wapi is enabled in driver and scanned network is
+ * compatible with it.
+ */
+static bool
+mwifiex_is_network_compatible_for_wapi(struct mwifiex_private *priv,
+ struct mwifiex_bssdescriptor *bss_desc)
+{
+ if (priv->sec_info.wapi_enabled &&
+ (bss_desc->bcn_wapi_ie &&
+ ((*(bss_desc->bcn_wapi_ie)).ieee_hdr.element_id ==
+ WLAN_EID_BSS_AC_ACCESS_DELAY))) {
+ return true;
+ }
+ return false;
+}
+
+/*
+ * This function checks if driver is configured with no security mode and
+ * scanned network is compatible with it.
+ */
+static bool
+mwifiex_is_network_compatible_for_no_sec(struct mwifiex_private *priv,
+ struct mwifiex_bssdescriptor *bss_desc)
+{
+ if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
+ && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
+ && ((!bss_desc->bcn_wpa_ie) ||
+ ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id !=
+ WLAN_EID_WPA))
+ && ((!bss_desc->bcn_rsn_ie) ||
+ ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id !=
+ WLAN_EID_RSN))
+ && !priv->sec_info.encryption_mode
+ && !bss_desc->privacy) {
+ return true;
+ }
+ return false;
+}
+
+/*
+ * This function checks if static WEP is enabled in driver and scanned network
+ * is compatible with it.
+ */
+static bool
+mwifiex_is_network_compatible_for_static_wep(struct mwifiex_private *priv,
+ struct mwifiex_bssdescriptor *bss_desc)
+{
+ if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED
+ && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
+ && bss_desc->privacy) {
+ return true;
+ }
+ return false;
+}
+
+/*
+ * This function checks if wpa is enabled in driver and scanned network is
+ * compatible with it.
+ */
+static bool
+mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv,
+ struct mwifiex_bssdescriptor *bss_desc,
+ int index)
+{
+ if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
+ && priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
+ && ((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)).vend_hdr.
+ element_id == WLAN_EID_WPA))
+ /*
+ * Privacy bit may NOT be set in some APs like
+ * LinkSys WRT54G && bss_desc->privacy
+ */
+ ) {
+ dev_dbg(priv->adapter->dev, "info: %s: WPA: index=%d"
+ " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
+ "EncMode=%#x privacy=%#x\n", __func__, index,
+ (bss_desc->bcn_wpa_ie) ?
+ (*(bss_desc->bcn_wpa_ie)).
+ vend_hdr.element_id : 0,
+ (bss_desc->bcn_rsn_ie) ?
+ (*(bss_desc->bcn_rsn_ie)).
+ ieee_hdr.element_id : 0,
+ (priv->sec_info.wep_status ==
+ MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d",
+ (priv->sec_info.wpa_enabled) ? "e" : "d",
+ (priv->sec_info.wpa2_enabled) ? "e" : "d",
+ priv->sec_info.encryption_mode,
+ bss_desc->privacy);
+ return true;
+ }
+ return false;
+}
+
+/*
+ * This function checks if wpa2 is enabled in driver and scanned network is
+ * compatible with it.
+ */
+static bool
+mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv,
+ struct mwifiex_bssdescriptor *bss_desc,
+ int index)
+{
+ if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
+ && !priv->sec_info.wpa_enabled && priv->sec_info.wpa2_enabled
+ && ((bss_desc->bcn_rsn_ie) && ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.
+ element_id == WLAN_EID_RSN))
+ /*
+ * Privacy bit may NOT be set in some APs like
+ * LinkSys WRT54G && bss_desc->privacy
+ */
+ ) {
+ dev_dbg(priv->adapter->dev, "info: %s: WPA2: index=%d"
+ " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s "
+ "EncMode=%#x privacy=%#x\n", __func__, index,
+ (bss_desc->bcn_wpa_ie) ?
+ (*(bss_desc->bcn_wpa_ie)).
+ vend_hdr.element_id : 0,
+ (bss_desc->bcn_rsn_ie) ?
+ (*(bss_desc->bcn_rsn_ie)).
+ ieee_hdr.element_id : 0,
+ (priv->sec_info.wep_status ==
+ MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d",
+ (priv->sec_info.wpa_enabled) ? "e" : "d",
+ (priv->sec_info.wpa2_enabled) ? "e" : "d",
+ priv->sec_info.encryption_mode,
+ bss_desc->privacy);
+ return true;
+ }
+ return false;
+}
+
+/*
+ * This function checks if adhoc AES is enabled in driver and scanned network is
+ * compatible with it.
+ */
+static bool
+mwifiex_is_network_compatible_for_adhoc_aes(struct mwifiex_private *priv,
+ struct mwifiex_bssdescriptor *bss_desc)
+{
+ if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
+ && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
+ && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr.
+ element_id != WLAN_EID_WPA))
+ && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.
+ element_id != WLAN_EID_RSN))
+ && !priv->sec_info.encryption_mode
+ && bss_desc->privacy) {
+ return true;
+ }
+ return false;
+}
+
+/*
+ * This function checks if dynamic WEP is enabled in driver and scanned network
+ * is compatible with it.
+ */
+static bool
+mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv,
+ struct mwifiex_bssdescriptor *bss_desc,
+ int index)
+{
+ if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED
+ && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled
+ && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr.
+ element_id != WLAN_EID_WPA))
+ && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.
+ element_id != WLAN_EID_RSN))
+ && priv->sec_info.encryption_mode
+ && bss_desc->privacy) {
+ dev_dbg(priv->adapter->dev, "info: %s: dynamic "
+ "WEP: index=%d wpa_ie=%#x wpa2_ie=%#x "
+ "EncMode=%#x privacy=%#x\n",
+ __func__, index,
+ (bss_desc->bcn_wpa_ie) ?
+ (*(bss_desc->bcn_wpa_ie)).
+ vend_hdr.element_id : 0,
+ (bss_desc->bcn_rsn_ie) ?
+ (*(bss_desc->bcn_rsn_ie)).
+ ieee_hdr.element_id : 0,
+ priv->sec_info.encryption_mode,
+ bss_desc->privacy);
+ return true;
+ }
+ return false;
+}
+
+/*
+ * This function checks if a scanned network is 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
+ * 0 1 0 0 x 1x 1 x yes WPA (disable
+ * HT if no AES)
+ * 0 0 1 0 x 1x x 1 yes WPA2 (disable
+ * HT if no AES)
+ * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES
+ * 1 0 0 0 NONE 1 0 0 yes Static WEP
+ * (disable HT)
+ * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP
+ *
+ * Compatibility is not matched while roaming, except for mode.
+ */
+static s32
+mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_bssdescriptor *bss_desc;
+
+ bss_desc = &adapter->scan_table[index];
+ bss_desc->disable_11n = false;
+
+ /* Don't check for compatibility if roaming */
+ if (priv->media_connected && (priv->bss_mode == NL80211_IFTYPE_STATION)
+ && (bss_desc->bss_mode == NL80211_IFTYPE_STATION))
+ return index;
+
+ if (priv->wps.session_enable) {
+ dev_dbg(adapter->dev,
+ "info: return success directly in WPS period\n");
+ return index;
+ }
+
+ if (mwifiex_is_network_compatible_for_wapi(priv, bss_desc)) {
+ dev_dbg(adapter->dev, "info: return success for WAPI AP\n");
+ return index;
+ }
+
+ if (bss_desc->bss_mode == mode) {
+ if (mwifiex_is_network_compatible_for_no_sec(priv, bss_desc)) {
+ /* No security */
+ return index;
+ } else if (mwifiex_is_network_compatible_for_static_wep(priv,
+ bss_desc)) {
+ /* Static WEP enabled */
+ dev_dbg(adapter->dev, "info: Disable 11n in WEP mode.\n");
+ bss_desc->disable_11n = true;
+ return index;
+ } else if (mwifiex_is_network_compatible_for_wpa(priv, bss_desc,
+ index)) {
+ /* WPA enabled */
+ if (((priv->adapter->config_bands & BAND_GN
+ || priv->adapter->config_bands & BAND_AN)
+ && bss_desc->bcn_ht_cap)
+ && !mwifiex_is_wpa_oui_present(bss_desc,
+ CIPHER_SUITE_CCMP)) {
+
+ if (mwifiex_is_wpa_oui_present(bss_desc,
+ CIPHER_SUITE_TKIP)) {
+ dev_dbg(adapter->dev,
+ "info: Disable 11n if AES "
+ "is not supported by AP\n");
+ bss_desc->disable_11n = true;
+ } else {
+ return -1;
+ }
+ }
+ return index;
+ } else if (mwifiex_is_network_compatible_for_wpa2(priv,
+ bss_desc, index)) {
+ /* WPA2 enabled */
+ if (((priv->adapter->config_bands & BAND_GN
+ || priv->adapter->config_bands & BAND_AN)
+ && bss_desc->bcn_ht_cap)
+ && !mwifiex_is_rsn_oui_present(bss_desc,
+ CIPHER_SUITE_CCMP)) {
+
+ if (mwifiex_is_rsn_oui_present(bss_desc,
+ CIPHER_SUITE_TKIP)) {
+ dev_dbg(adapter->dev,
+ "info: Disable 11n if AES "
+ "is not supported by AP\n");
+ bss_desc->disable_11n = true;
+ } else {
+ return -1;
+ }
+ }
+ return index;
+ } else if (mwifiex_is_network_compatible_for_adhoc_aes(priv,
+ bss_desc)) {
+ /* Ad-hoc AES enabled */
+ return index;
+ } else if (mwifiex_is_network_compatible_for_dynamic_wep(priv,
+ bss_desc, index)) {
+ /* Dynamic WEP enabled */
+ return index;
+ }
+
+ /* Security doesn't match */
+ dev_dbg(adapter->dev, "info: %s: failed: index=%d "
+ "wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode"
+ "=%#x privacy=%#x\n",
+ __func__, index,
+ (bss_desc->bcn_wpa_ie) ?
+ (*(bss_desc->bcn_wpa_ie)).vend_hdr.
+ element_id : 0,
+ (bss_desc->bcn_rsn_ie) ?
+ (*(bss_desc->bcn_rsn_ie)).ieee_hdr.
+ element_id : 0,
+ (priv->sec_info.wep_status ==
+ MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d",
+ (priv->sec_info.wpa_enabled) ? "e" : "d",
+ (priv->sec_info.wpa2_enabled) ? "e" : "d",
+ priv->sec_info.encryption_mode, bss_desc->privacy);
+ return -1;
+ }
+
+ /* Mode doesn't match */
+ return -1;
+}
+
+/*
+ * This function finds the best SSID in the scan list.
+ *
+ * It searches the scan table for the best SSID that also matches the current
+ * adapter network preference (mode, security etc.).
+ */
+static s32
+mwifiex_find_best_network_in_list(struct mwifiex_private *priv)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ u32 mode = priv->bss_mode;
+ s32 best_net = -1;
+ s32 best_rssi = 0;
+ u32 i;
+
+ dev_dbg(adapter->dev, "info: num of BSSIDs = %d\n",
+ adapter->num_in_scan_table);
+
+ for (i = 0; i < adapter->num_in_scan_table; i++) {
+ switch (mode) {
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ if (mwifiex_is_network_compatible(priv, i, mode) >= 0) {
+ if (SCAN_RSSI(adapter->scan_table[i].rssi) >
+ best_rssi) {
+ best_rssi = SCAN_RSSI(adapter->
+ scan_table[i].rssi);
+ best_net = i;
+ }
+ }
+ break;
+ case NL80211_IFTYPE_UNSPECIFIED:
+ default:
+ if (SCAN_RSSI(adapter->scan_table[i].rssi) >
+ best_rssi) {
+ best_rssi = SCAN_RSSI(adapter->scan_table[i].
+ rssi);
+ best_net = i;
+ }
+ break;
+ }
+ }
+
+ return best_net;
+}
+
+/*
+ * This function creates a channel list for the driver to scan, based
+ * on region/band information.
+ *
+ * This routine is used for any scan that is not provided with a
+ * specific channel list to scan.
+ */
+static void
+mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
+ const struct mwifiex_user_scan_cfg
+ *user_scan_in,
+ struct mwifiex_chan_scan_param_set
+ *scan_chan_list,
+ u8 filtered_scan)
+{
+ enum ieee80211_band band;
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_channel *ch;
+ struct mwifiex_adapter *adapter = priv->adapter;
+ int chan_idx = 0, i;
+ u8 scan_type;
+
+ for (band = 0; (band < IEEE80211_NUM_BANDS) ; band++) {
+
+ if (!priv->wdev->wiphy->bands[band])
+ continue;
+
+ sband = priv->wdev->wiphy->bands[band];
+
+ for (i = 0; (i < sband->n_channels) ; i++, chan_idx++) {
+ ch = &sband->channels[i];
+ if (ch->flags & IEEE80211_CHAN_DISABLED)
+ continue;
+ scan_chan_list[chan_idx].radio_type = band;
+ scan_type = ch->flags & IEEE80211_CHAN_PASSIVE_SCAN;
+ if (user_scan_in &&
+ user_scan_in->chan_list[0].scan_time)
+ scan_chan_list[chan_idx].max_scan_time =
+ cpu_to_le16((u16) user_scan_in->
+ chan_list[0].scan_time);
+ else if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
+ scan_chan_list[chan_idx].max_scan_time =
+ cpu_to_le16(adapter->passive_scan_time);
+ else
+ scan_chan_list[chan_idx].max_scan_time =
+ cpu_to_le16(adapter->active_scan_time);
+ if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
+ scan_chan_list[chan_idx].chan_scan_mode_bitmap
+ |= MWIFIEX_PASSIVE_SCAN;
+ else
+ scan_chan_list[chan_idx].chan_scan_mode_bitmap
+ &= ~MWIFIEX_PASSIVE_SCAN;
+ scan_chan_list[chan_idx].chan_number =
+ (u32) ch->hw_value;
+ if (filtered_scan) {
+ scan_chan_list[chan_idx].max_scan_time =
+ cpu_to_le16(adapter->specific_scan_time);
+ scan_chan_list[chan_idx].chan_scan_mode_bitmap
+ |= MWIFIEX_DISABLE_CHAN_FILT;
+ }
+ }
+
+ }
+}
+
+/*
+ * This function constructs and sends multiple scan config commands to
+ * the firmware.
+ *
+ * Previous routines in the code flow have created a scan command configuration
+ * with any requested TLVs. This function splits the channel TLV into maximum
+ * channels supported per scan lists and sends the portion of the channel TLV,
+ * along with the other TLVs, to the firmware.
+ */
+static int
+mwifiex_scan_channel_list(struct mwifiex_private *priv,
+ u32 max_chan_per_scan, u8 filtered_scan,
+ struct mwifiex_scan_cmd_config *scan_cfg_out,
+ struct mwifiex_ie_types_chan_list_param_set
+ *chan_tlv_out,
+ struct mwifiex_chan_scan_param_set *scan_chan_list)
+{
+ int ret = 0;
+ struct mwifiex_chan_scan_param_set *tmp_chan_list;
+ struct mwifiex_chan_scan_param_set *start_chan;
+
+ u32 tlv_idx;
+ u32 total_scan_time;
+ u32 done_early;
+
+ if (!scan_cfg_out || !chan_tlv_out || !scan_chan_list) {
+ dev_dbg(priv->adapter->dev,
+ "info: Scan: Null detect: %p, %p, %p\n",
+ scan_cfg_out, chan_tlv_out, scan_chan_list);
+ return -1;
+ }
+
+ chan_tlv_out->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
+
+ /* Set the temp channel struct pointer to the start of the desired
+ list */
+ tmp_chan_list = scan_chan_list;
+
+ /* Loop through the desired channel list, sending a new firmware scan
+ commands for each max_chan_per_scan channels (or for 1,6,11
+ individually if configured accordingly) */
+ while (tmp_chan_list->chan_number) {
+
+ tlv_idx = 0;
+ total_scan_time = 0;
+ chan_tlv_out->header.len = 0;
+ start_chan = tmp_chan_list;
+ done_early = false;
+
+ /*
+ * Construct the Channel TLV for the scan command. Continue to
+ * insert channel TLVs until:
+ * - the tlv_idx hits the maximum configured per scan command
+ * - the next channel to insert is 0 (end of desired channel
+ * list)
+ * - done_early is set (controlling individual scanning of
+ * 1,6,11)
+ */
+ while (tlv_idx < max_chan_per_scan
+ && tmp_chan_list->chan_number && !done_early) {
+
+ dev_dbg(priv->adapter->dev,
+ "info: Scan: Chan(%3d), Radio(%d),"
+ " Mode(%d, %d), Dur(%d)\n",
+ tmp_chan_list->chan_number,
+ tmp_chan_list->radio_type,
+ tmp_chan_list->chan_scan_mode_bitmap
+ & MWIFIEX_PASSIVE_SCAN,
+ (tmp_chan_list->chan_scan_mode_bitmap
+ & MWIFIEX_DISABLE_CHAN_FILT) >> 1,
+ le16_to_cpu(tmp_chan_list->max_scan_time));
+
+ /* Copy the current channel TLV to the command being
+ prepared */
+ memcpy(chan_tlv_out->chan_scan_param + tlv_idx,
+ tmp_chan_list,
+ sizeof(chan_tlv_out->chan_scan_param));
+
+ /* Increment the TLV header length by the size
+ appended */
+ chan_tlv_out->header.len =
+ cpu_to_le16(le16_to_cpu(chan_tlv_out->header.len) +
+ (sizeof(chan_tlv_out->chan_scan_param)));
+
+ /*
+ * The tlv buffer length is set to the number of bytes
+ * of the between the channel tlv pointer and the start
+ * of the tlv buffer. This compensates for any TLVs
+ * that were appended before the channel list.
+ */
+ scan_cfg_out->tlv_buf_len = (u32) ((u8 *) chan_tlv_out -
+ scan_cfg_out->tlv_buf);
+
+ /* Add the size of the channel tlv header and the data
+ length */
+ scan_cfg_out->tlv_buf_len +=
+ (sizeof(chan_tlv_out->header)
+ + le16_to_cpu(chan_tlv_out->header.len));
+
+ /* Increment the index to the channel tlv we are
+ constructing */
+ tlv_idx++;
+
+ /* Count the total scan time per command */
+ total_scan_time +=
+ le16_to_cpu(tmp_chan_list->max_scan_time);
+
+ done_early = false;
+
+ /* Stop the loop if the *current* channel is in the
+ 1,6,11 set and we are not filtering on a BSSID
+ or SSID. */
+ if (!filtered_scan && (tmp_chan_list->chan_number == 1
+ || tmp_chan_list->chan_number == 6
+ || tmp_chan_list->chan_number == 11))
+ done_early = true;
+
+ /* Increment the tmp pointer to the next channel to
+ be scanned */
+ tmp_chan_list++;
+
+ /* Stop the loop if the *next* channel is in the 1,6,11
+ set. This will cause it to be the only channel
+ scanned on the next interation */
+ if (!filtered_scan && (tmp_chan_list->chan_number == 1
+ || tmp_chan_list->chan_number == 6
+ || tmp_chan_list->chan_number == 11))
+ done_early = true;
+ }
+
+ /* The total scan time should be less than scan command timeout
+ value */
+ if (total_scan_time > MWIFIEX_MAX_TOTAL_SCAN_TIME) {
+ dev_err(priv->adapter->dev, "total scan time %dms"
+ " is over limit (%dms), scan skipped\n",
+ total_scan_time, MWIFIEX_MAX_TOTAL_SCAN_TIME);
+ ret = -1;
+ break;
+ }
+
+ priv->adapter->scan_channels = start_chan;
+
+ /* Send the scan command to the firmware with the specified
+ cfg */
+ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SCAN,
+ HostCmd_ACT_GEN_SET, 0,
+ scan_cfg_out);
+ if (ret)
+ break;
+ }
+
+ if (ret)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * This function constructs a scan command configuration structure to use
+ * in scan commands.
+ *
+ * Application layer or other functions can invoke network scanning
+ * with a scan configuration supplied in a user scan configuration structure.
+ * This structure is used as the basis of one or many scan command configuration
+ * commands that are sent to the command processing module and eventually to the
+ * firmware.
+ *
+ * This function creates a scan command configuration structure based on the
+ * following user supplied parameters (if present):
+ * - SSID filter
+ * - BSSID filter
+ * - Number of Probes to be sent
+ * - Channel list
+ *
+ * If the SSID or BSSID filter is not present, the filter is disabled/cleared.
+ * If the number of probes is not set, adapter default setting is used.
+ */
+static void
+mwifiex_scan_setup_scan_config(struct mwifiex_private *priv,
+ const struct mwifiex_user_scan_cfg *user_scan_in,
+ struct mwifiex_scan_cmd_config *scan_cfg_out,
+ struct mwifiex_ie_types_chan_list_param_set
+ **chan_list_out,
+ struct mwifiex_chan_scan_param_set
+ *scan_chan_list,
+ u8 *max_chan_per_scan, u8 *filtered_scan,
+ u8 *scan_current_only)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_ie_types_num_probes *num_probes_tlv;
+ struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv;
+ struct mwifiex_ie_types_rates_param_set *rates_tlv;
+ const u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+ u8 *tlv_pos;
+ u32 num_probes;
+ u32 ssid_len;
+ u32 chan_idx;
+ u32 scan_type;
+ u16 scan_dur;
+ u8 channel;
+ u8 radio_type;
+ u32 ssid_idx;
+ u8 ssid_filter;
+ u8 rates[MWIFIEX_SUPPORTED_RATES];
+ u32 rates_size;
+ struct mwifiex_ie_types_htcap *ht_cap;
+
+ /* The tlv_buf_len is calculated for each scan command. The TLVs added
+ in this routine will be preserved since the routine that sends the
+ command will append channelTLVs at *chan_list_out. The difference
+ between the *chan_list_out and the tlv_buf start will be used to
+ calculate the size of anything we add in this routine. */
+ scan_cfg_out->tlv_buf_len = 0;
+
+ /* Running tlv pointer. Assigned to chan_list_out at end of function
+ so later routines know where channels can be added to the command
+ buf */
+ tlv_pos = scan_cfg_out->tlv_buf;
+
+ /* Initialize the scan as un-filtered; the flag is later set to TRUE
+ below if a SSID or BSSID filter is sent in the command */
+ *filtered_scan = false;
+
+ /* Initialize the scan as not being only on the current channel. If
+ the channel list is customized, only contains one channel, and is
+ the active channel, this is set true and data flow is not halted. */
+ *scan_current_only = false;
+
+ if (user_scan_in) {
+
+ /* Default the ssid_filter flag to TRUE, set false under
+ certain wildcard conditions and qualified by the existence
+ of an SSID list before marking the scan as filtered */
+ ssid_filter = true;
+
+ /* Set the BSS type scan filter, use Adapter setting if
+ unset */
+ scan_cfg_out->bss_mode =
+ (user_scan_in->bss_mode ? (u8) user_scan_in->
+ bss_mode : (u8) adapter->scan_mode);
+
+ /* Set the number of probes to send, use Adapter setting
+ if unset */
+ num_probes =
+ (user_scan_in->num_probes ? user_scan_in->
+ num_probes : adapter->scan_probes);
+
+ /*
+ * Set the BSSID filter to the incoming configuration,
+ * if non-zero. If not set, it will remain disabled
+ * (all zeros).
+ */
+ memcpy(scan_cfg_out->specific_bssid,
+ user_scan_in->specific_bssid,
+ sizeof(scan_cfg_out->specific_bssid));
+
+ for (ssid_idx = 0;
+ ((ssid_idx < ARRAY_SIZE(user_scan_in->ssid_list))
+ && (*user_scan_in->ssid_list[ssid_idx].ssid
+ || user_scan_in->ssid_list[ssid_idx].max_len));
+ ssid_idx++) {
+
+ ssid_len = strlen(user_scan_in->ssid_list[ssid_idx].
+ ssid) + 1;
+
+ wildcard_ssid_tlv =
+ (struct mwifiex_ie_types_wildcard_ssid_params *)
+ tlv_pos;
+ wildcard_ssid_tlv->header.type =
+ cpu_to_le16(TLV_TYPE_WILDCARDSSID);
+ wildcard_ssid_tlv->header.len = cpu_to_le16(
+ (u16) (ssid_len + sizeof(wildcard_ssid_tlv->
+ max_ssid_length)));
+ wildcard_ssid_tlv->max_ssid_length =
+ user_scan_in->ssid_list[ssid_idx].max_len;
+
+ memcpy(wildcard_ssid_tlv->ssid,
+ user_scan_in->ssid_list[ssid_idx].ssid,
+ ssid_len);
+
+ tlv_pos += (sizeof(wildcard_ssid_tlv->header)
+ + le16_to_cpu(wildcard_ssid_tlv->header.len));
+
+ dev_dbg(adapter->dev, "info: scan: ssid_list[%d]: %s, %d\n",
+ ssid_idx, wildcard_ssid_tlv->ssid,
+ wildcard_ssid_tlv->max_ssid_length);
+
+ /* Empty wildcard ssid with a maxlen will match many or
+ potentially all SSIDs (maxlen == 32), therefore do
+ not treat the scan as
+ filtered. */
+ if (!ssid_len && wildcard_ssid_tlv->max_ssid_length)
+ ssid_filter = false;
+
+ }
+
+ /*
+ * The default number of channels sent in the command is low to
+ * ensure the response buffer from the firmware does not
+ * truncate scan results. That is not an issue with an SSID
+ * or BSSID filter applied to the scan results in the firmware.
+ */
+ if ((ssid_idx && ssid_filter)
+ || memcmp(scan_cfg_out->specific_bssid, &zero_mac,
+ sizeof(zero_mac)))
+ *filtered_scan = true;
+ } else {
+ scan_cfg_out->bss_mode = (u8) adapter->scan_mode;
+ num_probes = adapter->scan_probes;
+ }
+
+ /*
+ * If a specific BSSID or SSID is used, the number of channels in the
+ * scan command will be increased to the absolute maximum.
+ */
+ if (*filtered_scan)
+ *max_chan_per_scan = MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN;
+ else
+ *max_chan_per_scan = MWIFIEX_CHANNELS_PER_SCAN_CMD;
+
+ /* If the input config or adapter has the number of Probes set,
+ add tlv */
+ if (num_probes) {
+
+ dev_dbg(adapter->dev, "info: scan: num_probes = %d\n",
+ num_probes);
+
+ num_probes_tlv = (struct mwifiex_ie_types_num_probes *) tlv_pos;
+ num_probes_tlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES);
+ num_probes_tlv->header.len =
+ cpu_to_le16(sizeof(num_probes_tlv->num_probes));
+ num_probes_tlv->num_probes = cpu_to_le16((u16) num_probes);
+
+ tlv_pos += sizeof(num_probes_tlv->header) +
+ le16_to_cpu(num_probes_tlv->header.len);
+
+ }
+
+ /* Append rates tlv */
+ memset(rates, 0, sizeof(rates));
+
+ rates_size = mwifiex_get_supported_rates(priv, rates);
+
+ rates_tlv = (struct mwifiex_ie_types_rates_param_set *) tlv_pos;
+ rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES);
+ rates_tlv->header.len = cpu_to_le16((u16) rates_size);
+ memcpy(rates_tlv->rates, rates, rates_size);
+ tlv_pos += sizeof(rates_tlv->header) + rates_size;
+
+ dev_dbg(adapter->dev, "info: SCAN_CMD: Rates size = %d\n", rates_size);
+
+ if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info)
+ && (priv->adapter->config_bands & BAND_GN
+ || priv->adapter->config_bands & BAND_AN)) {
+ ht_cap = (struct mwifiex_ie_types_htcap *) tlv_pos;
+ memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap));
+ ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY);
+ ht_cap->header.len =
+ cpu_to_le16(sizeof(struct ieee80211_ht_cap));
+ radio_type =
+ mwifiex_band_to_radio_type(priv->adapter->config_bands);
+ mwifiex_fill_cap_info(priv, radio_type, ht_cap);
+ tlv_pos += sizeof(struct mwifiex_ie_types_htcap);
+ }
+
+ /* Append vendor specific IE TLV */
+ mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_SCAN, &tlv_pos);
+
+ /*
+ * Set the output for the channel TLV to the address in the tlv buffer
+ * past any TLVs that were added in this function (SSID, num_probes).
+ * Channel TLVs will be added past this for each scan command,
+ * preserving the TLVs that were previously added.
+ */
+ *chan_list_out =
+ (struct mwifiex_ie_types_chan_list_param_set *) tlv_pos;
+
+ if (user_scan_in && user_scan_in->chan_list[0].chan_number) {
+
+ dev_dbg(adapter->dev, "info: Scan: Using supplied channel list\n");
+
+ for (chan_idx = 0;
+ chan_idx < MWIFIEX_USER_SCAN_CHAN_MAX
+ && user_scan_in->chan_list[chan_idx].chan_number;
+ chan_idx++) {
+
+ channel = user_scan_in->chan_list[chan_idx].chan_number;
+ (scan_chan_list + chan_idx)->chan_number = channel;
+
+ radio_type =
+ user_scan_in->chan_list[chan_idx].radio_type;
+ (scan_chan_list + chan_idx)->radio_type = radio_type;
+
+ scan_type = user_scan_in->chan_list[chan_idx].scan_type;
+
+ if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
+ (scan_chan_list +
+ chan_idx)->chan_scan_mode_bitmap
+ |= MWIFIEX_PASSIVE_SCAN;
+ else
+ (scan_chan_list +
+ chan_idx)->chan_scan_mode_bitmap
+ &= ~MWIFIEX_PASSIVE_SCAN;
+
+ if (user_scan_in->chan_list[chan_idx].scan_time) {
+ scan_dur = (u16) user_scan_in->
+ chan_list[chan_idx].scan_time;
+ } else {
+ if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
+ scan_dur = adapter->passive_scan_time;
+ else if (*filtered_scan)
+ scan_dur = adapter->specific_scan_time;
+ else
+ scan_dur = adapter->active_scan_time;
+ }
+
+ (scan_chan_list + chan_idx)->min_scan_time =
+ cpu_to_le16(scan_dur);
+ (scan_chan_list + chan_idx)->max_scan_time =
+ cpu_to_le16(scan_dur);
+ }
+
+ /* Check if we are only scanning the current channel */
+ if ((chan_idx == 1)
+ && (user_scan_in->chan_list[0].chan_number
+ == priv->curr_bss_params.bss_descriptor.channel)) {
+ *scan_current_only = true;
+ dev_dbg(adapter->dev,
+ "info: Scan: Scanning current channel only\n");
+ }
+
+ } else {
+ dev_dbg(adapter->dev,
+ "info: Scan: Creating full region channel list\n");
+ mwifiex_scan_create_channel_list(priv, user_scan_in,
+ scan_chan_list,
+ *filtered_scan);
+ }
+}
+
+/*
+ * This function inspects the scan response buffer for pointers to
+ * expected TLVs.
+ *
+ * TLVs can be included at the end of the scan response BSS information.
+ *
+ * Data in the buffer is parsed pointers to TLVs that can potentially
+ * be passed back in the response.
+ */
+static void
+mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter,
+ struct mwifiex_ie_types_data *tlv,
+ u32 tlv_buf_size, u32 req_tlv_type,
+ struct mwifiex_ie_types_data **tlv_data)
+{
+ struct mwifiex_ie_types_data *current_tlv;
+ u32 tlv_buf_left;
+ u32 tlv_type;
+ u32 tlv_len;
+
+ current_tlv = tlv;
+ tlv_buf_left = tlv_buf_size;
+ *tlv_data = NULL;
+
+ dev_dbg(adapter->dev, "info: SCAN_RESP: tlv_buf_size = %d\n",
+ tlv_buf_size);
+
+ while (tlv_buf_left >= sizeof(struct mwifiex_ie_types_header)) {
+
+ tlv_type = le16_to_cpu(current_tlv->header.type);
+ tlv_len = le16_to_cpu(current_tlv->header.len);
+
+ if (sizeof(tlv->header) + tlv_len > tlv_buf_left) {
+ dev_err(adapter->dev, "SCAN_RESP: TLV buffer corrupt\n");
+ break;
+ }
+
+ if (req_tlv_type == tlv_type) {
+ switch (tlv_type) {
+ case TLV_TYPE_TSFTIMESTAMP:
+ dev_dbg(adapter->dev, "info: SCAN_RESP: TSF "
+ "timestamp TLV, len = %d\n", tlv_len);
+ *tlv_data = (struct mwifiex_ie_types_data *)
+ current_tlv;
+ break;
+ case TLV_TYPE_CHANNELBANDLIST:
+ dev_dbg(adapter->dev, "info: SCAN_RESP: channel"
+ " band list TLV, len = %d\n", tlv_len);
+ *tlv_data = (struct mwifiex_ie_types_data *)
+ current_tlv;
+ break;
+ default:
+ dev_err(adapter->dev,
+ "SCAN_RESP: unhandled TLV = %d\n",
+ tlv_type);
+ /* Give up, this seems corrupted */
+ return;
+ }
+ }
+
+ if (*tlv_data)
+ break;
+
+
+ tlv_buf_left -= (sizeof(tlv->header) + tlv_len);
+ current_tlv =
+ (struct mwifiex_ie_types_data *) (current_tlv->data +
+ tlv_len);
+
+ } /* while */
+}
+
+/*
+ * This function interprets a BSS scan response returned from the firmware.
+ *
+ * The various fixed fields and IEs are parsed and passed back for a BSS
+ * probe response or beacon from scan command. Information is recorded as
+ * needed in the scan table for that entry.
+ *
+ * The following IE types are recognized and parsed -
+ * - SSID
+ * - Supported rates
+ * - FH parameters set
+ * - DS parameters set
+ * - CF parameters set
+ * - IBSS parameters set
+ * - ERP information
+ * - Extended supported rates
+ * - Vendor specific (221)
+ * - RSN IE
+ * - WAPI IE
+ * - HT capability
+ * - HT operation
+ * - BSS Coexistence 20/40
+ * - Extended capability
+ * - Overlapping BSS scan parameters
+ */
+static int
+mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter,
+ struct mwifiex_bssdescriptor *bss_entry,
+ u8 **beacon_info, u32 *bytes_left)
+{
+ int ret = 0;
+ u8 element_id;
+ struct ieee_types_fh_param_set *fh_param_set;
+ struct ieee_types_ds_param_set *ds_param_set;
+ struct ieee_types_cf_param_set *cf_param_set;
+ struct ieee_types_ibss_param_set *ibss_param_set;
+ __le16 beacon_interval;
+ __le16 capabilities;
+ u8 *current_ptr;
+ u8 *rate;
+ u8 element_len;
+ u16 total_ie_len;
+ u8 bytes_to_copy;
+ u8 rate_size;
+ u16 beacon_size;
+ u8 found_data_rate_ie;
+ u32 bytes_left_for_current_beacon;
+ struct ieee_types_vendor_specific *vendor_ie;
+ const u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 };
+ const u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 };
+
+ found_data_rate_ie = false;
+ rate_size = 0;
+ beacon_size = 0;
+
+ if (*bytes_left >= sizeof(beacon_size)) {
+ /* Extract & convert beacon size from the command buffer */
+ memcpy(&beacon_size, *beacon_info, sizeof(beacon_size));
+ *bytes_left -= sizeof(beacon_size);
+ *beacon_info += sizeof(beacon_size);
+ }
+
+ if (!beacon_size || beacon_size > *bytes_left) {
+ *beacon_info += *bytes_left;
+ *bytes_left = 0;
+ return -1;
+ }
+
+ /* Initialize the current working beacon pointer for this BSS
+ iteration */
+ current_ptr = *beacon_info;
+
+ /* Advance the return beacon pointer past the current beacon */
+ *beacon_info += beacon_size;
+ *bytes_left -= beacon_size;
+
+ bytes_left_for_current_beacon = beacon_size;
+
+ memcpy(bss_entry->mac_address, current_ptr, ETH_ALEN);
+ dev_dbg(adapter->dev, "info: InterpretIE: AP MAC Addr: %pM\n",
+ bss_entry->mac_address);
+
+ current_ptr += ETH_ALEN;
+ bytes_left_for_current_beacon -= ETH_ALEN;
+
+ if (bytes_left_for_current_beacon < 12) {
+ dev_err(adapter->dev, "InterpretIE: not enough bytes left\n");
+ return -1;
+ }
+
+ /*
+ * Next 4 fields are RSSI, time stamp, beacon interval,
+ * and capability information
+ */
+
+ /* RSSI is 1 byte long */
+ bss_entry->rssi = (s32) (*current_ptr);
+ dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%02X\n", *current_ptr);
+ current_ptr += 1;
+ bytes_left_for_current_beacon -= 1;
+
+ /*
+ * The RSSI is not part of the beacon/probe response. After we have
+ * advanced current_ptr past the RSSI field, save the remaining
+ * data for use at the application layer
+ */
+ bss_entry->beacon_buf = current_ptr;
+ bss_entry->beacon_buf_size = bytes_left_for_current_beacon;
+
+ /* Time stamp is 8 bytes long */
+ memcpy(bss_entry->time_stamp, current_ptr, 8);
+ current_ptr += 8;
+ bytes_left_for_current_beacon -= 8;
+
+ /* Beacon interval is 2 bytes long */
+ memcpy(&beacon_interval, current_ptr, 2);
+ bss_entry->beacon_period = le16_to_cpu(beacon_interval);
+ current_ptr += 2;
+ bytes_left_for_current_beacon -= 2;
+
+ /* Capability information is 2 bytes long */
+ memcpy(&capabilities, current_ptr, 2);
+ dev_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n",
+ capabilities);
+ bss_entry->cap_info_bitmap = le16_to_cpu(capabilities);
+ current_ptr += 2;
+ bytes_left_for_current_beacon -= 2;
+
+ /* Rest of the current buffer are IE's */
+ dev_dbg(adapter->dev, "info: InterpretIE: IELength for this AP = %d\n",
+ bytes_left_for_current_beacon);
+
+ if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) {
+ dev_dbg(adapter->dev, "info: InterpretIE: AP WEP enabled\n");
+ bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
+ } else {
+ bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL;
+ }
+
+ if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_IBSS)
+ bss_entry->bss_mode = NL80211_IFTYPE_ADHOC;
+ else
+ bss_entry->bss_mode = NL80211_IFTYPE_STATION;
+
+
+ /* Process variable IE */
+ while (bytes_left_for_current_beacon >= 2) {
+ element_id = *current_ptr;
+ element_len = *(current_ptr + 1);
+ total_ie_len = element_len + sizeof(struct ieee_types_header);
+
+ if (bytes_left_for_current_beacon < total_ie_len) {
+ dev_err(adapter->dev, "err: InterpretIE: in processing"
+ " IE, bytes left < IE length\n");
+ bytes_left_for_current_beacon = 0;
+ ret = -1;
+ continue;
+ }
+ switch (element_id) {
+ case WLAN_EID_SSID:
+ bss_entry->ssid.ssid_len = element_len;
+ memcpy(bss_entry->ssid.ssid, (current_ptr + 2),
+ element_len);
+ dev_dbg(adapter->dev, "info: InterpretIE: ssid: %-32s\n",
+ bss_entry->ssid.ssid);
+ break;
+
+ case WLAN_EID_SUPP_RATES:
+ memcpy(bss_entry->data_rates, current_ptr + 2,
+ element_len);
+ memcpy(bss_entry->supported_rates, current_ptr + 2,
+ element_len);
+ rate_size = element_len;
+ found_data_rate_ie = true;
+ break;
+
+ case WLAN_EID_FH_PARAMS:
+ fh_param_set =
+ (struct ieee_types_fh_param_set *) current_ptr;
+ memcpy(&bss_entry->phy_param_set.fh_param_set,
+ fh_param_set,
+ sizeof(struct ieee_types_fh_param_set));
+ break;
+
+ case WLAN_EID_DS_PARAMS:
+ ds_param_set =
+ (struct ieee_types_ds_param_set *) current_ptr;
+
+ bss_entry->channel = ds_param_set->current_chan;
+
+ memcpy(&bss_entry->phy_param_set.ds_param_set,
+ ds_param_set,
+ sizeof(struct ieee_types_ds_param_set));
+ break;
+
+ case WLAN_EID_CF_PARAMS:
+ cf_param_set =
+ (struct ieee_types_cf_param_set *) current_ptr;
+ memcpy(&bss_entry->ss_param_set.cf_param_set,
+ cf_param_set,
+ sizeof(struct ieee_types_cf_param_set));
+ break;
+
+ case WLAN_EID_IBSS_PARAMS:
+ ibss_param_set =
+ (struct ieee_types_ibss_param_set *)
+ current_ptr;
+ memcpy(&bss_entry->ss_param_set.ibss_param_set,
+ ibss_param_set,
+ sizeof(struct ieee_types_ibss_param_set));
+ break;
+
+ case WLAN_EID_ERP_INFO:
+ bss_entry->erp_flags = *(current_ptr + 2);
+ 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
+ */
+ if (found_data_rate_ie) {
+ if ((element_len + rate_size) >
+ MWIFIEX_SUPPORTED_RATES)
+ bytes_to_copy =
+ (MWIFIEX_SUPPORTED_RATES -
+ rate_size);
+ else
+ bytes_to_copy = element_len;
+
+ rate = (u8 *) bss_entry->data_rates;
+ rate += rate_size;
+ memcpy(rate, current_ptr + 2, bytes_to_copy);
+
+ rate = (u8 *) bss_entry->supported_rates;
+ rate += rate_size;
+ memcpy(rate, current_ptr + 2, bytes_to_copy);
+ }
+ break;
+
+ case WLAN_EID_VENDOR_SPECIFIC:
+ vendor_ie = (struct ieee_types_vendor_specific *)
+ current_ptr;
+
+ if (!memcmp
+ (vendor_ie->vend_hdr.oui, wpa_oui,
+ sizeof(wpa_oui))) {
+ bss_entry->bcn_wpa_ie =
+ (struct ieee_types_vendor_specific *)
+ current_ptr;
+ bss_entry->wpa_offset = (u16) (current_ptr -
+ bss_entry->beacon_buf);
+ } else if (!memcmp(vendor_ie->vend_hdr.oui, wmm_oui,
+ sizeof(wmm_oui))) {
+ if (total_ie_len ==
+ sizeof(struct ieee_types_wmm_parameter)
+ || total_ie_len ==
+ sizeof(struct ieee_types_wmm_info))
+ /*
+ * Only accept and copy the WMM IE if
+ * it matches the size expected for the
+ * WMM Info IE or the WMM Parameter IE.
+ */
+ memcpy((u8 *) &bss_entry->wmm_ie,
+ current_ptr, total_ie_len);
+ }
+ break;
+ case WLAN_EID_RSN:
+ bss_entry->bcn_rsn_ie =
+ (struct ieee_types_generic *) current_ptr;
+ bss_entry->rsn_offset = (u16) (current_ptr -
+ bss_entry->beacon_buf);
+ break;
+ case WLAN_EID_BSS_AC_ACCESS_DELAY:
+ bss_entry->bcn_wapi_ie =
+ (struct ieee_types_generic *) current_ptr;
+ bss_entry->wapi_offset = (u16) (current_ptr -
+ bss_entry->beacon_buf);
+ break;
+ case WLAN_EID_HT_CAPABILITY:
+ bss_entry->bcn_ht_cap = (struct ieee80211_ht_cap *)
+ (current_ptr +
+ sizeof(struct ieee_types_header));
+ bss_entry->ht_cap_offset = (u16) (current_ptr +
+ sizeof(struct ieee_types_header) -
+ bss_entry->beacon_buf);
+ break;
+ case WLAN_EID_HT_INFORMATION:
+ bss_entry->bcn_ht_info = (struct ieee80211_ht_info *)
+ (current_ptr +
+ sizeof(struct ieee_types_header));
+ bss_entry->ht_info_offset = (u16) (current_ptr +
+ sizeof(struct ieee_types_header) -
+ bss_entry->beacon_buf);
+ break;
+ case WLAN_EID_BSS_COEX_2040:
+ bss_entry->bcn_bss_co_2040 = (u8 *) (current_ptr +
+ sizeof(struct ieee_types_header));
+ bss_entry->bss_co_2040_offset = (u16) (current_ptr +
+ sizeof(struct ieee_types_header) -
+ bss_entry->beacon_buf);
+ break;
+ case WLAN_EID_EXT_CAPABILITY:
+ bss_entry->bcn_ext_cap = (u8 *) (current_ptr +
+ sizeof(struct ieee_types_header));
+ bss_entry->ext_cap_offset = (u16) (current_ptr +
+ sizeof(struct ieee_types_header) -
+ bss_entry->beacon_buf);
+ break;
+ case WLAN_EID_OVERLAP_BSS_SCAN_PARAM:
+ bss_entry->bcn_obss_scan =
+ (struct ieee_types_obss_scan_param *)
+ current_ptr;
+ bss_entry->overlap_bss_offset = (u16) (current_ptr -
+ bss_entry->beacon_buf);
+ break;
+ default:
+ break;
+ }
+
+ current_ptr += element_len + 2;
+
+ /* Need to account for IE ID and IE Len */
+ bytes_left_for_current_beacon -= (element_len + 2);
+
+ } /* while (bytes_left_for_current_beacon > 2) */
+ return ret;
+}
+
+/*
+ * This function adjusts the pointers used in beacon buffers to reflect
+ * shifts.
+ *
+ * The memory allocated for beacon buffers is of fixed sizes where all the
+ * saved beacons must be stored. New beacons are added in the free portion
+ * of this memory, space permitting; while duplicate beacon buffers are
+ * placed at the same start location. However, since duplicate beacon
+ * buffers may not match the size of the old one, all the following buffers
+ * in the memory must be shifted to either make space, or to fill up freed
+ * up space.
+ *
+ * This function is used to update the beacon buffer pointers that are past
+ * an existing beacon buffer that is updated with a new one of different
+ * size. The pointers are shifted by a fixed amount, either forward or
+ * backward.
+ *
+ * the following pointers in every affected beacon buffers are changed, if
+ * present -
+ * - WPA IE pointer
+ * - RSN IE pointer
+ * - WAPI IE pointer
+ * - HT capability IE pointer
+ * - HT information IE pointer
+ * - BSS coexistence 20/40 IE pointer
+ * - Extended capability IE pointer
+ * - Overlapping BSS scan parameter IE pointer
+ */
+static void
+mwifiex_adjust_beacon_buffer_ptrs(struct mwifiex_private *priv, u8 advance,
+ u8 *bcn_store, u32 rem_bcn_size,
+ u32 num_of_ent)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ u32 adj_idx;
+ for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) {
+ if (adapter->scan_table[adj_idx].beacon_buf > bcn_store) {
+
+ if (advance)
+ adapter->scan_table[adj_idx].beacon_buf +=
+ rem_bcn_size;
+ else
+ adapter->scan_table[adj_idx].beacon_buf -=
+ rem_bcn_size;
+
+ if (adapter->scan_table[adj_idx].bcn_wpa_ie)
+ adapter->scan_table[adj_idx].bcn_wpa_ie =
+ (struct ieee_types_vendor_specific *)
+ (adapter->scan_table[adj_idx].beacon_buf +
+ adapter->scan_table[adj_idx].wpa_offset);
+ if (adapter->scan_table[adj_idx].bcn_rsn_ie)
+ adapter->scan_table[adj_idx].bcn_rsn_ie =
+ (struct ieee_types_generic *)
+ (adapter->scan_table[adj_idx].beacon_buf +
+ adapter->scan_table[adj_idx].rsn_offset);
+ if (adapter->scan_table[adj_idx].bcn_wapi_ie)
+ adapter->scan_table[adj_idx].bcn_wapi_ie =
+ (struct ieee_types_generic *)
+ (adapter->scan_table[adj_idx].beacon_buf +
+ adapter->scan_table[adj_idx].wapi_offset);
+ if (adapter->scan_table[adj_idx].bcn_ht_cap)
+ adapter->scan_table[adj_idx].bcn_ht_cap =
+ (struct ieee80211_ht_cap *)
+ (adapter->scan_table[adj_idx].beacon_buf +
+ adapter->scan_table[adj_idx].ht_cap_offset);
+
+ if (adapter->scan_table[adj_idx].bcn_ht_info)
+ adapter->scan_table[adj_idx].bcn_ht_info =
+ (struct ieee80211_ht_info *)
+ (adapter->scan_table[adj_idx].beacon_buf +
+ adapter->scan_table[adj_idx].ht_info_offset);
+ if (adapter->scan_table[adj_idx].bcn_bss_co_2040)
+ adapter->scan_table[adj_idx].bcn_bss_co_2040 =
+ (u8 *)
+ (adapter->scan_table[adj_idx].beacon_buf +
+ adapter->scan_table[adj_idx].bss_co_2040_offset);
+ if (adapter->scan_table[adj_idx].bcn_ext_cap)
+ adapter->scan_table[adj_idx].bcn_ext_cap =
+ (u8 *)
+ (adapter->scan_table[adj_idx].beacon_buf +
+ adapter->scan_table[adj_idx].ext_cap_offset);
+ if (adapter->scan_table[adj_idx].bcn_obss_scan)
+ adapter->scan_table[adj_idx].bcn_obss_scan =
+ (struct ieee_types_obss_scan_param *)
+ (adapter->scan_table[adj_idx].beacon_buf +
+ adapter->scan_table[adj_idx].overlap_bss_offset);
+ }
+ }
+}
+
+/*
+ * This function updates the pointers used in beacon buffer for given bss
+ * descriptor to reflect shifts
+ *
+ * Following pointers are updated
+ * - WPA IE pointer
+ * - RSN IE pointer
+ * - WAPI IE pointer
+ * - HT capability IE pointer
+ * - HT information IE pointer
+ * - BSS coexistence 20/40 IE pointer
+ * - Extended capability IE pointer
+ * - Overlapping BSS scan parameter IE pointer
+ */
+static void
+mwifiex_update_beacon_buffer_ptrs(struct mwifiex_bssdescriptor *beacon)
+{
+ if (beacon->bcn_wpa_ie)
+ beacon->bcn_wpa_ie = (struct ieee_types_vendor_specific *)
+ (beacon->beacon_buf + beacon->wpa_offset);
+ if (beacon->bcn_rsn_ie)
+ beacon->bcn_rsn_ie = (struct ieee_types_generic *)
+ (beacon->beacon_buf + beacon->rsn_offset);
+ if (beacon->bcn_wapi_ie)
+ beacon->bcn_wapi_ie = (struct ieee_types_generic *)
+ (beacon->beacon_buf + beacon->wapi_offset);
+ if (beacon->bcn_ht_cap)
+ beacon->bcn_ht_cap = (struct ieee80211_ht_cap *)
+ (beacon->beacon_buf + beacon->ht_cap_offset);
+ if (beacon->bcn_ht_info)
+ beacon->bcn_ht_info = (struct ieee80211_ht_info *)
+ (beacon->beacon_buf + beacon->ht_info_offset);
+ if (beacon->bcn_bss_co_2040)
+ beacon->bcn_bss_co_2040 = (u8 *) (beacon->beacon_buf +
+ beacon->bss_co_2040_offset);
+ if (beacon->bcn_ext_cap)
+ beacon->bcn_ext_cap = (u8 *) (beacon->beacon_buf +
+ beacon->ext_cap_offset);
+ if (beacon->bcn_obss_scan)
+ beacon->bcn_obss_scan = (struct ieee_types_obss_scan_param *)
+ (beacon->beacon_buf + beacon->overlap_bss_offset);
+}
+
+/*
+ * This function stores a beacon or probe response for a BSS returned
+ * in the scan.
+ *
+ * This stores a new scan response or an update for a previous scan response.
+ * New entries need to verify that they do not exceed the total amount of
+ * memory allocated for the table.
+ *
+ * Replacement entries need to take into consideration the amount of space
+ * currently allocated for the beacon/probe response and adjust the entry
+ * as needed.
+ *
+ * A small amount of extra pad (SCAN_BEACON_ENTRY_PAD) is generally reserved
+ * for an entry in case it is a beacon since a probe response for the
+ * network will by larger per the standard. This helps to reduce the
+ * amount of memory copying to fit a new probe response into an entry
+ * already occupied by a network's previously stored beacon.
+ */
+static void
+mwifiex_ret_802_11_scan_store_beacon(struct mwifiex_private *priv,
+ u32 beacon_idx, u32 num_of_ent,
+ struct mwifiex_bssdescriptor *new_beacon)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ u8 *bcn_store;
+ u32 new_bcn_size;
+ u32 old_bcn_size;
+ u32 bcn_space;
+
+ if (adapter->scan_table[beacon_idx].beacon_buf) {
+
+ new_bcn_size = new_beacon->beacon_buf_size;
+ old_bcn_size = adapter->scan_table[beacon_idx].beacon_buf_size;
+ bcn_space = adapter->scan_table[beacon_idx].beacon_buf_size_max;
+ bcn_store = adapter->scan_table[beacon_idx].beacon_buf;
+
+ /* Set the max to be the same as current entry unless changed
+ below */
+ new_beacon->beacon_buf_size_max = bcn_space;
+ if (new_bcn_size == old_bcn_size) {
+ /*
+ * Beacon is the same size as the previous entry.
+ * Replace the previous contents with the scan result
+ */
+ memcpy(bcn_store, new_beacon->beacon_buf,
+ new_beacon->beacon_buf_size);
+
+ } else if (new_bcn_size <= bcn_space) {
+ /*
+ * New beacon size will fit in the amount of space
+ * we have previously allocated for it
+ */
+
+ /* Copy the new beacon buffer entry over the old one */
+ memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size);
+
+ /*
+ * If the old beacon size was less than the maximum
+ * we had alloted for the entry, and the new entry
+ * is even smaller, reset the max size to the old
+ * beacon entry and compress the storage space
+ * (leaving a new pad space of (old_bcn_size -
+ * new_bcn_size).
+ */
+ if (old_bcn_size < bcn_space
+ && new_bcn_size <= old_bcn_size) {
+ /*
+ * Old Beacon size is smaller than the alloted
+ * storage size. Shrink the alloted storage
+ * space.
+ */
+ dev_dbg(adapter->dev, "info: AppControl:"
+ " smaller duplicate beacon "
+ "(%d), old = %d, new = %d, space = %d,"
+ "left = %d\n",
+ beacon_idx, old_bcn_size, new_bcn_size,
+ bcn_space,
+ (int)(sizeof(adapter->bcn_buf) -
+ (adapter->bcn_buf_end -
+ adapter->bcn_buf)));
+
+ /*
+ * memmove (since the memory overlaps) the
+ * data after the beacon we just stored to the
+ * end of the current beacon. This cleans up
+ * any unused space the old larger beacon was
+ * using in the buffer
+ */
+ memmove(bcn_store + old_bcn_size,
+ bcn_store + bcn_space,
+ adapter->bcn_buf_end - (bcn_store +
+ bcn_space));
+
+ /*
+ * Decrement the end pointer by the difference
+ * between the old larger size and the new
+ * smaller size since we are using less space
+ * due to the new beacon being smaller
+ */
+ adapter->bcn_buf_end -=
+ (bcn_space - old_bcn_size);
+
+ /* Set the maximum storage size to the old
+ beacon size */
+ new_beacon->beacon_buf_size_max = old_bcn_size;
+
+ /* Adjust beacon buffer pointers that are past
+ the current */
+ mwifiex_adjust_beacon_buffer_ptrs(priv, 0,
+ bcn_store, (bcn_space - old_bcn_size),
+ num_of_ent);
+ }
+ } else if (adapter->bcn_buf_end + (new_bcn_size - bcn_space)
+ < (adapter->bcn_buf + sizeof(adapter->bcn_buf))) {
+ /*
+ * Beacon is larger than space previously allocated
+ * (bcn_space) and there is enough space left in the
+ * beaconBuffer to store the additional data
+ */
+ dev_dbg(adapter->dev, "info: AppControl:"
+ " larger duplicate beacon (%d), "
+ "old = %d, new = %d, space = %d, left = %d\n",
+ beacon_idx, old_bcn_size, new_bcn_size,
+ bcn_space,
+ (int)(sizeof(adapter->bcn_buf) -
+ (adapter->bcn_buf_end -
+ adapter->bcn_buf)));
+
+ /*
+ * memmove (since the memory overlaps) the data
+ * after the beacon we just stored to the end of
+ * the current beacon. This moves the data for
+ * the beacons after this further in memory to
+ * make space for the new larger beacon we are
+ * about to copy in.
+ */
+ memmove(bcn_store + new_bcn_size,
+ bcn_store + bcn_space,
+ adapter->bcn_buf_end - (bcn_store + bcn_space));
+
+ /* Copy the new beacon buffer entry over the old one */
+ memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size);
+
+ /* Move the beacon end pointer by the amount of new
+ beacon data we are adding */
+ adapter->bcn_buf_end += (new_bcn_size - bcn_space);
+
+ /*
+ * This entry is bigger than the alloted max space
+ * previously reserved. Increase the max space to
+ * be equal to the new beacon size
+ */
+ new_beacon->beacon_buf_size_max = new_bcn_size;
+
+ /* Adjust beacon buffer pointers that are past the
+ current */
+ mwifiex_adjust_beacon_buffer_ptrs(priv, 1, bcn_store,
+ (new_bcn_size - bcn_space),
+ num_of_ent);
+ } else {
+ /*
+ * Beacon is larger than the previously allocated space,
+ * but there is not enough free space to store the
+ * additional data.
+ */
+ dev_err(adapter->dev, "AppControl: larger duplicate "
+ " beacon (%d), old = %d new = %d, space = %d,"
+ " left = %d\n", beacon_idx, old_bcn_size,
+ new_bcn_size, bcn_space,
+ (int)(sizeof(adapter->bcn_buf) -
+ (adapter->bcn_buf_end - adapter->bcn_buf)));
+
+ /* Storage failure, keep old beacon intact */
+ new_beacon->beacon_buf_size = old_bcn_size;
+ if (new_beacon->bcn_wpa_ie)
+ new_beacon->wpa_offset =
+ adapter->scan_table[beacon_idx].
+ wpa_offset;
+ if (new_beacon->bcn_rsn_ie)
+ new_beacon->rsn_offset =
+ adapter->scan_table[beacon_idx].
+ rsn_offset;
+ if (new_beacon->bcn_wapi_ie)
+ new_beacon->wapi_offset =
+ adapter->scan_table[beacon_idx].
+ wapi_offset;
+ if (new_beacon->bcn_ht_cap)
+ new_beacon->ht_cap_offset =
+ adapter->scan_table[beacon_idx].
+ ht_cap_offset;
+ if (new_beacon->bcn_ht_info)
+ new_beacon->ht_info_offset =
+ adapter->scan_table[beacon_idx].
+ ht_info_offset;
+ if (new_beacon->bcn_bss_co_2040)
+ new_beacon->bss_co_2040_offset =
+ adapter->scan_table[beacon_idx].
+ bss_co_2040_offset;
+ if (new_beacon->bcn_ext_cap)
+ new_beacon->ext_cap_offset =
+ adapter->scan_table[beacon_idx].
+ ext_cap_offset;
+ if (new_beacon->bcn_obss_scan)
+ new_beacon->overlap_bss_offset =
+ adapter->scan_table[beacon_idx].
+ overlap_bss_offset;
+ }
+ /* Point the new entry to its permanent storage space */
+ new_beacon->beacon_buf = bcn_store;
+ mwifiex_update_beacon_buffer_ptrs(new_beacon);
+ } else {
+ /*
+ * No existing beacon data exists for this entry, check to see
+ * if we can fit it in the remaining space
+ */
+ if (adapter->bcn_buf_end + new_beacon->beacon_buf_size +
+ SCAN_BEACON_ENTRY_PAD < (adapter->bcn_buf +
+ sizeof(adapter->bcn_buf))) {
+
+ /*
+ * Copy the beacon buffer data from the local entry to
+ * the adapter dev struct buffer space used to store
+ * the raw beacon data for each entry in the scan table
+ */
+ memcpy(adapter->bcn_buf_end, new_beacon->beacon_buf,
+ new_beacon->beacon_buf_size);
+
+ /* Update the beacon ptr to point to the table save
+ area */
+ new_beacon->beacon_buf = adapter->bcn_buf_end;
+ new_beacon->beacon_buf_size_max =
+ (new_beacon->beacon_buf_size +
+ SCAN_BEACON_ENTRY_PAD);
+
+ mwifiex_update_beacon_buffer_ptrs(new_beacon);
+
+ /* Increment the end pointer by the size reserved */
+ adapter->bcn_buf_end += new_beacon->beacon_buf_size_max;
+
+ dev_dbg(adapter->dev, "info: AppControl: beacon[%02d]"
+ " sz=%03d, used = %04d, left = %04d\n",
+ beacon_idx,
+ new_beacon->beacon_buf_size,
+ (int)(adapter->bcn_buf_end - adapter->bcn_buf),
+ (int)(sizeof(adapter->bcn_buf) -
+ (adapter->bcn_buf_end -
+ adapter->bcn_buf)));
+ } else {
+ /* No space for new beacon */
+ dev_dbg(adapter->dev, "info: AppControl: no space for"
+ " beacon (%d): %pM sz=%03d, left=%03d\n",
+ beacon_idx, new_beacon->mac_address,
+ new_beacon->beacon_buf_size,
+ (int)(sizeof(adapter->bcn_buf) -
+ (adapter->bcn_buf_end -
+ adapter->bcn_buf)));
+
+ /* Storage failure; clear storage records for this
+ bcn */
+ new_beacon->beacon_buf = NULL;
+ new_beacon->beacon_buf_size = 0;
+ new_beacon->beacon_buf_size_max = 0;
+ new_beacon->bcn_wpa_ie = NULL;
+ new_beacon->wpa_offset = 0;
+ new_beacon->bcn_rsn_ie = NULL;
+ new_beacon->rsn_offset = 0;
+ new_beacon->bcn_wapi_ie = NULL;
+ new_beacon->wapi_offset = 0;
+ new_beacon->bcn_ht_cap = NULL;
+ new_beacon->ht_cap_offset = 0;
+ new_beacon->bcn_ht_info = NULL;
+ new_beacon->ht_info_offset = 0;
+ new_beacon->bcn_bss_co_2040 = NULL;
+ new_beacon->bss_co_2040_offset = 0;
+ new_beacon->bcn_ext_cap = NULL;
+ new_beacon->ext_cap_offset = 0;
+ new_beacon->bcn_obss_scan = NULL;
+ new_beacon->overlap_bss_offset = 0;
+ }
+ }
+}
+
+/*
+ * This function restores a beacon buffer of the current BSS descriptor.
+ */
+static void mwifiex_restore_curr_bcn(struct mwifiex_private *priv)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_bssdescriptor *curr_bss =
+ &priv->curr_bss_params.bss_descriptor;
+ unsigned long flags;
+
+ if (priv->curr_bcn_buf &&
+ ((adapter->bcn_buf_end + priv->curr_bcn_size) <
+ (adapter->bcn_buf + sizeof(adapter->bcn_buf)))) {
+ spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags);
+
+ /* restore the current beacon buffer */
+ memcpy(adapter->bcn_buf_end, priv->curr_bcn_buf,
+ priv->curr_bcn_size);
+ curr_bss->beacon_buf = adapter->bcn_buf_end;
+ curr_bss->beacon_buf_size = priv->curr_bcn_size;
+ adapter->bcn_buf_end += priv->curr_bcn_size;
+
+ /* adjust the pointers in the current BSS descriptor */
+ if (curr_bss->bcn_wpa_ie)
+ curr_bss->bcn_wpa_ie =
+ (struct ieee_types_vendor_specific *)
+ (curr_bss->beacon_buf +
+ curr_bss->wpa_offset);
+
+ if (curr_bss->bcn_rsn_ie)
+ curr_bss->bcn_rsn_ie = (struct ieee_types_generic *)
+ (curr_bss->beacon_buf +
+ curr_bss->rsn_offset);
+
+ if (curr_bss->bcn_ht_cap)
+ curr_bss->bcn_ht_cap = (struct ieee80211_ht_cap *)
+ (curr_bss->beacon_buf +
+ curr_bss->ht_cap_offset);
+
+ if (curr_bss->bcn_ht_info)
+ curr_bss->bcn_ht_info = (struct ieee80211_ht_info *)
+ (curr_bss->beacon_buf +
+ curr_bss->ht_info_offset);
+
+ if (curr_bss->bcn_bss_co_2040)
+ curr_bss->bcn_bss_co_2040 =
+ (u8 *) (curr_bss->beacon_buf +
+ curr_bss->bss_co_2040_offset);
+
+ if (curr_bss->bcn_ext_cap)
+ curr_bss->bcn_ext_cap = (u8 *) (curr_bss->beacon_buf +
+ curr_bss->ext_cap_offset);
+
+ if (curr_bss->bcn_obss_scan)
+ curr_bss->bcn_obss_scan =
+ (struct ieee_types_obss_scan_param *)
+ (curr_bss->beacon_buf +
+ curr_bss->overlap_bss_offset);
+
+ spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags);
+
+ dev_dbg(adapter->dev, "info: current beacon restored %d\n",
+ priv->curr_bcn_size);
+ } else {
+ dev_warn(adapter->dev,
+ "curr_bcn_buf not saved or bcn_buf has no space\n");
+ }
+}
+
+/*
+ * This function post processes the scan table after a new scan command has
+ * completed.
+ *
+ * It inspects each entry of the scan table and tries to find an entry that
+ * matches with our current associated/joined network from the scan. If
+ * one is found, the stored copy of the BSS descriptor of our current network
+ * is updated.
+ *
+ * It also debug dumps the current scan table contents after processing is over.
+ */
+static void
+mwifiex_process_scan_results(struct mwifiex_private *priv)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ s32 j;
+ u32 i;
+ unsigned long flags;
+
+ if (priv->media_connected) {
+
+ j = mwifiex_find_ssid_in_list(priv, &priv->curr_bss_params.
+ bss_descriptor.ssid,
+ priv->curr_bss_params.
+ bss_descriptor.mac_address,
+ priv->bss_mode);
+
+ if (j >= 0) {
+ spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags);
+ priv->curr_bss_params.bss_descriptor.bcn_wpa_ie = NULL;
+ priv->curr_bss_params.bss_descriptor.wpa_offset = 0;
+ priv->curr_bss_params.bss_descriptor.bcn_rsn_ie = NULL;
+ priv->curr_bss_params.bss_descriptor.rsn_offset = 0;
+ priv->curr_bss_params.bss_descriptor.bcn_wapi_ie = NULL;
+ priv->curr_bss_params.bss_descriptor.wapi_offset = 0;
+ priv->curr_bss_params.bss_descriptor.bcn_ht_cap = NULL;
+ priv->curr_bss_params.bss_descriptor.ht_cap_offset =
+ 0;
+ priv->curr_bss_params.bss_descriptor.bcn_ht_info = NULL;
+ priv->curr_bss_params.bss_descriptor.ht_info_offset =
+ 0;
+ priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 =
+ NULL;
+ priv->curr_bss_params.bss_descriptor.
+ bss_co_2040_offset = 0;
+ priv->curr_bss_params.bss_descriptor.bcn_ext_cap = NULL;
+ priv->curr_bss_params.bss_descriptor.ext_cap_offset = 0;
+ priv->curr_bss_params.bss_descriptor.
+ bcn_obss_scan = NULL;
+ priv->curr_bss_params.bss_descriptor.
+ overlap_bss_offset = 0;
+ priv->curr_bss_params.bss_descriptor.beacon_buf = NULL;
+ priv->curr_bss_params.bss_descriptor.beacon_buf_size =
+ 0;
+ priv->curr_bss_params.bss_descriptor.
+ beacon_buf_size_max = 0;
+
+ dev_dbg(adapter->dev, "info: Found current ssid/bssid"
+ " in list @ index #%d\n", j);
+ /* Make a copy of current BSSID descriptor */
+ memcpy(&priv->curr_bss_params.bss_descriptor,
+ &adapter->scan_table[j],
+ sizeof(priv->curr_bss_params.bss_descriptor));
+
+ mwifiex_save_curr_bcn(priv);
+ spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags);
+
+ } else {
+ mwifiex_restore_curr_bcn(priv);
+ }
+ }
+
+ for (i = 0; i < adapter->num_in_scan_table; i++)
+ dev_dbg(adapter->dev, "info: scan:(%02d) %pM "
+ "RSSI[%03d], SSID[%s]\n",
+ i, adapter->scan_table[i].mac_address,
+ (s32) adapter->scan_table[i].rssi,
+ adapter->scan_table[i].ssid.ssid);
+}
+
+/*
+ * This function converts radio type scan parameter to a band configuration
+ * to be used in join command.
+ */
+static u8
+mwifiex_radio_type_to_band(u8 radio_type)
+{
+ switch (radio_type) {
+ case HostCmd_SCAN_RADIO_TYPE_A:
+ return BAND_A;
+ case HostCmd_SCAN_RADIO_TYPE_BG:
+ default:
+ return BAND_G;
+ }
+}
+
+/*
+ * This function deletes a specific indexed entry from the scan table.
+ *
+ * This also compacts the remaining entries and adjusts any buffering
+ * of beacon/probe response data if needed.
+ */
+static void
+mwifiex_scan_delete_table_entry(struct mwifiex_private *priv, s32 table_idx)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ u32 del_idx;
+ u32 beacon_buf_adj;
+ u8 *beacon_buf;
+
+ /*
+ * Shift the saved beacon buffer data for the scan table back over the
+ * entry being removed. Update the end of buffer pointer. Save the
+ * deleted buffer allocation size for pointer adjustments for entries
+ * compacted after the deleted index.
+ */
+ beacon_buf_adj = adapter->scan_table[table_idx].beacon_buf_size_max;
+
+ dev_dbg(adapter->dev, "info: Scan: Delete Entry %d, beacon buffer "
+ "removal = %d bytes\n", table_idx, beacon_buf_adj);
+
+ /* Check if the table entry had storage allocated for its beacon */
+ if (beacon_buf_adj) {
+ beacon_buf = adapter->scan_table[table_idx].beacon_buf;
+
+ /*
+ * Remove the entry's buffer space, decrement the table end
+ * pointer by the amount we are removing
+ */
+ adapter->bcn_buf_end -= beacon_buf_adj;
+
+ dev_dbg(adapter->dev, "info: scan: delete entry %d,"
+ " compact data: %p <- %p (sz = %d)\n",
+ table_idx, beacon_buf,
+ beacon_buf + beacon_buf_adj,
+ (int)(adapter->bcn_buf_end - beacon_buf));
+
+ /*
+ * Compact data storage. Copy all data after the deleted
+ * entry's end address (beacon_buf + beacon_buf_adj) back
+ * to the original start address (beacon_buf).
+ *
+ * Scan table entries affected by the move will have their
+ * entry pointer adjusted below.
+ *
+ * Use memmove since the dest/src memory regions overlap.
+ */
+ memmove(beacon_buf, beacon_buf + beacon_buf_adj,
+ adapter->bcn_buf_end - beacon_buf);
+ }
+
+ dev_dbg(adapter->dev,
+ "info: Scan: Delete Entry %d, num_in_scan_table = %d\n",
+ table_idx, adapter->num_in_scan_table);
+
+ /* Shift all of the entries after the table_idx back by one, compacting
+ the table and removing the requested entry */
+ for (del_idx = table_idx; (del_idx + 1) < adapter->num_in_scan_table;
+ del_idx++) {
+ /* Copy the next entry over this one */
+ memcpy(adapter->scan_table + del_idx,
+ adapter->scan_table + del_idx + 1,
+ sizeof(struct mwifiex_bssdescriptor));
+
+ /*
+ * Adjust this entry's pointer to its beacon buffer based on
+ * the removed/compacted entry from the deleted index. Don't
+ * decrement if the buffer pointer is NULL (no data stored for
+ * this entry).
+ */
+ if (adapter->scan_table[del_idx].beacon_buf) {
+ adapter->scan_table[del_idx].beacon_buf -=
+ beacon_buf_adj;
+ if (adapter->scan_table[del_idx].bcn_wpa_ie)
+ adapter->scan_table[del_idx].bcn_wpa_ie =
+ (struct ieee_types_vendor_specific *)
+ (adapter->scan_table[del_idx].
+ beacon_buf +
+ adapter->scan_table[del_idx].
+ wpa_offset);
+ if (adapter->scan_table[del_idx].bcn_rsn_ie)
+ adapter->scan_table[del_idx].bcn_rsn_ie =
+ (struct ieee_types_generic *)
+ (adapter->scan_table[del_idx].
+ beacon_buf +
+ adapter->scan_table[del_idx].
+ rsn_offset);
+ if (adapter->scan_table[del_idx].bcn_wapi_ie)
+ adapter->scan_table[del_idx].bcn_wapi_ie =
+ (struct ieee_types_generic *)
+ (adapter->scan_table[del_idx].beacon_buf
+ + adapter->scan_table[del_idx].
+ wapi_offset);
+ if (adapter->scan_table[del_idx].bcn_ht_cap)
+ adapter->scan_table[del_idx].bcn_ht_cap =
+ (struct ieee80211_ht_cap *)
+ (adapter->scan_table[del_idx].beacon_buf
+ + adapter->scan_table[del_idx].
+ ht_cap_offset);
+
+ if (adapter->scan_table[del_idx].bcn_ht_info)
+ adapter->scan_table[del_idx].bcn_ht_info =
+ (struct ieee80211_ht_info *)
+ (adapter->scan_table[del_idx].beacon_buf
+ + adapter->scan_table[del_idx].
+ ht_info_offset);
+ if (adapter->scan_table[del_idx].bcn_bss_co_2040)
+ adapter->scan_table[del_idx].bcn_bss_co_2040 =
+ (u8 *)
+ (adapter->scan_table[del_idx].beacon_buf
+ + adapter->scan_table[del_idx].
+ bss_co_2040_offset);
+ if (adapter->scan_table[del_idx].bcn_ext_cap)
+ adapter->scan_table[del_idx].bcn_ext_cap =
+ (u8 *)
+ (adapter->scan_table[del_idx].beacon_buf
+ + adapter->scan_table[del_idx].
+ ext_cap_offset);
+ if (adapter->scan_table[del_idx].bcn_obss_scan)
+ adapter->scan_table[del_idx].
+ bcn_obss_scan =
+ (struct ieee_types_obss_scan_param *)
+ (adapter->scan_table[del_idx].beacon_buf
+ + adapter->scan_table[del_idx].
+ overlap_bss_offset);
+ }
+ }
+
+ /* The last entry is invalid now that it has been deleted or moved
+ back */
+ memset(adapter->scan_table + adapter->num_in_scan_table - 1,
+ 0x00, sizeof(struct mwifiex_bssdescriptor));
+
+ adapter->num_in_scan_table--;
+}
+
+/*
+ * This function deletes all occurrences of a given SSID from the scan table.
+ *
+ * This iterates through the scan table and deletes all entries that match
+ * the given SSID. It also compacts the remaining scan table entries.
+ */
+static int
+mwifiex_scan_delete_ssid_table_entry(struct mwifiex_private *priv,
+ struct mwifiex_802_11_ssid *del_ssid)
+{
+ s32 table_idx = -1;
+
+ dev_dbg(priv->adapter->dev, "info: scan: delete ssid entry: %-32s\n",
+ del_ssid->ssid);
+
+ /* If the requested SSID is found in the table, delete it. Then keep
+ searching the table for multiple entires for the SSID until no
+ more are found */
+ while ((table_idx = mwifiex_find_ssid_in_list(priv, del_ssid, NULL,
+ NL80211_IFTYPE_UNSPECIFIED)) >= 0) {
+ dev_dbg(priv->adapter->dev,
+ "info: Scan: Delete SSID Entry: Found Idx = %d\n",
+ table_idx);
+ mwifiex_scan_delete_table_entry(priv, table_idx);
+ }
+
+ return table_idx == -1 ? -1 : 0;
+}
+
+/*
+ * This is an internal function used to start a scan based on an input
+ * configuration.
+ *
+ * This uses 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.
+ */
+int mwifiex_scan_networks(struct mwifiex_private *priv,
+ const struct mwifiex_user_scan_cfg *user_scan_in)
+{
+ int ret = 0;
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *cmd_node;
+ union mwifiex_scan_cmd_config_tlv *scan_cfg_out;
+ struct mwifiex_ie_types_chan_list_param_set *chan_list_out;
+ u32 buf_size;
+ struct mwifiex_chan_scan_param_set *scan_chan_list;
+ u8 keep_previous_scan;
+ u8 filtered_scan;
+ u8 scan_current_chan_only;
+ u8 max_chan_per_scan;
+ unsigned long flags;
+
+ if (adapter->scan_processing) {
+ dev_dbg(adapter->dev, "cmd: Scan already in process...\n");
+ return ret;
+ }
+
+ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ adapter->scan_processing = true;
+ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+
+ if (priv->scan_block) {
+ dev_dbg(adapter->dev,
+ "cmd: Scan is blocked during association...\n");
+ return ret;
+ }
+
+ scan_cfg_out = kzalloc(sizeof(union mwifiex_scan_cmd_config_tlv),
+ GFP_KERNEL);
+ if (!scan_cfg_out) {
+ dev_err(adapter->dev, "failed to alloc scan_cfg_out\n");
+ return -ENOMEM;
+ }
+
+ buf_size = sizeof(struct mwifiex_chan_scan_param_set) *
+ MWIFIEX_USER_SCAN_CHAN_MAX;
+ scan_chan_list = kzalloc(buf_size, GFP_KERNEL);
+ if (!scan_chan_list) {
+ dev_err(adapter->dev, "failed to alloc scan_chan_list\n");
+ kfree(scan_cfg_out);
+ return -ENOMEM;
+ }
+
+ keep_previous_scan = false;
+
+ mwifiex_scan_setup_scan_config(priv, user_scan_in,
+ &scan_cfg_out->config, &chan_list_out,
+ scan_chan_list, &max_chan_per_scan,
+ &filtered_scan, &scan_current_chan_only);
+
+ if (user_scan_in)
+ keep_previous_scan = user_scan_in->keep_previous_scan;
+
+
+ if (!keep_previous_scan) {
+ memset(adapter->scan_table, 0x00,
+ sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP);
+ adapter->num_in_scan_table = 0;
+ adapter->bcn_buf_end = adapter->bcn_buf;
+ }
+
+ ret = mwifiex_scan_channel_list(priv, max_chan_per_scan, filtered_scan,
+ &scan_cfg_out->config, chan_list_out,
+ scan_chan_list);
+
+ /* Get scan command from scan_pending_q and put to cmd_pending_q */
+ if (!ret) {
+ spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+ if (!list_empty(&adapter->scan_pending_q)) {
+ cmd_node = list_first_entry(&adapter->scan_pending_q,
+ struct cmd_ctrl_node, list);
+ list_del(&cmd_node->list);
+ spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+ flags);
+ mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
+ true);
+ } else {
+ spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+ flags);
+ }
+ } else {
+ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ adapter->scan_processing = true;
+ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+ }
+
+ kfree(scan_cfg_out);
+ kfree(scan_chan_list);
+ return ret;
+}
+
+/*
+ * This function prepares a scan command to be sent to the firmware.
+ *
+ * This uses the scan command configuration sent to the command processing
+ * module in command preparation stage to configure a scan command structure
+ * to send to firmware.
+ *
+ * The fixed fields specifying the BSS type and BSSID filters as well as a
+ * variable number/length of TLVs are sent in the command to firmware.
+ *
+ * Preparation also includes -
+ * - Setting command ID, and proper size
+ * - Ensuring correct endian-ness
+ */
+int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd, void *data_buf)
+{
+ struct host_cmd_ds_802_11_scan *scan_cmd = &cmd->params.scan;
+ struct mwifiex_scan_cmd_config *scan_cfg;
+
+ scan_cfg = (struct mwifiex_scan_cmd_config *) data_buf;
+
+ /* Set fixed field variables in scan command */
+ scan_cmd->bss_mode = scan_cfg->bss_mode;
+ memcpy(scan_cmd->bssid, scan_cfg->specific_bssid,
+ sizeof(scan_cmd->bssid));
+ memcpy(scan_cmd->tlv_buffer, scan_cfg->tlv_buf, scan_cfg->tlv_buf_len);
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SCAN);
+
+ /* Size is equal to the sizeof(fixed portions) + the TLV len + header */
+ cmd->size = cpu_to_le16((u16) (sizeof(scan_cmd->bss_mode)
+ + sizeof(scan_cmd->bssid)
+ + scan_cfg->tlv_buf_len + S_DS_GEN));
+
+ return 0;
+}
+
+/*
+ * This function handles the command response of scan.
+ *
+ * The response buffer for the scan command has the following
+ * memory layout:
+ *
+ * .-------------------------------------------------------------.
+ * | Header (4 * sizeof(t_u16)): Standard command response hdr |
+ * .-------------------------------------------------------------.
+ * | BufSize (t_u16) : sizeof the BSS Description data |
+ * .-------------------------------------------------------------.
+ * | NumOfSet (t_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) |
+ * .-------------------------------------------------------------.
+ */
+int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
+{
+ int ret = 0;
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct cmd_ctrl_node *cmd_node;
+ struct host_cmd_ds_802_11_scan_rsp *scan_rsp;
+ struct mwifiex_bssdescriptor *bss_new_entry = NULL;
+ struct mwifiex_ie_types_data *tlv_data;
+ struct mwifiex_ie_types_tsf_timestamp *tsf_tlv;
+ u8 *bss_info;
+ u32 scan_resp_size;
+ u32 bytes_left;
+ u32 num_in_table;
+ u32 bss_idx;
+ u32 idx;
+ u32 tlv_buf_size;
+ long long tsf_val;
+ struct mwifiex_chan_freq_power *cfp;
+ struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv;
+ struct chan_band_param_set *chan_band;
+ u8 band;
+ u8 is_bgscan_resp;
+ unsigned long flags;
+
+ is_bgscan_resp = (le16_to_cpu(resp->command)
+ == HostCmd_CMD_802_11_BG_SCAN_QUERY);
+ if (is_bgscan_resp)
+ scan_rsp = &resp->params.bg_scan_query_resp.scan_resp;
+ else
+ scan_rsp = &resp->params.scan_resp;
+
+
+ if (scan_rsp->number_of_sets > IW_MAX_AP) {
+ dev_err(adapter->dev, "SCAN_RESP: too many AP returned (%d)\n",
+ scan_rsp->number_of_sets);
+ ret = -1;
+ goto done;
+ }
+
+ bytes_left = le16_to_cpu(scan_rsp->bss_descript_size);
+ dev_dbg(adapter->dev, "info: SCAN_RESP: bss_descript_size %d\n",
+ bytes_left);
+
+ scan_resp_size = le16_to_cpu(resp->size);
+
+ dev_dbg(adapter->dev,
+ "info: SCAN_RESP: returned %d APs before parsing\n",
+ scan_rsp->number_of_sets);
+
+ num_in_table = adapter->num_in_scan_table;
+ bss_info = scan_rsp->bss_desc_and_tlv_buffer;
+
+ /*
+ * The size of the TLV buffer is equal to the entire command response
+ * size (scan_resp_size) minus the fixed fields (sizeof()'s), the
+ * BSS Descriptions (bss_descript_size as bytesLef) and the command
+ * response header (S_DS_GEN)
+ */
+ tlv_buf_size = scan_resp_size - (bytes_left
+ + sizeof(scan_rsp->bss_descript_size)
+ + sizeof(scan_rsp->number_of_sets)
+ + S_DS_GEN);
+
+ tlv_data = (struct mwifiex_ie_types_data *) (scan_rsp->
+ bss_desc_and_tlv_buffer +
+ bytes_left);
+
+ /* Search the TLV buffer space in the scan response for any valid
+ TLVs */
+ mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size,
+ TLV_TYPE_TSFTIMESTAMP,
+ (struct mwifiex_ie_types_data **)
+ &tsf_tlv);
+
+ /* Search the TLV buffer space in the scan response for any valid
+ TLVs */
+ mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size,
+ TLV_TYPE_CHANNELBANDLIST,
+ (struct mwifiex_ie_types_data **)
+ &chan_band_tlv);
+
+ /*
+ * Process each scan response returned (scan_rsp->number_of_sets).
+ * Save the information in the bss_new_entry 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
+ */
+ bss_new_entry = kzalloc(sizeof(struct mwifiex_bssdescriptor),
+ GFP_KERNEL);
+ if (!bss_new_entry) {
+ dev_err(adapter->dev, " failed to alloc bss_new_entry\n");
+ return -ENOMEM;
+ }
+
+ for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) {
+ /* Zero out the bss_new_entry we are about to store info in */
+ memset(bss_new_entry, 0x00,
+ sizeof(struct mwifiex_bssdescriptor));
+
+ if (mwifiex_interpret_bss_desc_with_ie(adapter, bss_new_entry,
+ &bss_info,
+ &bytes_left)) {
+ /* Error parsing/interpreting scan response, skipped */
+ dev_err(adapter->dev, "SCAN_RESP: "
+ "mwifiex_interpret_bss_desc_with_ie "
+ "returned ERROR\n");
+ continue;
+ }
+
+ /* Process the data fields and IEs returned for this BSS */
+ dev_dbg(adapter->dev, "info: SCAN_RESP: BSSID = %pM\n",
+ bss_new_entry->mac_address);
+
+ /* Search the scan table for the same bssid */
+ for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) {
+ if (memcmp(bss_new_entry->mac_address,
+ adapter->scan_table[bss_idx].mac_address,
+ sizeof(bss_new_entry->mac_address))) {
+ continue;
+ }
+ /*
+ * If the SSID matches as well, it is a
+ * duplicate of this entry. Keep the bss_idx
+ * set to this entry so we replace the old
+ * contents in the table
+ */
+ if ((bss_new_entry->ssid.ssid_len
+ == adapter->scan_table[bss_idx]. ssid.ssid_len)
+ && (!memcmp(bss_new_entry->ssid.ssid,
+ adapter->scan_table[bss_idx].ssid.ssid,
+ bss_new_entry->ssid.ssid_len))) {
+ dev_dbg(adapter->dev, "info: SCAN_RESP:"
+ " duplicate of index: %d\n", bss_idx);
+ break;
+ }
+ }
+ /*
+ * If the bss_idx is equal to the number of entries in
+ * the table, the new entry was not a duplicate; append
+ * it to the scan table
+ */
+ if (bss_idx == num_in_table) {
+ /* Range check the bss_idx, keep it limited to
+ the last entry */
+ if (bss_idx == IW_MAX_AP)
+ bss_idx--;
+ else
+ num_in_table++;
+ }
+
+ /*
+ * Save the beacon/probe response returned for later application
+ * retrieval. Duplicate beacon/probe responses are updated if
+ * possible
+ */
+ mwifiex_ret_802_11_scan_store_beacon(priv, bss_idx,
+ num_in_table, bss_new_entry);
+ /*
+ * If the TSF TLV was appended to the scan results, save this
+ * entry's TSF value in the networkTSF field.The networkTSF is
+ * the firmware's TSF value at the time the beacon or probe
+ * response was received.
+ */
+ if (tsf_tlv) {
+ memcpy(&tsf_val, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE]
+ , sizeof(tsf_val));
+ memcpy(&bss_new_entry->network_tsf, &tsf_val,
+ sizeof(bss_new_entry->network_tsf));
+ }
+ band = BAND_G;
+ if (chan_band_tlv) {
+ chan_band = &chan_band_tlv->chan_band_param[idx];
+ band = mwifiex_radio_type_to_band(chan_band->radio_type
+ & (BIT(0) | BIT(1)));
+ }
+
+ /* Save the band designation for this entry for use in join */
+ bss_new_entry->bss_band = band;
+ cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv,
+ (u8) bss_new_entry->bss_band,
+ (u16)bss_new_entry->channel);
+
+ if (cfp)
+ bss_new_entry->freq = cfp->freq;
+ else
+ bss_new_entry->freq = 0;
+
+ /* Copy the locally created bss_new_entry to the scan table */
+ memcpy(&adapter->scan_table[bss_idx], bss_new_entry,
+ sizeof(adapter->scan_table[bss_idx]));
+
+ }
+
+ dev_dbg(adapter->dev,
+ "info: SCAN_RESP: Scanned %2d APs, %d valid, %d total\n",
+ scan_rsp->number_of_sets,
+ num_in_table - adapter->num_in_scan_table, num_in_table);
+
+ /* Update the total number of BSSIDs in the scan table */
+ adapter->num_in_scan_table = num_in_table;
+
+ spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+ if (list_empty(&adapter->scan_pending_q)) {
+ spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ adapter->scan_processing = false;
+ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+ /*
+ * Process the resulting scan table:
+ * - Remove any bad ssids
+ * - Update our current BSS information from scan data
+ */
+ mwifiex_process_scan_results(priv);
+
+ /* Need to indicate IOCTL complete */
+ if (adapter->curr_cmd->wait_q_enabled) {
+ adapter->cmd_wait_q.status = 0;
+ mwifiex_complete_cmd(adapter);
+ }
+ if (priv->report_scan_result)
+ priv->report_scan_result = false;
+ if (priv->scan_pending_on_block) {
+ priv->scan_pending_on_block = false;
+ up(&priv->async_sem);
+ }
+
+ } else {
+ /* Get scan command from scan_pending_q and put to
+ cmd_pending_q */
+ cmd_node = list_first_entry(&adapter->scan_pending_q,
+ struct cmd_ctrl_node, list);
+ list_del(&cmd_node->list);
+ spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+
+ mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
+ }
+
+done:
+ kfree((u8 *) bss_new_entry);
+ return ret;
+}
+
+/*
+ * This function prepares command for background scan query.
+ *
+ * Preparation includes -
+ * - Setting command ID and proper size
+ * - Setting background scan flush parameter
+ * - Ensuring correct endian-ness
+ */
+int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd)
+{
+ struct host_cmd_ds_802_11_bg_scan_query *bg_query =
+ &cmd->params.bg_scan_query;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_QUERY);
+ cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_bg_scan_query)
+ + S_DS_GEN);
+
+ bg_query->flush = 1;
+
+ return 0;
+}
+
+/*
+ * This function finds a SSID in the scan table.
+ *
+ * A BSSID may optionally be provided to qualify the SSID.
+ * For non-Auto mode, further check is made to make sure the
+ * BSS found in the scan table is compatible with the current
+ * settings of the driver.
+ */
+s32
+mwifiex_find_ssid_in_list(struct mwifiex_private *priv,
+ struct mwifiex_802_11_ssid *ssid, u8 *bssid,
+ u32 mode)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ s32 net = -1, j;
+ u8 best_rssi = 0;
+ u32 i;
+
+ dev_dbg(adapter->dev, "info: num of entries in table = %d\n",
+ adapter->num_in_scan_table);
+
+ /*
+ * Loop through the table until the maximum is reached or until a match
+ * is found based on the bssid field comparison
+ */
+ for (i = 0;
+ i < adapter->num_in_scan_table && (!bssid || (bssid && net < 0));
+ i++) {
+ if (!mwifiex_ssid_cmp(&adapter->scan_table[i].ssid, ssid) &&
+ (!bssid
+ || !memcmp(adapter->scan_table[i].mac_address, bssid,
+ ETH_ALEN))
+ &&
+ (mwifiex_get_cfp_by_band_and_channel_from_cfg80211
+ (priv, (u8) adapter->scan_table[i].bss_band,
+ (u16) adapter->scan_table[i].channel))) {
+ switch (mode) {
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ j = mwifiex_is_network_compatible(priv, i,
+ mode);
+
+ if (j >= 0) {
+ if (SCAN_RSSI
+ (adapter->scan_table[i].rssi) >
+ best_rssi) {
+ best_rssi = SCAN_RSSI(adapter->
+ scan_table
+ [i].rssi);
+ net = i;
+ }
+ } else {
+ if (net == -1)
+ net = j;
+ }
+ break;
+ case NL80211_IFTYPE_UNSPECIFIED:
+ default:
+ /*
+ * Do not check compatibility if the mode
+ * requested is Auto/Unknown. Allows generic
+ * find to work without verifying against the
+ * Adapter security settings
+ */
+ if (SCAN_RSSI(adapter->scan_table[i].rssi) >
+ best_rssi) {
+ best_rssi = SCAN_RSSI(adapter->
+ scan_table[i].rssi);
+ net = i;
+ }
+ break;
+ }
+ }
+ }
+
+ return net;
+}
+
+/*
+ * This function finds a specific compatible BSSID in the scan list.
+ *
+ * This function loops through the scan table looking for a compatible
+ * match. If a BSSID matches, but the BSS is found to be not compatible
+ * the function ignores it and continues to search through the rest of
+ * the entries in case there is an AP with multiple SSIDs assigned to
+ * the same BSSID.
+ */
+s32
+mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid,
+ u32 mode)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ s32 net = -1;
+ u32 i;
+
+ if (!bssid)
+ return -1;
+
+ dev_dbg(adapter->dev, "info: FindBSSID: Num of BSSIDs = %d\n",
+ adapter->num_in_scan_table);
+
+ /*
+ * Look through the scan table for a compatible match. The ret return
+ * variable will be equal to the index in the scan table (greater
+ * than zero) if the network is compatible. 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
+ */
+ for (i = 0; net < 0 && i < adapter->num_in_scan_table; i++) {
+ if (!memcmp
+ (adapter->scan_table[i].mac_address, bssid, ETH_ALEN)
+ && mwifiex_get_cfp_by_band_and_channel_from_cfg80211
+ (priv,
+ (u8) adapter->
+ scan_table[i].
+ bss_band,
+ (u16) adapter->
+ scan_table[i].
+ channel)) {
+ switch (mode) {
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ net = mwifiex_is_network_compatible(priv, i,
+ mode);
+ break;
+ default:
+ net = i;
+ break;
+ }
+ }
+ }
+
+ return net;
+}
+
+/*
+ * This function inserts scan command node to the scan pending queue.
+ */
+void
+mwifiex_queue_scan_cmd(struct mwifiex_private *priv,
+ struct cmd_ctrl_node *cmd_node)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ unsigned long flags;
+
+ cmd_node->wait_q_enabled = true;
+ spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+ list_add_tail(&cmd_node->list, &adapter->scan_pending_q);
+ spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+}
+
+/*
+ * This function finds an AP with specific ssid in the scan list.
+ */
+int mwifiex_find_best_network(struct mwifiex_private *priv,
+ struct mwifiex_ssid_bssid *req_ssid_bssid)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_bssdescriptor *req_bss;
+ s32 i;
+
+ memset(req_ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid));
+
+ i = mwifiex_find_best_network_in_list(priv);
+
+ if (i >= 0) {
+ req_bss = &adapter->scan_table[i];
+ memcpy(&req_ssid_bssid->ssid, &req_bss->ssid,
+ sizeof(struct mwifiex_802_11_ssid));
+ memcpy((u8 *) &req_ssid_bssid->bssid,
+ (u8 *) &req_bss->mac_address, ETH_ALEN);
+
+ /* Make sure we are in the right mode */
+ if (priv->bss_mode == NL80211_IFTYPE_UNSPECIFIED)
+ priv->bss_mode = req_bss->bss_mode;
+ }
+
+ if (!req_ssid_bssid->ssid.ssid_len)
+ return -1;
+
+ dev_dbg(adapter->dev, "info: Best network found = [%s], "
+ "[%pM]\n", req_ssid_bssid->ssid.ssid,
+ req_ssid_bssid->bssid);
+
+ return 0;
+}
+
+/*
+ * This function sends a scan command for all available channels to the
+ * firmware, filtered on a specific SSID.
+ */
+static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv,
+ struct mwifiex_802_11_ssid *req_ssid)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ int ret = 0;
+ struct mwifiex_user_scan_cfg *scan_cfg;
+
+ if (!req_ssid)
+ return -1;
+
+ if (adapter->scan_processing) {
+ dev_dbg(adapter->dev, "cmd: Scan already in process...\n");
+ return ret;
+ }
+
+ if (priv->scan_block) {
+ dev_dbg(adapter->dev,
+ "cmd: Scan is blocked during association...\n");
+ return ret;
+ }
+
+ mwifiex_scan_delete_ssid_table_entry(priv, req_ssid);
+
+ scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL);
+ if (!scan_cfg) {
+ dev_err(adapter->dev, "failed to alloc scan_cfg\n");
+ return -ENOMEM;
+ }
+
+ memcpy(scan_cfg->ssid_list[0].ssid, req_ssid->ssid,
+ req_ssid->ssid_len);
+ scan_cfg->keep_previous_scan = true;
+
+ ret = mwifiex_scan_networks(priv, scan_cfg);
+
+ kfree(scan_cfg);
+ return ret;
+}
+
+/*
+ * Sends IOCTL request to start a scan.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ *
+ * Scan command can be issued for both normal scan and specific SSID
+ * scan, depending upon whether an SSID is provided or not.
+ */
+int mwifiex_request_scan(struct mwifiex_private *priv,
+ struct mwifiex_802_11_ssid *req_ssid)
+{
+ int ret;
+
+ if (down_interruptible(&priv->async_sem)) {
+ dev_err(priv->adapter->dev, "%s: acquire semaphore\n",
+ __func__);
+ return -1;
+ }
+ priv->scan_pending_on_block = true;
+
+ priv->adapter->cmd_wait_q.condition = false;
+
+ if (req_ssid && req_ssid->ssid_len != 0)
+ /* Specific SSID scan */
+ ret = mwifiex_scan_specific_ssid(priv, req_ssid);
+ else
+ /* Normal scan */
+ ret = mwifiex_scan_networks(priv, NULL);
+
+ if (!ret)
+ ret = mwifiex_wait_queue_complete(priv->adapter);
+
+ if (ret == -1) {
+ priv->scan_pending_on_block = false;
+ up(&priv->async_sem);
+ }
+
+ return ret;
+}
+
+/*
+ * This function appends the vendor specific IE TLV to a buffer.
+ */
+int
+mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv,
+ u16 vsie_mask, u8 **buffer)
+{
+ int id, ret_len = 0;
+ struct mwifiex_ie_types_vendor_param_set *vs_param_set;
+
+ if (!buffer)
+ return 0;
+ if (!(*buffer))
+ return 0;
+
+ /*
+ * Traverse through the saved vendor specific IE array and append
+ * the selected(scan/assoc/adhoc) IE as TLV to the command
+ */
+ for (id = 0; id < MWIFIEX_MAX_VSIE_NUM; id++) {
+ if (priv->vs_ie[id].mask & vsie_mask) {
+ vs_param_set =
+ (struct mwifiex_ie_types_vendor_param_set *)
+ *buffer;
+ vs_param_set->header.type =
+ cpu_to_le16(TLV_TYPE_PASSTHROUGH);
+ vs_param_set->header.len =
+ cpu_to_le16((((u16) priv->vs_ie[id].ie[1])
+ & 0x00FF) + 2);
+ memcpy(vs_param_set->ie, priv->vs_ie[id].ie,
+ le16_to_cpu(vs_param_set->header.len));
+ *buffer += le16_to_cpu(vs_param_set->header.len) +
+ sizeof(struct mwifiex_ie_types_header);
+ ret_len += le16_to_cpu(vs_param_set->header.len) +
+ sizeof(struct mwifiex_ie_types_header);
+ }
+ }
+ return ret_len;
+}
+
+/*
+ * This function saves a beacon buffer of the current BSS descriptor.
+ *
+ * The current beacon buffer is saved so that it can be restored in the
+ * following cases that makes the beacon buffer not to contain the current
+ * ssid's beacon buffer.
+ * - The current ssid was not found somehow in the last scan.
+ * - The current ssid was the last entry of the scan table and overloaded.
+ */
+void
+mwifiex_save_curr_bcn(struct mwifiex_private *priv)
+{
+ struct mwifiex_bssdescriptor *curr_bss =
+ &priv->curr_bss_params.bss_descriptor;
+
+ if (!curr_bss->beacon_buf_size)
+ return;
+
+ /* allocate beacon buffer at 1st time; or if it's size has changed */
+ if (!priv->curr_bcn_buf ||
+ priv->curr_bcn_size != curr_bss->beacon_buf_size) {
+ priv->curr_bcn_size = curr_bss->beacon_buf_size;
+
+ kfree(priv->curr_bcn_buf);
+ priv->curr_bcn_buf = kzalloc(curr_bss->beacon_buf_size,
+ GFP_KERNEL);
+ if (!priv->curr_bcn_buf) {
+ dev_err(priv->adapter->dev,
+ "failed to alloc curr_bcn_buf\n");
+ return;
+ }
+ }
+
+ memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf,
+ curr_bss->beacon_buf_size);
+ dev_dbg(priv->adapter->dev, "info: current beacon saved %d\n",
+ priv->curr_bcn_size);
+}
+
+/*
+ * This function frees the current BSS descriptor beacon buffer.
+ */
+void
+mwifiex_free_curr_bcn(struct mwifiex_private *priv)
+{
+ kfree(priv->curr_bcn_buf);
+ priv->curr_bcn_buf = NULL;
+}
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
new file mode 100644
index 000000000000..d425dbd91d19
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -0,0 +1,1754 @@
+/*
+ * Marvell Wireless LAN device driver: SDIO specific handling
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include <linux/firmware.h>
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+#include "sdio.h"
+
+
+#define SDIO_VERSION "1.0"
+
+static struct mwifiex_if_ops sdio_ops;
+
+static struct semaphore add_remove_card_sem;
+
+/*
+ * SDIO probe.
+ *
+ * This function probes an mwifiex device and registers it. It allocates
+ * the card structure, enables SDIO function number and initiates the
+ * device registration and initialization procedure by adding a logical
+ * interface.
+ */
+static int
+mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
+{
+ int ret;
+ struct sdio_mmc_card *card = NULL;
+
+ pr_debug("info: vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n",
+ func->vendor, func->device, func->class, func->num);
+
+ card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL);
+ if (!card) {
+ pr_err("%s: failed to alloc memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ card->func = func;
+
+ func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
+
+ sdio_claim_host(func);
+ ret = sdio_enable_func(func);
+ sdio_release_host(func);
+
+ if (ret) {
+ pr_err("%s: failed to enable function\n", __func__);
+ kfree(card);
+ return -EIO;
+ }
+
+ if (mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops)) {
+ pr_err("%s: add card failed\n", __func__);
+ kfree(card);
+ sdio_claim_host(func);
+ ret = sdio_disable_func(func);
+ sdio_release_host(func);
+ ret = -1;
+ }
+
+ return ret;
+}
+
+/*
+ * SDIO remove.
+ *
+ * This function removes the interface and frees up the card structure.
+ */
+static void
+mwifiex_sdio_remove(struct sdio_func *func)
+{
+ struct sdio_mmc_card *card;
+
+ pr_debug("info: SDIO func num=%d\n", func->num);
+
+ if (func) {
+ card = sdio_get_drvdata(func);
+ if (card) {
+ mwifiex_remove_card(card->adapter,
+ &add_remove_card_sem);
+ kfree(card);
+ }
+ }
+}
+
+/*
+ * SDIO suspend.
+ *
+ * Kernel needs to suspend all functions separately. Therefore all
+ * registered functions must have drivers with suspend and resume
+ * methods. Failing that the kernel simply removes the whole card.
+ *
+ * If already not suspended, this function allocates and sends a host
+ * sleep activate request to the firmware and turns off the traffic.
+ */
+static int mwifiex_sdio_suspend(struct device *dev)
+{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ struct sdio_mmc_card *card;
+ struct mwifiex_adapter *adapter;
+ mmc_pm_flag_t pm_flag = 0;
+ int hs_actived = 0;
+ int i;
+ int ret = 0;
+
+ if (func) {
+ pm_flag = sdio_get_host_pm_caps(func);
+ pr_debug("cmd: %s: suspend: PM flag = 0x%x\n",
+ sdio_func_id(func), pm_flag);
+ if (!(pm_flag & MMC_PM_KEEP_POWER)) {
+ pr_err("%s: cannot remain alive while host is"
+ " suspended\n", sdio_func_id(func));
+ return -ENOSYS;
+ }
+
+ card = sdio_get_drvdata(func);
+ if (!card || !card->adapter) {
+ pr_err("suspend: invalid card or adapter\n");
+ return 0;
+ }
+ } else {
+ pr_err("suspend: sdio_func is not specified\n");
+ return 0;
+ }
+
+ adapter = card->adapter;
+
+ /* Enable the Host Sleep */
+ hs_actived = mwifiex_enable_hs(adapter);
+ if (hs_actived) {
+ pr_debug("cmd: suspend with MMC_PM_KEEP_POWER\n");
+ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+ }
+
+ /* Indicate device suspended */
+ adapter->is_suspended = true;
+
+ for (i = 0; i < adapter->priv_num; i++)
+ netif_carrier_off(adapter->priv[i]->netdev);
+
+ return ret;
+}
+
+/*
+ * SDIO resume.
+ *
+ * Kernel needs to suspend all functions separately. Therefore all
+ * registered functions must have drivers with suspend and resume
+ * methods. Failing that the kernel simply removes the whole card.
+ *
+ * If already not resumed, this function turns on the traffic and
+ * sends a host sleep cancel request to the firmware.
+ */
+static int mwifiex_sdio_resume(struct device *dev)
+{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ struct sdio_mmc_card *card;
+ struct mwifiex_adapter *adapter;
+ mmc_pm_flag_t pm_flag = 0;
+ int i;
+
+ if (func) {
+ pm_flag = sdio_get_host_pm_caps(func);
+ card = sdio_get_drvdata(func);
+ if (!card || !card->adapter) {
+ pr_err("resume: invalid card or adapter\n");
+ return 0;
+ }
+ } else {
+ pr_err("resume: sdio_func is not specified\n");
+ return 0;
+ }
+
+ adapter = card->adapter;
+
+ if (!adapter->is_suspended) {
+ dev_warn(adapter->dev, "device already resumed\n");
+ return 0;
+ }
+
+ adapter->is_suspended = false;
+
+ for (i = 0; i < adapter->priv_num; i++)
+ if (adapter->priv[i]->media_connected)
+ netif_carrier_on(adapter->priv[i]->netdev);
+
+ /* Disable Host Sleep */
+ mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
+ MWIFIEX_ASYNC_CMD);
+
+ return 0;
+}
+
+/* Device ID for SD8787 */
+#define SDIO_DEVICE_ID_MARVELL_8787 (0x9119)
+
+/* WLAN IDs */
+static const struct sdio_device_id mwifiex_ids[] = {
+ {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8787)},
+ {},
+};
+
+MODULE_DEVICE_TABLE(sdio, mwifiex_ids);
+
+static const struct dev_pm_ops mwifiex_sdio_pm_ops = {
+ .suspend = mwifiex_sdio_suspend,
+ .resume = mwifiex_sdio_resume,
+};
+
+static struct sdio_driver mwifiex_sdio = {
+ .name = "mwifiex_sdio",
+ .id_table = mwifiex_ids,
+ .probe = mwifiex_sdio_probe,
+ .remove = mwifiex_sdio_remove,
+ .drv = {
+ .owner = THIS_MODULE,
+ .pm = &mwifiex_sdio_pm_ops,
+ }
+};
+
+/*
+ * This function writes data into SDIO card register.
+ */
+static int
+mwifiex_write_reg(struct mwifiex_adapter *adapter, u32 reg, u32 data)
+{
+ struct sdio_mmc_card *card = adapter->card;
+ int ret = -1;
+
+ sdio_claim_host(card->func);
+ sdio_writeb(card->func, (u8) data, reg, &ret);
+ sdio_release_host(card->func);
+
+ return ret;
+}
+
+/*
+ * This function reads data from SDIO card register.
+ */
+static int
+mwifiex_read_reg(struct mwifiex_adapter *adapter, u32 reg, u32 *data)
+{
+ struct sdio_mmc_card *card = adapter->card;
+ int ret = -1;
+ u8 val;
+
+ sdio_claim_host(card->func);
+ val = sdio_readb(card->func, reg, &ret);
+ sdio_release_host(card->func);
+
+ *data = val;
+
+ return ret;
+}
+
+/*
+ * This function writes multiple data into SDIO card memory.
+ *
+ * This does not work in suspended mode.
+ */
+static int
+mwifiex_write_data_sync(struct mwifiex_adapter *adapter,
+ u8 *buffer, u32 pkt_len, u32 port)
+{
+ struct sdio_mmc_card *card = adapter->card;
+ int ret = -1;
+ u8 blk_mode =
+ (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE;
+ u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1;
+ u32 blk_cnt =
+ (blk_mode ==
+ BLOCK_MODE) ? (pkt_len /
+ MWIFIEX_SDIO_BLOCK_SIZE) : pkt_len;
+ u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK);
+
+ if (adapter->is_suspended) {
+ dev_err(adapter->dev,
+ "%s: not allowed while suspended\n", __func__);
+ return -1;
+ }
+
+ sdio_claim_host(card->func);
+
+ if (!sdio_writesb(card->func, ioport, buffer, blk_cnt * blk_size))
+ ret = 0;
+
+ sdio_release_host(card->func);
+
+ return ret;
+}
+
+/*
+ * This function reads multiple data from SDIO card memory.
+ */
+static int mwifiex_read_data_sync(struct mwifiex_adapter *adapter, u8 *buffer,
+ u32 len, u32 port, u8 claim)
+{
+ struct sdio_mmc_card *card = adapter->card;
+ int ret = -1;
+ u8 blk_mode =
+ (port & MWIFIEX_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE;
+ u32 blk_size = (blk_mode == BLOCK_MODE) ? MWIFIEX_SDIO_BLOCK_SIZE : 1;
+ u32 blk_cnt =
+ (blk_mode ==
+ BLOCK_MODE) ? (len / MWIFIEX_SDIO_BLOCK_SIZE) : len;
+ u32 ioport = (port & MWIFIEX_SDIO_IO_PORT_MASK);
+
+ if (claim)
+ sdio_claim_host(card->func);
+
+ if (!sdio_readsb(card->func, buffer, ioport, blk_cnt * blk_size))
+ ret = 0;
+
+ if (claim)
+ sdio_release_host(card->func);
+
+ return ret;
+}
+
+/*
+ * This function wakes up the card.
+ *
+ * A host power up command is written to the card configuration
+ * register to wake up the card.
+ */
+static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
+{
+ dev_dbg(adapter->dev, "event: wakeup device...\n");
+
+ return mwifiex_write_reg(adapter, CONFIGURATION_REG, HOST_POWER_UP);
+}
+
+/*
+ * This function is called after the card has woken up.
+ *
+ * The card configuration register is reset.
+ */
+static int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter)
+{
+ dev_dbg(adapter->dev, "cmd: wakeup device completed\n");
+
+ return mwifiex_write_reg(adapter, CONFIGURATION_REG, 0);
+}
+
+/*
+ * This function initializes the IO ports.
+ *
+ * The following operations are performed -
+ * - Read the IO ports (0, 1 and 2)
+ * - Set host interrupt Reset-To-Read to clear
+ * - Set auto re-enable interrupt
+ */
+static int mwifiex_init_sdio_ioport(struct mwifiex_adapter *adapter)
+{
+ u32 reg;
+
+ adapter->ioport = 0;
+
+ /* Read the IO port */
+ if (!mwifiex_read_reg(adapter, IO_PORT_0_REG, &reg))
+ adapter->ioport |= (reg & 0xff);
+ else
+ return -1;
+
+ if (!mwifiex_read_reg(adapter, IO_PORT_1_REG, &reg))
+ adapter->ioport |= ((reg & 0xff) << 8);
+ else
+ return -1;
+
+ if (!mwifiex_read_reg(adapter, IO_PORT_2_REG, &reg))
+ adapter->ioport |= ((reg & 0xff) << 16);
+ else
+ return -1;
+
+ pr_debug("info: SDIO FUNC1 IO port: %#x\n", adapter->ioport);
+
+ /* Set Host interrupt reset to read to clear */
+ if (!mwifiex_read_reg(adapter, HOST_INT_RSR_REG, &reg))
+ mwifiex_write_reg(adapter, HOST_INT_RSR_REG,
+ reg | SDIO_INT_MASK);
+ else
+ return -1;
+
+ /* Dnld/Upld ready set to auto reset */
+ if (!mwifiex_read_reg(adapter, CARD_MISC_CFG_REG, &reg))
+ mwifiex_write_reg(adapter, CARD_MISC_CFG_REG,
+ reg | AUTO_RE_ENABLE_INT);
+ else
+ return -1;
+
+ return 0;
+}
+
+/*
+ * This function sends data to the card.
+ */
+static int mwifiex_write_data_to_card(struct mwifiex_adapter *adapter,
+ u8 *payload, u32 pkt_len, u32 port)
+{
+ u32 i = 0;
+ int ret;
+
+ do {
+ ret = mwifiex_write_data_sync(adapter, payload, pkt_len, port);
+ if (ret) {
+ i++;
+ dev_err(adapter->dev, "host_to_card, write iomem"
+ " (%d) failed: %d\n", i, ret);
+ if (mwifiex_write_reg(adapter,
+ CONFIGURATION_REG, 0x04))
+ dev_err(adapter->dev, "write CFG reg failed\n");
+
+ ret = -1;
+ if (i > MAX_WRITE_IOMEM_RETRY)
+ return ret;
+ }
+ } while (ret == -1);
+
+ return ret;
+}
+
+/*
+ * This function gets the read port.
+ *
+ * If control port bit is set in MP read bitmap, the control port
+ * is returned, otherwise the current read port is returned and
+ * the value is increased (provided it does not reach the maximum
+ * limit, in which case it is reset to 1)
+ */
+static int mwifiex_get_rd_port(struct mwifiex_adapter *adapter, u8 *port)
+{
+ struct sdio_mmc_card *card = adapter->card;
+ u16 rd_bitmap = card->mp_rd_bitmap;
+
+ dev_dbg(adapter->dev, "data: mp_rd_bitmap=0x%04x\n", rd_bitmap);
+
+ if (!(rd_bitmap & (CTRL_PORT_MASK | DATA_PORT_MASK)))
+ return -1;
+
+ if (card->mp_rd_bitmap & CTRL_PORT_MASK) {
+ card->mp_rd_bitmap &= (u16) (~CTRL_PORT_MASK);
+ *port = CTRL_PORT;
+ dev_dbg(adapter->dev, "data: port=%d mp_rd_bitmap=0x%04x\n",
+ *port, card->mp_rd_bitmap);
+ } else {
+ if (card->mp_rd_bitmap & (1 << card->curr_rd_port)) {
+ card->mp_rd_bitmap &=
+ (u16) (~(1 << card->curr_rd_port));
+ *port = card->curr_rd_port;
+
+ if (++card->curr_rd_port == MAX_PORT)
+ card->curr_rd_port = 1;
+ } else {
+ return -1;
+ }
+
+ dev_dbg(adapter->dev,
+ "data: port=%d mp_rd_bitmap=0x%04x -> 0x%04x\n",
+ *port, rd_bitmap, card->mp_rd_bitmap);
+ }
+ return 0;
+}
+
+/*
+ * This function gets the write port for data.
+ *
+ * The current write port is returned if available and the value is
+ * increased (provided it does not reach the maximum limit, in which
+ * case it is reset to 1)
+ */
+static int mwifiex_get_wr_port_data(struct mwifiex_adapter *adapter, u8 *port)
+{
+ struct sdio_mmc_card *card = adapter->card;
+ u16 wr_bitmap = card->mp_wr_bitmap;
+
+ dev_dbg(adapter->dev, "data: mp_wr_bitmap=0x%04x\n", wr_bitmap);
+
+ if (!(wr_bitmap & card->mp_data_port_mask))
+ return -1;
+
+ if (card->mp_wr_bitmap & (1 << card->curr_wr_port)) {
+ card->mp_wr_bitmap &= (u16) (~(1 << card->curr_wr_port));
+ *port = card->curr_wr_port;
+ if (++card->curr_wr_port == card->mp_end_port)
+ card->curr_wr_port = 1;
+ } else {
+ adapter->data_sent = true;
+ return -EBUSY;
+ }
+
+ if (*port == CTRL_PORT) {
+ dev_err(adapter->dev, "invalid data port=%d cur port=%d"
+ " mp_wr_bitmap=0x%04x -> 0x%04x\n",
+ *port, card->curr_wr_port, wr_bitmap,
+ card->mp_wr_bitmap);
+ return -1;
+ }
+
+ dev_dbg(adapter->dev, "data: port=%d mp_wr_bitmap=0x%04x -> 0x%04x\n",
+ *port, wr_bitmap, card->mp_wr_bitmap);
+
+ return 0;
+}
+
+/*
+ * This function polls the card status.
+ */
+static int
+mwifiex_sdio_poll_card_status(struct mwifiex_adapter *adapter, u8 bits)
+{
+ u32 tries;
+ u32 cs;
+
+ for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
+ if (mwifiex_read_reg(adapter, CARD_STATUS_REG, &cs))
+ break;
+ else if ((cs & bits) == bits)
+ return 0;
+
+ udelay(10);
+ }
+
+ dev_err(adapter->dev, "poll card status failed, tries = %d\n",
+ tries);
+ return -1;
+}
+
+/*
+ * This function reads the firmware status.
+ */
+static int
+mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat)
+{
+ u32 fws0, fws1;
+
+ if (mwifiex_read_reg(adapter, CARD_FW_STATUS0_REG, &fws0))
+ return -1;
+
+ if (mwifiex_read_reg(adapter, CARD_FW_STATUS1_REG, &fws1))
+ return -1;
+
+ *dat = (u16) ((fws1 << 8) | fws0);
+
+ return 0;
+}
+
+/*
+ * This function disables the host interrupt.
+ *
+ * The host interrupt mask is read, the disable bit is reset and
+ * written back to the card host interrupt mask register.
+ */
+static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter)
+{
+ u32 host_int_mask;
+
+ /* Read back the host_int_mask register */
+ if (mwifiex_read_reg(adapter, HOST_INT_MASK_REG, &host_int_mask))
+ return -1;
+
+ /* Update with the mask and write back to the register */
+ host_int_mask &= ~HOST_INT_DISABLE;
+
+ if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, host_int_mask)) {
+ dev_err(adapter->dev, "disable host interrupt failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * This function enables the host interrupt.
+ *
+ * The host interrupt enable mask is written to the card
+ * host interrupt mask register.
+ */
+static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter)
+{
+ /* Simply write the mask to the register */
+ if (mwifiex_write_reg(adapter, HOST_INT_MASK_REG, HOST_INT_ENABLE)) {
+ dev_err(adapter->dev, "enable host interrupt failed\n");
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * This function sends a data buffer to the card.
+ */
+static int mwifiex_sdio_card_to_host(struct mwifiex_adapter *adapter,
+ u32 *type, u8 *buffer,
+ u32 npayload, u32 ioport)
+{
+ int ret;
+ u32 nb;
+
+ if (!buffer) {
+ dev_err(adapter->dev, "%s: buffer is NULL\n", __func__);
+ return -1;
+ }
+
+ ret = mwifiex_read_data_sync(adapter, buffer, npayload, ioport, 1);
+
+ if (ret) {
+ dev_err(adapter->dev, "%s: read iomem failed: %d\n", __func__,
+ ret);
+ return -1;
+ }
+
+ nb = le16_to_cpu(*(__le16 *) (buffer));
+ if (nb > npayload) {
+ dev_err(adapter->dev, "%s: invalid packet, nb=%d, npayload=%d\n",
+ __func__, nb, npayload);
+ return -1;
+ }
+
+ *type = le16_to_cpu(*(__le16 *) (buffer + 2));
+
+ return ret;
+}
+
+/*
+ * This function downloads the firmware to the card.
+ *
+ * Firmware is downloaded to the card in blocks. Every block download
+ * is tested for CRC errors, and retried a number of times before
+ * returning failure.
+ */
+static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
+ struct mwifiex_fw_image *fw)
+{
+ int ret;
+ u8 *firmware = fw->fw_buf;
+ u32 firmware_len = fw->fw_len;
+ u32 offset = 0;
+ u32 base0, base1;
+ u8 *fwbuf;
+ u16 len = 0;
+ u32 txlen, tx_blocks = 0, tries;
+ u32 i = 0;
+
+ if (!firmware_len) {
+ dev_err(adapter->dev, "firmware image not found!"
+ " Terminating download\n");
+ return -1;
+ }
+
+ dev_dbg(adapter->dev, "info: downloading FW image (%d bytes)\n",
+ firmware_len);
+
+ /* Assume that the allocated buffer is 8-byte aligned */
+ fwbuf = kzalloc(MWIFIEX_UPLD_SIZE, GFP_KERNEL);
+ if (!fwbuf) {
+ dev_err(adapter->dev, "unable to alloc buffer for firmware."
+ " Terminating download\n");
+ return -ENOMEM;
+ }
+
+ /* Perform firmware data transfer */
+ do {
+ /* The host polls for the DN_LD_CARD_RDY and CARD_IO_READY
+ bits */
+ ret = mwifiex_sdio_poll_card_status(adapter, CARD_IO_READY |
+ DN_LD_CARD_RDY);
+ if (ret) {
+ dev_err(adapter->dev, "FW download with helper:"
+ " poll status timeout @ %d\n", offset);
+ goto done;
+ }
+
+ /* More data? */
+ if (offset >= firmware_len)
+ break;
+
+ for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
+ ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_0,
+ &base0);
+ if (ret) {
+ dev_err(adapter->dev, "dev BASE0 register read"
+ " failed: base0=0x%04X(%d). Terminating "
+ "download\n", base0, base0);
+ goto done;
+ }
+ ret = mwifiex_read_reg(adapter, HOST_F1_RD_BASE_1,
+ &base1);
+ if (ret) {
+ dev_err(adapter->dev, "dev BASE1 register read"
+ " failed: base1=0x%04X(%d). Terminating "
+ "download\n", base1, base1);
+ goto done;
+ }
+ len = (u16) (((base1 & 0xff) << 8) | (base0 & 0xff));
+
+ if (len)
+ break;
+
+ udelay(10);
+ }
+
+ if (!len) {
+ break;
+ } else if (len > MWIFIEX_UPLD_SIZE) {
+ dev_err(adapter->dev, "FW download failed @ %d,"
+ " invalid length %d\n", offset, len);
+ ret = -1;
+ goto done;
+ }
+
+ txlen = len;
+
+ if (len & BIT(0)) {
+ i++;
+ if (i > MAX_WRITE_IOMEM_RETRY) {
+ dev_err(adapter->dev, "FW download failed @"
+ " %d, over max retry count\n", offset);
+ ret = -1;
+ goto done;
+ }
+ dev_err(adapter->dev, "CRC indicated by the helper:"
+ " len = 0x%04X, txlen = %d\n", len, txlen);
+ len &= ~BIT(0);
+ /* Setting this to 0 to resend from same offset */
+ txlen = 0;
+ } else {
+ i = 0;
+
+ /* Set blocksize to transfer - checking for last
+ block */
+ if (firmware_len - offset < txlen)
+ txlen = firmware_len - offset;
+
+ tx_blocks = (txlen + MWIFIEX_SDIO_BLOCK_SIZE -
+ 1) / MWIFIEX_SDIO_BLOCK_SIZE;
+
+ /* Copy payload to buffer */
+ memmove(fwbuf, &firmware[offset], txlen);
+ }
+
+ ret = mwifiex_write_data_sync(adapter, fwbuf, tx_blocks *
+ MWIFIEX_SDIO_BLOCK_SIZE,
+ adapter->ioport);
+ if (ret) {
+ dev_err(adapter->dev, "FW download, write iomem (%d)"
+ " failed @ %d\n", i, offset);
+ if (mwifiex_write_reg(adapter, CONFIGURATION_REG, 0x04))
+ dev_err(adapter->dev, "write CFG reg failed\n");
+
+ ret = -1;
+ goto done;
+ }
+
+ offset += txlen;
+ } while (true);
+
+ dev_dbg(adapter->dev, "info: FW download over, size %d bytes\n",
+ offset);
+
+ ret = 0;
+done:
+ kfree(fwbuf);
+ return ret;
+}
+
+/*
+ * This function checks the firmware status in card.
+ *
+ * The winner interface is also determined by this function.
+ */
+static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
+ u32 poll_num, int *winner)
+{
+ int ret = 0;
+ u16 firmware_stat;
+ u32 tries;
+ u32 winner_status;
+
+ /* Wait for firmware initialization event */
+ for (tries = 0; tries < poll_num; tries++) {
+ ret = mwifiex_sdio_read_fw_status(adapter, &firmware_stat);
+ if (ret)
+ continue;
+ if (firmware_stat == FIRMWARE_READY) {
+ ret = 0;
+ break;
+ } else {
+ mdelay(100);
+ ret = -1;
+ }
+ }
+
+ if (winner && ret) {
+ if (mwifiex_read_reg
+ (adapter, CARD_FW_STATUS0_REG, &winner_status))
+ winner_status = 0;
+
+ if (winner_status)
+ *winner = 0;
+ else
+ *winner = 1;
+ }
+ return ret;
+}
+
+/*
+ * This function reads the interrupt status from card.
+ */
+static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
+{
+ struct sdio_mmc_card *card = adapter->card;
+ u32 sdio_ireg;
+ unsigned long flags;
+
+ if (mwifiex_read_data_sync(adapter, card->mp_regs, MAX_MP_REGS,
+ REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK,
+ 0)) {
+ dev_err(adapter->dev, "read mp_regs failed\n");
+ return;
+ }
+
+ sdio_ireg = card->mp_regs[HOST_INTSTATUS_REG];
+ if (sdio_ireg) {
+ /*
+ * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
+ * Clear the interrupt status register
+ */
+ dev_dbg(adapter->dev, "int: sdio_ireg = %#x\n", sdio_ireg);
+ spin_lock_irqsave(&adapter->int_lock, flags);
+ adapter->int_status |= sdio_ireg;
+ spin_unlock_irqrestore(&adapter->int_lock, flags);
+ }
+}
+
+/*
+ * SDIO interrupt handler.
+ *
+ * This function reads the interrupt status from firmware and assigns
+ * the main process in workqueue which will handle the interrupt.
+ */
+static void
+mwifiex_sdio_interrupt(struct sdio_func *func)
+{
+ struct mwifiex_adapter *adapter;
+ struct sdio_mmc_card *card;
+
+ card = sdio_get_drvdata(func);
+ if (!card || !card->adapter) {
+ pr_debug("int: func=%p card=%p adapter=%p\n",
+ func, card, card ? card->adapter : NULL);
+ return;
+ }
+ adapter = card->adapter;
+
+ if (adapter->surprise_removed)
+ return;
+
+ if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP)
+ adapter->ps_state = PS_STATE_AWAKE;
+
+ mwifiex_interrupt_status(adapter);
+ queue_work(adapter->workqueue, &adapter->main_work);
+}
+
+/*
+ * This function decodes a received packet.
+ *
+ * Based on the type, the packet is treated as either a data, or
+ * a command response, or an event, and the correct handler
+ * function is invoked.
+ */
+static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter,
+ struct sk_buff *skb, u32 upld_typ)
+{
+ u8 *cmd_buf;
+
+ skb_pull(skb, INTF_HEADER_LEN);
+
+ switch (upld_typ) {
+ case MWIFIEX_TYPE_DATA:
+ dev_dbg(adapter->dev, "info: --- Rx: Data packet ---\n");
+ mwifiex_handle_rx_packet(adapter, skb);
+ break;
+
+ case MWIFIEX_TYPE_CMD:
+ dev_dbg(adapter->dev, "info: --- Rx: Cmd Response ---\n");
+ /* take care of curr_cmd = NULL case */
+ if (!adapter->curr_cmd) {
+ cmd_buf = adapter->upld_buf;
+
+ if (adapter->ps_state == PS_STATE_SLEEP_CFM)
+ mwifiex_process_sleep_confirm_resp(adapter,
+ skb->data, skb->len);
+
+ memcpy(cmd_buf, skb->data, min_t(u32,
+ MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len));
+
+ dev_kfree_skb_any(skb);
+ } else {
+ adapter->cmd_resp_received = true;
+ adapter->curr_cmd->resp_skb = skb;
+ }
+ break;
+
+ case MWIFIEX_TYPE_EVENT:
+ dev_dbg(adapter->dev, "info: --- Rx: Event ---\n");
+ adapter->event_cause = *(u32 *) skb->data;
+
+ skb_pull(skb, MWIFIEX_EVENT_HEADER_LEN);
+
+ if ((skb->len > 0) && (skb->len < MAX_EVENT_SIZE))
+ memcpy(adapter->event_body, skb->data, skb->len);
+
+ /* event cause has been saved to adapter->event_cause */
+ adapter->event_received = true;
+ adapter->event_skb = skb;
+
+ break;
+
+ default:
+ dev_err(adapter->dev, "unknown upload type %#x\n", upld_typ);
+ dev_kfree_skb_any(skb);
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * This function transfers received packets from card to driver, performing
+ * aggregation if required.
+ *
+ * For data received on control port, or if aggregation is disabled, the
+ * received buffers are uploaded as separate packets. However, if aggregation
+ * is enabled and required, the buffers are copied onto an aggregation buffer,
+ * provided there is space left, processed and finally uploaded.
+ */
+static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter,
+ struct sk_buff *skb, u8 port)
+{
+ struct sdio_mmc_card *card = adapter->card;
+ s32 f_do_rx_aggr = 0;
+ s32 f_do_rx_cur = 0;
+ s32 f_aggr_cur = 0;
+ struct sk_buff *skb_deaggr;
+ u32 pind;
+ u32 pkt_len, pkt_type = 0;
+ u8 *curr_ptr;
+ u32 rx_len = skb->len;
+
+ if (port == CTRL_PORT) {
+ /* Read the command Resp without aggr */
+ dev_dbg(adapter->dev, "info: %s: no aggregation for cmd "
+ "response\n", __func__);
+
+ f_do_rx_cur = 1;
+ goto rx_curr_single;
+ }
+
+ if (!card->mpa_rx.enabled) {
+ dev_dbg(adapter->dev, "info: %s: rx aggregation disabled\n",
+ __func__);
+
+ f_do_rx_cur = 1;
+ goto rx_curr_single;
+ }
+
+ if (card->mp_rd_bitmap & (~((u16) CTRL_PORT_MASK))) {
+ /* Some more data RX pending */
+ dev_dbg(adapter->dev, "info: %s: not last packet\n", __func__);
+
+ if (MP_RX_AGGR_IN_PROGRESS(card)) {
+ if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) {
+ f_aggr_cur = 1;
+ } else {
+ /* No room in Aggr buf, do rx aggr now */
+ f_do_rx_aggr = 1;
+ f_do_rx_cur = 1;
+ }
+ } else {
+ /* Rx aggr not in progress */
+ f_aggr_cur = 1;
+ }
+
+ } else {
+ /* No more data RX pending */
+ dev_dbg(adapter->dev, "info: %s: last packet\n", __func__);
+
+ if (MP_RX_AGGR_IN_PROGRESS(card)) {
+ f_do_rx_aggr = 1;
+ if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len))
+ f_aggr_cur = 1;
+ else
+ /* No room in Aggr buf, do rx aggr now */
+ f_do_rx_cur = 1;
+ } else {
+ f_do_rx_cur = 1;
+ }
+ }
+
+ if (f_aggr_cur) {
+ dev_dbg(adapter->dev, "info: current packet aggregation\n");
+ /* Curr pkt can be aggregated */
+ MP_RX_AGGR_SETUP(card, skb, port);
+
+ if (MP_RX_AGGR_PKT_LIMIT_REACHED(card) ||
+ MP_RX_AGGR_PORT_LIMIT_REACHED(card)) {
+ dev_dbg(adapter->dev, "info: %s: aggregated packet "
+ "limit reached\n", __func__);
+ /* No more pkts allowed in Aggr buf, rx it */
+ f_do_rx_aggr = 1;
+ }
+ }
+
+ if (f_do_rx_aggr) {
+ /* do aggr RX now */
+ dev_dbg(adapter->dev, "info: do_rx_aggr: num of packets: %d\n",
+ card->mpa_rx.pkt_cnt);
+
+ if (mwifiex_read_data_sync(adapter, card->mpa_rx.buf,
+ card->mpa_rx.buf_len,
+ (adapter->ioport | 0x1000 |
+ (card->mpa_rx.ports << 4)) +
+ card->mpa_rx.start_port, 1))
+ return -1;
+
+ curr_ptr = card->mpa_rx.buf;
+
+ for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) {
+
+ /* get curr PKT len & type */
+ pkt_len = *(u16 *) &curr_ptr[0];
+ pkt_type = *(u16 *) &curr_ptr[2];
+
+ /* copy pkt to deaggr buf */
+ skb_deaggr = card->mpa_rx.skb_arr[pind];
+
+ if ((pkt_type == MWIFIEX_TYPE_DATA) && (pkt_len <=
+ card->mpa_rx.len_arr[pind])) {
+
+ memcpy(skb_deaggr->data, curr_ptr, pkt_len);
+
+ skb_trim(skb_deaggr, pkt_len);
+
+ /* Process de-aggr packet */
+ mwifiex_decode_rx_packet(adapter, skb_deaggr,
+ pkt_type);
+ } else {
+ dev_err(adapter->dev, "wrong aggr pkt:"
+ " type=%d len=%d max_len=%d\n",
+ pkt_type, pkt_len,
+ card->mpa_rx.len_arr[pind]);
+ dev_kfree_skb_any(skb_deaggr);
+ }
+ curr_ptr += card->mpa_rx.len_arr[pind];
+ }
+ MP_RX_AGGR_BUF_RESET(card);
+ }
+
+rx_curr_single:
+ if (f_do_rx_cur) {
+ dev_dbg(adapter->dev, "info: RX: port: %d, rx_len: %d\n",
+ port, rx_len);
+
+ if (mwifiex_sdio_card_to_host(adapter, &pkt_type,
+ skb->data, skb->len,
+ adapter->ioport + port))
+ return -1;
+
+ mwifiex_decode_rx_packet(adapter, skb, pkt_type);
+ }
+
+ return 0;
+}
+
+/*
+ * This function checks the current interrupt status.
+ *
+ * The following interrupts are checked and handled by this function -
+ * - Data sent
+ * - Command sent
+ * - Packets received
+ *
+ * Since the firmware does not generate download ready interrupt if the
+ * port updated is command port only, command sent interrupt checking
+ * should be done manually, and for every SDIO interrupt.
+ *
+ * In case of Rx packets received, the packets are uploaded from card to
+ * host and processed accordingly.
+ */
+static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
+{
+ struct sdio_mmc_card *card = adapter->card;
+ int ret = 0;
+ u8 sdio_ireg;
+ struct sk_buff *skb;
+ u8 port = CTRL_PORT;
+ u32 len_reg_l, len_reg_u;
+ u32 rx_blocks;
+ u16 rx_len;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->int_lock, flags);
+ sdio_ireg = adapter->int_status;
+ adapter->int_status = 0;
+ spin_unlock_irqrestore(&adapter->int_lock, flags);
+
+ if (!sdio_ireg)
+ return ret;
+
+ if (sdio_ireg & DN_LD_HOST_INT_STATUS) {
+ card->mp_wr_bitmap = ((u16) card->mp_regs[WR_BITMAP_U]) << 8;
+ card->mp_wr_bitmap |= (u16) card->mp_regs[WR_BITMAP_L];
+ dev_dbg(adapter->dev, "int: DNLD: wr_bitmap=0x%04x\n",
+ card->mp_wr_bitmap);
+ if (adapter->data_sent &&
+ (card->mp_wr_bitmap & card->mp_data_port_mask)) {
+ dev_dbg(adapter->dev,
+ "info: <--- Tx DONE Interrupt --->\n");
+ adapter->data_sent = false;
+ }
+ }
+
+ /* As firmware will not generate download ready interrupt if the port
+ updated is command port only, cmd_sent should be done for any SDIO
+ interrupt. */
+ if (adapter->cmd_sent) {
+ /* Check if firmware has attach buffer at command port and
+ update just that in wr_bit_map. */
+ card->mp_wr_bitmap |=
+ (u16) card->mp_regs[WR_BITMAP_L] & CTRL_PORT_MASK;
+ if (card->mp_wr_bitmap & CTRL_PORT_MASK)
+ adapter->cmd_sent = false;
+ }
+
+ dev_dbg(adapter->dev, "info: cmd_sent=%d data_sent=%d\n",
+ adapter->cmd_sent, adapter->data_sent);
+ if (sdio_ireg & UP_LD_HOST_INT_STATUS) {
+ card->mp_rd_bitmap = ((u16) card->mp_regs[RD_BITMAP_U]) << 8;
+ card->mp_rd_bitmap |= (u16) card->mp_regs[RD_BITMAP_L];
+ dev_dbg(adapter->dev, "int: UPLD: rd_bitmap=0x%04x\n",
+ card->mp_rd_bitmap);
+
+ while (true) {
+ ret = mwifiex_get_rd_port(adapter, &port);
+ if (ret) {
+ dev_dbg(adapter->dev,
+ "info: no more rd_port available\n");
+ break;
+ }
+ len_reg_l = RD_LEN_P0_L + (port << 1);
+ len_reg_u = RD_LEN_P0_U + (port << 1);
+ rx_len = ((u16) card->mp_regs[len_reg_u]) << 8;
+ rx_len |= (u16) card->mp_regs[len_reg_l];
+ dev_dbg(adapter->dev, "info: RX: port=%d rx_len=%u\n",
+ port, rx_len);
+ rx_blocks =
+ (rx_len + MWIFIEX_SDIO_BLOCK_SIZE -
+ 1) / MWIFIEX_SDIO_BLOCK_SIZE;
+ if (rx_len <= INTF_HEADER_LEN
+ || (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE) >
+ MWIFIEX_RX_DATA_BUF_SIZE) {
+ dev_err(adapter->dev, "invalid rx_len=%d\n",
+ rx_len);
+ return -1;
+ }
+ rx_len = (u16) (rx_blocks * MWIFIEX_SDIO_BLOCK_SIZE);
+
+ skb = dev_alloc_skb(rx_len);
+
+ if (!skb) {
+ dev_err(adapter->dev, "%s: failed to alloc skb",
+ __func__);
+ return -1;
+ }
+
+ skb_put(skb, rx_len);
+
+ dev_dbg(adapter->dev, "info: rx_len = %d skb->len = %d\n",
+ rx_len, skb->len);
+
+ if (mwifiex_sdio_card_to_host_mp_aggr(adapter, skb,
+ port)) {
+ u32 cr = 0;
+
+ dev_err(adapter->dev, "card_to_host_mpa failed:"
+ " int status=%#x\n", sdio_ireg);
+ if (mwifiex_read_reg(adapter,
+ CONFIGURATION_REG, &cr))
+ dev_err(adapter->dev,
+ "read CFG reg failed\n");
+
+ dev_dbg(adapter->dev,
+ "info: CFG reg val = %d\n", cr);
+ if (mwifiex_write_reg(adapter,
+ CONFIGURATION_REG,
+ (cr | 0x04)))
+ dev_err(adapter->dev,
+ "write CFG reg failed\n");
+
+ dev_dbg(adapter->dev, "info: write success\n");
+ if (mwifiex_read_reg(adapter,
+ CONFIGURATION_REG, &cr))
+ dev_err(adapter->dev,
+ "read CFG reg failed\n");
+
+ dev_dbg(adapter->dev,
+ "info: CFG reg val =%x\n", cr);
+ dev_kfree_skb_any(skb);
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * This function aggregates transmission buffers in driver and downloads
+ * the aggregated packet to card.
+ *
+ * The individual packets are aggregated by copying into an aggregation
+ * buffer and then downloaded to the card. Previous unsent packets in the
+ * aggregation buffer are pre-copied first before new packets are added.
+ * Aggregation is done till there is space left in the aggregation buffer,
+ * or till new packets are available.
+ *
+ * The function will only download the packet to the card when aggregation
+ * stops, otherwise it will just aggregate the packet in aggregation buffer
+ * and return.
+ */
+static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter,
+ u8 *payload, u32 pkt_len, u8 port,
+ u32 next_pkt_len)
+{
+ struct sdio_mmc_card *card = adapter->card;
+ int ret = 0;
+ s32 f_send_aggr_buf = 0;
+ s32 f_send_cur_buf = 0;
+ s32 f_precopy_cur_buf = 0;
+ s32 f_postcopy_cur_buf = 0;
+
+ if ((!card->mpa_tx.enabled) || (port == CTRL_PORT)) {
+ dev_dbg(adapter->dev, "info: %s: tx aggregation disabled\n",
+ __func__);
+
+ f_send_cur_buf = 1;
+ goto tx_curr_single;
+ }
+
+ if (next_pkt_len) {
+ /* More pkt in TX queue */
+ dev_dbg(adapter->dev, "info: %s: more packets in queue.\n",
+ __func__);
+
+ if (MP_TX_AGGR_IN_PROGRESS(card)) {
+ if (!MP_TX_AGGR_PORT_LIMIT_REACHED(card) &&
+ MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)) {
+ f_precopy_cur_buf = 1;
+
+ if (!(card->mp_wr_bitmap &
+ (1 << card->curr_wr_port))
+ || !MP_TX_AGGR_BUF_HAS_ROOM(
+ card, next_pkt_len))
+ f_send_aggr_buf = 1;
+ } else {
+ /* No room in Aggr buf, send it */
+ f_send_aggr_buf = 1;
+
+ if (MP_TX_AGGR_PORT_LIMIT_REACHED(card) ||
+ !(card->mp_wr_bitmap &
+ (1 << card->curr_wr_port)))
+ f_send_cur_buf = 1;
+ else
+ f_postcopy_cur_buf = 1;
+ }
+ } else {
+ if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len)
+ && (card->mp_wr_bitmap & (1 << card->curr_wr_port)))
+ f_precopy_cur_buf = 1;
+ else
+ f_send_cur_buf = 1;
+ }
+ } else {
+ /* Last pkt in TX queue */
+ dev_dbg(adapter->dev, "info: %s: Last packet in Tx Queue.\n",
+ __func__);
+
+ if (MP_TX_AGGR_IN_PROGRESS(card)) {
+ /* some packs in Aggr buf already */
+ f_send_aggr_buf = 1;
+
+ if (MP_TX_AGGR_BUF_HAS_ROOM(card, pkt_len))
+ f_precopy_cur_buf = 1;
+ else
+ /* No room in Aggr buf, send it */
+ f_send_cur_buf = 1;
+ } else {
+ f_send_cur_buf = 1;
+ }
+ }
+
+ if (f_precopy_cur_buf) {
+ dev_dbg(adapter->dev, "data: %s: precopy current buffer\n",
+ __func__);
+ MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port);
+
+ if (MP_TX_AGGR_PKT_LIMIT_REACHED(card) ||
+ MP_TX_AGGR_PORT_LIMIT_REACHED(card))
+ /* No more pkts allowed in Aggr buf, send it */
+ f_send_aggr_buf = 1;
+ }
+
+ if (f_send_aggr_buf) {
+ dev_dbg(adapter->dev, "data: %s: send aggr buffer: %d %d\n",
+ __func__,
+ card->mpa_tx.start_port, card->mpa_tx.ports);
+ ret = mwifiex_write_data_to_card(adapter, card->mpa_tx.buf,
+ card->mpa_tx.buf_len,
+ (adapter->ioport | 0x1000 |
+ (card->mpa_tx.ports << 4)) +
+ card->mpa_tx.start_port);
+
+ MP_TX_AGGR_BUF_RESET(card);
+ }
+
+tx_curr_single:
+ if (f_send_cur_buf) {
+ dev_dbg(adapter->dev, "data: %s: send current buffer %d\n",
+ __func__, port);
+ ret = mwifiex_write_data_to_card(adapter, payload, pkt_len,
+ adapter->ioport + port);
+ }
+
+ if (f_postcopy_cur_buf) {
+ dev_dbg(adapter->dev, "data: %s: postcopy current buffer\n",
+ __func__);
+ MP_TX_AGGR_BUF_PUT(card, payload, pkt_len, port);
+ }
+
+ return ret;
+}
+
+/*
+ * This function downloads data from driver to card.
+ *
+ * Both commands and data packets are transferred to the card by this
+ * function.
+ *
+ * This function adds the SDIO specific header to the front of the buffer
+ * before transferring. The header contains the length of the packet and
+ * the type. The firmware handles the packets based upon this set type.
+ */
+static int mwifiex_sdio_host_to_card(struct mwifiex_adapter *adapter,
+ u8 type, u8 *payload, u32 pkt_len,
+ struct mwifiex_tx_param *tx_param)
+{
+ struct sdio_mmc_card *card = adapter->card;
+ int ret;
+ u32 buf_block_len;
+ u32 blk_size;
+ u8 port = CTRL_PORT;
+
+ /* Allocate buffer and copy payload */
+ blk_size = MWIFIEX_SDIO_BLOCK_SIZE;
+ buf_block_len = (pkt_len + blk_size - 1) / blk_size;
+ *(u16 *) &payload[0] = (u16) pkt_len;
+ *(u16 *) &payload[2] = type;
+
+ /*
+ * This is SDIO specific header
+ * u16 length,
+ * u16 type (MWIFIEX_TYPE_DATA = 0, MWIFIEX_TYPE_CMD = 1,
+ * MWIFIEX_TYPE_EVENT = 3)
+ */
+ if (type == MWIFIEX_TYPE_DATA) {
+ ret = mwifiex_get_wr_port_data(adapter, &port);
+ if (ret) {
+ dev_err(adapter->dev, "%s: no wr_port available\n",
+ __func__);
+ return ret;
+ }
+ } else {
+ adapter->cmd_sent = true;
+ /* Type must be MWIFIEX_TYPE_CMD */
+
+ if (pkt_len <= INTF_HEADER_LEN ||
+ pkt_len > MWIFIEX_UPLD_SIZE)
+ dev_err(adapter->dev, "%s: payload=%p, nb=%d\n",
+ __func__, payload, pkt_len);
+ }
+
+ /* Transfer data to card */
+ pkt_len = buf_block_len * blk_size;
+
+ if (tx_param)
+ ret = mwifiex_host_to_card_mp_aggr(adapter, payload, pkt_len,
+ port, tx_param->next_pkt_len);
+ else
+ ret = mwifiex_host_to_card_mp_aggr(adapter, payload, pkt_len,
+ port, 0);
+
+ if (ret) {
+ if (type == MWIFIEX_TYPE_CMD)
+ adapter->cmd_sent = false;
+ if (type == MWIFIEX_TYPE_DATA)
+ adapter->data_sent = false;
+ } else {
+ if (type == MWIFIEX_TYPE_DATA) {
+ if (!(card->mp_wr_bitmap & (1 << card->curr_wr_port)))
+ adapter->data_sent = true;
+ else
+ adapter->data_sent = false;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * This function allocates the MPA Tx and Rx buffers.
+ */
+static int mwifiex_alloc_sdio_mpa_buffers(struct mwifiex_adapter *adapter,
+ u32 mpa_tx_buf_size, u32 mpa_rx_buf_size)
+{
+ struct sdio_mmc_card *card = adapter->card;
+ int ret = 0;
+
+ card->mpa_tx.buf = kzalloc(mpa_tx_buf_size, GFP_KERNEL);
+ if (!card->mpa_tx.buf) {
+ dev_err(adapter->dev, "could not alloc buffer for MP-A TX\n");
+ ret = -1;
+ goto error;
+ }
+
+ card->mpa_tx.buf_size = mpa_tx_buf_size;
+
+ card->mpa_rx.buf = kzalloc(mpa_rx_buf_size, GFP_KERNEL);
+ if (!card->mpa_rx.buf) {
+ dev_err(adapter->dev, "could not alloc buffer for MP-A RX\n");
+ ret = -1;
+ goto error;
+ }
+
+ card->mpa_rx.buf_size = mpa_rx_buf_size;
+
+error:
+ if (ret) {
+ kfree(card->mpa_tx.buf);
+ kfree(card->mpa_rx.buf);
+ }
+
+ return ret;
+}
+
+/*
+ * This function unregisters the SDIO device.
+ *
+ * The SDIO IRQ is released, the function is disabled and driver
+ * data is set to null.
+ */
+static void
+mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
+{
+ struct sdio_mmc_card *card = adapter->card;
+
+ if (adapter->card) {
+ /* Release the SDIO IRQ */
+ sdio_claim_host(card->func);
+ sdio_release_irq(card->func);
+ sdio_disable_func(card->func);
+ sdio_release_host(card->func);
+ sdio_set_drvdata(card->func, NULL);
+ }
+}
+
+/*
+ * This function registers the SDIO device.
+ *
+ * SDIO IRQ is claimed, block size is set and driver data is initialized.
+ */
+static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
+{
+ int ret = 0;
+ struct sdio_mmc_card *card = adapter->card;
+ struct sdio_func *func = card->func;
+
+ /* save adapter pointer in card */
+ card->adapter = adapter;
+
+ sdio_claim_host(func);
+
+ /* Request the SDIO IRQ */
+ ret = sdio_claim_irq(func, mwifiex_sdio_interrupt);
+ if (ret) {
+ pr_err("claim irq failed: ret=%d\n", ret);
+ goto disable_func;
+ }
+
+ /* Set block size */
+ ret = sdio_set_block_size(card->func, MWIFIEX_SDIO_BLOCK_SIZE);
+ if (ret) {
+ pr_err("cannot set SDIO block size\n");
+ ret = -1;
+ goto release_irq;
+ }
+
+ sdio_release_host(func);
+ sdio_set_drvdata(func, card);
+
+ adapter->dev = &func->dev;
+
+ return 0;
+
+release_irq:
+ sdio_release_irq(func);
+disable_func:
+ sdio_disable_func(func);
+ sdio_release_host(func);
+ adapter->card = NULL;
+
+ return -1;
+}
+
+/*
+ * This function initializes the SDIO driver.
+ *
+ * The following initializations steps are followed -
+ * - Read the Host interrupt status register to acknowledge
+ * the first interrupt got from bootloader
+ * - Disable host interrupt mask register
+ * - Get SDIO port
+ * - Get revision ID
+ * - Initialize SDIO variables in card
+ * - Allocate MP registers
+ * - Allocate MPA Tx and Rx buffers
+ */
+static int mwifiex_init_sdio(struct mwifiex_adapter *adapter)
+{
+ struct sdio_mmc_card *card = adapter->card;
+ int ret;
+ u32 sdio_ireg;
+
+ /*
+ * Read the HOST_INT_STATUS_REG for ACK the first interrupt got
+ * from the bootloader. If we don't do this we get a interrupt
+ * as soon as we register the irq.
+ */
+ mwifiex_read_reg(adapter, HOST_INTSTATUS_REG, &sdio_ireg);
+
+ /* Disable host interrupt mask register for SDIO */
+ mwifiex_sdio_disable_host_int(adapter);
+
+ /* Get SDIO ioport */
+ mwifiex_init_sdio_ioport(adapter);
+
+ /* Get revision ID */
+#define REV_ID_REG 0x5c
+ mwifiex_read_reg(adapter, REV_ID_REG, &adapter->revision_id);
+
+ /* Initialize SDIO variables in card */
+ card->mp_rd_bitmap = 0;
+ card->mp_wr_bitmap = 0;
+ card->curr_rd_port = 1;
+ card->curr_wr_port = 1;
+
+ card->mp_data_port_mask = DATA_PORT_MASK;
+
+ card->mpa_tx.buf_len = 0;
+ card->mpa_tx.pkt_cnt = 0;
+ card->mpa_tx.start_port = 0;
+
+ card->mpa_tx.enabled = 0;
+ card->mpa_tx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
+
+ card->mpa_rx.buf_len = 0;
+ card->mpa_rx.pkt_cnt = 0;
+ card->mpa_rx.start_port = 0;
+
+ card->mpa_rx.enabled = 0;
+ card->mpa_rx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
+
+ /* Allocate buffers for SDIO MP-A */
+ card->mp_regs = kzalloc(MAX_MP_REGS, GFP_KERNEL);
+ if (!card->mp_regs) {
+ dev_err(adapter->dev, "failed to alloc mp_regs\n");
+ return -ENOMEM;
+ }
+
+ ret = mwifiex_alloc_sdio_mpa_buffers(adapter,
+ SDIO_MP_TX_AGGR_DEF_BUF_SIZE,
+ SDIO_MP_RX_AGGR_DEF_BUF_SIZE);
+ if (ret) {
+ dev_err(adapter->dev, "failed to alloc sdio mp-a buffers\n");
+ kfree(card->mp_regs);
+ return -1;
+ }
+
+ return ret;
+}
+
+/*
+ * This function resets the MPA Tx and Rx buffers.
+ */
+static void mwifiex_cleanup_mpa_buf(struct mwifiex_adapter *adapter)
+{
+ struct sdio_mmc_card *card = adapter->card;
+
+ MP_TX_AGGR_BUF_RESET(card);
+ MP_RX_AGGR_BUF_RESET(card);
+}
+
+/*
+ * This function cleans up the allocated card buffers.
+ *
+ * The following are freed by this function -
+ * - MP registers
+ * - MPA Tx buffer
+ * - MPA Rx buffer
+ */
+static void mwifiex_cleanup_sdio(struct mwifiex_adapter *adapter)
+{
+ struct sdio_mmc_card *card = adapter->card;
+
+ kfree(card->mp_regs);
+ kfree(card->mpa_tx.buf);
+ kfree(card->mpa_rx.buf);
+}
+
+/*
+ * This function updates the MP end port in card.
+ */
+static void
+mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port)
+{
+ struct sdio_mmc_card *card = adapter->card;
+ int i;
+
+ card->mp_end_port = port;
+
+ card->mp_data_port_mask = DATA_PORT_MASK;
+
+ for (i = 1; i <= MAX_PORT - card->mp_end_port; i++)
+ card->mp_data_port_mask &= ~(1 << (MAX_PORT - i));
+
+ card->curr_wr_port = 1;
+
+ dev_dbg(adapter->dev, "cmd: mp_end_port %d, data port mask 0x%x\n",
+ port, card->mp_data_port_mask);
+}
+
+static struct mwifiex_if_ops sdio_ops = {
+ .init_if = mwifiex_init_sdio,
+ .cleanup_if = mwifiex_cleanup_sdio,
+ .check_fw_status = mwifiex_check_fw_status,
+ .prog_fw = mwifiex_prog_fw_w_helper,
+ .register_dev = mwifiex_register_dev,
+ .unregister_dev = mwifiex_unregister_dev,
+ .enable_int = mwifiex_sdio_enable_host_int,
+ .process_int_status = mwifiex_process_int_status,
+ .host_to_card = mwifiex_sdio_host_to_card,
+ .wakeup = mwifiex_pm_wakeup_card,
+ .wakeup_complete = mwifiex_pm_wakeup_card_complete,
+
+ /* SDIO specific */
+ .update_mp_end_port = mwifiex_update_mp_end_port,
+ .cleanup_mpa_buf = mwifiex_cleanup_mpa_buf,
+};
+
+/*
+ * This function initializes the SDIO driver.
+ *
+ * This initiates the semaphore and registers the device with
+ * SDIO bus.
+ */
+static int
+mwifiex_sdio_init_module(void)
+{
+ sema_init(&add_remove_card_sem, 1);
+
+ return sdio_register_driver(&mwifiex_sdio);
+}
+
+/*
+ * This function cleans up the SDIO driver.
+ *
+ * The following major steps are followed for cleanup -
+ * - Resume the device if its suspended
+ * - Disconnect the device if connected
+ * - Shutdown the firmware
+ * - Unregister the device from SDIO bus.
+ */
+static void
+mwifiex_sdio_cleanup_module(void)
+{
+ struct mwifiex_adapter *adapter = g_adapter;
+ int i;
+
+ if (down_interruptible(&add_remove_card_sem))
+ goto exit_sem_err;
+
+ if (!adapter || !adapter->priv_num)
+ goto exit;
+
+ if (adapter->is_suspended)
+ mwifiex_sdio_resume(adapter->dev);
+
+ for (i = 0; i < adapter->priv_num; i++)
+ if ((GET_BSS_ROLE(adapter->priv[i]) == MWIFIEX_BSS_ROLE_STA) &&
+ adapter->priv[i]->media_connected)
+ mwifiex_deauthenticate(adapter->priv[i], NULL);
+
+ if (!adapter->surprise_removed)
+ mwifiex_init_shutdown_fw(mwifiex_get_priv(adapter,
+ MWIFIEX_BSS_ROLE_ANY),
+ MWIFIEX_FUNC_SHUTDOWN);
+
+exit:
+ up(&add_remove_card_sem);
+
+exit_sem_err:
+ sdio_unregister_driver(&mwifiex_sdio);
+}
+
+module_init(mwifiex_sdio_init_module);
+module_exit(mwifiex_sdio_cleanup_module);
+
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_DESCRIPTION("Marvell WiFi-Ex SDIO Driver version " SDIO_VERSION);
+MODULE_VERSION(SDIO_VERSION);
+MODULE_LICENSE("GPL v2");
+MODULE_FIRMWARE("sd8787.bin");
diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h
new file mode 100644
index 000000000000..a0e9bc5253e0
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sdio.h
@@ -0,0 +1,305 @@
+/*
+ * Marvell Wireless LAN device driver: SDIO specific definitions
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef _MWIFIEX_SDIO_H
+#define _MWIFIEX_SDIO_H
+
+
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/card.h>
+
+#include "main.h"
+
+#define BLOCK_MODE 1
+#define BYTE_MODE 0
+
+#define REG_PORT 0
+#define RD_BITMAP_L 0x04
+#define RD_BITMAP_U 0x05
+#define WR_BITMAP_L 0x06
+#define WR_BITMAP_U 0x07
+#define RD_LEN_P0_L 0x08
+#define RD_LEN_P0_U 0x09
+
+#define MWIFIEX_SDIO_IO_PORT_MASK 0xfffff
+
+#define MWIFIEX_SDIO_BYTE_MODE_MASK 0x80000000
+
+#define CTRL_PORT 0
+#define CTRL_PORT_MASK 0x0001
+#define DATA_PORT_MASK 0xfffe
+
+#define MAX_MP_REGS 64
+#define MAX_PORT 16
+
+#define SDIO_MP_AGGR_DEF_PKT_LIMIT 8
+
+#define SDIO_MP_TX_AGGR_DEF_BUF_SIZE (4096) /* 4K */
+
+/* Multi port RX aggregation buffer size */
+#define SDIO_MP_RX_AGGR_DEF_BUF_SIZE (4096) /* 4K */
+
+/* Misc. Config Register : Auto Re-enable interrupts */
+#define AUTO_RE_ENABLE_INT BIT(4)
+
+/* Host Control Registers */
+/* Host Control Registers : I/O port 0 */
+#define IO_PORT_0_REG 0x78
+/* Host Control Registers : I/O port 1 */
+#define IO_PORT_1_REG 0x79
+/* Host Control Registers : I/O port 2 */
+#define IO_PORT_2_REG 0x7A
+
+/* Host Control Registers : Configuration */
+#define CONFIGURATION_REG 0x00
+/* Host Control Registers : Host without Command 53 finish host*/
+#define HOST_TO_CARD_EVENT (0x1U << 3)
+/* Host Control Registers : Host without Command 53 finish host */
+#define HOST_WO_CMD53_FINISH_HOST (0x1U << 2)
+/* Host Control Registers : Host power up */
+#define HOST_POWER_UP (0x1U << 1)
+/* Host Control Registers : Host power down */
+#define HOST_POWER_DOWN (0x1U << 0)
+
+/* Host Control Registers : Host interrupt mask */
+#define HOST_INT_MASK_REG 0x02
+/* Host Control Registers : Upload host interrupt mask */
+#define UP_LD_HOST_INT_MASK (0x1U)
+/* Host Control Registers : Download host interrupt mask */
+#define DN_LD_HOST_INT_MASK (0x2U)
+/* Enable Host interrupt mask */
+#define HOST_INT_ENABLE (UP_LD_HOST_INT_MASK | DN_LD_HOST_INT_MASK)
+/* Disable Host interrupt mask */
+#define HOST_INT_DISABLE 0xff
+
+/* Host Control Registers : Host interrupt status */
+#define HOST_INTSTATUS_REG 0x03
+/* Host Control Registers : Upload host interrupt status */
+#define UP_LD_HOST_INT_STATUS (0x1U)
+/* Host Control Registers : Download host interrupt status */
+#define DN_LD_HOST_INT_STATUS (0x2U)
+
+/* Host Control Registers : Host interrupt RSR */
+#define HOST_INT_RSR_REG 0x01
+/* Host Control Registers : Upload host interrupt RSR */
+#define UP_LD_HOST_INT_RSR (0x1U)
+#define SDIO_INT_MASK 0x3F
+
+/* Host Control Registers : Host interrupt status */
+#define HOST_INT_STATUS_REG 0x28
+/* Host Control Registers : Upload CRC error */
+#define UP_LD_CRC_ERR (0x1U << 2)
+/* Host Control Registers : Upload restart */
+#define UP_LD_RESTART (0x1U << 1)
+/* Host Control Registers : Download restart */
+#define DN_LD_RESTART (0x1U << 0)
+
+/* Card Control Registers : Card status register */
+#define CARD_STATUS_REG 0x30
+/* Card Control Registers : Card I/O ready */
+#define CARD_IO_READY (0x1U << 3)
+/* Card Control Registers : CIS card ready */
+#define CIS_CARD_RDY (0x1U << 2)
+/* Card Control Registers : Upload card ready */
+#define UP_LD_CARD_RDY (0x1U << 1)
+/* Card Control Registers : Download card ready */
+#define DN_LD_CARD_RDY (0x1U << 0)
+
+/* Card Control Registers : Host interrupt mask register */
+#define HOST_INTERRUPT_MASK_REG 0x34
+/* Card Control Registers : Host power interrupt mask */
+#define HOST_POWER_INT_MASK (0x1U << 3)
+/* Card Control Registers : Abort card interrupt mask */
+#define ABORT_CARD_INT_MASK (0x1U << 2)
+/* Card Control Registers : Upload card interrupt mask */
+#define UP_LD_CARD_INT_MASK (0x1U << 1)
+/* Card Control Registers : Download card interrupt mask */
+#define DN_LD_CARD_INT_MASK (0x1U << 0)
+
+/* Card Control Registers : Card interrupt status register */
+#define CARD_INTERRUPT_STATUS_REG 0x38
+/* Card Control Registers : Power up interrupt */
+#define POWER_UP_INT (0x1U << 4)
+/* Card Control Registers : Power down interrupt */
+#define POWER_DOWN_INT (0x1U << 3)
+
+/* Card Control Registers : Card interrupt RSR register */
+#define CARD_INTERRUPT_RSR_REG 0x3c
+/* Card Control Registers : Power up RSR */
+#define POWER_UP_RSR (0x1U << 4)
+/* Card Control Registers : Power down RSR */
+#define POWER_DOWN_RSR (0x1U << 3)
+
+/* Card Control Registers : Miscellaneous Configuration Register */
+#define CARD_MISC_CFG_REG 0x6C
+
+/* Host F1 read base 0 */
+#define HOST_F1_RD_BASE_0 0x0040
+/* Host F1 read base 1 */
+#define HOST_F1_RD_BASE_1 0x0041
+/* Host F1 card ready */
+#define HOST_F1_CARD_RDY 0x0020
+
+/* Firmware status 0 register */
+#define CARD_FW_STATUS0_REG 0x60
+/* Firmware status 1 register */
+#define CARD_FW_STATUS1_REG 0x61
+/* Rx length register */
+#define CARD_RX_LEN_REG 0x62
+/* Rx unit register */
+#define CARD_RX_UNIT_REG 0x63
+
+/* Event header Len*/
+#define MWIFIEX_EVENT_HEADER_LEN 8
+
+/* Max retry number of CMD53 write */
+#define MAX_WRITE_IOMEM_RETRY 2
+
+/* SDIO Tx aggregation in progress ? */
+#define MP_TX_AGGR_IN_PROGRESS(a) (a->mpa_tx.pkt_cnt > 0)
+
+/* SDIO Tx aggregation buffer room for next packet ? */
+#define MP_TX_AGGR_BUF_HAS_ROOM(a, len) ((a->mpa_tx.buf_len+len) \
+ <= a->mpa_tx.buf_size)
+
+/* Copy current packet (SDIO Tx aggregation buffer) to SDIO buffer */
+#define MP_TX_AGGR_BUF_PUT(a, payload, pkt_len, port) do { \
+ memmove(&a->mpa_tx.buf[a->mpa_tx.buf_len], \
+ payload, pkt_len); \
+ a->mpa_tx.buf_len += pkt_len; \
+ if (!a->mpa_tx.pkt_cnt) \
+ a->mpa_tx.start_port = port; \
+ if (a->mpa_tx.start_port <= port) \
+ a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt)); \
+ else \
+ a->mpa_tx.ports |= (1<<(a->mpa_tx.pkt_cnt+1+(MAX_PORT - \
+ a->mp_end_port))); \
+ a->mpa_tx.pkt_cnt++; \
+} while (0);
+
+/* SDIO Tx aggregation limit ? */
+#define MP_TX_AGGR_PKT_LIMIT_REACHED(a) \
+ (a->mpa_tx.pkt_cnt == a->mpa_tx.pkt_aggr_limit)
+
+/* SDIO Tx aggregation port limit ? */
+#define MP_TX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_wr_port < \
+ a->mpa_tx.start_port) && (((MAX_PORT - \
+ a->mpa_tx.start_port) + a->curr_wr_port) >= \
+ SDIO_MP_AGGR_DEF_PKT_LIMIT))
+
+/* Reset SDIO Tx aggregation buffer parameters */
+#define MP_TX_AGGR_BUF_RESET(a) do { \
+ a->mpa_tx.pkt_cnt = 0; \
+ a->mpa_tx.buf_len = 0; \
+ a->mpa_tx.ports = 0; \
+ a->mpa_tx.start_port = 0; \
+} while (0);
+
+/* SDIO Rx aggregation limit ? */
+#define MP_RX_AGGR_PKT_LIMIT_REACHED(a) \
+ (a->mpa_rx.pkt_cnt == a->mpa_rx.pkt_aggr_limit)
+
+/* SDIO Tx aggregation port limit ? */
+#define MP_RX_AGGR_PORT_LIMIT_REACHED(a) ((a->curr_rd_port < \
+ a->mpa_rx.start_port) && (((MAX_PORT - \
+ a->mpa_rx.start_port) + a->curr_rd_port) >= \
+ SDIO_MP_AGGR_DEF_PKT_LIMIT))
+
+/* SDIO Rx aggregation in progress ? */
+#define MP_RX_AGGR_IN_PROGRESS(a) (a->mpa_rx.pkt_cnt > 0)
+
+/* SDIO Rx aggregation buffer room for next packet ? */
+#define MP_RX_AGGR_BUF_HAS_ROOM(a, rx_len) \
+ ((a->mpa_rx.buf_len+rx_len) <= a->mpa_rx.buf_size)
+
+/* Prepare to copy current packet from card to SDIO Rx aggregation buffer */
+#define MP_RX_AGGR_SETUP(a, skb, port) do { \
+ a->mpa_rx.buf_len += skb->len; \
+ if (!a->mpa_rx.pkt_cnt) \
+ a->mpa_rx.start_port = port; \
+ if (a->mpa_rx.start_port <= port) \
+ a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt)); \
+ else \
+ a->mpa_rx.ports |= (1<<(a->mpa_rx.pkt_cnt+1)); \
+ a->mpa_rx.skb_arr[a->mpa_rx.pkt_cnt] = skb; \
+ a->mpa_rx.len_arr[a->mpa_rx.pkt_cnt] = skb->len; \
+ a->mpa_rx.pkt_cnt++; \
+} while (0);
+
+/* Reset SDIO Rx aggregation buffer parameters */
+#define MP_RX_AGGR_BUF_RESET(a) do { \
+ a->mpa_rx.pkt_cnt = 0; \
+ a->mpa_rx.buf_len = 0; \
+ a->mpa_rx.ports = 0; \
+ a->mpa_rx.start_port = 0; \
+} while (0);
+
+
+/* data structure for SDIO MPA TX */
+struct mwifiex_sdio_mpa_tx {
+ /* multiport tx aggregation buffer pointer */
+ u8 *buf;
+ u32 buf_len;
+ u32 pkt_cnt;
+ u16 ports;
+ u16 start_port;
+ u8 enabled;
+ u32 buf_size;
+ u32 pkt_aggr_limit;
+};
+
+struct mwifiex_sdio_mpa_rx {
+ u8 *buf;
+ u32 buf_len;
+ u32 pkt_cnt;
+ u16 ports;
+ u16 start_port;
+
+ struct sk_buff *skb_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT];
+ u32 len_arr[SDIO_MP_AGGR_DEF_PKT_LIMIT];
+
+ u8 enabled;
+ u32 buf_size;
+ u32 pkt_aggr_limit;
+};
+
+int mwifiex_bus_register(void);
+void mwifiex_bus_unregister(void);
+
+struct sdio_mmc_card {
+ struct sdio_func *func;
+ struct mwifiex_adapter *adapter;
+
+ u16 mp_rd_bitmap;
+ u16 mp_wr_bitmap;
+
+ u16 mp_end_port;
+ u16 mp_data_port_mask;
+
+ u8 curr_rd_port;
+ u8 curr_wr_port;
+
+ u8 *mp_regs;
+
+ struct mwifiex_sdio_mpa_tx mpa_tx;
+ struct mwifiex_sdio_mpa_rx mpa_rx;
+};
+#endif /* _MWIFIEX_SDIO_H */
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
new file mode 100644
index 000000000000..8af3a78d2723
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -0,0 +1,1219 @@
+/*
+ * Marvell Wireless LAN device driver: station command handling
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+
+/*
+ * This function prepares command to set/get RSSI information.
+ *
+ * Preparation includes -
+ * - Setting command ID, action and proper size
+ * - Setting data/beacon average factors
+ * - Resetting SNR/NF/RSSI values in private structure
+ * - Ensuring correct endian-ness
+ */
+static int
+mwifiex_cmd_802_11_rssi_info(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd, u16 cmd_action)
+{
+ cmd->command = cpu_to_le16(HostCmd_CMD_RSSI_INFO);
+ cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_rssi_info) +
+ S_DS_GEN);
+ cmd->params.rssi_info.action = cpu_to_le16(cmd_action);
+ cmd->params.rssi_info.ndata = cpu_to_le16(priv->data_avg_factor);
+ cmd->params.rssi_info.nbcn = cpu_to_le16(priv->bcn_avg_factor);
+
+ /* Reset SNR/NF/RSSI values in private structure */
+ priv->data_rssi_last = 0;
+ priv->data_nf_last = 0;
+ priv->data_rssi_avg = 0;
+ priv->data_nf_avg = 0;
+ priv->bcn_rssi_last = 0;
+ priv->bcn_nf_last = 0;
+ priv->bcn_rssi_avg = 0;
+ priv->bcn_nf_avg = 0;
+
+ return 0;
+}
+
+/*
+ * This function prepares command to set MAC control.
+ *
+ * Preparation includes -
+ * - Setting command ID, action and proper size
+ * - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_mac_control(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ u16 cmd_action, void *data_buf)
+{
+ struct host_cmd_ds_mac_control *mac_ctrl = &cmd->params.mac_ctrl;
+ u16 action = *((u16 *) data_buf);
+
+ if (cmd_action != HostCmd_ACT_GEN_SET) {
+ dev_err(priv->adapter->dev,
+ "mac_control: only support set cmd\n");
+ return -1;
+ }
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_MAC_CONTROL);
+ cmd->size =
+ cpu_to_le16(sizeof(struct host_cmd_ds_mac_control) + S_DS_GEN);
+ mac_ctrl->action = cpu_to_le16(action);
+
+ return 0;
+}
+
+/*
+ * This function prepares command to set/get SNMP MIB.
+ *
+ * Preparation includes -
+ * - Setting command ID, action and proper size
+ * - Setting SNMP MIB OID number and value
+ * (as required)
+ * - Ensuring correct endian-ness
+ *
+ * The following SNMP MIB OIDs are supported -
+ * - FRAG_THRESH_I : Fragmentation threshold
+ * - RTS_THRESH_I : RTS threshold
+ * - SHORT_RETRY_LIM_I : Short retry limit
+ * - DOT11D_I : 11d support
+ */
+static int mwifiex_cmd_802_11_snmp_mib(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ u16 cmd_action, u32 cmd_oid,
+ void *data_buf)
+{
+ struct host_cmd_ds_802_11_snmp_mib *snmp_mib = &cmd->params.smib;
+ u32 ul_temp;
+
+ dev_dbg(priv->adapter->dev, "cmd: SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid);
+ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB);
+ cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_snmp_mib)
+ - 1 + S_DS_GEN);
+
+ if (cmd_action == HostCmd_ACT_GEN_GET) {
+ snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_GET);
+ snmp_mib->buf_size = cpu_to_le16(MAX_SNMP_BUF_SIZE);
+ cmd->size = cpu_to_le16(le16_to_cpu(cmd->size)
+ + MAX_SNMP_BUF_SIZE);
+ }
+
+ switch (cmd_oid) {
+ case FRAG_THRESH_I:
+ snmp_mib->oid = cpu_to_le16((u16) FRAG_THRESH_I);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET);
+ snmp_mib->buf_size = cpu_to_le16(sizeof(u16));
+ ul_temp = *((u32 *) data_buf);
+ *((__le16 *) (snmp_mib->value)) =
+ cpu_to_le16((u16) ul_temp);
+ cmd->size = cpu_to_le16(le16_to_cpu(cmd->size)
+ + sizeof(u16));
+ }
+ break;
+ case RTS_THRESH_I:
+ snmp_mib->oid = cpu_to_le16((u16) RTS_THRESH_I);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET);
+ snmp_mib->buf_size = cpu_to_le16(sizeof(u16));
+ ul_temp = *((u32 *) data_buf);
+ *(__le16 *) (snmp_mib->value) =
+ cpu_to_le16((u16) ul_temp);
+ cmd->size = cpu_to_le16(le16_to_cpu(cmd->size)
+ + sizeof(u16));
+ }
+ break;
+
+ case SHORT_RETRY_LIM_I:
+ snmp_mib->oid = cpu_to_le16((u16) SHORT_RETRY_LIM_I);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET);
+ snmp_mib->buf_size = cpu_to_le16(sizeof(u16));
+ ul_temp = (*(u32 *) data_buf);
+ *((__le16 *) (snmp_mib->value)) =
+ cpu_to_le16((u16) ul_temp);
+ cmd->size = cpu_to_le16(le16_to_cpu(cmd->size)
+ + sizeof(u16));
+ }
+ break;
+ case DOT11D_I:
+ snmp_mib->oid = cpu_to_le16((u16) DOT11D_I);
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET);
+ snmp_mib->buf_size = cpu_to_le16(sizeof(u16));
+ ul_temp = *(u32 *) data_buf;
+ *((__le16 *) (snmp_mib->value)) =
+ cpu_to_le16((u16) ul_temp);
+ cmd->size = cpu_to_le16(le16_to_cpu(cmd->size)
+ + sizeof(u16));
+ }
+ break;
+ default:
+ break;
+ }
+ dev_dbg(priv->adapter->dev,
+ "cmd: SNMP_CMD: Action=0x%x, OID=0x%x, OIDSize=0x%x,"
+ " Value=0x%x\n",
+ cmd_action, cmd_oid, le16_to_cpu(snmp_mib->buf_size),
+ le16_to_cpu(*(__le16 *) snmp_mib->value));
+ return 0;
+}
+
+/*
+ * This function prepares command to get log.
+ *
+ * Preparation includes -
+ * - Setting command ID and proper size
+ * - Ensuring correct endian-ness
+ */
+static int
+mwifiex_cmd_802_11_get_log(struct host_cmd_ds_command *cmd)
+{
+ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_GET_LOG);
+ cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_get_log) +
+ S_DS_GEN);
+ return 0;
+}
+
+/*
+ * This function prepares command to set/get Tx data rate configuration.
+ *
+ * Preparation includes -
+ * - Setting command ID, action and proper size
+ * - Setting configuration index, rate scope and rate drop pattern
+ * parameters (as required)
+ * - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_tx_rate_cfg(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ u16 cmd_action, void *data_buf)
+{
+ struct host_cmd_ds_tx_rate_cfg *rate_cfg = &cmd->params.tx_rate_cfg;
+ struct mwifiex_rate_scope *rate_scope;
+ struct mwifiex_rate_drop_pattern *rate_drop;
+ u16 *pbitmap_rates = (u16 *) data_buf;
+
+ u32 i;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_TX_RATE_CFG);
+
+ rate_cfg->action = cpu_to_le16(cmd_action);
+ rate_cfg->cfg_index = 0;
+
+ rate_scope = (struct mwifiex_rate_scope *) ((u8 *) rate_cfg +
+ sizeof(struct host_cmd_ds_tx_rate_cfg));
+ rate_scope->type = cpu_to_le16(TLV_TYPE_RATE_SCOPE);
+ rate_scope->length = cpu_to_le16(sizeof(struct mwifiex_rate_scope) -
+ sizeof(struct mwifiex_ie_types_header));
+ if (pbitmap_rates != NULL) {
+ rate_scope->hr_dsss_rate_bitmap = cpu_to_le16(pbitmap_rates[0]);
+ rate_scope->ofdm_rate_bitmap = cpu_to_le16(pbitmap_rates[1]);
+ for (i = 0;
+ i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16);
+ i++)
+ rate_scope->ht_mcs_rate_bitmap[i] =
+ cpu_to_le16(pbitmap_rates[2 + i]);
+ } else {
+ rate_scope->hr_dsss_rate_bitmap =
+ cpu_to_le16(priv->bitmap_rates[0]);
+ rate_scope->ofdm_rate_bitmap =
+ cpu_to_le16(priv->bitmap_rates[1]);
+ for (i = 0;
+ i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16);
+ i++)
+ rate_scope->ht_mcs_rate_bitmap[i] =
+ cpu_to_le16(priv->bitmap_rates[2 + i]);
+ }
+
+ rate_drop = (struct mwifiex_rate_drop_pattern *) ((u8 *) rate_scope +
+ sizeof(struct mwifiex_rate_scope));
+ rate_drop->type = cpu_to_le16(TLV_TYPE_RATE_DROP_CONTROL);
+ rate_drop->length = cpu_to_le16(sizeof(rate_drop->rate_drop_mode));
+ rate_drop->rate_drop_mode = 0;
+
+ cmd->size =
+ cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_tx_rate_cfg) +
+ sizeof(struct mwifiex_rate_scope) +
+ sizeof(struct mwifiex_rate_drop_pattern));
+
+ return 0;
+}
+
+/*
+ * This function prepares command to set/get Tx power configuration.
+ *
+ * Preparation includes -
+ * - Setting command ID, action and proper size
+ * - Setting Tx power mode, power group TLV
+ * (as required)
+ * - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_tx_power_cfg(struct host_cmd_ds_command *cmd,
+ u16 cmd_action, void *data_buf)
+{
+ struct mwifiex_types_power_group *pg_tlv;
+ struct host_cmd_ds_txpwr_cfg *txp;
+ struct host_cmd_ds_txpwr_cfg *cmd_txp_cfg = &cmd->params.txp_cfg;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_TXPWR_CFG);
+ cmd->size =
+ cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_txpwr_cfg));
+ switch (cmd_action) {
+ case HostCmd_ACT_GEN_SET:
+ txp = (struct host_cmd_ds_txpwr_cfg *) data_buf;
+ if (txp->mode) {
+ pg_tlv = (struct mwifiex_types_power_group
+ *) ((unsigned long) data_buf +
+ sizeof(struct host_cmd_ds_txpwr_cfg));
+ memmove(cmd_txp_cfg, data_buf,
+ sizeof(struct host_cmd_ds_txpwr_cfg) +
+ sizeof(struct mwifiex_types_power_group) +
+ pg_tlv->length);
+
+ pg_tlv = (struct mwifiex_types_power_group *) ((u8 *)
+ cmd_txp_cfg +
+ sizeof(struct host_cmd_ds_txpwr_cfg));
+ cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) +
+ sizeof(struct mwifiex_types_power_group) +
+ pg_tlv->length);
+ } else {
+ memmove(cmd_txp_cfg, data_buf,
+ sizeof(struct host_cmd_ds_txpwr_cfg));
+ }
+ cmd_txp_cfg->action = cpu_to_le16(cmd_action);
+ break;
+ case HostCmd_ACT_GEN_GET:
+ cmd_txp_cfg->action = cpu_to_le16(cmd_action);
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * This function prepares command to set Host Sleep configuration.
+ *
+ * Preparation includes -
+ * - Setting command ID and proper size
+ * - Setting Host Sleep action, conditions, ARP filters
+ * (as required)
+ * - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_802_11_hs_cfg(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ u16 cmd_action,
+ struct mwifiex_hs_config_param *data_buf)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct host_cmd_ds_802_11_hs_cfg_enh *hs_cfg = &cmd->params.opt_hs_cfg;
+ u16 hs_activate = false;
+
+ if (data_buf == NULL)
+ /* New Activate command */
+ hs_activate = true;
+ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH);
+
+ if (!hs_activate &&
+ (data_buf->conditions
+ != cpu_to_le32(HOST_SLEEP_CFG_CANCEL))
+ && ((adapter->arp_filter_size > 0)
+ && (adapter->arp_filter_size <= ARP_FILTER_MAX_BUF_SIZE))) {
+ dev_dbg(adapter->dev,
+ "cmd: Attach %d bytes ArpFilter to HSCfg cmd\n",
+ adapter->arp_filter_size);
+ memcpy(((u8 *) hs_cfg) +
+ sizeof(struct host_cmd_ds_802_11_hs_cfg_enh),
+ adapter->arp_filter, adapter->arp_filter_size);
+ cmd->size = cpu_to_le16(adapter->arp_filter_size +
+ sizeof(struct host_cmd_ds_802_11_hs_cfg_enh)
+ + S_DS_GEN);
+ } else {
+ cmd->size = cpu_to_le16(S_DS_GEN + sizeof(struct
+ host_cmd_ds_802_11_hs_cfg_enh));
+ }
+ if (hs_activate) {
+ hs_cfg->action = cpu_to_le16(HS_ACTIVATE);
+ hs_cfg->params.hs_activate.resp_ctrl = RESP_NEEDED;
+ } else {
+ hs_cfg->action = cpu_to_le16(HS_CONFIGURE);
+ hs_cfg->params.hs_config.conditions = data_buf->conditions;
+ hs_cfg->params.hs_config.gpio = data_buf->gpio;
+ hs_cfg->params.hs_config.gap = data_buf->gap;
+ dev_dbg(adapter->dev,
+ "cmd: HS_CFG_CMD: condition:0x%x gpio:0x%x gap:0x%x\n",
+ hs_cfg->params.hs_config.conditions,
+ hs_cfg->params.hs_config.gpio,
+ hs_cfg->params.hs_config.gap);
+ }
+
+ return 0;
+}
+
+/*
+ * This function prepares command to set/get MAC address.
+ *
+ * Preparation includes -
+ * - Setting command ID, action and proper size
+ * - Setting MAC address (for SET only)
+ * - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_802_11_mac_address(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ u16 cmd_action)
+{
+ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_MAC_ADDRESS);
+ cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_mac_address) +
+ S_DS_GEN);
+ cmd->result = 0;
+
+ cmd->params.mac_addr.action = cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET)
+ memcpy(cmd->params.mac_addr.mac_addr, priv->curr_addr,
+ ETH_ALEN);
+ return 0;
+}
+
+/*
+ * This function prepares command to set MAC multicast address.
+ *
+ * Preparation includes -
+ * - Setting command ID, action and proper size
+ * - Setting MAC multicast address
+ * - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_mac_multicast_adr(struct host_cmd_ds_command *cmd,
+ u16 cmd_action, void *data_buf)
+{
+ struct mwifiex_multicast_list *mcast_list =
+ (struct mwifiex_multicast_list *) data_buf;
+ struct host_cmd_ds_mac_multicast_adr *mcast_addr = &cmd->params.mc_addr;
+
+ cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_mac_multicast_adr) +
+ S_DS_GEN);
+ cmd->command = cpu_to_le16(HostCmd_CMD_MAC_MULTICAST_ADR);
+
+ mcast_addr->action = cpu_to_le16(cmd_action);
+ mcast_addr->num_of_adrs =
+ cpu_to_le16((u16) mcast_list->num_multicast_addr);
+ memcpy(mcast_addr->mac_list, mcast_list->mac_list,
+ mcast_list->num_multicast_addr * ETH_ALEN);
+
+ return 0;
+}
+
+/*
+ * This function prepares command to deauthenticate.
+ *
+ * Preparation includes -
+ * - Setting command ID and proper size
+ * - Setting AP MAC address and reason code
+ * - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_802_11_deauthenticate(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ void *data_buf)
+{
+ struct host_cmd_ds_802_11_deauthenticate *deauth = &cmd->params.deauth;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_DEAUTHENTICATE);
+ cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_deauthenticate)
+ + S_DS_GEN);
+
+ /* Set AP MAC address */
+ memcpy(deauth->mac_addr, (u8 *) data_buf, ETH_ALEN);
+
+ dev_dbg(priv->adapter->dev, "cmd: Deauth: %pM\n", deauth->mac_addr);
+
+ deauth->reason_code = cpu_to_le16(WLAN_REASON_DEAUTH_LEAVING);
+
+ return 0;
+}
+
+/*
+ * This function prepares command to stop Ad-Hoc network.
+ *
+ * Preparation includes -
+ * - Setting command ID and proper size
+ * - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_802_11_ad_hoc_stop(struct host_cmd_ds_command *cmd)
+{
+ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_STOP);
+ cmd->size = cpu_to_le16(S_DS_GEN);
+ return 0;
+}
+
+/*
+ * This function sets WEP key(s) to key parameter TLV(s).
+ *
+ * Multi-key parameter TLVs are supported, so we can send multiple
+ * WEP keys in a single buffer.
+ */
+static int
+mwifiex_set_keyparamset_wep(struct mwifiex_private *priv,
+ struct mwifiex_ie_type_key_param_set *key_param_set,
+ u16 *key_param_len)
+{
+ int cur_key_param_len;
+ u8 i;
+
+ /* Multi-key_param_set TLV is supported */
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ if ((priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP40) ||
+ (priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP104)) {
+ key_param_set->type =
+ cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+/* Key_param_set WEP fixed length */
+#define KEYPARAMSET_WEP_FIXED_LEN 8
+ key_param_set->length = cpu_to_le16((u16)
+ (priv->wep_key[i].
+ key_length +
+ KEYPARAMSET_WEP_FIXED_LEN));
+ key_param_set->key_type_id =
+ cpu_to_le16(KEY_TYPE_ID_WEP);
+ key_param_set->key_info =
+ cpu_to_le16(KEY_ENABLED | KEY_UNICAST |
+ KEY_MCAST);
+ key_param_set->key_len =
+ cpu_to_le16(priv->wep_key[i].key_length);
+ /* Set WEP key index */
+ key_param_set->key[0] = i;
+ /* Set default Tx key flag */
+ if (i ==
+ (priv->
+ wep_key_curr_index & HostCmd_WEP_KEY_INDEX_MASK))
+ key_param_set->key[1] = 1;
+ else
+ key_param_set->key[1] = 0;
+ memmove(&key_param_set->key[2],
+ priv->wep_key[i].key_material,
+ priv->wep_key[i].key_length);
+
+ cur_key_param_len = priv->wep_key[i].key_length +
+ KEYPARAMSET_WEP_FIXED_LEN +
+ sizeof(struct mwifiex_ie_types_header);
+ *key_param_len += (u16) cur_key_param_len;
+ key_param_set =
+ (struct mwifiex_ie_type_key_param_set *)
+ ((u8 *)key_param_set +
+ cur_key_param_len);
+ } else if (!priv->wep_key[i].key_length) {
+ continue;
+ } else {
+ dev_err(priv->adapter->dev,
+ "key%d Length = %d is incorrect\n",
+ (i + 1), priv->wep_key[i].key_length);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * This function prepares command to set/get/reset network key(s).
+ *
+ * Preparation includes -
+ * - Setting command ID, action and proper size
+ * - Setting WEP keys, WAPI keys or WPA keys along with required
+ * encryption (TKIP, AES) (as required)
+ * - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ u16 cmd_action,
+ u32 cmd_oid, void *data_buf)
+{
+ struct host_cmd_ds_802_11_key_material *key_material =
+ &cmd->params.key_material;
+ struct mwifiex_ds_encrypt_key *enc_key =
+ (struct mwifiex_ds_encrypt_key *) data_buf;
+ u16 key_param_len = 0;
+ int ret = 0;
+ const u8 bc_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL);
+ key_material->action = cpu_to_le16(cmd_action);
+
+ if (cmd_action == HostCmd_ACT_GEN_GET) {
+ cmd->size =
+ cpu_to_le16(sizeof(key_material->action) + S_DS_GEN);
+ return ret;
+ }
+
+ if (!enc_key) {
+ memset(&key_material->key_param_set, 0,
+ (NUM_WEP_KEYS *
+ sizeof(struct mwifiex_ie_type_key_param_set)));
+ ret = mwifiex_set_keyparamset_wep(priv,
+ &key_material->key_param_set,
+ &key_param_len);
+ cmd->size = cpu_to_le16(key_param_len +
+ sizeof(key_material->action) + S_DS_GEN);
+ return ret;
+ } else
+ memset(&key_material->key_param_set, 0,
+ sizeof(struct mwifiex_ie_type_key_param_set));
+ if (enc_key->is_wapi_key) {
+ dev_dbg(priv->adapter->dev, "info: Set WAPI Key\n");
+ key_material->key_param_set.key_type_id =
+ cpu_to_le16(KEY_TYPE_ID_WAPI);
+ if (cmd_oid == KEY_INFO_ENABLED)
+ key_material->key_param_set.key_info =
+ cpu_to_le16(KEY_ENABLED);
+ else
+ key_material->key_param_set.key_info =
+ cpu_to_le16(!KEY_ENABLED);
+
+ key_material->key_param_set.key[0] = enc_key->key_index;
+ if (!priv->sec_info.wapi_key_on)
+ key_material->key_param_set.key[1] = 1;
+ else
+ /* set 0 when re-key */
+ key_material->key_param_set.key[1] = 0;
+
+ if (0 != memcmp(enc_key->mac_addr, bc_mac, sizeof(bc_mac))) {
+ /* WAPI pairwise key: unicast */
+ key_material->key_param_set.key_info |=
+ cpu_to_le16(KEY_UNICAST);
+ } else { /* WAPI group key: multicast */
+ key_material->key_param_set.key_info |=
+ cpu_to_le16(KEY_MCAST);
+ priv->sec_info.wapi_key_on = true;
+ }
+
+ key_material->key_param_set.type =
+ cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+ key_material->key_param_set.key_len =
+ cpu_to_le16(WAPI_KEY_LEN);
+ memcpy(&key_material->key_param_set.key[2],
+ enc_key->key_material, enc_key->key_len);
+ memcpy(&key_material->key_param_set.key[2 + enc_key->key_len],
+ enc_key->wapi_rxpn, WAPI_RXPN_LEN);
+ key_material->key_param_set.length =
+ cpu_to_le16(WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN);
+
+ key_param_len = (WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN) +
+ sizeof(struct mwifiex_ie_types_header);
+ cmd->size = cpu_to_le16(key_param_len +
+ sizeof(key_material->action) + S_DS_GEN);
+ return ret;
+ }
+ if (enc_key->key_len == WLAN_KEY_LEN_CCMP) {
+ dev_dbg(priv->adapter->dev, "cmd: WPA_AES\n");
+ key_material->key_param_set.key_type_id =
+ cpu_to_le16(KEY_TYPE_ID_AES);
+ if (cmd_oid == KEY_INFO_ENABLED)
+ key_material->key_param_set.key_info =
+ cpu_to_le16(KEY_ENABLED);
+ else
+ key_material->key_param_set.key_info =
+ cpu_to_le16(!KEY_ENABLED);
+
+ if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
+ /* AES pairwise key: unicast */
+ key_material->key_param_set.key_info |=
+ cpu_to_le16(KEY_UNICAST);
+ else /* AES group key: multicast */
+ key_material->key_param_set.key_info |=
+ cpu_to_le16(KEY_MCAST);
+ } else if (enc_key->key_len == WLAN_KEY_LEN_TKIP) {
+ dev_dbg(priv->adapter->dev, "cmd: WPA_TKIP\n");
+ key_material->key_param_set.key_type_id =
+ cpu_to_le16(KEY_TYPE_ID_TKIP);
+ key_material->key_param_set.key_info =
+ cpu_to_le16(KEY_ENABLED);
+
+ if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
+ /* TKIP pairwise key: unicast */
+ key_material->key_param_set.key_info |=
+ cpu_to_le16(KEY_UNICAST);
+ else /* TKIP group key: multicast */
+ key_material->key_param_set.key_info |=
+ cpu_to_le16(KEY_MCAST);
+ }
+
+ if (key_material->key_param_set.key_type_id) {
+ key_material->key_param_set.type =
+ cpu_to_le16(TLV_TYPE_KEY_MATERIAL);
+ key_material->key_param_set.key_len =
+ cpu_to_le16((u16) enc_key->key_len);
+ memcpy(key_material->key_param_set.key, enc_key->key_material,
+ enc_key->key_len);
+ key_material->key_param_set.length =
+ cpu_to_le16((u16) enc_key->key_len +
+ KEYPARAMSET_FIXED_LEN);
+
+ key_param_len = (u16) (enc_key->key_len + KEYPARAMSET_FIXED_LEN)
+ + sizeof(struct mwifiex_ie_types_header);
+
+ cmd->size = cpu_to_le16(key_param_len +
+ sizeof(key_material->action) + S_DS_GEN);
+ }
+
+ return ret;
+}
+
+/*
+ * This function prepares command to set/get 11d domain information.
+ *
+ * Preparation includes -
+ * - Setting command ID, action and proper size
+ * - Setting domain information fields (for SET only)
+ * - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_802_11d_domain_info(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ u16 cmd_action)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct host_cmd_ds_802_11d_domain_info *domain_info =
+ &cmd->params.domain_info;
+ struct mwifiex_ietypes_domain_param_set *domain =
+ &domain_info->domain;
+ u8 no_of_triplet = adapter->domain_reg.no_of_triplet;
+
+ dev_dbg(adapter->dev, "info: 11D: no_of_triplet=0x%x\n", no_of_triplet);
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_802_11D_DOMAIN_INFO);
+ domain_info->action = cpu_to_le16(cmd_action);
+ if (cmd_action == HostCmd_ACT_GEN_GET) {
+ cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN);
+ return 0;
+ }
+
+ /* Set domain info fields */
+ domain->header.type = cpu_to_le16(WLAN_EID_COUNTRY);
+ memcpy(domain->country_code, adapter->domain_reg.country_code,
+ sizeof(domain->country_code));
+
+ domain->header.len = cpu_to_le16((no_of_triplet *
+ sizeof(struct ieee80211_country_ie_triplet)) +
+ sizeof(domain->country_code));
+
+ if (no_of_triplet) {
+ memcpy(domain->triplet, adapter->domain_reg.triplet,
+ no_of_triplet *
+ sizeof(struct ieee80211_country_ie_triplet));
+
+ cmd->size = cpu_to_le16(sizeof(domain_info->action) +
+ le16_to_cpu(domain->header.len) +
+ sizeof(struct mwifiex_ie_types_header)
+ + S_DS_GEN);
+ } else {
+ cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN);
+ }
+
+ return 0;
+}
+
+/*
+ * This function prepares command to set/get RF channel.
+ *
+ * Preparation includes -
+ * - Setting command ID, action and proper size
+ * - Setting RF type and current RF channel (for SET only)
+ * - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_802_11_rf_channel(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ u16 cmd_action, void *data_buf)
+{
+ struct host_cmd_ds_802_11_rf_channel *rf_chan =
+ &cmd->params.rf_channel;
+ uint16_t rf_type = le16_to_cpu(rf_chan->rf_type);
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_RF_CHANNEL);
+ cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_rf_channel)
+ + S_DS_GEN);
+
+ if (cmd_action == HostCmd_ACT_GEN_SET) {
+ if ((priv->adapter->adhoc_start_band & BAND_A)
+ || (priv->adapter->adhoc_start_band & BAND_AN))
+ rf_chan->rf_type =
+ cpu_to_le16(HostCmd_SCAN_RADIO_TYPE_A);
+
+ rf_type = le16_to_cpu(rf_chan->rf_type);
+ SET_SECONDARYCHAN(rf_type, priv->adapter->chan_offset);
+ rf_chan->current_channel = cpu_to_le16(*((u16 *) data_buf));
+ }
+ rf_chan->action = cpu_to_le16(cmd_action);
+ return 0;
+}
+
+/*
+ * This function prepares command to set/get IBSS coalescing status.
+ *
+ * Preparation includes -
+ * - Setting command ID, action and proper size
+ * - Setting status to enable or disable (for SET only)
+ * - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_ibss_coalescing_status(struct host_cmd_ds_command *cmd,
+ u16 cmd_action, void *data_buf)
+{
+ struct host_cmd_ds_802_11_ibss_status *ibss_coal =
+ &(cmd->params.ibss_coalescing);
+ u16 enable = 0;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_802_11_IBSS_COALESCING_STATUS);
+ cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_ibss_status) +
+ S_DS_GEN);
+ cmd->result = 0;
+ ibss_coal->action = cpu_to_le16(cmd_action);
+
+ switch (cmd_action) {
+ case HostCmd_ACT_GEN_SET:
+ if (data_buf != NULL)
+ enable = *(u16 *) data_buf;
+ ibss_coal->enable = cpu_to_le16(enable);
+ break;
+
+ /* In other case.. Nothing to do */
+ case HostCmd_ACT_GEN_GET:
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * This function prepares command to set/get register value.
+ *
+ * Preparation includes -
+ * - Setting command ID, action and proper size
+ * - Setting register offset (for both GET and SET) and
+ * register value (for SET only)
+ * - Ensuring correct endian-ness
+ *
+ * The following type of registers can be accessed with this function -
+ * - MAC register
+ * - BBP register
+ * - RF register
+ * - PMIC register
+ * - CAU register
+ * - EEPROM
+ */
+static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd,
+ u16 cmd_action, void *data_buf)
+{
+ struct mwifiex_ds_reg_rw *reg_rw;
+
+ reg_rw = (struct mwifiex_ds_reg_rw *) data_buf;
+ switch (le16_to_cpu(cmd->command)) {
+ case HostCmd_CMD_MAC_REG_ACCESS:
+ {
+ struct host_cmd_ds_mac_reg_access *mac_reg;
+
+ cmd->size = cpu_to_le16(sizeof(*mac_reg) + S_DS_GEN);
+ mac_reg = (struct host_cmd_ds_mac_reg_access *) &cmd->
+ params.mac_reg;
+ mac_reg->action = cpu_to_le16(cmd_action);
+ mac_reg->offset =
+ cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
+ mac_reg->value = reg_rw->value;
+ break;
+ }
+ case HostCmd_CMD_BBP_REG_ACCESS:
+ {
+ struct host_cmd_ds_bbp_reg_access *bbp_reg;
+
+ cmd->size = cpu_to_le16(sizeof(*bbp_reg) + S_DS_GEN);
+ bbp_reg = (struct host_cmd_ds_bbp_reg_access *) &cmd->
+ params.bbp_reg;
+ bbp_reg->action = cpu_to_le16(cmd_action);
+ bbp_reg->offset =
+ cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
+ bbp_reg->value = (u8) le32_to_cpu(reg_rw->value);
+ break;
+ }
+ case HostCmd_CMD_RF_REG_ACCESS:
+ {
+ struct host_cmd_ds_rf_reg_access *rf_reg;
+
+ cmd->size = cpu_to_le16(sizeof(*rf_reg) + S_DS_GEN);
+ rf_reg = (struct host_cmd_ds_rf_reg_access *) &cmd->
+ params.rf_reg;
+ rf_reg->action = cpu_to_le16(cmd_action);
+ rf_reg->offset =
+ cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
+ rf_reg->value = (u8) le32_to_cpu(reg_rw->value);
+ break;
+ }
+ case HostCmd_CMD_PMIC_REG_ACCESS:
+ {
+ struct host_cmd_ds_pmic_reg_access *pmic_reg;
+
+ cmd->size = cpu_to_le16(sizeof(*pmic_reg) + S_DS_GEN);
+ pmic_reg = (struct host_cmd_ds_pmic_reg_access *) &cmd->
+ params.pmic_reg;
+ pmic_reg->action = cpu_to_le16(cmd_action);
+ pmic_reg->offset =
+ cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
+ pmic_reg->value = (u8) le32_to_cpu(reg_rw->value);
+ break;
+ }
+ case HostCmd_CMD_CAU_REG_ACCESS:
+ {
+ struct host_cmd_ds_rf_reg_access *cau_reg;
+
+ cmd->size = cpu_to_le16(sizeof(*cau_reg) + S_DS_GEN);
+ cau_reg = (struct host_cmd_ds_rf_reg_access *) &cmd->
+ params.rf_reg;
+ cau_reg->action = cpu_to_le16(cmd_action);
+ cau_reg->offset =
+ cpu_to_le16((u16) le32_to_cpu(reg_rw->offset));
+ cau_reg->value = (u8) le32_to_cpu(reg_rw->value);
+ break;
+ }
+ case HostCmd_CMD_802_11_EEPROM_ACCESS:
+ {
+ struct mwifiex_ds_read_eeprom *rd_eeprom =
+ (struct mwifiex_ds_read_eeprom *) data_buf;
+ struct host_cmd_ds_802_11_eeprom_access *cmd_eeprom =
+ (struct host_cmd_ds_802_11_eeprom_access *)
+ &cmd->params.eeprom;
+
+ cmd->size = cpu_to_le16(sizeof(*cmd_eeprom) + S_DS_GEN);
+ cmd_eeprom->action = cpu_to_le16(cmd_action);
+ cmd_eeprom->offset = rd_eeprom->offset;
+ cmd_eeprom->byte_count = rd_eeprom->byte_count;
+ cmd_eeprom->value = 0;
+ break;
+ }
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * This function prepares the commands before sending them to the firmware.
+ *
+ * This is a generic function which calls specific command preparation
+ * routines based upon the command number.
+ */
+int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
+ u16 cmd_action, u32 cmd_oid,
+ void *data_buf, void *cmd_buf)
+{
+ struct host_cmd_ds_command *cmd_ptr =
+ (struct host_cmd_ds_command *) cmd_buf;
+ int ret = 0;
+
+ /* Prepare command */
+ switch (cmd_no) {
+ case HostCmd_CMD_GET_HW_SPEC:
+ ret = mwifiex_cmd_get_hw_spec(priv, cmd_ptr);
+ break;
+ case HostCmd_CMD_MAC_CONTROL:
+ ret = mwifiex_cmd_mac_control(priv, cmd_ptr, cmd_action,
+ data_buf);
+ break;
+ case HostCmd_CMD_802_11_MAC_ADDRESS:
+ ret = mwifiex_cmd_802_11_mac_address(priv, cmd_ptr,
+ cmd_action);
+ break;
+ case HostCmd_CMD_MAC_MULTICAST_ADR:
+ ret = mwifiex_cmd_mac_multicast_adr(cmd_ptr, cmd_action,
+ data_buf);
+ break;
+ case HostCmd_CMD_TX_RATE_CFG:
+ ret = mwifiex_cmd_tx_rate_cfg(priv, cmd_ptr, cmd_action,
+ data_buf);
+ break;
+ case HostCmd_CMD_TXPWR_CFG:
+ ret = mwifiex_cmd_tx_power_cfg(cmd_ptr, cmd_action,
+ data_buf);
+ break;
+ case HostCmd_CMD_802_11_PS_MODE_ENH:
+ ret = mwifiex_cmd_enh_power_mode(priv, cmd_ptr, cmd_action,
+ (uint16_t)cmd_oid, data_buf);
+ break;
+ case HostCmd_CMD_802_11_HS_CFG_ENH:
+ ret = mwifiex_cmd_802_11_hs_cfg(priv, cmd_ptr, cmd_action,
+ (struct mwifiex_hs_config_param *) data_buf);
+ break;
+ case HostCmd_CMD_802_11_SCAN:
+ ret = mwifiex_cmd_802_11_scan(cmd_ptr, data_buf);
+ break;
+ case HostCmd_CMD_802_11_BG_SCAN_QUERY:
+ ret = mwifiex_cmd_802_11_bg_scan_query(cmd_ptr);
+ break;
+ case HostCmd_CMD_802_11_ASSOCIATE:
+ ret = mwifiex_cmd_802_11_associate(priv, cmd_ptr, data_buf);
+ break;
+ case HostCmd_CMD_802_11_DEAUTHENTICATE:
+ ret = mwifiex_cmd_802_11_deauthenticate(priv, cmd_ptr,
+ data_buf);
+ break;
+ case HostCmd_CMD_802_11_AD_HOC_START:
+ ret = mwifiex_cmd_802_11_ad_hoc_start(priv, cmd_ptr,
+ data_buf);
+ break;
+ case HostCmd_CMD_802_11_GET_LOG:
+ ret = mwifiex_cmd_802_11_get_log(cmd_ptr);
+ break;
+ case HostCmd_CMD_802_11_AD_HOC_JOIN:
+ ret = mwifiex_cmd_802_11_ad_hoc_join(priv, cmd_ptr,
+ data_buf);
+ break;
+ case HostCmd_CMD_802_11_AD_HOC_STOP:
+ ret = mwifiex_cmd_802_11_ad_hoc_stop(cmd_ptr);
+ break;
+ case HostCmd_CMD_RSSI_INFO:
+ ret = mwifiex_cmd_802_11_rssi_info(priv, cmd_ptr, cmd_action);
+ break;
+ case HostCmd_CMD_802_11_SNMP_MIB:
+ ret = mwifiex_cmd_802_11_snmp_mib(priv, cmd_ptr, cmd_action,
+ cmd_oid, data_buf);
+ break;
+ case HostCmd_CMD_802_11_TX_RATE_QUERY:
+ cmd_ptr->command =
+ cpu_to_le16(HostCmd_CMD_802_11_TX_RATE_QUERY);
+ cmd_ptr->size =
+ cpu_to_le16(sizeof(struct host_cmd_ds_tx_rate_query) +
+ S_DS_GEN);
+ priv->tx_rate = 0;
+ ret = 0;
+ break;
+ case HostCmd_CMD_VERSION_EXT:
+ cmd_ptr->command = cpu_to_le16(cmd_no);
+ cmd_ptr->params.verext.version_str_sel =
+ (u8) (*((u32 *) data_buf));
+ memcpy(&cmd_ptr->params, data_buf,
+ sizeof(struct host_cmd_ds_version_ext));
+ cmd_ptr->size =
+ cpu_to_le16(sizeof(struct host_cmd_ds_version_ext) +
+ S_DS_GEN);
+ ret = 0;
+ break;
+ case HostCmd_CMD_802_11_RF_CHANNEL:
+ ret = mwifiex_cmd_802_11_rf_channel(priv, cmd_ptr, cmd_action,
+ data_buf);
+ break;
+ case HostCmd_CMD_FUNC_INIT:
+ if (priv->adapter->hw_status == MWIFIEX_HW_STATUS_RESET)
+ priv->adapter->hw_status = MWIFIEX_HW_STATUS_READY;
+ cmd_ptr->command = cpu_to_le16(cmd_no);
+ cmd_ptr->size = cpu_to_le16(S_DS_GEN);
+ break;
+ case HostCmd_CMD_FUNC_SHUTDOWN:
+ priv->adapter->hw_status = MWIFIEX_HW_STATUS_RESET;
+ cmd_ptr->command = cpu_to_le16(cmd_no);
+ cmd_ptr->size = cpu_to_le16(S_DS_GEN);
+ break;
+ case HostCmd_CMD_11N_ADDBA_REQ:
+ ret = mwifiex_cmd_11n_addba_req(cmd_ptr, data_buf);
+ break;
+ case HostCmd_CMD_11N_DELBA:
+ ret = mwifiex_cmd_11n_delba(cmd_ptr, data_buf);
+ break;
+ case HostCmd_CMD_11N_ADDBA_RSP:
+ ret = mwifiex_cmd_11n_addba_rsp_gen(priv, cmd_ptr, data_buf);
+ break;
+ case HostCmd_CMD_802_11_KEY_MATERIAL:
+ ret = mwifiex_cmd_802_11_key_material(priv, cmd_ptr,
+ cmd_action, cmd_oid,
+ data_buf);
+ break;
+ case HostCmd_CMD_802_11D_DOMAIN_INFO:
+ ret = mwifiex_cmd_802_11d_domain_info(priv, cmd_ptr,
+ cmd_action);
+ break;
+ case HostCmd_CMD_RECONFIGURE_TX_BUFF:
+ ret = mwifiex_cmd_recfg_tx_buf(priv, cmd_ptr, cmd_action,
+ data_buf);
+ break;
+ case HostCmd_CMD_AMSDU_AGGR_CTRL:
+ ret = mwifiex_cmd_amsdu_aggr_ctrl(cmd_ptr, cmd_action,
+ data_buf);
+ break;
+ case HostCmd_CMD_11N_CFG:
+ ret = mwifiex_cmd_11n_cfg(cmd_ptr, cmd_action,
+ data_buf);
+ break;
+ case HostCmd_CMD_WMM_GET_STATUS:
+ dev_dbg(priv->adapter->dev,
+ "cmd: WMM: WMM_GET_STATUS cmd sent\n");
+ cmd_ptr->command = cpu_to_le16(HostCmd_CMD_WMM_GET_STATUS);
+ cmd_ptr->size =
+ cpu_to_le16(sizeof(struct host_cmd_ds_wmm_get_status) +
+ S_DS_GEN);
+ ret = 0;
+ break;
+ case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
+ ret = mwifiex_cmd_ibss_coalescing_status(cmd_ptr, cmd_action,
+ data_buf);
+ break;
+ case HostCmd_CMD_MAC_REG_ACCESS:
+ case HostCmd_CMD_BBP_REG_ACCESS:
+ case HostCmd_CMD_RF_REG_ACCESS:
+ case HostCmd_CMD_PMIC_REG_ACCESS:
+ case HostCmd_CMD_CAU_REG_ACCESS:
+ case HostCmd_CMD_802_11_EEPROM_ACCESS:
+ ret = mwifiex_cmd_reg_access(cmd_ptr, cmd_action, data_buf);
+ break;
+ case HostCmd_CMD_SET_BSS_MODE:
+ cmd_ptr->command = cpu_to_le16(cmd_no);
+ if (priv->bss_mode == NL80211_IFTYPE_ADHOC)
+ cmd_ptr->params.bss_mode.con_type =
+ CONNECTION_TYPE_ADHOC;
+ else if (priv->bss_mode == NL80211_IFTYPE_STATION)
+ cmd_ptr->params.bss_mode.con_type =
+ CONNECTION_TYPE_INFRA;
+ cmd_ptr->size = cpu_to_le16(sizeof(struct
+ host_cmd_ds_set_bss_mode) + S_DS_GEN);
+ ret = 0;
+ break;
+ default:
+ dev_err(priv->adapter->dev,
+ "PREP_CMD: unknown cmd- %#x\n", cmd_no);
+ ret = -1;
+ break;
+ }
+ return ret;
+}
+
+/*
+ * This function issues commands to initialize firmware.
+ *
+ * This is called after firmware download to bring the card to
+ * working state.
+ *
+ * The following commands are issued sequentially -
+ * - Function init (for first interface only)
+ * - Read MAC address (for first interface only)
+ * - Reconfigure Tx buffer size (for first interface only)
+ * - Enable auto deep sleep (for first interface only)
+ * - Get Tx rate
+ * - Get Tx power
+ * - Set IBSS coalescing status
+ * - Set AMSDU aggregation control
+ * - Set 11d control
+ * - Set MAC control (this must be the last command to initialize firmware)
+ */
+int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
+{
+ int ret;
+ u16 enable = true;
+ struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl;
+ struct mwifiex_ds_auto_ds auto_ds;
+ enum state_11d_t state_11d;
+
+ if (first_sta) {
+
+ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_FUNC_INIT,
+ HostCmd_ACT_GEN_SET, 0, NULL);
+ if (ret)
+ return -1;
+ /* Read MAC address from HW */
+ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_GET_HW_SPEC,
+ HostCmd_ACT_GEN_GET, 0, NULL);
+ if (ret)
+ return -1;
+
+ /* Reconfigure tx buf size */
+ ret = mwifiex_send_cmd_async(priv,
+ HostCmd_CMD_RECONFIGURE_TX_BUFF,
+ HostCmd_ACT_GEN_SET, 0,
+ &priv->adapter->tx_buf_size);
+ if (ret)
+ return -1;
+
+ /* Enable IEEE PS by default */
+ priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
+ ret = mwifiex_send_cmd_async(priv,
+ HostCmd_CMD_802_11_PS_MODE_ENH,
+ EN_AUTO_PS, BITMAP_STA_PS, NULL);
+ if (ret)
+ return -1;
+ }
+
+ /* get tx rate */
+ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_TX_RATE_CFG,
+ HostCmd_ACT_GEN_GET, 0, NULL);
+ if (ret)
+ return -1;
+ priv->data_rate = 0;
+
+ /* get tx power */
+ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_TXPWR_CFG,
+ HostCmd_ACT_GEN_GET, 0, NULL);
+ if (ret)
+ return -1;
+
+ /* set ibss coalescing_status */
+ ret = mwifiex_send_cmd_async(priv,
+ HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
+ HostCmd_ACT_GEN_SET, 0, &enable);
+ if (ret)
+ return -1;
+
+ memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl));
+ amsdu_aggr_ctrl.enable = true;
+ /* Send request to firmware */
+ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_AMSDU_AGGR_CTRL,
+ HostCmd_ACT_GEN_SET, 0,
+ (void *) &amsdu_aggr_ctrl);
+ if (ret)
+ return -1;
+ /* MAC Control must be the last command in init_fw */
+ /* set MAC Control */
+ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET, 0,
+ &priv->curr_pkt_filter);
+ if (ret)
+ return -1;
+
+ if (first_sta) {
+ /* Enable auto deep sleep */
+ auto_ds.auto_ds = DEEP_SLEEP_ON;
+ auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME;
+ ret = mwifiex_send_cmd_async(priv,
+ HostCmd_CMD_802_11_PS_MODE_ENH,
+ EN_AUTO_PS, BITMAP_AUTO_DS,
+ &auto_ds);
+ if (ret)
+ return -1;
+ }
+
+ /* Send cmd to FW to enable/disable 11D function */
+ state_11d = ENABLE_11D;
+ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SNMP_MIB,
+ HostCmd_ACT_GEN_SET, DOT11D_I, &state_11d);
+ if (ret)
+ dev_err(priv->adapter->dev, "11D: failed to enable 11D\n");
+
+ /* set last_init_cmd */
+ priv->adapter->last_init_cmd = HostCmd_CMD_802_11_SNMP_MIB;
+ ret = -EINPROGRESS;
+
+ return ret;
+}
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
new file mode 100644
index 000000000000..d08f76429a0a
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -0,0 +1,972 @@
+/*
+ * Marvell Wireless LAN device driver: station command response handling
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+
+
+/*
+ * This function handles the command response error case.
+ *
+ * For scan response error, the function cancels all the pending
+ * scan commands and generates an event to inform the applications
+ * of the scan completion.
+ *
+ * For Power Save command failure, we do not retry enter PS
+ * command in case of Ad-hoc mode.
+ *
+ * For all other response errors, the current command buffer is freed
+ * and returned to the free command queue.
+ */
+static void
+mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
+{
+ struct cmd_ctrl_node *cmd_node = NULL, *tmp_node;
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct host_cmd_ds_802_11_ps_mode_enh *pm;
+ unsigned long flags;
+
+ dev_err(adapter->dev, "CMD_RESP: cmd %#x error, result=%#x\n",
+ resp->command, resp->result);
+
+ if (adapter->curr_cmd->wait_q_enabled)
+ adapter->cmd_wait_q.status = -1;
+
+ switch (le16_to_cpu(resp->command)) {
+ case HostCmd_CMD_802_11_PS_MODE_ENH:
+ pm = &resp->params.psmode_enh;
+ dev_err(adapter->dev, "PS_MODE_ENH cmd failed: "
+ "result=0x%x action=0x%X\n",
+ resp->result, le16_to_cpu(pm->action));
+ /* We do not re-try enter-ps command in ad-hoc mode. */
+ if (le16_to_cpu(pm->action) == EN_AUTO_PS &&
+ (le16_to_cpu(pm->params.ps_bitmap) & BITMAP_STA_PS) &&
+ priv->bss_mode == NL80211_IFTYPE_ADHOC)
+ adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
+
+ break;
+ case HostCmd_CMD_802_11_SCAN:
+ /* Cancel all pending scan command */
+ spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+ list_for_each_entry_safe(cmd_node, tmp_node,
+ &adapter->scan_pending_q, list) {
+ list_del(&cmd_node->list);
+ spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+ flags);
+ mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+ spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+ }
+ spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+
+ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ adapter->scan_processing = false;
+ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+ if (priv->report_scan_result)
+ priv->report_scan_result = false;
+ if (priv->scan_pending_on_block) {
+ priv->scan_pending_on_block = false;
+ up(&priv->async_sem);
+ }
+ break;
+
+ case HostCmd_CMD_MAC_CONTROL:
+ break;
+
+ default:
+ break;
+ }
+ /* Handling errors here */
+ mwifiex_insert_cmd_to_free_q(adapter, adapter->curr_cmd);
+
+ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ adapter->curr_cmd = NULL;
+ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+}
+
+/*
+ * This function handles the command response of get RSSI info.
+ *
+ * Handling includes changing the header fields into CPU format
+ * and saving the following parameters in driver -
+ * - Last data and beacon RSSI value
+ * - Average data and beacon RSSI value
+ * - Last data and beacon NF value
+ * - Average data and beacon NF value
+ *
+ * The parameters are send to the application as well, along with
+ * calculated SNR values.
+ */
+static int mwifiex_ret_802_11_rssi_info(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp,
+ void *data_buf)
+{
+ struct host_cmd_ds_802_11_rssi_info_rsp *rssi_info_rsp =
+ &resp->params.rssi_info_rsp;
+ struct mwifiex_ds_get_signal *signal;
+
+ priv->data_rssi_last = le16_to_cpu(rssi_info_rsp->data_rssi_last);
+ priv->data_nf_last = le16_to_cpu(rssi_info_rsp->data_nf_last);
+
+ priv->data_rssi_avg = le16_to_cpu(rssi_info_rsp->data_rssi_avg);
+ priv->data_nf_avg = le16_to_cpu(rssi_info_rsp->data_nf_avg);
+
+ priv->bcn_rssi_last = le16_to_cpu(rssi_info_rsp->bcn_rssi_last);
+ priv->bcn_nf_last = le16_to_cpu(rssi_info_rsp->bcn_nf_last);
+
+ priv->bcn_rssi_avg = le16_to_cpu(rssi_info_rsp->bcn_rssi_avg);
+ priv->bcn_nf_avg = le16_to_cpu(rssi_info_rsp->bcn_nf_avg);
+
+ /* Need to indicate IOCTL complete */
+ if (data_buf) {
+ signal = (struct mwifiex_ds_get_signal *) data_buf;
+ memset(signal, 0, sizeof(struct mwifiex_ds_get_signal));
+
+ signal->selector = ALL_RSSI_INFO_MASK;
+
+ /* RSSI */
+ signal->bcn_rssi_last = priv->bcn_rssi_last;
+ signal->bcn_rssi_avg = priv->bcn_rssi_avg;
+ signal->data_rssi_last = priv->data_rssi_last;
+ signal->data_rssi_avg = priv->data_rssi_avg;
+
+ /* SNR */
+ signal->bcn_snr_last =
+ CAL_SNR(priv->bcn_rssi_last, priv->bcn_nf_last);
+ signal->bcn_snr_avg =
+ CAL_SNR(priv->bcn_rssi_avg, priv->bcn_nf_avg);
+ signal->data_snr_last =
+ CAL_SNR(priv->data_rssi_last, priv->data_nf_last);
+ signal->data_snr_avg =
+ CAL_SNR(priv->data_rssi_avg, priv->data_nf_avg);
+
+ /* NF */
+ signal->bcn_nf_last = priv->bcn_nf_last;
+ signal->bcn_nf_avg = priv->bcn_nf_avg;
+ signal->data_nf_last = priv->data_nf_last;
+ signal->data_nf_avg = priv->data_nf_avg;
+ }
+
+ return 0;
+}
+
+/*
+ * This function handles the command response of set/get SNMP
+ * MIB parameters.
+ *
+ * Handling includes changing the header fields into CPU format
+ * and saving the parameter in driver.
+ *
+ * The following parameters are supported -
+ * - Fragmentation threshold
+ * - RTS threshold
+ * - Short retry limit
+ */
+static int mwifiex_ret_802_11_snmp_mib(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp,
+ void *data_buf)
+{
+ struct host_cmd_ds_802_11_snmp_mib *smib = &resp->params.smib;
+ u16 oid = le16_to_cpu(smib->oid);
+ u16 query_type = le16_to_cpu(smib->query_type);
+ u32 ul_temp;
+
+ dev_dbg(priv->adapter->dev, "info: SNMP_RESP: oid value = %#x,"
+ " query_type = %#x, buf size = %#x\n",
+ oid, query_type, le16_to_cpu(smib->buf_size));
+ if (query_type == HostCmd_ACT_GEN_GET) {
+ ul_temp = le16_to_cpu(*((__le16 *) (smib->value)));
+ if (data_buf)
+ *(u32 *)data_buf = ul_temp;
+ switch (oid) {
+ case FRAG_THRESH_I:
+ dev_dbg(priv->adapter->dev,
+ "info: SNMP_RESP: FragThsd =%u\n", ul_temp);
+ break;
+ case RTS_THRESH_I:
+ dev_dbg(priv->adapter->dev,
+ "info: SNMP_RESP: RTSThsd =%u\n", ul_temp);
+ break;
+ case SHORT_RETRY_LIM_I:
+ dev_dbg(priv->adapter->dev,
+ "info: SNMP_RESP: TxRetryCount=%u\n", ul_temp);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * This function handles the command response of get log request
+ *
+ * Handling includes changing the header fields into CPU format
+ * and sending the received parameters to application.
+ */
+static int mwifiex_ret_get_log(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp,
+ void *data_buf)
+{
+ struct host_cmd_ds_802_11_get_log *get_log =
+ (struct host_cmd_ds_802_11_get_log *) &resp->params.get_log;
+ struct mwifiex_ds_get_stats *stats;
+
+ if (data_buf) {
+ stats = (struct mwifiex_ds_get_stats *) data_buf;
+ stats->mcast_tx_frame = le32_to_cpu(get_log->mcast_tx_frame);
+ stats->failed = le32_to_cpu(get_log->failed);
+ stats->retry = le32_to_cpu(get_log->retry);
+ stats->multi_retry = le32_to_cpu(get_log->multi_retry);
+ stats->frame_dup = le32_to_cpu(get_log->frame_dup);
+ stats->rts_success = le32_to_cpu(get_log->rts_success);
+ stats->rts_failure = le32_to_cpu(get_log->rts_failure);
+ stats->ack_failure = le32_to_cpu(get_log->ack_failure);
+ stats->rx_frag = le32_to_cpu(get_log->rx_frag);
+ stats->mcast_rx_frame = le32_to_cpu(get_log->mcast_rx_frame);
+ stats->fcs_error = le32_to_cpu(get_log->fcs_error);
+ stats->tx_frame = le32_to_cpu(get_log->tx_frame);
+ stats->wep_icv_error[0] =
+ le32_to_cpu(get_log->wep_icv_err_cnt[0]);
+ stats->wep_icv_error[1] =
+ le32_to_cpu(get_log->wep_icv_err_cnt[1]);
+ stats->wep_icv_error[2] =
+ le32_to_cpu(get_log->wep_icv_err_cnt[2]);
+ stats->wep_icv_error[3] =
+ le32_to_cpu(get_log->wep_icv_err_cnt[3]);
+ }
+
+ return 0;
+}
+
+/*
+ * This function handles the command response of set/get Tx rate
+ * configurations.
+ *
+ * Handling includes changing the header fields into CPU format
+ * and saving the following parameters in driver -
+ * - DSSS rate bitmap
+ * - OFDM rate bitmap
+ * - HT MCS rate bitmaps
+ *
+ * Based on the new rate bitmaps, the function re-evaluates if
+ * auto data rate has been activated. If not, it sends another
+ * query to the firmware to get the current Tx data rate and updates
+ * the driver value.
+ */
+static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp,
+ void *data_buf)
+{
+ struct mwifiex_rate_cfg *ds_rate;
+ struct host_cmd_ds_tx_rate_cfg *rate_cfg = &resp->params.tx_rate_cfg;
+ struct mwifiex_rate_scope *rate_scope;
+ struct mwifiex_ie_types_header *head;
+ u16 tlv, tlv_buf_len;
+ u8 *tlv_buf;
+ u32 i;
+ int ret = 0;
+
+ tlv_buf = (u8 *) ((u8 *) rate_cfg) +
+ sizeof(struct host_cmd_ds_tx_rate_cfg);
+ tlv_buf_len = *(u16 *) (tlv_buf + sizeof(u16));
+
+ while (tlv_buf && tlv_buf_len > 0) {
+ tlv = (*tlv_buf);
+ tlv = tlv | (*(tlv_buf + 1) << 8);
+
+ switch (tlv) {
+ case TLV_TYPE_RATE_SCOPE:
+ rate_scope = (struct mwifiex_rate_scope *) tlv_buf;
+ priv->bitmap_rates[0] =
+ le16_to_cpu(rate_scope->hr_dsss_rate_bitmap);
+ priv->bitmap_rates[1] =
+ le16_to_cpu(rate_scope->ofdm_rate_bitmap);
+ for (i = 0;
+ i <
+ sizeof(rate_scope->ht_mcs_rate_bitmap) /
+ sizeof(u16); i++)
+ priv->bitmap_rates[2 + i] =
+ le16_to_cpu(rate_scope->
+ ht_mcs_rate_bitmap[i]);
+ break;
+ /* Add RATE_DROP tlv here */
+ }
+
+ head = (struct mwifiex_ie_types_header *) tlv_buf;
+ tlv_buf += le16_to_cpu(head->len) + sizeof(*head);
+ tlv_buf_len -= le16_to_cpu(head->len);
+ }
+
+ priv->is_data_rate_auto = mwifiex_is_rate_auto(priv);
+
+ if (priv->is_data_rate_auto)
+ priv->data_rate = 0;
+ else
+ ret = mwifiex_send_cmd_async(priv,
+ HostCmd_CMD_802_11_TX_RATE_QUERY,
+ HostCmd_ACT_GEN_GET, 0, NULL);
+
+ if (data_buf) {
+ ds_rate = (struct mwifiex_rate_cfg *) data_buf;
+ if (le16_to_cpu(rate_cfg->action) == HostCmd_ACT_GEN_GET) {
+ if (priv->is_data_rate_auto) {
+ ds_rate->is_rate_auto = 1;
+ } else {
+ ds_rate->rate = mwifiex_get_rate_index(priv->
+ bitmap_rates,
+ sizeof(priv->
+ bitmap_rates));
+ if (ds_rate->rate >=
+ MWIFIEX_RATE_BITMAP_OFDM0
+ && ds_rate->rate <=
+ MWIFIEX_RATE_BITMAP_OFDM7)
+ ds_rate->rate -=
+ (MWIFIEX_RATE_BITMAP_OFDM0 -
+ MWIFIEX_RATE_INDEX_OFDM0);
+ if (ds_rate->rate >=
+ MWIFIEX_RATE_BITMAP_MCS0
+ && ds_rate->rate <=
+ MWIFIEX_RATE_BITMAP_MCS127)
+ ds_rate->rate -=
+ (MWIFIEX_RATE_BITMAP_MCS0 -
+ MWIFIEX_RATE_INDEX_MCS0);
+ }
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * This function handles the command response of get Tx power level.
+ *
+ * Handling includes saving the maximum and minimum Tx power levels
+ * in driver, as well as sending the values to user.
+ */
+static int mwifiex_get_power_level(struct mwifiex_private *priv, void *data_buf)
+{
+ int length, max_power = -1, min_power = -1;
+ struct mwifiex_types_power_group *pg_tlv_hdr;
+ struct mwifiex_power_group *pg;
+
+ if (data_buf) {
+ pg_tlv_hdr =
+ (struct mwifiex_types_power_group *) ((u8 *) data_buf
+ + sizeof(struct host_cmd_ds_txpwr_cfg));
+ pg = (struct mwifiex_power_group *) ((u8 *) pg_tlv_hdr +
+ sizeof(struct mwifiex_types_power_group));
+ length = pg_tlv_hdr->length;
+ if (length > 0) {
+ max_power = pg->power_max;
+ min_power = pg->power_min;
+ length -= sizeof(struct mwifiex_power_group);
+ }
+ while (length) {
+ pg++;
+ if (max_power < pg->power_max)
+ max_power = pg->power_max;
+
+ if (min_power > pg->power_min)
+ min_power = pg->power_min;
+
+ length -= sizeof(struct mwifiex_power_group);
+ }
+ if (pg_tlv_hdr->length > 0) {
+ priv->min_tx_power_level = (u8) min_power;
+ priv->max_tx_power_level = (u8) max_power;
+ }
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * This function handles the command response of set/get Tx power
+ * configurations.
+ *
+ * Handling includes changing the header fields into CPU format
+ * and saving the current Tx power level in driver.
+ */
+static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp,
+ void *data_buf)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct host_cmd_ds_txpwr_cfg *txp_cfg = &resp->params.txp_cfg;
+ struct mwifiex_types_power_group *pg_tlv_hdr;
+ struct mwifiex_power_group *pg;
+ u16 action = le16_to_cpu(txp_cfg->action);
+
+ switch (action) {
+ case HostCmd_ACT_GEN_GET:
+ {
+ pg_tlv_hdr =
+ (struct mwifiex_types_power_group *) ((u8 *)
+ txp_cfg +
+ sizeof
+ (struct
+ host_cmd_ds_txpwr_cfg));
+ pg = (struct mwifiex_power_group *) ((u8 *)
+ pg_tlv_hdr +
+ sizeof(struct
+ mwifiex_types_power_group));
+ if (adapter->hw_status ==
+ MWIFIEX_HW_STATUS_INITIALIZING)
+ mwifiex_get_power_level(priv, txp_cfg);
+ priv->tx_power_level = (u16) pg->power_min;
+ break;
+ }
+ case HostCmd_ACT_GEN_SET:
+ if (le32_to_cpu(txp_cfg->mode)) {
+ pg_tlv_hdr =
+ (struct mwifiex_types_power_group *) ((u8 *)
+ txp_cfg +
+ sizeof
+ (struct
+ host_cmd_ds_txpwr_cfg));
+ pg = (struct mwifiex_power_group *) ((u8 *) pg_tlv_hdr
+ +
+ sizeof(struct
+ mwifiex_types_power_group));
+ if (pg->power_max == pg->power_min)
+ priv->tx_power_level = (u16) pg->power_min;
+ }
+ break;
+ default:
+ dev_err(adapter->dev, "CMD_RESP: unknown cmd action %d\n",
+ action);
+ return 0;
+ }
+ dev_dbg(adapter->dev,
+ "info: Current TxPower Level = %d, Max Power=%d, Min Power=%d\n",
+ priv->tx_power_level, priv->max_tx_power_level,
+ priv->min_tx_power_level);
+
+ return 0;
+}
+
+/*
+ * This function handles the command response of set/get MAC address.
+ *
+ * Handling includes saving the MAC address in driver.
+ */
+static int mwifiex_ret_802_11_mac_address(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
+{
+ struct host_cmd_ds_802_11_mac_address *cmd_mac_addr =
+ &resp->params.mac_addr;
+
+ memcpy(priv->curr_addr, cmd_mac_addr->mac_addr, ETH_ALEN);
+
+ dev_dbg(priv->adapter->dev,
+ "info: set mac address: %pM\n", priv->curr_addr);
+
+ return 0;
+}
+
+/*
+ * This function handles the command response of set/get MAC multicast
+ * address.
+ */
+static int mwifiex_ret_mac_multicast_adr(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
+{
+ return 0;
+}
+
+/*
+ * This function handles the command response of get Tx rate query.
+ *
+ * Handling includes changing the header fields into CPU format
+ * and saving the Tx rate and HT information parameters in driver.
+ *
+ * Both rate configuration and current data rate can be retrieved
+ * with this request.
+ */
+static int mwifiex_ret_802_11_tx_rate_query(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
+{
+ priv->tx_rate = resp->params.tx_rate.tx_rate;
+ priv->tx_htinfo = resp->params.tx_rate.ht_info;
+ if (!priv->is_data_rate_auto)
+ priv->data_rate =
+ mwifiex_index_to_data_rate(priv->tx_rate,
+ priv->tx_htinfo);
+
+ return 0;
+}
+
+/*
+ * This function handles the command response of a deauthenticate
+ * command.
+ *
+ * If the deauthenticated MAC matches the current BSS MAC, the connection
+ * state is reset.
+ */
+static int mwifiex_ret_802_11_deauthenticate(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+
+ adapter->dbg.num_cmd_deauth++;
+ if (!memcmp(resp->params.deauth.mac_addr,
+ &priv->curr_bss_params.bss_descriptor.mac_address,
+ sizeof(resp->params.deauth.mac_addr)))
+ mwifiex_reset_connect_state(priv);
+
+ return 0;
+}
+
+/*
+ * This function handles the command response of ad-hoc stop.
+ *
+ * The function resets the connection state in driver.
+ */
+static int mwifiex_ret_802_11_ad_hoc_stop(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
+{
+ mwifiex_reset_connect_state(priv);
+ return 0;
+}
+
+/*
+ * This function handles the command response of set/get key material.
+ *
+ * Handling includes updating the driver parameters to reflect the
+ * changes.
+ */
+static int mwifiex_ret_802_11_key_material(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
+{
+ struct host_cmd_ds_802_11_key_material *key =
+ &resp->params.key_material;
+
+ if (le16_to_cpu(key->action) == HostCmd_ACT_GEN_SET) {
+ if ((le16_to_cpu(key->key_param_set.key_info) & KEY_MCAST)) {
+ dev_dbg(priv->adapter->dev, "info: key: GTK is set\n");
+ priv->wpa_is_gtk_set = true;
+ priv->scan_block = false;
+ }
+ }
+
+ memset(priv->aes_key.key_param_set.key, 0,
+ sizeof(key->key_param_set.key));
+ priv->aes_key.key_param_set.key_len = key->key_param_set.key_len;
+ memcpy(priv->aes_key.key_param_set.key, key->key_param_set.key,
+ le16_to_cpu(priv->aes_key.key_param_set.key_len));
+
+ return 0;
+}
+
+/*
+ * This function handles the command response of get 11d domain information.
+ */
+static int mwifiex_ret_802_11d_domain_info(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
+{
+ struct host_cmd_ds_802_11d_domain_info_rsp *domain_info =
+ &resp->params.domain_info_resp;
+ struct mwifiex_ietypes_domain_param_set *domain = &domain_info->domain;
+ u16 action = le16_to_cpu(domain_info->action);
+ u8 no_of_triplet;
+
+ no_of_triplet = (u8) ((le16_to_cpu(domain->header.len) -
+ IEEE80211_COUNTRY_STRING_LEN) /
+ sizeof(struct ieee80211_country_ie_triplet));
+
+ dev_dbg(priv->adapter->dev, "info: 11D Domain Info Resp:"
+ " no_of_triplet=%d\n", no_of_triplet);
+
+ if (no_of_triplet > MWIFIEX_MAX_TRIPLET_802_11D) {
+ dev_warn(priv->adapter->dev,
+ "11D: invalid number of triplets %d "
+ "returned!!\n", no_of_triplet);
+ return -1;
+ }
+
+ switch (action) {
+ case HostCmd_ACT_GEN_SET: /* Proc Set Action */
+ break;
+ case HostCmd_ACT_GEN_GET:
+ break;
+ default:
+ dev_err(priv->adapter->dev,
+ "11D: invalid action:%d\n", domain_info->action);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * This function handles the command response of get RF channel.
+ *
+ * Handling includes changing the header fields into CPU format
+ * and saving the new channel in driver.
+ */
+static int mwifiex_ret_802_11_rf_channel(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp,
+ void *data_buf)
+{
+ struct host_cmd_ds_802_11_rf_channel *rf_channel =
+ &resp->params.rf_channel;
+ u16 new_channel = le16_to_cpu(rf_channel->current_channel);
+
+ if (priv->curr_bss_params.bss_descriptor.channel != new_channel) {
+ dev_dbg(priv->adapter->dev, "cmd: Channel Switch: %d to %d\n",
+ priv->curr_bss_params.bss_descriptor.channel,
+ new_channel);
+ /* Update the channel again */
+ priv->curr_bss_params.bss_descriptor.channel = new_channel;
+ }
+ if (data_buf)
+ *((u16 *)data_buf) = new_channel;
+
+ return 0;
+}
+
+/*
+ * This function handles the command response of get extended version.
+ *
+ * Handling includes forming the extended version string and sending it
+ * to application.
+ */
+static int mwifiex_ret_ver_ext(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp,
+ void *data_buf)
+{
+ struct host_cmd_ds_version_ext *ver_ext = &resp->params.verext;
+ struct host_cmd_ds_version_ext *version_ext;
+
+ if (data_buf) {
+ version_ext = (struct host_cmd_ds_version_ext *)data_buf;
+ version_ext->version_str_sel = ver_ext->version_str_sel;
+ memcpy(version_ext->version_str, ver_ext->version_str,
+ sizeof(char) * 128);
+ memcpy(priv->version_str, ver_ext->version_str, 128);
+ }
+ return 0;
+}
+
+/*
+ * This function handles the command response of register access.
+ *
+ * The register value and offset are returned to the user. For EEPROM
+ * access, the byte count is also returned.
+ */
+static int mwifiex_ret_reg_access(u16 type, struct host_cmd_ds_command *resp,
+ void *data_buf)
+{
+ struct mwifiex_ds_reg_rw *reg_rw;
+ struct mwifiex_ds_read_eeprom *eeprom;
+
+ if (data_buf) {
+ reg_rw = (struct mwifiex_ds_reg_rw *) data_buf;
+ eeprom = (struct mwifiex_ds_read_eeprom *) data_buf;
+ switch (type) {
+ case HostCmd_CMD_MAC_REG_ACCESS:
+ {
+ struct host_cmd_ds_mac_reg_access *reg;
+ reg = (struct host_cmd_ds_mac_reg_access *)
+ &resp->params.mac_reg;
+ reg_rw->offset = cpu_to_le32(
+ (u32) le16_to_cpu(reg->offset));
+ reg_rw->value = reg->value;
+ break;
+ }
+ case HostCmd_CMD_BBP_REG_ACCESS:
+ {
+ struct host_cmd_ds_bbp_reg_access *reg;
+ reg = (struct host_cmd_ds_bbp_reg_access *)
+ &resp->params.bbp_reg;
+ reg_rw->offset = cpu_to_le32(
+ (u32) le16_to_cpu(reg->offset));
+ reg_rw->value = cpu_to_le32((u32) reg->value);
+ break;
+ }
+
+ case HostCmd_CMD_RF_REG_ACCESS:
+ {
+ struct host_cmd_ds_rf_reg_access *reg;
+ reg = (struct host_cmd_ds_rf_reg_access *)
+ &resp->params.rf_reg;
+ reg_rw->offset = cpu_to_le32(
+ (u32) le16_to_cpu(reg->offset));
+ reg_rw->value = cpu_to_le32((u32) reg->value);
+ break;
+ }
+ case HostCmd_CMD_PMIC_REG_ACCESS:
+ {
+ struct host_cmd_ds_pmic_reg_access *reg;
+ reg = (struct host_cmd_ds_pmic_reg_access *)
+ &resp->params.pmic_reg;
+ reg_rw->offset = cpu_to_le32(
+ (u32) le16_to_cpu(reg->offset));
+ reg_rw->value = cpu_to_le32((u32) reg->value);
+ break;
+ }
+ case HostCmd_CMD_CAU_REG_ACCESS:
+ {
+ struct host_cmd_ds_rf_reg_access *reg;
+ reg = (struct host_cmd_ds_rf_reg_access *)
+ &resp->params.rf_reg;
+ reg_rw->offset = cpu_to_le32(
+ (u32) le16_to_cpu(reg->offset));
+ reg_rw->value = cpu_to_le32((u32) reg->value);
+ break;
+ }
+ case HostCmd_CMD_802_11_EEPROM_ACCESS:
+ {
+ struct host_cmd_ds_802_11_eeprom_access
+ *cmd_eeprom =
+ (struct host_cmd_ds_802_11_eeprom_access
+ *) &resp->params.eeprom;
+ pr_debug("info: EEPROM read len=%x\n",
+ cmd_eeprom->byte_count);
+ if (le16_to_cpu(eeprom->byte_count) <
+ le16_to_cpu(
+ cmd_eeprom->byte_count)) {
+ eeprom->byte_count = cpu_to_le16(0);
+ pr_debug("info: EEPROM read "
+ "length is too big\n");
+ return -1;
+ }
+ eeprom->offset = cmd_eeprom->offset;
+ eeprom->byte_count = cmd_eeprom->byte_count;
+ if (le16_to_cpu(eeprom->byte_count) > 0)
+ memcpy(&eeprom->value,
+ &cmd_eeprom->value,
+ le16_to_cpu(eeprom->byte_count));
+
+ break;
+ }
+ default:
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * This function handles the command response of get IBSS coalescing status.
+ *
+ * If the received BSSID is different than the current one, the current BSSID,
+ * beacon interval, ATIM window and ERP information are updated, along with
+ * changing the ad-hoc state accordingly.
+ */
+static int mwifiex_ret_ibss_coalescing_status(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *resp)
+{
+ struct host_cmd_ds_802_11_ibss_status *ibss_coal_resp =
+ &(resp->params.ibss_coalescing);
+ u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+
+ if (le16_to_cpu(ibss_coal_resp->action) == HostCmd_ACT_GEN_SET)
+ return 0;
+
+ dev_dbg(priv->adapter->dev,
+ "info: new BSSID %pM\n", ibss_coal_resp->bssid);
+
+ /* If rsp has NULL BSSID, Just return..... No Action */
+ if (!memcmp(ibss_coal_resp->bssid, zero_mac, ETH_ALEN)) {
+ dev_warn(priv->adapter->dev, "new BSSID is NULL\n");
+ return 0;
+ }
+
+ /* If BSSID is diff, modify current BSS parameters */
+ if (memcmp(priv->curr_bss_params.bss_descriptor.mac_address,
+ ibss_coal_resp->bssid, ETH_ALEN)) {
+ /* BSSID */
+ memcpy(priv->curr_bss_params.bss_descriptor.mac_address,
+ ibss_coal_resp->bssid, ETH_ALEN);
+
+ /* Beacon Interval */
+ priv->curr_bss_params.bss_descriptor.beacon_period
+ = le16_to_cpu(ibss_coal_resp->beacon_interval);
+
+ /* ERP Information */
+ priv->curr_bss_params.bss_descriptor.erp_flags =
+ (u8) le16_to_cpu(ibss_coal_resp->use_g_rate_protect);
+
+ priv->adhoc_state = ADHOC_COALESCED;
+ }
+
+ return 0;
+}
+
+/*
+ * This function handles the command responses.
+ *
+ * This is a generic function, which calls command specific
+ * response handlers based on the command ID.
+ */
+int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv,
+ u16 cmdresp_no, void *cmd_buf)
+{
+ int ret = 0;
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct host_cmd_ds_command *resp =
+ (struct host_cmd_ds_command *) cmd_buf;
+ void *data_buf = adapter->curr_cmd->data_buf;
+
+ /* If the command is not successful, cleanup and return failure */
+ if (resp->result != HostCmd_RESULT_OK) {
+ mwifiex_process_cmdresp_error(priv, resp);
+ return -1;
+ }
+ /* Command successful, handle response */
+ switch (cmdresp_no) {
+ case HostCmd_CMD_GET_HW_SPEC:
+ ret = mwifiex_ret_get_hw_spec(priv, resp);
+ break;
+ case HostCmd_CMD_MAC_CONTROL:
+ break;
+ case HostCmd_CMD_802_11_MAC_ADDRESS:
+ ret = mwifiex_ret_802_11_mac_address(priv, resp);
+ break;
+ case HostCmd_CMD_MAC_MULTICAST_ADR:
+ ret = mwifiex_ret_mac_multicast_adr(priv, resp);
+ break;
+ case HostCmd_CMD_TX_RATE_CFG:
+ ret = mwifiex_ret_tx_rate_cfg(priv, resp, data_buf);
+ break;
+ case HostCmd_CMD_802_11_SCAN:
+ ret = mwifiex_ret_802_11_scan(priv, resp);
+ adapter->curr_cmd->wait_q_enabled = false;
+ break;
+ case HostCmd_CMD_802_11_BG_SCAN_QUERY:
+ ret = mwifiex_ret_802_11_scan(priv, resp);
+ dev_dbg(adapter->dev,
+ "info: CMD_RESP: BG_SCAN result is ready!\n");
+ break;
+ case HostCmd_CMD_TXPWR_CFG:
+ ret = mwifiex_ret_tx_power_cfg(priv, resp, data_buf);
+ break;
+ case HostCmd_CMD_802_11_PS_MODE_ENH:
+ ret = mwifiex_ret_enh_power_mode(priv, resp, data_buf);
+ break;
+ case HostCmd_CMD_802_11_HS_CFG_ENH:
+ ret = mwifiex_ret_802_11_hs_cfg(priv, resp);
+ break;
+ case HostCmd_CMD_802_11_ASSOCIATE:
+ ret = mwifiex_ret_802_11_associate(priv, resp);
+ break;
+ case HostCmd_CMD_802_11_DEAUTHENTICATE:
+ ret = mwifiex_ret_802_11_deauthenticate(priv, resp);
+ break;
+ case HostCmd_CMD_802_11_AD_HOC_START:
+ case HostCmd_CMD_802_11_AD_HOC_JOIN:
+ ret = mwifiex_ret_802_11_ad_hoc(priv, resp);
+ break;
+ case HostCmd_CMD_802_11_AD_HOC_STOP:
+ ret = mwifiex_ret_802_11_ad_hoc_stop(priv, resp);
+ break;
+ case HostCmd_CMD_802_11_GET_LOG:
+ ret = mwifiex_ret_get_log(priv, resp, data_buf);
+ break;
+ case HostCmd_CMD_RSSI_INFO:
+ ret = mwifiex_ret_802_11_rssi_info(priv, resp, data_buf);
+ break;
+ case HostCmd_CMD_802_11_SNMP_MIB:
+ ret = mwifiex_ret_802_11_snmp_mib(priv, resp, data_buf);
+ break;
+ case HostCmd_CMD_802_11_TX_RATE_QUERY:
+ ret = mwifiex_ret_802_11_tx_rate_query(priv, resp);
+ break;
+ case HostCmd_CMD_802_11_RF_CHANNEL:
+ ret = mwifiex_ret_802_11_rf_channel(priv, resp, data_buf);
+ break;
+ case HostCmd_CMD_VERSION_EXT:
+ ret = mwifiex_ret_ver_ext(priv, resp, data_buf);
+ break;
+ case HostCmd_CMD_FUNC_INIT:
+ case HostCmd_CMD_FUNC_SHUTDOWN:
+ break;
+ case HostCmd_CMD_802_11_KEY_MATERIAL:
+ ret = mwifiex_ret_802_11_key_material(priv, resp);
+ break;
+ case HostCmd_CMD_802_11D_DOMAIN_INFO:
+ ret = mwifiex_ret_802_11d_domain_info(priv, resp);
+ break;
+ case HostCmd_CMD_11N_ADDBA_REQ:
+ ret = mwifiex_ret_11n_addba_req(priv, resp);
+ break;
+ case HostCmd_CMD_11N_DELBA:
+ ret = mwifiex_ret_11n_delba(priv, resp);
+ break;
+ case HostCmd_CMD_11N_ADDBA_RSP:
+ ret = mwifiex_ret_11n_addba_resp(priv, resp);
+ break;
+ case HostCmd_CMD_RECONFIGURE_TX_BUFF:
+ adapter->tx_buf_size = (u16) le16_to_cpu(resp->params.
+ tx_buf.buff_size);
+ adapter->tx_buf_size = (adapter->tx_buf_size /
+ MWIFIEX_SDIO_BLOCK_SIZE) *
+ MWIFIEX_SDIO_BLOCK_SIZE;
+ adapter->curr_tx_buf_size = adapter->tx_buf_size;
+ dev_dbg(adapter->dev,
+ "cmd: max_tx_buf_size=%d, tx_buf_size=%d\n",
+ adapter->max_tx_buf_size, adapter->tx_buf_size);
+
+ if (adapter->if_ops.update_mp_end_port)
+ adapter->if_ops.update_mp_end_port(adapter,
+ le16_to_cpu(resp->
+ params.
+ tx_buf.
+ mp_end_port));
+ break;
+ case HostCmd_CMD_AMSDU_AGGR_CTRL:
+ ret = mwifiex_ret_amsdu_aggr_ctrl(resp, data_buf);
+ break;
+ case HostCmd_CMD_WMM_GET_STATUS:
+ ret = mwifiex_ret_wmm_get_status(priv, resp);
+ break;
+ case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:
+ ret = mwifiex_ret_ibss_coalescing_status(priv, resp);
+ break;
+ case HostCmd_CMD_MAC_REG_ACCESS:
+ case HostCmd_CMD_BBP_REG_ACCESS:
+ case HostCmd_CMD_RF_REG_ACCESS:
+ case HostCmd_CMD_PMIC_REG_ACCESS:
+ case HostCmd_CMD_CAU_REG_ACCESS:
+ case HostCmd_CMD_802_11_EEPROM_ACCESS:
+ ret = mwifiex_ret_reg_access(cmdresp_no, resp, data_buf);
+ break;
+ case HostCmd_CMD_SET_BSS_MODE:
+ break;
+ case HostCmd_CMD_11N_CFG:
+ ret = mwifiex_ret_11n_cfg(resp, data_buf);
+ break;
+ default:
+ dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n",
+ resp->command);
+ break;
+ }
+
+ return ret;
+}
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c
new file mode 100644
index 000000000000..fc265cab0907
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sta_event.c
@@ -0,0 +1,406 @@
+/*
+ * Marvell Wireless LAN device driver: station event handling
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+
+/*
+ * This function resets the connection state.
+ *
+ * The function is invoked after receiving a disconnect event from firmware,
+ * and performs the following actions -
+ * - Set media status to disconnected
+ * - Clean up Tx and Rx packets
+ * - Resets SNR/NF/RSSI value in driver
+ * - Resets security configurations in driver
+ * - Enables auto data rate
+ * - Saves the previous SSID and BSSID so that they can
+ * be used for re-association, if required
+ * - Erases current SSID and BSSID information
+ * - Sends a disconnect event to upper layers/applications.
+ */
+void
+mwifiex_reset_connect_state(struct mwifiex_private *priv)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+
+ if (!priv->media_connected)
+ return;
+
+ dev_dbg(adapter->dev, "info: handles disconnect event\n");
+
+ priv->media_connected = false;
+
+ priv->scan_block = false;
+
+ /* Free Tx and Rx packets, report disconnect to upper layer */
+ mwifiex_clean_txrx(priv);
+
+ /* Reset SNR/NF/RSSI values */
+ priv->data_rssi_last = 0;
+ priv->data_nf_last = 0;
+ priv->data_rssi_avg = 0;
+ priv->data_nf_avg = 0;
+ priv->bcn_rssi_last = 0;
+ priv->bcn_nf_last = 0;
+ priv->bcn_rssi_avg = 0;
+ priv->bcn_nf_avg = 0;
+ priv->rxpd_rate = 0;
+ priv->rxpd_htinfo = 0;
+ priv->sec_info.wpa_enabled = false;
+ priv->sec_info.wpa2_enabled = false;
+ priv->wpa_ie_len = 0;
+
+ priv->sec_info.wapi_enabled = false;
+ priv->wapi_ie_len = 0;
+ priv->sec_info.wapi_key_on = false;
+
+ priv->sec_info.encryption_mode = 0;
+
+ /* Enable auto data rate */
+ priv->is_data_rate_auto = true;
+ priv->data_rate = 0;
+
+ if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
+ priv->adhoc_state = ADHOC_IDLE;
+ priv->adhoc_is_link_sensed = false;
+ }
+
+ /*
+ * Memorize the previous SSID and BSSID so
+ * it could be used for re-assoc
+ */
+
+ dev_dbg(adapter->dev, "info: previous SSID=%s, SSID len=%u\n",
+ priv->prev_ssid.ssid, priv->prev_ssid.ssid_len);
+
+ dev_dbg(adapter->dev, "info: current SSID=%s, SSID len=%u\n",
+ priv->curr_bss_params.bss_descriptor.ssid.ssid,
+ priv->curr_bss_params.bss_descriptor.ssid.ssid_len);
+
+ memcpy(&priv->prev_ssid,
+ &priv->curr_bss_params.bss_descriptor.ssid,
+ sizeof(struct mwifiex_802_11_ssid));
+
+ memcpy(priv->prev_bssid,
+ priv->curr_bss_params.bss_descriptor.mac_address, ETH_ALEN);
+
+ /* Need to erase the current SSID and BSSID info */
+ memset(&priv->curr_bss_params, 0x00, sizeof(priv->curr_bss_params));
+
+ adapter->tx_lock_flag = false;
+ adapter->pps_uapsd_mode = false;
+
+ if (adapter->num_cmd_timeout && adapter->curr_cmd)
+ return;
+ priv->media_connected = false;
+ if (!priv->disconnect) {
+ priv->disconnect = 1;
+ dev_dbg(adapter->dev, "info: successfully disconnected from"
+ " %pM: reason code %d\n", priv->cfg_bssid,
+ WLAN_REASON_DEAUTH_LEAVING);
+ cfg80211_disconnected(priv->netdev,
+ WLAN_REASON_DEAUTH_LEAVING, NULL, 0,
+ GFP_KERNEL);
+ queue_work(priv->workqueue, &priv->cfg_workqueue);
+ }
+ if (!netif_queue_stopped(priv->netdev))
+ netif_stop_queue(priv->netdev);
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ /* Reset wireless stats signal info */
+ priv->w_stats.qual.level = 0;
+ priv->w_stats.qual.noise = 0;
+}
+
+/*
+ * This function handles events generated by firmware.
+ *
+ * This is a generic function and handles all events.
+ *
+ * Event specific routines are called by this function based
+ * upon the generated event cause.
+ *
+ * For the following events, the function just forwards them to upper
+ * layers, optionally recording the change -
+ * - EVENT_LINK_SENSED
+ * - EVENT_MIC_ERR_UNICAST
+ * - EVENT_MIC_ERR_MULTICAST
+ * - EVENT_PORT_RELEASE
+ * - EVENT_RSSI_LOW
+ * - EVENT_SNR_LOW
+ * - EVENT_MAX_FAIL
+ * - EVENT_RSSI_HIGH
+ * - EVENT_SNR_HIGH
+ * - EVENT_DATA_RSSI_LOW
+ * - EVENT_DATA_SNR_LOW
+ * - EVENT_DATA_RSSI_HIGH
+ * - EVENT_DATA_SNR_HIGH
+ * - EVENT_LINK_QUALITY
+ * - EVENT_PRE_BEACON_LOST
+ * - EVENT_IBSS_COALESCED
+ * - EVENT_WEP_ICV_ERR
+ * - EVENT_BW_CHANGE
+ * - EVENT_HOSTWAKE_STAIE
+ *
+ * For the following events, no action is taken -
+ * - EVENT_MIB_CHANGED
+ * - EVENT_INIT_DONE
+ * - EVENT_DUMMY_HOST_WAKEUP_SIGNAL
+ *
+ * Rest of the supported events requires driver handling -
+ * - EVENT_DEAUTHENTICATED
+ * - EVENT_DISASSOCIATED
+ * - EVENT_LINK_LOST
+ * - EVENT_PS_SLEEP
+ * - EVENT_PS_AWAKE
+ * - EVENT_DEEP_SLEEP_AWAKE
+ * - EVENT_HS_ACT_REQ
+ * - EVENT_ADHOC_BCN_LOST
+ * - EVENT_BG_SCAN_REPORT
+ * - EVENT_WMM_STATUS_CHANGE
+ * - EVENT_ADDBA
+ * - EVENT_DELBA
+ * - EVENT_BA_STREAM_TIEMOUT
+ * - EVENT_AMSDU_AGGR_CTRL
+ */
+int mwifiex_process_sta_event(struct mwifiex_private *priv)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ int ret = 0;
+ u32 eventcause = adapter->event_cause;
+
+ switch (eventcause) {
+ case EVENT_DUMMY_HOST_WAKEUP_SIGNAL:
+ dev_err(adapter->dev, "invalid EVENT: DUMMY_HOST_WAKEUP_SIGNAL,"
+ " ignoring it\n");
+ break;
+ case EVENT_LINK_SENSED:
+ dev_dbg(adapter->dev, "event: LINK_SENSED\n");
+ if (!netif_carrier_ok(priv->netdev))
+ netif_carrier_on(priv->netdev);
+ if (netif_queue_stopped(priv->netdev))
+ netif_wake_queue(priv->netdev);
+ break;
+
+ case EVENT_DEAUTHENTICATED:
+ dev_dbg(adapter->dev, "event: Deauthenticated\n");
+ adapter->dbg.num_event_deauth++;
+ if (priv->media_connected)
+ mwifiex_reset_connect_state(priv);
+ break;
+
+ case EVENT_DISASSOCIATED:
+ dev_dbg(adapter->dev, "event: Disassociated\n");
+ adapter->dbg.num_event_disassoc++;
+ if (priv->media_connected)
+ mwifiex_reset_connect_state(priv);
+ break;
+
+ case EVENT_LINK_LOST:
+ dev_dbg(adapter->dev, "event: Link lost\n");
+ adapter->dbg.num_event_link_lost++;
+ if (priv->media_connected)
+ mwifiex_reset_connect_state(priv);
+ break;
+
+ case EVENT_PS_SLEEP:
+ dev_dbg(adapter->dev, "info: EVENT: SLEEP\n");
+
+ adapter->ps_state = PS_STATE_PRE_SLEEP;
+
+ mwifiex_check_ps_cond(adapter);
+ break;
+
+ case EVENT_PS_AWAKE:
+ dev_dbg(adapter->dev, "info: EVENT: AWAKE\n");
+ if (!adapter->pps_uapsd_mode &&
+ priv->media_connected &&
+ adapter->sleep_period.period) {
+ adapter->pps_uapsd_mode = true;
+ dev_dbg(adapter->dev,
+ "event: PPS/UAPSD mode activated\n");
+ }
+ adapter->tx_lock_flag = false;
+ if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) {
+ if (mwifiex_check_last_packet_indication(priv)) {
+ if (!adapter->data_sent) {
+ if (!mwifiex_send_null_packet(priv,
+ MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET
+ |
+ MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET))
+ adapter->ps_state =
+ PS_STATE_SLEEP;
+ return 0;
+ }
+ }
+ }
+ adapter->ps_state = PS_STATE_AWAKE;
+ adapter->pm_wakeup_card_req = false;
+ adapter->pm_wakeup_fw_try = false;
+
+ break;
+
+ case EVENT_DEEP_SLEEP_AWAKE:
+ adapter->if_ops.wakeup_complete(adapter);
+ dev_dbg(adapter->dev, "event: DS_AWAKE\n");
+ if (adapter->is_deep_sleep)
+ adapter->is_deep_sleep = false;
+ break;
+
+ case EVENT_HS_ACT_REQ:
+ dev_dbg(adapter->dev, "event: HS_ACT_REQ\n");
+ ret = mwifiex_send_cmd_async(priv,
+ HostCmd_CMD_802_11_HS_CFG_ENH,
+ 0, 0, NULL);
+ break;
+
+ case EVENT_MIC_ERR_UNICAST:
+ dev_dbg(adapter->dev, "event: UNICAST MIC ERROR\n");
+ break;
+
+ case EVENT_MIC_ERR_MULTICAST:
+ dev_dbg(adapter->dev, "event: MULTICAST MIC ERROR\n");
+ break;
+ case EVENT_MIB_CHANGED:
+ case EVENT_INIT_DONE:
+ break;
+
+ case EVENT_ADHOC_BCN_LOST:
+ dev_dbg(adapter->dev, "event: ADHOC_BCN_LOST\n");
+ priv->adhoc_is_link_sensed = false;
+ mwifiex_clean_txrx(priv);
+ if (!netif_queue_stopped(priv->netdev))
+ netif_stop_queue(priv->netdev);
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ break;
+
+ case EVENT_BG_SCAN_REPORT:
+ dev_dbg(adapter->dev, "event: BGS_REPORT\n");
+ /* Clear the previous scan result */
+ memset(adapter->scan_table, 0x00,
+ sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP);
+ adapter->num_in_scan_table = 0;
+ adapter->bcn_buf_end = adapter->bcn_buf;
+ ret = mwifiex_send_cmd_async(priv,
+ HostCmd_CMD_802_11_BG_SCAN_QUERY,
+ HostCmd_ACT_GEN_GET, 0, NULL);
+ break;
+
+ case EVENT_PORT_RELEASE:
+ dev_dbg(adapter->dev, "event: PORT RELEASE\n");
+ break;
+
+ case EVENT_WMM_STATUS_CHANGE:
+ dev_dbg(adapter->dev, "event: WMM status changed\n");
+ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_WMM_GET_STATUS,
+ 0, 0, NULL);
+ break;
+
+ case EVENT_RSSI_LOW:
+ dev_dbg(adapter->dev, "event: Beacon RSSI_LOW\n");
+ break;
+ case EVENT_SNR_LOW:
+ dev_dbg(adapter->dev, "event: Beacon SNR_LOW\n");
+ break;
+ case EVENT_MAX_FAIL:
+ dev_dbg(adapter->dev, "event: MAX_FAIL\n");
+ break;
+ case EVENT_RSSI_HIGH:
+ dev_dbg(adapter->dev, "event: Beacon RSSI_HIGH\n");
+ break;
+ case EVENT_SNR_HIGH:
+ dev_dbg(adapter->dev, "event: Beacon SNR_HIGH\n");
+ break;
+ case EVENT_DATA_RSSI_LOW:
+ dev_dbg(adapter->dev, "event: Data RSSI_LOW\n");
+ break;
+ case EVENT_DATA_SNR_LOW:
+ dev_dbg(adapter->dev, "event: Data SNR_LOW\n");
+ break;
+ case EVENT_DATA_RSSI_HIGH:
+ dev_dbg(adapter->dev, "event: Data RSSI_HIGH\n");
+ break;
+ case EVENT_DATA_SNR_HIGH:
+ dev_dbg(adapter->dev, "event: Data SNR_HIGH\n");
+ break;
+ case EVENT_LINK_QUALITY:
+ dev_dbg(adapter->dev, "event: Link Quality\n");
+ break;
+ case EVENT_PRE_BEACON_LOST:
+ dev_dbg(adapter->dev, "event: Pre-Beacon Lost\n");
+ break;
+ case EVENT_IBSS_COALESCED:
+ dev_dbg(adapter->dev, "event: IBSS_COALESCED\n");
+ ret = mwifiex_send_cmd_async(priv,
+ HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
+ HostCmd_ACT_GEN_GET, 0, NULL);
+ break;
+ case EVENT_ADDBA:
+ dev_dbg(adapter->dev, "event: ADDBA Request\n");
+ mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_RSP,
+ HostCmd_ACT_GEN_SET, 0,
+ adapter->event_body);
+ break;
+ case EVENT_DELBA:
+ dev_dbg(adapter->dev, "event: DELBA Request\n");
+ mwifiex_11n_delete_ba_stream(priv, adapter->event_body);
+ break;
+ case EVENT_BA_STREAM_TIEMOUT:
+ dev_dbg(adapter->dev, "event: BA Stream timeout\n");
+ mwifiex_11n_ba_stream_timeout(priv,
+ (struct host_cmd_ds_11n_batimeout
+ *)
+ adapter->event_body);
+ break;
+ case EVENT_AMSDU_AGGR_CTRL:
+ dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n",
+ *(u16 *) adapter->event_body);
+ adapter->tx_buf_size =
+ min(adapter->curr_tx_buf_size,
+ le16_to_cpu(*(__le16 *) adapter->event_body));
+ dev_dbg(adapter->dev, "event: tx_buf_size %d\n",
+ adapter->tx_buf_size);
+ break;
+
+ case EVENT_WEP_ICV_ERR:
+ dev_dbg(adapter->dev, "event: WEP ICV error\n");
+ break;
+
+ case EVENT_BW_CHANGE:
+ dev_dbg(adapter->dev, "event: BW Change\n");
+ break;
+
+ case EVENT_HOSTWAKE_STAIE:
+ dev_dbg(adapter->dev, "event: HOSTWAKE_STAIE %d\n", eventcause);
+ break;
+ default:
+ dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
+ eventcause);
+ break;
+ }
+
+ return ret;
+}
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
new file mode 100644
index 000000000000..d05907d05039
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -0,0 +1,1593 @@
+/*
+ * Marvell Wireless LAN device driver: functions for station ioctl
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+#include "cfg80211.h"
+
+/*
+ * Copies the multicast address list from device to driver.
+ *
+ * This function does not validate the destination memory for
+ * size, and the calling function must ensure enough memory is
+ * available.
+ */
+int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist,
+ struct net_device *dev)
+{
+ int i = 0;
+ struct netdev_hw_addr *ha;
+
+ netdev_for_each_mc_addr(ha, dev)
+ memcpy(&mlist->mac_list[i++], ha->addr, ETH_ALEN);
+
+ return i;
+}
+
+/*
+ * Wait queue completion handler.
+ *
+ * This function waits on a cmd wait queue. It also cancels the pending
+ * request after waking up, in case of errors.
+ */
+int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter)
+{
+ bool cancel_flag = false;
+ int status = adapter->cmd_wait_q.status;
+
+ dev_dbg(adapter->dev, "cmd pending\n");
+ atomic_inc(&adapter->cmd_pending);
+
+ /* Status pending, wake up main process */
+ queue_work(adapter->workqueue, &adapter->main_work);
+
+ /* Wait for completion */
+ wait_event_interruptible(adapter->cmd_wait_q.wait,
+ adapter->cmd_wait_q.condition);
+ if (!adapter->cmd_wait_q.condition)
+ cancel_flag = true;
+
+ if (cancel_flag) {
+ mwifiex_cancel_pending_ioctl(adapter);
+ dev_dbg(adapter->dev, "cmd cancel\n");
+ }
+ adapter->cmd_wait_q.status = 0;
+
+ return status;
+}
+
+/*
+ * This function prepares the correct firmware command and
+ * issues it to set the multicast list.
+ *
+ * This function can be used to enable promiscuous mode, or enable all
+ * multicast packets, or to enable selective multicast.
+ */
+int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
+ struct mwifiex_multicast_list *mcast_list)
+{
+ int ret = 0;
+ u16 old_pkt_filter;
+
+ old_pkt_filter = priv->curr_pkt_filter;
+
+ if (mcast_list->mode == MWIFIEX_PROMISC_MODE) {
+ dev_dbg(priv->adapter->dev, "info: Enable Promiscuous mode\n");
+ priv->curr_pkt_filter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
+ priv->curr_pkt_filter &=
+ ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
+ } else {
+ /* Multicast */
+ priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE;
+ if (mcast_list->mode == MWIFIEX_MULTICAST_MODE) {
+ dev_dbg(priv->adapter->dev,
+ "info: Enabling All Multicast!\n");
+ priv->curr_pkt_filter |=
+ HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
+ } else {
+ priv->curr_pkt_filter &=
+ ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE;
+ if (mcast_list->num_multicast_addr) {
+ dev_dbg(priv->adapter->dev,
+ "info: Set multicast list=%d\n",
+ mcast_list->num_multicast_addr);
+ /* Set multicast addresses to firmware */
+ if (old_pkt_filter == priv->curr_pkt_filter) {
+ /* Send request to firmware */
+ ret = mwifiex_send_cmd_async(priv,
+ HostCmd_CMD_MAC_MULTICAST_ADR,
+ HostCmd_ACT_GEN_SET, 0,
+ mcast_list);
+ } else {
+ /* Send request to firmware */
+ ret = mwifiex_send_cmd_async(priv,
+ HostCmd_CMD_MAC_MULTICAST_ADR,
+ HostCmd_ACT_GEN_SET, 0,
+ mcast_list);
+ }
+ }
+ }
+ }
+ dev_dbg(priv->adapter->dev,
+ "info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n",
+ old_pkt_filter, priv->curr_pkt_filter);
+ if (old_pkt_filter != priv->curr_pkt_filter) {
+ ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET,
+ 0, &priv->curr_pkt_filter);
+ }
+
+ return ret;
+}
+
+/*
+ * In Ad-Hoc mode, the IBSS is created if not found in scan list.
+ * In both Ad-Hoc and infra mode, an deauthentication is performed
+ * first.
+ */
+int mwifiex_bss_start(struct mwifiex_private *priv,
+ struct mwifiex_ssid_bssid *ssid_bssid)
+{
+ int ret;
+ struct mwifiex_adapter *adapter = priv->adapter;
+ s32 i = -1;
+
+ priv->scan_block = false;
+ if (!ssid_bssid)
+ return -1;
+
+ if (priv->bss_mode == NL80211_IFTYPE_STATION) {
+ /* Infra mode */
+ ret = mwifiex_deauthenticate(priv, NULL);
+ if (ret)
+ return ret;
+
+ /* Search for the requested SSID in the scan table */
+ if (ssid_bssid->ssid.ssid_len)
+ i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid,
+ NULL, NL80211_IFTYPE_STATION);
+ else
+ i = mwifiex_find_bssid_in_list(priv,
+ (u8 *) &ssid_bssid->bssid,
+ NL80211_IFTYPE_STATION);
+ if (i < 0)
+ return -1;
+
+ dev_dbg(adapter->dev,
+ "info: SSID found in scan list ... associating...\n");
+
+ /* Clear any past association response stored for
+ * application retrieval */
+ priv->assoc_rsp_size = 0;
+ ret = mwifiex_associate(priv, &adapter->scan_table[i]);
+ if (ret)
+ return ret;
+ } else {
+ /* Adhoc mode */
+ /* If the requested SSID matches current SSID, return */
+ if (ssid_bssid->ssid.ssid_len &&
+ (!mwifiex_ssid_cmp
+ (&priv->curr_bss_params.bss_descriptor.ssid,
+ &ssid_bssid->ssid)))
+ return 0;
+
+ /* Exit Adhoc mode first */
+ dev_dbg(adapter->dev, "info: Sending Adhoc Stop\n");
+ ret = mwifiex_deauthenticate(priv, NULL);
+ if (ret)
+ return ret;
+
+ priv->adhoc_is_link_sensed = false;
+
+ /* Search for the requested network in the scan table */
+ if (ssid_bssid->ssid.ssid_len)
+ i = mwifiex_find_ssid_in_list(priv,
+ &ssid_bssid->ssid, NULL,
+ NL80211_IFTYPE_ADHOC);
+ else
+ i = mwifiex_find_bssid_in_list(priv,
+ (u8 *)&ssid_bssid->bssid,
+ NL80211_IFTYPE_ADHOC);
+
+ if (i >= 0) {
+ dev_dbg(adapter->dev, "info: network found in scan"
+ " list. Joining...\n");
+ ret = mwifiex_adhoc_join(priv, &adapter->scan_table[i]);
+ if (ret)
+ return ret;
+ } else {
+ dev_dbg(adapter->dev, "info: Network not found in "
+ "the list, creating adhoc with ssid = %s\n",
+ ssid_bssid->ssid.ssid);
+ ret = mwifiex_adhoc_start(priv, &ssid_bssid->ssid);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * IOCTL request handler to set host sleep configuration.
+ *
+ * This function prepares the correct firmware command and
+ * issues it.
+ */
+int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,
+ int cmd_type, struct mwifiex_ds_hs_cfg *hs_cfg)
+
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ int status = 0;
+ u32 prev_cond = 0;
+
+ if (!hs_cfg)
+ return -ENOMEM;
+
+ switch (action) {
+ case HostCmd_ACT_GEN_SET:
+ if (adapter->pps_uapsd_mode) {
+ dev_dbg(adapter->dev, "info: Host Sleep IOCTL"
+ " is blocked in UAPSD/PPS mode\n");
+ status = -1;
+ break;
+ }
+ if (hs_cfg->is_invoke_hostcmd) {
+ if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL) {
+ if (!adapter->is_hs_configured)
+ /* Already cancelled */
+ break;
+ /* Save previous condition */
+ prev_cond = le32_to_cpu(adapter->hs_cfg
+ .conditions);
+ adapter->hs_cfg.conditions =
+ cpu_to_le32(hs_cfg->conditions);
+ } else if (hs_cfg->conditions) {
+ adapter->hs_cfg.conditions =
+ cpu_to_le32(hs_cfg->conditions);
+ adapter->hs_cfg.gpio = (u8)hs_cfg->gpio;
+ if (hs_cfg->gap)
+ adapter->hs_cfg.gap = (u8)hs_cfg->gap;
+ } else if (adapter->hs_cfg.conditions ==
+ cpu_to_le32(
+ HOST_SLEEP_CFG_CANCEL)) {
+ /* Return failure if no parameters for HS
+ enable */
+ status = -1;
+ break;
+ }
+ if (cmd_type == MWIFIEX_SYNC_CMD)
+ status = mwifiex_send_cmd_sync(priv,
+ HostCmd_CMD_802_11_HS_CFG_ENH,
+ HostCmd_ACT_GEN_SET, 0,
+ &adapter->hs_cfg);
+ else
+ status = mwifiex_send_cmd_async(priv,
+ HostCmd_CMD_802_11_HS_CFG_ENH,
+ HostCmd_ACT_GEN_SET, 0,
+ &adapter->hs_cfg);
+ if (hs_cfg->conditions == HOST_SLEEP_CFG_CANCEL)
+ /* Restore previous condition */
+ adapter->hs_cfg.conditions =
+ cpu_to_le32(prev_cond);
+ } else {
+ adapter->hs_cfg.conditions =
+ cpu_to_le32(hs_cfg->conditions);
+ adapter->hs_cfg.gpio = (u8)hs_cfg->gpio;
+ adapter->hs_cfg.gap = (u8)hs_cfg->gap;
+ }
+ break;
+ case HostCmd_ACT_GEN_GET:
+ hs_cfg->conditions = le32_to_cpu(adapter->hs_cfg.conditions);
+ hs_cfg->gpio = adapter->hs_cfg.gpio;
+ hs_cfg->gap = adapter->hs_cfg.gap;
+ break;
+ default:
+ status = -1;
+ break;
+ }
+
+ return status;
+}
+
+/*
+ * Sends IOCTL request to cancel the existing Host Sleep configuration.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type)
+{
+ struct mwifiex_ds_hs_cfg hscfg;
+
+ hscfg.conditions = HOST_SLEEP_CFG_CANCEL;
+ hscfg.is_invoke_hostcmd = true;
+
+ return mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
+ cmd_type, &hscfg);
+}
+EXPORT_SYMBOL_GPL(mwifiex_cancel_hs);
+
+/*
+ * Sends IOCTL request to cancel the existing Host Sleep configuration.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int mwifiex_enable_hs(struct mwifiex_adapter *adapter)
+{
+ struct mwifiex_ds_hs_cfg hscfg;
+
+ if (adapter->hs_activated) {
+ dev_dbg(adapter->dev, "cmd: HS Already actived\n");
+ return true;
+ }
+
+ adapter->hs_activate_wait_q_woken = false;
+
+ memset(&hscfg, 0, sizeof(struct mwifiex_hs_config_param));
+ hscfg.is_invoke_hostcmd = true;
+
+ if (mwifiex_set_hs_params(mwifiex_get_priv(adapter,
+ MWIFIEX_BSS_ROLE_STA),
+ HostCmd_ACT_GEN_SET, MWIFIEX_SYNC_CMD,
+ &hscfg)) {
+ dev_err(adapter->dev, "IOCTL request HS enable failed\n");
+ return false;
+ }
+
+ wait_event_interruptible(adapter->hs_activate_wait_q,
+ adapter->hs_activate_wait_q_woken);
+
+ return true;
+}
+EXPORT_SYMBOL_GPL(mwifiex_enable_hs);
+
+/*
+ * IOCTL request handler to get BSS information.
+ *
+ * This function collates the information from different driver structures
+ * to send to the user.
+ */
+int mwifiex_get_bss_info(struct mwifiex_private *priv,
+ struct mwifiex_bss_info *info)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_bssdescriptor *bss_desc;
+ s32 tbl_idx;
+
+ if (!info)
+ return -1;
+
+ bss_desc = &priv->curr_bss_params.bss_descriptor;
+
+ info->bss_mode = priv->bss_mode;
+
+ memcpy(&info->ssid, &bss_desc->ssid,
+ sizeof(struct mwifiex_802_11_ssid));
+
+ memcpy(&info->bssid, &bss_desc->mac_address, ETH_ALEN);
+
+ info->bss_chan = bss_desc->channel;
+
+ info->region_code = adapter->region_code;
+
+ /* Scan table index if connected */
+ info->scan_table_idx = 0;
+ if (priv->media_connected) {
+ tbl_idx =
+ mwifiex_find_ssid_in_list(priv, &bss_desc->ssid,
+ bss_desc->mac_address,
+ priv->bss_mode);
+ if (tbl_idx >= 0)
+ info->scan_table_idx = tbl_idx;
+ }
+
+ info->media_connected = priv->media_connected;
+
+ info->max_power_level = priv->max_tx_power_level;
+ info->min_power_level = priv->min_tx_power_level;
+
+ info->adhoc_state = priv->adhoc_state;
+
+ info->bcn_nf_last = priv->bcn_nf_last;
+
+ if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED)
+ info->wep_status = true;
+ else
+ info->wep_status = false;
+
+ info->is_hs_configured = adapter->is_hs_configured;
+ info->is_deep_sleep = adapter->is_deep_sleep;
+
+ return 0;
+}
+
+/*
+ * The function sets band configurations.
+ *
+ * it performs extra checks to make sure the Ad-Hoc
+ * band and channel are compatible. Otherwise it returns an error.
+ *
+ */
+int mwifiex_set_radio_band_cfg(struct mwifiex_private *priv,
+ struct mwifiex_ds_band_cfg *radio_cfg)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ u8 infra_band, adhoc_band;
+ u32 adhoc_channel;
+
+ infra_band = (u8) radio_cfg->config_bands;
+ adhoc_band = (u8) radio_cfg->adhoc_start_band;
+ adhoc_channel = radio_cfg->adhoc_channel;
+
+ /* SET Infra band */
+ if ((infra_band | adapter->fw_bands) & ~adapter->fw_bands)
+ return -1;
+
+ adapter->config_bands = infra_band;
+
+ /* SET Ad-hoc Band */
+ if ((adhoc_band | adapter->fw_bands) & ~adapter->fw_bands)
+ return -1;
+
+ if (adhoc_band)
+ adapter->adhoc_start_band = adhoc_band;
+ adapter->chan_offset = (u8) radio_cfg->sec_chan_offset;
+ /*
+ * If no adhoc_channel is supplied verify if the existing adhoc
+ * channel compiles with new adhoc_band
+ */
+ if (!adhoc_channel) {
+ if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211
+ (priv, adapter->adhoc_start_band,
+ priv->adhoc_channel)) {
+ /* Pass back the default channel */
+ radio_cfg->adhoc_channel = DEFAULT_AD_HOC_CHANNEL;
+ if ((adapter->adhoc_start_band & BAND_A)
+ || (adapter->adhoc_start_band & BAND_AN))
+ radio_cfg->adhoc_channel =
+ DEFAULT_AD_HOC_CHANNEL_A;
+ }
+ } else { /* Retrurn error if adhoc_band and
+ adhoc_channel combination is invalid */
+ if (!mwifiex_get_cfp_by_band_and_channel_from_cfg80211
+ (priv, adapter->adhoc_start_band, (u16) adhoc_channel))
+ return -1;
+ priv->adhoc_channel = (u8) adhoc_channel;
+ }
+ if ((adhoc_band & BAND_GN) || (adhoc_band & BAND_AN))
+ adapter->adhoc_11n_enabled = true;
+ else
+ adapter->adhoc_11n_enabled = false;
+
+ return 0;
+}
+
+/*
+ * IOCTL request handler to set/get active channel.
+ *
+ * This function performs validity checking on channel/frequency
+ * compatibility and returns failure if not valid.
+ */
+int mwifiex_bss_set_channel(struct mwifiex_private *priv,
+ struct mwifiex_chan_freq_power *chan)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_chan_freq_power *cfp = NULL;
+
+ if (!chan)
+ return -1;
+
+ if (!chan->channel && !chan->freq)
+ return -1;
+ if (adapter->adhoc_start_band & BAND_AN)
+ adapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN;
+ else if (adapter->adhoc_start_band & BAND_A)
+ adapter->adhoc_start_band = BAND_G | BAND_B;
+ if (chan->channel) {
+ if (chan->channel <= MAX_CHANNEL_BAND_BG)
+ cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211
+ (priv, 0, (u16) chan->channel);
+ if (!cfp) {
+ cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211
+ (priv, BAND_A, (u16) chan->channel);
+ if (cfp) {
+ if (adapter->adhoc_11n_enabled)
+ adapter->adhoc_start_band = BAND_A
+ | BAND_AN;
+ else
+ adapter->adhoc_start_band = BAND_A;
+ }
+ }
+ } else {
+ if (chan->freq <= MAX_FREQUENCY_BAND_BG)
+ cfp = mwifiex_get_cfp_by_band_and_freq_from_cfg80211(
+ priv, 0, chan->freq);
+ if (!cfp) {
+ cfp = mwifiex_get_cfp_by_band_and_freq_from_cfg80211
+ (priv, BAND_A, chan->freq);
+ if (cfp) {
+ if (adapter->adhoc_11n_enabled)
+ adapter->adhoc_start_band = BAND_A
+ | BAND_AN;
+ else
+ adapter->adhoc_start_band = BAND_A;
+ }
+ }
+ }
+ if (!cfp || !cfp->channel) {
+ dev_err(adapter->dev, "invalid channel/freq\n");
+ return -1;
+ }
+ priv->adhoc_channel = (u8) cfp->channel;
+ chan->channel = cfp->channel;
+ chan->freq = cfp->freq;
+
+ return 0;
+}
+
+/*
+ * IOCTL request handler to set/get Ad-Hoc channel.
+ *
+ * This function prepares the correct firmware command and
+ * issues it to set or get the ad-hoc channel.
+ */
+static int mwifiex_bss_ioctl_ibss_channel(struct mwifiex_private *priv,
+ u16 action, u16 *channel)
+{
+ if (action == HostCmd_ACT_GEN_GET) {
+ if (!priv->media_connected) {
+ *channel = priv->adhoc_channel;
+ return 0;
+ }
+ } else {
+ priv->adhoc_channel = (u8) *channel;
+ }
+
+ return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_RF_CHANNEL,
+ action, 0, channel);
+}
+
+/*
+ * IOCTL request handler to find a particular BSS.
+ *
+ * The BSS can be searched with either a BSSID or a SSID. If none of
+ * these are provided, just the best BSS (best RSSI) is returned.
+ */
+int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *priv,
+ struct mwifiex_ssid_bssid *ssid_bssid)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_bssdescriptor *bss_desc;
+ u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+ u8 mac[ETH_ALEN];
+ int i = 0;
+
+ if (memcmp(ssid_bssid->bssid, zero_mac, sizeof(zero_mac))) {
+ i = mwifiex_find_bssid_in_list(priv,
+ (u8 *) ssid_bssid->bssid,
+ priv->bss_mode);
+ if (i < 0) {
+ memcpy(mac, ssid_bssid->bssid, sizeof(mac));
+ dev_err(adapter->dev, "cannot find bssid %pM\n", mac);
+ return -1;
+ }
+ bss_desc = &adapter->scan_table[i];
+ memcpy(&ssid_bssid->ssid, &bss_desc->ssid,
+ sizeof(struct mwifiex_802_11_ssid));
+ } else if (ssid_bssid->ssid.ssid_len) {
+ i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, NULL,
+ priv->bss_mode);
+ if (i < 0) {
+ dev_err(adapter->dev, "cannot find ssid %s\n",
+ ssid_bssid->ssid.ssid);
+ return -1;
+ }
+ bss_desc = &adapter->scan_table[i];
+ memcpy(ssid_bssid->bssid, bss_desc->mac_address, ETH_ALEN);
+ } else {
+ return mwifiex_find_best_network(priv, ssid_bssid);
+ }
+
+ return 0;
+}
+
+/*
+ * IOCTL request handler to change Ad-Hoc channel.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ *
+ * The function follows the following steps to perform the change -
+ * - Get current IBSS information
+ * - Get current channel
+ * - If no change is required, return
+ * - If not connected, change channel and return
+ * - If connected,
+ * - Disconnect
+ * - Change channel
+ * - Perform specific SSID scan with same SSID
+ * - Start/Join the IBSS
+ */
+int
+mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel)
+{
+ int ret;
+ struct mwifiex_bss_info bss_info;
+ struct mwifiex_ssid_bssid ssid_bssid;
+ u16 curr_chan = 0;
+
+ memset(&bss_info, 0, sizeof(bss_info));
+
+ /* Get BSS information */
+ if (mwifiex_get_bss_info(priv, &bss_info))
+ return -1;
+
+ /* Get current channel */
+ ret = mwifiex_bss_ioctl_ibss_channel(priv, HostCmd_ACT_GEN_GET,
+ &curr_chan);
+
+ if (curr_chan == channel) {
+ ret = 0;
+ goto done;
+ }
+ dev_dbg(priv->adapter->dev, "cmd: updating channel from %d to %d\n",
+ curr_chan, channel);
+
+ if (!bss_info.media_connected) {
+ ret = 0;
+ goto done;
+ }
+
+ /* Do disonnect */
+ memset(&ssid_bssid, 0, ETH_ALEN);
+ ret = mwifiex_deauthenticate(priv, ssid_bssid.bssid);
+
+ ret = mwifiex_bss_ioctl_ibss_channel(priv, HostCmd_ACT_GEN_SET,
+ (u16 *) &channel);
+
+ /* Do specific SSID scanning */
+ if (mwifiex_request_scan(priv, &bss_info.ssid)) {
+ ret = -1;
+ goto done;
+ }
+ /* Start/Join Adhoc network */
+ memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid));
+ memcpy(&ssid_bssid.ssid, &bss_info.ssid,
+ sizeof(struct mwifiex_802_11_ssid));
+
+ ret = mwifiex_bss_start(priv, &ssid_bssid);
+done:
+ return ret;
+}
+
+/*
+ * IOCTL request handler to get rate.
+ *
+ * This function prepares the correct firmware command and
+ * issues it to get the current rate if it is connected,
+ * otherwise, the function returns the lowest supported rate
+ * for the band.
+ */
+static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv,
+ struct mwifiex_rate_cfg *rate_cfg)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+
+ rate_cfg->is_rate_auto = priv->is_data_rate_auto;
+ if (!priv->media_connected) {
+ switch (adapter->config_bands) {
+ case BAND_B:
+ /* Return the lowest supported rate for B band */
+ rate_cfg->rate = supported_rates_b[0] & 0x7f;
+ break;
+ case BAND_G:
+ case BAND_G | BAND_GN:
+ /* Return the lowest supported rate for G band */
+ rate_cfg->rate = supported_rates_g[0] & 0x7f;
+ break;
+ case BAND_B | BAND_G:
+ case BAND_A | BAND_B | BAND_G:
+ case BAND_A | BAND_B:
+ case BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN:
+ case BAND_B | BAND_G | BAND_GN:
+ /* Return the lowest supported rate for BG band */
+ rate_cfg->rate = supported_rates_bg[0] & 0x7f;
+ break;
+ case BAND_A:
+ case BAND_A | BAND_G:
+ case BAND_A | BAND_G | BAND_AN | BAND_GN:
+ case BAND_A | BAND_AN:
+ /* Return the lowest supported rate for A band */
+ rate_cfg->rate = supported_rates_a[0] & 0x7f;
+ break;
+ case BAND_GN:
+ /* Return the lowest supported rate for N band */
+ rate_cfg->rate = supported_rates_n[0] & 0x7f;
+ break;
+ default:
+ dev_warn(adapter->dev, "invalid band %#x\n",
+ adapter->config_bands);
+ break;
+ }
+ } else {
+ return mwifiex_send_cmd_sync(priv,
+ HostCmd_CMD_802_11_TX_RATE_QUERY,
+ HostCmd_ACT_GEN_GET, 0, NULL);
+ }
+
+ return 0;
+}
+
+/*
+ * IOCTL request handler to set rate.
+ *
+ * This function prepares the correct firmware command and
+ * issues it to set the current rate.
+ *
+ * The function also performs validation checking on the supplied value.
+ */
+static int mwifiex_rate_ioctl_set_rate_value(struct mwifiex_private *priv,
+ struct mwifiex_rate_cfg *rate_cfg)
+{
+ u8 rates[MWIFIEX_SUPPORTED_RATES];
+ u8 *rate;
+ int rate_index, ret;
+ u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
+ u32 i;
+ struct mwifiex_adapter *adapter = priv->adapter;
+
+ if (rate_cfg->is_rate_auto) {
+ memset(bitmap_rates, 0, sizeof(bitmap_rates));
+ /* Support all HR/DSSS rates */
+ bitmap_rates[0] = 0x000F;
+ /* Support all OFDM rates */
+ bitmap_rates[1] = 0x00FF;
+ /* Support all HT-MCSs rate */
+ for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates) - 3; i++)
+ bitmap_rates[i + 2] = 0xFFFF;
+ bitmap_rates[9] = 0x3FFF;
+ } else {
+ memset(rates, 0, sizeof(rates));
+ mwifiex_get_active_data_rates(priv, rates);
+ rate = rates;
+ for (i = 0; (rate[i] && i < MWIFIEX_SUPPORTED_RATES); i++) {
+ dev_dbg(adapter->dev, "info: rate=%#x wanted=%#x\n",
+ rate[i], rate_cfg->rate);
+ if ((rate[i] & 0x7f) == (rate_cfg->rate & 0x7f))
+ break;
+ }
+ if (!rate[i] || (i == MWIFIEX_SUPPORTED_RATES)) {
+ dev_err(adapter->dev, "fixed data rate %#x is out "
+ "of range\n", rate_cfg->rate);
+ return -1;
+ }
+ memset(bitmap_rates, 0, sizeof(bitmap_rates));
+
+ rate_index = mwifiex_data_rate_to_index(rate_cfg->rate);
+
+ /* Only allow b/g rates to be set */
+ if (rate_index >= MWIFIEX_RATE_INDEX_HRDSSS0 &&
+ rate_index <= MWIFIEX_RATE_INDEX_HRDSSS3) {
+ bitmap_rates[0] = 1 << rate_index;
+ } else {
+ rate_index -= 1; /* There is a 0x00 in the table */
+ if (rate_index >= MWIFIEX_RATE_INDEX_OFDM0 &&
+ rate_index <= MWIFIEX_RATE_INDEX_OFDM7)
+ bitmap_rates[1] = 1 << (rate_index -
+ MWIFIEX_RATE_INDEX_OFDM0);
+ }
+ }
+
+ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_TX_RATE_CFG,
+ HostCmd_ACT_GEN_SET, 0, bitmap_rates);
+
+ return ret;
+}
+
+/*
+ * IOCTL request handler to set/get rate.
+ *
+ * This function can be used to set/get either the rate value or the
+ * rate index.
+ */
+static int mwifiex_rate_ioctl_cfg(struct mwifiex_private *priv,
+ struct mwifiex_rate_cfg *rate_cfg)
+{
+ int status;
+
+ if (!rate_cfg)
+ return -1;
+
+ if (rate_cfg->action == HostCmd_ACT_GEN_GET)
+ status = mwifiex_rate_ioctl_get_rate_value(priv, rate_cfg);
+ else
+ status = mwifiex_rate_ioctl_set_rate_value(priv, rate_cfg);
+
+ return status;
+}
+
+/*
+ * Sends IOCTL request to get the data rate.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int mwifiex_drv_get_data_rate(struct mwifiex_private *priv,
+ struct mwifiex_rate_cfg *rate)
+{
+ int ret;
+
+ memset(rate, 0, sizeof(struct mwifiex_rate_cfg));
+ rate->action = HostCmd_ACT_GEN_GET;
+ ret = mwifiex_rate_ioctl_cfg(priv, rate);
+
+ if (!ret) {
+ if (rate && rate->is_rate_auto)
+ rate->rate = mwifiex_index_to_data_rate(priv->tx_rate,
+ priv->tx_htinfo);
+ else if (rate)
+ rate->rate = priv->data_rate;
+ } else {
+ ret = -1;
+ }
+
+ return ret;
+}
+
+/*
+ * IOCTL request handler to set tx power configuration.
+ *
+ * This function prepares the correct firmware command and
+ * issues it.
+ *
+ * For non-auto power mode, all the following power groups are set -
+ * - Modulation class HR/DSSS
+ * - Modulation class OFDM
+ * - Modulation class HTBW20
+ * - Modulation class HTBW40
+ */
+int mwifiex_set_tx_power(struct mwifiex_private *priv,
+ struct mwifiex_power_cfg *power_cfg)
+{
+ int ret;
+ struct host_cmd_ds_txpwr_cfg *txp_cfg;
+ struct mwifiex_types_power_group *pg_tlv;
+ struct mwifiex_power_group *pg;
+ u8 *buf;
+ u16 dbm = 0;
+
+ if (!power_cfg->is_power_auto) {
+ dbm = (u16) power_cfg->power_level;
+ if ((dbm < priv->min_tx_power_level) ||
+ (dbm > priv->max_tx_power_level)) {
+ dev_err(priv->adapter->dev, "txpower value %d dBm"
+ " is out of range (%d dBm-%d dBm)\n",
+ dbm, priv->min_tx_power_level,
+ priv->max_tx_power_level);
+ return -1;
+ }
+ }
+ buf = kzalloc(MWIFIEX_SIZE_OF_CMD_BUFFER, GFP_KERNEL);
+ if (!buf) {
+ dev_err(priv->adapter->dev, "%s: failed to alloc cmd buffer\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ txp_cfg = (struct host_cmd_ds_txpwr_cfg *) buf;
+ txp_cfg->action = cpu_to_le16(HostCmd_ACT_GEN_SET);
+ if (!power_cfg->is_power_auto) {
+ txp_cfg->mode = cpu_to_le32(1);
+ pg_tlv = (struct mwifiex_types_power_group *) (buf +
+ sizeof(struct host_cmd_ds_txpwr_cfg));
+ pg_tlv->type = TLV_TYPE_POWER_GROUP;
+ pg_tlv->length = 4 * sizeof(struct mwifiex_power_group);
+ pg = (struct mwifiex_power_group *) (buf +
+ sizeof(struct host_cmd_ds_txpwr_cfg) +
+ sizeof(struct mwifiex_types_power_group));
+ /* Power group for modulation class HR/DSSS */
+ pg->first_rate_code = 0x00;
+ pg->last_rate_code = 0x03;
+ pg->modulation_class = MOD_CLASS_HR_DSSS;
+ pg->power_step = 0;
+ pg->power_min = (s8) dbm;
+ pg->power_max = (s8) dbm;
+ pg++;
+ /* Power group for modulation class OFDM */
+ pg->first_rate_code = 0x00;
+ pg->last_rate_code = 0x07;
+ pg->modulation_class = MOD_CLASS_OFDM;
+ pg->power_step = 0;
+ pg->power_min = (s8) dbm;
+ pg->power_max = (s8) dbm;
+ pg++;
+ /* Power group for modulation class HTBW20 */
+ pg->first_rate_code = 0x00;
+ pg->last_rate_code = 0x20;
+ pg->modulation_class = MOD_CLASS_HT;
+ pg->power_step = 0;
+ pg->power_min = (s8) dbm;
+ pg->power_max = (s8) dbm;
+ pg->ht_bandwidth = HT_BW_20;
+ pg++;
+ /* Power group for modulation class HTBW40 */
+ pg->first_rate_code = 0x00;
+ pg->last_rate_code = 0x20;
+ pg->modulation_class = MOD_CLASS_HT;
+ pg->power_step = 0;
+ pg->power_min = (s8) dbm;
+ pg->power_max = (s8) dbm;
+ pg->ht_bandwidth = HT_BW_40;
+ }
+ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_TXPWR_CFG,
+ HostCmd_ACT_GEN_SET, 0, buf);
+
+ kfree(buf);
+ return ret;
+}
+
+/*
+ * IOCTL request handler to get power save mode.
+ *
+ * This function prepares the correct firmware command and
+ * issues it.
+ */
+int mwifiex_drv_set_power(struct mwifiex_private *priv, u32 *ps_mode)
+{
+ int ret;
+ struct mwifiex_adapter *adapter = priv->adapter;
+ u16 sub_cmd;
+
+ if (*ps_mode)
+ adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
+ else
+ adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;
+ sub_cmd = (*ps_mode) ? EN_AUTO_PS : DIS_AUTO_PS;
+ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_PS_MODE_ENH,
+ sub_cmd, BITMAP_STA_PS, NULL);
+ if ((!ret) && (sub_cmd == DIS_AUTO_PS))
+ ret = mwifiex_send_cmd_async(priv,
+ HostCmd_CMD_802_11_PS_MODE_ENH, GET_PS,
+ 0, NULL);
+
+ return ret;
+}
+
+/*
+ * IOCTL request handler to set/reset WPA IE.
+ *
+ * The supplied WPA IE is treated as a opaque buffer. Only the first field
+ * is checked to determine WPA version. If buffer length is zero, the existing
+ * WPA IE is reset.
+ */
+static int mwifiex_set_wpa_ie_helper(struct mwifiex_private *priv,
+ u8 *ie_data_ptr, u16 ie_len)
+{
+ if (ie_len) {
+ if (ie_len > sizeof(priv->wpa_ie)) {
+ dev_err(priv->adapter->dev,
+ "failed to copy WPA IE, too big\n");
+ return -1;
+ }
+ memcpy(priv->wpa_ie, ie_data_ptr, ie_len);
+ priv->wpa_ie_len = (u8) ie_len;
+ dev_dbg(priv->adapter->dev, "cmd: Set Wpa_ie_len=%d IE=%#x\n",
+ priv->wpa_ie_len, priv->wpa_ie[0]);
+
+ if (priv->wpa_ie[0] == WLAN_EID_WPA) {
+ priv->sec_info.wpa_enabled = true;
+ } else if (priv->wpa_ie[0] == WLAN_EID_RSN) {
+ priv->sec_info.wpa2_enabled = true;
+ } else {
+ priv->sec_info.wpa_enabled = false;
+ priv->sec_info.wpa2_enabled = false;
+ }
+ } else {
+ memset(priv->wpa_ie, 0, sizeof(priv->wpa_ie));
+ priv->wpa_ie_len = 0;
+ dev_dbg(priv->adapter->dev, "info: reset wpa_ie_len=%d IE=%#x\n",
+ priv->wpa_ie_len, priv->wpa_ie[0]);
+ priv->sec_info.wpa_enabled = false;
+ priv->sec_info.wpa2_enabled = false;
+ }
+
+ return 0;
+}
+
+/*
+ * IOCTL request handler to set/reset WAPI IE.
+ *
+ * The supplied WAPI IE is treated as a opaque buffer. Only the first field
+ * is checked to internally enable WAPI. If buffer length is zero, the existing
+ * WAPI IE is reset.
+ */
+static int mwifiex_set_wapi_ie(struct mwifiex_private *priv,
+ u8 *ie_data_ptr, u16 ie_len)
+{
+ if (ie_len) {
+ if (ie_len > sizeof(priv->wapi_ie)) {
+ dev_dbg(priv->adapter->dev,
+ "info: failed to copy WAPI IE, too big\n");
+ return -1;
+ }
+ memcpy(priv->wapi_ie, ie_data_ptr, ie_len);
+ priv->wapi_ie_len = ie_len;
+ dev_dbg(priv->adapter->dev, "cmd: Set wapi_ie_len=%d IE=%#x\n",
+ priv->wapi_ie_len, priv->wapi_ie[0]);
+
+ if (priv->wapi_ie[0] == WLAN_EID_BSS_AC_ACCESS_DELAY)
+ priv->sec_info.wapi_enabled = true;
+ } else {
+ memset(priv->wapi_ie, 0, sizeof(priv->wapi_ie));
+ priv->wapi_ie_len = ie_len;
+ dev_dbg(priv->adapter->dev,
+ "info: Reset wapi_ie_len=%d IE=%#x\n",
+ priv->wapi_ie_len, priv->wapi_ie[0]);
+ priv->sec_info.wapi_enabled = false;
+ }
+ return 0;
+}
+
+/*
+ * IOCTL request handler to set WAPI key.
+ *
+ * This function prepares the correct firmware command and
+ * issues it.
+ */
+static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_private *priv,
+ struct mwifiex_ds_encrypt_key *encrypt_key)
+{
+
+ return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
+ encrypt_key);
+}
+
+/*
+ * IOCTL request handler to set WEP network key.
+ *
+ * This function prepares the correct firmware command and
+ * issues it, after validation checks.
+ */
+static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
+ struct mwifiex_ds_encrypt_key *encrypt_key)
+{
+ int ret;
+ struct mwifiex_wep_key *wep_key;
+ int index;
+
+ if (priv->wep_key_curr_index >= NUM_WEP_KEYS)
+ priv->wep_key_curr_index = 0;
+ wep_key = &priv->wep_key[priv->wep_key_curr_index];
+ index = encrypt_key->key_index;
+ if (encrypt_key->key_disable) {
+ priv->sec_info.wep_status = MWIFIEX_802_11_WEP_DISABLED;
+ } else if (!encrypt_key->key_len) {
+ /* Copy the required key as the current key */
+ wep_key = &priv->wep_key[index];
+ if (!wep_key->key_length) {
+ dev_err(priv->adapter->dev,
+ "key not set, so cannot enable it\n");
+ return -1;
+ }
+ priv->wep_key_curr_index = (u16) index;
+ priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED;
+ } else {
+ wep_key = &priv->wep_key[index];
+ memset(wep_key, 0, sizeof(struct mwifiex_wep_key));
+ /* Copy the key in the driver */
+ memcpy(wep_key->key_material,
+ encrypt_key->key_material,
+ encrypt_key->key_len);
+ wep_key->key_index = index;
+ wep_key->key_length = encrypt_key->key_len;
+ priv->sec_info.wep_status = MWIFIEX_802_11_WEP_ENABLED;
+ }
+ if (wep_key->key_length) {
+ /* Send request to firmware */
+ ret = mwifiex_send_cmd_async(priv,
+ HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET, 0, NULL);
+ if (ret)
+ return ret;
+ }
+ if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED)
+ priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
+ else
+ priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
+
+ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET, 0,
+ &priv->curr_pkt_filter);
+
+ return ret;
+}
+
+/*
+ * IOCTL request handler to set WPA key.
+ *
+ * This function prepares the correct firmware command and
+ * issues it, after validation checks.
+ *
+ * Current driver only supports key length of up to 32 bytes.
+ *
+ * This function can also be used to disable a currently set key.
+ */
+static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv,
+ struct mwifiex_ds_encrypt_key *encrypt_key)
+{
+ int ret;
+ u8 remove_key = false;
+ struct host_cmd_ds_802_11_key_material *ibss_key;
+
+ /* Current driver only supports key length of up to 32 bytes */
+ if (encrypt_key->key_len > WLAN_MAX_KEY_LEN) {
+ dev_err(priv->adapter->dev, "key length too long\n");
+ return -1;
+ }
+
+ if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
+ /*
+ * IBSS/WPA-None uses only one key (Group) for both receiving
+ * and sending unicast and multicast packets.
+ */
+ /* Send the key as PTK to firmware */
+ encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST;
+ ret = mwifiex_send_cmd_async(priv,
+ HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
+ encrypt_key);
+ if (ret)
+ return ret;
+
+ ibss_key = &priv->aes_key;
+ memset(ibss_key, 0,
+ sizeof(struct host_cmd_ds_802_11_key_material));
+ /* Copy the key in the driver */
+ memcpy(ibss_key->key_param_set.key, encrypt_key->key_material,
+ encrypt_key->key_len);
+ memcpy(&ibss_key->key_param_set.key_len, &encrypt_key->key_len,
+ sizeof(ibss_key->key_param_set.key_len));
+ ibss_key->key_param_set.key_type_id
+ = cpu_to_le16(KEY_TYPE_ID_TKIP);
+ ibss_key->key_param_set.key_info = cpu_to_le16(KEY_ENABLED);
+
+ /* Send the key as GTK to firmware */
+ encrypt_key->key_index = ~MWIFIEX_KEY_INDEX_UNICAST;
+ }
+
+ if (!encrypt_key->key_index)
+ encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST;
+
+ if (remove_key)
+ ret = mwifiex_send_cmd_sync(priv,
+ HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET, !(KEY_INFO_ENABLED),
+ encrypt_key);
+ else
+ ret = mwifiex_send_cmd_sync(priv,
+ HostCmd_CMD_802_11_KEY_MATERIAL,
+ HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,
+ encrypt_key);
+
+ return ret;
+}
+
+/*
+ * IOCTL request handler to set/get network keys.
+ *
+ * This is a generic key handling function which supports WEP, WPA
+ * and WAPI.
+ */
+static int
+mwifiex_sec_ioctl_encrypt_key(struct mwifiex_private *priv,
+ struct mwifiex_ds_encrypt_key *encrypt_key)
+{
+ int status;
+
+ if (encrypt_key->is_wapi_key)
+ status = mwifiex_sec_ioctl_set_wapi_key(priv, encrypt_key);
+ else if (encrypt_key->key_len > WLAN_KEY_LEN_WEP104)
+ status = mwifiex_sec_ioctl_set_wpa_key(priv, encrypt_key);
+ else
+ status = mwifiex_sec_ioctl_set_wep_key(priv, encrypt_key);
+ return status;
+}
+
+/*
+ * This function returns the driver version.
+ */
+int
+mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version,
+ int max_len)
+{
+ union {
+ u32 l;
+ u8 c[4];
+ } ver;
+ char fw_ver[32];
+
+ ver.l = adapter->fw_release_number;
+ sprintf(fw_ver, "%u.%u.%u.p%u", ver.c[2], ver.c[1], ver.c[0], ver.c[3]);
+
+ snprintf(version, max_len, driver_version, fw_ver);
+
+ dev_dbg(adapter->dev, "info: MWIFIEX VERSION: %s\n", version);
+
+ return 0;
+}
+
+/*
+ * Sends IOCTL request to get signal information.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int mwifiex_get_signal_info(struct mwifiex_private *priv,
+ struct mwifiex_ds_get_signal *signal)
+{
+ int status;
+
+ signal->selector = ALL_RSSI_INFO_MASK;
+
+ /* Signal info can be obtained only if connected */
+ if (!priv->media_connected) {
+ dev_dbg(priv->adapter->dev,
+ "info: Can not get signal in disconnected state\n");
+ return -1;
+ }
+
+ status = mwifiex_send_cmd_sync(priv, HostCmd_CMD_RSSI_INFO,
+ HostCmd_ACT_GEN_GET, 0, signal);
+
+ if (!status) {
+ if (signal->selector & BCN_RSSI_AVG_MASK)
+ priv->w_stats.qual.level = signal->bcn_rssi_avg;
+ if (signal->selector & BCN_NF_AVG_MASK)
+ priv->w_stats.qual.noise = signal->bcn_nf_avg;
+ }
+
+ return status;
+}
+
+/*
+ * Sends IOCTL request to set encoding parameters.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key,
+ int key_len, u8 key_index, int disable)
+{
+ struct mwifiex_ds_encrypt_key encrypt_key;
+
+ memset(&encrypt_key, 0, sizeof(struct mwifiex_ds_encrypt_key));
+ encrypt_key.key_len = key_len;
+ if (!disable) {
+ encrypt_key.key_index = key_index;
+ if (key_len)
+ memcpy(encrypt_key.key_material, key, key_len);
+ } else {
+ encrypt_key.key_disable = true;
+ }
+
+ return mwifiex_sec_ioctl_encrypt_key(priv, &encrypt_key);
+}
+
+/*
+ * Sends IOCTL request to get extended version.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int
+mwifiex_get_ver_ext(struct mwifiex_private *priv)
+{
+ struct mwifiex_ver_ext ver_ext;
+
+ memset(&ver_ext, 0, sizeof(struct host_cmd_ds_version_ext));
+ if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_VERSION_EXT,
+ HostCmd_ACT_GEN_GET, 0, &ver_ext))
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Sends IOCTL request to get statistics information.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int
+mwifiex_get_stats_info(struct mwifiex_private *priv,
+ struct mwifiex_ds_get_stats *log)
+{
+ int ret;
+
+ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_GET_LOG,
+ HostCmd_ACT_GEN_GET, 0, log);
+
+ if (!ret) {
+ priv->w_stats.discard.fragment = log->fcs_error;
+ priv->w_stats.discard.retries = log->retry;
+ priv->w_stats.discard.misc = log->ack_failure;
+ }
+
+ return ret;
+}
+
+/*
+ * IOCTL request handler to read/write register.
+ *
+ * This function prepares the correct firmware command and
+ * issues it.
+ *
+ * Access to the following registers are supported -
+ * - MAC
+ * - BBP
+ * - RF
+ * - PMIC
+ * - CAU
+ */
+static int mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private *priv,
+ struct mwifiex_ds_reg_rw *reg_rw,
+ u16 action)
+{
+ u16 cmd_no;
+
+ switch (le32_to_cpu(reg_rw->type)) {
+ case MWIFIEX_REG_MAC:
+ cmd_no = HostCmd_CMD_MAC_REG_ACCESS;
+ break;
+ case MWIFIEX_REG_BBP:
+ cmd_no = HostCmd_CMD_BBP_REG_ACCESS;
+ break;
+ case MWIFIEX_REG_RF:
+ cmd_no = HostCmd_CMD_RF_REG_ACCESS;
+ break;
+ case MWIFIEX_REG_PMIC:
+ cmd_no = HostCmd_CMD_PMIC_REG_ACCESS;
+ break;
+ case MWIFIEX_REG_CAU:
+ cmd_no = HostCmd_CMD_CAU_REG_ACCESS;
+ break;
+ default:
+ return -1;
+ }
+
+ return mwifiex_send_cmd_sync(priv, cmd_no, action, 0, reg_rw);
+
+}
+
+/*
+ * Sends IOCTL request to write to a register.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int
+mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type,
+ u32 reg_offset, u32 reg_value)
+{
+ struct mwifiex_ds_reg_rw reg_rw;
+
+ reg_rw.type = cpu_to_le32(reg_type);
+ reg_rw.offset = cpu_to_le32(reg_offset);
+ reg_rw.value = cpu_to_le32(reg_value);
+
+ return mwifiex_reg_mem_ioctl_reg_rw(priv, &reg_rw, HostCmd_ACT_GEN_SET);
+}
+
+/*
+ * Sends IOCTL request to read from a register.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int
+mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type,
+ u32 reg_offset, u32 *value)
+{
+ int ret;
+ struct mwifiex_ds_reg_rw reg_rw;
+
+ reg_rw.type = cpu_to_le32(reg_type);
+ reg_rw.offset = cpu_to_le32(reg_offset);
+ ret = mwifiex_reg_mem_ioctl_reg_rw(priv, &reg_rw, HostCmd_ACT_GEN_GET);
+
+ if (ret)
+ goto done;
+
+ *value = le32_to_cpu(reg_rw.value);
+
+done:
+ return ret;
+}
+
+/*
+ * Sends IOCTL request to read from EEPROM.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int
+mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes,
+ u8 *value)
+{
+ int ret;
+ struct mwifiex_ds_read_eeprom rd_eeprom;
+
+ rd_eeprom.offset = cpu_to_le16((u16) offset);
+ rd_eeprom.byte_count = cpu_to_le16((u16) bytes);
+
+ /* Send request to firmware */
+ ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_EEPROM_ACCESS,
+ HostCmd_ACT_GEN_GET, 0, &rd_eeprom);
+
+ if (!ret)
+ memcpy(value, rd_eeprom.value, MAX_EEPROM_DATA);
+ return ret;
+}
+
+/*
+ * This function sets a generic IE. In addition to generic IE, it can
+ * also handle WPA, WPA2 and WAPI IEs.
+ */
+static int
+mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr,
+ u16 ie_len)
+{
+ int ret = 0;
+ struct ieee_types_vendor_header *pvendor_ie;
+ const u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 };
+ const u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 };
+
+ /* If the passed length is zero, reset the buffer */
+ if (!ie_len) {
+ priv->gen_ie_buf_len = 0;
+ priv->wps.session_enable = false;
+
+ return 0;
+ } else if (!ie_data_ptr) {
+ return -1;
+ }
+ pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr;
+ /* Test to see if it is a WPA IE, if not, then it is a gen IE */
+ if (((pvendor_ie->element_id == WLAN_EID_WPA)
+ && (!memcmp(pvendor_ie->oui, wpa_oui, sizeof(wpa_oui))))
+ || (pvendor_ie->element_id == WLAN_EID_RSN)) {
+
+ /* IE is a WPA/WPA2 IE so call set_wpa function */
+ ret = mwifiex_set_wpa_ie_helper(priv, ie_data_ptr, ie_len);
+ priv->wps.session_enable = false;
+
+ return ret;
+ } else if (pvendor_ie->element_id == WLAN_EID_BSS_AC_ACCESS_DELAY) {
+ /* IE is a WAPI IE so call set_wapi function */
+ ret = mwifiex_set_wapi_ie(priv, ie_data_ptr, ie_len);
+
+ return ret;
+ }
+ /*
+ * Verify that the passed length is not larger than the
+ * available space remaining in the buffer
+ */
+ if (ie_len < (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) {
+
+ /* Test to see if it is a WPS IE, if so, enable
+ * wps session flag
+ */
+ pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr;
+ if ((pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC)
+ && (!memcmp(pvendor_ie->oui, wps_oui,
+ sizeof(wps_oui)))) {
+ priv->wps.session_enable = true;
+ dev_dbg(priv->adapter->dev,
+ "info: WPS Session Enabled.\n");
+ }
+
+ /* Append the passed data to the end of the
+ genIeBuffer */
+ memcpy(priv->gen_ie_buf + priv->gen_ie_buf_len, ie_data_ptr,
+ ie_len);
+ /* Increment the stored buffer length by the
+ size passed */
+ priv->gen_ie_buf_len += ie_len;
+ } else {
+ /* Passed data does not fit in the remaining
+ buffer space */
+ ret = -1;
+ }
+
+ /* Return 0, or -1 for error case */
+ return ret;
+}
+
+/*
+ * IOCTL request handler to set/get generic IE.
+ *
+ * In addition to various generic IEs, this function can also be
+ * used to set the ARP filter.
+ */
+static int mwifiex_misc_ioctl_gen_ie(struct mwifiex_private *priv,
+ struct mwifiex_ds_misc_gen_ie *gen_ie,
+ u16 action)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+
+ switch (gen_ie->type) {
+ case MWIFIEX_IE_TYPE_GEN_IE:
+ if (action == HostCmd_ACT_GEN_GET) {
+ gen_ie->len = priv->wpa_ie_len;
+ memcpy(gen_ie->ie_data, priv->wpa_ie, gen_ie->len);
+ } else {
+ mwifiex_set_gen_ie_helper(priv, gen_ie->ie_data,
+ (u16) gen_ie->len);
+ }
+ break;
+ case MWIFIEX_IE_TYPE_ARP_FILTER:
+ memset(adapter->arp_filter, 0, sizeof(adapter->arp_filter));
+ if (gen_ie->len > ARP_FILTER_MAX_BUF_SIZE) {
+ adapter->arp_filter_size = 0;
+ dev_err(adapter->dev, "invalid ARP filter size\n");
+ return -1;
+ } else {
+ memcpy(adapter->arp_filter, gen_ie->ie_data,
+ gen_ie->len);
+ adapter->arp_filter_size = gen_ie->len;
+ }
+ break;
+ default:
+ dev_err(adapter->dev, "invalid IE type\n");
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Sends IOCTL request to set a generic IE.
+ *
+ * This function allocates the IOCTL request buffer, fills it
+ * with requisite parameters and calls the IOCTL handler.
+ */
+int
+mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len)
+{
+ struct mwifiex_ds_misc_gen_ie gen_ie;
+
+ if (ie_len > IW_CUSTOM_MAX)
+ return -EFAULT;
+
+ gen_ie.type = MWIFIEX_IE_TYPE_GEN_IE;
+ gen_ie.len = ie_len;
+ memcpy(gen_ie.ie_data, ie, ie_len);
+ if (mwifiex_misc_ioctl_gen_ie(priv, &gen_ie, HostCmd_ACT_GEN_SET))
+ return -EFAULT;
+
+ return 0;
+}
diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c
new file mode 100644
index 000000000000..1fdddece7479
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sta_rx.c
@@ -0,0 +1,200 @@
+/*
+ * Marvell Wireless LAN device driver: station RX data handling
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "11n_aggr.h"
+#include "11n_rxreorder.h"
+
+/*
+ * This function processes the received packet and forwards it
+ * to kernel/upper layer.
+ *
+ * This function parses through the received packet and determines
+ * if it is a debug packet or normal packet.
+ *
+ * For non-debug packets, the function chops off unnecessary leading
+ * header bytes, reconstructs the packet as an ethernet frame or
+ * 802.2/llc/snap frame as required, and sends it to kernel/upper layer.
+ *
+ * The completion callback is called after processing in complete.
+ */
+int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter,
+ struct sk_buff *skb)
+{
+ int ret;
+ struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
+ struct mwifiex_private *priv = adapter->priv[rx_info->bss_index];
+ struct rx_packet_hdr *rx_pkt_hdr;
+ struct rxpd *local_rx_pd;
+ int hdr_chop;
+ struct ethhdr *eth_hdr;
+ u8 rfc1042_eth_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+ local_rx_pd = (struct rxpd *) (skb->data);
+
+ rx_pkt_hdr = (struct rx_packet_hdr *) ((u8 *) local_rx_pd +
+ local_rx_pd->rx_pkt_offset);
+
+ if (!memcmp(&rx_pkt_hdr->rfc1042_hdr,
+ rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr))) {
+ /*
+ * Replace the 803 header and rfc1042 header (llc/snap) with an
+ * EthernetII header, keep the src/dst and snap_type
+ * (ethertype).
+ * The firmware only passes up SNAP frames converting
+ * all RX Data from 802.11 to 802.2/LLC/SNAP frames.
+ * To create the Ethernet II, just move the src, dst address
+ * right before the snap_type.
+ */
+ eth_hdr = (struct ethhdr *)
+ ((u8 *) &rx_pkt_hdr->eth803_hdr
+ + sizeof(rx_pkt_hdr->eth803_hdr) +
+ sizeof(rx_pkt_hdr->rfc1042_hdr)
+ - sizeof(rx_pkt_hdr->eth803_hdr.h_dest)
+ - sizeof(rx_pkt_hdr->eth803_hdr.h_source)
+ - sizeof(rx_pkt_hdr->rfc1042_hdr.snap_type));
+
+ memcpy(eth_hdr->h_source, rx_pkt_hdr->eth803_hdr.h_source,
+ sizeof(eth_hdr->h_source));
+ memcpy(eth_hdr->h_dest, rx_pkt_hdr->eth803_hdr.h_dest,
+ sizeof(eth_hdr->h_dest));
+
+ /* Chop off the rxpd + the excess memory from the 802.2/llc/snap
+ header that was removed. */
+ hdr_chop = (u8 *) eth_hdr - (u8 *) local_rx_pd;
+ } else {
+ /* Chop off the rxpd */
+ hdr_chop = (u8 *) &rx_pkt_hdr->eth803_hdr -
+ (u8 *) local_rx_pd;
+ }
+
+ /* Chop off the leading header bytes so the it points to the start of
+ either the reconstructed EthII frame or the 802.2/llc/snap frame */
+ skb_pull(skb, hdr_chop);
+
+ priv->rxpd_rate = local_rx_pd->rx_rate;
+
+ priv->rxpd_htinfo = local_rx_pd->ht_info;
+
+ ret = mwifiex_recv_packet(adapter, skb);
+ if (ret == -1)
+ dev_err(adapter->dev, "recv packet failed\n");
+
+ return ret;
+}
+
+/*
+ * This function processes the received buffer.
+ *
+ * The function looks into the RxPD and performs sanity tests on the
+ * received buffer to ensure its a valid packet, before processing it
+ * further. If the packet is determined to be aggregated, it is
+ * de-aggregated accordingly. Non-unicast packets are sent directly to
+ * the kernel/upper layers. Unicast packets are handed over to the
+ * Rx reordering routine if 11n is enabled.
+ *
+ * The completion callback is called after processing in complete.
+ */
+int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,
+ struct sk_buff *skb)
+{
+ int ret = 0;
+ struct rxpd *local_rx_pd;
+ struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
+ struct rx_packet_hdr *rx_pkt_hdr;
+ u8 ta[ETH_ALEN];
+ u16 rx_pkt_type;
+ struct mwifiex_private *priv = adapter->priv[rx_info->bss_index];
+
+ local_rx_pd = (struct rxpd *) (skb->data);
+ rx_pkt_type = local_rx_pd->rx_pkt_type;
+
+ rx_pkt_hdr = (struct rx_packet_hdr *) ((u8 *) local_rx_pd +
+ local_rx_pd->rx_pkt_offset);
+
+ if ((local_rx_pd->rx_pkt_offset + local_rx_pd->rx_pkt_length) >
+ (u16) skb->len) {
+ dev_err(adapter->dev, "wrong rx packet: len=%d,"
+ " rx_pkt_offset=%d, rx_pkt_length=%d\n", skb->len,
+ local_rx_pd->rx_pkt_offset, local_rx_pd->rx_pkt_length);
+ priv->stats.rx_dropped++;
+ dev_kfree_skb_any(skb);
+ return ret;
+ }
+
+ if (local_rx_pd->rx_pkt_type == PKT_TYPE_AMSDU) {
+ struct sk_buff_head list;
+ struct sk_buff *rx_skb;
+
+ __skb_queue_head_init(&list);
+
+ skb_pull(skb, local_rx_pd->rx_pkt_offset);
+ skb_trim(skb, local_rx_pd->rx_pkt_length);
+
+ ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
+ priv->wdev->iftype, 0, false);
+
+ while (!skb_queue_empty(&list)) {
+ rx_skb = __skb_dequeue(&list);
+ ret = mwifiex_recv_packet(adapter, rx_skb);
+ if (ret == -1)
+ dev_err(adapter->dev, "Rx of A-MSDU failed");
+ }
+ return 0;
+ }
+
+ /*
+ * If the packet is not an unicast packet then send the packet
+ * directly to os. Don't pass thru rx reordering
+ */
+ if (!IS_11N_ENABLED(priv) ||
+ memcmp(priv->curr_addr, rx_pkt_hdr->eth803_hdr.h_dest, ETH_ALEN)) {
+ mwifiex_process_rx_packet(adapter, skb);
+ return ret;
+ }
+
+ if (mwifiex_queuing_ra_based(priv)) {
+ memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN);
+ } else {
+ if (rx_pkt_type != PKT_TYPE_BAR)
+ priv->rx_seq[local_rx_pd->priority] =
+ local_rx_pd->seq_num;
+ memcpy(ta, priv->curr_bss_params.bss_descriptor.mac_address,
+ ETH_ALEN);
+ }
+
+ /* Reorder and send to OS */
+ ret = mwifiex_11n_rx_reorder_pkt(priv, local_rx_pd->seq_num,
+ local_rx_pd->priority, ta,
+ (u8) local_rx_pd->rx_pkt_type,
+ (void *) skb);
+
+ if (ret || (rx_pkt_type == PKT_TYPE_BAR)) {
+ if (priv && (ret == -1))
+ priv->stats.rx_dropped++;
+
+ dev_kfree_skb_any(skb);
+ }
+
+ return ret;
+}
diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c
new file mode 100644
index 000000000000..fa6221bc9104
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/sta_tx.c
@@ -0,0 +1,198 @@
+/*
+ * Marvell Wireless LAN device driver: station TX data handling
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+
+/*
+ * This function fills the TxPD for tx packets.
+ *
+ * The Tx buffer received by this function should already have the
+ * header space allocated for TxPD.
+ *
+ * This function inserts the TxPD in between interface header and actual
+ * data and adjusts the buffer pointers accordingly.
+ *
+ * The following TxPD fields are set by this function, as required -
+ * - BSS number
+ * - Tx packet length and offset
+ * - Priority
+ * - Packet delay
+ * - Priority specific Tx control
+ * - Flags
+ */
+void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
+ struct sk_buff *skb)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct txpd *local_tx_pd;
+ struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb);
+
+ if (!skb->len) {
+ dev_err(adapter->dev, "Tx: bad packet length: %d\n",
+ skb->len);
+ tx_info->status_code = -1;
+ return skb->data;
+ }
+
+ BUG_ON(skb_headroom(skb) < (sizeof(*local_tx_pd) + INTF_HEADER_LEN));
+ skb_push(skb, sizeof(*local_tx_pd));
+
+ local_tx_pd = (struct txpd *) skb->data;
+ memset(local_tx_pd, 0, sizeof(struct txpd));
+ local_tx_pd->bss_num = priv->bss_num;
+ local_tx_pd->bss_type = priv->bss_type;
+ local_tx_pd->tx_pkt_length = cpu_to_le16((u16) (skb->len -
+ sizeof(struct txpd)));
+
+ local_tx_pd->priority = (u8) skb->priority;
+ local_tx_pd->pkt_delay_2ms =
+ mwifiex_wmm_compute_drv_pkt_delay(priv, skb);
+
+ if (local_tx_pd->priority <
+ ARRAY_SIZE(priv->wmm.user_pri_pkt_tx_ctrl))
+ /*
+ * Set the priority specific tx_control field, setting of 0 will
+ * cause the default value to be used later in this function
+ */
+ local_tx_pd->tx_control =
+ cpu_to_le32(priv->wmm.user_pri_pkt_tx_ctrl[local_tx_pd->
+ priority]);
+
+ if (adapter->pps_uapsd_mode) {
+ if (mwifiex_check_last_packet_indication(priv)) {
+ adapter->tx_lock_flag = true;
+ local_tx_pd->flags =
+ MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET;
+ }
+ }
+
+ /* Offset of actual data */
+ local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd));
+
+ /* make space for INTF_HEADER_LEN */
+ skb_push(skb, INTF_HEADER_LEN);
+
+ if (!local_tx_pd->tx_control)
+ /* TxCtrl set by user or default */
+ local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl);
+
+ return skb->data;
+}
+
+/*
+ * This function tells firmware to send a NULL data packet.
+ *
+ * The function creates a NULL data packet with TxPD and sends to the
+ * firmware for transmission, with highest priority setting.
+ */
+int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct txpd *local_tx_pd;
+/* sizeof(struct txpd) + Interface specific header */
+#define NULL_PACKET_HDR 64
+ u32 data_len = NULL_PACKET_HDR;
+ struct sk_buff *skb;
+ int ret;
+ struct mwifiex_txinfo *tx_info = NULL;
+
+ if (adapter->surprise_removed)
+ return -1;
+
+ if (!priv->media_connected)
+ return -1;
+
+ if (adapter->data_sent)
+ return -1;
+
+ skb = dev_alloc_skb(data_len);
+ if (!skb)
+ return -1;
+
+ tx_info = MWIFIEX_SKB_TXCB(skb);
+ tx_info->bss_index = priv->bss_index;
+ skb_reserve(skb, sizeof(struct txpd) + INTF_HEADER_LEN);
+ skb_push(skb, sizeof(struct txpd));
+
+ local_tx_pd = (struct txpd *) skb->data;
+ local_tx_pd->tx_control = cpu_to_le32(priv->pkt_tx_ctrl);
+ local_tx_pd->flags = flags;
+ local_tx_pd->priority = WMM_HIGHEST_PRIORITY;
+ local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd));
+ local_tx_pd->bss_num = priv->bss_num;
+ local_tx_pd->bss_type = priv->bss_type;
+
+ skb_push(skb, INTF_HEADER_LEN);
+
+ ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
+ skb->data, skb->len, NULL);
+ switch (ret) {
+ case -EBUSY:
+ adapter->data_sent = true;
+ /* Fall through FAILURE handling */
+ case -1:
+ dev_kfree_skb_any(skb);
+ dev_err(adapter->dev, "%s: host_to_card failed: ret=%d\n",
+ __func__, ret);
+ adapter->dbg.num_tx_host_to_card_failure++;
+ break;
+ case 0:
+ dev_kfree_skb_any(skb);
+ dev_dbg(adapter->dev, "data: %s: host_to_card succeeded\n",
+ __func__);
+ adapter->tx_lock_flag = true;
+ break;
+ case -EINPROGRESS:
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * This function checks if we need to send last packet indication.
+ */
+u8
+mwifiex_check_last_packet_indication(struct mwifiex_private *priv)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ u8 ret = false;
+
+ if (!adapter->sleep_period.period)
+ return ret;
+ if (mwifiex_wmm_lists_empty(adapter))
+ ret = true;
+
+ if (ret && !adapter->cmd_sent && !adapter->curr_cmd
+ && !is_command_pending(adapter)) {
+ adapter->delay_null_pkt = false;
+ ret = true;
+ } else {
+ ret = false;
+ adapter->delay_null_pkt = true;
+ }
+ return ret;
+}
diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c
new file mode 100644
index 000000000000..aaa50c074196
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/txrx.c
@@ -0,0 +1,202 @@
+/*
+ * Marvell Wireless LAN device driver: generic TX/RX data handling
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+
+/*
+ * This function processes the received buffer.
+ *
+ * Main responsibility of this function is to parse the RxPD to
+ * identify the correct interface this packet is headed for and
+ * forwarding it to the associated handling function, where the
+ * packet will be further processed and sent to kernel/upper layer
+ * if required.
+ */
+int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter,
+ struct sk_buff *skb)
+{
+ struct mwifiex_private *priv =
+ mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+ struct rxpd *local_rx_pd;
+ struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
+
+ local_rx_pd = (struct rxpd *) (skb->data);
+ /* Get the BSS number from rxpd, get corresponding priv */
+ priv = mwifiex_get_priv_by_id(adapter, local_rx_pd->bss_num &
+ BSS_NUM_MASK, local_rx_pd->bss_type);
+ if (!priv)
+ priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+
+ rx_info->bss_index = priv->bss_index;
+
+ return mwifiex_process_sta_rx_packet(adapter, skb);
+}
+EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet);
+
+/*
+ * This function sends a packet to device.
+ *
+ * It processes the packet to add the TxPD, checks condition and
+ * sends the processed packet to firmware for transmission.
+ *
+ * On successful completion, the function calls the completion callback
+ * and logs the time.
+ */
+int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
+ struct mwifiex_tx_param *tx_param)
+{
+ int ret = -1;
+ struct mwifiex_adapter *adapter = priv->adapter;
+ u8 *head_ptr;
+ struct txpd *local_tx_pd = NULL;
+
+ head_ptr = (u8 *) mwifiex_process_sta_txpd(priv, skb);
+ if (head_ptr) {
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA)
+ local_tx_pd =
+ (struct txpd *) (head_ptr + INTF_HEADER_LEN);
+
+ ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
+ skb->data, skb->len, tx_param);
+ }
+
+ switch (ret) {
+ case -EBUSY:
+ if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) &&
+ (adapter->pps_uapsd_mode) &&
+ (adapter->tx_lock_flag)) {
+ priv->adapter->tx_lock_flag = false;
+ local_tx_pd->flags = 0;
+ }
+ dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
+ break;
+ case -1:
+ adapter->data_sent = false;
+ dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n",
+ ret);
+ adapter->dbg.num_tx_host_to_card_failure++;
+ mwifiex_write_data_complete(adapter, skb, ret);
+ break;
+ case -EINPROGRESS:
+ adapter->data_sent = false;
+ break;
+ case 0:
+ mwifiex_write_data_complete(adapter, skb, ret);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Packet send completion callback handler.
+ *
+ * It either frees the buffer directly or forwards it to another
+ * completion callback which checks conditions, updates statistics,
+ * wakes up stalled traffic queue if required, and then frees the buffer.
+ */
+int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
+ struct sk_buff *skb, int status)
+{
+ struct mwifiex_private *priv, *tpriv;
+ struct mwifiex_txinfo *tx_info;
+ int i;
+
+ if (!skb)
+ return 0;
+
+ tx_info = MWIFIEX_SKB_TXCB(skb);
+ priv = mwifiex_bss_index_to_priv(adapter, tx_info->bss_index);
+ if (!priv)
+ goto done;
+
+ priv->netdev->trans_start = jiffies;
+ if (!status) {
+ priv->stats.tx_packets++;
+ priv->stats.tx_bytes += skb->len;
+ } else {
+ priv->stats.tx_errors++;
+ }
+
+ if (atomic_dec_return(&adapter->tx_pending) >= LOW_TX_PENDING)
+ goto done;
+
+ for (i = 0; i < adapter->priv_num; i++) {
+
+ tpriv = adapter->priv[i];
+
+ if ((GET_BSS_ROLE(tpriv) == MWIFIEX_BSS_ROLE_STA)
+ && (tpriv->media_connected)) {
+ if (netif_queue_stopped(tpriv->netdev))
+ netif_wake_queue(tpriv->netdev);
+ }
+ }
+done:
+ dev_kfree_skb_any(skb);
+
+ return 0;
+}
+
+/*
+ * Packet receive completion callback handler.
+ *
+ * This function calls another completion callback handler which
+ * updates the statistics, and optionally updates the parent buffer
+ * use count before freeing the received packet.
+ */
+int mwifiex_recv_packet_complete(struct mwifiex_adapter *adapter,
+ struct sk_buff *skb, int status)
+{
+ struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
+ struct mwifiex_rxinfo *rx_info_parent;
+ struct mwifiex_private *priv;
+ struct sk_buff *skb_parent;
+ unsigned long flags;
+
+ priv = adapter->priv[rx_info->bss_index];
+
+ if (priv && (status == -1))
+ priv->stats.rx_dropped++;
+
+ if (rx_info->parent) {
+ skb_parent = rx_info->parent;
+ rx_info_parent = MWIFIEX_SKB_RXCB(skb_parent);
+
+ spin_lock_irqsave(&priv->rx_pkt_lock, flags);
+ --rx_info_parent->use_count;
+
+ if (!rx_info_parent->use_count) {
+ spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
+ dev_kfree_skb_any(skb_parent);
+ } else {
+ spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
+ }
+ } else {
+ dev_kfree_skb_any(skb);
+ }
+
+ return 0;
+}
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c
new file mode 100644
index 000000000000..d41291529bc0
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/util.c
@@ -0,0 +1,202 @@
+/*
+ * Marvell Wireless LAN device driver: utility functions
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+
+/*
+ * Firmware initialization complete callback handler.
+ *
+ * This function wakes up the function waiting on the init
+ * wait queue for the firmware initialization to complete.
+ */
+int mwifiex_init_fw_complete(struct mwifiex_adapter *adapter)
+{
+
+ adapter->init_wait_q_woken = true;
+ wake_up_interruptible(&adapter->init_wait_q);
+ return 0;
+}
+
+/*
+ * Firmware shutdown complete callback handler.
+ *
+ * This function sets the hardware status to not ready and wakes up
+ * the function waiting on the init wait queue for the firmware
+ * shutdown to complete.
+ */
+int mwifiex_shutdown_fw_complete(struct mwifiex_adapter *adapter)
+{
+ adapter->hw_status = MWIFIEX_HW_STATUS_NOT_READY;
+ adapter->init_wait_q_woken = true;
+ wake_up_interruptible(&adapter->init_wait_q);
+ return 0;
+}
+
+/*
+ * This function sends init/shutdown command
+ * to firmware.
+ */
+int mwifiex_init_shutdown_fw(struct mwifiex_private *priv,
+ u32 func_init_shutdown)
+{
+ u16 cmd;
+
+ if (func_init_shutdown == MWIFIEX_FUNC_INIT) {
+ cmd = HostCmd_CMD_FUNC_INIT;
+ } else if (func_init_shutdown == MWIFIEX_FUNC_SHUTDOWN) {
+ cmd = HostCmd_CMD_FUNC_SHUTDOWN;
+ } else {
+ dev_err(priv->adapter->dev, "unsupported parameter\n");
+ return -1;
+ }
+
+ return mwifiex_send_cmd_sync(priv, cmd, HostCmd_ACT_GEN_SET, 0, NULL);
+}
+EXPORT_SYMBOL_GPL(mwifiex_init_shutdown_fw);
+
+/*
+ * IOCTL request handler to set/get debug information.
+ *
+ * This function collates/sets the information from/to different driver
+ * structures.
+ */
+int mwifiex_get_debug_info(struct mwifiex_private *priv,
+ struct mwifiex_debug_info *info)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+
+ if (info) {
+ memcpy(info->packets_out,
+ priv->wmm.packets_out,
+ sizeof(priv->wmm.packets_out));
+ info->max_tx_buf_size = (u32) adapter->max_tx_buf_size;
+ info->tx_buf_size = (u32) adapter->tx_buf_size;
+ info->rx_tbl_num = mwifiex_get_rx_reorder_tbl(
+ priv, info->rx_tbl);
+ info->tx_tbl_num = mwifiex_get_tx_ba_stream_tbl(
+ priv, info->tx_tbl);
+ info->ps_mode = adapter->ps_mode;
+ info->ps_state = adapter->ps_state;
+ info->is_deep_sleep = adapter->is_deep_sleep;
+ info->pm_wakeup_card_req = adapter->pm_wakeup_card_req;
+ info->pm_wakeup_fw_try = adapter->pm_wakeup_fw_try;
+ info->is_hs_configured = adapter->is_hs_configured;
+ info->hs_activated = adapter->hs_activated;
+ info->num_cmd_host_to_card_failure
+ = adapter->dbg.num_cmd_host_to_card_failure;
+ info->num_cmd_sleep_cfm_host_to_card_failure
+ = adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure;
+ info->num_tx_host_to_card_failure
+ = adapter->dbg.num_tx_host_to_card_failure;
+ info->num_event_deauth = adapter->dbg.num_event_deauth;
+ info->num_event_disassoc = adapter->dbg.num_event_disassoc;
+ info->num_event_link_lost = adapter->dbg.num_event_link_lost;
+ info->num_cmd_deauth = adapter->dbg.num_cmd_deauth;
+ info->num_cmd_assoc_success =
+ adapter->dbg.num_cmd_assoc_success;
+ info->num_cmd_assoc_failure =
+ adapter->dbg.num_cmd_assoc_failure;
+ info->num_tx_timeout = adapter->dbg.num_tx_timeout;
+ info->num_cmd_timeout = adapter->dbg.num_cmd_timeout;
+ info->timeout_cmd_id = adapter->dbg.timeout_cmd_id;
+ info->timeout_cmd_act = adapter->dbg.timeout_cmd_act;
+ memcpy(info->last_cmd_id, adapter->dbg.last_cmd_id,
+ sizeof(adapter->dbg.last_cmd_id));
+ memcpy(info->last_cmd_act, adapter->dbg.last_cmd_act,
+ sizeof(adapter->dbg.last_cmd_act));
+ info->last_cmd_index = adapter->dbg.last_cmd_index;
+ memcpy(info->last_cmd_resp_id, adapter->dbg.last_cmd_resp_id,
+ sizeof(adapter->dbg.last_cmd_resp_id));
+ info->last_cmd_resp_index = adapter->dbg.last_cmd_resp_index;
+ memcpy(info->last_event, adapter->dbg.last_event,
+ sizeof(adapter->dbg.last_event));
+ info->last_event_index = adapter->dbg.last_event_index;
+ info->data_sent = adapter->data_sent;
+ info->cmd_sent = adapter->cmd_sent;
+ info->cmd_resp_received = adapter->cmd_resp_received;
+ }
+
+ return 0;
+}
+
+/*
+ * This function processes the received packet before sending it to the
+ * kernel.
+ *
+ * It extracts the SKB from the received buffer and sends it to kernel.
+ * In case the received buffer does not contain the data in SKB format,
+ * the function creates a blank SKB, fills it with the data from the
+ * received buffer and then sends this new SKB to the kernel.
+ */
+int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb)
+{
+ struct mwifiex_rxinfo *rx_info;
+ struct mwifiex_private *priv;
+
+ if (!skb)
+ return -1;
+
+ rx_info = MWIFIEX_SKB_RXCB(skb);
+ priv = mwifiex_bss_index_to_priv(adapter, rx_info->bss_index);
+ if (!priv)
+ return -1;
+
+ skb->dev = priv->netdev;
+ skb->protocol = eth_type_trans(skb, priv->netdev);
+ skb->ip_summed = CHECKSUM_NONE;
+ priv->stats.rx_bytes += skb->len;
+ priv->stats.rx_packets++;
+ if (in_interrupt())
+ netif_rx(skb);
+ else
+ netif_rx_ni(skb);
+
+ return 0;
+}
+
+/*
+ * IOCTL completion callback handler.
+ *
+ * This function is called when a pending IOCTL is completed.
+ *
+ * If work queue support is enabled, the function wakes up the
+ * corresponding waiting function. Otherwise, it processes the
+ * IOCTL response and frees the response buffer.
+ */
+int mwifiex_complete_cmd(struct mwifiex_adapter *adapter)
+{
+ atomic_dec(&adapter->cmd_pending);
+ dev_dbg(adapter->dev, "cmd completed: status=%d\n",
+ adapter->cmd_wait_q.status);
+
+ adapter->cmd_wait_q.condition = true;
+
+ if (adapter->cmd_wait_q.status == -ETIMEDOUT)
+ dev_err(adapter->dev, "cmd timeout\n");
+ else
+ wake_up_interruptible(&adapter->cmd_wait_q.wait);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/mwifiex/util.h b/drivers/net/wireless/mwifiex/util.h
new file mode 100644
index 000000000000..9506afc6c0e4
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/util.h
@@ -0,0 +1,32 @@
+/*
+ * Marvell Wireless LAN device driver: utility functions
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef _MWIFIEX_UTIL_H_
+#define _MWIFIEX_UTIL_H_
+
+static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb)
+{
+ return (struct mwifiex_rxinfo *)skb->cb;
+}
+
+static inline struct mwifiex_txinfo *MWIFIEX_SKB_TXCB(struct sk_buff *skb)
+{
+ return (struct mwifiex_txinfo *)skb->cb;
+}
+#endif /* !_MWIFIEX_UTIL_H_ */
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
new file mode 100644
index 000000000000..91634daec306
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -0,0 +1,1264 @@
+/*
+ * Marvell Wireless LAN device driver: WMM
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "util.h"
+#include "fw.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n.h"
+
+
+/* Maximum value FW can accept for driver delay in packet transmission */
+#define DRV_PKT_DELAY_TO_FW_MAX 512
+
+
+#define WMM_QUEUED_PACKET_LOWER_LIMIT 180
+
+#define WMM_QUEUED_PACKET_UPPER_LIMIT 200
+
+/* Offset for TOS field in the IP header */
+#define IPTOS_OFFSET 5
+
+/* WMM information IE */
+static const u8 wmm_info_ie[] = { WLAN_EID_VENDOR_SPECIFIC, 0x07,
+ 0x00, 0x50, 0xf2, 0x02,
+ 0x00, 0x01, 0x00
+};
+
+static const u8 wmm_aci_to_qidx_map[] = { WMM_AC_BE,
+ WMM_AC_BK,
+ WMM_AC_VI,
+ WMM_AC_VO
+};
+
+static u8 tos_to_tid[] = {
+ /* TID DSCP_P2 DSCP_P1 DSCP_P0 WMM_AC */
+ 0x01, /* 0 1 0 AC_BK */
+ 0x02, /* 0 0 0 AC_BK */
+ 0x00, /* 0 0 1 AC_BE */
+ 0x03, /* 0 1 1 AC_BE */
+ 0x04, /* 1 0 0 AC_VI */
+ 0x05, /* 1 0 1 AC_VI */
+ 0x06, /* 1 1 0 AC_VO */
+ 0x07 /* 1 1 1 AC_VO */
+};
+
+/*
+ * This table inverses the tos_to_tid operation to get a priority
+ * which is in sequential order, and can be compared.
+ * Use this to compare the priority of two different TIDs.
+ */
+static u8 tos_to_tid_inv[] = {
+ 0x02, /* from tos_to_tid[2] = 0 */
+ 0x00, /* from tos_to_tid[0] = 1 */
+ 0x01, /* from tos_to_tid[1] = 2 */
+ 0x03,
+ 0x04,
+ 0x05,
+ 0x06,
+ 0x07};
+
+static u8 ac_to_tid[4][2] = { {1, 2}, {0, 3}, {4, 5}, {6, 7} };
+
+/*
+ * This function debug prints the priority parameters for a WMM AC.
+ */
+static void
+mwifiex_wmm_ac_debug_print(const struct ieee_types_wmm_ac_parameters *ac_param)
+{
+ const char *ac_str[] = { "BK", "BE", "VI", "VO" };
+
+ pr_debug("info: WMM AC_%s: ACI=%d, ACM=%d, Aifsn=%d, "
+ "EcwMin=%d, EcwMax=%d, TxopLimit=%d\n",
+ ac_str[wmm_aci_to_qidx_map[(ac_param->aci_aifsn_bitmap
+ & MWIFIEX_ACI) >> 5]],
+ (ac_param->aci_aifsn_bitmap & MWIFIEX_ACI) >> 5,
+ (ac_param->aci_aifsn_bitmap & MWIFIEX_ACM) >> 4,
+ ac_param->aci_aifsn_bitmap & MWIFIEX_AIFSN,
+ ac_param->ecw_bitmap & MWIFIEX_ECW_MIN,
+ (ac_param->ecw_bitmap & MWIFIEX_ECW_MAX) >> 4,
+ le16_to_cpu(ac_param->tx_op_limit));
+}
+
+/*
+ * This function allocates a route address list.
+ *
+ * The function also initializes the list with the provided RA.
+ */
+static struct mwifiex_ra_list_tbl *
+mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, u8 *ra)
+{
+ struct mwifiex_ra_list_tbl *ra_list;
+
+ ra_list = kzalloc(sizeof(struct mwifiex_ra_list_tbl), GFP_ATOMIC);
+
+ if (!ra_list) {
+ dev_err(adapter->dev, "%s: failed to alloc ra_list\n",
+ __func__);
+ return NULL;
+ }
+ INIT_LIST_HEAD(&ra_list->list);
+ skb_queue_head_init(&ra_list->skb_head);
+
+ memcpy(ra_list->ra, ra, ETH_ALEN);
+
+ ra_list->total_pkts_size = 0;
+
+ dev_dbg(adapter->dev, "info: allocated ra_list %p\n", ra_list);
+
+ return ra_list;
+}
+
+/*
+ * This function allocates and adds a RA list for all TIDs
+ * with the given RA.
+ */
+void
+mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra)
+{
+ int i;
+ struct mwifiex_ra_list_tbl *ra_list;
+ struct mwifiex_adapter *adapter = priv->adapter;
+
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ ra_list = mwifiex_wmm_allocate_ralist_node(adapter, ra);
+ dev_dbg(adapter->dev, "info: created ra_list %p\n", ra_list);
+
+ if (!ra_list)
+ break;
+
+ if (!mwifiex_queuing_ra_based(priv))
+ ra_list->is_11n_enabled = IS_11N_ENABLED(priv);
+ else
+ ra_list->is_11n_enabled = false;
+
+ dev_dbg(adapter->dev, "data: ralist %p: is_11n_enabled=%d\n",
+ ra_list, ra_list->is_11n_enabled);
+
+ list_add_tail(&ra_list->list,
+ &priv->wmm.tid_tbl_ptr[i].ra_list);
+
+ if (!priv->wmm.tid_tbl_ptr[i].ra_list_curr)
+ priv->wmm.tid_tbl_ptr[i].ra_list_curr = ra_list;
+ }
+}
+
+/*
+ * This function sets the WMM queue priorities to their default values.
+ */
+static void mwifiex_wmm_default_queue_priorities(struct mwifiex_private *priv)
+{
+ /* Default queue priorities: VO->VI->BE->BK */
+ priv->wmm.queue_priority[0] = WMM_AC_VO;
+ priv->wmm.queue_priority[1] = WMM_AC_VI;
+ priv->wmm.queue_priority[2] = WMM_AC_BE;
+ priv->wmm.queue_priority[3] = WMM_AC_BK;
+}
+
+/*
+ * This function map ACs to TIDs.
+ */
+static void
+mwifiex_wmm_queue_priorities_tid(struct mwifiex_wmm_desc *wmm)
+{
+ u8 *queue_priority = wmm->queue_priority;
+ int i;
+
+ for (i = 0; i < 4; ++i) {
+ tos_to_tid[7 - (i * 2)] = ac_to_tid[queue_priority[i]][1];
+ tos_to_tid[6 - (i * 2)] = ac_to_tid[queue_priority[i]][0];
+ }
+
+ for (i = 0; i < MAX_NUM_TID; ++i)
+ tos_to_tid_inv[tos_to_tid[i]] = (u8)i;
+
+ atomic_set(&wmm->highest_queued_prio, HIGH_PRIO_TID);
+}
+
+/*
+ * This function initializes WMM priority queues.
+ */
+void
+mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv,
+ struct ieee_types_wmm_parameter *wmm_ie)
+{
+ u16 cw_min, avg_back_off, tmp[4];
+ u32 i, j, num_ac;
+ u8 ac_idx;
+
+ if (!wmm_ie || !priv->wmm_enabled) {
+ /* WMM is not enabled, just set the defaults and return */
+ mwifiex_wmm_default_queue_priorities(priv);
+ return;
+ }
+
+ dev_dbg(priv->adapter->dev, "info: WMM Parameter IE: version=%d, "
+ "qos_info Parameter Set Count=%d, Reserved=%#x\n",
+ wmm_ie->vend_hdr.version, wmm_ie->qos_info_bitmap &
+ IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK,
+ wmm_ie->reserved);
+
+ for (num_ac = 0; num_ac < ARRAY_SIZE(wmm_ie->ac_params); num_ac++) {
+ cw_min = (1 << (wmm_ie->ac_params[num_ac].ecw_bitmap &
+ MWIFIEX_ECW_MIN)) - 1;
+ avg_back_off = (cw_min >> 1) +
+ (wmm_ie->ac_params[num_ac].aci_aifsn_bitmap &
+ MWIFIEX_AIFSN);
+
+ ac_idx = wmm_aci_to_qidx_map[(wmm_ie->ac_params[num_ac].
+ aci_aifsn_bitmap &
+ MWIFIEX_ACI) >> 5];
+ priv->wmm.queue_priority[ac_idx] = ac_idx;
+ tmp[ac_idx] = avg_back_off;
+
+ dev_dbg(priv->adapter->dev, "info: WMM: CWmax=%d CWmin=%d Avg Back-off=%d\n",
+ (1 << ((wmm_ie->ac_params[num_ac].ecw_bitmap &
+ MWIFIEX_ECW_MAX) >> 4)) - 1,
+ cw_min, avg_back_off);
+ mwifiex_wmm_ac_debug_print(&wmm_ie->ac_params[num_ac]);
+ }
+
+ /* Bubble sort */
+ for (i = 0; i < num_ac; i++) {
+ for (j = 1; j < num_ac - i; j++) {
+ if (tmp[j - 1] > tmp[j]) {
+ swap(tmp[j - 1], tmp[j]);
+ swap(priv->wmm.queue_priority[j - 1],
+ priv->wmm.queue_priority[j]);
+ } else if (tmp[j - 1] == tmp[j]) {
+ if (priv->wmm.queue_priority[j - 1]
+ < priv->wmm.queue_priority[j])
+ swap(priv->wmm.queue_priority[j - 1],
+ priv->wmm.queue_priority[j]);
+ }
+ }
+ }
+
+ mwifiex_wmm_queue_priorities_tid(&priv->wmm);
+}
+
+/*
+ * This function evaluates whether or not an AC is to be downgraded.
+ *
+ * In case the AC is not enabled, the highest AC is returned that is
+ * enabled and does not require admission control.
+ */
+static enum mwifiex_wmm_ac_e
+mwifiex_wmm_eval_downgrade_ac(struct mwifiex_private *priv,
+ enum mwifiex_wmm_ac_e eval_ac)
+{
+ int down_ac;
+ enum mwifiex_wmm_ac_e ret_ac;
+ struct mwifiex_wmm_ac_status *ac_status;
+
+ ac_status = &priv->wmm.ac_status[eval_ac];
+
+ if (!ac_status->disabled)
+ /* Okay to use this AC, its enabled */
+ return eval_ac;
+
+ /* Setup a default return value of the lowest priority */
+ ret_ac = WMM_AC_BK;
+
+ /*
+ * Find the highest AC that is enabled and does not require
+ * admission control. The spec disallows downgrading to an AC,
+ * which is enabled due to a completed admission control.
+ * Unadmitted traffic is not to be sent on an AC with admitted
+ * traffic.
+ */
+ for (down_ac = WMM_AC_BK; down_ac < eval_ac; down_ac++) {
+ ac_status = &priv->wmm.ac_status[down_ac];
+
+ if (!ac_status->disabled && !ac_status->flow_required)
+ /* AC is enabled and does not require admission
+ control */
+ ret_ac = (enum mwifiex_wmm_ac_e) down_ac;
+ }
+
+ return ret_ac;
+}
+
+/*
+ * This function downgrades WMM priority queue.
+ */
+void
+mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv)
+{
+ int ac_val;
+
+ dev_dbg(priv->adapter->dev, "info: WMM: AC Priorities:"
+ "BK(0), BE(1), VI(2), VO(3)\n");
+
+ if (!priv->wmm_enabled) {
+ /* WMM is not enabled, default priorities */
+ for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++)
+ priv->wmm.ac_down_graded_vals[ac_val] =
+ (enum mwifiex_wmm_ac_e) ac_val;
+ } else {
+ for (ac_val = WMM_AC_BK; ac_val <= WMM_AC_VO; ac_val++) {
+ priv->wmm.ac_down_graded_vals[ac_val]
+ = mwifiex_wmm_eval_downgrade_ac(priv,
+ (enum mwifiex_wmm_ac_e) ac_val);
+ dev_dbg(priv->adapter->dev, "info: WMM: AC PRIO %d maps to %d\n",
+ ac_val, priv->wmm.ac_down_graded_vals[ac_val]);
+ }
+ }
+}
+
+/*
+ * This function converts the IP TOS field to an WMM AC
+ * Queue assignment.
+ */
+static enum mwifiex_wmm_ac_e
+mwifiex_wmm_convert_tos_to_ac(struct mwifiex_adapter *adapter, u32 tos)
+{
+ /* Map of TOS UP values to WMM AC */
+ const enum mwifiex_wmm_ac_e tos_to_ac[] = { WMM_AC_BE,
+ WMM_AC_BK,
+ WMM_AC_BK,
+ WMM_AC_BE,
+ WMM_AC_VI,
+ WMM_AC_VI,
+ WMM_AC_VO,
+ WMM_AC_VO
+ };
+
+ if (tos >= ARRAY_SIZE(tos_to_ac))
+ return WMM_AC_BE;
+
+ return tos_to_ac[tos];
+}
+
+/*
+ * This function evaluates a given TID and downgrades it to a lower
+ * TID if the WMM Parameter IE received from the AP indicates that the
+ * AP is disabled (due to call admission control (ACM bit). Mapping
+ * of TID to AC is taken care of internally.
+ */
+static u8
+mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid)
+{
+ enum mwifiex_wmm_ac_e ac, ac_down;
+ u8 new_tid;
+
+ ac = mwifiex_wmm_convert_tos_to_ac(priv->adapter, tid);
+ ac_down = priv->wmm.ac_down_graded_vals[ac];
+
+ /* Send the index to tid array, picking from the array will be
+ * taken care by dequeuing function
+ */
+ new_tid = ac_to_tid[ac_down][tid % 2];
+
+ return new_tid;
+}
+
+/*
+ * This function initializes the WMM state information and the
+ * WMM data path queues.
+ */
+void
+mwifiex_wmm_init(struct mwifiex_adapter *adapter)
+{
+ int i, j;
+ struct mwifiex_private *priv;
+
+ for (j = 0; j < adapter->priv_num; ++j) {
+ priv = adapter->priv[j];
+ if (!priv)
+ continue;
+
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ priv->aggr_prio_tbl[i].amsdu = tos_to_tid_inv[i];
+ priv->aggr_prio_tbl[i].ampdu_ap = tos_to_tid_inv[i];
+ priv->aggr_prio_tbl[i].ampdu_user = tos_to_tid_inv[i];
+ priv->wmm.tid_tbl_ptr[i].ra_list_curr = NULL;
+ }
+
+ priv->aggr_prio_tbl[6].amsdu
+ = priv->aggr_prio_tbl[6].ampdu_ap
+ = priv->aggr_prio_tbl[6].ampdu_user
+ = BA_STREAM_NOT_ALLOWED;
+
+ priv->aggr_prio_tbl[7].amsdu = priv->aggr_prio_tbl[7].ampdu_ap
+ = priv->aggr_prio_tbl[7].ampdu_user
+ = BA_STREAM_NOT_ALLOWED;
+
+ priv->add_ba_param.timeout = MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT;
+ priv->add_ba_param.tx_win_size = MWIFIEX_AMPDU_DEF_TXWINSIZE;
+ priv->add_ba_param.rx_win_size = MWIFIEX_AMPDU_DEF_RXWINSIZE;
+
+ atomic_set(&priv->wmm.tx_pkts_queued, 0);
+ atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID);
+ }
+}
+
+/*
+ * This function checks if WMM Tx queue is empty.
+ */
+int
+mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter)
+{
+ int i;
+ struct mwifiex_private *priv;
+
+ for (i = 0; i < adapter->priv_num; ++i) {
+ priv = adapter->priv[i];
+ if (priv && atomic_read(&priv->wmm.tx_pkts_queued))
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * This function deletes all packets in an RA list node.
+ *
+ * The packet sent completion callback handler are called with
+ * status failure, after they are dequeued to ensure proper
+ * cleanup. The RA list node itself is freed at the end.
+ */
+static void
+mwifiex_wmm_del_pkts_in_ralist_node(struct mwifiex_private *priv,
+ struct mwifiex_ra_list_tbl *ra_list)
+{
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct sk_buff *skb, *tmp;
+
+ skb_queue_walk_safe(&ra_list->skb_head, skb, tmp)
+ mwifiex_write_data_complete(adapter, skb, -1);
+}
+
+/*
+ * This function deletes all packets in an RA list.
+ *
+ * Each nodes in the RA list are freed individually first, and then
+ * the RA list itself is freed.
+ */
+static void
+mwifiex_wmm_del_pkts_in_ralist(struct mwifiex_private *priv,
+ struct list_head *ra_list_head)
+{
+ struct mwifiex_ra_list_tbl *ra_list;
+
+ list_for_each_entry(ra_list, ra_list_head, list)
+ mwifiex_wmm_del_pkts_in_ralist_node(priv, ra_list);
+}
+
+/*
+ * This function deletes all packets in all RA lists.
+ */
+static void mwifiex_wmm_cleanup_queues(struct mwifiex_private *priv)
+{
+ int i;
+
+ for (i = 0; i < MAX_NUM_TID; i++)
+ mwifiex_wmm_del_pkts_in_ralist(priv, &priv->wmm.tid_tbl_ptr[i].
+ ra_list);
+
+ atomic_set(&priv->wmm.tx_pkts_queued, 0);
+ atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID);
+}
+
+/*
+ * This function deletes all route addresses from all RA lists.
+ */
+static void mwifiex_wmm_delete_all_ralist(struct mwifiex_private *priv)
+{
+ struct mwifiex_ra_list_tbl *ra_list, *tmp_node;
+ int i;
+
+ for (i = 0; i < MAX_NUM_TID; ++i) {
+ dev_dbg(priv->adapter->dev,
+ "info: ra_list: freeing buf for tid %d\n", i);
+ list_for_each_entry_safe(ra_list, tmp_node,
+ &priv->wmm.tid_tbl_ptr[i].ra_list, list) {
+ list_del(&ra_list->list);
+ kfree(ra_list);
+ }
+
+ INIT_LIST_HEAD(&priv->wmm.tid_tbl_ptr[i].ra_list);
+
+ priv->wmm.tid_tbl_ptr[i].ra_list_curr = NULL;
+ }
+}
+
+/*
+ * This function cleans up the Tx and Rx queues.
+ *
+ * Cleanup includes -
+ * - All packets in RA lists
+ * - All entries in Rx reorder table
+ * - All entries in Tx BA stream table
+ * - MPA buffer (if required)
+ * - All RA lists
+ */
+void
+mwifiex_clean_txrx(struct mwifiex_private *priv)
+{
+ unsigned long flags;
+
+ mwifiex_11n_cleanup_reorder_tbl(priv);
+ spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
+
+ mwifiex_wmm_cleanup_queues(priv);
+ mwifiex_11n_delete_all_tx_ba_stream_tbl(priv);
+
+ if (priv->adapter->if_ops.cleanup_mpa_buf)
+ priv->adapter->if_ops.cleanup_mpa_buf(priv->adapter);
+
+ mwifiex_wmm_delete_all_ralist(priv);
+ memcpy(tos_to_tid, ac_to_tid, sizeof(tos_to_tid));
+
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
+}
+
+/*
+ * This function retrieves a particular RA list node, matching with the
+ * given TID and RA address.
+ */
+static struct mwifiex_ra_list_tbl *
+mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid,
+ u8 *ra_addr)
+{
+ struct mwifiex_ra_list_tbl *ra_list;
+
+ list_for_each_entry(ra_list, &priv->wmm.tid_tbl_ptr[tid].ra_list,
+ list) {
+ if (!memcmp(ra_list->ra, ra_addr, ETH_ALEN))
+ return ra_list;
+ }
+
+ return NULL;
+}
+
+/*
+ * This function retrieves an RA list node for a given TID and
+ * RA address pair.
+ *
+ * If no such node is found, a new node is added first and then
+ * retrieved.
+ */
+static struct mwifiex_ra_list_tbl *
+mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, u8 *ra_addr)
+{
+ struct mwifiex_ra_list_tbl *ra_list;
+
+ ra_list = mwifiex_wmm_get_ralist_node(priv, tid, ra_addr);
+ if (ra_list)
+ return ra_list;
+ mwifiex_ralist_add(priv, ra_addr);
+
+ return mwifiex_wmm_get_ralist_node(priv, tid, ra_addr);
+}
+
+/*
+ * This function checks if a particular RA list node exists in a given TID
+ * table index.
+ */
+int
+mwifiex_is_ralist_valid(struct mwifiex_private *priv,
+ struct mwifiex_ra_list_tbl *ra_list, int ptr_index)
+{
+ struct mwifiex_ra_list_tbl *rlist;
+
+ list_for_each_entry(rlist, &priv->wmm.tid_tbl_ptr[ptr_index].ra_list,
+ list) {
+ if (rlist == ra_list)
+ return true;
+ }
+
+ return false;
+}
+
+/*
+ * This function adds a packet to WMM queue.
+ *
+ * In disconnected state the packet is immediately dropped and the
+ * packet send completion callback is called with status failure.
+ *
+ * Otherwise, the correct RA list node is located and the packet
+ * is queued at the list tail.
+ */
+void
+mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter,
+ struct sk_buff *skb)
+{
+ struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb);
+ struct mwifiex_private *priv = adapter->priv[tx_info->bss_index];
+ u32 tid;
+ struct mwifiex_ra_list_tbl *ra_list;
+ u8 ra[ETH_ALEN], tid_down;
+ unsigned long flags;
+
+ if (!priv->media_connected) {
+ dev_dbg(adapter->dev, "data: drop packet in disconnect\n");
+ mwifiex_write_data_complete(adapter, skb, -1);
+ return;
+ }
+
+ tid = skb->priority;
+
+ spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
+
+ tid_down = mwifiex_wmm_downgrade_tid(priv, tid);
+
+ /* In case of infra as we have already created the list during
+ association we just don't have to call get_queue_raptr, we will
+ have only 1 raptr for a tid in case of infra */
+ if (!mwifiex_queuing_ra_based(priv)) {
+ if (!list_empty(&priv->wmm.tid_tbl_ptr[tid_down].ra_list))
+ ra_list = list_first_entry(
+ &priv->wmm.tid_tbl_ptr[tid_down].ra_list,
+ struct mwifiex_ra_list_tbl, list);
+ else
+ ra_list = NULL;
+ } else {
+ memcpy(ra, skb->data, ETH_ALEN);
+ ra_list = mwifiex_wmm_get_queue_raptr(priv, tid_down, ra);
+ }
+
+ if (!ra_list) {
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
+ mwifiex_write_data_complete(adapter, skb, -1);
+ return;
+ }
+
+ skb_queue_tail(&ra_list->skb_head, skb);
+
+ ra_list->total_pkts_size += skb->len;
+
+ atomic_inc(&priv->wmm.tx_pkts_queued);
+
+ if (atomic_read(&priv->wmm.highest_queued_prio) <
+ tos_to_tid_inv[tid_down])
+ atomic_set(&priv->wmm.highest_queued_prio,
+ tos_to_tid_inv[tid_down]);
+
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
+}
+
+/*
+ * This function processes the get WMM status command response from firmware.
+ *
+ * The response may contain multiple TLVs -
+ * - AC Queue status TLVs
+ * - Current WMM Parameter IE TLV
+ * - Admission Control action frame TLVs
+ *
+ * This function parses the TLVs and then calls further specific functions
+ * to process any changes in the queue prioritize or state.
+ */
+int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv,
+ const struct host_cmd_ds_command *resp)
+{
+ u8 *curr = (u8 *) &resp->params.get_wmm_status;
+ uint16_t resp_len = le16_to_cpu(resp->size), tlv_len;
+ int valid = true;
+
+ struct mwifiex_ie_types_data *tlv_hdr;
+ struct mwifiex_ie_types_wmm_queue_status *tlv_wmm_qstatus;
+ struct ieee_types_wmm_parameter *wmm_param_ie = NULL;
+ struct mwifiex_wmm_ac_status *ac_status;
+
+ dev_dbg(priv->adapter->dev, "info: WMM: WMM_GET_STATUS cmdresp received: %d\n",
+ resp_len);
+
+ while ((resp_len >= sizeof(tlv_hdr->header)) && valid) {
+ tlv_hdr = (struct mwifiex_ie_types_data *) curr;
+ tlv_len = le16_to_cpu(tlv_hdr->header.len);
+
+ switch (le16_to_cpu(tlv_hdr->header.type)) {
+ case TLV_TYPE_WMMQSTATUS:
+ tlv_wmm_qstatus =
+ (struct mwifiex_ie_types_wmm_queue_status *)
+ tlv_hdr;
+ dev_dbg(priv->adapter->dev,
+ "info: CMD_RESP: WMM_GET_STATUS:"
+ " QSTATUS TLV: %d, %d, %d\n",
+ tlv_wmm_qstatus->queue_index,
+ tlv_wmm_qstatus->flow_required,
+ tlv_wmm_qstatus->disabled);
+
+ ac_status = &priv->wmm.ac_status[tlv_wmm_qstatus->
+ queue_index];
+ ac_status->disabled = tlv_wmm_qstatus->disabled;
+ ac_status->flow_required =
+ tlv_wmm_qstatus->flow_required;
+ ac_status->flow_created = tlv_wmm_qstatus->flow_created;
+ break;
+
+ case WLAN_EID_VENDOR_SPECIFIC:
+ /*
+ * Point the regular IEEE IE 2 bytes into the Marvell IE
+ * and setup the IEEE IE type and length byte fields
+ */
+
+ wmm_param_ie =
+ (struct ieee_types_wmm_parameter *) (curr +
+ 2);
+ wmm_param_ie->vend_hdr.len = (u8) tlv_len;
+ wmm_param_ie->vend_hdr.element_id =
+ WLAN_EID_VENDOR_SPECIFIC;
+
+ dev_dbg(priv->adapter->dev,
+ "info: CMD_RESP: WMM_GET_STATUS:"
+ " WMM Parameter Set Count: %d\n",
+ wmm_param_ie->qos_info_bitmap &
+ IEEE80211_WMM_IE_AP_QOSINFO_PARAM_SET_CNT_MASK);
+
+ memcpy((u8 *) &priv->curr_bss_params.bss_descriptor.
+ wmm_ie, wmm_param_ie,
+ wmm_param_ie->vend_hdr.len + 2);
+
+ break;
+
+ default:
+ valid = false;
+ break;
+ }
+
+ curr += (tlv_len + sizeof(tlv_hdr->header));
+ resp_len -= (tlv_len + sizeof(tlv_hdr->header));
+ }
+
+ mwifiex_wmm_setup_queue_priorities(priv, wmm_param_ie);
+ mwifiex_wmm_setup_ac_downgrade(priv);
+
+ return 0;
+}
+
+/*
+ * Callback handler from the command module to allow insertion of a WMM TLV.
+ *
+ * If the BSS we are associating to supports WMM, this function adds the
+ * required WMM Information IE to the association request command buffer in
+ * the form of a Marvell extended IEEE IE.
+ */
+u32
+mwifiex_wmm_process_association_req(struct mwifiex_private *priv,
+ u8 **assoc_buf,
+ struct ieee_types_wmm_parameter *wmm_ie,
+ struct ieee80211_ht_cap *ht_cap)
+{
+ struct mwifiex_ie_types_wmm_param_set *wmm_tlv;
+ u32 ret_len = 0;
+
+ /* Null checks */
+ if (!assoc_buf)
+ return 0;
+ if (!(*assoc_buf))
+ return 0;
+
+ if (!wmm_ie)
+ return 0;
+
+ dev_dbg(priv->adapter->dev, "info: WMM: process assoc req:"
+ "bss->wmmIe=0x%x\n",
+ wmm_ie->vend_hdr.element_id);
+
+ if ((priv->wmm_required
+ || (ht_cap && (priv->adapter->config_bands & BAND_GN
+ || priv->adapter->config_bands & BAND_AN))
+ )
+ && wmm_ie->vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC) {
+ wmm_tlv = (struct mwifiex_ie_types_wmm_param_set *) *assoc_buf;
+ wmm_tlv->header.type = cpu_to_le16((u16) wmm_info_ie[0]);
+ wmm_tlv->header.len = cpu_to_le16((u16) wmm_info_ie[1]);
+ memcpy(wmm_tlv->wmm_ie, &wmm_info_ie[2],
+ le16_to_cpu(wmm_tlv->header.len));
+ if (wmm_ie->qos_info_bitmap & IEEE80211_WMM_IE_AP_QOSINFO_UAPSD)
+ memcpy((u8 *) (wmm_tlv->wmm_ie
+ + le16_to_cpu(wmm_tlv->header.len)
+ - sizeof(priv->wmm_qosinfo)),
+ &priv->wmm_qosinfo,
+ sizeof(priv->wmm_qosinfo));
+
+ ret_len = sizeof(wmm_tlv->header)
+ + le16_to_cpu(wmm_tlv->header.len);
+
+ *assoc_buf += ret_len;
+ }
+
+ return ret_len;
+}
+
+/*
+ * This function computes the time delay in the driver queues for a
+ * given packet.
+ *
+ * When the packet is received at the OS/Driver interface, the current
+ * time is set in the packet structure. The difference between the present
+ * time and that received time is computed in this function and limited
+ * based on pre-compiled limits in the driver.
+ */
+u8
+mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv,
+ const struct sk_buff *skb)
+{
+ u8 ret_val;
+ struct timeval out_tstamp, in_tstamp;
+ u32 queue_delay;
+
+ do_gettimeofday(&out_tstamp);
+ in_tstamp = ktime_to_timeval(skb->tstamp);
+
+ queue_delay = (out_tstamp.tv_sec - in_tstamp.tv_sec) * 1000;
+ queue_delay += (out_tstamp.tv_usec - in_tstamp.tv_usec) / 1000;
+
+ /*
+ * Queue delay is passed as a uint8 in units of 2ms (ms shifted
+ * by 1). Min value (other than 0) is therefore 2ms, max is 510ms.
+ *
+ * Pass max value if queue_delay is beyond the uint8 range
+ */
+ ret_val = (u8) (min(queue_delay, priv->wmm.drv_pkt_delay_max) >> 1);
+
+ dev_dbg(priv->adapter->dev, "data: WMM: Pkt Delay: %d ms,"
+ " %d ms sent to FW\n", queue_delay, ret_val);
+
+ return ret_val;
+}
+
+/*
+ * This function retrieves the highest priority RA list table pointer.
+ */
+static struct mwifiex_ra_list_tbl *
+mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
+ struct mwifiex_private **priv, int *tid)
+{
+ struct mwifiex_private *priv_tmp;
+ struct mwifiex_ra_list_tbl *ptr, *head;
+ struct mwifiex_bss_prio_node *bssprio_node, *bssprio_head;
+ struct mwifiex_tid_tbl *tid_ptr;
+ int is_list_empty;
+ unsigned long flags;
+ int i, j;
+
+ for (j = adapter->priv_num - 1; j >= 0; --j) {
+ spin_lock_irqsave(&adapter->bss_prio_tbl[j].bss_prio_lock,
+ flags);
+ is_list_empty = list_empty(&adapter->bss_prio_tbl[j]
+ .bss_prio_head);
+ spin_unlock_irqrestore(&adapter->bss_prio_tbl[j].bss_prio_lock,
+ flags);
+ if (is_list_empty)
+ continue;
+
+ if (adapter->bss_prio_tbl[j].bss_prio_cur ==
+ (struct mwifiex_bss_prio_node *)
+ &adapter->bss_prio_tbl[j].bss_prio_head) {
+ bssprio_node =
+ list_first_entry(&adapter->bss_prio_tbl[j]
+ .bss_prio_head,
+ struct mwifiex_bss_prio_node,
+ list);
+ bssprio_head = bssprio_node;
+ } else {
+ bssprio_node = adapter->bss_prio_tbl[j].bss_prio_cur;
+ bssprio_head = bssprio_node;
+ }
+
+ do {
+ atomic_t *hqp;
+ spinlock_t *lock;
+
+ priv_tmp = bssprio_node->priv;
+ hqp = &priv_tmp->wmm.highest_queued_prio;
+ lock = &priv_tmp->wmm.ra_list_spinlock;
+
+ for (i = atomic_read(hqp); i >= LOW_PRIO_TID; --i) {
+
+ tid_ptr = &(priv_tmp)->wmm.
+ tid_tbl_ptr[tos_to_tid[i]];
+
+ spin_lock_irqsave(&tid_ptr->tid_tbl_lock,
+ flags);
+ is_list_empty =
+ list_empty(&adapter->bss_prio_tbl[j]
+ .bss_prio_head);
+ spin_unlock_irqrestore(&tid_ptr->tid_tbl_lock,
+ flags);
+ if (is_list_empty)
+ continue;
+
+ /*
+ * Always choose the next ra we transmitted
+ * last time, this way we pick the ra's in
+ * round robin fashion.
+ */
+ ptr = list_first_entry(
+ &tid_ptr->ra_list_curr->list,
+ struct mwifiex_ra_list_tbl,
+ list);
+
+ head = ptr;
+ if (ptr == (struct mwifiex_ra_list_tbl *)
+ &tid_ptr->ra_list) {
+ /* Get next ra */
+ ptr = list_first_entry(&ptr->list,
+ struct mwifiex_ra_list_tbl, list);
+ head = ptr;
+ }
+
+ do {
+ is_list_empty =
+ skb_queue_empty(&ptr->skb_head);
+ if (!is_list_empty) {
+ spin_lock_irqsave(lock, flags);
+ if (atomic_read(hqp) > i)
+ atomic_set(hqp, i);
+ spin_unlock_irqrestore(lock,
+ flags);
+ *priv = priv_tmp;
+ *tid = tos_to_tid[i];
+ return ptr;
+ }
+ /* Get next ra */
+ ptr = list_first_entry(&ptr->list,
+ struct mwifiex_ra_list_tbl,
+ list);
+ if (ptr ==
+ (struct mwifiex_ra_list_tbl *)
+ &tid_ptr->ra_list)
+ ptr = list_first_entry(
+ &ptr->list,
+ struct mwifiex_ra_list_tbl,
+ list);
+ } while (ptr != head);
+ }
+
+ /* No packet at any TID for this priv. Mark as such
+ * to skip checking TIDs for this priv (until pkt is
+ * added).
+ */
+ atomic_set(hqp, NO_PKT_PRIO_TID);
+
+ /* Get next bss priority node */
+ bssprio_node = list_first_entry(&bssprio_node->list,
+ struct mwifiex_bss_prio_node,
+ list);
+
+ if (bssprio_node ==
+ (struct mwifiex_bss_prio_node *)
+ &adapter->bss_prio_tbl[j].bss_prio_head)
+ /* Get next bss priority node */
+ bssprio_node = list_first_entry(
+ &bssprio_node->list,
+ struct mwifiex_bss_prio_node,
+ list);
+ } while (bssprio_node != bssprio_head);
+ }
+ return NULL;
+}
+
+/*
+ * This function gets the number of packets in the Tx queue of a
+ * particular RA list.
+ */
+static int
+mwifiex_num_pkts_in_txq(struct mwifiex_private *priv,
+ struct mwifiex_ra_list_tbl *ptr, int max_buf_size)
+{
+ int count = 0, total_size = 0;
+ struct sk_buff *skb, *tmp;
+
+ skb_queue_walk_safe(&ptr->skb_head, skb, tmp) {
+ total_size += skb->len;
+ if (total_size < max_buf_size)
+ ++count;
+ else
+ break;
+ }
+
+ return count;
+}
+
+/*
+ * This function sends a single packet to firmware for transmission.
+ */
+static void
+mwifiex_send_single_packet(struct mwifiex_private *priv,
+ struct mwifiex_ra_list_tbl *ptr, int ptr_index,
+ unsigned long ra_list_flags)
+ __releases(&priv->wmm.ra_list_spinlock)
+{
+ struct sk_buff *skb, *skb_next;
+ struct mwifiex_tx_param tx_param;
+ struct mwifiex_adapter *adapter = priv->adapter;
+ struct mwifiex_txinfo *tx_info;
+
+ if (skb_queue_empty(&ptr->skb_head)) {
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+ ra_list_flags);
+ dev_dbg(adapter->dev, "data: nothing to send\n");
+ return;
+ }
+
+ skb = skb_dequeue(&ptr->skb_head);
+
+ tx_info = MWIFIEX_SKB_TXCB(skb);
+ dev_dbg(adapter->dev, "data: dequeuing the packet %p %p\n", ptr, skb);
+
+ ptr->total_pkts_size -= skb->len;
+
+ if (!skb_queue_empty(&ptr->skb_head))
+ skb_next = skb_peek(&ptr->skb_head);
+ else
+ skb_next = NULL;
+
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags);
+
+ tx_param.next_pkt_len = ((skb_next) ? skb_next->len +
+ sizeof(struct txpd) : 0);
+
+ if (mwifiex_process_tx(priv, skb, &tx_param) == -EBUSY) {
+ /* Queue the packet back at the head */
+ spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
+
+ if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+ ra_list_flags);
+ mwifiex_write_data_complete(adapter, skb, -1);
+ return;
+ }
+
+ skb_queue_tail(&ptr->skb_head, skb);
+
+ ptr->total_pkts_size += skb->len;
+ tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+ ra_list_flags);
+ } else {
+ spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
+ if (mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
+ priv->wmm.packets_out[ptr_index]++;
+ priv->wmm.tid_tbl_ptr[ptr_index].ra_list_curr = ptr;
+ }
+ adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur =
+ list_first_entry(
+ &adapter->bss_prio_tbl[priv->bss_priority]
+ .bss_prio_cur->list,
+ struct mwifiex_bss_prio_node,
+ list);
+ atomic_dec(&priv->wmm.tx_pkts_queued);
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+ ra_list_flags);
+ }
+}
+
+/*
+ * This function checks if the first packet in the given RA list
+ * is already processed or not.
+ */
+static int
+mwifiex_is_ptr_processed(struct mwifiex_private *priv,
+ struct mwifiex_ra_list_tbl *ptr)
+{
+ struct sk_buff *skb;
+ struct mwifiex_txinfo *tx_info;
+
+ if (skb_queue_empty(&ptr->skb_head))
+ return false;
+
+ skb = skb_peek(&ptr->skb_head);
+
+ tx_info = MWIFIEX_SKB_TXCB(skb);
+ if (tx_info->flags & MWIFIEX_BUF_FLAG_REQUEUED_PKT)
+ return true;
+
+ return false;
+}
+
+/*
+ * This function sends a single processed packet to firmware for
+ * transmission.
+ */
+static void
+mwifiex_send_processed_packet(struct mwifiex_private *priv,
+ struct mwifiex_ra_list_tbl *ptr, int ptr_index,
+ unsigned long ra_list_flags)
+ __releases(&priv->wmm.ra_list_spinlock)
+{
+ struct mwifiex_tx_param tx_param;
+ struct mwifiex_adapter *adapter = priv->adapter;
+ int ret = -1;
+ struct sk_buff *skb, *skb_next;
+ struct mwifiex_txinfo *tx_info;
+
+ if (skb_queue_empty(&ptr->skb_head)) {
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+ ra_list_flags);
+ return;
+ }
+
+ skb = skb_dequeue(&ptr->skb_head);
+
+ if (!skb_queue_empty(&ptr->skb_head))
+ skb_next = skb_peek(&ptr->skb_head);
+ else
+ skb_next = NULL;
+
+ tx_info = MWIFIEX_SKB_TXCB(skb);
+
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags);
+ tx_param.next_pkt_len =
+ ((skb_next) ? skb_next->len +
+ sizeof(struct txpd) : 0);
+ ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
+ skb->data, skb->len, &tx_param);
+ switch (ret) {
+ case -EBUSY:
+ dev_dbg(adapter->dev, "data: -EBUSY is returned\n");
+ spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
+
+ if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+ ra_list_flags);
+ mwifiex_write_data_complete(adapter, skb, -1);
+ return;
+ }
+
+ skb_queue_tail(&ptr->skb_head, skb);
+
+ tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+ ra_list_flags);
+ break;
+ case -1:
+ adapter->data_sent = false;
+ dev_err(adapter->dev, "host_to_card failed: %#x\n", ret);
+ adapter->dbg.num_tx_host_to_card_failure++;
+ mwifiex_write_data_complete(adapter, skb, ret);
+ break;
+ case -EINPROGRESS:
+ adapter->data_sent = false;
+ default:
+ break;
+ }
+ if (ret != -EBUSY) {
+ spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
+ if (mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
+ priv->wmm.packets_out[ptr_index]++;
+ priv->wmm.tid_tbl_ptr[ptr_index].ra_list_curr = ptr;
+ }
+ adapter->bss_prio_tbl[priv->bss_priority].bss_prio_cur =
+ list_first_entry(
+ &adapter->bss_prio_tbl[priv->bss_priority]
+ .bss_prio_cur->list,
+ struct mwifiex_bss_prio_node,
+ list);
+ atomic_dec(&priv->wmm.tx_pkts_queued);
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
+ ra_list_flags);
+ }
+}
+
+/*
+ * This function dequeues a packet from the highest priority list
+ * and transmits it.
+ */
+static int
+mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
+{
+ struct mwifiex_ra_list_tbl *ptr;
+ struct mwifiex_private *priv = NULL;
+ int ptr_index = 0;
+ u8 ra[ETH_ALEN];
+ int tid_del = 0, tid = 0;
+ unsigned long flags;
+
+ ptr = mwifiex_wmm_get_highest_priolist_ptr(adapter, &priv, &ptr_index);
+ if (!ptr)
+ return -1;
+
+ tid = mwifiex_get_tid(ptr);
+
+ dev_dbg(adapter->dev, "data: tid=%d\n", tid);
+
+ spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags);
+ if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
+ spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
+ return -1;
+ }
+
+ if (mwifiex_is_ptr_processed(priv, ptr)) {
+ mwifiex_send_processed_packet(priv, ptr, ptr_index, flags);
+ /* ra_list_spinlock has been freed in
+ mwifiex_send_processed_packet() */
+ return 0;
+ }
+
+ if (!ptr->is_11n_enabled || mwifiex_is_ba_stream_setup(priv, ptr, tid)
+ || ((priv->sec_info.wpa_enabled
+ || priv->sec_info.wpa2_enabled) && !priv->wpa_is_gtk_set)
+ ) {
+ mwifiex_send_single_packet(priv, ptr, ptr_index, flags);
+ /* ra_list_spinlock has been freed in
+ mwifiex_send_single_packet() */
+ } else {
+ if (mwifiex_is_ampdu_allowed(priv, tid)) {
+ if (mwifiex_space_avail_for_new_ba_stream(adapter)) {
+ mwifiex_11n_create_tx_ba_stream_tbl(priv,
+ ptr->ra, tid,
+ BA_STREAM_SETUP_INPROGRESS);
+ mwifiex_send_addba(priv, tid, ptr->ra);
+ } else if (mwifiex_find_stream_to_delete
+ (priv, tid, &tid_del, ra)) {
+ mwifiex_11n_create_tx_ba_stream_tbl(priv,
+ ptr->ra, tid,
+ BA_STREAM_SETUP_INPROGRESS);
+ mwifiex_send_delba(priv, tid_del, ra, 1);
+ }
+ }
+/* Minimum number of AMSDU */
+#define MIN_NUM_AMSDU 2
+ if (mwifiex_is_amsdu_allowed(priv, tid) &&
+ (mwifiex_num_pkts_in_txq(priv, ptr, adapter->tx_buf_size) >=
+ MIN_NUM_AMSDU))
+ mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN,
+ ptr_index, flags);
+ /* ra_list_spinlock has been freed in
+ mwifiex_11n_aggregate_pkt() */
+ else
+ mwifiex_send_single_packet(priv, ptr, ptr_index, flags);
+ /* ra_list_spinlock has been freed in
+ mwifiex_send_single_packet() */
+ }
+ return 0;
+}
+
+/*
+ * This function transmits the highest priority packet awaiting in the
+ * WMM Queues.
+ */
+void
+mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter)
+{
+ do {
+ /* Check if busy */
+ if (adapter->data_sent || adapter->tx_lock_flag)
+ break;
+
+ if (mwifiex_dequeue_tx_packet(adapter))
+ break;
+ } while (!mwifiex_wmm_lists_empty(adapter));
+}
diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h
new file mode 100644
index 000000000000..fcea1f68792f
--- /dev/null
+++ b/drivers/net/wireless/mwifiex/wmm.h
@@ -0,0 +1,110 @@
+/*
+ * Marvell Wireless LAN device driver: WMM
+ *
+ * Copyright (C) 2011, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#ifndef _MWIFIEX_WMM_H_
+#define _MWIFIEX_WMM_H_
+
+enum ieee_types_wmm_aciaifsn_bitmasks {
+ MWIFIEX_AIFSN = (BIT(0) | BIT(1) | BIT(2) | BIT(3)),
+ MWIFIEX_ACM = BIT(4),
+ MWIFIEX_ACI = (BIT(5) | BIT(6)),
+};
+
+enum ieee_types_wmm_ecw_bitmasks {
+ MWIFIEX_ECW_MIN = (BIT(0) | BIT(1) | BIT(2) | BIT(3)),
+ MWIFIEX_ECW_MAX = (BIT(4) | BIT(5) | BIT(6) | BIT(7)),
+};
+
+/*
+ * This function retrieves the TID of the given RA list.
+ */
+static inline int
+mwifiex_get_tid(struct mwifiex_ra_list_tbl *ptr)
+{
+ struct sk_buff *skb;
+
+ if (skb_queue_empty(&ptr->skb_head))
+ return 0;
+
+ skb = skb_peek(&ptr->skb_head);
+
+ return skb->priority;
+}
+
+/*
+ * This function gets the length of a list.
+ */
+static inline int
+mwifiex_wmm_list_len(struct list_head *head)
+{
+ struct list_head *pos;
+ int count = 0;
+
+ list_for_each(pos, head)
+ ++count;
+
+ return count;
+}
+
+/*
+ * This function checks if a RA list is empty or not.
+ */
+static inline u8
+mwifiex_wmm_is_ra_list_empty(struct list_head *ra_list_hhead)
+{
+ struct mwifiex_ra_list_tbl *ra_list;
+ int is_list_empty;
+
+ list_for_each_entry(ra_list, ra_list_hhead, list) {
+ is_list_empty = skb_queue_empty(&ra_list->skb_head);
+ if (!is_list_empty)
+ return false;
+ }
+
+ return true;
+}
+
+void mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter,
+ struct sk_buff *skb);
+void mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra);
+
+int mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter);
+void mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter);
+int mwifiex_is_ralist_valid(struct mwifiex_private *priv,
+ struct mwifiex_ra_list_tbl *ra_list, int tid);
+
+u8 mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv,
+ const struct sk_buff *skb);
+void mwifiex_wmm_init(struct mwifiex_adapter *adapter);
+
+extern u32 mwifiex_wmm_process_association_req(struct mwifiex_private *priv,
+ u8 **assoc_buf,
+ struct ieee_types_wmm_parameter
+ *wmmie,
+ struct ieee80211_ht_cap
+ *htcap);
+
+void mwifiex_wmm_setup_queue_priorities(struct mwifiex_private *priv,
+ struct ieee_types_wmm_parameter
+ *wmm_ie);
+void mwifiex_wmm_setup_ac_downgrade(struct mwifiex_private *priv);
+extern int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv,
+ const struct host_cmd_ds_command *resp);
+
+#endif /* !_MWIFIEX_WMM_H_ */
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index c1ceb4b23971..32261189bcef 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -63,6 +63,7 @@ MODULE_PARM_DESC(ap_mode_default,
#define MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL 0x00000c38
#define MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK 0x00000c3c
#define MWL8K_A2H_INT_DUMMY (1 << 20)
+#define MWL8K_A2H_INT_BA_WATCHDOG (1 << 14)
#define MWL8K_A2H_INT_CHNL_SWITCHED (1 << 11)
#define MWL8K_A2H_INT_QUEUE_EMPTY (1 << 10)
#define MWL8K_A2H_INT_RADAR_DETECT (1 << 7)
@@ -73,6 +74,14 @@ MODULE_PARM_DESC(ap_mode_default,
#define MWL8K_A2H_INT_RX_READY (1 << 1)
#define MWL8K_A2H_INT_TX_DONE (1 << 0)
+/* HW micro second timer register
+ * located at offset 0xA600. This
+ * will be used to timestamp tx
+ * packets.
+ */
+
+#define MWL8K_HW_TIMER_REGISTER 0x0000a600
+
#define MWL8K_A2H_EVENTS (MWL8K_A2H_INT_DUMMY | \
MWL8K_A2H_INT_CHNL_SWITCHED | \
MWL8K_A2H_INT_QUEUE_EMPTY | \
@@ -82,10 +91,14 @@ MODULE_PARM_DESC(ap_mode_default,
MWL8K_A2H_INT_MAC_EVENT | \
MWL8K_A2H_INT_OPC_DONE | \
MWL8K_A2H_INT_RX_READY | \
- MWL8K_A2H_INT_TX_DONE)
+ MWL8K_A2H_INT_TX_DONE | \
+ MWL8K_A2H_INT_BA_WATCHDOG)
#define MWL8K_RX_QUEUES 1
-#define MWL8K_TX_QUEUES 4
+#define MWL8K_TX_WMM_QUEUES 4
+#define MWL8K_MAX_AMPDU_QUEUES 8
+#define MWL8K_MAX_TX_QUEUES (MWL8K_TX_WMM_QUEUES + MWL8K_MAX_AMPDU_QUEUES)
+#define mwl8k_tx_queues(priv) (MWL8K_TX_WMM_QUEUES + (priv)->num_ampdu_queues)
struct rxd_ops {
int rxd_size;
@@ -134,6 +147,21 @@ struct mwl8k_tx_queue {
struct sk_buff **skb;
};
+enum {
+ AMPDU_NO_STREAM,
+ AMPDU_STREAM_NEW,
+ AMPDU_STREAM_IN_PROGRESS,
+ AMPDU_STREAM_ACTIVE,
+};
+
+struct mwl8k_ampdu_stream {
+ struct ieee80211_sta *sta;
+ u8 tid;
+ u8 state;
+ u8 idx;
+ u8 txq_idx; /* index of this stream in priv->txq */
+};
+
struct mwl8k_priv {
struct ieee80211_hw *hw;
struct pci_dev *pdev;
@@ -160,6 +188,12 @@ struct mwl8k_priv {
u32 ap_macids_supported;
u32 sta_macids_supported;
+ /* Ampdu stream information */
+ u8 num_ampdu_queues;
+ spinlock_t stream_lock;
+ struct mwl8k_ampdu_stream ampdu[MWL8K_MAX_AMPDU_QUEUES];
+ struct work_struct watchdog_ba_handle;
+
/* firmware access */
struct mutex fw_mutex;
struct task_struct *fw_mutex_owner;
@@ -191,7 +225,8 @@ struct mwl8k_priv {
int pending_tx_pkts;
struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES];
- struct mwl8k_tx_queue txq[MWL8K_TX_QUEUES];
+ struct mwl8k_tx_queue txq[MWL8K_MAX_TX_QUEUES];
+ u32 txq_offset[MWL8K_MAX_TX_QUEUES];
bool radio_on;
bool radio_short_preamble;
@@ -224,7 +259,7 @@ struct mwl8k_priv {
* preserve the queue configurations so they can be restored if/when
* the firmware image is swapped.
*/
- struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_QUEUES];
+ struct ieee80211_tx_queue_params wmm_params[MWL8K_TX_WMM_QUEUES];
/* async firmware loading state */
unsigned fw_state;
@@ -262,9 +297,17 @@ struct mwl8k_vif {
#define MWL8K_VIF(_vif) ((struct mwl8k_vif *)&((_vif)->drv_priv))
#define IEEE80211_KEY_CONF(_u8) ((struct ieee80211_key_conf *)(_u8))
+struct tx_traffic_info {
+ u32 start_time;
+ u32 pkts;
+};
+
+#define MWL8K_MAX_TID 8
struct mwl8k_sta {
/* Index into station database. Returned by UPDATE_STADB. */
u8 peer_id;
+ u8 is_ampdu_allowed;
+ struct tx_traffic_info tx_stats[MWL8K_MAX_TID];
};
#define MWL8K_STA(_sta) ((struct mwl8k_sta *)&((_sta)->drv_priv))
@@ -352,10 +395,12 @@ static const struct ieee80211_rate mwl8k_rates_50[] = {
#define MWL8K_CMD_ENABLE_SNIFFER 0x0150
#define MWL8K_CMD_SET_MAC_ADDR 0x0202 /* per-vif */
#define MWL8K_CMD_SET_RATEADAPT_MODE 0x0203
+#define MWL8K_CMD_GET_WATCHDOG_BITMAP 0x0205
#define MWL8K_CMD_BSS_START 0x1100 /* per-vif */
#define MWL8K_CMD_SET_NEW_STN 0x1111 /* per-vif */
#define MWL8K_CMD_UPDATE_ENCRYPTION 0x1122 /* per-vif */
#define MWL8K_CMD_UPDATE_STADB 0x1123
+#define MWL8K_CMD_BASTREAM 0x1125
static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize)
{
@@ -395,6 +440,8 @@ static const char *mwl8k_cmd_name(__le16 cmd, char *buf, int bufsize)
MWL8K_CMDNAME(SET_NEW_STN);
MWL8K_CMDNAME(UPDATE_ENCRYPTION);
MWL8K_CMDNAME(UPDATE_STADB);
+ MWL8K_CMDNAME(BASTREAM);
+ MWL8K_CMDNAME(GET_WATCHDOG_BITMAP);
default:
snprintf(buf, bufsize, "0x%x", cmd);
}
@@ -669,7 +716,7 @@ static int mwl8k_load_firmware(struct ieee80211_hw *hw)
"helper image\n", pci_name(priv->pdev));
return rc;
}
- msleep(5);
+ msleep(20);
rc = mwl8k_feed_fw_image(priv, fw->data, fw->size);
} else {
@@ -734,8 +781,11 @@ static inline void mwl8k_remove_dma_header(struct sk_buff *skb, __le16 qos)
skb_pull(skb, sizeof(*tr) - hdrlen);
}
+#define REDUCED_TX_HEADROOM 8
+
static void
-mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad)
+mwl8k_add_dma_header(struct mwl8k_priv *priv, struct sk_buff *skb,
+ int head_pad, int tail_pad)
{
struct ieee80211_hdr *wh;
int hdrlen;
@@ -751,7 +801,23 @@ mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad)
wh = (struct ieee80211_hdr *)skb->data;
hdrlen = ieee80211_hdrlen(wh->frame_control);
- reqd_hdrlen = sizeof(*tr);
+
+ /*
+ * Check if skb_resize is required because of
+ * tx_headroom adjustment.
+ */
+ if (priv->ap_fw && (hdrlen < (sizeof(struct ieee80211_cts)
+ + REDUCED_TX_HEADROOM))) {
+ if (pskb_expand_head(skb, REDUCED_TX_HEADROOM, 0, GFP_ATOMIC)) {
+
+ wiphy_err(priv->hw->wiphy,
+ "Failed to reallocate TX buffer\n");
+ return;
+ }
+ skb->truesize += REDUCED_TX_HEADROOM;
+ }
+
+ reqd_hdrlen = sizeof(*tr) + head_pad;
if (hdrlen != reqd_hdrlen)
skb_push(skb, reqd_hdrlen - hdrlen);
@@ -773,12 +839,14 @@ mwl8k_add_dma_header(struct sk_buff *skb, int tail_pad)
tr->fwlen = cpu_to_le16(skb->len - sizeof(*tr) + tail_pad);
}
-static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb)
+static void mwl8k_encapsulate_tx_frame(struct mwl8k_priv *priv,
+ struct sk_buff *skb)
{
struct ieee80211_hdr *wh;
struct ieee80211_tx_info *tx_info;
struct ieee80211_key_conf *key_conf;
int data_pad;
+ int head_pad = 0;
wh = (struct ieee80211_hdr *)skb->data;
@@ -790,9 +858,7 @@ static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb)
/*
* Make sure the packet header is in the DMA header format (4-address
- * without QoS), the necessary crypto padding between the header and the
- * payload has already been provided by mac80211, but it doesn't add tail
- * padding when HW crypto is enabled.
+ * without QoS), and add head & tail padding when HW crypto is enabled.
*
* We have the following trailer padding requirements:
* - WEP: 4 trailer bytes (ICV)
@@ -801,6 +867,7 @@ static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb)
*/
data_pad = 0;
if (key_conf != NULL) {
+ head_pad = key_conf->iv_len;
switch (key_conf->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
@@ -814,7 +881,7 @@ static void mwl8k_encapsulate_tx_frame(struct sk_buff *skb)
break;
}
}
- mwl8k_add_dma_header(skb, data_pad);
+ mwl8k_add_dma_header(priv, skb, head_pad, data_pad);
}
/*
@@ -1127,6 +1194,9 @@ static void mwl8k_rxq_deinit(struct ieee80211_hw *hw, int index)
struct mwl8k_rx_queue *rxq = priv->rxq + index;
int i;
+ if (rxq->rxd == NULL)
+ return;
+
for (i = 0; i < MWL8K_RX_DESCS; i++) {
if (rxq->buf[i].skb != NULL) {
pci_unmap_single(priv->pdev,
@@ -1319,7 +1389,7 @@ struct mwl8k_tx_desc {
__le16 pkt_len;
__u8 dest_MAC_addr[ETH_ALEN];
__le32 next_txd_phys_addr;
- __le32 reserved;
+ __le32 timestamp;
__le16 rate_info;
__u8 peer_id;
__u8 tx_frag_cnt;
@@ -1383,7 +1453,7 @@ static void mwl8k_dump_tx_rings(struct ieee80211_hw *hw)
struct mwl8k_priv *priv = hw->priv;
int i;
- for (i = 0; i < MWL8K_TX_QUEUES; i++) {
+ for (i = 0; i < mwl8k_tx_queues(priv); i++) {
struct mwl8k_tx_queue *txq = priv->txq + i;
int fw_owned = 0;
int drv_owned = 0;
@@ -1452,9 +1522,8 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
if (timeout) {
WARN_ON(priv->pending_tx_pkts);
- if (retry) {
+ if (retry)
wiphy_notice(hw->wiphy, "tx rings drained\n");
- }
break;
}
@@ -1484,6 +1553,41 @@ static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw)
MWL8K_TXD_STATUS_OK_RETRY | \
MWL8K_TXD_STATUS_OK_MORE_RETRY))
+static int mwl8k_tid_queue_mapping(u8 tid)
+{
+ BUG_ON(tid > 7);
+
+ switch (tid) {
+ case 0:
+ case 3:
+ return IEEE80211_AC_BE;
+ break;
+ case 1:
+ case 2:
+ return IEEE80211_AC_BK;
+ break;
+ case 4:
+ case 5:
+ return IEEE80211_AC_VI;
+ break;
+ case 6:
+ case 7:
+ return IEEE80211_AC_VO;
+ break;
+ default:
+ return -1;
+ break;
+ }
+}
+
+/* The firmware will fill in the rate information
+ * for each packet that gets queued in the hardware
+ * and these macros will interpret that info.
+ */
+
+#define RI_FORMAT(a) (a & 0x0001)
+#define RI_RATE_ID_MCS(a) ((a & 0x01f8) >> 3)
+
static int
mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force)
{
@@ -1500,6 +1604,10 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force)
struct sk_buff *skb;
struct ieee80211_tx_info *info;
u32 status;
+ struct ieee80211_sta *sta;
+ struct mwl8k_sta *sta_info = NULL;
+ u16 rate_info;
+ struct ieee80211_hdr *wh;
tx = txq->head;
tx_desc = txq->txd + tx;
@@ -1528,18 +1636,40 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force)
mwl8k_remove_dma_header(skb, tx_desc->qos_control);
+ wh = (struct ieee80211_hdr *) skb->data;
+
/* Mark descriptor as unused */
tx_desc->pkt_phys_addr = 0;
tx_desc->pkt_len = 0;
info = IEEE80211_SKB_CB(skb);
+ if (ieee80211_is_data(wh->frame_control)) {
+ sta = info->control.sta;
+ if (sta) {
+ sta_info = MWL8K_STA(sta);
+ BUG_ON(sta_info == NULL);
+ rate_info = le16_to_cpu(tx_desc->rate_info);
+ /* If rate is < 6.5 Mpbs for an ht station
+ * do not form an ampdu. If the station is a
+ * legacy station (format = 0), do not form an
+ * ampdu
+ */
+ if (RI_RATE_ID_MCS(rate_info) < 1 ||
+ RI_FORMAT(rate_info) == 0) {
+ sta_info->is_ampdu_allowed = false;
+ } else {
+ sta_info->is_ampdu_allowed = true;
+ }
+ }
+ }
+
ieee80211_tx_info_clear_status(info);
/* Rate control is happening in the firmware.
* Ensure no tx rate is being reported.
*/
- info->status.rates[0].idx = -1;
- info->status.rates[0].count = 1;
+ info->status.rates[0].idx = -1;
+ info->status.rates[0].count = 1;
if (MWL8K_TXD_SUCCESS(status))
info->flags |= IEEE80211_TX_STAT_ACK;
@@ -1549,9 +1679,6 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force)
processed++;
}
- if (processed && priv->radio_on && !mutex_is_locked(&priv->fw_mutex))
- ieee80211_wake_queue(hw, index);
-
return processed;
}
@@ -1561,6 +1688,9 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index)
struct mwl8k_priv *priv = hw->priv;
struct mwl8k_tx_queue *txq = priv->txq + index;
+ if (txq->txd == NULL)
+ return;
+
mwl8k_txq_reclaim(hw, index, INT_MAX, 1);
kfree(txq->skb);
@@ -1572,12 +1702,116 @@ static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index)
txq->txd = NULL;
}
+/* caller must hold priv->stream_lock when calling the stream functions */
+static struct mwl8k_ampdu_stream *
+mwl8k_add_stream(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u8 tid)
+{
+ struct mwl8k_ampdu_stream *stream;
+ struct mwl8k_priv *priv = hw->priv;
+ int i;
+
+ for (i = 0; i < priv->num_ampdu_queues; i++) {
+ stream = &priv->ampdu[i];
+ if (stream->state == AMPDU_NO_STREAM) {
+ stream->sta = sta;
+ stream->state = AMPDU_STREAM_NEW;
+ stream->tid = tid;
+ stream->idx = i;
+ stream->txq_idx = MWL8K_TX_WMM_QUEUES + i;
+ wiphy_debug(hw->wiphy, "Added a new stream for %pM %d",
+ sta->addr, tid);
+ return stream;
+ }
+ }
+ return NULL;
+}
+
+static int
+mwl8k_start_stream(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream)
+{
+ int ret;
+
+ /* if the stream has already been started, don't start it again */
+ if (stream->state != AMPDU_STREAM_NEW)
+ return 0;
+ ret = ieee80211_start_tx_ba_session(stream->sta, stream->tid, 0);
+ if (ret)
+ wiphy_debug(hw->wiphy, "Failed to start stream for %pM %d: "
+ "%d\n", stream->sta->addr, stream->tid, ret);
+ else
+ wiphy_debug(hw->wiphy, "Started stream for %pM %d\n",
+ stream->sta->addr, stream->tid);
+ return ret;
+}
+
+static void
+mwl8k_remove_stream(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream)
+{
+ wiphy_debug(hw->wiphy, "Remove stream for %pM %d\n", stream->sta->addr,
+ stream->tid);
+ memset(stream, 0, sizeof(*stream));
+}
+
+static struct mwl8k_ampdu_stream *
+mwl8k_lookup_stream(struct ieee80211_hw *hw, u8 *addr, u8 tid)
+{
+ struct mwl8k_priv *priv = hw->priv;
+ int i;
+
+ for (i = 0 ; i < priv->num_ampdu_queues; i++) {
+ struct mwl8k_ampdu_stream *stream;
+ stream = &priv->ampdu[i];
+ if (stream->state == AMPDU_NO_STREAM)
+ continue;
+ if (!memcmp(stream->sta->addr, addr, ETH_ALEN) &&
+ stream->tid == tid)
+ return stream;
+ }
+ return NULL;
+}
+
+#define MWL8K_AMPDU_PACKET_THRESHOLD 64
+static inline bool mwl8k_ampdu_allowed(struct ieee80211_sta *sta, u8 tid)
+{
+ struct mwl8k_sta *sta_info = MWL8K_STA(sta);
+ struct tx_traffic_info *tx_stats;
+
+ BUG_ON(tid >= MWL8K_MAX_TID);
+ tx_stats = &sta_info->tx_stats[tid];
+
+ return sta_info->is_ampdu_allowed &&
+ tx_stats->pkts > MWL8K_AMPDU_PACKET_THRESHOLD;
+}
+
+static inline void mwl8k_tx_count_packet(struct ieee80211_sta *sta, u8 tid)
+{
+ struct mwl8k_sta *sta_info = MWL8K_STA(sta);
+ struct tx_traffic_info *tx_stats;
+
+ BUG_ON(tid >= MWL8K_MAX_TID);
+ tx_stats = &sta_info->tx_stats[tid];
+
+ if (tx_stats->start_time == 0)
+ tx_stats->start_time = jiffies;
+
+ /* reset the packet count after each second elapses. If the number of
+ * packets ever exceeds the ampdu_min_traffic threshold, we will allow
+ * an ampdu stream to be started.
+ */
+ if (jiffies - tx_stats->start_time > HZ) {
+ tx_stats->pkts = 0;
+ tx_stats->start_time = 0;
+ } else
+ tx_stats->pkts++;
+}
+
static void
mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
{
struct mwl8k_priv *priv = hw->priv;
struct ieee80211_tx_info *tx_info;
struct mwl8k_vif *mwl8k_vif;
+ struct ieee80211_sta *sta;
struct ieee80211_hdr *wh;
struct mwl8k_tx_queue *txq;
struct mwl8k_tx_desc *tx;
@@ -1585,6 +1819,12 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
u32 txstatus;
u8 txdatarate;
u16 qos;
+ int txpriority;
+ u8 tid = 0;
+ struct mwl8k_ampdu_stream *stream = NULL;
+ bool start_ba_session = false;
+ bool mgmtframe = false;
+ struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
wh = (struct ieee80211_hdr *)skb->data;
if (ieee80211_is_data_qos(wh->frame_control))
@@ -1592,14 +1832,18 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
else
qos = 0;
+ if (ieee80211_is_mgmt(wh->frame_control))
+ mgmtframe = true;
+
if (priv->ap_fw)
- mwl8k_encapsulate_tx_frame(skb);
+ mwl8k_encapsulate_tx_frame(priv, skb);
else
- mwl8k_add_dma_header(skb, 0);
+ mwl8k_add_dma_header(priv, skb, 0, 0);
wh = &((struct mwl8k_dma_data *)skb->data)->wh;
tx_info = IEEE80211_SKB_CB(skb);
+ sta = tx_info->control.sta;
mwl8k_vif = MWL8K_VIF(tx_info->control.vif);
if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
@@ -1627,12 +1871,91 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
qos |= MWL8K_QOS_ACK_POLICY_NORMAL;
}
+ /* Queue ADDBA request in the respective data queue. While setting up
+ * the ampdu stream, mac80211 queues further packets for that
+ * particular ra/tid pair. However, packets piled up in the hardware
+ * for that ra/tid pair will still go out. ADDBA request and the
+ * related data packets going out from different queues asynchronously
+ * will cause a shift in the receiver window which might result in
+ * ampdu packets getting dropped at the receiver after the stream has
+ * been setup.
+ */
+ if (unlikely(ieee80211_is_action(wh->frame_control) &&
+ mgmt->u.action.category == WLAN_CATEGORY_BACK &&
+ mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ &&
+ priv->ap_fw)) {
+ u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
+ tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
+ index = mwl8k_tid_queue_mapping(tid);
+ }
+
+ txpriority = index;
+
+ if (ieee80211_is_data_qos(wh->frame_control) &&
+ skb->protocol != cpu_to_be16(ETH_P_PAE) &&
+ sta->ht_cap.ht_supported && priv->ap_fw) {
+ tid = qos & 0xf;
+ mwl8k_tx_count_packet(sta, tid);
+ spin_lock(&priv->stream_lock);
+ stream = mwl8k_lookup_stream(hw, sta->addr, tid);
+ if (stream != NULL) {
+ if (stream->state == AMPDU_STREAM_ACTIVE) {
+ txpriority = stream->txq_idx;
+ index = stream->txq_idx;
+ } else if (stream->state == AMPDU_STREAM_NEW) {
+ /* We get here if the driver sends us packets
+ * after we've initiated a stream, but before
+ * our ampdu_action routine has been called
+ * with IEEE80211_AMPDU_TX_START to get the SSN
+ * for the ADDBA request. So this packet can
+ * go out with no risk of sequence number
+ * mismatch. No special handling is required.
+ */
+ } else {
+ /* Drop packets that would go out after the
+ * ADDBA request was sent but before the ADDBA
+ * response is received. If we don't do this,
+ * the recipient would probably receive it
+ * after the ADDBA request with SSN 0. This
+ * will cause the recipient's BA receive window
+ * to shift, which would cause the subsequent
+ * packets in the BA stream to be discarded.
+ * mac80211 queues our packets for us in this
+ * case, so this is really just a safety check.
+ */
+ wiphy_warn(hw->wiphy,
+ "Cannot send packet while ADDBA "
+ "dialog is underway.\n");
+ spin_unlock(&priv->stream_lock);
+ dev_kfree_skb(skb);
+ return;
+ }
+ } else {
+ /* Defer calling mwl8k_start_stream so that the current
+ * skb can go out before the ADDBA request. This
+ * prevents sequence number mismatch at the recepient
+ * as described above.
+ */
+ if (mwl8k_ampdu_allowed(sta, tid)) {
+ stream = mwl8k_add_stream(hw, sta, tid);
+ if (stream != NULL)
+ start_ba_session = true;
+ }
+ }
+ spin_unlock(&priv->stream_lock);
+ }
+
dma = pci_map_single(priv->pdev, skb->data,
skb->len, PCI_DMA_TODEVICE);
if (pci_dma_mapping_error(priv->pdev, dma)) {
wiphy_debug(hw->wiphy,
"failed to dma map skb, dropping TX frame.\n");
+ if (start_ba_session) {
+ spin_lock(&priv->stream_lock);
+ mwl8k_remove_stream(hw, stream);
+ spin_unlock(&priv->stream_lock);
+ }
dev_kfree_skb(skb);
return;
}
@@ -1641,12 +1964,34 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
txq = priv->txq + index;
+ /* Mgmt frames that go out frequently are probe
+ * responses. Other mgmt frames got out relatively
+ * infrequently. Hence reserve 2 buffers so that
+ * other mgmt frames do not get dropped due to an
+ * already queued probe response in one of the
+ * reserved buffers.
+ */
+
+ if (txq->len >= MWL8K_TX_DESCS - 2) {
+ if (mgmtframe == false ||
+ txq->len == MWL8K_TX_DESCS) {
+ if (start_ba_session) {
+ spin_lock(&priv->stream_lock);
+ mwl8k_remove_stream(hw, stream);
+ spin_unlock(&priv->stream_lock);
+ }
+ spin_unlock_bh(&priv->tx_lock);
+ dev_kfree_skb(skb);
+ return;
+ }
+ }
+
BUG_ON(txq->skb[txq->tail] != NULL);
txq->skb[txq->tail] = skb;
tx = txq->txd + txq->tail;
tx->data_rate = txdatarate;
- tx->tx_priority = index;
+ tx->tx_priority = txpriority;
tx->qos_control = cpu_to_le16(qos);
tx->pkt_phys_addr = cpu_to_le32(dma);
tx->pkt_len = cpu_to_le16(skb->len);
@@ -1655,6 +2000,11 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
tx->peer_id = MWL8K_STA(tx_info->control.sta)->peer_id;
else
tx->peer_id = 0;
+
+ if (priv->ap_fw)
+ tx->timestamp = cpu_to_le32(ioread32(priv->regs +
+ MWL8K_HW_TIMER_REGISTER));
+
wmb();
tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus);
@@ -1665,12 +2015,17 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
if (txq->tail == MWL8K_TX_DESCS)
txq->tail = 0;
- if (txq->head == txq->tail)
- ieee80211_stop_queue(hw, index);
-
mwl8k_tx_start(priv);
spin_unlock_bh(&priv->tx_lock);
+
+ /* Initiate the ampdu session here */
+ if (start_ba_session) {
+ spin_lock(&priv->stream_lock);
+ if (mwl8k_start_stream(hw, stream))
+ mwl8k_remove_stream(hw, stream);
+ spin_unlock(&priv->stream_lock);
+ }
}
@@ -1868,7 +2223,7 @@ struct mwl8k_cmd_get_hw_spec_sta {
__u8 mcs_bitmap[16];
__le32 rx_queue_ptr;
__le32 num_tx_queues;
- __le32 tx_queue_ptrs[MWL8K_TX_QUEUES];
+ __le32 tx_queue_ptrs[MWL8K_TX_WMM_QUEUES];
__le32 caps2;
__le32 num_tx_desc_per_queue;
__le32 total_rxd;
@@ -1974,8 +2329,8 @@ static int mwl8k_cmd_get_hw_spec_sta(struct ieee80211_hw *hw)
memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr));
cmd->ps_cookie = cpu_to_le32(priv->cookie_dma);
cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma);
- cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES);
- for (i = 0; i < MWL8K_TX_QUEUES; i++)
+ cmd->num_tx_queues = cpu_to_le32(mwl8k_tx_queues(priv));
+ for (i = 0; i < mwl8k_tx_queues(priv); i++)
cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].txd_dma);
cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS);
cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS);
@@ -2017,13 +2372,16 @@ struct mwl8k_cmd_get_hw_spec_ap {
__le32 wcbbase2;
__le32 wcbbase3;
__le32 fw_api_version;
+ __le32 caps;
+ __le32 num_of_ampdu_queues;
+ __le32 wcbbase_ampdu[MWL8K_MAX_AMPDU_QUEUES];
} __packed;
static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw)
{
struct mwl8k_priv *priv = hw->priv;
struct mwl8k_cmd_get_hw_spec_ap *cmd;
- int rc;
+ int rc, i;
u32 api_version;
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
@@ -2055,27 +2413,31 @@ static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw)
priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs);
priv->fw_rev = le32_to_cpu(cmd->fw_rev);
priv->hw_rev = cmd->hw_rev;
- mwl8k_setup_2ghz_band(hw);
+ mwl8k_set_caps(hw, le32_to_cpu(cmd->caps));
priv->ap_macids_supported = 0x000000ff;
priv->sta_macids_supported = 0x00000000;
-
- off = le32_to_cpu(cmd->wcbbase0) & 0xffff;
- iowrite32(priv->txq[0].txd_dma, priv->sram + off);
-
+ priv->num_ampdu_queues = le32_to_cpu(cmd->num_of_ampdu_queues);
+ if (priv->num_ampdu_queues > MWL8K_MAX_AMPDU_QUEUES) {
+ wiphy_warn(hw->wiphy, "fw reported %d ampdu queues"
+ " but we only support %d.\n",
+ priv->num_ampdu_queues,
+ MWL8K_MAX_AMPDU_QUEUES);
+ priv->num_ampdu_queues = MWL8K_MAX_AMPDU_QUEUES;
+ }
off = le32_to_cpu(cmd->rxwrptr) & 0xffff;
iowrite32(priv->rxq[0].rxd_dma, priv->sram + off);
off = le32_to_cpu(cmd->rxrdptr) & 0xffff;
iowrite32(priv->rxq[0].rxd_dma, priv->sram + off);
- off = le32_to_cpu(cmd->wcbbase1) & 0xffff;
- iowrite32(priv->txq[1].txd_dma, priv->sram + off);
+ priv->txq_offset[0] = le32_to_cpu(cmd->wcbbase0) & 0xffff;
+ priv->txq_offset[1] = le32_to_cpu(cmd->wcbbase1) & 0xffff;
+ priv->txq_offset[2] = le32_to_cpu(cmd->wcbbase2) & 0xffff;
+ priv->txq_offset[3] = le32_to_cpu(cmd->wcbbase3) & 0xffff;
- off = le32_to_cpu(cmd->wcbbase2) & 0xffff;
- iowrite32(priv->txq[2].txd_dma, priv->sram + off);
-
- off = le32_to_cpu(cmd->wcbbase3) & 0xffff;
- iowrite32(priv->txq[3].txd_dma, priv->sram + off);
+ for (i = 0; i < priv->num_ampdu_queues; i++)
+ priv->txq_offset[i + MWL8K_TX_WMM_QUEUES] =
+ le32_to_cpu(cmd->wcbbase_ampdu[i]) & 0xffff;
}
done:
@@ -2098,12 +2460,20 @@ struct mwl8k_cmd_set_hw_spec {
__le32 caps;
__le32 rx_queue_ptr;
__le32 num_tx_queues;
- __le32 tx_queue_ptrs[MWL8K_TX_QUEUES];
+ __le32 tx_queue_ptrs[MWL8K_MAX_TX_QUEUES];
__le32 flags;
__le32 num_tx_desc_per_queue;
__le32 total_rxd;
} __packed;
+/* If enabled, MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY will cause
+ * packets to expire 500 ms after the timestamp in the tx descriptor. That is,
+ * the packets that are queued for more than 500ms, will be dropped in the
+ * hardware. This helps minimizing the issues caused due to head-of-line
+ * blocking where a slow client can hog the bandwidth and affect traffic to a
+ * faster client.
+ */
+#define MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY 0x00000400
#define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080
#define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP 0x00000020
#define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON 0x00000010
@@ -2124,7 +2494,7 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw)
cmd->ps_cookie = cpu_to_le32(priv->cookie_dma);
cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rxd_dma);
- cmd->num_tx_queues = cpu_to_le32(MWL8K_TX_QUEUES);
+ cmd->num_tx_queues = cpu_to_le32(mwl8k_tx_queues(priv));
/*
* Mac80211 stack has Q0 as highest priority and Q3 as lowest in
@@ -2132,14 +2502,15 @@ static int mwl8k_cmd_set_hw_spec(struct ieee80211_hw *hw)
* in that order. Map Q3 of mac80211 to Q0 of firmware so that the
* priority is interpreted the right way in firmware.
*/
- for (i = 0; i < MWL8K_TX_QUEUES; i++) {
- int j = MWL8K_TX_QUEUES - 1 - i;
+ for (i = 0; i < mwl8k_tx_queues(priv); i++) {
+ int j = mwl8k_tx_queues(priv) - 1 - i;
cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[j].txd_dma);
}
cmd->flags = cpu_to_le32(MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT |
MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP |
- MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON);
+ MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_BEACON |
+ MWL8K_SET_HW_SPEC_FLAG_ENABLE_LIFE_TIME_EXPIRY);
cmd->num_tx_desc_per_queue = cpu_to_le32(MWL8K_TX_DESCS);
cmd->total_rxd = cpu_to_le32(MWL8K_RX_DESCS);
@@ -2356,7 +2727,7 @@ struct mwl8k_cmd_tx_power {
__le16 bw;
__le16 sub_ch;
__le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL];
-} __attribute__((packed));
+} __packed;
static int mwl8k_cmd_tx_power(struct ieee80211_hw *hw,
struct ieee80211_conf *conf,
@@ -3123,6 +3494,65 @@ static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode)
}
/*
+ * CMD_GET_WATCHDOG_BITMAP.
+ */
+struct mwl8k_cmd_get_watchdog_bitmap {
+ struct mwl8k_cmd_pkt header;
+ u8 bitmap;
+} __packed;
+
+static int mwl8k_cmd_get_watchdog_bitmap(struct ieee80211_hw *hw, u8 *bitmap)
+{
+ struct mwl8k_cmd_get_watchdog_bitmap *cmd;
+ int rc;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENOMEM;
+
+ cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_WATCHDOG_BITMAP);
+ cmd->header.length = cpu_to_le16(sizeof(*cmd));
+
+ rc = mwl8k_post_cmd(hw, &cmd->header);
+ if (!rc)
+ *bitmap = cmd->bitmap;
+
+ kfree(cmd);
+
+ return rc;
+}
+
+#define INVALID_BA 0xAA
+static void mwl8k_watchdog_ba_events(struct work_struct *work)
+{
+ int rc;
+ u8 bitmap = 0, stream_index;
+ struct mwl8k_ampdu_stream *streams;
+ struct mwl8k_priv *priv =
+ container_of(work, struct mwl8k_priv, watchdog_ba_handle);
+
+ rc = mwl8k_cmd_get_watchdog_bitmap(priv->hw, &bitmap);
+ if (rc)
+ return;
+
+ if (bitmap == INVALID_BA)
+ return;
+
+ /* the bitmap is the hw queue number. Map it to the ampdu queue. */
+ stream_index = bitmap - MWL8K_TX_WMM_QUEUES;
+
+ BUG_ON(stream_index >= priv->num_ampdu_queues);
+
+ streams = &priv->ampdu[stream_index];
+
+ if (streams->state == AMPDU_STREAM_ACTIVE)
+ ieee80211_stop_tx_ba_session(streams->sta, streams->tid);
+
+ return;
+}
+
+
+/*
* CMD_BSS_START.
*/
struct mwl8k_cmd_bss_start {
@@ -3151,6 +3581,152 @@ static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw,
}
/*
+ * CMD_BASTREAM.
+ */
+
+/*
+ * UPSTREAM is tx direction
+ */
+#define BASTREAM_FLAG_DIRECTION_UPSTREAM 0x00
+#define BASTREAM_FLAG_IMMEDIATE_TYPE 0x01
+
+enum ba_stream_action_type {
+ MWL8K_BA_CREATE,
+ MWL8K_BA_UPDATE,
+ MWL8K_BA_DESTROY,
+ MWL8K_BA_FLUSH,
+ MWL8K_BA_CHECK,
+};
+
+
+struct mwl8k_create_ba_stream {
+ __le32 flags;
+ __le32 idle_thrs;
+ __le32 bar_thrs;
+ __le32 window_size;
+ u8 peer_mac_addr[6];
+ u8 dialog_token;
+ u8 tid;
+ u8 queue_id;
+ u8 param_info;
+ __le32 ba_context;
+ u8 reset_seq_no_flag;
+ __le16 curr_seq_no;
+ u8 sta_src_mac_addr[6];
+} __packed;
+
+struct mwl8k_destroy_ba_stream {
+ __le32 flags;
+ __le32 ba_context;
+} __packed;
+
+struct mwl8k_cmd_bastream {
+ struct mwl8k_cmd_pkt header;
+ __le32 action;
+ union {
+ struct mwl8k_create_ba_stream create_params;
+ struct mwl8k_destroy_ba_stream destroy_params;
+ };
+} __packed;
+
+static int
+mwl8k_check_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream)
+{
+ struct mwl8k_cmd_bastream *cmd;
+ int rc;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENOMEM;
+
+ cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM);
+ cmd->header.length = cpu_to_le16(sizeof(*cmd));
+
+ cmd->action = cpu_to_le32(MWL8K_BA_CHECK);
+
+ cmd->create_params.queue_id = stream->idx;
+ memcpy(&cmd->create_params.peer_mac_addr[0], stream->sta->addr,
+ ETH_ALEN);
+ cmd->create_params.tid = stream->tid;
+
+ cmd->create_params.flags =
+ cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE) |
+ cpu_to_le32(BASTREAM_FLAG_DIRECTION_UPSTREAM);
+
+ rc = mwl8k_post_cmd(hw, &cmd->header);
+
+ kfree(cmd);
+
+ return rc;
+}
+
+static int
+mwl8k_create_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream,
+ u8 buf_size)
+{
+ struct mwl8k_cmd_bastream *cmd;
+ int rc;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENOMEM;
+
+
+ cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM);
+ cmd->header.length = cpu_to_le16(sizeof(*cmd));
+
+ cmd->action = cpu_to_le32(MWL8K_BA_CREATE);
+
+ cmd->create_params.bar_thrs = cpu_to_le32((u32)buf_size);
+ cmd->create_params.window_size = cpu_to_le32((u32)buf_size);
+ cmd->create_params.queue_id = stream->idx;
+
+ memcpy(cmd->create_params.peer_mac_addr, stream->sta->addr, ETH_ALEN);
+ cmd->create_params.tid = stream->tid;
+ cmd->create_params.curr_seq_no = cpu_to_le16(0);
+ cmd->create_params.reset_seq_no_flag = 1;
+
+ cmd->create_params.param_info =
+ (stream->sta->ht_cap.ampdu_factor &
+ IEEE80211_HT_AMPDU_PARM_FACTOR) |
+ ((stream->sta->ht_cap.ampdu_density << 2) &
+ IEEE80211_HT_AMPDU_PARM_DENSITY);
+
+ cmd->create_params.flags =
+ cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE |
+ BASTREAM_FLAG_DIRECTION_UPSTREAM);
+
+ rc = mwl8k_post_cmd(hw, &cmd->header);
+
+ wiphy_debug(hw->wiphy, "Created a BA stream for %pM : tid %d\n",
+ stream->sta->addr, stream->tid);
+ kfree(cmd);
+
+ return rc;
+}
+
+static void mwl8k_destroy_ba(struct ieee80211_hw *hw,
+ struct mwl8k_ampdu_stream *stream)
+{
+ struct mwl8k_cmd_bastream *cmd;
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (cmd == NULL)
+ return;
+
+ cmd->header.code = cpu_to_le16(MWL8K_CMD_BASTREAM);
+ cmd->header.length = cpu_to_le16(sizeof(*cmd));
+ cmd->action = cpu_to_le32(MWL8K_BA_DESTROY);
+
+ cmd->destroy_params.ba_context = cpu_to_le32(stream->idx);
+ mwl8k_post_cmd(hw, &cmd->header);
+
+ wiphy_debug(hw->wiphy, "Deleted BA stream index %d\n", stream->idx);
+
+ kfree(cmd);
+}
+
+/*
* CMD_SET_NEW_STN.
*/
struct mwl8k_cmd_set_new_stn {
@@ -3274,7 +3850,7 @@ struct mwl8k_cmd_update_encryption {
__u8 mac_addr[6];
__u8 encr_type;
-} __attribute__((packed));
+} __packed;
struct mwl8k_cmd_set_key {
struct mwl8k_cmd_pkt header;
@@ -3294,7 +3870,7 @@ struct mwl8k_cmd_set_key {
__le16 tkip_tsc_low;
__le32 tkip_tsc_high;
__u8 mac_addr[6];
-} __attribute__((packed));
+} __packed;
enum {
MWL8K_ENCR_ENABLE,
@@ -3422,7 +3998,7 @@ static int mwl8k_cmd_encryption_set_key(struct ieee80211_hw *hw,
mwl8k_vif->wep_key_conf[idx].enabled = 1;
}
- keymlen = 0;
+ keymlen = key->keylen;
action = MWL8K_ENCR_SET_KEY;
break;
case WLAN_CIPHER_SUITE_TKIP:
@@ -3496,7 +4072,6 @@ static int mwl8k_set_key(struct ieee80211_hw *hw,
addr = sta->addr;
if (cmd_param == SET_KEY) {
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
rc = mwl8k_cmd_encryption_set_key(hw, vif, addr, key);
if (rc)
goto out;
@@ -3671,6 +4246,11 @@ static irqreturn_t mwl8k_interrupt(int irq, void *dev_id)
tasklet_schedule(&priv->poll_rx_task);
}
+ if (status & MWL8K_A2H_INT_BA_WATCHDOG) {
+ status &= ~MWL8K_A2H_INT_BA_WATCHDOG;
+ ieee80211_queue_work(hw, &priv->watchdog_ba_handle);
+ }
+
if (status)
iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
@@ -3699,7 +4279,7 @@ static void mwl8k_tx_poll(unsigned long data)
spin_lock_bh(&priv->tx_lock);
- for (i = 0; i < MWL8K_TX_QUEUES; i++)
+ for (i = 0; i < mwl8k_tx_queues(priv); i++)
limit -= mwl8k_txq_reclaim(hw, i, limit, 0);
if (!priv->pending_tx_pkts && priv->tx_wait != NULL) {
@@ -3774,6 +4354,8 @@ static int mwl8k_start(struct ieee80211_hw *hw)
/* Enable interrupts */
iowrite32(MWL8K_A2H_EVENTS, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
+ iowrite32(MWL8K_A2H_EVENTS,
+ priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
rc = mwl8k_fw_lock(hw);
if (!rc) {
@@ -3829,6 +4411,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw)
/* Stop finalize join worker */
cancel_work_sync(&priv->finalize_join_worker);
+ cancel_work_sync(&priv->watchdog_ba_handle);
if (priv->beacon_skb != NULL)
dev_kfree_skb(priv->beacon_skb);
@@ -3837,7 +4420,7 @@ static void mwl8k_stop(struct ieee80211_hw *hw)
tasklet_disable(&priv->poll_rx_task);
/* Return all skbs to mac80211 */
- for (i = 0; i < MWL8K_TX_QUEUES; i++)
+ for (i = 0; i < mwl8k_tx_queues(priv); i++)
mwl8k_txq_reclaim(hw, i, INT_MAX, 1);
}
@@ -3958,9 +4541,12 @@ static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
conf->power_level = 18;
if (priv->ap_fw) {
- rc = mwl8k_cmd_tx_power(hw, conf, conf->power_level);
- if (rc)
- goto out;
+
+ if (conf->flags & IEEE80211_CONF_CHANGE_POWER) {
+ rc = mwl8k_cmd_tx_power(hw, conf, conf->power_level);
+ if (rc)
+ goto out;
+ }
rc = mwl8k_cmd_rf_antenna(hw, MWL8K_RF_ANTENNA_RX, 0x3);
if (rc)
@@ -3987,7 +4573,7 @@ mwl8k_bss_info_changed_sta(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info, u32 changed)
{
struct mwl8k_priv *priv = hw->priv;
- u32 ap_legacy_rates;
+ u32 ap_legacy_rates = 0;
u8 ap_mcs_rates[16];
int rc;
@@ -4312,6 +4898,8 @@ static int mwl8k_sta_add(struct ieee80211_hw *hw,
ret = mwl8k_cmd_update_stadb_add(hw, vif, sta);
if (ret >= 0) {
MWL8K_STA(sta)->peer_id = ret;
+ if (sta->ht_cap.ht_supported)
+ MWL8K_STA(sta)->is_ampdu_allowed = true;
ret = 0;
}
@@ -4335,14 +4923,14 @@ static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue,
rc = mwl8k_fw_lock(hw);
if (!rc) {
- BUG_ON(queue > MWL8K_TX_QUEUES - 1);
+ BUG_ON(queue > MWL8K_TX_WMM_QUEUES - 1);
memcpy(&priv->wmm_params[queue], params, sizeof(*params));
if (!priv->wmm_enabled)
rc = mwl8k_cmd_set_wmm_mode(hw, 1);
if (!rc) {
- int q = MWL8K_TX_QUEUES - 1 - queue;
+ int q = MWL8K_TX_WMM_QUEUES - 1 - queue;
rc = mwl8k_cmd_set_edca_params(hw, q,
params->cw_min,
params->cw_max,
@@ -4378,21 +4966,118 @@ static int mwl8k_get_survey(struct ieee80211_hw *hw, int idx,
return 0;
}
+#define MAX_AMPDU_ATTEMPTS 5
+
static int
mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
enum ieee80211_ampdu_mlme_action action,
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
u8 buf_size)
{
+
+ int i, rc = 0;
+ struct mwl8k_priv *priv = hw->priv;
+ struct mwl8k_ampdu_stream *stream;
+ u8 *addr = sta->addr;
+
+ if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
+ return -ENOTSUPP;
+
+ spin_lock(&priv->stream_lock);
+ stream = mwl8k_lookup_stream(hw, addr, tid);
+
switch (action) {
case IEEE80211_AMPDU_RX_START:
case IEEE80211_AMPDU_RX_STOP:
- if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
- return -ENOTSUPP;
- return 0;
+ break;
+ case IEEE80211_AMPDU_TX_START:
+ /* By the time we get here the hw queues may contain outgoing
+ * packets for this RA/TID that are not part of this BA
+ * session. The hw will assign sequence numbers to these
+ * packets as they go out. So if we query the hw for its next
+ * sequence number and use that for the SSN here, it may end up
+ * being wrong, which will lead to sequence number mismatch at
+ * the recipient. To avoid this, we reset the sequence number
+ * to O for the first MPDU in this BA stream.
+ */
+ *ssn = 0;
+ if (stream == NULL) {
+ /* This means that somebody outside this driver called
+ * ieee80211_start_tx_ba_session. This is unexpected
+ * because we do our own rate control. Just warn and
+ * move on.
+ */
+ wiphy_warn(hw->wiphy, "Unexpected call to %s. "
+ "Proceeding anyway.\n", __func__);
+ stream = mwl8k_add_stream(hw, sta, tid);
+ }
+ if (stream == NULL) {
+ wiphy_debug(hw->wiphy, "no free AMPDU streams\n");
+ rc = -EBUSY;
+ break;
+ }
+ stream->state = AMPDU_STREAM_IN_PROGRESS;
+
+ /* Release the lock before we do the time consuming stuff */
+ spin_unlock(&priv->stream_lock);
+ for (i = 0; i < MAX_AMPDU_ATTEMPTS; i++) {
+ rc = mwl8k_check_ba(hw, stream);
+
+ if (!rc)
+ break;
+ /*
+ * HW queues take time to be flushed, give them
+ * sufficient time
+ */
+
+ msleep(1000);
+ }
+ spin_lock(&priv->stream_lock);
+ if (rc) {
+ wiphy_err(hw->wiphy, "Stream for tid %d busy after %d"
+ " attempts\n", tid, MAX_AMPDU_ATTEMPTS);
+ mwl8k_remove_stream(hw, stream);
+ rc = -EBUSY;
+ break;
+ }
+ ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid);
+ break;
+ case IEEE80211_AMPDU_TX_STOP:
+ if (stream == NULL)
+ break;
+ if (stream->state == AMPDU_STREAM_ACTIVE) {
+ spin_unlock(&priv->stream_lock);
+ mwl8k_destroy_ba(hw, stream);
+ spin_lock(&priv->stream_lock);
+ }
+ mwl8k_remove_stream(hw, stream);
+ ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid);
+ break;
+ case IEEE80211_AMPDU_TX_OPERATIONAL:
+ BUG_ON(stream == NULL);
+ BUG_ON(stream->state != AMPDU_STREAM_IN_PROGRESS);
+ spin_unlock(&priv->stream_lock);
+ rc = mwl8k_create_ba(hw, stream, buf_size);
+ spin_lock(&priv->stream_lock);
+ if (!rc)
+ stream->state = AMPDU_STREAM_ACTIVE;
+ else {
+ spin_unlock(&priv->stream_lock);
+ mwl8k_destroy_ba(hw, stream);
+ spin_lock(&priv->stream_lock);
+ wiphy_debug(hw->wiphy,
+ "Failed adding stream for sta %pM tid %d\n",
+ addr, tid);
+ mwl8k_remove_stream(hw, stream);
+ }
+ break;
+
default:
- return -ENOTSUPP;
+ rc = -ENOTSUPP;
}
+
+ spin_unlock(&priv->stream_lock);
+ return rc;
}
static const struct ieee80211_ops mwl8k_ops = {
@@ -4441,7 +5126,7 @@ enum {
MWL8366,
};
-#define MWL8K_8366_AP_FW_API 1
+#define MWL8K_8366_AP_FW_API 2
#define _MWL8K_8366_AP_FW(api) "mwl8k/fmimage_8366_ap-" #api ".fw"
#define MWL8K_8366_AP_FW(api) _MWL8K_8366_AP_FW(api)
@@ -4607,6 +5292,23 @@ static int mwl8k_init_firmware(struct ieee80211_hw *hw, char *fw_image,
return rc;
}
+static int mwl8k_init_txqs(struct ieee80211_hw *hw)
+{
+ struct mwl8k_priv *priv = hw->priv;
+ int rc = 0;
+ int i;
+
+ for (i = 0; i < mwl8k_tx_queues(priv); i++) {
+ rc = mwl8k_txq_init(hw, i);
+ if (rc)
+ break;
+ if (priv->ap_fw)
+ iowrite32(priv->txq[i].txd_dma,
+ priv->sram + priv->txq_offset[i]);
+ }
+ return rc;
+}
+
/* initialize hw after successfully loading a firmware image */
static int mwl8k_probe_hw(struct ieee80211_hw *hw)
{
@@ -4634,17 +5336,26 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw)
goto err_stop_firmware;
rxq_refill(hw, 0, INT_MAX);
- for (i = 0; i < MWL8K_TX_QUEUES; i++) {
- rc = mwl8k_txq_init(hw, i);
+ /* For the sta firmware, we need to know the dma addresses of tx queues
+ * before sending MWL8K_CMD_GET_HW_SPEC. So we must initialize them
+ * prior to issuing this command. But for the AP case, we learn the
+ * total number of queues from the result CMD_GET_HW_SPEC, so for this
+ * case we must initialize the tx queues after.
+ */
+ priv->num_ampdu_queues = 0;
+ if (!priv->ap_fw) {
+ rc = mwl8k_init_txqs(hw);
if (rc)
goto err_free_queues;
}
iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
- iowrite32(MWL8K_A2H_INT_TX_DONE | MWL8K_A2H_INT_RX_READY,
+ iowrite32(MWL8K_A2H_INT_TX_DONE|MWL8K_A2H_INT_RX_READY|
+ MWL8K_A2H_INT_BA_WATCHDOG,
priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL);
- iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
+ iowrite32(MWL8K_A2H_INT_OPC_DONE,
+ priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
rc = request_irq(priv->pdev->irq, mwl8k_interrupt,
IRQF_SHARED, MWL8K_NAME, hw);
@@ -4653,6 +5364,8 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw)
goto err_free_queues;
}
+ memset(priv->ampdu, 0, sizeof(priv->ampdu));
+
/*
* Temporarily enable interrupts. Initial firmware host
* commands use interrupts and avoid polling. Disable
@@ -4664,6 +5377,8 @@ static int mwl8k_probe_hw(struct ieee80211_hw *hw)
if (priv->ap_fw) {
rc = mwl8k_cmd_get_hw_spec_ap(hw);
if (!rc)
+ rc = mwl8k_init_txqs(hw);
+ if (!rc)
rc = mwl8k_cmd_set_hw_spec(hw);
} else {
rc = mwl8k_cmd_get_hw_spec_sta(hw);
@@ -4705,7 +5420,7 @@ err_free_irq:
free_irq(priv->pdev->irq, hw);
err_free_queues:
- for (i = 0; i < MWL8K_TX_QUEUES; i++)
+ for (i = 0; i < mwl8k_tx_queues(priv); i++)
mwl8k_txq_deinit(hw, i);
mwl8k_rxq_deinit(hw, 0);
@@ -4727,7 +5442,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image)
mwl8k_stop(hw);
mwl8k_rxq_deinit(hw, 0);
- for (i = 0; i < MWL8K_TX_QUEUES; i++)
+ for (i = 0; i < mwl8k_tx_queues(priv); i++)
mwl8k_txq_deinit(hw, i);
rc = mwl8k_init_firmware(hw, fw_image, false);
@@ -4746,7 +5461,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image)
if (rc)
goto fail;
- for (i = 0; i < MWL8K_TX_QUEUES; i++) {
+ for (i = 0; i < MWL8K_TX_WMM_QUEUES; i++) {
rc = mwl8k_conf_tx(hw, i, &priv->wmm_params[i]);
if (rc)
goto fail;
@@ -4778,9 +5493,11 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv)
hw->extra_tx_headroom =
sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts);
+ hw->extra_tx_headroom -= priv->ap_fw ? REDUCED_TX_HEADROOM : 0;
+
hw->channel_change_time = 10;
- hw->queues = MWL8K_TX_QUEUES;
+ hw->queues = MWL8K_TX_WMM_QUEUES;
/* Set rssi values to dBm */
hw->flags |= IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_HAS_RATE_CONTROL;
@@ -4796,6 +5513,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv)
/* Finalize join worker */
INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker);
+ /* Handle watchdog ba events */
+ INIT_WORK(&priv->watchdog_ba_handle, mwl8k_watchdog_ba_events);
/* TX reclaim and RX tasklets. */
tasklet_init(&priv->poll_tx_task, mwl8k_tx_poll, (unsigned long)hw);
@@ -4815,6 +5534,8 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv)
spin_lock_init(&priv->tx_lock);
+ spin_lock_init(&priv->stream_lock);
+
priv->tx_wait = NULL;
rc = mwl8k_probe_hw(hw);
@@ -4836,7 +5557,7 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv)
return 0;
err_unprobe_hw:
- for (i = 0; i < MWL8K_TX_QUEUES; i++)
+ for (i = 0; i < mwl8k_tx_queues(priv); i++)
mwl8k_txq_deinit(hw, i);
mwl8k_rxq_deinit(hw, 0);
@@ -4995,10 +5716,10 @@ static void __devexit mwl8k_remove(struct pci_dev *pdev)
mwl8k_hw_reset(priv);
/* Return all skbs to mac80211 */
- for (i = 0; i < MWL8K_TX_QUEUES; i++)
+ for (i = 0; i < mwl8k_tx_queues(priv); i++)
mwl8k_txq_reclaim(hw, i, INT_MAX, 1);
- for (i = 0; i < MWL8K_TX_QUEUES; i++)
+ for (i = 0; i < mwl8k_tx_queues(priv); i++)
mwl8k_txq_deinit(hw, i);
mwl8k_rxq_deinit(hw, 0);
diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c
index 32954c4b243a..88e3c0ebcaad 100644
--- a/drivers/net/wireless/orinoco/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco/orinoco_cs.c
@@ -237,7 +237,7 @@ static int orinoco_cs_resume(struct pcmcia_device *link)
/* Module initialization */
/********************************************************************/
-static struct pcmcia_device_id orinoco_cs_ids[] = {
+static const struct pcmcia_device_id orinoco_cs_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), /* 3Com AirConnect PCI 777A */
PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), /* Lucent Orinoco and old Intersil */
PCMCIA_DEVICE_MANF_CARD(0x016b, 0x0001), /* Ericsson WLAN Card C11 */
diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c
index db34c282e59b..81f3673d31d4 100644
--- a/drivers/net/wireless/orinoco/spectrum_cs.c
+++ b/drivers/net/wireless/orinoco/spectrum_cs.c
@@ -301,7 +301,7 @@ spectrum_cs_resume(struct pcmcia_device *link)
/* Module initialization */
/********************************************************************/
-static struct pcmcia_device_id spectrum_cs_ids[] = {
+static const struct pcmcia_device_id spectrum_cs_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4137 */
PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */
PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless LAN PC Card", 0x816cc815, 0x6fbf459a), /* 2011B, not 2011 */
diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c
index 13d750da9301..54cc0bba66b9 100644
--- a/drivers/net/wireless/p54/eeprom.c
+++ b/drivers/net/wireless/p54/eeprom.c
@@ -491,7 +491,7 @@ static int p54_parse_rssical(struct ieee80211_hw *dev,
struct pda_rssi_cal_entry *cal = (void *) &data[offset];
for (i = 0; i < entries; i++) {
- u16 freq;
+ u16 freq = 0;
switch (i) {
case IEEE80211_BAND_2GHZ:
freq = 2437;
diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c
index 2fab7d20ffc2..b6a061cbbdec 100644
--- a/drivers/net/wireless/p54/fwio.c
+++ b/drivers/net/wireless/p54/fwio.c
@@ -727,3 +727,34 @@ int p54_fetch_statistics(struct p54_common *priv)
p54_tx(priv, skb);
return 0;
}
+
+int p54_set_groupfilter(struct p54_common *priv)
+{
+ struct p54_group_address_table *grp;
+ struct sk_buff *skb;
+ bool on = false;
+
+ skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*grp),
+ P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+ grp = (struct p54_group_address_table *)skb_put(skb, sizeof(*grp));
+
+ on = !(priv->filter_flags & FIF_ALLMULTI) &&
+ (priv->mc_maclist_num > 0 &&
+ priv->mc_maclist_num <= MC_FILTER_ADDRESS_NUM);
+
+ if (on) {
+ grp->filter_enable = cpu_to_le16(1);
+ grp->num_address = cpu_to_le16(priv->mc_maclist_num);
+ memcpy(grp->mac_list, priv->mc_maclist, sizeof(grp->mac_list));
+ } else {
+ grp->filter_enable = cpu_to_le16(0);
+ grp->num_address = cpu_to_le16(0);
+ memset(grp->mac_list, 0, sizeof(grp->mac_list));
+ }
+
+ p54_tx(priv, skb);
+ return 0;
+}
diff --git a/drivers/net/wireless/p54/lmac.h b/drivers/net/wireless/p54/lmac.h
index eb581abc1079..3d8d622bec55 100644
--- a/drivers/net/wireless/p54/lmac.h
+++ b/drivers/net/wireless/p54/lmac.h
@@ -540,6 +540,7 @@ int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set);
int p54_setup_mac(struct p54_common *priv);
int p54_set_ps(struct p54_common *priv);
int p54_fetch_statistics(struct p54_common *priv);
+int p54_set_groupfilter(struct p54_common *priv);
/* e/v DCF setup */
int p54_set_edcf(struct p54_common *priv);
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
index a946991989c6..a5a6d9e647bb 100644
--- a/drivers/net/wireless/p54/main.c
+++ b/drivers/net/wireless/p54/main.c
@@ -308,6 +308,31 @@ out:
return ret;
}
+static u64 p54_prepare_multicast(struct ieee80211_hw *dev,
+ struct netdev_hw_addr_list *mc_list)
+{
+ struct p54_common *priv = dev->priv;
+ struct netdev_hw_addr *ha;
+ int i;
+
+ BUILD_BUG_ON(ARRAY_SIZE(priv->mc_maclist) !=
+ ARRAY_SIZE(((struct p54_group_address_table *)NULL)->mac_list));
+ /*
+ * The first entry is reserved for the global broadcast MAC.
+ * Otherwise the firmware will drop it and ARP will no longer work.
+ */
+ i = 1;
+ priv->mc_maclist_num = netdev_hw_addr_list_count(mc_list) + i;
+ netdev_hw_addr_list_for_each(ha, mc_list) {
+ memcpy(&priv->mc_maclist[i], ha->addr, ETH_ALEN);
+ i++;
+ if (i >= ARRAY_SIZE(priv->mc_maclist))
+ break;
+ }
+
+ return 1; /* update */
+}
+
static void p54_configure_filter(struct ieee80211_hw *dev,
unsigned int changed_flags,
unsigned int *total_flags,
@@ -316,12 +341,16 @@ static void p54_configure_filter(struct ieee80211_hw *dev,
struct p54_common *priv = dev->priv;
*total_flags &= FIF_PROMISC_IN_BSS |
+ FIF_ALLMULTI |
FIF_OTHER_BSS;
priv->filter_flags = *total_flags;
if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS))
p54_setup_mac(priv);
+
+ if (changed_flags & FIF_ALLMULTI || multicast)
+ p54_set_groupfilter(priv);
}
static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue,
@@ -591,6 +620,7 @@ static const struct ieee80211_ops p54_ops = {
.config = p54_config,
.flush = p54_flush,
.bss_info_changed = p54_bss_info_changed,
+ .prepare_multicast = p54_prepare_multicast,
.configure_filter = p54_configure_filter,
.conf_tx = p54_conf_tx,
.get_stats = p54_get_stats,
@@ -660,6 +690,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
init_completion(&priv->beacon_comp);
INIT_DELAYED_WORK(&priv->work, p54_work);
+ memset(&priv->mc_maclist[0], ~0, ETH_ALEN);
return dev;
}
EXPORT_SYMBOL_GPL(p54_init_common);
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
index 50730fc23fe5..799d05e12595 100644
--- a/drivers/net/wireless/p54/p54.h
+++ b/drivers/net/wireless/p54/p54.h
@@ -211,8 +211,10 @@ struct p54_common {
/* BBP/MAC state */
u8 mac_addr[ETH_ALEN];
u8 bssid[ETH_ALEN];
+ u8 mc_maclist[4][ETH_ALEN];
u16 wakeup_timer;
unsigned int filter_flags;
+ int mc_maclist_num;
int mode;
u32 tsf_low32, tsf_high32;
u32 basic_rate_mask;
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index 0494d7b102d4..1b753173680f 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -331,10 +331,9 @@ static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
struct p54p_ring_control *ring_control = priv->ring_control;
struct p54p_desc *desc;
dma_addr_t mapping;
- u32 device_idx, idx, i;
+ u32 idx, i;
spin_lock_irqsave(&priv->lock, flags);
- device_idx = le32_to_cpu(ring_control->device_idx[1]);
idx = le32_to_cpu(ring_control->host_idx[1]);
i = idx % ARRAY_SIZE(ring_control->tx_data);
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index e18358725b69..a8f3bc740dfa 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -82,6 +82,7 @@ static struct usb_device_id p54u_table[] __devinitdata = {
{USB_DEVICE(0x06b9, 0x0121)}, /* Thomson SpeedTouch 121g */
{USB_DEVICE(0x0707, 0xee13)}, /* SMC 2862W-G version 2 */
{USB_DEVICE(0x083a, 0x4521)}, /* Siemens Gigaset USB Adapter 54 version 2 */
+ {USB_DEVICE(0x083a, 0xc501)}, /* Zoom Wireless-G 4410 */
{USB_DEVICE(0x083a, 0xf503)}, /* Accton FD7050E ver 1010ec */
{USB_DEVICE(0x0846, 0x4240)}, /* Netgear WG111 (v2) */
{USB_DEVICE(0x0915, 0x2000)}, /* Cohiba Proto board */
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 0764d1a30d13..2a06ebcd67c5 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -2781,7 +2781,7 @@ static const struct file_operations int_proc_fops = {
};
#endif
-static struct pcmcia_device_id ray_ids[] = {
+static const struct pcmcia_device_id ray_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x01a6, 0x0000),
PCMCIA_DEVICE_NULL,
};
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 518542b4bf9e..29f938930667 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -2830,7 +2830,8 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
req_ie_len, resp_ie,
resp_ie_len, 0, GFP_KERNEL);
else
- cfg80211_roamed(usbdev->net, bssid, req_ie, req_ie_len,
+ cfg80211_roamed(usbdev->net, NULL, bssid,
+ req_ie, req_ie_len,
resp_ie, resp_ie_len, GFP_KERNEL);
} else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC)
cfg80211_ibss_joined(usbdev->net, bssid, GFP_KERNEL);
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index f630552427b7..9def1e5369a1 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -59,7 +59,6 @@ config RT2800PCI
select RT2800_LIB
select RT2X00_LIB_PCI if PCI
select RT2X00_LIB_SOC if RALINK_RT288X || RALINK_RT305X
- select RT2X00_LIB_HT
select RT2X00_LIB_FIRMWARE
select RT2X00_LIB_CRYPTO
select CRC_CCITT
@@ -74,17 +73,13 @@ config RT2800PCI
if RT2800PCI
config RT2800PCI_RT33XX
- bool "rt2800pci - Include support for rt33xx devices (EXPERIMENTAL)"
- depends on EXPERIMENTAL
- default n
+ bool "rt2800pci - Include support for rt33xx devices"
+ default y
---help---
This adds support for rt33xx wireless chipset family to the
rt2800pci driver.
Supported chips: RT3390
- Support for these devices is non-functional at the moment and is
- intended for testers and developers.
-
config RT2800PCI_RT35XX
bool "rt2800pci - Include support for rt35xx devices (EXPERIMENTAL)"
depends on EXPERIMENTAL
@@ -98,17 +93,14 @@ config RT2800PCI_RT35XX
intended for testers and developers.
config RT2800PCI_RT53XX
- bool "rt2800-pci - Include support for rt53xx devices (EXPERIMENTAL)"
+ bool "rt2800pci - Include support for rt53xx devices (EXPERIMENTAL)"
depends on EXPERIMENTAL
- default n
+ default y
---help---
This adds support for rt53xx wireless chipset family to the
rt2800pci driver.
Supported chips: RT5390
- Support for these devices is non-functional at the moment and is
- intended for testers and developers.
-
endif
config RT2500USB
@@ -140,7 +132,6 @@ config RT2800USB
depends on USB
select RT2800_LIB
select RT2X00_LIB_USB
- select RT2X00_LIB_HT
select RT2X00_LIB_FIRMWARE
select RT2X00_LIB_CRYPTO
select CRC_CCITT
@@ -153,17 +144,13 @@ config RT2800USB
if RT2800USB
config RT2800USB_RT33XX
- bool "rt2800usb - Include support for rt33xx devices (EXPERIMENTAL)"
- depends on EXPERIMENTAL
- default n
+ bool "rt2800usb - Include support for rt33xx devices"
+ default y
---help---
This adds support for rt33xx wireless chipset family to the
rt2800usb driver.
Supported chips: RT3370
- Support for these devices is non-functional at the moment and is
- intended for testers and developers.
-
config RT2800USB_RT35XX
bool "rt2800usb - Include support for rt35xx devices (EXPERIMENTAL)"
depends on EXPERIMENTAL
@@ -176,6 +163,15 @@ config RT2800USB_RT35XX
Support for these devices is non-functional at the moment and is
intended for testers and developers.
+config RT2800USB_RT53XX
+ bool "rt2800usb - Include support for rt53xx devices (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ default y
+ ---help---
+ This adds support for rt53xx wireless chipset family to the
+ rt2800pci driver.
+ Supported chips: RT5370
+
config RT2800USB_UNKNOWN
bool "rt2800usb - Include support for unknown (USB) devices"
default n
@@ -207,9 +203,6 @@ config RT2X00_LIB_USB
config RT2X00_LIB
tristate
-config RT2X00_LIB_HT
- boolean
-
config RT2X00_LIB_FIRMWARE
boolean
select FW_LOADER
diff --git a/drivers/net/wireless/rt2x00/Makefile b/drivers/net/wireless/rt2x00/Makefile
index 971339858297..349d5b8284a4 100644
--- a/drivers/net/wireless/rt2x00/Makefile
+++ b/drivers/net/wireless/rt2x00/Makefile
@@ -7,7 +7,6 @@ rt2x00lib-$(CONFIG_RT2X00_LIB_DEBUGFS) += rt2x00debug.o
rt2x00lib-$(CONFIG_RT2X00_LIB_CRYPTO) += rt2x00crypto.o
rt2x00lib-$(CONFIG_RT2X00_LIB_FIRMWARE) += rt2x00firmware.o
rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o
-rt2x00lib-$(CONFIG_RT2X00_LIB_HT) += rt2x00ht.o
obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o
obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index 329f3283697b..937f9e8bf05f 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -1314,8 +1314,8 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev,
}
}
-static void rt2400pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
- struct rt2x00_field32 irq_field)
+static inline void rt2400pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00_field32 irq_field)
{
u32 reg;
@@ -1368,8 +1368,10 @@ static void rt2400pci_tbtt_tasklet(unsigned long data)
static void rt2400pci_rxdone_tasklet(unsigned long data)
{
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
- rt2x00pci_rxdone(rt2x00dev);
- rt2400pci_enable_interrupt(rt2x00dev, CSR8_RXDONE);
+ if (rt2x00pci_rxdone(rt2x00dev))
+ tasklet_schedule(&rt2x00dev->rxdone_tasklet);
+ else
+ rt2400pci_enable_interrupt(rt2x00dev, CSR8_RXDONE);
}
static irqreturn_t rt2400pci_interrupt(int irq, void *dev_instance)
@@ -1534,13 +1536,13 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
* Detect if this device has an hardware controlled radio.
*/
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
- __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags);
/*
* Check if the BBP tuning should be enabled.
*/
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RX_AGCVGC_TUNING))
- __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags);
return 0;
}
@@ -1638,9 +1640,9 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* This device requires the atim queue and DMA-mapped skbs.
*/
- __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
- __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
- __set_bit(DRIVER_REQUIRE_SW_SEQNO, &rt2x00dev->flags);
+ __set_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags);
+ __set_bit(REQUIRE_DMA, &rt2x00dev->cap_flags);
+ __set_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags);
/*
* Set the rssi offset.
@@ -1718,6 +1720,9 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = {
.tx_last_beacon = rt2400pci_tx_last_beacon,
.rfkill_poll = rt2x00mac_rfkill_poll,
.flush = rt2x00mac_flush,
+ .set_antenna = rt2x00mac_set_antenna,
+ .get_antenna = rt2x00mac_get_antenna,
+ .get_ringparam = rt2x00mac_get_ringparam,
};
static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
@@ -1738,6 +1743,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
.start_queue = rt2400pci_start_queue,
.kick_queue = rt2400pci_kick_queue,
.stop_queue = rt2400pci_stop_queue,
+ .flush_queue = rt2x00pci_flush_queue,
.write_tx_desc = rt2400pci_write_tx_desc,
.write_beacon = rt2400pci_write_beacon,
.fill_rxdone = rt2400pci_fill_rxdone,
@@ -1799,10 +1805,11 @@ static const struct rt2x00_ops rt2400pci_ops = {
* RT2400pci module information.
*/
static DEFINE_PCI_DEVICE_TABLE(rt2400pci_device_table) = {
- { PCI_DEVICE(0x1814, 0x0101), PCI_DEVICE_DATA(&rt2400pci_ops) },
+ { PCI_DEVICE(0x1814, 0x0101) },
{ 0, }
};
+
MODULE_AUTHOR(DRV_PROJECT);
MODULE_VERSION(DRV_VERSION);
MODULE_DESCRIPTION("Ralink RT2400 PCI & PCMCIA Wireless LAN driver.");
@@ -1810,10 +1817,16 @@ MODULE_SUPPORTED_DEVICE("Ralink RT2460 PCI & PCMCIA chipset based cards");
MODULE_DEVICE_TABLE(pci, rt2400pci_device_table);
MODULE_LICENSE("GPL");
+static int rt2400pci_probe(struct pci_dev *pci_dev,
+ const struct pci_device_id *id)
+{
+ return rt2x00pci_probe(pci_dev, &rt2400pci_ops);
+}
+
static struct pci_driver rt2400pci_driver = {
.name = KBUILD_MODNAME,
.id_table = rt2400pci_device_table,
- .probe = rt2x00pci_probe,
+ .probe = rt2400pci_probe,
.remove = __devexit_p(rt2x00pci_remove),
.suspend = rt2x00pci_suspend,
.resume = rt2x00pci_resume,
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 58277878889e..d27d7b8ba3b6 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -1446,8 +1446,8 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev,
}
}
-static void rt2500pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
- struct rt2x00_field32 irq_field)
+static inline void rt2500pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00_field32 irq_field)
{
u32 reg;
@@ -1500,8 +1500,10 @@ static void rt2500pci_tbtt_tasklet(unsigned long data)
static void rt2500pci_rxdone_tasklet(unsigned long data)
{
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
- rt2x00pci_rxdone(rt2x00dev);
- rt2500pci_enable_interrupt(rt2x00dev, CSR8_RXDONE);
+ if (rt2x00pci_rxdone(rt2x00dev))
+ tasklet_schedule(&rt2x00dev->rxdone_tasklet);
+ else
+ rt2500pci_enable_interrupt(rt2x00dev, CSR8_RXDONE);
}
static irqreturn_t rt2500pci_interrupt(int irq, void *dev_instance)
@@ -1685,14 +1687,14 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
* Detect if this device has an hardware controlled radio.
*/
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
- __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags);
/*
* 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(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags);
/*
* Read the RSSI <-> dBm offset information.
@@ -1956,9 +1958,9 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* This device requires the atim queue and DMA-mapped skbs.
*/
- __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
- __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
- __set_bit(DRIVER_REQUIRE_SW_SEQNO, &rt2x00dev->flags);
+ __set_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags);
+ __set_bit(REQUIRE_DMA, &rt2x00dev->cap_flags);
+ __set_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags);
/*
* Set the rssi offset.
@@ -2011,6 +2013,9 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = {
.tx_last_beacon = rt2500pci_tx_last_beacon,
.rfkill_poll = rt2x00mac_rfkill_poll,
.flush = rt2x00mac_flush,
+ .set_antenna = rt2x00mac_set_antenna,
+ .get_antenna = rt2x00mac_get_antenna,
+ .get_ringparam = rt2x00mac_get_ringparam,
};
static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
@@ -2031,6 +2036,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
.start_queue = rt2500pci_start_queue,
.kick_queue = rt2500pci_kick_queue,
.stop_queue = rt2500pci_stop_queue,
+ .flush_queue = rt2x00pci_flush_queue,
.write_tx_desc = rt2500pci_write_tx_desc,
.write_beacon = rt2500pci_write_beacon,
.fill_rxdone = rt2500pci_fill_rxdone,
@@ -2092,7 +2098,7 @@ static const struct rt2x00_ops rt2500pci_ops = {
* RT2500pci module information.
*/
static DEFINE_PCI_DEVICE_TABLE(rt2500pci_device_table) = {
- { PCI_DEVICE(0x1814, 0x0201), PCI_DEVICE_DATA(&rt2500pci_ops) },
+ { PCI_DEVICE(0x1814, 0x0201) },
{ 0, }
};
@@ -2103,10 +2109,16 @@ MODULE_SUPPORTED_DEVICE("Ralink RT2560 PCI & PCMCIA chipset based cards");
MODULE_DEVICE_TABLE(pci, rt2500pci_device_table);
MODULE_LICENSE("GPL");
+static int rt2500pci_probe(struct pci_dev *pci_dev,
+ const struct pci_device_id *id)
+{
+ return rt2x00pci_probe(pci_dev, &rt2500pci_ops);
+}
+
static struct pci_driver rt2500pci_driver = {
.name = KBUILD_MODNAME,
.id_table = rt2500pci_device_table,
- .probe = rt2x00pci_probe,
+ .probe = rt2500pci_probe,
.remove = __devexit_p(rt2x00pci_remove),
.suspend = rt2x00pci_suspend,
.resume = rt2x00pci_resume,
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 979fe6596a2d..15237c275486 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1519,7 +1519,7 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
* Detect if this device has an hardware controlled radio.
*/
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
- __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags);
/*
* Read the RSSI <-> dBm offset information.
@@ -1790,14 +1790,14 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* This device requires the atim queue
*/
- __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
- __set_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags);
+ __set_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags);
+ __set_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags);
if (!modparam_nohwcrypt) {
- __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
- __set_bit(DRIVER_REQUIRE_COPY_IV, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags);
+ __set_bit(REQUIRE_COPY_IV, &rt2x00dev->cap_flags);
}
- __set_bit(DRIVER_SUPPORT_WATCHDOG, &rt2x00dev->flags);
- __set_bit(DRIVER_REQUIRE_SW_SEQNO, &rt2x00dev->flags);
+ __set_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags);
+ __set_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags);
/*
* Set the rssi offset.
@@ -1824,6 +1824,9 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = {
.conf_tx = rt2x00mac_conf_tx,
.rfkill_poll = rt2x00mac_rfkill_poll,
.flush = rt2x00mac_flush,
+ .set_antenna = rt2x00mac_set_antenna,
+ .get_antenna = rt2x00mac_get_antenna,
+ .get_ringparam = rt2x00mac_get_ringparam,
};
static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
@@ -1905,58 +1908,54 @@ static const struct rt2x00_ops rt2500usb_ops = {
*/
static struct usb_device_id rt2500usb_device_table[] = {
/* ASUS */
- { USB_DEVICE(0x0b05, 0x1706), USB_DEVICE_DATA(&rt2500usb_ops) },
- { USB_DEVICE(0x0b05, 0x1707), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x0b05, 0x1706) },
+ { USB_DEVICE(0x0b05, 0x1707) },
/* Belkin */
- { USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt2500usb_ops) },
- { USB_DEVICE(0x050d, 0x7051), USB_DEVICE_DATA(&rt2500usb_ops) },
- { USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x050d, 0x7050) },
+ { USB_DEVICE(0x050d, 0x7051) },
/* Cisco Systems */
- { USB_DEVICE(0x13b1, 0x000d), USB_DEVICE_DATA(&rt2500usb_ops) },
- { USB_DEVICE(0x13b1, 0x0011), USB_DEVICE_DATA(&rt2500usb_ops) },
- { USB_DEVICE(0x13b1, 0x001a), USB_DEVICE_DATA(&rt2500usb_ops) },
- /* CNet */
- { USB_DEVICE(0x1371, 0x9022), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x13b1, 0x000d) },
+ { USB_DEVICE(0x13b1, 0x0011) },
+ { USB_DEVICE(0x13b1, 0x001a) },
/* Conceptronic */
- { USB_DEVICE(0x14b2, 0x3c02), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x14b2, 0x3c02) },
/* D-LINK */
- { USB_DEVICE(0x2001, 0x3c00), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x2001, 0x3c00) },
/* Gigabyte */
- { USB_DEVICE(0x1044, 0x8001), USB_DEVICE_DATA(&rt2500usb_ops) },
- { USB_DEVICE(0x1044, 0x8007), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x1044, 0x8001) },
+ { USB_DEVICE(0x1044, 0x8007) },
/* Hercules */
- { USB_DEVICE(0x06f8, 0xe000), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x06f8, 0xe000) },
/* Melco */
- { USB_DEVICE(0x0411, 0x005e), USB_DEVICE_DATA(&rt2500usb_ops) },
- { USB_DEVICE(0x0411, 0x0066), USB_DEVICE_DATA(&rt2500usb_ops) },
- { USB_DEVICE(0x0411, 0x0067), USB_DEVICE_DATA(&rt2500usb_ops) },
- { USB_DEVICE(0x0411, 0x008b), USB_DEVICE_DATA(&rt2500usb_ops) },
- { USB_DEVICE(0x0411, 0x0097), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x0411, 0x005e) },
+ { USB_DEVICE(0x0411, 0x0066) },
+ { USB_DEVICE(0x0411, 0x0067) },
+ { USB_DEVICE(0x0411, 0x008b) },
+ { USB_DEVICE(0x0411, 0x0097) },
/* MSI */
- { USB_DEVICE(0x0db0, 0x6861), USB_DEVICE_DATA(&rt2500usb_ops) },
- { USB_DEVICE(0x0db0, 0x6865), USB_DEVICE_DATA(&rt2500usb_ops) },
- { USB_DEVICE(0x0db0, 0x6869), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x0db0, 0x6861) },
+ { USB_DEVICE(0x0db0, 0x6865) },
+ { USB_DEVICE(0x0db0, 0x6869) },
/* Ralink */
- { USB_DEVICE(0x148f, 0x1706), USB_DEVICE_DATA(&rt2500usb_ops) },
- { USB_DEVICE(0x148f, 0x2570), USB_DEVICE_DATA(&rt2500usb_ops) },
- { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt2500usb_ops) },
- { USB_DEVICE(0x148f, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x148f, 0x1706) },
+ { USB_DEVICE(0x148f, 0x2570) },
+ { USB_DEVICE(0x148f, 0x9020) },
/* Sagem */
- { USB_DEVICE(0x079b, 0x004b), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x079b, 0x004b) },
/* Siemens */
- { USB_DEVICE(0x0681, 0x3c06), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x0681, 0x3c06) },
/* SMC */
- { USB_DEVICE(0x0707, 0xee13), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x0707, 0xee13) },
/* Spairon */
- { USB_DEVICE(0x114b, 0x0110), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x114b, 0x0110) },
/* SURECOM */
- { USB_DEVICE(0x0769, 0x11f3), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x0769, 0x11f3) },
/* Trust */
- { USB_DEVICE(0x0eb0, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x0eb0, 0x9020) },
/* VTech */
- { USB_DEVICE(0x0f88, 0x3012), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x0f88, 0x3012) },
/* Zinwell */
- { USB_DEVICE(0x5a57, 0x0260), USB_DEVICE_DATA(&rt2500usb_ops) },
+ { USB_DEVICE(0x5a57, 0x0260) },
{ 0, }
};
@@ -1967,10 +1966,16 @@ MODULE_SUPPORTED_DEVICE("Ralink RT2570 USB chipset based cards");
MODULE_DEVICE_TABLE(usb, rt2500usb_device_table);
MODULE_LICENSE("GPL");
+static int rt2500usb_probe(struct usb_interface *usb_intf,
+ const struct usb_device_id *id)
+{
+ return rt2x00usb_probe(usb_intf, &rt2500usb_ops);
+}
+
static struct usb_driver rt2500usb_driver = {
.name = KBUILD_MODNAME,
.id_table = rt2500usb_device_table,
- .probe = rt2x00usb_probe,
+ .probe = rt2500usb_probe,
.disconnect = rt2x00usb_disconnect,
.suspend = rt2x00usb_suspend,
.resume = rt2x00usb_resume,
diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index 8fbc5fa965e0..f67bc9b31b28 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -51,6 +51,7 @@
* RF3320 2.4G 1T1R(RT3350/RT3370/RT3390)
* RF3322 2.4G 2T2R(RT3352/RT3371/RT3372/RT3391/RT3392)
* RF3853 2.4G/5G 3T3R(RT3883/RT3563/RT3573/RT3593/RT3662)
+ * RF5370 2.4G 1T1R
* RF5390 2.4G 1T1R
*/
#define RF2820 0x0001
@@ -66,6 +67,7 @@
#define RF3320 0x000b
#define RF3322 0x000c
#define RF3853 0x000d
+#define RF5370 0x5370
#define RF5390 0x5390
/*
@@ -2104,6 +2106,59 @@ struct mac_iveiv_entry {
#define EEPROM_TXPOWER_BG_2 FIELD16(0xff00)
/*
+ * EEPROM temperature compensation boundaries 802.11BG
+ * MINUS4: If the actual TSSI is below this boundary, tx power needs to be
+ * reduced by (agc_step * -4)
+ * MINUS3: If the actual TSSI is below this boundary, tx power needs to be
+ * reduced by (agc_step * -3)
+ */
+#define EEPROM_TSSI_BOUND_BG1 0x0037
+#define EEPROM_TSSI_BOUND_BG1_MINUS4 FIELD16(0x00ff)
+#define EEPROM_TSSI_BOUND_BG1_MINUS3 FIELD16(0xff00)
+
+/*
+ * EEPROM temperature compensation boundaries 802.11BG
+ * MINUS2: If the actual TSSI is below this boundary, tx power needs to be
+ * reduced by (agc_step * -2)
+ * MINUS1: If the actual TSSI is below this boundary, tx power needs to be
+ * reduced by (agc_step * -1)
+ */
+#define EEPROM_TSSI_BOUND_BG2 0x0038
+#define EEPROM_TSSI_BOUND_BG2_MINUS2 FIELD16(0x00ff)
+#define EEPROM_TSSI_BOUND_BG2_MINUS1 FIELD16(0xff00)
+
+/*
+ * EEPROM temperature compensation boundaries 802.11BG
+ * REF: Reference TSSI value, no tx power changes needed
+ * PLUS1: If the actual TSSI is above this boundary, tx power needs to be
+ * increased by (agc_step * 1)
+ */
+#define EEPROM_TSSI_BOUND_BG3 0x0039
+#define EEPROM_TSSI_BOUND_BG3_REF FIELD16(0x00ff)
+#define EEPROM_TSSI_BOUND_BG3_PLUS1 FIELD16(0xff00)
+
+/*
+ * EEPROM temperature compensation boundaries 802.11BG
+ * PLUS2: If the actual TSSI is above this boundary, tx power needs to be
+ * increased by (agc_step * 2)
+ * PLUS3: If the actual TSSI is above this boundary, tx power needs to be
+ * increased by (agc_step * 3)
+ */
+#define EEPROM_TSSI_BOUND_BG4 0x003a
+#define EEPROM_TSSI_BOUND_BG4_PLUS2 FIELD16(0x00ff)
+#define EEPROM_TSSI_BOUND_BG4_PLUS3 FIELD16(0xff00)
+
+/*
+ * EEPROM temperature compensation boundaries 802.11BG
+ * PLUS4: If the actual TSSI is above this boundary, tx power needs to be
+ * increased by (agc_step * 4)
+ * AGC_STEP: Temperature compensation step.
+ */
+#define EEPROM_TSSI_BOUND_BG5 0x003b
+#define EEPROM_TSSI_BOUND_BG5_PLUS4 FIELD16(0x00ff)
+#define EEPROM_TSSI_BOUND_BG5_AGC_STEP FIELD16(0xff00)
+
+/*
* EEPROM TXPOWER 802.11A
*/
#define EEPROM_TXPOWER_A1 0x003c
@@ -2113,6 +2168,59 @@ struct mac_iveiv_entry {
#define EEPROM_TXPOWER_A_2 FIELD16(0xff00)
/*
+ * EEPROM temperature compensation boundaries 802.11A
+ * MINUS4: If the actual TSSI is below this boundary, tx power needs to be
+ * reduced by (agc_step * -4)
+ * MINUS3: If the actual TSSI is below this boundary, tx power needs to be
+ * reduced by (agc_step * -3)
+ */
+#define EEPROM_TSSI_BOUND_A1 0x006a
+#define EEPROM_TSSI_BOUND_A1_MINUS4 FIELD16(0x00ff)
+#define EEPROM_TSSI_BOUND_A1_MINUS3 FIELD16(0xff00)
+
+/*
+ * EEPROM temperature compensation boundaries 802.11A
+ * MINUS2: If the actual TSSI is below this boundary, tx power needs to be
+ * reduced by (agc_step * -2)
+ * MINUS1: If the actual TSSI is below this boundary, tx power needs to be
+ * reduced by (agc_step * -1)
+ */
+#define EEPROM_TSSI_BOUND_A2 0x006b
+#define EEPROM_TSSI_BOUND_A2_MINUS2 FIELD16(0x00ff)
+#define EEPROM_TSSI_BOUND_A2_MINUS1 FIELD16(0xff00)
+
+/*
+ * EEPROM temperature compensation boundaries 802.11A
+ * REF: Reference TSSI value, no tx power changes needed
+ * PLUS1: If the actual TSSI is above this boundary, tx power needs to be
+ * increased by (agc_step * 1)
+ */
+#define EEPROM_TSSI_BOUND_A3 0x006c
+#define EEPROM_TSSI_BOUND_A3_REF FIELD16(0x00ff)
+#define EEPROM_TSSI_BOUND_A3_PLUS1 FIELD16(0xff00)
+
+/*
+ * EEPROM temperature compensation boundaries 802.11A
+ * PLUS2: If the actual TSSI is above this boundary, tx power needs to be
+ * increased by (agc_step * 2)
+ * PLUS3: If the actual TSSI is above this boundary, tx power needs to be
+ * increased by (agc_step * 3)
+ */
+#define EEPROM_TSSI_BOUND_A4 0x006d
+#define EEPROM_TSSI_BOUND_A4_PLUS2 FIELD16(0x00ff)
+#define EEPROM_TSSI_BOUND_A4_PLUS3 FIELD16(0xff00)
+
+/*
+ * EEPROM temperature compensation boundaries 802.11A
+ * PLUS4: If the actual TSSI is above this boundary, tx power needs to be
+ * increased by (agc_step * 4)
+ * AGC_STEP: Temperature compensation step.
+ */
+#define EEPROM_TSSI_BOUND_A5 0x006e
+#define EEPROM_TSSI_BOUND_A5_PLUS4 FIELD16(0x00ff)
+#define EEPROM_TSSI_BOUND_A5_AGC_STEP FIELD16(0xff00)
+
+/*
* EEPROM TXPOWER by rate: tx power per tx rate for HT20 mode
*/
#define EEPROM_TXPOWER_BYRATE 0x006f
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index dbf74d07d947..2a6aa85cc6c9 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -687,6 +687,9 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status)
mcs = real_mcs;
}
+ if (aggr == 1 || ampdu == 1)
+ __set_bit(TXDONE_AMPDU, &txdesc.flags);
+
/*
* Ralink has a retry mechanism using a global fallback
* table. We setup this fallback table to try the immediate
@@ -727,34 +730,20 @@ void rt2800_txdone(struct rt2x00_dev *rt2x00dev)
struct data_queue *queue;
struct queue_entry *entry;
u32 reg;
- u8 pid;
- int i;
+ u8 qid;
- /*
- * 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.
- */
- for (i = 0; i < rt2x00dev->ops->tx->entry_num; i++) {
- rt2800_register_read(rt2x00dev, TX_STA_FIFO, &reg);
- if (!rt2x00_get_field32(reg, TX_STA_FIFO_VALID))
- break;
+ while (kfifo_get(&rt2x00dev->txstatus_fifo, &reg)) {
- /*
- * Skip this entry when it contains an invalid
- * queue identication number.
+ /* TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus
+ * qid is guaranteed to be one of the TX QIDs
*/
- pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE);
- if (pid >= QID_RX)
- continue;
-
- queue = rt2x00queue_get_tx_queue(rt2x00dev, pid);
- if (unlikely(!queue))
+ qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE);
+ queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
+ if (unlikely(!queue)) {
+ WARNING(rt2x00dev, "Got TX status for an unavailable "
+ "queue %u, dropping\n", qid);
continue;
+ }
/*
* Inside each queue, we process each entry in a chronological
@@ -946,25 +935,49 @@ static void rt2800_brightness_set(struct led_classdev *led_cdev,
unsigned int ledmode =
rt2x00_get_field16(led->rt2x00dev->led_mcu_reg,
EEPROM_FREQ_LED_MODE);
+ u32 reg;
- if (led->type == LED_TYPE_RADIO) {
- rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode,
- enabled ? 0x20 : 0);
- } else if (led->type == LED_TYPE_ASSOC) {
- rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode,
- enabled ? (bg_mode ? 0x60 : 0xa0) : 0x20);
- } else if (led->type == LED_TYPE_QUALITY) {
- /*
- * The brightness is divided into 6 levels (0 - 5),
- * The specs tell us the following levels:
- * 0, 1 ,3, 7, 15, 31
- * to determine the level in a simple way we can simply
- * work with bitshifting:
- * (1 << level) - 1
- */
- rt2800_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff,
- (1 << brightness / (LED_FULL / 6)) - 1,
- polarity);
+ /* Check for SoC (SOC devices don't support MCU requests) */
+ if (rt2x00_is_soc(led->rt2x00dev)) {
+ rt2800_register_read(led->rt2x00dev, LED_CFG, &reg);
+
+ /* Set LED Polarity */
+ rt2x00_set_field32(&reg, LED_CFG_LED_POLAR, polarity);
+
+ /* Set LED Mode */
+ if (led->type == LED_TYPE_RADIO) {
+ rt2x00_set_field32(&reg, LED_CFG_G_LED_MODE,
+ enabled ? 3 : 0);
+ } else if (led->type == LED_TYPE_ASSOC) {
+ rt2x00_set_field32(&reg, LED_CFG_Y_LED_MODE,
+ enabled ? 3 : 0);
+ } else if (led->type == LED_TYPE_QUALITY) {
+ rt2x00_set_field32(&reg, LED_CFG_R_LED_MODE,
+ enabled ? 3 : 0);
+ }
+
+ rt2800_register_write(led->rt2x00dev, LED_CFG, reg);
+
+ } else {
+ if (led->type == LED_TYPE_RADIO) {
+ rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode,
+ enabled ? 0x20 : 0);
+ } else if (led->type == LED_TYPE_ASSOC) {
+ rt2800_mcu_request(led->rt2x00dev, MCU_LED, 0xff, ledmode,
+ enabled ? (bg_mode ? 0x60 : 0xa0) : 0x20);
+ } else if (led->type == LED_TYPE_QUALITY) {
+ /*
+ * The brightness is divided into 6 levels (0 - 5),
+ * The specs tell us the following levels:
+ * 0, 1 ,3, 7, 15, 31
+ * to determine the level in a simple way we can simply
+ * work with bitshifting:
+ * (1 << level) - 1
+ */
+ rt2800_mcu_request(led->rt2x00dev, MCU_LED_STRENGTH, 0xff,
+ (1 << brightness / (LED_FULL / 6)) - 1,
+ polarity);
+ }
}
}
@@ -1218,6 +1231,25 @@ void rt2800_config_intf(struct rt2x00_dev *rt2x00dev, struct rt2x00_intf *intf,
rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_SYNC, conf->sync);
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+
+ if (conf->sync == TSF_SYNC_AP_NONE) {
+ /*
+ * Tune beacon queue transmit parameters for AP mode
+ */
+ rt2800_register_read(rt2x00dev, TBTT_SYNC_CFG, &reg);
+ rt2x00_set_field32(&reg, TBTT_SYNC_CFG_BCN_CWMIN, 0);
+ rt2x00_set_field32(&reg, TBTT_SYNC_CFG_BCN_AIFSN, 1);
+ rt2x00_set_field32(&reg, TBTT_SYNC_CFG_BCN_EXP_WIN, 32);
+ rt2x00_set_field32(&reg, TBTT_SYNC_CFG_TBTT_ADJUST, 0);
+ rt2800_register_write(rt2x00dev, TBTT_SYNC_CFG, reg);
+ } else {
+ rt2800_register_read(rt2x00dev, TBTT_SYNC_CFG, &reg);
+ rt2x00_set_field32(&reg, TBTT_SYNC_CFG_BCN_CWMIN, 4);
+ rt2x00_set_field32(&reg, TBTT_SYNC_CFG_BCN_AIFSN, 2);
+ rt2x00_set_field32(&reg, TBTT_SYNC_CFG_BCN_EXP_WIN, 32);
+ rt2x00_set_field32(&reg, TBTT_SYNC_CFG_TBTT_ADJUST, 16);
+ rt2800_register_write(rt2x00dev, TBTT_SYNC_CFG, reg);
+ }
}
if (flags & CONFIG_UPDATE_MAC) {
@@ -1608,7 +1640,6 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev,
struct channel_info *info)
{
u8 rfcsr;
- u16 eeprom;
rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1);
rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3);
@@ -1638,11 +1669,10 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field8(&rfcsr, RFCSR17_CODE, rt2x00dev->freq_offset);
rt2800_rfcsr_write(rt2x00dev, 17, rfcsr);
- rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
if (rf->channel <= 14) {
int idx = rf->channel-1;
- if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST)) {
+ if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) {
if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) {
/* r55/r59 value array of channel 1~14 */
static const char r55_bt_rev[] = {0x83, 0x83,
@@ -1721,7 +1751,8 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
rt2x00_rf(rt2x00dev, RF3052) ||
rt2x00_rf(rt2x00dev, RF3320))
rt2800_config_channel_rf3xxx(rt2x00dev, conf, rf, info);
- else if (rt2x00_rf(rt2x00dev, RF5390))
+ else if (rt2x00_rf(rt2x00dev, RF5370) ||
+ rt2x00_rf(rt2x00dev, RF5390))
rt2800_config_channel_rf53xx(rt2x00dev, conf, rf, info);
else
rt2800_config_channel_rf2xxx(rt2x00dev, conf, rf, info);
@@ -1736,8 +1767,8 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
if (rf->channel <= 14) {
if (!rt2x00_rt(rt2x00dev, RT5390)) {
- if (test_bit(CONFIG_EXTERNAL_LNA_BG,
- &rt2x00dev->flags)) {
+ if (test_bit(CAPABILITY_EXTERNAL_LNA_BG,
+ &rt2x00dev->cap_flags)) {
rt2800_bbp_write(rt2x00dev, 82, 0x62);
rt2800_bbp_write(rt2x00dev, 75, 0x46);
} else {
@@ -1748,7 +1779,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
} else {
rt2800_bbp_write(rt2x00dev, 82, 0xf2);
- if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags))
+ if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags))
rt2800_bbp_write(rt2x00dev, 75, 0x46);
else
rt2800_bbp_write(rt2x00dev, 75, 0x50);
@@ -1813,17 +1844,131 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, &reg);
}
+static int rt2800_get_gain_calibration_delta(struct rt2x00_dev *rt2x00dev)
+{
+ u8 tssi_bounds[9];
+ u8 current_tssi;
+ u16 eeprom;
+ u8 step;
+ int i;
+
+ /*
+ * Read TSSI boundaries for temperature compensation from
+ * the EEPROM.
+ *
+ * Array idx 0 1 2 3 4 5 6 7 8
+ * Matching Delta value -4 -3 -2 -1 0 +1 +2 +3 +4
+ * Example TSSI bounds 0xF0 0xD0 0xB5 0xA0 0x88 0x45 0x25 0x15 0x00
+ */
+ if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG1, &eeprom);
+ tssi_bounds[0] = rt2x00_get_field16(eeprom,
+ EEPROM_TSSI_BOUND_BG1_MINUS4);
+ tssi_bounds[1] = rt2x00_get_field16(eeprom,
+ EEPROM_TSSI_BOUND_BG1_MINUS3);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG2, &eeprom);
+ tssi_bounds[2] = rt2x00_get_field16(eeprom,
+ EEPROM_TSSI_BOUND_BG2_MINUS2);
+ tssi_bounds[3] = rt2x00_get_field16(eeprom,
+ EEPROM_TSSI_BOUND_BG2_MINUS1);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG3, &eeprom);
+ tssi_bounds[4] = rt2x00_get_field16(eeprom,
+ EEPROM_TSSI_BOUND_BG3_REF);
+ tssi_bounds[5] = rt2x00_get_field16(eeprom,
+ EEPROM_TSSI_BOUND_BG3_PLUS1);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG4, &eeprom);
+ tssi_bounds[6] = rt2x00_get_field16(eeprom,
+ EEPROM_TSSI_BOUND_BG4_PLUS2);
+ tssi_bounds[7] = rt2x00_get_field16(eeprom,
+ EEPROM_TSSI_BOUND_BG4_PLUS3);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_BG5, &eeprom);
+ tssi_bounds[8] = rt2x00_get_field16(eeprom,
+ EEPROM_TSSI_BOUND_BG5_PLUS4);
+
+ step = rt2x00_get_field16(eeprom,
+ EEPROM_TSSI_BOUND_BG5_AGC_STEP);
+ } else {
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A1, &eeprom);
+ tssi_bounds[0] = rt2x00_get_field16(eeprom,
+ EEPROM_TSSI_BOUND_A1_MINUS4);
+ tssi_bounds[1] = rt2x00_get_field16(eeprom,
+ EEPROM_TSSI_BOUND_A1_MINUS3);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A2, &eeprom);
+ tssi_bounds[2] = rt2x00_get_field16(eeprom,
+ EEPROM_TSSI_BOUND_A2_MINUS2);
+ tssi_bounds[3] = rt2x00_get_field16(eeprom,
+ EEPROM_TSSI_BOUND_A2_MINUS1);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A3, &eeprom);
+ tssi_bounds[4] = rt2x00_get_field16(eeprom,
+ EEPROM_TSSI_BOUND_A3_REF);
+ tssi_bounds[5] = rt2x00_get_field16(eeprom,
+ EEPROM_TSSI_BOUND_A3_PLUS1);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A4, &eeprom);
+ tssi_bounds[6] = rt2x00_get_field16(eeprom,
+ EEPROM_TSSI_BOUND_A4_PLUS2);
+ tssi_bounds[7] = rt2x00_get_field16(eeprom,
+ EEPROM_TSSI_BOUND_A4_PLUS3);
+
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_TSSI_BOUND_A5, &eeprom);
+ tssi_bounds[8] = rt2x00_get_field16(eeprom,
+ EEPROM_TSSI_BOUND_A5_PLUS4);
+
+ step = rt2x00_get_field16(eeprom,
+ EEPROM_TSSI_BOUND_A5_AGC_STEP);
+ }
+
+ /*
+ * Check if temperature compensation is supported.
+ */
+ if (tssi_bounds[4] == 0xff)
+ return 0;
+
+ /*
+ * Read current TSSI (BBP 49).
+ */
+ rt2800_bbp_read(rt2x00dev, 49, &current_tssi);
+
+ /*
+ * Compare TSSI value (BBP49) with the compensation boundaries
+ * from the EEPROM and increase or decrease tx power.
+ */
+ for (i = 0; i <= 3; i++) {
+ if (current_tssi > tssi_bounds[i])
+ break;
+ }
+
+ if (i == 4) {
+ for (i = 8; i >= 5; i--) {
+ if (current_tssi < tssi_bounds[i])
+ break;
+ }
+ }
+
+ return (i - 4) * step;
+}
+
static int rt2800_get_txpower_bw_comp(struct rt2x00_dev *rt2x00dev,
enum ieee80211_band band)
{
u16 eeprom;
u8 comp_en;
u8 comp_type;
- int comp_value;
+ int comp_value = 0;
rt2x00_eeprom_read(rt2x00dev, EEPROM_TXPOWER_DELTA, &eeprom);
- if (eeprom == 0xffff)
+ /*
+ * HT40 compensation not required.
+ */
+ if (eeprom == 0xffff ||
+ !test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags))
return 0;
if (band == IEEE80211_BAND_2GHZ) {
@@ -1853,11 +1998,9 @@ static int rt2800_get_txpower_bw_comp(struct rt2x00_dev *rt2x00dev,
return comp_value;
}
-static u8 rt2800_compesate_txpower(struct rt2x00_dev *rt2x00dev,
- int is_rate_b,
- enum ieee80211_band band,
- int power_level,
- u8 txpower)
+static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b,
+ enum ieee80211_band band, int power_level,
+ u8 txpower, int delta)
{
u32 reg;
u16 eeprom;
@@ -1865,15 +2008,11 @@ static u8 rt2800_compesate_txpower(struct rt2x00_dev *rt2x00dev,
u8 eirp_txpower;
u8 eirp_txpower_criterion;
u8 reg_limit;
- int bw_comp = 0;
if (!((band == IEEE80211_BAND_5GHZ) && is_rate_b))
return txpower;
- if (test_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags))
- bw_comp = rt2800_get_txpower_bw_comp(rt2x00dev, band);
-
- if (test_bit(CONFIG_SUPPORT_POWER_LIMIT, &rt2x00dev->flags)) {
+ if (test_bit(CAPABILITY_POWER_LIMIT, &rt2x00dev->cap_flags)) {
/*
* Check if eirp txpower exceed txpower_limit.
* We use OFDM 6M as criterion and its eirp txpower
@@ -1895,18 +2034,19 @@ static u8 rt2800_compesate_txpower(struct rt2x00_dev *rt2x00dev,
EEPROM_EIRP_MAX_TX_POWER_5GHZ);
eirp_txpower = eirp_txpower_criterion + (txpower - criterion) +
- (is_rate_b ? 4 : 0) + bw_comp;
+ (is_rate_b ? 4 : 0) + delta;
reg_limit = (eirp_txpower > power_level) ?
(eirp_txpower - power_level) : 0;
} else
reg_limit = 0;
- return txpower + bw_comp - reg_limit;
+ return txpower + delta - reg_limit;
}
static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
- struct ieee80211_conf *conf)
+ enum ieee80211_band band,
+ int power_level)
{
u8 txpower;
u16 eeprom;
@@ -1914,8 +2054,17 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
u32 reg;
u8 r1;
u32 offset;
- enum ieee80211_band band = conf->channel->band;
- int power_level = conf->power_level;
+ int delta;
+
+ /*
+ * Calculate HT40 compensation delta
+ */
+ delta = rt2800_get_txpower_bw_comp(rt2x00dev, band);
+
+ /*
+ * calculate temperature compensation delta
+ */
+ delta += rt2800_get_gain_calibration_delta(rt2x00dev);
/*
* set to normal bbp tx power control mode: +/- 0dBm
@@ -1944,8 +2093,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
*/
txpower = rt2x00_get_field16(eeprom,
EEPROM_TXPOWER_BYRATE_RATE0);
- txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band,
- power_level, txpower);
+ txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band,
+ power_level, txpower, delta);
rt2x00_set_field32(&reg, TX_PWR_CFG_RATE0, txpower);
/*
@@ -1955,8 +2104,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
*/
txpower = rt2x00_get_field16(eeprom,
EEPROM_TXPOWER_BYRATE_RATE1);
- txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band,
- power_level, txpower);
+ txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band,
+ power_level, txpower, delta);
rt2x00_set_field32(&reg, TX_PWR_CFG_RATE1, txpower);
/*
@@ -1966,8 +2115,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
*/
txpower = rt2x00_get_field16(eeprom,
EEPROM_TXPOWER_BYRATE_RATE2);
- txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band,
- power_level, txpower);
+ txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band,
+ power_level, txpower, delta);
rt2x00_set_field32(&reg, TX_PWR_CFG_RATE2, txpower);
/*
@@ -1977,8 +2126,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
*/
txpower = rt2x00_get_field16(eeprom,
EEPROM_TXPOWER_BYRATE_RATE3);
- txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band,
- power_level, txpower);
+ txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band,
+ power_level, txpower, delta);
rt2x00_set_field32(&reg, TX_PWR_CFG_RATE3, txpower);
/* read the next four txpower values */
@@ -1993,8 +2142,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
*/
txpower = rt2x00_get_field16(eeprom,
EEPROM_TXPOWER_BYRATE_RATE0);
- txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band,
- power_level, txpower);
+ txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band,
+ power_level, txpower, delta);
rt2x00_set_field32(&reg, TX_PWR_CFG_RATE4, txpower);
/*
@@ -2004,8 +2153,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
*/
txpower = rt2x00_get_field16(eeprom,
EEPROM_TXPOWER_BYRATE_RATE1);
- txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band,
- power_level, txpower);
+ txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band,
+ power_level, txpower, delta);
rt2x00_set_field32(&reg, TX_PWR_CFG_RATE5, txpower);
/*
@@ -2015,8 +2164,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
*/
txpower = rt2x00_get_field16(eeprom,
EEPROM_TXPOWER_BYRATE_RATE2);
- txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band,
- power_level, txpower);
+ txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band,
+ power_level, txpower, delta);
rt2x00_set_field32(&reg, TX_PWR_CFG_RATE6, txpower);
/*
@@ -2026,8 +2175,8 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
*/
txpower = rt2x00_get_field16(eeprom,
EEPROM_TXPOWER_BYRATE_RATE3);
- txpower = rt2800_compesate_txpower(rt2x00dev, is_rate_b, band,
- power_level, txpower);
+ txpower = rt2800_compensate_txpower(rt2x00dev, is_rate_b, band,
+ power_level, txpower, delta);
rt2x00_set_field32(&reg, TX_PWR_CFG_RATE7, txpower);
rt2800_register_write(rt2x00dev, offset, reg);
@@ -2037,6 +2186,13 @@ static void rt2800_config_txpower(struct rt2x00_dev *rt2x00dev,
}
}
+void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev)
+{
+ rt2800_config_txpower(rt2x00dev, rt2x00dev->curr_band,
+ rt2x00dev->tx_power);
+}
+EXPORT_SYMBOL_GPL(rt2800_gain_calibration);
+
static void rt2800_config_retry_limit(struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_conf *libconf)
{
@@ -2090,10 +2246,12 @@ void rt2800_config(struct rt2x00_dev *rt2x00dev,
if (flags & IEEE80211_CONF_CHANGE_CHANNEL) {
rt2800_config_channel(rt2x00dev, libconf->conf,
&libconf->rf, &libconf->channel);
- rt2800_config_txpower(rt2x00dev, libconf->conf);
+ rt2800_config_txpower(rt2x00dev, libconf->conf->channel->band,
+ libconf->conf->power_level);
}
if (flags & IEEE80211_CONF_CHANGE_POWER)
- rt2800_config_txpower(rt2x00dev, libconf->conf);
+ rt2800_config_txpower(rt2x00dev, libconf->conf->channel->band,
+ libconf->conf->power_level);
if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
rt2800_config_retry_limit(rt2x00dev, libconf);
if (flags & IEEE80211_CONF_CHANGE_PS)
@@ -2254,7 +2412,7 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
} 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);
+ rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000030);
} else if (rt2x00_rt(rt2x00dev, RT5390)) {
rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404);
rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
@@ -2758,8 +2916,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
ant = (div_mode == 3) ? 1 : 0;
/* check if this is a Bluetooth combo card */
- rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
- if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST)) {
+ if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) {
u32 reg;
rt2800_register_read(rt2x00dev, GPIO_CTRL_CFG, &reg);
@@ -3155,8 +3312,8 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) ||
rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) {
- if (!test_bit(CONFIG_EXTERNAL_LNA_BG,
- &rt2x00dev->flags))
+ if (!test_bit(CAPABILITY_EXTERNAL_LNA_BG,
+ &rt2x00dev->cap_flags))
rt2x00_set_field8(&rfcsr, RFCSR17_R, 1);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG, &eeprom);
@@ -3530,6 +3687,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
!rt2x00_rf(rt2x00dev, RF3022) &&
!rt2x00_rf(rt2x00dev, RF3052) &&
!rt2x00_rf(rt2x00dev, RF3320) &&
+ !rt2x00_rf(rt2x00dev, RF5370) &&
!rt2x00_rf(rt2x00dev, RF5390)) {
ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
return -ENODEV;
@@ -3568,26 +3726,30 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
}
/*
- * Read frequency offset and RF programming sequence.
+ * Determine external LNA informations.
*/
- rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom);
- rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET);
-
- /*
- * Read external LNA informations.
- */
- rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1, &eeprom);
-
if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_5G))
- __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags);
if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_LNA_2G))
- __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags);
/*
* Detect if this device has an hardware controlled radio.
*/
if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_HW_RADIO))
- __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags);
+
+ /*
+ * Detect if this device has Bluetooth co-existence.
+ */
+ if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_BT_COEXIST))
+ __set_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags);
+
+ /*
+ * Read frequency offset and RF programming sequence.
+ */
+ rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom);
+ rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET);
/*
* Store led settings, for correct led behaviour.
@@ -3597,7 +3759,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC);
rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY);
- rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &rt2x00dev->led_mcu_reg);
+ rt2x00dev->led_mcu_reg = eeprom;
#endif /* CONFIG_RT2X00_LIB_LEDS */
/*
@@ -3607,7 +3769,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
if (rt2x00_get_field16(eeprom, EEPROM_EIRP_MAX_TX_POWER_2GHZ) <
EIRP_MAX_TX_POWER_LIMIT)
- __set_bit(CONFIG_SUPPORT_POWER_LIMIT, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_POWER_LIMIT, &rt2x00dev->cap_flags);
return 0;
}
@@ -3828,6 +3990,7 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
rt2x00_rf(rt2x00dev, RF3021) ||
rt2x00_rf(rt2x00dev, RF3022) ||
rt2x00_rf(rt2x00dev, RF3320) ||
+ rt2x00_rf(rt2x00dev, RF5370) ||
rt2x00_rf(rt2x00dev, RF5390)) {
spec->num_channels = 14;
spec->channels = rf_vals_3x;
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index 0c92d86a36f4..f2d15941c71a 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -181,6 +181,7 @@ void rt2800_link_stats(struct rt2x00_dev *rt2x00dev, struct link_qual *qual);
void rt2800_reset_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual);
void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual,
const u32 count);
+void rt2800_gain_calibration(struct rt2x00_dev *rt2x00dev);
int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev);
void rt2800_disable_radio(struct rt2x00_dev *rt2x00dev);
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index 808073aa9dcc..cc4a54f571b8 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -66,7 +66,7 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token)
return;
for (i = 0; i < 200; i++) {
- rt2800_register_read(rt2x00dev, H2M_MAILBOX_CID, &reg);
+ rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CID, &reg);
if ((rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD0) == token) ||
(rt2x00_get_field32(reg, H2M_MAILBOX_CID_CMD1) == token) ||
@@ -80,8 +80,8 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token)
if (i == 200)
ERROR(rt2x00dev, "MCU request failed, no response from hardware\n");
- rt2800_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
- rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
}
#if defined(CONFIG_RALINK_RT288X) || defined(CONFIG_RALINK_RT305X)
@@ -105,7 +105,7 @@ static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom)
struct rt2x00_dev *rt2x00dev = eeprom->data;
u32 reg;
- rt2800_register_read(rt2x00dev, E2PROM_CSR, &reg);
+ rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, &reg);
eeprom->reg_data_in = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_IN);
eeprom->reg_data_out = !!rt2x00_get_field32(reg, E2PROM_CSR_DATA_OUT);
@@ -127,7 +127,7 @@ static void rt2800pci_eepromregister_write(struct eeprom_93cx6 *eeprom)
rt2x00_set_field32(&reg, E2PROM_CSR_CHIP_SELECT,
!!eeprom->reg_chip_select);
- rt2800_register_write(rt2x00dev, E2PROM_CSR, reg);
+ rt2x00pci_register_write(rt2x00dev, E2PROM_CSR, reg);
}
static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
@@ -135,7 +135,7 @@ static void rt2800pci_read_eeprom_pci(struct rt2x00_dev *rt2x00dev)
struct eeprom_93cx6 eeprom;
u32 reg;
- rt2800_register_read(rt2x00dev, E2PROM_CSR, &reg);
+ rt2x00pci_register_read(rt2x00dev, E2PROM_CSR, &reg);
eeprom.data = rt2x00dev;
eeprom.register_read = rt2800pci_eepromregister_read;
@@ -195,9 +195,9 @@ static void rt2800pci_start_queue(struct data_queue *queue)
switch (queue->qid) {
case QID_RX:
- rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 1);
- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+ rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
break;
case QID_BEACON:
/*
@@ -207,15 +207,15 @@ static void rt2800pci_start_queue(struct data_queue *queue)
tasklet_enable(&rt2x00dev->tbtt_tasklet);
tasklet_enable(&rt2x00dev->pretbtt_tasklet);
- rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
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);
+ rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg);
- rt2800_register_read(rt2x00dev, INT_TIMER_EN, &reg);
+ rt2x00pci_register_read(rt2x00dev, INT_TIMER_EN, &reg);
rt2x00_set_field32(&reg, INT_TIMER_EN_PRE_TBTT_TIMER, 1);
- rt2800_register_write(rt2x00dev, INT_TIMER_EN, reg);
+ rt2x00pci_register_write(rt2x00dev, INT_TIMER_EN, reg);
break;
default:
break;
@@ -233,11 +233,13 @@ static void rt2800pci_kick_queue(struct data_queue *queue)
case QID_AC_BE:
case QID_AC_BK:
entry = rt2x00queue_get_entry(queue, Q_INDEX);
- rt2800_register_write(rt2x00dev, TX_CTX_IDX(queue->qid), entry->entry_idx);
+ rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX(queue->qid),
+ entry->entry_idx);
break;
case QID_MGMT:
entry = rt2x00queue_get_entry(queue, Q_INDEX);
- rt2800_register_write(rt2x00dev, TX_CTX_IDX(5), entry->entry_idx);
+ rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX(5),
+ entry->entry_idx);
break;
default:
break;
@@ -251,20 +253,20 @@ static void rt2800pci_stop_queue(struct data_queue *queue)
switch (queue->qid) {
case QID_RX:
- rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00pci_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+ rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
break;
case QID_BEACON:
- rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00pci_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 0);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
- rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+ rt2x00pci_register_write(rt2x00dev, BCN_TIME_CFG, reg);
- rt2800_register_read(rt2x00dev, INT_TIMER_EN, &reg);
+ rt2x00pci_register_read(rt2x00dev, INT_TIMER_EN, &reg);
rt2x00_set_field32(&reg, INT_TIMER_EN_PRE_TBTT_TIMER, 0);
- rt2800_register_write(rt2x00dev, INT_TIMER_EN, reg);
+ rt2x00pci_register_write(rt2x00dev, INT_TIMER_EN, reg);
/*
* Wait for tbtt tasklets to finish.
@@ -295,19 +297,19 @@ static int rt2800pci_write_firmware(struct rt2x00_dev *rt2x00dev,
*/
reg = 0;
rt2x00_set_field32(&reg, PBF_SYS_CTRL_HOST_RAM_WRITE, 1);
- rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg);
+ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, reg);
/*
* Write firmware to device.
*/
- rt2800_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
- data, len);
+ rt2x00pci_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
+ data, len);
- rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000);
- rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001);
+ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000);
+ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00001);
- rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
- rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
+ rt2x00pci_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
return 0;
}
@@ -351,7 +353,7 @@ static void rt2800pci_clear_entry(struct queue_entry *entry)
* Set RX IDX in register to inform hardware that we have
* handled this entry and it is available for reuse again.
*/
- rt2800_register_write(rt2x00dev, RX_CRX_IDX,
+ rt2x00pci_register_write(rt2x00dev, RX_CRX_IDX,
entry->entry_idx);
} else {
rt2x00_desc_read(entry_priv->desc, 1, &word);
@@ -369,45 +371,51 @@ static int rt2800pci_init_queues(struct rt2x00_dev *rt2x00dev)
* Initialize registers.
*/
entry_priv = rt2x00dev->tx[0].entries[0].priv_data;
- rt2800_register_write(rt2x00dev, TX_BASE_PTR0, entry_priv->desc_dma);
- rt2800_register_write(rt2x00dev, TX_MAX_CNT0, rt2x00dev->tx[0].limit);
- rt2800_register_write(rt2x00dev, TX_CTX_IDX0, 0);
- rt2800_register_write(rt2x00dev, TX_DTX_IDX0, 0);
+ rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR0, entry_priv->desc_dma);
+ rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT0,
+ rt2x00dev->tx[0].limit);
+ rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX0, 0);
+ rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX0, 0);
entry_priv = rt2x00dev->tx[1].entries[0].priv_data;
- rt2800_register_write(rt2x00dev, TX_BASE_PTR1, entry_priv->desc_dma);
- rt2800_register_write(rt2x00dev, TX_MAX_CNT1, rt2x00dev->tx[1].limit);
- rt2800_register_write(rt2x00dev, TX_CTX_IDX1, 0);
- rt2800_register_write(rt2x00dev, TX_DTX_IDX1, 0);
+ rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR1, entry_priv->desc_dma);
+ rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT1,
+ rt2x00dev->tx[1].limit);
+ rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX1, 0);
+ rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX1, 0);
entry_priv = rt2x00dev->tx[2].entries[0].priv_data;
- rt2800_register_write(rt2x00dev, TX_BASE_PTR2, entry_priv->desc_dma);
- rt2800_register_write(rt2x00dev, TX_MAX_CNT2, rt2x00dev->tx[2].limit);
- rt2800_register_write(rt2x00dev, TX_CTX_IDX2, 0);
- rt2800_register_write(rt2x00dev, TX_DTX_IDX2, 0);
+ rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR2, entry_priv->desc_dma);
+ rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT2,
+ rt2x00dev->tx[2].limit);
+ rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX2, 0);
+ rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX2, 0);
entry_priv = rt2x00dev->tx[3].entries[0].priv_data;
- rt2800_register_write(rt2x00dev, TX_BASE_PTR3, entry_priv->desc_dma);
- rt2800_register_write(rt2x00dev, TX_MAX_CNT3, rt2x00dev->tx[3].limit);
- rt2800_register_write(rt2x00dev, TX_CTX_IDX3, 0);
- rt2800_register_write(rt2x00dev, TX_DTX_IDX3, 0);
+ rt2x00pci_register_write(rt2x00dev, TX_BASE_PTR3, entry_priv->desc_dma);
+ rt2x00pci_register_write(rt2x00dev, TX_MAX_CNT3,
+ rt2x00dev->tx[3].limit);
+ rt2x00pci_register_write(rt2x00dev, TX_CTX_IDX3, 0);
+ rt2x00pci_register_write(rt2x00dev, TX_DTX_IDX3, 0);
entry_priv = rt2x00dev->rx->entries[0].priv_data;
- rt2800_register_write(rt2x00dev, RX_BASE_PTR, entry_priv->desc_dma);
- rt2800_register_write(rt2x00dev, RX_MAX_CNT, rt2x00dev->rx[0].limit);
- rt2800_register_write(rt2x00dev, RX_CRX_IDX, rt2x00dev->rx[0].limit - 1);
- rt2800_register_write(rt2x00dev, RX_DRX_IDX, 0);
+ rt2x00pci_register_write(rt2x00dev, RX_BASE_PTR, entry_priv->desc_dma);
+ rt2x00pci_register_write(rt2x00dev, RX_MAX_CNT,
+ rt2x00dev->rx[0].limit);
+ rt2x00pci_register_write(rt2x00dev, RX_CRX_IDX,
+ rt2x00dev->rx[0].limit - 1);
+ rt2x00pci_register_write(rt2x00dev, RX_DRX_IDX, 0);
/*
* Enable global DMA configuration
*/
- rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
+ rt2x00pci_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_ENABLE_RX_DMA, 0);
rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
- rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
+ rt2x00pci_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
- rt2800_register_write(rt2x00dev, DELAY_INT_CFG, 0);
+ rt2x00pci_register_write(rt2x00dev, DELAY_INT_CFG, 0);
return 0;
}
@@ -427,8 +435,8 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
* should clear the register to assure a clean state.
*/
if (state == STATE_RADIO_IRQ_ON) {
- rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
- rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
+ rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
+ rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
/*
* Enable tasklets. The beacon related tasklets are
@@ -440,7 +448,7 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
}
spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags);
- rt2800_register_read(rt2x00dev, INT_MASK_CSR, &reg);
+ rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg);
rt2x00_set_field32(&reg, INT_MASK_CSR_RXDELAYINT, 0);
rt2x00_set_field32(&reg, INT_MASK_CSR_TXDELAYINT, 0);
rt2x00_set_field32(&reg, INT_MASK_CSR_RX_DONE, mask);
@@ -459,7 +467,7 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field32(&reg, INT_MASK_CSR_GPTIMER, 0);
rt2x00_set_field32(&reg, INT_MASK_CSR_RX_COHERENT, 0);
rt2x00_set_field32(&reg, INT_MASK_CSR_TX_COHERENT, 0);
- rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);
+ rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags);
if (state == STATE_RADIO_IRQ_OFF) {
@@ -480,7 +488,7 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev)
/*
* Reset DMA indexes
*/
- rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
+ rt2x00pci_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);
@@ -488,26 +496,26 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev)
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);
+ rt2x00pci_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
- rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
- rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
+ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
+ rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
if (rt2x00_rt(rt2x00dev, RT5390)) {
- rt2800_register_read(rt2x00dev, AUX_CTRL, &reg);
+ rt2x00pci_register_read(rt2x00dev, AUX_CTRL, &reg);
rt2x00_set_field32(&reg, AUX_CTRL_FORCE_PCIE_CLK, 1);
rt2x00_set_field32(&reg, AUX_CTRL_WAKE_PCIE_EN, 1);
- rt2800_register_write(rt2x00dev, AUX_CTRL, reg);
+ rt2x00pci_register_write(rt2x00dev, AUX_CTRL, reg);
}
- rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
+ rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
- rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00pci_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);
+ rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
+ rt2x00pci_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
return 0;
}
@@ -525,8 +533,8 @@ static void rt2800pci_disable_radio(struct rt2x00_dev *rt2x00dev)
{
if (rt2x00_is_soc(rt2x00dev)) {
rt2800_disable_radio(rt2x00dev);
- rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0);
- rt2800_register_write(rt2x00dev, TX_PIN_CFG, 0);
+ rt2x00pci_register_write(rt2x00dev, PWR_PIN_CFG, 0);
+ rt2x00pci_register_write(rt2x00dev, TX_PIN_CFG, 0);
}
}
@@ -537,8 +545,10 @@ static int rt2800pci_set_state(struct rt2x00_dev *rt2x00dev,
rt2800_mcu_request(rt2x00dev, MCU_WAKEUP, TOKEN_WAKUP, 0, 0x02);
rt2800pci_mcu_status(rt2x00dev, TOKEN_WAKUP);
} else if (state == STATE_SLEEP) {
- rt2800_register_write(rt2x00dev, H2M_MAILBOX_STATUS, 0xffffffff);
- rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, 0xffffffff);
+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_STATUS,
+ 0xffffffff);
+ rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CID,
+ 0xffffffff);
rt2800_mcu_request(rt2x00dev, MCU_SLEEP, 0x01, 0xff, 0x01);
}
@@ -717,12 +727,13 @@ static void rt2800pci_wakeup(struct rt2x00_dev *rt2x00dev)
rt2800_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
}
-static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
+static bool rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
struct queue_entry *entry;
u32 status;
u8 qid;
+ int max_tx_done = 16;
while (kfifo_get(&rt2x00dev->txstatus_fifo, &status)) {
qid = rt2x00_get_field32(status, TX_STA_FIFO_PID_QUEUE);
@@ -759,11 +770,16 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
rt2800_txdone_entry(entry, status);
+
+ if (--max_tx_done == 0)
+ break;
}
+
+ return !max_tx_done;
}
-static void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
- struct rt2x00_field32 irq_field)
+static inline void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00_field32 irq_field)
{
u32 reg;
@@ -772,15 +788,17 @@ static void rt2800pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
* access needs locking.
*/
spin_lock_irq(&rt2x00dev->irqmask_lock);
- rt2800_register_read(rt2x00dev, INT_MASK_CSR, &reg);
+ rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg);
rt2x00_set_field32(&reg, irq_field, 1);
- rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);
+ rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
spin_unlock_irq(&rt2x00dev->irqmask_lock);
}
static void rt2800pci_txstatus_tasklet(unsigned long data)
{
- rt2800pci_txdone((struct rt2x00_dev *)data);
+ struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
+ if (rt2800pci_txdone(rt2x00dev))
+ tasklet_schedule(&rt2x00dev->txstatus_tasklet);
/*
* No need to enable the tx status interrupt here as we always
@@ -806,8 +824,10 @@ static void rt2800pci_tbtt_tasklet(unsigned long data)
static void rt2800pci_rxdone_tasklet(unsigned long data)
{
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
- rt2x00pci_rxdone(rt2x00dev);
- rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RX_DONE);
+ if (rt2x00pci_rxdone(rt2x00dev))
+ tasklet_schedule(&rt2x00dev->rxdone_tasklet);
+ else
+ rt2800pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RX_DONE);
}
static void rt2800pci_autowake_tasklet(unsigned long data)
@@ -841,7 +861,7 @@ static void rt2800pci_txstatus_interrupt(struct rt2x00_dev *rt2x00dev)
* need to lock the kfifo.
*/
for (i = 0; i < rt2x00dev->ops->tx->entry_num; i++) {
- rt2800_register_read(rt2x00dev, TX_STA_FIFO, &status);
+ rt2x00pci_register_read(rt2x00dev, TX_STA_FIFO, &status);
if (!rt2x00_get_field32(status, TX_STA_FIFO_VALID))
break;
@@ -863,8 +883,8 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
u32 reg, mask;
/* Read status and ACK all interrupts */
- rt2800_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
- rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
+ rt2x00pci_register_read(rt2x00dev, INT_SOURCE_CSR, &reg);
+ rt2x00pci_register_write(rt2x00dev, INT_SOURCE_CSR, reg);
if (!reg)
return IRQ_NONE;
@@ -904,9 +924,9 @@ static irqreturn_t rt2800pci_interrupt(int irq, void *dev_instance)
* the tasklet will reenable the appropriate interrupts.
*/
spin_lock(&rt2x00dev->irqmask_lock);
- rt2800_register_read(rt2x00dev, INT_MASK_CSR, &reg);
+ rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, &reg);
reg &= mask;
- rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);
+ rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg);
spin_unlock(&rt2x00dev->irqmask_lock);
return IRQ_HANDLED;
@@ -956,28 +976,28 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
* This device has multiple filters for control frames
* and has a separate filter for PS Poll frames.
*/
- __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags);
- __set_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags);
+ __set_bit(CAPABILITY_CONTROL_FILTER_PSPOLL, &rt2x00dev->cap_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);
+ __set_bit(CAPABILITY_PRE_TBTT_INTERRUPT, &rt2x00dev->cap_flags);
/*
* This device requires firmware.
*/
if (!rt2x00_is_soc(rt2x00dev))
- __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
- __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
- __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
- __set_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags);
- __set_bit(DRIVER_REQUIRE_TASKLET_CONTEXT, &rt2x00dev->flags);
+ __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags);
+ __set_bit(REQUIRE_DMA, &rt2x00dev->cap_flags);
+ __set_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags);
+ __set_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags);
+ __set_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags);
if (!modparam_nohwcrypt)
- __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
- __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
- __set_bit(DRIVER_REQUIRE_HT_TX_DESC, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags);
+ __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags);
+ __set_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags);
/*
* Set the rssi offset.
@@ -1008,6 +1028,7 @@ static const struct ieee80211_ops rt2800pci_mac80211_ops = {
.ampdu_action = rt2800_ampdu_action,
.flush = rt2x00mac_flush,
.get_survey = rt2800_get_survey,
+ .get_ringparam = rt2x00mac_get_ringparam,
};
static const struct rt2800_ops rt2800pci_rt2800_ops = {
@@ -1043,9 +1064,11 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
.link_stats = rt2800_link_stats,
.reset_tuner = rt2800_reset_tuner,
.link_tuner = rt2800_link_tuner,
+ .gain_calibration = rt2800_gain_calibration,
.start_queue = rt2800pci_start_queue,
.kick_queue = rt2800pci_kick_queue,
.stop_queue = rt2800pci_stop_queue,
+ .flush_queue = rt2x00pci_flush_queue,
.write_tx_desc = rt2800pci_write_tx_desc,
.write_tx_data = rt2800_write_tx_data,
.write_beacon = rt2800_write_beacon,
@@ -1105,36 +1128,36 @@ static const struct rt2x00_ops rt2800pci_ops = {
*/
#ifdef CONFIG_PCI
static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
- { PCI_DEVICE(0x1814, 0x0601), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1814, 0x0681), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1814, 0x0701), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1814, 0x0781), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1814, 0x3090), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1814, 0x3091), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1814, 0x3092), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1432, 0x7708), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1432, 0x7727), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1432, 0x7728), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1432, 0x7738), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1432, 0x7748), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1432, 0x7758), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1432, 0x7768), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1462, 0x891a), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1a3b, 0x1059), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x0601) },
+ { PCI_DEVICE(0x1814, 0x0681) },
+ { PCI_DEVICE(0x1814, 0x0701) },
+ { PCI_DEVICE(0x1814, 0x0781) },
+ { PCI_DEVICE(0x1814, 0x3090) },
+ { PCI_DEVICE(0x1814, 0x3091) },
+ { PCI_DEVICE(0x1814, 0x3092) },
+ { PCI_DEVICE(0x1432, 0x7708) },
+ { PCI_DEVICE(0x1432, 0x7727) },
+ { PCI_DEVICE(0x1432, 0x7728) },
+ { PCI_DEVICE(0x1432, 0x7738) },
+ { PCI_DEVICE(0x1432, 0x7748) },
+ { PCI_DEVICE(0x1432, 0x7758) },
+ { PCI_DEVICE(0x1432, 0x7768) },
+ { PCI_DEVICE(0x1462, 0x891a) },
+ { PCI_DEVICE(0x1a3b, 0x1059) },
#ifdef CONFIG_RT2800PCI_RT33XX
- { PCI_DEVICE(0x1814, 0x3390), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x3390) },
#endif
#ifdef CONFIG_RT2800PCI_RT35XX
- { PCI_DEVICE(0x1432, 0x7711), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1432, 0x7722), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1814, 0x3060), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1814, 0x3062), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1814, 0x3562), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1814, 0x3592), PCI_DEVICE_DATA(&rt2800pci_ops) },
- { PCI_DEVICE(0x1814, 0x3593), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1432, 0x7711) },
+ { PCI_DEVICE(0x1432, 0x7722) },
+ { PCI_DEVICE(0x1814, 0x3060) },
+ { PCI_DEVICE(0x1814, 0x3062) },
+ { PCI_DEVICE(0x1814, 0x3562) },
+ { PCI_DEVICE(0x1814, 0x3592) },
+ { PCI_DEVICE(0x1814, 0x3593) },
#endif
#ifdef CONFIG_RT2800PCI_RT53XX
- { PCI_DEVICE(0x1814, 0x5390), PCI_DEVICE_DATA(&rt2800pci_ops) },
+ { PCI_DEVICE(0x1814, 0x5390) },
#endif
{ 0, }
};
@@ -1170,10 +1193,16 @@ static struct platform_driver rt2800soc_driver = {
#endif /* CONFIG_RALINK_RT288X || CONFIG_RALINK_RT305X */
#ifdef CONFIG_PCI
+static int rt2800pci_probe(struct pci_dev *pci_dev,
+ const struct pci_device_id *id)
+{
+ return rt2x00pci_probe(pci_dev, &rt2800pci_ops);
+}
+
static struct pci_driver rt2800pci_driver = {
.name = KBUILD_MODNAME,
.id_table = rt2800pci_device_table,
- .probe = rt2x00pci_probe,
+ .probe = rt2800pci_probe,
.remove = __devexit_p(rt2x00pci_remove),
.suspend = rt2x00pci_suspend,
.resume = rt2x00pci_resume,
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 37509d019910..ba82c972703a 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -59,16 +59,16 @@ static void rt2800usb_start_queue(struct data_queue *queue)
switch (queue->qid) {
case QID_RX:
- rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 1);
- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+ rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
break;
case QID_BEACON:
- rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
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);
+ rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg);
break;
default:
break;
@@ -82,16 +82,16 @@ static void rt2800usb_stop_queue(struct data_queue *queue)
switch (queue->qid) {
case QID_RX:
- rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00usb_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
rt2x00_set_field32(&reg, MAC_SYS_CTRL_ENABLE_RX, 0);
- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+ rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
break;
case QID_BEACON:
- rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00usb_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 0);
rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 0);
rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
- rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+ rt2x00usb_register_write(rt2x00dev, BCN_TIME_CFG, reg);
break;
default:
break;
@@ -99,6 +99,63 @@ static void rt2800usb_stop_queue(struct data_queue *queue)
}
/*
+ * test if there is an entry in any TX queue for which DMA is done
+ * but the TX status has not been returned yet
+ */
+static bool rt2800usb_txstatus_pending(struct rt2x00_dev *rt2x00dev)
+{
+ struct data_queue *queue;
+
+ tx_queue_for_each(rt2x00dev, queue) {
+ if (rt2x00queue_get_entry(queue, Q_INDEX_DMA_DONE) !=
+ rt2x00queue_get_entry(queue, Q_INDEX_DONE))
+ return true;
+ }
+ return false;
+}
+
+static bool rt2800usb_tx_sta_fifo_read_completed(struct rt2x00_dev *rt2x00dev,
+ int urb_status, u32 tx_status)
+{
+ if (urb_status) {
+ WARNING(rt2x00dev, "rt2x00usb_register_read_async failed: %d\n", urb_status);
+ return false;
+ }
+
+ /* try to read all TX_STA_FIFO entries before scheduling txdone_work */
+ if (rt2x00_get_field32(tx_status, TX_STA_FIFO_VALID)) {
+ if (!kfifo_put(&rt2x00dev->txstatus_fifo, &tx_status)) {
+ WARNING(rt2x00dev, "TX status FIFO overrun, "
+ "drop tx status report.\n");
+ queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
+ } else
+ return true;
+ } else if (!kfifo_is_empty(&rt2x00dev->txstatus_fifo)) {
+ queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
+ } else if (rt2800usb_txstatus_pending(rt2x00dev)) {
+ mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(2));
+ }
+
+ return false;
+}
+
+static void rt2800usb_tx_dma_done(struct queue_entry *entry)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+
+ rt2x00usb_register_read_async(rt2x00dev, TX_STA_FIFO,
+ rt2800usb_tx_sta_fifo_read_completed);
+}
+
+static void rt2800usb_tx_sta_fifo_timeout(unsigned long data)
+{
+ struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
+
+ rt2x00usb_register_read_async(rt2x00dev, TX_STA_FIFO,
+ rt2800usb_tx_sta_fifo_read_completed);
+}
+
+/*
* Firmware functions
*/
static char *rt2800usb_get_firmware_name(struct rt2x00_dev *rt2x00dev)
@@ -129,11 +186,11 @@ static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev,
/*
* Write firmware to device.
*/
- rt2800_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
- data + offset, length);
+ rt2x00usb_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);
+ rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
+ rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
/*
* Send firmware request to device to load firmware,
@@ -148,7 +205,7 @@ static int rt2800usb_write_firmware(struct rt2x00_dev *rt2x00dev,
}
msleep(10);
- rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
+ rt2x00usb_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
return 0;
}
@@ -166,22 +223,22 @@ static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev)
if (rt2800_wait_csr_ready(rt2x00dev))
return -EBUSY;
- rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
- rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000);
+ rt2x00usb_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
+ rt2x00usb_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000);
- rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
+ rt2x00usb_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
- rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00usb_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);
+ rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
- rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000);
+ rt2x00usb_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);
+ rt2x00usb_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
return 0;
}
@@ -193,7 +250,7 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev)
if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev)))
return -EIO;
- rt2800_register_read(rt2x00dev, USB_DMA_CFG, &reg);
+ rt2x00usb_register_read(rt2x00dev, USB_DMA_CFG, &reg);
rt2x00_set_field32(&reg, USB_DMA_CFG_PHY_CLEAR, 0);
rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_AGG_EN, 0);
rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_AGG_TIMEOUT, 128);
@@ -206,7 +263,7 @@ static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev)
/ 1024) - 3);
rt2x00_set_field32(&reg, USB_DMA_CFG_RX_BULK_EN, 1);
rt2x00_set_field32(&reg, USB_DMA_CFG_TX_BULK_EN, 1);
- rt2800_register_write(rt2x00dev, USB_DMA_CFG, reg);
+ rt2x00usb_register_write(rt2x00dev, USB_DMA_CFG, reg);
return rt2800_enable_radio(rt2x00dev);
}
@@ -282,12 +339,12 @@ static void rt2800usb_watchdog(struct rt2x00_dev *rt2x00dev)
unsigned int i;
u32 reg;
- rt2800_register_read(rt2x00dev, TXRXQ_PCNT, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRXQ_PCNT, &reg);
if (rt2x00_get_field32(reg, TXRXQ_PCNT_TX0Q)) {
WARNING(rt2x00dev, "TX HW queue 0 timed out,"
" invoke forced kick\n");
- rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40012);
+ rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf40012);
for (i = 0; i < 10; i++) {
udelay(10);
@@ -295,15 +352,15 @@ static void rt2800usb_watchdog(struct rt2x00_dev *rt2x00dev)
break;
}
- rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006);
+ rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf40006);
}
- rt2800_register_read(rt2x00dev, TXRXQ_PCNT, &reg);
+ rt2x00usb_register_read(rt2x00dev, TXRXQ_PCNT, &reg);
if (rt2x00_get_field32(reg, TXRXQ_PCNT_TX1Q)) {
WARNING(rt2x00dev, "TX HW queue 1 timed out,"
" invoke forced kick\n");
- rt2800_register_write(rt2x00dev, PBF_CFG, 0xf4000a);
+ rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf4000a);
for (i = 0; i < 10; i++) {
udelay(10);
@@ -311,7 +368,7 @@ static void rt2800usb_watchdog(struct rt2x00_dev *rt2x00dev)
break;
}
- rt2800_register_write(rt2x00dev, PBF_CFG, 0xf40006);
+ rt2x00usb_register_write(rt2x00dev, PBF_CFG, 0xf40006);
}
rt2x00usb_watchdog(rt2x00dev);
@@ -420,13 +477,24 @@ static void rt2800usb_work_txdone(struct work_struct *work)
while (!rt2x00queue_empty(queue)) {
entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
- if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
- !test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
+ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ break;
+ if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
+ rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
+ else if (rt2x00queue_status_timeout(entry))
+ rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN);
+ else
break;
-
- rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
}
}
+
+ /*
+ * The hw may delay sending the packet after DMA complete
+ * if the medium is busy, thus the TX_STA_FIFO entry is
+ * also delayed -> use a timer to retrieve it.
+ */
+ if (rt2800usb_txstatus_pending(rt2x00dev))
+ mod_timer(&rt2x00dev->txstatus_timer, jiffies + msecs_to_jiffies(2));
}
/*
@@ -553,19 +621,24 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
* This device has multiple filters for control frames
* and has a separate filter for PS Poll frames.
*/
- __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags);
- __set_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags);
+ __set_bit(CAPABILITY_CONTROL_FILTER_PSPOLL, &rt2x00dev->cap_flags);
/*
* This device requires firmware.
*/
- __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
- __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
+ __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags);
+ __set_bit(REQUIRE_L2PAD, &rt2x00dev->cap_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_bit(DRIVER_REQUIRE_HT_TX_DESC, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags);
+ __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags);
+ __set_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags);
+ __set_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags);
+ __set_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags);
+
+ setup_timer(&rt2x00dev->txstatus_timer,
+ rt2800usb_tx_sta_fifo_timeout,
+ (unsigned long) rt2x00dev);
/*
* Set the rssi offset.
@@ -602,6 +675,7 @@ static const struct ieee80211_ops rt2800usb_mac80211_ops = {
.ampdu_action = rt2800_ampdu_action,
.flush = rt2x00mac_flush,
.get_survey = rt2800_get_survey,
+ .get_ringparam = rt2x00mac_get_ringparam,
};
static const struct rt2800_ops rt2800usb_rt2800_ops = {
@@ -630,11 +704,13 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
.link_stats = rt2800_link_stats,
.reset_tuner = rt2800_reset_tuner,
.link_tuner = rt2800_link_tuner,
+ .gain_calibration = rt2800_gain_calibration,
.watchdog = rt2800usb_watchdog,
.start_queue = rt2800usb_start_queue,
.kick_queue = rt2x00usb_kick_queue,
.stop_queue = rt2800usb_stop_queue,
.flush_queue = rt2x00usb_flush_queue,
+ .tx_dma_done = rt2800usb_tx_dma_done,
.write_tx_desc = rt2800usb_write_tx_desc,
.write_tx_data = rt2800usb_write_tx_data,
.write_beacon = rt2800_write_beacon,
@@ -695,294 +771,340 @@ static const struct rt2x00_ops rt2800usb_ops = {
*/
static struct usb_device_id rt2800usb_device_table[] = {
/* Abocom */
- { USB_DEVICE(0x07b8, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07b8, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07b8, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07b8, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07b8, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1482, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x07b8, 0x2870) },
+ { USB_DEVICE(0x07b8, 0x2770) },
+ { USB_DEVICE(0x07b8, 0x3070) },
+ { USB_DEVICE(0x07b8, 0x3071) },
+ { USB_DEVICE(0x07b8, 0x3072) },
+ { USB_DEVICE(0x1482, 0x3c09) },
/* AirTies */
- { USB_DEVICE(0x1eda, 0x2310), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1eda, 0x2012) },
+ { USB_DEVICE(0x1eda, 0x2310) },
/* Allwin */
- { USB_DEVICE(0x8516, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x8516, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x8516, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x8516, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x8516, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x8516, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x8516, 0x2070) },
+ { USB_DEVICE(0x8516, 0x2770) },
+ { USB_DEVICE(0x8516, 0x2870) },
+ { USB_DEVICE(0x8516, 0x3070) },
+ { USB_DEVICE(0x8516, 0x3071) },
+ { USB_DEVICE(0x8516, 0x3072) },
+ /* Alpha Networks */
+ { USB_DEVICE(0x14b2, 0x3c06) },
+ { USB_DEVICE(0x14b2, 0x3c07) },
+ { USB_DEVICE(0x14b2, 0x3c09) },
+ { USB_DEVICE(0x14b2, 0x3c12) },
+ { USB_DEVICE(0x14b2, 0x3c23) },
+ { USB_DEVICE(0x14b2, 0x3c25) },
+ { USB_DEVICE(0x14b2, 0x3c27) },
+ { USB_DEVICE(0x14b2, 0x3c28) },
+ { USB_DEVICE(0x14b2, 0x3c2c) },
/* Amit */
- { USB_DEVICE(0x15c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x15c5, 0x0008) },
/* Askey */
- { USB_DEVICE(0x1690, 0x0740), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1690, 0x0740) },
/* ASUS */
- { USB_DEVICE(0x0b05, 0x1731), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0b05, 0x1732), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0b05, 0x1742), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0b05, 0x1784), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1761, 0x0b05), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0b05, 0x1731) },
+ { USB_DEVICE(0x0b05, 0x1732) },
+ { USB_DEVICE(0x0b05, 0x1742) },
+ { USB_DEVICE(0x0b05, 0x1784) },
+ { USB_DEVICE(0x1761, 0x0b05) },
/* AzureWave */
- { USB_DEVICE(0x13d3, 0x3247), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x13d3, 0x3273), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x13d3, 0x3305), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x13d3, 0x3307), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x13d3, 0x3321), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x13d3, 0x3247) },
+ { USB_DEVICE(0x13d3, 0x3273) },
+ { USB_DEVICE(0x13d3, 0x3305) },
+ { USB_DEVICE(0x13d3, 0x3307) },
+ { USB_DEVICE(0x13d3, 0x3321) },
/* Belkin */
- { USB_DEVICE(0x050d, 0x8053), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x050d, 0x805c), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x050d, 0x815c), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x050d, 0x825b), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x050d, 0x935a), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x050d, 0x935b), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x050d, 0x8053) },
+ { USB_DEVICE(0x050d, 0x805c) },
+ { USB_DEVICE(0x050d, 0x815c) },
+ { USB_DEVICE(0x050d, 0x825b) },
+ { USB_DEVICE(0x050d, 0x935a) },
+ { USB_DEVICE(0x050d, 0x935b) },
/* Buffalo */
- { USB_DEVICE(0x0411, 0x00e8), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0411, 0x016f), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* Conceptronic */
- { USB_DEVICE(0x14b2, 0x3c06), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x14b2, 0x3c07), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x14b2, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x14b2, 0x3c12), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x14b2, 0x3c23), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x14b2, 0x3c25), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x14b2, 0x3c27), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x14b2, 0x3c28), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0411, 0x00e8) },
+ { USB_DEVICE(0x0411, 0x016f) },
+ { USB_DEVICE(0x0411, 0x01a2) },
/* Corega */
- { USB_DEVICE(0x07aa, 0x002f), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07aa, 0x003c), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07aa, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x18c5, 0x0012), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x07aa, 0x002f) },
+ { USB_DEVICE(0x07aa, 0x003c) },
+ { USB_DEVICE(0x07aa, 0x003f) },
+ { USB_DEVICE(0x18c5, 0x0012) },
/* D-Link */
- { USB_DEVICE(0x07d1, 0x3c09), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07d1, 0x3c0a), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07d1, 0x3c0d), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07d1, 0x3c0e), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07d1, 0x3c0f), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07d1, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07d1, 0x3c16), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x07d1, 0x3c09) },
+ { USB_DEVICE(0x07d1, 0x3c0a) },
+ { USB_DEVICE(0x07d1, 0x3c0d) },
+ { USB_DEVICE(0x07d1, 0x3c0e) },
+ { USB_DEVICE(0x07d1, 0x3c0f) },
+ { USB_DEVICE(0x07d1, 0x3c11) },
+ { USB_DEVICE(0x07d1, 0x3c16) },
/* Draytek */
- { USB_DEVICE(0x07fa, 0x7712), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x07fa, 0x7712) },
/* Edimax */
- { USB_DEVICE(0x7392, 0x7711), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x7392, 0x7717), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x7392, 0x7718), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x7392, 0x7711) },
+ { USB_DEVICE(0x7392, 0x7717) },
+ { USB_DEVICE(0x7392, 0x7718) },
/* Encore */
- { USB_DEVICE(0x203d, 0x1480), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x203d, 0x14a9), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x203d, 0x1480) },
+ { USB_DEVICE(0x203d, 0x14a9) },
/* EnGenius */
- { USB_DEVICE(0x1740, 0x9701), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1740, 0x9702), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1740, 0x9703), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1740, 0x9705), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1740, 0x9706), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1740, 0x9707), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1740, 0x9708), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1740, 0x9709), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1740, 0x9701) },
+ { USB_DEVICE(0x1740, 0x9702) },
+ { USB_DEVICE(0x1740, 0x9703) },
+ { USB_DEVICE(0x1740, 0x9705) },
+ { USB_DEVICE(0x1740, 0x9706) },
+ { USB_DEVICE(0x1740, 0x9707) },
+ { USB_DEVICE(0x1740, 0x9708) },
+ { USB_DEVICE(0x1740, 0x9709) },
+ /* Gemtek */
+ { USB_DEVICE(0x15a9, 0x0012) },
/* Gigabyte */
- { USB_DEVICE(0x1044, 0x800b), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1044, 0x800d), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1044, 0x800b) },
+ { USB_DEVICE(0x1044, 0x800d) },
/* Hawking */
- { USB_DEVICE(0x0e66, 0x0001), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0e66, 0x0003), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0e66, 0x0009), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0e66, 0x000b), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0e66, 0x0013), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0e66, 0x0017), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0e66, 0x0018), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0e66, 0x0001) },
+ { USB_DEVICE(0x0e66, 0x0003) },
+ { USB_DEVICE(0x0e66, 0x0009) },
+ { USB_DEVICE(0x0e66, 0x000b) },
+ { USB_DEVICE(0x0e66, 0x0013) },
+ { USB_DEVICE(0x0e66, 0x0017) },
+ { USB_DEVICE(0x0e66, 0x0018) },
/* I-O DATA */
- { USB_DEVICE(0x04bb, 0x0945), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x04bb, 0x0947), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x04bb, 0x0948), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x04bb, 0x0945) },
+ { USB_DEVICE(0x04bb, 0x0947) },
+ { USB_DEVICE(0x04bb, 0x0948) },
/* Linksys */
- { USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x13b1, 0x0031) },
+ { USB_DEVICE(0x1737, 0x0070) },
+ { USB_DEVICE(0x1737, 0x0071) },
/* Logitec */
- { USB_DEVICE(0x0789, 0x0162), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0789, 0x0163), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0789, 0x0164), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0789, 0x0166), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0789, 0x0162) },
+ { USB_DEVICE(0x0789, 0x0163) },
+ { USB_DEVICE(0x0789, 0x0164) },
+ { USB_DEVICE(0x0789, 0x0166) },
/* Motorola */
- { USB_DEVICE(0x100d, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x100d, 0x9031) },
/* MSI */
- { USB_DEVICE(0x0db0, 0x3820), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x3821), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x3822), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x3870), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x3871), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x6899), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x821a), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x822a), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x822b), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x822c), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x870a), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x871a), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x871b), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x871c), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0db0, 0x899a), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0db0, 0x3820) },
+ { USB_DEVICE(0x0db0, 0x3821) },
+ { USB_DEVICE(0x0db0, 0x3822) },
+ { USB_DEVICE(0x0db0, 0x3870) },
+ { USB_DEVICE(0x0db0, 0x3871) },
+ { USB_DEVICE(0x0db0, 0x6899) },
+ { USB_DEVICE(0x0db0, 0x821a) },
+ { USB_DEVICE(0x0db0, 0x822a) },
+ { USB_DEVICE(0x0db0, 0x822b) },
+ { USB_DEVICE(0x0db0, 0x822c) },
+ { USB_DEVICE(0x0db0, 0x870a) },
+ { USB_DEVICE(0x0db0, 0x871a) },
+ { USB_DEVICE(0x0db0, 0x871b) },
+ { USB_DEVICE(0x0db0, 0x871c) },
+ { USB_DEVICE(0x0db0, 0x899a) },
/* Para */
- { USB_DEVICE(0x20b8, 0x8888), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x20b8, 0x8888) },
/* Pegatron */
- { USB_DEVICE(0x1d4d, 0x000c), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1d4d, 0x000e), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1d4d, 0x0011), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1d4d, 0x000c) },
+ { USB_DEVICE(0x1d4d, 0x000e) },
+ { USB_DEVICE(0x1d4d, 0x0011) },
/* Philips */
- { USB_DEVICE(0x0471, 0x200f), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0471, 0x200f) },
/* Planex */
- { USB_DEVICE(0x2019, 0xab25), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x2019, 0xed06), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x2019, 0xab25) },
+ { USB_DEVICE(0x2019, 0xed06) },
/* Quanta */
- { USB_DEVICE(0x1a32, 0x0304), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1a32, 0x0304) },
/* Ralink */
- { USB_DEVICE(0x148f, 0x2070), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x148f, 0x2770), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x148f, 0x2870), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x148f, 0x3070), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x148f, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x148f, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x148f, 0x2070) },
+ { USB_DEVICE(0x148f, 0x2770) },
+ { USB_DEVICE(0x148f, 0x2870) },
+ { USB_DEVICE(0x148f, 0x3070) },
+ { USB_DEVICE(0x148f, 0x3071) },
+ { USB_DEVICE(0x148f, 0x3072) },
/* Samsung */
- { USB_DEVICE(0x04e8, 0x2018), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x04e8, 0x2018) },
/* Siemens */
- { USB_DEVICE(0x129b, 0x1828), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x129b, 0x1828) },
/* Sitecom */
- { USB_DEVICE(0x0df6, 0x0017), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0df6, 0x002b), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0df6, 0x002c), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0df6, 0x002d), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0df6, 0x0039), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0df6, 0x003b), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0df6, 0x003d), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0df6, 0x003e), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0df6, 0x003f), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0df6, 0x0040), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0df6, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0df6, 0x0047), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0df6, 0x0048), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0df6, 0x0017) },
+ { USB_DEVICE(0x0df6, 0x002b) },
+ { USB_DEVICE(0x0df6, 0x002c) },
+ { USB_DEVICE(0x0df6, 0x002d) },
+ { USB_DEVICE(0x0df6, 0x0039) },
+ { USB_DEVICE(0x0df6, 0x003b) },
+ { USB_DEVICE(0x0df6, 0x003d) },
+ { USB_DEVICE(0x0df6, 0x003e) },
+ { USB_DEVICE(0x0df6, 0x003f) },
+ { USB_DEVICE(0x0df6, 0x0040) },
+ { USB_DEVICE(0x0df6, 0x0042) },
+ { USB_DEVICE(0x0df6, 0x0047) },
+ { USB_DEVICE(0x0df6, 0x0048) },
+ { USB_DEVICE(0x0df6, 0x0051) },
+ { USB_DEVICE(0x0df6, 0x005f) },
/* SMC */
- { USB_DEVICE(0x083a, 0x6618), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x083a, 0x7511), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x083a, 0x7512), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x083a, 0x7522), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x083a, 0x8522), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x083a, 0xa618), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x083a, 0xa701), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x083a, 0xa702), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x083a, 0xa703), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x083a, 0xb522), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x083a, 0x6618) },
+ { USB_DEVICE(0x083a, 0x7511) },
+ { USB_DEVICE(0x083a, 0x7512) },
+ { USB_DEVICE(0x083a, 0x7522) },
+ { USB_DEVICE(0x083a, 0x8522) },
+ { USB_DEVICE(0x083a, 0xa618) },
+ { USB_DEVICE(0x083a, 0xa701) },
+ { USB_DEVICE(0x083a, 0xa702) },
+ { USB_DEVICE(0x083a, 0xa703) },
+ { USB_DEVICE(0x083a, 0xb522) },
/* Sparklan */
- { USB_DEVICE(0x15a9, 0x0006), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x15a9, 0x0006) },
/* Sweex */
- { USB_DEVICE(0x177f, 0x0302), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* U-Media*/
- { USB_DEVICE(0x157e, 0x300e), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x177f, 0x0302) },
+ /* U-Media */
+ { USB_DEVICE(0x157e, 0x300e) },
+ { USB_DEVICE(0x157e, 0x3013) },
/* ZCOM */
- { USB_DEVICE(0x0cde, 0x0022), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0cde, 0x0025), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0cde, 0x0022) },
+ { USB_DEVICE(0x0cde, 0x0025) },
/* Zinwell */
- { USB_DEVICE(0x5a57, 0x0280), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x5a57, 0x0282), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x5a57, 0x0283), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x5a57, 0x5257), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x5a57, 0x0280) },
+ { USB_DEVICE(0x5a57, 0x0282) },
+ { USB_DEVICE(0x5a57, 0x0283) },
+ { USB_DEVICE(0x5a57, 0x5257) },
/* Zyxel */
- { USB_DEVICE(0x0586, 0x3416), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0586, 0x3416) },
+ { USB_DEVICE(0x0586, 0x3418) },
+ { USB_DEVICE(0x0586, 0x341e) },
+ { USB_DEVICE(0x0586, 0x343e) },
#ifdef CONFIG_RT2800USB_RT33XX
/* Ralink */
- { USB_DEVICE(0x148f, 0x3370), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x148f, 0x8070), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x148f, 0x3370) },
+ { USB_DEVICE(0x148f, 0x8070) },
/* Sitecom */
- { USB_DEVICE(0x0df6, 0x0050), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0df6, 0x0050) },
#endif
#ifdef CONFIG_RT2800USB_RT35XX
/* Allwin */
- { USB_DEVICE(0x8516, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x8516, 0x3572) },
/* Askey */
- { USB_DEVICE(0x1690, 0x0744), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1690, 0x0744) },
/* Cisco */
- { USB_DEVICE(0x167b, 0x4001), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x167b, 0x4001) },
/* EnGenius */
- { USB_DEVICE(0x1740, 0x9801), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1740, 0x9801) },
/* I-O DATA */
- { USB_DEVICE(0x04bb, 0x0944), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x04bb, 0x0944) },
+ /* Linksys */
+ { USB_DEVICE(0x13b1, 0x002f) },
+ { USB_DEVICE(0x1737, 0x0079) },
/* Ralink */
- { USB_DEVICE(0x148f, 0x3572), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x148f, 0x3572) },
/* Sitecom */
- { USB_DEVICE(0x0df6, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0df6, 0x0041) },
/* Toshiba */
- { USB_DEVICE(0x0930, 0x0a07), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0930, 0x0a07) },
/* Zinwell */
- { USB_DEVICE(0x5a57, 0x0284), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x5a57, 0x0284) },
+#endif
+#ifdef CONFIG_RT2800USB_RT53XX
+ /* Azurewave */
+ { USB_DEVICE(0x13d3, 0x3329) },
+ { USB_DEVICE(0x13d3, 0x3365) },
+ /* Ralink */
+ { USB_DEVICE(0x148f, 0x5370) },
+ { USB_DEVICE(0x148f, 0x5372) },
#endif
#ifdef CONFIG_RT2800USB_UNKNOWN
/*
* Unclear what kind of devices these are (they aren't supported by the
* vendor linux driver).
*/
+ /* Abocom */
+ { USB_DEVICE(0x07b8, 0x3073) },
+ { USB_DEVICE(0x07b8, 0x3074) },
+ /* Alpha Networks */
+ { USB_DEVICE(0x14b2, 0x3c08) },
+ { USB_DEVICE(0x14b2, 0x3c11) },
/* Amigo */
- { USB_DEVICE(0x0e0b, 0x9031), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0e0b, 0x9041), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0e0b, 0x9031) },
+ { USB_DEVICE(0x0e0b, 0x9041) },
/* ASUS */
- { USB_DEVICE(0x0b05, 0x1760), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0b05, 0x1761), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0b05, 0x1790), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0b05, 0x166a) },
+ { USB_DEVICE(0x0b05, 0x1760) },
+ { USB_DEVICE(0x0b05, 0x1761) },
+ { USB_DEVICE(0x0b05, 0x1790) },
+ { USB_DEVICE(0x0b05, 0x179d) },
/* AzureWave */
- { USB_DEVICE(0x13d3, 0x3262), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x13d3, 0x3284), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x13d3, 0x3322), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x13d3, 0x3262) },
+ { USB_DEVICE(0x13d3, 0x3284) },
+ { USB_DEVICE(0x13d3, 0x3322) },
/* Belkin */
- { USB_DEVICE(0x050d, 0x825a), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x050d, 0x1003) },
+ { USB_DEVICE(0x050d, 0x825a) },
/* Buffalo */
- { USB_DEVICE(0x0411, 0x012e), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0411, 0x0148), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0411, 0x0150), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x0411, 0x015d), USB_DEVICE_DATA(&rt2800usb_ops) },
- /* Conceptronic */
- { USB_DEVICE(0x14b2, 0x3c08), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x14b2, 0x3c11), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0411, 0x012e) },
+ { USB_DEVICE(0x0411, 0x0148) },
+ { USB_DEVICE(0x0411, 0x0150) },
+ { USB_DEVICE(0x0411, 0x015d) },
/* Corega */
- { USB_DEVICE(0x07aa, 0x0041), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07aa, 0x0042), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x18c5, 0x0008), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x07aa, 0x0041) },
+ { USB_DEVICE(0x07aa, 0x0042) },
+ { USB_DEVICE(0x18c5, 0x0008) },
/* D-Link */
- { USB_DEVICE(0x07d1, 0x3c0b), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07d1, 0x3c13), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07d1, 0x3c15), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x07d1, 0x3c17), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x07d1, 0x3c0b) },
+ { USB_DEVICE(0x07d1, 0x3c13) },
+ { USB_DEVICE(0x07d1, 0x3c15) },
+ { USB_DEVICE(0x07d1, 0x3c17) },
+ { USB_DEVICE(0x2001, 0x3c17) },
/* Edimax */
- { USB_DEVICE(0x7392, 0x4085), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x7392, 0x4085) },
+ { USB_DEVICE(0x7392, 0x7722) },
/* Encore */
- { USB_DEVICE(0x203d, 0x14a1), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x203d, 0x14a1) },
/* Gemtek */
- { USB_DEVICE(0x15a9, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x15a9, 0x0010) },
/* Gigabyte */
- { USB_DEVICE(0x1044, 0x800c), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1044, 0x800c) },
+ /* Huawei */
+ { USB_DEVICE(0x148f, 0xf101) },
+ /* I-O DATA */
+ { USB_DEVICE(0x04bb, 0x094b) },
/* LevelOne */
- { USB_DEVICE(0x1740, 0x0605), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1740, 0x0615), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1740, 0x0605) },
+ { USB_DEVICE(0x1740, 0x0615) },
/* Linksys */
- { USB_DEVICE(0x1737, 0x0077), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1737, 0x0078), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1737, 0x0079), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1737, 0x0077) },
+ { USB_DEVICE(0x1737, 0x0078) },
+ /* Logitec */
+ { USB_DEVICE(0x0789, 0x0168) },
+ { USB_DEVICE(0x0789, 0x0169) },
/* Motorola */
- { USB_DEVICE(0x100d, 0x9032), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x100d, 0x9032) },
/* Ovislink */
- { USB_DEVICE(0x1b75, 0x3071), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1b75, 0x3072), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x1b75, 0x3071) },
+ { USB_DEVICE(0x1b75, 0x3072) },
/* Pegatron */
- { USB_DEVICE(0x05a6, 0x0101), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1d4d, 0x0002), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x1d4d, 0x0010), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x05a6, 0x0101) },
+ { USB_DEVICE(0x1d4d, 0x0002) },
+ { USB_DEVICE(0x1d4d, 0x0010) },
/* Planex */
- { USB_DEVICE(0x2019, 0x5201), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x2019, 0xab24), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x2019, 0x5201) },
+ { USB_DEVICE(0x2019, 0xab24) },
/* Qcom */
- { USB_DEVICE(0x18e8, 0x6259), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x18e8, 0x6259) },
+ /* RadioShack */
+ { USB_DEVICE(0x08b9, 0x1197) },
+ /* Sitecom */
+ { USB_DEVICE(0x0df6, 0x003c) },
+ { USB_DEVICE(0x0df6, 0x004a) },
+ { USB_DEVICE(0x0df6, 0x004d) },
+ { USB_DEVICE(0x0df6, 0x0053) },
+ { USB_DEVICE(0x0df6, 0x0060) },
+ { USB_DEVICE(0x0df6, 0x0062) },
/* SMC */
- { USB_DEVICE(0x083a, 0xa512), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x083a, 0xc522), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x083a, 0xd522), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x083a, 0xf511), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x083a, 0xa512) },
+ { USB_DEVICE(0x083a, 0xc522) },
+ { USB_DEVICE(0x083a, 0xd522) },
+ { USB_DEVICE(0x083a, 0xf511) },
/* Sweex */
- { USB_DEVICE(0x177f, 0x0153), USB_DEVICE_DATA(&rt2800usb_ops) },
- { USB_DEVICE(0x177f, 0x0313), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x177f, 0x0153) },
+ { USB_DEVICE(0x177f, 0x0313) },
/* Zyxel */
- { USB_DEVICE(0x0586, 0x341a), USB_DEVICE_DATA(&rt2800usb_ops) },
+ { USB_DEVICE(0x0586, 0x341a) },
#endif
{ 0, }
};
@@ -995,10 +1117,16 @@ MODULE_DEVICE_TABLE(usb, rt2800usb_device_table);
MODULE_FIRMWARE(FIRMWARE_RT2870);
MODULE_LICENSE("GPL");
+static int rt2800usb_probe(struct usb_interface *usb_intf,
+ const struct usb_device_id *id)
+{
+ return rt2x00usb_probe(usb_intf, &rt2800usb_ops);
+}
+
static struct usb_driver rt2800usb_driver = {
.name = KBUILD_MODNAME,
.id_table = rt2800usb_device_table,
- .probe = rt2x00usb_probe,
+ .probe = rt2800usb_probe,
.disconnect = rt2x00usb_disconnect,
.suspend = rt2x00usb_suspend,
.resume = rt2x00usb_resume,
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 7f10239f56a8..c446db69bd3c 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -37,6 +37,7 @@
#include <linux/etherdevice.h>
#include <linux/input-polldev.h>
#include <linux/kfifo.h>
+#include <linux/timer.h>
#include <net/mac80211.h>
@@ -348,6 +349,11 @@ struct link {
* to bring the device/driver back into the desired state.
*/
struct delayed_work watchdog_work;
+
+ /*
+ * Work structure for scheduling periodic AGC adjustments.
+ */
+ struct delayed_work agc_work;
};
enum rt2x00_delayed_flags {
@@ -556,6 +562,7 @@ struct rt2x00lib_ops {
struct link_qual *qual);
void (*link_tuner) (struct rt2x00_dev *rt2x00dev,
struct link_qual *qual, const u32 count);
+ void (*gain_calibration) (struct rt2x00_dev *rt2x00dev);
/*
* Data queue handlers.
@@ -564,7 +571,8 @@ struct rt2x00lib_ops {
void (*start_queue) (struct data_queue *queue);
void (*kick_queue) (struct data_queue *queue);
void (*stop_queue) (struct data_queue *queue);
- void (*flush_queue) (struct data_queue *queue);
+ void (*flush_queue) (struct data_queue *queue, bool drop);
+ void (*tx_dma_done) (struct queue_entry *entry);
/*
* TX control handlers
@@ -637,11 +645,11 @@ struct rt2x00_ops {
};
/*
- * rt2x00 device flags
+ * rt2x00 state flags
*/
-enum rt2x00_flags {
+enum rt2x00_state_flags {
/*
- * Device state flags
+ * Device flags
*/
DEVICE_STATE_PRESENT,
DEVICE_STATE_REGISTERED_HW,
@@ -651,40 +659,47 @@ enum rt2x00_flags {
DEVICE_STATE_SCANNING,
/*
- * Driver requirements
- */
- DRIVER_REQUIRE_FIRMWARE,
- DRIVER_REQUIRE_BEACON_GUARD,
- DRIVER_REQUIRE_ATIM_QUEUE,
- DRIVER_REQUIRE_DMA,
- DRIVER_REQUIRE_COPY_IV,
- DRIVER_REQUIRE_L2PAD,
- DRIVER_REQUIRE_TXSTATUS_FIFO,
- DRIVER_REQUIRE_TASKLET_CONTEXT,
- DRIVER_REQUIRE_SW_SEQNO,
- DRIVER_REQUIRE_HT_TX_DESC,
-
- /*
- * Driver features
- */
- CONFIG_SUPPORT_HW_BUTTON,
- CONFIG_SUPPORT_HW_CRYPTO,
- CONFIG_SUPPORT_POWER_LIMIT,
- DRIVER_SUPPORT_CONTROL_FILTERS,
- DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL,
- DRIVER_SUPPORT_PRE_TBTT_INTERRUPT,
- DRIVER_SUPPORT_LINK_TUNING,
- DRIVER_SUPPORT_WATCHDOG,
-
- /*
* Driver configuration
*/
- CONFIG_FRAME_TYPE,
- CONFIG_RF_SEQUENCE,
- CONFIG_EXTERNAL_LNA_A,
- CONFIG_EXTERNAL_LNA_BG,
- CONFIG_DOUBLE_ANTENNA,
CONFIG_CHANNEL_HT40,
+ CONFIG_POWERSAVING,
+};
+
+/*
+ * rt2x00 capability flags
+ */
+enum rt2x00_capability_flags {
+ /*
+ * Requirements
+ */
+ REQUIRE_FIRMWARE,
+ REQUIRE_BEACON_GUARD,
+ REQUIRE_ATIM_QUEUE,
+ REQUIRE_DMA,
+ REQUIRE_COPY_IV,
+ REQUIRE_L2PAD,
+ REQUIRE_TXSTATUS_FIFO,
+ REQUIRE_TASKLET_CONTEXT,
+ REQUIRE_SW_SEQNO,
+ REQUIRE_HT_TX_DESC,
+ REQUIRE_PS_AUTOWAKE,
+
+ /*
+ * Capabilities
+ */
+ CAPABILITY_HW_BUTTON,
+ CAPABILITY_HW_CRYPTO,
+ CAPABILITY_POWER_LIMIT,
+ CAPABILITY_CONTROL_FILTERS,
+ CAPABILITY_CONTROL_FILTER_PSPOLL,
+ CAPABILITY_PRE_TBTT_INTERRUPT,
+ CAPABILITY_LINK_TUNING,
+ CAPABILITY_FRAME_TYPE,
+ CAPABILITY_RF_SEQUENCE,
+ CAPABILITY_EXTERNAL_LNA_A,
+ CAPABILITY_EXTERNAL_LNA_BG,
+ CAPABILITY_DOUBLE_ANTENNA,
+ CAPABILITY_BT_COEXIST,
};
/*
@@ -733,13 +748,20 @@ struct rt2x00_dev {
#endif /* CONFIG_RT2X00_LIB_LEDS */
/*
- * Device flags.
- * In these flags the current status and some
- * of the device capabilities are stored.
+ * Device state flags.
+ * In these flags the current status is stored.
+ * Access to these flags should occur atomically.
*/
unsigned long flags;
/*
+ * Device capabiltiy flags.
+ * In these flags the device/driver capabilities are stored.
+ * Access to these flags should occur non-atomically.
+ */
+ unsigned long cap_flags;
+
+ /*
* Device information, Bus IRQ and name (PCI, SoC)
*/
int irq;
@@ -855,10 +877,20 @@ struct rt2x00_dev {
u8 calibration[2];
/*
+ * Association id.
+ */
+ u16 aid;
+
+ /*
* Beacon interval.
*/
u16 beacon_int;
+ /**
+ * Timestamp of last received beacon
+ */
+ unsigned long last_beacon;
+
/*
* Low level statistics which will have
* to be kept up to date while device is running.
@@ -887,6 +919,11 @@ struct rt2x00_dev {
struct work_struct txdone_work;
/*
+ * Powersaving work
+ */
+ struct delayed_work autowakeup_work;
+
+ /*
* Data queue arrays for RX, TX, Beacon and ATIM.
*/
unsigned int data_queues;
@@ -906,6 +943,11 @@ struct rt2x00_dev {
DECLARE_KFIFO_PTR(txstatus_fifo, u32);
/*
+ * Timer to ensure tx status reports are read (rt2800usb).
+ */
+ struct timer_list txstatus_timer;
+
+ /*
* Tasklet for processing tx status reports (rt2800pci).
*/
struct tasklet_struct txstatus_tasklet;
@@ -1230,6 +1272,10 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
const struct ieee80211_tx_queue_params *params);
void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw);
void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop);
+int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant);
+int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
+void rt2x00mac_get_ringparam(struct ieee80211_hw *hw,
+ u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max);
/*
* Driver allocation handlers.
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index 9416e36de29e..555180d8f4aa 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -100,6 +100,10 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
erp.basic_rates = bss_conf->basic_rates;
erp.beacon_int = bss_conf->beacon_int;
+ /* Update the AID, this is needed for dynamic PS support */
+ rt2x00dev->aid = bss_conf->assoc ? bss_conf->aid : 0;
+ rt2x00dev->last_beacon = bss_conf->timestamp;
+
/* Update global beacon interval time, this is needed for PS support */
rt2x00dev->beacon_int = bss_conf->beacon_int;
@@ -109,15 +113,6 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp, changed);
}
-static inline
-enum antenna rt2x00lib_config_antenna_check(enum antenna current_ant,
- enum antenna default_ant)
-{
- if (current_ant != ANTENNA_SW_DIVERSITY)
- return current_ant;
- return (default_ant != ANTENNA_SW_DIVERSITY) ? default_ant : ANTENNA_B;
-}
-
void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
struct antenna_setup config)
{
@@ -126,19 +121,35 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
struct antenna_setup *active = &rt2x00dev->link.ant.active;
/*
- * Failsafe: Make sure we are not sending the
- * ANTENNA_SW_DIVERSITY state to the driver.
- * If that happens, fallback to hardware defaults,
- * or our own default.
+ * When the caller tries to send the SW diversity,
+ * we must update the ANTENNA_RX_DIVERSITY flag to
+ * enable the antenna diversity in the link tuner.
+ *
+ * Secondly, we must guarentee we never send the
+ * software antenna diversity command to the driver.
*/
- if (!(ant->flags & ANTENNA_RX_DIVERSITY))
- config.rx = rt2x00lib_config_antenna_check(config.rx, def->rx);
- else if (config.rx == ANTENNA_SW_DIVERSITY)
+ if (!(ant->flags & ANTENNA_RX_DIVERSITY)) {
+ if (config.rx == ANTENNA_SW_DIVERSITY) {
+ ant->flags |= ANTENNA_RX_DIVERSITY;
+
+ if (def->rx == ANTENNA_SW_DIVERSITY)
+ config.rx = ANTENNA_B;
+ else
+ config.rx = def->rx;
+ }
+ } else if (config.rx == ANTENNA_SW_DIVERSITY)
config.rx = active->rx;
- if (!(ant->flags & ANTENNA_TX_DIVERSITY))
- config.tx = rt2x00lib_config_antenna_check(config.tx, def->tx);
- else if (config.tx == ANTENNA_SW_DIVERSITY)
+ if (!(ant->flags & ANTENNA_TX_DIVERSITY)) {
+ if (config.tx == ANTENNA_SW_DIVERSITY) {
+ ant->flags |= ANTENNA_TX_DIVERSITY;
+
+ if (def->tx == ANTENNA_SW_DIVERSITY)
+ config.tx = ANTENNA_B;
+ else
+ config.tx = def->tx;
+ }
+ } else if (config.tx == ANTENNA_SW_DIVERSITY)
config.tx = active->tx;
/*
@@ -163,12 +174,43 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
rt2x00queue_start_queue(rt2x00dev->rx);
}
+static 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;
+}
+
void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
struct ieee80211_conf *conf,
unsigned int ieee80211_flags)
{
struct rt2x00lib_conf libconf;
u16 hw_value;
+ u16 autowake_timeout;
+ u16 beacon_int;
+ u16 beacon_diff;
memset(&libconf, 0, sizeof(libconf));
@@ -176,10 +218,10 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) {
if (conf_is_ht40(conf)) {
- __set_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags);
+ set_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags);
hw_value = rt2x00ht_center_channel(rt2x00dev, conf);
} else {
- __clear_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags);
+ clear_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags);
hw_value = conf->channel->hw_value;
}
@@ -192,6 +234,10 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
sizeof(libconf.channel));
}
+ if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) &&
+ (ieee80211_flags & IEEE80211_CONF_CHANGE_PS))
+ cancel_delayed_work_sync(&rt2x00dev->autowakeup_work);
+
/*
* Start configuration.
*/
@@ -204,6 +250,26 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL)
rt2x00link_reset_tuner(rt2x00dev, false);
+ if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) &&
+ (ieee80211_flags & IEEE80211_CONF_CHANGE_PS) &&
+ (conf->flags & IEEE80211_CONF_PS)) {
+ beacon_diff = (long)jiffies - (long)rt2x00dev->last_beacon;
+ beacon_int = msecs_to_jiffies(rt2x00dev->beacon_int);
+
+ if (beacon_diff > beacon_int)
+ beacon_diff = 0;
+
+ autowake_timeout = (conf->max_sleep_period * beacon_int) - beacon_diff;
+ queue_delayed_work(rt2x00dev->workqueue,
+ &rt2x00dev->autowakeup_work,
+ autowake_timeout - 15);
+ }
+
+ if (conf->flags & IEEE80211_CONF_PS)
+ set_bit(CONFIG_POWERSAVING, &rt2x00dev->flags);
+ else
+ clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags);
+
rt2x00dev->curr_band = conf->channel->band;
rt2x00dev->curr_freq = conf->channel->center_freq;
rt2x00dev->tx_power = conf->power_level;
diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c
index 3f5688fbf3f7..1bb9d46077ff 100644
--- a/drivers/net/wireless/rt2x00/rt2x00crypto.c
+++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c
@@ -52,7 +52,7 @@ void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry,
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
- if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !hw_key)
+ if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags) || !hw_key)
return;
__set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags);
@@ -80,7 +80,7 @@ unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev,
struct ieee80211_key_conf *key = tx_info->control.hw_key;
unsigned int overhead = 0;
- if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) || !key)
+ if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags) || !key)
return overhead;
/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index c92db3264741..78787fcc919e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -63,7 +63,8 @@ struct rt2x00debug_intf {
* - driver folder
* - driver file
* - chipset file
- * - device flags file
+ * - device state flags file
+ * - device capability flags file
* - register folder
* - csr offset/value files
* - eeprom offset/value files
@@ -78,6 +79,7 @@ struct rt2x00debug_intf {
struct dentry *driver_entry;
struct dentry *chipset_entry;
struct dentry *dev_flags;
+ struct dentry *cap_flags;
struct dentry *register_folder;
struct dentry *csr_off_entry;
struct dentry *csr_val_entry;
@@ -553,6 +555,35 @@ static const struct file_operations rt2x00debug_fop_dev_flags = {
.llseek = default_llseek,
};
+static ssize_t rt2x00debug_read_cap_flags(struct file *file,
+ char __user *buf,
+ size_t length,
+ loff_t *offset)
+{
+ struct rt2x00debug_intf *intf = file->private_data;
+ char line[16];
+ size_t size;
+
+ if (*offset)
+ return 0;
+
+ size = sprintf(line, "0x%.8x\n", (unsigned int)intf->rt2x00dev->cap_flags);
+
+ if (copy_to_user(buf, line, size))
+ return -EFAULT;
+
+ *offset += size;
+ return size;
+}
+
+static const struct file_operations rt2x00debug_fop_cap_flags = {
+ .owner = THIS_MODULE,
+ .read = rt2x00debug_read_cap_flags,
+ .open = rt2x00debug_file_open,
+ .release = rt2x00debug_file_release,
+ .llseek = default_llseek,
+};
+
static struct dentry *rt2x00debug_create_file_driver(const char *name,
struct rt2x00debug_intf
*intf,
@@ -568,7 +599,6 @@ static struct dentry *rt2x00debug_create_file_driver(const char *name,
blob->data = data;
data += sprintf(data, "driver:\t%s\n", intf->rt2x00dev->ops->name);
data += sprintf(data, "version:\t%s\n", DRV_VERSION);
- data += sprintf(data, "compiled:\t%s %s\n", __DATE__, __TIME__);
blob->size = strlen(blob->data);
return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob);
@@ -653,6 +683,12 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
if (IS_ERR(intf->dev_flags) || !intf->dev_flags)
goto exit;
+ intf->cap_flags = debugfs_create_file("cap_flags", S_IRUSR,
+ intf->driver_folder, intf,
+ &rt2x00debug_fop_cap_flags);
+ if (IS_ERR(intf->cap_flags) || !intf->cap_flags)
+ goto exit;
+
intf->register_folder =
debugfs_create_dir("register", intf->driver_folder);
if (IS_ERR(intf->register_folder) || !intf->register_folder)
@@ -706,7 +742,7 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
intf, &rt2x00debug_fop_queue_stats);
#ifdef CONFIG_RT2X00_LIB_CRYPTO
- if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags))
+ if (test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags))
intf->crypto_stats_entry =
debugfs_create_file("crypto", S_IRUGO, intf->queue_folder,
intf, &rt2x00debug_fop_crypto_stats);
@@ -744,6 +780,7 @@ void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
debugfs_remove(intf->csr_off_entry);
debugfs_remove(intf->register_folder);
debugfs_remove(intf->dev_flags);
+ debugfs_remove(intf->cap_flags);
debugfs_remove(intf->chipset_entry);
debugfs_remove(intf->driver_entry);
debugfs_remove(intf->driver_folder);
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 84eb6ad36377..c018d67aab8e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -27,6 +27,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/log2.h>
#include "rt2x00.h"
#include "rt2x00lib.h"
@@ -70,6 +71,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
*/
rt2x00queue_start_queues(rt2x00dev);
rt2x00link_start_tuner(rt2x00dev);
+ rt2x00link_start_agc(rt2x00dev);
/*
* Start watchdog monitoring.
@@ -92,6 +94,7 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
/*
* Stop all queues
*/
+ rt2x00link_stop_agc(rt2x00dev);
rt2x00link_stop_tuner(rt2x00dev);
rt2x00queue_stop_queues(rt2x00dev);
rt2x00queue_flush_queues(rt2x00dev, true);
@@ -138,6 +141,16 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work)
rt2x00dev);
}
+static void rt2x00lib_autowakeup(struct work_struct *work)
+{
+ struct rt2x00_dev *rt2x00dev =
+ container_of(work, struct rt2x00_dev, autowakeup_work.work);
+
+ if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
+ ERROR(rt2x00dev, "Device failed to wakeup.\n");
+ clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags);
+}
+
/*
* Interrupt context handlers.
*/
@@ -197,7 +210,7 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
* here as they will fetch the next beacon directly prior to
* transmission.
*/
- if (test_bit(DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, &rt2x00dev->flags))
+ if (test_bit(CAPABILITY_PRE_TBTT_INTERRUPT, &rt2x00dev->cap_flags))
return;
/* fetch next beacon */
@@ -222,7 +235,7 @@ EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt);
void rt2x00lib_dmastart(struct queue_entry *entry)
{
set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
- rt2x00queue_index_inc(entry->queue, Q_INDEX);
+ rt2x00queue_index_inc(entry, Q_INDEX);
}
EXPORT_SYMBOL_GPL(rt2x00lib_dmastart);
@@ -230,7 +243,7 @@ void rt2x00lib_dmadone(struct queue_entry *entry)
{
set_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags);
clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
- rt2x00queue_index_inc(entry->queue, Q_INDEX_DMA_DONE);
+ rt2x00queue_index_inc(entry, Q_INDEX_DMA_DONE);
}
EXPORT_SYMBOL_GPL(rt2x00lib_dmadone);
@@ -268,7 +281,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
/*
* Remove L2 padding which was added during
*/
- if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags))
+ if (test_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags))
rt2x00queue_remove_l2pad(entry->skb, header_length);
/*
@@ -277,7 +290,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
* 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))
+ if (test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags))
rt2x00crypto_tx_insert_iv(entry->skb, header_length);
/*
@@ -350,10 +363,14 @@ void rt2x00lib_txdone(struct queue_entry *entry,
* which would allow the rc algorithm to better decide on
* which rates are suitable.
*/
- if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
+ if (test_bit(TXDONE_AMPDU, &txdesc->flags) ||
+ 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 (!success)
+ tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
}
if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
@@ -370,7 +387,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
* send the status report back.
*/
if (!(skbdesc_flags & SKBDESC_NOT_MAC80211)) {
- if (test_bit(DRIVER_REQUIRE_TASKLET_CONTEXT, &rt2x00dev->flags))
+ if (test_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags))
ieee80211_tx_status(rt2x00dev->hw, entry->skb);
else
ieee80211_tx_status_ni(rt2x00dev->hw, entry->skb);
@@ -385,7 +402,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
rt2x00dev->ops->lib->clear_entry(entry);
- rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
+ rt2x00queue_index_inc(entry, Q_INDEX_DONE);
/*
* If the data queue was below the threshold before the txdone
@@ -409,6 +426,77 @@ void rt2x00lib_txdone_noinfo(struct queue_entry *entry, u32 status)
}
EXPORT_SYMBOL_GPL(rt2x00lib_txdone_noinfo);
+static u8 *rt2x00lib_find_ie(u8 *data, unsigned int len, u8 ie)
+{
+ struct ieee80211_mgmt *mgmt = (void *)data;
+ u8 *pos, *end;
+
+ pos = (u8 *)mgmt->u.beacon.variable;
+ end = data + len;
+ while (pos < end) {
+ if (pos + 2 + pos[1] > end)
+ return NULL;
+
+ if (pos[0] == ie)
+ return pos;
+
+ pos += 2 + pos[1];
+ }
+
+ return NULL;
+}
+
+static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev,
+ struct sk_buff *skb,
+ struct rxdone_entry_desc *rxdesc)
+{
+ struct ieee80211_hdr *hdr = (void *) skb->data;
+ struct ieee80211_tim_ie *tim_ie;
+ u8 *tim;
+ u8 tim_len;
+ bool cam;
+
+ /* If this is not a beacon, or if mac80211 has no powersaving
+ * configured, or if the device is already in powersaving mode
+ * we can exit now. */
+ if (likely(!ieee80211_is_beacon(hdr->frame_control) ||
+ !(rt2x00dev->hw->conf.flags & IEEE80211_CONF_PS)))
+ return;
+
+ /* min. beacon length + FCS_LEN */
+ if (skb->len <= 40 + FCS_LEN)
+ return;
+
+ /* and only beacons from the associated BSSID, please */
+ if (!(rxdesc->dev_flags & RXDONE_MY_BSS) ||
+ !rt2x00dev->aid)
+ return;
+
+ rt2x00dev->last_beacon = jiffies;
+
+ tim = rt2x00lib_find_ie(skb->data, skb->len - FCS_LEN, WLAN_EID_TIM);
+ if (!tim)
+ return;
+
+ if (tim[1] < sizeof(*tim_ie))
+ return;
+
+ tim_len = tim[1];
+ tim_ie = (struct ieee80211_tim_ie *) &tim[2];
+
+ /* Check whenever the PHY can be turned off again. */
+
+ /* 1. What about buffered unicast traffic for our AID? */
+ cam = ieee80211_check_tim(tim_ie, tim_len, rt2x00dev->aid);
+
+ /* 2. Maybe the AP wants to send multicast/broadcast data? */
+ cam |= (tim_ie->bitmap_ctrl & 0x01);
+
+ if (!cam && !test_bit(CONFIG_POWERSAVING, &rt2x00dev->flags))
+ rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf,
+ IEEE80211_CONF_CHANGE_PS);
+}
+
static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev,
struct rxdone_entry_desc *rxdesc)
{
@@ -511,8 +599,6 @@ void rt2x00lib_rxdone(struct queue_entry *entry)
(rxdesc.size > header_length) &&
(rxdesc.dev_flags & RXDONE_L2PAD))
rt2x00queue_remove_l2pad(entry->skb, header_length);
- else
- rt2x00queue_align_payload(entry->skb, header_length);
/* Trim buffer to correct size */
skb_trim(entry->skb, rxdesc.size);
@@ -526,6 +612,12 @@ void rt2x00lib_rxdone(struct queue_entry *entry)
rxdesc.flags |= RX_FLAG_HT;
/*
+ * Check if this is a beacon, and more frames have been
+ * buffered while we were in powersaving mode.
+ */
+ rt2x00lib_rxdone_check_ps(rt2x00dev, entry->skb, &rxdesc);
+
+ /*
* Update extra components
*/
rt2x00link_update_stats(rt2x00dev, entry->skb, &rxdesc);
@@ -554,7 +646,7 @@ void rt2x00lib_rxdone(struct queue_entry *entry)
submit_entry:
entry->flags = 0;
- rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE);
+ rt2x00queue_index_inc(entry, Q_INDEX_DONE);
if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
rt2x00dev->ops->lib->clear_entry(entry);
@@ -801,23 +893,28 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* Take TX headroom required for alignment into account.
*/
- if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags))
+ if (test_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags))
rt2x00dev->hw->extra_tx_headroom += RT2X00_L2PAD_SIZE;
- else if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags))
+ else if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags))
rt2x00dev->hw->extra_tx_headroom += RT2X00_ALIGN_SIZE;
/*
* Allocate tx status FIFO for driver use.
*/
- if (test_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags)) {
+ if (test_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags)) {
/*
- * Allocate txstatus fifo and tasklet, we use a size of 512
- * for the kfifo which is big enough to store 512/4=128 tx
- * status reports. In the worst case (tx status for all tx
- * queues gets reported before we've got a chance to handle
- * them) 24*4=384 tx status reports need to be cached.
+ * Allocate the txstatus fifo. In the worst case the tx
+ * status fifo has to hold the tx status of all entries
+ * in all tx queues. Hence, calculate the kfifo size as
+ * tx_queues * entry_num and round up to the nearest
+ * power of 2.
*/
- status = kfifo_alloc(&rt2x00dev->txstatus_fifo, 512,
+ int kfifo_size =
+ roundup_pow_of_two(rt2x00dev->ops->tx_queues *
+ rt2x00dev->ops->tx->entry_num *
+ sizeof(u32));
+
+ status = kfifo_alloc(&rt2x00dev->txstatus_fifo, kfifo_size,
GFP_KERNEL);
if (status)
return status;
@@ -1007,6 +1104,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
}
INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled);
+ INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup);
/*
* Let the driver probe the device to detect the capabilities.
@@ -1063,6 +1161,7 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
*/
cancel_work_sync(&rt2x00dev->intf_work);
if (rt2x00_is_usb(rt2x00dev)) {
+ del_timer_sync(&rt2x00dev->txstatus_timer);
cancel_work_sync(&rt2x00dev->rxdone_work);
cancel_work_sync(&rt2x00dev->txdone_work);
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c
index be0ff78c1b16..f316aad30612 100644
--- a/drivers/net/wireless/rt2x00/rt2x00firmware.c
+++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c
@@ -99,7 +99,7 @@ int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev)
{
int retval;
- if (!test_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags))
+ if (!test_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags))
return 0;
if (!rt2x00dev->fw) {
diff --git a/drivers/net/wireless/rt2x00/rt2x00ht.c b/drivers/net/wireless/rt2x00/rt2x00ht.c
deleted file mode 100644
index ae1219dffaae..000000000000
--- a/drivers/net/wireless/rt2x00/rt2x00ht.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
- <http://rt2x00.serialmonkey.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.
- */
-
-/*
- Module: rt2x00lib
- Abstract: rt2x00 HT specific routines.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-#include "rt2x00.h"
-#include "rt2x00lib.h"
-
-void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
- struct txentry_desc *txdesc,
- const struct rt2x00_rate *hwrate)
-{
- struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
- struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0];
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data;
-
- if (tx_info->control.sta)
- txdesc->u.ht.mpdu_density =
- tx_info->control.sta->ht_cap.ampdu_density;
-
- txdesc->u.ht.ba_size = 7; /* FIXME: What value is needed? */
-
- txdesc->u.ht.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->u.ht.mcs = txrate->idx;
-
- /*
- * MIMO PS should be set to 1 for STA's using dynamic SM PS
- * when using more then one tx stream (>MCS7).
- */
- if (tx_info->control.sta && txdesc->u.ht.mcs > 7 &&
- ((tx_info->control.sta->ht_cap.cap &
- IEEE80211_HT_CAP_SM_PS) >>
- IEEE80211_HT_CAP_SM_PS_SHIFT) ==
- WLAN_HT_CAP_SM_PS_DYNAMIC)
- __set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags);
- } else {
- txdesc->u.ht.mcs = rt2x00_get_rate_mcs(hwrate->mcs);
- if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
- txdesc->u.ht.mcs |= 0x08;
- }
-
- /*
- * This frame is eligible for an AMPDU, however, don't aggregate
- * frames that are intended to probe a specific tx rate.
- */
- if (tx_info->flags & IEEE80211_TX_CTL_AMPDU &&
- !(tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE))
- __set_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags);
-
- /*
- * Set 40Mhz mode if necessary (for legacy rates this will
- * duplicate the frame to both channels).
- */
- if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH ||
- txrate->flags & IEEE80211_TX_RC_DUP_DATA)
- __set_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags);
- if (txrate->flags & IEEE80211_TX_RC_SHORT_GI)
- __set_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags);
-
- /*
- * Determine IFS values
- * - Use TXOP_BACKOFF for management frames
- * - Use TXOP_SIFS for fragment bursts
- * - Use TXOP_HTTXOP for everything else
- *
- * Note: rt2800 devices won't use CTS protection (if used)
- * for frames not transmitted with TXOP_HTTXOP
- */
- if (ieee80211_is_mgmt(hdr->frame_control))
- txdesc->u.ht.txop = TXOP_BACKOFF;
- else if (!(tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT))
- txdesc->u.ht.txop = TXOP_SIFS;
- else
- txdesc->u.ht.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 2d94cbaf5f4a..322cc4f3de5d 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -32,6 +32,7 @@
*/
#define WATCHDOG_INTERVAL round_jiffies_relative(HZ)
#define LINK_TUNE_INTERVAL round_jiffies_relative(HZ)
+#define AGC_INTERVAL round_jiffies_relative(4 * HZ)
/*
* rt2x00_rate: Per rate device information
@@ -119,16 +120,6 @@ void rt2x00queue_free_skb(struct queue_entry *entry);
void rt2x00queue_align_frame(struct sk_buff *skb);
/**
- * rt2x00queue_align_payload - Align 802.11 payload to 4-byte boundary
- * @skb: The skb to align
- * @header_length: Length of 802.11 header
- *
- * Align the 802.11 payload to a 4-byte boundary, this could
- * mean the header is not aligned properly though.
- */
-void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length);
-
-/**
* rt2x00queue_insert_l2pad - Align 802.11 header & payload to 4-byte boundary
* @skb: The skb to align
* @header_length: Length of 802.11 header
@@ -184,14 +175,14 @@ int rt2x00queue_clear_beacon(struct rt2x00_dev *rt2x00dev,
/**
* rt2x00queue_index_inc - Index incrementation function
- * @queue: Queue (&struct data_queue) to perform the action on.
+ * @entry: Queue entry (&struct queue_entry) to perform the action on.
* @index: Index type (&enum queue_index) to perform the action on.
*
- * This function will increase the requested index on the queue,
+ * This function will increase the requested index on the entry's queue,
* it will grab the appropriate locks and handle queue overflow events by
* resetting the index to the start of the queue.
*/
-void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index);
+void rt2x00queue_index_inc(struct queue_entry *entry, enum queue_index index);
/**
* rt2x00queue_init_queues - Initialize all data queues
@@ -281,6 +272,18 @@ void rt2x00link_start_watchdog(struct rt2x00_dev *rt2x00dev);
void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev);
/**
+ * rt2x00link_start_agc - Start periodic gain calibration
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ */
+void rt2x00link_start_agc(struct rt2x00_dev *rt2x00dev);
+
+/**
+ * rt2x00link_stop_agc - Stop periodic gain calibration
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ */
+void rt2x00link_stop_agc(struct rt2x00_dev *rt2x00dev);
+
+/**
* rt2x00link_register - Initialize link tuning & watchdog functionality
* @rt2x00dev: Pointer to &struct rt2x00_dev.
*
@@ -385,41 +388,17 @@ static inline void rt2x00crypto_rx_insert_iv(struct sk_buff *skb,
#endif /* CONFIG_RT2X00_LIB_CRYPTO */
/*
- * HT handlers.
- */
-#ifdef CONFIG_RT2X00_LIB_HT
-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 */
-
-/*
* RFkill handlers.
*/
static inline void rt2x00rfkill_register(struct rt2x00_dev *rt2x00dev)
{
- if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+ if (test_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags))
wiphy_rfkill_start_polling(rt2x00dev->hw->wiphy);
}
static inline void rt2x00rfkill_unregister(struct rt2x00_dev *rt2x00dev)
{
- if (test_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags))
+ if (test_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags))
wiphy_rfkill_stop_polling(rt2x00dev->hw->wiphy);
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00link.c b/drivers/net/wireless/rt2x00/rt2x00link.c
index 29abfdeb0b65..ea10b0068f82 100644
--- a/drivers/net/wireless/rt2x00/rt2x00link.c
+++ b/drivers/net/wireless/rt2x00/rt2x00link.c
@@ -192,17 +192,7 @@ static bool rt2x00lib_antenna_diversity(struct rt2x00_dev *rt2x00dev)
/*
* Determine if software diversity is enabled for
* either the TX or RX antenna (or both).
- * Always perform this check since within the link
- * tuner interval the configuration might have changed.
*/
- ant->flags &= ~ANTENNA_RX_DIVERSITY;
- ant->flags &= ~ANTENNA_TX_DIVERSITY;
-
- if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY)
- ant->flags |= ANTENNA_RX_DIVERSITY;
- if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY)
- ant->flags |= ANTENNA_TX_DIVERSITY;
-
if (!(ant->flags & ANTENNA_RX_DIVERSITY) &&
!(ant->flags & ANTENNA_TX_DIVERSITY)) {
ant->flags = 0;
@@ -383,7 +373,7 @@ static void rt2x00link_tuner(struct work_struct *work)
* do not support link tuning at all, while other devices can disable
* the feature from the EEPROM.
*/
- if (test_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags))
+ if (test_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags))
rt2x00dev->ops->lib->link_tuner(rt2x00dev, qual, link->count);
/*
@@ -413,12 +403,11 @@ 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);
+ if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
+ rt2x00dev->ops->lib->watchdog)
+ ieee80211_queue_delayed_work(rt2x00dev->hw,
+ &link->watchdog_work,
+ WATCHDOG_INTERVAL);
}
void rt2x00link_stop_watchdog(struct rt2x00_dev *rt2x00dev)
@@ -447,8 +436,46 @@ static void rt2x00link_watchdog(struct work_struct *work)
WATCHDOG_INTERVAL);
}
+void rt2x00link_start_agc(struct rt2x00_dev *rt2x00dev)
+{
+ struct link *link = &rt2x00dev->link;
+
+ if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
+ rt2x00dev->ops->lib->gain_calibration)
+ ieee80211_queue_delayed_work(rt2x00dev->hw,
+ &link->agc_work,
+ AGC_INTERVAL);
+}
+
+void rt2x00link_stop_agc(struct rt2x00_dev *rt2x00dev)
+{
+ cancel_delayed_work_sync(&rt2x00dev->link.agc_work);
+}
+
+static void rt2x00link_agc(struct work_struct *work)
+{
+ struct rt2x00_dev *rt2x00dev =
+ container_of(work, struct rt2x00_dev, link.agc_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->gain_calibration(rt2x00dev);
+
+ if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
+ ieee80211_queue_delayed_work(rt2x00dev->hw,
+ &link->agc_work,
+ AGC_INTERVAL);
+}
+
void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
{
+ INIT_DELAYED_WORK(&rt2x00dev->link.agc_work, rt2x00link_agc);
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 661c6baad2b9..93bec140e598 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -119,7 +119,7 @@ void rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
* Use the ATIM queue if appropriate and present.
*/
if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM &&
- test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags))
+ test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags))
qid = QID_ATIM;
queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
@@ -158,7 +158,7 @@ void rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
return;
exit_fail:
- ieee80211_stop_queue(rt2x00dev->hw, qid);
+ rt2x00queue_pause_queue(queue);
dev_kfree_skb_any(skb);
}
EXPORT_SYMBOL_GPL(rt2x00mac_tx);
@@ -411,11 +411,11 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
* of different types, but has no a separate filter for PS Poll frames,
* FIF_CONTROL flag implies FIF_PSPOLL.
*/
- if (!test_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags)) {
+ if (!test_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags)) {
if (*total_flags & FIF_CONTROL || *total_flags & FIF_PSPOLL)
*total_flags |= FIF_CONTROL | FIF_PSPOLL;
}
- if (!test_bit(DRIVER_SUPPORT_CONTROL_FILTER_PSPOLL, &rt2x00dev->flags)) {
+ if (!test_bit(CAPABILITY_CONTROL_FILTER_PSPOLL, &rt2x00dev->cap_flags)) {
if (*total_flags & FIF_CONTROL)
*total_flags |= FIF_PSPOLL;
}
@@ -496,7 +496,7 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
return 0;
- else if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags))
+ else if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags))
return -EOPNOTSUPP;
else if (key->keylen > 32)
return -ENOSPC;
@@ -562,7 +562,7 @@ EXPORT_SYMBOL_GPL(rt2x00mac_set_key);
void rt2x00mac_sw_scan_start(struct ieee80211_hw *hw)
{
struct rt2x00_dev *rt2x00dev = hw->priv;
- __set_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags);
+ set_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags);
rt2x00link_stop_tuner(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_start);
@@ -570,7 +570,7 @@ 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);
+ clear_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags);
rt2x00link_start_tuner(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_complete);
@@ -737,3 +737,84 @@ void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop)
rt2x00queue_flush_queue(queue, drop);
}
EXPORT_SYMBOL_GPL(rt2x00mac_flush);
+
+int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct link_ant *ant = &rt2x00dev->link.ant;
+ struct antenna_setup *def = &rt2x00dev->default_ant;
+ struct antenna_setup setup;
+
+ // The antenna value is not supposed to be 0,
+ // or exceed the maximum number of antenna's.
+ if (!tx_ant || (tx_ant & ~3) || !rx_ant || (rx_ant & ~3))
+ return -EINVAL;
+
+ // When the client tried to configure the antenna to or from
+ // diversity mode, we must reset the default antenna as well
+ // as that controls the diversity switch.
+ if (ant->flags & ANTENNA_TX_DIVERSITY && tx_ant != 3)
+ ant->flags &= ~ANTENNA_TX_DIVERSITY;
+ if (ant->flags & ANTENNA_RX_DIVERSITY && rx_ant != 3)
+ ant->flags &= ~ANTENNA_RX_DIVERSITY;
+
+ // If diversity is being enabled, check if we need hardware
+ // or software diversity. In the latter case, reset the value,
+ // and make sure we update the antenna flags to have the
+ // link tuner pick up the diversity tuning.
+ if (tx_ant == 3 && def->tx == ANTENNA_SW_DIVERSITY) {
+ tx_ant = ANTENNA_SW_DIVERSITY;
+ ant->flags |= ANTENNA_TX_DIVERSITY;
+ }
+
+ if (rx_ant == 3 && def->rx == ANTENNA_SW_DIVERSITY) {
+ rx_ant = ANTENNA_SW_DIVERSITY;
+ ant->flags |= ANTENNA_RX_DIVERSITY;
+ }
+
+ setup.tx = tx_ant;
+ setup.rx = rx_ant;
+
+ rt2x00lib_config_antenna(rt2x00dev, setup);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_set_antenna);
+
+int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct link_ant *ant = &rt2x00dev->link.ant;
+ struct antenna_setup *active = &rt2x00dev->link.ant.active;
+
+ // When software diversity is active, we must report this to the
+ // client and not the current active antenna state.
+ if (ant->flags & ANTENNA_TX_DIVERSITY)
+ *tx_ant = ANTENNA_HW_DIVERSITY;
+ else
+ *tx_ant = active->tx;
+
+ if (ant->flags & ANTENNA_RX_DIVERSITY)
+ *rx_ant = ANTENNA_HW_DIVERSITY;
+ else
+ *rx_ant = active->rx;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_get_antenna);
+
+void rt2x00mac_get_ringparam(struct ieee80211_hw *hw,
+ u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max)
+{
+ struct rt2x00_dev *rt2x00dev = hw->priv;
+ struct data_queue *queue;
+
+ tx_queue_for_each(rt2x00dev, queue) {
+ *tx += queue->length;
+ *tx_max += queue->limit;
+ }
+
+ *rx = rt2x00dev->rx->length;
+ *rx_max = rt2x00dev->rx->limit;
+}
+EXPORT_SYMBOL_GPL(rt2x00mac_get_ringparam);
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index 4dd82b0b0520..17148bb24426 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -60,14 +60,15 @@ int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev,
}
EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read);
-void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
+bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue = rt2x00dev->rx;
struct queue_entry *entry;
struct queue_entry_priv_pci *entry_priv;
struct skb_frame_desc *skbdesc;
+ int max_rx = 16;
- while (1) {
+ while (--max_rx) {
entry = rt2x00queue_get_entry(queue, Q_INDEX);
entry_priv = entry->priv_data;
@@ -93,9 +94,20 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
*/
rt2x00lib_rxdone(entry);
}
+
+ return !max_rx;
}
EXPORT_SYMBOL_GPL(rt2x00pci_rxdone);
+void rt2x00pci_flush_queue(struct data_queue *queue, bool drop)
+{
+ unsigned int i;
+
+ for (i = 0; !rt2x00queue_empty(queue) && i < 10; i++)
+ msleep(10);
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_flush_queue);
+
/*
* Device initialization handlers.
*/
@@ -239,9 +251,8 @@ exit:
return -ENOMEM;
}
-int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
+int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops)
{
- struct rt2x00_ops *ops = (struct rt2x00_ops *)id->driver_data;
struct ieee80211_hw *hw;
struct rt2x00_dev *rt2x00dev;
int retval;
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h
index 746ce8fe8cf4..e2c99f2b9a14 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.h
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.h
@@ -101,8 +101,21 @@ struct queue_entry_priv_pci {
/**
* rt2x00pci_rxdone - Handle RX done events
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ *
+ * Returns true if there are still rx frames pending and false if all
+ * pending rx frames were processed.
+ */
+bool rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev);
+
+/**
+ * rt2x00pci_flush_queue - Flush data queue
+ * @queue: Data queue to stop
+ * @drop: True to drop all pending frames.
+ *
+ * This will wait for a maximum of 100ms, waiting for the queues
+ * to become empty.
*/
-void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev);
+void rt2x00pci_flush_queue(struct data_queue *queue, bool drop);
/*
* Device initialization handlers.
@@ -113,7 +126,7 @@ void rt2x00pci_uninitialize(struct rt2x00_dev *rt2x00dev);
/*
* PCI driver handlers.
*/
-int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id);
+int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops);
void rt2x00pci_remove(struct pci_dev *pci_dev);
#ifdef CONFIG_PM
int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state);
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 4358051bfe1a..ab8c16f8bcaf 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -60,7 +60,7 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry)
* at least 8 bytes bytes available in headroom for IV/EIV
* and 8 bytes for ICV data as tailroon.
*/
- if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) {
+ if (test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags)) {
head_size += 8;
tail_size += 8;
}
@@ -86,7 +86,7 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry)
memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->entry = entry;
- if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags)) {
+ if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags)) {
skbdesc->skb_dma = dma_map_single(rt2x00dev->dev,
skb->data,
skb->len,
@@ -148,19 +148,6 @@ void rt2x00queue_align_frame(struct sk_buff *skb)
skb_trim(skb, frame_length);
}
-void rt2x00queue_align_payload(struct sk_buff *skb, unsigned int header_length)
-{
- unsigned int frame_length = skb->len;
- unsigned int align = ALIGN_SIZE(skb, header_length);
-
- if (!align)
- return;
-
- skb_push(skb, align);
- memmove(skb->data, skb->data + align, frame_length);
- skb_trim(skb, frame_length);
-}
-
void rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int header_length)
{
unsigned int payload_length = skb->len - header_length;
@@ -226,7 +213,7 @@ static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry,
__set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags);
- if (!test_bit(DRIVER_REQUIRE_SW_SEQNO, &entry->queue->rt2x00dev->flags))
+ if (!test_bit(REQUIRE_SW_SEQNO, &entry->queue->rt2x00dev->cap_flags))
return;
/*
@@ -315,6 +302,85 @@ static void rt2x00queue_create_tx_descriptor_plcp(struct queue_entry *entry,
}
}
+static void rt2x00queue_create_tx_descriptor_ht(struct queue_entry *entry,
+ struct txentry_desc *txdesc,
+ const struct rt2x00_rate *hwrate)
+{
+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
+ struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0];
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data;
+
+ if (tx_info->control.sta)
+ txdesc->u.ht.mpdu_density =
+ tx_info->control.sta->ht_cap.ampdu_density;
+
+ txdesc->u.ht.ba_size = 7; /* FIXME: What value is needed? */
+
+ /*
+ * Only one STBC stream is supported for now.
+ */
+ if (tx_info->flags & IEEE80211_TX_CTL_STBC)
+ txdesc->u.ht.stbc = 1;
+
+ /*
+ * 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->u.ht.mcs = txrate->idx;
+
+ /*
+ * MIMO PS should be set to 1 for STA's using dynamic SM PS
+ * when using more then one tx stream (>MCS7).
+ */
+ if (tx_info->control.sta && txdesc->u.ht.mcs > 7 &&
+ ((tx_info->control.sta->ht_cap.cap &
+ IEEE80211_HT_CAP_SM_PS) >>
+ IEEE80211_HT_CAP_SM_PS_SHIFT) ==
+ WLAN_HT_CAP_SM_PS_DYNAMIC)
+ __set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags);
+ } else {
+ txdesc->u.ht.mcs = rt2x00_get_rate_mcs(hwrate->mcs);
+ if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
+ txdesc->u.ht.mcs |= 0x08;
+ }
+
+ /*
+ * This frame is eligible for an AMPDU, however, don't aggregate
+ * frames that are intended to probe a specific tx rate.
+ */
+ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU &&
+ !(tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE))
+ __set_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags);
+
+ /*
+ * Set 40Mhz mode if necessary (for legacy rates this will
+ * duplicate the frame to both channels).
+ */
+ if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH ||
+ txrate->flags & IEEE80211_TX_RC_DUP_DATA)
+ __set_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags);
+ if (txrate->flags & IEEE80211_TX_RC_SHORT_GI)
+ __set_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags);
+
+ /*
+ * Determine IFS values
+ * - Use TXOP_BACKOFF for management frames except beacons
+ * - Use TXOP_SIFS for fragment bursts
+ * - Use TXOP_HTTXOP for everything else
+ *
+ * Note: rt2800 devices won't use CTS protection (if used)
+ * for frames not transmitted with TXOP_HTTXOP
+ */
+ if (ieee80211_is_mgmt(hdr->frame_control) &&
+ !ieee80211_is_beacon(hdr->frame_control))
+ txdesc->u.ht.txop = TXOP_BACKOFF;
+ else if (!(tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT))
+ txdesc->u.ht.txop = TXOP_SIFS;
+ else
+ txdesc->u.ht.txop = TXOP_HTTXOP;
+}
+
static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
@@ -409,8 +475,8 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
rt2x00crypto_create_tx_descriptor(entry, txdesc);
rt2x00queue_create_tx_descriptor_seq(entry, txdesc);
- if (test_bit(DRIVER_REQUIRE_HT_TX_DESC, &rt2x00dev->flags))
- rt2x00ht_create_tx_descriptor(entry, txdesc, hwrate);
+ if (test_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags))
+ rt2x00queue_create_tx_descriptor_ht(entry, txdesc, hwrate);
else
rt2x00queue_create_tx_descriptor_plcp(entry, txdesc, hwrate);
}
@@ -449,7 +515,7 @@ static int rt2x00queue_write_tx_data(struct queue_entry *entry,
/*
* Map the skb to DMA.
*/
- if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags))
+ if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags))
rt2x00queue_map_txskb(entry);
return 0;
@@ -495,8 +561,11 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
struct skb_frame_desc *skbdesc;
u8 rate_idx, rate_flags;
- if (unlikely(rt2x00queue_full(queue)))
+ if (unlikely(rt2x00queue_full(queue))) {
+ ERROR(queue->rt2x00dev,
+ "Dropping frame due to full tx queue %d.\n", queue->qid);
return -ENOBUFS;
+ }
if (unlikely(test_and_set_bit(ENTRY_OWNER_DEVICE_DATA,
&entry->flags))) {
@@ -539,7 +608,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
*/
if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) &&
!test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) {
- if (test_bit(DRIVER_REQUIRE_COPY_IV, &queue->rt2x00dev->flags))
+ if (test_bit(REQUIRE_COPY_IV, &queue->rt2x00dev->cap_flags))
rt2x00crypto_tx_copy_iv(skb, &txdesc);
else
rt2x00crypto_tx_remove_iv(skb, &txdesc);
@@ -553,9 +622,9 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
* PCI and USB devices, while header alignment only is valid
* for PCI devices.
*/
- if (test_bit(DRIVER_REQUIRE_L2PAD, &queue->rt2x00dev->flags))
+ if (test_bit(REQUIRE_L2PAD, &queue->rt2x00dev->cap_flags))
rt2x00queue_insert_l2pad(entry->skb, txdesc.header_length);
- else if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags))
+ else if (test_bit(REQUIRE_DMA, &queue->rt2x00dev->cap_flags))
rt2x00queue_align_frame(entry->skb);
/*
@@ -571,7 +640,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
set_bit(ENTRY_DATA_PENDING, &entry->flags);
- rt2x00queue_index_inc(queue, Q_INDEX);
+ rt2x00queue_index_inc(entry, Q_INDEX);
rt2x00queue_write_tx_descriptor(entry, &txdesc);
rt2x00queue_kick_tx_queue(queue, &txdesc);
@@ -660,10 +729,12 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
return ret;
}
-void rt2x00queue_for_each_entry(struct data_queue *queue,
+bool rt2x00queue_for_each_entry(struct data_queue *queue,
enum queue_index start,
enum queue_index end,
- void (*fn)(struct queue_entry *entry))
+ void *data,
+ bool (*fn)(struct queue_entry *entry,
+ void *data))
{
unsigned long irqflags;
unsigned int index_start;
@@ -674,7 +745,7 @@ void rt2x00queue_for_each_entry(struct data_queue *queue,
ERROR(queue->rt2x00dev,
"Entry requested from invalid index range (%d - %d)\n",
start, end);
- return;
+ return true;
}
/*
@@ -693,15 +764,23 @@ void rt2x00queue_for_each_entry(struct data_queue *queue,
* send out all frames in the correct order.
*/
if (index_start < index_end) {
- for (i = index_start; i < index_end; i++)
- fn(&queue->entries[i]);
+ for (i = index_start; i < index_end; i++) {
+ if (fn(&queue->entries[i], data))
+ return true;
+ }
} else {
- for (i = index_start; i < queue->limit; i++)
- fn(&queue->entries[i]);
+ for (i = index_start; i < queue->limit; i++) {
+ if (fn(&queue->entries[i], data))
+ return true;
+ }
- for (i = 0; i < index_end; i++)
- fn(&queue->entries[i]);
+ for (i = 0; i < index_end; i++) {
+ if (fn(&queue->entries[i], data))
+ return true;
+ }
}
+
+ return false;
}
EXPORT_SYMBOL_GPL(rt2x00queue_for_each_entry);
@@ -727,8 +806,9 @@ struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
}
EXPORT_SYMBOL_GPL(rt2x00queue_get_entry);
-void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index)
+void rt2x00queue_index_inc(struct queue_entry *entry, enum queue_index index)
{
+ struct data_queue *queue = entry->queue;
unsigned long irqflags;
if (unlikely(index >= Q_INDEX_MAX)) {
@@ -743,7 +823,7 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index)
if (queue->index[index] >= queue->limit)
queue->index[index] = 0;
- queue->last_action[index] = jiffies;
+ entry->last_action = jiffies;
if (index == Q_INDEX) {
queue->length++;
@@ -848,7 +928,6 @@ EXPORT_SYMBOL_GPL(rt2x00queue_stop_queue);
void rt2x00queue_flush_queue(struct data_queue *queue, bool drop)
{
- unsigned int i;
bool started;
bool tx_queue =
(queue->qid == QID_AC_VO) ||
@@ -883,20 +962,12 @@ void rt2x00queue_flush_queue(struct data_queue *queue, bool drop)
}
/*
- * Check if driver supports flushing, we can only guarantee
- * full support for flushing if the driver is able
- * to cancel all pending frames (drop = true).
- */
- if (drop && queue->rt2x00dev->ops->lib->flush_queue)
- queue->rt2x00dev->ops->lib->flush_queue(queue);
-
- /*
- * When we don't want to drop any frames, or when
- * the driver doesn't fully flush the queue correcly,
- * we must wait for the queue to become empty.
+ * Check if driver supports flushing, if that is the case we can
+ * defer the flushing to the driver. Otherwise we must use the
+ * alternative which just waits for the queue to become empty.
*/
- for (i = 0; !rt2x00queue_empty(queue) && i < 100; i++)
- msleep(10);
+ if (likely(queue->rt2x00dev->ops->lib->flush_queue))
+ queue->rt2x00dev->ops->lib->flush_queue(queue, drop);
/*
* The queue flush has failed...
@@ -969,10 +1040,8 @@ static void rt2x00queue_reset(struct data_queue *queue)
queue->count = 0;
queue->length = 0;
- for (i = 0; i < Q_INDEX_MAX; i++) {
+ for (i = 0; i < Q_INDEX_MAX; i++)
queue->index[i] = 0;
- queue->last_action[i] = jiffies;
- }
spin_unlock_irqrestore(&queue->index_lock, irqflags);
}
@@ -1079,7 +1148,7 @@ int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev)
if (status)
goto exit;
- if (test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags)) {
+ if (test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags)) {
status = rt2x00queue_alloc_entries(rt2x00dev->atim,
rt2x00dev->ops->atim);
if (status)
@@ -1131,7 +1200,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
struct data_queue *queue;
enum data_queue_qid qid;
unsigned int req_atim =
- !!test_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags);
+ !!test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags);
/*
* We need the following queues:
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h
index 217861f8d95f..167d45873dca 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.h
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.h
@@ -217,6 +217,7 @@ enum txdone_entry_desc_flags {
TXDONE_FALLBACK,
TXDONE_FAILURE,
TXDONE_EXCESSIVE_RETRY,
+ TXDONE_AMPDU,
};
/**
@@ -363,6 +364,7 @@ enum queue_entry_flags {
* struct queue_entry: Entry inside the &struct data_queue
*
* @flags: Entry flags, see &enum queue_entry_flags.
+ * @last_action: Timestamp of last change.
* @queue: The data queue (&struct data_queue) to which this entry belongs.
* @skb: The buffer which is currently being transmitted (for TX queue),
* or used to directly receive data in (for RX queue).
@@ -372,6 +374,7 @@ enum queue_entry_flags {
*/
struct queue_entry {
unsigned long flags;
+ unsigned long last_action;
struct data_queue *queue;
@@ -462,7 +465,6 @@ struct data_queue {
unsigned short threshold;
unsigned short length;
unsigned short index[Q_INDEX_MAX];
- unsigned long last_action[Q_INDEX_MAX];
unsigned short txop;
unsigned short aifs;
@@ -579,16 +581,22 @@ struct data_queue_desc {
* @queue: Pointer to @data_queue
* @start: &enum queue_index Pointer to start index
* @end: &enum queue_index Pointer to end index
+ * @data: Data to pass to the callback function
* @fn: The function to call for each &struct queue_entry
*
* This will walk through all entries in the queue, in chronological
* order. This means it will start at the current @start pointer
* and will walk through the queue until it reaches the @end pointer.
+ *
+ * If fn returns true for an entry rt2x00queue_for_each_entry will stop
+ * processing and return true as well.
*/
-void rt2x00queue_for_each_entry(struct data_queue *queue,
+bool rt2x00queue_for_each_entry(struct data_queue *queue,
enum queue_index start,
enum queue_index end,
- void (*fn)(struct queue_entry *entry));
+ void *data,
+ bool (*fn)(struct queue_entry *entry,
+ void *data));
/**
* rt2x00queue_empty - Check if the queue is empty.
@@ -628,22 +636,24 @@ static inline int rt2x00queue_threshold(struct data_queue *queue)
/**
* rt2x00queue_status_timeout - Check if a timeout occurred for STATUS reports
- * @queue: Queue to check.
+ * @entry: Queue entry to check.
*/
-static inline int rt2x00queue_status_timeout(struct data_queue *queue)
+static inline int rt2x00queue_status_timeout(struct queue_entry *entry)
{
- return time_after(queue->last_action[Q_INDEX_DMA_DONE],
- queue->last_action[Q_INDEX_DONE] + (HZ / 10));
+ if (!test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
+ return false;
+ return time_after(jiffies, entry->last_action + msecs_to_jiffies(100));
}
/**
- * rt2x00queue_timeout - Check if a timeout occurred for DMA transfers
- * @queue: Queue to check.
+ * rt2x00queue_dma_timeout - Check if a timeout occurred for DMA transfers
+ * @entry: Queue entry to check.
*/
-static inline int rt2x00queue_dma_timeout(struct data_queue *queue)
+static inline int rt2x00queue_dma_timeout(struct queue_entry *entry)
{
- return time_after(queue->last_action[Q_INDEX],
- queue->last_action[Q_INDEX_DMA_DONE] + (HZ / 10));
+ if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ return false;
+ return time_after(jiffies, entry->last_action + msecs_to_jiffies(100));
}
/**
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index 36f388f97d65..8f90f6268077 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -165,6 +165,59 @@ int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
}
EXPORT_SYMBOL_GPL(rt2x00usb_regbusy_read);
+
+struct rt2x00_async_read_data {
+ __le32 reg;
+ struct usb_ctrlrequest cr;
+ struct rt2x00_dev *rt2x00dev;
+ bool (*callback)(struct rt2x00_dev *, int, u32);
+};
+
+static void rt2x00usb_register_read_async_cb(struct urb *urb)
+{
+ struct rt2x00_async_read_data *rd = urb->context;
+ if (rd->callback(rd->rt2x00dev, urb->status, le32_to_cpu(rd->reg))) {
+ if (usb_submit_urb(urb, GFP_ATOMIC) < 0)
+ kfree(rd);
+ } else
+ kfree(rd);
+}
+
+void rt2x00usb_register_read_async(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ bool (*callback)(struct rt2x00_dev*, int, u32))
+{
+ struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
+ struct urb *urb;
+ struct rt2x00_async_read_data *rd;
+
+ rd = kmalloc(sizeof(*rd), GFP_ATOMIC);
+ if (!rd)
+ return;
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ kfree(rd);
+ return;
+ }
+
+ rd->rt2x00dev = rt2x00dev;
+ rd->callback = callback;
+ rd->cr.bRequestType = USB_VENDOR_REQUEST_IN;
+ rd->cr.bRequest = USB_MULTI_READ;
+ rd->cr.wValue = 0;
+ rd->cr.wIndex = cpu_to_le16(offset);
+ rd->cr.wLength = cpu_to_le16(sizeof(u32));
+
+ usb_fill_control_urb(urb, usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+ (unsigned char *)(&rd->cr), &rd->reg, sizeof(rd->reg),
+ rt2x00usb_register_read_async_cb, rd);
+ if (usb_submit_urb(urb, GFP_ATOMIC) < 0)
+ kfree(rd);
+ usb_free_urb(urb);
+}
+EXPORT_SYMBOL_GPL(rt2x00usb_register_read_async);
+
/*
* TX data handlers.
*/
@@ -212,6 +265,9 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
if (!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return;
+ if (rt2x00dev->ops->lib->tx_dma_done)
+ rt2x00dev->ops->lib->tx_dma_done(entry);
+
/*
* Report the frame as DMA done
*/
@@ -227,10 +283,12 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
* Schedule the delayed work for reading the TX status
* from the device.
*/
- queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
+ if (!test_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags) ||
+ !kfifo_is_empty(&rt2x00dev->txstatus_fifo))
+ queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
}
-static void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
+static bool rt2x00usb_kick_tx_entry(struct queue_entry *entry, void* data)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
@@ -240,7 +298,7 @@ static void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
if (!test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags) ||
test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
- return;
+ return false;
/*
* USB devices cannot blindly pass the skb->len as the
@@ -261,6 +319,8 @@ static void rt2x00usb_kick_tx_entry(struct queue_entry *entry)
set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
rt2x00lib_dmadone(entry);
}
+
+ return false;
}
/*
@@ -323,7 +383,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb)
queue_work(rt2x00dev->workqueue, &rt2x00dev->rxdone_work);
}
-static void rt2x00usb_kick_rx_entry(struct queue_entry *entry)
+static bool rt2x00usb_kick_rx_entry(struct queue_entry *entry, void* data)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev);
@@ -332,7 +392,7 @@ static void rt2x00usb_kick_rx_entry(struct queue_entry *entry)
if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
- return;
+ return false;
rt2x00lib_dmastart(entry);
@@ -348,6 +408,8 @@ static void rt2x00usb_kick_rx_entry(struct queue_entry *entry)
set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
rt2x00lib_dmadone(entry);
}
+
+ return false;
}
void rt2x00usb_kick_queue(struct data_queue *queue)
@@ -358,12 +420,18 @@ void rt2x00usb_kick_queue(struct data_queue *queue)
case QID_AC_BE:
case QID_AC_BK:
if (!rt2x00queue_empty(queue))
- rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
+ rt2x00queue_for_each_entry(queue,
+ Q_INDEX_DONE,
+ Q_INDEX,
+ NULL,
rt2x00usb_kick_tx_entry);
break;
case QID_RX:
if (!rt2x00queue_full(queue))
- rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
+ rt2x00queue_for_each_entry(queue,
+ Q_INDEX_DONE,
+ Q_INDEX,
+ NULL,
rt2x00usb_kick_rx_entry);
break;
default:
@@ -372,14 +440,14 @@ void rt2x00usb_kick_queue(struct data_queue *queue)
}
EXPORT_SYMBOL_GPL(rt2x00usb_kick_queue);
-static void rt2x00usb_flush_entry(struct queue_entry *entry)
+static bool rt2x00usb_flush_entry(struct queue_entry *entry, void* data)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct queue_entry_priv_usb *entry_priv = entry->priv_data;
struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
- return;
+ return false;
usb_kill_urb(entry_priv->urb);
@@ -387,17 +455,20 @@ static void rt2x00usb_flush_entry(struct queue_entry *entry)
* Kill guardian urb (if required by driver).
*/
if ((entry->queue->qid == QID_BEACON) &&
- (test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags)))
+ (test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags)))
usb_kill_urb(bcn_priv->guardian_urb);
+
+ return false;
}
-void rt2x00usb_flush_queue(struct data_queue *queue)
+void rt2x00usb_flush_queue(struct data_queue *queue, bool drop)
{
struct work_struct *completion;
unsigned int i;
- rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX,
- rt2x00usb_flush_entry);
+ if (drop)
+ rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, NULL,
+ rt2x00usb_flush_entry);
/*
* Obtain the queue completion handler
@@ -416,7 +487,7 @@ void rt2x00usb_flush_queue(struct data_queue *queue)
return;
}
- for (i = 0; i < 20; i++) {
+ for (i = 0; i < 10; i++) {
/*
* Check if the driver is already done, otherwise we
* have to sleep a little while to give the driver/hw
@@ -456,15 +527,31 @@ static void rt2x00usb_watchdog_tx_status(struct data_queue *queue)
queue_work(queue->rt2x00dev->workqueue, &queue->rt2x00dev->txdone_work);
}
+static int rt2x00usb_status_timeout(struct data_queue *queue)
+{
+ struct queue_entry *entry;
+
+ entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
+ return rt2x00queue_status_timeout(entry);
+}
+
+static int rt2x00usb_dma_timeout(struct data_queue *queue)
+{
+ struct queue_entry *entry;
+
+ entry = rt2x00queue_get_entry(queue, Q_INDEX_DMA_DONE);
+ return rt2x00queue_dma_timeout(entry);
+}
+
void rt2x00usb_watchdog(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue;
tx_queue_for_each(rt2x00dev, queue) {
if (!rt2x00queue_empty(queue)) {
- if (rt2x00queue_dma_timeout(queue))
+ if (rt2x00usb_dma_timeout(queue))
rt2x00usb_watchdog_tx_dma(queue);
- if (rt2x00queue_status_timeout(queue))
+ if (rt2x00usb_status_timeout(queue))
rt2x00usb_watchdog_tx_status(queue);
}
}
@@ -489,7 +576,7 @@ void rt2x00usb_clear_entry(struct queue_entry *entry)
entry->flags = 0;
if (entry->queue->qid == QID_RX)
- rt2x00usb_kick_rx_entry(entry);
+ rt2x00usb_kick_rx_entry(entry, NULL);
}
EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry);
@@ -583,7 +670,7 @@ static int rt2x00usb_alloc_entries(struct data_queue *queue)
* then we are done.
*/
if (queue->qid != QID_BEACON ||
- !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))
+ !test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags))
return 0;
for (i = 0; i < queue->limit; i++) {
@@ -618,7 +705,7 @@ static void rt2x00usb_free_entries(struct data_queue *queue)
* then we are done.
*/
if (queue->qid != QID_BEACON ||
- !test_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags))
+ !test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags))
return;
for (i = 0; i < queue->limit; i++) {
@@ -707,10 +794,9 @@ exit:
}
int rt2x00usb_probe(struct usb_interface *usb_intf,
- const struct usb_device_id *id)
+ const struct rt2x00_ops *ops)
{
struct usb_device *usb_dev = interface_to_usbdev(usb_intf);
- struct rt2x00_ops *ops = (struct rt2x00_ops *)id->driver_info;
struct ieee80211_hw *hw;
struct rt2x00_dev *rt2x00dev;
int retval;
@@ -735,6 +821,7 @@ int rt2x00usb_probe(struct usb_interface *usb_intf,
INIT_WORK(&rt2x00dev->rxdone_work, rt2x00usb_work_rxdone);
INIT_WORK(&rt2x00dev->txdone_work, rt2x00usb_work_txdone);
+ init_timer(&rt2x00dev->txstatus_timer);
retval = rt2x00usb_alloc_reg(rt2x00dev);
if (retval)
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h
index e11c759ac9ed..323ca7b2b095 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.h
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.h
@@ -35,12 +35,6 @@
})
/*
- * This variable should be used with the
- * usb_driver structure initialization.
- */
-#define USB_DEVICE_DATA(__ops) .driver_info = (kernel_ulong_t)(__ops)
-
-/*
* For USB vendor requests we need to pass a timeout
* time in ms, for this we use the REGISTER_TIMEOUT,
* however when loading firmware a higher value is
@@ -345,6 +339,23 @@ int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
const struct rt2x00_field32 field,
u32 *reg);
+/**
+ * rt2x00usb_register_read_async - Asynchronously read 32bit register word
+ * @rt2x00dev: Device pointer, see &struct rt2x00_dev.
+ * @offset: Register offset
+ * @callback: Functon to call when read completes.
+ *
+ * Submit a control URB to read a 32bit register. This safe to
+ * be called from atomic context. The callback will be called
+ * when the URB completes. Otherwise the function is similar
+ * to rt2x00usb_register_read().
+ * When the callback function returns false, the memory will be cleaned up,
+ * when it returns true, the urb will be fired again.
+ */
+void rt2x00usb_register_read_async(struct rt2x00_dev *rt2x00dev,
+ const unsigned int offset,
+ bool (*callback)(struct rt2x00_dev*, int, u32));
+
/*
* Radio handlers
*/
@@ -389,11 +400,13 @@ void rt2x00usb_kick_queue(struct data_queue *queue);
/**
* rt2x00usb_flush_queue - Flush data queue
* @queue: Data queue to stop
+ * @drop: True to drop all pending frames.
*
- * This will walk through all entries of the queue and kill all
- * URB's which were send to the device.
+ * This will walk through all entries of the queue and will optionally
+ * kill all URB's which were send to the device, or at least wait until
+ * they have been returned from the device..
*/
-void rt2x00usb_flush_queue(struct data_queue *queue);
+void rt2x00usb_flush_queue(struct data_queue *queue, bool drop);
/**
* rt2x00usb_watchdog - Watchdog for USB communication
@@ -416,7 +429,7 @@ void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev);
* USB driver handlers.
*/
int rt2x00usb_probe(struct usb_interface *usb_intf,
- const struct usb_device_id *id);
+ const struct rt2x00_ops *ops);
void rt2x00usb_disconnect(struct usb_interface *usb_intf);
#ifdef CONFIG_PM
int rt2x00usb_suspend(struct usb_interface *usb_intf, pm_message_t state);
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 77e8113b91e1..9d35ec16a3a5 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -683,7 +683,7 @@ static void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF2529));
rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
- !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags));
+ !test_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags));
/*
* Configure the RX antenna.
@@ -811,10 +811,10 @@ static void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev,
if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
sel = antenna_sel_a;
- lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
+ lna = test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags);
} else {
sel = antenna_sel_bg;
- lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
+ lna = test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags);
}
for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++)
@@ -834,7 +834,7 @@ static void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev,
else if (rt2x00_rf(rt2x00dev, RF2527))
rt61pci_config_antenna_2x(rt2x00dev, ant);
else if (rt2x00_rf(rt2x00dev, RF2529)) {
- if (test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags))
+ if (test_bit(CAPABILITY_DOUBLE_ANTENNA, &rt2x00dev->cap_flags))
rt61pci_config_antenna_2x(rt2x00dev, ant);
else
rt61pci_config_antenna_2529(rt2x00dev, ant);
@@ -848,13 +848,13 @@ static void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev,
short lna_gain = 0;
if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) {
- if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
+ if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags))
lna_gain += 14;
rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
} else {
- if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags))
+ if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags))
lna_gain += 14;
rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
@@ -1050,14 +1050,14 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev,
if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
low_bound = 0x28;
up_bound = 0x48;
- if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) {
+ if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) {
low_bound += 0x10;
up_bound += 0x10;
}
} else {
low_bound = 0x20;
up_bound = 0x40;
- if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) {
+ if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags)) {
low_bound += 0x10;
up_bound += 0x10;
}
@@ -2260,8 +2260,8 @@ static void rt61pci_wakeup(struct rt2x00_dev *rt2x00dev)
rt61pci_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
}
-static void rt61pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
- struct rt2x00_field32 irq_field)
+static inline void rt61pci_enable_interrupt(struct rt2x00_dev *rt2x00dev,
+ struct rt2x00_field32 irq_field)
{
u32 reg;
@@ -2313,8 +2313,10 @@ static void rt61pci_tbtt_tasklet(unsigned long data)
static void rt61pci_rxdone_tasklet(unsigned long data)
{
struct rt2x00_dev *rt2x00dev = (struct rt2x00_dev *)data;
- rt2x00pci_rxdone(rt2x00dev);
- rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE);
+ if (rt2x00pci_rxdone(rt2x00dev))
+ rt2x00pci_rxdone(rt2x00dev);
+ else
+ rt61pci_enable_interrupt(rt2x00dev, INT_MASK_CSR_RXDONE);
}
static void rt61pci_autowake_tasklet(unsigned long data)
@@ -2535,7 +2537,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
* Determine number of antennas.
*/
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_NUM) == 2)
- __set_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_DOUBLE_ANTENNA, &rt2x00dev->cap_flags);
/*
* Identify default antenna configuration.
@@ -2549,20 +2551,20 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
* Read the Frame type.
*/
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_FRAME_TYPE))
- __set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags);
/*
* Detect if this device has a hardware controlled radio.
*/
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
- __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags);
/*
* Read frequency offset and RF programming sequence.
*/
rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom);
if (rt2x00_get_field16(eeprom, EEPROM_FREQ_SEQ))
- __set_bit(CONFIG_RF_SEQUENCE, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_RF_SEQUENCE, &rt2x00dev->cap_flags);
rt2x00dev->freq_offset = rt2x00_get_field16(eeprom, EEPROM_FREQ_OFFSET);
@@ -2572,9 +2574,9 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_A))
- __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags);
if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG))
- __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags);
/*
* When working with a RF2529 chip without double antenna,
@@ -2582,7 +2584,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
* eeprom word.
*/
if (rt2x00_rf(rt2x00dev, RF2529) &&
- !test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) {
+ !test_bit(CAPABILITY_DOUBLE_ANTENNA, &rt2x00dev->cap_flags)) {
rt2x00dev->default_ant.rx =
ANTENNA_A + rt2x00_get_field16(eeprom, EEPROM_NIC_RX_FIXED);
rt2x00dev->default_ant.tx =
@@ -2797,7 +2799,7 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
spec->supported_bands = SUPPORT_BAND_2GHZ;
spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
- if (!test_bit(CONFIG_RF_SEQUENCE, &rt2x00dev->flags)) {
+ if (!test_bit(CAPABILITY_RF_SEQUENCE, &rt2x00dev->cap_flags)) {
spec->num_channels = 14;
spec->channels = rf_vals_noseq;
} else {
@@ -2867,16 +2869,16 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
* This device has multiple filters for control frames,
* but has no a separate filter for PS Poll frames.
*/
- __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags);
/*
* This device requires firmware and DMA mapped skbs.
*/
- __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
- __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
+ __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags);
+ __set_bit(REQUIRE_DMA, &rt2x00dev->cap_flags);
if (!modparam_nohwcrypt)
- __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
- __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags);
+ __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags);
/*
* Set the rssi offset.
@@ -2977,6 +2979,9 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = {
.get_tsf = rt61pci_get_tsf,
.rfkill_poll = rt2x00mac_rfkill_poll,
.flush = rt2x00mac_flush,
+ .set_antenna = rt2x00mac_set_antenna,
+ .get_antenna = rt2x00mac_get_antenna,
+ .get_ringparam = rt2x00mac_get_ringparam,
};
static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
@@ -3001,6 +3006,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = {
.start_queue = rt61pci_start_queue,
.kick_queue = rt61pci_kick_queue,
.stop_queue = rt61pci_stop_queue,
+ .flush_queue = rt2x00pci_flush_queue,
.write_tx_desc = rt61pci_write_tx_desc,
.write_beacon = rt61pci_write_beacon,
.clear_beacon = rt61pci_clear_beacon,
@@ -3058,11 +3064,11 @@ static const struct rt2x00_ops rt61pci_ops = {
*/
static DEFINE_PCI_DEVICE_TABLE(rt61pci_device_table) = {
/* RT2561s */
- { PCI_DEVICE(0x1814, 0x0301), PCI_DEVICE_DATA(&rt61pci_ops) },
+ { PCI_DEVICE(0x1814, 0x0301) },
/* RT2561 v2 */
- { PCI_DEVICE(0x1814, 0x0302), PCI_DEVICE_DATA(&rt61pci_ops) },
+ { PCI_DEVICE(0x1814, 0x0302) },
/* RT2661 */
- { PCI_DEVICE(0x1814, 0x0401), PCI_DEVICE_DATA(&rt61pci_ops) },
+ { PCI_DEVICE(0x1814, 0x0401) },
{ 0, }
};
@@ -3077,10 +3083,16 @@ MODULE_FIRMWARE(FIRMWARE_RT2561s);
MODULE_FIRMWARE(FIRMWARE_RT2661);
MODULE_LICENSE("GPL");
+static int rt61pci_probe(struct pci_dev *pci_dev,
+ const struct pci_device_id *id)
+{
+ return rt2x00pci_probe(pci_dev, &rt61pci_ops);
+}
+
static struct pci_driver rt61pci_driver = {
.name = KBUILD_MODNAME,
.id_table = rt61pci_device_table,
- .probe = rt2x00pci_probe,
+ .probe = rt61pci_probe,
.remove = __devexit_p(rt2x00pci_remove),
.suspend = rt2x00pci_suspend,
.resume = rt2x00pci_resume,
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 02f1148c577e..ad20953cbf05 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -595,7 +595,7 @@ static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
switch (ant->rx) {
case ANTENNA_HW_DIVERSITY:
rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2);
- temp = !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags)
+ temp = !test_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags)
&& (rt2x00dev->curr_band != IEEE80211_BAND_5GHZ);
rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, temp);
break;
@@ -636,7 +636,7 @@ static void rt73usb_config_antenna_2x(struct rt2x00_dev *rt2x00dev,
rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0);
rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
- !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags));
+ !test_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags));
/*
* Configure the RX antenna.
@@ -709,10 +709,10 @@ static void rt73usb_config_ant(struct rt2x00_dev *rt2x00dev,
if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
sel = antenna_sel_a;
- lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
+ lna = test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags);
} else {
sel = antenna_sel_bg;
- lna = test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
+ lna = test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags);
}
for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++)
@@ -740,7 +740,7 @@ static void rt73usb_config_lna_gain(struct rt2x00_dev *rt2x00dev,
short lna_gain = 0;
if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) {
- if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
+ if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags))
lna_gain += 14;
rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
@@ -930,7 +930,7 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev,
low_bound = 0x28;
up_bound = 0x48;
- if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) {
+ if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) {
low_bound += 0x10;
up_bound += 0x10;
}
@@ -946,7 +946,7 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev,
up_bound = 0x1c;
}
- if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) {
+ if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags)) {
low_bound += 0x14;
up_bound += 0x10;
}
@@ -1661,7 +1661,7 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
}
if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
- if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) {
+ if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) {
if (lna == 3 || lna == 2)
offset += 10;
} else {
@@ -1899,13 +1899,13 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
* Read the Frame type.
*/
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_FRAME_TYPE))
- __set_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags);
/*
* Detect if this device has an hardware controlled radio.
*/
if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_HARDWARE_RADIO))
- __set_bit(CONFIG_SUPPORT_HW_BUTTON, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_HW_BUTTON, &rt2x00dev->cap_flags);
/*
* Read frequency offset.
@@ -1919,8 +1919,8 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA)) {
- __set_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags);
- __set_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags);
+ __set_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags);
}
/*
@@ -2200,16 +2200,16 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev)
* This device has multiple filters for control frames,
* but has no a separate filter for PS Poll frames.
*/
- __set_bit(DRIVER_SUPPORT_CONTROL_FILTERS, &rt2x00dev->flags);
+ __set_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags);
/*
* This device requires firmware.
*/
- __set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
+ __set_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_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_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags);
+ __set_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags);
+ __set_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags);
/*
* Set the rssi offset.
@@ -2311,6 +2311,9 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = {
.get_tsf = rt73usb_get_tsf,
.rfkill_poll = rt2x00mac_rfkill_poll,
.flush = rt2x00mac_flush,
+ .set_antenna = rt2x00mac_set_antenna,
+ .get_antenna = rt2x00mac_get_antenna,
+ .get_ringparam = rt2x00mac_get_ringparam,
};
static const struct rt2x00lib_ops rt73usb_rt2x00_ops = {
@@ -2389,114 +2392,113 @@ static const struct rt2x00_ops rt73usb_ops = {
*/
static struct usb_device_id rt73usb_device_table[] = {
/* AboCom */
- { USB_DEVICE(0x07b8, 0xb21b), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x07b8, 0xb21c), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x07b8, 0xb21d), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x07b8, 0xb21e), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x07b8, 0xb21f), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x07b8, 0xb21b) },
+ { USB_DEVICE(0x07b8, 0xb21c) },
+ { USB_DEVICE(0x07b8, 0xb21d) },
+ { USB_DEVICE(0x07b8, 0xb21e) },
+ { USB_DEVICE(0x07b8, 0xb21f) },
/* AL */
- { USB_DEVICE(0x14b2, 0x3c10), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x14b2, 0x3c10) },
/* Amigo */
- { USB_DEVICE(0x148f, 0x9021), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x0eb0, 0x9021), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x148f, 0x9021) },
+ { USB_DEVICE(0x0eb0, 0x9021) },
/* AMIT */
- { USB_DEVICE(0x18c5, 0x0002), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x18c5, 0x0002) },
/* Askey */
- { USB_DEVICE(0x1690, 0x0722), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x1690, 0x0722) },
/* ASUS */
- { USB_DEVICE(0x0b05, 0x1723), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x0b05, 0x1724), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x0b05, 0x1723) },
+ { USB_DEVICE(0x0b05, 0x1724) },
/* Belkin */
- { USB_DEVICE(0x050d, 0x7050), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x050d, 0x705a), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x050d, 0x905b), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x050d, 0x905c), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x050d, 0x705a) },
+ { USB_DEVICE(0x050d, 0x905b) },
+ { USB_DEVICE(0x050d, 0x905c) },
/* Billionton */
- { USB_DEVICE(0x1631, 0xc019), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x08dd, 0x0120), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x1631, 0xc019) },
+ { USB_DEVICE(0x08dd, 0x0120) },
/* Buffalo */
- { USB_DEVICE(0x0411, 0x00d8), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x0411, 0x00d9), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x0411, 0x00f4), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x0411, 0x0116), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x0411, 0x0119), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x0411, 0x0137), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x0411, 0x00d8) },
+ { USB_DEVICE(0x0411, 0x00d9) },
+ { USB_DEVICE(0x0411, 0x00f4) },
+ { USB_DEVICE(0x0411, 0x0116) },
+ { USB_DEVICE(0x0411, 0x0119) },
+ { USB_DEVICE(0x0411, 0x0137) },
/* CEIVA */
- { USB_DEVICE(0x178d, 0x02be), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x178d, 0x02be) },
/* CNet */
- { USB_DEVICE(0x1371, 0x9022), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x1371, 0x9032), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x1371, 0x9022) },
+ { USB_DEVICE(0x1371, 0x9032) },
/* Conceptronic */
- { USB_DEVICE(0x14b2, 0x3c22), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x14b2, 0x3c22) },
/* Corega */
- { USB_DEVICE(0x07aa, 0x002e), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x07aa, 0x002e) },
/* D-Link */
- { USB_DEVICE(0x07d1, 0x3c03), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x07d1, 0x3c04), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x07d1, 0x3c06), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x07d1, 0x3c07), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x07d1, 0x3c03) },
+ { USB_DEVICE(0x07d1, 0x3c04) },
+ { USB_DEVICE(0x07d1, 0x3c06) },
+ { USB_DEVICE(0x07d1, 0x3c07) },
/* Edimax */
- { USB_DEVICE(0x7392, 0x7318), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x7392, 0x7618), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x7392, 0x7318) },
+ { USB_DEVICE(0x7392, 0x7618) },
/* EnGenius */
- { USB_DEVICE(0x1740, 0x3701), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x1740, 0x3701) },
/* Gemtek */
- { USB_DEVICE(0x15a9, 0x0004), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x15a9, 0x0004) },
/* Gigabyte */
- { USB_DEVICE(0x1044, 0x8008), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x1044, 0x800a), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x1044, 0x8008) },
+ { USB_DEVICE(0x1044, 0x800a) },
/* Huawei-3Com */
- { USB_DEVICE(0x1472, 0x0009), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x1472, 0x0009) },
/* Hercules */
- { USB_DEVICE(0x06f8, 0xe002), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x06f8, 0xe010), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x06f8, 0xe020), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x06f8, 0xe002) },
+ { USB_DEVICE(0x06f8, 0xe010) },
+ { USB_DEVICE(0x06f8, 0xe020) },
/* Linksys */
- { USB_DEVICE(0x13b1, 0x0020), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x13b1, 0x0023), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x13b1, 0x0028), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x13b1, 0x0020) },
+ { USB_DEVICE(0x13b1, 0x0023) },
+ { USB_DEVICE(0x13b1, 0x0028) },
/* MSI */
- { USB_DEVICE(0x0db0, 0x4600), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x0db0, 0x6877), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x0db0, 0x6874), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x0db0, 0xa861), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x0db0, 0xa874), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x0db0, 0x4600) },
+ { USB_DEVICE(0x0db0, 0x6877) },
+ { USB_DEVICE(0x0db0, 0x6874) },
+ { USB_DEVICE(0x0db0, 0xa861) },
+ { USB_DEVICE(0x0db0, 0xa874) },
/* Ovislink */
- { USB_DEVICE(0x1b75, 0x7318), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x1b75, 0x7318) },
/* Ralink */
- { USB_DEVICE(0x04bb, 0x093d), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x148f, 0x2671), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x0812, 0x3101), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x04bb, 0x093d) },
+ { USB_DEVICE(0x148f, 0x2573) },
+ { USB_DEVICE(0x148f, 0x2671) },
+ { USB_DEVICE(0x0812, 0x3101) },
/* Qcom */
- { USB_DEVICE(0x18e8, 0x6196), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x18e8, 0x6229), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x18e8, 0x6238), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x18e8, 0x6196) },
+ { USB_DEVICE(0x18e8, 0x6229) },
+ { USB_DEVICE(0x18e8, 0x6238) },
/* Samsung */
- { USB_DEVICE(0x04e8, 0x4471), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x04e8, 0x4471) },
/* Senao */
- { USB_DEVICE(0x1740, 0x7100), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x1740, 0x7100) },
/* Sitecom */
- { USB_DEVICE(0x0df6, 0x0024), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x0df6, 0x0027), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x0df6, 0x002f), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x0df6, 0x90ac), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x0df6, 0x9712), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x0df6, 0x0024) },
+ { USB_DEVICE(0x0df6, 0x0027) },
+ { USB_DEVICE(0x0df6, 0x002f) },
+ { USB_DEVICE(0x0df6, 0x90ac) },
+ { USB_DEVICE(0x0df6, 0x9712) },
/* Surecom */
- { USB_DEVICE(0x0769, 0x31f3), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x0769, 0x31f3) },
/* Tilgin */
- { USB_DEVICE(0x6933, 0x5001), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x6933, 0x5001) },
/* Philips */
- { USB_DEVICE(0x0471, 0x200a), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x0471, 0x200a) },
/* Planex */
- { USB_DEVICE(0x2019, 0xab01), USB_DEVICE_DATA(&rt73usb_ops) },
- { USB_DEVICE(0x2019, 0xab50), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x2019, 0xab01) },
+ { USB_DEVICE(0x2019, 0xab50) },
/* WideTell */
- { USB_DEVICE(0x7167, 0x3840), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x7167, 0x3840) },
/* Zcom */
- { USB_DEVICE(0x0cde, 0x001c), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x0cde, 0x001c) },
/* ZyXEL */
- { USB_DEVICE(0x0586, 0x3415), USB_DEVICE_DATA(&rt73usb_ops) },
+ { USB_DEVICE(0x0586, 0x3415) },
{ 0, }
};
@@ -2508,10 +2510,16 @@ MODULE_DEVICE_TABLE(usb, rt73usb_device_table);
MODULE_FIRMWARE(FIRMWARE_RT2571);
MODULE_LICENSE("GPL");
+static int rt73usb_probe(struct usb_interface *usb_intf,
+ const struct usb_device_id *id)
+{
+ return rt2x00usb_probe(usb_intf, &rt73usb_ops);
+}
+
static struct usb_driver rt73usb_driver = {
.name = KBUILD_MODNAME,
.id_table = rt73usb_device_table,
- .probe = rt2x00usb_probe,
+ .probe = rt73usb_probe,
.disconnect = rt2x00usb_disconnect,
.suspend = rt2x00usb_suspend,
.resume = rt2x00usb_resume,
diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig
index ce49e0ce7cad..5aee8b22d74e 100644
--- a/drivers/net/wireless/rtlwifi/Kconfig
+++ b/drivers/net/wireless/rtlwifi/Kconfig
@@ -10,6 +10,17 @@ config RTL8192CE
If you choose to build it as a module, it will be called rtl8192ce
+config RTL8192SE
+ tristate "Realtek RTL8192SE/RTL8191SE PCIe Wireless Network Adapter"
+ depends on MAC80211 && EXPERIMENTAL
+ select FW_LOADER
+ select RTLWIFI
+ ---help---
+ This is the driver for Realtek RTL8192SE/RTL8191SE 802.11n PCIe
+ wireless network adapters.
+
+ If you choose to build it as a module, it will be called rtl8192se
+
config RTL8192CU
tristate "Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter"
depends on MAC80211 && USB && EXPERIMENTAL
@@ -24,10 +35,10 @@ config RTL8192CU
config RTLWIFI
tristate
- depends on RTL8192CE || RTL8192CU
+ depends on RTL8192CE || RTL8192CU || RTL8192SE
default m
config RTL8192C_COMMON
tristate
- depends on RTL8192CE || RTL8192CU
+ depends on RTL8192CE || RTL8192CU || RTL8192SE
default m
diff --git a/drivers/net/wireless/rtlwifi/Makefile b/drivers/net/wireless/rtlwifi/Makefile
index ec9393f24799..7acce83c3785 100644
--- a/drivers/net/wireless/rtlwifi/Makefile
+++ b/drivers/net/wireless/rtlwifi/Makefile
@@ -22,5 +22,6 @@ endif
obj-$(CONFIG_RTL8192C_COMMON) += rtl8192c/
obj-$(CONFIG_RTL8192CE) += rtl8192ce/
obj-$(CONFIG_RTL8192CU) += rtl8192cu/
+obj-$(CONFIG_RTL8192SE) += rtl8192se/
ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c
index 0d7d93e1d398..ccb6da38fe22 100644
--- a/drivers/net/wireless/rtlwifi/base.c
+++ b/drivers/net/wireless/rtlwifi/base.c
@@ -50,8 +50,9 @@
*3) functions called by core.c
*4) wq & timer callback functions
*5) frame process functions
- *6) sysfs functions
- *7) ...
+ *6) IOT functions
+ *7) sysfs functions
+ *8) ...
*/
/*********************************************************
@@ -59,7 +60,7 @@
* mac80211 init functions
*
*********************************************************/
-static struct ieee80211_channel rtl_channeltable[] = {
+static struct ieee80211_channel rtl_channeltable_2g[] = {
{.center_freq = 2412, .hw_value = 1,},
{.center_freq = 2417, .hw_value = 2,},
{.center_freq = 2422, .hw_value = 3,},
@@ -76,7 +77,34 @@ static struct ieee80211_channel rtl_channeltable[] = {
{.center_freq = 2484, .hw_value = 14,},
};
-static struct ieee80211_rate rtl_ratetable[] = {
+static struct ieee80211_channel rtl_channeltable_5g[] = {
+ {.center_freq = 5180, .hw_value = 36,},
+ {.center_freq = 5200, .hw_value = 40,},
+ {.center_freq = 5220, .hw_value = 44,},
+ {.center_freq = 5240, .hw_value = 48,},
+ {.center_freq = 5260, .hw_value = 52,},
+ {.center_freq = 5280, .hw_value = 56,},
+ {.center_freq = 5300, .hw_value = 60,},
+ {.center_freq = 5320, .hw_value = 64,},
+ {.center_freq = 5500, .hw_value = 100,},
+ {.center_freq = 5520, .hw_value = 104,},
+ {.center_freq = 5540, .hw_value = 108,},
+ {.center_freq = 5560, .hw_value = 112,},
+ {.center_freq = 5580, .hw_value = 116,},
+ {.center_freq = 5600, .hw_value = 120,},
+ {.center_freq = 5620, .hw_value = 124,},
+ {.center_freq = 5640, .hw_value = 128,},
+ {.center_freq = 5660, .hw_value = 132,},
+ {.center_freq = 5680, .hw_value = 136,},
+ {.center_freq = 5700, .hw_value = 140,},
+ {.center_freq = 5745, .hw_value = 149,},
+ {.center_freq = 5765, .hw_value = 153,},
+ {.center_freq = 5785, .hw_value = 157,},
+ {.center_freq = 5805, .hw_value = 161,},
+ {.center_freq = 5825, .hw_value = 165,},
+};
+
+static struct ieee80211_rate rtl_ratetable_2g[] = {
{.bitrate = 10, .hw_value = 0x00,},
{.bitrate = 20, .hw_value = 0x01,},
{.bitrate = 55, .hw_value = 0x02,},
@@ -91,18 +119,57 @@ static struct ieee80211_rate rtl_ratetable[] = {
{.bitrate = 540, .hw_value = 0x0b,},
};
+static struct ieee80211_rate rtl_ratetable_5g[] = {
+ {.bitrate = 60, .hw_value = 0x04,},
+ {.bitrate = 90, .hw_value = 0x05,},
+ {.bitrate = 120, .hw_value = 0x06,},
+ {.bitrate = 180, .hw_value = 0x07,},
+ {.bitrate = 240, .hw_value = 0x08,},
+ {.bitrate = 360, .hw_value = 0x09,},
+ {.bitrate = 480, .hw_value = 0x0a,},
+ {.bitrate = 540, .hw_value = 0x0b,},
+};
+
static const struct ieee80211_supported_band rtl_band_2ghz = {
.band = IEEE80211_BAND_2GHZ,
- .channels = rtl_channeltable,
- .n_channels = ARRAY_SIZE(rtl_channeltable),
+ .channels = rtl_channeltable_2g,
+ .n_channels = ARRAY_SIZE(rtl_channeltable_2g),
- .bitrates = rtl_ratetable,
- .n_bitrates = ARRAY_SIZE(rtl_ratetable),
+ .bitrates = rtl_ratetable_2g,
+ .n_bitrates = ARRAY_SIZE(rtl_ratetable_2g),
.ht_cap = {0},
};
+static struct ieee80211_supported_band rtl_band_5ghz = {
+ .band = IEEE80211_BAND_5GHZ,
+
+ .channels = rtl_channeltable_5g,
+ .n_channels = ARRAY_SIZE(rtl_channeltable_5g),
+
+ .bitrates = rtl_ratetable_5g,
+ .n_bitrates = ARRAY_SIZE(rtl_ratetable_5g),
+
+ .ht_cap = {0},
+};
+
+static const u8 tid_to_ac[] = {
+ 2, /* IEEE80211_AC_BE */
+ 3, /* IEEE80211_AC_BK */
+ 3, /* IEEE80211_AC_BK */
+ 2, /* IEEE80211_AC_BE */
+ 1, /* IEEE80211_AC_VI */
+ 1, /* IEEE80211_AC_VI */
+ 0, /* IEEE80211_AC_VO */
+ 0, /* IEEE80211_AC_VO */
+};
+
+u8 rtl_tid_to_ac(struct ieee80211_hw *hw, u8 tid)
+{
+ return tid_to_ac[tid];
+}
+
static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw,
struct ieee80211_sta_ht_cap *ht_cap)
{
@@ -115,6 +182,9 @@ static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw,
IEEE80211_HT_CAP_SGI_20 |
IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU;
+ if (rtlpriv->rtlhal.disable_amsdu_8k)
+ ht_cap->cap &= ~IEEE80211_HT_CAP_MAX_AMSDU;
+
/*
*Maximum length of AMPDU that the STA can receive.
*Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets)
@@ -159,37 +229,99 @@ static void _rtl_init_hw_ht_capab(struct ieee80211_hw *hw,
static void _rtl_init_mac80211(struct ieee80211_hw *hw)
{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw));
struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
struct ieee80211_supported_band *sband;
- /* <1> use mac->bands as mem for hw->wiphy->bands */
- sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]);
- /*
- * <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ]
- * to default value(1T1R)
- */
- memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]), &rtl_band_2ghz,
- sizeof(struct ieee80211_supported_band));
+ if (rtlhal->macphymode == SINGLEMAC_SINGLEPHY && rtlhal->bandset ==
+ BAND_ON_BOTH) {
+ /* 1: 2.4 G bands */
+ /* <1> use mac->bands as mem for hw->wiphy->bands */
+ sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]);
+
+ /* <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ]
+ * to default value(1T1R) */
+ memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]), &rtl_band_2ghz,
+ sizeof(struct ieee80211_supported_band));
- /* <3> init ht cap base on ant_num */
- _rtl_init_hw_ht_capab(hw, &sband->ht_cap);
+ /* <3> init ht cap base on ant_num */
+ _rtl_init_hw_ht_capab(hw, &sband->ht_cap);
- /* <4> set mac->sband to wiphy->sband */
- hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband;
+ /* <4> set mac->sband to wiphy->sband */
+ hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband;
+ /* 2: 5 G bands */
+ /* <1> use mac->bands as mem for hw->wiphy->bands */
+ sband = &(rtlmac->bands[IEEE80211_BAND_5GHZ]);
+
+ /* <2> set hw->wiphy->bands[IEEE80211_BAND_5GHZ]
+ * to default value(1T1R) */
+ memcpy(&(rtlmac->bands[IEEE80211_BAND_5GHZ]), &rtl_band_5ghz,
+ sizeof(struct ieee80211_supported_band));
+
+ /* <3> init ht cap base on ant_num */
+ _rtl_init_hw_ht_capab(hw, &sband->ht_cap);
+
+ /* <4> set mac->sband to wiphy->sband */
+ hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband;
+ } else {
+ if (rtlhal->current_bandtype == BAND_ON_2_4G) {
+ /* <1> use mac->bands as mem for hw->wiphy->bands */
+ sband = &(rtlmac->bands[IEEE80211_BAND_2GHZ]);
+
+ /* <2> set hw->wiphy->bands[IEEE80211_BAND_2GHZ]
+ * to default value(1T1R) */
+ memcpy(&(rtlmac->bands[IEEE80211_BAND_2GHZ]),
+ &rtl_band_2ghz,
+ sizeof(struct ieee80211_supported_band));
+
+ /* <3> init ht cap base on ant_num */
+ _rtl_init_hw_ht_capab(hw, &sband->ht_cap);
+
+ /* <4> set mac->sband to wiphy->sband */
+ hw->wiphy->bands[IEEE80211_BAND_2GHZ] = sband;
+ } else if (rtlhal->current_bandtype == BAND_ON_5G) {
+ /* <1> use mac->bands as mem for hw->wiphy->bands */
+ sband = &(rtlmac->bands[IEEE80211_BAND_5GHZ]);
+
+ /* <2> set hw->wiphy->bands[IEEE80211_BAND_5GHZ]
+ * to default value(1T1R) */
+ memcpy(&(rtlmac->bands[IEEE80211_BAND_5GHZ]),
+ &rtl_band_5ghz,
+ sizeof(struct ieee80211_supported_band));
+
+ /* <3> init ht cap base on ant_num */
+ _rtl_init_hw_ht_capab(hw, &sband->ht_cap);
+
+ /* <4> set mac->sband to wiphy->sband */
+ hw->wiphy->bands[IEEE80211_BAND_5GHZ] = sband;
+ } else {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
+ ("Err BAND %d\n",
+ rtlhal->current_bandtype));
+ }
+ }
/* <5> set hw caps */
hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_RX_INCLUDES_FCS |
- IEEE80211_HW_BEACON_FILTER | IEEE80211_HW_AMPDU_AGGREGATION | /*PS*/
- /*IEEE80211_HW_SUPPORTS_PS | */
- /*IEEE80211_HW_PS_NULLFUNC_STACK | */
- /*IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */
+ IEEE80211_HW_BEACON_FILTER |
+ IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_REPORTS_TX_ACK_STATUS | 0;
+ /* swlps or hwlps has been set in diff chip in init_sw_vars */
+ if (rtlpriv->psc.swctrl_lps)
+ hw->flags |= IEEE80211_HW_SUPPORTS_PS |
+ IEEE80211_HW_PS_NULLFUNC_STACK |
+ /* IEEE80211_HW_SUPPORTS_DYNAMIC_PS | */
+ 0;
+
hw->wiphy->interface_modes =
- BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC);
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC);
hw->wiphy->rts_threshold = 2347;
@@ -199,9 +331,10 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw)
/* TODO: Correct this value for our hw */
/* TODO: define these hard code value */
hw->channel_change_time = 100;
- hw->max_listen_interval = 5;
+ hw->max_listen_interval = 10;
hw->max_rate_tries = 4;
/* hw->max_rates = 1; */
+ hw->sta_data_size = sizeof(struct rtl_sta_info);
/* <6> mac address */
if (is_valid_ether_addr(rtlefuse->dev_addr)) {
@@ -230,6 +363,10 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw)
(void *)rtl_watchdog_wq_callback);
INIT_DELAYED_WORK(&rtlpriv->works.ips_nic_off_wq,
(void *)rtl_ips_nic_off_wq_callback);
+ INIT_DELAYED_WORK(&rtlpriv->works.ps_work,
+ (void *)rtl_swlps_wq_callback);
+ INIT_DELAYED_WORK(&rtlpriv->works.ps_rfon_wq,
+ (void *)rtl_swlps_rfon_wq_callback);
}
@@ -241,6 +378,8 @@ void rtl_deinit_deferred_work(struct ieee80211_hw *hw)
cancel_delayed_work(&rtlpriv->works.watchdog_wq);
cancel_delayed_work(&rtlpriv->works.ips_nic_off_wq);
+ cancel_delayed_work(&rtlpriv->works.ps_work);
+ cancel_delayed_work(&rtlpriv->works.ps_rfon_wq);
}
void rtl_init_rfkill(struct ieee80211_hw *hw)
@@ -251,14 +390,16 @@ void rtl_init_rfkill(struct ieee80211_hw *hw)
bool blocked;
u8 valid = 0;
- radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid);
+ /*set init state to on */
+ rtlpriv->rfkill.rfkill_state = 1;
+ wiphy_rfkill_set_hw_state(hw->wiphy, 0);
- /*set init state to that of switch */
- rtlpriv->rfkill.rfkill_state = radio_state;
- printk(KERN_INFO "rtlwifi: wireless switch is %s\n",
- rtlpriv->rfkill.rfkill_state ? "on" : "off");
+ radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid);
if (valid) {
+ printk(KERN_INFO "rtlwifi: wireless switch is %s\n",
+ rtlpriv->rfkill.rfkill_state ? "on" : "off");
+
rtlpriv->rfkill.rfkill_state = radio_state;
blocked = (rtlpriv->rfkill.rfkill_state == 1) ? 0 : 1;
@@ -308,6 +449,8 @@ int rtl_init_core(struct ieee80211_hw *hw)
spin_lock_init(&rtlpriv->locks.rf_ps_lock);
spin_lock_init(&rtlpriv->locks.rf_lock);
spin_lock_init(&rtlpriv->locks.lps_lock);
+ spin_lock_init(&rtlpriv->locks.waitq_lock);
+ spin_lock_init(&rtlpriv->locks.cck_and_rw_pagea_lock);
rtlmac->link_state = MAC80211_NOLINK;
@@ -327,12 +470,6 @@ void rtl_init_rx_config(struct ieee80211_hw *hw)
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_RCR, (u8 *) (&mac->rx_conf));
- rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_MGT_FILTER,
- (u8 *) (&mac->rx_mgt_filter));
- rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_CTRL_FILTER,
- (u8 *) (&mac->rx_ctrl_filter));
- rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_DATA_FILTER,
- (u8 *) (&mac->rx_data_filter));
}
/*********************************************************
@@ -359,28 +496,40 @@ static void _rtl_qurey_shortpreamble_mode(struct ieee80211_hw *hw,
}
static void _rtl_query_shortgi(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
struct rtl_tcb_desc *tcb_desc,
struct ieee80211_tx_info *info)
{
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
u8 rate_flag = info->control.rates[0].flags;
-
+ u8 sgi_40 = 0, sgi_20 = 0, bw_40 = 0;
tcb_desc->use_shortgi = false;
- if (!mac->ht_enable)
+ if (sta == NULL)
+ return;
+
+ sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40;
+ sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20;
+
+ if (!(sta->ht_cap.ht_supported))
return;
- if (!mac->sgi_40 && !mac->sgi_20)
+ if (!sgi_40 && !sgi_20)
return;
- if ((mac->bw_40 == true) && mac->sgi_40)
+ if (mac->opmode == NL80211_IFTYPE_STATION)
+ bw_40 = mac->bw_40;
+ else if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_ADHOC)
+ bw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+
+ if ((bw_40 == true) && sgi_40)
tcb_desc->use_shortgi = true;
- else if ((mac->bw_40 == false) && mac->sgi_20)
+ else if ((bw_40 == false) && sgi_20)
tcb_desc->use_shortgi = true;
if (!(rate_flag & IEEE80211_TX_RC_SHORT_GI))
tcb_desc->use_shortgi = false;
-
}
static void _rtl_query_protection_mode(struct ieee80211_hw *hw,
@@ -408,19 +557,25 @@ static void _rtl_query_protection_mode(struct ieee80211_hw *hw,
tcb_desc->rts_enable = true;
tcb_desc->rts_rate = rtlpriv->cfg->maps[RTL_RC_OFDM_RATE24M];
}
-
}
static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
struct rtl_tcb_desc *tcb_desc)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_sta_info *sta_entry = NULL;
+ u8 ratr_index = 7;
+ if (sta) {
+ sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+ ratr_index = sta_entry->ratr_index;
+ }
if (!tcb_desc->disable_ratefallback || !tcb_desc->use_driver_rate) {
- if (mac->opmode == NL80211_IFTYPE_STATION)
+ if (mac->opmode == NL80211_IFTYPE_STATION) {
tcb_desc->ratr_index = 0;
- else if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+ } else if (mac->opmode == NL80211_IFTYPE_ADHOC) {
if (tcb_desc->multicast || tcb_desc->broadcast) {
tcb_desc->hw_rate =
rtlpriv->cfg->maps[RTL_RC_CCK_RATE2M];
@@ -428,36 +583,61 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw,
} else {
/* TODO */
}
+ tcb_desc->ratr_index = ratr_index;
+ } else if (mac->opmode == NL80211_IFTYPE_AP) {
+ tcb_desc->ratr_index = ratr_index;
}
}
if (rtlpriv->dm.useramask) {
/* TODO we will differentiate adhoc and station futrue */
- tcb_desc->mac_id = 0;
-
- if ((mac->mode == WIRELESS_MODE_N_24G) ||
- (mac->mode == WIRELESS_MODE_N_5G)) {
- tcb_desc->ratr_index = RATR_INX_WIRELESS_NGB;
- } else if (mac->mode & WIRELESS_MODE_G) {
- tcb_desc->ratr_index = RATR_INX_WIRELESS_GB;
- } else if (mac->mode & WIRELESS_MODE_B) {
- tcb_desc->ratr_index = RATR_INX_WIRELESS_B;
+ if (mac->opmode == NL80211_IFTYPE_STATION) {
+ tcb_desc->mac_id = 0;
+
+ if (mac->mode == WIRELESS_MODE_N_24G)
+ tcb_desc->ratr_index = RATR_INX_WIRELESS_NGB;
+ else if (mac->mode == WIRELESS_MODE_N_5G)
+ tcb_desc->ratr_index = RATR_INX_WIRELESS_NG;
+ else if (mac->mode & WIRELESS_MODE_G)
+ tcb_desc->ratr_index = RATR_INX_WIRELESS_GB;
+ else if (mac->mode & WIRELESS_MODE_B)
+ tcb_desc->ratr_index = RATR_INX_WIRELESS_B;
+ else if (mac->mode & WIRELESS_MODE_A)
+ tcb_desc->ratr_index = RATR_INX_WIRELESS_G;
+ } else if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_ADHOC) {
+ if (NULL != sta) {
+ if (sta->aid > 0)
+ tcb_desc->mac_id = sta->aid + 1;
+ else
+ tcb_desc->mac_id = 1;
+ } else {
+ tcb_desc->mac_id = 0;
+ }
}
}
}
static void _rtl_query_bandwidth_mode(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
struct rtl_tcb_desc *tcb_desc)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
tcb_desc->packet_bw = false;
-
- if (!mac->bw_40 || !mac->ht_enable)
+ if (!sta)
return;
-
+ if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_ADHOC) {
+ if (!(sta->ht_cap.ht_supported) ||
+ !(sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
+ return;
+ } else if (mac->opmode == NL80211_IFTYPE_STATION) {
+ if (!mac->bw_40 || !(sta->ht_cap.ht_supported))
+ return;
+ }
if (tcb_desc->multicast || tcb_desc->broadcast)
return;
@@ -484,22 +664,21 @@ static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw)
void rtl_get_tcb_desc(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info,
+ struct ieee80211_sta *sta,
struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *rtlmac = rtl_mac(rtl_priv(hw));
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
+ struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
struct ieee80211_rate *txrate;
__le16 fc = hdr->frame_control;
- memset(tcb_desc, 0, sizeof(struct rtl_tcb_desc));
+ txrate = ieee80211_get_tx_rate(hw, info);
+ tcb_desc->hw_rate = txrate->hw_value;
if (ieee80211_is_data(fc)) {
- txrate = ieee80211_get_tx_rate(hw, info);
- tcb_desc->hw_rate = txrate->hw_value;
-
/*
- *we set data rate RTL_RC_CCK_RATE1M
+ *we set data rate INX 0
*in rtl_rc.c if skb is special data or
*mgt which need low data rate.
*/
@@ -508,12 +687,11 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw,
*So tcb_desc->hw_rate is just used for
*special data and mgt frames
*/
- if (tcb_desc->hw_rate < rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M]) {
+ if (info->control.rates[0].idx == 0 &&
+ ieee80211_is_nullfunc(fc)) {
tcb_desc->use_driver_rate = true;
- tcb_desc->ratr_index = 7;
+ tcb_desc->ratr_index = RATR_INX_WIRELESS_MC;
- tcb_desc->hw_rate =
- rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M];
tcb_desc->disable_ratefallback = 1;
} else {
/*
@@ -523,7 +701,7 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw,
*and N rate will all be controlled by FW
*when tcb_desc->use_driver_rate = false
*/
- if (rtlmac->ht_enable) {
+ if (sta && (sta->ht_cap.ht_supported)) {
tcb_desc->hw_rate = _rtl_get_highest_n_rate(hw);
} else {
if (rtlmac->mode == WIRELESS_MODE_B) {
@@ -541,43 +719,25 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw,
else if (is_broadcast_ether_addr(ieee80211_get_DA(hdr)))
tcb_desc->broadcast = 1;
- _rtl_txrate_selectmode(hw, tcb_desc);
- _rtl_query_bandwidth_mode(hw, tcb_desc);
+ _rtl_txrate_selectmode(hw, sta, tcb_desc);
+ _rtl_query_bandwidth_mode(hw, sta, tcb_desc);
_rtl_qurey_shortpreamble_mode(hw, tcb_desc, info);
- _rtl_query_shortgi(hw, tcb_desc, info);
+ _rtl_query_shortgi(hw, sta, tcb_desc, info);
_rtl_query_protection_mode(hw, tcb_desc, info);
} else {
tcb_desc->use_driver_rate = true;
- tcb_desc->ratr_index = 7;
+ tcb_desc->ratr_index = RATR_INX_WIRELESS_MC;
tcb_desc->disable_ratefallback = 1;
tcb_desc->mac_id = 0;
-
- tcb_desc->hw_rate = rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M];
+ tcb_desc->packet_bw = false;
}
}
EXPORT_SYMBOL(rtl_get_tcb_desc);
-bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
- struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
- __le16 fc = hdr->frame_control;
-
- if (ieee80211_is_auth(fc)) {
- RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n"));
- rtl_ips_nic_on(hw);
-
- mac->link_state = MAC80211_LINKING;
- }
-
- return true;
-}
-
bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
{
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
+ struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
struct rtl_priv *rtlpriv = rtl_priv(hw);
__le16 fc = hdr->frame_control;
u8 *act = (u8 *) (((u8 *) skb->data + MAC80211_3ADDR_LEN));
@@ -622,22 +782,20 @@ bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
- __le16 fc = hdr->frame_control;
+ __le16 fc = rtl_get_fc(skb);
u16 ether_type;
u8 mac_hdr_len = ieee80211_get_hdrlen_from_skb(skb);
const struct iphdr *ip;
if (!ieee80211_is_data(fc))
- goto end;
+ return false;
- if (ieee80211_is_nullfunc(fc))
- return true;
ip = (struct iphdr *)((u8 *) skb->data + mac_hdr_len +
SNAP_SIZE + PROTOC_TYPE_SIZE);
ether_type = *(u16 *) ((u8 *) skb->data + mac_hdr_len + SNAP_SIZE);
+ /* ether_type = ntohs(ether_type); */
if (ETH_P_IP == ether_type) {
if (IPPROTO_UDP == ip->protocol) {
@@ -686,7 +844,6 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx)
return true;
}
-end:
return false;
}
@@ -695,61 +852,92 @@ end:
* functions called by core.c
*
*********************************************************/
-int rtl_tx_agg_start(struct ieee80211_hw *hw, const u8 *ra, u16 tid, u16 *ssn)
+int rtl_tx_agg_start(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u16 tid, u16 *ssn)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_tid_data *tid_data;
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_sta_info *sta_entry = NULL;
- RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG,
- ("on ra = %pM tid = %d\n", ra, tid));
+ if (sta == NULL)
+ return -EINVAL;
if (unlikely(tid >= MAX_TID_COUNT))
return -EINVAL;
- if (mac->tids[tid].agg.agg_state != RTL_AGG_OFF) {
- RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
- ("Start AGG when state is not RTL_AGG_OFF !\n"));
+ sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+ if (!sta_entry)
return -ENXIO;
- }
-
- tid_data = &mac->tids[tid];
- *ssn = SEQ_TO_SN(tid_data->seq_number);
+ tid_data = &sta_entry->tids[tid];
RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG,
- ("HW queue is empty tid:%d\n", tid));
- tid_data->agg.agg_state = RTL_AGG_ON;
+ ("on ra = %pM tid = %d seq:%d\n", sta->addr, tid,
+ tid_data->seq_number));
+
+ *ssn = tid_data->seq_number;
+ tid_data->agg.agg_state = RTL_AGG_START;
- ieee80211_start_tx_ba_cb_irqsafe(mac->vif, ra, tid);
+ ieee80211_start_tx_ba_cb_irqsafe(mac->vif, sta->addr, tid);
return 0;
}
-int rtl_tx_agg_stop(struct ieee80211_hw *hw, const u8 * ra, u16 tid)
+int rtl_tx_agg_stop(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u16 tid)
{
- int ssn = -1;
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_tid_data *tid_data;
+ struct rtl_sta_info *sta_entry = NULL;
+
+ if (sta == NULL)
+ return -EINVAL;
- if (!ra) {
+ if (!sta->addr) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("ra = NULL\n"));
return -EINVAL;
}
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG,
+ ("on ra = %pM tid = %d\n", sta->addr, tid));
+
if (unlikely(tid >= MAX_TID_COUNT))
return -EINVAL;
- if (mac->tids[tid].agg.agg_state != RTL_AGG_ON)
- RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
- ("Stopping AGG while state not ON or starting\n"));
+ sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+ tid_data = &sta_entry->tids[tid];
+ sta_entry->tids[tid].agg.agg_state = RTL_AGG_STOP;
+
+ ieee80211_stop_tx_ba_cb_irqsafe(mac->vif, sta->addr, tid);
- tid_data = &mac->tids[tid];
- ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4;
+ return 0;
+}
- mac->tids[tid].agg.agg_state = RTL_AGG_OFF;
+int rtl_tx_agg_oper(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u16 tid)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_tid_data *tid_data;
+ struct rtl_sta_info *sta_entry = NULL;
- ieee80211_stop_tx_ba_cb_irqsafe(mac->vif, ra, tid);
+ if (sta == NULL)
+ return -EINVAL;
+
+ if (!sta->addr) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("ra = NULL\n"));
+ return -EINVAL;
+ }
+
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG,
+ ("on ra = %pM tid = %d\n", sta->addr, tid));
+
+ if (unlikely(tid >= MAX_TID_COUNT))
+ return -EINVAL;
+
+ sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+ tid_data = &sta_entry->tids[tid];
+ sta_entry->tids[tid].agg.agg_state = RTL_AGG_OPERATIONAL;
return 0;
}
@@ -768,18 +956,16 @@ void rtl_watchdog_wq_callback(void *data)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-
bool busytraffic = false;
bool higher_busytraffic = false;
bool higher_busyrxtraffic = false;
- bool higher_busytxtraffic = false;
-
- u8 idx = 0;
+ u8 idx, tid;
u32 rx_cnt_inp4eriod = 0;
u32 tx_cnt_inp4eriod = 0;
u32 aver_rx_cnt_inperiod = 0;
u32 aver_tx_cnt_inperiod = 0;
-
+ u32 aver_tidtx_inperiod[MAX_TID_COUNT] = {0};
+ u32 tidtx_inp4eriod[MAX_TID_COUNT] = {0};
bool enter_ps = false;
if (is_hal_stop(rtlhal))
@@ -793,9 +979,6 @@ void rtl_watchdog_wq_callback(void *data)
mac->cnt_after_linked = 0;
}
- /* <2> DM */
- rtlpriv->cfg->ops->dm_watchdog(hw);
-
/*
*<3> to check if traffic busy, if
* busytraffic we don't change channel
@@ -834,8 +1017,27 @@ void rtl_watchdog_wq_callback(void *data)
/* Extremely high Rx data. */
if (aver_rx_cnt_inperiod > 5000)
higher_busyrxtraffic = true;
+ }
+
+ /* check every tid's tx traffic */
+ for (tid = 0; tid <= 7; tid++) {
+ for (idx = 0; idx <= 2; idx++)
+ rtlpriv->link_info.tidtx_in4period[tid][idx] =
+ rtlpriv->link_info.tidtx_in4period[tid]
+ [idx + 1];
+ rtlpriv->link_info.tidtx_in4period[tid][3] =
+ rtlpriv->link_info.tidtx_inperiod[tid];
+
+ for (idx = 0; idx <= 3; idx++)
+ tidtx_inp4eriod[tid] +=
+ rtlpriv->link_info.tidtx_in4period[tid][idx];
+ aver_tidtx_inperiod[tid] = tidtx_inp4eriod[tid] / 4;
+ if (aver_tidtx_inperiod[tid] > 5000)
+ rtlpriv->link_info.higher_busytxtraffic[tid] =
+ true;
else
- higher_busytxtraffic = false;
+ rtlpriv->link_info.higher_busytxtraffic[tid] =
+ false;
}
if (((rtlpriv->link_info.num_rx_inperiod +
@@ -854,11 +1056,15 @@ void rtl_watchdog_wq_callback(void *data)
rtlpriv->link_info.num_rx_inperiod = 0;
rtlpriv->link_info.num_tx_inperiod = 0;
+ for (tid = 0; tid <= 7; tid++)
+ rtlpriv->link_info.tidtx_inperiod[tid] = 0;
rtlpriv->link_info.busytraffic = busytraffic;
rtlpriv->link_info.higher_busytraffic = higher_busytraffic;
rtlpriv->link_info.higher_busyrxtraffic = higher_busyrxtraffic;
+ /* <3> DM */
+ rtlpriv->cfg->ops->dm_watchdog(hw);
}
void rtl_watch_dog_timer_callback(unsigned long data)
@@ -875,6 +1081,268 @@ void rtl_watch_dog_timer_callback(unsigned long data)
/*********************************************************
*
+ * frame process functions
+ *
+ *********************************************************/
+u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie)
+{
+ struct ieee80211_mgmt *mgmt = (void *)data;
+ u8 *pos, *end;
+
+ pos = (u8 *)mgmt->u.beacon.variable;
+ end = data + len;
+ while (pos < end) {
+ if (pos + 2 + pos[1] > end)
+ return NULL;
+
+ if (pos[0] == ie)
+ return pos;
+
+ pos += 2 + pos[1];
+ }
+ return NULL;
+}
+
+/* when we use 2 rx ants we send IEEE80211_SMPS_OFF */
+/* when we use 1 rx ant we send IEEE80211_SMPS_STATIC */
+static struct sk_buff *rtl_make_smps_action(struct ieee80211_hw *hw,
+ enum ieee80211_smps_mode smps, u8 *da, u8 *bssid)
+{
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct sk_buff *skb;
+ struct ieee80211_mgmt *action_frame;
+
+ /* 27 = header + category + action + smps mode */
+ skb = dev_alloc_skb(27 + hw->extra_tx_headroom);
+ if (!skb)
+ return NULL;
+
+ skb_reserve(skb, hw->extra_tx_headroom);
+ action_frame = (void *)skb_put(skb, 27);
+ memset(action_frame, 0, 27);
+ memcpy(action_frame->da, da, ETH_ALEN);
+ memcpy(action_frame->sa, rtlefuse->dev_addr, ETH_ALEN);
+ memcpy(action_frame->bssid, bssid, ETH_ALEN);
+ action_frame->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+ IEEE80211_STYPE_ACTION);
+ action_frame->u.action.category = WLAN_CATEGORY_HT;
+ action_frame->u.action.u.ht_smps.action = WLAN_HT_ACTION_SMPS;
+ switch (smps) {
+ case IEEE80211_SMPS_AUTOMATIC:/* 0 */
+ case IEEE80211_SMPS_NUM_MODES:/* 4 */
+ WARN_ON(1);
+ case IEEE80211_SMPS_OFF:/* 1 */ /*MIMO_PS_NOLIMIT*/
+ action_frame->u.action.u.ht_smps.smps_control =
+ WLAN_HT_SMPS_CONTROL_DISABLED;/* 0 */
+ break;
+ case IEEE80211_SMPS_STATIC:/* 2 */ /*MIMO_PS_STATIC*/
+ action_frame->u.action.u.ht_smps.smps_control =
+ WLAN_HT_SMPS_CONTROL_STATIC;/* 1 */
+ break;
+ case IEEE80211_SMPS_DYNAMIC:/* 3 */ /*MIMO_PS_DYNAMIC*/
+ action_frame->u.action.u.ht_smps.smps_control =
+ WLAN_HT_SMPS_CONTROL_DYNAMIC;/* 3 */
+ break;
+ }
+
+ return skb;
+}
+
+int rtl_send_smps_action(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u8 *da, u8 *bssid,
+ enum ieee80211_smps_mode smps)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct sk_buff *skb = rtl_make_smps_action(hw, smps, da, bssid);
+ struct rtl_tcb_desc tcb_desc;
+ memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
+
+ if (rtlpriv->mac80211.act_scanning)
+ goto err_free;
+
+ if (!sta)
+ goto err_free;
+
+ if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON))
+ goto err_free;
+
+ if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status))
+ goto err_free;
+
+ /* this is a type = mgmt * stype = action frame */
+ if (skb) {
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct rtl_sta_info *sta_entry =
+ (struct rtl_sta_info *) sta->drv_priv;
+ sta_entry->mimo_ps = smps;
+ rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
+
+ info->control.rates[0].idx = 0;
+ info->control.sta = sta;
+ info->band = hw->conf.channel->band;
+ rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc);
+ }
+err_free:
+ return 0;
+}
+
+/*********************************************************
+ *
+ * IOT functions
+ *
+ *********************************************************/
+static bool rtl_chk_vendor_ouisub(struct ieee80211_hw *hw,
+ struct octet_string vendor_ie)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ bool matched = false;
+ static u8 athcap_1[] = { 0x00, 0x03, 0x7F };
+ static u8 athcap_2[] = { 0x00, 0x13, 0x74 };
+ static u8 broadcap_1[] = { 0x00, 0x10, 0x18 };
+ static u8 broadcap_2[] = { 0x00, 0x0a, 0xf7 };
+ static u8 broadcap_3[] = { 0x00, 0x05, 0xb5 };
+ static u8 racap[] = { 0x00, 0x0c, 0x43 };
+ static u8 ciscocap[] = { 0x00, 0x40, 0x96 };
+ static u8 marvcap[] = { 0x00, 0x50, 0x43 };
+
+ if (memcmp(vendor_ie.octet, athcap_1, 3) == 0 ||
+ memcmp(vendor_ie.octet, athcap_2, 3) == 0) {
+ rtlpriv->mac80211.vendor = PEER_ATH;
+ matched = true;
+ } else if (memcmp(vendor_ie.octet, broadcap_1, 3) == 0 ||
+ memcmp(vendor_ie.octet, broadcap_2, 3) == 0 ||
+ memcmp(vendor_ie.octet, broadcap_3, 3) == 0) {
+ rtlpriv->mac80211.vendor = PEER_BROAD;
+ matched = true;
+ } else if (memcmp(vendor_ie.octet, racap, 3) == 0) {
+ rtlpriv->mac80211.vendor = PEER_RAL;
+ matched = true;
+ } else if (memcmp(vendor_ie.octet, ciscocap, 3) == 0) {
+ rtlpriv->mac80211.vendor = PEER_CISCO;
+ matched = true;
+ } else if (memcmp(vendor_ie.octet, marvcap, 3) == 0) {
+ rtlpriv->mac80211.vendor = PEER_MARV;
+ matched = true;
+ }
+
+ return matched;
+}
+
+static bool rtl_find_221_ie(struct ieee80211_hw *hw, u8 *data,
+ unsigned int len)
+{
+ struct ieee80211_mgmt *mgmt = (void *)data;
+ struct octet_string vendor_ie;
+ u8 *pos, *end;
+
+ pos = (u8 *)mgmt->u.beacon.variable;
+ end = data + len;
+ while (pos < end) {
+ if (pos[0] == 221) {
+ vendor_ie.length = pos[1];
+ vendor_ie.octet = &pos[2];
+ if (rtl_chk_vendor_ouisub(hw, vendor_ie))
+ return true;
+ }
+
+ if (pos + 2 + pos[1] > end)
+ return false;
+
+ pos += 2 + pos[1];
+ }
+ return false;
+}
+
+void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct ieee80211_hdr *hdr = (void *)data;
+ u32 vendor = PEER_UNKNOWN;
+
+ static u8 ap3_1[3] = { 0x00, 0x14, 0xbf };
+ static u8 ap3_2[3] = { 0x00, 0x1a, 0x70 };
+ static u8 ap3_3[3] = { 0x00, 0x1d, 0x7e };
+ static u8 ap4_1[3] = { 0x00, 0x90, 0xcc };
+ static u8 ap4_2[3] = { 0x00, 0x0e, 0x2e };
+ static u8 ap4_3[3] = { 0x00, 0x18, 0x02 };
+ static u8 ap4_4[3] = { 0x00, 0x17, 0x3f };
+ static u8 ap4_5[3] = { 0x00, 0x1c, 0xdf };
+ static u8 ap5_1[3] = { 0x00, 0x1c, 0xf0 };
+ static u8 ap5_2[3] = { 0x00, 0x21, 0x91 };
+ static u8 ap5_3[3] = { 0x00, 0x24, 0x01 };
+ static u8 ap5_4[3] = { 0x00, 0x15, 0xe9 };
+ static u8 ap5_5[3] = { 0x00, 0x17, 0x9A };
+ static u8 ap5_6[3] = { 0x00, 0x18, 0xE7 };
+ static u8 ap6_1[3] = { 0x00, 0x17, 0x94 };
+ static u8 ap7_1[3] = { 0x00, 0x14, 0xa4 };
+
+ if (mac->opmode != NL80211_IFTYPE_STATION)
+ return;
+
+ if (mac->link_state == MAC80211_NOLINK) {
+ mac->vendor = PEER_UNKNOWN;
+ return;
+ }
+
+ if (mac->cnt_after_linked > 2)
+ return;
+
+ /* check if this really is a beacon */
+ if (!ieee80211_is_beacon(hdr->frame_control))
+ return;
+
+ /* min. beacon length + FCS_LEN */
+ if (len <= 40 + FCS_LEN)
+ return;
+
+ /* and only beacons from the associated BSSID, please */
+ if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid))
+ return;
+
+ if (rtl_find_221_ie(hw, data, len))
+ vendor = mac->vendor;
+
+ if ((memcmp(mac->bssid, ap5_1, 3) == 0) ||
+ (memcmp(mac->bssid, ap5_2, 3) == 0) ||
+ (memcmp(mac->bssid, ap5_3, 3) == 0) ||
+ (memcmp(mac->bssid, ap5_4, 3) == 0) ||
+ (memcmp(mac->bssid, ap5_5, 3) == 0) ||
+ (memcmp(mac->bssid, ap5_6, 3) == 0) ||
+ vendor == PEER_ATH) {
+ vendor = PEER_ATH;
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>ath find\n"));
+ } else if ((memcmp(mac->bssid, ap4_4, 3) == 0) ||
+ (memcmp(mac->bssid, ap4_5, 3) == 0) ||
+ (memcmp(mac->bssid, ap4_1, 3) == 0) ||
+ (memcmp(mac->bssid, ap4_2, 3) == 0) ||
+ (memcmp(mac->bssid, ap4_3, 3) == 0) ||
+ vendor == PEER_RAL) {
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>ral findn\n"));
+ vendor = PEER_RAL;
+ } else if (memcmp(mac->bssid, ap6_1, 3) == 0 ||
+ vendor == PEER_CISCO) {
+ vendor = PEER_CISCO;
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>cisco find\n"));
+ } else if ((memcmp(mac->bssid, ap3_1, 3) == 0) ||
+ (memcmp(mac->bssid, ap3_2, 3) == 0) ||
+ (memcmp(mac->bssid, ap3_3, 3) == 0) ||
+ vendor == PEER_BROAD) {
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>broad find\n"));
+ vendor = PEER_BROAD;
+ } else if (memcmp(mac->bssid, ap7_1, 3) == 0 ||
+ vendor == PEER_MARV) {
+ vendor = PEER_MARV;
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("=>marv find\n"));
+ }
+
+ mac->vendor = vendor;
+}
+
+/*********************************************************
+ *
* sysfs functions
*
*********************************************************/
@@ -940,12 +1408,13 @@ static int __init rtl_core_module_init(void)
if (rtl_rate_control_register())
printk(KERN_ERR "rtlwifi: Unable to register rtl_rc,"
"use default RC !!\n");
+
return 0;
}
static void __exit rtl_core_module_exit(void)
{
- /*RC*/
+ /*RC*/
rtl_rate_control_unregister();
}
diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h
index 043045342bc7..a91f3eee59c8 100644
--- a/drivers/net/wireless/rtlwifi/base.h
+++ b/drivers/net/wireless/rtlwifi/base.h
@@ -24,13 +24,26 @@
* Hsinchu 300, Taiwan.
*
* Larry Finger <Larry.Finger@lwfinger.net>
+ *
*****************************************************************************/
#ifndef __RTL_BASE_H__
#define __RTL_BASE_H__
+enum ap_peer {
+ PEER_UNKNOWN = 0,
+ PEER_RTL = 1,
+ PEER_RTL_92SE = 2,
+ PEER_BROAD = 3,
+ PEER_RAL = 4,
+ PEER_ATH = 5,
+ PEER_CISCO = 6,
+ PEER_MARV = 7,
+ PEER_AIRGO = 9,
+ PEER_MAX = 10,
+} ;
+
#define RTL_DUMMY_OFFSET 0
-#define RTL_RX_DESC_SIZE 24
#define RTL_DUMMY_UNIT 8
#define RTL_TX_DUMMY_SIZE (RTL_DUMMY_OFFSET * RTL_DUMMY_UNIT)
#define RTL_TX_DESC_SIZE 32
@@ -53,6 +66,14 @@
#define FRAME_OFFSET_SEQUENCE 22
#define FRAME_OFFSET_ADDRESS4 24
+#define SET_80211_HDR_FRAME_CONTROL(_hdr, _val) \
+ WRITEEF2BYTE(_hdr, _val)
+#define SET_80211_HDR_TYPE_AND_SUBTYPE(_hdr, _val) \
+ WRITEEF1BYTE(_hdr, _val)
+#define SET_80211_HDR_PWR_MGNT(_hdr, _val) \
+ SET_BITS_TO_LE_2BYTE(_hdr, 12, 1, _val)
+#define SET_80211_HDR_TO_DS(_hdr, _val) \
+ SET_BITS_TO_LE_2BYTE(_hdr, 8, 1, _val)
#define SET_80211_PS_POLL_AID(_hdr, _val) \
(*(u16 *)((u8 *)(_hdr) + 2) = le16_to_cpu(_val))
@@ -64,11 +85,27 @@
#define SET_80211_HDR_DURATION(_hdr, _val) \
(*(u16 *)((u8 *)(_hdr) + FRAME_OFFSET_DURATION) = le16_to_cpu(_val))
#define SET_80211_HDR_ADDRESS1(_hdr, _val) \
- memcpy((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS1, (u8*)(_val), ETH_ALEN)
+ CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS1, (u8 *)(_val))
#define SET_80211_HDR_ADDRESS2(_hdr, _val) \
- memcpy((u8 *)(_hdr) + FRAME_OFFSET_ADDRESS2, (u8 *)(_val), ETH_ALEN)
+ CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS2, (u8 *)(_val))
#define SET_80211_HDR_ADDRESS3(_hdr, _val) \
- memcpy((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS3, (u8 *)(_val), ETH_ALEN)
+ CP_MACADDR((u8 *)(_hdr)+FRAME_OFFSET_ADDRESS3, (u8 *)(_val))
+#define SET_80211_HDR_FRAGMENT_SEQUENCE(_hdr, _val) \
+ WRITEEF2BYTE((u8 *)(_hdr)+FRAME_OFFSET_SEQUENCE, _val)
+
+#define SET_BEACON_PROBE_RSP_TIME_STAMP_LOW(__phdr, __val) \
+ WRITEEF4BYTE(((u8 *)(__phdr)) + 24, __val)
+#define SET_BEACON_PROBE_RSP_TIME_STAMP_HIGH(__phdr, __val) \
+ WRITEEF4BYTE(((u8 *)(__phdr)) + 28, __val)
+#define SET_BEACON_PROBE_RSP_BEACON_INTERVAL(__phdr, __val) \
+ WRITEEF2BYTE(((u8 *)(__phdr)) + 32, __val)
+#define GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr) \
+ READEF2BYTE(((u8 *)(__phdr)) + 34)
+#define SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, __val) \
+ WRITEEF2BYTE(((u8 *)(__phdr)) + 34, __val)
+#define MASK_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, __val) \
+ SET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr, \
+ (GET_BEACON_PROBE_RSP_CAPABILITY_INFO(__phdr) & (~(__val))))
int rtl_init_core(struct ieee80211_hw *hw);
void rtl_deinit_core(struct ieee80211_hw *hw);
@@ -80,18 +117,27 @@ void rtl_watch_dog_timer_callback(unsigned long data);
void rtl_deinit_deferred_work(struct ieee80211_hw *hw);
bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx);
-bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb);
u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx);
void rtl_watch_dog_timer_callback(unsigned long data);
-int rtl_tx_agg_start(struct ieee80211_hw *hw, const u8 *ra,
+int rtl_tx_agg_start(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
u16 tid, u16 *ssn);
-int rtl_tx_agg_stop(struct ieee80211_hw *hw, const u8 *ra, u16 tid);
+int rtl_tx_agg_stop(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
+ u16 tid);
+int rtl_tx_agg_oper(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
+ u16 tid);
void rtl_watchdog_wq_callback(void *data);
void rtl_get_tcb_desc(struct ieee80211_hw *hw,
struct ieee80211_tx_info *info,
+ struct ieee80211_sta *sta,
struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc);
+int rtl_send_smps_action(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u8 *da, u8 *bssid,
+ enum ieee80211_smps_mode smps);
+u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie);
+void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len);
+u8 rtl_tid_to_ac(struct ieee80211_hw *hw, u8 tid);
extern struct attribute_group rtl_attribute_group;
#endif
diff --git a/drivers/net/wireless/rtlwifi/cam.c b/drivers/net/wireless/rtlwifi/cam.c
index 52c9c1367cac..7295af0536b7 100644
--- a/drivers/net/wireless/rtlwifi/cam.c
+++ b/drivers/net/wireless/rtlwifi/cam.c
@@ -23,6 +23,8 @@
* Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
* Hsinchu 300, Taiwan.
*
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
*****************************************************************************/
#include "wifi.h"
@@ -49,7 +51,7 @@ static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no,
u32 target_content = 0;
u8 entry_i;
- RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
("key_cont_128:\n %x:%x:%x:%x:%x:%x\n",
key_cont_128[0], key_cont_128[1],
key_cont_128[2], key_cont_128[3],
@@ -68,15 +70,13 @@ static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no,
rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
target_command);
- RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
- ("rtl_cam_program_entry(): "
- "WRITE %x: %x\n",
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+ ("WRITE %x: %x\n",
rtlpriv->cfg->maps[WCAMI], target_content));
- RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
("The Key ID is %d\n", entry_no));
- RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
- ("rtl_cam_program_entry(): "
- "WRITE %x: %x\n",
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+ ("WRITE %x: %x\n",
rtlpriv->cfg->maps[RWCAM], target_command));
} else if (entry_i == 1) {
@@ -91,12 +91,10 @@ static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no,
rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[RWCAM],
target_command);
- RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
- ("rtl_cam_program_entry(): WRITE A4: %x\n",
- target_content));
- RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
- ("rtl_cam_program_entry(): WRITE A0: %x\n",
- target_command));
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+ ("WRITE A4: %x\n", target_content));
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+ ("WRITE A0: %x\n", target_command));
} else {
@@ -113,16 +111,14 @@ static void rtl_cam_program_entry(struct ieee80211_hw *hw, u32 entry_no,
target_command);
udelay(100);
- RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
- ("rtl_cam_program_entry(): WRITE A4: %x\n",
- target_content));
- RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
- ("rtl_cam_program_entry(): WRITE A0: %x\n",
- target_command));
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+ ("WRITE A4: %x\n", target_content));
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+ ("WRITE A0: %x\n", target_command));
}
}
- RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
("after set key, usconfig:%x\n", us_config));
}
@@ -289,3 +285,71 @@ void rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index)
}
EXPORT_SYMBOL(rtl_cam_empty_entry);
+
+u8 rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> 4;
+ u8 entry_idx = 0;
+ u8 i, *addr;
+
+ if (NULL == sta_addr) {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG,
+ ("sta_addr is NULL.\n"));
+ return TOTAL_CAM_ENTRY;
+ }
+ /* Does STA already exist? */
+ for (i = 4; i < TOTAL_CAM_ENTRY; i++) {
+ addr = rtlpriv->sec.hwsec_cam_sta_addr[i];
+ if (memcmp(addr, sta_addr, ETH_ALEN) == 0)
+ return i;
+ }
+ /* Get a free CAM entry. */
+ for (entry_idx = 4; entry_idx < TOTAL_CAM_ENTRY; entry_idx++) {
+ if ((bitmap & BIT(0)) == 0) {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG,
+ ("-----hwsec_cam_bitmap: 0x%x entry_idx=%d\n",
+ rtlpriv->sec.hwsec_cam_bitmap, entry_idx));
+ rtlpriv->sec.hwsec_cam_bitmap |= BIT(0) << entry_idx;
+ memcpy(rtlpriv->sec.hwsec_cam_sta_addr[entry_idx],
+ sta_addr, ETH_ALEN);
+ return entry_idx;
+ }
+ bitmap = bitmap >> 1;
+ }
+ return TOTAL_CAM_ENTRY;
+}
+EXPORT_SYMBOL(rtl_cam_get_free_entry);
+
+void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 bitmap;
+ u8 i, *addr;
+
+ if (NULL == sta_addr) {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG,
+ ("sta_addr is NULL.\n"));
+ }
+
+ if ((sta_addr[0]|sta_addr[1]|sta_addr[2]|sta_addr[3]|\
+ sta_addr[4]|sta_addr[5]) == 0) {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_EMERG,
+ ("sta_addr is 00:00:00:00:00:00.\n"));
+ return;
+ }
+ /* Does STA already exist? */
+ for (i = 4; i < TOTAL_CAM_ENTRY; i++) {
+ addr = rtlpriv->sec.hwsec_cam_sta_addr[i];
+ bitmap = (rtlpriv->sec.hwsec_cam_bitmap) >> i;
+ if (((bitmap & BIT(0)) == BIT(0)) &&
+ (memcmp(addr, sta_addr, ETH_ALEN) == 0)) {
+ /* Remove from HW Security CAM */
+ memset(rtlpriv->sec.hwsec_cam_sta_addr[i], 0, ETH_ALEN);
+ rtlpriv->sec.hwsec_cam_bitmap &= ~(BIT(0) << i);
+ printk(KERN_INFO "&&&&&&&&&del entry %d\n", i);
+ }
+ }
+ return;
+}
+EXPORT_SYMBOL(rtl_cam_del_entry);
diff --git a/drivers/net/wireless/rtlwifi/cam.h b/drivers/net/wireless/rtlwifi/cam.h
index dd82f057d53d..c62da4eefc75 100644
--- a/drivers/net/wireless/rtlwifi/cam.h
+++ b/drivers/net/wireless/rtlwifi/cam.h
@@ -23,12 +23,13 @@
* Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
* Hsinchu 300, Taiwan.
*
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
*****************************************************************************/
#ifndef __RTL_CAM_H_
#define __RTL_CAM_H_
-#define TOTAL_CAM_ENTRY 32
#define CAM_CONTENT_COUNT 8
#define CFG_DEFAULT_KEY BIT(5)
@@ -49,5 +50,7 @@ int rtl_cam_delete_one_entry(struct ieee80211_hw *hw, u8 *mac_addr,
void rtl_cam_mark_invalid(struct ieee80211_hw *hw, u8 uc_index);
void rtl_cam_empty_entry(struct ieee80211_hw *hw, u8 uc_index);
void rtl_cam_reset_sec_info(struct ieee80211_hw *hw);
+u8 rtl_cam_get_free_entry(struct ieee80211_hw *hw, u8 *sta_addr);
+void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr);
#endif
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c
index e4f4aee8f298..d2ec2535aa3c 100644
--- a/drivers/net/wireless/rtlwifi/core.c
+++ b/drivers/net/wireless/rtlwifi/core.c
@@ -24,6 +24,7 @@
* Hsinchu 300, Taiwan.
*
* Larry Finger <Larry.Finger@lwfinger.net>
+ *
*****************************************************************************/
#include "wifi.h"
@@ -35,7 +36,7 @@
/*mutex for start & stop is must here. */
static int rtl_op_start(struct ieee80211_hw *hw)
{
- int err = 0;
+ int err;
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
@@ -45,10 +46,8 @@ static int rtl_op_start(struct ieee80211_hw *hw)
return 0;
mutex_lock(&rtlpriv->locks.conf_mutex);
err = rtlpriv->intf_ops->adapter_start(hw);
- if (err)
- goto out;
- rtl_watch_dog_timer_callback((unsigned long)hw);
-out:
+ if (!err)
+ rtl_watch_dog_timer_callback((unsigned long)hw);
mutex_unlock(&rtlpriv->locks.conf_mutex);
return err;
}
@@ -72,6 +71,7 @@ static void rtl_op_stop(struct ieee80211_hw *hw)
mac->link_state = MAC80211_NOLINK;
memset(mac->bssid, 0, 6);
+ mac->vendor = PEER_UNKNOWN;
/*reset sec info */
rtl_cam_reset_sec_info(hw);
@@ -87,6 +87,8 @@ static void rtl_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_tcb_desc tcb_desc;
+ memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
if (unlikely(is_hal_stop(rtlhal) || ppsc->rfpwr_state != ERFON))
goto err_free;
@@ -94,8 +96,8 @@ static void rtl_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
if (!test_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status))
goto err_free;
-
- rtlpriv->intf_ops->adapter_tx(hw, skb);
+ if (!rtlpriv->intf_ops->waitq_insert(hw, skb))
+ rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc);
return;
@@ -136,10 +138,26 @@ static int rtl_op_add_interface(struct ieee80211_hw *hw,
mac->link_state = MAC80211_LINKED;
rtlpriv->cfg->ops->set_bcn_reg(hw);
+ if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G)
+ mac->basic_rates = 0xfff;
+ else
+ mac->basic_rates = 0xff0;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
+ (u8 *) (&mac->basic_rates));
+
break;
case NL80211_IFTYPE_AP:
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
("NL80211_IFTYPE_AP\n"));
+
+ mac->link_state = MAC80211_LINKED;
+ rtlpriv->cfg->ops->set_bcn_reg(hw);
+ if (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G)
+ mac->basic_rates = 0xfff;
+ else
+ mac->basic_rates = 0xff0;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
+ (u8 *) (&mac->basic_rates));
break;
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
@@ -186,13 +204,12 @@ static void rtl_op_remove_interface(struct ieee80211_hw *hw,
mac->vif = NULL;
mac->link_state = MAC80211_NOLINK;
memset(mac->bssid, 0, 6);
+ mac->vendor = PEER_UNKNOWN;
mac->opmode = NL80211_IFTYPE_UNSPECIFIED;
rtlpriv->cfg->ops->set_network_type(hw, mac->opmode);
-
mutex_unlock(&rtlpriv->locks.conf_mutex);
}
-
static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -224,10 +241,25 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
/*For LPS */
if (changed & IEEE80211_CONF_CHANGE_PS) {
- if (conf->flags & IEEE80211_CONF_PS)
- rtl_lps_enter(hw);
- else
- rtl_lps_leave(hw);
+ cancel_delayed_work(&rtlpriv->works.ps_work);
+ cancel_delayed_work(&rtlpriv->works.ps_rfon_wq);
+ if (conf->flags & IEEE80211_CONF_PS) {
+ rtlpriv->psc.sw_ps_enabled = true;
+ /* sleep here is must, or we may recv the beacon and
+ * cause mac80211 into wrong ps state, this will cause
+ * power save nullfunc send fail, and further cause
+ * pkt loss, So sleep must quickly but not immediatly
+ * because that will cause nullfunc send by mac80211
+ * fail, and cause pkt loss, we have tested that 5mA
+ * is worked very well */
+ if (!rtlpriv->psc.multi_buffered)
+ queue_delayed_work(rtlpriv->works.rtl_wq,
+ &rtlpriv->works.ps_work,
+ MSECS(5));
+ } else {
+ rtl_swlps_rf_awake(hw);
+ rtlpriv->psc.sw_ps_enabled = false;
+ }
}
if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) {
@@ -259,7 +291,7 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
case NL80211_CHAN_NO_HT:
/* SC */
mac->cur_40_prime_sc =
- PRIME_CHNL_OFFSET_DONT_CARE;
+ PRIME_CHNL_OFFSET_DONT_CARE;
rtlphy->current_chan_bw = HT_CHANNEL_WIDTH_20;
mac->bw_40 = false;
break;
@@ -267,7 +299,7 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
/* SC */
mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_UPPER;
rtlphy->current_chan_bw =
- HT_CHANNEL_WIDTH_20_40;
+ HT_CHANNEL_WIDTH_20_40;
mac->bw_40 = true;
/*wide channel */
@@ -278,7 +310,7 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
/* SC */
mac->cur_40_prime_sc = PRIME_CHNL_OFFSET_LOWER;
rtlphy->current_chan_bw =
- HT_CHANNEL_WIDTH_20_40;
+ HT_CHANNEL_WIDTH_20_40;
mac->bw_40 = true;
/*wide channel */
@@ -288,16 +320,29 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
default:
mac->bw_40 = false;
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
- ("switch case not processed\n"));
+ ("switch case not processed\n"));
break;
}
if (wide_chan <= 0)
wide_chan = 1;
+
+ /* In scanning, before we go offchannel we may send a ps=1 null
+ * to AP, and then we may send a ps = 0 null to AP quickly, but
+ * first null may have caused AP to put lots of packet to hw tx
+ * buffer. These packets must be tx'd before we go off channel
+ * so we must delay more time to let AP flush these packets
+ * before going offchannel, or dis-association or delete BA will
+ * happen by AP
+ */
+ if (rtlpriv->mac80211.offchan_deley) {
+ rtlpriv->mac80211.offchan_deley = false;
+ mdelay(50);
+ }
rtlphy->current_channel = wide_chan;
- rtlpriv->cfg->ops->set_channel_access(hw);
rtlpriv->cfg->ops->switch_channel(hw);
+ rtlpriv->cfg->ops->set_channel_access(hw);
rtlpriv->cfg->ops->set_bw_mode(hw,
hw->conf.channel_type);
}
@@ -345,27 +390,28 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw,
}
}
- if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
- /*
- *TODO: BIT(5) is probe response BIT(8) is beacon
- *TODO: Use define for BIT(5) and BIT(8)
- */
- if (*new_flags & FIF_BCN_PRBRESP_PROMISC)
- mac->rx_mgt_filter |= (BIT(5) | BIT(8));
- else
- mac->rx_mgt_filter &= ~(BIT(5) | BIT(8));
+ /* if ssid not set to hw don't check bssid
+ * here just used for linked scanning, & linked
+ * and nolink check bssid is set in set network_type */
+ if ((changed_flags & FIF_BCN_PRBRESP_PROMISC) &&
+ (mac->link_state >= MAC80211_LINKED)) {
+ if (mac->opmode != NL80211_IFTYPE_AP) {
+ if (*new_flags & FIF_BCN_PRBRESP_PROMISC) {
+ rtlpriv->cfg->ops->set_chk_bssid(hw, false);
+ } else {
+ rtlpriv->cfg->ops->set_chk_bssid(hw, true);
+ }
+ }
}
if (changed_flags & FIF_CONTROL) {
if (*new_flags & FIF_CONTROL) {
mac->rx_conf |= rtlpriv->cfg->maps[MAC_RCR_ACF];
- mac->rx_ctrl_filter |= RTL_SUPPORTED_CTRL_FILTER;
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
("Enable receive control frame.\n"));
} else {
mac->rx_conf &= ~rtlpriv->cfg->maps[MAC_RCR_ACF];
- mac->rx_ctrl_filter &= ~RTL_SUPPORTED_CTRL_FILTER;
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
("Disable receive control frame.\n"));
}
@@ -382,14 +428,54 @@ static void rtl_op_configure_filter(struct ieee80211_hw *hw,
("Disable receive other BSS's frame.\n"));
}
}
-
- rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *) (&mac->rx_conf));
- rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_MGT_FILTER,
- (u8 *) (&mac->rx_mgt_filter));
- rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CTRL_FILTER,
- (u8 *) (&mac->rx_ctrl_filter));
}
+static int rtl_op_sta_add(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_sta_info *sta_entry;
+
+ if (sta) {
+ sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+ if (rtlhal->current_bandtype == BAND_ON_2_4G) {
+ sta_entry->wireless_mode = WIRELESS_MODE_G;
+ if (sta->supp_rates[0] <= 0xf)
+ sta_entry->wireless_mode = WIRELESS_MODE_B;
+ if (sta->ht_cap.ht_supported == true)
+ sta_entry->wireless_mode = WIRELESS_MODE_N_24G;
+ } else if (rtlhal->current_bandtype == BAND_ON_5G) {
+ sta_entry->wireless_mode = WIRELESS_MODE_A;
+ if (sta->ht_cap.ht_supported == true)
+ sta_entry->wireless_mode = WIRELESS_MODE_N_24G;
+ }
+
+ /* I found some times mac80211 give wrong supp_rates for adhoc*/
+ if (rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC)
+ sta_entry->wireless_mode = WIRELESS_MODE_G;
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
+ ("Add sta addr is "MAC_FMT"\n", MAC_ARG(sta->addr)));
+ rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
+ }
+ return 0;
+}
+static int rtl_op_sta_remove(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_sta_info *sta_entry;
+ if (sta) {
+ RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
+ ("Remove sta addr is "MAC_FMT"\n", MAC_ARG(sta->addr)));
+ sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+ sta_entry->wireless_mode = 0;
+ sta_entry->ratr_index = 0;
+ }
+ return 0;
+}
static int _rtl_get_hal_qnum(u16 queue)
{
int qnum;
@@ -446,19 +532,18 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_bss_conf *bss_conf, u32 changed)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct ieee80211_sta *sta = NULL;
mutex_lock(&rtlpriv->locks.conf_mutex);
-
if ((vif->type == NL80211_IFTYPE_ADHOC) ||
(vif->type == NL80211_IFTYPE_AP) ||
(vif->type == NL80211_IFTYPE_MESH_POINT)) {
-
if ((changed & BSS_CHANGED_BEACON) ||
(changed & BSS_CHANGED_BEACON_ENABLED &&
bss_conf->enable_beacon)) {
-
if (mac->beacon_enabled == 0) {
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
("BSS_CHANGED_BEACON_ENABLED\n"));
@@ -470,8 +555,13 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
rtlpriv->cfg->maps
[RTL_IBSS_INT_MASKS],
0);
+
+ if (rtlpriv->cfg->ops->linked_set_reg)
+ rtlpriv->cfg->ops->linked_set_reg(hw);
}
- } else {
+ }
+ if ((changed & BSS_CHANGED_BEACON_ENABLED &&
+ !bss_conf->enable_beacon)) {
if (mac->beacon_enabled == 1) {
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
("ADHOC DISABLE BEACON\n"));
@@ -482,7 +572,6 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
[RTL_IBSS_INT_MASKS]);
}
}
-
if (changed & BSS_CHANGED_BEACON_INT) {
RT_TRACE(rtlpriv, COMP_BEACON, DBG_TRACE,
("BSS_CHANGED_BEACON_INT\n"));
@@ -494,11 +583,25 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
/*TODO: reference to enum ieee80211_bss_change */
if (changed & BSS_CHANGED_ASSOC) {
if (bss_conf->assoc) {
+ /* we should reset all sec info & cam
+ * before set cam after linked, we should not
+ * reset in disassoc, that will cause tkip->wep
+ * fail because some flag will be wrong */
+ /* reset sec info */
+ rtl_cam_reset_sec_info(hw);
+ /* reset cam to fix wep fail issue
+ * when change from wpa to wep */
+ rtl_cam_reset_all_entry(hw);
+
mac->link_state = MAC80211_LINKED;
mac->cnt_after_linked = 0;
mac->assoc_id = bss_conf->aid;
memcpy(mac->bssid, bss_conf->bssid, 6);
+ if (rtlpriv->cfg->ops->linked_set_reg)
+ rtlpriv->cfg->ops->linked_set_reg(hw);
+ if (mac->opmode == NL80211_IFTYPE_STATION && sta)
+ rtlpriv->cfg->ops->update_rate_tbl(hw, sta, 0);
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
("BSS_CHANGED_ASSOC\n"));
} else {
@@ -507,9 +610,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
mac->link_state = MAC80211_NOLINK;
memset(mac->bssid, 0, 6);
-
- /* reset sec info */
- rtl_cam_reset_sec_info(hw);
+ mac->vendor = PEER_UNKNOWN;
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
("BSS_CHANGED_UN_ASSOC\n"));
@@ -546,14 +647,10 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
}
if (changed & BSS_CHANGED_HT) {
- struct ieee80211_sta *sta = NULL;
-
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
("BSS_CHANGED_HT\n"));
-
rcu_read_lock();
- sta = ieee80211_find_sta(mac->vif, mac->bssid);
-
+ sta = get_sta(hw, vif, (u8 *)bss_conf->bssid);
if (sta) {
if (sta->ht_cap.ampdu_density >
mac->current_ampdu_density)
@@ -575,9 +672,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
}
if (changed & BSS_CHANGED_BSSID) {
- struct ieee80211_sta *sta = NULL;
u32 basic_rates;
- u8 i;
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BSSID,
(u8 *) bss_conf->bssid);
@@ -585,96 +680,65 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_DMESG,
(MAC_FMT "\n", MAC_ARG(bss_conf->bssid)));
+ mac->vendor = PEER_UNKNOWN;
memcpy(mac->bssid, bss_conf->bssid, 6);
- if (is_valid_ether_addr(bss_conf->bssid)) {
- switch (vif->type) {
- case NL80211_IFTYPE_UNSPECIFIED:
- break;
- case NL80211_IFTYPE_ADHOC:
- break;
- case NL80211_IFTYPE_STATION:
- break;
- case NL80211_IFTYPE_AP:
- break;
- default:
- RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
- ("switch case not process\n"));
- break;
- }
- rtlpriv->cfg->ops->set_network_type(hw, vif->type);
- } else
- rtlpriv->cfg->ops->set_network_type(hw,
- NL80211_IFTYPE_UNSPECIFIED);
-
- memset(mac->mcs, 0, 16);
- mac->ht_enable = false;
- mac->sgi_40 = false;
- mac->sgi_20 = false;
-
- if (!bss_conf->use_short_slot)
- mac->mode = WIRELESS_MODE_B;
- else
- mac->mode = WIRELESS_MODE_G;
+ rtlpriv->cfg->ops->set_network_type(hw, vif->type);
rcu_read_lock();
- sta = ieee80211_find_sta(mac->vif, mac->bssid);
+ sta = get_sta(hw, vif, (u8 *)bss_conf->bssid);
+ if (!sta) {
+ rcu_read_unlock();
+ goto out;
+ }
- if (sta) {
- if (sta->ht_cap.ht_supported) {
+ if (rtlhal->current_bandtype == BAND_ON_5G) {
+ mac->mode = WIRELESS_MODE_A;
+ } else {
+ if (sta->supp_rates[0] <= 0xf)
+ mac->mode = WIRELESS_MODE_B;
+ else
+ mac->mode = WIRELESS_MODE_G;
+ }
+
+ if (sta->ht_cap.ht_supported) {
+ if (rtlhal->current_bandtype == BAND_ON_2_4G)
mac->mode = WIRELESS_MODE_N_24G;
- mac->ht_enable = true;
- }
+ else
+ mac->mode = WIRELESS_MODE_N_5G;
+ }
- if (mac->ht_enable) {
- u16 ht_cap = sta->ht_cap.cap;
- memcpy(mac->mcs, (u8 *) (&sta->ht_cap.mcs), 16);
-
- for (i = 0; i < 16; i++)
- RT_TRACE(rtlpriv, COMP_MAC80211,
- DBG_LOUD, ("%x ",
- mac->mcs[i]));
- RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD,
- ("\n"));
-
- if (ht_cap & IEEE80211_HT_CAP_SGI_40)
- mac->sgi_40 = true;
-
- if (ht_cap & IEEE80211_HT_CAP_SGI_20)
- mac->sgi_20 = true;
-
- /*
- * for cisco 1252 bw20 it's wrong
- * if (ht_cap &
- * IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
- * mac->bw_40 = true;
- * }
- */
- }
+ /* just station need it, because ibss & ap mode will
+ * set in sta_add, and will be NULL here */
+ if (mac->opmode == NL80211_IFTYPE_STATION) {
+ struct rtl_sta_info *sta_entry;
+ sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+ sta_entry->wireless_mode = mac->mode;
+ }
+
+ if (sta->ht_cap.ht_supported) {
+ mac->ht_enable = true;
+
+ /*
+ * for cisco 1252 bw20 it's wrong
+ * if (ht_cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
+ * mac->bw_40 = true;
+ * }
+ * */
}
- rcu_read_unlock();
- /*mac80211 just give us CCK rates any time
- *So we add G rate in basic rates when
- not in B mode*/
if (changed & BSS_CHANGED_BASIC_RATES) {
- if (mac->mode == WIRELESS_MODE_B)
- basic_rates = bss_conf->basic_rates | 0x00f;
+ /* for 5G must << RATE_6M_INDEX=4,
+ * because 5G have no cck rate*/
+ if (rtlhal->current_bandtype == BAND_ON_5G)
+ basic_rates = sta->supp_rates[1] << 4;
else
- basic_rates = bss_conf->basic_rates | 0xff0;
-
- if (!vif)
- goto out;
+ basic_rates = sta->supp_rates[0];
mac->basic_rates = basic_rates;
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_BASIC_RATE,
(u8 *) (&basic_rates));
-
- if (rtlpriv->dm.useramask)
- rtlpriv->cfg->ops->update_rate_mask(hw, 0);
- else
- rtlpriv->cfg->ops->update_rate_table(hw);
-
}
+ rcu_read_unlock();
}
/*
@@ -719,7 +783,7 @@ static void rtl_op_set_tsf(struct ieee80211_hw *hw, u64 tsf)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
- u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0;;
+ u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0;
mac->tsf = tsf;
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CORRECT_TSF, (u8 *) (&bibss));
@@ -760,16 +824,17 @@ static int rtl_op_ampdu_action(struct ieee80211_hw *hw,
case IEEE80211_AMPDU_TX_START:
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
("IEEE80211_AMPDU_TX_START: TID:%d\n", tid));
- return rtl_tx_agg_start(hw, sta->addr, tid, ssn);
+ return rtl_tx_agg_start(hw, sta, tid, ssn);
break;
case IEEE80211_AMPDU_TX_STOP:
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
("IEEE80211_AMPDU_TX_STOP: TID:%d\n", tid));
- return rtl_tx_agg_stop(hw, sta->addr, tid);
+ return rtl_tx_agg_stop(hw, sta, tid);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
("IEEE80211_AMPDU_TX_OPERATIONAL:TID:%d\n", tid));
+ rtl_tx_agg_oper(hw, sta, tid);
break;
case IEEE80211_AMPDU_RX_START:
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_TRACE,
@@ -799,8 +864,12 @@ static void rtl_op_sw_scan_start(struct ieee80211_hw *hw)
if (mac->link_state == MAC80211_LINKED) {
rtl_lps_leave(hw);
mac->link_state = MAC80211_LINKED_SCANNING;
- } else
+ } else {
rtl_ips_nic_on(hw);
+ }
+
+ /* Dual mac */
+ rtlpriv->rtlhal.load_imrandiqk_setting_for2g = false;
rtlpriv->cfg->ops->led_control(hw, LED_CTL_SITE_SURVEY);
rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_BACKUP);
@@ -812,22 +881,19 @@ static void rtl_op_sw_scan_complete(struct ieee80211_hw *hw)
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
RT_TRACE(rtlpriv, COMP_MAC80211, DBG_LOUD, ("\n"));
-
- rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_RESTORE);
mac->act_scanning = false;
+ /* Dual mac */
+ rtlpriv->rtlhal.load_imrandiqk_setting_for2g = false;
+
if (mac->link_state == MAC80211_LINKED_SCANNING) {
mac->link_state = MAC80211_LINKED;
-
- /* fix fwlps issue */
- rtlpriv->cfg->ops->set_network_type(hw, mac->opmode);
-
- if (rtlpriv->dm.useramask)
- rtlpriv->cfg->ops->update_rate_mask(hw, 0);
- else
- rtlpriv->cfg->ops->update_rate_table(hw);
-
+ if (mac->opmode == NL80211_IFTYPE_STATION) {
+ /* fix fwlps issue */
+ rtlpriv->cfg->ops->set_network_type(hw, mac->opmode);
+ }
}
+ rtlpriv->cfg->ops->scan_operation_backup(hw, SCAN_OPT_RESTORE);
}
static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
@@ -858,49 +924,73 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
rtl_ips_nic_on(hw);
mutex_lock(&rtlpriv->locks.conf_mutex);
/* <1> get encryption alg */
+
switch (key->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
key_type = WEP40_ENCRYPTION;
RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:WEP40\n"));
- rtlpriv->sec.use_defaultkey = true;
break;
case WLAN_CIPHER_SUITE_WEP104:
RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
("alg:WEP104\n"));
key_type = WEP104_ENCRYPTION;
- rtlpriv->sec.use_defaultkey = true;
break;
case WLAN_CIPHER_SUITE_TKIP:
key_type = TKIP_ENCRYPTION;
RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:TKIP\n"));
- if (mac->opmode == NL80211_IFTYPE_ADHOC)
- rtlpriv->sec.use_defaultkey = true;
break;
case WLAN_CIPHER_SUITE_CCMP:
key_type = AESCCMP_ENCRYPTION;
RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("alg:CCMP\n"));
- if (mac->opmode == NL80211_IFTYPE_ADHOC)
- rtlpriv->sec.use_defaultkey = true;
break;
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
("alg_err:%x!!!!:\n", key->cipher));
goto out_unlock;
}
+ if (key_type == WEP40_ENCRYPTION ||
+ key_type == WEP104_ENCRYPTION ||
+ mac->opmode == NL80211_IFTYPE_ADHOC)
+ rtlpriv->sec.use_defaultkey = true;
+
/* <2> get key_idx */
key_idx = (u8) (key->keyidx);
if (key_idx > 3)
goto out_unlock;
/* <3> if pairwise key enable_hw_sec */
group_key = !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE);
- if ((!group_key) || (mac->opmode == NL80211_IFTYPE_ADHOC) ||
- rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION) {
- if (rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION &&
- (key_type == WEP40_ENCRYPTION ||
- key_type == WEP104_ENCRYPTION))
- wep_only = true;
- rtlpriv->sec.pairwise_enc_algorithm = key_type;
- rtlpriv->cfg->ops->enable_hw_sec(hw);
+
+ /* wep always be group key, but there are two conditions:
+ * 1) wep only: is just for wep enc, in this condition
+ * rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION
+ * will be true & enable_hw_sec will be set when wep
+ * ke setting.
+ * 2) wep(group) + AES(pairwise): some AP like cisco
+ * may use it, in this condition enable_hw_sec will not
+ * be set when wep key setting */
+ /* we must reset sec_info after lingked before set key,
+ * or some flag will be wrong*/
+ if (mac->opmode == NL80211_IFTYPE_AP) {
+ if (!group_key || key_type == WEP40_ENCRYPTION ||
+ key_type == WEP104_ENCRYPTION) {
+ if (group_key)
+ wep_only = true;
+ rtlpriv->cfg->ops->enable_hw_sec(hw);
+ }
+ } else {
+ if ((!group_key) || (mac->opmode == NL80211_IFTYPE_ADHOC) ||
+ rtlpriv->sec.pairwise_enc_algorithm == NO_ENCRYPTION) {
+ if (rtlpriv->sec.pairwise_enc_algorithm ==
+ NO_ENCRYPTION &&
+ (key_type == WEP40_ENCRYPTION ||
+ key_type == WEP104_ENCRYPTION))
+ wep_only = true;
+ rtlpriv->sec.pairwise_enc_algorithm = key_type;
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("set enable_hw_sec, key_type:%x(OPEN:0 WEP40:1"
+ " TKIP:2 AES:4 WEP104:5)\n", key_type));
+ rtlpriv->cfg->ops->enable_hw_sec(hw);
+ }
}
/* <4> set key based on cmd */
switch (cmd) {
@@ -932,6 +1022,7 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
if (!sta) {
RT_ASSERT(false, ("pairwise key withnot"
"mac_addr\n"));
+
err = -EOPNOTSUPP;
goto out_unlock;
}
@@ -959,6 +1050,10 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
("disable key delete one entry\n"));
/*set local buf about wep key. */
+ if (mac->opmode == NL80211_IFTYPE_AP) {
+ if (sta)
+ rtl_cam_del_entry(hw, sta->addr);
+ }
memset(rtlpriv->sec.key_buf[key_idx], 0, key->keylen);
rtlpriv->sec.key_len[key_idx] = 0;
memcpy(mac_addr, zero_addr, ETH_ALEN);
@@ -1011,6 +1106,18 @@ static void rtl_op_rfkill_poll(struct ieee80211_hw *hw)
mutex_unlock(&rtlpriv->locks.conf_mutex);
}
+/* this function is called by mac80211 to flush tx buffer
+ * before switch channle or power save, or tx buffer packet
+ * maybe send after offchannel or rf sleep, this may cause
+ * dis-association by AP */
+static void rtl_op_flush(struct ieee80211_hw *hw, bool drop)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (rtlpriv->intf_ops->flush)
+ rtlpriv->intf_ops->flush(hw, drop);
+}
+
const struct ieee80211_ops rtl_ops = {
.start = rtl_op_start,
.stop = rtl_op_stop,
@@ -1019,6 +1126,8 @@ const struct ieee80211_ops rtl_ops = {
.remove_interface = rtl_op_remove_interface,
.config = rtl_op_config,
.configure_filter = rtl_op_configure_filter,
+ .sta_add = rtl_op_sta_add,
+ .sta_remove = rtl_op_sta_remove,
.set_key = rtl_op_set_key,
.conf_tx = rtl_op_conf_tx,
.bss_info_changed = rtl_op_bss_info_changed,
@@ -1030,4 +1139,5 @@ const struct ieee80211_ops rtl_ops = {
.sw_scan_start = rtl_op_sw_scan_start,
.sw_scan_complete = rtl_op_sw_scan_complete,
.rfkill_poll = rtl_op_rfkill_poll,
+ .flush = rtl_op_flush,
};
diff --git a/drivers/net/wireless/rtlwifi/core.h b/drivers/net/wireless/rtlwifi/core.h
index 0ef31c3c6196..4b247db2861d 100644
--- a/drivers/net/wireless/rtlwifi/core.h
+++ b/drivers/net/wireless/rtlwifi/core.h
@@ -24,6 +24,7 @@
* Hsinchu 300, Taiwan.
*
* Larry Finger <Larry.Finger@lwfinger.net>
+ *
*****************************************************************************/
#ifndef __RTL_CORE_H__
diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c
index 590f14f45a89..50de6f5d8a56 100644
--- a/drivers/net/wireless/rtlwifi/efuse.c
+++ b/drivers/net/wireless/rtlwifi/efuse.c
@@ -52,8 +52,6 @@ static const struct efuse_map RTL8712_SDIO_EFUSE_TABLE[] = {
{11, 0, 0, 28}
};
-static void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset,
- u8 *pbuf);
static void efuse_shadow_read_1byte(struct ieee80211_hw *hw, u16 offset,
u8 *value);
static void efuse_shadow_read_2byte(struct ieee80211_hw *hw, u16 offset,
@@ -79,7 +77,7 @@ static void efuse_word_enable_data_read(u8 word_en, u8 *sourdata,
u8 *targetdata);
static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw,
u16 efuse_addr, u8 word_en, u8 *data);
-static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite,
+static void efuse_power_switch(struct ieee80211_hw *hw, u8 write,
u8 pwrstate);
static u16 efuse_get_current_size(struct ieee80211_hw *hw);
static u8 efuse_calculate_word_cnts(u8 word_en);
@@ -115,8 +113,10 @@ u8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address)
u8 bytetemp;
u8 temp;
u32 k = 0;
+ const u32 efuse_len =
+ rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE];
- if (address < EFUSE_REAL_CONTENT_LEN) {
+ if (address < efuse_len) {
temp = address & 0xFF;
rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1,
temp);
@@ -158,11 +158,13 @@ void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value)
u8 bytetemp;
u8 temp;
u32 k = 0;
+ const u32 efuse_len =
+ rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE];
RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
("Addr=%x Data =%x\n", address, value));
- if (address < EFUSE_REAL_CONTENT_LEN) {
+ if (address < efuse_len) {
rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL], value);
temp = address & 0xFF;
@@ -198,7 +200,7 @@ void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value)
}
-static void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf)
+void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 value32;
@@ -233,26 +235,45 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
- u8 efuse_tbl[EFUSE_MAP_LEN];
+ u8 *efuse_tbl;
u8 rtemp8[1];
u16 efuse_addr = 0;
u8 offset, wren;
u16 i;
u16 j;
- u16 efuse_word[EFUSE_MAX_SECTION][EFUSE_MAX_WORD_UNIT];
+ const u16 efuse_max_section =
+ rtlpriv->cfg->maps[EFUSE_MAX_SECTION_MAP];
+ const u32 efuse_len =
+ rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE];
+ u16 **efuse_word;
u16 efuse_utilized = 0;
u8 efuse_usage;
- if ((_offset + _size_byte) > EFUSE_MAP_LEN) {
+ if ((_offset + _size_byte) > rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]) {
RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
("read_efuse(): Invalid offset(%#x) with read "
"bytes(%#x)!!\n", _offset, _size_byte));
return;
}
- for (i = 0; i < EFUSE_MAX_SECTION; i++)
+ /* allocate memory for efuse_tbl and efuse_word */
+ efuse_tbl = kmalloc(rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE] *
+ sizeof(u8), GFP_ATOMIC);
+ if (!efuse_tbl)
+ return;
+ efuse_word = kmalloc(EFUSE_MAX_WORD_UNIT * sizeof(u16 *), GFP_ATOMIC);
+ if (!efuse_word)
+ goto done;
+ for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
+ efuse_word[i] = kmalloc(efuse_max_section * sizeof(u16),
+ GFP_ATOMIC);
+ if (!efuse_word[i])
+ goto done;
+ }
+
+ for (i = 0; i < efuse_max_section; i++)
for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++)
- efuse_word[i][j] = 0xFFFF;
+ efuse_word[j][i] = 0xFFFF;
read_efuse_byte(hw, efuse_addr, rtemp8);
if (*rtemp8 != 0xFF) {
@@ -262,10 +283,10 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
efuse_addr++;
}
- while ((*rtemp8 != 0xFF) && (efuse_addr < EFUSE_REAL_CONTENT_LEN)) {
+ while ((*rtemp8 != 0xFF) && (efuse_addr < efuse_len)) {
offset = ((*rtemp8 >> 4) & 0x0f);
- if (offset < EFUSE_MAX_SECTION) {
+ if (offset < efuse_max_section) {
wren = (*rtemp8 & 0x0f);
RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL,
("offset-%d Worden=%x\n", offset, wren));
@@ -279,9 +300,10 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
read_efuse_byte(hw, efuse_addr, rtemp8);
efuse_addr++;
efuse_utilized++;
- efuse_word[offset][i] = (*rtemp8 & 0xff);
+ efuse_word[i][offset] =
+ (*rtemp8 & 0xff);
- if (efuse_addr >= EFUSE_REAL_CONTENT_LEN)
+ if (efuse_addr >= efuse_len)
break;
RTPRINT(rtlpriv, FEEPROM,
@@ -291,10 +313,10 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
read_efuse_byte(hw, efuse_addr, rtemp8);
efuse_addr++;
efuse_utilized++;
- efuse_word[offset][i] |=
+ efuse_word[i][offset] |=
(((u16)*rtemp8 << 8) & 0xff00);
- if (efuse_addr >= EFUSE_REAL_CONTENT_LEN)
+ if (efuse_addr >= efuse_len)
break;
}
@@ -305,18 +327,18 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
RTPRINT(rtlpriv, FEEPROM, EFUSE_READ_ALL,
("Addr=%d\n", efuse_addr));
read_efuse_byte(hw, efuse_addr, rtemp8);
- if (*rtemp8 != 0xFF && (efuse_addr < 512)) {
+ if (*rtemp8 != 0xFF && (efuse_addr < efuse_len)) {
efuse_utilized++;
efuse_addr++;
}
}
- for (i = 0; i < EFUSE_MAX_SECTION; i++) {
+ for (i = 0; i < efuse_max_section; i++) {
for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) {
efuse_tbl[(i * 8) + (j * 2)] =
- (efuse_word[i][j] & 0xff);
+ (efuse_word[j][i] & 0xff);
efuse_tbl[(i * 8) + ((j * 2) + 1)] =
- ((efuse_word[i][j] >> 8) & 0xff);
+ ((efuse_word[j][i] >> 8) & 0xff);
}
}
@@ -324,12 +346,17 @@ void read_efuse(struct ieee80211_hw *hw, u16 _offset, u16 _size_byte, u8 *pbuf)
pbuf[i] = efuse_tbl[_offset + i];
rtlefuse->efuse_usedbytes = efuse_utilized;
- efuse_usage = (u8)((efuse_utilized * 100) / EFUSE_REAL_CONTENT_LEN);
+ efuse_usage = (u8) ((efuse_utilized * 100) / efuse_len);
rtlefuse->efuse_usedpercentage = efuse_usage;
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_BYTES,
(u8 *)&efuse_utilized);
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_USAGE,
(u8 *)&efuse_usage);
+done:
+ for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++)
+ kfree(efuse_word[i]);
+ kfree(efuse_word);
+ kfree(efuse_tbl);
}
bool efuse_shadow_update_chk(struct ieee80211_hw *hw)
@@ -338,11 +365,11 @@ bool efuse_shadow_update_chk(struct ieee80211_hw *hw)
struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
u8 section_idx, i, Base;
u16 words_need = 0, hdr_num = 0, totalbytes, efuse_used;
- bool bwordchanged, bresult = true;
+ bool wordchanged, result = true;
for (section_idx = 0; section_idx < 16; section_idx++) {
Base = section_idx * 8;
- bwordchanged = false;
+ wordchanged = false;
for (i = 0; i < 8; i = i + 2) {
if ((rtlefuse->efuse_map[EFUSE_INIT_MAP][Base + i] !=
@@ -351,11 +378,11 @@ bool efuse_shadow_update_chk(struct ieee80211_hw *hw)
rtlefuse->efuse_map[EFUSE_MODIFY_MAP][Base + i +
1])) {
words_need++;
- bwordchanged = true;
+ wordchanged = true;
}
}
- if (bwordchanged == true)
+ if (wordchanged == true)
hdr_num++;
}
@@ -364,14 +391,14 @@ bool efuse_shadow_update_chk(struct ieee80211_hw *hw)
if ((totalbytes + efuse_used) >=
(EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES))
- bresult = false;
+ result = false;
RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
("efuse_shadow_update_chk(): totalbytes(%#x), "
"hdr_num(%#x), words_need(%#x), efuse_used(%d)\n",
totalbytes, hdr_num, words_need, efuse_used));
- return bresult;
+ return result;
}
void efuse_shadow_read(struct ieee80211_hw *hw, u8 type,
@@ -394,7 +421,7 @@ void efuse_shadow_write(struct ieee80211_hw *hw, u8 type, u16 offset,
else if (type == 2)
efuse_shadow_write_2byte(hw, offset, (u16) value);
else if (type == 4)
- efuse_shadow_write_4byte(hw, offset, (u32) value);
+ efuse_shadow_write_4byte(hw, offset, value);
}
@@ -478,9 +505,10 @@ void rtl_efuse_shadow_map_update(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
- if (rtlefuse->autoload_failflag == true) {
- memset(&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], 0xFF, 128);
- } else
+ if (rtlefuse->autoload_failflag == true)
+ memset(&rtlefuse->efuse_map[EFUSE_INIT_MAP][0], 0xFF,
+ rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]);
+ else
efuse_read_all_map(hw, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0]);
memcpy(&rtlefuse->efuse_map[EFUSE_MODIFY_MAP][0],
@@ -572,7 +600,7 @@ static int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u8 tmpidx = 0;
- int bresult;
+ int result;
rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL] + 1,
(u8) (addr & 0xff));
@@ -592,19 +620,18 @@ static int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data)
if (tmpidx < 100) {
*data = rtl_read_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CTRL]);
- bresult = true;
+ result = true;
} else {
*data = 0xff;
- bresult = false;
+ result = false;
}
- return bresult;
+ return result;
}
static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u8 tmpidx = 0;
- bool bresult;
RT_TRACE(rtlpriv, COMP_EFUSE, DBG_LOUD,
("Addr = %x Data=%x\n", addr, data));
@@ -626,17 +653,16 @@ static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data)
}
if (tmpidx < 100)
- bresult = true;
- else
- bresult = false;
+ return true;
- return bresult;
+ return false;
}
static void efuse_read_all_map(struct ieee80211_hw *hw, u8 * efuse)
{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
efuse_power_switch(hw, false, true);
- read_efuse(hw, 0, 128, efuse);
+ read_efuse(hw, 0, rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE], efuse);
efuse_power_switch(hw, false, false);
}
@@ -644,7 +670,7 @@ static void efuse_read_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
u8 efuse_data, u8 offset, u8 *tmpdata,
u8 *readstate)
{
- bool bdataempty = true;
+ bool dataempty = true;
u8 hoffset;
u8 tmpidx;
u8 hworden;
@@ -660,13 +686,13 @@ static void efuse_read_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
&efuse_data)) {
tmpdata[tmpidx] = efuse_data;
if (efuse_data != 0xff)
- bdataempty = true;
+ dataempty = true;
}
}
- if (bdataempty == true)
+ if (dataempty == true) {
*readstate = PG_STATE_DATA;
- else {
+ } else {
*efuse_addr = *efuse_addr + (word_cnts * 2) + 1;
*readstate = PG_STATE_HEADER;
}
@@ -680,12 +706,9 @@ static void efuse_read_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data)
{
u8 readstate = PG_STATE_HEADER;
-
- bool bcontinual = true;
-
+ bool continual = true;
u8 efuse_data, word_cnts = 0;
u16 efuse_addr = 0;
- u8 hworden = 0;
u8 tmpdata[8];
if (data == NULL)
@@ -696,7 +719,7 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data)
memset(data, 0xff, PGPKT_DATA_SIZE * sizeof(u8));
memset(tmpdata, 0xff, PGPKT_DATA_SIZE * sizeof(u8));
- while (bcontinual && (efuse_addr < EFUSE_MAX_SIZE)) {
+ while (continual && (efuse_addr < EFUSE_MAX_SIZE)) {
if (readstate & PG_STATE_HEADER) {
if (efuse_one_byte_read(hw, efuse_addr, &efuse_data)
&& (efuse_data != 0xFF))
@@ -705,9 +728,9 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data)
offset, tmpdata,
&readstate);
else
- bcontinual = false;
+ continual = false;
} else if (readstate & PG_STATE_DATA) {
- efuse_word_enable_data_read(hworden, tmpdata, data);
+ efuse_word_enable_data_read(0, tmpdata, data);
efuse_addr = efuse_addr + (word_cnts * 2) + 1;
readstate = PG_STATE_HEADER;
}
@@ -725,13 +748,13 @@ static int efuse_pg_packet_read(struct ieee80211_hw *hw, u8 offset, u8 *data)
}
static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
- u8 efuse_data, u8 offset, int *bcontinual,
+ u8 efuse_data, u8 offset, int *continual,
u8 *write_state, struct pgpkt_struct *target_pkt,
- int *repeat_times, int *bresult, u8 word_en)
+ int *repeat_times, int *result, u8 word_en)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct pgpkt_struct tmp_pkt;
- int bdataempty = true;
+ bool dataempty = true;
u8 originaldata[8 * sizeof(u8)];
u8 badworden = 0x0F;
u8 match_word_en, tmp_word_en;
@@ -751,10 +774,10 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
u16 address = *efuse_addr + 1 + tmpindex;
if (efuse_one_byte_read(hw, address,
&efuse_data) && (efuse_data != 0xFF))
- bdataempty = false;
+ dataempty = false;
}
- if (bdataempty == false) {
+ if (dataempty == false) {
*efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1;
*write_state = PG_STATE_HEADER;
} else {
@@ -799,24 +822,25 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
tmp_word_en &= (~BIT(1));
if ((target_pkt->word_en & BIT(2)) ^
- (match_word_en & BIT(2)))
+ (match_word_en & BIT(2)))
tmp_word_en &= (~BIT(2));
if ((target_pkt->word_en & BIT(3)) ^
- (match_word_en & BIT(3)))
+ (match_word_en & BIT(3)))
tmp_word_en &= (~BIT(3));
if ((tmp_word_en & 0x0F) != 0x0F) {
*efuse_addr = efuse_get_current_size(hw);
target_pkt->offset = offset;
target_pkt->word_en = tmp_word_en;
- } else
- *bcontinual = false;
+ } else {
+ *continual = false;
+ }
*write_state = PG_STATE_HEADER;
*repeat_times += 1;
if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) {
- *bcontinual = false;
- *bresult = false;
+ *continual = false;
+ *result = false;
}
} else {
*efuse_addr += (2 * tmp_word_cnts) + 1;
@@ -830,9 +854,9 @@ static void efuse_write_data_case1(struct ieee80211_hw *hw, u16 *efuse_addr,
}
static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr,
- int *bcontinual, u8 *write_state,
+ int *continual, u8 *write_state,
struct pgpkt_struct target_pkt,
- int *repeat_times, int *bresult)
+ int *repeat_times, int *result)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct pgpkt_struct tmp_pkt;
@@ -846,14 +870,14 @@ static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr,
efuse_one_byte_write(hw, *efuse_addr, pg_header);
efuse_one_byte_read(hw, *efuse_addr, &tmp_header);
- if (tmp_header == pg_header)
+ if (tmp_header == pg_header) {
*write_state = PG_STATE_DATA;
- else if (tmp_header == 0xFF) {
+ } else if (tmp_header == 0xFF) {
*write_state = PG_STATE_HEADER;
*repeat_times += 1;
if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) {
- *bcontinual = false;
- *bresult = false;
+ *continual = false;
+ *result = false;
}
} else {
tmp_pkt.offset = (tmp_header >> 4) & 0x0F;
@@ -875,17 +899,19 @@ static void efuse_write_data_case2(struct ieee80211_hw *hw, u16 *efuse_addr,
reorg_worden,
originaldata);
*efuse_addr = efuse_get_current_size(hw);
- } else
+ } else {
*efuse_addr = *efuse_addr + (tmp_word_cnts * 2)
+ 1;
- } else
+ }
+ } else {
*efuse_addr = *efuse_addr + (tmp_word_cnts * 2) + 1;
+ }
*write_state = PG_STATE_HEADER;
*repeat_times += 1;
if (*repeat_times > EFUSE_REPEAT_THRESHOLD_) {
- *bcontinual = false;
- *bresult = false;
+ *continual = false;
+ *result = false;
}
RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
@@ -899,7 +925,7 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw,
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct pgpkt_struct target_pkt;
u8 write_state = PG_STATE_HEADER;
- int bcontinual = true, bdataempty = true, bresult = true;
+ int continual = true, dataempty = true, result = true;
u16 efuse_addr = 0;
u8 efuse_data;
u8 target_word_cnts = 0;
@@ -923,11 +949,11 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw,
RTPRINT(rtlpriv, FEEPROM, EFUSE_PG, ("efuse Power ON\n"));
- while (bcontinual && (efuse_addr <
+ while (continual && (efuse_addr <
(EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES))) {
if (write_state == PG_STATE_HEADER) {
- bdataempty = true;
+ dataempty = true;
badworden = 0x0F;
RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
("efuse PG_STATE_HEADER\n"));
@@ -936,32 +962,30 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw,
(efuse_data != 0xFF))
efuse_write_data_case1(hw, &efuse_addr,
efuse_data, offset,
- &bcontinual,
+ &continual,
&write_state, &target_pkt,
- &repeat_times, &bresult,
+ &repeat_times, &result,
word_en);
else
efuse_write_data_case2(hw, &efuse_addr,
- &bcontinual,
+ &continual,
&write_state,
target_pkt,
&repeat_times,
- &bresult);
+ &result);
} else if (write_state == PG_STATE_DATA) {
RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
("efuse PG_STATE_DATA\n"));
- badworden = 0x0f;
badworden =
efuse_word_enable_data_write(hw, efuse_addr + 1,
target_pkt.word_en,
target_pkt.data);
if ((badworden & 0x0F) == 0x0F) {
- bcontinual = false;
+ continual = false;
} else {
- efuse_addr =
- efuse_addr + (2 * target_word_cnts) + 1;
+ efuse_addr += (2 * target_word_cnts) + 1;
target_pkt.offset = offset;
target_pkt.word_en = badworden;
@@ -971,8 +995,8 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw,
write_state = PG_STATE_HEADER;
repeat_times++;
if (repeat_times > EFUSE_REPEAT_THRESHOLD_) {
- bcontinual = false;
- bresult = false;
+ continual = false;
+ result = false;
}
RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
("efuse PG_STATE_HEADER-3\n"));
@@ -1072,13 +1096,15 @@ static u8 efuse_word_enable_data_write(struct ieee80211_hw *hw,
return badworden;
}
-static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate)
+static void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
u8 tempval;
u16 tmpV16;
- if (pwrstate == true) {
+ if (pwrstate && (rtlhal->hw_type !=
+ HARDWARE_TYPE_RTL8192SE)) {
tmpV16 = rtl_read_word(rtlpriv,
rtlpriv->cfg->maps[SYS_ISO_CTRL]);
if (!(tmpV16 & rtlpriv->cfg->maps[EFUSE_PWC_EV12V])) {
@@ -1106,20 +1132,29 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate)
}
}
- if (pwrstate == true) {
- if (bwrite == true) {
+ if (pwrstate) {
+ if (write) {
tempval = rtl_read_byte(rtlpriv,
rtlpriv->cfg->maps[EFUSE_TEST] +
3);
- tempval &= 0x0F;
- tempval |= (VOLTAGE_V25 << 4);
+
+ if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE) {
+ tempval &= 0x0F;
+ tempval |= (VOLTAGE_V25 << 4);
+ }
+
rtl_write_byte(rtlpriv,
rtlpriv->cfg->maps[EFUSE_TEST] + 3,
(tempval | 0x80));
}
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) {
+ rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK],
+ 0x03);
+ }
+
} else {
- if (bwrite == true) {
+ if (write) {
tempval = rtl_read_byte(rtlpriv,
rtlpriv->cfg->maps[EFUSE_TEST] +
3);
@@ -1128,18 +1163,23 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate)
(tempval & 0x7F));
}
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) {
+ rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_CLK],
+ 0x02);
+ }
+
}
}
static u16 efuse_get_current_size(struct ieee80211_hw *hw)
{
- int bcontinual = true;
+ int continual = true;
u16 efuse_addr = 0;
u8 hoffset, hworden;
u8 efuse_data, word_cnts;
- while (bcontinual && efuse_one_byte_read(hw, efuse_addr, &efuse_data)
+ while (continual && efuse_one_byte_read(hw, efuse_addr, &efuse_data)
&& (efuse_addr < EFUSE_MAX_SIZE)) {
if (efuse_data != 0xFF) {
hoffset = (efuse_data >> 4) & 0x0F;
@@ -1147,7 +1187,7 @@ static u16 efuse_get_current_size(struct ieee80211_hw *hw)
word_cnts = efuse_calculate_word_cnts(hworden);
efuse_addr = efuse_addr + (word_cnts * 2) + 1;
} else {
- bcontinual = false;
+ continual = false;
}
}
diff --git a/drivers/net/wireless/rtlwifi/efuse.h b/drivers/net/wireless/rtlwifi/efuse.h
index 47774dd4c2a6..164dabaa7615 100644
--- a/drivers/net/wireless/rtlwifi/efuse.h
+++ b/drivers/net/wireless/rtlwifi/efuse.h
@@ -30,9 +30,10 @@
#ifndef __RTL_EFUSE_H_
#define __RTL_EFUSE_H_
+#define EFUSE_IC_ID_OFFSET 506
+
#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
@@ -52,6 +53,7 @@
#define _PRE_EXECUTE_READ_CMD_
#define EFUSE_REPEAT_THRESHOLD_ 3
+#define EFUSE_ERROE_HANDLE 1
struct efuse_map {
u8 offset;
@@ -103,6 +105,7 @@ struct efuse_priv {
u8 tx_power_g[14];
};
+extern void read_efuse_byte(struct ieee80211_hw *hw, u16 _offset, u8 *pbuf);
extern void efuse_initialize(struct ieee80211_hw *hw);
extern u8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address);
extern void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value);
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
index 5938f6ee21e4..a40952845436 100644
--- a/drivers/net/wireless/rtlwifi/pci.c
+++ b/drivers/net/wireless/rtlwifi/pci.c
@@ -32,6 +32,7 @@
#include "pci.h"
#include "base.h"
#include "ps.h"
+#include "efuse.h"
static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = {
INTEL_VENDOR_ID,
@@ -40,6 +41,31 @@ static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = {
SIS_VENDOR_ID
};
+static const u8 ac_to_hwq[] = {
+ VO_QUEUE,
+ VI_QUEUE,
+ BE_QUEUE,
+ BK_QUEUE
+};
+
+static u8 _rtl_mac_to_hwqueue(struct ieee80211_hw *hw,
+ struct sk_buff *skb)
+{
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ __le16 fc = rtl_get_fc(skb);
+ u8 queue_index = skb_get_queue_mapping(skb);
+
+ if (unlikely(ieee80211_is_beacon(fc)))
+ return BEACON_QUEUE;
+ if (ieee80211_is_mgmt(fc))
+ return MGNT_QUEUE;
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE)
+ if (ieee80211_is_nullfunc(fc))
+ return HIGH_QUEUE;
+
+ return ac_to_hwq[queue_index];
+}
+
/* Update PCI dependent default settings*/
static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw)
{
@@ -48,6 +74,7 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw)
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
+ u8 init_aspm;
ppsc->reg_rfps_level = 0;
ppsc->support_aspm = 0;
@@ -125,7 +152,7 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw)
bool support_backdoor = true;
ppsc->support_aspm = support_aspm;
- /*if(priv->oem_id == RT_CID_TOSHIBA &&
+ /*if (priv->oem_id == RT_CID_TOSHIBA &&
!priv->ndis_adapter.amd_l1_patch)
support_backdoor = false; */
@@ -145,6 +172,13 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw)
("switch case not process\n"));
break;
}
+
+ /* toshiba aspm issue, toshiba will set aspm selfly
+ * so we should not set aspm in driver */
+ pci_read_config_byte(rtlpci->pdev, 0x80, &init_aspm);
+ if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8192SE &&
+ init_aspm == 0x43)
+ ppsc->support_aspm = false;
}
static bool _rtl_pci_platform_switch_device_pci_aspm(
@@ -152,28 +186,28 @@ static bool _rtl_pci_platform_switch_device_pci_aspm(
u8 value)
{
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- bool bresult = false;
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
- value |= 0x40;
+ if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE)
+ value |= 0x40;
pci_write_config_byte(rtlpci->pdev, 0x80, value);
- return bresult;
+ return false;
}
/*When we set 0x01 to enable clk request. Set 0x0 to disable clk req.*/
static bool _rtl_pci_switch_clk_req(struct ieee80211_hw *hw, u8 value)
{
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- u8 buffer;
- bool bresult = false;
-
- buffer = value;
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
pci_write_config_byte(rtlpci->pdev, 0x81, value);
- bresult = true;
- return bresult;
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE)
+ udelay(100);
+
+ return true;
}
/*Disable RTL8192SE ASPM & Disable Pci Bridge ASPM*/
@@ -191,6 +225,10 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw)
u16 pcibridge_linkctrlreg = pcipriv->ndis_adapter.
pcibridge_linkctrlreg;
u16 aspmlevel = 0;
+ u8 tmp_u1b = 0;
+
+ if (!ppsc->support_aspm)
+ return;
if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) {
RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
@@ -204,11 +242,8 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw)
_rtl_pci_switch_clk_req(hw, 0x0);
}
- if (1) {
- /*for promising device will in L0 state after an I/O. */
- u8 tmp_u1b;
- pci_read_config_byte(rtlpci->pdev, 0x80, &tmp_u1b);
- }
+ /*for promising device will in L0 state after an I/O. */
+ pci_read_config_byte(rtlpci->pdev, 0x80, &tmp_u1b);
/*Set corresponding value. */
aspmlevel |= BIT(0) | BIT(1);
@@ -224,7 +259,6 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw)
rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, pcibridge_linkctrlreg);
udelay(50);
-
}
/*
@@ -249,6 +283,9 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
u8 u_pcibridge_aspmsetting;
u8 u_device_aspmsetting;
+ if (!ppsc->support_aspm)
+ return;
+
if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) {
RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
("PCI(Bridge) UNKNOWN.\n"));
@@ -293,7 +330,7 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
RT_RF_OFF_LEVL_CLK_REQ) ? 1 : 0);
RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_CLK_REQ);
}
- udelay(200);
+ udelay(100);
}
static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw)
@@ -330,13 +367,13 @@ static void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw)
u8 capabilityoffset = pcipriv->ndis_adapter.pcibridge_pciehdr_offset;
u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport;
u8 linkctrl_reg;
- u8 num4bBytes;
+ u8 num4bbytes;
- num4bBytes = (capabilityoffset + 0x10) / 4;
+ num4bbytes = (capabilityoffset + 0x10) / 4;
/*Read Link Control Register */
rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
- pcicfg_addrport + (num4bBytes << 2));
+ pcicfg_addrport + (num4bbytes << 2));
rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &linkctrl_reg);
pcipriv->ndis_adapter.pcibridge_linkctrlreg = linkctrl_reg;
@@ -369,7 +406,7 @@ static void rtl_pci_parse_configuration(struct pci_dev *pdev,
pci_write_config_byte(pdev, 0x70f, tmp);
}
-static void _rtl_pci_initialize_adapter_common(struct ieee80211_hw *hw)
+static void rtl_pci_init_aspm(struct ieee80211_hw *hw)
{
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
@@ -383,52 +420,6 @@ static void _rtl_pci_initialize_adapter_common(struct ieee80211_hw *hw)
}
-static void rtl_pci_init_aspm(struct ieee80211_hw *hw)
-{
- struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-
- /*close ASPM for AMD defaultly */
- rtlpci->const_amdpci_aspm = 0;
-
- /*
- * ASPM PS mode.
- * 0 - Disable ASPM,
- * 1 - Enable ASPM without Clock Req,
- * 2 - Enable ASPM with Clock Req,
- * 3 - Always Enable ASPM with Clock Req,
- * 4 - Always Enable ASPM without Clock Req.
- * set defult to RTL8192CE:3 RTL8192E:2
- * */
- rtlpci->const_pci_aspm = 3;
-
- /*Setting for PCI-E device */
- rtlpci->const_devicepci_aspm_setting = 0x03;
-
- /*Setting for PCI-E bridge */
- rtlpci->const_hostpci_aspm_setting = 0x02;
-
- /*
- * In Hw/Sw Radio Off situation.
- * 0 - Default,
- * 1 - From ASPM setting without low Mac Pwr,
- * 2 - From ASPM setting with low Mac Pwr,
- * 3 - Bus D3
- * set default to RTL8192CE:0 RTL8192SE:2
- */
- rtlpci->const_hwsw_rfoff_d3 = 0;
-
- /*
- * This setting works for those device with
- * backdoor ASPM setting such as EPHY setting.
- * 0 - Not support ASPM,
- * 1 - Support ASPM,
- * 2 - According to chipset.
- */
- rtlpci->const_support_pciaspm = 1;
-
- _rtl_pci_initialize_adapter_common(hw);
-}
-
static void _rtl_pci_io_handler_init(struct device *dev,
struct ieee80211_hw *hw)
{
@@ -450,6 +441,90 @@ static void _rtl_pci_io_handler_release(struct ieee80211_hw *hw)
{
}
+static bool _rtl_update_earlymode_info(struct ieee80211_hw *hw,
+ struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc, u8 tid)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ u8 additionlen = FCS_LEN;
+ struct sk_buff *next_skb;
+
+ /* here open is 4, wep/tkip is 8, aes is 12*/
+ if (info->control.hw_key)
+ additionlen += info->control.hw_key->icv_len;
+
+ /* The most skb num is 6 */
+ tcb_desc->empkt_num = 0;
+ spin_lock_bh(&rtlpriv->locks.waitq_lock);
+ skb_queue_walk(&rtlpriv->mac80211.skb_waitq[tid], next_skb) {
+ struct ieee80211_tx_info *next_info;
+
+ next_info = IEEE80211_SKB_CB(next_skb);
+ if (next_info->flags & IEEE80211_TX_CTL_AMPDU) {
+ tcb_desc->empkt_len[tcb_desc->empkt_num] =
+ next_skb->len + additionlen;
+ tcb_desc->empkt_num++;
+ } else {
+ break;
+ }
+
+ if (skb_queue_is_last(&rtlpriv->mac80211.skb_waitq[tid],
+ next_skb))
+ break;
+
+ if (tcb_desc->empkt_num >= 5)
+ break;
+ }
+ spin_unlock_bh(&rtlpriv->locks.waitq_lock);
+
+ return true;
+}
+
+/* just for early mode now */
+static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct sk_buff *skb = NULL;
+ struct ieee80211_tx_info *info = NULL;
+ int tid; /* should be int */
+
+ if (!rtlpriv->rtlhal.earlymode_enable)
+ return;
+
+ /* we juse use em for BE/BK/VI/VO */
+ for (tid = 7; tid >= 0; tid--) {
+ u8 hw_queue = ac_to_hwq[rtl_tid_to_ac(hw, tid)];
+ struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue];
+ while (!mac->act_scanning &&
+ rtlpriv->psc.rfpwr_state == ERFON) {
+ struct rtl_tcb_desc tcb_desc;
+ memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
+
+ spin_lock_bh(&rtlpriv->locks.waitq_lock);
+ if (!skb_queue_empty(&mac->skb_waitq[tid]) &&
+ (ring->entries - skb_queue_len(&ring->queue) > 5)) {
+ skb = skb_dequeue(&mac->skb_waitq[tid]);
+ } else {
+ spin_unlock_bh(&rtlpriv->locks.waitq_lock);
+ break;
+ }
+ spin_unlock_bh(&rtlpriv->locks.waitq_lock);
+
+ /* Some macaddr can't do early mode. like
+ * multicast/broadcast/no_qos data */
+ info = IEEE80211_SKB_CB(skb);
+ if (info->flags & IEEE80211_TX_CTL_AMPDU)
+ _rtl_update_earlymode_info(hw, skb,
+ &tcb_desc, tid);
+
+ rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc);
+ }
+ }
+}
+
+
static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -461,6 +536,8 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
struct rtl_tx_desc *entry = &ring->desc[ring->idx];
struct sk_buff *skb;
struct ieee80211_tx_info *info;
+ __le16 fc;
+ u8 tid;
u8 own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) entry, true,
HW_DESC_OWN);
@@ -481,6 +558,10 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
HW_DESC_TXBUFF_ADDR),
skb->len, PCI_DMA_TODEVICE);
+ /* remove early mode header */
+ if (rtlpriv->rtlhal.earlymode_enable)
+ skb_pull(skb, EM_HDR_LEN);
+
RT_TRACE(rtlpriv, (COMP_INTR | COMP_SEND), DBG_TRACE,
("new ring->idx:%d, "
"free: skb_queue_len:%d, free: seq:%x\n",
@@ -488,6 +569,30 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
skb_queue_len(&ring->queue),
*(u16 *) (skb->data + 22)));
+ if (prio == TXCMD_QUEUE) {
+ dev_kfree_skb(skb);
+ goto tx_status_ok;
+
+ }
+
+ /* for sw LPS, just after NULL skb send out, we can
+ * sure AP kown we are sleeped, our we should not let
+ * rf to sleep*/
+ fc = rtl_get_fc(skb);
+ if (ieee80211_is_nullfunc(fc)) {
+ if (ieee80211_has_pm(fc)) {
+ rtlpriv->mac80211.offchan_deley = true;
+ rtlpriv->psc.state_inap = 1;
+ } else {
+ rtlpriv->psc.state_inap = 0;
+ }
+ }
+
+ /* update tid tx pkt num */
+ tid = rtl_get_tid(skb);
+ if (tid <= 7)
+ rtlpriv->link_info.tidtx_inperiod[tid]++;
+
info = IEEE80211_SKB_CB(skb);
ieee80211_tx_info_clear_status(info);
@@ -510,7 +615,7 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
skb_get_queue_mapping
(skb));
}
-
+tx_status_ok:
skb = NULL;
}
@@ -582,23 +687,21 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
*skb_trim(skb, skb->len - 4);
*/
- hdr = (struct ieee80211_hdr *)(skb->data);
- fc = hdr->frame_control;
+ hdr = rtl_get_hdr(skb);
+ fc = rtl_get_fc(skb);
- if (!stats.crc) {
+ if (!stats.crc || !stats.hwerror) {
memcpy(IEEE80211_SKB_RXCB(skb), &rx_status,
sizeof(rx_status));
- if (is_broadcast_ether_addr(hdr->addr1))
+ if (is_broadcast_ether_addr(hdr->addr1)) {
;/*TODO*/
- else {
- if (is_multicast_ether_addr(hdr->addr1))
- ;/*TODO*/
- else {
- unicast = true;
- rtlpriv->stats.rxbytesunicast +=
- skb->len;
- }
+ } else if (is_multicast_ether_addr(hdr->addr1)) {
+ ;/*TODO*/
+ } else {
+ unicast = true;
+ rtlpriv->stats.rxbytesunicast +=
+ skb->len;
}
rtl_is_special_data(hw, skb, false);
@@ -612,28 +715,38 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
num_rx_inperiod++;
}
- if (unlikely(!rtl_action_proc(hw, skb,
- false))) {
+ /* for sw lps */
+ rtl_swlps_beacon(hw, (void *)skb->data,
+ skb->len);
+ rtl_recognize_peer(hw, (void *)skb->data,
+ skb->len);
+ if ((rtlpriv->mac80211.opmode ==
+ NL80211_IFTYPE_AP) &&
+ (rtlpriv->rtlhal.current_bandtype ==
+ BAND_ON_2_4G) &&
+ (ieee80211_is_beacon(fc) ||
+ ieee80211_is_probe_resp(fc))) {
dev_kfree_skb_any(skb);
} else {
- struct sk_buff *uskb = NULL;
- u8 *pdata;
- uskb = dev_alloc_skb(skb->len + 128);
- if (!uskb) {
- RT_TRACE(rtlpriv,
- (COMP_INTR | COMP_RECV),
- DBG_EMERG,
- ("can't alloc rx skb\n"));
- goto done;
+ if (unlikely(!rtl_action_proc(hw, skb,
+ false))) {
+ dev_kfree_skb_any(skb);
+ } else {
+ struct sk_buff *uskb = NULL;
+ u8 *pdata;
+ uskb = dev_alloc_skb(skb->len
+ + 128);
+ memcpy(IEEE80211_SKB_RXCB(uskb),
+ &rx_status,
+ sizeof(rx_status));
+ pdata = (u8 *)skb_put(uskb,
+ skb->len);
+ memcpy(pdata, skb->data,
+ skb->len);
+ dev_kfree_skb_any(skb);
+
+ ieee80211_rx_irqsafe(hw, uskb);
}
- memcpy(IEEE80211_SKB_RXCB(uskb),
- &rx_status,
- sizeof(rx_status));
- pdata = (u8 *)skb_put(uskb, skb->len);
- memcpy(pdata, skb->data, skb->len);
- dev_kfree_skb_any(skb);
-
- ieee80211_rx_irqsafe(hw, uskb);
}
} else {
dev_kfree_skb_any(skb);
@@ -648,7 +761,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
if (unlikely(!new_skb)) {
RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV),
- DBG_EMERG,
+ DBG_DMESG,
("can't alloc skb for rx\n"));
goto done;
}
@@ -666,7 +779,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
}
done:
- bufferaddress = (u32)(*((dma_addr_t *) skb->cb));
+ bufferaddress = (*((dma_addr_t *)skb->cb));
tmp_one = 1;
rtlpriv->cfg->ops->set_desc((u8 *) pdesc, false,
HW_DESC_RXBUFF_ADDR,
@@ -695,6 +808,7 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
struct ieee80211_hw *hw = dev_id;
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
unsigned long flags;
u32 inta = 0;
u32 intb = 0;
@@ -781,23 +895,36 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
_rtl_pci_tx_isr(hw, VO_QUEUE);
}
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) {
+ if (inta & rtlpriv->cfg->maps[RTL_IMR_COMDOK]) {
+ rtlpriv->link_info.num_tx_inperiod++;
+
+ RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
+ ("CMD TX OK interrupt!\n"));
+ _rtl_pci_tx_isr(hw, TXCMD_QUEUE);
+ }
+ }
+
/*<2> Rx related */
if (inta & rtlpriv->cfg->maps[RTL_IMR_ROK]) {
RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, ("Rx ok interrupt!\n"));
- tasklet_schedule(&rtlpriv->works.irq_tasklet);
+ _rtl_pci_rx_interrupt(hw);
}
if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RDU])) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
("rx descriptor unavailable!\n"));
- tasklet_schedule(&rtlpriv->works.irq_tasklet);
+ _rtl_pci_rx_interrupt(hw);
}
if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RXFOVW])) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("rx overflow !\n"));
- tasklet_schedule(&rtlpriv->works.irq_tasklet);
+ _rtl_pci_rx_interrupt(hw);
}
+ if (rtlpriv->rtlhal.earlymode_enable)
+ tasklet_schedule(&rtlpriv->works.irq_tasklet);
+
spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
return IRQ_HANDLED;
@@ -808,7 +935,7 @@ done:
static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw)
{
- _rtl_pci_rx_interrupt(hw);
+ _rtl_pci_tx_chk_waitq(hw);
}
static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
@@ -816,14 +943,15 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
- struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE];
+ struct rtl8192_tx_ring *ring = NULL;
struct ieee80211_hdr *hdr = NULL;
struct ieee80211_tx_info *info = NULL;
struct sk_buff *pskb = NULL;
struct rtl_tx_desc *pdesc = NULL;
- unsigned int queue_index;
+ struct rtl_tcb_desc tcb_desc;
u8 temp_one = 1;
+ memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
ring = &rtlpci->tx_ring[BEACON_QUEUE];
pskb = __skb_dequeue(&ring->queue);
if (pskb)
@@ -833,14 +961,11 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
pskb = ieee80211_beacon_get(hw, mac->vif);
if (pskb == NULL)
return;
- hdr = (struct ieee80211_hdr *)(pskb->data);
+ hdr = rtl_get_hdr(pskb);
info = IEEE80211_SKB_CB(pskb);
-
- queue_index = BEACON_QUEUE;
-
pdesc = &ring->desc[0];
rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc,
- info, pskb, queue_index);
+ info, pskb, BEACON_QUEUE, &tcb_desc);
__skb_queue_tail(&ring->queue, pskb);
@@ -882,7 +1007,6 @@ static void _rtl_pci_init_struct(struct ieee80211_hw *hw,
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
- struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
rtlpci->up_first_time = true;
rtlpci->being_init_adapter = false;
@@ -890,31 +1014,20 @@ static void _rtl_pci_init_struct(struct ieee80211_hw *hw,
rtlhal->hw = hw;
rtlpci->pdev = pdev;
- ppsc->inactiveps = false;
- ppsc->leisure_ps = true;
- ppsc->fwctrl_lps = true;
- ppsc->reg_fwctrl_lps = 3;
- ppsc->reg_max_lps_awakeintvl = 5;
-
- if (ppsc->reg_fwctrl_lps == 1)
- ppsc->fwctrl_psmode = FW_PS_MIN_MODE;
- else if (ppsc->reg_fwctrl_lps == 2)
- ppsc->fwctrl_psmode = FW_PS_MAX_MODE;
- else if (ppsc->reg_fwctrl_lps == 3)
- ppsc->fwctrl_psmode = FW_PS_DTIM_MODE;
-
/*Tx/Rx related var */
_rtl_pci_init_trx_var(hw);
- /*IBSS*/ mac->beacon_interval = 100;
+ /*IBSS*/ mac->beacon_interval = 100;
- /*AMPDU*/ mac->min_space_cfg = 0;
+ /*AMPDU*/
+ mac->min_space_cfg = 0;
mac->max_mss_density = 0;
/*set sane AMPDU defaults */
mac->current_ampdu_density = 7;
mac->current_ampdu_factor = 3;
- /*QOS*/ rtlpci->acm_method = eAcmWay2_SW;
+ /*QOS*/
+ rtlpci->acm_method = eAcmWay2_SW;
/*task */
tasklet_init(&rtlpriv->works.irq_tasklet,
@@ -955,7 +1068,8 @@ static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw,
("queue:%d, ring_addr:%p\n", prio, ring));
for (i = 0; i < entries; i++) {
- nextdescaddress = (u32) dma + ((i + 1) % entries) *
+ nextdescaddress = (u32) dma +
+ ((i + 1) % entries) *
sizeof(*ring);
rtlpriv->cfg->ops->set_desc((u8 *)&(ring[i]),
@@ -1020,7 +1134,7 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw)
rtlpci->rxbuffersize,
PCI_DMA_FROMDEVICE);
- bufferaddress = (u32)(*((dma_addr_t *)skb->cb));
+ bufferaddress = (*((dma_addr_t *)skb->cb));
rtlpriv->cfg->ops->set_desc((u8 *)entry, false,
HW_DESC_RXBUFF_ADDR,
(u8 *)&bufferaddress);
@@ -1203,72 +1317,73 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw)
return 0;
}
-static unsigned int _rtl_mac_to_hwqueue(__le16 fc,
- unsigned int mac80211_queue_index)
+static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw,
+ struct sk_buff *skb)
{
- unsigned int hw_queue_index;
-
- if (unlikely(ieee80211_is_beacon(fc))) {
- hw_queue_index = BEACON_QUEUE;
- goto out;
- }
-
- if (ieee80211_is_mgmt(fc)) {
- hw_queue_index = MGNT_QUEUE;
- goto out;
- }
-
- switch (mac80211_queue_index) {
- case 0:
- hw_queue_index = VO_QUEUE;
- break;
- case 1:
- hw_queue_index = VI_QUEUE;
- break;
- case 2:
- hw_queue_index = BE_QUEUE;;
- break;
- case 3:
- hw_queue_index = BK_QUEUE;
- break;
- default:
- hw_queue_index = BE_QUEUE;
- RT_ASSERT(false, ("QSLT_BE queue, skb_queue:%d\n",
- mac80211_queue_index));
- break;
- }
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_sta *sta = info->control.sta;
+ struct rtl_sta_info *sta_entry = NULL;
+ u8 tid = rtl_get_tid(skb);
+
+ if (!sta)
+ return false;
+ sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+
+ if (!rtlpriv->rtlhal.earlymode_enable)
+ return false;
+ if (sta_entry->tids[tid].agg.agg_state != RTL_AGG_OPERATIONAL)
+ return false;
+ if (_rtl_mac_to_hwqueue(hw, skb) > VO_QUEUE)
+ return false;
+ if (tid > 7)
+ return false;
+
+ /* maybe every tid should be checked */
+ if (!rtlpriv->link_info.higher_busytxtraffic[tid])
+ return false;
+
+ spin_lock_bh(&rtlpriv->locks.waitq_lock);
+ skb_queue_tail(&rtlpriv->mac80211.skb_waitq[tid], skb);
+ spin_unlock_bh(&rtlpriv->locks.waitq_lock);
-out:
- return hw_queue_index;
+ return true;
}
-static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct rtl_tcb_desc *ptcb_desc)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_sta_info *sta_entry = NULL;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_sta *sta = info->control.sta;
struct rtl8192_tx_ring *ring;
struct rtl_tx_desc *pdesc;
u8 idx;
- unsigned int queue_index, hw_queue;
+ u8 hw_queue = _rtl_mac_to_hwqueue(hw, skb);
unsigned long flags;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
- __le16 fc = hdr->frame_control;
+ struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
+ __le16 fc = rtl_get_fc(skb);
u8 *pda_addr = hdr->addr1;
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
/*ssn */
- u8 *qc = NULL;
u8 tid = 0;
u16 seq_number = 0;
u8 own;
u8 temp_one = 1;
- if (ieee80211_is_mgmt(fc))
- rtl_tx_mgmt_proc(hw, skb);
- rtl_action_proc(hw, skb, true);
+ if (ieee80211_is_auth(fc)) {
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n"));
+ rtl_ips_nic_on(hw);
+ }
+
+ if (rtlpriv->psc.sw_ps_enabled) {
+ if (ieee80211_is_data(fc) && !ieee80211_is_nullfunc(fc) &&
+ !ieee80211_has_pm(fc))
+ hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
+ }
- queue_index = skb_get_queue_mapping(skb);
- hw_queue = _rtl_mac_to_hwqueue(fc, queue_index);
+ rtl_action_proc(hw, skb, true);
if (is_multicast_ether_addr(pda_addr))
rtlpriv->stats.txbytesmulticast += skb->len;
@@ -1278,7 +1393,6 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
rtlpriv->stats.txbytesunicast += skb->len;
spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
-
ring = &rtlpci->tx_ring[hw_queue];
if (hw_queue != BEACON_QUEUE)
idx = (ring->idx + skb_queue_len(&ring->queue)) %
@@ -1301,43 +1415,30 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
return skb->len;
}
- /*
- *if(ieee80211_is_nullfunc(fc)) {
- * spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
- * return 1;
- *}
- */
-
if (ieee80211_is_data_qos(fc)) {
- qc = ieee80211_get_qos_ctl(hdr);
- tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
-
- seq_number = mac->tids[tid].seq_number;
- seq_number &= IEEE80211_SCTL_SEQ;
- /*
- *hdr->seq_ctrl = hdr->seq_ctrl &
- *cpu_to_le16(IEEE80211_SCTL_FRAG);
- *hdr->seq_ctrl |= cpu_to_le16(seq_number);
- */
-
- seq_number += 1;
+ tid = rtl_get_tid(skb);
+ if (sta) {
+ sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+ seq_number = (le16_to_cpu(hdr->seq_ctrl) &
+ IEEE80211_SCTL_SEQ) >> 4;
+ seq_number += 1;
+
+ if (!ieee80211_has_morefrags(hdr->frame_control))
+ sta_entry->tids[tid].seq_number = seq_number;
+ }
}
if (ieee80211_is_data(fc))
rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX);
- rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc,
- info, skb, hw_queue);
+ rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc,
+ info, skb, hw_queue, ptcb_desc);
__skb_queue_tail(&ring->queue, skb);
- rtlpriv->cfg->ops->set_desc((u8 *) pdesc, true,
+ rtlpriv->cfg->ops->set_desc((u8 *)pdesc, true,
HW_DESC_OWN, (u8 *)&temp_one);
- if (!ieee80211_has_morefrags(hdr->frame_control)) {
- if (qc)
- mac->tids[tid].seq_number = seq_number;
- }
if ((ring->entries - skb_queue_len(&ring->queue)) < 2 &&
hw_queue != BEACON_QUEUE) {
@@ -1359,6 +1460,35 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
return 0;
}
+static void rtl_pci_flush(struct ieee80211_hw *hw, bool drop)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u16 i = 0;
+ int queue_id;
+ struct rtl8192_tx_ring *ring;
+
+ for (queue_id = RTL_PCI_MAX_TX_QUEUE_COUNT - 1; queue_id >= 0;) {
+ u32 queue_len;
+ ring = &pcipriv->dev.tx_ring[queue_id];
+ queue_len = skb_queue_len(&ring->queue);
+ if (queue_len == 0 || queue_id == BEACON_QUEUE ||
+ queue_id == TXCMD_QUEUE) {
+ queue_id--;
+ continue;
+ } else {
+ msleep(20);
+ i++;
+ }
+
+ /* we just wait 1s for all queues */
+ if (rtlpriv->psc.rfpwr_state == ERFOFF ||
+ is_hal_stop(rtlhal) || i >= 200)
+ return;
+ }
+}
+
static void rtl_pci_deinit(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1477,11 +1607,14 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
struct pci_dev *bridge_pdev = pdev->bus->self;
u16 venderid;
u16 deviceid;
+ u8 revisionid;
u16 irqline;
u8 tmp;
+ pcipriv->ndis_adapter.pcibridge_vendor = PCI_BRIDGE_VENDOR_UNKNOWN;
venderid = pdev->vendor;
deviceid = pdev->device;
+ pci_read_config_byte(pdev, 0x8, &revisionid);
pci_read_config_word(pdev, 0x3C, &irqline);
if (deviceid == RTL_PCI_8192_DID ||
@@ -1492,7 +1625,7 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
deviceid == RTL_PCI_8173_DID ||
deviceid == RTL_PCI_8172_DID ||
deviceid == RTL_PCI_8171_DID) {
- switch (pdev->revision) {
+ switch (revisionid) {
case RTL_PCI_REVISION_ID_8192PCIE:
RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
("8192 PCI-E is found - "
@@ -1521,6 +1654,12 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
("8192C PCI-E is found - "
"vid/did=%x/%x\n", venderid, deviceid));
+ } else if (deviceid == RTL_PCI_8192DE_DID ||
+ deviceid == RTL_PCI_8192DE_DID2) {
+ rtlhal->hw_type = HARDWARE_TYPE_RTL8192DE;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ ("8192D PCI-E is found - "
+ "vid/did=%x/%x\n", venderid, deviceid));
} else {
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
("Err: Unknown device -"
@@ -1529,6 +1668,25 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
rtlhal->hw_type = RTL_DEFAULT_HARDWARE_TYPE;
}
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192DE) {
+ if (revisionid == 0 || revisionid == 1) {
+ if (revisionid == 0) {
+ RT_TRACE(rtlpriv, COMP_INIT,
+ DBG_LOUD, ("Find 92DE MAC0.\n"));
+ rtlhal->interfaceindex = 0;
+ } else if (revisionid == 1) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("Find 92DE MAC1.\n"));
+ rtlhal->interfaceindex = 1;
+ }
+ } else {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("Unknown device - "
+ "VendorID/DeviceID=%x/%x, Revision=%x\n",
+ venderid, deviceid, revisionid));
+ rtlhal->interfaceindex = 0;
+ }
+ }
/*find bus info */
pcipriv->ndis_adapter.busnumber = pdev->bus->number;
pcipriv->ndis_adapter.devnumber = PCI_SLOT(pdev->devfn);
@@ -1554,12 +1712,12 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
PCI_SLOT(bridge_pdev->devfn);
pcipriv->ndis_adapter.pcibridge_funcnum =
PCI_FUNC(bridge_pdev->devfn);
- pcipriv->ndis_adapter.pcibridge_pciehdr_offset =
- pci_pcie_cap(bridge_pdev);
pcipriv->ndis_adapter.pcicfg_addrport =
(pcipriv->ndis_adapter.pcibridge_busnum << 16) |
(pcipriv->ndis_adapter.pcibridge_devnum << 11) |
(pcipriv->ndis_adapter.pcibridge_funcnum << 8) | (1 << 31);
+ pcipriv->ndis_adapter.pcibridge_pciehdr_offset =
+ pci_pcie_cap(bridge_pdev);
pcipriv->ndis_adapter.num4bytes =
(pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10) / 4;
@@ -1642,6 +1800,11 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
pcipriv = (void *)rtlpriv->priv;
pcipriv->dev.pdev = pdev;
+ /* init cfg & intf_ops */
+ rtlpriv->rtlhal.interface = INTF_PCI;
+ rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data);
+ rtlpriv->intf_ops = &rtl_pci_ops;
+
/*
*init dbgp flags before all
*other functions, because we will
@@ -1659,13 +1822,14 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
return err;
}
- pmem_start = pci_resource_start(pdev, 2);
- pmem_len = pci_resource_len(pdev, 2);
- pmem_flags = pci_resource_flags(pdev, 2);
+ pmem_start = pci_resource_start(pdev, rtlpriv->cfg->bar_id);
+ pmem_len = pci_resource_len(pdev, rtlpriv->cfg->bar_id);
+ pmem_flags = pci_resource_flags(pdev, rtlpriv->cfg->bar_id);
/*shared mem start */
rtlpriv->io.pci_mem_start =
- (unsigned long)pci_iomap(pdev, 2, pmem_len);
+ (unsigned long)pci_iomap(pdev,
+ rtlpriv->cfg->bar_id, pmem_len);
if (rtlpriv->io.pci_mem_start == 0) {
RT_ASSERT(false, ("Can't map PCI mem\n"));
goto fail2;
@@ -1684,11 +1848,6 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
pci_write_config_byte(pdev, 0x04, 0x06);
pci_write_config_byte(pdev, 0x04, 0x07);
- /* init cfg & intf_ops */
- rtlpriv->rtlhal.interface = INTF_PCI;
- rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data);
- rtlpriv->intf_ops = &rtl_pci_ops;
-
/* find adapter */
_rtl_pci_find_adapter(pdev, hw);
@@ -1806,7 +1965,6 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
rtl_pci_deinit(hw);
rtl_deinit_core(hw);
- rtlpriv->cfg->ops->deinit_sw_leds(hw);
_rtl_pci_io_handler_release(hw);
rtlpriv->cfg->ops->deinit_sw_vars(hw);
@@ -1821,6 +1979,9 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
}
pci_disable_device(pdev);
+
+ rtl_pci_disable_aspm(hw);
+
pci_set_drvdata(pdev, NULL);
ieee80211_free_hw(hw);
@@ -1844,10 +2005,15 @@ no need to call hw_disable here.
****************************************/
int rtl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
{
+ struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->cfg->ops->hw_suspend(hw);
+ rtl_deinit_rfkill(hw);
+
pci_save_state(pdev);
pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);
-
return 0;
}
EXPORT_SYMBOL(rtl_pci_suspend);
@@ -1855,6 +2021,8 @@ EXPORT_SYMBOL(rtl_pci_suspend);
int rtl_pci_resume(struct pci_dev *pdev)
{
int ret;
+ struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
pci_set_power_state(pdev, PCI_D0);
ret = pci_enable_device(pdev);
@@ -1865,15 +2033,20 @@ int rtl_pci_resume(struct pci_dev *pdev)
pci_restore_state(pdev);
+ rtlpriv->cfg->ops->hw_resume(hw);
+ rtl_init_rfkill(hw);
return 0;
}
EXPORT_SYMBOL(rtl_pci_resume);
struct rtl_intf_ops rtl_pci_ops = {
+ .read_efuse_byte = read_efuse_byte,
.adapter_start = rtl_pci_start,
.adapter_stop = rtl_pci_stop,
.adapter_tx = rtl_pci_tx,
+ .flush = rtl_pci_flush,
.reset_trx_ring = rtl_pci_reset_trx_ring,
+ .waitq_insert = rtl_pci_tx_chk_waitq_insert,
.disable_aspm = rtl_pci_disable_aspm,
.enable_aspm = rtl_pci_enable_aspm,
diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h
index 0caa81429726..671b1f5aa0cf 100644
--- a/drivers/net/wireless/rtlwifi/pci.h
+++ b/drivers/net/wireless/rtlwifi/pci.h
@@ -102,8 +102,8 @@
#define RTL_PCI_8191CE_DID 0x8177 /*8192ce */
#define RTL_PCI_8188CE_DID 0x8176 /*8192ce */
#define RTL_PCI_8192CU_DID 0x8191 /*8192ce */
-#define RTL_PCI_8192DE_DID 0x092D /*8192ce */
-#define RTL_PCI_8192DU_DID 0x092D /*8192ce */
+#define RTL_PCI_8192DE_DID 0x8193 /*8192de */
+#define RTL_PCI_8192DE_DID2 0x002B /*92DE*/
/*8192 support 16 pages of IO registers*/
#define RTL_MEM_MAPPED_IO_RANGE_8190PCI 0x1000
@@ -129,6 +129,11 @@ enum pci_bridge_vendor {
PCI_BRIDGE_VENDOR_MAX,
};
+struct rtl_pci_capabilities_header {
+ u8 capability_id;
+ u8 next;
+};
+
struct rtl_rx_desc {
u32 dword[8];
} __packed;
@@ -161,7 +166,9 @@ struct rtl_pci {
bool driver_is_goingto_unload;
bool up_first_time;
+ bool first_init;
bool being_init_adapter;
+ bool init_ready;
bool irq_enabled;
/*Tx */
@@ -192,11 +199,14 @@ struct rtl_pci {
u8 const_devicepci_aspm_setting;
/*If it supports ASPM, Offset[560h] = 0x40,
otherwise Offset[560h] = 0x00. */
- bool b_support_aspm;
- bool b_support_backdoor;
+ bool support_aspm;
+ bool support_backdoor;
/*QOS & EDCA */
enum acm_method acm_method;
+
+ u16 shortretry_limit;
+ u16 longretry_limit;
};
struct mp_adapter {
@@ -227,6 +237,7 @@ struct rtl_pci_priv {
struct rtl_pci dev;
struct mp_adapter ndis_adapter;
struct rtl_led_ctl ledctl;
+ struct bt_coexist_info bt_coexist;
};
#define rtl_pcipriv(hw) (((struct rtl_pci_priv *)(rtl_priv(hw))->priv))
diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c
index 6b7e217b6b89..39b0297ce925 100644
--- a/drivers/net/wireless/rtlwifi/ps.c
+++ b/drivers/net/wireless/rtlwifi/ps.c
@@ -36,7 +36,6 @@ bool rtl_ps_enable_nic(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
- bool init_status = true;
/*<1> reset trx ring */
if (rtlhal->interface == INTF_PCI)
@@ -49,7 +48,6 @@ bool rtl_ps_enable_nic(struct ieee80211_hw *hw)
/*<2> Enable Adapter */
rtlpriv->cfg->ops->hw_init(hw);
RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
- /*init_status = false; */
/*<3> Enable Interrupt */
rtlpriv->cfg->ops->enable_interrupt(hw);
@@ -57,13 +55,12 @@ bool rtl_ps_enable_nic(struct ieee80211_hw *hw)
/*<enable timer> */
rtl_watch_dog_timer_callback((unsigned long)hw);
- return init_status;
+ return true;
}
EXPORT_SYMBOL(rtl_ps_enable_nic);
bool rtl_ps_disable_nic(struct ieee80211_hw *hw)
{
- bool status = true;
struct rtl_priv *rtlpriv = rtl_priv(hw);
/*<1> Stop all timer */
@@ -75,7 +72,7 @@ bool rtl_ps_disable_nic(struct ieee80211_hw *hw)
/*<3> Disable Adapter */
rtlpriv->cfg->ops->hw_disable(hw);
- return status;
+ return true;
}
EXPORT_SYMBOL(rtl_ps_disable_nic);
@@ -193,12 +190,13 @@ static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw)
ppsc->swrf_processing = true;
- if (ppsc->inactive_pwrstate == ERFON && rtlhal->interface == INTF_PCI) {
+ if (ppsc->inactive_pwrstate == ERFON &&
+ rtlhal->interface == INTF_PCI) {
if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) &&
- RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM) &&
+ RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) &&
rtlhal->interface == INTF_PCI) {
rtlpriv->intf_ops->disable_aspm(hw);
- RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM);
+ RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
}
}
@@ -207,9 +205,10 @@ static void _rtl_ps_inactive_ps(struct ieee80211_hw *hw)
if (ppsc->inactive_pwrstate == ERFOFF &&
rtlhal->interface == INTF_PCI) {
- if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) {
+ if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM &&
+ !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
rtlpriv->intf_ops->enable_aspm(hw);
- RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM);
+ RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
}
}
@@ -233,6 +232,9 @@ void rtl_ips_nic_off_wq_callback(void *data)
return;
}
+ if (mac->link_state > MAC80211_NOLINK)
+ return;
+
if (is_hal_stop(rtlhal))
return;
@@ -284,10 +286,14 @@ void rtl_ips_nic_off(struct ieee80211_hw *hw)
void rtl_ips_nic_on(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
enum rf_pwrstate rtstate;
unsigned long flags;
+ if (mac->opmode != NL80211_IFTYPE_STATION)
+ return;
+
spin_lock_irqsave(&rtlpriv->locks.ips_lock, flags);
if (ppsc->inactiveps) {
@@ -370,8 +376,7 @@ static void rtl_lps_set_psmode(struct ieee80211_hw *hw, u8 rt_psmode)
* mode and set RPWM to turn RF on.
*/
- if ((ppsc->fwctrl_lps) && (ppsc->leisure_ps) &&
- ppsc->report_linked) {
+ if ((ppsc->fwctrl_lps) && ppsc->report_linked) {
bool fw_current_inps;
if (ppsc->dot11_psmode == EACTIVE) {
RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
@@ -425,7 +430,7 @@ void rtl_lps_enter(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
unsigned long flag;
- if (!(ppsc->fwctrl_lps && ppsc->leisure_ps))
+ if (!ppsc->fwctrl_lps)
return;
if (rtlpriv->sec.being_setkey)
@@ -446,17 +451,16 @@ void rtl_lps_enter(struct ieee80211_hw *hw)
spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
- if (ppsc->leisure_ps) {
- /* Idle for a while if we connect to AP a while ago. */
- if (mac->cnt_after_linked >= 2) {
- if (ppsc->dot11_psmode == EACTIVE) {
- RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ /* Idle for a while if we connect to AP a while ago. */
+ if (mac->cnt_after_linked >= 2) {
+ if (ppsc->dot11_psmode == EACTIVE) {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
("Enter 802.11 power save mode...\n"));
- rtl_lps_set_psmode(hw, EAUTOPS);
- }
+ rtl_lps_set_psmode(hw, EAUTOPS);
}
}
+
spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
}
@@ -470,17 +474,17 @@ void rtl_lps_leave(struct ieee80211_hw *hw)
spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
- if (ppsc->fwctrl_lps && ppsc->leisure_ps) {
+ if (ppsc->fwctrl_lps) {
if (ppsc->dot11_psmode != EACTIVE) {
/*FIX ME */
rtlpriv->cfg->ops->enable_interrupt(hw);
if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM &&
- RT_IN_PS_LEVEL(ppsc, RT_RF_LPS_LEVEL_ASPM) &&
+ RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM) &&
rtlhal->interface == INTF_PCI) {
rtlpriv->intf_ops->disable_aspm(hw);
- RT_CLEAR_PS_LEVEL(ppsc, RT_RF_LPS_LEVEL_ASPM);
+ RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
}
RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
@@ -491,3 +495,214 @@ void rtl_lps_leave(struct ieee80211_hw *hw)
}
spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
}
+
+/* For sw LPS*/
+void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct ieee80211_hdr *hdr = (void *) data;
+ struct ieee80211_tim_ie *tim_ie;
+ u8 *tim;
+ u8 tim_len;
+ bool u_buffed;
+ bool m_buffed;
+
+ if (mac->opmode != NL80211_IFTYPE_STATION)
+ return;
+
+ if (!rtlpriv->psc.swctrl_lps)
+ return;
+
+ if (rtlpriv->mac80211.link_state != MAC80211_LINKED)
+ return;
+
+ if (!rtlpriv->psc.sw_ps_enabled)
+ return;
+
+ if (rtlpriv->psc.fwctrl_lps)
+ return;
+
+ if (likely(!(hw->conf.flags & IEEE80211_CONF_PS)))
+ return;
+
+ /* check if this really is a beacon */
+ if (!ieee80211_is_beacon(hdr->frame_control))
+ return;
+
+ /* min. beacon length + FCS_LEN */
+ if (len <= 40 + FCS_LEN)
+ return;
+
+ /* and only beacons from the associated BSSID, please */
+ if (compare_ether_addr(hdr->addr3, rtlpriv->mac80211.bssid))
+ return;
+
+ rtlpriv->psc.last_beacon = jiffies;
+
+ tim = rtl_find_ie(data, len - FCS_LEN, WLAN_EID_TIM);
+ if (!tim)
+ return;
+
+ if (tim[1] < sizeof(*tim_ie))
+ return;
+
+ tim_len = tim[1];
+ tim_ie = (struct ieee80211_tim_ie *) &tim[2];
+
+ if (!WARN_ON_ONCE(!hw->conf.ps_dtim_period))
+ rtlpriv->psc.dtim_counter = tim_ie->dtim_count;
+
+ /* Check whenever the PHY can be turned off again. */
+
+ /* 1. What about buffered unicast traffic for our AID? */
+ u_buffed = ieee80211_check_tim(tim_ie, tim_len,
+ rtlpriv->mac80211.assoc_id);
+
+ /* 2. Maybe the AP wants to send multicast/broadcast data? */
+ m_buffed = tim_ie->bitmap_ctrl & 0x01;
+ rtlpriv->psc.multi_buffered = m_buffed;
+
+ /* unicast will process by mac80211 through
+ * set ~IEEE80211_CONF_PS, So we just check
+ * multicast frames here */
+ if (!m_buffed) {
+ /* back to low-power land. and delay is
+ * prevent null power save frame tx fail */
+ queue_delayed_work(rtlpriv->works.rtl_wq,
+ &rtlpriv->works.ps_work, MSECS(5));
+ } else {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG, ("u_bufferd: %x, "
+ "m_buffered: %x\n", u_buffed, m_buffed));
+ }
+}
+
+void rtl_swlps_rf_awake(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ unsigned long flag;
+
+ if (!rtlpriv->psc.swctrl_lps)
+ return;
+ if (mac->link_state != MAC80211_LINKED)
+ return;
+
+ if (ppsc->reg_rfps_level & RT_RF_LPS_LEVEL_ASPM &&
+ RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
+ rtlpriv->intf_ops->disable_aspm(hw);
+ RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
+ }
+
+ spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
+ rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS, false);
+ spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
+}
+
+void rtl_swlps_rfon_wq_callback(void *data)
+{
+ struct rtl_works *rtlworks =
+ container_of_dwork_rtl(data, struct rtl_works, ps_rfon_wq);
+ struct ieee80211_hw *hw = rtlworks->hw;
+
+ rtl_swlps_rf_awake(hw);
+}
+
+void rtl_swlps_rf_sleep(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ unsigned long flag;
+ u8 sleep_intv;
+
+ if (!rtlpriv->psc.sw_ps_enabled)
+ return;
+
+ if ((rtlpriv->sec.being_setkey) ||
+ (mac->opmode == NL80211_IFTYPE_ADHOC))
+ return;
+
+ /*sleep after linked 10s, to let DHCP and 4-way handshake ok enough!! */
+ if ((mac->link_state != MAC80211_LINKED) || (mac->cnt_after_linked < 5))
+ return;
+
+ if (rtlpriv->link_info.busytraffic)
+ return;
+
+ spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
+ if (rtlpriv->psc.rfchange_inprogress) {
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
+ return;
+ }
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
+
+ spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
+ rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS, false);
+ spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
+
+ if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM &&
+ !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
+ rtlpriv->intf_ops->enable_aspm(hw);
+ RT_SET_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
+ }
+
+ /* here is power save alg, when this beacon is DTIM
+ * we will set sleep time to dtim_period * n;
+ * when this beacon is not DTIM, we will set sleep
+ * time to sleep_intv = rtlpriv->psc.dtim_counter or
+ * MAX_SW_LPS_SLEEP_INTV(default set to 5) */
+
+ if (rtlpriv->psc.dtim_counter == 0) {
+ if (hw->conf.ps_dtim_period == 1)
+ sleep_intv = hw->conf.ps_dtim_period * 2;
+ else
+ sleep_intv = hw->conf.ps_dtim_period;
+ } else {
+ sleep_intv = rtlpriv->psc.dtim_counter;
+ }
+
+ if (sleep_intv > MAX_SW_LPS_SLEEP_INTV)
+ sleep_intv = MAX_SW_LPS_SLEEP_INTV;
+
+ /* this print should always be dtim_conter = 0 &
+ * sleep = dtim_period, that meaons, we should
+ * awake before every dtim */
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
+ ("dtim_counter:%x will sleep :%d"
+ " beacon_intv\n", rtlpriv->psc.dtim_counter, sleep_intv));
+
+ /* we tested that 40ms is enough for sw & hw sw delay */
+ queue_delayed_work(rtlpriv->works.rtl_wq, &rtlpriv->works.ps_rfon_wq,
+ MSECS(sleep_intv * mac->vif->bss_conf.beacon_int - 40));
+}
+
+
+void rtl_swlps_wq_callback(void *data)
+{
+ struct rtl_works *rtlworks = container_of_dwork_rtl(data,
+ struct rtl_works,
+ ps_work);
+ struct ieee80211_hw *hw = rtlworks->hw;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ bool ps = false;
+
+ ps = (hw->conf.flags & IEEE80211_CONF_PS);
+
+ /* we can sleep after ps null send ok */
+ if (rtlpriv->psc.state_inap) {
+ rtl_swlps_rf_sleep(hw);
+
+ if (rtlpriv->psc.state && !ps) {
+ rtlpriv->psc.sleep_ms = jiffies_to_msecs(jiffies -
+ rtlpriv->psc.last_action);
+ }
+
+ if (ps)
+ rtlpriv->psc.last_slept = jiffies;
+
+ rtlpriv->psc.last_action = jiffies;
+ rtlpriv->psc.state = ps;
+ }
+}
diff --git a/drivers/net/wireless/rtlwifi/ps.h b/drivers/net/wireless/rtlwifi/ps.h
index ae56da801a23..e3bf89840370 100644
--- a/drivers/net/wireless/rtlwifi/ps.h
+++ b/drivers/net/wireless/rtlwifi/ps.h
@@ -30,6 +30,8 @@
#ifndef __REALTEK_RTL_PCI_PS_H__
#define __REALTEK_RTL_PCI_PS_H__
+#define MAX_SW_LPS_SLEEP_INTV 5
+
bool rtl_ps_set_rf_state(struct ieee80211_hw *hw,
enum rf_pwrstate state_toset, u32 changesource,
bool protect_or_not);
@@ -40,4 +42,11 @@ void rtl_ips_nic_on(struct ieee80211_hw *hw);
void rtl_ips_nic_off_wq_callback(void *data);
void rtl_lps_enter(struct ieee80211_hw *hw);
void rtl_lps_leave(struct ieee80211_hw *hw);
+
+void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len);
+void rtl_swlps_wq_callback(void *data);
+void rtl_swlps_rfon_wq_callback(void *data);
+void rtl_swlps_rf_awake(struct ieee80211_hw *hw);
+void rtl_swlps_rf_sleep(struct ieee80211_hw *hw);
+
#endif
diff --git a/drivers/net/wireless/rtlwifi/rc.c b/drivers/net/wireless/rtlwifi/rc.c
index 91634107434a..30da68a77786 100644
--- a/drivers/net/wireless/rtlwifi/rc.c
+++ b/drivers/net/wireless/rtlwifi/rc.c
@@ -38,17 +38,14 @@
*CCK11M or OFDM_54M based on wireless mode.
*/
static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv,
+ struct ieee80211_sta *sta,
struct sk_buff *skb, bool not_data)
{
struct rtl_mac *rtlmac = rtl_mac(rtlpriv);
-
- /*
- *mgt use 1M, although we have check it
- *before this function use rate_control_send_low,
- *we still check it here
- */
- if (not_data)
- return rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M];
+ struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_sta_info *sta_entry = NULL;
+ u8 wireless_mode = 0;
/*
*this rate is no use for true rate, firmware
@@ -57,35 +54,78 @@ static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv,
*2.in rtl_get_tcb_desc when we check rate is
* 1M we will not use FW rate but user rate.
*/
- if (rtl_is_special_data(rtlpriv->mac80211.hw, skb, true)) {
- return rtlpriv->cfg->maps[RTL_RC_CCK_RATE1M];
+ if (rtlmac->opmode == NL80211_IFTYPE_AP ||
+ rtlmac->opmode == NL80211_IFTYPE_ADHOC) {
+ if (sta) {
+ sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+ wireless_mode = sta_entry->wireless_mode;
+ } else {
+ return 0;
+ }
+ } else {
+ wireless_mode = rtlmac->mode;
+ }
+
+ if (rtl_is_special_data(rtlpriv->mac80211.hw, skb, true) ||
+ not_data) {
+ return 0;
} else {
- if (rtlmac->mode == WIRELESS_MODE_B)
- return rtlpriv->cfg->maps[RTL_RC_CCK_RATE11M];
- else
- return rtlpriv->cfg->maps[RTL_RC_OFDM_RATE54M];
+ if (rtlhal->current_bandtype == BAND_ON_2_4G) {
+ if (wireless_mode == WIRELESS_MODE_B) {
+ return B_MODE_MAX_RIX;
+ } else if (wireless_mode == WIRELESS_MODE_G) {
+ return G_MODE_MAX_RIX;
+ } else {
+ if (get_rf_type(rtlphy) != RF_2T2R)
+ return N_MODE_MCS7_RIX;
+ else
+ return N_MODE_MCS15_RIX;
+ }
+ } else {
+ if (wireless_mode == WIRELESS_MODE_A) {
+ return A_MODE_MAX_RIX;
+ } else {
+ if (get_rf_type(rtlphy) != RF_2T2R)
+ return N_MODE_MCS7_RIX;
+ else
+ return N_MODE_MCS15_RIX;
+ }
+ }
}
}
static void _rtl_rc_rate_set_series(struct rtl_priv *rtlpriv,
+ struct ieee80211_sta *sta,
struct ieee80211_tx_rate *rate,
struct ieee80211_tx_rate_control *txrc,
- u8 tries, u8 rix, int rtsctsenable,
+ u8 tries, char rix, int rtsctsenable,
bool not_data)
{
struct rtl_mac *mac = rtl_mac(rtlpriv);
+ u8 sgi_20 = 0, sgi_40 = 0;
+ if (sta) {
+ sgi_20 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20;
+ sgi_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40;
+ }
rate->count = tries;
- rate->idx = (rix > 0x2) ? rix : 0x2;
+ rate->idx = rix >= 0x00 ? rix : 0x00;
if (!not_data) {
if (txrc->short_preamble)
rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
- if (mac->bw_40)
- rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
- if (mac->sgi_20 || mac->sgi_40)
+ if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_ADHOC) {
+ if (sta && (sta->ht_cap.cap &
+ IEEE80211_HT_CAP_SUP_WIDTH_20_40))
+ rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+ } else {
+ if (mac->bw_40)
+ rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
+ }
+ if (sgi_20 || sgi_40)
rate->flags |= IEEE80211_TX_RC_SHORT_GI;
- if (mac->ht_enable)
+ if (sta && sta->ht_cap.ht_supported)
rate->flags |= IEEE80211_TX_RC_MCS;
}
}
@@ -97,39 +137,39 @@ static void rtl_get_rate(void *ppriv, struct ieee80211_sta *sta,
struct sk_buff *skb = txrc->skb;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_tx_rate *rates = tx_info->control.rates;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- __le16 fc = hdr->frame_control;
+ __le16 fc = rtl_get_fc(skb);
u8 try_per_rate, i, rix;
bool not_data = !ieee80211_is_data(fc);
if (rate_control_send_low(sta, priv_sta, txrc))
return;
- rix = _rtl_rc_get_highest_rix(rtlpriv, skb, not_data);
-
+ rix = _rtl_rc_get_highest_rix(rtlpriv, sta, skb, not_data);
try_per_rate = 1;
- _rtl_rc_rate_set_series(rtlpriv, &rates[0], txrc,
+ _rtl_rc_rate_set_series(rtlpriv, sta, &rates[0], txrc,
try_per_rate, rix, 1, not_data);
if (!not_data) {
for (i = 1; i < 4; i++)
- _rtl_rc_rate_set_series(rtlpriv, &rates[i],
+ _rtl_rc_rate_set_series(rtlpriv, sta, &rates[i],
txrc, i, (rix - i), 1,
not_data);
}
}
-static bool _rtl_tx_aggr_check(struct rtl_priv *rtlpriv, u16 tid)
+static bool _rtl_tx_aggr_check(struct rtl_priv *rtlpriv,
+ struct rtl_sta_info *sta_entry, u16 tid)
{
struct rtl_mac *mac = rtl_mac(rtlpriv);
if (mac->act_scanning)
return false;
- if (mac->cnt_after_linked < 3)
+ if (mac->opmode == NL80211_IFTYPE_STATION &&
+ mac->cnt_after_linked < 3)
return false;
- if (mac->tids[tid].agg.agg_state == RTL_AGG_OFF)
+ if (sta_entry->tids[tid].agg.agg_state == RTL_AGG_STOP)
return true;
return false;
@@ -143,11 +183,9 @@ static void rtl_tx_status(void *ppriv,
{
struct rtl_priv *rtlpriv = ppriv;
struct rtl_mac *mac = rtl_mac(rtlpriv);
- struct ieee80211_hdr *hdr;
- __le16 fc;
-
- hdr = (struct ieee80211_hdr *)skb->data;
- fc = hdr->frame_control;
+ struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
+ __le16 fc = rtl_get_fc(skb);
+ struct rtl_sta_info *sta_entry;
if (!priv_sta || !ieee80211_is_data(fc))
return;
@@ -159,17 +197,21 @@ static void rtl_tx_status(void *ppriv,
|| is_broadcast_ether_addr(ieee80211_get_DA(hdr)))
return;
- /* Check if aggregation has to be enabled for this tid */
- if (conf_is_ht(&mac->hw->conf) &&
- !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
- if (ieee80211_is_data_qos(fc)) {
- u8 *qc, tid;
-
- qc = ieee80211_get_qos_ctl(hdr);
- tid = qc[0] & 0xf;
-
- if (_rtl_tx_aggr_check(rtlpriv, tid))
- ieee80211_start_tx_ba_session(sta, tid, 5000);
+ if (sta) {
+ /* Check if aggregation has to be enabled for this tid */
+ sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+ if ((sta->ht_cap.ht_supported == true) &&
+ !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
+ if (ieee80211_is_data_qos(fc)) {
+ u8 tid = rtl_get_tid(skb);
+ if (_rtl_tx_aggr_check(rtlpriv, sta_entry,
+ tid)) {
+ sta_entry->tids[tid].agg.agg_state =
+ RTL_AGG_PROGRESS;
+ ieee80211_start_tx_ba_session(sta,
+ tid, 5000);
+ }
+ }
}
}
}
@@ -178,43 +220,6 @@ static void rtl_rate_init(void *ppriv,
struct ieee80211_supported_band *sband,
struct ieee80211_sta *sta, void *priv_sta)
{
- struct rtl_priv *rtlpriv = ppriv;
- struct rtl_mac *mac = rtl_mac(rtlpriv);
- u8 is_ht = conf_is_ht(&mac->hw->conf);
-
- if ((mac->opmode == NL80211_IFTYPE_STATION) ||
- (mac->opmode == NL80211_IFTYPE_MESH_POINT) ||
- (mac->opmode == NL80211_IFTYPE_ADHOC)) {
-
- switch (sband->band) {
- case IEEE80211_BAND_2GHZ:
- rtlpriv->rate_priv->cur_ratetab_idx =
- RATR_INX_WIRELESS_G;
- if (is_ht)
- rtlpriv->rate_priv->cur_ratetab_idx =
- RATR_INX_WIRELESS_NGB;
- break;
- case IEEE80211_BAND_5GHZ:
- rtlpriv->rate_priv->cur_ratetab_idx =
- RATR_INX_WIRELESS_A;
- if (is_ht)
- rtlpriv->rate_priv->cur_ratetab_idx =
- RATR_INX_WIRELESS_NGB;
- break;
- default:
- RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
- ("Invalid band\n"));
- rtlpriv->rate_priv->cur_ratetab_idx =
- RATR_INX_WIRELESS_NGB;
- break;
- }
-
- RT_TRACE(rtlpriv, COMP_RATE, DBG_DMESG,
- ("Choosing rate table index: %d\n",
- rtlpriv->rate_priv->cur_ratetab_idx));
-
- }
-
}
static void rtl_rate_update(void *ppriv,
@@ -223,49 +228,6 @@ static void rtl_rate_update(void *ppriv,
u32 changed,
enum nl80211_channel_type oper_chan_type)
{
- struct rtl_priv *rtlpriv = ppriv;
- struct rtl_mac *mac = rtl_mac(rtlpriv);
- struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
- bool oper_cw40 = false, oper_sgi40;
- bool local_cw40 = mac->bw_40;
- bool local_sgi40 = mac->sgi_40;
- u8 is_ht = conf_is_ht(&mac->hw->conf);
-
- if (changed & IEEE80211_RC_HT_CHANGED) {
- if (mac->opmode != NL80211_IFTYPE_STATION)
- return;
-
- if (rtlhal->hw->conf.channel_type == NL80211_CHAN_HT40MINUS ||
- rtlhal->hw->conf.channel_type == NL80211_CHAN_HT40PLUS)
- oper_cw40 = true;
-
- oper_sgi40 = mac->sgi_40;
-
- if ((local_cw40 != oper_cw40) || (local_sgi40 != oper_sgi40)) {
- switch (sband->band) {
- case IEEE80211_BAND_2GHZ:
- rtlpriv->rate_priv->cur_ratetab_idx =
- RATR_INX_WIRELESS_G;
- if (is_ht)
- rtlpriv->rate_priv->cur_ratetab_idx =
- RATR_INX_WIRELESS_NGB;
- break;
- case IEEE80211_BAND_5GHZ:
- rtlpriv->rate_priv->cur_ratetab_idx =
- RATR_INX_WIRELESS_A;
- if (is_ht)
- rtlpriv->rate_priv->cur_ratetab_idx =
- RATR_INX_WIRELESS_NGB;
- break;
- default:
- RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
- ("Invalid band\n"));
- rtlpriv->rate_priv->cur_ratetab_idx =
- RATR_INX_WIRELESS_NGB;
- break;
- }
- }
- }
}
static void *rtl_rate_alloc(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/rtlwifi/rc.h b/drivers/net/wireless/rtlwifi/rc.h
index b4667c035f0b..4afa2c20adcf 100644
--- a/drivers/net/wireless/rtlwifi/rc.h
+++ b/drivers/net/wireless/rtlwifi/rc.h
@@ -30,8 +30,15 @@
#ifndef __RTL_RC_H__
#define __RTL_RC_H__
+#define B_MODE_MAX_RIX 3
+#define G_MODE_MAX_RIX 11
+#define A_MODE_MAX_RIX 7
+
+/* in mac80211 mcs0-mcs15 is idx0-idx15*/
+#define N_MODE_MCS7_RIX 7
+#define N_MODE_MCS15_RIX 15
+
struct rtl_rate_priv {
- u8 cur_ratetab_idx;
u8 ht_cap;
};
diff --git a/drivers/net/wireless/rtlwifi/regd.c b/drivers/net/wireless/rtlwifi/regd.c
index d26f957981ad..8f6718f163e5 100644
--- a/drivers/net/wireless/rtlwifi/regd.c
+++ b/drivers/net/wireless/rtlwifi/regd.c
@@ -66,31 +66,83 @@ static struct country_code_to_enum_rd allCountries[] = {
NL80211_RRF_PASSIVE_SCAN | \
NL80211_RRF_NO_OFDM)
+/* 5G chan 36 - chan 64*/
+#define RTL819x_5GHZ_5150_5350 \
+ REG_RULE(5150-10, 5350+10, 40, 0, 30, \
+ NL80211_RRF_PASSIVE_SCAN | \
+ NL80211_RRF_NO_IBSS)
+
+/* 5G chan 100 - chan 165*/
+#define RTL819x_5GHZ_5470_5850 \
+ REG_RULE(5470-10, 5850+10, 40, 0, 30, \
+ NL80211_RRF_PASSIVE_SCAN | \
+ NL80211_RRF_NO_IBSS)
+
+/* 5G chan 149 - chan 165*/
+#define RTL819x_5GHZ_5725_5850 \
+ REG_RULE(5725-10, 5850+10, 40, 0, 30, \
+ NL80211_RRF_PASSIVE_SCAN | \
+ NL80211_RRF_NO_IBSS)
+
+#define RTL819x_5GHZ_ALL \
+ (RTL819x_5GHZ_5150_5350, RTL819x_5GHZ_5470_5850)
+
static const struct ieee80211_regdomain rtl_regdom_11 = {
.n_reg_rules = 1,
.alpha2 = "99",
.reg_rules = {
RTL819x_2GHZ_CH01_11,
- }
+ }
+};
+
+static const struct ieee80211_regdomain rtl_regdom_12_13 = {
+ .n_reg_rules = 2,
+ .alpha2 = "99",
+ .reg_rules = {
+ RTL819x_2GHZ_CH01_11,
+ RTL819x_2GHZ_CH12_13,
+ }
};
-static const struct ieee80211_regdomain rtl_regdom_global = {
+static const struct ieee80211_regdomain rtl_regdom_no_midband = {
.n_reg_rules = 3,
.alpha2 = "99",
.reg_rules = {
RTL819x_2GHZ_CH01_11,
- RTL819x_2GHZ_CH12_13,
- RTL819x_2GHZ_CH14,
- }
+ RTL819x_5GHZ_5150_5350,
+ RTL819x_5GHZ_5725_5850,
+ }
};
-static const struct ieee80211_regdomain rtl_regdom_world = {
- .n_reg_rules = 2,
+static const struct ieee80211_regdomain rtl_regdom_60_64 = {
+ .n_reg_rules = 3,
.alpha2 = "99",
.reg_rules = {
RTL819x_2GHZ_CH01_11,
- RTL819x_2GHZ_CH12_13,
- }
+ RTL819x_2GHZ_CH12_13,
+ RTL819x_5GHZ_5725_5850,
+ }
+};
+
+static const struct ieee80211_regdomain rtl_regdom_14_60_64 = {
+ .n_reg_rules = 4,
+ .alpha2 = "99",
+ .reg_rules = {
+ RTL819x_2GHZ_CH01_11,
+ RTL819x_2GHZ_CH12_13,
+ RTL819x_2GHZ_CH14,
+ RTL819x_5GHZ_5725_5850,
+ }
+};
+
+static const struct ieee80211_regdomain rtl_regdom_14 = {
+ .n_reg_rules = 3,
+ .alpha2 = "99",
+ .reg_rules = {
+ RTL819x_2GHZ_CH01_11,
+ RTL819x_2GHZ_CH12_13,
+ RTL819x_2GHZ_CH14,
+ }
};
static bool _rtl_is_radar_freq(u16 center_freq)
@@ -162,6 +214,8 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy,
u32 bandwidth = 0;
int r;
+ if (!wiphy->bands[IEEE80211_BAND_2GHZ])
+ return;
sband = wiphy->bands[IEEE80211_BAND_2GHZ];
/*
@@ -292,25 +346,26 @@ static const struct ieee80211_regdomain *_rtl_regdomain_select(
{
switch (reg->country_code) {
case COUNTRY_CODE_FCC:
+ return &rtl_regdom_no_midband;
case COUNTRY_CODE_IC:
return &rtl_regdom_11;
case COUNTRY_CODE_ETSI:
+ case COUNTRY_CODE_TELEC_NETGEAR:
+ return &rtl_regdom_60_64;
case COUNTRY_CODE_SPAIN:
case COUNTRY_CODE_FRANCE:
case COUNTRY_CODE_ISRAEL:
- case COUNTRY_CODE_TELEC_NETGEAR:
- return &rtl_regdom_world;
+ case COUNTRY_CODE_WORLD_WIDE_13:
+ return &rtl_regdom_12_13;
case COUNTRY_CODE_MKK:
case COUNTRY_CODE_MKK1:
case COUNTRY_CODE_TELEC:
case COUNTRY_CODE_MIC:
- return &rtl_regdom_global;
+ return &rtl_regdom_14_60_64;
case COUNTRY_CODE_GLOBAL_DOMAIN:
- return &rtl_regdom_global;
- case COUNTRY_CODE_WORLD_WIDE_13:
- return &rtl_regdom_world;
+ return &rtl_regdom_14;
default:
- return &rtl_regdom_world;
+ return &rtl_regdom_no_midband;
}
}
@@ -323,9 +378,11 @@ static int _rtl_regd_init_wiphy(struct rtl_regulatory *reg,
const struct ieee80211_regdomain *regd;
wiphy->reg_notifier = reg_notifier;
+
wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
wiphy->flags &= ~WIPHY_FLAG_STRICT_REGULATORY;
wiphy->flags &= ~WIPHY_FLAG_DISABLE_BEACON_HINTS;
+
regd = _rtl_regdomain_select(reg);
wiphy_apply_custom_regulatory(wiphy, regd);
_rtl_reg_apply_radar_flags(wiphy);
@@ -355,8 +412,8 @@ int rtl_regd_init(struct ieee80211_hw *hw,
if (wiphy == NULL || &rtlpriv->regd == NULL)
return -EINVAL;
- /* force the channel plan to world wide 13 */
- rtlpriv->regd.country_code = COUNTRY_CODE_WORLD_WIDE_13;
+ /* init country_code from efuse channel plan */
+ rtlpriv->regd.country_code = rtlpriv->efuse.channel_plan;
RT_TRACE(rtlpriv, COMP_REGD, DBG_TRACE,
(KERN_DEBUG "rtl: EEPROM regdomain: 0x%0x\n",
@@ -373,8 +430,8 @@ int rtl_regd_init(struct ieee80211_hw *hw,
country = _rtl_regd_find_country(rtlpriv->regd.country_code);
if (country) {
- rtlpriv->regd.alpha2[0] = country->isoName[0];
- rtlpriv->regd.alpha2[1] = country->isoName[1];
+ rtlpriv->regd.alpha2[0] = country->iso_name[0];
+ rtlpriv->regd.alpha2[1] = country->iso_name[1];
} else {
rtlpriv->regd.alpha2[0] = '0';
rtlpriv->regd.alpha2[1] = '0';
diff --git a/drivers/net/wireless/rtlwifi/regd.h b/drivers/net/wireless/rtlwifi/regd.h
index 4cdbc4ae76d4..d23118938fac 100644
--- a/drivers/net/wireless/rtlwifi/regd.h
+++ b/drivers/net/wireless/rtlwifi/regd.h
@@ -32,7 +32,7 @@
struct country_code_to_enum_rd {
u16 countrycode;
- const char *isoName;
+ const char *iso_name;
};
enum country_code_type_t {
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
index bb023274414c..97183829b9be 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
@@ -28,10 +28,26 @@
*****************************************************************************/
#include "dm_common.h"
+#include "phy_common.h"
+#include "../pci.h"
+#include "../base.h"
struct dig_t dm_digtable;
static struct ps_t dm_pstable;
+#define BT_RSSI_STATE_NORMAL_POWER BIT_OFFSET_LEN_MASK_32(0, 1)
+#define BT_RSSI_STATE_AMDPU_OFF BIT_OFFSET_LEN_MASK_32(1, 1)
+#define BT_RSSI_STATE_SPECIAL_LOW BIT_OFFSET_LEN_MASK_32(2, 1)
+#define BT_RSSI_STATE_BG_EDCA_LOW BIT_OFFSET_LEN_MASK_32(3, 1)
+#define BT_RSSI_STATE_TXPOWER_LOW BIT_OFFSET_LEN_MASK_32(4, 1)
+
+#define RTLPRIV (struct rtl_priv *)
+#define GET_UNDECORATED_AVERAGE_RSSI(_priv) \
+ ((RTLPRIV(_priv))->mac80211.opmode == \
+ NL80211_IFTYPE_ADHOC) ? \
+ ((RTLPRIV(_priv))->dm.entry_min_undecoratedsmoothed_pwdb) : \
+ ((RTLPRIV(_priv))->dm.undecorated_smoothed_pwdb)
+
static const u32 ofdmswing_table[OFDM_TABLE_SIZE] = {
0x7f8001fe,
0x788001e2,
@@ -304,7 +320,7 @@ static void rtl92c_dm_ctrl_initgain_by_rssi(struct ieee80211_hw *hw)
static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw)
{
- static u8 binitialized; /* initialized to false */
+ static u8 initialized; /* initialized to false */
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
long rssi_strength = rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
@@ -315,11 +331,11 @@ static void rtl92c_dm_initial_gain_multi_sta(struct ieee80211_hw *hw)
if ((multi_sta == false) || (dm_digtable.cursta_connectctate !=
DIG_STA_DISCONNECT)) {
- binitialized = false;
+ initialized = false;
dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
return;
- } else if (binitialized == false) {
- binitialized = true;
+ } else if (initialized == false) {
+ initialized = true;
dm_digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_0;
dm_digtable.cur_igvalue = 0x20;
rtl92c_dm_write_dig(hw);
@@ -461,10 +477,7 @@ static void rtl92c_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw)
if (mac->act_scanning == true)
return;
- if ((mac->link_state > MAC80211_NOLINK) &&
- (mac->link_state < MAC80211_LINKED))
- dm_digtable.cursta_connectctate = DIG_STA_BEFORE_CONNECT;
- else if (mac->link_state >= MAC80211_LINKED)
+ if (mac->link_state >= MAC80211_LINKED)
dm_digtable.cursta_connectctate = DIG_STA_CONNECT;
else
dm_digtable.cursta_connectctate = DIG_STA_DISCONNECT;
@@ -562,23 +575,42 @@ EXPORT_SYMBOL(rtl92c_dm_init_edca_turbo);
static void rtl92c_dm_check_edca_turbo(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
static u64 last_txok_cnt;
static u64 last_rxok_cnt;
- u64 cur_txok_cnt;
- u64 cur_rxok_cnt;
+ static u32 last_bt_edca_ul;
+ static u32 last_bt_edca_dl;
+ u64 cur_txok_cnt = 0;
+ u64 cur_rxok_cnt = 0;
u32 edca_be_ul = 0x5ea42b;
u32 edca_be_dl = 0x5ea42b;
+ bool bt_change_edca = false;
- if (mac->opmode == NL80211_IFTYPE_ADHOC)
- goto dm_checkedcaturbo_exit;
+ if ((last_bt_edca_ul != rtlpcipriv->bt_coexist.bt_edca_ul) ||
+ (last_bt_edca_dl != rtlpcipriv->bt_coexist.bt_edca_dl)) {
+ rtlpriv->dm.current_turbo_edca = false;
+ last_bt_edca_ul = rtlpcipriv->bt_coexist.bt_edca_ul;
+ last_bt_edca_dl = rtlpcipriv->bt_coexist.bt_edca_dl;
+ }
+
+ if (rtlpcipriv->bt_coexist.bt_edca_ul != 0) {
+ edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_ul;
+ bt_change_edca = true;
+ }
+
+ if (rtlpcipriv->bt_coexist.bt_edca_dl != 0) {
+ edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_dl;
+ bt_change_edca = true;
+ }
if (mac->link_state != MAC80211_LINKED) {
rtlpriv->dm.current_turbo_edca = false;
return;
}
- if (!mac->ht_enable) { /*FIX MERGE */
+ if ((!mac->ht_enable) && (!rtlpcipriv->bt_coexist.bt_coexistence)) {
if (!(edca_be_ul & 0xffff0000))
edca_be_ul |= 0x005e0000;
@@ -586,10 +618,12 @@ static void rtl92c_dm_check_edca_turbo(struct ieee80211_hw *hw)
edca_be_dl |= 0x005e0000;
}
- if ((!rtlpriv->dm.is_any_nonbepkts) &&
- (!rtlpriv->dm.disable_framebursting)) {
+ if ((bt_change_edca) || ((!rtlpriv->dm.is_any_nonbepkts) &&
+ (!rtlpriv->dm.disable_framebursting))) {
+
cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt;
cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt;
+
if (cur_rxok_cnt > 4 * cur_txok_cnt) {
if (!rtlpriv->dm.is_cur_rdlstate ||
!rtlpriv->dm.current_turbo_edca) {
@@ -618,7 +652,6 @@ static void rtl92c_dm_check_edca_turbo(struct ieee80211_hw *hw)
}
}
-dm_checkedcaturbo_exit:
rtlpriv->dm.is_any_nonbepkts = false;
last_txok_cnt = rtlpriv->stats.txbytesunicast;
last_rxok_cnt = rtlpriv->stats.rxbytesunicast;
@@ -633,14 +666,14 @@ static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw
struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
u8 thermalvalue, delta, delta_lck, delta_iqk;
long ele_a, ele_d, temp_cck, val_x, value32;
- long val_y, ele_c;
- u8 ofdm_index[2], cck_index, ofdm_index_old[2], cck_index_old;
+ long val_y, ele_c = 0;
+ u8 ofdm_index[2], cck_index = 0, ofdm_index_old[2], cck_index_old = 0;
int i;
bool is2t = IS_92C_SERIAL(rtlhal->version);
u8 txpwr_level[2] = {0, 0};
u8 ofdm_min_index = 6, rf;
- rtlpriv->dm.txpower_trackingInit = true;
+ rtlpriv->dm.txpower_trackinginit = true;
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
("rtl92c_dm_txpower_tracking_callback_thermalmeter\n"));
@@ -683,7 +716,6 @@ static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw
for (i = 0; i < OFDM_TABLE_LENGTH; i++) {
if (ele_d == (ofdmswing_table[i] &
MASKOFDM_D)) {
- ofdm_index_old[1] = (u8) i;
RT_TRACE(rtlpriv, COMP_POWER_TRACKING,
DBG_LOUD,
@@ -1062,7 +1094,7 @@ static void rtl92c_dm_initialize_txpower_tracking_thermalmeter(
struct rtl_priv *rtlpriv = rtl_priv(hw);
rtlpriv->dm.txpower_tracking = true;
- rtlpriv->dm.txpower_trackingInit = false;
+ rtlpriv->dm.txpower_trackinginit = false;
RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
("pMgntInfo->txpower_tracking = %d\n",
@@ -1132,6 +1164,7 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rate_adaptive *p_ra = &(rtlpriv->ra);
u32 low_rssithresh_for_ra, high_rssithresh_for_ra;
+ struct ieee80211_sta *sta = NULL;
if (is_hal_stop(rtlhal)) {
RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD,
@@ -1145,8 +1178,8 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
return;
}
- if (mac->link_state == MAC80211_LINKED) {
-
+ if (mac->link_state == MAC80211_LINKED &&
+ mac->opmode == NL80211_IFTYPE_STATION) {
switch (p_ra->pre_ratr_state) {
case DM_RATR_STA_HIGH:
high_rssithresh_for_ra = 50;
@@ -1185,10 +1218,13 @@ static void rtl92c_dm_refresh_rate_adaptive_mask(struct ieee80211_hw *hw)
("PreState = %d, CurState = %d\n",
p_ra->pre_ratr_state, p_ra->ratr_state));
- rtlpriv->cfg->ops->update_rate_mask(hw,
+ rcu_read_lock();
+ sta = ieee80211_find_sta(mac->vif, mac->bssid);
+ rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
p_ra->ratr_state);
p_ra->pre_ratr_state = p_ra->ratr_state;
+ rcu_read_unlock();
}
}
}
@@ -1202,51 +1238,6 @@ static void rtl92c_dm_init_dynamic_bb_powersaving(struct ieee80211_hw *hw)
dm_pstable.rssi_val_min = 0;
}
-static void rtl92c_dm_1r_cca(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_phy *rtlphy = &(rtlpriv->phy);
-
- if (dm_pstable.rssi_val_min != 0) {
- if (dm_pstable.pre_ccastate == CCA_2R) {
- if (dm_pstable.rssi_val_min >= 35)
- dm_pstable.cur_ccasate = CCA_1R;
- else
- dm_pstable.cur_ccasate = CCA_2R;
- } else {
- if (dm_pstable.rssi_val_min <= 30)
- dm_pstable.cur_ccasate = CCA_2R;
- else
- dm_pstable.cur_ccasate = CCA_1R;
- }
- } else {
- dm_pstable.cur_ccasate = CCA_MAX;
- }
-
- if (dm_pstable.pre_ccastate != dm_pstable.cur_ccasate) {
- if (dm_pstable.cur_ccasate == CCA_1R) {
- if (get_rf_type(rtlphy) == RF_2T2R) {
- rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE,
- MASKBYTE0, 0x13);
- rtl_set_bbreg(hw, 0xe70, MASKBYTE3, 0x20);
- } else {
- rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE,
- MASKBYTE0, 0x23);
- rtl_set_bbreg(hw, 0xe70, 0x7fc00000, 0x10c);
- }
- } else {
- rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0,
- 0x33);
- rtl_set_bbreg(hw, 0xe70, MASKBYTE3, 0x63);
- }
- dm_pstable.pre_ccastate = dm_pstable.cur_ccasate;
- }
-
- RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD, ("CCAStage = %s\n",
- (dm_pstable.cur_ccasate ==
- 0) ? "1RCCA" : "2RCCA"));
-}
-
void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal)
{
static u8 initialize;
@@ -1352,7 +1343,9 @@ static void rtl92c_dm_dynamic_bb_powersaving(struct ieee80211_hw *hw)
}
if (IS_92C_SERIAL(rtlhal->version))
- rtl92c_dm_1r_cca(hw);
+ ;/* rtl92c_dm_1r_cca(hw); */
+ else
+ rtl92c_dm_rf_saving(hw, false);
}
void rtl92c_dm_init(struct ieee80211_hw *hw)
@@ -1369,6 +1362,84 @@ void rtl92c_dm_init(struct ieee80211_hw *hw)
}
EXPORT_SYMBOL(rtl92c_dm_init);
+void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ long undecorated_smoothed_pwdb;
+
+ if (!rtlpriv->dm.dynamic_txpower_enable)
+ return;
+
+ if (rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) {
+ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+ return;
+ }
+
+ if ((mac->link_state < MAC80211_LINKED) &&
+ (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
+ ("Not connected to any\n"));
+
+ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+
+ rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL;
+ return;
+ }
+
+ if (mac->link_state >= MAC80211_LINKED) {
+ if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+ undecorated_smoothed_pwdb =
+ rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("AP Client PWDB = 0x%lx\n",
+ undecorated_smoothed_pwdb));
+ } else {
+ undecorated_smoothed_pwdb =
+ rtlpriv->dm.undecorated_smoothed_pwdb;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("STA Default Port PWDB = 0x%lx\n",
+ undecorated_smoothed_pwdb));
+ }
+ } else {
+ undecorated_smoothed_pwdb =
+ rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("AP Ext Port PWDB = 0x%lx\n",
+ undecorated_smoothed_pwdb));
+ }
+
+ if (undecorated_smoothed_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) {
+ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n"));
+ } else if ((undecorated_smoothed_pwdb <
+ (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) &&
+ (undecorated_smoothed_pwdb >=
+ TX_POWER_NEAR_FIELD_THRESH_LVL1)) {
+
+ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x10)\n"));
+ } else if (undecorated_smoothed_pwdb <
+ (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) {
+ rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("TXHIGHPWRLEVEL_NORMAL\n"));
+ }
+
+ if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl)) {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("PHY_SetTxPowerLevel8192S() Channel = %d\n",
+ rtlphy->current_channel));
+ rtl92c_phy_set_txpower_level(hw, rtlphy->current_channel);
+ }
+
+ rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl;
+}
+
void rtl92c_dm_watchdog(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1388,11 +1459,321 @@ void rtl92c_dm_watchdog(struct ieee80211_hw *hw)
rtl92c_dm_dig(hw);
rtl92c_dm_false_alarm_counter_statistics(hw);
rtl92c_dm_dynamic_bb_powersaving(hw);
- rtlpriv->cfg->ops->dm_dynamic_txpower(hw);
+ rtl92c_dm_dynamic_txpower(hw);
rtl92c_dm_check_txpower_tracking(hw);
rtl92c_dm_refresh_rate_adaptive_mask(hw);
+ rtl92c_dm_bt_coexist(hw);
rtl92c_dm_check_edca_turbo(hw);
-
}
}
EXPORT_SYMBOL(rtl92c_dm_watchdog);
+
+u8 rtl92c_bt_rssi_state_change(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+ long undecorated_smoothed_pwdb;
+ u8 curr_bt_rssi_state = 0x00;
+
+ if (rtlpriv->mac80211.link_state == MAC80211_LINKED) {
+ undecorated_smoothed_pwdb =
+ GET_UNDECORATED_AVERAGE_RSSI(rtlpriv);
+ } else {
+ if (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)
+ undecorated_smoothed_pwdb = 100;
+ else
+ undecorated_smoothed_pwdb =
+ rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+ }
+
+ /* Check RSSI to determine HighPower/NormalPower state for
+ * BT coexistence. */
+ if (undecorated_smoothed_pwdb >= 67)
+ curr_bt_rssi_state &= (~BT_RSSI_STATE_NORMAL_POWER);
+ else if (undecorated_smoothed_pwdb < 62)
+ curr_bt_rssi_state |= BT_RSSI_STATE_NORMAL_POWER;
+
+ /* Check RSSI to determine AMPDU setting for BT coexistence. */
+ if (undecorated_smoothed_pwdb >= 40)
+ curr_bt_rssi_state &= (~BT_RSSI_STATE_AMDPU_OFF);
+ else if (undecorated_smoothed_pwdb <= 32)
+ curr_bt_rssi_state |= BT_RSSI_STATE_AMDPU_OFF;
+
+ /* Marked RSSI state. It will be used to determine BT coexistence
+ * setting later. */
+ if (undecorated_smoothed_pwdb < 35)
+ curr_bt_rssi_state |= BT_RSSI_STATE_SPECIAL_LOW;
+ else
+ curr_bt_rssi_state &= (~BT_RSSI_STATE_SPECIAL_LOW);
+
+ /* Set Tx Power according to BT status. */
+ if (undecorated_smoothed_pwdb >= 30)
+ curr_bt_rssi_state |= BT_RSSI_STATE_TXPOWER_LOW;
+ else if (undecorated_smoothed_pwdb < 25)
+ curr_bt_rssi_state &= (~BT_RSSI_STATE_TXPOWER_LOW);
+
+ /* Check BT state related to BT_Idle in B/G mode. */
+ if (undecorated_smoothed_pwdb < 15)
+ curr_bt_rssi_state |= BT_RSSI_STATE_BG_EDCA_LOW;
+ else
+ curr_bt_rssi_state &= (~BT_RSSI_STATE_BG_EDCA_LOW);
+
+ if (curr_bt_rssi_state != rtlpcipriv->bt_coexist.bt_rssi_state) {
+ rtlpcipriv->bt_coexist.bt_rssi_state = curr_bt_rssi_state;
+ return true;
+ } else {
+ return false;
+ }
+}
+EXPORT_SYMBOL(rtl92c_bt_rssi_state_change);
+
+static bool rtl92c_bt_state_change(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+ u32 polling, ratio_tx, ratio_pri;
+ u32 bt_tx, bt_pri;
+ u8 bt_state;
+ u8 cur_service_type;
+
+ if (rtlpriv->mac80211.link_state < MAC80211_LINKED)
+ return false;
+
+ bt_state = rtl_read_byte(rtlpriv, 0x4fd);
+ bt_tx = rtl_read_dword(rtlpriv, 0x488);
+ bt_tx = bt_tx & 0x00ffffff;
+ bt_pri = rtl_read_dword(rtlpriv, 0x48c);
+ bt_pri = bt_pri & 0x00ffffff;
+ polling = rtl_read_dword(rtlpriv, 0x490);
+
+ if (bt_tx == 0xffffffff && bt_pri == 0xffffffff &&
+ polling == 0xffffffff && bt_state == 0xff)
+ return false;
+
+ bt_state &= BIT_OFFSET_LEN_MASK_32(0, 1);
+ if (bt_state != rtlpcipriv->bt_coexist.bt_cur_state) {
+ rtlpcipriv->bt_coexist.bt_cur_state = bt_state;
+
+ if (rtlpcipriv->bt_coexist.reg_bt_sco == 3) {
+ rtlpcipriv->bt_coexist.bt_service = BT_IDLE;
+
+ bt_state = bt_state |
+ ((rtlpcipriv->bt_coexist.bt_ant_isolation == 1) ?
+ 0 : BIT_OFFSET_LEN_MASK_32(1, 1)) |
+ BIT_OFFSET_LEN_MASK_32(2, 1);
+ rtl_write_byte(rtlpriv, 0x4fd, bt_state);
+ }
+ return true;
+ }
+
+ ratio_tx = bt_tx * 1000 / polling;
+ ratio_pri = bt_pri * 1000 / polling;
+ rtlpcipriv->bt_coexist.ratio_tx = ratio_tx;
+ rtlpcipriv->bt_coexist.ratio_pri = ratio_pri;
+
+ if (bt_state && rtlpcipriv->bt_coexist.reg_bt_sco == 3) {
+
+ if ((ratio_tx < 30) && (ratio_pri < 30))
+ cur_service_type = BT_IDLE;
+ else if ((ratio_pri > 110) && (ratio_pri < 250))
+ cur_service_type = BT_SCO;
+ else if ((ratio_tx >= 200) && (ratio_pri >= 200))
+ cur_service_type = BT_BUSY;
+ else if ((ratio_tx >= 350) && (ratio_tx < 500))
+ cur_service_type = BT_OTHERBUSY;
+ else if (ratio_tx >= 500)
+ cur_service_type = BT_PAN;
+ else
+ cur_service_type = BT_OTHER_ACTION;
+
+ if (cur_service_type != rtlpcipriv->bt_coexist.bt_service) {
+ rtlpcipriv->bt_coexist.bt_service = cur_service_type;
+ bt_state = bt_state |
+ ((rtlpcipriv->bt_coexist.bt_ant_isolation == 1) ?
+ 0 : BIT_OFFSET_LEN_MASK_32(1, 1)) |
+ ((rtlpcipriv->bt_coexist.bt_service != BT_IDLE) ?
+ 0 : BIT_OFFSET_LEN_MASK_32(2, 1));
+
+ /* Add interrupt migration when bt is not ini
+ * idle state (no traffic). */
+ if (rtlpcipriv->bt_coexist.bt_service != BT_IDLE) {
+ rtl_write_word(rtlpriv, 0x504, 0x0ccc);
+ rtl_write_byte(rtlpriv, 0x506, 0x54);
+ rtl_write_byte(rtlpriv, 0x507, 0x54);
+ } else {
+ rtl_write_byte(rtlpriv, 0x506, 0x00);
+ rtl_write_byte(rtlpriv, 0x507, 0x00);
+ }
+
+ rtl_write_byte(rtlpriv, 0x4fd, bt_state);
+ return true;
+ }
+ }
+
+ return false;
+
+}
+
+static bool rtl92c_bt_wifi_connect_change(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ static bool media_connect;
+
+ if (rtlpriv->mac80211.link_state < MAC80211_LINKED) {
+ media_connect = false;
+ } else {
+ if (!media_connect) {
+ media_connect = true;
+ return true;
+ }
+ media_connect = true;
+ }
+
+ return false;
+}
+
+static void rtl92c_bt_set_normal(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+
+ if (rtlpcipriv->bt_coexist.bt_service == BT_OTHERBUSY) {
+ rtlpcipriv->bt_coexist.bt_edca_ul = 0x5ea72b;
+ rtlpcipriv->bt_coexist.bt_edca_dl = 0x5ea72b;
+ } else if (rtlpcipriv->bt_coexist.bt_service == BT_BUSY) {
+ rtlpcipriv->bt_coexist.bt_edca_ul = 0x5eb82f;
+ rtlpcipriv->bt_coexist.bt_edca_dl = 0x5eb82f;
+ } else if (rtlpcipriv->bt_coexist.bt_service == BT_SCO) {
+ if (rtlpcipriv->bt_coexist.ratio_tx > 160) {
+ rtlpcipriv->bt_coexist.bt_edca_ul = 0x5ea72f;
+ rtlpcipriv->bt_coexist.bt_edca_dl = 0x5ea72f;
+ } else {
+ rtlpcipriv->bt_coexist.bt_edca_ul = 0x5ea32b;
+ rtlpcipriv->bt_coexist.bt_edca_dl = 0x5ea42b;
+ }
+ } else {
+ rtlpcipriv->bt_coexist.bt_edca_ul = 0;
+ rtlpcipriv->bt_coexist.bt_edca_dl = 0;
+ }
+
+ if ((rtlpcipriv->bt_coexist.bt_service != BT_IDLE) &&
+ (rtlpriv->mac80211.mode == WIRELESS_MODE_G ||
+ (rtlpriv->mac80211.mode == (WIRELESS_MODE_G | WIRELESS_MODE_B))) &&
+ (rtlpcipriv->bt_coexist.bt_rssi_state &
+ BT_RSSI_STATE_BG_EDCA_LOW)) {
+ rtlpcipriv->bt_coexist.bt_edca_ul = 0x5eb82b;
+ rtlpcipriv->bt_coexist.bt_edca_dl = 0x5eb82b;
+ }
+}
+
+static void rtl92c_bt_ant_isolation(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+
+ /* Only enable HW BT coexist when BT in "Busy" state. */
+ if (rtlpriv->mac80211.vendor == PEER_CISCO &&
+ rtlpcipriv->bt_coexist.bt_service == BT_OTHER_ACTION) {
+ rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0);
+ } else {
+ if ((rtlpcipriv->bt_coexist.bt_service == BT_BUSY) &&
+ (rtlpcipriv->bt_coexist.bt_rssi_state &
+ BT_RSSI_STATE_NORMAL_POWER)) {
+ rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0);
+ } else if ((rtlpcipriv->bt_coexist.bt_service ==
+ BT_OTHER_ACTION) && (rtlpriv->mac80211.mode <
+ WIRELESS_MODE_N_24G) &&
+ (rtlpcipriv->bt_coexist.bt_rssi_state &
+ BT_RSSI_STATE_SPECIAL_LOW)) {
+ rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0);
+ } else if (rtlpcipriv->bt_coexist.bt_service == BT_PAN) {
+ rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00);
+ } else {
+ rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00);
+ }
+ }
+
+ if (rtlpcipriv->bt_coexist.bt_service == BT_PAN)
+ rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x10100);
+ else
+ rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x0);
+
+ if (rtlpcipriv->bt_coexist.bt_rssi_state &
+ BT_RSSI_STATE_NORMAL_POWER) {
+ rtl92c_bt_set_normal(hw);
+ } else {
+ rtlpcipriv->bt_coexist.bt_edca_ul = 0;
+ rtlpcipriv->bt_coexist.bt_edca_dl = 0;
+ }
+
+ if (rtlpcipriv->bt_coexist.bt_service != BT_IDLE) {
+ rtlpriv->cfg->ops->set_rfreg(hw,
+ RF90_PATH_A,
+ 0x1e,
+ 0xf0, 0xf);
+ } else {
+ rtlpriv->cfg->ops->set_rfreg(hw,
+ RF90_PATH_A, 0x1e, 0xf0,
+ rtlpcipriv->bt_coexist.bt_rfreg_origin_1e);
+ }
+
+ if (!rtlpriv->dm.dynamic_txpower_enable) {
+ if (rtlpcipriv->bt_coexist.bt_service != BT_IDLE) {
+ if (rtlpcipriv->bt_coexist.bt_rssi_state &
+ BT_RSSI_STATE_TXPOWER_LOW) {
+ rtlpriv->dm.dynamic_txhighpower_lvl =
+ TXHIGHPWRLEVEL_BT2;
+ } else {
+ rtlpriv->dm.dynamic_txhighpower_lvl =
+ TXHIGHPWRLEVEL_BT1;
+ }
+ } else {
+ rtlpriv->dm.dynamic_txhighpower_lvl =
+ TXHIGHPWRLEVEL_NORMAL;
+ }
+ rtl92c_phy_set_txpower_level(hw,
+ rtlpriv->phy.current_channel);
+ }
+}
+
+static void rtl92c_check_bt_change(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+ if (rtlpcipriv->bt_coexist.bt_cur_state) {
+ if (rtlpcipriv->bt_coexist.bt_ant_isolation)
+ rtl92c_bt_ant_isolation(hw);
+ } else {
+ rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0x00);
+ rtlpriv->cfg->ops->set_rfreg(hw, RF90_PATH_A, 0x1e, 0xf0,
+ rtlpcipriv->bt_coexist.bt_rfreg_origin_1e);
+
+ rtlpcipriv->bt_coexist.bt_edca_ul = 0;
+ rtlpcipriv->bt_coexist.bt_edca_dl = 0;
+ }
+}
+
+void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw)
+{
+ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+ bool wifi_connect_change;
+ bool bt_state_change;
+ bool rssi_state_change;
+
+ if ((rtlpcipriv->bt_coexist.bt_coexistence) &&
+ (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) {
+
+ wifi_connect_change = rtl92c_bt_wifi_connect_change(hw);
+ bt_state_change = rtl92c_bt_state_change(hw);
+ rssi_state_change = rtl92c_bt_rssi_state_change(hw);
+
+ if (wifi_connect_change || bt_state_change || rssi_state_change)
+ rtl92c_check_bt_change(hw);
+ }
+}
+EXPORT_SYMBOL(rtl92c_dm_bt_coexist);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h
index b9cbb0a3c03f..b9736d3e9a39 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h
@@ -200,5 +200,7 @@ void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal);
void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta);
void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw);
void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery);
+void rtl92c_dm_dynamic_txpower(struct ieee80211_hw *hw);
+void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw);
#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
index 28a6ce3bc239..50303e1adff1 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
@@ -171,7 +171,6 @@ static void _rtl92c_write_fw(struct ieee80211_hw *hw,
static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- int err = -EIO;
u32 counter = 0;
u32 value32;
@@ -184,7 +183,7 @@ static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
("chksum report faill ! REG_MCUFWDL:0x%08x .\n",
value32));
- goto exit;
+ return -EIO;
}
RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
@@ -204,8 +203,7 @@ static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw)
("Polling FW ready success!!"
" REG_MCUFWDL:0x%08x .\n",
value32));
- err = 0;
- goto exit;
+ return 0;
}
mdelay(FW_8192C_POLLING_DELAY);
@@ -214,9 +212,7 @@ static int _rtl92c_fw_free_to_go(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
("Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32));
-
-exit:
- return err;
+ return -EIO;
}
int rtl92c_download_fw(struct ieee80211_hw *hw)
@@ -226,32 +222,16 @@ int rtl92c_download_fw(struct ieee80211_hw *hw)
struct rtl92c_firmware_header *pfwheader;
u8 *pfwdata;
u32 fwsize;
- int err;
enum version_8192c version = rtlhal->version;
- const struct firmware *firmware;
- printk(KERN_INFO "rtl8192cu: Loading firmware file %s\n",
+ printk(KERN_INFO "rtl8192c: Loading firmware file %s\n",
rtlpriv->cfg->fw_name);
- err = request_firmware(&firmware, rtlpriv->cfg->fw_name,
- rtlpriv->io.dev);
- if (err) {
- printk(KERN_ERR "rtl8192cu: Firmware loading failed\n");
- return 1;
- }
-
- if (firmware->size > 0x4000) {
- RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
- ("Firmware is too big!\n"));
- release_firmware(firmware);
+ if (!rtlhal->pfirmware)
return 1;
- }
-
- memcpy(rtlhal->pfirmware, firmware->data, firmware->size);
- fwsize = firmware->size;
- release_firmware(firmware);
pfwheader = (struct rtl92c_firmware_header *)rtlhal->pfirmware;
pfwdata = (u8 *) rtlhal->pfirmware;
+ fwsize = rtlhal->fwsize;
if (IS_FW_HEADER_EXIST(pfwheader)) {
RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
@@ -267,8 +247,7 @@ int rtl92c_download_fw(struct ieee80211_hw *hw)
_rtl92c_write_fw(hw, version, pfwdata, fwsize);
_rtl92c_enable_fw_download(hw, false);
- err = _rtl92c_fw_free_to_go(hw);
- if (err) {
+ if (_rtl92c_fw_free_to_go(hw)) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
("Firmware is not ready to run!\n"));
} else {
@@ -300,10 +279,9 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
u8 boxnum;
- u16 box_reg, box_extreg;
+ u16 box_reg = 0, box_extreg = 0;
u8 u1b_tmp;
bool isfw_read = false;
- u8 buf_index = 0;
bool bwrite_sucess = false;
u8 wait_h2c_limmit = 100;
u8 wait_writeh2c_limmit = 100;
@@ -414,7 +392,7 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
case 1:
boxcontent[0] &= ~(BIT(7));
memcpy((u8 *) (boxcontent) + 1,
- p_cmdbuffer + buf_index, 1);
+ p_cmdbuffer, 1);
for (idx = 0; idx < 4; idx++) {
rtl_write_byte(rtlpriv, box_reg + idx,
@@ -424,7 +402,7 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
case 2:
boxcontent[0] &= ~(BIT(7));
memcpy((u8 *) (boxcontent) + 1,
- p_cmdbuffer + buf_index, 2);
+ p_cmdbuffer, 2);
for (idx = 0; idx < 4; idx++) {
rtl_write_byte(rtlpriv, box_reg + idx,
@@ -434,7 +412,7 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
case 3:
boxcontent[0] &= ~(BIT(7));
memcpy((u8 *) (boxcontent) + 1,
- p_cmdbuffer + buf_index, 3);
+ p_cmdbuffer, 3);
for (idx = 0; idx < 4; idx++) {
rtl_write_byte(rtlpriv, box_reg + idx,
@@ -444,9 +422,9 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
case 4:
boxcontent[0] |= (BIT(7));
memcpy((u8 *) (boxextcontent),
- p_cmdbuffer + buf_index, 2);
+ p_cmdbuffer, 2);
memcpy((u8 *) (boxcontent) + 1,
- p_cmdbuffer + buf_index + 2, 2);
+ p_cmdbuffer + 2, 2);
for (idx = 0; idx < 2; idx++) {
rtl_write_byte(rtlpriv, box_extreg + idx,
@@ -461,9 +439,9 @@ static void _rtl92c_fill_h2c_command(struct ieee80211_hw *hw,
case 5:
boxcontent[0] |= (BIT(7));
memcpy((u8 *) (boxextcontent),
- p_cmdbuffer + buf_index, 2);
+ p_cmdbuffer, 2);
memcpy((u8 *) (boxcontent) + 1,
- p_cmdbuffer + buf_index + 2, 3);
+ p_cmdbuffer + 2, 3);
for (idx = 0; idx < 2; idx++) {
rtl_write_byte(rtlpriv, box_extreg + idx,
@@ -561,6 +539,39 @@ void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
}
EXPORT_SYMBOL(rtl92c_set_fw_pwrmode_cmd);
+static bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw,
+ struct sk_buff *skb)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl8192_tx_ring *ring;
+ struct rtl_tx_desc *pdesc;
+ u8 own;
+ unsigned long flags;
+ struct sk_buff *pskb = NULL;
+
+ ring = &rtlpci->tx_ring[BEACON_QUEUE];
+
+ pskb = __skb_dequeue(&ring->queue);
+ if (pskb)
+ kfree_skb(pskb);
+
+ spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
+
+ pdesc = &ring->desc[0];
+ own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN);
+
+ rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
+
+ __skb_queue_tail(&ring->queue, skb);
+
+ spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
+
+ rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
+
+ return true;
+}
+
#define BEACON_PG 0 /*->1*/
#define PSPOLL_PG 2
#define NULL_PG 3
@@ -678,7 +689,7 @@ static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
-void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
+void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
@@ -687,12 +698,12 @@ void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
u32 totalpacketlen;
bool rtstatus;
u8 u1RsvdPageLoc[3] = {0};
- bool b_dlok = false;
+ bool dlok = false;
u8 *beacon;
- u8 *p_pspoll;
+ u8 *pspoll;
u8 *nullfunc;
- u8 *p_probersp;
+ u8 *probersp;
/*---------------------------------------------------------
(1) beacon
---------------------------------------------------------*/
@@ -703,10 +714,10 @@ void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
/*-------------------------------------------------------
(2) ps-poll
--------------------------------------------------------*/
- p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
- SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
- SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
- SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
+ pspoll = &reserved_page_packet[PSPOLL_PG * 128];
+ SET_80211_PS_POLL_AID(pspoll, (mac->assoc_id | 0xc000));
+ SET_80211_PS_POLL_BSSID(pspoll, mac->bssid);
+ SET_80211_PS_POLL_TA(pspoll, mac->mac_addr);
SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
@@ -723,10 +734,10 @@ void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
/*---------------------------------------------------------
(4) probe response
----------------------------------------------------------*/
- p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
- SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
- SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
- SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
+ probersp = &reserved_page_packet[PROBERSP_PG * 128];
+ SET_80211_HDR_ADDRESS1(probersp, mac->bssid);
+ SET_80211_HDR_ADDRESS2(probersp, mac->mac_addr);
+ SET_80211_HDR_ADDRESS3(probersp, mac->bssid);
SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
@@ -744,12 +755,12 @@ void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
memcpy((u8 *) skb_put(skb, totalpacketlen),
&reserved_page_packet, totalpacketlen);
- rtstatus = rtlpriv->cfg->ops->cmd_send_packet(hw, skb);
+ rtstatus = _rtl92c_cmd_send_packet(hw, skb);
if (rtstatus)
- b_dlok = true;
+ dlok = true;
- if (b_dlok) {
+ if (dlok) {
RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
("Set RSVD page location to Fw.\n"));
RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h
index 3db33bd14666..3d5823c12621 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h
@@ -27,8 +27,8 @@
*
*****************************************************************************/
-#ifndef __RTL92C__FW__H__
-#define __RTL92C__FW__H__
+#ifndef __RTL92C__FW__COMMON__H__
+#define __RTL92C__FW__COMMON__H__
#define FW_8192C_SIZE 0x3000
#define FW_8192C_START_ADDRESS 0x1000
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c
index a70228278398..d2cc81586a6a 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c
@@ -78,27 +78,29 @@ void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw,
RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x),"
" data(%#x)\n", regaddr, bitmask,
data));
+
}
EXPORT_SYMBOL(rtl92c_phy_set_bb_reg);
u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw,
- enum radio_path rfpath, u32 offset)
+ enum radio_path rfpath, u32 offset)
{
RT_ASSERT(false, ("deprecated!\n"));
return 0;
+
}
EXPORT_SYMBOL(_rtl92c_phy_fw_rf_serial_read);
void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw,
- enum radio_path rfpath, u32 offset,
- u32 data)
+ enum radio_path rfpath, u32 offset,
+ u32 data)
{
RT_ASSERT(false, ("deprecated!\n"));
}
EXPORT_SYMBOL(_rtl92c_phy_fw_rf_serial_write);
u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw,
- enum radio_path rfpath, u32 offset)
+ enum radio_path rfpath, u32 offset)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
@@ -149,8 +151,8 @@ u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw,
EXPORT_SYMBOL(_rtl92c_phy_rf_serial_read);
void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw,
- enum radio_path rfpath, u32 offset,
- u32 data)
+ enum radio_path rfpath, u32 offset,
+ u32 data)
{
u32 data_and_addr;
u32 newoffset;
@@ -197,6 +199,7 @@ static void _rtl92c_phy_bb_config_1t(struct ieee80211_hw *hw)
rtl_set_bbreg(hw, 0xe80, 0x0c000000, 0x2);
rtl_set_bbreg(hw, 0xe88, 0x0c000000, 0x2);
}
+
bool rtl92c_phy_rf_config(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -241,13 +244,14 @@ bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw)
rtlphy->cck_high_power = (bool) (rtl_get_bbreg(hw,
RFPGA0_XA_HSSIPARAMETER2,
0x200));
+
return true;
}
EXPORT_SYMBOL(_rtl92c_phy_bb8192c_config_parafile);
void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw,
- u32 regaddr, u32 bitmask,
- u32 data)
+ u32 regaddr, u32 bitmask,
+ u32 data)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
@@ -317,61 +321,48 @@ void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw,
}
if (regaddr == RTXAGC_B_RATE54_24) {
rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][9] = data;
-
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
("MCSTxPowerLevelOriginalOffset[%d][9] = 0x%x\n",
rtlphy->pwrgroup_cnt,
rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][9]));
}
-
if (regaddr == RTXAGC_B_CCK1_55_MCS32) {
rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][14] = data;
-
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
("MCSTxPowerLevelOriginalOffset[%d][14] = 0x%x\n",
rtlphy->pwrgroup_cnt,
rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][14]));
}
-
if (regaddr == RTXAGC_B_CCK11_A_CCK2_11 && bitmask == 0x000000ff) {
rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][15] = data;
-
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
("MCSTxPowerLevelOriginalOffset[%d][15] = 0x%x\n",
rtlphy->pwrgroup_cnt,
rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][15]));
}
-
if (regaddr == RTXAGC_B_MCS03_MCS00) {
rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][10] = data;
-
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
("MCSTxPowerLevelOriginalOffset[%d][10] = 0x%x\n",
rtlphy->pwrgroup_cnt,
rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][10]));
}
-
if (regaddr == RTXAGC_B_MCS07_MCS04) {
rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][11] = data;
-
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
("MCSTxPowerLevelOriginalOffset[%d][11] = 0x%x\n",
rtlphy->pwrgroup_cnt,
rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][11]));
}
-
if (regaddr == RTXAGC_B_MCS11_MCS08) {
rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][12] = data;
-
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
("MCSTxPowerLevelOriginalOffset[%d][12] = 0x%x\n",
rtlphy->pwrgroup_cnt,
rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][12]));
}
-
if (regaddr == RTXAGC_B_MCS15_MCS12) {
rtlphy->MCS_TXPWR[rtlphy->pwrgroup_cnt][13] = data;
-
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
("MCSTxPowerLevelOriginalOffset[%d][13] = 0x%x\n",
rtlphy->pwrgroup_cnt,
@@ -583,6 +574,7 @@ static void _rtl92c_ccxpower_index_check(struct ieee80211_hw *hw,
rtlphy->cur_cck_txpwridx = cckpowerlevel[0];
rtlphy->cur_ofdm24g_txpwridx = ofdmpowerlevel[0];
+
}
void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel)
@@ -611,7 +603,6 @@ bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, long power_indbm)
struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
u8 idx;
u8 rf_path;
-
u8 ccktxpwridx = _rtl92c_phy_dbm_to_txpwr_Idx(hw,
WIRELESS_MODE_B,
power_indbm);
@@ -639,11 +630,6 @@ bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw, long power_indbm)
}
EXPORT_SYMBOL(rtl92c_phy_update_txpower_dbm);
-void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw, u16 beaconinterval)
-{
-}
-EXPORT_SYMBOL(rtl92c_phy_set_beacon_hw_reg);
-
u8 _rtl92c_phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw,
enum wireless_mode wirelessmode,
long power_indbm)
@@ -741,9 +727,9 @@ void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw,
if (rtlphy->set_bwmode_inprogress)
return;
rtlphy->set_bwmode_inprogress = true;
- if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw)))
+ if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) {
rtlpriv->cfg->ops->phy_set_bw_mode_callback(hw);
- else {
+ } else {
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
("FALSE driver sleep or unload\n"));
rtlphy->set_bwmode_inprogress = false;
@@ -773,8 +759,9 @@ void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw)
mdelay(delay);
else
continue;
- } else
+ } else {
rtlphy->sw_chnl_inprogress = false;
+ }
break;
} while (true);
RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n"));
@@ -811,9 +798,32 @@ u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw)
}
EXPORT_SYMBOL(rtl92c_phy_sw_chnl);
-static bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
- u8 channel, u8 *stage, u8 *step,
- u32 *delay)
+static bool _rtl92c_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
+ u32 cmdtableidx, u32 cmdtablesz,
+ enum swchnlcmd_id cmdid,
+ u32 para1, u32 para2, u32 msdelay)
+{
+ struct swchnlcmd *pcmd;
+
+ if (cmdtable == NULL) {
+ RT_ASSERT(false, ("cmdtable cannot be NULL.\n"));
+ return false;
+ }
+
+ if (cmdtableidx >= cmdtablesz)
+ return false;
+
+ pcmd = cmdtable + cmdtableidx;
+ pcmd->cmdid = cmdid;
+ pcmd->para1 = para1;
+ pcmd->para2 = para2;
+ pcmd->msdelay = msdelay;
+ return true;
+}
+
+bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
+ u8 channel, u8 *stage, u8 *step,
+ u32 *delay)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
@@ -917,29 +927,6 @@ static bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
return false;
}
-static bool _rtl92c_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
- u32 cmdtableidx, u32 cmdtablesz,
- enum swchnlcmd_id cmdid,
- u32 para1, u32 para2, u32 msdelay)
-{
- struct swchnlcmd *pcmd;
-
- if (cmdtable == NULL) {
- RT_ASSERT(false, ("cmdtable cannot be NULL.\n"));
- return false;
- }
-
- if (cmdtableidx >= cmdtablesz)
- return false;
-
- pcmd = cmdtable + cmdtableidx;
- pcmd->cmdid = cmdid;
- pcmd->para1 = para1;
- pcmd->para2 = para2;
- pcmd->msdelay = msdelay;
- return true;
-}
-
bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, u32 rfpath)
{
return true;
@@ -1002,13 +989,13 @@ static u8 _rtl92c_phy_path_b_iqk(struct ieee80211_hw *hw)
reg_ebc = rtl_get_bbreg(hw, 0xebc, MASKDWORD);
reg_ec4 = rtl_get_bbreg(hw, 0xec4, MASKDWORD);
reg_ecc = rtl_get_bbreg(hw, 0xecc, MASKDWORD);
+
if (!(reg_eac & BIT(31)) &&
(((reg_eb4 & 0x03FF0000) >> 16) != 0x142) &&
(((reg_ebc & 0x03FF0000) >> 16) != 0x42))
result |= 0x01;
else
return result;
-
if (!(reg_eac & BIT(30)) &&
(((reg_ec4 & 0x03FF0000) >> 16) != 0x132) &&
(((reg_ecc & 0x03FF0000) >> 16) != 0x36))
@@ -1023,9 +1010,9 @@ static void _rtl92c_phy_path_a_fill_iqk_matrix(struct ieee80211_hw *hw,
u32 oldval_0, x, tx0_a, reg;
long y, tx0_c;
- if (final_candidate == 0xFF)
+ if (final_candidate == 0xFF) {
return;
- else if (iqk_ok) {
+ } else if (iqk_ok) {
oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE,
MASKDWORD) >> 22) & 0x3FF;
x = result[final_candidate][0];
@@ -1063,9 +1050,9 @@ static void _rtl92c_phy_path_b_fill_iqk_matrix(struct ieee80211_hw *hw,
u32 oldval_1, x, tx1_a, reg;
long y, tx1_c;
- if (final_candidate == 0xFF)
+ if (final_candidate == 0xFF) {
return;
- else if (iqk_ok) {
+ } else if (iqk_ok) {
oldval_1 = (rtl_get_bbreg(hw, ROFDM0_XBTXIQIMBALANCE,
MASKDWORD) >> 22) & 0x3FF;
x = result[final_candidate][4];
@@ -1282,6 +1269,7 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw,
RFPGA0_XA_HSSIPARAMETER1,
BIT(8));
}
+
if (!rtlphy->rfpi_enable)
_rtl92c_phy_pi_mode_switch(hw, true);
if (t == 0) {
@@ -1317,9 +1305,10 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw,
0x3FF0000) >> 16;
break;
} else if (i == (retrycount - 1) && patha_ok == 0x01)
+
result[t][0] = (rtl_get_bbreg(hw, 0xe94,
MASKDWORD) & 0x3FF0000) >>
- 16;
+ 16;
result[t][1] =
(rtl_get_bbreg(hw, 0xe9c, MASKDWORD) & 0x3FF0000) >> 16;
@@ -1375,8 +1364,7 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw,
static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw,
char delta, bool is2t)
{
- /* This routine is deliberately dummied out for later fixes */
-#if 0
+#if 0 /* This routine is deliberately dummied out for later fixes */
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
@@ -1434,7 +1422,7 @@ static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw,
0x04db25a4, 0x0b1b25a4
};
- u32 apk_offset[PATH_NUM] = { 0xb68, 0xb6c };
+ const u32 apk_offset[PATH_NUM] = { 0xb68, 0xb6c };
u32 apk_normal_offset[PATH_NUM] = { 0xb28, 0xb98 };
@@ -1463,13 +1451,15 @@ static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw,
0x00050006
};
- const u32 apk_result[PATH_NUM][APK_BB_REG_NUM];
+ u32 apk_result[PATH_NUM][APK_BB_REG_NUM];
long bb_offset, delta_v, delta_offset;
if (!is2t)
pathbound = 1;
+ return;
+
for (index = 0; index < PATH_NUM; index++) {
apk_offset[index] = apk_normal_offset[index];
apk_value[index] = apk_normal_value[index];
@@ -1730,8 +1720,7 @@ static void _rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw,
0x08));
}
-
- rtlphy->apk_done = true;
+ rtlphy->b_apk_done = true;
#endif
}
@@ -1758,6 +1747,7 @@ static void _rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw,
rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, 0x300, 0x1);
}
+
}
#undef IQK_ADDA_REG_NUM
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h
index 53ffb0981586..9a264c0d6127 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h
@@ -27,8 +27,8 @@
*
*****************************************************************************/
-#ifndef __RTL92C_PHY_H__
-#define __RTL92C_PHY_H__
+#ifndef __RTL92C_PHY_COMMON_H__
+#define __RTL92C_PHY_COMMON_H__
#define MAX_PRECMD_CNT 16
#define MAX_RFDEPENDCMD_CNT 16
@@ -39,6 +39,7 @@
#define RT_CANNOT_IO(hw) false
#define HIGHPOWER_RADIOA_ARRAYLEN 22
+#define IQK_ADDA_REG_NUM 16
#define MAX_TOLERANCE 5
#define IQK_DELAY_TIME 1
@@ -56,6 +57,7 @@
#define IQK_ADDA_REG_NUM 16
#define IQK_MAC_REG_NUM 4
+#define IQK_DELAY_TIME 1
#define RF90_PATH_MAX 2
#define CT_OFFSET_MAC_ADDR 0X16
@@ -77,6 +79,7 @@
#define RTL92C_MAX_PATH_NUM 2
#define LLT_LAST_ENTRY_OF_TX_PKT_BUFFER 255
+
enum swchnlcmd_id {
CMDID_END,
CMDID_SET_TXPOWEROWER_LEVEL,
@@ -184,45 +187,41 @@ struct tx_power_struct {
u32 mcs_original_offset[4][16];
};
-extern u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw,
+u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw,
u32 regaddr, u32 bitmask);
-extern void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw,
+void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw,
u32 regaddr, u32 bitmask, u32 data);
-extern u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw,
+u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw,
enum radio_path rfpath, u32 regaddr,
u32 bitmask);
-extern void rtl92c_phy_set_rf_reg(struct ieee80211_hw *hw,
- enum radio_path rfpath, u32 regaddr,
- u32 bitmask, u32 data);
-extern bool rtl92c_phy_mac_config(struct ieee80211_hw *hw);
-extern bool rtl92c_phy_bb_config(struct ieee80211_hw *hw);
-extern bool rtl92c_phy_rf_config(struct ieee80211_hw *hw);
-extern bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw,
+bool rtl92c_phy_mac_config(struct ieee80211_hw *hw);
+bool rtl92c_phy_bb_config(struct ieee80211_hw *hw);
+bool rtl92c_phy_rf_config(struct ieee80211_hw *hw);
+bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw,
enum radio_path rfpath);
-extern void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw);
-extern void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw,
+void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw);
+void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw,
long *powerlevel);
-extern void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel);
-extern bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw,
+void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel);
+bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw,
long power_indbm);
-extern void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw,
+void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw,
u8 operation);
-extern void rtl92c_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
-extern void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw,
+void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw,
enum nl80211_channel_type ch_type);
-extern void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw);
-extern u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw);
-extern void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery);
-extern void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw,
+void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw);
+u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw);
+void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery);
+void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw,
u16 beaconinterval);
void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta);
void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw);
void rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain);
bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
enum radio_path rfpath);
-extern bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw,
+bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw,
u32 rfpath);
-extern bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw,
+bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw,
enum rf_pwrstate rfpwr_state);
void rtl92ce_phy_set_rf_on(struct ieee80211_hw *hw);
void rtl92c_phy_set_io(struct ieee80211_hw *hw);
@@ -235,12 +234,25 @@ u8 _rtl92c_phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw,
enum wireless_mode wirelessmode,
long power_indbm);
void _rtl92c_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw);
-static bool _rtl92c_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
- u32 cmdtableidx, u32 cmdtablesz,
- enum swchnlcmd_id cmdid, u32 para1,
- u32 para2, u32 msdelay);
-static bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
- u8 channel, u8 *stage, u8 *step,
- u32 *delay);
+void _rtl92c_phy_set_rf_sleep(struct ieee80211_hw *hw);
+bool _rtl92c_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
+ u8 channel, u8 *stage, u8 *step,
+ u32 *delay);
+u8 rtl92c_bt_rssi_state_change(struct ieee80211_hw *hw);
+u32 _rtl92c_phy_fw_rf_serial_read(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 offset);
+void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 offset,
+ u32 data);
+u32 _rtl92c_phy_rf_serial_read(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 offset);
+void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 offset,
+ u32 data);
+bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw);
+void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw,
+ u32 regaddr, u32 bitmask,
+ u32 data);
+bool rtl92c_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype);
#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h
index 2f577c8828fc..35ff7df41a1d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/def.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/def.h
@@ -121,19 +121,6 @@
#define CHIP_92C 0x01
#define CHIP_88C 0x00
-/* Add vendor information into chip version definition.
- * Add UMC B-Cut and RTL8723 chip info definition.
- *
- * BIT 7 Reserved
- * BIT 6 UMC BCut
- * BIT 5 Manufacturer(TSMC/UMC)
- * BIT 4 TEST/NORMAL
- * BIT 3 8723 Version
- * BIT 2 8723?
- * BIT 1 1T2R?
- * BIT 0 88C/92C
-*/
-
enum version_8192c {
VERSION_A_CHIP_92C = 0x01,
VERSION_A_CHIP_88C = 0x00,
@@ -280,20 +267,6 @@ struct h2c_cmd_8192c {
u8 *p_cmdbuffer;
};
-static inline u8 _rtl92c_get_chnl_group(u8 chnl)
-{
- u8 group = 0;
-
- if (chnl < 3)
- group = 0;
- else if (chnl < 9)
- group = 1;
- else
- group = 2;
-
- return group;
-}
-
/* NOTE: reference to rtl8192c_rates struct */
static inline int _rtl92c_rate_mapping(struct ieee80211_hw *hw, bool isHT,
u8 desc_rate, bool first_ampdu)
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c
index 7d76504df4d1..2df33e53e15a 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c
@@ -29,10 +29,12 @@
#include "../wifi.h"
#include "../base.h"
+#include "../pci.h"
#include "reg.h"
#include "def.h"
#include "phy.h"
#include "dm.h"
+#include "../rtl8192c/fw_common.h"
void rtl92ce_dm_dynamic_txpower(struct ieee80211_hw *hw)
{
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h
index 36302ebae4a3..07dd9552e82f 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h
@@ -192,6 +192,7 @@ void rtl92c_dm_init_edca_turbo(struct ieee80211_hw *hw);
void rtl92c_dm_check_txpower_tracking(struct ieee80211_hw *hw);
void rtl92c_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw);
void rtl92c_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal);
+void rtl92c_dm_bt_coexist(struct ieee80211_hw *hw);
void rtl92ce_dm_dynamic_txpower(struct ieee80211_hw *hw);
#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
index 05477f465a75..defb4370cf74 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
@@ -30,12 +30,14 @@
#include "../wifi.h"
#include "../efuse.h"
#include "../base.h"
+#include "../regd.h"
#include "../cam.h"
#include "../ps.h"
#include "../pci.h"
#include "reg.h"
#include "def.h"
#include "phy.h"
+#include "../rtl8192c/fw_common.h"
#include "dm.h"
#include "led.h"
#include "hw.h"
@@ -137,15 +139,6 @@ void rtl92ce_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
break;
}
- case HW_VAR_MGT_FILTER:
- *((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP0);
- break;
- case HW_VAR_CTRL_FILTER:
- *((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP1);
- break;
- case HW_VAR_DATA_FILTER:
- *((u16 *) (val)) = rtl_read_word(rtlpriv, REG_RXFLTMAP2);
- break;
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
("switch case not process\n"));
@@ -156,6 +149,7 @@ void rtl92ce_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
@@ -178,7 +172,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
rate_cfg |= 0x01;
rtl_write_byte(rtlpriv, REG_RRSR, rate_cfg & 0xff);
rtl_write_byte(rtlpriv, REG_RRSR + 1,
- (rate_cfg >> 8)&0xff);
+ (rate_cfg >> 8) & 0xff);
while (rate_cfg > 0x1) {
rate_cfg = (rate_cfg >> 1);
rate_index++;
@@ -276,13 +270,19 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
break;
}
case HW_VAR_AMPDU_FACTOR:{
- u8 regtoset_normal[4] = { 0x41, 0xa8, 0x72, 0xb9 };
+ u8 regtoset_normal[4] = {0x41, 0xa8, 0x72, 0xb9};
+ u8 regtoset_bt[4] = {0x31, 0x74, 0x42, 0x97};
u8 factor_toset;
u8 *p_regtoset = NULL;
u8 index = 0;
- p_regtoset = regtoset_normal;
+ if ((rtlpcipriv->bt_coexist.bt_coexistence) &&
+ (rtlpcipriv->bt_coexist.bt_coexist_type ==
+ BT_CSR_BC4))
+ p_regtoset = regtoset_bt;
+ else
+ p_regtoset = regtoset_normal;
factor_toset = *((u8 *) val);
if (factor_toset <= 3) {
@@ -317,45 +317,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
}
case HW_VAR_AC_PARAM:{
u8 e_aci = *((u8 *) val);
- u32 u4b_ac_param;
- u16 cw_min = le16_to_cpu(mac->ac[e_aci].cw_min);
- u16 cw_max = le16_to_cpu(mac->ac[e_aci].cw_max);
- u16 tx_op = le16_to_cpu(mac->ac[e_aci].tx_op);
-
- u4b_ac_param = (u32) mac->ac[e_aci].aifs;
- u4b_ac_param |= ((u32)cw_min
- & 0xF) << AC_PARAM_ECW_MIN_OFFSET;
- u4b_ac_param |= ((u32)cw_max &
- 0xF) << AC_PARAM_ECW_MAX_OFFSET;
- u4b_ac_param |= (u32)tx_op << AC_PARAM_TXOP_OFFSET;
-
- RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
- ("queue:%x, ac_param:%x\n", e_aci,
- u4b_ac_param));
-
- switch (e_aci) {
- case AC1_BK:
- rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM,
- u4b_ac_param);
- break;
- case AC0_BE:
- rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM,
- u4b_ac_param);
- break;
- case AC2_VI:
- rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM,
- u4b_ac_param);
- break;
- case AC3_VO:
- rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM,
- u4b_ac_param);
- break;
- default:
- RT_ASSERT(false,
- ("SetHwReg8185(): invalid aci: %d !\n",
- e_aci));
- break;
- }
+ rtl92c_dm_init_edca_turbo(hw);
if (rtlpci->acm_method != eAcmWay2_SW)
rtlpriv->cfg->ops->set_hw_reg(hw,
@@ -526,9 +488,6 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
case HW_VAR_CORRECT_TSF:{
u8 btype_ibss = ((u8 *) (val))[0];
- /*btype_ibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ?
- 1 : 0;*/
-
if (btype_ibss == true)
_rtl92ce_stop_tx_beacon(hw);
@@ -537,7 +496,7 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
rtl_write_dword(rtlpriv, REG_TSFTR,
(u32) (mac->tsf & 0xffffffff));
rtl_write_dword(rtlpriv, REG_TSFTR + 4,
- (u32) ((mac->tsf >> 32)&0xffffffff));
+ (u32) ((mac->tsf >> 32) & 0xffffffff));
_rtl92ce_set_bcn_ctrl_reg(hw, BIT(3), 0);
@@ -547,15 +506,6 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
break;
}
- case HW_VAR_MGT_FILTER:
- rtl_write_word(rtlpriv, REG_RXFLTMAP0, *(u16 *) val);
- break;
- case HW_VAR_CTRL_FILTER:
- rtl_write_word(rtlpriv, REG_RXFLTMAP1, *(u16 *) val);
- break;
- case HW_VAR_DATA_FILTER:
- rtl_write_word(rtlpriv, REG_RXFLTMAP2, *(u16 *) val);
- break;
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("switch case "
"not process\n"));
@@ -679,12 +629,12 @@ static void _rtl92ce_gen_refresh_led_state(struct ieee80211_hw *hw)
rtl92ce_sw_led_on(hw, pLed0);
else
rtl92ce_sw_led_off(hw, pLed0);
-
}
static bool _rtl92ce_init_mac(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
@@ -693,9 +643,22 @@ static bool _rtl92ce_init_mac(struct ieee80211_hw *hw)
u16 retry;
rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00);
+ if (rtlpcipriv->bt_coexist.bt_coexistence) {
+ u32 value32;
+ value32 = rtl_read_dword(rtlpriv, REG_APS_FSMCO);
+ value32 |= (SOP_ABG | SOP_AMB | XOP_BTCK);
+ rtl_write_dword(rtlpriv, REG_APS_FSMCO, value32);
+ }
rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b);
rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL, 0x0F);
+ if (rtlpcipriv->bt_coexist.bt_coexistence) {
+ u32 u4b_tmp = rtl_read_dword(rtlpriv, REG_AFE_XTAL_CTRL);
+
+ u4b_tmp &= (~0x00024800);
+ rtl_write_dword(rtlpriv, REG_AFE_XTAL_CTRL, u4b_tmp);
+ }
+
bytetmp = rtl_read_byte(rtlpriv, REG_APS_FSMCO + 1) | BIT(0);
udelay(2);
@@ -726,10 +689,15 @@ static bool _rtl92ce_init_mac(struct ieee80211_hw *hw)
rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, 0x82);
udelay(2);
+ if (rtlpcipriv->bt_coexist.bt_coexistence) {
+ bytetmp = rtl_read_byte(rtlpriv, REG_AFE_XTAL_CTRL+2) & 0xfd;
+ rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL+2, bytetmp);
+ }
+
rtl_write_word(rtlpriv, REG_CR, 0x2ff);
if (_rtl92ce_llt_table_init(hw) == false)
- return false;;
+ return false;
rtl_write_dword(rtlpriv, REG_HISR, 0xffffffff);
rtl_write_byte(rtlpriv, REG_HISRE, 0xff);
@@ -786,13 +754,14 @@ static bool _rtl92ce_init_mac(struct ieee80211_hw *hw)
rtl_write_dword(rtlpriv, REG_MCUTST_1, 0x0);
- return true;;
+ return true;
}
static void _rtl92ce_hw_configure(struct ieee80211_hw *hw)
{
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
u8 reg_bw_opmode;
u32 reg_ratr, reg_prsr;
@@ -824,7 +793,11 @@ static void _rtl92ce_hw_configure(struct ieee80211_hw *hw)
rtl_write_dword(rtlpriv, REG_RARFRC, 0x01000000);
rtl_write_dword(rtlpriv, REG_RARFRC + 4, 0x07060504);
- rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0xb972a841);
+ if ((rtlpcipriv->bt_coexist.bt_coexistence) &&
+ (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4))
+ rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0x97427431);
+ else
+ rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0xb972a841);
rtl_write_byte(rtlpriv, REG_ATIMWND, 0x2);
@@ -840,11 +813,20 @@ static void _rtl92ce_hw_configure(struct ieee80211_hw *hw)
rtl_write_byte(rtlpriv, REG_PIFS, 0x1C);
rtl_write_byte(rtlpriv, REG_AGGR_BREAK_TIME, 0x16);
- rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020);
-
- rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020);
+ if ((rtlpcipriv->bt_coexist.bt_coexistence) &&
+ (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) {
+ rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020);
+ rtl_write_word(rtlpriv, REG_PROT_MODE_CTRL, 0x0402);
+ } else {
+ rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020);
+ rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020);
+ }
- rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x086666);
+ if ((rtlpcipriv->bt_coexist.bt_coexistence) &&
+ (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4))
+ rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x03086666);
+ else
+ rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x086666);
rtl_write_byte(rtlpriv, REG_ACKTO, 0x40);
@@ -948,8 +930,8 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)
}
rtlhal->last_hmeboxnum = 0;
- rtl92ce_phy_mac_config(hw);
- rtl92ce_phy_bb_config(hw);
+ rtl92c_phy_mac_config(hw);
+ rtl92c_phy_bb_config(hw);
rtlphy->rf_mode = RF_OP_BY_SW_3WIRE;
rtl92c_phy_rf_config(hw);
rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0,
@@ -962,15 +944,20 @@ int rtl92ce_hw_init(struct ieee80211_hw *hw)
_rtl92ce_hw_configure(hw);
rtl_cam_reset_all_entry(hw);
rtl92ce_enable_hw_security_config(hw);
+
ppsc->rfpwr_state = ERFON;
+
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr);
_rtl92ce_enable_aspm_back_door(hw);
rtlpriv->intf_ops->enable_aspm(hw);
+
+ rtl8192ce_bt_hw_init(hw);
+
if (ppsc->rfpwr_state == ERFON) {
rtl92c_phy_set_rfpath_switch(hw, 1);
- if (iqk_initialized)
+ if (iqk_initialized) {
rtl92c_phy_iq_calibrate(hw, true);
- else {
+ } else {
rtl92c_phy_iq_calibrate(hw, false);
iqk_initialized = true;
}
@@ -1128,75 +1115,62 @@ static int _rtl92ce_set_media_status(struct ieee80211_hw *hw,
return 0;
}
-static void _rtl92ce_set_check_bssid(struct ieee80211_hw *hw,
- enum nl80211_iftype type)
+void rtl92ce_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 reg_rcr = rtl_read_dword(rtlpriv, REG_RCR);
- u8 filterout_non_associated_bssid = false;
- switch (type) {
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_STATION:
- filterout_non_associated_bssid = true;
- break;
- case NL80211_IFTYPE_UNSPECIFIED:
- case NL80211_IFTYPE_AP:
- default:
- break;
- }
+ if (rtlpriv->psc.rfpwr_state != ERFON)
+ return;
- if (filterout_non_associated_bssid == true) {
+ if (check_bssid == true) {
reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN);
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR,
(u8 *) (&reg_rcr));
_rtl92ce_set_bcn_ctrl_reg(hw, 0, BIT(4));
- } else if (filterout_non_associated_bssid == false) {
+ } else if (check_bssid == false) {
reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN));
_rtl92ce_set_bcn_ctrl_reg(hw, BIT(4), 0);
rtlpriv->cfg->ops->set_hw_reg(hw,
HW_VAR_RCR, (u8 *) (&reg_rcr));
}
+
}
int rtl92ce_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type)
{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
if (_rtl92ce_set_media_status(hw, type))
return -EOPNOTSUPP;
- _rtl92ce_set_check_bssid(hw, type);
+
+ if (rtlpriv->mac80211.link_state == MAC80211_LINKED) {
+ if (type != NL80211_IFTYPE_AP)
+ rtl92ce_set_check_bssid(hw, true);
+ } else {
+ rtl92ce_set_check_bssid(hw, false);
+ }
+
return 0;
}
+/* don't set REG_EDCA_BE_PARAM here because mac80211 will send pkt when scan */
void rtl92ce_set_qos(struct ieee80211_hw *hw, int aci)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
- u32 u4b_ac_param;
- u16 cw_min = le16_to_cpu(mac->ac[aci].cw_min);
- u16 cw_max = le16_to_cpu(mac->ac[aci].cw_max);
- u16 tx_op = le16_to_cpu(mac->ac[aci].tx_op);
-
rtl92c_dm_init_edca_turbo(hw);
- u4b_ac_param = (u32) mac->ac[aci].aifs;
- u4b_ac_param |= (u32) ((cw_min & 0xF) << AC_PARAM_ECW_MIN_OFFSET);
- u4b_ac_param |= (u32) ((cw_max & 0xF) << AC_PARAM_ECW_MAX_OFFSET);
- u4b_ac_param |= (u32) (tx_op << AC_PARAM_TXOP_OFFSET);
- RT_TRACE(rtlpriv, COMP_QOS, DBG_DMESG,
- ("queue:%x, ac_param:%x aifs:%x cwmin:%x cwmax:%x txop:%x\n",
- aci, u4b_ac_param, mac->ac[aci].aifs, cw_min,
- cw_max, tx_op));
switch (aci) {
case AC1_BK:
- rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, u4b_ac_param);
+ rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0xa44f);
break;
case AC0_BE:
- rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, u4b_ac_param);
+ /* rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, u4b_ac_param); */
break;
case AC2_VI:
- rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, u4b_ac_param);
+ rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, 0x5e4322);
break;
case AC3_VO:
- rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, u4b_ac_param);
+ rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, 0x2f3222);
break;
default:
RT_ASSERT(false, ("invalid aci: %d !\n", aci));
@@ -1227,8 +1201,10 @@ void rtl92ce_disable_interrupt(struct ieee80211_hw *hw)
static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
u8 u1b_tmp;
+ u32 u4b_tmp;
rtlpriv->intf_ops->enable_aspm(hw);
rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF);
@@ -1243,13 +1219,27 @@ static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw)
rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00000000);
u1b_tmp = rtl_read_byte(rtlpriv, REG_GPIO_PIN_CTRL);
- rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00FF0000 |
- (u1b_tmp << 8));
+ if ((rtlpcipriv->bt_coexist.bt_coexistence) &&
+ ((rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) ||
+ (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC8))) {
+ rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00F30000 |
+ (u1b_tmp << 8));
+ } else {
+ rtl_write_dword(rtlpriv, REG_GPIO_PIN_CTRL, 0x00FF0000 |
+ (u1b_tmp << 8));
+ }
rtl_write_word(rtlpriv, REG_GPIO_IO_SEL, 0x0790);
rtl_write_word(rtlpriv, REG_LEDCFG0, 0x8080);
rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x80);
rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x23);
- rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL, 0x0e);
+ if (rtlpcipriv->bt_coexist.bt_coexistence) {
+ u4b_tmp = rtl_read_dword(rtlpriv, REG_AFE_XTAL_CTRL);
+ u4b_tmp |= 0x03824800;
+ rtl_write_dword(rtlpriv, REG_AFE_XTAL_CTRL, u4b_tmp);
+ } else {
+ rtl_write_dword(rtlpriv, REG_AFE_XTAL_CTRL, 0x0e);
+ }
+
rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0e);
rtl_write_byte(rtlpriv, REG_APS_FSMCO + 1, 0x10);
}
@@ -1327,6 +1317,7 @@ void rtl92ce_update_interrupt_mask(struct ieee80211_hw *hw,
RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD,
("add_msr:%x, rm_msr:%x\n", add_msr, rm_msr));
+
if (add_msr)
rtlpci->irq_mask[0] |= add_msr;
if (rm_msr)
@@ -1582,7 +1573,7 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw)
("RTL819X Not boot from eeprom, check it !!"));
}
- RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_LOUD, ("MAP\n"),
+ RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("MAP\n"),
hwinfo, HWSET_MAX_SIZE);
eeprom_id = *((u16 *)&hwinfo[0]);
@@ -1610,6 +1601,10 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw)
rtlefuse->autoload_failflag,
hwinfo);
+ rtl8192ce_read_bt_coexist_info_from_hwpg(hw,
+ rtlefuse->autoload_failflag,
+ hwinfo);
+
rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN];
rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION];
rtlefuse->txpwr_fromeprom = true;
@@ -1618,6 +1613,9 @@ static void _rtl92ce_read_adapter_info(struct ieee80211_hw *hw)
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
("EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid));
+ /* set channel paln to world wide 13 */
+ rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13;
+
if (rtlhal->oem_id == RT_CID_DEFAULT) {
switch (rtlefuse->eeprom_oemid) {
case EEPROM_CID_DEFAULT:
@@ -1701,30 +1699,36 @@ void rtl92ce_read_eeprom_info(struct ieee80211_hw *hw)
} else {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Autoload ERR!!\n"));
}
-
_rtl92ce_hal_customized_behavior(hw);
}
-void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw)
+static void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-
- u32 ratr_value = (u32) mac->basic_rates;
- u8 *mcsrate = mac->mcs;
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u32 ratr_value;
u8 ratr_index = 0;
u8 nmode = mac->ht_enable;
- u8 mimo_ps = 1;
+ u8 mimo_ps = IEEE80211_SMPS_OFF;
u16 shortgi_rate;
u32 tmp_ratr_value;
u8 curtxbw_40mhz = mac->bw_40;
- u8 curshortgi_40mhz = mac->sgi_40;
- u8 curshortgi_20mhz = mac->sgi_20;
+ u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+ 1 : 0;
+ u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+ 1 : 0;
enum wireless_mode wirelessmode = mac->mode;
- ratr_value |= ((*(u16 *) (mcsrate))) << 12;
-
+ if (rtlhal->current_bandtype == BAND_ON_5G)
+ ratr_value = sta->supp_rates[1] << 4;
+ else
+ ratr_value = sta->supp_rates[0];
+ ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+ sta->ht_cap.mcs.rx_mask[0] << 12);
switch (wirelessmode) {
case WIRELESS_MODE_B:
if (ratr_value & 0x0000000c)
@@ -1738,7 +1742,7 @@ void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw)
case WIRELESS_MODE_N_24G:
case WIRELESS_MODE_N_5G:
nmode = 1;
- if (mimo_ps == 0) {
+ if (mimo_ps == IEEE80211_SMPS_STATIC) {
ratr_value &= 0x0007F005;
} else {
u32 ratr_mask;
@@ -1761,10 +1765,19 @@ void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw)
break;
}
- ratr_value &= 0x0FFFFFFF;
+ if ((rtlpcipriv->bt_coexist.bt_coexistence) &&
+ (rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) &&
+ (rtlpcipriv->bt_coexist.bt_cur_state) &&
+ (rtlpcipriv->bt_coexist.bt_ant_isolation) &&
+ ((rtlpcipriv->bt_coexist.bt_service == BT_SCO) ||
+ (rtlpcipriv->bt_coexist.bt_service == BT_BUSY)))
+ ratr_value &= 0x0fffcfc0;
+ else
+ ratr_value &= 0x0FFFFFFF;
- if (nmode && ((curtxbw_40mhz && curshortgi_40mhz) || (!curtxbw_40mhz &&
- curshortgi_20mhz))) {
+ if (nmode && ((curtxbw_40mhz &&
+ curshortgi_40mhz) || (!curtxbw_40mhz &&
+ curshortgi_20mhz))) {
ratr_value |= 0x10000000;
tmp_ratr_value = (ratr_value >> 12);
@@ -1784,24 +1797,42 @@ void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw)
("%x\n", rtl_read_dword(rtlpriv, REG_ARFR0)));
}
-void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
+static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u8 rssi_level)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
- u32 ratr_bitmap = (u32) mac->basic_rates;
- u8 *p_mcsrate = mac->mcs;
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_sta_info *sta_entry = NULL;
+ u32 ratr_bitmap;
u8 ratr_index;
- u8 curtxbw_40mhz = mac->bw_40;
- u8 curshortgi_40mhz = mac->sgi_40;
- u8 curshortgi_20mhz = mac->sgi_20;
- enum wireless_mode wirelessmode = mac->mode;
+ u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
+ ? 1 : 0;
+ u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+ 1 : 0;
+ u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+ 1 : 0;
+ enum wireless_mode wirelessmode = 0;
bool shortgi = false;
u8 rate_mask[5];
u8 macid = 0;
- u8 mimops = 1;
-
- ratr_bitmap |= (p_mcsrate[1] << 20) | (p_mcsrate[0] << 12);
+ u8 mimo_ps = IEEE80211_SMPS_OFF;
+
+ sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+ wirelessmode = sta_entry->wireless_mode;
+ if (mac->opmode == NL80211_IFTYPE_STATION)
+ curtxbw_40mhz = mac->bw_40;
+ else if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_ADHOC)
+ macid = sta->aid + 1;
+
+ if (rtlhal->current_bandtype == BAND_ON_5G)
+ ratr_bitmap = sta->supp_rates[1] << 4;
+ else
+ ratr_bitmap = sta->supp_rates[0];
+ ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+ sta->ht_cap.mcs.rx_mask[0] << 12);
switch (wirelessmode) {
case WIRELESS_MODE_B:
ratr_index = RATR_INX_WIRELESS_B;
@@ -1828,7 +1859,7 @@ void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
case WIRELESS_MODE_N_5G:
ratr_index = RATR_INX_WIRELESS_NGB;
- if (mimops == 0) {
+ if (mimo_ps == IEEE80211_SMPS_STATIC) {
if (rssi_level == 1)
ratr_bitmap &= 0x00070000;
else if (rssi_level == 2)
@@ -1892,8 +1923,8 @@ void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
}
RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
("ratr_bitmap :%x\n", ratr_bitmap));
- *(u32 *)&rate_mask = (ratr_bitmap & 0x0fffffff) |
- (ratr_index << 28);
+ *(u32 *)&rate_mask = EF4BYTE((ratr_bitmap & 0x0fffffff) |
+ (ratr_index << 28));
rate_mask[4] = macid | (shortgi ? 0x20 : 0x00) | 0x80;
RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG, ("Rate_index:%x, "
"ratr_val:%x, %x:%x:%x:%x:%x\n",
@@ -1902,6 +1933,20 @@ void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level)
rate_mask[2], rate_mask[3],
rate_mask[4]));
rtl92c_fill_h2c_cmd(hw, H2C_RA_MASK, 5, rate_mask);
+
+ if (macid != 0)
+ sta_entry->ratr_index = ratr_index;
+}
+
+void rtl92ce_update_hal_rate_tbl(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u8 rssi_level)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (rtlpriv->dm.useramask)
+ rtl92ce_update_hal_rate_mask(hw, sta, rssi_level);
+ else
+ rtl92ce_update_hal_rate_table(hw, sta);
}
void rtl92ce_update_channel_access_setting(struct ieee80211_hw *hw)
@@ -1919,7 +1964,7 @@ void rtl92ce_update_channel_access_setting(struct ieee80211_hw *hw)
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer);
}
-bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid)
+bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
@@ -1929,7 +1974,7 @@ bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid)
bool actuallyset = false;
unsigned long flag;
- if ((rtlpci->up_first_time == 1) || (rtlpci->being_init_adapter))
+ if (rtlpci->being_init_adapter)
return false;
if (ppsc->swrf_processing)
@@ -1946,12 +1991,6 @@ bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid)
cur_rfstate = ppsc->rfpwr_state;
- if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) &&
- RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM)) {
- rtlpriv->intf_ops->disable_aspm(hw);
- RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM);
- }
-
rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, rtl_read_byte(rtlpriv,
REG_MAC_PINMUX_CFG)&~(BIT(3)));
@@ -1976,38 +2015,13 @@ bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid)
}
if (actuallyset) {
- if (e_rfpowerstate_toset == ERFON) {
- if ((ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) &&
- RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM)) {
- rtlpriv->intf_ops->disable_aspm(hw);
- RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM);
- }
- }
-
spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
ppsc->rfchange_inprogress = false;
spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
-
- if (e_rfpowerstate_toset == ERFOFF) {
- if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) {
- rtlpriv->intf_ops->enable_aspm(hw);
- RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM);
- }
- }
-
- } else if (e_rfpowerstate_toset == ERFOFF || cur_rfstate == ERFOFF) {
+ } else {
if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC)
RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
- if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) {
- rtlpriv->intf_ops->enable_aspm(hw);
- RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_ASPM);
- }
-
- spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
- ppsc->rfchange_inprogress = false;
- spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
- } else {
spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
ppsc->rfchange_inprogress = false;
spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
@@ -2086,15 +2100,31 @@ void rtl92ce_set_key(struct ieee80211_hw *hw, u32 key_index,
macaddr = cam_const_broad;
entry_id = key_index;
} else {
+ if (mac->opmode == NL80211_IFTYPE_AP) {
+ entry_id = rtl_cam_get_free_entry(hw,
+ p_macaddr);
+ if (entry_id >= TOTAL_CAM_ENTRY) {
+ RT_TRACE(rtlpriv, COMP_SEC,
+ DBG_EMERG,
+ ("Can not find free hw"
+ " security cam entry\n"));
+ return;
+ }
+ } else {
+ entry_id = CAM_PAIRWISE_KEY_POSITION;
+ }
+
key_index = PAIRWISE_KEYIDX;
- entry_id = CAM_PAIRWISE_KEY_POSITION;
is_pairwise = true;
}
}
if (rtlpriv->sec.key_len[key_index] == 0) {
RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
- ("delete one entry\n"));
+ ("delete one entry, entry_id is %d\n",
+ entry_id));
+ if (mac->opmode == NL80211_IFTYPE_AP)
+ rtl_cam_del_entry(hw, p_macaddr);
rtl_cam_delete_one_entry(hw, p_macaddr, entry_id);
} else {
RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
@@ -2146,3 +2176,132 @@ void rtl92ce_set_key(struct ieee80211_hw *hw, u32 key_index,
}
}
}
+
+static void rtl8192ce_bt_var_init(struct ieee80211_hw *hw)
+{
+ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+ rtlpcipriv->bt_coexist.bt_coexistence =
+ rtlpcipriv->bt_coexist.eeprom_bt_coexist;
+ rtlpcipriv->bt_coexist.bt_ant_num =
+ rtlpcipriv->bt_coexist.eeprom_bt_ant_num;
+ rtlpcipriv->bt_coexist.bt_coexist_type =
+ rtlpcipriv->bt_coexist.eeprom_bt_type;
+
+ if (rtlpcipriv->bt_coexist.reg_bt_iso == 2)
+ rtlpcipriv->bt_coexist.bt_ant_isolation =
+ rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation;
+ else
+ rtlpcipriv->bt_coexist.bt_ant_isolation =
+ rtlpcipriv->bt_coexist.reg_bt_iso;
+
+ rtlpcipriv->bt_coexist.bt_radio_shared_type =
+ rtlpcipriv->bt_coexist.eeprom_bt_radio_shared;
+
+ if (rtlpcipriv->bt_coexist.bt_coexistence) {
+
+ if (rtlpcipriv->bt_coexist.reg_bt_sco == 1)
+ rtlpcipriv->bt_coexist.bt_service = BT_OTHER_ACTION;
+ else if (rtlpcipriv->bt_coexist.reg_bt_sco == 2)
+ rtlpcipriv->bt_coexist.bt_service = BT_SCO;
+ else if (rtlpcipriv->bt_coexist.reg_bt_sco == 4)
+ rtlpcipriv->bt_coexist.bt_service = BT_BUSY;
+ else if (rtlpcipriv->bt_coexist.reg_bt_sco == 5)
+ rtlpcipriv->bt_coexist.bt_service = BT_OTHERBUSY;
+ else
+ rtlpcipriv->bt_coexist.bt_service = BT_IDLE;
+
+ rtlpcipriv->bt_coexist.bt_edca_ul = 0;
+ rtlpcipriv->bt_coexist.bt_edca_dl = 0;
+ rtlpcipriv->bt_coexist.bt_rssi_state = 0xff;
+ }
+}
+
+void rtl8192ce_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw,
+ bool auto_load_fail, u8 *hwinfo)
+{
+ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+ u8 value;
+
+ if (!auto_load_fail) {
+ rtlpcipriv->bt_coexist.eeprom_bt_coexist =
+ ((hwinfo[RF_OPTION1] & 0xe0) >> 5);
+ value = hwinfo[RF_OPTION4];
+ rtlpcipriv->bt_coexist.eeprom_bt_type = ((value & 0xe) >> 1);
+ rtlpcipriv->bt_coexist.eeprom_bt_ant_num = (value & 0x1);
+ rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation =
+ ((value & 0x10) >> 4);
+ rtlpcipriv->bt_coexist.eeprom_bt_radio_shared =
+ ((value & 0x20) >> 5);
+ } else {
+ rtlpcipriv->bt_coexist.eeprom_bt_coexist = 0;
+ rtlpcipriv->bt_coexist.eeprom_bt_type = BT_2WIRE;
+ rtlpcipriv->bt_coexist.eeprom_bt_ant_num = ANT_X2;
+ rtlpcipriv->bt_coexist.eeprom_bt_ant_isolation = 0;
+ rtlpcipriv->bt_coexist.eeprom_bt_radio_shared = BT_RADIO_SHARED;
+ }
+
+ rtl8192ce_bt_var_init(hw);
+}
+
+void rtl8192ce_bt_reg_init(struct ieee80211_hw *hw)
+{
+ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+ /* 0:Low, 1:High, 2:From Efuse. */
+ rtlpcipriv->bt_coexist.reg_bt_iso = 2;
+ /* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter. */
+ rtlpcipriv->bt_coexist.reg_bt_sco = 3;
+ /* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */
+ rtlpcipriv->bt_coexist.reg_bt_sco = 0;
+}
+
+
+void rtl8192ce_bt_hw_init(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+ u8 u1_tmp;
+
+ if (rtlpcipriv->bt_coexist.bt_coexistence &&
+ ((rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) ||
+ rtlpcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC8)) {
+
+ if (rtlpcipriv->bt_coexist.bt_ant_isolation)
+ rtl_write_byte(rtlpriv, REG_GPIO_MUXCFG, 0xa0);
+
+ u1_tmp = rtl_read_byte(rtlpriv, 0x4fd) &
+ BIT_OFFSET_LEN_MASK_32(0, 1);
+ u1_tmp = u1_tmp |
+ ((rtlpcipriv->bt_coexist.bt_ant_isolation == 1) ?
+ 0 : BIT_OFFSET_LEN_MASK_32(1, 1)) |
+ ((rtlpcipriv->bt_coexist.bt_service == BT_SCO) ?
+ 0 : BIT_OFFSET_LEN_MASK_32(2, 1));
+ rtl_write_byte(rtlpriv, 0x4fd, u1_tmp);
+
+ rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+4, 0xaaaa9aaa);
+ rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+8, 0xffbd0040);
+ rtl_write_dword(rtlpriv, REG_BT_COEX_TABLE+0xc, 0x40000010);
+
+ /* Config to 1T1R. */
+ if (rtlphy->rf_type == RF_1T1R) {
+ u1_tmp = rtl_read_byte(rtlpriv, ROFDM0_TRXPATHENABLE);
+ u1_tmp &= ~(BIT_OFFSET_LEN_MASK_32(1, 1));
+ rtl_write_byte(rtlpriv, ROFDM0_TRXPATHENABLE, u1_tmp);
+
+ u1_tmp = rtl_read_byte(rtlpriv, ROFDM1_TRXPATHENABLE);
+ u1_tmp &= ~(BIT_OFFSET_LEN_MASK_32(1, 1));
+ rtl_write_byte(rtlpriv, ROFDM1_TRXPATHENABLE, u1_tmp);
+ }
+ }
+}
+
+void rtl92ce_suspend(struct ieee80211_hw *hw)
+{
+}
+
+void rtl92ce_resume(struct ieee80211_hw *hw)
+{
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h
index a3dfdb635168..07dbe3e340a5 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.h
@@ -30,7 +30,18 @@
#ifndef __RTL92CE_HW_H__
#define __RTL92CE_HW_H__
-#define H2C_RA_MASK 6
+static inline u8 _rtl92c_get_chnl_group(u8 chnl)
+{
+ u8 group;
+
+ if (chnl < 3)
+ group = 0;
+ else if (chnl < 9)
+ group = 1;
+ else
+ group = 2;
+ return group;
+}
void rtl92ce_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
void rtl92ce_read_eeprom_info(struct ieee80211_hw *hw);
@@ -41,28 +52,27 @@ void rtl92ce_card_disable(struct ieee80211_hw *hw);
void rtl92ce_enable_interrupt(struct ieee80211_hw *hw);
void rtl92ce_disable_interrupt(struct ieee80211_hw *hw);
int rtl92ce_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type);
+void rtl92ce_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid);
void rtl92ce_set_qos(struct ieee80211_hw *hw, int aci);
void rtl92ce_set_beacon_related_registers(struct ieee80211_hw *hw);
void rtl92ce_set_beacon_interval(struct ieee80211_hw *hw);
void rtl92ce_update_interrupt_mask(struct ieee80211_hw *hw,
u32 add_msr, u32 rm_msr);
void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
-void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw);
-void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level);
+void rtl92ce_update_hal_rate_tbl(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u8 rssi_level);
void rtl92ce_update_channel_access_setting(struct ieee80211_hw *hw);
bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid);
void rtl92ce_enable_hw_security_config(struct ieee80211_hw *hw);
void rtl92ce_set_key(struct ieee80211_hw *hw, u32 key_index,
u8 *p_macaddr, bool is_group, u8 enc_algo,
bool is_wepkey, bool clear_all);
-bool _rtl92ce_phy_config_mac_with_headerfile(struct ieee80211_hw *hw);
-void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished);
-void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
-void rtl92c_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus);
-int rtl92c_download_fw(struct ieee80211_hw *hw);
-void rtl92c_firmware_selfreset(struct ieee80211_hw *hw);
-void rtl92c_fill_h2c_cmd(struct ieee80211_hw *hw,
- u8 element_id, u32 cmd_len, u8 *p_cmdbuffer);
-bool rtl92ce_phy_mac_config(struct ieee80211_hw *hw);
+
+void rtl8192ce_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw,
+ bool autoload_fail, u8 *hwinfo);
+void rtl8192ce_bt_reg_init(struct ieee80211_hw *hw);
+void rtl8192ce_bt_hw_init(struct ieee80211_hw *hw);
+void rtl92ce_suspend(struct ieee80211_hw *hw);
+void rtl92ce_resume(struct ieee80211_hw *hw);
#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/led.c b/drivers/net/wireless/rtlwifi/rtl8192ce/led.c
index 7b1da8d7508f..9dd1ed7b6422 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/led.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/led.c
@@ -32,6 +32,14 @@
#include "reg.h"
#include "led.h"
+static void _rtl92ce_init_led(struct ieee80211_hw *hw,
+ struct rtl_led *pled, enum rtl_led_pin ledpin)
+{
+ pled->hw = hw;
+ pled->ledpin = ledpin;
+ pled->ledon = false;
+}
+
void rtl92ce_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled)
{
u8 ledcfg;
@@ -97,13 +105,12 @@ void rtl92ce_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled)
void rtl92ce_init_sw_leds(struct ieee80211_hw *hw)
{
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ _rtl92ce_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0);
+ _rtl92ce_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1);
}
-void rtl92ce_deinit_sw_leds(struct ieee80211_hw *hw)
-{
-}
-
-void _rtl92ce_sw_led_control(struct ieee80211_hw *hw,
+static void _rtl92ce_sw_led_control(struct ieee80211_hw *hw,
enum led_ctl_mode ledaction)
{
struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
@@ -138,7 +145,7 @@ void rtl92ce_led_control(struct ieee80211_hw *hw,
ledaction == LED_CTL_POWER_ON)) {
return;
}
- RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, ("ledaction %d,\n",
+ RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, ("ledaction %d.\n",
ledaction));
_rtl92ce_sw_led_control(hw, ledaction);
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/led.h b/drivers/net/wireless/rtlwifi/rtl8192ce/led.h
index 10da3018f4b7..7dfccea2095b 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/led.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/led.h
@@ -31,11 +31,8 @@
#define __RTL92CE_LED_H__
void rtl92ce_init_sw_leds(struct ieee80211_hw *hw);
-void rtl92ce_deinit_sw_leds(struct ieee80211_hw *hw);
void rtl92ce_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled);
void rtl92ce_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled);
void rtl92ce_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction);
-void _rtl92ce_sw_led_control(struct ieee80211_hw *hw,
- enum led_ctl_mode ledaction);
#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c
index d0541e8c6012..abe0fcc75368 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c
@@ -38,7 +38,9 @@
#include "dm.h"
#include "table.h"
-u32 rtl92ce_phy_query_rf_reg(struct ieee80211_hw *hw,
+static bool _rtl92c_phy_config_mac_with_headerfile(struct ieee80211_hw *hw);
+
+u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw,
enum radio_path rfpath, u32 regaddr, u32 bitmask)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -73,9 +75,47 @@ u32 rtl92ce_phy_query_rf_reg(struct ieee80211_hw *hw,
return readback_value;
}
+bool rtl92c_phy_mac_config(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ bool is92c = IS_92C_SERIAL(rtlhal->version);
+ bool rtstatus = _rtl92c_phy_config_mac_with_headerfile(hw);
+
+ if (is92c)
+ rtl_write_byte(rtlpriv, 0x14, 0x71);
+ return rtstatus;
+}
+
+bool rtl92c_phy_bb_config(struct ieee80211_hw *hw)
+{
+ bool rtstatus = true;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u16 regval;
+ u32 regvaldw;
+ u8 reg_hwparafile = 1;
+
+ _rtl92c_phy_init_bb_rf_register_definition(hw);
+ regval = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN);
+ rtl_write_word(rtlpriv, REG_SYS_FUNC_EN,
+ regval | BIT(13) | BIT(0) | BIT(1));
+ rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x83);
+ rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL + 1, 0xdb);
+ rtl_write_byte(rtlpriv, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN,
+ FEN_PPLL | FEN_PCIEA | FEN_DIO_PCIE |
+ FEN_BB_GLB_RSTn | FEN_BBRSTB);
+ rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80);
+ regvaldw = rtl_read_dword(rtlpriv, REG_LEDCFG0);
+ rtl_write_dword(rtlpriv, REG_LEDCFG0, regvaldw | BIT(23));
+ if (reg_hwparafile == 1)
+ rtstatus = _rtl92c_phy_bb8192c_config_parafile(hw);
+ return rtstatus;
+}
+
void rtl92ce_phy_set_rf_reg(struct ieee80211_hw *hw,
- enum radio_path rfpath,
- u32 regaddr, u32 bitmask, u32 data)
+ enum radio_path rfpath,
+ u32 regaddr, u32 bitmask, u32 data)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
@@ -121,45 +161,7 @@ void rtl92ce_phy_set_rf_reg(struct ieee80211_hw *hw,
bitmask, data, rfpath));
}
-bool rtl92ce_phy_mac_config(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
- bool is92c = IS_92C_SERIAL(rtlhal->version);
- bool rtstatus = _rtl92ce_phy_config_mac_with_headerfile(hw);
-
- if (is92c)
- rtl_write_byte(rtlpriv, 0x14, 0x71);
- return rtstatus;
-}
-
-bool rtl92ce_phy_bb_config(struct ieee80211_hw *hw)
-{
- bool rtstatus = true;
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u16 regval;
- u32 regvaldw;
- u8 reg_hwparafile = 1;
-
- _rtl92c_phy_init_bb_rf_register_definition(hw);
- regval = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN);
- rtl_write_word(rtlpriv, REG_SYS_FUNC_EN,
- regval | BIT(13) | BIT(0) | BIT(1));
- rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, 0x83);
- rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL + 1, 0xdb);
- rtl_write_byte(rtlpriv, REG_RF_CTRL, RF_EN | RF_RSTB | RF_SDMRSTB);
- rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN,
- FEN_PPLL | FEN_PCIEA | FEN_DIO_PCIE |
- FEN_BB_GLB_RSTn | FEN_BBRSTB);
- rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL + 1, 0x80);
- regvaldw = rtl_read_dword(rtlpriv, REG_LEDCFG0);
- rtl_write_dword(rtlpriv, REG_LEDCFG0, regvaldw | BIT(23));
- if (reg_hwparafile == 1)
- rtstatus = _rtl92c_phy_bb8192c_config_parafile(hw);
- return rtstatus;
-}
-
-bool _rtl92ce_phy_config_mac_with_headerfile(struct ieee80211_hw *hw)
+static bool _rtl92c_phy_config_mac_with_headerfile(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 i;
@@ -177,7 +179,7 @@ bool _rtl92ce_phy_config_mac_with_headerfile(struct ieee80211_hw *hw)
}
bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
- u8 configtype)
+ u8 configtype)
{
int i;
u32 *phy_regarray_table;
@@ -236,7 +238,7 @@ bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
}
bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
- u8 configtype)
+ u8 configtype)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
int i;
@@ -274,7 +276,7 @@ bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
return true;
}
-bool rtl92ce_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
+bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
enum radio_path rfpath)
{
@@ -378,8 +380,10 @@ void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ?
"20MHz" : "40MHz"))
- if (is_hal_stop(rtlhal))
+ if (is_hal_stop(rtlhal)) {
+ rtlphy->set_bwmode_inprogress = false;
return;
+ }
reg_bw_opmode = rtl_read_byte(rtlpriv, REG_BWOPMODE);
reg_prsr_rsc = rtl_read_byte(rtlpriv, REG_RRSR + 2);
@@ -389,16 +393,13 @@ void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
reg_bw_opmode |= BW_OPMODE_20MHZ;
rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
break;
-
case HT_CHANNEL_WIDTH_20_40:
reg_bw_opmode &= ~BW_OPMODE_20MHZ;
rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
-
reg_prsr_rsc =
(reg_prsr_rsc & 0x90) | (mac->cur_40_prime_sc << 5);
rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_prsr_rsc);
break;
-
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
("unknown bandwidth: %#X\n", rtlphy->current_chan_bw));
@@ -414,10 +415,12 @@ void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
case HT_CHANNEL_WIDTH_20_40:
rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1);
rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1);
+
rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND,
(mac->cur_40_prime_sc >> 1));
rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc);
rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 0);
+
rtl_set_bbreg(hw, 0x818, (BIT(26) | BIT(27)),
(mac->cur_40_prime_sc ==
HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1);
@@ -427,7 +430,7 @@ void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
("unknown bandwidth: %#X\n", rtlphy->current_chan_bw));
break;
}
- rtl92c_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw);
+ rtl92ce_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw);
rtlphy->set_bwmode_inprogress = false;
RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n"));
}
@@ -477,6 +480,36 @@ void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t)
}
}
+static void _rtl92ce_phy_set_rf_sleep(struct ieee80211_hw *hw)
+{
+ u32 u4b_tmp;
+ u8 delay = 5;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF);
+ rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00);
+ rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40);
+ u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK);
+ while (u4b_tmp != 0 && delay > 0) {
+ rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x0);
+ rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00);
+ rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40);
+ u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK);
+ delay--;
+ }
+ if (delay == 0) {
+ rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x00);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3);
+ rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00);
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
+ ("Switch RF timeout !!!.\n"));
+ return;
+ }
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
+ rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x22);
+}
+
static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw,
enum rf_pwrstate rfpwr_state)
{
@@ -523,33 +556,6 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw,
break;
}
case ERFOFF:{
- for (queue_id = 0, i = 0;
- queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) {
- ring = &pcipriv->dev.tx_ring[queue_id];
- if (skb_queue_len(&ring->queue) == 0 ||
- queue_id == BEACON_QUEUE) {
- queue_id++;
- continue;
- } else {
- RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
- ("eRf Off/Sleep: %d times "
- "TcbBusyQueue[%d] "
- "=%d before doze!\n", (i + 1),
- queue_id,
- skb_queue_len(&ring->queue)));
- udelay(10);
- i++;
- }
- if (i >= MAX_DOZE_WAITING_TIMES_9x) {
- RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
- ("\nERFOFF: %d times "
- "TcbBusyQueue[%d] = %d !\n",
- MAX_DOZE_WAITING_TIMES_9x,
- queue_id,
- skb_queue_len(&ring->queue)));
- break;
- }
- }
if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) {
RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
("IPS Set eRf nic disable\n"));
@@ -581,6 +587,7 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw,
"TcbBusyQueue[%d] =%d before "
"doze!\n", (i + 1), queue_id,
skb_queue_len(&ring->queue)));
+
udelay(10);
i++;
}
@@ -599,7 +606,7 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw,
jiffies_to_msecs(jiffies -
ppsc->last_awake_jiffies)));
ppsc->last_sleep_jiffies = jiffies;
- _rtl92c_phy_set_rf_sleep(hw);
+ _rtl92ce_phy_set_rf_sleep(hw);
break;
}
default:
@@ -614,10 +621,11 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw,
return bresult;
}
-bool rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw,
+bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw,
enum rf_pwrstate rfpwr_state)
{
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
bool bresult = false;
if (rfpwr_state == ppsc->rfpwr_state)
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h
index a37267e3fc22..be2c92adef33 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.h
@@ -39,6 +39,7 @@
#define RT_CANNOT_IO(hw) false
#define HIGHPOWER_RADIOA_ARRAYLEN 22
+#define IQK_ADDA_REG_NUM 16
#define MAX_TOLERANCE 5
#define IQK_DELAY_TIME 1
@@ -56,6 +57,8 @@
#define IQK_ADDA_REG_NUM 16
#define IQK_MAC_REG_NUM 4
+#define IQK_DELAY_TIME 1
+
#define RF90_PATH_MAX 2
#define CT_OFFSET_MAC_ADDR 0X16
@@ -76,7 +79,7 @@
#define CT_OFFSET_CUSTOMER_ID 0x7F
#define RTL92C_MAX_PATH_NUM 2
-#define LLT_LAST_ENTRY_OF_TX_PKT_BUFFER 255
+
enum swchnlcmd_id {
CMDID_END,
CMDID_SET_TXPOWEROWER_LEVEL,
@@ -184,43 +187,44 @@ struct tx_power_struct {
u32 mcs_original_offset[4][16];
};
-extern u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw,
+bool rtl92c_phy_bb_config(struct ieee80211_hw *hw);
+u32 rtl92c_phy_query_bb_reg(struct ieee80211_hw *hw,
u32 regaddr, u32 bitmask);
-extern void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw,
+void rtl92c_phy_set_bb_reg(struct ieee80211_hw *hw,
u32 regaddr, u32 bitmask, u32 data);
-extern u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw,
+u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw,
enum radio_path rfpath, u32 regaddr,
u32 bitmask);
extern void rtl92ce_phy_set_rf_reg(struct ieee80211_hw *hw,
- enum radio_path rfpath, u32 regaddr,
- u32 bitmask, u32 data);
-extern bool rtl92c_phy_mac_config(struct ieee80211_hw *hw);
+ enum radio_path rfpath, u32 regaddr,
+ u32 bitmask, u32 data);
+bool rtl92c_phy_mac_config(struct ieee80211_hw *hw);
bool rtl92ce_phy_bb_config(struct ieee80211_hw *hw);
-extern bool rtl92c_phy_rf_config(struct ieee80211_hw *hw);
-extern bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw,
+bool rtl92c_phy_rf_config(struct ieee80211_hw *hw);
+bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw,
enum radio_path rfpath);
-extern void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw);
-extern void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw,
+void rtl92c_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw);
+void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw,
long *powerlevel);
-extern void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel);
-extern bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw,
+void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel);
+bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw,
long power_indbm);
-extern void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw,
+void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw,
u8 operation);
-extern void rtl92c_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
-extern void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw,
+void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw,
enum nl80211_channel_type ch_type);
-extern void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw);
-extern u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw);
-extern void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery);
-extern void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw,
+void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw);
+u8 rtl92c_phy_sw_chnl(struct ieee80211_hw *hw);
+void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool b_recovery);
+void rtl92c_phy_set_beacon_hw_reg(struct ieee80211_hw *hw,
u16 beaconinterval);
void rtl92c_phy_ap_calibrate(struct ieee80211_hw *hw, char delta);
void rtl92c_phy_lc_calibrate(struct ieee80211_hw *hw);
+void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t);
void rtl92c_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain);
bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
enum radio_path rfpath);
-extern bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw,
+bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw,
u32 rfpath);
bool rtl92c_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype);
bool rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw,
@@ -237,9 +241,6 @@ u32 _rtl92c_phy_calculate_bit_shift(u32 bitmask);
void _rtl92c_phy_rf_serial_write(struct ieee80211_hw *hw,
enum radio_path rfpath, u32 offset,
u32 data);
-void _rtl92c_store_pwrIndex_diffrate_offset(struct ieee80211_hw *hw,
- u32 regaddr, u32 bitmask,
- u32 data);
void _rtl92c_phy_fw_rf_serial_write(struct ieee80211_hw *hw,
enum radio_path rfpath, u32 offset,
u32 data);
@@ -250,5 +251,12 @@ bool _rtl92ce_phy_config_mac_with_headerfile(struct ieee80211_hw *hw);
void _rtl92c_phy_init_bb_rf_register_definition(struct ieee80211_hw *hw);
bool _rtl92c_phy_bb8192c_config_parafile(struct ieee80211_hw *hw);
void _rtl92c_phy_set_rf_sleep(struct ieee80211_hw *hw);
+bool rtl92c_phy_set_rf_power_state(struct ieee80211_hw *hw,
+ enum rf_pwrstate rfpwr_state);
+bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
+ u8 configtype);
+bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
+ u8 configtype);
+void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h
index b0868a613841..598cecc63f41 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/reg.h
@@ -72,6 +72,7 @@
#define REG_GPIO_IO_SEL_2 0x0062
/* RTL8723 WIFI/BT/GPS Multi-Function control source. */
#define REG_MULTI_FUNC_CTRL 0x0068
+
#define REG_MCUFWDL 0x0080
#define REG_HMEBOX_EXT_0 0x0088
@@ -542,7 +543,7 @@
#define IMR_OCPINT BIT(1)
#define IMR_WLANOFF BIT(0)
-#define HWSET_MAX_SIZE 128
+#define EFUSE_REAL_CONTENT_LEN 512
#define EEPROM_DEFAULT_TSSI 0x0
#define EEPROM_DEFAULT_TXPOWERDIFF 0x0
@@ -656,6 +657,7 @@
#define STOPBE BIT(1)
#define STOPBK BIT(0)
+#define RCR_APPFCS BIT(31)
#define RCR_APP_FCS BIT(31)
#define RCR_APP_MIC BIT(30)
#define RCR_APP_ICV BIT(29)
@@ -688,6 +690,7 @@
#define REG_USB_INFO 0xFE17
#define REG_USB_SPECIAL_OPTION 0xFE55
+
#define REG_USB_DMA_AGG_TO 0xFE5B
#define REG_USB_AGG_TO 0xFE5C
#define REG_USB_AGG_TH 0xFE5D
@@ -775,7 +778,6 @@
#define BOOT_FROM_EEPROM BIT(4)
#define EEPROM_EN BIT(5)
-#define EEPROMSEL BOOT_FROM_EEPROM
#define AFE_BGEN BIT(0)
#define AFE_MBEN BIT(1)
@@ -901,28 +903,7 @@
#define BD_PKG_SEL BIT(25)
#define BD_HCI_SEL BIT(26)
#define TYPE_ID BIT(27)
-
-/* REG_GPIO_OUTSTS (For RTL8723 only) */
-#define EFS_HCI_SEL (BIT(0)|BIT(1))
-#define PAD_HCI_SEL (BIT(2)|BIT(3))
-#define HCI_SEL (BIT(4)|BIT(5))
-#define PKG_SEL_HCI BIT(6)
-#define FEN_GPS BIT(7)
-#define FEN_BT BIT(8)
-#define FEN_WL BIT(9)
-#define FEN_PCI BIT(10)
-#define FEN_USB BIT(11)
-#define BTRF_HWPDN_N BIT(12)
-#define WLRF_HWPDN_N BIT(13)
-#define PDN_BT_N BIT(14)
-#define PDN_GPS_N BIT(15)
-#define BT_CTL_HWPDN BIT(16)
-#define GPS_CTL_HWPDN BIT(17)
-#define PPHY_SUSB BIT(20)
-#define UPHY_SUSB BIT(21)
-#define PCI_SUSEN BIT(22)
-#define USB_SUSEN BIT(23)
-#define RF_RL_ID (BIT(31) | BIT(30) | BIT(29) | BIT(28))
+#define RF_RL_ID (BIT(31) | BIT(30) | BIT(29) | BIT(28))
#define CHIP_VER_RTL_MASK 0xF000
#define CHIP_VER_RTL_SHIFT 12
@@ -1077,6 +1058,7 @@
#define _RARF_RC8(x) (((x) & 0x1F) << 24)
#define AC_PARAM_TXOP_OFFSET 16
+#define AC_PARAM_TXOP_LIMIT_OFFSET 16
#define AC_PARAM_ECW_MAX_OFFSET 12
#define AC_PARAM_ECW_MIN_OFFSET 8
#define AC_PARAM_AIFS_OFFSET 0
@@ -1221,33 +1203,11 @@
#define EPROM_CMD_CONFIG 0x3
#define EPROM_CMD_LOAD 1
-#define HWSET_MAX_SIZE_92S HWSET_MAX_SIZE
+#define HWSET_MAX_SIZE_92S HWSET_MAX_SIZE
-#define HAL_8192C_HW_GPIO_WPS_BIT BIT(2)
-
-/* REG_MULTI_FUNC_CTRL(For RTL8723 Only) */
-/* Enable GPIO[9] as WiFi HW PDn source */
#define WL_HWPDN_EN BIT(0)
-/* WiFi HW PDn polarity control */
-#define WL_HWPDN_SL BIT(1)
-/* WiFi function enable */
-#define WL_FUNC_EN BIT(2)
-/* Enable GPIO[9] as WiFi RF HW PDn source */
-#define WL_HWROF_EN BIT(3)
-/* Enable GPIO[11] as BT HW PDn source */
-#define BT_HWPDN_EN BIT(16)
-/* BT HW PDn polarity control */
-#define BT_HWPDN_SL BIT(17)
-/* BT function enable */
-#define BT_FUNC_EN BIT(18)
-/* Enable GPIO[11] as BT/GPS RF HW PDn source */
-#define BT_HWROF_EN BIT(19)
-/* Enable GPIO[10] as GPS HW PDn source */
-#define GPS_HWPDN_EN BIT(20)
-/* GPS HW PDn polarity control */
-#define GPS_HWPDN_SL BIT(21)
-/* GPS function enable */
-#define GPS_FUNC_EN BIT(22)
+
+#define HAL_8192C_HW_GPIO_WPS_BIT BIT(2)
#define RPMAC_RESET 0x100
#define RPMAC_TXSTART 0x104
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c
index 669b1168dbec..90d0f2cf3b27 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.c
@@ -34,9 +34,9 @@
#include "rf.h"
#include "dm.h"
-static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw);
+static bool _rtl92ce_phy_rf6052_config_parafile(struct ieee80211_hw *hw);
-void rtl92c_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
+void rtl92ce_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
@@ -62,7 +62,7 @@ void rtl92c_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
}
void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
- u8 *ppowerlevel)
+ u8 *ppowerlevel)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
@@ -128,8 +128,7 @@ void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
tmpval = tx_agc[RF90_PATH_A] >> 8;
- if (mac->mode == WIRELESS_MODE_B)
- tmpval = tmpval & 0xff00ffff;
+ tmpval = tmpval & 0xff00ffff;
rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
@@ -202,7 +201,7 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw,
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
- u8 i, chnlgroup, pwr_diff_limit[4];
+ u8 i, chnlgroup = 0, pwr_diff_limit[4];
u32 writeVal, customer_limit, rf;
for (rf = 0; rf < 2; rf++) {
@@ -440,16 +439,17 @@ bool rtl92ce_phy_rf6052_config(struct ieee80211_hw *hw)
else
rtlphy->num_total_rfpath = 2;
- return _rtl92c_phy_rf6052_config_parafile(hw);
+ return _rtl92ce_phy_rf6052_config_parafile(hw);
+
}
-static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw)
+static bool _rtl92ce_phy_rf6052_config_parafile(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
- u32 u4_regvalue;
+ u32 u4_regvalue = 0;
u8 rfpath;
- bool rtstatus;
+ bool rtstatus = true;
struct bb_reg_def *pphyreg;
for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {
@@ -484,12 +484,12 @@ static bool _rtl92c_phy_rf6052_config_parafile(struct ieee80211_hw *hw)
switch (rfpath) {
case RF90_PATH_A:
- rtstatus = rtl92ce_phy_config_rf_with_headerfile(hw,
- (enum radio_path) rfpath);
+ rtstatus = rtl92c_phy_config_rf_with_headerfile(hw,
+ (enum radio_path)rfpath);
break;
case RF90_PATH_B:
- rtstatus = rtl92ce_phy_config_rf_with_headerfile(hw,
- (enum radio_path) rfpath);
+ rtstatus = rtl92c_phy_config_rf_with_headerfile(hw,
+ (enum radio_path)rfpath);
break;
case RF90_PATH_C:
break;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h
index 3aa520c1c171..39ff03685986 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/rf.h
@@ -34,14 +34,11 @@
#define RF6052_MAX_REG 0x3F
#define RF6052_MAX_PATH 2
-extern void rtl92c_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw,
- u8 bandwidth);
-extern void rtl92c_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
- u8 *ppowerlevel);
-extern void rtl92c_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
- u8 *ppowerlevel, u8 channel);
-bool rtl92ce_phy_rf6052_config(struct ieee80211_hw *hw);
-bool rtl92ce_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
- enum radio_path rfpath);
-
+extern void rtl92ce_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw,
+ u8 bandwidth);
+extern void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
+ u8 *ppowerlevel);
+extern void rtl92ce_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
+ u8 *ppowerlevel, u8 channel);
+extern bool rtl92ce_phy_rf6052_config(struct ieee80211_hw *hw);
#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
index b1cc4d44f534..373dc78af1dc 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
@@ -42,10 +42,58 @@
#include "trx.h"
#include "led.h"
+static void rtl92c_init_aspm_vars(struct ieee80211_hw *hw)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ /*close ASPM for AMD defaultly */
+ rtlpci->const_amdpci_aspm = 0;
+
+ /*
+ * ASPM PS mode.
+ * 0 - Disable ASPM,
+ * 1 - Enable ASPM without Clock Req,
+ * 2 - Enable ASPM with Clock Req,
+ * 3 - Alwyas Enable ASPM with Clock Req,
+ * 4 - Always Enable ASPM without Clock Req.
+ * set defult to RTL8192CE:3 RTL8192E:2
+ * */
+ rtlpci->const_pci_aspm = 3;
+
+ /*Setting for PCI-E device */
+ rtlpci->const_devicepci_aspm_setting = 0x03;
+
+ /*Setting for PCI-E bridge */
+ rtlpci->const_hostpci_aspm_setting = 0x02;
+
+ /*
+ * In Hw/Sw Radio Off situation.
+ * 0 - Default,
+ * 1 - From ASPM setting without low Mac Pwr,
+ * 2 - From ASPM setting with low Mac Pwr,
+ * 3 - Bus D3
+ * set default to RTL8192CE:0 RTL8192SE:2
+ */
+ rtlpci->const_hwsw_rfoff_d3 = 0;
+
+ /*
+ * This setting works for those device with
+ * backdoor ASPM setting such as EPHY setting.
+ * 0 - Not support ASPM,
+ * 1 - Support ASPM,
+ * 2 - According to chipset.
+ */
+ rtlpci->const_support_pciaspm = 1;
+}
+
int rtl92c_init_sw_vars(struct ieee80211_hw *hw)
{
+ int err;
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ const struct firmware *firmware;
+
+ rtl8192ce_bt_reg_init(hw);
rtlpriv->dm.dm_initialgain_enable = 1;
rtlpriv->dm.dm_flag = 0;
@@ -53,7 +101,12 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw)
rtlpriv->dm.thermalvalue = 0;
rtlpci->transmit_config = CFENDFORM | BIT(12) | BIT(13);
- rtlpci->receive_config = (RCR_APP_FCS |
+ /* compatible 5G band 88ce just 2.4G band & smsp */
+ rtlpriv->rtlhal.current_bandtype = BAND_ON_2_4G;
+ rtlpriv->rtlhal.bandset = BAND_ON_2_4G;
+ rtlpriv->rtlhal.macphymode = SINGLEMAC_SINGLEPHY;
+
+ rtlpci->receive_config = (RCR_APPFCS |
RCR_AMF |
RCR_ADF |
RCR_APP_MIC |
@@ -76,13 +129,49 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw)
rtlpci->irq_mask[1] = (u32) (IMR_CPWM | IMR_C2HCMD | 0);
- rtlpriv->rtlhal.pfirmware = (u8 *) vmalloc(0x4000);
+ /* for LPS & IPS */
+ rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps;
+ rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
+ rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
+ rtlpriv->psc.reg_fwctrl_lps = 3;
+ rtlpriv->psc.reg_max_lps_awakeintvl = 5;
+ /* for ASPM, you can close aspm through
+ * set const_support_pciaspm = 0 */
+ rtl92c_init_aspm_vars(hw);
+
+ if (rtlpriv->psc.reg_fwctrl_lps == 1)
+ rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE;
+ else if (rtlpriv->psc.reg_fwctrl_lps == 2)
+ rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE;
+ else if (rtlpriv->psc.reg_fwctrl_lps == 3)
+ rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE;
+
+ /* for firmware buf */
+ rtlpriv->rtlhal.pfirmware = vzalloc(0x4000);
if (!rtlpriv->rtlhal.pfirmware) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
("Can't alloc buffer for fw.\n"));
return 1;
}
+ /* request fw */
+ err = request_firmware(&firmware, rtlpriv->cfg->fw_name,
+ rtlpriv->io.dev);
+ if (err) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Failed to request firmware!\n"));
+ return 1;
+ }
+ if (firmware->size > 0x4000) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Firmware is too big!\n"));
+ release_firmware(firmware);
+ return 1;
+ }
+ memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size);
+ rtlpriv->rtlhal.fwsize = firmware->size;
+ release_firmware(firmware);
+
return 0;
}
@@ -103,17 +192,19 @@ static struct rtl_hal_ops rtl8192ce_hal_ops = {
.interrupt_recognized = rtl92ce_interrupt_recognized,
.hw_init = rtl92ce_hw_init,
.hw_disable = rtl92ce_card_disable,
+ .hw_suspend = rtl92ce_suspend,
+ .hw_resume = rtl92ce_resume,
.enable_interrupt = rtl92ce_enable_interrupt,
.disable_interrupt = rtl92ce_disable_interrupt,
.set_network_type = rtl92ce_set_network_type,
+ .set_chk_bssid = rtl92ce_set_check_bssid,
.set_qos = rtl92ce_set_qos,
.set_bcn_reg = rtl92ce_set_beacon_related_registers,
.set_bcn_intv = rtl92ce_set_beacon_interval,
.update_interrupt_mask = rtl92ce_update_interrupt_mask,
.get_hw_reg = rtl92ce_get_hw_reg,
.set_hw_reg = rtl92ce_set_hw_reg,
- .update_rate_table = rtl92ce_update_hal_rate_table,
- .update_rate_mask = rtl92ce_update_hal_rate_mask,
+ .update_rate_tbl = rtl92ce_update_hal_rate_tbl,
.fill_tx_desc = rtl92ce_tx_fill_desc,
.fill_tx_cmddesc = rtl92ce_tx_fill_cmddesc,
.query_rx_desc = rtl92ce_rx_query_desc,
@@ -123,7 +214,7 @@ static struct rtl_hal_ops rtl8192ce_hal_ops = {
.switch_channel = rtl92c_phy_sw_chnl,
.dm_watchdog = rtl92c_dm_watchdog,
.scan_operation_backup = rtl92c_phy_scan_operation_backup,
- .set_rf_power_state = rtl92ce_phy_set_rf_power_state,
+ .set_rf_power_state = rtl92c_phy_set_rf_power_state,
.led_control = rtl92ce_led_control,
.set_desc = rtl92ce_set_desc,
.get_desc = rtl92ce_get_desc,
@@ -131,12 +222,10 @@ static struct rtl_hal_ops rtl8192ce_hal_ops = {
.enable_hw_sec = rtl92ce_enable_hw_security_config,
.set_key = rtl92ce_set_key,
.init_sw_leds = rtl92ce_init_sw_leds,
- .deinit_sw_leds = rtl92ce_deinit_sw_leds,
.get_bbreg = rtl92c_phy_query_bb_reg,
.set_bbreg = rtl92c_phy_set_bb_reg,
- .get_rfreg = rtl92ce_phy_query_rf_reg,
.set_rfreg = rtl92ce_phy_set_rf_reg,
- .cmd_send_packet = _rtl92c_cmd_send_packet,
+ .get_rfreg = rtl92c_phy_query_rf_reg,
.phy_rf6052_config = rtl92ce_phy_rf6052_config,
.phy_rf6052_set_cck_txpower = rtl92ce_phy_rf6052_set_cck_txpower,
.phy_rf6052_set_ofdm_txpower = rtl92ce_phy_rf6052_set_ofdm_txpower,
@@ -148,10 +237,15 @@ static struct rtl_hal_ops rtl8192ce_hal_ops = {
};
static struct rtl_mod_params rtl92ce_mod_params = {
- .sw_crypto = 0,
+ .sw_crypto = false,
+ .inactiveps = true,
+ .swctrl_lps = false,
+ .fwctrl_lps = true,
};
static struct rtl_hal_cfg rtl92ce_hal_cfg = {
+ .bar_id = 2,
+ .write_readback = true,
.name = "rtl92c_pci",
.fw_name = "rtlwifi/rtl8192cfw.bin",
.ops = &rtl8192ce_hal_ops,
@@ -175,6 +269,8 @@ static struct rtl_hal_cfg rtl92ce_hal_cfg = {
.maps[EFUSE_LOADER_CLK_EN] = LOADER_CLK_EN,
.maps[EFUSE_ANA8M] = EFUSE_ANA8M,
.maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE,
+ .maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION,
+ .maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN,
.maps[RWCAM] = REG_CAMCMD,
.maps[WCAMI] = REG_CAMWRITE,
@@ -239,7 +335,7 @@ static struct rtl_hal_cfg rtl92ce_hal_cfg = {
.maps[RTL_RC_HT_RATEMCS15] = DESC92C_RATEMCS15,
};
-static struct pci_device_id rtl92ce_pci_ids[] __devinitdata = {
+DEFINE_PCI_DEVICE_TABLE(rtl92ce_pci_ids) = {
{RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8191, rtl92ce_hal_cfg)},
{RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8178, rtl92ce_hal_cfg)},
{RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8177, rtl92ce_hal_cfg)},
@@ -257,7 +353,13 @@ MODULE_DESCRIPTION("Realtek 8192C/8188C 802.11n PCI wireless");
MODULE_FIRMWARE("rtlwifi/rtl8192cfw.bin");
module_param_named(swenc, rtl92ce_mod_params.sw_crypto, bool, 0444);
+module_param_named(ips, rtl92ce_mod_params.inactiveps, bool, 0444);
+module_param_named(swlps, rtl92ce_mod_params.swctrl_lps, bool, 0444);
+module_param_named(fwlps, rtl92ce_mod_params.fwctrl_lps, bool, 0444);
MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n");
+MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n");
+MODULE_PARM_DESC(fwlps, "using linked fw control power save "
+ "(default 1 is open)\n");
static struct pci_driver rtl92ce_driver = {
.name = KBUILD_MODNAME,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h
index 36e657668c1e..b7dc3263e433 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.h
@@ -33,19 +33,9 @@
int rtl92c_init_sw_vars(struct ieee80211_hw *hw);
void rtl92c_deinit_sw_vars(struct ieee80211_hw *hw);
void rtl92c_init_var_map(struct ieee80211_hw *hw);
-bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw,
- struct sk_buff *skb);
-void rtl92ce_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
- u8 *ppowerlevel);
-void rtl92ce_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
- u8 *ppowerlevel, u8 channel);
bool _rtl92ce_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
- u8 configtype);
+ u8 configtype);
bool _rtl92ce_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
- u8 configtype);
-void _rtl92ce_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t);
-u32 rtl92ce_phy_query_rf_reg(struct ieee80211_hw *hw,
- enum radio_path rfpath, u32 regaddr, u32 bitmask);
-void rtl92ce_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
+ u8 configtype);
#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
index aa2b5815600f..54b2bd53d36a 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
@@ -36,42 +36,16 @@
#include "trx.h"
#include "led.h"
-static enum rtl_desc_qsel _rtl92ce_map_hwqueue_to_fwqueue(__le16 fc,
- unsigned int
- skb_queue)
+static u8 _rtl92ce_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
{
- enum rtl_desc_qsel qsel;
+ __le16 fc = rtl_get_fc(skb);
- if (unlikely(ieee80211_is_beacon(fc))) {
- qsel = QSLT_BEACON;
- return qsel;
- }
-
- if (ieee80211_is_mgmt(fc)) {
- qsel = QSLT_MGNT;
- return qsel;
- }
+ if (unlikely(ieee80211_is_beacon(fc)))
+ return QSLT_BEACON;
+ if (ieee80211_is_mgmt(fc))
+ return QSLT_MGNT;
- switch (skb_queue) {
- case VO_QUEUE:
- qsel = QSLT_VO;
- break;
- case VI_QUEUE:
- qsel = QSLT_VI;
- break;
- case BE_QUEUE:
- qsel = QSLT_BE;
- break;
- case BK_QUEUE:
- qsel = QSLT_BK;
- break;
- default:
- qsel = QSLT_BE;
- RT_ASSERT(false, ("BE queue, skb_queue:%d,"
- " set qsel = 0x%X\n", skb_queue, QSLT_BE));
- break;
- }
- return qsel;
+ return skb->priority;
}
static int _rtl92ce_rate_mapping(bool isht, u8 desc_rate, bool first_ampdu)
@@ -255,6 +229,7 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,
u8 evm, pwdb_all, rf_rx_num = 0;
u8 i, max_spatial_stream;
u32 rssi, total_rssi = 0;
+ bool in_powersavemode = false;
bool is_cck_rate;
is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc);
@@ -270,9 +245,13 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,
u8 report, cck_highpwr;
cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo;
- cck_highpwr = (u8) rtl_get_bbreg(hw,
- RFPGA0_XA_HSSIPARAMETER2,
- BIT(9));
+ if (!in_powersavemode)
+ cck_highpwr = (u8) rtl_get_bbreg(hw,
+ RFPGA0_XA_HSSIPARAMETER2,
+ BIT(9));
+ else
+ cck_highpwr = false;
+
if (!cck_highpwr) {
u8 cck_agc_rpt = cck_buf->cck_agc_rpt;
report = cck_buf->cck_agc_rpt & 0xc0;
@@ -398,6 +377,7 @@ static void _rtl92ce_process_ui_rssi(struct ieee80211_hw *hw,
if (rtlpriv->stats.ui_rssi.total_num++ >=
PHY_RSSI_SLID_WIN_MAX) {
+
rtlpriv->stats.ui_rssi.total_num =
PHY_RSSI_SLID_WIN_MAX;
last_rssi =
@@ -424,10 +404,6 @@ static void _rtl92ce_process_ui_rssi(struct ieee80211_hw *hw,
if (!pstats->is_cck && pstats->packet_toself) {
for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath;
rfpath++) {
-
- if (!rtl8192_phy_check_is_legal_rfpath(hw, rfpath))
- continue;
-
if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) {
rtlpriv->stats.rx_rssi_percentage[rfpath] =
pstats->rx_mimo_signalstrength[rfpath];
@@ -723,7 +699,7 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr, u8 *pdesc_tx,
struct ieee80211_tx_info *info, struct sk_buff *skb,
- unsigned int queue_index)
+ u8 hw_queue, struct rtl_tcb_desc *tcb_desc)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
@@ -732,16 +708,9 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
bool defaultadapter = true;
struct ieee80211_sta *sta;
u8 *pdesc = (u8 *) pdesc_tx;
- struct rtl_tcb_desc tcb_desc;
- u8 *qc = ieee80211_get_qos_ctl(hdr);
- u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
u16 seq_number;
__le16 fc = hdr->frame_control;
- u8 rate_flag = info->control.rates[0].flags;
-
- enum rtl_desc_qsel fw_qsel =
- _rtl92ce_map_hwqueue_to_fwqueue(fc, queue_index);
-
+ u8 fw_qsel = _rtl92ce_map_hwqueue_to_fwqueue(skb, hw_queue);
bool firstseg = ((hdr->seq_ctrl &
cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0);
@@ -751,56 +720,68 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
dma_addr_t mapping = pci_map_single(rtlpci->pdev,
skb->data, skb->len,
PCI_DMA_TODEVICE);
+ u8 bw_40 = 0;
+
+ rcu_read_lock();
+ sta = get_sta(hw, mac->vif, mac->bssid);
+ if (mac->opmode == NL80211_IFTYPE_STATION) {
+ bw_40 = mac->bw_40;
+ } else if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_ADHOC) {
+ if (sta)
+ bw_40 = sta->ht_cap.cap &
+ IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ }
seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
- rtl_get_tcb_desc(hw, info, skb, &tcb_desc);
+ rtl_get_tcb_desc(hw, info, sta, skb, tcb_desc);
CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_92c));
+ if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) {
+ firstseg = true;
+ lastseg = true;
+ }
if (firstseg) {
SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
- SET_TX_DESC_TX_RATE(pdesc, tcb_desc.hw_rate);
+ SET_TX_DESC_TX_RATE(pdesc, tcb_desc->hw_rate);
- if (tcb_desc.use_shortgi || tcb_desc.use_shortpreamble)
+ if (tcb_desc->use_shortgi || tcb_desc->use_shortpreamble)
SET_TX_DESC_DATA_SHORTGI(pdesc, 1);
- if (mac->tids[tid].agg.agg_state == RTL_AGG_ON &&
- info->flags & IEEE80211_TX_CTL_AMPDU) {
+ if (info->flags & IEEE80211_TX_CTL_AMPDU) {
SET_TX_DESC_AGG_BREAK(pdesc, 1);
SET_TX_DESC_MAX_AGG_NUM(pdesc, 0x14);
}
SET_TX_DESC_SEQ(pdesc, seq_number);
- SET_TX_DESC_RTS_ENABLE(pdesc, ((tcb_desc.rts_enable &&
- !tcb_desc.
+ SET_TX_DESC_RTS_ENABLE(pdesc, ((tcb_desc->rts_enable &&
+ !tcb_desc->
cts_enable) ? 1 : 0));
SET_TX_DESC_HW_RTS_ENABLE(pdesc,
- ((tcb_desc.rts_enable
- || tcb_desc.cts_enable) ? 1 : 0));
- SET_TX_DESC_CTS2SELF(pdesc, ((tcb_desc.cts_enable) ? 1 : 0));
- SET_TX_DESC_RTS_STBC(pdesc, ((tcb_desc.rts_stbc) ? 1 : 0));
+ ((tcb_desc->rts_enable
+ || tcb_desc->cts_enable) ? 1 : 0));
+ SET_TX_DESC_CTS2SELF(pdesc, ((tcb_desc->cts_enable) ? 1 : 0));
+ SET_TX_DESC_RTS_STBC(pdesc, ((tcb_desc->rts_stbc) ? 1 : 0));
- SET_TX_DESC_RTS_RATE(pdesc, tcb_desc.rts_rate);
+ SET_TX_DESC_RTS_RATE(pdesc, tcb_desc->rts_rate);
SET_TX_DESC_RTS_BW(pdesc, 0);
- SET_TX_DESC_RTS_SC(pdesc, tcb_desc.rts_sc);
+ SET_TX_DESC_RTS_SC(pdesc, tcb_desc->rts_sc);
SET_TX_DESC_RTS_SHORT(pdesc,
- ((tcb_desc.rts_rate <= DESC92C_RATE54M) ?
- (tcb_desc.rts_use_shortpreamble ? 1 : 0)
- : (tcb_desc.rts_use_shortgi ? 1 : 0)));
+ ((tcb_desc->rts_rate <= DESC92C_RATE54M) ?
+ (tcb_desc->rts_use_shortpreamble ? 1 : 0)
+ : (tcb_desc->rts_use_shortgi ? 1 : 0)));
- if (mac->bw_40) {
- if (tcb_desc.packet_bw) {
+ if (bw_40) {
+ if (tcb_desc->packet_bw) {
SET_TX_DESC_DATA_BW(pdesc, 1);
SET_TX_DESC_TX_SUB_CARRIER(pdesc, 3);
} else {
SET_TX_DESC_DATA_BW(pdesc, 0);
-
- if (rate_flag & IEEE80211_TX_RC_DUP_DATA) {
- SET_TX_DESC_TX_SUB_CARRIER(pdesc,
- mac->cur_40_prime_sc);
- }
+ SET_TX_DESC_TX_SUB_CARRIER(pdesc,
+ mac->cur_40_prime_sc);
}
} else {
SET_TX_DESC_DATA_BW(pdesc, 0);
@@ -810,13 +791,10 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
SET_TX_DESC_LINIP(pdesc, 0);
SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb->len);
- rcu_read_lock();
- sta = ieee80211_find_sta(mac->vif, mac->bssid);
if (sta) {
u8 ampdu_density = sta->ht_cap.ampdu_density;
SET_TX_DESC_AMPDU_DENSITY(pdesc, ampdu_density);
}
- rcu_read_unlock();
if (info->control.hw_key) {
struct ieee80211_key_conf *keyconf =
@@ -844,7 +822,7 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F);
SET_TX_DESC_RTS_RATE_FB_LIMIT(pdesc, 0xF);
SET_TX_DESC_DISABLE_FB(pdesc, 0);
- SET_TX_DESC_USE_RATE(pdesc, tcb_desc.use_driver_rate ? 1 : 0);
+ SET_TX_DESC_USE_RATE(pdesc, tcb_desc->use_driver_rate ? 1 : 0);
if (ieee80211_is_data_qos(fc)) {
if (mac->rdg_en) {
@@ -855,24 +833,24 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
}
}
}
+ rcu_read_unlock();
SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0));
SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0));
SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) skb->len);
- SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping));
+ SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
if (rtlpriv->dm.useramask) {
- SET_TX_DESC_RATE_ID(pdesc, tcb_desc.ratr_index);
- SET_TX_DESC_MACID(pdesc, tcb_desc.mac_id);
+ SET_TX_DESC_RATE_ID(pdesc, tcb_desc->ratr_index);
+ SET_TX_DESC_MACID(pdesc, tcb_desc->mac_id);
} else {
- SET_TX_DESC_RATE_ID(pdesc, 0xC + tcb_desc.ratr_index);
- SET_TX_DESC_MACID(pdesc, tcb_desc.ratr_index);
+ SET_TX_DESC_RATE_ID(pdesc, 0xC + tcb_desc->ratr_index);
+ SET_TX_DESC_MACID(pdesc, tcb_desc->ratr_index);
}
- if ((!ieee80211_is_data_qos(fc)) && ppsc->leisure_ps &&
- ppsc->fwctrl_lps) {
+ if ((!ieee80211_is_data_qos(fc)) && ppsc->fwctrl_lps) {
SET_TX_DESC_HWSEQ_EN(pdesc, 1);
SET_TX_DESC_PKT_ID(pdesc, 8);
@@ -923,7 +901,7 @@ void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw,
SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) (skb->len));
- SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping));
+ SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
SET_TX_DESC_RATE_ID(pdesc, 7);
SET_TX_DESC_MACID(pdesc, 0);
@@ -1021,7 +999,7 @@ u32 rtl92ce_get_desc(u8 *p_desc, bool istx, u8 desc_name)
return ret;
}
-void rtl92ce_tx_polling(struct ieee80211_hw *hw, unsigned int hw_queue)
+void rtl92ce_tx_polling(struct ieee80211_hw *hw, u8 hw_queue)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
if (hw_queue == BEACON_QUEUE) {
@@ -1032,35 +1010,3 @@ void rtl92ce_tx_polling(struct ieee80211_hw *hw, unsigned int hw_queue)
}
}
-bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw,
- struct sk_buff *skb)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- struct rtl8192_tx_ring *ring;
- struct rtl_tx_desc *pdesc;
- u8 own;
- unsigned long flags;
- struct sk_buff *pskb = NULL;
-
- ring = &rtlpci->tx_ring[BEACON_QUEUE];
-
- spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
-
- pskb = __skb_dequeue(&ring->queue);
- if (pskb)
- kfree_skb(pskb);
-
- pdesc = &ring->desc[0];
- own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN);
-
- rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
-
- __skb_queue_tail(&ring->queue, skb);
-
- spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
-
- rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
-
- return true;
-}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h
index 803adcc80c96..0f1177137501 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.h
@@ -532,9 +532,9 @@
#define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size) \
do { \
if (_size > TX_DESC_NEXT_DESC_OFFSET) \
- memset((void *)__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \
+ memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \
else \
- memset((void *)__pdesc, 0, _size); \
+ memset(__pdesc, 0, _size); \
} while (0);
#define RX_HAL_IS_CCK_RATE(_pdesc)\
@@ -724,17 +724,16 @@ struct rx_desc_92c {
void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr,
u8 *pdesc, struct ieee80211_tx_info *info,
- struct sk_buff *skb, unsigned int qsel);
+ struct sk_buff *skb, u8 hw_queue,
+ struct rtl_tcb_desc *ptcb_desc);
bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
struct rtl_stats *stats,
struct ieee80211_rx_status *rx_status,
u8 *pdesc, struct sk_buff *skb);
void rtl92ce_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val);
u32 rtl92ce_get_desc(u8 *pdesc, bool istx, u8 desc_name);
-void rtl92ce_tx_polling(struct ieee80211_hw *hw, unsigned int hw_queue);
+void rtl92ce_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
bool b_firstseg, bool b_lastseg,
struct sk_buff *skb);
-bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb);
-
#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
index 9444e76838cf..52e2af58c1ed 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
@@ -39,6 +39,7 @@
#include "mac.h"
#include "dm.h"
#include "hw.h"
+#include "../rtl8192ce/hw.h"
#include "trx.h"
#include "led.h"
#include "table.h"
@@ -605,10 +606,10 @@ void rtl92cu_read_eeprom_info(struct ieee80211_hw *hw)
if (!IS_NORMAL_CHIP(rtlhal->version))
return;
tmp_u1b = rtl_read_byte(rtlpriv, REG_9346CR);
- rtlefuse->epromtype = (tmp_u1b & EEPROMSEL) ?
+ rtlefuse->epromtype = (tmp_u1b & BOOT_FROM_EEPROM) ?
EEPROM_93C46 : EEPROM_BOOT_EFUSE;
RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("Boot from %s\n",
- (tmp_u1b & EEPROMSEL) ? "EERROM" : "EFUSE"));
+ (tmp_u1b & BOOT_FROM_EEPROM) ? "EERROM" : "EFUSE"));
rtlefuse->autoload_failflag = (tmp_u1b & EEPROM_EN) ? false : true;
RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Autoload %s\n",
(tmp_u1b & EEPROM_EN) ? "OK!!" : "ERR!!"));
@@ -921,7 +922,7 @@ static void _rtl92cu_init_chipT_queue_priority(struct ieee80211_hw *hw,
u8 out_ep_num,
u8 queue_sel)
{
- u8 hq_sele;
+ u8 hq_sele = 0;
struct rtl_priv *rtlpriv = rtl_priv(hw);
switch (out_ep_num) {
@@ -977,7 +978,7 @@ static void _rtl92cu_init_wmac_setting(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
- mac->rx_conf = (RCR_APM | RCR_AM | RCR_ADF | RCR_AB | RCR_APP_FCS |
+ mac->rx_conf = (RCR_APM | RCR_AM | RCR_ADF | RCR_AB | RCR_APPFCS |
RCR_APP_ICV | RCR_AMF | RCR_HTC_LOC_CTRL |
RCR_APP_MIC | RCR_APP_PHYSTS | RCR_ACRC32);
rtl_write_dword(rtlpriv, REG_RCR, mac->rx_conf);
@@ -2182,7 +2183,9 @@ void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
}
}
-void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw)
+void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ u8 rssi_level)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h
index 62af555bb61c..32f85cba106a 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.h
@@ -98,13 +98,14 @@ void rtl92cu_update_interrupt_mask(struct ieee80211_hw *hw,
u32 add_msr, u32 rm_msr);
void rtl92cu_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
void rtl92cu_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
-void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw);
+void rtl92cu_update_hal_rate_table(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ u8 rssi_level);
void rtl92cu_update_hal_rate_mask(struct ieee80211_hw *hw, u8 rssi_level);
void rtl92cu_update_channel_access_setting(struct ieee80211_hw *hw);
bool rtl92cu_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid);
void rtl92cu_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid);
-u8 _rtl92c_get_chnl_group(u8 chnl);
int rtl92c_download_fw(struct ieee80211_hw *hw);
void rtl92c_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
void rtl92c_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c
index 4e020e654e6b..9a3d0239e27e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c
@@ -38,7 +38,7 @@
#include "table.h"
u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw,
- enum radio_path rfpath, u32 regaddr, u32 bitmask)
+ enum radio_path rfpath, u32 regaddr, u32 bitmask)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
u32 original_value, readback_value, bitshift;
@@ -64,8 +64,8 @@ u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw,
}
void rtl92cu_phy_set_rf_reg(struct ieee80211_hw *hw,
- enum radio_path rfpath,
- u32 regaddr, u32 bitmask, u32 data)
+ enum radio_path rfpath,
+ u32 regaddr, u32 bitmask, u32 data)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
@@ -163,7 +163,7 @@ bool _rtl92cu_phy_config_mac_with_headerfile(struct ieee80211_hw *hw)
}
bool _rtl92cu_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
- u8 configtype)
+ u8 configtype)
{
int i;
u32 *phy_regarray_table;
@@ -223,7 +223,7 @@ bool _rtl92cu_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
}
bool _rtl92cu_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
- u8 configtype)
+ u8 configtype)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
@@ -459,7 +459,7 @@ void _rtl92cu_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t)
}
}
-bool _rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw,
+static bool _rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw,
enum rf_pwrstate rfpwr_state)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -595,7 +595,7 @@ bool _rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw,
}
bool rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw,
- enum rf_pwrstate rfpwr_state)
+ enum rf_pwrstate rfpwr_state)
{
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
bool bresult = false;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h
index 06299559ab68..ff81a61729d7 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.h
@@ -34,3 +34,17 @@ bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw, u32 rfpath);
void rtl92c_phy_set_io(struct ieee80211_hw *hw);
bool _rtl92cu_phy_config_mac_with_headerfile(struct ieee80211_hw *hw);
bool rtl92cu_phy_bb_config(struct ieee80211_hw *hw);
+u32 rtl92cu_phy_query_rf_reg(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 regaddr, u32 bitmask);
+void rtl92cu_phy_set_rf_reg(struct ieee80211_hw *hw,
+ enum radio_path rfpath,
+ u32 regaddr, u32 bitmask, u32 data);
+bool rtl92cu_phy_mac_config(struct ieee80211_hw *hw);
+bool _rtl92cu_phy_config_bb_with_pgheaderfile(struct ieee80211_hw *hw,
+ u8 configtype);
+void _rtl92cu_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t);
+bool _rtl92cu_phy_config_bb_with_headerfile(struct ieee80211_hw *hw,
+ u8 configtype);
+void rtl92cu_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
+bool rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw,
+ enum rf_pwrstate rfpwr_state);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
index 1c79c226f145..c7576ec4744e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.c
@@ -62,7 +62,7 @@ void rtl92cu_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
}
void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
- u8 *ppowerlevel)
+ u8 *ppowerlevel)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &(rtlpriv->phy);
@@ -389,7 +389,7 @@ static void _rtl92c_write_ofdm_power_reg(struct ieee80211_hw *hw,
}
void rtl92cu_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
- u8 *ppowerlevel, u8 channel)
+ u8 *ppowerlevel, u8 channel)
{
u32 writeVal[2], powerBase0[2], powerBase1[2];
u8 index = 0;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h
index 86c2728cfa00..500a2094b6bb 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/rf.h
@@ -43,5 +43,9 @@ extern void rtl92c_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
bool rtl92cu_phy_rf6052_config(struct ieee80211_hw *hw);
bool rtl92cu_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
enum radio_path rfpath);
+void rtl92cu_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
+ u8 *ppowerlevel);
+void rtl92cu_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
+ u8 *ppowerlevel, u8 channel);
#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
index 71244a38d49e..bee7c1480f63 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
@@ -94,7 +94,7 @@ static struct rtl_hal_ops rtl8192cu_hal_ops = {
.update_interrupt_mask = rtl92cu_update_interrupt_mask,
.get_hw_reg = rtl92cu_get_hw_reg,
.set_hw_reg = rtl92cu_set_hw_reg,
- .update_rate_table = rtl92cu_update_hal_rate_table,
+ .update_rate_tbl = rtl92cu_update_hal_rate_table,
.update_rate_mask = rtl92cu_update_hal_rate_mask,
.fill_tx_desc = rtl92cu_tx_fill_desc,
.fill_fake_txdesc = rtl92cu_fill_fake_txdesc,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
index d0b0d43b9a6d..3a92ba3c4a1e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
@@ -372,7 +372,7 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb)
__le16 fc;
struct ieee80211_hdr *hdr;
- memset(rx_status, 0, sizeof(rx_status));
+ memset(rx_status, 0, sizeof(*rx_status));
rxdesc = skb->data;
skb_len = skb->len;
drvinfo_len = (GET_RX_DESC_DRVINFO_SIZE(rxdesc) * RTL_RX_DRV_INFO_UNIT);
@@ -434,7 +434,7 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb)
"0x%02X\n", fc, (u32)hdr->addr1[0], (u32)hdr->addr1[1],
(u32)hdr->addr1[2], (u32)hdr->addr1[3], (u32)hdr->addr1[4],
(u32)hdr->addr1[5]));
- memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+ memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status));
ieee80211_rx_irqsafe(hw, skb);
}
@@ -498,14 +498,14 @@ static void _rtl_tx_desc_checksum(u8 *txdesc)
void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr, u8 *pdesc_tx,
struct ieee80211_tx_info *info, struct sk_buff *skb,
- unsigned int queue_index)
+ u8 queue_index,
+ struct rtl_tcb_desc *tcb_desc)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
bool defaultadapter = true;
- struct ieee80211_sta *sta;
- struct rtl_tcb_desc tcb_desc;
+ struct ieee80211_sta *sta = info->control.sta = info->control.sta;
u8 *qc = ieee80211_get_qos_ctl(hdr);
u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
u16 seq_number;
@@ -517,15 +517,15 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw,
u8 *txdesc;
seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
- rtl_get_tcb_desc(hw, info, skb, &tcb_desc);
+ rtl_get_tcb_desc(hw, info, sta, skb, tcb_desc);
txdesc = (u8 *)skb_push(skb, RTL_TX_HEADER_SIZE);
memset(txdesc, 0, RTL_TX_HEADER_SIZE);
SET_TX_DESC_PKT_SIZE(txdesc, pktlen);
SET_TX_DESC_LINIP(txdesc, 0);
SET_TX_DESC_PKT_OFFSET(txdesc, RTL_DUMMY_OFFSET);
SET_TX_DESC_OFFSET(txdesc, RTL_TX_HEADER_SIZE);
- SET_TX_DESC_TX_RATE(txdesc, tcb_desc.hw_rate);
- if (tcb_desc.use_shortgi || tcb_desc.use_shortpreamble)
+ SET_TX_DESC_TX_RATE(txdesc, tcb_desc->hw_rate);
+ if (tcb_desc->use_shortgi || tcb_desc->use_shortpreamble)
SET_TX_DESC_DATA_SHORTGI(txdesc, 1);
if (mac->tids[tid].agg.agg_state == RTL_AGG_ON &&
info->flags & IEEE80211_TX_CTL_AMPDU) {
@@ -535,21 +535,21 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw,
SET_TX_DESC_AGG_BREAK(txdesc, 1);
}
SET_TX_DESC_SEQ(txdesc, seq_number);
- SET_TX_DESC_RTS_ENABLE(txdesc, ((tcb_desc.rts_enable &&
- !tcb_desc.cts_enable) ? 1 : 0));
- SET_TX_DESC_HW_RTS_ENABLE(txdesc, ((tcb_desc.rts_enable ||
- tcb_desc.cts_enable) ? 1 : 0));
- SET_TX_DESC_CTS2SELF(txdesc, ((tcb_desc.cts_enable) ? 1 : 0));
- SET_TX_DESC_RTS_STBC(txdesc, ((tcb_desc.rts_stbc) ? 1 : 0));
- SET_TX_DESC_RTS_RATE(txdesc, tcb_desc.rts_rate);
+ SET_TX_DESC_RTS_ENABLE(txdesc, ((tcb_desc->rts_enable &&
+ !tcb_desc->cts_enable) ? 1 : 0));
+ SET_TX_DESC_HW_RTS_ENABLE(txdesc, ((tcb_desc->rts_enable ||
+ tcb_desc->cts_enable) ? 1 : 0));
+ SET_TX_DESC_CTS2SELF(txdesc, ((tcb_desc->cts_enable) ? 1 : 0));
+ SET_TX_DESC_RTS_STBC(txdesc, ((tcb_desc->rts_stbc) ? 1 : 0));
+ SET_TX_DESC_RTS_RATE(txdesc, tcb_desc->rts_rate);
SET_TX_DESC_RTS_BW(txdesc, 0);
- SET_TX_DESC_RTS_SC(txdesc, tcb_desc.rts_sc);
+ SET_TX_DESC_RTS_SC(txdesc, tcb_desc->rts_sc);
SET_TX_DESC_RTS_SHORT(txdesc,
- ((tcb_desc.rts_rate <= DESC92C_RATE54M) ?
- (tcb_desc.rts_use_shortpreamble ? 1 : 0)
- : (tcb_desc.rts_use_shortgi ? 1 : 0)));
+ ((tcb_desc->rts_rate <= DESC92C_RATE54M) ?
+ (tcb_desc->rts_use_shortpreamble ? 1 : 0)
+ : (tcb_desc->rts_use_shortgi ? 1 : 0)));
if (mac->bw_40) {
- if (tcb_desc.packet_bw) {
+ if (tcb_desc->packet_bw) {
SET_TX_DESC_DATA_BW(txdesc, 1);
SET_TX_DESC_DATA_SC(txdesc, 3);
} else {
@@ -590,7 +590,7 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw,
SET_TX_DESC_DATA_RATE_FB_LIMIT(txdesc, 0x1F);
SET_TX_DESC_RTS_RATE_FB_LIMIT(txdesc, 0xF);
SET_TX_DESC_DISABLE_FB(txdesc, 0);
- SET_TX_DESC_USE_RATE(txdesc, tcb_desc.use_driver_rate ? 1 : 0);
+ SET_TX_DESC_USE_RATE(txdesc, tcb_desc->use_driver_rate ? 1 : 0);
if (ieee80211_is_data_qos(fc)) {
if (mac->rdg_en) {
RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
@@ -600,11 +600,11 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw,
}
}
if (rtlpriv->dm.useramask) {
- SET_TX_DESC_RATE_ID(txdesc, tcb_desc.ratr_index);
- SET_TX_DESC_MACID(txdesc, tcb_desc.mac_id);
+ SET_TX_DESC_RATE_ID(txdesc, tcb_desc->ratr_index);
+ SET_TX_DESC_MACID(txdesc, tcb_desc->mac_id);
} else {
- SET_TX_DESC_RATE_ID(txdesc, 0xC + tcb_desc.ratr_index);
- SET_TX_DESC_MACID(txdesc, tcb_desc.ratr_index);
+ SET_TX_DESC_RATE_ID(txdesc, 0xC + tcb_desc->ratr_index);
+ SET_TX_DESC_MACID(txdesc, tcb_desc->ratr_index);
}
if ((!ieee80211_is_data_qos(fc)) && ppsc->leisure_ps &&
ppsc->fwctrl_lps) {
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h
index b396d46edbb7..53de5f66e242 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.h
@@ -37,6 +37,8 @@
#define RTL92C_SIZE_MAX_RX_BUFFER 15360 /* 8192 */
#define RX_DRV_INFO_SIZE_UNIT 8
+#define RTL_AGG_ON 1
+
enum usb_rx_agg_mode {
USB_RX_AGG_DISABLE,
USB_RX_AGG_DMA,
@@ -419,7 +421,8 @@ struct sk_buff *rtl8192c_tx_aggregate_hdl(struct ieee80211_hw *,
void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr, u8 *pdesc_tx,
struct ieee80211_tx_info *info, struct sk_buff *skb,
- unsigned int queue_index);
+ u8 queue_index,
+ struct rtl_tcb_desc *tcb_desc);
void rtl92cu_fill_fake_txdesc(struct ieee80211_hw *hw, u8 * pDesc,
u32 buffer_len, bool bIsPsPoll);
void rtl92cu_tx_fill_cmddesc(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/Makefile b/drivers/net/wireless/rtlwifi/rtl8192se/Makefile
new file mode 100644
index 000000000000..b7eb13819cbc
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/Makefile
@@ -0,0 +1,15 @@
+rtl8192se-objs := \
+ dm.o \
+ fw.o \
+ hw.o \
+ led.o \
+ phy.o \
+ rf.o \
+ sw.o \
+ table.o \
+ trx.o
+
+obj-$(CONFIG_RTL8192SE) += rtl8192se.o
+
+ccflags-y += -D__CHECK_ENDIAN__
+
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/def.h b/drivers/net/wireless/rtlwifi/rtl8192se/def.h
new file mode 100644
index 000000000000..69828f2b3fab
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/def.h
@@ -0,0 +1,598 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#ifndef __REALTEK_92S_DEF_H__
+#define __REALTEK_92S_DEF_H__
+
+#define RX_MPDU_QUEUE 0
+#define RX_CMD_QUEUE 1
+#define RX_MAX_QUEUE 2
+
+#define DESC92S_RATE1M 0x00
+#define DESC92S_RATE2M 0x01
+#define DESC92S_RATE5_5M 0x02
+#define DESC92S_RATE11M 0x03
+#define DESC92S_RATE6M 0x04
+#define DESC92S_RATE9M 0x05
+#define DESC92S_RATE12M 0x06
+#define DESC92S_RATE18M 0x07
+#define DESC92S_RATE24M 0x08
+#define DESC92S_RATE36M 0x09
+#define DESC92S_RATE48M 0x0a
+#define DESC92S_RATE54M 0x0b
+#define DESC92S_RATEMCS0 0x0c
+#define DESC92S_RATEMCS1 0x0d
+#define DESC92S_RATEMCS2 0x0e
+#define DESC92S_RATEMCS3 0x0f
+#define DESC92S_RATEMCS4 0x10
+#define DESC92S_RATEMCS5 0x11
+#define DESC92S_RATEMCS6 0x12
+#define DESC92S_RATEMCS7 0x13
+#define DESC92S_RATEMCS8 0x14
+#define DESC92S_RATEMCS9 0x15
+#define DESC92S_RATEMCS10 0x16
+#define DESC92S_RATEMCS11 0x17
+#define DESC92S_RATEMCS12 0x18
+#define DESC92S_RATEMCS13 0x19
+#define DESC92S_RATEMCS14 0x1a
+#define DESC92S_RATEMCS15 0x1b
+#define DESC92S_RATEMCS15_SG 0x1c
+#define DESC92S_RATEMCS32 0x20
+
+#define SHORT_SLOT_TIME 9
+#define NON_SHORT_SLOT_TIME 20
+
+/* Rx smooth factor */
+#define RX_SMOOTH_FACTOR 20
+
+/* Queue Select Value in TxDesc */
+#define QSLT_BK 0x2
+#define QSLT_BE 0x0
+#define QSLT_VI 0x5
+#define QSLT_VO 0x6
+#define QSLT_BEACON 0x10
+#define QSLT_HIGH 0x11
+#define QSLT_MGNT 0x12
+#define QSLT_CMD 0x13
+
+#define PHY_RSSI_SLID_WIN_MAX 100
+#define PHY_LINKQUALITY_SLID_WIN_MAX 20
+#define PHY_BEACON_RSSI_SLID_WIN_MAX 10
+
+/* Tx Desc */
+#define TX_DESC_SIZE_RTL8192S (16 * 4)
+#define TX_CMDDESC_SIZE_RTL8192S (16 * 4)
+
+/* Define a macro that takes a le32 word, converts it to host ordering,
+ * right shifts by a specified count, creates a mask of the specified
+ * bit count, and extracts that number of bits.
+ */
+
+#define SHIFT_AND_MASK_LE(__pdesc, __shift, __mask) \
+ ((le32_to_cpu(*(((__le32 *)(__pdesc)))) >> (__shift)) & \
+ BIT_LEN_MASK_32(__mask))
+
+/* Define a macro that clears a bit field in an le32 word and
+ * sets the specified value into that bit field. The resulting
+ * value remains in le32 ordering; however, it is properly converted
+ * to host ordering for the clear and set operations before conversion
+ * back to le32.
+ */
+
+#define SET_BITS_OFFSET_LE(__pdesc, __shift, __len, __val) \
+ (*(__le32 *)(__pdesc) = \
+ (cpu_to_le32((le32_to_cpu(*((__le32 *)(__pdesc))) & \
+ (~(BIT_OFFSET_LEN_MASK_32((__shift), __len)))) | \
+ (((u32)(__val) & BIT_LEN_MASK_32(__len)) << (__shift)))));
+
+/* macros to read/write various fields in RX or TX descriptors */
+
+/* Dword 0 */
+#define SET_TX_DESC_PKT_SIZE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 0, 16, __val)
+#define SET_TX_DESC_OFFSET(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 16, 8, __val)
+#define SET_TX_DESC_TYPE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 24, 2, __val)
+#define SET_TX_DESC_LAST_SEG(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 26, 1, __val)
+#define SET_TX_DESC_FIRST_SEG(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 27, 1, __val)
+#define SET_TX_DESC_LINIP(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 28, 1, __val)
+#define SET_TX_DESC_AMSDU(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 29, 1, __val)
+#define SET_TX_DESC_GREEN_FIELD(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 30, 1, __val)
+#define SET_TX_DESC_OWN(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 31, 1, __val)
+
+#define GET_TX_DESC_OWN(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 31, 1)
+
+/* Dword 1 */
+#define SET_TX_DESC_MACID(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 0, 5, __val)
+#define SET_TX_DESC_MORE_DATA(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 5, 1, __val)
+#define SET_TX_DESC_MORE_FRAG(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 6, 1, __val)
+#define SET_TX_DESC_PIFS(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 7, 1, __val)
+#define SET_TX_DESC_QUEUE_SEL(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 8, 5, __val)
+#define SET_TX_DESC_ACK_POLICY(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 13, 2, __val)
+#define SET_TX_DESC_NO_ACM(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 15, 1, __val)
+#define SET_TX_DESC_NON_QOS(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 16, 1, __val)
+#define SET_TX_DESC_KEY_ID(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 17, 2, __val)
+#define SET_TX_DESC_OUI(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 19, 1, __val)
+#define SET_TX_DESC_PKT_TYPE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 20, 1, __val)
+#define SET_TX_DESC_EN_DESC_ID(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 21, 1, __val)
+#define SET_TX_DESC_SEC_TYPE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 22, 2, __val)
+#define SET_TX_DESC_WDS(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 24, 1, __val)
+#define SET_TX_DESC_HTC(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 25, 1, __val)
+#define SET_TX_DESC_PKT_OFFSET(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 26, 5, __val)
+#define SET_TX_DESC_HWPC(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 27, 1, __val)
+
+/* Dword 2 */
+#define SET_TX_DESC_DATA_RETRY_LIMIT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 8, 0, 6, __val)
+#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 8, 6, 1, __val)
+#define SET_TX_DESC_TSFL(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 8, 7, 5, __val)
+#define SET_TX_DESC_RTS_RETRY_COUNT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 8, 12, 6, __val)
+#define SET_TX_DESC_DATA_RETRY_COUNT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 8, 18, 6, __val)
+#define SET_TX_DESC_RSVD_MACID(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(((__pdesc) + 8), 24, 5, __val)
+#define SET_TX_DESC_AGG_ENABLE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 8, 29, 1, __val)
+#define SET_TX_DESC_AGG_BREAK(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 8, 30, 1, __val)
+#define SET_TX_DESC_OWN_MAC(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 8, 31, 1, __val)
+
+/* Dword 3 */
+#define SET_TX_DESC_NEXT_HEAP_PAGE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 0, 8, __val)
+#define SET_TX_DESC_TAIL_PAGE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 8, 8, __val)
+#define SET_TX_DESC_SEQ(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 16, 12, __val)
+#define SET_TX_DESC_FRAG(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 28, 4, __val)
+
+/* Dword 4 */
+#define SET_TX_DESC_RTS_RATE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 0, 6, __val)
+#define SET_TX_DESC_DISABLE_RTS_FB(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 6, 1, __val)
+#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 7, 4, __val)
+#define SET_TX_DESC_CTS_ENABLE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 11, 1, __val)
+#define SET_TX_DESC_RTS_ENABLE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 12, 1, __val)
+#define SET_TX_DESC_RA_BRSR_ID(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 13, 3, __val)
+#define SET_TX_DESC_TXHT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 16, 1, __val)
+#define SET_TX_DESC_TX_SHORT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 17, 1, __val)
+#define SET_TX_DESC_TX_BANDWIDTH(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 18, 1, __val)
+#define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 19, 2, __val)
+#define SET_TX_DESC_TX_STBC(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 21, 2, __val)
+#define SET_TX_DESC_TX_REVERSE_DIRECTION(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 23, 1, __val)
+#define SET_TX_DESC_RTS_HT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 24, 1, __val)
+#define SET_TX_DESC_RTS_SHORT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 25, 1, __val)
+#define SET_TX_DESC_RTS_BANDWIDTH(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 26, 1, __val)
+#define SET_TX_DESC_RTS_SUB_CARRIER(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 27, 2, __val)
+#define SET_TX_DESC_RTS_STBC(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 29, 2, __val)
+#define SET_TX_DESC_USER_RATE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 31, 1, __val)
+
+/* Dword 5 */
+#define SET_TX_DESC_PACKET_ID(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 20, 0, 9, __val)
+#define SET_TX_DESC_TX_RATE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 20, 9, 6, __val)
+#define SET_TX_DESC_DISABLE_FB(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 20, 15, 1, __val)
+#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 20, 16, 5, __val)
+#define SET_TX_DESC_TX_AGC(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 20, 21, 11, __val)
+
+/* Dword 6 */
+#define SET_TX_DESC_IP_CHECK_SUM(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 24, 0, 16, __val)
+#define SET_TX_DESC_TCP_CHECK_SUM(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 24, 16, 16, __val)
+
+/* Dword 7 */
+#define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 28, 0, 16, __val)
+#define SET_TX_DESC_IP_HEADER_OFFSET(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 28, 16, 8, __val)
+#define SET_TX_DESC_TCP_ENABLE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 28, 31, 1, __val)
+
+/* Dword 8 */
+#define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 32, 0, 32, __val)
+#define GET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 32, 0, 32)
+
+/* Dword 9 */
+#define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 36, 0, 32, __val)
+
+/* Because the PCI Tx descriptors are chaied at the
+ * initialization and all the NextDescAddresses in
+ * these descriptors cannot not be cleared (,or
+ * driver/HW cannot find the next descriptor), the
+ * offset 36 (NextDescAddresses) is reserved when
+ * the desc is cleared. */
+#define TX_DESC_NEXT_DESC_OFFSET 36
+#define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size) \
+do { \
+ if (_size > TX_DESC_NEXT_DESC_OFFSET) \
+ memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \
+ else \
+ memset(__pdesc, 0, _size); \
+} while (0);
+
+/* Rx Desc */
+#define RX_STATUS_DESC_SIZE 24
+#define RX_DRV_INFO_SIZE_UNIT 8
+
+/* DWORD 0 */
+#define SET_RX_STATUS_DESC_PKT_LEN(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 0, 14, __val)
+#define SET_RX_STATUS_DESC_CRC32(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 14, 1, __val)
+#define SET_RX_STATUS_DESC_ICV(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 15, 1, __val)
+#define SET_RX_STATUS_DESC_DRVINFO_SIZE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 16, 4, __val)
+#define SET_RX_STATUS_DESC_SECURITY(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 20, 3, __val)
+#define SET_RX_STATUS_DESC_QOS(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 23, 1, __val)
+#define SET_RX_STATUS_DESC_SHIFT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 24, 2, __val)
+#define SET_RX_STATUS_DESC_PHY_STATUS(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 26, 1, __val)
+#define SET_RX_STATUS_DESC_SWDEC(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 27, 1, __val)
+#define SET_RX_STATUS_DESC_LAST_SEG(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 28, 1, __val)
+#define SET_RX_STATUS_DESC_FIRST_SEG(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 29, 1, __val)
+#define SET_RX_STATUS_DESC_EOR(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 30, 1, __val)
+#define SET_RX_STATUS_DESC_OWN(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 31, 1, __val)
+
+#define GET_RX_STATUS_DESC_PKT_LEN(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 0, 14)
+#define GET_RX_STATUS_DESC_CRC32(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 14, 1)
+#define GET_RX_STATUS_DESC_ICV(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 15, 1)
+#define GET_RX_STATUS_DESC_DRVINFO_SIZE(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 16, 4)
+#define GET_RX_STATUS_DESC_SECURITY(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 20, 3)
+#define GET_RX_STATUS_DESC_QOS(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 23, 1)
+#define GET_RX_STATUS_DESC_SHIFT(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 24, 2)
+#define GET_RX_STATUS_DESC_PHY_STATUS(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 26, 1)
+#define GET_RX_STATUS_DESC_SWDEC(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 27, 1)
+#define GET_RX_STATUS_DESC_LAST_SEG(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 28, 1)
+#define GET_RX_STATUS_DESC_FIRST_SEG(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 29, 1)
+#define GET_RX_STATUS_DESC_EOR(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 30, 1)
+#define GET_RX_STATUS_DESC_OWN(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 31, 1)
+
+/* DWORD 1 */
+#define SET_RX_STATUS_DESC_MACID(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 0, 5, __val)
+#define SET_RX_STATUS_DESC_TID(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 5, 4, __val)
+#define SET_RX_STATUS_DESC_PAGGR(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 14, 1, __val)
+#define SET_RX_STATUS_DESC_FAGGR(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 15, 1, __val)
+#define SET_RX_STATUS_DESC_A1_FIT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 16, 4, __val)
+#define SET_RX_STATUS_DESC_A2_FIT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 20, 4, __val)
+#define SET_RX_STATUS_DESC_PAM(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 24, 1, __val)
+#define SET_RX_STATUS_DESC_PWR(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 25, 1, __val)
+#define SET_RX_STATUS_DESC_MOREDATA(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 26, 1, __val)
+#define SET_RX_STATUS_DESC_MOREFRAG(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 27, 1, __val)
+#define SET_RX_STATUS_DESC_TYPE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 28, 2, __val)
+#define SET_RX_STATUS_DESC_MC(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 30, 1, __val)
+#define SET_RX_STATUS_DESC_BC(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 31, 1, __val)
+
+#define GET_RX_STATUS_DEC_MACID(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 0, 5)
+#define GET_RX_STATUS_DESC_TID(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 5, 4)
+#define GET_RX_STATUS_DESC_PAGGR(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 14, 1)
+#define GET_RX_STATUS_DESC_FAGGR(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 15, 1)
+#define GET_RX_STATUS_DESC_A1_FIT(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 16, 4)
+#define GET_RX_STATUS_DESC_A2_FIT(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 20, 4)
+#define GET_RX_STATUS_DESC_PAM(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 24, 1)
+#define GET_RX_STATUS_DESC_PWR(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 25, 1)
+#define GET_RX_STATUS_DESC_MORE_DATA(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 26, 1)
+#define GET_RX_STATUS_DESC_MORE_FRAG(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 27, 1)
+#define GET_RX_STATUS_DESC_TYPE(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 28, 2)
+#define GET_RX_STATUS_DESC_MC(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 30, 1)
+#define GET_RX_STATUS_DESC_BC(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 31, 1)
+
+/* DWORD 2 */
+#define SET_RX_STATUS_DESC_SEQ(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 8, 0, 12, __val)
+#define SET_RX_STATUS_DESC_FRAG(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 8, 12, 4, __val)
+#define SET_RX_STATUS_DESC_NEXT_PKTLEN(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 8, 16, 8, __val)
+#define SET_RX_STATUS_DESC_NEXT_IND(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 8, 30, 1, __val)
+
+#define GET_RX_STATUS_DESC_SEQ(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 8, 0, 12)
+#define GET_RX_STATUS_DESC_FRAG(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 8, 12, 4)
+#define GET_RX_STATUS_DESC_NEXT_PKTLEN(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 8, 16, 8)
+#define GET_RX_STATUS_DESC_NEXT_IND(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 8, 30, 1)
+
+/* DWORD 3 */
+#define SET_RX_STATUS_DESC_RX_MCS(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 0, 6, __val)
+#define SET_RX_STATUS_DESC_RX_HT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 6, 1, __val)
+#define SET_RX_STATUS_DESC_AMSDU(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 7, 1, __val)
+#define SET_RX_STATUS_DESC_SPLCP(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 8, 1, __val)
+#define SET_RX_STATUS_DESC_BW(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 9, 1, __val)
+#define SET_RX_STATUS_DESC_HTC(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 10, 1, __val)
+#define SET_RX_STATUS_DESC_TCP_CHK_RPT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 11, 1, __val)
+#define SET_RX_STATUS_DESC_IP_CHK_RPT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 12, 1, __val)
+#define SET_RX_STATUS_DESC_TCP_CHK_VALID(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 13, 1, __val)
+#define SET_RX_STATUS_DESC_HWPC_ERR(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 14, 1, __val)
+#define SET_RX_STATUS_DESC_HWPC_IND(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 15, 1, __val)
+#define SET_RX_STATUS_DESC_IV0(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 16, 16, __val)
+
+#define GET_RX_STATUS_DESC_RX_MCS(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 12, 0, 6)
+#define GET_RX_STATUS_DESC_RX_HT(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 12, 6, 1)
+#define GET_RX_STATUS_DESC_AMSDU(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 12, 7, 1)
+#define GET_RX_STATUS_DESC_SPLCP(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 12, 8, 1)
+#define GET_RX_STATUS_DESC_BW(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 12, 9, 1)
+#define GET_RX_STATUS_DESC_HTC(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 12, 10, 1)
+#define GET_RX_STATUS_DESC_TCP_CHK_RPT(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 12, 11, 1)
+#define GET_RX_STATUS_DESC_IP_CHK_RPT(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 12, 12, 1)
+#define GET_RX_STATUS_DESC_TCP_CHK_VALID(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 12, 13, 1)
+#define GET_RX_STATUS_DESC_HWPC_ERR(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 12, 14, 1)
+#define GET_RX_STATUS_DESC_HWPC_IND(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 12, 15, 1)
+#define GET_RX_STATUS_DESC_IV0(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 12, 16, 16)
+
+/* DWORD 4 */
+#define SET_RX_STATUS_DESC_IV1(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 0, 32, __val)
+#define GET_RX_STATUS_DESC_IV1(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 16, 0, 32)
+
+/* DWORD 5 */
+#define SET_RX_STATUS_DESC_TSFL(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 20, 0, 32, __val)
+#define GET_RX_STATUS_DESC_TSFL(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 20, 0, 32)
+
+/* DWORD 6 */
+#define SET_RX_STATUS__DESC_BUFF_ADDR(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 24, 0, 32, __val)
+
+#define RX_HAL_IS_CCK_RATE(_pdesc)\
+ (GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE1M || \
+ GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE2M || \
+ GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE5_5M ||\
+ GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE11M)
+
+enum rf_optype {
+ RF_OP_BY_SW_3WIRE = 0,
+ RF_OP_BY_FW,
+ RF_OP_MAX
+};
+
+enum ic_inferiority {
+ IC_INFERIORITY_A = 0,
+ IC_INFERIORITY_B = 1,
+};
+
+enum fwcmd_iotype {
+ /* For DIG DM */
+ FW_CMD_DIG_ENABLE = 0,
+ FW_CMD_DIG_DISABLE = 1,
+ FW_CMD_DIG_HALT = 2,
+ FW_CMD_DIG_RESUME = 3,
+ /* For High Power DM */
+ FW_CMD_HIGH_PWR_ENABLE = 4,
+ FW_CMD_HIGH_PWR_DISABLE = 5,
+ /* For Rate adaptive DM */
+ FW_CMD_RA_RESET = 6,
+ 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_INIT = 11,
+ /* Tx power tracking switch,
+ * MP driver only */
+ FW_CMD_TXPWR_TRACK_ENABLE = 12,
+ /* Tx power tracking switch,
+ * MP driver only */
+ FW_CMD_TXPWR_TRACK_DISABLE = 13,
+ /* Tx power tracking with thermal
+ * indication, for Normal driver */
+ FW_CMD_TXPWR_TRACK_THERMAL = 14,
+ FW_CMD_PAUSE_DM_BY_SCAN = 15,
+ FW_CMD_RESUME_DM_BY_SCAN = 16,
+ 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,
+ /* Tx Status report for CCX from FW */
+ FW_CMD_TX_FEEDBACK_CCX_ENABLE = 21,
+ /* Indifate firmware that driver
+ * enters LPS, For PS-Poll issue */
+ FW_CMD_LPS_ENTER = 22,
+ /* Indicate firmware that driver
+ * leave LPS*/
+ FW_CMD_LPS_LEAVE = 23,
+ /* Set DIG mode to signal strength */
+ FW_CMD_DIG_MODE_SS = 24,
+ /* Set DIG mode to false alarm. */
+ 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_PAPE_CONTROL = 29,
+ FW_CMD_IQK_ENABLE = 30,
+};
+
+/*
+ * Driver info contain PHY status
+ * and other variabel size info
+ * PHY Status content as below
+ */
+struct rx_fwinfo {
+ /* DWORD 0 */
+ u8 gain_trsw[4];
+ /* DWORD 1 */
+ u8 pwdb_all;
+ u8 cfosho[4];
+ /* DWORD 2 */
+ u8 cfotail[4];
+ /* DWORD 3 */
+ s8 rxevm[2];
+ s8 rxsnr[4];
+ /* DWORD 4 */
+ u8 pdsnr[2];
+ /* DWORD 5 */
+ u8 csi_current[2];
+ u8 csi_target[2];
+ /* DWORD 6 */
+ u8 sigevm;
+ u8 max_ex_pwr;
+ u8 ex_intf_flag:1;
+ u8 sgi_en:1;
+ u8 rxsc:2;
+ u8 reserve:4;
+};
+
+struct phy_sts_cck_8192s_t {
+ u8 adc_pwdb_x[4];
+ u8 sq_rpt;
+ u8 cck_agc_rpt;
+};
+
+#endif
+
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c
new file mode 100644
index 000000000000..da86db86fa4a
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c
@@ -0,0 +1,733 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../base.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "fw.h"
+
+struct dig_t digtable;
+static const u32 edca_setting_dl[PEER_MAX] = {
+ 0xa44f, /* 0 UNKNOWN */
+ 0x5ea44f, /* 1 REALTEK_90 */
+ 0x5ea44f, /* 2 REALTEK_92SE */
+ 0xa630, /* 3 BROAD */
+ 0xa44f, /* 4 RAL */
+ 0xa630, /* 5 ATH */
+ 0xa630, /* 6 CISCO */
+ 0xa42b, /* 7 MARV */
+};
+
+static const u32 edca_setting_dl_gmode[PEER_MAX] = {
+ 0x4322, /* 0 UNKNOWN */
+ 0xa44f, /* 1 REALTEK_90 */
+ 0x5ea44f, /* 2 REALTEK_92SE */
+ 0xa42b, /* 3 BROAD */
+ 0x5e4322, /* 4 RAL */
+ 0x4322, /* 5 ATH */
+ 0xa430, /* 6 CISCO */
+ 0x5ea44f, /* 7 MARV */
+};
+
+static const u32 edca_setting_ul[PEER_MAX] = {
+ 0x5e4322, /* 0 UNKNOWN */
+ 0xa44f, /* 1 REALTEK_90 */
+ 0x5ea44f, /* 2 REALTEK_92SE */
+ 0x5ea322, /* 3 BROAD */
+ 0x5ea422, /* 4 RAL */
+ 0x5ea322, /* 5 ATH */
+ 0x3ea44f, /* 6 CISCO */
+ 0x5ea44f, /* 7 MARV */
+};
+
+static void _rtl92s_dm_check_edca_turbo(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
+ static u64 last_txok_cnt;
+ static u64 last_rxok_cnt;
+ u64 cur_txok_cnt = 0;
+ u64 cur_rxok_cnt = 0;
+
+ u32 edca_be_ul = edca_setting_ul[mac->vendor];
+ u32 edca_be_dl = edca_setting_dl[mac->vendor];
+ u32 edca_gmode = edca_setting_dl_gmode[mac->vendor];
+
+ if (mac->link_state != MAC80211_LINKED) {
+ rtlpriv->dm.current_turbo_edca = false;
+ goto dm_checkedcaturbo_exit;
+ }
+
+ if ((!rtlpriv->dm.is_any_nonbepkts) &&
+ (!rtlpriv->dm.disable_framebursting)) {
+ cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt;
+ cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt;
+
+ if (rtlpriv->phy.rf_type == RF_1T2R) {
+ if (cur_txok_cnt > 4 * cur_rxok_cnt) {
+ /* Uplink TP is present. */
+ if (rtlpriv->dm.is_cur_rdlstate ||
+ !rtlpriv->dm.current_turbo_edca) {
+ rtl_write_dword(rtlpriv, EDCAPARA_BE,
+ edca_be_ul);
+ rtlpriv->dm.is_cur_rdlstate = false;
+ }
+ } else {/* Balance TP is present. */
+ if (!rtlpriv->dm.is_cur_rdlstate ||
+ !rtlpriv->dm.current_turbo_edca) {
+ if (mac->mode == WIRELESS_MODE_G ||
+ mac->mode == WIRELESS_MODE_B)
+ rtl_write_dword(rtlpriv,
+ EDCAPARA_BE,
+ edca_gmode);
+ else
+ rtl_write_dword(rtlpriv,
+ EDCAPARA_BE,
+ edca_be_dl);
+ rtlpriv->dm.is_cur_rdlstate = true;
+ }
+ }
+ rtlpriv->dm.current_turbo_edca = true;
+ } else {
+ if (cur_rxok_cnt > 4 * cur_txok_cnt) {
+ if (!rtlpriv->dm.is_cur_rdlstate ||
+ !rtlpriv->dm.current_turbo_edca) {
+ if (mac->mode == WIRELESS_MODE_G ||
+ mac->mode == WIRELESS_MODE_B)
+ rtl_write_dword(rtlpriv,
+ EDCAPARA_BE,
+ edca_gmode);
+ else
+ rtl_write_dword(rtlpriv,
+ EDCAPARA_BE,
+ edca_be_dl);
+ rtlpriv->dm.is_cur_rdlstate = true;
+ }
+ } else {
+ if (rtlpriv->dm.is_cur_rdlstate ||
+ !rtlpriv->dm.current_turbo_edca) {
+ rtl_write_dword(rtlpriv, EDCAPARA_BE,
+ edca_be_ul);
+ rtlpriv->dm.is_cur_rdlstate = false;
+ }
+ }
+ rtlpriv->dm.current_turbo_edca = true;
+ }
+ } else {
+ if (rtlpriv->dm.current_turbo_edca) {
+ u8 tmp = AC0_BE;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
+ (u8 *)(&tmp));
+ rtlpriv->dm.current_turbo_edca = false;
+ }
+ }
+
+dm_checkedcaturbo_exit:
+ rtlpriv->dm.is_any_nonbepkts = false;
+ last_txok_cnt = rtlpriv->stats.txbytesunicast;
+ last_rxok_cnt = rtlpriv->stats.rxbytesunicast;
+}
+
+static void _rtl92s_dm_txpowertracking_callback_thermalmeter(
+ struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 thermalvalue = 0;
+
+ rtlpriv->dm.txpower_trackinginit = true;
+
+ thermalvalue = (u8)rtl_get_rfreg(hw, RF90_PATH_A, RF_T_METER, 0x1f);
+
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ ("Readback Thermal Meter = 0x%x pre thermal meter 0x%x "
+ "eeprom_thermalmeter 0x%x\n", thermalvalue,
+ rtlpriv->dm.thermalvalue, rtlefuse->eeprom_thermalmeter));
+
+ if (thermalvalue) {
+ rtlpriv->dm.thermalvalue = thermalvalue;
+ rtl92s_phy_set_fw_cmd(hw, FW_CMD_TXPWR_TRACK_THERMAL);
+ }
+
+ rtlpriv->dm.txpowercount = 0;
+}
+
+static void _rtl92s_dm_check_txpowertracking_thermalmeter(
+ struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ static u8 tm_trigger;
+ u8 tx_power_checkcnt = 5;
+
+ /* 2T2R TP issue */
+ if (rtlphy->rf_type == RF_2T2R)
+ return;
+
+ if (!rtlpriv->dm.txpower_tracking)
+ return;
+
+ if (rtlpriv->dm.txpowercount <= tx_power_checkcnt) {
+ rtlpriv->dm.txpowercount++;
+ return;
+ }
+
+ if (!tm_trigger) {
+ rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER,
+ RFREG_OFFSET_MASK, 0x60);
+ tm_trigger = 1;
+ } else {
+ _rtl92s_dm_txpowertracking_callback_thermalmeter(hw);
+ tm_trigger = 0;
+ }
+}
+
+static void _rtl92s_dm_refresh_rateadaptive_mask(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rate_adaptive *ra = &(rtlpriv->ra);
+
+ u32 low_rssi_thresh = 0;
+ u32 middle_rssi_thresh = 0;
+ u32 high_rssi_thresh = 0;
+ u8 rssi_level;
+ struct ieee80211_sta *sta = NULL;
+
+ if (is_hal_stop(rtlhal))
+ return;
+
+ if (!rtlpriv->dm.useramask)
+ return;
+
+ if (!rtlpriv->dm.inform_fw_driverctrldm) {
+ rtl92s_phy_set_fw_cmd(hw, FW_CMD_CTRL_DM_BY_DRIVER);
+ rtlpriv->dm.inform_fw_driverctrldm = true;
+ }
+
+ rcu_read_lock();
+ if (mac->opmode == NL80211_IFTYPE_STATION)
+ sta = get_sta(hw, mac->vif, mac->bssid);
+ if ((mac->link_state == MAC80211_LINKED) &&
+ (mac->opmode == NL80211_IFTYPE_STATION)) {
+ switch (ra->pre_ratr_state) {
+ case DM_RATR_STA_HIGH:
+ high_rssi_thresh = 40;
+ middle_rssi_thresh = 30;
+ low_rssi_thresh = 20;
+ break;
+ case DM_RATR_STA_MIDDLE:
+ high_rssi_thresh = 44;
+ middle_rssi_thresh = 30;
+ low_rssi_thresh = 20;
+ break;
+ case DM_RATR_STA_LOW:
+ high_rssi_thresh = 44;
+ middle_rssi_thresh = 34;
+ low_rssi_thresh = 20;
+ break;
+ case DM_RATR_STA_ULTRALOW:
+ high_rssi_thresh = 44;
+ middle_rssi_thresh = 34;
+ low_rssi_thresh = 24;
+ break;
+ default:
+ high_rssi_thresh = 44;
+ middle_rssi_thresh = 34;
+ low_rssi_thresh = 24;
+ break;
+ }
+
+ if (rtlpriv->dm.undecorated_smoothed_pwdb >
+ (long)high_rssi_thresh) {
+ ra->ratr_state = DM_RATR_STA_HIGH;
+ rssi_level = 1;
+ } else if (rtlpriv->dm.undecorated_smoothed_pwdb >
+ (long)middle_rssi_thresh) {
+ ra->ratr_state = DM_RATR_STA_LOW;
+ rssi_level = 3;
+ } else if (rtlpriv->dm.undecorated_smoothed_pwdb >
+ (long)low_rssi_thresh) {
+ ra->ratr_state = DM_RATR_STA_LOW;
+ rssi_level = 5;
+ } else {
+ ra->ratr_state = DM_RATR_STA_ULTRALOW;
+ rssi_level = 6;
+ }
+
+ if (ra->pre_ratr_state != ra->ratr_state) {
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, ("RSSI = %ld "
+ "RSSI_LEVEL = %d PreState = %d, CurState = %d\n",
+ rtlpriv->dm.undecorated_smoothed_pwdb,
+ ra->ratr_state,
+ ra->pre_ratr_state, ra->ratr_state));
+
+ rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
+ ra->ratr_state);
+ ra->pre_ratr_state = ra->ratr_state;
+ }
+ }
+ rcu_read_unlock();
+}
+
+static void _rtl92s_dm_switch_baseband_mrc(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ bool current_mrc;
+ bool enable_mrc = true;
+ long tmpentry_maxpwdb = 0;
+ u8 rssi_a = 0;
+ u8 rssi_b = 0;
+
+ if (is_hal_stop(rtlhal))
+ return;
+
+ if ((rtlphy->rf_type == RF_1T1R) || (rtlphy->rf_type == RF_2T2R))
+ return;
+
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_MRC, (u8 *)(&current_mrc));
+
+ if (mac->link_state >= MAC80211_LINKED) {
+ if (rtlpriv->dm.undecorated_smoothed_pwdb > tmpentry_maxpwdb) {
+ rssi_a = rtlpriv->stats.rx_rssi_percentage[RF90_PATH_A];
+ rssi_b = rtlpriv->stats.rx_rssi_percentage[RF90_PATH_B];
+ }
+ }
+
+ /* MRC settings would NOT affect TP on Wireless B mode. */
+ if (mac->mode != WIRELESS_MODE_B) {
+ if ((rssi_a == 0) && (rssi_b == 0)) {
+ enable_mrc = true;
+ } else if (rssi_b > 30) {
+ /* Turn on B-Path */
+ enable_mrc = true;
+ } else if (rssi_b < 5) {
+ /* Turn off B-path */
+ enable_mrc = false;
+ /* Take care of RSSI differentiation. */
+ } else if (rssi_a > 15 && (rssi_a >= rssi_b)) {
+ if ((rssi_a - rssi_b) > 15)
+ /* Turn off B-path */
+ enable_mrc = false;
+ else if ((rssi_a - rssi_b) < 10)
+ /* Turn on B-Path */
+ enable_mrc = true;
+ else
+ enable_mrc = current_mrc;
+ } else {
+ /* Turn on B-Path */
+ enable_mrc = true;
+ }
+ }
+
+ /* Update MRC settings if needed. */
+ if (enable_mrc != current_mrc)
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_MRC,
+ (u8 *)&enable_mrc);
+
+}
+
+void rtl92s_dm_init_edca_turbo(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->dm.current_turbo_edca = false;
+ rtlpriv->dm.is_any_nonbepkts = false;
+ rtlpriv->dm.is_cur_rdlstate = false;
+}
+
+static void _rtl92s_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rate_adaptive *ra = &(rtlpriv->ra);
+
+ ra->ratr_state = DM_RATR_STA_MAX;
+ ra->pre_ratr_state = DM_RATR_STA_MAX;
+
+ if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER)
+ rtlpriv->dm.useramask = true;
+ else
+ rtlpriv->dm.useramask = false;
+
+ rtlpriv->dm.useramask = false;
+ rtlpriv->dm.inform_fw_driverctrldm = false;
+}
+
+static void _rtl92s_dm_init_txpowertracking_thermalmeter(
+ struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->dm.txpower_tracking = true;
+ rtlpriv->dm.txpowercount = 0;
+ rtlpriv->dm.txpower_trackinginit = false;
+}
+
+static void _rtl92s_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt);
+ u32 ret_value;
+
+ ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER1, MASKDWORD);
+ falsealm_cnt->cnt_parity_fail = ((ret_value & 0xffff0000) >> 16);
+
+ ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER2, MASKDWORD);
+ falsealm_cnt->cnt_rate_illegal = (ret_value & 0xffff);
+ falsealm_cnt->cnt_crc8_fail = ((ret_value & 0xffff0000) >> 16);
+ ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, MASKDWORD);
+ falsealm_cnt->cnt_mcs_fail = (ret_value & 0xffff);
+
+ falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail +
+ falsealm_cnt->cnt_rate_illegal + falsealm_cnt->cnt_crc8_fail +
+ falsealm_cnt->cnt_mcs_fail;
+
+ /* read CCK false alarm */
+ ret_value = rtl_get_bbreg(hw, 0xc64, MASKDWORD);
+ falsealm_cnt->cnt_cck_fail = (ret_value & 0xffff);
+ falsealm_cnt->cnt_all = falsealm_cnt->cnt_ofdm_fail +
+ falsealm_cnt->cnt_cck_fail;
+}
+
+static void rtl92s_backoff_enable_flag(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt);
+
+ if (falsealm_cnt->cnt_all > digtable.fa_highthresh) {
+ if ((digtable.backoff_val - 6) <
+ digtable.backoffval_range_min)
+ digtable.backoff_val = digtable.backoffval_range_min;
+ else
+ digtable.backoff_val -= 6;
+ } else if (falsealm_cnt->cnt_all < digtable.fa_lowthresh) {
+ if ((digtable.backoff_val + 6) >
+ digtable.backoffval_range_max)
+ digtable.backoff_val =
+ digtable.backoffval_range_max;
+ else
+ digtable.backoff_val += 6;
+ }
+}
+
+static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt);
+ static u8 initialized, force_write;
+ u8 initial_gain = 0;
+
+ if ((digtable.pre_sta_connectstate == digtable.cur_sta_connectstate) ||
+ (digtable.cur_sta_connectstate == DIG_STA_BEFORE_CONNECT)) {
+ if (digtable.cur_sta_connectstate == DIG_STA_BEFORE_CONNECT) {
+ if (rtlpriv->psc.rfpwr_state != ERFON)
+ return;
+
+ if (digtable.backoff_enable_flag == true)
+ rtl92s_backoff_enable_flag(hw);
+ else
+ digtable.backoff_val = DM_DIG_BACKOFF;
+
+ if ((digtable.rssi_val + 10 - digtable.backoff_val) >
+ digtable.rx_gain_range_max)
+ digtable.cur_igvalue =
+ digtable.rx_gain_range_max;
+ else if ((digtable.rssi_val + 10 - digtable.backoff_val)
+ < digtable.rx_gain_range_min)
+ digtable.cur_igvalue =
+ digtable.rx_gain_range_min;
+ else
+ digtable.cur_igvalue = digtable.rssi_val + 10 -
+ digtable.backoff_val;
+
+ if (falsealm_cnt->cnt_all > 10000)
+ digtable.cur_igvalue =
+ (digtable.cur_igvalue > 0x33) ?
+ digtable.cur_igvalue : 0x33;
+
+ if (falsealm_cnt->cnt_all > 16000)
+ digtable.cur_igvalue =
+ digtable.rx_gain_range_max;
+ /* connected -> connected or disconnected -> disconnected */
+ } else {
+ /* Firmware control DIG, do nothing in driver dm */
+ return;
+ }
+ /* disconnected -> connected or connected ->
+ * disconnected or beforeconnect->(dis)connected */
+ } else {
+ /* Enable FW DIG */
+ digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
+ rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_ENABLE);
+
+ digtable.backoff_val = DM_DIG_BACKOFF;
+ digtable.cur_igvalue = rtlpriv->phy.default_initialgain[0];
+ digtable.pre_igvalue = 0;
+ return;
+ }
+
+ /* Forced writing to prevent from fw-dig overwriting. */
+ if (digtable.pre_igvalue != rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1,
+ MASKBYTE0))
+ force_write = 1;
+
+ if ((digtable.pre_igvalue != digtable.cur_igvalue) ||
+ !initialized || force_write) {
+ /* Disable FW DIG */
+ rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_DISABLE);
+
+ initial_gain = (u8)digtable.cur_igvalue;
+
+ /* Set initial gain. */
+ rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0, initial_gain);
+ rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0, initial_gain);
+ digtable.pre_igvalue = digtable.cur_igvalue;
+ initialized = 1;
+ force_write = 0;
+ }
+}
+
+static void _rtl92s_dm_ctrl_initgain_bytwoport(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (rtlpriv->mac80211.act_scanning)
+ return;
+
+ /* Decide the current status and if modify initial gain or not */
+ if (rtlpriv->mac80211.link_state >= MAC80211_LINKED ||
+ rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC)
+ digtable.cur_sta_connectstate = DIG_STA_CONNECT;
+ else
+ digtable.cur_sta_connectstate = DIG_STA_DISCONNECT;
+
+ digtable.rssi_val = rtlpriv->dm.undecorated_smoothed_pwdb;
+
+ /* Change dig mode to rssi */
+ if (digtable.cur_sta_connectstate != DIG_STA_DISCONNECT) {
+ if (digtable.dig_twoport_algorithm ==
+ DIG_TWO_PORT_ALGO_FALSE_ALARM) {
+ digtable.dig_twoport_algorithm = DIG_TWO_PORT_ALGO_RSSI;
+ rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_MODE_SS);
+ }
+ }
+
+ _rtl92s_dm_false_alarm_counter_statistics(hw);
+ _rtl92s_dm_initial_gain_sta_beforeconnect(hw);
+
+ digtable.pre_sta_connectstate = digtable.cur_sta_connectstate;
+}
+
+static void _rtl92s_dm_ctrl_initgain_byrssi(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ /* 2T2R TP issue */
+ if (rtlphy->rf_type == RF_2T2R)
+ return;
+
+ if (!rtlpriv->dm.dm_initialgain_enable)
+ return;
+
+ if (digtable.dig_enable_flag == false)
+ return;
+
+ _rtl92s_dm_ctrl_initgain_bytwoport(hw);
+}
+
+static void _rtl92s_dm_dynamic_txpower(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ long undecorated_smoothed_pwdb;
+ long txpwr_threshold_lv1, txpwr_threshold_lv2;
+
+ /* 2T2R TP issue */
+ if (rtlphy->rf_type == RF_2T2R)
+ return;
+
+ if (!rtlpriv->dm.dynamic_txpower_enable ||
+ rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) {
+ rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL;
+ return;
+ }
+
+ if ((mac->link_state < MAC80211_LINKED) &&
+ (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
+ ("Not connected to any\n"));
+
+ rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL;
+
+ rtlpriv->dm.last_dtp_lvl = TX_HIGHPWR_LEVEL_NORMAL;
+ return;
+ }
+
+ if (mac->link_state >= MAC80211_LINKED) {
+ if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+ undecorated_smoothed_pwdb =
+ rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("AP Client PWDB = 0x%lx\n",
+ undecorated_smoothed_pwdb));
+ } else {
+ undecorated_smoothed_pwdb =
+ rtlpriv->dm.undecorated_smoothed_pwdb;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("STA Default Port PWDB = 0x%lx\n",
+ undecorated_smoothed_pwdb));
+ }
+ } else {
+ undecorated_smoothed_pwdb =
+ rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("AP Ext Port PWDB = 0x%lx\n",
+ undecorated_smoothed_pwdb));
+ }
+
+ txpwr_threshold_lv2 = TX_POWER_NEAR_FIELD_THRESH_LVL2;
+ txpwr_threshold_lv1 = TX_POWER_NEAR_FIELD_THRESH_LVL1;
+
+ if (rtl_get_bbreg(hw, 0xc90, MASKBYTE0) == 1)
+ rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL;
+ else if (undecorated_smoothed_pwdb >= txpwr_threshold_lv2)
+ rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL2;
+ else if ((undecorated_smoothed_pwdb < (txpwr_threshold_lv2 - 3)) &&
+ (undecorated_smoothed_pwdb >= txpwr_threshold_lv1))
+ rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL1;
+ else if (undecorated_smoothed_pwdb < (txpwr_threshold_lv1 - 3))
+ rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL;
+
+ if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl))
+ rtl92s_phy_set_txpower(hw, rtlphy->current_channel);
+
+ rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl;
+}
+
+static void _rtl92s_dm_init_dig(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ /* Disable DIG scheme now.*/
+ digtable.dig_enable_flag = true;
+ digtable.backoff_enable_flag = true;
+
+ if ((rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER) &&
+ (hal_get_firmwareversion(rtlpriv) >= 0x3c))
+ digtable.dig_algorithm = DIG_ALGO_BY_TOW_PORT;
+ else
+ digtable.dig_algorithm =
+ DIG_ALGO_BEFORE_CONNECT_BY_RSSI_AND_ALARM;
+
+ digtable.dig_twoport_algorithm = DIG_TWO_PORT_ALGO_RSSI;
+ digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
+ /* off=by real rssi value, on=by digtable.rssi_val for new dig */
+ digtable.dig_dbgmode = DM_DBG_OFF;
+ digtable.dig_slgorithm_switch = 0;
+
+ /* 2007/10/04 MH Define init gain threshol. */
+ digtable.dig_state = DM_STA_DIG_MAX;
+ digtable.dig_highpwrstate = DM_STA_DIG_MAX;
+
+ digtable.cur_sta_connectstate = DIG_STA_DISCONNECT;
+ digtable.pre_sta_connectstate = DIG_STA_DISCONNECT;
+ digtable.cur_ap_connectstate = DIG_AP_DISCONNECT;
+ digtable.pre_ap_connectstate = DIG_AP_DISCONNECT;
+
+ digtable.rssi_lowthresh = DM_DIG_THRESH_LOW;
+ digtable.rssi_highthresh = DM_DIG_THRESH_HIGH;
+
+ digtable.fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
+ digtable.fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
+
+ digtable.rssi_highpower_lowthresh = DM_DIG_HIGH_PWR_THRESH_LOW;
+ digtable.rssi_highpower_highthresh = DM_DIG_HIGH_PWR_THRESH_HIGH;
+
+ /* for dig debug rssi value */
+ digtable.rssi_val = 50;
+ digtable.backoff_val = DM_DIG_BACKOFF;
+ digtable.rx_gain_range_max = DM_DIG_MAX;
+
+ digtable.rx_gain_range_min = DM_DIG_MIN;
+
+ digtable.backoffval_range_max = DM_DIG_BACKOFF_MAX;
+ digtable.backoffval_range_min = DM_DIG_BACKOFF_MIN;
+}
+
+static void _rtl92s_dm_init_dynamic_txpower(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if ((hal_get_firmwareversion(rtlpriv) >= 60) &&
+ (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER))
+ rtlpriv->dm.dynamic_txpower_enable = true;
+ else
+ rtlpriv->dm.dynamic_txpower_enable = false;
+
+ rtlpriv->dm.last_dtp_lvl = TX_HIGHPWR_LEVEL_NORMAL;
+ rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL;
+}
+
+void rtl92s_dm_init(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER;
+ rtlpriv->dm.undecorated_smoothed_pwdb = -1;
+
+ _rtl92s_dm_init_dynamic_txpower(hw);
+ rtl92s_dm_init_edca_turbo(hw);
+ _rtl92s_dm_init_rate_adaptive_mask(hw);
+ _rtl92s_dm_init_txpowertracking_thermalmeter(hw);
+ _rtl92s_dm_init_dig(hw);
+
+ rtl_write_dword(rtlpriv, WFM5, FW_CCA_CHK_ENABLE);
+}
+
+void rtl92s_dm_watchdog(struct ieee80211_hw *hw)
+{
+ _rtl92s_dm_check_edca_turbo(hw);
+ _rtl92s_dm_check_txpowertracking_thermalmeter(hw);
+ _rtl92s_dm_ctrl_initgain_byrssi(hw);
+ _rtl92s_dm_dynamic_txpower(hw);
+ _rtl92s_dm_refresh_rateadaptive_mask(hw);
+ _rtl92s_dm_switch_baseband_mrc(hw);
+}
+
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.h b/drivers/net/wireless/rtlwifi/rtl8192se/dm.h
new file mode 100644
index 000000000000..9051a556acc4
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.h
@@ -0,0 +1,164 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#ifndef __RTL_92S_DM_H__
+#define __RTL_92S_DM_H__
+
+struct dig_t {
+ u8 dig_enable_flag;
+ u8 dig_algorithm;
+ u8 dig_twoport_algorithm;
+ u8 dig_ext_port_stage;
+ u8 dig_dbgmode;
+ u8 dig_slgorithm_switch;
+
+ long rssi_lowthresh;
+ long rssi_highthresh;
+
+ u32 fa_lowthresh;
+ u32 fa_highthresh;
+
+ long rssi_highpower_lowthresh;
+ long rssi_highpower_highthresh;
+
+ u8 dig_state;
+ u8 dig_highpwrstate;
+ u8 cur_sta_connectstate;
+ u8 pre_sta_connectstate;
+ u8 cur_ap_connectstate;
+ u8 pre_ap_connectstate;
+
+ u8 cur_pd_thstate;
+ u8 pre_pd_thstate;
+ u8 cur_cs_ratiostate;
+ u8 pre_cs_ratiostate;
+
+ u32 pre_igvalue;
+ u32 cur_igvalue;
+
+ u8 backoff_enable_flag;
+ char backoff_val;
+ char backoffval_range_max;
+ char backoffval_range_min;
+ u8 rx_gain_range_max;
+ u8 rx_gain_range_min;
+
+ long rssi_val;
+};
+
+enum dm_dig_alg {
+ DIG_ALGO_BY_FALSE_ALARM = 0,
+ DIG_ALGO_BY_RSSI = 1,
+ DIG_ALGO_BEFORE_CONNECT_BY_RSSI_AND_ALARM = 2,
+ DIG_ALGO_BY_TOW_PORT = 3,
+ DIG_ALGO_MAX
+};
+
+enum dm_dig_two_port_alg {
+ DIG_TWO_PORT_ALGO_RSSI = 0,
+ DIG_TWO_PORT_ALGO_FALSE_ALARM = 1,
+};
+
+enum dm_dig_dbg {
+ DM_DBG_OFF = 0,
+ DM_DBG_ON = 1,
+ DM_DBG_MAX
+};
+
+enum dm_dig_sta {
+ DM_STA_DIG_OFF = 0,
+ DM_STA_DIG_ON,
+ DM_STA_DIG_MAX
+};
+
+enum dm_dig_connect {
+ DIG_STA_DISCONNECT = 0,
+ DIG_STA_CONNECT = 1,
+ DIG_STA_BEFORE_CONNECT = 2,
+ DIG_AP_DISCONNECT = 3,
+ DIG_AP_CONNECT = 4,
+ DIG_AP_ADD_STATION = 5,
+ DIG_CONNECT_MAX
+};
+
+enum dm_dig_ext_port_alg {
+ DIG_EXT_PORT_STAGE_0 = 0,
+ DIG_EXT_PORT_STAGE_1 = 1,
+ DIG_EXT_PORT_STAGE_2 = 2,
+ DIG_EXT_PORT_STAGE_3 = 3,
+ DIG_EXT_PORT_STAGE_MAX = 4,
+};
+
+enum dm_ratr_sta {
+ DM_RATR_STA_HIGH = 0,
+ DM_RATR_STA_MIDDLEHIGH = 1,
+ DM_RATR_STA_MIDDLE = 2,
+ DM_RATR_STA_MIDDLELOW = 3,
+ DM_RATR_STA_LOW = 4,
+ DM_RATR_STA_ULTRALOW = 5,
+ DM_RATR_STA_MAX
+};
+
+#define DM_TYPE_BYFW 0
+#define DM_TYPE_BYDRIVER 1
+
+#define TX_HIGH_PWR_LEVEL_NORMAL 0
+#define TX_HIGH_PWR_LEVEL_LEVEL1 1
+#define TX_HIGH_PWR_LEVEL_LEVEL2 2
+
+#define HAL_DM_DIG_DISABLE BIT(0) /* Disable Dig */
+#define HAL_DM_HIPWR_DISABLE BIT(1) /* Disable High Power */
+
+#define TX_HIGHPWR_LEVEL_NORMAL 0
+#define TX_HIGHPWR_LEVEL_NORMAL1 1
+#define TX_HIGHPWR_LEVEL_NORMAL2 2
+
+#define TX_POWER_NEAR_FIELD_THRESH_LVL2 74
+#define TX_POWER_NEAR_FIELD_THRESH_LVL1 67
+
+#define DM_DIG_THRESH_HIGH 40
+#define DM_DIG_THRESH_LOW 35
+#define DM_FALSEALARM_THRESH_LOW 40
+#define DM_FALSEALARM_THRESH_HIGH 1000
+#define DM_DIG_HIGH_PWR_THRESH_HIGH 75
+#define DM_DIG_HIGH_PWR_THRESH_LOW 70
+#define DM_DIG_BACKOFF 12
+#define DM_DIG_MAX 0x3e
+#define DM_DIG_MIN 0x1c
+#define DM_DIG_MIN_Netcore 0x12
+#define DM_DIG_BACKOFF_MAX 12
+#define DM_DIG_BACKOFF_MIN -4
+
+extern struct dig_t digtable;
+
+void rtl92s_dm_watchdog(struct ieee80211_hw *hw);
+void rtl92s_dm_init(struct ieee80211_hw *hw);
+void rtl92s_dm_init_edca_turbo(struct ieee80211_hw *hw);
+
+#endif
+
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/fw.c b/drivers/net/wireless/rtlwifi/rtl8192se/fw.c
new file mode 100644
index 000000000000..3b5af0113d7f
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/fw.c
@@ -0,0 +1,654 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../base.h"
+#include "reg.h"
+#include "def.h"
+#include "fw.h"
+
+static void _rtl92s_fw_set_rqpn(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtl_write_dword(rtlpriv, RQPN, 0xffffffff);
+ rtl_write_dword(rtlpriv, RQPN + 4, 0xffffffff);
+ rtl_write_byte(rtlpriv, RQPN + 8, 0xff);
+ rtl_write_byte(rtlpriv, RQPN + 0xB, 0x80);
+}
+
+static bool _rtl92s_firmware_enable_cpu(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 ichecktime = 200;
+ u16 tmpu2b;
+ u8 tmpu1b, cpustatus = 0;
+
+ _rtl92s_fw_set_rqpn(hw);
+
+ /* Enable CPU. */
+ tmpu1b = rtl_read_byte(rtlpriv, SYS_CLKR);
+ /* AFE source */
+ rtl_write_byte(rtlpriv, SYS_CLKR, (tmpu1b | SYS_CPU_CLKSEL));
+
+ tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN);
+ rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | FEN_CPUEN));
+
+ /* Polling IMEM Ready after CPU has refilled. */
+ do {
+ cpustatus = rtl_read_byte(rtlpriv, TCR);
+ if (cpustatus & IMEM_RDY) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("IMEM Ready after CPU has refilled.\n"));
+ break;
+ }
+
+ udelay(100);
+ } while (ichecktime--);
+
+ if (!(cpustatus & IMEM_RDY))
+ return false;
+
+ return true;
+}
+
+static enum fw_status _rtl92s_firmware_get_nextstatus(
+ enum fw_status fw_currentstatus)
+{
+ enum fw_status next_fwstatus = 0;
+
+ switch (fw_currentstatus) {
+ case FW_STATUS_INIT:
+ next_fwstatus = FW_STATUS_LOAD_IMEM;
+ break;
+ case FW_STATUS_LOAD_IMEM:
+ next_fwstatus = FW_STATUS_LOAD_EMEM;
+ break;
+ case FW_STATUS_LOAD_EMEM:
+ next_fwstatus = FW_STATUS_LOAD_DMEM;
+ break;
+ case FW_STATUS_LOAD_DMEM:
+ next_fwstatus = FW_STATUS_READY;
+ break;
+ default:
+ break;
+ }
+
+ return next_fwstatus;
+}
+
+static u8 _rtl92s_firmware_header_map_rftype(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ switch (rtlphy->rf_type) {
+ case RF_1T1R:
+ return 0x11;
+ break;
+ case RF_1T2R:
+ return 0x12;
+ break;
+ case RF_2T2R:
+ return 0x22;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
+ ("Unknown RF type(%x)\n",
+ rtlphy->rf_type));
+ break;
+ }
+ return 0x22;
+}
+
+static void _rtl92s_firmwareheader_priveupdate(struct ieee80211_hw *hw,
+ struct fw_priv *pfw_priv)
+{
+ /* Update RF types for RATR settings. */
+ pfw_priv->rf_config = _rtl92s_firmware_header_map_rftype(hw);
+}
+
+
+
+static bool _rtl92s_cmd_send_packet(struct ieee80211_hw *hw,
+ struct sk_buff *skb, u8 last)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl8192_tx_ring *ring;
+ struct rtl_tx_desc *pdesc;
+ unsigned long flags;
+ u8 idx = 0;
+
+ ring = &rtlpci->tx_ring[TXCMD_QUEUE];
+
+ spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
+
+ idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries;
+ pdesc = &ring->desc[idx];
+ rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb);
+ __skb_queue_tail(&ring->queue, skb);
+
+ spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
+
+ return true;
+}
+
+static bool _rtl92s_firmware_downloadcode(struct ieee80211_hw *hw,
+ u8 *code_virtual_address, u32 buffer_len)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct sk_buff *skb;
+ struct rtl_tcb_desc *tcb_desc;
+ unsigned char *seg_ptr;
+ u16 frag_threshold = MAX_FIRMWARE_CODE_SIZE;
+ u16 frag_length, frag_offset = 0;
+ u16 extra_descoffset = 0;
+ u8 last_inipkt = 0;
+
+ _rtl92s_fw_set_rqpn(hw);
+
+ if (buffer_len >= MAX_FIRMWARE_CODE_SIZE) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Size over FIRMWARE_CODE_SIZE!\n"));
+
+ return false;
+ }
+
+ extra_descoffset = 0;
+
+ do {
+ if ((buffer_len - frag_offset) > frag_threshold) {
+ frag_length = frag_threshold + extra_descoffset;
+ } else {
+ frag_length = (u16)(buffer_len - frag_offset +
+ extra_descoffset);
+ last_inipkt = 1;
+ }
+
+ /* Allocate skb buffer to contain firmware */
+ /* info and tx descriptor info. */
+ skb = dev_alloc_skb(frag_length);
+ skb_reserve(skb, extra_descoffset);
+ seg_ptr = (u8 *)skb_put(skb, (u32)(frag_length -
+ extra_descoffset));
+ memcpy(seg_ptr, code_virtual_address + frag_offset,
+ (u32)(frag_length - extra_descoffset));
+
+ tcb_desc = (struct rtl_tcb_desc *)(skb->cb);
+ tcb_desc->queue_index = TXCMD_QUEUE;
+ tcb_desc->cmd_or_init = DESC_PACKET_TYPE_INIT;
+ tcb_desc->last_inipkt = last_inipkt;
+
+ _rtl92s_cmd_send_packet(hw, skb, last_inipkt);
+
+ frag_offset += (frag_length - extra_descoffset);
+
+ } while (frag_offset < buffer_len);
+
+ rtl_write_byte(rtlpriv, TP_POLL, TPPOLL_CQ);
+
+ return true ;
+}
+
+static bool _rtl92s_firmware_checkready(struct ieee80211_hw *hw,
+ u8 loadfw_status)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rt_firmware *firmware = (struct rt_firmware *)rtlhal->pfirmware;
+ u32 tmpu4b;
+ u8 cpustatus = 0;
+ short pollingcnt = 1000;
+ bool rtstatus = true;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("LoadStaus(%d)\n",
+ loadfw_status));
+
+ firmware->fwstatus = (enum fw_status)loadfw_status;
+
+ switch (loadfw_status) {
+ case FW_STATUS_LOAD_IMEM:
+ /* Polling IMEM code done. */
+ do {
+ cpustatus = rtl_read_byte(rtlpriv, TCR);
+ if (cpustatus & IMEM_CODE_DONE)
+ break;
+ udelay(5);
+ } while (pollingcnt--);
+
+ if (!(cpustatus & IMEM_CHK_RPT) || (pollingcnt <= 0)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("FW_STATUS_LOAD_IMEM"
+ " FAIL CPU, Status=%x\r\n", cpustatus));
+ goto status_check_fail;
+ }
+ break;
+
+ case FW_STATUS_LOAD_EMEM:
+ /* Check Put Code OK and Turn On CPU */
+ /* Polling EMEM code done. */
+ do {
+ cpustatus = rtl_read_byte(rtlpriv, TCR);
+ if (cpustatus & EMEM_CODE_DONE)
+ break;
+ udelay(5);
+ } while (pollingcnt--);
+
+ if (!(cpustatus & EMEM_CHK_RPT) || (pollingcnt <= 0)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("FW_STATUS_LOAD_EMEM"
+ " FAIL CPU, Status=%x\r\n", cpustatus));
+ goto status_check_fail;
+ }
+
+ /* Turn On CPU */
+ rtstatus = _rtl92s_firmware_enable_cpu(hw);
+ if (rtstatus != true) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Enable CPU fail!\n"));
+ goto status_check_fail;
+ }
+ break;
+
+ case FW_STATUS_LOAD_DMEM:
+ /* Polling DMEM code done */
+ do {
+ cpustatus = rtl_read_byte(rtlpriv, TCR);
+ if (cpustatus & DMEM_CODE_DONE)
+ break;
+ udelay(5);
+ } while (pollingcnt--);
+
+ if (!(cpustatus & DMEM_CODE_DONE) || (pollingcnt <= 0)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Polling DMEM code done"
+ " fail ! cpustatus(%#x)\n", cpustatus));
+ goto status_check_fail;
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("DMEM code download success,"
+ " cpustatus(%#x)\n", cpustatus));
+
+ /* Prevent Delay too much and being scheduled out */
+ /* Polling Load Firmware ready */
+ pollingcnt = 2000;
+ do {
+ cpustatus = rtl_read_byte(rtlpriv, TCR);
+ if (cpustatus & FWRDY)
+ break;
+ udelay(40);
+ } while (pollingcnt--);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("Polling Load Firmware ready,"
+ " cpustatus(%x)\n", cpustatus));
+
+ if (((cpustatus & LOAD_FW_READY) != LOAD_FW_READY) ||
+ (pollingcnt <= 0)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Polling Load Firmware"
+ " ready fail ! cpustatus(%x)\n", cpustatus));
+ goto status_check_fail;
+ }
+
+ /* If right here, we can set TCR/RCR to desired value */
+ /* and config MAC lookback mode to normal mode */
+ tmpu4b = rtl_read_dword(rtlpriv, TCR);
+ rtl_write_dword(rtlpriv, TCR, (tmpu4b & (~TCR_ICV)));
+
+ tmpu4b = rtl_read_dword(rtlpriv, RCR);
+ rtl_write_dword(rtlpriv, RCR, (tmpu4b | RCR_APPFCS |
+ RCR_APP_ICV | RCR_APP_MIC));
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("Current RCR settings(%#x)\n", tmpu4b));
+
+ /* Set to normal mode. */
+ rtl_write_byte(rtlpriv, LBKMD_SEL, LBK_NORMAL);
+ break;
+
+ default:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
+ ("Unknown status check!\n"));
+ rtstatus = false;
+ break;
+ }
+
+status_check_fail:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("loadfw_status(%d), "
+ "rtstatus(%x)\n", loadfw_status, rtstatus));
+ return rtstatus;
+}
+
+int rtl92s_download_fw(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rt_firmware *firmware = NULL;
+ struct fw_hdr *pfwheader;
+ struct fw_priv *pfw_priv = NULL;
+ u8 *puc_mappedfile = NULL;
+ u32 ul_filelength = 0;
+ u32 file_length = 0;
+ u8 fwhdr_size = RT_8192S_FIRMWARE_HDR_SIZE;
+ u8 fwstatus = FW_STATUS_INIT;
+ bool rtstatus = true;
+
+ if (!rtlhal->pfirmware)
+ return 1;
+
+ firmware = (struct rt_firmware *)rtlhal->pfirmware;
+ firmware->fwstatus = FW_STATUS_INIT;
+
+ puc_mappedfile = firmware->sz_fw_tmpbuffer;
+ file_length = firmware->sz_fw_tmpbufferlen;
+
+ /* 1. Retrieve FW header. */
+ firmware->pfwheader = (struct fw_hdr *) puc_mappedfile;
+ pfwheader = firmware->pfwheader;
+ firmware->firmwareversion = byte(pfwheader->version, 0);
+ firmware->pfwheader->fwpriv.hci_sel = 1;/* pcie */
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("signature:%x, version:"
+ "%x, size:%x,"
+ "imemsize:%x, sram size:%x\n", pfwheader->signature,
+ pfwheader->version, pfwheader->dmem_size,
+ pfwheader->img_imem_size, pfwheader->img_sram_size));
+
+ /* 2. Retrieve IMEM image. */
+ if ((pfwheader->img_imem_size == 0) || (pfwheader->img_imem_size >
+ sizeof(firmware->fw_imem))) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("memory for data image is less than IMEM required\n"));
+ goto fail;
+ } else {
+ puc_mappedfile += fwhdr_size;
+
+ memcpy(firmware->fw_imem, puc_mappedfile,
+ pfwheader->img_imem_size);
+ firmware->fw_imem_len = pfwheader->img_imem_size;
+ }
+
+ /* 3. Retriecve EMEM image. */
+ if (pfwheader->img_sram_size > sizeof(firmware->fw_emem)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("memory for data image is less than EMEM required\n"));
+ goto fail;
+ } else {
+ puc_mappedfile += firmware->fw_imem_len;
+
+ memcpy(firmware->fw_emem, puc_mappedfile,
+ pfwheader->img_sram_size);
+ firmware->fw_emem_len = pfwheader->img_sram_size;
+ }
+
+ /* 4. download fw now */
+ fwstatus = _rtl92s_firmware_get_nextstatus(firmware->fwstatus);
+ while (fwstatus != FW_STATUS_READY) {
+ /* Image buffer redirection. */
+ switch (fwstatus) {
+ case FW_STATUS_LOAD_IMEM:
+ puc_mappedfile = firmware->fw_imem;
+ ul_filelength = firmware->fw_imem_len;
+ break;
+ case FW_STATUS_LOAD_EMEM:
+ puc_mappedfile = firmware->fw_emem;
+ ul_filelength = firmware->fw_emem_len;
+ break;
+ case FW_STATUS_LOAD_DMEM:
+ /* Partial update the content of header private. */
+ pfwheader = firmware->pfwheader;
+ pfw_priv = &pfwheader->fwpriv;
+ _rtl92s_firmwareheader_priveupdate(hw, pfw_priv);
+ puc_mappedfile = (u8 *)(firmware->pfwheader) +
+ RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE;
+ ul_filelength = fwhdr_size -
+ RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Unexpected Download step!!\n"));
+ goto fail;
+ break;
+ }
+
+ /* <2> Download image file */
+ rtstatus = _rtl92s_firmware_downloadcode(hw, puc_mappedfile,
+ ul_filelength);
+
+ if (rtstatus != true) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("fail!\n"));
+ goto fail;
+ }
+
+ /* <3> Check whether load FW process is ready */
+ rtstatus = _rtl92s_firmware_checkready(hw, fwstatus);
+ if (rtstatus != true) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("fail!\n"));
+ goto fail;
+ }
+
+ fwstatus = _rtl92s_firmware_get_nextstatus(firmware->fwstatus);
+ }
+
+ return rtstatus;
+fail:
+ return 0;
+}
+
+static u32 _rtl92s_fill_h2c_cmd(struct sk_buff *skb, u32 h2cbufferlen,
+ u32 cmd_num, u32 *pelement_id, u32 *pcmd_len,
+ u8 **pcmb_buffer, u8 *cmd_start_seq)
+{
+ u32 totallen = 0, len = 0, tx_desclen = 0;
+ u32 pre_continueoffset = 0;
+ u8 *ph2c_buffer;
+ u8 i = 0;
+
+ do {
+ /* 8 - Byte aligment */
+ len = H2C_TX_CMD_HDR_LEN + N_BYTE_ALIGMENT(pcmd_len[i], 8);
+
+ /* Buffer length is not enough */
+ if (h2cbufferlen < totallen + len + tx_desclen)
+ break;
+
+ /* Clear content */
+ ph2c_buffer = (u8 *)skb_put(skb, (u32)len);
+ memset((ph2c_buffer + totallen + tx_desclen), 0, len);
+
+ /* CMD len */
+ SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen),
+ 0, 16, pcmd_len[i]);
+
+ /* CMD ID */
+ SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen),
+ 16, 8, pelement_id[i]);
+
+ /* CMD Sequence */
+ *cmd_start_seq = *cmd_start_seq % 0x80;
+ SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen),
+ 24, 7, *cmd_start_seq);
+ ++*cmd_start_seq;
+
+ /* Copy memory */
+ memcpy((ph2c_buffer + totallen + tx_desclen +
+ H2C_TX_CMD_HDR_LEN), pcmb_buffer[i], pcmd_len[i]);
+
+ /* CMD continue */
+ /* set the continue in prevoius cmd. */
+ if (i < cmd_num - 1)
+ SET_BITS_TO_LE_4BYTE((ph2c_buffer + pre_continueoffset),
+ 31, 1, 1);
+
+ pre_continueoffset = totallen;
+
+ totallen += len;
+ } while (++i < cmd_num);
+
+ return totallen;
+}
+
+static u32 _rtl92s_get_h2c_cmdlen(u32 h2cbufferlen, u32 cmd_num, u32 *pcmd_len)
+{
+ u32 totallen = 0, len = 0, tx_desclen = 0;
+ u8 i = 0;
+
+ do {
+ /* 8 - Byte aligment */
+ len = H2C_TX_CMD_HDR_LEN + N_BYTE_ALIGMENT(pcmd_len[i], 8);
+
+ /* Buffer length is not enough */
+ if (h2cbufferlen < totallen + len + tx_desclen)
+ break;
+
+ totallen += len;
+ } while (++i < cmd_num);
+
+ return totallen + tx_desclen;
+}
+
+static bool _rtl92s_firmware_set_h2c_cmd(struct ieee80211_hw *hw, u8 h2c_cmd,
+ u8 *pcmd_buffer)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_tcb_desc *cb_desc;
+ struct sk_buff *skb;
+ u32 element_id = 0;
+ u32 cmd_len = 0;
+ u32 len;
+
+ switch (h2c_cmd) {
+ case FW_H2C_SETPWRMODE:
+ element_id = H2C_SETPWRMODE_CMD ;
+ cmd_len = sizeof(struct h2c_set_pwrmode_parm);
+ break;
+ case FW_H2C_JOINBSSRPT:
+ element_id = H2C_JOINBSSRPT_CMD;
+ cmd_len = sizeof(struct h2c_joinbss_rpt_parm);
+ break;
+ case FW_H2C_WOWLAN_UPDATE_GTK:
+ element_id = H2C_WOWLAN_UPDATE_GTK_CMD;
+ cmd_len = sizeof(struct h2c_wpa_two_way_parm);
+ break;
+ case FW_H2C_WOWLAN_UPDATE_IV:
+ element_id = H2C_WOWLAN_UPDATE_IV_CMD;
+ cmd_len = sizeof(unsigned long long);
+ break;
+ case FW_H2C_WOWLAN_OFFLOAD:
+ element_id = H2C_WOWLAN_FW_OFFLOAD;
+ cmd_len = sizeof(u8);
+ break;
+ default:
+ break;
+ }
+
+ len = _rtl92s_get_h2c_cmdlen(MAX_TRANSMIT_BUFFER_SIZE, 1, &cmd_len);
+ skb = dev_alloc_skb(len);
+ cb_desc = (struct rtl_tcb_desc *)(skb->cb);
+ cb_desc->queue_index = TXCMD_QUEUE;
+ cb_desc->cmd_or_init = DESC_PACKET_TYPE_NORMAL;
+ cb_desc->last_inipkt = false;
+
+ _rtl92s_fill_h2c_cmd(skb, MAX_TRANSMIT_BUFFER_SIZE, 1, &element_id,
+ &cmd_len, &pcmd_buffer, &rtlhal->h2c_txcmd_seq);
+ _rtl92s_cmd_send_packet(hw, skb, false);
+ rtlpriv->cfg->ops->tx_polling(hw, TXCMD_QUEUE);
+
+ return true;
+}
+
+void rtl92s_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 Mode)
+{
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct h2c_set_pwrmode_parm pwrmode;
+ u16 max_wakeup_period = 0;
+
+ pwrmode.mode = Mode;
+ pwrmode.flag_low_traffic_en = 0;
+ pwrmode.flag_lpnav_en = 0;
+ pwrmode.flag_rf_low_snr_en = 0;
+ pwrmode.flag_dps_en = 0;
+ pwrmode.bcn_rx_en = 0;
+ pwrmode.bcn_to = 0;
+ SET_BITS_TO_LE_2BYTE((u8 *)(&pwrmode) + 8, 0, 16,
+ mac->vif->bss_conf.beacon_int);
+ pwrmode.app_itv = 0;
+ pwrmode.awake_bcn_itvl = ppsc->reg_max_lps_awakeintvl;
+ pwrmode.smart_ps = 1;
+ pwrmode.bcn_pass_period = 10;
+
+ /* Set beacon pass count */
+ if (pwrmode.mode == FW_PS_MIN_MODE)
+ max_wakeup_period = mac->vif->bss_conf.beacon_int;
+ else if (pwrmode.mode == FW_PS_MAX_MODE)
+ max_wakeup_period = mac->vif->bss_conf.beacon_int *
+ mac->vif->bss_conf.dtim_period;
+
+ if (max_wakeup_period >= 500)
+ pwrmode.bcn_pass_cnt = 1;
+ else if ((max_wakeup_period >= 300) && (max_wakeup_period < 500))
+ pwrmode.bcn_pass_cnt = 2;
+ else if ((max_wakeup_period >= 200) && (max_wakeup_period < 300))
+ pwrmode.bcn_pass_cnt = 3;
+ else if ((max_wakeup_period >= 20) && (max_wakeup_period < 200))
+ pwrmode.bcn_pass_cnt = 5;
+ else
+ pwrmode.bcn_pass_cnt = 1;
+
+ _rtl92s_firmware_set_h2c_cmd(hw, FW_H2C_SETPWRMODE, (u8 *)&pwrmode);
+
+}
+
+void rtl92s_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw,
+ u8 mstatus, u8 ps_qosinfo)
+{
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct h2c_joinbss_rpt_parm joinbss_rpt;
+
+ joinbss_rpt.opmode = mstatus;
+ joinbss_rpt.ps_qos_info = ps_qosinfo;
+ joinbss_rpt.bssid[0] = mac->bssid[0];
+ joinbss_rpt.bssid[1] = mac->bssid[1];
+ joinbss_rpt.bssid[2] = mac->bssid[2];
+ joinbss_rpt.bssid[3] = mac->bssid[3];
+ joinbss_rpt.bssid[4] = mac->bssid[4];
+ joinbss_rpt.bssid[5] = mac->bssid[5];
+ SET_BITS_TO_LE_2BYTE((u8 *)(&joinbss_rpt) + 8, 0, 16,
+ mac->vif->bss_conf.beacon_int);
+ SET_BITS_TO_LE_2BYTE((u8 *)(&joinbss_rpt) + 10, 0, 16, mac->assoc_id);
+
+ _rtl92s_firmware_set_h2c_cmd(hw, FW_H2C_JOINBSSRPT, (u8 *)&joinbss_rpt);
+}
+
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/fw.h b/drivers/net/wireless/rtlwifi/rtl8192se/fw.h
new file mode 100644
index 000000000000..74cc503efe8a
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/fw.h
@@ -0,0 +1,375 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#ifndef __REALTEK_FIRMWARE92S_H__
+#define __REALTEK_FIRMWARE92S_H__
+
+#define RTL8190_MAX_FIRMWARE_CODE_SIZE 64000
+#define RTL8190_CPU_START_OFFSET 0x80
+/* Firmware Local buffer size. 64k */
+#define MAX_FIRMWARE_CODE_SIZE 0xFF00
+
+#define RT_8192S_FIRMWARE_HDR_SIZE 80
+#define RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE 32
+
+/* support till 64 bit bus width OS */
+#define MAX_DEV_ADDR_SIZE 8
+#define MAX_FIRMWARE_INFORMATION_SIZE 32
+#define MAX_802_11_HEADER_LENGTH (40 + \
+ MAX_FIRMWARE_INFORMATION_SIZE)
+#define ENCRYPTION_MAX_OVERHEAD 128
+#define MAX_FRAGMENT_COUNT 8
+#define MAX_TRANSMIT_BUFFER_SIZE (1600 + \
+ (MAX_802_11_HEADER_LENGTH + \
+ ENCRYPTION_MAX_OVERHEAD) *\
+ MAX_FRAGMENT_COUNT)
+
+#define H2C_TX_CMD_HDR_LEN 8
+
+/* The following DM control code are for Reg0x364, */
+#define FW_DIG_ENABLE_CTL BIT(0)
+#define FW_HIGH_PWR_ENABLE_CTL BIT(1)
+#define FW_SS_CTL BIT(2)
+#define FW_RA_INIT_CTL BIT(3)
+#define FW_RA_BG_CTL BIT(4)
+#define FW_RA_N_CTL BIT(5)
+#define FW_PWR_TRK_CTL BIT(6)
+#define FW_IQK_CTL BIT(7)
+#define FW_FA_CTL BIT(8)
+#define FW_DRIVER_CTRL_DM_CTL BIT(9)
+#define FW_PAPE_CTL_BY_SW_HW BIT(10)
+#define FW_DISABLE_ALL_DM 0
+#define FW_PWR_TRK_PARAM_CLR 0x0000ffff
+#define FW_RA_PARAM_CLR 0xffff0000
+
+enum desc_packet_type {
+ DESC_PACKET_TYPE_INIT = 0,
+ DESC_PACKET_TYPE_NORMAL = 1,
+};
+
+/* 8-bytes alignment required */
+struct fw_priv {
+ /* --- long word 0 ---- */
+ /* 0x12: CE product, 0x92: IT product */
+ u8 signature_0;
+ /* 0x87: CE product, 0x81: IT product */
+ u8 signature_1;
+ /* 0x81: PCI-AP, 01:PCIe, 02: 92S-U,
+ * 0x82: USB-AP, 0x12: 72S-U, 03:SDIO */
+ u8 hci_sel;
+ /* the same value as reigster value */
+ u8 chip_version;
+ /* customer ID low byte */
+ u8 customer_id_0;
+ /* customer ID high byte */
+ u8 customer_id_1;
+ /* 0x11: 1T1R, 0x12: 1T2R,
+ * 0x92: 1T2R turbo, 0x22: 2T2R */
+ u8 rf_config;
+ /* 4: 4EP, 6: 6EP, 11: 11EP */
+ u8 usb_ep_num;
+
+ /* --- long word 1 ---- */
+ /* regulatory class bit map 0 */
+ u8 regulatory_class_0;
+ /* regulatory class bit map 1 */
+ u8 regulatory_class_1;
+ /* regulatory class bit map 2 */
+ u8 regulatory_class_2;
+ /* regulatory class bit map 3 */
+ u8 regulatory_class_3;
+ /* 0:SWSI, 1:HWSI, 2:HWPI */
+ u8 rfintfs;
+ u8 def_nettype;
+ u8 rsvd010;
+ u8 rsvd011;
+
+ /* --- long word 2 ---- */
+ /* 0x00: normal, 0x03: MACLBK, 0x01: PHYLBK */
+ u8 lbk_mode;
+ /* 1: for MP use, 0: for normal
+ * driver (to be discussed) */
+ u8 mp_mode;
+ u8 rsvd020;
+ u8 rsvd021;
+ u8 rsvd022;
+ u8 rsvd023;
+ u8 rsvd024;
+ u8 rsvd025;
+
+ /* --- long word 3 ---- */
+ /* QoS enable */
+ u8 qos_en;
+ /* 40MHz BW enable */
+ /* 4181 convert AMSDU to AMPDU, 0: disable */
+ u8 bw_40mhz_en;
+ u8 amsdu2ampdu_en;
+ /* 11n AMPDU enable */
+ u8 ampdu_en;
+ /* FW offloads, 0: driver handles */
+ u8 rate_control_offload;
+ /* FW offloads, 0: driver handles */
+ u8 aggregation_offload;
+ u8 rsvd030;
+ u8 rsvd031;
+
+ /* --- long word 4 ---- */
+ /* 1. FW offloads, 0: driver handles */
+ u8 beacon_offload;
+ /* 2. FW offloads, 0: driver handles */
+ u8 mlme_offload;
+ /* 3. FW offloads, 0: driver handles */
+ u8 hwpc_offload;
+ /* 4. FW offloads, 0: driver handles */
+ u8 tcp_checksum_offload;
+ /* 5. FW offloads, 0: driver handles */
+ u8 tcp_offload;
+ /* 6. FW offloads, 0: driver handles */
+ u8 ps_control_offload;
+ /* 7. FW offloads, 0: driver handles */
+ u8 wwlan_offload;
+ u8 rsvd040;
+
+ /* --- long word 5 ---- */
+ /* tcp tx packet length low byte */
+ u8 tcp_tx_frame_len_L;
+ /* tcp tx packet length high byte */
+ u8 tcp_tx_frame_len_H;
+ /* tcp rx packet length low byte */
+ u8 tcp_rx_frame_len_L;
+ /* tcp rx packet length high byte */
+ u8 tcp_rx_frame_len_H;
+ u8 rsvd050;
+ u8 rsvd051;
+ u8 rsvd052;
+ u8 rsvd053;
+};
+
+/* 8-byte alinment required */
+struct fw_hdr {
+
+ /* --- LONG WORD 0 ---- */
+ u16 signature;
+ /* 0x8000 ~ 0x8FFF for FPGA version,
+ * 0x0000 ~ 0x7FFF for ASIC version, */
+ u16 version;
+ /* define the size of boot loader */
+ u32 dmem_size;
+
+
+ /* --- LONG WORD 1 ---- */
+ /* define the size of FW in IMEM */
+ u32 img_imem_size;
+ /* define the size of FW in SRAM */
+ u32 img_sram_size;
+
+ /* --- LONG WORD 2 ---- */
+ /* define the size of DMEM variable */
+ u32 fw_priv_size;
+ u32 rsvd0;
+
+ /* --- LONG WORD 3 ---- */
+ u32 rsvd1;
+ u32 rsvd2;
+
+ struct fw_priv fwpriv;
+
+} ;
+
+enum fw_status {
+ FW_STATUS_INIT = 0,
+ FW_STATUS_LOAD_IMEM = 1,
+ FW_STATUS_LOAD_EMEM = 2,
+ FW_STATUS_LOAD_DMEM = 3,
+ FW_STATUS_READY = 4,
+};
+
+struct rt_firmware {
+ struct fw_hdr *pfwheader;
+ enum fw_status fwstatus;
+ u16 firmwareversion;
+ u8 fw_imem[RTL8190_MAX_FIRMWARE_CODE_SIZE];
+ u8 fw_emem[RTL8190_MAX_FIRMWARE_CODE_SIZE];
+ u32 fw_imem_len;
+ u32 fw_emem_len;
+ u8 sz_fw_tmpbuffer[164000];
+ u32 sz_fw_tmpbufferlen;
+ u16 cmdpacket_fragthresold;
+};
+
+struct h2c_set_pwrmode_parm {
+ u8 mode;
+ u8 flag_low_traffic_en;
+ u8 flag_lpnav_en;
+ u8 flag_rf_low_snr_en;
+ /* 1: dps, 0: 32k */
+ u8 flag_dps_en;
+ u8 bcn_rx_en;
+ u8 bcn_pass_cnt;
+ /* beacon TO (ms). ¡§=0¡¨ no limit. */
+ u8 bcn_to;
+ u16 bcn_itv;
+ /* only for VOIP mode. */
+ u8 app_itv;
+ u8 awake_bcn_itvl;
+ u8 smart_ps;
+ /* unit: 100 ms */
+ u8 bcn_pass_period;
+};
+
+struct h2c_joinbss_rpt_parm {
+ u8 opmode;
+ u8 ps_qos_info;
+ u8 bssid[6];
+ u16 bcnitv;
+ u16 aid;
+} ;
+
+struct h2c_wpa_ptk {
+ /* EAPOL-Key Key Confirmation Key (KCK) */
+ u8 kck[16];
+ /* EAPOL-Key Key Encryption Key (KEK) */
+ u8 kek[16];
+ /* Temporal Key 1 (TK1) */
+ u8 tk1[16];
+ union {
+ /* Temporal Key 2 (TK2) */
+ u8 tk2[16];
+ struct {
+ u8 tx_mic_key[8];
+ u8 rx_mic_key[8];
+ } athu;
+ } u;
+};
+
+struct h2c_wpa_two_way_parm {
+ /* algorithm TKIP or AES */
+ u8 pairwise_en_alg;
+ u8 group_en_alg;
+ struct h2c_wpa_ptk wpa_ptk_value;
+} ;
+
+enum h2c_cmd {
+ FW_H2C_SETPWRMODE = 0,
+ FW_H2C_JOINBSSRPT = 1,
+ FW_H2C_WOWLAN_UPDATE_GTK = 2,
+ FW_H2C_WOWLAN_UPDATE_IV = 3,
+ FW_H2C_WOWLAN_OFFLOAD = 4,
+};
+
+enum fw_h2c_cmd {
+ H2C_READ_MACREG_CMD, /*0*/
+ H2C_WRITE_MACREG_CMD,
+ H2C_READBB_CMD,
+ H2C_WRITEBB_CMD,
+ H2C_READRF_CMD,
+ H2C_WRITERF_CMD, /*5*/
+ H2C_READ_EEPROM_CMD,
+ H2C_WRITE_EEPROM_CMD,
+ H2C_READ_EFUSE_CMD,
+ H2C_WRITE_EFUSE_CMD,
+ H2C_READ_CAM_CMD, /*10*/
+ H2C_WRITE_CAM_CMD,
+ H2C_SETBCNITV_CMD,
+ H2C_SETMBIDCFG_CMD,
+ H2C_JOINBSS_CMD,
+ H2C_DISCONNECT_CMD, /*15*/
+ H2C_CREATEBSS_CMD,
+ H2C_SETOPMode_CMD,
+ H2C_SITESURVEY_CMD,
+ H2C_SETAUTH_CMD,
+ H2C_SETKEY_CMD, /*20*/
+ H2C_SETSTAKEY_CMD,
+ H2C_SETASSOCSTA_CMD,
+ H2C_DELASSOCSTA_CMD,
+ H2C_SETSTAPWRSTATE_CMD,
+ H2C_SETBASICRATE_CMD, /*25*/
+ H2C_GETBASICRATE_CMD,
+ H2C_SETDATARATE_CMD,
+ H2C_GETDATARATE_CMD,
+ H2C_SETPHYINFO_CMD,
+ H2C_GETPHYINFO_CMD, /*30*/
+ H2C_SETPHY_CMD,
+ H2C_GETPHY_CMD,
+ H2C_READRSSI_CMD,
+ H2C_READGAIN_CMD,
+ H2C_SETATIM_CMD, /*35*/
+ H2C_SETPWRMODE_CMD,
+ H2C_JOINBSSRPT_CMD,
+ H2C_SETRATABLE_CMD,
+ H2C_GETRATABLE_CMD,
+ H2C_GETCCXREPORT_CMD, /*40*/
+ H2C_GETDTMREPORT_CMD,
+ H2C_GETTXRATESTATICS_CMD,
+ H2C_SETUSBSUSPEND_CMD,
+ H2C_SETH2CLBK_CMD,
+ H2C_TMP1, /*45*/
+ H2C_WOWLAN_UPDATE_GTK_CMD,
+ H2C_WOWLAN_FW_OFFLOAD,
+ H2C_TMP2,
+ H2C_TMP3,
+ H2C_WOWLAN_UPDATE_IV_CMD, /*50*/
+ H2C_TMP4,
+ MAX_H2CCMD /*52*/
+};
+
+/* The following macros are used for FW
+ * CMD map and parameter updated. */
+#define FW_CMD_IO_CLR(rtlpriv, _Bit) \
+ do { \
+ udelay(1000); \
+ rtlpriv->rtlhal.fwcmd_iomap &= (~_Bit); \
+ } while (0);
+
+#define FW_CMD_IO_UPDATE(rtlpriv, _val) \
+ rtlpriv->rtlhal.fwcmd_iomap = _val;
+
+#define FW_CMD_IO_SET(rtlpriv, _val) \
+ do { \
+ rtl_write_word(rtlpriv, LBUS_MON_ADDR, (u16)_val); \
+ FW_CMD_IO_UPDATE(rtlpriv, _val); \
+ } while (0);
+
+#define FW_CMD_PARA_SET(rtlpriv, _val) \
+ do { \
+ rtl_write_dword(rtlpriv, LBUS_ADDR_MASK, _val); \
+ rtlpriv->rtlhal.fwcmd_ioparam = _val; \
+ } while (0);
+
+#define FW_CMD_IO_QUERY(rtlpriv) \
+ (u16)(rtlpriv->rtlhal.fwcmd_iomap)
+#define FW_CMD_IO_PARA_QUERY(rtlpriv) \
+ ((u32)(rtlpriv->rtlhal.fwcmd_ioparam))
+
+int rtl92s_download_fw(struct ieee80211_hw *hw);
+void rtl92s_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
+void rtl92s_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw,
+ u8 mstatus, u8 ps_qosinfo);
+
+#endif
+
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
new file mode 100644
index 000000000000..2e9005d0454b
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
@@ -0,0 +1,2512 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../efuse.h"
+#include "../base.h"
+#include "../regd.h"
+#include "../cam.h"
+#include "../ps.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "fw.h"
+#include "led.h"
+#include "hw.h"
+
+void rtl92se_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ switch (variable) {
+ case HW_VAR_RCR: {
+ *((u32 *) (val)) = rtlpci->receive_config;
+ break;
+ }
+ case HW_VAR_RF_STATE: {
+ *((enum rf_pwrstate *)(val)) = ppsc->rfpwr_state;
+ break;
+ }
+ case HW_VAR_FW_PSMODE_STATUS: {
+ *((bool *) (val)) = ppsc->fw_current_inpsmode;
+ break;
+ }
+ case HW_VAR_CORRECT_TSF: {
+ u64 tsf;
+ u32 *ptsf_low = (u32 *)&tsf;
+ u32 *ptsf_high = ((u32 *)&tsf) + 1;
+
+ *ptsf_high = rtl_read_dword(rtlpriv, (TSFR + 4));
+ *ptsf_low = rtl_read_dword(rtlpriv, TSFR);
+
+ *((u64 *) (val)) = tsf;
+
+ break;
+ }
+ case HW_VAR_MRC: {
+ *((bool *)(val)) = rtlpriv->dm.current_mrc_switch;
+ break;
+ }
+ default: {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ }
+ }
+}
+
+void rtl92se_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+ switch (variable) {
+ case HW_VAR_ETHER_ADDR:{
+ rtl_write_dword(rtlpriv, IDR0, ((u32 *)(val))[0]);
+ rtl_write_word(rtlpriv, IDR4, ((u16 *)(val + 4))[0]);
+ break;
+ }
+ case HW_VAR_BASIC_RATE:{
+ u16 rate_cfg = ((u16 *) val)[0];
+ u8 rate_index = 0;
+
+ if (rtlhal->version == VERSION_8192S_ACUT)
+ rate_cfg = rate_cfg & 0x150;
+ else
+ rate_cfg = rate_cfg & 0x15f;
+
+ rate_cfg |= 0x01;
+
+ rtl_write_byte(rtlpriv, RRSR, rate_cfg & 0xff);
+ rtl_write_byte(rtlpriv, RRSR + 1,
+ (rate_cfg >> 8) & 0xff);
+
+ while (rate_cfg > 0x1) {
+ rate_cfg = (rate_cfg >> 1);
+ rate_index++;
+ }
+ rtl_write_byte(rtlpriv, INIRTSMCS_SEL, rate_index);
+
+ break;
+ }
+ case HW_VAR_BSSID:{
+ rtl_write_dword(rtlpriv, BSSIDR, ((u32 *)(val))[0]);
+ rtl_write_word(rtlpriv, BSSIDR + 4,
+ ((u16 *)(val + 4))[0]);
+ break;
+ }
+ case HW_VAR_SIFS:{
+ rtl_write_byte(rtlpriv, SIFS_OFDM, val[0]);
+ rtl_write_byte(rtlpriv, SIFS_OFDM + 1, val[1]);
+ break;
+ }
+ case HW_VAR_SLOT_TIME:{
+ u8 e_aci;
+
+ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+ ("HW_VAR_SLOT_TIME %x\n", val[0]));
+
+ rtl_write_byte(rtlpriv, SLOT_TIME, val[0]);
+
+ for (e_aci = 0; e_aci < AC_MAX; e_aci++) {
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_AC_PARAM,
+ (u8 *)(&e_aci));
+ }
+ break;
+ }
+ case HW_VAR_ACK_PREAMBLE:{
+ u8 reg_tmp;
+ u8 short_preamble = (bool) (*(u8 *) val);
+ reg_tmp = (mac->cur_40_prime_sc) << 5;
+ if (short_preamble)
+ reg_tmp |= 0x80;
+
+ rtl_write_byte(rtlpriv, RRSR + 2, reg_tmp);
+ break;
+ }
+ case HW_VAR_AMPDU_MIN_SPACE:{
+ u8 min_spacing_to_set;
+ u8 sec_min_space;
+
+ min_spacing_to_set = *((u8 *)val);
+ if (min_spacing_to_set <= 7) {
+ if (rtlpriv->sec.pairwise_enc_algorithm ==
+ NO_ENCRYPTION)
+ sec_min_space = 0;
+ else
+ sec_min_space = 1;
+
+ if (min_spacing_to_set < sec_min_space)
+ min_spacing_to_set = sec_min_space;
+ if (min_spacing_to_set > 5)
+ min_spacing_to_set = 5;
+
+ mac->min_space_cfg =
+ ((mac->min_space_cfg & 0xf8) |
+ min_spacing_to_set);
+
+ *val = min_spacing_to_set;
+
+ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+ ("Set HW_VAR_AMPDU_MIN_SPACE: %#x\n",
+ mac->min_space_cfg));
+
+ rtl_write_byte(rtlpriv, AMPDU_MIN_SPACE,
+ mac->min_space_cfg);
+ }
+ break;
+ }
+ case HW_VAR_SHORTGI_DENSITY:{
+ u8 density_to_set;
+
+ density_to_set = *((u8 *) val);
+ mac->min_space_cfg = rtlpriv->rtlhal.minspace_cfg;
+ mac->min_space_cfg |= (density_to_set << 3);
+
+ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+ ("Set HW_VAR_SHORTGI_DENSITY: %#x\n",
+ mac->min_space_cfg));
+
+ rtl_write_byte(rtlpriv, AMPDU_MIN_SPACE,
+ mac->min_space_cfg);
+
+ break;
+ }
+ case HW_VAR_AMPDU_FACTOR:{
+ u8 factor_toset;
+ u8 regtoset;
+ u8 factorlevel[18] = {
+ 2, 4, 4, 7, 7, 13, 13,
+ 13, 2, 7, 7, 13, 13,
+ 15, 15, 15, 15, 0};
+ u8 index = 0;
+
+ factor_toset = *((u8 *) val);
+ if (factor_toset <= 3) {
+ factor_toset = (1 << (factor_toset + 2));
+ if (factor_toset > 0xf)
+ factor_toset = 0xf;
+
+ for (index = 0; index < 17; index++) {
+ if (factorlevel[index] > factor_toset)
+ factorlevel[index] =
+ factor_toset;
+ }
+
+ for (index = 0; index < 8; index++) {
+ regtoset = ((factorlevel[index * 2]) |
+ (factorlevel[index *
+ 2 + 1] << 4));
+ rtl_write_byte(rtlpriv,
+ AGGLEN_LMT_L + index,
+ regtoset);
+ }
+
+ regtoset = ((factorlevel[16]) |
+ (factorlevel[17] << 4));
+ rtl_write_byte(rtlpriv, AGGLEN_LMT_H, regtoset);
+
+ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+ ("Set HW_VAR_AMPDU_FACTOR: %#x\n",
+ factor_toset));
+ }
+ break;
+ }
+ case HW_VAR_AC_PARAM:{
+ u8 e_aci = *((u8 *) val);
+ rtl92s_dm_init_edca_turbo(hw);
+
+ if (rtlpci->acm_method != eAcmWay2_SW)
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_ACM_CTRL,
+ (u8 *)(&e_aci));
+ break;
+ }
+ case HW_VAR_ACM_CTRL:{
+ u8 e_aci = *((u8 *) val);
+ union aci_aifsn *p_aci_aifsn = (union aci_aifsn *)(&(
+ mac->ac[0].aifs));
+ u8 acm = p_aci_aifsn->f.acm;
+ u8 acm_ctrl = rtl_read_byte(rtlpriv, AcmHwCtrl);
+
+ acm_ctrl = acm_ctrl | ((rtlpci->acm_method == 2) ?
+ 0x0 : 0x1);
+
+ if (acm) {
+ switch (e_aci) {
+ case AC0_BE:
+ acm_ctrl |= AcmHw_BeqEn;
+ break;
+ case AC2_VI:
+ acm_ctrl |= AcmHw_ViqEn;
+ break;
+ case AC3_VO:
+ acm_ctrl |= AcmHw_VoqEn;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("HW_VAR_ACM_CTRL acm set "
+ "failed: eACI is %d\n", acm));
+ break;
+ }
+ } else {
+ switch (e_aci) {
+ case AC0_BE:
+ acm_ctrl &= (~AcmHw_BeqEn);
+ break;
+ case AC2_VI:
+ acm_ctrl &= (~AcmHw_ViqEn);
+ break;
+ case AC3_VO:
+ acm_ctrl &= (~AcmHw_BeqEn);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ }
+ }
+
+ RT_TRACE(rtlpriv, COMP_QOS, DBG_TRACE,
+ ("HW_VAR_ACM_CTRL Write 0x%X\n", acm_ctrl));
+ rtl_write_byte(rtlpriv, AcmHwCtrl, acm_ctrl);
+ break;
+ }
+ case HW_VAR_RCR:{
+ rtl_write_dword(rtlpriv, RCR, ((u32 *) (val))[0]);
+ rtlpci->receive_config = ((u32 *) (val))[0];
+ break;
+ }
+ case HW_VAR_RETRY_LIMIT:{
+ u8 retry_limit = ((u8 *) (val))[0];
+
+ rtl_write_word(rtlpriv, RETRY_LIMIT,
+ retry_limit << RETRY_LIMIT_SHORT_SHIFT |
+ retry_limit << RETRY_LIMIT_LONG_SHIFT);
+ break;
+ }
+ case HW_VAR_DUAL_TSF_RST: {
+ break;
+ }
+ case HW_VAR_EFUSE_BYTES: {
+ rtlefuse->efuse_usedbytes = *((u16 *) val);
+ break;
+ }
+ case HW_VAR_EFUSE_USAGE: {
+ rtlefuse->efuse_usedpercentage = *((u8 *) val);
+ break;
+ }
+ case HW_VAR_IO_CMD: {
+ break;
+ }
+ case HW_VAR_WPA_CONFIG: {
+ rtl_write_byte(rtlpriv, REG_SECR, *((u8 *) val));
+ break;
+ }
+ case HW_VAR_SET_RPWM:{
+ break;
+ }
+ case HW_VAR_H2C_FW_PWRMODE:{
+ break;
+ }
+ case HW_VAR_FW_PSMODE_STATUS: {
+ ppsc->fw_current_inpsmode = *((bool *) val);
+ break;
+ }
+ case HW_VAR_H2C_FW_JOINBSSRPT:{
+ break;
+ }
+ case HW_VAR_AID:{
+ break;
+ }
+ case HW_VAR_CORRECT_TSF:{
+ break;
+ }
+ case HW_VAR_MRC: {
+ bool bmrc_toset = *((bool *)val);
+ u8 u1bdata = 0;
+
+ if (bmrc_toset) {
+ rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE,
+ MASKBYTE0, 0x33);
+ u1bdata = (u8)rtl_get_bbreg(hw,
+ ROFDM1_TRXPATHENABLE,
+ MASKBYTE0);
+ rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE,
+ MASKBYTE0,
+ ((u1bdata & 0xf0) | 0x03));
+ u1bdata = (u8)rtl_get_bbreg(hw,
+ ROFDM0_TRXPATHENABLE,
+ MASKBYTE1);
+ rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE,
+ MASKBYTE1,
+ (u1bdata | 0x04));
+
+ /* Update current settings. */
+ rtlpriv->dm.current_mrc_switch = bmrc_toset;
+ } else {
+ rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE,
+ MASKBYTE0, 0x13);
+ u1bdata = (u8)rtl_get_bbreg(hw,
+ ROFDM1_TRXPATHENABLE,
+ MASKBYTE0);
+ rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE,
+ MASKBYTE0,
+ ((u1bdata & 0xf0) | 0x01));
+ u1bdata = (u8)rtl_get_bbreg(hw,
+ ROFDM0_TRXPATHENABLE,
+ MASKBYTE1);
+ rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE,
+ MASKBYTE1, (u1bdata & 0xfb));
+
+ /* Update current settings. */
+ rtlpriv->dm.current_mrc_switch = bmrc_toset;
+ }
+
+ break;
+ }
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ }
+
+}
+
+void rtl92se_enable_hw_security_config(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 sec_reg_value = 0x0;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("PairwiseEncAlgorithm = %d "
+ "GroupEncAlgorithm = %d\n",
+ rtlpriv->sec.pairwise_enc_algorithm,
+ rtlpriv->sec.group_enc_algorithm));
+
+ if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("not open hw encryption\n"));
+ return;
+ }
+
+ sec_reg_value = SCR_TXENCENABLE | SCR_RXENCENABLE;
+
+ if (rtlpriv->sec.use_defaultkey) {
+ sec_reg_value |= SCR_TXUSEDK;
+ sec_reg_value |= SCR_RXUSEDK;
+ }
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, ("The SECR-value %x\n",
+ sec_reg_value));
+
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value);
+
+}
+
+static u8 _rtl92ce_halset_sysclk(struct ieee80211_hw *hw, u8 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 waitcount = 100;
+ bool bresult = false;
+ u8 tmpvalue;
+
+ rtl_write_byte(rtlpriv, SYS_CLKR + 1, data);
+
+ /* Wait the MAC synchronized. */
+ udelay(400);
+
+ /* Check if it is set ready. */
+ tmpvalue = rtl_read_byte(rtlpriv, SYS_CLKR + 1);
+ bresult = ((tmpvalue & BIT(7)) == (data & BIT(7)));
+
+ if ((data & (BIT(6) | BIT(7))) == false) {
+ waitcount = 100;
+ tmpvalue = 0;
+
+ while (1) {
+ waitcount--;
+
+ tmpvalue = rtl_read_byte(rtlpriv, SYS_CLKR + 1);
+ if ((tmpvalue & BIT(6)))
+ break;
+
+ printk(KERN_ERR "wait for BIT(6) return value %x\n",
+ tmpvalue);
+ if (waitcount == 0)
+ break;
+
+ udelay(10);
+ }
+
+ if (waitcount == 0)
+ bresult = false;
+ else
+ bresult = true;
+ }
+
+ return bresult;
+}
+
+void rtl8192se_gpiobit3_cfg_inputmode(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 u1tmp;
+
+ /* The following config GPIO function */
+ rtl_write_byte(rtlpriv, MAC_PINMUX_CFG, (GPIOMUX_EN | GPIOSEL_GPIO));
+ u1tmp = rtl_read_byte(rtlpriv, GPIO_IO_SEL);
+
+ /* config GPIO3 to input */
+ u1tmp &= HAL_8192S_HW_GPIO_OFF_MASK;
+ rtl_write_byte(rtlpriv, GPIO_IO_SEL, u1tmp);
+
+}
+
+static u8 _rtl92se_rf_onoff_detect(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 u1tmp;
+ u8 retval = ERFON;
+
+ /* The following config GPIO function */
+ rtl_write_byte(rtlpriv, MAC_PINMUX_CFG, (GPIOMUX_EN | GPIOSEL_GPIO));
+ u1tmp = rtl_read_byte(rtlpriv, GPIO_IO_SEL);
+
+ /* config GPIO3 to input */
+ u1tmp &= HAL_8192S_HW_GPIO_OFF_MASK;
+ rtl_write_byte(rtlpriv, GPIO_IO_SEL, u1tmp);
+
+ /* On some of the platform, driver cannot read correct
+ * value without delay between Write_GPIO_SEL and Read_GPIO_IN */
+ mdelay(10);
+
+ /* check GPIO3 */
+ u1tmp = rtl_read_byte(rtlpriv, GPIO_IN);
+ retval = (u1tmp & HAL_8192S_HW_GPIO_OFF_BIT) ? ERFON : ERFOFF;
+
+ return retval;
+}
+
+static void _rtl92se_macconfig_before_fwdownload(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+ u8 i;
+ u8 tmpu1b;
+ u16 tmpu2b;
+ u8 pollingcnt = 20;
+
+ if (rtlpci->first_init) {
+ /* Reset PCIE Digital */
+ tmpu1b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+ tmpu1b &= 0xFE;
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b);
+ udelay(1);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b | BIT(0));
+ }
+
+ /* Switch to SW IO control */
+ tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1));
+ if (tmpu1b & BIT(7)) {
+ tmpu1b &= ~(BIT(6) | BIT(7));
+
+ /* Set failed, return to prevent hang. */
+ if (!_rtl92ce_halset_sysclk(hw, tmpu1b))
+ return;
+ }
+
+ rtl_write_byte(rtlpriv, AFE_PLL_CTRL, 0x0);
+ udelay(50);
+ rtl_write_byte(rtlpriv, LDOA15_CTRL, 0x34);
+ udelay(50);
+
+ /* Clear FW RPWM for FW control LPS.*/
+ rtl_write_byte(rtlpriv, RPWM, 0x0);
+
+ /* Reset MAC-IO and CPU and Core Digital BIT(10)/11/15 */
+ tmpu1b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+ tmpu1b &= 0x73;
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b);
+ /* wait for BIT 10/11/15 to pull high automatically!! */
+ mdelay(1);
+
+ rtl_write_byte(rtlpriv, CMDR, 0);
+ rtl_write_byte(rtlpriv, TCR, 0);
+
+ /* Data sheet not define 0x562!!! Copy from WMAC!!!!! */
+ tmpu1b = rtl_read_byte(rtlpriv, 0x562);
+ tmpu1b |= 0x08;
+ rtl_write_byte(rtlpriv, 0x562, tmpu1b);
+ tmpu1b &= ~(BIT(3));
+ rtl_write_byte(rtlpriv, 0x562, tmpu1b);
+
+ /* Enable AFE clock source */
+ tmpu1b = rtl_read_byte(rtlpriv, AFE_XTAL_CTRL);
+ rtl_write_byte(rtlpriv, AFE_XTAL_CTRL, (tmpu1b | 0x01));
+ /* Delay 1.5ms */
+ mdelay(2);
+ tmpu1b = rtl_read_byte(rtlpriv, AFE_XTAL_CTRL + 1);
+ rtl_write_byte(rtlpriv, AFE_XTAL_CTRL + 1, (tmpu1b & 0xfb));
+
+ /* Enable AFE Macro Block's Bandgap */
+ tmpu1b = rtl_read_byte(rtlpriv, AFE_MISC);
+ rtl_write_byte(rtlpriv, AFE_MISC, (tmpu1b | BIT(0)));
+ mdelay(1);
+
+ /* Enable AFE Mbias */
+ tmpu1b = rtl_read_byte(rtlpriv, AFE_MISC);
+ rtl_write_byte(rtlpriv, AFE_MISC, (tmpu1b | 0x02));
+ mdelay(1);
+
+ /* Enable LDOA15 block */
+ tmpu1b = rtl_read_byte(rtlpriv, LDOA15_CTRL);
+ rtl_write_byte(rtlpriv, LDOA15_CTRL, (tmpu1b | BIT(0)));
+
+ /* Set Digital Vdd to Retention isolation Path. */
+ tmpu2b = rtl_read_word(rtlpriv, REG_SYS_ISO_CTRL);
+ rtl_write_word(rtlpriv, REG_SYS_ISO_CTRL, (tmpu2b | BIT(11)));
+
+ /* For warm reboot NIC disappera bug. */
+ tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN);
+ rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(13)));
+
+ rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, 0x68);
+
+ /* Enable AFE PLL Macro Block */
+ /* We need to delay 100u before enabling PLL. */
+ udelay(200);
+ tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL);
+ rtl_write_byte(rtlpriv, AFE_PLL_CTRL, (tmpu1b | BIT(0) | BIT(4)));
+
+ /* for divider reset */
+ udelay(100);
+ rtl_write_byte(rtlpriv, AFE_PLL_CTRL, (tmpu1b | BIT(0) |
+ BIT(4) | BIT(6)));
+ udelay(10);
+ rtl_write_byte(rtlpriv, AFE_PLL_CTRL, (tmpu1b | BIT(0) | BIT(4)));
+ udelay(10);
+
+ /* Enable MAC 80MHZ clock */
+ tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL + 1);
+ rtl_write_byte(rtlpriv, AFE_PLL_CTRL + 1, (tmpu1b | BIT(0)));
+ mdelay(1);
+
+ /* Release isolation AFE PLL & MD */
+ rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL, 0xA6);
+
+ /* Enable MAC clock */
+ tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR);
+ rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b | BIT(12) | BIT(11)));
+
+ /* Enable Core digital and enable IOREG R/W */
+ tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN);
+ rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(11)));
+
+ tmpu1b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b & ~(BIT(7)));
+
+ /* enable REG_EN */
+ rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(11) | BIT(15)));
+
+ /* Switch the control path. */
+ tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR);
+ rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b & (~BIT(2))));
+
+ tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1));
+ tmpu1b = ((tmpu1b | BIT(7)) & (~BIT(6)));
+ if (!_rtl92ce_halset_sysclk(hw, tmpu1b))
+ return; /* Set failed, return to prevent hang. */
+
+ rtl_write_word(rtlpriv, CMDR, 0x07FC);
+
+ /* MH We must enable the section of code to prevent load IMEM fail. */
+ /* Load MAC register from WMAc temporarily We simulate macreg. */
+ /* txt HW will provide MAC txt later */
+ rtl_write_byte(rtlpriv, 0x6, 0x30);
+ rtl_write_byte(rtlpriv, 0x49, 0xf0);
+
+ rtl_write_byte(rtlpriv, 0x4b, 0x81);
+
+ rtl_write_byte(rtlpriv, 0xb5, 0x21);
+
+ rtl_write_byte(rtlpriv, 0xdc, 0xff);
+ rtl_write_byte(rtlpriv, 0xdd, 0xff);
+ rtl_write_byte(rtlpriv, 0xde, 0xff);
+ rtl_write_byte(rtlpriv, 0xdf, 0xff);
+
+ rtl_write_byte(rtlpriv, 0x11a, 0x00);
+ rtl_write_byte(rtlpriv, 0x11b, 0x00);
+
+ for (i = 0; i < 32; i++)
+ rtl_write_byte(rtlpriv, INIMCS_SEL + i, 0x1b);
+
+ rtl_write_byte(rtlpriv, 0x236, 0xff);
+
+ rtl_write_byte(rtlpriv, 0x503, 0x22);
+
+ if (ppsc->support_aspm && !ppsc->support_backdoor)
+ rtl_write_byte(rtlpriv, 0x560, 0x40);
+ else
+ rtl_write_byte(rtlpriv, 0x560, 0x00);
+
+ rtl_write_byte(rtlpriv, DBG_PORT, 0x91);
+
+ /* Set RX Desc Address */
+ rtl_write_dword(rtlpriv, RDQDA, rtlpci->rx_ring[RX_MPDU_QUEUE].dma);
+ rtl_write_dword(rtlpriv, RCDA, rtlpci->rx_ring[RX_CMD_QUEUE].dma);
+
+ /* Set TX Desc Address */
+ rtl_write_dword(rtlpriv, TBKDA, rtlpci->tx_ring[BK_QUEUE].dma);
+ rtl_write_dword(rtlpriv, TBEDA, rtlpci->tx_ring[BE_QUEUE].dma);
+ rtl_write_dword(rtlpriv, TVIDA, rtlpci->tx_ring[VI_QUEUE].dma);
+ rtl_write_dword(rtlpriv, TVODA, rtlpci->tx_ring[VO_QUEUE].dma);
+ rtl_write_dword(rtlpriv, TBDA, rtlpci->tx_ring[BEACON_QUEUE].dma);
+ rtl_write_dword(rtlpriv, TCDA, rtlpci->tx_ring[TXCMD_QUEUE].dma);
+ rtl_write_dword(rtlpriv, TMDA, rtlpci->tx_ring[MGNT_QUEUE].dma);
+ rtl_write_dword(rtlpriv, THPDA, rtlpci->tx_ring[HIGH_QUEUE].dma);
+ rtl_write_dword(rtlpriv, HDA, rtlpci->tx_ring[HCCA_QUEUE].dma);
+
+ rtl_write_word(rtlpriv, CMDR, 0x37FC);
+
+ /* To make sure that TxDMA can ready to download FW. */
+ /* We should reset TxDMA if IMEM RPT was not ready. */
+ do {
+ tmpu1b = rtl_read_byte(rtlpriv, TCR);
+ if ((tmpu1b & TXDMA_INIT_VALUE) == TXDMA_INIT_VALUE)
+ break;
+
+ udelay(5);
+ } while (pollingcnt--);
+
+ if (pollingcnt <= 0) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Polling TXDMA_INIT_VALUE "
+ "timeout!! Current TCR(%#x)\n", tmpu1b));
+ tmpu1b = rtl_read_byte(rtlpriv, CMDR);
+ rtl_write_byte(rtlpriv, CMDR, tmpu1b & (~TXDMA_EN));
+ udelay(2);
+ /* Reset TxDMA */
+ rtl_write_byte(rtlpriv, CMDR, tmpu1b | TXDMA_EN);
+ }
+
+ /* After MACIO reset,we must refresh LED state. */
+ if ((ppsc->rfoff_reason == RF_CHANGE_BY_IPS) ||
+ (ppsc->rfoff_reason == 0)) {
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0);
+ enum rf_pwrstate rfpwr_state_toset;
+ rfpwr_state_toset = _rtl92se_rf_onoff_detect(hw);
+
+ if (rfpwr_state_toset == ERFON)
+ rtl92se_sw_led_on(hw, pLed0);
+ }
+}
+
+static void _rtl92se_macconfig_after_fwdownload(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ u8 i;
+ u16 tmpu2b;
+
+ /* 1. System Configure Register (Offset: 0x0000 - 0x003F) */
+
+ /* 2. Command Control Register (Offset: 0x0040 - 0x004F) */
+ /* Turn on 0x40 Command register */
+ rtl_write_word(rtlpriv, CMDR, (BBRSTN | BB_GLB_RSTN |
+ SCHEDULE_EN | MACRXEN | MACTXEN | DDMA_EN | FW2HW_EN |
+ RXDMA_EN | TXDMA_EN | HCI_RXDMA_EN | HCI_TXDMA_EN));
+
+ /* Set TCR TX DMA pre 2 FULL enable bit */
+ rtl_write_dword(rtlpriv, TCR, rtl_read_dword(rtlpriv, TCR) |
+ TXDMAPRE2FULL);
+
+ /* Set RCR */
+ rtl_write_dword(rtlpriv, RCR, rtlpci->receive_config);
+
+ /* 3. MACID Setting Register (Offset: 0x0050 - 0x007F) */
+
+ /* 4. Timing Control Register (Offset: 0x0080 - 0x009F) */
+ /* Set CCK/OFDM SIFS */
+ /* CCK SIFS shall always be 10us. */
+ rtl_write_word(rtlpriv, SIFS_CCK, 0x0a0a);
+ rtl_write_word(rtlpriv, SIFS_OFDM, 0x1010);
+
+ /* Set AckTimeout */
+ rtl_write_byte(rtlpriv, ACK_TIMEOUT, 0x40);
+
+ /* Beacon related */
+ rtl_write_word(rtlpriv, BCN_INTERVAL, 100);
+ rtl_write_word(rtlpriv, ATIMWND, 2);
+
+ /* 5. FIFO Control Register (Offset: 0x00A0 - 0x015F) */
+ /* 5.1 Initialize Number of Reserved Pages in Firmware Queue */
+ /* Firmware allocate now, associate with FW internal setting.!!! */
+
+ /* 5.2 Setting TX/RX page size 0/1/2/3/4=64/128/256/512/1024 */
+ /* 5.3 Set driver info, we only accept PHY status now. */
+ /* 5.4 Set RXDMA arbitration to control RXDMA/MAC/FW R/W for RXFIFO */
+ rtl_write_byte(rtlpriv, RXDMA, rtl_read_byte(rtlpriv, RXDMA) | BIT(6));
+
+ /* 6. Adaptive Control Register (Offset: 0x0160 - 0x01CF) */
+ /* Set RRSR to all legacy rate and HT rate
+ * CCK rate is supported by default.
+ * CCK rate will be filtered out only when associated
+ * AP does not support it.
+ * Only enable ACK rate to OFDM 24M
+ * Disable RRSR for CCK rate in A-Cut */
+
+ if (rtlhal->version == VERSION_8192S_ACUT)
+ rtl_write_byte(rtlpriv, RRSR, 0xf0);
+ else if (rtlhal->version == VERSION_8192S_BCUT)
+ rtl_write_byte(rtlpriv, RRSR, 0xff);
+ rtl_write_byte(rtlpriv, RRSR + 1, 0x01);
+ rtl_write_byte(rtlpriv, RRSR + 2, 0x00);
+
+ /* A-Cut IC do not support CCK rate. We forbid ARFR to */
+ /* fallback to CCK rate */
+ for (i = 0; i < 8; i++) {
+ /*Disable RRSR for CCK rate in A-Cut */
+ if (rtlhal->version == VERSION_8192S_ACUT)
+ rtl_write_dword(rtlpriv, ARFR0 + i * 4, 0x1f0ff0f0);
+ }
+
+ /* Different rate use different AMPDU size */
+ /* MCS32/ MCS15_SG use max AMPDU size 15*2=30K */
+ rtl_write_byte(rtlpriv, AGGLEN_LMT_H, 0x0f);
+ /* MCS0/1/2/3 use max AMPDU size 4*2=8K */
+ rtl_write_word(rtlpriv, AGGLEN_LMT_L, 0x7442);
+ /* MCS4/5 use max AMPDU size 8*2=16K 6/7 use 10*2=20K */
+ rtl_write_word(rtlpriv, AGGLEN_LMT_L + 2, 0xddd7);
+ /* MCS8/9 use max AMPDU size 8*2=16K 10/11 use 10*2=20K */
+ rtl_write_word(rtlpriv, AGGLEN_LMT_L + 4, 0xd772);
+ /* MCS12/13/14/15 use max AMPDU size 15*2=30K */
+ rtl_write_word(rtlpriv, AGGLEN_LMT_L + 6, 0xfffd);
+
+ /* Set Data / Response auto rate fallack retry count */
+ rtl_write_dword(rtlpriv, DARFRC, 0x04010000);
+ rtl_write_dword(rtlpriv, DARFRC + 4, 0x09070605);
+ rtl_write_dword(rtlpriv, RARFRC, 0x04010000);
+ rtl_write_dword(rtlpriv, RARFRC + 4, 0x09070605);
+
+ /* 7. EDCA Setting Register (Offset: 0x01D0 - 0x01FF) */
+ /* Set all rate to support SG */
+ rtl_write_word(rtlpriv, SG_RATE, 0xFFFF);
+
+ /* 8. WMAC, BA, and CCX related Register (Offset: 0x0200 - 0x023F) */
+ /* Set NAV protection length */
+ rtl_write_word(rtlpriv, NAV_PROT_LEN, 0x0080);
+ /* CF-END Threshold */
+ rtl_write_byte(rtlpriv, CFEND_TH, 0xFF);
+ /* Set AMPDU minimum space */
+ rtl_write_byte(rtlpriv, AMPDU_MIN_SPACE, 0x07);
+ /* Set TXOP stall control for several queue/HI/BCN/MGT/ */
+ rtl_write_byte(rtlpriv, TXOP_STALL_CTRL, 0x00);
+
+ /* 9. Security Control Register (Offset: 0x0240 - 0x025F) */
+ /* 10. Power Save Control Register (Offset: 0x0260 - 0x02DF) */
+ /* 11. General Purpose Register (Offset: 0x02E0 - 0x02FF) */
+ /* 12. Host Interrupt Status Register (Offset: 0x0300 - 0x030F) */
+ /* 13. Test Mode and Debug Control Register (Offset: 0x0310 - 0x034F) */
+
+ /* 14. Set driver info, we only accept PHY status now. */
+ rtl_write_byte(rtlpriv, RXDRVINFO_SZ, 4);
+
+ /* 15. For EEPROM R/W Workaround */
+ /* 16. For EFUSE to share REG_SYS_FUNC_EN with EEPROM!!! */
+ tmpu2b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, tmpu2b | BIT(13));
+ tmpu2b = rtl_read_byte(rtlpriv, REG_SYS_ISO_CTRL);
+ rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL, tmpu2b & (~BIT(8)));
+
+ /* 17. For EFUSE */
+ /* We may R/W EFUSE in EEPROM mode */
+ if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) {
+ u8 tempval;
+
+ tempval = rtl_read_byte(rtlpriv, REG_SYS_ISO_CTRL + 1);
+ tempval &= 0xFE;
+ rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, tempval);
+
+ /* Change Program timing */
+ rtl_write_byte(rtlpriv, REG_EFUSE_CTRL + 3, 0x72);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("EFUSE CONFIG OK\n"));
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("OK\n"));
+
+}
+
+static void _rtl92se_hw_configure(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ u8 reg_bw_opmode = 0;
+ u32 reg_ratr = 0, reg_rrsr = 0;
+ u8 regtmp = 0;
+
+ reg_bw_opmode = BW_OPMODE_20MHZ;
+ reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS |
+ RATE_ALL_OFDM_2SS;
+ reg_rrsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
+
+ regtmp = rtl_read_byte(rtlpriv, INIRTSMCS_SEL);
+ reg_rrsr = ((reg_rrsr & 0x000fffff) << 8) | regtmp;
+ rtl_write_dword(rtlpriv, INIRTSMCS_SEL, reg_rrsr);
+ rtl_write_byte(rtlpriv, BW_OPMODE, reg_bw_opmode);
+
+ /* Set Retry Limit here */
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RETRY_LIMIT,
+ (u8 *)(&rtlpci->shortretry_limit));
+
+ rtl_write_byte(rtlpriv, MLT, 0x8f);
+
+ /* For Min Spacing configuration. */
+ switch (rtlphy->rf_type) {
+ case RF_1T2R:
+ case RF_1T1R:
+ rtlhal->minspace_cfg = (MAX_MSS_DENSITY_1T << 3);
+ break;
+ case RF_2T2R:
+ case RF_2T2R_GREEN:
+ rtlhal->minspace_cfg = (MAX_MSS_DENSITY_2T << 3);
+ break;
+ }
+ rtl_write_byte(rtlpriv, AMPDU_MIN_SPACE, rtlhal->minspace_cfg);
+}
+
+int rtl92se_hw_init(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 tmp_byte = 0;
+
+ bool rtstatus = true;
+ u8 tmp_u1b;
+ int err = false;
+ u8 i;
+ int wdcapra_add[] = {
+ EDCAPARA_BE, EDCAPARA_BK,
+ EDCAPARA_VI, EDCAPARA_VO};
+ u8 secr_value = 0x0;
+
+ rtlpci->being_init_adapter = true;
+
+ rtlpriv->intf_ops->disable_aspm(hw);
+
+ /* 1. MAC Initialize */
+ /* Before FW download, we have to set some MAC register */
+ _rtl92se_macconfig_before_fwdownload(hw);
+
+ rtlhal->version = (enum version_8192s)((rtl_read_dword(rtlpriv,
+ PMC_FSM) >> 16) & 0xF);
+
+ rtl8192se_gpiobit3_cfg_inputmode(hw);
+
+ /* 2. download firmware */
+ rtstatus = rtl92s_download_fw(hw);
+ if (!rtstatus) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("Failed to download FW. "
+ "Init HW without FW now.., Please copy FW into"
+ "/lib/firmware/rtlwifi\n"));
+ rtlhal->fw_ready = false;
+ } else {
+ rtlhal->fw_ready = true;
+ }
+
+ /* After FW download, we have to reset MAC register */
+ _rtl92se_macconfig_after_fwdownload(hw);
+
+ /*Retrieve default FW Cmd IO map. */
+ rtlhal->fwcmd_iomap = rtl_read_word(rtlpriv, LBUS_MON_ADDR);
+ rtlhal->fwcmd_ioparam = rtl_read_dword(rtlpriv, LBUS_ADDR_MASK);
+
+ /* 3. Initialize MAC/PHY Config by MACPHY_reg.txt */
+ if (rtl92s_phy_mac_config(hw) != true) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("MAC Config failed\n"));
+ return rtstatus;
+ }
+
+ /* Make sure BB/RF write OK. We should prevent enter IPS. radio off. */
+ /* We must set flag avoid BB/RF config period later!! */
+ rtl_write_dword(rtlpriv, CMDR, 0x37FC);
+
+ /* 4. Initialize BB After MAC Config PHY_reg.txt, AGC_Tab.txt */
+ if (rtl92s_phy_bb_config(hw) != true) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, ("BB Config failed\n"));
+ return rtstatus;
+ }
+
+ /* 5. Initiailze RF RAIO_A.txt RF RAIO_B.txt */
+ /* Before initalizing RF. We can not use FW to do RF-R/W. */
+
+ rtlphy->rf_mode = RF_OP_BY_SW_3WIRE;
+
+ /* RF Power Save */
+#if 0
+ /* H/W or S/W RF OFF before sleep. */
+ if (rtlpriv->psc.rfoff_reason > RF_CHANGE_BY_PS) {
+ u32 rfoffreason = rtlpriv->psc.rfoff_reason;
+
+ rtlpriv->psc.rfoff_reason = RF_CHANGE_BY_INIT;
+ rtlpriv->psc.rfpwr_state = ERFON;
+ rtl_ps_set_rf_state(hw, ERFOFF, rfoffreason, true);
+ } else {
+ /* gpio radio on/off is out of adapter start */
+ if (rtlpriv->psc.hwradiooff == false) {
+ rtlpriv->psc.rfpwr_state = ERFON;
+ rtlpriv->psc.rfoff_reason = 0;
+ }
+ }
+#endif
+
+ /* Before RF-R/W we must execute the IO from Scott's suggestion. */
+ rtl_write_byte(rtlpriv, AFE_XTAL_CTRL + 1, 0xDB);
+ if (rtlhal->version == VERSION_8192S_ACUT)
+ rtl_write_byte(rtlpriv, SPS1_CTRL + 3, 0x07);
+ else
+ rtl_write_byte(rtlpriv, RF_CTRL, 0x07);
+
+ if (rtl92s_phy_rf_config(hw) != true) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("RF Config failed\n"));
+ return rtstatus;
+ }
+
+ /* After read predefined TXT, we must set BB/MAC/RF
+ * register as our requirement */
+
+ rtlphy->rfreg_chnlval[0] = rtl92s_phy_query_rf_reg(hw,
+ (enum radio_path)0,
+ RF_CHNLBW,
+ RFREG_OFFSET_MASK);
+ rtlphy->rfreg_chnlval[1] = rtl92s_phy_query_rf_reg(hw,
+ (enum radio_path)1,
+ RF_CHNLBW,
+ RFREG_OFFSET_MASK);
+
+ /*---- Set CCK and OFDM Block "ON"----*/
+ rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1);
+ rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1);
+
+ /*3 Set Hardware(Do nothing now) */
+ _rtl92se_hw_configure(hw);
+
+ /* Read EEPROM TX power index and PHY_REG_PG.txt to capture correct */
+ /* TX power index for different rate set. */
+ /* Get original hw reg values */
+ rtl92s_phy_get_hw_reg_originalvalue(hw);
+ /* Write correct tx power index */
+ rtl92s_phy_set_txpower(hw, rtlphy->current_channel);
+
+ /* We must set MAC address after firmware download. */
+ for (i = 0; i < 6; i++)
+ rtl_write_byte(rtlpriv, MACIDR0 + i, rtlefuse->dev_addr[i]);
+
+ /* EEPROM R/W workaround */
+ tmp_u1b = rtl_read_byte(rtlpriv, MAC_PINMUX_CFG);
+ rtl_write_byte(rtlpriv, MAC_PINMUX_CFG, tmp_u1b & (~BIT(3)));
+
+ rtl_write_byte(rtlpriv, 0x4d, 0x0);
+
+ if (hal_get_firmwareversion(rtlpriv) >= 0x49) {
+ tmp_byte = rtl_read_byte(rtlpriv, FW_RSVD_PG_CRTL) & (~BIT(4));
+ tmp_byte = tmp_byte | BIT(5);
+ rtl_write_byte(rtlpriv, FW_RSVD_PG_CRTL, tmp_byte);
+ rtl_write_dword(rtlpriv, TXDESC_MSK, 0xFFFFCFFF);
+ }
+
+ /* We enable high power and RA related mechanism after NIC
+ * initialized. */
+ rtl92s_phy_set_fw_cmd(hw, FW_CMD_RA_INIT);
+
+ /* Add to prevent ASPM bug. */
+ /* Always enable hst and NIC clock request. */
+ rtl92s_phy_switch_ephy_parameter(hw);
+
+ /* Security related
+ * 1. Clear all H/W keys.
+ * 2. Enable H/W encryption/decryption. */
+ rtl_cam_reset_all_entry(hw);
+ secr_value |= SCR_TXENCENABLE;
+ secr_value |= SCR_RXENCENABLE;
+ secr_value |= SCR_NOSKMC;
+ rtl_write_byte(rtlpriv, REG_SECR, secr_value);
+
+ for (i = 0; i < 4; i++)
+ rtl_write_dword(rtlpriv, wdcapra_add[i], 0x5e4322);
+
+ if (rtlphy->rf_type == RF_1T2R) {
+ bool mrc2set = true;
+ /* Turn on B-Path */
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_MRC, (u8 *)&mrc2set);
+ }
+
+ rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_ON);
+ rtl92s_dm_init(hw);
+ rtlpci->being_init_adapter = false;
+
+ return err;
+}
+
+void rtl92se_set_mac_addr(struct rtl_io *io, const u8 * addr)
+{
+}
+
+void rtl92se_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ u32 reg_rcr = rtlpci->receive_config;
+
+ if (rtlpriv->psc.rfpwr_state != ERFON)
+ return;
+
+ if (check_bssid == true) {
+ reg_rcr |= (RCR_CBSSID);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(&reg_rcr));
+ } else if (check_bssid == false) {
+ reg_rcr &= (~RCR_CBSSID);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(&reg_rcr));
+ }
+
+}
+
+static int _rtl92se_set_media_status(struct ieee80211_hw *hw,
+ enum nl80211_iftype type)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 bt_msr = rtl_read_byte(rtlpriv, MSR);
+ enum led_ctl_mode ledaction = LED_CTL_NO_LINK;
+ u32 temp;
+ bt_msr &= ~MSR_LINK_MASK;
+
+ switch (type) {
+ case NL80211_IFTYPE_UNSPECIFIED:
+ bt_msr |= (MSR_LINK_NONE << MSR_LINK_SHIFT);
+ ledaction = LED_CTL_LINK;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("Set Network type to NO LINK!\n"));
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ bt_msr |= (MSR_LINK_ADHOC << MSR_LINK_SHIFT);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("Set Network type to Ad Hoc!\n"));
+ break;
+ case NL80211_IFTYPE_STATION:
+ bt_msr |= (MSR_LINK_MANAGED << MSR_LINK_SHIFT);
+ ledaction = LED_CTL_LINK;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("Set Network type to STA!\n"));
+ break;
+ case NL80211_IFTYPE_AP:
+ bt_msr |= (MSR_LINK_MASTER << MSR_LINK_SHIFT);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("Set Network type to AP!\n"));
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Network type %d not support!\n", type));
+ return 1;
+ break;
+
+ }
+
+ rtl_write_byte(rtlpriv, (MSR), bt_msr);
+
+ temp = rtl_read_dword(rtlpriv, TCR);
+ rtl_write_dword(rtlpriv, TCR, temp & (~BIT(8)));
+ rtl_write_dword(rtlpriv, TCR, temp | BIT(8));
+
+
+ return 0;
+}
+
+/* HW_VAR_MEDIA_STATUS & HW_VAR_CECHK_BSSID */
+int rtl92se_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (_rtl92se_set_media_status(hw, type))
+ return -EOPNOTSUPP;
+
+ if (rtlpriv->mac80211.link_state == MAC80211_LINKED) {
+ if (type != NL80211_IFTYPE_AP)
+ rtl92se_set_check_bssid(hw, true);
+ } else {
+ rtl92se_set_check_bssid(hw, false);
+ }
+
+ return 0;
+}
+
+/* don't set REG_EDCA_BE_PARAM here because mac80211 will send pkt when scan */
+void rtl92se_set_qos(struct ieee80211_hw *hw, int aci)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ rtl92s_dm_init_edca_turbo(hw);
+
+ switch (aci) {
+ case AC1_BK:
+ rtl_write_dword(rtlpriv, EDCAPARA_BK, 0xa44f);
+ break;
+ case AC0_BE:
+ /* rtl_write_dword(rtlpriv, EDCAPARA_BE, u4b_ac_param); */
+ break;
+ case AC2_VI:
+ rtl_write_dword(rtlpriv, EDCAPARA_VI, 0x5e4322);
+ break;
+ case AC3_VO:
+ rtl_write_dword(rtlpriv, EDCAPARA_VO, 0x2f3222);
+ break;
+ default:
+ RT_ASSERT(false, ("invalid aci: %d !\n", aci));
+ break;
+ }
+}
+
+void rtl92se_enable_interrupt(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ rtl_write_dword(rtlpriv, INTA_MASK, rtlpci->irq_mask[0]);
+ /* Support Bit 32-37(Assign as Bit 0-5) interrupt setting now */
+ rtl_write_dword(rtlpriv, INTA_MASK + 4, rtlpci->irq_mask[1] & 0x3F);
+
+ rtlpci->irq_enabled = true;
+}
+
+void rtl92se_disable_interrupt(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ rtl_write_dword(rtlpriv, INTA_MASK, 0);
+ rtl_write_dword(rtlpriv, INTA_MASK + 4, 0);
+
+ rtlpci->irq_enabled = false;
+}
+
+
+static u8 _rtl92s_set_sysclk(struct ieee80211_hw *hw, u8 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 waitcnt = 100;
+ bool result = false;
+ u8 tmp;
+
+ rtl_write_byte(rtlpriv, SYS_CLKR + 1, data);
+
+ /* Wait the MAC synchronized. */
+ udelay(400);
+
+ /* Check if it is set ready. */
+ tmp = rtl_read_byte(rtlpriv, SYS_CLKR + 1);
+ result = ((tmp & BIT(7)) == (data & BIT(7)));
+
+ if ((data & (BIT(6) | BIT(7))) == false) {
+ waitcnt = 100;
+ tmp = 0;
+
+ while (1) {
+ waitcnt--;
+ tmp = rtl_read_byte(rtlpriv, SYS_CLKR + 1);
+
+ if ((tmp & BIT(6)))
+ break;
+
+ printk(KERN_ERR "wait for BIT(6) return value %x\n",
+ tmp);
+
+ if (waitcnt == 0)
+ break;
+ udelay(10);
+ }
+
+ if (waitcnt == 0)
+ result = false;
+ else
+ result = true;
+ }
+
+ return result;
+}
+
+static void _rtl92s_phy_set_rfhalt(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ u8 u1btmp;
+
+ if (rtlhal->driver_going2unload)
+ rtl_write_byte(rtlpriv, 0x560, 0x0);
+
+ /* Power save for BB/RF */
+ u1btmp = rtl_read_byte(rtlpriv, LDOV12D_CTRL);
+ u1btmp |= BIT(0);
+ rtl_write_byte(rtlpriv, LDOV12D_CTRL, u1btmp);
+ rtl_write_byte(rtlpriv, SPS1_CTRL, 0x0);
+ rtl_write_byte(rtlpriv, TXPAUSE, 0xFF);
+ rtl_write_word(rtlpriv, CMDR, 0x57FC);
+ udelay(100);
+ rtl_write_word(rtlpriv, CMDR, 0x77FC);
+ rtl_write_byte(rtlpriv, PHY_CCA, 0x0);
+ udelay(10);
+ rtl_write_word(rtlpriv, CMDR, 0x37FC);
+ udelay(10);
+ rtl_write_word(rtlpriv, CMDR, 0x77FC);
+ udelay(10);
+ rtl_write_word(rtlpriv, CMDR, 0x57FC);
+ rtl_write_word(rtlpriv, CMDR, 0x0000);
+
+ if (rtlhal->driver_going2unload) {
+ u1btmp = rtl_read_byte(rtlpriv, (REG_SYS_FUNC_EN + 1));
+ u1btmp &= ~(BIT(0));
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, u1btmp);
+ }
+
+ u1btmp = rtl_read_byte(rtlpriv, (SYS_CLKR + 1));
+
+ /* Add description. After switch control path. register
+ * after page1 will be invisible. We can not do any IO
+ * for register>0x40. After resume&MACIO reset, we need
+ * to remember previous reg content. */
+ if (u1btmp & BIT(7)) {
+ u1btmp &= ~(BIT(6) | BIT(7));
+ if (!_rtl92s_set_sysclk(hw, u1btmp)) {
+ printk(KERN_ERR "Switch ctrl path fail\n");
+ return;
+ }
+ }
+
+ /* Power save for MAC */
+ if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS &&
+ !rtlhal->driver_going2unload) {
+ /* enable LED function */
+ rtl_write_byte(rtlpriv, 0x03, 0xF9);
+ /* SW/HW radio off or halt adapter!! For example S3/S4 */
+ } else {
+ /* LED function disable. Power range is about 8mA now. */
+ /* if write 0xF1 disconnet_pci power
+ * ifconfig wlan0 down power are both high 35:70 */
+ /* if write oxF9 disconnet_pci power
+ * ifconfig wlan0 down power are both low 12:45*/
+ rtl_write_byte(rtlpriv, 0x03, 0xF9);
+ }
+
+ rtl_write_byte(rtlpriv, SYS_CLKR + 1, 0x70);
+ rtl_write_byte(rtlpriv, AFE_PLL_CTRL + 1, 0x68);
+ rtl_write_byte(rtlpriv, AFE_PLL_CTRL, 0x00);
+ rtl_write_byte(rtlpriv, LDOA15_CTRL, 0x34);
+ rtl_write_byte(rtlpriv, AFE_XTAL_CTRL, 0x0E);
+ RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+
+}
+
+static void _rtl92se_gen_refreshledstate(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0);
+
+ if (rtlpci->up_first_time == 1)
+ return;
+
+ if (rtlpriv->psc.rfoff_reason == RF_CHANGE_BY_IPS)
+ rtl92se_sw_led_on(hw, pLed0);
+ else
+ rtl92se_sw_led_off(hw, pLed0);
+}
+
+
+static void _rtl92se_power_domain_init(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u16 tmpu2b;
+ u8 tmpu1b;
+
+ rtlpriv->psc.pwrdomain_protect = true;
+
+ tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1));
+ if (tmpu1b & BIT(7)) {
+ tmpu1b &= ~(BIT(6) | BIT(7));
+ if (!_rtl92s_set_sysclk(hw, tmpu1b)) {
+ rtlpriv->psc.pwrdomain_protect = false;
+ return;
+ }
+ }
+
+ rtl_write_byte(rtlpriv, AFE_PLL_CTRL, 0x0);
+ rtl_write_byte(rtlpriv, LDOA15_CTRL, 0x34);
+
+ /* Reset MAC-IO and CPU and Core Digital BIT10/11/15 */
+ tmpu1b = rtl_read_byte(rtlpriv, SYS_FUNC_EN + 1);
+
+ /* If IPS we need to turn LED on. So we not
+ * not disable BIT 3/7 of reg3. */
+ if (rtlpriv->psc.rfoff_reason & (RF_CHANGE_BY_IPS | RF_CHANGE_BY_HW))
+ tmpu1b &= 0xFB;
+ else
+ tmpu1b &= 0x73;
+
+ rtl_write_byte(rtlpriv, SYS_FUNC_EN + 1, tmpu1b);
+ /* wait for BIT 10/11/15 to pull high automatically!! */
+ mdelay(1);
+
+ rtl_write_byte(rtlpriv, CMDR, 0);
+ rtl_write_byte(rtlpriv, TCR, 0);
+
+ /* Data sheet not define 0x562!!! Copy from WMAC!!!!! */
+ tmpu1b = rtl_read_byte(rtlpriv, 0x562);
+ tmpu1b |= 0x08;
+ rtl_write_byte(rtlpriv, 0x562, tmpu1b);
+ tmpu1b &= ~(BIT(3));
+ rtl_write_byte(rtlpriv, 0x562, tmpu1b);
+
+ /* Enable AFE clock source */
+ tmpu1b = rtl_read_byte(rtlpriv, AFE_XTAL_CTRL);
+ rtl_write_byte(rtlpriv, AFE_XTAL_CTRL, (tmpu1b | 0x01));
+ /* Delay 1.5ms */
+ udelay(1500);
+ tmpu1b = rtl_read_byte(rtlpriv, AFE_XTAL_CTRL + 1);
+ rtl_write_byte(rtlpriv, AFE_XTAL_CTRL + 1, (tmpu1b & 0xfb));
+
+ /* Enable AFE Macro Block's Bandgap */
+ tmpu1b = rtl_read_byte(rtlpriv, AFE_MISC);
+ rtl_write_byte(rtlpriv, AFE_MISC, (tmpu1b | BIT(0)));
+ mdelay(1);
+
+ /* Enable AFE Mbias */
+ tmpu1b = rtl_read_byte(rtlpriv, AFE_MISC);
+ rtl_write_byte(rtlpriv, AFE_MISC, (tmpu1b | 0x02));
+ mdelay(1);
+
+ /* Enable LDOA15 block */
+ tmpu1b = rtl_read_byte(rtlpriv, LDOA15_CTRL);
+ rtl_write_byte(rtlpriv, LDOA15_CTRL, (tmpu1b | BIT(0)));
+
+ /* Set Digital Vdd to Retention isolation Path. */
+ tmpu2b = rtl_read_word(rtlpriv, SYS_ISO_CTRL);
+ rtl_write_word(rtlpriv, SYS_ISO_CTRL, (tmpu2b | BIT(11)));
+
+
+ /* For warm reboot NIC disappera bug. */
+ tmpu2b = rtl_read_word(rtlpriv, SYS_FUNC_EN);
+ rtl_write_word(rtlpriv, SYS_FUNC_EN, (tmpu2b | BIT(13)));
+
+ rtl_write_byte(rtlpriv, SYS_ISO_CTRL + 1, 0x68);
+
+ /* Enable AFE PLL Macro Block */
+ tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL);
+ rtl_write_byte(rtlpriv, AFE_PLL_CTRL, (tmpu1b | BIT(0) | BIT(4)));
+ /* Enable MAC 80MHZ clock */
+ tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL + 1);
+ rtl_write_byte(rtlpriv, AFE_PLL_CTRL + 1, (tmpu1b | BIT(0)));
+ mdelay(1);
+
+ /* Release isolation AFE PLL & MD */
+ rtl_write_byte(rtlpriv, SYS_ISO_CTRL, 0xA6);
+
+ /* Enable MAC clock */
+ tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR);
+ rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b | BIT(12) | BIT(11)));
+
+ /* Enable Core digital and enable IOREG R/W */
+ tmpu2b = rtl_read_word(rtlpriv, SYS_FUNC_EN);
+ rtl_write_word(rtlpriv, SYS_FUNC_EN, (tmpu2b | BIT(11)));
+ /* enable REG_EN */
+ rtl_write_word(rtlpriv, SYS_FUNC_EN, (tmpu2b | BIT(11) | BIT(15)));
+
+ /* Switch the control path. */
+ tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR);
+ rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b & (~BIT(2))));
+
+ tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1));
+ tmpu1b = ((tmpu1b | BIT(7)) & (~BIT(6)));
+ if (!_rtl92s_set_sysclk(hw, tmpu1b)) {
+ rtlpriv->psc.pwrdomain_protect = false;
+ return;
+ }
+
+ rtl_write_word(rtlpriv, CMDR, 0x37FC);
+
+ /* After MACIO reset,we must refresh LED state. */
+ _rtl92se_gen_refreshledstate(hw);
+
+ rtlpriv->psc.pwrdomain_protect = false;
+}
+
+void rtl92se_card_disable(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ enum nl80211_iftype opmode;
+ u8 wait = 30;
+
+ rtlpriv->intf_ops->enable_aspm(hw);
+
+ if (rtlpci->driver_is_goingto_unload ||
+ ppsc->rfoff_reason > RF_CHANGE_BY_PS)
+ rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF);
+
+ /* we should chnge GPIO to input mode
+ * this will drop away current about 25mA*/
+ rtl8192se_gpiobit3_cfg_inputmode(hw);
+
+ /* this is very important for ips power save */
+ while (wait-- >= 10 && rtlpriv->psc.pwrdomain_protect) {
+ if (rtlpriv->psc.pwrdomain_protect)
+ mdelay(20);
+ else
+ break;
+ }
+
+ mac->link_state = MAC80211_NOLINK;
+ opmode = NL80211_IFTYPE_UNSPECIFIED;
+ _rtl92se_set_media_status(hw, opmode);
+
+ _rtl92s_phy_set_rfhalt(hw);
+ udelay(100);
+}
+
+void rtl92se_interrupt_recognized(struct ieee80211_hw *hw, u32 *p_inta,
+ u32 *p_intb)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ *p_inta = rtl_read_dword(rtlpriv, ISR) & rtlpci->irq_mask[0];
+ rtl_write_dword(rtlpriv, ISR, *p_inta);
+
+ *p_intb = rtl_read_dword(rtlpriv, ISR + 4) & rtlpci->irq_mask[1];
+ rtl_write_dword(rtlpriv, ISR + 4, *p_intb);
+}
+
+void rtl92se_set_beacon_related_registers(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u16 bcntime_cfg = 0;
+ u16 bcn_cw = 6, bcn_ifs = 0xf;
+ u16 atim_window = 2;
+
+ /* ATIM Window (in unit of TU). */
+ rtl_write_word(rtlpriv, ATIMWND, atim_window);
+
+ /* Beacon interval (in unit of TU). */
+ rtl_write_word(rtlpriv, BCN_INTERVAL, mac->beacon_interval);
+
+ /* DrvErlyInt (in unit of TU). (Time to send
+ * interrupt to notify driver to change
+ * beacon content) */
+ rtl_write_word(rtlpriv, BCN_DRV_EARLY_INT, 10 << 4);
+
+ /* BcnDMATIM(in unit of us). Indicates the
+ * time before TBTT to perform beacon queue DMA */
+ rtl_write_word(rtlpriv, BCN_DMATIME, 256);
+
+ /* Force beacon frame transmission even
+ * after receiving beacon frame from
+ * other ad hoc STA */
+ rtl_write_byte(rtlpriv, BCN_ERR_THRESH, 100);
+
+ /* Beacon Time Configuration */
+ if (mac->opmode == NL80211_IFTYPE_ADHOC)
+ bcntime_cfg |= (bcn_cw << BCN_TCFG_CW_SHIFT);
+
+ /* TODO: bcn_ifs may required to be changed on ASIC */
+ bcntime_cfg |= bcn_ifs << BCN_TCFG_IFS;
+
+ /*for beacon changed */
+ rtl92s_phy_set_beacon_hwreg(hw, mac->beacon_interval);
+}
+
+void rtl92se_set_beacon_interval(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u16 bcn_interval = mac->beacon_interval;
+
+ /* Beacon interval (in unit of TU). */
+ rtl_write_word(rtlpriv, BCN_INTERVAL, bcn_interval);
+ /* 2008.10.24 added by tynli for beacon changed. */
+ rtl92s_phy_set_beacon_hwreg(hw, bcn_interval);
+}
+
+void rtl92se_update_interrupt_mask(struct ieee80211_hw *hw,
+ u32 add_msr, u32 rm_msr)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD,
+ ("add_msr:%x, rm_msr:%x\n", add_msr, rm_msr));
+
+ if (add_msr)
+ rtlpci->irq_mask[0] |= add_msr;
+
+ if (rm_msr)
+ rtlpci->irq_mask[0] &= (~rm_msr);
+
+ rtl92se_disable_interrupt(hw);
+ rtl92se_enable_interrupt(hw);
+}
+
+static void _rtl8192se_get_IC_Inferiority(struct ieee80211_hw *hw)
+{
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u8 efuse_id;
+
+ rtlhal->ic_class = IC_INFERIORITY_A;
+
+ /* Only retrieving while using EFUSE. */
+ if ((rtlefuse->epromtype == EEPROM_BOOT_EFUSE) &&
+ !rtlefuse->autoload_failflag) {
+ efuse_id = efuse_read_1byte(hw, EFUSE_IC_ID_OFFSET);
+
+ if (efuse_id == 0xfe)
+ rtlhal->ic_class = IC_INFERIORITY_B;
+ }
+}
+
+static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u16 i, usvalue;
+ u16 eeprom_id;
+ u8 tempval;
+ u8 hwinfo[HWSET_MAX_SIZE_92S];
+ u8 rf_path, index;
+
+ if (rtlefuse->epromtype == EEPROM_93C46) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("RTL819X Not boot from eeprom, check it !!"));
+ } else if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) {
+ rtl_efuse_shadow_map_update(hw);
+
+ memcpy((void *)hwinfo, (void *)
+ &rtlefuse->efuse_map[EFUSE_INIT_MAP][0],
+ HWSET_MAX_SIZE_92S);
+ }
+
+ RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("MAP\n"),
+ hwinfo, HWSET_MAX_SIZE_92S);
+
+ eeprom_id = *((u16 *)&hwinfo[0]);
+ if (eeprom_id != RTL8190_EEPROM_ID) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("EEPROM ID(%#x) is invalid!!\n", eeprom_id));
+ rtlefuse->autoload_failflag = true;
+ } else {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Autoload OK\n"));
+ rtlefuse->autoload_failflag = false;
+ }
+
+ if (rtlefuse->autoload_failflag == true)
+ return;
+
+ _rtl8192se_get_IC_Inferiority(hw);
+
+ /* Read IC Version && Channel Plan */
+ /* VID, DID SE 0xA-D */
+ rtlefuse->eeprom_vid = *(u16 *)&hwinfo[EEPROM_VID];
+ rtlefuse->eeprom_did = *(u16 *)&hwinfo[EEPROM_DID];
+ rtlefuse->eeprom_svid = *(u16 *)&hwinfo[EEPROM_SVID];
+ rtlefuse->eeprom_smid = *(u16 *)&hwinfo[EEPROM_SMID];
+ rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION];
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("EEPROMId = 0x%4x\n", eeprom_id));
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid));
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did));
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid));
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid));
+
+ for (i = 0; i < 6; i += 2) {
+ usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i];
+ *((u16 *) (&rtlefuse->dev_addr[i])) = usvalue;
+ }
+
+ for (i = 0; i < 6; i++)
+ rtl_write_byte(rtlpriv, MACIDR0 + i, rtlefuse->dev_addr[i]);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ (MAC_FMT "\n", MAC_ARG(rtlefuse->dev_addr)));
+
+ /* Get Tx Power Level by Channel */
+ /* Read Tx power of Channel 1 ~ 14 from EEPROM. */
+ /* 92S suupport RF A & B */
+ for (rf_path = 0; rf_path < 2; rf_path++) {
+ for (i = 0; i < 3; i++) {
+ /* Read CCK RF A & B Tx power */
+ rtlefuse->eeprom_chnlarea_txpwr_cck[rf_path][i] =
+ hwinfo[EEPROM_TXPOWERBASE + rf_path * 3 + i];
+
+ /* Read OFDM RF A & B Tx power for 1T */
+ rtlefuse->eeprom_chnlarea_txpwr_ht40_1s[rf_path][i] =
+ hwinfo[EEPROM_TXPOWERBASE + 6 + rf_path * 3 + i];
+
+ /* Read OFDM RF A & B Tx power for 2T */
+ rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path][i]
+ = hwinfo[EEPROM_TXPOWERBASE + 12 +
+ rf_path * 3 + i];
+ }
+ }
+
+ for (rf_path = 0; rf_path < 2; rf_path++)
+ for (i = 0; i < 3; i++)
+ RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
+ ("RF(%d) EEPROM CCK Area(%d) = 0x%x\n", rf_path,
+ i, rtlefuse->eeprom_chnlarea_txpwr_cck
+ [rf_path][i]));
+ for (rf_path = 0; rf_path < 2; rf_path++)
+ for (i = 0; i < 3; i++)
+ RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
+ ("RF(%d) EEPROM HT40 1S Area(%d) = 0x%x\n",
+ rf_path, i,
+ rtlefuse->eeprom_chnlarea_txpwr_ht40_1s
+ [rf_path][i]));
+ for (rf_path = 0; rf_path < 2; rf_path++)
+ for (i = 0; i < 3; i++)
+ RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
+ ("RF(%d) EEPROM HT40 2S Diff Area(%d) = 0x%x\n",
+ rf_path, i,
+ rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif
+ [rf_path][i]));
+
+ for (rf_path = 0; rf_path < 2; rf_path++) {
+
+ /* Assign dedicated channel tx power */
+ for (i = 0; i < 14; i++) {
+ /* channel 1~3 use the same Tx Power Level. */
+ if (i < 3)
+ index = 0;
+ /* Channel 4-8 */
+ else if (i < 8)
+ index = 1;
+ /* Channel 9-14 */
+ else
+ index = 2;
+
+ /* Record A & B CCK /OFDM - 1T/2T Channel area
+ * tx power */
+ rtlefuse->txpwrlevel_cck[rf_path][i] =
+ rtlefuse->eeprom_chnlarea_txpwr_cck
+ [rf_path][index];
+ rtlefuse->txpwrlevel_ht40_1s[rf_path][i] =
+ rtlefuse->eeprom_chnlarea_txpwr_ht40_1s
+ [rf_path][index];
+ rtlefuse->txpwrlevel_ht40_2s[rf_path][i] =
+ rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif
+ [rf_path][index];
+ }
+
+ for (i = 0; i < 14; i++) {
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("RF(%d)-Ch(%d) [CCK / HT40_1S / HT40_2S] = "
+ "[0x%x / 0x%x / 0x%x]\n", rf_path, i,
+ rtlefuse->txpwrlevel_cck[rf_path][i],
+ rtlefuse->txpwrlevel_ht40_1s[rf_path][i],
+ rtlefuse->txpwrlevel_ht40_2s[rf_path][i]));
+ }
+ }
+
+ for (rf_path = 0; rf_path < 2; rf_path++) {
+ for (i = 0; i < 3; i++) {
+ /* Read Power diff limit. */
+ rtlefuse->eeprom_pwrgroup[rf_path][i] =
+ hwinfo[EEPROM_TXPWRGROUP + rf_path * 3 + i];
+ }
+ }
+
+ for (rf_path = 0; rf_path < 2; rf_path++) {
+ /* Fill Pwr group */
+ for (i = 0; i < 14; i++) {
+ /* Chanel 1-3 */
+ if (i < 3)
+ index = 0;
+ /* Channel 4-8 */
+ else if (i < 8)
+ index = 1;
+ /* Channel 9-13 */
+ else
+ index = 2;
+
+ rtlefuse->pwrgroup_ht20[rf_path][i] =
+ (rtlefuse->eeprom_pwrgroup[rf_path][index] &
+ 0xf);
+ rtlefuse->pwrgroup_ht40[rf_path][i] =
+ ((rtlefuse->eeprom_pwrgroup[rf_path][index] &
+ 0xf0) >> 4);
+
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("RF-%d pwrgroup_ht20[%d] = 0x%x\n",
+ rf_path, i,
+ rtlefuse->pwrgroup_ht20[rf_path][i]));
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("RF-%d pwrgroup_ht40[%d] = 0x%x\n",
+ rf_path, i,
+ rtlefuse->pwrgroup_ht40[rf_path][i]));
+ }
+ }
+
+ for (i = 0; i < 14; i++) {
+ /* Read tx power difference between HT OFDM 20/40 MHZ */
+ /* channel 1-3 */
+ if (i < 3)
+ index = 0;
+ /* Channel 4-8 */
+ else if (i < 8)
+ index = 1;
+ /* Channel 9-14 */
+ else
+ index = 2;
+
+ tempval = (*(u8 *)&hwinfo[EEPROM_TX_PWR_HT20_DIFF +
+ index]) & 0xff;
+ rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] = (tempval & 0xF);
+ rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] =
+ ((tempval >> 4) & 0xF);
+
+ /* Read OFDM<->HT tx power diff */
+ /* Channel 1-3 */
+ if (i < 3)
+ index = 0;
+ /* Channel 4-8 */
+ else if (i < 8)
+ index = 0x11;
+ /* Channel 9-14 */
+ else
+ index = 1;
+
+ tempval = (*(u8 *)&hwinfo[EEPROM_TX_PWR_OFDM_DIFF + index])
+ & 0xff;
+ rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i] =
+ (tempval & 0xF);
+ rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i] =
+ ((tempval >> 4) & 0xF);
+
+ tempval = (*(u8 *)&hwinfo[TX_PWR_SAFETY_CHK]);
+ rtlefuse->txpwr_safetyflag = (tempval & 0x01);
+ }
+
+ rtlefuse->eeprom_regulatory = 0;
+ if (rtlefuse->eeprom_version >= 2) {
+ /* BIT(0)~2 */
+ if (rtlefuse->eeprom_version >= 4)
+ rtlefuse->eeprom_regulatory =
+ (hwinfo[EEPROM_REGULATORY] & 0x7);
+ else /* BIT(0) */
+ rtlefuse->eeprom_regulatory =
+ (hwinfo[EEPROM_REGULATORY] & 0x1);
+ }
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory));
+
+ for (i = 0; i < 14; i++)
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("RF-A Ht20 to HT40 Diff[%d] = 0x%x\n", i,
+ rtlefuse->txpwr_ht20diff[RF90_PATH_A][i]));
+ for (i = 0; i < 14; i++)
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("RF-A Legacy to Ht40 Diff[%d] = 0x%x\n", i,
+ rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i]));
+ for (i = 0; i < 14; i++)
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("RF-B Ht20 to HT40 Diff[%d] = 0x%x\n", i,
+ rtlefuse->txpwr_ht20diff[RF90_PATH_B][i]));
+ for (i = 0; i < 14; i++)
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("RF-B Legacy to HT40 Diff[%d] = 0x%x\n", i,
+ rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i]));
+
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower, ("TxPwrSafetyFlag = %d\n",
+ rtlefuse->txpwr_safetyflag));
+
+ /* Read RF-indication and Tx Power gain
+ * index diff of legacy to HT OFDM rate. */
+ tempval = (*(u8 *)&hwinfo[EEPROM_RFIND_POWERDIFF]) & 0xff;
+ rtlefuse->eeprom_txpowerdiff = tempval;
+ rtlefuse->legacy_httxpowerdiff =
+ rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][0];
+
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower, ("TxPowerDiff = %#x\n",
+ rtlefuse->eeprom_txpowerdiff));
+
+ /* Get TSSI value for each path. */
+ usvalue = *(u16 *)&hwinfo[EEPROM_TSSI_A];
+ rtlefuse->eeprom_tssi[RF90_PATH_A] = (u8)((usvalue & 0xff00) >> 8);
+ usvalue = *(u8 *)&hwinfo[EEPROM_TSSI_B];
+ rtlefuse->eeprom_tssi[RF90_PATH_B] = (u8)(usvalue & 0xff);
+
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower, ("TSSI_A = 0x%x, TSSI_B = 0x%x\n",
+ rtlefuse->eeprom_tssi[RF90_PATH_A],
+ rtlefuse->eeprom_tssi[RF90_PATH_B]));
+
+ /* Read antenna tx power offset of B/C/D to A from EEPROM */
+ /* and read ThermalMeter from EEPROM */
+ tempval = *(u8 *)&hwinfo[EEPROM_THERMALMETER];
+ rtlefuse->eeprom_thermalmeter = tempval;
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower, ("thermalmeter = 0x%x\n",
+ rtlefuse->eeprom_thermalmeter));
+
+ /* ThermalMeter, BIT(0)~3 for RFIC1, BIT(4)~7 for RFIC2 */
+ rtlefuse->thermalmeter[0] = (rtlefuse->eeprom_thermalmeter & 0x1f);
+ rtlefuse->tssi_13dbm = rtlefuse->eeprom_thermalmeter * 100;
+
+ /* Read CrystalCap from EEPROM */
+ tempval = (*(u8 *)&hwinfo[EEPROM_CRYSTALCAP]) >> 4;
+ rtlefuse->eeprom_crystalcap = tempval;
+ /* CrystalCap, BIT(12)~15 */
+ rtlefuse->crystalcap = rtlefuse->eeprom_crystalcap;
+
+ /* Read IC Version && Channel Plan */
+ /* Version ID, Channel plan */
+ rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN];
+ rtlefuse->txpwr_fromeprom = true;
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower, ("EEPROM ChannelPlan = 0x%4x\n",
+ rtlefuse->eeprom_channelplan));
+
+ /* Read Customer ID or Board Type!!! */
+ tempval = *(u8 *)&hwinfo[EEPROM_BOARDTYPE];
+ /* Change RF type definition */
+ if (tempval == 0)
+ rtlphy->rf_type = RF_2T2R;
+ else if (tempval == 1)
+ rtlphy->rf_type = RF_1T2R;
+ else if (tempval == 2)
+ rtlphy->rf_type = RF_1T2R;
+ else if (tempval == 3)
+ rtlphy->rf_type = RF_1T1R;
+
+ /* 1T2R but 1SS (1x1 receive combining) */
+ rtlefuse->b1x1_recvcombine = false;
+ if (rtlphy->rf_type == RF_1T2R) {
+ tempval = rtl_read_byte(rtlpriv, 0x07);
+ if (!(tempval & BIT(0))) {
+ rtlefuse->b1x1_recvcombine = true;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("RF_TYPE=1T2R but only 1SS\n"));
+ }
+ }
+ rtlefuse->b1ss_support = rtlefuse->b1x1_recvcombine;
+ rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMID];
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("EEPROM Customer ID: 0x%2x",
+ rtlefuse->eeprom_oemid));
+
+ /* set channel paln to world wide 13 */
+ rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13;
+}
+
+void rtl92se_read_eeprom_info(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 tmp_u1b = 0;
+
+ tmp_u1b = rtl_read_byte(rtlpriv, EPROM_CMD);
+
+ if (tmp_u1b & BIT(4)) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("Boot from EEPROM\n"));
+ rtlefuse->epromtype = EEPROM_93C46;
+ } else {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("Boot from EFUSE\n"));
+ rtlefuse->epromtype = EEPROM_BOOT_EFUSE;
+ }
+
+ if (tmp_u1b & BIT(5)) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Autoload OK\n"));
+ rtlefuse->autoload_failflag = false;
+ _rtl92se_read_adapter_info(hw);
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Autoload ERR!!\n"));
+ rtlefuse->autoload_failflag = true;
+ }
+}
+
+static void rtl92se_update_hal_rate_table(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u32 ratr_value;
+ u8 ratr_index = 0;
+ u8 nmode = mac->ht_enable;
+ u8 mimo_ps = IEEE80211_SMPS_OFF;
+ u16 shortgi_rate = 0;
+ u32 tmp_ratr_value = 0;
+ u8 curtxbw_40mhz = mac->bw_40;
+ u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+ 1 : 0;
+ u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+ 1 : 0;
+ enum wireless_mode wirelessmode = mac->mode;
+
+ if (rtlhal->current_bandtype == BAND_ON_5G)
+ ratr_value = sta->supp_rates[1] << 4;
+ else
+ ratr_value = sta->supp_rates[0];
+ ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+ sta->ht_cap.mcs.rx_mask[0] << 12);
+ switch (wirelessmode) {
+ case WIRELESS_MODE_B:
+ ratr_value &= 0x0000000D;
+ break;
+ case WIRELESS_MODE_G:
+ ratr_value &= 0x00000FF5;
+ break;
+ case WIRELESS_MODE_N_24G:
+ case WIRELESS_MODE_N_5G:
+ nmode = 1;
+ if (mimo_ps == IEEE80211_SMPS_STATIC) {
+ ratr_value &= 0x0007F005;
+ } else {
+ u32 ratr_mask;
+
+ if (get_rf_type(rtlphy) == RF_1T2R ||
+ get_rf_type(rtlphy) == RF_1T1R) {
+ if (curtxbw_40mhz)
+ ratr_mask = 0x000ff015;
+ else
+ ratr_mask = 0x000ff005;
+ } else {
+ if (curtxbw_40mhz)
+ ratr_mask = 0x0f0ff015;
+ else
+ ratr_mask = 0x0f0ff005;
+ }
+
+ ratr_value &= ratr_mask;
+ }
+ break;
+ default:
+ if (rtlphy->rf_type == RF_1T2R)
+ ratr_value &= 0x000ff0ff;
+ else
+ ratr_value &= 0x0f0ff0ff;
+
+ break;
+ }
+
+ if (rtlpriv->rtlhal.version >= VERSION_8192S_BCUT)
+ ratr_value &= 0x0FFFFFFF;
+ else if (rtlpriv->rtlhal.version == VERSION_8192S_ACUT)
+ ratr_value &= 0x0FFFFFF0;
+
+ if (nmode && ((curtxbw_40mhz &&
+ curshortgi_40mhz) || (!curtxbw_40mhz &&
+ curshortgi_20mhz))) {
+
+ ratr_value |= 0x10000000;
+ tmp_ratr_value = (ratr_value >> 12);
+
+ for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) {
+ if ((1 << shortgi_rate) & tmp_ratr_value)
+ break;
+ }
+
+ shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) |
+ (shortgi_rate << 4) | (shortgi_rate);
+
+ rtl_write_byte(rtlpriv, SG_RATE, shortgi_rate);
+ }
+
+ rtl_write_dword(rtlpriv, ARFR0 + ratr_index * 4, ratr_value);
+ if (ratr_value & 0xfffff000)
+ rtl92s_phy_set_fw_cmd(hw, FW_CMD_RA_REFRESH_N);
+ else
+ rtl92s_phy_set_fw_cmd(hw, FW_CMD_RA_REFRESH_BG);
+
+ RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+ ("%x\n", rtl_read_dword(rtlpriv, ARFR0)));
+}
+
+static void rtl92se_update_hal_rate_mask(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ u8 rssi_level)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_sta_info *sta_entry = NULL;
+ u32 ratr_bitmap;
+ u8 ratr_index = 0;
+ u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
+ ? 1 : 0;
+ u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+ 1 : 0;
+ u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+ 1 : 0;
+ enum wireless_mode wirelessmode = 0;
+ bool shortgi = false;
+ u32 ratr_value = 0;
+ u8 shortgi_rate = 0;
+ u32 mask = 0;
+ u32 band = 0;
+ bool bmulticast = false;
+ u8 macid = 0;
+ u8 mimo_ps = IEEE80211_SMPS_OFF;
+
+ sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+ wirelessmode = sta_entry->wireless_mode;
+ if (mac->opmode == NL80211_IFTYPE_STATION)
+ curtxbw_40mhz = mac->bw_40;
+ else if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_ADHOC)
+ macid = sta->aid + 1;
+
+ if (rtlhal->current_bandtype == BAND_ON_5G)
+ ratr_bitmap = sta->supp_rates[1] << 4;
+ else
+ ratr_bitmap = sta->supp_rates[0];
+ ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+ sta->ht_cap.mcs.rx_mask[0] << 12);
+ switch (wirelessmode) {
+ case WIRELESS_MODE_B:
+ band |= WIRELESS_11B;
+ ratr_index = RATR_INX_WIRELESS_B;
+ if (ratr_bitmap & 0x0000000c)
+ ratr_bitmap &= 0x0000000d;
+ else
+ ratr_bitmap &= 0x0000000f;
+ break;
+ case WIRELESS_MODE_G:
+ band |= (WIRELESS_11G | WIRELESS_11B);
+ ratr_index = RATR_INX_WIRELESS_GB;
+
+ if (rssi_level == 1)
+ ratr_bitmap &= 0x00000f00;
+ else if (rssi_level == 2)
+ ratr_bitmap &= 0x00000ff0;
+ else
+ ratr_bitmap &= 0x00000ff5;
+ break;
+ case WIRELESS_MODE_A:
+ band |= WIRELESS_11A;
+ ratr_index = RATR_INX_WIRELESS_A;
+ ratr_bitmap &= 0x00000ff0;
+ break;
+ case WIRELESS_MODE_N_24G:
+ case WIRELESS_MODE_N_5G:
+ band |= (WIRELESS_11N | WIRELESS_11G | WIRELESS_11B);
+ ratr_index = RATR_INX_WIRELESS_NGB;
+
+ if (mimo_ps == IEEE80211_SMPS_STATIC) {
+ if (rssi_level == 1)
+ ratr_bitmap &= 0x00070000;
+ else if (rssi_level == 2)
+ ratr_bitmap &= 0x0007f000;
+ else
+ ratr_bitmap &= 0x0007f005;
+ } else {
+ if (rtlphy->rf_type == RF_1T2R ||
+ rtlphy->rf_type == RF_1T1R) {
+ if (rssi_level == 1) {
+ ratr_bitmap &= 0x000f0000;
+ } else if (rssi_level == 3) {
+ ratr_bitmap &= 0x000fc000;
+ } else if (rssi_level == 5) {
+ ratr_bitmap &= 0x000ff000;
+ } else {
+ if (curtxbw_40mhz)
+ ratr_bitmap &= 0x000ff015;
+ else
+ ratr_bitmap &= 0x000ff005;
+ }
+ } else {
+ if (rssi_level == 1) {
+ ratr_bitmap &= 0x0f8f0000;
+ } else if (rssi_level == 3) {
+ ratr_bitmap &= 0x0f8fc000;
+ } else if (rssi_level == 5) {
+ ratr_bitmap &= 0x0f8ff000;
+ } else {
+ if (curtxbw_40mhz)
+ ratr_bitmap &= 0x0f8ff015;
+ else
+ ratr_bitmap &= 0x0f8ff005;
+ }
+ }
+ }
+
+ if ((curtxbw_40mhz && curshortgi_40mhz) ||
+ (!curtxbw_40mhz && curshortgi_20mhz)) {
+ if (macid == 0)
+ shortgi = true;
+ else if (macid == 1)
+ shortgi = false;
+ }
+ break;
+ default:
+ band |= (WIRELESS_11N | WIRELESS_11G | WIRELESS_11B);
+ ratr_index = RATR_INX_WIRELESS_NGB;
+
+ if (rtlphy->rf_type == RF_1T2R)
+ ratr_bitmap &= 0x000ff0ff;
+ else
+ ratr_bitmap &= 0x0f8ff0ff;
+ break;
+ }
+
+ if (rtlpriv->rtlhal.version >= VERSION_8192S_BCUT)
+ ratr_bitmap &= 0x0FFFFFFF;
+ else if (rtlpriv->rtlhal.version == VERSION_8192S_ACUT)
+ ratr_bitmap &= 0x0FFFFFF0;
+
+ if (shortgi) {
+ ratr_bitmap |= 0x10000000;
+ /* Get MAX MCS available. */
+ ratr_value = (ratr_bitmap >> 12);
+ for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) {
+ if ((1 << shortgi_rate) & ratr_value)
+ break;
+ }
+
+ shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) |
+ (shortgi_rate << 4) | (shortgi_rate);
+ rtl_write_byte(rtlpriv, SG_RATE, shortgi_rate);
+ }
+
+ mask |= (bmulticast ? 1 : 0) << 9 | (macid & 0x1f) << 4 | (band & 0xf);
+
+ RT_TRACE(rtlpriv, COMP_RATR, DBG_TRACE, ("mask = %x, bitmap = %x\n",
+ mask, ratr_bitmap));
+ rtl_write_dword(rtlpriv, 0x2c4, ratr_bitmap);
+ rtl_write_dword(rtlpriv, WFM5, (FW_RA_UPDATE_MASK | (mask << 8)));
+
+ if (macid != 0)
+ sta_entry->ratr_index = ratr_index;
+}
+
+void rtl92se_update_hal_rate_tbl(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u8 rssi_level)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (rtlpriv->dm.useramask)
+ rtl92se_update_hal_rate_mask(hw, sta, rssi_level);
+ else
+ rtl92se_update_hal_rate_table(hw, sta);
+}
+
+void rtl92se_update_channel_access_setting(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u16 sifs_timer;
+
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME,
+ (u8 *)&mac->slot_time);
+ sifs_timer = 0x0e0e;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer);
+
+}
+
+/* this ifunction is for RFKILL, it's different with windows,
+ * because UI will disable wireless when GPIO Radio Off.
+ * And here we not check or Disable/Enable ASPM like windows*/
+bool rtl92se_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ enum rf_pwrstate rfpwr_toset, cur_rfstate;
+ unsigned long flag = 0;
+ bool actuallyset = false;
+ bool turnonbypowerdomain = false;
+
+ /* just 8191se can check gpio before firstup, 92c/92d have fixed it */
+ if ((rtlpci->up_first_time == 1) || (rtlpci->being_init_adapter))
+ return false;
+
+ if (ppsc->swrf_processing)
+ return false;
+
+ spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
+ if (ppsc->rfchange_inprogress) {
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
+ return false;
+ } else {
+ ppsc->rfchange_inprogress = true;
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
+ }
+
+ cur_rfstate = ppsc->rfpwr_state;
+
+ /* because after _rtl92s_phy_set_rfhalt, all power
+ * closed, so we must open some power for GPIO check,
+ * or we will always check GPIO RFOFF here,
+ * And we should close power after GPIO check */
+ if (RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) {
+ _rtl92se_power_domain_init(hw);
+ turnonbypowerdomain = true;
+ }
+
+ rfpwr_toset = _rtl92se_rf_onoff_detect(hw);
+
+ if ((ppsc->hwradiooff == true) && (rfpwr_toset == ERFON)) {
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ ("RFKILL-HW Radio ON, RF ON\n"));
+
+ rfpwr_toset = ERFON;
+ ppsc->hwradiooff = false;
+ actuallyset = true;
+ } else if ((ppsc->hwradiooff == false) && (rfpwr_toset == ERFOFF)) {
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ ("RFKILL-HW Radio OFF, RF OFF\n"));
+
+ rfpwr_toset = ERFOFF;
+ ppsc->hwradiooff = true;
+ actuallyset = true;
+ }
+
+ if (actuallyset) {
+ spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
+ ppsc->rfchange_inprogress = false;
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
+
+ /* this not include ifconfig wlan0 down case */
+ /* } else if (rfpwr_toset == ERFOFF || cur_rfstate == ERFOFF) { */
+ } else {
+ /* because power_domain_init may be happen when
+ * _rtl92s_phy_set_rfhalt, this will open some powers
+ * and cause current increasing about 40 mA for ips,
+ * rfoff and ifconfig down, so we set
+ * _rtl92s_phy_set_rfhalt again here */
+ if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC &&
+ turnonbypowerdomain) {
+ _rtl92s_phy_set_rfhalt(hw);
+ RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+ }
+
+ spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
+ ppsc->rfchange_inprogress = false;
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
+ }
+
+ *valid = 1;
+ return !ppsc->hwradiooff;
+
+}
+
+/* Is_wepkey just used for WEP used as group & pairwise key
+ * if pairwise is AES ang group is WEP Is_wepkey == false.*/
+void rtl92se_set_key(struct ieee80211_hw *hw, u32 key_index, u8 *p_macaddr,
+ bool is_group, u8 enc_algo, bool is_wepkey, bool clear_all)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 *macaddr = p_macaddr;
+
+ u32 entry_id = 0;
+ bool is_pairwise = false;
+
+ static 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[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+
+ if (clear_all) {
+ u8 idx = 0;
+ u8 cam_offset = 0;
+ u8 clear_number = 5;
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("clear_all\n"));
+
+ for (idx = 0; idx < clear_number; idx++) {
+ rtl_cam_mark_invalid(hw, cam_offset + idx);
+ rtl_cam_empty_entry(hw, cam_offset + idx);
+
+ if (idx < 5) {
+ memset(rtlpriv->sec.key_buf[idx], 0,
+ MAX_KEY_LEN);
+ rtlpriv->sec.key_len[idx] = 0;
+ }
+ }
+
+ } else {
+ switch (enc_algo) {
+ case WEP40_ENCRYPTION:
+ enc_algo = CAM_WEP40;
+ break;
+ case WEP104_ENCRYPTION:
+ enc_algo = CAM_WEP104;
+ break;
+ case TKIP_ENCRYPTION:
+ enc_algo = CAM_TKIP;
+ break;
+ case AESCCMP_ENCRYPTION:
+ enc_algo = CAM_AES;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ enc_algo = CAM_TKIP;
+ break;
+ }
+
+ if (is_wepkey || rtlpriv->sec.use_defaultkey) {
+ macaddr = cam_const_addr[key_index];
+ entry_id = key_index;
+ } else {
+ if (is_group) {
+ macaddr = cam_const_broad;
+ entry_id = key_index;
+ } else {
+ if (mac->opmode == NL80211_IFTYPE_AP) {
+ entry_id = rtl_cam_get_free_entry(hw,
+ p_macaddr);
+ if (entry_id >= TOTAL_CAM_ENTRY) {
+ RT_TRACE(rtlpriv,
+ COMP_SEC, DBG_EMERG,
+ ("Can not find free hw"
+ " security cam entry\n"));
+ return;
+ }
+ } else {
+ entry_id = CAM_PAIRWISE_KEY_POSITION;
+ }
+
+ key_index = PAIRWISE_KEYIDX;
+ is_pairwise = true;
+ }
+ }
+
+ if (rtlpriv->sec.key_len[key_index] == 0) {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("delete one entry, entry_id is %d\n",
+ entry_id));
+ if (mac->opmode == NL80211_IFTYPE_AP)
+ rtl_cam_del_entry(hw, p_macaddr);
+ rtl_cam_delete_one_entry(hw, p_macaddr, entry_id);
+ } else {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+ ("The insert KEY length is %d\n",
+ rtlpriv->sec.key_len[PAIRWISE_KEYIDX]));
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+ ("The insert KEY is %x %x\n",
+ rtlpriv->sec.key_buf[0][0],
+ rtlpriv->sec.key_buf[0][1]));
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("add one entry\n"));
+ if (is_pairwise) {
+ RT_PRINT_DATA(rtlpriv, COMP_SEC, DBG_LOUD,
+ "Pairwiase Key content :",
+ rtlpriv->sec.pairwise_key,
+ rtlpriv->sec.key_len[PAIRWISE_KEYIDX]);
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("set Pairwiase key\n"));
+
+ rtl_cam_add_one_entry(hw, macaddr, key_index,
+ entry_id, enc_algo,
+ CAM_CONFIG_NO_USEDK,
+ rtlpriv->sec.key_buf[key_index]);
+ } else {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("set group key\n"));
+
+ if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+ rtl_cam_add_one_entry(hw,
+ rtlefuse->dev_addr,
+ PAIRWISE_KEYIDX,
+ CAM_PAIRWISE_KEY_POSITION,
+ enc_algo, CAM_CONFIG_NO_USEDK,
+ rtlpriv->sec.key_buf[entry_id]);
+ }
+
+ rtl_cam_add_one_entry(hw, macaddr, key_index,
+ entry_id, enc_algo,
+ CAM_CONFIG_NO_USEDK,
+ rtlpriv->sec.key_buf[entry_id]);
+ }
+
+ }
+ }
+}
+
+void rtl92se_suspend(struct ieee80211_hw *hw)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ rtlpci->up_first_time = true;
+}
+
+void rtl92se_resume(struct ieee80211_hw *hw)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ u32 val;
+
+ pci_read_config_dword(rtlpci->pdev, 0x40, &val);
+ if ((val & 0x0000ff00) != 0)
+ pci_write_config_dword(rtlpci->pdev, 0x40,
+ val & 0xffff00ff);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.h b/drivers/net/wireless/rtlwifi/rtl8192se/hw.h
new file mode 100644
index 000000000000..6160a9bfe98a
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.h
@@ -0,0 +1,79 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#ifndef __REALTEK_PCI92SE_HW_H__
+#define __REALTEK_PCI92SE_HW_H__
+
+#define MSR_LINK_MANAGED 2
+#define MSR_LINK_NONE 0
+#define MSR_LINK_SHIFT 0
+#define MSR_LINK_ADHOC 1
+#define MSR_LINK_MASTER 3
+
+enum WIRELESS_NETWORK_TYPE {
+ WIRELESS_11B = 1,
+ WIRELESS_11G = 2,
+ WIRELESS_11A = 4,
+ WIRELESS_11N = 8
+};
+
+void rtl92se_get_hw_reg(struct ieee80211_hw *hw,
+ u8 variable, u8 *val);
+void rtl92se_read_eeprom_info(struct ieee80211_hw *hw);
+void rtl92se_interrupt_recognized(struct ieee80211_hw *hw,
+ u32 *inta, u32 *intb);
+int rtl92se_hw_init(struct ieee80211_hw *hw);
+void rtl92se_card_disable(struct ieee80211_hw *hw);
+void rtl92se_enable_interrupt(struct ieee80211_hw *hw);
+void rtl92se_disable_interrupt(struct ieee80211_hw *hw);
+int rtl92se_set_network_type(struct ieee80211_hw *hw,
+ enum nl80211_iftype type);
+void rtl92se_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid);
+void rtl92se_set_mac_addr(struct rtl_io *io, const u8 * addr);
+void rtl92se_set_qos(struct ieee80211_hw *hw, int aci);
+void rtl92se_set_beacon_related_registers(struct ieee80211_hw *hw);
+void rtl92se_set_beacon_interval(struct ieee80211_hw *hw);
+void rtl92se_update_interrupt_mask(struct ieee80211_hw *hw,
+ u32 add_msr, u32 rm_msr);
+void rtl92se_set_hw_reg(struct ieee80211_hw *hw, u8 variable,
+ u8 *val);
+void rtl92se_update_hal_rate_tbl(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u8 rssi_level);
+void rtl92se_update_channel_access_setting(struct ieee80211_hw *hw);
+bool rtl92se_gpio_radio_on_off_checking(struct ieee80211_hw *hw,
+ u8 *valid);
+void rtl8192se_gpiobit3_cfg_inputmode(struct ieee80211_hw *hw);
+void rtl92se_enable_hw_security_config(struct ieee80211_hw *hw);
+void rtl92se_set_key(struct ieee80211_hw *hw,
+ u32 key_index, u8 *macaddr, bool is_group,
+ u8 enc_algo, bool is_wepkey, bool clear_all);
+void rtl92se_suspend(struct ieee80211_hw *hw);
+void rtl92se_resume(struct ieee80211_hw *hw);
+
+#endif
+
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/led.c b/drivers/net/wireless/rtlwifi/rtl8192se/led.c
new file mode 100644
index 000000000000..6d4f66616680
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/led.c
@@ -0,0 +1,149 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "reg.h"
+#include "led.h"
+
+static void _rtl92se_init_led(struct ieee80211_hw *hw,
+ struct rtl_led *pled, enum rtl_led_pin ledpin)
+{
+ pled->hw = hw;
+ pled->ledpin = ledpin;
+ pled->ledon = false;
+}
+
+void rtl92se_init_sw_leds(struct ieee80211_hw *hw)
+{
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ _rtl92se_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0);
+ _rtl92se_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1);
+}
+
+void rtl92se_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled)
+{
+ u8 ledcfg;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
+ ("LedAddr:%X ledpin=%d\n", LEDCFG, pled->ledpin));
+
+ ledcfg = rtl_read_byte(rtlpriv, LEDCFG);
+
+ switch (pled->ledpin) {
+ case LED_PIN_GPIO0:
+ break;
+ case LED_PIN_LED0:
+ rtl_write_byte(rtlpriv, LEDCFG, ledcfg & 0xf0);
+ break;
+ case LED_PIN_LED1:
+ rtl_write_byte(rtlpriv, LEDCFG, ledcfg & 0x0f);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ }
+ pled->ledon = true;
+}
+
+void rtl92se_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ u8 ledcfg;
+
+ RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
+ ("LedAddr:%X ledpin=%d\n", LEDCFG, pled->ledpin));
+
+ ledcfg = rtl_read_byte(rtlpriv, LEDCFG);
+
+ switch (pled->ledpin) {
+ case LED_PIN_GPIO0:
+ break;
+ case LED_PIN_LED0:
+ ledcfg &= 0xf0;
+ if (pcipriv->ledctl.led_opendrain == true)
+ rtl_write_byte(rtlpriv, LEDCFG, (ledcfg | BIT(1)));
+ else
+ rtl_write_byte(rtlpriv, LEDCFG, (ledcfg | BIT(3)));
+ break;
+ case LED_PIN_LED1:
+ ledcfg &= 0x0f;
+ rtl_write_byte(rtlpriv, LEDCFG, (ledcfg | BIT(3)));
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ }
+ pled->ledon = false;
+}
+
+static void _rtl92se_sw_led_control(struct ieee80211_hw *hw,
+ enum led_ctl_mode ledaction)
+{
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0);
+ switch (ledaction) {
+ case LED_CTL_POWER_ON:
+ case LED_CTL_LINK:
+ case LED_CTL_NO_LINK:
+ rtl92se_sw_led_on(hw, pLed0);
+ break;
+ case LED_CTL_POWER_OFF:
+ rtl92se_sw_led_off(hw, pLed0);
+ break;
+ default:
+ break;
+ }
+}
+
+void rtl92se_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+ if ((ppsc->rfoff_reason > RF_CHANGE_BY_PS) &&
+ (ledaction == LED_CTL_TX ||
+ ledaction == LED_CTL_RX ||
+ ledaction == LED_CTL_SITE_SURVEY ||
+ ledaction == LED_CTL_LINK ||
+ ledaction == LED_CTL_NO_LINK ||
+ ledaction == LED_CTL_START_TO_LINK ||
+ ledaction == LED_CTL_POWER_ON)) {
+ return;
+ }
+ RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, ("ledaction %d,\n",
+ ledaction));
+
+ _rtl92se_sw_led_control(hw, ledaction);
+}
+
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/led.h b/drivers/net/wireless/rtlwifi/rtl8192se/led.h
new file mode 100644
index 000000000000..8cce3870af3c
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/led.h
@@ -0,0 +1,37 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#ifndef __REALTEK_PCI92SE_LED_H__
+#define __REALTEK_PCI92SE_LED_H__
+
+void rtl92se_init_sw_leds(struct ieee80211_hw *hw);
+void rtl92se_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled);
+void rtl92se_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled);
+void rtl92se_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c
new file mode 100644
index 000000000000..63b45e60a95e
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c
@@ -0,0 +1,1740 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../ps.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "rf.h"
+#include "dm.h"
+#include "fw.h"
+#include "hw.h"
+#include "table.h"
+
+static u32 _rtl92s_phy_calculate_bit_shift(u32 bitmask)
+{
+ u32 i;
+
+ for (i = 0; i <= 31; i++) {
+ if (((bitmask >> i) & 0x1) == 1)
+ break;
+ }
+
+ return i;
+}
+
+u32 rtl92s_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 returnvalue = 0, originalvalue, bitshift;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x)\n",
+ regaddr, bitmask));
+
+ originalvalue = rtl_read_dword(rtlpriv, regaddr);
+ bitshift = _rtl92s_phy_calculate_bit_shift(bitmask);
+ returnvalue = (originalvalue & bitmask) >> bitshift;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ ("BBR MASK=0x%x Addr[0x%x]=0x%x\n",
+ bitmask, regaddr, originalvalue));
+
+ return returnvalue;
+
+}
+
+void rtl92s_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask,
+ u32 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 originalvalue, bitshift;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x),"
+ " data(%#x)\n", regaddr, bitmask, data));
+
+ if (bitmask != MASKDWORD) {
+ originalvalue = rtl_read_dword(rtlpriv, regaddr);
+ bitshift = _rtl92s_phy_calculate_bit_shift(bitmask);
+ data = ((originalvalue & (~bitmask)) | (data << bitshift));
+ }
+
+ rtl_write_dword(rtlpriv, regaddr, data);
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x),"
+ " data(%#x)\n", regaddr, bitmask, data));
+
+}
+
+static u32 _rtl92s_phy_rf_serial_read(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 offset)
+{
+
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath];
+ u32 newoffset;
+ u32 tmplong, tmplong2;
+ u8 rfpi_enable = 0;
+ u32 retvalue = 0;
+
+ offset &= 0x3f;
+ newoffset = offset;
+
+ tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD);
+
+ if (rfpath == RF90_PATH_A)
+ tmplong2 = tmplong;
+ else
+ tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD);
+
+ tmplong2 = (tmplong2 & (~BLSSI_READADDRESS)) | (newoffset << 23) |
+ BLSSI_READEDGE;
+
+ rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
+ tmplong & (~BLSSI_READEDGE));
+
+ mdelay(1);
+
+ rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2);
+ mdelay(1);
+
+ rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, tmplong |
+ BLSSI_READEDGE);
+ mdelay(1);
+
+ if (rfpath == RF90_PATH_A)
+ rfpi_enable = (u8)rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1,
+ BIT(8));
+ else if (rfpath == RF90_PATH_B)
+ rfpi_enable = (u8)rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1,
+ BIT(8));
+
+ if (rfpi_enable)
+ retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readbackpi,
+ BLSSI_READBACK_DATA);
+ else
+ retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readback,
+ BLSSI_READBACK_DATA);
+
+ retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readback,
+ BLSSI_READBACK_DATA);
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("RFR-%d Addr[0x%x]=0x%x\n",
+ rfpath, pphyreg->rflssi_readback, retvalue));
+
+ return retvalue;
+
+}
+
+static void _rtl92s_phy_rf_serial_write(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 offset,
+ u32 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath];
+ u32 data_and_addr = 0;
+ u32 newoffset;
+
+ offset &= 0x3f;
+ newoffset = offset;
+
+ data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff;
+ rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr);
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("RFW-%d Addr[0x%x]=0x%x\n",
+ rfpath, pphyreg->rf3wire_offset, data_and_addr));
+}
+
+
+u32 rtl92s_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath,
+ u32 regaddr, u32 bitmask)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 original_value, readback_value, bitshift;
+ unsigned long flags;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), rfpath(%#x), "
+ "bitmask(%#x)\n", regaddr, rfpath, bitmask));
+
+ spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
+
+ original_value = _rtl92s_phy_rf_serial_read(hw, rfpath, regaddr);
+
+ bitshift = _rtl92s_phy_calculate_bit_shift(bitmask);
+ readback_value = (original_value & bitmask) >> bitshift;
+
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), rfpath(%#x), "
+ "bitmask(%#x), original_value(%#x)\n", regaddr, rfpath,
+ bitmask, original_value));
+
+ return readback_value;
+}
+
+void rtl92s_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath,
+ u32 regaddr, u32 bitmask, u32 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u32 original_value, bitshift;
+ unsigned long flags;
+
+ if (!((rtlphy->rf_pathmap >> rfpath) & 0x1))
+ return;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x),"
+ " data(%#x), rfpath(%#x)\n", regaddr, bitmask, data, rfpath));
+
+ spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
+
+ if (bitmask != RFREG_OFFSET_MASK) {
+ original_value = _rtl92s_phy_rf_serial_read(hw, rfpath,
+ regaddr);
+ bitshift = _rtl92s_phy_calculate_bit_shift(bitmask);
+ data = ((original_value & (~bitmask)) | (data << bitshift));
+ }
+
+ _rtl92s_phy_rf_serial_write(hw, rfpath, regaddr, data);
+
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x), "
+ "data(%#x), rfpath(%#x)\n", regaddr, bitmask, data, rfpath));
+
+}
+
+void rtl92s_phy_scan_operation_backup(struct ieee80211_hw *hw,
+ u8 operation)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ if (!is_hal_stop(rtlhal)) {
+ switch (operation) {
+ case SCAN_OPT_BACKUP:
+ rtl92s_phy_set_fw_cmd(hw, FW_CMD_PAUSE_DM_BY_SCAN);
+ break;
+ case SCAN_OPT_RESTORE:
+ rtl92s_phy_set_fw_cmd(hw, FW_CMD_RESUME_DM_BY_SCAN);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Unknown operation.\n"));
+ break;
+ }
+ }
+}
+
+void rtl92s_phy_set_bw_mode(struct ieee80211_hw *hw,
+ enum nl80211_channel_type ch_type)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u8 reg_bw_opmode;
+ u8 reg_prsr_rsc;
+
+ RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("Switch to %s bandwidth\n",
+ rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ?
+ "20MHz" : "40MHz"));
+
+ if (rtlphy->set_bwmode_inprogress)
+ return;
+ if (is_hal_stop(rtlhal))
+ return;
+
+ rtlphy->set_bwmode_inprogress = true;
+
+ reg_bw_opmode = rtl_read_byte(rtlpriv, BW_OPMODE);
+ reg_prsr_rsc = rtl_read_byte(rtlpriv, RRSR + 2);
+
+ switch (rtlphy->current_chan_bw) {
+ case HT_CHANNEL_WIDTH_20:
+ reg_bw_opmode |= BW_OPMODE_20MHZ;
+ rtl_write_byte(rtlpriv, BW_OPMODE, reg_bw_opmode);
+ break;
+ case HT_CHANNEL_WIDTH_20_40:
+ reg_bw_opmode &= ~BW_OPMODE_20MHZ;
+ rtl_write_byte(rtlpriv, BW_OPMODE, reg_bw_opmode);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("unknown bandwidth: %#X\n",
+ rtlphy->current_chan_bw));
+ break;
+ }
+
+ switch (rtlphy->current_chan_bw) {
+ case HT_CHANNEL_WIDTH_20:
+ rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0);
+ rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0);
+
+ if (rtlhal->version >= VERSION_8192S_BCUT)
+ rtl_write_byte(rtlpriv, RFPGA0_ANALOGPARAMETER2, 0x58);
+ break;
+ case HT_CHANNEL_WIDTH_20_40:
+ rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1);
+ rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1);
+
+ rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND,
+ (mac->cur_40_prime_sc >> 1));
+ rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc);
+
+ if (rtlhal->version >= VERSION_8192S_BCUT)
+ rtl_write_byte(rtlpriv, RFPGA0_ANALOGPARAMETER2, 0x18);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw));
+ break;
+ }
+
+ rtl92s_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw);
+ rtlphy->set_bwmode_inprogress = false;
+ RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n"));
+}
+
+static bool _rtl92s_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
+ u32 cmdtableidx, u32 cmdtablesz, enum swchnlcmd_id cmdid,
+ u32 para1, u32 para2, u32 msdelay)
+{
+ struct swchnlcmd *pcmd;
+
+ if (cmdtable == NULL) {
+ RT_ASSERT(false, ("cmdtable cannot be NULL.\n"));
+ return false;
+ }
+
+ if (cmdtableidx >= cmdtablesz)
+ return false;
+
+ pcmd = cmdtable + cmdtableidx;
+ pcmd->cmdid = cmdid;
+ pcmd->para1 = para1;
+ pcmd->para2 = para2;
+ pcmd->msdelay = msdelay;
+
+ return true;
+}
+
+static bool _rtl92s_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
+ u8 channel, u8 *stage, u8 *step, u32 *delay)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct swchnlcmd precommoncmd[MAX_PRECMD_CNT];
+ u32 precommoncmdcnt;
+ struct swchnlcmd postcommoncmd[MAX_POSTCMD_CNT];
+ u32 postcommoncmdcnt;
+ struct swchnlcmd rfdependcmd[MAX_RFDEPENDCMD_CNT];
+ u32 rfdependcmdcnt;
+ struct swchnlcmd *currentcmd = NULL;
+ u8 rfpath;
+ u8 num_total_rfpath = rtlphy->num_total_rfpath;
+
+ precommoncmdcnt = 0;
+ _rtl92s_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
+ MAX_PRECMD_CNT, CMDID_SET_TXPOWEROWER_LEVEL, 0, 0, 0);
+ _rtl92s_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
+ MAX_PRECMD_CNT, CMDID_END, 0, 0, 0);
+
+ postcommoncmdcnt = 0;
+
+ _rtl92s_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++,
+ MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0);
+
+ rfdependcmdcnt = 0;
+
+ RT_ASSERT((channel >= 1 && channel <= 14),
+ ("illegal channel for Zebra: %d\n", channel));
+
+ _rtl92s_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
+ MAX_RFDEPENDCMD_CNT, CMDID_RF_WRITEREG,
+ RF_CHNLBW, channel, 10);
+
+ _rtl92s_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
+ MAX_RFDEPENDCMD_CNT, CMDID_END, 0, 0, 0);
+
+ do {
+ switch (*stage) {
+ case 0:
+ currentcmd = &precommoncmd[*step];
+ break;
+ case 1:
+ currentcmd = &rfdependcmd[*step];
+ break;
+ case 2:
+ currentcmd = &postcommoncmd[*step];
+ break;
+ }
+
+ if (currentcmd->cmdid == CMDID_END) {
+ if ((*stage) == 2) {
+ return true;
+ } else {
+ (*stage)++;
+ (*step) = 0;
+ continue;
+ }
+ }
+
+ switch (currentcmd->cmdid) {
+ case CMDID_SET_TXPOWEROWER_LEVEL:
+ rtl92s_phy_set_txpower(hw, channel);
+ break;
+ case CMDID_WRITEPORT_ULONG:
+ rtl_write_dword(rtlpriv, currentcmd->para1,
+ currentcmd->para2);
+ break;
+ case CMDID_WRITEPORT_USHORT:
+ rtl_write_word(rtlpriv, currentcmd->para1,
+ (u16)currentcmd->para2);
+ break;
+ case CMDID_WRITEPORT_UCHAR:
+ rtl_write_byte(rtlpriv, currentcmd->para1,
+ (u8)currentcmd->para2);
+ break;
+ case CMDID_RF_WRITEREG:
+ for (rfpath = 0; rfpath < num_total_rfpath; rfpath++) {
+ rtlphy->rfreg_chnlval[rfpath] =
+ ((rtlphy->rfreg_chnlval[rfpath] &
+ 0xfffffc00) | currentcmd->para2);
+ rtl_set_rfreg(hw, (enum radio_path)rfpath,
+ currentcmd->para1,
+ RFREG_OFFSET_MASK,
+ rtlphy->rfreg_chnlval[rfpath]);
+ }
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ }
+
+ break;
+ } while (true);
+
+ (*delay) = currentcmd->msdelay;
+ (*step)++;
+ return false;
+}
+
+u8 rtl92s_phy_sw_chnl(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u32 delay;
+ bool ret;
+
+ RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
+ ("switch to channel%d\n",
+ rtlphy->current_channel));
+
+ if (rtlphy->sw_chnl_inprogress)
+ return 0;
+
+ if (rtlphy->set_bwmode_inprogress)
+ return 0;
+
+ if (is_hal_stop(rtlhal))
+ return 0;
+
+ rtlphy->sw_chnl_inprogress = true;
+ rtlphy->sw_chnl_stage = 0;
+ rtlphy->sw_chnl_step = 0;
+
+ do {
+ if (!rtlphy->sw_chnl_inprogress)
+ break;
+
+ ret = _rtl92s_phy_sw_chnl_step_by_step(hw,
+ rtlphy->current_channel,
+ &rtlphy->sw_chnl_stage,
+ &rtlphy->sw_chnl_step, &delay);
+ if (!ret) {
+ if (delay > 0)
+ mdelay(delay);
+ else
+ continue;
+ } else {
+ rtlphy->sw_chnl_inprogress = false;
+ }
+ break;
+ } while (true);
+
+ rtlphy->sw_chnl_inprogress = false;
+
+ RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n"));
+
+ return 1;
+}
+
+static void _rtl92se_phy_set_rf_sleep(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 u1btmp;
+
+ u1btmp = rtl_read_byte(rtlpriv, LDOV12D_CTRL);
+ u1btmp |= BIT(0);
+
+ rtl_write_byte(rtlpriv, LDOV12D_CTRL, u1btmp);
+ rtl_write_byte(rtlpriv, SPS1_CTRL, 0x0);
+ rtl_write_byte(rtlpriv, TXPAUSE, 0xFF);
+ rtl_write_word(rtlpriv, CMDR, 0x57FC);
+ udelay(100);
+
+ rtl_write_word(rtlpriv, CMDR, 0x77FC);
+ rtl_write_byte(rtlpriv, PHY_CCA, 0x0);
+ udelay(10);
+
+ rtl_write_word(rtlpriv, CMDR, 0x37FC);
+ udelay(10);
+
+ rtl_write_word(rtlpriv, CMDR, 0x77FC);
+ udelay(10);
+
+ rtl_write_word(rtlpriv, CMDR, 0x57FC);
+
+ /* we should chnge GPIO to input mode
+ * this will drop away current about 25mA*/
+ rtl8192se_gpiobit3_cfg_inputmode(hw);
+}
+
+bool rtl92s_phy_set_rf_power_state(struct ieee80211_hw *hw,
+ enum rf_pwrstate rfpwr_state)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ bool bresult = true;
+ u8 i, queue_id;
+ struct rtl8192_tx_ring *ring = NULL;
+
+ if (rfpwr_state == ppsc->rfpwr_state)
+ return false;
+
+ ppsc->set_rfpowerstate_inprogress = true;
+
+ switch (rfpwr_state) {
+ case ERFON:{
+ if ((ppsc->rfpwr_state == ERFOFF) &&
+ RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) {
+
+ bool rtstatus;
+ u32 InitializeCount = 0;
+ do {
+ InitializeCount++;
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ ("IPS Set eRf nic enable\n"));
+ rtstatus = rtl_ps_enable_nic(hw);
+ } while ((rtstatus != true) &&
+ (InitializeCount < 10));
+
+ RT_CLEAR_PS_LEVEL(ppsc,
+ RT_RF_OFF_LEVL_HALT_NIC);
+ } else {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
+ ("awake, sleeped:%d ms "
+ "state_inap:%x\n",
+ jiffies_to_msecs(jiffies -
+ ppsc->last_sleep_jiffies),
+ rtlpriv->psc.state_inap));
+ ppsc->last_awake_jiffies = jiffies;
+ rtl_write_word(rtlpriv, CMDR, 0x37FC);
+ rtl_write_byte(rtlpriv, TXPAUSE, 0x00);
+ rtl_write_byte(rtlpriv, PHY_CCA, 0x3);
+ }
+
+ if (mac->link_state == MAC80211_LINKED)
+ rtlpriv->cfg->ops->led_control(hw,
+ LED_CTL_LINK);
+ else
+ rtlpriv->cfg->ops->led_control(hw,
+ LED_CTL_NO_LINK);
+ break;
+ }
+ case ERFOFF:{
+ if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) {
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ ("IPS Set eRf nic disable\n"));
+ rtl_ps_disable_nic(hw);
+ RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+ } else {
+ if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS)
+ rtlpriv->cfg->ops->led_control(hw,
+ LED_CTL_NO_LINK);
+ else
+ rtlpriv->cfg->ops->led_control(hw,
+ LED_CTL_POWER_OFF);
+ }
+ break;
+ }
+ case ERFSLEEP:
+ if (ppsc->rfpwr_state == ERFOFF)
+ break;
+
+ for (queue_id = 0, i = 0;
+ queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) {
+ ring = &pcipriv->dev.tx_ring[queue_id];
+ if (skb_queue_len(&ring->queue) == 0 ||
+ queue_id == BEACON_QUEUE) {
+ queue_id++;
+ continue;
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("eRf Off/Sleep: "
+ "%d times TcbBusyQueue[%d] = "
+ "%d before doze!\n",
+ (i + 1), queue_id,
+ skb_queue_len(&ring->queue)));
+
+ udelay(10);
+ i++;
+ }
+
+ if (i >= MAX_DOZE_WAITING_TIMES_9x) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("\nERFOFF: %d times"
+ "TcbBusyQueue[%d] = %d !\n",
+ MAX_DOZE_WAITING_TIMES_9x,
+ queue_id,
+ skb_queue_len(&ring->queue)));
+ break;
+ }
+ }
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
+ ("Set ERFSLEEP awaked:%d ms\n",
+ jiffies_to_msecs(jiffies -
+ ppsc->last_awake_jiffies)));
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
+ ("sleep awaked:%d ms "
+ "state_inap:%x\n", jiffies_to_msecs(jiffies -
+ ppsc->last_awake_jiffies),
+ rtlpriv->psc.state_inap));
+ ppsc->last_sleep_jiffies = jiffies;
+ _rtl92se_phy_set_rf_sleep(hw);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ bresult = false;
+ break;
+ }
+
+ if (bresult)
+ ppsc->rfpwr_state = rfpwr_state;
+
+ ppsc->set_rfpowerstate_inprogress = false;
+
+ return bresult;
+}
+
+static bool _rtl92s_phy_config_rfpa_bias_current(struct ieee80211_hw *hw,
+ enum radio_path rfpath)
+{
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ bool rtstatus = true;
+ u32 tmpval = 0;
+
+ /* If inferiority IC, we have to increase the PA bias current */
+ if (rtlhal->ic_class != IC_INFERIORITY_A) {
+ tmpval = rtl92s_phy_query_rf_reg(hw, rfpath, RF_IPA, 0xf);
+ rtl92s_phy_set_rf_reg(hw, rfpath, RF_IPA, 0xf, tmpval + 1);
+ }
+
+ return rtstatus;
+}
+
+static void _rtl92s_store_pwrindex_diffrate_offset(struct ieee80211_hw *hw,
+ u32 reg_addr, u32 bitmask, u32 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ if (reg_addr == RTXAGC_RATE18_06)
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][0] =
+ data;
+ if (reg_addr == RTXAGC_RATE54_24)
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][1] =
+ data;
+ if (reg_addr == RTXAGC_CCK_MCS32)
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][6] =
+ data;
+ if (reg_addr == RTXAGC_MCS03_MCS00)
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][2] =
+ data;
+ if (reg_addr == RTXAGC_MCS07_MCS04)
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][3] =
+ data;
+ if (reg_addr == RTXAGC_MCS11_MCS08)
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][4] =
+ data;
+ if (reg_addr == RTXAGC_MCS15_MCS12) {
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][5] =
+ data;
+ rtlphy->pwrgroup_cnt++;
+ }
+}
+
+static void _rtl92s_phy_init_register_definition(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ /*RF Interface Sowrtware Control */
+ rtlphy->phyreg_def[RF90_PATH_A].rfintfs = RFPGA0_XAB_RFINTERFACESW;
+ rtlphy->phyreg_def[RF90_PATH_B].rfintfs = RFPGA0_XAB_RFINTERFACESW;
+ rtlphy->phyreg_def[RF90_PATH_C].rfintfs = RFPGA0_XCD_RFINTERFACESW;
+ rtlphy->phyreg_def[RF90_PATH_D].rfintfs = RFPGA0_XCD_RFINTERFACESW;
+
+ /* RF Interface Readback Value */
+ rtlphy->phyreg_def[RF90_PATH_A].rfintfi = RFPGA0_XAB_RFINTERFACERB;
+ rtlphy->phyreg_def[RF90_PATH_B].rfintfi = RFPGA0_XAB_RFINTERFACERB;
+ rtlphy->phyreg_def[RF90_PATH_C].rfintfi = RFPGA0_XCD_RFINTERFACERB;
+ rtlphy->phyreg_def[RF90_PATH_D].rfintfi = RFPGA0_XCD_RFINTERFACERB;
+
+ /* RF Interface Output (and Enable) */
+ rtlphy->phyreg_def[RF90_PATH_A].rfintfo = RFPGA0_XA_RFINTERFACEOE;
+ rtlphy->phyreg_def[RF90_PATH_B].rfintfo = RFPGA0_XB_RFINTERFACEOE;
+ rtlphy->phyreg_def[RF90_PATH_C].rfintfo = RFPGA0_XC_RFINTERFACEOE;
+ rtlphy->phyreg_def[RF90_PATH_D].rfintfo = RFPGA0_XD_RFINTERFACEOE;
+
+ /* RF Interface (Output and) Enable */
+ rtlphy->phyreg_def[RF90_PATH_A].rfintfe = RFPGA0_XA_RFINTERFACEOE;
+ rtlphy->phyreg_def[RF90_PATH_B].rfintfe = RFPGA0_XB_RFINTERFACEOE;
+ rtlphy->phyreg_def[RF90_PATH_C].rfintfe = RFPGA0_XC_RFINTERFACEOE;
+ rtlphy->phyreg_def[RF90_PATH_D].rfintfe = RFPGA0_XD_RFINTERFACEOE;
+
+ /* Addr of LSSI. Wirte RF register by driver */
+ rtlphy->phyreg_def[RF90_PATH_A].rf3wire_offset =
+ RFPGA0_XA_LSSIPARAMETER;
+ rtlphy->phyreg_def[RF90_PATH_B].rf3wire_offset =
+ RFPGA0_XB_LSSIPARAMETER;
+ rtlphy->phyreg_def[RF90_PATH_C].rf3wire_offset =
+ RFPGA0_XC_LSSIPARAMETER;
+ rtlphy->phyreg_def[RF90_PATH_D].rf3wire_offset =
+ RFPGA0_XD_LSSIPARAMETER;
+
+ /* RF parameter */
+ rtlphy->phyreg_def[RF90_PATH_A].rflssi_select = RFPGA0_XAB_RFPARAMETER;
+ rtlphy->phyreg_def[RF90_PATH_B].rflssi_select = RFPGA0_XAB_RFPARAMETER;
+ rtlphy->phyreg_def[RF90_PATH_C].rflssi_select = RFPGA0_XCD_RFPARAMETER;
+ rtlphy->phyreg_def[RF90_PATH_D].rflssi_select = RFPGA0_XCD_RFPARAMETER;
+
+ /* Tx AGC Gain Stage (same for all path. Should we remove this?) */
+ rtlphy->phyreg_def[RF90_PATH_A].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+ rtlphy->phyreg_def[RF90_PATH_B].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+ rtlphy->phyreg_def[RF90_PATH_C].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+ rtlphy->phyreg_def[RF90_PATH_D].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+
+ /* Tranceiver A~D HSSI Parameter-1 */
+ rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para1 = RFPGA0_XA_HSSIPARAMETER1;
+ rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para1 = RFPGA0_XB_HSSIPARAMETER1;
+ rtlphy->phyreg_def[RF90_PATH_C].rfhssi_para1 = RFPGA0_XC_HSSIPARAMETER1;
+ rtlphy->phyreg_def[RF90_PATH_D].rfhssi_para1 = RFPGA0_XD_HSSIPARAMETER1;
+
+ /* Tranceiver A~D HSSI Parameter-2 */
+ rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para2 = RFPGA0_XA_HSSIPARAMETER2;
+ rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para2 = RFPGA0_XB_HSSIPARAMETER2;
+ rtlphy->phyreg_def[RF90_PATH_C].rfhssi_para2 = RFPGA0_XC_HSSIPARAMETER2;
+ rtlphy->phyreg_def[RF90_PATH_D].rfhssi_para2 = RFPGA0_XD_HSSIPARAMETER2;
+
+ /* RF switch Control */
+ rtlphy->phyreg_def[RF90_PATH_A].rfswitch_control =
+ RFPGA0_XAB_SWITCHCONTROL;
+ rtlphy->phyreg_def[RF90_PATH_B].rfswitch_control =
+ RFPGA0_XAB_SWITCHCONTROL;
+ rtlphy->phyreg_def[RF90_PATH_C].rfswitch_control =
+ RFPGA0_XCD_SWITCHCONTROL;
+ rtlphy->phyreg_def[RF90_PATH_D].rfswitch_control =
+ RFPGA0_XCD_SWITCHCONTROL;
+
+ /* AGC control 1 */
+ rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1;
+ rtlphy->phyreg_def[RF90_PATH_B].rfagc_control1 = ROFDM0_XBAGCCORE1;
+ rtlphy->phyreg_def[RF90_PATH_C].rfagc_control1 = ROFDM0_XCAGCCORE1;
+ rtlphy->phyreg_def[RF90_PATH_D].rfagc_control1 = ROFDM0_XDAGCCORE1;
+
+ /* AGC control 2 */
+ rtlphy->phyreg_def[RF90_PATH_A].rfagc_control2 = ROFDM0_XAAGCCORE2;
+ rtlphy->phyreg_def[RF90_PATH_B].rfagc_control2 = ROFDM0_XBAGCCORE2;
+ rtlphy->phyreg_def[RF90_PATH_C].rfagc_control2 = ROFDM0_XCAGCCORE2;
+ rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2;
+
+ /* RX AFE control 1 */
+ rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbalance =
+ ROFDM0_XARXIQIMBALANCE;
+ rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbalance =
+ ROFDM0_XBRXIQIMBALANCE;
+ rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbalance =
+ ROFDM0_XCRXIQIMBALANCE;
+ rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbalance =
+ ROFDM0_XDRXIQIMBALANCE;
+
+ /* RX AFE control 1 */
+ rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE;
+ rtlphy->phyreg_def[RF90_PATH_B].rfrx_afe = ROFDM0_XBRXAFE;
+ rtlphy->phyreg_def[RF90_PATH_C].rfrx_afe = ROFDM0_XCRXAFE;
+ rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE;
+
+ /* Tx AFE control 1 */
+ rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbalance =
+ ROFDM0_XATXIQIMBALANCE;
+ rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbalance =
+ ROFDM0_XBTXIQIMBALANCE;
+ rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbalance =
+ ROFDM0_XCTXIQIMBALANCE;
+ rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbalance =
+ ROFDM0_XDTXIQIMBALANCE;
+
+ /* Tx AFE control 2 */
+ rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATXAFE;
+ rtlphy->phyreg_def[RF90_PATH_B].rftx_afe = ROFDM0_XBTXAFE;
+ rtlphy->phyreg_def[RF90_PATH_C].rftx_afe = ROFDM0_XCTXAFE;
+ rtlphy->phyreg_def[RF90_PATH_D].rftx_afe = ROFDM0_XDTXAFE;
+
+ /* Tranceiver LSSI Readback */
+ rtlphy->phyreg_def[RF90_PATH_A].rflssi_readback =
+ RFPGA0_XA_LSSIREADBACK;
+ rtlphy->phyreg_def[RF90_PATH_B].rflssi_readback =
+ RFPGA0_XB_LSSIREADBACK;
+ rtlphy->phyreg_def[RF90_PATH_C].rflssi_readback =
+ RFPGA0_XC_LSSIREADBACK;
+ rtlphy->phyreg_def[RF90_PATH_D].rflssi_readback =
+ RFPGA0_XD_LSSIREADBACK;
+
+ /* Tranceiver LSSI Readback PI mode */
+ rtlphy->phyreg_def[RF90_PATH_A].rflssi_readbackpi =
+ TRANSCEIVERA_HSPI_READBACK;
+ rtlphy->phyreg_def[RF90_PATH_B].rflssi_readbackpi =
+ TRANSCEIVERB_HSPI_READBACK;
+}
+
+
+static bool _rtl92s_phy_config_bb(struct ieee80211_hw *hw, u8 configtype)
+{
+ int i;
+ u32 *phy_reg_table;
+ u32 *agc_table;
+ u16 phy_reg_len, agc_len;
+
+ agc_len = AGCTAB_ARRAYLENGTH;
+ agc_table = rtl8192seagctab_array;
+ /* Default RF_type: 2T2R */
+ phy_reg_len = PHY_REG_2T2RARRAYLENGTH;
+ phy_reg_table = rtl8192sephy_reg_2t2rarray;
+
+ if (configtype == BASEBAND_CONFIG_PHY_REG) {
+ for (i = 0; i < phy_reg_len; i = i + 2) {
+ if (phy_reg_table[i] == 0xfe)
+ mdelay(50);
+ else if (phy_reg_table[i] == 0xfd)
+ mdelay(5);
+ else if (phy_reg_table[i] == 0xfc)
+ mdelay(1);
+ else if (phy_reg_table[i] == 0xfb)
+ udelay(50);
+ else if (phy_reg_table[i] == 0xfa)
+ udelay(5);
+ else if (phy_reg_table[i] == 0xf9)
+ udelay(1);
+
+ /* Add delay for ECS T20 & LG malow platform, */
+ udelay(1);
+
+ rtl92s_phy_set_bb_reg(hw, phy_reg_table[i], MASKDWORD,
+ phy_reg_table[i + 1]);
+ }
+ } else if (configtype == BASEBAND_CONFIG_AGC_TAB) {
+ for (i = 0; i < agc_len; i = i + 2) {
+ rtl92s_phy_set_bb_reg(hw, agc_table[i], MASKDWORD,
+ agc_table[i + 1]);
+
+ /* Add delay for ECS T20 & LG malow platform */
+ udelay(1);
+ }
+ }
+
+ return true;
+}
+
+static bool _rtl92s_phy_set_bb_to_diff_rf(struct ieee80211_hw *hw,
+ u8 configtype)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u32 *phy_regarray2xtxr_table;
+ u16 phy_regarray2xtxr_len;
+ int i;
+
+ if (rtlphy->rf_type == RF_1T1R) {
+ phy_regarray2xtxr_table = rtl8192sephy_changeto_1t1rarray;
+ phy_regarray2xtxr_len = PHY_CHANGETO_1T1RARRAYLENGTH;
+ } else if (rtlphy->rf_type == RF_1T2R) {
+ phy_regarray2xtxr_table = rtl8192sephy_changeto_1t2rarray;
+ phy_regarray2xtxr_len = PHY_CHANGETO_1T2RARRAYLENGTH;
+ } else {
+ return false;
+ }
+
+ if (configtype == BASEBAND_CONFIG_PHY_REG) {
+ for (i = 0; i < phy_regarray2xtxr_len; i = i + 3) {
+ if (phy_regarray2xtxr_table[i] == 0xfe)
+ mdelay(50);
+ else if (phy_regarray2xtxr_table[i] == 0xfd)
+ mdelay(5);
+ else if (phy_regarray2xtxr_table[i] == 0xfc)
+ mdelay(1);
+ else if (phy_regarray2xtxr_table[i] == 0xfb)
+ udelay(50);
+ else if (phy_regarray2xtxr_table[i] == 0xfa)
+ udelay(5);
+ else if (phy_regarray2xtxr_table[i] == 0xf9)
+ udelay(1);
+
+ rtl92s_phy_set_bb_reg(hw, phy_regarray2xtxr_table[i],
+ phy_regarray2xtxr_table[i + 1],
+ phy_regarray2xtxr_table[i + 2]);
+ }
+ }
+
+ return true;
+}
+
+static bool _rtl92s_phy_config_bb_with_pg(struct ieee80211_hw *hw,
+ u8 configtype)
+{
+ int i;
+ u32 *phy_table_pg;
+ u16 phy_pg_len;
+
+ phy_pg_len = PHY_REG_ARRAY_PGLENGTH;
+ phy_table_pg = rtl8192sephy_reg_array_pg;
+
+ if (configtype == BASEBAND_CONFIG_PHY_REG) {
+ for (i = 0; i < phy_pg_len; i = i + 3) {
+ if (phy_table_pg[i] == 0xfe)
+ mdelay(50);
+ else if (phy_table_pg[i] == 0xfd)
+ mdelay(5);
+ else if (phy_table_pg[i] == 0xfc)
+ mdelay(1);
+ else if (phy_table_pg[i] == 0xfb)
+ udelay(50);
+ else if (phy_table_pg[i] == 0xfa)
+ udelay(5);
+ else if (phy_table_pg[i] == 0xf9)
+ udelay(1);
+
+ _rtl92s_store_pwrindex_diffrate_offset(hw,
+ phy_table_pg[i],
+ phy_table_pg[i + 1],
+ phy_table_pg[i + 2]);
+ rtl92s_phy_set_bb_reg(hw, phy_table_pg[i],
+ phy_table_pg[i + 1],
+ phy_table_pg[i + 2]);
+ }
+ }
+
+ return true;
+}
+
+static bool _rtl92s_phy_bb_config_parafile(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ bool rtstatus = true;
+
+ /* 1. Read PHY_REG.TXT BB INIT!! */
+ /* We will separate as 1T1R/1T2R/1T2R_GREEN/2T2R */
+ if (rtlphy->rf_type == RF_1T2R || rtlphy->rf_type == RF_2T2R ||
+ rtlphy->rf_type == RF_1T1R || rtlphy->rf_type == RF_2T2R_GREEN) {
+ rtstatus = _rtl92s_phy_config_bb(hw, BASEBAND_CONFIG_PHY_REG);
+
+ if (rtlphy->rf_type != RF_2T2R &&
+ rtlphy->rf_type != RF_2T2R_GREEN)
+ /* so we should reconfig BB reg with the right
+ * PHY parameters. */
+ rtstatus = _rtl92s_phy_set_bb_to_diff_rf(hw,
+ BASEBAND_CONFIG_PHY_REG);
+ } else {
+ rtstatus = false;
+ }
+
+ if (rtstatus != true) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
+ ("Write BB Reg Fail!!"));
+ goto phy_BB8190_Config_ParaFile_Fail;
+ }
+
+ /* 2. If EEPROM or EFUSE autoload OK, We must config by
+ * PHY_REG_PG.txt */
+ if (rtlefuse->autoload_failflag == false) {
+ rtlphy->pwrgroup_cnt = 0;
+
+ rtstatus = _rtl92s_phy_config_bb_with_pg(hw,
+ BASEBAND_CONFIG_PHY_REG);
+ }
+ if (rtstatus != true) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
+ ("_rtl92s_phy_bb_config_parafile(): "
+ "BB_PG Reg Fail!!"));
+ goto phy_BB8190_Config_ParaFile_Fail;
+ }
+
+ /* 3. BB AGC table Initialization */
+ rtstatus = _rtl92s_phy_config_bb(hw, BASEBAND_CONFIG_AGC_TAB);
+
+ if (rtstatus != true) {
+ printk(KERN_ERR "_rtl92s_phy_bb_config_parafile(): "
+ "AGC Table Fail\n");
+ goto phy_BB8190_Config_ParaFile_Fail;
+ }
+
+ /* Check if the CCK HighPower is turned ON. */
+ /* This is used to calculate PWDB. */
+ rtlphy->cck_high_power = (bool)(rtl92s_phy_query_bb_reg(hw,
+ RFPGA0_XA_HSSIPARAMETER2, 0x200));
+
+phy_BB8190_Config_ParaFile_Fail:
+ return rtstatus;
+}
+
+u8 rtl92s_phy_config_rf(struct ieee80211_hw *hw, enum radio_path rfpath)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ int i;
+ bool rtstatus = true;
+ u32 *radio_a_table;
+ u32 *radio_b_table;
+ u16 radio_a_tblen, radio_b_tblen;
+
+ radio_a_tblen = RADIOA_1T_ARRAYLENGTH;
+ radio_a_table = rtl8192seradioa_1t_array;
+
+ /* Using Green mode array table for RF_2T2R_GREEN */
+ if (rtlphy->rf_type == RF_2T2R_GREEN) {
+ radio_b_table = rtl8192seradiob_gm_array;
+ radio_b_tblen = RADIOB_GM_ARRAYLENGTH;
+ } else {
+ radio_b_table = rtl8192seradiob_array;
+ radio_b_tblen = RADIOB_ARRAYLENGTH;
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Radio No %x\n", rfpath));
+ rtstatus = true;
+
+ switch (rfpath) {
+ case RF90_PATH_A:
+ for (i = 0; i < radio_a_tblen; i = i + 2) {
+ if (radio_a_table[i] == 0xfe)
+ /* Delay specific ms. Only RF configuration
+ * requires delay. */
+ mdelay(50);
+ else if (radio_a_table[i] == 0xfd)
+ mdelay(5);
+ else if (radio_a_table[i] == 0xfc)
+ mdelay(1);
+ else if (radio_a_table[i] == 0xfb)
+ udelay(50);
+ else if (radio_a_table[i] == 0xfa)
+ udelay(5);
+ else if (radio_a_table[i] == 0xf9)
+ udelay(1);
+ else
+ rtl92s_phy_set_rf_reg(hw, rfpath,
+ radio_a_table[i],
+ MASK20BITS,
+ radio_a_table[i + 1]);
+
+ /* Add delay for ECS T20 & LG malow platform */
+ udelay(1);
+ }
+
+ /* PA Bias current for inferiority IC */
+ _rtl92s_phy_config_rfpa_bias_current(hw, rfpath);
+ break;
+ case RF90_PATH_B:
+ for (i = 0; i < radio_b_tblen; i = i + 2) {
+ if (radio_b_table[i] == 0xfe)
+ /* Delay specific ms. Only RF configuration
+ * requires delay.*/
+ mdelay(50);
+ else if (radio_b_table[i] == 0xfd)
+ mdelay(5);
+ else if (radio_b_table[i] == 0xfc)
+ mdelay(1);
+ else if (radio_b_table[i] == 0xfb)
+ udelay(50);
+ else if (radio_b_table[i] == 0xfa)
+ udelay(5);
+ else if (radio_b_table[i] == 0xf9)
+ udelay(1);
+ else
+ rtl92s_phy_set_rf_reg(hw, rfpath,
+ radio_b_table[i],
+ MASK20BITS,
+ radio_b_table[i + 1]);
+
+ /* Add delay for ECS T20 & LG malow platform */
+ udelay(1);
+ }
+ break;
+ case RF90_PATH_C:
+ ;
+ break;
+ case RF90_PATH_D:
+ ;
+ break;
+ default:
+ break;
+ }
+
+ return rtstatus;
+}
+
+
+bool rtl92s_phy_mac_config(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 i;
+ u32 arraylength;
+ u32 *ptraArray;
+
+ arraylength = MAC_2T_ARRAYLENGTH;
+ ptraArray = rtl8192semac_2t_array;
+
+ for (i = 0; i < arraylength; i = i + 2)
+ rtl_write_byte(rtlpriv, ptraArray[i], (u8)ptraArray[i + 1]);
+
+ return true;
+}
+
+
+bool rtl92s_phy_bb_config(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ bool rtstatus = true;
+ u8 pathmap, index, rf_num = 0;
+ u8 path1, path2;
+
+ _rtl92s_phy_init_register_definition(hw);
+
+ /* Config BB and AGC */
+ rtstatus = _rtl92s_phy_bb_config_parafile(hw);
+
+
+ /* Check BB/RF confiuration setting. */
+ /* We only need to configure RF which is turned on. */
+ path1 = (u8)(rtl92s_phy_query_bb_reg(hw, RFPGA0_TXINFO, 0xf));
+ mdelay(10);
+ path2 = (u8)(rtl92s_phy_query_bb_reg(hw, ROFDM0_TRXPATHENABLE, 0xf));
+ pathmap = path1 | path2;
+
+ rtlphy->rf_pathmap = pathmap;
+ for (index = 0; index < 4; index++) {
+ if ((pathmap >> index) & 0x1)
+ rf_num++;
+ }
+
+ if ((rtlphy->rf_type == RF_1T1R && rf_num != 1) ||
+ (rtlphy->rf_type == RF_1T2R && rf_num != 2) ||
+ (rtlphy->rf_type == RF_2T2R && rf_num != 2) ||
+ (rtlphy->rf_type == RF_2T2R_GREEN && rf_num != 2)) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
+ ("RF_Type(%x) does not match "
+ "RF_Num(%x)!!\n", rtlphy->rf_type, rf_num));
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
+ ("path1 0x%x, path2 0x%x, pathmap "
+ "0x%x\n", path1, path2, pathmap));
+ }
+
+ return rtstatus;
+}
+
+bool rtl92s_phy_rf_config(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ /* Initialize general global value */
+ if (rtlphy->rf_type == RF_1T1R)
+ rtlphy->num_total_rfpath = 1;
+ else
+ rtlphy->num_total_rfpath = 2;
+
+ /* Config BB and RF */
+ return rtl92s_phy_rf6052_config(hw);
+}
+
+void rtl92s_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ /* read rx initial gain */
+ rtlphy->default_initialgain[0] = rtl_get_bbreg(hw,
+ ROFDM0_XAAGCCORE1, MASKBYTE0);
+ rtlphy->default_initialgain[1] = rtl_get_bbreg(hw,
+ ROFDM0_XBAGCCORE1, MASKBYTE0);
+ rtlphy->default_initialgain[2] = rtl_get_bbreg(hw,
+ ROFDM0_XCAGCCORE1, MASKBYTE0);
+ rtlphy->default_initialgain[3] = rtl_get_bbreg(hw,
+ ROFDM0_XDAGCCORE1, MASKBYTE0);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Default initial gain "
+ "(c50=0x%x, c58=0x%x, c60=0x%x, c68=0x%x)\n",
+ rtlphy->default_initialgain[0],
+ rtlphy->default_initialgain[1],
+ rtlphy->default_initialgain[2],
+ rtlphy->default_initialgain[3]));
+
+ /* read framesync */
+ rtlphy->framesync = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR3, MASKBYTE0);
+ rtlphy->framesync_c34 = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR2,
+ MASKDWORD);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("Default framesync (0x%x) = 0x%x\n",
+ ROFDM0_RXDETECTOR3, rtlphy->framesync));
+
+}
+
+static void _rtl92s_phy_get_txpower_index(struct ieee80211_hw *hw, u8 channel,
+ u8 *cckpowerlevel, u8 *ofdmpowerLevel)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 index = (channel - 1);
+
+ /* 1. CCK */
+ /* RF-A */
+ cckpowerlevel[0] = rtlefuse->txpwrlevel_cck[0][index];
+ /* RF-B */
+ cckpowerlevel[1] = rtlefuse->txpwrlevel_cck[1][index];
+
+ /* 2. OFDM for 1T or 2T */
+ if (rtlphy->rf_type == RF_1T2R || rtlphy->rf_type == RF_1T1R) {
+ /* Read HT 40 OFDM TX power */
+ ofdmpowerLevel[0] = rtlefuse->txpwrlevel_ht40_1s[0][index];
+ ofdmpowerLevel[1] = rtlefuse->txpwrlevel_ht40_1s[1][index];
+ } else if (rtlphy->rf_type == RF_2T2R) {
+ /* Read HT 40 OFDM TX power */
+ ofdmpowerLevel[0] = rtlefuse->txpwrlevel_ht40_2s[0][index];
+ ofdmpowerLevel[1] = rtlefuse->txpwrlevel_ht40_2s[1][index];
+ }
+}
+
+static void _rtl92s_phy_ccxpower_indexcheck(struct ieee80211_hw *hw,
+ u8 channel, u8 *cckpowerlevel, u8 *ofdmpowerlevel)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ rtlphy->cur_cck_txpwridx = cckpowerlevel[0];
+ rtlphy->cur_ofdm24g_txpwridx = ofdmpowerlevel[0];
+}
+
+void rtl92s_phy_set_txpower(struct ieee80211_hw *hw, u8 channel)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ /* [0]:RF-A, [1]:RF-B */
+ u8 cckpowerlevel[2], ofdmpowerLevel[2];
+
+ if (rtlefuse->txpwr_fromeprom == false)
+ return;
+
+ /* Mainly we use RF-A Tx Power to write the Tx Power registers,
+ * but the RF-B Tx Power must be calculated by the antenna diff.
+ * So we have to rewrite Antenna gain offset register here.
+ * Please refer to BB register 0x80c
+ * 1. For CCK.
+ * 2. For OFDM 1T or 2T */
+ _rtl92s_phy_get_txpower_index(hw, channel, &cckpowerlevel[0],
+ &ofdmpowerLevel[0]);
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("Channel-%d, cckPowerLevel (A / B) = "
+ "0x%x / 0x%x, ofdmPowerLevel (A / B) = 0x%x / 0x%x\n",
+ channel, cckpowerlevel[0], cckpowerlevel[1],
+ ofdmpowerLevel[0], ofdmpowerLevel[1]));
+
+ _rtl92s_phy_ccxpower_indexcheck(hw, channel, &cckpowerlevel[0],
+ &ofdmpowerLevel[0]);
+
+ rtl92s_phy_rf6052_set_ccktxpower(hw, cckpowerlevel[0]);
+ rtl92s_phy_rf6052_set_ofdmtxpower(hw, &ofdmpowerLevel[0], channel);
+
+}
+
+void rtl92s_phy_chk_fwcmd_iodone(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u16 pollingcnt = 10000;
+ u32 tmpvalue;
+
+ /* Make sure that CMD IO has be accepted by FW. */
+ do {
+ udelay(10);
+
+ tmpvalue = rtl_read_dword(rtlpriv, WFM5);
+ if (tmpvalue == 0)
+ break;
+ } while (--pollingcnt);
+
+ if (pollingcnt == 0)
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Set FW Cmd fail!!\n"));
+}
+
+
+static void _rtl92s_phy_set_fwcmd_io(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u32 input, current_aid = 0;
+
+ if (is_hal_stop(rtlhal))
+ return;
+
+ /* We re-map RA related CMD IO to combinational ones */
+ /* if FW version is v.52 or later. */
+ switch (rtlhal->current_fwcmd_io) {
+ case FW_CMD_RA_REFRESH_N:
+ rtlhal->current_fwcmd_io = FW_CMD_RA_REFRESH_N_COMB;
+ break;
+ case FW_CMD_RA_REFRESH_BG:
+ rtlhal->current_fwcmd_io = FW_CMD_RA_REFRESH_BG_COMB;
+ break;
+ default:
+ break;
+ }
+
+ switch (rtlhal->current_fwcmd_io) {
+ case FW_CMD_RA_RESET:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG,
+ ("FW_CMD_RA_RESET\n"));
+ rtl_write_dword(rtlpriv, WFM5, FW_RA_RESET);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ break;
+ case FW_CMD_RA_ACTIVE:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG,
+ ("FW_CMD_RA_ACTIVE\n"));
+ rtl_write_dword(rtlpriv, WFM5, FW_RA_ACTIVE);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ break;
+ case FW_CMD_RA_REFRESH_N:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG,
+ ("FW_CMD_RA_REFRESH_N\n"));
+ input = FW_RA_REFRESH;
+ rtl_write_dword(rtlpriv, WFM5, input);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ rtl_write_dword(rtlpriv, WFM5, FW_RA_ENABLE_RSSI_MASK);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ break;
+ case FW_CMD_RA_REFRESH_BG:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG,
+ ("FW_CMD_RA_REFRESH_BG\n"));
+ rtl_write_dword(rtlpriv, WFM5, FW_RA_REFRESH);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ rtl_write_dword(rtlpriv, WFM5, FW_RA_DISABLE_RSSI_MASK);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ break;
+ case FW_CMD_RA_REFRESH_N_COMB:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG,
+ ("FW_CMD_RA_REFRESH_N_COMB\n"));
+ input = FW_RA_IOT_N_COMB;
+ rtl_write_dword(rtlpriv, WFM5, input);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ break;
+ case FW_CMD_RA_REFRESH_BG_COMB:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG,
+ ("FW_CMD_RA_REFRESH_BG_COMB\n"));
+ input = FW_RA_IOT_BG_COMB;
+ rtl_write_dword(rtlpriv, WFM5, input);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ break;
+ case FW_CMD_IQK_ENABLE:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG,
+ ("FW_CMD_IQK_ENABLE\n"));
+ rtl_write_dword(rtlpriv, WFM5, FW_IQK_ENABLE);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ break;
+ case FW_CMD_PAUSE_DM_BY_SCAN:
+ /* Lower initial gain */
+ rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0, 0x17);
+ rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0, 0x17);
+ /* CCA threshold */
+ rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0x40);
+ break;
+ case FW_CMD_RESUME_DM_BY_SCAN:
+ /* CCA threshold */
+ rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd);
+ rtl92s_phy_set_txpower(hw, rtlphy->current_channel);
+ break;
+ case FW_CMD_HIGH_PWR_DISABLE:
+ if (rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE)
+ break;
+
+ /* Lower initial gain */
+ rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0, 0x17);
+ rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0, 0x17);
+ /* CCA threshold */
+ rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0x40);
+ break;
+ case FW_CMD_HIGH_PWR_ENABLE:
+ if ((rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) ||
+ (rtlpriv->dm.dynamic_txpower_enable == true))
+ break;
+
+ /* CCA threshold */
+ rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd);
+ break;
+ case FW_CMD_LPS_ENTER:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG,
+ ("FW_CMD_LPS_ENTER\n"));
+ current_aid = rtlpriv->mac80211.assoc_id;
+ rtl_write_dword(rtlpriv, WFM5, (FW_LPS_ENTER |
+ ((current_aid | 0xc000) << 8)));
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ /* FW set TXOP disable here, so disable EDCA
+ * turbo mode until driver leave LPS */
+ break;
+ case FW_CMD_LPS_LEAVE:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG,
+ ("FW_CMD_LPS_LEAVE\n"));
+ rtl_write_dword(rtlpriv, WFM5, FW_LPS_LEAVE);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ break;
+ case FW_CMD_ADD_A2_ENTRY:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG,
+ ("FW_CMD_ADD_A2_ENTRY\n"));
+ rtl_write_dword(rtlpriv, WFM5, FW_ADD_A2_ENTRY);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ break;
+ case FW_CMD_CTRL_DM_BY_DRIVER:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ ("FW_CMD_CTRL_DM_BY_DRIVER\n"));
+ rtl_write_dword(rtlpriv, WFM5, FW_CTRL_DM_BY_DRIVER);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ break;
+
+ default:
+ break;
+ }
+
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+
+ /* Clear FW CMD operation flag. */
+ rtlhal->set_fwcmd_inprogress = false;
+}
+
+bool rtl92s_phy_set_fw_cmd(struct ieee80211_hw *hw, enum fwcmd_iotype fw_cmdio)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u32 fw_param = FW_CMD_IO_PARA_QUERY(rtlpriv);
+ u16 fw_cmdmap = FW_CMD_IO_QUERY(rtlpriv);
+ bool bPostProcessing = false;
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ ("Set FW Cmd(%#x), set_fwcmd_inprogress(%d)\n",
+ fw_cmdio, rtlhal->set_fwcmd_inprogress));
+
+ do {
+ /* We re-map to combined FW CMD ones if firmware version */
+ /* is v.53 or later. */
+ switch (fw_cmdio) {
+ case FW_CMD_RA_REFRESH_N:
+ fw_cmdio = FW_CMD_RA_REFRESH_N_COMB;
+ break;
+ case FW_CMD_RA_REFRESH_BG:
+ fw_cmdio = FW_CMD_RA_REFRESH_BG_COMB;
+ break;
+ default:
+ break;
+ }
+
+ /* If firmware version is v.62 or later,
+ * use FW_CMD_IO_SET for FW_CMD_CTRL_DM_BY_DRIVER */
+ if (hal_get_firmwareversion(rtlpriv) >= 0x3E) {
+ if (fw_cmdio == FW_CMD_CTRL_DM_BY_DRIVER)
+ fw_cmdio = FW_CMD_CTRL_DM_BY_DRIVER_NEW;
+ }
+
+
+ /* We shall revise all FW Cmd IO into Reg0x364
+ * DM map table in the future. */
+ switch (fw_cmdio) {
+ case FW_CMD_RA_INIT:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("RA init!!\n"));
+ fw_cmdmap |= FW_RA_INIT_CTL;
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ /* Clear control flag to sync with FW. */
+ FW_CMD_IO_CLR(rtlpriv, FW_RA_INIT_CTL);
+ break;
+ case FW_CMD_DIG_DISABLE:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ ("Set DIG disable!!\n"));
+ fw_cmdmap &= ~FW_DIG_ENABLE_CTL;
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ break;
+ case FW_CMD_DIG_ENABLE:
+ case FW_CMD_DIG_RESUME:
+ if (!(rtlpriv->dm.dm_flag & HAL_DM_DIG_DISABLE)) {
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ ("Set DIG enable or resume!!\n"));
+ fw_cmdmap |= (FW_DIG_ENABLE_CTL | FW_SS_CTL);
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ }
+ break;
+ case FW_CMD_DIG_HALT:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ ("Set DIG halt!!\n"));
+ fw_cmdmap &= ~(FW_DIG_ENABLE_CTL | FW_SS_CTL);
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ break;
+ case FW_CMD_TXPWR_TRACK_THERMAL: {
+ u8 thermalval = 0;
+ fw_cmdmap |= FW_PWR_TRK_CTL;
+
+ /* Clear FW parameter in terms of thermal parts. */
+ fw_param &= FW_PWR_TRK_PARAM_CLR;
+
+ thermalval = rtlpriv->dm.thermalvalue;
+ fw_param |= ((thermalval << 24) |
+ (rtlefuse->thermalmeter[0] << 16));
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ ("Set TxPwr tracking!! "
+ "FwCmdMap(%#x), FwParam(%#x)\n",
+ fw_cmdmap, fw_param));
+
+ FW_CMD_PARA_SET(rtlpriv, fw_param);
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+
+ /* Clear control flag to sync with FW. */
+ FW_CMD_IO_CLR(rtlpriv, FW_PWR_TRK_CTL);
+ }
+ break;
+ /* The following FW CMDs are only compatible to
+ * v.53 or later. */
+ case FW_CMD_RA_REFRESH_N_COMB:
+ fw_cmdmap |= FW_RA_N_CTL;
+
+ /* Clear RA BG mode control. */
+ fw_cmdmap &= ~(FW_RA_BG_CTL | FW_RA_INIT_CTL);
+
+ /* Clear FW parameter in terms of RA parts. */
+ fw_param &= FW_RA_PARAM_CLR;
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ ("[FW CMD] [New Version] "
+ "Set RA/IOT Comb in n mode!! FwCmdMap(%#x), "
+ "FwParam(%#x)\n", fw_cmdmap, fw_param));
+
+ FW_CMD_PARA_SET(rtlpriv, fw_param);
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+
+ /* Clear control flag to sync with FW. */
+ FW_CMD_IO_CLR(rtlpriv, FW_RA_N_CTL);
+ break;
+ case FW_CMD_RA_REFRESH_BG_COMB:
+ fw_cmdmap |= FW_RA_BG_CTL;
+
+ /* Clear RA n-mode control. */
+ fw_cmdmap &= ~(FW_RA_N_CTL | FW_RA_INIT_CTL);
+ /* Clear FW parameter in terms of RA parts. */
+ fw_param &= FW_RA_PARAM_CLR;
+
+ FW_CMD_PARA_SET(rtlpriv, fw_param);
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+
+ /* Clear control flag to sync with FW. */
+ FW_CMD_IO_CLR(rtlpriv, FW_RA_BG_CTL);
+ break;
+ case FW_CMD_IQK_ENABLE:
+ fw_cmdmap |= FW_IQK_CTL;
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ /* Clear control flag to sync with FW. */
+ FW_CMD_IO_CLR(rtlpriv, FW_IQK_CTL);
+ break;
+ /* The following FW CMD is compatible to v.62 or later. */
+ case FW_CMD_CTRL_DM_BY_DRIVER_NEW:
+ fw_cmdmap |= FW_DRIVER_CTRL_DM_CTL;
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ break;
+ /* The followed FW Cmds needs post-processing later. */
+ case FW_CMD_RESUME_DM_BY_SCAN:
+ fw_cmdmap |= (FW_DIG_ENABLE_CTL |
+ FW_HIGH_PWR_ENABLE_CTL |
+ FW_SS_CTL);
+
+ if (rtlpriv->dm.dm_flag & HAL_DM_DIG_DISABLE ||
+ !digtable.dig_enable_flag)
+ fw_cmdmap &= ~FW_DIG_ENABLE_CTL;
+
+ if ((rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) ||
+ (rtlpriv->dm.dynamic_txpower_enable == true))
+ fw_cmdmap &= ~FW_HIGH_PWR_ENABLE_CTL;
+
+ if ((digtable.dig_ext_port_stage ==
+ DIG_EXT_PORT_STAGE_0) ||
+ (digtable.dig_ext_port_stage ==
+ DIG_EXT_PORT_STAGE_1))
+ fw_cmdmap &= ~FW_DIG_ENABLE_CTL;
+
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ bPostProcessing = true;
+ break;
+ case FW_CMD_PAUSE_DM_BY_SCAN:
+ fw_cmdmap &= ~(FW_DIG_ENABLE_CTL |
+ FW_HIGH_PWR_ENABLE_CTL |
+ FW_SS_CTL);
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ bPostProcessing = true;
+ break;
+ case FW_CMD_HIGH_PWR_DISABLE:
+ fw_cmdmap &= ~FW_HIGH_PWR_ENABLE_CTL;
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ bPostProcessing = true;
+ break;
+ case FW_CMD_HIGH_PWR_ENABLE:
+ if (!(rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) &&
+ (rtlpriv->dm.dynamic_txpower_enable != true)) {
+ fw_cmdmap |= (FW_HIGH_PWR_ENABLE_CTL |
+ FW_SS_CTL);
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ bPostProcessing = true;
+ }
+ break;
+ case FW_CMD_DIG_MODE_FA:
+ fw_cmdmap |= FW_FA_CTL;
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ break;
+ case FW_CMD_DIG_MODE_SS:
+ fw_cmdmap &= ~FW_FA_CTL;
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ break;
+ case FW_CMD_PAPE_CONTROL:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ ("[FW CMD] Set PAPE Control\n"));
+ fw_cmdmap &= ~FW_PAPE_CTL_BY_SW_HW;
+
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ break;
+ default:
+ /* Pass to original FW CMD processing callback
+ * routine. */
+ bPostProcessing = true;
+ break;
+ }
+ } while (false);
+
+ /* We shall post processing these FW CMD if
+ * variable bPostProcessing is set. */
+ if (bPostProcessing && !rtlhal->set_fwcmd_inprogress) {
+ rtlhal->set_fwcmd_inprogress = true;
+ /* Update current FW Cmd for callback use. */
+ rtlhal->current_fwcmd_io = fw_cmdio;
+ } else {
+ return false;
+ }
+
+ _rtl92s_phy_set_fwcmd_io(hw);
+ return true;
+}
+
+static void _rtl92s_phy_check_ephy_switchready(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 delay = 100;
+ u8 regu1;
+
+ regu1 = rtl_read_byte(rtlpriv, 0x554);
+ while ((regu1 & BIT(5)) && (delay > 0)) {
+ regu1 = rtl_read_byte(rtlpriv, 0x554);
+ delay--;
+ /* We delay only 50us to prevent
+ * being scheduled out. */
+ udelay(50);
+ }
+}
+
+void rtl92s_phy_switch_ephy_parameter(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+ /* The way to be capable to switch clock request
+ * when the PG setting does not support clock request.
+ * This is the backdoor solution to switch clock
+ * request before ASPM or D3. */
+ rtl_write_dword(rtlpriv, 0x540, 0x73c11);
+ rtl_write_dword(rtlpriv, 0x548, 0x2407c);
+
+ /* Switch EPHY parameter!!!! */
+ rtl_write_word(rtlpriv, 0x550, 0x1000);
+ rtl_write_byte(rtlpriv, 0x554, 0x20);
+ _rtl92s_phy_check_ephy_switchready(hw);
+
+ rtl_write_word(rtlpriv, 0x550, 0xa0eb);
+ rtl_write_byte(rtlpriv, 0x554, 0x3e);
+ _rtl92s_phy_check_ephy_switchready(hw);
+
+ rtl_write_word(rtlpriv, 0x550, 0xff80);
+ rtl_write_byte(rtlpriv, 0x554, 0x39);
+ _rtl92s_phy_check_ephy_switchready(hw);
+
+ /* Delay L1 enter time */
+ if (ppsc->support_aspm && !ppsc->support_backdoor)
+ rtl_write_byte(rtlpriv, 0x560, 0x40);
+ else
+ rtl_write_byte(rtlpriv, 0x560, 0x00);
+
+}
+
+void rtl92s_phy_set_beacon_hwreg(struct ieee80211_hw *hw, u16 BeaconInterval)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ rtl_write_dword(rtlpriv, WFM5, 0xF1000000 | (BeaconInterval << 8));
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.h b/drivers/net/wireless/rtlwifi/rtl8192se/phy.h
new file mode 100644
index 000000000000..37e504af6446
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.h
@@ -0,0 +1,101 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#ifndef __RTL92S_PHY_H__
+#define __RTL92S_PHY_H__
+
+#define MAX_TXPWR_IDX_NMODE_92S 63
+#define MAX_DOZE_WAITING_TIMES_9x 64
+
+/* 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 RF90_PATH_MAX 4
+
+enum version_8192s {
+ VERSION_8192S_ACUT,
+ VERSION_8192S_BCUT,
+ VERSION_8192S_CCUT
+};
+
+enum swchnlcmd_id {
+ CMDID_END,
+ CMDID_SET_TXPOWEROWER_LEVEL,
+ CMDID_BBREGWRITE10,
+ CMDID_WRITEPORT_ULONG,
+ CMDID_WRITEPORT_USHORT,
+ CMDID_WRITEPORT_UCHAR,
+ CMDID_RF_WRITEREG,
+};
+
+struct swchnlcmd {
+ enum swchnlcmd_id cmdid;
+ u32 para1;
+ u32 para2;
+ u32 msdelay;
+};
+
+enum baseband_config_type {
+ /* Radio Path A */
+ BASEBAND_CONFIG_PHY_REG = 0,
+ /* Radio Path B */
+ BASEBAND_CONFIG_AGC_TAB = 1,
+};
+
+#define hal_get_firmwareversion(rtlpriv) \
+ (((struct rt_firmware *)(rtlpriv->rtlhal.pfirmware))->firmwareversion)
+
+u32 rtl92s_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask);
+void rtl92s_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask,
+ u32 data);
+void rtl92s_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation);
+u32 rtl92s_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath,
+ u32 regaddr, u32 bitmask);
+void rtl92s_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath,
+ u32 regaddr, u32 bitmask, u32 data);
+void rtl92s_phy_set_bw_mode(struct ieee80211_hw *hw,
+ enum nl80211_channel_type ch_type);
+u8 rtl92s_phy_sw_chnl(struct ieee80211_hw *hw);
+bool rtl92s_phy_set_rf_power_state(struct ieee80211_hw *hw,
+ enum rf_pwrstate rfpower_state);
+bool rtl92s_phy_mac_config(struct ieee80211_hw *hw);
+void rtl92s_phy_switch_ephy_parameter(struct ieee80211_hw *hw);
+bool rtl92s_phy_bb_config(struct ieee80211_hw *hw);
+bool rtl92s_phy_rf_config(struct ieee80211_hw *hw);
+void rtl92s_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw);
+void rtl92s_phy_set_txpower(struct ieee80211_hw *hw, u8 channel);
+bool rtl92s_phy_set_fw_cmd(struct ieee80211_hw *hw, enum fwcmd_iotype fwcmd_io);
+void rtl92s_phy_chk_fwcmd_iodone(struct ieee80211_hw *hw);
+void rtl92s_phy_set_beacon_hwreg(struct ieee80211_hw *hw, u16 beaconinterval);
+u8 rtl92s_phy_config_rf(struct ieee80211_hw *hw, enum radio_path rfpath) ;
+
+#endif
+
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/reg.h b/drivers/net/wireless/rtlwifi/rtl8192se/reg.h
new file mode 100644
index 000000000000..0116eaddbfac
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/reg.h
@@ -0,0 +1,1188 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#ifndef __REALTEK_92S_REG_H__
+#define __REALTEK_92S_REG_H__
+
+/* 1. System Configuration Registers */
+#define REG_SYS_ISO_CTRL 0x0000
+#define REG_SYS_FUNC_EN 0x0002
+#define PMC_FSM 0x0004
+#define SYS_CLKR 0x0008
+#define EPROM_CMD 0x000A
+#define EE_VPD 0x000C
+#define AFE_MISC 0x0010
+#define SPS0_CTRL 0x0011
+#define SPS1_CTRL 0x0018
+#define RF_CTRL 0x001F
+#define LDOA15_CTRL 0x0020
+#define LDOV12D_CTRL 0x0021
+#define LDOHCI12_CTRL 0x0022
+#define LDO_USB_SDIO 0x0023
+#define LPLDO_CTRL 0x0024
+#define AFE_XTAL_CTRL 0x0026
+#define AFE_PLL_CTRL 0x0028
+#define REG_EFUSE_CTRL 0x0030
+#define REG_EFUSE_TEST 0x0034
+#define PWR_DATA 0x0038
+#define DBG_PORT 0x003A
+#define DPS_TIMER 0x003C
+#define RCLK_MON 0x003E
+
+/* 2. Command Control Registers */
+#define CMDR 0x0040
+#define TXPAUSE 0x0042
+#define LBKMD_SEL 0x0043
+#define TCR 0x0044
+#define RCR 0x0048
+#define MSR 0x004C
+#define SYSF_CFG 0x004D
+#define RX_PKY_LIMIT 0x004E
+#define MBIDCTRL 0x004F
+
+/* 3. MACID Setting Registers */
+#define MACIDR 0x0050
+#define MACIDR0 0x0050
+#define MACIDR4 0x0054
+#define BSSIDR 0x0058
+#define HWVID 0x005E
+#define MAR 0x0060
+#define MBIDCAMCONTENT 0x0068
+#define MBIDCAMCFG 0x0070
+#define BUILDTIME 0x0074
+#define BUILDUSER 0x0078
+
+#define IDR0 MACIDR0
+#define IDR4 MACIDR4
+
+/* 4. Timing Control Registers */
+#define TSFR 0x0080
+#define SLOT_TIME 0x0089
+#define USTIME 0x008A
+#define SIFS_CCK 0x008C
+#define SIFS_OFDM 0x008E
+#define PIFS_TIME 0x0090
+#define ACK_TIMEOUT 0x0091
+#define EIFSTR 0x0092
+#define BCN_INTERVAL 0x0094
+#define ATIMWND 0x0096
+#define BCN_DRV_EARLY_INT 0x0098
+#define BCN_DMATIME 0x009A
+#define BCN_ERR_THRESH 0x009C
+#define MLT 0x009D
+#define RSVD_MAC_TUNE_US 0x009E
+
+/* 5. FIFO Control Registers */
+#define RQPN 0x00A0
+#define RQPN1 0x00A0
+#define RQPN2 0x00A1
+#define RQPN3 0x00A2
+#define RQPN4 0x00A3
+#define RQPN5 0x00A4
+#define RQPN6 0x00A5
+#define RQPN7 0x00A6
+#define RQPN8 0x00A7
+#define RQPN9 0x00A8
+#define RQPN10 0x00A9
+#define LD_RQPN 0x00AB
+#define RXFF_BNDY 0x00AC
+#define RXRPT_BNDY 0x00B0
+#define TXPKTBUF_PGBNDY 0x00B4
+#define PBP 0x00B5
+#define RXDRVINFO_SZ 0x00B6
+#define TXFF_STATUS 0x00B7
+#define RXFF_STATUS 0x00B8
+#define TXFF_EMPTY_TH 0x00B9
+#define SDIO_RX_BLKSZ 0x00BC
+#define RXDMA 0x00BD
+#define RXPKT_NUM 0x00BE
+#define C2HCMD_UDT_SIZE 0x00C0
+#define C2HCMD_UDT_ADDR 0x00C2
+#define FIFOPAGE1 0x00C4
+#define FIFOPAGE2 0x00C8
+#define FIFOPAGE3 0x00CC
+#define FIFOPAGE4 0x00D0
+#define FIFOPAGE5 0x00D4
+#define FW_RSVD_PG_CRTL 0x00D8
+#define RXDMA_AGG_PG_TH 0x00D9
+#define TXDESC_MSK 0x00DC
+#define TXRPTFF_RDPTR 0x00E0
+#define TXRPTFF_WTPTR 0x00E4
+#define C2HFF_RDPTR 0x00E8
+#define C2HFF_WTPTR 0x00EC
+#define RXFF0_RDPTR 0x00F0
+#define RXFF0_WTPTR 0x00F4
+#define RXFF1_RDPTR 0x00F8
+#define RXFF1_WTPTR 0x00FC
+#define RXRPT0_RDPTR 0x0100
+#define RXRPT0_WTPTR 0x0104
+#define RXRPT1_RDPTR 0x0108
+#define RXRPT1_WTPTR 0x010C
+#define RX0_UDT_SIZE 0x0110
+#define RX1PKTNUM 0x0114
+#define RXFILTERMAP 0x0116
+#define RXFILTERMAP_GP1 0x0118
+#define RXFILTERMAP_GP2 0x011A
+#define RXFILTERMAP_GP3 0x011C
+#define BCNQ_CTRL 0x0120
+#define MGTQ_CTRL 0x0124
+#define HIQ_CTRL 0x0128
+#define VOTID7_CTRL 0x012c
+#define VOTID6_CTRL 0x0130
+#define VITID5_CTRL 0x0134
+#define VITID4_CTRL 0x0138
+#define BETID3_CTRL 0x013c
+#define BETID0_CTRL 0x0140
+#define BKTID2_CTRL 0x0144
+#define BKTID1_CTRL 0x0148
+#define CMDQ_CTRL 0x014c
+#define TXPKT_NUM_CTRL 0x0150
+#define TXQ_PGADD 0x0152
+#define TXFF_PG_NUM 0x0154
+#define TRXDMA_STATUS 0x0156
+
+/* 6. Adaptive Control Registers */
+#define INIMCS_SEL 0x0160
+#define TX_RATE_REG INIMCS_SEL
+#define INIRTSMCS_SEL 0x0180
+#define RRSR 0x0181
+#define ARFR0 0x0184
+#define ARFR1 0x0188
+#define ARFR2 0x018C
+#define ARFR3 0x0190
+#define ARFR4 0x0194
+#define ARFR5 0x0198
+#define ARFR6 0x019C
+#define ARFR7 0x01A0
+#define AGGLEN_LMT_H 0x01A7
+#define AGGLEN_LMT_L 0x01A8
+#define DARFRC 0x01B0
+#define RARFRC 0x01B8
+#define MCS_TXAGC 0x01C0
+#define CCK_TXAGC 0x01C8
+
+/* 7. EDCA Setting Registers */
+#define EDCAPARA_VO 0x01D0
+#define EDCAPARA_VI 0x01D4
+#define EDCAPARA_BE 0x01D8
+#define EDCAPARA_BK 0x01DC
+#define BCNTCFG 0x01E0
+#define CWRR 0x01E2
+#define ACMAVG 0x01E4
+#define AcmHwCtrl 0x01E7
+#define VO_ADMTM 0x01E8
+#define VI_ADMTM 0x01EC
+#define BE_ADMTM 0x01F0
+#define RETRY_LIMIT 0x01F4
+#define SG_RATE 0x01F6
+
+/* 8. WMAC, BA and CCX related Register. */
+#define NAV_CTRL 0x0200
+#define BW_OPMODE 0x0203
+#define BACAMCMD 0x0204
+#define BACAMCONTENT 0x0208
+
+/* the 0x2xx register WMAC definition */
+#define LBDLY 0x0210
+#define FWDLY 0x0211
+#define HWPC_RX_CTRL 0x0218
+#define MQIR 0x0220
+#define MAIR 0x0222
+#define MSIR 0x0224
+#define CLM_RESULT 0x0227
+#define NHM_RPI_CNT 0x0228
+#define RXERR_RPT 0x0230
+#define NAV_PROT_LEN 0x0234
+#define CFEND_TH 0x0236
+#define AMPDU_MIN_SPACE 0x0237
+#define TXOP_STALL_CTRL 0x0238
+
+/* 9. Security Control Registers */
+#define REG_RWCAM 0x0240
+#define REG_WCAMI 0x0244
+#define REG_RCAMO 0x0248
+#define REG_CAMDBG 0x024C
+#define REG_SECR 0x0250
+
+/* 10. Power Save Control Registers */
+#define WOW_CTRL 0x0260
+#define PSSTATUS 0x0261
+#define PSSWITCH 0x0262
+#define MIMOPS_WAIT_PERIOD 0x0263
+#define LPNAV_CTRL 0x0264
+#define WFM0 0x0270
+#define WFM1 0x0280
+#define WFM2 0x0290
+#define WFM3 0x02A0
+#define WFM4 0x02B0
+#define WFM5 0x02C0
+#define WFCRC 0x02D0
+#define FW_RPT_REG 0x02c4
+
+/* 11. General Purpose Registers */
+#define PSTIME 0x02E0
+#define TIMER0 0x02E4
+#define TIMER1 0x02E8
+#define GPIO_CTRL 0x02EC
+#define GPIO_IN 0x02EC
+#define GPIO_OUT 0x02ED
+#define GPIO_IO_SEL 0x02EE
+#define GPIO_MOD 0x02EF
+#define GPIO_INTCTRL 0x02F0
+#define MAC_PINMUX_CFG 0x02F1
+#define LEDCFG 0x02F2
+#define PHY_REG 0x02F3
+#define PHY_REG_DATA 0x02F4
+#define REG_EFUSE_CLK 0x02F8
+
+/* 12. Host Interrupt Status Registers */
+#define INTA_MASK 0x0300
+#define ISR 0x0308
+
+/* 13. Test Mode and Debug Control Registers */
+#define DBG_PORT_SWITCH 0x003A
+#define BIST 0x0310
+#define DBS 0x0314
+#define CPUINST 0x0318
+#define CPUCAUSE 0x031C
+#define LBUS_ERR_ADDR 0x0320
+#define LBUS_ERR_CMD 0x0324
+#define LBUS_ERR_DATA_L 0x0328
+#define LBUS_ERR_DATA_H 0x032C
+#define LX_EXCEPTION_ADDR 0x0330
+#define WDG_CTRL 0x0334
+#define INTMTU 0x0338
+#define INTM 0x033A
+#define FDLOCKTURN0 0x033C
+#define FDLOCKTURN1 0x033D
+#define TRXPKTBUF_DBG_DATA 0x0340
+#define TRXPKTBUF_DBG_CTRL 0x0348
+#define DPLL 0x034A
+#define CBUS_ERR_ADDR 0x0350
+#define CBUS_ERR_CMD 0x0354
+#define CBUS_ERR_DATA_L 0x0358
+#define CBUS_ERR_DATA_H 0x035C
+#define USB_SIE_INTF_ADDR 0x0360
+#define USB_SIE_INTF_WD 0x0361
+#define USB_SIE_INTF_RD 0x0362
+#define USB_SIE_INTF_CTRL 0x0363
+#define LBUS_MON_ADDR 0x0364
+#define LBUS_ADDR_MASK 0x0368
+
+/* Boundary is 0x37F */
+
+/* 14. PCIE config register */
+#define TP_POLL 0x0500
+#define PM_CTRL 0x0502
+#define PCIF 0x0503
+
+#define THPDA 0x0514
+#define TMDA 0x0518
+#define TCDA 0x051C
+#define HDA 0x0520
+#define TVODA 0x0524
+#define TVIDA 0x0528
+#define TBEDA 0x052C
+#define TBKDA 0x0530
+#define TBDA 0x0534
+#define RCDA 0x0538
+#define RDQDA 0x053C
+#define DBI_WDATA 0x0540
+#define DBI_RDATA 0x0544
+#define DBI_CTRL 0x0548
+#define MDIO_DATA 0x0550
+#define MDIO_CTRL 0x0554
+#define PCI_RPWM 0x0561
+#define PCI_CPWM 0x0563
+
+/* Config register (Offset 0x800-) */
+#define PHY_CCA 0x803
+
+/* Min Spacing related settings. */
+#define MAX_MSS_DENSITY_2T 0x13
+#define MAX_MSS_DENSITY_1T 0x0A
+
+/* Rx DMA Control related settings */
+#define RXDMA_AGG_EN BIT(7)
+
+#define RPWM PCI_RPWM
+
+/* Regsiter Bit and Content definition */
+
+#define ISO_MD2PP BIT(0)
+#define ISO_PA2PCIE BIT(3)
+#define ISO_PLL2MD BIT(4)
+#define ISO_PWC_DV2RP BIT(11)
+#define ISO_PWC_RV2RP BIT(12)
+
+
+#define FEN_MREGEN BIT(15)
+#define FEN_DCORE BIT(11)
+#define FEN_CPUEN BIT(10)
+
+#define PAD_HWPD_IDN BIT(22)
+
+#define SYS_CLKSEL_80M BIT(0)
+#define SYS_PS_CLKSEL BIT(1)
+#define SYS_CPU_CLKSEL BIT(2)
+#define SYS_MAC_CLK_EN BIT(11)
+#define SYS_SWHW_SEL BIT(14)
+#define SYS_FWHW_SEL BIT(15)
+
+#define CmdEEPROM_En BIT(5)
+#define CmdEERPOMSEL BIT(4)
+#define Cmd9346CR_9356SEL BIT(4)
+
+#define AFE_MBEN BIT(1)
+#define AFE_BGEN BIT(0)
+
+#define SPS1_SWEN BIT(1)
+#define SPS1_LDEN BIT(0)
+
+#define RF_EN BIT(0)
+#define RF_RSTB BIT(1)
+#define RF_SDMRSTB BIT(2)
+
+#define LDA15_EN BIT(0)
+
+#define LDV12_EN BIT(0)
+#define LDV12_SDBY BIT(1)
+
+#define XTAL_GATE_AFE BIT(10)
+
+#define APLL_EN BIT(0)
+
+#define AFR_CardBEn BIT(0)
+#define AFR_CLKRUN_SEL BIT(1)
+#define AFR_FuncRegEn BIT(2)
+
+#define APSDOFF_STATUS BIT(15)
+#define APSDOFF BIT(14)
+#define BBRSTN BIT(13)
+#define BB_GLB_RSTN BIT(12)
+#define SCHEDULE_EN BIT(10)
+#define MACRXEN BIT(9)
+#define MACTXEN BIT(8)
+#define DDMA_EN BIT(7)
+#define FW2HW_EN BIT(6)
+#define RXDMA_EN BIT(5)
+#define TXDMA_EN BIT(4)
+#define HCI_RXDMA_EN BIT(3)
+#define HCI_TXDMA_EN BIT(2)
+
+#define StopHCCA BIT(6)
+#define StopHigh BIT(5)
+#define StopMgt BIT(4)
+#define StopVO BIT(3)
+#define StopVI BIT(2)
+#define StopBE BIT(1)
+#define StopBK BIT(0)
+
+#define LBK_NORMAL 0x00
+#define LBK_MAC_LB (BIT(0) | BIT(1) | BIT(3))
+#define LBK_MAC_DLB (BIT(0) | BIT(1))
+#define LBK_DMA_LB (BIT(0) | BIT(1) | BIT(2))
+
+#define TCP_OFDL_EN BIT(25)
+#define HWPC_TX_EN BIT(24)
+#define TXDMAPRE2FULL BIT(23)
+#define DISCW BIT(20)
+#define TCRICV BIT(19)
+#define CfendForm BIT(17)
+#define TCRCRC BIT(16)
+#define FAKE_IMEM_EN BIT(15)
+#define TSFRST BIT(9)
+#define TSFEN BIT(8)
+#define FWALLRDY (BIT(0) | BIT(1) | BIT(2) | \
+ BIT(3) | BIT(4) | BIT(5) | \
+ BIT(6) | BIT(7))
+#define FWRDY BIT(7)
+#define BASECHG BIT(6)
+#define IMEM BIT(5)
+#define DMEM_CODE_DONE BIT(4)
+#define EXT_IMEM_CHK_RPT BIT(3)
+#define EXT_IMEM_CODE_DONE BIT(2)
+#define IMEM_CHK_RPT BIT(1)
+#define IMEM_CODE_DONE BIT(0)
+#define IMEM_CODE_DONE BIT(0)
+#define IMEM_CHK_RPT BIT(1)
+#define EMEM_CODE_DONE BIT(2)
+#define EMEM_CHK_RPT BIT(3)
+#define DMEM_CODE_DONE BIT(4)
+#define IMEM_RDY BIT(5)
+#define BASECHG BIT(6)
+#define FWRDY BIT(7)
+#define LOAD_FW_READY (IMEM_CODE_DONE | \
+ IMEM_CHK_RPT | \
+ EMEM_CODE_DONE | \
+ EMEM_CHK_RPT | \
+ DMEM_CODE_DONE | \
+ IMEM_RDY | \
+ BASECHG | \
+ FWRDY)
+#define TCR_TSFEN BIT(8)
+#define TCR_TSFRST BIT(9)
+#define TCR_FAKE_IMEM_EN BIT(15)
+#define TCR_CRC BIT(16)
+#define TCR_ICV BIT(19)
+#define TCR_DISCW BIT(20)
+#define TCR_HWPC_TX_EN BIT(24)
+#define TCR_TCP_OFDL_EN BIT(25)
+#define TXDMA_INIT_VALUE (IMEM_CHK_RPT | \
+ EXT_IMEM_CHK_RPT)
+
+#define RCR_APPFCS BIT(31)
+#define RCR_DIS_ENC_2BYTE BIT(30)
+#define RCR_DIS_AES_2BYTE BIT(29)
+#define RCR_HTC_LOC_CTRL BIT(28)
+#define RCR_ENMBID BIT(27)
+#define RCR_RX_TCPOFDL_EN BIT(26)
+#define RCR_APP_PHYST_RXFF BIT(25)
+#define RCR_APP_PHYST_STAFF BIT(24)
+#define RCR_CBSSID BIT(23)
+#define RCR_APWRMGT BIT(22)
+#define RCR_ADD3 BIT(21)
+#define RCR_AMF BIT(20)
+#define RCR_ACF BIT(19)
+#define RCR_ADF BIT(18)
+#define RCR_APP_MIC BIT(17)
+#define RCR_APP_ICV BIT(16)
+#define RCR_RXFTH BIT(13)
+#define RCR_AICV BIT(12)
+#define RCR_RXDESC_LK_EN BIT(11)
+#define RCR_APP_BA_SSN BIT(6)
+#define RCR_ACRC32 BIT(5)
+#define RCR_RXSHFT_EN BIT(4)
+#define RCR_AB BIT(3)
+#define RCR_AM BIT(2)
+#define RCR_APM BIT(1)
+#define RCR_AAP BIT(0)
+#define RCR_MXDMA_OFFSET 8
+#define RCR_FIFO_OFFSET 13
+
+
+#define MSR_LINK_MASK ((1 << 0) | (1 << 1))
+#define MSR_LINK_MANAGED 2
+#define MSR_LINK_NONE 0
+#define MSR_LINK_SHIFT 0
+#define MSR_LINK_ADHOC 1
+#define MSR_LINK_MASTER 3
+#define MSR_NOLINK 0x00
+#define MSR_ADHOC 0x01
+#define MSR_INFRA 0x02
+#define MSR_AP 0x03
+
+#define ENUART BIT(7)
+#define ENJTAG BIT(3)
+#define BTMODE (BIT(2) | BIT(1))
+#define ENBT BIT(0)
+
+#define ENMBID BIT(7)
+#define BCNUM (BIT(6) | BIT(5) | BIT(4))
+
+#define USTIME_EDCA 0xFF00
+#define USTIME_TSF 0x00FF
+
+#define SIFS_TRX 0xFF00
+#define SIFS_CTX 0x00FF
+
+#define ENSWBCN BIT(15)
+#define DRVERLY_TU 0x0FF0
+#define DRVERLY_US 0x000F
+#define BCN_TCFG_CW_SHIFT 8
+#define BCN_TCFG_IFS 0
+
+#define RRSR_RSC_OFFSET 21
+#define RRSR_SHORT_OFFSET 23
+#define RRSR_RSC_BW_40M 0x600000
+#define RRSR_RSC_UPSUBCHNL 0x400000
+#define RRSR_RSC_LOWSUBCHNL 0x200000
+#define RRSR_SHORT 0x800000
+#define RRSR_1M BIT(0)
+#define RRSR_2M BIT(1)
+#define RRSR_5_5M BIT(2)
+#define RRSR_11M BIT(3)
+#define RRSR_6M BIT(4)
+#define RRSR_9M BIT(5)
+#define RRSR_12M BIT(6)
+#define RRSR_18M BIT(7)
+#define RRSR_24M BIT(8)
+#define RRSR_36M BIT(9)
+#define RRSR_48M BIT(10)
+#define RRSR_54M BIT(11)
+#define RRSR_MCS0 BIT(12)
+#define RRSR_MCS1 BIT(13)
+#define RRSR_MCS2 BIT(14)
+#define RRSR_MCS3 BIT(15)
+#define RRSR_MCS4 BIT(16)
+#define RRSR_MCS5 BIT(17)
+#define RRSR_MCS6 BIT(18)
+#define RRSR_MCS7 BIT(19)
+#define BRSR_AckShortPmb BIT(23)
+
+#define RATR_1M 0x00000001
+#define RATR_2M 0x00000002
+#define RATR_55M 0x00000004
+#define RATR_11M 0x00000008
+#define RATR_6M 0x00000010
+#define RATR_9M 0x00000020
+#define RATR_12M 0x00000040
+#define RATR_18M 0x00000080
+#define RATR_24M 0x00000100
+#define RATR_36M 0x00000200
+#define RATR_48M 0x00000400
+#define RATR_54M 0x00000800
+#define RATR_MCS0 0x00001000
+#define RATR_MCS1 0x00002000
+#define RATR_MCS2 0x00004000
+#define RATR_MCS3 0x00008000
+#define RATR_MCS4 0x00010000
+#define RATR_MCS5 0x00020000
+#define RATR_MCS6 0x00040000
+#define RATR_MCS7 0x00080000
+#define RATR_MCS8 0x00100000
+#define RATR_MCS9 0x00200000
+#define RATR_MCS10 0x00400000
+#define RATR_MCS11 0x00800000
+#define RATR_MCS12 0x01000000
+#define RATR_MCS13 0x02000000
+#define RATR_MCS14 0x04000000
+#define RATR_MCS15 0x08000000
+
+#define RATE_ALL_CCK (RATR_1M | RATR_2M | \
+ RATR_55M | RATR_11M)
+#define RATE_ALL_OFDM_AG (RATR_6M | RATR_9M | \
+ RATR_12M | RATR_18M | \
+ RATR_24M | RATR_36M | \
+ RATR_48M | RATR_54M)
+#define RATE_ALL_OFDM_1SS (RATR_MCS0 | RATR_MCS1 | \
+ RATR_MCS2 | RATR_MCS3 | \
+ RATR_MCS4 | RATR_MCS5 | \
+ RATR_MCS6 | RATR_MCS7)
+#define RATE_ALL_OFDM_2SS (RATR_MCS8 | RATR_MCS9 | \
+ RATR_MCS10 | RATR_MCS11 | \
+ RATR_MCS12 | RATR_MCS13 | \
+ RATR_MCS14 | RATR_MCS15)
+
+#define AC_PARAM_TXOP_LIMIT_OFFSET 16
+#define AC_PARAM_ECW_MAX_OFFSET 12
+#define AC_PARAM_ECW_MIN_OFFSET 8
+#define AC_PARAM_AIFS_OFFSET 0
+
+#define AcmHw_HwEn BIT(0)
+#define AcmHw_BeqEn BIT(1)
+#define AcmHw_ViqEn BIT(2)
+#define AcmHw_VoqEn BIT(3)
+#define AcmHw_BeqStatus BIT(4)
+#define AcmHw_ViqStatus BIT(5)
+#define AcmHw_VoqStatus BIT(6)
+
+#define RETRY_LIMIT_SHORT_SHIFT 8
+#define RETRY_LIMIT_LONG_SHIFT 0
+
+#define NAV_UPPER_EN BIT(16)
+#define NAV_UPPER 0xFF00
+#define NAV_RTSRST 0xFF
+
+#define BW_OPMODE_20MHZ BIT(2)
+#define BW_OPMODE_5G BIT(1)
+#define BW_OPMODE_11J BIT(0)
+
+#define RXERR_RPT_RST BIT(27)
+#define RXERR_OFDM_PPDU 0
+#define RXERR_OFDM_FALSE_ALARM 1
+#define RXERR_OFDM_MPDU_OK 2
+#define RXERR_OFDM_MPDU_FAIL 3
+#define RXERR_CCK_PPDU 4
+#define RXERR_CCK_FALSE_ALARM 5
+#define RXERR_CCK_MPDU_OK 6
+#define RXERR_CCK_MPDU_FAIL 7
+#define RXERR_HT_PPDU 8
+#define RXERR_HT_FALSE_ALARM 9
+#define RXERR_HT_MPDU_TOTAL 10
+#define RXERR_HT_MPDU_OK 11
+#define RXERR_HT_MPDU_FAIL 12
+#define RXERR_RX_FULL_DROP 15
+
+#define SCR_TXUSEDK BIT(0)
+#define SCR_RXUSEDK BIT(1)
+#define SCR_TXENCENABLE BIT(2)
+#define SCR_RXENCENABLE BIT(3)
+#define SCR_SKBYA2 BIT(4)
+#define SCR_NOSKMC BIT(5)
+
+#define CAM_VALID BIT(15)
+#define CAM_NOTVALID 0x0000
+#define CAM_USEDK BIT(5)
+
+#define CAM_NONE 0x0
+#define CAM_WEP40 0x01
+#define CAM_TKIP 0x02
+#define CAM_AES 0x04
+#define CAM_WEP104 0x05
+
+#define TOTAL_CAM_ENTRY 32
+#define HALF_CAM_ENTRY 16
+
+#define CAM_WRITE BIT(16)
+#define CAM_READ 0x00000000
+#define CAM_POLLINIG BIT(31)
+
+#define WOW_PMEN BIT(0)
+#define WOW_WOMEN BIT(1)
+#define WOW_MAGIC BIT(2)
+#define WOW_UWF BIT(3)
+
+#define GPIOMUX_EN BIT(3)
+#define GPIOSEL_GPIO 0
+#define GPIOSEL_PHYDBG 1
+#define GPIOSEL_BT 2
+#define GPIOSEL_WLANDBG 3
+#define GPIOSEL_GPIO_MASK (~(BIT(0)|BIT(1)))
+
+#define HST_RDBUSY BIT(0)
+#define CPU_WTBUSY BIT(1)
+
+#define IMR8190_DISABLED 0x0
+#define IMR_CPUERR BIT(5)
+#define IMR_ATIMEND BIT(4)
+#define IMR_TBDOK BIT(3)
+#define IMR_TBDER BIT(2)
+#define IMR_BCNDMAINT8 BIT(1)
+#define IMR_BCNDMAINT7 BIT(0)
+#define IMR_BCNDMAINT6 BIT(31)
+#define IMR_BCNDMAINT5 BIT(30)
+#define IMR_BCNDMAINT4 BIT(29)
+#define IMR_BCNDMAINT3 BIT(28)
+#define IMR_BCNDMAINT2 BIT(27)
+#define IMR_BCNDMAINT1 BIT(26)
+#define IMR_BCNDOK8 BIT(25)
+#define IMR_BCNDOK7 BIT(24)
+#define IMR_BCNDOK6 BIT(23)
+#define IMR_BCNDOK5 BIT(22)
+#define IMR_BCNDOK4 BIT(21)
+#define IMR_BCNDOK3 BIT(20)
+#define IMR_BCNDOK2 BIT(19)
+#define IMR_BCNDOK1 BIT(18)
+#define IMR_TIMEOUT2 BIT(17)
+#define IMR_TIMEOUT1 BIT(16)
+#define IMR_TXFOVW BIT(15)
+#define IMR_PSTIMEOUT BIT(14)
+#define IMR_BCNINT BIT(13)
+#define IMR_RXFOVW BIT(12)
+#define IMR_RDU BIT(11)
+#define IMR_RXCMDOK BIT(10)
+#define IMR_BDOK BIT(9)
+#define IMR_HIGHDOK BIT(8)
+#define IMR_COMDOK BIT(7)
+#define IMR_MGNTDOK BIT(6)
+#define IMR_HCCADOK BIT(5)
+#define IMR_BKDOK BIT(4)
+#define IMR_BEDOK BIT(3)
+#define IMR_VIDOK BIT(2)
+#define IMR_VODOK BIT(1)
+#define IMR_ROK BIT(0)
+
+#define TPPOLL_BKQ BIT(0)
+#define TPPOLL_BEQ BIT(1)
+#define TPPOLL_VIQ BIT(2)
+#define TPPOLL_VOQ BIT(3)
+#define TPPOLL_BQ BIT(4)
+#define TPPOLL_CQ BIT(5)
+#define TPPOLL_MQ BIT(6)
+#define TPPOLL_HQ BIT(7)
+#define TPPOLL_HCCAQ BIT(8)
+#define TPPOLL_STOPBK BIT(9)
+#define TPPOLL_STOPBE BIT(10)
+#define TPPOLL_STOPVI BIT(11)
+#define TPPOLL_STOPVO BIT(12)
+#define TPPOLL_STOPMGT BIT(13)
+#define TPPOLL_STOPHIGH BIT(14)
+#define TPPOLL_STOPHCCA BIT(15)
+#define TPPOLL_SHIFT 8
+
+#define CCX_CMD_CLM_ENABLE BIT(0)
+#define CCX_CMD_NHM_ENABLE BIT(1)
+#define CCX_CMD_FUNCTION_ENABLE BIT(8)
+#define CCX_CMD_IGNORE_CCA BIT(9)
+#define CCX_CMD_IGNORE_TXON BIT(10)
+#define CCX_CLM_RESULT_READY BIT(16)
+#define CCX_NHM_RESULT_READY BIT(16)
+#define CCX_CMD_RESET 0x0
+
+
+#define HWSET_MAX_SIZE_92S 128
+#define EFUSE_MAX_SECTION 16
+#define EFUSE_REAL_CONTENT_LEN 512
+
+#define RTL8190_EEPROM_ID 0x8129
+#define EEPROM_HPON 0x02
+#define EEPROM_CLK 0x06
+#define EEPROM_TESTR 0x08
+
+#define EEPROM_VID 0x0A
+#define EEPROM_DID 0x0C
+#define EEPROM_SVID 0x0E
+#define EEPROM_SMID 0x10
+
+#define EEPROM_MAC_ADDR 0x12
+#define EEPROM_NODE_ADDRESS_BYTE_0 0x12
+
+#define EEPROM_PWDIFF 0x54
+
+#define EEPROM_TXPOWERBASE 0x50
+#define EEPROM_TX_PWR_INDEX_RANGE 28
+
+#define EEPROM_TX_PWR_HT20_DIFF 0x62
+#define DEFAULT_HT20_TXPWR_DIFF 2
+#define EEPROM_TX_PWR_OFDM_DIFF 0x65
+
+#define EEPROM_TXPWRGROUP 0x67
+#define EEPROM_REGULATORY 0x6D
+
+#define TX_PWR_SAFETY_CHK 0x6D
+#define EEPROM_TXPWINDEX_CCK_24G 0x5D
+#define EEPROM_TXPWINDEX_OFDM_24G 0x6B
+#define EEPROM_HT2T_CH1_A 0x6c
+#define EEPROM_HT2T_CH7_A 0x6d
+#define EEPROM_HT2T_CH13_A 0x6e
+#define EEPROM_HT2T_CH1_B 0x6f
+#define EEPROM_HT2T_CH7_B 0x70
+#define EEPROM_HT2T_CH13_B 0x71
+
+#define EEPROM_TSSI_A 0x74
+#define EEPROM_TSSI_B 0x75
+
+#define EEPROM_RFIND_POWERDIFF 0x76
+#define EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF 0x3
+
+#define EEPROM_THERMALMETER 0x77
+#define EEPROM_BLUETOOTH_COEXIST 0x78
+#define EEPROM_BLUETOOTH_TYPE 0x4f
+
+#define EEPROM_OPTIONAL 0x78
+#define EEPROM_WOWLAN 0x78
+
+#define EEPROM_CRYSTALCAP 0x79
+#define EEPROM_CHANNELPLAN 0x7B
+#define EEPROM_VERSION 0x7C
+#define EEPROM_CUSTOMID 0x7A
+#define EEPROM_BOARDTYPE 0x7E
+
+#define EEPROM_CHANNEL_PLAN_FCC 0x0
+#define EEPROM_CHANNEL_PLAN_IC 0x1
+#define EEPROM_CHANNEL_PLAN_ETSI 0x2
+#define EEPROM_CHANNEL_PLAN_SPAIN 0x3
+#define EEPROM_CHANNEL_PLAN_FRANCE 0x4
+#define EEPROM_CHANNEL_PLAN_MKK 0x5
+#define EEPROM_CHANNEL_PLAN_MKK1 0x6
+#define EEPROM_CHANNEL_PLAN_ISRAEL 0x7
+#define EEPROM_CHANNEL_PLAN_TELEC 0x8
+#define EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN 0x9
+#define EEPROM_CHANNEL_PLAN_WORLD_WIDE_13 0xA
+#define EEPROM_CHANNEL_PLAN_NCC 0xB
+#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80
+
+#define FW_DIG_DISABLE 0xfd00cc00
+#define FW_DIG_ENABLE 0xfd000000
+#define FW_DIG_HALT 0xfd000001
+#define FW_DIG_RESUME 0xfd000002
+#define FW_HIGH_PWR_DISABLE 0xfd000008
+#define FW_HIGH_PWR_ENABLE 0xfd000009
+#define FW_ADD_A2_ENTRY 0xfd000016
+#define FW_TXPWR_TRACK_ENABLE 0xfd000017
+#define FW_TXPWR_TRACK_DISABLE 0xfd000018
+#define FW_TXPWR_TRACK_THERMAL 0xfd000019
+#define FW_TXANT_SWITCH_ENABLE 0xfd000023
+#define FW_TXANT_SWITCH_DISABLE 0xfd000024
+#define FW_RA_INIT 0xfd000026
+#define FW_CTRL_DM_BY_DRIVER 0Xfd00002a
+#define FW_RA_IOT_BG_COMB 0xfd000030
+#define FW_RA_IOT_N_COMB 0xfd000031
+#define FW_RA_REFRESH 0xfd0000a0
+#define FW_RA_UPDATE_MASK 0xfd0000a2
+#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_TX_FEEDBACK_NONE 0xfb000000
+#define FW_TX_FEEDBACK_DTM_ENABLE (FW_TX_FEEDBACK_NONE | 0x1)
+#define FW_TX_FEEDBACK_CCX_ENABL (FW_TX_FEEDBACK_NONE | 0x2)
+#define FW_BB_RESET_ENABLE 0xff00000d
+#define FW_BB_RESET_DISABLE 0xff00000e
+#define FW_CCA_CHK_ENABLE 0xff000011
+#define FW_CCK_RESET_CNT 0xff000013
+#define FW_LPS_ENTER 0xfe000010
+#define FW_LPS_LEAVE 0xfe000011
+#define FW_INDIRECT_READ 0xf2000000
+#define FW_INDIRECT_WRITE 0xf2000001
+#define FW_CHAN_SET 0xf3000001
+
+#define RFPC 0x5F
+#define RCR_9356SEL BIT(6)
+#define TCR_LRL_OFFSET 0
+#define TCR_SRL_OFFSET 8
+#define TCR_MXDMA_OFFSET 21
+#define TCR_SAT BIT(24)
+#define RCR_MXDMA_OFFSET 8
+#define RCR_FIFO_OFFSET 13
+#define RCR_OnlyErlPkt BIT(31)
+#define CWR 0xDC
+#define RETRYCTR 0xDE
+
+#define CPU_GEN_SYSTEM_RESET 0x00000001
+
+#define CCX_COMMAND_REG 0x890
+#define CLM_PERIOD_REG 0x894
+#define NHM_PERIOD_REG 0x896
+
+#define NHM_THRESHOLD0 0x898
+#define NHM_THRESHOLD1 0x899
+#define NHM_THRESHOLD2 0x89A
+#define NHM_THRESHOLD3 0x89B
+#define NHM_THRESHOLD4 0x89C
+#define NHM_THRESHOLD5 0x89D
+#define NHM_THRESHOLD6 0x89E
+#define CLM_RESULT_REG 0x8D0
+#define NHM_RESULT_REG 0x8D4
+#define NHM_RPI_COUNTER0 0x8D8
+#define NHM_RPI_COUNTER1 0x8D9
+#define NHM_RPI_COUNTER2 0x8DA
+#define NHM_RPI_COUNTER3 0x8DB
+#define NHM_RPI_COUNTER4 0x8DC
+#define NHM_RPI_COUNTER5 0x8DD
+#define NHM_RPI_COUNTER6 0x8DE
+#define NHM_RPI_COUNTER7 0x8DF
+
+#define HAL_8192S_HW_GPIO_OFF_BIT BIT(3)
+#define HAL_8192S_HW_GPIO_OFF_MASK 0xF7
+#define HAL_8192S_HW_GPIO_WPS_BIT BIT(4)
+
+#define RPMAC_RESET 0x100
+#define RPMAC_TXSTART 0x104
+#define RPMAC_TXLEGACYSIG 0x108
+#define RPMAC_TXHTSIG1 0x10c
+#define RPMAC_TXHTSIG2 0x110
+#define RPMAC_PHYDEBUG 0x114
+#define RPMAC_TXPACKETNNM 0x118
+#define RPMAC_TXIDLE 0x11c
+#define RPMAC_TXMACHEADER0 0x120
+#define RPMAC_TXMACHEADER1 0x124
+#define RPMAC_TXMACHEADER2 0x128
+#define RPMAC_TXMACHEADER3 0x12c
+#define RPMAC_TXMACHEADER4 0x130
+#define RPMAC_TXMACHEADER5 0x134
+#define RPMAC_TXDATATYPE 0x138
+#define RPMAC_TXRANDOMSEED 0x13c
+#define RPMAC_CCKPLCPPREAMBLE 0x140
+#define RPMAC_CCKPLCPHEADER 0x144
+#define RPMAC_CCKCRC16 0x148
+#define RPMAC_OFDMRXCRC32OK 0x170
+#define RPMAC_OFDMRXCRC32ER 0x174
+#define RPMAC_OFDMRXPARITYER 0x178
+#define RPMAC_OFDMRXCRC8ER 0x17c
+#define RPMAC_CCKCRXRC16ER 0x180
+#define RPMAC_CCKCRXRC32ER 0x184
+#define RPMAC_CCKCRXRC32OK 0x188
+#define RPMAC_TXSTATUS 0x18c
+
+#define RF_BB_CMD_ADDR 0x02c0
+#define RF_BB_CMD_DATA 0x02c4
+
+#define RFPGA0_RFMOD 0x800
+
+#define RFPGA0_TXINFO 0x804
+#define RFPGA0_PSDFUNCTION 0x808
+
+#define RFPGA0_TXGAINSTAGE 0x80c
+
+#define RFPGA0_RFTIMING1 0x810
+#define RFPGA0_RFTIMING2 0x814
+#define RFPGA0_XA_HSSIPARAMETER1 0x820
+#define RFPGA0_XA_HSSIPARAMETER2 0x824
+#define RFPGA0_XB_HSSIPARAMETER1 0x828
+#define RFPGA0_XB_HSSIPARAMETER2 0x82c
+#define RFPGA0_XC_HSSIPARAMETER1 0x830
+#define RFPGA0_XC_HSSIPARAMETER2 0x834
+#define RFPGA0_XD_HSSIPARAMETER1 0x838
+#define RFPGA0_XD_HSSIPARAMETER2 0x83c
+#define RFPGA0_XA_LSSIPARAMETER 0x840
+#define RFPGA0_XB_LSSIPARAMETER 0x844
+#define RFPGA0_XC_LSSIPARAMETER 0x848
+#define RFPGA0_XD_LSSIPARAMETER 0x84c
+
+#define RFPGA0_RFWAKEUP_PARAMETER 0x850
+#define RFPGA0_RFSLEEPUP_PARAMETER 0x854
+
+#define RFPGA0_XAB_SWITCHCONTROL 0x858
+#define RFPGA0_XCD_SWITCHCONTROL 0x85c
+
+#define RFPGA0_XA_RFINTERFACEOE 0x860
+#define RFPGA0_XB_RFINTERFACEOE 0x864
+#define RFPGA0_XC_RFINTERFACEOE 0x868
+#define RFPGA0_XD_RFINTERFACEOE 0x86c
+
+#define RFPGA0_XAB_RFINTERFACESW 0x870
+#define RFPGA0_XCD_RFINTERFACESW 0x874
+
+#define RFPGA0_XAB_RFPARAMETER 0x878
+#define RFPGA0_XCD_RFPARAMETER 0x87c
+
+#define RFPGA0_ANALOGPARAMETER1 0x880
+#define RFPGA0_ANALOGPARAMETER2 0x884
+#define RFPGA0_ANALOGPARAMETER3 0x888
+#define RFPGA0_ANALOGPARAMETER4 0x88c
+
+#define RFPGA0_XA_LSSIREADBACK 0x8a0
+#define RFPGA0_XB_LSSIREADBACK 0x8a4
+#define RFPGA0_XC_LSSIREADBACK 0x8a8
+#define RFPGA0_XD_LSSIREADBACK 0x8ac
+
+#define RFPGA0_PSDREPORT 0x8b4
+#define TRANSCEIVERA_HSPI_READBACK 0x8b8
+#define TRANSCEIVERB_HSPI_READBACK 0x8bc
+#define RFPGA0_XAB_RFINTERFACERB 0x8e0
+#define RFPGA0_XCD_RFINTERFACERB 0x8e4
+#define RFPGA1_RFMOD 0x900
+
+#define RFPGA1_TXBLOCK 0x904
+#define RFPGA1_DEBUGSELECT 0x908
+#define RFPGA1_TXINFO 0x90c
+
+#define RCCK0_SYSTEM 0xa00
+
+#define RCCK0_AFESETTING 0xa04
+#define RCCK0_CCA 0xa08
+
+#define RCCK0_RXAGC1 0xa0c
+#define RCCK0_RXAGC2 0xa10
+
+#define RCCK0_RXHP 0xa14
+
+#define RCCK0_DSPPARAMETER1 0xa18
+#define RCCK0_DSPPARAMETER2 0xa1c
+
+#define RCCK0_TXFILTER1 0xa20
+#define RCCK0_TXFILTER2 0xa24
+#define RCCK0_DEBUGPORT 0xa28
+#define RCCK0_FALSEALARMREPORT 0xa2c
+#define RCCK0_TRSSIREPORT 0xa50
+#define RCCK0_RXREPORT 0xa54
+#define RCCK0_FACOUNTERLOWER 0xa5c
+#define RCCK0_FACOUNTERUPPER 0xa58
+
+#define ROFDM0_LSTF 0xc00
+
+#define ROFDM0_TRXPATHENABLE 0xc04
+#define ROFDM0_TRMUXPAR 0xc08
+#define ROFDM0_TRSWISOLATION 0xc0c
+
+#define ROFDM0_XARXAFE 0xc10
+#define ROFDM0_XARXIQIMBALANCE 0xc14
+#define ROFDM0_XBRXAFE 0xc18
+#define ROFDM0_XBRXIQIMBALANCE 0xc1c
+#define ROFDM0_XCRXAFE 0xc20
+#define ROFDM0_XCRXIQIMBALANCE 0xc24
+#define ROFDM0_XDRXAFE 0xc28
+#define ROFDM0_XDRXIQIMBALANCE 0xc2c
+
+#define ROFDM0_RXDETECTOR1 0xc30
+#define ROFDM0_RXDETECTOR2 0xc34
+#define ROFDM0_RXDETECTOR3 0xc38
+#define ROFDM0_RXDETECTOR4 0xc3c
+
+#define ROFDM0_RXDSP 0xc40
+#define ROFDM0_CFO_AND_DAGC 0xc44
+#define ROFDM0_CCADROP_THRESHOLD 0xc48
+#define ROFDM0_ECCA_THRESHOLD 0xc4c
+
+#define ROFDM0_XAAGCCORE1 0xc50
+#define ROFDM0_XAAGCCORE2 0xc54
+#define ROFDM0_XBAGCCORE1 0xc58
+#define ROFDM0_XBAGCCORE2 0xc5c
+#define ROFDM0_XCAGCCORE1 0xc60
+#define ROFDM0_XCAGCCORE2 0xc64
+#define ROFDM0_XDAGCCORE1 0xc68
+#define ROFDM0_XDAGCCORE2 0xc6c
+
+#define ROFDM0_AGCPARAMETER1 0xc70
+#define ROFDM0_AGCPARAMETER2 0xc74
+#define ROFDM0_AGCRSSITABLE 0xc78
+#define ROFDM0_HTSTFAGC 0xc7c
+
+#define ROFDM0_XATXIQIMBALANCE 0xc80
+#define ROFDM0_XATXAFE 0xc84
+#define ROFDM0_XBTXIQIMBALANCE 0xc88
+#define ROFDM0_XBTXAFE 0xc8c
+#define ROFDM0_XCTXIQIMBALANCE 0xc90
+#define ROFDM0_XCTXAFE 0xc94
+#define ROFDM0_XDTXIQIMBALANCE 0xc98
+#define ROFDM0_XDTXAFE 0xc9c
+
+#define ROFDM0_RXHP_PARAMETER 0xce0
+#define ROFDM0_TXPSEUDO_NOISE_WGT 0xce4
+#define ROFDM0_FRAME_SYNC 0xcf0
+#define ROFDM0_DFSREPORT 0xcf4
+#define ROFDM0_TXCOEFF1 0xca4
+#define ROFDM0_TXCOEFF2 0xca8
+#define ROFDM0_TXCOEFF3 0xcac
+#define ROFDM0_TXCOEFF4 0xcb0
+#define ROFDM0_TXCOEFF5 0xcb4
+#define ROFDM0_TXCOEFF6 0xcb8
+
+
+#define ROFDM1_LSTF 0xd00
+#define ROFDM1_TRXPATHENABLE 0xd04
+
+#define ROFDM1_CFO 0xd08
+#define ROFDM1_CSI1 0xd10
+#define ROFDM1_SBD 0xd14
+#define ROFDM1_CSI2 0xd18
+#define ROFDM1_CFOTRACKING 0xd2c
+#define ROFDM1_TRXMESAURE1 0xd34
+#define ROFDM1_INTF_DET 0xd3c
+#define ROFDM1_PSEUDO_NOISESTATEAB 0xd50
+#define ROFDM1_PSEUDO_NOISESTATECD 0xd54
+#define ROFDM1_RX_PSEUDO_NOISE_WGT 0xd58
+
+#define ROFDM_PHYCOUNTER1 0xda0
+#define ROFDM_PHYCOUNTER2 0xda4
+#define ROFDM_PHYCOUNTER3 0xda8
+
+#define ROFDM_SHORT_CFOAB 0xdac
+#define ROFDM_SHORT_CFOCD 0xdb0
+#define ROFDM_LONG_CFOAB 0xdb4
+#define ROFDM_LONG_CFOCD 0xdb8
+#define ROFDM_TAIL_CFOAB 0xdbc
+#define ROFDM_TAIL_CFOCD 0xdc0
+#define ROFDM_PW_MEASURE1 0xdc4
+#define ROFDM_PW_MEASURE2 0xdc8
+#define ROFDM_BW_REPORT 0xdcc
+#define ROFDM_AGC_REPORT 0xdd0
+#define ROFDM_RXSNR 0xdd4
+#define ROFDM_RXEVMCSI 0xdd8
+#define ROFDM_SIG_REPORT 0xddc
+
+
+#define RTXAGC_RATE18_06 0xe00
+#define RTXAGC_RATE54_24 0xe04
+#define RTXAGC_CCK_MCS32 0xe08
+#define RTXAGC_MCS03_MCS00 0xe10
+#define RTXAGC_MCS07_MCS04 0xe14
+#define RTXAGC_MCS11_MCS08 0xe18
+#define RTXAGC_MCS15_MCS12 0xe1c
+
+
+#define RF_AC 0x00
+#define RF_IQADJ_G1 0x01
+#define RF_IQADJ_G2 0x02
+#define RF_POW_TRSW 0x05
+#define RF_GAIN_RX 0x06
+#define RF_GAIN_TX 0x07
+#define RF_TXM_IDAC 0x08
+#define RF_BS_IQGEN 0x0F
+
+#define RF_MODE1 0x10
+#define RF_MODE2 0x11
+#define RF_RX_AGC_HP 0x12
+#define RF_TX_AGC 0x13
+#define RF_BIAS 0x14
+#define RF_IPA 0x15
+#define RF_POW_ABILITY 0x17
+#define RF_MODE_AG 0x18
+#define RF_CHANNEL 0x18
+#define RF_CHNLBW 0x18
+#define RF_TOP 0x19
+#define RF_RX_G1 0x1A
+#define RF_RX_G2 0x1B
+#define RF_RX_BB2 0x1C
+#define RF_RX_BB1 0x1D
+#define RF_RCK1 0x1E
+#define RF_RCK2 0x1F
+
+#define RF_TX_G1 0x20
+#define RF_TX_G2 0x21
+#define RF_TX_G3 0x22
+#define RF_TX_BB1 0x23
+#define RF_T_METER 0x24
+#define RF_SYN_G1 0x25
+#define RF_SYN_G2 0x26
+#define RF_SYN_G3 0x27
+#define RF_SYN_G4 0x28
+#define RF_SYN_G5 0x29
+#define RF_SYN_G6 0x2A
+#define RF_SYN_G7 0x2B
+#define RF_SYN_G8 0x2C
+
+#define RF_RCK_OS 0x30
+#define RF_TXPA_G1 0x31
+#define RF_TXPA_G2 0x32
+#define RF_TXPA_G3 0x33
+
+#define BRFMOD 0x1
+#define BCCKEN 0x1000000
+#define BOFDMEN 0x2000000
+
+#define BXBTXAGC 0xf00
+#define BXCTXAGC 0xf000
+#define BXDTXAGC 0xf0000
+
+#define B3WIRE_DATALENGTH 0x800
+#define B3WIRE_ADDRESSLENGTH 0x400
+
+#define BRFSI_RFENV 0x10
+
+#define BLSSI_READADDRESS 0x7f800000
+#define BLSSI_READEDGE 0x80000000
+#define BLSSI_READBACK_DATA 0xfffff
+
+#define BADCLKPHASE 0x4000000
+
+#define BCCK_SIDEBAND 0x10
+
+#define BTX_AGCRATECCK 0x7f00
+
+#define MASKBYTE0 0xff
+#define MASKBYTE1 0xff00
+#define MASKBYTE2 0xff0000
+#define MASKBYTE3 0xff000000
+#define MASKHWORD 0xffff0000
+#define MASKLWORD 0x0000ffff
+#define MASKDWORD 0xffffffff
+
+#define MAKS12BITS 0xfffff
+#define MASK20BITS 0xfffff
+#define RFREG_OFFSET_MASK 0xfffff
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/rf.c b/drivers/net/wireless/rtlwifi/rtl8192se/rf.c
new file mode 100644
index 000000000000..1d3a48330399
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/rf.c
@@ -0,0 +1,546 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "rf.h"
+#include "dm.h"
+
+
+static void _rtl92s_get_powerbase(struct ieee80211_hw *hw, u8 *p_pwrlevel,
+ u8 chnl, u32 *ofdmbase, u32 *mcsbase,
+ u8 *p_final_pwridx)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u32 pwrbase0, pwrbase1;
+ u8 legacy_pwrdiff = 0, ht20_pwrdiff = 0;
+ u8 i, pwrlevel[4];
+
+ for (i = 0; i < 2; i++)
+ pwrlevel[i] = p_pwrlevel[i];
+
+ /* We only care about the path A for legacy. */
+ if (rtlefuse->eeprom_version < 2) {
+ pwrbase0 = pwrlevel[0] + (rtlefuse->legacy_httxpowerdiff & 0xf);
+ } else if (rtlefuse->eeprom_version >= 2) {
+ legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff
+ [RF90_PATH_A][chnl - 1];
+
+ /* For legacy OFDM, tx pwr always > HT OFDM pwr.
+ * We do not care Path B
+ * legacy OFDM pwr diff. NO BB register
+ * to notify HW. */
+ pwrbase0 = pwrlevel[0] + legacy_pwrdiff;
+ }
+
+ pwrbase0 = (pwrbase0 << 24) | (pwrbase0 << 16) | (pwrbase0 << 8) |
+ pwrbase0;
+ *ofdmbase = pwrbase0;
+
+ /* MCS rates */
+ if (rtlefuse->eeprom_version >= 2) {
+ /* Check HT20 to HT40 diff */
+ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) {
+ for (i = 0; i < 2; i++) {
+ /* rf-A, rf-B */
+ /* HT 20<->40 pwr diff */
+ ht20_pwrdiff = rtlefuse->txpwr_ht20diff
+ [i][chnl - 1];
+
+ if (ht20_pwrdiff < 8) /* 0~+7 */
+ pwrlevel[i] += ht20_pwrdiff;
+ else /* index8-15=-8~-1 */
+ pwrlevel[i] -= (16 - ht20_pwrdiff);
+ }
+ }
+ }
+
+ /* use index of rf-A */
+ pwrbase1 = pwrlevel[0];
+ pwrbase1 = (pwrbase1 << 24) | (pwrbase1 << 16) | (pwrbase1 << 8) |
+ pwrbase1;
+ *mcsbase = pwrbase1;
+
+ /* The following is for Antenna
+ * diff from Ant-B to Ant-A */
+ p_final_pwridx[0] = pwrlevel[0];
+ p_final_pwridx[1] = pwrlevel[1];
+
+ switch (rtlefuse->eeprom_regulatory) {
+ case 3:
+ /* The following is for calculation
+ * of the power diff for Ant-B to Ant-A. */
+ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
+ p_final_pwridx[0] += rtlefuse->pwrgroup_ht40
+ [RF90_PATH_A][
+ chnl - 1];
+ p_final_pwridx[1] += rtlefuse->pwrgroup_ht40
+ [RF90_PATH_B][
+ chnl - 1];
+ } else {
+ p_final_pwridx[0] += rtlefuse->pwrgroup_ht20
+ [RF90_PATH_A][
+ chnl - 1];
+ p_final_pwridx[1] += rtlefuse->pwrgroup_ht20
+ [RF90_PATH_B][
+ chnl - 1];
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("40MHz finalpwr_idx "
+ "(A / B) = 0x%x / 0x%x\n", p_final_pwridx[0],
+ p_final_pwridx[1]));
+ } else {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("20MHz finalpwr_idx "
+ "(A / B) = 0x%x / 0x%x\n", p_final_pwridx[0],
+ p_final_pwridx[1]));
+ }
+}
+
+static void _rtl92s_set_antennadiff(struct ieee80211_hw *hw,
+ u8 *p_final_pwridx)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ char ant_pwr_diff = 0;
+ u32 u4reg_val = 0;
+
+ if (rtlphy->rf_type == RF_2T2R) {
+ ant_pwr_diff = p_final_pwridx[1] - p_final_pwridx[0];
+
+ /* range is from 7~-8,
+ * index = 0x0~0xf */
+ if (ant_pwr_diff > 7)
+ ant_pwr_diff = 7;
+ if (ant_pwr_diff < -8)
+ ant_pwr_diff = -8;
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("Antenna Diff from RF-B "
+ "to RF-A = %d (0x%x)\n", ant_pwr_diff,
+ ant_pwr_diff & 0xf));
+
+ ant_pwr_diff &= 0xf;
+ }
+
+ /* Antenna TX power difference */
+ rtlefuse->antenna_txpwdiff[2] = 0;/* RF-D, don't care */
+ rtlefuse->antenna_txpwdiff[1] = 0;/* RF-C, don't care */
+ rtlefuse->antenna_txpwdiff[0] = (u8)(ant_pwr_diff); /* RF-B */
+
+ u4reg_val = rtlefuse->antenna_txpwdiff[2] << 8 |
+ rtlefuse->antenna_txpwdiff[1] << 4 |
+ rtlefuse->antenna_txpwdiff[0];
+
+ rtl_set_bbreg(hw, RFPGA0_TXGAINSTAGE, (BXBTXAGC | BXCTXAGC | BXDTXAGC),
+ u4reg_val);
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("Write BCD-Diff(0x%x) = 0x%x\n",
+ RFPGA0_TXGAINSTAGE, u4reg_val));
+}
+
+static void _rtl92s_get_txpower_writeval_byregulatory(struct ieee80211_hw *hw,
+ u8 chnl, u8 index,
+ u32 pwrbase0,
+ u32 pwrbase1,
+ u32 *p_outwrite_val)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 i, chnlgroup, pwrdiff_limit[4];
+ u32 writeval, customer_limit;
+
+ /* Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate */
+ switch (rtlefuse->eeprom_regulatory) {
+ case 0:
+ /* Realtek better performance increase power diff
+ * defined by Realtek for large power */
+ chnlgroup = 0;
+
+ writeval = rtlphy->mcs_txpwrlevel_origoffset
+ [chnlgroup][index] +
+ ((index < 2) ? pwrbase0 : pwrbase1);
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("RTK better performance, "
+ "writeval = 0x%x\n", writeval));
+ break;
+ case 1:
+ /* Realtek regulatory increase power diff defined
+ * by Realtek for regulatory */
+ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
+ writeval = ((index < 2) ? pwrbase0 : pwrbase1);
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("Realtek regulatory, "
+ "40MHz, writeval = 0x%x\n", writeval));
+ } else {
+ if (rtlphy->pwrgroup_cnt == 1)
+ chnlgroup = 0;
+
+ if (rtlphy->pwrgroup_cnt >= 3) {
+ if (chnl <= 3)
+ chnlgroup = 0;
+ else if (chnl >= 4 && chnl <= 8)
+ chnlgroup = 1;
+ else if (chnl > 8)
+ chnlgroup = 2;
+ if (rtlphy->pwrgroup_cnt == 4)
+ chnlgroup++;
+ }
+
+ writeval = rtlphy->mcs_txpwrlevel_origoffset
+ [chnlgroup][index]
+ + ((index < 2) ?
+ pwrbase0 : pwrbase1);
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("Realtek regulatory, "
+ "20MHz, writeval = 0x%x\n", writeval));
+ }
+ break;
+ case 2:
+ /* Better regulatory don't increase any power diff */
+ writeval = ((index < 2) ? pwrbase0 : pwrbase1);
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("Better regulatory, "
+ "writeval = 0x%x\n", writeval));
+ break;
+ case 3:
+ /* Customer defined power diff. increase power diff
+ defined by customer. */
+ chnlgroup = 0;
+
+ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("customer's limit, 40MHz = 0x%x\n",
+ rtlefuse->pwrgroup_ht40
+ [RF90_PATH_A][chnl - 1]));
+ } else {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("customer's limit, 20MHz = 0x%x\n",
+ rtlefuse->pwrgroup_ht20
+ [RF90_PATH_A][chnl - 1]));
+ }
+
+ for (i = 0; i < 4; i++) {
+ pwrdiff_limit[i] =
+ (u8)((rtlphy->mcs_txpwrlevel_origoffset
+ [chnlgroup][index] & (0x7f << (i * 8)))
+ >> (i * 8));
+
+ if (rtlphy->current_chan_bw ==
+ HT_CHANNEL_WIDTH_20_40) {
+ if (pwrdiff_limit[i] >
+ rtlefuse->pwrgroup_ht40
+ [RF90_PATH_A][chnl - 1]) {
+ pwrdiff_limit[i] =
+ rtlefuse->pwrgroup_ht20
+ [RF90_PATH_A][chnl - 1];
+ }
+ } else {
+ if (pwrdiff_limit[i] >
+ rtlefuse->pwrgroup_ht20
+ [RF90_PATH_A][chnl - 1]) {
+ pwrdiff_limit[i] =
+ rtlefuse->pwrgroup_ht20
+ [RF90_PATH_A][chnl - 1];
+ }
+ }
+ }
+
+ customer_limit = (pwrdiff_limit[3] << 24) |
+ (pwrdiff_limit[2] << 16) |
+ (pwrdiff_limit[1] << 8) |
+ (pwrdiff_limit[0]);
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("Customer's limit = 0x%x\n",
+ customer_limit));
+
+ writeval = customer_limit + ((index < 2) ?
+ pwrbase0 : pwrbase1);
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("Customer, writeval = "
+ "0x%x\n", writeval));
+ break;
+ default:
+ chnlgroup = 0;
+ writeval = rtlphy->mcs_txpwrlevel_origoffset[chnlgroup][index] +
+ ((index < 2) ? pwrbase0 : pwrbase1);
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("RTK better performance, "
+ "writeval = 0x%x\n", writeval));
+ break;
+ }
+
+ if (rtlpriv->dm.dynamic_txhighpower_lvl == TX_HIGH_PWR_LEVEL_LEVEL1)
+ writeval = 0x10101010;
+ else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
+ TX_HIGH_PWR_LEVEL_LEVEL2)
+ writeval = 0x0;
+
+ *p_outwrite_val = writeval;
+
+}
+
+static void _rtl92s_write_ofdm_powerreg(struct ieee80211_hw *hw,
+ u8 index, u32 val)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u16 regoffset[6] = {0xe00, 0xe04, 0xe10, 0xe14, 0xe18, 0xe1c};
+ u8 i, rfa_pwr[4];
+ u8 rfa_lower_bound = 0, rfa_upper_bound = 0, rf_pwr_diff = 0;
+ u32 writeval = val;
+
+ /* If path A and Path B coexist, we must limit Path A tx power.
+ * Protect Path B pwr over or under flow. We need to calculate
+ * upper and lower bound of path A tx power. */
+ if (rtlphy->rf_type == RF_2T2R) {
+ rf_pwr_diff = rtlefuse->antenna_txpwdiff[0];
+
+ /* Diff=-8~-1 */
+ if (rf_pwr_diff >= 8) {
+ /* Prevent underflow!! */
+ rfa_lower_bound = 0x10 - rf_pwr_diff;
+ /* if (rf_pwr_diff >= 0) Diff = 0-7 */
+ } else {
+ rfa_upper_bound = RF6052_MAX_TX_PWR - rf_pwr_diff;
+ }
+ }
+
+ for (i = 0; i < 4; i++) {
+ rfa_pwr[i] = (u8)((writeval & (0x7f << (i * 8))) >> (i * 8));
+ if (rfa_pwr[i] > RF6052_MAX_TX_PWR)
+ rfa_pwr[i] = RF6052_MAX_TX_PWR;
+
+ /* If path A and Path B coexist, we must limit Path A tx power.
+ * Protect Path B pwr over or under flow. We need to calculate
+ * upper and lower bound of path A tx power. */
+ if (rtlphy->rf_type == RF_2T2R) {
+ /* Diff=-8~-1 */
+ if (rf_pwr_diff >= 8) {
+ /* Prevent underflow!! */
+ if (rfa_pwr[i] < rfa_lower_bound)
+ rfa_pwr[i] = rfa_lower_bound;
+ /* Diff = 0-7 */
+ } else if (rf_pwr_diff >= 1) {
+ /* Prevent overflow */
+ if (rfa_pwr[i] > rfa_upper_bound)
+ rfa_pwr[i] = rfa_upper_bound;
+ }
+ }
+
+ }
+
+ writeval = (rfa_pwr[3] << 24) | (rfa_pwr[2] << 16) | (rfa_pwr[1] << 8) |
+ rfa_pwr[0];
+
+ rtl_set_bbreg(hw, regoffset[index], 0x7f7f7f7f, writeval);
+}
+
+void rtl92s_phy_rf6052_set_ofdmtxpower(struct ieee80211_hw *hw,
+ u8 *p_pwrlevel, u8 chnl)
+{
+ u32 writeval, pwrbase0, pwrbase1;
+ u8 index = 0;
+ u8 finalpwr_idx[4];
+
+ _rtl92s_get_powerbase(hw, p_pwrlevel, chnl, &pwrbase0, &pwrbase1,
+ &finalpwr_idx[0]);
+ _rtl92s_set_antennadiff(hw, &finalpwr_idx[0]);
+
+ for (index = 0; index < 6; index++) {
+ _rtl92s_get_txpower_writeval_byregulatory(hw, chnl, index,
+ pwrbase0, pwrbase1, &writeval);
+
+ _rtl92s_write_ofdm_powerreg(hw, index, writeval);
+ }
+}
+
+void rtl92s_phy_rf6052_set_ccktxpower(struct ieee80211_hw *hw, u8 pwrlevel)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u32 txagc = 0;
+ bool dont_inc_cck_or_turboscanoff = false;
+
+ if (((rtlefuse->eeprom_version >= 2) &&
+ (rtlefuse->txpwr_safetyflag == 1)) ||
+ ((rtlefuse->eeprom_version >= 2) &&
+ (rtlefuse->eeprom_regulatory != 0)))
+ dont_inc_cck_or_turboscanoff = true;
+
+ if (mac->act_scanning == true) {
+ txagc = 0x3f;
+ if (dont_inc_cck_or_turboscanoff)
+ txagc = pwrlevel;
+ } else {
+ txagc = pwrlevel;
+
+ if (rtlpriv->dm.dynamic_txhighpower_lvl ==
+ TX_HIGH_PWR_LEVEL_LEVEL1)
+ txagc = 0x10;
+ else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
+ TX_HIGH_PWR_LEVEL_LEVEL2)
+ txagc = 0x0;
+ }
+
+ if (txagc > RF6052_MAX_TX_PWR)
+ txagc = RF6052_MAX_TX_PWR;
+
+ rtl_set_bbreg(hw, RTXAGC_CCK_MCS32, BTX_AGCRATECCK, txagc);
+
+}
+
+bool rtl92s_phy_rf6052_config(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u32 u4reg_val = 0;
+ u8 rfpath;
+ bool rtstatus = true;
+ struct bb_reg_def *pphyreg;
+
+ /* Initialize RF */
+ for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {
+
+ pphyreg = &rtlphy->phyreg_def[rfpath];
+
+ /* Store original RFENV control type */
+ switch (rfpath) {
+ case RF90_PATH_A:
+ case RF90_PATH_C:
+ u4reg_val = rtl92s_phy_query_bb_reg(hw,
+ pphyreg->rfintfs,
+ BRFSI_RFENV);
+ break;
+ case RF90_PATH_B:
+ case RF90_PATH_D:
+ u4reg_val = rtl92s_phy_query_bb_reg(hw,
+ pphyreg->rfintfs,
+ BRFSI_RFENV << 16);
+ break;
+ }
+
+ /* Set RF_ENV enable */
+ rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfe,
+ BRFSI_RFENV << 16, 0x1);
+
+ /* Set RF_ENV output high */
+ rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1);
+
+ /* Set bit number of Address and Data for RF register */
+ rtl92s_phy_set_bb_reg(hw, pphyreg->rfhssi_para2,
+ B3WIRE_ADDRESSLENGTH, 0x0);
+ rtl92s_phy_set_bb_reg(hw, pphyreg->rfhssi_para2,
+ B3WIRE_DATALENGTH, 0x0);
+
+ /* Initialize RF fom connfiguration file */
+ switch (rfpath) {
+ case RF90_PATH_A:
+ rtstatus = rtl92s_phy_config_rf(hw,
+ (enum radio_path)rfpath);
+ break;
+ case RF90_PATH_B:
+ rtstatus = rtl92s_phy_config_rf(hw,
+ (enum radio_path)rfpath);
+ break;
+ case RF90_PATH_C:
+ break;
+ case RF90_PATH_D:
+ break;
+ }
+
+ /* Restore RFENV control type */
+ switch (rfpath) {
+ case RF90_PATH_A:
+ case RF90_PATH_C:
+ rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfs, BRFSI_RFENV,
+ u4reg_val);
+ break;
+ case RF90_PATH_B:
+ case RF90_PATH_D:
+ rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfs,
+ BRFSI_RFENV << 16,
+ u4reg_val);
+ break;
+ }
+
+ if (rtstatus != true) {
+ printk(KERN_ERR "Radio[%d] Fail!!", rfpath);
+ goto fail;
+ }
+
+ }
+
+ return rtstatus;
+
+fail:
+ return rtstatus;
+}
+
+void rtl92s_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ switch (bandwidth) {
+ case HT_CHANNEL_WIDTH_20:
+ rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
+ 0xfffff3ff) | 0x0400);
+ rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
+ rtlphy->rfreg_chnlval[0]);
+ break;
+ case HT_CHANNEL_WIDTH_20_40:
+ rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
+ 0xfffff3ff));
+ rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
+ rtlphy->rfreg_chnlval[0]);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("unknown bandwidth: %#X\n",
+ bandwidth));
+ break;
+ }
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/rf.h b/drivers/net/wireless/rtlwifi/rtl8192se/rf.h
new file mode 100644
index 000000000000..3843baa1a874
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/rf.h
@@ -0,0 +1,43 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#ifndef __INC_RTL92S_RF_H
+#define __INC_RTL92S_RF_H
+
+#define RF6052_MAX_TX_PWR 0x3F
+
+void rtl92s_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw,
+ u8 bandwidth);
+bool rtl92s_phy_rf6052_config(struct ieee80211_hw *hw) ;
+void rtl92s_phy_rf6052_set_ccktxpower(struct ieee80211_hw *hw,
+ u8 powerlevel);
+void rtl92s_phy_rf6052_set_ofdmtxpower(struct ieee80211_hw *hw,
+ u8 *p_pwrlevel, u8 chnl);
+
+#endif
+
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
new file mode 100644
index 000000000000..1c6cb1d7d660
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
@@ -0,0 +1,423 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include <linux/vmalloc.h>
+
+#include "../wifi.h"
+#include "../core.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "fw.h"
+#include "hw.h"
+#include "sw.h"
+#include "trx.h"
+#include "led.h"
+
+static void rtl92s_init_aspm_vars(struct ieee80211_hw *hw)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ /*close ASPM for AMD defaultly */
+ rtlpci->const_amdpci_aspm = 0;
+
+ /*
+ * ASPM PS mode.
+ * 0 - Disable ASPM,
+ * 1 - Enable ASPM without Clock Req,
+ * 2 - Enable ASPM with Clock Req,
+ * 3 - Alwyas Enable ASPM with Clock Req,
+ * 4 - Always Enable ASPM without Clock Req.
+ * set defult to RTL8192CE:3 RTL8192E:2
+ * */
+ rtlpci->const_pci_aspm = 2;
+
+ /*Setting for PCI-E device */
+ rtlpci->const_devicepci_aspm_setting = 0x03;
+
+ /*Setting for PCI-E bridge */
+ rtlpci->const_hostpci_aspm_setting = 0x02;
+
+ /*
+ * In Hw/Sw Radio Off situation.
+ * 0 - Default,
+ * 1 - From ASPM setting without low Mac Pwr,
+ * 2 - From ASPM setting with low Mac Pwr,
+ * 3 - Bus D3
+ * set default to RTL8192CE:0 RTL8192SE:2
+ */
+ rtlpci->const_hwsw_rfoff_d3 = 2;
+
+ /*
+ * This setting works for those device with
+ * backdoor ASPM setting such as EPHY setting.
+ * 0 - Not support ASPM,
+ * 1 - Support ASPM,
+ * 2 - According to chipset.
+ */
+ rtlpci->const_support_pciaspm = 2;
+}
+
+static int rtl92s_init_sw_vars(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ const struct firmware *firmware;
+ struct rt_firmware *pfirmware = NULL;
+ int err = 0;
+ u16 earlyrxthreshold = 7;
+
+ rtlpriv->dm.dm_initialgain_enable = 1;
+ rtlpriv->dm.dm_flag = 0;
+ rtlpriv->dm.disable_framebursting = 0;
+ rtlpriv->dm.thermalvalue = 0;
+ rtlpriv->dm.useramask = true;
+
+ /* compatible 5G band 91se just 2.4G band & smsp */
+ rtlpriv->rtlhal.current_bandtype = BAND_ON_2_4G;
+ rtlpriv->rtlhal.bandset = BAND_ON_2_4G;
+ rtlpriv->rtlhal.macphymode = SINGLEMAC_SINGLEPHY;
+
+ rtlpci->transmit_config = 0;
+
+ rtlpci->receive_config =
+ RCR_APPFCS |
+ RCR_APWRMGT |
+ /*RCR_ADD3 |*/
+ RCR_AMF |
+ RCR_ADF |
+ RCR_APP_MIC |
+ RCR_APP_ICV |
+ RCR_AICV |
+ /* Accept ICV error, CRC32 Error */
+ RCR_ACRC32 |
+ RCR_AB |
+ /* Accept Broadcast, Multicast */
+ RCR_AM |
+ /* Accept Physical match */
+ RCR_APM |
+ /* Accept Destination Address packets */
+ /*RCR_AAP |*/
+ RCR_APP_PHYST_STAFF |
+ /* Accept PHY status */
+ RCR_APP_PHYST_RXFF |
+ (earlyrxthreshold << RCR_FIFO_OFFSET);
+
+ rtlpci->irq_mask[0] = (u32)
+ (IMR_ROK |
+ IMR_VODOK |
+ IMR_VIDOK |
+ IMR_BEDOK |
+ IMR_BKDOK |
+ IMR_HCCADOK |
+ IMR_MGNTDOK |
+ IMR_COMDOK |
+ IMR_HIGHDOK |
+ IMR_BDOK |
+ IMR_RXCMDOK |
+ /*IMR_TIMEOUT0 |*/
+ IMR_RDU |
+ IMR_RXFOVW |
+ IMR_BCNINT
+ /*| IMR_TXFOVW*/
+ /*| IMR_TBDOK |
+ IMR_TBDER*/);
+
+ rtlpci->irq_mask[1] = (u32) 0;
+
+ rtlpci->shortretry_limit = 0x30;
+ rtlpci->longretry_limit = 0x30;
+
+ rtlpci->first_init = true;
+
+ /* for LPS & IPS */
+ rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps;
+ rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
+ rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
+ rtlpriv->psc.reg_fwctrl_lps = 3;
+ rtlpriv->psc.reg_max_lps_awakeintvl = 5;
+ /* for ASPM, you can close aspm through
+ * set const_support_pciaspm = 0 */
+ rtl92s_init_aspm_vars(hw);
+
+ if (rtlpriv->psc.reg_fwctrl_lps == 1)
+ rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE;
+ else if (rtlpriv->psc.reg_fwctrl_lps == 2)
+ rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE;
+ else if (rtlpriv->psc.reg_fwctrl_lps == 3)
+ rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE;
+
+ /* for firmware buf */
+ rtlpriv->rtlhal.pfirmware = vzalloc(sizeof(struct rt_firmware));
+ if (!rtlpriv->rtlhal.pfirmware) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Can't alloc buffer for fw.\n"));
+ return 1;
+ }
+
+ printk(KERN_INFO "rtl8192se: Driver for Realtek RTL8192SE/RTL8191SE\n"
+ " Loading firmware %s\n", rtlpriv->cfg->fw_name);
+ /* request fw */
+ err = request_firmware(&firmware, rtlpriv->cfg->fw_name,
+ rtlpriv->io.dev);
+ if (err) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Failed to request firmware!\n"));
+ return 1;
+ }
+ if (firmware->size > sizeof(struct rt_firmware)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Firmware is too big!\n"));
+ release_firmware(firmware);
+ return 1;
+ }
+
+ pfirmware = (struct rt_firmware *)rtlpriv->rtlhal.pfirmware;
+ memcpy(pfirmware->sz_fw_tmpbuffer, firmware->data, firmware->size);
+ pfirmware->sz_fw_tmpbufferlen = firmware->size;
+ release_firmware(firmware);
+
+ return err;
+}
+
+static void rtl92s_deinit_sw_vars(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (rtlpriv->rtlhal.pfirmware) {
+ vfree(rtlpriv->rtlhal.pfirmware);
+ rtlpriv->rtlhal.pfirmware = NULL;
+ }
+}
+
+static struct rtl_hal_ops rtl8192se_hal_ops = {
+ .init_sw_vars = rtl92s_init_sw_vars,
+ .deinit_sw_vars = rtl92s_deinit_sw_vars,
+ .read_eeprom_info = rtl92se_read_eeprom_info,
+ .interrupt_recognized = rtl92se_interrupt_recognized,
+ .hw_init = rtl92se_hw_init,
+ .hw_disable = rtl92se_card_disable,
+ .hw_suspend = rtl92se_suspend,
+ .hw_resume = rtl92se_resume,
+ .enable_interrupt = rtl92se_enable_interrupt,
+ .disable_interrupt = rtl92se_disable_interrupt,
+ .set_network_type = rtl92se_set_network_type,
+ .set_chk_bssid = rtl92se_set_check_bssid,
+ .set_qos = rtl92se_set_qos,
+ .set_bcn_reg = rtl92se_set_beacon_related_registers,
+ .set_bcn_intv = rtl92se_set_beacon_interval,
+ .update_interrupt_mask = rtl92se_update_interrupt_mask,
+ .get_hw_reg = rtl92se_get_hw_reg,
+ .set_hw_reg = rtl92se_set_hw_reg,
+ .update_rate_tbl = rtl92se_update_hal_rate_tbl,
+ .fill_tx_desc = rtl92se_tx_fill_desc,
+ .fill_tx_cmddesc = rtl92se_tx_fill_cmddesc,
+ .query_rx_desc = rtl92se_rx_query_desc,
+ .set_channel_access = rtl92se_update_channel_access_setting,
+ .radio_onoff_checking = rtl92se_gpio_radio_on_off_checking,
+ .set_bw_mode = rtl92s_phy_set_bw_mode,
+ .switch_channel = rtl92s_phy_sw_chnl,
+ .dm_watchdog = rtl92s_dm_watchdog,
+ .scan_operation_backup = rtl92s_phy_scan_operation_backup,
+ .set_rf_power_state = rtl92s_phy_set_rf_power_state,
+ .led_control = rtl92se_led_control,
+ .set_desc = rtl92se_set_desc,
+ .get_desc = rtl92se_get_desc,
+ .tx_polling = rtl92se_tx_polling,
+ .enable_hw_sec = rtl92se_enable_hw_security_config,
+ .set_key = rtl92se_set_key,
+ .init_sw_leds = rtl92se_init_sw_leds,
+ .get_bbreg = rtl92s_phy_query_bb_reg,
+ .set_bbreg = rtl92s_phy_set_bb_reg,
+ .get_rfreg = rtl92s_phy_query_rf_reg,
+ .set_rfreg = rtl92s_phy_set_rf_reg,
+};
+
+static struct rtl_mod_params rtl92se_mod_params = {
+ .sw_crypto = false,
+ .inactiveps = true,
+ .swctrl_lps = true,
+ .fwctrl_lps = false,
+};
+
+/* Because memory R/W bursting will cause system hang/crash
+ * for 92se, so we don't read back after every write action */
+static struct rtl_hal_cfg rtl92se_hal_cfg = {
+ .bar_id = 1,
+ .write_readback = false,
+ .name = "rtl92s_pci",
+ .fw_name = "rtlwifi/rtl8192sefw.bin",
+ .ops = &rtl8192se_hal_ops,
+ .mod_params = &rtl92se_mod_params,
+
+ .maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL,
+ .maps[SYS_FUNC_EN] = REG_SYS_FUNC_EN,
+ .maps[SYS_CLK] = SYS_CLKR,
+ .maps[MAC_RCR_AM] = RCR_AM,
+ .maps[MAC_RCR_AB] = RCR_AB,
+ .maps[MAC_RCR_ACRC32] = RCR_ACRC32,
+ .maps[MAC_RCR_ACF] = RCR_ACF,
+ .maps[MAC_RCR_AAP] = RCR_AAP,
+
+ .maps[EFUSE_TEST] = REG_EFUSE_TEST,
+ .maps[EFUSE_CTRL] = REG_EFUSE_CTRL,
+ .maps[EFUSE_CLK] = REG_EFUSE_CLK,
+ .maps[EFUSE_CLK_CTRL] = REG_EFUSE_CTRL,
+ .maps[EFUSE_PWC_EV12V] = 0, /* nouse for 8192se */
+ .maps[EFUSE_FEN_ELDR] = 0, /* nouse for 8192se */
+ .maps[EFUSE_LOADER_CLK_EN] = 0,/* nouse for 8192se */
+ .maps[EFUSE_ANA8M] = EFUSE_ANA8M,
+ .maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE_92S,
+ .maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION,
+ .maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN,
+
+ .maps[RWCAM] = REG_RWCAM,
+ .maps[WCAMI] = REG_WCAMI,
+ .maps[RCAMO] = REG_RCAMO,
+ .maps[CAMDBG] = REG_CAMDBG,
+ .maps[SECR] = REG_SECR,
+ .maps[SEC_CAM_NONE] = CAM_NONE,
+ .maps[SEC_CAM_WEP40] = CAM_WEP40,
+ .maps[SEC_CAM_TKIP] = CAM_TKIP,
+ .maps[SEC_CAM_AES] = CAM_AES,
+ .maps[SEC_CAM_WEP104] = CAM_WEP104,
+
+ .maps[RTL_IMR_BCNDMAINT6] = IMR_BCNDMAINT6,
+ .maps[RTL_IMR_BCNDMAINT5] = IMR_BCNDMAINT5,
+ .maps[RTL_IMR_BCNDMAINT4] = IMR_BCNDMAINT4,
+ .maps[RTL_IMR_BCNDMAINT3] = IMR_BCNDMAINT3,
+ .maps[RTL_IMR_BCNDMAINT2] = IMR_BCNDMAINT2,
+ .maps[RTL_IMR_BCNDMAINT1] = IMR_BCNDMAINT1,
+ .maps[RTL_IMR_BCNDOK8] = IMR_BCNDOK8,
+ .maps[RTL_IMR_BCNDOK7] = IMR_BCNDOK7,
+ .maps[RTL_IMR_BCNDOK6] = IMR_BCNDOK6,
+ .maps[RTL_IMR_BCNDOK5] = IMR_BCNDOK5,
+ .maps[RTL_IMR_BCNDOK4] = IMR_BCNDOK4,
+ .maps[RTL_IMR_BCNDOK3] = IMR_BCNDOK3,
+ .maps[RTL_IMR_BCNDOK2] = IMR_BCNDOK2,
+ .maps[RTL_IMR_BCNDOK1] = IMR_BCNDOK1,
+ .maps[RTL_IMR_TIMEOUT2] = IMR_TIMEOUT2,
+ .maps[RTL_IMR_TIMEOUT1] = IMR_TIMEOUT1,
+
+ .maps[RTL_IMR_TXFOVW] = IMR_TXFOVW,
+ .maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT,
+ .maps[RTL_IMR_BcnInt] = IMR_BCNINT,
+ .maps[RTL_IMR_RXFOVW] = IMR_RXFOVW,
+ .maps[RTL_IMR_RDU] = IMR_RDU,
+ .maps[RTL_IMR_ATIMEND] = IMR_ATIMEND,
+ .maps[RTL_IMR_BDOK] = IMR_BDOK,
+ .maps[RTL_IMR_MGNTDOK] = IMR_MGNTDOK,
+ .maps[RTL_IMR_TBDER] = IMR_TBDER,
+ .maps[RTL_IMR_HIGHDOK] = IMR_HIGHDOK,
+ .maps[RTL_IMR_COMDOK] = IMR_COMDOK,
+ .maps[RTL_IMR_TBDOK] = IMR_TBDOK,
+ .maps[RTL_IMR_BKDOK] = IMR_BKDOK,
+ .maps[RTL_IMR_BEDOK] = IMR_BEDOK,
+ .maps[RTL_IMR_VIDOK] = IMR_VIDOK,
+ .maps[RTL_IMR_VODOK] = IMR_VODOK,
+ .maps[RTL_IMR_ROK] = IMR_ROK,
+ .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER),
+
+ .maps[RTL_RC_CCK_RATE1M] = DESC92S_RATE1M,
+ .maps[RTL_RC_CCK_RATE2M] = DESC92S_RATE2M,
+ .maps[RTL_RC_CCK_RATE5_5M] = DESC92S_RATE5_5M,
+ .maps[RTL_RC_CCK_RATE11M] = DESC92S_RATE11M,
+ .maps[RTL_RC_OFDM_RATE6M] = DESC92S_RATE6M,
+ .maps[RTL_RC_OFDM_RATE9M] = DESC92S_RATE9M,
+ .maps[RTL_RC_OFDM_RATE12M] = DESC92S_RATE12M,
+ .maps[RTL_RC_OFDM_RATE18M] = DESC92S_RATE18M,
+ .maps[RTL_RC_OFDM_RATE24M] = DESC92S_RATE24M,
+ .maps[RTL_RC_OFDM_RATE36M] = DESC92S_RATE36M,
+ .maps[RTL_RC_OFDM_RATE48M] = DESC92S_RATE48M,
+ .maps[RTL_RC_OFDM_RATE54M] = DESC92S_RATE54M,
+
+ .maps[RTL_RC_HT_RATEMCS7] = DESC92S_RATEMCS7,
+ .maps[RTL_RC_HT_RATEMCS15] = DESC92S_RATEMCS15,
+};
+
+static struct pci_device_id rtl92se_pci_ids[] __devinitdata = {
+ {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8192, rtl92se_hal_cfg)},
+ {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8171, rtl92se_hal_cfg)},
+ {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8172, rtl92se_hal_cfg)},
+ {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8173, rtl92se_hal_cfg)},
+ {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8174, rtl92se_hal_cfg)},
+ {},
+};
+
+MODULE_DEVICE_TABLE(pci, rtl92se_pci_ids);
+
+MODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>");
+MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek 8192S/8191S 802.11n PCI wireless");
+MODULE_FIRMWARE("rtlwifi/rtl8192sefw.bin");
+
+module_param_named(swenc, rtl92se_mod_params.sw_crypto, bool, 0444);
+module_param_named(ips, rtl92se_mod_params.inactiveps, bool, 0444);
+module_param_named(swlps, rtl92se_mod_params.swctrl_lps, bool, 0444);
+module_param_named(fwlps, rtl92se_mod_params.fwctrl_lps, bool, 0444);
+MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n");
+MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n");
+MODULE_PARM_DESC(swlps, "using linked sw control power save (default 1 is "
+ "open)\n");
+
+
+static struct pci_driver rtl92se_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = rtl92se_pci_ids,
+ .probe = rtl_pci_probe,
+ .remove = rtl_pci_disconnect,
+
+#ifdef CONFIG_PM
+ .suspend = rtl_pci_suspend,
+ .resume = rtl_pci_resume,
+#endif
+
+};
+
+static int __init rtl92se_module_init(void)
+{
+ int ret = 0;
+
+ ret = pci_register_driver(&rtl92se_driver);
+ if (ret)
+ RT_ASSERT(false, (": No device found\n"));
+
+ return ret;
+}
+
+static void __exit rtl92se_module_exit(void)
+{
+ pci_unregister_driver(&rtl92se_driver);
+}
+
+module_init(rtl92se_module_init);
+module_exit(rtl92se_module_exit);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-led.h b/drivers/net/wireless/rtlwifi/rtl8192se/sw.h
index 96f323dc5dd6..fc4eb285a0ac 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-led.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.h
@@ -1,6 +1,6 @@
/******************************************************************************
*
- * Copyright(c) 2003 - 2010 Intel Corporation. All rights reserved.
+ * Copyright(c) 2009-2010 Realtek Corporation.
*
* 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
@@ -19,15 +19,18 @@
* file called LICENSE.
*
* Contact Information:
- * Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
*
*****************************************************************************/
+#ifndef __REALTEK_PCI92SE_SW_H__
+#define __REALTEK_PCI92SE_SW_H__
-#ifndef __iwl_agn_led_h__
-#define __iwl_agn_led_h__
+#define EFUSE_MAX_SECTION 16
-extern const struct iwl_led_ops iwlagn_led_ops;
-void iwlagn_led_enable(struct iwl_priv *priv);
+int rtl92se_init_sw(struct ieee80211_hw *hw);
+void rtl92se_deinit_sw(struct ieee80211_hw *hw);
+void rtl92se_init_var_map(struct ieee80211_hw *hw);
-#endif /* __iwl_agn_led_h__ */
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/table.c b/drivers/net/wireless/rtlwifi/rtl8192se/table.c
new file mode 100644
index 000000000000..154185b3969d
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/table.c
@@ -0,0 +1,634 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ * Created on 2010/ 5/18, 1:41
+ *****************************************************************************/
+
+#include "table.h"
+
+u32 rtl8192sephy_reg_2t2rarray[PHY_REG_2T2RARRAYLENGTH] = {
+ 0x01c, 0x07000000,
+ 0x800, 0x00040000,
+ 0x804, 0x00008003,
+ 0x808, 0x0000fc00,
+ 0x80c, 0x0000000a,
+ 0x810, 0x10005088,
+ 0x814, 0x020c3d10,
+ 0x818, 0x00200185,
+ 0x81c, 0x00000000,
+ 0x820, 0x01000000,
+ 0x824, 0x00390004,
+ 0x828, 0x01000000,
+ 0x82c, 0x00390004,
+ 0x830, 0x00000004,
+ 0x834, 0x00690200,
+ 0x838, 0x00000004,
+ 0x83c, 0x00690200,
+ 0x840, 0x00010000,
+ 0x844, 0x00010000,
+ 0x848, 0x00000000,
+ 0x84c, 0x00000000,
+ 0x850, 0x00000000,
+ 0x854, 0x00000000,
+ 0x858, 0x48484848,
+ 0x85c, 0x65a965a9,
+ 0x860, 0x0f7f0130,
+ 0x864, 0x0f7f0130,
+ 0x868, 0x0f7f0130,
+ 0x86c, 0x0f7f0130,
+ 0x870, 0x03000700,
+ 0x874, 0x03000300,
+ 0x878, 0x00020002,
+ 0x87c, 0x004f0201,
+ 0x880, 0xa8300ac1,
+ 0x884, 0x00000058,
+ 0x888, 0x00000008,
+ 0x88c, 0x00000004,
+ 0x890, 0x00000000,
+ 0x894, 0xfffffffe,
+ 0x898, 0x40302010,
+ 0x89c, 0x00706050,
+ 0x8b0, 0x00000000,
+ 0x8e0, 0x00000000,
+ 0x8e4, 0x00000000,
+ 0xe00, 0x30333333,
+ 0xe04, 0x2a2d2e2f,
+ 0xe08, 0x00003232,
+ 0xe10, 0x30333333,
+ 0xe14, 0x2a2d2e2f,
+ 0xe18, 0x30333333,
+ 0xe1c, 0x2a2d2e2f,
+ 0xe30, 0x01007c00,
+ 0xe34, 0x01004800,
+ 0xe38, 0x1000dc1f,
+ 0xe3c, 0x10008c1f,
+ 0xe40, 0x021400a0,
+ 0xe44, 0x281600a0,
+ 0xe48, 0xf8000001,
+ 0xe4c, 0x00002910,
+ 0xe50, 0x01007c00,
+ 0xe54, 0x01004800,
+ 0xe58, 0x1000dc1f,
+ 0xe5c, 0x10008c1f,
+ 0xe60, 0x021400a0,
+ 0xe64, 0x281600a0,
+ 0xe6c, 0x00002910,
+ 0xe70, 0x31ed92fb,
+ 0xe74, 0x361536fb,
+ 0xe78, 0x361536fb,
+ 0xe7c, 0x361536fb,
+ 0xe80, 0x361536fb,
+ 0xe84, 0x000d92fb,
+ 0xe88, 0x000d92fb,
+ 0xe8c, 0x31ed92fb,
+ 0xed0, 0x31ed92fb,
+ 0xed4, 0x31ed92fb,
+ 0xed8, 0x000d92fb,
+ 0xedc, 0x000d92fb,
+ 0xee0, 0x000d92fb,
+ 0xee4, 0x015e5448,
+ 0xee8, 0x21555448,
+ 0x900, 0x00000000,
+ 0x904, 0x00000023,
+ 0x908, 0x00000000,
+ 0x90c, 0x01121313,
+ 0xa00, 0x00d047c8,
+ 0xa04, 0x80ff0008,
+ 0xa08, 0x8ccd8300,
+ 0xa0c, 0x2e62120f,
+ 0xa10, 0x9500bb78,
+ 0xa14, 0x11144028,
+ 0xa18, 0x00881117,
+ 0xa1c, 0x89140f00,
+ 0xa20, 0x1a1b0000,
+ 0xa24, 0x090e1317,
+ 0xa28, 0x00000204,
+ 0xa2c, 0x10d30000,
+ 0xc00, 0x40071d40,
+ 0xc04, 0x00a05633,
+ 0xc08, 0x000000e4,
+ 0xc0c, 0x6c6c6c6c,
+ 0xc10, 0x08800000,
+ 0xc14, 0x40000100,
+ 0xc18, 0x08000000,
+ 0xc1c, 0x40000100,
+ 0xc20, 0x08000000,
+ 0xc24, 0x40000100,
+ 0xc28, 0x08000000,
+ 0xc2c, 0x40000100,
+ 0xc30, 0x6de9ac44,
+ 0xc34, 0x469652cf,
+ 0xc38, 0x49795994,
+ 0xc3c, 0x0a979764,
+ 0xc40, 0x1f7c403f,
+ 0xc44, 0x000100b7,
+ 0xc48, 0xec020000,
+ 0xc4c, 0x007f037f,
+ 0xc50, 0x69543420,
+ 0xc54, 0x433c0094,
+ 0xc58, 0x69543420,
+ 0xc5c, 0x433c0094,
+ 0xc60, 0x69543420,
+ 0xc64, 0x433c0094,
+ 0xc68, 0x69543420,
+ 0xc6c, 0x433c0094,
+ 0xc70, 0x2c7f000d,
+ 0xc74, 0x0186155b,
+ 0xc78, 0x0000001f,
+ 0xc7c, 0x00b91612,
+ 0xc80, 0x40000100,
+ 0xc84, 0x20f60000,
+ 0xc88, 0x20000080,
+ 0xc8c, 0x20200000,
+ 0xc90, 0x40000100,
+ 0xc94, 0x00000000,
+ 0xc98, 0x40000100,
+ 0xc9c, 0x00000000,
+ 0xca0, 0x00492492,
+ 0xca4, 0x00000000,
+ 0xca8, 0x00000000,
+ 0xcac, 0x00000000,
+ 0xcb0, 0x00000000,
+ 0xcb4, 0x00000000,
+ 0xcb8, 0x00000000,
+ 0xcbc, 0x28000000,
+ 0xcc0, 0x00000000,
+ 0xcc4, 0x00000000,
+ 0xcc8, 0x00000000,
+ 0xccc, 0x00000000,
+ 0xcd0, 0x00000000,
+ 0xcd4, 0x00000000,
+ 0xcd8, 0x64b22427,
+ 0xcdc, 0x00766932,
+ 0xce0, 0x00222222,
+ 0xce4, 0x00000000,
+ 0xce8, 0x37644302,
+ 0xcec, 0x2f97d40c,
+ 0xd00, 0x00000750,
+ 0xd04, 0x00000403,
+ 0xd08, 0x0000907f,
+ 0xd0c, 0x00000001,
+ 0xd10, 0xa0633333,
+ 0xd14, 0x33333c63,
+ 0xd18, 0x6a8f5b6b,
+ 0xd1c, 0x00000000,
+ 0xd20, 0x00000000,
+ 0xd24, 0x00000000,
+ 0xd28, 0x00000000,
+ 0xd2c, 0xcc979975,
+ 0xd30, 0x00000000,
+ 0xd34, 0x00000000,
+ 0xd38, 0x00000000,
+ 0xd3c, 0x00027293,
+ 0xd40, 0x00000000,
+ 0xd44, 0x00000000,
+ 0xd48, 0x00000000,
+ 0xd50, 0x6437140a,
+ 0xd54, 0x024dbd02,
+ 0xd58, 0x00000000,
+ 0xd5c, 0x30032064,
+ 0xd60, 0x4653de68,
+ 0xd64, 0x00518a3c,
+ 0xd68, 0x00002101,
+ 0xf14, 0x00000003,
+ 0xf4c, 0x00000000,
+ 0xf00, 0x00000300,
+};
+
+u32 rtl8192sephy_changeto_1t1rarray[PHY_CHANGETO_1T1RARRAYLENGTH] = {
+ 0x844, 0xffffffff, 0x00010000,
+ 0x804, 0x0000000f, 0x00000001,
+ 0x824, 0x00f0000f, 0x00300004,
+ 0x82c, 0x00f0000f, 0x00100002,
+ 0x870, 0x04000000, 0x00000001,
+ 0x864, 0x00000400, 0x00000000,
+ 0x878, 0x000f000f, 0x00000002,
+ 0xe74, 0x0f000000, 0x00000002,
+ 0xe78, 0x0f000000, 0x00000002,
+ 0xe7c, 0x0f000000, 0x00000002,
+ 0xe80, 0x0f000000, 0x00000002,
+ 0x90c, 0x000000ff, 0x00000011,
+ 0xc04, 0x000000ff, 0x00000011,
+ 0xd04, 0x0000000f, 0x00000001,
+ 0x1f4, 0xffff0000, 0x00007777,
+ 0x234, 0xf8000000, 0x0000000a,
+};
+
+u32 rtl8192sephy_changeto_1t2rarray[PHY_CHANGETO_1T2RARRAYLENGTH] = {
+ 0x804, 0x0000000f, 0x00000003,
+ 0x824, 0x00f0000f, 0x00300004,
+ 0x82c, 0x00f0000f, 0x00300002,
+ 0x870, 0x04000000, 0x00000001,
+ 0x864, 0x00000400, 0x00000000,
+ 0x878, 0x000f000f, 0x00000002,
+ 0xe74, 0x0f000000, 0x00000002,
+ 0xe78, 0x0f000000, 0x00000002,
+ 0xe7c, 0x0f000000, 0x00000002,
+ 0xe80, 0x0f000000, 0x00000002,
+ 0x90c, 0x000000ff, 0x00000011,
+ 0xc04, 0x000000ff, 0x00000033,
+ 0xd04, 0x0000000f, 0x00000003,
+ 0x1f4, 0xffff0000, 0x00007777,
+ 0x234, 0xf8000000, 0x0000000a,
+};
+
+u32 rtl8192sephy_reg_array_pg[PHY_REG_ARRAY_PGLENGTH] = {
+ 0xe00, 0xffffffff, 0x06090909,
+ 0xe04, 0xffffffff, 0x00030406,
+ 0xe08, 0x0000ff00, 0x00000000,
+ 0xe10, 0xffffffff, 0x0a0c0d0e,
+ 0xe14, 0xffffffff, 0x04070809,
+ 0xe18, 0xffffffff, 0x0a0c0d0e,
+ 0xe1c, 0xffffffff, 0x04070809,
+ 0xe00, 0xffffffff, 0x04040404,
+ 0xe04, 0xffffffff, 0x00020204,
+ 0xe08, 0x0000ff00, 0x00000000,
+ 0xe10, 0xffffffff, 0x02040404,
+ 0xe14, 0xffffffff, 0x00000002,
+ 0xe18, 0xffffffff, 0x02040404,
+ 0xe1c, 0xffffffff, 0x00000002,
+ 0xe00, 0xffffffff, 0x04040404,
+ 0xe04, 0xffffffff, 0x00020204,
+ 0xe08, 0x0000ff00, 0x00000000,
+ 0xe10, 0xffffffff, 0x02040404,
+ 0xe14, 0xffffffff, 0x00000002,
+ 0xe18, 0xffffffff, 0x02040404,
+ 0xe1c, 0xffffffff, 0x00000002,
+ 0xe00, 0xffffffff, 0x02020202,
+ 0xe04, 0xffffffff, 0x00020202,
+ 0xe08, 0x0000ff00, 0x00000000,
+ 0xe10, 0xffffffff, 0x02020202,
+ 0xe14, 0xffffffff, 0x00000002,
+ 0xe18, 0xffffffff, 0x02020202,
+ 0xe1c, 0xffffffff, 0x00000002,
+};
+
+u32 rtl8192seradioa_1t_array[RADIOA_1T_ARRAYLENGTH] = {
+ 0x000, 0x00030159,
+ 0x001, 0x00030250,
+ 0x002, 0x00010000,
+ 0x010, 0x0008000f,
+ 0x011, 0x000231fc,
+ 0x010, 0x000c000f,
+ 0x011, 0x0003f9f8,
+ 0x010, 0x0002000f,
+ 0x011, 0x00020101,
+ 0x014, 0x0001093e,
+ 0x014, 0x0009093e,
+ 0x015, 0x0000f8f4,
+ 0x017, 0x000f6500,
+ 0x01a, 0x00013056,
+ 0x01b, 0x00060000,
+ 0x01c, 0x00000300,
+ 0x01e, 0x00031059,
+ 0x021, 0x00054000,
+ 0x022, 0x0000083c,
+ 0x023, 0x00001558,
+ 0x024, 0x00000060,
+ 0x025, 0x00022583,
+ 0x026, 0x0000f200,
+ 0x027, 0x000eacf1,
+ 0x028, 0x0009bd54,
+ 0x029, 0x00004582,
+ 0x02a, 0x00000001,
+ 0x02b, 0x00021334,
+ 0x02a, 0x00000000,
+ 0x02b, 0x0000000a,
+ 0x02a, 0x00000001,
+ 0x02b, 0x00000808,
+ 0x02b, 0x00053333,
+ 0x02c, 0x0000000c,
+ 0x02a, 0x00000002,
+ 0x02b, 0x00000808,
+ 0x02b, 0x0005b333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000003,
+ 0x02b, 0x00000808,
+ 0x02b, 0x00063333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000004,
+ 0x02b, 0x00000808,
+ 0x02b, 0x0006b333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000005,
+ 0x02b, 0x00000709,
+ 0x02b, 0x00053333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000006,
+ 0x02b, 0x00000709,
+ 0x02b, 0x0005b333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000007,
+ 0x02b, 0x00000709,
+ 0x02b, 0x00063333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000008,
+ 0x02b, 0x00000709,
+ 0x02b, 0x0006b333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000009,
+ 0x02b, 0x0000060a,
+ 0x02b, 0x00053333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x0000000a,
+ 0x02b, 0x0000060a,
+ 0x02b, 0x0005b333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x0000000b,
+ 0x02b, 0x0000060a,
+ 0x02b, 0x00063333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x0000000c,
+ 0x02b, 0x0000060a,
+ 0x02b, 0x0006b333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x0000000d,
+ 0x02b, 0x0000050b,
+ 0x02b, 0x00053333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x0000000e,
+ 0x02b, 0x0000050b,
+ 0x02b, 0x00066623,
+ 0x02c, 0x0000001a,
+ 0x02a, 0x000e4000,
+ 0x030, 0x00020000,
+ 0x031, 0x000b9631,
+ 0x032, 0x0000130d,
+ 0x033, 0x00000187,
+ 0x013, 0x00019e6c,
+ 0x013, 0x00015e94,
+ 0x000, 0x00010159,
+ 0x018, 0x0000f401,
+ 0x0fe, 0x00000000,
+ 0x01e, 0x0003105b,
+ 0x0fe, 0x00000000,
+ 0x000, 0x00030159,
+ 0x010, 0x0004000f,
+ 0x011, 0x000203f9,
+};
+
+u32 rtl8192seradiob_array[RADIOB_ARRAYLENGTH] = {
+ 0x000, 0x00030159,
+ 0x001, 0x00001041,
+ 0x002, 0x00011000,
+ 0x005, 0x00080fc0,
+ 0x007, 0x000fc803,
+ 0x013, 0x00017cb0,
+ 0x013, 0x00011cc0,
+ 0x013, 0x0000dc60,
+ 0x013, 0x00008c60,
+ 0x013, 0x00004450,
+ 0x013, 0x00000020,
+};
+
+u32 rtl8192seradiob_gm_array[RADIOB_GM_ARRAYLENGTH] = {
+ 0x000, 0x00030159,
+ 0x001, 0x00001041,
+ 0x002, 0x00011000,
+ 0x005, 0x00080fc0,
+ 0x007, 0x000fc803,
+};
+
+u32 rtl8192semac_2t_array[MAC_2T_ARRAYLENGTH] = {
+ 0x020, 0x00000035,
+ 0x048, 0x0000000e,
+ 0x049, 0x000000f0,
+ 0x04a, 0x00000077,
+ 0x04b, 0x00000083,
+ 0x0b5, 0x00000021,
+ 0x0dc, 0x000000ff,
+ 0x0dd, 0x000000ff,
+ 0x0de, 0x000000ff,
+ 0x0df, 0x000000ff,
+ 0x116, 0x00000000,
+ 0x117, 0x00000000,
+ 0x118, 0x00000000,
+ 0x119, 0x00000000,
+ 0x11a, 0x00000000,
+ 0x11b, 0x00000000,
+ 0x11c, 0x00000000,
+ 0x11d, 0x00000000,
+ 0x160, 0x0000000b,
+ 0x161, 0x0000000b,
+ 0x162, 0x0000000b,
+ 0x163, 0x0000000b,
+ 0x164, 0x0000000b,
+ 0x165, 0x0000000b,
+ 0x166, 0x0000000b,
+ 0x167, 0x0000000b,
+ 0x168, 0x0000000b,
+ 0x169, 0x0000000b,
+ 0x16a, 0x0000000b,
+ 0x16b, 0x0000000b,
+ 0x16c, 0x0000000b,
+ 0x16d, 0x0000000b,
+ 0x16e, 0x0000000b,
+ 0x16f, 0x0000000b,
+ 0x170, 0x0000000b,
+ 0x171, 0x0000000b,
+ 0x172, 0x0000000b,
+ 0x173, 0x0000000b,
+ 0x174, 0x0000000b,
+ 0x175, 0x0000000b,
+ 0x176, 0x0000000b,
+ 0x177, 0x0000000b,
+ 0x178, 0x0000000b,
+ 0x179, 0x0000000b,
+ 0x17a, 0x0000000b,
+ 0x17b, 0x0000000b,
+ 0x17c, 0x0000000b,
+ 0x17d, 0x0000000b,
+ 0x17e, 0x0000000b,
+ 0x17f, 0x0000000b,
+ 0x236, 0x0000000c,
+ 0x503, 0x00000022,
+ 0x560, 0x00000000,
+};
+
+u32 rtl8192seagctab_array[AGCTAB_ARRAYLENGTH] = {
+ 0xc78, 0x7f000001,
+ 0xc78, 0x7f010001,
+ 0xc78, 0x7e020001,
+ 0xc78, 0x7d030001,
+ 0xc78, 0x7c040001,
+ 0xc78, 0x7b050001,
+ 0xc78, 0x7a060001,
+ 0xc78, 0x79070001,
+ 0xc78, 0x78080001,
+ 0xc78, 0x77090001,
+ 0xc78, 0x760a0001,
+ 0xc78, 0x750b0001,
+ 0xc78, 0x740c0001,
+ 0xc78, 0x730d0001,
+ 0xc78, 0x720e0001,
+ 0xc78, 0x710f0001,
+ 0xc78, 0x70100001,
+ 0xc78, 0x6f110001,
+ 0xc78, 0x6f120001,
+ 0xc78, 0x6e130001,
+ 0xc78, 0x6d140001,
+ 0xc78, 0x6d150001,
+ 0xc78, 0x6c160001,
+ 0xc78, 0x6b170001,
+ 0xc78, 0x6a180001,
+ 0xc78, 0x6a190001,
+ 0xc78, 0x691a0001,
+ 0xc78, 0x681b0001,
+ 0xc78, 0x671c0001,
+ 0xc78, 0x661d0001,
+ 0xc78, 0x651e0001,
+ 0xc78, 0x641f0001,
+ 0xc78, 0x63200001,
+ 0xc78, 0x4c210001,
+ 0xc78, 0x4b220001,
+ 0xc78, 0x4a230001,
+ 0xc78, 0x49240001,
+ 0xc78, 0x48250001,
+ 0xc78, 0x47260001,
+ 0xc78, 0x46270001,
+ 0xc78, 0x45280001,
+ 0xc78, 0x44290001,
+ 0xc78, 0x2c2a0001,
+ 0xc78, 0x2b2b0001,
+ 0xc78, 0x2a2c0001,
+ 0xc78, 0x292d0001,
+ 0xc78, 0x282e0001,
+ 0xc78, 0x272f0001,
+ 0xc78, 0x26300001,
+ 0xc78, 0x25310001,
+ 0xc78, 0x24320001,
+ 0xc78, 0x23330001,
+ 0xc78, 0x22340001,
+ 0xc78, 0x09350001,
+ 0xc78, 0x08360001,
+ 0xc78, 0x07370001,
+ 0xc78, 0x06380001,
+ 0xc78, 0x05390001,
+ 0xc78, 0x043a0001,
+ 0xc78, 0x033b0001,
+ 0xc78, 0x023c0001,
+ 0xc78, 0x013d0001,
+ 0xc78, 0x003e0001,
+ 0xc78, 0x003f0001,
+ 0xc78, 0x7f400001,
+ 0xc78, 0x7f410001,
+ 0xc78, 0x7e420001,
+ 0xc78, 0x7d430001,
+ 0xc78, 0x7c440001,
+ 0xc78, 0x7b450001,
+ 0xc78, 0x7a460001,
+ 0xc78, 0x79470001,
+ 0xc78, 0x78480001,
+ 0xc78, 0x77490001,
+ 0xc78, 0x764a0001,
+ 0xc78, 0x754b0001,
+ 0xc78, 0x744c0001,
+ 0xc78, 0x734d0001,
+ 0xc78, 0x724e0001,
+ 0xc78, 0x714f0001,
+ 0xc78, 0x70500001,
+ 0xc78, 0x6f510001,
+ 0xc78, 0x6f520001,
+ 0xc78, 0x6e530001,
+ 0xc78, 0x6d540001,
+ 0xc78, 0x6d550001,
+ 0xc78, 0x6c560001,
+ 0xc78, 0x6b570001,
+ 0xc78, 0x6a580001,
+ 0xc78, 0x6a590001,
+ 0xc78, 0x695a0001,
+ 0xc78, 0x685b0001,
+ 0xc78, 0x675c0001,
+ 0xc78, 0x665d0001,
+ 0xc78, 0x655e0001,
+ 0xc78, 0x645f0001,
+ 0xc78, 0x63600001,
+ 0xc78, 0x4c610001,
+ 0xc78, 0x4b620001,
+ 0xc78, 0x4a630001,
+ 0xc78, 0x49640001,
+ 0xc78, 0x48650001,
+ 0xc78, 0x47660001,
+ 0xc78, 0x46670001,
+ 0xc78, 0x45680001,
+ 0xc78, 0x44690001,
+ 0xc78, 0x2c6a0001,
+ 0xc78, 0x2b6b0001,
+ 0xc78, 0x2a6c0001,
+ 0xc78, 0x296d0001,
+ 0xc78, 0x286e0001,
+ 0xc78, 0x276f0001,
+ 0xc78, 0x26700001,
+ 0xc78, 0x25710001,
+ 0xc78, 0x24720001,
+ 0xc78, 0x23730001,
+ 0xc78, 0x22740001,
+ 0xc78, 0x09750001,
+ 0xc78, 0x08760001,
+ 0xc78, 0x07770001,
+ 0xc78, 0x06780001,
+ 0xc78, 0x05790001,
+ 0xc78, 0x047a0001,
+ 0xc78, 0x037b0001,
+ 0xc78, 0x027c0001,
+ 0xc78, 0x017d0001,
+ 0xc78, 0x007e0001,
+ 0xc78, 0x007f0001,
+ 0xc78, 0x3000001e,
+ 0xc78, 0x3001001e,
+ 0xc78, 0x3002001e,
+ 0xc78, 0x3003001e,
+ 0xc78, 0x3004001e,
+ 0xc78, 0x3405001e,
+ 0xc78, 0x3806001e,
+ 0xc78, 0x3e07001e,
+ 0xc78, 0x3e08001e,
+ 0xc78, 0x4409001e,
+ 0xc78, 0x460a001e,
+ 0xc78, 0x480b001e,
+ 0xc78, 0x480c001e,
+ 0xc78, 0x4e0d001e,
+ 0xc78, 0x560e001e,
+ 0xc78, 0x5a0f001e,
+ 0xc78, 0x5e10001e,
+ 0xc78, 0x6211001e,
+ 0xc78, 0x6c12001e,
+ 0xc78, 0x7213001e,
+ 0xc78, 0x7214001e,
+ 0xc78, 0x7215001e,
+ 0xc78, 0x7216001e,
+ 0xc78, 0x7217001e,
+ 0xc78, 0x7218001e,
+ 0xc78, 0x7219001e,
+ 0xc78, 0x721a001e,
+ 0xc78, 0x721b001e,
+ 0xc78, 0x721c001e,
+ 0xc78, 0x721d001e,
+ 0xc78, 0x721e001e,
+ 0xc78, 0x721f001e,
+};
+
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/table.h b/drivers/net/wireless/rtlwifi/rtl8192se/table.h
new file mode 100644
index 000000000000..b4ed6d951ebb
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/table.h
@@ -0,0 +1,49 @@
+/******************************************************************************
+ * 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>
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ ******************************************************************************/
+#ifndef __INC_HAL8192SE_FW_IMG_H
+#define __INC_HAL8192SE_FW_IMG_H
+
+#include <linux/types.h>
+
+/*Created on 2010/ 4/12, 5:56*/
+
+#define PHY_REG_2T2RARRAYLENGTH 372
+extern u32 rtl8192sephy_reg_2t2rarray[PHY_REG_2T2RARRAYLENGTH];
+#define PHY_CHANGETO_1T1RARRAYLENGTH 48
+extern u32 rtl8192sephy_changeto_1t1rarray[PHY_CHANGETO_1T1RARRAYLENGTH];
+#define PHY_CHANGETO_1T2RARRAYLENGTH 45
+extern u32 rtl8192sephy_changeto_1t2rarray[PHY_CHANGETO_1T2RARRAYLENGTH];
+#define PHY_REG_ARRAY_PGLENGTH 84
+extern u32 rtl8192sephy_reg_array_pg[PHY_REG_ARRAY_PGLENGTH];
+#define RADIOA_1T_ARRAYLENGTH 202
+extern u32 rtl8192seradioa_1t_array[RADIOA_1T_ARRAYLENGTH];
+#define RADIOB_ARRAYLENGTH 22
+extern u32 rtl8192seradiob_array[RADIOB_ARRAYLENGTH];
+#define RADIOB_GM_ARRAYLENGTH 10
+extern u32 rtl8192seradiob_gm_array[RADIOB_GM_ARRAYLENGTH];
+#define MAC_2T_ARRAYLENGTH 106
+extern u32 rtl8192semac_2t_array[MAC_2T_ARRAYLENGTH];
+#define AGCTAB_ARRAYLENGTH 320
+extern u32 rtl8192seagctab_array[AGCTAB_ARRAYLENGTH];
+
+#endif
+
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
new file mode 100644
index 000000000000..5cf442373d46
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
@@ -0,0 +1,976 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../base.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "fw.h"
+#include "trx.h"
+#include "led.h"
+
+static u8 _rtl92se_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 skb_queue)
+{
+ __le16 fc = rtl_get_fc(skb);
+
+ if (unlikely(ieee80211_is_beacon(fc)))
+ return QSLT_BEACON;
+ if (ieee80211_is_mgmt(fc))
+ return QSLT_MGNT;
+ if (ieee80211_is_nullfunc(fc))
+ return QSLT_HIGH;
+
+ return skb->priority;
+}
+
+static int _rtl92se_rate_mapping(bool isht, u8 desc_rate, bool first_ampdu)
+{
+ int rate_idx = 0;
+
+ if (first_ampdu) {
+ if (false == isht) {
+ switch (desc_rate) {
+ case DESC92S_RATE1M:
+ rate_idx = 0;
+ break;
+ case DESC92S_RATE2M:
+ rate_idx = 1;
+ break;
+ case DESC92S_RATE5_5M:
+ rate_idx = 2;
+ break;
+ case DESC92S_RATE11M:
+ rate_idx = 3;
+ break;
+ case DESC92S_RATE6M:
+ rate_idx = 4;
+ break;
+ case DESC92S_RATE9M:
+ rate_idx = 5;
+ break;
+ case DESC92S_RATE12M:
+ rate_idx = 6;
+ break;
+ case DESC92S_RATE18M:
+ rate_idx = 7;
+ break;
+ case DESC92S_RATE24M:
+ rate_idx = 8;
+ break;
+ case DESC92S_RATE36M:
+ rate_idx = 9;
+ break;
+ case DESC92S_RATE48M:
+ rate_idx = 10;
+ break;
+ case DESC92S_RATE54M:
+ rate_idx = 11;
+ break;
+ default:
+ rate_idx = 0;
+ break;
+ }
+ } else {
+ rate_idx = 11;
+ }
+
+ return rate_idx;
+ }
+
+ switch (desc_rate) {
+ case DESC92S_RATE1M:
+ rate_idx = 0;
+ break;
+ case DESC92S_RATE2M:
+ rate_idx = 1;
+ break;
+ case DESC92S_RATE5_5M:
+ rate_idx = 2;
+ break;
+ case DESC92S_RATE11M:
+ rate_idx = 3;
+ break;
+ case DESC92S_RATE6M:
+ rate_idx = 4;
+ break;
+ case DESC92S_RATE9M:
+ rate_idx = 5;
+ break;
+ case DESC92S_RATE12M:
+ rate_idx = 6;
+ break;
+ case DESC92S_RATE18M:
+ rate_idx = 7;
+ break;
+ case DESC92S_RATE24M:
+ rate_idx = 8;
+ break;
+ case DESC92S_RATE36M:
+ rate_idx = 9;
+ break;
+ case DESC92S_RATE48M:
+ rate_idx = 10;
+ break;
+ case DESC92S_RATE54M:
+ rate_idx = 11;
+ break;
+ default:
+ rate_idx = 11;
+ break;
+ }
+ return rate_idx;
+}
+
+static u8 _rtl92s_query_rxpwrpercentage(char antpower)
+{
+ if ((antpower <= -100) || (antpower >= 20))
+ return 0;
+ else if (antpower >= 0)
+ return 100;
+ else
+ return 100 + antpower;
+}
+
+static u8 _rtl92s_evm_db_to_percentage(char value)
+{
+ char ret_val;
+ ret_val = value;
+
+ if (ret_val >= 0)
+ ret_val = 0;
+
+ if (ret_val <= -33)
+ ret_val = -33;
+
+ ret_val = 0 - ret_val;
+ ret_val *= 3;
+
+ if (ret_val == 99)
+ ret_val = 100;
+
+ return ret_val;
+}
+
+static long _rtl92se_translate_todbm(struct ieee80211_hw *hw,
+ u8 signal_strength_index)
+{
+ long signal_power;
+
+ signal_power = (long)((signal_strength_index + 1) >> 1);
+ signal_power -= 95;
+ return signal_power;
+}
+
+static long _rtl92se_signal_scale_mapping(struct ieee80211_hw *hw,
+ long currsig)
+{
+ long retsig = 0;
+
+ /* Step 1. Scale mapping. */
+ if (currsig > 47)
+ retsig = 100;
+ else if (currsig > 14 && currsig <= 47)
+ retsig = 100 - ((47 - currsig) * 3) / 2;
+ else if (currsig > 2 && currsig <= 14)
+ retsig = 48 - ((14 - currsig) * 15) / 7;
+ else if (currsig >= 0)
+ retsig = currsig * 9 + 1;
+
+ return retsig;
+}
+
+
+static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
+ struct rtl_stats *pstats, u8 *pdesc,
+ struct rx_fwinfo *p_drvinfo,
+ bool packet_match_bssid,
+ bool packet_toself,
+ bool packet_beacon)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct phy_sts_cck_8192s_t *cck_buf;
+ s8 rx_pwr_all = 0, rx_pwr[4];
+ u8 rf_rx_num = 0, evm, pwdb_all;
+ u8 i, max_spatial_stream;
+ u32 rssi, total_rssi = 0;
+ bool in_powersavemode = false;
+ bool is_cck_rate;
+
+ is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc);
+ pstats->packet_matchbssid = packet_match_bssid;
+ pstats->packet_toself = packet_toself;
+ pstats->is_cck = is_cck_rate;
+ pstats->packet_beacon = packet_beacon;
+ pstats->is_cck = is_cck_rate;
+ pstats->rx_mimo_signalquality[0] = -1;
+ pstats->rx_mimo_signalquality[1] = -1;
+
+ if (is_cck_rate) {
+ u8 report, cck_highpwr;
+ cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo;
+
+ if (!in_powersavemode)
+ cck_highpwr = (u8) rtl_get_bbreg(hw,
+ RFPGA0_XA_HSSIPARAMETER2,
+ 0x200);
+ else
+ cck_highpwr = false;
+
+ if (!cck_highpwr) {
+ u8 cck_agc_rpt = cck_buf->cck_agc_rpt;
+ report = cck_buf->cck_agc_rpt & 0xc0;
+ report = report >> 6;
+ switch (report) {
+ case 0x3:
+ rx_pwr_all = -40 - (cck_agc_rpt & 0x3e);
+ break;
+ case 0x2:
+ rx_pwr_all = -20 - (cck_agc_rpt & 0x3e);
+ break;
+ case 0x1:
+ rx_pwr_all = -2 - (cck_agc_rpt & 0x3e);
+ break;
+ case 0x0:
+ rx_pwr_all = 14 - (cck_agc_rpt & 0x3e);
+ break;
+ }
+ } else {
+ u8 cck_agc_rpt = cck_buf->cck_agc_rpt;
+ report = p_drvinfo->cfosho[0] & 0x60;
+ report = report >> 5;
+ switch (report) {
+ case 0x3:
+ rx_pwr_all = -40 - ((cck_agc_rpt & 0x1f) << 1);
+ break;
+ case 0x2:
+ rx_pwr_all = -20 - ((cck_agc_rpt & 0x1f) << 1);
+ break;
+ case 0x1:
+ rx_pwr_all = -2 - ((cck_agc_rpt & 0x1f) << 1);
+ break;
+ case 0x0:
+ rx_pwr_all = 14 - ((cck_agc_rpt & 0x1f) << 1);
+ break;
+ }
+ }
+
+ pwdb_all = _rtl92s_query_rxpwrpercentage(rx_pwr_all);
+
+ /* CCK gain is smaller than OFDM/MCS gain, */
+ /* so we add gain diff by experiences, the val is 6 */
+ pwdb_all += 6;
+ if (pwdb_all > 100)
+ pwdb_all = 100;
+ /* modify the offset to make the same gain index with OFDM. */
+ if (pwdb_all > 34 && pwdb_all <= 42)
+ pwdb_all -= 2;
+ else if (pwdb_all > 26 && pwdb_all <= 34)
+ pwdb_all -= 6;
+ else if (pwdb_all > 14 && pwdb_all <= 26)
+ pwdb_all -= 8;
+ else if (pwdb_all > 4 && pwdb_all <= 14)
+ pwdb_all -= 4;
+
+ pstats->rx_pwdb_all = pwdb_all;
+ pstats->recvsignalpower = rx_pwr_all;
+
+ if (packet_match_bssid) {
+ u8 sq;
+ if (pstats->rx_pwdb_all > 40) {
+ sq = 100;
+ } else {
+ sq = cck_buf->sq_rpt;
+ if (sq > 64)
+ sq = 0;
+ else if (sq < 20)
+ sq = 100;
+ else
+ sq = ((64 - sq) * 100) / 44;
+ }
+
+ pstats->signalquality = sq;
+ pstats->rx_mimo_signalquality[0] = sq;
+ pstats->rx_mimo_signalquality[1] = -1;
+ }
+ } else {
+ rtlpriv->dm.rfpath_rxenable[0] =
+ rtlpriv->dm.rfpath_rxenable[1] = true;
+ for (i = RF90_PATH_A; i < RF90_PATH_MAX; i++) {
+ if (rtlpriv->dm.rfpath_rxenable[i])
+ rf_rx_num++;
+
+ rx_pwr[i] = ((p_drvinfo->gain_trsw[i] &
+ 0x3f) * 2) - 110;
+ rssi = _rtl92s_query_rxpwrpercentage(rx_pwr[i]);
+ total_rssi += rssi;
+ rtlpriv->stats.rx_snr_db[i] =
+ (long)(p_drvinfo->rxsnr[i] / 2);
+
+ if (packet_match_bssid)
+ pstats->rx_mimo_signalstrength[i] = (u8) rssi;
+ }
+
+ rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110;
+ pwdb_all = _rtl92s_query_rxpwrpercentage(rx_pwr_all);
+ pstats->rx_pwdb_all = pwdb_all;
+ pstats->rxpower = rx_pwr_all;
+ pstats->recvsignalpower = rx_pwr_all;
+
+ if (GET_RX_STATUS_DESC_RX_HT(pdesc) &&
+ GET_RX_STATUS_DESC_RX_MCS(pdesc) >= DESC92S_RATEMCS8 &&
+ GET_RX_STATUS_DESC_RX_MCS(pdesc) <= DESC92S_RATEMCS15)
+ max_spatial_stream = 2;
+ else
+ max_spatial_stream = 1;
+
+ for (i = 0; i < max_spatial_stream; i++) {
+ evm = _rtl92s_evm_db_to_percentage(p_drvinfo->rxevm[i]);
+
+ if (packet_match_bssid) {
+ if (i == 0)
+ pstats->signalquality = (u8)(evm &
+ 0xff);
+ pstats->rx_mimo_signalquality[i] =
+ (u8) (evm & 0xff);
+ }
+ }
+ }
+
+ if (is_cck_rate)
+ pstats->signalstrength = (u8)(_rtl92se_signal_scale_mapping(hw,
+ pwdb_all));
+ else if (rf_rx_num != 0)
+ pstats->signalstrength = (u8) (_rtl92se_signal_scale_mapping(hw,
+ total_rssi /= rf_rx_num));
+}
+
+static void _rtl92se_process_ui_rssi(struct ieee80211_hw *hw,
+ struct rtl_stats *pstats)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u8 rfpath;
+ u32 last_rssi, tmpval;
+
+ if (pstats->packet_toself || pstats->packet_beacon) {
+ rtlpriv->stats.rssi_calculate_cnt++;
+
+ if (rtlpriv->stats.ui_rssi.total_num++ >=
+ PHY_RSSI_SLID_WIN_MAX) {
+ rtlpriv->stats.ui_rssi.total_num =
+ PHY_RSSI_SLID_WIN_MAX;
+ last_rssi = rtlpriv->stats.ui_rssi.elements[
+ rtlpriv->stats.ui_rssi.index];
+ rtlpriv->stats.ui_rssi.total_val -= last_rssi;
+ }
+
+ rtlpriv->stats.ui_rssi.total_val += pstats->signalstrength;
+ rtlpriv->stats.ui_rssi.elements[rtlpriv->stats.ui_rssi.index++]
+ = pstats->signalstrength;
+
+ if (rtlpriv->stats.ui_rssi.index >= PHY_RSSI_SLID_WIN_MAX)
+ rtlpriv->stats.ui_rssi.index = 0;
+
+ tmpval = rtlpriv->stats.ui_rssi.total_val /
+ rtlpriv->stats.ui_rssi.total_num;
+ rtlpriv->stats.signal_strength = _rtl92se_translate_todbm(hw,
+ (u8) tmpval);
+ pstats->rssi = rtlpriv->stats.signal_strength;
+ }
+
+ if (!pstats->is_cck && pstats->packet_toself) {
+ for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath;
+ rfpath++) {
+ if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) {
+ rtlpriv->stats.rx_rssi_percentage[rfpath] =
+ pstats->rx_mimo_signalstrength[rfpath];
+
+ }
+
+ if (pstats->rx_mimo_signalstrength[rfpath] >
+ rtlpriv->stats.rx_rssi_percentage[rfpath]) {
+ rtlpriv->stats.rx_rssi_percentage[rfpath] =
+ ((rtlpriv->stats.rx_rssi_percentage[rfpath]
+ * (RX_SMOOTH_FACTOR - 1)) +
+ (pstats->rx_mimo_signalstrength[rfpath])) /
+ (RX_SMOOTH_FACTOR);
+
+ rtlpriv->stats.rx_rssi_percentage[rfpath] =
+ rtlpriv->stats.rx_rssi_percentage[rfpath]
+ + 1;
+ } else {
+ rtlpriv->stats.rx_rssi_percentage[rfpath] =
+ ((rtlpriv->stats.rx_rssi_percentage[rfpath]
+ * (RX_SMOOTH_FACTOR - 1)) +
+ (pstats->rx_mimo_signalstrength[rfpath])) /
+ (RX_SMOOTH_FACTOR);
+ }
+
+ }
+ }
+}
+
+static void _rtl92se_update_rxsignalstatistics(struct ieee80211_hw *hw,
+ struct rtl_stats *pstats)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ int weighting = 0;
+
+ if (rtlpriv->stats.recv_signal_power == 0)
+ rtlpriv->stats.recv_signal_power = pstats->recvsignalpower;
+
+ if (pstats->recvsignalpower > rtlpriv->stats.recv_signal_power)
+ weighting = 5;
+ else if (pstats->recvsignalpower < rtlpriv->stats.recv_signal_power)
+ weighting = (-5);
+
+ rtlpriv->stats.recv_signal_power = (rtlpriv->stats.recv_signal_power * 5
+ + pstats->recvsignalpower +
+ weighting) / 6;
+}
+
+static void _rtl92se_process_pwdb(struct ieee80211_hw *hw,
+ struct rtl_stats *pstats)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ long undec_sm_pwdb = 0;
+
+ if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+ return;
+ } else {
+ undec_sm_pwdb =
+ rtlpriv->dm.undecorated_smoothed_pwdb;
+ }
+
+ if (pstats->packet_toself || pstats->packet_beacon) {
+ if (undec_sm_pwdb < 0)
+ undec_sm_pwdb = pstats->rx_pwdb_all;
+
+ if (pstats->rx_pwdb_all > (u32) undec_sm_pwdb) {
+ undec_sm_pwdb =
+ (((undec_sm_pwdb) *
+ (RX_SMOOTH_FACTOR - 1)) +
+ (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
+
+ undec_sm_pwdb = undec_sm_pwdb + 1;
+ } else {
+ undec_sm_pwdb = (((undec_sm_pwdb) *
+ (RX_SMOOTH_FACTOR - 1)) + (pstats->rx_pwdb_all)) /
+ (RX_SMOOTH_FACTOR);
+ }
+
+ rtlpriv->dm.undecorated_smoothed_pwdb = undec_sm_pwdb;
+ _rtl92se_update_rxsignalstatistics(hw, pstats);
+ }
+}
+
+static void rtl_92s_process_streams(struct ieee80211_hw *hw,
+ struct rtl_stats *pstats)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 stream;
+
+ for (stream = 0; stream < 2; stream++) {
+ if (pstats->rx_mimo_signalquality[stream] != -1) {
+ if (rtlpriv->stats.rx_evm_percentage[stream] == 0) {
+ rtlpriv->stats.rx_evm_percentage[stream] =
+ pstats->rx_mimo_signalquality[stream];
+ }
+
+ rtlpriv->stats.rx_evm_percentage[stream] =
+ ((rtlpriv->stats.rx_evm_percentage[stream] *
+ (RX_SMOOTH_FACTOR - 1)) +
+ (pstats->rx_mimo_signalquality[stream] *
+ 1)) / (RX_SMOOTH_FACTOR);
+ }
+ }
+}
+
+static void _rtl92se_process_ui_link_quality(struct ieee80211_hw *hw,
+ struct rtl_stats *pstats)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 last_evm = 0, tmpval;
+
+ if (pstats->signalquality != 0) {
+ if (pstats->packet_toself || pstats->packet_beacon) {
+
+ if (rtlpriv->stats.ui_link_quality.total_num++ >=
+ PHY_LINKQUALITY_SLID_WIN_MAX) {
+ rtlpriv->stats.ui_link_quality.total_num =
+ PHY_LINKQUALITY_SLID_WIN_MAX;
+ last_evm =
+ rtlpriv->stats.ui_link_quality.elements[
+ rtlpriv->stats.ui_link_quality.index];
+ rtlpriv->stats.ui_link_quality.total_val -=
+ last_evm;
+ }
+
+ rtlpriv->stats.ui_link_quality.total_val +=
+ pstats->signalquality;
+ rtlpriv->stats.ui_link_quality.elements[
+ rtlpriv->stats.ui_link_quality.index++] =
+ pstats->signalquality;
+
+ if (rtlpriv->stats.ui_link_quality.index >=
+ PHY_LINKQUALITY_SLID_WIN_MAX)
+ rtlpriv->stats.ui_link_quality.index = 0;
+
+ tmpval = rtlpriv->stats.ui_link_quality.total_val /
+ rtlpriv->stats.ui_link_quality.total_num;
+ rtlpriv->stats.signal_quality = tmpval;
+
+ rtlpriv->stats.last_sigstrength_inpercent = tmpval;
+
+ rtl_92s_process_streams(hw, pstats);
+
+ }
+ }
+}
+
+static void _rtl92se_process_phyinfo(struct ieee80211_hw *hw,
+ u8 *buffer,
+ struct rtl_stats *pcurrent_stats)
+{
+
+ if (!pcurrent_stats->packet_matchbssid &&
+ !pcurrent_stats->packet_beacon)
+ return;
+
+ _rtl92se_process_ui_rssi(hw, pcurrent_stats);
+ _rtl92se_process_pwdb(hw, pcurrent_stats);
+ _rtl92se_process_ui_link_quality(hw, pcurrent_stats);
+}
+
+static void _rtl92se_translate_rx_signal_stuff(struct ieee80211_hw *hw,
+ struct sk_buff *skb, struct rtl_stats *pstats,
+ u8 *pdesc, struct rx_fwinfo *p_drvinfo)
+{
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+
+ struct ieee80211_hdr *hdr;
+ u8 *tmp_buf;
+ u8 *praddr;
+ u8 *psaddr;
+ __le16 fc;
+ u16 type, cfc;
+ bool packet_matchbssid, packet_toself, packet_beacon;
+
+ tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift;
+
+ hdr = (struct ieee80211_hdr *)tmp_buf;
+ fc = hdr->frame_control;
+ cfc = le16_to_cpu(fc);
+ type = WLAN_FC_GET_TYPE(fc);
+ praddr = hdr->addr1;
+ psaddr = hdr->addr2;
+
+ packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) &&
+ (!compare_ether_addr(mac->bssid, (cfc & IEEE80211_FCTL_TODS) ?
+ hdr->addr1 : (cfc & IEEE80211_FCTL_FROMDS) ?
+ hdr->addr2 : hdr->addr3)) && (!pstats->hwerror) &&
+ (!pstats->crc) && (!pstats->icv));
+
+ packet_toself = packet_matchbssid &&
+ (!compare_ether_addr(praddr, rtlefuse->dev_addr));
+
+ if (ieee80211_is_beacon(fc))
+ packet_beacon = true;
+
+ _rtl92se_query_rxphystatus(hw, pstats, pdesc, p_drvinfo,
+ packet_matchbssid, packet_toself, packet_beacon);
+ _rtl92se_process_phyinfo(hw, tmp_buf, pstats);
+}
+
+bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
+ struct ieee80211_rx_status *rx_status, u8 *pdesc,
+ struct sk_buff *skb)
+{
+ struct rx_fwinfo *p_drvinfo;
+ u32 phystatus = (u32)GET_RX_STATUS_DESC_PHY_STATUS(pdesc);
+
+ stats->length = (u16)GET_RX_STATUS_DESC_PKT_LEN(pdesc);
+ stats->rx_drvinfo_size = (u8)GET_RX_STATUS_DESC_DRVINFO_SIZE(pdesc) * 8;
+ stats->rx_bufshift = (u8)(GET_RX_STATUS_DESC_SHIFT(pdesc) & 0x03);
+ stats->icv = (u16)GET_RX_STATUS_DESC_ICV(pdesc);
+ stats->crc = (u16)GET_RX_STATUS_DESC_CRC32(pdesc);
+ stats->hwerror = (u16)(stats->crc | stats->icv);
+ stats->decrypted = !GET_RX_STATUS_DESC_SWDEC(pdesc);
+
+ stats->rate = (u8)GET_RX_STATUS_DESC_RX_MCS(pdesc);
+ stats->shortpreamble = (u16)GET_RX_STATUS_DESC_SPLCP(pdesc);
+ stats->isampdu = (bool)(GET_RX_STATUS_DESC_PAGGR(pdesc) == 1);
+ stats->timestamp_low = GET_RX_STATUS_DESC_TSFL(pdesc);
+ stats->rx_is40Mhzpacket = (bool)GET_RX_STATUS_DESC_BW(pdesc);
+
+ if (stats->hwerror)
+ return false;
+
+ rx_status->freq = hw->conf.channel->center_freq;
+ rx_status->band = hw->conf.channel->band;
+
+ if (GET_RX_STATUS_DESC_CRC32(pdesc))
+ rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+
+ if (!GET_RX_STATUS_DESC_SWDEC(pdesc))
+ rx_status->flag |= RX_FLAG_DECRYPTED;
+
+ if (GET_RX_STATUS_DESC_BW(pdesc))
+ rx_status->flag |= RX_FLAG_40MHZ;
+
+ if (GET_RX_STATUS_DESC_RX_HT(pdesc))
+ rx_status->flag |= RX_FLAG_HT;
+
+ rx_status->flag |= RX_FLAG_MACTIME_MPDU;
+
+ if (stats->decrypted)
+ rx_status->flag |= RX_FLAG_DECRYPTED;
+
+ rx_status->rate_idx = _rtl92se_rate_mapping((bool)
+ GET_RX_STATUS_DESC_RX_HT(pdesc),
+ (u8)GET_RX_STATUS_DESC_RX_MCS(pdesc),
+ (bool)GET_RX_STATUS_DESC_PAGGR(pdesc));
+
+
+ rx_status->mactime = GET_RX_STATUS_DESC_TSFL(pdesc);
+ if (phystatus == true) {
+ p_drvinfo = (struct rx_fwinfo *)(skb->data +
+ stats->rx_bufshift);
+ _rtl92se_translate_rx_signal_stuff(hw, skb, stats, pdesc,
+ p_drvinfo);
+ }
+
+ /*rx_status->qual = stats->signal; */
+ rx_status->signal = stats->rssi + 10;
+ /*rx_status->noise = -stats->noise; */
+
+ return true;
+}
+
+void rtl92se_tx_fill_desc(struct ieee80211_hw *hw,
+ struct ieee80211_hdr *hdr, u8 *pdesc_tx,
+ struct ieee80211_tx_info *info, struct sk_buff *skb,
+ u8 hw_queue, struct rtl_tcb_desc *ptcb_desc)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct ieee80211_sta *sta = info->control.sta;
+ u8 *pdesc = (u8 *) pdesc_tx;
+ u16 seq_number;
+ __le16 fc = hdr->frame_control;
+ u8 reserved_macid = 0;
+ u8 fw_qsel = _rtl92se_map_hwqueue_to_fwqueue(skb, hw_queue);
+ bool firstseg = (!(hdr->seq_ctrl & cpu_to_le16(IEEE80211_SCTL_FRAG)));
+ bool lastseg = (!(hdr->frame_control &
+ cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)));
+ dma_addr_t mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len,
+ PCI_DMA_TODEVICE);
+ u8 bw_40 = 0;
+
+ if (mac->opmode == NL80211_IFTYPE_STATION) {
+ bw_40 = mac->bw_40;
+ } else if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_ADHOC) {
+ if (sta)
+ bw_40 = sta->ht_cap.cap &
+ IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ }
+
+ seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
+
+ rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc);
+
+ CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE_RTL8192S);
+
+ if (firstseg) {
+ if (rtlpriv->dm.useramask) {
+ /* set txdesc macId */
+ if (ptcb_desc->mac_id < 32) {
+ SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id);
+ reserved_macid |= ptcb_desc->mac_id;
+ }
+ }
+ SET_TX_DESC_RSVD_MACID(pdesc, reserved_macid);
+
+ SET_TX_DESC_TXHT(pdesc, ((ptcb_desc->hw_rate >=
+ DESC92S_RATEMCS0) ? 1 : 0));
+
+ if (rtlhal->version == VERSION_8192S_ACUT) {
+ if (ptcb_desc->hw_rate == DESC92S_RATE1M ||
+ ptcb_desc->hw_rate == DESC92S_RATE2M ||
+ ptcb_desc->hw_rate == DESC92S_RATE5_5M ||
+ ptcb_desc->hw_rate == DESC92S_RATE11M) {
+ ptcb_desc->hw_rate = DESC92S_RATE12M;
+ }
+ }
+
+ SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate);
+
+ if (ptcb_desc->use_shortgi || ptcb_desc->use_shortpreamble)
+ SET_TX_DESC_TX_SHORT(pdesc, 0);
+
+ /* Aggregation related */
+ if (info->flags & IEEE80211_TX_CTL_AMPDU)
+ SET_TX_DESC_AGG_ENABLE(pdesc, 1);
+
+ /* For AMPDU, we must insert SSN into TX_DESC */
+ SET_TX_DESC_SEQ(pdesc, seq_number);
+
+ /* Protection mode related */
+ /* For 92S, if RTS/CTS are set, HW will execute RTS. */
+ /* We choose only one protection mode to execute */
+ SET_TX_DESC_RTS_ENABLE(pdesc, ((ptcb_desc->rts_enable &&
+ !ptcb_desc->cts_enable) ? 1 : 0));
+ SET_TX_DESC_CTS_ENABLE(pdesc, ((ptcb_desc->cts_enable) ?
+ 1 : 0));
+ SET_TX_DESC_RTS_STBC(pdesc, ((ptcb_desc->rts_stbc) ? 1 : 0));
+
+ SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate);
+ SET_TX_DESC_RTS_BANDWIDTH(pdesc, 0);
+ SET_TX_DESC_RTS_SUB_CARRIER(pdesc, ptcb_desc->rts_sc);
+ SET_TX_DESC_RTS_SHORT(pdesc, ((ptcb_desc->rts_rate <=
+ DESC92S_RATE54M) ?
+ (ptcb_desc->rts_use_shortpreamble ? 1 : 0)
+ : (ptcb_desc->rts_use_shortgi ? 1 : 0)));
+
+
+ /* Set Bandwidth and sub-channel settings. */
+ if (bw_40) {
+ if (ptcb_desc->packet_bw) {
+ SET_TX_DESC_TX_BANDWIDTH(pdesc, 1);
+ /* use duplicated mode */
+ SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0);
+ } else {
+ SET_TX_DESC_TX_BANDWIDTH(pdesc, 0);
+ SET_TX_DESC_TX_SUB_CARRIER(pdesc,
+ mac->cur_40_prime_sc);
+ }
+ } else {
+ SET_TX_DESC_TX_BANDWIDTH(pdesc, 0);
+ SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0);
+ }
+
+ /* 3 Fill necessary field in First Descriptor */
+ /*DWORD 0*/
+ SET_TX_DESC_LINIP(pdesc, 0);
+ SET_TX_DESC_OFFSET(pdesc, 32);
+ SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb->len);
+
+ /*DWORD 1*/
+ SET_TX_DESC_RA_BRSR_ID(pdesc, ptcb_desc->ratr_index);
+
+ /* Fill security related */
+ if (info->control.hw_key) {
+ struct ieee80211_key_conf *keyconf;
+
+ keyconf = info->control.hw_key;
+ switch (keyconf->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ SET_TX_DESC_SEC_TYPE(pdesc, 0x1);
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ SET_TX_DESC_SEC_TYPE(pdesc, 0x2);
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ SET_TX_DESC_SEC_TYPE(pdesc, 0x3);
+ break;
+ default:
+ SET_TX_DESC_SEC_TYPE(pdesc, 0x0);
+ break;
+
+ }
+ }
+
+ /* Set Packet ID */
+ SET_TX_DESC_PACKET_ID(pdesc, 0);
+
+ /* We will assign magement queue to BK. */
+ SET_TX_DESC_QUEUE_SEL(pdesc, fw_qsel);
+
+ /* Alwasy enable all rate fallback range */
+ SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F);
+
+ /* Fix: I don't kown why hw use 6.5M to tx when set it */
+ SET_TX_DESC_USER_RATE(pdesc,
+ ptcb_desc->use_driver_rate ? 1 : 0);
+
+ /* Set NON_QOS bit. */
+ if (!ieee80211_is_data_qos(fc))
+ SET_TX_DESC_NON_QOS(pdesc, 1);
+
+ }
+
+ /* Fill fields that are required to be initialized
+ * in all of the descriptors */
+ /*DWORD 0 */
+ SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0));
+ SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0));
+
+ /* DWORD 7 */
+ SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) skb->len);
+
+ /* DOWRD 8 */
+ SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping));
+
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, ("\n"));
+}
+
+void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
+ bool firstseg, bool lastseg, struct sk_buff *skb)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_tcb_desc *tcb_desc = (struct rtl_tcb_desc *)(skb->cb);
+
+ dma_addr_t mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len,
+ PCI_DMA_TODEVICE);
+
+ /* Clear all status */
+ CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_CMDDESC_SIZE_RTL8192S);
+
+ /* This bit indicate this packet is used for FW download. */
+ if (tcb_desc->cmd_or_init == DESC_PACKET_TYPE_INIT) {
+ /* For firmware downlaod we only need to set LINIP */
+ SET_TX_DESC_LINIP(pdesc, tcb_desc->last_inipkt);
+
+ /* 92SE must set as 1 for firmware download HW DMA error */
+ SET_TX_DESC_FIRST_SEG(pdesc, 1);
+ SET_TX_DESC_LAST_SEG(pdesc, 1);
+
+ /* 92SE need not to set TX packet size when firmware download */
+ SET_TX_DESC_PKT_SIZE(pdesc, (u16)(skb->len));
+ SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len));
+ SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping));
+
+ SET_TX_DESC_OWN(pdesc, 1);
+ } else { /* H2C Command Desc format (Host TXCMD) */
+ /* 92SE must set as 1 for firmware download HW DMA error */
+ SET_TX_DESC_FIRST_SEG(pdesc, 1);
+ SET_TX_DESC_LAST_SEG(pdesc, 1);
+
+ SET_TX_DESC_OFFSET(pdesc, 0x20);
+
+ /* Buffer size + command header */
+ SET_TX_DESC_PKT_SIZE(pdesc, (u16)(skb->len));
+ /* Fixed queue of H2C command */
+ SET_TX_DESC_QUEUE_SEL(pdesc, 0x13);
+
+ SET_BITS_TO_LE_4BYTE(skb->data, 24, 7, rtlhal->h2c_txcmd_seq);
+
+ SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len));
+ SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping));
+
+ SET_TX_DESC_OWN(pdesc, 1);
+
+ }
+}
+
+void rtl92se_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val)
+{
+ if (istx == true) {
+ switch (desc_name) {
+ case HW_DESC_OWN:
+ SET_TX_DESC_OWN(pdesc, 1);
+ break;
+ case HW_DESC_TX_NEXTDESC_ADDR:
+ SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *) val);
+ break;
+ default:
+ RT_ASSERT(false, ("ERR txdesc :%d not process\n",
+ desc_name));
+ break;
+ }
+ } else {
+ switch (desc_name) {
+ case HW_DESC_RXOWN:
+ SET_RX_STATUS_DESC_OWN(pdesc, 1);
+ break;
+ case HW_DESC_RXBUFF_ADDR:
+ SET_RX_STATUS__DESC_BUFF_ADDR(pdesc, *(u32 *) val);
+ break;
+ case HW_DESC_RXPKT_LEN:
+ SET_RX_STATUS_DESC_PKT_LEN(pdesc, *(u32 *) val);
+ break;
+ case HW_DESC_RXERO:
+ SET_RX_STATUS_DESC_EOR(pdesc, 1);
+ break;
+ default:
+ RT_ASSERT(false, ("ERR rxdesc :%d not process\n",
+ desc_name));
+ break;
+ }
+ }
+}
+
+u32 rtl92se_get_desc(u8 *desc, bool istx, u8 desc_name)
+{
+ u32 ret = 0;
+
+ if (istx == true) {
+ switch (desc_name) {
+ case HW_DESC_OWN:
+ ret = GET_TX_DESC_OWN(desc);
+ break;
+ case HW_DESC_TXBUFF_ADDR:
+ ret = GET_TX_DESC_TX_BUFFER_ADDRESS(desc);
+ break;
+ default:
+ RT_ASSERT(false, ("ERR txdesc :%d not process\n",
+ desc_name));
+ break;
+ }
+ } else {
+ switch (desc_name) {
+ case HW_DESC_OWN:
+ ret = GET_RX_STATUS_DESC_OWN(desc);
+ break;
+ case HW_DESC_RXPKT_LEN:
+ ret = GET_RX_STATUS_DESC_PKT_LEN(desc);
+ break;
+ default:
+ RT_ASSERT(false, ("ERR rxdesc :%d not process\n",
+ desc_name));
+ break;
+ }
+ }
+ return ret;
+}
+
+void rtl92se_tx_polling(struct ieee80211_hw *hw, u8 hw_queue)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ rtl_write_word(rtlpriv, TP_POLL, BIT(0) << (hw_queue));
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.h b/drivers/net/wireless/rtlwifi/rtl8192se/trx.h
new file mode 100644
index 000000000000..05862c51b861
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.h
@@ -0,0 +1,45 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#ifndef __REALTEK_PCI92SE_TRX_H__
+#define __REALTEK_PCI92SE_TRX_H__
+
+void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr,
+ u8 *pdesc, struct ieee80211_tx_info *info,
+ struct sk_buff *skb, u8 hw_queue,
+ struct rtl_tcb_desc *ptcb_desc);
+void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool firstseg,
+ bool lastseg, struct sk_buff *skb);
+bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
+ struct ieee80211_rx_status *rx_status, u8 *pdesc,
+ struct sk_buff *skb);
+void rtl92se_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val);
+u32 rtl92se_get_desc(u8 *pdesc, bool istx, u8 desc_name);
+void rtl92se_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c
index f5d85735d642..a9367eba1ea7 100644
--- a/drivers/net/wireless/rtlwifi/usb.c
+++ b/drivers/net/wireless/rtlwifi/usb.c
@@ -852,6 +852,7 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb,
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct rtl_tx_desc *pdesc = NULL;
+ struct rtl_tcb_desc tcb_desc;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
__le16 fc = hdr->frame_control;
u8 *pda_addr = hdr->addr1;
@@ -860,8 +861,17 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb,
u8 tid = 0;
u16 seq_number = 0;
- if (ieee80211_is_mgmt(fc))
- rtl_tx_mgmt_proc(hw, skb);
+ if (ieee80211_is_auth(fc)) {
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n"));
+ rtl_ips_nic_on(hw);
+ }
+
+ if (rtlpriv->psc.sw_ps_enabled) {
+ if (ieee80211_is_data(fc) && !ieee80211_is_nullfunc(fc) &&
+ !ieee80211_has_pm(fc))
+ hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
+ }
+
rtl_action_proc(hw, skb, true);
if (is_multicast_ether_addr(pda_addr))
rtlpriv->stats.txbytesmulticast += skb->len;
@@ -878,7 +888,7 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb,
seq_number <<= 4;
}
rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc, info, skb,
- hw_queue);
+ hw_queue, &tcb_desc);
if (!ieee80211_has_morefrags(hdr->frame_control)) {
if (qc)
mac->tids[tid].seq_number = seq_number;
@@ -887,7 +897,8 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb,
rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX);
}
-static int rtl_usb_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static int rtl_usb_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct rtl_tcb_desc *dummy)
{
struct rtl_usb *rtlusb = rtl_usbdev(rtl_usbpriv(hw));
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
diff --git a/drivers/net/wireless/rtlwifi/usb.h b/drivers/net/wireless/rtlwifi/usb.h
index abadfe918d30..d2a63fb3e1e6 100644
--- a/drivers/net/wireless/rtlwifi/usb.h
+++ b/drivers/net/wireless/rtlwifi/usb.h
@@ -31,6 +31,8 @@
#include <linux/usb.h>
#include <linux/skbuff.h>
+#define RTL_RX_DESC_SIZE 24
+
#define RTL_USB_DEVICE(vend, prod, cfg) \
.match_flags = USB_DEVICE_ID_MATCH_DEVICE, \
.idVendor = (vend), \
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h
index 07db95ff9bc5..693395ee98f9 100644
--- a/drivers/net/wireless/rtlwifi/wifi.h
+++ b/drivers/net/wireless/rtlwifi/wifi.h
@@ -68,6 +68,8 @@
#define QBSS_LOAD_SIZE 5
#define MAX_WMMELE_LENGTH 64
+#define TOTAL_CAM_ENTRY 32
+
/*slot time for 11g. */
#define RTL_SLOT_TIME_9 9
#define RTL_SLOT_TIME_20 20
@@ -94,8 +96,10 @@
#define CHANNEL_GROUP_MAX_5G 9
#define CHANNEL_MAX_NUMBER_2G 14
#define AVG_THERMAL_NUM 8
+#define MAX_TID_COUNT 9
/* for early mode */
+#define FCS_LEN 4
#define EM_HDR_LEN 8
enum intf_type {
INTF_PCI = 0,
@@ -159,6 +163,8 @@ enum hardware_type {
(IS_HARDWARE_TYPE_8192DE(rtlhal) || IS_HARDWARE_TYPE_8192DU(rtlhal))
#define IS_HARDWARE_TYPE_8723(rtlhal) \
(IS_HARDWARE_TYPE_8723E(rtlhal) || IS_HARDWARE_TYPE_8723U(rtlhal))
+#define IS_HARDWARE_TYPE_8723U(rtlhal) \
+ (rtlhal->hw_type == HARDWARE_TYPE_RTL8723U)
enum scan_operation_backup_opt {
SCAN_OPT_BACKUP = 0,
@@ -297,6 +303,9 @@ enum hw_variables {
HW_VAR_DATA_FILTER,
};
+#define HWSET_MAX_SIZE 128
+#define EFUSE_MAX_SECTION 16
+
enum _RT_MEDIA_STATUS {
RT_MEDIA_DISCONNECT = 0,
RT_MEDIA_CONNECT = 1
@@ -766,7 +775,7 @@ struct rtl_rfkill {
#define IQK_MATRIX_REG_NUM 8
#define IQK_MATRIX_SETTINGS_NUM (1 + 24 + 21)
struct iqk_matrix_regs {
- bool b_iqk_done;
+ bool iqk_done;
long value[1][IQK_MATRIX_REG_NUM];
};
@@ -843,6 +852,7 @@ struct rtl_phy {
bool apk_done;
u32 reg_rf3c[2]; /* pathA / pathB */
+ /* bfsync */
u8 framesync;
u32 framesync_c34;
@@ -852,6 +862,10 @@ struct rtl_phy {
};
#define MAX_TID_COUNT 9
+#define RTL_AGG_STOP 0
+#define RTL_AGG_PROGRESS 1
+#define RTL_AGG_START 2
+#define RTL_AGG_OPERATIONAL 3
#define RTL_AGG_OFF 0
#define RTL_AGG_ON 1
#define RTL_AGG_EMPTYING_HW_QUEUE_ADDBA 2
@@ -871,6 +885,13 @@ struct rtl_tid_data {
struct rtl_ht_agg agg;
};
+struct rtl_sta_info {
+ u8 ratr_index;
+ u8 wireless_mode;
+ u8 mimo_ps;
+ struct rtl_tid_data tids[MAX_TID_COUNT];
+} __packed;
+
struct rtl_priv;
struct rtl_io {
struct device *dev;
@@ -894,6 +915,7 @@ struct rtl_io {
u32(*read32_sync) (struct rtl_priv *rtlpriv, u32 addr);
int (*readN_sync) (struct rtl_priv *rtlpriv, u32 addr, u16 len,
u8 *pdata);
+
};
struct rtl_mac {
@@ -916,6 +938,8 @@ struct rtl_mac {
int n_channels;
int n_bitrates;
+ bool offchan_deley;
+
/*filters */
u32 rx_conf;
u16 rx_mgt_filter;
@@ -1032,7 +1056,9 @@ struct rtl_security {
enum rt_enc_alg pairwise_enc_algorithm;
/*Encryption Algorithm for Brocast/Multicast */
enum rt_enc_alg group_enc_algorithm;
-
+ /*Cam Entry Bitmap */
+ u32 hwsec_cam_bitmap;
+ u8 hwsec_cam_sta_addr[TOTAL_CAM_ENTRY][ETH_ALEN];
/*local Key buffer, indx 0 is for
pairwise key 1-4 is for agoup key. */
u8 key_buf[KEY_BUF_SIZE][MAX_KEY_LEN];
@@ -1053,7 +1079,7 @@ struct rtl_dm {
bool current_turbo_edca;
bool is_any_nonbepkts; /*out dm */
bool is_cur_rdlstate;
- bool txpower_trackingInit;
+ bool txpower_trackinginit;
bool disable_framebursting;
bool cck_inch14;
bool txpower_tracking;
@@ -1079,7 +1105,6 @@ struct rtl_dm {
bool disable_tx_int;
char ofdm_index[2];
char cck_index;
- u8 power_index_backup[6];
};
#define EFUSE_MAX_LOGICAL_SIZE 256
@@ -1175,6 +1200,7 @@ struct rtl_ps_ctl {
* otherwise Offset[560h] = 0x00.
* */
bool support_aspm;
+
bool support_backdoor;
/*for LPS */
@@ -1201,7 +1227,6 @@ struct rtl_ps_ctl {
/*just for PCIE ASPM */
u8 const_amdpci_aspm;
-
bool pwrdown_mode;
enum rf_pwrstate inactive_pwrstate;
@@ -1282,6 +1307,10 @@ struct rt_link_detect {
bool busytraffic;
bool higher_busytraffic;
bool higher_busyrxtraffic;
+
+ u32 tidtx_in4period[MAX_TID_COUNT][4];
+ u32 tidtx_inperiod[MAX_TID_COUNT];
+ bool higher_busytxtraffic[MAX_TID_COUNT];
};
struct rtl_tcb_desc {
@@ -1344,13 +1373,15 @@ struct rtl_hal_ops {
u32 add_msr, u32 rm_msr);
void (*get_hw_reg) (struct ieee80211_hw *hw, u8 variable, u8 *val);
void (*set_hw_reg) (struct ieee80211_hw *hw, u8 variable, u8 *val);
- void (*update_rate_table) (struct ieee80211_hw *hw);
+ void (*update_rate_tbl) (struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u8 rssi_level);
void (*update_rate_mask) (struct ieee80211_hw *hw, u8 rssi_level);
void (*fill_tx_desc) (struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr, u8 *pdesc_tx,
struct ieee80211_tx_info *info,
- struct sk_buff *skb, unsigned int queue_index);
- void (*fill_fake_txdesc) (struct ieee80211_hw *hw, u8 * pDesc,
+ struct sk_buff *skb, u8 hw_queue,
+ struct rtl_tcb_desc *ptcb_desc);
+ void (*fill_fake_txdesc) (struct ieee80211_hw *hw, u8 *pDesc,
u32 buffer_len, bool bIsPsPoll);
void (*fill_tx_cmddesc) (struct ieee80211_hw *hw, u8 *pdesc,
bool firstseg, bool lastseg,
@@ -1370,10 +1401,10 @@ struct rtl_hal_ops {
enum led_ctl_mode ledaction);
void (*set_desc) (u8 *pdesc, bool istx, u8 desc_name, u8 *val);
u32 (*get_desc) (u8 *pdesc, bool istx, u8 desc_name);
- void (*tx_polling) (struct ieee80211_hw *hw, unsigned int hw_queue);
+ void (*tx_polling) (struct ieee80211_hw *hw, u8 hw_queue);
void (*enable_hw_sec) (struct ieee80211_hw *hw);
void (*set_key) (struct ieee80211_hw *hw, u32 key_index,
- u8 *p_macaddr, bool is_group, u8 enc_algo,
+ u8 *macaddr, bool is_group, u8 enc_algo,
bool is_wepkey, bool clear_all);
void (*init_sw_leds) (struct ieee80211_hw *hw);
void (*deinit_sw_leds) (struct ieee80211_hw *hw);
@@ -1384,6 +1415,7 @@ struct rtl_hal_ops {
u32 regaddr, u32 bitmask);
void (*set_rfreg) (struct ieee80211_hw *hw, enum radio_path rfpath,
u32 regaddr, u32 bitmask, u32 data);
+ void (*linked_set_reg) (struct ieee80211_hw *hw);
bool (*phy_rf6052_config) (struct ieee80211_hw *hw);
void (*phy_rf6052_set_cck_txpower) (struct ieee80211_hw *hw,
u8 *powerlevel);
@@ -1404,7 +1436,9 @@ struct rtl_intf_ops {
int (*adapter_start) (struct ieee80211_hw *hw);
void (*adapter_stop) (struct ieee80211_hw *hw);
- int (*adapter_tx) (struct ieee80211_hw *hw, struct sk_buff *skb);
+ int (*adapter_tx) (struct ieee80211_hw *hw, struct sk_buff *skb,
+ struct rtl_tcb_desc *ptcb_desc);
+ void (*flush)(struct ieee80211_hw *hw, bool drop);
int (*reset_trx_ring) (struct ieee80211_hw *hw);
bool (*waitq_insert) (struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -1418,6 +1452,15 @@ struct rtl_intf_ops {
struct rtl_mod_params {
/* default: 0 = using hardware encryption */
int sw_crypto;
+
+ /* default: 1 = using no linked power save */
+ bool inactiveps;
+
+ /* default: 1 = using linked sw power save */
+ bool swctrl_lps;
+
+ /* default: 1 = using linked fw power save */
+ bool fwctrl_lps;
};
struct rtl_hal_usbint_cfg {
@@ -1445,6 +1488,7 @@ struct rtl_hal_usbint_cfg {
struct rtl_hal_cfg {
u8 bar_id;
+ bool write_readback;
char *name;
char *fw_name;
struct rtl_hal_ops *ops;
@@ -1469,7 +1513,6 @@ struct rtl_locks {
spinlock_t rf_lock;
spinlock_t lps_lock;
spinlock_t waitq_lock;
- spinlock_t tx_urb_lock;
/*Dual mac*/
spinlock_t cck_and_rw_pagea_lock;
@@ -1621,19 +1664,19 @@ struct bt_coexist_info {
u32 bt_edca_ul;
u32 bt_edca_dl;
- bool b_init_set;
- bool b_bt_busy_traffic;
- bool b_bt_traffic_mode_set;
- bool b_bt_non_traffic_mode_set;
+ bool init_set;
+ bool bt_busy_traffic;
+ bool bt_traffic_mode_set;
+ bool bt_non_traffic_mode_set;
- bool b_fw_coexist_all_off;
- bool b_sw_coexist_all_off;
+ bool fw_coexist_all_off;
+ bool sw_coexist_all_off;
u32 current_state;
u32 previous_state;
u8 bt_pre_rssi_state;
- u8 b_reg_bt_iso;
- u8 b_reg_bt_sco;
+ u8 reg_bt_iso;
+ u8 reg_bt_sco;
};
@@ -1653,13 +1696,23 @@ struct bt_coexist_info {
#define EF4BYTE(_val) \
(le32_to_cpu(_val))
+/* Read data from memory */
+#define READEF1BYTE(_ptr) \
+ EF1BYTE(*((u8 *)(_ptr)))
/* Read le16 data from memory and convert to host ordering */
#define READEF2BYTE(_ptr) \
EF2BYTE(*((u16 *)(_ptr)))
+#define READEF4BYTE(_ptr) \
+ EF4BYTE(*((u32 *)(_ptr)))
+/* Write data to memory */
+#define WRITEEF1BYTE(_ptr, _val) \
+ (*((u8 *)(_ptr))) = EF1BYTE(_val)
/* Write le16 data to memory in host ordering */
#define WRITEEF2BYTE(_ptr, _val) \
(*((u16 *)(_ptr))) = EF2BYTE(_val)
+#define WRITEEF4BYTE(_ptr, _val) \
+ (*((u16 *)(_ptr))) = EF2BYTE(_val)
/* Create a bit mask
* Examples:
@@ -1698,6 +1751,25 @@ struct bt_coexist_info {
#define LE_P1BYTE_TO_HOST_1BYTE(__pstart) \
(EF1BYTE(*((u8 *)(__pstart))))
+/*Description:
+Translate subfield (continuous bits in little-endian) of 4-byte
+value to host byte ordering.*/
+#define LE_BITS_TO_4BYTE(__pstart, __bitoffset, __bitlen) \
+ ( \
+ (LE_P4BYTE_TO_HOST_4BYTE(__pstart) >> (__bitoffset)) & \
+ BIT_LEN_MASK_32(__bitlen) \
+ )
+#define LE_BITS_TO_2BYTE(__pstart, __bitoffset, __bitlen) \
+ ( \
+ (LE_P2BYTE_TO_HOST_2BYTE(__pstart) >> (__bitoffset)) & \
+ BIT_LEN_MASK_16(__bitlen) \
+ )
+#define LE_BITS_TO_1BYTE(__pstart, __bitoffset, __bitlen) \
+ ( \
+ (LE_P1BYTE_TO_HOST_1BYTE(__pstart) >> (__bitoffset)) & \
+ BIT_LEN_MASK_8(__bitlen) \
+ )
+
/* Description:
* Mask subfield (continuous bits in little-endian) of 4-byte value
* and return the result in 4-byte value in host byte ordering.
@@ -1721,6 +1793,18 @@ struct bt_coexist_info {
/* Description:
* Set subfield of little-endian 4-byte value to specified value.
*/
+#define SET_BITS_TO_LE_4BYTE(__pstart, __bitoffset, __bitlen, __val) \
+ *((u32 *)(__pstart)) = EF4BYTE \
+ ( \
+ LE_BITS_CLEARED_TO_4BYTE(__pstart, __bitoffset, __bitlen) | \
+ ((((u32)__val) & BIT_LEN_MASK_32(__bitlen)) << (__bitoffset)) \
+ );
+#define SET_BITS_TO_LE_2BYTE(__pstart, __bitoffset, __bitlen, __val) \
+ *((u16 *)(__pstart)) = EF2BYTE \
+ ( \
+ LE_BITS_CLEARED_TO_2BYTE(__pstart, __bitoffset, __bitlen) | \
+ ((((u16)__val) & BIT_LEN_MASK_16(__bitlen)) << (__bitoffset)) \
+ );
#define SET_BITS_TO_LE_1BYTE(__pstart, __bitoffset, __bitlen, __val) \
*((u8 *)(__pstart)) = EF1BYTE \
( \
@@ -1728,12 +1812,16 @@ struct bt_coexist_info {
((((u8)__val) & BIT_LEN_MASK_8(__bitlen)) << (__bitoffset)) \
);
+#define N_BYTE_ALIGMENT(__value, __aligment) ((__aligment == 1) ? \
+ (__value) : (((__value + __aligment - 1) / __aligment) * __aligment))
+
/****************************************
mem access macro define end
****************************************/
#define byte(x, n) ((x >> (8 * n)) & 0xff)
+#define packet_get_type(_packet) (EF1BYTE((_packet).octet[0]) & 0xFC)
#define RTL_WATCH_DOG_TIME 2000
#define MSECS(t) msecs_to_jiffies(t)
#define WLAN_FC_GET_VERS(fc) (le16_to_cpu(fc) & IEEE80211_FCTL_VERS)
@@ -1768,6 +1856,15 @@ struct bt_coexist_info {
#define container_of_dwork_rtl(x, y, z) \
container_of(container_of(x, struct delayed_work, work), y, z)
+#define FILL_OCTET_STRING(_os, _octet, _len) \
+ (_os).octet = (u8 *)(_octet); \
+ (_os).length = (_len);
+
+#define CP_MACADDR(des, src) \
+ ((des)[0] = (src)[0], (des)[1] = (src)[1],\
+ (des)[2] = (src)[2], (des)[3] = (src)[3],\
+ (des)[4] = (src)[4], (des)[5] = (src)[5])
+
static inline u8 rtl_read_byte(struct rtl_priv *rtlpriv, u32 addr)
{
return rtlpriv->io.read8_sync(rtlpriv, addr);
@@ -1786,17 +1883,26 @@ static inline u32 rtl_read_dword(struct rtl_priv *rtlpriv, u32 addr)
static inline void rtl_write_byte(struct rtl_priv *rtlpriv, u32 addr, u8 val8)
{
rtlpriv->io.write8_async(rtlpriv, addr, val8);
+
+ if (rtlpriv->cfg->write_readback)
+ rtlpriv->io.read8_sync(rtlpriv, addr);
}
static inline void rtl_write_word(struct rtl_priv *rtlpriv, u32 addr, u16 val16)
{
rtlpriv->io.write16_async(rtlpriv, addr, val16);
+
+ if (rtlpriv->cfg->write_readback)
+ rtlpriv->io.read16_sync(rtlpriv, addr);
}
static inline void rtl_write_dword(struct rtl_priv *rtlpriv,
u32 addr, u32 val32)
{
rtlpriv->io.write32_async(rtlpriv, addr, val32);
+
+ if (rtlpriv->cfg->write_readback)
+ rtlpriv->io.read32_sync(rtlpriv, addr);
}
static inline u32 rtl_get_bbreg(struct ieee80211_hw *hw,
@@ -1855,4 +1961,31 @@ static inline u8 get_rf_type(struct rtl_phy *rtlphy)
return rtlphy->rf_type;
}
+static inline struct ieee80211_hdr *rtl_get_hdr(struct sk_buff *skb)
+{
+ return (struct ieee80211_hdr *)(skb->data);
+}
+
+static inline __le16 rtl_get_fc(struct sk_buff *skb)
+{
+ return rtl_get_hdr(skb)->frame_control;
+}
+
+static inline u16 rtl_get_tid_h(struct ieee80211_hdr *hdr)
+{
+ return (ieee80211_get_qos_ctl(hdr))[0] & IEEE80211_QOS_CTL_TID_MASK;
+}
+
+static inline u16 rtl_get_tid(struct sk_buff *skb)
+{
+ return rtl_get_tid_h(rtl_get_hdr(skb));
+}
+
+static inline struct ieee80211_sta *get_sta(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ u8 *bssid)
+{
+ return ieee80211_find_sta(vif, bssid);
+}
+
#endif
diff --git a/drivers/net/wireless/wl1251/cmd.h b/drivers/net/wireless/wl1251/cmd.h
index e5c74c631374..79ca5273c9e9 100644
--- a/drivers/net/wireless/wl1251/cmd.h
+++ b/drivers/net/wireless/wl1251/cmd.h
@@ -313,8 +313,8 @@ struct wl1251_cmd_vbm_update {
} __packed;
enum wl1251_cmd_ps_mode {
- STATION_ACTIVE_MODE,
- STATION_POWER_SAVE_MODE
+ CHIP_ACTIVE_MODE,
+ CHIP_POWER_SAVE_MODE
};
struct wl1251_cmd_ps_params {
diff --git a/drivers/net/wireless/wl1251/event.c b/drivers/net/wireless/wl1251/event.c
index dfc4579acb06..9f15ccaf8f05 100644
--- a/drivers/net/wireless/wl1251/event.c
+++ b/drivers/net/wireless/wl1251/event.c
@@ -68,14 +68,16 @@ static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox)
if (vector & BSS_LOSE_EVENT_ID) {
wl1251_debug(DEBUG_EVENT, "BSS_LOSE_EVENT");
- if (wl->psm_requested && wl->psm) {
+ if (wl->psm_requested &&
+ wl->station_mode != STATION_ACTIVE_MODE) {
ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
if (ret < 0)
return ret;
}
}
- if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID && wl->psm) {
+ if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID &&
+ wl->station_mode != STATION_ACTIVE_MODE) {
wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT");
/* indicate to the stack, that beacons have been lost */
diff --git a/drivers/net/wireless/wl1251/main.c b/drivers/net/wireless/wl1251/main.c
index 12c9e635a6d6..a14a48c99cdc 100644
--- a/drivers/net/wireless/wl1251/main.c
+++ b/drivers/net/wireless/wl1251/main.c
@@ -497,7 +497,7 @@ static void wl1251_op_stop(struct ieee80211_hw *hw)
wl->rx_last_id = 0;
wl->next_tx_complete = 0;
wl->elp = false;
- wl->psm = 0;
+ wl->station_mode = STATION_ACTIVE_MODE;
wl->tx_queue_stopped = false;
wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
wl->rssi_thold = 0;
@@ -632,13 +632,29 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
wl->psm_requested = false;
- if (wl->psm) {
+ if (wl->station_mode != STATION_ACTIVE_MODE) {
ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
if (ret < 0)
goto out_sleep;
}
}
+ if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+ if (conf->flags & IEEE80211_CONF_IDLE) {
+ ret = wl1251_ps_set_mode(wl, STATION_IDLE);
+ if (ret < 0)
+ goto out_sleep;
+ } else {
+ ret = wl1251_ps_set_mode(wl, STATION_ACTIVE_MODE);
+ if (ret < 0)
+ goto out_sleep;
+ ret = wl1251_join(wl, wl->bss_type, wl->channel,
+ wl->beacon_int, wl->dtim_period);
+ if (ret < 0)
+ goto out_sleep;
+ }
+ }
+
if (conf->power_level != wl->power_level) {
ret = wl1251_acx_tx_power(wl, conf->power_level);
if (ret < 0)
@@ -1384,7 +1400,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void)
wl->rx_config = WL1251_DEFAULT_RX_CONFIG;
wl->rx_filter = WL1251_DEFAULT_RX_FILTER;
wl->elp = false;
- wl->psm = 0;
+ wl->station_mode = STATION_ACTIVE_MODE;
wl->psm_requested = false;
wl->tx_queue_stopped = false;
wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
diff --git a/drivers/net/wireless/wl1251/ps.c b/drivers/net/wireless/wl1251/ps.c
index 9cc514703d2a..db719f7d2692 100644
--- a/drivers/net/wireless/wl1251/ps.c
+++ b/drivers/net/wireless/wl1251/ps.c
@@ -39,7 +39,7 @@ void wl1251_elp_work(struct work_struct *work)
mutex_lock(&wl->mutex);
- if (wl->elp || !wl->psm)
+ if (wl->elp || wl->station_mode == STATION_ACTIVE_MODE)
goto out;
wl1251_debug(DEBUG_PSM, "chip to elp");
@@ -57,7 +57,7 @@ void wl1251_ps_elp_sleep(struct wl1251 *wl)
{
unsigned long delay;
- if (wl->psm) {
+ if (wl->station_mode != STATION_ACTIVE_MODE) {
delay = msecs_to_jiffies(ELP_ENTRY_DELAY);
ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, delay);
}
@@ -104,7 +104,7 @@ int wl1251_ps_elp_wakeup(struct wl1251 *wl)
return 0;
}
-int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode)
+int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_station_mode mode)
{
int ret;
@@ -128,15 +128,24 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode)
if (ret < 0)
return ret;
- ret = wl1251_cmd_ps_mode(wl, STATION_POWER_SAVE_MODE);
+ ret = wl1251_cmd_ps_mode(wl, CHIP_POWER_SAVE_MODE);
if (ret < 0)
return ret;
ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP);
if (ret < 0)
return ret;
+ break;
+ case STATION_IDLE:
+ wl1251_debug(DEBUG_PSM, "entering idle");
- wl->psm = 1;
+ ret = wl1251_acx_sleep_auth(wl, WL1251_PSM_ELP);
+ if (ret < 0)
+ return ret;
+
+ ret = wl1251_cmd_template_set(wl, CMD_DISCONNECT, NULL, 0);
+ if (ret < 0)
+ return ret;
break;
case STATION_ACTIVE_MODE:
default:
@@ -163,13 +172,13 @@ int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode)
if (ret < 0)
return ret;
- ret = wl1251_cmd_ps_mode(wl, STATION_ACTIVE_MODE);
+ ret = wl1251_cmd_ps_mode(wl, CHIP_ACTIVE_MODE);
if (ret < 0)
return ret;
- wl->psm = 0;
break;
}
+ wl->station_mode = mode;
return ret;
}
diff --git a/drivers/net/wireless/wl1251/ps.h b/drivers/net/wireless/wl1251/ps.h
index 55c3dda75e69..75efad246d67 100644
--- a/drivers/net/wireless/wl1251/ps.h
+++ b/drivers/net/wireless/wl1251/ps.h
@@ -26,7 +26,7 @@
#include "wl1251.h"
#include "acx.h"
-int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_cmd_ps_mode mode);
+int wl1251_ps_set_mode(struct wl1251 *wl, enum wl1251_station_mode mode);
void wl1251_ps_elp_sleep(struct wl1251 *wl);
int wl1251_ps_elp_wakeup(struct wl1251 *wl);
void wl1251_elp_work(struct work_struct *work);
diff --git a/drivers/net/wireless/wl1251/wl1251.h b/drivers/net/wireless/wl1251/wl1251.h
index bb23cd522b22..a77f1bbbed0a 100644
--- a/drivers/net/wireless/wl1251/wl1251.h
+++ b/drivers/net/wireless/wl1251/wl1251.h
@@ -129,6 +129,12 @@ enum wl1251_partition_type {
PART_TABLE_LEN
};
+enum wl1251_station_mode {
+ STATION_ACTIVE_MODE,
+ STATION_POWER_SAVE_MODE,
+ STATION_IDLE,
+};
+
struct wl1251_partition {
u32 size;
u32 start;
@@ -358,8 +364,7 @@ struct wl1251 {
struct delayed_work elp_work;
- /* we can be in psm, but not in elp, we have to differentiate */
- bool psm;
+ enum wl1251_station_mode station_mode;
/* PSM mode requested */
bool psm_requested;
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig
index 692ebff38fc8..35ce7b0f4a60 100644
--- a/drivers/net/wireless/wl12xx/Kconfig
+++ b/drivers/net/wireless/wl12xx/Kconfig
@@ -3,7 +3,7 @@ menuconfig WL12XX_MENU
depends on MAC80211 && EXPERIMENTAL
---help---
This will enable TI wl12xx driver support for the following chips:
- wl1271 and wl1273.
+ wl1271, wl1273, wl1281 and wl1283.
The drivers make use of the mac80211 stack.
config WL12XX
diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index a3db755ceeda..c6ee530e5bf7 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -325,12 +325,19 @@ out:
return ret;
}
-int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold)
+int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold)
{
struct acx_rts_threshold *rts;
int ret;
- wl1271_debug(DEBUG_ACX, "acx rts threshold");
+ /*
+ * If the RTS threshold is not configured or out of range, use the
+ * default value.
+ */
+ if (rts_threshold > IEEE80211_MAX_RTS_THRESHOLD)
+ rts_threshold = wl->conf.rx.rts_threshold;
+
+ wl1271_debug(DEBUG_ACX, "acx rts threshold: %d", rts_threshold);
rts = kzalloc(sizeof(*rts), GFP_KERNEL);
if (!rts) {
@@ -338,7 +345,7 @@ int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold)
goto out;
}
- rts->threshold = cpu_to_le16(rts_threshold);
+ rts->threshold = cpu_to_le16((u16)rts_threshold);
ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts));
if (ret < 0) {
@@ -540,13 +547,13 @@ out:
return ret;
}
-int wl1271_acx_sg_cfg(struct wl1271 *wl)
+int wl1271_acx_sta_sg_cfg(struct wl1271 *wl)
{
- struct acx_bt_wlan_coex_param *param;
+ struct acx_sta_bt_wlan_coex_param *param;
struct conf_sg_settings *c = &wl->conf.sg;
int i, ret;
- wl1271_debug(DEBUG_ACX, "acx sg cfg");
+ wl1271_debug(DEBUG_ACX, "acx sg sta cfg");
param = kzalloc(sizeof(*param), GFP_KERNEL);
if (!param) {
@@ -555,8 +562,38 @@ int wl1271_acx_sg_cfg(struct wl1271 *wl)
}
/* BT-WLAN coext parameters */
- for (i = 0; i < CONF_SG_PARAMS_MAX; i++)
- param->params[i] = cpu_to_le32(c->params[i]);
+ for (i = 0; i < CONF_SG_STA_PARAMS_MAX; i++)
+ param->params[i] = cpu_to_le32(c->sta_params[i]);
+ param->param_idx = CONF_SG_PARAMS_ALL;
+
+ ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
+ if (ret < 0) {
+ wl1271_warning("failed to set sg config: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(param);
+ return ret;
+}
+
+int wl1271_acx_ap_sg_cfg(struct wl1271 *wl)
+{
+ struct acx_ap_bt_wlan_coex_param *param;
+ struct conf_sg_settings *c = &wl->conf.sg;
+ int i, ret;
+
+ wl1271_debug(DEBUG_ACX, "acx sg ap cfg");
+
+ param = kzalloc(sizeof(*param), GFP_KERNEL);
+ if (!param) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* BT-WLAN coext parameters */
+ for (i = 0; i < CONF_SG_AP_PARAMS_MAX; i++)
+ param->params[i] = cpu_to_le32(c->ap_params[i]);
param->param_idx = CONF_SG_PARAMS_ALL;
ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
@@ -804,7 +841,8 @@ int wl1271_acx_ap_rate_policy(struct wl1271 *wl, struct conf_tx_rate_class *c,
struct acx_ap_rate_policy *acx;
int ret = 0;
- wl1271_debug(DEBUG_ACX, "acx ap rate policy");
+ wl1271_debug(DEBUG_ACX, "acx ap rate policy %d rates 0x%x",
+ idx, c->enabled_rates);
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
@@ -898,12 +936,19 @@ out:
return ret;
}
-int wl1271_acx_frag_threshold(struct wl1271 *wl, u16 frag_threshold)
+int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold)
{
struct acx_frag_threshold *acx;
int ret = 0;
- wl1271_debug(DEBUG_ACX, "acx frag threshold");
+ /*
+ * If the fragmentation is not configured or out of range, use the
+ * default value.
+ */
+ if (frag_threshold > IEEE80211_MAX_FRAG_THRESHOLD)
+ frag_threshold = wl->conf.tx.frag_threshold;
+
+ wl1271_debug(DEBUG_ACX, "acx frag threshold: %d", frag_threshold);
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
@@ -912,7 +957,7 @@ int wl1271_acx_frag_threshold(struct wl1271 *wl, u16 frag_threshold)
goto out;
}
- acx->frag_threshold = cpu_to_le16(frag_threshold);
+ acx->frag_threshold = cpu_to_le16((u16)frag_threshold);
ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("Setting of frag threshold failed: %d", ret);
@@ -954,6 +999,7 @@ out:
int wl1271_acx_ap_mem_cfg(struct wl1271 *wl)
{
struct wl1271_acx_ap_config_memory *mem_conf;
+ struct conf_memory_settings *mem;
int ret;
wl1271_debug(DEBUG_ACX, "wl1271 mem cfg");
@@ -964,11 +1010,21 @@ int wl1271_acx_ap_mem_cfg(struct wl1271 *wl)
goto out;
}
+ if (wl->chip.id == CHIP_ID_1283_PG20)
+ /*
+ * FIXME: The 128x AP FW does not yet support dynamic memory.
+ * Use the base memory configuration for 128x for now. This
+ * should be fine tuned in the future.
+ */
+ mem = &wl->conf.mem_wl128x;
+ else
+ mem = &wl->conf.mem_wl127x;
+
/* memory config */
- mem_conf->num_stations = wl->conf.mem.num_stations;
- mem_conf->rx_mem_block_num = wl->conf.mem.rx_block_num;
- mem_conf->tx_min_mem_block_num = wl->conf.mem.tx_min_block_num;
- mem_conf->num_ssid_profiles = wl->conf.mem.ssid_profiles;
+ mem_conf->num_stations = mem->num_stations;
+ mem_conf->rx_mem_block_num = mem->rx_block_num;
+ mem_conf->tx_min_mem_block_num = mem->tx_min_block_num;
+ mem_conf->num_ssid_profiles = mem->ssid_profiles;
mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS);
ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
@@ -986,6 +1042,7 @@ out:
int wl1271_acx_sta_mem_cfg(struct wl1271 *wl)
{
struct wl1271_acx_sta_config_memory *mem_conf;
+ struct conf_memory_settings *mem;
int ret;
wl1271_debug(DEBUG_ACX, "wl1271 mem cfg");
@@ -996,16 +1053,21 @@ int wl1271_acx_sta_mem_cfg(struct wl1271 *wl)
goto out;
}
+ if (wl->chip.id == CHIP_ID_1283_PG20)
+ mem = &wl->conf.mem_wl128x;
+ else
+ mem = &wl->conf.mem_wl127x;
+
/* memory config */
- mem_conf->num_stations = wl->conf.mem.num_stations;
- mem_conf->rx_mem_block_num = wl->conf.mem.rx_block_num;
- mem_conf->tx_min_mem_block_num = wl->conf.mem.tx_min_block_num;
- mem_conf->num_ssid_profiles = wl->conf.mem.ssid_profiles;
+ mem_conf->num_stations = mem->num_stations;
+ mem_conf->rx_mem_block_num = mem->rx_block_num;
+ mem_conf->tx_min_mem_block_num = mem->tx_min_block_num;
+ mem_conf->num_ssid_profiles = mem->ssid_profiles;
mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS);
- mem_conf->dyn_mem_enable = wl->conf.mem.dynamic_memory;
- mem_conf->tx_free_req = wl->conf.mem.min_req_tx_blocks;
- mem_conf->rx_free_req = wl->conf.mem.min_req_rx_blocks;
- mem_conf->tx_min = wl->conf.mem.tx_min;
+ mem_conf->dyn_mem_enable = mem->dynamic_memory;
+ mem_conf->tx_free_req = mem->min_req_tx_blocks;
+ mem_conf->rx_free_req = mem->min_req_rx_blocks;
+ mem_conf->tx_min = mem->tx_min;
ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
sizeof(*mem_conf));
@@ -1019,6 +1081,32 @@ out:
return ret;
}
+int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap)
+{
+ struct wl1271_acx_host_config_bitmap *bitmap_conf;
+ int ret;
+
+ bitmap_conf = kzalloc(sizeof(*bitmap_conf), GFP_KERNEL);
+ if (!bitmap_conf) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ bitmap_conf->host_cfg_bitmap = cpu_to_le32(host_cfg_bitmap);
+
+ ret = wl1271_cmd_configure(wl, ACX_HOST_IF_CFG_BITMAP,
+ bitmap_conf, sizeof(*bitmap_conf));
+ if (ret < 0) {
+ wl1271_warning("wl1271 bitmap config opt failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(bitmap_conf);
+
+ return ret;
+}
+
int wl1271_acx_init_mem_config(struct wl1271 *wl)
{
int ret;
@@ -1567,3 +1655,68 @@ out:
kfree(acx);
return ret;
}
+
+int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable)
+{
+ struct acx_ap_beacon_filter *acx = NULL;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx set ap beacon filter: %d", enable);
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx)
+ return -ENOMEM;
+
+ acx->enable = enable ? 1 : 0;
+
+ ret = wl1271_cmd_configure(wl, ACX_AP_BEACON_FILTER_OPT,
+ acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("acx set ap beacon filter failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1271_acx_fm_coex(struct wl1271 *wl)
+{
+ struct wl1271_acx_fm_coex *acx;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx fm coex setting");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->enable = wl->conf.fm_coex.enable;
+ acx->swallow_period = wl->conf.fm_coex.swallow_period;
+ acx->n_divider_fref_set_1 = wl->conf.fm_coex.n_divider_fref_set_1;
+ acx->n_divider_fref_set_2 = wl->conf.fm_coex.n_divider_fref_set_2;
+ acx->m_divider_fref_set_1 =
+ cpu_to_le16(wl->conf.fm_coex.m_divider_fref_set_1);
+ acx->m_divider_fref_set_2 =
+ cpu_to_le16(wl->conf.fm_coex.m_divider_fref_set_2);
+ acx->coex_pll_stabilization_time =
+ cpu_to_le32(wl->conf.fm_coex.coex_pll_stabilization_time);
+ acx->ldo_stabilization_time =
+ cpu_to_le16(wl->conf.fm_coex.ldo_stabilization_time);
+ acx->fm_disturbed_band_margin =
+ wl->conf.fm_coex.fm_disturbed_band_margin;
+ acx->swallow_clk_diff = wl->conf.fm_coex.swallow_clk_diff;
+
+ ret = wl1271_cmd_configure(wl, ACX_FM_COEX_CFG, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("acx fm coex setting failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h
index dd19b01d807b..9a895e3cc613 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -303,7 +303,6 @@ struct acx_beacon_filter_option {
struct acx_header header;
u8 enable;
-
/*
* The number of beacons without the unicast TIM
* bit set that the firmware buffers before
@@ -370,14 +369,23 @@ struct acx_bt_wlan_coex {
u8 pad[3];
} __packed;
-struct acx_bt_wlan_coex_param {
+struct acx_sta_bt_wlan_coex_param {
struct acx_header header;
- __le32 params[CONF_SG_PARAMS_MAX];
+ __le32 params[CONF_SG_STA_PARAMS_MAX];
u8 param_idx;
u8 padding[3];
} __packed;
+struct acx_ap_bt_wlan_coex_param {
+ struct acx_header header;
+
+ __le32 params[CONF_SG_AP_PARAMS_MAX];
+ u8 param_idx;
+ u8 padding[3];
+} __packed;
+
+
struct acx_dco_itrim_params {
struct acx_header header;
@@ -939,6 +947,16 @@ struct wl1271_acx_keep_alive_config {
u8 padding;
} __packed;
+#define HOST_IF_CFG_RX_FIFO_ENABLE BIT(0)
+#define HOST_IF_CFG_TX_EXTRA_BLKS_SWAP BIT(1)
+#define HOST_IF_CFG_TX_PAD_TO_SDIO_BLK BIT(3)
+
+struct wl1271_acx_host_config_bitmap {
+ struct acx_header header;
+
+ __le32 host_cfg_bitmap;
+} __packed;
+
enum {
WL1271_ACX_TRIG_TYPE_LEVEL = 0,
WL1271_ACX_TRIG_TYPE_EDGE,
@@ -1162,6 +1180,72 @@ struct wl1271_acx_inconnection_sta {
u8 padding1[2];
} __packed;
+struct acx_ap_beacon_filter {
+ struct acx_header header;
+
+ u8 enable;
+ u8 pad[3];
+} __packed;
+
+/*
+ * ACX_FM_COEX_CFG
+ * set the FM co-existence parameters.
+ */
+struct wl1271_acx_fm_coex {
+ struct acx_header header;
+ /* enable(1) / disable(0) the FM Coex feature */
+ u8 enable;
+ /*
+ * Swallow period used in COEX PLL swallowing mechanism.
+ * 0xFF = use FW default
+ */
+ u8 swallow_period;
+ /*
+ * The N divider used in COEX PLL swallowing mechanism for Fref of
+ * 38.4/19.2 Mhz. 0xFF = use FW default
+ */
+ u8 n_divider_fref_set_1;
+ /*
+ * The N divider used in COEX PLL swallowing mechanism for Fref of
+ * 26/52 Mhz. 0xFF = use FW default
+ */
+ u8 n_divider_fref_set_2;
+ /*
+ * The M divider used in COEX PLL swallowing mechanism for Fref of
+ * 38.4/19.2 Mhz. 0xFFFF = use FW default
+ */
+ __le16 m_divider_fref_set_1;
+ /*
+ * The M divider used in COEX PLL swallowing mechanism for Fref of
+ * 26/52 Mhz. 0xFFFF = use FW default
+ */
+ __le16 m_divider_fref_set_2;
+ /*
+ * The time duration in uSec required for COEX PLL to stabilize.
+ * 0xFFFFFFFF = use FW default
+ */
+ __le32 coex_pll_stabilization_time;
+ /*
+ * The time duration in uSec required for LDO to stabilize.
+ * 0xFFFFFFFF = use FW default
+ */
+ __le16 ldo_stabilization_time;
+ /*
+ * The disturbed frequency band margin around the disturbed frequency
+ * center (single sided).
+ * For example, if 2 is configured, the following channels will be
+ * considered disturbed channel:
+ * 80 +- 0.1 MHz, 91 +- 0.1 MHz, 98 +- 0.1 MHz, 102 +- 0.1 MH
+ * 0xFF = use FW default
+ */
+ u8 fm_disturbed_band_margin;
+ /*
+ * The swallow clock difference of the swallowing mechanism.
+ * 0xFF = use FW default
+ */
+ u8 swallow_clk_diff;
+} __packed;
+
enum {
ACX_WAKE_UP_CONDITIONS = 0x0002,
ACX_MEM_CFG = 0x0003,
@@ -1180,6 +1264,7 @@ enum {
ACX_TID_CFG = 0x001A,
ACX_PS_RX_STREAMING = 0x001B,
ACX_BEACON_FILTER_OPT = 0x001F,
+ ACX_AP_BEACON_FILTER_OPT = 0x0020,
ACX_NOISE_HIST = 0x0021,
ACX_HDK_VERSION = 0x0022, /* ??? */
ACX_PD_THRESHOLD = 0x0023,
@@ -1191,6 +1276,7 @@ enum {
ACX_BCN_DTIM_OPTIONS = 0x0031,
ACX_SG_ENABLE = 0x0032,
ACX_SG_CFG = 0x0033,
+ ACX_FM_COEX_CFG = 0x0034,
ACX_BEACON_FILTER_TABLE = 0x0038,
ACX_ARP_IP_FILTER = 0x0039,
ACX_ROAMING_STATISTICS_TBL = 0x003B,
@@ -1247,13 +1333,14 @@ int wl1271_acx_slot(struct wl1271 *wl, enum acx_slot_type slot_time);
int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable,
void *mc_list, u32 mc_list_len);
int wl1271_acx_service_period_timeout(struct wl1271 *wl);
-int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold);
+int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold);
int wl1271_acx_dco_itrim_params(struct wl1271 *wl);
int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter);
int wl1271_acx_beacon_filter_table(struct wl1271 *wl);
int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable);
int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable);
-int wl1271_acx_sg_cfg(struct wl1271 *wl);
+int wl1271_acx_sta_sg_cfg(struct wl1271 *wl);
+int wl1271_acx_ap_sg_cfg(struct wl1271 *wl);
int wl1271_acx_cca_threshold(struct wl1271 *wl);
int wl1271_acx_bcn_dtim_options(struct wl1271 *wl);
int wl1271_acx_aid(struct wl1271 *wl, u16 aid);
@@ -1270,11 +1357,12 @@ int wl1271_acx_ac_cfg(struct wl1271 *wl, u8 ac, u8 cw_min, u16 cw_max,
int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type,
u8 tsid, u8 ps_scheme, u8 ack_policy,
u32 apsd_conf0, u32 apsd_conf1);
-int wl1271_acx_frag_threshold(struct wl1271 *wl, u16 frag_threshold);
+int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold);
int wl1271_acx_tx_config_options(struct wl1271 *wl);
int wl1271_acx_ap_mem_cfg(struct wl1271 *wl);
int wl1271_acx_sta_mem_cfg(struct wl1271 *wl);
int wl1271_acx_init_mem_config(struct wl1271 *wl);
+int wl1271_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap);
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);
@@ -1299,5 +1387,7 @@ int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
int wl1271_acx_max_tx_retry(struct wl1271 *wl);
int wl1271_acx_config_ps(struct wl1271 *wl);
int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
+int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable);
+int wl1271_acx_fm_coex(struct wl1271 *wl);
#endif /* __WL1271_ACX_H__ */
diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c
index 6934dffd5174..b07f8b7e5f11 100644
--- a/drivers/net/wireless/wl12xx/boot.c
+++ b/drivers/net/wireless/wl12xx/boot.c
@@ -22,6 +22,7 @@
*/
#include <linux/slab.h>
+#include <linux/wl12xx.h>
#include "acx.h"
#include "reg.h"
@@ -243,33 +244,57 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
if (wl->nvs == NULL)
return -ENODEV;
- /*
- * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
- * configurations) can be removed when those NVS files stop floating
- * around.
- */
- if (wl->nvs_len == sizeof(struct wl1271_nvs_file) ||
- wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) {
- /* for now 11a is unsupported in AP mode */
- if (wl->bss_type != BSS_TYPE_AP_BSS &&
- wl->nvs->general_params.dual_mode_select)
- wl->enable_11a = true;
- }
+ if (wl->chip.id == CHIP_ID_1283_PG20) {
+ struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs;
+
+ if (wl->nvs_len == sizeof(struct wl128x_nvs_file)) {
+ if (nvs->general_params.dual_mode_select)
+ wl->enable_11a = true;
+ } else {
+ wl1271_error("nvs size is not as expected: %zu != %zu",
+ wl->nvs_len,
+ sizeof(struct wl128x_nvs_file));
+ kfree(wl->nvs);
+ wl->nvs = NULL;
+ wl->nvs_len = 0;
+ return -EILSEQ;
+ }
- if (wl->nvs_len != sizeof(struct wl1271_nvs_file) &&
- (wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
- wl->enable_11a)) {
- wl1271_error("nvs size is not as expected: %zu != %zu",
- wl->nvs_len, sizeof(struct wl1271_nvs_file));
- kfree(wl->nvs);
- wl->nvs = NULL;
- wl->nvs_len = 0;
- return -EILSEQ;
- }
+ /* only the first part of the NVS needs to be uploaded */
+ nvs_len = sizeof(nvs->nvs);
+ nvs_ptr = (u8 *)nvs->nvs;
+
+ } else {
+ struct wl1271_nvs_file *nvs =
+ (struct wl1271_nvs_file *)wl->nvs;
+ /*
+ * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz
+ * band configurations) can be removed when those NVS files stop
+ * floating around.
+ */
+ if (wl->nvs_len == sizeof(struct wl1271_nvs_file) ||
+ wl->nvs_len == WL1271_INI_LEGACY_NVS_FILE_SIZE) {
+ /* for now 11a is unsupported in AP mode */
+ if (wl->bss_type != BSS_TYPE_AP_BSS &&
+ nvs->general_params.dual_mode_select)
+ wl->enable_11a = true;
+ }
- /* only the first part of the NVS needs to be uploaded */
- nvs_len = sizeof(wl->nvs->nvs);
- nvs_ptr = (u8 *)wl->nvs->nvs;
+ if (wl->nvs_len != sizeof(struct wl1271_nvs_file) &&
+ (wl->nvs_len != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
+ wl->enable_11a)) {
+ wl1271_error("nvs size is not as expected: %zu != %zu",
+ wl->nvs_len, sizeof(struct wl1271_nvs_file));
+ kfree(wl->nvs);
+ wl->nvs = NULL;
+ wl->nvs_len = 0;
+ return -EILSEQ;
+ }
+
+ /* only the first part of the NVS needs to be uploaded */
+ nvs_len = sizeof(nvs->nvs);
+ nvs_ptr = (u8 *) nvs->nvs;
+ }
/* update current MAC address to NVS */
nvs_ptr[11] = wl->mac_addr[0];
@@ -319,10 +344,13 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl)
/*
* We've reached the first zero length, the first NVS table
* is located at an aligned offset which is at least 7 bytes further.
+ * NOTE: The wl->nvs->nvs element must be first, in order to
+ * simplify the casting, we assume it is at the beginning of
+ * the wl->nvs structure.
*/
- nvs_ptr = (u8 *)wl->nvs->nvs +
- ALIGN(nvs_ptr - (u8 *)wl->nvs->nvs + 7, 4);
- nvs_len -= nvs_ptr - (u8 *)wl->nvs->nvs;
+ nvs_ptr = (u8 *)wl->nvs +
+ ALIGN(nvs_ptr - (u8 *)wl->nvs + 7, 4);
+ nvs_len -= nvs_ptr - (u8 *)wl->nvs;
/* Now we must set the partition correctly */
wl1271_set_partition(wl, &part_table[PART_WORK]);
@@ -450,10 +478,14 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
DISCONNECT_EVENT_COMPLETE_ID |
RSSI_SNR_TRIGGER_0_EVENT_ID |
PSPOLL_DELIVERY_FAILURE_EVENT_ID |
- SOFT_GEMINI_SENSE_EVENT_ID;
+ SOFT_GEMINI_SENSE_EVENT_ID |
+ PERIODIC_SCAN_REPORT_EVENT_ID |
+ PERIODIC_SCAN_COMPLETE_EVENT_ID;
if (wl->bss_type == BSS_TYPE_AP_BSS)
wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID;
+ else
+ wl->event_mask |= DUMMY_PACKET_EVENT_ID;
ret = wl1271_event_unmask(wl);
if (ret < 0) {
@@ -493,24 +525,159 @@ static void wl1271_boot_hw_version(struct wl1271 *wl)
wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION;
}
-/* uploads NVS and firmware */
-int wl1271_load_firmware(struct wl1271 *wl)
+static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl)
{
- int ret = 0;
- u32 tmp, clk, pause;
+ u16 spare_reg;
+
+ /* Mask bits [2] & [8:4] in the sys_clk_cfg register */
+ spare_reg = wl1271_top_reg_read(wl, WL_SPARE_REG);
+ if (spare_reg == 0xFFFF)
+ return -EFAULT;
+ spare_reg |= (BIT(3) | BIT(5) | BIT(6));
+ wl1271_top_reg_write(wl, WL_SPARE_REG, spare_reg);
+
+ /* Enable FREF_CLK_REQ & mux MCS and coex PLLs to FREF */
+ wl1271_top_reg_write(wl, SYS_CLK_CFG_REG,
+ WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF);
+
+ /* Delay execution for 15msec, to let the HW settle */
+ mdelay(15);
+
+ return 0;
+}
+
+static bool wl128x_is_tcxo_valid(struct wl1271 *wl)
+{
+ u16 tcxo_detection;
+
+ tcxo_detection = wl1271_top_reg_read(wl, TCXO_CLK_DETECT_REG);
+ if (tcxo_detection & TCXO_DET_FAILED)
+ return false;
+
+ return true;
+}
+
+static bool wl128x_is_fref_valid(struct wl1271 *wl)
+{
+ u16 fref_detection;
+
+ fref_detection = wl1271_top_reg_read(wl, FREF_CLK_DETECT_REG);
+ if (fref_detection & FREF_CLK_DETECT_FAIL)
+ return false;
+
+ return true;
+}
+
+static int wl128x_manually_configure_mcs_pll(struct wl1271 *wl)
+{
+ wl1271_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL);
+ wl1271_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL);
+ wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, MCS_PLL_CONFIG_REG_VAL);
+
+ return 0;
+}
+
+static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk)
+{
+ u16 spare_reg;
+ u16 pll_config;
+ u8 input_freq;
+
+ /* Mask bits [3:1] in the sys_clk_cfg register */
+ spare_reg = wl1271_top_reg_read(wl, WL_SPARE_REG);
+ if (spare_reg == 0xFFFF)
+ return -EFAULT;
+ spare_reg |= BIT(2);
+ wl1271_top_reg_write(wl, WL_SPARE_REG, spare_reg);
+
+ /* Handle special cases of the TCXO clock */
+ if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_8 ||
+ wl->tcxo_clock == WL12XX_TCXOCLOCK_33_6)
+ return wl128x_manually_configure_mcs_pll(wl);
+
+ /* Set the input frequency according to the selected clock source */
+ input_freq = (clk & 1) + 1;
+
+ pll_config = wl1271_top_reg_read(wl, MCS_PLL_CONFIG_REG);
+ if (pll_config == 0xFFFF)
+ return -EFAULT;
+ pll_config |= (input_freq << MCS_SEL_IN_FREQ_SHIFT);
+ pll_config |= MCS_PLL_ENABLE_HP;
+ wl1271_top_reg_write(wl, MCS_PLL_CONFIG_REG, pll_config);
+
+ return 0;
+}
+
+/*
+ * WL128x has two clocks input - TCXO and FREF.
+ * TCXO is the main clock of the device, while FREF is used to sync
+ * between the GPS and the cellular modem.
+ * In cases where TCXO is 32.736MHz or 16.368MHz, the FREF will be used
+ * as the WLAN/BT main clock.
+ */
+static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock)
+{
+ u16 sys_clk_cfg;
+
+ /* For XTAL-only modes, FREF will be used after switching from TCXO */
+ if (wl->ref_clock == WL12XX_REFCLOCK_26_XTAL ||
+ wl->ref_clock == WL12XX_REFCLOCK_38_XTAL) {
+ if (!wl128x_switch_tcxo_to_fref(wl))
+ return -EINVAL;
+ goto fref_clk;
+ }
+
+ /* Query the HW, to determine which clock source we should use */
+ sys_clk_cfg = wl1271_top_reg_read(wl, SYS_CLK_CFG_REG);
+ if (sys_clk_cfg == 0xFFFF)
+ return -EINVAL;
+ if (sys_clk_cfg & PRCM_CM_EN_MUX_WLAN_FREF)
+ goto fref_clk;
+
+ /* If TCXO is either 32.736MHz or 16.368MHz, switch to FREF */
+ if (wl->tcxo_clock == WL12XX_TCXOCLOCK_16_368 ||
+ wl->tcxo_clock == WL12XX_TCXOCLOCK_32_736) {
+ if (!wl128x_switch_tcxo_to_fref(wl))
+ return -EINVAL;
+ goto fref_clk;
+ }
+
+ /* TCXO clock is selected */
+ if (!wl128x_is_tcxo_valid(wl))
+ return -EINVAL;
+ *selected_clock = wl->tcxo_clock;
+ goto config_mcs_pll;
+
+fref_clk:
+ /* FREF clock is selected */
+ if (!wl128x_is_fref_valid(wl))
+ return -EINVAL;
+ *selected_clock = wl->ref_clock;
+
+config_mcs_pll:
+ return wl128x_configure_mcs_pll(wl, *selected_clock);
+}
+
+static int wl127x_boot_clk(struct wl1271 *wl)
+{
+ u32 pause;
+ u32 clk;
wl1271_boot_hw_version(wl);
- if (wl->ref_clock == 0 || wl->ref_clock == 2 || wl->ref_clock == 4)
+ if (wl->ref_clock == CONF_REF_CLK_19_2_E ||
+ wl->ref_clock == CONF_REF_CLK_38_4_E ||
+ wl->ref_clock == CONF_REF_CLK_38_4_M_XTAL)
/* ref clk: 19.2/38.4/38.4-XTAL */
clk = 0x3;
- else if (wl->ref_clock == 1 || wl->ref_clock == 3)
+ else if (wl->ref_clock == CONF_REF_CLK_26_E ||
+ wl->ref_clock == CONF_REF_CLK_52_E)
/* ref clk: 26/52 */
clk = 0x5;
else
return -EINVAL;
- if (wl->ref_clock != 0) {
+ if (wl->ref_clock != CONF_REF_CLK_19_2_E) {
u16 val;
/* Set clock type (open drain) */
val = wl1271_top_reg_read(wl, OCP_REG_CLK_TYPE);
@@ -540,6 +707,26 @@ int wl1271_load_firmware(struct wl1271 *wl)
pause |= WU_COUNTER_PAUSE_VAL;
wl1271_write32(wl, WU_COUNTER_PAUSE, pause);
+ return 0;
+}
+
+/* uploads NVS and firmware */
+int wl1271_load_firmware(struct wl1271 *wl)
+{
+ int ret = 0;
+ u32 tmp, clk;
+ int selected_clock = -1;
+
+ if (wl->chip.id == CHIP_ID_1283_PG20) {
+ ret = wl128x_boot_clk(wl, &selected_clock);
+ if (ret < 0)
+ goto out;
+ } else {
+ ret = wl127x_boot_clk(wl);
+ if (ret < 0)
+ goto out;
+ }
+
/* Continue the ELP wake up sequence */
wl1271_write32(wl, WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL);
udelay(500);
@@ -555,7 +742,12 @@ int wl1271_load_firmware(struct wl1271 *wl)
wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk);
- clk |= (wl->ref_clock << 1) << 4;
+ if (wl->chip.id == CHIP_ID_1283_PG20) {
+ clk |= ((selected_clock & 0x3) << 1) << 4;
+ } else {
+ clk |= (wl->ref_clock << 1) << 4;
+ }
+
wl1271_write32(wl, DRPW_SCRATCH_START, clk);
wl1271_set_partition(wl, &part_table[PART_WORK]);
@@ -585,16 +777,12 @@ int wl1271_load_firmware(struct wl1271 *wl)
/* 6. read the EEPROM parameters */
tmp = wl1271_read32(wl, SCR_PAD2);
- ret = wl1271_boot_write_irq_polarity(wl);
- if (ret < 0)
- goto out;
-
- wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
- WL1271_ACX_ALL_EVENTS_VECTOR);
-
/* WL1271: The reference driver skips steps 7 to 10 (jumps directly
* to upload_fw) */
+ if (wl->chip.id == CHIP_ID_1283_PG20)
+ wl1271_top_reg_write(wl, SDIO_IO_DS, wl->conf.hci_io_ds);
+
ret = wl1271_boot_upload_firmware(wl);
if (ret < 0)
goto out;
@@ -618,6 +806,13 @@ int wl1271_boot(struct wl1271 *wl)
if (ret < 0)
goto out;
+ ret = wl1271_boot_write_irq_polarity(wl);
+ if (ret < 0)
+ goto out;
+
+ wl1271_write32(wl, ACX_REG_INTERRUPT_MASK,
+ WL1271_ACX_ALL_EVENTS_VECTOR);
+
/* Enable firmware interrupts now */
wl1271_boot_enable_interrupts(wl);
diff --git a/drivers/net/wireless/wl12xx/boot.h b/drivers/net/wireless/wl12xx/boot.h
index 17229b86fc71..e8f8255bbabe 100644
--- a/drivers/net/wireless/wl12xx/boot.h
+++ b/drivers/net/wireless/wl12xx/boot.h
@@ -74,4 +74,56 @@ struct wl1271_static_data {
#define FREF_CLK_POLARITY_BITS 0xfffff8ff
#define CLK_REQ_OUTN_SEL 0x700
+/* PLL configuration algorithm for wl128x */
+#define SYS_CLK_CFG_REG 0x2200
+/* Bit[0] - 0-TCXO, 1-FREF */
+#define MCS_PLL_CLK_SEL_FREF BIT(0)
+/* Bit[3:2] - 01-TCXO, 10-FREF */
+#define WL_CLK_REQ_TYPE_FREF BIT(3)
+#define WL_CLK_REQ_TYPE_PG2 (BIT(3) | BIT(2))
+/* Bit[4] - 0-TCXO, 1-FREF */
+#define PRCM_CM_EN_MUX_WLAN_FREF BIT(4)
+
+#define TCXO_ILOAD_INT_REG 0x2264
+#define TCXO_CLK_DETECT_REG 0x2266
+
+#define TCXO_DET_FAILED BIT(4)
+
+#define FREF_ILOAD_INT_REG 0x2084
+#define FREF_CLK_DETECT_REG 0x2086
+#define FREF_CLK_DETECT_FAIL BIT(4)
+
+/* Use this reg for masking during driver access */
+#define WL_SPARE_REG 0x2320
+#define WL_SPARE_VAL BIT(2)
+/* Bit[6:5:3] - mask wl write SYS_CLK_CFG[8:5:2:4] */
+#define WL_SPARE_MASK_8526 (BIT(6) | BIT(5) | BIT(3))
+
+#define PLL_LOCK_COUNTERS_REG 0xD8C
+#define PLL_LOCK_COUNTERS_COEX 0x0F
+#define PLL_LOCK_COUNTERS_MCS 0xF0
+#define MCS_PLL_OVERRIDE_REG 0xD90
+#define MCS_PLL_CONFIG_REG 0xD92
+#define MCS_SEL_IN_FREQ_MASK 0x0070
+#define MCS_SEL_IN_FREQ_SHIFT 4
+#define MCS_PLL_CONFIG_REG_VAL 0x73
+#define MCS_PLL_ENABLE_HP (BIT(0) | BIT(1))
+
+#define MCS_PLL_M_REG 0xD94
+#define MCS_PLL_N_REG 0xD96
+#define MCS_PLL_M_REG_VAL 0xC8
+#define MCS_PLL_N_REG_VAL 0x07
+
+#define SDIO_IO_DS 0xd14
+
+/* SDIO/wSPI DS configuration values */
+enum {
+ HCI_IO_DS_8MA = 0,
+ HCI_IO_DS_4MA = 1, /* default */
+ HCI_IO_DS_6MA = 2,
+ HCI_IO_DS_2MA = 3,
+};
+
+/* end PLL configuration algorithm for wl128x */
+
#endif
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index 96324336f936..42935ac72663 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -76,7 +76,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
if (time_after(jiffies, timeout)) {
wl1271_error("command complete timeout");
ret = -ETIMEDOUT;
- goto out;
+ goto fail;
}
poll_count++;
@@ -96,21 +96,67 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
status = le16_to_cpu(cmd->status);
if (status != CMD_STATUS_SUCCESS) {
wl1271_error("command execute failure %d", status);
- ieee80211_queue_work(wl->hw, &wl->recovery_work);
ret = -EIO;
+ goto fail;
}
wl1271_write32(wl, ACX_REG_INTERRUPT_ACK,
WL1271_ACX_INTR_CMD_COMPLETE);
+ return 0;
-out:
+fail:
+ WARN_ON(1);
+ ieee80211_queue_work(wl->hw, &wl->recovery_work);
return ret;
}
int wl1271_cmd_general_parms(struct wl1271 *wl)
{
struct wl1271_general_parms_cmd *gen_parms;
- struct wl1271_ini_general_params *gp = &wl->nvs->general_params;
+ struct wl1271_ini_general_params *gp =
+ &((struct wl1271_nvs_file *)wl->nvs)->general_params;
+ bool answer = false;
+ int ret;
+
+ if (!wl->nvs)
+ return -ENODEV;
+
+ gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
+ if (!gen_parms)
+ return -ENOMEM;
+
+ gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
+
+ memcpy(&gen_parms->general_params, gp, sizeof(*gp));
+
+ if (gp->tx_bip_fem_auto_detect)
+ answer = true;
+
+ /* Override the REF CLK from the NVS with the one from platform data */
+ gen_parms->general_params.ref_clock = wl->ref_clock;
+
+ ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
+ if (ret < 0) {
+ wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
+ goto out;
+ }
+
+ gp->tx_bip_fem_manufacturer =
+ gen_parms->general_params.tx_bip_fem_manufacturer;
+
+ wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n",
+ answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer);
+
+out:
+ kfree(gen_parms);
+ return ret;
+}
+
+int wl128x_cmd_general_parms(struct wl1271 *wl)
+{
+ struct wl128x_general_parms_cmd *gen_parms;
+ struct wl128x_ini_general_params *gp =
+ &((struct wl128x_nvs_file *)wl->nvs)->general_params;
bool answer = false;
int ret;
@@ -128,6 +174,10 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
if (gp->tx_bip_fem_auto_detect)
answer = true;
+ /* Replace REF and TCXO CLKs with the ones from platform data */
+ gen_parms->general_params.ref_clock = wl->ref_clock;
+ gen_parms->general_params.tcxo_ref_clock = wl->tcxo_clock;
+
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
if (ret < 0) {
wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
@@ -147,8 +197,9 @@ out:
int wl1271_cmd_radio_parms(struct wl1271 *wl)
{
+ struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs;
struct wl1271_radio_parms_cmd *radio_parms;
- struct wl1271_ini_general_params *gp = &wl->nvs->general_params;
+ struct wl1271_ini_general_params *gp = &nvs->general_params;
int ret;
if (!wl->nvs)
@@ -161,18 +212,18 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
/* 2.4GHz parameters */
- memcpy(&radio_parms->static_params_2, &wl->nvs->stat_radio_params_2,
+ memcpy(&radio_parms->static_params_2, &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,
+ &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,
+ &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,
+ &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: ",
@@ -186,6 +237,50 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
return ret;
}
+int wl128x_cmd_radio_parms(struct wl1271 *wl)
+{
+ struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs;
+ struct wl128x_radio_parms_cmd *radio_parms;
+ struct wl128x_ini_general_params *gp = &nvs->general_params;
+ int ret;
+
+ if (!wl->nvs)
+ return -ENODEV;
+
+ radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL);
+ if (!radio_parms)
+ return -ENOMEM;
+
+ radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
+
+ /* 2.4GHz parameters */
+ memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
+ sizeof(struct wl128x_ini_band_params_2));
+ memcpy(&radio_parms->dyn_params_2,
+ &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
+ sizeof(struct wl128x_ini_fem_params_2));
+
+ /* 5GHz parameters */
+ memcpy(&radio_parms->static_params_5,
+ &nvs->stat_radio_params_5,
+ sizeof(struct wl128x_ini_band_params_5));
+ memcpy(&radio_parms->dyn_params_5,
+ &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
+ sizeof(struct wl128x_ini_fem_params_5));
+
+ radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options;
+
+ wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
+ radio_parms, sizeof(*radio_parms));
+
+ ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0);
+ if (ret < 0)
+ wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed");
+
+ kfree(radio_parms);
+ return ret;
+}
+
int wl1271_cmd_ext_radio_parms(struct wl1271 *wl)
{
struct wl1271_ext_radio_parms_cmd *ext_radio_parms;
diff --git a/drivers/net/wireless/wl12xx/cmd.h b/drivers/net/wireless/wl12xx/cmd.h
index 54c12e71417e..5cac95d9480c 100644
--- a/drivers/net/wireless/wl12xx/cmd.h
+++ b/drivers/net/wireless/wl12xx/cmd.h
@@ -32,7 +32,9 @@ struct acx_header;
int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
size_t res_len);
int wl1271_cmd_general_parms(struct wl1271 *wl);
+int wl128x_cmd_general_parms(struct wl1271 *wl);
int wl1271_cmd_radio_parms(struct wl1271 *wl);
+int wl128x_cmd_radio_parms(struct wl1271 *wl);
int wl1271_cmd_ext_radio_parms(struct wl1271 *wl);
int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type);
int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer);
@@ -415,6 +417,21 @@ struct wl1271_general_parms_cmd {
u8 padding[3];
} __packed;
+struct wl128x_general_parms_cmd {
+ struct wl1271_cmd_header header;
+
+ struct wl1271_cmd_test_header test;
+
+ struct wl128x_ini_general_params general_params;
+
+ 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;
@@ -431,6 +448,23 @@ struct wl1271_radio_parms_cmd {
u8 padding3[2];
} __packed;
+struct wl128x_radio_parms_cmd {
+ struct wl1271_cmd_header header;
+
+ struct wl1271_cmd_test_header test;
+
+ /* Static radio parameters */
+ struct wl128x_ini_band_params_2 static_params_2;
+ struct wl128x_ini_band_params_5 static_params_5;
+
+ u8 fem_vendor_and_options;
+
+ /* Dynamic radio parameters */
+ struct wl128x_ini_fem_params_2 dyn_params_2;
+ u8 padding2;
+ struct wl128x_ini_fem_params_5 dyn_params_5;
+} __packed;
+
struct wl1271_ext_radio_parms_cmd {
struct wl1271_cmd_header header;
diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h
index 8a8323896eec..1ab6c86aac40 100644
--- a/drivers/net/wireless/wl12xx/conf.h
+++ b/drivers/net/wireless/wl12xx/conf.h
@@ -396,12 +396,43 @@ enum {
CONF_SG_TEMP_PARAM_3,
CONF_SG_TEMP_PARAM_4,
CONF_SG_TEMP_PARAM_5,
- CONF_SG_PARAMS_MAX,
+
+ /*
+ * AP beacon miss
+ *
+ * Range: 0 - 255
+ */
+ CONF_SG_AP_BEACON_MISS_TX,
+
+ /*
+ * AP RX window length
+ *
+ * Range: 0 - 50
+ */
+ CONF_SG_RX_WINDOW_LENGTH,
+
+ /*
+ * AP connection protection time
+ *
+ * Range: 0 - 5000
+ */
+ CONF_SG_AP_CONNECTION_PROTECTION_TIME,
+
+ CONF_SG_TEMP_PARAM_6,
+ CONF_SG_TEMP_PARAM_7,
+ CONF_SG_TEMP_PARAM_8,
+ CONF_SG_TEMP_PARAM_9,
+ CONF_SG_TEMP_PARAM_10,
+
+ CONF_SG_STA_PARAMS_MAX = CONF_SG_TEMP_PARAM_5 + 1,
+ CONF_SG_AP_PARAMS_MAX = CONF_SG_TEMP_PARAM_10 + 1,
+
CONF_SG_PARAMS_ALL = 0xff
};
struct conf_sg_settings {
- u32 params[CONF_SG_PARAMS_MAX];
+ u32 sta_params[CONF_SG_STA_PARAMS_MAX];
+ u32 ap_params[CONF_SG_AP_PARAMS_MAX];
u8 state;
};
@@ -509,6 +540,12 @@ struct conf_rx_settings {
CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \
CONF_HW_BIT_RATE_54MBPS)
+#define CONF_TX_OFDM_RATES (CONF_HW_BIT_RATE_6MBPS | \
+ CONF_HW_BIT_RATE_12MBPS | CONF_HW_BIT_RATE_24MBPS | \
+ CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \
+ CONF_HW_BIT_RATE_54MBPS)
+
+
/*
* Default rates for management traffic when operating in AP mode. This
* should be configured according to the basic rate set of the AP
@@ -516,6 +553,13 @@ struct conf_rx_settings {
#define CONF_TX_AP_DEFAULT_MGMT_RATES (CONF_HW_BIT_RATE_1MBPS | \
CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS)
+/*
+ * Default rates for working as IBSS. use 11b rates
+ */
+#define CONF_TX_IBSS_DEFAULT_RATES (CONF_HW_BIT_RATE_1MBPS | \
+ CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \
+ CONF_HW_BIT_RATE_11MBPS);
+
struct conf_tx_rate_class {
/*
@@ -667,22 +711,6 @@ struct conf_tx_settings {
struct conf_tx_ac_category ac_conf[CONF_TX_MAX_AC_COUNT];
/*
- * Configuration for rate classes in AP-mode. These rate classes
- * are for the AC TX queues
- */
- struct conf_tx_rate_class ap_rc_conf[CONF_TX_MAX_AC_COUNT];
-
- /*
- * Management TX rate class for AP-mode.
- */
- struct conf_tx_rate_class ap_mgmt_conf;
-
- /*
- * Broadcast TX rate class for AP-mode.
- */
- struct conf_tx_rate_class ap_bcst_conf;
-
- /*
* AP-mode - allow this number of TX retries to a station before an
* event is triggered from FW.
*/
@@ -1004,7 +1032,9 @@ enum {
CONF_REF_CLK_19_2_E,
CONF_REF_CLK_26_E,
CONF_REF_CLK_38_4_E,
- CONF_REF_CLK_52_E
+ CONF_REF_CLK_52_E,
+ CONF_REF_CLK_38_4_M_XTAL,
+ CONF_REF_CLK_26_M_XTAL,
};
enum single_dual_band_enum {
@@ -1018,15 +1048,6 @@ enum single_dual_band_enum {
#define CONF_NUMBER_OF_CHANNELS_2_4 14
#define CONF_NUMBER_OF_CHANNELS_5 35
-struct conf_radio_parms {
- /*
- * FEM parameter set to use
- *
- * Range: 0 or 1
- */
- u8 fem;
-};
-
struct conf_itrim_settings {
/* enable dco itrim */
u8 enable;
@@ -1126,6 +1147,26 @@ struct conf_scan_settings {
};
+struct conf_sched_scan_settings {
+ /* minimum time to wait on the channel for active scans (in TUs) */
+ u16 min_dwell_time_active;
+
+ /* maximum time to wait on the channel for active scans (in TUs) */
+ u16 max_dwell_time_active;
+
+ /* time to wait on the channel for passive scans (in TUs) */
+ u32 dwell_time_passive;
+
+ /* number of probe requests to send on each channel in active scans */
+ u8 num_probe_reqs;
+
+ /* RSSI threshold to be used for filtering */
+ s8 rssi_threshold;
+
+ /* SNR threshold to be used for filtering */
+ s8 snr_threshold;
+};
+
/* these are number of channels on the band divided by two, rounded up */
#define CONF_TX_PWR_COMPENSATION_LEN_2 7
#define CONF_TX_PWR_COMPENSATION_LEN_5 18
@@ -1191,6 +1232,19 @@ struct conf_memory_settings {
u8 tx_min;
};
+struct conf_fm_coex {
+ u8 enable;
+ u8 swallow_period;
+ u8 n_divider_fref_set_1;
+ u8 n_divider_fref_set_2;
+ u16 m_divider_fref_set_1;
+ u16 m_divider_fref_set_2;
+ u32 coex_pll_stabilization_time;
+ u16 ldo_stabilization_time;
+ u8 fm_disturbed_band_margin;
+ u8 swallow_clk_diff;
+};
+
struct conf_drv_settings {
struct conf_sg_settings sg;
struct conf_rx_settings rx;
@@ -1200,9 +1254,13 @@ struct conf_drv_settings {
struct conf_pm_config_settings pm_config;
struct conf_roam_trigger_settings roam_trigger;
struct conf_scan_settings scan;
+ struct conf_sched_scan_settings sched_scan;
struct conf_rf_settings rf;
struct conf_ht_setting ht;
- struct conf_memory_settings mem;
+ struct conf_memory_settings mem_wl127x;
+ struct conf_memory_settings mem_wl128x;
+ struct conf_fm_coex fm_coex;
+ u8 hci_io_ds;
};
#endif
diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
index 8e75b09723b9..f1f8df9b6cd7 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/debugfs.c
@@ -267,7 +267,7 @@ static ssize_t gpio_power_write(struct file *file,
}
buf[len] = '\0';
- ret = strict_strtoul(buf, 0, &value);
+ ret = kstrtoul(buf, 0, &value);
if (ret < 0) {
wl1271_warning("illegal value in gpio_power");
return -EINVAL;
@@ -291,6 +291,242 @@ static const struct file_operations gpio_power_ops = {
.llseek = default_llseek,
};
+static ssize_t start_recovery_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+
+ mutex_lock(&wl->mutex);
+ ieee80211_queue_work(wl->hw, &wl->recovery_work);
+ mutex_unlock(&wl->mutex);
+
+ return count;
+}
+
+static const struct file_operations start_recovery_ops = {
+ .write = start_recovery_write,
+ .open = wl1271_open_file_generic,
+ .llseek = default_llseek,
+};
+
+static ssize_t driver_state_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+ int res = 0;
+ char buf[1024];
+
+ mutex_lock(&wl->mutex);
+
+#define DRIVER_STATE_PRINT(x, fmt) \
+ (res += scnprintf(buf + res, sizeof(buf) - res,\
+ #x " = " fmt "\n", wl->x))
+
+#define DRIVER_STATE_PRINT_LONG(x) DRIVER_STATE_PRINT(x, "%ld")
+#define DRIVER_STATE_PRINT_INT(x) DRIVER_STATE_PRINT(x, "%d")
+#define DRIVER_STATE_PRINT_STR(x) DRIVER_STATE_PRINT(x, "%s")
+#define DRIVER_STATE_PRINT_LHEX(x) DRIVER_STATE_PRINT(x, "0x%lx")
+#define DRIVER_STATE_PRINT_HEX(x) DRIVER_STATE_PRINT(x, "0x%x")
+
+ DRIVER_STATE_PRINT_INT(tx_blocks_available);
+ DRIVER_STATE_PRINT_INT(tx_allocated_blocks);
+ DRIVER_STATE_PRINT_INT(tx_frames_cnt);
+ DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]);
+ DRIVER_STATE_PRINT_INT(tx_queue_count);
+ DRIVER_STATE_PRINT_INT(tx_packets_count);
+ DRIVER_STATE_PRINT_INT(tx_results_count);
+ DRIVER_STATE_PRINT_LHEX(flags);
+ DRIVER_STATE_PRINT_INT(tx_blocks_freed[0]);
+ DRIVER_STATE_PRINT_INT(tx_blocks_freed[1]);
+ DRIVER_STATE_PRINT_INT(tx_blocks_freed[2]);
+ DRIVER_STATE_PRINT_INT(tx_blocks_freed[3]);
+ DRIVER_STATE_PRINT_INT(tx_security_last_seq);
+ DRIVER_STATE_PRINT_INT(rx_counter);
+ DRIVER_STATE_PRINT_INT(session_counter);
+ DRIVER_STATE_PRINT_INT(state);
+ DRIVER_STATE_PRINT_INT(bss_type);
+ DRIVER_STATE_PRINT_INT(channel);
+ DRIVER_STATE_PRINT_HEX(rate_set);
+ DRIVER_STATE_PRINT_HEX(basic_rate_set);
+ DRIVER_STATE_PRINT_HEX(basic_rate);
+ DRIVER_STATE_PRINT_INT(band);
+ DRIVER_STATE_PRINT_INT(beacon_int);
+ DRIVER_STATE_PRINT_INT(psm_entry_retry);
+ DRIVER_STATE_PRINT_INT(ps_poll_failures);
+ DRIVER_STATE_PRINT_HEX(filters);
+ DRIVER_STATE_PRINT_HEX(rx_config);
+ DRIVER_STATE_PRINT_HEX(rx_filter);
+ DRIVER_STATE_PRINT_INT(power_level);
+ DRIVER_STATE_PRINT_INT(rssi_thold);
+ DRIVER_STATE_PRINT_INT(last_rssi_event);
+ DRIVER_STATE_PRINT_INT(sg_enabled);
+ DRIVER_STATE_PRINT_INT(enable_11a);
+ DRIVER_STATE_PRINT_INT(noise);
+ DRIVER_STATE_PRINT_LHEX(ap_hlid_map[0]);
+ DRIVER_STATE_PRINT_INT(last_tx_hlid);
+ DRIVER_STATE_PRINT_INT(ba_support);
+ DRIVER_STATE_PRINT_HEX(ba_rx_bitmap);
+ DRIVER_STATE_PRINT_HEX(ap_fw_ps_map);
+ DRIVER_STATE_PRINT_LHEX(ap_ps_map);
+ DRIVER_STATE_PRINT_HEX(quirks);
+ DRIVER_STATE_PRINT_HEX(irq);
+ DRIVER_STATE_PRINT_HEX(ref_clock);
+ DRIVER_STATE_PRINT_HEX(tcxo_clock);
+ DRIVER_STATE_PRINT_HEX(hw_pg_ver);
+ DRIVER_STATE_PRINT_HEX(platform_quirks);
+ DRIVER_STATE_PRINT_HEX(chip.id);
+ DRIVER_STATE_PRINT_STR(chip.fw_ver_str);
+ DRIVER_STATE_PRINT_INT(sched_scanning);
+
+#undef DRIVER_STATE_PRINT_INT
+#undef DRIVER_STATE_PRINT_LONG
+#undef DRIVER_STATE_PRINT_HEX
+#undef DRIVER_STATE_PRINT_LHEX
+#undef DRIVER_STATE_PRINT_STR
+#undef DRIVER_STATE_PRINT
+
+ mutex_unlock(&wl->mutex);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, res);
+}
+
+static const struct file_operations driver_state_ops = {
+ .read = driver_state_read,
+ .open = wl1271_open_file_generic,
+ .llseek = default_llseek,
+};
+
+static ssize_t dtim_interval_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+ u8 value;
+
+ if (wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_DTIM ||
+ wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_N_DTIM)
+ value = wl->conf.conn.listen_interval;
+ else
+ value = 0;
+
+ return wl1271_format_buffer(user_buf, count, ppos, "%d\n", value);
+}
+
+static ssize_t dtim_interval_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+ char buf[10];
+ size_t len;
+ unsigned long value;
+ int ret;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+ buf[len] = '\0';
+
+ ret = kstrtoul(buf, 0, &value);
+ if (ret < 0) {
+ wl1271_warning("illegal value for dtim_interval");
+ return -EINVAL;
+ }
+
+ if (value < 1 || value > 10) {
+ wl1271_warning("dtim value is not in valid range");
+ return -ERANGE;
+ }
+
+ mutex_lock(&wl->mutex);
+
+ wl->conf.conn.listen_interval = value;
+ /* for some reason there are different event types for 1 and >1 */
+ if (value == 1)
+ wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_DTIM;
+ else
+ wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM;
+
+ /*
+ * we don't reconfigure ACX_WAKE_UP_CONDITIONS now, so it will only
+ * take effect on the next time we enter psm.
+ */
+ mutex_unlock(&wl->mutex);
+ return count;
+}
+
+static const struct file_operations dtim_interval_ops = {
+ .read = dtim_interval_read,
+ .write = dtim_interval_write,
+ .open = wl1271_open_file_generic,
+ .llseek = default_llseek,
+};
+
+static ssize_t beacon_interval_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+ u8 value;
+
+ if (wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_BEACON ||
+ wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_N_BEACONS)
+ value = wl->conf.conn.listen_interval;
+ else
+ value = 0;
+
+ return wl1271_format_buffer(user_buf, count, ppos, "%d\n", value);
+}
+
+static ssize_t beacon_interval_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+ char buf[10];
+ size_t len;
+ unsigned long value;
+ int ret;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+ buf[len] = '\0';
+
+ ret = kstrtoul(buf, 0, &value);
+ if (ret < 0) {
+ wl1271_warning("illegal value for beacon_interval");
+ return -EINVAL;
+ }
+
+ if (value < 1 || value > 255) {
+ wl1271_warning("beacon interval value is not in valid range");
+ return -ERANGE;
+ }
+
+ mutex_lock(&wl->mutex);
+
+ wl->conf.conn.listen_interval = value;
+ /* for some reason there are different event types for 1 and >1 */
+ if (value == 1)
+ wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_BEACON;
+ else
+ wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_N_BEACONS;
+
+ /*
+ * we don't reconfigure ACX_WAKE_UP_CONDITIONS now, so it will only
+ * take effect on the next time we enter psm.
+ */
+ mutex_unlock(&wl->mutex);
+ return count;
+}
+
+static const struct file_operations beacon_interval_ops = {
+ .read = beacon_interval_read,
+ .write = beacon_interval_write,
+ .open = wl1271_open_file_generic,
+ .llseek = default_llseek,
+};
+
static int wl1271_debugfs_add_files(struct wl1271 *wl,
struct dentry *rootdir)
{
@@ -399,6 +635,10 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
DEBUGFS_ADD(excessive_retries, rootdir);
DEBUGFS_ADD(gpio_power, rootdir);
+ DEBUGFS_ADD(start_recovery, rootdir);
+ DEBUGFS_ADD(driver_state, rootdir);
+ DEBUGFS_ADD(dtim_interval, rootdir);
+ DEBUGFS_ADD(beacon_interval, rootdir);
return 0;
diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c
index 1b170c5cc595..c3c554cd6580 100644
--- a/drivers/net/wireless/wl12xx/event.c
+++ b/drivers/net/wireless/wl12xx/event.c
@@ -33,6 +33,7 @@ void wl1271_pspoll_work(struct work_struct *work)
{
struct delayed_work *dwork;
struct wl1271 *wl;
+ int ret;
dwork = container_of(work, struct delayed_work, work);
wl = container_of(dwork, struct wl1271, pspoll_work);
@@ -55,8 +56,13 @@ void wl1271_pspoll_work(struct work_struct *work)
* delivery failure occurred, and no-one changed state since, so
* we should go back to powersave.
*/
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE, wl->basic_rate, true);
+ wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
};
@@ -132,8 +138,10 @@ static int wl1271_event_ps_report(struct wl1271 *wl,
if (ret < 0)
break;
- /* go to extremely low power mode */
- wl1271_ps_elp_sleep(wl);
+ if (wl->ps_compl) {
+ complete(wl->ps_compl);
+ wl->ps_compl = NULL;
+ }
break;
default:
break;
@@ -187,6 +195,22 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
wl1271_scan_stm(wl);
}
+ if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) {
+ wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_REPORT_EVENT "
+ "(status 0x%0x)", mbox->scheduled_scan_status);
+
+ wl1271_scan_sched_scan_results(wl);
+ }
+
+ if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID) {
+ wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_COMPLETE_EVENT "
+ "(status 0x%0x)", mbox->scheduled_scan_status);
+ if (wl->sched_scanning) {
+ wl1271_scan_sched_scan_stop(wl);
+ ieee80211_sched_scan_stopped(wl->hw);
+ }
+ }
+
/* disable dynamic PS when requested by the firmware */
if (vector & SOFT_GEMINI_SENSE_EVENT_ID &&
wl->bss_type == BSS_TYPE_STA_BSS) {
@@ -228,6 +252,12 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
wl1271_event_rssi_trigger(wl, mbox);
}
+ if ((vector & DUMMY_PACKET_EVENT_ID) && !is_ap) {
+ wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
+ if (wl->vif)
+ wl1271_tx_dummy_packet(wl);
+ }
+
if (wl->vif && beacon_loss)
ieee80211_connection_loss(wl->vif);
diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h
index 0e80886f3031..b6cf06e565a4 100644
--- a/drivers/net/wireless/wl12xx/event.h
+++ b/drivers/net/wireless/wl12xx/event.h
@@ -59,7 +59,10 @@ enum {
BSS_LOSE_EVENT_ID = BIT(18),
REGAINED_BSS_EVENT_ID = BIT(19),
ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20),
- STA_REMOVE_COMPLETE_EVENT_ID = BIT(21), /* AP */
+ /* STA: dummy paket for dynamic mem blocks */
+ DUMMY_PACKET_EVENT_ID = BIT(21),
+ /* AP: STA remove complete */
+ STA_REMOVE_COMPLETE_EVENT_ID = BIT(21),
SOFT_GEMINI_SENSE_EVENT_ID = BIT(22),
SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23),
SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24),
diff --git a/drivers/net/wireless/wl12xx/ini.h b/drivers/net/wireless/wl12xx/ini.h
index c330a2583dfd..1420c842b8f1 100644
--- a/drivers/net/wireless/wl12xx/ini.h
+++ b/drivers/net/wireless/wl12xx/ini.h
@@ -41,6 +41,28 @@ struct wl1271_ini_general_params {
u8 srf3[WL1271_INI_MAX_SMART_REFLEX_PARAM];
} __packed;
+#define WL128X_INI_MAX_SETTINGS_PARAM 4
+
+struct wl128x_ini_general_params {
+ u8 ref_clock;
+ u8 settling_time;
+ u8 clk_valid_on_wakeup;
+ u8 tcxo_ref_clock;
+ u8 tcxo_settling_time;
+ u8 tcxo_valid_on_wakeup;
+ u8 tcxo_ldo_voltage;
+ u8 xtal_itrim_val;
+ u8 platform_conf;
+ u8 dual_mode_select;
+ u8 tx_bip_fem_auto_detect;
+ u8 tx_bip_fem_manufacturer;
+ u8 general_settings[WL128X_INI_MAX_SETTINGS_PARAM];
+ 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 {
@@ -49,9 +71,16 @@ struct wl1271_ini_band_params_2 {
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 wl128x_ini_band_params_2 {
+ u8 rx_trace_insertion_loss;
+ u8 tx_trace_loss[WL1271_INI_CHANNEL_COUNT_2];
+ u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE];
+} __packed;
+
+#define WL1271_INI_RATE_GROUP_COUNT 6
+
struct wl1271_ini_fem_params_2 {
__le16 tx_bip_ref_pd_voltage;
u8 tx_bip_ref_power;
@@ -68,6 +97,28 @@ struct wl1271_ini_fem_params_2 {
u8 normal_to_degraded_high_thr;
} __packed;
+#define WL128X_INI_RATE_GROUP_COUNT 7
+/* low and high temperatures */
+#define WL128X_INI_PD_VS_TEMPERATURE_RANGES 2
+
+struct wl128x_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[WL128X_INI_RATE_GROUP_COUNT];
+ u8 tx_per_rate_pwr_limits_degraded[WL128X_INI_RATE_GROUP_COUNT];
+ u8 tx_per_rate_pwr_limits_extreme[WL128X_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[WL128X_INI_RATE_GROUP_COUNT];
+ u8 tx_ibias[WL128X_INI_RATE_GROUP_COUNT + 1];
+ u8 tx_pd_vs_chan_offsets[WL1271_INI_CHANNEL_COUNT_2];
+ u8 tx_pd_vs_temperature[WL128X_INI_PD_VS_TEMPERATURE_RANGES];
+ 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
@@ -77,6 +128,12 @@ struct wl1271_ini_band_params_5 {
u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE];
} __packed;
+struct wl128x_ini_band_params_5 {
+ u8 rx_trace_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5];
+ u8 tx_trace_loss[WL1271_INI_CHANNEL_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];
@@ -92,6 +149,23 @@ struct wl1271_ini_fem_params_5 {
u8 normal_to_degraded_high_thr;
} __packed;
+struct wl128x_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[WL128X_INI_RATE_GROUP_COUNT];
+ u8 tx_per_rate_pwr_limits_degraded[WL128X_INI_RATE_GROUP_COUNT];
+ u8 tx_per_rate_pwr_limits_extreme[WL128X_INI_RATE_GROUP_COUNT];
+ u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_5];
+ u8 tx_pd_vs_rate_offsets[WL128X_INI_RATE_GROUP_COUNT];
+ u8 tx_ibias[WL128X_INI_RATE_GROUP_COUNT];
+ u8 tx_pd_vs_chan_offsets[WL1271_INI_CHANNEL_COUNT_5];
+ u8 tx_pd_vs_temperature[WL1271_INI_SUB_BAND_COUNT_5 *
+ WL128X_INI_PD_VS_TEMPERATURE_RANGES];
+ 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
@@ -100,7 +174,7 @@ struct wl1271_ini_fem_params_5 {
#define WL1271_INI_LEGACY_NVS_FILE_SIZE 800
struct wl1271_nvs_file {
- /* NVS section */
+ /* NVS section - must be first! */
u8 nvs[WL1271_INI_NVS_SECTION_SIZE];
/* INI section */
@@ -120,4 +194,24 @@ struct wl1271_nvs_file {
} dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT];
} __packed;
+struct wl128x_nvs_file {
+ /* NVS section - must be first! */
+ u8 nvs[WL1271_INI_NVS_SECTION_SIZE];
+
+ /* INI section */
+ struct wl128x_ini_general_params general_params;
+ u8 fem_vendor_and_options;
+ struct wl128x_ini_band_params_2 stat_radio_params_2;
+ u8 padding2;
+ struct {
+ struct wl128x_ini_fem_params_2 params;
+ u8 padding;
+ } dyn_radio_params_2[WL1271_INI_FEM_MODULE_COUNT];
+ struct wl128x_ini_band_params_5 stat_radio_params_5;
+ u8 padding3;
+ struct {
+ struct wl128x_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/init.c b/drivers/net/wireless/wl12xx/init.c
index 6072fe457135..a8f4f156c055 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -31,6 +31,7 @@
#include "cmd.h"
#include "reg.h"
#include "tx.h"
+#include "io.h"
int wl1271_sta_init_templates_config(struct wl1271 *wl)
{
@@ -257,7 +258,7 @@ int wl1271_init_phy_config(struct wl1271 *wl)
if (ret < 0)
return ret;
- ret = wl1271_acx_rts_threshold(wl, wl->conf.rx.rts_threshold);
+ ret = wl1271_acx_rts_threshold(wl, wl->hw->wiphy->rts_threshold);
if (ret < 0)
return ret;
@@ -284,7 +285,10 @@ int wl1271_init_pta(struct wl1271 *wl)
{
int ret;
- ret = wl1271_acx_sg_cfg(wl);
+ if (wl->bss_type == BSS_TYPE_AP_BSS)
+ ret = wl1271_acx_ap_sg_cfg(wl);
+ else
+ ret = wl1271_acx_sta_sg_cfg(wl);
if (ret < 0)
return ret;
@@ -321,9 +325,11 @@ static int wl1271_sta_hw_init(struct wl1271 *wl)
{
int ret;
- ret = wl1271_cmd_ext_radio_parms(wl);
- if (ret < 0)
- return ret;
+ if (wl->chip.id != CHIP_ID_1283_PG20) {
+ ret = wl1271_cmd_ext_radio_parms(wl);
+ if (ret < 0)
+ return ret;
+ }
/* PS config */
ret = wl1271_acx_config_ps(wl);
@@ -348,8 +354,8 @@ static int wl1271_sta_hw_init(struct wl1271 *wl)
if (ret < 0)
return ret;
- /* Bluetooth WLAN coexistence */
- ret = wl1271_init_pta(wl);
+ /* FM WLAN coexistence */
+ ret = wl1271_acx_fm_coex(wl);
if (ret < 0)
return ret;
@@ -407,7 +413,7 @@ static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl)
static int wl1271_ap_hw_init(struct wl1271 *wl)
{
- int ret, i;
+ int ret;
ret = wl1271_ap_init_templates_config(wl);
if (ret < 0)
@@ -418,23 +424,7 @@ static int wl1271_ap_hw_init(struct wl1271 *wl)
if (ret < 0)
return ret;
- /* Configure initial TX rate classes */
- for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
- ret = wl1271_acx_ap_rate_policy(wl,
- &wl->conf.tx.ap_rc_conf[i], i);
- if (ret < 0)
- return ret;
- }
-
- ret = wl1271_acx_ap_rate_policy(wl,
- &wl->conf.tx.ap_mgmt_conf,
- ACX_TX_AP_MODE_MGMT_RATE);
- if (ret < 0)
- return ret;
-
- ret = wl1271_acx_ap_rate_policy(wl,
- &wl->conf.tx.ap_bcst_conf,
- ACX_TX_AP_MODE_BCST_RATE);
+ ret = wl1271_init_ap_rates(wl);
if (ret < 0)
return ret;
@@ -449,7 +439,7 @@ static int wl1271_ap_hw_init(struct wl1271 *wl)
return 0;
}
-static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl)
+int wl1271_ap_init_templates(struct wl1271 *wl)
{
int ret;
@@ -465,6 +455,70 @@ static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl)
if (ret < 0)
return ret;
+ /*
+ * when operating as AP we want to receive external beacons for
+ * configuring ERP protection.
+ */
+ ret = wl1271_acx_set_ap_beacon_filter(wl, false);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl)
+{
+ return wl1271_ap_init_templates(wl);
+}
+
+int wl1271_init_ap_rates(struct wl1271 *wl)
+{
+ int i, ret;
+ struct conf_tx_rate_class rc;
+ u32 supported_rates;
+
+ wl1271_debug(DEBUG_AP, "AP basic rate set: 0x%x", wl->basic_rate_set);
+
+ if (wl->basic_rate_set == 0)
+ return -EINVAL;
+
+ rc.enabled_rates = wl->basic_rate_set;
+ rc.long_retry_limit = 10;
+ rc.short_retry_limit = 10;
+ rc.aflags = 0;
+ ret = wl1271_acx_ap_rate_policy(wl, &rc, ACX_TX_AP_MODE_MGMT_RATE);
+ if (ret < 0)
+ return ret;
+
+ /* use the min basic rate for AP broadcast/multicast */
+ rc.enabled_rates = wl1271_tx_min_rate_get(wl);
+ rc.short_retry_limit = 10;
+ rc.long_retry_limit = 10;
+ rc.aflags = 0;
+ ret = wl1271_acx_ap_rate_policy(wl, &rc, ACX_TX_AP_MODE_BCST_RATE);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * If the basic rates contain OFDM rates, use OFDM only
+ * rates for unicast TX as well. Else use all supported rates.
+ */
+ if ((wl->basic_rate_set & CONF_TX_OFDM_RATES))
+ supported_rates = CONF_TX_OFDM_RATES;
+ else
+ supported_rates = CONF_TX_AP_ENABLED_RATES;
+
+ /* configure unicast TX rate classes */
+ for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
+ rc.enabled_rates = supported_rates;
+ rc.short_retry_limit = 10;
+ rc.long_retry_limit = 10;
+ rc.aflags = 0;
+ ret = wl1271_acx_ap_rate_policy(wl, &rc, i);
+ if (ret < 0)
+ return ret;
+ }
+
return 0;
}
@@ -504,6 +558,27 @@ static int wl1271_set_ba_policies(struct wl1271 *wl)
return ret;
}
+int wl1271_chip_specific_init(struct wl1271 *wl)
+{
+ int ret = 0;
+
+ if (wl->chip.id == CHIP_ID_1283_PG20) {
+ u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE;
+
+ if (wl->quirks & WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT)
+ /* Enable SDIO padding */
+ host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK;
+
+ /* Must be before wl1271_acx_init_mem_config() */
+ ret = wl1271_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap);
+ if (ret < 0)
+ goto out;
+ }
+out:
+ return ret;
+}
+
+
int wl1271_hw_init(struct wl1271 *wl)
{
struct conf_tx_ac_category *conf_ac;
@@ -511,11 +586,22 @@ int wl1271_hw_init(struct wl1271 *wl)
int ret, i;
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
- ret = wl1271_cmd_general_parms(wl);
+ if (wl->chip.id == CHIP_ID_1283_PG20)
+ ret = wl128x_cmd_general_parms(wl);
+ else
+ ret = wl1271_cmd_general_parms(wl);
+ if (ret < 0)
+ return ret;
+
+ if (wl->chip.id == CHIP_ID_1283_PG20)
+ ret = wl128x_cmd_radio_parms(wl);
+ else
+ ret = wl1271_cmd_radio_parms(wl);
if (ret < 0)
return ret;
- ret = wl1271_cmd_radio_parms(wl);
+ /* Chip-specific init */
+ ret = wl1271_chip_specific_init(wl);
if (ret < 0)
return ret;
@@ -528,6 +614,11 @@ int wl1271_hw_init(struct wl1271 *wl)
if (ret < 0)
return ret;
+ /* Bluetooth WLAN coexistence */
+ ret = wl1271_init_pta(wl);
+ if (ret < 0)
+ return ret;
+
/* Default memory configuration */
ret = wl1271_acx_init_mem_config(wl);
if (ret < 0)
@@ -567,7 +658,7 @@ int wl1271_hw_init(struct wl1271 *wl)
goto out_free_memmap;
/* Default fragmentation threshold */
- ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
+ ret = wl1271_acx_frag_threshold(wl, wl->hw->wiphy->frag_threshold);
if (ret < 0)
goto out_free_memmap;
diff --git a/drivers/net/wireless/wl12xx/init.h b/drivers/net/wireless/wl12xx/init.h
index 3a8bd3f426d2..3a3c230fd292 100644
--- a/drivers/net/wireless/wl12xx/init.h
+++ b/drivers/net/wireless/wl12xx/init.h
@@ -31,6 +31,9 @@ int wl1271_sta_init_templates_config(struct wl1271 *wl);
int wl1271_init_phy_config(struct wl1271 *wl);
int wl1271_init_pta(struct wl1271 *wl);
int wl1271_init_energy_detection(struct wl1271 *wl);
+int wl1271_chip_specific_init(struct wl1271 *wl);
int wl1271_hw_init(struct wl1271 *wl);
+int wl1271_init_ap_rates(struct wl1271 *wl);
+int wl1271_ap_init_templates(struct wl1271 *wl);
#endif
diff --git a/drivers/net/wireless/wl12xx/io.c b/drivers/net/wireless/wl12xx/io.c
index d557f73e7c19..da5c1ad942a4 100644
--- a/drivers/net/wireless/wl12xx/io.c
+++ b/drivers/net/wireless/wl12xx/io.c
@@ -29,6 +29,7 @@
#include "wl12xx.h"
#include "wl12xx_80211.h"
#include "io.h"
+#include "tx.h"
#define OCP_CMD_LOOP 32
@@ -43,6 +44,16 @@
#define OCP_STATUS_REQ_FAILED 0x20000
#define OCP_STATUS_RESP_ERROR 0x30000
+bool wl1271_set_block_size(struct wl1271 *wl)
+{
+ if (wl->if_ops->set_block_size) {
+ wl->if_ops->set_block_size(wl, WL12XX_BUS_BLOCK_SIZE);
+ return true;
+ }
+
+ return false;
+}
+
void wl1271_disable_interrupts(struct wl1271 *wl)
{
wl->if_ops->disable_irq(wl);
diff --git a/drivers/net/wireless/wl12xx/io.h b/drivers/net/wireless/wl12xx/io.h
index 00c771ea70bf..beed621a8ae0 100644
--- a/drivers/net/wireless/wl12xx/io.h
+++ b/drivers/net/wireless/wl12xx/io.h
@@ -169,5 +169,8 @@ int wl1271_init_ieee80211(struct wl1271 *wl);
struct ieee80211_hw *wl1271_alloc_hw(void);
int wl1271_free_hw(struct wl1271 *wl);
irqreturn_t wl1271_irq(int irq, void *data);
+bool wl1271_set_block_size(struct wl1271 *wl);
+int wl1271_tx_dummy_packet(struct wl1271 *wl);
+void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters);
#endif
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 8b3c8d196b03..bc00e52f6445 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -30,6 +30,7 @@
#include <linux/vmalloc.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/wl12xx.h>
#include "wl12xx.h"
#include "wl12xx_80211.h"
@@ -50,11 +51,11 @@
static struct conf_drv_settings default_conf = {
.sg = {
- .params = {
+ .sta_params = {
[CONF_SG_BT_PER_THRESHOLD] = 7500,
[CONF_SG_HV3_MAX_OVERRIDE] = 0,
[CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
- [CONF_SG_BT_LOAD_RATIO] = 50,
+ [CONF_SG_BT_LOAD_RATIO] = 200,
[CONF_SG_AUTO_PS_MODE] = 1,
[CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
[CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
@@ -100,6 +101,61 @@ static struct conf_drv_settings default_conf = {
[CONF_SG_DHCP_TIME] = 5000,
[CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
},
+ .ap_params = {
+ [CONF_SG_BT_PER_THRESHOLD] = 7500,
+ [CONF_SG_HV3_MAX_OVERRIDE] = 0,
+ [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
+ [CONF_SG_BT_LOAD_RATIO] = 50,
+ [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,
+ [CONF_SG_BEACON_MISS_PERCENT] = 60,
+ [CONF_SG_RATE_ADAPT_THRESH] = 64,
+ [CONF_SG_RATE_ADAPT_SNR] = 1,
+ [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
+ [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 25,
+ [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 25,
+ [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
+ [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 25,
+ [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 25,
+ [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
+ [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
+ [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 25,
+ [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
+ [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 25,
+ [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 25,
+ [CONF_SG_RXT] = 1200,
+ [CONF_SG_TXT] = 1000,
+ [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
+ [CONF_SG_PS_POLL_TIMEOUT] = 10,
+ [CONF_SG_UPSD_TIMEOUT] = 10,
+ [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
+ [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
+ [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
+ [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
+ [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
+ [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
+ [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
+ [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
+ [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
+ [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
+ [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
+ [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
+ [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
+ [CONF_SG_HV3_MAX_SERVED] = 6,
+ [CONF_SG_DHCP_TIME] = 5000,
+ [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
+ [CONF_SG_TEMP_PARAM_1] = 0,
+ [CONF_SG_TEMP_PARAM_2] = 0,
+ [CONF_SG_TEMP_PARAM_3] = 0,
+ [CONF_SG_TEMP_PARAM_4] = 0,
+ [CONF_SG_TEMP_PARAM_5] = 0,
+ [CONF_SG_AP_BEACON_MISS_TX] = 3,
+ [CONF_SG_RX_WINDOW_LENGTH] = 6,
+ [CONF_SG_AP_CONNECTION_PROTECTION_TIME] = 50,
+ [CONF_SG_TEMP_PARAM_6] = 1,
+ },
.state = CONF_SG_PROTECTIVE,
},
.rx = {
@@ -107,7 +163,7 @@ static struct conf_drv_settings default_conf = {
.packet_detection_threshold = 0,
.ps_poll_timeout = 15,
.upsd_timeout = 15,
- .rts_threshold = 2347,
+ .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
.rx_cca_threshold = 0,
.irq_blk_threshold = 0xFFFF,
.irq_pkt_threshold = 0,
@@ -153,44 +209,6 @@ static struct conf_drv_settings default_conf = {
.tx_op_limit = 1504,
},
},
- .ap_rc_conf = {
- [0] = {
- .enabled_rates = CONF_TX_AP_ENABLED_RATES,
- .short_retry_limit = 10,
- .long_retry_limit = 10,
- .aflags = 0,
- },
- [1] = {
- .enabled_rates = CONF_TX_AP_ENABLED_RATES,
- .short_retry_limit = 10,
- .long_retry_limit = 10,
- .aflags = 0,
- },
- [2] = {
- .enabled_rates = CONF_TX_AP_ENABLED_RATES,
- .short_retry_limit = 10,
- .long_retry_limit = 10,
- .aflags = 0,
- },
- [3] = {
- .enabled_rates = CONF_TX_AP_ENABLED_RATES,
- .short_retry_limit = 10,
- .long_retry_limit = 10,
- .aflags = 0,
- },
- },
- .ap_mgmt_conf = {
- .enabled_rates = CONF_TX_AP_DEFAULT_MGMT_RATES,
- .short_retry_limit = 10,
- .long_retry_limit = 10,
- .aflags = 0,
- },
- .ap_bcst_conf = {
- .enabled_rates = CONF_HW_BIT_RATE_1MBPS,
- .short_retry_limit = 10,
- .long_retry_limit = 10,
- .aflags = 0,
- },
.ap_max_tx_retries = 100,
.tid_conf_count = 4,
.tid_conf = {
@@ -239,12 +257,16 @@ static struct conf_drv_settings default_conf = {
.wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
.listen_interval = 1,
.bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
- .bcn_filt_ie_count = 1,
+ .bcn_filt_ie_count = 2,
.bcn_filt_ie = {
[0] = {
.ie = WLAN_EID_CHANNEL_SWITCH,
.rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
- }
+ },
+ [1] = {
+ .ie = WLAN_EID_HT_INFORMATION,
+ .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
+ },
},
.synch_fail_thold = 10,
.bss_lose_timeout = 100,
@@ -254,9 +276,9 @@ static struct conf_drv_settings default_conf = {
.ps_poll_threshold = 10,
.ps_poll_recovery_period = 700,
.bet_enable = CONF_BET_MODE_ENABLE,
- .bet_max_consecutive = 10,
+ .bet_max_consecutive = 50,
.psm_entry_retries = 5,
- .psm_exit_retries = 255,
+ .psm_exit_retries = 16,
.psm_entry_nullfunc_retries = 3,
.psm_entry_hangover_period = 1,
.keep_alive_interval = 55000,
@@ -284,6 +306,15 @@ static struct conf_drv_settings default_conf = {
.max_dwell_time_passive = 100000,
.num_probe_reqs = 2,
},
+ .sched_scan = {
+ /* sched_scan requires dwell times in TU instead of TU/1000 */
+ .min_dwell_time_active = 8,
+ .max_dwell_time_active = 30,
+ .dwell_time_passive = 100,
+ .num_probe_reqs = 2,
+ .rssi_threshold = -90,
+ .snr_threshold = 0,
+ },
.rf = {
.tx_per_channel_power_compensation_2 = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -298,19 +329,43 @@ static struct conf_drv_settings default_conf = {
.tx_ba_win_size = 64,
.inactivity_timeout = 10000,
},
- .mem = {
+ .mem_wl127x = {
.num_stations = 1,
.ssid_profiles = 1,
.rx_block_num = 70,
.tx_min_block_num = 40,
- .dynamic_memory = 0,
+ .dynamic_memory = 1,
.min_req_tx_blocks = 100,
.min_req_rx_blocks = 22,
.tx_min = 27,
- }
+ },
+ .mem_wl128x = {
+ .num_stations = 1,
+ .ssid_profiles = 1,
+ .rx_block_num = 40,
+ .tx_min_block_num = 40,
+ .dynamic_memory = 1,
+ .min_req_tx_blocks = 45,
+ .min_req_rx_blocks = 22,
+ .tx_min = 27,
+ },
+ .fm_coex = {
+ .enable = true,
+ .swallow_period = 5,
+ .n_divider_fref_set_1 = 0xff, /* default */
+ .n_divider_fref_set_2 = 12,
+ .m_divider_fref_set_1 = 148,
+ .m_divider_fref_set_2 = 0xffff, /* default */
+ .coex_pll_stabilization_time = 0xffffffff, /* default */
+ .ldo_stabilization_time = 0xffff, /* default */
+ .fm_disturbed_band_margin = 0xff, /* default */
+ .swallow_clk_diff = 0xff, /* default */
+ },
+ .hci_io_ds = HCI_IO_DS_6MA,
};
-static void __wl1271_op_remove_interface(struct wl1271 *wl);
+static void __wl1271_op_remove_interface(struct wl1271 *wl,
+ bool reset_tx_queues);
static void wl1271_free_ap_keys(struct wl1271 *wl);
@@ -329,6 +384,7 @@ static struct platform_device wl1271_device = {
},
};
+static DEFINE_MUTEX(wl_list_mutex);
static LIST_HEAD(wl_list);
static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
@@ -359,10 +415,12 @@ static int wl1271_dev_notify(struct notifier_block *me, unsigned long what,
return NOTIFY_DONE;
wl_temp = hw->priv;
+ mutex_lock(&wl_list_mutex);
list_for_each_entry(wl, &wl_list, list) {
if (wl == wl_temp)
break;
}
+ mutex_unlock(&wl_list_mutex);
if (wl != wl_temp)
return NOTIFY_DONE;
@@ -438,15 +496,30 @@ static int wl1271_plt_init(struct wl1271 *wl)
struct conf_tx_tid *conf_tid;
int ret, i;
- ret = wl1271_cmd_general_parms(wl);
+ if (wl->chip.id == CHIP_ID_1283_PG20)
+ ret = wl128x_cmd_general_parms(wl);
+ else
+ ret = wl1271_cmd_general_parms(wl);
+ if (ret < 0)
+ return ret;
+
+ if (wl->chip.id == CHIP_ID_1283_PG20)
+ ret = wl128x_cmd_radio_parms(wl);
+ else
+ ret = wl1271_cmd_radio_parms(wl);
if (ret < 0)
return ret;
- ret = wl1271_cmd_radio_parms(wl);
+ if (wl->chip.id != CHIP_ID_1283_PG20) {
+ ret = wl1271_cmd_ext_radio_parms(wl);
+ if (ret < 0)
+ return ret;
+ }
if (ret < 0)
return ret;
- ret = wl1271_cmd_ext_radio_parms(wl);
+ /* Chip-specific initializations */
+ ret = wl1271_chip_specific_init(wl);
if (ret < 0)
return ret;
@@ -477,6 +550,11 @@ static int wl1271_plt_init(struct wl1271 *wl)
if (ret < 0)
goto out_free_memmap;
+ /* FM WLAN coexistence */
+ ret = wl1271_acx_fm_coex(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
/* Energy detection */
ret = wl1271_init_energy_detection(wl);
if (ret < 0)
@@ -593,15 +671,17 @@ static void wl1271_fw_status(struct wl1271 *wl,
{
struct wl1271_fw_common_status *status = &full_status->common;
struct timespec ts;
- u32 total = 0;
+ u32 old_tx_blk_count = wl->tx_blocks_available;
+ u32 freed_blocks = 0;
int i;
- if (wl->bss_type == BSS_TYPE_AP_BSS)
+ if (wl->bss_type == BSS_TYPE_AP_BSS) {
wl1271_raw_read(wl, FW_STATUS_ADDR, status,
sizeof(struct wl1271_fw_ap_status), false);
- else
+ } else {
wl1271_raw_read(wl, FW_STATUS_ADDR, status,
sizeof(struct wl1271_fw_sta_status), false);
+ }
wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, "
"drv_rx_counter = %d, tx_results_counter = %d)",
@@ -612,22 +692,37 @@ static void wl1271_fw_status(struct wl1271 *wl,
/* update number of available TX blocks */
for (i = 0; i < NUM_TX_QUEUES; i++) {
- u32 cnt = le32_to_cpu(status->tx_released_blks[i]) -
- wl->tx_blocks_freed[i];
+ freed_blocks += le32_to_cpu(status->tx_released_blks[i]) -
+ wl->tx_blocks_freed[i];
wl->tx_blocks_freed[i] =
le32_to_cpu(status->tx_released_blks[i]);
- wl->tx_blocks_available += cnt;
- total += cnt;
}
- /* if more blocks are available now, tx work can be scheduled */
- if (total)
- clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
+ wl->tx_allocated_blocks -= freed_blocks;
- /* for AP update num of allocated TX blocks per link and ps status */
- if (wl->bss_type == BSS_TYPE_AP_BSS)
+ if (wl->bss_type == BSS_TYPE_AP_BSS) {
+ /* Update num of allocated TX blocks per link and ps status */
wl1271_irq_update_links_status(wl, &full_status->ap);
+ wl->tx_blocks_available += freed_blocks;
+ } else {
+ int avail = full_status->sta.tx_total - wl->tx_allocated_blocks;
+
+ /*
+ * The FW might change the total number of TX memblocks before
+ * we get a notification about blocks being released. Thus, the
+ * available blocks calculation might yield a temporary result
+ * which is lower than the actual available blocks. Keeping in
+ * mind that only blocks that were allocated can be moved from
+ * TX to RX, tx_blocks_available should never decrease here.
+ */
+ wl->tx_blocks_available = max((int)wl->tx_blocks_available,
+ avail);
+ }
+
+ /* if more blocks are available now, tx work can be scheduled */
+ if (wl->tx_blocks_available > old_tx_blk_count)
+ clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
/* update the host-chipset time offset */
getnstimeofday(&ts);
@@ -674,6 +769,13 @@ irqreturn_t wl1271_irq(int irq, void *cookie)
set_bit(WL1271_FLAG_TX_PENDING, &wl->flags);
cancel_work_sync(&wl->tx_work);
+ /*
+ * In case edge triggered interrupt must be used, we cannot iterate
+ * more than once without introducing race conditions with the hardirq.
+ */
+ if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
+ loopcount = 1;
+
mutex_lock(&wl->mutex);
wl1271_debug(DEBUG_IRQ, "IRQ work");
@@ -785,11 +887,17 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)
switch (wl->bss_type) {
case BSS_TYPE_AP_BSS:
- fw_name = WL1271_AP_FW_NAME;
+ if (wl->chip.id == CHIP_ID_1283_PG20)
+ fw_name = WL128X_AP_FW_NAME;
+ else
+ fw_name = WL127X_AP_FW_NAME;
break;
case BSS_TYPE_IBSS:
case BSS_TYPE_STA_BSS:
- fw_name = WL1271_FW_NAME;
+ if (wl->chip.id == CHIP_ID_1283_PG20)
+ fw_name = WL128X_FW_NAME;
+ else
+ fw_name = WL1271_FW_NAME;
break;
default:
wl1271_error("no compatible firmware for bss_type %d",
@@ -838,14 +946,14 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
const struct firmware *fw;
int ret;
- ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
+ ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
if (ret < 0) {
wl1271_error("could not get nvs file: %d", ret);
return ret;
}
- wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
+ wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
if (!wl->nvs) {
wl1271_error("could not allocate memory for the nvs file");
@@ -871,15 +979,30 @@ static void wl1271_recovery_work(struct work_struct *work)
if (wl->state != WL1271_STATE_ON)
goto out;
- wl1271_info("Hardware recovery in progress.");
+ wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
+ wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
ieee80211_connection_loss(wl->vif);
+ /* Prevent spurious TX during FW restart */
+ ieee80211_stop_queues(wl->hw);
+
+ if (wl->sched_scanning) {
+ ieee80211_sched_scan_stopped(wl->hw);
+ wl->sched_scanning = false;
+ }
+
/* reboot the chipset */
- __wl1271_op_remove_interface(wl);
+ __wl1271_op_remove_interface(wl, false);
ieee80211_restart_hw(wl->hw);
+ /*
+ * Its safe to enable TX now - the queues are stopped after a request
+ * to restart the HW.
+ */
+ ieee80211_wake_queues(wl->hw);
+
out:
mutex_unlock(&wl->mutex);
}
@@ -950,10 +1073,25 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
wl->chip.id);
+ /* end-of-transaction flag should be set in wl127x AP mode */
+ if (wl->bss_type == BSS_TYPE_AP_BSS)
+ wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION;
+
ret = wl1271_setup(wl);
if (ret < 0)
goto out;
break;
+ case CHIP_ID_1283_PG20:
+ wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1283 PG20)",
+ wl->chip.id);
+
+ ret = wl1271_setup(wl);
+ if (ret < 0)
+ goto out;
+ if (wl1271_set_block_size(wl))
+ wl->quirks |= WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT;
+ break;
+ case CHIP_ID_1283_PG10:
default:
wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
ret = -ENODEV;
@@ -978,6 +1116,24 @@ out:
return ret;
}
+static unsigned int wl1271_get_fw_ver_quirks(struct wl1271 *wl)
+{
+ unsigned int quirks = 0;
+ unsigned int *fw_ver = wl->chip.fw_ver;
+
+ /* Only for wl127x */
+ if ((fw_ver[FW_VER_CHIP] == FW_VER_CHIP_WL127X) &&
+ /* Check STA version */
+ (((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_STA) &&
+ (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_STA_MIN)) ||
+ /* Check AP version */
+ ((fw_ver[FW_VER_IF_TYPE] == FW_VER_IF_TYPE_AP) &&
+ (fw_ver[FW_VER_MINOR] < FW_VER_MINOR_1_SPARE_AP_MIN))))
+ quirks |= WL12XX_QUIRK_USE_2_SPARE_BLOCKS;
+
+ return quirks;
+}
+
int wl1271_plt_start(struct wl1271 *wl)
{
int retries = WL1271_BOOT_RETRIES;
@@ -1013,6 +1169,9 @@ int wl1271_plt_start(struct wl1271 *wl)
wl->state = WL1271_STATE_PLT;
wl1271_notice("firmware booted in PLT mode (%s)",
wl->chip.fw_ver_str);
+
+ /* Check if any quirks are needed with older fw versions */
+ wl->quirks |= wl1271_get_fw_ver_quirks(wl);
goto out;
irq_disable:
@@ -1040,7 +1199,7 @@ out:
return ret;
}
-int __wl1271_plt_stop(struct wl1271 *wl)
+static int __wl1271_plt_stop(struct wl1271 *wl)
{
int ret = 0;
@@ -1124,10 +1283,219 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
spin_unlock_irqrestore(&wl->wl_lock, flags);
}
+int wl1271_tx_dummy_packet(struct wl1271 *wl)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&wl->wl_lock, flags);
+ set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
+ wl->tx_queue_count++;
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+
+ /* The FW is low on RX memory blocks, so send the dummy packet asap */
+ if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags))
+ wl1271_tx_work_locked(wl);
+
+ /*
+ * If the FW TX is busy, TX work will be scheduled by the threaded
+ * interrupt handler function
+ */
+ return 0;
+}
+
+/*
+ * The size of the dummy packet should be at least 1400 bytes. However, in
+ * order to minimize the number of bus transactions, aligning it to 512 bytes
+ * boundaries could be beneficial, performance wise
+ */
+#define TOTAL_TX_DUMMY_PACKET_SIZE (ALIGN(1400, 512))
+
+static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl)
+{
+ struct sk_buff *skb;
+ struct ieee80211_hdr_3addr *hdr;
+ unsigned int dummy_packet_size;
+
+ dummy_packet_size = TOTAL_TX_DUMMY_PACKET_SIZE -
+ sizeof(struct wl1271_tx_hw_descr) - sizeof(*hdr);
+
+ skb = dev_alloc_skb(TOTAL_TX_DUMMY_PACKET_SIZE);
+ if (!skb) {
+ wl1271_warning("Failed to allocate a dummy packet skb");
+ return NULL;
+ }
+
+ skb_reserve(skb, sizeof(struct wl1271_tx_hw_descr));
+
+ hdr = (struct ieee80211_hdr_3addr *) skb_put(skb, sizeof(*hdr));
+ memset(hdr, 0, sizeof(*hdr));
+ hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
+ IEEE80211_STYPE_NULLFUNC |
+ IEEE80211_FCTL_TODS);
+
+ memset(skb_put(skb, dummy_packet_size), 0, dummy_packet_size);
+
+ /* Dummy packets require the TID to be management */
+ skb->priority = WL1271_TID_MGMT;
+
+ /* Initialize all fields that might be used */
+ skb_set_queue_mapping(skb, 0);
+ memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
+
+ return skb;
+}
+
+
static struct notifier_block wl1271_dev_notifier = {
.notifier_call = wl1271_dev_notify,
};
+#ifdef CONFIG_PM
+static int wl1271_configure_suspend(struct wl1271 *wl)
+{
+ int ret;
+
+ if (wl->bss_type != BSS_TYPE_STA_BSS)
+ return 0;
+
+ mutex_lock(&wl->mutex);
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out_unlock;
+
+ /* enter psm if needed*/
+ if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
+ DECLARE_COMPLETION_ONSTACK(compl);
+
+ wl->ps_compl = &compl;
+ ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
+ wl->basic_rate, true);
+ if (ret < 0)
+ goto out_sleep;
+
+ /* we must unlock here so we will be able to get events */
+ wl1271_ps_elp_sleep(wl);
+ mutex_unlock(&wl->mutex);
+
+ ret = wait_for_completion_timeout(
+ &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
+ if (ret <= 0) {
+ wl1271_warning("couldn't enter ps mode!");
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* take mutex again, and wakeup */
+ mutex_lock(&wl->mutex);
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out_unlock;
+ }
+out_sleep:
+ wl1271_ps_elp_sleep(wl);
+out_unlock:
+ mutex_unlock(&wl->mutex);
+out:
+ return ret;
+
+}
+
+static void wl1271_configure_resume(struct wl1271 *wl)
+{
+ int ret;
+
+ if (wl->bss_type != BSS_TYPE_STA_BSS)
+ return;
+
+ mutex_lock(&wl->mutex);
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ /* exit psm if it wasn't configured */
+ if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
+ wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
+ wl->basic_rate, true);
+
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+}
+
+static int wl1271_op_suspend(struct ieee80211_hw *hw,
+ struct cfg80211_wowlan *wow)
+{
+ struct wl1271 *wl = hw->priv;
+ wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
+ wl->wow_enabled = !!wow;
+ if (wl->wow_enabled) {
+ int ret;
+ ret = wl1271_configure_suspend(wl);
+ if (ret < 0) {
+ wl1271_warning("couldn't prepare device to suspend");
+ return ret;
+ }
+ /* flush any remaining work */
+ wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
+ flush_delayed_work(&wl->scan_complete_work);
+
+ /*
+ * disable and re-enable interrupts in order to flush
+ * the threaded_irq
+ */
+ wl1271_disable_interrupts(wl);
+
+ /*
+ * set suspended flag to avoid triggering a new threaded_irq
+ * work. no need for spinlock as interrupts are disabled.
+ */
+ set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
+
+ wl1271_enable_interrupts(wl);
+ flush_work(&wl->tx_work);
+ flush_delayed_work(&wl->pspoll_work);
+ flush_delayed_work(&wl->elp_work);
+ }
+ return 0;
+}
+
+static int wl1271_op_resume(struct ieee80211_hw *hw)
+{
+ struct wl1271 *wl = hw->priv;
+ wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
+ wl->wow_enabled);
+
+ /*
+ * re-enable irq_work enqueuing, and call irq_work directly if
+ * there is a pending work.
+ */
+ if (wl->wow_enabled) {
+ struct wl1271 *wl = hw->priv;
+ unsigned long flags;
+ bool run_irq_work = false;
+
+ spin_lock_irqsave(&wl->wl_lock, flags);
+ clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
+ if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
+ run_irq_work = true;
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+
+ if (run_irq_work) {
+ wl1271_debug(DEBUG_MAC80211,
+ "run postponed irq_work directly");
+ wl1271_irq(0, wl);
+ wl1271_enable_interrupts(wl);
+ }
+
+ wl1271_configure_resume(wl);
+ }
+
+ return 0;
+}
+#endif
+
static int wl1271_op_start(struct ieee80211_hw *hw)
{
wl1271_debug(DEBUG_MAC80211, "mac80211 start");
@@ -1174,6 +1542,16 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
goto out;
}
+ /*
+ * in some very corner case HW recovery scenarios its possible to
+ * get here before __wl1271_op_remove_interface is complete, so
+ * opt out if that is the case.
+ */
+ if (test_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
switch (vif->type) {
case NL80211_IFTYPE_STATION:
wl->bss_type = BSS_TYPE_STA_BSS;
@@ -1242,6 +1620,7 @@ power_off:
wl->vif = vif;
wl->state = WL1271_STATE_ON;
+ set_bit(WL1271_FLAG_IF_INITIALIZED, &wl->flags);
wl1271_info("firmware booted (%s)", wl->chip.fw_ver_str);
/* update hw/fw version info in wiphy struct */
@@ -1249,6 +1628,9 @@ power_off:
strncpy(wiphy->fw_version, wl->chip.fw_ver_str,
sizeof(wiphy->fw_version));
+ /* Check if any quirks are needed with older fw versions */
+ wl->quirks |= wl1271_get_fw_ver_quirks(wl);
+
/*
* Now we know if 11a is supported (info from the NVS), so disable
* 11a channels if not supported
@@ -1262,23 +1644,30 @@ power_off:
out:
mutex_unlock(&wl->mutex);
+ mutex_lock(&wl_list_mutex);
if (!ret)
list_add(&wl->list, &wl_list);
+ mutex_unlock(&wl_list_mutex);
return ret;
}
-static void __wl1271_op_remove_interface(struct wl1271 *wl)
+static void __wl1271_op_remove_interface(struct wl1271 *wl,
+ bool reset_tx_queues)
{
int i;
wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface");
+ /* because of hardware recovery, we may get here twice */
+ if (wl->state != WL1271_STATE_ON)
+ return;
+
wl1271_info("down");
+ mutex_lock(&wl_list_mutex);
list_del(&wl->list);
-
- WARN_ON(wl->state != WL1271_STATE_ON);
+ mutex_unlock(&wl_list_mutex);
/* enable dyn ps just in case (if left on due to fw crash etc) */
if (wl->bss_type == BSS_TYPE_STA_BSS)
@@ -1286,12 +1675,15 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl)
if (wl->scan.state != WL1271_SCAN_STATE_IDLE) {
wl->scan.state = WL1271_SCAN_STATE_IDLE;
- kfree(wl->scan.scanned_ch);
- wl->scan.scanned_ch = NULL;
+ memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
wl->scan.req = NULL;
ieee80211_scan_completed(wl->hw, true);
}
+ /*
+ * this must be before the cancel_work calls below, so that the work
+ * functions don't perform further work.
+ */
wl->state = WL1271_STATE_OFF;
mutex_unlock(&wl->mutex);
@@ -1307,7 +1699,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl)
mutex_lock(&wl->mutex);
/* let's notify MAC80211 about the remaining pending TX frames */
- wl1271_tx_reset(wl);
+ wl1271_tx_reset(wl, reset_tx_queues);
wl1271_power_off(wl);
memset(wl->bssid, 0, ETH_ALEN);
@@ -1321,6 +1713,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl)
wl->psm_entry_retry = 0;
wl->power_level = WL1271_DEFAULT_POWER_LEVEL;
wl->tx_blocks_available = 0;
+ wl->tx_allocated_blocks = 0;
wl->tx_results_count = 0;
wl->tx_packets_count = 0;
wl->tx_security_last_seq = 0;
@@ -1328,13 +1721,20 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl)
wl->time_offset = 0;
wl->session_counter = 0;
wl->rate_set = CONF_TX_RATE_MASK_BASIC;
- wl->flags = 0;
wl->vif = NULL;
wl->filters = 0;
wl1271_free_ap_keys(wl);
memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
wl->ap_fw_ps_map = 0;
wl->ap_ps_map = 0;
+ wl->sched_scanning = false;
+
+ /*
+ * this is performed after the cancel_work calls and the associated
+ * mutex_lock, so that wl1271_op_add_interface does not accidentally
+ * get executed before all these vars have been reset.
+ */
+ wl->flags = 0;
for (i = 0; i < NUM_TX_QUEUES; i++)
wl->tx_blocks_freed[i] = 0;
@@ -1361,14 +1761,14 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
*/
if (wl->vif) {
WARN_ON(wl->vif != vif);
- __wl1271_op_remove_interface(wl);
+ __wl1271_op_remove_interface(wl, true);
}
mutex_unlock(&wl->mutex);
cancel_work_sync(&wl->recovery_work);
}
-static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
+void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
{
wl1271_set_default_filters(wl);
@@ -1431,10 +1831,10 @@ static int wl1271_join(struct wl1271 *wl, bool set_assoc)
* One of the side effects of the JOIN command is that is clears
* WPA/WPA2 keys from the chipset. Performing a JOIN while associated
* to a WPA/WPA2 access point will therefore kill the data-path.
- * Currently there is no supported scenario for JOIN during
- * association - if it becomes a supported scenario, the WPA/WPA2 keys
- * must be handled somehow.
- *
+ * Currently the only valid scenario for JOIN during association
+ * is on roaming, in which case we will also be given new keys.
+ * Keep the below message for now, unless it starts bothering
+ * users who really like to roam a lot :)
*/
if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
wl1271_info("JOIN while associated.");
@@ -1490,7 +1890,7 @@ static int wl1271_unjoin(struct wl1271 *wl)
clear_bit(WL1271_FLAG_JOINED, &wl->flags);
memset(wl->bssid, 0, ETH_ALEN);
- /* stop filterting packets based on bssid */
+ /* stop filtering packets based on bssid */
wl1271_configure_filters(wl, FIF_OTHER_BSS);
out:
@@ -1530,6 +1930,13 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
wl->session_counter++;
if (wl->session_counter >= SESSION_COUNTER_MAX)
wl->session_counter = 0;
+
+ /* The current firmware only supports sched_scan in idle */
+ if (wl->sched_scanning) {
+ wl1271_scan_sched_scan_stop(wl);
+ ieee80211_sched_scan_stopped(wl->hw);
+ }
+
ret = wl1271_dummy_join(wl);
if (ret < 0)
goto out;
@@ -1569,7 +1976,12 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
mutex_lock(&wl->mutex);
if (unlikely(wl->state == WL1271_STATE_OFF)) {
- ret = -EAGAIN;
+ /* we support configuring the channel and band while off */
+ if ((changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
+ wl->band = conf->channel->band;
+ wl->channel = channel;
+ }
+
goto out;
}
@@ -2077,6 +2489,60 @@ out:
return ret;
}
+static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct cfg80211_sched_scan_request *req,
+ struct ieee80211_sched_scan_ies *ies)
+{
+ struct wl1271 *wl = hw->priv;
+ int ret;
+
+ wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
+
+ mutex_lock(&wl->mutex);
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wl1271_scan_sched_scan_config(wl, req, ies);
+ if (ret < 0)
+ goto out_sleep;
+
+ ret = wl1271_scan_sched_scan_start(wl);
+ if (ret < 0)
+ goto out_sleep;
+
+ wl->sched_scanning = true;
+
+out_sleep:
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+ return ret;
+}
+
+static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct wl1271 *wl = hw->priv;
+ int ret;
+
+ wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
+
+ mutex_lock(&wl->mutex);
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ wl1271_scan_sched_scan_stop(wl);
+
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+}
+
static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
{
struct wl1271 *wl = hw->priv;
@@ -2093,7 +2559,7 @@ static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
if (ret < 0)
goto out;
- ret = wl1271_acx_frag_threshold(wl, (u16)value);
+ ret = wl1271_acx_frag_threshold(wl, value);
if (ret < 0)
wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
@@ -2121,7 +2587,7 @@ static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
if (ret < 0)
goto out;
- ret = wl1271_acx_rts_threshold(wl, (u16) value);
+ ret = wl1271_acx_rts_threshold(wl, value);
if (ret < 0)
wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
@@ -2136,20 +2602,24 @@ out:
static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
int offset)
{
- u8 *ptr = skb->data + offset;
+ u8 ssid_len;
+ const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
+ skb->len - offset);
- /* find the location of the ssid in the beacon */
- while (ptr < skb->data + skb->len) {
- if (ptr[0] == WLAN_EID_SSID) {
- wl->ssid_len = ptr[1];
- memcpy(wl->ssid, ptr+2, wl->ssid_len);
- return 0;
- }
- ptr += (ptr[1] + 2);
+ if (!ptr) {
+ wl1271_error("No SSID in IEs!");
+ return -ENOENT;
}
- wl1271_error("No SSID in IEs!\n");
- return -ENOENT;
+ ssid_len = ptr[1];
+ if (ssid_len > IEEE80211_MAX_SSID_LEN) {
+ wl1271_error("SSID is too long!");
+ return -EINVAL;
+ }
+
+ wl->ssid_len = ssid_len;
+ memcpy(wl->ssid, ptr+2, ssid_len);
+ return 0;
}
static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
@@ -2264,24 +2734,19 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
if ((changed & BSS_CHANGED_BASIC_RATES)) {
u32 rates = bss_conf->basic_rates;
- struct conf_tx_rate_class mgmt_rc;
wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
wl->basic_rate = wl1271_tx_min_rate_get(wl);
- wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
- wl->basic_rate_set);
-
- /* update the AP management rate policy with the new rates */
- mgmt_rc.enabled_rates = wl->basic_rate_set;
- mgmt_rc.long_retry_limit = 10;
- mgmt_rc.short_retry_limit = 10;
- mgmt_rc.aflags = 0;
- ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
- ACX_TX_AP_MODE_MGMT_RATE);
+
+ ret = wl1271_init_ap_rates(wl);
if (ret < 0) {
- wl1271_error("AP mgmt policy change failed %d", ret);
+ wl1271_error("AP rate policy change failed %d", ret);
goto out;
}
+
+ ret = wl1271_ap_init_templates(wl);
+ if (ret < 0)
+ goto out;
}
ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
@@ -2314,6 +2779,24 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
}
}
+ if (changed & BSS_CHANGED_IBSS) {
+ wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
+ bss_conf->ibss_joined);
+
+ if (bss_conf->ibss_joined) {
+ u32 rates = bss_conf->basic_rates;
+ wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
+ rates);
+ wl->basic_rate = wl1271_tx_min_rate_get(wl);
+
+ /* by default, use 11b rates */
+ wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
+ ret = wl1271_acx_sta_rate_policies(wl);
+ if (ret < 0)
+ goto out;
+ }
+ }
+
ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
if (ret < 0)
goto out;
@@ -2503,8 +2986,10 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
}
} else {
/* use defaults when not associated */
+ bool was_assoc =
+ !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
+ &wl->flags);
clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
- clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
wl->aid = 0;
/* free probe-request template */
@@ -2530,8 +3015,10 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
goto out;
/* restore the bssid filter and go to dummy bssid */
- wl1271_unjoin(wl);
- wl1271_dummy_join(wl);
+ if (was_assoc) {
+ wl1271_unjoin(wl);
+ wl1271_dummy_join(wl);
+ }
}
}
@@ -2650,32 +3137,31 @@ static int wl1271_op_conf_tx(struct ieee80211_hw *hw, u16 queue,
conf_tid->ack_policy = CONF_ACK_POLICY_LEGACY;
conf_tid->apsd_conf[0] = 0;
conf_tid->apsd_conf[1] = 0;
- } else {
- ret = wl1271_ps_elp_wakeup(wl);
- if (ret < 0)
- goto out;
+ goto out;
+ }
- /*
- * the txop is confed in units of 32us by the mac80211,
- * we need us
- */
- ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
- params->cw_min, params->cw_max,
- params->aifs, params->txop << 5);
- if (ret < 0)
- goto out_sleep;
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
- ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
- CONF_CHANNEL_TYPE_EDCF,
- wl1271_tx_get_queue(queue),
- ps_scheme, CONF_ACK_POLICY_LEGACY,
- 0, 0);
- if (ret < 0)
- goto out_sleep;
+ /*
+ * the txop is confed in units of 32us by the mac80211,
+ * we need us
+ */
+ ret = wl1271_acx_ac_cfg(wl, wl1271_tx_get_queue(queue),
+ params->cw_min, params->cw_max,
+ params->aifs, params->txop << 5);
+ if (ret < 0)
+ goto out_sleep;
+
+ ret = wl1271_acx_tid_cfg(wl, wl1271_tx_get_queue(queue),
+ CONF_CHANNEL_TYPE_EDCF,
+ wl1271_tx_get_queue(queue),
+ ps_scheme, CONF_ACK_POLICY_LEGACY,
+ 0, 0);
out_sleep:
- wl1271_ps_elp_sleep(wl);
- }
+ wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
@@ -2847,10 +3333,11 @@ out:
return ret;
}
-int wl1271_op_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- enum ieee80211_ampdu_mlme_action action,
- struct ieee80211_sta *sta, u16 tid, u16 *ssn,
- u8 buf_size)
+static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ enum ieee80211_ampdu_mlme_action action,
+ struct ieee80211_sta *sta, u16 tid, u16 *ssn,
+ u8 buf_size)
{
struct wl1271 *wl = hw->priv;
int ret;
@@ -2907,6 +3394,28 @@ out:
return ret;
}
+static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
+{
+ struct wl1271 *wl = hw->priv;
+ bool ret = false;
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state == WL1271_STATE_OFF))
+ goto out;
+
+ /* packets are considered pending if in the TX queue or the FW */
+ ret = (wl->tx_queue_count > 0) || (wl->tx_frames_cnt > 0);
+
+ /* the above is appropriate for STA mode for PS purposes */
+ WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
+
+out:
+ mutex_unlock(&wl->mutex);
+
+ return ret;
+}
+
/* can't be const, mac80211 writes to this */
static struct ieee80211_rate wl1271_rates[] = {
{ .bitrate = 10,
@@ -3003,7 +3512,8 @@ static const u8 wl1271_rate_to_idx_2ghz[] = {
#ifdef CONFIG_WL12XX_HT
#define WL12XX_HT_CAP { \
- .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20, \
+ .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
+ (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
.ht_supported = true, \
.ampdu_factor = IEEE80211_HT_MAX_AMPDU_8K, \
.ampdu_density = IEEE80211_HT_MPDU_DENSITY_8, \
@@ -3142,12 +3652,18 @@ static const struct ieee80211_ops wl1271_ops = {
.stop = wl1271_op_stop,
.add_interface = wl1271_op_add_interface,
.remove_interface = wl1271_op_remove_interface,
+#ifdef CONFIG_PM
+ .suspend = wl1271_op_suspend,
+ .resume = wl1271_op_resume,
+#endif
.config = wl1271_op_config,
.prepare_multicast = wl1271_op_prepare_multicast,
.configure_filter = wl1271_op_configure_filter,
.tx = wl1271_op_tx,
.set_key = wl1271_op_set_key,
.hw_scan = wl1271_op_hw_scan,
+ .sched_scan_start = wl1271_op_sched_scan_start,
+ .sched_scan_stop = wl1271_op_sched_scan_stop,
.bss_info_changed = wl1271_op_bss_info_changed,
.set_frag_threshold = wl1271_op_set_frag_threshold,
.set_rts_threshold = wl1271_op_set_rts_threshold,
@@ -3157,6 +3673,7 @@ static const struct ieee80211_ops wl1271_ops = {
.sta_add = wl1271_op_sta_add,
.sta_remove = wl1271_op_sta_remove,
.ampdu_action = wl1271_op_ampdu_action,
+ .tx_frames_pending = wl1271_tx_frames_pending,
CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
};
@@ -3207,8 +3724,7 @@ static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev,
unsigned long res;
int ret;
- ret = strict_strtoul(buf, 10, &res);
-
+ ret = kstrtoul(buf, 10, &res);
if (ret < 0) {
wl1271_warning("incorrect value written to bt_coex_mode");
return count;
@@ -3273,7 +3789,11 @@ int wl1271_register_hw(struct wl1271 *wl)
ret = wl1271_fetch_nvs(wl);
if (ret == 0) {
- u8 *nvs_ptr = (u8 *)wl->nvs->nvs;
+ /* NOTE: The wl->nvs->nvs element must be first, in
+ * order to simplify the casting, we assume it is at
+ * the beginning of the wl->nvs structure.
+ */
+ u8 *nvs_ptr = (u8 *)wl->nvs;
wl->mac_addr[0] = nvs_ptr[11];
wl->mac_addr[1] = nvs_ptr[10];
@@ -3342,6 +3862,7 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
IEEE80211_HW_CONNECTION_MONITOR |
IEEE80211_HW_SUPPORTS_CQM_RSSI |
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
+ IEEE80211_HW_SPECTRUM_MGMT |
IEEE80211_HW_AP_LINK_PS;
wl->hw->wiphy->cipher_suites = cipher_suites;
@@ -3358,6 +3879,10 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_MAX_SIZE -
sizeof(struct ieee80211_header);
+ /* make sure all our channels fit in the scanned_ch bitmask */
+ BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
+ ARRAY_SIZE(wl1271_channels_5ghz) >
+ WL1271_MAX_CHANNELS);
/*
* We keep local copies of the band structs because we need to
* modify them on a per-device basis.
@@ -3458,6 +3983,8 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
wl->ap_ps_map = 0;
wl->ap_fw_ps_map = 0;
wl->quirks = 0;
+ wl->platform_quirks = 0;
+ wl->sched_scanning = false;
memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
@@ -3478,11 +4005,17 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
goto err_hw;
}
+ wl->dummy_packet = wl12xx_alloc_dummy_packet(wl);
+ if (!wl->dummy_packet) {
+ ret = -ENOMEM;
+ goto err_aggr;
+ }
+
/* Register platform device */
ret = platform_device_register(wl->plat_dev);
if (ret) {
wl1271_error("couldn't register platform device");
- goto err_aggr;
+ goto err_dummy_packet;
}
dev_set_drvdata(&wl->plat_dev->dev, wl);
@@ -3508,6 +4041,9 @@ err_bt_coex_state:
err_platform:
platform_device_unregister(wl->plat_dev);
+err_dummy_packet:
+ dev_kfree_skb(wl->dummy_packet);
+
err_aggr:
free_pages((unsigned long)wl->aggr_buf, order);
@@ -3527,6 +4063,7 @@ EXPORT_SYMBOL_GPL(wl1271_alloc_hw);
int wl1271_free_hw(struct wl1271 *wl)
{
platform_device_unregister(wl->plat_dev);
+ dev_kfree_skb(wl->dummy_packet);
free_pages((unsigned long)wl->aggr_buf,
get_order(WL1271_AGGR_BUFFER_SIZE));
kfree(wl->plat_dev);
diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c
index 971f13e792da..b59b67711a17 100644
--- a/drivers/net/wireless/wl12xx/ps.c
+++ b/drivers/net/wireless/wl12xx/ps.c
@@ -43,6 +43,10 @@ void wl1271_elp_work(struct work_struct *work)
if (unlikely(wl->state == WL1271_STATE_OFF))
goto out;
+ /* our work might have been already cancelled */
+ if (unlikely(!test_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags)))
+ goto out;
+
if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) ||
(!test_bit(WL1271_FLAG_PSM, &wl->flags) &&
!test_bit(WL1271_FLAG_IDLE, &wl->flags)))
@@ -61,12 +65,16 @@ out:
/* Routines to toggle sleep mode while in ELP */
void wl1271_ps_elp_sleep(struct wl1271 *wl)
{
- if (test_bit(WL1271_FLAG_PSM, &wl->flags) ||
- test_bit(WL1271_FLAG_IDLE, &wl->flags)) {
- cancel_delayed_work(&wl->elp_work);
- ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
- msecs_to_jiffies(ELP_ENTRY_DELAY));
- }
+ /* we shouldn't get consecutive sleep requests */
+ if (WARN_ON(test_and_set_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags)))
+ return;
+
+ if (!test_bit(WL1271_FLAG_PSM, &wl->flags) &&
+ !test_bit(WL1271_FLAG_IDLE, &wl->flags))
+ return;
+
+ ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
+ msecs_to_jiffies(ELP_ENTRY_DELAY));
}
int wl1271_ps_elp_wakeup(struct wl1271 *wl)
@@ -77,6 +85,16 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl)
u32 start_time = jiffies;
bool pending = false;
+ /*
+ * we might try to wake up even if we didn't go to sleep
+ * before (e.g. on boot)
+ */
+ if (!test_and_clear_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags))
+ return 0;
+
+ /* don't cancel_sync as it might contend for a mutex and deadlock */
+ cancel_delayed_work(&wl->elp_work);
+
if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags))
return 0;
@@ -149,9 +167,6 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode,
case STATION_ACTIVE_MODE:
default:
wl1271_debug(DEBUG_PSM, "leaving psm");
- ret = wl1271_ps_elp_wakeup(wl);
- if (ret < 0)
- return ret;
/* disable beacon early termination */
ret = wl1271_acx_bet_enable(wl, false);
diff --git a/drivers/net/wireless/wl12xx/ps.h b/drivers/net/wireless/wl12xx/ps.h
index c41bd0a711bc..25eb9bc9b628 100644
--- a/drivers/net/wireless/wl12xx/ps.h
+++ b/drivers/net/wireless/wl12xx/ps.h
@@ -35,4 +35,6 @@ void wl1271_elp_work(struct work_struct *work);
void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues);
void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid);
+#define WL1271_PS_COMPLETE_TIMEOUT 500
+
#endif /* __WL1271_PS_H__ */
diff --git a/drivers/net/wireless/wl12xx/reg.h b/drivers/net/wireless/wl12xx/reg.h
index 990960771528..440a4ee9cb42 100644
--- a/drivers/net/wireless/wl12xx/reg.h
+++ b/drivers/net/wireless/wl12xx/reg.h
@@ -207,6 +207,8 @@
#define CHIP_ID_1271_PG10 (0x4030101)
#define CHIP_ID_1271_PG20 (0x4030111)
+#define CHIP_ID_1283_PG10 (0x05030101)
+#define CHIP_ID_1283_PG20 (0x05030111)
#define ENABLE (REGISTERS_BASE + 0x5450)
@@ -452,24 +454,11 @@
#define HI_CFG_UART_TX_OUT_GPIO_14 0x00000200
#define HI_CFG_UART_TX_OUT_GPIO_7 0x00000400
-/*
- * NOTE: USE_ACTIVE_HIGH compilation flag should be defined in makefile
- * for platforms using active high interrupt level
- */
-#ifdef USE_ACTIVE_HIGH
#define HI_CFG_DEF_VAL \
(HI_CFG_UART_ENABLE | \
HI_CFG_RST232_ENABLE | \
HI_CFG_CLOCK_REQ_SELECT | \
HI_CFG_HOST_INT_ENABLE)
-#else
-#define HI_CFG_DEF_VAL \
- (HI_CFG_UART_ENABLE | \
- HI_CFG_RST232_ENABLE | \
- HI_CFG_CLOCK_REQ_SELECT | \
- HI_CFG_HOST_INT_ENABLE)
-
-#endif
#define REF_FREQ_19_2 0
#define REF_FREQ_26_0 1
diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c
index 919b59f00301..70091035e019 100644
--- a/drivers/net/wireless/wl12xx/rx.c
+++ b/drivers/net/wireless/wl12xx/rx.c
@@ -48,18 +48,14 @@ static void wl1271_rx_status(struct wl1271 *wl,
struct ieee80211_rx_status *status,
u8 beacon)
{
- enum ieee80211_band desc_band;
-
memset(status, 0, sizeof(struct ieee80211_rx_status));
- status->band = wl->band;
-
if ((desc->flags & WL1271_RX_DESC_BAND_MASK) == WL1271_RX_DESC_BAND_BG)
- desc_band = IEEE80211_BAND_2GHZ;
+ status->band = IEEE80211_BAND_2GHZ;
else
- desc_band = IEEE80211_BAND_5GHZ;
+ status->band = IEEE80211_BAND_5GHZ;
- status->rate_idx = wl1271_rate_to_idx(desc->rate, desc_band);
+ status->rate_idx = wl1271_rate_to_idx(desc->rate, status->band);
#ifdef CONFIG_WL12XX_HT
/* 11n support */
@@ -76,15 +72,19 @@ static void wl1271_rx_status(struct wl1271 *wl,
*/
wl->noise = desc->rssi - (desc->snr >> 1);
- status->freq = ieee80211_channel_to_frequency(desc->channel, desc_band);
+ status->freq = ieee80211_channel_to_frequency(desc->channel,
+ status->band);
if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) {
- status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;
+ u8 desc_err_code = desc->status & WL1271_RX_DESC_STATUS_MASK;
+
+ status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED |
+ RX_FLAG_DECRYPTED;
- if (likely(!(desc->status & WL1271_RX_DESC_DECRYPT_FAIL)))
- status->flag |= RX_FLAG_DECRYPTED;
- if (unlikely(desc->status & WL1271_RX_DESC_MIC_FAIL))
+ if (unlikely(desc_err_code == WL1271_RX_DESC_MIC_FAIL)) {
status->flag |= RX_FLAG_MMIC_ERROR;
+ wl1271_warning("Michael MIC error");
+ }
}
}
@@ -103,6 +103,25 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
if (unlikely(wl->state == WL1271_STATE_PLT))
return -EINVAL;
+ /* the data read starts with the descriptor */
+ desc = (struct wl1271_rx_descriptor *) data;
+
+ switch (desc->status & WL1271_RX_DESC_STATUS_MASK) {
+ /* discard corrupted packets */
+ case WL1271_RX_DESC_DRIVER_RX_Q_FAIL:
+ case WL1271_RX_DESC_DECRYPT_FAIL:
+ wl1271_warning("corrupted packet in RX with status: 0x%x",
+ desc->status & WL1271_RX_DESC_STATUS_MASK);
+ return -EINVAL;
+ case WL1271_RX_DESC_SUCCESS:
+ case WL1271_RX_DESC_MIC_FAIL:
+ break;
+ default:
+ wl1271_error("invalid RX descriptor status: 0x%x",
+ desc->status & WL1271_RX_DESC_STATUS_MASK);
+ return -EINVAL;
+ }
+
skb = __dev_alloc_skb(length, GFP_KERNEL);
if (!skb) {
wl1271_error("Couldn't allocate RX frame");
@@ -112,9 +131,6 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
buf = skb_put(skb, length);
memcpy(buf, data, length);
- /* the data read starts with the descriptor */
- desc = (struct wl1271_rx_descriptor *) buf;
-
/* now we pull the descriptor out of the buffer */
skb_pull(skb, sizeof(*desc));
@@ -124,7 +140,8 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length)
wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon);
- wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len,
+ wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb,
+ skb->len - desc->pad_len,
beacon ? "beacon" : "");
skb_trim(skb, skb->len - desc->pad_len);
@@ -163,18 +180,25 @@ void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_common_status *status)
break;
}
- /*
- * Choose the block we want to read
- * For aggregated packets, only the first memory block should
- * be retrieved. The FW takes care of the rest.
- */
- mem_block = wl1271_rx_get_mem_block(status, drv_rx_counter);
- wl->rx_mem_pool_addr.addr = (mem_block << 8) +
- le32_to_cpu(wl_mem_map->packet_memory_pool_start);
- wl->rx_mem_pool_addr.addr_extra =
- wl->rx_mem_pool_addr.addr + 4;
- wl1271_write(wl, WL1271_SLV_REG_DATA, &wl->rx_mem_pool_addr,
- sizeof(wl->rx_mem_pool_addr), false);
+ if (wl->chip.id != CHIP_ID_1283_PG20) {
+ /*
+ * Choose the block we want to read
+ * For aggregated packets, only the first memory block
+ * should be retrieved. The FW takes care of the rest.
+ */
+ mem_block = wl1271_rx_get_mem_block(status,
+ drv_rx_counter);
+
+ wl->rx_mem_pool_addr.addr = (mem_block << 8) +
+ le32_to_cpu(wl_mem_map->packet_memory_pool_start);
+
+ wl->rx_mem_pool_addr.addr_extra =
+ wl->rx_mem_pool_addr.addr + 4;
+
+ wl1271_write(wl, WL1271_SLV_REG_DATA,
+ &wl->rx_mem_pool_addr,
+ sizeof(wl->rx_mem_pool_addr), false);
+ }
/* Read all available packets at once */
wl1271_read(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf,
diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c
index 420653a2859c..f37e5a391976 100644
--- a/drivers/net/wireless/wl12xx/scan.c
+++ b/drivers/net/wireless/wl12xx/scan.c
@@ -48,8 +48,7 @@ void wl1271_scan_complete_work(struct work_struct *work)
goto out;
wl->scan.state = WL1271_SCAN_STATE_IDLE;
- kfree(wl->scan.scanned_ch);
- wl->scan.scanned_ch = NULL;
+ memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
wl->scan.req = NULL;
ieee80211_scan_completed(wl->hw, false);
@@ -87,7 +86,7 @@ static int wl1271_get_scan_channels(struct wl1271 *wl,
flags = req->channels[i]->flags;
- if (!wl->scan.scanned_ch[i] &&
+ if (!test_bit(i, wl->scan.scanned_ch) &&
!(flags & IEEE80211_CHAN_DISABLED) &&
((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) &&
(req->channels[i]->band == band)) {
@@ -124,7 +123,7 @@ static int wl1271_get_scan_channels(struct wl1271 *wl,
memset(&channels[j].bssid_msb, 0xff, 2);
/* Mark the channels we already used */
- wl->scan.scanned_ch[i] = true;
+ set_bit(i, wl->scan.scanned_ch);
j++;
}
@@ -291,6 +290,12 @@ void wl1271_scan_stm(struct wl1271 *wl)
int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
struct cfg80211_scan_request *req)
{
+ /*
+ * cfg80211 should guarantee that we don't get more channels
+ * than what we have registered.
+ */
+ BUG_ON(req->n_channels > WL1271_MAX_CHANNELS);
+
if (wl->scan.state != WL1271_SCAN_STATE_IDLE)
return -EBUSY;
@@ -304,10 +309,8 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
}
wl->scan.req = req;
+ memset(wl->scan.scanned_ch, 0, sizeof(wl->scan.scanned_ch));
- wl->scan.scanned_ch = kcalloc(req->n_channels,
- sizeof(*wl->scan.scanned_ch),
- GFP_KERNEL);
/* we assume failure so that timeout scenarios are handled correctly */
wl->scan.failed = true;
ieee80211_queue_delayed_work(wl->hw, &wl->scan_complete_work,
@@ -317,3 +320,246 @@ int wl1271_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
return 0;
}
+
+static int
+wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
+ struct cfg80211_sched_scan_request *req,
+ struct conn_scan_ch_params *channels,
+ u32 band, bool radar, bool passive,
+ int start)
+{
+ struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
+ int i, j;
+ u32 flags;
+
+ for (i = 0, j = start;
+ i < req->n_channels && j < MAX_CHANNELS_ALL_BANDS;
+ i++) {
+ flags = req->channels[i]->flags;
+
+ if (!(flags & IEEE80211_CHAN_DISABLED) &&
+ ((flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive) &&
+ ((flags & IEEE80211_CHAN_RADAR) == radar) &&
+ (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_power %d",
+ req->channels[i]->max_power);
+
+ if (flags & IEEE80211_CHAN_PASSIVE_SCAN) {
+ channels[j].passive_duration =
+ cpu_to_le16(c->dwell_time_passive);
+ } else {
+ channels[j].min_duration =
+ cpu_to_le16(c->min_dwell_time_active);
+ channels[j].max_duration =
+ cpu_to_le16(c->max_dwell_time_active);
+ }
+ channels[j].tx_power_att = req->channels[j]->max_power;
+ channels[j].channel = req->channels[i]->hw_value;
+
+ j++;
+ }
+ }
+
+ return j - start;
+}
+
+static int
+wl1271_scan_sched_scan_channels(struct wl1271 *wl,
+ struct cfg80211_sched_scan_request *req,
+ struct wl1271_cmd_sched_scan_config *cfg)
+{
+ int idx = 0;
+
+ cfg->passive[0] =
+ wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
+ IEEE80211_BAND_2GHZ,
+ false, true, idx);
+ idx += cfg->passive[0];
+
+ cfg->active[0] =
+ wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
+ IEEE80211_BAND_2GHZ,
+ false, false, idx);
+ idx += cfg->active[0];
+
+ cfg->passive[1] =
+ wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
+ IEEE80211_BAND_5GHZ,
+ false, true, idx);
+ idx += cfg->passive[1];
+
+ cfg->active[1] =
+ wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
+ IEEE80211_BAND_5GHZ,
+ false, false, 14);
+ idx += cfg->active[1];
+
+ cfg->dfs =
+ wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
+ IEEE80211_BAND_5GHZ,
+ true, false, idx);
+ idx += cfg->dfs;
+
+ wl1271_debug(DEBUG_SCAN, " 2.4GHz: active %d passive %d",
+ cfg->active[0], cfg->passive[0]);
+ wl1271_debug(DEBUG_SCAN, " 5GHz: active %d passive %d",
+ cfg->active[1], cfg->passive[1]);
+
+ return idx;
+}
+
+int wl1271_scan_sched_scan_config(struct wl1271 *wl,
+ struct cfg80211_sched_scan_request *req,
+ struct ieee80211_sched_scan_ies *ies)
+{
+ struct wl1271_cmd_sched_scan_config *cfg = NULL;
+ struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
+ int i, total_channels, ret;
+
+ wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config");
+
+ cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
+ if (!cfg)
+ return -ENOMEM;
+
+ cfg->rssi_threshold = c->rssi_threshold;
+ cfg->snr_threshold = c->snr_threshold;
+ cfg->n_probe_reqs = c->num_probe_reqs;
+ /* cycles set to 0 it means infinite (until manually stopped) */
+ cfg->cycles = 0;
+ /* report APs when at least 1 is found */
+ cfg->report_after = 1;
+ /* don't stop scanning automatically when something is found */
+ cfg->terminate = 0;
+ cfg->tag = WL1271_SCAN_DEFAULT_TAG;
+ /* don't filter on BSS type */
+ cfg->bss_type = SCAN_BSS_TYPE_ANY;
+ /* currently NL80211 supports only a single interval */
+ for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++)
+ cfg->intervals[i] = cpu_to_le32(req->interval);
+
+ if (req->ssids[0].ssid_len && req->ssids[0].ssid) {
+ cfg->filter_type = SCAN_SSID_FILTER_SPECIFIC;
+ cfg->ssid_len = req->ssids[0].ssid_len;
+ memcpy(cfg->ssid, req->ssids[0].ssid,
+ req->ssids[0].ssid_len);
+ } else {
+ cfg->filter_type = SCAN_SSID_FILTER_ANY;
+ cfg->ssid_len = 0;
+ }
+
+ total_channels = wl1271_scan_sched_scan_channels(wl, req, cfg);
+ if (total_channels == 0) {
+ wl1271_error("scan channel list is empty");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (cfg->active[0]) {
+ ret = wl1271_cmd_build_probe_req(wl, req->ssids[0].ssid,
+ req->ssids[0].ssid_len,
+ ies->ie[IEEE80211_BAND_2GHZ],
+ ies->len[IEEE80211_BAND_2GHZ],
+ IEEE80211_BAND_2GHZ);
+ if (ret < 0) {
+ wl1271_error("2.4GHz PROBE request template failed");
+ goto out;
+ }
+ }
+
+ if (cfg->active[1]) {
+ ret = wl1271_cmd_build_probe_req(wl, req->ssids[0].ssid,
+ req->ssids[0].ssid_len,
+ ies->ie[IEEE80211_BAND_5GHZ],
+ ies->len[IEEE80211_BAND_5GHZ],
+ IEEE80211_BAND_5GHZ);
+ if (ret < 0) {
+ wl1271_error("5GHz PROBE request template failed");
+ goto out;
+ }
+ }
+
+ wl1271_dump(DEBUG_SCAN, "SCAN_CFG: ", cfg, sizeof(*cfg));
+
+ ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_CFG, cfg,
+ sizeof(*cfg), 0);
+ if (ret < 0) {
+ wl1271_error("SCAN configuration failed");
+ goto out;
+ }
+out:
+ kfree(cfg);
+ return ret;
+}
+
+int wl1271_scan_sched_scan_start(struct wl1271 *wl)
+{
+ struct wl1271_cmd_sched_scan_start *start;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_CMD, "cmd periodic scan start");
+
+ if (wl->bss_type != BSS_TYPE_STA_BSS)
+ return -EOPNOTSUPP;
+
+ if (!test_bit(WL1271_FLAG_IDLE, &wl->flags))
+ return -EBUSY;
+
+ start = kzalloc(sizeof(*start), GFP_KERNEL);
+ if (!start)
+ return -ENOMEM;
+
+ start->tag = WL1271_SCAN_DEFAULT_TAG;
+
+ ret = wl1271_cmd_send(wl, CMD_START_PERIODIC_SCAN, start,
+ sizeof(*start), 0);
+ if (ret < 0) {
+ wl1271_error("failed to send scan start command");
+ goto out_free;
+ }
+
+out_free:
+ kfree(start);
+ return ret;
+}
+
+void wl1271_scan_sched_scan_results(struct wl1271 *wl)
+{
+ wl1271_debug(DEBUG_SCAN, "got periodic scan results");
+
+ ieee80211_sched_scan_results(wl->hw);
+}
+
+void wl1271_scan_sched_scan_stop(struct wl1271 *wl)
+{
+ struct wl1271_cmd_sched_scan_stop *stop;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_CMD, "cmd periodic scan stop");
+
+ /* FIXME: what to do if alloc'ing to stop fails? */
+ stop = kzalloc(sizeof(*stop), GFP_KERNEL);
+ if (!stop) {
+ wl1271_error("failed to alloc memory to send sched scan stop");
+ return;
+ }
+
+ stop->tag = WL1271_SCAN_DEFAULT_TAG;
+
+ ret = wl1271_cmd_send(wl, CMD_STOP_PERIODIC_SCAN, stop,
+ sizeof(*stop), 0);
+ if (ret < 0) {
+ wl1271_error("failed to send sched scan stop command");
+ goto out_free;
+ }
+ wl->sched_scanning = false;
+
+out_free:
+ kfree(stop);
+}
diff --git a/drivers/net/wireless/wl12xx/scan.h b/drivers/net/wireless/wl12xx/scan.h
index 421a750add5a..c83319579ca3 100644
--- a/drivers/net/wireless/wl12xx/scan.h
+++ b/drivers/net/wireless/wl12xx/scan.h
@@ -33,6 +33,12 @@ int wl1271_scan_build_probe_req(struct wl1271 *wl,
const u8 *ie, size_t ie_len, u8 band);
void wl1271_scan_stm(struct wl1271 *wl);
void wl1271_scan_complete_work(struct work_struct *work);
+int wl1271_scan_sched_scan_config(struct wl1271 *wl,
+ struct cfg80211_sched_scan_request *req,
+ struct ieee80211_sched_scan_ies *ies);
+int wl1271_scan_sched_scan_start(struct wl1271 *wl);
+void wl1271_scan_sched_scan_stop(struct wl1271 *wl);
+void wl1271_scan_sched_scan_results(struct wl1271 *wl);
#define WL1271_SCAN_MAX_CHANNELS 24
#define WL1271_SCAN_DEFAULT_TAG 1
@@ -106,4 +112,112 @@ struct wl1271_cmd_trigger_scan_to {
__le32 timeout;
} __packed;
+#define MAX_CHANNELS_ALL_BANDS 41
+#define SCAN_MAX_CYCLE_INTERVALS 16
+#define SCAN_MAX_BANDS 3
+
+enum {
+ SCAN_CHANNEL_TYPE_2GHZ_PASSIVE,
+ SCAN_CHANNEL_TYPE_2GHZ_ACTIVE,
+ SCAN_CHANNEL_TYPE_5GHZ_PASSIVE,
+ SCAN_CHANNEL_TYPE_5GHZ_ACTIVE,
+ SCAN_CHANNEL_TYPE_5GHZ_DFS,
+};
+
+enum {
+ SCAN_SSID_FILTER_ANY = 0,
+ SCAN_SSID_FILTER_SPECIFIC = 1,
+ SCAN_SSID_FILTER_LIST = 2,
+ SCAN_SSID_FILTER_DISABLED = 3
+};
+
+enum {
+ SCAN_BSS_TYPE_INDEPENDENT,
+ SCAN_BSS_TYPE_INFRASTRUCTURE,
+ SCAN_BSS_TYPE_ANY,
+};
+
+struct conn_scan_ch_params {
+ __le16 min_duration;
+ __le16 max_duration;
+ __le16 passive_duration;
+
+ u8 channel;
+ u8 tx_power_att;
+
+ /* bit 0: DFS channel; bit 1: DFS enabled */
+ u8 flags;
+
+ u8 padding[3];
+} __packed;
+
+struct wl1271_cmd_sched_scan_config {
+ struct wl1271_cmd_header header;
+
+ __le32 intervals[SCAN_MAX_CYCLE_INTERVALS];
+
+ s8 rssi_threshold; /* for filtering (in dBm) */
+ s8 snr_threshold; /* for filtering (in dB) */
+
+ u8 cycles; /* maximum number of scan cycles */
+ u8 report_after; /* report when this number of results are received */
+ u8 terminate; /* stop scanning after reporting */
+
+ u8 tag;
+ u8 bss_type; /* for filtering */
+ u8 filter_type;
+
+ u8 ssid_len; /* For SCAN_SSID_FILTER_SPECIFIC */
+ u8 ssid[IW_ESSID_MAX_SIZE];
+
+ u8 n_probe_reqs; /* Number of probes requests per channel */
+
+ u8 passive[SCAN_MAX_BANDS];
+ u8 active[SCAN_MAX_BANDS];
+
+ u8 dfs;
+
+ u8 padding[3];
+
+ struct conn_scan_ch_params channels[MAX_CHANNELS_ALL_BANDS];
+} __packed;
+
+
+#define SCHED_SCAN_MAX_SSIDS 8
+
+enum {
+ SCAN_SSID_TYPE_PUBLIC = 0,
+ SCAN_SSID_TYPE_HIDDEN = 1,
+};
+
+struct wl1271_ssid {
+ u8 type;
+ u8 len;
+ u8 ssid[IW_ESSID_MAX_SIZE];
+ /* u8 padding[2]; */
+} __packed;
+
+struct wl1271_cmd_sched_scan_ssid_list {
+ struct wl1271_cmd_header header;
+
+ u8 n_ssids;
+ struct wl1271_ssid ssids[SCHED_SCAN_MAX_SSIDS];
+ u8 padding[3];
+} __packed;
+
+struct wl1271_cmd_sched_scan_start {
+ struct wl1271_cmd_header header;
+
+ u8 tag;
+ u8 padding[3];
+} __packed;
+
+struct wl1271_cmd_sched_scan_stop {
+ struct wl1271_cmd_header header;
+
+ u8 tag;
+ u8 padding[3];
+} __packed;
+
+
#endif /* __WL1271_SCAN_H__ */
diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c
index b1c7d031c391..536e5065454b 100644
--- a/drivers/net/wireless/wl12xx/sdio.c
+++ b/drivers/net/wireless/wl12xx/sdio.c
@@ -51,6 +51,13 @@ static const struct sdio_device_id wl1271_devices[] = {
};
MODULE_DEVICE_TABLE(sdio, wl1271_devices);
+static void wl1271_sdio_set_block_size(struct wl1271 *wl, unsigned int blksz)
+{
+ sdio_claim_host(wl->if_priv);
+ sdio_set_block_size(wl->if_priv, blksz);
+ sdio_release_host(wl->if_priv);
+}
+
static inline struct sdio_func *wl_to_func(struct wl1271 *wl)
{
return wl->if_priv;
@@ -75,6 +82,16 @@ static irqreturn_t wl1271_hardirq(int irq, void *cookie)
complete(wl->elp_compl);
wl->elp_compl = NULL;
}
+
+ if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
+ /* don't enqueue a work right now. mark it as pending */
+ set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
+ wl1271_debug(DEBUG_IRQ, "should not enqueue work");
+ disable_irq_nosync(wl->irq);
+ pm_wakeup_event(wl1271_sdio_wl_to_dev(wl), 0);
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+ return IRQ_HANDLED;
+ }
spin_unlock_irqrestore(&wl->wl_lock, flags);
return IRQ_WAKE_THREAD;
@@ -203,7 +220,8 @@ static struct wl1271_if_operations sdio_ops = {
.power = wl1271_sdio_set_power,
.dev = wl1271_sdio_wl_to_dev,
.enable_irq = wl1271_sdio_enable_interrupts,
- .disable_irq = wl1271_sdio_disable_interrupts
+ .disable_irq = wl1271_sdio_disable_interrupts,
+ .set_block_size = wl1271_sdio_set_block_size,
};
static int __devinit wl1271_probe(struct sdio_func *func,
@@ -212,6 +230,8 @@ static int __devinit wl1271_probe(struct sdio_func *func,
struct ieee80211_hw *hw;
const struct wl12xx_platform_data *wlan_data;
struct wl1271 *wl;
+ unsigned long irqflags;
+ mmc_pm_flag_t mmcflags;
int ret;
/* We are only able to handle the wlan function */
@@ -230,6 +250,9 @@ static int __devinit wl1271_probe(struct sdio_func *func,
/* Grab access to FN0 for ELP reg. */
func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
+ /* Use block mode for transferring over one block size of data */
+ func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
+
wlan_data = wl12xx_get_platform_data();
if (IS_ERR(wlan_data)) {
ret = PTR_ERR(wlan_data);
@@ -239,17 +262,34 @@ static int __devinit wl1271_probe(struct sdio_func *func,
wl->irq = wlan_data->irq;
wl->ref_clock = wlan_data->board_ref_clock;
+ wl->tcxo_clock = wlan_data->board_tcxo_clock;
+ wl->platform_quirks = wlan_data->platform_quirks;
+
+ if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
+ irqflags = IRQF_TRIGGER_RISING;
+ else
+ irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq,
- IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+ irqflags,
DRIVER_NAME, wl);
if (ret < 0) {
wl1271_error("request_irq() failed: %d", ret);
goto out_free;
}
+ enable_irq_wake(wl->irq);
+ device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 1);
+
disable_irq(wl->irq);
+ /* if sdio can keep power while host is suspended, enable wow */
+ mmcflags = sdio_get_host_pm_caps(func);
+ wl1271_debug(DEBUG_SDIO, "sdio PM caps = 0x%x", mmcflags);
+
+ if (mmcflags & MMC_PM_KEEP_POWER)
+ hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
+
ret = wl1271_init_ieee80211(wl);
if (ret)
goto out_irq;
@@ -284,19 +324,61 @@ static void __devexit wl1271_remove(struct sdio_func *func)
pm_runtime_get_noresume(&func->dev);
wl1271_unregister_hw(wl);
+ device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 0);
+ disable_irq_wake(wl->irq);
free_irq(wl->irq, wl);
wl1271_free_hw(wl);
}
+#ifdef CONFIG_PM
static int wl1271_suspend(struct device *dev)
{
/* Tell MMC/SDIO core it's OK to power down the card
* (if it isn't already), but not to remove it completely */
- return 0;
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ struct wl1271 *wl = sdio_get_drvdata(func);
+ mmc_pm_flag_t sdio_flags;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_MAC80211, "wl1271 suspend. wow_enabled: %d",
+ wl->wow_enabled);
+
+ /* check whether sdio should keep power */
+ if (wl->wow_enabled) {
+ sdio_flags = sdio_get_host_pm_caps(func);
+
+ if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
+ wl1271_error("can't keep power while host "
+ "is suspended");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* keep power while host suspended */
+ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+ if (ret) {
+ wl1271_error("error while trying to keep power");
+ goto out;
+ }
+
+ /* release host */
+ sdio_release_host(func);
+ }
+out:
+ return ret;
}
static int wl1271_resume(struct device *dev)
{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ struct wl1271 *wl = sdio_get_drvdata(func);
+
+ wl1271_debug(DEBUG_MAC80211, "wl1271 resume");
+ if (wl->wow_enabled) {
+ /* claim back host */
+ sdio_claim_host(func);
+ }
+
return 0;
}
@@ -304,15 +386,18 @@ static const struct dev_pm_ops wl1271_sdio_pm_ops = {
.suspend = wl1271_suspend,
.resume = wl1271_resume,
};
+#endif
static struct sdio_driver wl1271_sdio_driver = {
.name = "wl1271_sdio",
.id_table = wl1271_devices,
.probe = wl1271_probe,
.remove = __devexit_p(wl1271_remove),
+#ifdef CONFIG_PM
.drv = {
.pm = &wl1271_sdio_pm_ops,
},
+#endif
};
static int __init wl1271_init(void)
@@ -343,4 +428,6 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
MODULE_FIRMWARE(WL1271_FW_NAME);
-MODULE_FIRMWARE(WL1271_AP_FW_NAME);
+MODULE_FIRMWARE(WL128X_FW_NAME);
+MODULE_FIRMWARE(WL127X_AP_FW_NAME);
+MODULE_FIRMWARE(WL128X_AP_FW_NAME);
diff --git a/drivers/net/wireless/wl12xx/sdio_test.c b/drivers/net/wireless/wl12xx/sdio_test.c
index 9fcbd3dd8490..f28915392877 100644
--- a/drivers/net/wireless/wl12xx/sdio_test.c
+++ b/drivers/net/wireless/wl12xx/sdio_test.c
@@ -189,7 +189,12 @@ static int wl1271_fetch_firmware(struct wl1271 *wl)
const struct firmware *fw;
int ret;
- ret = request_firmware(&fw, WL1271_FW_NAME, wl1271_wl_to_dev(wl));
+ if (wl->chip.id == CHIP_ID_1283_PG20)
+ ret = request_firmware(&fw, WL128X_FW_NAME,
+ wl1271_wl_to_dev(wl));
+ else
+ ret = request_firmware(&fw, WL1271_FW_NAME,
+ wl1271_wl_to_dev(wl));
if (ret < 0) {
wl1271_error("could not get firmware: %d", ret);
@@ -227,14 +232,14 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
const struct firmware *fw;
int ret;
- ret = request_firmware(&fw, WL1271_NVS_NAME, wl1271_wl_to_dev(wl));
+ ret = request_firmware(&fw, WL12XX_NVS_NAME, wl1271_wl_to_dev(wl));
if (ret < 0) {
wl1271_error("could not get nvs file: %d", ret);
return ret;
}
- wl->nvs = kmemdup(fw->data, sizeof(struct wl1271_nvs_file), GFP_KERNEL);
+ wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
if (!wl->nvs) {
wl1271_error("could not allocate memory for the nvs file");
@@ -288,6 +293,11 @@ static int wl1271_chip_wakeup(struct wl1271 *wl)
wl1271_notice("chip id 0x%x (1271 PG20)",
wl->chip.id);
break;
+ case CHIP_ID_1283_PG20:
+ wl1271_notice("chip id 0x%x (1283 PG20)",
+ wl->chip.id);
+ break;
+ case CHIP_ID_1283_PG10:
default:
wl1271_warning("unsupported chip id: 0x%x", wl->chip.id);
return -ENODEV;
@@ -407,6 +417,9 @@ static int __devinit wl1271_probe(struct sdio_func *func,
/* Grab access to FN0 for ELP reg. */
func->card->quirks |= MMC_QUIRK_LENIENT_FN0;
+ /* Use block mode for transferring over one block size of data */
+ func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE;
+
wlan_data = wl12xx_get_platform_data();
if (IS_ERR(wlan_data)) {
ret = PTR_ERR(wlan_data);
@@ -416,6 +429,7 @@ static int __devinit wl1271_probe(struct sdio_func *func,
wl->irq = wlan_data->irq;
wl->ref_clock = wlan_data->board_ref_clock;
+ wl->tcxo_clock = wlan_data->board_tcxo_clock;
sdio_set_drvdata(func, wl_test);
diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c
index ffc745b17f4d..51662bb68019 100644
--- a/drivers/net/wireless/wl12xx/spi.c
+++ b/drivers/net/wireless/wl12xx/spi.c
@@ -355,7 +355,8 @@ static struct wl1271_if_operations spi_ops = {
.power = wl1271_spi_set_power,
.dev = wl1271_spi_wl_to_dev,
.enable_irq = wl1271_spi_enable_interrupts,
- .disable_irq = wl1271_spi_disable_interrupts
+ .disable_irq = wl1271_spi_disable_interrupts,
+ .set_block_size = NULL,
};
static int __devinit wl1271_probe(struct spi_device *spi)
@@ -363,6 +364,7 @@ static int __devinit wl1271_probe(struct spi_device *spi)
struct wl12xx_platform_data *pdata;
struct ieee80211_hw *hw;
struct wl1271 *wl;
+ unsigned long irqflags;
int ret;
pdata = spi->dev.platform_data;
@@ -400,6 +402,13 @@ static int __devinit wl1271_probe(struct spi_device *spi)
}
wl->ref_clock = pdata->board_ref_clock;
+ wl->tcxo_clock = pdata->board_tcxo_clock;
+ wl->platform_quirks = pdata->platform_quirks;
+
+ if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
+ irqflags = IRQF_TRIGGER_RISING;
+ else
+ irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
wl->irq = spi->irq;
if (wl->irq < 0) {
@@ -409,7 +418,7 @@ static int __devinit wl1271_probe(struct spi_device *spi)
}
ret = request_threaded_irq(wl->irq, wl1271_hardirq, wl1271_irq,
- IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+ irqflags,
DRIVER_NAME, wl);
if (ret < 0) {
wl1271_error("request_irq() failed: %d", ret);
@@ -490,5 +499,7 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
MODULE_FIRMWARE(WL1271_FW_NAME);
-MODULE_FIRMWARE(WL1271_AP_FW_NAME);
+MODULE_FIRMWARE(WL128X_FW_NAME);
+MODULE_FIRMWARE(WL127X_AP_FW_NAME);
+MODULE_FIRMWARE(WL128X_AP_FW_NAME);
MODULE_ALIAS("spi:wl1271");
diff --git a/drivers/net/wireless/wl12xx/testmode.c b/drivers/net/wireless/wl12xx/testmode.c
index 6ec06a4a4c6d..da351d7cd1f2 100644
--- a/drivers/net/wireless/wl12xx/testmode.c
+++ b/drivers/net/wireless/wl12xx/testmode.c
@@ -27,6 +27,7 @@
#include "wl12xx.h"
#include "acx.h"
+#include "reg.h"
#define WL1271_TM_MAX_DATA_LENGTH 1024
@@ -204,7 +205,10 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[])
kfree(wl->nvs);
- if (len != sizeof(struct wl1271_nvs_file))
+ if ((wl->chip.id == CHIP_ID_1283_PG20) &&
+ (len != sizeof(struct wl128x_nvs_file)))
+ return -EINVAL;
+ else if (len != sizeof(struct wl1271_nvs_file))
return -EINVAL;
wl->nvs = kzalloc(len, GFP_KERNEL);
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 5e9ef7d53e7e..ca3ab1c1acef 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -65,11 +65,36 @@ static int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb)
static void wl1271_free_tx_id(struct wl1271 *wl, int id)
{
if (__test_and_clear_bit(id, wl->tx_frames_map)) {
+ if (unlikely(wl->tx_frames_cnt == ACX_TX_DESCRIPTORS))
+ clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
+
wl->tx_frames[id] = NULL;
wl->tx_frames_cnt--;
}
}
+static int wl1271_tx_update_filters(struct wl1271 *wl,
+ struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr;
+
+ hdr = (struct ieee80211_hdr *)(skb->data +
+ sizeof(struct wl1271_tx_hw_descr));
+
+ /*
+ * stop bssid-based filtering before transmitting authentication
+ * requests. this way the hw will never drop authentication
+ * responses coming from BSSIDs it isn't familiar with (e.g. on
+ * roaming)
+ */
+ if (!ieee80211_is_auth(hdr->frame_control))
+ return 0;
+
+ wl1271_configure_filters(wl, FIF_OTHER_BSS);
+
+ return wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
+}
+
static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
struct sk_buff *skb)
{
@@ -127,13 +152,29 @@ u8 wl1271_tx_get_hlid(struct sk_buff *skb)
}
}
+static unsigned int wl12xx_calc_packet_alignment(struct wl1271 *wl,
+ unsigned int packet_length)
+{
+ if (wl->quirks & WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT)
+ return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE);
+ else
+ return ALIGN(packet_length, WL1271_TX_ALIGN_TO);
+}
+
static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
u32 buf_offset, u8 hlid)
{
struct wl1271_tx_hw_descr *desc;
u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
+ u32 len;
u32 total_blocks;
int id, ret = -EBUSY;
+ u32 spare_blocks;
+
+ if (unlikely(wl->quirks & WL12XX_QUIRK_USE_2_SPARE_BLOCKS))
+ spare_blocks = 2;
+ else
+ spare_blocks = 1;
if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE)
return -EAGAIN;
@@ -145,17 +186,27 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
/* approximate the number of blocks required for this packet
in the firmware */
- total_blocks = total_len + TX_HW_BLOCK_SIZE - 1;
- total_blocks = total_blocks / TX_HW_BLOCK_SIZE + TX_HW_BLOCK_SPARE;
+ len = wl12xx_calc_packet_alignment(wl, total_len);
+
+ total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE +
+ spare_blocks;
+
if (total_blocks <= wl->tx_blocks_available) {
desc = (struct wl1271_tx_hw_descr *)skb_push(
skb, total_len - skb->len);
- desc->extra_mem_blocks = TX_HW_BLOCK_SPARE;
- desc->total_mem_blocks = total_blocks;
+ /* HW descriptor fields change between wl127x and wl128x */
+ if (wl->chip.id == CHIP_ID_1283_PG20) {
+ desc->wl128x_mem.total_mem_blocks = total_blocks;
+ } else {
+ desc->wl127x_mem.extra_blocks = spare_blocks;
+ desc->wl127x_mem.total_mem_blocks = total_blocks;
+ }
+
desc->id = id;
wl->tx_blocks_available -= total_blocks;
+ wl->tx_allocated_blocks += total_blocks;
if (wl->bss_type == BSS_TYPE_AP_BSS)
wl->links[hlid].allocated_blks += total_blocks;
@@ -172,13 +223,18 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra,
return ret;
}
+static bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb)
+{
+ return wl->dummy_packet == skb;
+}
+
static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
u32 extra, struct ieee80211_tx_info *control,
u8 hlid)
{
struct timespec ts;
struct wl1271_tx_hw_descr *desc;
- int pad, ac, rate_idx;
+ int aligned_len, ac, rate_idx;
s64 hosttime;
u16 tx_attr;
@@ -202,12 +258,25 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
else
desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU);
- /* configure the tx attributes */
- tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
-
- /* queue (we use same identifiers for tid's and ac's */
+ /* queue */
ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
- desc->tid = ac;
+ desc->tid = skb->priority;
+
+ if (wl12xx_is_dummy_packet(wl, skb)) {
+ /*
+ * FW expects the dummy packet to have an invalid session id -
+ * any session id that is different than the one set in the join
+ */
+ tx_attr = ((~wl->session_counter) <<
+ TX_HW_ATTR_OFST_SESSION_COUNTER) &
+ TX_HW_ATTR_SESSION_COUNTER;
+
+ tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ;
+ } else {
+ /* configure the tx attributes */
+ tx_attr =
+ wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER;
+ }
if (wl->bss_type != BSS_TYPE_AP_BSS) {
desc->aid = hlid;
@@ -237,20 +306,37 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb,
tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY;
desc->reserved = 0;
- /* align the length (and store in terms of words) */
- pad = ALIGN(skb->len, WL1271_TX_ALIGN_TO);
- desc->length = cpu_to_le16(pad >> 2);
+ aligned_len = wl12xx_calc_packet_alignment(wl, skb->len);
- /* calculate number of padding bytes */
- pad = pad - skb->len;
- tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD;
+ if (wl->chip.id == CHIP_ID_1283_PG20) {
+ desc->wl128x_mem.extra_bytes = aligned_len - skb->len;
+ desc->length = cpu_to_le16(aligned_len >> 2);
- desc->tx_attr = cpu_to_le16(tx_attr);
+ wl1271_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d "
+ "tx_attr: 0x%x len: %d life: %d mem: %d",
+ desc->hlid, tx_attr,
+ le16_to_cpu(desc->length),
+ le16_to_cpu(desc->life_time),
+ desc->wl128x_mem.total_mem_blocks);
+ } else {
+ int pad;
- wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d hlid: %d "
- "tx_attr: 0x%x len: %d life: %d mem: %d", pad, desc->hlid,
- le16_to_cpu(desc->tx_attr), le16_to_cpu(desc->length),
- le16_to_cpu(desc->life_time), desc->total_mem_blocks);
+ /* Store the aligned length in terms of words */
+ desc->length = cpu_to_le16(aligned_len >> 2);
+
+ /* calculate number of padding bytes */
+ pad = aligned_len - skb->len;
+ tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD;
+
+ wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d hlid: %d "
+ "tx_attr: 0x%x len: %d life: %d mem: %d", pad,
+ desc->hlid, tx_attr,
+ le16_to_cpu(desc->length),
+ le16_to_cpu(desc->life_time),
+ desc->wl127x_mem.total_mem_blocks);
+ }
+
+ desc->tx_attr = cpu_to_le16(tx_attr);
}
/* caller must hold wl->mutex */
@@ -300,19 +386,29 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
if (wl->bss_type == BSS_TYPE_AP_BSS) {
wl1271_tx_ap_update_inconnection_sta(wl, skb);
wl1271_tx_regulate_link(wl, hlid);
+ } else {
+ wl1271_tx_update_filters(wl, skb);
}
wl1271_tx_fill_hdr(wl, skb, extra, info, hlid);
/*
- * The length of each packet is stored in terms of words. Thus, we must
- * pad the skb data to make sure its length is aligned.
- * The number of padding bytes is computed and set in wl1271_tx_fill_hdr
+ * The length of each packet is stored in terms of
+ * words. Thus, we must pad the skb data to make sure its
+ * length is aligned. The number of padding bytes is computed
+ * and set in wl1271_tx_fill_hdr.
+ * In special cases, we want to align to a specific block size
+ * (eg. for wl128x with SDIO we align to 256).
*/
- total_len = ALIGN(skb->len, WL1271_TX_ALIGN_TO);
+ total_len = wl12xx_calc_packet_alignment(wl, skb->len);
+
memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len);
memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len);
+ /* Revert side effects in the dummy packet skb, so it can be reused */
+ if (wl12xx_is_dummy_packet(wl, skb))
+ skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
+
return total_len;
}
@@ -425,10 +521,23 @@ out:
static struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl)
{
+ unsigned long flags;
+ struct sk_buff *skb = NULL;
+
if (wl->bss_type == BSS_TYPE_AP_BSS)
- return wl1271_ap_skb_dequeue(wl);
+ skb = wl1271_ap_skb_dequeue(wl);
+ else
+ skb = wl1271_sta_skb_dequeue(wl);
- return wl1271_sta_skb_dequeue(wl);
+ if (!skb &&
+ test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) {
+ skb = wl->dummy_packet;
+ spin_lock_irqsave(&wl->wl_lock, flags);
+ wl->tx_queue_count--;
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+ }
+
+ return skb;
}
static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb)
@@ -436,7 +545,9 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb)
unsigned long flags;
int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
- if (wl->bss_type == BSS_TYPE_AP_BSS) {
+ if (wl12xx_is_dummy_packet(wl, skb)) {
+ set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
+ } else if (wl->bss_type == BSS_TYPE_AP_BSS) {
u8 hlid = wl1271_tx_get_hlid(skb);
skb_queue_head(&wl->links[hlid].tx_queue[q], skb);
@@ -454,22 +565,14 @@ static void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb)
void wl1271_tx_work_locked(struct wl1271 *wl)
{
struct sk_buff *skb;
- bool woken_up = false;
u32 buf_offset = 0;
bool sent_packets = false;
int ret;
if (unlikely(wl->state == WL1271_STATE_OFF))
- goto out;
+ return;
while ((skb = wl1271_skb_dequeue(wl))) {
- if (!woken_up) {
- ret = wl1271_ps_elp_wakeup(wl);
- if (ret < 0)
- goto out_ack;
- woken_up = true;
- }
-
ret = wl1271_prepare_tx_frame(wl, skb, buf_offset);
if (ret == -EAGAIN) {
/*
@@ -516,18 +619,22 @@ out_ack:
wl1271_handle_tx_low_watermark(wl);
}
-
-out:
- if (woken_up)
- wl1271_ps_elp_sleep(wl);
}
void wl1271_tx_work(struct work_struct *work)
{
struct wl1271 *wl = container_of(work, struct wl1271, tx_work);
+ int ret;
mutex_lock(&wl->mutex);
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
wl1271_tx_work_locked(wl);
+
+ wl1271_ps_elp_sleep(wl);
+out:
mutex_unlock(&wl->mutex);
}
@@ -549,6 +656,11 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
skb = wl->tx_frames[id];
info = IEEE80211_SKB_CB(skb);
+ if (wl12xx_is_dummy_packet(wl, skb)) {
+ wl1271_free_tx_id(wl, id);
+ return;
+ }
+
/* update the TX status info */
if (result->status == TX_SUCCESS) {
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
@@ -657,8 +769,8 @@ void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid)
wl1271_handle_tx_low_watermark(wl);
}
-/* caller must hold wl->mutex */
-void wl1271_tx_reset(struct wl1271 *wl)
+/* caller must hold wl->mutex and TX must be stopped */
+void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
{
int i;
struct sk_buff *skb;
@@ -678,10 +790,13 @@ void wl1271_tx_reset(struct wl1271 *wl)
while ((skb = skb_dequeue(&wl->tx_queue[i]))) {
wl1271_debug(DEBUG_TX, "freeing skb 0x%p",
skb);
- info = IEEE80211_SKB_CB(skb);
- info->status.rates[0].idx = -1;
- info->status.rates[0].count = 0;
- ieee80211_tx_status(wl->hw, skb);
+
+ if (!wl12xx_is_dummy_packet(wl, skb)) {
+ info = IEEE80211_SKB_CB(skb);
+ info->status.rates[0].idx = -1;
+ info->status.rates[0].count = 0;
+ ieee80211_tx_status(wl->hw, skb);
+ }
}
}
}
@@ -691,8 +806,10 @@ void wl1271_tx_reset(struct wl1271 *wl)
/*
* Make sure the driver is at a consistent state, in case this
* function is called from a context other than interface removal.
+ * This call will always wake the TX queues.
*/
- wl1271_handle_tx_low_watermark(wl);
+ if (reset_tx_queues)
+ wl1271_handle_tx_low_watermark(wl);
for (i = 0; i < ACX_TX_DESCRIPTORS; i++) {
if (wl->tx_frames[i] == NULL)
@@ -702,21 +819,27 @@ void wl1271_tx_reset(struct wl1271 *wl)
wl1271_free_tx_id(wl, i);
wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);
- /* Remove private headers before passing the skb to mac80211 */
- info = IEEE80211_SKB_CB(skb);
- skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
- if (info->control.hw_key &&
- info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
- int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
- memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data,
- hdrlen);
- skb_pull(skb, WL1271_TKIP_IV_SPACE);
- }
+ if (!wl12xx_is_dummy_packet(wl, skb)) {
+ /*
+ * Remove private headers before passing the skb to
+ * mac80211
+ */
+ info = IEEE80211_SKB_CB(skb);
+ skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
+ if (info->control.hw_key &&
+ info->control.hw_key->cipher ==
+ WLAN_CIPHER_SUITE_TKIP) {
+ int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+ memmove(skb->data + WL1271_TKIP_IV_SPACE,
+ skb->data, hdrlen);
+ skb_pull(skb, WL1271_TKIP_IV_SPACE);
+ }
- info->status.rates[0].idx = -1;
- info->status.rates[0].count = 0;
+ info->status.rates[0].idx = -1;
+ info->status.rates[0].count = 0;
- ieee80211_tx_status(wl->hw, skb);
+ ieee80211_tx_status(wl->hw, skb);
+ }
}
}
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h
index 02f07fa66e82..832f9258d675 100644
--- a/drivers/net/wireless/wl12xx/tx.h
+++ b/drivers/net/wireless/wl12xx/tx.h
@@ -25,7 +25,6 @@
#ifndef __TX_H__
#define __TX_H__
-#define TX_HW_BLOCK_SPARE 2
#define TX_HW_BLOCK_SIZE 252
#define TX_HW_MGMT_PKT_LIFETIME_TU 2000
@@ -41,6 +40,7 @@
BIT(8) | BIT(9))
#define TX_HW_ATTR_LAST_WORD_PAD (BIT(10) | BIT(11))
#define TX_HW_ATTR_TX_CMPLT_REQ BIT(12)
+#define TX_HW_ATTR_TX_DUMMY_REQ BIT(13)
#define TX_HW_ATTR_OFST_SAVE_RETRIES 0
#define TX_HW_ATTR_OFST_HEADER_PAD 1
@@ -55,20 +55,60 @@
#define WL1271_TX_ALIGN_TO 4
#define WL1271_TKIP_IV_SPACE 4
+/* Used for management frames and dummy packets */
+#define WL1271_TID_MGMT 7
+
+struct wl127x_tx_mem {
+ /*
+ * Number of extra memory blocks to allocate for this packet
+ * in addition to the number of blocks derived from the packet
+ * length.
+ */
+ u8 extra_blocks;
+ /*
+ * Total number of memory blocks allocated by the host for
+ * this packet. Must be equal or greater than the actual
+ * blocks number allocated by HW.
+ */
+ u8 total_mem_blocks;
+} __packed;
+
+struct wl128x_tx_mem {
+ /*
+ * Total number of memory blocks allocated by the host for
+ * this packet.
+ */
+ u8 total_mem_blocks;
+ /*
+ * Number of extra bytes, at the end of the frame. the host
+ * uses this padding to complete each frame to integer number
+ * of SDIO blocks.
+ */
+ u8 extra_bytes;
+} __packed;
+
+/*
+ * On wl128x based devices, when TX packets are aggregated, each packet
+ * size must be aligned to the SDIO block size. The maximum block size
+ * is bounded by the type of the padded bytes field that is sent to the
+ * FW. Currently the type is u8, so the maximum block size is 256 bytes.
+ */
+#define WL12XX_BUS_BLOCK_SIZE min(512u, \
+ (1u << (8 * sizeof(((struct wl128x_tx_mem *) 0)->extra_bytes))))
+
struct wl1271_tx_hw_descr {
/* Length of packet in words, including descriptor+header+data */
__le16 length;
- /* Number of extra memory blocks to allocate for this packet in
- addition to the number of blocks derived from the packet length */
- u8 extra_mem_blocks;
- /* Total number of memory blocks allocated by the host for this packet.
- Must be equal or greater than the actual blocks number allocated by
- HW!! */
- u8 total_mem_blocks;
+ union {
+ struct wl127x_tx_mem wl127x_mem;
+ struct wl128x_tx_mem wl128x_mem;
+ } __packed;
/* Device time (in us) when the packet arrived to the driver */
__le32 start_time;
- /* Max delay in TUs until transmission. The last device time the
- packet can be transmitted is: startTime+(1024*LifeTime) */
+ /*
+ * Max delay in TUs until transmission. The last device time the
+ * packet can be transmitted is: start_time + (1024 * life_time)
+ */
__le16 life_time;
/* Bitwise fields - see TX_ATTR... definitions above. */
__le16 tx_attr;
@@ -145,7 +185,7 @@ static inline int wl1271_tx_get_queue(int queue)
void wl1271_tx_work(struct work_struct *work);
void wl1271_tx_work_locked(struct wl1271 *wl);
void wl1271_tx_complete(struct wl1271 *wl);
-void wl1271_tx_reset(struct wl1271 *wl);
+void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues);
void wl1271_tx_flush(struct wl1271 *wl);
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set);
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 86be83e25ec5..fbe8f46d1232 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -131,9 +131,16 @@ extern u32 wl12xx_debug_level;
#define WL1271_FW_NAME "ti-connectivity/wl1271-fw-2.bin"
-#define WL1271_AP_FW_NAME "ti-connectivity/wl1271-fw-ap.bin"
+#define WL128X_FW_NAME "ti-connectivity/wl128x-fw.bin"
+#define WL127X_AP_FW_NAME "ti-connectivity/wl1271-fw-ap.bin"
+#define WL128X_AP_FW_NAME "ti-connectivity/wl128x-fw-ap.bin"
-#define WL1271_NVS_NAME "ti-connectivity/wl1271-nvs.bin"
+/*
+ * wl127x and wl128x are using the same NVS file name. However, the
+ * ini parameters between them are different. The driver validates
+ * the correct NVS size in wl1271_boot_upload_nvs().
+ */
+#define WL12XX_NVS_NAME "ti-connectivity/wl1271-nvs.bin"
#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
#define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff))
@@ -200,13 +207,29 @@ struct wl1271_partition_set {
struct wl1271;
-#define WL12XX_NUM_FW_VER 5
+enum {
+ FW_VER_CHIP,
+ FW_VER_IF_TYPE,
+ FW_VER_MAJOR,
+ FW_VER_SUBTYPE,
+ FW_VER_MINOR,
+
+ NUM_FW_VER
+};
+
+#define FW_VER_CHIP_WL127X 6
+#define FW_VER_CHIP_WL128X 7
+
+#define FW_VER_IF_TYPE_STA 1
+#define FW_VER_IF_TYPE_AP 2
+
+#define FW_VER_MINOR_1_SPARE_STA_MIN 58
+#define FW_VER_MINOR_1_SPARE_AP_MIN 47
-/* FIXME: I'm not sure about this structure name */
struct wl1271_chip {
u32 id;
char fw_ver_str[ETHTOOL_BUSINFO_LEN];
- unsigned int fw_ver[WL12XX_NUM_FW_VER];
+ unsigned int fw_ver[NUM_FW_VER];
};
struct wl1271_stats {
@@ -261,6 +284,8 @@ struct wl1271_fw_sta_status {
u8 tx_total;
u8 reserved1;
__le16 reserved2;
+ /* Total structure size is 68 bytes */
+ u32 padding;
} __packed;
struct wl1271_fw_full_status {
@@ -277,9 +302,10 @@ struct wl1271_rx_mem_pool_addr {
u32 addr_extra;
};
+#define WL1271_MAX_CHANNELS 64
struct wl1271_scan {
struct cfg80211_scan_request *req;
- bool *scanned_ch;
+ unsigned long scanned_ch[BITS_TO_LONGS(WL1271_MAX_CHANNELS)];
bool failed;
u8 state;
u8 ssid[IW_ESSID_MAX_SIZE+1];
@@ -297,6 +323,7 @@ struct wl1271_if_operations {
struct device* (*dev)(struct wl1271 *wl);
void (*enable_irq)(struct wl1271 *wl);
void (*disable_irq)(struct wl1271 *wl);
+ void (*set_block_size) (struct wl1271 *wl, unsigned int blksz);
};
#define MAX_NUM_KEYS 14
@@ -319,15 +346,19 @@ enum wl12xx_flags {
WL1271_FLAG_TX_QUEUE_STOPPED,
WL1271_FLAG_TX_PENDING,
WL1271_FLAG_IN_ELP,
+ WL1271_FLAG_ELP_REQUESTED,
WL1271_FLAG_PSM,
WL1271_FLAG_PSM_REQUESTED,
WL1271_FLAG_IRQ_RUNNING,
WL1271_FLAG_IDLE,
- WL1271_FLAG_IDLE_REQUESTED,
WL1271_FLAG_PSPOLL_FAILURE,
WL1271_FLAG_STA_STATE_SENT,
WL1271_FLAG_FW_TX_BUSY,
- WL1271_FLAG_AP_STARTED
+ WL1271_FLAG_AP_STARTED,
+ WL1271_FLAG_IF_INITIALIZED,
+ WL1271_FLAG_DUMMY_PACKET_PENDING,
+ WL1271_FLAG_SUSPENDED,
+ WL1271_FLAG_PENDING_WORK,
};
struct wl1271_link {
@@ -371,7 +402,7 @@ struct wl1271 {
u8 *fw;
size_t fw_len;
u8 fw_bss_type;
- struct wl1271_nvs_file *nvs;
+ void *nvs;
size_t nvs_len;
s8 hw_pg_ver;
@@ -389,6 +420,7 @@ struct wl1271 {
/* Accounting for allocated / available TX blocks on HW */
u32 tx_blocks_freed[NUM_TX_QUEUES];
u32 tx_blocks_available;
+ u32 tx_allocated_blocks;
u32 tx_results_count;
/* Transmitted TX packets counter for chipset interface */
@@ -430,6 +462,9 @@ struct wl1271 {
/* Intermediate buffer, used for packet aggregation */
u8 *aggr_buf;
+ /* Reusable dummy packet template */
+ struct sk_buff *dummy_packet;
+
/* Network stack work */
struct work_struct netstack_work;
@@ -446,6 +481,8 @@ struct wl1271 {
struct wl1271_scan scan;
struct delayed_work scan_complete_work;
+ bool sched_scanning;
+
/* probe-req template for the current AP */
struct sk_buff *probereq;
@@ -476,6 +513,7 @@ struct wl1271 {
unsigned int rx_filter;
struct completion *elp_compl;
+ struct completion *ps_compl;
struct delayed_work elp_work;
struct delayed_work pspoll_work;
@@ -527,6 +565,14 @@ struct wl1271 {
bool ba_support;
u8 ba_rx_bitmap;
+ int tcxo_clock;
+
+ /*
+ * wowlan trigger was configured during suspend.
+ * (currently, only "ANY" trigger is supported)
+ */
+ bool wow_enabled;
+
/*
* AP-mode - links indexed by HLID. The global and broadcast links
* are always active.
@@ -544,6 +590,9 @@ struct wl1271 {
/* Quirks of specific hardware revisions */
unsigned int quirks;
+
+ /* Platform limitations */
+ unsigned int platform_quirks;
};
struct wl1271_station {
@@ -576,6 +625,15 @@ int wl1271_plt_stop(struct wl1271 *wl);
/* Quirks */
/* Each RX/TX transaction requires an end-of-transaction transfer */
-#define WL12XX_QUIRK_END_OF_TRANSACTION BIT(0)
+#define WL12XX_QUIRK_END_OF_TRANSACTION BIT(0)
+
+/*
+ * Older firmwares use 2 spare TX blocks
+ * (for STA < 6.1.3.50.58 or for AP < 6.2.0.0.47)
+ */
+#define WL12XX_QUIRK_USE_2_SPARE_BLOCKS BIT(1)
+
+/* WL128X requires aggregated packets to be aligned to the SDIO block size */
+#define WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT BIT(2)
#endif
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index fc08f36fe1f5..6bc7c92fbff7 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -2000,7 +2000,7 @@ static int wl3501_resume(struct pcmcia_device *link)
}
-static struct pcmcia_device_id wl3501_ids[] = {
+static const struct pcmcia_device_id wl3501_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0001),
PCMCIA_DEVICE_NULL
};
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index a73a305d3cba..ff306d763e37 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -557,7 +557,7 @@ int zd_chip_unlock_phy_regs(struct zd_chip *chip)
return r;
}
-/* CR157 can be optionally patched by the EEPROM for original ZD1211 */
+/* ZD_CR157 can be optionally patched by the EEPROM for original ZD1211 */
static int patch_cr157(struct zd_chip *chip)
{
int r;
@@ -571,7 +571,7 @@ static int patch_cr157(struct zd_chip *chip)
return r;
dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value >> 8);
- return zd_iowrite32_locked(chip, value >> 8, CR157);
+ return zd_iowrite32_locked(chip, value >> 8, ZD_CR157);
}
/*
@@ -593,8 +593,8 @@ static int patch_6m_band_edge(struct zd_chip *chip, u8 channel)
int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel)
{
struct zd_ioreq16 ioreqs[] = {
- { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
- { CR47, 0x1e },
+ { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 },
+ { ZD_CR47, 0x1e },
};
/* FIXME: Channel 11 is not the edge for all regulatory domains. */
@@ -608,69 +608,69 @@ int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel)
static int zd1211_hw_reset_phy(struct zd_chip *chip)
{
static const struct zd_ioreq16 ioreqs[] = {
- { CR0, 0x0a }, { CR1, 0x06 }, { CR2, 0x26 },
- { CR3, 0x38 }, { CR4, 0x80 }, { CR9, 0xa0 },
- { CR10, 0x81 }, { CR11, 0x00 }, { CR12, 0x7f },
- { CR13, 0x8c }, { CR14, 0x80 }, { CR15, 0x3d },
- { CR16, 0x20 }, { CR17, 0x1e }, { CR18, 0x0a },
- { CR19, 0x48 }, { CR20, 0x0c }, { CR21, 0x0c },
- { CR22, 0x23 }, { CR23, 0x90 }, { CR24, 0x14 },
- { CR25, 0x40 }, { CR26, 0x10 }, { CR27, 0x19 },
- { CR28, 0x7f }, { CR29, 0x80 }, { CR30, 0x4b },
- { CR31, 0x60 }, { CR32, 0x43 }, { CR33, 0x08 },
- { CR34, 0x06 }, { CR35, 0x0a }, { CR36, 0x00 },
- { CR37, 0x00 }, { CR38, 0x38 }, { CR39, 0x0c },
- { CR40, 0x84 }, { CR41, 0x2a }, { CR42, 0x80 },
- { CR43, 0x10 }, { CR44, 0x12 }, { CR46, 0xff },
- { CR47, 0x1E }, { CR48, 0x26 }, { CR49, 0x5b },
- { CR64, 0xd0 }, { CR65, 0x04 }, { CR66, 0x58 },
- { CR67, 0xc9 }, { CR68, 0x88 }, { CR69, 0x41 },
- { CR70, 0x23 }, { CR71, 0x10 }, { CR72, 0xff },
- { CR73, 0x32 }, { CR74, 0x30 }, { CR75, 0x65 },
- { CR76, 0x41 }, { CR77, 0x1b }, { CR78, 0x30 },
- { CR79, 0x68 }, { CR80, 0x64 }, { CR81, 0x64 },
- { CR82, 0x00 }, { CR83, 0x00 }, { CR84, 0x00 },
- { CR85, 0x02 }, { CR86, 0x00 }, { CR87, 0x00 },
- { CR88, 0xff }, { CR89, 0xfc }, { CR90, 0x00 },
- { CR91, 0x00 }, { CR92, 0x00 }, { CR93, 0x08 },
- { CR94, 0x00 }, { CR95, 0x00 }, { CR96, 0xff },
- { CR97, 0xe7 }, { CR98, 0x00 }, { CR99, 0x00 },
- { CR100, 0x00 }, { CR101, 0xae }, { CR102, 0x02 },
- { CR103, 0x00 }, { CR104, 0x03 }, { CR105, 0x65 },
- { CR106, 0x04 }, { CR107, 0x00 }, { CR108, 0x0a },
- { CR109, 0xaa }, { CR110, 0xaa }, { CR111, 0x25 },
- { CR112, 0x25 }, { CR113, 0x00 }, { CR119, 0x1e },
- { CR125, 0x90 }, { CR126, 0x00 }, { CR127, 0x00 },
+ { ZD_CR0, 0x0a }, { ZD_CR1, 0x06 }, { ZD_CR2, 0x26 },
+ { ZD_CR3, 0x38 }, { ZD_CR4, 0x80 }, { ZD_CR9, 0xa0 },
+ { ZD_CR10, 0x81 }, { ZD_CR11, 0x00 }, { ZD_CR12, 0x7f },
+ { ZD_CR13, 0x8c }, { ZD_CR14, 0x80 }, { ZD_CR15, 0x3d },
+ { ZD_CR16, 0x20 }, { ZD_CR17, 0x1e }, { ZD_CR18, 0x0a },
+ { ZD_CR19, 0x48 }, { ZD_CR20, 0x0c }, { ZD_CR21, 0x0c },
+ { ZD_CR22, 0x23 }, { ZD_CR23, 0x90 }, { ZD_CR24, 0x14 },
+ { ZD_CR25, 0x40 }, { ZD_CR26, 0x10 }, { ZD_CR27, 0x19 },
+ { ZD_CR28, 0x7f }, { ZD_CR29, 0x80 }, { ZD_CR30, 0x4b },
+ { ZD_CR31, 0x60 }, { ZD_CR32, 0x43 }, { ZD_CR33, 0x08 },
+ { ZD_CR34, 0x06 }, { ZD_CR35, 0x0a }, { ZD_CR36, 0x00 },
+ { ZD_CR37, 0x00 }, { ZD_CR38, 0x38 }, { ZD_CR39, 0x0c },
+ { ZD_CR40, 0x84 }, { ZD_CR41, 0x2a }, { ZD_CR42, 0x80 },
+ { ZD_CR43, 0x10 }, { ZD_CR44, 0x12 }, { ZD_CR46, 0xff },
+ { ZD_CR47, 0x1E }, { ZD_CR48, 0x26 }, { ZD_CR49, 0x5b },
+ { ZD_CR64, 0xd0 }, { ZD_CR65, 0x04 }, { ZD_CR66, 0x58 },
+ { ZD_CR67, 0xc9 }, { ZD_CR68, 0x88 }, { ZD_CR69, 0x41 },
+ { ZD_CR70, 0x23 }, { ZD_CR71, 0x10 }, { ZD_CR72, 0xff },
+ { ZD_CR73, 0x32 }, { ZD_CR74, 0x30 }, { ZD_CR75, 0x65 },
+ { ZD_CR76, 0x41 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x30 },
+ { ZD_CR79, 0x68 }, { ZD_CR80, 0x64 }, { ZD_CR81, 0x64 },
+ { ZD_CR82, 0x00 }, { ZD_CR83, 0x00 }, { ZD_CR84, 0x00 },
+ { ZD_CR85, 0x02 }, { ZD_CR86, 0x00 }, { ZD_CR87, 0x00 },
+ { ZD_CR88, 0xff }, { ZD_CR89, 0xfc }, { ZD_CR90, 0x00 },
+ { ZD_CR91, 0x00 }, { ZD_CR92, 0x00 }, { ZD_CR93, 0x08 },
+ { ZD_CR94, 0x00 }, { ZD_CR95, 0x00 }, { ZD_CR96, 0xff },
+ { ZD_CR97, 0xe7 }, { ZD_CR98, 0x00 }, { ZD_CR99, 0x00 },
+ { ZD_CR100, 0x00 }, { ZD_CR101, 0xae }, { ZD_CR102, 0x02 },
+ { ZD_CR103, 0x00 }, { ZD_CR104, 0x03 }, { ZD_CR105, 0x65 },
+ { ZD_CR106, 0x04 }, { ZD_CR107, 0x00 }, { ZD_CR108, 0x0a },
+ { ZD_CR109, 0xaa }, { ZD_CR110, 0xaa }, { ZD_CR111, 0x25 },
+ { ZD_CR112, 0x25 }, { ZD_CR113, 0x00 }, { ZD_CR119, 0x1e },
+ { ZD_CR125, 0x90 }, { ZD_CR126, 0x00 }, { ZD_CR127, 0x00 },
{ },
- { CR5, 0x00 }, { CR6, 0x00 }, { CR7, 0x00 },
- { CR8, 0x00 }, { CR9, 0x20 }, { CR12, 0xf0 },
- { CR20, 0x0e }, { CR21, 0x0e }, { CR27, 0x10 },
- { CR44, 0x33 }, { CR47, 0x1E }, { CR83, 0x24 },
- { CR84, 0x04 }, { CR85, 0x00 }, { CR86, 0x0C },
- { CR87, 0x12 }, { CR88, 0x0C }, { CR89, 0x00 },
- { CR90, 0x10 }, { CR91, 0x08 }, { CR93, 0x00 },
- { CR94, 0x01 }, { CR95, 0x00 }, { CR96, 0x50 },
- { CR97, 0x37 }, { CR98, 0x35 }, { CR101, 0x13 },
- { CR102, 0x27 }, { CR103, 0x27 }, { CR104, 0x18 },
- { CR105, 0x12 }, { CR109, 0x27 }, { CR110, 0x27 },
- { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 },
- { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 },
- { CR117, 0xfc }, { CR118, 0xfa }, { CR120, 0x4f },
- { CR125, 0xaa }, { CR127, 0x03 }, { CR128, 0x14 },
- { CR129, 0x12 }, { CR130, 0x10 }, { CR131, 0x0C },
- { CR136, 0xdf }, { CR137, 0x40 }, { CR138, 0xa0 },
- { CR139, 0xb0 }, { CR140, 0x99 }, { CR141, 0x82 },
- { CR142, 0x54 }, { CR143, 0x1c }, { CR144, 0x6c },
- { CR147, 0x07 }, { CR148, 0x4c }, { CR149, 0x50 },
- { CR150, 0x0e }, { CR151, 0x18 }, { CR160, 0xfe },
- { CR161, 0xee }, { CR162, 0xaa }, { CR163, 0xfa },
- { CR164, 0xfa }, { CR165, 0xea }, { CR166, 0xbe },
- { CR167, 0xbe }, { CR168, 0x6a }, { CR169, 0xba },
- { CR170, 0xba }, { CR171, 0xba },
- /* Note: CR204 must lead the CR203 */
- { CR204, 0x7d },
+ { ZD_CR5, 0x00 }, { ZD_CR6, 0x00 }, { ZD_CR7, 0x00 },
+ { ZD_CR8, 0x00 }, { ZD_CR9, 0x20 }, { ZD_CR12, 0xf0 },
+ { ZD_CR20, 0x0e }, { ZD_CR21, 0x0e }, { ZD_CR27, 0x10 },
+ { ZD_CR44, 0x33 }, { ZD_CR47, 0x1E }, { ZD_CR83, 0x24 },
+ { ZD_CR84, 0x04 }, { ZD_CR85, 0x00 }, { ZD_CR86, 0x0C },
+ { ZD_CR87, 0x12 }, { ZD_CR88, 0x0C }, { ZD_CR89, 0x00 },
+ { ZD_CR90, 0x10 }, { ZD_CR91, 0x08 }, { ZD_CR93, 0x00 },
+ { ZD_CR94, 0x01 }, { ZD_CR95, 0x00 }, { ZD_CR96, 0x50 },
+ { ZD_CR97, 0x37 }, { ZD_CR98, 0x35 }, { ZD_CR101, 0x13 },
+ { ZD_CR102, 0x27 }, { ZD_CR103, 0x27 }, { ZD_CR104, 0x18 },
+ { ZD_CR105, 0x12 }, { ZD_CR109, 0x27 }, { ZD_CR110, 0x27 },
+ { ZD_CR111, 0x27 }, { ZD_CR112, 0x27 }, { ZD_CR113, 0x27 },
+ { ZD_CR114, 0x27 }, { ZD_CR115, 0x26 }, { ZD_CR116, 0x24 },
+ { ZD_CR117, 0xfc }, { ZD_CR118, 0xfa }, { ZD_CR120, 0x4f },
+ { ZD_CR125, 0xaa }, { ZD_CR127, 0x03 }, { ZD_CR128, 0x14 },
+ { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 }, { ZD_CR131, 0x0C },
+ { ZD_CR136, 0xdf }, { ZD_CR137, 0x40 }, { ZD_CR138, 0xa0 },
+ { ZD_CR139, 0xb0 }, { ZD_CR140, 0x99 }, { ZD_CR141, 0x82 },
+ { ZD_CR142, 0x54 }, { ZD_CR143, 0x1c }, { ZD_CR144, 0x6c },
+ { ZD_CR147, 0x07 }, { ZD_CR148, 0x4c }, { ZD_CR149, 0x50 },
+ { ZD_CR150, 0x0e }, { ZD_CR151, 0x18 }, { ZD_CR160, 0xfe },
+ { ZD_CR161, 0xee }, { ZD_CR162, 0xaa }, { ZD_CR163, 0xfa },
+ { ZD_CR164, 0xfa }, { ZD_CR165, 0xea }, { ZD_CR166, 0xbe },
+ { ZD_CR167, 0xbe }, { ZD_CR168, 0x6a }, { ZD_CR169, 0xba },
+ { ZD_CR170, 0xba }, { ZD_CR171, 0xba },
+ /* Note: ZD_CR204 must lead the ZD_CR203 */
+ { ZD_CR204, 0x7d },
{ },
- { CR203, 0x30 },
+ { ZD_CR203, 0x30 },
};
int r, t;
@@ -697,62 +697,62 @@ out:
static int zd1211b_hw_reset_phy(struct zd_chip *chip)
{
static const struct zd_ioreq16 ioreqs[] = {
- { CR0, 0x14 }, { CR1, 0x06 }, { CR2, 0x26 },
- { CR3, 0x38 }, { CR4, 0x80 }, { CR9, 0xe0 },
- { CR10, 0x81 },
- /* power control { { CR11, 1 << 6 }, */
- { CR11, 0x00 },
- { CR12, 0xf0 }, { CR13, 0x8c }, { CR14, 0x80 },
- { CR15, 0x3d }, { CR16, 0x20 }, { CR17, 0x1e },
- { CR18, 0x0a }, { CR19, 0x48 },
- { CR20, 0x10 }, /* Org:0x0E, ComTrend:RalLink AP */
- { CR21, 0x0e }, { CR22, 0x23 }, { CR23, 0x90 },
- { CR24, 0x14 }, { CR25, 0x40 }, { CR26, 0x10 },
- { CR27, 0x10 }, { CR28, 0x7f }, { CR29, 0x80 },
- { CR30, 0x4b }, /* ASIC/FWT, no jointly decoder */
- { CR31, 0x60 }, { CR32, 0x43 }, { CR33, 0x08 },
- { CR34, 0x06 }, { CR35, 0x0a }, { CR36, 0x00 },
- { CR37, 0x00 }, { CR38, 0x38 }, { CR39, 0x0c },
- { CR40, 0x84 }, { CR41, 0x2a }, { CR42, 0x80 },
- { CR43, 0x10 }, { CR44, 0x33 }, { CR46, 0xff },
- { CR47, 0x1E }, { CR48, 0x26 }, { CR49, 0x5b },
- { CR64, 0xd0 }, { CR65, 0x04 }, { CR66, 0x58 },
- { CR67, 0xc9 }, { CR68, 0x88 }, { CR69, 0x41 },
- { CR70, 0x23 }, { CR71, 0x10 }, { CR72, 0xff },
- { CR73, 0x32 }, { CR74, 0x30 }, { CR75, 0x65 },
- { CR76, 0x41 }, { CR77, 0x1b }, { CR78, 0x30 },
- { CR79, 0xf0 }, { CR80, 0x64 }, { CR81, 0x64 },
- { CR82, 0x00 }, { CR83, 0x24 }, { CR84, 0x04 },
- { CR85, 0x00 }, { CR86, 0x0c }, { CR87, 0x12 },
- { CR88, 0x0c }, { CR89, 0x00 }, { CR90, 0x58 },
- { CR91, 0x04 }, { CR92, 0x00 }, { CR93, 0x00 },
- { CR94, 0x01 },
- { CR95, 0x20 }, /* ZD1211B */
- { CR96, 0x50 }, { CR97, 0x37 }, { CR98, 0x35 },
- { CR99, 0x00 }, { CR100, 0x01 }, { CR101, 0x13 },
- { CR102, 0x27 }, { CR103, 0x27 }, { CR104, 0x18 },
- { CR105, 0x12 }, { CR106, 0x04 }, { CR107, 0x00 },
- { CR108, 0x0a }, { CR109, 0x27 }, { CR110, 0x27 },
- { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 },
- { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 },
- { CR117, 0xfc }, { CR118, 0xfa }, { CR119, 0x1e },
- { CR125, 0x90 }, { CR126, 0x00 }, { CR127, 0x00 },
- { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
- { CR131, 0x0c }, { CR136, 0xdf }, { CR137, 0xa0 },
- { CR138, 0xa8 }, { CR139, 0xb4 }, { CR140, 0x98 },
- { CR141, 0x82 }, { CR142, 0x53 }, { CR143, 0x1c },
- { CR144, 0x6c }, { CR147, 0x07 }, { CR148, 0x40 },
- { CR149, 0x40 }, /* Org:0x50 ComTrend:RalLink AP */
- { CR150, 0x14 }, /* Org:0x0E ComTrend:RalLink AP */
- { CR151, 0x18 }, { CR159, 0x70 }, { CR160, 0xfe },
- { CR161, 0xee }, { CR162, 0xaa }, { CR163, 0xfa },
- { CR164, 0xfa }, { CR165, 0xea }, { CR166, 0xbe },
- { CR167, 0xbe }, { CR168, 0x6a }, { CR169, 0xba },
- { CR170, 0xba }, { CR171, 0xba },
- /* Note: CR204 must lead the CR203 */
- { CR204, 0x7d },
+ { ZD_CR0, 0x14 }, { ZD_CR1, 0x06 }, { ZD_CR2, 0x26 },
+ { ZD_CR3, 0x38 }, { ZD_CR4, 0x80 }, { ZD_CR9, 0xe0 },
+ { ZD_CR10, 0x81 },
+ /* power control { { ZD_CR11, 1 << 6 }, */
+ { ZD_CR11, 0x00 },
+ { ZD_CR12, 0xf0 }, { ZD_CR13, 0x8c }, { ZD_CR14, 0x80 },
+ { ZD_CR15, 0x3d }, { ZD_CR16, 0x20 }, { ZD_CR17, 0x1e },
+ { ZD_CR18, 0x0a }, { ZD_CR19, 0x48 },
+ { ZD_CR20, 0x10 }, /* Org:0x0E, ComTrend:RalLink AP */
+ { ZD_CR21, 0x0e }, { ZD_CR22, 0x23 }, { ZD_CR23, 0x90 },
+ { ZD_CR24, 0x14 }, { ZD_CR25, 0x40 }, { ZD_CR26, 0x10 },
+ { ZD_CR27, 0x10 }, { ZD_CR28, 0x7f }, { ZD_CR29, 0x80 },
+ { ZD_CR30, 0x4b }, /* ASIC/FWT, no jointly decoder */
+ { ZD_CR31, 0x60 }, { ZD_CR32, 0x43 }, { ZD_CR33, 0x08 },
+ { ZD_CR34, 0x06 }, { ZD_CR35, 0x0a }, { ZD_CR36, 0x00 },
+ { ZD_CR37, 0x00 }, { ZD_CR38, 0x38 }, { ZD_CR39, 0x0c },
+ { ZD_CR40, 0x84 }, { ZD_CR41, 0x2a }, { ZD_CR42, 0x80 },
+ { ZD_CR43, 0x10 }, { ZD_CR44, 0x33 }, { ZD_CR46, 0xff },
+ { ZD_CR47, 0x1E }, { ZD_CR48, 0x26 }, { ZD_CR49, 0x5b },
+ { ZD_CR64, 0xd0 }, { ZD_CR65, 0x04 }, { ZD_CR66, 0x58 },
+ { ZD_CR67, 0xc9 }, { ZD_CR68, 0x88 }, { ZD_CR69, 0x41 },
+ { ZD_CR70, 0x23 }, { ZD_CR71, 0x10 }, { ZD_CR72, 0xff },
+ { ZD_CR73, 0x32 }, { ZD_CR74, 0x30 }, { ZD_CR75, 0x65 },
+ { ZD_CR76, 0x41 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x30 },
+ { ZD_CR79, 0xf0 }, { ZD_CR80, 0x64 }, { ZD_CR81, 0x64 },
+ { ZD_CR82, 0x00 }, { ZD_CR83, 0x24 }, { ZD_CR84, 0x04 },
+ { ZD_CR85, 0x00 }, { ZD_CR86, 0x0c }, { ZD_CR87, 0x12 },
+ { ZD_CR88, 0x0c }, { ZD_CR89, 0x00 }, { ZD_CR90, 0x58 },
+ { ZD_CR91, 0x04 }, { ZD_CR92, 0x00 }, { ZD_CR93, 0x00 },
+ { ZD_CR94, 0x01 },
+ { ZD_CR95, 0x20 }, /* ZD1211B */
+ { ZD_CR96, 0x50 }, { ZD_CR97, 0x37 }, { ZD_CR98, 0x35 },
+ { ZD_CR99, 0x00 }, { ZD_CR100, 0x01 }, { ZD_CR101, 0x13 },
+ { ZD_CR102, 0x27 }, { ZD_CR103, 0x27 }, { ZD_CR104, 0x18 },
+ { ZD_CR105, 0x12 }, { ZD_CR106, 0x04 }, { ZD_CR107, 0x00 },
+ { ZD_CR108, 0x0a }, { ZD_CR109, 0x27 }, { ZD_CR110, 0x27 },
+ { ZD_CR111, 0x27 }, { ZD_CR112, 0x27 }, { ZD_CR113, 0x27 },
+ { ZD_CR114, 0x27 }, { ZD_CR115, 0x26 }, { ZD_CR116, 0x24 },
+ { ZD_CR117, 0xfc }, { ZD_CR118, 0xfa }, { ZD_CR119, 0x1e },
+ { ZD_CR125, 0x90 }, { ZD_CR126, 0x00 }, { ZD_CR127, 0x00 },
+ { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 },
+ { ZD_CR131, 0x0c }, { ZD_CR136, 0xdf }, { ZD_CR137, 0xa0 },
+ { ZD_CR138, 0xa8 }, { ZD_CR139, 0xb4 }, { ZD_CR140, 0x98 },
+ { ZD_CR141, 0x82 }, { ZD_CR142, 0x53 }, { ZD_CR143, 0x1c },
+ { ZD_CR144, 0x6c }, { ZD_CR147, 0x07 }, { ZD_CR148, 0x40 },
+ { ZD_CR149, 0x40 }, /* Org:0x50 ComTrend:RalLink AP */
+ { ZD_CR150, 0x14 }, /* Org:0x0E ComTrend:RalLink AP */
+ { ZD_CR151, 0x18 }, { ZD_CR159, 0x70 }, { ZD_CR160, 0xfe },
+ { ZD_CR161, 0xee }, { ZD_CR162, 0xaa }, { ZD_CR163, 0xfa },
+ { ZD_CR164, 0xfa }, { ZD_CR165, 0xea }, { ZD_CR166, 0xbe },
+ { ZD_CR167, 0xbe }, { ZD_CR168, 0x6a }, { ZD_CR169, 0xba },
+ { ZD_CR170, 0xba }, { ZD_CR171, 0xba },
+ /* Note: ZD_CR204 must lead the ZD_CR203 */
+ { ZD_CR204, 0x7d },
{},
- { CR203, 0x30 },
+ { ZD_CR203, 0x30 },
};
int r, t;
@@ -1200,24 +1200,24 @@ out:
static int update_pwr_int(struct zd_chip *chip, u8 channel)
{
u8 value = chip->pwr_int_values[channel - 1];
- return zd_iowrite16_locked(chip, value, CR31);
+ return zd_iowrite16_locked(chip, value, ZD_CR31);
}
static int update_pwr_cal(struct zd_chip *chip, u8 channel)
{
u8 value = chip->pwr_cal_values[channel-1];
- return zd_iowrite16_locked(chip, value, CR68);
+ return zd_iowrite16_locked(chip, value, ZD_CR68);
}
static int update_ofdm_cal(struct zd_chip *chip, u8 channel)
{
struct zd_ioreq16 ioreqs[3];
- ioreqs[0].addr = CR67;
+ ioreqs[0].addr = ZD_CR67;
ioreqs[0].value = chip->ofdm_cal_values[OFDM_36M_INDEX][channel-1];
- ioreqs[1].addr = CR66;
+ ioreqs[1].addr = ZD_CR66;
ioreqs[1].value = chip->ofdm_cal_values[OFDM_48M_INDEX][channel-1];
- ioreqs[2].addr = CR65;
+ ioreqs[2].addr = ZD_CR65;
ioreqs[2].value = chip->ofdm_cal_values[OFDM_54M_INDEX][channel-1];
return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
@@ -1236,9 +1236,9 @@ static int update_channel_integration_and_calibration(struct zd_chip *chip,
return r;
if (zd_chip_is_zd1211b(chip)) {
static const struct zd_ioreq16 ioreqs[] = {
- { CR69, 0x28 },
+ { ZD_CR69, 0x28 },
{},
- { CR69, 0x2a },
+ { ZD_CR69, 0x2a },
};
r = update_ofdm_cal(chip, channel);
@@ -1269,7 +1269,7 @@ static int patch_cck_gain(struct zd_chip *chip)
if (r)
return r;
dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value & 0xff);
- return zd_iowrite16_locked(chip, value & 0xff, CR47);
+ return zd_iowrite16_locked(chip, value & 0xff, ZD_CR47);
}
int zd_chip_set_channel(struct zd_chip *chip, u8 channel)
@@ -1505,9 +1505,9 @@ int zd_rfwritev_locked(struct zd_chip *chip,
int zd_rfwrite_cr_locked(struct zd_chip *chip, u32 value)
{
const struct zd_ioreq16 ioreqs[] = {
- { CR244, (value >> 16) & 0xff },
- { CR243, (value >> 8) & 0xff },
- { CR242, value & 0xff },
+ { ZD_CR244, (value >> 16) & 0xff },
+ { ZD_CR243, (value >> 8) & 0xff },
+ { ZD_CR242, value & 0xff },
};
ZD_ASSERT(mutex_is_locked(&chip->mutex));
return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index 14e4402a6111..4be7c3b5b265 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -61,277 +61,288 @@ enum {
#define FWRAW_DATA(offset) ((zd_addr_t)(FW_START + (offset)))
/* 8-bit hardware registers */
-#define CR0 CTL_REG(0x0000)
-#define CR1 CTL_REG(0x0004)
-#define CR2 CTL_REG(0x0008)
-#define CR3 CTL_REG(0x000C)
+#define ZD_CR0 CTL_REG(0x0000)
+#define ZD_CR1 CTL_REG(0x0004)
+#define ZD_CR2 CTL_REG(0x0008)
+#define ZD_CR3 CTL_REG(0x000C)
-#define CR5 CTL_REG(0x0010)
+#define ZD_CR5 CTL_REG(0x0010)
/* bit 5: if set short preamble used
* bit 6: filter band - Japan channel 14 on, else off
*/
-#define CR6 CTL_REG(0x0014)
-#define CR7 CTL_REG(0x0018)
-#define CR8 CTL_REG(0x001C)
+#define ZD_CR6 CTL_REG(0x0014)
+#define ZD_CR7 CTL_REG(0x0018)
+#define ZD_CR8 CTL_REG(0x001C)
-#define CR4 CTL_REG(0x0020)
+#define ZD_CR4 CTL_REG(0x0020)
-#define CR9 CTL_REG(0x0024)
-/* bit 2: antenna switch (together with CR10) */
-#define CR10 CTL_REG(0x0028)
-/* bit 1: antenna switch (together with CR9)
- * RF2959 controls with CR11 radion on and off
+#define ZD_CR9 CTL_REG(0x0024)
+/* bit 2: antenna switch (together with ZD_CR10) */
+#define ZD_CR10 CTL_REG(0x0028)
+/* bit 1: antenna switch (together with ZD_CR9)
+ * RF2959 controls with ZD_CR11 radion on and off
*/
-#define CR11 CTL_REG(0x002C)
+#define ZD_CR11 CTL_REG(0x002C)
/* bit 6: TX power control for OFDM
- * RF2959 controls with CR10 radio on and off
+ * RF2959 controls with ZD_CR10 radio on and off
*/
-#define CR12 CTL_REG(0x0030)
-#define CR13 CTL_REG(0x0034)
-#define CR14 CTL_REG(0x0038)
-#define CR15 CTL_REG(0x003C)
-#define CR16 CTL_REG(0x0040)
-#define CR17 CTL_REG(0x0044)
-#define CR18 CTL_REG(0x0048)
-#define CR19 CTL_REG(0x004C)
-#define CR20 CTL_REG(0x0050)
-#define CR21 CTL_REG(0x0054)
-#define CR22 CTL_REG(0x0058)
-#define CR23 CTL_REG(0x005C)
-#define CR24 CTL_REG(0x0060) /* CCA threshold */
-#define CR25 CTL_REG(0x0064)
-#define CR26 CTL_REG(0x0068)
-#define CR27 CTL_REG(0x006C)
-#define CR28 CTL_REG(0x0070)
-#define CR29 CTL_REG(0x0074)
-#define CR30 CTL_REG(0x0078)
-#define CR31 CTL_REG(0x007C) /* TX power control for RF in CCK mode */
-#define CR32 CTL_REG(0x0080)
-#define CR33 CTL_REG(0x0084)
-#define CR34 CTL_REG(0x0088)
-#define CR35 CTL_REG(0x008C)
-#define CR36 CTL_REG(0x0090)
-#define CR37 CTL_REG(0x0094)
-#define CR38 CTL_REG(0x0098)
-#define CR39 CTL_REG(0x009C)
-#define CR40 CTL_REG(0x00A0)
-#define CR41 CTL_REG(0x00A4)
-#define CR42 CTL_REG(0x00A8)
-#define CR43 CTL_REG(0x00AC)
-#define CR44 CTL_REG(0x00B0)
-#define CR45 CTL_REG(0x00B4)
-#define CR46 CTL_REG(0x00B8)
-#define CR47 CTL_REG(0x00BC) /* CCK baseband gain
- * (patch value might be in EEPROM)
- */
-#define CR48 CTL_REG(0x00C0)
-#define CR49 CTL_REG(0x00C4)
-#define CR50 CTL_REG(0x00C8)
-#define CR51 CTL_REG(0x00CC) /* TX power control for RF in 6-36M modes */
-#define CR52 CTL_REG(0x00D0) /* TX power control for RF in 48M mode */
-#define CR53 CTL_REG(0x00D4) /* TX power control for RF in 54M mode */
-#define CR54 CTL_REG(0x00D8)
-#define CR55 CTL_REG(0x00DC)
-#define CR56 CTL_REG(0x00E0)
-#define CR57 CTL_REG(0x00E4)
-#define CR58 CTL_REG(0x00E8)
-#define CR59 CTL_REG(0x00EC)
-#define CR60 CTL_REG(0x00F0)
-#define CR61 CTL_REG(0x00F4)
-#define CR62 CTL_REG(0x00F8)
-#define CR63 CTL_REG(0x00FC)
-#define CR64 CTL_REG(0x0100)
-#define CR65 CTL_REG(0x0104) /* OFDM 54M calibration */
-#define CR66 CTL_REG(0x0108) /* OFDM 48M calibration */
-#define CR67 CTL_REG(0x010C) /* OFDM 36M calibration */
-#define CR68 CTL_REG(0x0110) /* CCK calibration */
-#define CR69 CTL_REG(0x0114)
-#define CR70 CTL_REG(0x0118)
-#define CR71 CTL_REG(0x011C)
-#define CR72 CTL_REG(0x0120)
-#define CR73 CTL_REG(0x0124)
-#define CR74 CTL_REG(0x0128)
-#define CR75 CTL_REG(0x012C)
-#define CR76 CTL_REG(0x0130)
-#define CR77 CTL_REG(0x0134)
-#define CR78 CTL_REG(0x0138)
-#define CR79 CTL_REG(0x013C)
-#define CR80 CTL_REG(0x0140)
-#define CR81 CTL_REG(0x0144)
-#define CR82 CTL_REG(0x0148)
-#define CR83 CTL_REG(0x014C)
-#define CR84 CTL_REG(0x0150)
-#define CR85 CTL_REG(0x0154)
-#define CR86 CTL_REG(0x0158)
-#define CR87 CTL_REG(0x015C)
-#define CR88 CTL_REG(0x0160)
-#define CR89 CTL_REG(0x0164)
-#define CR90 CTL_REG(0x0168)
-#define CR91 CTL_REG(0x016C)
-#define CR92 CTL_REG(0x0170)
-#define CR93 CTL_REG(0x0174)
-#define CR94 CTL_REG(0x0178)
-#define CR95 CTL_REG(0x017C)
-#define CR96 CTL_REG(0x0180)
-#define CR97 CTL_REG(0x0184)
-#define CR98 CTL_REG(0x0188)
-#define CR99 CTL_REG(0x018C)
-#define CR100 CTL_REG(0x0190)
-#define CR101 CTL_REG(0x0194)
-#define CR102 CTL_REG(0x0198)
-#define CR103 CTL_REG(0x019C)
-#define CR104 CTL_REG(0x01A0)
-#define CR105 CTL_REG(0x01A4)
-#define CR106 CTL_REG(0x01A8)
-#define CR107 CTL_REG(0x01AC)
-#define CR108 CTL_REG(0x01B0)
-#define CR109 CTL_REG(0x01B4)
-#define CR110 CTL_REG(0x01B8)
-#define CR111 CTL_REG(0x01BC)
-#define CR112 CTL_REG(0x01C0)
-#define CR113 CTL_REG(0x01C4)
-#define CR114 CTL_REG(0x01C8)
-#define CR115 CTL_REG(0x01CC)
-#define CR116 CTL_REG(0x01D0)
-#define CR117 CTL_REG(0x01D4)
-#define CR118 CTL_REG(0x01D8)
-#define CR119 CTL_REG(0x01DC)
-#define CR120 CTL_REG(0x01E0)
-#define CR121 CTL_REG(0x01E4)
-#define CR122 CTL_REG(0x01E8)
-#define CR123 CTL_REG(0x01EC)
-#define CR124 CTL_REG(0x01F0)
-#define CR125 CTL_REG(0x01F4)
-#define CR126 CTL_REG(0x01F8)
-#define CR127 CTL_REG(0x01FC)
-#define CR128 CTL_REG(0x0200)
-#define CR129 CTL_REG(0x0204)
-#define CR130 CTL_REG(0x0208)
-#define CR131 CTL_REG(0x020C)
-#define CR132 CTL_REG(0x0210)
-#define CR133 CTL_REG(0x0214)
-#define CR134 CTL_REG(0x0218)
-#define CR135 CTL_REG(0x021C)
-#define CR136 CTL_REG(0x0220)
-#define CR137 CTL_REG(0x0224)
-#define CR138 CTL_REG(0x0228)
-#define CR139 CTL_REG(0x022C)
-#define CR140 CTL_REG(0x0230)
-#define CR141 CTL_REG(0x0234)
-#define CR142 CTL_REG(0x0238)
-#define CR143 CTL_REG(0x023C)
-#define CR144 CTL_REG(0x0240)
-#define CR145 CTL_REG(0x0244)
-#define CR146 CTL_REG(0x0248)
-#define CR147 CTL_REG(0x024C)
-#define CR148 CTL_REG(0x0250)
-#define CR149 CTL_REG(0x0254)
-#define CR150 CTL_REG(0x0258)
-#define CR151 CTL_REG(0x025C)
-#define CR152 CTL_REG(0x0260)
-#define CR153 CTL_REG(0x0264)
-#define CR154 CTL_REG(0x0268)
-#define CR155 CTL_REG(0x026C)
-#define CR156 CTL_REG(0x0270)
-#define CR157 CTL_REG(0x0274)
-#define CR158 CTL_REG(0x0278)
-#define CR159 CTL_REG(0x027C)
-#define CR160 CTL_REG(0x0280)
-#define CR161 CTL_REG(0x0284)
-#define CR162 CTL_REG(0x0288)
-#define CR163 CTL_REG(0x028C)
-#define CR164 CTL_REG(0x0290)
-#define CR165 CTL_REG(0x0294)
-#define CR166 CTL_REG(0x0298)
-#define CR167 CTL_REG(0x029C)
-#define CR168 CTL_REG(0x02A0)
-#define CR169 CTL_REG(0x02A4)
-#define CR170 CTL_REG(0x02A8)
-#define CR171 CTL_REG(0x02AC)
-#define CR172 CTL_REG(0x02B0)
-#define CR173 CTL_REG(0x02B4)
-#define CR174 CTL_REG(0x02B8)
-#define CR175 CTL_REG(0x02BC)
-#define CR176 CTL_REG(0x02C0)
-#define CR177 CTL_REG(0x02C4)
-#define CR178 CTL_REG(0x02C8)
-#define CR179 CTL_REG(0x02CC)
-#define CR180 CTL_REG(0x02D0)
-#define CR181 CTL_REG(0x02D4)
-#define CR182 CTL_REG(0x02D8)
-#define CR183 CTL_REG(0x02DC)
-#define CR184 CTL_REG(0x02E0)
-#define CR185 CTL_REG(0x02E4)
-#define CR186 CTL_REG(0x02E8)
-#define CR187 CTL_REG(0x02EC)
-#define CR188 CTL_REG(0x02F0)
-#define CR189 CTL_REG(0x02F4)
-#define CR190 CTL_REG(0x02F8)
-#define CR191 CTL_REG(0x02FC)
-#define CR192 CTL_REG(0x0300)
-#define CR193 CTL_REG(0x0304)
-#define CR194 CTL_REG(0x0308)
-#define CR195 CTL_REG(0x030C)
-#define CR196 CTL_REG(0x0310)
-#define CR197 CTL_REG(0x0314)
-#define CR198 CTL_REG(0x0318)
-#define CR199 CTL_REG(0x031C)
-#define CR200 CTL_REG(0x0320)
-#define CR201 CTL_REG(0x0324)
-#define CR202 CTL_REG(0x0328)
-#define CR203 CTL_REG(0x032C) /* I2C bus template value & flash control */
-#define CR204 CTL_REG(0x0330)
-#define CR205 CTL_REG(0x0334)
-#define CR206 CTL_REG(0x0338)
-#define CR207 CTL_REG(0x033C)
-#define CR208 CTL_REG(0x0340)
-#define CR209 CTL_REG(0x0344)
-#define CR210 CTL_REG(0x0348)
-#define CR211 CTL_REG(0x034C)
-#define CR212 CTL_REG(0x0350)
-#define CR213 CTL_REG(0x0354)
-#define CR214 CTL_REG(0x0358)
-#define CR215 CTL_REG(0x035C)
-#define CR216 CTL_REG(0x0360)
-#define CR217 CTL_REG(0x0364)
-#define CR218 CTL_REG(0x0368)
-#define CR219 CTL_REG(0x036C)
-#define CR220 CTL_REG(0x0370)
-#define CR221 CTL_REG(0x0374)
-#define CR222 CTL_REG(0x0378)
-#define CR223 CTL_REG(0x037C)
-#define CR224 CTL_REG(0x0380)
-#define CR225 CTL_REG(0x0384)
-#define CR226 CTL_REG(0x0388)
-#define CR227 CTL_REG(0x038C)
-#define CR228 CTL_REG(0x0390)
-#define CR229 CTL_REG(0x0394)
-#define CR230 CTL_REG(0x0398)
-#define CR231 CTL_REG(0x039C)
-#define CR232 CTL_REG(0x03A0)
-#define CR233 CTL_REG(0x03A4)
-#define CR234 CTL_REG(0x03A8)
-#define CR235 CTL_REG(0x03AC)
-#define CR236 CTL_REG(0x03B0)
-
-#define CR240 CTL_REG(0x03C0)
-/* bit 7: host-controlled RF register writes
- * CR241-CR245: for hardware controlled writing of RF bits, not needed for
- * USB
+#define ZD_CR12 CTL_REG(0x0030)
+#define ZD_CR13 CTL_REG(0x0034)
+#define ZD_CR14 CTL_REG(0x0038)
+#define ZD_CR15 CTL_REG(0x003C)
+#define ZD_CR16 CTL_REG(0x0040)
+#define ZD_CR17 CTL_REG(0x0044)
+#define ZD_CR18 CTL_REG(0x0048)
+#define ZD_CR19 CTL_REG(0x004C)
+#define ZD_CR20 CTL_REG(0x0050)
+#define ZD_CR21 CTL_REG(0x0054)
+#define ZD_CR22 CTL_REG(0x0058)
+#define ZD_CR23 CTL_REG(0x005C)
+#define ZD_CR24 CTL_REG(0x0060) /* CCA threshold */
+#define ZD_CR25 CTL_REG(0x0064)
+#define ZD_CR26 CTL_REG(0x0068)
+#define ZD_CR27 CTL_REG(0x006C)
+#define ZD_CR28 CTL_REG(0x0070)
+#define ZD_CR29 CTL_REG(0x0074)
+#define ZD_CR30 CTL_REG(0x0078)
+#define ZD_CR31 CTL_REG(0x007C) /* TX power control for RF in
+ * CCK mode
+ */
+#define ZD_CR32 CTL_REG(0x0080)
+#define ZD_CR33 CTL_REG(0x0084)
+#define ZD_CR34 CTL_REG(0x0088)
+#define ZD_CR35 CTL_REG(0x008C)
+#define ZD_CR36 CTL_REG(0x0090)
+#define ZD_CR37 CTL_REG(0x0094)
+#define ZD_CR38 CTL_REG(0x0098)
+#define ZD_CR39 CTL_REG(0x009C)
+#define ZD_CR40 CTL_REG(0x00A0)
+#define ZD_CR41 CTL_REG(0x00A4)
+#define ZD_CR42 CTL_REG(0x00A8)
+#define ZD_CR43 CTL_REG(0x00AC)
+#define ZD_CR44 CTL_REG(0x00B0)
+#define ZD_CR45 CTL_REG(0x00B4)
+#define ZD_CR46 CTL_REG(0x00B8)
+#define ZD_CR47 CTL_REG(0x00BC) /* CCK baseband gain
+ * (patch value might be in EEPROM)
+ */
+#define ZD_CR48 CTL_REG(0x00C0)
+#define ZD_CR49 CTL_REG(0x00C4)
+#define ZD_CR50 CTL_REG(0x00C8)
+#define ZD_CR51 CTL_REG(0x00CC) /* TX power control for RF in
+ * 6-36M modes
+ */
+#define ZD_CR52 CTL_REG(0x00D0) /* TX power control for RF in
+ * 48M mode
+ */
+#define ZD_CR53 CTL_REG(0x00D4) /* TX power control for RF in
+ * 54M mode
+ */
+#define ZD_CR54 CTL_REG(0x00D8)
+#define ZD_CR55 CTL_REG(0x00DC)
+#define ZD_CR56 CTL_REG(0x00E0)
+#define ZD_CR57 CTL_REG(0x00E4)
+#define ZD_CR58 CTL_REG(0x00E8)
+#define ZD_CR59 CTL_REG(0x00EC)
+#define ZD_CR60 CTL_REG(0x00F0)
+#define ZD_CR61 CTL_REG(0x00F4)
+#define ZD_CR62 CTL_REG(0x00F8)
+#define ZD_CR63 CTL_REG(0x00FC)
+#define ZD_CR64 CTL_REG(0x0100)
+#define ZD_CR65 CTL_REG(0x0104) /* OFDM 54M calibration */
+#define ZD_CR66 CTL_REG(0x0108) /* OFDM 48M calibration */
+#define ZD_CR67 CTL_REG(0x010C) /* OFDM 36M calibration */
+#define ZD_CR68 CTL_REG(0x0110) /* CCK calibration */
+#define ZD_CR69 CTL_REG(0x0114)
+#define ZD_CR70 CTL_REG(0x0118)
+#define ZD_CR71 CTL_REG(0x011C)
+#define ZD_CR72 CTL_REG(0x0120)
+#define ZD_CR73 CTL_REG(0x0124)
+#define ZD_CR74 CTL_REG(0x0128)
+#define ZD_CR75 CTL_REG(0x012C)
+#define ZD_CR76 CTL_REG(0x0130)
+#define ZD_CR77 CTL_REG(0x0134)
+#define ZD_CR78 CTL_REG(0x0138)
+#define ZD_CR79 CTL_REG(0x013C)
+#define ZD_CR80 CTL_REG(0x0140)
+#define ZD_CR81 CTL_REG(0x0144)
+#define ZD_CR82 CTL_REG(0x0148)
+#define ZD_CR83 CTL_REG(0x014C)
+#define ZD_CR84 CTL_REG(0x0150)
+#define ZD_CR85 CTL_REG(0x0154)
+#define ZD_CR86 CTL_REG(0x0158)
+#define ZD_CR87 CTL_REG(0x015C)
+#define ZD_CR88 CTL_REG(0x0160)
+#define ZD_CR89 CTL_REG(0x0164)
+#define ZD_CR90 CTL_REG(0x0168)
+#define ZD_CR91 CTL_REG(0x016C)
+#define ZD_CR92 CTL_REG(0x0170)
+#define ZD_CR93 CTL_REG(0x0174)
+#define ZD_CR94 CTL_REG(0x0178)
+#define ZD_CR95 CTL_REG(0x017C)
+#define ZD_CR96 CTL_REG(0x0180)
+#define ZD_CR97 CTL_REG(0x0184)
+#define ZD_CR98 CTL_REG(0x0188)
+#define ZD_CR99 CTL_REG(0x018C)
+#define ZD_CR100 CTL_REG(0x0190)
+#define ZD_CR101 CTL_REG(0x0194)
+#define ZD_CR102 CTL_REG(0x0198)
+#define ZD_CR103 CTL_REG(0x019C)
+#define ZD_CR104 CTL_REG(0x01A0)
+#define ZD_CR105 CTL_REG(0x01A4)
+#define ZD_CR106 CTL_REG(0x01A8)
+#define ZD_CR107 CTL_REG(0x01AC)
+#define ZD_CR108 CTL_REG(0x01B0)
+#define ZD_CR109 CTL_REG(0x01B4)
+#define ZD_CR110 CTL_REG(0x01B8)
+#define ZD_CR111 CTL_REG(0x01BC)
+#define ZD_CR112 CTL_REG(0x01C0)
+#define ZD_CR113 CTL_REG(0x01C4)
+#define ZD_CR114 CTL_REG(0x01C8)
+#define ZD_CR115 CTL_REG(0x01CC)
+#define ZD_CR116 CTL_REG(0x01D0)
+#define ZD_CR117 CTL_REG(0x01D4)
+#define ZD_CR118 CTL_REG(0x01D8)
+#define ZD_CR119 CTL_REG(0x01DC)
+#define ZD_CR120 CTL_REG(0x01E0)
+#define ZD_CR121 CTL_REG(0x01E4)
+#define ZD_CR122 CTL_REG(0x01E8)
+#define ZD_CR123 CTL_REG(0x01EC)
+#define ZD_CR124 CTL_REG(0x01F0)
+#define ZD_CR125 CTL_REG(0x01F4)
+#define ZD_CR126 CTL_REG(0x01F8)
+#define ZD_CR127 CTL_REG(0x01FC)
+#define ZD_CR128 CTL_REG(0x0200)
+#define ZD_CR129 CTL_REG(0x0204)
+#define ZD_CR130 CTL_REG(0x0208)
+#define ZD_CR131 CTL_REG(0x020C)
+#define ZD_CR132 CTL_REG(0x0210)
+#define ZD_CR133 CTL_REG(0x0214)
+#define ZD_CR134 CTL_REG(0x0218)
+#define ZD_CR135 CTL_REG(0x021C)
+#define ZD_CR136 CTL_REG(0x0220)
+#define ZD_CR137 CTL_REG(0x0224)
+#define ZD_CR138 CTL_REG(0x0228)
+#define ZD_CR139 CTL_REG(0x022C)
+#define ZD_CR140 CTL_REG(0x0230)
+#define ZD_CR141 CTL_REG(0x0234)
+#define ZD_CR142 CTL_REG(0x0238)
+#define ZD_CR143 CTL_REG(0x023C)
+#define ZD_CR144 CTL_REG(0x0240)
+#define ZD_CR145 CTL_REG(0x0244)
+#define ZD_CR146 CTL_REG(0x0248)
+#define ZD_CR147 CTL_REG(0x024C)
+#define ZD_CR148 CTL_REG(0x0250)
+#define ZD_CR149 CTL_REG(0x0254)
+#define ZD_CR150 CTL_REG(0x0258)
+#define ZD_CR151 CTL_REG(0x025C)
+#define ZD_CR152 CTL_REG(0x0260)
+#define ZD_CR153 CTL_REG(0x0264)
+#define ZD_CR154 CTL_REG(0x0268)
+#define ZD_CR155 CTL_REG(0x026C)
+#define ZD_CR156 CTL_REG(0x0270)
+#define ZD_CR157 CTL_REG(0x0274)
+#define ZD_CR158 CTL_REG(0x0278)
+#define ZD_CR159 CTL_REG(0x027C)
+#define ZD_CR160 CTL_REG(0x0280)
+#define ZD_CR161 CTL_REG(0x0284)
+#define ZD_CR162 CTL_REG(0x0288)
+#define ZD_CR163 CTL_REG(0x028C)
+#define ZD_CR164 CTL_REG(0x0290)
+#define ZD_CR165 CTL_REG(0x0294)
+#define ZD_CR166 CTL_REG(0x0298)
+#define ZD_CR167 CTL_REG(0x029C)
+#define ZD_CR168 CTL_REG(0x02A0)
+#define ZD_CR169 CTL_REG(0x02A4)
+#define ZD_CR170 CTL_REG(0x02A8)
+#define ZD_CR171 CTL_REG(0x02AC)
+#define ZD_CR172 CTL_REG(0x02B0)
+#define ZD_CR173 CTL_REG(0x02B4)
+#define ZD_CR174 CTL_REG(0x02B8)
+#define ZD_CR175 CTL_REG(0x02BC)
+#define ZD_CR176 CTL_REG(0x02C0)
+#define ZD_CR177 CTL_REG(0x02C4)
+#define ZD_CR178 CTL_REG(0x02C8)
+#define ZD_CR179 CTL_REG(0x02CC)
+#define ZD_CR180 CTL_REG(0x02D0)
+#define ZD_CR181 CTL_REG(0x02D4)
+#define ZD_CR182 CTL_REG(0x02D8)
+#define ZD_CR183 CTL_REG(0x02DC)
+#define ZD_CR184 CTL_REG(0x02E0)
+#define ZD_CR185 CTL_REG(0x02E4)
+#define ZD_CR186 CTL_REG(0x02E8)
+#define ZD_CR187 CTL_REG(0x02EC)
+#define ZD_CR188 CTL_REG(0x02F0)
+#define ZD_CR189 CTL_REG(0x02F4)
+#define ZD_CR190 CTL_REG(0x02F8)
+#define ZD_CR191 CTL_REG(0x02FC)
+#define ZD_CR192 CTL_REG(0x0300)
+#define ZD_CR193 CTL_REG(0x0304)
+#define ZD_CR194 CTL_REG(0x0308)
+#define ZD_CR195 CTL_REG(0x030C)
+#define ZD_CR196 CTL_REG(0x0310)
+#define ZD_CR197 CTL_REG(0x0314)
+#define ZD_CR198 CTL_REG(0x0318)
+#define ZD_CR199 CTL_REG(0x031C)
+#define ZD_CR200 CTL_REG(0x0320)
+#define ZD_CR201 CTL_REG(0x0324)
+#define ZD_CR202 CTL_REG(0x0328)
+#define ZD_CR203 CTL_REG(0x032C) /* I2C bus template value & flash
+ * control
+ */
+#define ZD_CR204 CTL_REG(0x0330)
+#define ZD_CR205 CTL_REG(0x0334)
+#define ZD_CR206 CTL_REG(0x0338)
+#define ZD_CR207 CTL_REG(0x033C)
+#define ZD_CR208 CTL_REG(0x0340)
+#define ZD_CR209 CTL_REG(0x0344)
+#define ZD_CR210 CTL_REG(0x0348)
+#define ZD_CR211 CTL_REG(0x034C)
+#define ZD_CR212 CTL_REG(0x0350)
+#define ZD_CR213 CTL_REG(0x0354)
+#define ZD_CR214 CTL_REG(0x0358)
+#define ZD_CR215 CTL_REG(0x035C)
+#define ZD_CR216 CTL_REG(0x0360)
+#define ZD_CR217 CTL_REG(0x0364)
+#define ZD_CR218 CTL_REG(0x0368)
+#define ZD_CR219 CTL_REG(0x036C)
+#define ZD_CR220 CTL_REG(0x0370)
+#define ZD_CR221 CTL_REG(0x0374)
+#define ZD_CR222 CTL_REG(0x0378)
+#define ZD_CR223 CTL_REG(0x037C)
+#define ZD_CR224 CTL_REG(0x0380)
+#define ZD_CR225 CTL_REG(0x0384)
+#define ZD_CR226 CTL_REG(0x0388)
+#define ZD_CR227 CTL_REG(0x038C)
+#define ZD_CR228 CTL_REG(0x0390)
+#define ZD_CR229 CTL_REG(0x0394)
+#define ZD_CR230 CTL_REG(0x0398)
+#define ZD_CR231 CTL_REG(0x039C)
+#define ZD_CR232 CTL_REG(0x03A0)
+#define ZD_CR233 CTL_REG(0x03A4)
+#define ZD_CR234 CTL_REG(0x03A8)
+#define ZD_CR235 CTL_REG(0x03AC)
+#define ZD_CR236 CTL_REG(0x03B0)
+
+#define ZD_CR240 CTL_REG(0x03C0)
+/* bit 7: host-controlled RF register writes
+ * ZD_CR241-ZD_CR245: for hardware controlled writing of RF bits, not needed for
+ * USB
*/
-#define CR241 CTL_REG(0x03C4)
-#define CR242 CTL_REG(0x03C8)
-#define CR243 CTL_REG(0x03CC)
-#define CR244 CTL_REG(0x03D0)
-#define CR245 CTL_REG(0x03D4)
-
-#define CR251 CTL_REG(0x03EC) /* only used for activation and deactivation of
- * Airoha RFs AL2230 and AL7230B
- */
-#define CR252 CTL_REG(0x03F0)
-#define CR253 CTL_REG(0x03F4)
-#define CR254 CTL_REG(0x03F8)
-#define CR255 CTL_REG(0x03FC)
+#define ZD_CR241 CTL_REG(0x03C4)
+#define ZD_CR242 CTL_REG(0x03C8)
+#define ZD_CR243 CTL_REG(0x03CC)
+#define ZD_CR244 CTL_REG(0x03D0)
+#define ZD_CR245 CTL_REG(0x03D4)
+
+#define ZD_CR251 CTL_REG(0x03EC) /* only used for activation and
+ * deactivation of Airoha RFs AL2230
+ * and AL7230B
+ */
+#define ZD_CR252 CTL_REG(0x03F0)
+#define ZD_CR253 CTL_REG(0x03F4)
+#define ZD_CR254 CTL_REG(0x03F8)
+#define ZD_CR255 CTL_REG(0x03FC)
#define CR_MAX_PHY_REG 255
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h
index 79dc1035592d..725b7c99b23d 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf.h
+++ b/drivers/net/wireless/zd1211rw/zd_rf.h
@@ -55,7 +55,7 @@ struct zd_rf {
* defaults to 1 (yes) */
u8 update_channel_int:1;
- /* whether CR47 should be patched from the EEPROM, if the appropriate
+ /* whether ZD_CR47 should be patched from the EEPROM, if the appropriate
* flag is set in the POD. The vendor driver suggests that this should
* be done for all RF's, but a bug in their code prevents but their
* HW_OverWritePhyRegFromE2P() routine from ever taking effect. */
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
index 74a8f7a55591..12babcb633c3 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
@@ -61,31 +61,31 @@ static const u32 zd1211b_al2230_table[][3] = {
};
static const struct zd_ioreq16 zd1211b_ioreqs_shared_1[] = {
- { CR240, 0x57 }, { CR9, 0xe0 },
+ { ZD_CR240, 0x57 }, { ZD_CR9, 0xe0 },
};
static const struct zd_ioreq16 ioreqs_init_al2230s[] = {
- { CR47, 0x1e }, /* MARK_002 */
- { CR106, 0x22 },
- { CR107, 0x2a }, /* MARK_002 */
- { CR109, 0x13 }, /* MARK_002 */
- { CR118, 0xf8 }, /* MARK_002 */
- { CR119, 0x12 }, { CR122, 0xe0 },
- { CR128, 0x10 }, /* MARK_001 from 0xe->0x10 */
- { CR129, 0x0e }, /* MARK_001 from 0xd->0x0e */
- { CR130, 0x10 }, /* MARK_001 from 0xb->0x0d */
+ { ZD_CR47, 0x1e }, /* MARK_002 */
+ { ZD_CR106, 0x22 },
+ { ZD_CR107, 0x2a }, /* MARK_002 */
+ { ZD_CR109, 0x13 }, /* MARK_002 */
+ { ZD_CR118, 0xf8 }, /* MARK_002 */
+ { ZD_CR119, 0x12 }, { ZD_CR122, 0xe0 },
+ { ZD_CR128, 0x10 }, /* MARK_001 from 0xe->0x10 */
+ { ZD_CR129, 0x0e }, /* MARK_001 from 0xd->0x0e */
+ { ZD_CR130, 0x10 }, /* MARK_001 from 0xb->0x0d */
};
static int zd1211b_al2230_finalize_rf(struct zd_chip *chip)
{
int r;
static const struct zd_ioreq16 ioreqs[] = {
- { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 },
- { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 },
- { CR203, 0x06 },
+ { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, { ZD_CR79, 0x58 },
+ { ZD_CR12, 0xf0 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x58 },
+ { ZD_CR203, 0x06 },
{ },
- { CR240, 0x80 },
+ { ZD_CR240, 0x80 },
};
r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
@@ -94,12 +94,12 @@ static int zd1211b_al2230_finalize_rf(struct zd_chip *chip)
/* related to antenna selection? */
if (chip->new_phy_layout) {
- r = zd_iowrite16_locked(chip, 0xe1, CR9);
+ r = zd_iowrite16_locked(chip, 0xe1, ZD_CR9);
if (r)
return r;
}
- return zd_iowrite16_locked(chip, 0x06, CR203);
+ return zd_iowrite16_locked(chip, 0x06, ZD_CR203);
}
static int zd1211_al2230_init_hw(struct zd_rf *rf)
@@ -108,40 +108,40 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
struct zd_chip *chip = zd_rf_to_chip(rf);
static const struct zd_ioreq16 ioreqs_init[] = {
- { CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 },
- { CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 },
- { CR44, 0x33 }, { CR106, 0x2a }, { CR107, 0x1a },
- { CR109, 0x09 }, { CR110, 0x27 }, { CR111, 0x2b },
- { CR112, 0x2b }, { CR119, 0x0a }, { CR10, 0x89 },
+ { ZD_CR15, 0x20 }, { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 },
+ { ZD_CR26, 0x11 }, { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 },
+ { ZD_CR44, 0x33 }, { ZD_CR106, 0x2a }, { ZD_CR107, 0x1a },
+ { ZD_CR109, 0x09 }, { ZD_CR110, 0x27 }, { ZD_CR111, 0x2b },
+ { ZD_CR112, 0x2b }, { ZD_CR119, 0x0a }, { ZD_CR10, 0x89 },
/* for newest (3rd cut) AL2300 */
- { CR17, 0x28 },
- { CR26, 0x93 }, { CR34, 0x30 },
+ { ZD_CR17, 0x28 },
+ { ZD_CR26, 0x93 }, { ZD_CR34, 0x30 },
/* for newest (3rd cut) AL2300 */
- { CR35, 0x3e },
- { CR41, 0x24 }, { CR44, 0x32 },
+ { ZD_CR35, 0x3e },
+ { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 },
/* for newest (3rd cut) AL2300 */
- { CR46, 0x96 },
- { CR47, 0x1e }, { CR79, 0x58 }, { CR80, 0x30 },
- { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 },
- { CR92, 0x0a }, { CR99, 0x28 }, { CR100, 0x00 },
- { CR101, 0x13 }, { CR102, 0x27 }, { CR106, 0x24 },
- { CR107, 0x2a }, { CR109, 0x09 }, { CR110, 0x13 },
- { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 },
- { CR114, 0x27 },
+ { ZD_CR46, 0x96 },
+ { ZD_CR47, 0x1e }, { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 },
+ { ZD_CR81, 0x30 }, { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 },
+ { ZD_CR92, 0x0a }, { ZD_CR99, 0x28 }, { ZD_CR100, 0x00 },
+ { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, { ZD_CR106, 0x24 },
+ { ZD_CR107, 0x2a }, { ZD_CR109, 0x09 }, { ZD_CR110, 0x13 },
+ { ZD_CR111, 0x1f }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 },
+ { ZD_CR114, 0x27 },
/* for newest (3rd cut) AL2300 */
- { CR115, 0x24 },
- { CR116, 0x24 }, { CR117, 0xf4 }, { CR118, 0xfc },
- { CR119, 0x10 }, { CR120, 0x4f }, { CR121, 0x77 },
- { CR122, 0xe0 }, { CR137, 0x88 }, { CR252, 0xff },
- { CR253, 0xff },
+ { ZD_CR115, 0x24 },
+ { ZD_CR116, 0x24 }, { ZD_CR117, 0xf4 }, { ZD_CR118, 0xfc },
+ { ZD_CR119, 0x10 }, { ZD_CR120, 0x4f }, { ZD_CR121, 0x77 },
+ { ZD_CR122, 0xe0 }, { ZD_CR137, 0x88 }, { ZD_CR252, 0xff },
+ { ZD_CR253, 0xff },
};
static const struct zd_ioreq16 ioreqs_pll[] = {
/* shdnb(PLL_ON)=0 */
- { CR251, 0x2f },
+ { ZD_CR251, 0x2f },
/* shdnb(PLL_ON)=1 */
- { CR251, 0x3f },
- { CR138, 0x28 }, { CR203, 0x06 },
+ { ZD_CR251, 0x3f },
+ { ZD_CR138, 0x28 }, { ZD_CR203, 0x06 },
};
static const u32 rv1[] = {
@@ -161,7 +161,7 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf)
0x0805b6,
0x011687,
0x000688,
- 0x0403b9, /* external control TX power (CR31) */
+ 0x0403b9, /* external control TX power (ZD_CR31) */
0x00dbba,
0x00099b,
0x0bdffc,
@@ -221,52 +221,54 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf)
struct zd_chip *chip = zd_rf_to_chip(rf);
static const struct zd_ioreq16 ioreqs1[] = {
- { CR10, 0x89 }, { CR15, 0x20 },
- { CR17, 0x2B }, /* for newest(3rd cut) AL2230 */
- { CR23, 0x40 }, { CR24, 0x20 }, { CR26, 0x93 },
- { CR28, 0x3e }, { CR29, 0x00 },
- { CR33, 0x28 }, /* 5621 */
- { CR34, 0x30 },
- { CR35, 0x3e }, /* for newest(3rd cut) AL2230 */
- { CR41, 0x24 }, { CR44, 0x32 },
- { CR46, 0x99 }, /* for newest(3rd cut) AL2230 */
- { CR47, 0x1e },
+ { ZD_CR10, 0x89 }, { ZD_CR15, 0x20 },
+ { ZD_CR17, 0x2B }, /* for newest(3rd cut) AL2230 */
+ { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, { ZD_CR26, 0x93 },
+ { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 },
+ { ZD_CR33, 0x28 }, /* 5621 */
+ { ZD_CR34, 0x30 },
+ { ZD_CR35, 0x3e }, /* for newest(3rd cut) AL2230 */
+ { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 },
+ { ZD_CR46, 0x99 }, /* for newest(3rd cut) AL2230 */
+ { ZD_CR47, 0x1e },
/* ZD1211B 05.06.10 */
- { CR48, 0x06 }, { CR49, 0xf9 }, { CR51, 0x01 },
- { CR52, 0x80 }, { CR53, 0x7e }, { CR65, 0x00 },
- { CR66, 0x00 }, { CR67, 0x00 }, { CR68, 0x00 },
- { CR69, 0x28 },
-
- { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 },
- { CR87, 0x0a }, { CR89, 0x04 },
- { CR91, 0x00 }, /* 5621 */
- { CR92, 0x0a },
- { CR98, 0x8d }, /* 4804, for 1212 new algorithm */
- { CR99, 0x00 }, /* 5621 */
- { CR101, 0x13 }, { CR102, 0x27 },
- { CR106, 0x24 }, /* for newest(3rd cut) AL2230 */
- { CR107, 0x2a },
- { CR109, 0x13 }, /* 4804, for 1212 new algorithm */
- { CR110, 0x1f }, /* 4804, for 1212 new algorithm */
- { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 },
- { CR114, 0x27 },
- { CR115, 0x26 }, /* 24->26 at 4902 for newest(3rd cut) AL2230 */
- { CR116, 0x24 },
- { CR117, 0xfa }, /* for 1211b */
- { CR118, 0xfa }, /* for 1211b */
- { CR119, 0x10 },
- { CR120, 0x4f },
- { CR121, 0x6c }, /* for 1211b */
- { CR122, 0xfc }, /* E0->FC at 4902 */
- { CR123, 0x57 }, /* 5623 */
- { CR125, 0xad }, /* 4804, for 1212 new algorithm */
- { CR126, 0x6c }, /* 5614 */
- { CR127, 0x03 }, /* 4804, for 1212 new algorithm */
- { CR137, 0x50 }, /* 5614 */
- { CR138, 0xa8 },
- { CR144, 0xac }, /* 5621 */
- { CR150, 0x0d }, { CR252, 0x34 }, { CR253, 0x34 },
+ { ZD_CR48, 0x06 }, { ZD_CR49, 0xf9 }, { ZD_CR51, 0x01 },
+ { ZD_CR52, 0x80 }, { ZD_CR53, 0x7e }, { ZD_CR65, 0x00 },
+ { ZD_CR66, 0x00 }, { ZD_CR67, 0x00 }, { ZD_CR68, 0x00 },
+ { ZD_CR69, 0x28 },
+
+ { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 },
+ { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 },
+ { ZD_CR91, 0x00 }, /* 5621 */
+ { ZD_CR92, 0x0a },
+ { ZD_CR98, 0x8d }, /* 4804, for 1212 new algorithm */
+ { ZD_CR99, 0x00 }, /* 5621 */
+ { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 },
+ { ZD_CR106, 0x24 }, /* for newest(3rd cut) AL2230 */
+ { ZD_CR107, 0x2a },
+ { ZD_CR109, 0x13 }, /* 4804, for 1212 new algorithm */
+ { ZD_CR110, 0x1f }, /* 4804, for 1212 new algorithm */
+ { ZD_CR111, 0x1f }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 },
+ { ZD_CR114, 0x27 },
+ { ZD_CR115, 0x26 }, /* 24->26 at 4902 for newest(3rd cut)
+ * AL2230
+ */
+ { ZD_CR116, 0x24 },
+ { ZD_CR117, 0xfa }, /* for 1211b */
+ { ZD_CR118, 0xfa }, /* for 1211b */
+ { ZD_CR119, 0x10 },
+ { ZD_CR120, 0x4f },
+ { ZD_CR121, 0x6c }, /* for 1211b */
+ { ZD_CR122, 0xfc }, /* E0->FC at 4902 */
+ { ZD_CR123, 0x57 }, /* 5623 */
+ { ZD_CR125, 0xad }, /* 4804, for 1212 new algorithm */
+ { ZD_CR126, 0x6c }, /* 5614 */
+ { ZD_CR127, 0x03 }, /* 4804, for 1212 new algorithm */
+ { ZD_CR137, 0x50 }, /* 5614 */
+ { ZD_CR138, 0xa8 },
+ { ZD_CR144, 0xac }, /* 5621 */
+ { ZD_CR150, 0x0d }, { ZD_CR252, 0x34 }, { ZD_CR253, 0x34 },
};
static const u32 rv1[] = {
@@ -284,7 +286,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf)
0x6da010, /* Reg6 update for MP versio */
0xe36280, /* Modified by jxiao for Bor-Chin on 2004/08/02 */
0x116000,
- 0x9dc020, /* External control TX power (CR31) */
+ 0x9dc020, /* External control TX power (ZD_CR31) */
0x5ddb00, /* RegA update for MP version */
0xd99000, /* RegB update for MP version */
0x3ffbd0, /* RegC update for MP version */
@@ -295,8 +297,8 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf)
};
static const struct zd_ioreq16 ioreqs2[] = {
- { CR251, 0x2f }, /* shdnb(PLL_ON)=0 */
- { CR251, 0x7f }, /* shdnb(PLL_ON)=1 */
+ { ZD_CR251, 0x2f }, /* shdnb(PLL_ON)=0 */
+ { ZD_CR251, 0x7f }, /* shdnb(PLL_ON)=1 */
};
static const u32 rv3[] = {
@@ -308,7 +310,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf)
static const struct zd_ioreq16 ioreqs3[] = {
/* related to 6M band edge patching, happens unconditionally */
- { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+ { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 },
};
r = zd_iowrite16a_locked(chip, zd1211b_ioreqs_shared_1,
@@ -361,8 +363,8 @@ static int zd1211_al2230_set_channel(struct zd_rf *rf, u8 channel)
const u32 *rv = zd1211_al2230_table[channel-1];
struct zd_chip *chip = zd_rf_to_chip(rf);
static const struct zd_ioreq16 ioreqs[] = {
- { CR138, 0x28 },
- { CR203, 0x06 },
+ { ZD_CR138, 0x28 },
+ { ZD_CR203, 0x06 },
};
r = zd_rfwritev_locked(chip, rv, 3, RF_RV_BITS);
@@ -393,8 +395,8 @@ static int zd1211_al2230_switch_radio_on(struct zd_rf *rf)
{
struct zd_chip *chip = zd_rf_to_chip(rf);
static const struct zd_ioreq16 ioreqs[] = {
- { CR11, 0x00 },
- { CR251, 0x3f },
+ { ZD_CR11, 0x00 },
+ { ZD_CR251, 0x3f },
};
return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
@@ -404,8 +406,8 @@ static int zd1211b_al2230_switch_radio_on(struct zd_rf *rf)
{
struct zd_chip *chip = zd_rf_to_chip(rf);
static const struct zd_ioreq16 ioreqs[] = {
- { CR11, 0x00 },
- { CR251, 0x7f },
+ { ZD_CR11, 0x00 },
+ { ZD_CR251, 0x7f },
};
return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
@@ -415,8 +417,8 @@ static int al2230_switch_radio_off(struct zd_rf *rf)
{
struct zd_chip *chip = zd_rf_to_chip(rf);
static const struct zd_ioreq16 ioreqs[] = {
- { CR11, 0x04 },
- { CR251, 0x2f },
+ { ZD_CR11, 0x04 },
+ { ZD_CR251, 0x2f },
};
return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
index 65095d661e6b..385c670d1293 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
@@ -68,19 +68,19 @@ static const u32 rv_init2[] = {
};
static const struct zd_ioreq16 ioreqs_sw[] = {
- { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
- { CR38, 0x38 }, { CR136, 0xdf },
+ { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 },
+ { ZD_CR38, 0x38 }, { ZD_CR136, 0xdf },
};
static int zd1211b_al7230b_finalize(struct zd_chip *chip)
{
int r;
static const struct zd_ioreq16 ioreqs[] = {
- { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 },
- { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 },
- { CR203, 0x04 },
+ { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, { ZD_CR79, 0x58 },
+ { ZD_CR12, 0xf0 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x58 },
+ { ZD_CR203, 0x04 },
{ },
- { CR240, 0x80 },
+ { ZD_CR240, 0x80 },
};
r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
@@ -89,12 +89,12 @@ static int zd1211b_al7230b_finalize(struct zd_chip *chip)
if (chip->new_phy_layout) {
/* antenna selection? */
- r = zd_iowrite16_locked(chip, 0xe5, CR9);
+ r = zd_iowrite16_locked(chip, 0xe5, ZD_CR9);
if (r)
return r;
}
- return zd_iowrite16_locked(chip, 0x04, CR203);
+ return zd_iowrite16_locked(chip, 0x04, ZD_CR203);
}
static int zd1211_al7230b_init_hw(struct zd_rf *rf)
@@ -106,66 +106,66 @@ static int zd1211_al7230b_init_hw(struct zd_rf *rf)
* specified */
static const struct zd_ioreq16 ioreqs_1[] = {
/* This one is 7230-specific, and happens before the rest */
- { CR240, 0x57 },
+ { ZD_CR240, 0x57 },
{ },
- { CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 },
- { CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 },
- { CR44, 0x33 },
+ { ZD_CR15, 0x20 }, { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 },
+ { ZD_CR26, 0x11 }, { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 },
+ { ZD_CR44, 0x33 },
/* This value is different for 7230 (was: 0x2a) */
- { CR106, 0x22 },
- { CR107, 0x1a }, { CR109, 0x09 }, { CR110, 0x27 },
- { CR111, 0x2b }, { CR112, 0x2b }, { CR119, 0x0a },
+ { ZD_CR106, 0x22 },
+ { ZD_CR107, 0x1a }, { ZD_CR109, 0x09 }, { ZD_CR110, 0x27 },
+ { ZD_CR111, 0x2b }, { ZD_CR112, 0x2b }, { ZD_CR119, 0x0a },
/* This happened further down in AL2230,
* and the value changed (was: 0xe0) */
- { CR122, 0xfc },
- { CR10, 0x89 },
+ { ZD_CR122, 0xfc },
+ { ZD_CR10, 0x89 },
/* for newest (3rd cut) AL2300 */
- { CR17, 0x28 },
- { CR26, 0x93 }, { CR34, 0x30 },
+ { ZD_CR17, 0x28 },
+ { ZD_CR26, 0x93 }, { ZD_CR34, 0x30 },
/* for newest (3rd cut) AL2300 */
- { CR35, 0x3e },
- { CR41, 0x24 }, { CR44, 0x32 },
+ { ZD_CR35, 0x3e },
+ { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 },
/* for newest (3rd cut) AL2300 */
- { CR46, 0x96 },
- { CR47, 0x1e }, { CR79, 0x58 }, { CR80, 0x30 },
- { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 },
- { CR92, 0x0a }, { CR99, 0x28 },
+ { ZD_CR46, 0x96 },
+ { ZD_CR47, 0x1e }, { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 },
+ { ZD_CR81, 0x30 }, { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 },
+ { ZD_CR92, 0x0a }, { ZD_CR99, 0x28 },
/* This value is different for 7230 (was: 0x00) */
- { CR100, 0x02 },
- { CR101, 0x13 }, { CR102, 0x27 },
+ { ZD_CR100, 0x02 },
+ { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 },
/* This value is different for 7230 (was: 0x24) */
- { CR106, 0x22 },
+ { ZD_CR106, 0x22 },
/* This value is different for 7230 (was: 0x2a) */
- { CR107, 0x3f },
- { CR109, 0x09 },
+ { ZD_CR107, 0x3f },
+ { ZD_CR109, 0x09 },
/* This value is different for 7230 (was: 0x13) */
- { CR110, 0x1f },
- { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 },
- { CR114, 0x27 },
+ { ZD_CR110, 0x1f },
+ { ZD_CR111, 0x1f }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 },
+ { ZD_CR114, 0x27 },
/* for newest (3rd cut) AL2300 */
- { CR115, 0x24 },
+ { ZD_CR115, 0x24 },
/* This value is different for 7230 (was: 0x24) */
- { CR116, 0x3f },
+ { ZD_CR116, 0x3f },
/* This value is different for 7230 (was: 0xf4) */
- { CR117, 0xfa },
- { CR118, 0xfc }, { CR119, 0x10 }, { CR120, 0x4f },
- { CR121, 0x77 }, { CR137, 0x88 },
+ { ZD_CR117, 0xfa },
+ { ZD_CR118, 0xfc }, { ZD_CR119, 0x10 }, { ZD_CR120, 0x4f },
+ { ZD_CR121, 0x77 }, { ZD_CR137, 0x88 },
/* This one is 7230-specific */
- { CR138, 0xa8 },
+ { ZD_CR138, 0xa8 },
/* This value is different for 7230 (was: 0xff) */
- { CR252, 0x34 },
+ { ZD_CR252, 0x34 },
/* This value is different for 7230 (was: 0xff) */
- { CR253, 0x34 },
+ { ZD_CR253, 0x34 },
/* PLL_OFF */
- { CR251, 0x2f },
+ { ZD_CR251, 0x2f },
};
static const struct zd_ioreq16 ioreqs_2[] = {
- { CR251, 0x3f }, /* PLL_ON */
- { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
- { CR38, 0x38 }, { CR136, 0xdf },
+ { ZD_CR251, 0x3f }, /* PLL_ON */
+ { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 },
+ { ZD_CR38, 0x38 }, { ZD_CR136, 0xdf },
};
r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1));
@@ -192,10 +192,10 @@ static int zd1211_al7230b_init_hw(struct zd_rf *rf)
if (r)
return r;
- r = zd_iowrite16_locked(chip, 0x06, CR203);
+ r = zd_iowrite16_locked(chip, 0x06, ZD_CR203);
if (r)
return r;
- r = zd_iowrite16_locked(chip, 0x80, CR240);
+ r = zd_iowrite16_locked(chip, 0x80, ZD_CR240);
if (r)
return r;
@@ -208,79 +208,79 @@ static int zd1211b_al7230b_init_hw(struct zd_rf *rf)
struct zd_chip *chip = zd_rf_to_chip(rf);
static const struct zd_ioreq16 ioreqs_1[] = {
- { CR240, 0x57 }, { CR9, 0x9 },
+ { ZD_CR240, 0x57 }, { ZD_CR9, 0x9 },
{ },
- { CR10, 0x8b }, { CR15, 0x20 },
- { CR17, 0x2B }, /* for newest (3rd cut) AL2230 */
- { CR20, 0x10 }, /* 4N25->Stone Request */
- { CR23, 0x40 }, { CR24, 0x20 }, { CR26, 0x93 },
- { CR28, 0x3e }, { CR29, 0x00 },
- { CR33, 0x28 }, /* 5613 */
- { CR34, 0x30 },
- { CR35, 0x3e }, /* for newest (3rd cut) AL2230 */
- { CR41, 0x24 }, { CR44, 0x32 },
- { CR46, 0x99 }, /* for newest (3rd cut) AL2230 */
- { CR47, 0x1e },
+ { ZD_CR10, 0x8b }, { ZD_CR15, 0x20 },
+ { ZD_CR17, 0x2B }, /* for newest (3rd cut) AL2230 */
+ { ZD_CR20, 0x10 }, /* 4N25->Stone Request */
+ { ZD_CR23, 0x40 }, { ZD_CR24, 0x20 }, { ZD_CR26, 0x93 },
+ { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 },
+ { ZD_CR33, 0x28 }, /* 5613 */
+ { ZD_CR34, 0x30 },
+ { ZD_CR35, 0x3e }, /* for newest (3rd cut) AL2230 */
+ { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 },
+ { ZD_CR46, 0x99 }, /* for newest (3rd cut) AL2230 */
+ { ZD_CR47, 0x1e },
/* ZD1215 5610 */
- { CR48, 0x00 }, { CR49, 0x00 }, { CR51, 0x01 },
- { CR52, 0x80 }, { CR53, 0x7e }, { CR65, 0x00 },
- { CR66, 0x00 }, { CR67, 0x00 }, { CR68, 0x00 },
- { CR69, 0x28 },
-
- { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 },
- { CR87, 0x0A }, { CR89, 0x04 },
- { CR90, 0x58 }, /* 5112 */
- { CR91, 0x00 }, /* 5613 */
- { CR92, 0x0a },
- { CR98, 0x8d }, /* 4804, for 1212 new algorithm */
- { CR99, 0x00 }, { CR100, 0x02 }, { CR101, 0x13 },
- { CR102, 0x27 },
- { CR106, 0x20 }, /* change to 0x24 for AL7230B */
- { CR109, 0x13 }, /* 4804, for 1212 new algorithm */
- { CR112, 0x1f },
+ { ZD_CR48, 0x00 }, { ZD_CR49, 0x00 }, { ZD_CR51, 0x01 },
+ { ZD_CR52, 0x80 }, { ZD_CR53, 0x7e }, { ZD_CR65, 0x00 },
+ { ZD_CR66, 0x00 }, { ZD_CR67, 0x00 }, { ZD_CR68, 0x00 },
+ { ZD_CR69, 0x28 },
+
+ { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 },
+ { ZD_CR87, 0x0A }, { ZD_CR89, 0x04 },
+ { ZD_CR90, 0x58 }, /* 5112 */
+ { ZD_CR91, 0x00 }, /* 5613 */
+ { ZD_CR92, 0x0a },
+ { ZD_CR98, 0x8d }, /* 4804, for 1212 new algorithm */
+ { ZD_CR99, 0x00 }, { ZD_CR100, 0x02 }, { ZD_CR101, 0x13 },
+ { ZD_CR102, 0x27 },
+ { ZD_CR106, 0x20 }, /* change to 0x24 for AL7230B */
+ { ZD_CR109, 0x13 }, /* 4804, for 1212 new algorithm */
+ { ZD_CR112, 0x1f },
};
static const struct zd_ioreq16 ioreqs_new_phy[] = {
- { CR107, 0x28 },
- { CR110, 0x1f }, /* 5127, 0x13->0x1f */
- { CR111, 0x1f }, /* 0x13 to 0x1f for AL7230B */
- { CR116, 0x2a }, { CR118, 0xfa }, { CR119, 0x12 },
- { CR121, 0x6c }, /* 5613 */
+ { ZD_CR107, 0x28 },
+ { ZD_CR110, 0x1f }, /* 5127, 0x13->0x1f */
+ { ZD_CR111, 0x1f }, /* 0x13 to 0x1f for AL7230B */
+ { ZD_CR116, 0x2a }, { ZD_CR118, 0xfa }, { ZD_CR119, 0x12 },
+ { ZD_CR121, 0x6c }, /* 5613 */
};
static const struct zd_ioreq16 ioreqs_old_phy[] = {
- { CR107, 0x24 },
- { CR110, 0x13 }, /* 5127, 0x13->0x1f */
- { CR111, 0x13 }, /* 0x13 to 0x1f for AL7230B */
- { CR116, 0x24 }, { CR118, 0xfc }, { CR119, 0x11 },
- { CR121, 0x6a }, /* 5613 */
+ { ZD_CR107, 0x24 },
+ { ZD_CR110, 0x13 }, /* 5127, 0x13->0x1f */
+ { ZD_CR111, 0x13 }, /* 0x13 to 0x1f for AL7230B */
+ { ZD_CR116, 0x24 }, { ZD_CR118, 0xfc }, { ZD_CR119, 0x11 },
+ { ZD_CR121, 0x6a }, /* 5613 */
};
static const struct zd_ioreq16 ioreqs_2[] = {
- { CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x24 },
- { CR117, 0xfa }, { CR120, 0x4f },
- { CR122, 0xfc }, /* E0->FCh at 4901 */
- { CR123, 0x57 }, /* 5613 */
- { CR125, 0xad }, /* 4804, for 1212 new algorithm */
- { CR126, 0x6c }, /* 5613 */
- { CR127, 0x03 }, /* 4804, for 1212 new algorithm */
- { CR130, 0x10 },
- { CR131, 0x00 }, /* 5112 */
- { CR137, 0x50 }, /* 5613 */
- { CR138, 0xa8 }, /* 5112 */
- { CR144, 0xac }, /* 5613 */
- { CR148, 0x40 }, /* 5112 */
- { CR149, 0x40 }, /* 4O07, 50->40 */
- { CR150, 0x1a }, /* 5112, 0C->1A */
- { CR252, 0x34 }, { CR253, 0x34 },
- { CR251, 0x2f }, /* PLL_OFF */
+ { ZD_CR113, 0x27 }, { ZD_CR114, 0x27 }, { ZD_CR115, 0x24 },
+ { ZD_CR117, 0xfa }, { ZD_CR120, 0x4f },
+ { ZD_CR122, 0xfc }, /* E0->FCh at 4901 */
+ { ZD_CR123, 0x57 }, /* 5613 */
+ { ZD_CR125, 0xad }, /* 4804, for 1212 new algorithm */
+ { ZD_CR126, 0x6c }, /* 5613 */
+ { ZD_CR127, 0x03 }, /* 4804, for 1212 new algorithm */
+ { ZD_CR130, 0x10 },
+ { ZD_CR131, 0x00 }, /* 5112 */
+ { ZD_CR137, 0x50 }, /* 5613 */
+ { ZD_CR138, 0xa8 }, /* 5112 */
+ { ZD_CR144, 0xac }, /* 5613 */
+ { ZD_CR148, 0x40 }, /* 5112 */
+ { ZD_CR149, 0x40 }, /* 4O07, 50->40 */
+ { ZD_CR150, 0x1a }, /* 5112, 0C->1A */
+ { ZD_CR252, 0x34 }, { ZD_CR253, 0x34 },
+ { ZD_CR251, 0x2f }, /* PLL_OFF */
};
static const struct zd_ioreq16 ioreqs_3[] = {
- { CR251, 0x7f }, /* PLL_ON */
- { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
- { CR38, 0x38 }, { CR136, 0xdf },
+ { ZD_CR251, 0x7f }, /* PLL_ON */
+ { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 }, { ZD_CR130, 0x10 },
+ { ZD_CR38, 0x38 }, { ZD_CR136, 0xdf },
};
r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1));
@@ -331,16 +331,16 @@ static int zd1211_al7230b_set_channel(struct zd_rf *rf, u8 channel)
static const struct zd_ioreq16 ioreqs[] = {
/* PLL_ON */
- { CR251, 0x3f },
- { CR203, 0x06 }, { CR240, 0x08 },
+ { ZD_CR251, 0x3f },
+ { ZD_CR203, 0x06 }, { ZD_CR240, 0x08 },
};
- r = zd_iowrite16_locked(chip, 0x57, CR240);
+ r = zd_iowrite16_locked(chip, 0x57, ZD_CR240);
if (r)
return r;
/* PLL_OFF */
- r = zd_iowrite16_locked(chip, 0x2f, CR251);
+ r = zd_iowrite16_locked(chip, 0x2f, ZD_CR251);
if (r)
return r;
@@ -376,15 +376,15 @@ static int zd1211b_al7230b_set_channel(struct zd_rf *rf, u8 channel)
const u32 *rv = chan_rv[channel-1];
struct zd_chip *chip = zd_rf_to_chip(rf);
- r = zd_iowrite16_locked(chip, 0x57, CR240);
+ r = zd_iowrite16_locked(chip, 0x57, ZD_CR240);
if (r)
return r;
- r = zd_iowrite16_locked(chip, 0xe4, CR9);
+ r = zd_iowrite16_locked(chip, 0xe4, ZD_CR9);
if (r)
return r;
/* PLL_OFF */
- r = zd_iowrite16_locked(chip, 0x2f, CR251);
+ r = zd_iowrite16_locked(chip, 0x2f, ZD_CR251);
if (r)
return r;
r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv));
@@ -410,7 +410,7 @@ static int zd1211b_al7230b_set_channel(struct zd_rf *rf, u8 channel)
if (r)
return r;
- r = zd_iowrite16_locked(chip, 0x7f, CR251);
+ r = zd_iowrite16_locked(chip, 0x7f, ZD_CR251);
if (r)
return r;
@@ -421,8 +421,8 @@ static int zd1211_al7230b_switch_radio_on(struct zd_rf *rf)
{
struct zd_chip *chip = zd_rf_to_chip(rf);
static const struct zd_ioreq16 ioreqs[] = {
- { CR11, 0x00 },
- { CR251, 0x3f },
+ { ZD_CR11, 0x00 },
+ { ZD_CR251, 0x3f },
};
return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
@@ -432,8 +432,8 @@ static int zd1211b_al7230b_switch_radio_on(struct zd_rf *rf)
{
struct zd_chip *chip = zd_rf_to_chip(rf);
static const struct zd_ioreq16 ioreqs[] = {
- { CR11, 0x00 },
- { CR251, 0x7f },
+ { ZD_CR11, 0x00 },
+ { ZD_CR251, 0x7f },
};
return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
@@ -443,8 +443,8 @@ static int al7230b_switch_radio_off(struct zd_rf *rf)
{
struct zd_chip *chip = zd_rf_to_chip(rf);
static const struct zd_ioreq16 ioreqs[] = {
- { CR11, 0x04 },
- { CR251, 0x2f },
+ { ZD_CR11, 0x04 },
+ { ZD_CR251, 0x2f },
};
return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
@@ -456,7 +456,7 @@ static int zd1211b_al7230b_patch_6m(struct zd_rf *rf, u8 channel)
{
struct zd_chip *chip = zd_rf_to_chip(rf);
struct zd_ioreq16 ioreqs[] = {
- { CR128, 0x14 }, { CR129, 0x12 },
+ { ZD_CR128, 0x14 }, { ZD_CR129, 0x12 },
};
/* FIXME: Channel 11 is not the edge for all regulatory domains. */
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
index e36117486c91..784d9ccb8fef 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
@@ -152,44 +152,44 @@ static int rf2959_init_hw(struct zd_rf *rf)
struct zd_chip *chip = zd_rf_to_chip(rf);
static const struct zd_ioreq16 ioreqs[] = {
- { CR2, 0x1E }, { CR9, 0x20 }, { CR10, 0x89 },
- { CR11, 0x00 }, { CR15, 0xD0 }, { CR17, 0x68 },
- { CR19, 0x4a }, { CR20, 0x0c }, { CR21, 0x0E },
- { CR23, 0x48 },
+ { ZD_CR2, 0x1E }, { ZD_CR9, 0x20 }, { ZD_CR10, 0x89 },
+ { ZD_CR11, 0x00 }, { ZD_CR15, 0xD0 }, { ZD_CR17, 0x68 },
+ { ZD_CR19, 0x4a }, { ZD_CR20, 0x0c }, { ZD_CR21, 0x0E },
+ { ZD_CR23, 0x48 },
/* normal size for cca threshold */
- { CR24, 0x14 },
- /* { CR24, 0x20 }, */
- { CR26, 0x90 }, { CR27, 0x30 }, { CR29, 0x20 },
- { CR31, 0xb2 }, { CR32, 0x43 }, { CR33, 0x28 },
- { CR38, 0x30 }, { CR34, 0x0f }, { CR35, 0xF0 },
- { CR41, 0x2a }, { CR46, 0x7F }, { CR47, 0x1E },
- { CR51, 0xc5 }, { CR52, 0xc5 }, { CR53, 0xc5 },
- { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 },
- { CR82, 0x00 }, { CR83, 0x24 }, { CR84, 0x04 },
- { CR85, 0x00 }, { CR86, 0x10 }, { CR87, 0x2A },
- { CR88, 0x10 }, { CR89, 0x24 }, { CR90, 0x18 },
- /* { CR91, 0x18 }, */
+ { ZD_CR24, 0x14 },
+ /* { ZD_CR24, 0x20 }, */
+ { ZD_CR26, 0x90 }, { ZD_CR27, 0x30 }, { ZD_CR29, 0x20 },
+ { ZD_CR31, 0xb2 }, { ZD_CR32, 0x43 }, { ZD_CR33, 0x28 },
+ { ZD_CR38, 0x30 }, { ZD_CR34, 0x0f }, { ZD_CR35, 0xF0 },
+ { ZD_CR41, 0x2a }, { ZD_CR46, 0x7F }, { ZD_CR47, 0x1E },
+ { ZD_CR51, 0xc5 }, { ZD_CR52, 0xc5 }, { ZD_CR53, 0xc5 },
+ { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 },
+ { ZD_CR82, 0x00 }, { ZD_CR83, 0x24 }, { ZD_CR84, 0x04 },
+ { ZD_CR85, 0x00 }, { ZD_CR86, 0x10 }, { ZD_CR87, 0x2A },
+ { ZD_CR88, 0x10 }, { ZD_CR89, 0x24 }, { ZD_CR90, 0x18 },
+ /* { ZD_CR91, 0x18 }, */
/* should solve continuous CTS frame problems */
- { CR91, 0x00 },
- { CR92, 0x0a }, { CR93, 0x00 }, { CR94, 0x01 },
- { CR95, 0x00 }, { CR96, 0x40 }, { CR97, 0x37 },
- { CR98, 0x05 }, { CR99, 0x28 }, { CR100, 0x00 },
- { CR101, 0x13 }, { CR102, 0x27 }, { CR103, 0x27 },
- { CR104, 0x18 }, { CR105, 0x12 },
+ { ZD_CR91, 0x00 },
+ { ZD_CR92, 0x0a }, { ZD_CR93, 0x00 }, { ZD_CR94, 0x01 },
+ { ZD_CR95, 0x00 }, { ZD_CR96, 0x40 }, { ZD_CR97, 0x37 },
+ { ZD_CR98, 0x05 }, { ZD_CR99, 0x28 }, { ZD_CR100, 0x00 },
+ { ZD_CR101, 0x13 }, { ZD_CR102, 0x27 }, { ZD_CR103, 0x27 },
+ { ZD_CR104, 0x18 }, { ZD_CR105, 0x12 },
/* normal size */
- { CR106, 0x1a },
- /* { CR106, 0x22 }, */
- { CR107, 0x24 }, { CR108, 0x0a }, { CR109, 0x13 },
- { CR110, 0x2F }, { CR111, 0x27 }, { CR112, 0x27 },
- { CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x40 },
- { CR116, 0x40 }, { CR117, 0xF0 }, { CR118, 0xF0 },
- { CR119, 0x16 },
+ { ZD_CR106, 0x1a },
+ /* { ZD_CR106, 0x22 }, */
+ { ZD_CR107, 0x24 }, { ZD_CR108, 0x0a }, { ZD_CR109, 0x13 },
+ { ZD_CR110, 0x2F }, { ZD_CR111, 0x27 }, { ZD_CR112, 0x27 },
+ { ZD_CR113, 0x27 }, { ZD_CR114, 0x27 }, { ZD_CR115, 0x40 },
+ { ZD_CR116, 0x40 }, { ZD_CR117, 0xF0 }, { ZD_CR118, 0xF0 },
+ { ZD_CR119, 0x16 },
/* no TX continuation */
- { CR122, 0x00 },
- /* { CR122, 0xff }, */
- { CR127, 0x03 }, { CR131, 0x08 }, { CR138, 0x28 },
- { CR148, 0x44 }, { CR150, 0x10 }, { CR169, 0xBB },
- { CR170, 0xBB },
+ { ZD_CR122, 0x00 },
+ /* { ZD_CR122, 0xff }, */
+ { ZD_CR127, 0x03 }, { ZD_CR131, 0x08 }, { ZD_CR138, 0x28 },
+ { ZD_CR148, 0x44 }, { ZD_CR150, 0x10 }, { ZD_CR169, 0xBB },
+ { ZD_CR170, 0xBB },
};
static const u32 rv[] = {
@@ -210,7 +210,7 @@ static int rf2959_init_hw(struct zd_rf *rf)
*/
0x294128, /* internal power */
/* 0x28252c, */ /* External control TX power */
- /* CR31_CCK, CR51_6-36M, CR52_48M, CR53_54M */
+ /* ZD_CR31_CCK, ZD_CR51_6-36M, ZD_CR52_48M, ZD_CR53_54M */
0x2c0000,
0x300000,
0x340000, /* REG13(0xD) */
@@ -245,8 +245,8 @@ static int rf2959_set_channel(struct zd_rf *rf, u8 channel)
static int rf2959_switch_radio_on(struct zd_rf *rf)
{
static const struct zd_ioreq16 ioreqs[] = {
- { CR10, 0x89 },
- { CR11, 0x00 },
+ { ZD_CR10, 0x89 },
+ { ZD_CR11, 0x00 },
};
struct zd_chip *chip = zd_rf_to_chip(rf);
@@ -256,8 +256,8 @@ static int rf2959_switch_radio_on(struct zd_rf *rf)
static int rf2959_switch_radio_off(struct zd_rf *rf)
{
static const struct zd_ioreq16 ioreqs[] = {
- { CR10, 0x15 },
- { CR11, 0x81 },
+ { ZD_CR10, 0x15 },
+ { ZD_CR11, 0x81 },
};
struct zd_chip *chip = zd_rf_to_chip(rf);
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c
index ba0a0ccb1fa0..c4d324e19c24 100644
--- a/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c
+++ b/drivers/net/wireless/zd1211rw/zd_rf_uw2453.c
@@ -314,42 +314,44 @@ static int uw2453_init_hw(struct zd_rf *rf)
struct zd_chip *chip = zd_rf_to_chip(rf);
static const struct zd_ioreq16 ioreqs[] = {
- { CR10, 0x89 }, { CR15, 0x20 },
- { CR17, 0x28 }, /* 6112 no change */
- { CR23, 0x38 }, { CR24, 0x20 }, { CR26, 0x93 },
- { CR27, 0x15 }, { CR28, 0x3e }, { CR29, 0x00 },
- { CR33, 0x28 }, { CR34, 0x30 },
- { CR35, 0x43 }, /* 6112 3e->43 */
- { CR41, 0x24 }, { CR44, 0x32 },
- { CR46, 0x92 }, /* 6112 96->92 */
- { CR47, 0x1e },
- { CR48, 0x04 }, /* 5602 Roger */
- { CR49, 0xfa }, { CR79, 0x58 }, { CR80, 0x30 },
- { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 },
- { CR91, 0x00 }, { CR92, 0x0a }, { CR98, 0x8d },
- { CR99, 0x28 }, { CR100, 0x02 },
- { CR101, 0x09 }, /* 6112 13->1f 6220 1f->13 6407 13->9 */
- { CR102, 0x27 },
- { CR106, 0x1c }, /* 5d07 5112 1f->1c 6220 1c->1f 6221 1f->1c */
- { CR107, 0x1c }, /* 6220 1c->1a 5221 1a->1c */
- { CR109, 0x13 },
- { CR110, 0x1f }, /* 6112 13->1f 6221 1f->13 6407 13->0x09 */
- { CR111, 0x13 }, { CR112, 0x1f }, { CR113, 0x27 },
- { CR114, 0x23 }, /* 6221 27->23 */
- { CR115, 0x24 }, /* 6112 24->1c 6220 1c->24 */
- { CR116, 0x24 }, /* 6220 1c->24 */
- { CR117, 0xfa }, /* 6112 fa->f8 6220 f8->f4 6220 f4->fa */
- { CR118, 0xf0 }, /* 5d07 6112 f0->f2 6220 f2->f0 */
- { CR119, 0x1a }, /* 6112 1a->10 6220 10->14 6220 14->1a */
- { CR120, 0x4f },
- { CR121, 0x1f }, /* 6220 4f->1f */
- { CR122, 0xf0 }, { CR123, 0x57 }, { CR125, 0xad },
- { CR126, 0x6c }, { CR127, 0x03 },
- { CR128, 0x14 }, /* 6302 12->11 */
- { CR129, 0x12 }, /* 6301 10->0f */
- { CR130, 0x10 }, { CR137, 0x50 }, { CR138, 0xa8 },
- { CR144, 0xac }, { CR146, 0x20 }, { CR252, 0xff },
- { CR253, 0xff },
+ { ZD_CR10, 0x89 }, { ZD_CR15, 0x20 },
+ { ZD_CR17, 0x28 }, /* 6112 no change */
+ { ZD_CR23, 0x38 }, { ZD_CR24, 0x20 }, { ZD_CR26, 0x93 },
+ { ZD_CR27, 0x15 }, { ZD_CR28, 0x3e }, { ZD_CR29, 0x00 },
+ { ZD_CR33, 0x28 }, { ZD_CR34, 0x30 },
+ { ZD_CR35, 0x43 }, /* 6112 3e->43 */
+ { ZD_CR41, 0x24 }, { ZD_CR44, 0x32 },
+ { ZD_CR46, 0x92 }, /* 6112 96->92 */
+ { ZD_CR47, 0x1e },
+ { ZD_CR48, 0x04 }, /* 5602 Roger */
+ { ZD_CR49, 0xfa }, { ZD_CR79, 0x58 }, { ZD_CR80, 0x30 },
+ { ZD_CR81, 0x30 }, { ZD_CR87, 0x0a }, { ZD_CR89, 0x04 },
+ { ZD_CR91, 0x00 }, { ZD_CR92, 0x0a }, { ZD_CR98, 0x8d },
+ { ZD_CR99, 0x28 }, { ZD_CR100, 0x02 },
+ { ZD_CR101, 0x09 }, /* 6112 13->1f 6220 1f->13 6407 13->9 */
+ { ZD_CR102, 0x27 },
+ { ZD_CR106, 0x1c }, /* 5d07 5112 1f->1c 6220 1c->1f
+ * 6221 1f->1c
+ */
+ { ZD_CR107, 0x1c }, /* 6220 1c->1a 5221 1a->1c */
+ { ZD_CR109, 0x13 },
+ { ZD_CR110, 0x1f }, /* 6112 13->1f 6221 1f->13 6407 13->0x09 */
+ { ZD_CR111, 0x13 }, { ZD_CR112, 0x1f }, { ZD_CR113, 0x27 },
+ { ZD_CR114, 0x23 }, /* 6221 27->23 */
+ { ZD_CR115, 0x24 }, /* 6112 24->1c 6220 1c->24 */
+ { ZD_CR116, 0x24 }, /* 6220 1c->24 */
+ { ZD_CR117, 0xfa }, /* 6112 fa->f8 6220 f8->f4 6220 f4->fa */
+ { ZD_CR118, 0xf0 }, /* 5d07 6112 f0->f2 6220 f2->f0 */
+ { ZD_CR119, 0x1a }, /* 6112 1a->10 6220 10->14 6220 14->1a */
+ { ZD_CR120, 0x4f },
+ { ZD_CR121, 0x1f }, /* 6220 4f->1f */
+ { ZD_CR122, 0xf0 }, { ZD_CR123, 0x57 }, { ZD_CR125, 0xad },
+ { ZD_CR126, 0x6c }, { ZD_CR127, 0x03 },
+ { ZD_CR128, 0x14 }, /* 6302 12->11 */
+ { ZD_CR129, 0x12 }, /* 6301 10->0f */
+ { ZD_CR130, 0x10 }, { ZD_CR137, 0x50 }, { ZD_CR138, 0xa8 },
+ { ZD_CR144, 0xac }, { ZD_CR146, 0x20 }, { ZD_CR252, 0xff },
+ { ZD_CR253, 0xff },
};
static const u32 rv[] = {
@@ -433,7 +435,7 @@ static int uw2453_init_hw(struct zd_rf *rf)
* the one that produced a lock. */
UW2453_PRIV(rf)->config = found_config + 1;
- return zd_iowrite16_locked(chip, 0x06, CR203);
+ return zd_iowrite16_locked(chip, 0x06, ZD_CR203);
}
static int uw2453_set_channel(struct zd_rf *rf, u8 channel)
@@ -445,8 +447,8 @@ static int uw2453_set_channel(struct zd_rf *rf, u8 channel)
struct zd_chip *chip = zd_rf_to_chip(rf);
static const struct zd_ioreq16 ioreqs[] = {
- { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 },
- { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 },
+ { ZD_CR80, 0x30 }, { ZD_CR81, 0x30 }, { ZD_CR79, 0x58 },
+ { ZD_CR12, 0xf0 }, { ZD_CR77, 0x1b }, { ZD_CR78, 0x58 },
};
r = uw2453_synth_set_channel(chip, channel, autocal);
@@ -474,7 +476,7 @@ static int uw2453_set_channel(struct zd_rf *rf, u8 channel)
if (r)
return r;
- return zd_iowrite16_locked(chip, 0x06, CR203);
+ return zd_iowrite16_locked(chip, 0x06, ZD_CR203);
}
static int uw2453_switch_radio_on(struct zd_rf *rf)
@@ -482,7 +484,7 @@ static int uw2453_switch_radio_on(struct zd_rf *rf)
int r;
struct zd_chip *chip = zd_rf_to_chip(rf);
struct zd_ioreq16 ioreqs[] = {
- { CR11, 0x00 }, { CR251, 0x3f },
+ { ZD_CR11, 0x00 }, { ZD_CR251, 0x3f },
};
/* enter RXTX mode */
@@ -501,7 +503,7 @@ static int uw2453_switch_radio_off(struct zd_rf *rf)
int r;
struct zd_chip *chip = zd_rf_to_chip(rf);
static const struct zd_ioreq16 ioreqs[] = {
- { CR11, 0x04 }, { CR251, 0x2f },
+ { ZD_CR11, 0x04 }, { ZD_CR251, 0x2f },
};
/* enter IDLE mode */
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index ab607bbd6291..0e819943b9e4 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -1893,10 +1893,10 @@ int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits)
dev_dbg_f(zd_usb_dev(usb), "value %#09x bits %d\n", value, bits);
- r = zd_usb_ioread16(usb, &bit_value_template, CR203);
+ r = zd_usb_ioread16(usb, &bit_value_template, ZD_CR203);
if (r) {
dev_dbg_f(zd_usb_dev(usb),
- "error %d: Couldn't read CR203\n", r);
+ "error %d: Couldn't read ZD_CR203\n", r);
return r;
}
bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA);
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
index 325d0f989257..bf942843b733 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.h
+++ b/drivers/net/wireless/zd1211rw/zd_usb.h
@@ -109,7 +109,7 @@ struct usb_req_rfwrite {
__le16 bits;
/* RF2595: 24 */
__le16 bit_values[0];
- /* (CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */
+ /* (ZD_CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */
} __packed;
/* USB interrupt */
diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
index 5d7bbf2b2ee7..161f207786a4 100644
--- a/drivers/net/xen-netback/common.h
+++ b/drivers/net/xen-netback/common.h
@@ -73,9 +73,6 @@ struct xenvif {
struct vm_struct *tx_comms_area;
struct vm_struct *rx_comms_area;
- /* Flags that must not be set in dev->features */
- u32 features_disabled;
-
/* Frontend feature information. */
u8 can_sg:1;
u8 gso:1;
@@ -109,8 +106,8 @@ struct xenvif {
wait_queue_head_t waiting_to_free;
};
-#define XEN_NETIF_TX_RING_SIZE __RING_SIZE((struct xen_netif_tx_sring *)0, PAGE_SIZE)
-#define XEN_NETIF_RX_RING_SIZE __RING_SIZE((struct xen_netif_rx_sring *)0, PAGE_SIZE)
+#define XEN_NETIF_TX_RING_SIZE __CONST_RING_SIZE(xen_netif_tx, PAGE_SIZE)
+#define XEN_NETIF_RX_RING_SIZE __CONST_RING_SIZE(xen_netif_rx, PAGE_SIZE)
struct xenvif *xenvif_alloc(struct device *parent,
domid_t domid,
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
index de569cc19da4..0ca86f9ec4ed 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -165,69 +165,18 @@ static int xenvif_change_mtu(struct net_device *dev, int mtu)
return 0;
}
-static void xenvif_set_features(struct xenvif *vif)
-{
- struct net_device *dev = vif->dev;
- u32 features = dev->features;
-
- if (vif->can_sg)
- features |= NETIF_F_SG;
- if (vif->gso || vif->gso_prefix)
- features |= NETIF_F_TSO;
- if (vif->csum)
- features |= NETIF_F_IP_CSUM;
-
- features &= ~(vif->features_disabled);
-
- if (!(features & NETIF_F_SG) && dev->mtu > ETH_DATA_LEN)
- dev->mtu = ETH_DATA_LEN;
-
- dev->features = features;
-}
-
-static int xenvif_set_tx_csum(struct net_device *dev, u32 data)
-{
- struct xenvif *vif = netdev_priv(dev);
- if (data) {
- if (!vif->csum)
- return -EOPNOTSUPP;
- vif->features_disabled &= ~NETIF_F_IP_CSUM;
- } else {
- vif->features_disabled |= NETIF_F_IP_CSUM;
- }
-
- xenvif_set_features(vif);
- return 0;
-}
-
-static int xenvif_set_sg(struct net_device *dev, u32 data)
+static u32 xenvif_fix_features(struct net_device *dev, u32 features)
{
struct xenvif *vif = netdev_priv(dev);
- if (data) {
- if (!vif->can_sg)
- return -EOPNOTSUPP;
- vif->features_disabled &= ~NETIF_F_SG;
- } else {
- vif->features_disabled |= NETIF_F_SG;
- }
- xenvif_set_features(vif);
- return 0;
-}
+ if (!vif->can_sg)
+ features &= ~NETIF_F_SG;
+ if (!vif->gso && !vif->gso_prefix)
+ features &= ~NETIF_F_TSO;
+ if (!vif->csum)
+ features &= ~NETIF_F_IP_CSUM;
-static int xenvif_set_tso(struct net_device *dev, u32 data)
-{
- struct xenvif *vif = netdev_priv(dev);
- if (data) {
- if (!vif->gso && !vif->gso_prefix)
- return -EOPNOTSUPP;
- vif->features_disabled &= ~NETIF_F_TSO;
- } else {
- vif->features_disabled |= NETIF_F_TSO;
- }
-
- xenvif_set_features(vif);
- return 0;
+ return features;
}
static const struct xenvif_stat {
@@ -274,12 +223,6 @@ static void xenvif_get_strings(struct net_device *dev, u32 stringset, u8 * data)
}
static struct ethtool_ops xenvif_ethtool_ops = {
- .get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = xenvif_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
- .set_sg = xenvif_set_sg,
- .get_tso = ethtool_op_get_tso,
- .set_tso = xenvif_set_tso,
.get_link = ethtool_op_get_link,
.get_sset_count = xenvif_get_sset_count,
@@ -293,6 +236,7 @@ static struct net_device_ops xenvif_netdev_ops = {
.ndo_open = xenvif_open,
.ndo_stop = xenvif_close,
.ndo_change_mtu = xenvif_change_mtu,
+ .ndo_fix_features = xenvif_fix_features,
};
struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
@@ -331,7 +275,8 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
vif->credit_timeout.expires = jiffies;
dev->netdev_ops = &xenvif_netdev_ops;
- xenvif_set_features(vif);
+ dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
+ dev->features = dev->hw_features;
SET_ETHTOOL_OPS(dev, &xenvif_ethtool_ops);
dev->tx_queue_len = XENVIF_QUEUE_LENGTH;
@@ -367,8 +312,6 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
if (vif->irq)
return 0;
- xenvif_set_features(vif);
-
err = xen_netbk_map_frontend_rings(vif, tx_ring_ref, rx_ring_ref);
if (err < 0)
goto err;
@@ -384,9 +327,12 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
xenvif_get(vif);
rtnl_lock();
- netif_carrier_on(vif->dev);
if (netif_running(vif->dev))
xenvif_up(vif);
+ if (!vif->can_sg && vif->dev->mtu > ETH_DATA_LEN)
+ dev_set_mtu(vif->dev, ETH_DATA_LEN);
+ netdev_update_features(vif->dev);
+ netif_carrier_on(vif->dev);
rtnl_unlock();
return 0;
diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c
index 22b8c3505991..1ce729d6af75 100644
--- a/drivers/net/xen-netback/xenbus.c
+++ b/drivers/net/xen-netback/xenbus.c
@@ -26,7 +26,7 @@ struct backend_info {
struct xenvif *vif;
enum xenbus_state frontend_state;
struct xenbus_watch hotplug_status_watch;
- int have_hotplug_status_watch:1;
+ u8 have_hotplug_status_watch:1;
};
static int connect_rings(struct backend_info *);
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index 5c8d9c385be0..d29365a232a1 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -1140,6 +1140,42 @@ static void xennet_uninit(struct net_device *dev)
gnttab_free_grant_references(np->gref_rx_head);
}
+static u32 xennet_fix_features(struct net_device *dev, u32 features)
+{
+ struct netfront_info *np = netdev_priv(dev);
+ int val;
+
+ if (features & NETIF_F_SG) {
+ if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, "feature-sg",
+ "%d", &val) < 0)
+ val = 0;
+
+ if (!val)
+ features &= ~NETIF_F_SG;
+ }
+
+ if (features & NETIF_F_TSO) {
+ if (xenbus_scanf(XBT_NIL, np->xbdev->otherend,
+ "feature-gso-tcpv4", "%d", &val) < 0)
+ val = 0;
+
+ if (!val)
+ features &= ~NETIF_F_TSO;
+ }
+
+ return features;
+}
+
+static int xennet_set_features(struct net_device *dev, u32 features)
+{
+ if (!(features & NETIF_F_SG) && dev->mtu > ETH_DATA_LEN) {
+ netdev_info(dev, "Reducing MTU because no SG offload");
+ dev->mtu = ETH_DATA_LEN;
+ }
+
+ return 0;
+}
+
static const struct net_device_ops xennet_netdev_ops = {
.ndo_open = xennet_open,
.ndo_uninit = xennet_uninit,
@@ -1148,6 +1184,8 @@ static const struct net_device_ops xennet_netdev_ops = {
.ndo_change_mtu = xennet_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
+ .ndo_fix_features = xennet_fix_features,
+ .ndo_set_features = xennet_set_features,
};
static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev)
@@ -1209,7 +1247,17 @@ static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev
netdev->netdev_ops = &xennet_netdev_ops;
netif_napi_add(netdev, &np->napi, xennet_poll, 64);
- netdev->features = NETIF_F_IP_CSUM;
+ netdev->features = NETIF_F_IP_CSUM | NETIF_F_RXCSUM |
+ NETIF_F_GSO_ROBUST;
+ netdev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO;
+
+ /*
+ * Assume that all hw features are available for now. This set
+ * will be adjusted by the call to netdev_update_features() in
+ * xennet_connect() which is the earliest point where we can
+ * negotiate with the backend regarding supported features.
+ */
+ netdev->features |= netdev->hw_features;
SET_ETHTOOL_OPS(netdev, &xennet_ethtool_ops);
SET_NETDEV_DEV(netdev, &dev->dev);
@@ -1416,8 +1464,7 @@ static int setup_netfront(struct xenbus_device *dev, struct netfront_info *info)
goto fail;
err = bind_evtchn_to_irqhandler(info->evtchn, xennet_interrupt,
- IRQF_SAMPLE_RANDOM, netdev->name,
- netdev);
+ 0, netdev->name, netdev);
if (err < 0)
goto fail;
netdev->irq = err;
@@ -1510,54 +1557,6 @@ again:
return err;
}
-static int xennet_set_sg(struct net_device *dev, u32 data)
-{
- if (data) {
- struct netfront_info *np = netdev_priv(dev);
- int val;
-
- if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, "feature-sg",
- "%d", &val) < 0)
- val = 0;
- if (!val)
- return -ENOSYS;
- } else if (dev->mtu > ETH_DATA_LEN)
- dev->mtu = ETH_DATA_LEN;
-
- return ethtool_op_set_sg(dev, data);
-}
-
-static int xennet_set_tso(struct net_device *dev, u32 data)
-{
- if (data) {
- struct netfront_info *np = netdev_priv(dev);
- int val;
-
- if (xenbus_scanf(XBT_NIL, np->xbdev->otherend,
- "feature-gso-tcpv4", "%d", &val) < 0)
- val = 0;
- if (!val)
- return -ENOSYS;
- }
-
- return ethtool_op_set_tso(dev, data);
-}
-
-static void xennet_set_features(struct net_device *dev)
-{
- /* Turn off all GSO bits except ROBUST. */
- dev->features &= ~NETIF_F_GSO_MASK;
- dev->features |= NETIF_F_GSO_ROBUST;
- xennet_set_sg(dev, 0);
-
- /* We need checksum offload to enable scatter/gather and TSO. */
- if (!(dev->features & NETIF_F_IP_CSUM))
- return;
-
- if (!xennet_set_sg(dev, 1))
- xennet_set_tso(dev, 1);
-}
-
static int xennet_connect(struct net_device *dev)
{
struct netfront_info *np = netdev_priv(dev);
@@ -1582,7 +1581,9 @@ static int xennet_connect(struct net_device *dev)
if (err)
return err;
- xennet_set_features(dev);
+ rtnl_lock();
+ netdev_update_features(dev);
+ rtnl_unlock();
spin_lock_bh(&np->rx_lock);
spin_lock_irq(&np->tx_lock);
@@ -1710,9 +1711,6 @@ static void xennet_get_strings(struct net_device *dev, u32 stringset, u8 * data)
static const struct ethtool_ops xennet_ethtool_ops =
{
- .set_tx_csum = ethtool_op_set_tx_csum,
- .set_sg = xennet_set_sg,
- .set_tso = xennet_set_tso,
.get_link = ethtool_op_get_link,
.get_sset_count = xennet_get_sset_count,
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index 75b0d3cb7676..9f689f1da0fc 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -56,7 +56,7 @@ EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
* 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 *of_irq_find_parent(struct device_node *child)
{
struct device_node *p;
const __be32 *parp;
diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c
index 787ebdeae310..067ad517c1f5 100644
--- a/drivers/parport/parport_cs.c
+++ b/drivers/parport/parport_cs.c
@@ -178,7 +178,7 @@ static void parport_cs_release(struct pcmcia_device *link)
} /* parport_cs_release */
-static struct pcmcia_device_id parport_ids[] = {
+static const struct pcmcia_device_id parport_ids[] = {
PCMCIA_DEVICE_FUNC_ID(3),
PCMCIA_MFC_DEVICE_PROD_ID12(1,"Elan","Serial+Parallel Port: SP230",0x3beb8cf2,0xdb9e58bc),
PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0003),
diff --git a/drivers/parport/parport_ip32.c b/drivers/parport/parport_ip32.c
index d3d7809af8bf..0dc34f12f92e 100644
--- a/drivers/parport/parport_ip32.c
+++ b/drivers/parport/parport_ip32.c
@@ -2203,7 +2203,6 @@ static __exit void parport_ip32_unregister_port(struct parport *p)
static int __init parport_ip32_init(void)
{
pr_info(PPIP32 "SGI IP32 built-in parallel port driver v0.6\n");
- pr_debug1(PPIP32 "Compiled on %s, %s\n", __DATE__, __TIME__);
this_port = parport_ip32_probe_port();
return IS_ERR(this_port) ? PTR_ERR(this_port) : 0;
}
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index bc8ce48f0778..f330338c2f22 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -1621,7 +1621,7 @@ static void __devinit detect_and_report_it87(void)
u8 origval, r;
if (verbose_probing)
printk(KERN_DEBUG "IT8705 Super-IO detection, now testing port 2E ...\n");
- if (!request_region(0x2e, 2, __func__))
+ if (!request_muxed_region(0x2e, 2, __func__))
return;
origval = inb(0x2e); /* Save original value */
outb(0x87, 0x2e);
diff --git a/drivers/pci/access.c b/drivers/pci/access.c
index 531bc697d800..fdaa42aac7c6 100644
--- a/drivers/pci/access.c
+++ b/drivers/pci/access.c
@@ -143,33 +143,41 @@ static noinline void pci_wait_ucfg(struct pci_dev *dev)
__remove_wait_queue(&pci_ucfg_wait, &wait);
}
+/* Returns 0 on success, negative values indicate error. */
#define PCI_USER_READ_CONFIG(size,type) \
int pci_user_read_config_##size \
(struct pci_dev *dev, int pos, type *val) \
{ \
int ret = 0; \
u32 data = -1; \
- if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \
+ if (PCI_##size##_BAD) \
+ return -EINVAL; \
raw_spin_lock_irq(&pci_lock); \
if (unlikely(dev->block_ucfg_access)) pci_wait_ucfg(dev); \
ret = dev->bus->ops->read(dev->bus, dev->devfn, \
pos, sizeof(type), &data); \
raw_spin_unlock_irq(&pci_lock); \
*val = (type)data; \
+ if (ret > 0) \
+ ret = -EINVAL; \
return ret; \
}
+/* Returns 0 on success, negative values indicate error. */
#define PCI_USER_WRITE_CONFIG(size,type) \
int pci_user_write_config_##size \
(struct pci_dev *dev, int pos, type val) \
{ \
int ret = -EIO; \
- if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \
+ if (PCI_##size##_BAD) \
+ return -EINVAL; \
raw_spin_lock_irq(&pci_lock); \
if (unlikely(dev->block_ucfg_access)) pci_wait_ucfg(dev); \
ret = dev->bus->ops->write(dev->bus, dev->devfn, \
pos, sizeof(type), val); \
raw_spin_unlock_irq(&pci_lock); \
+ if (ret > 0) \
+ ret = -EINVAL; \
return ret; \
}
@@ -197,6 +205,8 @@ struct pci_vpd_pci22 {
* This code has to spin since there is no other notification from the PCI
* hardware. Since the VPD is often implemented by serial attachment to an
* EEPROM, it may take many milliseconds to complete.
+ *
+ * Returns 0 on success, negative values indicate error.
*/
static int pci_vpd_pci22_wait(struct pci_dev *dev)
{
@@ -212,7 +222,7 @@ static int pci_vpd_pci22_wait(struct pci_dev *dev)
for (;;) {
ret = pci_user_read_config_word(dev, vpd->cap + PCI_VPD_ADDR,
&status);
- if (ret)
+ if (ret < 0)
return ret;
if ((status & PCI_VPD_ADDR_F) == vpd->flag) {
@@ -324,6 +334,8 @@ static ssize_t pci_vpd_pci22_write(struct pci_dev *dev, loff_t pos, size_t count
vpd->busy = true;
vpd->flag = 0;
ret = pci_vpd_pci22_wait(dev);
+ if (ret < 0)
+ break;
pos += sizeof(u32);
}
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 69546e9213dd..1e2ad92a4752 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -163,12 +163,6 @@ int pci_bus_add_child(struct pci_bus *bus)
bus->is_added = 1;
- retval = device_create_file(&bus->dev, &dev_attr_cpuaffinity);
- if (retval)
- return retval;
-
- retval = device_create_file(&bus->dev, &dev_attr_cpulistaffinity);
-
/* Create legacy_io and legacy_mem files for this bus */
pci_create_legacy_files(bus);
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 2f67e9bc2f96..a70fa89f76fd 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -827,6 +827,13 @@ static int __ref enable_device(struct acpiphp_slot *slot)
acpiphp_set_hpp_values(bus);
acpiphp_set_acpi_region(slot);
pci_enable_bridges(bus);
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ /* Assume that newly added devices are powered on already. */
+ if (!dev->is_added)
+ dev->current_state = PCI_D0;
+ }
+
pci_bus_add_devices(bus);
list_for_each_entry(func, &slot->funcs, sibling) {
diff --git a/drivers/pci/hotplug/pcihp_slot.c b/drivers/pci/hotplug/pcihp_slot.c
index 80b461c98557..749fdf070319 100644
--- a/drivers/pci/hotplug/pcihp_slot.c
+++ b/drivers/pci/hotplug/pcihp_slot.c
@@ -158,6 +158,47 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp)
*/
}
+/* Program PCIE MaxPayload setting on device: ensure parent maxpayload <= device */
+static int pci_set_payload(struct pci_dev *dev)
+{
+ int pos, ppos;
+ u16 pctl, psz;
+ u16 dctl, dsz, dcap, dmax;
+ struct pci_dev *parent;
+
+ parent = dev->bus->self;
+ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (!pos)
+ return 0;
+
+ /* Read Device MaxPayload capability and setting */
+ pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &dctl);
+ pci_read_config_word(dev, pos + PCI_EXP_DEVCAP, &dcap);
+ dsz = (dctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5;
+ dmax = (dcap & PCI_EXP_DEVCAP_PAYLOAD);
+
+ /* Read Parent MaxPayload setting */
+ ppos = pci_find_capability(parent, PCI_CAP_ID_EXP);
+ if (!ppos)
+ return 0;
+ pci_read_config_word(parent, ppos + PCI_EXP_DEVCTL, &pctl);
+ psz = (pctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5;
+
+ /* If parent payload > device max payload -> error
+ * If parent payload > device payload -> set speed
+ * If parent payload <= device payload -> do nothing
+ */
+ if (psz > dmax)
+ return -1;
+ else if (psz > dsz) {
+ dev_info(&dev->dev, "Setting MaxPayload to %d\n", 128 << psz);
+ pci_write_config_word(dev, pos + PCI_EXP_DEVCTL,
+ (dctl & ~PCI_EXP_DEVCTL_PAYLOAD) +
+ (psz << 5));
+ }
+ return 0;
+}
+
void pci_configure_slot(struct pci_dev *dev)
{
struct pci_dev *cdev;
@@ -169,6 +210,10 @@ void pci_configure_slot(struct pci_dev *dev)
(dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)))
return;
+ ret = pci_set_payload(dev);
+ if (ret)
+ dev_warn(&dev->dev, "could not set device max payload\n");
+
memset(&hpp, 0, sizeof(hpp));
ret = pci_get_hp_params(dev, &hpp);
if (ret)
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index d552d2c77844..6af6b628175b 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -39,6 +39,7 @@
#include <linux/syscore_ops.h>
#include <linux/tboot.h>
#include <linux/dmi.h>
+#include <linux/pci-ats.h>
#include <asm/cacheflush.h>
#include <asm/iommu.h>
#include "pci.h"
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index 553d8ee55c1c..42fae4776515 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -13,6 +13,7 @@
#include <linux/mutex.h>
#include <linux/string.h>
#include <linux/delay.h>
+#include <linux/pci-ats.h>
#include "pci.h"
#define VIRTFN_ID_LEN 16
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index f8deb3e380a2..7bcf12adced7 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -108,6 +108,40 @@ static ssize_t local_cpulist_show(struct device *dev,
return len;
}
+/*
+ * PCI Bus Class Devices
+ */
+static ssize_t pci_bus_show_cpuaffinity(struct device *dev,
+ int type,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ const struct cpumask *cpumask;
+
+ cpumask = cpumask_of_pcibus(to_pci_bus(dev));
+ ret = type ?
+ cpulist_scnprintf(buf, PAGE_SIZE-2, cpumask) :
+ cpumask_scnprintf(buf, PAGE_SIZE-2, cpumask);
+ buf[ret++] = '\n';
+ buf[ret] = '\0';
+ return ret;
+}
+
+static inline ssize_t pci_bus_show_cpumaskaffinity(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return pci_bus_show_cpuaffinity(dev, 0, attr, buf);
+}
+
+static inline ssize_t pci_bus_show_cpulistaffinity(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return pci_bus_show_cpuaffinity(dev, 1, attr, buf);
+}
+
/* show resources */
static ssize_t
resource_show(struct device * dev, struct device_attribute *attr, char * buf)
@@ -318,6 +352,25 @@ remove_store(struct device *dev, struct device_attribute *dummy,
count = ret;
return count;
}
+
+static ssize_t
+dev_bus_rescan_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ unsigned long val;
+ struct pci_bus *bus = to_pci_bus(dev);
+
+ if (strict_strtoul(buf, 0, &val) < 0)
+ return -EINVAL;
+
+ if (val) {
+ mutex_lock(&pci_remove_rescan_mutex);
+ pci_rescan_bus(bus);
+ mutex_unlock(&pci_remove_rescan_mutex);
+ }
+ return count;
+}
+
#endif
struct device_attribute pci_dev_attrs[] = {
@@ -347,6 +400,15 @@ struct device_attribute pci_dev_attrs[] = {
__ATTR_NULL,
};
+struct device_attribute pcibus_dev_attrs[] = {
+#ifdef CONFIG_HOTPLUG
+ __ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_bus_rescan_store),
+#endif
+ __ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpumaskaffinity, NULL),
+ __ATTR(cpulistaffinity, S_IRUGO, pci_bus_show_cpulistaffinity, NULL),
+ __ATTR_NULL,
+};
+
static ssize_t
boot_vga_show(struct device *dev, struct device_attribute *attr, char *buf)
{
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 2472e7177b4b..56098b3e17c0 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -830,7 +830,7 @@ static int pci_save_pcie_state(struct pci_dev *dev)
dev_err(&dev->dev, "buffer not found in %s\n", __func__);
return -ENOMEM;
}
- cap = (u16 *)&save_state->data[0];
+ cap = (u16 *)&save_state->cap.data[0];
pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &flags);
@@ -863,7 +863,7 @@ static void pci_restore_pcie_state(struct pci_dev *dev)
pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
if (!save_state || pos <= 0)
return;
- cap = (u16 *)&save_state->data[0];
+ cap = (u16 *)&save_state->cap.data[0];
pci_read_config_word(dev, pos + PCI_EXP_FLAGS, &flags);
@@ -899,7 +899,8 @@ static int pci_save_pcix_state(struct pci_dev *dev)
return -ENOMEM;
}
- pci_read_config_word(dev, pos + PCI_X_CMD, (u16 *)save_state->data);
+ pci_read_config_word(dev, pos + PCI_X_CMD,
+ (u16 *)save_state->cap.data);
return 0;
}
@@ -914,7 +915,7 @@ static void pci_restore_pcix_state(struct pci_dev *dev)
pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
if (!save_state || pos <= 0)
return;
- cap = (u16 *)&save_state->data[0];
+ cap = (u16 *)&save_state->cap.data[0];
pci_write_config_word(dev, pos + PCI_X_CMD, cap[i++]);
}
@@ -975,6 +976,104 @@ void pci_restore_state(struct pci_dev *dev)
dev->state_saved = false;
}
+struct pci_saved_state {
+ u32 config_space[16];
+ struct pci_cap_saved_data cap[0];
+};
+
+/**
+ * pci_store_saved_state - Allocate and return an opaque struct containing
+ * the device saved state.
+ * @dev: PCI device that we're dealing with
+ *
+ * Rerturn NULL if no state or error.
+ */
+struct pci_saved_state *pci_store_saved_state(struct pci_dev *dev)
+{
+ struct pci_saved_state *state;
+ struct pci_cap_saved_state *tmp;
+ struct pci_cap_saved_data *cap;
+ struct hlist_node *pos;
+ size_t size;
+
+ if (!dev->state_saved)
+ return NULL;
+
+ size = sizeof(*state) + sizeof(struct pci_cap_saved_data);
+
+ hlist_for_each_entry(tmp, pos, &dev->saved_cap_space, next)
+ size += sizeof(struct pci_cap_saved_data) + tmp->cap.size;
+
+ state = kzalloc(size, GFP_KERNEL);
+ if (!state)
+ return NULL;
+
+ memcpy(state->config_space, dev->saved_config_space,
+ sizeof(state->config_space));
+
+ cap = state->cap;
+ hlist_for_each_entry(tmp, pos, &dev->saved_cap_space, next) {
+ size_t len = sizeof(struct pci_cap_saved_data) + tmp->cap.size;
+ memcpy(cap, &tmp->cap, len);
+ cap = (struct pci_cap_saved_data *)((u8 *)cap + len);
+ }
+ /* Empty cap_save terminates list */
+
+ return state;
+}
+EXPORT_SYMBOL_GPL(pci_store_saved_state);
+
+/**
+ * pci_load_saved_state - Reload the provided save state into struct pci_dev.
+ * @dev: PCI device that we're dealing with
+ * @state: Saved state returned from pci_store_saved_state()
+ */
+int pci_load_saved_state(struct pci_dev *dev, struct pci_saved_state *state)
+{
+ struct pci_cap_saved_data *cap;
+
+ dev->state_saved = false;
+
+ if (!state)
+ return 0;
+
+ memcpy(dev->saved_config_space, state->config_space,
+ sizeof(state->config_space));
+
+ cap = state->cap;
+ while (cap->size) {
+ struct pci_cap_saved_state *tmp;
+
+ tmp = pci_find_saved_cap(dev, cap->cap_nr);
+ if (!tmp || tmp->cap.size != cap->size)
+ return -EINVAL;
+
+ memcpy(tmp->cap.data, cap->data, tmp->cap.size);
+ cap = (struct pci_cap_saved_data *)((u8 *)cap +
+ sizeof(struct pci_cap_saved_data) + cap->size);
+ }
+
+ dev->state_saved = true;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(pci_load_saved_state);
+
+/**
+ * pci_load_and_free_saved_state - Reload the save state pointed to by state,
+ * and free the memory allocated for it.
+ * @dev: PCI device that we're dealing with
+ * @state: Pointer to saved state returned from pci_store_saved_state()
+ */
+int pci_load_and_free_saved_state(struct pci_dev *dev,
+ struct pci_saved_state **state)
+{
+ int ret = pci_load_saved_state(dev, *state);
+ kfree(*state);
+ *state = NULL;
+ return ret;
+}
+EXPORT_SYMBOL_GPL(pci_load_and_free_saved_state);
+
static int do_pci_enable_device(struct pci_dev *dev, int bars)
{
int err;
@@ -1771,7 +1870,8 @@ static int pci_add_cap_save_buffer(
if (!save_state)
return -ENOMEM;
- save_state->cap_nr = cap;
+ save_state->cap.cap_nr = cap;
+ save_state->cap.size = size;
pci_add_saved_cap(dev, save_state);
return 0;
@@ -1834,6 +1934,300 @@ void pci_enable_ari(struct pci_dev *dev)
bridge->ari_enabled = 1;
}
+/**
+ * pci_enable_ido - enable ID-based ordering on a device
+ * @dev: the PCI device
+ * @type: which types of IDO to enable
+ *
+ * Enable ID-based ordering on @dev. @type can contain the bits
+ * %PCI_EXP_IDO_REQUEST and/or %PCI_EXP_IDO_COMPLETION to indicate
+ * which types of transactions are allowed to be re-ordered.
+ */
+void pci_enable_ido(struct pci_dev *dev, unsigned long type)
+{
+ int pos;
+ u16 ctrl;
+
+ pos = pci_pcie_cap(dev);
+ if (!pos)
+ return;
+
+ pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &ctrl);
+ if (type & PCI_EXP_IDO_REQUEST)
+ ctrl |= PCI_EXP_IDO_REQ_EN;
+ if (type & PCI_EXP_IDO_COMPLETION)
+ ctrl |= PCI_EXP_IDO_CMP_EN;
+ pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, ctrl);
+}
+EXPORT_SYMBOL(pci_enable_ido);
+
+/**
+ * pci_disable_ido - disable ID-based ordering on a device
+ * @dev: the PCI device
+ * @type: which types of IDO to disable
+ */
+void pci_disable_ido(struct pci_dev *dev, unsigned long type)
+{
+ int pos;
+ u16 ctrl;
+
+ if (!pci_is_pcie(dev))
+ return;
+
+ pos = pci_pcie_cap(dev);
+ if (!pos)
+ return;
+
+ pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &ctrl);
+ if (type & PCI_EXP_IDO_REQUEST)
+ ctrl &= ~PCI_EXP_IDO_REQ_EN;
+ if (type & PCI_EXP_IDO_COMPLETION)
+ ctrl &= ~PCI_EXP_IDO_CMP_EN;
+ pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, ctrl);
+}
+EXPORT_SYMBOL(pci_disable_ido);
+
+/**
+ * pci_enable_obff - enable optimized buffer flush/fill
+ * @dev: PCI device
+ * @type: type of signaling to use
+ *
+ * Try to enable @type OBFF signaling on @dev. It will try using WAKE#
+ * signaling if possible, falling back to message signaling only if
+ * WAKE# isn't supported. @type should indicate whether the PCIe link
+ * be brought out of L0s or L1 to send the message. It should be either
+ * %PCI_EXP_OBFF_SIGNAL_ALWAYS or %PCI_OBFF_SIGNAL_L0.
+ *
+ * If your device can benefit from receiving all messages, even at the
+ * power cost of bringing the link back up from a low power state, use
+ * %PCI_EXP_OBFF_SIGNAL_ALWAYS. Otherwise, use %PCI_OBFF_SIGNAL_L0 (the
+ * preferred type).
+ *
+ * RETURNS:
+ * Zero on success, appropriate error number on failure.
+ */
+int pci_enable_obff(struct pci_dev *dev, enum pci_obff_signal_type type)
+{
+ int pos;
+ u32 cap;
+ u16 ctrl;
+ int ret;
+
+ if (!pci_is_pcie(dev))
+ return -ENOTSUPP;
+
+ pos = pci_pcie_cap(dev);
+ if (!pos)
+ return -ENOTSUPP;
+
+ pci_read_config_dword(dev, pos + PCI_EXP_DEVCAP2, &cap);
+ if (!(cap & PCI_EXP_OBFF_MASK))
+ return -ENOTSUPP; /* no OBFF support at all */
+
+ /* Make sure the topology supports OBFF as well */
+ if (dev->bus) {
+ ret = pci_enable_obff(dev->bus->self, type);
+ if (ret)
+ return ret;
+ }
+
+ pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &ctrl);
+ if (cap & PCI_EXP_OBFF_WAKE)
+ ctrl |= PCI_EXP_OBFF_WAKE_EN;
+ else {
+ switch (type) {
+ case PCI_EXP_OBFF_SIGNAL_L0:
+ if (!(ctrl & PCI_EXP_OBFF_WAKE_EN))
+ ctrl |= PCI_EXP_OBFF_MSGA_EN;
+ break;
+ case PCI_EXP_OBFF_SIGNAL_ALWAYS:
+ ctrl &= ~PCI_EXP_OBFF_WAKE_EN;
+ ctrl |= PCI_EXP_OBFF_MSGB_EN;
+ break;
+ default:
+ WARN(1, "bad OBFF signal type\n");
+ return -ENOTSUPP;
+ }
+ }
+ pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, ctrl);
+
+ return 0;
+}
+EXPORT_SYMBOL(pci_enable_obff);
+
+/**
+ * pci_disable_obff - disable optimized buffer flush/fill
+ * @dev: PCI device
+ *
+ * Disable OBFF on @dev.
+ */
+void pci_disable_obff(struct pci_dev *dev)
+{
+ int pos;
+ u16 ctrl;
+
+ if (!pci_is_pcie(dev))
+ return;
+
+ pos = pci_pcie_cap(dev);
+ if (!pos)
+ return;
+
+ pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &ctrl);
+ ctrl &= ~PCI_EXP_OBFF_WAKE_EN;
+ pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, ctrl);
+}
+EXPORT_SYMBOL(pci_disable_obff);
+
+/**
+ * pci_ltr_supported - check whether a device supports LTR
+ * @dev: PCI device
+ *
+ * RETURNS:
+ * True if @dev supports latency tolerance reporting, false otherwise.
+ */
+bool pci_ltr_supported(struct pci_dev *dev)
+{
+ int pos;
+ u32 cap;
+
+ if (!pci_is_pcie(dev))
+ return false;
+
+ pos = pci_pcie_cap(dev);
+ if (!pos)
+ return false;
+
+ pci_read_config_dword(dev, pos + PCI_EXP_DEVCAP2, &cap);
+
+ return cap & PCI_EXP_DEVCAP2_LTR;
+}
+EXPORT_SYMBOL(pci_ltr_supported);
+
+/**
+ * pci_enable_ltr - enable latency tolerance reporting
+ * @dev: PCI device
+ *
+ * Enable LTR on @dev if possible, which means enabling it first on
+ * upstream ports.
+ *
+ * RETURNS:
+ * Zero on success, errno on failure.
+ */
+int pci_enable_ltr(struct pci_dev *dev)
+{
+ int pos;
+ u16 ctrl;
+ int ret;
+
+ if (!pci_ltr_supported(dev))
+ return -ENOTSUPP;
+
+ pos = pci_pcie_cap(dev);
+ if (!pos)
+ return -ENOTSUPP;
+
+ /* Only primary function can enable/disable LTR */
+ if (PCI_FUNC(dev->devfn) != 0)
+ return -EINVAL;
+
+ /* Enable upstream ports first */
+ if (dev->bus) {
+ ret = pci_enable_ltr(dev->bus->self);
+ if (ret)
+ return ret;
+ }
+
+ pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &ctrl);
+ ctrl |= PCI_EXP_LTR_EN;
+ pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, ctrl);
+
+ return 0;
+}
+EXPORT_SYMBOL(pci_enable_ltr);
+
+/**
+ * pci_disable_ltr - disable latency tolerance reporting
+ * @dev: PCI device
+ */
+void pci_disable_ltr(struct pci_dev *dev)
+{
+ int pos;
+ u16 ctrl;
+
+ if (!pci_ltr_supported(dev))
+ return;
+
+ pos = pci_pcie_cap(dev);
+ if (!pos)
+ return;
+
+ /* Only primary function can enable/disable LTR */
+ if (PCI_FUNC(dev->devfn) != 0)
+ return;
+
+ pci_read_config_word(dev, pos + PCI_EXP_DEVCTL2, &ctrl);
+ ctrl &= ~PCI_EXP_LTR_EN;
+ pci_write_config_word(dev, pos + PCI_EXP_DEVCTL2, ctrl);
+}
+EXPORT_SYMBOL(pci_disable_ltr);
+
+static int __pci_ltr_scale(int *val)
+{
+ int scale = 0;
+
+ while (*val > 1023) {
+ *val = (*val + 31) / 32;
+ scale++;
+ }
+ return scale;
+}
+
+/**
+ * pci_set_ltr - set LTR latency values
+ * @dev: PCI device
+ * @snoop_lat_ns: snoop latency in nanoseconds
+ * @nosnoop_lat_ns: nosnoop latency in nanoseconds
+ *
+ * Figure out the scale and set the LTR values accordingly.
+ */
+int pci_set_ltr(struct pci_dev *dev, int snoop_lat_ns, int nosnoop_lat_ns)
+{
+ int pos, ret, snoop_scale, nosnoop_scale;
+ u16 val;
+
+ if (!pci_ltr_supported(dev))
+ return -ENOTSUPP;
+
+ snoop_scale = __pci_ltr_scale(&snoop_lat_ns);
+ nosnoop_scale = __pci_ltr_scale(&nosnoop_lat_ns);
+
+ if (snoop_lat_ns > PCI_LTR_VALUE_MASK ||
+ nosnoop_lat_ns > PCI_LTR_VALUE_MASK)
+ return -EINVAL;
+
+ if ((snoop_scale > (PCI_LTR_SCALE_MASK >> PCI_LTR_SCALE_SHIFT)) ||
+ (nosnoop_scale > (PCI_LTR_SCALE_MASK >> PCI_LTR_SCALE_SHIFT)))
+ return -EINVAL;
+
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_LTR);
+ if (!pos)
+ return -ENOTSUPP;
+
+ val = (snoop_scale << PCI_LTR_SCALE_SHIFT) | snoop_lat_ns;
+ ret = pci_write_config_word(dev, pos + PCI_LTR_MAX_SNOOP_LAT, val);
+ if (ret != 4)
+ return -EIO;
+
+ val = (nosnoop_scale << PCI_LTR_SCALE_SHIFT) | nosnoop_lat_ns;
+ ret = pci_write_config_word(dev, pos + PCI_LTR_MAX_NOSNOOP_LAT, val);
+ if (ret != 4)
+ return -EIO;
+
+ return 0;
+}
+EXPORT_SYMBOL(pci_set_ltr);
+
static int pci_acs_enable;
/**
@@ -2479,6 +2873,21 @@ clear:
return 0;
}
+/**
+ * pci_pm_reset - Put device into PCI_D3 and back into PCI_D0.
+ * @dev: Device to reset.
+ * @probe: If set, only check if the device can be reset this way.
+ *
+ * If @dev supports native PCI PM and its PCI_PM_CTRL_NO_SOFT_RESET flag is
+ * unset, it will be reinitialized internally when going from PCI_D3hot to
+ * PCI_D0. If that's the case and the device is not in a low-power state
+ * already, force it into PCI_D3hot and back to PCI_D0, causing it to be reset.
+ *
+ * NOTE: This causes the caller to sleep for twice the device power transition
+ * cooldown period, which for the D0->D3hot and D3hot->D0 transitions is 10 ms
+ * by devault (i.e. unless the @dev's d3_delay field has a different value).
+ * Moreover, only devices in D0 can be reset by this function.
+ */
static int pci_pm_reset(struct pci_dev *dev, int probe)
{
u16 csr;
@@ -2875,31 +3284,34 @@ static int pci_set_vga_state_arch(struct pci_dev *dev, bool decode,
* @dev: the PCI device
* @decode: true = enable decoding, false = disable decoding
* @command_bits: PCI_COMMAND_IO and/or PCI_COMMAND_MEMORY
- * @change_bridge: traverse ancestors and change bridges
+ * @change_bridge_flags: traverse ancestors and change bridges
+ * CHANGE_BRIDGE_ONLY / CHANGE_BRIDGE
*/
int pci_set_vga_state(struct pci_dev *dev, bool decode,
- unsigned int command_bits, bool change_bridge)
+ unsigned int command_bits, u32 flags)
{
struct pci_bus *bus;
struct pci_dev *bridge;
u16 cmd;
int rc;
- WARN_ON(command_bits & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY));
+ WARN_ON((flags & PCI_VGA_STATE_CHANGE_DECODES) & (command_bits & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY)));
/* ARCH specific VGA enables */
- rc = pci_set_vga_state_arch(dev, decode, command_bits, change_bridge);
+ rc = pci_set_vga_state_arch(dev, decode, command_bits, flags);
if (rc)
return rc;
- pci_read_config_word(dev, PCI_COMMAND, &cmd);
- if (decode == true)
- cmd |= command_bits;
- else
- cmd &= ~command_bits;
- pci_write_config_word(dev, PCI_COMMAND, cmd);
+ if (flags & PCI_VGA_STATE_CHANGE_DECODES) {
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ if (decode == true)
+ cmd |= command_bits;
+ else
+ cmd &= ~command_bits;
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ }
- if (change_bridge == false)
+ if (!(flags & PCI_VGA_STATE_CHANGE_BRIDGE))
return 0;
bus = dev->bus;
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index a6ec200fe5ee..731e20265ace 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -156,8 +156,7 @@ static inline int pci_no_d1d2(struct pci_dev *dev)
}
extern struct device_attribute pci_dev_attrs[];
-extern struct device_attribute dev_attr_cpuaffinity;
-extern struct device_attribute dev_attr_cpulistaffinity;
+extern struct device_attribute pcibus_dev_attrs[];
#ifdef CONFIG_HOTPLUG
extern struct bus_attribute pci_bus_attrs[];
#else
@@ -250,15 +249,6 @@ struct pci_sriov {
u8 __iomem *mstate; /* VF Migration State Array */
};
-/* Address Translation Service */
-struct pci_ats {
- int pos; /* capability position */
- int stu; /* Smallest Translation Unit */
- int qdep; /* Invalidate Queue Depth */
- int ref_cnt; /* Physical Function reference count */
- unsigned int is_enabled:1; /* Enable bit is set */
-};
-
#ifdef CONFIG_PCI_IOV
extern int pci_iov_init(struct pci_dev *dev);
extern void pci_iov_release(struct pci_dev *dev);
@@ -269,19 +259,6 @@ extern resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev,
extern void pci_restore_iov_state(struct pci_dev *dev);
extern int pci_iov_bus_range(struct pci_bus *bus);
-extern int pci_enable_ats(struct pci_dev *dev, int ps);
-extern void pci_disable_ats(struct pci_dev *dev);
-extern int pci_ats_queue_depth(struct pci_dev *dev);
-/**
- * pci_ats_enabled - query the ATS status
- * @dev: the PCI device
- *
- * Returns 1 if ATS capability is enabled, or 0 if not.
- */
-static inline int pci_ats_enabled(struct pci_dev *dev)
-{
- return dev->ats && dev->ats->is_enabled;
-}
#else
static inline int pci_iov_init(struct pci_dev *dev)
{
@@ -304,21 +281,6 @@ static inline int pci_iov_bus_range(struct pci_bus *bus)
return 0;
}
-static inline int pci_enable_ats(struct pci_dev *dev, int ps)
-{
- return -ENODEV;
-}
-static inline void pci_disable_ats(struct pci_dev *dev)
-{
-}
-static inline int pci_ats_queue_depth(struct pci_dev *dev)
-{
- return -ENODEV;
-}
-static inline int pci_ats_enabled(struct pci_dev *dev)
-{
- return 0;
-}
#endif /* CONFIG_PCI_IOV */
static inline resource_size_t pci_resource_alignment(struct pci_dev *dev,
diff --git a/drivers/pci/pcie/aer/aer_inject.c b/drivers/pci/pcie/aer/aer_inject.c
index f62079ff06dd..95489cd9a555 100644
--- a/drivers/pci/pcie/aer/aer_inject.c
+++ b/drivers/pci/pcie/aer/aer_inject.c
@@ -326,7 +326,7 @@ static int aer_inject(struct aer_error_inj *einj)
unsigned long flags;
unsigned int devfn = PCI_DEVFN(einj->dev, einj->fn);
int pos_cap_err, rp_pos_cap_err;
- u32 sever, cor_mask, uncor_mask, cor_mask_orig, uncor_mask_orig;
+ u32 sever, cor_mask, uncor_mask, cor_mask_orig = 0, uncor_mask_orig = 0;
int ret = 0;
dev = pci_get_domain_bus_and_slot((int)einj->domain, einj->bus, devfn);
diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h
index 3eb77080366a..94a7598eb262 100644
--- a/drivers/pci/pcie/aer/aerdrv.h
+++ b/drivers/pci/pcie/aer/aerdrv.h
@@ -114,15 +114,6 @@ extern void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
extern void aer_print_port_info(struct pci_dev *dev, struct aer_err_info *info);
extern irqreturn_t aer_irq(int irq, void *context);
-#ifdef CONFIG_ACPI
-extern int aer_osc_setup(struct pcie_device *pciedev);
-#else
-static inline int aer_osc_setup(struct pcie_device *pciedev)
-{
- return 0;
-}
-#endif
-
#ifdef CONFIG_ACPI_APEI
extern int pcie_aer_get_firmware_first(struct pci_dev *pci_dev);
#else
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index eee09f756ec9..6892601fc76f 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -608,7 +608,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
* the BIOS's expectation, we'll do so once pci_enable_device() is
* called.
*/
- if (aspm_policy != POLICY_POWERSAVE) {
+ if (aspm_policy != POLICY_POWERSAVE || aspm_clear_state) {
pcie_config_aspm_path(link);
pcie_set_clkpm(link, policy_to_clkpm_state(link));
}
@@ -734,7 +734,7 @@ void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
* pci_disable_link_state - disable pci device's link state, so the link will
* never enter specific states
*/
-void pci_disable_link_state(struct pci_dev *pdev, int state)
+static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
{
struct pci_dev *parent = pdev->bus->self;
struct pcie_link_state *link;
@@ -747,7 +747,8 @@ void pci_disable_link_state(struct pci_dev *pdev, int state)
if (!parent || !parent->link_state)
return;
- down_read(&pci_bus_sem);
+ if (sem)
+ down_read(&pci_bus_sem);
mutex_lock(&aspm_lock);
link = parent->link_state;
if (state & PCIE_LINK_STATE_L0S)
@@ -761,7 +762,19 @@ void pci_disable_link_state(struct pci_dev *pdev, int state)
pcie_set_clkpm(link, 0);
}
mutex_unlock(&aspm_lock);
- up_read(&pci_bus_sem);
+ if (sem)
+ up_read(&pci_bus_sem);
+}
+
+void pci_disable_link_state_locked(struct pci_dev *pdev, int state)
+{
+ __pci_disable_link_state(pdev, state, false);
+}
+EXPORT_SYMBOL(pci_disable_link_state_locked);
+
+void pci_disable_link_state(struct pci_dev *pdev, int state)
+{
+ __pci_disable_link_state(pdev, state, true);
}
EXPORT_SYMBOL(pci_disable_link_state);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 44cbbbaa499d..48849ffdd672 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -43,43 +43,6 @@ int no_pci_devices(void)
EXPORT_SYMBOL(no_pci_devices);
/*
- * PCI Bus Class Devices
- */
-static ssize_t pci_bus_show_cpuaffinity(struct device *dev,
- int type,
- struct device_attribute *attr,
- char *buf)
-{
- int ret;
- const struct cpumask *cpumask;
-
- cpumask = cpumask_of_pcibus(to_pci_bus(dev));
- ret = type?
- cpulist_scnprintf(buf, PAGE_SIZE-2, cpumask) :
- cpumask_scnprintf(buf, PAGE_SIZE-2, cpumask);
- buf[ret++] = '\n';
- buf[ret] = '\0';
- return ret;
-}
-
-static ssize_t inline pci_bus_show_cpumaskaffinity(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return pci_bus_show_cpuaffinity(dev, 0, attr, buf);
-}
-
-static ssize_t inline pci_bus_show_cpulistaffinity(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return pci_bus_show_cpuaffinity(dev, 1, attr, buf);
-}
-
-DEVICE_ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpumaskaffinity, NULL);
-DEVICE_ATTR(cpulistaffinity, S_IRUGO, pci_bus_show_cpulistaffinity, NULL);
-
-/*
* PCI Bus Class
*/
static void release_pcibus_dev(struct device *dev)
@@ -95,6 +58,7 @@ static void release_pcibus_dev(struct device *dev)
static struct class pcibus_class = {
.name = "pci_bus",
.dev_release = &release_pcibus_dev,
+ .dev_attrs = pcibus_dev_attrs,
};
static int __init pcibus_class_init(void)
@@ -1455,9 +1419,6 @@ struct pci_bus * pci_create_bus(struct device *parent,
error = device_register(&b->dev);
if (error)
goto class_dev_reg_err;
- error = device_create_file(&b->dev, &dev_attr_cpuaffinity);
- if (error)
- goto dev_create_file_err;
/* Create legacy_io and legacy_mem files for this bus */
pci_create_legacy_files(b);
@@ -1468,8 +1429,6 @@ struct pci_bus * pci_create_bus(struct device *parent,
return b;
-dev_create_file_err:
- device_unregister(&b->dev);
class_dev_reg_err:
device_unregister(dev);
dev_reg_err:
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 5129ed6d8fa7..e8a140669f90 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -606,7 +606,7 @@ static void __devinit ich6_lpc_acpi_gpio(struct pci_dev *dev)
}
pci_read_config_byte(dev, ICH6_GPIO_CNTL, &enable);
- if (enable & ICH4_GPIO_EN) {
+ if (enable & ICH6_GPIO_EN) {
pci_read_config_dword(dev, ICH6_GPIOBASE, &region);
region &= PCI_BASE_ADDRESS_IO_MASK;
if (region >= PCIBIOS_MIN_IO)
@@ -681,7 +681,7 @@ static void __devinit ich7_lpc_generic_decode(struct pci_dev *dev, unsigned reg,
/* ICH7-10 has the same common LPC generic IO decode registers */
static void __devinit quirk_ich7_lpc(struct pci_dev *dev)
{
- /* We share the common ACPI/DPIO decode with ICH6 */
+ /* We share the common ACPI/GPIO decode with ICH6 */
ich6_lpc_acpi_gpio(dev);
/* And have 4 ICH7+ generic decodes */
@@ -2349,8 +2349,11 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8132_BRIDGE,
*/
static void __devinit nvenet_msi_disable(struct pci_dev *dev)
{
- if (dmi_name_in_vendors("P5N32-SLI PREMIUM") ||
- dmi_name_in_vendors("P5N32-E SLI")) {
+ const char *board_name = dmi_get_system_info(DMI_BOARD_NAME);
+
+ if (board_name &&
+ (strstr(board_name, "P5N32-SLI PREMIUM") ||
+ strstr(board_name, "P5N32-E SLI"))) {
dev_info(&dev->dev,
"Disabling msi for MCP55 NIC on P5N32-SLI\n");
dev->no_msi = 1;
@@ -2784,6 +2787,16 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x342e, vtd_mask_spec_errors);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x3c28, vtd_mask_spec_errors);
#endif
+static void __devinit fixup_ti816x_class(struct pci_dev* dev)
+{
+ /* TI 816x devices do not have class code set when in PCIe boot mode */
+ if (dev->class == PCI_CLASS_NOT_DEFINED) {
+ dev_info(&dev->dev, "Setting PCI class for 816x PCIe device\n");
+ dev->class = PCI_CLASS_MULTIMEDIA_VIDEO;
+ }
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_TI, 0xb800, fixup_ti816x_class);
+
static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f,
struct pci_fixup *end)
{
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 176615e7231f..7f87beed35ac 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -73,8 +73,6 @@ void pci_remove_bus(struct pci_bus *pci_bus)
return;
pci_remove_legacy_files(pci_bus);
- device_remove_file(&pci_bus->dev, &dev_attr_cpuaffinity);
- device_remove_file(&pci_bus->dev, &dev_attr_cpulistaffinity);
device_unregister(&pci_bus->dev);
}
EXPORT_SYMBOL(pci_remove_bus);
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index a806cb321d2e..1e9e5a5b8c81 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -991,30 +991,139 @@ static void pci_bus_dump_resources(struct pci_bus *bus)
}
}
+static int __init pci_bus_get_depth(struct pci_bus *bus)
+{
+ int depth = 0;
+ struct pci_dev *dev;
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ int ret;
+ struct pci_bus *b = dev->subordinate;
+ if (!b)
+ continue;
+
+ ret = pci_bus_get_depth(b);
+ if (ret + 1 > depth)
+ depth = ret + 1;
+ }
+
+ return depth;
+}
+static int __init pci_get_max_depth(void)
+{
+ int depth = 0;
+ struct pci_bus *bus;
+
+ list_for_each_entry(bus, &pci_root_buses, node) {
+ int ret;
+
+ ret = pci_bus_get_depth(bus);
+ if (ret > depth)
+ depth = ret;
+ }
+
+ return depth;
+}
+
+/*
+ * first try will not touch pci bridge res
+ * second and later try will clear small leaf bridge res
+ * will stop till to the max deepth if can not find good one
+ */
void __init
pci_assign_unassigned_resources(void)
{
struct pci_bus *bus;
struct resource_list_x add_list; /* list of resources that
want additional resources */
+ int tried_times = 0;
+ enum release_type rel_type = leaf_only;
+ struct resource_list_x head, *list;
+ unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
+ IORESOURCE_PREFETCH;
+ unsigned long failed_type;
+ int max_depth = pci_get_max_depth();
+ int pci_try_num;
+
+
+ head.next = NULL;
add_list.next = NULL;
+
+ pci_try_num = max_depth + 1;
+ printk(KERN_DEBUG "PCI: max bus depth: %d pci_try_num: %d\n",
+ max_depth, pci_try_num);
+
+again:
/* Depth first, calculate sizes and alignments of all
subordinate buses. */
- list_for_each_entry(bus, &pci_root_buses, node) {
+ list_for_each_entry(bus, &pci_root_buses, node)
__pci_bus_size_bridges(bus, &add_list);
- }
/* Depth last, allocate resources and update the hardware. */
- list_for_each_entry(bus, &pci_root_buses, node) {
- __pci_bus_assign_resources(bus, &add_list, NULL);
- pci_enable_bridges(bus);
- }
+ list_for_each_entry(bus, &pci_root_buses, node)
+ __pci_bus_assign_resources(bus, &add_list, &head);
BUG_ON(add_list.next);
+ tried_times++;
+
+ /* any device complain? */
+ if (!head.next)
+ goto enable_and_dump;
+ failed_type = 0;
+ for (list = head.next; list;) {
+ failed_type |= list->flags;
+ list = list->next;
+ }
+ /*
+ * io port are tight, don't try extra
+ * or if reach the limit, don't want to try more
+ */
+ failed_type &= type_mask;
+ if ((failed_type == IORESOURCE_IO) || (tried_times >= pci_try_num)) {
+ free_list(resource_list_x, &head);
+ goto enable_and_dump;
+ }
+
+ printk(KERN_DEBUG "PCI: No. %d try to assign unassigned res\n",
+ tried_times + 1);
+
+ /* third times and later will not check if it is leaf */
+ if ((tried_times + 1) > 2)
+ rel_type = whole_subtree;
+
+ /*
+ * Try to release leaf bridge's resources that doesn't fit resource of
+ * child device under that bridge
+ */
+ for (list = head.next; list;) {
+ bus = list->dev->bus;
+ pci_bus_release_bridge_resources(bus, list->flags & type_mask,
+ rel_type);
+ list = list->next;
+ }
+ /* restore size and flags */
+ for (list = head.next; list;) {
+ struct resource *res = list->res;
+
+ res->start = list->start;
+ res->end = list->end;
+ res->flags = list->flags;
+ if (list->dev->subordinate)
+ res->flags = 0;
+
+ list = list->next;
+ }
+ free_list(resource_list_x, &head);
+
+ goto again;
+
+enable_and_dump:
+ /* Depth last, update the hardware. */
+ list_for_each_entry(bus, &pci_root_buses, node)
+ pci_enable_bridges(bus);
/* dump the resource on buses */
- list_for_each_entry(bus, &pci_root_buses, node) {
+ list_for_each_entry(bus, &pci_root_buses, node)
pci_bus_dump_resources(bus);
- }
}
void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 100c4412457d..749c2a16012c 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -45,7 +45,7 @@ MODULE_LICENSE("GPL");
static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
{
- struct pcmcia_device_id *did = p_drv->id_table;
+ const struct pcmcia_device_id *did = p_drv->id_table;
unsigned int i;
u32 hash;
@@ -784,7 +784,7 @@ static inline int pcmcia_load_firmware(struct pcmcia_device *dev, char * filenam
static inline int pcmcia_devmatch(struct pcmcia_device *dev,
- struct pcmcia_device_id *did)
+ const struct pcmcia_device_id *did)
{
if (did->match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID) {
if ((!dev->has_manf_id) || (dev->manf_id != did->manf_id))
@@ -890,7 +890,7 @@ static int pcmcia_bus_match(struct device *dev, struct device_driver *drv)
{
struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
struct pcmcia_driver *p_drv = to_pcmcia_drv(drv);
- struct pcmcia_device_id *did = p_drv->id_table;
+ const struct pcmcia_device_id *did = p_drv->id_table;
struct pcmcia_dynid *dynid;
/* match dynamic devices first */
diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c
index fb9740d3e9a7..2eea664bc079 100644
--- a/drivers/pcmcia/sa1100_generic.c
+++ b/drivers/pcmcia/sa1100_generic.c
@@ -43,7 +43,7 @@
int __init pcmcia_collie_init(struct device *dev);
-static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) = {
+static int (*sa11x0_pcmcia_hw_init[])(struct device *dev) __devinitdata = {
#ifdef CONFIG_SA1100_ASSABET
pcmcia_assabet_init,
#endif
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 0485e394712a..5cb999b50f95 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -111,7 +111,7 @@ config DELL_WMI_AIO
All-In-One machines.
To compile this driver as a module, choose M here: the module will
- be called dell-wmi.
+ be called dell-wmi-aio.
config FUJITSU_LAPTOP
@@ -753,4 +753,11 @@ config SAMSUNG_LAPTOP
To compile this driver as a module, choose M here: the module
will be called samsung-laptop.
+config MXM_WMI
+ tristate "WMI support for MXM Laptop Graphics"
+ depends on ACPI_WMI
+ ---help---
+ MXM is a standard for laptop graphics cards, the WMI interface
+ is required for switchable nvidia graphics machines
+
endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 029e8861d086..a7ab3bc7b3a1 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -42,3 +42,4 @@ obj-$(CONFIG_XO15_EBOOK) += xo15-ebook.o
obj-$(CONFIG_IBM_RTL) += ibm_rtl.o
obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o
obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o
+obj-$(CONFIG_MXM_WMI) += mxm-wmi.o
diff --git a/drivers/platform/x86/ibm_rtl.c b/drivers/platform/x86/ibm_rtl.c
index 94a114aa8e28..b1396e5b2953 100644
--- a/drivers/platform/x86/ibm_rtl.c
+++ b/drivers/platform/x86/ibm_rtl.c
@@ -81,6 +81,19 @@ static void __iomem *rtl_cmd_addr;
static u8 rtl_cmd_type;
static u8 rtl_cmd_width;
+#ifndef readq
+static inline __u64 readq(const volatile void __iomem *addr)
+{
+ const volatile u32 __iomem *p = addr;
+ u32 low, high;
+
+ low = readl(p);
+ high = readl(p + 1);
+
+ return low + ((u64)high << 32);
+}
+#endif
+
static void __iomem *rtl_port_map(phys_addr_t addr, unsigned long len)
{
if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c
index 85c8ad43c0c5..5ffe7c398148 100644
--- a/drivers/platform/x86/intel_ips.c
+++ b/drivers/platform/x86/intel_ips.c
@@ -344,6 +344,19 @@ struct ips_driver {
static bool
ips_gpu_turbo_enabled(struct ips_driver *ips);
+#ifndef readq
+static inline __u64 readq(const volatile void __iomem *addr)
+{
+ const volatile u32 __iomem *p = addr;
+ u32 low, high;
+
+ low = readl(p);
+ high = readl(p + 1);
+
+ return low + ((u64)high << 32);
+}
+#endif
+
/**
* ips_cpu_busy - is CPU busy?
* @ips: IPS driver struct
diff --git a/drivers/platform/x86/mxm-wmi.c b/drivers/platform/x86/mxm-wmi.c
new file mode 100644
index 000000000000..0aea63b3729a
--- /dev/null
+++ b/drivers/platform/x86/mxm-wmi.c
@@ -0,0 +1,111 @@
+/*
+ * MXM WMI driver
+ *
+ * Copyright(C) 2010 Red Hat.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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 <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+MODULE_AUTHOR("Dave Airlie");
+MODULE_DESCRIPTION("MXM WMI Driver");
+MODULE_LICENSE("GPL");
+
+#define MXM_WMMX_GUID "F6CB5C3C-9CAE-4EBD-B577-931EA32A2CC0"
+
+MODULE_ALIAS("wmi:"MXM_WMMX_GUID);
+
+#define MXM_WMMX_FUNC_MXDS 0x5344584D /* "MXDS" */
+#define MXM_WMMX_FUNC_MXMX 0x53445344 /* "MXMX" */
+
+struct mxds_args {
+ u32 func;
+ u32 args;
+ u32 xarg;
+};
+
+int mxm_wmi_call_mxds(int adapter)
+{
+ struct mxds_args args = {
+ .func = MXM_WMMX_FUNC_MXDS,
+ .args = 0,
+ .xarg = 1,
+ };
+ struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ acpi_status status;
+
+ printk("calling mux switch %d\n", adapter);
+
+ status = wmi_evaluate_method(MXM_WMMX_GUID, 0x1, adapter, &input,
+ &output);
+
+ if (ACPI_FAILURE(status))
+ return status;
+
+ printk("mux switched %d\n", status);
+ return 0;
+
+}
+EXPORT_SYMBOL_GPL(mxm_wmi_call_mxds);
+
+int mxm_wmi_call_mxmx(int adapter)
+{
+ struct mxds_args args = {
+ .func = MXM_WMMX_FUNC_MXMX,
+ .args = 0,
+ .xarg = 1,
+ };
+ struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ acpi_status status;
+
+ printk("calling mux switch %d\n", adapter);
+
+ status = wmi_evaluate_method(MXM_WMMX_GUID, 0x1, adapter, &input,
+ &output);
+
+ if (ACPI_FAILURE(status))
+ return status;
+
+ printk("mux mutex set switched %d\n", status);
+ return 0;
+
+}
+EXPORT_SYMBOL_GPL(mxm_wmi_call_mxmx);
+
+bool mxm_wmi_supported(void)
+{
+ bool guid_valid;
+ guid_valid = wmi_has_guid(MXM_WMMX_GUID);
+ return guid_valid;
+}
+EXPORT_SYMBOL_GPL(mxm_wmi_supported);
+
+static int __init mxm_wmi_init(void)
+{
+ return 0;
+}
+
+static void __exit mxm_wmi_exit(void)
+{
+}
+
+module_init(mxm_wmi_init);
+module_exit(mxm_wmi_exit);
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 52a462fc6b84..e57b50b38565 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -68,6 +68,13 @@ config BATTERY_DS2760
help
Say Y here to enable support for batteries with ds2760 chip.
+config BATTERY_DS2780
+ tristate "DS2780 battery driver"
+ select W1
+ select W1_SLAVE_DS2780
+ help
+ Say Y here to enable support for batteries with ds2780 chip.
+
config BATTERY_DS2782
tristate "DS2782/DS2786 standalone gas-gauge"
depends on I2C
@@ -203,6 +210,15 @@ config CHARGER_ISP1704
Say Y to enable support for USB Charger Detection with
ISP1707/ISP1704 USB transceivers.
+config CHARGER_MAX8903
+ tristate "MAX8903 Battery DC-DC Charger for USB and Adapter Power"
+ depends on GENERIC_HARDIRQS
+ help
+ Say Y to enable support for the MAX8903 DC-DC charger and sysfs.
+ The driver supports controlling charger-enable and current-limit
+ pins based on the status of charger connections with interrupt
+ handlers.
+
config CHARGER_TWL4030
tristate "OMAP TWL4030 BCI charger driver"
depends on TWL4030_CORE
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 8385bfae8728..009a90fa8ac9 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_WM8350_POWER) += wm8350_power.o
obj-$(CONFIG_TEST_POWER) += test_power.o
obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o
+obj-$(CONFIG_BATTERY_DS2780) += ds2780_battery.o
obj-$(CONFIG_BATTERY_DS2782) += ds2782_battery.o
obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o
obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o
@@ -32,5 +33,6 @@ obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o
obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o
obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o
+obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o
obj-$(CONFIG_CHARGER_TWL4030) += twl4030_charger.o
obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c
index 59e68dbd028b..bb16f5b7e167 100644
--- a/drivers/power/bq27x00_battery.c
+++ b/drivers/power/bq27x00_battery.c
@@ -4,6 +4,7 @@
* Copyright (C) 2008 Rodolfo Giometti <giometti@linux.it>
* Copyright (C) 2008 Eurotech S.p.A. <info@eurotech.it>
* Copyright (C) 2010-2011 Lars-Peter Clausen <lars@metafoo.de>
+ * Copyright (C) 2011 Pali Rohár <pali.rohar@gmail.com>
*
* Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc.
*
@@ -76,7 +77,7 @@ struct bq27x00_reg_cache {
int time_to_empty_avg;
int time_to_full;
int charge_full;
- int charge_counter;
+ int cycle_count;
int capacity;
int flags;
@@ -115,7 +116,7 @@ static enum power_supply_property bq27x00_battery_props[] = {
POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_CHARGE_NOW,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
- POWER_SUPPLY_PROP_CHARGE_COUNTER,
+ POWER_SUPPLY_PROP_CYCLE_COUNT,
POWER_SUPPLY_PROP_ENERGY_NOW,
};
@@ -267,7 +268,7 @@ static void bq27x00_update(struct bq27x00_device_info *di)
cache.time_to_empty_avg = bq27x00_battery_read_time(di, BQ27x00_REG_TTECP);
cache.time_to_full = bq27x00_battery_read_time(di, BQ27x00_REG_TTF);
cache.charge_full = bq27x00_battery_read_lmd(di);
- cache.charge_counter = bq27x00_battery_read_cyct(di);
+ cache.cycle_count = bq27x00_battery_read_cyct(di);
if (!is_bq27500)
cache.current_now = bq27x00_read(di, BQ27x00_REG_AI, false);
@@ -496,8 +497,8 @@ static int bq27x00_battery_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
ret = bq27x00_simple_value(di->charge_design_full, val);
break;
- case POWER_SUPPLY_PROP_CHARGE_COUNTER:
- ret = bq27x00_simple_value(di->cache.charge_counter, val);
+ case POWER_SUPPLY_PROP_CYCLE_COUNT:
+ ret = bq27x00_simple_value(di->cache.cycle_count, val);
break;
case POWER_SUPPLY_PROP_ENERGY_NOW:
ret = bq27x00_battery_energy(di, val);
diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c
index e534290f3256..f2c9cc33c0f9 100644
--- a/drivers/power/ds2760_battery.c
+++ b/drivers/power/ds2760_battery.c
@@ -86,7 +86,11 @@ static int rated_capacities[] = {
920, /* NEC */
1440, /* Samsung */
1440, /* BYD */
+#ifdef CONFIG_MACH_H4700
+ 1800, /* HP iPAQ hx4700 3.7V 1800mAh (359113-001) */
+#else
1440, /* Lishen */
+#endif
1440, /* NEC */
2880, /* Samsung */
2880, /* BYD */
@@ -186,7 +190,7 @@ static int ds2760_battery_read_status(struct ds2760_device_info *di)
scale[0] = di->full_active_uAh;
for (i = 1; i < 5; i++)
- scale[i] = scale[i - 1] + di->raw[DS2760_ACTIVE_FULL + 2 + i];
+ scale[i] = scale[i - 1] + di->raw[DS2760_ACTIVE_FULL + 1 + i];
di->full_active_uAh = battery_interpolate(scale, di->temp_C / 10);
di->full_active_uAh *= 1000; /* convert to µAh */
diff --git a/drivers/power/ds2780_battery.c b/drivers/power/ds2780_battery.c
new file mode 100644
index 000000000000..1fefe82e12e3
--- /dev/null
+++ b/drivers/power/ds2780_battery.c
@@ -0,0 +1,853 @@
+/*
+ * 1-wire client/driver for the Maxim/Dallas DS2780 Stand-Alone Fuel Gauge IC
+ *
+ * Copyright (C) 2010 Indesign, LLC
+ *
+ * Author: Clifton Barnes <cabarnes@indesign-llc.com>
+ *
+ * Based on ds2760_battery and ds2782_battery drivers
+ *
+ * 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/slab.h>
+#include <linux/param.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/idr.h>
+
+#include "../w1/w1.h"
+#include "../w1/slaves/w1_ds2780.h"
+
+/* Current unit measurement in uA for a 1 milli-ohm sense resistor */
+#define DS2780_CURRENT_UNITS 1563
+/* Charge unit measurement in uAh for a 1 milli-ohm sense resistor */
+#define DS2780_CHARGE_UNITS 6250
+/* Number of bytes in user EEPROM space */
+#define DS2780_USER_EEPROM_SIZE (DS2780_EEPROM_BLOCK0_END - \
+ DS2780_EEPROM_BLOCK0_START + 1)
+/* Number of bytes in parameter EEPROM space */
+#define DS2780_PARAM_EEPROM_SIZE (DS2780_EEPROM_BLOCK1_END - \
+ DS2780_EEPROM_BLOCK1_START + 1)
+
+struct ds2780_device_info {
+ struct device *dev;
+ struct power_supply bat;
+ struct device *w1_dev;
+};
+
+enum current_types {
+ CURRENT_NOW,
+ CURRENT_AVG,
+};
+
+static const char model[] = "DS2780";
+static const char manufacturer[] = "Maxim/Dallas";
+
+static inline struct ds2780_device_info *to_ds2780_device_info(
+ struct power_supply *psy)
+{
+ return container_of(psy, struct ds2780_device_info, bat);
+}
+
+static inline struct power_supply *to_power_supply(struct device *dev)
+{
+ return dev_get_drvdata(dev);
+}
+
+static inline int ds2780_read8(struct device *dev, u8 *val, int addr)
+{
+ return w1_ds2780_io(dev, val, addr, sizeof(u8), 0);
+}
+
+static int ds2780_read16(struct device *dev, s16 *val, int addr)
+{
+ int ret;
+ u8 raw[2];
+
+ ret = w1_ds2780_io(dev, raw, addr, sizeof(u8) * 2, 0);
+ if (ret < 0)
+ return ret;
+
+ *val = (raw[0] << 8) | raw[1];
+
+ return 0;
+}
+
+static inline int ds2780_read_block(struct device *dev, u8 *val, int addr,
+ size_t count)
+{
+ return w1_ds2780_io(dev, val, addr, count, 0);
+}
+
+static inline int ds2780_write(struct device *dev, u8 *val, int addr,
+ size_t count)
+{
+ return w1_ds2780_io(dev, val, addr, count, 1);
+}
+
+static inline int ds2780_store_eeprom(struct device *dev, int addr)
+{
+ return w1_ds2780_eeprom_cmd(dev, addr, W1_DS2780_COPY_DATA);
+}
+
+static inline int ds2780_recall_eeprom(struct device *dev, int addr)
+{
+ return w1_ds2780_eeprom_cmd(dev, addr, W1_DS2780_RECALL_DATA);
+}
+
+static int ds2780_save_eeprom(struct ds2780_device_info *dev_info, int reg)
+{
+ int ret;
+
+ ret = ds2780_store_eeprom(dev_info->w1_dev, reg);
+ if (ret < 0)
+ return ret;
+
+ ret = ds2780_recall_eeprom(dev_info->w1_dev, reg);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/* Set sense resistor value in mhos */
+static int ds2780_set_sense_register(struct ds2780_device_info *dev_info,
+ u8 conductance)
+{
+ int ret;
+
+ ret = ds2780_write(dev_info->w1_dev, &conductance,
+ DS2780_RSNSP_REG, sizeof(u8));
+ if (ret < 0)
+ return ret;
+
+ return ds2780_save_eeprom(dev_info, DS2780_RSNSP_REG);
+}
+
+/* Get RSGAIN value from 0 to 1.999 in steps of 0.001 */
+static int ds2780_get_rsgain_register(struct ds2780_device_info *dev_info,
+ u16 *rsgain)
+{
+ return ds2780_read16(dev_info->w1_dev, rsgain, DS2780_RSGAIN_MSB_REG);
+}
+
+/* Set RSGAIN value from 0 to 1.999 in steps of 0.001 */
+static int ds2780_set_rsgain_register(struct ds2780_device_info *dev_info,
+ u16 rsgain)
+{
+ int ret;
+ u8 raw[] = {rsgain >> 8, rsgain & 0xFF};
+
+ ret = ds2780_write(dev_info->w1_dev, raw,
+ DS2780_RSGAIN_MSB_REG, sizeof(u8) * 2);
+ if (ret < 0)
+ return ret;
+
+ return ds2780_save_eeprom(dev_info, DS2780_RSGAIN_MSB_REG);
+}
+
+static int ds2780_get_voltage(struct ds2780_device_info *dev_info,
+ int *voltage_uV)
+{
+ int ret;
+ s16 voltage_raw;
+
+ /*
+ * The voltage value is located in 10 bits across the voltage MSB
+ * and LSB registers in two's compliment form
+ * Sign bit of the voltage value is in bit 7 of the voltage MSB register
+ * Bits 9 - 3 of the voltage value are in bits 6 - 0 of the
+ * voltage MSB register
+ * Bits 2 - 0 of the voltage value are in bits 7 - 5 of the
+ * voltage LSB register
+ */
+ ret = ds2780_read16(dev_info->w1_dev, &voltage_raw,
+ DS2780_VOLT_MSB_REG);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * DS2780 reports voltage in units of 4.88mV, but the battery class
+ * reports in units of uV, so convert by multiplying by 4880.
+ */
+ *voltage_uV = (voltage_raw / 32) * 4880;
+ return 0;
+}
+
+static int ds2780_get_temperature(struct ds2780_device_info *dev_info,
+ int *temperature)
+{
+ int ret;
+ s16 temperature_raw;
+
+ /*
+ * The temperature value is located in 10 bits across the temperature
+ * MSB and LSB registers in two's compliment form
+ * Sign bit of the temperature value is in bit 7 of the temperature
+ * MSB register
+ * Bits 9 - 3 of the temperature value are in bits 6 - 0 of the
+ * temperature MSB register
+ * Bits 2 - 0 of the temperature value are in bits 7 - 5 of the
+ * temperature LSB register
+ */
+ ret = ds2780_read16(dev_info->w1_dev, &temperature_raw,
+ DS2780_TEMP_MSB_REG);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Temperature is measured in units of 0.125 degrees celcius, the
+ * power_supply class measures temperature in tenths of degrees
+ * celsius. The temperature value is stored as a 10 bit number, plus
+ * sign in the upper bits of a 16 bit register.
+ */
+ *temperature = ((temperature_raw / 32) * 125) / 100;
+ return 0;
+}
+
+static int ds2780_get_current(struct ds2780_device_info *dev_info,
+ enum current_types type, int *current_uA)
+{
+ int ret, sense_res;
+ s16 current_raw;
+ u8 sense_res_raw, reg_msb;
+
+ /*
+ * The units of measurement for current are dependent on the value of
+ * the sense resistor.
+ */
+ ret = ds2780_read8(dev_info->w1_dev, &sense_res_raw, DS2780_RSNSP_REG);
+ if (ret < 0)
+ return ret;
+
+ if (sense_res_raw == 0) {
+ dev_err(dev_info->dev, "sense resistor value is 0\n");
+ return -ENXIO;
+ }
+ sense_res = 1000 / sense_res_raw;
+
+ if (type == CURRENT_NOW)
+ reg_msb = DS2780_CURRENT_MSB_REG;
+ else if (type == CURRENT_AVG)
+ reg_msb = DS2780_IAVG_MSB_REG;
+ else
+ return -EINVAL;
+
+ /*
+ * The current value is located in 16 bits across the current MSB
+ * and LSB registers in two's compliment form
+ * Sign bit of the current value is in bit 7 of the current MSB register
+ * Bits 14 - 8 of the current value are in bits 6 - 0 of the current
+ * MSB register
+ * Bits 7 - 0 of the current value are in bits 7 - 0 of the current
+ * LSB register
+ */
+ ret = ds2780_read16(dev_info->w1_dev, &current_raw, reg_msb);
+ if (ret < 0)
+ return ret;
+
+ *current_uA = current_raw * (DS2780_CURRENT_UNITS / sense_res);
+ return 0;
+}
+
+static int ds2780_get_accumulated_current(struct ds2780_device_info *dev_info,
+ int *accumulated_current)
+{
+ int ret, sense_res;
+ s16 current_raw;
+ u8 sense_res_raw;
+
+ /*
+ * The units of measurement for accumulated current are dependent on
+ * the value of the sense resistor.
+ */
+ ret = ds2780_read8(dev_info->w1_dev, &sense_res_raw, DS2780_RSNSP_REG);
+ if (ret < 0)
+ return ret;
+
+ if (sense_res_raw == 0) {
+ dev_err(dev_info->dev, "sense resistor value is 0\n");
+ return -ENXIO;
+ }
+ sense_res = 1000 / sense_res_raw;
+
+ /*
+ * The ACR value is located in 16 bits across the ACR MSB and
+ * LSB registers
+ * Bits 15 - 8 of the ACR value are in bits 7 - 0 of the ACR
+ * MSB register
+ * Bits 7 - 0 of the ACR value are in bits 7 - 0 of the ACR
+ * LSB register
+ */
+ ret = ds2780_read16(dev_info->w1_dev, &current_raw, DS2780_ACR_MSB_REG);
+ if (ret < 0)
+ return ret;
+
+ *accumulated_current = current_raw * (DS2780_CHARGE_UNITS / sense_res);
+ return 0;
+}
+
+static int ds2780_get_capacity(struct ds2780_device_info *dev_info,
+ int *capacity)
+{
+ int ret;
+ u8 raw;
+
+ ret = ds2780_read8(dev_info->w1_dev, &raw, DS2780_RARC_REG);
+ if (ret < 0)
+ return ret;
+
+ *capacity = raw;
+ return raw;
+}
+
+static int ds2780_get_status(struct ds2780_device_info *dev_info, int *status)
+{
+ int ret, current_uA, capacity;
+
+ ret = ds2780_get_current(dev_info, CURRENT_NOW, &current_uA);
+ if (ret < 0)
+ return ret;
+
+ ret = ds2780_get_capacity(dev_info, &capacity);
+ if (ret < 0)
+ return ret;
+
+ if (capacity == 100)
+ *status = POWER_SUPPLY_STATUS_FULL;
+ else if (current_uA == 0)
+ *status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ else if (current_uA < 0)
+ *status = POWER_SUPPLY_STATUS_DISCHARGING;
+ else
+ *status = POWER_SUPPLY_STATUS_CHARGING;
+
+ return 0;
+}
+
+static int ds2780_get_charge_now(struct ds2780_device_info *dev_info,
+ int *charge_now)
+{
+ int ret;
+ u16 charge_raw;
+
+ /*
+ * The RAAC value is located in 16 bits across the RAAC MSB and
+ * LSB registers
+ * Bits 15 - 8 of the RAAC value are in bits 7 - 0 of the RAAC
+ * MSB register
+ * Bits 7 - 0 of the RAAC value are in bits 7 - 0 of the RAAC
+ * LSB register
+ */
+ ret = ds2780_read16(dev_info->w1_dev, &charge_raw, DS2780_RAAC_MSB_REG);
+ if (ret < 0)
+ return ret;
+
+ *charge_now = charge_raw * 1600;
+ return 0;
+}
+
+static int ds2780_get_control_register(struct ds2780_device_info *dev_info,
+ u8 *control_reg)
+{
+ return ds2780_read8(dev_info->w1_dev, control_reg, DS2780_CONTROL_REG);
+}
+
+static int ds2780_set_control_register(struct ds2780_device_info *dev_info,
+ u8 control_reg)
+{
+ int ret;
+
+ ret = ds2780_write(dev_info->w1_dev, &control_reg,
+ DS2780_CONTROL_REG, sizeof(u8));
+ if (ret < 0)
+ return ret;
+
+ return ds2780_save_eeprom(dev_info, DS2780_CONTROL_REG);
+}
+
+static int ds2780_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ int ret = 0;
+ struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ ret = ds2780_get_voltage(dev_info, &val->intval);
+ break;
+
+ case POWER_SUPPLY_PROP_TEMP:
+ ret = ds2780_get_temperature(dev_info, &val->intval);
+ break;
+
+ case POWER_SUPPLY_PROP_MODEL_NAME:
+ val->strval = model;
+ break;
+
+ case POWER_SUPPLY_PROP_MANUFACTURER:
+ val->strval = manufacturer;
+ break;
+
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ ret = ds2780_get_current(dev_info, CURRENT_NOW, &val->intval);
+ break;
+
+ case POWER_SUPPLY_PROP_CURRENT_AVG:
+ ret = ds2780_get_current(dev_info, CURRENT_AVG, &val->intval);
+ break;
+
+ case POWER_SUPPLY_PROP_STATUS:
+ ret = ds2780_get_status(dev_info, &val->intval);
+ break;
+
+ case POWER_SUPPLY_PROP_CAPACITY:
+ ret = ds2780_get_capacity(dev_info, &val->intval);
+ break;
+
+ case POWER_SUPPLY_PROP_CHARGE_COUNTER:
+ ret = ds2780_get_accumulated_current(dev_info, &val->intval);
+ break;
+
+ case POWER_SUPPLY_PROP_CHARGE_NOW:
+ ret = ds2780_get_charge_now(dev_info, &val->intval);
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static enum power_supply_property ds2780_battery_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_MANUFACTURER,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CURRENT_AVG,
+ POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_CHARGE_COUNTER,
+ POWER_SUPPLY_PROP_CHARGE_NOW,
+};
+
+static ssize_t ds2780_get_pmod_enabled(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u8 control_reg;
+ struct power_supply *psy = to_power_supply(dev);
+ struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+
+ /* Get power mode */
+ ret = ds2780_get_control_register(dev_info, &control_reg);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n",
+ !!(control_reg & DS2780_CONTROL_REG_PMOD));
+}
+
+static ssize_t ds2780_set_pmod_enabled(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ int ret;
+ u8 control_reg, new_setting;
+ struct power_supply *psy = to_power_supply(dev);
+ struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+
+ /* Set power mode */
+ ret = ds2780_get_control_register(dev_info, &control_reg);
+ if (ret < 0)
+ return ret;
+
+ ret = kstrtou8(buf, 0, &new_setting);
+ if (ret < 0)
+ return ret;
+
+ if ((new_setting != 0) && (new_setting != 1)) {
+ dev_err(dev_info->dev, "Invalid pmod setting (0 or 1)\n");
+ return -EINVAL;
+ }
+
+ if (new_setting)
+ control_reg |= DS2780_CONTROL_REG_PMOD;
+ else
+ control_reg &= ~DS2780_CONTROL_REG_PMOD;
+
+ ret = ds2780_set_control_register(dev_info, control_reg);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static ssize_t ds2780_get_sense_resistor_value(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u8 sense_resistor;
+ struct power_supply *psy = to_power_supply(dev);
+ struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+
+ ret = ds2780_read8(dev_info->w1_dev, &sense_resistor, DS2780_RSNSP_REG);
+ if (ret < 0)
+ return ret;
+
+ ret = sprintf(buf, "%d\n", sense_resistor);
+ return ret;
+}
+
+static ssize_t ds2780_set_sense_resistor_value(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ int ret;
+ u8 new_setting;
+ struct power_supply *psy = to_power_supply(dev);
+ struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+
+ ret = kstrtou8(buf, 0, &new_setting);
+ if (ret < 0)
+ return ret;
+
+ ret = ds2780_set_sense_register(dev_info, new_setting);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static ssize_t ds2780_get_rsgain_setting(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u16 rsgain;
+ struct power_supply *psy = to_power_supply(dev);
+ struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+
+ ret = ds2780_get_rsgain_register(dev_info, &rsgain);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", rsgain);
+}
+
+static ssize_t ds2780_set_rsgain_setting(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ int ret;
+ u16 new_setting;
+ struct power_supply *psy = to_power_supply(dev);
+ struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+
+ ret = kstrtou16(buf, 0, &new_setting);
+ if (ret < 0)
+ return ret;
+
+ /* Gain can only be from 0 to 1.999 in steps of .001 */
+ if (new_setting > 1999) {
+ dev_err(dev_info->dev, "Invalid rsgain setting (0 - 1999)\n");
+ return -EINVAL;
+ }
+
+ ret = ds2780_set_rsgain_register(dev_info, new_setting);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static ssize_t ds2780_get_pio_pin(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+ u8 sfr;
+ struct power_supply *psy = to_power_supply(dev);
+ struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+
+ ret = ds2780_read8(dev_info->w1_dev, &sfr, DS2780_SFR_REG);
+ if (ret < 0)
+ return ret;
+
+ ret = sprintf(buf, "%d\n", sfr & DS2780_SFR_REG_PIOSC);
+ return ret;
+}
+
+static ssize_t ds2780_set_pio_pin(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ int ret;
+ u8 new_setting;
+ struct power_supply *psy = to_power_supply(dev);
+ struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+
+ ret = kstrtou8(buf, 0, &new_setting);
+ if (ret < 0)
+ return ret;
+
+ if ((new_setting != 0) && (new_setting != 1)) {
+ dev_err(dev_info->dev, "Invalid pio_pin setting (0 or 1)\n");
+ return -EINVAL;
+ }
+
+ ret = ds2780_write(dev_info->w1_dev, &new_setting,
+ DS2780_SFR_REG, sizeof(u8));
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static ssize_t ds2780_read_param_eeprom_bin(struct file *filp,
+ struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct power_supply *psy = to_power_supply(dev);
+ struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+
+ count = min_t(loff_t, count,
+ DS2780_EEPROM_BLOCK1_END -
+ DS2780_EEPROM_BLOCK1_START + 1 - off);
+
+ return ds2780_read_block(dev_info->w1_dev, buf,
+ DS2780_EEPROM_BLOCK1_START + off, count);
+}
+
+static ssize_t ds2780_write_param_eeprom_bin(struct file *filp,
+ struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct power_supply *psy = to_power_supply(dev);
+ struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+ int ret;
+
+ count = min_t(loff_t, count,
+ DS2780_EEPROM_BLOCK1_END -
+ DS2780_EEPROM_BLOCK1_START + 1 - off);
+
+ ret = ds2780_write(dev_info->w1_dev, buf,
+ DS2780_EEPROM_BLOCK1_START + off, count);
+ if (ret < 0)
+ return ret;
+
+ ret = ds2780_save_eeprom(dev_info, DS2780_EEPROM_BLOCK1_START);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static struct bin_attribute ds2780_param_eeprom_bin_attr = {
+ .attr = {
+ .name = "param_eeprom",
+ .mode = S_IRUGO | S_IWUSR,
+ },
+ .size = DS2780_EEPROM_BLOCK1_END - DS2780_EEPROM_BLOCK1_START + 1,
+ .read = ds2780_read_param_eeprom_bin,
+ .write = ds2780_write_param_eeprom_bin,
+};
+
+static ssize_t ds2780_read_user_eeprom_bin(struct file *filp,
+ struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct power_supply *psy = to_power_supply(dev);
+ struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+
+ count = min_t(loff_t, count,
+ DS2780_EEPROM_BLOCK0_END -
+ DS2780_EEPROM_BLOCK0_START + 1 - off);
+
+ return ds2780_read_block(dev_info->w1_dev, buf,
+ DS2780_EEPROM_BLOCK0_START + off, count);
+
+}
+
+static ssize_t ds2780_write_user_eeprom_bin(struct file *filp,
+ struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct power_supply *psy = to_power_supply(dev);
+ struct ds2780_device_info *dev_info = to_ds2780_device_info(psy);
+ int ret;
+
+ count = min_t(loff_t, count,
+ DS2780_EEPROM_BLOCK0_END -
+ DS2780_EEPROM_BLOCK0_START + 1 - off);
+
+ ret = ds2780_write(dev_info->w1_dev, buf,
+ DS2780_EEPROM_BLOCK0_START + off, count);
+ if (ret < 0)
+ return ret;
+
+ ret = ds2780_save_eeprom(dev_info, DS2780_EEPROM_BLOCK0_START);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static struct bin_attribute ds2780_user_eeprom_bin_attr = {
+ .attr = {
+ .name = "user_eeprom",
+ .mode = S_IRUGO | S_IWUSR,
+ },
+ .size = DS2780_EEPROM_BLOCK0_END - DS2780_EEPROM_BLOCK0_START + 1,
+ .read = ds2780_read_user_eeprom_bin,
+ .write = ds2780_write_user_eeprom_bin,
+};
+
+static DEVICE_ATTR(pmod_enabled, S_IRUGO | S_IWUSR, ds2780_get_pmod_enabled,
+ ds2780_set_pmod_enabled);
+static DEVICE_ATTR(sense_resistor_value, S_IRUGO | S_IWUSR,
+ ds2780_get_sense_resistor_value, ds2780_set_sense_resistor_value);
+static DEVICE_ATTR(rsgain_setting, S_IRUGO | S_IWUSR, ds2780_get_rsgain_setting,
+ ds2780_set_rsgain_setting);
+static DEVICE_ATTR(pio_pin, S_IRUGO | S_IWUSR, ds2780_get_pio_pin,
+ ds2780_set_pio_pin);
+
+
+static struct attribute *ds2780_attributes[] = {
+ &dev_attr_pmod_enabled.attr,
+ &dev_attr_sense_resistor_value.attr,
+ &dev_attr_rsgain_setting.attr,
+ &dev_attr_pio_pin.attr,
+ NULL
+};
+
+static const struct attribute_group ds2780_attr_group = {
+ .attrs = ds2780_attributes,
+};
+
+static int __devinit ds2780_battery_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct ds2780_device_info *dev_info;
+
+ dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL);
+ if (!dev_info) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ platform_set_drvdata(pdev, dev_info);
+
+ dev_info->dev = &pdev->dev;
+ dev_info->w1_dev = pdev->dev.parent;
+ dev_info->bat.name = dev_name(&pdev->dev);
+ dev_info->bat.type = POWER_SUPPLY_TYPE_BATTERY;
+ dev_info->bat.properties = ds2780_battery_props;
+ dev_info->bat.num_properties = ARRAY_SIZE(ds2780_battery_props);
+ dev_info->bat.get_property = ds2780_battery_get_property;
+
+ ret = power_supply_register(&pdev->dev, &dev_info->bat);
+ if (ret) {
+ dev_err(dev_info->dev, "failed to register battery\n");
+ goto fail_free_info;
+ }
+
+ ret = sysfs_create_group(&dev_info->bat.dev->kobj, &ds2780_attr_group);
+ if (ret) {
+ dev_err(dev_info->dev, "failed to create sysfs group\n");
+ goto fail_unregister;
+ }
+
+ ret = sysfs_create_bin_file(&dev_info->bat.dev->kobj,
+ &ds2780_param_eeprom_bin_attr);
+ if (ret) {
+ dev_err(dev_info->dev,
+ "failed to create param eeprom bin file");
+ goto fail_remove_group;
+ }
+
+ ret = sysfs_create_bin_file(&dev_info->bat.dev->kobj,
+ &ds2780_user_eeprom_bin_attr);
+ if (ret) {
+ dev_err(dev_info->dev,
+ "failed to create user eeprom bin file");
+ goto fail_remove_bin_file;
+ }
+
+ return 0;
+
+fail_remove_bin_file:
+ sysfs_remove_bin_file(&dev_info->bat.dev->kobj,
+ &ds2780_param_eeprom_bin_attr);
+fail_remove_group:
+ sysfs_remove_group(&dev_info->bat.dev->kobj, &ds2780_attr_group);
+fail_unregister:
+ power_supply_unregister(&dev_info->bat);
+fail_free_info:
+ kfree(dev_info);
+fail:
+ return ret;
+}
+
+static int __devexit ds2780_battery_remove(struct platform_device *pdev)
+{
+ struct ds2780_device_info *dev_info = platform_get_drvdata(pdev);
+
+ /* remove attributes */
+ sysfs_remove_group(&dev_info->bat.dev->kobj, &ds2780_attr_group);
+
+ power_supply_unregister(&dev_info->bat);
+
+ kfree(dev_info);
+ return 0;
+}
+
+MODULE_ALIAS("platform:ds2780-battery");
+
+static struct platform_driver ds2780_battery_driver = {
+ .driver = {
+ .name = "ds2780-battery",
+ },
+ .probe = ds2780_battery_probe,
+ .remove = ds2780_battery_remove,
+};
+
+static int __init ds2780_battery_init(void)
+{
+ return platform_driver_register(&ds2780_battery_driver);
+}
+
+static void __exit ds2780_battery_exit(void)
+{
+ platform_driver_unregister(&ds2780_battery_driver);
+}
+
+module_init(ds2780_battery_init);
+module_exit(ds2780_battery_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Clifton Barnes <cabarnes@indesign-llc.com>");
+MODULE_DESCRIPTION("Maxim/Dallas DS2780 Stand-Alone Fuel Gauage IC driver");
diff --git a/drivers/power/gpio-charger.c b/drivers/power/gpio-charger.c
index 25b88ac1d44c..718f2c537827 100644
--- a/drivers/power/gpio-charger.c
+++ b/drivers/power/gpio-charger.c
@@ -161,12 +161,27 @@ static int __devexit gpio_charger_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int gpio_charger_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct gpio_charger *gpio_charger = platform_get_drvdata(pdev);
+
+ power_supply_changed(&gpio_charger->charger);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(gpio_charger_pm_ops, NULL, gpio_charger_resume);
+
static struct platform_driver gpio_charger_driver = {
.probe = gpio_charger_probe,
.remove = __devexit_p(gpio_charger_remove),
.driver = {
.name = "gpio-charger",
.owner = THIS_MODULE,
+ .pm = &gpio_charger_pm_ops,
},
};
diff --git a/drivers/power/intel_mid_battery.c b/drivers/power/intel_mid_battery.c
index bce3a01da2f0..cffcb7c00b00 100644
--- a/drivers/power/intel_mid_battery.c
+++ b/drivers/power/intel_mid_battery.c
@@ -522,7 +522,7 @@ static int pmic_battery_set_charger(struct pmic_power_module_info *pbi,
if (retval) {
dev_warn(pbi->dev, "%s(): ipc pmic read failed\n",
__func__);
- return retval;;
+ return retval;
}
return 0;
diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c
index 2ad9b14a5ce3..f6d72b402a8e 100644
--- a/drivers/power/isp1704_charger.c
+++ b/drivers/power/isp1704_charger.c
@@ -33,6 +33,7 @@
#include <linux/usb/ulpi.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
+#include <linux/power/isp1704_charger.h>
/* Vendor specific Power Control register */
#define ISP1704_PWR_CTRL 0x3d
@@ -71,6 +72,18 @@ struct isp1704_charger {
};
/*
+ * Disable/enable the power from the isp1704 if a function for it
+ * has been provided with platform data.
+ */
+static void isp1704_charger_set_power(struct isp1704_charger *isp, bool on)
+{
+ struct isp1704_charger_data *board = isp->dev->platform_data;
+
+ if (board->set_power)
+ board->set_power(on);
+}
+
+/*
* Determine is the charging port DCP (dedicated charger) or CDP (Host/HUB
* chargers).
*
@@ -222,6 +235,9 @@ static void isp1704_charger_work(struct work_struct *data)
mutex_lock(&lock);
+ if (event != USB_EVENT_NONE)
+ isp1704_charger_set_power(isp, 1);
+
switch (event) {
case USB_EVENT_VBUS:
isp->online = true;
@@ -269,6 +285,8 @@ static void isp1704_charger_work(struct work_struct *data)
*/
if (isp->otg->gadget)
usb_gadget_disconnect(isp->otg->gadget);
+
+ isp1704_charger_set_power(isp, 0);
break;
case USB_EVENT_ENUMERATED:
if (isp->present)
@@ -394,6 +412,8 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
isp->dev = &pdev->dev;
platform_set_drvdata(pdev, isp);
+ isp1704_charger_set_power(isp, 1);
+
ret = isp1704_test_ulpi(isp);
if (ret < 0)
goto fail1;
@@ -434,6 +454,7 @@ static int __devinit isp1704_charger_probe(struct platform_device *pdev)
/* Detect charger if VBUS is valid (the cable was already plugged). */
ret = otg_io_read(isp->otg, ULPI_USB_INT_STS);
+ isp1704_charger_set_power(isp, 0);
if ((ret & ULPI_INT_VBUS_VALID) && !isp->otg->default_a) {
isp->event = USB_EVENT_VBUS;
schedule_work(&isp->work);
@@ -459,6 +480,7 @@ static int __devexit isp1704_charger_remove(struct platform_device *pdev)
otg_unregister_notifier(isp->otg, &isp->nb);
power_supply_unregister(&isp->psy);
otg_put_transceiver(isp->otg);
+ isp1704_charger_set_power(isp, 0);
kfree(isp);
return 0;
diff --git a/drivers/power/max8903_charger.c b/drivers/power/max8903_charger.c
new file mode 100644
index 000000000000..33ff0e37809e
--- /dev/null
+++ b/drivers/power/max8903_charger.c
@@ -0,0 +1,391 @@
+/*
+ * max8903_charger.c - Maxim 8903 USB/Adapter Charger Driver
+ *
+ * Copyright (C) 2011 Samsung Electronics
+ * MyungJoo Ham <myungjoo.ham@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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You 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/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/power_supply.h>
+#include <linux/platform_device.h>
+#include <linux/power/max8903_charger.h>
+
+struct max8903_data {
+ struct max8903_pdata *pdata;
+ struct device *dev;
+ struct power_supply psy;
+ bool fault;
+ bool usb_in;
+ bool ta_in;
+};
+
+static enum power_supply_property max8903_charger_props[] = {
+ POWER_SUPPLY_PROP_STATUS, /* Charger status output */
+ POWER_SUPPLY_PROP_ONLINE, /* External power source */
+ POWER_SUPPLY_PROP_HEALTH, /* Fault or OK */
+};
+
+static int max8903_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct max8903_data *data = container_of(psy,
+ struct max8903_data, psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+ if (data->pdata->chg) {
+ if (gpio_get_value(data->pdata->chg) == 0)
+ val->intval = POWER_SUPPLY_STATUS_CHARGING;
+ else if (data->usb_in || data->ta_in)
+ val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ else
+ val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+ }
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = 0;
+ if (data->usb_in || data->ta_in)
+ val->intval = 1;
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ val->intval = POWER_SUPPLY_HEALTH_GOOD;
+ if (data->fault)
+ val->intval = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static irqreturn_t max8903_dcin(int irq, void *_data)
+{
+ struct max8903_data *data = _data;
+ struct max8903_pdata *pdata = data->pdata;
+ bool ta_in;
+ enum power_supply_type old_type;
+
+ ta_in = gpio_get_value(pdata->dok) ? false : true;
+
+ if (ta_in == data->ta_in)
+ return IRQ_HANDLED;
+
+ data->ta_in = ta_in;
+
+ /* Set Current-Limit-Mode 1:DC 0:USB */
+ if (pdata->dcm)
+ gpio_set_value(pdata->dcm, ta_in ? 1 : 0);
+
+ /* Charger Enable / Disable (cen is negated) */
+ if (pdata->cen)
+ gpio_set_value(pdata->cen, ta_in ? 0 :
+ (data->usb_in ? 0 : 1));
+
+ dev_dbg(data->dev, "TA(DC-IN) Charger %s.\n", ta_in ?
+ "Connected" : "Disconnected");
+
+ old_type = data->psy.type;
+
+ if (data->ta_in)
+ data->psy.type = POWER_SUPPLY_TYPE_MAINS;
+ else if (data->usb_in)
+ data->psy.type = POWER_SUPPLY_TYPE_USB;
+ else
+ data->psy.type = POWER_SUPPLY_TYPE_BATTERY;
+
+ if (old_type != data->psy.type)
+ power_supply_changed(&data->psy);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t max8903_usbin(int irq, void *_data)
+{
+ struct max8903_data *data = _data;
+ struct max8903_pdata *pdata = data->pdata;
+ bool usb_in;
+ enum power_supply_type old_type;
+
+ usb_in = gpio_get_value(pdata->uok) ? false : true;
+
+ if (usb_in == data->usb_in)
+ return IRQ_HANDLED;
+
+ data->usb_in = usb_in;
+
+ /* Do not touch Current-Limit-Mode */
+
+ /* Charger Enable / Disable (cen is negated) */
+ if (pdata->cen)
+ gpio_set_value(pdata->cen, usb_in ? 0 :
+ (data->ta_in ? 0 : 1));
+
+ dev_dbg(data->dev, "USB Charger %s.\n", usb_in ?
+ "Connected" : "Disconnected");
+
+ old_type = data->psy.type;
+
+ if (data->ta_in)
+ data->psy.type = POWER_SUPPLY_TYPE_MAINS;
+ else if (data->usb_in)
+ data->psy.type = POWER_SUPPLY_TYPE_USB;
+ else
+ data->psy.type = POWER_SUPPLY_TYPE_BATTERY;
+
+ if (old_type != data->psy.type)
+ power_supply_changed(&data->psy);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t max8903_fault(int irq, void *_data)
+{
+ struct max8903_data *data = _data;
+ struct max8903_pdata *pdata = data->pdata;
+ bool fault;
+
+ fault = gpio_get_value(pdata->flt) ? false : true;
+
+ if (fault == data->fault)
+ return IRQ_HANDLED;
+
+ data->fault = fault;
+
+ if (fault)
+ dev_err(data->dev, "Charger suffers a fault and stops.\n");
+ else
+ dev_err(data->dev, "Charger recovered from a fault.\n");
+
+ return IRQ_HANDLED;
+}
+
+static __devinit int max8903_probe(struct platform_device *pdev)
+{
+ struct max8903_data *data;
+ struct device *dev = &pdev->dev;
+ struct max8903_pdata *pdata = pdev->dev.platform_data;
+ int ret = 0;
+ int gpio;
+ int ta_in = 0;
+ int usb_in = 0;
+
+ data = kzalloc(sizeof(struct max8903_data), GFP_KERNEL);
+ if (data == NULL) {
+ dev_err(dev, "Cannot allocate memory.\n");
+ return -ENOMEM;
+ }
+ data->pdata = pdata;
+ data->dev = dev;
+ platform_set_drvdata(pdev, data);
+
+ if (pdata->dc_valid == false && pdata->usb_valid == false) {
+ dev_err(dev, "No valid power sources.\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (pdata->dc_valid) {
+ if (pdata->dok && gpio_is_valid(pdata->dok) &&
+ pdata->dcm && gpio_is_valid(pdata->dcm)) {
+ gpio = pdata->dok; /* PULL_UPed Interrupt */
+ ta_in = gpio_get_value(gpio) ? 0 : 1;
+
+ gpio = pdata->dcm; /* Output */
+ gpio_set_value(gpio, ta_in);
+ } else {
+ dev_err(dev, "When DC is wired, DOK and DCM should"
+ " be wired as well.\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ } else {
+ if (pdata->dcm) {
+ if (gpio_is_valid(pdata->dcm))
+ gpio_set_value(pdata->dcm, 0);
+ else {
+ dev_err(dev, "Invalid pin: dcm.\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ }
+ }
+
+ if (pdata->usb_valid) {
+ if (pdata->uok && gpio_is_valid(pdata->uok)) {
+ gpio = pdata->uok;
+ usb_in = gpio_get_value(gpio) ? 0 : 1;
+ } else {
+ dev_err(dev, "When USB is wired, UOK should be wired."
+ "as well.\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ }
+
+ if (pdata->cen) {
+ if (gpio_is_valid(pdata->cen)) {
+ gpio_set_value(pdata->cen, (ta_in || usb_in) ? 0 : 1);
+ } else {
+ dev_err(dev, "Invalid pin: cen.\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ }
+
+ if (pdata->chg) {
+ if (!gpio_is_valid(pdata->chg)) {
+ dev_err(dev, "Invalid pin: chg.\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ }
+
+ if (pdata->flt) {
+ if (!gpio_is_valid(pdata->flt)) {
+ dev_err(dev, "Invalid pin: flt.\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ }
+
+ if (pdata->usus) {
+ if (!gpio_is_valid(pdata->usus)) {
+ dev_err(dev, "Invalid pin: usus.\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ }
+
+ data->fault = false;
+ data->ta_in = ta_in;
+ data->usb_in = usb_in;
+
+ data->psy.name = "max8903_charger";
+ data->psy.type = (ta_in) ? POWER_SUPPLY_TYPE_MAINS :
+ ((usb_in) ? POWER_SUPPLY_TYPE_USB :
+ POWER_SUPPLY_TYPE_BATTERY);
+ data->psy.get_property = max8903_get_property;
+ data->psy.properties = max8903_charger_props;
+ data->psy.num_properties = ARRAY_SIZE(max8903_charger_props);
+
+ ret = power_supply_register(dev, &data->psy);
+ if (ret) {
+ dev_err(dev, "failed: power supply register.\n");
+ goto err;
+ }
+
+ if (pdata->dc_valid) {
+ ret = request_threaded_irq(gpio_to_irq(pdata->dok),
+ NULL, max8903_dcin,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ "MAX8903 DC IN", data);
+ if (ret) {
+ dev_err(dev, "Cannot request irq %d for DC (%d)\n",
+ gpio_to_irq(pdata->dok), ret);
+ goto err_psy;
+ }
+ }
+
+ if (pdata->usb_valid) {
+ ret = request_threaded_irq(gpio_to_irq(pdata->uok),
+ NULL, max8903_usbin,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ "MAX8903 USB IN", data);
+ if (ret) {
+ dev_err(dev, "Cannot request irq %d for USB (%d)\n",
+ gpio_to_irq(pdata->uok), ret);
+ goto err_dc_irq;
+ }
+ }
+
+ if (pdata->flt) {
+ ret = request_threaded_irq(gpio_to_irq(pdata->flt),
+ NULL, max8903_fault,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+ "MAX8903 Fault", data);
+ if (ret) {
+ dev_err(dev, "Cannot request irq %d for Fault (%d)\n",
+ gpio_to_irq(pdata->flt), ret);
+ goto err_usb_irq;
+ }
+ }
+
+ return 0;
+
+err_usb_irq:
+ if (pdata->usb_valid)
+ free_irq(gpio_to_irq(pdata->uok), data);
+err_dc_irq:
+ if (pdata->dc_valid)
+ free_irq(gpio_to_irq(pdata->dok), data);
+err_psy:
+ power_supply_unregister(&data->psy);
+err:
+ kfree(data);
+ return ret;
+}
+
+static __devexit int max8903_remove(struct platform_device *pdev)
+{
+ struct max8903_data *data = platform_get_drvdata(pdev);
+
+ if (data) {
+ struct max8903_pdata *pdata = data->pdata;
+
+ if (pdata->flt)
+ free_irq(gpio_to_irq(pdata->flt), data);
+ if (pdata->usb_valid)
+ free_irq(gpio_to_irq(pdata->uok), data);
+ if (pdata->dc_valid)
+ free_irq(gpio_to_irq(pdata->dok), data);
+ power_supply_unregister(&data->psy);
+ kfree(data);
+ }
+
+ return 0;
+}
+
+static struct platform_driver max8903_driver = {
+ .probe = max8903_probe,
+ .remove = __devexit_p(max8903_remove),
+ .driver = {
+ .name = "max8903-charger",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init max8903_init(void)
+{
+ return platform_driver_register(&max8903_driver);
+}
+module_init(max8903_init);
+
+static void __exit max8903_exit(void)
+{
+ platform_driver_unregister(&max8903_driver);
+}
+module_exit(max8903_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MAX8903 Charger Driver");
+MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
+MODULE_ALIAS("max8903-charger");
diff --git a/drivers/power/max8925_power.c b/drivers/power/max8925_power.c
index 8e5aec260866..a70e16d3a3dc 100644
--- a/drivers/power/max8925_power.c
+++ b/drivers/power/max8925_power.c
@@ -425,16 +425,11 @@ static __devexit int max8925_deinit_charger(struct max8925_power_info *info)
static __devinit int max8925_power_probe(struct platform_device *pdev)
{
struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);
- struct max8925_platform_data *max8925_pdata;
struct max8925_power_pdata *pdata = NULL;
struct max8925_power_info *info;
int ret;
- if (pdev->dev.parent->platform_data) {
- max8925_pdata = pdev->dev.parent->platform_data;
- pdata = max8925_pdata->power;
- }
-
+ pdata = pdev->dev.platform_data;
if (!pdata) {
dev_err(&pdev->dev, "platform data isn't assigned to "
"power supply\n");
@@ -447,6 +442,7 @@ static __devinit int max8925_power_probe(struct platform_device *pdev)
info->chip = chip;
info->gpm = chip->i2c;
info->adc = chip->adc;
+ platform_set_drvdata(pdev, info);
info->ac.name = "max8925-ac";
info->ac.type = POWER_SUPPLY_TYPE_MAINS;
@@ -482,8 +478,6 @@ static __devinit int max8925_power_probe(struct platform_device *pdev)
info->topoff_threshold = pdata->topoff_threshold;
info->fast_charge = pdata->fast_charge;
info->set_charger = pdata->set_charger;
- dev_set_drvdata(&pdev->dev, info);
- platform_set_drvdata(pdev, info);
max8925_init_charger(chip, info);
return 0;
diff --git a/drivers/power/test_power.c b/drivers/power/test_power.c
index 0cd9f67d33e5..b527c93bf2f3 100644
--- a/drivers/power/test_power.c
+++ b/drivers/power/test_power.c
@@ -3,6 +3,12 @@
*
* Copyright 2010 Anton Vorontsov <cbouatmailru@gmail.com>
*
+ * Dynamic module parameter code from the Virtual Battery Driver
+ * Copyright (C) 2008 Pylone, Inc.
+ * By: Masashi YOKOTA <yokota@pylone.jp>
+ * Originally found here:
+ * http://downloads.pylone.jp/src/virtual_battery/virtual_battery-0.0.1.tar.bz2
+ *
* 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.
@@ -15,8 +21,12 @@
#include <linux/delay.h>
#include <linux/vermagic.h>
-static int test_power_ac_online = 1;
-static int test_power_battery_status = POWER_SUPPLY_STATUS_CHARGING;
+static int ac_online = 1;
+static int battery_status = POWER_SUPPLY_STATUS_DISCHARGING;
+static int battery_health = POWER_SUPPLY_HEALTH_GOOD;
+static int battery_present = 1; /* true */
+static int battery_technology = POWER_SUPPLY_TECHNOLOGY_LION;
+static int battery_capacity = 50;
static int test_power_get_ac_property(struct power_supply *psy,
enum power_supply_property psp,
@@ -24,7 +34,7 @@ static int test_power_get_ac_property(struct power_supply *psy,
{
switch (psp) {
case POWER_SUPPLY_PROP_ONLINE:
- val->intval = test_power_ac_online;
+ val->intval = ac_online;
break;
default:
return -EINVAL;
@@ -47,22 +57,30 @@ static int test_power_get_battery_property(struct power_supply *psy,
val->strval = UTS_RELEASE;
break;
case POWER_SUPPLY_PROP_STATUS:
- val->intval = test_power_battery_status;
+ val->intval = battery_status;
break;
case POWER_SUPPLY_PROP_CHARGE_TYPE:
val->intval = POWER_SUPPLY_CHARGE_TYPE_FAST;
break;
case POWER_SUPPLY_PROP_HEALTH:
- val->intval = POWER_SUPPLY_HEALTH_GOOD;
+ val->intval = battery_health;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = battery_present;
break;
case POWER_SUPPLY_PROP_TECHNOLOGY:
- val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+ val->intval = battery_technology;
break;
case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
break;
case POWER_SUPPLY_PROP_CAPACITY:
- val->intval = 50;
+ case POWER_SUPPLY_PROP_CHARGE_NOW:
+ val->intval = battery_capacity;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+ case POWER_SUPPLY_PROP_CHARGE_FULL:
+ val->intval = 100;
break;
case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG:
case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW:
@@ -84,9 +102,11 @@ static enum power_supply_property test_power_battery_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_CHARGE_TYPE,
POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
POWER_SUPPLY_PROP_CHARGE_FULL,
- POWER_SUPPLY_PROP_CHARGE_EMPTY,
+ POWER_SUPPLY_PROP_CHARGE_NOW,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CAPACITY_LEVEL,
POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
@@ -118,6 +138,7 @@ static struct power_supply test_power_supplies[] = {
},
};
+
static int __init test_power_init(void)
{
int i;
@@ -145,8 +166,8 @@ static void __exit test_power_exit(void)
int i;
/* Let's see how we handle changes... */
- test_power_ac_online = 0;
- test_power_battery_status = POWER_SUPPLY_STATUS_DISCHARGING;
+ ac_online = 0;
+ battery_status = POWER_SUPPLY_STATUS_DISCHARGING;
for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++)
power_supply_changed(&test_power_supplies[i]);
pr_info("%s: 'changed' event sent, sleeping for 10 seconds...\n",
@@ -158,6 +179,241 @@ static void __exit test_power_exit(void)
}
module_exit(test_power_exit);
+
+
+#define MAX_KEYLENGTH 256
+struct battery_property_map {
+ int value;
+ char const *key;
+};
+
+static struct battery_property_map map_ac_online[] = {
+ { 0, "on" },
+ { 1, "off" },
+ { -1, NULL },
+};
+
+static struct battery_property_map map_status[] = {
+ { POWER_SUPPLY_STATUS_CHARGING, "charging" },
+ { POWER_SUPPLY_STATUS_DISCHARGING, "discharging" },
+ { POWER_SUPPLY_STATUS_NOT_CHARGING, "not-charging" },
+ { POWER_SUPPLY_STATUS_FULL, "full" },
+ { -1, NULL },
+};
+
+static struct battery_property_map map_health[] = {
+ { POWER_SUPPLY_HEALTH_GOOD, "good" },
+ { POWER_SUPPLY_HEALTH_OVERHEAT, "overheat" },
+ { POWER_SUPPLY_HEALTH_DEAD, "dead" },
+ { POWER_SUPPLY_HEALTH_OVERVOLTAGE, "overvoltage" },
+ { POWER_SUPPLY_HEALTH_UNSPEC_FAILURE, "failure" },
+ { -1, NULL },
+};
+
+static struct battery_property_map map_present[] = {
+ { 0, "false" },
+ { 1, "true" },
+ { -1, NULL },
+};
+
+static struct battery_property_map map_technology[] = {
+ { POWER_SUPPLY_TECHNOLOGY_NiMH, "NiMH" },
+ { POWER_SUPPLY_TECHNOLOGY_LION, "LION" },
+ { POWER_SUPPLY_TECHNOLOGY_LIPO, "LIPO" },
+ { POWER_SUPPLY_TECHNOLOGY_LiFe, "LiFe" },
+ { POWER_SUPPLY_TECHNOLOGY_NiCd, "NiCd" },
+ { POWER_SUPPLY_TECHNOLOGY_LiMn, "LiMn" },
+ { -1, NULL },
+};
+
+
+static int map_get_value(struct battery_property_map *map, const char *key,
+ int def_val)
+{
+ char buf[MAX_KEYLENGTH];
+ int cr;
+
+ strncpy(buf, key, MAX_KEYLENGTH);
+ buf[MAX_KEYLENGTH-1] = '\0';
+
+ cr = strnlen(buf, MAX_KEYLENGTH) - 1;
+ if (buf[cr] == '\n')
+ buf[cr] = '\0';
+
+ while (map->key) {
+ if (strncasecmp(map->key, buf, MAX_KEYLENGTH) == 0)
+ return map->value;
+ map++;
+ }
+
+ return def_val;
+}
+
+
+static const char *map_get_key(struct battery_property_map *map, int value,
+ const char *def_key)
+{
+ while (map->key) {
+ if (map->value == value)
+ return map->key;
+ map++;
+ }
+
+ return def_key;
+}
+
+static int param_set_ac_online(const char *key, const struct kernel_param *kp)
+{
+ ac_online = map_get_value(map_ac_online, key, ac_online);
+ power_supply_changed(&test_power_supplies[0]);
+ return 0;
+}
+
+static int param_get_ac_online(char *buffer, const struct kernel_param *kp)
+{
+ strcpy(buffer, map_get_key(map_ac_online, ac_online, "unknown"));
+ return strlen(buffer);
+}
+
+static int param_set_battery_status(const char *key,
+ const struct kernel_param *kp)
+{
+ battery_status = map_get_value(map_status, key, battery_status);
+ power_supply_changed(&test_power_supplies[1]);
+ return 0;
+}
+
+static int param_get_battery_status(char *buffer, const struct kernel_param *kp)
+{
+ strcpy(buffer, map_get_key(map_status, battery_status, "unknown"));
+ return strlen(buffer);
+}
+
+static int param_set_battery_health(const char *key,
+ const struct kernel_param *kp)
+{
+ battery_health = map_get_value(map_health, key, battery_health);
+ power_supply_changed(&test_power_supplies[1]);
+ return 0;
+}
+
+static int param_get_battery_health(char *buffer, const struct kernel_param *kp)
+{
+ strcpy(buffer, map_get_key(map_health, battery_health, "unknown"));
+ return strlen(buffer);
+}
+
+static int param_set_battery_present(const char *key,
+ const struct kernel_param *kp)
+{
+ battery_present = map_get_value(map_present, key, battery_present);
+ power_supply_changed(&test_power_supplies[0]);
+ return 0;
+}
+
+static int param_get_battery_present(char *buffer,
+ const struct kernel_param *kp)
+{
+ strcpy(buffer, map_get_key(map_present, battery_present, "unknown"));
+ return strlen(buffer);
+}
+
+static int param_set_battery_technology(const char *key,
+ const struct kernel_param *kp)
+{
+ battery_technology = map_get_value(map_technology, key,
+ battery_technology);
+ power_supply_changed(&test_power_supplies[1]);
+ return 0;
+}
+
+static int param_get_battery_technology(char *buffer,
+ const struct kernel_param *kp)
+{
+ strcpy(buffer,
+ map_get_key(map_technology, battery_technology, "unknown"));
+ return strlen(buffer);
+}
+
+static int param_set_battery_capacity(const char *key,
+ const struct kernel_param *kp)
+{
+ int tmp;
+
+ if (1 != sscanf(key, "%d", &tmp))
+ return -EINVAL;
+
+ battery_capacity = tmp;
+ power_supply_changed(&test_power_supplies[1]);
+ return 0;
+}
+
+#define param_get_battery_capacity param_get_int
+
+
+
+static struct kernel_param_ops param_ops_ac_online = {
+ .set = param_set_ac_online,
+ .get = param_get_ac_online,
+};
+
+static struct kernel_param_ops param_ops_battery_status = {
+ .set = param_set_battery_status,
+ .get = param_get_battery_status,
+};
+
+static struct kernel_param_ops param_ops_battery_present = {
+ .set = param_set_battery_present,
+ .get = param_get_battery_present,
+};
+
+static struct kernel_param_ops param_ops_battery_technology = {
+ .set = param_set_battery_technology,
+ .get = param_get_battery_technology,
+};
+
+static struct kernel_param_ops param_ops_battery_health = {
+ .set = param_set_battery_health,
+ .get = param_get_battery_health,
+};
+
+static struct kernel_param_ops param_ops_battery_capacity = {
+ .set = param_set_battery_capacity,
+ .get = param_get_battery_capacity,
+};
+
+
+#define param_check_ac_online(name, p) __param_check(name, p, void);
+#define param_check_battery_status(name, p) __param_check(name, p, void);
+#define param_check_battery_present(name, p) __param_check(name, p, void);
+#define param_check_battery_technology(name, p) __param_check(name, p, void);
+#define param_check_battery_health(name, p) __param_check(name, p, void);
+#define param_check_battery_capacity(name, p) __param_check(name, p, void);
+
+
+module_param(ac_online, ac_online, 0644);
+MODULE_PARM_DESC(ac_online, "AC charging state <on|off>");
+
+module_param(battery_status, battery_status, 0644);
+MODULE_PARM_DESC(battery_status,
+ "battery status <charging|discharging|not-charging|full>");
+
+module_param(battery_present, battery_present, 0644);
+MODULE_PARM_DESC(battery_present,
+ "battery presence state <good|overheat|dead|overvoltage|failure>");
+
+module_param(battery_technology, battery_technology, 0644);
+MODULE_PARM_DESC(battery_technology,
+ "battery technology <NiMH|LION|LIPO|LiFe|NiCd|LiMn>");
+
+module_param(battery_health, battery_health, 0644);
+MODULE_PARM_DESC(battery_health,
+ "battery health state <good|overheat|dead|overvoltage|failure>");
+
+module_param(battery_capacity, battery_capacity, 0644);
+MODULE_PARM_DESC(battery_capacity, "battery capacity (percentage)");
+
+
MODULE_DESCRIPTION("Power supply driver for testing");
MODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>");
MODULE_LICENSE("GPL");
diff --git a/drivers/power/z2_battery.c b/drivers/power/z2_battery.c
index e5ced3a4c1ed..d119c38b3ff6 100644
--- a/drivers/power/z2_battery.c
+++ b/drivers/power/z2_battery.c
@@ -271,24 +271,33 @@ static int __devexit z2_batt_remove(struct i2c_client *client)
}
#ifdef CONFIG_PM
-static int z2_batt_suspend(struct i2c_client *client, pm_message_t state)
+static int z2_batt_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct z2_charger *charger = i2c_get_clientdata(client);
flush_work_sync(&charger->bat_work);
return 0;
}
-static int z2_batt_resume(struct i2c_client *client)
+static int z2_batt_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct z2_charger *charger = i2c_get_clientdata(client);
schedule_work(&charger->bat_work);
return 0;
}
+
+static const struct dev_pm_ops z2_battery_pm_ops = {
+ .suspend = z2_batt_suspend,
+ .resume = z2_batt_resume,
+};
+
+#define Z2_BATTERY_PM_OPS (&z2_battery_pm_ops)
+
#else
-#define z2_batt_suspend NULL
-#define z2_batt_resume NULL
+#define Z2_BATTERY_PM_OPS (NULL)
#endif
static const struct i2c_device_id z2_batt_id[] = {
@@ -301,11 +310,10 @@ static struct i2c_driver z2_batt_driver = {
.driver = {
.name = "z2-battery",
.owner = THIS_MODULE,
+ .pm = Z2_BATTERY_PM_OPS
},
.probe = z2_batt_probe,
.remove = z2_batt_remove,
- .suspend = z2_batt_suspend,
- .resume = z2_batt_resume,
.id_table = z2_batt_id,
};
diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig
new file mode 100644
index 000000000000..68d720102296
--- /dev/null
+++ b/drivers/ptp/Kconfig
@@ -0,0 +1,75 @@
+#
+# PTP clock support configuration
+#
+
+menu "PTP clock support"
+
+comment "Enable Device Drivers -> PPS to see the PTP clock options."
+ depends on PPS=n
+
+config PTP_1588_CLOCK
+ tristate "PTP clock support"
+ depends on EXPERIMENTAL
+ depends on PPS
+ help
+ The IEEE 1588 standard defines a method to precisely
+ synchronize distributed clocks over Ethernet networks. The
+ standard defines a Precision Time Protocol (PTP), which can
+ be used to achieve synchronization within a few dozen
+ microseconds. In addition, with the help of special hardware
+ time stamping units, it can be possible to achieve
+ synchronization to within a few hundred nanoseconds.
+
+ This driver adds support for PTP clocks as character
+ devices. If you want to use a PTP clock, then you should
+ also enable at least one clock driver as well.
+
+ To compile this driver as a module, choose M here: the module
+ will be called ptp.
+
+config PTP_1588_CLOCK_GIANFAR
+ tristate "Freescale eTSEC as PTP clock"
+ depends on PTP_1588_CLOCK
+ depends on GIANFAR
+ help
+ This driver adds support for using the eTSEC as a PTP
+ clock. This clock is only useful if your PTP programs are
+ getting hardware time stamps on the PTP Ethernet packets
+ using the SO_TIMESTAMPING API.
+
+ To compile this driver as a module, choose M here: the module
+ will be called gianfar_ptp.
+
+config PTP_1588_CLOCK_IXP46X
+ tristate "Intel IXP46x as PTP clock"
+ depends on PTP_1588_CLOCK
+ depends on IXP4XX_ETH
+ help
+ This driver adds support for using the IXP46X as a PTP
+ clock. This clock is only useful if your PTP programs are
+ getting hardware time stamps on the PTP Ethernet packets
+ using the SO_TIMESTAMPING API.
+
+ To compile this driver as a module, choose M here: the module
+ will be called ptp_ixp46x.
+
+comment "Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks."
+ depends on PTP_1588_CLOCK && (PHYLIB=n || NETWORK_PHY_TIMESTAMPING=n)
+
+config DP83640_PHY
+ tristate "Driver for the National Semiconductor DP83640 PHYTER"
+ depends on PTP_1588_CLOCK
+ depends on NETWORK_PHY_TIMESTAMPING
+ depends on PHYLIB
+ ---help---
+ Supports the DP83640 PHYTER with IEEE 1588 features.
+
+ This driver adds support for using the DP83640 as a PTP
+ clock. This clock is only useful if your PTP programs are
+ getting hardware time stamps on the PTP Ethernet packets
+ using the SO_TIMESTAMPING API.
+
+ In order for this to work, your MAC driver must also
+ implement the skb_tx_timetamp() function.
+
+endmenu
diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile
new file mode 100644
index 000000000000..f6933e83de72
--- /dev/null
+++ b/drivers/ptp/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for PTP 1588 clock support.
+#
+
+ptp-y := ptp_clock.o ptp_chardev.o ptp_sysfs.o
+obj-$(CONFIG_PTP_1588_CLOCK) += ptp.o
+obj-$(CONFIG_PTP_1588_CLOCK_IXP46X) += ptp_ixp46x.o
diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c
new file mode 100644
index 000000000000..a8d03aeb4051
--- /dev/null
+++ b/drivers/ptp/ptp_chardev.c
@@ -0,0 +1,159 @@
+/*
+ * PTP 1588 clock support - character device implementation.
+ *
+ * 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/module.h>
+#include <linux/posix-clock.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+
+#include "ptp_private.h"
+
+int ptp_open(struct posix_clock *pc, fmode_t fmode)
+{
+ return 0;
+}
+
+long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)
+{
+ struct ptp_clock_caps caps;
+ struct ptp_clock_request req;
+ struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+ struct ptp_clock_info *ops = ptp->info;
+ int enable, err = 0;
+
+ switch (cmd) {
+
+ case PTP_CLOCK_GETCAPS:
+ memset(&caps, 0, sizeof(caps));
+ caps.max_adj = ptp->info->max_adj;
+ caps.n_alarm = ptp->info->n_alarm;
+ caps.n_ext_ts = ptp->info->n_ext_ts;
+ caps.n_per_out = ptp->info->n_per_out;
+ caps.pps = ptp->info->pps;
+ err = copy_to_user((void __user *)arg, &caps, sizeof(caps));
+ break;
+
+ case PTP_EXTTS_REQUEST:
+ if (copy_from_user(&req.extts, (void __user *)arg,
+ sizeof(req.extts))) {
+ err = -EFAULT;
+ break;
+ }
+ if (req.extts.index >= ops->n_ext_ts) {
+ err = -EINVAL;
+ break;
+ }
+ req.type = PTP_CLK_REQ_EXTTS;
+ enable = req.extts.flags & PTP_ENABLE_FEATURE ? 1 : 0;
+ err = ops->enable(ops, &req, enable);
+ break;
+
+ case PTP_PEROUT_REQUEST:
+ if (copy_from_user(&req.perout, (void __user *)arg,
+ sizeof(req.perout))) {
+ err = -EFAULT;
+ break;
+ }
+ if (req.perout.index >= ops->n_per_out) {
+ err = -EINVAL;
+ break;
+ }
+ req.type = PTP_CLK_REQ_PEROUT;
+ enable = req.perout.period.sec || req.perout.period.nsec;
+ err = ops->enable(ops, &req, enable);
+ break;
+
+ case PTP_ENABLE_PPS:
+ if (!capable(CAP_SYS_TIME))
+ return -EPERM;
+ req.type = PTP_CLK_REQ_PPS;
+ enable = arg ? 1 : 0;
+ err = ops->enable(ops, &req, enable);
+ break;
+
+ default:
+ err = -ENOTTY;
+ break;
+ }
+ return err;
+}
+
+unsigned int ptp_poll(struct posix_clock *pc, struct file *fp, poll_table *wait)
+{
+ struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+
+ poll_wait(fp, &ptp->tsev_wq, wait);
+
+ return queue_cnt(&ptp->tsevq) ? POLLIN : 0;
+}
+
+ssize_t ptp_read(struct posix_clock *pc,
+ uint rdflags, char __user *buf, size_t cnt)
+{
+ struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+ struct timestamp_event_queue *queue = &ptp->tsevq;
+ struct ptp_extts_event event[PTP_BUF_TIMESTAMPS];
+ unsigned long flags;
+ size_t qcnt, i;
+
+ if (cnt % sizeof(struct ptp_extts_event) != 0)
+ return -EINVAL;
+
+ if (cnt > sizeof(event))
+ cnt = sizeof(event);
+
+ cnt = cnt / sizeof(struct ptp_extts_event);
+
+ if (mutex_lock_interruptible(&ptp->tsevq_mux))
+ return -ERESTARTSYS;
+
+ if (wait_event_interruptible(ptp->tsev_wq,
+ ptp->defunct || queue_cnt(queue))) {
+ mutex_unlock(&ptp->tsevq_mux);
+ return -ERESTARTSYS;
+ }
+
+ if (ptp->defunct)
+ return -ENODEV;
+
+ spin_lock_irqsave(&queue->lock, flags);
+
+ qcnt = queue_cnt(queue);
+
+ if (cnt > qcnt)
+ cnt = qcnt;
+
+ for (i = 0; i < cnt; i++) {
+ event[i] = queue->buf[queue->head];
+ queue->head = (queue->head + 1) % PTP_MAX_TIMESTAMPS;
+ }
+
+ spin_unlock_irqrestore(&queue->lock, flags);
+
+ cnt = cnt * sizeof(struct ptp_extts_event);
+
+ mutex_unlock(&ptp->tsevq_mux);
+
+ if (copy_to_user(buf, event, cnt)) {
+ mutex_unlock(&ptp->tsevq_mux);
+ return -EFAULT;
+ }
+
+ return cnt;
+}
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
new file mode 100644
index 000000000000..cf3f9997546d
--- /dev/null
+++ b/drivers/ptp/ptp_clock.c
@@ -0,0 +1,343 @@
+/*
+ * PTP 1588 clock support
+ *
+ * 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/bitops.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/posix-clock.h>
+#include <linux/pps_kernel.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+#include <linux/uaccess.h>
+
+#include "ptp_private.h"
+
+#define PTP_MAX_ALARMS 4
+#define PTP_MAX_CLOCKS 8
+#define PTP_PPS_DEFAULTS (PPS_CAPTUREASSERT | PPS_OFFSETASSERT)
+#define PTP_PPS_EVENT PPS_CAPTUREASSERT
+#define PTP_PPS_MODE (PTP_PPS_DEFAULTS | PPS_CANWAIT | PPS_TSFMT_TSPEC)
+
+/* private globals */
+
+static dev_t ptp_devt;
+static struct class *ptp_class;
+
+static DECLARE_BITMAP(ptp_clocks_map, PTP_MAX_CLOCKS);
+static DEFINE_MUTEX(ptp_clocks_mutex); /* protects 'ptp_clocks_map' */
+
+/* time stamp event queue operations */
+
+static inline int queue_free(struct timestamp_event_queue *q)
+{
+ return PTP_MAX_TIMESTAMPS - queue_cnt(q) - 1;
+}
+
+static void enqueue_external_timestamp(struct timestamp_event_queue *queue,
+ struct ptp_clock_event *src)
+{
+ struct ptp_extts_event *dst;
+ unsigned long flags;
+ s64 seconds;
+ u32 remainder;
+
+ seconds = div_u64_rem(src->timestamp, 1000000000, &remainder);
+
+ spin_lock_irqsave(&queue->lock, flags);
+
+ dst = &queue->buf[queue->tail];
+ dst->index = src->index;
+ dst->t.sec = seconds;
+ dst->t.nsec = remainder;
+
+ if (!queue_free(queue))
+ queue->head = (queue->head + 1) % PTP_MAX_TIMESTAMPS;
+
+ queue->tail = (queue->tail + 1) % PTP_MAX_TIMESTAMPS;
+
+ spin_unlock_irqrestore(&queue->lock, flags);
+}
+
+static s32 scaled_ppm_to_ppb(long ppm)
+{
+ /*
+ * The 'freq' field in the 'struct timex' is in parts per
+ * million, but with a 16 bit binary fractional field.
+ *
+ * We want to calculate
+ *
+ * ppb = scaled_ppm * 1000 / 2^16
+ *
+ * which simplifies to
+ *
+ * ppb = scaled_ppm * 125 / 2^13
+ */
+ s64 ppb = 1 + ppm;
+ ppb *= 125;
+ ppb >>= 13;
+ return (s32) ppb;
+}
+
+/* posix clock implementation */
+
+static int ptp_clock_getres(struct posix_clock *pc, struct timespec *tp)
+{
+ return 1; /* always round timer functions to one nanosecond */
+}
+
+static int ptp_clock_settime(struct posix_clock *pc, const struct timespec *tp)
+{
+ struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+ return ptp->info->settime(ptp->info, tp);
+}
+
+static int ptp_clock_gettime(struct posix_clock *pc, struct timespec *tp)
+{
+ struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+ return ptp->info->gettime(ptp->info, tp);
+}
+
+static int ptp_clock_adjtime(struct posix_clock *pc, struct timex *tx)
+{
+ struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+ struct ptp_clock_info *ops;
+ int err = -EOPNOTSUPP;
+
+ ops = ptp->info;
+
+ if (tx->modes & ADJ_SETOFFSET) {
+ struct timespec ts;
+ ktime_t kt;
+ s64 delta;
+
+ ts.tv_sec = tx->time.tv_sec;
+ ts.tv_nsec = tx->time.tv_usec;
+
+ if (!(tx->modes & ADJ_NANO))
+ ts.tv_nsec *= 1000;
+
+ if ((unsigned long) ts.tv_nsec >= NSEC_PER_SEC)
+ return -EINVAL;
+
+ kt = timespec_to_ktime(ts);
+ delta = ktime_to_ns(kt);
+ err = ops->adjtime(ops, delta);
+
+ } else if (tx->modes & ADJ_FREQUENCY) {
+
+ err = ops->adjfreq(ops, scaled_ppm_to_ppb(tx->freq));
+ }
+
+ return err;
+}
+
+static struct posix_clock_operations ptp_clock_ops = {
+ .owner = THIS_MODULE,
+ .clock_adjtime = ptp_clock_adjtime,
+ .clock_gettime = ptp_clock_gettime,
+ .clock_getres = ptp_clock_getres,
+ .clock_settime = ptp_clock_settime,
+ .ioctl = ptp_ioctl,
+ .open = ptp_open,
+ .poll = ptp_poll,
+ .read = ptp_read,
+};
+
+static void delete_ptp_clock(struct posix_clock *pc)
+{
+ struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock);
+
+ mutex_destroy(&ptp->tsevq_mux);
+
+ /* Remove the clock from the bit map. */
+ mutex_lock(&ptp_clocks_mutex);
+ clear_bit(ptp->index, ptp_clocks_map);
+ mutex_unlock(&ptp_clocks_mutex);
+
+ kfree(ptp);
+}
+
+/* public interface */
+
+struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info)
+{
+ struct ptp_clock *ptp;
+ int err = 0, index, major = MAJOR(ptp_devt);
+
+ if (info->n_alarm > PTP_MAX_ALARMS)
+ return ERR_PTR(-EINVAL);
+
+ /* Find a free clock slot and reserve it. */
+ err = -EBUSY;
+ mutex_lock(&ptp_clocks_mutex);
+ index = find_first_zero_bit(ptp_clocks_map, PTP_MAX_CLOCKS);
+ if (index < PTP_MAX_CLOCKS)
+ set_bit(index, ptp_clocks_map);
+ else
+ goto no_slot;
+
+ /* Initialize a clock structure. */
+ err = -ENOMEM;
+ ptp = kzalloc(sizeof(struct ptp_clock), GFP_KERNEL);
+ if (ptp == NULL)
+ goto no_memory;
+
+ ptp->clock.ops = ptp_clock_ops;
+ ptp->clock.release = delete_ptp_clock;
+ ptp->info = info;
+ ptp->devid = MKDEV(major, index);
+ ptp->index = index;
+ spin_lock_init(&ptp->tsevq.lock);
+ mutex_init(&ptp->tsevq_mux);
+ init_waitqueue_head(&ptp->tsev_wq);
+
+ /* Create a new device in our class. */
+ ptp->dev = device_create(ptp_class, NULL, ptp->devid, ptp,
+ "ptp%d", ptp->index);
+ if (IS_ERR(ptp->dev))
+ goto no_device;
+
+ dev_set_drvdata(ptp->dev, ptp);
+
+ err = ptp_populate_sysfs(ptp);
+ if (err)
+ goto no_sysfs;
+
+ /* Register a new PPS source. */
+ if (info->pps) {
+ struct pps_source_info pps;
+ memset(&pps, 0, sizeof(pps));
+ snprintf(pps.name, PPS_MAX_NAME_LEN, "ptp%d", index);
+ pps.mode = PTP_PPS_MODE;
+ pps.owner = info->owner;
+ ptp->pps_source = pps_register_source(&pps, PTP_PPS_DEFAULTS);
+ if (!ptp->pps_source) {
+ pr_err("failed to register pps source\n");
+ goto no_pps;
+ }
+ }
+
+ /* Create a posix clock. */
+ err = posix_clock_register(&ptp->clock, ptp->devid);
+ if (err) {
+ pr_err("failed to create posix clock\n");
+ goto no_clock;
+ }
+
+ mutex_unlock(&ptp_clocks_mutex);
+ return ptp;
+
+no_clock:
+ if (ptp->pps_source)
+ pps_unregister_source(ptp->pps_source);
+no_pps:
+ ptp_cleanup_sysfs(ptp);
+no_sysfs:
+ device_destroy(ptp_class, ptp->devid);
+no_device:
+ mutex_destroy(&ptp->tsevq_mux);
+ kfree(ptp);
+no_memory:
+ clear_bit(index, ptp_clocks_map);
+no_slot:
+ mutex_unlock(&ptp_clocks_mutex);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL(ptp_clock_register);
+
+int ptp_clock_unregister(struct ptp_clock *ptp)
+{
+ ptp->defunct = 1;
+ wake_up_interruptible(&ptp->tsev_wq);
+
+ /* Release the clock's resources. */
+ if (ptp->pps_source)
+ pps_unregister_source(ptp->pps_source);
+ ptp_cleanup_sysfs(ptp);
+ device_destroy(ptp_class, ptp->devid);
+
+ posix_clock_unregister(&ptp->clock);
+ return 0;
+}
+EXPORT_SYMBOL(ptp_clock_unregister);
+
+void ptp_clock_event(struct ptp_clock *ptp, struct ptp_clock_event *event)
+{
+ struct pps_event_time evt;
+
+ switch (event->type) {
+
+ case PTP_CLOCK_ALARM:
+ break;
+
+ case PTP_CLOCK_EXTTS:
+ enqueue_external_timestamp(&ptp->tsevq, event);
+ wake_up_interruptible(&ptp->tsev_wq);
+ break;
+
+ case PTP_CLOCK_PPS:
+ pps_get_ts(&evt);
+ pps_event(ptp->pps_source, &evt, PTP_PPS_EVENT, NULL);
+ break;
+ }
+}
+EXPORT_SYMBOL(ptp_clock_event);
+
+/* module operations */
+
+static void __exit ptp_exit(void)
+{
+ class_destroy(ptp_class);
+ unregister_chrdev_region(ptp_devt, PTP_MAX_CLOCKS);
+}
+
+static int __init ptp_init(void)
+{
+ int err;
+
+ ptp_class = class_create(THIS_MODULE, "ptp");
+ if (IS_ERR(ptp_class)) {
+ pr_err("ptp: failed to allocate class\n");
+ return PTR_ERR(ptp_class);
+ }
+
+ err = alloc_chrdev_region(&ptp_devt, 0, PTP_MAX_CLOCKS, "ptp");
+ if (err < 0) {
+ pr_err("ptp: failed to allocate device region\n");
+ goto no_region;
+ }
+
+ ptp_class->dev_attrs = ptp_dev_attrs;
+ pr_info("PTP clock support registered\n");
+ return 0;
+
+no_region:
+ class_destroy(ptp_class);
+ return err;
+}
+
+subsys_initcall(ptp_init);
+module_exit(ptp_exit);
+
+MODULE_AUTHOR("Richard Cochran <richard.cochran@omicron.at>");
+MODULE_DESCRIPTION("PTP clocks support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ptp/ptp_ixp46x.c b/drivers/ptp/ptp_ixp46x.c
new file mode 100644
index 000000000000..803d665b15ef
--- /dev/null
+++ b/drivers/ptp/ptp_ixp46x.c
@@ -0,0 +1,332 @@
+/*
+ * PTP 1588 clock using the IXP46X
+ *
+ * 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/device.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <linux/ptp_clock_kernel.h>
+#include <mach/ixp46x_ts.h>
+
+#define DRIVER "ptp_ixp46x"
+#define N_EXT_TS 2
+#define MASTER_GPIO 8
+#define MASTER_IRQ 25
+#define SLAVE_GPIO 7
+#define SLAVE_IRQ 24
+
+struct ixp_clock {
+ struct ixp46x_ts_regs *regs;
+ struct ptp_clock *ptp_clock;
+ struct ptp_clock_info caps;
+ int exts0_enabled;
+ int exts1_enabled;
+};
+
+DEFINE_SPINLOCK(register_lock);
+
+/*
+ * Register access functions
+ */
+
+static u64 ixp_systime_read(struct ixp46x_ts_regs *regs)
+{
+ u64 ns;
+ u32 lo, hi;
+
+ lo = __raw_readl(&regs->systime_lo);
+ hi = __raw_readl(&regs->systime_hi);
+
+ ns = ((u64) hi) << 32;
+ ns |= lo;
+ ns <<= TICKS_NS_SHIFT;
+
+ return ns;
+}
+
+static void ixp_systime_write(struct ixp46x_ts_regs *regs, u64 ns)
+{
+ u32 hi, lo;
+
+ ns >>= TICKS_NS_SHIFT;
+ hi = ns >> 32;
+ lo = ns & 0xffffffff;
+
+ __raw_writel(lo, &regs->systime_lo);
+ __raw_writel(hi, &regs->systime_hi);
+}
+
+/*
+ * Interrupt service routine
+ */
+
+static irqreturn_t isr(int irq, void *priv)
+{
+ struct ixp_clock *ixp_clock = priv;
+ struct ixp46x_ts_regs *regs = ixp_clock->regs;
+ struct ptp_clock_event event;
+ u32 ack = 0, lo, hi, val;
+
+ val = __raw_readl(&regs->event);
+
+ if (val & TSER_SNS) {
+ ack |= TSER_SNS;
+ if (ixp_clock->exts0_enabled) {
+ hi = __raw_readl(&regs->asms_hi);
+ lo = __raw_readl(&regs->asms_lo);
+ event.type = PTP_CLOCK_EXTTS;
+ event.index = 0;
+ event.timestamp = ((u64) hi) << 32;
+ event.timestamp |= lo;
+ event.timestamp <<= TICKS_NS_SHIFT;
+ ptp_clock_event(ixp_clock->ptp_clock, &event);
+ }
+ }
+
+ if (val & TSER_SNM) {
+ ack |= TSER_SNM;
+ if (ixp_clock->exts1_enabled) {
+ hi = __raw_readl(&regs->amms_hi);
+ lo = __raw_readl(&regs->amms_lo);
+ event.type = PTP_CLOCK_EXTTS;
+ event.index = 1;
+ event.timestamp = ((u64) hi) << 32;
+ event.timestamp |= lo;
+ event.timestamp <<= TICKS_NS_SHIFT;
+ ptp_clock_event(ixp_clock->ptp_clock, &event);
+ }
+ }
+
+ if (val & TTIPEND)
+ ack |= TTIPEND; /* this bit seems to be always set */
+
+ if (ack) {
+ __raw_writel(ack, &regs->event);
+ return IRQ_HANDLED;
+ } else
+ return IRQ_NONE;
+}
+
+/*
+ * PTP clock operations
+ */
+
+static int ptp_ixp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
+{
+ u64 adj;
+ u32 diff, addend;
+ int neg_adj = 0;
+ struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps);
+ struct ixp46x_ts_regs *regs = ixp_clock->regs;
+
+ if (ppb < 0) {
+ neg_adj = 1;
+ ppb = -ppb;
+ }
+ addend = DEFAULT_ADDEND;
+ adj = addend;
+ adj *= ppb;
+ diff = div_u64(adj, 1000000000ULL);
+
+ addend = neg_adj ? addend - diff : addend + diff;
+
+ __raw_writel(addend, &regs->addend);
+
+ return 0;
+}
+
+static int ptp_ixp_adjtime(struct ptp_clock_info *ptp, s64 delta)
+{
+ s64 now;
+ unsigned long flags;
+ struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps);
+ struct ixp46x_ts_regs *regs = ixp_clock->regs;
+
+ spin_lock_irqsave(&register_lock, flags);
+
+ now = ixp_systime_read(regs);
+ now += delta;
+ ixp_systime_write(regs, now);
+
+ spin_unlock_irqrestore(&register_lock, flags);
+
+ return 0;
+}
+
+static int ptp_ixp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
+{
+ u64 ns;
+ u32 remainder;
+ unsigned long flags;
+ struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps);
+ struct ixp46x_ts_regs *regs = ixp_clock->regs;
+
+ spin_lock_irqsave(&register_lock, flags);
+
+ ns = ixp_systime_read(regs);
+
+ spin_unlock_irqrestore(&register_lock, flags);
+
+ ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder);
+ ts->tv_nsec = remainder;
+ return 0;
+}
+
+static int ptp_ixp_settime(struct ptp_clock_info *ptp,
+ const struct timespec *ts)
+{
+ u64 ns;
+ unsigned long flags;
+ struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps);
+ struct ixp46x_ts_regs *regs = ixp_clock->regs;
+
+ ns = ts->tv_sec * 1000000000ULL;
+ ns += ts->tv_nsec;
+
+ spin_lock_irqsave(&register_lock, flags);
+
+ ixp_systime_write(regs, ns);
+
+ spin_unlock_irqrestore(&register_lock, flags);
+
+ return 0;
+}
+
+static int ptp_ixp_enable(struct ptp_clock_info *ptp,
+ struct ptp_clock_request *rq, int on)
+{
+ struct ixp_clock *ixp_clock = container_of(ptp, struct ixp_clock, caps);
+
+ switch (rq->type) {
+ case PTP_CLK_REQ_EXTTS:
+ switch (rq->extts.index) {
+ case 0:
+ ixp_clock->exts0_enabled = on ? 1 : 0;
+ break;
+ case 1:
+ ixp_clock->exts1_enabled = on ? 1 : 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static struct ptp_clock_info ptp_ixp_caps = {
+ .owner = THIS_MODULE,
+ .name = "IXP46X timer",
+ .max_adj = 66666655,
+ .n_ext_ts = N_EXT_TS,
+ .pps = 0,
+ .adjfreq = ptp_ixp_adjfreq,
+ .adjtime = ptp_ixp_adjtime,
+ .gettime = ptp_ixp_gettime,
+ .settime = ptp_ixp_settime,
+ .enable = ptp_ixp_enable,
+};
+
+/* module operations */
+
+static struct ixp_clock ixp_clock;
+
+static int setup_interrupt(int gpio)
+{
+ int irq;
+
+ gpio_line_config(gpio, IXP4XX_GPIO_IN);
+
+ irq = gpio_to_irq(gpio);
+
+ if (NO_IRQ == irq)
+ return NO_IRQ;
+
+ if (irq_set_irq_type(irq, IRQF_TRIGGER_FALLING)) {
+ pr_err("cannot set trigger type for irq %d\n", irq);
+ return NO_IRQ;
+ }
+
+ if (request_irq(irq, isr, 0, DRIVER, &ixp_clock)) {
+ pr_err("request_irq failed for irq %d\n", irq);
+ return NO_IRQ;
+ }
+
+ return irq;
+}
+
+static void __exit ptp_ixp_exit(void)
+{
+ free_irq(MASTER_IRQ, &ixp_clock);
+ free_irq(SLAVE_IRQ, &ixp_clock);
+ ptp_clock_unregister(ixp_clock.ptp_clock);
+}
+
+static int __init ptp_ixp_init(void)
+{
+ if (!cpu_is_ixp46x())
+ return -ENODEV;
+
+ ixp_clock.regs =
+ (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT;
+
+ ixp_clock.caps = ptp_ixp_caps;
+
+ ixp_clock.ptp_clock = ptp_clock_register(&ixp_clock.caps);
+
+ if (IS_ERR(ixp_clock.ptp_clock))
+ return PTR_ERR(ixp_clock.ptp_clock);
+
+ __raw_writel(DEFAULT_ADDEND, &ixp_clock.regs->addend);
+ __raw_writel(1, &ixp_clock.regs->trgt_lo);
+ __raw_writel(0, &ixp_clock.regs->trgt_hi);
+ __raw_writel(TTIPEND, &ixp_clock.regs->event);
+
+ if (MASTER_IRQ != setup_interrupt(MASTER_GPIO)) {
+ pr_err("failed to setup gpio %d as irq\n", MASTER_GPIO);
+ goto no_master;
+ }
+ if (SLAVE_IRQ != setup_interrupt(SLAVE_GPIO)) {
+ pr_err("failed to setup gpio %d as irq\n", SLAVE_GPIO);
+ goto no_slave;
+ }
+
+ return 0;
+no_slave:
+ free_irq(MASTER_IRQ, &ixp_clock);
+no_master:
+ ptp_clock_unregister(ixp_clock.ptp_clock);
+ return -ENODEV;
+}
+
+module_init(ptp_ixp_init);
+module_exit(ptp_ixp_exit);
+
+MODULE_AUTHOR("Richard Cochran <richard.cochran@omicron.at>");
+MODULE_DESCRIPTION("PTP clock using the IXP46X timer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ptp/ptp_private.h b/drivers/ptp/ptp_private.h
new file mode 100644
index 000000000000..4d5b5082c3b1
--- /dev/null
+++ b/drivers/ptp/ptp_private.h
@@ -0,0 +1,92 @@
+/*
+ * PTP 1588 clock support - private declarations for the core module.
+ *
+ * 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_PRIVATE_H_
+#define _PTP_PRIVATE_H_
+
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/posix-clock.h>
+#include <linux/ptp_clock.h>
+#include <linux/ptp_clock_kernel.h>
+#include <linux/time.h>
+
+#define PTP_MAX_TIMESTAMPS 128
+#define PTP_BUF_TIMESTAMPS 30
+
+struct timestamp_event_queue {
+ struct ptp_extts_event buf[PTP_MAX_TIMESTAMPS];
+ int head;
+ int tail;
+ spinlock_t lock;
+};
+
+struct ptp_clock {
+ struct posix_clock clock;
+ struct device *dev;
+ struct ptp_clock_info *info;
+ dev_t devid;
+ int index; /* index into clocks.map */
+ struct pps_device *pps_source;
+ struct timestamp_event_queue tsevq; /* simple fifo for time stamps */
+ struct mutex tsevq_mux; /* one process at a time reading the fifo */
+ wait_queue_head_t tsev_wq;
+ int defunct; /* tells readers to go away when clock is being removed */
+};
+
+/*
+ * The function queue_cnt() is safe for readers to call without
+ * holding q->lock. Readers use this function to verify that the queue
+ * is nonempty before proceeding with a dequeue operation. The fact
+ * that a writer might concurrently increment the tail does not
+ * matter, since the queue remains nonempty nonetheless.
+ */
+static inline int queue_cnt(struct timestamp_event_queue *q)
+{
+ int cnt = q->tail - q->head;
+ return cnt < 0 ? PTP_MAX_TIMESTAMPS + cnt : cnt;
+}
+
+/*
+ * see ptp_chardev.c
+ */
+
+long ptp_ioctl(struct posix_clock *pc,
+ unsigned int cmd, unsigned long arg);
+
+int ptp_open(struct posix_clock *pc, fmode_t fmode);
+
+ssize_t ptp_read(struct posix_clock *pc,
+ uint flags, char __user *buf, size_t cnt);
+
+uint ptp_poll(struct posix_clock *pc,
+ struct file *fp, poll_table *wait);
+
+/*
+ * see ptp_sysfs.c
+ */
+
+extern struct device_attribute ptp_dev_attrs[];
+
+int ptp_cleanup_sysfs(struct ptp_clock *ptp);
+
+int ptp_populate_sysfs(struct ptp_clock *ptp);
+
+#endif
diff --git a/drivers/ptp/ptp_sysfs.c b/drivers/ptp/ptp_sysfs.c
new file mode 100644
index 000000000000..2f93926ac976
--- /dev/null
+++ b/drivers/ptp/ptp_sysfs.c
@@ -0,0 +1,230 @@
+/*
+ * PTP 1588 clock support - sysfs interface.
+ *
+ * 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/capability.h>
+
+#include "ptp_private.h"
+
+static ssize_t clock_name_show(struct device *dev,
+ struct device_attribute *attr, char *page)
+{
+ struct ptp_clock *ptp = dev_get_drvdata(dev);
+ return snprintf(page, PAGE_SIZE-1, "%s\n", ptp->info->name);
+}
+
+#define PTP_SHOW_INT(name) \
+static ssize_t name##_show(struct device *dev, \
+ struct device_attribute *attr, char *page) \
+{ \
+ struct ptp_clock *ptp = dev_get_drvdata(dev); \
+ return snprintf(page, PAGE_SIZE-1, "%d\n", ptp->info->name); \
+}
+
+PTP_SHOW_INT(max_adj);
+PTP_SHOW_INT(n_alarm);
+PTP_SHOW_INT(n_ext_ts);
+PTP_SHOW_INT(n_per_out);
+PTP_SHOW_INT(pps);
+
+#define PTP_RO_ATTR(_var, _name) { \
+ .attr = { .name = __stringify(_name), .mode = 0444 }, \
+ .show = _var##_show, \
+}
+
+struct device_attribute ptp_dev_attrs[] = {
+ PTP_RO_ATTR(clock_name, clock_name),
+ PTP_RO_ATTR(max_adj, max_adjustment),
+ PTP_RO_ATTR(n_alarm, n_alarms),
+ PTP_RO_ATTR(n_ext_ts, n_external_timestamps),
+ PTP_RO_ATTR(n_per_out, n_periodic_outputs),
+ PTP_RO_ATTR(pps, pps_available),
+ __ATTR_NULL,
+};
+
+static ssize_t extts_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ptp_clock *ptp = dev_get_drvdata(dev);
+ struct ptp_clock_info *ops = ptp->info;
+ struct ptp_clock_request req = { .type = PTP_CLK_REQ_EXTTS };
+ int cnt, enable;
+ int err = -EINVAL;
+
+ cnt = sscanf(buf, "%u %d", &req.extts.index, &enable);
+ if (cnt != 2)
+ goto out;
+ if (req.extts.index >= ops->n_ext_ts)
+ goto out;
+
+ err = ops->enable(ops, &req, enable ? 1 : 0);
+ if (err)
+ goto out;
+
+ return count;
+out:
+ return err;
+}
+
+static ssize_t extts_fifo_show(struct device *dev,
+ struct device_attribute *attr, char *page)
+{
+ struct ptp_clock *ptp = dev_get_drvdata(dev);
+ struct timestamp_event_queue *queue = &ptp->tsevq;
+ struct ptp_extts_event event;
+ unsigned long flags;
+ size_t qcnt;
+ int cnt = 0;
+
+ memset(&event, 0, sizeof(event));
+
+ if (mutex_lock_interruptible(&ptp->tsevq_mux))
+ return -ERESTARTSYS;
+
+ spin_lock_irqsave(&queue->lock, flags);
+ qcnt = queue_cnt(queue);
+ if (qcnt) {
+ event = queue->buf[queue->head];
+ queue->head = (queue->head + 1) % PTP_MAX_TIMESTAMPS;
+ }
+ spin_unlock_irqrestore(&queue->lock, flags);
+
+ if (!qcnt)
+ goto out;
+
+ cnt = snprintf(page, PAGE_SIZE, "%u %lld %u\n",
+ event.index, event.t.sec, event.t.nsec);
+out:
+ mutex_unlock(&ptp->tsevq_mux);
+ return cnt;
+}
+
+static ssize_t period_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ptp_clock *ptp = dev_get_drvdata(dev);
+ struct ptp_clock_info *ops = ptp->info;
+ struct ptp_clock_request req = { .type = PTP_CLK_REQ_PEROUT };
+ int cnt, enable, err = -EINVAL;
+
+ cnt = sscanf(buf, "%u %lld %u %lld %u", &req.perout.index,
+ &req.perout.start.sec, &req.perout.start.nsec,
+ &req.perout.period.sec, &req.perout.period.nsec);
+ if (cnt != 5)
+ goto out;
+ if (req.perout.index >= ops->n_per_out)
+ goto out;
+
+ enable = req.perout.period.sec || req.perout.period.nsec;
+ err = ops->enable(ops, &req, enable);
+ if (err)
+ goto out;
+
+ return count;
+out:
+ return err;
+}
+
+static ssize_t pps_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ptp_clock *ptp = dev_get_drvdata(dev);
+ struct ptp_clock_info *ops = ptp->info;
+ struct ptp_clock_request req = { .type = PTP_CLK_REQ_PPS };
+ int cnt, enable;
+ int err = -EINVAL;
+
+ if (!capable(CAP_SYS_TIME))
+ return -EPERM;
+
+ cnt = sscanf(buf, "%d", &enable);
+ if (cnt != 1)
+ goto out;
+
+ err = ops->enable(ops, &req, enable ? 1 : 0);
+ if (err)
+ goto out;
+
+ return count;
+out:
+ return err;
+}
+
+static DEVICE_ATTR(extts_enable, 0220, NULL, extts_enable_store);
+static DEVICE_ATTR(fifo, 0444, extts_fifo_show, NULL);
+static DEVICE_ATTR(period, 0220, NULL, period_store);
+static DEVICE_ATTR(pps_enable, 0220, NULL, pps_enable_store);
+
+int ptp_cleanup_sysfs(struct ptp_clock *ptp)
+{
+ struct device *dev = ptp->dev;
+ struct ptp_clock_info *info = ptp->info;
+
+ if (info->n_ext_ts) {
+ device_remove_file(dev, &dev_attr_extts_enable);
+ device_remove_file(dev, &dev_attr_fifo);
+ }
+ if (info->n_per_out)
+ device_remove_file(dev, &dev_attr_period);
+
+ if (info->pps)
+ device_remove_file(dev, &dev_attr_pps_enable);
+
+ return 0;
+}
+
+int ptp_populate_sysfs(struct ptp_clock *ptp)
+{
+ struct device *dev = ptp->dev;
+ struct ptp_clock_info *info = ptp->info;
+ int err;
+
+ if (info->n_ext_ts) {
+ err = device_create_file(dev, &dev_attr_extts_enable);
+ if (err)
+ goto out1;
+ err = device_create_file(dev, &dev_attr_fifo);
+ if (err)
+ goto out2;
+ }
+ if (info->n_per_out) {
+ err = device_create_file(dev, &dev_attr_period);
+ if (err)
+ goto out3;
+ }
+ if (info->pps) {
+ err = device_create_file(dev, &dev_attr_pps_enable);
+ if (err)
+ goto out4;
+ }
+ return 0;
+out4:
+ if (info->n_per_out)
+ device_remove_file(dev, &dev_attr_period);
+out3:
+ if (info->n_ext_ts)
+ device_remove_file(dev, &dev_attr_fifo);
+out2:
+ if (info->n_ext_ts)
+ device_remove_file(dev, &dev_attr_extts_enable);
+out1:
+ return err;
+}
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c
index 859251250b55..d63fddb0fbb0 100644
--- a/drivers/regulator/88pm8607.c
+++ b/drivers/regulator/88pm8607.c
@@ -15,7 +15,6 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
-#include <linux/mfd/core.h>
#include <linux/mfd/88pm860x.h>
struct pm8607_regulator_info {
@@ -399,36 +398,33 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
{
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
struct pm8607_regulator_info *info = NULL;
- struct regulator_init_data *pdata;
- struct mfd_cell *cell;
+ struct regulator_init_data *pdata = pdev->dev.platform_data;
+ struct resource *res;
int i;
- cell = pdev->dev.platform_data;
- if (cell == NULL)
- return -ENODEV;
- pdata = cell->mfd_data;
- if (pdata == NULL)
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "No I/O resource!\n");
return -EINVAL;
-
+ }
for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
info = &pm8607_regulator_info[i];
- if (!strcmp(info->desc.name, pdata->constraints.name))
+ if (info->desc.id == res->start)
break;
}
- if (i > ARRAY_SIZE(pm8607_regulator_info)) {
- dev_err(&pdev->dev, "Failed to find regulator %s\n",
- pdata->constraints.name);
+ if ((i < 0) || (i > PM8607_ID_RG_MAX)) {
+ dev_err(&pdev->dev, "Failed to find regulator %llu\n",
+ (unsigned long long)res->start);
return -EINVAL;
}
-
info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
info->chip = chip;
/* check DVC ramp slope double */
- if (!strcmp(info->desc.name, "BUCK3"))
- if (info->chip->buck3_double)
- info->slope_double = 1;
+ if ((i == PM8607_ID_BUCK3) && info->chip->buck3_double)
+ info->slope_double = 1;
+ /* replace driver_data with info */
info->regulator = regulator_register(&info->desc, &pdev->dev,
pdata, info);
if (IS_ERR(info->regulator)) {
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index b9f29e0d4295..d7ed20f293d7 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -274,6 +274,13 @@ config REGULATOR_AB8500
This driver supports the regulators found on the ST-Ericsson mixed
signal AB8500 PMIC
+config REGULATOR_DB8500_PRCMU
+ bool "ST-Ericsson DB8500 Voltage Domain Regulators"
+ depends on MFD_DB8500_PRCMU
+ help
+ This driver supports the voltage domain regulators controlled by the
+ DB8500 PRCMU
+
config REGULATOR_TPS6586X
tristate "TI TPS6586X Power regulators"
depends on MFD_TPS6586X
@@ -290,5 +297,11 @@ config REGULATOR_TPS6524X
serial interface currently supported on the sequencer serial
port controller.
+config REGULATOR_TPS65910
+ tristate "TI TPS65910 Power Regulator"
+ depends on MFD_TPS65910
+ help
+ This driver supports TPS65910 voltage regulator chips.
+
endif
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index d72a42756778..3932d2ec38f3 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -41,5 +41,7 @@ obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o
obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o
obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o
+obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o
+obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c
index b1d77946e9c6..585e4946fe0a 100644
--- a/drivers/regulator/ab3100.c
+++ b/drivers/regulator/ab3100.c
@@ -17,7 +17,6 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/mfd/abx500.h>
-#include <linux/mfd/core.h>
/* LDO registers and some handy masking definitions for AB3100 */
#define AB3100_LDO_A 0x40
@@ -582,7 +581,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
static int __devinit ab3100_regulators_probe(struct platform_device *pdev)
{
- struct ab3100_platform_data *plfdata = mfd_get_data(pdev);
+ struct ab3100_platform_data *plfdata = pdev->dev.platform_data;
int err = 0;
u8 data;
int i;
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 0fae51c4845a..d3e38790906e 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -158,6 +158,13 @@ static int regulator_check_consumers(struct regulator_dev *rdev,
struct regulator *regulator;
list_for_each_entry(regulator, &rdev->consumer_list, list) {
+ /*
+ * Assume consumers that didn't say anything are OK
+ * with anything in the constraint range.
+ */
+ if (!regulator->min_uV && !regulator->max_uV)
+ continue;
+
if (*max_uV > regulator->max_uV)
*max_uV = regulator->max_uV;
if (*min_uV < regulator->min_uV)
@@ -197,9 +204,9 @@ static int regulator_check_current_limit(struct regulator_dev *rdev,
}
/* operating mode constraint check */
-static int regulator_check_mode(struct regulator_dev *rdev, int mode)
+static int regulator_mode_constrain(struct regulator_dev *rdev, int *mode)
{
- switch (mode) {
+ switch (*mode) {
case REGULATOR_MODE_FAST:
case REGULATOR_MODE_NORMAL:
case REGULATOR_MODE_IDLE:
@@ -217,11 +224,17 @@ static int regulator_check_mode(struct regulator_dev *rdev, int mode)
rdev_err(rdev, "operation not allowed\n");
return -EPERM;
}
- if (!(rdev->constraints->valid_modes_mask & mode)) {
- rdev_err(rdev, "invalid mode %x\n", mode);
- return -EINVAL;
+
+ /* The modes are bitmasks, the most power hungry modes having
+ * the lowest values. If the requested mode isn't supported
+ * try higher modes. */
+ while (*mode) {
+ if (rdev->constraints->valid_modes_mask & *mode)
+ return 0;
+ *mode /= 2;
}
- return 0;
+
+ return -EINVAL;
}
/* dynamic regulator mode switching constraint check */
@@ -612,7 +625,7 @@ static void drms_uA_update(struct regulator_dev *rdev)
output_uV, current_uA);
/* check the new mode is allowed */
- err = regulator_check_mode(rdev, mode);
+ err = regulator_mode_constrain(rdev, &mode);
if (err == 0)
rdev->desc->ops->set_mode(rdev, mode);
}
@@ -718,6 +731,10 @@ static void print_constraints(struct regulator_dev *rdev)
count += sprintf(buf + count, "at %d mV ", ret / 1000);
}
+ if (constraints->uV_offset)
+ count += sprintf(buf, "%dmV offset ",
+ constraints->uV_offset / 1000);
+
if (constraints->min_uA && constraints->max_uA) {
if (constraints->min_uA == constraints->max_uA)
count += sprintf(buf + count, "%d mA ",
@@ -1498,13 +1515,14 @@ static int _regulator_force_disable(struct regulator_dev *rdev,
*/
int regulator_force_disable(struct regulator *regulator)
{
+ struct regulator_dev *rdev = regulator->rdev;
struct regulator_dev *supply_rdev = NULL;
int ret;
- mutex_lock(&regulator->rdev->mutex);
+ mutex_lock(&rdev->mutex);
regulator->uA_load = 0;
- ret = _regulator_force_disable(regulator->rdev, &supply_rdev);
- mutex_unlock(&regulator->rdev->mutex);
+ ret = _regulator_force_disable(rdev, &supply_rdev);
+ mutex_unlock(&rdev->mutex);
if (supply_rdev)
regulator_disable(get_device_regulator(rdev_get_dev(supply_rdev)));
@@ -1634,6 +1652,9 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV);
+ min_uV += rdev->constraints->uV_offset;
+ max_uV += rdev->constraints->uV_offset;
+
if (rdev->desc->ops->set_voltage) {
ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV,
&selector);
@@ -1858,18 +1879,22 @@ EXPORT_SYMBOL_GPL(regulator_sync_voltage);
static int _regulator_get_voltage(struct regulator_dev *rdev)
{
- int sel;
+ int sel, ret;
if (rdev->desc->ops->get_voltage_sel) {
sel = rdev->desc->ops->get_voltage_sel(rdev);
if (sel < 0)
return sel;
- return rdev->desc->ops->list_voltage(rdev, sel);
- }
- if (rdev->desc->ops->get_voltage)
- return rdev->desc->ops->get_voltage(rdev);
- else
+ ret = rdev->desc->ops->list_voltage(rdev, sel);
+ } else if (rdev->desc->ops->get_voltage) {
+ ret = rdev->desc->ops->get_voltage(rdev);
+ } else {
return -EINVAL;
+ }
+
+ if (ret < 0)
+ return ret;
+ return ret - rdev->constraints->uV_offset;
}
/**
@@ -2005,7 +2030,7 @@ int regulator_set_mode(struct regulator *regulator, unsigned int mode)
}
/* constraints check */
- ret = regulator_check_mode(rdev, mode);
+ ret = regulator_mode_constrain(rdev, &mode);
if (ret < 0)
goto out;
@@ -2081,16 +2106,26 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
mutex_lock(&rdev->mutex);
+ /*
+ * first check to see if we can set modes at all, otherwise just
+ * tell the consumer everything is OK.
+ */
regulator->uA_load = uA_load;
ret = regulator_check_drms(rdev);
- if (ret < 0)
+ if (ret < 0) {
+ ret = 0;
goto out;
- ret = -EINVAL;
+ }
- /* sanity check */
if (!rdev->desc->ops->get_optimum_mode)
goto out;
+ /*
+ * we can actually do this so any errors are indicators of
+ * potential real failure.
+ */
+ ret = -EINVAL;
+
/* get output voltage */
output_uV = _regulator_get_voltage(rdev);
if (output_uV <= 0) {
@@ -2116,7 +2151,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
mode = rdev->desc->ops->get_optimum_mode(rdev,
input_uV, output_uV,
total_uA_load);
- ret = regulator_check_mode(rdev, mode);
+ ret = regulator_mode_constrain(rdev, &mode);
if (ret < 0) {
rdev_err(rdev, "failed to get optimum mode @ %d uA %d -> %d uV\n",
total_uA_load, input_uV, output_uV);
@@ -2589,14 +2624,6 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
if (ret < 0)
goto scrub;
- /* set supply regulator if it exists */
- if (init_data->supply_regulator && init_data->supply_regulator_dev) {
- dev_err(dev,
- "Supply regulator specified by both name and dev\n");
- ret = -EINVAL;
- goto scrub;
- }
-
if (init_data->supply_regulator) {
struct regulator_dev *r;
int found = 0;
@@ -2621,14 +2648,6 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
goto scrub;
}
- if (init_data->supply_regulator_dev) {
- dev_warn(dev, "Uses supply_regulator_dev instead of regulator_supply\n");
- ret = set_supply(rdev,
- dev_get_drvdata(init_data->supply_regulator_dev));
- if (ret < 0)
- goto scrub;
- }
-
/* add consumers devices */
for (i = 0; i < init_data->num_consumer_supplies; i++) {
ret = set_consumer_device_supply(rdev,
diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c
new file mode 100644
index 000000000000..e5f7b8fe51f4
--- /dev/null
+++ b/drivers/regulator/db8500-prcmu.c
@@ -0,0 +1,558 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * License Terms: GNU General Public License v2
+ * Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
+ * Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
+ *
+ * Power domain regulators on DB8500
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/db8500-prcmu.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/db8500-prcmu.h>
+
+/*
+ * power state reference count
+ */
+static int power_state_active_cnt; /* will initialize to zero */
+static DEFINE_SPINLOCK(power_state_active_lock);
+
+static void power_state_active_enable(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&power_state_active_lock, flags);
+ power_state_active_cnt++;
+ spin_unlock_irqrestore(&power_state_active_lock, flags);
+}
+
+static int power_state_active_disable(void)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&power_state_active_lock, flags);
+ if (power_state_active_cnt <= 0) {
+ pr_err("power state: unbalanced enable/disable calls\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ power_state_active_cnt--;
+out:
+ spin_unlock_irqrestore(&power_state_active_lock, flags);
+ return ret;
+}
+
+/*
+ * Exported interface for CPUIdle only. This function is called when interrupts
+ * are turned off. Hence, no locking.
+ */
+int power_state_active_is_enabled(void)
+{
+ return (power_state_active_cnt > 0);
+}
+
+/**
+ * struct db8500_regulator_info - db8500 regulator information
+ * @dev: device pointer
+ * @desc: regulator description
+ * @rdev: regulator device pointer
+ * @is_enabled: status of the regulator
+ * @epod_id: id for EPOD (power domain)
+ * @is_ramret: RAM retention switch for EPOD (power domain)
+ * @operating_point: operating point (only for vape, to be removed)
+ *
+ */
+struct db8500_regulator_info {
+ struct device *dev;
+ struct regulator_desc desc;
+ struct regulator_dev *rdev;
+ bool is_enabled;
+ u16 epod_id;
+ bool is_ramret;
+ bool exclude_from_power_state;
+ unsigned int operating_point;
+};
+
+static int db8500_regulator_enable(struct regulator_dev *rdev)
+{
+ struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ if (info == NULL)
+ return -EINVAL;
+
+ dev_vdbg(rdev_get_dev(rdev), "regulator-%s-enable\n",
+ info->desc.name);
+
+ info->is_enabled = true;
+ if (!info->exclude_from_power_state)
+ power_state_active_enable();
+
+ return 0;
+}
+
+static int db8500_regulator_disable(struct regulator_dev *rdev)
+{
+ struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+ int ret = 0;
+
+ if (info == NULL)
+ return -EINVAL;
+
+ dev_vdbg(rdev_get_dev(rdev), "regulator-%s-disable\n",
+ info->desc.name);
+
+ info->is_enabled = false;
+ if (!info->exclude_from_power_state)
+ ret = power_state_active_disable();
+
+ return ret;
+}
+
+static int db8500_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ if (info == NULL)
+ return -EINVAL;
+
+ dev_vdbg(rdev_get_dev(rdev), "regulator-%s-is_enabled (is_enabled):"
+ " %i\n", info->desc.name, info->is_enabled);
+
+ return info->is_enabled;
+}
+
+/* db8500 regulator operations */
+static struct regulator_ops db8500_regulator_ops = {
+ .enable = db8500_regulator_enable,
+ .disable = db8500_regulator_disable,
+ .is_enabled = db8500_regulator_is_enabled,
+};
+
+/*
+ * EPOD control
+ */
+static bool epod_on[NUM_EPOD_ID];
+static bool epod_ramret[NUM_EPOD_ID];
+
+static int enable_epod(u16 epod_id, bool ramret)
+{
+ int ret;
+
+ if (ramret) {
+ if (!epod_on[epod_id]) {
+ ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET);
+ if (ret < 0)
+ return ret;
+ }
+ epod_ramret[epod_id] = true;
+ } else {
+ ret = prcmu_set_epod(epod_id, EPOD_STATE_ON);
+ if (ret < 0)
+ return ret;
+ epod_on[epod_id] = true;
+ }
+
+ return 0;
+}
+
+static int disable_epod(u16 epod_id, bool ramret)
+{
+ int ret;
+
+ if (ramret) {
+ if (!epod_on[epod_id]) {
+ ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF);
+ if (ret < 0)
+ return ret;
+ }
+ epod_ramret[epod_id] = false;
+ } else {
+ if (epod_ramret[epod_id]) {
+ ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET);
+ if (ret < 0)
+ return ret;
+ } else {
+ ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF);
+ if (ret < 0)
+ return ret;
+ }
+ epod_on[epod_id] = false;
+ }
+
+ return 0;
+}
+
+/*
+ * Regulator switch
+ */
+static int db8500_regulator_switch_enable(struct regulator_dev *rdev)
+{
+ struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+ int ret;
+
+ if (info == NULL)
+ return -EINVAL;
+
+ dev_vdbg(rdev_get_dev(rdev), "regulator-switch-%s-enable\n",
+ info->desc.name);
+
+ ret = enable_epod(info->epod_id, info->is_ramret);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev),
+ "regulator-switch-%s-enable: prcmu call failed\n",
+ info->desc.name);
+ goto out;
+ }
+
+ info->is_enabled = true;
+out:
+ return ret;
+}
+
+static int db8500_regulator_switch_disable(struct regulator_dev *rdev)
+{
+ struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+ int ret;
+
+ if (info == NULL)
+ return -EINVAL;
+
+ dev_vdbg(rdev_get_dev(rdev), "regulator-switch-%s-disable\n",
+ info->desc.name);
+
+ ret = disable_epod(info->epod_id, info->is_ramret);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev),
+ "regulator_switch-%s-disable: prcmu call failed\n",
+ info->desc.name);
+ goto out;
+ }
+
+ info->is_enabled = 0;
+out:
+ return ret;
+}
+
+static int db8500_regulator_switch_is_enabled(struct regulator_dev *rdev)
+{
+ struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ if (info == NULL)
+ return -EINVAL;
+
+ dev_vdbg(rdev_get_dev(rdev),
+ "regulator-switch-%s-is_enabled (is_enabled): %i\n",
+ info->desc.name, info->is_enabled);
+
+ return info->is_enabled;
+}
+
+static struct regulator_ops db8500_regulator_switch_ops = {
+ .enable = db8500_regulator_switch_enable,
+ .disable = db8500_regulator_switch_disable,
+ .is_enabled = db8500_regulator_switch_is_enabled,
+};
+
+/*
+ * Regulator information
+ */
+static struct db8500_regulator_info
+ db8500_regulator_info[DB8500_NUM_REGULATORS] = {
+ [DB8500_REGULATOR_VAPE] = {
+ .desc = {
+ .name = "db8500-vape",
+ .id = DB8500_REGULATOR_VAPE,
+ .ops = &db8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ },
+ [DB8500_REGULATOR_VARM] = {
+ .desc = {
+ .name = "db8500-varm",
+ .id = DB8500_REGULATOR_VARM,
+ .ops = &db8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ },
+ [DB8500_REGULATOR_VMODEM] = {
+ .desc = {
+ .name = "db8500-vmodem",
+ .id = DB8500_REGULATOR_VMODEM,
+ .ops = &db8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ },
+ [DB8500_REGULATOR_VPLL] = {
+ .desc = {
+ .name = "db8500-vpll",
+ .id = DB8500_REGULATOR_VPLL,
+ .ops = &db8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ },
+ [DB8500_REGULATOR_VSMPS1] = {
+ .desc = {
+ .name = "db8500-vsmps1",
+ .id = DB8500_REGULATOR_VSMPS1,
+ .ops = &db8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ },
+ [DB8500_REGULATOR_VSMPS2] = {
+ .desc = {
+ .name = "db8500-vsmps2",
+ .id = DB8500_REGULATOR_VSMPS2,
+ .ops = &db8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .exclude_from_power_state = true,
+ },
+ [DB8500_REGULATOR_VSMPS3] = {
+ .desc = {
+ .name = "db8500-vsmps3",
+ .id = DB8500_REGULATOR_VSMPS3,
+ .ops = &db8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ },
+ [DB8500_REGULATOR_VRF1] = {
+ .desc = {
+ .name = "db8500-vrf1",
+ .id = DB8500_REGULATOR_VRF1,
+ .ops = &db8500_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ },
+ [DB8500_REGULATOR_SWITCH_SVAMMDSP] = {
+ .desc = {
+ .name = "db8500-sva-mmdsp",
+ .id = DB8500_REGULATOR_SWITCH_SVAMMDSP,
+ .ops = &db8500_regulator_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .epod_id = EPOD_ID_SVAMMDSP,
+ },
+ [DB8500_REGULATOR_SWITCH_SVAMMDSPRET] = {
+ .desc = {
+ .name = "db8500-sva-mmdsp-ret",
+ .id = DB8500_REGULATOR_SWITCH_SVAMMDSPRET,
+ .ops = &db8500_regulator_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .epod_id = EPOD_ID_SVAMMDSP,
+ .is_ramret = true,
+ },
+ [DB8500_REGULATOR_SWITCH_SVAPIPE] = {
+ .desc = {
+ .name = "db8500-sva-pipe",
+ .id = DB8500_REGULATOR_SWITCH_SVAPIPE,
+ .ops = &db8500_regulator_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .epod_id = EPOD_ID_SVAPIPE,
+ },
+ [DB8500_REGULATOR_SWITCH_SIAMMDSP] = {
+ .desc = {
+ .name = "db8500-sia-mmdsp",
+ .id = DB8500_REGULATOR_SWITCH_SIAMMDSP,
+ .ops = &db8500_regulator_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .epod_id = EPOD_ID_SIAMMDSP,
+ },
+ [DB8500_REGULATOR_SWITCH_SIAMMDSPRET] = {
+ .desc = {
+ .name = "db8500-sia-mmdsp-ret",
+ .id = DB8500_REGULATOR_SWITCH_SIAMMDSPRET,
+ .ops = &db8500_regulator_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .epod_id = EPOD_ID_SIAMMDSP,
+ .is_ramret = true,
+ },
+ [DB8500_REGULATOR_SWITCH_SIAPIPE] = {
+ .desc = {
+ .name = "db8500-sia-pipe",
+ .id = DB8500_REGULATOR_SWITCH_SIAPIPE,
+ .ops = &db8500_regulator_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .epod_id = EPOD_ID_SIAPIPE,
+ },
+ [DB8500_REGULATOR_SWITCH_SGA] = {
+ .desc = {
+ .name = "db8500-sga",
+ .id = DB8500_REGULATOR_SWITCH_SGA,
+ .ops = &db8500_regulator_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .epod_id = EPOD_ID_SGA,
+ },
+ [DB8500_REGULATOR_SWITCH_B2R2_MCDE] = {
+ .desc = {
+ .name = "db8500-b2r2-mcde",
+ .id = DB8500_REGULATOR_SWITCH_B2R2_MCDE,
+ .ops = &db8500_regulator_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .epod_id = EPOD_ID_B2R2_MCDE,
+ },
+ [DB8500_REGULATOR_SWITCH_ESRAM12] = {
+ .desc = {
+ .name = "db8500-esram12",
+ .id = DB8500_REGULATOR_SWITCH_ESRAM12,
+ .ops = &db8500_regulator_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .epod_id = EPOD_ID_ESRAM12,
+ .is_enabled = true,
+ },
+ [DB8500_REGULATOR_SWITCH_ESRAM12RET] = {
+ .desc = {
+ .name = "db8500-esram12-ret",
+ .id = DB8500_REGULATOR_SWITCH_ESRAM12RET,
+ .ops = &db8500_regulator_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .epod_id = EPOD_ID_ESRAM12,
+ .is_ramret = true,
+ },
+ [DB8500_REGULATOR_SWITCH_ESRAM34] = {
+ .desc = {
+ .name = "db8500-esram34",
+ .id = DB8500_REGULATOR_SWITCH_ESRAM34,
+ .ops = &db8500_regulator_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .epod_id = EPOD_ID_ESRAM34,
+ .is_enabled = true,
+ },
+ [DB8500_REGULATOR_SWITCH_ESRAM34RET] = {
+ .desc = {
+ .name = "db8500-esram34-ret",
+ .id = DB8500_REGULATOR_SWITCH_ESRAM34RET,
+ .ops = &db8500_regulator_switch_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ .epod_id = EPOD_ID_ESRAM34,
+ .is_ramret = true,
+ },
+};
+
+static int __devinit db8500_regulator_probe(struct platform_device *pdev)
+{
+ struct regulator_init_data *db8500_init_data =
+ dev_get_platdata(&pdev->dev);
+ int i, err;
+
+ /* register all regulators */
+ for (i = 0; i < ARRAY_SIZE(db8500_regulator_info); i++) {
+ struct db8500_regulator_info *info;
+ struct regulator_init_data *init_data = &db8500_init_data[i];
+
+ /* assign per-regulator data */
+ info = &db8500_regulator_info[i];
+ info->dev = &pdev->dev;
+
+ /* register with the regulator framework */
+ info->rdev = regulator_register(&info->desc, &pdev->dev,
+ init_data, info);
+ if (IS_ERR(info->rdev)) {
+ err = PTR_ERR(info->rdev);
+ dev_err(&pdev->dev, "failed to register %s: err %i\n",
+ info->desc.name, err);
+
+ /* if failing, unregister all earlier regulators */
+ i--;
+ while (i >= 0) {
+ info = &db8500_regulator_info[i];
+ regulator_unregister(info->rdev);
+ i--;
+ }
+ return err;
+ }
+
+ dev_dbg(rdev_get_dev(info->rdev),
+ "regulator-%s-probed\n", info->desc.name);
+ }
+
+ return 0;
+}
+
+static int __exit db8500_regulator_remove(struct platform_device *pdev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(db8500_regulator_info); i++) {
+ struct db8500_regulator_info *info;
+ info = &db8500_regulator_info[i];
+
+ dev_vdbg(rdev_get_dev(info->rdev),
+ "regulator-%s-remove\n", info->desc.name);
+
+ regulator_unregister(info->rdev);
+ }
+
+ return 0;
+}
+
+static struct platform_driver db8500_regulator_driver = {
+ .driver = {
+ .name = "db8500-prcmu-regulators",
+ .owner = THIS_MODULE,
+ },
+ .probe = db8500_regulator_probe,
+ .remove = __exit_p(db8500_regulator_remove),
+};
+
+static int __init db8500_regulator_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&db8500_regulator_driver);
+ if (ret < 0)
+ return -ENODEV;
+
+ return 0;
+}
+
+static void __exit db8500_regulator_exit(void)
+{
+ platform_driver_unregister(&db8500_regulator_driver);
+}
+
+arch_initcall(db8500_regulator_init);
+module_exit(db8500_regulator_exit);
+
+MODULE_AUTHOR("STMicroelectronics/ST-Ericsson");
+MODULE_DESCRIPTION("DB8500 regulator driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c
index 8ae147549c6a..e4dbd667c043 100644
--- a/drivers/regulator/max8925-regulator.c
+++ b/drivers/regulator/max8925-regulator.c
@@ -23,6 +23,10 @@
#define SD1_DVM_SHIFT 5 /* SDCTL1 bit5 */
#define SD1_DVM_EN 6 /* SDV1 bit 6 */
+/* bit definitions in SD & LDO control registers */
+#define OUT_ENABLE 0x1f /* Power U/D sequence as I2C */
+#define OUT_DISABLE 0x1e /* Power U/D sequence as I2C */
+
struct max8925_regulator_info {
struct regulator_desc desc;
struct regulator_dev *regulator;
@@ -93,8 +97,8 @@ static int max8925_enable(struct regulator_dev *rdev)
struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
return max8925_set_bits(info->i2c, info->enable_reg,
- 1 << info->enable_bit,
- 1 << info->enable_bit);
+ OUT_ENABLE << info->enable_bit,
+ OUT_ENABLE << info->enable_bit);
}
static int max8925_disable(struct regulator_dev *rdev)
@@ -102,7 +106,8 @@ static int max8925_disable(struct regulator_dev *rdev)
struct max8925_regulator_info *info = rdev_get_drvdata(rdev);
return max8925_set_bits(info->i2c, info->enable_reg,
- 1 << info->enable_bit, 0);
+ OUT_ENABLE << info->enable_bit,
+ OUT_DISABLE << info->enable_bit);
}
static int max8925_is_enabled(struct regulator_dev *rdev)
diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c
index 77e0cfb30b23..10d5a1d9768e 100644
--- a/drivers/regulator/max8997.c
+++ b/drivers/regulator/max8997.c
@@ -267,7 +267,6 @@ static int max8997_get_enable_register(struct regulator_dev *rdev,
default:
/* Not controllable or not exists */
return -EINVAL;
- break;
}
return 0;
@@ -1033,11 +1032,11 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
/* For the safety, set max voltage before setting up */
for (i = 0; i < 8; i++) {
- max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS(i + 1),
+ max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS1 + i,
max_buck1, 0x3f);
- max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS(i + 1),
+ max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS1 + i,
max_buck2, 0x3f);
- max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS(i + 1),
+ max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS1 + i,
max_buck5, 0x3f);
}
@@ -1114,13 +1113,13 @@ static __devinit int max8997_pmic_probe(struct platform_device *pdev)
/* Initialize all the DVS related BUCK registers */
for (i = 0; i < 8; i++) {
- max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS(i + 1),
+ max8997_update_reg(i2c, MAX8997_REG_BUCK1DVS1 + i,
max8997->buck1_vol[i],
0x3f);
- max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS(i + 1),
+ max8997_update_reg(i2c, MAX8997_REG_BUCK2DVS1 + i,
max8997->buck2_vol[i],
0x3f);
- max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS(i + 1),
+ max8997_update_reg(i2c, MAX8997_REG_BUCK5DVS1 + i,
max8997->buck5_vol[i],
0x3f);
}
diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c
index 43410266f993..41a1495eec2b 100644
--- a/drivers/regulator/max8998.c
+++ b/drivers/regulator/max8998.c
@@ -405,8 +405,8 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev,
switch (buck) {
case MAX8998_BUCK1:
dev_dbg(max8998->dev,
- "BUCK1, i:%d, buck1_vol1:%d, buck1_vol2:%d\n\
- buck1_vol3:%d, buck1_vol4:%d\n",
+ "BUCK1, i:%d, buck1_vol1:%d, buck1_vol2:%d\n"
+ "buck1_vol3:%d, buck1_vol4:%d\n",
i, max8998->buck1_vol[0], max8998->buck1_vol[1],
max8998->buck1_vol[2], max8998->buck1_vol[3]);
@@ -732,13 +732,15 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
if (!pdata->buck1_set1) {
printk(KERN_ERR "MAX8998 SET1 GPIO defined as 0 !\n");
WARN_ON(!pdata->buck1_set1);
- return -EIO;
+ ret = -EIO;
+ goto err_free_mem;
}
/* Check if SET2 is not equal to 0 */
if (!pdata->buck1_set2) {
printk(KERN_ERR "MAX8998 SET2 GPIO defined as 0 !\n");
WARN_ON(!pdata->buck1_set2);
- return -EIO;
+ ret = -EIO;
+ goto err_free_mem;
}
gpio_request(pdata->buck1_set1, "MAX8998 BUCK1_SET1");
@@ -758,7 +760,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
max8998->buck1_vol[0] = i;
ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE1, i);
if (ret)
- return ret;
+ goto err_free_mem;
/* Set predefined value for BUCK1 register 2 */
i = 0;
@@ -770,7 +772,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
max8998->buck1_vol[1] = i;
ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE2, i);
if (ret)
- return ret;
+ goto err_free_mem;
/* Set predefined value for BUCK1 register 3 */
i = 0;
@@ -782,7 +784,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
max8998->buck1_vol[2] = i;
ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE3, i);
if (ret)
- return ret;
+ goto err_free_mem;
/* Set predefined value for BUCK1 register 4 */
i = 0;
@@ -794,7 +796,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
max8998->buck1_vol[3] = i;
ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE4, i);
if (ret)
- return ret;
+ goto err_free_mem;
}
@@ -803,7 +805,8 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
if (!pdata->buck2_set3) {
printk(KERN_ERR "MAX8998 SET3 GPIO defined as 0 !\n");
WARN_ON(!pdata->buck2_set3);
- return -EIO;
+ ret = -EIO;
+ goto err_free_mem;
}
gpio_request(pdata->buck2_set3, "MAX8998 BUCK2_SET3");
gpio_direction_output(pdata->buck2_set3,
@@ -818,7 +821,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
max8998->buck2_vol[0] = i;
ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE1, i);
if (ret)
- return ret;
+ goto err_free_mem;
/* BUCK2 register 2 */
i = 0;
@@ -830,7 +833,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev)
max8998->buck2_vol[1] = i;
ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE2, i);
if (ret)
- return ret;
+ goto err_free_mem;
}
for (i = 0; i < pdata->num_regulators; i++) {
@@ -860,6 +863,7 @@ err:
if (rdev[i])
regulator_unregister(rdev[i]);
+err_free_mem:
kfree(max8998->rdev);
kfree(max8998);
diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c
index 23249cb0a8bd..730f43ad415b 100644
--- a/drivers/regulator/mc13783-regulator.c
+++ b/drivers/regulator/mc13783-regulator.c
@@ -15,7 +15,6 @@
#include <linux/regulator/driver.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
-#include <linux/mfd/core.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/err.h>
@@ -337,11 +336,12 @@ static int __devinit mc13783_regulator_probe(struct platform_device *pdev)
{
struct mc13xxx_regulator_priv *priv;
struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent);
- struct mc13783_regulator_platform_data *pdata = mfd_get_data(pdev);
+ struct mc13783_regulator_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
struct mc13783_regulator_init_data *init_data;
int i, ret;
- dev_dbg(&pdev->dev, "mc13783_regulator_probe id %d\n", pdev->id);
+ dev_dbg(&pdev->dev, "%s id %d\n", __func__, pdev->id);
priv = kzalloc(sizeof(*priv) +
pdata->num_regulators * sizeof(priv->regulators[0]),
@@ -381,7 +381,8 @@ err:
static int __devexit mc13783_regulator_remove(struct platform_device *pdev)
{
struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
- struct mc13783_regulator_platform_data *pdata = mfd_get_data(pdev);
+ struct mc13783_regulator_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
int i;
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c
index 6f15168e5ed4..3285d41842f2 100644
--- a/drivers/regulator/mc13892-regulator.c
+++ b/drivers/regulator/mc13892-regulator.c
@@ -15,7 +15,6 @@
#include <linux/regulator/driver.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
-#include <linux/mfd/core.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/err.h>
@@ -432,7 +431,8 @@ static int mc13892_sw_regulator_set_voltage(struct regulator_dev *rdev,
int min_uV, int max_uV, unsigned *selector)
{
struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
- int hi, value, val, mask, id = rdev_get_id(rdev);
+ int hi, value, mask, id = rdev_get_id(rdev);
+ u32 valread;
int ret;
dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n",
@@ -448,15 +448,16 @@ static int mc13892_sw_regulator_set_voltage(struct regulator_dev *rdev,
mc13xxx_lock(priv->mc13xxx);
ret = mc13xxx_reg_read(priv->mc13xxx,
- mc13892_regulators[id].vsel_reg, &val);
+ mc13892_regulators[id].vsel_reg, &valread);
if (ret)
goto err;
- hi = val & MC13892_SWITCHERS0_SWxHI;
- if (value > 1375)
+ if (value > 1375000)
hi = 1;
- if (value < 1100)
+ else if (value < 1100000)
hi = 0;
+ else
+ hi = valread & MC13892_SWITCHERS0_SWxHI;
if (hi) {
value = (value - 1100000) / 25000;
@@ -465,8 +466,10 @@ static int mc13892_sw_regulator_set_voltage(struct regulator_dev *rdev,
value = (value - 600000) / 25000;
mask = mc13892_regulators[id].vsel_mask | MC13892_SWITCHERS0_SWxHI;
- ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].vsel_reg,
- mask, value << mc13892_regulators[id].vsel_shift);
+ valread = (valread & ~mask) |
+ (value << mc13892_regulators[id].vsel_shift);
+ ret = mc13xxx_reg_write(priv->mc13xxx, mc13892_regulators[id].vsel_reg,
+ valread);
err:
mc13xxx_unlock(priv->mc13xxx);
@@ -521,7 +524,8 @@ static int __devinit mc13892_regulator_probe(struct platform_device *pdev)
{
struct mc13xxx_regulator_priv *priv;
struct mc13xxx *mc13892 = dev_get_drvdata(pdev->dev.parent);
- struct mc13xxx_regulator_platform_data *pdata = mfd_get_data(pdev);
+ struct mc13xxx_regulator_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
struct mc13xxx_regulator_init_data *init_data;
int i, ret;
u32 val;
@@ -595,7 +599,8 @@ err_free:
static int __devexit mc13892_regulator_remove(struct platform_device *pdev)
{
struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev);
- struct mc13xxx_regulator_platform_data *pdata = mfd_get_data(pdev);
+ struct mc13xxx_regulator_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
int i;
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c
index 2bb5de1f2421..bc27ab136378 100644
--- a/drivers/regulator/mc13xxx-regulator-core.c
+++ b/drivers/regulator/mc13xxx-regulator-core.c
@@ -174,7 +174,7 @@ static int mc13xxx_regulator_get_voltage(struct regulator_dev *rdev)
dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val);
- BUG_ON(val > mc13xxx_regulators[id].desc.n_voltages);
+ BUG_ON(val >= mc13xxx_regulators[id].desc.n_voltages);
return mc13xxx_regulators[id].voltages[val];
}
diff --git a/drivers/regulator/tps6105x-regulator.c b/drivers/regulator/tps6105x-regulator.c
index 1661499feda4..1011873896dc 100644
--- a/drivers/regulator/tps6105x-regulator.c
+++ b/drivers/regulator/tps6105x-regulator.c
@@ -137,7 +137,7 @@ static struct regulator_desc tps6105x_regulator_desc = {
*/
static int __devinit tps6105x_regulator_probe(struct platform_device *pdev)
{
- struct tps6105x *tps6105x = mfd_get_data(pdev);
+ struct tps6105x *tps6105x = dev_get_platdata(&pdev->dev);
struct tps6105x_platform_data *pdata = tps6105x->pdata;
int ret;
@@ -158,13 +158,14 @@ static int __devinit tps6105x_regulator_probe(struct platform_device *pdev)
"failed to register regulator\n");
return ret;
}
+ platform_set_drvdata(pdev, tps6105x);
return 0;
}
static int __devexit tps6105x_regulator_remove(struct platform_device *pdev)
{
- struct tps6105x *tps6105x = platform_get_drvdata(pdev);
+ struct tps6105x *tps6105x = dev_get_platdata(&pdev->dev);
regulator_unregister(tps6105x->regulator);
return 0;
}
diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c
index 60a7ca5409e9..fbddc15e1811 100644
--- a/drivers/regulator/tps65023-regulator.c
+++ b/drivers/regulator/tps65023-regulator.c
@@ -466,7 +466,6 @@ static struct regulator_ops tps65023_ldo_ops = {
static int __devinit tps_65023_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- static int desc_id;
const struct tps_info *info = (void *)id->driver_data;
struct regulator_init_data *init_data;
struct regulator_dev *rdev;
@@ -499,7 +498,7 @@ static int __devinit tps_65023_probe(struct i2c_client *client,
tps->info[i] = info;
tps->desc[i].name = info->name;
- tps->desc[i].id = desc_id++;
+ tps->desc[i].id = i;
tps->desc[i].n_voltages = num_voltages[i];
tps->desc[i].ops = (i > TPS65023_DCDC_3 ?
&tps65023_ldo_ops : &tps65023_dcdc_ops);
diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c
index 064755290599..bfffabc21eda 100644
--- a/drivers/regulator/tps6507x-regulator.c
+++ b/drivers/regulator/tps6507x-regulator.c
@@ -553,7 +553,6 @@ static __devinit
int tps6507x_pmic_probe(struct platform_device *pdev)
{
struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
- static int desc_id;
struct tps_info *info = &tps6507x_pmic_regs[0];
struct regulator_init_data *init_data;
struct regulator_dev *rdev;
@@ -598,7 +597,7 @@ int tps6507x_pmic_probe(struct platform_device *pdev)
}
tps->desc[i].name = info->name;
- tps->desc[i].id = desc_id++;
+ tps->desc[i].id = i;
tps->desc[i].n_voltages = num_voltages[i];
tps->desc[i].ops = (i > TPS6507X_DCDC_3 ?
&tps6507x_pmic_ldo_ops : &tps6507x_pmic_dcdc_ops);
diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c
new file mode 100644
index 000000000000..55dd4e6650db
--- /dev/null
+++ b/drivers/regulator/tps65910-regulator.c
@@ -0,0 +1,993 @@
+/*
+ * tps65910.c -- TI tps65910
+ *
+ * Copyright 2010 Texas Instruments Inc.
+ *
+ * Author: Graeme Gregory <gg@slimlogic.co.uk>
+ * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/mfd/tps65910.h>
+
+#define TPS65910_REG_VRTC 0
+#define TPS65910_REG_VIO 1
+#define TPS65910_REG_VDD1 2
+#define TPS65910_REG_VDD2 3
+#define TPS65910_REG_VDD3 4
+#define TPS65910_REG_VDIG1 5
+#define TPS65910_REG_VDIG2 6
+#define TPS65910_REG_VPLL 7
+#define TPS65910_REG_VDAC 8
+#define TPS65910_REG_VAUX1 9
+#define TPS65910_REG_VAUX2 10
+#define TPS65910_REG_VAUX33 11
+#define TPS65910_REG_VMMC 12
+
+#define TPS65911_REG_VDDCTRL 4
+#define TPS65911_REG_LDO1 5
+#define TPS65911_REG_LDO2 6
+#define TPS65911_REG_LDO3 7
+#define TPS65911_REG_LDO4 8
+#define TPS65911_REG_LDO5 9
+#define TPS65911_REG_LDO6 10
+#define TPS65911_REG_LDO7 11
+#define TPS65911_REG_LDO8 12
+
+#define TPS65910_NUM_REGULATOR 13
+#define TPS65910_SUPPLY_STATE_ENABLED 0x1
+
+/* supported VIO voltages in milivolts */
+static const u16 VIO_VSEL_table[] = {
+ 1500, 1800, 2500, 3300,
+};
+
+/* VSEL tables for TPS65910 specific LDOs and dcdc's */
+
+/* supported VDD3 voltages in milivolts */
+static const u16 VDD3_VSEL_table[] = {
+ 5000,
+};
+
+/* supported VDIG1 voltages in milivolts */
+static const u16 VDIG1_VSEL_table[] = {
+ 1200, 1500, 1800, 2700,
+};
+
+/* supported VDIG2 voltages in milivolts */
+static const u16 VDIG2_VSEL_table[] = {
+ 1000, 1100, 1200, 1800,
+};
+
+/* supported VPLL voltages in milivolts */
+static const u16 VPLL_VSEL_table[] = {
+ 1000, 1100, 1800, 2500,
+};
+
+/* supported VDAC voltages in milivolts */
+static const u16 VDAC_VSEL_table[] = {
+ 1800, 2600, 2800, 2850,
+};
+
+/* supported VAUX1 voltages in milivolts */
+static const u16 VAUX1_VSEL_table[] = {
+ 1800, 2500, 2800, 2850,
+};
+
+/* supported VAUX2 voltages in milivolts */
+static const u16 VAUX2_VSEL_table[] = {
+ 1800, 2800, 2900, 3300,
+};
+
+/* supported VAUX33 voltages in milivolts */
+static const u16 VAUX33_VSEL_table[] = {
+ 1800, 2000, 2800, 3300,
+};
+
+/* supported VMMC voltages in milivolts */
+static const u16 VMMC_VSEL_table[] = {
+ 1800, 2800, 3000, 3300,
+};
+
+struct tps_info {
+ const char *name;
+ unsigned min_uV;
+ unsigned max_uV;
+ u8 table_len;
+ const u16 *table;
+};
+
+static struct tps_info tps65910_regs[] = {
+ {
+ .name = "VRTC",
+ },
+ {
+ .name = "VIO",
+ .min_uV = 1500000,
+ .max_uV = 3300000,
+ .table_len = ARRAY_SIZE(VIO_VSEL_table),
+ .table = VIO_VSEL_table,
+ },
+ {
+ .name = "VDD1",
+ .min_uV = 600000,
+ .max_uV = 4500000,
+ },
+ {
+ .name = "VDD2",
+ .min_uV = 600000,
+ .max_uV = 4500000,
+ },
+ {
+ .name = "VDD3",
+ .min_uV = 5000000,
+ .max_uV = 5000000,
+ .table_len = ARRAY_SIZE(VDD3_VSEL_table),
+ .table = VDD3_VSEL_table,
+ },
+ {
+ .name = "VDIG1",
+ .min_uV = 1200000,
+ .max_uV = 2700000,
+ .table_len = ARRAY_SIZE(VDIG1_VSEL_table),
+ .table = VDIG1_VSEL_table,
+ },
+ {
+ .name = "VDIG2",
+ .min_uV = 1000000,
+ .max_uV = 1800000,
+ .table_len = ARRAY_SIZE(VDIG2_VSEL_table),
+ .table = VDIG2_VSEL_table,
+ },
+ {
+ .name = "VPLL",
+ .min_uV = 1000000,
+ .max_uV = 2500000,
+ .table_len = ARRAY_SIZE(VPLL_VSEL_table),
+ .table = VPLL_VSEL_table,
+ },
+ {
+ .name = "VDAC",
+ .min_uV = 1800000,
+ .max_uV = 2850000,
+ .table_len = ARRAY_SIZE(VDAC_VSEL_table),
+ .table = VDAC_VSEL_table,
+ },
+ {
+ .name = "VAUX1",
+ .min_uV = 1800000,
+ .max_uV = 2850000,
+ .table_len = ARRAY_SIZE(VAUX1_VSEL_table),
+ .table = VAUX1_VSEL_table,
+ },
+ {
+ .name = "VAUX2",
+ .min_uV = 1800000,
+ .max_uV = 3300000,
+ .table_len = ARRAY_SIZE(VAUX2_VSEL_table),
+ .table = VAUX2_VSEL_table,
+ },
+ {
+ .name = "VAUX33",
+ .min_uV = 1800000,
+ .max_uV = 3300000,
+ .table_len = ARRAY_SIZE(VAUX33_VSEL_table),
+ .table = VAUX33_VSEL_table,
+ },
+ {
+ .name = "VMMC",
+ .min_uV = 1800000,
+ .max_uV = 3300000,
+ .table_len = ARRAY_SIZE(VMMC_VSEL_table),
+ .table = VMMC_VSEL_table,
+ },
+};
+
+static struct tps_info tps65911_regs[] = {
+ {
+ .name = "VIO",
+ .min_uV = 1500000,
+ .max_uV = 3300000,
+ .table_len = ARRAY_SIZE(VIO_VSEL_table),
+ .table = VIO_VSEL_table,
+ },
+ {
+ .name = "VDD1",
+ .min_uV = 600000,
+ .max_uV = 4500000,
+ },
+ {
+ .name = "VDD2",
+ .min_uV = 600000,
+ .max_uV = 4500000,
+ },
+ {
+ .name = "VDDCTRL",
+ .min_uV = 600000,
+ .max_uV = 1400000,
+ },
+ {
+ .name = "LDO1",
+ .min_uV = 1000000,
+ .max_uV = 3300000,
+ },
+ {
+ .name = "LDO2",
+ .min_uV = 1000000,
+ .max_uV = 3300000,
+ },
+ {
+ .name = "LDO3",
+ .min_uV = 1000000,
+ .max_uV = 3300000,
+ },
+ {
+ .name = "LDO4",
+ .min_uV = 1000000,
+ .max_uV = 3300000,
+ },
+ {
+ .name = "LDO5",
+ .min_uV = 1000000,
+ .max_uV = 3300000,
+ },
+ {
+ .name = "LDO6",
+ .min_uV = 1000000,
+ .max_uV = 3300000,
+ },
+ {
+ .name = "LDO7",
+ .min_uV = 1000000,
+ .max_uV = 3300000,
+ },
+ {
+ .name = "LDO8",
+ .min_uV = 1000000,
+ .max_uV = 3300000,
+ },
+};
+
+struct tps65910_reg {
+ struct regulator_desc desc[TPS65910_NUM_REGULATOR];
+ struct tps65910 *mfd;
+ struct regulator_dev *rdev[TPS65910_NUM_REGULATOR];
+ struct tps_info *info[TPS65910_NUM_REGULATOR];
+ struct mutex mutex;
+ int mode;
+ int (*get_ctrl_reg)(int);
+};
+
+static inline int tps65910_read(struct tps65910_reg *pmic, u8 reg)
+{
+ u8 val;
+ int err;
+
+ err = pmic->mfd->read(pmic->mfd, reg, 1, &val);
+ if (err)
+ return err;
+
+ return val;
+}
+
+static inline int tps65910_write(struct tps65910_reg *pmic, u8 reg, u8 val)
+{
+ return pmic->mfd->write(pmic->mfd, reg, 1, &val);
+}
+
+static int tps65910_modify_bits(struct tps65910_reg *pmic, u8 reg,
+ u8 set_mask, u8 clear_mask)
+{
+ int err, data;
+
+ mutex_lock(&pmic->mutex);
+
+ data = tps65910_read(pmic, reg);
+ if (data < 0) {
+ dev_err(pmic->mfd->dev, "Read from reg 0x%x failed\n", reg);
+ err = data;
+ goto out;
+ }
+
+ data &= ~clear_mask;
+ data |= set_mask;
+ err = tps65910_write(pmic, reg, data);
+ if (err)
+ dev_err(pmic->mfd->dev, "Write for reg 0x%x failed\n", reg);
+
+out:
+ mutex_unlock(&pmic->mutex);
+ return err;
+}
+
+static int tps65910_reg_read(struct tps65910_reg *pmic, u8 reg)
+{
+ int data;
+
+ mutex_lock(&pmic->mutex);
+
+ data = tps65910_read(pmic, reg);
+ if (data < 0)
+ dev_err(pmic->mfd->dev, "Read from reg 0x%x failed\n", reg);
+
+ mutex_unlock(&pmic->mutex);
+ return data;
+}
+
+static int tps65910_reg_write(struct tps65910_reg *pmic, u8 reg, u8 val)
+{
+ int err;
+
+ mutex_lock(&pmic->mutex);
+
+ err = tps65910_write(pmic, reg, val);
+ if (err < 0)
+ dev_err(pmic->mfd->dev, "Write for reg 0x%x failed\n", reg);
+
+ mutex_unlock(&pmic->mutex);
+ return err;
+}
+
+static int tps65910_get_ctrl_register(int id)
+{
+ switch (id) {
+ case TPS65910_REG_VRTC:
+ return TPS65910_VRTC;
+ case TPS65910_REG_VIO:
+ return TPS65910_VIO;
+ case TPS65910_REG_VDD1:
+ return TPS65910_VDD1;
+ case TPS65910_REG_VDD2:
+ return TPS65910_VDD2;
+ case TPS65910_REG_VDD3:
+ return TPS65910_VDD3;
+ case TPS65910_REG_VDIG1:
+ return TPS65910_VDIG1;
+ case TPS65910_REG_VDIG2:
+ return TPS65910_VDIG2;
+ case TPS65910_REG_VPLL:
+ return TPS65910_VPLL;
+ case TPS65910_REG_VDAC:
+ return TPS65910_VDAC;
+ case TPS65910_REG_VAUX1:
+ return TPS65910_VAUX1;
+ case TPS65910_REG_VAUX2:
+ return TPS65910_VAUX2;
+ case TPS65910_REG_VAUX33:
+ return TPS65910_VAUX33;
+ case TPS65910_REG_VMMC:
+ return TPS65910_VMMC;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tps65911_get_ctrl_register(int id)
+{
+ switch (id) {
+ case TPS65910_REG_VRTC:
+ return TPS65910_VRTC;
+ case TPS65910_REG_VIO:
+ return TPS65910_VIO;
+ case TPS65910_REG_VDD1:
+ return TPS65910_VDD1;
+ case TPS65910_REG_VDD2:
+ return TPS65910_VDD2;
+ case TPS65911_REG_VDDCTRL:
+ return TPS65911_VDDCTRL;
+ case TPS65911_REG_LDO1:
+ return TPS65911_LDO1;
+ case TPS65911_REG_LDO2:
+ return TPS65911_LDO2;
+ case TPS65911_REG_LDO3:
+ return TPS65911_LDO3;
+ case TPS65911_REG_LDO4:
+ return TPS65911_LDO4;
+ case TPS65911_REG_LDO5:
+ return TPS65911_LDO5;
+ case TPS65911_REG_LDO6:
+ return TPS65911_LDO6;
+ case TPS65911_REG_LDO7:
+ return TPS65911_LDO7;
+ case TPS65911_REG_LDO8:
+ return TPS65911_LDO8;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tps65910_is_enabled(struct regulator_dev *dev)
+{
+ struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+ int reg, value, id = rdev_get_id(dev);
+
+ reg = pmic->get_ctrl_reg(id);
+ if (reg < 0)
+ return reg;
+
+ value = tps65910_reg_read(pmic, reg);
+ if (value < 0)
+ return value;
+
+ return value & TPS65910_SUPPLY_STATE_ENABLED;
+}
+
+static int tps65910_enable(struct regulator_dev *dev)
+{
+ struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+ struct tps65910 *mfd = pmic->mfd;
+ int reg, id = rdev_get_id(dev);
+
+ reg = pmic->get_ctrl_reg(id);
+ if (reg < 0)
+ return reg;
+
+ return tps65910_set_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED);
+}
+
+static int tps65910_disable(struct regulator_dev *dev)
+{
+ struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+ struct tps65910 *mfd = pmic->mfd;
+ int reg, id = rdev_get_id(dev);
+
+ reg = pmic->get_ctrl_reg(id);
+ if (reg < 0)
+ return reg;
+
+ return tps65910_clear_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED);
+}
+
+
+static int tps65910_set_mode(struct regulator_dev *dev, unsigned int mode)
+{
+ struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+ struct tps65910 *mfd = pmic->mfd;
+ int reg, value, id = rdev_get_id(dev);
+
+ reg = pmic->get_ctrl_reg(id);
+ if (reg < 0)
+ return reg;
+
+ switch (mode) {
+ case REGULATOR_MODE_NORMAL:
+ return tps65910_modify_bits(pmic, reg, LDO_ST_ON_BIT,
+ LDO_ST_MODE_BIT);
+ case REGULATOR_MODE_IDLE:
+ value = LDO_ST_ON_BIT | LDO_ST_MODE_BIT;
+ return tps65910_set_bits(mfd, reg, value);
+ case REGULATOR_MODE_STANDBY:
+ return tps65910_clear_bits(mfd, reg, LDO_ST_ON_BIT);
+ }
+
+ return -EINVAL;
+}
+
+static unsigned int tps65910_get_mode(struct regulator_dev *dev)
+{
+ struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+ int reg, value, id = rdev_get_id(dev);
+
+ reg = pmic->get_ctrl_reg(id);
+ if (reg < 0)
+ return reg;
+
+ value = tps65910_reg_read(pmic, reg);
+ if (value < 0)
+ return value;
+
+ if (value & LDO_ST_ON_BIT)
+ return REGULATOR_MODE_STANDBY;
+ else if (value & LDO_ST_MODE_BIT)
+ return REGULATOR_MODE_IDLE;
+ else
+ return REGULATOR_MODE_NORMAL;
+}
+
+static int tps65910_get_voltage_dcdc(struct regulator_dev *dev)
+{
+ struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+ int id = rdev_get_id(dev), voltage = 0;
+ int opvsel = 0, srvsel = 0, vselmax = 0, mult = 0, sr = 0;
+
+ switch (id) {
+ case TPS65910_REG_VDD1:
+ opvsel = tps65910_reg_read(pmic, TPS65910_VDD1_OP);
+ mult = tps65910_reg_read(pmic, TPS65910_VDD1);
+ mult = (mult & VDD1_VGAIN_SEL_MASK) >> VDD1_VGAIN_SEL_SHIFT;
+ srvsel = tps65910_reg_read(pmic, TPS65910_VDD1_SR);
+ sr = opvsel & VDD1_OP_CMD_MASK;
+ opvsel &= VDD1_OP_SEL_MASK;
+ srvsel &= VDD1_SR_SEL_MASK;
+ vselmax = 75;
+ break;
+ case TPS65910_REG_VDD2:
+ opvsel = tps65910_reg_read(pmic, TPS65910_VDD2_OP);
+ mult = tps65910_reg_read(pmic, TPS65910_VDD2);
+ mult = (mult & VDD2_VGAIN_SEL_MASK) >> VDD2_VGAIN_SEL_SHIFT;
+ srvsel = tps65910_reg_read(pmic, TPS65910_VDD2_SR);
+ sr = opvsel & VDD2_OP_CMD_MASK;
+ opvsel &= VDD2_OP_SEL_MASK;
+ srvsel &= VDD2_SR_SEL_MASK;
+ vselmax = 75;
+ break;
+ case TPS65911_REG_VDDCTRL:
+ opvsel = tps65910_reg_read(pmic, TPS65911_VDDCTRL_OP);
+ srvsel = tps65910_reg_read(pmic, TPS65911_VDDCTRL_SR);
+ sr = opvsel & VDDCTRL_OP_CMD_MASK;
+ opvsel &= VDDCTRL_OP_SEL_MASK;
+ srvsel &= VDDCTRL_SR_SEL_MASK;
+ vselmax = 64;
+ break;
+ }
+
+ /* multiplier 0 == 1 but 2,3 normal */
+ if (!mult)
+ mult=1;
+
+ if (sr) {
+ /* normalise to valid range */
+ if (srvsel < 3)
+ srvsel = 3;
+ if (srvsel > vselmax)
+ srvsel = vselmax;
+ srvsel -= 3;
+
+ voltage = (srvsel * VDD1_2_OFFSET + VDD1_2_MIN_VOLT) * 100;
+ } else {
+
+ /* normalise to valid range*/
+ if (opvsel < 3)
+ opvsel = 3;
+ if (opvsel > vselmax)
+ opvsel = vselmax;
+ opvsel -= 3;
+
+ voltage = (opvsel * VDD1_2_OFFSET + VDD1_2_MIN_VOLT) * 100;
+ }
+
+ voltage *= mult;
+
+ return voltage;
+}
+
+static int tps65910_get_voltage(struct regulator_dev *dev)
+{
+ struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+ int reg, value, id = rdev_get_id(dev), voltage = 0;
+
+ reg = pmic->get_ctrl_reg(id);
+ if (reg < 0)
+ return reg;
+
+ value = tps65910_reg_read(pmic, reg);
+ if (value < 0)
+ return value;
+
+ switch (id) {
+ case TPS65910_REG_VIO:
+ case TPS65910_REG_VDIG1:
+ case TPS65910_REG_VDIG2:
+ case TPS65910_REG_VPLL:
+ case TPS65910_REG_VDAC:
+ case TPS65910_REG_VAUX1:
+ case TPS65910_REG_VAUX2:
+ case TPS65910_REG_VAUX33:
+ case TPS65910_REG_VMMC:
+ value &= LDO_SEL_MASK;
+ value >>= LDO_SEL_SHIFT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ voltage = pmic->info[id]->table[value] * 1000;
+
+ return voltage;
+}
+
+static int tps65910_get_voltage_vdd3(struct regulator_dev *dev)
+{
+ return 5 * 1000 * 1000;
+}
+
+static int tps65911_get_voltage(struct regulator_dev *dev)
+{
+ struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+ int step_mv, id = rdev_get_id(dev);
+ u8 value, reg;
+
+ reg = pmic->get_ctrl_reg(id);
+
+ value = tps65910_reg_read(pmic, reg);
+
+ switch (id) {
+ case TPS65911_REG_LDO1:
+ case TPS65911_REG_LDO2:
+ case TPS65911_REG_LDO4:
+ value &= LDO1_SEL_MASK;
+ value >>= LDO_SEL_SHIFT;
+ /* The first 5 values of the selector correspond to 1V */
+ if (value < 5)
+ value = 0;
+ else
+ value -= 4;
+
+ step_mv = 50;
+ break;
+ case TPS65911_REG_LDO3:
+ case TPS65911_REG_LDO5:
+ case TPS65911_REG_LDO6:
+ case TPS65911_REG_LDO7:
+ case TPS65911_REG_LDO8:
+ value &= LDO3_SEL_MASK;
+ value >>= LDO_SEL_SHIFT;
+ /* The first 3 values of the selector correspond to 1V */
+ if (value < 3)
+ value = 0;
+ else
+ value -= 2;
+
+ step_mv = 100;
+ break;
+ case TPS65910_REG_VIO:
+ return pmic->info[id]->table[value] * 1000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return (LDO_MIN_VOLT + value * step_mv) * 1000;
+}
+
+static int tps65910_set_voltage_dcdc(struct regulator_dev *dev,
+ unsigned selector)
+{
+ struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+ int id = rdev_get_id(dev), vsel;
+ int dcdc_mult = 0;
+
+ switch (id) {
+ case TPS65910_REG_VDD1:
+ dcdc_mult = (selector / VDD1_2_NUM_VOLTS) + 1;
+ if (dcdc_mult == 1)
+ dcdc_mult--;
+ vsel = (selector % VDD1_2_NUM_VOLTS) + 3;
+
+ tps65910_modify_bits(pmic, TPS65910_VDD1,
+ (dcdc_mult << VDD1_VGAIN_SEL_SHIFT),
+ VDD1_VGAIN_SEL_MASK);
+ tps65910_reg_write(pmic, TPS65910_VDD1_OP, vsel);
+ break;
+ case TPS65910_REG_VDD2:
+ dcdc_mult = (selector / VDD1_2_NUM_VOLTS) + 1;
+ if (dcdc_mult == 1)
+ dcdc_mult--;
+ vsel = (selector % VDD1_2_NUM_VOLTS) + 3;
+
+ tps65910_modify_bits(pmic, TPS65910_VDD2,
+ (dcdc_mult << VDD2_VGAIN_SEL_SHIFT),
+ VDD1_VGAIN_SEL_MASK);
+ tps65910_reg_write(pmic, TPS65910_VDD2_OP, vsel);
+ break;
+ case TPS65911_REG_VDDCTRL:
+ vsel = selector;
+ tps65910_reg_write(pmic, TPS65911_VDDCTRL_OP, vsel);
+ }
+
+ return 0;
+}
+
+static int tps65910_set_voltage(struct regulator_dev *dev, unsigned selector)
+{
+ struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+ int reg, id = rdev_get_id(dev);
+
+ reg = pmic->get_ctrl_reg(id);
+ if (reg < 0)
+ return reg;
+
+ switch (id) {
+ case TPS65910_REG_VIO:
+ case TPS65910_REG_VDIG1:
+ case TPS65910_REG_VDIG2:
+ case TPS65910_REG_VPLL:
+ case TPS65910_REG_VDAC:
+ case TPS65910_REG_VAUX1:
+ case TPS65910_REG_VAUX2:
+ case TPS65910_REG_VAUX33:
+ case TPS65910_REG_VMMC:
+ return tps65910_modify_bits(pmic, reg,
+ (selector << LDO_SEL_SHIFT), LDO_SEL_MASK);
+ }
+
+ return -EINVAL;
+}
+
+static int tps65911_set_voltage(struct regulator_dev *dev, unsigned selector)
+{
+ struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+ int reg, id = rdev_get_id(dev);
+
+ reg = pmic->get_ctrl_reg(id);
+ if (reg < 0)
+ return reg;
+
+ switch (id) {
+ case TPS65911_REG_LDO1:
+ case TPS65911_REG_LDO2:
+ case TPS65911_REG_LDO4:
+ return tps65910_modify_bits(pmic, reg,
+ (selector << LDO_SEL_SHIFT), LDO1_SEL_MASK);
+ case TPS65911_REG_LDO3:
+ case TPS65911_REG_LDO5:
+ case TPS65911_REG_LDO6:
+ case TPS65911_REG_LDO7:
+ case TPS65911_REG_LDO8:
+ case TPS65910_REG_VIO:
+ return tps65910_modify_bits(pmic, reg,
+ (selector << LDO_SEL_SHIFT), LDO3_SEL_MASK);
+ }
+
+ return -EINVAL;
+}
+
+
+static int tps65910_list_voltage_dcdc(struct regulator_dev *dev,
+ unsigned selector)
+{
+ int volt, mult = 1, id = rdev_get_id(dev);
+
+ switch (id) {
+ case TPS65910_REG_VDD1:
+ case TPS65910_REG_VDD2:
+ mult = (selector / VDD1_2_NUM_VOLTS) + 1;
+ volt = VDD1_2_MIN_VOLT +
+ (selector % VDD1_2_NUM_VOLTS) * VDD1_2_OFFSET;
+ case TPS65911_REG_VDDCTRL:
+ volt = VDDCTRL_MIN_VOLT + (selector * VDDCTRL_OFFSET);
+ }
+
+ return volt * 100 * mult;
+}
+
+static int tps65910_list_voltage(struct regulator_dev *dev,
+ unsigned selector)
+{
+ struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+ int id = rdev_get_id(dev), voltage;
+
+ if (id < TPS65910_REG_VIO || id > TPS65910_REG_VMMC)
+ return -EINVAL;
+
+ if (selector >= pmic->info[id]->table_len)
+ return -EINVAL;
+ else
+ voltage = pmic->info[id]->table[selector] * 1000;
+
+ return voltage;
+}
+
+static int tps65911_list_voltage(struct regulator_dev *dev, unsigned selector)
+{
+ struct tps65910_reg *pmic = rdev_get_drvdata(dev);
+ int step_mv = 0, id = rdev_get_id(dev);
+
+ switch(id) {
+ case TPS65911_REG_LDO1:
+ case TPS65911_REG_LDO2:
+ case TPS65911_REG_LDO4:
+ /* The first 5 values of the selector correspond to 1V */
+ if (selector < 5)
+ selector = 0;
+ else
+ selector -= 4;
+
+ step_mv = 50;
+ break;
+ case TPS65911_REG_LDO3:
+ case TPS65911_REG_LDO5:
+ case TPS65911_REG_LDO6:
+ case TPS65911_REG_LDO7:
+ case TPS65911_REG_LDO8:
+ /* The first 3 values of the selector correspond to 1V */
+ if (selector < 3)
+ selector = 0;
+ else
+ selector -= 2;
+
+ step_mv = 100;
+ break;
+ case TPS65910_REG_VIO:
+ return pmic->info[id]->table[selector] * 1000;
+ default:
+ return -EINVAL;
+ }
+
+ return (LDO_MIN_VOLT + selector * step_mv) * 1000;
+}
+
+/* Regulator ops (except VRTC) */
+static struct regulator_ops tps65910_ops_dcdc = {
+ .is_enabled = tps65910_is_enabled,
+ .enable = tps65910_enable,
+ .disable = tps65910_disable,
+ .set_mode = tps65910_set_mode,
+ .get_mode = tps65910_get_mode,
+ .get_voltage = tps65910_get_voltage_dcdc,
+ .set_voltage_sel = tps65910_set_voltage_dcdc,
+ .list_voltage = tps65910_list_voltage_dcdc,
+};
+
+static struct regulator_ops tps65910_ops_vdd3 = {
+ .is_enabled = tps65910_is_enabled,
+ .enable = tps65910_enable,
+ .disable = tps65910_disable,
+ .set_mode = tps65910_set_mode,
+ .get_mode = tps65910_get_mode,
+ .get_voltage = tps65910_get_voltage_vdd3,
+ .list_voltage = tps65910_list_voltage,
+};
+
+static struct regulator_ops tps65910_ops = {
+ .is_enabled = tps65910_is_enabled,
+ .enable = tps65910_enable,
+ .disable = tps65910_disable,
+ .set_mode = tps65910_set_mode,
+ .get_mode = tps65910_get_mode,
+ .get_voltage = tps65910_get_voltage,
+ .set_voltage_sel = tps65910_set_voltage,
+ .list_voltage = tps65910_list_voltage,
+};
+
+static struct regulator_ops tps65911_ops = {
+ .is_enabled = tps65910_is_enabled,
+ .enable = tps65910_enable,
+ .disable = tps65910_disable,
+ .set_mode = tps65910_set_mode,
+ .get_mode = tps65910_get_mode,
+ .get_voltage = tps65911_get_voltage,
+ .set_voltage_sel = tps65911_set_voltage,
+ .list_voltage = tps65911_list_voltage,
+};
+
+static __devinit int tps65910_probe(struct platform_device *pdev)
+{
+ struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent);
+ struct tps_info *info;
+ struct regulator_init_data *reg_data;
+ struct regulator_dev *rdev;
+ struct tps65910_reg *pmic;
+ struct tps65910_board *pmic_plat_data;
+ int i, err;
+
+ pmic_plat_data = dev_get_platdata(tps65910->dev);
+ if (!pmic_plat_data)
+ return -EINVAL;
+
+ reg_data = pmic_plat_data->tps65910_pmic_init_data;
+
+ pmic = kzalloc(sizeof(*pmic), GFP_KERNEL);
+ if (!pmic)
+ return -ENOMEM;
+
+ mutex_init(&pmic->mutex);
+ pmic->mfd = tps65910;
+ platform_set_drvdata(pdev, pmic);
+
+ /* Give control of all register to control port */
+ tps65910_set_bits(pmic->mfd, TPS65910_DEVCTRL,
+ DEVCTRL_SR_CTL_I2C_SEL_MASK);
+
+ switch(tps65910_chip_id(tps65910)) {
+ case TPS65910:
+ pmic->get_ctrl_reg = &tps65910_get_ctrl_register;
+ info = tps65910_regs;
+ case TPS65911:
+ pmic->get_ctrl_reg = &tps65911_get_ctrl_register;
+ info = tps65911_regs;
+ default:
+ pr_err("Invalid tps chip version\n");
+ return -ENODEV;
+ }
+
+ for (i = 0; i < TPS65910_NUM_REGULATOR; i++, info++, reg_data++) {
+ /* Register the regulators */
+ pmic->info[i] = info;
+
+ pmic->desc[i].name = info->name;
+ pmic->desc[i].id = i;
+ pmic->desc[i].n_voltages = info->table_len;
+
+ if (i == TPS65910_REG_VDD1 || i == TPS65910_REG_VDD2) {
+ pmic->desc[i].ops = &tps65910_ops_dcdc;
+ } else if (i == TPS65910_REG_VDD3) {
+ if (tps65910_chip_id(tps65910) == TPS65910)
+ pmic->desc[i].ops = &tps65910_ops_vdd3;
+ else
+ pmic->desc[i].ops = &tps65910_ops_dcdc;
+ } else {
+ if (tps65910_chip_id(tps65910) == TPS65910)
+ pmic->desc[i].ops = &tps65910_ops;
+ else
+ pmic->desc[i].ops = &tps65911_ops;
+ }
+
+ pmic->desc[i].type = REGULATOR_VOLTAGE;
+ pmic->desc[i].owner = THIS_MODULE;
+
+ rdev = regulator_register(&pmic->desc[i],
+ tps65910->dev, reg_data, pmic);
+ if (IS_ERR(rdev)) {
+ dev_err(tps65910->dev,
+ "failed to register %s regulator\n",
+ pdev->name);
+ err = PTR_ERR(rdev);
+ goto err;
+ }
+
+ /* Save regulator for cleanup */
+ pmic->rdev[i] = rdev;
+ }
+ return 0;
+
+err:
+ while (--i >= 0)
+ regulator_unregister(pmic->rdev[i]);
+
+ kfree(pmic);
+ return err;
+}
+
+static int __devexit tps65910_remove(struct platform_device *pdev)
+{
+ struct tps65910_reg *tps65910_reg = platform_get_drvdata(pdev);
+ int i;
+
+ for (i = 0; i < TPS65910_NUM_REGULATOR; i++)
+ regulator_unregister(tps65910_reg->rdev[i]);
+
+ kfree(tps65910_reg);
+ return 0;
+}
+
+static struct platform_driver tps65910_driver = {
+ .driver = {
+ .name = "tps65910-pmic",
+ .owner = THIS_MODULE,
+ },
+ .probe = tps65910_probe,
+ .remove = __devexit_p(tps65910_remove),
+};
+
+static int __init tps65910_init(void)
+{
+ return platform_driver_register(&tps65910_driver);
+}
+subsys_initcall(tps65910_init);
+
+static void __exit tps65910_cleanup(void)
+{
+ platform_driver_unregister(&tps65910_driver);
+}
+module_exit(tps65910_cleanup);
+
+MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
+MODULE_DESCRIPTION("TPS6507x voltage regulator driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:tps65910-pmic");
diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c
index 6a292852a358..87fe0f75a56e 100644
--- a/drivers/regulator/twl-regulator.c
+++ b/drivers/regulator/twl-regulator.c
@@ -51,8 +51,13 @@ struct twlreg_info {
u16 min_mV;
u16 max_mV;
+ u8 flags;
+
/* used by regulator core */
struct regulator_desc desc;
+
+ /* chip specific features */
+ unsigned long features;
};
@@ -70,12 +75,35 @@ struct twlreg_info {
#define VREG_TRANS 1
#define VREG_STATE 2
#define VREG_VOLTAGE 3
+#define VREG_VOLTAGE_SMPS 4
/* TWL6030 Misc register offsets */
#define VREG_BC_ALL 1
#define VREG_BC_REF 2
#define VREG_BC_PROC 3
#define VREG_BC_CLK_RST 4
+/* TWL6030 LDO register values for CFG_STATE */
+#define TWL6030_CFG_STATE_OFF 0x00
+#define TWL6030_CFG_STATE_ON 0x01
+#define TWL6030_CFG_STATE_OFF2 0x02
+#define TWL6030_CFG_STATE_SLEEP 0x03
+#define TWL6030_CFG_STATE_GRP_SHIFT 5
+#define TWL6030_CFG_STATE_APP_SHIFT 2
+#define TWL6030_CFG_STATE_APP_MASK (0x03 << TWL6030_CFG_STATE_APP_SHIFT)
+#define TWL6030_CFG_STATE_APP(v) (((v) & TWL6030_CFG_STATE_APP_MASK) >>\
+ TWL6030_CFG_STATE_APP_SHIFT)
+
+/* Flags for SMPS Voltage reading */
+#define SMPS_OFFSET_EN BIT(0)
+#define SMPS_EXTENDED_EN BIT(1)
+
+/* twl6025 SMPS EPROM values */
+#define TWL6030_SMPS_OFFSET 0xB0
+#define TWL6030_SMPS_MULT 0xB3
+#define SMPS_MULTOFFSET_SMPS4 BIT(0)
+#define SMPS_MULTOFFSET_VIO BIT(1)
+#define SMPS_MULTOFFSET_SMPS3 BIT(6)
+
static inline int
twlreg_read(struct twlreg_info *info, unsigned slave_subgp, unsigned offset)
{
@@ -118,21 +146,38 @@ static int twlreg_grp(struct regulator_dev *rdev)
#define P2_GRP_6030 BIT(1) /* "peripherals" */
#define P1_GRP_6030 BIT(0) /* CPU/Linux */
-static int twlreg_is_enabled(struct regulator_dev *rdev)
+static int twl4030reg_is_enabled(struct regulator_dev *rdev)
{
int state = twlreg_grp(rdev);
if (state < 0)
return state;
- if (twl_class_is_4030())
- state &= P1_GRP_4030;
+ return state & P1_GRP_4030;
+}
+
+static int twl6030reg_is_enabled(struct regulator_dev *rdev)
+{
+ struct twlreg_info *info = rdev_get_drvdata(rdev);
+ int grp = 0, val;
+
+ if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
+ grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
+ if (grp < 0)
+ return grp;
+
+ if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
+ grp &= P1_GRP_6030;
else
- state &= P1_GRP_6030;
- return state;
+ grp = 1;
+
+ val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE);
+ val = TWL6030_CFG_STATE_APP(val);
+
+ return grp && (val == TWL6030_CFG_STATE_ON);
}
-static int twlreg_enable(struct regulator_dev *rdev)
+static int twl4030reg_enable(struct regulator_dev *rdev)
{
struct twlreg_info *info = rdev_get_drvdata(rdev);
int grp;
@@ -142,10 +187,7 @@ static int twlreg_enable(struct regulator_dev *rdev)
if (grp < 0)
return grp;
- if (twl_class_is_4030())
- grp |= P1_GRP_4030;
- else
- grp |= P1_GRP_6030;
+ grp |= P1_GRP_4030;
ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
@@ -154,29 +196,63 @@ static int twlreg_enable(struct regulator_dev *rdev)
return ret;
}
-static int twlreg_disable(struct regulator_dev *rdev)
+static int twl6030reg_enable(struct regulator_dev *rdev)
+{
+ struct twlreg_info *info = rdev_get_drvdata(rdev);
+ int grp = 0;
+ int ret;
+
+ if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
+ grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
+ if (grp < 0)
+ return grp;
+
+ ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE,
+ grp << TWL6030_CFG_STATE_GRP_SHIFT |
+ TWL6030_CFG_STATE_ON);
+
+ udelay(info->delay);
+
+ return ret;
+}
+
+static int twl4030reg_disable(struct regulator_dev *rdev)
{
struct twlreg_info *info = rdev_get_drvdata(rdev);
int grp;
+ int ret;
grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
if (grp < 0)
return grp;
- if (twl_class_is_4030())
- grp &= ~(P1_GRP_4030 | P2_GRP_4030 | P3_GRP_4030);
- else
- grp &= ~(P1_GRP_6030 | P2_GRP_6030 | P3_GRP_6030);
+ grp &= ~(P1_GRP_4030 | P2_GRP_4030 | P3_GRP_4030);
- return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
+ ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
+
+ return ret;
}
-static int twlreg_get_status(struct regulator_dev *rdev)
+static int twl6030reg_disable(struct regulator_dev *rdev)
{
- int state = twlreg_grp(rdev);
+ struct twlreg_info *info = rdev_get_drvdata(rdev);
+ int grp = 0;
+ int ret;
+
+ if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
+ grp = P1_GRP_6030 | P2_GRP_6030 | P3_GRP_6030;
+
+ /* For 6030, set the off state for all grps enabled */
+ ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE,
+ (grp) << TWL6030_CFG_STATE_GRP_SHIFT |
+ TWL6030_CFG_STATE_OFF);
+
+ return ret;
+}
- if (twl_class_is_6030())
- return 0; /* FIXME return for 6030 regulator */
+static int twl4030reg_get_status(struct regulator_dev *rdev)
+{
+ int state = twlreg_grp(rdev);
if (state < 0)
return state;
@@ -190,15 +266,39 @@ static int twlreg_get_status(struct regulator_dev *rdev)
: REGULATOR_STATUS_STANDBY;
}
-static int twlreg_set_mode(struct regulator_dev *rdev, unsigned mode)
+static int twl6030reg_get_status(struct regulator_dev *rdev)
+{
+ struct twlreg_info *info = rdev_get_drvdata(rdev);
+ int val;
+
+ val = twlreg_grp(rdev);
+ if (val < 0)
+ return val;
+
+ val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE);
+
+ switch (TWL6030_CFG_STATE_APP(val)) {
+ case TWL6030_CFG_STATE_ON:
+ return REGULATOR_STATUS_NORMAL;
+
+ case TWL6030_CFG_STATE_SLEEP:
+ return REGULATOR_STATUS_STANDBY;
+
+ case TWL6030_CFG_STATE_OFF:
+ case TWL6030_CFG_STATE_OFF2:
+ default:
+ break;
+ }
+
+ return REGULATOR_STATUS_OFF;
+}
+
+static int twl4030reg_set_mode(struct regulator_dev *rdev, unsigned mode)
{
struct twlreg_info *info = rdev_get_drvdata(rdev);
unsigned message;
int status;
- if (twl_class_is_6030())
- return 0; /* FIXME return for 6030 regulator */
-
/* We can only set the mode through state machine commands... */
switch (mode) {
case REGULATOR_MODE_NORMAL:
@@ -227,6 +327,36 @@ static int twlreg_set_mode(struct regulator_dev *rdev, unsigned mode)
message & 0xff, TWL4030_PM_MASTER_PB_WORD_LSB);
}
+static int twl6030reg_set_mode(struct regulator_dev *rdev, unsigned mode)
+{
+ struct twlreg_info *info = rdev_get_drvdata(rdev);
+ int grp = 0;
+ int val;
+
+ if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS)))
+ grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
+
+ if (grp < 0)
+ return grp;
+
+ /* Compose the state register settings */
+ val = grp << TWL6030_CFG_STATE_GRP_SHIFT;
+ /* We can only set the mode through state machine commands... */
+ switch (mode) {
+ case REGULATOR_MODE_NORMAL:
+ val |= TWL6030_CFG_STATE_ON;
+ break;
+ case REGULATOR_MODE_STANDBY:
+ val |= TWL6030_CFG_STATE_SLEEP;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE, val);
+}
+
/*----------------------------------------------------------------------*/
/*
@@ -375,13 +505,13 @@ static struct regulator_ops twl4030ldo_ops = {
.set_voltage = twl4030ldo_set_voltage,
.get_voltage = twl4030ldo_get_voltage,
- .enable = twlreg_enable,
- .disable = twlreg_disable,
- .is_enabled = twlreg_is_enabled,
+ .enable = twl4030reg_enable,
+ .disable = twl4030reg_disable,
+ .is_enabled = twl4030reg_is_enabled,
- .set_mode = twlreg_set_mode,
+ .set_mode = twl4030reg_set_mode,
- .get_status = twlreg_get_status,
+ .get_status = twl4030reg_get_status,
};
static int twl6030ldo_list_voltage(struct regulator_dev *rdev, unsigned index)
@@ -433,13 +563,13 @@ static struct regulator_ops twl6030ldo_ops = {
.set_voltage = twl6030ldo_set_voltage,
.get_voltage = twl6030ldo_get_voltage,
- .enable = twlreg_enable,
- .disable = twlreg_disable,
- .is_enabled = twlreg_is_enabled,
+ .enable = twl6030reg_enable,
+ .disable = twl6030reg_disable,
+ .is_enabled = twl6030reg_is_enabled,
- .set_mode = twlreg_set_mode,
+ .set_mode = twl6030reg_set_mode,
- .get_status = twlreg_get_status,
+ .get_status = twl6030reg_get_status,
};
/*----------------------------------------------------------------------*/
@@ -461,25 +591,242 @@ static int twlfixed_get_voltage(struct regulator_dev *rdev)
return info->min_mV * 1000;
}
-static struct regulator_ops twlfixed_ops = {
+static struct regulator_ops twl4030fixed_ops = {
+ .list_voltage = twlfixed_list_voltage,
+
+ .get_voltage = twlfixed_get_voltage,
+
+ .enable = twl4030reg_enable,
+ .disable = twl4030reg_disable,
+ .is_enabled = twl4030reg_is_enabled,
+
+ .set_mode = twl4030reg_set_mode,
+
+ .get_status = twl4030reg_get_status,
+};
+
+static struct regulator_ops twl6030fixed_ops = {
.list_voltage = twlfixed_list_voltage,
.get_voltage = twlfixed_get_voltage,
- .enable = twlreg_enable,
- .disable = twlreg_disable,
- .is_enabled = twlreg_is_enabled,
+ .enable = twl6030reg_enable,
+ .disable = twl6030reg_disable,
+ .is_enabled = twl6030reg_is_enabled,
- .set_mode = twlreg_set_mode,
+ .set_mode = twl6030reg_set_mode,
- .get_status = twlreg_get_status,
+ .get_status = twl6030reg_get_status,
};
static struct regulator_ops twl6030_fixed_resource = {
- .enable = twlreg_enable,
- .disable = twlreg_disable,
- .is_enabled = twlreg_is_enabled,
- .get_status = twlreg_get_status,
+ .enable = twl6030reg_enable,
+ .disable = twl6030reg_disable,
+ .is_enabled = twl6030reg_is_enabled,
+ .get_status = twl6030reg_get_status,
+};
+
+/*
+ * SMPS status and control
+ */
+
+static int twl6030smps_list_voltage(struct regulator_dev *rdev, unsigned index)
+{
+ struct twlreg_info *info = rdev_get_drvdata(rdev);
+
+ int voltage = 0;
+
+ switch (info->flags) {
+ case SMPS_OFFSET_EN:
+ voltage = 100000;
+ /* fall through */
+ case 0:
+ switch (index) {
+ case 0:
+ voltage = 0;
+ break;
+ case 58:
+ voltage = 1350 * 1000;
+ break;
+ case 59:
+ voltage = 1500 * 1000;
+ break;
+ case 60:
+ voltage = 1800 * 1000;
+ break;
+ case 61:
+ voltage = 1900 * 1000;
+ break;
+ case 62:
+ voltage = 2100 * 1000;
+ break;
+ default:
+ voltage += (600000 + (12500 * (index - 1)));
+ }
+ break;
+ case SMPS_EXTENDED_EN:
+ switch (index) {
+ case 0:
+ voltage = 0;
+ break;
+ case 58:
+ voltage = 2084 * 1000;
+ break;
+ case 59:
+ voltage = 2315 * 1000;
+ break;
+ case 60:
+ voltage = 2778 * 1000;
+ break;
+ case 61:
+ voltage = 2932 * 1000;
+ break;
+ case 62:
+ voltage = 3241 * 1000;
+ break;
+ default:
+ voltage = (1852000 + (38600 * (index - 1)));
+ }
+ break;
+ case SMPS_OFFSET_EN | SMPS_EXTENDED_EN:
+ switch (index) {
+ case 0:
+ voltage = 0;
+ break;
+ case 58:
+ voltage = 4167 * 1000;
+ break;
+ case 59:
+ voltage = 2315 * 1000;
+ break;
+ case 60:
+ voltage = 2778 * 1000;
+ break;
+ case 61:
+ voltage = 2932 * 1000;
+ break;
+ case 62:
+ voltage = 3241 * 1000;
+ break;
+ default:
+ voltage = (2161000 + (38600 * (index - 1)));
+ }
+ break;
+ }
+
+ return voltage;
+}
+
+static int
+twl6030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
+ unsigned int *selector)
+{
+ struct twlreg_info *info = rdev_get_drvdata(rdev);
+ int vsel = 0;
+
+ switch (info->flags) {
+ case 0:
+ if (min_uV == 0)
+ vsel = 0;
+ else if ((min_uV >= 600000) && (max_uV <= 1300000)) {
+ vsel = (min_uV - 600000) / 125;
+ if (vsel % 100)
+ vsel += 100;
+ vsel /= 100;
+ vsel++;
+ }
+ /* Values 1..57 for vsel are linear and can be calculated
+ * values 58..62 are non linear.
+ */
+ else if ((min_uV > 1900000) && (max_uV >= 2100000))
+ vsel = 62;
+ else if ((min_uV > 1800000) && (max_uV >= 1900000))
+ vsel = 61;
+ else if ((min_uV > 1500000) && (max_uV >= 1800000))
+ vsel = 60;
+ else if ((min_uV > 1350000) && (max_uV >= 1500000))
+ vsel = 59;
+ else if ((min_uV > 1300000) && (max_uV >= 1350000))
+ vsel = 58;
+ else
+ return -EINVAL;
+ break;
+ case SMPS_OFFSET_EN:
+ if (min_uV == 0)
+ vsel = 0;
+ else if ((min_uV >= 700000) && (max_uV <= 1420000)) {
+ vsel = (min_uV - 700000) / 125;
+ if (vsel % 100)
+ vsel += 100;
+ vsel /= 100;
+ vsel++;
+ }
+ /* Values 1..57 for vsel are linear and can be calculated
+ * values 58..62 are non linear.
+ */
+ else if ((min_uV > 1900000) && (max_uV >= 2100000))
+ vsel = 62;
+ else if ((min_uV > 1800000) && (max_uV >= 1900000))
+ vsel = 61;
+ else if ((min_uV > 1350000) && (max_uV >= 1800000))
+ vsel = 60;
+ else if ((min_uV > 1350000) && (max_uV >= 1500000))
+ vsel = 59;
+ else if ((min_uV > 1300000) && (max_uV >= 1350000))
+ vsel = 58;
+ else
+ return -EINVAL;
+ break;
+ case SMPS_EXTENDED_EN:
+ if (min_uV == 0)
+ vsel = 0;
+ else if ((min_uV >= 1852000) && (max_uV <= 4013600)) {
+ vsel = (min_uV - 1852000) / 386;
+ if (vsel % 100)
+ vsel += 100;
+ vsel /= 100;
+ vsel++;
+ }
+ break;
+ case SMPS_OFFSET_EN|SMPS_EXTENDED_EN:
+ if (min_uV == 0)
+ vsel = 0;
+ else if ((min_uV >= 2161000) && (max_uV <= 4321000)) {
+ vsel = (min_uV - 1852000) / 386;
+ if (vsel % 100)
+ vsel += 100;
+ vsel /= 100;
+ vsel++;
+ }
+ break;
+ }
+
+ *selector = vsel;
+
+ return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS,
+ vsel);
+}
+
+static int twl6030smps_get_voltage_sel(struct regulator_dev *rdev)
+{
+ struct twlreg_info *info = rdev_get_drvdata(rdev);
+
+ return twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS);
+}
+
+static struct regulator_ops twlsmps_ops = {
+ .list_voltage = twl6030smps_list_voltage,
+
+ .set_voltage = twl6030smps_set_voltage,
+ .get_voltage_sel = twl6030smps_get_voltage_sel,
+
+ .enable = twl6030reg_enable,
+ .disable = twl6030reg_disable,
+ .is_enabled = twl6030reg_is_enabled,
+
+ .set_mode = twl6030reg_set_mode,
+
+ .get_status = twl6030reg_get_status,
};
/*----------------------------------------------------------------------*/
@@ -487,11 +834,10 @@ static struct regulator_ops twl6030_fixed_resource = {
#define TWL4030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
remap_conf) \
TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
- remap_conf, TWL4030)
-#define TWL6030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
- remap_conf) \
+ remap_conf, TWL4030, twl4030fixed_ops)
+#define TWL6030_FIXED_LDO(label, offset, mVolts, num, turnon_delay) \
TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
- remap_conf, TWL6030)
+ 0x0, TWL6030, twl6030fixed_ops)
#define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) { \
.base = offset, \
@@ -510,13 +856,11 @@ static struct regulator_ops twl6030_fixed_resource = {
}, \
}
-#define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts, num, \
- remap_conf) { \
+#define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts, num) { \
.base = offset, \
.id = num, \
.min_mV = min_mVolts, \
.max_mV = max_mVolts, \
- .remap = remap_conf, \
.desc = { \
.name = #label, \
.id = TWL6030_REG_##label, \
@@ -527,9 +871,23 @@ static struct regulator_ops twl6030_fixed_resource = {
}, \
}
+#define TWL6025_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts, num) { \
+ .base = offset, \
+ .id = num, \
+ .min_mV = min_mVolts, \
+ .max_mV = max_mVolts, \
+ .desc = { \
+ .name = #label, \
+ .id = TWL6025_REG_##label, \
+ .n_voltages = ((max_mVolts - min_mVolts)/100) + 1, \
+ .ops = &twl6030ldo_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ }, \
+ }
#define TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, remap_conf, \
- family) { \
+ family, operations) { \
.base = offset, \
.id = num, \
.min_mV = mVolts, \
@@ -539,17 +897,16 @@ static struct regulator_ops twl6030_fixed_resource = {
.name = #label, \
.id = family##_REG_##label, \
.n_voltages = 1, \
- .ops = &twlfixed_ops, \
+ .ops = &operations, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
}, \
}
-#define TWL6030_FIXED_RESOURCE(label, offset, num, turnon_delay, remap_conf) { \
+#define TWL6030_FIXED_RESOURCE(label, offset, num, turnon_delay) { \
.base = offset, \
.id = num, \
.delay = turnon_delay, \
- .remap = remap_conf, \
.desc = { \
.name = #label, \
.id = TWL6030_REG_##label, \
@@ -559,6 +916,21 @@ static struct regulator_ops twl6030_fixed_resource = {
}, \
}
+#define TWL6025_ADJUSTABLE_SMPS(label, offset, num) { \
+ .base = offset, \
+ .id = num, \
+ .min_mV = 600, \
+ .max_mV = 2100, \
+ .desc = { \
+ .name = #label, \
+ .id = TWL6025_REG_##label, \
+ .n_voltages = 63, \
+ .ops = &twlsmps_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ }, \
+ }
+
/*
* We list regulators here if systems need some level of
* software control over them after boot.
@@ -589,19 +961,52 @@ static struct twlreg_info twl_regs[] = {
/* 6030 REG with base as PMC Slave Misc : 0x0030 */
/* Turnon-delay and remap configuration values for 6030 are not
verified since the specification is not public */
- TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000, 3300, 1, 0x21),
- TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300, 2, 0x21),
- TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300, 3, 0x21),
- TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300, 4, 0x21),
- TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300, 5, 0x21),
- TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300, 7, 0x21),
- TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0, 0x21),
- TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0, 0x21),
- TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0, 0x21),
- TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0, 0x21),
- TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 48, 0, 0x21),
+ TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000, 3300, 1),
+ TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300, 2),
+ TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300, 3),
+ TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300, 4),
+ TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300, 5),
+ TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300, 7),
+ TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0),
+ TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0),
+ TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0),
+ TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0),
+ TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 48, 0),
+
+ /* 6025 are renamed compared to 6030 versions */
+ TWL6025_ADJUSTABLE_LDO(LDO2, 0x54, 1000, 3300, 1),
+ TWL6025_ADJUSTABLE_LDO(LDO4, 0x58, 1000, 3300, 2),
+ TWL6025_ADJUSTABLE_LDO(LDO3, 0x5c, 1000, 3300, 3),
+ TWL6025_ADJUSTABLE_LDO(LDO5, 0x68, 1000, 3300, 4),
+ TWL6025_ADJUSTABLE_LDO(LDO1, 0x6c, 1000, 3300, 5),
+ TWL6025_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300, 7),
+ TWL6025_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300, 16),
+ TWL6025_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300, 17),
+ TWL6025_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300, 18),
+
+ TWL6025_ADJUSTABLE_SMPS(SMPS3, 0x34, 1),
+ TWL6025_ADJUSTABLE_SMPS(SMPS4, 0x10, 2),
+ TWL6025_ADJUSTABLE_SMPS(VIO, 0x16, 3),
};
+static u8 twl_get_smps_offset(void)
+{
+ u8 value;
+
+ twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &value,
+ TWL6030_SMPS_OFFSET);
+ return value;
+}
+
+static u8 twl_get_smps_mult(void)
+{
+ u8 value;
+
+ twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &value,
+ TWL6030_SMPS_MULT);
+ return value;
+}
+
static int __devinit twlreg_probe(struct platform_device *pdev)
{
int i;
@@ -623,6 +1028,9 @@ static int __devinit twlreg_probe(struct platform_device *pdev)
if (!initdata)
return -EINVAL;
+ /* copy the features into regulator data */
+ info->features = (unsigned long)initdata->driver_data;
+
/* Constrain board-specific capabilities according to what
* this driver and the chip itself can actually do.
*/
@@ -645,6 +1053,27 @@ static int __devinit twlreg_probe(struct platform_device *pdev)
break;
}
+ switch (pdev->id) {
+ case TWL6025_REG_SMPS3:
+ if (twl_get_smps_mult() & SMPS_MULTOFFSET_SMPS3)
+ info->flags |= SMPS_EXTENDED_EN;
+ if (twl_get_smps_offset() & SMPS_MULTOFFSET_SMPS3)
+ info->flags |= SMPS_OFFSET_EN;
+ break;
+ case TWL6025_REG_SMPS4:
+ if (twl_get_smps_mult() & SMPS_MULTOFFSET_SMPS4)
+ info->flags |= SMPS_EXTENDED_EN;
+ if (twl_get_smps_offset() & SMPS_MULTOFFSET_SMPS4)
+ info->flags |= SMPS_OFFSET_EN;
+ break;
+ case TWL6025_REG_VIO:
+ if (twl_get_smps_mult() & SMPS_MULTOFFSET_VIO)
+ info->flags |= SMPS_EXTENDED_EN;
+ if (twl_get_smps_offset() & SMPS_MULTOFFSET_VIO)
+ info->flags |= SMPS_OFFSET_EN;
+ break;
+ }
+
rdev = regulator_register(&info->desc, &pdev->dev, initdata, info);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "can't register %s, %ld\n",
@@ -653,7 +1082,8 @@ static int __devinit twlreg_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, rdev);
- twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_REMAP,
+ if (twl_class_is_4030())
+ twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_REMAP,
info->remap);
/* NOTE: many regulators support short-circuit IRQs (presentable
diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c
index e93453b1b978..a0982e809851 100644
--- a/drivers/regulator/wm831x-dcdc.c
+++ b/drivers/regulator/wm831x-dcdc.c
@@ -600,7 +600,6 @@ err:
static __devexit int wm831x_buckv_remove(struct platform_device *pdev)
{
struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev);
- struct wm831x *wm831x = dcdc->wm831x;
platform_set_drvdata(pdev, NULL);
@@ -776,7 +775,6 @@ err:
static __devexit int wm831x_buckp_remove(struct platform_device *pdev)
{
struct wm831x_dcdc *dcdc = platform_get_drvdata(pdev);
- struct wm831x *wm831x = dcdc->wm831x;
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c
index b42d01cef35a..0f12c70bebc9 100644
--- a/drivers/regulator/wm8400-regulator.c
+++ b/drivers/regulator/wm8400-regulator.c
@@ -55,7 +55,7 @@ static int wm8400_ldo_list_voltage(struct regulator_dev *dev,
return 1600000 + ((selector - 14) * 100000);
}
-static int wm8400_ldo_get_voltage(struct regulator_dev *dev)
+static int wm8400_ldo_get_voltage_sel(struct regulator_dev *dev)
{
struct wm8400 *wm8400 = rdev_get_drvdata(dev);
u16 val;
@@ -63,7 +63,7 @@ static int wm8400_ldo_get_voltage(struct regulator_dev *dev)
val = wm8400_reg_read(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev));
val &= WM8400_LDO1_VSEL_MASK;
- return wm8400_ldo_list_voltage(dev, val);
+ return val;
}
static int wm8400_ldo_set_voltage(struct regulator_dev *dev,
@@ -104,7 +104,7 @@ static struct regulator_ops wm8400_ldo_ops = {
.enable = wm8400_ldo_enable,
.disable = wm8400_ldo_disable,
.list_voltage = wm8400_ldo_list_voltage,
- .get_voltage = wm8400_ldo_get_voltage,
+ .get_voltage_sel = wm8400_ldo_get_voltage_sel,
.set_voltage = wm8400_ldo_set_voltage,
};
@@ -145,7 +145,7 @@ static int wm8400_dcdc_list_voltage(struct regulator_dev *dev,
return 850000 + (selector * 25000);
}
-static int wm8400_dcdc_get_voltage(struct regulator_dev *dev)
+static int wm8400_dcdc_get_voltage_sel(struct regulator_dev *dev)
{
struct wm8400 *wm8400 = rdev_get_drvdata(dev);
u16 val;
@@ -154,7 +154,7 @@ static int wm8400_dcdc_get_voltage(struct regulator_dev *dev)
val = wm8400_reg_read(wm8400, WM8400_DCDC1_CONTROL_1 + offset);
val &= WM8400_DC1_VSEL_MASK;
- return 850000 + (25000 * val);
+ return val;
}
static int wm8400_dcdc_set_voltage(struct regulator_dev *dev,
@@ -261,7 +261,7 @@ static struct regulator_ops wm8400_dcdc_ops = {
.enable = wm8400_dcdc_enable,
.disable = wm8400_dcdc_disable,
.list_voltage = wm8400_dcdc_list_voltage,
- .get_voltage = wm8400_dcdc_get_voltage,
+ .get_voltage_sel = wm8400_dcdc_get_voltage_sel,
.set_voltage = wm8400_dcdc_set_voltage,
.get_mode = wm8400_dcdc_get_mode,
.set_mode = wm8400_dcdc_set_mode,
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index e1878877399c..f822e13dc04b 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -3,10 +3,10 @@
#
config RTC_LIB
- tristate
+ bool
menuconfig RTC_CLASS
- tristate "Real Time Clock"
+ bool "Real Time Clock"
default n
depends on !S390
select RTC_LIB
@@ -15,9 +15,6 @@ menuconfig RTC_CLASS
be allowed to plug one or more RTCs to your system. You will
probably want to enable one or more of the interfaces below.
- This driver can also be built as a module. If so, the module
- will be called rtc-core.
-
if RTC_CLASS
config RTC_HCTOSYS
@@ -128,6 +125,16 @@ comment "I2C RTC drivers"
if I2C
+config RTC_DRV_88PM860X
+ tristate "Marvell 88PM860x"
+ depends on RTC_CLASS && I2C && MFD_88PM860X
+ help
+ If you say yes here you get support for RTC function in Marvell
+ 88PM860x chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-88pm860x.
+
config RTC_DRV_DS1307
tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025"
help
@@ -354,12 +361,39 @@ config RTC_DRV_RX8025
This driver can also be built as a module. If so, the module
will be called rtc-rx8025.
+config RTC_DRV_EM3027
+ tristate "EM Microelectronic EM3027"
+ help
+ If you say yes here you get support for the EM
+ Microelectronic EM3027 RTC chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-em3027.
+
+config RTC_DRV_RV3029C2
+ tristate "Micro Crystal RTC"
+ help
+ If you say yes here you get support for the Micro Crystal
+ RV3029-C2 RTC chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-rv3029c2.
+
endif # I2C
comment "SPI RTC drivers"
if SPI_MASTER
+config RTC_DRV_M41T93
+ tristate "ST M41T93"
+ help
+ If you say yes here you will get support for the
+ ST M41T93 SPI RTC chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-m41t93.
+
config RTC_DRV_M41T94
tristate "ST M41T94"
help
@@ -648,6 +682,14 @@ config RTC_DRV_WM8350
This driver can also be built as a module. If so, the module
will be called "rtc-wm8350".
+config RTC_DRV_SPEAR
+ tristate "SPEAR ST RTC"
+ depends on PLAT_SPEAR
+ default y
+ help
+ If you say Y here you will get support for the RTC found on
+ spear
+
config RTC_DRV_PCF50633
depends on MFD_PCF50633
tristate "NXP PCF50633 RTC"
@@ -877,6 +919,13 @@ config RTC_DRV_PXA
This RTC driver uses PXA RTC registers available since pxa27x
series (RDxR, RYxR) instead of legacy RCNR, RTAR.
+config RTC_DRV_VT8500
+ tristate "VIA/WonderMedia 85xx SoC RTC"
+ depends on ARCH_VT8500
+ help
+ If you say Y here you will get access to the real time clock
+ built into your VIA VT8500 SoC or its relatives.
+
config RTC_DRV_SUN4V
bool "SUN4V Hypervisor RTC"
@@ -995,4 +1044,11 @@ config RTC_DRV_TEGRA
This drive can also be built as a module. If so, the module
will be called rtc-tegra.
+config RTC_DRV_TILE
+ tristate "Tilera hypervisor RTC support"
+ depends on TILE
+ help
+ Enable support for the Linux driver side of the Tilera
+ hypervisor's real-time clock interface.
+
endif # RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index ca91c3c42e98..213d725f16d4 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -15,6 +15,7 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
# Keep the list ordered.
+obj-$(CONFIG_RTC_DRV_88PM860X) += rtc-88pm860x.o
obj-$(CONFIG_RTC_DRV_AB3100) += rtc-ab3100.o
obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o
obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
@@ -43,6 +44,7 @@ obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
obj-$(CONFIG_RTC_DRV_DS3232) += rtc-ds3232.o
obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o
obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o
+obj-$(CONFIG_RTC_DRV_EM3027) += rtc-em3027.o
obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o
@@ -52,6 +54,7 @@ obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o
obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o
obj-$(CONFIG_RTC_DRV_LPC32XX) += rtc-lpc32xx.o
obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o
+obj-$(CONFIG_RTC_DRV_M41T93) += rtc-m41t93.o
obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o
obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o
obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o
@@ -81,22 +84,26 @@ obj-$(CONFIG_RTC_DRV_RP5C01) += rtc-rp5c01.o
obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o
+obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o
obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o
obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o
obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o
obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o
obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o
obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
+obj-$(CONFIG_RTC_DRV_SPEAR) += rtc-spear.o
obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o
obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
obj-$(CONFIG_RTC_DRV_STMP) += rtc-stmp3xxx.o
obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o
obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o
obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
+obj-$(CONFIG_RTC_DRV_TILE) += rtc-tile.o
obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o
obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o
obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o
+obj-$(CONFIG_RTC_DRV_VT8500) += rtc-vt8500.o
obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o
obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 39013867cbd6..4194e59e14cd 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -41,26 +41,21 @@ static void rtc_device_release(struct device *dev)
* system's wall clock; restore it on resume().
*/
-static struct timespec delta;
static time_t oldtime;
+static struct timespec oldts;
static int rtc_suspend(struct device *dev, pm_message_t mesg)
{
struct rtc_device *rtc = to_rtc_device(dev);
struct rtc_time tm;
- struct timespec ts = current_kernel_time();
if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0)
return 0;
rtc_read_time(rtc, &tm);
+ ktime_get_ts(&oldts);
rtc_tm_to_time(&tm, &oldtime);
- /* RTC precision is 1 second; adjust delta for avg 1/2 sec err */
- set_normalized_timespec(&delta,
- ts.tv_sec - oldtime,
- ts.tv_nsec - (NSEC_PER_SEC >> 1));
-
return 0;
}
@@ -70,10 +65,12 @@ static int rtc_resume(struct device *dev)
struct rtc_time tm;
time_t newtime;
struct timespec time;
+ struct timespec newts;
if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0)
return 0;
+ ktime_get_ts(&newts);
rtc_read_time(rtc, &tm);
if (rtc_valid_tm(&tm) != 0) {
pr_debug("%s: bogus resume time\n", dev_name(&rtc->dev));
@@ -85,15 +82,13 @@ static int rtc_resume(struct device *dev)
pr_debug("%s: time travel!\n", dev_name(&rtc->dev));
return 0;
}
+ /* calculate the RTC time delta */
+ set_normalized_timespec(&time, newtime - oldtime, 0);
- /* restore wall clock using delta against this RTC;
- * adjust again for avg 1/2 second RTC sampling error
- */
- set_normalized_timespec(&time,
- newtime + delta.tv_sec,
- (NSEC_PER_SEC >> 1) + delta.tv_nsec);
- do_settimeofday(&time);
+ /* subtract kernel time between rtc_suspend to rtc_resume */
+ time = timespec_sub(time, timespec_sub(newts, oldts));
+ timekeeping_inject_sleeptime(&time);
return 0;
}
diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c
new file mode 100644
index 000000000000..64b847b7f970
--- /dev/null
+++ b/drivers/rtc/rtc-88pm860x.c
@@ -0,0 +1,427 @@
+/*
+ * Real Time Clock driver for Marvell 88PM860x PMIC
+ *
+ * Copyright (c) 2010 Marvell International Ltd.
+ * Author: Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/rtc.h>
+#include <linux/delay.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/88pm860x.h>
+
+#define VRTC_CALIBRATION
+
+struct pm860x_rtc_info {
+ struct pm860x_chip *chip;
+ struct i2c_client *i2c;
+ struct rtc_device *rtc_dev;
+ struct device *dev;
+ struct delayed_work calib_work;
+
+ int irq;
+ int vrtc;
+ int (*sync)(unsigned int ticks);
+};
+
+#define REG_VRTC_MEAS1 0x7D
+
+#define REG0_ADDR 0xB0
+#define REG1_ADDR 0xB2
+#define REG2_ADDR 0xB4
+#define REG3_ADDR 0xB6
+
+#define REG0_DATA 0xB1
+#define REG1_DATA 0xB3
+#define REG2_DATA 0xB5
+#define REG3_DATA 0xB7
+
+/* bit definitions of Measurement Enable Register 2 (0x51) */
+#define MEAS2_VRTC (1 << 0)
+
+/* bit definitions of RTC Register 1 (0xA0) */
+#define ALARM_EN (1 << 3)
+#define ALARM_WAKEUP (1 << 4)
+#define ALARM (1 << 5)
+#define RTC1_USE_XO (1 << 7)
+
+#define VRTC_CALIB_INTERVAL (HZ * 60 * 10) /* 10 minutes */
+
+static irqreturn_t rtc_update_handler(int irq, void *data)
+{
+ struct pm860x_rtc_info *info = (struct pm860x_rtc_info *)data;
+ int mask;
+
+ mask = ALARM | ALARM_WAKEUP;
+ pm860x_set_bits(info->i2c, PM8607_RTC1, mask | ALARM_EN, mask);
+ rtc_update_irq(info->rtc_dev, 1, RTC_AF);
+ return IRQ_HANDLED;
+}
+
+static int pm860x_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct pm860x_rtc_info *info = dev_get_drvdata(dev);
+
+ if (enabled)
+ pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM, ALARM);
+ else
+ pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM, 0);
+ return 0;
+}
+
+/*
+ * Calculate the next alarm time given the requested alarm time mask
+ * and the current time.
+ */
+static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now,
+ struct rtc_time *alrm)
+{
+ unsigned long next_time;
+ unsigned long now_time;
+
+ next->tm_year = now->tm_year;
+ next->tm_mon = now->tm_mon;
+ next->tm_mday = now->tm_mday;
+ next->tm_hour = alrm->tm_hour;
+ next->tm_min = alrm->tm_min;
+ next->tm_sec = alrm->tm_sec;
+
+ rtc_tm_to_time(now, &now_time);
+ rtc_tm_to_time(next, &next_time);
+
+ if (next_time < now_time) {
+ /* Advance one day */
+ next_time += 60 * 60 * 24;
+ rtc_time_to_tm(next_time, next);
+ }
+}
+
+static int pm860x_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct pm860x_rtc_info *info = dev_get_drvdata(dev);
+ unsigned char buf[8];
+ unsigned long ticks, base, data;
+
+ pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf);
+ dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1],
+ buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+ base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7];
+
+ /* load 32-bit read-only counter */
+ pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf);
+ data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+ ticks = base + data;
+ dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
+ base, data, ticks);
+
+ rtc_time_to_tm(ticks, tm);
+
+ return 0;
+}
+
+static int pm860x_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct pm860x_rtc_info *info = dev_get_drvdata(dev);
+ unsigned char buf[4];
+ unsigned long ticks, base, data;
+
+ if ((tm->tm_year < 70) || (tm->tm_year > 138)) {
+ dev_dbg(info->dev, "Set time %d out of range. "
+ "Please set time between 1970 to 2038.\n",
+ 1900 + tm->tm_year);
+ return -EINVAL;
+ }
+ rtc_tm_to_time(tm, &ticks);
+
+ /* load 32-bit read-only counter */
+ pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf);
+ data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+ base = ticks - data;
+ dev_dbg(info->dev, "set base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
+ base, data, ticks);
+
+ pm860x_page_reg_write(info->i2c, REG0_DATA, (base >> 24) & 0xFF);
+ pm860x_page_reg_write(info->i2c, REG1_DATA, (base >> 16) & 0xFF);
+ pm860x_page_reg_write(info->i2c, REG2_DATA, (base >> 8) & 0xFF);
+ pm860x_page_reg_write(info->i2c, REG3_DATA, base & 0xFF);
+
+ if (info->sync)
+ info->sync(ticks);
+ return 0;
+}
+
+static int pm860x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct pm860x_rtc_info *info = dev_get_drvdata(dev);
+ unsigned char buf[8];
+ unsigned long ticks, base, data;
+ int ret;
+
+ pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf);
+ dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1],
+ buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+ base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7];
+
+ pm860x_bulk_read(info->i2c, PM8607_RTC_EXPIRE1, 4, buf);
+ data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+ ticks = base + data;
+ dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
+ base, data, ticks);
+
+ rtc_time_to_tm(ticks, &alrm->time);
+ ret = pm860x_reg_read(info->i2c, PM8607_RTC1);
+ alrm->enabled = (ret & ALARM_EN) ? 1 : 0;
+ alrm->pending = (ret & (ALARM | ALARM_WAKEUP)) ? 1 : 0;
+ return 0;
+}
+
+static int pm860x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct pm860x_rtc_info *info = dev_get_drvdata(dev);
+ struct rtc_time now_tm, alarm_tm;
+ unsigned long ticks, base, data;
+ unsigned char buf[8];
+ int mask;
+
+ pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM_EN, 0);
+
+ pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf);
+ dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1],
+ buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+ base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7];
+
+ /* load 32-bit read-only counter */
+ pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf);
+ data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+ ticks = base + data;
+ dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
+ base, data, ticks);
+
+ rtc_time_to_tm(ticks, &now_tm);
+ rtc_next_alarm_time(&alarm_tm, &now_tm, &alrm->time);
+ /* get new ticks for alarm in 24 hours */
+ rtc_tm_to_time(&alarm_tm, &ticks);
+ data = ticks - base;
+
+ buf[0] = data & 0xff;
+ buf[1] = (data >> 8) & 0xff;
+ buf[2] = (data >> 16) & 0xff;
+ buf[3] = (data >> 24) & 0xff;
+ pm860x_bulk_write(info->i2c, PM8607_RTC_EXPIRE1, 4, buf);
+ if (alrm->enabled) {
+ mask = ALARM | ALARM_WAKEUP | ALARM_EN;
+ pm860x_set_bits(info->i2c, PM8607_RTC1, mask, mask);
+ } else {
+ mask = ALARM | ALARM_WAKEUP | ALARM_EN;
+ pm860x_set_bits(info->i2c, PM8607_RTC1, mask,
+ ALARM | ALARM_WAKEUP);
+ }
+ return 0;
+}
+
+static const struct rtc_class_ops pm860x_rtc_ops = {
+ .read_time = pm860x_rtc_read_time,
+ .set_time = pm860x_rtc_set_time,
+ .read_alarm = pm860x_rtc_read_alarm,
+ .set_alarm = pm860x_rtc_set_alarm,
+ .alarm_irq_enable = pm860x_rtc_alarm_irq_enable,
+};
+
+#ifdef VRTC_CALIBRATION
+static void calibrate_vrtc_work(struct work_struct *work)
+{
+ struct pm860x_rtc_info *info = container_of(work,
+ struct pm860x_rtc_info, calib_work.work);
+ unsigned char buf[2];
+ unsigned int sum, data, mean, vrtc_set;
+ int i;
+
+ for (i = 0, sum = 0; i < 16; i++) {
+ msleep(100);
+ pm860x_bulk_read(info->i2c, REG_VRTC_MEAS1, 2, buf);
+ data = (buf[0] << 4) | buf[1];
+ data = (data * 5400) >> 12; /* convert to mv */
+ sum += data;
+ }
+ mean = sum >> 4;
+ vrtc_set = 2700 + (info->vrtc & 0x3) * 200;
+ dev_dbg(info->dev, "mean:%d, vrtc_set:%d\n", mean, vrtc_set);
+
+ sum = pm860x_reg_read(info->i2c, PM8607_RTC_MISC1);
+ data = sum & 0x3;
+ if ((mean + 200) < vrtc_set) {
+ /* try higher voltage */
+ if (++data == 4)
+ goto out;
+ data = (sum & 0xf8) | (data & 0x3);
+ pm860x_reg_write(info->i2c, PM8607_RTC_MISC1, data);
+ } else if ((mean - 200) > vrtc_set) {
+ /* try lower voltage */
+ if (data-- == 0)
+ goto out;
+ data = (sum & 0xf8) | (data & 0x3);
+ pm860x_reg_write(info->i2c, PM8607_RTC_MISC1, data);
+ } else
+ goto out;
+ dev_dbg(info->dev, "set 0x%x to RTC_MISC1\n", data);
+ /* trigger next calibration since VRTC is updated */
+ schedule_delayed_work(&info->calib_work, VRTC_CALIB_INTERVAL);
+ return;
+out:
+ /* disable measurement */
+ pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, 0);
+ dev_dbg(info->dev, "finish VRTC calibration\n");
+ return;
+}
+#endif
+
+static int __devinit pm860x_rtc_probe(struct platform_device *pdev)
+{
+ struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct pm860x_rtc_pdata *pdata = NULL;
+ struct pm860x_rtc_info *info;
+ struct rtc_time tm;
+ unsigned long ticks = 0;
+ int ret;
+
+ pdata = pdev->dev.platform_data;
+ if (pdata == NULL)
+ dev_warn(&pdev->dev, "No platform data!\n");
+
+ info = kzalloc(sizeof(struct pm860x_rtc_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+ info->irq = platform_get_irq(pdev, 0);
+ if (info->irq < 0) {
+ dev_err(&pdev->dev, "No IRQ resource!\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ info->chip = chip;
+ info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
+ info->dev = &pdev->dev;
+ dev_set_drvdata(&pdev->dev, info);
+
+ ret = request_threaded_irq(info->irq, NULL, rtc_update_handler,
+ IRQF_ONESHOT, "rtc", info);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
+ info->irq, ret);
+ goto out;
+ }
+
+ /* set addresses of 32-bit base value for RTC time */
+ pm860x_page_reg_write(info->i2c, REG0_ADDR, REG0_DATA);
+ pm860x_page_reg_write(info->i2c, REG1_ADDR, REG1_DATA);
+ pm860x_page_reg_write(info->i2c, REG2_ADDR, REG2_DATA);
+ pm860x_page_reg_write(info->i2c, REG3_ADDR, REG3_DATA);
+
+ ret = pm860x_rtc_read_time(&pdev->dev, &tm);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to read initial time.\n");
+ goto out_rtc;
+ }
+ if ((tm.tm_year < 70) || (tm.tm_year > 138)) {
+ tm.tm_year = 70;
+ tm.tm_mon = 0;
+ tm.tm_mday = 1;
+ tm.tm_hour = 0;
+ tm.tm_min = 0;
+ tm.tm_sec = 0;
+ ret = pm860x_rtc_set_time(&pdev->dev, &tm);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to set initial time.\n");
+ goto out_rtc;
+ }
+ }
+ rtc_tm_to_time(&tm, &ticks);
+ if (pdata && pdata->sync) {
+ pdata->sync(ticks);
+ info->sync = pdata->sync;
+ }
+
+ info->rtc_dev = rtc_device_register("88pm860x-rtc", &pdev->dev,
+ &pm860x_rtc_ops, THIS_MODULE);
+ ret = PTR_ERR(info->rtc_dev);
+ if (IS_ERR(info->rtc_dev)) {
+ dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
+ goto out_rtc;
+ }
+
+ /*
+ * enable internal XO instead of internal 3.25MHz clock since it can
+ * free running in PMIC power-down state.
+ */
+ pm860x_set_bits(info->i2c, PM8607_RTC1, RTC1_USE_XO, RTC1_USE_XO);
+
+#ifdef VRTC_CALIBRATION
+ /* <00> -- 2.7V, <01> -- 2.9V, <10> -- 3.1V, <11> -- 3.3V */
+ if (pdata && pdata->vrtc)
+ info->vrtc = pdata->vrtc & 0x3;
+ else
+ info->vrtc = 1;
+ pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, MEAS2_VRTC);
+
+ /* calibrate VRTC */
+ INIT_DELAYED_WORK(&info->calib_work, calibrate_vrtc_work);
+ schedule_delayed_work(&info->calib_work, VRTC_CALIB_INTERVAL);
+#endif /* VRTC_CALIBRATION */
+ return 0;
+out_rtc:
+ free_irq(info->irq, info);
+out:
+ kfree(info);
+ return ret;
+}
+
+static int __devexit pm860x_rtc_remove(struct platform_device *pdev)
+{
+ struct pm860x_rtc_info *info = platform_get_drvdata(pdev);
+
+#ifdef VRTC_CALIBRATION
+ flush_scheduled_work();
+ /* disable measurement */
+ pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, 0);
+#endif /* VRTC_CALIBRATION */
+
+ platform_set_drvdata(pdev, NULL);
+ rtc_device_unregister(info->rtc_dev);
+ free_irq(info->irq, info);
+ kfree(info);
+ return 0;
+}
+
+static struct platform_driver pm860x_rtc_driver = {
+ .driver = {
+ .name = "88pm860x-rtc",
+ .owner = THIS_MODULE,
+ },
+ .probe = pm860x_rtc_probe,
+ .remove = __devexit_p(pm860x_rtc_remove),
+};
+
+static int __init pm860x_rtc_init(void)
+{
+ return platform_driver_register(&pm860x_rtc_driver);
+}
+module_init(pm860x_rtc_init);
+
+static void __exit pm860x_rtc_exit(void)
+{
+ platform_driver_unregister(&pm860x_rtc_driver);
+}
+module_exit(pm860x_rtc_exit);
+
+MODULE_DESCRIPTION("Marvell 88PM860x RTC driver");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-em3027.c b/drivers/rtc/rtc-em3027.c
new file mode 100644
index 000000000000..d8e1c2578553
--- /dev/null
+++ b/drivers/rtc/rtc-em3027.c
@@ -0,0 +1,161 @@
+/*
+ * An rtc/i2c driver for the EM Microelectronic EM3027
+ * Copyright 2011 CompuLab, Ltd.
+ *
+ * Author: Mike Rapoport <mike@compulab.co.il>
+ *
+ * Based on rtc-ds1672.c by Alessandro Zummo <a.zummo@towertech.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.
+ */
+
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+
+/* Registers */
+#define EM3027_REG_ON_OFF_CTRL 0x00
+#define EM3027_REG_IRQ_CTRL 0x01
+#define EM3027_REG_IRQ_FLAGS 0x02
+#define EM3027_REG_STATUS 0x03
+#define EM3027_REG_RST_CTRL 0x04
+
+#define EM3027_REG_WATCH_SEC 0x08
+#define EM3027_REG_WATCH_MIN 0x09
+#define EM3027_REG_WATCH_HOUR 0x0a
+#define EM3027_REG_WATCH_DATE 0x0b
+#define EM3027_REG_WATCH_DAY 0x0c
+#define EM3027_REG_WATCH_MON 0x0d
+#define EM3027_REG_WATCH_YEAR 0x0e
+
+#define EM3027_REG_ALARM_SEC 0x10
+#define EM3027_REG_ALARM_MIN 0x11
+#define EM3027_REG_ALARM_HOUR 0x12
+#define EM3027_REG_ALARM_DATE 0x13
+#define EM3027_REG_ALARM_DAY 0x14
+#define EM3027_REG_ALARM_MON 0x15
+#define EM3027_REG_ALARM_YEAR 0x16
+
+static struct i2c_driver em3027_driver;
+
+static int em3027_get_time(struct device *dev, struct rtc_time *tm)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ unsigned char addr = EM3027_REG_WATCH_SEC;
+ unsigned char buf[7];
+
+ struct i2c_msg msgs[] = {
+ {client->addr, 0, 1, &addr}, /* setup read addr */
+ {client->addr, I2C_M_RD, 7, buf}, /* read time/date */
+ };
+
+ /* read time/date registers */
+ if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+ dev_err(&client->dev, "%s: read error\n", __func__);
+ return -EIO;
+ }
+
+ tm->tm_sec = bcd2bin(buf[0]);
+ tm->tm_min = bcd2bin(buf[1]);
+ tm->tm_hour = bcd2bin(buf[2]);
+ tm->tm_mday = bcd2bin(buf[3]);
+ tm->tm_wday = bcd2bin(buf[4]);
+ tm->tm_mon = bcd2bin(buf[5]);
+ tm->tm_year = bcd2bin(buf[6]) + 100;
+
+ return 0;
+}
+
+static int em3027_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ unsigned char buf[8];
+
+ struct i2c_msg msg = {
+ client->addr, 0, 8, buf, /* write time/date */
+ };
+
+ buf[0] = EM3027_REG_WATCH_SEC;
+ buf[1] = bin2bcd(tm->tm_sec);
+ buf[2] = bin2bcd(tm->tm_min);
+ buf[3] = bin2bcd(tm->tm_hour);
+ buf[4] = bin2bcd(tm->tm_mday);
+ buf[5] = bin2bcd(tm->tm_wday);
+ buf[6] = bin2bcd(tm->tm_mon);
+ buf[7] = bin2bcd(tm->tm_year % 100);
+
+ /* write time/date registers */
+ if ((i2c_transfer(client->adapter, &msg, 1)) != 1) {
+ dev_err(&client->dev, "%s: write error\n", __func__);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static const struct rtc_class_ops em3027_rtc_ops = {
+ .read_time = em3027_get_time,
+ .set_time = em3027_set_time,
+};
+
+static int em3027_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct rtc_device *rtc;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ return -ENODEV;
+
+ rtc = rtc_device_register(em3027_driver.driver.name, &client->dev,
+ &em3027_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
+
+ i2c_set_clientdata(client, rtc);
+
+ return 0;
+}
+
+static int em3027_remove(struct i2c_client *client)
+{
+ struct rtc_device *rtc = i2c_get_clientdata(client);
+
+ if (rtc)
+ rtc_device_unregister(rtc);
+
+ return 0;
+}
+
+static struct i2c_device_id em3027_id[] = {
+ { "em3027", 0 },
+ { }
+};
+
+static struct i2c_driver em3027_driver = {
+ .driver = {
+ .name = "rtc-em3027",
+ },
+ .probe = &em3027_probe,
+ .remove = &em3027_remove,
+ .id_table = em3027_id,
+};
+
+static int __init em3027_init(void)
+{
+ return i2c_add_driver(&em3027_driver);
+}
+
+static void __exit em3027_exit(void)
+{
+ i2c_del_driver(&em3027_driver);
+}
+
+MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
+MODULE_DESCRIPTION("EM Microelectronic EM3027 RTC driver");
+MODULE_LICENSE("GPL");
+
+module_init(em3027_init);
+module_exit(em3027_exit);
diff --git a/drivers/rtc/rtc-m41t93.c b/drivers/rtc/rtc-m41t93.c
new file mode 100644
index 000000000000..1a84b3e227d1
--- /dev/null
+++ b/drivers/rtc/rtc-m41t93.c
@@ -0,0 +1,225 @@
+/*
+ *
+ * Driver for ST M41T93 SPI RTC
+ *
+ * (c) 2010 Nikolaus Voss, Weinmann Medical GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bcd.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/spi/spi.h>
+
+#define M41T93_REG_SSEC 0
+#define M41T93_REG_ST_SEC 1
+#define M41T93_REG_MIN 2
+#define M41T93_REG_CENT_HOUR 3
+#define M41T93_REG_WDAY 4
+#define M41T93_REG_DAY 5
+#define M41T93_REG_MON 6
+#define M41T93_REG_YEAR 7
+
+
+#define M41T93_REG_ALM_HOUR_HT 0xc
+#define M41T93_REG_FLAGS 0xf
+
+#define M41T93_FLAG_ST (1 << 7)
+#define M41T93_FLAG_OF (1 << 2)
+#define M41T93_FLAG_BL (1 << 4)
+#define M41T93_FLAG_HT (1 << 6)
+
+static inline int m41t93_set_reg(struct spi_device *spi, u8 addr, u8 data)
+{
+ u8 buf[2];
+
+ /* MSB must be '1' to write */
+ buf[0] = addr | 0x80;
+ buf[1] = data;
+
+ return spi_write(spi, buf, sizeof(buf));
+}
+
+static int m41t93_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ u8 buf[9] = {0x80}; /* write cmd + 8 data bytes */
+ u8 * const data = &buf[1]; /* ptr to first data byte */
+
+ dev_dbg(dev, "%s secs=%d, mins=%d, "
+ "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
+ "write", tm->tm_sec, tm->tm_min,
+ tm->tm_hour, tm->tm_mday,
+ tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+ if (tm->tm_year < 100) {
+ dev_warn(&spi->dev, "unsupported date (before 2000-01-01).\n");
+ return -EINVAL;
+ }
+
+ data[M41T93_REG_SSEC] = 0;
+ data[M41T93_REG_ST_SEC] = bin2bcd(tm->tm_sec);
+ data[M41T93_REG_MIN] = bin2bcd(tm->tm_min);
+ data[M41T93_REG_CENT_HOUR] = bin2bcd(tm->tm_hour) |
+ ((tm->tm_year/100-1) << 6);
+ data[M41T93_REG_DAY] = bin2bcd(tm->tm_mday);
+ data[M41T93_REG_WDAY] = bin2bcd(tm->tm_wday + 1);
+ data[M41T93_REG_MON] = bin2bcd(tm->tm_mon + 1);
+ data[M41T93_REG_YEAR] = bin2bcd(tm->tm_year % 100);
+
+ return spi_write(spi, buf, sizeof(buf));
+}
+
+
+static int m41t93_get_time(struct device *dev, struct rtc_time *tm)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ const u8 start_addr = 0;
+ u8 buf[8];
+ int century_after_1900;
+ int tmp;
+ int ret = 0;
+
+ /* Check status of clock. Two states must be considered:
+ 1. halt bit (HT) is set: the clock is running but update of readout
+ registers has been disabled due to power failure. This is normal
+ case after poweron. Time is valid after resetting HT bit.
+ 2. oscillator fail bit (OF) is set. Oscillator has be stopped and
+ time is invalid:
+ a) OF can be immeditely reset.
+ b) OF cannot be immediately reset: oscillator has to be restarted.
+ */
+ tmp = spi_w8r8(spi, M41T93_REG_ALM_HOUR_HT);
+ if (tmp < 0)
+ return tmp;
+
+ if (tmp & M41T93_FLAG_HT) {
+ dev_dbg(&spi->dev, "HT bit is set, reenable clock update.\n");
+ m41t93_set_reg(spi, M41T93_REG_ALM_HOUR_HT,
+ tmp & ~M41T93_FLAG_HT);
+ }
+
+ tmp = spi_w8r8(spi, M41T93_REG_FLAGS);
+ if (tmp < 0)
+ return tmp;
+
+ if (tmp & M41T93_FLAG_OF) {
+ ret = -EINVAL;
+ dev_warn(&spi->dev, "OF bit is set, resetting.\n");
+ m41t93_set_reg(spi, M41T93_REG_FLAGS, tmp & ~M41T93_FLAG_OF);
+
+ tmp = spi_w8r8(spi, M41T93_REG_FLAGS);
+ if (tmp < 0)
+ return tmp;
+ else if (tmp & M41T93_FLAG_OF) {
+ u8 reset_osc = buf[M41T93_REG_ST_SEC] | M41T93_FLAG_ST;
+
+ dev_warn(&spi->dev,
+ "OF bit is still set, kickstarting clock.\n");
+ m41t93_set_reg(spi, M41T93_REG_ST_SEC, reset_osc);
+ reset_osc &= ~M41T93_FLAG_ST;
+ m41t93_set_reg(spi, M41T93_REG_ST_SEC, reset_osc);
+ }
+ }
+
+ if (tmp & M41T93_FLAG_BL)
+ dev_warn(&spi->dev, "BL bit is set, replace battery.\n");
+
+ /* read actual time/date */
+ tmp = spi_write_then_read(spi, &start_addr, 1, buf, sizeof(buf));
+ if (tmp < 0)
+ return tmp;
+
+ tm->tm_sec = bcd2bin(buf[M41T93_REG_ST_SEC]);
+ tm->tm_min = bcd2bin(buf[M41T93_REG_MIN]);
+ tm->tm_hour = bcd2bin(buf[M41T93_REG_CENT_HOUR] & 0x3f);
+ tm->tm_mday = bcd2bin(buf[M41T93_REG_DAY]);
+ tm->tm_mon = bcd2bin(buf[M41T93_REG_MON]) - 1;
+ tm->tm_wday = bcd2bin(buf[M41T93_REG_WDAY] & 0x0f) - 1;
+
+ century_after_1900 = (buf[M41T93_REG_CENT_HOUR] >> 6) + 1;
+ tm->tm_year = bcd2bin(buf[M41T93_REG_YEAR]) + century_after_1900 * 100;
+
+ dev_dbg(dev, "%s secs=%d, mins=%d, "
+ "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
+ "read", tm->tm_sec, tm->tm_min,
+ tm->tm_hour, tm->tm_mday,
+ tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+ return ret < 0 ? ret : rtc_valid_tm(tm);
+}
+
+
+static const struct rtc_class_ops m41t93_rtc_ops = {
+ .read_time = m41t93_get_time,
+ .set_time = m41t93_set_time,
+};
+
+static struct spi_driver m41t93_driver;
+
+static int __devinit m41t93_probe(struct spi_device *spi)
+{
+ struct rtc_device *rtc;
+ int res;
+
+ spi->bits_per_word = 8;
+ spi_setup(spi);
+
+ res = spi_w8r8(spi, M41T93_REG_WDAY);
+ if (res < 0 || (res & 0xf8) != 0) {
+ dev_err(&spi->dev, "not found 0x%x.\n", res);
+ return -ENODEV;
+ }
+
+ rtc = rtc_device_register(m41t93_driver.driver.name,
+ &spi->dev, &m41t93_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
+
+ dev_set_drvdata(&spi->dev, rtc);
+
+ return 0;
+}
+
+
+static int __devexit m41t93_remove(struct spi_device *spi)
+{
+ struct rtc_device *rtc = platform_get_drvdata(spi);
+
+ if (rtc)
+ rtc_device_unregister(rtc);
+
+ return 0;
+}
+
+static struct spi_driver m41t93_driver = {
+ .driver = {
+ .name = "rtc-m41t93",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = m41t93_probe,
+ .remove = __devexit_p(m41t93_remove),
+};
+
+static __init int m41t93_init(void)
+{
+ return spi_register_driver(&m41t93_driver);
+}
+module_init(m41t93_init);
+
+static __exit void m41t93_exit(void)
+{
+ spi_unregister_driver(&m41t93_driver);
+}
+module_exit(m41t93_exit);
+
+MODULE_AUTHOR("Nikolaus Voss <n.voss@weinmann.de>");
+MODULE_DESCRIPTION("Driver for ST M41T93 SPI RTC");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:rtc-m41t93");
diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c
index b2f096871a97..0cec5650d56a 100644
--- a/drivers/rtc/rtc-mrst.c
+++ b/drivers/rtc/rtc-mrst.c
@@ -380,7 +380,7 @@ cleanup1:
cleanup0:
dev_set_drvdata(dev, NULL);
mrst_rtc.dev = NULL;
- release_region(iomem->start, iomem->end + 1 - iomem->start);
+ release_mem_region(iomem->start, resource_size(iomem));
dev_err(dev, "rtc-mrst: unable to initialise\n");
return retval;
}
@@ -406,7 +406,7 @@ static void __devexit rtc_mrst_do_remove(struct device *dev)
mrst->rtc = NULL;
iomem = mrst->iomem;
- release_region(iomem->start, iomem->end + 1 - iomem->start);
+ release_mem_region(iomem->start, resource_size(iomem));
mrst->iomem = NULL;
mrst->dev = NULL;
diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c
index d814417bee8c..39e41fbdf08b 100644
--- a/drivers/rtc/rtc-mxc.c
+++ b/drivers/rtc/rtc-mxc.c
@@ -55,12 +55,6 @@ static const u32 PIE_BIT_DEF[MAX_PIE_NUM][2] = {
{ MAX_PIE_FREQ, RTC_SAM7_BIT },
};
-/* Those are the bits from a classic RTC we want to mimic */
-#define RTC_IRQF 0x80 /* any of the following 3 is active */
-#define RTC_PF 0x40 /* Periodic interrupt */
-#define RTC_AF 0x20 /* Alarm interrupt */
-#define RTC_UF 0x10 /* Update interrupt for 1Hz RTC */
-
#define MXC_RTC_TIME 0
#define MXC_RTC_ALARM 1
diff --git a/drivers/rtc/rtc-pcf50633.c b/drivers/rtc/rtc-pcf50633.c
index f90c574f9d05..0c423892923c 100644
--- a/drivers/rtc/rtc-pcf50633.c
+++ b/drivers/rtc/rtc-pcf50633.c
@@ -58,7 +58,6 @@ struct pcf50633_time {
struct pcf50633_rtc {
int alarm_enabled;
- int second_enabled;
int alarm_pending;
struct pcf50633 *pcf;
@@ -143,7 +142,7 @@ static int pcf50633_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct pcf50633_rtc *rtc;
struct pcf50633_time pcf_tm;
- int second_masked, alarm_masked, ret = 0;
+ int alarm_masked, ret = 0;
rtc = dev_get_drvdata(dev);
@@ -162,11 +161,8 @@ static int pcf50633_rtc_set_time(struct device *dev, struct rtc_time *tm)
pcf_tm.time[PCF50633_TI_SEC]);
- second_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_SECOND);
alarm_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_ALARM);
- if (!second_masked)
- pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_SECOND);
if (!alarm_masked)
pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM);
@@ -175,8 +171,6 @@ static int pcf50633_rtc_set_time(struct device *dev, struct rtc_time *tm)
PCF50633_TI_EXTENT,
&pcf_tm.time[0]);
- if (!second_masked)
- pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_SECOND);
if (!alarm_masked)
pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM);
@@ -250,15 +244,8 @@ static void pcf50633_rtc_irq(int irq, void *data)
{
struct pcf50633_rtc *rtc = data;
- switch (irq) {
- case PCF50633_IRQ_ALARM:
- rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
- rtc->alarm_pending = 1;
- break;
- case PCF50633_IRQ_SECOND:
- rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF);
- break;
- }
+ rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
+ rtc->alarm_pending = 1;
}
static int __devinit pcf50633_rtc_probe(struct platform_device *pdev)
@@ -282,9 +269,6 @@ static int __devinit pcf50633_rtc_probe(struct platform_device *pdev)
pcf50633_register_irq(rtc->pcf, PCF50633_IRQ_ALARM,
pcf50633_rtc_irq, rtc);
- pcf50633_register_irq(rtc->pcf, PCF50633_IRQ_SECOND,
- pcf50633_rtc_irq, rtc);
-
return 0;
}
@@ -295,7 +279,6 @@ static int __devexit pcf50633_rtc_remove(struct platform_device *pdev)
rtc = platform_get_drvdata(pdev);
pcf50633_free_irq(rtc->pcf, PCF50633_IRQ_ALARM);
- pcf50633_free_irq(rtc->pcf, PCF50633_IRQ_SECOND);
rtc_device_unregister(rtc->rtc_dev);
kfree(rtc);
diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c
new file mode 100644
index 000000000000..ea09ff211dc6
--- /dev/null
+++ b/drivers/rtc/rtc-rv3029c2.c
@@ -0,0 +1,454 @@
+/*
+ * Micro Crystal RV-3029C2 rtc class driver
+ *
+ * Author: Gregory Hermant <gregory.hermant@calao-systems.com>
+ *
+ * based on previously existing rtc class drivers
+ *
+ * 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.
+ *
+ * NOTE: Currently this driver only supports the bare minimum for read
+ * and write the RTC and alarms. The extra features provided by this chip
+ * (trickle charger, eeprom, T° compensation) are unavailable.
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/bcd.h>
+#include <linux/rtc.h>
+
+/* Register map */
+/* control section */
+#define RV3029C2_ONOFF_CTRL 0x00
+#define RV3029C2_IRQ_CTRL 0x01
+#define RV3029C2_IRQ_CTRL_AIE (1 << 0)
+#define RV3029C2_IRQ_FLAGS 0x02
+#define RV3029C2_IRQ_FLAGS_AF (1 << 0)
+#define RV3029C2_STATUS 0x03
+#define RV3029C2_STATUS_VLOW1 (1 << 2)
+#define RV3029C2_STATUS_VLOW2 (1 << 3)
+#define RV3029C2_STATUS_SR (1 << 4)
+#define RV3029C2_STATUS_PON (1 << 5)
+#define RV3029C2_STATUS_EEBUSY (1 << 7)
+#define RV3029C2_RST_CTRL 0x04
+#define RV3029C2_CONTROL_SECTION_LEN 0x05
+
+/* watch section */
+#define RV3029C2_W_SEC 0x08
+#define RV3029C2_W_MINUTES 0x09
+#define RV3029C2_W_HOURS 0x0A
+#define RV3029C2_REG_HR_12_24 (1<<6) /* 24h/12h mode */
+#define RV3029C2_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */
+#define RV3029C2_W_DATE 0x0B
+#define RV3029C2_W_DAYS 0x0C
+#define RV3029C2_W_MONTHS 0x0D
+#define RV3029C2_W_YEARS 0x0E
+#define RV3029C2_WATCH_SECTION_LEN 0x07
+
+/* alarm section */
+#define RV3029C2_A_SC 0x10
+#define RV3029C2_A_MN 0x11
+#define RV3029C2_A_HR 0x12
+#define RV3029C2_A_DT 0x13
+#define RV3029C2_A_DW 0x14
+#define RV3029C2_A_MO 0x15
+#define RV3029C2_A_YR 0x16
+#define RV3029C2_ALARM_SECTION_LEN 0x07
+
+/* timer section */
+#define RV3029C2_TIMER_LOW 0x18
+#define RV3029C2_TIMER_HIGH 0x19
+
+/* temperature section */
+#define RV3029C2_TEMP_PAGE 0x20
+
+/* eeprom data section */
+#define RV3029C2_E2P_EEDATA1 0x28
+#define RV3029C2_E2P_EEDATA2 0x29
+
+/* eeprom control section */
+#define RV3029C2_CONTROL_E2P_EECTRL 0x30
+#define RV3029C2_TRICKLE_1K (1<<0) /* 1K resistance */
+#define RV3029C2_TRICKLE_5K (1<<1) /* 5K resistance */
+#define RV3029C2_TRICKLE_20K (1<<2) /* 20K resistance */
+#define RV3029C2_TRICKLE_80K (1<<3) /* 80K resistance */
+#define RV3029C2_CONTROL_E2P_XTALOFFSET 0x31
+#define RV3029C2_CONTROL_E2P_QCOEF 0x32
+#define RV3029C2_CONTROL_E2P_TURNOVER 0x33
+
+/* user ram section */
+#define RV3029C2_USR1_RAM_PAGE 0x38
+#define RV3029C2_USR1_SECTION_LEN 0x04
+#define RV3029C2_USR2_RAM_PAGE 0x3C
+#define RV3029C2_USR2_SECTION_LEN 0x04
+
+static int
+rv3029c2_i2c_read_regs(struct i2c_client *client, u8 reg, u8 *buf,
+ unsigned len)
+{
+ int ret;
+
+ if ((reg > RV3029C2_USR1_RAM_PAGE + 7) ||
+ (reg + len > RV3029C2_USR1_RAM_PAGE + 8))
+ return -EINVAL;
+
+ ret = i2c_smbus_read_i2c_block_data(client, reg, len, buf);
+ if (ret < 0)
+ return ret;
+ if (ret < len)
+ return -EIO;
+ return 0;
+}
+
+static int
+rv3029c2_i2c_write_regs(struct i2c_client *client, u8 reg, u8 const buf[],
+ unsigned len)
+{
+ if ((reg > RV3029C2_USR1_RAM_PAGE + 7) ||
+ (reg + len > RV3029C2_USR1_RAM_PAGE + 8))
+ return -EINVAL;
+
+ return i2c_smbus_write_i2c_block_data(client, reg, len, buf);
+}
+
+static int
+rv3029c2_i2c_get_sr(struct i2c_client *client, u8 *buf)
+{
+ int ret = rv3029c2_i2c_read_regs(client, RV3029C2_STATUS, buf, 1);
+
+ if (ret < 0)
+ return -EIO;
+ dev_dbg(&client->dev, "status = 0x%.2x (%d)\n", buf[0], buf[0]);
+ return 0;
+}
+
+static int
+rv3029c2_i2c_set_sr(struct i2c_client *client, u8 val)
+{
+ u8 buf[1];
+ int sr;
+
+ buf[0] = val;
+ sr = rv3029c2_i2c_write_regs(client, RV3029C2_STATUS, buf, 1);
+ dev_dbg(&client->dev, "status = 0x%.2x (%d)\n", buf[0], buf[0]);
+ if (sr < 0)
+ return -EIO;
+ return 0;
+}
+
+static int
+rv3029c2_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
+{
+ u8 buf[1];
+ int ret;
+ u8 regs[RV3029C2_WATCH_SECTION_LEN] = { 0, };
+
+ ret = rv3029c2_i2c_get_sr(client, buf);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s: reading SR failed\n", __func__);
+ return -EIO;
+ }
+
+ ret = rv3029c2_i2c_read_regs(client, RV3029C2_W_SEC , regs,
+ RV3029C2_WATCH_SECTION_LEN);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s: reading RTC section failed\n",
+ __func__);
+ return ret;
+ }
+
+ tm->tm_sec = bcd2bin(regs[RV3029C2_W_SEC-RV3029C2_W_SEC]);
+ tm->tm_min = bcd2bin(regs[RV3029C2_W_MINUTES-RV3029C2_W_SEC]);
+
+ /* HR field has a more complex interpretation */
+ {
+ const u8 _hr = regs[RV3029C2_W_HOURS-RV3029C2_W_SEC];
+ if (_hr & RV3029C2_REG_HR_12_24) {
+ /* 12h format */
+ tm->tm_hour = bcd2bin(_hr & 0x1f);
+ if (_hr & RV3029C2_REG_HR_PM) /* PM flag set */
+ tm->tm_hour += 12;
+ } else /* 24h format */
+ tm->tm_hour = bcd2bin(_hr & 0x3f);
+ }
+
+ tm->tm_mday = bcd2bin(regs[RV3029C2_W_DATE-RV3029C2_W_SEC]);
+ tm->tm_mon = bcd2bin(regs[RV3029C2_W_MONTHS-RV3029C2_W_SEC]) - 1;
+ tm->tm_year = bcd2bin(regs[RV3029C2_W_YEARS-RV3029C2_W_SEC]) + 100;
+ tm->tm_wday = bcd2bin(regs[RV3029C2_W_DAYS-RV3029C2_W_SEC]) - 1;
+
+ return 0;
+}
+
+static int rv3029c2_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ return rv3029c2_i2c_read_time(to_i2c_client(dev), tm);
+}
+
+static int
+rv3029c2_i2c_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alarm)
+{
+ struct rtc_time *const tm = &alarm->time;
+ int ret;
+ u8 regs[8];
+
+ ret = rv3029c2_i2c_get_sr(client, regs);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s: reading SR failed\n", __func__);
+ return -EIO;
+ }
+
+ ret = rv3029c2_i2c_read_regs(client, RV3029C2_A_SC, regs,
+ RV3029C2_ALARM_SECTION_LEN);
+
+ if (ret < 0) {
+ dev_err(&client->dev, "%s: reading alarm section failed\n",
+ __func__);
+ return ret;
+ }
+
+ tm->tm_sec = bcd2bin(regs[RV3029C2_A_SC-RV3029C2_A_SC] & 0x7f);
+ tm->tm_min = bcd2bin(regs[RV3029C2_A_MN-RV3029C2_A_SC] & 0x7f);
+ tm->tm_hour = bcd2bin(regs[RV3029C2_A_HR-RV3029C2_A_SC] & 0x3f);
+ tm->tm_mday = bcd2bin(regs[RV3029C2_A_DT-RV3029C2_A_SC] & 0x3f);
+ tm->tm_mon = bcd2bin(regs[RV3029C2_A_MO-RV3029C2_A_SC] & 0x1f) - 1;
+ tm->tm_year = bcd2bin(regs[RV3029C2_A_YR-RV3029C2_A_SC] & 0x7f) + 100;
+ tm->tm_wday = bcd2bin(regs[RV3029C2_A_DW-RV3029C2_A_SC] & 0x07) - 1;
+
+ return 0;
+}
+
+static int
+rv3029c2_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ return rv3029c2_i2c_read_alarm(to_i2c_client(dev), alarm);
+}
+
+static int rv3029c2_rtc_i2c_alarm_set_irq(struct i2c_client *client,
+ int enable)
+{
+ int ret;
+ u8 buf[1];
+
+ /* enable AIE irq */
+ ret = rv3029c2_i2c_read_regs(client, RV3029C2_IRQ_CTRL, buf, 1);
+ if (ret < 0) {
+ dev_err(&client->dev, "can't read INT reg\n");
+ return ret;
+ }
+ if (enable)
+ buf[0] |= RV3029C2_IRQ_CTRL_AIE;
+ else
+ buf[0] &= ~RV3029C2_IRQ_CTRL_AIE;
+
+ ret = rv3029c2_i2c_write_regs(client, RV3029C2_IRQ_CTRL, buf, 1);
+ if (ret < 0) {
+ dev_err(&client->dev, "can't set INT reg\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rv3029c2_rtc_i2c_set_alarm(struct i2c_client *client,
+ struct rtc_wkalrm *alarm)
+{
+ struct rtc_time *const tm = &alarm->time;
+ int ret;
+ u8 regs[8];
+
+ /*
+ * The clock has an 8 bit wide bcd-coded register (they never learn)
+ * for the year. tm_year is an offset from 1900 and we are interested
+ * in the 2000-2099 range, so any value less than 100 is invalid.
+ */
+ if (tm->tm_year < 100)
+ return -EINVAL;
+
+ ret = rv3029c2_i2c_get_sr(client, regs);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s: reading SR failed\n", __func__);
+ return -EIO;
+ }
+ regs[RV3029C2_A_SC-RV3029C2_A_SC] = bin2bcd(tm->tm_sec & 0x7f);
+ regs[RV3029C2_A_MN-RV3029C2_A_SC] = bin2bcd(tm->tm_min & 0x7f);
+ regs[RV3029C2_A_HR-RV3029C2_A_SC] = bin2bcd(tm->tm_hour & 0x3f);
+ regs[RV3029C2_A_DT-RV3029C2_A_SC] = bin2bcd(tm->tm_mday & 0x3f);
+ regs[RV3029C2_A_MO-RV3029C2_A_SC] = bin2bcd((tm->tm_mon & 0x1f) - 1);
+ regs[RV3029C2_A_DW-RV3029C2_A_SC] = bin2bcd((tm->tm_wday & 7) - 1);
+ regs[RV3029C2_A_YR-RV3029C2_A_SC] = bin2bcd((tm->tm_year & 0x7f) - 100);
+
+ ret = rv3029c2_i2c_write_regs(client, RV3029C2_A_SC, regs,
+ RV3029C2_ALARM_SECTION_LEN);
+ if (ret < 0)
+ return ret;
+
+ if (alarm->enabled) {
+ u8 buf[1];
+
+ /* clear AF flag */
+ ret = rv3029c2_i2c_read_regs(client, RV3029C2_IRQ_FLAGS,
+ buf, 1);
+ if (ret < 0) {
+ dev_err(&client->dev, "can't read alarm flag\n");
+ return ret;
+ }
+ buf[0] &= ~RV3029C2_IRQ_FLAGS_AF;
+ ret = rv3029c2_i2c_write_regs(client, RV3029C2_IRQ_FLAGS,
+ buf, 1);
+ if (ret < 0) {
+ dev_err(&client->dev, "can't set alarm flag\n");
+ return ret;
+ }
+ /* enable AIE irq */
+ ret = rv3029c2_rtc_i2c_alarm_set_irq(client, 1);
+ if (ret)
+ return ret;
+
+ dev_dbg(&client->dev, "alarm IRQ armed\n");
+ } else {
+ /* disable AIE irq */
+ ret = rv3029c2_rtc_i2c_alarm_set_irq(client, 1);
+ if (ret)
+ return ret;
+
+ dev_dbg(&client->dev, "alarm IRQ disabled\n");
+ }
+
+ return 0;
+}
+
+static int rv3029c2_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ return rv3029c2_rtc_i2c_set_alarm(to_i2c_client(dev), alarm);
+}
+
+static int
+rv3029c2_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm)
+{
+ u8 regs[8];
+ int ret;
+
+ /*
+ * The clock has an 8 bit wide bcd-coded register (they never learn)
+ * for the year. tm_year is an offset from 1900 and we are interested
+ * in the 2000-2099 range, so any value less than 100 is invalid.
+ */
+ if (tm->tm_year < 100)
+ return -EINVAL;
+
+ regs[RV3029C2_W_SEC-RV3029C2_W_SEC] = bin2bcd(tm->tm_sec);
+ regs[RV3029C2_W_MINUTES-RV3029C2_W_SEC] = bin2bcd(tm->tm_min);
+ regs[RV3029C2_W_HOURS-RV3029C2_W_SEC] = bin2bcd(tm->tm_hour);
+ regs[RV3029C2_W_DATE-RV3029C2_W_SEC] = bin2bcd(tm->tm_mday);
+ regs[RV3029C2_W_MONTHS-RV3029C2_W_SEC] = bin2bcd(tm->tm_mon+1);
+ regs[RV3029C2_W_DAYS-RV3029C2_W_SEC] = bin2bcd((tm->tm_wday & 7)+1);
+ regs[RV3029C2_W_YEARS-RV3029C2_W_SEC] = bin2bcd(tm->tm_year - 100);
+
+ ret = rv3029c2_i2c_write_regs(client, RV3029C2_W_SEC, regs,
+ RV3029C2_WATCH_SECTION_LEN);
+ if (ret < 0)
+ return ret;
+
+ ret = rv3029c2_i2c_get_sr(client, regs);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s: reading SR failed\n", __func__);
+ return ret;
+ }
+ /* clear PON bit */
+ ret = rv3029c2_i2c_set_sr(client, (regs[0] & ~RV3029C2_STATUS_PON));
+ if (ret < 0) {
+ dev_err(&client->dev, "%s: reading SR failed\n", __func__);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rv3029c2_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ return rv3029c2_i2c_set_time(to_i2c_client(dev), tm);
+}
+
+static const struct rtc_class_ops rv3029c2_rtc_ops = {
+ .read_time = rv3029c2_rtc_read_time,
+ .set_time = rv3029c2_rtc_set_time,
+ .read_alarm = rv3029c2_rtc_read_alarm,
+ .set_alarm = rv3029c2_rtc_set_alarm,
+};
+
+static struct i2c_device_id rv3029c2_id[] = {
+ { "rv3029c2", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, rv3029c2_id);
+
+static int __devinit
+rv3029c2_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ struct rtc_device *rtc;
+ int rc = 0;
+ u8 buf[1];
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_EMUL))
+ return -ENODEV;
+
+ rtc = rtc_device_register(client->name,
+ &client->dev, &rv3029c2_rtc_ops,
+ THIS_MODULE);
+
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
+
+ i2c_set_clientdata(client, rtc);
+
+ rc = rv3029c2_i2c_get_sr(client, buf);
+ if (rc < 0) {
+ dev_err(&client->dev, "reading status failed\n");
+ goto exit_unregister;
+ }
+
+ return 0;
+
+exit_unregister:
+ rtc_device_unregister(rtc);
+
+ return rc;
+}
+
+static int __devexit rv3029c2_remove(struct i2c_client *client)
+{
+ struct rtc_device *rtc = i2c_get_clientdata(client);
+
+ rtc_device_unregister(rtc);
+
+ return 0;
+}
+
+static struct i2c_driver rv3029c2_driver = {
+ .driver = {
+ .name = "rtc-rv3029c2",
+ },
+ .probe = rv3029c2_probe,
+ .remove = __devexit_p(rv3029c2_remove),
+ .id_table = rv3029c2_id,
+};
+
+static int __init rv3029c2_init(void)
+{
+ return i2c_add_driver(&rv3029c2_driver);
+}
+
+static void __exit rv3029c2_exit(void)
+{
+ i2c_del_driver(&rv3029c2_driver);
+}
+
+module_init(rv3029c2_init);
+module_exit(rv3029c2_exit);
+
+MODULE_AUTHOR("Gregory Hermant <gregory.hermant@calao-systems.com>");
+MODULE_DESCRIPTION("Micro Crystal RV3029C2 RTC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-spear.c b/drivers/rtc/rtc-spear.c
new file mode 100644
index 000000000000..893bac2bb21b
--- /dev/null
+++ b/drivers/rtc/rtc-spear.c
@@ -0,0 +1,534 @@
+/*
+ * drivers/rtc/rtc-spear.c
+ *
+ * Copyright (C) 2010 ST Microelectronics
+ * Rajeev Kumar<rajeev-dlh.kumar@st.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/bcd.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+/* RTC registers */
+#define TIME_REG 0x00
+#define DATE_REG 0x04
+#define ALARM_TIME_REG 0x08
+#define ALARM_DATE_REG 0x0C
+#define CTRL_REG 0x10
+#define STATUS_REG 0x14
+
+/* TIME_REG & ALARM_TIME_REG */
+#define SECONDS_UNITS (0xf<<0) /* seconds units position */
+#define SECONDS_TENS (0x7<<4) /* seconds tens position */
+#define MINUTES_UNITS (0xf<<8) /* minutes units position */
+#define MINUTES_TENS (0x7<<12) /* minutes tens position */
+#define HOURS_UNITS (0xf<<16) /* hours units position */
+#define HOURS_TENS (0x3<<20) /* hours tens position */
+
+/* DATE_REG & ALARM_DATE_REG */
+#define DAYS_UNITS (0xf<<0) /* days units position */
+#define DAYS_TENS (0x3<<4) /* days tens position */
+#define MONTHS_UNITS (0xf<<8) /* months units position */
+#define MONTHS_TENS (0x1<<12) /* months tens position */
+#define YEARS_UNITS (0xf<<16) /* years units position */
+#define YEARS_TENS (0xf<<20) /* years tens position */
+#define YEARS_HUNDREDS (0xf<<24) /* years hundereds position */
+#define YEARS_MILLENIUMS (0xf<<28) /* years millenium position */
+
+/* MASK SHIFT TIME_REG & ALARM_TIME_REG*/
+#define SECOND_SHIFT 0x00 /* seconds units */
+#define MINUTE_SHIFT 0x08 /* minutes units position */
+#define HOUR_SHIFT 0x10 /* hours units position */
+#define MDAY_SHIFT 0x00 /* Month day shift */
+#define MONTH_SHIFT 0x08 /* Month shift */
+#define YEAR_SHIFT 0x10 /* Year shift */
+
+#define SECOND_MASK 0x7F
+#define MIN_MASK 0x7F
+#define HOUR_MASK 0x3F
+#define DAY_MASK 0x3F
+#define MONTH_MASK 0x7F
+#define YEAR_MASK 0xFFFF
+
+/* date reg equal to time reg, for debug only */
+#define TIME_BYP (1<<9)
+#define INT_ENABLE (1<<31) /* interrupt enable */
+
+/* STATUS_REG */
+#define CLK_UNCONNECTED (1<<0)
+#define PEND_WR_TIME (1<<2)
+#define PEND_WR_DATE (1<<3)
+#define LOST_WR_TIME (1<<4)
+#define LOST_WR_DATE (1<<5)
+#define RTC_INT_MASK (1<<31)
+#define STATUS_BUSY (PEND_WR_TIME | PEND_WR_DATE)
+#define STATUS_FAIL (LOST_WR_TIME | LOST_WR_DATE)
+
+struct spear_rtc_config {
+ struct clk *clk;
+ spinlock_t lock;
+ void __iomem *ioaddr;
+};
+
+static inline void spear_rtc_clear_interrupt(struct spear_rtc_config *config)
+{
+ unsigned int val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&config->lock, flags);
+ val = readl(config->ioaddr + STATUS_REG);
+ val |= RTC_INT_MASK;
+ writel(val, config->ioaddr + STATUS_REG);
+ spin_unlock_irqrestore(&config->lock, flags);
+}
+
+static inline void spear_rtc_enable_interrupt(struct spear_rtc_config *config)
+{
+ unsigned int val;
+
+ val = readl(config->ioaddr + CTRL_REG);
+ if (!(val & INT_ENABLE)) {
+ spear_rtc_clear_interrupt(config);
+ val |= INT_ENABLE;
+ writel(val, config->ioaddr + CTRL_REG);
+ }
+}
+
+static inline void spear_rtc_disable_interrupt(struct spear_rtc_config *config)
+{
+ unsigned int val;
+
+ val = readl(config->ioaddr + CTRL_REG);
+ if (val & INT_ENABLE) {
+ val &= ~INT_ENABLE;
+ writel(val, config->ioaddr + CTRL_REG);
+ }
+}
+
+static inline int is_write_complete(struct spear_rtc_config *config)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&config->lock, flags);
+ if ((readl(config->ioaddr + STATUS_REG)) & STATUS_FAIL)
+ ret = -EIO;
+ spin_unlock_irqrestore(&config->lock, flags);
+
+ return ret;
+}
+
+static void rtc_wait_not_busy(struct spear_rtc_config *config)
+{
+ int status, count = 0;
+ unsigned long flags;
+
+ /* Assuming BUSY may stay active for 80 msec) */
+ for (count = 0; count < 80; count++) {
+ spin_lock_irqsave(&config->lock, flags);
+ status = readl(config->ioaddr + STATUS_REG);
+ spin_unlock_irqrestore(&config->lock, flags);
+ if ((status & STATUS_BUSY) == 0)
+ break;
+ /* check status busy, after each msec */
+ msleep(1);
+ }
+}
+
+static irqreturn_t spear_rtc_irq(int irq, void *dev_id)
+{
+ struct rtc_device *rtc = (struct rtc_device *)dev_id;
+ struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+ unsigned long flags, events = 0;
+ unsigned int irq_data;
+
+ spin_lock_irqsave(&config->lock, flags);
+ irq_data = readl(config->ioaddr + STATUS_REG);
+ spin_unlock_irqrestore(&config->lock, flags);
+
+ if ((irq_data & RTC_INT_MASK)) {
+ spear_rtc_clear_interrupt(config);
+ events = RTC_IRQF | RTC_AF;
+ rtc_update_irq(rtc, 1, events);
+ return IRQ_HANDLED;
+ } else
+ return IRQ_NONE;
+
+}
+
+static int tm2bcd(struct rtc_time *tm)
+{
+ if (rtc_valid_tm(tm) != 0)
+ return -EINVAL;
+ tm->tm_sec = bin2bcd(tm->tm_sec);
+ tm->tm_min = bin2bcd(tm->tm_min);
+ tm->tm_hour = bin2bcd(tm->tm_hour);
+ tm->tm_mday = bin2bcd(tm->tm_mday);
+ tm->tm_mon = bin2bcd(tm->tm_mon + 1);
+ tm->tm_year = bin2bcd(tm->tm_year);
+
+ return 0;
+}
+
+static void bcd2tm(struct rtc_time *tm)
+{
+ tm->tm_sec = bcd2bin(tm->tm_sec);
+ tm->tm_min = bcd2bin(tm->tm_min);
+ tm->tm_hour = bcd2bin(tm->tm_hour);
+ tm->tm_mday = bcd2bin(tm->tm_mday);
+ tm->tm_mon = bcd2bin(tm->tm_mon) - 1;
+ /* epoch == 1900 */
+ tm->tm_year = bcd2bin(tm->tm_year);
+}
+
+/*
+ * spear_rtc_read_time - set the time
+ * @dev: rtc device in use
+ * @tm: holds date and time
+ *
+ * This function read time and date. On success it will return 0
+ * otherwise -ve error is returned.
+ */
+static int spear_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_device *rtc = platform_get_drvdata(pdev);
+ struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+ unsigned int time, date;
+
+ /* we don't report wday/yday/isdst ... */
+ rtc_wait_not_busy(config);
+
+ time = readl(config->ioaddr + TIME_REG);
+ date = readl(config->ioaddr + DATE_REG);
+ tm->tm_sec = (time >> SECOND_SHIFT) & SECOND_MASK;
+ tm->tm_min = (time >> MINUTE_SHIFT) & MIN_MASK;
+ tm->tm_hour = (time >> HOUR_SHIFT) & HOUR_MASK;
+ tm->tm_mday = (date >> MDAY_SHIFT) & DAY_MASK;
+ tm->tm_mon = (date >> MONTH_SHIFT) & MONTH_MASK;
+ tm->tm_year = (date >> YEAR_SHIFT) & YEAR_MASK;
+
+ bcd2tm(tm);
+ return 0;
+}
+
+/*
+ * spear_rtc_set_time - set the time
+ * @dev: rtc device in use
+ * @tm: holds date and time
+ *
+ * This function set time and date. On success it will return 0
+ * otherwise -ve error is returned.
+ */
+static int spear_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_device *rtc = platform_get_drvdata(pdev);
+ struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+ unsigned int time, date, err = 0;
+
+ if (tm2bcd(tm) < 0)
+ return -EINVAL;
+
+ rtc_wait_not_busy(config);
+ time = (tm->tm_sec << SECOND_SHIFT) | (tm->tm_min << MINUTE_SHIFT) |
+ (tm->tm_hour << HOUR_SHIFT);
+ date = (tm->tm_mday << MDAY_SHIFT) | (tm->tm_mon << MONTH_SHIFT) |
+ (tm->tm_year << YEAR_SHIFT);
+ writel(time, config->ioaddr + TIME_REG);
+ writel(date, config->ioaddr + DATE_REG);
+ err = is_write_complete(config);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+/*
+ * spear_rtc_read_alarm - read the alarm time
+ * @dev: rtc device in use
+ * @alm: holds alarm date and time
+ *
+ * This function read alarm time and date. On success it will return 0
+ * otherwise -ve error is returned.
+ */
+static int spear_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_device *rtc = platform_get_drvdata(pdev);
+ struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+ unsigned int time, date;
+
+ rtc_wait_not_busy(config);
+
+ time = readl(config->ioaddr + ALARM_TIME_REG);
+ date = readl(config->ioaddr + ALARM_DATE_REG);
+ alm->time.tm_sec = (time >> SECOND_SHIFT) & SECOND_MASK;
+ alm->time.tm_min = (time >> MINUTE_SHIFT) & MIN_MASK;
+ alm->time.tm_hour = (time >> HOUR_SHIFT) & HOUR_MASK;
+ alm->time.tm_mday = (date >> MDAY_SHIFT) & DAY_MASK;
+ alm->time.tm_mon = (date >> MONTH_SHIFT) & MONTH_MASK;
+ alm->time.tm_year = (date >> YEAR_SHIFT) & YEAR_MASK;
+
+ bcd2tm(&alm->time);
+ alm->enabled = readl(config->ioaddr + CTRL_REG) & INT_ENABLE;
+
+ return 0;
+}
+
+/*
+ * spear_rtc_set_alarm - set the alarm time
+ * @dev: rtc device in use
+ * @alm: holds alarm date and time
+ *
+ * This function set alarm time and date. On success it will return 0
+ * otherwise -ve error is returned.
+ */
+static int spear_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_device *rtc = platform_get_drvdata(pdev);
+ struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+ unsigned int time, date, err = 0;
+
+ if (tm2bcd(&alm->time) < 0)
+ return -EINVAL;
+
+ rtc_wait_not_busy(config);
+
+ time = (alm->time.tm_sec << SECOND_SHIFT) | (alm->time.tm_min <<
+ MINUTE_SHIFT) | (alm->time.tm_hour << HOUR_SHIFT);
+ date = (alm->time.tm_mday << MDAY_SHIFT) | (alm->time.tm_mon <<
+ MONTH_SHIFT) | (alm->time.tm_year << YEAR_SHIFT);
+
+ writel(time, config->ioaddr + ALARM_TIME_REG);
+ writel(date, config->ioaddr + ALARM_DATE_REG);
+ err = is_write_complete(config);
+ if (err < 0)
+ return err;
+
+ if (alm->enabled)
+ spear_rtc_enable_interrupt(config);
+ else
+ spear_rtc_disable_interrupt(config);
+
+ return 0;
+}
+static struct rtc_class_ops spear_rtc_ops = {
+ .read_time = spear_rtc_read_time,
+ .set_time = spear_rtc_set_time,
+ .read_alarm = spear_rtc_read_alarm,
+ .set_alarm = spear_rtc_set_alarm,
+};
+
+static int __devinit spear_rtc_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct rtc_device *rtc;
+ struct spear_rtc_config *config;
+ unsigned int status = 0;
+ int irq;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no resource defined\n");
+ return -EBUSY;
+ }
+ if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
+ dev_err(&pdev->dev, "rtc region already claimed\n");
+ return -EBUSY;
+ }
+
+ config = kzalloc(sizeof(*config), GFP_KERNEL);
+ if (!config) {
+ dev_err(&pdev->dev, "out of memory\n");
+ status = -ENOMEM;
+ goto err_release_region;
+ }
+
+ config->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(config->clk)) {
+ status = PTR_ERR(config->clk);
+ goto err_kfree;
+ }
+
+ status = clk_enable(config->clk);
+ if (status < 0)
+ goto err_clk_put;
+
+ config->ioaddr = ioremap(res->start, resource_size(res));
+ if (!config->ioaddr) {
+ dev_err(&pdev->dev, "ioremap fail\n");
+ status = -ENOMEM;
+ goto err_disable_clock;
+ }
+
+ spin_lock_init(&config->lock);
+
+ rtc = rtc_device_register(pdev->name, &pdev->dev, &spear_rtc_ops,
+ THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
+ PTR_ERR(rtc));
+ status = PTR_ERR(rtc);
+ goto err_iounmap;
+ }
+
+ platform_set_drvdata(pdev, rtc);
+ dev_set_drvdata(&rtc->dev, config);
+
+ /* alarm irqs */
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "no update irq?\n");
+ status = irq;
+ goto err_clear_platdata;
+ }
+
+ status = request_irq(irq, spear_rtc_irq, 0, pdev->name, rtc);
+ if (status) {
+ dev_err(&pdev->dev, "Alarm interrupt IRQ%d already \
+ claimed\n", irq);
+ goto err_clear_platdata;
+ }
+
+ if (!device_can_wakeup(&pdev->dev))
+ device_init_wakeup(&pdev->dev, 1);
+
+ return 0;
+
+err_clear_platdata:
+ platform_set_drvdata(pdev, NULL);
+ dev_set_drvdata(&rtc->dev, NULL);
+ rtc_device_unregister(rtc);
+err_iounmap:
+ iounmap(config->ioaddr);
+err_disable_clock:
+ clk_disable(config->clk);
+err_clk_put:
+ clk_put(config->clk);
+err_kfree:
+ kfree(config);
+err_release_region:
+ release_mem_region(res->start, resource_size(res));
+
+ return status;
+}
+
+static int __devexit spear_rtc_remove(struct platform_device *pdev)
+{
+ struct rtc_device *rtc = platform_get_drvdata(pdev);
+ struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+ int irq;
+ struct resource *res;
+
+ /* leave rtc running, but disable irqs */
+ spear_rtc_disable_interrupt(config);
+ device_init_wakeup(&pdev->dev, 0);
+ irq = platform_get_irq(pdev, 0);
+ if (irq)
+ free_irq(irq, pdev);
+ clk_disable(config->clk);
+ clk_put(config->clk);
+ iounmap(config->ioaddr);
+ kfree(config);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, resource_size(res));
+ platform_set_drvdata(pdev, NULL);
+ dev_set_drvdata(&rtc->dev, NULL);
+ rtc_device_unregister(rtc);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int spear_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct rtc_device *rtc = platform_get_drvdata(pdev);
+ struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+ int irq;
+
+ irq = platform_get_irq(pdev, 0);
+ if (device_may_wakeup(&pdev->dev))
+ enable_irq_wake(irq);
+ else {
+ spear_rtc_disable_interrupt(config);
+ clk_disable(config->clk);
+ }
+
+ return 0;
+}
+
+static int spear_rtc_resume(struct platform_device *pdev)
+{
+ struct rtc_device *rtc = platform_get_drvdata(pdev);
+ struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+ int irq;
+
+ irq = platform_get_irq(pdev, 0);
+
+ if (device_may_wakeup(&pdev->dev))
+ disable_irq_wake(irq);
+ else {
+ clk_enable(config->clk);
+ spear_rtc_enable_interrupt(config);
+ }
+
+ return 0;
+}
+
+#else
+#define spear_rtc_suspend NULL
+#define spear_rtc_resume NULL
+#endif
+
+static void spear_rtc_shutdown(struct platform_device *pdev)
+{
+ struct rtc_device *rtc = platform_get_drvdata(pdev);
+ struct spear_rtc_config *config = dev_get_drvdata(&rtc->dev);
+
+ spear_rtc_disable_interrupt(config);
+ clk_disable(config->clk);
+}
+
+static struct platform_driver spear_rtc_driver = {
+ .probe = spear_rtc_probe,
+ .remove = __devexit_p(spear_rtc_remove),
+ .suspend = spear_rtc_suspend,
+ .resume = spear_rtc_resume,
+ .shutdown = spear_rtc_shutdown,
+ .driver = {
+ .name = "rtc-spear",
+ },
+};
+
+static int __init rtc_init(void)
+{
+ return platform_driver_register(&spear_rtc_driver);
+}
+module_init(rtc_init);
+
+static void __exit rtc_exit(void)
+{
+ platform_driver_unregister(&spear_rtc_driver);
+}
+module_exit(rtc_exit);
+
+MODULE_ALIAS("platform:rtc-spear");
+MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>");
+MODULE_DESCRIPTION("ST SPEAr Realtime Clock Driver (RTC)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-tile.c b/drivers/rtc/rtc-tile.c
new file mode 100644
index 000000000000..eb65dafee66e
--- /dev/null
+++ b/drivers/rtc/rtc-tile.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in 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.
+ *
+ * Tilera-specific RTC driver.
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+
+/* Platform device pointer. */
+static struct platform_device *tile_rtc_platform_device;
+
+/*
+ * RTC read routine. Gets time info from RTC chip via hypervisor syscall.
+ */
+static int read_rtc_time(struct device *dev, struct rtc_time *tm)
+{
+ HV_RTCTime hvtm = hv_get_rtc();
+
+ tm->tm_sec = hvtm.tm_sec;
+ tm->tm_min = hvtm.tm_min;
+ tm->tm_hour = hvtm.tm_hour;
+ tm->tm_mday = hvtm.tm_mday;
+ tm->tm_mon = hvtm.tm_mon;
+ tm->tm_year = hvtm.tm_year;
+ tm->tm_wday = 0;
+ tm->tm_yday = 0;
+ tm->tm_isdst = 0;
+
+ if (rtc_valid_tm(tm) < 0)
+ dev_warn(dev, "Read invalid date/time from RTC\n");
+
+ return 0;
+}
+
+/*
+ * RTC write routine. Sends time info to hypervisor via syscall, to be
+ * written to RTC chip.
+ */
+static int set_rtc_time(struct device *dev, struct rtc_time *tm)
+{
+ HV_RTCTime hvtm;
+
+ hvtm.tm_sec = tm->tm_sec;
+ hvtm.tm_min = tm->tm_min;
+ hvtm.tm_hour = tm->tm_hour;
+ hvtm.tm_mday = tm->tm_mday;
+ hvtm.tm_mon = tm->tm_mon;
+ hvtm.tm_year = tm->tm_year;
+
+ hv_set_rtc(hvtm);
+
+ return 0;
+}
+
+/*
+ * RTC read/write ops.
+ */
+static const struct rtc_class_ops tile_rtc_ops = {
+ .read_time = read_rtc_time,
+ .set_time = set_rtc_time,
+};
+
+/*
+ * Device probe routine.
+ */
+static int __devinit tile_rtc_probe(struct platform_device *dev)
+{
+ struct rtc_device *rtc;
+
+ rtc = rtc_device_register("tile",
+ &dev->dev, &tile_rtc_ops, THIS_MODULE);
+
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
+
+ platform_set_drvdata(dev, rtc);
+
+ return 0;
+}
+
+/*
+ * Device cleanup routine.
+ */
+static int __devexit tile_rtc_remove(struct platform_device *dev)
+{
+ struct rtc_device *rtc = platform_get_drvdata(dev);
+
+ if (rtc)
+ rtc_device_unregister(rtc);
+
+ platform_set_drvdata(dev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver tile_rtc_platform_driver = {
+ .driver = {
+ .name = "rtc-tile",
+ .owner = THIS_MODULE,
+ },
+ .probe = tile_rtc_probe,
+ .remove = __devexit_p(tile_rtc_remove),
+};
+
+/*
+ * Driver init routine.
+ */
+static int __init tile_rtc_driver_init(void)
+{
+ int err;
+
+ err = platform_driver_register(&tile_rtc_platform_driver);
+ if (err)
+ return err;
+
+ tile_rtc_platform_device = platform_device_alloc("rtc-tile", 0);
+ if (tile_rtc_platform_device == NULL) {
+ err = -ENOMEM;
+ goto exit_driver_unregister;
+ }
+
+ err = platform_device_add(tile_rtc_platform_device);
+ if (err)
+ goto exit_device_put;
+
+ return 0;
+
+exit_device_put:
+ platform_device_put(tile_rtc_platform_device);
+
+exit_driver_unregister:
+ platform_driver_unregister(&tile_rtc_platform_driver);
+ return err;
+}
+
+/*
+ * Driver cleanup routine.
+ */
+static void __exit tile_rtc_driver_exit(void)
+{
+ platform_driver_unregister(&tile_rtc_platform_driver);
+}
+
+module_init(tile_rtc_driver_init);
+module_exit(tile_rtc_driver_exit);
+
+MODULE_DESCRIPTION("Tilera-specific Real Time Clock Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:rtc-tile");
diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c
new file mode 100644
index 000000000000..b8bc862903ae
--- /dev/null
+++ b/drivers/rtc/rtc-vt8500.c
@@ -0,0 +1,366 @@
+/*
+ * drivers/rtc/rtc-vt8500.c
+ *
+ * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
+ *
+ * Based on rtc-pxa.c
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/rtc.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/bcd.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+/*
+ * Register definitions
+ */
+#define VT8500_RTC_TS 0x00 /* Time set */
+#define VT8500_RTC_DS 0x04 /* Date set */
+#define VT8500_RTC_AS 0x08 /* Alarm set */
+#define VT8500_RTC_CR 0x0c /* Control */
+#define VT8500_RTC_TR 0x10 /* Time read */
+#define VT8500_RTC_DR 0x14 /* Date read */
+#define VT8500_RTC_WS 0x18 /* Write status */
+#define VT8500_RTC_CL 0x20 /* Calibration */
+#define VT8500_RTC_IS 0x24 /* Interrupt status */
+#define VT8500_RTC_ST 0x28 /* Status */
+
+#define INVALID_TIME_BIT (1 << 31)
+
+#define DATE_CENTURY_S 19
+#define DATE_YEAR_S 11
+#define DATE_YEAR_MASK (0xff << DATE_YEAR_S)
+#define DATE_MONTH_S 6
+#define DATE_MONTH_MASK (0x1f << DATE_MONTH_S)
+#define DATE_DAY_MASK 0x3f
+
+#define TIME_DOW_S 20
+#define TIME_DOW_MASK (0x07 << TIME_DOW_S)
+#define TIME_HOUR_S 14
+#define TIME_HOUR_MASK (0x3f << TIME_HOUR_S)
+#define TIME_MIN_S 7
+#define TIME_MIN_MASK (0x7f << TIME_MIN_S)
+#define TIME_SEC_MASK 0x7f
+
+#define ALARM_DAY_S 20
+#define ALARM_DAY_MASK (0x3f << ALARM_DAY_S)
+
+#define ALARM_DAY_BIT (1 << 29)
+#define ALARM_HOUR_BIT (1 << 28)
+#define ALARM_MIN_BIT (1 << 27)
+#define ALARM_SEC_BIT (1 << 26)
+
+#define ALARM_ENABLE_MASK (ALARM_DAY_BIT \
+ | ALARM_HOUR_BIT \
+ | ALARM_MIN_BIT \
+ | ALARM_SEC_BIT)
+
+#define VT8500_RTC_CR_ENABLE (1 << 0) /* Enable RTC */
+#define VT8500_RTC_CR_24H (1 << 1) /* 24h time format */
+#define VT8500_RTC_CR_SM_ENABLE (1 << 2) /* Enable periodic irqs */
+#define VT8500_RTC_CR_SM_SEC (1 << 3) /* 0: 1Hz/60, 1: 1Hz */
+#define VT8500_RTC_CR_CALIB (1 << 4) /* Enable calibration */
+
+struct vt8500_rtc {
+ void __iomem *regbase;
+ struct resource *res;
+ int irq_alarm;
+ int irq_hz;
+ struct rtc_device *rtc;
+ spinlock_t lock; /* Protects this structure */
+};
+
+static irqreturn_t vt8500_rtc_irq(int irq, void *dev_id)
+{
+ struct vt8500_rtc *vt8500_rtc = dev_id;
+ u32 isr;
+ unsigned long events = 0;
+
+ spin_lock(&vt8500_rtc->lock);
+
+ /* clear interrupt sources */
+ isr = readl(vt8500_rtc->regbase + VT8500_RTC_IS);
+ writel(isr, vt8500_rtc->regbase + VT8500_RTC_IS);
+
+ spin_unlock(&vt8500_rtc->lock);
+
+ if (isr & 1)
+ events |= RTC_AF | RTC_IRQF;
+
+ /* Only second/minute interrupts are supported */
+ if (isr & 2)
+ events |= RTC_UF | RTC_IRQF;
+
+ rtc_update_irq(vt8500_rtc->rtc, 1, events);
+
+ return IRQ_HANDLED;
+}
+
+static int vt8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev);
+ u32 date, time;
+
+ date = readl(vt8500_rtc->regbase + VT8500_RTC_DR);
+ time = readl(vt8500_rtc->regbase + VT8500_RTC_TR);
+
+ tm->tm_sec = bcd2bin(time & TIME_SEC_MASK);
+ tm->tm_min = bcd2bin((time & TIME_MIN_MASK) >> TIME_MIN_S);
+ tm->tm_hour = bcd2bin((time & TIME_HOUR_MASK) >> TIME_HOUR_S);
+ tm->tm_mday = bcd2bin(date & DATE_DAY_MASK);
+ tm->tm_mon = bcd2bin((date & DATE_MONTH_MASK) >> DATE_MONTH_S);
+ tm->tm_year = bcd2bin((date & DATE_YEAR_MASK) >> DATE_YEAR_S)
+ + ((date >> DATE_CENTURY_S) & 1 ? 200 : 100);
+ tm->tm_wday = (time & TIME_DOW_MASK) >> TIME_DOW_S;
+
+ return 0;
+}
+
+static int vt8500_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev);
+
+ if (tm->tm_year < 100) {
+ dev_warn(dev, "Only years 2000-2199 are supported by the "
+ "hardware!\n");
+ return -EINVAL;
+ }
+
+ writel((bin2bcd(tm->tm_year - 100) << DATE_YEAR_S)
+ | (bin2bcd(tm->tm_mon) << DATE_MONTH_S)
+ | (bin2bcd(tm->tm_mday)),
+ vt8500_rtc->regbase + VT8500_RTC_DS);
+ writel((bin2bcd(tm->tm_wday) << TIME_DOW_S)
+ | (bin2bcd(tm->tm_hour) << TIME_HOUR_S)
+ | (bin2bcd(tm->tm_min) << TIME_MIN_S)
+ | (bin2bcd(tm->tm_sec)),
+ vt8500_rtc->regbase + VT8500_RTC_TS);
+
+ return 0;
+}
+
+static int vt8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev);
+ u32 isr, alarm;
+
+ alarm = readl(vt8500_rtc->regbase + VT8500_RTC_AS);
+ isr = readl(vt8500_rtc->regbase + VT8500_RTC_IS);
+
+ alrm->time.tm_mday = bcd2bin((alarm & ALARM_DAY_MASK) >> ALARM_DAY_S);
+ alrm->time.tm_hour = bcd2bin((alarm & TIME_HOUR_MASK) >> TIME_HOUR_S);
+ alrm->time.tm_min = bcd2bin((alarm & TIME_MIN_MASK) >> TIME_MIN_S);
+ alrm->time.tm_sec = bcd2bin((alarm & TIME_SEC_MASK));
+
+ alrm->enabled = (alarm & ALARM_ENABLE_MASK) ? 1 : 0;
+
+ alrm->pending = (isr & 1) ? 1 : 0;
+ return rtc_valid_tm(&alrm->time);
+}
+
+static int vt8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev);
+
+ writel((alrm->enabled ? ALARM_ENABLE_MASK : 0)
+ | (bin2bcd(alrm->time.tm_mday) << ALARM_DAY_S)
+ | (bin2bcd(alrm->time.tm_hour) << TIME_HOUR_S)
+ | (bin2bcd(alrm->time.tm_min) << TIME_MIN_S)
+ | (bin2bcd(alrm->time.tm_sec)),
+ vt8500_rtc->regbase + VT8500_RTC_AS);
+
+ return 0;
+}
+
+static int vt8500_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev);
+ unsigned long tmp = readl(vt8500_rtc->regbase + VT8500_RTC_AS);
+
+ if (enabled)
+ tmp |= ALARM_ENABLE_MASK;
+ else
+ tmp &= ~ALARM_ENABLE_MASK;
+
+ writel(tmp, vt8500_rtc->regbase + VT8500_RTC_AS);
+ return 0;
+}
+
+static int vt8500_update_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev);
+ unsigned long tmp = readl(vt8500_rtc->regbase + VT8500_RTC_CR);
+
+ if (enabled)
+ tmp |= VT8500_RTC_CR_SM_SEC | VT8500_RTC_CR_SM_ENABLE;
+ else
+ tmp &= ~VT8500_RTC_CR_SM_ENABLE;
+
+ writel(tmp, vt8500_rtc->regbase + VT8500_RTC_CR);
+ return 0;
+}
+
+static const struct rtc_class_ops vt8500_rtc_ops = {
+ .read_time = vt8500_rtc_read_time,
+ .set_time = vt8500_rtc_set_time,
+ .read_alarm = vt8500_rtc_read_alarm,
+ .set_alarm = vt8500_rtc_set_alarm,
+ .alarm_irq_enable = vt8500_alarm_irq_enable,
+ .update_irq_enable = vt8500_update_irq_enable,
+};
+
+static int __devinit vt8500_rtc_probe(struct platform_device *pdev)
+{
+ struct vt8500_rtc *vt8500_rtc;
+ int ret;
+
+ vt8500_rtc = kzalloc(sizeof(struct vt8500_rtc), GFP_KERNEL);
+ if (!vt8500_rtc)
+ return -ENOMEM;
+
+ spin_lock_init(&vt8500_rtc->lock);
+ platform_set_drvdata(pdev, vt8500_rtc);
+
+ vt8500_rtc->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!vt8500_rtc->res) {
+ dev_err(&pdev->dev, "No I/O memory resource defined\n");
+ ret = -ENXIO;
+ goto err_free;
+ }
+
+ vt8500_rtc->irq_alarm = platform_get_irq(pdev, 0);
+ if (vt8500_rtc->irq_alarm < 0) {
+ dev_err(&pdev->dev, "No alarm IRQ resource defined\n");
+ ret = -ENXIO;
+ goto err_free;
+ }
+
+ vt8500_rtc->irq_hz = platform_get_irq(pdev, 1);
+ if (vt8500_rtc->irq_hz < 0) {
+ dev_err(&pdev->dev, "No 1Hz IRQ resource defined\n");
+ ret = -ENXIO;
+ goto err_free;
+ }
+
+ vt8500_rtc->res = request_mem_region(vt8500_rtc->res->start,
+ resource_size(vt8500_rtc->res),
+ "vt8500-rtc");
+ if (vt8500_rtc->res == NULL) {
+ dev_err(&pdev->dev, "failed to request I/O memory\n");
+ ret = -EBUSY;
+ goto err_free;
+ }
+
+ vt8500_rtc->regbase = ioremap(vt8500_rtc->res->start,
+ resource_size(vt8500_rtc->res));
+ if (!vt8500_rtc->regbase) {
+ dev_err(&pdev->dev, "Unable to map RTC I/O memory\n");
+ ret = -EBUSY;
+ goto err_release;
+ }
+
+ /* Enable the second/minute interrupt generation and enable RTC */
+ writel(VT8500_RTC_CR_ENABLE | VT8500_RTC_CR_24H
+ | VT8500_RTC_CR_SM_ENABLE | VT8500_RTC_CR_SM_SEC,
+ vt8500_rtc->regbase + VT8500_RTC_CR);
+
+ vt8500_rtc->rtc = rtc_device_register("vt8500-rtc", &pdev->dev,
+ &vt8500_rtc_ops, THIS_MODULE);
+ if (IS_ERR(vt8500_rtc->rtc)) {
+ ret = PTR_ERR(vt8500_rtc->rtc);
+ dev_err(&pdev->dev,
+ "Failed to register RTC device -> %d\n", ret);
+ goto err_unmap;
+ }
+
+ ret = request_irq(vt8500_rtc->irq_hz, vt8500_rtc_irq, 0,
+ "rtc 1Hz", vt8500_rtc);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "can't get irq %i, err %d\n",
+ vt8500_rtc->irq_hz, ret);
+ goto err_unreg;
+ }
+
+ ret = request_irq(vt8500_rtc->irq_alarm, vt8500_rtc_irq, 0,
+ "rtc alarm", vt8500_rtc);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "can't get irq %i, err %d\n",
+ vt8500_rtc->irq_alarm, ret);
+ goto err_free_hz;
+ }
+
+ return 0;
+
+err_free_hz:
+ free_irq(vt8500_rtc->irq_hz, vt8500_rtc);
+err_unreg:
+ rtc_device_unregister(vt8500_rtc->rtc);
+err_unmap:
+ iounmap(vt8500_rtc->regbase);
+err_release:
+ release_mem_region(vt8500_rtc->res->start,
+ resource_size(vt8500_rtc->res));
+err_free:
+ kfree(vt8500_rtc);
+ return ret;
+}
+
+static int __devexit vt8500_rtc_remove(struct platform_device *pdev)
+{
+ struct vt8500_rtc *vt8500_rtc = platform_get_drvdata(pdev);
+
+ free_irq(vt8500_rtc->irq_alarm, vt8500_rtc);
+ free_irq(vt8500_rtc->irq_hz, vt8500_rtc);
+
+ rtc_device_unregister(vt8500_rtc->rtc);
+
+ /* Disable alarm matching */
+ writel(0, vt8500_rtc->regbase + VT8500_RTC_IS);
+ iounmap(vt8500_rtc->regbase);
+ release_mem_region(vt8500_rtc->res->start,
+ resource_size(vt8500_rtc->res));
+
+ kfree(vt8500_rtc);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver vt8500_rtc_driver = {
+ .probe = vt8500_rtc_probe,
+ .remove = __devexit_p(vt8500_rtc_remove),
+ .driver = {
+ .name = "vt8500-rtc",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init vt8500_rtc_init(void)
+{
+ return platform_driver_register(&vt8500_rtc_driver);
+}
+module_init(vt8500_rtc_init);
+
+static void __exit vt8500_rtc_exit(void)
+{
+ platform_driver_unregister(&vt8500_rtc_driver);
+}
+module_exit(vt8500_rtc_exit);
+
+MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>");
+MODULE_DESCRIPTION("VIA VT8500 SoC Realtime Clock Driver (RTC)");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:vt8500-rtc");
diff --git a/drivers/s390/block/dasd_alias.c b/drivers/s390/block/dasd_alias.c
index 2b771f18d1ad..c388eda1e2b1 100644
--- a/drivers/s390/block/dasd_alias.c
+++ b/drivers/s390/block/dasd_alias.c
@@ -253,13 +253,11 @@ int dasd_alias_make_device_known_to_lcu(struct dasd_device *device)
*/
void dasd_alias_lcu_setup_complete(struct dasd_device *device)
{
- struct dasd_eckd_private *private;
unsigned long flags;
struct alias_server *server;
struct alias_lcu *lcu;
struct dasd_uid uid;
- private = (struct dasd_eckd_private *) device->private;
device->discipline->get_uid(device, &uid);
lcu = NULL;
spin_lock_irqsave(&aliastree.lock, flags);
@@ -279,13 +277,11 @@ void dasd_alias_lcu_setup_complete(struct dasd_device *device)
void dasd_alias_wait_for_lcu_setup(struct dasd_device *device)
{
- struct dasd_eckd_private *private;
unsigned long flags;
struct alias_server *server;
struct alias_lcu *lcu;
struct dasd_uid uid;
- private = (struct dasd_eckd_private *) device->private;
device->discipline->get_uid(device, &uid);
lcu = NULL;
spin_lock_irqsave(&aliastree.lock, flags);
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index 85dddb1e4126..46784b83c5c4 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -24,7 +24,7 @@
#include <asm/debug.h>
#include <asm/ebcdic.h>
#include <asm/io.h>
-#include <asm/s390_ext.h>
+#include <asm/irq.h>
#include <asm/vtoc.h>
#include <asm/diag.h>
@@ -642,7 +642,7 @@ dasd_diag_init(void)
}
ASCEBC(dasd_diag_discipline.ebcname, 4);
- ctl_set_bit(0, 9);
+ service_subclass_irq_register();
register_external_interrupt(0x2603, dasd_ext_handler);
dasd_diag_discipline_pointer = &dasd_diag_discipline;
return 0;
@@ -652,7 +652,7 @@ static void __exit
dasd_diag_cleanup(void)
{
unregister_external_interrupt(0x2603, dasd_ext_handler);
- ctl_clear_bit(0, 9);
+ service_subclass_irq_unregister();
dasd_diag_discipline_pointer = NULL;
}
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 3ebdf5f92f8f..30fb979d684d 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -1611,10 +1611,8 @@ static void dasd_eckd_analysis_callback(struct dasd_ccw_req *init_cqr,
static int dasd_eckd_start_analysis(struct dasd_block *block)
{
- struct dasd_eckd_private *private;
struct dasd_ccw_req *init_cqr;
- private = (struct dasd_eckd_private *) block->base->private;
init_cqr = dasd_eckd_analysis_ccw(block->base);
if (IS_ERR(init_cqr))
return PTR_ERR(init_cqr);
@@ -2264,7 +2262,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
unsigned int blk_per_trk,
unsigned int blksize)
{
- struct dasd_eckd_private *private;
unsigned long *idaws;
struct dasd_ccw_req *cqr;
struct ccw1 *ccw;
@@ -2283,7 +2280,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
unsigned int recoffs;
basedev = block->base;
- private = (struct dasd_eckd_private *) basedev->private;
if (rq_data_dir(req) == READ)
cmd = DASD_ECKD_CCW_READ_TRACK_DATA;
else if (rq_data_dir(req) == WRITE)
@@ -2556,8 +2552,7 @@ static int prepare_itcw(struct itcw *itcw,
dcw = itcw_add_dcw(itcw, pfx_cmd, 0,
&pfxdata, sizeof(pfxdata), total_data_size);
-
- return rc;
+ return IS_ERR(dcw) ? PTR_ERR(dcw) : 0;
}
static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
@@ -2573,7 +2568,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
unsigned int blk_per_trk,
unsigned int blksize)
{
- struct dasd_eckd_private *private;
struct dasd_ccw_req *cqr;
struct req_iterator iter;
struct bio_vec *bv;
@@ -2594,7 +2588,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
unsigned int count, count_to_trk_end;
basedev = block->base;
- private = (struct dasd_eckd_private *) basedev->private;
if (rq_data_dir(req) == READ) {
cmd = DASD_ECKD_CCW_READ_TRACK_DATA;
itcw_op = ITCW_OP_READ;
@@ -2801,7 +2794,6 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
struct dasd_block *block,
struct request *req)
{
- struct dasd_eckd_private *private;
unsigned long *idaws;
struct dasd_device *basedev;
struct dasd_ccw_req *cqr;
@@ -2836,7 +2828,6 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
trkcount = last_trk - first_trk + 1;
first_offs = 0;
basedev = block->base;
- private = (struct dasd_eckd_private *) basedev->private;
if (rq_data_dir(req) == READ)
cmd = DASD_ECKD_CCW_READ_TRACK;
diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig
index dcee3c5c8954..a4f117d9fdc6 100644
--- a/drivers/s390/char/Kconfig
+++ b/drivers/s390/char/Kconfig
@@ -119,18 +119,6 @@ config S390_TAPE
comment "S/390 tape interface support"
depends on S390_TAPE
-config S390_TAPE_BLOCK
- def_bool y
- prompt "Support for tape block devices"
- depends on S390_TAPE && BLOCK
- help
- Select this option if you want to access your channel-attached tape
- devices using the block device interface. This interface is similar
- to CD-ROM devices on other platforms. The tapes can only be
- accessed read-only when using this interface. Have a look at
- <file:Documentation/s390/TAPE> for further information about creating
- volumes for and using this interface. It is safe to say "Y" here.
-
comment "S/390 tape hardware support"
depends on S390_TAPE
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
index efb500ab66c0..f3c325207445 100644
--- a/drivers/s390/char/Makefile
+++ b/drivers/s390/char/Makefile
@@ -3,7 +3,7 @@
#
obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
- sclp_cmd.o sclp_config.o sclp_cpi_sys.o
+ sclp_cmd.o sclp_config.o sclp_cpi_sys.o sclp_ocf.o
obj-$(CONFIG_TN3270) += raw3270.o
obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
@@ -22,7 +22,6 @@ obj-$(CONFIG_ZVM_WATCHDOG) += vmwatchdog.o
obj-$(CONFIG_VMLOGRDR) += vmlogrdr.o
obj-$(CONFIG_VMCP) += vmcp.o
-tape-$(CONFIG_S390_TAPE_BLOCK) += tape_block.o
tape-$(CONFIG_PROC_FS) += tape_proc.o
tape-objs := tape_core.o tape_std.o tape_char.o $(tape-y)
obj-$(CONFIG_S390_TAPE) += tape.o tape_class.o
diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c
index e0702d3ea33b..4600aa10a1c6 100644
--- a/drivers/s390/char/monwriter.c
+++ b/drivers/s390/char/monwriter.c
@@ -97,7 +97,7 @@ static int monwrite_new_hdr(struct mon_private *monpriv)
{
struct monwrite_hdr *monhdr = &monpriv->hdr;
struct mon_buf *monbuf;
- int rc;
+ int rc = 0;
if (monhdr->datalen > MONWRITE_MAX_DATALEN ||
monhdr->mon_function > MONWRITE_START_CONFIG ||
@@ -135,7 +135,7 @@ static int monwrite_new_hdr(struct mon_private *monpriv)
mon_buf_count++;
}
monpriv->current_buf = monbuf;
- return 0;
+ return rc;
}
static int monwrite_new_data(struct mon_private *monpriv)
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index e21a5c39ef20..810ac38631c3 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -598,7 +598,6 @@ __raw3270_size_device(struct raw3270 *rp)
static const unsigned char wbuf[] =
{ 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 };
struct raw3270_ua *uap;
- unsigned short count;
int rc;
/*
@@ -653,7 +652,6 @@ __raw3270_size_device(struct raw3270 *rp)
if (rc)
return rc;
/* Got a Query Reply */
- count = sizeof(rp->init_data) - rp->init_request.rescnt;
uap = (struct raw3270_ua *) (rp->init_data + 1);
/* Paranoia check. */
if (rp->init_data[0] != 0x88 || uap->uab.qcode != 0x81)
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index b76c61f82485..eaa7e78186f9 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -19,7 +19,6 @@
#include <linux/suspend.h>
#include <linux/completion.h>
#include <linux/platform_device.h>
-#include <asm/s390_ext.h>
#include <asm/types.h>
#include <asm/irq.h>
@@ -885,12 +884,12 @@ sclp_check_interface(void)
spin_unlock_irqrestore(&sclp_lock, flags);
/* Enable service-signal interruption - needs to happen
* with IRQs enabled. */
- ctl_set_bit(0, 9);
+ service_subclass_irq_register();
/* Wait for signal from interrupt or timeout */
sclp_sync_wait();
/* Disable service-signal interruption - needs to happen
* with IRQs enabled. */
- ctl_clear_bit(0,9);
+ service_subclass_irq_unregister();
spin_lock_irqsave(&sclp_lock, flags);
del_timer(&sclp_request_timer);
if (sclp_init_req.status == SCLP_REQ_DONE &&
@@ -1070,7 +1069,7 @@ sclp_init(void)
spin_unlock_irqrestore(&sclp_lock, flags);
/* Enable service-signal external interruption - needs to happen with
* IRQs enabled. */
- ctl_set_bit(0, 9);
+ service_subclass_irq_register();
sclp_init_mask(1);
return 0;
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h
index 6bb5a6bdfab5..49a1bb52bc87 100644
--- a/drivers/s390/char/sclp.h
+++ b/drivers/s390/char/sclp.h
@@ -28,6 +28,7 @@
#define EVTYP_CONFMGMDATA 0x04
#define EVTYP_SDIAS 0x1C
#define EVTYP_ASYNC 0x0A
+#define EVTYP_OCF 0x1E
#define EVTYP_OPCMD_MASK 0x80000000
#define EVTYP_MSG_MASK 0x40000000
@@ -40,6 +41,7 @@
#define EVTYP_CONFMGMDATA_MASK 0x10000000
#define EVTYP_SDIAS_MASK 0x00000010
#define EVTYP_ASYNC_MASK 0x00400000
+#define EVTYP_OCF_MASK 0x00000004
#define GNRLMSGFLGS_DOM 0x8000
#define GNRLMSGFLGS_SNDALRM 0x4000
@@ -186,4 +188,26 @@ sclp_ascebc_str(unsigned char *str, int nr)
(MACHINE_IS_VM) ? ASCEBC(str, nr) : ASCEBC_500(str, nr);
}
+static inline struct gds_vector *
+sclp_find_gds_vector(void *start, void *end, u16 id)
+{
+ struct gds_vector *v;
+
+ for (v = start; (void *) v < end; v = (void *) v + v->length)
+ if (v->gds_id == id)
+ return v;
+ return NULL;
+}
+
+static inline struct gds_subvector *
+sclp_find_gds_subvector(void *start, void *end, u8 key)
+{
+ struct gds_subvector *sv;
+
+ for (sv = start; (void *) sv < end; sv = (void *) sv + sv->length)
+ if (sv->key == key)
+ return sv;
+ return NULL;
+}
+
#endif /* __SCLP_H__ */
diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c
index 16e232a99fb7..95b909ac2b73 100644
--- a/drivers/s390/char/sclp_config.c
+++ b/drivers/s390/char/sclp_config.c
@@ -71,21 +71,9 @@ static struct sclp_register sclp_conf_register =
static int __init sclp_conf_init(void)
{
- int rc;
-
INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify);
INIT_WORK(&sclp_cpu_change_work, sclp_cpu_change_notify);
-
- rc = sclp_register(&sclp_conf_register);
- if (rc)
- return rc;
-
- if (!(sclp_conf_register.sclp_send_mask & EVTYP_CONFMGMDATA_MASK)) {
- pr_warning("no configuration management.\n");
- sclp_unregister(&sclp_conf_register);
- rc = -ENOSYS;
- }
- return rc;
+ return sclp_register(&sclp_conf_register);
}
__initcall(sclp_conf_init);
diff --git a/drivers/s390/char/sclp_ocf.c b/drivers/s390/char/sclp_ocf.c
new file mode 100644
index 000000000000..ab294d5a534e
--- /dev/null
+++ b/drivers/s390/char/sclp_ocf.c
@@ -0,0 +1,145 @@
+/*
+ * drivers/s390/char/sclp_ocf.c
+ * SCLP OCF communication parameters sysfs interface
+ *
+ * Copyright IBM Corp. 2011
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+
+#define KMSG_COMPONENT "sclp_ocf"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/stat.h>
+#include <linux/device.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/kmod.h>
+#include <linux/timer.h>
+#include <linux/err.h>
+#include <asm/ebcdic.h>
+#include <asm/sclp.h>
+
+#include "sclp.h"
+
+#define OCF_LENGTH_HMC_NETWORK 8UL
+#define OCF_LENGTH_CPC_NAME 8UL
+
+static char hmc_network[OCF_LENGTH_HMC_NETWORK + 1];
+static char cpc_name[OCF_LENGTH_CPC_NAME + 1];
+
+static DEFINE_SPINLOCK(sclp_ocf_lock);
+static struct work_struct sclp_ocf_change_work;
+
+static struct kset *ocf_kset;
+
+static void sclp_ocf_change_notify(struct work_struct *work)
+{
+ kobject_uevent(&ocf_kset->kobj, KOBJ_CHANGE);
+}
+
+/* Handler for OCF event. Look for the CPC image name. */
+static void sclp_ocf_handler(struct evbuf_header *evbuf)
+{
+ struct gds_vector *v;
+ struct gds_subvector *sv, *netid, *cpc;
+ size_t size;
+
+ /* Find the 0x9f00 block. */
+ v = sclp_find_gds_vector(evbuf + 1, (void *) evbuf + evbuf->length,
+ 0x9f00);
+ if (!v)
+ return;
+ /* Find the 0x9f22 block inside the 0x9f00 block. */
+ v = sclp_find_gds_vector(v + 1, (void *) v + v->length, 0x9f22);
+ if (!v)
+ return;
+ /* Find the 0x81 block inside the 0x9f22 block. */
+ sv = sclp_find_gds_subvector(v + 1, (void *) v + v->length, 0x81);
+ if (!sv)
+ return;
+ /* Find the 0x01 block inside the 0x81 block. */
+ netid = sclp_find_gds_subvector(sv + 1, (void *) sv + sv->length, 1);
+ /* Find the 0x02 block inside the 0x81 block. */
+ cpc = sclp_find_gds_subvector(sv + 1, (void *) sv + sv->length, 2);
+ /* Copy network name and cpc name. */
+ spin_lock(&sclp_ocf_lock);
+ if (netid) {
+ size = min(OCF_LENGTH_HMC_NETWORK, (size_t) netid->length);
+ memcpy(hmc_network, netid + 1, size);
+ EBCASC(hmc_network, size);
+ hmc_network[size] = 0;
+ }
+ if (cpc) {
+ size = min(OCF_LENGTH_CPC_NAME, (size_t) cpc->length);
+ memcpy(cpc_name, cpc + 1, size);
+ EBCASC(cpc_name, size);
+ cpc_name[size] = 0;
+ }
+ spin_unlock(&sclp_ocf_lock);
+ schedule_work(&sclp_ocf_change_work);
+}
+
+static struct sclp_register sclp_ocf_event = {
+ .receive_mask = EVTYP_OCF_MASK,
+ .receiver_fn = sclp_ocf_handler,
+};
+
+static ssize_t cpc_name_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *page)
+{
+ int rc;
+
+ spin_lock_irq(&sclp_ocf_lock);
+ rc = snprintf(page, PAGE_SIZE, "%s\n", cpc_name);
+ spin_unlock_irq(&sclp_ocf_lock);
+ return rc;
+}
+
+static struct kobj_attribute cpc_name_attr =
+ __ATTR(cpc_name, 0444, cpc_name_show, NULL);
+
+static ssize_t hmc_network_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *page)
+{
+ int rc;
+
+ spin_lock_irq(&sclp_ocf_lock);
+ rc = snprintf(page, PAGE_SIZE, "%s\n", hmc_network);
+ spin_unlock_irq(&sclp_ocf_lock);
+ return rc;
+}
+
+static struct kobj_attribute hmc_network_attr =
+ __ATTR(hmc_network, 0444, hmc_network_show, NULL);
+
+static struct attribute *ocf_attrs[] = {
+ &cpc_name_attr.attr,
+ &hmc_network_attr.attr,
+ NULL,
+};
+
+static struct attribute_group ocf_attr_group = {
+ .attrs = ocf_attrs,
+};
+
+static int __init ocf_init(void)
+{
+ int rc;
+
+ INIT_WORK(&sclp_ocf_change_work, sclp_ocf_change_notify);
+ ocf_kset = kset_create_and_add("ocf", NULL, firmware_kobj);
+ if (!ocf_kset)
+ return -ENOMEM;
+
+ rc = sysfs_create_group(&ocf_kset->kobj, &ocf_attr_group);
+ if (rc) {
+ kset_unregister(ocf_kset);
+ return rc;
+ }
+
+ return sclp_register(&sclp_ocf_event);
+}
+
+device_initcall(ocf_init);
diff --git a/drivers/s390/char/sclp_sdias.c b/drivers/s390/char/sclp_sdias.c
index 6a1c58dc61a7..fa733ecd3d70 100644
--- a/drivers/s390/char/sclp_sdias.c
+++ b/drivers/s390/char/sclp_sdias.c
@@ -69,9 +69,6 @@ static DEFINE_MUTEX(sdias_mutex);
static void sdias_callback(struct sclp_req *request, void *data)
{
- struct sdias_sccb *cbsccb;
-
- cbsccb = (struct sdias_sccb *) request->sccb;
sclp_req_done = 1;
wake_up(&sdias_wq); /* Inform caller, that request is complete */
TRACE("callback done\n");
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c
index 8258d590505f..a879c139926a 100644
--- a/drivers/s390/char/sclp_tty.c
+++ b/drivers/s390/char/sclp_tty.c
@@ -408,118 +408,72 @@ static int sclp_switch_cases(unsigned char *buf, int count)
return op - buf;
}
-static void
-sclp_get_input(unsigned char *start, unsigned char *end)
+static void sclp_get_input(struct gds_subvector *sv)
{
+ unsigned char *str;
int count;
- count = end - start;
+ str = (unsigned char *) (sv + 1);
+ count = sv->length - sizeof(*sv);
if (sclp_tty_tolower)
- EBC_TOLOWER(start, count);
- count = sclp_switch_cases(start, count);
+ EBC_TOLOWER(str, count);
+ count = sclp_switch_cases(str, count);
/* convert EBCDIC to ASCII (modify original input in SCCB) */
- sclp_ebcasc_str(start, count);
+ sclp_ebcasc_str(str, count);
/* transfer input to high level driver */
- sclp_tty_input(start, count);
-}
-
-static inline struct gds_vector *
-find_gds_vector(struct gds_vector *start, struct gds_vector *end, u16 id)
-{
- struct gds_vector *vec;
-
- for (vec = start; vec < end; vec = (void *) vec + vec->length)
- if (vec->gds_id == id)
- return vec;
- return NULL;
+ sclp_tty_input(str, count);
}
-static inline struct gds_subvector *
-find_gds_subvector(struct gds_subvector *start,
- struct gds_subvector *end, u8 key)
+static inline void sclp_eval_selfdeftextmsg(struct gds_subvector *sv)
{
- struct gds_subvector *subvec;
+ void *end;
- for (subvec = start; subvec < end;
- subvec = (void *) subvec + subvec->length)
- if (subvec->key == key)
- return subvec;
- return NULL;
+ end = (void *) sv + sv->length;
+ for (sv = sv + 1; (void *) sv < end; sv = (void *) sv + sv->length)
+ if (sv->key == 0x30)
+ sclp_get_input(sv);
}
-static inline void
-sclp_eval_selfdeftextmsg(struct gds_subvector *start,
- struct gds_subvector *end)
+static inline void sclp_eval_textcmd(struct gds_vector *v)
{
- struct gds_subvector *subvec;
-
- subvec = start;
- while (subvec < end) {
- subvec = find_gds_subvector(subvec, end, 0x30);
- if (!subvec)
- break;
- sclp_get_input((unsigned char *)(subvec + 1),
- (unsigned char *) subvec + subvec->length);
- subvec = (void *) subvec + subvec->length;
- }
-}
+ struct gds_subvector *sv;
+ void *end;
-static inline void
-sclp_eval_textcmd(struct gds_subvector *start,
- struct gds_subvector *end)
-{
- struct gds_subvector *subvec;
+ end = (void *) v + v->length;
+ for (sv = (struct gds_subvector *) (v + 1);
+ (void *) sv < end; sv = (void *) sv + sv->length)
+ if (sv->key == GDS_KEY_SELFDEFTEXTMSG)
+ sclp_eval_selfdeftextmsg(sv);
- subvec = start;
- while (subvec < end) {
- subvec = find_gds_subvector(subvec, end,
- GDS_KEY_SELFDEFTEXTMSG);
- if (!subvec)
- break;
- sclp_eval_selfdeftextmsg((struct gds_subvector *)(subvec + 1),
- (void *)subvec + subvec->length);
- subvec = (void *) subvec + subvec->length;
- }
}
-static inline void
-sclp_eval_cpmsu(struct gds_vector *start, struct gds_vector *end)
+static inline void sclp_eval_cpmsu(struct gds_vector *v)
{
- struct gds_vector *vec;
+ void *end;
- vec = start;
- while (vec < end) {
- vec = find_gds_vector(vec, end, GDS_ID_TEXTCMD);
- if (!vec)
- break;
- sclp_eval_textcmd((struct gds_subvector *)(vec + 1),
- (void *) vec + vec->length);
- vec = (void *) vec + vec->length;
- }
+ end = (void *) v + v->length;
+ for (v = v + 1; (void *) v < end; v = (void *) v + v->length)
+ if (v->gds_id == GDS_ID_TEXTCMD)
+ sclp_eval_textcmd(v);
}
-static inline void
-sclp_eval_mdsmu(struct gds_vector *start, void *end)
+static inline void sclp_eval_mdsmu(struct gds_vector *v)
{
- struct gds_vector *vec;
-
- vec = find_gds_vector(start, end, GDS_ID_CPMSU);
- if (vec)
- sclp_eval_cpmsu(vec + 1, (void *) vec + vec->length);
+ v = sclp_find_gds_vector(v + 1, (void *) v + v->length, GDS_ID_CPMSU);
+ if (v)
+ sclp_eval_cpmsu(v);
}
-static void
-sclp_tty_receiver(struct evbuf_header *evbuf)
+static void sclp_tty_receiver(struct evbuf_header *evbuf)
{
- struct gds_vector *start, *end, *vec;
+ struct gds_vector *v;
- start = (struct gds_vector *)(evbuf + 1);
- end = (void *) evbuf + evbuf->length;
- vec = find_gds_vector(start, end, GDS_ID_MDSMU);
- if (vec)
- sclp_eval_mdsmu(vec + 1, (void *) vec + vec->length);
+ v = sclp_find_gds_vector(evbuf + 1, (void *) evbuf + evbuf->length,
+ GDS_ID_MDSMU);
+ if (v)
+ sclp_eval_mdsmu(v);
}
static void
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index b98dcbd16711..a7d570728882 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -796,10 +796,8 @@ static void tape_3590_med_state_set(struct tape_device *device,
static int
tape_3590_done(struct tape_device *device, struct tape_request *request)
{
- struct tape_3590_disc_data *disc_data;
DBF_EVENT(6, "%s done\n", tape_op_verbose[request->op]);
- disc_data = device->discdata;
switch (request->op) {
case TO_BSB:
@@ -1394,17 +1392,12 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb)
static int tape_3590_crypt_error(struct tape_device *device,
struct tape_request *request, struct irb *irb)
{
- u8 cu_rc, ekm_rc1;
+ u8 cu_rc;
u16 ekm_rc2;
- u32 drv_rc;
- const char *bus_id;
char *sense;
sense = ((struct tape_3590_sense *) irb->ecw)->fmt.data;
- bus_id = dev_name(&device->cdev->dev);
cu_rc = sense[0];
- drv_rc = *((u32*) &sense[5]) & 0xffffff;
- ekm_rc1 = sense[9];
ekm_rc2 = *((u16*) &sense[10]);
if ((cu_rc == 0) && (ekm_rc2 == 0xee31))
/* key not defined on EKM */
@@ -1429,7 +1422,6 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
struct irb *irb)
{
struct tape_3590_sense *sense;
- int rc;
#ifdef CONFIG_S390_TAPE_BLOCK
if (request->op == TO_BLOCK) {
@@ -1454,7 +1446,6 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
* - "break": basic error recovery is done
* - "goto out:": just print error message if available
*/
- rc = -EIO;
switch (sense->rc_rqc) {
case 0x1110:
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c
deleted file mode 100644
index 1b3924c2fffd..000000000000
--- a/drivers/s390/char/tape_block.c
+++ /dev/null
@@ -1,444 +0,0 @@
-/*
- * drivers/s390/char/tape_block.c
- * block device frontend for tape device driver
- *
- * S390 and zSeries version
- * Copyright (C) 2001,2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Carsten Otte <cotte@de.ibm.com>
- * Tuan Ngo-Anh <ngoanh@de.ibm.com>
- * Martin Schwidefsky <schwidefsky@de.ibm.com>
- * Stefan Bader <shbader@de.ibm.com>
- */
-
-#define KMSG_COMPONENT "tape"
-#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
-
-#include <linux/fs.h>
-#include <linux/module.h>
-#include <linux/blkdev.h>
-#include <linux/mutex.h>
-#include <linux/interrupt.h>
-#include <linux/buffer_head.h>
-#include <linux/kernel.h>
-
-#include <asm/debug.h>
-
-#define TAPE_DBF_AREA tape_core_dbf
-
-#include "tape.h"
-
-#define TAPEBLOCK_MAX_SEC 100
-#define TAPEBLOCK_MIN_REQUEUE 3
-
-/*
- * 2003/11/25 Stefan Bader <shbader@de.ibm.com>
- *
- * In 2.5/2.6 the block device request function is very likely to be called
- * with disabled interrupts (e.g. generic_unplug_device). So the driver can't
- * just call any function that tries to allocate CCW requests from that con-
- * text since it might sleep. There are two choices to work around this:
- * a) do not allocate with kmalloc but use its own memory pool
- * b) take requests from the queue outside that context, knowing that
- * allocation might sleep
- */
-
-/*
- * file operation structure for tape block frontend
- */
-static DEFINE_MUTEX(tape_block_mutex);
-static int tapeblock_open(struct block_device *, fmode_t);
-static int tapeblock_release(struct gendisk *, fmode_t);
-static unsigned int tapeblock_check_events(struct gendisk *, unsigned int);
-static int tapeblock_revalidate_disk(struct gendisk *);
-
-static const struct block_device_operations tapeblock_fops = {
- .owner = THIS_MODULE,
- .open = tapeblock_open,
- .release = tapeblock_release,
- .check_events = tapeblock_check_events,
- .revalidate_disk = tapeblock_revalidate_disk,
-};
-
-static int tapeblock_major = 0;
-
-static void
-tapeblock_trigger_requeue(struct tape_device *device)
-{
- /* Protect against rescheduling. */
- if (atomic_cmpxchg(&device->blk_data.requeue_scheduled, 0, 1) != 0)
- return;
- schedule_work(&device->blk_data.requeue_task);
-}
-
-/*
- * Post finished request.
- */
-static void
-__tapeblock_end_request(struct tape_request *ccw_req, void *data)
-{
- struct tape_device *device;
- struct request *req;
-
- DBF_LH(6, "__tapeblock_end_request()\n");
-
- device = ccw_req->device;
- req = (struct request *) data;
- blk_end_request_all(req, (ccw_req->rc == 0) ? 0 : -EIO);
- if (ccw_req->rc == 0)
- /* Update position. */
- device->blk_data.block_position =
- (blk_rq_pos(req) + blk_rq_sectors(req)) >> TAPEBLOCK_HSEC_S2B;
- else
- /* We lost the position information due to an error. */
- device->blk_data.block_position = -1;
- device->discipline->free_bread(ccw_req);
- if (!list_empty(&device->req_queue) ||
- blk_peek_request(device->blk_data.request_queue))
- tapeblock_trigger_requeue(device);
-}
-
-/*
- * Feed the tape device CCW queue with requests supplied in a list.
- */
-static int
-tapeblock_start_request(struct tape_device *device, struct request *req)
-{
- struct tape_request * ccw_req;
- int rc;
-
- DBF_LH(6, "tapeblock_start_request(%p, %p)\n", device, req);
-
- ccw_req = device->discipline->bread(device, req);
- if (IS_ERR(ccw_req)) {
- DBF_EVENT(1, "TBLOCK: bread failed\n");
- blk_end_request_all(req, -EIO);
- return PTR_ERR(ccw_req);
- }
- ccw_req->callback = __tapeblock_end_request;
- ccw_req->callback_data = (void *) req;
- ccw_req->retries = TAPEBLOCK_RETRIES;
-
- rc = tape_do_io_async(device, ccw_req);
- if (rc) {
- /*
- * Start/enqueueing failed. No retries in
- * this case.
- */
- blk_end_request_all(req, -EIO);
- device->discipline->free_bread(ccw_req);
- }
-
- return rc;
-}
-
-/*
- * Move requests from the block device request queue to the tape device ccw
- * queue.
- */
-static void
-tapeblock_requeue(struct work_struct *work) {
- struct tape_blk_data * blkdat;
- struct tape_device * device;
- struct request_queue * queue;
- int nr_queued;
- struct request * req;
- struct list_head * l;
- int rc;
-
- blkdat = container_of(work, struct tape_blk_data, requeue_task);
- device = blkdat->device;
- if (!device)
- return;
-
- spin_lock_irq(get_ccwdev_lock(device->cdev));
- queue = device->blk_data.request_queue;
-
- /* Count number of requests on ccw queue. */
- nr_queued = 0;
- list_for_each(l, &device->req_queue)
- nr_queued++;
- spin_unlock(get_ccwdev_lock(device->cdev));
-
- spin_lock_irq(&device->blk_data.request_queue_lock);
- while (
- blk_peek_request(queue) &&
- nr_queued < TAPEBLOCK_MIN_REQUEUE
- ) {
- req = blk_fetch_request(queue);
- if (rq_data_dir(req) == WRITE) {
- DBF_EVENT(1, "TBLOCK: Rejecting write request\n");
- spin_unlock_irq(&device->blk_data.request_queue_lock);
- blk_end_request_all(req, -EIO);
- spin_lock_irq(&device->blk_data.request_queue_lock);
- continue;
- }
- nr_queued++;
- spin_unlock_irq(&device->blk_data.request_queue_lock);
- rc = tapeblock_start_request(device, req);
- spin_lock_irq(&device->blk_data.request_queue_lock);
- }
- spin_unlock_irq(&device->blk_data.request_queue_lock);
- atomic_set(&device->blk_data.requeue_scheduled, 0);
-}
-
-/*
- * Tape request queue function. Called from ll_rw_blk.c
- */
-static void
-tapeblock_request_fn(struct request_queue *queue)
-{
- struct tape_device *device;
-
- device = (struct tape_device *) queue->queuedata;
- DBF_LH(6, "tapeblock_request_fn(device=%p)\n", device);
- BUG_ON(device == NULL);
- tapeblock_trigger_requeue(device);
-}
-
-/*
- * This function is called for every new tapedevice
- */
-int
-tapeblock_setup_device(struct tape_device * device)
-{
- struct tape_blk_data * blkdat;
- struct gendisk * disk;
- int rc;
-
- blkdat = &device->blk_data;
- blkdat->device = device;
- spin_lock_init(&blkdat->request_queue_lock);
- atomic_set(&blkdat->requeue_scheduled, 0);
-
- blkdat->request_queue = blk_init_queue(
- tapeblock_request_fn,
- &blkdat->request_queue_lock
- );
- if (!blkdat->request_queue)
- return -ENOMEM;
-
- rc = elevator_change(blkdat->request_queue, "noop");
- if (rc)
- goto cleanup_queue;
-
- blk_queue_logical_block_size(blkdat->request_queue, TAPEBLOCK_HSEC_SIZE);
- blk_queue_max_hw_sectors(blkdat->request_queue, TAPEBLOCK_MAX_SEC);
- blk_queue_max_segments(blkdat->request_queue, -1L);
- blk_queue_max_segment_size(blkdat->request_queue, -1L);
- blk_queue_segment_boundary(blkdat->request_queue, -1L);
-
- disk = alloc_disk(1);
- if (!disk) {
- rc = -ENOMEM;
- goto cleanup_queue;
- }
-
- disk->major = tapeblock_major;
- disk->first_minor = device->first_minor;
- disk->fops = &tapeblock_fops;
- disk->private_data = tape_get_device(device);
- disk->queue = blkdat->request_queue;
- set_capacity(disk, 0);
- sprintf(disk->disk_name, "btibm%d",
- device->first_minor / TAPE_MINORS_PER_DEV);
-
- blkdat->disk = disk;
- blkdat->medium_changed = 1;
- blkdat->request_queue->queuedata = tape_get_device(device);
-
- add_disk(disk);
-
- tape_get_device(device);
- INIT_WORK(&blkdat->requeue_task, tapeblock_requeue);
-
- return 0;
-
-cleanup_queue:
- blk_cleanup_queue(blkdat->request_queue);
- blkdat->request_queue = NULL;
-
- return rc;
-}
-
-void
-tapeblock_cleanup_device(struct tape_device *device)
-{
- flush_work_sync(&device->blk_data.requeue_task);
- tape_put_device(device);
-
- if (!device->blk_data.disk) {
- goto cleanup_queue;
- }
-
- del_gendisk(device->blk_data.disk);
- device->blk_data.disk->private_data = NULL;
- tape_put_device(device);
- put_disk(device->blk_data.disk);
-
- device->blk_data.disk = NULL;
-cleanup_queue:
- device->blk_data.request_queue->queuedata = NULL;
- tape_put_device(device);
-
- blk_cleanup_queue(device->blk_data.request_queue);
- device->blk_data.request_queue = NULL;
-}
-
-/*
- * Detect number of blocks of the tape.
- * FIXME: can we extent this to detect the blocks size as well ?
- */
-static int
-tapeblock_revalidate_disk(struct gendisk *disk)
-{
- struct tape_device * device;
- unsigned int nr_of_blks;
- int rc;
-
- device = (struct tape_device *) disk->private_data;
- BUG_ON(!device);
-
- if (!device->blk_data.medium_changed)
- return 0;
-
- rc = tape_mtop(device, MTFSFM, 1);
- if (rc)
- return rc;
-
- rc = tape_mtop(device, MTTELL, 1);
- if (rc < 0)
- return rc;
-
- pr_info("%s: Determining the size of the recorded area...\n",
- dev_name(&device->cdev->dev));
- DBF_LH(3, "Image file ends at %d\n", rc);
- nr_of_blks = rc;
-
- /* This will fail for the first file. Catch the error by checking the
- * position. */
- tape_mtop(device, MTBSF, 1);
-
- rc = tape_mtop(device, MTTELL, 1);
- if (rc < 0)
- return rc;
-
- if (rc > nr_of_blks)
- return -EINVAL;
-
- DBF_LH(3, "Image file starts at %d\n", rc);
- device->bof = rc;
- nr_of_blks -= rc;
-
- pr_info("%s: The size of the recorded area is %i blocks\n",
- dev_name(&device->cdev->dev), nr_of_blks);
- set_capacity(device->blk_data.disk,
- nr_of_blks*(TAPEBLOCK_HSEC_SIZE/512));
-
- device->blk_data.block_position = 0;
- device->blk_data.medium_changed = 0;
- return 0;
-}
-
-static unsigned int
-tapeblock_check_events(struct gendisk *disk, unsigned int clearing)
-{
- struct tape_device *device;
-
- device = (struct tape_device *) disk->private_data;
- DBF_LH(6, "tapeblock_medium_changed(%p) = %d\n",
- device, device->blk_data.medium_changed);
-
- return device->blk_data.medium_changed ? DISK_EVENT_MEDIA_CHANGE : 0;
-}
-
-/*
- * Block frontend tape device open function.
- */
-static int
-tapeblock_open(struct block_device *bdev, fmode_t mode)
-{
- struct gendisk * disk = bdev->bd_disk;
- struct tape_device * device;
- int rc;
-
- mutex_lock(&tape_block_mutex);
- device = tape_get_device(disk->private_data);
-
- if (device->required_tapemarks) {
- DBF_EVENT(2, "TBLOCK: missing tapemarks\n");
- pr_warning("%s: Opening the tape failed because of missing "
- "end-of-file marks\n", dev_name(&device->cdev->dev));
- rc = -EPERM;
- goto put_device;
- }
-
- rc = tape_open(device);
- if (rc)
- goto put_device;
-
- rc = tapeblock_revalidate_disk(disk);
- if (rc)
- goto release;
-
- /*
- * Note: The reference to <device> is hold until the release function
- * is called.
- */
- tape_state_set(device, TS_BLKUSE);
- mutex_unlock(&tape_block_mutex);
- return 0;
-
-release:
- tape_release(device);
- put_device:
- tape_put_device(device);
- mutex_unlock(&tape_block_mutex);
- return rc;
-}
-
-/*
- * Block frontend tape device release function.
- *
- * Note: One reference to the tape device was made by the open function. So
- * we just get the pointer here and release the reference.
- */
-static int
-tapeblock_release(struct gendisk *disk, fmode_t mode)
-{
- struct tape_device *device = disk->private_data;
-
- mutex_lock(&tape_block_mutex);
- tape_state_set(device, TS_IN_USE);
- tape_release(device);
- tape_put_device(device);
- mutex_unlock(&tape_block_mutex);
-
- return 0;
-}
-
-/*
- * Initialize block device frontend.
- */
-int
-tapeblock_init(void)
-{
- int rc;
-
- /* Register the tape major number to the kernel */
- rc = register_blkdev(tapeblock_major, "tBLK");
- if (rc < 0)
- return rc;
-
- if (tapeblock_major == 0)
- tapeblock_major = rc;
- return 0;
-}
-
-/*
- * Deregister major for block device frontend
- */
-void
-tapeblock_exit(void)
-{
- unregister_blkdev(tapeblock_major, "tBLK");
-}
diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c
index 3c3f342149ec..e7650170274a 100644
--- a/drivers/s390/char/tape_std.c
+++ b/drivers/s390/char/tape_std.c
@@ -564,7 +564,6 @@ int
tape_std_mtreten(struct tape_device *device, int mt_count)
{
struct tape_request *request;
- int rc;
request = tape_alloc_request(4, 0);
if (IS_ERR(request))
@@ -576,7 +575,7 @@ tape_std_mtreten(struct tape_device *device, int mt_count)
tape_ccw_cc(request->cpaddr + 2, NOP, 0, NULL);
tape_ccw_end(request->cpaddr + 3, CCW_CMD_TIC, 0, request->cpaddr);
/* execute it, MTRETEN rc gets ignored */
- rc = tape_do_io_interruptible(device, request);
+ tape_do_io_interruptible(device, request);
tape_free_request(request);
return tape_mtop(device, MTREW, 1);
}
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index 0689fcf23a11..75c3f1f8fd43 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -326,6 +326,36 @@ static void chsc_process_sei_res_acc(struct chsc_sei_area *sei_area)
s390_process_res_acc(&link);
}
+static void chsc_process_sei_chp_avail(struct chsc_sei_area *sei_area)
+{
+ struct channel_path *chp;
+ struct chp_id chpid;
+ u8 *data;
+ int num;
+
+ CIO_CRW_EVENT(4, "chsc: channel path availability information\n");
+ if (sei_area->rs != 0)
+ return;
+ data = sei_area->ccdf;
+ chp_id_init(&chpid);
+ for (num = 0; num <= __MAX_CHPID; num++) {
+ if (!chp_test_bit(data, num))
+ continue;
+ chpid.id = num;
+
+ CIO_CRW_EVENT(4, "Update information for channel path "
+ "%x.%02x\n", chpid.cssid, chpid.id);
+ chp = chpid_to_chp(chpid);
+ if (!chp) {
+ chp_new(chpid);
+ continue;
+ }
+ mutex_lock(&chp->lock);
+ chsc_determine_base_channel_path_desc(chpid, &chp->desc);
+ mutex_unlock(&chp->lock);
+ }
+}
+
struct chp_config_data {
u8 map[32];
u8 op;
@@ -376,9 +406,12 @@ static void chsc_process_sei(struct chsc_sei_area *sei_area)
case 1: /* link incident*/
chsc_process_sei_link_incident(sei_area);
break;
- case 2: /* i/o resource accessibiliy */
+ case 2: /* i/o resource accessibility */
chsc_process_sei_res_acc(sei_area);
break;
+ case 7: /* channel-path-availability information */
+ chsc_process_sei_chp_avail(sei_area);
+ break;
case 8: /* channel-path-configuration notification */
chsc_process_sei_chp_config(sei_area);
break;
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 6084103672b5..52c233fa2b12 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -408,9 +408,10 @@ ccw_device_done(struct ccw_device *cdev, int state)
CIO_MSG_EVENT(0, "Disconnected device %04x on subchannel "
"%04x\n", cdev->private->dev_id.devno,
sch->schid.sch_no);
- if (ccw_device_notify(cdev, CIO_NO_PATH) != NOTIFY_OK)
+ if (ccw_device_notify(cdev, CIO_NO_PATH) != NOTIFY_OK) {
+ cdev->private->state = DEV_STATE_NOT_OPER;
ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
- else
+ } else
ccw_device_set_disconnected(cdev);
cdev->private->flags.donotify = 0;
break;
@@ -840,9 +841,6 @@ call_handler:
static void
ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event)
{
- struct subchannel *sch;
-
- sch = to_subchannel(cdev->dev.parent);
ccw_device_set_timeout(cdev, 0);
/* Start delayed path verification. */
ccw_device_online_verify(cdev, 0);
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index 651976b54af8..f98698d5735e 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -418,12 +418,9 @@ int ccw_device_resume(struct ccw_device *cdev)
int
ccw_device_call_handler(struct ccw_device *cdev)
{
- struct subchannel *sch;
unsigned int stctl;
int ending_status;
- sch = to_subchannel(cdev->dev.parent);
-
/*
* we allow for the device action handler if .
* - we received ending status
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index e8f267eb8887..55e8f721e38a 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -1446,7 +1446,7 @@ set:
static int handle_outbound(struct qdio_q *q, unsigned int callflags,
int bufnr, int count)
{
- unsigned char state;
+ unsigned char state = 0;
int used, rc = 0;
qperf_inc(q, outbound_call);
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 67302b944ab3..16e4a25596e7 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -1183,8 +1183,12 @@ static void ap_scan_bus(struct work_struct *unused)
INIT_LIST_HEAD(&ap_dev->list);
setup_timer(&ap_dev->timeout, ap_request_timeout,
(unsigned long) ap_dev);
- if (device_type == 0)
- ap_probe_device_type(ap_dev);
+ if (device_type == 0) {
+ if (ap_probe_device_type(ap_dev)) {
+ kfree(ap_dev);
+ continue;
+ }
+ }
else
ap_dev->device_type = device_type;
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c
index 607998f0b7d8..aec60d55b10d 100644
--- a/drivers/s390/kvm/kvm_virtio.c
+++ b/drivers/s390/kvm/kvm_virtio.c
@@ -25,7 +25,6 @@
#include <asm/kvm_para.h>
#include <asm/kvm_virtio.h>
#include <asm/setup.h>
-#include <asm/s390_ext.h>
#include <asm/irq.h>
#define VIRTIO_SUBCODE_64 0x0D00
@@ -441,7 +440,7 @@ static int __init kvm_devices_init(void)
INIT_WORK(&hotplug_work, hotplug_devices);
- ctl_set_bit(0, 9);
+ service_subclass_irq_register();
register_external_interrupt(0x2603, kvm_extint_handler);
scan_devices();
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index da8aa75bb20b..f1fa2483ae6b 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -845,12 +845,10 @@ claw_irq_tasklet ( unsigned long data )
{
struct chbk * p_ch;
struct net_device *dev;
- struct claw_privbk * privptr;
p_ch = (struct chbk *) data;
dev = (struct net_device *)p_ch->ndev;
CLAW_DBF_TEXT(4, trace, "IRQtask");
- privptr = (struct claw_privbk *)dev->ml_priv;
unpack_read(dev);
clear_bit(CLAW_BH_ACTIVE, (void *)&p_ch->flag_a);
CLAW_DBF_TEXT(4, trace, "TskletXt");
@@ -1026,7 +1024,6 @@ claw_write_next ( struct chbk * p_ch )
struct net_device *dev;
struct claw_privbk *privptr=NULL;
struct sk_buff *pk_skb;
- int rc;
CLAW_DBF_TEXT(4, trace, "claw_wrt");
if (p_ch->claw_state == CLAW_STOP)
@@ -1038,7 +1035,7 @@ claw_write_next ( struct chbk * p_ch )
!skb_queue_empty(&p_ch->collect_queue)) {
pk_skb = claw_pack_skb(privptr);
while (pk_skb != NULL) {
- rc = claw_hw_tx( pk_skb, dev,1);
+ claw_hw_tx(pk_skb, dev, 1);
if (privptr->write_free_count > 0) {
pk_skb = claw_pack_skb(privptr);
} else
@@ -1322,15 +1319,12 @@ claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid)
unsigned char *pDataAddress;
struct endccw *pEnd;
struct ccw1 tempCCW;
- struct chbk *p_ch;
struct claw_env *p_env;
- int lock;
struct clawph *pk_head;
struct chbk *ch;
CLAW_DBF_TEXT(4, trace, "hw_tx");
privptr = (struct claw_privbk *)(dev->ml_priv);
- p_ch = (struct chbk *)&privptr->channel[WRITE_CHANNEL];
p_env =privptr->p_env;
claw_free_wrt_buf(dev); /* Clean up free chain if posible */
/* scan the write queue to free any completed write packets */
@@ -1511,12 +1505,6 @@ claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid)
} /* endif (p_first_ccw!=NULL) */
dev_kfree_skb_any(skb);
- if (linkid==0) {
- lock=LOCK_NO;
- }
- else {
- lock=LOCK_YES;
- }
claw_strt_out_IO(dev );
/* if write free count is zero , set NOBUFFER */
if (privptr->write_free_count==0) {
@@ -2821,15 +2809,11 @@ claw_free_wrt_buf( struct net_device *dev )
{
struct claw_privbk *privptr = (struct claw_privbk *)dev->ml_priv;
- struct ccwbk*p_first_ccw;
- struct ccwbk*p_last_ccw;
struct ccwbk*p_this_ccw;
struct ccwbk*p_next_ccw;
CLAW_DBF_TEXT(4, trace, "freewrtb");
/* scan the write queue to free any completed write packets */
- p_first_ccw=NULL;
- p_last_ccw=NULL;
p_this_ccw=privptr->p_write_active_first;
while ( (p_this_ccw!=NULL) && (p_this_ccw->header.flag!=CLAW_PENDING))
{
@@ -3072,7 +3056,7 @@ claw_shutdown_device(struct ccwgroup_device *cgdev)
{
struct claw_privbk *priv;
struct net_device *ndev;
- int ret;
+ int ret = 0;
CLAW_DBF_TEXT_(2, setup, "%s", dev_name(&cgdev->dev));
priv = dev_get_drvdata(&cgdev->dev);
@@ -3095,7 +3079,7 @@ claw_shutdown_device(struct ccwgroup_device *cgdev)
}
ccw_device_set_offline(cgdev->cdev[1]);
ccw_device_set_offline(cgdev->cdev[0]);
- return 0;
+ return ret;
}
static void
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c
index c189296763a4..426787efc492 100644
--- a/drivers/s390/net/ctcm_main.c
+++ b/drivers/s390/net/ctcm_main.c
@@ -672,7 +672,6 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb)
int ccw_idx;
unsigned long hi;
unsigned long saveflags = 0; /* avoids compiler warning */
- __u16 block_len;
CTCM_PR_DEBUG("Enter %s: %s, cp=%i ch=0x%p id=%s state=%s\n",
__func__, dev->name, smp_processor_id(), ch,
@@ -719,7 +718,6 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb)
*/
atomic_inc(&skb->users);
- block_len = skb->len + TH_HEADER_LENGTH + PDU_HEADER_LENGTH;
/*
* IDAL support in CTCM is broken, so we have to
* care about skb's above 2G ourselves.
diff --git a/drivers/s390/net/ctcm_mpc.c b/drivers/s390/net/ctcm_mpc.c
index b64881f33f23..da4c747335e7 100644
--- a/drivers/s390/net/ctcm_mpc.c
+++ b/drivers/s390/net/ctcm_mpc.c
@@ -653,7 +653,6 @@ static void ctcmpc_send_sweep_resp(struct channel *rch)
struct net_device *dev = rch->netdev;
struct ctcm_priv *priv = dev->ml_priv;
struct mpc_group *grp = priv->mpcg;
- int rc = 0;
struct th_sweep *header;
struct sk_buff *sweep_skb;
struct channel *ch = priv->channel[CTCM_WRITE];
@@ -665,16 +664,14 @@ static void ctcmpc_send_sweep_resp(struct channel *rch)
CTCM_DBF_TEXT_(MPC_ERROR, CTC_DBF_ERROR,
"%s(%s): sweep_skb allocation ERROR\n",
CTCM_FUNTAIL, rch->id);
- rc = -ENOMEM;
- goto done;
+ goto done;
}
header = kmalloc(sizeof(struct th_sweep), gfp_type());
if (!header) {
dev_kfree_skb_any(sweep_skb);
- rc = -ENOMEM;
- goto done;
+ goto done;
}
header->th.th_seg = 0x00 ;
@@ -1370,8 +1367,7 @@ static void mpc_action_go_inop(fsm_instance *fi, int event, void *arg)
struct net_device *dev = arg;
struct ctcm_priv *priv;
struct mpc_group *grp;
- int rc = 0;
- struct channel *wch, *rch;
+ struct channel *wch;
BUG_ON(dev == NULL);
CTCM_PR_DEBUG("Enter %s: %s\n", __func__, dev->name);
@@ -1396,7 +1392,6 @@ static void mpc_action_go_inop(fsm_instance *fi, int event, void *arg)
fsm_deltimer(&priv->restart_timer);
wch = priv->channel[CTCM_WRITE];
- rch = priv->channel[CTCM_READ];
switch (grp->saved_state) {
case MPCG_STATE_RESET:
@@ -1435,7 +1430,7 @@ static void mpc_action_go_inop(fsm_instance *fi, int event, void *arg)
if (grp->send_qllc_disc == 1) {
grp->send_qllc_disc = 0;
- rc = mpc_send_qllc_discontact(dev);
+ mpc_send_qllc_discontact(dev);
}
/* DO NOT issue DEV_EVENT_STOP directly out of this code */
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index 49d1cfc3217e..c3b8064a102d 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -1483,7 +1483,6 @@ lcs_tasklet(unsigned long data)
struct lcs_channel *channel;
struct lcs_buffer *iob;
int buf_idx;
- int rc;
channel = (struct lcs_channel *) data;
LCS_DBF_TEXT_(5, trace, "tlet%s", dev_name(&channel->ccwdev->dev));
@@ -1500,14 +1499,11 @@ lcs_tasklet(unsigned long data)
channel->buf_idx = buf_idx;
if (channel->state == LCS_CH_STATE_STOPPED)
- // FIXME: what if rc != 0 ??
- rc = lcs_start_channel(channel);
+ lcs_start_channel(channel);
spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
if (channel->state == LCS_CH_STATE_SUSPENDED &&
- channel->iob[channel->io_idx].state == LCS_BUF_STATE_READY) {
- // FIXME: what if rc != 0 ??
- rc = __lcs_resume_channel(channel);
- }
+ channel->iob[channel->io_idx].state == LCS_BUF_STATE_READY)
+ __lcs_resume_channel(channel);
spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
/* Something happened on the channel. Wake up waiters. */
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index b6a6356d09b3..3251333a23df 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -1994,8 +1994,6 @@ static struct net_device *netiucv_init_netdevice(char *username)
netiucv_setup_netdevice);
if (!dev)
return NULL;
- if (dev_alloc_name(dev, dev->name) < 0)
- goto out_netdev;
privptr = netdev_priv(dev);
privptr->fsm = init_fsm("netiucvdev", dev_state_names,
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index af3f7b095647..55c6aa1c9704 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -407,12 +407,6 @@ struct qeth_qdio_q {
int next_buf_to_init;
} __attribute__ ((aligned(256)));
-/* possible types of qeth large_send support */
-enum qeth_large_send_types {
- QETH_LARGE_SEND_NO,
- QETH_LARGE_SEND_TSO,
-};
-
struct qeth_qdio_out_buffer {
struct qdio_buffer *buffer;
atomic_t state;
@@ -637,6 +631,8 @@ struct qeth_card_info {
__u32 csum_mask;
__u32 tx_csum_mask;
enum qeth_ipa_promisc_modes promisc_mode;
+ __u32 diagass_support;
+ __u32 hwtrap;
};
struct qeth_card_options {
@@ -645,13 +641,11 @@ struct qeth_card_options {
struct qeth_ipa_info adp; /*Adapter parameters*/
struct qeth_routing_info route6;
struct qeth_ipa_info ipa6;
- enum qeth_checksum_types checksum_type;
int broadcast_mode;
int macaddr_mode;
int fake_broadcast;
int add_hhlen;
int layer2;
- enum qeth_large_send_types large_send;
int performance_stats;
int rx_sg_cb;
enum qeth_ipa_isolation_modes isolation;
@@ -760,6 +754,14 @@ struct qeth_card_list_struct {
rwlock_t rwlock;
};
+struct qeth_trap_id {
+ __u16 lparnr;
+ char vmname[8];
+ __u8 chpid;
+ __u8 ssid;
+ __u16 devno;
+} __packed;
+
/*some helper functions*/
#define QETH_CARD_IFNAME(card) (((card)->dev)? (card)->dev->name : "")
@@ -794,6 +796,12 @@ static inline void qeth_put_buffer_pool_entry(struct qeth_card *card,
list_add_tail(&entry->list, &card->qdio.in_buf_pool.entry_list);
}
+static inline int qeth_is_diagass_supported(struct qeth_card *card,
+ enum qeth_diags_cmds cmd)
+{
+ return card->info.diagass_support & (__u32)cmd;
+}
+
extern struct ccwgroup_driver qeth_l2_ccwgroup_driver;
extern struct ccwgroup_driver qeth_l3_ccwgroup_driver;
const char *qeth_get_cardname_short(struct qeth_card *);
@@ -879,6 +887,8 @@ 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);
+int qeth_hw_trap(struct qeth_card *, enum qeth_diags_trap_action);
+int qeth_query_ipassists(struct qeth_card *, enum qeth_prot_versions prot);
/* 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 85cc53117ea6..503678a30981 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -24,6 +24,7 @@
#include <asm/ebcdic.h>
#include <asm/io.h>
+#include <asm/sysinfo.h>
#include "qeth_core.h"
@@ -349,6 +350,8 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card,
card->info.chpid);
netif_carrier_on(card->dev);
card->lan_online = 1;
+ if (card->info.hwtrap)
+ card->info.hwtrap = 2;
qeth_schedule_recovery(card);
return NULL;
case IPA_CMD_MODCCID:
@@ -1039,7 +1042,6 @@ static void qeth_set_intial_options(struct qeth_card *card)
{
card->options.route4.type = NO_ROUTER;
card->options.route6.type = NO_ROUTER;
- card->options.checksum_type = QETH_CHECKSUM_DEFAULT;
card->options.broadcast_mode = QETH_TR_BROADCAST_ALLRINGS;
card->options.macaddr_mode = QETH_TR_MACADDR_NONCANONICAL;
card->options.fake_broadcast = 0;
@@ -2574,6 +2576,142 @@ int qeth_query_setadapterparms(struct qeth_card *card)
}
EXPORT_SYMBOL_GPL(qeth_query_setadapterparms);
+static int qeth_query_ipassists_cb(struct qeth_card *card,
+ struct qeth_reply *reply, unsigned long data)
+{
+ struct qeth_ipa_cmd *cmd;
+
+ QETH_DBF_TEXT(SETUP, 2, "qipasscb");
+
+ cmd = (struct qeth_ipa_cmd *) data;
+ if (cmd->hdr.prot_version == QETH_PROT_IPV4) {
+ card->options.ipa4.supported_funcs = cmd->hdr.ipa_supported;
+ card->options.ipa4.enabled_funcs = cmd->hdr.ipa_enabled;
+ } else {
+ card->options.ipa6.supported_funcs = cmd->hdr.ipa_supported;
+ card->options.ipa6.enabled_funcs = cmd->hdr.ipa_enabled;
+ }
+ QETH_DBF_TEXT(SETUP, 2, "suppenbl");
+ QETH_DBF_TEXT_(SETUP, 2, "%x", cmd->hdr.ipa_supported);
+ QETH_DBF_TEXT_(SETUP, 2, "%x", cmd->hdr.ipa_enabled);
+ return 0;
+}
+
+int qeth_query_ipassists(struct qeth_card *card, enum qeth_prot_versions prot)
+{
+ int rc;
+ struct qeth_cmd_buffer *iob;
+
+ QETH_DBF_TEXT_(SETUP, 2, "qipassi%i", prot);
+ iob = qeth_get_ipacmd_buffer(card, IPA_CMD_QIPASSIST, prot);
+ rc = qeth_send_ipa_cmd(card, iob, qeth_query_ipassists_cb, NULL);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(qeth_query_ipassists);
+
+static int qeth_query_setdiagass_cb(struct qeth_card *card,
+ struct qeth_reply *reply, unsigned long data)
+{
+ struct qeth_ipa_cmd *cmd;
+ __u16 rc;
+
+ cmd = (struct qeth_ipa_cmd *)data;
+ rc = cmd->hdr.return_code;
+ if (rc)
+ QETH_CARD_TEXT_(card, 2, "diagq:%x", rc);
+ else
+ card->info.diagass_support = cmd->data.diagass.ext;
+ return 0;
+}
+
+static int qeth_query_setdiagass(struct qeth_card *card)
+{
+ struct qeth_cmd_buffer *iob;
+ struct qeth_ipa_cmd *cmd;
+
+ QETH_DBF_TEXT(SETUP, 2, "qdiagass");
+ iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0);
+ cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
+ cmd->data.diagass.subcmd_len = 16;
+ cmd->data.diagass.subcmd = QETH_DIAGS_CMD_QUERY;
+ return qeth_send_ipa_cmd(card, iob, qeth_query_setdiagass_cb, NULL);
+}
+
+static void qeth_get_trap_id(struct qeth_card *card, struct qeth_trap_id *tid)
+{
+ unsigned long info = get_zeroed_page(GFP_KERNEL);
+ struct sysinfo_2_2_2 *info222 = (struct sysinfo_2_2_2 *)info;
+ struct sysinfo_3_2_2 *info322 = (struct sysinfo_3_2_2 *)info;
+ struct ccw_dev_id ccwid;
+ int level, rc;
+
+ tid->chpid = card->info.chpid;
+ ccw_device_get_id(CARD_RDEV(card), &ccwid);
+ tid->ssid = ccwid.ssid;
+ tid->devno = ccwid.devno;
+ if (!info)
+ return;
+
+ rc = stsi(NULL, 0, 0, 0);
+ if (rc == -ENOSYS)
+ level = rc;
+ else
+ level = (((unsigned int) rc) >> 28);
+
+ if ((level >= 2) && (stsi(info222, 2, 2, 2) != -ENOSYS))
+ tid->lparnr = info222->lpar_number;
+
+ if ((level >= 3) && (stsi(info322, 3, 2, 2) != -ENOSYS)) {
+ EBCASC(info322->vm[0].name, sizeof(info322->vm[0].name));
+ memcpy(tid->vmname, info322->vm[0].name, sizeof(tid->vmname));
+ }
+ free_page(info);
+ return;
+}
+
+static int qeth_hw_trap_cb(struct qeth_card *card,
+ struct qeth_reply *reply, unsigned long data)
+{
+ struct qeth_ipa_cmd *cmd;
+ __u16 rc;
+
+ cmd = (struct qeth_ipa_cmd *)data;
+ rc = cmd->hdr.return_code;
+ if (rc)
+ QETH_CARD_TEXT_(card, 2, "trapc:%x", rc);
+ return 0;
+}
+
+int qeth_hw_trap(struct qeth_card *card, enum qeth_diags_trap_action action)
+{
+ struct qeth_cmd_buffer *iob;
+ struct qeth_ipa_cmd *cmd;
+
+ QETH_DBF_TEXT(SETUP, 2, "diagtrap");
+ iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SET_DIAG_ASS, 0);
+ cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE);
+ cmd->data.diagass.subcmd_len = 80;
+ cmd->data.diagass.subcmd = QETH_DIAGS_CMD_TRAP;
+ cmd->data.diagass.type = 1;
+ cmd->data.diagass.action = action;
+ switch (action) {
+ case QETH_DIAGS_TRAP_ARM:
+ cmd->data.diagass.options = 0x0003;
+ cmd->data.diagass.ext = 0x00010000 +
+ sizeof(struct qeth_trap_id);
+ qeth_get_trap_id(card,
+ (struct qeth_trap_id *)cmd->data.diagass.cdata);
+ break;
+ case QETH_DIAGS_TRAP_DISARM:
+ cmd->data.diagass.options = 0x0001;
+ break;
+ case QETH_DIAGS_TRAP_CAPTURE:
+ break;
+ }
+ return qeth_send_ipa_cmd(card, iob, qeth_hw_trap_cb, NULL);
+}
+EXPORT_SYMBOL_GPL(qeth_hw_trap);
+
int qeth_check_qdio_errors(struct qeth_card *card, struct qdio_buffer *buf,
unsigned int qdio_error, const char *dbftext)
{
@@ -3903,6 +4041,7 @@ MODULE_DEVICE_TABLE(ccw, qeth_ids);
static struct ccw_driver qeth_ccw_driver = {
.driver = {
+ .owner = THIS_MODULE,
.name = "qeth",
},
.ids = qeth_ids,
@@ -3984,6 +4123,15 @@ retriable:
QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc);
goto out;
}
+
+ card->options.ipa4.supported_funcs = 0;
+ card->options.adp.supported_funcs = 0;
+ card->info.diagass_support = 0;
+ qeth_query_ipassists(card, QETH_PROT_IPV4);
+ if (qeth_is_supported(card, IPA_SETADAPTERPARMS))
+ qeth_query_setadapterparms(card);
+ if (qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST))
+ qeth_query_setdiagass(card);
return 0;
out:
dev_warn(&card->gdev->dev, "The qeth device driver failed to recover "
diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h
index 07d588867b57..e5a9d1c03839 100644
--- a/drivers/s390/net/qeth_core_mpc.h
+++ b/drivers/s390/net/qeth_core_mpc.h
@@ -80,14 +80,6 @@ enum qeth_tr_broadcast_modes {
QETH_TR_BROADCAST_LOCAL = 1,
};
-/* these values match CHECKSUM_* in include/linux/skbuff.h */
-enum qeth_checksum_types {
- SW_CHECKSUMMING = 0, /* TODO: set to bit flag used in IPA Command */
- HW_CHECKSUMMING = 1,
- NO_CHECKSUMMING = 2,
-};
-#define QETH_CHECKSUM_DEFAULT SW_CHECKSUMMING
-
/*
* Routing stuff
*/
@@ -456,6 +448,12 @@ enum qeth_diags_trace_cmds {
QETH_DIAGS_CMD_TRACE_QUERY = 0x0010,
};
+enum qeth_diags_trap_action {
+ QETH_DIAGS_TRAP_ARM = 0x01,
+ QETH_DIAGS_TRAP_DISARM = 0x02,
+ QETH_DIAGS_TRAP_CAPTURE = 0x04,
+};
+
struct qeth_ipacmd_diagass {
__u32 host_tod2;
__u32:32;
@@ -465,7 +463,8 @@ struct qeth_ipacmd_diagass {
__u8 type;
__u8 action;
__u16 options;
- __u32:32;
+ __u32 ext;
+ __u8 cdata[64];
} __attribute__ ((packed));
/* Header for each IPA command */
diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c
index b5e967cf7e2d..0a8e86c1b0ea 100644
--- a/drivers/s390/net/qeth_core_sys.c
+++ b/drivers/s390/net/qeth_core_sys.c
@@ -530,6 +530,66 @@ out:
static DEVICE_ATTR(isolation, 0644, qeth_dev_isolation_show,
qeth_dev_isolation_store);
+static ssize_t qeth_hw_trap_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct qeth_card *card = dev_get_drvdata(dev);
+
+ if (!card)
+ return -EINVAL;
+ if (card->info.hwtrap)
+ return snprintf(buf, 5, "arm\n");
+ else
+ return snprintf(buf, 8, "disarm\n");
+}
+
+static ssize_t qeth_hw_trap_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct qeth_card *card = dev_get_drvdata(dev);
+ int rc = 0;
+ char *tmp, *curtoken;
+ int state = 0;
+ curtoken = (char *)buf;
+
+ if (!card)
+ return -EINVAL;
+
+ mutex_lock(&card->conf_mutex);
+ if (card->state == CARD_STATE_SOFTSETUP || card->state == CARD_STATE_UP)
+ state = 1;
+ tmp = strsep(&curtoken, "\n");
+
+ if (!strcmp(tmp, "arm") && !card->info.hwtrap) {
+ if (state) {
+ if (qeth_is_diagass_supported(card,
+ QETH_DIAGS_CMD_TRAP)) {
+ rc = qeth_hw_trap(card, QETH_DIAGS_TRAP_ARM);
+ if (!rc)
+ card->info.hwtrap = 1;
+ } else
+ rc = -EINVAL;
+ } else
+ card->info.hwtrap = 1;
+ } else if (!strcmp(tmp, "disarm") && card->info.hwtrap) {
+ if (state) {
+ rc = qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
+ if (!rc)
+ card->info.hwtrap = 0;
+ } else
+ card->info.hwtrap = 0;
+ } else if (!strcmp(tmp, "trap") && state && card->info.hwtrap)
+ rc = qeth_hw_trap(card, QETH_DIAGS_TRAP_CAPTURE);
+ else
+ rc = -EINVAL;
+
+ mutex_unlock(&card->conf_mutex);
+ return rc ? rc : count;
+}
+
+static DEVICE_ATTR(hw_trap, 0644, qeth_hw_trap_show,
+ qeth_hw_trap_store);
+
static ssize_t qeth_dev_blkt_show(char *buf, struct qeth_card *card, int value)
{
@@ -653,6 +713,7 @@ static struct attribute *qeth_device_attrs[] = {
&dev_attr_performance_stats.attr,
&dev_attr_layer2.attr,
&dev_attr_isolation.attr,
+ &dev_attr_hw_trap.attr,
NULL,
};
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 6fbaacb21943..b70b47fbd6cd 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -420,10 +420,7 @@ static int qeth_l2_process_inbound_buffer(struct qeth_card *card,
case QETH_HEADER_TYPE_LAYER2:
skb->pkt_type = PACKET_HOST;
skb->protocol = eth_type_trans(skb, skb->dev);
- if (card->options.checksum_type == NO_CHECKSUMMING)
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- else
- skb->ip_summed = CHECKSUM_NONE;
+ skb->ip_summed = CHECKSUM_NONE;
if (skb->protocol == htons(ETH_P_802_2))
*((__u32 *)skb->cb) = ++card->seqno.pkt_seqno;
len = skb->len;
@@ -879,6 +876,7 @@ static int qeth_l2_probe_device(struct ccwgroup_device *gdev)
INIT_LIST_HEAD(&card->vid_list);
INIT_LIST_HEAD(&card->mc_list);
card->options.layer2 = 1;
+ card->info.hwtrap = 0;
card->discipline.start_poll = qeth_qdio_start_poll;
card->discipline.input_handler = (qdio_handler_t *)
qeth_qdio_input_handler;
@@ -997,6 +995,13 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
if (card->info.type != QETH_CARD_TYPE_OSN)
qeth_l2_send_setmac(card, &card->dev->dev_addr[0]);
+ if (qeth_is_diagass_supported(card, QETH_DIAGS_CMD_TRAP)) {
+ if (card->info.hwtrap &&
+ qeth_hw_trap(card, QETH_DIAGS_TRAP_ARM))
+ card->info.hwtrap = 0;
+ } else
+ card->info.hwtrap = 0;
+
card->state = CARD_STATE_HARDSETUP;
memset(&card->rx, 0, sizeof(struct qeth_rx));
qeth_print_status_message(card);
@@ -1095,6 +1100,10 @@ static int __qeth_l2_set_offline(struct ccwgroup_device *cgdev,
if (card->dev && netif_carrier_ok(card->dev))
netif_carrier_off(card->dev);
recover_flag = card->state;
+ if ((!recovery_mode && card->info.hwtrap) || card->info.hwtrap == 2) {
+ qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
+ card->info.hwtrap = 1;
+ }
qeth_l2_stop_card(card, recovery_mode);
rc = ccw_device_set_offline(CARD_DDEV(card));
rc2 = ccw_device_set_offline(CARD_WDEV(card));
@@ -1160,6 +1169,8 @@ static void __exit qeth_l2_exit(void)
static void qeth_l2_shutdown(struct ccwgroup_device *gdev)
{
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+ if ((gdev->state == CCWGROUP_ONLINE) && card->info.hwtrap)
+ qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
qeth_qdio_clear_card(card, 0);
qeth_clear_qdio_buffers(card);
}
@@ -1175,6 +1186,8 @@ static int qeth_l2_pm_suspend(struct ccwgroup_device *gdev)
if (gdev->state == CCWGROUP_OFFLINE)
return 0;
if (card->state == CARD_STATE_UP) {
+ if (card->info.hwtrap)
+ qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
__qeth_l2_set_offline(card->gdev, 1);
} else
__qeth_l2_set_offline(card->gdev, 0);
diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h
index e705b27ec7dc..14a43aeb0c2a 100644
--- a/drivers/s390/net/qeth_l3.h
+++ b/drivers/s390/net/qeth_l3.h
@@ -62,8 +62,6 @@ void qeth_l3_del_vipa(struct qeth_card *, enum qeth_prot_versions, const u8 *);
int qeth_l3_add_rxip(struct qeth_card *, enum qeth_prot_versions, const u8 *);
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 142e5f6ef4f3..fd69da3fa6b4 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -43,33 +43,6 @@ static int qeth_l3_deregister_addr_entry(struct qeth_card *,
static int __qeth_l3_set_online(struct ccwgroup_device *, int);
static int __qeth_l3_set_offline(struct ccwgroup_device *, int);
-int qeth_l3_set_large_send(struct qeth_card *card,
- enum qeth_large_send_types type)
-{
- int rc = 0;
-
- card->options.large_send = type;
- if (card->dev == NULL)
- return 0;
-
- if (card->options.large_send == QETH_LARGE_SEND_TSO) {
- if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) {
- card->dev->features |= NETIF_F_TSO | NETIF_F_SG |
- NETIF_F_IP_CSUM;
- } else {
- card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG |
- NETIF_F_IP_CSUM);
- card->options.large_send = QETH_LARGE_SEND_NO;
- rc = -EOPNOTSUPP;
- }
- } else {
- card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG |
- NETIF_F_IP_CSUM);
- card->options.large_send = QETH_LARGE_SEND_NO;
- }
- return rc;
-}
-
static int qeth_l3_isxdigit(char *buf)
{
while (*buf) {
@@ -1304,39 +1277,6 @@ static int qeth_l3_start_ipa_multicast(struct qeth_card *card)
return rc;
}
-static int qeth_l3_query_ipassists_cb(struct qeth_card *card,
- struct qeth_reply *reply, unsigned long data)
-{
- struct qeth_ipa_cmd *cmd;
-
- QETH_DBF_TEXT(SETUP, 2, "qipasscb");
-
- cmd = (struct qeth_ipa_cmd *) data;
- if (cmd->hdr.prot_version == QETH_PROT_IPV4) {
- card->options.ipa4.supported_funcs = cmd->hdr.ipa_supported;
- card->options.ipa4.enabled_funcs = cmd->hdr.ipa_enabled;
- } else {
- card->options.ipa6.supported_funcs = cmd->hdr.ipa_supported;
- card->options.ipa6.enabled_funcs = cmd->hdr.ipa_enabled;
- }
- QETH_DBF_TEXT(SETUP, 2, "suppenbl");
- QETH_DBF_TEXT_(SETUP, 2, "%x", cmd->hdr.ipa_supported);
- QETH_DBF_TEXT_(SETUP, 2, "%x", cmd->hdr.ipa_enabled);
- return 0;
-}
-
-static int qeth_l3_query_ipassists(struct qeth_card *card,
- enum qeth_prot_versions prot)
-{
- int rc;
- struct qeth_cmd_buffer *iob;
-
- QETH_DBF_TEXT_(SETUP, 2, "qipassi%i", prot);
- iob = qeth_get_ipacmd_buffer(card, IPA_CMD_QIPASSIST, prot);
- rc = qeth_send_ipa_cmd(card, iob, qeth_l3_query_ipassists_cb, NULL);
- return rc;
-}
-
#ifdef CONFIG_QETH_IPV6
static int qeth_l3_softsetup_ipv6(struct qeth_card *card)
{
@@ -1347,7 +1287,7 @@ static int qeth_l3_softsetup_ipv6(struct qeth_card *card)
if (card->info.type == QETH_CARD_TYPE_IQD)
goto out;
- rc = qeth_l3_query_ipassists(card, QETH_PROT_IPV6);
+ rc = qeth_query_ipassists(card, QETH_PROT_IPV6);
if (rc) {
dev_err(&card->gdev->dev,
"Activating IPv6 support for %s failed\n",
@@ -1472,68 +1412,38 @@ static int qeth_l3_send_checksum_command(struct qeth_card *card)
return 0;
}
-int qeth_l3_set_rx_csum(struct qeth_card *card,
- enum qeth_checksum_types csum_type)
+int qeth_l3_set_rx_csum(struct qeth_card *card, int on)
{
int rc = 0;
- if (card->options.checksum_type == HW_CHECKSUMMING) {
- if ((csum_type != HW_CHECKSUMMING) &&
- (card->state != CARD_STATE_DOWN)) {
- rc = qeth_l3_send_simple_setassparms(card,
- IPA_INBOUND_CHECKSUM, IPA_CMD_ASS_STOP, 0);
- if (rc)
- return -EIO;
- }
+ if (on) {
+ rc = qeth_l3_send_checksum_command(card);
+ if (rc)
+ return -EIO;
+ dev_info(&card->gdev->dev,
+ "HW Checksumming (inbound) enabled\n");
} else {
- if (csum_type == HW_CHECKSUMMING) {
- if (card->state != CARD_STATE_DOWN) {
- if (!qeth_is_supported(card,
- IPA_INBOUND_CHECKSUM))
- return -EPERM;
- rc = qeth_l3_send_checksum_command(card);
- if (rc)
- return -EIO;
- }
- }
+ rc = qeth_l3_send_simple_setassparms(card,
+ IPA_INBOUND_CHECKSUM, IPA_CMD_ASS_STOP, 0);
+ if (rc)
+ return -EIO;
}
- card->options.checksum_type = csum_type;
- return rc;
+
+ return 0;
}
static int qeth_l3_start_ipa_checksum(struct qeth_card *card)
{
- int rc = 0;
-
QETH_CARD_TEXT(card, 3, "strtcsum");
- if (card->options.checksum_type == NO_CHECKSUMMING) {
- dev_info(&card->gdev->dev,
- "Using no checksumming on %s.\n",
- QETH_CARD_IFNAME(card));
- return 0;
- }
- if (card->options.checksum_type == SW_CHECKSUMMING) {
- dev_info(&card->gdev->dev,
- "Using SW checksumming on %s.\n",
- QETH_CARD_IFNAME(card));
- return 0;
- }
- if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM)) {
- dev_info(&card->gdev->dev,
- "Inbound HW Checksumming not "
- "supported on %s,\ncontinuing "
- "using Inbound SW Checksumming\n",
- QETH_CARD_IFNAME(card));
- card->options.checksum_type = SW_CHECKSUMMING;
- return 0;
+ if (card->dev->features & NETIF_F_RXCSUM) {
+ rtnl_lock();
+ /* force set_features call */
+ card->dev->features &= ~NETIF_F_RXCSUM;
+ netdev_update_features(card->dev);
+ rtnl_unlock();
}
- rc = qeth_l3_send_checksum_command(card);
- if (!rc)
- dev_info(&card->gdev->dev,
- "HW Checksumming (inbound) enabled\n");
-
- return rc;
+ return 0;
}
static int qeth_l3_start_ipa_tx_checksum(struct qeth_card *card)
@@ -1580,10 +1490,8 @@ static int qeth_l3_start_ipa_tso(struct qeth_card *card)
dev_info(&card->gdev->dev,
"Outbound TSO enabled\n");
}
- if (rc && (card->options.large_send == QETH_LARGE_SEND_TSO)) {
- card->options.large_send = QETH_LARGE_SEND_NO;
- card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG);
- }
+ if (rc)
+ card->dev->features &= ~NETIF_F_TSO;
return rc;
}
@@ -2064,14 +1972,7 @@ static inline int qeth_l3_rebuild_skb(struct qeth_card *card,
is_vlan = 1;
}
- switch (card->options.checksum_type) {
- case SW_CHECKSUMMING:
- skb->ip_summed = CHECKSUM_NONE;
- break;
- case NO_CHECKSUMMING:
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- break;
- case HW_CHECKSUMMING:
+ if (card->dev->features & NETIF_F_RXCSUM) {
if ((hdr->hdr.l3.ext_flags &
(QETH_HDR_EXT_CSUM_HDR_REQ |
QETH_HDR_EXT_CSUM_TRANSP_REQ)) ==
@@ -2080,7 +1981,8 @@ static inline int qeth_l3_rebuild_skb(struct qeth_card *card,
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
skb->ip_summed = CHECKSUM_NONE;
- }
+ } else
+ skb->ip_summed = CHECKSUM_NONE;
return is_vlan;
}
@@ -3024,7 +2926,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct qeth_qdio_out_q *queue = card->qdio.out_qs
[qeth_get_priority_queue(card, skb, ipv, cast_type)];
int tx_bytes = skb->len;
- enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO;
+ bool large_send;
int data_offset = -1;
int nr_frags;
@@ -3046,8 +2948,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
card->perf_stats.outbound_start_time = qeth_get_micros();
}
- if (skb_is_gso(skb))
- large_send = card->options.large_send;
+ large_send = skb_is_gso(skb);
if ((card->info.type == QETH_CARD_TYPE_IQD) && (!large_send) &&
(skb_shinfo(skb)->nr_frags == 0)) {
@@ -3096,7 +2997,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* fix hardware limitation: as long as we do not have sbal
* chaining we can not send long frag lists
*/
- if (large_send == QETH_LARGE_SEND_TSO) {
+ if (large_send) {
if (qeth_l3_tso_elements(new_skb) + 1 > 16) {
if (skb_linearize(new_skb))
goto tx_drop;
@@ -3105,8 +3006,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
}
- if ((large_send == QETH_LARGE_SEND_TSO) &&
- (cast_type == RTN_UNSPEC)) {
+ if (large_send && (cast_type == RTN_UNSPEC)) {
hdr = (struct qeth_hdr *)skb_push(new_skb,
sizeof(struct qeth_hdr_tso));
memset(hdr, 0, sizeof(struct qeth_hdr_tso));
@@ -3141,7 +3041,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (card->info.type != QETH_CARD_TYPE_IQD) {
int len;
- if (large_send == QETH_LARGE_SEND_TSO)
+ if (large_send)
len = ((unsigned long)tcp_hdr(new_skb) +
tcp_hdr(new_skb)->doff * 4) -
(unsigned long)new_skb->data;
@@ -3162,7 +3062,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (new_skb != skb)
dev_kfree_skb_any(skb);
if (card->options.performance_stats) {
- if (large_send != QETH_LARGE_SEND_NO) {
+ if (large_send) {
card->perf_stats.large_send_bytes += tx_bytes;
card->perf_stats.large_send_cnt++;
}
@@ -3248,65 +3148,42 @@ static int qeth_l3_stop(struct net_device *dev)
return 0;
}
-static u32 qeth_l3_ethtool_get_rx_csum(struct net_device *dev)
+static u32 qeth_l3_fix_features(struct net_device *dev, u32 features)
{
struct qeth_card *card = dev->ml_priv;
- return (card->options.checksum_type == HW_CHECKSUMMING);
-}
-
-static int qeth_l3_ethtool_set_rx_csum(struct net_device *dev, u32 data)
-{
- struct qeth_card *card = dev->ml_priv;
- enum qeth_checksum_types csum_type;
-
- if (data)
- csum_type = HW_CHECKSUMMING;
- else
- csum_type = SW_CHECKSUMMING;
+ if (!qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM))
+ features &= ~NETIF_F_IP_CSUM;
+ if (!qeth_is_supported(card, IPA_OUTBOUND_TSO))
+ features &= ~NETIF_F_TSO;
+ if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM))
+ features &= ~NETIF_F_RXCSUM;
- return qeth_l3_set_rx_csum(card, csum_type);
+ return features;
}
-static int qeth_l3_ethtool_set_tso(struct net_device *dev, u32 data)
+static int qeth_l3_set_features(struct net_device *dev, u32 features)
{
struct qeth_card *card = dev->ml_priv;
- int rc = 0;
+ u32 changed = dev->features ^ features;
+ int err;
- if (data) {
- rc = qeth_l3_set_large_send(card, QETH_LARGE_SEND_TSO);
- } else {
- dev->features &= ~NETIF_F_TSO;
- card->options.large_send = QETH_LARGE_SEND_NO;
- }
- return rc;
-}
+ if (!(changed & NETIF_F_RXCSUM))
+ return 0;
-static int qeth_l3_ethtool_set_tx_csum(struct net_device *dev, u32 data)
-{
- struct qeth_card *card = dev->ml_priv;
+ if (card->state == CARD_STATE_DOWN ||
+ card->state == CARD_STATE_RECOVER)
+ return 0;
- if (data) {
- if (qeth_is_supported(card, IPA_OUTBOUND_CHECKSUM))
- dev->features |= NETIF_F_IP_CSUM;
- else
- return -EPERM;
- } else
- dev->features &= ~NETIF_F_IP_CSUM;
+ err = qeth_l3_set_rx_csum(card, features & NETIF_F_RXCSUM);
+ if (err)
+ dev->features = features ^ NETIF_F_RXCSUM;
- return 0;
+ return err;
}
static const struct ethtool_ops qeth_l3_ethtool_ops = {
.get_link = ethtool_op_get_link,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = qeth_l3_ethtool_set_tx_csum,
- .get_rx_csum = qeth_l3_ethtool_get_rx_csum,
- .set_rx_csum = qeth_l3_ethtool_set_rx_csum,
- .get_sg = ethtool_op_get_sg,
- .set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
- .set_tso = qeth_l3_ethtool_set_tso,
.get_strings = qeth_core_get_strings,
.get_ethtool_stats = qeth_core_get_ethtool_stats,
.get_sset_count = qeth_core_get_sset_count,
@@ -3347,6 +3224,8 @@ static const struct net_device_ops qeth_l3_netdev_ops = {
.ndo_set_multicast_list = qeth_l3_set_multicast_list,
.ndo_do_ioctl = qeth_l3_do_ioctl,
.ndo_change_mtu = qeth_change_mtu,
+ .ndo_fix_features = qeth_l3_fix_features,
+ .ndo_set_features = qeth_l3_set_features,
.ndo_vlan_rx_register = qeth_l3_vlan_rx_register,
.ndo_vlan_rx_add_vid = qeth_l3_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = qeth_l3_vlan_rx_kill_vid,
@@ -3362,6 +3241,8 @@ static const struct net_device_ops qeth_l3_osa_netdev_ops = {
.ndo_set_multicast_list = qeth_l3_set_multicast_list,
.ndo_do_ioctl = qeth_l3_do_ioctl,
.ndo_change_mtu = qeth_change_mtu,
+ .ndo_fix_features = qeth_l3_fix_features,
+ .ndo_set_features = qeth_l3_set_features,
.ndo_vlan_rx_register = qeth_l3_vlan_rx_register,
.ndo_vlan_rx_add_vid = qeth_l3_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = qeth_l3_vlan_rx_kill_vid,
@@ -3392,8 +3273,12 @@ static int qeth_l3_setup_netdev(struct qeth_card *card)
if (!(card->info.unique_id & UNIQUE_ID_NOT_BY_CARD))
card->dev->dev_id = card->info.unique_id &
0xffff;
- if (!card->info.guestlan)
- card->dev->features |= NETIF_F_GRO;
+ if (!card->info.guestlan) {
+ card->dev->hw_features = NETIF_F_SG |
+ NETIF_F_RXCSUM | NETIF_F_IP_CSUM |
+ NETIF_F_TSO;
+ card->dev->features = NETIF_F_RXCSUM;
+ }
}
} else if (card->info.type == QETH_CARD_TYPE_IQD) {
card->dev = alloc_netdev(0, "hsi%d", ether_setup);
@@ -3426,15 +3311,13 @@ static int qeth_l3_probe_device(struct ccwgroup_device *gdev)
qeth_l3_create_device_attributes(&gdev->dev);
card->options.layer2 = 0;
+ card->info.hwtrap = 0;
card->discipline.start_poll = qeth_qdio_start_poll;
card->discipline.input_handler = (qdio_handler_t *)
qeth_qdio_input_handler;
card->discipline.output_handler = (qdio_handler_t *)
qeth_qdio_output_handler;
card->discipline.recover = qeth_l3_recover;
- if ((card->info.type == QETH_CARD_TYPE_OSD) ||
- (card->info.type == QETH_CARD_TYPE_OSX))
- card->options.checksum_type = HW_CHECKSUMMING;
return 0;
}
@@ -3480,13 +3363,18 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
goto out_remove;
}
- qeth_l3_query_ipassists(card, QETH_PROT_IPV4);
-
if (!card->dev && qeth_l3_setup_netdev(card)) {
rc = -ENODEV;
goto out_remove;
}
+ if (qeth_is_diagass_supported(card, QETH_DIAGS_CMD_TRAP)) {
+ if (card->info.hwtrap &&
+ qeth_hw_trap(card, QETH_DIAGS_TRAP_ARM))
+ card->info.hwtrap = 0;
+ } else
+ card->info.hwtrap = 0;
+
card->state = CARD_STATE_HARDSETUP;
memset(&card->rx, 0, sizeof(struct qeth_rx));
qeth_print_status_message(card);
@@ -3516,7 +3404,6 @@ contin:
rc = qeth_l3_start_ipassists(card);
if (rc)
QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
- qeth_l3_set_large_send(card, card->options.large_send);
rc = qeth_l3_setrouting_v4(card);
if (rc)
QETH_DBF_TEXT_(SETUP, 2, "4err%d", rc);
@@ -3589,6 +3476,10 @@ static int __qeth_l3_set_offline(struct ccwgroup_device *cgdev,
if (card->dev && netif_carrier_ok(card->dev))
netif_carrier_off(card->dev);
recover_flag = card->state;
+ if ((!recovery_mode && card->info.hwtrap) || card->info.hwtrap == 2) {
+ qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
+ card->info.hwtrap = 1;
+ }
qeth_l3_stop_card(card, recovery_mode);
rc = ccw_device_set_offline(CARD_DDEV(card));
rc2 = ccw_device_set_offline(CARD_WDEV(card));
@@ -3644,6 +3535,8 @@ static int qeth_l3_recover(void *ptr)
static void qeth_l3_shutdown(struct ccwgroup_device *gdev)
{
struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+ if ((gdev->state == CCWGROUP_ONLINE) && card->info.hwtrap)
+ qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
qeth_qdio_clear_card(card, 0);
qeth_clear_qdio_buffers(card);
}
@@ -3659,6 +3552,8 @@ static int qeth_l3_pm_suspend(struct ccwgroup_device *gdev)
if (gdev->state == CCWGROUP_OFFLINE)
return 0;
if (card->state == CARD_STATE_UP) {
+ if (card->info.hwtrap)
+ qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
__qeth_l3_set_offline(card->gdev, 1);
} else
__qeth_l3_set_offline(card->gdev, 0);
diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c
index 67cfa68dcf1b..cd99210296e2 100644
--- a/drivers/s390/net/qeth_l3_sys.c
+++ b/drivers/s390/net/qeth_l3_sys.c
@@ -15,16 +15,6 @@
#define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \
struct device_attribute dev_attr_##_id = __ATTR(_name, _mode, _show, _store)
-static const char *qeth_l3_get_checksum_str(struct qeth_card *card)
-{
- if (card->options.checksum_type == SW_CHECKSUMMING)
- return "sw";
- else if (card->options.checksum_type == HW_CHECKSUMMING)
- return "hw";
- else
- return "no";
-}
-
static ssize_t qeth_l3_dev_route_show(struct qeth_card *card,
struct qeth_routing_info *route, char *buf)
{
@@ -295,51 +285,6 @@ out:
static DEVICE_ATTR(canonical_macaddr, 0644, qeth_l3_dev_canonical_macaddr_show,
qeth_l3_dev_canonical_macaddr_store);
-static ssize_t qeth_l3_dev_checksum_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct qeth_card *card = dev_get_drvdata(dev);
-
- if (!card)
- return -EINVAL;
-
- return sprintf(buf, "%s checksumming\n",
- qeth_l3_get_checksum_str(card));
-}
-
-static ssize_t qeth_l3_dev_checksum_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct qeth_card *card = dev_get_drvdata(dev);
- enum qeth_checksum_types csum_type;
- char *tmp;
- int rc = 0;
-
- if (!card)
- return -EINVAL;
-
- mutex_lock(&card->conf_mutex);
- tmp = strsep((char **) &buf, "\n");
- if (!strcmp(tmp, "sw_checksumming"))
- csum_type = SW_CHECKSUMMING;
- else if (!strcmp(tmp, "hw_checksumming"))
- csum_type = HW_CHECKSUMMING;
- else if (!strcmp(tmp, "no_checksumming"))
- csum_type = NO_CHECKSUMMING;
- else {
- rc = -EINVAL;
- goto out;
- }
-
- rc = qeth_l3_set_rx_csum(card, csum_type);
-out:
- mutex_unlock(&card->conf_mutex);
- return rc ? rc : count;
-}
-
-static DEVICE_ATTR(checksumming, 0644, qeth_l3_dev_checksum_show,
- qeth_l3_dev_checksum_store);
-
static ssize_t qeth_l3_dev_sniffer_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -402,61 +347,13 @@ out:
static DEVICE_ATTR(sniffer, 0644, qeth_l3_dev_sniffer_show,
qeth_l3_dev_sniffer_store);
-static ssize_t qeth_l3_dev_large_send_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct qeth_card *card = dev_get_drvdata(dev);
-
- if (!card)
- return -EINVAL;
-
- switch (card->options.large_send) {
- case QETH_LARGE_SEND_NO:
- return sprintf(buf, "%s\n", "no");
- case QETH_LARGE_SEND_TSO:
- return sprintf(buf, "%s\n", "TSO");
- default:
- return sprintf(buf, "%s\n", "N/A");
- }
-}
-
-static ssize_t qeth_l3_dev_large_send_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct qeth_card *card = dev_get_drvdata(dev);
- enum qeth_large_send_types type;
- int rc = 0;
- char *tmp;
-
- if (!card)
- return -EINVAL;
- tmp = strsep((char **) &buf, "\n");
- if (!strcmp(tmp, "no"))
- type = QETH_LARGE_SEND_NO;
- else if (!strcmp(tmp, "TSO"))
- type = QETH_LARGE_SEND_TSO;
- else
- return -EINVAL;
-
- mutex_lock(&card->conf_mutex);
- if (card->options.large_send != type)
- rc = qeth_l3_set_large_send(card, type);
- mutex_unlock(&card->conf_mutex);
- return rc ? rc : count;
-}
-
-static DEVICE_ATTR(large_send, 0644, qeth_l3_dev_large_send_show,
- qeth_l3_dev_large_send_store);
-
static struct attribute *qeth_l3_device_attrs[] = {
&dev_attr_route4.attr,
&dev_attr_route6.attr,
&dev_attr_fake_broadcast.attr,
&dev_attr_broadcast_mode.attr,
&dev_attr_canonical_macaddr.attr,
- &dev_attr_checksumming.attr,
&dev_attr_sniffer.attr,
- &dev_attr_large_send.attr,
NULL,
};
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 4ff26521d75f..3382475dc22d 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -59,7 +59,6 @@
#ifndef AAC_DRIVER_BRANCH
#define AAC_DRIVER_BRANCH ""
#endif
-#define AAC_DRIVER_BUILD_DATE __DATE__ " " __TIME__
#define AAC_DRIVERNAME "aacraid"
#ifdef AAC_DRIVER_BUILD
@@ -67,7 +66,7 @@
#define str(x) _str(x)
#define AAC_DRIVER_FULL_VERSION AAC_DRIVER_VERSION "[" str(AAC_DRIVER_BUILD) "]" AAC_DRIVER_BRANCH
#else
-#define AAC_DRIVER_FULL_VERSION AAC_DRIVER_VERSION AAC_DRIVER_BRANCH " " AAC_DRIVER_BUILD_DATE
+#define AAC_DRIVER_FULL_VERSION AAC_DRIVER_VERSION AAC_DRIVER_BRANCH
#endif
MODULE_AUTHOR("Red Hat Inc and Adaptec");
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c
index 078ed600f47a..232aff1fe784 100644
--- a/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c
@@ -1,5 +1,5 @@
/*
- * Aic7xxx SCSI host adapter firmware asssembler symbol table implementation
+ * Aic7xxx SCSI host adapter firmware assembler symbol table implementation
*
* Copyright (c) 1997 Justin T. Gibbs.
* Copyright (c) 2002 Adaptec Inc.
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h
index 2ba73ae7c777..34bbcad7f83f 100644
--- a/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h
@@ -1,5 +1,5 @@
/*
- * Aic7xxx SCSI host adapter firmware asssembler symbol table definitions
+ * Aic7xxx SCSI host adapter firmware assembler symbol table definitions
*
* Copyright (c) 1997 Justin T. Gibbs.
* Copyright (c) 2002 Adaptec Inc.
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index da7b9887ec48..f980600f78a8 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -75,8 +75,10 @@ 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 = 12;
+
+#define ARCMSR_SLEEPTIME 10
+#define ARCMSR_RETRYCOUNT 12
+
wait_queue_head_t wait_q;
static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
struct scsi_cmnd *cmd);
@@ -171,24 +173,6 @@ static struct pci_driver arcmsr_pci_driver = {
****************************************************************************
****************************************************************************
*/
-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);
- }
- return 0;
-}
static void arcmsr_free_hbb_mu(struct AdapterControlBlock *acb)
{
@@ -323,66 +307,64 @@ static void arcmsr_define_adapter_type(struct AdapterControlBlock *acb)
default: acb->adapter_type = ACB_ADAPTER_TYPE_A;
}
-}
+}
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*/
+ int i;
+
+ for (i = 0; i < 2000; i++) {
+ if (readl(&reg->outbound_intstatus) &
+ ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
+ writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT,
+ &reg->outbound_intstatus);
+ return true;
+ }
+ msleep(10);
+ } /* max 20 seconds */
- } while (Retries++ < 20);/*max 20 sec*/
return false;
}
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*/
+ int i;
+
+ for (i = 0; i < 2000; i++) {
+ 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 20 seconds */
- } while (Retries++ < 20);/*max 20 sec*/
return false;
}
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*/
+ int i;
+
+ for (i = 0; i < 2000; i++) {
+ 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;
+ }
+ msleep(10);
+ } /* max 20 seconds */
+
return false;
}
+
static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb)
{
struct MessageUnit_A __iomem *reg = acb->pmuA;
@@ -459,10 +441,11 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
struct CommandControlBlock *ccb_tmp;
int i = 0, j = 0;
dma_addr_t cdb_phyaddr;
- unsigned long roundup_ccbsize = 0, offset;
+ unsigned long roundup_ccbsize;
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;
@@ -472,23 +455,20 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
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);
+ 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;
+ acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM;
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);
+ 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++){
@@ -2602,12 +2582,8 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
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);
- }
+ printk(KERN_NOTICE "arcmsr%d: cdb_phyaddr_hi32=0x%x\n",
+ acb->adapter_index, cdb_phyaddr_hi32);
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);
@@ -2955,12 +2931,12 @@ static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
arcmsr_hardware_reset(acb);
acb->acb_flags &= ~ACB_F_IOP_INITED;
sleep_again:
- arcmsr_sleep_for_bus_reset(cmd);
+ ssleep(ARCMSR_SLEEPTIME);
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) {
+ printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d\n", acb->host->host_no, retry_count);
+ if (retry_count > ARCMSR_RETRYCOUNT) {
acb->fw_flag = FW_DEADLOCK;
- printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!! \n", acb->host->host_no);
+ printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!!\n", acb->host->host_no);
return FAILED;
}
retry_count++;
@@ -3025,12 +3001,12 @@ sleep_again:
arcmsr_hardware_reset(acb);
acb->acb_flags &= ~ACB_F_IOP_INITED;
sleep:
- arcmsr_sleep_for_bus_reset(cmd);
+ ssleep(ARCMSR_SLEEPTIME);
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) {
+ printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d\n", acb->host->host_no, retry_count);
+ if (retry_count > ARCMSR_RETRYCOUNT) {
acb->fw_flag = FW_DEADLOCK;
- printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!! \n", acb->host->host_no);
+ printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!!\n", acb->host->host_no);
return FAILED;
}
retry_count++;
diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h
index 1cb8a5e85c7f..1d7b976c850f 100644
--- a/drivers/scsi/be2iscsi/be.h
+++ b/drivers/scsi/be2iscsi/be.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2010 ServerEngines
+ * Copyright (C) 2005 - 2011 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -8,11 +8,11 @@
* Public License is included in this distribution in the file called COPYING.
*
* Contact Information:
- * linux-drivers@serverengines.com
+ * linux-drivers@emulex.com
*
- * ServerEngines
- * 209 N. Fair Oaks Ave
- * Sunnyvale, CA 94085
+ * Emulex
+ * 3333 Susan Street
+ * Costa Mesa, CA 92626
*/
#ifndef BEISCSI_H
diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c
index ad246369d373..b8a82f2c62c8 100644
--- a/drivers/scsi/be2iscsi/be_cmds.c
+++ b/drivers/scsi/be2iscsi/be_cmds.c
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2010 ServerEngines
+ * Copyright (C) 2005 - 2011 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -8,11 +8,11 @@
* Public License is included in this distribution in the file called COPYING.
*
* Contact Information:
- * linux-drivers@serverengines.com
+ * linux-drivers@emulex.com
*
- * ServerEngines
- * 209 N. Fair Oaks Ave
- * Sunnyvale, CA 94085
+ * Emulex
+ * 3333 Susan Street
+ * Costa Mesa, CA 92626
*/
#include "be.h"
@@ -458,6 +458,7 @@ void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr,
req_hdr->opcode = opcode;
req_hdr->subsystem = subsystem;
req_hdr->request_length = cpu_to_le32(cmd_len - sizeof(*req_hdr));
+ req_hdr->timeout = 120;
}
static void be_cmd_page_addrs_prepare(struct phys_addr *pages, u32 max_pages,
diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h
index fbd1dc2c15f7..497eb29e5c9e 100644
--- a/drivers/scsi/be2iscsi/be_cmds.h
+++ b/drivers/scsi/be2iscsi/be_cmds.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2010 ServerEngines
+ * Copyright (C) 2005 - 2011 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -8,11 +8,11 @@
* Public License is included in this distribution in the file called COPYING.
*
* Contact Information:
- * linux-drivers@serverengines.com
+ * linux-drivers@emulex.com
*
- * ServerEngines
- * 209 N. Fair Oaks Ave
- * Sunnyvale, CA 94085
+ * Emulex
+ * 3333 Susan Street
+ * Costa Mesa, CA 92626
*/
#ifndef BEISCSI_CMDS_H
diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c
index 868cc5590145..3cad10605023 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.c
+++ b/drivers/scsi/be2iscsi/be_iscsi.c
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2010 ServerEngines
+ * Copyright (C) 2005 - 2011 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -7,15 +7,14 @@
* as published by the Free Software Foundation. The full GNU General
* Public License is included in this distribution in the file called COPYING.
*
- * Written by: Jayamohan Kallickal (jayamohank@serverengines.com)
+ * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com)
*
* Contact Information:
- * linux-drivers@serverengines.com
- *
- * ServerEngines
- * 209 N. Fair Oaks Ave
- * Sunnyvale, CA 94085
+ * linux-drivers@emulex.com
*
+ * Emulex
+ * 3333 Susan Street
+ * Costa Mesa, CA 92626
*/
#include <scsi/libiscsi.h>
diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h
index 9c532797c29e..ff60b7fd92d6 100644
--- a/drivers/scsi/be2iscsi/be_iscsi.h
+++ b/drivers/scsi/be2iscsi/be_iscsi.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2010 ServerEngines
+ * Copyright (C) 2005 - 2011 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -7,15 +7,14 @@
* as published by the Free Software Foundation. The full GNU General
* Public License is included in this distribution in the file called COPYING.
*
- * Written by: Jayamohan Kallickal (jayamohank@serverengines.com)
+ * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com)
*
* Contact Information:
- * linux-drivers@serverengines.com
- *
- * ServerEngines
- * 209 N. Fair Oaks Ave
- * Sunnyvale, CA 94085
+ * linux-drivers@emulex.com
*
+ * Emulex
+ * 3333 Susan Street
+ * Costa Mesa, CA 92626
*/
#ifndef _BE_ISCSI_
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 24e20ba9633c..94b9a07845d5 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2010 ServerEngines
+ * Copyright (C) 2005 - 2011 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -7,16 +7,16 @@
* as published by the Free Software Foundation. The full GNU General
* Public License is included in this distribution in the file called COPYING.
*
- * Written by: Jayamohan Kallickal (jayamohank@serverengines.com)
+ * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com)
*
* Contact Information:
- * linux-drivers@serverengines.com
- *
- * ServerEngines
- * 209 N. Fair Oaks Ave
- * Sunnyvale, CA 94085
+ * linux-drivers@emulex.com
*
+ * Emulex
+ * 3333 Susan Street
+ * Costa Mesa, CA 92626
*/
+
#include <linux/reboot.h>
#include <linux/delay.h>
#include <linux/slab.h>
@@ -420,7 +420,8 @@ static int beiscsi_setup_boot_info(struct beiscsi_hba *phba)
return 0;
free_kset:
- iscsi_boot_destroy_kset(phba->boot_kset);
+ if (phba->boot_kset)
+ iscsi_boot_destroy_kset(phba->boot_kset);
return -ENOMEM;
}
@@ -618,7 +619,7 @@ static void beiscsi_get_params(struct beiscsi_hba *phba)
+ BE2_NOPOUT_REQ));
phba->params.cxns_per_ctrl = phba->fw_config.iscsi_cid_count;
phba->params.asyncpdus_per_ctrl = phba->fw_config.iscsi_cid_count * 2;
- phba->params.icds_per_ctrl = phba->fw_config.iscsi_icd_count;;
+ phba->params.icds_per_ctrl = phba->fw_config.iscsi_icd_count;
phba->params.num_sge_per_io = BE2_SGE;
phba->params.defpdu_hdr_sz = BE2_DEFPDU_HDR_SZ;
phba->params.defpdu_data_sz = BE2_DEFPDU_DATA_SZ;
@@ -781,7 +782,7 @@ static irqreturn_t be_isr(int irq, void *dev_id)
int isr;
phba = dev_id;
- ctrl = &phba->ctrl;;
+ ctrl = &phba->ctrl;
isr = ioread32(ctrl->csr + CEV_ISR0_OFFSET +
(PCI_FUNC(ctrl->pdev->devfn) * CEV_ISR_SIZE));
if (!isr)
@@ -3464,23 +3465,23 @@ static void 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);
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);
iowrite32(reg, addr);
- if (!phba->msix_enabled) {
- eq = &phwi_context->be_eq[0].q;
+ }
+
+ if (!phba->msix_enabled) {
+ eq = &phwi_context->be_eq[0].q;
+ 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);
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);
- hwi_ring_eq_db(phba, eq->id, 0, 0, 1, 1);
- }
}
}
}
@@ -4019,12 +4020,17 @@ static int beiscsi_mtask(struct iscsi_task *task)
hwi_write_buffer(pwrb, task);
break;
case ISCSI_OP_NOOP_OUT:
- AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
- INI_RD_CMD);
- if (task->hdr->ttt == ISCSI_RESERVED_TAG)
+ if (task->hdr->ttt != ISCSI_RESERVED_TAG) {
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
+ TGT_DM_CMD);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt,
+ pwrb, 0);
AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0);
- else
+ } else {
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
+ INI_RD_CMD);
AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 1);
+ }
hwi_write_buffer(pwrb, task);
break;
case ISCSI_OP_TEXT:
@@ -4144,10 +4150,11 @@ static void beiscsi_remove(struct pci_dev *pcidev)
phba->ctrl.mbox_mem_alloced.size,
phba->ctrl.mbox_mem_alloced.va,
phba->ctrl.mbox_mem_alloced.dma);
+ if (phba->boot_kset)
+ iscsi_boot_destroy_kset(phba->boot_kset);
iscsi_host_remove(phba->shost);
pci_dev_put(phba->pcidev);
iscsi_host_free(phba->shost);
- iscsi_boot_destroy_kset(phba->boot_kset);
}
static void beiscsi_msix_enable(struct beiscsi_hba *phba)
diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h
index 90eb74f6bcab..081c171a1ed6 100644
--- a/drivers/scsi/be2iscsi/be_main.h
+++ b/drivers/scsi/be2iscsi/be_main.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2010 ServerEngines
+ * Copyright (C) 2005 - 2011 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -7,15 +7,14 @@
* as published by the Free Software Foundation. The full GNU General
* Public License is included in this distribution in the file called COPYING.
*
- * Written by: Jayamohan Kallickal (jayamohank@serverengines.com)
+ * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com)
*
* Contact Information:
- * linux-drivers@serverengines.com
- *
- * ServerEngines
- * 209 N. Fair Oaks Ave
- * Sunnyvale, CA 94085
+ * linux-drivers@emulex.com
*
+ * Emulex
+ * 3333 Susan Street
+ * Costa Mesa, CA 92626
*/
#ifndef _BEISCSI_MAIN_
@@ -35,7 +34,7 @@
#include "be.h"
#define DRV_NAME "be2iscsi"
-#define BUILD_STR "2.0.549.0"
+#define BUILD_STR "2.103.298.0"
#define BE_NAME "ServerEngines BladeEngine2" \
"Linux iSCSI Driver version" BUILD_STR
#define DRV_DESC BE_NAME " " "Driver"
diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c
index 877324fc594c..44762cfa3e12 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.c
+++ b/drivers/scsi/be2iscsi/be_mgmt.c
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2010 ServerEngines
+ * Copyright (C) 2005 - 2011 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -7,15 +7,14 @@
* as published by the Free Software Foundation. The full GNU General
* Public License is included in this distribution in the file called COPYING.
*
- * Written by: Jayamohan Kallickal (jayamohank@serverengines.com)
+ * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com)
*
* Contact Information:
- * linux-drivers@serverengines.com
- *
- * ServerEngines
- * 209 N. Fair Oaks Ave
- * Sunnyvale, CA 94085
+ * linux-drivers@emulex.com
*
+ * Emulex
+ * 3333 Susan Street
+ * Costa Mesa, CA 92626
*/
#include "be_mgmt.h"
@@ -203,8 +202,8 @@ int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute)
OPCODE_COMMON_ISCSI_CLEANUP, sizeof(*req));
req->chute = chute;
- req->hdr_ring_id = 0;
- req->data_ring_id = 0;
+ req->hdr_ring_id = cpu_to_le16(HWI_GET_DEF_HDRQ_ID(phba));
+ req->data_ring_id = cpu_to_le16(HWI_GET_DEF_BUFQ_ID(phba));
status = be_mcc_notify_wait(phba);
if (status)
diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h
index b9acedf78653..08428824ace2 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.h
+++ b/drivers/scsi/be2iscsi/be_mgmt.h
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2005 - 2010 ServerEngines
+ * Copyright (C) 2005 - 2011 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -7,15 +7,14 @@
* as published by the Free Software Foundation. The full GNU General
* Public License is included in this distribution in the file called COPYING.
*
- * Written by: Jayamohan Kallickal (jayamohank@serverengines.com)
+ * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com)
*
* Contact Information:
- * linux-drivers@serverengines.com
- *
- * ServerEngines
- * 209 N. Fair Oaks Ave
- * Sunnyvale, CA 94085
+ * linux-drivers@emulex.com
*
+ * Emulex
+ * 3333 Susan Street
+ * Costa Mesa, CA 92626
*/
#ifndef _BEISCSI_MGMT_
diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c
index 0fd510a01561..59b5e9b61d71 100644
--- a/drivers/scsi/bfa/bfad.c
+++ b/drivers/scsi/bfa/bfad.c
@@ -57,9 +57,19 @@ int pcie_max_read_reqsz;
int bfa_debugfs_enable = 1;
int msix_disable_cb = 0, msix_disable_ct = 0;
+/* Firmware releated */
u32 bfi_image_ct_fc_size, bfi_image_ct_cna_size, bfi_image_cb_fc_size;
u32 *bfi_image_ct_fc, *bfi_image_ct_cna, *bfi_image_cb_fc;
+#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"
+
+static u32 *bfad_load_fwimg(struct pci_dev *pdev);
+static void bfad_free_fwimg(void);
+static void bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
+ u32 *bfi_image_size, char *fw_name);
+
static const char *msix_name_ct[] = {
"cpe0", "cpe1", "cpe2", "cpe3",
"rme0", "rme1", "rme2", "rme3",
@@ -222,6 +232,9 @@ bfad_sm_created(struct bfad_s *bfad, enum bfad_sm_event event)
if ((bfad->bfad_flags & BFAD_HAL_INIT_DONE)) {
bfa_sm_send_event(bfad, BFAD_E_INIT_SUCCESS);
} else {
+ printk(KERN_WARNING
+ "bfa %s: bfa init failed\n",
+ bfad->pci_name);
bfad->bfad_flags |= BFAD_HAL_INIT_FAIL;
bfa_sm_send_event(bfad, BFAD_E_INIT_FAILED);
}
@@ -991,10 +1004,6 @@ bfad_cfg_pport(struct bfad_s *bfad, enum bfa_lport_role role)
bfad->pport.roles |= BFA_LPORT_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:
@@ -1004,10 +1013,6 @@ 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 ((supported_fc4s & BFA_LPORT_ROLE_FCP_IM) &&
(bfad->pport.roles & BFA_LPORT_ROLE_FCP_IM)) {
bfad_im_scsi_host_free(bfad, bfad->pport.im_port);
@@ -1389,6 +1394,10 @@ bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
bfad->pport.bfad = bfad;
INIT_LIST_HEAD(&bfad->pbc_vport_list);
+ /* Setup the debugfs node for this bfad */
+ if (bfa_debugfs_enable)
+ bfad_debugfs_init(&bfad->pport);
+
retval = bfad_drv_init(bfad);
if (retval != BFA_STATUS_OK)
goto out_drv_init_failure;
@@ -1404,6 +1413,9 @@ out_bfad_sm_failure:
bfa_detach(&bfad->bfa);
bfad_hal_mem_release(bfad);
out_drv_init_failure:
+ /* Remove the debugfs node for this bfad */
+ kfree(bfad->regdata);
+ bfad_debugfs_exit(&bfad->pport);
mutex_lock(&bfad_mutex);
bfad_inst--;
list_del(&bfad->list_entry);
@@ -1445,6 +1457,10 @@ bfad_pci_remove(struct pci_dev *pdev)
spin_unlock_irqrestore(&bfad->bfad_lock, flags);
bfad_hal_mem_release(bfad);
+ /* Remove the debugfs node for this bfad */
+ kfree(bfad->regdata);
+ bfad_debugfs_exit(&bfad->pport);
+
/* Cleaning the BFAD instance */
mutex_lock(&bfad_mutex);
bfad_inst--;
@@ -1550,7 +1566,7 @@ bfad_exit(void)
}
/* Firmware handling */
-u32 *
+static void
bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
u32 *bfi_image_size, char *fw_name)
{
@@ -1558,27 +1574,25 @@ bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
if (request_firmware(&fw, fw_name, &pdev->dev)) {
printk(KERN_ALERT "Can't locate firmware %s\n", fw_name);
- goto error;
+ *bfi_image = NULL;
+ goto out;
}
*bfi_image = vmalloc(fw->size);
if (NULL == *bfi_image) {
printk(KERN_ALERT "Fail to allocate buffer for fw image "
"size=%x!\n", (u32) fw->size);
- goto error;
+ goto out;
}
memcpy(*bfi_image, fw->data, fw->size);
*bfi_image_size = fw->size/sizeof(u32);
-
- return *bfi_image;
-
-error:
- return NULL;
+out:
+ release_firmware(fw);
}
-u32 *
-bfad_get_firmware_buf(struct pci_dev *pdev)
+static u32 *
+bfad_load_fwimg(struct pci_dev *pdev)
{
if (pdev->device == BFA_PCI_DEVICE_ID_CT_FC) {
if (bfi_image_ct_fc_size == 0)
@@ -1598,6 +1612,17 @@ bfad_get_firmware_buf(struct pci_dev *pdev)
}
}
+static void
+bfad_free_fwimg(void)
+{
+ 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);
+}
+
module_init(bfad_init);
module_exit(bfad_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/bfa/bfad_debugfs.c b/drivers/scsi/bfa/bfad_debugfs.c
index c66e32eced7b..48be0c54f2de 100644
--- a/drivers/scsi/bfa/bfad_debugfs.c
+++ b/drivers/scsi/bfa/bfad_debugfs.c
@@ -28,10 +28,10 @@
* 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#
+ * - bfa/pci_dev:<pci_name>
+ * where the pci_name corresponds to the one under /sys/bus/pci/drivers/bfa
*
- * Debugging service available per host:
+ * Debugging service available per pci_dev:
* 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.
@@ -489,11 +489,9 @@ 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;
+ struct bfad_s *bfad = port->bfad;
const struct bfad_debugfs_entry *file;
- char name[16];
+ char name[64];
int i;
if (!bfa_debugfs_enable)
@@ -510,17 +508,15 @@ bfad_debugfs_init(struct bfad_port_s *port)
}
}
- /*
- * 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);
+ /* Setup the pci_dev debugfs directory for the port */
+ snprintf(name, sizeof(name), "pci_dev:%s", bfad->pci_name);
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");
+ "bfa %s: debugfs root creation failed\n",
+ bfad->pci_name);
goto err;
}
@@ -536,8 +532,8 @@ bfad_debugfs_init(struct bfad_port_s *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);
+ "bfa %s: debugfs %s creation failed\n",
+ bfad->pci_name, file->name);
goto err;
}
}
@@ -550,8 +546,7 @@ err:
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;
+ struct bfad_s *bfad = port->bfad;
int i;
for (i = 0; i < ARRAY_SIZE(bfad_debugfs_files); i++) {
@@ -562,9 +557,7 @@ bfad_debugfs_exit(struct bfad_port_s *port)
}
/*
- * Remove the host# directory for the port,
- * corresponds to the scsi_host num of this port.
- */
+ * Remove the pci_dev debugfs directory for the port */
if (port->port_debugfs_root) {
debugfs_remove(port->port_debugfs_root);
port->port_debugfs_root = NULL;
diff --git a/drivers/scsi/bfa/bfad_im.h b/drivers/scsi/bfa/bfad_im.h
index bfee63b16fa9..c296c8968511 100644
--- a/drivers/scsi/bfa/bfad_im.h
+++ b/drivers/scsi/bfa/bfad_im.h
@@ -141,29 +141,4 @@ extern struct device_attribute *bfad_im_vport_attrs[];
irqreturn_t bfad_intx(int irq, void *dev_id);
-/* Firmware releated */
-#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"
-
-u32 *bfad_get_firmware_buf(struct pci_dev *pdev);
-u32 *bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
- u32 *bfi_image_size, char *fw_name);
-
-static inline u32 *
-bfad_load_fwimg(struct pci_dev *pdev)
-{
- return bfad_get_firmware_buf(pdev);
-}
-
-static inline void
-bfad_free_fwimg(void)
-{
- 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/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h
index b6d350ac4288..0a404bfb44fe 100644
--- a/drivers/scsi/bnx2fc/bnx2fc.h
+++ b/drivers/scsi/bnx2fc/bnx2fc.h
@@ -130,7 +130,7 @@
#define BNX2FC_TM_TIMEOUT 60 /* secs */
#define BNX2FC_IO_TIMEOUT 20000UL /* msecs */
-#define BNX2FC_WAIT_CNT 120
+#define BNX2FC_WAIT_CNT 1200
#define BNX2FC_FW_TIMEOUT (3 * HZ)
#define PORT_MAX 2
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
index e2e647509a73..ab255fbc7f36 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@ -664,7 +664,7 @@ static void bnx2fc_link_speed_update(struct fc_lport *lport)
struct fcoe_port *port = lport_priv(lport);
struct bnx2fc_hba *hba = port->priv;
struct net_device *netdev = hba->netdev;
- struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+ struct ethtool_cmd ecmd;
if (!dev_ethtool_get_settings(netdev, &ecmd)) {
lport->link_supported_speeds &=
@@ -675,12 +675,15 @@ static void bnx2fc_link_speed_update(struct fc_lport *lport)
if (ecmd.supported & SUPPORTED_10000baseT_Full)
lport->link_supported_speeds |= FC_PORTSPEED_10GBIT;
- if (ecmd.speed == SPEED_1000)
+ switch (ethtool_cmd_speed(&ecmd)) {
+ case SPEED_1000:
lport->link_speed = FC_PORTSPEED_1GBIT;
- if (ecmd.speed == SPEED_10000)
+ break;
+ case SPEED_10000:
lport->link_speed = FC_PORTSPEED_10GBIT;
+ break;
+ }
}
- return;
}
static int bnx2fc_link_ok(struct fc_lport *lport)
{
@@ -1130,7 +1133,7 @@ static void bnx2fc_interface_release(struct kref *kref)
struct net_device *phys_dev;
hba = container_of(kref, struct bnx2fc_hba, kref);
- BNX2FC_HBA_DBG(hba->ctlr.lp, "Interface is being released\n");
+ BNX2FC_MISC_DBG("Interface is being released\n");
netdev = hba->netdev;
phys_dev = hba->phys_dev;
@@ -1254,20 +1257,17 @@ setup_err:
static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba,
struct device *parent, int npiv)
{
- struct fc_lport *lport = NULL;
+ struct fc_lport *lport, *n_port;
struct fcoe_port *port;
struct Scsi_Host *shost;
struct fc_vport *vport = dev_to_vport(parent);
int rc = 0;
/* Allocate Scsi_Host structure */
- if (!npiv) {
- lport = libfc_host_alloc(&bnx2fc_shost_template,
- sizeof(struct fcoe_port));
- } else {
- lport = libfc_vport_create(vport,
- sizeof(struct fcoe_port));
- }
+ if (!npiv)
+ lport = libfc_host_alloc(&bnx2fc_shost_template, sizeof(*port));
+ else
+ lport = libfc_vport_create(vport, sizeof(*port));
if (!lport) {
printk(KERN_ERR PFX "could not allocate scsi host structure\n");
@@ -1285,7 +1285,6 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba,
goto lp_config_err;
if (npiv) {
- vport = dev_to_vport(parent);
printk(KERN_ERR PFX "Setting vport names, 0x%llX 0x%llX\n",
vport->node_name, vport->port_name);
fc_set_wwnn(lport, vport->node_name);
@@ -1314,12 +1313,17 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba,
fc_host_port_type(lport->host) = FC_PORTTYPE_UNKNOWN;
/* Allocate exchange manager */
- if (!npiv) {
+ if (!npiv)
rc = bnx2fc_em_config(lport);
- if (rc) {
- printk(KERN_ERR PFX "Error on bnx2fc_em_config\n");
- goto shost_err;
- }
+ else {
+ shost = vport_to_shost(vport);
+ n_port = shost_priv(shost);
+ rc = fc_exch_mgr_list_clone(n_port, lport);
+ }
+
+ if (rc) {
+ printk(KERN_ERR PFX "Error on bnx2fc_em_config\n");
+ goto shost_err;
}
bnx2fc_interface_get(hba);
@@ -1352,8 +1356,6 @@ static void bnx2fc_if_destroy(struct fc_lport *lport)
/* Free existing transmit skbs */
fcoe_clean_pending_queue(lport);
- bnx2fc_interface_put(hba);
-
/* Free queued packets for the receive thread */
bnx2fc_clean_rx_queue(lport);
@@ -1372,6 +1374,8 @@ static void bnx2fc_if_destroy(struct fc_lport *lport)
/* Release Scsi_Host */
scsi_host_put(lport->host);
+
+ bnx2fc_interface_put(hba);
}
/**
diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
index 1b680e288c56..f756d5f85c7a 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
@@ -522,6 +522,7 @@ void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt,
fp = fc_frame_alloc(lport, payload_len);
if (!fp) {
printk(KERN_ERR PFX "fc_frame_alloc failure\n");
+ kfree(unsol_els);
return;
}
@@ -547,6 +548,7 @@ void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt,
*/
printk(KERN_ERR PFX "dropping ELS 0x%x\n", op);
kfree_skb(skb);
+ kfree(unsol_els);
return;
}
}
@@ -563,6 +565,7 @@ void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt,
} else {
BNX2FC_HBA_DBG(lport, "fh_r_ctl = 0x%x\n", fh->fh_r_ctl);
kfree_skb(skb);
+ kfree(unsol_els);
}
}
diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c
index 1decefbf32e3..b5b5c346d779 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_io.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_io.c
@@ -1663,6 +1663,12 @@ int bnx2fc_queuecommand(struct Scsi_Host *host,
tgt = (struct bnx2fc_rport *)&rp[1];
if (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) {
+ if (test_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags)) {
+ sc_cmd->result = DID_NO_CONNECT << 16;
+ sc_cmd->scsi_done(sc_cmd);
+ return 0;
+
+ }
/*
* Session is not offloaded yet. Let SCSI-ml retry
* the command.
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index d0c82340f0e2..450e011f981a 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -34,7 +34,7 @@
static const char * cdb_byte0_names[] = {
/* 00-03 */ "Test Unit Ready", "Rezero Unit/Rewind", NULL, "Request Sense",
/* 04-07 */ "Format Unit/Medium", "Read Block Limits", NULL,
- "Reasssign Blocks",
+ "Reassign Blocks",
/* 08-0d */ "Read(6)", NULL, "Write(6)", "Seek(6)", NULL, NULL,
/* 0e-12 */ NULL, "Read Reverse", "Write Filemarks", "Space", "Inquiry",
/* 13-16 */ "Verify(6)", "Recover Buffered Data", "Mode Select(6)",
@@ -772,6 +772,7 @@ static const struct error_info additional[] =
{0x3802, "Esn - power management class event"},
{0x3804, "Esn - media class event"},
{0x3806, "Esn - device busy class event"},
+ {0x3807, "Thin Provisioning soft threshold reached"},
{0x3900, "Saving parameters not supported"},
diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c
index de764ea7419d..a2a9c7c6c643 100644
--- a/drivers/scsi/cxgbi/libcxgbi.c
+++ b/drivers/scsi/cxgbi/libcxgbi.c
@@ -450,12 +450,13 @@ static struct cxgbi_sock *cxgbi_sock_create(struct cxgbi_device *cdev)
return csk;
}
-static struct rtable *find_route_ipv4(__be32 saddr, __be32 daddr,
+static struct rtable *find_route_ipv4(struct flowi4 *fl4,
+ __be32 saddr, __be32 daddr,
__be16 sport, __be16 dport, u8 tos)
{
struct rtable *rt;
- rt = ip_route_output_ports(&init_net, NULL, daddr, saddr,
+ rt = ip_route_output_ports(&init_net, fl4, NULL, daddr, saddr,
dport, sport, IPPROTO_TCP, tos, 0);
if (IS_ERR(rt))
return NULL;
@@ -470,6 +471,7 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr)
struct net_device *ndev;
struct cxgbi_device *cdev;
struct rtable *rt = NULL;
+ struct flowi4 fl4;
struct cxgbi_sock *csk = NULL;
unsigned int mtu = 0;
int port = 0xFFFF;
@@ -482,7 +484,7 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr)
goto err_out;
}
- rt = find_route_ipv4(0, daddr->sin_addr.s_addr, 0, daddr->sin_port, 0);
+ rt = find_route_ipv4(&fl4, 0, daddr->sin_addr.s_addr, 0, daddr->sin_port, 0);
if (!rt) {
pr_info("no route to ipv4 0x%x, port %u.\n",
daddr->sin_addr.s_addr, daddr->sin_port);
@@ -531,7 +533,7 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr)
csk->daddr.sin_addr.s_addr = daddr->sin_addr.s_addr;
csk->daddr.sin_port = daddr->sin_port;
csk->daddr.sin_family = daddr->sin_family;
- csk->saddr.sin_addr.s_addr = rt->rt_src;
+ csk->saddr.sin_addr.s_addr = fl4.saddr;
return csk;
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index b10b3841535c..f5b718d3c31b 100644
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -778,8 +778,8 @@ static void srb_free_insert(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
static void srb_waiting_insert(struct DeviceCtlBlk *dcb,
struct ScsiReqBlk *srb)
{
- dprintkdbg(DBG_0, "srb_waiting_insert: (pid#%li) <%02i-%i> srb=%p\n",
- srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
+ dprintkdbg(DBG_0, "srb_waiting_insert: (0x%p) <%02i-%i> srb=%p\n",
+ srb->cmd, dcb->target_id, dcb->target_lun, srb);
list_add(&srb->list, &dcb->srb_waiting_list);
}
@@ -787,16 +787,16 @@ static void srb_waiting_insert(struct DeviceCtlBlk *dcb,
static void srb_waiting_append(struct DeviceCtlBlk *dcb,
struct ScsiReqBlk *srb)
{
- dprintkdbg(DBG_0, "srb_waiting_append: (pid#%li) <%02i-%i> srb=%p\n",
- srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
+ dprintkdbg(DBG_0, "srb_waiting_append: (0x%p) <%02i-%i> srb=%p\n",
+ srb->cmd, dcb->target_id, dcb->target_lun, srb);
list_add_tail(&srb->list, &dcb->srb_waiting_list);
}
static void srb_going_append(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
{
- dprintkdbg(DBG_0, "srb_going_append: (pid#%li) <%02i-%i> srb=%p\n",
- srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
+ dprintkdbg(DBG_0, "srb_going_append: (0x%p) <%02i-%i> srb=%p\n",
+ srb->cmd, dcb->target_id, dcb->target_lun, srb);
list_add_tail(&srb->list, &dcb->srb_going_list);
}
@@ -805,8 +805,8 @@ static void srb_going_remove(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
{
struct ScsiReqBlk *i;
struct ScsiReqBlk *tmp;
- dprintkdbg(DBG_0, "srb_going_remove: (pid#%li) <%02i-%i> srb=%p\n",
- srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
+ dprintkdbg(DBG_0, "srb_going_remove: (0x%p) <%02i-%i> srb=%p\n",
+ srb->cmd, dcb->target_id, dcb->target_lun, srb);
list_for_each_entry_safe(i, tmp, &dcb->srb_going_list, list)
if (i == srb) {
@@ -821,8 +821,8 @@ static void srb_waiting_remove(struct DeviceCtlBlk *dcb,
{
struct ScsiReqBlk *i;
struct ScsiReqBlk *tmp;
- dprintkdbg(DBG_0, "srb_waiting_remove: (pid#%li) <%02i-%i> srb=%p\n",
- srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
+ dprintkdbg(DBG_0, "srb_waiting_remove: (0x%p) <%02i-%i> srb=%p\n",
+ srb->cmd, dcb->target_id, dcb->target_lun, srb);
list_for_each_entry_safe(i, tmp, &dcb->srb_waiting_list, list)
if (i == srb) {
@@ -836,8 +836,8 @@ static void srb_going_to_waiting_move(struct DeviceCtlBlk *dcb,
struct ScsiReqBlk *srb)
{
dprintkdbg(DBG_0,
- "srb_going_to_waiting_move: (pid#%li) <%02i-%i> srb=%p\n",
- srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
+ "srb_going_to_waiting_move: (0x%p) <%02i-%i> srb=%p\n",
+ srb->cmd, dcb->target_id, dcb->target_lun, srb);
list_move(&srb->list, &dcb->srb_waiting_list);
}
@@ -846,8 +846,8 @@ static void srb_waiting_to_going_move(struct DeviceCtlBlk *dcb,
struct ScsiReqBlk *srb)
{
dprintkdbg(DBG_0,
- "srb_waiting_to_going_move: (pid#%li) <%02i-%i> srb=%p\n",
- srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
+ "srb_waiting_to_going_move: (0x%p) <%02i-%i> srb=%p\n",
+ srb->cmd, dcb->target_id, dcb->target_lun, srb);
list_move(&srb->list, &dcb->srb_going_list);
}
@@ -982,8 +982,8 @@ static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
{
int nseg;
enum dma_data_direction dir = cmd->sc_data_direction;
- dprintkdbg(DBG_0, "build_srb: (pid#%li) <%02i-%i>\n",
- cmd->serial_number, dcb->target_id, dcb->target_lun);
+ dprintkdbg(DBG_0, "build_srb: (0x%p) <%02i-%i>\n",
+ cmd, dcb->target_id, dcb->target_lun);
srb->dcb = dcb;
srb->cmd = cmd;
@@ -1086,8 +1086,8 @@ static int dc395x_queue_command_lck(struct scsi_cmnd *cmd, void (*done)(struct s
struct ScsiReqBlk *srb;
struct AdapterCtlBlk *acb =
(struct AdapterCtlBlk *)cmd->device->host->hostdata;
- dprintkdbg(DBG_0, "queue_command: (pid#%li) <%02i-%i> cmnd=0x%02x\n",
- cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+ dprintkdbg(DBG_0, "queue_command: (0x%p) <%02i-%i> cmnd=0x%02x\n",
+ cmd, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
/* Assume BAD_TARGET; will be cleared later */
cmd->result = DID_BAD_TARGET << 16;
@@ -1140,7 +1140,7 @@ static int dc395x_queue_command_lck(struct scsi_cmnd *cmd, void (*done)(struct s
/* process immediately */
send_srb(acb, srb);
}
- dprintkdbg(DBG_1, "queue_command: (pid#%li) done\n", cmd->serial_number);
+ dprintkdbg(DBG_1, "queue_command: (0x%p) done\n", cmd);
return 0;
complete:
@@ -1203,9 +1203,9 @@ static void dump_register_info(struct AdapterCtlBlk *acb,
dprintkl(KERN_INFO, "dump: srb=%p cmd=%p OOOPS!\n",
srb, srb->cmd);
else
- dprintkl(KERN_INFO, "dump: srb=%p cmd=%p (pid#%li) "
+ dprintkl(KERN_INFO, "dump: srb=%p cmd=%p "
"cmnd=0x%02x <%02i-%i>\n",
- srb, srb->cmd, srb->cmd->serial_number,
+ srb, srb->cmd,
srb->cmd->cmnd[0], srb->cmd->device->id,
srb->cmd->device->lun);
printk(" sglist=%p cnt=%i idx=%i len=%zu\n",
@@ -1301,8 +1301,8 @@ static int __dc395x_eh_bus_reset(struct scsi_cmnd *cmd)
struct AdapterCtlBlk *acb =
(struct AdapterCtlBlk *)cmd->device->host->hostdata;
dprintkl(KERN_INFO,
- "eh_bus_reset: (pid#%li) target=<%02i-%i> cmd=%p\n",
- cmd->serial_number, cmd->device->id, cmd->device->lun, cmd);
+ "eh_bus_reset: (0%p) target=<%02i-%i> cmd=%p\n",
+ cmd, cmd->device->id, cmd->device->lun, cmd);
if (timer_pending(&acb->waiting_timer))
del_timer(&acb->waiting_timer);
@@ -1368,8 +1368,8 @@ static int dc395x_eh_abort(struct scsi_cmnd *cmd)
(struct AdapterCtlBlk *)cmd->device->host->hostdata;
struct DeviceCtlBlk *dcb;
struct ScsiReqBlk *srb;
- dprintkl(KERN_INFO, "eh_abort: (pid#%li) target=<%02i-%i> cmd=%p\n",
- cmd->serial_number, cmd->device->id, cmd->device->lun, cmd);
+ dprintkl(KERN_INFO, "eh_abort: (0x%p) target=<%02i-%i> cmd=%p\n",
+ cmd, cmd->device->id, cmd->device->lun, cmd);
dcb = find_dcb(acb, cmd->device->id, cmd->device->lun);
if (!dcb) {
@@ -1495,8 +1495,8 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
u16 s_stat2, return_code;
u8 s_stat, scsicommand, i, identify_message;
u8 *ptr;
- dprintkdbg(DBG_0, "start_scsi: (pid#%li) <%02i-%i> srb=%p\n",
- srb->cmd->serial_number, dcb->target_id, dcb->target_lun, srb);
+ dprintkdbg(DBG_0, "start_scsi: (0x%p) <%02i-%i> srb=%p\n",
+ dcb->target_id, dcb->target_lun, srb);
srb->tag_number = TAG_NONE; /* acb->tag_max_num: had error read in eeprom */
@@ -1505,8 +1505,8 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
s_stat2 = DC395x_read16(acb, TRM_S1040_SCSI_STATUS);
#if 1
if (s_stat & 0x20 /* s_stat2 & 0x02000 */ ) {
- dprintkdbg(DBG_KG, "start_scsi: (pid#%li) BUSY %02x %04x\n",
- srb->cmd->serial_number, s_stat, s_stat2);
+ dprintkdbg(DBG_KG, "start_scsi: (0x%p) BUSY %02x %04x\n",
+ s_stat, s_stat2);
/*
* Try anyway?
*
@@ -1522,16 +1522,15 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
}
#endif
if (acb->active_dcb) {
- dprintkl(KERN_DEBUG, "start_scsi: (pid#%li) Attempt to start a"
- "command while another command (pid#%li) is active.",
- srb->cmd->serial_number,
+ dprintkl(KERN_DEBUG, "start_scsi: (0x%p) Attempt to start a"
+ "command while another command (0x%p) is active.",
+ srb->cmd,
acb->active_dcb->active_srb ?
- acb->active_dcb->active_srb->cmd->serial_number : 0);
+ acb->active_dcb->active_srb->cmd : 0);
return 1;
}
if (DC395x_read16(acb, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) {
- dprintkdbg(DBG_KG, "start_scsi: (pid#%li) Failed (busy)\n",
- srb->cmd->serial_number);
+ dprintkdbg(DBG_KG, "start_scsi: (0x%p) Failed (busy)\n", srb->cmd);
return 1;
}
/* Allow starting of SCSI commands half a second before we allow the mid-level
@@ -1603,9 +1602,9 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
tag_number++;
}
if (tag_number >= dcb->max_command) {
- dprintkl(KERN_WARNING, "start_scsi: (pid#%li) "
+ dprintkl(KERN_WARNING, "start_scsi: (0x%p) "
"Out of tags target=<%02i-%i>)\n",
- srb->cmd->serial_number, srb->cmd->device->id,
+ srb->cmd, srb->cmd->device->id,
srb->cmd->device->lun);
srb->state = SRB_READY;
DC395x_write16(acb, TRM_S1040_SCSI_CONTROL,
@@ -1623,8 +1622,8 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
#endif
/*polling:*/
/* Send CDB ..command block ......... */
- dprintkdbg(DBG_KG, "start_scsi: (pid#%li) <%02i-%i> cmnd=0x%02x tag=%i\n",
- srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun,
+ dprintkdbg(DBG_KG, "start_scsi: (0x%p) <%02i-%i> cmnd=0x%02x tag=%i\n",
+ srb->cmd, srb->cmd->device->id, srb->cmd->device->lun,
srb->cmd->cmnd[0], srb->tag_number);
if (srb->flag & AUTO_REQSENSE) {
DC395x_write8(acb, TRM_S1040_SCSI_FIFO, REQUEST_SENSE);
@@ -1647,8 +1646,8 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
* we caught an interrupt (must be reset or reselection ... )
* : Let's process it first!
*/
- dprintkdbg(DBG_0, "start_scsi: (pid#%li) <%02i-%i> Failed - busy\n",
- srb->cmd->serial_number, dcb->target_id, dcb->target_lun);
+ dprintkdbg(DBG_0, "start_scsi: (0x%p) <%02i-%i> Failed - busy\n",
+ srb->cmd, dcb->target_id, dcb->target_lun);
srb->state = SRB_READY;
free_tag(dcb, srb);
srb->msg_count = 0;
@@ -1843,7 +1842,7 @@ static irqreturn_t dc395x_interrupt(int irq, void *dev_id)
static void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
- dprintkdbg(DBG_0, "msgout_phase0: (pid#%li)\n", srb->cmd->serial_number);
+ dprintkdbg(DBG_0, "msgout_phase0: (0x%p)\n", srb->cmd);
if (srb->state & (SRB_UNEXPECT_RESEL + SRB_ABORT_SENT))
*pscsi_status = PH_BUS_FREE; /*.. initial phase */
@@ -1857,18 +1856,18 @@ static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
{
u16 i;
u8 *ptr;
- dprintkdbg(DBG_0, "msgout_phase1: (pid#%li)\n", srb->cmd->serial_number);
+ dprintkdbg(DBG_0, "msgout_phase1: (0x%p)\n", srb->cmd);
clear_fifo(acb, "msgout_phase1");
if (!(srb->state & SRB_MSGOUT)) {
srb->state |= SRB_MSGOUT;
dprintkl(KERN_DEBUG,
- "msgout_phase1: (pid#%li) Phase unexpected\n",
- srb->cmd->serial_number); /* So what ? */
+ "msgout_phase1: (0x%p) Phase unexpected\n",
+ srb->cmd); /* So what ? */
}
if (!srb->msg_count) {
- dprintkdbg(DBG_0, "msgout_phase1: (pid#%li) NOP msg\n",
- srb->cmd->serial_number);
+ dprintkdbg(DBG_0, "msgout_phase1: (0x%p) NOP msg\n",
+ srb->cmd);
DC395x_write8(acb, TRM_S1040_SCSI_FIFO, MSG_NOP);
DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */
DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
@@ -1888,7 +1887,7 @@ static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
static void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
- dprintkdbg(DBG_0, "command_phase0: (pid#%li)\n", srb->cmd->serial_number);
+ dprintkdbg(DBG_0, "command_phase0: (0x%p)\n", srb->cmd);
DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
}
@@ -1899,7 +1898,7 @@ static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
struct DeviceCtlBlk *dcb;
u8 *ptr;
u16 i;
- dprintkdbg(DBG_0, "command_phase1: (pid#%li)\n", srb->cmd->serial_number);
+ dprintkdbg(DBG_0, "command_phase1: (0x%p)\n", srb->cmd);
clear_fifo(acb, "command_phase1");
DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRATN);
@@ -2041,8 +2040,8 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
struct DeviceCtlBlk *dcb = srb->dcb;
u16 scsi_status = *pscsi_status;
u32 d_left_counter = 0;
- dprintkdbg(DBG_0, "data_out_phase0: (pid#%li) <%02i-%i>\n",
- srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun);
+ dprintkdbg(DBG_0, "data_out_phase0: (0x%p) <%02i-%i>\n",
+ srb->cmd, srb->cmd->device->id, srb->cmd->device->lun);
/*
* KG: We need to drain the buffers before we draw any conclusions!
@@ -2171,8 +2170,8 @@ static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
static void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
- dprintkdbg(DBG_0, "data_out_phase1: (pid#%li) <%02i-%i>\n",
- srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun);
+ dprintkdbg(DBG_0, "data_out_phase1: (0x%p) <%02i-%i>\n",
+ srb->cmd, srb->cmd->device->id, srb->cmd->device->lun);
clear_fifo(acb, "data_out_phase1");
/* do prepare before transfer when data out phase */
data_io_transfer(acb, srb, XFERDATAOUT);
@@ -2183,8 +2182,8 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
{
u16 scsi_status = *pscsi_status;
- dprintkdbg(DBG_0, "data_in_phase0: (pid#%li) <%02i-%i>\n",
- srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun);
+ dprintkdbg(DBG_0, "data_in_phase0: (0x%p) <%02i-%i>\n",
+ srb->cmd, srb->cmd->device->id, srb->cmd->device->lun);
/*
* KG: DataIn is much more tricky than DataOut. When the device is finished
@@ -2204,8 +2203,8 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
unsigned int sc, fc;
if (scsi_status & PARITYERROR) {
- dprintkl(KERN_INFO, "data_in_phase0: (pid#%li) "
- "Parity Error\n", srb->cmd->serial_number);
+ dprintkl(KERN_INFO, "data_in_phase0: (0x%p) "
+ "Parity Error\n", srb->cmd);
srb->status |= PARITY_ERROR;
}
/*
@@ -2394,8 +2393,8 @@ static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
static void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
- dprintkdbg(DBG_0, "data_in_phase1: (pid#%li) <%02i-%i>\n",
- srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun);
+ dprintkdbg(DBG_0, "data_in_phase1: (0x%p) <%02i-%i>\n",
+ srb->cmd, srb->cmd->device->id, srb->cmd->device->lun);
data_io_transfer(acb, srb, XFERDATAIN);
}
@@ -2406,8 +2405,8 @@ static void data_io_transfer(struct AdapterCtlBlk *acb,
struct DeviceCtlBlk *dcb = srb->dcb;
u8 bval;
dprintkdbg(DBG_0,
- "data_io_transfer: (pid#%li) <%02i-%i> %c len=%i, sg=(%i/%i)\n",
- srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun,
+ "data_io_transfer: (0x%p) <%02i-%i> %c len=%i, sg=(%i/%i)\n",
+ srb->cmd, srb->cmd->device->id, srb->cmd->device->lun,
((io_dir & DMACMD_DIR) ? 'r' : 'w'),
srb->total_xfer_length, srb->sg_index, srb->sg_count);
if (srb == acb->tmp_srb)
@@ -2579,8 +2578,8 @@ static void data_io_transfer(struct AdapterCtlBlk *acb,
static void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
- dprintkdbg(DBG_0, "status_phase0: (pid#%li) <%02i-%i>\n",
- srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun);
+ dprintkdbg(DBG_0, "status_phase0: (0x%p) <%02i-%i>\n",
+ srb->cmd, srb->cmd->device->id, srb->cmd->device->lun);
srb->target_status = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
srb->end_message = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); /* get message */
srb->state = SRB_COMPLETED;
@@ -2593,8 +2592,8 @@ static void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
static void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
- dprintkdbg(DBG_0, "status_phase1: (pid#%li) <%02i-%i>\n",
- srb->cmd->serial_number, srb->cmd->device->id, srb->cmd->device->lun);
+ dprintkdbg(DBG_0, "status_phase1: (0x%p) <%02i-%i>\n",
+ srb->cmd, srb->cmd->device->id, srb->cmd->device->lun);
srb->state = SRB_STATUS;
DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */
DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_COMP);
@@ -2635,8 +2634,8 @@ static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb,
{
struct ScsiReqBlk *srb = NULL;
struct ScsiReqBlk *i;
- dprintkdbg(DBG_0, "msgin_qtag: (pid#%li) tag=%i srb=%p\n",
- srb->cmd->serial_number, tag, srb);
+ dprintkdbg(DBG_0, "msgin_qtag: (0x%p) tag=%i srb=%p\n",
+ srb->cmd, tag, srb);
if (!(dcb->tag_mask & (1 << tag)))
dprintkl(KERN_DEBUG,
@@ -2654,8 +2653,8 @@ static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb,
if (!srb)
goto mingx0;
- dprintkdbg(DBG_0, "msgin_qtag: (pid#%li) <%02i-%i>\n",
- srb->cmd->serial_number, srb->dcb->target_id, srb->dcb->target_lun);
+ dprintkdbg(DBG_0, "msgin_qtag: (0x%p) <%02i-%i>\n",
+ srb->cmd, srb->dcb->target_id, srb->dcb->target_lun);
if (dcb->flag & ABORT_DEV_) {
/*srb->state = SRB_ABORT_SENT; */
enable_msgout_abort(acb, srb);
@@ -2865,7 +2864,7 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
struct DeviceCtlBlk *dcb = acb->active_dcb;
- dprintkdbg(DBG_0, "msgin_phase0: (pid#%li)\n", srb->cmd->serial_number);
+ dprintkdbg(DBG_0, "msgin_phase0: (0x%p)\n", srb->cmd);
srb->msgin_buf[acb->msg_len++] = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
if (msgin_completed(srb->msgin_buf, acb->msg_len)) {
@@ -2931,9 +2930,9 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
* SAVE POINTER may be ignored as we have the struct
* ScsiReqBlk* associated with the scsi command.
*/
- dprintkdbg(DBG_0, "msgin_phase0: (pid#%li) "
+ dprintkdbg(DBG_0, "msgin_phase0: (0x%p) "
"SAVE POINTER rem=%i Ignore\n",
- srb->cmd->serial_number, srb->total_xfer_length);
+ srb->cmd, srb->total_xfer_length);
break;
case RESTORE_POINTERS:
@@ -2941,9 +2940,9 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
break;
case ABORT:
- dprintkdbg(DBG_0, "msgin_phase0: (pid#%li) "
+ dprintkdbg(DBG_0, "msgin_phase0: (0x%p) "
"<%02i-%i> ABORT msg\n",
- srb->cmd->serial_number, dcb->target_id,
+ srb->cmd, dcb->target_id,
dcb->target_lun);
dcb->flag |= ABORT_DEV_;
enable_msgout_abort(acb, srb);
@@ -2975,7 +2974,7 @@ static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
static void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
u16 *pscsi_status)
{
- dprintkdbg(DBG_0, "msgin_phase1: (pid#%li)\n", srb->cmd->serial_number);
+ dprintkdbg(DBG_0, "msgin_phase1: (0x%p)\n", srb->cmd);
clear_fifo(acb, "msgin_phase1");
DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1);
if (!(srb->state & SRB_MSGIN)) {
@@ -3041,7 +3040,7 @@ static void disconnect(struct AdapterCtlBlk *acb)
}
srb = dcb->active_srb;
acb->active_dcb = NULL;
- dprintkdbg(DBG_0, "disconnect: (pid#%li)\n", srb->cmd->serial_number);
+ dprintkdbg(DBG_0, "disconnect: (0x%p)\n", srb->cmd);
srb->scsi_phase = PH_BUS_FREE; /* initial phase */
clear_fifo(acb, "disconnect");
@@ -3071,14 +3070,14 @@ static void disconnect(struct AdapterCtlBlk *acb)
&& srb->state != SRB_MSGOUT) {
srb->state = SRB_READY;
dprintkl(KERN_DEBUG,
- "disconnect: (pid#%li) Unexpected\n",
- srb->cmd->serial_number);
+ "disconnect: (0x%p) Unexpected\n",
+ srb->cmd);
srb->target_status = SCSI_STAT_SEL_TIMEOUT;
goto disc1;
} else {
/* Normal selection timeout */
- dprintkdbg(DBG_KG, "disconnect: (pid#%li) "
- "<%02i-%i> SelTO\n", srb->cmd->serial_number,
+ dprintkdbg(DBG_KG, "disconnect: (0x%p) "
+ "<%02i-%i> SelTO\n", srb->cmd,
dcb->target_id, dcb->target_lun);
if (srb->retry_count++ > DC395x_MAX_RETRIES
|| acb->scan_devices) {
@@ -3089,8 +3088,8 @@ static void disconnect(struct AdapterCtlBlk *acb)
free_tag(dcb, srb);
srb_going_to_waiting_move(dcb, srb);
dprintkdbg(DBG_KG,
- "disconnect: (pid#%li) Retry\n",
- srb->cmd->serial_number);
+ "disconnect: (0x%p) Retry\n",
+ srb->cmd);
waiting_set_timer(acb, HZ / 20);
}
} else if (srb->state & SRB_DISCONNECT) {
@@ -3142,9 +3141,9 @@ static void reselect(struct AdapterCtlBlk *acb)
}
/* Why the if ? */
if (!acb->scan_devices) {
- dprintkdbg(DBG_KG, "reselect: (pid#%li) <%02i-%i> "
+ dprintkdbg(DBG_KG, "reselect: (0x%p) <%02i-%i> "
"Arb lost but Resel win rsel=%i stat=0x%04x\n",
- srb->cmd->serial_number, dcb->target_id,
+ srb->cmd, dcb->target_id,
dcb->target_lun, rsel_tar_lun_id,
DC395x_read16(acb, TRM_S1040_SCSI_STATUS));
arblostflag = 1;
@@ -3318,7 +3317,7 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
enum dma_data_direction dir = cmd->sc_data_direction;
int ckc_only = 1;
- dprintkdbg(DBG_1, "srb_done: (pid#%li) <%02i-%i>\n", srb->cmd->serial_number,
+ dprintkdbg(DBG_1, "srb_done: (0x%p) <%02i-%i>\n", srb->cmd,
srb->cmd->device->id, srb->cmd->device->lun);
dprintkdbg(DBG_SG, "srb_done: srb=%p sg=%i(%i/%i) buf=%p\n",
srb, scsi_sg_count(cmd), srb->sg_index, srb->sg_count,
@@ -3497,9 +3496,9 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
cmd->SCp.buffers_residual = 0;
if (debug_enabled(DBG_KG)) {
if (srb->total_xfer_length)
- dprintkdbg(DBG_KG, "srb_done: (pid#%li) <%02i-%i> "
+ dprintkdbg(DBG_KG, "srb_done: (0x%p) <%02i-%i> "
"cmnd=0x%02x Missed %i bytes\n",
- cmd->serial_number, cmd->device->id, cmd->device->lun,
+ cmd, cmd->device->id, cmd->device->lun,
cmd->cmnd[0], srb->total_xfer_length);
}
@@ -3508,8 +3507,8 @@ static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
if (srb == acb->tmp_srb)
dprintkl(KERN_ERR, "srb_done: ERROR! Completed cmd with tmp_srb\n");
else {
- dprintkdbg(DBG_0, "srb_done: (pid#%li) done result=0x%08x\n",
- cmd->serial_number, cmd->result);
+ dprintkdbg(DBG_0, "srb_done: (0x%p) done result=0x%08x\n",
+ cmd, cmd->result);
srb_free_insert(acb, srb);
}
pci_unmap_srb(acb, srb);
@@ -3538,7 +3537,7 @@ static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag,
p = srb->cmd;
dir = p->sc_data_direction;
result = MK_RES(0, did_flag, 0, 0);
- printk("G:%li(%02i-%i) ", p->serial_number,
+ printk("G:%p(%02i-%i) ", p,
p->device->id, p->device->lun);
srb_going_remove(dcb, srb);
free_tag(dcb, srb);
@@ -3568,7 +3567,7 @@ static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag,
p = srb->cmd;
result = MK_RES(0, did_flag, 0, 0);
- printk("W:%li<%02i-%i>", p->serial_number, p->device->id,
+ printk("W:%p<%02i-%i>", p, p->device->id,
p->device->lun);
srb_waiting_remove(dcb, srb);
srb_free_insert(acb, srb);
@@ -3677,8 +3676,8 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
struct ScsiReqBlk *srb)
{
struct scsi_cmnd *cmd = srb->cmd;
- dprintkdbg(DBG_1, "request_sense: (pid#%li) <%02i-%i>\n",
- cmd->serial_number, cmd->device->id, cmd->device->lun);
+ dprintkdbg(DBG_1, "request_sense: (0x%p) <%02i-%i>\n",
+ cmd, cmd->device->id, cmd->device->lun);
srb->flag |= AUTO_REQSENSE;
srb->adapter_status = 0;
@@ -3708,8 +3707,8 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
if (start_scsi(acb, dcb, srb)) { /* Should only happen, if sb. else grabs the bus */
dprintkl(KERN_DEBUG,
- "request_sense: (pid#%li) failed <%02i-%i>\n",
- srb->cmd->serial_number, dcb->target_id, dcb->target_lun);
+ "request_sense: (0x%p) failed <%02i-%i>\n",
+ srb->cmd, dcb->target_id, dcb->target_lun);
srb_going_to_waiting_move(dcb, srb);
waiting_set_timer(acb, HZ / 100);
}
@@ -4717,13 +4716,13 @@ static int dc395x_proc_info(struct Scsi_Host *host, char *buffer,
dcb->target_id, dcb->target_lun,
list_size(&dcb->srb_waiting_list));
list_for_each_entry(srb, &dcb->srb_waiting_list, list)
- SPRINTF(" %li", srb->cmd->serial_number);
+ SPRINTF(" %p", srb->cmd);
if (!list_empty(&dcb->srb_going_list))
SPRINTF("\nDCB (%02i-%i): Going : %i:",
dcb->target_id, dcb->target_lun,
list_size(&dcb->srb_going_list));
list_for_each_entry(srb, &dcb->srb_going_list, list)
- SPRINTF(" %li", srb->cmd->serial_number);
+ SPRINTF(" %p", srb->cmd);
if (!list_empty(&dcb->srb_waiting_list) || !list_empty(&dcb->srb_going_list))
SPRINTF("\n");
}
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index 42fe52902add..6fec9fe5dc39 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -782,7 +782,7 @@ static int alua_bus_attach(struct scsi_device *sdev)
h->sdev = sdev;
err = alua_initialize(sdev, h);
- if (err != SCSI_DH_OK)
+ if ((err != SCSI_DH_OK) && (err != SCSI_DH_DEV_OFFLINED))
goto failed;
if (!try_module_get(THIS_MODULE))
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index 293c183dfe6d..e7fc70d6b478 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -182,14 +182,24 @@ struct rdac_dh_data {
struct rdac_controller *ctlr;
#define UNINITIALIZED_LUN (1 << 8)
unsigned lun;
+
+#define RDAC_MODE 0
+#define RDAC_MODE_AVT 1
+#define RDAC_MODE_IOSHIP 2
+ unsigned char mode;
+
#define RDAC_STATE_ACTIVE 0
#define RDAC_STATE_PASSIVE 1
unsigned char state;
#define RDAC_LUN_UNOWNED 0
#define RDAC_LUN_OWNED 1
-#define RDAC_LUN_AVT 2
char lun_state;
+
+#define RDAC_PREFERRED 0
+#define RDAC_NON_PREFERRED 1
+ char preferred;
+
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
union {
struct c2_inquiry c2;
@@ -199,11 +209,15 @@ struct rdac_dh_data {
} inq;
};
+static const char *mode[] = {
+ "RDAC",
+ "AVT",
+ "IOSHIP",
+};
static const char *lun_state[] =
{
"unowned",
"owned",
- "owned (AVT mode)",
};
struct rdac_queue_data {
@@ -458,25 +472,33 @@ static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h)
int err;
struct c9_inquiry *inqp;
- h->lun_state = RDAC_LUN_UNOWNED;
h->state = RDAC_STATE_ACTIVE;
err = submit_inquiry(sdev, 0xC9, sizeof(struct c9_inquiry), h);
if (err == SCSI_DH_OK) {
inqp = &h->inq.c9;
- if ((inqp->avte_cvp >> 7) == 0x1) {
- /* LUN in AVT mode */
- sdev_printk(KERN_NOTICE, sdev,
- "%s: AVT mode detected\n",
- RDAC_NAME);
- h->lun_state = RDAC_LUN_AVT;
- } else if ((inqp->avte_cvp & 0x1) != 0) {
- /* LUN was owned by the controller */
+ /* detect the operating mode */
+ if ((inqp->avte_cvp >> 5) & 0x1)
+ h->mode = RDAC_MODE_IOSHIP; /* LUN in IOSHIP mode */
+ else if (inqp->avte_cvp >> 7)
+ h->mode = RDAC_MODE_AVT; /* LUN in AVT mode */
+ else
+ h->mode = RDAC_MODE; /* LUN in RDAC mode */
+
+ /* Update ownership */
+ if (inqp->avte_cvp & 0x1)
h->lun_state = RDAC_LUN_OWNED;
+ else {
+ h->lun_state = RDAC_LUN_UNOWNED;
+ if (h->mode == RDAC_MODE)
+ h->state = RDAC_STATE_PASSIVE;
}
- }
- if (h->lun_state == RDAC_LUN_UNOWNED)
- h->state = RDAC_STATE_PASSIVE;
+ /* Update path prio*/
+ if (inqp->path_prio & 0x1)
+ h->preferred = RDAC_PREFERRED;
+ else
+ h->preferred = RDAC_NON_PREFERRED;
+ }
return err;
}
@@ -648,12 +670,27 @@ static int rdac_activate(struct scsi_device *sdev,
{
struct rdac_dh_data *h = get_rdac_data(sdev);
int err = SCSI_DH_OK;
+ int act = 0;
err = check_ownership(sdev, h);
if (err != SCSI_DH_OK)
goto done;
- if (h->lun_state == RDAC_LUN_UNOWNED) {
+ switch (h->mode) {
+ case RDAC_MODE:
+ if (h->lun_state == RDAC_LUN_UNOWNED)
+ act = 1;
+ break;
+ case RDAC_MODE_IOSHIP:
+ if ((h->lun_state == RDAC_LUN_UNOWNED) &&
+ (h->preferred == RDAC_PREFERRED))
+ act = 1;
+ break;
+ default:
+ break;
+ }
+
+ if (act) {
err = queue_mode_select(sdev, fn, data);
if (err == SCSI_DH_OK)
return 0;
@@ -836,8 +873,9 @@ static int rdac_bus_attach(struct scsi_device *sdev)
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
sdev_printk(KERN_NOTICE, sdev,
- "%s: LUN %d (%s)\n",
- RDAC_NAME, h->lun, lun_state[(int)h->lun_state]);
+ "%s: LUN %d (%s) (%s)\n",
+ RDAC_NAME, h->lun, mode[(int)h->mode],
+ lun_state[(int)h->lun_state]);
return 0;
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index cffcb108ac96..b4f6c9a84e71 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -780,7 +780,7 @@ static int adpt_abort(struct scsi_cmnd * cmd)
return FAILED;
}
pHba = (adpt_hba*) cmd->device->host->hostdata[0];
- printk(KERN_INFO"%s: Trying to Abort cmd=%ld\n",pHba->name, cmd->serial_number);
+ printk(KERN_INFO"%s: Trying to Abort\n",pHba->name);
if ((dptdevice = (void*) (cmd->device->hostdata)) == NULL) {
printk(KERN_ERR "%s: Unable to abort: No device in cmnd\n",pHba->name);
return FAILED;
@@ -802,10 +802,10 @@ static int adpt_abort(struct scsi_cmnd * cmd)
printk(KERN_INFO"%s: Abort cmd not supported\n",pHba->name);
return FAILED;
}
- printk(KERN_INFO"%s: Abort cmd=%ld failed.\n",pHba->name, cmd->serial_number);
+ printk(KERN_INFO"%s: Abort failed.\n",pHba->name);
return FAILED;
}
- printk(KERN_INFO"%s: Abort cmd=%ld complete.\n",pHba->name, cmd->serial_number);
+ printk(KERN_INFO"%s: Abort complete.\n",pHba->name);
return SUCCESS;
}
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index 0eb4fe6a4c8a..94de88955a99 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -1766,8 +1766,8 @@ static int eata2x_queuecommand_lck(struct scsi_cmnd *SCpnt,
struct mscp *cpp;
if (SCpnt->host_scribble)
- panic("%s: qcomm, pid %ld, SCpnt %p already active.\n",
- ha->board_name, SCpnt->serial_number, SCpnt);
+ panic("%s: qcomm, SCpnt %p already active.\n",
+ ha->board_name, SCpnt);
/* i is the mailbox number, look for the first free mailbox
starting from last_cp_used */
@@ -1801,7 +1801,7 @@ static int eata2x_queuecommand_lck(struct scsi_cmnd *SCpnt,
if (do_trace)
scmd_printk(KERN_INFO, SCpnt,
- "qcomm, mbox %d, pid %ld.\n", i, SCpnt->serial_number);
+ "qcomm, mbox %d.\n", i);
cpp->reqsen = 1;
cpp->dispri = 1;
@@ -1833,8 +1833,7 @@ static int eata2x_queuecommand_lck(struct scsi_cmnd *SCpnt,
if (do_dma(shost->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) {
unmap_dma(i, ha);
SCpnt->host_scribble = NULL;
- scmd_printk(KERN_INFO, SCpnt,
- "qcomm, pid %ld, adapter busy.\n", SCpnt->serial_number);
+ scmd_printk(KERN_INFO, SCpnt, "qcomm, adapter busy.\n");
return 1;
}
@@ -1851,14 +1850,12 @@ static int eata2x_eh_abort(struct scsi_cmnd *SCarg)
unsigned int i;
if (SCarg->host_scribble == NULL) {
- scmd_printk(KERN_INFO, SCarg,
- "abort, pid %ld inactive.\n", SCarg->serial_number);
+ scmd_printk(KERN_INFO, SCarg, "abort, cmd inactive.\n");
return SUCCESS;
}
i = *(unsigned int *)SCarg->host_scribble;
- scmd_printk(KERN_WARNING, SCarg,
- "abort, mbox %d, pid %ld.\n", i, SCarg->serial_number);
+ scmd_printk(KERN_WARNING, SCarg, "abort, mbox %d.\n", i);
if (i >= shost->can_queue)
panic("%s: abort, invalid SCarg->host_scribble.\n", ha->board_name);
@@ -1902,8 +1899,8 @@ static int eata2x_eh_abort(struct scsi_cmnd *SCarg)
SCarg->result = DID_ABORT << 16;
SCarg->host_scribble = NULL;
ha->cp_stat[i] = FREE;
- printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n",
- ha->board_name, i, SCarg->serial_number);
+ printk("%s, abort, mbox %d ready, DID_ABORT, done.\n",
+ ha->board_name, i);
SCarg->scsi_done(SCarg);
return SUCCESS;
}
@@ -1919,13 +1916,12 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg)
struct Scsi_Host *shost = SCarg->device->host;
struct hostdata *ha = (struct hostdata *)shost->hostdata;
- scmd_printk(KERN_INFO, SCarg,
- "reset, enter, pid %ld.\n", SCarg->serial_number);
+ scmd_printk(KERN_INFO, SCarg, "reset, enter.\n");
spin_lock_irq(shost->host_lock);
if (SCarg->host_scribble == NULL)
- printk("%s: reset, pid %ld inactive.\n", ha->board_name, SCarg->serial_number);
+ printk("%s: reset, inactive.\n", ha->board_name);
if (ha->in_reset) {
printk("%s: reset, exit, already in reset.\n", ha->board_name);
@@ -1964,14 +1960,14 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg)
if (ha->cp_stat[i] == READY || ha->cp_stat[i] == ABORTING) {
ha->cp_stat[i] = ABORTING;
- printk("%s: reset, mbox %d aborting, pid %ld.\n",
- ha->board_name, i, SCpnt->serial_number);
+ printk("%s: reset, mbox %d aborting.\n",
+ ha->board_name, i);
}
else {
ha->cp_stat[i] = IN_RESET;
- printk("%s: reset, mbox %d in reset, pid %ld.\n",
- ha->board_name, i, SCpnt->serial_number);
+ printk("%s: reset, mbox %d in reset.\n",
+ ha->board_name, i);
}
if (SCpnt->host_scribble == NULL)
@@ -2025,8 +2021,8 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg)
ha->cp_stat[i] = LOCKED;
printk
- ("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n",
- ha->board_name, i, SCpnt->serial_number);
+ ("%s, reset, mbox %d locked, DID_RESET, done.\n",
+ ha->board_name, i);
}
else if (ha->cp_stat[i] == ABORTING) {
@@ -2039,8 +2035,8 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg)
ha->cp_stat[i] = FREE;
printk
- ("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n",
- ha->board_name, i, SCpnt->serial_number);
+ ("%s, reset, mbox %d aborting, DID_RESET, done.\n",
+ ha->board_name, i);
}
else
@@ -2054,7 +2050,7 @@ static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg)
do_trace = 0;
if (arg_done)
- printk("%s: reset, exit, pid %ld done.\n", ha->board_name, SCarg->serial_number);
+ printk("%s: reset, exit, done.\n", ha->board_name);
else
printk("%s: reset, exit.\n", ha->board_name);
@@ -2238,10 +2234,10 @@ static int reorder(struct hostdata *ha, unsigned long cursec,
cpp = &ha->cp[k];
SCpnt = cpp->SCpnt;
scmd_printk(KERN_INFO, SCpnt,
- "%s pid %ld mb %d fc %d nr %d sec %ld ns %u"
+ "%s mb %d fc %d nr %d sec %ld ns %u"
" cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n",
(ihdlr ? "ihdlr" : "qcomm"),
- SCpnt->serial_number, k, flushcount,
+ k, flushcount,
n_ready, blk_rq_pos(SCpnt->request),
blk_rq_sectors(SCpnt->request), cursec, YESNO(s),
YESNO(r), YESNO(rev), YESNO(input_only),
@@ -2285,10 +2281,10 @@ static void flush_dev(struct scsi_device *dev, unsigned long cursec,
if (do_dma(dev->host->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) {
scmd_printk(KERN_INFO, SCpnt,
- "%s, pid %ld, mbox %d, adapter"
+ "%s, mbox %d, adapter"
" busy, will abort.\n",
(ihdlr ? "ihdlr" : "qcomm"),
- SCpnt->serial_number, k);
+ k);
ha->cp_stat[k] = ABORTING;
continue;
}
@@ -2398,12 +2394,12 @@ static irqreturn_t ihdlr(struct Scsi_Host *shost)
panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", ha->board_name, i);
if (SCpnt->host_scribble == NULL)
- panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", ha->board_name,
- i, SCpnt->serial_number, SCpnt);
+ panic("%s: ihdlr, mbox %d, SCpnt %p garbled.\n", ha->board_name,
+ i, SCpnt);
if (*(unsigned int *)SCpnt->host_scribble != i)
- panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n",
- ha->board_name, i, SCpnt->serial_number,
+ panic("%s: ihdlr, mbox %d, index mismatch %d.\n",
+ ha->board_name, i,
*(unsigned int *)SCpnt->host_scribble);
sync_dma(i, ha);
@@ -2449,11 +2445,11 @@ static irqreturn_t ihdlr(struct Scsi_Host *shost)
if (spp->target_status && SCpnt->device->type == TYPE_DISK &&
(!(tstatus == CHECK_CONDITION && ha->iocount <= 1000 &&
(SCpnt->sense_buffer[2] & 0xf) == NOT_READY)))
- printk("%s: ihdlr, target %d.%d:%d, pid %ld, "
+ printk("%s: ihdlr, target %d.%d:%d, "
"target_status 0x%x, sense key 0x%x.\n",
ha->board_name,
SCpnt->device->channel, SCpnt->device->id,
- SCpnt->device->lun, SCpnt->serial_number,
+ SCpnt->device->lun,
spp->target_status, SCpnt->sense_buffer[2]);
ha->target_to[SCpnt->device->id][SCpnt->device->channel] = 0;
@@ -2522,9 +2518,9 @@ static irqreturn_t ihdlr(struct Scsi_Host *shost)
do_trace || msg_byte(spp->target_status))
#endif
scmd_printk(KERN_INFO, SCpnt, "ihdlr, mbox %2d, err 0x%x:%x,"
- " pid %ld, reg 0x%x, count %d.\n",
+ " reg 0x%x, count %d.\n",
i, spp->adapter_status, spp->target_status,
- SCpnt->serial_number, reg, ha->iocount);
+ reg, ha->iocount);
unmap_dma(i, ha);
diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
index 4a9641e69f54..d5f8362335d3 100644
--- a/drivers/scsi/eata_pio.c
+++ b/drivers/scsi/eata_pio.c
@@ -372,8 +372,7 @@ static int eata_pio_queue_lck(struct scsi_cmnd *cmd,
cp->status = USED; /* claim free slot */
DBG(DBG_QUEUE, scmd_printk(KERN_DEBUG, cmd,
- "eata_pio_queue pid %ld, y %d\n",
- cmd->serial_number, y));
+ "eata_pio_queue 0x%p, y %d\n", cmd, y));
cmd->scsi_done = (void *) done;
@@ -417,8 +416,8 @@ static int eata_pio_queue_lck(struct scsi_cmnd *cmd,
if (eata_pio_send_command(base, EATA_CMD_PIO_SEND_CP)) {
cmd->result = DID_BUS_BUSY << 16;
scmd_printk(KERN_NOTICE, cmd,
- "eata_pio_queue pid %ld, HBA busy, "
- "returning DID_BUS_BUSY, done.\n", cmd->serial_number);
+ "eata_pio_queue pid 0x%p, HBA busy, "
+ "returning DID_BUS_BUSY, done.\n", cmd);
done(cmd);
cp->status = FREE;
return 0;
@@ -432,8 +431,8 @@ static int eata_pio_queue_lck(struct scsi_cmnd *cmd,
outw(0, base + HA_RDATA);
DBG(DBG_QUEUE, scmd_printk(KERN_DEBUG, cmd,
- "Queued base %#.4lx pid: %ld "
- "slot %d irq %d\n", sh->base, cmd->serial_number, y, sh->irq));
+ "Queued base %#.4lx cmd: 0x%p "
+ "slot %d irq %d\n", sh->base, cmd, y, sh->irq));
return 0;
}
@@ -445,8 +444,7 @@ static int eata_pio_abort(struct scsi_cmnd *cmd)
unsigned int loop = 100;
DBG(DBG_ABNORM, scmd_printk(KERN_WARNING, cmd,
- "eata_pio_abort called pid: %ld\n",
- cmd->serial_number));
+ "eata_pio_abort called pid: 0x%p\n", cmd));
while (inb(cmd->device->host->base + HA_RAUXSTAT) & HA_ABUSY)
if (--loop == 0) {
@@ -481,8 +479,7 @@ static int eata_pio_host_reset(struct scsi_cmnd *cmd)
struct Scsi_Host *host = cmd->device->host;
DBG(DBG_ABNORM, scmd_printk(KERN_WARNING, cmd,
- "eata_pio_reset called pid:%ld\n",
- cmd->serial_number));
+ "eata_pio_reset called\n"));
spin_lock_irq(host->host_lock);
@@ -501,7 +498,7 @@ static int eata_pio_host_reset(struct scsi_cmnd *cmd)
sp = HD(cmd)->ccb[x].cmd;
HD(cmd)->ccb[x].status = RESET;
- printk(KERN_WARNING "eata_pio_reset: slot %d in reset, pid %ld.\n", x, sp->serial_number);
+ printk(KERN_WARNING "eata_pio_reset: slot %d in reset.\n", x);
if (sp == NULL)
panic("eata_pio_reset: slot %d, sp==NULL.\n", x);
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index 57558523c1b8..394ed9e79fd4 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -708,8 +708,7 @@ static void esp_maybe_execute_command(struct esp *esp)
tp = &esp->target[tgt];
lp = dev->hostdata;
- list_del(&ent->list);
- list_add(&ent->list, &esp->active_cmds);
+ list_move(&ent->list, &esp->active_cmds);
esp->active_cmd = ent;
@@ -1059,7 +1058,7 @@ static struct esp_cmd_entry *esp_reconnect_with_tag(struct esp *esp,
esp->ops->send_dma_cmd(esp, esp->command_block_dma,
2, 2, 1, ESP_CMD_DMA | ESP_CMD_TI);
- /* ACK the msssage. */
+ /* ACK the message. */
scsi_esp_cmd(esp, ESP_CMD_MOK);
for (i = 0; i < ESP_RESELECT_TAG_LIMIT; i++) {
@@ -1244,8 +1243,7 @@ static int esp_finish_select(struct esp *esp)
/* Now that the state is unwound properly, put back onto
* the issue queue. This command is no longer active.
*/
- list_del(&ent->list);
- list_add(&ent->list, &esp->queued_cmds);
+ list_move(&ent->list, &esp->queued_cmds);
esp->active_cmd = NULL;
/* Return value ignored by caller, it directly invokes
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index bde6ee5333eb..cc23bd9480b2 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -381,6 +381,42 @@ out:
}
/**
+ * fcoe_interface_release() - fcoe_port kref release function
+ * @kref: Embedded reference count in an fcoe_interface struct
+ */
+static void fcoe_interface_release(struct kref *kref)
+{
+ struct fcoe_interface *fcoe;
+ struct net_device *netdev;
+
+ fcoe = container_of(kref, struct fcoe_interface, kref);
+ netdev = fcoe->netdev;
+ /* tear-down the FCoE controller */
+ fcoe_ctlr_destroy(&fcoe->ctlr);
+ kfree(fcoe);
+ dev_put(netdev);
+ module_put(THIS_MODULE);
+}
+
+/**
+ * fcoe_interface_get() - Get a reference to a FCoE interface
+ * @fcoe: The FCoE interface to be held
+ */
+static inline void fcoe_interface_get(struct fcoe_interface *fcoe)
+{
+ kref_get(&fcoe->kref);
+}
+
+/**
+ * fcoe_interface_put() - Put a reference to a FCoE interface
+ * @fcoe: The FCoE interface to be released
+ */
+static inline void fcoe_interface_put(struct fcoe_interface *fcoe)
+{
+ kref_put(&fcoe->kref, fcoe_interface_release);
+}
+
+/**
* fcoe_interface_cleanup() - Clean up a FCoE interface
* @fcoe: The FCoE interface to be cleaned up
*
@@ -392,6 +428,21 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
struct fcoe_ctlr *fip = &fcoe->ctlr;
u8 flogi_maddr[ETH_ALEN];
const struct net_device_ops *ops;
+ struct fcoe_port *port = lport_priv(fcoe->ctlr.lp);
+
+ FCOE_NETDEV_DBG(netdev, "Destroying interface\n");
+
+ /* Logout of the fabric */
+ fc_fabric_logoff(fcoe->ctlr.lp);
+
+ /* Cleanup the fc_lport */
+ fc_lport_destroy(fcoe->ctlr.lp);
+
+ /* Stop the transmit retry timer */
+ del_timer_sync(&port->timer);
+
+ /* Free existing transmit skbs */
+ fcoe_clean_pending_queue(fcoe->ctlr.lp);
/*
* Don't listen for Ethernet packets anymore.
@@ -414,6 +465,9 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
} else
dev_mc_del(netdev, FIP_ALL_ENODE_MACS);
+ if (!is_zero_ether_addr(port->data_src_addr))
+ dev_uc_del(netdev, port->data_src_addr);
+
/* Tell the LLD we are done w/ FCoE */
ops = netdev->netdev_ops;
if (ops->ndo_fcoe_disable) {
@@ -421,42 +475,7 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
FCOE_NETDEV_DBG(netdev, "Failed to disable FCoE"
" specific feature for LLD.\n");
}
-}
-
-/**
- * fcoe_interface_release() - fcoe_port kref release function
- * @kref: Embedded reference count in an fcoe_interface struct
- */
-static void fcoe_interface_release(struct kref *kref)
-{
- struct fcoe_interface *fcoe;
- struct net_device *netdev;
-
- fcoe = container_of(kref, struct fcoe_interface, kref);
- netdev = fcoe->netdev;
- /* tear-down the FCoE controller */
- fcoe_ctlr_destroy(&fcoe->ctlr);
- kfree(fcoe);
- dev_put(netdev);
- module_put(THIS_MODULE);
-}
-
-/**
- * fcoe_interface_get() - Get a reference to a FCoE interface
- * @fcoe: The FCoE interface to be held
- */
-static inline void fcoe_interface_get(struct fcoe_interface *fcoe)
-{
- kref_get(&fcoe->kref);
-}
-
-/**
- * fcoe_interface_put() - Put a reference to a FCoE interface
- * @fcoe: The FCoE interface to be released
- */
-static inline void fcoe_interface_put(struct fcoe_interface *fcoe)
-{
- kref_put(&fcoe->kref, fcoe_interface_release);
+ fcoe_interface_put(fcoe);
}
/**
@@ -821,39 +840,9 @@ skip_oem:
* fcoe_if_destroy() - Tear down a SW FCoE instance
* @lport: The local port to be destroyed
*
- * Locking: must be called with the RTNL mutex held and RTNL mutex
- * needed to be dropped by this function since not dropping RTNL
- * would cause circular locking warning on synchronous fip worker
- * cancelling thru fcoe_interface_put invoked by this function.
- *
*/
static void fcoe_if_destroy(struct fc_lport *lport)
{
- struct fcoe_port *port = lport_priv(lport);
- struct fcoe_interface *fcoe = port->priv;
- struct net_device *netdev = fcoe->netdev;
-
- FCOE_NETDEV_DBG(netdev, "Destroying interface\n");
-
- /* Logout of the fabric */
- fc_fabric_logoff(lport);
-
- /* Cleanup the fc_lport */
- fc_lport_destroy(lport);
-
- /* Stop the transmit retry timer */
- del_timer_sync(&port->timer);
-
- /* Free existing transmit skbs */
- fcoe_clean_pending_queue(lport);
-
- if (!is_zero_ether_addr(port->data_src_addr))
- dev_uc_del(netdev, port->data_src_addr);
- rtnl_unlock();
-
- /* receives may not be stopped until after this */
- fcoe_interface_put(fcoe);
-
/* Free queued packets for the per-CPU receive threads */
fcoe_percpu_clean(lport);
@@ -1783,23 +1772,8 @@ static int fcoe_disable(struct net_device *netdev)
int rc = 0;
mutex_lock(&fcoe_config_mutex);
-#ifdef CONFIG_FCOE_MODULE
- /*
- * Make sure the module has been initialized, and is not about to be
- * removed. Module paramter sysfs files are writable before the
- * module_init function is called and after module_exit.
- */
- if (THIS_MODULE->state != MODULE_STATE_LIVE) {
- rc = -ENODEV;
- goto out_nodev;
- }
-#endif
-
- if (!rtnl_trylock()) {
- mutex_unlock(&fcoe_config_mutex);
- return -ERESTARTSYS;
- }
+ rtnl_lock();
fcoe = fcoe_hostlist_lookup_port(netdev);
rtnl_unlock();
@@ -1809,7 +1783,6 @@ static int fcoe_disable(struct net_device *netdev)
} else
rc = -ENODEV;
-out_nodev:
mutex_unlock(&fcoe_config_mutex);
return rc;
}
@@ -1828,22 +1801,7 @@ static int fcoe_enable(struct net_device *netdev)
int rc = 0;
mutex_lock(&fcoe_config_mutex);
-#ifdef CONFIG_FCOE_MODULE
- /*
- * Make sure the module has been initialized, and is not about to be
- * removed. Module paramter sysfs files are writable before the
- * module_init function is called and after module_exit.
- */
- if (THIS_MODULE->state != MODULE_STATE_LIVE) {
- rc = -ENODEV;
- goto out_nodev;
- }
-#endif
- if (!rtnl_trylock()) {
- mutex_unlock(&fcoe_config_mutex);
- return -ERESTARTSYS;
- }
-
+ rtnl_lock();
fcoe = fcoe_hostlist_lookup_port(netdev);
rtnl_unlock();
@@ -1852,7 +1810,6 @@ static int fcoe_enable(struct net_device *netdev)
else if (!fcoe_link_ok(fcoe->ctlr.lp))
fcoe_ctlr_link_up(&fcoe->ctlr);
-out_nodev:
mutex_unlock(&fcoe_config_mutex);
return rc;
}
@@ -1868,35 +1825,22 @@ out_nodev:
static int fcoe_destroy(struct net_device *netdev)
{
struct fcoe_interface *fcoe;
+ struct fc_lport *lport;
int rc = 0;
mutex_lock(&fcoe_config_mutex);
-#ifdef CONFIG_FCOE_MODULE
- /*
- * Make sure the module has been initialized, and is not about to be
- * removed. Module paramter sysfs files are writable before the
- * module_init function is called and after module_exit.
- */
- if (THIS_MODULE->state != MODULE_STATE_LIVE) {
- rc = -ENODEV;
- goto out_nodev;
- }
-#endif
- if (!rtnl_trylock()) {
- mutex_unlock(&fcoe_config_mutex);
- return -ERESTARTSYS;
- }
-
+ rtnl_lock();
fcoe = fcoe_hostlist_lookup_port(netdev);
if (!fcoe) {
rtnl_unlock();
rc = -ENODEV;
goto out_nodev;
}
- fcoe_interface_cleanup(fcoe);
+ lport = fcoe->ctlr.lp;
list_del(&fcoe->list);
- /* RTNL mutex is dropped by fcoe_if_destroy */
- fcoe_if_destroy(fcoe->ctlr.lp);
+ fcoe_interface_cleanup(fcoe);
+ rtnl_unlock();
+ fcoe_if_destroy(lport);
out_nodev:
mutex_unlock(&fcoe_config_mutex);
return rc;
@@ -1912,8 +1856,6 @@ static void fcoe_destroy_work(struct work_struct *work)
port = container_of(work, struct fcoe_port, destroy_work);
mutex_lock(&fcoe_config_mutex);
- rtnl_lock();
- /* RTNL mutex is dropped by fcoe_if_destroy */
fcoe_if_destroy(port->lport);
mutex_unlock(&fcoe_config_mutex);
}
@@ -1948,23 +1890,7 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode)
struct fc_lport *lport;
mutex_lock(&fcoe_config_mutex);
-
- if (!rtnl_trylock()) {
- mutex_unlock(&fcoe_config_mutex);
- return -ERESTARTSYS;
- }
-
-#ifdef CONFIG_FCOE_MODULE
- /*
- * Make sure the module has been initialized, and is not about to be
- * removed. Module paramter sysfs files are writable before the
- * module_init function is called and after module_exit.
- */
- if (THIS_MODULE->state != MODULE_STATE_LIVE) {
- rc = -ENODEV;
- goto out_nodev;
- }
-#endif
+ rtnl_lock();
/* look for existing lport */
if (fcoe_hostlist_lookup(netdev)) {
@@ -2026,7 +1952,7 @@ out_nodev:
int fcoe_link_speed_update(struct fc_lport *lport)
{
struct net_device *netdev = fcoe_netdev(lport);
- struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+ struct ethtool_cmd ecmd;
if (!dev_ethtool_get_settings(netdev, &ecmd)) {
lport->link_supported_speeds &=
@@ -2037,11 +1963,14 @@ int fcoe_link_speed_update(struct fc_lport *lport)
if (ecmd.supported & SUPPORTED_10000baseT_Full)
lport->link_supported_speeds |=
FC_PORTSPEED_10GBIT;
- if (ecmd.speed == SPEED_1000)
+ switch (ethtool_cmd_speed(&ecmd)) {
+ case SPEED_1000:
lport->link_speed = FC_PORTSPEED_1GBIT;
- if (ecmd.speed == SPEED_10000)
+ break;
+ case SPEED_10000:
lport->link_speed = FC_PORTSPEED_10GBIT;
-
+ break;
+ }
return 0;
}
return -1;
diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c
index 9d38be2a41f9..229e4af5508a 100644
--- a/drivers/scsi/fcoe/fcoe_ctlr.c
+++ b/drivers/scsi/fcoe/fcoe_ctlr.c
@@ -978,10 +978,8 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
* the FCF that answers multicast solicitations, not the others that
* are sending periodic multicast advertisements.
*/
- if (mtu_valid) {
- list_del(&fcf->list);
- list_add(&fcf->list, &fip->fcfs);
- }
+ if (mtu_valid)
+ list_move(&fcf->list, &fip->fcfs);
/*
* If this is the first validated FCF, note the time and
diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c
index 258684101bfd..f81f77c8569e 100644
--- a/drivers/scsi/fcoe/fcoe_transport.c
+++ b/drivers/scsi/fcoe/fcoe_transport.c
@@ -335,7 +335,7 @@ out_attach:
EXPORT_SYMBOL(fcoe_transport_attach);
/**
- * fcoe_transport_attach - Detaches an FCoE transport
+ * fcoe_transport_detach - Detaches an FCoE transport
* @ft: The fcoe transport to be attached
*
* Returns : 0 for success
@@ -343,6 +343,7 @@ EXPORT_SYMBOL(fcoe_transport_attach);
int fcoe_transport_detach(struct fcoe_transport *ft)
{
int rc = 0;
+ struct fcoe_netdev_mapping *nm = NULL, *tmp;
mutex_lock(&ft_mutex);
if (!ft->attached) {
@@ -352,6 +353,19 @@ int fcoe_transport_detach(struct fcoe_transport *ft)
goto out_attach;
}
+ /* remove netdev mapping for this transport as it is going away */
+ mutex_lock(&fn_mutex);
+ list_for_each_entry_safe(nm, tmp, &fcoe_netdevs, list) {
+ if (nm->ft == ft) {
+ LIBFCOE_TRANSPORT_DBG("transport %s going away, "
+ "remove its netdev mapping for %s\n",
+ ft->name, nm->netdev->name);
+ list_del(&nm->list);
+ kfree(nm);
+ }
+ }
+ mutex_unlock(&fn_mutex);
+
list_del(&ft->list);
ft->attached = false;
LIBFCOE_TRANSPORT_DBG("detaching transport %s\n", ft->name);
@@ -371,9 +385,9 @@ static int fcoe_transport_show(char *buffer, const struct kernel_param *kp)
i = j = sprintf(buffer, "Attached FCoE transports:");
mutex_lock(&ft_mutex);
list_for_each_entry(ft, &fcoe_transports, list) {
- i += snprintf(&buffer[i], IFNAMSIZ, "%s ", ft->name);
- if (i >= PAGE_SIZE)
+ if (i >= PAGE_SIZE - IFNAMSIZ)
break;
+ i += snprintf(&buffer[i], IFNAMSIZ, "%s ", ft->name);
}
mutex_unlock(&ft_mutex);
if (i == j)
@@ -530,9 +544,6 @@ static int fcoe_transport_create(const char *buffer, struct kernel_param *kp)
struct fcoe_transport *ft = NULL;
enum fip_state fip_mode = (enum fip_state)(long)kp->arg;
- if (!mutex_trylock(&ft_mutex))
- return restart_syscall();
-
#ifdef CONFIG_LIBFCOE_MODULE
/*
* Make sure the module has been initialized, and is not about to be
@@ -543,6 +554,8 @@ static int fcoe_transport_create(const char *buffer, struct kernel_param *kp)
goto out_nodev;
#endif
+ mutex_lock(&ft_mutex);
+
netdev = fcoe_if_to_netdev(buffer);
if (!netdev) {
LIBFCOE_TRANSPORT_DBG("Invalid device %s.\n", buffer);
@@ -586,10 +599,7 @@ out_putdev:
dev_put(netdev);
out_nodev:
mutex_unlock(&ft_mutex);
- if (rc == -ERESTARTSYS)
- return restart_syscall();
- else
- return rc;
+ return rc;
}
/**
@@ -608,9 +618,6 @@ static int fcoe_transport_destroy(const char *buffer, struct kernel_param *kp)
struct net_device *netdev = NULL;
struct fcoe_transport *ft = NULL;
- if (!mutex_trylock(&ft_mutex))
- return restart_syscall();
-
#ifdef CONFIG_LIBFCOE_MODULE
/*
* Make sure the module has been initialized, and is not about to be
@@ -621,6 +628,8 @@ static int fcoe_transport_destroy(const char *buffer, struct kernel_param *kp)
goto out_nodev;
#endif
+ mutex_lock(&ft_mutex);
+
netdev = fcoe_if_to_netdev(buffer);
if (!netdev) {
LIBFCOE_TRANSPORT_DBG("invalid device %s.\n", buffer);
@@ -645,11 +654,7 @@ out_putdev:
dev_put(netdev);
out_nodev:
mutex_unlock(&ft_mutex);
-
- if (rc == -ERESTARTSYS)
- return restart_syscall();
- else
- return rc;
+ return rc;
}
/**
@@ -667,9 +672,6 @@ static int fcoe_transport_disable(const char *buffer, struct kernel_param *kp)
struct net_device *netdev = NULL;
struct fcoe_transport *ft = NULL;
- if (!mutex_trylock(&ft_mutex))
- return restart_syscall();
-
#ifdef CONFIG_LIBFCOE_MODULE
/*
* Make sure the module has been initialized, and is not about to be
@@ -680,6 +682,8 @@ static int fcoe_transport_disable(const char *buffer, struct kernel_param *kp)
goto out_nodev;
#endif
+ mutex_lock(&ft_mutex);
+
netdev = fcoe_if_to_netdev(buffer);
if (!netdev)
goto out_nodev;
@@ -716,9 +720,6 @@ static int fcoe_transport_enable(const char *buffer, struct kernel_param *kp)
struct net_device *netdev = NULL;
struct fcoe_transport *ft = NULL;
- if (!mutex_trylock(&ft_mutex))
- return restart_syscall();
-
#ifdef CONFIG_LIBFCOE_MODULE
/*
* Make sure the module has been initialized, and is not about to be
@@ -729,6 +730,8 @@ static int fcoe_transport_enable(const char *buffer, struct kernel_param *kp)
goto out_nodev;
#endif
+ mutex_lock(&ft_mutex);
+
netdev = fcoe_if_to_netdev(buffer);
if (!netdev)
goto out_nodev;
@@ -743,10 +746,7 @@ out_putdev:
dev_put(netdev);
out_nodev:
mutex_unlock(&ft_mutex);
- if (rc == -ERESTARTSYS)
- return restart_syscall();
- else
- return rc;
+ return rc;
}
/**
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 415ad4fb50d4..c6c0434d8034 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -273,7 +273,7 @@ static ssize_t host_show_transport_mode(struct device *dev,
"performant" : "simple");
}
-/* List of controllers which cannot be reset on kexec with reset_devices */
+/* List of controllers which cannot be hard reset on kexec with reset_devices */
static u32 unresettable_controller[] = {
0x324a103C, /* Smart Array P712m */
0x324b103C, /* SmartArray P711m */
@@ -291,16 +291,45 @@ static u32 unresettable_controller[] = {
0x409D0E11, /* Smart Array 6400 EM */
};
-static int ctlr_is_resettable(struct ctlr_info *h)
+/* List of controllers which cannot even be soft reset */
+static u32 soft_unresettable_controller[] = {
+ /* 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.
+ */
+ 0x409C0E11, /* Smart Array 6400 */
+ 0x409D0E11, /* Smart Array 6400 EM */
+};
+
+static int ctlr_is_hard_resettable(u32 board_id)
{
int i;
for (i = 0; i < ARRAY_SIZE(unresettable_controller); i++)
- if (unresettable_controller[i] == h->board_id)
+ if (unresettable_controller[i] == board_id)
+ return 0;
+ return 1;
+}
+
+static int ctlr_is_soft_resettable(u32 board_id)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(soft_unresettable_controller); i++)
+ if (soft_unresettable_controller[i] == board_id)
return 0;
return 1;
}
+static int ctlr_is_resettable(u32 board_id)
+{
+ return ctlr_is_hard_resettable(board_id) ||
+ ctlr_is_soft_resettable(board_id);
+}
+
static ssize_t host_show_resettable(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -308,7 +337,7 @@ static ssize_t host_show_resettable(struct device *dev,
struct Scsi_Host *shost = class_to_shost(dev);
h = shost_to_hba(shost);
- return snprintf(buf, 20, "%d\n", ctlr_is_resettable(h));
+ return snprintf(buf, 20, "%d\n", ctlr_is_resettable(h->board_id));
}
static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[])
@@ -929,13 +958,6 @@ static void hpsa_slave_destroy(struct scsi_device *sdev)
/* nothing to do. */
}
-static void hpsa_scsi_setup(struct ctlr_info *h)
-{
- h->ndevices = 0;
- h->scsi_host = NULL;
- spin_lock_init(&h->devlock);
-}
-
static void hpsa_free_sg_chain_blocks(struct ctlr_info *h)
{
int i;
@@ -1006,8 +1028,7 @@ static void hpsa_unmap_sg_chain_block(struct ctlr_info *h,
pci_unmap_single(h->pdev, temp64.val, chain_sg->Len, PCI_DMA_TODEVICE);
}
-static void complete_scsi_command(struct CommandList *cp,
- int timeout, u32 tag)
+static void complete_scsi_command(struct CommandList *cp)
{
struct scsi_cmnd *cmd;
struct ctlr_info *h;
@@ -1308,7 +1329,7 @@ static void hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h,
int retry_count = 0;
do {
- memset(c->err_info, 0, sizeof(c->err_info));
+ memset(c->err_info, 0, sizeof(*c->err_info));
hpsa_scsi_do_simple_cmd_core(h, c);
retry_count++;
} while (check_for_unit_attention(h, c) && retry_count <= 3);
@@ -1570,6 +1591,7 @@ static unsigned char *msa2xxx_model[] = {
"MSA2024",
"MSA2312",
"MSA2324",
+ "P2000 G3 SAS",
NULL,
};
@@ -2751,6 +2773,26 @@ static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg)
}
}
+static int __devinit hpsa_send_host_reset(struct ctlr_info *h,
+ unsigned char *scsi3addr, u8 reset_type)
+{
+ struct CommandList *c;
+
+ c = cmd_alloc(h);
+ if (!c)
+ return -ENOMEM;
+ fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0,
+ RAID_CTLR_LUNID, TYPE_MSG);
+ c->Request.CDB[1] = reset_type; /* fill_cmd defaults to target reset */
+ c->waiting = NULL;
+ enqueue_cmd_and_start_io(h, c);
+ /* Don't wait for completion, the reset won't complete. Don't free
+ * the command either. This is the last command we will send before
+ * re-initializing everything, so it doesn't matter and won't leak.
+ */
+ return 0;
+}
+
static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
void *buff, size_t size, u8 page_code, unsigned char *scsi3addr,
int cmd_type)
@@ -2828,7 +2870,8 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
c->Request.Type.Attribute = ATTR_SIMPLE;
c->Request.Type.Direction = XFER_NONE;
c->Request.Timeout = 0; /* Don't time out */
- c->Request.CDB[0] = 0x01; /* RESET_MSG is 0x01 */
+ memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB));
+ c->Request.CDB[0] = cmd;
c->Request.CDB[1] = 0x03; /* Reset target above */
/* If bytes 4-7 are zero, it means reset the */
/* LunID device */
@@ -2936,7 +2979,7 @@ static inline void finish_cmd(struct CommandList *c, u32 raw_tag)
{
removeQ(c);
if (likely(c->cmd_type == CMD_SCSI))
- complete_scsi_command(c, 0, raw_tag);
+ complete_scsi_command(c);
else if (c->cmd_type == CMD_IOCTL_PEND)
complete(c->waiting);
}
@@ -2994,6 +3037,63 @@ static inline u32 process_nonindexed_cmd(struct ctlr_info *h,
return next_command(h);
}
+/* Some controllers, like p400, will give us one interrupt
+ * after a soft reset, even if we turned interrupts off.
+ * Only need to check for this in the hpsa_xxx_discard_completions
+ * functions.
+ */
+static int ignore_bogus_interrupt(struct ctlr_info *h)
+{
+ if (likely(!reset_devices))
+ return 0;
+
+ if (likely(h->interrupts_enabled))
+ return 0;
+
+ dev_info(&h->pdev->dev, "Received interrupt while interrupts disabled "
+ "(known firmware bug.) Ignoring.\n");
+
+ return 1;
+}
+
+static irqreturn_t hpsa_intx_discard_completions(int irq, void *dev_id)
+{
+ struct ctlr_info *h = dev_id;
+ unsigned long flags;
+ u32 raw_tag;
+
+ if (ignore_bogus_interrupt(h))
+ return IRQ_NONE;
+
+ 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)
+ raw_tag = next_command(h);
+ }
+ spin_unlock_irqrestore(&h->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t hpsa_msix_discard_completions(int irq, void *dev_id)
+{
+ struct ctlr_info *h = dev_id;
+ unsigned long flags;
+ u32 raw_tag;
+
+ if (ignore_bogus_interrupt(h))
+ return IRQ_NONE;
+
+ spin_lock_irqsave(&h->lock, flags);
+ raw_tag = get_next_completion(h);
+ while (raw_tag != FIFO_EMPTY)
+ raw_tag = next_command(h);
+ spin_unlock_irqrestore(&h->lock, flags);
+ return IRQ_HANDLED;
+}
+
static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id)
{
struct ctlr_info *h = dev_id;
@@ -3132,11 +3232,10 @@ static __devinit int hpsa_message(struct pci_dev *pdev, unsigned char opcode,
return 0;
}
-#define hpsa_soft_reset_controller(p) hpsa_message(p, 1, 0)
#define hpsa_noop(p) hpsa_message(p, 3, 0)
static int hpsa_controller_hard_reset(struct pci_dev *pdev,
- void * __iomem vaddr, bool use_doorbell)
+ void * __iomem vaddr, u32 use_doorbell)
{
u16 pmcsr;
int pos;
@@ -3147,8 +3246,7 @@ static int hpsa_controller_hard_reset(struct pci_dev *pdev,
* 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);
+ writel(use_doorbell, vaddr + SA5_DOORBELL);
} else { /* Try to do it the PCI power state way */
/* Quoting from the Open CISS Specification: "The Power
@@ -3179,12 +3277,63 @@ static int hpsa_controller_hard_reset(struct pci_dev *pdev,
pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
pmcsr |= PCI_D0;
pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
-
- msleep(500);
}
return 0;
}
+static __devinit void init_driver_version(char *driver_version, int len)
+{
+ memset(driver_version, 0, len);
+ strncpy(driver_version, "hpsa " HPSA_DRIVER_VERSION, len - 1);
+}
+
+static __devinit int write_driver_ver_to_cfgtable(
+ struct CfgTable __iomem *cfgtable)
+{
+ char *driver_version;
+ int i, size = sizeof(cfgtable->driver_version);
+
+ driver_version = kmalloc(size, GFP_KERNEL);
+ if (!driver_version)
+ return -ENOMEM;
+
+ init_driver_version(driver_version, size);
+ for (i = 0; i < size; i++)
+ writeb(driver_version[i], &cfgtable->driver_version[i]);
+ kfree(driver_version);
+ return 0;
+}
+
+static __devinit void read_driver_ver_from_cfgtable(
+ struct CfgTable __iomem *cfgtable, unsigned char *driver_ver)
+{
+ int i;
+
+ for (i = 0; i < sizeof(cfgtable->driver_version); i++)
+ driver_ver[i] = readb(&cfgtable->driver_version[i]);
+}
+
+static __devinit int controller_reset_failed(
+ struct CfgTable __iomem *cfgtable)
+{
+
+ char *driver_ver, *old_driver_ver;
+ int rc, size = sizeof(cfgtable->driver_version);
+
+ old_driver_ver = kmalloc(2 * size, GFP_KERNEL);
+ if (!old_driver_ver)
+ return -ENOMEM;
+ driver_ver = old_driver_ver + size;
+
+ /* After a reset, the 32 bytes of "driver version" in the cfgtable
+ * should have been changed, otherwise we know the reset failed.
+ */
+ init_driver_version(old_driver_ver, size);
+ read_driver_ver_from_cfgtable(cfgtable, driver_ver);
+ rc = !memcmp(driver_ver, old_driver_ver, size);
+ kfree(old_driver_ver);
+ return rc;
+}
/* This does a hard reset of the controller using PCI power management
* states or the using the doorbell register.
*/
@@ -3195,10 +3344,10 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
u64 cfg_base_addr_index;
void __iomem *vaddr;
unsigned long paddr;
- u32 misc_fw_support, active_transport;
+ u32 misc_fw_support;
int rc;
struct CfgTable __iomem *cfgtable;
- bool use_doorbell;
+ u32 use_doorbell;
u32 board_id;
u16 command_register;
@@ -3215,20 +3364,15 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
* 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.
- */
rc = hpsa_lookup_board_id(pdev, &board_id);
- if (rc < 0) {
+ if (rc < 0 || !ctlr_is_resettable(board_id)) {
dev_warn(&pdev->dev, "Not resetting device.\n");
return -ENODEV;
}
- if (board_id == 0x409C0E11 || board_id == 0x409D0E11)
- return -ENOTSUPP;
+
+ /* if controller is soft- but not hard resettable... */
+ if (!ctlr_is_hard_resettable(board_id))
+ return -ENOTSUPP; /* try soft reset later. */
/* Save the PCI command register */
pci_read_config_word(pdev, 4, &command_register);
@@ -3257,10 +3401,28 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
rc = -ENOMEM;
goto unmap_vaddr;
}
+ rc = write_driver_ver_to_cfgtable(cfgtable);
+ if (rc)
+ goto unmap_vaddr;
- /* If reset via doorbell register is supported, use that. */
+ /* If reset via doorbell register is supported, use that.
+ * There are two such methods. Favor the newest method.
+ */
misc_fw_support = readl(&cfgtable->misc_fw_support);
- use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET;
+ use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET2;
+ if (use_doorbell) {
+ use_doorbell = DOORBELL_CTLR_RESET2;
+ } else {
+ use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET;
+ if (use_doorbell) {
+ dev_warn(&pdev->dev, "Controller claims that "
+ "'Bit 2 doorbell reset' is "
+ "supported, but not 'bit 5 doorbell reset'. "
+ "Firmware update is recommended.\n");
+ rc = -ENOTSUPP; /* try soft reset */
+ goto unmap_cfgtable;
+ }
+ }
rc = hpsa_controller_hard_reset(pdev, vaddr, use_doorbell);
if (rc)
@@ -3279,30 +3441,32 @@ static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
msleep(HPSA_POST_RESET_PAUSE_MSECS);
/* Wait for board to become not ready, then ready. */
- dev_info(&pdev->dev, "Waiting for board to become ready.\n");
+ dev_info(&pdev->dev, "Waiting for board to reset.\n");
rc = hpsa_wait_for_board_state(pdev, vaddr, BOARD_NOT_READY);
- if (rc)
+ if (rc) {
dev_warn(&pdev->dev,
- "failed waiting for board to become not ready\n");
+ "failed waiting for board to reset."
+ " Will try soft reset.\n");
+ rc = -ENOTSUPP; /* Not expected, but try soft reset later */
+ goto unmap_cfgtable;
+ }
rc = hpsa_wait_for_board_state(pdev, vaddr, BOARD_READY);
if (rc) {
dev_warn(&pdev->dev,
- "failed waiting for board to become ready\n");
+ "failed waiting for board to become ready "
+ "after hard reset\n");
goto unmap_cfgtable;
}
- dev_info(&pdev->dev, "board ready.\n");
- /* 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, don't try to proceed, as it generally doesn't work.
- */
- active_transport = readl(&cfgtable->TransportActive);
- if (active_transport & PERFORMANT_MODE) {
- dev_warn(&pdev->dev, "Unable to successfully reset controller,"
- " Ignoring controller.\n");
- rc = -ENODEV;
+ rc = controller_reset_failed(vaddr);
+ if (rc < 0)
+ goto unmap_cfgtable;
+ if (rc) {
+ dev_warn(&pdev->dev, "Unable to successfully reset "
+ "controller. Will try soft reset.\n");
+ rc = -ENOTSUPP;
+ } else {
+ dev_info(&pdev->dev, "board ready after hard reset.\n");
}
unmap_cfgtable:
@@ -3543,6 +3707,9 @@ static int __devinit hpsa_find_cfgtables(struct ctlr_info *h)
cfg_base_addr_index) + cfg_offset, sizeof(*h->cfgtable));
if (!h->cfgtable)
return -ENOMEM;
+ rc = write_driver_ver_to_cfgtable(h->cfgtable);
+ if (rc)
+ return rc;
/* Find performant mode table. */
trans_offset = readl(&h->cfgtable->TransMethodOffset);
h->transtable = remap_pci_mem(pci_resource_start(h->pdev,
@@ -3777,11 +3944,12 @@ static __devinit int hpsa_init_reset_devices(struct pci_dev *pdev)
* due to concerns about shared bbwc between 6402/6404 pair.
*/
if (rc == -ENOTSUPP)
- return 0; /* just try to do the kdump anyhow. */
+ return rc; /* just try to do the kdump anyhow. */
if (rc)
return -ENODEV;
/* Now try to get the controller to respond to a no-op */
+ dev_warn(&pdev->dev, "Waiting for controller to respond to no-op\n");
for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) {
if (hpsa_noop(pdev) == 0)
break;
@@ -3792,18 +3960,133 @@ static __devinit int hpsa_init_reset_devices(struct pci_dev *pdev)
return 0;
}
+static __devinit int hpsa_allocate_cmd_pool(struct ctlr_info *h)
+{
+ h->cmd_pool_bits = kzalloc(
+ DIV_ROUND_UP(h->nr_cmds, BITS_PER_LONG) *
+ sizeof(unsigned long), GFP_KERNEL);
+ h->cmd_pool = pci_alloc_consistent(h->pdev,
+ h->nr_cmds * sizeof(*h->cmd_pool),
+ &(h->cmd_pool_dhandle));
+ h->errinfo_pool = pci_alloc_consistent(h->pdev,
+ h->nr_cmds * sizeof(*h->errinfo_pool),
+ &(h->errinfo_pool_dhandle));
+ if ((h->cmd_pool_bits == NULL)
+ || (h->cmd_pool == NULL)
+ || (h->errinfo_pool == NULL)) {
+ dev_err(&h->pdev->dev, "out of memory in %s", __func__);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static void hpsa_free_cmd_pool(struct ctlr_info *h)
+{
+ kfree(h->cmd_pool_bits);
+ if (h->cmd_pool)
+ pci_free_consistent(h->pdev,
+ h->nr_cmds * sizeof(struct CommandList),
+ h->cmd_pool, h->cmd_pool_dhandle);
+ if (h->errinfo_pool)
+ pci_free_consistent(h->pdev,
+ h->nr_cmds * sizeof(struct ErrorInfo),
+ h->errinfo_pool,
+ h->errinfo_pool_dhandle);
+}
+
+static int hpsa_request_irq(struct ctlr_info *h,
+ irqreturn_t (*msixhandler)(int, void *),
+ irqreturn_t (*intxhandler)(int, void *))
+{
+ int rc;
+
+ if (h->msix_vector || h->msi_vector)
+ rc = request_irq(h->intr[h->intr_mode], msixhandler,
+ IRQF_DISABLED, h->devname, h);
+ else
+ rc = request_irq(h->intr[h->intr_mode], intxhandler,
+ IRQF_DISABLED, h->devname, h);
+ if (rc) {
+ dev_err(&h->pdev->dev, "unable to get irq %d for %s\n",
+ h->intr[h->intr_mode], h->devname);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int __devinit hpsa_kdump_soft_reset(struct ctlr_info *h)
+{
+ if (hpsa_send_host_reset(h, RAID_CTLR_LUNID,
+ HPSA_RESET_TYPE_CONTROLLER)) {
+ dev_warn(&h->pdev->dev, "Resetting array controller failed.\n");
+ return -EIO;
+ }
+
+ dev_info(&h->pdev->dev, "Waiting for board to soft reset.\n");
+ if (hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_NOT_READY)) {
+ dev_warn(&h->pdev->dev, "Soft reset had no effect.\n");
+ return -1;
+ }
+
+ dev_info(&h->pdev->dev, "Board reset, awaiting READY status.\n");
+ if (hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY)) {
+ dev_warn(&h->pdev->dev, "Board failed to become ready "
+ "after soft reset.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h)
+{
+ free_irq(h->intr[h->intr_mode], h);
+#ifdef CONFIG_PCI_MSI
+ if (h->msix_vector)
+ pci_disable_msix(h->pdev);
+ else if (h->msi_vector)
+ pci_disable_msi(h->pdev);
+#endif /* CONFIG_PCI_MSI */
+ hpsa_free_sg_chain_blocks(h);
+ hpsa_free_cmd_pool(h);
+ kfree(h->blockFetchTable);
+ pci_free_consistent(h->pdev, h->reply_pool_size,
+ h->reply_pool, h->reply_pool_dhandle);
+ if (h->vaddr)
+ iounmap(h->vaddr);
+ if (h->transtable)
+ iounmap(h->transtable);
+ if (h->cfgtable)
+ iounmap(h->cfgtable);
+ pci_release_regions(h->pdev);
+ kfree(h);
+}
+
static int __devinit hpsa_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
int dac, rc;
struct ctlr_info *h;
+ int try_soft_reset = 0;
+ unsigned long flags;
if (number_of_controllers == 0)
printk(KERN_INFO DRIVER_NAME "\n");
rc = hpsa_init_reset_devices(pdev);
- if (rc)
- return rc;
+ if (rc) {
+ if (rc != -ENOTSUPP)
+ return rc;
+ /* If the reset fails in a particular way (it has no way to do
+ * a proper hard reset, so returns -ENOTSUPP) we can try to do
+ * a soft reset once we get the controller configured up to the
+ * point that it can accept a command.
+ */
+ try_soft_reset = 1;
+ rc = 0;
+ }
+
+reinit_after_soft_reset:
/* 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
@@ -3847,54 +4130,82 @@ 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);
- if (h->msix_vector || h->msi_vector)
- rc = request_irq(h->intr[h->intr_mode], do_hpsa_intr_msi,
- IRQF_DISABLED, h->devname, h);
- else
- rc = request_irq(h->intr[h->intr_mode], 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[h->intr_mode], h->devname);
+ if (hpsa_request_irq(h, do_hpsa_intr_msi, do_hpsa_intr_intx))
goto clean2;
- }
-
dev_info(&pdev->dev, "%s: <0x%x> at IRQ %d%s using DAC\n",
h->devname, pdev->device,
h->intr[h->intr_mode], dac ? "" : " not");
-
- h->cmd_pool_bits =
- kmalloc(((h->nr_cmds + BITS_PER_LONG -
- 1) / BITS_PER_LONG) * sizeof(unsigned long), GFP_KERNEL);
- h->cmd_pool = pci_alloc_consistent(h->pdev,
- h->nr_cmds * sizeof(*h->cmd_pool),
- &(h->cmd_pool_dhandle));
- h->errinfo_pool = pci_alloc_consistent(h->pdev,
- h->nr_cmds * sizeof(*h->errinfo_pool),
- &(h->errinfo_pool_dhandle));
- if ((h->cmd_pool_bits == NULL)
- || (h->cmd_pool == NULL)
- || (h->errinfo_pool == NULL)) {
- dev_err(&pdev->dev, "out of memory");
- rc = -ENOMEM;
+ if (hpsa_allocate_cmd_pool(h))
goto clean4;
- }
if (hpsa_allocate_sg_chain_blocks(h))
goto clean4;
init_waitqueue_head(&h->scan_wait_queue);
h->scan_finished = 1; /* no scan currently in progress */
pci_set_drvdata(pdev, h);
- memset(h->cmd_pool_bits, 0,
- ((h->nr_cmds + BITS_PER_LONG -
- 1) / BITS_PER_LONG) * sizeof(unsigned long));
+ h->ndevices = 0;
+ h->scsi_host = NULL;
+ spin_lock_init(&h->devlock);
+ hpsa_put_ctlr_into_performant_mode(h);
+
+ /* At this point, the controller is ready to take commands.
+ * Now, if reset_devices and the hard reset didn't work, try
+ * the soft reset and see if that works.
+ */
+ if (try_soft_reset) {
+
+ /* This is kind of gross. We may or may not get a completion
+ * from the soft reset command, and if we do, then the value
+ * from the fifo may or may not be valid. So, we wait 10 secs
+ * after the reset throwing away any completions we get during
+ * that time. Unregister the interrupt handler and register
+ * fake ones to scoop up any residual completions.
+ */
+ spin_lock_irqsave(&h->lock, flags);
+ h->access.set_intr_mask(h, HPSA_INTR_OFF);
+ spin_unlock_irqrestore(&h->lock, flags);
+ free_irq(h->intr[h->intr_mode], h);
+ rc = hpsa_request_irq(h, hpsa_msix_discard_completions,
+ hpsa_intx_discard_completions);
+ if (rc) {
+ dev_warn(&h->pdev->dev, "Failed to request_irq after "
+ "soft reset.\n");
+ goto clean4;
+ }
+
+ rc = hpsa_kdump_soft_reset(h);
+ if (rc)
+ /* Neither hard nor soft reset worked, we're hosed. */
+ goto clean4;
+
+ dev_info(&h->pdev->dev, "Board READY.\n");
+ dev_info(&h->pdev->dev,
+ "Waiting for stale completions to drain.\n");
+ h->access.set_intr_mask(h, HPSA_INTR_ON);
+ msleep(10000);
+ h->access.set_intr_mask(h, HPSA_INTR_OFF);
+
+ rc = controller_reset_failed(h->cfgtable);
+ if (rc)
+ dev_info(&h->pdev->dev,
+ "Soft reset appears to have failed.\n");
+
+ /* since the controller's reset, we have to go back and re-init
+ * everything. Easiest to just forget what we've done and do it
+ * all over again.
+ */
+ hpsa_undo_allocations_after_kdump_soft_reset(h);
+ try_soft_reset = 0;
+ if (rc)
+ /* don't go to clean4, we already unallocated */
+ return -ENODEV;
- hpsa_scsi_setup(h);
+ goto reinit_after_soft_reset;
+ }
/* Turn the interrupts on so we can service requests */
h->access.set_intr_mask(h, HPSA_INTR_ON);
- hpsa_put_ctlr_into_performant_mode(h);
hpsa_hba_inquiry(h);
hpsa_register_scsi(h); /* hook ourselves into SCSI subsystem */
h->busy_initializing = 0;
@@ -3902,16 +4213,7 @@ static int __devinit hpsa_init_one(struct pci_dev *pdev,
clean4:
hpsa_free_sg_chain_blocks(h);
- kfree(h->cmd_pool_bits);
- if (h->cmd_pool)
- pci_free_consistent(h->pdev,
- h->nr_cmds * sizeof(struct CommandList),
- h->cmd_pool, h->cmd_pool_dhandle);
- if (h->errinfo_pool)
- pci_free_consistent(h->pdev,
- h->nr_cmds * sizeof(struct ErrorInfo),
- h->errinfo_pool,
- h->errinfo_pool_dhandle);
+ hpsa_free_cmd_pool(h);
free_irq(h->intr[h->intr_mode], h);
clean2:
clean1:
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 621a1530054a..6d8dcd4dd06b 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -127,10 +127,12 @@ struct ctlr_info {
};
#define HPSA_ABORT_MSG 0
#define HPSA_DEVICE_RESET_MSG 1
-#define HPSA_BUS_RESET_MSG 2
-#define HPSA_HOST_RESET_MSG 3
+#define HPSA_RESET_TYPE_CONTROLLER 0x00
+#define HPSA_RESET_TYPE_BUS 0x01
+#define HPSA_RESET_TYPE_TARGET 0x03
+#define HPSA_RESET_TYPE_LUN 0x04
#define HPSA_MSG_SEND_RETRY_LIMIT 10
-#define HPSA_MSG_SEND_RETRY_INTERVAL_MSECS 1000
+#define HPSA_MSG_SEND_RETRY_INTERVAL_MSECS (10000)
/* Maximum time in seconds driver will wait for command completions
* when polling before giving up.
@@ -155,7 +157,7 @@ struct ctlr_info {
* HPSA_BOARD_READY_ITERATIONS are derived from those.
*/
#define HPSA_BOARD_READY_WAIT_SECS (120)
-#define HPSA_BOARD_NOT_READY_WAIT_SECS (10)
+#define HPSA_BOARD_NOT_READY_WAIT_SECS (100)
#define HPSA_BOARD_READY_POLL_INTERVAL_MSECS (100)
#define HPSA_BOARD_READY_POLL_INTERVAL \
((HPSA_BOARD_READY_POLL_INTERVAL_MSECS * HZ) / 1000)
@@ -212,6 +214,7 @@ static void SA5_submit_command(struct ctlr_info *h,
dev_dbg(&h->pdev->dev, "Sending %x, tag = %x\n", c->busaddr,
c->Header.Tag.lower);
writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET);
+ (void) readl(h->vaddr + SA5_REQUEST_PORT_OFFSET);
h->commands_outstanding++;
if (h->commands_outstanding > h->max_outstanding)
h->max_outstanding = h->commands_outstanding;
@@ -227,10 +230,12 @@ static void SA5_intr_mask(struct ctlr_info *h, unsigned long val)
if (val) { /* Turn interrupts on */
h->interrupts_enabled = 1;
writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+ (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
} else { /* Turn them off */
h->interrupts_enabled = 0;
writel(SA5_INTR_OFF,
h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+ (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
}
}
@@ -239,10 +244,12 @@ static void SA5_performant_intr_mask(struct ctlr_info *h, unsigned long val)
if (val) { /* turn on interrupts */
h->interrupts_enabled = 1;
writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+ (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
} else {
h->interrupts_enabled = 0;
writel(SA5_PERF_INTR_OFF,
h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+ (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET);
}
}
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index 18464900e761..55d741b019db 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -101,6 +101,7 @@
#define CFGTBL_ChangeReq 0x00000001l
#define CFGTBL_AccCmds 0x00000001l
#define DOORBELL_CTLR_RESET 0x00000004l
+#define DOORBELL_CTLR_RESET2 0x00000020l
#define CFGTBL_Trans_Simple 0x00000002l
#define CFGTBL_Trans_Performant 0x00000004l
@@ -256,14 +257,6 @@ struct ErrorInfo {
#define CMD_IOCTL_PEND 0x01
#define CMD_SCSI 0x03
-/* This structure needs to be divisible by 32 for new
- * indexing method and performant mode.
- */
-#define PAD32 32
-#define PAD64DIFF 0
-#define USEEXTRA ((sizeof(void *) - 4)/4)
-#define PADSIZE (PAD32 + PAD64DIFF * USEEXTRA)
-
#define DIRECT_LOOKUP_SHIFT 5
#define DIRECT_LOOKUP_BIT 0x10
#define DIRECT_LOOKUP_MASK (~((1 << DIRECT_LOOKUP_SHIFT) - 1))
@@ -345,6 +338,8 @@ struct CfgTable {
u8 reserved[0x78 - 0x58];
u32 misc_fw_support; /* offset 0x78 */
#define MISC_FW_DOORBELL_RESET (0x02)
+#define MISC_FW_DOORBELL_RESET2 (0x010)
+ u8 driver_version[32];
};
#define NUM_BLOCKFETCH_ENTRIES 8
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 041958453e2a..3d391dc3f11f 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -1849,8 +1849,7 @@ static void ibmvscsi_do_work(struct ibmvscsi_host_data *hostdata)
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));
+ vio_enable_interrupts(to_vio_dev(hostdata->dev));
} else if (hostdata->reenable_crq) {
smp_rmb();
action = "enable";
diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
index 6568aab745a0..112f1bec7756 100644
--- a/drivers/scsi/in2000.c
+++ b/drivers/scsi/in2000.c
@@ -343,7 +343,7 @@ static int in2000_queuecommand_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
instance = cmd->device->host;
hostdata = (struct IN2000_hostdata *) instance->hostdata;
- DB(DB_QUEUE_COMMAND, scmd_printk(KERN_DEBUG, cmd, "Q-%02x-%ld(", cmd->cmnd[0], cmd->serial_number))
+ DB(DB_QUEUE_COMMAND, scmd_printk(KERN_DEBUG, cmd, "Q-%02x(", cmd->cmnd[0]))
/* Set up a few fields in the Scsi_Cmnd structure for our own use:
* - host_scribble is the pointer to the next cmd in the input queue
@@ -427,7 +427,7 @@ static int in2000_queuecommand_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
in2000_execute(cmd->device->host);
- DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->serial_number))
+ DB(DB_QUEUE_COMMAND, printk(")Q "))
return 0;
}
@@ -705,7 +705,7 @@ static void in2000_execute(struct Scsi_Host *instance)
* to search the input_Q again...
*/
- DB(DB_EXECUTE, printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->serial_number))
+ DB(DB_EXECUTE, printk("%s)EX-2 ", (cmd->SCp.phase) ? "d:" : ""))
}
@@ -1149,7 +1149,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
case CSR_XFER_DONE | PHS_COMMAND:
case CSR_UNEXP | PHS_COMMAND:
case CSR_SRV_REQ | PHS_COMMAND:
- DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->serial_number))
+ DB(DB_INTR, printk("CMND-%02x", cmd->cmnd[0]))
transfer_pio(cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, hostdata);
hostdata->state = S_CONNECTED;
break;
@@ -1191,7 +1191,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
switch (msg) {
case COMMAND_COMPLETE:
- DB(DB_INTR, printk("CCMP-%ld", cmd->serial_number))
+ DB(DB_INTR, printk("CCMP"))
write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
hostdata->state = S_PRE_CMP_DISC;
break;
@@ -1329,7 +1329,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
write_3393(hostdata, WD_SOURCE_ID, SRCID_ER);
if (phs == 0x60) {
- DB(DB_INTR, printk("SX-DONE-%ld", cmd->serial_number))
+ DB(DB_INTR, printk("SX-DONE"))
cmd->SCp.Message = COMMAND_COMPLETE;
lun = read_3393(hostdata, WD_TARGET_LUN);
DB(DB_INTR, printk(":%d.%d", cmd->SCp.Status, lun))
@@ -1350,7 +1350,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
in2000_execute(instance);
} else {
- printk("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---", asr, sr, phs, cmd->serial_number);
+ printk("%02x:%02x:%02x: Unknown SEL_XFER_DONE phase!!---", asr, sr, phs);
}
break;
@@ -1417,7 +1417,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
spin_unlock_irqrestore(instance->host_lock, flags);
return IRQ_HANDLED;
}
- DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->serial_number))
+ DB(DB_INTR, printk("UNEXP_DISC"))
hostdata->connected = NULL;
hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
hostdata->state = S_UNCONNECTED;
@@ -1442,7 +1442,7 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
*/
write_3393(hostdata, WD_SOURCE_ID, SRCID_ER);
- DB(DB_INTR, printk("DISC-%ld", cmd->serial_number))
+ DB(DB_INTR, printk("DISC"))
if (cmd == NULL) {
printk(" - Already disconnected! ");
hostdata->state = S_UNCONNECTED;
@@ -1575,7 +1575,6 @@ static irqreturn_t in2000_intr(int irqnum, void *dev_id)
} else
hostdata->state = S_CONNECTED;
- DB(DB_INTR, printk("-%ld", cmd->serial_number))
break;
default:
@@ -1704,7 +1703,7 @@ static int __in2000_abort(Scsi_Cmnd * cmd)
prev->host_scribble = cmd->host_scribble;
cmd->host_scribble = NULL;
cmd->result = DID_ABORT << 16;
- printk(KERN_WARNING "scsi%d: Abort - removing command %ld from input_Q. ", instance->host_no, cmd->serial_number);
+ printk(KERN_WARNING "scsi%d: Abort - removing command from input_Q. ", instance->host_no);
cmd->scsi_done(cmd);
return SUCCESS;
}
@@ -1725,7 +1724,7 @@ static int __in2000_abort(Scsi_Cmnd * cmd)
if (hostdata->connected == cmd) {
- printk(KERN_WARNING "scsi%d: Aborting connected command %ld - ", instance->host_no, cmd->serial_number);
+ printk(KERN_WARNING "scsi%d: Aborting connected command - ", instance->host_no);
printk("sending wd33c93 ABORT command - ");
write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
@@ -2228,7 +2227,7 @@ static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start,
bp = buf;
*bp = '\0';
if (hd->proc & PR_VERSION) {
- sprintf(tbuf, "\nVersion %s - %s. Compiled %s %s", IN2000_VERSION, IN2000_DATE, __DATE__, __TIME__);
+ sprintf(tbuf, "\nVersion %s - %s.", IN2000_VERSION, IN2000_DATE);
strcat(bp, tbuf);
}
if (hd->proc & PR_INFO) {
@@ -2270,7 +2269,7 @@ static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start,
strcat(bp, "\nconnected: ");
if (hd->connected) {
cmd = (Scsi_Cmnd *) hd->connected;
- sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+ sprintf(tbuf, " %d:%d(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
strcat(bp, tbuf);
}
}
@@ -2278,7 +2277,7 @@ static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start,
strcat(bp, "\ninput_Q: ");
cmd = (Scsi_Cmnd *) hd->input_Q;
while (cmd) {
- sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+ sprintf(tbuf, " %d:%d(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
strcat(bp, tbuf);
cmd = (Scsi_Cmnd *) cmd->host_scribble;
}
@@ -2287,7 +2286,7 @@ static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start,
strcat(bp, "\ndisconnected_Q:");
cmd = (Scsi_Cmnd *) hd->disconnected_Q;
while (cmd) {
- sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->serial_number, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+ sprintf(tbuf, " %d:%d(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
strcat(bp, tbuf);
cmd = (Scsi_Cmnd *) cmd->host_scribble;
}
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 0621238fac4a..12868ca46110 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -60,6 +60,7 @@
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/slab.h>
+#include <linux/vmalloc.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/pci.h>
@@ -2717,13 +2718,18 @@ static int ipr_sdt_copy(struct ipr_ioa_cfg *ioa_cfg,
unsigned long pci_address, u32 length)
{
int bytes_copied = 0;
- int cur_len, rc, rem_len, rem_page_len;
+ int cur_len, rc, rem_len, rem_page_len, max_dump_size;
__be32 *page;
unsigned long lock_flags = 0;
struct ipr_ioa_dump *ioa_dump = &ioa_cfg->dump->ioa_dump;
+ if (ioa_cfg->sis64)
+ max_dump_size = IPR_FMT3_MAX_IOA_DUMP_SIZE;
+ else
+ max_dump_size = IPR_FMT2_MAX_IOA_DUMP_SIZE;
+
while (bytes_copied < length &&
- (ioa_dump->hdr.len + bytes_copied) < IPR_MAX_IOA_DUMP_SIZE) {
+ (ioa_dump->hdr.len + bytes_copied) < max_dump_size) {
if (ioa_dump->page_offset >= PAGE_SIZE ||
ioa_dump->page_offset == 0) {
page = (__be32 *)__get_free_page(GFP_ATOMIC);
@@ -2885,8 +2891,8 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump)
unsigned long lock_flags = 0;
struct ipr_driver_dump *driver_dump = &dump->driver_dump;
struct ipr_ioa_dump *ioa_dump = &dump->ioa_dump;
- u32 num_entries, start_off, end_off;
- u32 bytes_to_copy, bytes_copied, rc;
+ u32 num_entries, max_num_entries, start_off, end_off;
+ u32 max_dump_size, bytes_to_copy, bytes_copied, rc;
struct ipr_sdt *sdt;
int valid = 1;
int i;
@@ -2947,8 +2953,18 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump)
on entries in this table */
sdt = &ioa_dump->sdt;
+ if (ioa_cfg->sis64) {
+ max_num_entries = IPR_FMT3_NUM_SDT_ENTRIES;
+ max_dump_size = IPR_FMT3_MAX_IOA_DUMP_SIZE;
+ } else {
+ max_num_entries = IPR_FMT2_NUM_SDT_ENTRIES;
+ max_dump_size = IPR_FMT2_MAX_IOA_DUMP_SIZE;
+ }
+
+ bytes_to_copy = offsetof(struct ipr_sdt, entry) +
+ (max_num_entries * sizeof(struct ipr_sdt_entry));
rc = ipr_get_ldump_data_section(ioa_cfg, start_addr, (__be32 *)sdt,
- sizeof(struct ipr_sdt) / sizeof(__be32));
+ bytes_to_copy / sizeof(__be32));
/* Smart Dump table is ready to use and the first entry is valid */
if (rc || ((be32_to_cpu(sdt->hdr.state) != IPR_FMT3_SDT_READY_TO_USE) &&
@@ -2964,13 +2980,20 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump)
num_entries = be32_to_cpu(sdt->hdr.num_entries_used);
- if (num_entries > IPR_NUM_SDT_ENTRIES)
- num_entries = IPR_NUM_SDT_ENTRIES;
+ if (num_entries > max_num_entries)
+ num_entries = max_num_entries;
+
+ /* Update dump length to the actual data to be copied */
+ dump->driver_dump.hdr.len += sizeof(struct ipr_sdt_header);
+ if (ioa_cfg->sis64)
+ dump->driver_dump.hdr.len += num_entries * sizeof(struct ipr_sdt_entry);
+ else
+ dump->driver_dump.hdr.len += max_num_entries * sizeof(struct ipr_sdt_entry);
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
for (i = 0; i < num_entries; i++) {
- if (ioa_dump->hdr.len > IPR_MAX_IOA_DUMP_SIZE) {
+ if (ioa_dump->hdr.len > max_dump_size) {
driver_dump->hdr.status = IPR_DUMP_STATUS_QUAL_SUCCESS;
break;
}
@@ -2989,7 +3012,7 @@ static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump)
valid = 0;
}
if (valid) {
- if (bytes_to_copy > IPR_MAX_IOA_DUMP_SIZE) {
+ if (bytes_to_copy > max_dump_size) {
sdt->entry[i].flags &= ~IPR_SDT_VALID_ENTRY;
continue;
}
@@ -3044,6 +3067,7 @@ static void ipr_release_dump(struct kref *kref)
for (i = 0; i < dump->ioa_dump.next_page_index; i++)
free_page((unsigned long) dump->ioa_dump.ioa_data[i]);
+ vfree(dump->ioa_dump.ioa_data);
kfree(dump);
LEAVE;
}
@@ -3835,7 +3859,7 @@ static ssize_t ipr_read_dump(struct file *filp, struct kobject *kobj,
struct ipr_dump *dump;
unsigned long lock_flags = 0;
char *src;
- int len;
+ int len, sdt_end;
size_t rc = count;
if (!capable(CAP_SYS_ADMIN))
@@ -3875,9 +3899,17 @@ static ssize_t ipr_read_dump(struct file *filp, struct kobject *kobj,
off -= sizeof(dump->driver_dump);
- if (count && off < offsetof(struct ipr_ioa_dump, ioa_data)) {
- if (off + count > offsetof(struct ipr_ioa_dump, ioa_data))
- len = offsetof(struct ipr_ioa_dump, ioa_data) - off;
+ if (ioa_cfg->sis64)
+ sdt_end = offsetof(struct ipr_ioa_dump, sdt.entry) +
+ (be32_to_cpu(dump->ioa_dump.sdt.hdr.num_entries_used) *
+ sizeof(struct ipr_sdt_entry));
+ else
+ sdt_end = offsetof(struct ipr_ioa_dump, sdt.entry) +
+ (IPR_FMT2_NUM_SDT_ENTRIES * sizeof(struct ipr_sdt_entry));
+
+ if (count && off < sdt_end) {
+ if (off + count > sdt_end)
+ len = sdt_end - off;
else
len = count;
src = (u8 *)&dump->ioa_dump + off;
@@ -3887,7 +3919,7 @@ static ssize_t ipr_read_dump(struct file *filp, struct kobject *kobj,
count -= len;
}
- off -= offsetof(struct ipr_ioa_dump, ioa_data);
+ off -= sdt_end;
while (count) {
if ((off & PAGE_MASK) != ((off + count) & PAGE_MASK))
@@ -3916,6 +3948,7 @@ static ssize_t ipr_read_dump(struct file *filp, struct kobject *kobj,
static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg)
{
struct ipr_dump *dump;
+ __be32 **ioa_data;
unsigned long lock_flags = 0;
dump = kzalloc(sizeof(struct ipr_dump), GFP_KERNEL);
@@ -3925,6 +3958,19 @@ static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg)
return -ENOMEM;
}
+ if (ioa_cfg->sis64)
+ ioa_data = vmalloc(IPR_FMT3_MAX_NUM_DUMP_PAGES * sizeof(__be32 *));
+ else
+ ioa_data = vmalloc(IPR_FMT2_MAX_NUM_DUMP_PAGES * sizeof(__be32 *));
+
+ if (!ioa_data) {
+ ipr_err("Dump memory allocation failed\n");
+ kfree(dump);
+ return -ENOMEM;
+ }
+
+ dump->ioa_dump.ioa_data = ioa_data;
+
kref_init(&dump->kref);
dump->ioa_cfg = ioa_cfg;
@@ -3932,6 +3978,7 @@ static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg)
if (INACTIVE != ioa_cfg->sdt_state) {
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+ vfree(dump->ioa_dump.ioa_data);
kfree(dump);
return 0;
}
@@ -4953,9 +5000,35 @@ static int ipr_eh_abort(struct scsi_cmnd * scsi_cmd)
* IRQ_NONE / IRQ_HANDLED
**/
static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg,
- volatile u32 int_reg)
+ u32 int_reg)
{
irqreturn_t rc = IRQ_HANDLED;
+ u32 int_mask_reg;
+
+ int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg32);
+ int_reg &= ~int_mask_reg;
+
+ /* If an interrupt on the adapter did not occur, ignore it.
+ * Or in the case of SIS 64, check for a stage change interrupt.
+ */
+ if ((int_reg & IPR_PCII_OPER_INTERRUPTS) == 0) {
+ if (ioa_cfg->sis64) {
+ int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
+ int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
+ if (int_reg & IPR_PCII_IPL_STAGE_CHANGE) {
+
+ /* clear stage change */
+ writel(IPR_PCII_IPL_STAGE_CHANGE, ioa_cfg->regs.clr_interrupt_reg);
+ int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
+ list_del(&ioa_cfg->reset_cmd->queue);
+ del_timer(&ioa_cfg->reset_cmd->timer);
+ ipr_reset_ioa_job(ioa_cfg->reset_cmd);
+ return IRQ_HANDLED;
+ }
+ }
+
+ return IRQ_NONE;
+ }
if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) {
/* Mask the interrupt */
@@ -4968,6 +5041,13 @@ static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg,
list_del(&ioa_cfg->reset_cmd->queue);
del_timer(&ioa_cfg->reset_cmd->timer);
ipr_reset_ioa_job(ioa_cfg->reset_cmd);
+ } else if ((int_reg & IPR_PCII_HRRQ_UPDATED) == int_reg) {
+ if (ipr_debug && printk_ratelimit())
+ dev_err(&ioa_cfg->pdev->dev,
+ "Spurious interrupt detected. 0x%08X\n", int_reg);
+ writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg32);
+ int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32);
+ return IRQ_NONE;
} else {
if (int_reg & IPR_PCII_IOA_UNIT_CHECKED)
ioa_cfg->ioa_unit_checked = 1;
@@ -5016,10 +5096,11 @@ static irqreturn_t ipr_isr(int irq, void *devp)
{
struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)devp;
unsigned long lock_flags = 0;
- volatile u32 int_reg, int_mask_reg;
+ u32 int_reg = 0;
u32 ioasc;
u16 cmd_index;
int num_hrrq = 0;
+ int irq_none = 0;
struct ipr_cmnd *ipr_cmd;
irqreturn_t rc = IRQ_NONE;
@@ -5031,33 +5112,6 @@ static irqreturn_t ipr_isr(int irq, void *devp)
return IRQ_NONE;
}
- int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg32);
- int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32) & ~int_mask_reg;
-
- /* If an interrupt on the adapter did not occur, ignore it.
- * Or in the case of SIS 64, check for a stage change interrupt.
- */
- if (unlikely((int_reg & IPR_PCII_OPER_INTERRUPTS) == 0)) {
- if (ioa_cfg->sis64) {
- int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
- int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
- if (int_reg & IPR_PCII_IPL_STAGE_CHANGE) {
-
- /* clear stage change */
- writel(IPR_PCII_IPL_STAGE_CHANGE, ioa_cfg->regs.clr_interrupt_reg);
- int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
- list_del(&ioa_cfg->reset_cmd->queue);
- del_timer(&ioa_cfg->reset_cmd->timer);
- ipr_reset_ioa_job(ioa_cfg->reset_cmd);
- spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
- return IRQ_HANDLED;
- }
- }
-
- spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
- return IRQ_NONE;
- }
-
while (1) {
ipr_cmd = NULL;
@@ -5097,7 +5151,7 @@ static irqreturn_t ipr_isr(int irq, void *devp)
/* Clear the PCI interrupt */
do {
writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg32);
- int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32) & ~int_mask_reg;
+ int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32);
} while (int_reg & IPR_PCII_HRRQ_UPDATED &&
num_hrrq++ < IPR_MAX_HRRQ_RETRIES);
@@ -5107,6 +5161,9 @@ static irqreturn_t ipr_isr(int irq, void *devp)
return IRQ_HANDLED;
}
+ } else if (rc == IRQ_NONE && irq_none == 0) {
+ int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32);
+ irq_none++;
} else
break;
}
@@ -5143,7 +5200,8 @@ static int ipr_build_ioadl64(struct ipr_ioa_cfg *ioa_cfg,
nseg = scsi_dma_map(scsi_cmd);
if (nseg < 0) {
- dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n");
+ if (printk_ratelimit())
+ dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n");
return -1;
}
@@ -5773,7 +5831,8 @@ static int ipr_queuecommand_lck(struct scsi_cmnd *scsi_cmd,
}
ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC;
- ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_DELAY_AFTER_RST;
+ if (ipr_is_gscsi(res))
+ ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_DELAY_AFTER_RST;
ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_ALIGNED_BFR;
ioarcb->cmd_pkt.flags_lo |= ipr_get_task_attributes(scsi_cmd);
}
@@ -7516,7 +7575,7 @@ static int ipr_reset_get_unit_check_job(struct ipr_cmnd *ipr_cmd)
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;
+ u32 int_reg;
ENTER;
ioa_cfg->pdev->state_saved = true;
@@ -7555,7 +7614,10 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd)
ipr_cmd->job_step = ipr_reset_enable_ioa;
if (GET_DUMP == ioa_cfg->sdt_state) {
- ipr_reset_start_timer(ipr_cmd, IPR_DUMP_TIMEOUT);
+ if (ioa_cfg->sis64)
+ ipr_reset_start_timer(ipr_cmd, IPR_SIS64_DUMP_TIMEOUT);
+ else
+ ipr_reset_start_timer(ipr_cmd, IPR_SIS32_DUMP_TIMEOUT);
ipr_cmd->job_step = ipr_reset_wait_for_dump;
schedule_work(&ioa_cfg->work_q);
return IPR_RC_JOB_RETURN;
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index 13f425fb8851..f93f8637c5a1 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -38,8 +38,8 @@
/*
* Literals
*/
-#define IPR_DRIVER_VERSION "2.5.1"
-#define IPR_DRIVER_DATE "(August 10, 2010)"
+#define IPR_DRIVER_VERSION "2.5.2"
+#define IPR_DRIVER_DATE "(April 27, 2011)"
/*
* IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding
@@ -217,7 +217,8 @@
#define IPR_CHECK_FOR_RESET_TIMEOUT (HZ / 10)
#define IPR_WAIT_FOR_BIST_TIMEOUT (2 * HZ)
#define IPR_PCI_RESET_TIMEOUT (HZ / 2)
-#define IPR_DUMP_TIMEOUT (15 * HZ)
+#define IPR_SIS32_DUMP_TIMEOUT (15 * HZ)
+#define IPR_SIS64_DUMP_TIMEOUT (40 * HZ)
#define IPR_DUMP_DELAY_SECONDS 4
#define IPR_DUMP_DELAY_TIMEOUT (IPR_DUMP_DELAY_SECONDS * HZ)
@@ -285,9 +286,12 @@ IPR_PCII_NO_HOST_RRQ | IPR_PCII_IOARRIN_LOST | IPR_PCII_MMIO_ERROR)
/*
* Dump literals
*/
-#define IPR_MAX_IOA_DUMP_SIZE (4 * 1024 * 1024)
-#define IPR_NUM_SDT_ENTRIES 511
-#define IPR_MAX_NUM_DUMP_PAGES ((IPR_MAX_IOA_DUMP_SIZE / PAGE_SIZE) + 1)
+#define IPR_FMT2_MAX_IOA_DUMP_SIZE (4 * 1024 * 1024)
+#define IPR_FMT3_MAX_IOA_DUMP_SIZE (32 * 1024 * 1024)
+#define IPR_FMT2_NUM_SDT_ENTRIES 511
+#define IPR_FMT3_NUM_SDT_ENTRIES 0xFFF
+#define IPR_FMT2_MAX_NUM_DUMP_PAGES ((IPR_FMT2_MAX_IOA_DUMP_SIZE / PAGE_SIZE) + 1)
+#define IPR_FMT3_MAX_NUM_DUMP_PAGES ((IPR_FMT3_MAX_IOA_DUMP_SIZE / PAGE_SIZE) + 1)
/*
* Misc literals
@@ -474,7 +478,7 @@ struct ipr_cmd_pkt {
u8 flags_lo;
#define IPR_FLAGS_LO_ALIGNED_BFR 0x20
-#define IPR_FLAGS_LO_DELAY_AFTER_RST 0x10
+#define IPR_FLAGS_LO_DELAY_AFTER_RST 0x10
#define IPR_FLAGS_LO_UNTAGGED_TASK 0x00
#define IPR_FLAGS_LO_SIMPLE_TASK 0x02
#define IPR_FLAGS_LO_ORDERED_TASK 0x04
@@ -1164,7 +1168,7 @@ struct ipr_sdt_header {
struct ipr_sdt {
struct ipr_sdt_header hdr;
- struct ipr_sdt_entry entry[IPR_NUM_SDT_ENTRIES];
+ struct ipr_sdt_entry entry[IPR_FMT3_NUM_SDT_ENTRIES];
}__attribute__((packed, aligned (4)));
struct ipr_uc_sdt {
@@ -1608,7 +1612,7 @@ struct ipr_driver_dump {
struct ipr_ioa_dump {
struct ipr_dump_entry_header hdr;
struct ipr_sdt sdt;
- __be32 *ioa_data[IPR_MAX_NUM_DUMP_PAGES];
+ __be32 **ioa_data;
u32 reserved;
u32 next_page_index;
u32 page_offset;
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c
index 5b799a37ad09..2a3a4720a771 100644
--- a/drivers/scsi/libfc/fc_fcp.c
+++ b/drivers/scsi/libfc/fc_fcp.c
@@ -57,9 +57,6 @@ static struct kmem_cache *scsi_pkt_cachep;
#define FC_SRB_READ (1 << 1)
#define FC_SRB_WRITE (1 << 0)
-/* constant added to e_d_tov timeout to get rec_tov value */
-#define REC_TOV_CONST 1
-
/*
* The SCp.ptr should be tested and set under the scsi_pkt_queue lock
*/
@@ -248,7 +245,7 @@ static inline void fc_fcp_unlock_pkt(struct fc_fcp_pkt *fsp)
/**
* fc_fcp_timer_set() - Start a timer for a fcp_pkt
* @fsp: The FCP packet to start a timer for
- * @delay: The timeout period for the timer
+ * @delay: The timeout period in jiffies
*/
static void fc_fcp_timer_set(struct fc_fcp_pkt *fsp, unsigned long delay)
{
@@ -335,22 +332,23 @@ static void fc_fcp_ddp_done(struct fc_fcp_pkt *fsp)
/**
* fc_fcp_can_queue_ramp_up() - increases can_queue
* @lport: lport to ramp up can_queue
- *
- * Locking notes: Called with Scsi_Host lock held
*/
static void fc_fcp_can_queue_ramp_up(struct fc_lport *lport)
{
struct fc_fcp_internal *si = fc_get_scsi_internal(lport);
+ unsigned long flags;
int can_queue;
+ spin_lock_irqsave(lport->host->host_lock, flags);
+
if (si->last_can_queue_ramp_up_time &&
(time_before(jiffies, si->last_can_queue_ramp_up_time +
FC_CAN_QUEUE_PERIOD)))
- return;
+ goto unlock;
if (time_before(jiffies, si->last_can_queue_ramp_down_time +
FC_CAN_QUEUE_PERIOD))
- return;
+ goto unlock;
si->last_can_queue_ramp_up_time = jiffies;
@@ -362,6 +360,9 @@ static void fc_fcp_can_queue_ramp_up(struct fc_lport *lport)
lport->host->can_queue = can_queue;
shost_printk(KERN_ERR, lport->host, "libfc: increased "
"can_queue to %d.\n", can_queue);
+
+unlock:
+ spin_unlock_irqrestore(lport->host->host_lock, flags);
}
/**
@@ -373,18 +374,19 @@ static void fc_fcp_can_queue_ramp_up(struct fc_lport *lport)
* commands complete or timeout, then try again with a reduced
* can_queue. Eventually we will hit the point where we run
* on all reserved structs.
- *
- * Locking notes: Called with Scsi_Host lock held
*/
static void fc_fcp_can_queue_ramp_down(struct fc_lport *lport)
{
struct fc_fcp_internal *si = fc_get_scsi_internal(lport);
+ unsigned long flags;
int can_queue;
+ spin_lock_irqsave(lport->host->host_lock, flags);
+
if (si->last_can_queue_ramp_down_time &&
(time_before(jiffies, si->last_can_queue_ramp_down_time +
FC_CAN_QUEUE_PERIOD)))
- return;
+ goto unlock;
si->last_can_queue_ramp_down_time = jiffies;
@@ -395,6 +397,9 @@ static void fc_fcp_can_queue_ramp_down(struct fc_lport *lport)
lport->host->can_queue = can_queue;
shost_printk(KERN_ERR, lport->host, "libfc: Could not allocate frame.\n"
"Reducing can_queue to %d.\n", can_queue);
+
+unlock:
+ spin_unlock_irqrestore(lport->host->host_lock, flags);
}
/*
@@ -409,16 +414,13 @@ static inline struct fc_frame *fc_fcp_frame_alloc(struct fc_lport *lport,
size_t len)
{
struct fc_frame *fp;
- unsigned long flags;
fp = fc_frame_alloc(lport, len);
if (likely(fp))
return fp;
/* error case */
- spin_lock_irqsave(lport->host->host_lock, flags);
fc_fcp_can_queue_ramp_down(lport);
- spin_unlock_irqrestore(lport->host->host_lock, flags);
return NULL;
}
@@ -1093,16 +1095,14 @@ static int fc_fcp_pkt_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp)
/**
* get_fsp_rec_tov() - Helper function to get REC_TOV
* @fsp: the FCP packet
+ *
+ * Returns rec tov in jiffies as rpriv->e_d_tov + 1 second
*/
static inline unsigned int get_fsp_rec_tov(struct fc_fcp_pkt *fsp)
{
- struct fc_rport *rport;
- struct fc_rport_libfc_priv *rpriv;
-
- rport = fsp->rport;
- rpriv = rport->dd_data;
+ struct fc_rport_libfc_priv *rpriv = fsp->rport->dd_data;
- return rpriv->e_d_tov + REC_TOV_CONST;
+ return msecs_to_jiffies(rpriv->e_d_tov) + HZ;
}
/**
@@ -1122,7 +1122,6 @@ static int fc_fcp_cmd_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp,
struct fc_rport_libfc_priv *rpriv;
const size_t len = sizeof(fsp->cdb_cmd);
int rc = 0;
- unsigned int rec_tov;
if (fc_fcp_lock_pkt(fsp))
return 0;
@@ -1153,12 +1152,9 @@ static int fc_fcp_cmd_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp,
fsp->seq_ptr = seq;
fc_fcp_pkt_hold(fsp); /* hold for fc_fcp_pkt_destroy */
- rec_tov = get_fsp_rec_tov(fsp);
-
setup_timer(&fsp->timer, fc_fcp_timeout, (unsigned long)fsp);
-
if (rpriv->flags & FC_RP_FLAGS_REC_SUPPORTED)
- fc_fcp_timer_set(fsp, rec_tov);
+ fc_fcp_timer_set(fsp, get_fsp_rec_tov(fsp));
unlock:
fc_fcp_unlock_pkt(fsp);
@@ -1235,16 +1231,14 @@ static void fc_lun_reset_send(unsigned long data)
{
struct fc_fcp_pkt *fsp = (struct fc_fcp_pkt *)data;
struct fc_lport *lport = fsp->lp;
- unsigned int rec_tov;
if (lport->tt.fcp_cmd_send(lport, fsp, fc_tm_done)) {
if (fsp->recov_retry++ >= FC_MAX_RECOV_RETRY)
return;
if (fc_fcp_lock_pkt(fsp))
return;
- rec_tov = get_fsp_rec_tov(fsp);
setup_timer(&fsp->timer, fc_lun_reset_send, (unsigned long)fsp);
- fc_fcp_timer_set(fsp, rec_tov);
+ fc_fcp_timer_set(fsp, get_fsp_rec_tov(fsp));
fc_fcp_unlock_pkt(fsp);
}
}
@@ -1536,12 +1530,11 @@ static void fc_fcp_rec_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
}
fc_fcp_srr(fsp, r_ctl, offset);
} else if (e_stat & ESB_ST_SEQ_INIT) {
- unsigned int rec_tov = get_fsp_rec_tov(fsp);
/*
* The remote port has the initiative, so just
* keep waiting for it to complete.
*/
- fc_fcp_timer_set(fsp, rec_tov);
+ fc_fcp_timer_set(fsp, get_fsp_rec_tov(fsp));
} else {
/*
@@ -1705,7 +1698,6 @@ static void fc_fcp_srr_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
{
struct fc_fcp_pkt *fsp = arg;
struct fc_frame_header *fh;
- unsigned int rec_tov;
if (IS_ERR(fp)) {
fc_fcp_srr_error(fsp, fp);
@@ -1732,8 +1724,7 @@ static void fc_fcp_srr_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg)
switch (fc_frame_payload_op(fp)) {
case ELS_LS_ACC:
fsp->recov_retry = 0;
- rec_tov = get_fsp_rec_tov(fsp);
- fc_fcp_timer_set(fsp, rec_tov);
+ fc_fcp_timer_set(fsp, get_fsp_rec_tov(fsp));
break;
case ELS_LS_RJT:
default:
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index 906bbcad0e2d..389ab80aef0a 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -1590,7 +1590,6 @@ void fc_lport_enter_flogi(struct fc_lport *lport)
*/
int fc_lport_config(struct fc_lport *lport)
{
- INIT_LIST_HEAD(&lport->ema_list);
INIT_DELAYED_WORK(&lport->retry_work, fc_lport_timeout);
mutex_init(&lport->lp_mutex);
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 60e98a62f308..02d53d89534f 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -805,6 +805,8 @@ struct lpfc_hba {
struct dentry *idiag_root;
struct dentry *idiag_pci_cfg;
struct dentry *idiag_que_info;
+ struct dentry *idiag_que_acc;
+ struct dentry *idiag_drb_acc;
#endif
/* Used for deferred freeing of ELS data buffers */
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 17d789325f40..8dcbf8fff673 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c